@@ -30,18 +30,28 @@ def __init__(
3030 exposure_params : Optional [Tuple [int , int ]] = None ,
3131 mx_id : str = "" ,
3232 ) -> None :
33+ self ._data_h264 : Dict [str , npt .NDArray [np .uint8 ]] = {}
34+ self ._latency_h264 : Dict [str , float ] = {}
35+ self ._ts_h264 : Dict [str , timedelta ] = {}
36+
37+ self ._data_mjpeg : Dict [str , npt .NDArray [np .uint8 ]] = {}
38+ self ._latency_mjpeg : Dict [str , float ] = {}
39+ self ._ts_mjpeg : Dict [str , timedelta ] = {}
40+
41+ self ._queues_mjpeg : Dict [str , dai .DataOutputQueue ] = {}
42+
3343 super ().__init__ (
3444 cam_config_json ,
3545 fps ,
3646 force_usb2 = force_usb2 ,
37- resize = (1280 , 720 ),
47+ resize = (960 , 720 ),
3848 rectify = rectify ,
3949 exposure_params = exposure_params ,
4050 mx_id = mx_id ,
4151 isp_scale = (2 , 3 ),
4252 )
4353
44- def get_data (
54+ def get_data_h264 (
4555 self ,
4656 ) -> Tuple [Dict [str , npt .NDArray [np .uint8 ]], Dict [str , float ], Dict [str , timedelta ]]:
4757 """Extends the get_data method of the Wrapper class to return the h264 encoded left and right images.
@@ -51,32 +61,57 @@ def get_data(
5161 latencies and timestamps for each camera.
5262 """
5363
54- data , latency , ts = super ().get_data ()
64+ for name , queue in self .queues .items ():
65+ pkt = queue .get ()
66+ self ._data_h264 [name ] = pkt .getData ()
67+ self ._latency_h264 [name ] = dai .Clock .now () - pkt .getTimestamp () # type: ignore[call-arg]
68+ self ._ts_h264 [name ] = pkt .getTimestamp ()
69+
70+ return self ._data_h264 , self ._latency_h264 , self ._ts_h264
71+
72+ def get_data_mjpeg (self ) -> Tuple [Dict [str , npt .NDArray [np .uint8 ]], Dict [str , float ], Dict [str , timedelta ]]:
73+ for name , queue in self ._queues_mjpeg .items ():
74+ pkt = queue .get ()
75+ self ._data_mjpeg [name ] = pkt .getData () # type: ignore[attr-defined]
76+ self ._latency_mjpeg [name ] = dai .Clock .now () - pkt .getTimestamp () # type: ignore[attr-defined, call-arg]
77+ self ._ts_mjpeg [name ] = pkt .getTimestamp () # type: ignore[attr-defined]
5578
56- for name , pkt in data .items ():
57- data [name ] = pkt .getData ()
79+ return self ._data_mjpeg , self ._latency_mjpeg , self ._ts_mjpeg
5880
59- return data , latency , ts
81+ def _create_output_streams (self , pipeline : dai .Pipeline ) -> dai .Pipeline :
82+ super ()._create_output_streams (pipeline )
83+
84+ self .xout_left_mjpeg = pipeline .createXLinkOut ()
85+ self .xout_left_mjpeg .setStreamName ("left_mjpeg" )
86+
87+ self .xout_right_mjpeg = pipeline .createXLinkOut ()
88+ self .xout_right_mjpeg .setStreamName ("right_mjpeg" )
89+
90+ return pipeline
6091
6192 def _link_pipeline (self , pipeline : dai .Pipeline ) -> dai .Pipeline :
6293 """Overloads the base class abstract method to link the pipeline with the nodes together."""
6394
6495 self .left .isp .link (self .left_manip .inputImage )
6596 self .left_manip .out .link (self .left_encoder .input )
66- self .right .isp .link (self .right_manip .inputImage )
67- self .right_manip .out .link (self .right_encoder .input )
68-
97+ self .left_manip .out .link (self .left_encoder_mjpeg .input )
6998 self .left_encoder .bitstream .link (self .xout_left .input )
7099 self .right_encoder .bitstream .link (self .xout_right .input )
71100
101+ self .right .isp .link (self .right_manip .inputImage )
102+ self .right_manip .out .link (self .right_encoder .input )
103+ self .right_manip .out .link (self .right_encoder_mjpeg .input )
104+ self .left_encoder_mjpeg .bitstream .link (self .xout_left_mjpeg .input )
105+ self .right_encoder_mjpeg .bitstream .link (self .xout_right_mjpeg .input )
106+
72107 return pipeline
73108
74109 def _create_encoders (self , pipeline : dai .Pipeline ) -> dai .Pipeline :
75110 """Creates the h264 encoders for the left and right images."""
76111
77112 profile = dai .VideoEncoderProperties .Profile .H264_BASELINE
78113 bitrate = 4000
79- numBFrames = 0 # gstreamer recommends 0 B frames
114+ numBFrames = 0 # no B frames for streaming
80115 self .left_encoder = pipeline .create (dai .node .VideoEncoder )
81116 self .left_encoder .setDefaultProfilePreset (self .cam_config .fps , profile )
82117 self .left_encoder .setKeyframeFrequency (self .cam_config .fps ) # every 1s
@@ -91,6 +126,16 @@ def _create_encoders(self, pipeline: dai.Pipeline) -> dai.Pipeline:
91126 self .right_encoder .setBitrateKbps (bitrate )
92127 # self.right_encoder.setQuality(self.cam_config.encoder_quality)
93128
129+ profile = dai .VideoEncoderProperties .Profile .MJPEG
130+
131+ self .left_encoder_mjpeg = pipeline .create (dai .node .VideoEncoder )
132+ self .left_encoder_mjpeg .setDefaultProfilePreset (self .cam_config .fps , profile )
133+ # self.left_encoder_mjpeg.setLossless(True)
134+
135+ self .right_encoder_mjpeg = pipeline .create (dai .node .VideoEncoder )
136+ self .right_encoder_mjpeg .setDefaultProfilePreset (self .cam_config .fps , profile )
137+ # self.right_encoder_mjpeg.setLossless(True)
138+
94139 return pipeline
95140
96141 def _create_pipeline (self ) -> dai .Pipeline :
@@ -111,7 +156,11 @@ def _create_queues(self) -> Dict[str, dai.DataOutputQueue]:
111156 """Extends the base class method _create_queues() to add the h264 encoded left and right images queues."""
112157
113158 # config for video: https://docs.luxonis.com/projects/api/en/latest/components/device/#output-queue-maxsize-and-blocking
114- queues : Dict [str , dai .DataOutputQueue ] = {}
159+ queues_h264 : Dict [str , dai .DataOutputQueue ] = {}
115160 for name in ["left" , "right" ]:
116- queues [name ] = self ._device .getOutputQueue (name , maxSize = 10 , blocking = True )
117- return queues
161+ queues_h264 [name ] = self ._device .getOutputQueue (name , maxSize = 30 , blocking = True )
162+
163+ for name in ["left_mjpeg" , "right_mjpeg" ]:
164+ self ._queues_mjpeg [name ] = self ._device .getOutputQueue (name , maxSize = 1 , blocking = False )
165+
166+ return queues_h264
0 commit comments