1use byteorder::{BigEndian, WriteBytesExt};
2use serde::Serialize;
3use std::io::Write;
4
5use crate::mp4box::*;
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
8pub struct MvhdBox {
9 pub version: u8,
10 pub flags: u32,
11 pub creation_time: u64,
12 pub modification_time: u64,
13 pub timescale: u32,
14 pub duration: u64,
15
16 #[serde(with = "value_u32")]
17 pub rate: FixedPointU16,
18 #[serde(with = "value_u8")]
19 pub volume: FixedPointU8,
20
21 pub matrix: tkhd::Matrix,
22
23 pub next_track_id: u32,
24}
25
26impl MvhdBox {
27 pub fn get_type(&self) -> BoxType {
28 BoxType::MvhdBox
29 }
30
31 pub fn get_size(&self) -> u64 {
32 let mut size = HEADER_SIZE + HEADER_EXT_SIZE;
33 if self.version == 1 {
34 size += 28;
35 } else if self.version == 0 {
36 size += 16;
37 }
38 size += 80;
39 size
40 }
41}
42
43impl Default for MvhdBox {
44 fn default() -> Self {
45 MvhdBox {
46 version: 0,
47 flags: 0,
48 creation_time: 0,
49 modification_time: 0,
50 timescale: 1000,
51 duration: 0,
52 rate: FixedPointU16::new(1),
53 matrix: tkhd::Matrix::default(),
54 volume: FixedPointU8::new(1),
55 next_track_id: 1,
56 }
57 }
58}
59
60impl Mp4Box for MvhdBox {
61 const TYPE: BoxType = BoxType::MvhdBox;
62
63 fn box_size(&self) -> u64 {
64 self.get_size()
65 }
66
67 fn to_json(&self) -> Result<String, Error> {
68 Ok(serde_json::to_string(&self).unwrap())
69 }
70
71 fn summary(&self) -> Result<String, Error> {
72 let s = format!(
73 "creation_time={} timescale={} duration={} rate={} volume={}, matrix={}, next_track_id={}",
74 self.creation_time,
75 self.timescale,
76 self.duration,
77 self.rate.value(),
78 self.volume.value(),
79 self.matrix,
80 self.next_track_id
81 );
82 Ok(s)
83 }
84}
85
86impl BlockReader for MvhdBox {
87 fn read_block<'a>(reader: &mut impl Reader<'a>) -> Result<Self, Error> {
88 let (version, flags) = read_box_header_ext(reader);
89
90 let (creation_time, modification_time, timescale, duration) = if version == 1 {
91 if reader.remaining() < Self::size_hint() - 4 + 12 {
92 return Err(Error::InvalidData("expected more bytes"));
93 }
94
95 (
96 reader.get_u64(),
97 reader.get_u64(),
98 reader.get_u32(),
99 reader.get_u64(),
100 )
101 } else if version == 0 {
102 (
103 reader.get_u32() as u64,
104 reader.get_u32() as u64,
105 reader.get_u32(),
106 reader.get_u32() as u64,
107 )
108 } else {
109 return Err(Error::InvalidData("version must be 0 or 1"));
110 };
111
112 let rate = FixedPointU16::new_raw(reader.get_u32());
113 let volume = FixedPointU8::new_raw(reader.get_u16());
114
115 reader.get_u16(); reader.get_u64(); let matrix = tkhd::Matrix {
119 a: reader.get_i32(),
120 b: reader.get_i32(),
121 u: reader.get_i32(),
122 c: reader.get_i32(),
123 d: reader.get_i32(),
124 v: reader.get_i32(),
125 x: reader.get_i32(),
126 y: reader.get_i32(),
127 w: reader.get_i32(),
128 };
129
130 reader.skip(24);
131
132 let next_track_id = reader.get_u32();
133
134 Ok(MvhdBox {
135 version,
136 flags,
137 creation_time,
138 modification_time,
139 timescale,
140 duration,
141 rate,
142 volume,
143 matrix,
144 next_track_id,
145 })
146 }
147
148 fn size_hint() -> usize {
149 100
150 }
151}
152
153impl<W: Write> WriteBox<&mut W> for MvhdBox {
154 fn write_box(&self, writer: &mut W) -> Result<u64, Error> {
155 let size = self.box_size();
156 BoxHeader::new(Self::TYPE, size).write(writer)?;
157
158 write_box_header_ext(writer, self.version, self.flags)?;
159
160 if self.version == 1 {
161 writer.write_u64::<BigEndian>(self.creation_time)?;
162 writer.write_u64::<BigEndian>(self.modification_time)?;
163 writer.write_u32::<BigEndian>(self.timescale)?;
164 writer.write_u64::<BigEndian>(self.duration)?;
165 } else if self.version == 0 {
166 writer.write_u32::<BigEndian>(self.creation_time as u32)?;
167 writer.write_u32::<BigEndian>(self.modification_time as u32)?;
168 writer.write_u32::<BigEndian>(self.timescale)?;
169 writer.write_u32::<BigEndian>(self.duration as u32)?;
170 } else {
171 return Err(Error::InvalidData("version must be 0 or 1"));
172 }
173 writer.write_u32::<BigEndian>(self.rate.raw_value())?;
174
175 writer.write_u16::<BigEndian>(self.volume.raw_value())?;
176
177 writer.write_u16::<BigEndian>(0)?; writer.write_u64::<BigEndian>(0)?; writer.write_i32::<BigEndian>(self.matrix.a)?;
182 writer.write_i32::<BigEndian>(self.matrix.b)?;
183 writer.write_i32::<BigEndian>(self.matrix.u)?;
184 writer.write_i32::<BigEndian>(self.matrix.c)?;
185 writer.write_i32::<BigEndian>(self.matrix.d)?;
186 writer.write_i32::<BigEndian>(self.matrix.v)?;
187 writer.write_i32::<BigEndian>(self.matrix.x)?;
188 writer.write_i32::<BigEndian>(self.matrix.y)?;
189 writer.write_i32::<BigEndian>(self.matrix.w)?;
190
191 write_zeros(writer, 24)?; writer.write_u32::<BigEndian>(self.next_track_id)?;
194
195 Ok(size)
196 }
197}
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202 use crate::mp4box::BoxHeader;
203
204 #[tokio::test]
205 async fn test_mvhd32() {
206 let src_box = MvhdBox {
207 version: 0,
208 flags: 0,
209 creation_time: 100,
210 modification_time: 200,
211 timescale: 1000,
212 duration: 634634,
213 rate: FixedPointU16::new(1),
214 volume: FixedPointU8::new(1),
215 matrix: tkhd::Matrix::default(),
216 next_track_id: 1,
217 };
218 let mut buf = Vec::new();
219 src_box.write_box(&mut buf).unwrap();
220 assert_eq!(buf.len(), src_box.box_size() as usize);
221
222 let mut reader = buf.as_slice();
223 let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
224 assert_eq!(header.kind, BoxType::MvhdBox);
225 assert_eq!(src_box.box_size(), header.size);
226
227 let dst_box = MvhdBox::read_block(&mut reader).unwrap();
228 assert_eq!(src_box, dst_box);
229 }
230
231 #[tokio::test]
232 async fn test_mvhd64() {
233 let src_box = MvhdBox {
234 version: 1,
235 flags: 0,
236 creation_time: 100,
237 modification_time: 200,
238 timescale: 1000,
239 duration: 634634,
240 rate: FixedPointU16::new(1),
241 volume: FixedPointU8::new(1),
242 matrix: tkhd::Matrix::default(),
243 next_track_id: 1,
244 };
245 let mut buf = Vec::new();
246 src_box.write_box(&mut buf).unwrap();
247 assert_eq!(buf.len(), src_box.box_size() as usize);
248
249 let mut reader = buf.as_slice();
250 let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
251 assert_eq!(header.kind, BoxType::MvhdBox);
252 assert_eq!(src_box.box_size(), header.size);
253
254 let dst_box = MvhdBox::read_block(&mut reader).unwrap();
255 assert_eq!(src_box, dst_box);
256 }
257}