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}