Skip to content

Commit db0506f

Browse files
alfredoyangkinetiknz
authored andcommitted
Parse ESDS. (#38)
* Parse ESDS. Structure of ESDS: ESDS box | |- ES descriptor |- 3 bytes extension (optional) |- 1 byte length |- 2 bytes ES ID |- 1 byte stream priority and flags |- stream dependency (optional, depends on flags) | |- 2 bytes |- url (optional, depends on flags) | |- 1 byte length | |- x bytes, x is the length | |- Decoder Config descriptior |- 3 bytes extension (optional) |- 1 byte length |- 1 byte object profile indicator We need to get object profile indicator for the codec type.
1 parent 1cc0580 commit db0506f

File tree

4 files changed

+111
-16
lines changed

4 files changed

+111
-16
lines changed

mp4parse/src/lib.rs

Lines changed: 90 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ extern crate afl;
1111
extern crate byteorder;
1212
use byteorder::ReadBytesExt;
1313
use std::io::{Read, Take};
14+
use std::io::Cursor;
1415
use std::cmp;
1516

1617
mod boxes;
@@ -203,10 +204,17 @@ pub enum SampleEntry {
203204
Unknown,
204205
}
205206

207+
#[allow(non_camel_case_types)]
208+
#[derive(Debug, Clone)]
209+
pub struct ES_Descriptor {
210+
pub audio_codec: CodecType,
211+
pub codec_specific_config: Vec<u8>,
212+
}
213+
206214
#[allow(non_camel_case_types)]
207215
#[derive(Debug, Clone)]
208216
pub enum AudioCodecSpecific {
209-
ES_Descriptor(Vec<u8>),
217+
ES_Descriptor(ES_Descriptor),
210218
FLACSpecificBox(FLACSpecificBox),
211219
OpusSpecificBox(OpusSpecificBox),
212220
}
@@ -310,9 +318,10 @@ impl Default for TrackType {
310318
fn default() -> Self { TrackType::Unknown }
311319
}
312320

313-
#[derive(Debug)]
321+
#[derive(Debug, Clone, Copy, PartialEq)]
314322
pub enum CodecType {
315323
Unknown,
324+
MP3,
316325
AAC,
317326
FLAC,
318327
Opus,
@@ -1105,16 +1114,84 @@ fn read_flac_metadata<T: Read>(src: &mut BMFFBox<T>) -> Result<FLACMetadataBlock
11051114
})
11061115
}
11071116

1108-
fn read_esds<T: Read>(src: &mut BMFFBox<T>) -> Result<AudioCodecSpecific> {
1117+
fn read_esds<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
1118+
// Tags for elementary stream description
1119+
const ESDESCR_TAG: u8 = 0x03;
1120+
const DECODER_CONFIG_TAG: u8 = 0x04;
1121+
11091122
let (_, _) = try!(read_fullbox_extra(src));
11101123

11111124
let esds_size = src.head.size - src.head.offset - 4;
11121125
if esds_size > BUF_SIZE_LIMIT {
11131126
return Err(Error::InvalidData("esds box exceeds BUF_SIZE_LIMIT"));
11141127
}
1115-
let esds = try!(read_buf(&mut src.content, esds_size as usize));
1128+
let esds_array = try!(read_buf(src, esds_size as usize));
1129+
1130+
// Parsing DecoderConfig descriptor to get the object_profile_indicator
1131+
// for correct codec type.
1132+
let object_profile_indicator = {
1133+
// clone a esds cursor for parsing.
1134+
let esds = &mut Cursor::new(&esds_array);
1135+
let esds_tag = try!(esds.read_u8());
1136+
1137+
if esds_tag != ESDESCR_TAG {
1138+
return Err(Error::Unsupported("fail to parse ES descriptor"));
1139+
}
1140+
1141+
let esds_extend = try!(esds.read_u8());
1142+
// extension tag start from 0x80.
1143+
if esds_extend >= 0x80 {
1144+
// skip remaining extension and length.
1145+
try!(skip(esds, 5));
1146+
} else {
1147+
try!(skip(esds, 2));
1148+
}
1149+
1150+
let esds_flags = try!(esds.read_u8());
11161151

1117-
Ok(AudioCodecSpecific::ES_Descriptor(esds))
1152+
// Stream dependency flag, first bit from left most.
1153+
if esds_flags & 0x80 > 0 {
1154+
// Skip uninteresting fields.
1155+
try!(skip(esds, 2));
1156+
}
1157+
1158+
// Url flag, second bit from left most.
1159+
if esds_flags & 0x40 > 0 {
1160+
// Skip uninteresting fields.
1161+
let skip_es_len: usize = try!(esds.read_u8()) as usize + 2;
1162+
try!(skip(esds, skip_es_len));
1163+
}
1164+
1165+
// find DecoderConfig descriptor (tag = DECODER_CONFIG_TAG)
1166+
let dcds = try!(esds.read_u8());
1167+
if dcds != DECODER_CONFIG_TAG {
1168+
return Err(Error::Unsupported("fail to parse decoder config descriptor"));
1169+
}
1170+
1171+
let dcds_extend = try!(esds.read_u8());
1172+
// extension tag start from 0x80.
1173+
if dcds_extend >= 0x80 {
1174+
// skip remains extension and length.
1175+
try!(skip(esds, 3));
1176+
}
1177+
1178+
try!(esds.read_u8())
1179+
};
1180+
1181+
let codec = match object_profile_indicator {
1182+
0x40 | 0x41 => CodecType::AAC,
1183+
0x6B => CodecType::MP3,
1184+
_ => CodecType::Unknown,
1185+
};
1186+
1187+
if codec == CodecType::Unknown {
1188+
return Err(Error::Unsupported("unknown audio codec"));
1189+
}
1190+
1191+
Ok(ES_Descriptor {
1192+
audio_codec: codec,
1193+
codec_specific_config: esds_array,
1194+
})
11181195
}
11191196

11201197
/// Parse `FLACSpecificBox`.
@@ -1325,7 +1402,7 @@ fn read_video_sample_entry<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) ->
13251402
.ok_or_else(|| Error::InvalidData("malformed video sample entry"))
13261403
}
13271404

1328-
fn read_qt_wave_atom<T: Read>(src: &mut BMFFBox<T>) -> Result<AudioCodecSpecific> {
1405+
fn read_qt_wave_atom<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
13291406
let mut codec_specific = None;
13301407
let mut iter = src.box_iter();
13311408
while let Some(mut b) = try!(iter.next_box()) {
@@ -1398,14 +1475,16 @@ fn read_audio_sample_entry<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) ->
13981475
}
13991476

14001477
let esds = try!(read_esds(&mut b));
1401-
codec_specific = Some(esds);
1478+
track.codec_type = esds.audio_codec;
1479+
codec_specific = Some(AudioCodecSpecific::ES_Descriptor(esds));
14021480
}
14031481
BoxType::FLACSpecificBox => {
14041482
if name != BoxType::FLACSampleEntry ||
14051483
codec_specific.is_some() {
14061484
return Err(Error::InvalidData("malformed audio sample entry"));
14071485
}
14081486
let dfla = try!(read_dfla(&mut b));
1487+
track.codec_type = CodecType::FLAC;
14091488
codec_specific = Some(AudioCodecSpecific::FLACSpecificBox(dfla));
14101489
}
14111490
BoxType::OpusSpecificBox => {
@@ -1414,11 +1493,13 @@ fn read_audio_sample_entry<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) ->
14141493
return Err(Error::InvalidData("malformed audio sample entry"));
14151494
}
14161495
let dops = try!(read_dops(&mut b));
1496+
track.codec_type = CodecType::Opus;
14171497
codec_specific = Some(AudioCodecSpecific::OpusSpecificBox(dops));
14181498
}
14191499
BoxType::QTWaveAtom => {
1420-
let qt_desc = try!(read_qt_wave_atom(&mut b));
1421-
codec_specific = Some(qt_desc);
1500+
let qt_esds = try!(read_qt_wave_atom(&mut b));
1501+
track.codec_type = qt_esds.audio_codec;
1502+
codec_specific = Some(AudioCodecSpecific::ES_Descriptor(qt_esds));
14221503
}
14231504
_ => try!(skip_box_content(&mut b)),
14241505
}

mp4parse/src/tests.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,14 @@ fn skip_padding_in_stsd() {
826826
#[test]
827827
fn read_qt_wave_atom() {
828828
let esds = make_fullbox(BoxSize::Auto, b"esds", 0, |s| {
829-
s.append_repeated(0, 30)
829+
s.B8(0x03) // elementary stream descriptor tag
830+
.B8(0x0b) // esds length
831+
.append_repeated(0, 2)
832+
.B8(0x00) // flags
833+
.B8(0x04) // decoder config descriptor tag
834+
.B8(0x06) // dcds length
835+
.B8(0x6b) // mp3
836+
.append_repeated(0, 5)
830837
}).into_inner();
831838
let wave = make_box(BoxSize::Auto, b"wave", |s| {
832839
s.append_bytes(esds.as_slice())
@@ -849,4 +856,5 @@ fn read_qt_wave_atom() {
849856
let mut track = super::Track::new(0);
850857
super::read_audio_sample_entry(&mut stream, &mut track)
851858
.expect("fail to read qt wave atom");
859+
assert_eq!(track.codec_type, super::CodecType::MP3);
852860
}

mp4parse/tests/public.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ fn public_api() {
7070

7171
// track.data part
7272
assert_eq!(match a.codec_specific {
73-
mp4::AudioCodecSpecific::ES_Descriptor(v) => {
74-
assert!(v.len() > 0);
73+
mp4::AudioCodecSpecific::ES_Descriptor(esds) => {
74+
assert_eq!(esds.audio_codec, mp4::CodecType::AAC);
7575
"ES"
7676
}
7777
mp4::AudioCodecSpecific::FLACSpecificBox(_) => {

mp4parse_capi/src/lib.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ use mp4parse::MediaScaledTime;
5252
use mp4parse::TrackTimeScale;
5353
use mp4parse::TrackScaledTime;
5454
use mp4parse::serialize_opus_header;
55+
use mp4parse::CodecType;
5556

5657
// rusty-cheddar's C enum generation doesn't namespace enum members by
5758
// prefixing them, so we're forced to do it in our member names until
@@ -88,6 +89,7 @@ pub enum mp4parse_codec {
8889
MP4PARSE_CODEC_OPUS,
8990
MP4PARSE_CODEC_AVC,
9091
MP4PARSE_CODEC_VP9,
92+
MP4PARSE_CODEC_MP3,
9193
}
9294

9395
#[repr(C)]
@@ -345,8 +347,12 @@ pub unsafe extern fn mp4parse_get_track_info(parser: *mut mp4parse_parser, track
345347
mp4parse_codec::MP4PARSE_CODEC_OPUS,
346348
AudioCodecSpecific::FLACSpecificBox(_) =>
347349
mp4parse_codec::MP4PARSE_CODEC_FLAC,
348-
AudioCodecSpecific::ES_Descriptor(_) =>
350+
AudioCodecSpecific::ES_Descriptor(ref esds) if esds.audio_codec == CodecType::AAC =>
349351
mp4parse_codec::MP4PARSE_CODEC_AAC,
352+
AudioCodecSpecific::ES_Descriptor(ref esds) if esds.audio_codec == CodecType::MP3 =>
353+
mp4parse_codec::MP4PARSE_CODEC_MP3,
354+
AudioCodecSpecific::ES_Descriptor(_) =>
355+
mp4parse_codec::MP4PARSE_CODEC_UNKNOWN,
350356
},
351357
Some(SampleEntry::Video(ref video)) => match video.codec_specific {
352358
VideoCodecSpecific::VPxConfig(_) =>
@@ -433,11 +439,11 @@ pub unsafe extern fn mp4parse_get_track_audio_info(parser: *mut mp4parse_parser,
433439

434440
match audio.codec_specific {
435441
AudioCodecSpecific::ES_Descriptor(ref v) => {
436-
if v.len() > std::u32::MAX as usize {
442+
if v.codec_specific_config.len() > std::u32::MAX as usize {
437443
return MP4PARSE_ERROR_INVALID;
438444
}
439-
(*info).codec_specific_config.length = v.len() as u32;
440-
(*info).codec_specific_config.data = v.as_ptr();
445+
(*info).codec_specific_config.length = v.codec_specific_config.len() as u32;
446+
(*info).codec_specific_config.data = v.codec_specific_config.as_ptr();
441447
}
442448
AudioCodecSpecific::FLACSpecificBox(_) => {
443449
return MP4PARSE_ERROR_UNSUPPORTED;

0 commit comments

Comments
 (0)