matrice-streaming 0.1.68__py3-none-any.whl → 0.1.69__py3-none-any.whl

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.
@@ -96,8 +96,23 @@ except (ImportError, AttributeError, RuntimeError, TypeError):
96
96
  CudaIpcRingBuffer = None
97
97
  GlobalFrameCounter = None
98
98
 
99
+ try:
100
+ from matrice_common.stream.gpu_camera_map import GpuCameraMap
101
+ GPU_CAMERA_MAP_AVAILABLE = True
102
+ except ImportError:
103
+ GPU_CAMERA_MAP_AVAILABLE = False
104
+ GpuCameraMap = None
105
+
99
106
  logger = logging.getLogger(__name__)
100
107
 
108
+ # =============================================================================
109
+ # Fixed dimensions for NV12 output - ALL cameras resize to this size
110
+ # This matches the TensorRT model input requirements (640x640)
111
+ # =============================================================================
112
+ TARGET_WIDTH = 640
113
+ TARGET_HEIGHT = 640
114
+ NV12_HEIGHT = TARGET_HEIGHT + TARGET_HEIGHT // 2 # 960 = H * 1.5 for NV12 format
115
+
101
116
  def setup_logging(quiet: bool = True):
102
117
  """Configure logging level based on quiet mode."""
103
118
  level = logging.WARNING if quiet else logging.INFO
@@ -407,6 +422,8 @@ class StreamState:
407
422
  width: int = 640
408
423
  height: int = 640
409
424
  empty_packets: int = 0
425
+ decode_errors: int = 0 # Consecutive decode errors
426
+ MAX_DECODE_ERRORS: int = 5 # Restart demuxer after this many consecutive errors
410
427
 
411
428
 
412
429
  # =============================================================================
@@ -664,18 +681,44 @@ class NVDECDecoderPool:
664
681
  break
665
682
 
666
683
  frames_before = frames_this_stream
667
- for surface in decoder.Decode(packet):
668
- tensor = surface_to_nv12(surface, target_h, target_w)
669
-
670
- if tensor is not None:
671
- decoded_frames.append((stream.camera_id, tensor))
672
- frames_this_stream += 1
673
- stream.frames_decoded += 1
674
- total_frames += 1
675
- stream.empty_packets = 0
676
684
 
677
- if frames_this_stream >= frames_per_stream:
678
- break
685
+ # Wrap decode loop in try/except to catch decode errors
686
+ try:
687
+ for surface in decoder.Decode(packet):
688
+ tensor = surface_to_nv12(surface, target_h, target_w)
689
+
690
+ if tensor is not None:
691
+ decoded_frames.append((stream.camera_id, tensor))
692
+ frames_this_stream += 1
693
+ stream.frames_decoded += 1
694
+ total_frames += 1
695
+ stream.empty_packets = 0
696
+ stream.decode_errors = 0 # Reset on success
697
+
698
+ if frames_this_stream >= frames_per_stream:
699
+ break
700
+
701
+ except Exception as decode_err:
702
+ # Handle decode errors - these can happen with corrupted packets
703
+ stream.decode_errors += 1
704
+ if stream.decode_errors == 1:
705
+ # Only log first error per stream to avoid spam
706
+ logger.warning(f"{stream.camera_id}: Decode error: {decode_err}")
707
+
708
+ if stream.decode_errors >= stream.MAX_DECODE_ERRORS:
709
+ # Too many consecutive errors - restart demuxer
710
+ logger.warning(
711
+ f"{stream.camera_id}: {stream.decode_errors} consecutive decode errors, "
712
+ f"restarting demuxer"
713
+ )
714
+ try:
715
+ stream.demuxer = nvc.CreateDemuxer(stream.video_path)
716
+ stream.decode_errors = 0
717
+ stream.empty_packets = 0
718
+ logger.info(f"{stream.camera_id}: Demuxer restarted successfully")
719
+ except Exception as restart_err:
720
+ logger.error(f"{stream.camera_id}: Failed to restart demuxer: {restart_err}")
721
+ break # Exit this stream's loop
679
722
 
680
723
  if frames_this_stream == frames_before:
681
724
  stream.empty_packets += 1
@@ -683,7 +726,17 @@ class NVDECDecoderPool:
683
726
  stream.demuxer = nvc.CreateDemuxer(stream.video_path)
684
727
  stream.empty_packets = 0
685
728
 
686
- except Exception:
729
+ except Exception as demux_err:
730
+ # Handle demux errors
731
+ logger.warning(f"{stream.camera_id}: Demux error: {demux_err}")
732
+ stream.decode_errors += 1
733
+ if stream.decode_errors >= stream.MAX_DECODE_ERRORS:
734
+ try:
735
+ stream.demuxer = nvc.CreateDemuxer(stream.video_path)
736
+ stream.decode_errors = 0
737
+ logger.info(f"{stream.camera_id}: Demuxer restarted after demux errors")
738
+ except Exception:
739
+ pass
687
740
  break
688
741
 
689
742
  if frames_this_stream >= frames_per_stream:
@@ -778,16 +831,28 @@ def nvdec_pool_worker(
778
831
 
779
832
  try:
780
833
  with cuda_stream:
834
+ # Always use fixed TARGET dimensions to ensure consistent NV12 output
781
835
  num_frames, decoded_frames = pool.decode_round(
782
836
  decoder_idx,
783
837
  frames_per_stream=burst_size,
784
- target_h=target_h,
785
- target_w=target_w
838
+ target_h=TARGET_HEIGHT, # Always 640
839
+ target_w=TARGET_WIDTH # Always 640
786
840
  )
787
841
 
788
842
  for cam_id, tensor in decoded_frames:
789
843
  if cam_id in ring_buffers:
790
844
  try:
845
+ # Validate frame shape matches expected NV12 dimensions
846
+ expected_shape = (NV12_HEIGHT, TARGET_WIDTH, 1) # (960, 640, 1)
847
+ if tensor.shape != expected_shape:
848
+ local_errors += 1
849
+ if local_errors <= 5:
850
+ logger.error(
851
+ f"Worker {worker_id} shape mismatch for {cam_id}: "
852
+ f"got {tensor.shape}, expected {expected_shape}"
853
+ )
854
+ continue # Skip this frame
855
+
791
856
  ring_buffers[cam_id].write_frame_fast(tensor, sync=False)
792
857
  local_frames += 1
793
858
  frames_since_counter_update += 1
@@ -932,30 +997,64 @@ def nvdec_pool_process(
932
997
  })
933
998
  return
934
999
 
935
- # Create NV12 ring buffers: (H + H/2, W, 1) = 0.6 MB/frame
1000
+ # Create NV12 ring buffers with FIXED dimensions (640x640 -> 960x640 for NV12)
1001
+ # ALL cameras resize to TARGET_WIDTH x TARGET_HEIGHT regardless of source resolution
936
1002
  ring_buffers: Dict[str, CudaIpcRingBuffer] = {}
937
- frame_size_mb = target_h * target_w * 1.5 / 1e6
1003
+ frame_size_mb = TARGET_WIDTH * NV12_HEIGHT * 1 / 1e6 # 640 * 960 * 1 channel
938
1004
 
939
1005
  try:
1006
+ # Initialize GPU camera map (producer side) - process 0 creates, others connect
1007
+ gpu_map = None
1008
+ if GPU_CAMERA_MAP_AVAILABLE:
1009
+ gpu_map = GpuCameraMap(is_producer=True)
1010
+ if process_id == 0:
1011
+ if gpu_map.initialize():
1012
+ logger.info(f"Process {process_id}: GpuCameraMap initialized")
1013
+ else:
1014
+ logger.warning(f"Process {process_id}: Failed to initialize GpuCameraMap")
1015
+ gpu_map = None
1016
+ else:
1017
+ # Wait for process 0 to initialize
1018
+ for retry in range(50):
1019
+ if gpu_map.connect():
1020
+ logger.info(f"Process {process_id}: Connected to GpuCameraMap")
1021
+ break
1022
+ time.sleep(0.1)
1023
+ else:
1024
+ logger.warning(f"Process {process_id}: Failed to connect to GpuCameraMap")
1025
+ gpu_map = None
1026
+
1027
+ # Collect GPU mappings for bulk write
1028
+ gpu_mappings = {}
1029
+
940
1030
  for i, config in enumerate(camera_configs):
1031
+ # Use fixed dimensions - ALL cameras output 640x640 (960x640 for NV12)
941
1032
  rb = CudaIpcRingBuffer.create_producer(
942
1033
  config.camera_id,
943
1034
  gpu_id=config.gpu_id,
944
1035
  num_slots=num_slots,
945
- width=config.width,
946
- height=config.height + config.height // 2, # H * 1.5 for NV12
1036
+ width=TARGET_WIDTH, # Always 640
1037
+ height=NV12_HEIGHT, # Always 960 (640 * 1.5 for NV12)
947
1038
  channels=1,
948
1039
  )
949
1040
  ring_buffers[config.camera_id] = rb
950
1041
 
1042
+ # Track GPU assignment for this camera
1043
+ gpu_mappings[config.camera_id] = config.gpu_id
1044
+
951
1045
  pool.assign_stream(
952
1046
  stream_id=i,
953
1047
  camera_id=config.camera_id,
954
1048
  video_path=config.video_path,
955
- width=config.width,
956
- height=config.height
1049
+ width=TARGET_WIDTH, # Use fixed width
1050
+ height=TARGET_HEIGHT # Use fixed height
957
1051
  )
958
1052
 
1053
+ # Write all GPU mappings at once
1054
+ if gpu_map and gpu_mappings:
1055
+ gpu_map.set_bulk_mapping(gpu_mappings)
1056
+ logger.info(f"Process {process_id}: Wrote {len(gpu_mappings)} camera-GPU mappings")
1057
+
959
1058
  logger.info(f"Process {process_id}: {pool.actual_pool_size} decoders, "
960
1059
  f"{len(camera_configs)} streams, NV12 ({frame_size_mb:.1f} MB/frame)")
961
1060
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: matrice_streaming
3
- Version: 0.1.68
3
+ Version: 0.1.69
4
4
  Summary: Common server utilities for Matrice.ai services
5
5
  Author-email: "Matrice.ai" <dipendra@matrice.ai>
6
6
  License-Expression: MIT
@@ -33,7 +33,7 @@ matrice_streaming/streaming_gateway/camera_streamer/gstreamer_camera_streamer.py
33
33
  matrice_streaming/streaming_gateway/camera_streamer/gstreamer_worker.py,sha256=AqKNJ6q_BxFphOlJ2GaS4WpoLCHXLEu5JVvoKQNrGV0,42822
34
34
  matrice_streaming/streaming_gateway/camera_streamer/gstreamer_worker_manager.py,sha256=jlKwIWWMXpztdyKiyremGmkVyw9mf2AxEmT7154xnrc,22002
35
35
  matrice_streaming/streaming_gateway/camera_streamer/message_builder.py,sha256=W295q6cIm05ReF1ooQus3rsKgZOG3EldZplbQco-OyM,10231
36
- matrice_streaming/streaming_gateway/camera_streamer/nvdec.py,sha256=Y3zhycfTpZ_bF5-Ef55J0iFi9wTLTv4Xxmw-woV1occ,53118
36
+ matrice_streaming/streaming_gateway/camera_streamer/nvdec.py,sha256=A94bIwBC9rX7AJUdNYm9KRoKgiVEgSI5z_0zMpeQZ7g,58503
37
37
  matrice_streaming/streaming_gateway/camera_streamer/nvdec_worker_manager.py,sha256=KlcwKFUPVZTQ3J1VIuhPev8Xv9BNw4dj2iLGHrREQCQ,16035
38
38
  matrice_streaming/streaming_gateway/camera_streamer/platform_pipelines.py,sha256=UNjsYYWbUJteOq2tzxISFAbWMa2e9GUExSS6fWc2Aow,27303
39
39
  matrice_streaming/streaming_gateway/camera_streamer/retry_manager.py,sha256=d8tlGoWoeSlgpCgXbUHTM61ekCQZki7TO1HzL2yPVzk,3607
@@ -49,8 +49,8 @@ matrice_streaming/streaming_gateway/debug/debug_streaming_gateway.py,sha256=ZiDg
49
49
  matrice_streaming/streaming_gateway/debug/debug_utils.py,sha256=jWcSBgrk_YVt1QzSyw6geX17YBnTvgVdA5ubqO531a0,10477
50
50
  matrice_streaming/streaming_gateway/debug/example_debug_streaming.py,sha256=-gS8zNDswAoj6oss66QQWYZhY24usfLiMH0FFK06vV0,7994
51
51
  matrice_streaming/streaming_gateway/debug/test_videoplayback.py,sha256=s_dgWkoESiuJHlUAf_iv4d7OGmAhwocwDZmIcFUZzvo,11093
52
- matrice_streaming-0.1.68.dist-info/licenses/LICENSE.txt,sha256=_uQUZpgO0mRYL5-fPoEvLSbNnLPv6OmbeEDCHXhK6Qc,1066
53
- matrice_streaming-0.1.68.dist-info/METADATA,sha256=vSC8p6EEAKwozRFvArLlVcJoipCaAe9KX7S_H9vyJ8I,2477
54
- matrice_streaming-0.1.68.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
55
- matrice_streaming-0.1.68.dist-info/top_level.txt,sha256=PM_trIe8f4JLc90J871rNMYGVM3Po9Inx4As5LrCFUU,18
56
- matrice_streaming-0.1.68.dist-info/RECORD,,
52
+ matrice_streaming-0.1.69.dist-info/licenses/LICENSE.txt,sha256=_uQUZpgO0mRYL5-fPoEvLSbNnLPv6OmbeEDCHXhK6Qc,1066
53
+ matrice_streaming-0.1.69.dist-info/METADATA,sha256=NV4zme78D-pqD9uC6HMAXCLNZHPqbQtwCT1zmiPjTnU,2477
54
+ matrice_streaming-0.1.69.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
55
+ matrice_streaming-0.1.69.dist-info/top_level.txt,sha256=PM_trIe8f4JLc90J871rNMYGVM3Po9Inx4As5LrCFUU,18
56
+ matrice_streaming-0.1.69.dist-info/RECORD,,