Skip to content

Commit d050c64

Browse files
authored
Merge pull request #252 from mozilla/return-parser-context
Make parsers return context objects rather that using out params
2 parents 7a0b275 + c196ca8 commit d050c64

File tree

5 files changed

+71
-83
lines changed

5 files changed

+71
-83
lines changed

mp4parse/benches/avif_benchmark.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@ criterion_group!(benches, criterion_benchmark);
1515
criterion_main!(benches);
1616

1717
fn avif_largest() {
18-
let context = &mut mp4::AvifContext::new();
1918
let input = &mut File::open(
2019
"av1-avif/testFiles/Netflix/avif/cosmos_frame05000_yuv444_12bpc_bt2020_pq_qlossless.avif",
2120
)
2221
.expect("Unknown file");
23-
assert!(mp4::read_avif(input, context).is_ok());
22+
assert!(mp4::read_avif(input).is_ok());
2423
}

mp4parse/src/lib.rs

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,10 +1218,7 @@ fn skip_box_remain<T: Read>(src: &mut BMFFBox<T>) -> Result<()> {
12181218
}
12191219

12201220
/// Read the contents of an AVIF file
1221-
///
1222-
/// Metadata is accumulated in the passed-through `AvifContext` struct,
1223-
/// which can be examined later.
1224-
pub fn read_avif<T: Read>(f: &mut T, context: &mut AvifContext) -> Result<()> {
1221+
pub fn read_avif<T: Read>(f: &mut T) -> Result<AvifContext> {
12251222
let _ = env_logger::try_init();
12261223

12271224
let mut f = OffsetReader::new(f);
@@ -1297,20 +1294,23 @@ pub fn read_avif<T: Read>(f: &mut T, context: &mut AvifContext) -> Result<()> {
12971294
return Err(Error::InvalidData("multiple alpha planes"));
12981295
}
12991296

1300-
context.premultiplied_alpha = alpha_item_id.map_or(false, |alpha_item_id| {
1297+
let premultiplied_alpha = alpha_item_id.map_or(false, |alpha_item_id| {
13011298
meta.item_references.iter().any(|iref| {
13021299
iref.from_item_id == meta.primary_item_id
13031300
&& iref.to_item_id == alpha_item_id
13041301
&& iref.item_type == b"prem"
13051302
})
13061303
});
13071304

1305+
let mut primary_item = TryVec::new();
1306+
let mut alpha_item = None;
1307+
13081308
// load data of relevant items
13091309
for loc in meta.iloc_items.iter() {
13101310
let mut item_data = if loc.item_id == meta.primary_item_id {
1311-
&mut context.primary_item
1311+
&mut primary_item
13121312
} else if Some(loc.item_id) == alpha_item_id {
1313-
context.alpha_item.get_or_insert_with(TryVec::new)
1313+
alpha_item.get_or_insert_with(TryVec::new)
13141314
} else {
13151315
continue;
13161316
};
@@ -1340,7 +1340,11 @@ pub fn read_avif<T: Read>(f: &mut T, context: &mut AvifContext) -> Result<()> {
13401340
}
13411341
}
13421342

1343-
Ok(())
1343+
Ok(AvifContext {
1344+
primary_item,
1345+
alpha_item,
1346+
premultiplied_alpha,
1347+
})
13441348
}
13451349

13461350
/// Parse a metadata box in the context of an AVIF
@@ -2040,12 +2044,9 @@ fn read_iloc<T: Read>(src: &mut BMFFBox<T>) -> Result<TryVec<ItemLocationBoxItem
20402044
}
20412045

20422046
/// Read the contents of a box, including sub boxes.
2043-
///
2044-
/// Metadata is accumulated in the passed-through `MediaContext` struct,
2045-
/// which can be examined later.
2046-
pub fn read_mp4<T: Read>(f: &mut T, context: &mut MediaContext) -> Result<()> {
2047+
pub fn read_mp4<T: Read>(f: &mut T) -> Result<MediaContext> {
2048+
let mut context = None;
20472049
let mut found_ftyp = false;
2048-
let mut found_moov = false;
20492050
// TODO(kinetik): Top-level parsing should handle zero-sized boxes
20502051
// rather than throwing an error.
20512052
let mut iter = BoxIter::new(f);
@@ -2072,13 +2073,12 @@ pub fn read_mp4<T: Read>(f: &mut T, context: &mut MediaContext) -> Result<()> {
20722073
debug!("{:?}", ftyp);
20732074
}
20742075
BoxType::MovieBox => {
2075-
read_moov(&mut b, context)?;
2076-
found_moov = true;
2076+
context = Some(read_moov(&mut b)?);
20772077
}
20782078
_ => skip_box_content(&mut b)?,
20792079
};
20802080
check_parser_state!(b.content);
2081-
if found_moov {
2081+
if context.is_some() {
20822082
debug!(
20832083
"found moov {}, could stop pure 'moov' parser now",
20842084
if found_ftyp {
@@ -2093,56 +2093,64 @@ pub fn read_mp4<T: Read>(f: &mut T, context: &mut MediaContext) -> Result<()> {
20932093
// XXX(kinetik): This isn't perfect, as a "moov" with no contents is
20942094
// treated as okay but we haven't found anything useful. Needs more
20952095
// thought for clearer behaviour here.
2096-
if found_moov {
2097-
Ok(())
2098-
} else {
2099-
Err(Error::NoMoov)
2100-
}
2096+
context.ok_or(Error::NoMoov)
21012097
}
21022098

2103-
fn parse_mvhd<T: Read>(f: &mut BMFFBox<T>) -> Result<(MovieHeaderBox, Option<MediaTimeScale>)> {
2099+
fn parse_mvhd<T: Read>(f: &mut BMFFBox<T>) -> Result<Option<MediaTimeScale>> {
21042100
let mvhd = read_mvhd(f)?;
2101+
debug!("{:?}", mvhd);
21052102
if mvhd.timescale == 0 {
21062103
return Err(Error::InvalidData("zero timescale in mdhd"));
21072104
}
21082105
let timescale = Some(MediaTimeScale(u64::from(mvhd.timescale)));
2109-
Ok((mvhd, timescale))
2106+
Ok(timescale)
21102107
}
21112108

2112-
fn read_moov<T: Read>(f: &mut BMFFBox<T>, context: &mut MediaContext) -> Result<()> {
2109+
fn read_moov<T: Read>(f: &mut BMFFBox<T>) -> Result<MediaContext> {
2110+
let MediaContext {
2111+
mut timescale,
2112+
mut tracks,
2113+
mut mvex,
2114+
mut psshs,
2115+
mut userdata,
2116+
} = Default::default();
2117+
21132118
let mut iter = f.box_iter();
21142119
while let Some(mut b) = iter.next_box()? {
21152120
match b.head.name {
21162121
BoxType::MovieHeaderBox => {
2117-
let (mvhd, timescale) = parse_mvhd(&mut b)?;
2118-
context.timescale = timescale;
2119-
debug!("{:?}", mvhd);
2122+
timescale = parse_mvhd(&mut b)?;
21202123
}
21212124
BoxType::TrackBox => {
2122-
let mut track = Track::new(context.tracks.len());
2125+
let mut track = Track::new(tracks.len());
21232126
read_trak(&mut b, &mut track)?;
2124-
context.tracks.push(track)?;
2127+
tracks.push(track)?;
21252128
}
21262129
BoxType::MovieExtendsBox => {
2127-
let mvex = read_mvex(&mut b)?;
2130+
mvex = Some(read_mvex(&mut b)?);
21282131
debug!("{:?}", mvex);
2129-
context.mvex = Some(mvex);
21302132
}
21312133
BoxType::ProtectionSystemSpecificHeaderBox => {
21322134
let pssh = read_pssh(&mut b)?;
21332135
debug!("{:?}", pssh);
2134-
context.psshs.push(pssh)?;
2136+
psshs.push(pssh)?;
21352137
}
21362138
BoxType::UserdataBox => {
2137-
let udta = read_udta(&mut b);
2138-
debug!("{:?}", udta);
2139-
context.userdata = Some(udta);
2139+
userdata = Some(read_udta(&mut b));
2140+
debug!("{:?}", userdata);
21402141
}
21412142
_ => skip_box_content(&mut b)?,
21422143
};
21432144
check_parser_state!(b.content);
21442145
}
2145-
Ok(())
2146+
2147+
Ok(MediaContext {
2148+
timescale,
2149+
tracks,
2150+
mvex,
2151+
psshs,
2152+
userdata,
2153+
})
21462154
}
21472155

21482156
fn read_pssh<T: Read>(src: &mut BMFFBox<T>) -> Result<ProtectionSystemSpecificHeaderBox> {

mp4parse/src/tests.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
use super::read_mp4;
99
use super::Error;
10-
use super::MediaContext;
1110
use fallible_collections::TryRead as _;
1211

1312
use std::convert::TryInto as _;
@@ -195,8 +194,7 @@ fn read_truncated_ftyp() {
195194
.B32(0) // minor version
196195
.append_bytes(b"isom")
197196
});
198-
let mut context = MediaContext::new();
199-
match read_mp4(&mut stream, &mut context) {
197+
match read_mp4(&mut stream) {
200198
Err(Error::UnexpectedEOF) => (),
201199
Ok(_) => panic!("expected an error result"),
202200
_ => panic!("expected a different error result"),
@@ -346,7 +344,7 @@ fn read_mdhd_invalid_timescale() {
346344
assert_eq!(stream.head.name, BoxType::MediaHeaderBox);
347345
assert_eq!(stream.head.size, 44);
348346
let r = super::parse_mdhd(&mut stream, &mut super::Track::new(0));
349-
assert_eq!(r.is_err(), true);
347+
assert!(r.is_err());
350348
}
351349

352350
#[test]
@@ -387,7 +385,7 @@ fn read_mvhd_invalid_timescale() {
387385
assert_eq!(stream.head.name, BoxType::MovieHeaderBox);
388386
assert_eq!(stream.head.size, 120);
389387
let r = super::parse_mvhd(&mut stream);
390-
assert_eq!(r.is_err(), true);
388+
assert!(r.is_err());
391389
}
392390

393391
#[test]
@@ -1249,9 +1247,8 @@ fn read_invalid_pssh() {
12491247
let mut stream = make_box(BoxSize::Auto, b"moov", |s| s.append_bytes(pssh.as_slice()));
12501248
let mut iter = super::BoxIter::new(&mut stream);
12511249
let mut stream = iter.next_box().unwrap().unwrap();
1252-
let mut context = super::MediaContext::new();
12531250

1254-
match super::read_moov(&mut stream, &mut context) {
1251+
match super::read_moov(&mut stream) {
12551252
Err(Error::InvalidData(s)) => assert_eq!(s, "read_buf size exceeds BUF_SIZE_LIMIT"),
12561253
_ => panic!("unexpected result with invalid descriptor"),
12571254
}

mp4parse/tests/public.rs

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ fn public_api() {
4343
fd.read_to_end(&mut buf).expect("File error");
4444

4545
let mut c = Cursor::new(&buf);
46-
let mut context = mp4::MediaContext::new();
47-
mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
46+
let context = mp4::read_mp4(&mut c).expect("read_mp4 failed");
4847
assert_eq!(context.timescale, Some(mp4::MediaTimeScale(1000)));
4948
for track in context.tracks {
5049
match track.track_type {
@@ -164,8 +163,7 @@ fn public_metadata() {
164163
fd.read_to_end(&mut buf).expect("File error");
165164

166165
let mut c = Cursor::new(&buf);
167-
let mut context = mp4::MediaContext::new();
168-
mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
166+
let context = mp4::read_mp4(&mut c).expect("read_mp4 failed");
169167
let udta = context
170168
.userdata
171169
.expect("didn't find udta")
@@ -232,8 +230,7 @@ fn public_metadata_gnre() {
232230
fd.read_to_end(&mut buf).expect("File error");
233231

234232
let mut c = Cursor::new(&buf);
235-
let mut context = mp4::MediaContext::new();
236-
mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
233+
let context = mp4::read_mp4(&mut c).expect("read_mp4 failed");
237234
let udta = context
238235
.userdata
239236
.expect("didn't find udta")
@@ -301,8 +298,7 @@ fn public_audio_tenc() {
301298
fd.read_to_end(&mut buf).expect("File error");
302299

303300
let mut c = Cursor::new(&buf);
304-
let mut context = mp4::MediaContext::new();
305-
mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
301+
let context = mp4::read_mp4(&mut c).expect("read_mp4 failed");
306302
for track in context.tracks {
307303
let stsd = track.stsd.expect("expected an stsd");
308304
let a = match stsd.descriptions.first().expect("expected a SampleEntry") {
@@ -360,8 +356,7 @@ fn public_video_cenc() {
360356
fd.read_to_end(&mut buf).expect("File error");
361357

362358
let mut c = Cursor::new(&buf);
363-
let mut context = mp4::MediaContext::new();
364-
mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
359+
let context = mp4::read_mp4(&mut c).expect("read_mp4 failed");
365360
for track in context.tracks {
366361
let stsd = track.stsd.expect("expected an stsd");
367362
let v = match stsd.descriptions.first().expect("expected a SampleEntry") {
@@ -433,8 +428,7 @@ fn public_audio_cbcs() {
433428
fd.read_to_end(&mut buf).expect("File error");
434429

435430
let mut c = Cursor::new(&buf);
436-
let mut context = mp4::MediaContext::new();
437-
mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
431+
let context = mp4::read_mp4(&mut c).expect("read_mp4 failed");
438432
for track in context.tracks {
439433
let stsd = track.stsd.expect("expected an stsd");
440434
assert_eq!(stsd.descriptions.len(), 2);
@@ -516,8 +510,7 @@ fn public_video_cbcs() {
516510
fd.read_to_end(&mut buf).expect("File error");
517511

518512
let mut c = Cursor::new(&buf);
519-
let mut context = mp4::MediaContext::new();
520-
mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
513+
let context = mp4::read_mp4(&mut c).expect("read_mp4 failed");
521514
for track in context.tracks {
522515
let stsd = track.stsd.expect("expected an stsd");
523516
assert_eq!(stsd.descriptions.len(), 2);
@@ -576,8 +569,7 @@ fn public_video_av1() {
576569
fd.read_to_end(&mut buf).expect("File error");
577570

578571
let mut c = Cursor::new(&buf);
579-
let mut context = mp4::MediaContext::new();
580-
mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
572+
let context = mp4::read_mp4(&mut c).expect("read_mp4 failed");
581573
for track in context.tracks {
582574
// track part
583575
assert_eq!(track.duration, Some(mp4::TrackScaledTime(512, 0)));
@@ -623,41 +615,36 @@ fn public_video_av1() {
623615

624616
#[test]
625617
fn public_avif_primary_item() {
626-
let context = &mut mp4::AvifContext::new();
627618
let input = &mut File::open(IMAGE_AVIF).expect("Unknown file");
628-
mp4::read_avif(input, context).expect("read_avif failed");
619+
let context = mp4::read_avif(input).expect("read_avif failed");
629620
assert_eq!(context.primary_item.len(), 6979);
630621
assert_eq!(context.primary_item[0..4], [0x12, 0x00, 0x0a, 0x0a]);
631622
}
632623

633624
#[test]
634625
fn public_avif_primary_item_split_extents() {
635-
let context = &mut mp4::AvifContext::new();
636626
let input = &mut File::open(IMAGE_AVIF_EXTENTS).expect("Unknown file");
637-
mp4::read_avif(input, context).expect("read_avif failed");
627+
let context = mp4::read_avif(input).expect("read_avif failed");
638628
assert_eq!(context.primary_item.len(), 4387);
639629
}
640630

641631
#[test]
642632
fn public_avif_bug_1655846() {
643-
let context = &mut mp4::AvifContext::new();
644633
let input = &mut File::open(IMAGE_AVIF_CORRUPT).expect("Unknown file");
645-
assert!(mp4::read_avif(input, context).is_err());
634+
assert!(mp4::read_avif(input).is_err());
646635
}
647636

648637
#[test]
649638
fn public_avif_bug_1661347() {
650-
let context = &mut mp4::AvifContext::new();
651639
let input = &mut File::open(IMAGE_AVIF_CORRUPT_2).expect("Unknown file");
652-
assert!(mp4::read_avif(input, context).is_err());
640+
assert!(mp4::read_avif(input).is_err());
653641
}
654642

655643
#[test]
656644
#[ignore] // Remove when we add support; see https://github.com/mozilla/mp4parse-rust/issues/198
657645
fn public_avif_primary_item_is_grid() {
658-
let context = &mut mp4::AvifContext::new();
659646
let input = &mut File::open(IMAGE_AVIF_GRID).expect("Unknown file");
660-
mp4::read_avif(input, context).expect("read_avif failed");
647+
mp4::read_avif(input).expect("read_avif failed");
661648
// Add some additional checks
662649
}
663650

@@ -675,8 +662,7 @@ fn public_avif_read_samples() {
675662
continue; // Remove when public_avif_primary_item_is_grid passes
676663
}
677664
println!("parsing {:?}", path);
678-
let context = &mut mp4::AvifContext::new();
679665
let input = &mut File::open(path).expect("Unknow file");
680-
mp4::read_avif(input, context).expect("read_avif failed");
666+
mp4::read_avif(input).expect("read_avif failed");
681667
}
682668
}

0 commit comments

Comments
 (0)