--- a/media/libstagefright/binding/mp4parse/src/lib.rs
+++ b/media/libstagefright/binding/mp4parse/src/lib.rs
@@ -200,22 +200,22 @@ struct SampleDescriptionBox {
#[derive(Debug, Clone)]
pub enum SampleEntry {
Audio(AudioSampleEntry),
Video(VideoSampleEntry),
Unknown,
}
#[allow(non_camel_case_types)]
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Default)]
pub struct ES_Descriptor {
pub audio_codec: CodecType,
pub audio_sample_rate: Option<u32>,
pub audio_channel_count: Option<u16>,
- pub codec_specific_config: Vec<u8>,
+ pub codec_esds: Vec<u8>,
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone)]
pub enum AudioCodecSpecific {
ES_Descriptor(ES_Descriptor),
FLACSpecificBox(FLACSpecificBox),
OpusSpecificBox(OpusSpecificBox),
@@ -454,23 +454,23 @@ impl<'a, T: Read> BMFFBox<'a, T> {
/// Read and parse a box header.
///
/// Call this first to determine the type of a particular mp4 box
/// and its length. Used internally for dispatching to specific
/// parsers for the internal content, or to get the length to
/// skip unknown or uninteresting boxes.
fn read_box_header<T: ReadBytesExt>(src: &mut T) -> Result<BoxHeader> {
- let size32 = try!(be_u32(src));
- let name = BoxType::from(try!(be_u32(src)));
+ let size32 = be_u32(src)?;
+ let name = BoxType::from(be_u32(src)?);
let size = match size32 {
// valid only for top-level box and indicates it's the last box in the file. usually mdat.
0 => return Err(Error::Unsupported("unknown sized box")),
1 => {
- let size64 = try!(be_u64(src));
+ let size64 = be_u64(src)?;
if size64 < 16 {
return Err(Error::InvalidData("malformed wide size"));
}
size64
}
2...7 => return Err(Error::InvalidData("malformed size")),
_ => size32 as u64,
};
@@ -483,33 +483,33 @@ fn read_box_header<T: ReadBytesExt>(src:
name: name,
size: size,
offset: offset,
})
}
/// Parse the extra header fields for a full box.
fn read_fullbox_extra<T: ReadBytesExt>(src: &mut T) -> Result<(u8, u32)> {
- let version = try!(src.read_u8());
- let flags_a = try!(src.read_u8());
- let flags_b = try!(src.read_u8());
- let flags_c = try!(src.read_u8());
+ let version = src.read_u8()?;
+ let flags_a = src.read_u8()?;
+ let flags_b = src.read_u8()?;
+ let flags_c = src.read_u8()?;
Ok((version,
(flags_a as u32) << 16 | (flags_b as u32) << 8 | (flags_c as u32)))
}
/// Skip over the entire contents of a box.
fn skip_box_content<T: Read>(src: &mut BMFFBox<T>) -> Result<()> {
// Skip the contents of unknown chunks.
let to_skip = {
let header = src.get_header();
log!("{:?} (skipped)", header);
(header.size - header.offset) as usize
};
- assert!(to_skip == src.bytes_left());
+ assert_eq!(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();
@@ -533,17 +533,17 @@ macro_rules! check_parser_state {
/// Metadata is accumulated in the passed-through `MediaContext` struct,
/// which can be examined later.
pub fn read_mp4<T: Read>(f: &mut T, context: &mut MediaContext) -> Result<()> {
let mut found_ftyp = false;
let mut found_moov = false;
// TODO(kinetik): Top-level parsing should handle zero-sized boxes
// rather than throwing an error.
let mut iter = BoxIter::new(f);
- while let Some(mut b) = try!(iter.next_box()) {
+ while let Some(mut b) = iter.next_box()? {
// box ordering: ftyp before any variable length box (inc. moov),
// but may not be first box in file if file signatures etc. present
// fragmented mp4 order: ftyp, moov, pairs of moof/mdat (1-multiple), mfra
// "special": uuid, wide (= 8 bytes)
// isom: moov, mdat, free, skip, udta, ftyp, moof, mfra
// iso2: pdin, meta
// iso3: meco
@@ -551,25 +551,25 @@ pub fn read_mp4<T: Read>(f: &mut T, cont
// unknown, maybe: id32
// qt: pnot
// possibly allow anything where all printable and/or all lowercase printable
// "four printable characters from the ISO 8859-1 character set"
match b.head.name {
BoxType::FileTypeBox => {
- let ftyp = try!(read_ftyp(&mut b));
+ let ftyp = read_ftyp(&mut b)?;
found_ftyp = true;
log!("{:?}", ftyp);
}
BoxType::MovieBox => {
- try!(read_moov(&mut b, context));
+ read_moov(&mut b, context)?;
found_moov = true;
}
- _ => try!(skip_box_content(&mut b)),
+ _ => skip_box_content(&mut b)?,
};
check_parser_state!(b.content);
if found_moov {
log!("found moov {}, could stop pure 'moov' parser now", if found_ftyp {
"and ftyp"
} else {
"but no ftyp"
});
@@ -582,146 +582,146 @@ pub fn read_mp4<T: Read>(f: &mut T, cont
if found_moov {
Ok(())
} else {
Err(Error::NoMoov)
}
}
fn parse_mvhd<T: Read>(f: &mut BMFFBox<T>) -> Result<(MovieHeaderBox, Option<MediaTimeScale>)> {
- let mvhd = try!(read_mvhd(f));
+ let mvhd = read_mvhd(f)?;
if mvhd.timescale == 0 {
return Err(Error::InvalidData("zero timescale in mdhd"));
}
let timescale = Some(MediaTimeScale(mvhd.timescale as u64));
Ok((mvhd, timescale))
}
fn read_moov<T: Read>(f: &mut BMFFBox<T>, context: &mut MediaContext) -> Result<()> {
let mut iter = f.box_iter();
- while let Some(mut b) = try!(iter.next_box()) {
+ while let Some(mut b) = iter.next_box()? {
match b.head.name {
BoxType::MovieHeaderBox => {
- let (mvhd, timescale) = try!(parse_mvhd(&mut b));
+ let (mvhd, timescale) = parse_mvhd(&mut b)?;
context.timescale = timescale;
log!("{:?}", mvhd);
}
BoxType::TrackBox => {
let mut track = Track::new(context.tracks.len());
- try!(read_trak(&mut b, &mut track));
+ read_trak(&mut b, &mut track)?;
context.tracks.push(track);
}
BoxType::MovieExtendsBox => {
- let mvex = try!(read_mvex(&mut b));
+ let mvex = read_mvex(&mut b)?;
log!("{:?}", mvex);
context.mvex = Some(mvex);
}
BoxType::ProtectionSystemSpecificHeaderBox => {
- let pssh = try!(read_pssh(&mut b));
+ let pssh = read_pssh(&mut b)?;
log!("{:?}", pssh);
context.psshs.push(pssh);
}
- _ => try!(skip_box_content(&mut b)),
+ _ => skip_box_content(&mut b)?,
};
check_parser_state!(b.content);
}
Ok(())
}
fn read_pssh<T: Read>(src: &mut BMFFBox<T>) -> Result<ProtectionSystemSpecificHeaderBox> {
let mut box_content = Vec::with_capacity(src.head.size as usize);
- try!(src.read_to_end(&mut box_content));
+ src.read_to_end(&mut box_content)?;
let (system_id, kid, data) = {
let pssh = &mut Cursor::new(box_content.as_slice());
- let (version, _) = try!(read_fullbox_extra(pssh));
+ let (version, _) = read_fullbox_extra(pssh)?;
- let system_id = try!(read_buf(pssh, 16));
+ let system_id = read_buf(pssh, 16)?;
let mut kid: Vec<ByteData> = Vec::new();
if version > 0 {
- let count = try!(be_i32(pssh));
+ let count = be_i32(pssh)?;
for _ in 0..count {
- let item = try!(read_buf(pssh, 16));
+ let item = read_buf(pssh, 16)?;
kid.push(item);
}
}
- let data_size = try!(be_i32(pssh)) as usize;
- let data = try!(read_buf(pssh, data_size));
+ let data_size = be_i32(pssh)? as usize;
+ let data = read_buf(pssh, data_size)?;
(system_id, kid, data)
};
let mut pssh_box = Vec::new();
- try!(write_be_u32(&mut pssh_box, src.head.size as u32));
+ write_be_u32(&mut pssh_box, src.head.size as u32)?;
pssh_box.append(&mut b"pssh".to_vec());
pssh_box.append(&mut box_content);
Ok(ProtectionSystemSpecificHeaderBox {
system_id: system_id,
kid: kid,
data: data,
box_content: pssh_box,
})
}
fn read_mvex<T: Read>(src: &mut BMFFBox<T>) -> Result<MovieExtendsBox> {
let mut iter = src.box_iter();
let mut fragment_duration = None;
- while let Some(mut b) = try!(iter.next_box()) {
+ while let Some(mut b) = iter.next_box()? {
match b.head.name {
BoxType::MovieExtendsHeaderBox => {
- let duration = try!(read_mehd(&mut b));
+ let duration = read_mehd(&mut b)?;
fragment_duration = Some(duration);
},
- _ => try!(skip_box_content(&mut b)),
+ _ => skip_box_content(&mut b)?,
}
}
Ok(MovieExtendsBox {
fragment_duration: fragment_duration,
})
}
fn read_mehd<T: Read>(src: &mut BMFFBox<T>) -> Result<MediaScaledTime> {
- let (version, _) = try!(read_fullbox_extra(src));
+ let (version, _) = read_fullbox_extra(src)?;
let fragment_duration = match version {
- 1 => try!(be_u64(src)),
- 0 => try!(be_u32(src)) as u64,
+ 1 => be_u64(src)?,
+ 0 => be_u32(src)? as u64,
_ => return Err(Error::InvalidData("unhandled mehd version")),
};
Ok(MediaScaledTime(fragment_duration))
}
fn read_trak<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
let mut iter = f.box_iter();
- while let Some(mut b) = try!(iter.next_box()) {
+ while let Some(mut b) = iter.next_box()? {
match b.head.name {
BoxType::TrackHeaderBox => {
- let tkhd = try!(read_tkhd(&mut b));
+ let tkhd = read_tkhd(&mut b)?;
track.track_id = Some(tkhd.track_id);
track.tkhd = Some(tkhd.clone());
log!("{:?}", tkhd);
}
- BoxType::EditBox => try!(read_edts(&mut b, track)),
- BoxType::MediaBox => try!(read_mdia(&mut b, track)),
- _ => try!(skip_box_content(&mut b)),
+ BoxType::EditBox => read_edts(&mut b, track)?,
+ BoxType::MediaBox => read_mdia(&mut b, track)?,
+ _ => skip_box_content(&mut b)?,
};
check_parser_state!(b.content);
}
Ok(())
}
fn read_edts<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
let mut iter = f.box_iter();
- while let Some(mut b) = try!(iter.next_box()) {
+ while let Some(mut b) = iter.next_box()? {
match b.head.name {
BoxType::EditListBox => {
- let elst = try!(read_elst(&mut b));
+ let elst = read_elst(&mut b)?;
let mut empty_duration = 0;
let mut idx = 0;
if elst.edits.len() > 2 {
return Err(Error::Unsupported("more than two edits"));
}
if elst.edits[idx].media_time == -1 {
empty_duration = elst.edits[idx].segment_duration;
if elst.edits.len() < 2 {
@@ -732,589 +732,601 @@ fn read_edts<T: Read>(f: &mut BMFFBox<T>
track.empty_duration = Some(MediaScaledTime(empty_duration));
if elst.edits[idx].media_time < 0 {
return Err(Error::InvalidData("unexpected negative media time in edit"));
}
track.media_time = Some(TrackScaledTime(elst.edits[idx].media_time as u64,
track.id));
log!("{:?}", elst);
}
- _ => try!(skip_box_content(&mut b)),
+ _ => skip_box_content(&mut b)?,
};
check_parser_state!(b.content);
}
Ok(())
}
fn parse_mdhd<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<(MediaHeaderBox, Option<TrackScaledTime>, Option<TrackTimeScale>)> {
- let mdhd = try!(read_mdhd(f));
+ let mdhd = read_mdhd(f)?;
let duration = match mdhd.duration {
std::u64::MAX => None,
duration => Some(TrackScaledTime(duration, track.id)),
};
if mdhd.timescale == 0 {
return Err(Error::InvalidData("zero timescale in mdhd"));
}
let timescale = Some(TrackTimeScale(mdhd.timescale as u64, track.id));
Ok((mdhd, duration, timescale))
}
fn read_mdia<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
let mut iter = f.box_iter();
- while let Some(mut b) = try!(iter.next_box()) {
+ while let Some(mut b) = iter.next_box()? {
match b.head.name {
BoxType::MediaHeaderBox => {
- let (mdhd, duration, timescale) = try!(parse_mdhd(&mut b, track));
+ let (mdhd, duration, timescale) = parse_mdhd(&mut b, track)?;
track.duration = duration;
track.timescale = timescale;
log!("{:?}", mdhd);
}
BoxType::HandlerBox => {
- let hdlr = try!(read_hdlr(&mut b));
+ let hdlr = read_hdlr(&mut b)?;
match hdlr.handler_type {
0x76696465 /* 'vide' */ => track.track_type = TrackType::Video,
0x736f756e /* 'soun' */ => track.track_type = TrackType::Audio,
_ => (),
}
log!("{:?}", hdlr);
}
- BoxType::MediaInformationBox => try!(read_minf(&mut b, track)),
- _ => try!(skip_box_content(&mut b)),
+ BoxType::MediaInformationBox => read_minf(&mut b, track)?,
+ _ => skip_box_content(&mut b)?,
};
check_parser_state!(b.content);
}
Ok(())
}
fn read_minf<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
let mut iter = f.box_iter();
- while let Some(mut b) = try!(iter.next_box()) {
+ while let Some(mut b) = iter.next_box()? {
match b.head.name {
- BoxType::SampleTableBox => try!(read_stbl(&mut b, track)),
- _ => try!(skip_box_content(&mut b)),
+ BoxType::SampleTableBox => read_stbl(&mut b, track)?,
+ _ => skip_box_content(&mut b)?,
};
check_parser_state!(b.content);
}
Ok(())
}
fn read_stbl<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
let mut iter = f.box_iter();
- while let Some(mut b) = try!(iter.next_box()) {
+ while let Some(mut b) = iter.next_box()? {
match b.head.name {
BoxType::SampleDescriptionBox => {
- let stsd = try!(read_stsd(&mut b, track));
+ let stsd = read_stsd(&mut b, track)?;
log!("{:?}", stsd);
}
BoxType::TimeToSampleBox => {
- let stts = try!(read_stts(&mut b));
+ let stts = read_stts(&mut b)?;
track.empty_sample_boxes.empty_stts = stts.samples.is_empty();
log!("{:?}", stts);
}
BoxType::SampleToChunkBox => {
- let stsc = try!(read_stsc(&mut b));
+ let stsc = read_stsc(&mut b)?;
track.empty_sample_boxes.empty_stsc = stsc.samples.is_empty();
log!("{:?}", stsc);
}
BoxType::SampleSizeBox => {
- let stsz = try!(read_stsz(&mut b));
+ let stsz = read_stsz(&mut b)?;
log!("{:?}", stsz);
}
BoxType::ChunkOffsetBox => {
- let stco = try!(read_stco(&mut b));
+ let stco = read_stco(&mut b)?;
track.empty_sample_boxes.empty_stco = stco.offsets.is_empty();
log!("{:?}", stco);
}
BoxType::ChunkLargeOffsetBox => {
- let co64 = try!(read_co64(&mut b));
+ let co64 = read_co64(&mut b)?;
log!("{:?}", co64);
}
BoxType::SyncSampleBox => {
- let stss = try!(read_stss(&mut b));
+ let stss = read_stss(&mut b)?;
log!("{:?}", stss);
}
- _ => try!(skip_box_content(&mut b)),
+ _ => skip_box_content(&mut b)?,
};
check_parser_state!(b.content);
}
Ok(())
}
/// Parse an ftyp box.
fn read_ftyp<T: Read>(src: &mut BMFFBox<T>) -> Result<FileTypeBox> {
- let major = try!(be_u32(src));
- let minor = try!(be_u32(src));
+ let major = be_u32(src)?;
+ let minor = be_u32(src)?;
let bytes_left = src.bytes_left();
if bytes_left % 4 != 0 {
return Err(Error::InvalidData("invalid ftyp size"));
}
// Is a brand_count of zero valid?
let brand_count = bytes_left / 4;
let mut brands = Vec::new();
for _ in 0..brand_count {
- brands.push(try!(be_u32(src)));
+ brands.push(be_u32(src)?);
}
Ok(FileTypeBox {
major_brand: major,
minor_version: minor,
compatible_brands: brands,
})
}
/// Parse an mvhd box.
fn read_mvhd<T: Read>(src: &mut BMFFBox<T>) -> Result<MovieHeaderBox> {
- let (version, _) = try!(read_fullbox_extra(src));
+ let (version, _) = read_fullbox_extra(src)?;
match version {
// 64 bit creation and modification times.
1 => {
- try!(skip(src, 16));
+ skip(src, 16)?;
}
// 32 bit creation and modification times.
0 => {
- try!(skip(src, 8));
+ skip(src, 8)?;
}
_ => return Err(Error::InvalidData("unhandled mvhd version")),
}
- let timescale = try!(be_u32(src));
+ let timescale = be_u32(src)?;
let duration = match version {
- 1 => try!(be_u64(src)),
+ 1 => be_u64(src)?,
0 => {
- let d = try!(be_u32(src));
+ let d = be_u32(src)?;
if d == std::u32::MAX {
std::u64::MAX
} else {
d as u64
}
}
_ => return Err(Error::InvalidData("unhandled mvhd version")),
};
// Skip remaining fields.
- try!(skip(src, 80));
+ skip(src, 80)?;
Ok(MovieHeaderBox {
timescale: timescale,
duration: duration,
})
}
/// Parse a tkhd box.
fn read_tkhd<T: Read>(src: &mut BMFFBox<T>) -> Result<TrackHeaderBox> {
- let (version, flags) = try!(read_fullbox_extra(src));
+ let (version, flags) = read_fullbox_extra(src)?;
let disabled = flags & 0x1u32 == 0 || flags & 0x2u32 == 0;
match version {
// 64 bit creation and modification times.
1 => {
- try!(skip(src, 16));
+ skip(src, 16)?;
}
// 32 bit creation and modification times.
0 => {
- try!(skip(src, 8));
+ skip(src, 8)?;
}
_ => return Err(Error::InvalidData("unhandled tkhd version")),
}
- let track_id = try!(be_u32(src));
- try!(skip(src, 4));
+ let track_id = be_u32(src)?;
+ skip(src, 4)?;
let duration = match version {
- 1 => try!(be_u64(src)),
- 0 => try!(be_u32(src)) as u64,
+ 1 => be_u64(src)?,
+ 0 => be_u32(src)? as u64,
_ => return Err(Error::InvalidData("unhandled tkhd version")),
};
// Skip uninteresting fields.
- try!(skip(src, 52));
- let width = try!(be_u32(src));
- let height = try!(be_u32(src));
+ skip(src, 52)?;
+ let width = be_u32(src)?;
+ let height = be_u32(src)?;
Ok(TrackHeaderBox {
track_id: track_id,
disabled: disabled,
duration: duration,
width: width,
height: height,
})
}
/// Parse a elst box.
fn read_elst<T: Read>(src: &mut BMFFBox<T>) -> Result<EditListBox> {
- let (version, _) = try!(read_fullbox_extra(src));
- let edit_count = try!(be_u32(src));
+ let (version, _) = read_fullbox_extra(src)?;
+ let edit_count = be_u32(src)?;
if edit_count == 0 {
return Err(Error::InvalidData("invalid edit count"));
}
let mut edits = Vec::new();
for _ in 0..edit_count {
let (segment_duration, media_time) = match version {
1 => {
// 64 bit segment duration and media times.
- (try!(be_u64(src)), try!(be_i64(src)))
+ (be_u64(src)?, be_i64(src)?)
}
0 => {
// 32 bit segment duration and media times.
- (try!(be_u32(src)) as u64, try!(be_i32(src)) as i64)
+ (be_u32(src)? as u64, be_i32(src)? as i64)
}
_ => return Err(Error::InvalidData("unhandled elst version")),
};
- let media_rate_integer = try!(be_i16(src));
- let media_rate_fraction = try!(be_i16(src));
+ let media_rate_integer = be_i16(src)?;
+ let media_rate_fraction = be_i16(src)?;
edits.push(Edit {
segment_duration: segment_duration,
media_time: media_time,
media_rate_integer: media_rate_integer,
media_rate_fraction: media_rate_fraction,
})
}
Ok(EditListBox {
edits: edits,
})
}
/// Parse a mdhd box.
fn read_mdhd<T: Read>(src: &mut BMFFBox<T>) -> Result<MediaHeaderBox> {
- let (version, _) = try!(read_fullbox_extra(src));
+ let (version, _) = read_fullbox_extra(src)?;
let (timescale, duration) = match version {
1 => {
// Skip 64-bit creation and modification times.
- try!(skip(src, 16));
+ skip(src, 16)?;
// 64 bit duration.
- (try!(be_u32(src)), try!(be_u64(src)))
+ (be_u32(src)?, be_u64(src)?)
}
0 => {
// Skip 32-bit creation and modification times.
- try!(skip(src, 8));
+ skip(src, 8)?;
// 32 bit duration.
- let timescale = try!(be_u32(src));
+ let timescale = be_u32(src)?;
let duration = {
// Since we convert the 32-bit duration to 64-bit by
// upcasting, we need to preserve the special all-1s
// ("unknown") case by hand.
- let d = try!(be_u32(src));
+ let d = be_u32(src)?;
if d == std::u32::MAX {
std::u64::MAX
} else {
d as u64
}
};
(timescale, duration)
}
_ => return Err(Error::InvalidData("unhandled mdhd version")),
};
// Skip uninteresting fields.
- try!(skip(src, 4));
+ skip(src, 4)?;
Ok(MediaHeaderBox {
timescale: timescale,
duration: duration,
})
}
/// Parse a stco box.
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 (_, _) = read_fullbox_extra(src)?;
+ let offset_count = be_u32(src)?;
let mut offsets = Vec::new();
for _ in 0..offset_count {
- offsets.push(try!(be_u32(src)) as u64);
+ offsets.push(be_u32(src)? as u64);
}
// Padding could be added in some contents.
- try!(skip_box_remain(src));
+ 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 (_, _) = read_fullbox_extra(src)?;
+ let offset_count = be_u32(src)?;
let mut offsets = Vec::new();
for _ in 0..offset_count {
- offsets.push(try!(be_u64(src)));
+ offsets.push(be_u64(src)?);
}
// Padding could be added in some contents.
- try!(skip_box_remain(src));
+ 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 (_, _) = read_fullbox_extra(src)?;
+ let sample_count = be_u32(src)?;
let mut samples = Vec::new();
for _ in 0..sample_count {
- samples.push(try!(be_u32(src)));
+ samples.push(be_u32(src)?);
}
// Padding could be added in some contents.
- try!(skip_box_remain(src));
+ 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));
- let sample_count = try!(be_u32(src));
+ let (_, _) = read_fullbox_extra(src)?;
+ let sample_count = be_u32(src)?;
let mut samples = Vec::new();
for _ in 0..sample_count {
- let first_chunk = try!(be_u32(src));
- let samples_per_chunk = try!(be_u32(src));
- let sample_description_index = try!(be_u32(src));
+ let first_chunk = be_u32(src)?;
+ let samples_per_chunk = be_u32(src)?;
+ let sample_description_index = 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));
+ 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));
- let sample_size = try!(be_u32(src));
- let sample_count = try!(be_u32(src));
+ let (_, _) = read_fullbox_extra(src)?;
+ let sample_size = be_u32(src)?;
+ let sample_count = 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)));
+ sample_sizes.push(be_u32(src)?);
}
}
// Padding could be added in some contents.
- try!(skip_box_remain(src));
+ 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> {
- let (_, _) = try!(read_fullbox_extra(src));
- let sample_count = try!(be_u32(src));
+ let (_, _) = read_fullbox_extra(src)?;
+ let sample_count = be_u32(src)?;
let mut samples = Vec::new();
for _ in 0..sample_count {
- let sample_count = try!(be_u32(src));
- let sample_delta = try!(be_u32(src));
+ let sample_count = be_u32(src)?;
+ let sample_delta = 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));
+ 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));
+ let (version, _) = read_fullbox_extra(src)?;
if version != 0 {
return Err(Error::Unsupported("unknown vpcC version"));
}
- let profile = try!(src.read_u8());
- let level = try!(src.read_u8());
+ let profile = src.read_u8()?;
+ let level = src.read_u8()?;
let (bit_depth, color_space) = {
- let byte = try!(src.read_u8());
+ let byte = src.read_u8()?;
((byte >> 4) & 0x0f, byte & 0x0f)
};
let (chroma_subsampling, transfer_function, video_full_range) = {
- let byte = try!(src.read_u8());
+ let byte = src.read_u8()?;
((byte >> 4) & 0x0f, (byte >> 1) & 0x07, (byte & 1) == 1)
};
- let codec_init_size = try!(be_u16(src));
- let codec_init = try!(read_buf(src, codec_init_size as usize));
+ let codec_init_size = be_u16(src)?;
+ let codec_init = read_buf(src, codec_init_size as usize)?;
// TODO(rillian): validate field value ranges.
Ok(VPxConfigBox {
profile: profile,
level: level,
bit_depth: bit_depth,
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 temp = src.read_u8()?;
let block_type = temp & 0x7f;
- let length = try!(be_u24(src));
+ let length = 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));
+ let data = 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> {
+fn find_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
// Tags for elementary stream description
const ESDESCR_TAG: u8 = 0x03;
const DECODER_CONFIG_TAG: u8 = 0x04;
const DECODER_SPECIFIC_TAG: u8 = 0x05;
+ let mut remains = data;
+
+ while !remains.is_empty() {
+ let des = &mut Cursor::new(remains);
+ let tag = des.read_u8()?;
+
+ let extend_or_len = des.read_u8()?;
+ // extension tag start from 0x80.
+ let end = if extend_or_len >= 0x80 {
+ // Extension found, skip remaining extension.
+ skip(des, 2)?;
+ des.read_u8()? as u64 + des.position()
+ } else {
+ extend_or_len as u64 + des.position()
+ };
+
+ if end as usize > remains.len() {
+ return Err(Error::InvalidData("Invalid descriptor."));
+ }
+
+ let descriptor = &remains[des.position() as usize .. end as usize];
+
+ match tag {
+ ESDESCR_TAG => {
+ read_es_descriptor(descriptor, esds)?;
+ },
+ DECODER_CONFIG_TAG => {
+ read_dc_descriptor(descriptor, esds)?;
+ },
+ DECODER_SPECIFIC_TAG => {
+ read_ds_descriptor(descriptor, esds)?;
+ },
+ _ => {
+ log!("Unsupported descriptor, tag {}", tag);
+ },
+ }
+
+ remains = &remains[end as usize .. remains.len()];
+ }
+
+ Ok(())
+}
+
+fn read_ds_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
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 des = &mut Cursor::new(data);
+
+ let audio_specific_config = be_u16(des)?;
+
+ let sample_index = (audio_specific_config & 0x07FF) >> 7;
+
+ let channel_counts = (audio_specific_config & 0x007F) >> 3;
+
+ let sample_frequency =
+ frequency_table.iter().find(|item| item.0 == sample_index).map(|x| x.1);
+
+ esds.audio_sample_rate = sample_frequency;
+ esds.audio_channel_count = Some(channel_counts);
+
+ Ok(())
+}
+
+fn read_dc_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
+ let des = &mut Cursor::new(data);
+ let object_profile = des.read_u8()?;
+
+ // Skip uninteresting fields.
+ skip(des, 12)?;
+
+ if data.len() > des.position() as usize {
+ find_descriptor(&data[des.position() as usize .. data.len()], esds)?;
+ }
+
+ esds.audio_codec = match object_profile {
+ 0x40 | 0x41 => CodecType::AAC,
+ 0x6B => CodecType::MP3,
+ _ => CodecType::Unknown,
+ };
+
+ Ok(())
+}
+
+fn read_es_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
+ let des = &mut Cursor::new(data);
+
+ skip(des, 2)?;
+
+ let esds_flags = des.read_u8()?;
+
+ // Stream dependency flag, first bit from left most.
+ if esds_flags & 0x80 > 0 {
+ // Skip uninteresting fields.
+ skip(des, 2)?;
+ }
+
+ // Url flag, second bit from left most.
+ if esds_flags & 0x40 > 0 {
+ // Skip uninteresting fields.
+ let skip_es_len: usize = des.read_u8()? as usize + 2;
+ skip(des, skip_es_len)?;
+ }
+
+ if data.len() > des.position() as usize {
+ find_descriptor(&data[des.position() as usize .. data.len()], esds)?;
+ }
+
+ Ok(())
+}
+
+fn read_esds<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
+ let (_, _) = 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, audio sample rate and channel counts.
- let (object_profile_indicator, sample_frequency, channels) = {
- let mut object_profile: u8 = 0;
- let mut sample_frequency = None;
- let mut channels = 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));
- }
+ let esds_array = read_buf(src, esds_size as usize)?;
- // 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 mut es_data = ES_Descriptor::default();
+ find_descriptor(&esds_array, &mut es_data)?;
- let audio_specific_config = try!(be_u16(esds));
-
- let sample_index = (audio_specific_config & 0x07FF) >> 7;
-
- let channel_counts = (audio_specific_config & 0x007F) >> 3;
-
- sample_frequency =
- frequency_table.iter().find(|item| item.0 == sample_index).map(|x| x.1);
-
- channels = Some(channel_counts);
- }
- }
-
- (object_profile, sample_frequency, channels)
- };
+ es_data.codec_esds = esds_array;
- 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,
- audio_channel_count: channels,
- codec_specific_config: esds_array,
- })
+ Ok(es_data)
}
/// Parse `FLACSpecificBox`.
fn read_dfla<T: Read>(src: &mut BMFFBox<T>) -> Result<FLACSpecificBox> {
- let (version, flags) = try!(read_fullbox_extra(src));
+ let (version, flags) = 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));
+ let block = 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]);
@@ -1327,33 +1339,33 @@ fn read_dfla<T: Read>(src: &mut BMFFBox<
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());
+ let version = src.read_u8()?;
if version != 0 {
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());
+ let output_channel_count = src.read_u8()?;
+ let pre_skip = be_u16(src)?;
+ let input_sample_rate = be_u32(src)?;
+ let output_gain = be_i16(src)?;
+ let channel_mapping_family = src.read_u8()?;
let channel_mapping_table = if channel_mapping_family == 0 {
None
} else {
- let stream_count = try!(src.read_u8());
- let coupled_count = try!(src.read_u8());
- let channel_mapping = try!(read_buf(src, output_channel_count as usize));
+ let stream_count = src.read_u8()?;
+ let coupled_count = src.read_u8()?;
+ let channel_mapping = read_buf(src, output_channel_count as usize)?;
Some(ChannelMappingTable {
stream_count: stream_count,
coupled_count: coupled_count,
channel_mapping: channel_mapping,
})
};
@@ -1383,54 +1395,54 @@ pub fn serialize_opus_header<W: byteorde
return Err(Error::InvalidData("Couldn't write OpusHead tag."));
}
}
}
// In mp4 encapsulation, the version field is 0, but in ogg
// it is 1. While decoders generally accept zero as well, write
// out the version of the header we're supporting rather than
// whatever we parsed out of mp4.
- try!(dst.write_u8(1));
- try!(dst.write_u8(opus.output_channel_count));
- try!(dst.write_u16::<byteorder::LittleEndian>(opus.pre_skip));
- try!(dst.write_u32::<byteorder::LittleEndian>(opus.input_sample_rate));
- try!(dst.write_i16::<byteorder::LittleEndian>(opus.output_gain));
- try!(dst.write_u8(opus.channel_mapping_family));
+ dst.write_u8(1)?;
+ dst.write_u8(opus.output_channel_count)?;
+ dst.write_u16::<byteorder::LittleEndian>(opus.pre_skip)?;
+ dst.write_u32::<byteorder::LittleEndian>(opus.input_sample_rate)?;
+ dst.write_i16::<byteorder::LittleEndian>(opus.output_gain)?;
+ dst.write_u8(opus.channel_mapping_family)?;
match opus.channel_mapping_table {
None => {}
Some(ref table) => {
- try!(dst.write_u8(table.stream_count));
- try!(dst.write_u8(table.coupled_count));
+ dst.write_u8(table.stream_count)?;
+ dst.write_u8(table.coupled_count)?;
match dst.write(&table.channel_mapping) {
Err(e) => return Err(Error::from(e)),
Ok(bytes) => {
if bytes != table.channel_mapping.len() {
return Err(Error::InvalidData("Couldn't write channel mapping table data."));
}
}
}
}
};
Ok(())
}
/// Parse a hdlr box.
fn read_hdlr<T: Read>(src: &mut BMFFBox<T>) -> Result<HandlerBox> {
- let (_, _) = try!(read_fullbox_extra(src));
+ let (_, _) = read_fullbox_extra(src)?;
// Skip uninteresting fields.
- try!(skip(src, 4));
+ skip(src, 4)?;
- let handler_type = try!(be_u32(src));
+ let handler_type = be_u32(src)?;
// Skip uninteresting fields.
- try!(skip(src, 12));
+ skip(src, 12)?;
let bytes_left = src.bytes_left();
- let _name = try!(read_null_terminated_string(src, bytes_left));
+ 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> {
@@ -1439,64 +1451,64 @@ fn read_video_sample_entry<T: Read>(src:
BoxType::AVCSampleEntry | BoxType::AVC3SampleEntry => CodecType::H264,
BoxType::VP8SampleEntry => CodecType::VP8,
BoxType::VP9SampleEntry => CodecType::VP9,
BoxType::ProtectedVisualSampleEntry => CodecType::EncryptedVideo,
_ => CodecType::Unknown,
};
// Skip uninteresting fields.
- try!(skip(src, 6));
+ skip(src, 6)?;
- let data_reference_index = try!(be_u16(src));
+ let data_reference_index = be_u16(src)?;
// Skip uninteresting fields.
- try!(skip(src, 16));
+ skip(src, 16)?;
- let width = try!(be_u16(src));
- let height = try!(be_u16(src));
+ let width = be_u16(src)?;
+ let height = be_u16(src)?;
// Skip uninteresting fields.
- try!(skip(src, 14));
+ skip(src, 14)?;
- let _compressorname = try!(read_fixed_length_pascal_string(src, 32));
+ let _compressorname = read_fixed_length_pascal_string(src, 32)?;
// Skip uninteresting fields.
- try!(skip(src, 4));
+ skip(src, 4)?;
// Skip clap/pasp/etc. for now.
let mut codec_specific = None;
let mut iter = src.box_iter();
- while let Some(mut b) = try!(iter.next_box()) {
+ while let Some(mut b) = iter.next_box()? {
match b.head.name {
BoxType::AVCConfigurationBox => {
if (name != BoxType::AVCSampleEntry &&
name != BoxType::AVC3SampleEntry &&
name != BoxType::ProtectedVisualSampleEntry) ||
codec_specific.is_some() {
return Err(Error::InvalidData("malformed video sample entry"));
}
let avcc_size = b.head.size - b.head.offset;
if avcc_size > BUF_SIZE_LIMIT {
return Err(Error::InvalidData("avcC box exceeds BUF_SIZE_LIMIT"));
}
- let avcc = try!(read_buf(&mut b.content, avcc_size as usize));
+ let avcc = read_buf(&mut b.content, avcc_size as usize)?;
// TODO(kinetik): Parse avcC box? For now we just stash the data.
codec_specific = Some(VideoCodecSpecific::AVCConfig(avcc));
}
BoxType::VPCodecConfigurationBox => { // vpcC
if (name != BoxType::VP8SampleEntry &&
name != BoxType::VP9SampleEntry) ||
codec_specific.is_some() {
return Err(Error::InvalidData("malformed video sample entry"));
}
- let vpcc = try!(read_vpcc(&mut b));
+ let vpcc = read_vpcc(&mut b)?;
codec_specific = Some(VideoCodecSpecific::VPxConfig(vpcc));
}
- _ => try!(skip_box_content(&mut b)),
+ _ => skip_box_content(&mut b)?,
}
check_parser_state!(b.content);
}
codec_specific
.map(|codec_specific| SampleEntry::Video(VideoSampleEntry {
data_reference_index: data_reference_index,
width: width,
@@ -1504,23 +1516,23 @@ fn read_video_sample_entry<T: Read>(src:
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()) {
+ while let Some(mut b) = iter.next_box()? {
match b.head.name {
BoxType::ESDBox => {
- let esds = try!(read_esds(&mut b));
+ let esds = read_esds(&mut b)?;
codec_specific = Some(esds);
},
- _ => try!(skip_box_content(&mut b)),
+ _ => 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> {
@@ -1530,87 +1542,87 @@ fn read_audio_sample_entry<T: Read>(src:
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));
+ skip(src, 6)?;
- let data_reference_index = try!(be_u16(src));
+ let data_reference_index = be_u16(src)?;
// XXX(kinetik): This is "reserved" in BMFF, but some old QT MOV variant
// uses it, need to work out if we have to support it. Without checking
// here and reading extra fields after samplerate (or bailing with an
// error), the parser loses sync completely.
- let version = try!(be_u16(src));
+ let version = be_u16(src)?;
// Skip uninteresting fields.
- try!(skip(src, 6));
+ skip(src, 6)?;
- let channelcount = try!(be_u16(src));
- let samplesize = try!(be_u16(src));
+ let channelcount = be_u16(src)?;
+ let samplesize = be_u16(src)?;
// Skip uninteresting fields.
- try!(skip(src, 4));
+ skip(src, 4)?;
- let samplerate = try!(be_u32(src));
+ let samplerate = be_u32(src)?;
match version {
0 => (),
1 => {
// Quicktime sound sample description version 1.
// Skip uninteresting fields.
- try!(skip(src, 16));
+ 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()) {
+ 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 = try!(read_esds(&mut b));
+ let esds = 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));
+ let dfla = 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));
+ let dops = 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));
+ let qt_esds = 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)),
+ _ => skip_box_content(&mut b)?,
}
check_parser_state!(b.content);
}
codec_specific
.map(|codec_specific| SampleEntry::Audio(AudioSampleEntry {
data_reference_index: data_reference_index,
channelcount: channelcount,
@@ -1618,38 +1630,38 @@ fn read_audio_sample_entry<T: Read>(src:
samplerate: samplerate,
codec_specific: codec_specific,
}))
.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 (_, _) = try!(read_fullbox_extra(src));
+ let (_, _) = read_fullbox_extra(src)?;
- let description_count = try!(be_u32(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) = try!(iter.next_box()) {
+ 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::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));
+ 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 **");
@@ -1658,80 +1670,80 @@ fn read_stsd<T: Read>(src: &mut BMFFBox<
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));
+ 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;
let mut buf = vec![0; BUF_SIZE];
while bytes > 0 {
let buf_size = cmp::min(bytes, BUF_SIZE);
- let len = try!(src.take(buf_size as u64).read(&mut buf));
+ let len = src.take(buf_size as u64).read(&mut buf)?;
if len == 0 {
return Err(Error::UnexpectedEOF);
}
bytes -= len;
}
Ok(())
}
/// Read size bytes into a Vector or return error.
fn read_buf<T: ReadBytesExt>(src: &mut T, size: usize) -> Result<Vec<u8>> {
let mut buf = vec![0; size];
- let r = try!(src.read(&mut buf));
+ let r = src.read(&mut buf)?;
if r != size {
return Err(Error::InvalidData("failed buffer read"));
}
Ok(buf)
}
// TODO(kinetik): Find a copy of ISO/IEC 14496-1 to confirm various string encodings.
// XXX(kinetik): definition of "null-terminated" string is fuzzy, we have:
// - zero or more byte strings, with a single null terminating the string.
// - zero byte strings with no null terminator (i.e. zero space in the box for the string)
// - length-prefixed strings with no null terminator (e.g. bear_rotate_0.mp4)
fn read_null_terminated_string<T: ReadBytesExt>(src: &mut T, mut size: usize) -> Result<String> {
let mut buf = Vec::new();
while size > 0 {
- let c = try!(src.read_u8());
+ let c = src.read_u8()?;
if c == 0 {
break;
}
buf.push(c);
size -= 1;
}
String::from_utf8(buf).map_err(From::from)
}
#[allow(dead_code)]
fn read_pascal_string<T: ReadBytesExt>(src: &mut T) -> Result<String> {
- let len = try!(src.read_u8());
- let buf = try!(read_buf(src, len as usize));
+ let len = src.read_u8()?;
+ let buf = read_buf(src, len as usize)?;
String::from_utf8(buf).map_err(From::from)
}
// Weird string encoding with a length prefix and a fixed sized buffer which
// contains padding if the string doesn't fill the buffer.
fn read_fixed_length_pascal_string<T: Read>(src: &mut T, size: usize) -> Result<String> {
assert!(size > 0);
- let len = cmp::min(try!(src.read_u8()) as usize, size - 1);
- let buf = try!(read_buf(src, len));
- try!(skip(src, size - 1 - buf.len()));
+ let len = cmp::min(src.read_u8()? as usize, size - 1);
+ let buf = read_buf(src, len)?;
+ skip(src, size - 1 - buf.len())?;
String::from_utf8(buf).map_err(From::from)
}
fn be_i16<T: ReadBytesExt>(src: &mut T) -> Result<i16> {
src.read_i16::<byteorder::BigEndian>().map_err(From::from)
}
fn be_i32<T: ReadBytesExt>(src: &mut T) -> Result<i32> {
--- a/media/libstagefright/binding/mp4parse/src/tests.rs
+++ b/media/libstagefright/binding/mp4parse/src/tests.rs
@@ -143,18 +143,18 @@ fn read_truncated_ftyp() {
let mut stream = make_box(BoxSize::UncheckedShort(24), b"ftyp", |s| {
s.append_bytes(b"mp42")
.B32(0) // minor version
.append_bytes(b"isom")
});
let mut context = MediaContext::new();
match read_mp4(&mut stream, &mut context) {
Err(Error::UnexpectedEOF) => (),
- Ok(_) => assert!(false, "expected an error result"),
- _ => assert!(false, "expected a different error result"),
+ Ok(_) => panic!("expected an error result"),
+ _ => panic!("expected a different error result"),
}
}
#[test]
fn read_ftyp_case() {
// Brands in BMFF are represented as a u32, so it would seem clear that
// 0x6d703432 ("mp42") is not equal to 0x4d503432 ("MP42"), but some
// demuxers treat these as case-insensitive strings, e.g. street.mp4's
@@ -588,18 +588,18 @@ fn serialize_opus_header() {
pre_skip: 342,
input_sample_rate: 24000,
output_gain: 0,
channel_mapping_family: 0,
channel_mapping_table: None,
};
let mut v = Vec::<u8>::new();
super::serialize_opus_header(&opus, &mut v).unwrap();
- assert!(v.len() == 19);
- assert!(v == vec![
+ assert_eq!(v.len(), 19);
+ assert_eq!(v, vec![
0x4f, 0x70, 0x75, 0x73, 0x48,0x65, 0x61, 0x64,
0x01, 0x01, 0x56, 0x01,
0xc0, 0x5d, 0x00, 0x00,
0x00, 0x00, 0x00,
]);
let opus = super::OpusSpecificBox {
version: 0,
output_channel_count: 6,
@@ -610,18 +610,18 @@ fn serialize_opus_header() {
channel_mapping_table: Some(super::ChannelMappingTable {
stream_count: 4,
coupled_count: 2,
channel_mapping: vec![0, 4, 1, 2, 3, 5],
}),
};
let mut v = Vec::<u8>::new();
super::serialize_opus_header(&opus, &mut v).unwrap();
- assert!(v.len() == 27);
- assert!(v == vec![
+ assert_eq!(v.len(), 27);
+ assert_eq!(v, vec![
0x4f, 0x70, 0x75, 0x73, 0x48,0x65, 0x61, 0x64,
0x01, 0x06, 0x98, 0x00,
0x80, 0xbb, 0x00, 0x00,
0x00, 0x00, 0x01, 0x04, 0x02,
0x00, 0x04, 0x01, 0x02, 0x03, 0x05,
]);
}
@@ -640,18 +640,18 @@ fn avcc_limit() {
.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) {
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"),
+ Ok(_) => panic!("expected an error result"),
+ _ => panic!("expected a different error result"),
}
}
#[test]
fn esds_limit() {
let mut stream = make_box(BoxSize::Auto, b"mp4a", |s| {
s.append_repeated(0, 6)
.B16(1)
@@ -666,18 +666,18 @@ fn esds_limit() {
.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) {
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"),
+ Ok(_) => panic!("expected an error result"),
+ _ => panic!("expected a different error result"),
}
}
#[test]
fn esds_limit_2() {
let mut stream = make_box(BoxSize::Auto, b"mp4a", |s| {
s.append_repeated(0, 6)
.B16(1)
@@ -692,34 +692,34 @@ fn esds_limit_2() {
.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) {
Err(Error::UnexpectedEOF) => (),
- Ok(_) => assert!(false, "expected an error result"),
- _ => assert!(false, "expected a different error result"),
+ Ok(_) => panic!("expected an error result"),
+ _ => panic!("expected a different error result"),
}
}
#[test]
fn read_elst_zero_entries() {
let mut stream = make_fullbox(BoxSize::Auto, b"elst", 0, |s| {
s.B32(0)
.B16(12)
.B16(34)
});
let mut iter = super::BoxIter::new(&mut stream);
let mut stream = iter.next_box().unwrap().unwrap();
match super::read_elst(&mut stream) {
Err(Error::InvalidData(s)) => assert_eq!(s, "invalid edit count"),
- Ok(_) => assert!(false, "expected an error result"),
- _ => assert!(false, "expected a different error result"),
+ Ok(_) => panic!("expected an error result"),
+ _ => panic!("expected a different error result"),
}
}
fn make_elst() -> Cursor<Vec<u8>> {
make_fullbox(BoxSize::Auto, b"elst", 1, |s| {
s.B32(1)
// first entry
.B64(1234) // duration
@@ -736,18 +736,18 @@ fn read_edts_bogus() {
let mut stream = make_box(BoxSize::Auto, b"edts", |s| {
s.append_bytes(&make_elst().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);
match super::read_edts(&mut stream, &mut track) {
Err(Error::InvalidData(s)) => assert_eq!(s, "expected additional edit"),
- Ok(_) => assert!(false, "expected an error result"),
- _ => assert!(false, "expected a different error result"),
+ Ok(_) => panic!("expected an error result"),
+ _ => panic!("expected a different error result"),
}
}
#[test]
fn invalid_pascal_string() {
// String claims to be 32 bytes long (we provide 33 bytes to account for
// the 1 byte length prefix).
let pstr = "\x20xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
@@ -822,17 +822,17 @@ fn skip_padding_in_stsd() {
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
+ .B8(0x12) // 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| {
--- a/media/libstagefright/binding/mp4parse_capi/src/lib.rs
+++ b/media/libstagefright/binding/mp4parse_capi/src/lib.rs
@@ -136,28 +136,26 @@ pub struct mp4parse_pssh_info {
#[repr(C)]
pub struct mp4parse_track_audio_info {
pub channels: u16,
pub bit_depth: u16,
pub sample_rate: u32,
// TODO(kinetik):
// int32_t profile;
// int32_t extended_profile; // check types
- codec_specific_config: mp4parse_byte_data,
+ pub codec_specific_config: mp4parse_byte_data,
}
#[repr(C)]
pub struct mp4parse_track_video_info {
pub display_width: u32,
pub display_height: u32,
pub image_width: u16,
pub image_height: u16,
- // TODO(kinetik):
- // extra_data
- // codec_specific_config
+ pub extra_data: mp4parse_byte_data,
}
#[repr(C)]
pub struct mp4parse_fragment_info {
pub fragment_duration: u64,
// TODO:
// info in trex box.
}
@@ -331,17 +329,17 @@ fn rational_scale(numerator: u64, denomi
}
fn media_time_to_us(time: MediaScaledTime, scale: MediaTimeScale) -> Option<u64> {
let microseconds_per_second = 1000000;
rational_scale(time.0, scale.0, microseconds_per_second)
}
fn track_time_to_us(time: TrackScaledTime, scale: TrackTimeScale) -> Option<u64> {
- assert!(time.1 == scale.1);
+ assert_eq!(time.1, scale.1);
let microseconds_per_second = 1000000;
rational_scale(time.0, scale.0, microseconds_per_second)
}
/// Fill the supplied `mp4parse_track_info` with metadata for `track`.
#[no_mangle]
pub unsafe extern fn mp4parse_get_track_info(parser: *mut mp4parse_parser, track_index: u32, info: *mut mp4parse_track_info) -> mp4parse_error {
if parser.is_null() || info.is_null() || (*parser).poisoned() {
@@ -455,21 +453,21 @@ 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.codec_specific_config.len() > std::u32::MAX as usize {
+ if v.codec_esds.len() > std::u32::MAX as usize {
return MP4PARSE_ERROR_INVALID;
}
- (*info).codec_specific_config.length = v.codec_specific_config.len() as u32;
- (*info).codec_specific_config.data = v.codec_specific_config.as_ptr();
+ (*info).codec_specific_config.length = v.codec_esds.len() as u32;
+ (*info).codec_specific_config.data = v.codec_esds.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;
}
}
AudioCodecSpecific::FLACSpecificBox(ref flac) => {
@@ -542,16 +540,23 @@ pub unsafe extern fn mp4parse_get_track_
(*info).display_width = tkhd.width >> 16; // 16.16 fixed point
(*info).display_height = tkhd.height >> 16; // 16.16 fixed point
} else {
return MP4PARSE_ERROR_INVALID;
}
(*info).image_width = video.width;
(*info).image_height = video.height;
+ match video.codec_specific {
+ VideoCodecSpecific::AVCConfig(ref avc) => {
+ (*info).extra_data.set_data(avc);
+ },
+ _ => {},
+ }
+
MP4PARSE_OK
}
/// Fill the supplied `mp4parse_fragment_info` with metadata from fragmented file.
#[no_mangle]
pub unsafe extern fn mp4parse_get_fragment_info(parser: *mut mp4parse_parser, info: *mut mp4parse_fragment_info) -> mp4parse_error {
if parser.is_null() || info.is_null() || (*parser).poisoned() {
return MP4PARSE_ERROR_BADARG;
@@ -681,19 +686,19 @@ fn free_null_parser() {
}
}
#[test]
fn get_track_count_null_parser() {
unsafe {
let mut count: u32 = 0;
let rv = mp4parse_get_track_count(std::ptr::null(), std::ptr::null_mut());
- assert!(rv == MP4PARSE_ERROR_BADARG);
+ assert_eq!(rv, MP4PARSE_ERROR_BADARG);
let rv = mp4parse_get_track_count(std::ptr::null(), &mut count);
- assert!(rv == MP4PARSE_ERROR_BADARG);
+ assert_eq!(rv, MP4PARSE_ERROR_BADARG);
}
}
#[test]
fn arg_validation() {
unsafe {
// Passing a null mp4parse_io is an error.
let parser = mp4parse_new(std::ptr::null());
@@ -732,16 +737,17 @@ fn arg_validation() {
};
assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_info(std::ptr::null_mut(), 0, &mut dummy_info));
let mut dummy_video = mp4parse_track_video_info {
display_width: 0,
display_height: 0,
image_width: 0,
image_height: 0,
+ extra_data: mp4parse_byte_data::default(),
};
assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_video_info(std::ptr::null_mut(), 0, &mut dummy_video));
let mut dummy_audio = Default::default();
assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_audio_info(std::ptr::null_mut(), 0, &mut dummy_audio));
}
}
@@ -776,16 +782,17 @@ fn arg_validation_with_parser() {
};
assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_info(parser, 0, &mut dummy_info));
let mut dummy_video = mp4parse_track_video_info {
display_width: 0,
display_height: 0,
image_width: 0,
image_height: 0,
+ extra_data: mp4parse_byte_data::default(),
};
assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_video_info(parser, 0, &mut dummy_video));
let mut dummy_audio = Default::default();
assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_audio_info(parser, 0, &mut dummy_audio));
mp4parse_free(parser);
}
@@ -802,17 +809,17 @@ fn get_track_count_poisoned_parser() {
let parser = mp4parse_new(&io);
assert!(!parser.is_null());
// Our mp4parse_io read should simply fail with an error.
assert_eq!(MP4PARSE_ERROR_IO, mp4parse_read(parser));
let mut count: u32 = 0;
let rv = mp4parse_get_track_count(parser, &mut count);
- assert!(rv == MP4PARSE_ERROR_BADARG);
+ assert_eq!(rv, MP4PARSE_ERROR_BADARG);
}
}
#[test]
fn arg_validation_with_data() {
unsafe {
let mut file = std::fs::File::open("../mp4parse/tests/minimal.mp4").unwrap();
let io = mp4parse_io { read: valid_read,
@@ -847,16 +854,17 @@ fn arg_validation_with_data() {
assert_eq!(info.duration, 61333);
assert_eq!(info.media_time, 21333);
let mut video = mp4parse_track_video_info {
display_width: 0,
display_height: 0,
image_width: 0,
image_height: 0,
+ extra_data: mp4parse_byte_data::default(),
};
assert_eq!(MP4PARSE_OK, mp4parse_get_track_video_info(parser, 0, &mut video));
assert_eq!(video.display_width, 320);
assert_eq!(video.display_height, 240);
assert_eq!(video.image_width, 320);
assert_eq!(video.image_height, 240);
let mut audio = Default::default();
@@ -878,17 +886,18 @@ fn arg_validation_with_data() {
assert_eq!(info.codec, mp4parse_codec::MP4PARSE_CODEC_UNKNOWN);
assert_eq!(info.track_id, 0);
assert_eq!(info.duration, 0);
assert_eq!(info.media_time, 0);
let mut video = mp4parse_track_video_info { display_width: 0,
display_height: 0,
image_width: 0,
- image_height: 0 };
+ image_height: 0,
+ extra_data: mp4parse_byte_data::default(),};
assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_video_info(parser, 3, &mut video));
assert_eq!(video.display_width, 0);
assert_eq!(video.display_height, 0);
assert_eq!(video.image_width, 0);
assert_eq!(video.image_height, 0);
let mut audio = Default::default();
assert_eq!(MP4PARSE_ERROR_BADARG, mp4parse_get_track_audio_info(parser, 3, &mut audio));