From 8df1ccc30a7d51d625f96d63eeee51e66db20afa Mon Sep 17 00:00:00 2001 From: Valerian G Date: Tue, 29 Jun 2021 00:25:15 +0000 Subject: [PATCH 01/11] added more box parsers --- examples/fragdump.rs | 92 ++++++++++++++++++++++++++++++++++ src/lib.rs | 6 +-- src/mp4box/ftyp.rs | 5 +- src/mp4box/mod.rs | 17 ++++++- src/mp4box/moof.rs | 2 +- src/mp4box/sidx.rs | 117 +++++++++++++++++++++++++++++++++++++++++++ src/mp4box/tfdt.rs | 63 +++++++++++++++++++++++ src/mp4box/tfhd.rs | 18 ++++++- src/mp4box/traf.rs | 18 +++++++ src/reader.rs | 10 ++-- src/writer.rs | 1 + 11 files changed, 334 insertions(+), 15 deletions(-) create mode 100644 examples/fragdump.rs create mode 100644 src/mp4box/sidx.rs create mode 100644 src/mp4box/tfdt.rs diff --git a/examples/fragdump.rs b/examples/fragdump.rs new file mode 100644 index 00000000..b031bd25 --- /dev/null +++ b/examples/fragdump.rs @@ -0,0 +1,92 @@ +use std::io::prelude::*; +use std::io; +use std::io::BufReader; +use std::env; +use std::path::Path; +use std::fs::File; +use std::io::SeekFrom; + +use mp4::Result; +use mp4::mp4box::*; + +fn main() { + let args: Vec = env::args().collect(); + + if args.len() < 3 { + println!("Usage: fragdump "); + std::process::exit(1); + } + + if let Err(err) = dump(&args[1], &args[2]) { + let _ = writeln!(io::stderr(), "{}", err); + } +} + +fn dump>(filename: &P, out: &P) -> Result<()> { + let f = File::open(filename)?; + let size = f.metadata()?.len(); + let mut reader = BufReader::new(f); + + let start = reader.seek(SeekFrom::Current(0))?; + + let mut styp = None; + let mut sidx = None; + let mut moof = None; + let mut mdat = None; + + let mut current = start; + while current < size { + let header = BoxHeader::read(&mut reader)?; + let BoxHeader { name, size: s } = header; + + match name { + BoxType::SidxBox => { + println!(" sidx in len {}", s); + sidx = Some(SidxBox::read_box(&mut reader, s)?); + } + BoxType::MoofBox => { + println!(" moof in len {}", s); + moof = Some(MoofBox::read_box(&mut reader, s)?); + } + BoxType::MdatBox => { + println!(" mdat in len {}", s); + let mut vec_mdat = vec![0; (s - 8) as usize]; + reader.read_exact(&mut vec_mdat)?; + mdat = Some(vec_mdat); + } + BoxType::StypBox => { + println!(" styp in len {}", s); + styp = Some(FtypBox::read_box(&mut reader, s)?); + } + b => { + println!("WARN: got unexpected box {:?}", b); + skip_box(&mut reader, s)?; + } + } + + current = reader.seek(SeekFrom::Current(0))?; + } + + let styp = styp.unwrap(); + let sidx = sidx.unwrap(); + let moof = moof.unwrap(); + let mdat = mdat.unwrap(); + +let mut vec = File::create(out)?; +// let mut vec = Vec::new(); + let t = styp.write_box(&mut vec)?; +// println!(" styp out len {} vs {}", t, vec.len()); +// let mut vec = Vec::new(); + let t = sidx.write_box(&mut vec)?; +// println!(" sidx out len {} vs {}", t, vec.len()); +// let mut vec = Vec::new(); + let t = moof.write_box(&mut vec)?; +// println!(" moof out len {} vs {}", t, vec.len()); + let mdat_hdr = BoxHeader::new(BoxType::MdatBox, mdat.len() as u64 + 8); +// let mut vec = Vec::new(); + let t = mdat_hdr.write(&mut vec)?; + let t = t + vec.write(&mdat)? as u64; +// println!(" mdat out len {} vs {}", t, vec.len()); + + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index eb5c24db..edd44b09 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,8 +77,8 @@ pub type Result = std::result::Result; mod types; pub use types::*; -mod mp4box; -pub use mp4box::{Mp4Box}; +pub mod mp4box; +pub use mp4box::Mp4Box; mod track; pub use track::{Mp4Track, TrackConfig}; @@ -94,4 +94,4 @@ pub fn read_mp4(f: File) -> Result>> { let reader = BufReader::new(f); let mp4 = reader::Mp4Reader::read_header(reader, size)?; Ok(mp4) -} \ No newline at end of file +} diff --git a/src/mp4box/ftyp.rs b/src/mp4box/ftyp.rs index 7f653137..05af247b 100644 --- a/src/mp4box/ftyp.rs +++ b/src/mp4box/ftyp.rs @@ -9,11 +9,12 @@ pub struct FtypBox { pub major_brand: FourCC, pub minor_version: u32, pub compatible_brands: Vec, + pub box_type: BoxType, } impl FtypBox { pub fn get_type(&self) -> BoxType { - BoxType::FtypBox + self.box_type } pub fn get_size(&self) -> u64 { @@ -68,6 +69,7 @@ impl ReadBox<&mut R> for FtypBox { major_brand: From::from(major), minor_version: minor, compatible_brands: brands, + box_type: BoxType::FtypBox }) } } @@ -103,6 +105,7 @@ mod tests { str::parse("avc1").unwrap(), str::parse("mp41").unwrap(), ], + box_type: BoxType::FtypBox, }; let mut buf = Vec::new(); src_box.write_box(&mut buf).unwrap(); diff --git a/src/mp4box/mod.rs b/src/mp4box/mod.rs index 1cca042a..5a36eb1e 100644 --- a/src/mp4box/mod.rs +++ b/src/mp4box/mod.rs @@ -92,10 +92,14 @@ pub(crate) mod tx3g; pub(crate) mod vmhd; pub(crate) mod vp09; pub(crate) mod vpcc; +pub mod sidx; +pub mod tfdt; pub use ftyp::FtypBox; pub use moov::MoovBox; pub use moof::MoofBox; +pub use sidx::SidxBox; +pub use tfdt::TfdtBox; pub const HEADER_SIZE: u64 = 8; // const HEADER_LARGE_SIZE: u64 = 16; @@ -103,12 +107,18 @@ pub const HEADER_EXT_SIZE: u64 = 4; macro_rules! boxtype { ($( $name:ident => $value:expr ),*) => { - #[derive(Clone, Copy, PartialEq)] + #[derive(Clone, Copy, PartialEq, serde::Serialize)] pub enum BoxType { $( $name, )* UnknownBox(u32), } + impl Default for BoxType { + fn default() -> BoxType { + BoxType::FreeBox + } + } + impl From for BoxType { fn from(t: u32) -> BoxType { match t { @@ -174,7 +184,10 @@ boxtype! { EsdsBox => 0x65736473, Tx3gBox => 0x74783367, VpccBox => 0x76706343, - Vp09Box => 0x76703039 + Vp09Box => 0x76703039, + SidxBox => 0x73696478, + StypBox => 0x73747970, + TfdtBox => 0x74666474 } pub trait Mp4Box: Sized { diff --git a/src/mp4box/moof.rs b/src/mp4box/moof.rs index d6533f36..01358f28 100644 --- a/src/mp4box/moof.rs +++ b/src/mp4box/moof.rs @@ -97,6 +97,6 @@ impl WriteBox<&mut W> for MoofBox { for traf in self.trafs.iter() { traf.write_box(writer)?; } - Ok(0) + Ok(size) } } diff --git a/src/mp4box/sidx.rs b/src/mp4box/sidx.rs new file mode 100644 index 00000000..45137c21 --- /dev/null +++ b/src/mp4box/sidx.rs @@ -0,0 +1,117 @@ +use crate::mp4box::*; +#[derive(Debug, Clone, PartialEq, Default, serde::Serialize)] +pub struct SidxBox { + pub version: u8, + pub flags: u32, + pub reference_id: u32, + pub timescale: u32, + pub earliest_presentation_time: u64, + pub first_offset: u64, + pub rest: Vec<(u64, u32)>, +} + +impl SidxBox { + pub fn get_type(&self) -> BoxType { + BoxType::SidxBox + } + + pub fn get_size(&self) -> u64 { + let sub_hdr_sz = match self.version { + 0 => 8, + _ => 16, + }; + + HEADER_SIZE + HEADER_EXT_SIZE + 4 + 8 + sub_hdr_sz + (self.rest.len() as u64 * 12) + } +} + +impl Mp4Box for SidxBox { + fn box_type(&self) -> BoxType { + self.get_type() + } + + fn box_size(&self) -> u64 { + self.get_size() + } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + Ok(String::new()) + } +} + +impl ReadBox<&mut R> for SidxBox { + fn read_box(reader: &mut R, size: u64) -> Result { + let start = box_start(reader)?; + + let version = reader.read_u8()?; + let flags = reader.read_u24::()?; + + let reference_id = match version { + 0 => reader.read_u16::()? as u32, + _ => reader.read_u32::()?, + }; + + let timescale = match version { + 0 => reader.read_u16::()? as u32, + _ => reader.read_u32::()?, + }; + + let earliest_presentation_time = reader.read_u64::()?; + let first_offset = reader.read_u64::()?; + let _reserved = reader.read_u16::()?; + let ref_count = reader.read_u16::()?; + + let mut rest = Vec::new(); + for _ in 1..=ref_count { + let rest_1 = reader.read_u64::()?; + let rest_2 = reader.read_u32::()?; + + rest.push((rest_1, rest_2)); + } + + skip_bytes_to(reader, start + size)?; + + Ok(Self { + version, + flags, + reference_id, + timescale, + earliest_presentation_time, + first_offset, + rest + }) + } +} + +impl WriteBox<&mut W> for SidxBox { + fn write_box(&self, writer: &mut W) -> Result { + let size = self.box_size(); + BoxHeader::new(self.box_type(), size).write(writer)?; + + write_box_header_ext(writer, self.version, self.flags)?; + match self.version { + 0 => writer.write_u16::(self.reference_id as u16)?, + _ => writer.write_u32::(self.reference_id)?, + } + + match self.version { + 0 => writer.write_u16::(self.timescale as u16)?, + _ => writer.write_u32::(self.timescale)?, + } + + writer.write_u64::(self.earliest_presentation_time)?; + writer.write_u64::(self.first_offset)?; + writer.write_u16::(0)?; + writer.write_u16::(self.rest.len() as u16)?; + for r in &self.rest { + writer.write_u64::(r.0)?; + writer.write_u32::(r.1)?; + } + + Ok(size) + } +} diff --git a/src/mp4box/tfdt.rs b/src/mp4box/tfdt.rs new file mode 100644 index 00000000..741d184b --- /dev/null +++ b/src/mp4box/tfdt.rs @@ -0,0 +1,63 @@ +use std::io::{Read, Seek, Write}; +use serde::{Serialize}; + +use crate::mp4box::*; + +#[derive(Debug, Default, Clone, PartialEq, Serialize)] +pub struct TfdtBox { + pub version: u8, + pub flags: u32, + pub base_media_decode_time: u64 +} + +impl Mp4Box for TfdtBox { + fn box_type(&self) -> BoxType { + BoxType::TfdtBox + } + + fn box_size(&self) -> u64 { + HEADER_SIZE + HEADER_EXT_SIZE + 8 + } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + Ok(String::new()) + } +} + +impl ReadBox<&mut R> for TfdtBox { + fn read_box(reader: &mut R, size: u64) -> Result { + let start = box_start(reader)?; + + let (version, flags) = read_box_header_ext(reader)?; + let base_media_decode_time = match version { + 0 => reader.read_u32::()? as u64, + _ => reader.read_u64::()?, + }; + + skip_bytes_to(reader, start + size)?; + + Ok(TfdtBox { + version, + flags, + base_media_decode_time, + }) + + } +} + +impl WriteBox<&mut W> for TfdtBox { + fn write_box(&self, writer: &mut W) -> Result { + let size = self.box_size(); + BoxHeader::new(self.box_type(), size).write(writer)?; + + write_box_header_ext(writer, self.version, self.flags)?; + writer.write_u64::(self.base_media_decode_time)?; + + Ok(size) + + } +} diff --git a/src/mp4box/tfhd.rs b/src/mp4box/tfhd.rs index bf7169c4..0353c47e 100644 --- a/src/mp4box/tfhd.rs +++ b/src/mp4box/tfhd.rs @@ -10,6 +10,9 @@ pub struct TfhdBox { pub flags: u32, pub track_id: u32, pub base_data_offset: u64, + pub default_sample_duration: u32, + pub default_sample_size: u32, + pub default_sample_flags: u32, } impl Default for TfhdBox { @@ -19,6 +22,9 @@ impl Default for TfhdBox { flags: 0, track_id: 0, base_data_offset: 0, + default_sample_duration: 0, + default_sample_size: 0, + default_sample_flags: 0 } } } @@ -29,7 +35,7 @@ impl TfhdBox { } pub fn get_size(&self) -> u64 { - HEADER_SIZE + HEADER_EXT_SIZE + 4 + 8 + HEADER_SIZE + HEADER_EXT_SIZE + 4 + 4 + 8 } } @@ -59,6 +65,9 @@ impl ReadBox<&mut R> for TfhdBox { let (version, flags) = read_box_header_ext(reader)?; let track_id = reader.read_u32::()?; let base_data_offset = reader.read_u64::()?; + let default_sample_duration = reader.read_u32::()?; + let default_sample_size = reader.read_u32::()?; + let default_sample_flags = reader.read_u32::()?; skip_bytes_to(reader, start + size)?; @@ -67,6 +76,9 @@ impl ReadBox<&mut R> for TfhdBox { flags, track_id, base_data_offset, + default_sample_duration, + default_sample_flags, + default_sample_size }) } } @@ -79,6 +91,7 @@ impl WriteBox<&mut W> for TfhdBox { write_box_header_ext(writer, self.version, self.flags)?; writer.write_u32::(self.track_id)?; writer.write_u64::(self.base_data_offset)?; + writer.write_u32::(self.default_sample_duration)?; Ok(size) } @@ -97,6 +110,9 @@ mod tests { flags: 0, track_id: 1, base_data_offset: 0, + default_sample_duration: 0, + default_sample_flags: 0, + default_sample_size: 0, }; let mut buf = Vec::new(); src_box.write_box(&mut buf).unwrap(); diff --git a/src/mp4box/traf.rs b/src/mp4box/traf.rs index e4c1ad43..4381d935 100644 --- a/src/mp4box/traf.rs +++ b/src/mp4box/traf.rs @@ -7,6 +7,7 @@ use crate::mp4box::{tfhd::TfhdBox, trun::TrunBox}; #[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct TrafBox { pub tfhd: TfhdBox, + pub tfdt: Option, pub trun: Option, } @@ -21,6 +22,9 @@ impl TrafBox { if let Some(ref trun) = self.trun { size += trun.box_size(); } + if let Some(ref tfdt) = self.tfdt { + size += tfdt.box_size(); + } size } } @@ -49,6 +53,7 @@ impl ReadBox<&mut R> for TrafBox { let start = box_start(reader)?; let mut tfhd = None; + let mut tfdt = None; let mut trun = None; let mut current = reader.seek(SeekFrom::Current(0))?; @@ -62,6 +67,9 @@ impl ReadBox<&mut R> for TrafBox { BoxType::TfhdBox => { tfhd = Some(TfhdBox::read_box(reader, s)?); } + BoxType::TfdtBox => { + tfdt = Some(TfdtBox::read_box(reader, s)?); + } BoxType::TrunBox => { trun = Some(TrunBox::read_box(reader, s)?); } @@ -82,6 +90,7 @@ impl ReadBox<&mut R> for TrafBox { Ok(TrafBox { tfhd: tfhd.unwrap(), + tfdt, trun, }) } @@ -94,6 +103,15 @@ impl WriteBox<&mut W> for TrafBox { self.tfhd.write_box(writer)?; + if let Some(ref tfdt) = self.tfdt { + tfdt.write_box(writer)?; + } + + if let Some(ref trun) = self.trun { + trun.write_box(writer)?; + } + + Ok(size) } } diff --git a/src/reader.rs b/src/reader.rs index b610942e..98257df5 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -47,6 +47,9 @@ impl Mp4Reader { let moof = MoofBox::read_box(&mut reader, s)?; moofs.push(moof); } + BoxType::SidxBox => { + let _sidx = SidxBox::read_box(&mut reader, s)?; + } _ => { // XXX warn!() skip_box(&mut reader, s)?; @@ -55,13 +58,6 @@ impl Mp4Reader { current = reader.seek(SeekFrom::Current(0))?; } - if ftyp.is_none() { - return Err(Error::BoxNotFound(BoxType::FtypBox)); - } - if moov.is_none() { - return Err(Error::BoxNotFound(BoxType::MoovBox)); - } - let size = current - start; let mut tracks = if let Some(ref moov) = moov { let mut tracks = Vec::with_capacity(moov.traks.len()); diff --git a/src/writer.rs b/src/writer.rs index 5c946f6f..b74d0836 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -65,6 +65,7 @@ impl Mp4Writer { major_brand: config.major_brand.clone(), minor_version: config.minor_version.clone(), compatible_brands: config.compatible_brands.clone(), + box_type: BoxType::FtypBox, }; ftyp.write_box(&mut writer)?; From b5a89e7ff0d64157912bd0fea44a17808f588244 Mon Sep 17 00:00:00 2001 From: Valerian G Date: Fri, 2 Jul 2021 22:26:48 +0100 Subject: [PATCH 02/11] add mdat atom parser --- examples/fragdump.rs | 4 +++- src/mp4box/mdat.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++ src/mp4box/mod.rs | 2 ++ src/mp4box/trun.rs | 4 ++-- 4 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 src/mp4box/mdat.rs diff --git a/examples/fragdump.rs b/examples/fragdump.rs index b031bd25..cbc8a651 100644 --- a/examples/fragdump.rs +++ b/examples/fragdump.rs @@ -69,7 +69,9 @@ fn dump>(filename: &P, out: &P) -> Result<()> { let styp = styp.unwrap(); let sidx = sidx.unwrap(); - let moof = moof.unwrap(); + let mut moof = moof.unwrap(); + let tfdt = moof.trafs[0].tfdt.as_mut().unwrap(); + tfdt.base_media_decode_time = sidx.earliest_presentation_time + 5; let mdat = mdat.unwrap(); let mut vec = File::create(out)?; diff --git a/src/mp4box/mdat.rs b/src/mp4box/mdat.rs new file mode 100644 index 00000000..19d8245e --- /dev/null +++ b/src/mp4box/mdat.rs @@ -0,0 +1,50 @@ +use crate::mp4box::*; + +#[derive(Debug, Clone, PartialEq, Default, serde::Serialize)] +pub struct MdatBox { + pub data: Vec, +} + +impl Mp4Box for MdatBox { + fn box_type(&self) -> BoxType { + BoxType::MdatBox + } + + fn box_size(&self) -> u64 { + HEADER_SIZE + self.data.len() as u64 + } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + Ok(String::new()) + } +} + +impl ReadBox<&mut R> for MdatBox { + fn read_box(reader: &mut R, size: u64) -> Result { + let start = box_start(reader)?; + + let mut data = Vec::with_capacity(size as usize); + reader.read_exact(&mut data)?; + + skip_bytes_to(reader, start + size)?; + + Ok(Self { + data + }) + } +} + +impl WriteBox<&mut W> for MdatBox { + fn write_box(&self, writer: &mut W) -> Result { + let size = self.box_size(); + BoxHeader::new(self.box_type(), size).write(writer)?; + + writer.write_all(&self.data)?; + + Ok(size) + } +} diff --git a/src/mp4box/mod.rs b/src/mp4box/mod.rs index 5a36eb1e..cc3e3db9 100644 --- a/src/mp4box/mod.rs +++ b/src/mp4box/mod.rs @@ -94,12 +94,14 @@ pub(crate) mod vp09; pub(crate) mod vpcc; pub mod sidx; pub mod tfdt; +pub mod mdat; pub use ftyp::FtypBox; pub use moov::MoovBox; pub use moof::MoofBox; pub use sidx::SidxBox; pub use tfdt::TfdtBox; +pub use mdat::MdatBox; pub const HEADER_SIZE: u64 = 8; // const HEADER_LARGE_SIZE: u64 = 16; diff --git a/src/mp4box/trun.rs b/src/mp4box/trun.rs index bf6f1cf5..7c9f5da4 100644 --- a/src/mp4box/trun.rs +++ b/src/mp4box/trun.rs @@ -154,8 +154,8 @@ impl WriteBox<&mut W> for TrunBox { if let Some(v) = self.first_sample_flags { writer.write_u32::(v)?; } - assert_eq!(self.sample_count, self.sample_sizes.len() as u32); - for i in 0..self.sample_count as usize { + + for i in 0..self.sample_sizes.len() as usize { if TrunBox::FLAG_SAMPLE_DURATION & self.flags > 0 { writer.write_u32::(self.sample_durations[i])?; } From 7a8db1a21050a16ee956aa307647d8cb4af5f442 Mon Sep 17 00:00:00 2001 From: Valerian G Date: Fri, 2 Jul 2021 22:36:37 +0100 Subject: [PATCH 03/11] add AnyBox type --- src/mp4box/mdat.rs | 35 +++++++++++++++++++++++++++++++++++ src/mp4box/mod.rs | 1 + 2 files changed, 36 insertions(+) diff --git a/src/mp4box/mdat.rs b/src/mp4box/mdat.rs index 19d8245e..020936b3 100644 --- a/src/mp4box/mdat.rs +++ b/src/mp4box/mdat.rs @@ -48,3 +48,38 @@ impl WriteBox<&mut W> for MdatBox { Ok(size) } } + +#[derive(Debug, Clone, PartialEq, Default, serde::Serialize)] +pub struct AnyBox { + pub box_type: BoxType, + pub data: Vec, +} + +impl Mp4Box for AnyBox { + fn box_type(&self) -> BoxType { + self.box_type + } + + fn box_size(&self) -> u64 { + HEADER_SIZE + self.data.len() as u64 + } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + Ok(String::new()) + } +} + +impl WriteBox<&mut W> for AnyBox { + fn write_box(&self, writer: &mut W) -> Result { + let size = self.box_size(); + BoxHeader::new(self.box_type(), size).write(writer)?; + + writer.write_all(&self.data)?; + + Ok(size) + } +} diff --git a/src/mp4box/mod.rs b/src/mp4box/mod.rs index cc3e3db9..68a941f4 100644 --- a/src/mp4box/mod.rs +++ b/src/mp4box/mod.rs @@ -102,6 +102,7 @@ pub use moof::MoofBox; pub use sidx::SidxBox; pub use tfdt::TfdtBox; pub use mdat::MdatBox; +pub use mdat::AnyBox; pub const HEADER_SIZE: u64 = 8; // const HEADER_LARGE_SIZE: u64 = 16; From baf40af44ae717d40c7f29d97be24407e6164dac Mon Sep 17 00:00:00 2001 From: Valerian G Date: Sat, 3 Jul 2021 00:09:07 +0100 Subject: [PATCH 04/11] fixed bug where mdat buffer wasnt getting filled --- src/mp4box/mdat.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mp4box/mdat.rs b/src/mp4box/mdat.rs index 020936b3..1f318ab3 100644 --- a/src/mp4box/mdat.rs +++ b/src/mp4box/mdat.rs @@ -27,7 +27,7 @@ impl ReadBox<&mut R> for MdatBox { fn read_box(reader: &mut R, size: u64) -> Result { let start = box_start(reader)?; - let mut data = Vec::with_capacity(size as usize); + let mut data = vec![0; size as usize - 8]; reader.read_exact(&mut data)?; skip_bytes_to(reader, start + size)?; From 98227a1cc85f27c46e467a4fbbc9bc9e887adf47 Mon Sep 17 00:00:00 2001 From: Valerian G Date: Wed, 7 Jul 2021 14:47:49 +0100 Subject: [PATCH 05/11] added more ub + formatting --- src/lib.rs | 17 ++++----- src/mp4box/avc1.rs | 11 +++--- src/mp4box/co64.rs | 2 +- src/mp4box/ctts.rs | 2 +- src/mp4box/dinf.rs | 8 ++-- src/mp4box/edts.rs | 2 +- src/mp4box/elst.rs | 2 +- src/mp4box/ftyp.rs | 12 ++++-- src/mp4box/hdlr.rs | 8 +++- src/mp4box/hev1.rs | 11 +++--- src/mp4box/mdat.rs | 4 +- src/mp4box/mdhd.rs | 8 ++-- src/mp4box/mdia.rs | 2 +- src/mp4box/mehd.rs | 3 +- src/mp4box/mfhd.rs | 4 +- src/mp4box/minf.rs | 2 +- src/mp4box/mod.rs | 72 +++++++++++++++-------------------- src/mp4box/moof.rs | 2 +- src/mp4box/moov.rs | 4 +- src/mp4box/mp4a.rs | 30 ++++++++++----- src/mp4box/mvex.rs | 4 +- src/mp4box/mvhd.rs | 11 ++++-- src/mp4box/sidx.rs | 4 +- src/mp4box/smhd.rs | 2 +- src/mp4box/stbl.rs | 12 ++---- src/mp4box/stco.rs | 2 +- src/mp4box/stsc.rs | 2 +- src/mp4box/stsd.rs | 6 +-- src/mp4box/stss.rs | 2 +- src/mp4box/stsz.rs | 10 +++-- src/mp4box/stts.rs | 2 +- src/mp4box/tfdt.rs | 8 ++-- src/mp4box/tfhd.rs | 6 +-- src/mp4box/tkhd.rs | 15 ++++++-- src/mp4box/traf.rs | 3 +- src/mp4box/trak.rs | 2 +- src/mp4box/trex.rs | 16 ++++---- src/mp4box/trun.rs | 45 ++++++++++++++++++---- src/mp4box/tx3g.rs | 10 ++--- src/mp4box/vmhd.rs | 10 ++--- src/mp4box/vp09.rs | 21 ++++++++--- src/mp4box/vpcc.rs | 12 ++++-- src/track.rs | 49 +++++++++++------------- src/types.rs | 94 ++++++++++++++++++++++++---------------------- src/writer.rs | 4 +- 45 files changed, 308 insertions(+), 250 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index edd44b09..13193bdd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,14 @@ //! `mp4` is a Rust library to read and write ISO-MP4 files. -//! +//! //! This package contains MPEG-4 specifications defined in parts: //! * ISO/IEC 14496-12 - ISO Base Media File Format (QuickTime, MPEG-4, etc) //! * ISO/IEC 14496-14 - MP4 file format //! * ISO/IEC 14496-17 - Streaming text format -//! +//! //! See: [mp4box] for supported MP4 atoms. -//! +//! //! ### Example -//! +//! //! ``` //! use std::fs::File; //! use std::io::{BufReader}; @@ -49,9 +49,9 @@ //! Ok(()) //! } //! ``` -//! +//! //! See [examples] for more examples. -//! +//! //! # Installation //! //! Add the following to your `Cargo.toml` file: @@ -60,14 +60,13 @@ //! [dependencies] //! mp4 = "0.7.0" //! ``` -//! +//! //! [mp4box]: https://github.com/alfg/mp4-rust/blob/master/src/mp4box/mod.rs //! [examples]: https://github.com/alfg/mp4-rust/blob/master/src/examples #![doc(html_root_url = "https://docs.rs/mp4/*")] - -use std::io::{BufReader}; use std::fs::File; +use std::io::BufReader; mod error; pub use error::Error; diff --git a/src/mp4box/avc1.rs b/src/mp4box/avc1.rs index 640c97e7..8dfdf81e 100644 --- a/src/mp4box/avc1.rs +++ b/src/mp4box/avc1.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; @@ -72,8 +72,10 @@ impl Mp4Box for Avc1Box { } fn summary(&self) -> Result { - let s = format!("data_reference_index={} width={} height={} frame_count={}", - self.data_reference_index, self.width, self.height, self.frame_count); + let s = format!( + "data_reference_index={} width={} height={} frame_count={}", + self.data_reference_index, self.width, self.height, self.frame_count + ); Ok(s) } } @@ -197,8 +199,7 @@ impl Mp4Box for AvcCBox { } fn summary(&self) -> Result { - let s = format!("avc_profile_indication={}", - self.avc_profile_indication); + let s = format!("avc_profile_indication={}", self.avc_profile_indication); Ok(s) } } diff --git a/src/mp4box/co64.rs b/src/mp4box/co64.rs index d54ce12d..463a5941 100644 --- a/src/mp4box/co64.rs +++ b/src/mp4box/co64.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; diff --git a/src/mp4box/ctts.rs b/src/mp4box/ctts.rs index e7b05109..5c034291 100644 --- a/src/mp4box/ctts.rs +++ b/src/mp4box/ctts.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; diff --git a/src/mp4box/dinf.rs b/src/mp4box/dinf.rs index 8b10848d..a9ec79f1 100644 --- a/src/mp4box/dinf.rs +++ b/src/mp4box/dinf.rs @@ -1,5 +1,5 @@ +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; @@ -159,7 +159,7 @@ impl ReadBox<&mut R> for DrefBox { match name { BoxType::UrlBox => { - url = Some(UrlBox::read_box(reader, s)?); + url = Some(UrlBox::read_box(reader, s)?); } _ => { skip_box(reader, s)?; @@ -221,7 +221,7 @@ impl UrlBox { pub fn get_size(&self) -> u64 { let mut size = HEADER_SIZE + HEADER_EXT_SIZE; - if ! self.location.is_empty() { + if !self.location.is_empty() { size += self.location.bytes().len() as u64 + 1; } @@ -286,7 +286,7 @@ impl WriteBox<&mut W> for UrlBox { write_box_header_ext(writer, self.version, self.flags)?; - if ! self.location.is_empty() { + if !self.location.is_empty() { writer.write(self.location.as_bytes())?; writer.write_u8(0)?; } diff --git a/src/mp4box/edts.rs b/src/mp4box/edts.rs index fb7308a6..4adc01ff 100644 --- a/src/mp4box/edts.rs +++ b/src/mp4box/edts.rs @@ -1,5 +1,5 @@ +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::elst::ElstBox; use crate::mp4box::*; diff --git a/src/mp4box/elst.rs b/src/mp4box/elst.rs index 7407eee2..0d53f575 100644 --- a/src/mp4box/elst.rs +++ b/src/mp4box/elst.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; diff --git a/src/mp4box/ftyp.rs b/src/mp4box/ftyp.rs index 05af247b..67bf31d8 100644 --- a/src/mp4box/ftyp.rs +++ b/src/mp4box/ftyp.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; @@ -40,8 +40,12 @@ impl Mp4Box for FtypBox { for brand in self.compatible_brands.iter() { compatible_brands.push(brand.to_string()); } - let s = format!("major_brand={} minor_version={} compatible_brands={}", - self.major_brand, self.minor_version, compatible_brands.join("-")); + let s = format!( + "major_brand={} minor_version={} compatible_brands={}", + self.major_brand, + self.minor_version, + compatible_brands.join("-") + ); Ok(s) } } @@ -69,7 +73,7 @@ impl ReadBox<&mut R> for FtypBox { major_brand: From::from(major), minor_version: minor, compatible_brands: brands, - box_type: BoxType::FtypBox + box_type: BoxType::FtypBox, }) } } diff --git a/src/mp4box/hdlr.rs b/src/mp4box/hdlr.rs index 62410a85..56707dac 100644 --- a/src/mp4box/hdlr.rs +++ b/src/mp4box/hdlr.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; @@ -36,7 +36,11 @@ impl Mp4Box for HdlrBox { } fn summary(&self) -> Result { - let s = format!("handler_type={} name={}", self.handler_type.to_string(), self.name); + let s = format!( + "handler_type={} name={}", + self.handler_type.to_string(), + self.name + ); Ok(s) } } diff --git a/src/mp4box/hev1.rs b/src/mp4box/hev1.rs index 248218d2..01cc1710 100644 --- a/src/mp4box/hev1.rs +++ b/src/mp4box/hev1.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; @@ -72,8 +72,10 @@ impl Mp4Box for Hev1Box { } fn summary(&self) -> Result { - let s = format!("data_reference_index={} width={} height={} frame_count={}", - self.data_reference_index, self.width, self.height, self.frame_count); + let s = format!( + "data_reference_index={} width={} height={} frame_count={}", + self.data_reference_index, self.width, self.height, self.frame_count + ); Ok(s) } } @@ -179,8 +181,7 @@ impl Mp4Box for HvcCBox { } fn summary(&self) -> Result { - let s = format!("configuration_version={}", - self.configuration_version); + let s = format!("configuration_version={}", self.configuration_version); Ok(s) } } diff --git a/src/mp4box/mdat.rs b/src/mp4box/mdat.rs index 1f318ab3..07621ab0 100644 --- a/src/mp4box/mdat.rs +++ b/src/mp4box/mdat.rs @@ -32,9 +32,7 @@ impl ReadBox<&mut R> for MdatBox { skip_bytes_to(reader, start + size)?; - Ok(Self { - data - }) + Ok(Self { data }) } } diff --git a/src/mp4box/mdhd.rs b/src/mp4box/mdhd.rs index c3d24df2..03238d1f 100644 --- a/src/mp4box/mdhd.rs +++ b/src/mp4box/mdhd.rs @@ -1,7 +1,7 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::char::{decode_utf16, REPLACEMENT_CHARACTER}; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; @@ -63,8 +63,10 @@ impl Mp4Box for MdhdBox { } fn summary(&self) -> Result { - let s = format!("creation_time={} timescale={} duration={} language={}", - self.creation_time, self.timescale, self.duration, self.language); + let s = format!( + "creation_time={} timescale={} duration={} language={}", + self.creation_time, self.timescale, self.duration, self.language + ); Ok(s) } } diff --git a/src/mp4box/mdia.rs b/src/mp4box/mdia.rs index d6f3cfd0..afe95d83 100644 --- a/src/mp4box/mdia.rs +++ b/src/mp4box/mdia.rs @@ -1,5 +1,5 @@ +use serde::Serialize; use std::io::{Read, Seek, SeekFrom, Write}; -use serde::{Serialize}; use crate::mp4box::*; use crate::mp4box::{hdlr::HdlrBox, mdhd::MdhdBox, minf::MinfBox}; diff --git a/src/mp4box/mehd.rs b/src/mp4box/mehd.rs index 7a4627b6..1fe06e37 100644 --- a/src/mp4box/mehd.rs +++ b/src/mp4box/mehd.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; @@ -104,7 +104,6 @@ mod tests { use crate::mp4box::BoxHeader; use std::io::Cursor; - #[test] fn test_mehd32() { let src_box = MehdBox { diff --git a/src/mp4box/mfhd.rs b/src/mp4box/mfhd.rs index 0d108d1b..0442dcd3 100644 --- a/src/mp4box/mfhd.rs +++ b/src/mp4box/mfhd.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; @@ -27,7 +27,7 @@ impl MfhdBox { } pub fn get_size(&self) -> u64 { - HEADER_SIZE + HEADER_EXT_SIZE + 4 + HEADER_SIZE + HEADER_EXT_SIZE + 4 } } diff --git a/src/mp4box/minf.rs b/src/mp4box/minf.rs index fac40de6..8afa25ec 100644 --- a/src/mp4box/minf.rs +++ b/src/mp4box/minf.rs @@ -1,5 +1,5 @@ +use serde::Serialize; use std::io::{Read, Seek, SeekFrom, Write}; -use serde::{Serialize}; use crate::mp4box::*; use crate::mp4box::{dinf::DinfBox, smhd::SmhdBox, stbl::StblBox, vmhd::VmhdBox}; diff --git a/src/mp4box/mod.rs b/src/mp4box/mod.rs index 68a941f4..7ac5580c 100644 --- a/src/mp4box/mod.rs +++ b/src/mp4box/mod.rs @@ -1,13 +1,13 @@ //! All ISO-MP4 boxes (atoms) and operations. -//! +//! //! * [ISO/IEC 14496-12](https://en.wikipedia.org/wiki/MPEG-4_Part_14) - ISO Base Media File Format (QuickTime, MPEG-4, etc) //! * [ISO/IEC 14496-14](https://en.wikipedia.org/wiki/MPEG-4_Part_14) - MP4 file format //! * ISO/IEC 14496-17 - Streaming text format -//! +//! //! http://developer.apple.com/documentation/QuickTime/QTFF/index.html //! http://www.adobe.com/devnet/video/articles/mp4_movie_atom.html -//! http://mp4ra.org/#/atoms -//! +//! http://mp4ra.org/#/atoms +//! //! Supported Atoms: //! ftyp //! moov @@ -47,7 +47,7 @@ //! trun //! mdat //! free -//! +//! use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::convert::TryInto; @@ -62,19 +62,20 @@ pub(crate) mod dinf; pub(crate) mod edts; pub(crate) mod elst; pub(crate) mod ftyp; -pub(crate) mod hev1; pub(crate) mod hdlr; +pub(crate) mod hev1; +pub mod mdat; pub(crate) mod mdhd; pub(crate) mod mdia; -pub(crate) mod minf; -pub(crate) mod moov; -pub(crate) mod mvex; pub(crate) mod mehd; -pub(crate) mod trex; +pub(crate) mod mfhd; +pub(crate) mod minf; pub(crate) mod moof; +pub(crate) mod moov; pub(crate) mod mp4a; +pub(crate) mod mvex; pub(crate) mod mvhd; -pub(crate) mod mfhd; +pub mod sidx; pub(crate) mod smhd; pub(crate) mod stbl; pub(crate) mod stco; @@ -83,26 +84,25 @@ pub(crate) mod stsd; pub(crate) mod stss; pub(crate) mod stsz; pub(crate) mod stts; -pub(crate) mod tkhd; +pub mod tfdt; pub(crate) mod tfhd; -pub(crate) mod trak; +pub(crate) mod tkhd; pub(crate) mod traf; +pub(crate) mod trak; +pub(crate) mod trex; pub(crate) mod trun; pub(crate) mod tx3g; pub(crate) mod vmhd; pub(crate) mod vp09; pub(crate) mod vpcc; -pub mod sidx; -pub mod tfdt; -pub mod mdat; pub use ftyp::FtypBox; -pub use moov::MoovBox; +pub use mdat::AnyBox; +pub use mdat::MdatBox; pub use moof::MoofBox; +pub use moov::MoovBox; pub use sidx::SidxBox; pub use tfdt::TfdtBox; -pub use mdat::MdatBox; -pub use mdat::AnyBox; pub const HEADER_SIZE: u64 = 8; // const HEADER_LARGE_SIZE: u64 = 16; @@ -308,48 +308,38 @@ mod value_u32 { use crate::types::FixedPointU16; use serde::{self, Serializer}; - pub fn serialize( - fixed: &FixedPointU16, - serializer: S, - ) -> Result + pub fn serialize(fixed: &FixedPointU16, serializer: S) -> Result where S: Serializer, - { - serializer.serialize_u16(fixed.value()) - } + { + serializer.serialize_u16(fixed.value()) + } } mod value_i16 { use crate::types::FixedPointI8; use serde::{self, Serializer}; - pub fn serialize( - fixed: &FixedPointI8, - serializer: S, - ) -> Result + pub fn serialize(fixed: &FixedPointI8, serializer: S) -> Result where S: Serializer, - { - serializer.serialize_i8(fixed.value()) - } + { + serializer.serialize_i8(fixed.value()) + } } mod value_u8 { use crate::types::FixedPointU8; use serde::{self, Serializer}; - pub fn serialize( - fixed: &FixedPointU8, - serializer: S, - ) -> Result + pub fn serialize(fixed: &FixedPointU8, serializer: S) -> Result where S: Serializer, - { - serializer.serialize_u8(fixed.value()) - } + { + serializer.serialize_u8(fixed.value()) + } } - #[cfg(test)] mod tests { use super::*; diff --git a/src/mp4box/moof.rs b/src/mp4box/moof.rs index 01358f28..341cf6e9 100644 --- a/src/mp4box/moof.rs +++ b/src/mp4box/moof.rs @@ -1,5 +1,5 @@ +use serde::Serialize; use std::io::{Read, Seek, SeekFrom, Write}; -use serde::{Serialize}; use crate::mp4box::*; use crate::mp4box::{mfhd::MfhdBox, traf::TrafBox}; diff --git a/src/mp4box/moov.rs b/src/mp4box/moov.rs index c7243caa..7cc3610d 100644 --- a/src/mp4box/moov.rs +++ b/src/mp4box/moov.rs @@ -1,8 +1,8 @@ +use serde::Serialize; use std::io::{Read, Seek, SeekFrom, Write}; -use serde::{Serialize}; use crate::mp4box::*; -use crate::mp4box::{mvhd::MvhdBox, mvex::MvexBox, trak::TrakBox}; +use crate::mp4box::{mvex::MvexBox, mvhd::MvhdBox, trak::TrakBox}; #[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct MoovBox { diff --git a/src/mp4box/mp4a.rs b/src/mp4box/mp4a.rs index fc8ec694..3492d7e8 100644 --- a/src/mp4box/mp4a.rs +++ b/src/mp4box/mp4a.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; @@ -65,8 +65,12 @@ impl Mp4Box for Mp4aBox { } fn summary(&self) -> Result { - let s = format!("channel_count={} sample_size={} sample_rate={}", - self.channelcount, self.samplesize, self.samplerate.value()); + let s = format!( + "channel_count={} sample_size={} sample_rate={}", + self.channelcount, + self.samplesize, + self.samplerate.value() + ); Ok(s) } } @@ -150,8 +154,11 @@ impl Mp4Box for EsdsBox { } fn box_size(&self) -> u64 { - HEADER_SIZE + HEADER_EXT_SIZE - + 1 + size_of_length(ESDescriptor::desc_size()) as u64 + ESDescriptor::desc_size() as u64 + HEADER_SIZE + + HEADER_EXT_SIZE + + 1 + + size_of_length(ESDescriptor::desc_size()) as u64 + + ESDescriptor::desc_size() as u64 } fn to_json(&self) -> Result { @@ -293,9 +300,12 @@ impl Descriptor for ESDescriptor { } fn desc_size() -> u32 { - 3 - + 1 + size_of_length(DecoderConfigDescriptor::desc_size()) + DecoderConfigDescriptor::desc_size() - + 1 + size_of_length(SLConfigDescriptor::desc_size()) + SLConfigDescriptor::desc_size() + 3 + 1 + + size_of_length(DecoderConfigDescriptor::desc_size()) + + DecoderConfigDescriptor::desc_size() + + 1 + + size_of_length(SLConfigDescriptor::desc_size()) + + SLConfigDescriptor::desc_size() } } @@ -382,7 +392,9 @@ impl Descriptor for DecoderConfigDescriptor { } fn desc_size() -> u32 { - 13 + 1 + size_of_length(DecoderSpecificDescriptor::desc_size()) + DecoderSpecificDescriptor::desc_size() + 13 + 1 + + size_of_length(DecoderSpecificDescriptor::desc_size()) + + DecoderSpecificDescriptor::desc_size() } } diff --git a/src/mp4box/mvex.rs b/src/mp4box/mvex.rs index 31dc0b7c..7dee9638 100644 --- a/src/mp4box/mvex.rs +++ b/src/mp4box/mvex.rs @@ -1,5 +1,5 @@ +use serde::Serialize; use std::io::{Read, Seek, SeekFrom, Write}; -use serde::{Serialize}; use crate::mp4box::*; use crate::mp4box::{mehd::MehdBox, trex::TrexBox}; @@ -87,7 +87,7 @@ impl WriteBox<&mut W> for MvexBox { let size = self.box_size(); BoxHeader::new(self.box_type(), size).write(writer)?; - if let Some(mehd) = &self.mehd{ + if let Some(mehd) = &self.mehd { mehd.write_box(writer)?; } self.trex.write_box(writer)?; diff --git a/src/mp4box/mvhd.rs b/src/mp4box/mvhd.rs index 3a96f103..c1ac5762 100644 --- a/src/mp4box/mvhd.rs +++ b/src/mp4box/mvhd.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; @@ -63,8 +63,13 @@ impl Mp4Box for MvhdBox { } fn summary(&self) -> Result { - let s = format!("creation_time={} timescale={} duration={} rate={}", - self.creation_time, self.timescale, self.duration, self.rate.value()); + let s = format!( + "creation_time={} timescale={} duration={} rate={}", + self.creation_time, + self.timescale, + self.duration, + self.rate.value() + ); Ok(s) } } diff --git a/src/mp4box/sidx.rs b/src/mp4box/sidx.rs index 45137c21..acfcf237 100644 --- a/src/mp4box/sidx.rs +++ b/src/mp4box/sidx.rs @@ -74,7 +74,7 @@ impl ReadBox<&mut R> for SidxBox { } skip_bytes_to(reader, start + size)?; - + Ok(Self { version, flags, @@ -82,7 +82,7 @@ impl ReadBox<&mut R> for SidxBox { timescale, earliest_presentation_time, first_offset, - rest + rest, }) } } diff --git a/src/mp4box/smhd.rs b/src/mp4box/smhd.rs index fc5b2683..4232050d 100644 --- a/src/mp4box/smhd.rs +++ b/src/mp4box/smhd.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; diff --git a/src/mp4box/stbl.rs b/src/mp4box/stbl.rs index c399b125..ed9be04e 100644 --- a/src/mp4box/stbl.rs +++ b/src/mp4box/stbl.rs @@ -1,16 +1,10 @@ +use serde::Serialize; use std::io::{Read, Seek, SeekFrom, Write}; -use serde::{Serialize}; use crate::mp4box::*; use crate::mp4box::{ - co64::Co64Box, - ctts::CttsBox, - stco::StcoBox, - stsc::StscBox, - stsd::StsdBox, - stss::StssBox, - stsz::StszBox, - stts::SttsBox, + co64::Co64Box, ctts::CttsBox, stco::StcoBox, stsc::StscBox, stsd::StsdBox, stss::StssBox, + stsz::StszBox, stts::SttsBox, }; #[derive(Debug, Clone, PartialEq, Default, Serialize)] diff --git a/src/mp4box/stco.rs b/src/mp4box/stco.rs index 89210bd3..eddcd829 100644 --- a/src/mp4box/stco.rs +++ b/src/mp4box/stco.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; diff --git a/src/mp4box/stsc.rs b/src/mp4box/stsc.rs index c1556217..89f5fa60 100644 --- a/src/mp4box/stsc.rs +++ b/src/mp4box/stsc.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; diff --git a/src/mp4box/stsd.rs b/src/mp4box/stsd.rs index a05c65fd..d7b1b1d1 100644 --- a/src/mp4box/stsd.rs +++ b/src/mp4box/stsd.rs @@ -1,10 +1,10 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; +use crate::mp4box::vp09::Vp09Box; use crate::mp4box::*; use crate::mp4box::{avc1::Avc1Box, hev1::Hev1Box, mp4a::Mp4aBox, tx3g::Tx3gBox}; -use crate::mp4box::vp09::Vp09Box; #[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct StsdBox { @@ -16,7 +16,7 @@ pub struct StsdBox { #[serde(skip_serializing_if = "Option::is_none")] pub hev1: Option, - + #[serde(skip_serializing_if = "Option::is_none")] pub vp09: Option, diff --git a/src/mp4box/stss.rs b/src/mp4box/stss.rs index 639698e6..b24606ff 100644 --- a/src/mp4box/stss.rs +++ b/src/mp4box/stss.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; diff --git a/src/mp4box/stsz.rs b/src/mp4box/stsz.rs index b76ba860..ffc97a15 100644 --- a/src/mp4box/stsz.rs +++ b/src/mp4box/stsz.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; @@ -39,8 +39,12 @@ impl Mp4Box for StszBox { } fn summary(&self) -> Result { - let s = format!("sample_size={} sample_count={} sample_sizes={}", - self.sample_size, self.sample_count, self.sample_sizes.len()); + let s = format!( + "sample_size={} sample_count={} sample_sizes={}", + self.sample_size, + self.sample_count, + self.sample_sizes.len() + ); Ok(s) } } diff --git a/src/mp4box/stts.rs b/src/mp4box/stts.rs index 5260ff1f..141a450f 100644 --- a/src/mp4box/stts.rs +++ b/src/mp4box/stts.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; diff --git a/src/mp4box/tfdt.rs b/src/mp4box/tfdt.rs index 741d184b..cc29f7d4 100644 --- a/src/mp4box/tfdt.rs +++ b/src/mp4box/tfdt.rs @@ -1,5 +1,5 @@ +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; @@ -7,7 +7,7 @@ use crate::mp4box::*; pub struct TfdtBox { pub version: u8, pub flags: u32, - pub base_media_decode_time: u64 + pub base_media_decode_time: u64, } impl Mp4Box for TfdtBox { @@ -18,7 +18,7 @@ impl Mp4Box for TfdtBox { fn box_size(&self) -> u64 { HEADER_SIZE + HEADER_EXT_SIZE + 8 } - + fn to_json(&self) -> Result { Ok(serde_json::to_string(&self).unwrap()) } @@ -45,7 +45,6 @@ impl ReadBox<&mut R> for TfdtBox { flags, base_media_decode_time, }) - } } @@ -58,6 +57,5 @@ impl WriteBox<&mut W> for TfdtBox { writer.write_u64::(self.base_media_decode_time)?; Ok(size) - } } diff --git a/src/mp4box/tfhd.rs b/src/mp4box/tfhd.rs index 0353c47e..90af8b97 100644 --- a/src/mp4box/tfhd.rs +++ b/src/mp4box/tfhd.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; @@ -24,7 +24,7 @@ impl Default for TfhdBox { base_data_offset: 0, default_sample_duration: 0, default_sample_size: 0, - default_sample_flags: 0 + default_sample_flags: 0, } } } @@ -78,7 +78,7 @@ impl ReadBox<&mut R> for TfhdBox { base_data_offset, default_sample_duration, default_sample_flags, - default_sample_size + default_sample_size, }) } } diff --git a/src/mp4box/tkhd.rs b/src/mp4box/tkhd.rs index 75de65d0..3cfe7307 100644 --- a/src/mp4box/tkhd.rs +++ b/src/mp4box/tkhd.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; @@ -104,9 +104,16 @@ impl Mp4Box for TkhdBox { } fn summary(&self) -> Result { - let s = format!("creation_time={} track_id={} duration={} layer={} volume={} width={} height={}", - self.creation_time, self.track_id, self.duration, self.layer, - self.volume.value(), self.width.value(), self.height.value()); + let s = format!( + "creation_time={} track_id={} duration={} layer={} volume={} width={} height={}", + self.creation_time, + self.track_id, + self.duration, + self.layer, + self.volume.value(), + self.width.value(), + self.height.value() + ); Ok(s) } } diff --git a/src/mp4box/traf.rs b/src/mp4box/traf.rs index 4381d935..b19ce6e8 100644 --- a/src/mp4box/traf.rs +++ b/src/mp4box/traf.rs @@ -1,5 +1,5 @@ +use serde::Serialize; use std::io::{Read, Seek, SeekFrom, Write}; -use serde::{Serialize}; use crate::mp4box::*; use crate::mp4box::{tfhd::TfhdBox, trun::TrunBox}; @@ -111,7 +111,6 @@ impl WriteBox<&mut W> for TrafBox { trun.write_box(writer)?; } - Ok(size) } } diff --git a/src/mp4box/trak.rs b/src/mp4box/trak.rs index 3d7c4654..e03b63a2 100644 --- a/src/mp4box/trak.rs +++ b/src/mp4box/trak.rs @@ -1,5 +1,5 @@ +use serde::Serialize; use std::io::{Read, Seek, SeekFrom, Write}; -use serde::{Serialize}; use crate::mp4box::*; use crate::mp4box::{edts::EdtsBox, mdia::MdiaBox, tkhd::TkhdBox}; diff --git a/src/mp4box/trex.rs b/src/mp4box/trex.rs index 943265fd..010c1f18 100644 --- a/src/mp4box/trex.rs +++ b/src/mp4box/trex.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; @@ -9,10 +9,10 @@ pub struct TrexBox { pub version: u8, pub flags: u32, pub track_id: u32, - pub default_sample_description_index: u32, - pub default_sample_duration: u32, - pub default_sample_size: u32, - pub default_sample_flags: u32, + pub default_sample_description_index: u32, + pub default_sample_duration: u32, + pub default_sample_size: u32, + pub default_sample_flags: u32, } impl TrexBox { @@ -39,8 +39,10 @@ impl Mp4Box for TrexBox { } fn summary(&self) -> Result { - let s = format!("track_id={} default_sample_duration={}", - self.track_id, self.default_sample_duration); + let s = format!( + "track_id={} default_sample_duration={}", + self.track_id, self.default_sample_duration + ); Ok(s) } } diff --git a/src/mp4box/trun.rs b/src/mp4box/trun.rs index 7c9f5da4..4191bea7 100644 --- a/src/mp4box/trun.rs +++ b/src/mp4box/trun.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; @@ -44,15 +44,19 @@ impl TrunBox { } if TrunBox::FLAG_SAMPLE_DURATION & self.flags > 0 { sum += 4 * self.sample_count as u64; + assert_eq!(self.sample_count as usize, self.sample_durations.len()); } if TrunBox::FLAG_SAMPLE_SIZE & self.flags > 0 { sum += 4 * self.sample_count as u64; + assert_eq!(self.sample_count as usize, self.sample_sizes.len()); } if TrunBox::FLAG_SAMPLE_FLAGS & self.flags > 0 { sum += 4 * self.sample_count as u64; + assert_eq!(self.sample_count as usize, self.sample_flags.len()); } if TrunBox::FLAG_SAMPLE_CTS & self.flags > 0 { sum += 4 * self.sample_count as u64; + assert_eq!(self.sample_count as usize, self.sample_cts.len()); } sum } @@ -72,8 +76,7 @@ impl Mp4Box for TrunBox { } fn summary(&self) -> Result { - let s = format!("sample_size={}", - self.sample_count); + let s = format!("sample_size={}", self.sample_count); Ok(s) } } @@ -142,34 +145,59 @@ impl ReadBox<&mut R> for TrunBox { impl WriteBox<&mut W> for TrunBox { fn write_box(&self, writer: &mut W) -> Result { + let mut real_len = 0; let size = self.box_size(); - BoxHeader::new(self.box_type(), size).write(writer)?; + real_len += BoxHeader::new(self.box_type(), size).write(writer)?; - write_box_header_ext(writer, self.version, self.flags)?; + real_len += write_box_header_ext(writer, self.version, self.flags)?; + real_len += 4; writer.write_u32::(self.sample_count)?; - if let Some(v) = self.data_offset{ + if let Some(v) = self.data_offset { + real_len += 4; writer.write_i32::(v)?; + } else if TrunBox::FLAG_DATA_OFFSET & self.flags > 0 { + println!("got flag data offset but self.data_offset is None"); } + if let Some(v) = self.first_sample_flags { + real_len += 4; writer.write_u32::(v)?; + } else if TrunBox::FLAG_FIRST_SAMPLE_FLAGS & self.flags > 0 { + println!("got flag_first_sample_flags but self.first_sample_flags is None."); } for i in 0..self.sample_sizes.len() as usize { if TrunBox::FLAG_SAMPLE_DURATION & self.flags > 0 { + real_len += 4; writer.write_u32::(self.sample_durations[i])?; } if TrunBox::FLAG_SAMPLE_SIZE & self.flags > 0 { + real_len += 4; writer.write_u32::(self.sample_sizes[i])?; } if TrunBox::FLAG_SAMPLE_FLAGS & self.flags > 0 { + real_len += 4; writer.write_u32::(self.sample_flags[i])?; } if TrunBox::FLAG_SAMPLE_CTS & self.flags > 0 { + real_len += 4; writer.write_u32::(self.sample_cts[i])?; } } + // sanity check + // assert_eq!(real_len, size); + // FIXME: Ugly hack, it seems that sometimes the writer writes less bytes than it expects + // which makes no fucking sense btw, anyway we detect this and fill it with zeroes. + // + // NOTE: 95% sure this is UB. + if real_len < size { + for _ in 0..(size - real_len) { + writer.write_u8(0)?; + } + } + Ok(size) } } @@ -210,7 +238,10 @@ mod tests { fn test_trun_many_sizes() { let src_box = TrunBox { version: 0, - flags: TrunBox::FLAG_SAMPLE_DURATION | TrunBox::FLAG_SAMPLE_SIZE | TrunBox::FLAG_SAMPLE_FLAGS | TrunBox::FLAG_SAMPLE_CTS, + flags: TrunBox::FLAG_SAMPLE_DURATION + | TrunBox::FLAG_SAMPLE_SIZE + | TrunBox::FLAG_SAMPLE_FLAGS + | TrunBox::FLAG_SAMPLE_CTS, data_offset: None, sample_count: 9, sample_sizes: vec![1165, 11, 11, 8545, 10126, 10866, 9643, 9351, 7730], diff --git a/src/mp4box/tx3g.rs b/src/mp4box/tx3g.rs index 55b6ab18..eb5c1699 100644 --- a/src/mp4box/tx3g.rs +++ b/src/mp4box/tx3g.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; @@ -20,7 +20,7 @@ pub struct RgbaColor { pub red: u8, pub green: u8, pub blue: u8, - pub alpha: u8 + pub alpha: u8, } impl Default for Tx3gBox { @@ -30,7 +30,7 @@ impl Default for Tx3gBox { display_flags: 0, horizontal_justification: 1, vertical_justification: -1, - bg_color_rgba: RgbaColor{ + bg_color_rgba: RgbaColor { red: 0, green: 0, blue: 0, @@ -48,7 +48,7 @@ impl Tx3gBox { } pub fn get_size(&self) -> u64 { - HEADER_SIZE + 6 + 32 + HEADER_SIZE + 6 + 32 } } @@ -165,7 +165,7 @@ mod tests { display_flags: 0, horizontal_justification: 1, vertical_justification: -1, - bg_color_rgba: RgbaColor{ + bg_color_rgba: RgbaColor { red: 0, green: 0, blue: 0, diff --git a/src/mp4box/vmhd.rs b/src/mp4box/vmhd.rs index 20250556..9e01c709 100644 --- a/src/mp4box/vmhd.rs +++ b/src/mp4box/vmhd.rs @@ -1,6 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use serde::Serialize; use std::io::{Read, Seek, Write}; -use serde::{Serialize}; use crate::mp4box::*; @@ -43,11 +43,9 @@ impl Mp4Box for VmhdBox { } fn summary(&self) -> Result { - let s = format!("graphics_mode={} op_color={}{}{}", - self.graphics_mode, - self.op_color.red, - self.op_color.green, - self.op_color.blue + let s = format!( + "graphics_mode={} op_color={}{}{}", + self.graphics_mode, self.op_color.red, self.op_color.green, self.op_color.blue ); Ok(s) } diff --git a/src/mp4box/vp09.rs b/src/mp4box/vp09.rs index cdb49e42..0b9fdad1 100644 --- a/src/mp4box/vp09.rs +++ b/src/mp4box/vp09.rs @@ -1,7 +1,7 @@ -use crate::Mp4Box; -use crate::mp4box::*; -use serde::{Serialize}; use crate::mp4box::vpcc::VpccBox; +use crate::mp4box::*; +use crate::Mp4Box; +use serde::Serialize; #[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct Vp09Box { @@ -97,8 +97,14 @@ impl ReadBox<&mut R> for Vp09Box { }; let width: u16 = reader.read_u16::()?; let height: u16 = reader.read_u16::()?; - let horizresolution: (u16, u16) = (reader.read_u16::()?, reader.read_u16::()?); - let vertresolution: (u16, u16) = (reader.read_u16::()?, reader.read_u16::()?); + let horizresolution: (u16, u16) = ( + reader.read_u16::()?, + reader.read_u16::()?, + ); + let vertresolution: (u16, u16) = ( + reader.read_u16::()?, + reader.read_u16::()?, + ); let reserved1: [u8; 4] = { let mut buf = [0u8; 4]; reader.read_exact(&mut buf)?; @@ -175,7 +181,10 @@ mod tests { #[test] fn test_vpcc() { - let src_box = Vp09Box::new(&Vp9Config{ width: 1920, height: 1080 }); + let src_box = Vp09Box::new(&Vp9Config { + width: 1920, + height: 1080, + }); let mut buf = Vec::new(); src_box.write_box(&mut buf).unwrap(); assert_eq!(buf.len(), src_box.box_size() as usize); diff --git a/src/mp4box/vpcc.rs b/src/mp4box/vpcc.rs index 7330c336..a1d883f2 100644 --- a/src/mp4box/vpcc.rs +++ b/src/mp4box/vpcc.rs @@ -1,6 +1,6 @@ -use crate::Mp4Box; use crate::mp4box::*; -use serde::{Serialize}; +use crate::Mp4Box; +use serde::Serialize; #[derive(Debug, Clone, PartialEq, Default, Serialize)] pub struct VpccBox { @@ -82,7 +82,11 @@ impl WriteBox<&mut W> for VpccBox { writer.write_u8(self.profile)?; writer.write_u8(self.level)?; - writer.write_u8((self.bit_depth << 4) | (self.chroma_subsampling << 1) | (self.video_full_range_flag as u8))?; + writer.write_u8( + (self.bit_depth << 4) + | (self.chroma_subsampling << 1) + | (self.video_full_range_flag as u8), + )?; writer.write_u8(self.color_primaries)?; writer.write_u8(self.transfer_characteristics)?; writer.write_u8(self.matrix_coefficients)?; @@ -125,4 +129,4 @@ mod tests { let dst_box = VpccBox::read_box(&mut reader, header.size).unwrap(); assert_eq!(src_box, dst_box); } -} \ No newline at end of file +} diff --git a/src/track.rs b/src/track.rs index 46e846cd..7e21b8ea 100644 --- a/src/track.rs +++ b/src/track.rs @@ -4,23 +4,13 @@ use std::convert::TryFrom; use std::io::{Read, Seek, SeekFrom, Write}; use std::time::Duration; -use crate::mp4box::trak::TrakBox; use crate::mp4box::traf::TrafBox; +use crate::mp4box::trak::TrakBox; use crate::mp4box::*; use crate::mp4box::{ - avc1::Avc1Box, - hev1::Hev1Box, + avc1::Avc1Box, ctts::CttsBox, ctts::CttsEntry, hev1::Hev1Box, mp4a::Mp4aBox, smhd::SmhdBox, + stco::StcoBox, stsc::StscEntry, stss::StssBox, stts::SttsEntry, tx3g::Tx3gBox, vmhd::VmhdBox, vp09::Vp09Box, - ctts::CttsBox, - ctts::CttsEntry, - mp4a::Mp4aBox, - smhd::SmhdBox, - stco::StcoBox, - stsc::StscEntry, - stss::StssBox, - stts::SttsEntry, - tx3g::Tx3gBox, - vmhd::VmhdBox, }; use crate::*; @@ -111,7 +101,11 @@ pub struct Mp4Track { impl Mp4Track { pub(crate) fn from(trak: &TrakBox) -> Self { let trak = trak.clone(); - Self { trak, trafs: Vec::new(), default_sample_duration: 0, } + Self { + trak, + trafs: Vec::new(), + default_sample_duration: 0, + } } pub fn track_id(&self) -> u32 { @@ -362,7 +356,7 @@ impl Mp4Track { } /// return `(traf_idx, sample_idx_in_trun)` - fn find_traf_idx_and_sample_idx(&self, sample_id: u32) -> Option<(usize, usize)>{ + fn find_traf_idx_and_sample_idx(&self, sample_id: u32) -> Option<(usize, usize)> { let global_idx = sample_id - 1; let mut offset = 0; for traf_idx in 0..self.trafs.len() { @@ -380,7 +374,13 @@ impl Mp4Track { fn sample_size(&self, sample_id: u32) -> Result { if self.trafs.len() > 0 { if let Some((traf_idx, sample_idx)) = self.find_traf_idx_and_sample_idx(sample_id) { - if let Some(size) = self.trafs[traf_idx].trun.as_ref().unwrap().sample_sizes.get(sample_idx) { + if let Some(size) = self.trafs[traf_idx] + .trun + .as_ref() + .unwrap() + .sample_sizes + .get(sample_idx) + { Ok(*size) } else { Err(Error::EntryInTrunNotFound( @@ -390,10 +390,7 @@ impl Mp4Track { )) } } else { - Err(Error::BoxInTrafNotFound( - self.track_id(), - BoxType::TrafBox, - )) + Err(Error::BoxInTrafNotFound(self.track_id(), BoxType::TrafBox)) } } else { let stsz = &self.trak.mdia.minf.stbl.stsz; @@ -430,10 +427,7 @@ impl Mp4Track { if let Some((traf_idx, _sample_idx)) = self.find_traf_idx_and_sample_idx(sample_id) { Ok(self.trafs[traf_idx].tfhd.base_data_offset as u64) } else { - Err(Error::BoxInTrafNotFound( - self.track_id(), - BoxType::TrafBox, - )) + Err(Error::BoxInTrafNotFound(self.track_id(), BoxType::TrafBox)) } } else { let stsc_index = self.stsc_index(sample_id); @@ -467,8 +461,8 @@ impl Mp4Track { let mut elapsed = 0; if self.trafs.len() > 0 { - let start_time = ((sample_id - 1) * self.default_sample_duration) as u64; - return Ok((start_time, self.default_sample_duration)) + let start_time = ((sample_id - 1) * self.default_sample_duration) as u64; + return Ok((start_time, self.default_sample_duration)); } else { for entry in stts.entries.iter() { if sample_id <= sample_count + entry.sample_count - 1 { @@ -502,7 +496,7 @@ impl Mp4Track { fn is_sync_sample(&self, sample_id: u32) -> bool { if self.trafs.len() > 0 { let sample_sizes_count = self.sample_count() / self.trafs.len() as u32; - return sample_id == 1 || sample_id % sample_sizes_count == 0 + return sample_id == 1 || sample_id % sample_sizes_count == 0; } if let Some(ref stss) = self.trak.mdia.minf.stbl.stss { @@ -608,7 +602,6 @@ impl Mp4TrackWriter { let tx3g = Tx3gBox::default(); trak.mdia.minf.stbl.stsd.tx3g = Some(tx3g); } - } Ok(Mp4TrackWriter { trak, diff --git a/src/types.rs b/src/types.rs index 22bc933d..272da397 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,6 +1,6 @@ +use serde::Serialize; use std::convert::TryFrom; use std::fmt; -use serde::{Serialize}; use crate::mp4box::*; use crate::*; @@ -95,7 +95,9 @@ impl std::str::FromStr for FourCC { fn from_str(s: &str) -> Result { if let [a, b, c, d] = s.as_bytes() { - Ok(Self { value: [*a, *b, *c, *d] }) + Ok(Self { + value: [*a, *b, *c, *d], + }) } else { Err(Error::InvalidData("expected exactly four bytes in string")) } @@ -104,7 +106,9 @@ impl std::str::FromStr for FourCC { impl From for FourCC { fn from(number: u32) -> Self { - FourCC { value: number.to_be_bytes() } + FourCC { + value: number.to_be_bytes(), + } } } @@ -313,48 +317,48 @@ impl fmt::Display for AvcProfile { #[derive(Debug, PartialEq, Clone, Copy)] pub enum AudioObjectType { - AacMain = 1, // AAC Main Profile - AacLowComplexity = 2, // AAC Low Complexity - AacScalableSampleRate = 3, // AAC Scalable Sample Rate - AacLongTermPrediction = 4, // AAC Long Term Predictor - SpectralBandReplication = 5, // Spectral band Replication - AACScalable = 6, // AAC Scalable - TwinVQ = 7, // Twin VQ - CodeExcitedLinearPrediction = 8, // CELP - HarmonicVectorExcitationCoding = 9, // HVXC - TextToSpeechtInterface = 12, // TTSI - MainSynthetic = 13, // Main Synthetic - WavetableSynthesis = 14, // Wavetable Synthesis - GeneralMIDI = 15, // General MIDI - AlgorithmicSynthesis = 16, // Algorithmic Synthesis - ErrorResilientAacLowComplexity = 17, // ER AAC LC - ErrorResilientAacLongTermPrediction = 19, // ER AAC LTP - ErrorResilientAacScalable = 20, // ER AAC Scalable - ErrorResilientAacTwinVQ = 21, // ER AAC TwinVQ - ErrorResilientAacBitSlicedArithmeticCoding = 22, // ER Bit Sliced Arithmetic Coding - ErrorResilientAacLowDelay = 23, // ER AAC Low Delay - ErrorResilientCodeExcitedLinearPrediction = 24, // ER CELP - ErrorResilientHarmonicVectorExcitationCoding = 25, // ER HVXC - ErrorResilientHarmonicIndividualLinesNoise = 26, // ER HILN - ErrorResilientParametric = 27, // ER Parametric - SinuSoidalCoding = 28, // SSC - ParametricStereo = 29, // PS - MpegSurround = 30, // MPEG Surround - MpegLayer1 = 32, // MPEG Layer 1 - MpegLayer2 = 33, // MPEG Layer 2 - MpegLayer3 = 34, // MPEG Layer 3 - DirectStreamTransfer = 35, // DST Direct Stream Transfer - AudioLosslessCoding = 36, // ALS Audio Lossless Coding - ScalableLosslessCoding = 37, // SLC Scalable Lossless Coding - ScalableLosslessCodingNoneCore = 38, // SLC non-core - ErrorResilientAacEnhancedLowDelay = 39, // ER AAC ELD - SymbolicMusicRepresentationSimple = 40, // SMR Simple - SymbolicMusicRepresentationMain = 41, // SMR Main - UnifiedSpeechAudioCoding = 42, // USAC - SpatialAudioObjectCoding = 43, // SAOC - LowDelayMpegSurround = 44, // LD MPEG Surround - SpatialAudioObjectCodingDialogueEnhancement = 45, // SAOC-DE - AudioSync = 46, // Audio Sync + AacMain = 1, // AAC Main Profile + AacLowComplexity = 2, // AAC Low Complexity + AacScalableSampleRate = 3, // AAC Scalable Sample Rate + AacLongTermPrediction = 4, // AAC Long Term Predictor + SpectralBandReplication = 5, // Spectral band Replication + AACScalable = 6, // AAC Scalable + TwinVQ = 7, // Twin VQ + CodeExcitedLinearPrediction = 8, // CELP + HarmonicVectorExcitationCoding = 9, // HVXC + TextToSpeechtInterface = 12, // TTSI + MainSynthetic = 13, // Main Synthetic + WavetableSynthesis = 14, // Wavetable Synthesis + GeneralMIDI = 15, // General MIDI + AlgorithmicSynthesis = 16, // Algorithmic Synthesis + ErrorResilientAacLowComplexity = 17, // ER AAC LC + ErrorResilientAacLongTermPrediction = 19, // ER AAC LTP + ErrorResilientAacScalable = 20, // ER AAC Scalable + ErrorResilientAacTwinVQ = 21, // ER AAC TwinVQ + ErrorResilientAacBitSlicedArithmeticCoding = 22, // ER Bit Sliced Arithmetic Coding + ErrorResilientAacLowDelay = 23, // ER AAC Low Delay + ErrorResilientCodeExcitedLinearPrediction = 24, // ER CELP + ErrorResilientHarmonicVectorExcitationCoding = 25, // ER HVXC + ErrorResilientHarmonicIndividualLinesNoise = 26, // ER HILN + ErrorResilientParametric = 27, // ER Parametric + SinuSoidalCoding = 28, // SSC + ParametricStereo = 29, // PS + MpegSurround = 30, // MPEG Surround + MpegLayer1 = 32, // MPEG Layer 1 + MpegLayer2 = 33, // MPEG Layer 2 + MpegLayer3 = 34, // MPEG Layer 3 + DirectStreamTransfer = 35, // DST Direct Stream Transfer + AudioLosslessCoding = 36, // ALS Audio Lossless Coding + ScalableLosslessCoding = 37, // SLC Scalable Lossless Coding + ScalableLosslessCodingNoneCore = 38, // SLC non-core + ErrorResilientAacEnhancedLowDelay = 39, // ER AAC ELD + SymbolicMusicRepresentationSimple = 40, // SMR Simple + SymbolicMusicRepresentationMain = 41, // SMR Main + UnifiedSpeechAudioCoding = 42, // USAC + SpatialAudioObjectCoding = 43, // SAOC + LowDelayMpegSurround = 44, // LD MPEG Surround + SpatialAudioObjectCodingDialogueEnhancement = 45, // SAOC-DE + AudioSync = 46, // Audio Sync } impl TryFrom for AudioObjectType { diff --git a/src/writer.rs b/src/writer.rs index b74d0836..a1c87ad3 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -27,9 +27,9 @@ impl Mp4Writer { /// /// This can be useful to recover the inner writer after completion in case /// it's owned by the [Mp4Writer] instance. - /// + /// /// # Examples - /// + /// /// ```rust /// use mp4::{Mp4Writer, Mp4Config}; /// use std::io::Cursor; From 02a2907d653e6cde67cf129caaf7cce886143a7f Mon Sep 17 00:00:00 2001 From: Valerian G Date: Fri, 10 Sep 2021 14:38:05 +0100 Subject: [PATCH 06/11] bump num-rational to v0.4 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 0387c4d9..ca654dcd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ license = "MIT" thiserror = "^1.0" byteorder = "1" bytes = "0.5" -num-rational = { version = "0.3", features = ["serde"] } +num-rational = { version = "0.4", features = ["serde"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" From d4f85ce3a438bc80d93df467c3f3320c5b3352e7 Mon Sep 17 00:00:00 2001 From: Valerian G Date: Mon, 20 Sep 2021 13:21:51 +0100 Subject: [PATCH 07/11] disable num-bigint --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ca654dcd..a6a9796d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ license = "MIT" thiserror = "^1.0" byteorder = "1" bytes = "0.5" -num-rational = { version = "0.4", features = ["serde"] } +num-rational = { version = "0.4", default-features = false, features = ["std", "serde"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" From 27f62343cdf4fc7fe94c455135d6210c77e17f9a Mon Sep 17 00:00:00 2001 From: Valerian Garleanu Date: Thu, 7 Dec 2023 15:06:30 +0000 Subject: [PATCH 08/11] sidx: parse subseg durations --- examples/mp4dump.rs | 4 ++-- examples/mp4info.rs | 2 +- src/mp4box/sidx.rs | 32 +++++++++++++++++++++----------- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/examples/mp4dump.rs b/examples/mp4dump.rs index 2882e328..5a97f75e 100644 --- a/examples/mp4dump.rs +++ b/examples/mp4dump.rs @@ -48,7 +48,7 @@ fn get_boxes(file: File) -> Result> { let mut boxes = Vec::new(); // ftyp, moov, mvhd - boxes.push(build_box(&mp4.ftyp)); + boxes.push(build_box(mp4.ftyp())); boxes.push(build_box(&mp4.moov)); boxes.push(build_box(&mp4.moov.mvhd)); @@ -140,4 +140,4 @@ fn build_box(ref m: &M) -> Box { summary: m.summary().unwrap(), indent: 0, }; -} \ No newline at end of file +} diff --git a/examples/mp4info.rs b/examples/mp4info.rs index a2637771..69f41dcf 100644 --- a/examples/mp4info.rs +++ b/examples/mp4info.rs @@ -141,4 +141,4 @@ fn creation_time(creation_time: u64) -> u64 { } else { creation_time } -} \ No newline at end of file +} diff --git a/src/mp4box/sidx.rs b/src/mp4box/sidx.rs index acfcf237..4d437129 100644 --- a/src/mp4box/sidx.rs +++ b/src/mp4box/sidx.rs @@ -7,7 +7,8 @@ pub struct SidxBox { pub timescale: u32, pub earliest_presentation_time: u64, pub first_offset: u64, - pub rest: Vec<(u64, u32)>, + + pub subseg_durations: Vec, } impl SidxBox { @@ -15,13 +16,21 @@ impl SidxBox { BoxType::SidxBox } + pub fn total_duration(&self) -> u32 { + self.subseg_durations.iter().sum() + } + + pub fn timescale(&self) -> u32 { + self.timescale + } + pub fn get_size(&self) -> u64 { let sub_hdr_sz = match self.version { 0 => 8, _ => 16, }; - HEADER_SIZE + HEADER_EXT_SIZE + 4 + 8 + sub_hdr_sz + (self.rest.len() as u64 * 12) + HEADER_SIZE + HEADER_EXT_SIZE + 4 + 8 + sub_hdr_sz + (self.subseg_durations.len() as u64 * 12) } } @@ -65,12 +74,14 @@ impl ReadBox<&mut R> for SidxBox { let _reserved = reader.read_u16::()?; let ref_count = reader.read_u16::()?; - let mut rest = Vec::new(); + let mut subseg_durations = Vec::new(); for _ in 1..=ref_count { - let rest_1 = reader.read_u64::()?; - let rest_2 = reader.read_u32::()?; + let _ = reader.read_u32::()?; + let duration = reader.read_u32::()?; + + let _ = reader.read_u32::()?; - rest.push((rest_1, rest_2)); + subseg_durations.push(duration); } skip_bytes_to(reader, start + size)?; @@ -82,7 +93,7 @@ impl ReadBox<&mut R> for SidxBox { timescale, earliest_presentation_time, first_offset, - rest, + subseg_durations }) } } @@ -106,10 +117,9 @@ impl WriteBox<&mut W> for SidxBox { writer.write_u64::(self.earliest_presentation_time)?; writer.write_u64::(self.first_offset)?; writer.write_u16::(0)?; - writer.write_u16::(self.rest.len() as u16)?; - for r in &self.rest { - writer.write_u64::(r.0)?; - writer.write_u32::(r.1)?; + // writer.write_u16::(self.rest.len() as u16)?; + for _ in &self.subseg_durations { + // NOTE: Todo } Ok(size) From f51d0d5a7b02c70568fa9697e937139e36d01ed2 Mon Sep 17 00:00:00 2001 From: Eric Ortega <24722023+ejortega@users.noreply.github.com> Date: Tue, 26 Aug 2025 00:06:46 -0500 Subject: [PATCH 09/11] Fix clippy errors --- src/mp4box/dinf.rs | 2 +- src/mp4box/mp4a.rs | 2 +- src/track.rs | 4 ++-- src/writer.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mp4box/dinf.rs b/src/mp4box/dinf.rs index e365e4ae..b6ab4845 100644 --- a/src/mp4box/dinf.rs +++ b/src/mp4box/dinf.rs @@ -232,7 +232,7 @@ impl UrlBox { let mut size = HEADER_SIZE + HEADER_EXT_SIZE; if !self.location.is_empty() { - size += self.location.bytes().len() as u64 + 1; + size += self.location.len() as u64 + 1; } size diff --git a/src/mp4box/mp4a.rs b/src/mp4box/mp4a.rs index a80c6c46..d7f6f25b 100644 --- a/src/mp4box/mp4a.rs +++ b/src/mp4box/mp4a.rs @@ -285,7 +285,7 @@ fn size_of_length(size: u32) -> u32 { fn write_desc(writer: &mut W, tag: u8, size: u32) -> Result { writer.write_u8(tag)?; - if size as u64 > std::u32::MAX as u64 { + if size as u64 > u32::MAX as u64 { return Err(Error::InvalidData("invalid descriptor length range")); } diff --git a/src/track.rs b/src/track.rs index ee79049d..bd3276db 100644 --- a/src/track.rs +++ b/src/track.rs @@ -262,7 +262,7 @@ impl Mp4Track { pub fn sequence_parameter_set(&self) -> Result<&[u8]> { if let Some(ref avc1) = self.trak.mdia.minf.stbl.stsd.avc1 { - match avc1.avcc.sequence_parameter_sets.get(0) { + match avc1.avcc.sequence_parameter_sets.first() { Some(nal) => Ok(nal.bytes.as_ref()), None => Err(Error::EntryInStblNotFound( self.track_id(), @@ -277,7 +277,7 @@ impl Mp4Track { pub fn picture_parameter_set(&self) -> Result<&[u8]> { if let Some(ref avc1) = self.trak.mdia.minf.stbl.stsd.avc1 { - match avc1.avcc.picture_parameter_sets.get(0) { + match avc1.avcc.picture_parameter_sets.first() { Some(nal) => Ok(nal.bytes.as_ref()), None => Err(Error::EntryInStblNotFound( self.track_id(), diff --git a/src/writer.rs b/src/writer.rs index 9179117c..3ac06cff 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -118,7 +118,7 @@ impl Mp4Writer { fn update_mdat_size(&mut self) -> Result<()> { let mdat_end = self.writer.stream_position()?; let mdat_size = mdat_end - self.mdat_pos; - if mdat_size > std::u32::MAX as u64 { + if mdat_size > u32::MAX as u64 { self.writer.seek(SeekFrom::Start(self.mdat_pos))?; self.writer.write_u32::(1)?; self.writer.seek(SeekFrom::Start(self.mdat_pos + 8))?; From e0e791e77f76448cf4a4d3203ca430eadb426f84 Mon Sep 17 00:00:00 2001 From: Eric Ortega <24722023+ejortega@users.noreply.github.com> Date: Tue, 26 Aug 2025 00:09:51 -0500 Subject: [PATCH 10/11] Fix test format --- examples/mp4dump.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/mp4dump.rs b/examples/mp4dump.rs index 462b212a..6a97d9a0 100644 --- a/examples/mp4dump.rs +++ b/examples/mp4dump.rs @@ -138,9 +138,5 @@ fn build_box(m: &M) -> Box { size: m.box_size(), summary: m.summary().unwrap(), indent: 0, -<<<<<<< HEAD } -======= - }; ->>>>>>> vgarleanu/master } From 732519a415b051e5802756e059cc5d11e89fac0b Mon Sep 17 00:00:00 2001 From: Eric Ortega <24722023+ejortega@users.noreply.github.com> Date: Tue, 26 Aug 2025 00:12:40 -0500 Subject: [PATCH 11/11] Update deps --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ec35a0d4..6f7dc339 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ license = "MIT" include = ["src", "benches", "Cargo.toml", "README", "LICENSE"] [dependencies] -thiserror = "^1.0" +thiserror = "2.0" byteorder = "1" bytes = "1.1.0" num-rational = { version = "0.4.0", features = ["serde"] } @@ -21,7 +21,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" [dev-dependencies] -criterion = "0.3" +criterion = "0.7" [[bench]] name = "bench_main"