matrice-streaming 0.1.64__tar.gz → 0.1.65__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.64 → matrice_streaming-0.1.65}/PKG-INFO +1 -1
  2. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/matrice_streaming.egg-info/PKG-INFO +1 -1
  3. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/nvdec.py +76 -26
  4. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/nvdec_worker_manager.py +34 -2
  5. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/LICENSE.txt +0 -0
  6. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/README.md +0 -0
  7. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/matrice_streaming.egg-info/SOURCES.txt +0 -0
  8. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/matrice_streaming.egg-info/dependency_links.txt +0 -0
  9. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/matrice_streaming.egg-info/not-zip-safe +0 -0
  10. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/matrice_streaming.egg-info/top_level.txt +0 -0
  11. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/pyproject.toml +0 -0
  12. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/setup.cfg +0 -0
  13. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/setup.py +0 -0
  14. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/__init__.py +0 -0
  15. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/client/__init__.py +0 -0
  16. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/client/client.py +0 -0
  17. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/client/client_utils.py +0 -0
  18. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/deployment/__init__.py +0 -0
  19. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/deployment/camera_manager.py +0 -0
  20. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/deployment/deployment.py +0 -0
  21. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/deployment/inference_pipeline.py +0 -0
  22. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/deployment/streaming_gateway_manager.py +0 -0
  23. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/deployment/todo.txt +0 -0
  24. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/py.typed +0 -0
  25. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/__init__.py +0 -0
  26. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/ARCHITECTURE.md +0 -0
  27. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/__init__.py +0 -0
  28. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/async_camera_worker.py +0 -0
  29. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/async_ffmpeg_worker.py +0 -0
  30. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/camera_streamer.py +0 -0
  31. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/device_detection.py +0 -0
  32. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/encoder_manager.py +0 -0
  33. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/encoding_pool_manager.py +0 -0
  34. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/ffmpeg_camera_streamer.py +0 -0
  35. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/ffmpeg_config.py +0 -0
  36. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/ffmpeg_worker_manager.py +0 -0
  37. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/frame_processor.py +0 -0
  38. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/gstreamer_camera_streamer.py +0 -0
  39. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/gstreamer_worker.py +0 -0
  40. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/gstreamer_worker_manager.py +0 -0
  41. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/message_builder.py +0 -0
  42. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/platform_pipelines.py +0 -0
  43. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/retry_manager.py +0 -0
  44. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/stream_statistics.py +0 -0
  45. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/video_capture_manager.py +0 -0
  46. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/camera_streamer/worker_manager.py +0 -0
  47. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/debug/README.md +0 -0
  48. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/debug/__init__.py +0 -0
  49. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/debug/benchmark.py +0 -0
  50. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/debug/debug_gstreamer_gateway.py +0 -0
  51. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/debug/debug_stream_backend.py +0 -0
  52. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/debug/debug_streaming_gateway.py +0 -0
  53. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/debug/debug_utils.py +0 -0
  54. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/debug/example_debug_streaming.py +0 -0
  55. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/debug/test_videoplayback.py +0 -0
  56. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/dynamic_camera_manager.py +0 -0
  57. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/event_listener.py +0 -0
  58. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/metrics_reporter.py +0 -0
  59. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/streaming_action.py +0 -0
  60. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/streaming_gateway.py +0 -0
  61. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/streaming_gateway_utils.py +0 -0
  62. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/src/matrice_streaming/streaming_gateway/streaming_status_listener.py +0 -0
  63. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/tests/test_async_infrastructure.py +0 -0
  64. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/tests/test_batch_auto_calculation.py +0 -0
  65. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/tests/test_batching_verification.py +0 -0
  66. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/tests/test_e2e_production.py +0 -0
  67. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/tests/test_flatten_binary.py +0 -0
  68. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/tests/test_gstreamer_integration.py +0 -0
  69. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/tests/test_msgpack_fix.py +0 -0
  70. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/tests/test_phase1_unit.py +0 -0
  71. {matrice_streaming-0.1.64 → matrice_streaming-0.1.65}/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.64
3
+ Version: 0.1.65
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.64
3
+ Version: 0.1.65
4
4
  Summary: Common server utilities for Matrice.ai services
5
5
  Author-email: "Matrice.ai" <dipendra@matrice.ai>
6
6
  License-Expression: MIT
@@ -714,12 +714,17 @@ def nvdec_pool_worker(
714
714
  target_w: int = 640,
715
715
  target_fps: int = 0,
716
716
  shared_frame_count: Optional[mp.Value] = None,
717
+ gpu_frame_count: Optional[mp.Value] = None,
717
718
  ):
718
719
  """NVDEC worker thread.
719
720
 
720
721
  Decodes frames and writes NV12 tensors to ring buffers.
721
722
  Uses dedicated CUDA stream per worker for kernel overlap.
722
723
  Supports FPS limiting when target_fps > 0.
724
+
725
+ Args:
726
+ shared_frame_count: Global counter (all GPUs)
727
+ gpu_frame_count: Per-GPU counter (this GPU only)
723
728
  """
724
729
  if CUPY_AVAILABLE:
725
730
  cp.cuda.Device(pool.gpu_id).use()
@@ -779,11 +784,16 @@ def nvdec_pool_worker(
779
784
  local_frames += 1
780
785
  frames_since_counter_update += 1
781
786
 
782
- # Update shared counter for real-time progress
787
+ # Update global counter (all GPUs)
783
788
  if shared_frame_count is not None:
784
789
  with shared_frame_count.get_lock():
785
790
  shared_frame_count.value += 1
786
791
 
792
+ # Update per-GPU counter (this GPU only)
793
+ if gpu_frame_count is not None:
794
+ with gpu_frame_count.get_lock():
795
+ gpu_frame_count.value += 1
796
+
787
797
  # Update next frame time for FPS limiting
788
798
  if fps_limit_enabled:
789
799
  next_frame_time += frame_interval
@@ -839,10 +849,19 @@ def nvdec_pool_process(
839
849
  num_slots: int = 32,
840
850
  target_fps: int = 0,
841
851
  shared_frame_count: Optional[mp.Value] = None,
852
+ gpu_frame_counts: Optional[Dict[int, mp.Value]] = None,
853
+ total_num_streams: int = 0,
854
+ total_num_gpus: int = 1,
842
855
  ):
843
856
  """NVDEC process for one GPU.
844
857
 
845
858
  Creates NV12 ring buffers: (H*1.5, W) = 0.6 MB/frame.
859
+
860
+ Args:
861
+ gpu_frame_counts: Dict mapping gpu_id -> per-GPU frame counter (for per-GPU stats)
862
+ shared_frame_count: Global frame counter (for overall stats)
863
+ total_num_streams: Total streams across ALL GPUs (for global per-stream calc)
864
+ total_num_gpus: Total number of GPUs (for context in logging)
846
865
  """
847
866
  if not camera_configs:
848
867
  return
@@ -851,6 +870,9 @@ def nvdec_pool_process(
851
870
  target_h = camera_configs[0].height
852
871
  target_w = camera_configs[0].width
853
872
 
873
+ # Get per-GPU counter (or fall back to shared if not provided)
874
+ gpu_frame_count = gpu_frame_counts.get(gpu_id) if gpu_frame_counts else None
875
+
854
876
  if CUPY_AVAILABLE:
855
877
  cp.cuda.Device(gpu_id).use()
856
878
 
@@ -944,6 +966,7 @@ def nvdec_pool_process(
944
966
  target_w,
945
967
  target_fps,
946
968
  shared_frame_count,
969
+ gpu_frame_count, # Per-GPU counter
947
970
  )
948
971
  )
949
972
  t.start()
@@ -952,10 +975,13 @@ def nvdec_pool_process(
952
975
  # Progress monitoring loop with current/avg FPS tracking
953
976
  start_time = time.perf_counter()
954
977
  last_report_time = start_time
955
- last_frame_count = 0
978
+ last_gpu_frame_count = 0
979
+ last_global_frame_count = 0
956
980
  report_interval = 5.0
957
981
  processing_start_time = None
958
- frames_at_processing_start = 0
982
+ gpu_frames_at_start = 0
983
+ global_frames_at_start = 0
984
+ num_gpu_streams = len(camera_configs)
959
985
 
960
986
  while not stop_event.is_set():
961
987
  current_time = time.perf_counter()
@@ -965,34 +991,58 @@ def nvdec_pool_process(
965
991
  # Periodic progress report with current and average FPS
966
992
  if current_time - last_report_time >= report_interval:
967
993
  elapsed = current_time - start_time
994
+ remaining = max(0, duration_sec - elapsed)
995
+
996
+ # Get per-GPU frame count (this GPU only)
997
+ gpu_frames = gpu_frame_count.value if gpu_frame_count else 0
998
+ gpu_interval_frames = gpu_frames - last_gpu_frame_count
999
+ gpu_interval_fps = gpu_interval_frames / report_interval
1000
+ gpu_per_stream_fps = gpu_interval_fps / num_gpu_streams if num_gpu_streams > 0 else 0
1001
+
1002
+ # Get global frame count (all GPUs)
1003
+ global_frames = shared_frame_count.value if shared_frame_count else 0
1004
+ global_interval_frames = global_frames - last_global_frame_count
1005
+ global_interval_fps = global_interval_frames / report_interval
1006
+ global_per_stream_fps = global_interval_fps / total_num_streams if total_num_streams > 0 else 0
1007
+
1008
+ # Track when processing actually starts (exclude warmup)
1009
+ if processing_start_time is None and gpu_frames > 0:
1010
+ processing_start_time = last_report_time
1011
+ gpu_frames_at_start = last_gpu_frame_count
1012
+ global_frames_at_start = last_global_frame_count
1013
+
1014
+ # Calculate average FPS excluding warmup
1015
+ if processing_start_time is not None:
1016
+ processing_elapsed = current_time - processing_start_time
968
1017
 
969
- if shared_frame_count is not None:
970
- current_frames = shared_frame_count.value
971
- interval_frames = current_frames - last_frame_count
972
- interval_fps = interval_frames / report_interval
973
- per_stream_fps = interval_fps / len(camera_configs) if camera_configs else 0
974
-
975
- # Track when processing actually starts (exclude warmup)
976
- if processing_start_time is None and current_frames > 0:
977
- processing_start_time = last_report_time
978
- frames_at_processing_start = last_frame_count
979
-
980
- # Calculate average FPS excluding warmup
981
- if processing_start_time is not None:
982
- processing_elapsed = current_time - processing_start_time
983
- processing_frames = current_frames - frames_at_processing_start
984
- avg_fps = processing_frames / processing_elapsed if processing_elapsed > 0 else 0
985
- avg_per_stream = avg_fps / len(camera_configs) if camera_configs else 0
986
- remaining = max(0, duration_sec - elapsed)
987
-
1018
+ # Per-GPU averages
1019
+ gpu_processing_frames = gpu_frames - gpu_frames_at_start
1020
+ gpu_avg_fps = gpu_processing_frames / processing_elapsed if processing_elapsed > 0 else 0
1021
+ gpu_avg_per_stream = gpu_avg_fps / num_gpu_streams if num_gpu_streams > 0 else 0
1022
+
1023
+ # Global averages
1024
+ global_processing_frames = global_frames - global_frames_at_start
1025
+ global_avg_fps = global_processing_frames / processing_elapsed if processing_elapsed > 0 else 0
1026
+ global_avg_per_stream = global_avg_fps / total_num_streams if total_num_streams > 0 else 0
1027
+
1028
+ # Log per-GPU stats
1029
+ logger.info(
1030
+ f"GPU{gpu_id} [{elapsed:5.1f}s] {gpu_frames:,} frames ({num_gpu_streams} cams) | "
1031
+ f"cur: {gpu_interval_fps:,.0f} FPS ({gpu_per_stream_fps:.1f}/cam) | "
1032
+ f"avg: {gpu_avg_fps:,.0f} FPS ({gpu_avg_per_stream:.1f}/cam)"
1033
+ )
1034
+
1035
+ # Log global stats (only from GPU0 to avoid spam)
1036
+ if gpu_id == 0:
988
1037
  logger.info(
989
- f"GPU{gpu_id} [{elapsed:5.1f}s] {current_frames:,} frames | "
990
- f"cur: {interval_fps:,.0f} FPS ({per_stream_fps:.1f}/stream) | "
991
- f"avg: {avg_fps:,.0f} FPS ({avg_per_stream:.1f}/stream) | "
1038
+ f"GLOBAL [{elapsed:5.1f}s] {global_frames:,} frames ({total_num_streams} cams, {total_num_gpus} GPUs) | "
1039
+ f"cur: {global_interval_fps:,.0f} FPS ({global_per_stream_fps:.1f}/cam) | "
1040
+ f"avg: {global_avg_fps:,.0f} FPS ({global_avg_per_stream:.1f}/cam) | "
992
1041
  f"{remaining:.0f}s left"
993
1042
  )
994
1043
 
995
- last_frame_count = current_frames
1044
+ last_gpu_frame_count = gpu_frames
1045
+ last_global_frame_count = global_frames
996
1046
  last_report_time = current_time
997
1047
 
998
1048
  time.sleep(0.1)
@@ -123,6 +123,7 @@ class NVDECWorkerManager:
123
123
  self._stop_event: Optional[mp.Event] = None
124
124
  self._result_queue: Optional[mp.Queue] = None
125
125
  self._shared_frame_count: Optional[mp.Value] = None
126
+ self._gpu_frame_counts: Dict[int, mp.Value] = {} # Per-GPU counters
126
127
  self._start_time: Optional[float] = None
127
128
  self._is_running = False
128
129
 
@@ -200,9 +201,20 @@ class NVDECWorkerManager:
200
201
  ctx = mp.get_context("spawn")
201
202
  self._stop_event = ctx.Event()
202
203
  self._result_queue = ctx.Queue()
203
- self._shared_frame_count = ctx.Value('i', 0)
204
+ self._shared_frame_count = ctx.Value('L', 0) # Global counter (all GPUs)
204
205
  self._start_time = time.perf_counter()
205
206
 
207
+ # Create per-GPU frame counters
208
+ self._gpu_frame_counts = {}
209
+ for gpu_id in range(self.num_gpus):
210
+ if self._gpu_camera_assignments[gpu_id]: # Only if GPU has cameras
211
+ self._gpu_frame_counts[gpu_id] = ctx.Value('L', 0)
212
+
213
+ total_num_streams = len(self._stream_configs)
214
+ total_num_gpus = len([g for g in range(self.num_gpus) if self._gpu_camera_assignments[g]])
215
+
216
+ logger.info(f"Starting NVDEC: {total_num_streams} cameras across {total_num_gpus} GPUs")
217
+
206
218
  # Start one process per GPU that has cameras
207
219
  for gpu_id in range(self.num_gpus):
208
220
  gpu_cameras = self._gpu_camera_assignments[gpu_id]
@@ -221,7 +233,10 @@ class NVDECWorkerManager:
221
233
  self.nvdec_burst_size, # burst_size
222
234
  self.num_slots, # num_slots
223
235
  self.target_fps, # target_fps
224
- self._shared_frame_count, # shared_frame_count
236
+ self._shared_frame_count, # shared_frame_count (global)
237
+ self._gpu_frame_counts, # gpu_frame_counts (per-GPU dict)
238
+ total_num_streams, # total_num_streams
239
+ total_num_gpus, # total_num_gpus
225
240
  ),
226
241
  name=f"NVDECWorker-GPU{gpu_id}",
227
242
  daemon=False,
@@ -311,6 +326,23 @@ class NVDECWorkerManager:
311
326
  if self._stream_configs else 0
312
327
  )
313
328
 
329
+ # Add per-GPU frame counts and FPS
330
+ if self._gpu_frame_counts and self._start_time:
331
+ elapsed = time.perf_counter() - self._start_time
332
+ gpu_stats = {}
333
+ for gpu_id, counter in self._gpu_frame_counts.items():
334
+ gpu_frames = counter.value
335
+ num_cams = len(self._gpu_camera_assignments.get(gpu_id, []))
336
+ gpu_fps = gpu_frames / elapsed if elapsed > 0 else 0
337
+ gpu_per_cam = gpu_fps / num_cams if num_cams > 0 else 0
338
+ gpu_stats[f'GPU{gpu_id}'] = {
339
+ 'frames': gpu_frames,
340
+ 'cameras': num_cams,
341
+ 'fps': gpu_fps,
342
+ 'fps_per_cam': gpu_per_cam,
343
+ }
344
+ stats['per_gpu_stats'] = gpu_stats
345
+
314
346
  # Collect any available results from queue (non-blocking)
315
347
  gpu_results = []
316
348
  if self._result_queue: