Bug 1347834 - update rust mp4 parser for audio codec specific data. r=kinetik
authorAlfredo.Yang <ayang@mozilla.com>
Fri, 17 Mar 2017 11:13:22 +0800
changeset 348387 32e03588ec39f9ecf41c359bccd428b3ea74d034
parent 348386 51c124a0f50b6484c40fe47878430a1a79a618bf
child 348388 8b0d4d072cf0f78e8c78b08cbca7f5b082d5a9c1
push id39137
push userayang@mozilla.com
push dateMon, 20 Mar 2017 01:27:31 +0000
treeherderautoland@32e03588ec39 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik
bugs1347834
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1347834 - update rust mp4 parser for audio codec specific data. r=kinetik MozReview-Commit-ID: 29yu6VsFIE6
media/libstagefright/binding/include/mp4parse.h
media/libstagefright/binding/mp4parse/src/lib.rs
media/libstagefright/binding/mp4parse/src/tests.rs
media/libstagefright/binding/mp4parse/tests/public.rs
media/libstagefright/binding/mp4parse_capi/src/lib.rs
media/libstagefright/binding/update-rust.sh
--- a/media/libstagefright/binding/include/mp4parse.h
+++ b/media/libstagefright/binding/include/mp4parse.h
@@ -73,16 +73,17 @@ typedef struct mp4parse_sinf_info {
 	mp4parse_byte_data kid;
 } mp4parse_sinf_info;
 
 typedef struct mp4parse_track_audio_info {
 	uint16_t channels;
 	uint16_t bit_depth;
 	uint32_t sample_rate;
 	uint16_t profile;
+	mp4parse_byte_data codec_specific_data;
 	mp4parse_byte_data codec_specific_config;
 	mp4parse_sinf_info protected_data;
 } mp4parse_track_audio_info;
 
 typedef struct mp4parse_track_video_info {
 	uint32_t display_width;
 	uint32_t display_height;
 	uint16_t image_width;
@@ -103,17 +104,17 @@ typedef struct mp4parse_io {
 } mp4parse_io;
 
 /// Allocate an `mp4parse_parser*` to read from the supplied `mp4parse_io`.
 mp4parse_parser* mp4parse_new(mp4parse_io const* io);
 
 /// Free an `mp4parse_parser*` allocated by `mp4parse_new()`.
 void mp4parse_free(mp4parse_parser* parser);
 
-/// Enable mp4_parser log.
+/// Enable `mp4_parser` log.
 void mp4parse_log(bool enable);
 
 /// Run the `mp4parse_parser*` allocated by `mp4parse_new()` until EOF or error.
 mp4parse_error mp4parse_read(mp4parse_parser* parser);
 
 /// Return the number of tracks parsed by previous `mp4parse_read()` call.
 mp4parse_error mp4parse_get_track_count(mp4parse_parser const* parser, uint32_t* count);
 
@@ -131,20 +132,21 @@ mp4parse_error mp4parse_get_indice_table
 /// Fill the supplied `mp4parse_fragment_info` with metadata from fragmented file.
 mp4parse_error mp4parse_get_fragment_info(mp4parse_parser* parser, mp4parse_fragment_info* info);
 
 /// A fragmented file needs mvex table and contains no data in stts, stsc, and stco boxes.
 mp4parse_error mp4parse_is_fragmented(mp4parse_parser* parser, uint32_t track_id, uint8_t* fragmented);
 
 /// Get 'pssh' system id and 'pssh' box content for eme playback.
 ///
-/// The data format in 'info' passing to gecko is:
-///   system_id
-///   pssh box size (in native endian)
-///   pssh box content (including header)
+/// The data format of the `info` struct passed to gecko is:
+///
+/// - system id (16 byte uuid)
+/// - pssh box size (32-bit native endian)
+/// - pssh box content (including header)
 mp4parse_error mp4parse_get_pssh_info(mp4parse_parser* parser, mp4parse_pssh_info* info);
 
 
 
 #ifdef __cplusplus
 }
 #endif
 
--- a/media/libstagefright/binding/mp4parse/src/lib.rs
+++ b/media/libstagefright/binding/mp4parse/src/lib.rs
@@ -233,16 +233,17 @@ pub enum SampleEntry {
 #[allow(non_camel_case_types)]
 #[derive(Debug, Clone, Default)]
 pub struct ES_Descriptor {
     pub audio_codec: CodecType,
     pub audio_object_type: Option<u16>,
     pub audio_sample_rate: Option<u32>,
     pub audio_channel_count: Option<u16>,
     pub codec_esds: Vec<u8>,
+    pub decoder_specific_data: Vec<u8>, // Data in DECODER_SPECIFIC_TAG
 }
 
 #[allow(non_camel_case_types)]
 #[derive(Debug, Clone)]
 pub enum AudioCodecSpecific {
     ES_Descriptor(ES_Descriptor),
     FLACSpecificBox(FLACSpecificBox),
     OpusSpecificBox(OpusSpecificBox),
@@ -1407,16 +1408,18 @@ fn read_ds_descriptor(data: &[u8], esds:
         channel_counts += read_surround_channel_count(bit_reader, num_side_channel)?;
         channel_counts += read_surround_channel_count(bit_reader, num_back_channel)?;
         channel_counts += read_surround_channel_count(bit_reader, num_lfe_channel)?;
     }
 
     esds.audio_object_type = Some(audio_object_type);
     esds.audio_sample_rate = sample_frequency;
     esds.audio_channel_count = Some(channel_counts);
+    assert!(esds.decoder_specific_data.is_empty());
+    esds.decoder_specific_data.extend(data.iter());
 
     Ok(())
 }
 
 fn read_surround_channel_count(bit_reader: &mut BitReader, channels: u8) -> Result<u16> {
     let mut count = 0;
     for _ in 0..channels {
         let is_cpe: bool = ReadInto::read(bit_reader, 1)?;
--- a/media/libstagefright/binding/mp4parse/src/tests.rs
+++ b/media/libstagefright/binding/mp4parse/src/tests.rs
@@ -858,30 +858,33 @@ fn read_esds() {
     let aac_esds =
         vec![
             0x03, 0x24, 0x00, 0x00, 0x00, 0x04, 0x1c, 0x40,
             0x15, 0x00, 0x12, 0x00, 0x00, 0x01, 0xf4, 0x00,
             0x00, 0x01, 0xf4, 0x00, 0x05, 0x0d, 0x13, 0x00,
             0x05, 0x88, 0x05, 0x00, 0x48, 0x21, 0x10, 0x00,
             0x56, 0xe5, 0x98, 0x06, 0x01, 0x02,
         ];
+    let aac_dc_descriptor = &aac_esds[22 .. 35];
+
     let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
         s.B32(0) // reserved
          .append_bytes(aac_esds.as_slice())
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
 
     let es = super::read_esds(&mut stream).unwrap();
 
     assert_eq!(es.audio_codec, super::CodecType::AAC);
     assert_eq!(es.audio_object_type, Some(2));
     assert_eq!(es.audio_sample_rate, Some(24000));
     assert_eq!(es.audio_channel_count, Some(6));
     assert_eq!(es.codec_esds, aac_esds);
+    assert_eq!(es.decoder_specific_data, aac_dc_descriptor);
 }
 
 #[test]
 fn read_null_terminated_string() {
     let tests = vec![
         vec![0u8],                         // Short null-terminated string.
         vec![65u8, 0u8],                   // Normal null-terminated string.
         vec![],                            // Empty string (no data).
--- a/media/libstagefright/binding/mp4parse/tests/public.rs
+++ b/media/libstagefright/binding/mp4parse/tests/public.rs
@@ -117,22 +117,22 @@ fn public_audio_tenc() {
     let mut c = Cursor::new(&buf);
     let mut context = mp4::MediaContext::new();
     mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
     for track in context.tracks {
         assert_eq!(track.codec_type, mp4::CodecType::EncryptedAudio);
         match track.data {
             Some(mp4::SampleEntry::Audio(a)) => {
                 match a.protection_info.iter().find(|sinf| sinf.tenc.is_some()) {
-                    Some(ref p) => {
+                    Some(p) => {
                         assert_eq!(p.code_name, "mp4a");
                         if let Some(ref tenc) = p.tenc {
                             assert!(tenc.is_encrypted > 0);
-                            assert!(tenc.iv_size ==  16);
-                            assert!(tenc.kid == kid);
+                            assert_eq!(tenc.iv_size, 16);
+                            assert_eq!(tenc.kid, kid);
                         } else {
                             assert!(false, "Invalid test condition");
                         }
                     },
                     _=> {
                         assert!(false, "Invalid test condition");
                     },
                 }
@@ -170,22 +170,22 @@ fn public_video_cenc() {
     let mut c = Cursor::new(&buf);
     let mut context = mp4::MediaContext::new();
     mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
     for track in context.tracks {
         assert_eq!(track.codec_type, mp4::CodecType::EncryptedVideo);
         match track.data {
             Some(mp4::SampleEntry::Video(v)) => {
                 match v.protection_info.iter().find(|sinf| sinf.tenc.is_some()) {
-                    Some(ref p) => {
+                    Some(p) => {
                         assert_eq!(p.code_name, "avc1");
                         if let Some(ref tenc) = p.tenc {
                             assert!(tenc.is_encrypted > 0);
-                            assert!(tenc.iv_size ==  16);
-                            assert!(tenc.kid == kid);
+                            assert_eq!(tenc.iv_size, 16);
+                            assert_eq!(tenc.kid, kid);
                         } else {
                             assert!(false, "Invalid test condition");
                         }
                     },
                     _=> {
                         assert!(false, "Invalid test condition");
                     },
                 }
--- a/media/libstagefright/binding/mp4parse_capi/src/lib.rs
+++ b/media/libstagefright/binding/mp4parse_capi/src/lib.rs
@@ -142,21 +142,21 @@ impl Default for mp4parse_byte_data {
             length: 0,
             data: std::ptr::null(),
             indices: std::ptr::null(),
         }
     }
 }
 
 impl mp4parse_byte_data {
-    fn set_data(&mut self, data: &Vec<u8>) {
+    fn set_data(&mut self, data: &[u8]) {
         self.length = data.len() as u32;
         self.data = data.as_ptr();
     }
-    fn set_indices(&mut self, data: &Vec<mp4parse_indice>) {
+    fn set_indices(&mut self, data: &[mp4parse_indice]) {
         self.length = data.len() as u32;
         self.indices = data.as_ptr();
     }
 }
 
 #[repr(C)]
 #[derive(Default)]
 pub struct mp4parse_pssh_info {
@@ -173,16 +173,21 @@ pub struct mp4parse_sinf_info {
 
 #[repr(C)]
 #[derive(Default)]
 pub struct mp4parse_track_audio_info {
     pub channels: u16,
     pub bit_depth: u16,
     pub sample_rate: u32,
     pub profile: u16,
+    // TODO:
+    //  codec_specific_data is AudioInfo.mCodecSpecificConfig,
+    //  codec_specific_config is AudioInfo.mExtraData.
+    //  It'd be better to change name same as AudioInfo.
+    pub codec_specific_data: mp4parse_byte_data,
     pub codec_specific_config: mp4parse_byte_data,
     pub protected_data: mp4parse_sinf_info,
 }
 
 #[repr(C)]
 #[derive(Default)]
 pub struct mp4parse_track_video_info {
     pub display_width: u32,
@@ -301,17 +306,17 @@ pub unsafe extern fn mp4parse_new(io: *c
 
 /// Free an `mp4parse_parser*` allocated by `mp4parse_new()`.
 #[no_mangle]
 pub unsafe extern fn mp4parse_free(parser: *mut mp4parse_parser) {
     assert!(!parser.is_null());
     let _ = Box::from_raw(parser);
 }
 
-/// Enable mp4_parser log.
+/// Enable `mp4_parser` log.
 #[no_mangle]
 pub unsafe extern fn mp4parse_log(enable: bool) {
     mp4parse::set_debug_mode(enable);
 }
 
 /// Run the `mp4parse_parser*` allocated by `mp4parse_new()` until EOF or error.
 #[no_mangle]
 pub unsafe extern fn mp4parse_read(parser: *mut mp4parse_parser) -> mp4parse_error {
@@ -520,16 +525,18 @@ pub unsafe extern fn mp4parse_get_track_
 
     match audio.codec_specific {
         AudioCodecSpecific::ES_Descriptor(ref v) => {
             if v.codec_esds.len() > std::u32::MAX as usize {
                 return MP4PARSE_ERROR_INVALID;
             }
             (*info).codec_specific_config.length = v.codec_esds.len() as u32;
             (*info).codec_specific_config.data = v.codec_esds.as_ptr();
+            (*info).codec_specific_data.length = v.decoder_specific_data.len() as u32;
+            (*info).codec_specific_data.data = v.decoder_specific_data.as_ptr();
             if let Some(rate) = v.audio_sample_rate {
                 (*info).sample_rate = rate;
             }
             if let Some(channels) = v.audio_channel_count {
                 (*info).channels = channels;
             }
             if let Some(profile) = v.audio_object_type {
                 (*info).profile = profile;
@@ -565,17 +572,17 @@ pub unsafe extern fn mp4parse_get_track_
                     }
                 }
             }
         }
         AudioCodecSpecific::MP3 => (),
     }
 
     match audio.protection_info.iter().find(|sinf| sinf.tenc.is_some()) {
-        Some(ref p) => {
+        Some(p) => {
             if let Some(ref tenc) = p.tenc {
                 (*info).protected_data.is_encrypted = tenc.is_encrypted;
                 (*info).protected_data.iv_size = tenc.iv_size;
                 (*info).protected_data.kid.set_data(&(tenc.kid));
             }
         },
         _ => {},
     }
@@ -628,17 +635,17 @@ pub unsafe extern fn mp4parse_get_track_
     match video.codec_specific {
         VideoCodecSpecific::AVCConfig(ref avc) => {
             (*info).extra_data.set_data(avc);
         },
         _ => {},
     }
 
     match video.protection_info.iter().find(|sinf| sinf.tenc.is_some()) {
-        Some(ref p) => {
+        Some(p) => {
             if let Some(ref tenc) = p.tenc {
                 (*info).protected_data.is_encrypted = tenc.is_encrypted;
                 (*info).protected_data.iv_size = tenc.iv_size;
                 (*info).protected_data.kid.set_data(&(tenc.kid));
             }
         },
         _ => {},
     }
@@ -927,27 +934,27 @@ fn create_sample_table(track: &Track, tr
                     start_decode: 0,
                     sync: !has_sync_table,
                 }
             );
         }
     }
 
     // Mark the sync sample in sample_table according to 'stss'.
-    match &track.stss {
-        &Some(ref v) => {
+    match track.stss {
+        Some(ref v) => {
             for iter in &v.samples {
                 sample_table[(iter - 1) as usize].sync = true;
             }
         },
         _ => {}
     }
 
-    let ctts_iter = match &track.ctts {
-        &Some(ref v) => Some(v.samples.as_slice().iter()),
+    let ctts_iter = match track.ctts {
+        Some(ref v) => Some(v.samples.as_slice().iter()),
         _ => None,
     };
 
     let mut ctts_offset_iter = TimeOffsetIterator {
         cur_sample_range: (0 .. 0),
         cur_offset: 0,
         ctts_iter: ctts_iter,
     };
@@ -1001,17 +1008,17 @@ fn create_sample_table(track: &Track, tr
             }
         });
 
         let iter = sort_table.iter();
         for i in 0 .. (iter.len() - 1) {
             let current_index = sort_table[i] as usize;
             let peek_index = sort_table[i + 1] as usize;
             let next_start_composition_time = sample_table[peek_index].start_composition;
-            let ref mut sample = sample_table[current_index];
+            let sample = &mut sample_table[current_index];
             sample.end_composition = next_start_composition_time;
         }
     }
 
     Some(sample_table)
 }
 
 /// Fill the supplied `mp4parse_fragment_info` with metadata from fragmented file.
@@ -1067,20 +1074,21 @@ pub unsafe extern fn mp4parse_is_fragmen
         None => return MP4PARSE_ERROR_BADARG,
     }
 
     MP4PARSE_OK
 }
 
 /// Get 'pssh' system id and 'pssh' box content for eme playback.
 ///
-/// The data format in 'info' passing to gecko is:
-///   system_id
-///   pssh box size (in native endian)
-///   pssh box content (including header)
+/// The data format of the `info` struct passed to gecko is:
+///
+/// - system id (16 byte uuid)
+/// - pssh box size (32-bit native endian)
+/// - pssh box content (including header)
 #[no_mangle]
 pub unsafe extern fn mp4parse_get_pssh_info(parser: *mut mp4parse_parser, info: *mut mp4parse_pssh_info) -> mp4parse_error {
     if parser.is_null() || info.is_null() || (*parser).poisoned() {
         return MP4PARSE_ERROR_BADARG;
     }
 
     // Initialize fields to default values to ensure all fields are always valid.
     *info = Default::default();
@@ -1098,17 +1106,17 @@ pub unsafe extern fn mp4parse_get_pssh_i
             },
             _ => (),
         }
         pssh_data.extend_from_slice(pssh.system_id.as_slice());
         pssh_data.extend_from_slice(data_len.as_slice());
         pssh_data.extend_from_slice(pssh.box_content.as_slice());
     }
 
-    info.data.set_data(&pssh_data);
+    info.data.set_data(pssh_data);
 
     MP4PARSE_OK
 }
 
 #[cfg(test)]
 extern fn panic_read(_: *mut u8, _: usize, _: *mut std::os::raw::c_void) -> isize {
     panic!("panic_read shouldn't be called in these tests");
 }
--- 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=a422808043e6a21ee98729dd8bfe1e8234897d18
+VER=6cd06d46565f55a8259d4ad7f083c52d6335750f
 
 # Accept version or commit from the command line.
 if test -n "$1"; then
   VER=$1
 fi
 
 echo "Fetching sources..."
 rm -rf _upstream