Skip to content

Commit b0e9ae7

Browse files
authored
Merge pull request #39 from alfredoyang/parse_csd
Parse codec specific descriptor to retrieve audio sample rate
2 parents e3c9d96 + 305cc92 commit b0e9ae7

File tree

4 files changed

+66
-22
lines changed

4 files changed

+66
-22
lines changed

mp4parse/src/lib.rs

Lines changed: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ pub enum SampleEntry {
208208
#[derive(Debug, Clone)]
209209
pub struct ES_Descriptor {
210210
pub audio_codec: CodecType,
211+
pub audio_sample_rate: Option<u32>,
211212
pub codec_specific_config: Vec<u8>,
212213
}
213214

@@ -1116,8 +1117,15 @@ fn read_flac_metadata<T: Read>(src: &mut BMFFBox<T>) -> Result<FLACMetadataBlock
11161117

11171118
fn read_esds<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
11181119
// Tags for elementary stream description
1119-
const ESDESCR_TAG: u8 = 0x03;
1120-
const DECODER_CONFIG_TAG: u8 = 0x04;
1120+
const ESDESCR_TAG: u8 = 0x03;
1121+
const DECODER_CONFIG_TAG: u8 = 0x04;
1122+
const DECODER_SPECIFIC_TAG: u8 = 0x05;
1123+
1124+
let frequency_table =
1125+
vec![(0x1, 96000), (0x1, 88200), (0x2, 64000), (0x3, 48000),
1126+
(0x4, 44100), (0x5, 32000), (0x6, 24000), (0x7, 22050),
1127+
(0x8, 16000), (0x9, 12000), (0xa, 11025), (0xb, 8000),
1128+
(0xc, 7350)];
11211129

11221130
let (_, _) = try!(read_fullbox_extra(src));
11231131

@@ -1128,24 +1136,29 @@ fn read_esds<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
11281136
let esds_array = try!(read_buf(src, esds_size as usize));
11291137

11301138
// Parsing DecoderConfig descriptor to get the object_profile_indicator
1131-
// for correct codec type.
1132-
let object_profile_indicator = {
1139+
// for correct codec type and audio sample rate.
1140+
let (object_profile_indicator, sample_frequency) = {
1141+
let mut object_profile: u8 = 0;
1142+
let mut sample_frequency = None;
1143+
11331144
// clone a esds cursor for parsing.
11341145
let esds = &mut Cursor::new(&esds_array);
1135-
let esds_tag = try!(esds.read_u8());
1146+
let next_tag = try!(esds.read_u8());
11361147

1137-
if esds_tag != ESDESCR_TAG {
1148+
if next_tag != ESDESCR_TAG {
11381149
return Err(Error::Unsupported("fail to parse ES descriptor"));
11391150
}
11401151

11411152
let esds_extend = try!(esds.read_u8());
11421153
// extension tag start from 0x80.
1143-
if esds_extend >= 0x80 {
1144-
// skip remaining extension and length.
1145-
try!(skip(esds, 5));
1146-
} else {
1154+
let esds_end = if esds_extend >= 0x80 {
1155+
// skip remaining extension.
11471156
try!(skip(esds, 2));
1148-
}
1157+
esds.position() + try!(esds.read_u8()) as u64
1158+
} else {
1159+
esds.position() + esds_extend as u64
1160+
};
1161+
try!(skip(esds, 2));
11491162

11501163
let esds_flags = try!(esds.read_u8());
11511164

@@ -1163,19 +1176,45 @@ fn read_esds<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
11631176
}
11641177

11651178
// 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"));
1179+
if esds_end > esds.position() {
1180+
let next_tag = try!(esds.read_u8());
1181+
if next_tag == DECODER_CONFIG_TAG {
1182+
let dcds_extend = try!(esds.read_u8());
1183+
// extension tag start from 0x80.
1184+
if dcds_extend >= 0x80 {
1185+
// skip remains extension and length.
1186+
try!(skip(esds, 3));
1187+
}
1188+
1189+
object_profile = try!(esds.read_u8());
1190+
1191+
// Skip uninteresting fields.
1192+
try!(skip(esds, 12));
1193+
}
11691194
}
11701195

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));
1196+
1197+
// find DecoderSpecific descriptor (tag = DECODER_SPECIFIC_TAG)
1198+
if esds_end > esds.position() {
1199+
let next_tag = try!(esds.read_u8());
1200+
if next_tag == DECODER_SPECIFIC_TAG {
1201+
let dsds_extend = try!(esds.read_u8());
1202+
// extension tag start from 0x80.
1203+
if dsds_extend >= 0x80 {
1204+
// skip remains extension and length.
1205+
try!(skip(esds, 3));
1206+
}
1207+
1208+
let audio_specific_config = try!(be_u16(esds));
1209+
1210+
let sample_index = (audio_specific_config & 0x07FF) >> 7;
1211+
1212+
sample_frequency =
1213+
frequency_table.iter().find(|item| item.0 == sample_index).map(|x| x.1);
1214+
}
11761215
}
11771216

1178-
try!(esds.read_u8())
1217+
(object_profile, sample_frequency)
11791218
};
11801219

11811220
let codec = match object_profile_indicator {
@@ -1190,6 +1229,7 @@ fn read_esds<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
11901229

11911230
Ok(ES_Descriptor {
11921231
audio_codec: codec,
1232+
audio_sample_rate: sample_frequency,
11931233
codec_specific_config: esds_array,
11941234
})
11951235
}

mp4parse/src/tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -831,9 +831,9 @@ fn read_qt_wave_atom() {
831831
.append_repeated(0, 2)
832832
.B8(0x00) // flags
833833
.B8(0x04) // decoder config descriptor tag
834-
.B8(0x06) // dcds length
834+
.B8(0x0d) // dcds length
835835
.B8(0x6b) // mp3
836-
.append_repeated(0, 5)
836+
.append_repeated(0, 12)
837837
}).into_inner();
838838
let wave = make_box(BoxSize::Auto, b"wave", |s| {
839839
s.append_bytes(esds.as_slice())

mp4parse/tests/public.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ fn public_api() {
7272
assert_eq!(match a.codec_specific {
7373
mp4::AudioCodecSpecific::ES_Descriptor(esds) => {
7474
assert_eq!(esds.audio_codec, mp4::CodecType::AAC);
75+
assert_eq!(esds.audio_sample_rate.unwrap(), 48000);
7576
"ES"
7677
}
7778
mp4::AudioCodecSpecific::FLACSpecificBox(_) => {

mp4parse_capi/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,9 @@ pub unsafe extern fn mp4parse_get_track_audio_info(parser: *mut mp4parse_parser,
444444
}
445445
(*info).codec_specific_config.length = v.codec_specific_config.len() as u32;
446446
(*info).codec_specific_config.data = v.codec_specific_config.as_ptr();
447+
if let Some(rate) = v.audio_sample_rate {
448+
(*info).sample_rate = rate;
449+
}
447450
}
448451
AudioCodecSpecific::FLACSpecificBox(_) => {
449452
return MP4PARSE_ERROR_UNSUPPORTED;

0 commit comments

Comments
 (0)