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 const TYPE: BoxType = BoxType::Vp09Box;
70
71 fn box_size(&self) -> u64 {
72 0x6A
73 }
74
75 fn to_json(&self) -> Result<String, Error> {
76 Ok(serde_json::to_string(&self).unwrap())
77 }
78
79 fn summary(&self) -> Result<String, Error> {
80 Ok(format!("{self:?}"))
81 }
82}
83
84impl BlockReader for Vp09Box {
85 fn read_block<'a>(reader: &mut impl Reader<'a>) -> Result<Self, Error> {
86 let (version, flags) = read_box_header_ext(reader);
87
88 let start_code: u16 = reader.get_u16();
89 let data_reference_index: u16 = reader.get_u16();
90 let reserved0: [u8; 16] = {
91 let mut buf = [0u8; 16];
92 reader.copy_to_slice(&mut buf)?;
93 buf
94 };
95
96 let width: u16 = reader.get_u16();
97 let height: u16 = reader.get_u16();
98 let horizresolution: (u16, u16) = (reader.get_u16(), reader.get_u16());
99 let vertresolution: (u16, u16) = (reader.get_u16(), reader.get_u16());
100 let reserved1: [u8; 4] = {
101 let mut buf = [0u8; 4];
102 reader.copy_to_slice(&mut buf)?;
103 buf
104 };
105
106 let frame_count: u16 = reader.get_u16();
107 let compressorname: [u8; 32] = {
108 let mut buf = [0u8; 32];
109 reader.copy_to_slice(&mut buf)?;
110 buf
111 };
112
113 let depth: u16 = reader.get_u16();
114 let end_code: u16 = reader.get_u16();
115
116 Ok(Self {
117 version,
118 flags,
119 start_code,
120 data_reference_index,
121 reserved0,
122 width,
123 height,
124 horizresolution,
125 vertresolution,
126 reserved1,
127 frame_count,
128 compressorname,
129 depth,
130 end_code,
131 vpcc: reader.find_box::<VpccBox>()?,
132 })
133 }
134
135 fn size_hint() -> usize {
136 78
137 }
138}
139
140impl<W: Write> WriteBox<&mut W> for Vp09Box {
141 fn write_box(&self, writer: &mut W) -> Result<u64, Error> {
142 let size = self.box_size();
143 BoxHeader::new(Self::TYPE, size).write(writer)?;
144
145 write_box_header_ext(writer, self.version, self.flags)?;
146
147 writer.write_u16::<BigEndian>(self.start_code)?;
148 writer.write_u16::<BigEndian>(self.data_reference_index)?;
149 writer.write_all(&self.reserved0)?;
150 writer.write_u16::<BigEndian>(self.width)?;
151 writer.write_u16::<BigEndian>(self.height)?;
152 writer.write_u16::<BigEndian>(self.horizresolution.0)?;
153 writer.write_u16::<BigEndian>(self.horizresolution.1)?;
154 writer.write_u16::<BigEndian>(self.vertresolution.0)?;
155 writer.write_u16::<BigEndian>(self.vertresolution.1)?;
156 writer.write_all(&self.reserved1)?;
157 writer.write_u16::<BigEndian>(self.frame_count)?;
158 writer.write_all(&self.compressorname)?;
159 writer.write_u16::<BigEndian>(self.depth)?;
160 writer.write_u16::<BigEndian>(self.end_code)?;
161 VpccBox::write_box(&self.vpcc, writer)?;
162
163 Ok(size)
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170 use crate::mp4box::BoxHeader;
171
172 #[tokio::test]
173 async fn test_vpcc() {
174 let src_box = Vp09Box::new(&Vp9Config {
175 width: 1920,
176 height: 1080,
177 });
178 let mut buf = Vec::new();
179 src_box.write_box(&mut buf).unwrap();
180 assert_eq!(buf.len(), src_box.box_size() as usize);
181
182 let mut reader = buf.as_slice();
183 let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
184 assert_eq!(header.kind, BoxType::Vp09Box);
185 assert_eq!(src_box.box_size(), header.size);
186
187 let dst_box = Vp09Box::read_block(&mut reader).unwrap();
188 assert_eq!(src_box, dst_box);
189 }
190}