1mod export;
14mod import;
15mod split;
16
17pub use export::*;
18pub use import::*;
19pub use split::*;
20
21use bytes::{Buf, BufMut, Bytes, BytesMut};
22
23const NAL_TYPE_SPS: u8 = 7;
25const NAL_TYPE_PPS: u8 = 8;
26
27pub(crate) fn avc1_frame(
35 data: impl moq_net::IntoBytes,
36 length_size: usize,
37 pts: moq_net::Timestamp,
38) -> crate::Result<crate::container::Frame> {
39 let keyframe = avc1_is_keyframe(data.as_ref(), length_size);
40 Ok(crate::container::Frame {
41 timestamp: pts,
42 payload: data.into_bytes(),
43 keyframe,
44 duration: None,
45 })
46}
47
48fn avc1_is_keyframe(data: &[u8], length_size: usize) -> bool {
50 let Ok(nals) = crate::codec::annexb::length_prefixed_nals(data, length_size) else {
51 return false;
52 };
53 nals.map_while(std::result::Result::ok)
54 .any(|nal| nal.first().is_some_and(|header| header & 0x1f == 5))
55}
56
57#[derive(Debug, Clone, thiserror::Error)]
59#[non_exhaustive]
60pub enum Error {
61 #[error("SPS NAL too short")]
62 SpsTooShort,
63
64 #[error("failed to parse SPS")]
65 SpsParse,
66
67 #[error("AVCDecoderConfigurationRecord too short")]
68 AvccTooShort,
69
70 #[error("AVCDecoderConfigurationRecord truncated")]
71 AvccTruncated,
72
73 #[error("avc1 description for rendition {name:?} is missing SPS or PPS (sps={sps}, pps={pps})")]
74 MissingParamSets { name: String, sps: usize, pps: usize },
75
76 #[error("SPS too large for avcC length field ({0} > {max})", max = u16::MAX)]
77 SpsTooLarge(usize),
78
79 #[error("PPS too large for avcC length field ({0} > {max})", max = u16::MAX)]
80 PpsTooLarge(usize),
81
82 #[error("avcC requires at least one SPS")]
83 MissingSps,
84
85 #[error("too many SPS for avcC ({0} > 31)")]
86 TooManySps(usize),
87
88 #[error("too many PPS for avcC ({0} > 255)")]
89 TooManyPps(usize),
90
91 #[error("NAL too large for 4-byte length prefix")]
92 NalTooLarge,
93
94 #[error("NAL unit is too short")]
95 NalTooShort,
96
97 #[error("forbidden zero bit is not zero")]
98 ForbiddenZeroBit,
99
100 #[error("not initialized")]
101 NotInitialized,
102
103 #[error("avc3 track not created")]
104 Avc3TrackNotCreated,
105
106 #[error("missing timestamp")]
107 MissingTimestamp,
108
109 #[error("annexb: {0}")]
110 Annexb(#[from] crate::codec::annexb::Error),
111}
112
113pub type Result<T> = std::result::Result<T, Error>;
114
115#[derive(Debug, Clone)]
121pub struct Sps {
122 pub profile: u8,
123 pub constraints: u8,
124 pub level: u8,
125 pub coded_width: u32,
126 pub coded_height: u32,
127}
128
129impl Sps {
130 pub fn parse(nal: &[u8]) -> Result<Self> {
132 if nal.len() < 4 {
133 return Err(Error::SpsTooShort);
134 }
135 let rbsp = h264_parser::nal::ebsp_to_rbsp(&nal[1..]);
136 let sps = h264_parser::Sps::parse(&rbsp).map_err(|_| Error::SpsParse)?;
137 Ok(Self {
138 profile: sps.profile_idc,
139 constraints: pack_constraint_flags(&sps),
140 level: sps.level_idc,
141 coded_width: sps.width,
142 coded_height: sps.height,
143 })
144 }
145}
146
147pub(crate) fn sps_reorder(nal: &[u8]) -> Option<crate::codec::video::Reorder> {
152 let vui = sps_vui(nal)?;
153 Some(crate::codec::video::Reorder {
154 depth: vui.depth?,
155 period: vui.period,
156 })
157}
158
159pub(crate) fn sps_framerate(nal: &[u8]) -> Option<f64> {
165 let vui = sps_vui(nal)?;
166 if !vui.frame_only {
167 return None;
168 }
169 let (units, scale) = vui.period?;
170 Some(scale as f64 / units as f64)
171}
172
173struct Vui {
175 frame_only: bool,
177 period: Option<(u64, u64)>,
179 depth: Option<u32>,
181}
182
183fn sps_vui(nal: &[u8]) -> Option<Vui> {
185 if nal.len() < 4 {
186 return None;
187 }
188 let rbsp = h264_parser::nal::ebsp_to_rbsp(&nal[1..]);
189 let sps = h264_parser::Sps::parse(&rbsp).ok()?;
190 if !sps.vui_parameters_present_flag {
191 return None;
192 }
193 vui(&rbsp).ok().flatten()
194}
195
196fn vui(rbsp: &[u8]) -> h264_parser::Result<Option<Vui>> {
200 use h264_parser::bitreader::BitReader;
201 use h264_parser::eg::{read_se, read_ue};
202
203 let mut r = BitReader::new(rbsp);
204 let profile_idc = r.read_u8()?;
205 r.skip_bits(16)?; read_ue(&mut r)?; if matches!(
208 profile_idc,
209 100 | 110 | 122 | 244 | 44 | 83 | 86 | 118 | 128 | 138 | 139 | 134 | 135
210 ) {
211 let chroma_format_idc = read_ue(&mut r)?;
212 if chroma_format_idc == 3 {
213 r.skip_bits(1)?; }
215 read_ue(&mut r)?; read_ue(&mut r)?; r.skip_bits(1)?; if r.read_flag()? {
219 let lists = if chroma_format_idc == 3 { 12 } else { 8 };
220 for i in 0..lists {
221 if r.read_flag()? {
222 let size = if i < 6 { 16 } else { 64 };
223 let (mut last, mut next) = (8i32, 8i32);
224 for _ in 0..size {
225 if next != 0 {
226 next = (last + read_se(&mut r)?).rem_euclid(256);
227 }
228 if next != 0 {
229 last = next;
230 }
231 }
232 }
233 }
234 }
235 }
236 read_ue(&mut r)?; match read_ue(&mut r)? {
238 0 => {
239 read_ue(&mut r)?; }
241 1 => {
242 r.skip_bits(1)?; read_se(&mut r)?; read_se(&mut r)?; for _ in 0..read_ue(&mut r)? {
246 read_se(&mut r)?; }
248 }
249 _ => {}
250 }
251 read_ue(&mut r)?; r.skip_bits(1)?; read_ue(&mut r)?; read_ue(&mut r)?; let frame_only = r.read_flag()?; if !frame_only {
257 r.skip_bits(1)?; }
259 r.skip_bits(1)?; if r.read_flag()? {
261 for _ in 0..4 {
262 read_ue(&mut r)?; }
264 }
265 if !r.read_flag()? {
266 return Ok(None);
267 }
268
269 if r.read_flag()? && r.read_u8()? == 255 {
271 r.skip_bits(32)?; }
273 if r.read_flag()? {
274 r.skip_bits(1)?; }
276 if r.read_flag()? {
277 r.skip_bits(4)?; if r.read_flag()? {
279 r.skip_bits(24)?; }
281 }
282 if r.read_flag()? {
283 read_ue(&mut r)?; read_ue(&mut r)?; }
286 let mut period = None;
287 if r.read_flag()? {
288 let units = r.read_bits(32)?;
289 let scale = r.read_bits(32)?;
290 if r.read_flag()? && units > 0 && scale > 0 {
292 period = Some((2 * u64::from(units), u64::from(scale)));
293 }
294 }
295 let nal_hrd = r.read_flag()?;
296 if nal_hrd {
297 skip_hrd(&mut r)?;
298 }
299 let vcl_hrd = r.read_flag()?;
300 if vcl_hrd {
301 skip_hrd(&mut r)?;
302 }
303 if nal_hrd || vcl_hrd {
304 r.skip_bits(1)?; }
306 r.skip_bits(1)?; if !r.read_flag()? {
308 return Ok(Some(Vui {
309 frame_only,
310 period,
311 depth: None,
312 }));
313 }
314 r.skip_bits(1)?; for _ in 0..4 {
316 read_ue(&mut r)?; }
318 let depth = read_ue(&mut r)?; Ok(Some(Vui {
320 frame_only,
321 period,
322 depth: Some(depth),
323 }))
324}
325
326fn skip_hrd(r: &mut h264_parser::bitreader::BitReader) -> h264_parser::Result<()> {
328 use h264_parser::eg::read_ue;
329
330 let cpb_cnt_minus1 = read_ue(r)?;
331 if cpb_cnt_minus1 > 31 {
332 return Err(h264_parser::Error::MalformedSps("cpb_cnt_minus1 out of range".into()));
333 }
334 r.skip_bits(8)?; for _ in 0..=cpb_cnt_minus1 {
336 read_ue(r)?; read_ue(r)?; r.skip_bits(1)?; }
340 r.skip_bits(20) }
342
343#[derive(Debug, Clone)]
349#[non_exhaustive]
350pub struct Avcc {
351 pub profile: u8,
353 pub constraints: u8,
355 pub level: u8,
357 pub length_size: usize,
359 pub sps: Vec<Bytes>,
361 pub pps: Vec<Bytes>,
363 pub coded_width: Option<u32>,
365 pub coded_height: Option<u32>,
366}
367
368impl Avcc {
369 pub fn parse(avcc: &[u8]) -> Result<Self> {
371 if avcc.len() < 7 {
372 return Err(Error::AvccTooShort);
373 }
374
375 let profile = avcc[1];
376 let constraints = avcc[2];
377 let level = avcc[3];
378 let length_size = (avcc[4] & 0x03) as usize + 1;
379 let num_sps = (avcc[5] & 0x1f) as usize;
380
381 let mut pos = 6;
382 let sps = read_param_sets(avcc, &mut pos, num_sps)?;
383
384 if avcc.len() <= pos {
385 return Err(Error::AvccTruncated);
386 }
387 let num_pps = avcc[pos] as usize;
388 pos += 1;
389 let pps = read_param_sets(avcc, &mut pos, num_pps)?;
390
391 let (mut coded_width, mut coded_height) = (None, None);
393 if let Some(first) = sps.first()
394 && first.len() > 1
395 && let Ok(parsed) = Sps::parse(first)
396 {
397 coded_width = Some(parsed.coded_width);
398 coded_height = Some(parsed.coded_height);
399 }
400
401 Ok(Self {
402 profile,
403 constraints,
404 level,
405 length_size,
406 sps,
407 pps,
408 coded_width,
409 coded_height,
410 })
411 }
412}
413
414fn pack_constraint_flags(sps: &h264_parser::Sps) -> u8 {
415 ((sps.constraint_set0_flag as u8) << 7)
416 | ((sps.constraint_set1_flag as u8) << 6)
417 | ((sps.constraint_set2_flag as u8) << 5)
418 | ((sps.constraint_set3_flag as u8) << 4)
419 | ((sps.constraint_set4_flag as u8) << 3)
420 | ((sps.constraint_set5_flag as u8) << 2)
421}
422
423pub(crate) fn build_avcc(sps_nals: &[Bytes], pps_nals: &[Bytes]) -> Result<Bytes> {
429 let first_sps = sps_nals.first().ok_or(Error::MissingSps)?;
430 if first_sps.len() < 4 {
431 return Err(Error::SpsTooShort);
432 }
433 if sps_nals.len() > 0x1f {
435 return Err(Error::TooManySps(sps_nals.len()));
436 }
437 if pps_nals.len() > u8::MAX as usize {
438 return Err(Error::TooManyPps(pps_nals.len()));
439 }
440 for sps in sps_nals {
441 if sps.len() > u16::MAX as usize {
442 return Err(Error::SpsTooLarge(sps.len()));
443 }
444 }
445 for pps in pps_nals {
446 if pps.len() > u16::MAX as usize {
447 return Err(Error::PpsTooLarge(pps.len()));
448 }
449 }
450
451 let profile_idc = first_sps[1];
452 let constraints = first_sps[2];
453 let level_idc = first_sps[3];
454
455 let payload: usize = sps_nals.iter().chain(pps_nals).map(|n| 2 + n.len()).sum();
456 let mut out = BytesMut::with_capacity(7 + payload);
457 out.put_u8(1); out.put_u8(profile_idc);
459 out.put_u8(constraints);
460 out.put_u8(level_idc);
461 out.put_u8(0xff); out.put_u8(0xe0 | sps_nals.len() as u8); for sps in sps_nals {
464 out.put_u16(sps.len() as u16);
465 out.put_slice(sps);
466 }
467 out.put_u8(pps_nals.len() as u8); for pps in pps_nals {
469 out.put_u16(pps.len() as u16);
470 out.put_slice(pps);
471 }
472 Ok(out.freeze())
473}
474
475fn read_param_sets(buf: &[u8], pos: &mut usize, count: usize) -> Result<Vec<Bytes>> {
479 let mut out = Vec::with_capacity(count);
480 for _ in 0..count {
481 let after_len = pos.checked_add(2).ok_or(Error::AvccTruncated)?;
482 if buf.len() < after_len {
483 return Err(Error::AvccTruncated);
484 }
485 let len = u16::from_be_bytes([buf[*pos], buf[*pos + 1]]) as usize;
486 let after_nal = after_len.checked_add(len).ok_or(Error::AvccTruncated)?;
487 if buf.len() < after_nal {
488 return Err(Error::AvccTruncated);
489 }
490 out.push(Bytes::copy_from_slice(&buf[after_len..after_nal]));
491 *pos = after_nal;
492 }
493 Ok(out)
494}
495
496pub(crate) fn avcc_params(avcc: &[u8]) -> anyhow::Result<(usize, Vec<Bytes>)> {
500 anyhow::ensure!(avcc.len() >= 6, "AVCDecoderConfigurationRecord too short");
501 let length_size = (avcc[4] & 0x03) as usize + 1;
502
503 let mut params = Vec::new();
504 let num_sps = avcc[5] & 0x1f;
505 let mut pos = read_param_set_array(avcc, 6, num_sps as usize, &mut params)?;
506
507 anyhow::ensure!(avcc.len() > pos, "avcC missing PPS count");
508 let num_pps = avcc[pos];
509 pos += 1;
510 read_param_set_array(avcc, pos, num_pps as usize, &mut params)?;
511
512 Ok((length_size, params))
513}
514
515fn read_param_set_array(buf: &[u8], mut pos: usize, count: usize, params: &mut Vec<Bytes>) -> anyhow::Result<usize> {
518 for _ in 0..count {
519 anyhow::ensure!(buf.len() >= pos + 2, "truncated parameter-set length");
520 let len = u16::from_be_bytes([buf[pos], buf[pos + 1]]) as usize;
521 pos += 2;
522 anyhow::ensure!(buf.len() >= pos + len, "parameter-set NAL exceeds buffer");
523 params.push(Bytes::copy_from_slice(&buf[pos..pos + len]));
524 pos += len;
525 }
526 Ok(pos)
527}
528
529pub struct Avc1 {
541 avcc: Option<Bytes>,
542 sps: Vec<Bytes>,
544 pps: Vec<Bytes>,
546}
547
548impl Default for Avc1 {
549 fn default() -> Self {
550 Self::new()
551 }
552}
553
554impl Avc1 {
555 pub fn new() -> Self {
557 Self {
558 avcc: None,
559 sps: Vec::new(),
560 pps: Vec::new(),
561 }
562 }
563
564 pub fn avcc(&self) -> Option<&Bytes> {
566 self.avcc.as_ref()
567 }
568
569 pub fn transform(&mut self, payload: Bytes) -> Result<Option<Bytes>> {
577 let mut buf = payload.clone();
581 let mut nal_iter = crate::codec::annexb::NalIterator::new(&mut buf);
582
583 let mut out = BytesMut::with_capacity(payload.remaining());
584 let mut frame_sps: Vec<Bytes> = Vec::new();
585 let mut frame_pps: Vec<Bytes> = Vec::new();
586 let mut emitted_any_slice = false;
587
588 loop {
589 let nal = match nal_iter.next() {
590 Some(Ok(n)) => n,
591 Some(Err(e)) => return Err(e.into()),
592 None => break,
593 };
594 if process_nal(&nal, &mut out, &mut frame_sps, &mut frame_pps)? {
595 emitted_any_slice = true;
596 }
597 }
598
599 if let Some(nal) = nal_iter.flush()?
600 && process_nal(&nal, &mut out, &mut frame_sps, &mut frame_pps)?
601 {
602 emitted_any_slice = true;
603 }
604
605 let mut changed = false;
610 if !frame_sps.is_empty() && frame_sps != self.sps {
611 self.sps = frame_sps;
612 changed = true;
613 }
614 if !frame_pps.is_empty() && frame_pps != self.pps {
615 self.pps = frame_pps;
616 changed = true;
617 }
618 if changed {
619 self.rebuild_avcc()?;
620 }
621
622 if !emitted_any_slice {
623 return Ok(None);
624 }
625
626 Ok(Some(out.freeze()))
627 }
628
629 fn rebuild_avcc(&mut self) -> Result<()> {
630 if self.sps.is_empty() || self.pps.is_empty() {
631 return Ok(());
632 }
633 self.avcc = Some(build_avcc(&self.sps, &self.pps)?);
634 Ok(())
635 }
636}
637
638fn process_nal(
642 nal: &Bytes,
643 out: &mut BytesMut,
644 frame_sps: &mut Vec<Bytes>,
645 frame_pps: &mut Vec<Bytes>,
646) -> Result<bool> {
647 if nal.is_empty() {
648 return Ok(false);
649 }
650 match nal[0] & 0x1f {
651 NAL_TYPE_SPS => {
652 crate::codec::annexb::push_distinct(frame_sps, nal);
653 Ok(false)
654 }
655 NAL_TYPE_PPS => {
656 crate::codec::annexb::push_distinct(frame_pps, nal);
657 Ok(false)
658 }
659 _ => {
660 let len = u32::try_from(nal.len()).map_err(|_| Error::NalTooLarge)?;
661 out.extend_from_slice(&len.to_be_bytes());
662 out.extend_from_slice(nal);
663 Ok(true)
664 }
665 }
666}
667
668#[cfg(test)]
671pub(crate) mod fixtures {
672 pub(crate) const SPS_IPB: &[u8] = &[
675 0x67, 0x64, 0x00, 0x0a, 0xac, 0xe4, 0x10, 0x9b, 0x01, 0x10, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x03,
676 0x03, 0x28, 0xf1, 0x22, 0x51, 0x20,
677 ];
678 pub(crate) const SPS_PYRAMID: &[u8] = &[
681 0x67, 0x64, 0x00, 0x0a, 0xac, 0xd9, 0x44, 0x26, 0xc0, 0x44, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x03,
682 0x00, 0xca, 0x3c, 0x48, 0x96, 0x58,
683 ];
684 pub(crate) const SPS_IPB_VARIABLE: &[u8] = &[
686 0x67, 0x64, 0x00, 0x0a, 0xac, 0xe4, 0x10, 0x9b, 0x01, 0x10, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x03,
687 0x03, 0x20, 0xf1, 0x22, 0x51, 0x20,
688 ];
689 pub(crate) const SPS_FIELD: &[u8] = &[
692 0x67, 0xf4, 0x00, 0x15, 0x91, 0x9d, 0x02, 0x82, 0x1f, 0x89, 0xc0, 0x44, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
693 0x00, 0x03, 0x00, 0xca, 0x7c, 0x50, 0xaa, 0x80,
694 ];
695 pub(crate) const PPS: &[u8] = &[0x68, 0xeb, 0xe3, 0xcb, 0x22, 0xc0];
696}
697
698#[cfg(test)]
699mod tests {
700 use super::*;
701
702 const SC4: &[u8] = &[0, 0, 0, 1];
703
704 #[test]
705 fn sps_reorder_reads_the_vui() {
706 use crate::codec::video::Reorder;
707
708 let fixed = Some((2, 50));
709 assert_eq!(
710 sps_reorder(fixtures::SPS_IPB),
711 Some(Reorder {
712 depth: 1,
713 period: fixed
714 })
715 );
716 assert_eq!(
717 sps_reorder(fixtures::SPS_PYRAMID),
718 Some(Reorder {
719 depth: 2,
720 period: fixed
721 })
722 );
723 assert_eq!(
724 sps_reorder(fixtures::SPS_IPB_VARIABLE),
725 Some(Reorder { depth: 1, period: None })
726 );
727 assert_eq!(
730 sps_reorder(fixtures::SPS_FIELD),
731 Some(Reorder {
732 depth: 0,
733 period: Some((2, 50))
734 })
735 );
736 assert_eq!(sps_reorder(&[0x67, 0x42, 0xc0, 0x1f, 0xde]), None);
738 assert_eq!(sps_reorder(&fixtures::SPS_IPB[..fixtures::SPS_IPB.len() - 3]), None);
740 }
741
742 #[test]
743 fn sps_framerate_needs_a_fixed_rate() {
744 assert_eq!(sps_framerate(fixtures::SPS_IPB), Some(25.0));
745 assert_eq!(sps_framerate(fixtures::SPS_IPB_VARIABLE), None);
747 assert_eq!(sps_framerate(fixtures::SPS_FIELD), None);
749 assert_eq!(sps_framerate(&[0x67, 0x42, 0xc0, 0x1f, 0xde]), None);
750 }
751
752 fn annexb_frame(nals: &[&[u8]]) -> Bytes {
753 let mut buf = BytesMut::new();
754 for nal in nals {
755 buf.extend_from_slice(SC4);
756 buf.extend_from_slice(nal);
757 }
758 buf.freeze()
759 }
760
761 #[test]
764 fn avc1_frame_keyframe() {
765 let idr: &[u8] = &[0x65, 0x88, 0x84, 0x21];
766 let mut au = BytesMut::new();
767 au.extend_from_slice(&(idr.len() as u32).to_be_bytes());
768 au.extend_from_slice(idr);
769
770 let frame = avc1_frame(&au, 4, moq_net::Timestamp::from_micros(0).unwrap()).unwrap();
771 assert!(frame.keyframe);
772 assert_eq!(frame.payload[4..], *idr);
773 }
774
775 #[test]
777 fn avc1_frame_delta() {
778 let pslice: &[u8] = &[0x61, 0xe0, 0x12, 0x34];
779 let mut au = BytesMut::new();
780 au.extend_from_slice(&(pslice.len() as u32).to_be_bytes());
781 au.extend_from_slice(pslice);
782
783 let frame = avc1_frame(&au, 4, moq_net::Timestamp::from_micros(0).unwrap()).unwrap();
784 assert!(!frame.keyframe);
785 }
786
787 #[test]
788 fn avc3_strips_sps_pps_and_builds_avcc() {
789 let sps = &[0x67, 0x42, 0xc0, 0x1f, 0xde][..];
790 let pps = &[0x68, 0xce, 0x3c, 0x80][..];
791 let idr = &[0x65, 0x88, 0x84, 0x21][..];
792
793 let mut tx = Avc1::new();
794 assert!(tx.avcc().is_none());
795
796 let frame = annexb_frame(&[sps, pps, idr]);
797 let out = tx.transform(frame).expect("transform").expect("expected output");
798
799 let avcc = tx.avcc().expect("avcC available").clone();
800 assert_eq!(avcc[0], 1);
801 assert_eq!(avcc[1], sps[1]);
802 assert_eq!(avcc[3], sps[3]);
803
804 let mut expected = BytesMut::new();
805 expected.extend_from_slice(&(idr.len() as u32).to_be_bytes());
806 expected.extend_from_slice(idr);
807 assert_eq!(out.as_ref(), expected.as_ref());
808 }
809
810 #[test]
811 fn avcc_params_roundtrips_build_avcc() {
812 let sps = Bytes::from_static(&[0x67, 0x42, 0xc0, 0x1f, 0xde]);
813 let pps = Bytes::from_static(&[0x68, 0xce, 0x3c, 0x80]);
814
815 let avcc = build_avcc(std::slice::from_ref(&sps), std::slice::from_ref(&pps)).unwrap();
816 let (length_size, params) = avcc_params(&avcc).unwrap();
817
818 assert_eq!(length_size, 4);
819 assert_eq!(params.len(), 2);
820 assert_eq!(params[0], sps);
821 assert_eq!(params[1], pps);
822 }
823
824 #[test]
825 fn build_avcc_carries_multiple_pps() {
826 let sps = Bytes::from_static(&[0x67, 0x42, 0xc0, 0x1f, 0xde]);
829 let pps0 = Bytes::from_static(&[0x68, 0xce, 0x3c, 0x80]);
830 let pps1 = Bytes::from_static(&[0x68, 0xce, 0x3c, 0x81]);
831
832 let avcc = build_avcc(std::slice::from_ref(&sps), &[pps0.clone(), pps1.clone()]).unwrap();
833 assert_eq!(avcc[5] & 0x1f, 1);
835
836 let (_, params) = avcc_params(&avcc).unwrap();
837 assert_eq!(params, vec![sps, pps0, pps1]);
838 }
839
840 #[test]
841 fn avc3_keyframe_with_two_pps_keeps_both() {
842 let sps = &[0x67, 0x42, 0xc0, 0x1f, 0xde][..];
844 let pps0 = &[0x68, 0xce, 0x3c, 0x80][..];
845 let pps1 = &[0x68, 0xce, 0x3c, 0x81][..];
846 let idr = &[0x65, 0x88][..];
847
848 let mut tx = Avc1::new();
849 tx.transform(annexb_frame(&[sps, pps0, pps1, idr])).unwrap();
850
851 let avcc = tx.avcc().expect("avcC available");
852 let (_, params) = avcc_params(avcc).unwrap();
853 assert_eq!(
854 params.iter().map(|p| p.as_ref()).collect::<Vec<_>>(),
855 vec![sps, pps0, pps1]
856 );
857 }
858
859 #[test]
860 fn avc3_reinit_drops_superseded_pps() {
861 let sps = &[0x67, 0x42, 0xc0, 0x1f, 0xde][..];
864 let pps0 = &[0x68, 0xce, 0x3c, 0x80][..];
865 let pps1 = &[0x68, 0xce, 0x3c, 0x81][..];
866 let idr = &[0x65, 0x88][..];
867
868 let mut tx = Avc1::new();
869 tx.transform(annexb_frame(&[sps, pps0, idr])).unwrap();
870 tx.transform(annexb_frame(&[sps, pps1, idr])).unwrap();
871
872 let avcc = tx.avcc().expect("avcC available");
873 let (_, params) = avcc_params(avcc).unwrap();
874 assert_eq!(
875 params.iter().map(|p| p.as_ref()).collect::<Vec<_>>(),
876 vec![sps, pps1],
877 "reinit must drop the superseded PPS"
878 );
879 }
880
881 #[test]
882 fn avc3_parameter_only_frame_returns_none() {
883 let sps = &[0x67, 0x42, 0xc0, 0x1f, 0xde][..];
884 let pps = &[0x68, 0xce, 0x3c, 0x80][..];
885
886 let mut tx = Avc1::new();
887 let frame = annexb_frame(&[sps, pps]);
888 assert!(tx.transform(frame).unwrap().is_none());
889 assert!(tx.avcc().is_some());
890 }
891
892 #[test]
893 fn avc3_subsequent_frame_uses_cached_avcc() {
894 let sps = &[0x67, 0x42, 0xc0, 0x1f, 0xde][..];
895 let pps = &[0x68, 0xce, 0x3c, 0x80][..];
896 let idr = &[0x65, 0x88][..];
897 let p = &[0x61, 0xe0, 0x12][..];
898
899 let mut tx = Avc1::new();
900 tx.transform(annexb_frame(&[sps, pps, idr])).unwrap();
901 let avcc_v1 = tx.avcc().unwrap().clone();
902
903 let out = tx.transform(annexb_frame(&[p])).unwrap().unwrap();
904 assert_eq!(tx.avcc().unwrap(), &avcc_v1);
905 let mut expected = BytesMut::new();
906 expected.extend_from_slice(&(p.len() as u32).to_be_bytes());
907 expected.extend_from_slice(p);
908 assert_eq!(out.as_ref(), expected.as_ref());
909 }
910
911 #[test]
912 fn avc3_export_e2e_payload_shape() {
913 let sps = &[0x67u8, 0x42, 0xc0, 0x1f, 0xde, 0xad, 0xbe, 0xef][..];
916 let pps = &[0x68u8, 0xce, 0x3c, 0x80][..];
917 let idr = &[0x65u8, 0x88, 0x84, 0x21, 0x00, 0x11, 0x22, 0x33][..];
918 let pslice = &[0x61u8, 0xe0, 0x12, 0x34][..];
919
920 let mut tx = Avc1::new();
921 let key = annexb_frame(&[sps, pps, idr]);
922 let key_out = tx.transform(key).expect("transform key").expect("output");
923 assert!(tx.avcc().is_some());
924
925 assert_eq!(key_out.len(), 4 + idr.len());
926 assert_eq!(&key_out[4..], idr);
927
928 let p = annexb_frame(&[pslice]);
929 let p_out = tx.transform(p).expect("transform p").expect("output");
930 assert_eq!(p_out.len(), 4 + pslice.len());
931 assert_eq!(&p_out[4..], pslice);
932 }
933}