Skip to content

Commit 2e2c39a

Browse files
authored
Merge pull request #296 from dreamaniajp/master
Add support for MPEG-4 Part 2 video codec (ISO 14496-2).
2 parents db11833 + 5961927 commit 2e2c39a

File tree

7 files changed

+78
-11
lines changed

7 files changed

+78
-11
lines changed

mp4parse/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ criterion = "0.3"
4444
3gpp = []
4545
meta-xml = []
4646
unstable-api = []
47+
mp4v = []
4748

4849
[[bench]]
4950
name = "avif_benchmark"

mp4parse/src/lib.rs

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,8 @@ pub struct ES_Descriptor {
407407
pub extended_audio_object_type: Option<u16>,
408408
pub audio_sample_rate: Option<u32>,
409409
pub audio_channel_count: Option<u16>,
410+
#[cfg(feature = "mp4v")]
411+
pub video_codec: CodecType,
410412
pub codec_esds: TryVec<u8>,
411413
pub decoder_specific_data: TryVec<u8>, // Data in DECODER_SPECIFIC_TAG
412414
}
@@ -3725,6 +3727,14 @@ fn get_audio_object_type(bit_reader: &mut BitReader) -> Result<u16> {
37253727

37263728
/// See MPEG-4 Systems (ISO 14496-1:2010) § 7.2.6.7 and probably 14496-3 somewhere?
37273729
fn read_ds_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
3730+
#[cfg(feature = "mp4v")]
3731+
// Check if we are in a Visual esda Box.
3732+
if esds.video_codec != CodecType::Unknown {
3733+
esds.decoder_specific_data.extend_from_slice(data)?;
3734+
return Ok(());
3735+
}
3736+
3737+
// We are in an Audio esda Box.
37283738
let frequency_table = vec![
37293739
(0x0, 96000),
37303740
(0x1, 88200),
@@ -3899,6 +3909,14 @@ fn read_dc_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
38993909
let des = &mut Cursor::new(data);
39003910
let object_profile = des.read_u8()?;
39013911

3912+
#[cfg(feature = "mp4v")]
3913+
{
3914+
esds.video_codec = match object_profile {
3915+
0x20..=0x24 => CodecType::MP4V,
3916+
_ => CodecType::Unknown,
3917+
};
3918+
}
3919+
39023920
// Skip uninteresting fields.
39033921
skip(des, 12)?;
39043922

@@ -4214,16 +4232,27 @@ fn read_video_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleEntry>
42144232
if name != BoxType::MP4VideoSampleEntry || codec_specific.is_some() {
42154233
return Err(Error::InvalidData("malformed video sample entry"));
42164234
}
4217-
let (_, _) = read_fullbox_extra(&mut b.content)?;
4218-
// Subtract 4 extra to offset the members of fullbox not
4219-
// accounted for in head.offset
4220-
let esds_size = b
4221-
.head
4222-
.size
4223-
.checked_sub(b.head.offset + 4)
4224-
.expect("offset invalid");
4225-
let esds = read_buf(&mut b.content, esds_size)?;
4226-
codec_specific = Some(VideoCodecSpecific::ESDSConfig(esds));
4235+
#[cfg(not(feature = "mp4v"))]
4236+
{
4237+
let (_, _) = read_fullbox_extra(&mut b.content)?;
4238+
// Subtract 4 extra to offset the members of fullbox not
4239+
// accounted for in head.offset
4240+
let esds_size = b
4241+
.head
4242+
.size
4243+
.checked_sub(b.head.offset + 4)
4244+
.expect("offset invalid");
4245+
let esds = read_buf(&mut b.content, esds_size)?;
4246+
codec_specific = Some(VideoCodecSpecific::ESDSConfig(esds));
4247+
}
4248+
#[cfg(feature = "mp4v")]
4249+
{
4250+
// Read ES_Descriptor inside an esds box.
4251+
// See ISOBMFF (ISO 14496-1:2010 §7.2.6.5)
4252+
let esds = read_esds(&mut b)?;
4253+
codec_specific =
4254+
Some(VideoCodecSpecific::ESDSConfig(esds.decoder_specific_data));
4255+
}
42274256
}
42284257
BoxType::ProtectionSchemeInfoBox => {
42294258
if name != BoxType::ProtectedVisualSampleEntry {

mp4parse/src/tests.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1039,8 +1039,10 @@ fn read_stsd_mp4v() {
10391039
0x2e, 0xa6, 0x60, 0x16, 0xf4, 0x01, 0xf4, 0x24, 0xc8, 0x01, 0xe5, 0x16, 0x84, 0x3c, 0x14,
10401040
0x63, 0x06, 0x01, 0x02,
10411041
];
1042-
1042+
#[cfg(not(feature = "mp4v"))]
10431043
let esds_specific_data = &mp4v[90..];
1044+
#[cfg(feature = "mp4v")]
1045+
let esds_specific_data = &mp4v[112..151];
10441046
println!("esds_specific_data {:?}", esds_specific_data);
10451047

10461048
let mut stream = make_box(BoxSize::Auto, b"mp4v", |s| s.append_bytes(mp4v.as_slice()));
Binary file not shown.

mp4parse/tests/public.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ static AUDIO_AMRNB_3GP: &str = "tests/amr_nb_1f.3gp";
7979
// "ffmpeg -i [input file] -f 3gp -acodec amr_wb -ar 16000 -ac 1 -frames:a 1 -vn output.3gp"
8080
#[cfg(feature = "3gpp")]
8181
static AUDIO_AMRWB_3GP: &str = "tests/amr_wb_1f.3gp";
82+
#[cfg(feature = "mp4v")]
83+
// The 1 frame mp4v mp4 file can be generated by ffmpeg with command
84+
// "ffmpeg -i [input file] -f mp4 -c:v mpeg4 -vf scale=176x144 -frames:v 1 -an output.mp4"
85+
static VIDEO_MP4V_MP4: &str = "tests/bbb_sunflower_QCIF_30fps_mp4v_noaudio_1f.mp4";
8286

8387
// Adapted from https://github.com/GuillaumeGomez/audio-video-metadata/blob/9dff40f565af71d5502e03a2e78ae63df95cfd40/src/metadata.rs#L53
8488
#[test]
@@ -1054,3 +1058,30 @@ fn public_audio_amrwb() {
10541058
};
10551059
}
10561060
}
1061+
1062+
#[test]
1063+
#[cfg(feature = "mp4v")]
1064+
fn public_video_mp4v() {
1065+
let mut fd = File::open(VIDEO_MP4V_MP4).expect("Unknown file");
1066+
let mut buf = Vec::new();
1067+
fd.read_to_end(&mut buf).expect("File error");
1068+
1069+
let mut c = Cursor::new(&buf);
1070+
let context = mp4::read_mp4(&mut c).expect("read_mp4 failed");
1071+
for track in context.tracks {
1072+
let stsd = track.stsd.expect("expected an stsd");
1073+
let v = match stsd.descriptions.first().expect("expected a SampleEntry") {
1074+
mp4::SampleEntry::Video(ref v) => v,
1075+
_ => panic!("expected a VideoSampleEntry"),
1076+
};
1077+
assert_eq!(v.codec_type, mp4::CodecType::MP4V);
1078+
assert_eq!(v.width, 176);
1079+
assert_eq!(v.height, 144);
1080+
let _codec_specific = match v.codec_specific {
1081+
mp4::VideoCodecSpecific::ESDSConfig(_) => true,
1082+
_ => {
1083+
panic!("expected a ESDSConfig",);
1084+
}
1085+
};
1086+
}
1087+
}

mp4parse_capi/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,4 @@ env_logger = "0.8"
3636
[features]
3737
3gpp = ["mp4parse/3gpp"]
3838
meta-xml = ["mp4parse/meta-xml"]
39+
mp4v = ["mp4parse/mp4v"]

mp4parse_capi/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,9 @@ fn mp4parse_get_track_video_info_safe(
973973
VideoCodecSpecific::AV1Config(_) => Mp4parseCodec::Av1,
974974
VideoCodecSpecific::AVCConfig(_) => Mp4parseCodec::Avc,
975975
VideoCodecSpecific::H263Config(_) => Mp4parseCodec::H263,
976+
#[cfg(feature = "mp4v")]
977+
VideoCodecSpecific::ESDSConfig(_) => Mp4parseCodec::Mp4v,
978+
#[cfg(not(feature = "mp4v"))]
976979
VideoCodecSpecific::ESDSConfig(_) =>
977980
// MP4V (14496-2) video is unsupported.
978981
{

0 commit comments

Comments
 (0)