1use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
60use std::convert::TryInto;
61use std::io::{Read, Seek, SeekFrom, Write};
62
63use crate::*;
64
65pub(crate) mod avc1;
66pub(crate) mod co64;
67pub(crate) mod ctts;
68pub(crate) mod data;
69pub(crate) mod dinf;
70pub(crate) mod edts;
71pub(crate) mod elst;
72pub(crate) mod emsg;
73pub(crate) mod ftyp;
74pub(crate) mod hdlr;
75pub(crate) mod hev1;
76pub(crate) mod ilst;
77pub(crate) mod mdhd;
78pub(crate) mod mdia;
79pub(crate) mod mehd;
80pub(crate) mod meta;
81pub(crate) mod mfhd;
82pub(crate) mod minf;
83pub(crate) mod moof;
84pub(crate) mod moov;
85pub(crate) mod mp4a;
86pub(crate) mod mvex;
87pub(crate) mod mvhd;
88pub(crate) mod smhd;
89pub(crate) mod stbl;
90pub(crate) mod stco;
91pub(crate) mod stsc;
92pub(crate) mod stsd;
93pub(crate) mod stss;
94pub(crate) mod stsz;
95pub(crate) mod stts;
96pub(crate) mod tfdt;
97pub(crate) mod tfhd;
98pub(crate) mod tkhd;
99pub(crate) mod traf;
100pub(crate) mod trak;
101pub(crate) mod trex;
102pub(crate) mod trun;
103pub(crate) mod tx3g;
104pub(crate) mod udta;
105pub(crate) mod vmhd;
106pub(crate) mod vp09;
107pub(crate) mod vpcc;
108
109pub use emsg::EmsgBox;
110pub use ftyp::FtypBox;
111pub use moof::MoofBox;
112pub use moov::MoovBox;
113
114pub const HEADER_SIZE: u64 = 8;
115pub const HEADER_EXT_SIZE: u64 = 4;
117
118macro_rules! boxtype {
119 ($( $name:ident => $value:expr ),*) => {
120 #[derive(Clone, Copy, PartialEq, Eq)]
121 pub enum BoxType {
122 $( $name, )*
123 UnknownBox(u32),
124 }
125
126 impl From<u32> for BoxType {
127 fn from(t: u32) -> BoxType {
128 match t {
129 $( $value => BoxType::$name, )*
130 _ => BoxType::UnknownBox(t),
131 }
132 }
133 }
134
135 impl From<BoxType> for u32 {
136 fn from(b: BoxType) -> u32 {
137 match b {
138 $( BoxType::$name => $value, )*
139 BoxType::UnknownBox(t) => t,
140 }
141 }
142 }
143 }
144}
145
146boxtype! {
147 FtypBox => 0x66747970,
148 MvhdBox => 0x6d766864,
149 MfhdBox => 0x6d666864,
150 FreeBox => 0x66726565,
151 MdatBox => 0x6d646174,
152 MoovBox => 0x6d6f6f76,
153 MvexBox => 0x6d766578,
154 MehdBox => 0x6d656864,
155 TrexBox => 0x74726578,
156 EmsgBox => 0x656d7367,
157 MoofBox => 0x6d6f6f66,
158 TkhdBox => 0x746b6864,
159 TfhdBox => 0x74666864,
160 TfdtBox => 0x74666474,
161 EdtsBox => 0x65647473,
162 MdiaBox => 0x6d646961,
163 ElstBox => 0x656c7374,
164 MdhdBox => 0x6d646864,
165 HdlrBox => 0x68646c72,
166 MinfBox => 0x6d696e66,
167 VmhdBox => 0x766d6864,
168 StblBox => 0x7374626c,
169 StsdBox => 0x73747364,
170 SttsBox => 0x73747473,
171 CttsBox => 0x63747473,
172 StssBox => 0x73747373,
173 StscBox => 0x73747363,
174 StszBox => 0x7374737A,
175 StcoBox => 0x7374636F,
176 Co64Box => 0x636F3634,
177 TrakBox => 0x7472616b,
178 TrafBox => 0x74726166,
179 TrunBox => 0x7472756E,
180 UdtaBox => 0x75647461,
181 MetaBox => 0x6d657461,
182 DinfBox => 0x64696e66,
183 DrefBox => 0x64726566,
184 UrlBox => 0x75726C20,
185 SmhdBox => 0x736d6864,
186 Avc1Box => 0x61766331,
187 AvcCBox => 0x61766343,
188 Hev1Box => 0x68657631,
189 HvcCBox => 0x68766343,
190 Mp4aBox => 0x6d703461,
191 EsdsBox => 0x65736473,
192 Tx3gBox => 0x74783367,
193 VpccBox => 0x76706343,
194 Vp09Box => 0x76703039,
195 DataBox => 0x64617461,
196 IlstBox => 0x696c7374,
197 NameBox => 0xa96e616d,
198 DayBox => 0xa9646179,
199 CovrBox => 0x636f7672,
200 DescBox => 0x64657363,
201 WideBox => 0x77696465
202}
203
204pub trait Mp4Box: Sized {
205 fn box_type(&self) -> BoxType;
206 fn box_size(&self) -> u64;
207 fn to_json(&self) -> Result<String>;
208 fn summary(&self) -> Result<String>;
209}
210
211pub trait ReadBox<T>: Sized {
212 fn read_box(_: T, size: u64) -> Result<Self>;
213}
214
215pub trait WriteBox<T>: Sized {
216 fn write_box(&self, _: T) -> Result<u64>;
217}
218
219#[derive(Debug, Clone, Copy)]
220pub struct BoxHeader {
221 pub name: BoxType,
222 pub size: u64,
223}
224
225impl BoxHeader {
226 pub fn new(name: BoxType, size: u64) -> Self {
227 Self { name, size }
228 }
229
230 pub fn read<R: Read>(reader: &mut R) -> Result<Self> {
232 let mut buf = [0u8; 8]; reader.read_exact(&mut buf)?;
235
236 let s = buf[0..4].try_into().unwrap();
238 let size = u32::from_be_bytes(s);
239
240 let t = buf[4..8].try_into().unwrap();
242 let typ = u32::from_be_bytes(t);
243
244 if size == 1 {
246 reader.read_exact(&mut buf)?;
247 let largesize = u64::from_be_bytes(buf);
248
249 Ok(BoxHeader {
250 name: BoxType::from(typ),
251
252 size: match largesize {
256 0 => 0,
257 1..=15 => return Err(Error::InvalidData("64-bit box size too small")),
258 16..=u64::MAX => largesize - 8,
259 },
260 })
261 } else {
262 Ok(BoxHeader {
263 name: BoxType::from(typ),
264 size: size as u64,
265 })
266 }
267 }
268
269 pub fn write<W: Write>(&self, writer: &mut W) -> Result<u64> {
270 if self.size > u32::MAX as u64 {
271 writer.write_u32::<BigEndian>(1)?;
272 writer.write_u32::<BigEndian>(self.name.into())?;
273 writer.write_u64::<BigEndian>(self.size)?;
274 Ok(16)
275 } else {
276 writer.write_u32::<BigEndian>(self.size as u32)?;
277 writer.write_u32::<BigEndian>(self.name.into())?;
278 Ok(8)
279 }
280 }
281}
282
283pub fn read_box_header_ext<R: Read>(reader: &mut R) -> Result<(u8, u32)> {
284 let version = reader.read_u8()?;
285 let flags = reader.read_u24::<BigEndian>()?;
286 Ok((version, flags))
287}
288
289pub fn write_box_header_ext<W: Write>(w: &mut W, v: u8, f: u32) -> Result<u64> {
290 w.write_u8(v)?;
291 w.write_u24::<BigEndian>(f)?;
292 Ok(4)
293}
294
295pub fn box_start<R: Seek>(seeker: &mut R) -> Result<u64> {
296 Ok(seeker.stream_position()? - HEADER_SIZE)
297}
298
299pub fn skip_bytes<S: Seek>(seeker: &mut S, size: u64) -> Result<()> {
300 seeker.seek(SeekFrom::Current(size as i64))?;
301 Ok(())
302}
303
304pub fn skip_bytes_to<S: Seek>(seeker: &mut S, pos: u64) -> Result<()> {
305 seeker.seek(SeekFrom::Start(pos))?;
306 Ok(())
307}
308
309pub fn skip_box<S: Seek>(seeker: &mut S, size: u64) -> Result<()> {
310 let start = box_start(seeker)?;
311 skip_bytes_to(seeker, start + size)?;
312 Ok(())
313}
314
315pub fn write_zeros<W: Write>(writer: &mut W, size: u64) -> Result<()> {
316 for _ in 0..size {
317 writer.write_u8(0)?;
318 }
319 Ok(())
320}
321
322mod value_u32 {
323 use crate::types::FixedPointU16;
324 use serde::{self, Serializer};
325
326 pub fn serialize<S>(fixed: &FixedPointU16, serializer: S) -> Result<S::Ok, S::Error>
327 where
328 S: Serializer,
329 {
330 serializer.serialize_u16(fixed.value())
331 }
332}
333
334mod value_i16 {
335 use crate::types::FixedPointI8;
336 use serde::{self, Serializer};
337
338 pub fn serialize<S>(fixed: &FixedPointI8, serializer: S) -> Result<S::Ok, S::Error>
339 where
340 S: Serializer,
341 {
342 serializer.serialize_i8(fixed.value())
343 }
344}
345
346mod value_u8 {
347 use crate::types::FixedPointU8;
348 use serde::{self, Serializer};
349
350 pub fn serialize<S>(fixed: &FixedPointU8, serializer: S) -> Result<S::Ok, S::Error>
351 where
352 S: Serializer,
353 {
354 serializer.serialize_u8(fixed.value())
355 }
356}
357
358#[cfg(test)]
359mod tests {
360 use super::*;
361
362 #[test]
363 fn test_fourcc() {
364 let ftyp_fcc = 0x66747970;
365 let ftyp_value = FourCC::from(ftyp_fcc);
366 assert_eq!(&ftyp_value.value[..], b"ftyp");
367 let ftyp_fcc2: u32 = ftyp_value.into();
368 assert_eq!(ftyp_fcc, ftyp_fcc2);
369 }
370
371 #[test]
372 fn test_largesize_too_small() {
373 let error = BoxHeader::read(&mut &[0, 0, 0, 1, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 7][..]);
374 assert!(matches!(error, Err(Error::InvalidData(_))));
375 }
376
377 #[test]
378 fn test_zero_largesize() {
379 let error = BoxHeader::read(&mut &[0, 0, 0, 1, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 8][..]);
380 assert!(matches!(error, Err(Error::InvalidData(_))));
381 }
382
383 #[test]
384 fn test_nonzero_largesize_too_small() {
385 let error = BoxHeader::read(&mut &[0, 0, 0, 1, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 15][..]);
386 assert!(matches!(error, Err(Error::InvalidData(_))));
387 }
388
389 #[test]
390 fn test_valid_largesize() {
391 let header = BoxHeader::read(&mut &[0, 0, 0, 1, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 16][..]);
392 assert!(matches!(header, Ok(BoxHeader { size: 8, .. })));
393 }
394}