From a3508fe1c92561a498a88fac814598f33ad98845 Mon Sep 17 00:00:00 2001 From: Richard Steinmetz Date: Wed, 29 Mar 2023 09:04:51 +0200 Subject: [PATCH 01/10] Fix link to examples in docs (#97) --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 06658cf..92319e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,7 +62,7 @@ //! ``` //! //! [mp4box]: https://github.com/alfg/mp4-rust/blob/master/src/mp4box/mod.rs -//! [examples]: https://github.com/alfg/mp4-rust/blob/master/src/examples +//! [examples]: https://github.com/alfg/mp4-rust/tree/master/examples #![doc(html_root_url = "https://docs.rs/mp4/*")] use std::fs::File; From 55875d72de32b6f5a4eecc950b8b1510b92fe933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= Date: Mon, 19 Jun 2023 05:38:41 +0200 Subject: [PATCH 02/10] Derive Default trait for DataType (#100) --- src/types.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/types.rs b/src/types.rs index 19fd40b..0983468 100644 --- a/src/types.rs +++ b/src/types.rs @@ -657,20 +657,15 @@ pub fn creation_time(creation_time: u64) -> u64 { } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize)] pub enum DataType { + #[default] Binary = 0x000000, Text = 0x000001, Image = 0x00000D, TempoCpil = 0x000015, } -impl std::default::Default for DataType { - fn default() -> Self { - DataType::Binary - } -} - impl TryFrom for DataType { type Error = Error; fn try_from(value: u32) -> Result { From aff3bf6c452c42428e0579e3654af5d62dab633b Mon Sep 17 00:00:00 2001 From: rolleifx <110799844+rolleifx@users.noreply.github.com> Date: Sat, 29 Jul 2023 10:21:34 +0800 Subject: [PATCH 03/10] fix clippy (rustc 1.71.0) (#115) --- src/mp4box/stsc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mp4box/stsc.rs b/src/mp4box/stsc.rs index e5b444e..a2b034b 100644 --- a/src/mp4box/stsc.rs +++ b/src/mp4box/stsc.rs @@ -85,7 +85,7 @@ impl ReadBox<&mut R> for StscBox { let mut sample_id = 1; for i in 0..entry_count { let (first_chunk, samples_per_chunk) = { - let mut entry = entries.get_mut(i as usize).unwrap(); + let entry = entries.get_mut(i as usize).unwrap(); entry.first_sample = sample_id; (entry.first_chunk, entry.samples_per_chunk) }; From c1040472157d175ffc009144863f68f43bf39b88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=AD=90=EF=B8=8FNINIKA=E2=AD=90=EF=B8=8F?= Date: Sat, 29 Jul 2023 06:43:13 +0300 Subject: [PATCH 04/10] Allow Hdlr to be not the first in the Meta box (#95) While the spec says that the hdlr box should be the first one, not all implementations follow that. Actually look over all boxes in Meta to find Hdlr. Also add a test for such weirdly-formatted box Change the way unknown MetaBox is stored: store a list of boxes instead of raw bytes Co-authored-by: Alfred Gutierrez --- src/mp4box/meta.rs | 103 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 88 insertions(+), 15 deletions(-) diff --git a/src/mp4box/meta.rs b/src/mp4box/meta.rs index df57c77..6e155a2 100644 --- a/src/mp4box/meta.rs +++ b/src/mp4box/meta.rs @@ -21,7 +21,7 @@ pub enum MetaBox { hdlr: HdlrBox, #[serde(skip)] - data: Vec, + data: Vec<(BoxType, Vec)>, }, } @@ -41,7 +41,13 @@ impl MetaBox { size += ilst.box_size(); } } - Self::Unknown { hdlr, data } => size += hdlr.box_size() + data.len() as u64, + Self::Unknown { hdlr, data } => { + size += hdlr.box_size() + + data + .iter() + .map(|(_, data)| data.len() as u64 + HEADER_SIZE) + .sum::() + } } size } @@ -89,17 +95,41 @@ impl ReadBox<&mut R> for MetaBox { return Err(Error::UnsupportedBoxVersion(BoxType::UdtaBox, version)); } - let hdlr_header = BoxHeader::read(reader)?; - if hdlr_header.name != BoxType::HdlrBox { - return Err(Error::BoxNotFound(BoxType::HdlrBox)); - } - let hdlr = HdlrBox::read_box(reader, hdlr_header.size)?; - - let mut ilst = None; - let mut current = reader.stream_position()?; let end = start + size; + let content_start = current; + + // find the hdlr box + let mut hdlr = None; + while current < end { + // Get box header. + let header = BoxHeader::read(reader)?; + let BoxHeader { name, size: s } = header; + + match name { + BoxType::HdlrBox => { + hdlr = Some(HdlrBox::read_box(reader, s)?); + } + _ => { + // XXX warn!() + skip_box(reader, s)?; + } + } + + current = reader.stream_position()?; + } + + let Some(hdlr) = hdlr else { + return Err(Error::BoxNotFound(BoxType::HdlrBox)); + }; + + // rewind and handle the other boxes + reader.seek(SeekFrom::Start(content_start))?; + current = reader.stream_position()?; + + let mut ilst = None; + match hdlr.handler_type { MDIR => { while current < end { @@ -123,8 +153,27 @@ impl ReadBox<&mut R> for MetaBox { Ok(MetaBox::Mdir { ilst }) } _ => { - let mut data = vec![0u8; (end - current) as usize]; - reader.read_exact(&mut data)?; + let mut data = Vec::new(); + + while current < end { + // Get box header. + let header = BoxHeader::read(reader)?; + let BoxHeader { name, size: s } = header; + + match name { + BoxType::HdlrBox => { + skip_box(reader, s)?; + } + _ => { + let mut box_data = vec![0; (s - HEADER_SIZE) as usize]; + reader.read_exact(&mut box_data)?; + + data.push((name, box_data)); + } + } + + current = reader.stream_position()?; + } Ok(MetaBox::Unknown { hdlr, data }) } @@ -154,7 +203,12 @@ impl WriteBox<&mut W> for MetaBox { ilst.write_box(writer)?; } } - Self::Unknown { data, .. } => writer.write_all(data)?, + Self::Unknown { data, .. } => { + for (box_type, data) in data { + BoxHeader::new(*box_type, data.len() as u64 + HEADER_SIZE).write(writer)?; + writer.write_all(data)?; + } + } } Ok(size) } @@ -202,16 +256,35 @@ mod tests { assert_eq!(dst_box, src_box); } + #[test] + fn test_meta_hdrl_non_first() { + let data = b"\x00\x00\x00\x7fmeta\x00\x00\x00\x00\x00\x00\x00Qilst\x00\x00\x00I\xa9too\x00\x00\x00Adata\x00\x00\x00\x01\x00\x00\x00\x00TMPGEnc Video Mastering Works 7 Version 7.0.15.17\x00\x00\x00\"hdlr\x00\x00\x00\x00\x00\x00\x00\x00mdirappl\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; + let mut reader = Cursor::new(data); + let header = BoxHeader::read(&mut reader).unwrap(); + assert_eq!(header.name, BoxType::MetaBox); + + let meta_box = MetaBox::read_box(&mut reader, header.size).unwrap(); + + // this contains \xa9too box in the ilst + // it designates the tool that created the file, but is not yet supported by this crate + assert_eq!( + meta_box, + MetaBox::Mdir { + ilst: Some(IlstBox::default()) + } + ); + } + #[test] fn test_meta_unknown() { let src_hdlr = HdlrBox { handler_type: FourCC::from(*b"test"), ..Default::default() }; - let src_data = b"123"; + let src_data = (BoxType::UnknownBox(0x42494241), b"123".to_vec()); let src_box = MetaBox::Unknown { hdlr: src_hdlr, - data: src_data.to_vec(), + data: vec![src_data], }; let mut buf = Vec::new(); From d6c38642de48360693132fd07552a454016d71c3 Mon Sep 17 00:00:00 2001 From: w-flo Date: Sat, 29 Jul 2023 06:06:22 +0200 Subject: [PATCH 05/10] Try to skip extended header in MetaBox. (#111) Fixes #102 Co-authored-by: Alfred Gutierrez --- src/mp4box/meta.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/mp4box/meta.rs b/src/mp4box/meta.rs index 6e155a2..56ca816 100644 --- a/src/mp4box/meta.rs +++ b/src/mp4box/meta.rs @@ -90,9 +90,19 @@ impl ReadBox<&mut R> for MetaBox { fn read_box(reader: &mut R, size: u64) -> Result { let start = box_start(reader)?; - let (version, _) = read_box_header_ext(reader)?; - if version != 0 { - return Err(Error::UnsupportedBoxVersion(BoxType::UdtaBox, version)); + let extended_header = reader.read_u32::()?; + if extended_header != 0 { + // ISO mp4 requires this header (version & flags) to be 0. Some + // files skip the extended header and directly start the hdlr box. + let possible_hdlr = BoxType::from(reader.read_u32::()?); + if possible_hdlr == BoxType::HdlrBox { + // This file skipped the extended header! Go back to start. + reader.seek(SeekFrom::Current(-8))?; + } else { + // Looks like we actually have a bad version number or flags. + let v = (extended_header >> 24) as u8; + return Err(Error::UnsupportedBoxVersion(BoxType::MetaBox, v)); + } } let mut current = reader.stream_position()?; From 18f1718b70955e2982f81b9827aa396b533c4fbc Mon Sep 17 00:00:00 2001 From: Alfred Gutierrez Date: Mon, 31 Jul 2023 20:54:29 -0700 Subject: [PATCH 06/10] Release 0.14.0 (#117) * Update Cargo.toml * Update README.md --- Cargo.toml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bd5f479..ec35a0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mp4" -version = "0.13.0" +version = "0.14.0" authors = ["Alf "] edition = "2018" description = "MP4 reader and writer library in Rust." diff --git a/README.md b/README.md index e011773..91778ec 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ cargo add mp4 ``` or add to your `Cargo.toml`: ```toml -mp4 = "0.13.0" +mp4 = "0.14.0" ``` #### Documentation From b90e43dd9c53d5b2bb0519de55f75f1569710ff3 Mon Sep 17 00:00:00 2001 From: jensenn Date: Wed, 2 Aug 2023 21:53:43 -0600 Subject: [PATCH 07/10] Fix getting samples from movie fragments (#106) * Fix getting samples from movie fragments * Add a function to the reader to read in fragments from a different reader --------- Co-authored-by: Alfred Gutierrez --- src/reader.rs | 92 ++++++++++++++++++++++++++++- src/track.rs | 80 +++++++++++++++++++++---- tests/lib.rs | 33 +++++++++++ tests/samples/minimal_fragment.m4s | Bin 0 -> 867 bytes tests/samples/minimal_init.mp4 | Bin 0 -> 692 bytes 5 files changed, 194 insertions(+), 11 deletions(-) create mode 100644 tests/samples/minimal_fragment.m4s create mode 100644 tests/samples/minimal_init.mp4 diff --git a/src/reader.rs b/src/reader.rs index 5a39eeb..4a285c4 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -24,6 +24,7 @@ impl Mp4Reader { let mut ftyp = None; let mut moov = None; let mut moofs = Vec::new(); + let mut moof_offsets = Vec::new(); let mut emsgs = Vec::new(); let mut current = start; @@ -57,8 +58,10 @@ impl Mp4Reader { moov = Some(MoovBox::read_box(&mut reader, s)?); } BoxType::MoofBox => { + let moof_offset = reader.stream_position()? - 8; let moof = MoofBox::read_box(&mut reader, s)?; moofs.push(moof); + moof_offsets.push(moof_offset); } BoxType::EmsgBox => { let emsg = EmsgBox::read_box(&mut reader, s)?; @@ -101,11 +104,12 @@ impl Mp4Reader { } } - for moof in moofs.iter() { + for (moof, moof_offset) in moofs.iter().zip(moof_offsets) { for traf in moof.trafs.iter() { let track_id = traf.tfhd.track_id; if let Some(track) = tracks.get_mut(&track_id) { track.default_sample_duration = default_sample_duration; + track.moof_offsets.push(moof_offset); track.trafs.push(traf.clone()) } else { return Err(Error::TrakNotFound(track_id)); @@ -125,6 +129,92 @@ impl Mp4Reader { }) } + pub fn read_fragment_header( + &self, + mut reader: FR, + size: u64, + ) -> Result> { + let start = reader.stream_position()?; + + let mut moofs = Vec::new(); + let mut moof_offsets = Vec::new(); + + let mut current = start; + while current < size { + // Get box header. + let header = BoxHeader::read(&mut reader)?; + let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "file contains a box with a larger size than it", + )); + } + + // Break if size zero BoxHeader, which can result in dead-loop. + if s == 0 { + break; + } + + // Match and parse the atom boxes. + match name { + BoxType::MdatBox => { + skip_box(&mut reader, s)?; + } + BoxType::MoofBox => { + let moof_offset = reader.stream_position()? - 8; + let moof = MoofBox::read_box(&mut reader, s)?; + moofs.push(moof); + moof_offsets.push(moof_offset); + } + _ => { + // XXX warn!() + skip_box(&mut reader, s)?; + } + } + current = reader.stream_position()?; + } + + if moofs.is_empty() { + return Err(Error::BoxNotFound(BoxType::MoofBox)); + } + + let size = current - start; + let mut tracks: HashMap = self + .moov + .traks + .iter() + .map(|trak| (trak.tkhd.track_id, Mp4Track::from(trak))) + .collect(); + + let mut default_sample_duration = 0; + if let Some(ref mvex) = &self.moov.mvex { + default_sample_duration = mvex.trex.default_sample_duration + } + + for (moof, moof_offset) in moofs.iter().zip(moof_offsets) { + for traf in moof.trafs.iter() { + let track_id = traf.tfhd.track_id; + if let Some(track) = tracks.get_mut(&track_id) { + track.default_sample_duration = default_sample_duration; + track.moof_offsets.push(moof_offset); + track.trafs.push(traf.clone()) + } else { + return Err(Error::TrakNotFound(track_id)); + } + } + } + + Ok(Mp4Reader { + reader, + ftyp: self.ftyp.clone(), + moov: self.moov.clone(), + moofs, + emsgs: Vec::new(), + tracks, + size, + }) + } + pub fn size(&self) -> u64 { self.size } diff --git a/src/track.rs b/src/track.rs index 472ca1d..3a99c3e 100644 --- a/src/track.rs +++ b/src/track.rs @@ -6,6 +6,7 @@ use std::time::Duration; use crate::mp4box::traf::TrafBox; use crate::mp4box::trak::TrakBox; +use crate::mp4box::trun::TrunBox; use crate::mp4box::{ avc1::Avc1Box, co64::Co64Box, ctts::CttsBox, ctts::CttsEntry, hev1::Hev1Box, mp4a::Mp4aBox, smhd::SmhdBox, stco::StcoBox, stsc::StscEntry, stss::StssBox, stts::SttsEntry, tx3g::Tx3gBox, @@ -92,6 +93,7 @@ impl From for TrackConfig { pub struct Mp4Track { pub trak: TrakBox, pub trafs: Vec, + pub moof_offsets: Vec, // Fragmented Tracks Defaults. pub default_sample_duration: u32, @@ -103,6 +105,7 @@ impl Mp4Track { Self { trak, trafs: Vec::new(), + moof_offsets: Vec::new(), default_sample_duration: 0, } } @@ -436,8 +439,32 @@ impl Mp4Track { fn sample_offset(&self, sample_id: u32) -> Result { if !self.trafs.is_empty() { - 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.unwrap_or(0)) + if let Some((traf_idx, sample_idx)) = self.find_traf_idx_and_sample_idx(sample_id) { + let mut sample_offset = self.trafs[traf_idx] + .tfhd + .base_data_offset + .unwrap_or(self.moof_offsets[traf_idx]); + + if let Some(data_offset) = self.trafs[traf_idx] + .trun + .as_ref() + .and_then(|trun| trun.data_offset) + { + sample_offset = sample_offset.checked_add_signed(data_offset as i64).ok_or( + Error::InvalidData("attempt to calculate trun sample offset with overflow"), + )?; + } + + let first_sample_in_trun = sample_id - sample_idx as u32; + for i in first_sample_in_trun..sample_id { + sample_offset = sample_offset + .checked_add(self.sample_size(i)? as u64) + .ok_or(Error::InvalidData( + "attempt to calculate trun entry sample offset with overflow", + ))?; + } + + Ok(sample_offset) } else { Err(Error::BoxInTrafNotFound(self.track_id(), BoxType::TrafBox)) } @@ -473,15 +500,38 @@ impl Mp4Track { } fn sample_time(&self, sample_id: u32) -> Result<(u64, u32)> { - let stts = &self.trak.mdia.minf.stbl.stts; - - let mut sample_count: u32 = 1; - let mut elapsed = 0; - if !self.trafs.is_empty() { - let start_time = ((sample_id - 1) * self.default_sample_duration) as u64; - Ok((start_time, self.default_sample_duration)) + let mut base_start_time = 0; + let mut default_sample_duration = self.default_sample_duration; + if let Some((traf_idx, sample_idx)) = self.find_traf_idx_and_sample_idx(sample_id) { + let traf = &self.trafs[traf_idx]; + if let Some(tfdt) = &traf.tfdt { + base_start_time = tfdt.base_media_decode_time; + } + if let Some(duration) = traf.tfhd.default_sample_duration { + default_sample_duration = duration; + } + if let Some(trun) = &traf.trun { + if TrunBox::FLAG_SAMPLE_DURATION & trun.flags != 0 { + let mut start_offset = 0u64; + for duration in &trun.sample_durations[..sample_idx] { + start_offset = start_offset.checked_add(*duration as u64).ok_or( + Error::InvalidData("attempt to sum sample durations with overflow"), + )?; + } + let duration = trun.sample_durations[sample_idx]; + return Ok((base_start_time + start_offset, duration)); + } + } + } + let start_offset = ((sample_id - 1) * default_sample_duration) as u64; + Ok((base_start_time + start_offset, default_sample_duration)) } else { + let stts = &self.trak.mdia.minf.stbl.stts; + + let mut sample_count: u32 = 1; + let mut elapsed = 0; + for entry in stts.entries.iter() { let new_sample_count = sample_count @@ -508,7 +558,17 @@ impl Mp4Track { } fn sample_rendering_offset(&self, sample_id: u32) -> i32 { - if let Some(ref ctts) = self.trak.mdia.minf.stbl.ctts { + if !self.trafs.is_empty() { + if let Some((traf_idx, sample_idx)) = self.find_traf_idx_and_sample_idx(sample_id) { + if let Some(cts) = self.trafs[traf_idx] + .trun + .as_ref() + .and_then(|trun| trun.sample_cts.get(sample_idx)) + { + return *cts as i32; + } + } + } else if let Some(ref ctts) = self.trak.mdia.minf.stbl.ctts { if let Ok((ctts_index, _)) = self.ctts_index(sample_id) { let ctts_entry = ctts.entries.get(ctts_index).unwrap(); return ctts_entry.sample_offset; diff --git a/tests/lib.rs b/tests/lib.rs index c24ce1e..896efb1 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -176,3 +176,36 @@ fn test_read_metadata() { assert_eq!(poster.len(), want_poster.len()); assert_eq!(poster, want_poster.as_slice()); } + +#[test] +fn test_read_fragments() { + let mp4 = get_reader("tests/samples/minimal_init.mp4"); + + assert_eq!(692, mp4.size()); + assert_eq!(5, mp4.compatible_brands().len()); + + let sample_count = mp4.sample_count(1).unwrap(); + assert_eq!(sample_count, 0); + + let f = File::open("tests/samples/minimal_fragment.m4s").unwrap(); + let f_size = f.metadata().unwrap().len(); + let frag_reader = BufReader::new(f); + + let mut mp4_fragment = mp4.read_fragment_header(frag_reader, f_size).unwrap(); + let sample_count = mp4_fragment.sample_count(1).unwrap(); + assert_eq!(sample_count, 1); + let sample_1_1 = mp4_fragment.read_sample(1, 1).unwrap().unwrap(); + assert_eq!(sample_1_1.bytes.len(), 751); + assert_eq!( + sample_1_1, + mp4::Mp4Sample { + start_time: 0, + duration: 512, + rendering_offset: 0, + is_sync: true, + bytes: mp4::Bytes::from(vec![0x0u8; 751]), + } + ); + let eos = mp4_fragment.read_sample(1, 2); + assert!(eos.is_err()); +} diff --git a/tests/samples/minimal_fragment.m4s b/tests/samples/minimal_fragment.m4s new file mode 100644 index 0000000000000000000000000000000000000000..25532bc10745b065e122d3336987f820a6befd40 GIT binary patch literal 867 zcmX|9&1)1f6wfZLs37&Aw;n>h+3s#;_M`1$z*>qG5j+&HLnf2i2|F{%CRuk^dJq)x z=0z+N1&`vvt6uy+EVdU9f++T+-mEX%)R0#d1r=Y1yyGOdzGtt7F7>n|0xpY;C^>z_UP#C z{>HbDU-vfOzgYT&_pbar9EY72u3@f>z(H#T8<3m0%{%R7;uV{9AR2e>ZrrT3@Y=m~ zuuKF8#k$gyT%-<%gfwd*3EDtr&gpKWF&d5P_hlkf&dRzny@r3Kp1C3i8>O98rR`$Q zV#aBJjYw$|CnC-j@6(`5x&*V5WleU^a`opJ%Tx#W<`DM4^)rf+arFz54- zr4uG+U<7=e4-K0{Tosx*kU6vnK7%YF1Q;6TZBoMuVWC-Zq$hx7LPNkTVcJ&_N3mqq zKO&8o)-@8cm$?{pN{ce;DGl0VQiE$>OdvK5+vEgBg)BkDmWxvGp`$J0(=^Pt)Cik_ zyW!FQa=qSg%1w%k82akV0)d9jI>7^93?=mrKh($ literal 0 HcmV?d00001 diff --git a/tests/samples/minimal_init.mp4 b/tests/samples/minimal_init.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..fcfe89285db5a190f206954d8c61c03be9a46b7d GIT binary patch literal 692 zcmZWmJx{|h5WP?d7LYo0=)e#`2i8`t#8kCq=^uazAwryzsBu%pCITil#KwXU|A8OD zz{W3N1C;@Z1y+{wE+5owPd?v!@6MN;O+>YUz8D88l0+-S5#DeTw=T!cI&cg6t&F0C zh(ek80+HVCj&9hAN}r%@vWVBr<_P2k-kDV{p(zXpK6LC1kv!DH^qXr&VbN{J&@xzL zio^o%K(~1NhLd$AMc@F~Qe< Date: Wed, 2 Aug 2023 21:57:20 -0600 Subject: [PATCH 08/10] Export all boxes to allow more flexible use for writing (#108) Co-authored-by: Alfred Gutierrez --- src/mp4box/mod.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/mp4box/mod.rs b/src/mp4box/mod.rs index 0af14b5..2346ef1 100644 --- a/src/mp4box/mod.rs +++ b/src/mp4box/mod.rs @@ -106,10 +106,49 @@ pub(crate) mod vmhd; pub(crate) mod vp09; pub(crate) mod vpcc; +pub use avc1::Avc1Box; +pub use co64::Co64Box; +pub use ctts::CttsBox; +pub use data::DataBox; +pub use dinf::DinfBox; +pub use edts::EdtsBox; +pub use elst::ElstBox; pub use emsg::EmsgBox; pub use ftyp::FtypBox; +pub use hdlr::HdlrBox; +pub use hev1::Hev1Box; +pub use ilst::IlstBox; +pub use mdhd::MdhdBox; +pub use mdia::MdiaBox; +pub use mehd::MehdBox; +pub use meta::MetaBox; +pub use mfhd::MfhdBox; +pub use minf::MinfBox; pub use moof::MoofBox; pub use moov::MoovBox; +pub use mp4a::Mp4aBox; +pub use mvex::MvexBox; +pub use mvhd::MvhdBox; +pub use smhd::SmhdBox; +pub use stbl::StblBox; +pub use stco::StcoBox; +pub use stsc::StscBox; +pub use stsd::StsdBox; +pub use stss::StssBox; +pub use stsz::StszBox; +pub use stts::SttsBox; +pub use tfdt::TfdtBox; +pub use tfhd::TfhdBox; +pub use tkhd::TkhdBox; +pub use traf::TrafBox; +pub use trak::TrakBox; +pub use trex::TrexBox; +pub use trun::TrunBox; +pub use tx3g::Tx3gBox; +pub use udta::UdtaBox; +pub use vmhd::VmhdBox; +pub use vp09::Vp09Box; +pub use vpcc::VpccBox; pub const HEADER_SIZE: u64 = 8; // const HEADER_LARGE_SIZE: u64 = 16; From df92ac893ccd038f57988e52860d009bf960fa26 Mon Sep 17 00:00:00 2001 From: jensenn Date: Wed, 2 Aug 2023 22:02:05 -0600 Subject: [PATCH 09/10] Fix some minor issues writing traf box (#109) Co-authored-by: Alfred Gutierrez --- src/mp4box/tfhd.rs | 2 ++ src/mp4box/traf.rs | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/src/mp4box/tfhd.rs b/src/mp4box/tfhd.rs index e67e5cb..5b529e6 100644 --- a/src/mp4box/tfhd.rs +++ b/src/mp4box/tfhd.rs @@ -22,6 +22,8 @@ impl TfhdBox { pub const FLAG_DEFAULT_SAMPLE_DURATION: u32 = 0x08; pub const FLAG_DEFAULT_SAMPLE_SIZE: u32 = 0x10; pub const FLAG_DEFAULT_SAMPLE_FLAGS: u32 = 0x20; + pub const FLAG_DURATION_IS_EMPTY: u32 = 0x10000; + pub const FLAG_DEFAULT_BASE_IS_MOOF: u32 = 0x20000; pub fn get_type(&self) -> BoxType { BoxType::TfhdBox diff --git a/src/mp4box/traf.rs b/src/mp4box/traf.rs index 51f812d..d53d713 100644 --- a/src/mp4box/traf.rs +++ b/src/mp4box/traf.rs @@ -19,6 +19,9 @@ impl TrafBox { pub fn get_size(&self) -> u64 { let mut size = HEADER_SIZE; size += self.tfhd.box_size(); + if let Some(ref tfdt) = self.tfdt { + size += tfdt.box_size(); + } if let Some(ref trun) = self.trun { size += trun.box_size(); } @@ -104,6 +107,12 @@ impl WriteBox<&mut W> for TrafBox { BoxHeader::new(self.box_type(), size).write(writer)?; 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) } From b4fca8a1995ef93ab3326270f0ecf83cdd330bc7 Mon Sep 17 00:00:00 2001 From: jensenn Date: Wed, 2 Aug 2023 22:05:09 -0600 Subject: [PATCH 10/10] Fix writing SLConfigDescriptor (#107) Co-authored-by: Alfred Gutierrez --- src/mp4box/mp4a.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mp4box/mp4a.rs b/src/mp4box/mp4a.rs index e4d6a45..89ad9f5 100644 --- a/src/mp4box/mp4a.rs +++ b/src/mp4box/mp4a.rs @@ -585,9 +585,9 @@ impl ReadDesc<&mut R> for SLConfigDescriptor { impl WriteDesc<&mut W> for SLConfigDescriptor { fn write_desc(&self, writer: &mut W) -> Result { let size = Self::desc_size(); - write_desc(writer, Self::desc_tag(), size - 1)?; + write_desc(writer, Self::desc_tag(), size)?; - writer.write_u8(0)?; // pre-defined + writer.write_u8(2)?; // pre-defined Ok(size) } }