Skip to content

Commit 9ebaabc

Browse files
pando-fredrikkixelatedLinusUrolleifxDCNick3
authored
Pr 103 multiple trex (#3)
* Add support for multiple trex boxes. While it's common to construct a fMP4 file for a single track, it's totally valid to have multiple tracks. This means you also need multiple to support multiple trex boxes. Untested. * cargo fmt * Add a missing write_box call for mvex. * Ran clippy * Fix more errors when serializing a mvex box. udta is also broken but that can be fixed in another PR. * Derive Default trait for DataType (alfg#100) * fix clippy (rustc 1.71.0) (alfg#115) * Allow Hdlr to be not the first in the Meta box (alfg#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 <[email protected]> * Try to skip extended header in MetaBox. (alfg#111) Fixes alfg#102 Co-authored-by: Alfred Gutierrez <[email protected]> * Release 0.14.0 (alfg#117) * Update Cargo.toml * Update README.md * Fix getting samples from movie fragments (alfg#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 <[email protected]> * Export all boxes to allow more flexible use for writing (alfg#108) Co-authored-by: Alfred Gutierrez <[email protected]> * Fix some minor issues writing traf box (alfg#109) Co-authored-by: Alfred Gutierrez <[email protected]> * Fix writing SLConfigDescriptor (alfg#107) Co-authored-by: Alfred Gutierrez <[email protected]> * Extract esds box from wave box (alfg#96) * Extract esds from wave box * Allow empty, multi-byte, and arbitrary NUL terminated strings * Skip unsupported avc1 sub-boxes * Fixed non-integer framerates * Fixed bitrate calculation * Fixed format issue * Public read sample offset * Fix lint warning. --------- Co-authored-by: Alfred Gutierrez <[email protected]> * hev1 box parser (alfg#101) Co-authored-by: Alfred Gutierrez <[email protected]> --------- Co-authored-by: Luke Curley <[email protected]> Co-authored-by: Linus Unnebäck <[email protected]> Co-authored-by: rolleifx <[email protected]> Co-authored-by: ⭐️NINIKA⭐️ <[email protected]> Co-authored-by: Alfred Gutierrez <[email protected]> Co-authored-by: w-flo <[email protected]> Co-authored-by: jensenn <[email protected]> Co-authored-by: emkman99 <[email protected]> Co-authored-by: Andrey Tkachenko <[email protected]>
1 parent 35560e9 commit 9ebaabc

File tree

4 files changed

+44
-18
lines changed

4 files changed

+44
-18
lines changed

examples/mp4dump.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ fn get_boxes(file: File) -> Result<Vec<Box>> {
5656
if let Some(mehd) = &mvex.mehd {
5757
boxes.push(build_box(mehd));
5858
}
59-
boxes.push(build_box(&mvex.trex));
59+
for trex in mvex.trexs.iter() {
60+
boxes.push(build_box(trex));
61+
}
6062
}
6163

6264
// trak.

src/mp4box/moov.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ impl MoovBox {
3838
if let Some(udta) = &self.udta {
3939
size += udta.box_size();
4040
}
41+
if let Some(mvex) = &self.mvex {
42+
size += mvex.box_size();
43+
}
4144
size
4245
}
4346
}
@@ -134,6 +137,9 @@ impl<W: Write> WriteBox<&mut W> for MoovBox {
134137
for trak in self.traks.iter() {
135138
trak.write_box(writer)?;
136139
}
140+
if let Some(mvex) = &self.mvex {
141+
mvex.write_box(writer)?;
142+
}
137143
if let Some(meta) = &self.meta {
138144
meta.write_box(writer)?;
139145
}

src/mp4box/mvex.rs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,26 @@ use crate::mp4box::{mehd::MehdBox, trex::TrexBox};
77
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
88
pub struct MvexBox {
99
pub mehd: Option<MehdBox>,
10-
pub trex: TrexBox,
10+
11+
#[serde(rename = "trex")]
12+
pub trexs: Vec<TrexBox>,
1113
}
1214

1315
impl MvexBox {
1416
pub fn get_type(&self) -> BoxType {
15-
BoxType::MdiaBox
17+
BoxType::MvexBox
1618
}
1719

1820
pub fn get_size(&self) -> u64 {
19-
HEADER_SIZE + self.mehd.as_ref().map(|x| x.box_size()).unwrap_or(0) + self.trex.box_size()
21+
let mut size = HEADER_SIZE;
22+
23+
size += self.mehd.as_ref().map_or(0, |x| x.box_size());
24+
25+
for trex in self.trexs.iter() {
26+
size += trex.box_size();
27+
}
28+
29+
size
2030
}
2131
}
2232

@@ -44,7 +54,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for MvexBox {
4454
let start = box_start(reader)?;
4555

4656
let mut mehd = None;
47-
let mut trex = None;
57+
let mut trexs = Vec::new();
4858

4959
let mut current = reader.stream_position()?;
5060
let end = start + size;
@@ -63,7 +73,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for MvexBox {
6373
mehd = Some(MehdBox::read_box(reader, s)?);
6474
}
6575
BoxType::TrexBox => {
66-
trex = Some(TrexBox::read_box(reader, s)?);
76+
trexs.push(TrexBox::read_box(reader, s)?);
6777
}
6878
_ => {
6979
// XXX warn!()
@@ -74,16 +84,13 @@ impl<R: Read + Seek> ReadBox<&mut R> for MvexBox {
7484
current = reader.stream_position()?;
7585
}
7686

77-
if trex.is_none() {
87+
if trexs.is_empty() {
7888
return Err(Error::BoxNotFound(BoxType::TrexBox));
7989
}
8090

8191
skip_bytes_to(reader, start + size)?;
8292

83-
Ok(MvexBox {
84-
mehd,
85-
trex: trex.unwrap(),
86-
})
93+
Ok(MvexBox { mehd, trexs })
8794
}
8895
}
8996

@@ -95,7 +102,10 @@ impl<W: Write> WriteBox<&mut W> for MvexBox {
95102
if let Some(mehd) = &self.mehd {
96103
mehd.write_box(writer)?;
97104
}
98-
self.trex.write_box(writer)?;
105+
106+
for trex in self.trexs.iter() {
107+
trex.write_box(writer)?;
108+
}
99109

100110
Ok(size)
101111
}

src/reader.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,16 +97,24 @@ impl<R: Read + Seek> Mp4Reader<R> {
9797

9898
// Update tracks if any fragmented (moof) boxes are found.
9999
if !moofs.is_empty() {
100-
let mut default_sample_duration = 0;
101-
if let Some(ref moov) = moov {
102-
if let Some(ref mvex) = &moov.mvex {
103-
default_sample_duration = mvex.trex.default_sample_duration
104-
}
105-
}
100+
// Grab the mvex box if it exists.
101+
let mvex = moov.as_ref().and_then(|moov| moov.mvex.as_ref());
106102

107103
for (moof, moof_offset) in moofs.iter().zip(moof_offsets) {
108104
for traf in moof.trafs.iter() {
109105
let track_id = traf.tfhd.track_id;
106+
107+
// Get the default sample duration for the indicated track.
108+
// This is buried in the optional mvex box, in a trex box per track.
109+
let default_sample_duration = mvex
110+
.and_then(|mvex| {
111+
mvex.trexs
112+
.iter()
113+
.find(|trex| trex.track_id == track_id)
114+
.map(|trex| trex.default_sample_duration)
115+
})
116+
.unwrap_or(0);
117+
110118
if let Some(track) = tracks.get_mut(&track_id) {
111119
track.default_sample_duration = default_sample_duration;
112120
track.moof_offsets.push(moof_offset);

0 commit comments

Comments
 (0)