@@ -110,6 +110,9 @@ class LiveVideoSource : public VideoDecoder, public T::Callback
110110 webrtc::ArrayView<const uint8_t > data (buffer, size);
111111 std::vector<webrtc::H264::NaluIndex> indexes = webrtc::H264::FindNaluIndices (data);
112112 RTC_LOG (LS_VERBOSE) << " LiveVideoSource:onData nbNalu:" << indexes.size ();
113+ // Support multi-slice IDR: accumulate all IDR slices (and SPS/PPS cfg) into a single access unit
114+ std::vector<uint8_t > idrContent; // holds concatenated IDR slices + config
115+ int idrSliceCount = 0 ;
113116 for (const webrtc::H264::NaluIndex & index : indexes) {
114117 webrtc::H264::NaluType nalu_type = webrtc::H264::ParseNaluType (buffer[index.payload_start_offset ]);
115118 RTC_LOG (LS_VERBOSE) << " LiveVideoSource:onData NALU type:" << nalu_type << " payload_size:" << index.payload_size << " payload_start_offset:" << index.payload_start_offset << " start_offset:" << index.start_offset ;
@@ -137,18 +140,26 @@ class LiveVideoSource : public VideoDecoder, public T::Callback
137140 RTC_LOG (LS_VERBOSE) << " LiveVideoSource:onData PPS" ;
138141 m_cfg.insert (m_cfg.end (), buffer + index.start_offset , buffer + index.payload_size + index.payload_start_offset );
139142 }
140- else if (nalu_type == webrtc::H264::NaluType::kSei )
143+ else if (nalu_type == webrtc::H264::NaluType::kSei )
141144 {
142- }
145+ }
143146 else
144147 {
145148 webrtc::VideoFrameType frameType = webrtc::VideoFrameType::kVideoFrameDelta ;
146149 std::vector<uint8_t > content;
147150 if (nalu_type == webrtc::H264::NaluType::kIdr )
148151 {
152+ // Multi-slice IDR handling: accumulate and defer posting until all slices processed
149153 frameType = webrtc::VideoFrameType::kVideoFrameKey ;
150- RTC_LOG (LS_VERBOSE) << " LiveVideoSource:onData IDR" ;
151- content.insert (content.end (), m_cfg.begin (), m_cfg.end ());
154+ RTC_LOG (LS_VERBOSE) << " LiveVideoSource:onData IDR slice" ;
155+ if (idrSliceCount == 0 ) {
156+ // first IDR slice: prepend SPS/PPS config
157+ idrContent.insert (idrContent.end (), m_cfg.begin (), m_cfg.end ());
158+ }
159+ idrContent.insert (idrContent.end (), buffer + index.start_offset , buffer + index.payload_size + index.payload_start_offset );
160+ idrSliceCount++;
161+ // do not post yet; continue to gather potential further IDR slices
162+ continue ;
152163 }
153164 else
154165 {
@@ -165,11 +176,20 @@ class LiveVideoSource : public VideoDecoder, public T::Callback
165176 }
166177 }
167178 }
179+ // After processing all NALUs, if we collected IDR slices, post them as a single key frame
180+ if (idrSliceCount > 0 ) {
181+ webrtc::scoped_refptr<webrtc::EncodedImageBuffer> frame = webrtc::EncodedImageBuffer::Create (idrContent.data (), idrContent.size ());
182+ PostFrame (frame, ts, webrtc::VideoFrameType::kVideoFrameKey );
183+ RTC_LOG (LS_VERBOSE) << " LiveVideoSource:onData posted multi-slice IDR frame slices=" << idrSliceCount << " total_size=" << idrContent.size ();
184+ }
168185 }
169186
170187 void onH265Data (unsigned char *buffer, ssize_t size, int64_t ts, const std::string & codec) {
171188 std::vector<webrtc::H265::NaluIndex> indexes = webrtc::H265::FindNaluIndices (buffer,size);
172189 RTC_LOG (LS_VERBOSE) << " LiveVideoSource:onData nbNalu:" << indexes.size ();
190+ // Support multi-slice IDR: accumulate all IDR slices (and VPS/SPS/PPS cfg) into a single access unit
191+ std::vector<uint8_t > idrContentH265;
192+ int idrSliceCountH265 = 0 ;
173193 for (const webrtc::H265::NaluIndex & index : indexes) {
174194 webrtc::H265::NaluType nalu_type = webrtc::H265::ParseNaluType (buffer[index.payload_start_offset ]);
175195 RTC_LOG (LS_VERBOSE) << " LiveVideoSource:onData NALU type:" << nalu_type << " payload_size:" << index.payload_size << " payload_start_offset:" << index.payload_start_offset << " start_offset:" << index.start_offset ;
@@ -207,9 +227,17 @@ class LiveVideoSource : public VideoDecoder, public T::Callback
207227 std::vector<uint8_t > content;
208228 if ( (nalu_type == webrtc::H265::NaluType::kIdrWRadl ) || (nalu_type == webrtc::H265::NaluType::kIdrNLp ) )
209229 {
230+ // Multi-slice IDR handling: accumulate and defer posting until all slices processed
210231 frameType = webrtc::VideoFrameType::kVideoFrameKey ;
211- RTC_LOG (LS_VERBOSE) << " LiveVideoSource:onData IDR" ;
212- content.insert (content.end (), m_cfg.begin (), m_cfg.end ());
232+ RTC_LOG (LS_VERBOSE) << " LiveVideoSource:onData IDR slice" ;
233+ if (idrSliceCountH265 == 0 ) {
234+ // first IDR slice: prepend VPS/SPS/PPS config
235+ idrContentH265.insert (idrContentH265.end (), m_cfg.begin (), m_cfg.end ());
236+ }
237+ idrContentH265.insert (idrContentH265.end (), buffer + index.start_offset , buffer + index.payload_size + index.payload_start_offset );
238+ idrSliceCountH265++;
239+ // do not post yet; continue to gather potential further IDR slices
240+ continue ;
213241 }
214242 else
215243 {
@@ -226,6 +254,12 @@ class LiveVideoSource : public VideoDecoder, public T::Callback
226254 }
227255 }
228256 }
257+ // After processing all NALUs, if we collected IDR slices, post them as a single key frame
258+ if (idrSliceCountH265 > 0 ) {
259+ webrtc::scoped_refptr<webrtc::EncodedImageBuffer> frame = webrtc::EncodedImageBuffer::Create (idrContentH265.data (), idrContentH265.size ());
260+ PostFrame (frame, ts, webrtc::VideoFrameType::kVideoFrameKey );
261+ RTC_LOG (LS_VERBOSE) << " LiveVideoSource:onData posted H265 multi-slice IDR frame slices=" << idrSliceCountH265 << " total_size=" << idrContentH265.size ();
262+ }
229263 }
230264
231265 int onJPEGData (unsigned char *buffer, ssize_t size, int64_t ts, const std::string & codec) {
0 commit comments