Spaces:
Sleeping
Sleeping
GeraldoRiberia commited on
Commit ·
d5fe478
1
Parent(s): 679b5d0
updat
Browse files
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
|
| 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
|
| 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
|
| 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
|
| 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
|
| 273 |
-
if is_obs_active
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
| 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
|