Skip to content

Commit

Permalink
Bug 1328221 - Support GASpecificConfig audio channel in rust mp4 pars…
Browse files Browse the repository at this point in the history
…er. r=rillian

MozReview-Commit-ID: IQKxtjatU9J
  • Loading branch information
Alfredo.Yang committed Jan 11, 2017
1 parent fe286da commit bd1e86d
Show file tree
Hide file tree
Showing 23 changed files with 457 additions and 235 deletions.
3 changes: 3 additions & 0 deletions media/libstagefright/binding/include/mp4parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ 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.
void mp4parse_log(bool enable);

/// Run the `mp4parse_parser*` allocated by `mp4parse_new()` until EOF or error.
mp4parse_error mp4parse_read(mp4parse_parser* parser);

Expand Down
10 changes: 5 additions & 5 deletions media/libstagefright/binding/mp4parse-cargo.patch
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ index ff9422c..814c4c6 100644
]

[dependencies]
-byteorder = "0.5.0"
-byteorder = "1.0.0"
-afl = { version = "0.1.1", optional = true }
-afl-plugin = { version = "0.1.1", optional = true }
-abort_on_panic = { version = "1.0.0", optional = true }
-bitreader = { version = "0.1.0" }
+byteorder = "0.5.0"
+bitreader = { version = "0.1.0" }
-bitreader = { version = "0.2.0" }
+byteorder = "1.0.0"
+bitreader = { version = "0.2.0" }

[dev-dependencies]
test-assembler = "0.1.2"
Expand All @@ -34,7 +34,7 @@ index aeeebc65..5c0836a 100644
-build = "build.rs"
-
[dependencies]
byteorder = "0.5.0"
byteorder = "1.0.0"
"mp4parse" = {version = "0.6.0", path = "../mp4parse"}

-[build-dependencies]
Expand Down
4 changes: 2 additions & 2 deletions media/libstagefright/binding/mp4parse/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ exclude = [
]

[dependencies]
byteorder = "0.5.0"
bitreader = { version = "0.1.0" }
byteorder = "1.0.0"
bitreader = { version = "0.2.0" }

[dev-dependencies]
test-assembler = "0.1.2"
Expand Down
72 changes: 71 additions & 1 deletion media/libstagefright/binding/mp4parse/src/boxes.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use std::fmt;

macro_rules! box_database {
($($boxenum:ident $boxtype:expr),*,) => {
#[derive(Debug, Clone, Copy, PartialEq)]
#[derive(Clone, Copy, PartialEq)]
pub enum BoxType {
$($boxenum),*,
UnknownBox(u32),
Expand All @@ -19,6 +20,75 @@ macro_rules! box_database {
}
}
}

impl Into<u32> for BoxType {
fn into(self) -> u32 {
use self::BoxType::*;
match self {
$($boxenum => $boxtype),*,
UnknownBox(t) => t,
}
}
}

impl fmt::Debug for BoxType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let fourcc: FourCC = From::from(self.clone());
write!(f, "{}", fourcc)
}
}
}
}

#[derive(Default, PartialEq)]
pub struct FourCC {
pub value: String
}

impl From<u32> for FourCC {
fn from(number: u32) -> FourCC {
let mut box_chars = Vec::new();
for x in 0..4 {
let c = (number >> x * 8 & 0x000000FF) as u8;
box_chars.push(c);
}
box_chars.reverse();

let box_string = match String::from_utf8(box_chars) {
Ok(t) => t,
_ => String::from("null"), // error to retrieve fourcc
};

FourCC {
value: box_string
}
}
}

impl From<BoxType> for FourCC {
fn from(t: BoxType) -> FourCC {
let box_num: u32 = Into::into(t);
From::from(box_num)
}
}

impl<'a> From<&'a str> for FourCC {
fn from(v: &'a str) -> FourCC {
FourCC {
value: v.to_owned()
}
}
}

impl fmt::Debug for FourCC {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}

impl fmt::Display for FourCC {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}

Expand Down
87 changes: 76 additions & 11 deletions media/libstagefright/binding/mp4parse/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::io::Cursor;
use std::cmp;

mod boxes;
use boxes::BoxType;
use boxes::{BoxType, FourCC};

// Unit tests.
#[cfg(test)]
Expand Down Expand Up @@ -106,9 +106,9 @@ struct BoxHeader {
/// File type box 'ftyp'.
#[derive(Debug)]
struct FileTypeBox {
major_brand: u32,
major_brand: FourCC,
minor_version: u32,
compatible_brands: Vec<u32>,
compatible_brands: Vec<FourCC>,
}

/// Movie header box 'mvhd'.
Expand Down Expand Up @@ -196,7 +196,7 @@ struct Sample {
// Handler reference box 'hdlr'
#[derive(Debug)]
struct HandlerBox {
handler_type: u32,
handler_type: FourCC,
}

// Sample description box 'stsd'
Expand Down Expand Up @@ -476,6 +476,15 @@ impl<'a, T: Read> BMFFBox<'a, T> {
}
}

impl<'a, T: Read> Drop for BMFFBox<'a, T> {
fn drop(&mut self) {
if self.content.limit() > 0 {
let name: FourCC = From::from(self.head.name);
log!("Dropping {} bytes in '{}'", self.content.limit(), name);
}
}
}

/// Read and parse a box header.
///
/// Call this first to determine the type of a particular mp4 box
Expand Down Expand Up @@ -793,9 +802,10 @@ fn read_mdia<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
}
BoxType::HandlerBox => {
let hdlr = read_hdlr(&mut b)?;
match hdlr.handler_type {
0x76696465 /* 'vide' */ => track.track_type = TrackType::Video,
0x736f756e /* 'soun' */ => track.track_type = TrackType::Audio,

match hdlr.handler_type.value.as_ref() {
"vide" => track.track_type = TrackType::Video,
"soun" => track.track_type = TrackType::Audio,
_ => (),
}
log!("{:?}", hdlr);
Expand Down Expand Up @@ -874,10 +884,10 @@ fn read_ftyp<T: Read>(src: &mut BMFFBox<T>) -> Result<FileTypeBox> {
let brand_count = bytes_left / 4;
let mut brands = Vec::new();
for _ in 0..brand_count {
brands.push(be_u32(src)?);
brands.push(From::from(be_u32(src)?));
}
Ok(FileTypeBox {
major_brand: major,
major_brand: From::from(major),
minor_version: minor,
compatible_brands: brands,
})
Expand Down Expand Up @@ -1276,7 +1286,52 @@ fn read_ds_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
},
};

let channel_counts: u16 = ReadInto::read(bit_reader, 4)?;
let mut channel_counts: u16 = ReadInto::read(bit_reader, 4)?;

// parsing GASpecificConfig
bit_reader.skip(1)?; // frameLengthFlag
let depend_on_core_order: u8 = ReadInto::read(bit_reader, 1)?;
if depend_on_core_order > 0 {
bit_reader.skip(14)?; // codeCoderDelay
}
bit_reader.skip(1)?; // extensionFlag

// When channel_counts is 0, we need to parse the program_config_element
// to calculate the channel counts.
if channel_counts == 0 {
log!("Parsing program_config_element for channel counts");

bit_reader.skip(4)?; // element_instance_tag
bit_reader.skip(2)?; // object_type
bit_reader.skip(4)?; // sampling_frequency_index
let num_front_channel: u8 = ReadInto::read(bit_reader, 4)?;
let num_side_channel: u8 = ReadInto::read(bit_reader, 4)?;
let num_back_channel:u8 = ReadInto::read(bit_reader, 4)?;
let num_lfe_channel: u8 = ReadInto::read(bit_reader, 2)?;
bit_reader.skip(3)?; // num_assoc_data
bit_reader.skip(4)?; // num_valid_cc

let mono_mixdown_present: bool = ReadInto::read(bit_reader, 1)?;
if mono_mixdown_present {
bit_reader.skip(4)?; // mono_mixdown_element_number
}

let stereo_mixdown_present: bool = ReadInto::read(bit_reader, 1)?;
if stereo_mixdown_present {
bit_reader.skip(4)?; // stereo_mixdown_element_number
}

let matrix_mixdown_idx_present: bool = ReadInto::read(bit_reader, 1)?;
if matrix_mixdown_idx_present {
bit_reader.skip(2)?; // matrix_mixdown_idx
bit_reader.skip(1)?; // pseudo_surround_enable
}

channel_counts += read_surround_channel_count(bit_reader, num_front_channel)?;
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;
Expand All @@ -1285,6 +1340,16 @@ fn read_ds_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
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)?;
count += if is_cpe { 2 } else { 1 };
bit_reader.skip(4)?;
}
Ok(count)
}

fn read_dc_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
let des = &mut Cursor::new(data);
let object_profile = des.read_u8()?;
Expand Down Expand Up @@ -1470,7 +1535,7 @@ fn read_hdlr<T: Read>(src: &mut BMFFBox<T>) -> Result<HandlerBox> {
// Skip uninteresting fields.
skip(src, 4)?;

let handler_type = be_u32(src)?;
let handler_type = FourCC::from(be_u32(src)?);

// Skip uninteresting fields.
skip(src, 12)?;
Expand Down
46 changes: 36 additions & 10 deletions media/libstagefright/binding/mp4parse/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use super::Error;
extern crate test_assembler;
use self::test_assembler::*;

use boxes::BoxType;
use boxes::{BoxType, FourCC};

enum BoxSize {
Short(u32),
Expand Down Expand Up @@ -130,11 +130,11 @@ fn read_ftyp() {
assert_eq!(stream.head.name, BoxType::FileTypeBox);
assert_eq!(stream.head.size, 24);
let parsed = super::read_ftyp(&mut stream).unwrap();
assert_eq!(parsed.major_brand, 0x6d703432); // mp42
assert_eq!(parsed.major_brand, FourCC::from("mp42")); // mp42
assert_eq!(parsed.minor_version, 0);
assert_eq!(parsed.compatible_brands.len(), 2);
assert_eq!(parsed.compatible_brands[0], 0x69736f6d); // isom
assert_eq!(parsed.compatible_brands[1], 0x6d703432); // mp42
assert_eq!(parsed.compatible_brands[0], FourCC::from("isom")); // isom
assert_eq!(parsed.compatible_brands[1], FourCC::from("mp42")); // mp42
}

#[test]
Expand Down Expand Up @@ -172,11 +172,11 @@ fn read_ftyp_case() {
assert_eq!(stream.head.name, BoxType::FileTypeBox);
assert_eq!(stream.head.size, 24);
let parsed = super::read_ftyp(&mut stream).unwrap();
assert_eq!(parsed.major_brand, 0x4d503432);
assert_eq!(parsed.major_brand, FourCC::from("MP42"));
assert_eq!(parsed.minor_version, 0);
assert_eq!(parsed.compatible_brands.len(), 2);
assert_eq!(parsed.compatible_brands[0], 0x49534f4d); // ISOM
assert_eq!(parsed.compatible_brands[1], 0x4d503432); // MP42
assert_eq!(parsed.compatible_brands[0], FourCC::from("ISOM")); // ISOM
assert_eq!(parsed.compatible_brands[1], FourCC::from("MP42")); // MP42
}

#[test]
Expand Down Expand Up @@ -404,7 +404,7 @@ fn read_hdlr() {
assert_eq!(stream.head.name, BoxType::HandlerBox);
assert_eq!(stream.head.size, 45);
let parsed = super::read_hdlr(&mut stream).unwrap();
assert_eq!(parsed.handler_type, 0x76696465); // vide
assert_eq!(parsed.handler_type, FourCC::from("vide"));
}

#[test]
Expand All @@ -422,7 +422,7 @@ fn read_hdlr_short_name() {
assert_eq!(stream.head.name, BoxType::HandlerBox);
assert_eq!(stream.head.size, 33);
let parsed = super::read_hdlr(&mut stream).unwrap();
assert_eq!(parsed.handler_type, 0x76696465); // vide
assert_eq!(parsed.handler_type, FourCC::from("vide"));
}

#[test]
Expand All @@ -439,7 +439,7 @@ fn read_hdlr_zero_length_name() {
assert_eq!(stream.head.name, BoxType::HandlerBox);
assert_eq!(stream.head.size, 32);
let parsed = super::read_hdlr(&mut stream).unwrap();
assert_eq!(parsed.handler_type, 0x76696465); // vide
assert_eq!(parsed.handler_type, FourCC::from("vide"));
}

fn flac_streaminfo() -> Vec<u8> {
Expand Down Expand Up @@ -858,3 +858,29 @@ fn read_qt_wave_atom() {
.expect("fail to read qt wave atom");
assert_eq!(track.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,
0x00, 0x01, 0xf4, 0x00, 0x05, 0x0d, 0x13, 0x00,
0x05, 0x88, 0x05, 0x00, 0x48, 0x21, 0x10, 0x00,
0x56, 0xe5, 0x98, 0x06, 0x01, 0x02,
];
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);
}
2 changes: 1 addition & 1 deletion media/libstagefright/binding/mp4parse_capi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ exclude = [
]

[dependencies]
byteorder = "0.5.0"
byteorder = "1.0.0"
"mp4parse" = {version = "0.6.0", path = "../mp4parse"}

# Somewhat heavy-handed, but we want at least -Z force-overflow-checks=on.
Expand Down
Loading

0 comments on commit bd1e86d

Please sign in to comment.