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