Skip to main content

mp4_atom/moov/trak/mdia/minf/stbl/stsd/h264/
avc3.rs

1use crate::*;
2
3/// An H.264 sample entry like [Avc1], except parameter sets may also be in-band in the samples.
4///
5/// The `avcC` box is still required (ISO/IEC 14496-15:2022 5.4.2.1.1) but may list no parameter sets.
6#[derive(Debug, Clone, PartialEq, Eq, Default)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub struct Avc3 {
9    pub visual: Visual,
10    pub avcc: Avcc,
11    pub btrt: Option<Btrt>,
12    pub colr: Option<Colr>,
13    pub pasp: Option<Pasp>,
14    pub taic: Option<Taic>,
15    pub fiel: Option<Fiel>,
16    pub spatial: Option<Box<Spatial>>,
17}
18
19impl Atom for Avc3 {
20    const KIND: FourCC = FourCC::new(b"avc3");
21
22    fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
23        let visual = Visual::decode(buf)?;
24
25        let mut avcc = None;
26        let mut btrt = None;
27        let mut colr = None;
28        let mut pasp = None;
29        let mut taic = None;
30        let mut fiel = None;
31        let mut spatial = None;
32        while let Some(atom) = Any::decode_maybe(buf)? {
33            match atom {
34                Any::Avcc(atom) => avcc = atom.into(),
35                Any::Btrt(atom) => btrt = atom.into(),
36                Any::Colr(atom) => colr = atom.into(),
37                Any::Pasp(atom) => pasp = atom.into(),
38                Any::Taic(atom) => taic = atom.into(),
39                Any::Fiel(atom) => fiel = atom.into(),
40                atom => Spatial::decode_child::<Self>(&mut spatial, atom)?,
41            }
42        }
43        skip_trailing_padding(buf);
44
45        Ok(Avc3 {
46            visual,
47            avcc: avcc.ok_or(Error::MissingBox(Avcc::KIND))?,
48            btrt,
49            colr,
50            pasp,
51            taic,
52            fiel,
53            spatial,
54        })
55    }
56
57    fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
58        self.visual.encode(buf)?;
59        self.avcc.encode(buf)?;
60        self.btrt.encode(buf)?;
61        self.colr.encode(buf)?;
62        if let Some(spatial) = &self.spatial {
63            spatial.encode(buf)?;
64        }
65        self.pasp.encode(buf)?;
66        self.taic.encode(buf)?;
67        self.fiel.encode(buf)?;
68        Ok(())
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    fn roundtrip(expected: &Avc3) {
77        let mut buf = Vec::new();
78        expected.encode(&mut buf).unwrap();
79
80        let decoded = Avc3::decode(&mut buf.as_slice()).unwrap();
81        assert_eq!(&decoded, expected);
82
83        // Through the stsd dispatch too, since `Codec::Unknown` refuses to encode.
84        let codec = Codec::from(expected.clone());
85        let mut buf = Vec::new();
86        codec.encode(&mut buf).unwrap();
87        assert_eq!(Codec::decode(&mut buf.as_slice()).unwrap(), codec);
88    }
89
90    // The avc3 sample entry from the init segment of the BBC Testcard HLS stream:
91    // https://vs-dash-ww-rd-live.akamaized.net/pl/testcard2020/192x108p25/media.m3u8
92    // Its avcC lists no SPS or PPS; they are all in-band.
93    const BBC: &[u8] = &[
94        0x00, 0x00, 0x00, 0x88, 0x61, 0x76, 0x63, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95        0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96        0x00, 0x00, 0x00, 0xC0, 0x00, 0x6C, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
97        0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x68, 0x32, 0x36, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00,
98        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
99        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0F,
100        0x61, 0x76, 0x63, 0x43, 0x01, 0x42, 0xC0, 0x15, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x10,
101        0x70, 0x61, 0x73, 0x70, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
102        0x13, 0x63, 0x6F, 0x6C, 0x72, 0x6E, 0x63, 0x6C, 0x78, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
103        0x00,
104    ];
105
106    #[test]
107    fn test_avc3_bbc() {
108        let expected = Avc3 {
109            visual: Visual {
110                data_reference_index: 1,
111                width: 192,
112                height: 108,
113                horizresolution: 0x48.into(),
114                vertresolution: 0x48.into(),
115                frame_count: 1,
116                compressor: "h264".into(),
117                depth: 24,
118            },
119            avcc: Avcc {
120                configuration_version: 1,
121                avc_profile_indication: 0x42,
122                profile_compatibility: 0xC0,
123                avc_level_indication: 0x15,
124                length_size: 4,
125                sequence_parameter_sets: Vec::new(),
126                picture_parameter_sets: Vec::new(),
127                ext: None,
128            },
129            colr: Some(Colr::Nclx {
130                colour_primaries: 1,
131                transfer_characteristics: 1,
132                matrix_coefficients: 1,
133                full_range_flag: false,
134            }),
135            pasp: Some(Pasp {
136                h_spacing: 1,
137                v_spacing: 1,
138            }),
139            ..Default::default()
140        };
141
142        let decoded = Avc3::decode(&mut &BBC[..]).unwrap();
143        assert_eq!(decoded, expected);
144        roundtrip(&expected);
145    }
146
147    #[test]
148    fn test_avc3_with_extras() {
149        roundtrip(&Avc3 {
150            visual: Visual {
151                data_reference_index: 1,
152                width: 320,
153                height: 240,
154                horizresolution: 0x48.into(),
155                vertresolution: 0x48.into(),
156                frame_count: 1,
157                compressor: "they".into(),
158                depth: 24,
159            },
160            avcc: Avcc {
161                configuration_version: 1,
162                avc_profile_indication: 100,
163                profile_compatibility: 0,
164                avc_level_indication: 13,
165                length_size: 4,
166                sequence_parameter_sets: vec![vec![
167                    0x67, 0x64, 0x00, 0x0D, 0xAC, 0xD9, 0x41, 0x41, 0xFA, 0x10, 0x00, 0x00, 0x03,
168                    0x00, 0x10, 0x00, 0x00, 0x03, 0x03, 0x20, 0xF1, 0x42, 0x99, 0x60,
169                ]],
170                picture_parameter_sets: vec![vec![0x68, 0xEB, 0xE3, 0xCB, 0x22, 0xC0]],
171                ..Default::default()
172            },
173            btrt: Some(Btrt {
174                buffer_size_db: 14075,
175                max_bitrate: 374288,
176                avg_bitrate: 240976,
177            }),
178            colr: Some(Colr::default()),
179            pasp: Some(Pasp {
180                h_spacing: 4,
181                v_spacing: 3,
182            }),
183            taic: Some(Taic {
184                time_uncertainty: u64::MAX,
185                clock_resolution: 1000,
186                clock_drift_rate: i32::MAX,
187                clock_type: ClockType::CanSync,
188            }),
189            fiel: Some(Fiel {
190                field_count: 2,
191                field_order: 0,
192            }),
193            spatial: Default::default(),
194        });
195    }
196}