Bug 1347834 - update rust mp4 parser for audio codec specific data. r=kinetik
MozReview-Commit-ID: 29yu6VsFIE6
--- 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