in mp4parse_capi/src/lib.rs [698:881]
fn get_track_audio_info(
parser: &mut Mp4parseParser,
track_index: u32,
info: &mut Mp4parseTrackAudioInfo,
) -> Result<(), Mp4parseStatus> {
let Mp4parseParser {
context,
opus_header,
..
} = parser;
if track_index as usize >= context.tracks.len() {
return Err(Mp4parseStatus::BadArg);
}
let track = &context.tracks[track_index as usize];
if track.track_type != TrackType::Audio {
return Err(Mp4parseStatus::Invalid);
}
// Handle track.stsd
let stsd = match track.stsd {
Some(ref stsd) => stsd,
None => return Err(Mp4parseStatus::Invalid), // Stsd should be present
};
if stsd.descriptions.is_empty() {
return Err(Mp4parseStatus::Invalid); // Should have at least 1 description
}
let mut audio_sample_infos = TryVec::with_capacity(stsd.descriptions.len())?;
for description in stsd.descriptions.iter() {
let mut sample_info = Mp4parseTrackAudioSampleInfo::default();
let audio = match description {
SampleEntry::Audio(a) => a,
_ => return Err(Mp4parseStatus::Invalid),
};
// UNKNOWN for unsupported format.
sample_info.codec_type = match audio.codec_specific {
AudioCodecSpecific::OpusSpecificBox(_) => Mp4parseCodec::Opus,
AudioCodecSpecific::FLACSpecificBox(_) => Mp4parseCodec::Flac,
AudioCodecSpecific::ES_Descriptor(ref esds) if esds.audio_codec == CodecType::AAC => {
Mp4parseCodec::Aac
}
AudioCodecSpecific::ES_Descriptor(ref esds) if esds.audio_codec == CodecType::MP3 => {
Mp4parseCodec::Mp3
}
AudioCodecSpecific::ES_Descriptor(_) | AudioCodecSpecific::LPCM => {
Mp4parseCodec::Unknown
}
AudioCodecSpecific::MP3 => Mp4parseCodec::Mp3,
AudioCodecSpecific::ALACSpecificBox(_) => Mp4parseCodec::Alac,
#[cfg(feature = "3gpp")]
AudioCodecSpecific::AMRSpecificBox(_) => {
if audio.codec_type == CodecType::AMRNB {
Mp4parseCodec::AMRNB
} else {
Mp4parseCodec::AMRWB
}
}
};
sample_info.channels = audio.channelcount as u16;
sample_info.bit_depth = audio.samplesize;
sample_info.sample_rate = audio.samplerate as u32;
// sample_info.profile is handled below on a per case basis
match audio.codec_specific {
AudioCodecSpecific::ES_Descriptor(ref esds) => {
if esds.codec_esds.len() > u32::MAX as usize {
return Err(Mp4parseStatus::Invalid);
}
sample_info.extra_data.length = esds.codec_esds.len();
sample_info.extra_data.data = esds.codec_esds.as_ptr();
sample_info.codec_specific_config.length = esds.decoder_specific_data.len();
sample_info.codec_specific_config.data = esds.decoder_specific_data.as_ptr();
if let Some(rate) = esds.audio_sample_rate {
sample_info.sample_rate = rate;
}
if let Some(channels) = esds.audio_channel_count {
sample_info.channels = channels;
}
if let Some(profile) = esds.audio_object_type {
sample_info.profile = profile;
}
sample_info.extended_profile = match esds.extended_audio_object_type {
Some(extended_profile) => extended_profile,
_ => sample_info.profile,
};
}
AudioCodecSpecific::FLACSpecificBox(ref flac) => {
// Return the STREAMINFO metadata block in the codec_specific.
let streaminfo = &flac.blocks[0];
if streaminfo.block_type != 0 || streaminfo.data.len() != 34 {
return Err(Mp4parseStatus::Invalid);
}
sample_info.codec_specific_config.length = streaminfo.data.len();
sample_info.codec_specific_config.data = streaminfo.data.as_ptr();
}
AudioCodecSpecific::OpusSpecificBox(ref opus) => {
let mut v = TryVec::new();
match serialize_opus_header(opus, &mut v) {
Err(_) => {
return Err(Mp4parseStatus::Invalid);
}
Ok(_) => {
opus_header.insert(track_index, v)?;
if let Some(v) = opus_header.get(&track_index) {
if v.len() > u32::MAX as usize {
return Err(Mp4parseStatus::Invalid);
}
sample_info.codec_specific_config.length = v.len();
sample_info.codec_specific_config.data = v.as_ptr();
}
}
}
}
AudioCodecSpecific::ALACSpecificBox(ref alac) => {
sample_info.codec_specific_config.length = alac.data.len();
sample_info.codec_specific_config.data = alac.data.as_ptr();
}
AudioCodecSpecific::MP3 | AudioCodecSpecific::LPCM => (),
#[cfg(feature = "3gpp")]
AudioCodecSpecific::AMRSpecificBox(_) => (),
}
if let Some(p) = audio
.protection_info
.iter()
.find(|sinf| sinf.tenc.is_some())
{
sample_info.protected_data.original_format =
OptionalFourCc::Some(p.original_format.value);
sample_info.protected_data.scheme_type = match p.scheme_type {
Some(ref scheme_type_box) => {
match scheme_type_box.scheme_type.value.as_ref() {
b"cenc" => Mp4ParseEncryptionSchemeType::Cenc,
b"cbcs" => Mp4ParseEncryptionSchemeType::Cbcs,
// We don't support other schemes, and shouldn't reach
// this case. Try to gracefully handle by treating as
// no encryption case.
_ => Mp4ParseEncryptionSchemeType::None,
}
}
None => Mp4ParseEncryptionSchemeType::None,
};
if let Some(ref tenc) = p.tenc {
sample_info.protected_data.is_encrypted = tenc.is_encrypted;
sample_info.protected_data.iv_size = tenc.iv_size;
sample_info.protected_data.kid.set_data(&(tenc.kid));
sample_info.protected_data.crypt_byte_block =
tenc.crypt_byte_block_count.unwrap_or(0);
sample_info.protected_data.skip_byte_block =
tenc.skip_byte_block_count.unwrap_or(0);
if let Some(ref iv_vec) = tenc.constant_iv {
if iv_vec.len() > u32::MAX as usize {
return Err(Mp4parseStatus::Invalid);
}
sample_info.protected_data.constant_iv.set_data(iv_vec);
};
}
}
audio_sample_infos.push(sample_info)?;
}
parser
.audio_track_sample_descriptions
.insert(track_index, audio_sample_infos)?;
match parser.audio_track_sample_descriptions.get(&track_index) {
Some(sample_info) => {
if sample_info.len() > u32::MAX as usize {
// Should never happen due to upper limits on number of sample
// descriptions a track can have, but lets be safe.
return Err(Mp4parseStatus::Invalid);
}
info.sample_info_count = sample_info.len() as u32;
info.sample_info = sample_info.as_ptr();
}
None => return Err(Mp4parseStatus::Invalid), // Shouldn't happen, we just inserted the info!
}
Ok(())
}