From 045677e56e4260d14b2a2ed81e916bd67fd322d4 Mon Sep 17 00:00:00 2001 From: Andrey Tkachenko Date: Fri, 22 Sep 2023 14:25:53 +0400 Subject: [PATCH] refactoring: split off Mp4Header from Mp4Reader --- examples/mp4dump.rs | 10 ++-- examples/mp4info.rs | 4 +- src/lib.rs | 6 +- src/reader.rs | 137 ++++++++++++++++++++++++++++++++++---------- 4 files changed, 118 insertions(+), 39 deletions(-) diff --git a/examples/mp4dump.rs b/examples/mp4dump.rs index 6a97d9a..bfbc800 100644 --- a/examples/mp4dump.rs +++ b/examples/mp4dump.rs @@ -46,12 +46,12 @@ fn get_boxes(file: File) -> Result> { // collect known boxes let mut boxes = vec![ - build_box(&mp4.ftyp), - build_box(&mp4.moov), - build_box(&mp4.moov.mvhd), + build_box(&mp4.header.ftyp), + build_box(&mp4.header.moov), + build_box(&mp4.header.moov.mvhd), ]; - if let Some(ref mvex) = &mp4.moov.mvex { + if let Some(ref mvex) = &mp4.header.moov.mvex { boxes.push(build_box(mvex)); if let Some(mehd) = &mvex.mehd { boxes.push(build_box(mehd)); @@ -117,7 +117,7 @@ fn get_boxes(file: File) -> Result> { } // If fragmented, add moof boxes. - for moof in mp4.moofs.iter() { + for moof in mp4.header.moofs.iter() { boxes.push(build_box(moof)); boxes.push(build_box(&moof.mfhd)); for traf in moof.trafs.iter() { diff --git a/examples/mp4info.rs b/examples/mp4info.rs index 00de8ce..84a8366 100644 --- a/examples/mp4info.rs +++ b/examples/mp4info.rs @@ -37,10 +37,10 @@ fn info>(filename: &P) -> Result<()> { println!(" compatible_brands: {}\n", compatible_brands); println!("Movie:"); - println!(" version: {}", mp4.moov.mvhd.version); + println!(" version: {}", mp4.header.moov.mvhd.version); println!( " creation time: {}", - creation_time(mp4.moov.mvhd.creation_time) + creation_time(mp4.header.moov.mvhd.creation_time) ); println!(" duration: {:?}", mp4.duration()); println!(" fragments: {:?}", mp4.is_fragmented()); diff --git a/src/lib.rs b/src/lib.rs index 92319e1..00c08d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,8 +22,8 @@ //! let mp4 = mp4::Mp4Reader::read_header(reader, size)?; //! //! // Print boxes. -//! println!("major brand: {}", mp4.ftyp.major_brand); -//! println!("timescale: {}", mp4.moov.mvhd.timescale); +//! println!("major brand: {}", mp4.header.ftyp.major_brand); +//! println!("timescale: {}", mp4.header.moov.mvhd.timescale); //! //! // Use available methods. //! println!("size: {}", mp4.size()); @@ -83,7 +83,7 @@ mod track; pub use track::{Mp4Track, TrackConfig}; mod reader; -pub use reader::Mp4Reader; +pub use reader::{Mp4Header, Mp4Reader}; mod writer; pub use writer::{Mp4Config, Mp4Writer}; diff --git a/src/reader.rs b/src/reader.rs index e5ac296..7c2674a 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -6,8 +6,7 @@ use crate::meta::MetaBox; use crate::*; #[derive(Debug)] -pub struct Mp4Reader { - reader: R, +pub struct Mp4Header { pub ftyp: FtypBox, pub moov: MoovBox, pub moofs: Vec, @@ -17,8 +16,8 @@ pub struct Mp4Reader { size: u64, } -impl Mp4Reader { - pub fn read_header(mut reader: R, size: u64) -> Result { +impl Mp4Header { + pub fn read(reader: &mut R, size: u64) -> Result { let start = reader.stream_position()?; let mut ftyp = None; @@ -30,7 +29,7 @@ impl Mp4Reader { let mut current = start; while current < size { // Get box header. - let header = BoxHeader::read(&mut reader)?; + let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; if s > size { return Err(Error::InvalidData( @@ -46,30 +45,30 @@ impl Mp4Reader { // Match and parse the atom boxes. match name { BoxType::FtypBox => { - ftyp = Some(FtypBox::read_box(&mut reader, s)?); + ftyp = Some(FtypBox::read_box(reader, s)?); } BoxType::FreeBox => { - skip_box(&mut reader, s)?; + skip_box(reader, s)?; } BoxType::MdatBox => { - skip_box(&mut reader, s)?; + skip_box(reader, s)?; } BoxType::MoovBox => { - moov = Some(MoovBox::read_box(&mut reader, s)?); + moov = Some(MoovBox::read_box(reader, s)?); } BoxType::MoofBox => { let moof_offset = reader.stream_position()? - 8; - let moof = MoofBox::read_box(&mut reader, s)?; + let moof = MoofBox::read_box(reader, s)?; moofs.push(moof); moof_offsets.push(moof_offset); } BoxType::EmsgBox => { - let emsg = EmsgBox::read_box(&mut reader, s)?; + let emsg = EmsgBox::read_box(reader, s)?; emsgs.push(emsg); } _ => { // XXX warn!() - skip_box(&mut reader, s)?; + skip_box(reader, s)?; } } current = reader.stream_position()?; @@ -118,8 +117,7 @@ impl Mp4Reader { } } - Ok(Mp4Reader { - reader, + Ok(Mp4Header { ftyp: ftyp.unwrap(), moov: moov.unwrap(), moofs, @@ -129,11 +127,7 @@ impl Mp4Reader { }) } - pub fn read_fragment_header( - &self, - mut reader: FR, - size: u64, - ) -> Result> { + pub fn read_fragment(&self, reader: &mut R, size: u64) -> Result { let start = reader.stream_position()?; let mut moofs = Vec::new(); @@ -142,7 +136,7 @@ impl Mp4Reader { let mut current = start; while current < size { // Get box header. - let header = BoxHeader::read(&mut reader)?; + let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; if s > size { return Err(Error::InvalidData( @@ -158,17 +152,17 @@ impl Mp4Reader { // Match and parse the atom boxes. match name { BoxType::MdatBox => { - skip_box(&mut reader, s)?; + skip_box(reader, s)?; } BoxType::MoofBox => { let moof_offset = reader.stream_position()? - 8; - let moof = MoofBox::read_box(&mut reader, s)?; + let moof = MoofBox::read_box(reader, s)?; moofs.push(moof); moof_offsets.push(moof_offset); } _ => { // XXX warn!() - skip_box(&mut reader, s)?; + skip_box(reader, s)?; } } current = reader.stream_position()?; @@ -204,8 +198,7 @@ impl Mp4Reader { } } - Ok(Mp4Reader { - reader, + Ok(Mp4Header { ftyp: self.ftyp.clone(), moov: self.moov.clone(), moofs, @@ -215,10 +208,12 @@ impl Mp4Reader { }) } + #[inline] pub fn size(&self) -> u64 { self.size } + #[inline] pub fn major_brand(&self) -> &FourCC { &self.ftyp.major_brand } @@ -255,9 +250,14 @@ impl Mp4Reader { } } - pub fn read_sample(&mut self, track_id: u32, sample_id: u32) -> Result> { + pub fn read_sample( + &mut self, + reader: &mut R, + track_id: u32, + sample_id: u32, + ) -> Result> { if let Some(track) = self.tracks.get(&track_id) { - track.read_sample(&mut self.reader, sample_id) + track.read_sample(reader, sample_id) } else { Err(Error::TrakNotFound(track_id)) } @@ -270,9 +270,7 @@ impl Mp4Reader { Err(Error::TrakNotFound(track_id)) } } -} -impl Mp4Reader { pub fn metadata(&self) -> impl Metadata<'_> { self.moov.udta.as_ref().and_then(|udta| { udta.meta.as_ref().and_then(|meta| match meta { @@ -282,3 +280,84 @@ impl Mp4Reader { }) } } + +#[derive(Debug)] +pub struct Mp4Reader { + reader: R, + pub header: Mp4Header, +} + +impl Mp4Reader { + pub fn from_reader(reader: R, header: Mp4Header) -> Self { + Self { reader, header } + } + + pub fn read_header(mut reader: R, size: u64) -> Result { + Ok(Mp4Reader { + header: Mp4Header::read(&mut reader, size)?, + reader, + }) + } + + pub fn read_fragment_header( + &self, + mut reader: FR, + size: u64, + ) -> Result> { + Ok(Mp4Reader { + header: self.header.read_fragment(&mut reader, size)?, + reader, + }) + } + + pub fn size(&self) -> u64 { + self.header.size() + } + + pub fn major_brand(&self) -> &FourCC { + self.header.major_brand() + } + + pub fn minor_version(&self) -> u32 { + self.header.minor_version() + } + + pub fn compatible_brands(&self) -> &[FourCC] { + self.header.compatible_brands() + } + + pub fn duration(&self) -> Duration { + self.header.duration() + } + + pub fn timescale(&self) -> u32 { + self.header.timescale() + } + + pub fn is_fragmented(&self) -> bool { + self.header.is_fragmented() + } + + pub fn tracks(&self) -> &HashMap { + self.header.tracks() + } + + pub fn sample_count(&self, track_id: u32) -> Result { + self.header.sample_count(track_id) + } + + pub fn read_sample(&mut self, track_id: u32, sample_id: u32) -> Result> { + self.header + .read_sample(&mut self.reader, track_id, sample_id) + } + + pub fn sample_offset(&mut self, track_id: u32, sample_id: u32) -> Result { + self.header.sample_offset(track_id, sample_id) + } +} + +impl Mp4Reader { + pub fn metadata(&self) -> impl Metadata<'_> { + self.header.metadata() + } +}