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 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 fn box_type(&self) -> BoxType {
62 self.get_type()
63 }
64
65 fn box_size(&self) -> u64 {
66 self.get_size()
67 }
68
69 fn to_json(&self) -> Result<String> {
70 Ok(serde_json::to_string(&self).unwrap())
71 }
72
73 fn summary(&self) -> Result<String> {
74 let s = format!(
75 "creation_time={} timescale={} duration={} rate={} volume={}, matrix={}, next_track_id={}",
76 self.creation_time,
77 self.timescale,
78 self.duration,
79 self.rate.value(),
80 self.volume.value(),
81 self.matrix,
82 self.next_track_id
83 );
84 Ok(s)
85 }
86}
87
88impl<R: Read + Seek> ReadBox<&mut R> for MvhdBox {
89 fn read_box(reader: &mut R, size: u64) -> Result<Self> {
90 let start = box_start(reader)?;
91
92 let (version, flags) = read_box_header_ext(reader)?;
93
94 let (creation_time, modification_time, timescale, duration) = if version == 1 {
95 (
96 reader.read_u64::<BigEndian>()?,
97 reader.read_u64::<BigEndian>()?,
98 reader.read_u32::<BigEndian>()?,
99 reader.read_u64::<BigEndian>()?,
100 )
101 } else if version == 0 {
102 (
103 reader.read_u32::<BigEndian>()? as u64,
104 reader.read_u32::<BigEndian>()? as u64,
105 reader.read_u32::<BigEndian>()?,
106 reader.read_u32::<BigEndian>()? as u64,
107 )
108 } else {
109 return Err(Error::InvalidData("version must be 0 or 1"));
110 };
111 let rate = FixedPointU16::new_raw(reader.read_u32::<BigEndian>()?);
112
113 let volume = FixedPointU8::new_raw(reader.read_u16::<BigEndian>()?);
114
115 reader.read_u16::<BigEndian>()?; reader.read_u64::<BigEndian>()?; let matrix = tkhd::Matrix {
120 a: reader.read_i32::<BigEndian>()?,
121 b: reader.read_i32::<BigEndian>()?,
122 u: reader.read_i32::<BigEndian>()?,
123 c: reader.read_i32::<BigEndian>()?,
124 d: reader.read_i32::<BigEndian>()?,
125 v: reader.read_i32::<BigEndian>()?,
126 x: reader.read_i32::<BigEndian>()?,
127 y: reader.read_i32::<BigEndian>()?,
128 w: reader.read_i32::<BigEndian>()?,
129 };
130
131 skip_bytes(reader, 24)?; let next_track_id = reader.read_u32::<BigEndian>()?;
134
135 skip_bytes_to(reader, start + size)?;
136
137 Ok(MvhdBox {
138 version,
139 flags,
140 creation_time,
141 modification_time,
142 timescale,
143 duration,
144 rate,
145 volume,
146 matrix,
147 next_track_id,
148 })
149 }
150}
151
152impl<W: Write> WriteBox<&mut W> for MvhdBox {
153 fn write_box(&self, writer: &mut W) -> Result<u64> {
154 let size = self.box_size();
155 BoxHeader::new(self.box_type(), size).write(writer)?;
156
157 write_box_header_ext(writer, self.version, self.flags)?;
158
159 if self.version == 1 {
160 writer.write_u64::<BigEndian>(self.creation_time)?;
161 writer.write_u64::<BigEndian>(self.modification_time)?;
162 writer.write_u32::<BigEndian>(self.timescale)?;
163 writer.write_u64::<BigEndian>(self.duration)?;
164 } else if self.version == 0 {
165 writer.write_u32::<BigEndian>(self.creation_time as u32)?;
166 writer.write_u32::<BigEndian>(self.modification_time as u32)?;
167 writer.write_u32::<BigEndian>(self.timescale)?;
168 writer.write_u32::<BigEndian>(self.duration as u32)?;
169 } else {
170 return Err(Error::InvalidData("version must be 0 or 1"));
171 }
172 writer.write_u32::<BigEndian>(self.rate.raw_value())?;
173
174 writer.write_u16::<BigEndian>(self.volume.raw_value())?;
175
176 writer.write_u16::<BigEndian>(0)?; writer.write_u64::<BigEndian>(0)?; writer.write_i32::<BigEndian>(self.matrix.a)?;
181 writer.write_i32::<BigEndian>(self.matrix.b)?;
182 writer.write_i32::<BigEndian>(self.matrix.u)?;
183 writer.write_i32::<BigEndian>(self.matrix.c)?;
184 writer.write_i32::<BigEndian>(self.matrix.d)?;
185 writer.write_i32::<BigEndian>(self.matrix.v)?;
186 writer.write_i32::<BigEndian>(self.matrix.x)?;
187 writer.write_i32::<BigEndian>(self.matrix.y)?;
188 writer.write_i32::<BigEndian>(self.matrix.w)?;
189
190 write_zeros(writer, 24)?; writer.write_u32::<BigEndian>(self.next_track_id)?;
193
194 Ok(size)
195 }
196}
197
198#[cfg(test)]
199mod tests {
200 use super::*;
201 use crate::mp4box::BoxHeader;
202 use std::io::Cursor;
203
204 #[test]
205 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 = Cursor::new(&buf);
223 let header = BoxHeader::read(&mut reader).unwrap();
224 assert_eq!(header.name, BoxType::MvhdBox);
225 assert_eq!(src_box.box_size(), header.size);
226
227 let dst_box = MvhdBox::read_box(&mut reader, header.size).unwrap();
228 assert_eq!(src_box, dst_box);
229 }
230
231 #[test]
232 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 = Cursor::new(&buf);
250 let header = BoxHeader::read(&mut reader).unwrap();
251 assert_eq!(header.name, BoxType::MvhdBox);
252 assert_eq!(src_box.box_size(), header.size);
253
254 let dst_box = MvhdBox::read_box(&mut reader, header.size).unwrap();
255 assert_eq!(src_box, dst_box);
256 }
257}