matrice-streaming 0.1.69__tar.gz → 0.1.71__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/PKG-INFO +1 -1
  2. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/matrice_streaming.egg-info/PKG-INFO +1 -1
  3. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/async_camera_worker.py +42 -12
  4. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/async_ffmpeg_worker.py +2 -2
  5. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/camera_streamer.py +1 -1
  6. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/ffmpeg_camera_streamer.py +1 -1
  7. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/gstreamer_camera_streamer.py +1 -1
  8. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/worker_manager.py +31 -6
  9. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/LICENSE.txt +0 -0
  10. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/README.md +0 -0
  11. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/matrice_streaming.egg-info/SOURCES.txt +0 -0
  12. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/matrice_streaming.egg-info/dependency_links.txt +0 -0
  13. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/matrice_streaming.egg-info/not-zip-safe +0 -0
  14. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/matrice_streaming.egg-info/top_level.txt +0 -0
  15. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/pyproject.toml +0 -0
  16. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/setup.cfg +0 -0
  17. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/setup.py +0 -0
  18. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/__init__.py +0 -0
  19. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/client/__init__.py +0 -0
  20. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/client/client.py +0 -0
  21. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/client/client_utils.py +0 -0
  22. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/deployment/__init__.py +0 -0
  23. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/deployment/camera_manager.py +0 -0
  24. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/deployment/deployment.py +0 -0
  25. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/deployment/inference_pipeline.py +0 -0
  26. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/deployment/streaming_gateway_manager.py +0 -0
  27. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/deployment/todo.txt +0 -0
  28. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/py.typed +0 -0
  29. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/__init__.py +0 -0
  30. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/ARCHITECTURE.md +0 -0
  31. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/__init__.py +0 -0
  32. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/device_detection.py +0 -0
  33. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/encoder_manager.py +0 -0
  34. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/encoding_pool_manager.py +0 -0
  35. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/ffmpeg_config.py +0 -0
  36. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/ffmpeg_worker_manager.py +0 -0
  37. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/frame_processor.py +0 -0
  38. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/gstreamer_worker.py +0 -0
  39. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/gstreamer_worker_manager.py +0 -0
  40. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/message_builder.py +0 -0
  41. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/nvdec.py +0 -0
  42. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/nvdec_worker_manager.py +0 -0
  43. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/platform_pipelines.py +0 -0
  44. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/retry_manager.py +0 -0
  45. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/stream_statistics.py +0 -0
  46. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/camera_streamer/video_capture_manager.py +0 -0
  47. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/debug/README.md +0 -0
  48. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/debug/__init__.py +0 -0
  49. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/debug/benchmark.py +0 -0
  50. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/debug/debug_gstreamer_gateway.py +0 -0
  51. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/debug/debug_stream_backend.py +0 -0
  52. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/debug/debug_streaming_gateway.py +0 -0
  53. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/debug/debug_utils.py +0 -0
  54. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/debug/example_debug_streaming.py +0 -0
  55. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/debug/test_videoplayback.py +0 -0
  56. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/dynamic_camera_manager.py +0 -0
  57. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/event_listener.py +0 -0
  58. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/metrics_reporter.py +0 -0
  59. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/streaming_action.py +0 -0
  60. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/streaming_gateway.py +0 -0
  61. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/streaming_gateway_utils.py +0 -0
  62. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/src/matrice_streaming/streaming_gateway/streaming_status_listener.py +0 -0
  63. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/tests/test_async_infrastructure.py +0 -0
  64. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/tests/test_batch_auto_calculation.py +0 -0
  65. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/tests/test_batching_verification.py +0 -0
  66. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/tests/test_e2e_production.py +0 -0
  67. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/tests/test_flatten_binary.py +0 -0
  68. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/tests/test_gstreamer_integration.py +0 -0
  69. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/tests/test_msgpack_fix.py +0 -0
  70. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/tests/test_phase1_unit.py +0 -0
  71. {matrice_streaming-0.1.69 → matrice_streaming-0.1.71}/tests/test_phase2_scaling.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: matrice_streaming
3
- Version: 0.1.69
3
+ Version: 0.1.71
4
4
  Summary: Common server utilities for Matrice.ai services
5
5
  Author-email: "Matrice.ai" <dipendra@matrice.ai>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: matrice_streaming
3
- Version: 0.1.69
3
+ Version: 0.1.71
4
4
  Summary: Common server utilities for Matrice.ai services
5
5
  Author-email: "Matrice.ai" <dipendra@matrice.ai>
6
6
  License-Expression: MIT
@@ -88,7 +88,7 @@ class AsyncCameraWorker:
88
88
  health_queue: multiprocessing.Queue,
89
89
  command_queue: Optional[multiprocessing.Queue] = None,
90
90
  response_queue: Optional[multiprocessing.Queue] = None,
91
- frame_optimizer_enabled: bool = True,
91
+ frame_optimizer_enabled: bool = False, # Disabled for ML quality
92
92
  frame_optimizer_config: Optional[Dict[str, Any]] = None,
93
93
  # ================================================================
94
94
  # SHM_MODE: New parameters for shared memory architecture
@@ -99,7 +99,8 @@ class AsyncCameraWorker:
99
99
  # ================================================================
100
100
  # PERFORMANCE: New parameters for optimized frame capture
101
101
  # ================================================================
102
- drop_stale_frames: bool = True, # Use grab()/grab()/retrieve() pattern for latest frame
102
+ drop_stale_frames: bool = False, # Disabled for ML quality
103
+ use_simple_read: bool = True, # Use cap.read() directly instead of grab/retrieve
103
104
  pin_cpu_affinity: bool = True, # Pin worker to specific CPU cores
104
105
  total_workers: int = 1, # Total worker count for CPU affinity calculation
105
106
  buffer_size: int = 1, # Minimal buffer for low latency (cv2_bench uses 1)
@@ -120,6 +121,7 @@ class AsyncCameraWorker:
120
121
  shm_slot_count: Number of frame slots per camera ring buffer
121
122
  shm_frame_format: Frame format for SHM storage ("BGR", "RGB", or "NV12")
122
123
  drop_stale_frames: Use grab()/grab()/retrieve() pattern to get latest frame
124
+ use_simple_read: Use cap.read() directly instead of grab/retrieve pattern
123
125
  pin_cpu_affinity: Pin worker process to specific CPU cores for cache locality
124
126
  total_workers: Total number of workers (for CPU affinity calculation)
125
127
  buffer_size: VideoCapture buffer size (1 = minimal latency)
@@ -207,6 +209,7 @@ class AsyncCameraWorker:
207
209
  # PERFORMANCE: Optimized frame capture configuration
208
210
  # ================================================================
209
211
  self.drop_stale_frames = drop_stale_frames
212
+ self.use_simple_read = use_simple_read
210
213
  self.pin_cpu_affinity = pin_cpu_affinity
211
214
  self.total_workers = total_workers
212
215
  self.buffer_size = buffer_size
@@ -225,6 +228,9 @@ class AsyncCameraWorker:
225
228
  if drop_stale_frames:
226
229
  self.logger.info(f"Worker {worker_id}: Frame dropping ENABLED (grab/grab/retrieve pattern)")
227
230
 
231
+ if use_simple_read:
232
+ self.logger.info(f"Worker {worker_id}: Simple read ENABLED (cap.read() directly)")
233
+
228
234
  # ThreadPoolExecutor for I/O-bound frame capture only
229
235
  # Encoding is done inline (cv2.imencode releases GIL, ~5ms for 480p)
230
236
  #
@@ -329,9 +335,10 @@ class AsyncCameraWorker:
329
335
 
330
336
  # Create MatriceStream with async support
331
337
  # Unpack stream_config as keyword arguments (MatriceStream expects **config)
338
+ # NOTE: enable_shm_batching=False for real-time frame delivery (avoids batch delays)
332
339
  self.stream = MatriceStream(
333
340
  stream_type=StreamType.REDIS,
334
- enable_shm_batching=True,
341
+ enable_shm_batching=False,
335
342
  **self.stream_config
336
343
  )
337
344
 
@@ -409,23 +416,33 @@ class AsyncCameraWorker:
409
416
  async def _read_latest_frame(
410
417
  self,
411
418
  cap: cv2.VideoCapture,
412
- drop_stale: bool = True
419
+ drop_stale: bool = False,
420
+ use_simple_read: bool = False,
413
421
  ) -> Tuple[bool, Optional[Any]]:
414
- """Read latest frame, optionally dropping stale buffered frames.
422
+ """Read frame from video capture.
415
423
 
416
- This optimization from cv2_bench.py uses grab()/grab()/retrieve()
417
- pattern to always get the most recent frame instead of reading
418
- stale frames from the buffer.
424
+ Three modes available:
425
+ 1. use_simple_read=True: Uses cap.read() directly - best for video files
426
+ 2. drop_stale=True: Uses grab/grab/retrieve to skip stale buffered frames
427
+ 3. drop_stale=False: Uses grab/retrieve (no frame dropping)
419
428
 
420
429
  Args:
421
430
  cap: OpenCV VideoCapture object
422
431
  drop_stale: If True, use grab/grab/retrieve pattern to skip stale frames
432
+ use_simple_read: If True, use cap.read() directly (ignores drop_stale)
423
433
 
424
434
  Returns:
425
435
  Tuple of (success, frame) where frame is None if read failed
426
436
  """
427
437
  loop = asyncio.get_event_loop()
428
438
 
439
+ # SIMPLE READ: Use cap.read() directly - best for video files
440
+ # This reads frames sequentially without any buffer manipulation
441
+ if use_simple_read:
442
+ ret, frame = await loop.run_in_executor(self.capture_executor, cap.read)
443
+ return ret, frame
444
+
445
+ # GRAB/RETRIEVE PATTERN: For live streams where we want latest frame
429
446
  if drop_stale:
430
447
  # Aggressive frame dropping: grab twice to get latest frame
431
448
  # First grab clears any stale frame, second grab gets current
@@ -514,7 +531,9 @@ class AsyncCameraWorker:
514
531
  # This gets the latest frame and drops stale buffered frames
515
532
  read_start = time.time()
516
533
  ret, frame = await self._read_latest_frame(
517
- cap, drop_stale=self.drop_stale_frames
534
+ cap,
535
+ drop_stale=self.drop_stale_frames,
536
+ use_simple_read=self.use_simple_read,
518
537
  )
519
538
  read_time = time.time() - read_start
520
539
 
@@ -586,7 +605,8 @@ class AsyncCameraWorker:
586
605
  return # Exit completely on cancellation
587
606
  except Exception as exc:
588
607
  self.logger.error(
589
- f"Worker {self.worker_id}: Error in camera {stream_key}: {exc}",
608
+ f"Worker {self.worker_id}: Error in camera {stream_key} "
609
+ f"at frame {frame_counter}: {exc}",
590
610
  exc_info=True
591
611
  )
592
612
  consecutive_failures += 1
@@ -596,7 +616,7 @@ class AsyncCameraWorker:
596
616
  f"max failures in inner loop, reconnecting..."
597
617
  )
598
618
  break # Break inner loop to reconnect
599
- await asyncio.sleep(1.0)
619
+ await asyncio.sleep(0.1) # Reduced from 1.0s to minimize frame loss
600
620
 
601
621
  except asyncio.CancelledError:
602
622
  self.logger.info(f"Worker {self.worker_id}: Camera {stream_key} task cancelled during setup")
@@ -1313,10 +1333,15 @@ def run_async_worker(
1313
1333
  # ================================================================
1314
1334
  # PERFORMANCE: New parameters for optimized frame capture
1315
1335
  # ================================================================
1316
- drop_stale_frames: bool = True,
1336
+ drop_stale_frames: bool = False, # Disabled for ML quality
1337
+ use_simple_read: bool = True, # Use cap.read() directly instead of grab/retrieve
1317
1338
  pin_cpu_affinity: bool = True,
1318
1339
  total_workers: int = 1,
1319
1340
  buffer_size: int = 1,
1341
+ # ================================================================
1342
+ # FRAME OPTIMIZER: Control frame similarity detection
1343
+ # ================================================================
1344
+ frame_optimizer_enabled: bool = False, # Disabled for ML quality
1320
1345
  ):
1321
1346
  """Entry point for async worker process.
1322
1347
 
@@ -1334,9 +1359,11 @@ def run_async_worker(
1334
1359
  shm_slot_count: Number of frame slots per camera ring buffer
1335
1360
  shm_frame_format: Frame format for SHM storage
1336
1361
  drop_stale_frames: Use grab()/grab()/retrieve() pattern for latest frame
1362
+ use_simple_read: Use cap.read() directly instead of grab/retrieve pattern
1337
1363
  pin_cpu_affinity: Pin worker process to specific CPU cores
1338
1364
  total_workers: Total number of workers for CPU affinity calculation
1339
1365
  buffer_size: VideoCapture buffer size (1 = minimal latency)
1366
+ frame_optimizer_enabled: Enable frame similarity detection (skip similar frames)
1340
1367
  """
1341
1368
  # Setup logging for this process
1342
1369
  logging.basicConfig(
@@ -1375,9 +1402,12 @@ def run_async_worker(
1375
1402
  shm_frame_format=shm_frame_format,
1376
1403
  # PERFORMANCE: Pass through optimized frame capture parameters
1377
1404
  drop_stale_frames=drop_stale_frames,
1405
+ use_simple_read=use_simple_read,
1378
1406
  pin_cpu_affinity=pin_cpu_affinity,
1379
1407
  total_workers=total_workers,
1380
1408
  buffer_size=buffer_size,
1409
+ # FRAME OPTIMIZER: Pass through frame similarity detection setting
1410
+ frame_optimizer_enabled=frame_optimizer_enabled,
1381
1411
  )
1382
1412
 
1383
1413
  # Run event loop
@@ -86,7 +86,7 @@ class AsyncFFmpegWorker:
86
86
  pin_cpu_affinity: bool = True,
87
87
  total_workers: int = 1,
88
88
  # Frame optimizer options
89
- frame_optimizer_enabled: bool = True,
89
+ frame_optimizer_enabled: bool = False, # Disabled for ML quality
90
90
  frame_optimizer_config: Optional[Dict[str, Any]] = None,
91
91
  ):
92
92
  """Initialize async FFmpeg worker.
@@ -905,7 +905,7 @@ def run_ffmpeg_worker(
905
905
  shm_frame_format: str = "BGR",
906
906
  pin_cpu_affinity: bool = True,
907
907
  total_workers: int = 1,
908
- frame_optimizer_enabled: bool = True,
908
+ frame_optimizer_enabled: bool = False, # Disabled for ML quality
909
909
  frame_optimizer_config: Optional[Dict[str, Any]] = None,
910
910
  ):
911
911
  """Entry point for FFmpeg worker process.
@@ -41,7 +41,7 @@ class CameraStreamer:
41
41
  gateway_util: StreamingGatewayUtil = None,
42
42
  connection_refresh_threshold: int = 10,
43
43
  connection_refresh_interval: float = 60.0,
44
- frame_optimizer_enabled: bool = True,
44
+ frame_optimizer_enabled: bool = False, # Disabled for ML quality
45
45
  frame_optimizer_config: Optional[Dict[str, Any]] = None,
46
46
  ):
47
47
  """Initialize CameraStreamer.
@@ -315,7 +315,7 @@ class FFmpegCameraStreamer:
315
315
  shm_slot_count: int = 1000,
316
316
  shm_frame_format: str = "BGR",
317
317
  # Frame optimizer options
318
- frame_optimizer_enabled: bool = True,
318
+ frame_optimizer_enabled: bool = False, # Disabled for ML quality
319
319
  frame_optimizer_config: Optional[Dict[str, Any]] = None,
320
320
  # CPU affinity options
321
321
  pin_cpu_affinity: bool = False,
@@ -532,7 +532,7 @@ class GStreamerCameraStreamer:
532
532
  video_codec: Optional[str] = None,
533
533
  gateway_util: StreamingGatewayUtil = None,
534
534
  gstreamer_config: Optional[GStreamerConfig] = None,
535
- frame_optimizer_enabled: bool = True,
535
+ frame_optimizer_enabled: bool = False, # Disabled for ML quality
536
536
  frame_optimizer_config: Optional[Dict[str, Any]] = None,
537
537
  ):
538
538
  """Initialize GStreamerCameraStreamer.
@@ -43,9 +43,14 @@ class WorkerManager:
43
43
  # ================================================================
44
44
  # PERFORMANCE: New parameters for optimized frame capture
45
45
  # ================================================================
46
- drop_stale_frames: bool = True, # Use grab()/grab()/retrieve() for latest frame
46
+ drop_stale_frames: bool = False, # Use grab()/grab()/retrieve() for latest frame (disabled for ML quality)
47
+ use_simple_read: bool = True, # Use cap.read() directly instead of grab/retrieve
47
48
  pin_cpu_affinity: bool = True, # Pin workers to specific CPU cores
48
49
  buffer_size: int = 1, # VideoCapture buffer size (1 = minimal latency)
50
+ # ================================================================
51
+ # FRAME OPTIMIZER: Control frame similarity detection
52
+ # ================================================================
53
+ frame_optimizer_enabled: bool = False, # Enable frame similarity detection (disabled for ML quality)
49
54
  ):
50
55
  """Initialize worker manager with dynamic CPU-based scaling.
51
56
 
@@ -60,8 +65,10 @@ class WorkerManager:
60
65
  shm_slot_count: Number of frame slots per camera ring buffer
61
66
  shm_frame_format: Frame format for SHM storage
62
67
  drop_stale_frames: Use grab()/grab()/retrieve() pattern for latest frame
68
+ use_simple_read: Use cap.read() directly instead of grab/retrieve pattern
63
69
  pin_cpu_affinity: Pin worker processes to specific CPU cores for cache locality
64
70
  buffer_size: VideoCapture buffer size (1 = minimal latency)
71
+ frame_optimizer_enabled: Enable frame similarity detection (skip similar frames for bandwidth saving)
65
72
  """
66
73
  self.camera_configs = camera_configs
67
74
  self.stream_config = stream_config
@@ -119,17 +126,32 @@ class WorkerManager:
119
126
  # PERFORMANCE: Store optimized frame capture configuration
120
127
  # ================================================================
121
128
  self.drop_stale_frames = drop_stale_frames
129
+ self.use_simple_read = use_simple_read
122
130
  self.pin_cpu_affinity = pin_cpu_affinity
123
131
  self.buffer_size = buffer_size
124
132
 
125
- if drop_stale_frames or pin_cpu_affinity:
133
+ # ================================================================
134
+ # FRAME OPTIMIZER: Store frame similarity detection configuration
135
+ # ================================================================
136
+ self.frame_optimizer_enabled = frame_optimizer_enabled
137
+
138
+ if frame_optimizer_enabled:
126
139
  self.logger.info(
127
- f"PERFORMANCE OPTIMIZATIONS ENABLED: "
128
- f"drop_stale_frames={drop_stale_frames}, "
129
- f"pin_cpu_affinity={pin_cpu_affinity}, "
130
- f"buffer_size={buffer_size}"
140
+ "FRAME OPTIMIZER ENABLED: Similar frames will be skipped (may reduce ML quality)"
131
141
  )
132
142
 
143
+ if drop_stale_frames:
144
+ self.logger.info(
145
+ "DROP STALE FRAMES ENABLED: Using grab/grab/retrieve pattern (may reduce ML quality)"
146
+ )
147
+
148
+ self.logger.info(
149
+ f"Worker config: frame_optimizer={frame_optimizer_enabled}, "
150
+ f"drop_stale_frames={drop_stale_frames}, "
151
+ f"pin_cpu_affinity={pin_cpu_affinity}, "
152
+ f"buffer_size={buffer_size}"
153
+ )
154
+
133
155
  # Note: Batch parameters are calculated per-worker in _start_worker()
134
156
  # based on each worker's camera count, not the global total.
135
157
  # This ensures optimal batching when cameras are distributed across workers.
@@ -288,9 +310,12 @@ class WorkerManager:
288
310
  self.shm_frame_format,
289
311
  # PERFORMANCE: Pass optimized frame capture parameters
290
312
  self.drop_stale_frames,
313
+ self.use_simple_read,
291
314
  self.pin_cpu_affinity,
292
315
  self.num_workers, # Total workers for CPU affinity calculation
293
316
  self.buffer_size,
317
+ # FRAME OPTIMIZER: Pass frame similarity detection setting
318
+ self.frame_optimizer_enabled,
294
319
  ),
295
320
  name=f"AsyncWorker-{worker_id}",
296
321
  daemon=False # Non-daemon so we can properly wait for shutdown