Skip to main content

mp4/mp4box/
vp09.rs

1use crate::mp4box::vpcc::VpccBox;
2use crate::mp4box::*;
3use crate::Mp4Box;
4use serde::Serialize;
5
6#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
7pub struct Vp09Box {
8    pub version: u8,
9    pub flags: u32,
10    pub start_code: u16,
11    pub data_reference_index: u16,
12    pub reserved0: [u8; 16],
13    pub width: u16,
14    pub height: u16,
15    pub horizresolution: (u16, u16),
16    pub vertresolution: (u16, u16),
17    pub reserved1: [u8; 4],
18    pub frame_count: u16,
19    pub compressorname: [u8; 32],
20    pub depth: u16,
21    pub end_code: u16,
22    pub vpcc: VpccBox,
23}
24
25impl Vp09Box {
26    pub const DEFAULT_START_CODE: u16 = 0;
27    pub const DEFAULT_END_CODE: u16 = 0xFFFF;
28    pub const DEFAULT_DATA_REFERENCE_INDEX: u16 = 1;
29    pub const DEFAULT_HORIZRESOLUTION: (u16, u16) = (0x48, 0x00);
30    pub const DEFAULT_VERTRESOLUTION: (u16, u16) = (0x48, 0x00);
31    pub const DEFAULT_FRAME_COUNT: u16 = 1;
32    pub const DEFAULT_COMPRESSORNAME: [u8; 32] = [0; 32];
33    pub const DEFAULT_DEPTH: u16 = 24;
34
35    pub fn new(config: &Vp9Config) -> Self {
36        Vp09Box {
37            version: 0,
38            flags: 0,
39            start_code: Vp09Box::DEFAULT_START_CODE,
40            data_reference_index: Vp09Box::DEFAULT_DATA_REFERENCE_INDEX,
41            reserved0: Default::default(),
42            width: config.width,
43            height: config.height,
44            horizresolution: Vp09Box::DEFAULT_HORIZRESOLUTION,
45            vertresolution: Vp09Box::DEFAULT_VERTRESOLUTION,
46            reserved1: Default::default(),
47            frame_count: Vp09Box::DEFAULT_FRAME_COUNT,
48            compressorname: Vp09Box::DEFAULT_COMPRESSORNAME,
49            depth: Vp09Box::DEFAULT_DEPTH,
50            end_code: Vp09Box::DEFAULT_END_CODE,
51            vpcc: VpccBox {
52                version: VpccBox::DEFAULT_VERSION,
53                flags: 0,
54                profile: 0,
55                level: 0x1F,
56                bit_depth: VpccBox::DEFAULT_BIT_DEPTH,
57                chroma_subsampling: 0,
58                video_full_range_flag: false,
59                color_primaries: 0,
60                transfer_characteristics: 0,
61                matrix_coefficients: 0,
62                codec_initialization_data_size: 0,
63            },
64        }
65    }
66}
67
68impl Mp4Box for Vp09Box {
69    fn box_type(&self) -> BoxType {
70        BoxType::Vp09Box
71    }
72
73    fn box_size(&self) -> u64 {
74        0x6A
75    }
76
77    fn to_json(&self) -> Result<String> {
78        Ok(serde_json::to_string(&self).unwrap())
79    }
80
81    fn summary(&self) -> Result<String> {
82        Ok(format!("{self:?}"))
83    }
84}
85
86impl<R: Read + Seek> ReadBox<&mut R> for Vp09Box {
87    fn read_box(reader: &mut R, size: u64) -> Result<Self> {
88        let start = box_start(reader)?;
89        let (version, flags) = read_box_header_ext(reader)?;
90
91        let start_code: u16 = reader.read_u16::<BigEndian>()?;
92        let data_reference_index: u16 = reader.read_u16::<BigEndian>()?;
93        let reserved0: [u8; 16] = {
94            let mut buf = [0u8; 16];
95            reader.read_exact(&mut buf)?;
96            buf
97        };
98        let width: u16 = reader.read_u16::<BigEndian>()?;
99        let height: u16 = reader.read_u16::<BigEndian>()?;
100        let horizresolution: (u16, u16) = (
101            reader.read_u16::<BigEndian>()?,
102            reader.read_u16::<BigEndian>()?,
103        );
104        let vertresolution: (u16, u16) = (
105            reader.read_u16::<BigEndian>()?,
106            reader.read_u16::<BigEndian>()?,
107        );
108        let reserved1: [u8; 4] = {
109            let mut buf = [0u8; 4];
110            reader.read_exact(&mut buf)?;
111            buf
112        };
113        let frame_count: u16 = reader.read_u16::<BigEndian>()?;
114        let compressorname: [u8; 32] = {
115            let mut buf = [0u8; 32];
116            reader.read_exact(&mut buf)?;
117            buf
118        };
119        let depth: u16 = reader.read_u16::<BigEndian>()?;
120        let end_code: u16 = reader.read_u16::<BigEndian>()?;
121
122        let vpcc = {
123            let header = BoxHeader::read(reader)?;
124            if header.size > size {
125                return Err(Error::InvalidData(
126                    "vp09 box contains a box with a larger size than it",
127                ));
128            }
129            VpccBox::read_box(reader, header.size)?
130        };
131
132        skip_bytes_to(reader, start + size)?;
133
134        Ok(Self {
135            version,
136            flags,
137            start_code,
138            data_reference_index,
139            reserved0,
140            width,
141            height,
142            horizresolution,
143            vertresolution,
144            reserved1,
145            frame_count,
146            compressorname,
147            depth,
148            end_code,
149            vpcc,
150        })
151    }
152}
153
154impl<W: Write> WriteBox<&mut W> for Vp09Box {
155    fn write_box(&self, writer: &mut W) -> Result<u64> {
156        let size = self.box_size();
157        BoxHeader::new(self.box_type(), size).write(writer)?;
158
159        write_box_header_ext(writer, self.version, self.flags)?;
160
161        writer.write_u16::<BigEndian>(self.start_code)?;
162        writer.write_u16::<BigEndian>(self.data_reference_index)?;
163        writer.write_all(&self.reserved0)?;
164        writer.write_u16::<BigEndian>(self.width)?;
165        writer.write_u16::<BigEndian>(self.height)?;
166        writer.write_u16::<BigEndian>(self.horizresolution.0)?;
167        writer.write_u16::<BigEndian>(self.horizresolution.1)?;
168        writer.write_u16::<BigEndian>(self.vertresolution.0)?;
169        writer.write_u16::<BigEndian>(self.vertresolution.1)?;
170        writer.write_all(&self.reserved1)?;
171        writer.write_u16::<BigEndian>(self.frame_count)?;
172        writer.write_all(&self.compressorname)?;
173        writer.write_u16::<BigEndian>(self.depth)?;
174        writer.write_u16::<BigEndian>(self.end_code)?;
175        VpccBox::write_box(&self.vpcc, writer)?;
176
177        Ok(size)
178    }
179}
180
181#[cfg(test)]
182mod tests {
183    use super::*;
184    use crate::mp4box::BoxHeader;
185    use std::io::Cursor;
186
187    #[test]
188    fn test_vpcc() {
189        let src_box = Vp09Box::new(&Vp9Config {
190            width: 1920,
191            height: 1080,
192        });
193        let mut buf = Vec::new();
194        src_box.write_box(&mut buf).unwrap();
195        assert_eq!(buf.len(), src_box.box_size() as usize);
196
197        let mut reader = Cursor::new(&buf);
198        let header = BoxHeader::read(&mut reader).unwrap();
199        assert_eq!(header.name, BoxType::Vp09Box);
200        assert_eq!(src_box.box_size(), header.size);
201
202        let dst_box = Vp09Box::read_box(&mut reader, header.size).unwrap();
203        assert_eq!(src_box, dst_box);
204    }
205}