GeraldoRiberia commited on
Commit
d5fe478
·
1 Parent(s): 679b5d0
Files changed (1) hide show
  1. server.py +25 -27
server.py CHANGED
@@ -11,7 +11,6 @@ import asyncio
11
  from concurrent.futures import ThreadPoolExecutor
12
  from datetime import datetime
13
  import threading
14
- import pyvirtualcam
15
 
16
  from services.single_tracker import SingleTracker
17
  from services.multi_tracker import MultiTracker
@@ -24,10 +23,9 @@ logger = logging.getLogger(__name__)
24
  executor = ThreadPoolExecutor(max_workers=1)
25
 
26
  # --- OBS and Recording State ---
27
- latest_obs_frame = None # Store the latest JPEG encoded cropped frame for the OBS feed (deprecated by vcam)
28
  obs_frame_lock = threading.Lock()
29
  is_obs_active = False
30
- vcam = None # Virtual Camera reference
31
  is_recording = False
32
  video_writer = None
33
  recording_filename = ""
@@ -175,9 +173,24 @@ async def obs_feed():
175
  """Endpoint for OBS Media Source to connect to."""
176
  return StreamingResponse(generate_obs_stream(), media_type="multipart/x-mixed-replace; boundary=frame")
177
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  @app.websocket("/ws")
179
  async def websocket_endpoint(websocket: WebSocket):
180
- global is_recording, video_writer, recording_filename, latest_obs_frame, is_obs_active, vcam
181
 
182
  await websocket.accept()
183
  logger.info("New WebSocket connection established.")
@@ -215,20 +228,12 @@ async def websocket_endpoint(websocket: WebSocket):
215
  elif command == "start_obs":
216
  if not is_obs_active:
217
  is_obs_active = True
218
- logger.info("Started OBS Virtual Camera stream")
219
- try:
220
- if vcam is None:
221
- vcam = pyvirtualcam.Camera(width=1280, height=720, fps=30)
222
- except Exception as e:
223
- logger.error(f"Failed to start vcam: {e}")
224
  await websocket.send_json({"type": "obs_ack", "status": "started"})
225
  elif command == "stop_obs":
226
  if is_obs_active:
227
  is_obs_active = False
228
- logger.info("Stopped OBS Virtual Camera stream")
229
- if vcam is not None:
230
- vcam.close()
231
- vcam = None
232
  await websocket.send_json({"type": "obs_ack", "status": "stopped"})
233
  except json.JSONDecodeError:
234
  logger.error("Invalid JSON received.")
@@ -269,15 +274,12 @@ async def websocket_endpoint(websocket: WebSocket):
269
  try:
270
  cropped_frame = apply_center_stage_crop(frame, response_data)
271
 
272
- # 1. Update OBS Virtual Camera
273
- if is_obs_active and vcam is not None:
274
- try:
275
- # Virtual cameras generally strict size requirements
276
- cam_frame = cv2.resize(cropped_frame, (vcam.width, vcam.height))
277
- cam_frame = cv2.cvtColor(cam_frame, cv2.COLOR_BGR2RGB)
278
- vcam.send(cam_frame)
279
- except Exception as e:
280
- logger.error(f"Failed to push vcam frame: {e}")
281
 
282
  # 2. Update Recording Output
283
  if is_recording:
@@ -302,10 +304,6 @@ async def websocket_endpoint(websocket: WebSocket):
302
  except Exception as e:
303
  logger.error(f"WebSocket error: {e}")
304
  finally:
305
- # Cleanup Virtual Camera
306
- if vcam is not None:
307
- vcam.close()
308
- vcam = None
309
  is_obs_active = False
310
 
311
  # Cleanup Recording
 
11
  from concurrent.futures import ThreadPoolExecutor
12
  from datetime import datetime
13
  import threading
 
14
 
15
  from services.single_tracker import SingleTracker
16
  from services.multi_tracker import MultiTracker
 
23
  executor = ThreadPoolExecutor(max_workers=1)
24
 
25
  # --- OBS and Recording State ---
26
+ latest_obs_frame = None # Store the latest JPEG encoded cropped frame for the OBS feed
27
  obs_frame_lock = threading.Lock()
28
  is_obs_active = False
 
29
  is_recording = False
30
  video_writer = None
31
  recording_filename = ""
 
173
  """Endpoint for OBS Media Source to connect to."""
174
  return StreamingResponse(generate_obs_stream(), media_type="multipart/x-mixed-replace; boundary=frame")
175
 
176
+ async def vcam_generator_loop():
177
+ """Background task to push frames to the virtual camera at 30fps."""
178
+ global is_obs_active, vcam, latest_vcam_frame
179
+ while True:
180
+ try:
181
+ if is_obs_active and vcam is not None and latest_vcam_frame is not None:
182
+ vcam.send(latest_vcam_frame)
183
+ except Exception as e:
184
+ logger.error(f"vcam loop error: {e}")
185
+ await asyncio.sleep(1/30)
186
+
187
+ @app.on_event("startup")
188
+ async def startup_event():
189
+ asyncio.create_task(vcam_generator_loop())
190
+
191
  @app.websocket("/ws")
192
  async def websocket_endpoint(websocket: WebSocket):
193
+ global is_recording, video_writer, recording_filename, latest_obs_frame, is_obs_active
194
 
195
  await websocket.accept()
196
  logger.info("New WebSocket connection established.")
 
228
  elif command == "start_obs":
229
  if not is_obs_active:
230
  is_obs_active = True
231
+ logger.info("Started OBS MJPEG stream")
 
 
 
 
 
232
  await websocket.send_json({"type": "obs_ack", "status": "started"})
233
  elif command == "stop_obs":
234
  if is_obs_active:
235
  is_obs_active = False
236
+ logger.info("Stopped OBS MJPEG stream")
 
 
 
237
  await websocket.send_json({"type": "obs_ack", "status": "stopped"})
238
  except json.JSONDecodeError:
239
  logger.error("Invalid JSON received.")
 
274
  try:
275
  cropped_frame = apply_center_stage_crop(frame, response_data)
276
 
277
+ # 1. Update OBS Feed
278
+ if is_obs_active:
279
+ ret, buffer = cv2.imencode('.jpg', cropped_frame)
280
+ if ret:
281
+ with obs_frame_lock:
282
+ latest_obs_frame = buffer.tobytes()
 
 
 
283
 
284
  # 2. Update Recording Output
285
  if is_recording:
 
304
  except Exception as e:
305
  logger.error(f"WebSocket error: {e}")
306
  finally:
 
 
 
 
307
  is_obs_active = False
308
 
309
  # Cleanup Recording