Skip to main content

moq_mux/codec/
annexb.rs

1use bytes::{Buf, Bytes, BytesMut};
2
3pub const START_CODE: Bytes = Bytes::from_static(&[0, 0, 0, 1]);
4
5/// Annex B parsing errors.
6#[derive(Debug, Clone, thiserror::Error)]
7#[non_exhaustive]
8pub enum Error {
9	#[error("missing Annex B start code")]
10	MissingStartCode,
11
12	#[error("invalid Annex B start code")]
13	InvalidStartCode,
14
15	#[error("invalid avc1/hvc1 length size {0}")]
16	InvalidLengthSize(usize),
17
18	#[error("truncated length-prefixed NAL unit")]
19	Truncated,
20}
21
22pub type Result<T> = std::result::Result<T, Error>;
23
24/// True when the buffer is an out-of-band config record (avcC / hvcC) rather than an
25/// Annex-B elementary stream: a 3- or 4-byte start code means Annex-B, anything else
26/// non-empty is a config record. An empty buffer is Annex-B, since there's no record to
27/// parse and the in-band shapes self-initialize from the first keyframe (e.g. moqsink
28/// hands an empty init for inline-parameter-set streams).
29pub(crate) fn is_config_record(bytes: &[u8]) -> bool {
30	!(bytes.is_empty() || matches!(bytes, [0, 0, 1, ..]) || matches!(bytes, [0, 0, 0, 1, ..]))
31}
32
33/// Iterate the NAL units of a length-prefixed (avc1 / hvc1) access unit, where each NAL
34/// is preceded by a `length_size`-byte big-endian length.
35///
36/// Yields [`Error::Truncated`] as the final item when a prefix or length runs past the end
37/// of the buffer: callers that must reject a malformed AU propagate it, while a lenient
38/// scan can stop at it (`.map_while(Result::ok)`).
39pub(crate) fn length_prefixed_nals(data: &[u8], length_size: usize) -> Result<LengthPrefixedNals<'_>> {
40	if !(1..=4).contains(&length_size) {
41		return Err(Error::InvalidLengthSize(length_size));
42	}
43	Ok(LengthPrefixedNals { data, length_size })
44}
45
46/// The iterator [`length_prefixed_nals`] returns.
47pub(crate) struct LengthPrefixedNals<'a> {
48	data: &'a [u8],
49	length_size: usize,
50}
51
52impl<'a> Iterator for LengthPrefixedNals<'a> {
53	type Item = Result<&'a [u8]>;
54
55	fn next(&mut self) -> Option<Self::Item> {
56		if self.data.is_empty() {
57			return None;
58		}
59		if self.data.len() < self.length_size {
60			self.data = &[];
61			return Some(Err(Error::Truncated));
62		}
63		let (prefix, rest) = self.data.split_at(self.length_size);
64		let len = prefix.iter().fold(0usize, |acc, &byte| (acc << 8) | byte as usize);
65		if rest.len() < len {
66			self.data = &[];
67			return Some(Err(Error::Truncated));
68		}
69		let (nal, rest) = rest.split_at(len);
70		self.data = rest;
71		Some(Ok(nal))
72	}
73}
74
75/// Convert a length-prefixed NALU payload (avc1 / hvc1 wire shape) to Annex-B,
76/// optionally prepending `prefix` bytes (typically VPS/SPS/PPS NAL units already
77/// in Annex-B form, for keyframe parameter-set injection).
78pub fn from_length_prefixed(payload: &[u8], length_size: usize, prefix: Option<&[u8]>) -> Result<Bytes> {
79	let mut out = BytesMut::with_capacity(payload.len() + prefix.map(|p| p.len()).unwrap_or(0) + 16);
80	if let Some(p) = prefix {
81		out.extend_from_slice(p);
82	}
83
84	for nal in length_prefixed_nals(payload, length_size)? {
85		out.extend_from_slice(&START_CODE);
86		out.extend_from_slice(nal?);
87	}
88
89	Ok(out.freeze())
90}
91
92/// Concatenate `start_code | nal` for every NAL in `nals` and freeze the
93/// result. Used to build a keyframe parameter-set prefix for an Annex-B
94/// elementary stream.
95pub fn build_prefix<'a, I: IntoIterator<Item = &'a Bytes>>(nals: I) -> Bytes {
96	let nals: Vec<&Bytes> = nals.into_iter().collect();
97	let total: usize = nals.iter().map(|n| n.len() + START_CODE.len()).sum();
98	let mut out = BytesMut::with_capacity(total);
99	for nal in nals {
100		out.extend_from_slice(&START_CODE);
101		out.extend_from_slice(nal);
102	}
103	out.freeze()
104}
105
106/// Append `nal` to `set` unless a byte-identical entry is already present,
107/// preserving insertion order. Returns true if it was added.
108///
109/// Used to accumulate the distinct parameter-set NALs (SPS/PPS, plus VPS for
110/// H.265) a stream carries: avcC/hvcC hold an ordered list, and a source may
111/// define several (e.g. two PPS) that slices reference by id.
112pub(crate) fn push_distinct(set: &mut Vec<Bytes>, nal: &Bytes) -> bool {
113	if set.iter().any(|existing| existing == nal) {
114		return false;
115	}
116	set.push(nal.clone());
117	true
118}
119
120/// Reconcile the retained parameter sets with what a keyframe access unit carried
121/// inline, called when the keyframe slice is reached:
122///
123/// - If the AU presented its own set (`seen` non-empty), adopt it as the retained
124///   set, dropping any the new GOP no longer uses (a mid-stream reinit).
125/// - If the AU carried none, re-inject the retained set into `chunks` as Annex-B
126///   so a receiver tuning in at this keyframe still gets them.
127///
128/// `seen` is this AU's inline NALs (already appended to `chunks`); `retained` is
129/// the cross-GOP set re-injected on bare keyframes.
130pub(crate) fn reconcile_keyframe_params(chunks: &mut BytesMut, retained: &mut Vec<Bytes>, seen: &mut Vec<Bytes>) {
131	if seen.is_empty() {
132		for nal in retained.iter() {
133			chunks.extend_from_slice(&START_CODE);
134			chunks.extend_from_slice(nal);
135		}
136		seen.clone_from(retained);
137	} else if seen != retained {
138		retained.clone_from(seen);
139	}
140}
141
142pub struct NalIterator<'a, T: Buf + AsRef<[u8]> + 'a> {
143	buf: &'a mut T,
144	start: Option<usize>,
145}
146
147impl<'a, T: Buf + AsRef<[u8]> + 'a> NalIterator<'a, T> {
148	pub fn new(buf: &'a mut T) -> Self {
149		Self { buf, start: None }
150	}
151
152	/// Assume the buffer ends with a NAL unit and flush it.
153	/// This is more efficient because we cache the last "start" code position.
154	pub fn flush(self) -> Result<Option<Bytes>> {
155		let start = match self.start {
156			Some(start) => start,
157			None => {
158				let Some(start) = after_start_code(self.buf.as_ref())? else {
159					return Ok(None);
160				};
161				start
162			}
163		};
164
165		self.buf.advance(start);
166
167		let nal = self.buf.copy_to_bytes(self.buf.remaining());
168		Ok(Some(nal))
169	}
170}
171
172impl<'a, T: Buf + AsRef<[u8]> + 'a> Iterator for NalIterator<'a, T> {
173	type Item = Result<Bytes>;
174
175	fn next(&mut self) -> Option<Self::Item> {
176		let start = match self.start {
177			Some(start) => start,
178			None => match after_start_code(self.buf.as_ref()).transpose()? {
179				Ok(start) => start,
180				Err(err) => return Some(Err(err)),
181			},
182		};
183
184		let (size, new_start) = find_start_code(&self.buf.as_ref()[start..])?;
185		self.buf.advance(start);
186
187		let nal = self.buf.copy_to_bytes(size);
188		self.start = Some(new_start);
189		Some(Ok(nal))
190	}
191}
192
193/// Rewrite a length-prefixed NALU buffer (avc1/hvc1 sample, each NAL preceded
194/// by a `length_size`-byte big-endian length) into Annex-B by replacing every
195/// length prefix with a 4-byte start code. This is the inverse of the
196/// length-prefixing done by [`crate::codec::h264::Avc1`] / [`crate::codec::h265::Hvc1`].
197pub fn length_prefixed_to_annexb(data: &[u8], length_size: usize, out: &mut Vec<u8>) -> anyhow::Result<()> {
198	for nal in length_prefixed_nals(data, length_size)? {
199		out.extend_from_slice(&START_CODE);
200		out.extend_from_slice(nal?);
201	}
202	Ok(())
203}
204
205// Return the size of the start code at the start of the buffer.
206pub fn after_start_code(b: &[u8]) -> Result<Option<usize>> {
207	if b.len() < 3 {
208		return Ok(None);
209	}
210
211	// NOTE: We have to check every byte, so the `find_start_code` optimization doesn't matter.
212	if b[0] != 0 || b[1] != 0 {
213		return Err(Error::MissingStartCode);
214	}
215
216	match b[2] {
217		0 if b.len() < 4 => Ok(None),
218		0 if b[3] != 1 => Err(Error::MissingStartCode),
219		0 => Ok(Some(4)),
220		1 => Ok(Some(3)),
221		_ => Err(Error::InvalidStartCode),
222	}
223}
224
225// Return the number of bytes until the next start code, and the size of that start code.
226//
227// Both forms share the `0 0 1` suffix (3-byte is `0 0 1`, 4-byte is `0 0 0 1`), so a single
228// SIMD-accelerated substring search for `0 0 1` finds the core. We then peek one byte back to
229// decide whether a leading zero promotes it to a 4-byte code.
230pub fn find_start_code(b: &[u8]) -> Option<(usize, usize)> {
231	let core = memchr::memmem::find(b, &[0, 0, 1])?;
232	if core > 0 && b[core - 1] == 0 {
233		Some((core - 1, 4))
234	} else {
235		Some((core, 3))
236	}
237}
238
239#[cfg(test)]
240mod tests {
241	use super::*;
242
243	// Tests for from_length_prefixed - converts avc1/hvc1 to Annex-B,
244	// with optional SPS/PPS prefix injection on keyframes.
245
246	#[test]
247	fn from_length_prefixed_no_prefix() {
248		// One 4-byte length, then 2-byte NAL `0x65 0x88` (an H.264 IDR slice).
249		let payload = &[0, 0, 0, 2, 0x65, 0x88];
250		let out = from_length_prefixed(payload, 4, None).unwrap();
251		assert_eq!(out.as_ref(), &[0, 0, 0, 1, 0x65, 0x88]);
252	}
253
254	#[test]
255	fn from_length_prefixed_with_prefix_injects_verbatim() {
256		// SPS+PPS prefix built by `build_prefix` (start_code + sps_nal + start_code + pps_nal).
257		let sps = Bytes::from_static(&[0x67, 0x42, 0xc0, 0x1f]);
258		let pps = Bytes::from_static(&[0x68, 0xce, 0x3c, 0x80]);
259		let prefix = build_prefix([&sps, &pps]);
260		assert_eq!(
261			prefix.as_ref(),
262			&[
263				0, 0, 0, 1, 0x67, 0x42, 0xc0, 0x1f, // start_code + SPS
264				0, 0, 0, 1, 0x68, 0xce, 0x3c, 0x80, // start_code + PPS
265			]
266		);
267
268		// One length-prefixed IDR slice.
269		let payload = &[0, 0, 0, 2, 0x65, 0x88];
270		let out = from_length_prefixed(payload, 4, Some(&prefix)).unwrap();
271
272		// Output must start with the prefix byte-for-byte, then the slice in Annex-B form.
273		assert_eq!(&out[..prefix.len()], prefix.as_ref());
274		assert_eq!(&out[prefix.len()..], &[0, 0, 0, 1, 0x65, 0x88]);
275	}
276
277	#[test]
278	fn from_length_prefixed_multiple_nals_with_prefix() {
279		// Two NALs in one frame: AUD then IDR slice. Prefix gets prepended once.
280		let prefix = build_prefix([&Bytes::from_static(&[0x67, 0x42])]);
281		let payload = &[
282			0, 0, 0, 2, 0x09, 0x10, // AUD
283			0, 0, 0, 2, 0x65, 0x88, // IDR slice
284		];
285		let out = from_length_prefixed(payload, 4, Some(&prefix)).unwrap();
286
287		// Single prefix followed by both NALs in Annex-B order.
288		let mut expected = Vec::new();
289		expected.extend_from_slice(&prefix);
290		expected.extend_from_slice(&[0, 0, 0, 1, 0x09, 0x10]); // AUD
291		expected.extend_from_slice(&[0, 0, 0, 1, 0x65, 0x88]); // IDR
292		assert_eq!(out.as_ref(), expected.as_slice());
293	}
294
295	#[test]
296	fn length_prefixed_to_annexb_rewrites_prefixes() {
297		// Two 4-byte-length-prefixed NALs -> two start-code-delimited NALs.
298		let input = [0, 0, 0, 2, 0x67, 0x42, 0, 0, 0, 3, 0x68, 0xce, 0x3c];
299		let mut out = Vec::new();
300		length_prefixed_to_annexb(&input, 4, &mut out).unwrap();
301		assert_eq!(out, vec![0, 0, 0, 1, 0x67, 0x42, 0, 0, 0, 1, 0x68, 0xce, 0x3c]);
302	}
303
304	#[test]
305	fn length_prefixed_to_annexb_rejects_truncated() {
306		// Declared length (5) overruns the buffer.
307		let input = [0, 0, 0, 5, 0x67];
308		let mut out = Vec::new();
309		assert!(length_prefixed_to_annexb(&input, 4, &mut out).is_err());
310	}
311
312	// Tests for after_start_code - validates and measures start code at buffer beginning
313
314	#[test]
315	fn test_after_start_code_3_byte() {
316		let buf = &[0, 0, 1, 0x67];
317		assert_eq!(after_start_code(buf).unwrap(), Some(3));
318	}
319
320	#[test]
321	fn test_after_start_code_4_byte() {
322		let buf = &[0, 0, 0, 1, 0x67];
323		assert_eq!(after_start_code(buf).unwrap(), Some(4));
324	}
325
326	#[test]
327	fn test_after_start_code_too_short() {
328		let buf = &[0, 0];
329		assert_eq!(after_start_code(buf).unwrap(), None);
330	}
331
332	#[test]
333	fn test_after_start_code_incomplete_4_byte() {
334		let buf = &[0, 0, 0];
335		assert_eq!(after_start_code(buf).unwrap(), None);
336	}
337
338	#[test]
339	fn test_after_start_code_invalid_first_byte() {
340		let buf = &[1, 0, 1];
341		assert!(after_start_code(buf).is_err());
342	}
343
344	#[test]
345	fn test_after_start_code_invalid_second_byte() {
346		let buf = &[0, 1, 1];
347		assert!(after_start_code(buf).is_err());
348	}
349
350	#[test]
351	fn test_after_start_code_invalid_third_byte() {
352		let buf = &[0, 0, 2];
353		assert!(after_start_code(buf).is_err());
354	}
355
356	#[test]
357	fn test_after_start_code_invalid_4_byte_pattern() {
358		let buf = &[0, 0, 0, 2];
359		assert!(after_start_code(buf).is_err());
360	}
361
362	// Tests for find_start_code - finds next start code in NAL data
363
364	#[test]
365	fn test_find_start_code_3_byte() {
366		let buf = &[0x67, 0x42, 0x00, 0x1f, 0, 0, 1];
367		assert_eq!(find_start_code(buf), Some((4, 3)));
368	}
369
370	#[test]
371	fn test_find_start_code_4_byte() {
372		// Should detect 4-byte start code at beginning
373		let buf = &[0, 0, 0, 1, 0x67];
374		assert_eq!(find_start_code(buf), Some((0, 4)));
375	}
376
377	#[test]
378	fn test_find_start_code_4_byte_after_data() {
379		// Should detect 4-byte start code after NAL data
380		let buf = &[0x67, 0x42, 0xff, 0x1f, 0, 0, 0, 1];
381		assert_eq!(find_start_code(buf), Some((4, 4)));
382	}
383
384	#[test]
385	fn test_find_start_code_at_start_3_byte() {
386		let buf = &[0, 0, 1, 0x67];
387		assert_eq!(find_start_code(buf), Some((0, 3)));
388	}
389
390	#[test]
391	fn test_find_start_code_none() {
392		let buf = &[0x67, 0x42, 0x00, 0x1f, 0xff];
393		assert_eq!(find_start_code(buf), None);
394	}
395
396	#[test]
397	fn test_find_start_code_trailing_zeros() {
398		let buf = &[0x67, 0x42, 0x00, 0x1f, 0, 0];
399		assert_eq!(find_start_code(buf), None);
400	}
401
402	#[test]
403	fn test_find_start_code_edge_case_3_byte() {
404		let buf = &[0xff, 0, 0, 1];
405		assert_eq!(find_start_code(buf), Some((1, 3)));
406	}
407
408	#[test]
409	fn test_find_start_code_false_positive_avoidance() {
410		// Pattern like: x 0 0 y (where y != 1) - should skip ahead
411		let buf = &[0xff, 0, 0, 0xff, 0, 0, 1];
412		assert_eq!(find_start_code(buf), Some((4, 3)));
413	}
414
415	#[test]
416	fn test_find_start_code_4_byte_after_nonzero() {
417		// Critical edge case: x 0 0 0 1 should find 4-byte start code at position 1
418		// This tests that we only skip 1 byte when seeing ? ? 0 0
419		let buf = &[0xff, 0, 0, 0, 1];
420		assert_eq!(find_start_code(buf), Some((1, 4)));
421	}
422
423	#[test]
424	fn test_find_start_code_consecutive_zeros() {
425		// Multiple consecutive zeros before the 1
426		let buf = &[0xff, 0, 0, 0, 0, 0, 1];
427		// Should skip past leading zeros and find the start code
428		let result = find_start_code(buf);
429		assert!(result.is_some());
430		let (pos, size) = result.unwrap();
431		// The exact position depends on the algorithm, but it should find a valid start code
432		assert!(size == 3 || size == 4);
433		assert!(pos < buf.len());
434	}
435
436	// Tests for NalIterator - iterates over NAL units in Annex B format
437
438	#[test]
439	fn test_nal_iterator_simple_3_byte() {
440		let mut data = Bytes::from(vec![0, 0, 1, 0x67, 0x42, 0, 0, 1]);
441		let mut iter = NalIterator::new(&mut data);
442
443		let nal = iter.next().unwrap().unwrap();
444		assert_eq!(nal.as_ref(), &[0x67, 0x42]);
445		assert!(iter.next().is_none());
446
447		// Make sure the trailing 001 is still in the buffer.
448		assert_eq!(data.as_ref(), &[0, 0, 1]);
449	}
450
451	#[test]
452	fn test_nal_iterator_simple_4_byte() {
453		let mut data = Bytes::from(vec![0, 0, 0, 1, 0x67, 0x42, 0, 0, 0, 1]);
454		let mut iter = NalIterator::new(&mut data);
455
456		let nal = iter.next().unwrap().unwrap();
457		assert_eq!(nal.as_ref(), &[0x67, 0x42]);
458		assert!(iter.next().is_none());
459
460		// Make sure the trailing 0001 is still in the buffer.
461		assert_eq!(data.as_ref(), &[0, 0, 0, 1]);
462	}
463
464	#[test]
465	fn test_nal_iterator_multiple_nals() {
466		let mut data = Bytes::from(vec![0, 0, 0, 1, 0x67, 0x42, 0, 0, 0, 1, 0x68, 0xce, 0, 0, 0, 1]);
467		let mut iter = NalIterator::new(&mut data);
468
469		let nal1 = iter.next().unwrap().unwrap();
470		assert_eq!(nal1.as_ref(), &[0x67, 0x42]);
471
472		let nal2 = iter.next().unwrap().unwrap();
473		assert_eq!(nal2.as_ref(), &[0x68, 0xce]);
474
475		assert!(iter.next().is_none());
476
477		// Make sure the trailing 0001 is still in the buffer.
478		assert_eq!(data.as_ref(), &[0, 0, 0, 1]);
479	}
480
481	#[test]
482	fn test_nal_iterator_realistic_h264() {
483		// A realistic H.264 stream with SPS, PPS, and IDR
484		let mut data = Bytes::from(vec![
485			0, 0, 0, 1, 0x67, 0x42, 0x00, 0x1f, // SPS NAL
486			0, 0, 0, 1, 0x68, 0xce, 0x3c, 0x80, // PPS NAL
487			0, 0, 0, 1, 0x65, 0x88, 0x84, 0x00, // IDR slice
488			// Trailing start code (needed to detect the end of the last NAL)
489			0, 0, 0, 1,
490		]);
491		let mut iter = NalIterator::new(&mut data);
492
493		let sps = iter.next().unwrap().unwrap();
494		assert_eq!(sps[0] & 0x1f, 7); // SPS type
495		assert_eq!(sps.as_ref(), &[0x67, 0x42, 0x00, 0x1f]);
496
497		let pps = iter.next().unwrap().unwrap();
498		assert_eq!(pps[0] & 0x1f, 8); // PPS type
499		assert_eq!(pps.as_ref(), &[0x68, 0xce, 0x3c, 0x80]);
500
501		let idr = iter.next().unwrap().unwrap();
502		assert_eq!(idr[0] & 0x1f, 5); // IDR type
503		assert_eq!(idr.as_ref(), &[0x65, 0x88, 0x84, 0x00]);
504
505		assert!(iter.next().is_none());
506
507		// Make sure the trailing 0001 is still in the buffer.
508		assert_eq!(data.as_ref(), &[0, 0, 0, 1]);
509	}
510
511	#[test]
512	fn test_nal_iterator_realistic_h265() {
513		// A realistic H.265 stream with VPS, SPS, PPS, and IDR
514		let mut data = Bytes::from(vec![
515			0, 0, 0, 1, 0x40, 0x01, 0x0c, 0x01, // VPS NAL
516			0, 0, 0, 1, 0x42, 0x01, 0x01, 0x60, // SPS NAL
517			0, 0, 0, 1, 0x44, 0x01, 0xc0, 0xf1, // PPS NAL
518			0, 0, 0, 1, 0x26, 0x01, 0x9a, 0x20, // IDR_W_RADL slice
519			// Trailing start code (needed to detect the end of the last NAL)
520			0, 0, 0, 1,
521		]);
522		let mut iter = NalIterator::new(&mut data);
523
524		let vps = iter.next().unwrap().unwrap();
525		assert_eq!((vps[0] >> 1) & 0x3f, 32); // VPS type
526		assert_eq!(vps.as_ref(), &[0x40, 0x01, 0x0c, 0x01]);
527
528		let sps = iter.next().unwrap().unwrap();
529		assert_eq!((sps[0] >> 1) & 0x3f, 33); // SPS type
530		assert_eq!(sps.as_ref(), &[0x42, 0x01, 0x01, 0x60]);
531
532		let pps = iter.next().unwrap().unwrap();
533		assert_eq!((pps[0] >> 1) & 0x3f, 34); // PPS type
534		assert_eq!(pps.as_ref(), &[0x44, 0x01, 0xc0, 0xf1]);
535
536		let idr = iter.next().unwrap().unwrap();
537		assert_eq!((idr[0] >> 1) & 0x3f, 19); // IDR slice type (IDR_W_RADL)
538		assert_eq!(idr.as_ref(), &[0x26, 0x01, 0x9a, 0x20]);
539
540		assert!(iter.next().is_none());
541
542		// Make sure the trailing 0001 is still in the buffer.
543		assert_eq!(data.as_ref(), &[0, 0, 0, 1]);
544	}
545
546	#[test]
547	fn test_nal_iterator_invalid_start() {
548		let mut data = Bytes::from(vec![1, 0, 1, 0x67]);
549		let mut iter = NalIterator::new(&mut data);
550
551		assert!(iter.next().unwrap().is_err());
552
553		// Make sure the data is still in the buffer.
554		assert_eq!(data.as_ref(), &[1, 0, 1, 0x67]);
555	}
556
557	#[test]
558	fn test_nal_iterator_empty_nal() {
559		// Two consecutive start codes create an empty NAL
560		let mut data = Bytes::from(vec![0, 0, 1, 0, 0, 1, 0x67, 0, 0, 1]);
561		let mut iter = NalIterator::new(&mut data);
562
563		let nal1 = iter.next().unwrap().unwrap();
564		assert_eq!(nal1.len(), 0);
565
566		let nal2 = iter.next().unwrap().unwrap();
567		assert_eq!(nal2.as_ref(), &[0x67]);
568
569		assert!(iter.next().is_none());
570
571		// Make sure the data is still in the buffer.
572		assert_eq!(data.as_ref(), &[0, 0, 1]);
573	}
574
575	#[test]
576	fn test_nal_iterator_nal_with_embedded_zeros() {
577		// NAL data that contains zeros (but not a start code pattern)
578		let mut data = Bytes::from(vec![
579			0, 0, 1, 0x67, 0x00, 0x00, 0x00, 0xff, // NAL with embedded zeros
580			0, 0, 1, 0x68, // Next NAL
581			0, 0, 1,
582		]);
583		let mut iter = NalIterator::new(&mut data);
584
585		let nal1 = iter.next().unwrap().unwrap();
586		assert_eq!(nal1.as_ref(), &[0x67, 0x00, 0x00, 0x00, 0xff]);
587
588		let nal2 = iter.next().unwrap().unwrap();
589		assert_eq!(nal2.as_ref(), &[0x68]);
590
591		assert!(iter.next().is_none());
592
593		// Make sure the data is still in the buffer.
594		assert_eq!(data.as_ref(), &[0, 0, 1]);
595	}
596
597	// Tests for flush - extracts final NAL without trailing start code
598
599	#[test]
600	fn test_flush_after_iteration() {
601		// Normal case: iterate over NALs, then flush the final one
602		let mut data = Bytes::from(vec![
603			0, 0, 0, 1, 0x67, 0x42, // First NAL
604			0, 0, 0, 1, 0x68, 0xce, 0x3c, 0x80, // Second NAL (final, no trailing start code)
605		]);
606		let mut iter = NalIterator::new(&mut data);
607
608		let nal1 = iter.next().unwrap().unwrap();
609		assert_eq!(nal1.as_ref(), &[0x67, 0x42]);
610
611		assert!(iter.next().is_none());
612
613		let final_nal = iter.flush().unwrap().unwrap();
614		assert_eq!(final_nal.as_ref(), &[0x68, 0xce, 0x3c, 0x80]);
615	}
616
617	#[test]
618	fn test_flush_single_nal() {
619		// Buffer contains only a single NAL with no trailing start code
620		let mut data = Bytes::from(vec![0, 0, 1, 0x67, 0x42, 0x00, 0x1f]);
621		let iter = NalIterator::new(&mut data);
622
623		let final_nal = iter.flush().unwrap().unwrap();
624		assert_eq!(final_nal.as_ref(), &[0x67, 0x42, 0x00, 0x1f]);
625	}
626
627	#[test]
628	fn test_flush_4_byte_start_code() {
629		// Test flush with 4-byte start code
630		let mut data = Bytes::from(vec![0, 0, 0, 1, 0x65, 0x88, 0x84, 0x00, 0xff]);
631		let iter = NalIterator::new(&mut data);
632
633		let final_nal = iter.flush().unwrap().unwrap();
634		assert_eq!(final_nal.as_ref(), &[0x65, 0x88, 0x84, 0x00, 0xff]);
635	}
636
637	#[test]
638	fn test_flush_no_start_code() {
639		// Buffer doesn't start with a start code and has no cached start position
640		let mut data = Bytes::from(vec![0x67, 0x42, 0x00, 0x1f]);
641		let iter = NalIterator::new(&mut data);
642
643		let result = iter.flush();
644		assert!(result.is_err());
645	}
646
647	#[test]
648	fn test_flush_empty_buffer() {
649		// Empty buffer should return None
650		let mut data = Bytes::from(vec![]);
651		let iter = NalIterator::new(&mut data);
652
653		let result = iter.flush().unwrap();
654		assert!(result.is_none());
655	}
656
657	#[test]
658	fn test_flush_incomplete_start_code() {
659		// Buffer has incomplete start code (not enough bytes)
660		let mut data = Bytes::from(vec![0, 0]);
661		let iter = NalIterator::new(&mut data);
662
663		let result = iter.flush().unwrap();
664		assert!(result.is_none());
665	}
666
667	#[test]
668	fn test_flush_multiple_nals_then_flush() {
669		// Iterate over multiple NALs, then flush the final one
670		let mut data = Bytes::from(vec![
671			0, 0, 0, 1, 0x67, 0x42, // SPS
672			0, 0, 0, 1, 0x68, 0xce, // PPS
673			0, 0, 0, 1, 0x65, 0x88, 0x84, // IDR (final NAL)
674		]);
675		let mut iter = NalIterator::new(&mut data);
676
677		let sps = iter.next().unwrap().unwrap();
678		assert_eq!(sps.as_ref(), &[0x67, 0x42]);
679
680		let pps = iter.next().unwrap().unwrap();
681		assert_eq!(pps.as_ref(), &[0x68, 0xce]);
682
683		assert!(iter.next().is_none());
684
685		let idr = iter.flush().unwrap().unwrap();
686		assert_eq!(idr.as_ref(), &[0x65, 0x88, 0x84]);
687	}
688
689	#[test]
690	fn test_flush_empty_final_nal() {
691		// Edge case: final NAL is empty (just a start code with no data)
692		let mut data = Bytes::from(vec![
693			0, 0, 0, 1, 0x67, 0x42, // First NAL
694			0, 0, 0, 1, // Second NAL (empty)
695		]);
696		let mut iter = NalIterator::new(&mut data);
697
698		let nal1 = iter.next().unwrap().unwrap();
699		assert_eq!(nal1.as_ref(), &[0x67, 0x42]);
700
701		assert!(iter.next().is_none());
702
703		let final_nal = iter.flush().unwrap().unwrap();
704		assert_eq!(final_nal.len(), 0);
705	}
706}