Skip to main content

mp4/mp4box/
avc1.rs

1use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
2use serde::Serialize;
3use std::io::{Read, Seek, Write};
4
5use crate::mp4box::*;
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
8pub struct Avc1Box {
9    pub data_reference_index: u16,
10    pub width: u16,
11    pub height: u16,
12
13    #[serde(with = "value_u32")]
14    pub horizresolution: FixedPointU16,
15
16    #[serde(with = "value_u32")]
17    pub vertresolution: FixedPointU16,
18    pub frame_count: u16,
19    pub depth: u16,
20    pub avcc: AvcCBox,
21}
22
23impl Default for Avc1Box {
24    fn default() -> Self {
25        Avc1Box {
26            data_reference_index: 0,
27            width: 0,
28            height: 0,
29            horizresolution: FixedPointU16::new(0x48),
30            vertresolution: FixedPointU16::new(0x48),
31            frame_count: 1,
32            depth: 0x0018,
33            avcc: AvcCBox::default(),
34        }
35    }
36}
37
38impl Avc1Box {
39    pub fn new(config: &AvcConfig) -> Self {
40        Avc1Box {
41            data_reference_index: 1,
42            width: config.width,
43            height: config.height,
44            horizresolution: FixedPointU16::new(0x48),
45            vertresolution: FixedPointU16::new(0x48),
46            frame_count: 1,
47            depth: 0x0018,
48            avcc: AvcCBox::new(&config.seq_param_set, &config.pic_param_set),
49        }
50    }
51
52    pub fn get_type(&self) -> BoxType {
53        BoxType::Avc1Box
54    }
55
56    pub fn get_size(&self) -> u64 {
57        HEADER_SIZE + 8 + 70 + self.avcc.box_size()
58    }
59}
60
61impl Mp4Box for Avc1Box {
62    fn box_type(&self) -> BoxType {
63        self.get_type()
64    }
65
66    fn box_size(&self) -> u64 {
67        self.get_size()
68    }
69
70    fn to_json(&self) -> Result<String> {
71        Ok(serde_json::to_string(&self).unwrap())
72    }
73
74    fn summary(&self) -> Result<String> {
75        let s = format!(
76            "data_reference_index={} width={} height={} frame_count={}",
77            self.data_reference_index, self.width, self.height, self.frame_count
78        );
79        Ok(s)
80    }
81}
82
83impl<R: Read + Seek> ReadBox<&mut R> for Avc1Box {
84    fn read_box(reader: &mut R, size: u64) -> Result<Self> {
85        let start = box_start(reader)?;
86
87        reader.read_u32::<BigEndian>()?; // reserved
88        reader.read_u16::<BigEndian>()?; // reserved
89        let data_reference_index = reader.read_u16::<BigEndian>()?;
90
91        reader.read_u32::<BigEndian>()?; // pre-defined, reserved
92        reader.read_u64::<BigEndian>()?; // pre-defined
93        reader.read_u32::<BigEndian>()?; // pre-defined
94        let width = reader.read_u16::<BigEndian>()?;
95        let height = reader.read_u16::<BigEndian>()?;
96        let horizresolution = FixedPointU16::new_raw(reader.read_u32::<BigEndian>()?);
97        let vertresolution = FixedPointU16::new_raw(reader.read_u32::<BigEndian>()?);
98        reader.read_u32::<BigEndian>()?; // reserved
99        let frame_count = reader.read_u16::<BigEndian>()?;
100        skip_bytes(reader, 32)?; // compressorname
101        let depth = reader.read_u16::<BigEndian>()?;
102        reader.read_i16::<BigEndian>()?; // pre-defined
103
104        let end = start + size;
105        loop {
106            let current = reader.stream_position()?;
107            if current >= end {
108                return Err(Error::InvalidData("avcc not found"));
109            }
110            let header = BoxHeader::read(reader)?;
111            let BoxHeader { name, size: s } = header;
112            if s > size {
113                return Err(Error::InvalidData(
114                    "avc1 box contains a box with a larger size than it",
115                ));
116            }
117            if name == BoxType::AvcCBox {
118                let avcc = AvcCBox::read_box(reader, s)?;
119
120                skip_bytes_to(reader, start + size)?;
121
122                return Ok(Avc1Box {
123                    data_reference_index,
124                    width,
125                    height,
126                    horizresolution,
127                    vertresolution,
128                    frame_count,
129                    depth,
130                    avcc,
131                });
132            } else {
133                skip_bytes_to(reader, current + s)?;
134            }
135        }
136    }
137}
138
139impl<W: Write> WriteBox<&mut W> for Avc1Box {
140    fn write_box(&self, writer: &mut W) -> Result<u64> {
141        let size = self.box_size();
142        BoxHeader::new(self.box_type(), size).write(writer)?;
143
144        writer.write_u32::<BigEndian>(0)?; // reserved
145        writer.write_u16::<BigEndian>(0)?; // reserved
146        writer.write_u16::<BigEndian>(self.data_reference_index)?;
147
148        writer.write_u32::<BigEndian>(0)?; // pre-defined, reserved
149        writer.write_u64::<BigEndian>(0)?; // pre-defined
150        writer.write_u32::<BigEndian>(0)?; // pre-defined
151        writer.write_u16::<BigEndian>(self.width)?;
152        writer.write_u16::<BigEndian>(self.height)?;
153        writer.write_u32::<BigEndian>(self.horizresolution.raw_value())?;
154        writer.write_u32::<BigEndian>(self.vertresolution.raw_value())?;
155        writer.write_u32::<BigEndian>(0)?; // reserved
156        writer.write_u16::<BigEndian>(self.frame_count)?;
157        // skip compressorname
158        write_zeros(writer, 32)?;
159        writer.write_u16::<BigEndian>(self.depth)?;
160        writer.write_i16::<BigEndian>(-1)?; // pre-defined
161
162        self.avcc.write_box(writer)?;
163
164        Ok(size)
165    }
166}
167
168#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
169pub struct AvcCBox {
170    pub configuration_version: u8,
171    pub avc_profile_indication: u8,
172    pub profile_compatibility: u8,
173    pub avc_level_indication: u8,
174    pub length_size_minus_one: u8,
175    pub sequence_parameter_sets: Vec<NalUnit>,
176    pub picture_parameter_sets: Vec<NalUnit>,
177}
178
179impl AvcCBox {
180    pub fn new(sps: &[u8], pps: &[u8]) -> Self {
181        Self {
182            configuration_version: 1,
183            avc_profile_indication: sps[1],
184            profile_compatibility: sps[2],
185            avc_level_indication: sps[3],
186            length_size_minus_one: 0xff, // length_size = 4
187            sequence_parameter_sets: vec![NalUnit::from(sps)],
188            picture_parameter_sets: vec![NalUnit::from(pps)],
189        }
190    }
191}
192
193impl Mp4Box for AvcCBox {
194    fn box_type(&self) -> BoxType {
195        BoxType::AvcCBox
196    }
197
198    fn box_size(&self) -> u64 {
199        let mut size = HEADER_SIZE + 7;
200        for sps in self.sequence_parameter_sets.iter() {
201            size += sps.size() as u64;
202        }
203        for pps in self.picture_parameter_sets.iter() {
204            size += pps.size() as u64;
205        }
206        size
207    }
208
209    fn to_json(&self) -> Result<String> {
210        Ok(serde_json::to_string(&self).unwrap())
211    }
212
213    fn summary(&self) -> Result<String> {
214        let s = format!("avc_profile_indication={}", self.avc_profile_indication);
215        Ok(s)
216    }
217}
218
219impl<R: Read + Seek> ReadBox<&mut R> for AvcCBox {
220    fn read_box(reader: &mut R, size: u64) -> Result<Self> {
221        let start = box_start(reader)?;
222
223        let configuration_version = reader.read_u8()?;
224        let avc_profile_indication = reader.read_u8()?;
225        let profile_compatibility = reader.read_u8()?;
226        let avc_level_indication = reader.read_u8()?;
227        let length_size_minus_one = reader.read_u8()? & 0x3;
228        let num_of_spss = reader.read_u8()? & 0x1F;
229        let mut sequence_parameter_sets = Vec::with_capacity(num_of_spss as usize);
230        for _ in 0..num_of_spss {
231            let nal_unit = NalUnit::read(reader)?;
232            sequence_parameter_sets.push(nal_unit);
233        }
234        let num_of_ppss = reader.read_u8()?;
235        let mut picture_parameter_sets = Vec::with_capacity(num_of_ppss as usize);
236        for _ in 0..num_of_ppss {
237            let nal_unit = NalUnit::read(reader)?;
238            picture_parameter_sets.push(nal_unit);
239        }
240
241        skip_bytes_to(reader, start + size)?;
242
243        Ok(AvcCBox {
244            configuration_version,
245            avc_profile_indication,
246            profile_compatibility,
247            avc_level_indication,
248            length_size_minus_one,
249            sequence_parameter_sets,
250            picture_parameter_sets,
251        })
252    }
253}
254
255impl<W: Write> WriteBox<&mut W> for AvcCBox {
256    fn write_box(&self, writer: &mut W) -> Result<u64> {
257        let size = self.box_size();
258        BoxHeader::new(self.box_type(), size).write(writer)?;
259
260        writer.write_u8(self.configuration_version)?;
261        writer.write_u8(self.avc_profile_indication)?;
262        writer.write_u8(self.profile_compatibility)?;
263        writer.write_u8(self.avc_level_indication)?;
264        writer.write_u8(self.length_size_minus_one | 0xFC)?;
265        writer.write_u8(self.sequence_parameter_sets.len() as u8 | 0xE0)?;
266        for sps in self.sequence_parameter_sets.iter() {
267            sps.write(writer)?;
268        }
269        writer.write_u8(self.picture_parameter_sets.len() as u8)?;
270        for pps in self.picture_parameter_sets.iter() {
271            pps.write(writer)?;
272        }
273        Ok(size)
274    }
275}
276
277#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
278pub struct NalUnit {
279    pub bytes: Vec<u8>,
280}
281
282impl From<&[u8]> for NalUnit {
283    fn from(bytes: &[u8]) -> Self {
284        Self {
285            bytes: bytes.to_vec(),
286        }
287    }
288}
289
290impl NalUnit {
291    fn size(&self) -> usize {
292        2 + self.bytes.len()
293    }
294
295    fn read<R: Read + Seek>(reader: &mut R) -> Result<Self> {
296        let length = reader.read_u16::<BigEndian>()? as usize;
297        let mut bytes = vec![0u8; length];
298        reader.read_exact(&mut bytes)?;
299        Ok(NalUnit { bytes })
300    }
301
302    fn write<W: Write>(&self, writer: &mut W) -> Result<u64> {
303        writer.write_u16::<BigEndian>(self.bytes.len() as u16)?;
304        writer.write_all(&self.bytes)?;
305        Ok(self.size() as u64)
306    }
307}
308
309#[cfg(test)]
310mod tests {
311    use super::*;
312    use crate::mp4box::BoxHeader;
313    use std::io::Cursor;
314
315    #[test]
316    fn test_avc1() {
317        let src_box = Avc1Box {
318            data_reference_index: 1,
319            width: 320,
320            height: 240,
321            horizresolution: FixedPointU16::new(0x48),
322            vertresolution: FixedPointU16::new(0x48),
323            frame_count: 1,
324            depth: 24,
325            avcc: AvcCBox {
326                configuration_version: 1,
327                avc_profile_indication: 100,
328                profile_compatibility: 0,
329                avc_level_indication: 13,
330                length_size_minus_one: 3,
331                sequence_parameter_sets: vec![NalUnit {
332                    bytes: vec![
333                        0x67, 0x64, 0x00, 0x0D, 0xAC, 0xD9, 0x41, 0x41, 0xFA, 0x10, 0x00, 0x00,
334                        0x03, 0x00, 0x10, 0x00, 0x00, 0x03, 0x03, 0x20, 0xF1, 0x42, 0x99, 0x60,
335                    ],
336                }],
337                picture_parameter_sets: vec![NalUnit {
338                    bytes: vec![0x68, 0xEB, 0xE3, 0xCB, 0x22, 0xC0],
339                }],
340            },
341        };
342        let mut buf = Vec::new();
343        src_box.write_box(&mut buf).unwrap();
344        assert_eq!(buf.len(), src_box.box_size() as usize);
345
346        let mut reader = Cursor::new(&buf);
347        let header = BoxHeader::read(&mut reader).unwrap();
348        assert_eq!(header.name, BoxType::Avc1Box);
349        assert_eq!(src_box.box_size(), header.size);
350
351        let dst_box = Avc1Box::read_box(&mut reader, header.size).unwrap();
352        assert_eq!(src_box, dst_box);
353    }
354}