matrice-streaming 0.1.72__tar.gz → 0.1.73__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.72 → matrice_streaming-0.1.73}/PKG-INFO +1 -1
  2. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/matrice_streaming.egg-info/PKG-INFO +1 -1
  3. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/async_camera_worker.py +46 -13
  4. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/LICENSE.txt +0 -0
  5. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/README.md +0 -0
  6. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/matrice_streaming.egg-info/SOURCES.txt +0 -0
  7. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/matrice_streaming.egg-info/dependency_links.txt +0 -0
  8. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/matrice_streaming.egg-info/not-zip-safe +0 -0
  9. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/matrice_streaming.egg-info/top_level.txt +0 -0
  10. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/pyproject.toml +0 -0
  11. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/setup.cfg +0 -0
  12. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/setup.py +0 -0
  13. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/__init__.py +0 -0
  14. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/client/__init__.py +0 -0
  15. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/client/client.py +0 -0
  16. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/client/client_utils.py +0 -0
  17. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/deployment/__init__.py +0 -0
  18. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/deployment/camera_manager.py +0 -0
  19. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/deployment/deployment.py +0 -0
  20. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/deployment/inference_pipeline.py +0 -0
  21. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/deployment/streaming_gateway_manager.py +0 -0
  22. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/deployment/todo.txt +0 -0
  23. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/py.typed +0 -0
  24. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/__init__.py +0 -0
  25. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/ARCHITECTURE.md +0 -0
  26. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/__init__.py +0 -0
  27. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/async_ffmpeg_worker.py +0 -0
  28. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/camera_streamer.py +0 -0
  29. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/device_detection.py +0 -0
  30. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/encoder_manager.py +0 -0
  31. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/encoding_pool_manager.py +0 -0
  32. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/ffmpeg_camera_streamer.py +0 -0
  33. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/ffmpeg_config.py +0 -0
  34. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/ffmpeg_worker_manager.py +0 -0
  35. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/frame_processor.py +0 -0
  36. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/gstreamer_camera_streamer.py +0 -0
  37. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/gstreamer_worker.py +0 -0
  38. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/gstreamer_worker_manager.py +0 -0
  39. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/message_builder.py +0 -0
  40. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/nvdec.py +0 -0
  41. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/nvdec_worker_manager.py +0 -0
  42. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/platform_pipelines.py +0 -0
  43. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/retry_manager.py +0 -0
  44. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/stream_statistics.py +0 -0
  45. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/video_capture_manager.py +0 -0
  46. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/camera_streamer/worker_manager.py +0 -0
  47. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/debug/README.md +0 -0
  48. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/debug/__init__.py +0 -0
  49. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/debug/benchmark.py +0 -0
  50. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/debug/debug_gstreamer_gateway.py +0 -0
  51. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/debug/debug_stream_backend.py +0 -0
  52. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/debug/debug_streaming_gateway.py +0 -0
  53. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/debug/debug_utils.py +0 -0
  54. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/debug/example_debug_streaming.py +0 -0
  55. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/debug/test_videoplayback.py +0 -0
  56. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/dynamic_camera_manager.py +0 -0
  57. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/event_listener.py +0 -0
  58. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/metrics_reporter.py +0 -0
  59. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/streaming_action.py +0 -0
  60. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/streaming_gateway.py +0 -0
  61. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/streaming_gateway_utils.py +0 -0
  62. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/src/matrice_streaming/streaming_gateway/streaming_status_listener.py +0 -0
  63. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/tests/test_async_infrastructure.py +0 -0
  64. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/tests/test_batch_auto_calculation.py +0 -0
  65. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/tests/test_batching_verification.py +0 -0
  66. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/tests/test_e2e_production.py +0 -0
  67. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/tests/test_flatten_binary.py +0 -0
  68. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/tests/test_gstreamer_integration.py +0 -0
  69. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/tests/test_msgpack_fix.py +0 -0
  70. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/tests/test_phase1_unit.py +0 -0
  71. {matrice_streaming-0.1.72 → matrice_streaming-0.1.73}/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.72
3
+ Version: 0.1.73
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.72
3
+ Version: 0.1.73
4
4
  Summary: Common server utilities for Matrice.ai services
5
5
  Author-email: "Matrice.ai" <dipendra@matrice.ai>
6
6
  License-Expression: MIT
@@ -495,6 +495,9 @@ class AsyncCameraWorker:
495
495
  cap = None
496
496
  consecutive_failures = 0
497
497
  frame_counter = 0
498
+ # PTS-based pacing for video files
499
+ first_video_ms = None
500
+ first_wall_time = None
498
501
 
499
502
  try:
500
503
  # Prepare source (download if URL)
@@ -570,6 +573,18 @@ class AsyncCameraWorker:
570
573
  consecutive_failures = 0
571
574
  frame_counter += 1
572
575
 
576
+ # Get video file timestamp (for video files, use video PTS instead of wall clock)
577
+ # This prevents timestamp jumps when pipeline stalls
578
+ video_ts_ms = cap.get(cv2.CAP_PROP_POS_MSEC) if source_type == "video_file" else None
579
+
580
+ # Frame decimation: Read ALL frames, skip based on target FPS
581
+ # This avoids sleep-based throttling which misses frames
582
+ source_fps = video_props.get('original_fps', 30) if video_props else 30
583
+ if fps > 0 and source_fps > fps:
584
+ skip_ratio = int(source_fps / fps)
585
+ if skip_ratio > 1 and frame_counter % skip_ratio != 0:
586
+ continue # Skip this frame, read next immediately
587
+
573
588
  # Resize if needed
574
589
  if width or height:
575
590
  frame = FrameProcessor.resize_frame(frame, width, height)
@@ -581,7 +596,7 @@ class AsyncCameraWorker:
581
596
  await self._process_frame_shm_mode(
582
597
  frame, stream_key, stream_group_key, topic,
583
598
  actual_width, actual_height, frame_counter,
584
- camera_location, read_time
599
+ camera_location, read_time, video_ts_ms
585
600
  )
586
601
  else:
587
602
  # EXISTING FLOW: JPEG encode and send full frame
@@ -589,16 +604,22 @@ class AsyncCameraWorker:
589
604
  frame, stream_key, stream_group_key, topic,
590
605
  source, video_props, fps, quality,
591
606
  actual_width, actual_height, source_type,
592
- frame_counter, camera_location, read_time
607
+ frame_counter, camera_location, read_time,
608
+ video_ts_ms
593
609
  )
594
610
 
595
- # Maintain target FPS for ALL sources (video files AND live cameras)
596
- # This prevents overwhelming the encoder by reading at native camera rate (30+ FPS)
597
- frame_interval = 1.0 / fps
598
- frame_elapsed = time.time() - read_start
599
- sleep_time = max(0, frame_interval - frame_elapsed)
600
- if sleep_time > 0:
601
- await asyncio.sleep(sleep_time)
611
+ # PTS-based pacing for video files (smooth playback without drift)
612
+ # Instead of fixed-interval sleep, pace based on video timeline
613
+ if source_type == "video_file" and video_ts_ms is not None:
614
+ if first_video_ms is None:
615
+ first_video_ms = video_ts_ms
616
+ first_wall_time = time.time()
617
+ else:
618
+ # Calculate target wall time based on video PTS
619
+ target_wall = first_wall_time + (video_ts_ms - first_video_ms) / 1000.0
620
+ sleep_time = target_wall - time.time()
621
+ if sleep_time > 0:
622
+ await asyncio.sleep(sleep_time)
602
623
 
603
624
  except asyncio.CancelledError:
604
625
  self.logger.info(f"Worker {self.worker_id}: Camera {stream_key} task cancelled")
@@ -671,7 +692,8 @@ class AsyncCameraWorker:
671
692
  source_type: str,
672
693
  frame_counter: int,
673
694
  camera_location: str,
674
- read_time: float
695
+ read_time: float,
696
+ video_ts_ms: Optional[float] = None
675
697
  ):
676
698
  """Process frame and send to Redis asynchronously.
677
699
 
@@ -692,6 +714,7 @@ class AsyncCameraWorker:
692
714
  frame_counter: Current frame number
693
715
  camera_location: Camera location
694
716
  read_time: Time taken to read frame
717
+ video_ts_ms: Video file timestamp in milliseconds (None for live streams)
695
718
  """
696
719
  frame_start = time.time()
697
720
 
@@ -865,7 +888,8 @@ class AsyncCameraWorker:
865
888
  height: int,
866
889
  frame_counter: int,
867
890
  camera_location: str,
868
- read_time: float
891
+ read_time: float,
892
+ video_ts_ms: Optional[float] = None
869
893
  ):
870
894
  """SHM_MODE: Write raw frame to SHM, send metadata to Redis.
871
895
 
@@ -882,6 +906,7 @@ class AsyncCameraWorker:
882
906
  frame_counter: Current frame number
883
907
  camera_location: Camera location string
884
908
  read_time: Time taken to read frame
909
+ video_ts_ms: Video file timestamp in milliseconds (None for live streams)
885
910
  """
886
911
  frame_start = time.time()
887
912
 
@@ -895,7 +920,11 @@ class AsyncCameraWorker:
895
920
  if is_similar and reference_frame_idx is not None:
896
921
  # Frame is similar - send metadata with reference to previous frame
897
922
  # Consumer can skip reading SHM and use previous result
898
- ts_ns = int(time.time() * 1e9)
923
+ # Use video PTS for video files, wall clock for live streams
924
+ if video_ts_ms is not None:
925
+ ts_ns = int(video_ts_ms * 1e6) # Convert ms to ns
926
+ else:
927
+ ts_ns = int(time.time() * 1e9)
899
928
  shm_buffer = self._shm_buffers.get(stream_key)
900
929
 
901
930
  await self.redis_client.add_shm_metadata(
@@ -950,7 +979,11 @@ class AsyncCameraWorker:
950
979
  self._last_shm_frame_idx[stream_key] = frame_idx
951
980
 
952
981
  # Send metadata-only message to Redis
953
- ts_ns = int(time.time() * 1e9)
982
+ # Use video PTS for video files, wall clock for live streams
983
+ if video_ts_ms is not None:
984
+ ts_ns = int(video_ts_ms * 1e6) # Convert ms to ns
985
+ else:
986
+ ts_ns = int(time.time() * 1e9)
954
987
  write_start = time.time()
955
988
 
956
989
  await self.redis_client.add_shm_metadata(