feat: frame work off the event loop, each frame encoded once
- Endpoints that wait for the camera or encode/compute (capture, rgb, depth, depth/color, pointcloud, pointcloud/roi, measure, snapshot, and the SDK calls discover/open/close) are plain `def`: FastAPI runs them in its thread pool, so one slow request no longer holds the others. Plain `def` rather than asyncio.to_thread in each route: it is FastAPI's own mechanism and keeps the route bodies unchanged. - /ws and the NATS snapshot stay async and use asyncio.to_thread for the frame wait, the encoding and the recording write. - EncodedFrame: the JPEG q85, 16-bit PNG, colormap JPEG q90, their base64 and the depth stats of a frame are computed once, on first use, and shared: parallel requests, /ws and NATS on the same frame get the same bytes. The last 4 frames' encodings are kept. - camera.cached_frame(): the whole cached frame (get_rgb/get_depth unchanged). Contract unchanged: same endpoints, same JSON fields. frame_id still counts responses (now under a lock); two parallel /api/capture served by one frame have different frame_id and the same timestamp and images. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
cc28127c9c
commit
1ad422062c
4 files changed
+125
-50
No files matched your search
@@ -56,15 +56,17 @@ async def websocket_stream(ws: WebSocket):
|
||||
try:
|
||||
while True:
|
||||
if streaming and _camera and _camera.is_open():
|
||||
frame = _camera.capture(timeout_ms=500)
|
||||
# Waiting for the frame, encoding and saving run in threads: the
|
||||
# event loop keeps serving REST and the other sockets meanwhile.
|
||||
frame = await asyncio.to_thread(_camera.capture, 500)
|
||||
if frame:
|
||||
data = _frame_to_dict(frame)
|
||||
data = await asyncio.to_thread(_frame_to_dict, frame)
|
||||
if predicting and _detector is not None:
|
||||
data["detections"] = await asyncio.to_thread(_detector.detect, frame.rgb)
|
||||
with timer.phase("ws_send"):
|
||||
await ws.send_json(data)
|
||||
if _saver and _saver.is_recording:
|
||||
_saver.save_rec_frame(frame.rgb)
|
||||
await asyncio.to_thread(_saver.save_rec_frame, frame.rgb)
|
||||
await asyncio.sleep(0.033)
|
||||
|
||||
try:
|
||||
|
||||
Reference in new issue
Block a user