Bug 1303888 - Update rust mp4parse. r?kinetik draft
authorRalph Giles <giles@mozilla.com>
Tue, 25 Oct 2016 19:25:18 -0700
changeset 429483 7bcf03b9894f99cd0b8cdf3f6fb75fd3d4ee6cab
parent 429408 b1b18f25c0ea69d9ee57c4198d577dfcd0129ce1
child 429484 3259110b024236ce43ddffc7fb8ab19281bddc85
push id33593
push userbmo:giles@thaumas.net
push dateWed, 26 Oct 2016 02:31:05 +0000
reviewerskinetik
bugs1303888
milestone52.0a1
Bug 1303888 - Update rust mp4parse. r?kinetik Update to the latest upstream master, including skipping padding at the end of some boxes, esds parsing and flac support. MozReview-Commit-ID: GdHEQIrtyLB
media/libstagefright/binding/include/mp4parse.h
media/libstagefright/binding/mp4parse/Cargo.toml
media/libstagefright/binding/mp4parse/src/boxes.rs
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/build.rs
media/libstagefright/binding/mp4parse_capi/src/lib.rs
--- a/media/libstagefright/binding/include/mp4parse.h
+++ b/media/libstagefright/binding/include/mp4parse.h
@@ -28,19 +28,21 @@ typedef enum mp4parse_error {
 typedef enum mp4parse_track_type {
 	MP4PARSE_TRACK_TYPE_VIDEO = 0,
 	MP4PARSE_TRACK_TYPE_AUDIO = 1,
 } mp4parse_track_type;
 
 typedef enum mp4parse_codec {
 	MP4PARSE_CODEC_UNKNOWN,
 	MP4PARSE_CODEC_AAC,
+	MP4PARSE_CODEC_FLAC,
 	MP4PARSE_CODEC_OPUS,
 	MP4PARSE_CODEC_AVC,
 	MP4PARSE_CODEC_VP9,
+	MP4PARSE_CODEC_MP3,
 } mp4parse_codec;
 
 typedef struct mp4parse_track_info {
 	mp4parse_track_type track_type;
 	mp4parse_codec codec;
 	uint32_t track_id;
 	uint64_t duration;
 	int64_t media_time;
--- a/media/libstagefright/binding/mp4parse/Cargo.toml
+++ b/media/libstagefright/binding/mp4parse/Cargo.toml
@@ -13,16 +13,16 @@ license = "MPL-2.0"
 repository = "https://github.com/mozilla/mp4parse-rust"
 
 # Avoid complaints about trying to package test files.
 exclude = [
   "*.mp4",
 ]
 
 [dependencies]
-byteorder = { version = "0.5.0" }
+byteorder = "0.5.0"
 
 [dev-dependencies]
 test-assembler = "0.1.2"
 
 # Somewhat heavy-handed, but we want at least -Z force-overflow-checks=on.
 [profile.release]
 debug-assertions = true
--- a/media/libstagefright/binding/mp4parse/src/boxes.rs
+++ b/media/libstagefright/binding/mp4parse/src/boxes.rs
@@ -45,15 +45,18 @@ box_database!(
     AVCSampleEntry             0x61766331, // "avc1"
     AVC3SampleEntry            0x61766333, // "avc3" - Need to check official name in spec.
     AVCConfigurationBox        0x61766343, // "avcC"
     MP4AudioSampleEntry        0x6d703461, // "mp4a"
     ESDBox                     0x65736473, // "esds"
     VP8SampleEntry             0x76703038, // "vp08"
     VP9SampleEntry             0x76703039, // "vp09"
     VPCodecConfigurationBox    0x76706343, // "vpcC"
+    FLACSampleEntry            0x664c6143, // "fLaC"
+    FLACSpecificBox            0x64664c61, // "dfLa"
     OpusSampleEntry            0x4f707573, // "Opus"
     OpusSpecificBox            0x644f7073, // "dOps"
     ProtectedVisualSampleEntry 0x656e6376, // "encv" - Need to check official name in spec.
     ProtectedAudioSampleEntry  0x656e6361, // "enca" - Need to check official name in spec.
     MovieExtendsBox            0x6d766578, // "mvex"
     MovieExtendsHeaderBox      0x6d656864, // "mehd"
+    QTWaveAtom                 0x77617665, // "wave" - quicktime atom
 );
--- a/media/libstagefright/binding/mp4parse/src/lib.rs
+++ b/media/libstagefright/binding/mp4parse/src/lib.rs
@@ -6,16 +6,17 @@
 #![cfg_attr(feature = "fuzz", feature(plugin))]
 #![cfg_attr(feature = "fuzz", plugin(afl_plugin))]
 #[cfg(feature = "fuzz")]
 extern crate afl;
 
 extern crate byteorder;
 use byteorder::ReadBytesExt;
 use std::io::{Read, Take};
+use std::io::Cursor;
 use std::cmp;
 
 mod boxes;
 use boxes::BoxType;
 
 // Unit tests.
 #[cfg(test)]
 mod tests;
@@ -200,18 +201,27 @@ struct SampleDescriptionBox {
 pub enum SampleEntry {
     Audio(AudioSampleEntry),
     Video(VideoSampleEntry),
     Unknown,
 }
 
 #[allow(non_camel_case_types)]
 #[derive(Debug, Clone)]
+pub struct ES_Descriptor {
+    pub audio_codec: CodecType,
+    pub audio_sample_rate: Option<u32>,
+    pub codec_specific_config: Vec<u8>,
+}
+
+#[allow(non_camel_case_types)]
+#[derive(Debug, Clone)]
 pub enum AudioCodecSpecific {
-    ES_Descriptor(Vec<u8>),
+    ES_Descriptor(ES_Descriptor),
+    FLACSpecificBox(FLACSpecificBox),
     OpusSpecificBox(OpusSpecificBox),
 }
 
 #[derive(Debug, Clone)]
 pub struct AudioSampleEntry {
     data_reference_index: u16,
     pub channelcount: u16,
     pub samplesize: u16,
@@ -242,16 +252,29 @@ pub struct VPxConfigBox {
     pub color_space: u8, // Really an enum
     pub chroma_subsampling: u8,
     transfer_function: u8,
     video_full_range: bool,
     pub codec_init: Vec<u8>, // Empty for vp8/vp9.
 }
 
 #[derive(Debug, Clone)]
+pub struct FLACMetadataBlock {
+    pub block_type: u8,
+    pub data: Vec<u8>,
+}
+
+/// Represet a FLACSpecificBox 'dfLa'
+#[derive(Debug, Clone)]
+pub struct FLACSpecificBox {
+    version: u8,
+    pub blocks: Vec<FLACMetadataBlock>,
+}
+
+#[derive(Debug, Clone)]
 struct ChannelMappingTable {
     stream_count: u8,
     coupled_count: u8,
     channel_mapping: Vec<u8>,
 }
 
 /// Represent an OpusSpecificBox 'dOps'
 #[derive(Debug, Clone)]
@@ -280,31 +303,33 @@ pub struct MediaContext {
 }
 
 impl MediaContext {
     pub fn new() -> MediaContext {
         Default::default()
     }
 }
 
-#[derive(Debug)]
+#[derive(Debug, PartialEq)]
 pub enum TrackType {
     Audio,
     Video,
     Unknown,
 }
 
 impl Default for TrackType {
     fn default() -> Self { TrackType::Unknown }
 }
 
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy, PartialEq)]
 pub enum CodecType {
     Unknown,
+    MP3,
     AAC,
+    FLAC,
     Opus,
     H264,
     VP9,
     VP8,
     EncryptedVideo,
     EncryptedAudio,
 }
 
@@ -464,16 +489,27 @@ fn skip_box_content<T: Read>(src: &mut B
         let header = src.get_header();
         log!("{:?} (skipped)", header);
         (header.size - header.offset) as usize
     };
     assert!(to_skip == src.bytes_left());
     skip(src, to_skip)
 }
 
+/// Skip over the remain data of a box.
+fn skip_box_remain<T: Read>(src: &mut BMFFBox<T>) -> Result<()> {
+    let remain = {
+        let header = src.get_header();
+        let len = src.bytes_left();
+        log!("remain {} (skipped) in {:?}", len, header);
+        len
+    };
+    skip(src, remain)
+}
+
 macro_rules! check_parser_state {
     ( $src:expr ) => {
         if $src.limit() > 0 {
             log!("bad parser state: {} content bytes left", $src.limit());
             return Err(Error::InvalidData("unread box content or bad parser sync"));
         }
     }
 }
@@ -916,44 +952,53 @@ fn read_mdhd<T: Read>(src: &mut BMFFBox<
 fn read_stco<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
     let (_, _) = try!(read_fullbox_extra(src));
     let offset_count = try!(be_u32(src));
     let mut offsets = Vec::new();
     for _ in 0..offset_count {
         offsets.push(try!(be_u32(src)) as u64);
     }
 
+    // Padding could be added in some contents.
+    try!(skip_box_remain(src));
+
     Ok(ChunkOffsetBox {
         offsets: offsets,
     })
 }
 
 /// Parse a co64 box.
 fn read_co64<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
     let (_, _) = try!(read_fullbox_extra(src));
     let offset_count = try!(be_u32(src));
     let mut offsets = Vec::new();
     for _ in 0..offset_count {
         offsets.push(try!(be_u64(src)));
     }
 
+    // Padding could be added in some contents.
+    try!(skip_box_remain(src));
+
     Ok(ChunkOffsetBox {
         offsets: offsets,
     })
 }
 
 /// Parse a stss box.
 fn read_stss<T: Read>(src: &mut BMFFBox<T>) -> Result<SyncSampleBox> {
     let (_, _) = try!(read_fullbox_extra(src));
     let sample_count = try!(be_u32(src));
     let mut samples = Vec::new();
     for _ in 0..sample_count {
         samples.push(try!(be_u32(src)));
     }
 
+    // Padding could be added in some contents.
+    try!(skip_box_remain(src));
+
     Ok(SyncSampleBox {
         samples: samples,
     })
 }
 
 /// Parse a stsc box.
 fn read_stsc<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleToChunkBox> {
     let (_, _) = try!(read_fullbox_extra(src));
@@ -965,16 +1010,19 @@ fn read_stsc<T: Read>(src: &mut BMFFBox<
         let sample_description_index = try!(be_u32(src));
         samples.push(SampleToChunk {
             first_chunk: first_chunk,
             samples_per_chunk: samples_per_chunk,
             sample_description_index: sample_description_index,
         });
     }
 
+    // Padding could be added in some contents.
+    try!(skip_box_remain(src));
+
     Ok(SampleToChunkBox {
         samples: samples,
     })
 }
 
 /// Parse a stsz box.
 fn read_stsz<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleSizeBox> {
     let (_, _) = try!(read_fullbox_extra(src));
@@ -982,16 +1030,19 @@ fn read_stsz<T: Read>(src: &mut BMFFBox<
     let sample_count = try!(be_u32(src));
     let mut sample_sizes = Vec::new();
     if sample_size == 0 {
         for _ in 0..sample_count {
             sample_sizes.push(try!(be_u32(src)));
         }
     }
 
+    // Padding could be added in some contents.
+    try!(skip_box_remain(src));
+
     Ok(SampleSizeBox {
         sample_size: sample_size,
         sample_sizes: sample_sizes,
     })
 }
 
 /// Parse a stts box.
 fn read_stts<T: Read>(src: &mut BMFFBox<T>) -> Result<TimeToSampleBox> {
@@ -1002,16 +1053,19 @@ fn read_stts<T: Read>(src: &mut BMFFBox<
         let sample_count = try!(be_u32(src));
         let sample_delta = try!(be_u32(src));
         samples.push(Sample {
             sample_count: sample_count,
             sample_delta: sample_delta,
         });
     }
 
+    // Padding could be added in some contents.
+    try!(skip_box_remain(src));
+
     Ok(TimeToSampleBox {
         samples: samples,
     })
 }
 
 /// Parse a VPx Config Box.
 fn read_vpcc<T: Read>(src: &mut BMFFBox<T>) -> Result<VPxConfigBox> {
     let (version, _) = try!(read_fullbox_extra(src));
@@ -1041,21 +1095,187 @@ fn read_vpcc<T: Read>(src: &mut BMFFBox<
         color_space: color_space,
         chroma_subsampling: chroma_subsampling,
         transfer_function: transfer_function,
         video_full_range: video_full_range,
         codec_init: codec_init,
     })
 }
 
+fn read_flac_metadata<T: Read>(src: &mut BMFFBox<T>) -> Result<FLACMetadataBlock> {
+    let temp = try!(src.read_u8());
+    let block_type = temp & 0x7f;
+    let length = try!(be_u24(src));
+    if length as usize > src.bytes_left() {
+        return Err(Error::InvalidData(
+                "FLACMetadataBlock larger than parent box"));
+    }
+    let data = try!(read_buf(src, length as usize));
+    Ok(FLACMetadataBlock {
+        block_type: block_type,
+        data: data,
+    })
+}
+
+fn read_esds<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
+    // Tags for elementary stream description
+    const ESDESCR_TAG: u8          = 0x03;
+    const DECODER_CONFIG_TAG: u8   = 0x04;
+    const DECODER_SPECIFIC_TAG: u8 = 0x05;
+
+    let frequency_table =
+        vec![(0x1, 96000), (0x1, 88200), (0x2, 64000), (0x3, 48000),
+             (0x4, 44100), (0x5, 32000), (0x6, 24000), (0x7, 22050),
+             (0x8, 16000), (0x9, 12000), (0xa, 11025), (0xb, 8000),
+             (0xc, 7350)];
+
+    let (_, _) = try!(read_fullbox_extra(src));
+
+    let esds_size = src.head.size - src.head.offset - 4;
+    if esds_size > BUF_SIZE_LIMIT {
+        return Err(Error::InvalidData("esds box exceeds BUF_SIZE_LIMIT"));
+    }
+    let esds_array = try!(read_buf(src, esds_size as usize));
+
+    // Parsing DecoderConfig descriptor to get the object_profile_indicator
+    // for correct codec type and audio sample rate.
+    let (object_profile_indicator, sample_frequency) = {
+        let mut object_profile: u8 = 0;
+        let mut sample_frequency = None;
+
+        // clone a esds cursor for parsing.
+        let esds = &mut Cursor::new(&esds_array);
+        let next_tag = try!(esds.read_u8());
+
+        if next_tag != ESDESCR_TAG {
+            return Err(Error::Unsupported("fail to parse ES descriptor"));
+        }
+
+        let esds_extend = try!(esds.read_u8());
+        // extension tag start from 0x80.
+        let esds_end = if esds_extend >= 0x80 {
+            // skip remaining extension.
+            try!(skip(esds, 2));
+            esds.position() + try!(esds.read_u8()) as u64
+        } else {
+            esds.position() + esds_extend as u64
+        };
+        try!(skip(esds, 2));
+
+        let esds_flags = try!(esds.read_u8());
+
+        // Stream dependency flag, first bit from left most.
+        if esds_flags & 0x80 > 0 {
+            // Skip uninteresting fields.
+            try!(skip(esds, 2));
+        }
+
+        // Url flag, second bit from left most.
+        if esds_flags & 0x40 > 0 {
+            // Skip uninteresting fields.
+            let skip_es_len: usize = try!(esds.read_u8()) as usize + 2;
+            try!(skip(esds, skip_es_len));
+        }
+
+        // find DecoderConfig descriptor (tag = DECODER_CONFIG_TAG)
+        if esds_end > esds.position() {
+            let next_tag = try!(esds.read_u8());
+            if next_tag == DECODER_CONFIG_TAG {
+                let dcds_extend = try!(esds.read_u8());
+                // extension tag start from 0x80.
+                if dcds_extend >= 0x80 {
+                    // skip remains extension and length.
+                    try!(skip(esds, 3));
+                }
+
+                object_profile = try!(esds.read_u8());
+
+                // Skip uninteresting fields.
+                try!(skip(esds, 12));
+            }
+        }
+
+
+        // find DecoderSpecific descriptor (tag = DECODER_SPECIFIC_TAG)
+        if esds_end > esds.position() {
+            let next_tag = try!(esds.read_u8());
+            if next_tag == DECODER_SPECIFIC_TAG {
+                let dsds_extend = try!(esds.read_u8());
+                // extension tag start from 0x80.
+                if dsds_extend >= 0x80 {
+                    // skip remains extension and length.
+                    try!(skip(esds, 3));
+                }
+
+                let audio_specific_config = try!(be_u16(esds));
+
+                let sample_index = (audio_specific_config & 0x07FF) >> 7;
+
+                sample_frequency =
+                    frequency_table.iter().find(|item| item.0 == sample_index).map(|x| x.1);
+            }
+        }
+
+        (object_profile, sample_frequency)
+    };
+
+    let codec = match object_profile_indicator {
+        0x40 | 0x41 => CodecType::AAC,
+        0x6B => CodecType::MP3,
+        _ => CodecType::Unknown,
+    };
+
+    if codec == CodecType::Unknown {
+        return Err(Error::Unsupported("unknown audio codec"));
+    }
+
+    Ok(ES_Descriptor {
+        audio_codec: codec,
+        audio_sample_rate: sample_frequency,
+        codec_specific_config: esds_array,
+    })
+}
+
+/// Parse `FLACSpecificBox`.
+fn read_dfla<T: Read>(src: &mut BMFFBox<T>) -> Result<FLACSpecificBox> {
+    let (version, flags) = try!(read_fullbox_extra(src));
+    if version != 0 {
+        return Err(Error::Unsupported("unknown dfLa (FLAC) version"));
+    }
+    if flags != 0 {
+        return Err(Error::InvalidData("no-zero dfLa (FLAC) flags"));
+    }
+    let mut blocks = Vec::new();
+    while src.bytes_left() > 0 {
+        let block = try!(read_flac_metadata(src));
+        blocks.push(block);
+    }
+    // The box must have at least one meta block, and the first block
+    // must be the METADATA_BLOCK_STREAMINFO
+    if blocks.is_empty() {
+        return Err(Error::InvalidData("FLACSpecificBox missing metadata"));
+    } else if blocks[0].block_type != 0 {
+        println!("flac metadata block:\n  {:?}", blocks[0]);
+        return Err(Error::InvalidData(
+                "FLACSpecificBox must have STREAMINFO metadata first"));
+    } else if blocks[0].data.len() != 34 {
+        return Err(Error::InvalidData(
+                "FLACSpecificBox STREAMINFO block is the wrong size"));
+    }
+    Ok(FLACSpecificBox {
+        version: version,
+        blocks: blocks,
+    })
+}
+
 /// Parse `OpusSpecificBox`.
 fn read_dops<T: Read>(src: &mut BMFFBox<T>) -> Result<OpusSpecificBox> {
     let version = try!(src.read_u8());
     if version != 0 {
-        return Err(Error::Unsupported("unknown dOps version"));
+        return Err(Error::Unsupported("unknown dOps (Opus) version"));
     }
 
     let output_channel_count = try!(src.read_u8());
     let pre_skip = try!(be_u16(src));
     let input_sample_rate = try!(be_u32(src));
     let output_gain = try!(be_i16(src));
     let channel_mapping_family = try!(src.read_u8());
 
@@ -1144,17 +1364,17 @@ fn read_hdlr<T: Read>(src: &mut BMFFBox<
     let _name = try!(read_null_terminated_string(src, bytes_left));
 
     Ok(HandlerBox {
         handler_type: handler_type,
     })
 }
 
 /// Parse an video description inside an stsd box.
-fn read_video_desc<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) -> Result<SampleEntry> {
+fn read_video_sample_entry<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) -> Result<SampleEntry> {
     let name = src.get_header().name;
     track.codec_type = match name {
         BoxType::AVCSampleEntry | BoxType::AVC3SampleEntry => CodecType::H264,
         BoxType::VP8SampleEntry => CodecType::VP8,
         BoxType::VP9SampleEntry => CodecType::VP9,
         BoxType::ProtectedVisualSampleEntry => CodecType::EncryptedVideo,
         _ => CodecType::Unknown,
     };
@@ -1217,22 +1437,39 @@ fn read_video_desc<T: Read>(src: &mut BM
             data_reference_index: data_reference_index,
             width: width,
             height: height,
             codec_specific: codec_specific,
         }))
         .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) = try!(iter.next_box()) {
+        match b.head.name {
+            BoxType::ESDBox => {
+                let esds = try!(read_esds(&mut b));
+                codec_specific = Some(esds);
+            },
+            _ => try!(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_desc<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) -> Result<SampleEntry> {
+fn read_audio_sample_entry<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) -> Result<SampleEntry> {
     let name = src.get_header().name;
     track.codec_type = match name {
         // TODO(kinetik): stagefright inspects ESDS to detect MP3 (audio/mpeg).
         BoxType::MP4AudioSampleEntry => CodecType::AAC,
+        BoxType::FLACSampleEntry => CodecType::FLAC,
         BoxType::OpusSampleEntry => CodecType::Opus,
         BoxType::ProtectedAudioSampleEntry => CodecType::EncryptedAudio,
         _ => CodecType::Unknown,
     };
 
     // Skip uninteresting fields.
     try!(skip(src, 6));
 
@@ -1252,47 +1489,63 @@ fn read_audio_desc<T: Read>(src: &mut BM
 
     // Skip uninteresting fields.
     try!(skip(src, 4));
 
     let samplerate = try!(be_u32(src));
 
     match version {
         0 => (),
+        1 => {
+            // Quicktime sound sample description version 1.
+            // Skip uninteresting fields.
+            try!(skip(src, 16));
+        },
         _ => return Err(Error::Unsupported("unsupported non-isom audio sample entry")),
     }
 
     // Skip chan/etc. for now.
     let mut codec_specific = None;
     let mut iter = src.box_iter();
     while let Some(mut b) = try!(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 (_, _) = try!(read_fullbox_extra(&mut b.content));
-                let esds_size = b.head.size - b.head.offset - 4;
-                if esds_size > BUF_SIZE_LIMIT {
-                    return Err(Error::InvalidData("esds box exceeds BUF_SIZE_LIMIT"));
                 }
-                let esds = try!(read_buf(&mut b.content, esds_size as usize));
-                // TODO(kinetik): Parse esds box?  For now we just stash the data.
+
+                let esds = try!(read_esds(&mut b));
+                track.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 = try!(read_dfla(&mut b));
+                track.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 = try!(read_dops(&mut b));
+                track.codec_type = CodecType::Opus;
                 codec_specific = Some(AudioCodecSpecific::OpusSpecificBox(dops));
             }
+            BoxType::QTWaveAtom => {
+                let qt_esds = try!(read_qt_wave_atom(&mut b));
+                track.codec_type = qt_esds.audio_codec;
+                codec_specific = Some(AudioCodecSpecific::ES_Descriptor(qt_esds));
+            }
             _ => try!(skip_box_content(&mut b)),
         }
         check_parser_state!(b.content);
     }
 
     codec_specific
         .map(|codec_specific| SampleEntry::Audio(AudioSampleEntry {
             data_reference_index: data_reference_index,
@@ -1306,48 +1559,53 @@ fn read_audio_desc<T: Read>(src: &mut BM
 
 /// Parse a stsd box.
 fn read_stsd<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) -> Result<SampleDescriptionBox> {
     let (_, _) = try!(read_fullbox_extra(src));
 
     let description_count = try!(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) = try!(iter.next_box()) {
-        let description = match track.track_type {
-            TrackType::Video => read_video_desc(&mut b, track),
-            TrackType::Audio => read_audio_desc(&mut b, track),
-            TrackType::Unknown => Err(Error::Unsupported("unknown track type")),
-        };
-        let description = match description {
-            Ok(desc) => 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();
-                try!(skip(&mut b, to_skip));
-                SampleEntry::Unknown
+    {
+        // 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) = try!(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::Unknown => Err(Error::Unsupported("unknown track type")),
+            };
+            let description = match description {
+                Ok(desc) => 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();
+                    try!(skip(&mut b, to_skip));
+                    SampleEntry::Unknown
+                }
+                Err(e) => return Err(e),
+            };
+            if track.data.is_none() {
+                track.data = Some(description.clone());
+            } else {
+                log!("** don't know how to handle multiple descriptions **");
             }
-            Err(e) => return Err(e),
-        };
-        if track.data.is_none() {
-            track.data = Some(description.clone());
-        } else {
-            log!("** don't know how to handle multiple descriptions **");
-        }
-        descriptions.push(description);
-        check_parser_state!(b.content);
-        if descriptions.len() == description_count as usize {
-            break;
+            descriptions.push(description);
+            check_parser_state!(b.content);
+            if descriptions.len() == description_count as usize {
+                break;
+            }
         }
     }
 
+    // Padding could be added in some contents.
+    try!(skip_box_remain(src));
+
     Ok(SampleDescriptionBox {
         descriptions: descriptions,
     })
 }
 
 /// Skip a number of bytes that we don't care to parse.
 fn skip<T: Read>(src: &mut T, mut bytes: usize) -> Result<()> {
     const BUF_SIZE: usize = 64 * 1024;
@@ -1419,15 +1677,21 @@ fn be_i32<T: ReadBytesExt>(src: &mut T) 
 fn be_i64<T: ReadBytesExt>(src: &mut T) -> Result<i64> {
     src.read_i64::<byteorder::BigEndian>().map_err(From::from)
 }
 
 fn be_u16<T: ReadBytesExt>(src: &mut T) -> Result<u16> {
     src.read_u16::<byteorder::BigEndian>().map_err(From::from)
 }
 
+fn be_u24<T: ReadBytesExt>(src: &mut T) -> Result<u32> {
+    src.read_uint::<byteorder::BigEndian>(3)
+        .map(|v| v as u32)
+        .map_err(From::from)
+}
+
 fn be_u32<T: ReadBytesExt>(src: &mut T) -> Result<u32> {
     src.read_u32::<byteorder::BigEndian>().map_err(From::from)
 }
 
 fn be_u64<T: ReadBytesExt>(src: &mut T) -> Result<u64> {
     src.read_u64::<byteorder::BigEndian>().map_err(From::from)
 }
--- a/media/libstagefright/binding/mp4parse/src/tests.rs
+++ b/media/libstagefright/binding/mp4parse/src/tests.rs
@@ -437,16 +437,112 @@ fn read_hdlr_zero_length_name() {
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     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
 }
 
+fn flac_streaminfo() -> Vec<u8> {
+    vec![
+        0x10, 0x00, 0x10, 0x00, 0x00, 0x0a, 0x11, 0x00,
+        0x38, 0x32, 0x0a, 0xc4, 0x42, 0xf0, 0x00, 0xc9,
+        0xdf, 0xae, 0xb5, 0x66, 0xfc, 0x02, 0x15, 0xa3,
+        0xb1, 0x54, 0x61, 0x47, 0x0f, 0xfb, 0x05, 0x00,
+        0x33, 0xad,
+    ]
+}
+
+#[test]
+fn read_flac() {
+    let mut stream = make_box(BoxSize::Auto, b"fLaC", |s| {
+        s.append_repeated(0, 6) // reserved
+         .B16(1) // data reference index
+         .B32(0) // reserved
+         .B32(0) // reserved
+         .B16(2) // channel count
+         .B16(16) // bits per sample
+         .B16(0) // pre_defined
+         .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();
+}
+
+#[derive(Clone, Copy)]
+enum FlacBlockType {
+    StreamInfo = 0,
+    _Padding = 1,
+    _Application = 2,
+    _Seektable = 3,
+    _Comment = 4,
+    _Cuesheet = 5,
+    _Picture = 6,
+    _Reserved,
+    _Invalid = 127,
+}
+
+enum FlacBlockLength {
+    Correct,
+    Incorrect(usize),
+}
+
+fn make_dfla(block_type: FlacBlockType, last: bool, data: &Vec<u8>,
+             data_length: FlacBlockLength) -> Cursor<Vec<u8>> {
+    assert!(data.len() < 1<<24);
+    make_fullbox(BoxSize::Auto, b"dfLa", 0, |s| {
+        let flag = match last {
+            true => 1,
+            false => 0,
+        };
+        let size = match data_length {
+            FlacBlockLength::Correct => (data.len() as u32) & 0xffffff,
+            FlacBlockLength::Incorrect(size) => {
+                assert!(size < 1<<24);
+                (size as u32) & 0xffffff
+            }
+        };
+        let block_type = (block_type as u32) & 0x7f;
+        s.B32(flag << 31 | block_type << 24 | size)
+         .append_bytes(data)
+    })
+}
+
+#[test]
+fn read_dfla() {
+    let mut stream = make_dfla(FlacBlockType::StreamInfo, true,
+                               &flac_streaminfo(), FlacBlockLength::Correct);
+    let mut iter = super::BoxIter::new(&mut stream);
+    let mut stream = iter.next_box().unwrap().unwrap();
+    assert_eq!(stream.head.name, BoxType::FLACSpecificBox);
+    let dfla = super::read_dfla(&mut stream).unwrap();
+    assert_eq!(dfla.version, 0);
+}
+
+#[test]
+fn long_flac_metadata() {
+    let streaminfo = flac_streaminfo();
+    let mut stream = make_dfla(FlacBlockType::StreamInfo, true,
+                               &streaminfo,
+                               FlacBlockLength::Incorrect(streaminfo.len() + 4));
+    let mut iter = super::BoxIter::new(&mut stream);
+    let mut stream = iter.next_box().unwrap().unwrap();
+    assert_eq!(stream.head.name, BoxType::FLACSpecificBox);
+    let r = super::read_dfla(&mut stream);
+    assert!(r.is_err());
+}
+
 #[test]
 fn read_opus() {
     let mut stream = make_box(BoxSize::Auto, b"Opus", |s| {
         s.append_repeated(0, 6)
          .B16(1) // data reference index
          .B32(0)
          .B32(0)
          .B16(2) // channel count
@@ -454,17 +550,17 @@ fn read_opus() {
          .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_desc(&mut stream, &mut track);
+    let r = super::read_audio_sample_entry(&mut stream, &mut track);
     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
@@ -542,17 +638,17 @@ fn avcc_limit() {
          .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_desc(&mut stream, &mut track) {
+    match super::read_video_sample_entry(&mut stream, &mut track) {
         Err(Error::InvalidData(s)) => assert_eq!(s, "avcC box exceeds BUF_SIZE_LIMIT"),
         Ok(_) => assert!(false, "expected an error result"),
         _ => assert!(false, "expected a different error result"),
     }
 }
 
 #[test]
 fn esds_limit() {
@@ -568,17 +664,17 @@ fn esds_limit() {
          .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_desc(&mut stream, &mut track) {
+    match super::read_audio_sample_entry(&mut stream, &mut track) {
         Err(Error::InvalidData(s)) => assert_eq!(s, "esds box exceeds BUF_SIZE_LIMIT"),
         Ok(_) => assert!(false, "expected an error result"),
         _ => assert!(false, "expected a different error result"),
     }
 }
 
 #[test]
 fn esds_limit_2() {
@@ -594,17 +690,17 @@ fn esds_limit_2() {
          .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_desc(&mut stream, &mut track) {
+    match super::read_audio_sample_entry(&mut stream, &mut track) {
         Err(Error::UnexpectedEOF) => (),
         Ok(_) => assert!(false, "expected an error result"),
         _ => assert!(false, "expected a different error result"),
     }
 }
 
 #[test]
 fn read_elst_zero_entries() {
@@ -656,8 +752,109 @@ fn invalid_pascal_string() {
     // the 1 byte length prefix).
     let pstr = "\x20xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
     let mut stream = Cursor::new(pstr);
     // Reader wants to limit the total read length to 32 bytes, so any
     // returned string must be no longer than 31 bytes.
     let s = super::read_fixed_length_pascal_string(&mut stream, 32).unwrap();
     assert_eq!(s.len(), 31);
 }
+
+#[test]
+fn skip_padding_in_boxes() {
+    // Padding data could be added in the end of these boxes. Parser needs to skip
+    // them instead of returning error.
+    let box_names = vec![b"stts", b"stsc", b"stsz", b"stco", b"co64", b"stss"];
+
+    for name in box_names {
+        let mut stream = make_fullbox(BoxSize::Auto, name, 1, |s| {
+            s.append_repeated(0, 100) // add padding data
+        });
+        let mut iter = super::BoxIter::new(&mut stream);
+        let mut stream = iter.next_box().unwrap().unwrap();
+        match name {
+            b"stts" => {
+                super::read_stts(&mut stream).expect("fail to skip padding: stts");
+            },
+            b"stsc" => {
+                super::read_stsc(&mut stream).expect("fail to skip padding: stsc");
+            },
+            b"stsz" => {
+                super::read_stsz(&mut stream).expect("fail to skip padding: stsz");
+            },
+            b"stco" => {
+                super::read_stco(&mut stream).expect("fail to skip padding: stco");
+            },
+            b"co64" => {
+                super::read_co64(&mut stream).expect("fail to skip padding: co64");
+            },
+            b"stss" => {
+                super::read_stss(&mut stream).expect("fail to skip padding: stss");
+            },
+            _ => (),
+        }
+    }
+}
+
+#[test]
+fn skip_padding_in_stsd() {
+    // Padding data could be added in the end of stsd boxes. Parser needs to skip
+    // them instead of returning error.
+    let avc = make_box(BoxSize::Auto, b"avc1", |s| {
+        s.append_repeated(0, 6)
+         .B16(1)
+         .append_repeated(0, 16)
+         .B16(320)
+         .B16(240)
+         .append_repeated(0, 14)
+         .append_repeated(0, 32)
+         .append_repeated(0, 4)
+         .B32(0xffffffff)
+         .append_bytes(b"avcC")
+         .append_repeated(0, 100)
+    }).into_inner();
+    let mut stream = make_fullbox(BoxSize::Auto, b"stsd", 0, |s| {
+        s.B32(1)
+         .append_bytes(avc.as_slice())
+         .append_repeated(0, 100) // add padding data
+    });
+
+    let mut iter = super::BoxIter::new(&mut stream);
+    let mut stream = iter.next_box().unwrap().unwrap();
+    super::read_stsd(&mut stream, &mut super::Track::new(0))
+          .expect("fail to skip padding: stsd");
+}
+
+#[test]
+fn read_qt_wave_atom() {
+    let esds = make_fullbox(BoxSize::Auto, b"esds", 0, |s| {
+        s.B8(0x03)  // elementary stream descriptor tag
+         .B8(0x0b)  // esds length
+         .append_repeated(0, 2)
+         .B8(0x00)  // flags
+         .B8(0x04)  // decoder config descriptor tag
+         .B8(0x0d)  // dcds length
+         .B8(0x6b)  // mp3
+         .append_repeated(0, 12)
+    }).into_inner();
+    let wave = make_box(BoxSize::Auto, b"wave", |s| {
+        s.append_bytes(esds.as_slice())
+    }).into_inner();
+    let mut stream = make_box(BoxSize::Auto, b"mp4a", |s| {
+        s.append_repeated(0, 6)
+         .B16(1)    // data_reference_count
+         .B16(1)    // verion: qt -> 1
+         .append_repeated(0, 6)
+         .B16(2)
+         .B16(16)
+         .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)
+          .expect("fail to read qt wave atom");
+    assert_eq!(track.codec_type, super::CodecType::MP3);
+}
--- a/media/libstagefright/binding/mp4parse/tests/public.rs
+++ b/media/libstagefright/binding/mp4parse/tests/public.rs
@@ -65,20 +65,28 @@ fn public_api() {
                 let tkhd = track.tkhd.unwrap();
                 assert_eq!(tkhd.disabled, false);
                 assert_eq!(tkhd.duration, 62);
                 assert_eq!(tkhd.width, 0);
                 assert_eq!(tkhd.height, 0);
 
                 // track.data part
                 assert_eq!(match a.codec_specific {
-                    mp4::AudioCodecSpecific::ES_Descriptor(v) => {
-                        assert!(v.len() > 0);
+                    mp4::AudioCodecSpecific::ES_Descriptor(esds) => {
+                        assert_eq!(esds.audio_codec, mp4::CodecType::AAC);
+                        assert_eq!(esds.audio_sample_rate.unwrap(), 48000);
                         "ES"
                     }
+                    mp4::AudioCodecSpecific::FLACSpecificBox(flac) => {
+                        // STREAMINFO block must be present and first.
+                        assert!(flac.blocks.len() > 0);
+                        assert!(flac.blocks[0].block_type == 0);
+                        assert!(flac.blocks[0].data.len() == 34);
+                        "FLAC"
+                    }
                     mp4::AudioCodecSpecific::OpusSpecificBox(opus) => {
                         // We don't enter in here, we just check if fields are public.
                         assert!(opus.version > 0);
                         "Opus"
                     }
                 }, "ES");
                 assert!(a.samplesize > 0);
                 assert!(a.samplerate > 0);
--- a/media/libstagefright/binding/mp4parse_capi/build.rs
+++ b/media/libstagefright/binding/mp4parse_capi/build.rs
@@ -1,11 +1,12 @@
 extern crate cheddar;
 
 fn main() {
+    println!("cargo:rerun-if-changed=src/lib.rs");
     // Generate mp4parse.h.
     cheddar::Cheddar::new().expect("could not read manifest")
         .insert_code("// THIS FILE IS AUTOGENERATED BY mp4parse-rust/build.rs - DO NOT EDIT\n\n")
         .insert_code("// This Source Code Form is subject to the terms of the Mozilla Public\n")
         .insert_code("// License, v. 2.0. If a copy of the MPL was not distributed with this\n")
         .insert_code("// file, You can obtain one at https://mozilla.org/MPL/2.0/.")
         .run_build("include/mp4parse.h");
 }
--- a/media/libstagefright/binding/mp4parse_capi/src/lib.rs
+++ b/media/libstagefright/binding/mp4parse_capi/src/lib.rs
@@ -47,16 +47,17 @@ use mp4parse::Error;
 use mp4parse::SampleEntry;
 use mp4parse::AudioCodecSpecific;
 use mp4parse::VideoCodecSpecific;
 use mp4parse::MediaTimeScale;
 use mp4parse::MediaScaledTime;
 use mp4parse::TrackTimeScale;
 use mp4parse::TrackScaledTime;
 use mp4parse::serialize_opus_header;
+use mp4parse::CodecType;
 
 // rusty-cheddar's C enum generation doesn't namespace enum members by
 // prefixing them, so we're forced to do it in our member names until
 // https://github.com/Sean1708/rusty-cheddar/pull/35 is fixed.  Importing
 // the members into the module namespace avoids doubling up on the
 // namespacing on the Rust side.
 use mp4parse_error::*;
 use mp4parse_track_type::*;
@@ -79,19 +80,21 @@ pub enum mp4parse_track_type {
     MP4PARSE_TRACK_TYPE_AUDIO = 1,
 }
 
 #[repr(C)]
 #[derive(PartialEq, Debug)]
 pub enum mp4parse_codec {
     MP4PARSE_CODEC_UNKNOWN,
     MP4PARSE_CODEC_AAC,
+    MP4PARSE_CODEC_FLAC,
     MP4PARSE_CODEC_OPUS,
     MP4PARSE_CODEC_AVC,
     MP4PARSE_CODEC_VP9,
+    MP4PARSE_CODEC_MP3,
 }
 
 #[repr(C)]
 pub struct mp4parse_track_info {
     pub track_type: mp4parse_track_type,
     pub codec: mp4parse_codec,
     pub track_id: u32,
     pub duration: u64,
@@ -337,52 +340,61 @@ pub unsafe extern fn mp4parse_get_track_
         TrackType::Audio => MP4PARSE_TRACK_TYPE_AUDIO,
         TrackType::Unknown => return MP4PARSE_ERROR_UNSUPPORTED,
     };
 
     info.codec = match context.tracks[track_index].data {
         Some(SampleEntry::Audio(ref audio)) => match audio.codec_specific {
             AudioCodecSpecific::OpusSpecificBox(_) =>
                 mp4parse_codec::MP4PARSE_CODEC_OPUS,
+            AudioCodecSpecific::FLACSpecificBox(_) =>
+                mp4parse_codec::MP4PARSE_CODEC_FLAC,
+            AudioCodecSpecific::ES_Descriptor(ref esds) if esds.audio_codec == CodecType::AAC =>
+                mp4parse_codec::MP4PARSE_CODEC_AAC,
+            AudioCodecSpecific::ES_Descriptor(ref esds) if esds.audio_codec == CodecType::MP3 =>
+                mp4parse_codec::MP4PARSE_CODEC_MP3,
             AudioCodecSpecific::ES_Descriptor(_) =>
-                mp4parse_codec::MP4PARSE_CODEC_AAC,
+                mp4parse_codec::MP4PARSE_CODEC_UNKNOWN,
         },
         Some(SampleEntry::Video(ref video)) => match video.codec_specific {
             VideoCodecSpecific::VPxConfig(_) =>
                 mp4parse_codec::MP4PARSE_CODEC_VP9,
             VideoCodecSpecific::AVCConfig(_) =>
                 mp4parse_codec::MP4PARSE_CODEC_AVC,
         },
         _ => mp4parse_codec::MP4PARSE_CODEC_UNKNOWN,
     };
 
     let track = &context.tracks[track_index];
 
     if let (Some(track_timescale),
-            Some(context_timescale),
-            Some(track_duration)) = (track.timescale,
-                                     context.timescale,
-                                     track.duration) {
+            Some(context_timescale)) = (track.timescale,
+                                        context.timescale) {
         let media_time =
             match track.media_time.map_or(Some(0), |media_time| {
                     track_time_to_us(media_time, track_timescale) }) {
                 Some(time) => time as i64,
                 None => return MP4PARSE_ERROR_INVALID,
             };
         let empty_duration =
             match track.empty_duration.map_or(Some(0), |empty_duration| {
                     media_time_to_us(empty_duration, context_timescale) }) {
                 Some(time) => time as i64,
                 None => return MP4PARSE_ERROR_INVALID,
             };
         info.media_time = media_time - empty_duration;
 
-        match track_time_to_us(track_duration, track_timescale) {
-            Some(duration) => info.duration = duration,
-            None => return MP4PARSE_ERROR_INVALID,
+        if let Some(track_duration) = track.duration {
+            match track_time_to_us(track_duration, track_timescale) {
+                Some(duration) => info.duration = duration,
+                None => return MP4PARSE_ERROR_INVALID,
+            }
+        } else {
+            // Duration unknown; stagefright returns 0 for this.
+            info.duration = 0
         }
     } else {
         return MP4PARSE_ERROR_INVALID
     }
 
     info.track_id = match track.track_id {
         Some(track_id) => track_id,
         None => return MP4PARSE_ERROR_INVALID,
@@ -422,34 +434,49 @@ pub unsafe extern fn mp4parse_get_track_
     };
 
     (*info).channels = audio.channelcount;
     (*info).bit_depth = audio.samplesize;
     (*info).sample_rate = audio.samplerate >> 16; // 16.16 fixed point
 
     match audio.codec_specific {
         AudioCodecSpecific::ES_Descriptor(ref v) => {
-            if v.len() > std::u32::MAX as usize {
+            if v.codec_specific_config.len() > std::u32::MAX as usize {
                 return MP4PARSE_ERROR_INVALID;
             }
-            (*info).codec_specific_config.length = v.len() as u32;
-            (*info).codec_specific_config.data = v.as_ptr();
+            (*info).codec_specific_config.length = v.codec_specific_config.len() as u32;
+            (*info).codec_specific_config.data = v.codec_specific_config.as_ptr();
+            if let Some(rate) = v.audio_sample_rate {
+                (*info).sample_rate = rate;
+            }
+        }
+        AudioCodecSpecific::FLACSpecificBox(ref flac) => {
+            // Return the STREAMINFO metadata block in the codec_specific.
+            let streaminfo = &flac.blocks[0];
+            if streaminfo.block_type != 0 || streaminfo.data.len() != 34 {
+                return MP4PARSE_ERROR_INVALID;
+            }
+            (*info).codec_specific_config.length = streaminfo.data.len() as u32;
+            (*info).codec_specific_config.data = streaminfo.data.as_ptr();
         }
         AudioCodecSpecific::OpusSpecificBox(ref opus) => {
             let mut v = Vec::new();
             match serialize_opus_header(opus, &mut v) {
                 Err(_) => {
                     return MP4PARSE_ERROR_INVALID;
                 }
                 Ok(_) => {
                     let header = (*parser).opus_header_mut();
                     header.insert(track_index, v);
                     match header.get(&track_index) {
                         None => {}
                         Some(v) => {
+                            if v.len() > std::u32::MAX as usize {
+                                return MP4PARSE_ERROR_INVALID;
+                            }
                             (*info).codec_specific_config.length = v.len() as u32;
                             (*info).codec_specific_config.data = v.as_ptr();
                         }
                     }
                 }
             }
         }
     }