diff --git a/examples/mp4dump.rs b/examples/mp4dump.rs index 6a97d9a0..657e5478 100644 --- a/examples/mp4dump.rs +++ b/examples/mp4dump.rs @@ -56,7 +56,9 @@ fn get_boxes(file: File) -> Result> { if let Some(mehd) = &mvex.mehd { boxes.push(build_box(mehd)); } - boxes.push(build_box(&mvex.trex)); + for trex in mvex.trexs.iter() { + boxes.push(build_box(trex)); + } } // trak. diff --git a/src/mp4box/moov.rs b/src/mp4box/moov.rs index ac19381a..80f9953f 100644 --- a/src/mp4box/moov.rs +++ b/src/mp4box/moov.rs @@ -38,6 +38,9 @@ impl MoovBox { if let Some(udta) = &self.udta { size += udta.box_size(); } + if let Some(mvex) = &self.mvex { + size += mvex.box_size(); + } size } } @@ -134,6 +137,9 @@ impl WriteBox<&mut W> for MoovBox { for trak in self.traks.iter() { trak.write_box(writer)?; } + if let Some(mvex) = &self.mvex { + mvex.write_box(writer)?; + } if let Some(meta) = &self.meta { meta.write_box(writer)?; } diff --git a/src/mp4box/mvex.rs b/src/mp4box/mvex.rs index 8be683b8..58d33329 100644 --- a/src/mp4box/mvex.rs +++ b/src/mp4box/mvex.rs @@ -7,16 +7,26 @@ use crate::mp4box::{mehd::MehdBox, trex::TrexBox}; #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)] pub struct MvexBox { pub mehd: Option, - pub trex: TrexBox, + + #[serde(rename = "trex")] + pub trexs: Vec, } impl MvexBox { pub fn get_type(&self) -> BoxType { - BoxType::MdiaBox + BoxType::MvexBox } pub fn get_size(&self) -> u64 { - HEADER_SIZE + self.mehd.as_ref().map(|x| x.box_size()).unwrap_or(0) + self.trex.box_size() + let mut size = HEADER_SIZE; + + size += self.mehd.as_ref().map_or(0, |x| x.box_size()); + + for trex in self.trexs.iter() { + size += trex.box_size(); + } + + size } } @@ -44,7 +54,7 @@ impl ReadBox<&mut R> for MvexBox { let start = box_start(reader)?; let mut mehd = None; - let mut trex = None; + let mut trexs = Vec::new(); let mut current = reader.stream_position()?; let end = start + size; @@ -63,7 +73,7 @@ impl ReadBox<&mut R> for MvexBox { mehd = Some(MehdBox::read_box(reader, s)?); } BoxType::TrexBox => { - trex = Some(TrexBox::read_box(reader, s)?); + trexs.push(TrexBox::read_box(reader, s)?); } _ => { // XXX warn!() @@ -74,16 +84,13 @@ impl ReadBox<&mut R> for MvexBox { current = reader.stream_position()?; } - if trex.is_none() { + if trexs.is_empty() { return Err(Error::BoxNotFound(BoxType::TrexBox)); } skip_bytes_to(reader, start + size)?; - Ok(MvexBox { - mehd, - trex: trex.unwrap(), - }) + Ok(MvexBox { mehd, trexs }) } } @@ -95,7 +102,10 @@ impl WriteBox<&mut W> for MvexBox { if let Some(mehd) = &self.mehd { mehd.write_box(writer)?; } - self.trex.write_box(writer)?; + + for trex in self.trexs.iter() { + trex.write_box(writer)?; + } Ok(size) } diff --git a/src/reader.rs b/src/reader.rs index 5a39eebb..567cb2f2 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -94,16 +94,24 @@ impl Mp4Reader { // Update tracks if any fragmented (moof) boxes are found. if !moofs.is_empty() { - let mut default_sample_duration = 0; - if let Some(ref moov) = moov { - if let Some(ref mvex) = &moov.mvex { - default_sample_duration = mvex.trex.default_sample_duration - } - } + // Grab the mvex box if it exists. + let mvex = moov.as_ref().and_then(|moov| moov.mvex.as_ref()); for moof in moofs.iter() { for traf in moof.trafs.iter() { let track_id = traf.tfhd.track_id; + + // Get the default sample duration for the indicated track. + // This is buried in the optional mvex box, in a trex box per track. + let default_sample_duration = mvex + .and_then(|mvex| { + mvex.trexs + .iter() + .find(|trex| trex.track_id == track_id) + .map(|trex| trex.default_sample_duration) + }) + .unwrap_or(0); + if let Some(track) = tracks.get_mut(&track_id) { track.default_sample_duration = default_sample_duration; track.trafs.push(traf.clone()) diff --git a/src/types.rs b/src/types.rs index 19fd40b3..a26c0b5a 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, Clone, PartialEq, Eq, Serialize, Default)] 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 {