Bug 1238420 - Update mp4parse-rust to 0.1.6. r=kinetik

Bump default version in the update script and run it against
the tagged v0.1.6 upstream repo.
This commit is contained in:
Matthew Gregan 2016-01-11 11:02:00 +13:00
parent 3d32a4fdf1
commit 5e513e1a31
4 changed files with 718 additions and 508 deletions

File diff suppressed because it is too large Load Diff

View File

@ -34,16 +34,30 @@ use media_time_to_ms;
use track_time_to_ms;
use SampleEntry;
// These constants *must* match those in include/mp4parse.h.
/// Map Error to int32 return codes.
const MP4PARSE_OK: i32 = 0;
const MP4PARSE_ERROR_BADARG: i32 = -1;
const MP4PARSE_ERROR_INVALID: i32 = -2;
const MP4PARSE_ERROR_UNSUPPORTED: i32 = -3;
const MP4PARSE_ERROR_EOF: i32 = -4;
const MP4PARSE_ASSERT: i32 = -5;
const MP4PARSE_ERROR_IO: i32 = -6;
/// Map TrackType to uint32 constants.
const TRACK_TYPE_H264: u32 = 0;
const TRACK_TYPE_AAC: u32 = 1;
const TRACK_TYPE_AAC: u32 = 1;
// These structs *must* match those declared in include/mp4parse.h.
#[repr(C)]
pub struct TrackInfo {
track_type: u32,
track_id: u32,
duration: u64,
media_time: i64, // wants to be u64? understand how elst adjustment works
// TODO(kinetik): include crypto guff
}
#[repr(C)]
@ -51,8 +65,11 @@ pub struct TrackAudioInfo {
channels: u16,
bit_depth: u16,
sample_rate: u32,
// profile: i32,
// extended_profile: i32, // check types
// TODO(kinetik):
// int32_t profile;
// int32_t extended_profile; // check types
// extra_data
// codec_specific_config
}
#[repr(C)]
@ -61,8 +78,13 @@ pub struct TrackVideoInfo {
display_height: u32,
image_width: u16,
image_height: u16,
// TODO(kinetik):
// extra_data
// codec_specific_config
}
// C API wrapper functions.
/// Allocate an opaque rust-side parser context.
#[no_mangle]
pub extern "C" fn mp4parse_new() -> *mut MediaContext {
@ -78,7 +100,7 @@ pub unsafe extern "C" fn mp4parse_free(context: *mut MediaContext) {
}
/// Feed a buffer through `read_mp4()` with the given rust-side
/// parser context, returning the number of detected tracks.
/// parser context, returning success or an error code.
///
/// This is safe to call with NULL arguments but will crash
/// if given invalid pointers, as is usual for C.
@ -86,7 +108,7 @@ pub unsafe extern "C" fn mp4parse_free(context: *mut MediaContext) {
pub unsafe extern "C" fn mp4parse_read(context: *mut MediaContext, buffer: *const u8, size: usize) -> i32 {
// Validate arguments from C.
if context.is_null() || buffer.is_null() || size < 8 {
return -1;
return MP4PARSE_ERROR_BADARG;
}
let mut context: &mut MediaContext = &mut *context;
@ -96,24 +118,38 @@ pub unsafe extern "C" fn mp4parse_read(context: *mut MediaContext, buffer: *cons
let mut c = Cursor::new(b);
// Parse in a subthread to catch any panics.
let task = std::thread::spawn(move || {
match read_mp4(&mut c, &mut context) {
Ok(_) => {},
Err(Error::UnexpectedEOF) => {},
Err(e) => { panic!(e); },
}
// Make sure the track count fits in an i32 so we can use
// negative values for failure.
assert!(context.tracks.len() < i32::max_value() as usize);
context.tracks.len() as i32
});
task.join().unwrap_or(-1)
let task = std::thread::spawn(move || read_mp4(&mut c, &mut context));
// The task's JoinHandle will return an error result if the
// thread panicked, and will wrap the closure's return'd
// result in an Ok(..) otherwise, meaning we could see
// Ok(Err(Error::..)) here. So map thread failures back
// to an mp4parse::Error before converting to a C return value.
match task.join().or(Err(Error::AssertCaught)) {
Ok(_) => MP4PARSE_OK,
Err(Error::InvalidData) => MP4PARSE_ERROR_INVALID,
Err(Error::Unsupported) => MP4PARSE_ERROR_UNSUPPORTED,
Err(Error::UnexpectedEOF) => MP4PARSE_ERROR_EOF,
Err(Error::AssertCaught) => MP4PARSE_ASSERT,
Err(Error::Io(_)) => MP4PARSE_ERROR_IO,
}
}
/// Return the number of tracks parsed by previous `read_mp4()` calls.
#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_count(context: *const MediaContext) -> u32 {
// Validate argument from C.
assert!(!context.is_null());
let context = &*context;
// Make sure the track count fits in a u32.
assert!(context.tracks.len() < u32::max_value() as usize);
context.tracks.len() as u32
}
#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_info(context: *mut MediaContext, track: i32, info: *mut TrackInfo) -> i32 {
if context.is_null() || track < 0 || info.is_null() {
return -1;
pub unsafe extern "C" fn mp4parse_get_track_info(context: *mut MediaContext, track: u32, info: *mut TrackInfo) -> i32 {
if context.is_null() || info.is_null() {
return MP4PARSE_ERROR_BADARG;
}
let context: &mut MediaContext = &mut *context;
@ -121,13 +157,13 @@ pub unsafe extern "C" fn mp4parse_get_track_info(context: *mut MediaContext, tra
let info: &mut TrackInfo = &mut *info;
if track_index >= context.tracks.len() {
return -1;
return MP4PARSE_ERROR_BADARG;
}
info.track_type = match context.tracks[track_index].track_type {
TrackType::Video => TRACK_TYPE_H264,
TrackType::Audio => TRACK_TYPE_AAC,
TrackType::Unknown => return -1,
TrackType::Unknown => return MP4PARSE_ERROR_UNSUPPORTED,
};
// Maybe context & track should just have a single simple is_valid() instead?
@ -135,8 +171,8 @@ pub unsafe extern "C" fn mp4parse_get_track_info(context: *mut MediaContext, tra
context.tracks[track_index].timescale.is_none() ||
context.tracks[track_index].duration.is_none() ||
context.tracks[track_index].track_id.is_none() {
return -1;
}
return MP4PARSE_ERROR_INVALID;
}
std::thread::spawn(move || {
let track = &context.tracks[track_index];
@ -152,98 +188,102 @@ pub unsafe extern "C" fn mp4parse_get_track_info(context: *mut MediaContext, tra
};
info.duration = track_time_to_ms(track.duration.unwrap(), track.timescale.unwrap());
info.track_id = track.track_id.unwrap();
0
}).join().unwrap_or(-1)
MP4PARSE_OK
}).join().unwrap_or(MP4PARSE_ERROR_INVALID)
}
#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_audio_info(context: *mut MediaContext, track: i32, info: *mut TrackAudioInfo) -> i32 {
if context.is_null() || track < 0 || info.is_null() {
return -1;
pub unsafe extern "C" fn mp4parse_get_track_audio_info(context: *mut MediaContext, track: u32, info: *mut TrackAudioInfo) -> i32 {
if context.is_null() || info.is_null() {
return MP4PARSE_ERROR_BADARG;
}
let context: &mut MediaContext = &mut *context;
if track as usize >= context.tracks.len() {
return -1;
return MP4PARSE_ERROR_BADARG;
}
let track = &context.tracks[track as usize];
match track.track_type {
TrackType::Audio => {},
_ => return -1,
TrackType::Audio => {}
_ => return MP4PARSE_ERROR_INVALID,
};
let audio = match track.data {
Some(ref data) => data,
None => return -1,
None => return MP4PARSE_ERROR_INVALID,
};
let audio = match audio {
&SampleEntry::Audio(ref x) => x,
_ => return -1,
let audio = match *audio {
SampleEntry::Audio(ref x) => x,
_ => return MP4PARSE_ERROR_INVALID,
};
(*info).channels = audio.channelcount;
(*info).bit_depth = audio.samplesize;
(*info).sample_rate = audio.samplerate >> 16; // 16.16 fixed point
0
MP4PARSE_OK
}
#[no_mangle]
pub unsafe extern "C" fn mp4parse_get_track_video_info(context: *mut MediaContext, track: i32, info: *mut TrackVideoInfo) -> i32 {
if context.is_null() || track < 0 || info.is_null() {
return -1;
pub unsafe extern "C" fn mp4parse_get_track_video_info(context: *mut MediaContext, track: u32, info: *mut TrackVideoInfo) -> i32 {
if context.is_null() || info.is_null() {
return MP4PARSE_ERROR_BADARG;
}
let context: &mut MediaContext = &mut *context;
if track as usize >= context.tracks.len() {
return -1;
return MP4PARSE_ERROR_BADARG;
}
let track = &context.tracks[track as usize];
match track.track_type {
TrackType::Video => {},
_ => return -1,
TrackType::Video => {}
_ => return MP4PARSE_ERROR_INVALID,
};
let video = match track.data {
Some(ref data) => data,
None => return -1,
None => return MP4PARSE_ERROR_INVALID,
};
let video = match video {
&SampleEntry::Video(ref x) => x,
_ => return -1,
let video = match *video {
SampleEntry::Video(ref x) => x,
_ => return MP4PARSE_ERROR_INVALID,
};
if let Some(ref tkhd) = track.tkhd {
(*info).display_width = tkhd.width >> 16; // 16.16 fixed point
(*info).display_height = tkhd.height >> 16; // 16.16 fixed point
} else {
return -1
return MP4PARSE_ERROR_INVALID;
}
(*info).image_width = video.width;
(*info).image_width = video.height;
0
MP4PARSE_OK
}
#[test]
fn new_context() {
let context = mp4parse_new();
assert!(!context.is_null());
unsafe { mp4parse_free(context); }
unsafe {
mp4parse_free(context);
}
}
#[test]
#[should_panic(expected = "assertion failed")]
fn free_null_context() {
unsafe { mp4parse_free(std::ptr::null_mut()); }
unsafe {
mp4parse_free(std::ptr::null_mut());
}
}
#[test]
@ -257,16 +297,21 @@ fn arg_validation() {
let buffer = vec![0u8; 8];
unsafe {
assert_eq!(-1, mp4parse_read(null_context, null_buffer, 0));
assert_eq!(-1, mp4parse_read(context, null_buffer, 0));
assert_eq!(MP4PARSE_ERROR_BADARG,
mp4parse_read(null_context, null_buffer, 0));
assert_eq!(MP4PARSE_ERROR_BADARG,
mp4parse_read(context, null_buffer, 0));
}
for size in 0..buffer.len() {
println!("testing buffer length {}", size);
unsafe {
assert_eq!(-1, mp4parse_read(context, buffer.as_ptr(), size));
assert_eq!(MP4PARSE_ERROR_BADARG,
mp4parse_read(context, buffer.as_ptr(), size));
}
}
unsafe { mp4parse_free(context); }
unsafe {
mp4parse_free(context);
}
}

View File

@ -11,6 +11,14 @@ extern "C" {
struct mp4parse_state;
#define MP4PARSE_OK 0
#define MP4PARSE_ERROR_BADARG -1 // Argument validation failure
#define MP4PARSE_ERROR_INVALID -2 // Error::InvalidData
#define MP4PARSE_ERROR_UNSUPPORTED -3 // Error::Unsupported
#define MP4PARSE_ERROR_EOF -4 // Error::UnexpectedEOF
#define MP4PARSE_ASSERT -5 // Error::AssertCaught
#define MP4PARSE_ERROR_IO -6 // Error::Io(_)
#define MP4PARSE_TRACK_TYPE_H264 0 // "video/avc"
#define MP4PARSE_TRACK_TYPE_AAC 1 // "audio/mp4a-latm"
@ -18,12 +26,6 @@ struct mp4parse_track_audio_info {
uint16_t channels;
uint16_t bit_depth;
uint32_t sample_rate;
//int32_t profile;
//int32_t extended_profile; // check types
// TODO(kinetik):
// extra_data
// codec_specific_config
};
struct mp4parse_track_video_info {
@ -31,10 +33,6 @@ struct mp4parse_track_video_info {
uint32_t display_height;
uint16_t image_width;
uint16_t image_height;
// TODO(kinetik):
// extra_data
// codec_specific_config
};
struct mp4parse_track_info {
@ -42,7 +40,6 @@ struct mp4parse_track_info {
uint32_t track_id;
uint64_t duration;
int64_t media_time;
// TODO(kinetik): crypto guff
};
struct mp4parse_state* mp4parse_new(void);
@ -50,11 +47,13 @@ void mp4parse_free(struct mp4parse_state* state);
int32_t mp4parse_read(struct mp4parse_state* state, uint8_t *buffer, size_t size);
int32_t mp4parse_get_track_info(struct mp4parse_state* state, int32_t track, struct mp4parse_track_info* track_info);
uint32_t mp4parse_get_track_count(struct mp4parse_state* state);
int32_t mp4parse_get_track_audio_info(struct mp4parse_state* state, int32_t track, struct mp4parse_track_audio_info* track_info);
int32_t mp4parse_get_track_info(struct mp4parse_state* state, uint32_t track, struct mp4parse_track_info* track_info);
int32_t mp4parse_get_track_video_info(struct mp4parse_state* state, int32_t track, struct mp4parse_track_video_info* track_info);
int32_t mp4parse_get_track_audio_info(struct mp4parse_state* state, uint32_t track, struct mp4parse_track_audio_info* track_info);
int32_t mp4parse_get_track_video_info(struct mp4parse_state* state, uint32_t track, struct mp4parse_track_video_info* track_info);
#ifdef __cplusplus
}

View File

@ -2,7 +2,7 @@
# Script to update mp4parse-rust sources to latest upstream
# Default version.
VER=v0.1.4
VER=v0.1.6
# Accept version or commit from the command line.
if test -n "$1"; then