Bug 1363669 - update rust mp4 parser for mp4v. r=kinetik

MozReview-Commit-ID: 3HhKbIxTBPV

--HG--
extra : rebase_source : 6dcb95775b5b196d02fa2fce0083742e5fc703fa
This commit is contained in:
Alfredo Yang 2017-05-25 14:33:36 +08:00
Родитель 0725d6f5e0
Коммит a87d972281
7 изменённых файлов: 135 добавлений и 14 удалений

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

@ -38,6 +38,7 @@ typedef enum mp4parse_codec {
mp4parse_codec_AVC, mp4parse_codec_AVC,
mp4parse_codec_VP9, mp4parse_codec_VP9,
mp4parse_codec_MP3, mp4parse_codec_MP3,
mp4parse_codec_MP4V,
} mp4parse_codec; } mp4parse_codec;
typedef struct mp4parse_track_info { typedef struct mp4parse_track_info {

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

@ -116,6 +116,7 @@ box_database!(
AVC3SampleEntry 0x61766333, // "avc3" - Need to check official name in spec. AVC3SampleEntry 0x61766333, // "avc3" - Need to check official name in spec.
AVCConfigurationBox 0x61766343, // "avcC" AVCConfigurationBox 0x61766343, // "avcC"
MP4AudioSampleEntry 0x6d703461, // "mp4a" MP4AudioSampleEntry 0x6d703461, // "mp4a"
MP4VideoSampleEntry 0x6d703476, // "mp4v"
ESDBox 0x65736473, // "esds" ESDBox 0x65736473, // "esds"
VP8SampleEntry 0x76703038, // "vp08" VP8SampleEntry 0x76703038, // "vp08"
VP9SampleEntry 0x76703039, // "vp09" VP9SampleEntry 0x76703039, // "vp09"

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

@ -280,6 +280,7 @@ pub struct AudioSampleEntry {
pub enum VideoCodecSpecific { pub enum VideoCodecSpecific {
AVCConfig(Vec<u8>), AVCConfig(Vec<u8>),
VPxConfig(VPxConfigBox), VPxConfig(VPxConfigBox),
ESDSConfig(Vec<u8>),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -300,6 +301,7 @@ pub struct VPxConfigBox {
pub color_space: u8, // Really an enum pub color_space: u8, // Really an enum
pub chroma_subsampling: u8, pub chroma_subsampling: u8,
transfer_function: u8, transfer_function: u8,
matrix: Option<u8>, // Available in 'VP Codec ISO Media File Format' version 1 only.
video_full_range: bool, video_full_range: bool,
pub codec_init: Vec<u8>, // Empty for vp8/vp9. pub codec_init: Vec<u8>, // Empty for vp8/vp9.
} }
@ -400,7 +402,9 @@ pub enum CodecType {
AAC, AAC,
FLAC, FLAC,
Opus, Opus,
H264, H264, // 14496-10
MP4V, // 14496-2
VP10,
VP9, VP9,
VP8, VP8,
EncryptedVideo, EncryptedVideo,
@ -1248,20 +1252,35 @@ fn read_stts<T: Read>(src: &mut BMFFBox<T>) -> Result<TimeToSampleBox> {
/// Parse a VPx Config Box. /// Parse a VPx Config Box.
fn read_vpcc<T: Read>(src: &mut BMFFBox<T>) -> Result<VPxConfigBox> { fn read_vpcc<T: Read>(src: &mut BMFFBox<T>) -> Result<VPxConfigBox> {
let (version, _) = read_fullbox_extra(src)?; let (version, _) = read_fullbox_extra(src)?;
if version != 0 { let supported_versions = [0, 1];
if ! supported_versions.contains(&version) {
return Err(Error::Unsupported("unknown vpcC version")); return Err(Error::Unsupported("unknown vpcC version"));
} }
let profile = src.read_u8()?; let profile = src.read_u8()?;
let level = src.read_u8()?; let level = src.read_u8()?;
let (bit_depth, color_space) = { let (bit_depth, color_space, chroma_subsampling, transfer_function, matrix, video_full_range) =
let byte = src.read_u8()?; if version == 0 {
((byte >> 4) & 0x0f, byte & 0x0f) let (bit_depth, color_space) = {
}; let byte = src.read_u8()?;
let (chroma_subsampling, transfer_function, video_full_range) = { ((byte >> 4) & 0x0f, byte & 0x0f)
let byte = src.read_u8()?; };
((byte >> 4) & 0x0f, (byte >> 1) & 0x07, (byte & 1) == 1) let (chroma_subsampling, transfer_function, video_full_range) = {
}; let byte = src.read_u8()?;
((byte >> 4) & 0x0f, (byte >> 1) & 0x07, (byte & 1) == 1)
};
(bit_depth, color_space, chroma_subsampling, transfer_function, None, video_full_range)
} else {
let (bit_depth, chroma_subsampling, video_full_range) = {
let byte = src.read_u8()?;
((byte >> 4) & 0x0f, (byte >> 1) & 0x07, (byte & 1) == 1)
};
let color_space = src.read_u8()?;
let transfer_function = src.read_u8()?;
let matrix = src.read_u8()?;
(bit_depth, color_space, chroma_subsampling, transfer_function, Some(matrix), video_full_range)
};
let codec_init_size = be_u16(src)?; let codec_init_size = be_u16(src)?;
let codec_init = read_buf(src, codec_init_size as usize)?; let codec_init = read_buf(src, codec_init_size as usize)?;
@ -1274,6 +1293,7 @@ fn read_vpcc<T: Read>(src: &mut BMFFBox<T>) -> Result<VPxConfigBox> {
color_space: color_space, color_space: color_space,
chroma_subsampling: chroma_subsampling, chroma_subsampling: chroma_subsampling,
transfer_function: transfer_function, transfer_function: transfer_function,
matrix: matrix,
video_full_range: video_full_range, video_full_range: video_full_range,
codec_init: codec_init, codec_init: codec_init,
}) })
@ -1640,6 +1660,7 @@ fn read_video_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<(CodecType,
let name = src.get_header().name; let name = src.get_header().name;
let codec_type = match name { let codec_type = match name {
BoxType::AVCSampleEntry | BoxType::AVC3SampleEntry => CodecType::H264, BoxType::AVCSampleEntry | BoxType::AVC3SampleEntry => CodecType::H264,
BoxType::MP4VideoSampleEntry => CodecType::MP4V,
BoxType::VP8SampleEntry => CodecType::VP8, BoxType::VP8SampleEntry => CodecType::VP8,
BoxType::VP9SampleEntry => CodecType::VP9, BoxType::VP9SampleEntry => CodecType::VP9,
BoxType::ProtectedVisualSampleEntry => CodecType::EncryptedVideo, BoxType::ProtectedVisualSampleEntry => CodecType::EncryptedVideo,
@ -1689,6 +1710,15 @@ fn read_video_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<(CodecType,
let vpcc = read_vpcc(&mut b)?; let vpcc = read_vpcc(&mut b)?;
codec_specific = Some(VideoCodecSpecific::VPxConfig(vpcc)); codec_specific = Some(VideoCodecSpecific::VPxConfig(vpcc));
} }
BoxType::ESDBox => {
if name != BoxType::MP4VideoSampleEntry || codec_specific.is_some() {
return Err(Error::InvalidData("malformed video sample entry"));
}
let (_, _) = read_fullbox_extra(&mut b.content)?;
let esds_size = b.head.size - b.head.offset - 4;
let esds = read_buf(&mut b.content, esds_size as usize)?;
codec_specific = Some(VideoCodecSpecific::ESDSConfig(esds));
}
BoxType::ProtectionSchemeInformationBox => { BoxType::ProtectionSchemeInformationBox => {
if name != BoxType::ProtectedVisualSampleEntry { if name != BoxType::ProtectedVisualSampleEntry {
return Err(Error::InvalidData("malformed video sample entry")); return Err(Error::InvalidData("malformed video sample entry"));

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

@ -371,7 +371,7 @@ fn read_mvhd_unknown_duration() {
} }
#[test] #[test]
fn read_vpcc() { fn read_vpcc_version_0() {
let data_length = 12u16; let data_length = 12u16;
let mut stream = make_fullbox(BoxSize::Auto, b"vpcC", 0, |s| { let mut stream = make_fullbox(BoxSize::Auto, b"vpcC", 0, |s| {
s.B8(2) s.B8(2)
@ -388,6 +388,36 @@ fn read_vpcc() {
assert!(r.is_ok()); assert!(r.is_ok());
} }
// TODO: it'd be better to find a real sample here.
#[test]
fn read_vpcc_version_1() {
let data_length = 12u16;
let mut stream = make_fullbox(BoxSize::Auto, b"vpcC", 1, |s| {
s.B8(2) // profile
.B8(0) // level
.B8(0b1000_011_0) // bitdepth (4 bits), chroma (3 bits), video full range (1 bit)
.B8(1) // color primaries
.B8(1) // transfer characteristics
.B8(1) // matrix
.B16(data_length)
.append_repeated(42, data_length as usize)
});
let mut iter = super::BoxIter::new(&mut stream);
let mut stream = iter.next_box().unwrap().unwrap();
assert_eq!(stream.head.name, BoxType::VPCodecConfigurationBox);
let r = super::read_vpcc(&mut stream);
match r {
Ok(vpcc) => {
assert_eq!(vpcc.bit_depth, 8);
assert_eq!(vpcc.chroma_subsampling, 3);
assert_eq!(vpcc.video_full_range, false);
assert_eq!(vpcc.matrix.unwrap(), 1);
},
_ => panic!("vpcc parsing error"),
}
}
#[test] #[test]
fn read_hdlr() { fn read_hdlr() {
let mut stream = make_fullbox(BoxSize::Short(45), b"hdlr", 0, |s| { let mut stream = make_fullbox(BoxSize::Short(45), b"hdlr", 0, |s| {
@ -870,6 +900,55 @@ fn read_esds() {
assert_eq!(es.decoder_specific_data, aac_dc_descriptor); assert_eq!(es.decoder_specific_data, aac_dc_descriptor);
} }
#[test]
fn read_stsd_mp4v() {
let mp4v =
vec![
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xd0, 0x01, 0xe0, 0x00, 0x48,
0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x18, 0xff, 0xff,
0x00, 0x00, 0x00, 0x4c, 0x65, 0x73, 0x64, 0x73, 0x00, 0x00, 0x00, 0x00,
0x03, 0x3e, 0x00, 0x00, 0x1f, 0x04, 0x36, 0x20, 0x11, 0x01, 0x77, 0x00,
0x00, 0x03, 0xe8, 0x00, 0x00, 0x03, 0xe8, 0x00, 0x05, 0x27, 0x00, 0x00,
0x01, 0xb0, 0x05, 0x00, 0x00, 0x01, 0xb5, 0x0e, 0xcf, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x86, 0xe0, 0x00, 0x2e, 0xa6, 0x60,
0x16, 0xf4, 0x01, 0xf4, 0x24, 0xc8, 0x01, 0xe5, 0x16, 0x84, 0x3c, 0x14,
0x63, 0x06, 0x01, 0x02,
];
let esds_specific_data = &mp4v[90 ..];
println!("esds_specific_data {:?}", esds_specific_data);
let mut stream = make_box(BoxSize::Auto, b"mp4v", |s| {
s.append_bytes(mp4v.as_slice())
});
let mut iter = super::BoxIter::new(&mut stream);
let mut stream = iter.next_box().unwrap().unwrap();
let (codec_type, sample_entry) = super::read_video_sample_entry(&mut stream).unwrap();
assert_eq!(codec_type, super::CodecType::MP4V);
match sample_entry {
super::SampleEntry::Video(v) => {
assert_eq!(v.width, 720);
assert_eq!(v.height, 480);
match v.codec_specific {
super::VideoCodecSpecific::ESDSConfig(esds_data) => {
assert_eq!(esds_data, esds_specific_data.to_vec());
},
_ => panic!("it should be ESDSConfig!"),
}
},
_ => panic!("it should be a video sample entry!"),
}
}
#[test] #[test]
fn read_esds_one_byte_extension_descriptor() { fn read_esds_one_byte_extension_descriptor() {
let esds = let esds =

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

@ -56,6 +56,10 @@ fn public_api() {
assert!(!vpx.codec_init.is_empty()); assert!(!vpx.codec_init.is_empty());
"VPx" "VPx"
} }
mp4::VideoCodecSpecific::ESDSConfig(mp4v) => {
assert!(!mp4v.is_empty());
"MP4V"
}
}, "AVC"); }, "AVC");
} }
Some(mp4::SampleEntry::Audio(a)) => { Some(mp4::SampleEntry::Audio(a)) => {

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

@ -94,6 +94,7 @@ pub enum mp4parse_codec {
AVC, AVC,
VP9, VP9,
MP3, MP3,
MP4V,
} }
impl Default for mp4parse_codec { impl Default for mp4parse_codec {
@ -433,6 +434,8 @@ pub unsafe extern fn mp4parse_get_track_info(parser: *mut mp4parse_parser, track
mp4parse_codec::VP9, mp4parse_codec::VP9,
VideoCodecSpecific::AVCConfig(_) => VideoCodecSpecific::AVCConfig(_) =>
mp4parse_codec::AVC, mp4parse_codec::AVC,
VideoCodecSpecific::ESDSConfig(_) =>
mp4parse_codec::MP4V,
}, },
_ => mp4parse_codec::UNKNOWN, _ => mp4parse_codec::UNKNOWN,
}; };
@ -625,8 +628,11 @@ pub unsafe extern fn mp4parse_get_track_video_info(parser: *mut mp4parse_parser,
(*info).image_width = video.width; (*info).image_width = video.width;
(*info).image_height = video.height; (*info).image_height = video.height;
if let VideoCodecSpecific::AVCConfig(ref avc) = video.codec_specific { match video.codec_specific {
(*info).extra_data.set_data(avc); VideoCodecSpecific::AVCConfig(ref data) | VideoCodecSpecific::ESDSConfig(ref data) => {
(*info).extra_data.set_data(data);
},
_ => {}
} }
if let Some(p) = video.protection_info.iter().find(|sinf| sinf.tenc.is_some()) { if let Some(p) = video.protection_info.iter().find(|sinf| sinf.tenc.is_some()) {

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

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