mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-17 22:32:51 +00:00
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:
parent
3985298455
commit
104d30ab53
@ -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`.
|
||||
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
|
||||
|
@ -1,25 +1,28 @@
|
||||
[package]
|
||||
name = "mp4parse"
|
||||
version = "0.4.0"
|
||||
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"
|
||||
|
||||
# Cargo includes random files from the working directory
|
||||
# by default! Avoid bloating the package with test files.
|
||||
# Avoid complaints about trying to package test files.
|
||||
exclude = [
|
||||
"*.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.
|
||||
[profile.release]
|
||||
debug-assertions = true
|
||||
|
||||
[dependencies]
|
||||
byteorder = { path = "../byteorder" }
|
||||
|
@ -54,4 +54,5 @@ box_database!(
|
||||
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"
|
||||
);
|
||||
|
@ -13,10 +13,6 @@ use byteorder::ReadBytesExt;
|
||||
use std::io::{Read, Take};
|
||||
use std::cmp;
|
||||
|
||||
// Expose C api wrapper.
|
||||
pub mod capi;
|
||||
pub use capi::*;
|
||||
|
||||
mod boxes;
|
||||
use boxes::BoxType;
|
||||
|
||||
@ -109,18 +105,18 @@ struct FileTypeBox {
|
||||
/// Movie header box 'mvhd'.
|
||||
#[derive(Debug)]
|
||||
struct MovieHeaderBox {
|
||||
timescale: u32,
|
||||
pub timescale: u32,
|
||||
duration: u64,
|
||||
}
|
||||
|
||||
/// Track header box 'tkhd'
|
||||
#[derive(Debug, Clone)]
|
||||
struct TrackHeaderBox {
|
||||
pub struct TrackHeaderBox {
|
||||
track_id: u32,
|
||||
disabled: bool,
|
||||
duration: u64,
|
||||
width: u32,
|
||||
height: u32,
|
||||
pub disabled: bool,
|
||||
pub duration: u64,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
}
|
||||
|
||||
/// Edit list box 'elst'
|
||||
@ -201,7 +197,7 @@ struct SampleDescriptionBox {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum SampleEntry {
|
||||
pub enum SampleEntry {
|
||||
Audio(AudioSampleEntry),
|
||||
Video(VideoSampleEntry),
|
||||
Unknown,
|
||||
@ -209,45 +205,45 @@ enum SampleEntry {
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug, Clone)]
|
||||
enum AudioCodecSpecific {
|
||||
pub enum AudioCodecSpecific {
|
||||
ES_Descriptor(Vec<u8>),
|
||||
OpusSpecificBox(OpusSpecificBox),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct AudioSampleEntry {
|
||||
pub struct AudioSampleEntry {
|
||||
data_reference_index: u16,
|
||||
channelcount: u16,
|
||||
samplesize: u16,
|
||||
samplerate: u32,
|
||||
codec_specific: AudioCodecSpecific,
|
||||
pub channelcount: u16,
|
||||
pub samplesize: u16,
|
||||
pub samplerate: u32,
|
||||
pub codec_specific: AudioCodecSpecific,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum VideoCodecSpecific {
|
||||
pub enum VideoCodecSpecific {
|
||||
AVCConfig(Vec<u8>),
|
||||
VPxConfig(VPxConfigBox),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct VideoSampleEntry {
|
||||
pub struct VideoSampleEntry {
|
||||
data_reference_index: u16,
|
||||
width: u16,
|
||||
height: u16,
|
||||
codec_specific: VideoCodecSpecific,
|
||||
pub width: u16,
|
||||
pub height: u16,
|
||||
pub codec_specific: VideoCodecSpecific,
|
||||
}
|
||||
|
||||
/// Represent a Video Partition Codec Configuration 'vpcC' box (aka vp9).
|
||||
#[derive(Debug, Clone)]
|
||||
struct VPxConfigBox {
|
||||
pub struct VPxConfigBox {
|
||||
profile: u8,
|
||||
level: u8,
|
||||
bit_depth: u8,
|
||||
color_space: u8, // Really an enum
|
||||
chroma_subsampling: u8,
|
||||
pub bit_depth: u8,
|
||||
pub color_space: u8, // Really an enum
|
||||
pub chroma_subsampling: u8,
|
||||
transfer_function: u8,
|
||||
video_full_range: bool,
|
||||
codec_init: Vec<u8>, // Empty for vp8/vp9.
|
||||
pub codec_init: Vec<u8>, // Empty for vp8/vp9.
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -259,8 +255,8 @@ struct ChannelMappingTable {
|
||||
|
||||
/// Represent an OpusSpecificBox 'dOps'
|
||||
#[derive(Debug, Clone)]
|
||||
struct OpusSpecificBox {
|
||||
version: u8,
|
||||
pub struct OpusSpecificBox {
|
||||
pub version: u8,
|
||||
output_channel_count: u8,
|
||||
pre_skip: u16,
|
||||
input_sample_rate: u32,
|
||||
@ -270,73 +266,80 @@ struct OpusSpecificBox {
|
||||
}
|
||||
|
||||
/// Internal data structures.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct MediaContext {
|
||||
timescale: Option<MediaTimeScale>,
|
||||
pub timescale: Option<MediaTimeScale>,
|
||||
pub has_mvex: bool,
|
||||
/// Tracks found in the file.
|
||||
tracks: Vec<Track>,
|
||||
pub tracks: Vec<Track>,
|
||||
}
|
||||
|
||||
impl MediaContext {
|
||||
pub fn new() -> MediaContext {
|
||||
MediaContext {
|
||||
timescale: None,
|
||||
tracks: Vec::new(),
|
||||
}
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum TrackType {
|
||||
pub enum TrackType {
|
||||
Audio,
|
||||
Video,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl Default for TrackType {
|
||||
fn default() -> Self { TrackType::Unknown }
|
||||
}
|
||||
|
||||
/// The media's global (mvhd) timescale.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct MediaTimeScale(u64);
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub struct MediaTimeScale(pub u64);
|
||||
|
||||
/// A time scaled by the media's global (mvhd) timescale.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct MediaScaledTime(u64);
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub struct MediaScaledTime(pub u64);
|
||||
|
||||
/// The track's local (mdhd) timescale.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct TrackTimeScale(u64, usize);
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub struct TrackTimeScale(pub u64, pub usize);
|
||||
|
||||
/// A time scaled by the track's local (mdhd) timescale.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct TrackScaledTime(u64, usize);
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub struct TrackScaledTime(pub u64, pub usize);
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Track {
|
||||
/// A fragmented file contains no sample data in stts, stsc, and stco.
|
||||
#[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,
|
||||
track_type: TrackType,
|
||||
empty_duration: Option<MediaScaledTime>,
|
||||
media_time: Option<TrackScaledTime>,
|
||||
timescale: Option<TrackTimeScale>,
|
||||
duration: Option<TrackScaledTime>,
|
||||
track_id: Option<u32>,
|
||||
mime_type: String,
|
||||
data: Option<SampleEntry>,
|
||||
tkhd: Option<TrackHeaderBox>, // TODO(kinetik): find a nicer way to export this.
|
||||
pub track_type: TrackType,
|
||||
pub empty_duration: Option<MediaScaledTime>,
|
||||
pub media_time: Option<TrackScaledTime>,
|
||||
pub timescale: Option<TrackTimeScale>,
|
||||
pub duration: Option<TrackScaledTime>,
|
||||
pub track_id: Option<u32>,
|
||||
pub mime_type: String,
|
||||
pub empty_sample_boxes: EmptySampleTableBoxes,
|
||||
pub data: Option<SampleEntry>,
|
||||
pub tkhd: Option<TrackHeaderBox>, // TODO(kinetik): find a nicer way to export this.
|
||||
}
|
||||
|
||||
impl Track {
|
||||
fn new(id: usize) -> Track {
|
||||
Track {
|
||||
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,
|
||||
}
|
||||
Track { id: id, ..Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
@ -454,7 +457,7 @@ macro_rules! check_parser_state {
|
||||
|
||||
/// 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.
|
||||
pub fn read_mp4<T: Read>(f: &mut T, context: &mut MediaContext) -> Result<()> {
|
||||
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));
|
||||
context.tracks.push(track);
|
||||
}
|
||||
BoxType::MovieExtendsBox => {
|
||||
context.has_mvex = true;
|
||||
try!(skip_box_content(&mut b));
|
||||
}
|
||||
_ => try!(skip_box_content(&mut b)),
|
||||
};
|
||||
check_parser_state!(b.content);
|
||||
@ -654,10 +661,12 @@ fn read_stbl<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
|
||||
}
|
||||
BoxType::TimeToSampleBox => {
|
||||
let stts = try!(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));
|
||||
track.empty_sample_boxes.empty_stsc = stsc.samples.is_empty();
|
||||
log!("{:?}", stsc);
|
||||
}
|
||||
BoxType::SampleSizeBox => {
|
||||
@ -666,6 +675,7 @@ fn read_stbl<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
|
||||
}
|
||||
BoxType::ChunkOffsetBox => {
|
||||
let stco = try!(read_stco(&mut b));
|
||||
track.empty_sample_boxes.empty_stco = stco.offsets.is_empty();
|
||||
log!("{:?}", stco);
|
||||
}
|
||||
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> {
|
||||
let version = try!(src.read_u8());
|
||||
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
|
||||
/// 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
|
||||
/// 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") {
|
||||
Err(e) => return Err(Error::from(e)),
|
||||
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);
|
||||
}
|
||||
|
||||
if codec_specific.is_none() {
|
||||
return Err(Error::InvalidData("malformed video sample entry"));
|
||||
}
|
||||
|
||||
Ok(SampleEntry::Video(VideoSampleEntry {
|
||||
data_reference_index: data_reference_index,
|
||||
width: width,
|
||||
height: height,
|
||||
codec_specific: codec_specific.unwrap(),
|
||||
}))
|
||||
codec_specific
|
||||
.map(|codec_specific| SampleEntry::Video(VideoSampleEntry {
|
||||
data_reference_index: data_reference_index,
|
||||
width: width,
|
||||
height: height,
|
||||
codec_specific: codec_specific,
|
||||
}))
|
||||
.ok_or_else(|| Error::InvalidData("malformed video sample entry"))
|
||||
}
|
||||
|
||||
/// 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);
|
||||
}
|
||||
|
||||
if codec_specific.is_none() {
|
||||
return Err(Error::InvalidData("malformed audio sample entry"));
|
||||
}
|
||||
|
||||
Ok(SampleEntry::Audio(AudioSampleEntry {
|
||||
data_reference_index: data_reference_index,
|
||||
channelcount: channelcount,
|
||||
samplesize: samplesize,
|
||||
samplerate: samplerate,
|
||||
codec_specific: codec_specific.unwrap(),
|
||||
}))
|
||||
codec_specific
|
||||
.map(|codec_specific| SampleEntry::Audio(AudioSampleEntry {
|
||||
data_reference_index: data_reference_index,
|
||||
channelcount: channelcount,
|
||||
samplesize: samplesize,
|
||||
samplerate: samplerate,
|
||||
codec_specific: codec_specific,
|
||||
}))
|
||||
.ok_or_else(|| Error::InvalidData("malformed audio sample entry"))
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
|
||||
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> {
|
||||
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/.
|
||||
|
||||
use std::io::Cursor;
|
||||
use super::*;
|
||||
use super::read_mp4;
|
||||
use super::MediaContext;
|
||||
use super::Error;
|
||||
extern crate test_assembler;
|
||||
use self::test_assembler::*;
|
||||
|
||||
|
28
media/libstagefright/binding/mp4parse_capi/Cargo.toml
Normal file
28
media/libstagefright/binding/mp4parse_capi/Cargo.toml
Normal file
@ -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() {
|
||||
// Generate mp4parse.h.
|
||||
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 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")
|
@ -5,7 +5,7 @@
|
||||
//! # Examples
|
||||
//!
|
||||
//! ```rust
|
||||
//! extern crate mp4parse;
|
||||
//! extern crate mp4parse_capi;
|
||||
//! use std::io::Read;
|
||||
//!
|
||||
//! 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 io = mp4parse::mp4parse_io { read: buf_read,
|
||||
//! userdata: &mut file as *mut _ as *mut std::os::raw::c_void };
|
||||
//! let mut file = std::fs::File::open("../mp4parse/tests/minimal.mp4").unwrap();
|
||||
//! let io = mp4parse_capi::mp4parse_io {
|
||||
//! read: buf_read,
|
||||
//! userdata: &mut file as *mut _ as *mut std::os::raw::c_void
|
||||
//! };
|
||||
//! unsafe {
|
||||
//! let parser = mp4parse::mp4parse_new(&io);
|
||||
//! let rv = mp4parse::mp4parse_read(parser);
|
||||
//! assert_eq!(rv, mp4parse::mp4parse_error::MP4PARSE_OK);
|
||||
//! mp4parse::mp4parse_free(parser);
|
||||
//! let parser = mp4parse_capi::mp4parse_new(&io);
|
||||
//! let rv = mp4parse_capi::mp4parse_read(parser);
|
||||
//! assert_eq!(rv, mp4parse_capi::mp4parse_error::MP4PARSE_OK);
|
||||
//! mp4parse_capi::mp4parse_free(parser);
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
@ -32,21 +34,24 @@
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
use std;
|
||||
extern crate mp4parse;
|
||||
|
||||
use std::io::Read;
|
||||
use std::collections::HashMap;
|
||||
|
||||
// Symbols we need from our rust api.
|
||||
use MediaContext;
|
||||
use TrackType;
|
||||
use read_mp4;
|
||||
use Error;
|
||||
use media_time_to_ms;
|
||||
use track_time_to_ms;
|
||||
use SampleEntry;
|
||||
use AudioCodecSpecific;
|
||||
use VideoCodecSpecific;
|
||||
use serialize_opus_header;
|
||||
use mp4parse::MediaContext;
|
||||
use mp4parse::TrackType;
|
||||
use mp4parse::read_mp4;
|
||||
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;
|
||||
|
||||
// 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
|
||||
@ -266,13 +271,24 @@ pub unsafe extern fn mp4parse_get_track_count(parser: *const mp4parse_parser, co
|
||||
let context = (*parser).context();
|
||||
|
||||
// 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;
|
||||
}
|
||||
*count = context.tracks.len() as u32;
|
||||
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`.
|
||||
#[no_mangle]
|
||||
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,
|
||||
};
|
||||
|
||||
// Maybe context & track should just have a single simple is_valid() instead?
|
||||
if context.timescale.is_none() ||
|
||||
context.tracks[track_index].timescale.is_none() ||
|
||||
context.tracks[track_index].duration.is_none() ||
|
||||
context.tracks[track_index].track_id.is_none() {
|
||||
return MP4PARSE_ERROR_INVALID;
|
||||
let track = &context.tracks[track_index];
|
||||
|
||||
if let (Some(track_timescale),
|
||||
Some(context_timescale),
|
||||
Some(track_duration)) = (track.timescale,
|
||||
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.media_time = track.media_time.map_or(0, |media_time| {
|
||||
track_time_to_ms(media_time, track.timescale.unwrap()) as i64
|
||||
}) - 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();
|
||||
info.track_id = match track.track_id {
|
||||
Some(track_id) => track_id,
|
||||
None => return MP4PARSE_ERROR_INVALID,
|
||||
};
|
||||
|
||||
MP4PARSE_OK
|
||||
}
|
||||
@ -438,6 +460,32 @@ pub unsafe extern fn mp4parse_get_track_video_info(parser: *mut mp4parse_parser,
|
||||
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)]
|
||||
extern fn panic_read(_: *mut u8, _: usize, _: *mut std::os::raw::c_void) -> isize {
|
||||
panic!("panic_read shouldn't be called in these tests");
|
||||
@ -614,7 +662,7 @@ fn get_track_count_poisoned_parser() {
|
||||
#[test]
|
||||
fn arg_validation_with_data() {
|
||||
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,
|
||||
userdata: &mut file as *mut _ as *mut std::os::raw::c_void };
|
||||
let parser = mp4parse_new(&io);
|
11
toolkit/library/rust/Cargo.lock
generated
11
toolkit/library/rust/Cargo.lock
generated
@ -2,7 +2,7 @@
|
||||
name = "gkrust"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"mp4parse 0.4.0",
|
||||
"mp4parse_capi 0.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -11,8 +11,15 @@ version = "0.5.3"
|
||||
|
||||
[[package]]
|
||||
name = "mp4parse"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"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"
|
||||
|
||||
[dependencies]
|
||||
mp4parse = { path = "../../../media/libstagefright/binding/mp4parse" }
|
||||
mp4parse_capi = { path = "../../../media/libstagefright/binding/mp4parse_capi" }
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
@ -2,4 +2,4 @@
|
||||
// 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/.
|
||||
|
||||
extern crate mp4parse;
|
||||
extern crate mp4parse_capi;
|
||||
|
Loading…
x
Reference in New Issue
Block a user