Bug 1342852 - update rust mp4 parser. r=kinetik draft
authorAlfredo.Yang <ayang@mozilla.com>
Wed, 01 Mar 2017 16:52:46 +0800
changeset 490780 716bb6df434acc245721d15a7ee14c5bfae0f44a
parent 490433 1bc2ad020aee2830e0a7941f10958dbec108c254
child 547371 3987919858a668886545c89fe8bf4bbb6e7faaf9
push id47221
push userbmo:ayang@mozilla.com
push dateWed, 01 Mar 2017 08:58:11 +0000
reviewerskinetik
bugs1342852
milestone54.0a1
Bug 1342852 - update rust mp4 parser. r=kinetik MozReview-Commit-ID: 5GzgpfPqMD8
media/libstagefright/binding/mp4parse-cargo.patch
media/libstagefright/binding/mp4parse/Cargo.toml
media/libstagefright/binding/mp4parse/src/lib.rs
media/libstagefright/binding/mp4parse/src/tests.rs
media/libstagefright/binding/mp4parse_capi/Cargo.toml
media/libstagefright/binding/mp4parse_capi/src/lib.rs
media/libstagefright/binding/update-rust.sh
toolkit/library/gtest/rust/Cargo.lock
toolkit/library/rust/Cargo.lock
--- a/media/libstagefright/binding/mp4parse-cargo.patch
+++ b/media/libstagefright/binding/mp4parse-cargo.patch
@@ -31,20 +31,20 @@ index aeeebc65..5c0836a 100644
    "*.mp4",
  ]
  
 -build = "build.rs"
 -
 -[badges]
 -travis-ci = { repository = "https://github.com/mozilla/mp4parse-rust" }
 +build = false
-
+ 
  [dependencies]
  byteorder = "1.0.0"
- "mp4parse" = {version = "0.6.0", path = "../mp4parse"}
+ mp4parse = {version = "0.7.0", path = "../mp4parse"}
  
 -[build-dependencies]
 -rusty-cheddar = "0.3.2"
 -
 -[features]
 -fuzz = ["mp4parse/fuzz"]
 -
  # Somewhat heavy-handed, but we want at least -Z force-overflow-checks=on.
--- a/media/libstagefright/binding/mp4parse/Cargo.toml
+++ b/media/libstagefright/binding/mp4parse/Cargo.toml
@@ -1,11 +1,11 @@
 [package]
 name = "mp4parse"
-version = "0.6.0"
+version = "0.7.0"
 authors = [
   "Ralph Giles <giles@mozilla.com>",
   "Matthew Gregan <kinetik@flim.org>",
   "Alfredo Yang <ayang@mozilla.com>",
 ]
 
 description = "Parser for ISO base media file format (mp4)"
 documentation = "https://mp4parse-docs.surge.sh/mp4parse/"
--- a/media/libstagefright/binding/mp4parse/src/lib.rs
+++ b/media/libstagefright/binding/mp4parse/src/lib.rs
@@ -1619,19 +1619,19 @@ fn read_hdlr<T: Read>(src: &mut BMFFBox<
     let _name = read_null_terminated_string(src, bytes_left)?;
 
     Ok(HandlerBox {
         handler_type: handler_type,
     })
 }
 
 /// Parse an video description inside an stsd box.
-fn read_video_sample_entry<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) -> Result<SampleEntry> {
+fn read_video_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<(CodecType, SampleEntry)> {
     let name = src.get_header().name;
-    track.codec_type = match name {
+    let codec_type = match name {
         BoxType::AVCSampleEntry | BoxType::AVC3SampleEntry => CodecType::H264,
         BoxType::VP8SampleEntry => CodecType::VP8,
         BoxType::VP9SampleEntry => CodecType::VP9,
         BoxType::ProtectedVisualSampleEntry => CodecType::EncryptedVideo,
         _ => CodecType::Unknown,
     };
 
     // Skip uninteresting fields.
@@ -1694,23 +1694,23 @@ fn read_video_sample_entry<T: Read>(src:
                 protection_info.push(sinf);
             }
             _ => skip_box_content(&mut b)?,
         }
         check_parser_state!(b.content);
     }
 
     codec_specific
-        .map(|codec_specific| SampleEntry::Video(VideoSampleEntry {
+        .map(|codec_specific| (codec_type, SampleEntry::Video(VideoSampleEntry {
             data_reference_index: data_reference_index,
             width: width,
             height: height,
             codec_specific: codec_specific,
             protection_info: protection_info,
-        }))
+        })))
         .ok_or_else(|| Error::InvalidData("malformed video sample entry"))
 }
 
 fn read_qt_wave_atom<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
     let mut codec_specific = None;
     let mut iter = src.box_iter();
     while let Some(mut b) = iter.next_box()? {
         match b.head.name {
@@ -1721,17 +1721,17 @@ fn read_qt_wave_atom<T: Read>(src: &mut 
             _ => skip_box_content(&mut b)?,
         }
     }
 
     codec_specific.ok_or_else(|| Error::InvalidData("malformed audio sample entry"))
 }
 
 /// Parse an audio description inside an stsd box.
-fn read_audio_sample_entry<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) -> Result<SampleEntry> {
+fn read_audio_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<(CodecType, SampleEntry)> {
     let name = src.get_header().name;
 
     // Skip uninteresting fields.
     skip(src, 6)?;
 
     let data_reference_index = be_u16(src)?;
 
     // XXX(kinetik): This is "reserved" in BMFF, but some old QT MOV variant
@@ -1757,102 +1757,107 @@ fn read_audio_sample_entry<T: Read>(src:
             // Quicktime sound sample description version 1.
             // Skip uninteresting fields.
             skip(src, 16)?;
         },
         _ => return Err(Error::Unsupported("unsupported non-isom audio sample entry")),
     }
 
     // Skip chan/etc. for now.
+    let mut codec_type = CodecType::Unknown;
     let mut codec_specific = None;
     if name == BoxType::MP3AudioSampleEntry {
+        codec_type = CodecType::MP3;
         codec_specific = Some(AudioCodecSpecific::MP3);
     }
     let mut protection_info = Vec::new();
     let mut iter = src.box_iter();
     while let Some(mut b) = iter.next_box()? {
         match b.head.name {
             BoxType::ESDBox => {
                 if (name != BoxType::MP4AudioSampleEntry &&
                     name != BoxType::ProtectedAudioSampleEntry) ||
                     codec_specific.is_some() {
                         return Err(Error::InvalidData("malformed audio sample entry"));
                 }
 
                 let esds = read_esds(&mut b)?;
-                track.codec_type = esds.audio_codec;
+                codec_type = esds.audio_codec;
                 codec_specific = Some(AudioCodecSpecific::ES_Descriptor(esds));
             }
             BoxType::FLACSpecificBox => {
                 if name != BoxType::FLACSampleEntry ||
                     codec_specific.is_some() {
                     return Err(Error::InvalidData("malformed audio sample entry"));
                 }
                 let dfla = read_dfla(&mut b)?;
-                track.codec_type = CodecType::FLAC;
+                codec_type = CodecType::FLAC;
                 codec_specific = Some(AudioCodecSpecific::FLACSpecificBox(dfla));
             }
             BoxType::OpusSpecificBox => {
                 if name != BoxType::OpusSampleEntry ||
                     codec_specific.is_some() {
                     return Err(Error::InvalidData("malformed audio sample entry"));
                 }
                 let dops = read_dops(&mut b)?;
-                track.codec_type = CodecType::Opus;
+                codec_type = CodecType::Opus;
                 codec_specific = Some(AudioCodecSpecific::OpusSpecificBox(dops));
             }
             BoxType::QTWaveAtom => {
                 let qt_esds = read_qt_wave_atom(&mut b)?;
-                track.codec_type = qt_esds.audio_codec;
+                codec_type = qt_esds.audio_codec;
                 codec_specific = Some(AudioCodecSpecific::ES_Descriptor(qt_esds));
             }
             BoxType::ProtectionSchemeInformationBox => {
                 if name != BoxType::ProtectedAudioSampleEntry {
                     return Err(Error::InvalidData("malformed audio sample entry"));
                 }
                 let sinf = read_sinf(&mut b)?;
                 log!("{:?} (sinf)", sinf);
-                track.codec_type = CodecType::EncryptedAudio;
+                codec_type = CodecType::EncryptedAudio;
                 protection_info.push(sinf);
             }
             _ => skip_box_content(&mut b)?,
         }
         check_parser_state!(b.content);
     }
 
     codec_specific
-        .map(|codec_specific| SampleEntry::Audio(AudioSampleEntry {
+        .map(|codec_specific| (codec_type, SampleEntry::Audio(AudioSampleEntry {
             data_reference_index: data_reference_index,
             channelcount: channelcount,
             samplesize: samplesize,
             samplerate: samplerate,
             codec_specific: codec_specific,
             protection_info: protection_info,
-        }))
+        })))
         .ok_or_else(|| Error::InvalidData("malformed audio sample entry"))
 }
 
 /// Parse a stsd box.
 fn read_stsd<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) -> Result<SampleDescriptionBox> {
     let (_, _) = read_fullbox_extra(src)?;
 
     let description_count = be_u32(src)?;
     let mut descriptions = Vec::new();
 
     {
         // TODO(kinetik): check if/when more than one desc per track? do we need to support?
         let mut iter = src.box_iter();
         while let Some(mut b) = iter.next_box()? {
             let description = match track.track_type {
-                TrackType::Video => read_video_sample_entry(&mut b, track),
-                TrackType::Audio => read_audio_sample_entry(&mut b, track),
+                TrackType::Video => read_video_sample_entry(&mut b),
+                TrackType::Audio => read_audio_sample_entry(&mut b),
                 TrackType::Unknown => Err(Error::Unsupported("unknown track type")),
             };
             let description = match description {
-                Ok(desc) => desc,
+                Ok((codec_type, desc)) => {
+                    track.codec_type = codec_type;
+                    desc
+                }
                 Err(Error::Unsupported(_)) => {
                     // read_{audio,video}_desc may have returned Unsupported
                     // after partially reading the box content, so we can't
                     // simply use skip_box_content here.
                     let to_skip = b.bytes_left();
                     skip(&mut b, to_skip)?;
                     SampleEntry::Unknown
                 }
--- a/media/libstagefright/binding/mp4parse/src/tests.rs
+++ b/media/libstagefright/binding/mp4parse/src/tests.rs
@@ -465,19 +465,18 @@ fn read_flac() {
          .B16(0) // reserved
          .B32(44100 << 16) // Sample rate
          .append_bytes(&make_dfla(FlacBlockType::StreamInfo, true,
                                   &flac_streaminfo(), FlacBlockLength::Correct)
          .into_inner())
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
-    let mut track = super::Track::new(0);
-    let r = super::read_audio_sample_entry(&mut stream, &mut track);
-    r.unwrap();
+    let r = super::read_audio_sample_entry(&mut stream);
+    assert!(r.is_ok());
 }
 
 #[derive(Clone, Copy)]
 enum FlacBlockType {
     StreamInfo = 0,
     _Padding = 1,
     _Application = 2,
     _Seektable = 3,
@@ -549,18 +548,17 @@ fn read_opus() {
          .B16(16) // bits per sample
          .B16(0)
          .B16(0)
          .B32(48000 << 16) // Sample rate is always 48 kHz for Opus.
          .append_bytes(&make_dops().into_inner())
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
-    let mut track = super::Track::new(0);
-    let r = super::read_audio_sample_entry(&mut stream, &mut track);
+    let r = super::read_audio_sample_entry(&mut stream);
     assert!(r.is_ok());
 }
 
 fn make_dops() -> Cursor<Vec<u8>> {
     make_box(BoxSize::Auto, b"dOps", |s| {
         s.B8(0) // version
          .B8(2) // channel count
          .B16(348) // pre-skip
@@ -637,18 +635,17 @@ fn avcc_limit() {
          .append_repeated(0, 32)
          .append_repeated(0, 4)
          .B32(0xffffffff)
          .append_bytes(b"avcC")
          .append_repeated(0, 100)
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
-    let mut track = super::Track::new(0);
-    match super::read_video_sample_entry(&mut stream, &mut track) {
+    match super::read_video_sample_entry(&mut stream) {
         Err(Error::InvalidData(s)) => assert_eq!(s, "avcC box exceeds BUF_SIZE_LIMIT"),
         Ok(_) => panic!("expected an error result"),
         _ => panic!("expected a different error result"),
     }
 }
 
 #[test]
 fn esds_limit() {
@@ -663,18 +660,17 @@ fn esds_limit() {
          .B16(0)
          .B32(48000 << 16)
          .B32(0xffffffff)
          .append_bytes(b"esds")
          .append_repeated(0, 100)
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
-    let mut track = super::Track::new(0);
-    match super::read_audio_sample_entry(&mut stream, &mut track) {
+    match super::read_audio_sample_entry(&mut stream) {
         Err(Error::InvalidData(s)) => assert_eq!(s, "esds box exceeds BUF_SIZE_LIMIT"),
         Ok(_) => panic!("expected an error result"),
         _ => panic!("expected a different error result"),
     }
 }
 
 #[test]
 fn esds_limit_2() {
@@ -689,18 +685,17 @@ fn esds_limit_2() {
          .B16(0)
          .B32(48000 << 16)
          .B32(8)
          .append_bytes(b"esds")
          .append_repeated(0, 4)
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
-    let mut track = super::Track::new(0);
-    match super::read_audio_sample_entry(&mut stream, &mut track) {
+    match super::read_audio_sample_entry(&mut stream) {
         Err(Error::UnexpectedEOF) => (),
         Ok(_) => panic!("expected an error result"),
         _ => panic!("expected a different error result"),
     }
 }
 
 #[test]
 fn read_elst_zero_entries() {
@@ -848,20 +843,19 @@ fn read_qt_wave_atom() {
          .append_repeated(0, 4)
          .B32(48000 << 16)
          .append_repeated(0, 16)
          .append_bytes(wave.as_slice())
     });
 
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
-    let mut track = super::Track::new(0);
-    super::read_audio_sample_entry(&mut stream, &mut track)
+    let (codec_type, _) = super::read_audio_sample_entry(&mut stream)
           .expect("fail to read qt wave atom");
-    assert_eq!(track.codec_type, super::CodecType::MP3);
+    assert_eq!(codec_type, super::CodecType::MP3);
 }
 
 #[test]
 fn read_esds() {
     let aac_esds =
         vec![
             0x03, 0x24, 0x00, 0x00, 0x00, 0x04, 0x1c, 0x40,
             0x15, 0x00, 0x12, 0x00, 0x00, 0x01, 0xf4, 0x00,
@@ -895,8 +889,28 @@ fn read_null_terminated_string() {
         vec![0u8, 0u8],                    // Doubly null-terminated string.
     ];
     for v in tests.iter() {
         let mut c = Cursor::new(v);
         super::read_null_terminated_string(&mut c, v.len()).expect("string read failed");
         assert_eq!(c.position(), v.len() as u64);
     }
 }
+
+#[test]
+fn read_f4v_stsd() {
+    let mut stream = make_box(BoxSize::Auto, b".mp3", |s| {
+        s.append_repeated(0, 6)
+         .B16(1)
+         .B16(0)
+         .append_repeated(0, 6)
+         .B16(2)
+         .B16(16)
+         .append_repeated(0, 4)
+         .B32(48000 << 16)
+    });
+
+    let mut iter = super::BoxIter::new(&mut stream);
+    let mut stream = iter.next_box().unwrap().unwrap();
+    let (codec_type, _) = super::read_audio_sample_entry(&mut stream)
+          .expect("failed to read f4v stsd atom");
+    assert_eq!(codec_type, super::CodecType::MP3);
+}
--- a/media/libstagefright/binding/mp4parse_capi/Cargo.toml
+++ b/media/libstagefright/binding/mp4parse_capi/Cargo.toml
@@ -1,11 +1,11 @@
 [package]
 name = "mp4parse_capi"
-version = "0.6.0"
+version = "0.7.0"
 authors = [
   "Ralph Giles <giles@mozilla.com>",
   "Matthew Gregan <kinetik@flim.org>",
   "Alfredo Yang <ayang@mozilla.com>",
 ]
 
 description = "Parser for ISO base media file format (mp4)"
 documentation = "https://mp4parse-docs.surge.sh/mp4parse/"
@@ -17,13 +17,13 @@ repository = "https://github.com/mozilla
 exclude = [
   "*.mp4",
 ]
 
 build = false
 
 [dependencies]
 byteorder = "1.0.0"
-"mp4parse" = {version = "0.6.0", path = "../mp4parse"}
+mp4parse = {version = "0.7.0", path = "../mp4parse"}
 
 # Somewhat heavy-handed, but we want at least -Z force-overflow-checks=on.
 [profile.release]
 debug-assertions = true
--- a/media/libstagefright/binding/mp4parse_capi/src/lib.rs
+++ b/media/libstagefright/binding/mp4parse_capi/src/lib.rs
@@ -669,23 +669,23 @@ pub unsafe extern fn mp4parse_get_indice
     }
 
     // Find the track start offset time from 'elst'.
     // 'media_time' maps start time onward, 'empty_duration' adds time offset
     // before first frame is displayed.
     let offset_time =
         match (&track.empty_duration, &track.media_time, &context.timescale) {
             (&Some(empty_duration), &Some(media_time), &Some(scale)) => {
-                (empty_duration.0 - media_time.0) as i64 * scale.0 as i64
+                (empty_duration.0 as i64 - media_time.0 as i64) * scale.0 as i64
             },
             (&Some(empty_duration), _, &Some(scale)) => {
                 empty_duration.0 as i64 * scale.0 as i64
             },
             (_, &Some(media_time), &Some(scale)) => {
-                (0 - media_time.0) as i64 * scale.0 as i64
+                (0 - media_time.0 as i64) * scale.0 as i64
             },
             _ => 0,
         };
 
     match create_sample_table(track, offset_time) {
         Some(v) => {
             (*indices).set_indices(&v);
             index_table.insert(track_id, v);
--- a/media/libstagefright/binding/update-rust.sh
+++ b/media/libstagefright/binding/update-rust.sh
@@ -1,13 +1,13 @@
 #!/bin/sh -e
 # Script to update mp4parse-rust sources to latest upstream
 
 # Default version.
-VER=6dfc85b277f8a072083b71f23cc05981b22a10bc
+VER=1fbd8ce2f76c93b88bc7bc41bb67ca76a9f67712
 
 # Accept version or commit from the command line.
 if test -n "$1"; then
   VER=$1
 fi
 
 echo "Fetching sources..."
 rm -rf _upstream
--- a/toolkit/library/gtest/rust/Cargo.lock
+++ b/toolkit/library/gtest/rust/Cargo.lock
@@ -379,17 +379,17 @@ name = "getopts"
 version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "gkrust-shared"
 version = "0.1.0"
 dependencies = [
  "geckoservo 0.0.1",
- "mp4parse_capi 0.6.0",
+ "mp4parse_capi 0.7.0",
  "nsstring 0.1.0",
  "rust_url_capi 0.0.1",
  "webrender_bindings 0.1.0",
 ]
 
 [[package]]
 name = "gl_generator"
 version = "0.5.2"
@@ -497,32 +497,32 @@ source = "registry+https://github.com/ru
 dependencies = [
  "error-chain 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "mp4parse"
-version = "0.6.0"
+version = "0.7.0"
 dependencies = [
  "bitreader 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "mp4parse-gtest"
 version = "0.1.0"
 
 [[package]]
 name = "mp4parse_capi"
-version = "0.6.0"
+version = "0.7.0"
 dependencies = [
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "mp4parse 0.6.0",
+ "mp4parse 0.7.0",
 ]
 
 [[package]]
 name = "nom"
 version = "1.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
--- a/toolkit/library/rust/Cargo.lock
+++ b/toolkit/library/rust/Cargo.lock
@@ -377,17 +377,17 @@ name = "getopts"
 version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "gkrust-shared"
 version = "0.1.0"
 dependencies = [
  "geckoservo 0.0.1",
- "mp4parse_capi 0.6.0",
+ "mp4parse_capi 0.7.0",
  "nsstring 0.1.0",
  "rust_url_capi 0.0.1",
  "webrender_bindings 0.1.0",
 ]
 
 [[package]]
 name = "gl_generator"
 version = "0.5.2"
@@ -495,28 +495,28 @@ source = "registry+https://github.com/ru
 dependencies = [
  "error-chain 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "mp4parse"
-version = "0.6.0"
+version = "0.7.0"
 dependencies = [
  "bitreader 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "mp4parse_capi"
-version = "0.6.0"
+version = "0.7.0"
 dependencies = [
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "mp4parse 0.6.0",
+ "mp4parse 0.7.0",
 ]
 
 [[package]]
 name = "nom"
 version = "1.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]