scuffle_mp4/boxes/types/
mvhd.rs1use std::io;
2
3use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
4use bytes::Bytes;
5use fixed::types::extra::{U8, U16};
6use fixed::{FixedI16, FixedI32};
7
8use crate::boxes::header::{BoxHeader, FullBoxHeader};
9use crate::boxes::traits::BoxType;
10
11#[derive(Debug, Clone, PartialEq)]
12pub struct Mvhd {
15 pub header: FullBoxHeader,
16 pub creation_time: u64,
17 pub modification_time: u64,
18 pub timescale: u32,
19 pub duration: u64,
20 pub rate: FixedI32<U16>,
21 pub volume: FixedI16<U8>,
22 pub reserved: u16,
23 pub reserved2: [u32; 2],
24 pub matrix: [u32; 9],
25 pub pre_defined: [u32; 6],
26 pub next_track_id: u32,
27}
28
29impl Mvhd {
30 pub fn new(creation_time: u64, modification_time: u64, timescale: u32, duration: u64, next_track_id: u32) -> Self {
31 Self {
32 header: FullBoxHeader::new(Self::NAME, 0, 0),
33 creation_time,
34 modification_time,
35 timescale,
36 duration,
37 rate: FixedI32::<U16>::from_num(1),
38 volume: FixedI16::<U8>::from_num(1),
39 reserved: 0,
40 reserved2: [0; 2],
41 matrix: Self::MATRIX,
42 pre_defined: [0; 6],
43 next_track_id,
44 }
45 }
46}
47
48impl Mvhd {
49 pub const MATRIX: [u32; 9] = [0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000];
50}
51
52impl BoxType for Mvhd {
53 const NAME: [u8; 4] = *b"mvhd";
54
55 fn demux(header: BoxHeader, data: Bytes) -> io::Result<Self> {
56 let mut reader = io::Cursor::new(data);
57
58 let header = FullBoxHeader::demux(header, &mut reader)?;
59
60 let (creation_time, modification_time, timescale, duration) = if header.version == 1 {
61 (
62 reader.read_u64::<BigEndian>()?, reader.read_u64::<BigEndian>()?, reader.read_u32::<BigEndian>()?, reader.read_u64::<BigEndian>()?, )
67 } else {
68 (
69 reader.read_u32::<BigEndian>()? as u64, reader.read_u32::<BigEndian>()? as u64, reader.read_u32::<BigEndian>()?, reader.read_u32::<BigEndian>()? as u64, )
74 };
75
76 let rate = reader.read_i32::<BigEndian>()?;
77 let volume = reader.read_i16::<BigEndian>()?;
78
79 let reserved = reader.read_u16::<BigEndian>()?;
80 let mut reserved2 = [0; 2];
81 for v in reserved2.iter_mut() {
82 *v = reader.read_u32::<BigEndian>()?;
83 }
84
85 let mut matrix = [0; 9];
86 for v in matrix.iter_mut() {
87 *v = reader.read_u32::<BigEndian>()?;
88 }
89
90 let mut pre_defined = [0; 6];
91 for v in pre_defined.iter_mut() {
92 *v = reader.read_u32::<BigEndian>()?;
93 }
94
95 let next_track_id = reader.read_u32::<BigEndian>()?;
96
97 Ok(Self {
98 header,
99 creation_time,
100 modification_time,
101 timescale,
102 duration,
103 rate: FixedI32::from_bits(rate),
104 volume: FixedI16::from_bits(volume),
105 reserved,
106 reserved2,
107 matrix,
108 pre_defined,
109 next_track_id,
110 })
111 }
112
113 fn primitive_size(&self) -> u64 {
114 let mut size = self.header.size();
115
116 if self.header.version == 1 {
117 size += 8 + 8 + 4 + 8; } else {
120 size += 4 + 4 + 4 + 4; }
123
124 size += 4 + 2 + 2; size += 4 * 2; size += 4 * 9; size += 4 * 6; size += 4; size
131 }
132
133 fn primitive_mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
134 self.header.mux(writer)?;
135
136 if self.header.version == 1 {
137 writer.write_u64::<BigEndian>(self.creation_time)?;
138 writer.write_u64::<BigEndian>(self.modification_time)?;
139 writer.write_u32::<BigEndian>(self.timescale)?;
140 writer.write_u64::<BigEndian>(self.duration)?;
141 } else {
142 writer.write_u32::<BigEndian>(self.creation_time as u32)?;
143 writer.write_u32::<BigEndian>(self.modification_time as u32)?;
144 writer.write_u32::<BigEndian>(self.timescale)?;
145 writer.write_u32::<BigEndian>(self.duration as u32)?;
146 }
147
148 writer.write_i32::<BigEndian>(self.rate.to_bits())?;
149 writer.write_i16::<BigEndian>(self.volume.to_bits())?;
150
151 writer.write_u16::<BigEndian>(self.reserved)?;
152
153 for v in self.reserved2.iter() {
154 writer.write_u32::<BigEndian>(*v)?;
155 }
156
157 for v in self.matrix.iter() {
158 writer.write_u32::<BigEndian>(*v)?;
159 }
160
161 for v in self.pre_defined.iter() {
162 writer.write_u32::<BigEndian>(*v)?;
163 }
164
165 writer.write_u32::<BigEndian>(self.next_track_id)?;
166
167 Ok(())
168 }
169
170 fn validate(&self) -> io::Result<()> {
171 if self.header.flags != 0 {
172 return Err(io::Error::new(io::ErrorKind::InvalidData, "mvhd flags must be 0"));
173 }
174
175 if self.header.version > 1 {
176 return Err(io::Error::new(io::ErrorKind::InvalidData, "mvhd version must be 0 or 1"));
177 }
178
179 if self.header.version == 0 {
180 if self.creation_time > u32::MAX as u64 {
181 return Err(io::Error::new(
182 io::ErrorKind::InvalidData,
183 "mvhd creation_time must be less than 2^32",
184 ));
185 }
186
187 if self.modification_time > u32::MAX as u64 {
188 return Err(io::Error::new(
189 io::ErrorKind::InvalidData,
190 "mvhd modification_time must be less than 2^32",
191 ));
192 }
193
194 if self.duration > u32::MAX as u64 {
195 return Err(io::Error::new(
196 io::ErrorKind::InvalidData,
197 "mvhd duration must be less than 2^32",
198 ));
199 }
200 }
201
202 if self.reserved != 0 {
203 return Err(io::Error::new(io::ErrorKind::InvalidData, "mvhd reserved must be 0"));
204 }
205
206 if self.reserved2 != [0; 2] {
207 return Err(io::Error::new(io::ErrorKind::InvalidData, "mvhd reserved2 must be 0"));
208 }
209
210 if self.pre_defined != [0; 6] {
211 return Err(io::Error::new(io::ErrorKind::InvalidData, "mvhd pre_defined must be 0"));
212 }
213
214 Ok(())
215 }
216}