Skip to content

Conversation

baumanj
Copy link
Contributor

@baumanj baumanj commented Dec 12, 2020

Resolves #261

https://treeherder.mozilla.org/jobs?repo=try&revision=96f98a79084b97402f73c8d3155d5889bdd75d35 is testing this applied to the mozilla-central tree and looks good. (Note that the ImageDecoders.AVIFStackCheck error on Windows is expected)

The behavior change was introduced by c196ca8

Despite being invalid according to ISOBMFF (ISO 14496-12:2015) § 8.2.1.1, this restores the original behavior, while maintaining the interface that eliminates the necessity for callers to create a MediaContext object to pass in.

A brief note about the approach here:
The original code for read_moov took a &mut MediaContext parameter and returned a Result<()>. This was fairly natural when the caller (read_mp4) also took a &mut MediaContext parameter. The point of #252 was to improve ergonomics by replacing the in-out context parameters and Result<()> returns with functions that returned the context (inside a Result). There are a number of benefits to this approach. It's less code since

    let mut context = MediaContext::new();
    read_mp4(input)

is reduced to

    read_mp4(input)

and it eliminates the possibility that an empty/invalid context even exists to be operated on. However, in the case of read_moov, despite the fact that ISOBMFF (ISO 14496-12:2015) § 8.2.1.1 states there should be "exactly one" moov box at the file level, at least one C++ test case depends on the parser accepting a file with multiple moov boxes and merging their content. It's not clear to me if this is a concession to the reality of pervasive invalid MP4 files encoded this way in the wild, or if we just happened to create an invalid test case, but for the sake of not blocking other work, this restores the previous behavior, but with a slightly different approach.

The previous signature was

fn read_moov<T: Read>(f: &mut BMFFBox<T>, context: &mut MediaContext) -> Result<()>

and the new one is

fn read_moov<T: Read>(f: &mut BMFFBox<T>, context: Option<MediaContext>) -> Result<MediaContext>

Though this has the slightly unconventional approach of taking an owned Option<MediaContext> and returning a Result<MediaContext>, it has the benefit of not requiring the caller to ever create a MediaContext object, and since in the case of a Some(_) argument for context, that same object is returned, performance should be similar to using a &mut MediaContext parameter.

The behavior change was introduced by c196ca8

Despite being invalid according to ISOBMFF (ISO 14496-12:2015) § 8.2.1.1, this
restores the original behavior, while maintaining the interface that eliminates
the necessity for callers to create a `MediaContext` object to pass in.
@baumanj baumanj self-assigned this Dec 12, 2020
This was referenced Dec 12, 2020
Comment on lines -741 to -746
impl MediaContext {
pub fn new() -> MediaContext {
Default::default()
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could've been removed in c196ca8, but better late than never

@@ -618,6 +618,24 @@ fn public_video_av1() {
}
}

#[test]
fn public_mp4_bug_1185230() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to do more here, but it was turning into a yak shave, so I've filed #264

Copy link
Collaborator

@kinetiknz kinetiknz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with reverting the behaviour, but it may be worth investigating whether we depend on this functionality for media in the wild.

It's not clear to me if this is a concession to the reality of pervasive invalid MP4 files encoded this way in the wild, or if we just happened to create an invalid test case, but for the sake of not blocking other work, this restores the previous behavior, but with a slightly different approach.

The original file attached to BMO bug 1185230 looks like the result of a fuzzing tool pasting a seed file together twice, so it seems to be an invalid testcase rather than a concession to media in the wild. Splitting the file in half (offset 13651) and comparing the two halves reveals only 6 differing locations in sequences of 2, 8, 4, 4, 1, and 2 bytes - 3 changes inside an mdat binary blob, a key bug triggering change to the time scale of an mdhd (3523726793 vs. 44100), and 2 inside a data element.

test_case_1185230.mp4 seems to be a remuxed derivative of that file with mdatss removed and some other rearrangement, but I'm not sure exactly how it was produced.

Copy link
Member

@ChunMinChang ChunMinChang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not actively working on these stuff. But I am happy to ship it to unblock the AVIF work.

@@ -2278,7 +2272,7 @@ pub fn read_mp4<T: Read>(f: &mut T) -> Result<MediaContext> {
debug!("{:?}", ftyp);
}
BoxType::MovieBox => {
context = Some(read_moov(&mut b)?);
context = Some(read_moov(&mut b, context)?);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the passed context here solves the problem?

Copy link
Contributor

@SingingTree SingingTree left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense to unblock work. Echoing what has already been said, if we can test that we don't need this in the wild it would be nice to not support it, but that's a task for telemetry in another patch.

@baumanj
Copy link
Contributor Author

baumanj commented Dec 14, 2020

For the sake of unblocking the AVIF work, I'm merging this for now. I filed https://bugzilla.mozilla.org/show_bug.cgi?id=1682376 to consider changing the behavior in the future.

@baumanj baumanj merged commit 3d9efdc into master Dec 14, 2020
@baumanj baumanj deleted the fix-read_moov branch December 14, 2020 19:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

c196ca8 cause MP4Metadata.test_case_mp4 fails
4 participants