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

1use crate::*;
2
3#[derive(Debug, Clone, PartialEq, Eq, Default)]
4#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5pub struct Avcc {
6    pub configuration_version: u8,
7    pub avc_profile_indication: u8,
8    pub profile_compatibility: u8,
9    pub avc_level_indication: u8,
10    pub length_size: u8,
11    pub sequence_parameter_sets: Vec<Vec<u8>>,
12    pub picture_parameter_sets: Vec<Vec<u8>>,
13    pub ext: Option<AvccExt>,
14}
15
16// Only valid for certain profiles
17#[derive(Debug, Clone, PartialEq, Eq)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19pub struct AvccExt {
20    pub chroma_format: u8,
21    pub bit_depth_luma: u8,
22    pub bit_depth_chroma: u8,
23    pub sequence_parameter_sets_ext: Vec<Vec<u8>>,
24}
25
26impl Default for AvccExt {
27    fn default() -> Self {
28        AvccExt {
29            chroma_format: 1,
30            bit_depth_luma: 8,
31            bit_depth_chroma: 8,
32            sequence_parameter_sets_ext: Vec::new(),
33        }
34    }
35}
36
37impl Avcc {
38    pub fn new(sps: &[u8], pps: &[u8]) -> Result<Self> {
39        if sps.len() < 4 {
40            return Err(Error::OutOfBounds);
41        }
42
43        Ok(Self {
44            configuration_version: 1,
45            avc_profile_indication: sps[1],
46            profile_compatibility: sps[2],
47            avc_level_indication: sps[3],
48            length_size: 4,
49            sequence_parameter_sets: vec![sps.into()],
50            picture_parameter_sets: vec![pps.into()],
51
52            // TODO This information could be parsed out of the SPS
53            ext: None,
54        })
55    }
56}
57
58impl Atom for Avcc {
59    const KIND: FourCC = FourCC::new(b"avcC");
60
61    fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
62        let configuration_version = u8::decode(buf)?;
63        if configuration_version != 1 {
64            return Err(Error::UnknownVersion(configuration_version));
65        }
66        let avc_profile_indication = u8::decode(buf)?;
67        let profile_compatibility = u8::decode(buf)?;
68        let avc_level_indication = u8::decode(buf)?;
69
70        // The first 6 bits are reserved and the value is encoded - 1
71        let length_size = (u8::decode(buf)? & 0b00000011) + 1;
72
73        let num_of_spss = u8::decode(buf)? & 0x1F;
74        let mut sequence_parameter_sets = Vec::with_capacity(num_of_spss as usize);
75        for _ in 0..num_of_spss {
76            let size = u16::decode(buf)? as usize;
77            let nal = Vec::decode_exact(buf, size)?;
78            sequence_parameter_sets.push(nal);
79        }
80
81        let num_of_ppss = u8::decode(buf)?;
82        let mut picture_parameter_sets = Vec::with_capacity(num_of_ppss as usize);
83        for _ in 0..num_of_ppss {
84            let size = u16::decode(buf)? as usize;
85            let nal = Vec::decode_exact(buf, size)?;
86            picture_parameter_sets.push(nal);
87        }
88
89        // NOTE: Many encoders/decoders skip this extended avcC part.
90        // It's profile specific, but we don't really care and will parse it if present.
91        let ext = if buf.has_remaining() {
92            let chroma_format = u8::decode(buf)? & 0x3;
93            let bit_depth_luma_minus8 = u8::decode(buf)? & 0x7;
94            let bit_depth_chroma_minus8 = u8::decode(buf)? & 0x7;
95            let num_of_sequence_parameter_set_exts = u8::decode(buf)? as usize;
96            let mut sequence_parameter_sets_ext =
97                Vec::with_capacity(num_of_sequence_parameter_set_exts);
98
99            for _ in 0..num_of_sequence_parameter_set_exts {
100                let size = u16::decode(buf)? as usize;
101                let nal = Vec::decode_exact(buf, size)?;
102                sequence_parameter_sets_ext.push(nal);
103            }
104
105            Some(AvccExt {
106                chroma_format,
107                bit_depth_luma: bit_depth_luma_minus8 + 8,
108                bit_depth_chroma: bit_depth_chroma_minus8 + 8,
109                sequence_parameter_sets_ext,
110            })
111        } else {
112            None
113        };
114
115        Ok(Avcc {
116            configuration_version,
117            avc_profile_indication,
118            profile_compatibility,
119            avc_level_indication,
120            length_size,
121            sequence_parameter_sets,
122            picture_parameter_sets,
123            ext,
124        })
125    }
126
127    fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
128        self.configuration_version.encode(buf)?;
129        self.avc_profile_indication.encode(buf)?;
130        self.profile_compatibility.encode(buf)?;
131        self.avc_level_indication.encode(buf)?;
132        let length_size = match self.length_size {
133            0 => return Err(Error::InvalidSize),
134            1..=4 => self.length_size - 1,
135            _ => return Err(Error::InvalidSize),
136        };
137        (length_size | 0xFC).encode(buf)?;
138
139        (self.sequence_parameter_sets.len() as u8 | 0xE0).encode(buf)?;
140        for sps in &self.sequence_parameter_sets {
141            (sps.len() as u16).encode(buf)?;
142            sps.encode(buf)?;
143        }
144
145        (self.picture_parameter_sets.len() as u8).encode(buf)?;
146        for pps in &self.picture_parameter_sets {
147            (pps.len() as u16).encode(buf)?;
148            pps.encode(buf)?;
149        }
150
151        if let Some(ext) = &self.ext {
152            ok_in_range(ext.chroma_format, 0..4)
153                .map(|n| n | 0b11111100)?
154                .encode(buf)?;
155            ok_in_range(
156                ext.bit_depth_luma
157                    .checked_sub(8)
158                    .ok_or(Error::InvalidSize)?,
159                0..8,
160            )
161            .map(|n| n | 0b11111000)?
162            .encode(buf)?;
163            ok_in_range(
164                ext.bit_depth_chroma
165                    .checked_sub(8)
166                    .ok_or(Error::InvalidSize)?,
167                0..8,
168            )
169            .map(|n| n | 0b11111000)?
170            .encode(buf)?;
171            (ext.sequence_parameter_sets_ext.len() as u8).encode(buf)?;
172            for sps in &ext.sequence_parameter_sets_ext {
173                (sps.len() as u16).encode(buf)?;
174                sps.encode(buf)?;
175            }
176        }
177
178        Ok(())
179    }
180}
181
182/// Returns the input `n` if it is within the provided `range`. Otherwise, it returns an
183/// [`Error::InvalidSize`] error.
184fn ok_in_range(n: u8, range: std::ops::Range<u8>) -> Result<u8> {
185    if range.contains(&n) {
186        Ok(n)
187    } else {
188        Err(Error::InvalidSize)
189    }
190}
191
192#[cfg(test)]
193mod tests {
194    use super::*;
195    use std::io::Cursor;
196
197    #[test]
198    fn ok_in_range_is_ok_when_in_range() {
199        assert_eq!(1, ok_in_range(1, 0..8).expect("should be Ok"));
200    }
201
202    #[test]
203    fn ok_in_range_is_err_when_out_of_range() {
204        match ok_in_range(8, 0..8) {
205            Err(Error::InvalidSize) => (),
206            Ok(n) => panic!("unexpected Ok value Ok({n})"),
207            Err(e) => panic!("unexpected error case {e}"),
208        }
209    }
210
211    // This example was taken from:
212    // https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v8/main.mp4
213    //
214    // I just extracted the bytes for the avcc atom location.
215    //
216    // NOTE: this atom is badly configured, in that the reserved bits before lengthSizeMinusOne are
217    // supposed to be 0b111111 and the reserved bits before numOfSequenceParameterSets are supposed
218    // to be 0b111; however, in this example, they are 0b000000 and 0b000. The test therefore also
219    // validates relaxed validation in decoding.
220    const ENCODED: &[u8] = &[
221        0x00, 0x00, 0x00, 0x41, 0x61, 0x76, 0x63, 0x43, 0x01, 0x64, 0x00, 0x2A, 0x03, 0x01, 0x00,
222        0x26, 0x27, 0x64, 0x00, 0x2A, 0xAC, 0x24, 0x8C, 0x07, 0x80, 0x22, 0x7E, 0x5C, 0x04, 0x40,
223        0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x1E, 0x38, 0xA0, 0x00, 0x0B, 0x71, 0xB0, 0x00,
224        0x16, 0xE3, 0x7B, 0xDE, 0xE0, 0x3E, 0x11, 0x08, 0xA7, 0x01, 0x00, 0x04, 0x28, 0xDE, 0xBC,
225        0xB0, 0xFD, 0xF8, 0xF8, 0x00,
226    ];
227
228    #[test]
229    fn avcc_decodes_correctly() {
230        let mut buf = Cursor::new(ENCODED);
231        let avcc = Avcc {
232            configuration_version: 1,
233            avc_profile_indication: 100,
234            profile_compatibility: 0,
235            avc_level_indication: 42,
236            length_size: 4,
237            sequence_parameter_sets: vec![ENCODED[16..54].to_vec()],
238            picture_parameter_sets: vec![ENCODED[57..61].to_vec()],
239            ext: Some(AvccExt {
240                chroma_format: 1,
241                bit_depth_luma: 8,
242                bit_depth_chroma: 8,
243                sequence_parameter_sets_ext: Vec::new(),
244            }),
245        };
246        let decoded = Avcc::decode(&mut buf).expect("avcC should decode successfully");
247        assert_eq!(avcc, decoded);
248        let mut encoded = Vec::new();
249        avcc.encode(&mut encoded)
250            .expect("encode should be successful");
251        // Here we fix the encoded bytes so that the problem reserved bits are set properly to
252        // 0b111111 and 0b111.
253        let mut fixed_encoded = ENCODED.to_vec();
254        if let Some(length_size_minus_one) = fixed_encoded.get_mut(12) {
255            *length_size_minus_one |= 0b11111100;
256        }
257        if let Some(num_of_sequence_parameter_sets) = fixed_encoded.get_mut(13) {
258            *num_of_sequence_parameter_sets |= 0b11100000;
259        }
260        assert_eq!(fixed_encoded, encoded);
261    }
262}