Bug 1300219 - Update mp4parse to v0.5.0. r=kinetik

Result of running the update script and updating gecko's
integration crate for the layout change.

MozReview-Commit-ID: GaIMFKmPmtf

--HG--
extra : rebase_source : 0d3a2f1d211840879e562cb56afcc9ef7e38c730
This commit is contained in:
Ralph Giles 2016-09-02 14:27:50 -07:00
Родитель 3985298455
Коммит 104d30ab53
11 изменённых файлов: 237 добавлений и 152 удалений

Просмотреть файл

@ -93,6 +93,8 @@ mp4parse_error mp4parse_get_track_audio_info(mp4parse_parser* parser, uint32_t t
/// Fill the supplied `mp4parse_track_video_info` with metadata for `track`. /// Fill the supplied `mp4parse_track_video_info` with metadata for `track`.
mp4parse_error mp4parse_get_track_video_info(mp4parse_parser* parser, uint32_t track_index, mp4parse_track_video_info* info); mp4parse_error mp4parse_get_track_video_info(mp4parse_parser* parser, uint32_t track_index, mp4parse_track_video_info* info);
mp4parse_error mp4parse_is_fragmented(mp4parse_parser* parser, uint32_t track_id, uint8_t* fragmented);
#ifdef __cplusplus #ifdef __cplusplus

Просмотреть файл

@ -1,25 +1,28 @@
[package] [package]
name = "mp4parse" name = "mp4parse"
version = "0.4.0" version = "0.5.0"
authors = [ authors = [
"Ralph Giles <giles@mozilla.com>", "Ralph Giles <giles@mozilla.com>",
"Matthew Gregan <kinetik@flim.org>", "Matthew Gregan <kinetik@flim.org>",
] ]
description = "Parser for ISO base media file format (mp4)" description = "Parser for ISO base media file format (mp4)"
documentation = "https://mp4parse-docs.surge.sh/mp4parse/"
license = "MPL-2.0" license = "MPL-2.0"
repository = "https://github.com/mozilla/mp4parse-rust" repository = "https://github.com/mozilla/mp4parse-rust"
# Cargo includes random files from the working directory # Avoid complaints about trying to package test files.
# by default! Avoid bloating the package with test files.
exclude = [ exclude = [
"*.mp4", "*.mp4",
] ]
[dependencies]
byteorder = { version = "0.5.0", path = "../byteorder" }
[dev-dependencies]
test-assembler = "0.1.2"
# Somewhat heavy-handed, but we want at least -Z force-overflow-checks=on. # Somewhat heavy-handed, but we want at least -Z force-overflow-checks=on.
[profile.release] [profile.release]
debug-assertions = true debug-assertions = true
[dependencies]
byteorder = { path = "../byteorder" }

Просмотреть файл

@ -54,4 +54,5 @@ box_database!(
OpusSpecificBox 0x644f7073, // "dOps" OpusSpecificBox 0x644f7073, // "dOps"
ProtectedVisualSampleEntry 0x656e6376, // "encv" - Need to check official name in spec. ProtectedVisualSampleEntry 0x656e6376, // "encv" - Need to check official name in spec.
ProtectedAudioSampleEntry 0x656e6361, // "enca" - Need to check official name in spec. ProtectedAudioSampleEntry 0x656e6361, // "enca" - Need to check official name in spec.
MovieExtendsBox 0x6d766578, // "mvex"
); );

Просмотреть файл

@ -13,10 +13,6 @@ use byteorder::ReadBytesExt;
use std::io::{Read, Take}; use std::io::{Read, Take};
use std::cmp; use std::cmp;
// Expose C api wrapper.
pub mod capi;
pub use capi::*;
mod boxes; mod boxes;
use boxes::BoxType; use boxes::BoxType;
@ -109,18 +105,18 @@ struct FileTypeBox {
/// Movie header box 'mvhd'. /// Movie header box 'mvhd'.
#[derive(Debug)] #[derive(Debug)]
struct MovieHeaderBox { struct MovieHeaderBox {
timescale: u32, pub timescale: u32,
duration: u64, duration: u64,
} }
/// Track header box 'tkhd' /// Track header box 'tkhd'
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct TrackHeaderBox { pub struct TrackHeaderBox {
track_id: u32, track_id: u32,
disabled: bool, pub disabled: bool,
duration: u64, pub duration: u64,
width: u32, pub width: u32,
height: u32, pub height: u32,
} }
/// Edit list box 'elst' /// Edit list box 'elst'
@ -201,7 +197,7 @@ struct SampleDescriptionBox {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
enum SampleEntry { pub enum SampleEntry {
Audio(AudioSampleEntry), Audio(AudioSampleEntry),
Video(VideoSampleEntry), Video(VideoSampleEntry),
Unknown, Unknown,
@ -209,45 +205,45 @@ enum SampleEntry {
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
enum AudioCodecSpecific { pub enum AudioCodecSpecific {
ES_Descriptor(Vec<u8>), ES_Descriptor(Vec<u8>),
OpusSpecificBox(OpusSpecificBox), OpusSpecificBox(OpusSpecificBox),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct AudioSampleEntry { pub struct AudioSampleEntry {
data_reference_index: u16, data_reference_index: u16,
channelcount: u16, pub channelcount: u16,
samplesize: u16, pub samplesize: u16,
samplerate: u32, pub samplerate: u32,
codec_specific: AudioCodecSpecific, pub codec_specific: AudioCodecSpecific,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
enum VideoCodecSpecific { pub enum VideoCodecSpecific {
AVCConfig(Vec<u8>), AVCConfig(Vec<u8>),
VPxConfig(VPxConfigBox), VPxConfig(VPxConfigBox),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct VideoSampleEntry { pub struct VideoSampleEntry {
data_reference_index: u16, data_reference_index: u16,
width: u16, pub width: u16,
height: u16, pub height: u16,
codec_specific: VideoCodecSpecific, pub codec_specific: VideoCodecSpecific,
} }
/// Represent a Video Partition Codec Configuration 'vpcC' box (aka vp9). /// Represent a Video Partition Codec Configuration 'vpcC' box (aka vp9).
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct VPxConfigBox { pub struct VPxConfigBox {
profile: u8, profile: u8,
level: u8, level: u8,
bit_depth: u8, pub bit_depth: u8,
color_space: u8, // Really an enum pub color_space: u8, // Really an enum
chroma_subsampling: u8, pub chroma_subsampling: u8,
transfer_function: u8, transfer_function: u8,
video_full_range: bool, video_full_range: bool,
codec_init: Vec<u8>, // Empty for vp8/vp9. pub codec_init: Vec<u8>, // Empty for vp8/vp9.
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -259,8 +255,8 @@ struct ChannelMappingTable {
/// Represent an OpusSpecificBox 'dOps' /// Represent an OpusSpecificBox 'dOps'
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct OpusSpecificBox { pub struct OpusSpecificBox {
version: u8, pub version: u8,
output_channel_count: u8, output_channel_count: u8,
pre_skip: u16, pre_skip: u16,
input_sample_rate: u32, input_sample_rate: u32,
@ -270,73 +266,80 @@ struct OpusSpecificBox {
} }
/// Internal data structures. /// Internal data structures.
#[derive(Debug)] #[derive(Debug, Default)]
pub struct MediaContext { pub struct MediaContext {
timescale: Option<MediaTimeScale>, pub timescale: Option<MediaTimeScale>,
pub has_mvex: bool,
/// Tracks found in the file. /// Tracks found in the file.
tracks: Vec<Track>, pub tracks: Vec<Track>,
} }
impl MediaContext { impl MediaContext {
pub fn new() -> MediaContext { pub fn new() -> MediaContext {
MediaContext { Default::default()
timescale: None,
tracks: Vec::new(),
}
} }
} }
#[derive(Debug)] #[derive(Debug)]
enum TrackType { pub enum TrackType {
Audio, Audio,
Video, Video,
Unknown, Unknown,
} }
impl Default for TrackType {
fn default() -> Self { TrackType::Unknown }
}
/// The media's global (mvhd) timescale. /// The media's global (mvhd) timescale.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, PartialEq)]
struct MediaTimeScale(u64); pub struct MediaTimeScale(pub u64);
/// A time scaled by the media's global (mvhd) timescale. /// A time scaled by the media's global (mvhd) timescale.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, PartialEq)]
struct MediaScaledTime(u64); pub struct MediaScaledTime(pub u64);
/// The track's local (mdhd) timescale. /// The track's local (mdhd) timescale.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, PartialEq)]
struct TrackTimeScale(u64, usize); pub struct TrackTimeScale(pub u64, pub usize);
/// A time scaled by the track's local (mdhd) timescale. /// A time scaled by the track's local (mdhd) timescale.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, PartialEq)]
struct TrackScaledTime(u64, usize); pub struct TrackScaledTime(pub u64, pub usize);
#[derive(Debug)] /// A fragmented file contains no sample data in stts, stsc, and stco.
struct Track { #[derive(Debug, Default)]
pub struct EmptySampleTableBoxes {
pub empty_stts : bool,
pub empty_stsc : bool,
pub empty_stco : bool,
}
/// Check boxes contain data.
impl EmptySampleTableBoxes {
pub fn all_empty(&self) -> bool {
self.empty_stts & self.empty_stsc & self.empty_stco
}
}
#[derive(Debug, Default)]
pub struct Track {
id: usize, id: usize,
track_type: TrackType, pub track_type: TrackType,
empty_duration: Option<MediaScaledTime>, pub empty_duration: Option<MediaScaledTime>,
media_time: Option<TrackScaledTime>, pub media_time: Option<TrackScaledTime>,
timescale: Option<TrackTimeScale>, pub timescale: Option<TrackTimeScale>,
duration: Option<TrackScaledTime>, pub duration: Option<TrackScaledTime>,
track_id: Option<u32>, pub track_id: Option<u32>,
mime_type: String, pub mime_type: String,
data: Option<SampleEntry>, pub empty_sample_boxes: EmptySampleTableBoxes,
tkhd: Option<TrackHeaderBox>, // TODO(kinetik): find a nicer way to export this. pub data: Option<SampleEntry>,
pub tkhd: Option<TrackHeaderBox>, // TODO(kinetik): find a nicer way to export this.
} }
impl Track { impl Track {
fn new(id: usize) -> Track { fn new(id: usize) -> Track {
Track { Track { id: id, ..Default::default() }
id: id,
track_type: TrackType::Unknown,
empty_duration: None,
media_time: None,
timescale: None,
duration: None,
track_id: None,
mime_type: String::new(),
data: None,
tkhd: None,
}
} }
} }
@ -454,7 +457,7 @@ macro_rules! check_parser_state {
/// Read the contents of a box, including sub boxes. /// Read the contents of a box, including sub boxes.
/// ///
/// Metadata is accumulated in the passed-through MediaContext struct, /// Metadata is accumulated in the passed-through `MediaContext` struct,
/// which can be examined later. /// which can be examined later.
pub fn read_mp4<T: Read>(f: &mut T, context: &mut MediaContext) -> Result<()> { pub fn read_mp4<T: Read>(f: &mut T, context: &mut MediaContext) -> Result<()> {
let mut found_ftyp = false; let mut found_ftyp = false;
@ -533,6 +536,10 @@ fn read_moov<T: Read>(f: &mut BMFFBox<T>, context: &mut MediaContext) -> Result<
try!(read_trak(&mut b, &mut track)); try!(read_trak(&mut b, &mut track));
context.tracks.push(track); context.tracks.push(track);
} }
BoxType::MovieExtendsBox => {
context.has_mvex = true;
try!(skip_box_content(&mut b));
}
_ => try!(skip_box_content(&mut b)), _ => try!(skip_box_content(&mut b)),
}; };
check_parser_state!(b.content); check_parser_state!(b.content);
@ -654,10 +661,12 @@ fn read_stbl<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
} }
BoxType::TimeToSampleBox => { BoxType::TimeToSampleBox => {
let stts = try!(read_stts(&mut b)); let stts = try!(read_stts(&mut b));
track.empty_sample_boxes.empty_stts = stts.samples.is_empty();
log!("{:?}", stts); log!("{:?}", stts);
} }
BoxType::SampleToChunkBox => { BoxType::SampleToChunkBox => {
let stsc = try!(read_stsc(&mut b)); let stsc = try!(read_stsc(&mut b));
track.empty_sample_boxes.empty_stsc = stsc.samples.is_empty();
log!("{:?}", stsc); log!("{:?}", stsc);
} }
BoxType::SampleSizeBox => { BoxType::SampleSizeBox => {
@ -666,6 +675,7 @@ fn read_stbl<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
} }
BoxType::ChunkOffsetBox => { BoxType::ChunkOffsetBox => {
let stco = try!(read_stco(&mut b)); let stco = try!(read_stco(&mut b));
track.empty_sample_boxes.empty_stco = stco.offsets.is_empty();
log!("{:?}", stco); log!("{:?}", stco);
} }
BoxType::ChunkLargeOffsetBox => { BoxType::ChunkLargeOffsetBox => {
@ -985,7 +995,7 @@ fn read_vpcc<T: Read>(src: &mut BMFFBox<T>) -> Result<VPxConfigBox> {
}) })
} }
/// Parse OpusSpecificBox. /// Parse `OpusSpecificBox`.
fn read_dops<T: Read>(src: &mut BMFFBox<T>) -> Result<OpusSpecificBox> { fn read_dops<T: Read>(src: &mut BMFFBox<T>) -> Result<OpusSpecificBox> {
let version = try!(src.read_u8()); let version = try!(src.read_u8());
if version != 0 { if version != 0 {
@ -1024,13 +1034,13 @@ fn read_dops<T: Read>(src: &mut BMFFBox<T>) -> Result<OpusSpecificBox> {
}) })
} }
/// Re-serialize the Opus codec-specific config data as an OpusHead packet. /// Re-serialize the Opus codec-specific config data as an `OpusHead` packet.
/// ///
/// Some decoders expect the initialization data in the format used by the /// Some decoders expect the initialization data in the format used by the
/// Ogg and WebM encapsulations. To support this we prepend the 'OpusHead' /// Ogg and WebM encapsulations. To support this we prepend the `OpusHead`
/// tag and byte-swap the data from big- to little-endian relative to the /// tag and byte-swap the data from big- to little-endian relative to the
/// dOps box. /// dOps box.
fn serialize_opus_header<W: byteorder::WriteBytesExt + std::io::Write>(opus: &OpusSpecificBox, dst: &mut W) -> Result<()> { pub fn serialize_opus_header<W: byteorder::WriteBytesExt + std::io::Write>(opus: &OpusSpecificBox, dst: &mut W) -> Result<()> {
match dst.write(b"OpusHead") { match dst.write(b"OpusHead") {
Err(e) => return Err(Error::from(e)), Err(e) => return Err(Error::from(e)),
Ok(bytes) => { Ok(bytes) => {
@ -1151,16 +1161,14 @@ fn read_video_desc<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) -> Result<S
check_parser_state!(b.content); check_parser_state!(b.content);
} }
if codec_specific.is_none() { codec_specific
return Err(Error::InvalidData("malformed video sample entry")); .map(|codec_specific| SampleEntry::Video(VideoSampleEntry {
} data_reference_index: data_reference_index,
width: width,
Ok(SampleEntry::Video(VideoSampleEntry { height: height,
data_reference_index: data_reference_index, codec_specific: codec_specific,
width: width, }))
height: height, .ok_or_else(|| Error::InvalidData("malformed video sample entry"))
codec_specific: codec_specific.unwrap(),
}))
} }
/// Parse an audio description inside an stsd box. /// Parse an audio description inside an stsd box.
@ -1235,17 +1243,15 @@ fn read_audio_desc<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) -> Result<S
check_parser_state!(b.content); check_parser_state!(b.content);
} }
if codec_specific.is_none() { codec_specific
return Err(Error::InvalidData("malformed audio sample entry")); .map(|codec_specific| SampleEntry::Audio(AudioSampleEntry {
} data_reference_index: data_reference_index,
channelcount: channelcount,
Ok(SampleEntry::Audio(AudioSampleEntry { samplesize: samplesize,
data_reference_index: data_reference_index, samplerate: samplerate,
channelcount: channelcount, codec_specific: codec_specific,
samplesize: samplesize, }))
samplerate: samplerate, .ok_or_else(|| Error::InvalidData("malformed audio sample entry"))
codec_specific: codec_specific.unwrap(),
}))
} }
/// Parse a stsd box. /// Parse a stsd box.
@ -1352,17 +1358,6 @@ fn read_fixed_length_pascal_string<T: Read>(src: &mut T, size: usize) -> Result<
String::from_utf8(buf).map_err(From::from) String::from_utf8(buf).map_err(From::from)
} }
fn media_time_to_ms(time: MediaScaledTime, scale: MediaTimeScale) -> u64 {
assert!(scale.0 != 0);
time.0 * 1000000 / scale.0
}
fn track_time_to_ms(time: TrackScaledTime, scale: TrackTimeScale) -> u64 {
assert!(time.1 == scale.1);
assert!(scale.0 != 0);
time.0 * 1000000 / scale.0
}
fn be_i16<T: ReadBytesExt>(src: &mut T) -> Result<i16> { fn be_i16<T: ReadBytesExt>(src: &mut T) -> Result<i16> {
src.read_i16::<byteorder::BigEndian>().map_err(From::from) src.read_i16::<byteorder::BigEndian>().map_err(From::from)
} }

Просмотреть файл

@ -6,7 +6,9 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/. // file, You can obtain one at https://mozilla.org/MPL/2.0/.
use std::io::Cursor; use std::io::Cursor;
use super::*; use super::read_mp4;
use super::MediaContext;
use super::Error;
extern crate test_assembler; extern crate test_assembler;
use self::test_assembler::*; use self::test_assembler::*;

Просмотреть файл

@ -0,0 +1,28 @@
[package]
name = "mp4parse_capi"
version = "0.5.0"
authors = [
"Ralph Giles <giles@mozilla.com>",
"Matthew Gregan <kinetik@flim.org>",
]
description = "Parser for ISO base media file format (mp4)"
documentation = "https://mp4parse-docs.surge.sh/mp4parse/"
license = "MPL-2.0"
repository = "https://github.com/mozilla/mp4parse-rust"
# Avoid complaints about trying to package test files.
exclude = [
"*.mp4",
]
[dependencies]
"mp4parse" = {version = "0.5.0", path = "../mp4parse"}
[features]
fuzz = ["mp4parse/fuzz"]
# Somewhat heavy-handed, but we want at least -Z force-overflow-checks=on.
[profile.release]
debug-assertions = true

Просмотреть файл

@ -3,7 +3,6 @@ extern crate cheddar;
fn main() { fn main() {
// Generate mp4parse.h. // Generate mp4parse.h.
cheddar::Cheddar::new().expect("could not read manifest") cheddar::Cheddar::new().expect("could not read manifest")
.module("capi").expect("invalid module path")
.insert_code("// THIS FILE IS AUTOGENERATED BY mp4parse-rust/build.rs - DO NOT EDIT\n\n") .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("// 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("// License, v. 2.0. If a copy of the MPL was not distributed with this\n")

Просмотреть файл

@ -5,7 +5,7 @@
//! # Examples //! # Examples
//! //!
//! ```rust //! ```rust
//! extern crate mp4parse; //! extern crate mp4parse_capi;
//! use std::io::Read; //! use std::io::Read;
//! //!
//! extern fn buf_read(buf: *mut u8, size: usize, userdata: *mut std::os::raw::c_void) -> isize { //! extern fn buf_read(buf: *mut u8, size: usize, userdata: *mut std::os::raw::c_void) -> isize {
@ -17,14 +17,16 @@
//! } //! }
//! } //! }
//! //!
//! let mut file = std::fs::File::open("examples/minimal.mp4").unwrap(); //! let mut file = std::fs::File::open("../mp4parse/tests/minimal.mp4").unwrap();
//! let io = mp4parse::mp4parse_io { read: buf_read, //! let io = mp4parse_capi::mp4parse_io {
//! userdata: &mut file as *mut _ as *mut std::os::raw::c_void }; //! read: buf_read,
//! userdata: &mut file as *mut _ as *mut std::os::raw::c_void
//! };
//! unsafe { //! unsafe {
//! let parser = mp4parse::mp4parse_new(&io); //! let parser = mp4parse_capi::mp4parse_new(&io);
//! let rv = mp4parse::mp4parse_read(parser); //! let rv = mp4parse_capi::mp4parse_read(parser);
//! assert_eq!(rv, mp4parse::mp4parse_error::MP4PARSE_OK); //! assert_eq!(rv, mp4parse_capi::mp4parse_error::MP4PARSE_OK);
//! mp4parse::mp4parse_free(parser); //! mp4parse_capi::mp4parse_free(parser);
//! } //! }
//! ``` //! ```
@ -32,21 +34,24 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this // License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/. // file, You can obtain one at https://mozilla.org/MPL/2.0/.
use std; extern crate mp4parse;
use std::io::Read; use std::io::Read;
use std::collections::HashMap; use std::collections::HashMap;
// Symbols we need from our rust api. // Symbols we need from our rust api.
use MediaContext; use mp4parse::MediaContext;
use TrackType; use mp4parse::TrackType;
use read_mp4; use mp4parse::read_mp4;
use Error; use mp4parse::Error;
use media_time_to_ms; use mp4parse::SampleEntry;
use track_time_to_ms; use mp4parse::AudioCodecSpecific;
use SampleEntry; use mp4parse::VideoCodecSpecific;
use AudioCodecSpecific; use mp4parse::MediaTimeScale;
use VideoCodecSpecific; use mp4parse::MediaScaledTime;
use serialize_opus_header; use mp4parse::TrackTimeScale;
use mp4parse::TrackScaledTime;
use mp4parse::serialize_opus_header;
// rusty-cheddar's C enum generation doesn't namespace enum members by // 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 // prefixing them, so we're forced to do it in our member names until
@ -266,13 +271,24 @@ pub unsafe extern fn mp4parse_get_track_count(parser: *const mp4parse_parser, co
let context = (*parser).context(); let context = (*parser).context();
// Make sure the track count fits in a u32. // Make sure the track count fits in a u32.
if context.tracks.len() >= u32::max_value() as usize { if context.tracks.len() > u32::max_value() as usize {
return MP4PARSE_ERROR_INVALID; return MP4PARSE_ERROR_INVALID;
} }
*count = context.tracks.len() as u32; *count = context.tracks.len() as u32;
MP4PARSE_OK MP4PARSE_OK
} }
fn media_time_to_ms(time: MediaScaledTime, scale: MediaTimeScale) -> u64 {
assert!(scale.0 != 0);
time.0 * 1000000 / scale.0
}
fn track_time_to_ms(time: TrackScaledTime, scale: TrackTimeScale) -> u64 {
assert!(time.1 == scale.1);
assert!(scale.0 != 0);
time.0 * 1000000 / scale.0
}
/// Fill the supplied `mp4parse_track_info` with metadata for `track`. /// Fill the supplied `mp4parse_track_info` with metadata for `track`.
#[no_mangle] #[no_mangle]
pub unsafe extern fn mp4parse_get_track_info(parser: *mut mp4parse_parser, track_index: u32, info: *mut mp4parse_track_info) -> mp4parse_error { pub unsafe extern fn mp4parse_get_track_info(parser: *mut mp4parse_parser, track_index: u32, info: *mut mp4parse_track_info) -> mp4parse_error {
@ -310,22 +326,28 @@ pub unsafe extern fn mp4parse_get_track_info(parser: *mut mp4parse_parser, track
_ => mp4parse_codec::MP4PARSE_CODEC_UNKNOWN, _ => mp4parse_codec::MP4PARSE_CODEC_UNKNOWN,
}; };
// Maybe context & track should just have a single simple is_valid() instead? let track = &context.tracks[track_index];
if context.timescale.is_none() ||
context.tracks[track_index].timescale.is_none() || if let (Some(track_timescale),
context.tracks[track_index].duration.is_none() || Some(context_timescale),
context.tracks[track_index].track_id.is_none() { Some(track_duration)) = (track.timescale,
return MP4PARSE_ERROR_INVALID; context.timescale,
track.duration) {
info.media_time = track.media_time.map_or(0, |media_time| {
track_time_to_ms(media_time, track_timescale) as i64
}) - track.empty_duration.map_or(0, |empty_duration| {
media_time_to_ms(empty_duration, context_timescale) as i64
});
info.duration = track_time_to_ms(track_duration, track_timescale);
} else {
return MP4PARSE_ERROR_INVALID
} }
let track = &context.tracks[track_index]; info.track_id = match track.track_id {
info.media_time = track.media_time.map_or(0, |media_time| { Some(track_id) => track_id,
track_time_to_ms(media_time, track.timescale.unwrap()) as i64 None => return MP4PARSE_ERROR_INVALID,
}) - track.empty_duration.map_or(0, |empty_duration| { };
media_time_to_ms(empty_duration, context.timescale.unwrap()) as i64
});
info.duration = track_time_to_ms(track.duration.unwrap(), track.timescale.unwrap());
info.track_id = track.track_id.unwrap();
MP4PARSE_OK MP4PARSE_OK
} }
@ -438,6 +460,32 @@ pub unsafe extern fn mp4parse_get_track_video_info(parser: *mut mp4parse_parser,
MP4PARSE_OK MP4PARSE_OK
} }
// A fragmented file needs mvex table and contains no data in stts, stsc, and stco boxes.
#[no_mangle]
pub unsafe extern fn mp4parse_is_fragmented(parser: *mut mp4parse_parser, track_id: u32, fragmented: *mut u8) -> mp4parse_error {
if parser.is_null() || (*parser).poisoned() {
return MP4PARSE_ERROR_BADARG;
}
let context = (*parser).context_mut();
let tracks = &context.tracks;
(*fragmented) = false as u8;
if !context.has_mvex {
return MP4PARSE_OK;
}
// check sample tables.
let mut iter = tracks.iter();
match iter.find(|track| track.track_id == Some(track_id)) {
Some(track) if track.empty_sample_boxes.all_empty() => (*fragmented) = true as u8,
Some(_) => {},
None => return MP4PARSE_ERROR_BADARG,
}
MP4PARSE_OK
}
#[cfg(test)] #[cfg(test)]
extern fn panic_read(_: *mut u8, _: usize, _: *mut std::os::raw::c_void) -> isize { extern fn panic_read(_: *mut u8, _: usize, _: *mut std::os::raw::c_void) -> isize {
panic!("panic_read shouldn't be called in these tests"); panic!("panic_read shouldn't be called in these tests");
@ -614,7 +662,7 @@ fn get_track_count_poisoned_parser() {
#[test] #[test]
fn arg_validation_with_data() { fn arg_validation_with_data() {
unsafe { unsafe {
let mut file = std::fs::File::open("examples/minimal.mp4").unwrap(); let mut file = std::fs::File::open("../mp4parse/tests/minimal.mp4").unwrap();
let io = mp4parse_io { read: valid_read, let io = mp4parse_io { read: valid_read,
userdata: &mut file as *mut _ as *mut std::os::raw::c_void }; userdata: &mut file as *mut _ as *mut std::os::raw::c_void };
let parser = mp4parse_new(&io); let parser = mp4parse_new(&io);

11
toolkit/library/rust/Cargo.lock сгенерированный
Просмотреть файл

@ -2,7 +2,7 @@
name = "gkrust" name = "gkrust"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"mp4parse 0.4.0", "mp4parse_capi 0.5.0",
] ]
[[package]] [[package]]
@ -11,8 +11,15 @@ version = "0.5.3"
[[package]] [[package]]
name = "mp4parse" name = "mp4parse"
version = "0.4.0" version = "0.5.0"
dependencies = [ dependencies = [
"byteorder 0.5.3", "byteorder 0.5.3",
] ]
[[package]]
name = "mp4parse_capi"
version = "0.5.0"
dependencies = [
"mp4parse 0.5.0",
]

Просмотреть файл

@ -6,7 +6,7 @@ license = "MPL-2.0"
description = "Rust code for libxul" description = "Rust code for libxul"
[dependencies] [dependencies]
mp4parse = { path = "../../../media/libstagefright/binding/mp4parse" } mp4parse_capi = { path = "../../../media/libstagefright/binding/mp4parse_capi" }
[lib] [lib]
path = "lib.rs" path = "lib.rs"

Просмотреть файл

@ -2,4 +2,4 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this // License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
extern crate mp4parse; extern crate mp4parse_capi;