in mp4parse/src/lib.rs [5642:5797]
fn read_audio_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleEntry> {
let name = src.get_header().name;
// Skip uninteresting fields.
skip(src, 6)?;
let data_reference_index = be_u16(src)?;
// XXX(kinetik): This is "reserved" in BMFF, but some old QT MOV variant
// uses it, need to work out if we have to support it. Without checking
// here and reading extra fields after samplerate (or bailing with an
// error), the parser loses sync completely.
let version = be_u16(src)?;
// Skip uninteresting fields.
skip(src, 6)?;
let mut channelcount = u32::from(be_u16(src)?);
let samplesize = be_u16(src)?;
// Skip uninteresting fields.
skip(src, 4)?;
let mut samplerate = f64::from(be_u32(src)? >> 16); // 16.16 fixed point;
match version {
0 => (),
1 => {
// Quicktime sound sample description version 1.
// Skip uninteresting fields.
skip(src, 16)?;
}
2 => {
// Quicktime sound sample description version 2.
skip(src, 4)?;
samplerate = f64::from_bits(be_u64(src)?);
channelcount = be_u32(src)?;
skip(src, 20)?;
}
_ => {
return Err(Error::Unsupported(
"unsupported non-isom audio sample entry",
))
}
}
let (mut codec_type, mut codec_specific) = match name {
BoxType::MP3AudioSampleEntry => (CodecType::MP3, Some(AudioCodecSpecific::MP3)),
BoxType::LPCMAudioSampleEntry => (CodecType::LPCM, Some(AudioCodecSpecific::LPCM)),
// Some mp4 file with AMR doesn't have AMRSpecificBox "damr" in followed while loop,
// we use empty box by default.
#[cfg(feature = "3gpp")]
BoxType::AMRNBSampleEntry => (
CodecType::AMRNB,
Some(AudioCodecSpecific::AMRSpecificBox(Default::default())),
),
#[cfg(feature = "3gpp")]
BoxType::AMRWBSampleEntry => (
CodecType::AMRWB,
Some(AudioCodecSpecific::AMRSpecificBox(Default::default())),
),
_ => (CodecType::Unknown, None),
};
let mut protection_info = TryVec::new();
let mut iter = src.box_iter();
while let Some(mut b) = iter.next_box()? {
match b.head.name {
BoxType::ESDBox => {
if (name != BoxType::MP4AudioSampleEntry
&& name != BoxType::ProtectedAudioSampleEntry)
|| codec_specific.is_some()
{
return Status::StsdBadAudioSampleEntry.into();
}
let esds = read_esds(&mut b)?;
codec_type = esds.audio_codec;
codec_specific = Some(AudioCodecSpecific::ES_Descriptor(esds));
}
BoxType::FLACSpecificBox => {
if (name != BoxType::FLACSampleEntry && name != BoxType::ProtectedAudioSampleEntry)
|| codec_specific.is_some()
{
return Status::StsdBadAudioSampleEntry.into();
}
let dfla = read_dfla(&mut b)?;
codec_type = CodecType::FLAC;
codec_specific = Some(AudioCodecSpecific::FLACSpecificBox(dfla));
}
BoxType::OpusSpecificBox => {
if (name != BoxType::OpusSampleEntry && name != BoxType::ProtectedAudioSampleEntry)
|| codec_specific.is_some()
{
return Status::StsdBadAudioSampleEntry.into();
}
let dops = read_dops(&mut b)?;
codec_type = CodecType::Opus;
codec_specific = Some(AudioCodecSpecific::OpusSpecificBox(dops));
}
BoxType::ALACSpecificBox => {
if name != BoxType::ALACSpecificBox || codec_specific.is_some() {
return Status::StsdBadAudioSampleEntry.into();
}
let alac = read_alac(&mut b)?;
codec_type = CodecType::ALAC;
codec_specific = Some(AudioCodecSpecific::ALACSpecificBox(alac));
}
BoxType::QTWaveAtom => {
let qt_esds = read_qt_wave_atom(&mut b)?;
codec_type = qt_esds.audio_codec;
codec_specific = Some(AudioCodecSpecific::ES_Descriptor(qt_esds));
}
BoxType::ProtectionSchemeInfoBox => {
if name != BoxType::ProtectedAudioSampleEntry {
return Status::StsdBadAudioSampleEntry.into();
}
let sinf = read_sinf(&mut b)?;
debug!("{:?} (sinf)", sinf);
codec_type = CodecType::EncryptedAudio;
protection_info.push(sinf)?;
}
#[cfg(feature = "3gpp")]
BoxType::AMRSpecificBox => {
if codec_type != CodecType::AMRNB && codec_type != CodecType::AMRWB {
return Status::StsdBadAudioSampleEntry.into();
}
let amr_dec_spec_struc_size = b
.head
.size
.checked_sub(b.head.offset)
.expect("offset invalid");
let amr_dec_spec_struc = read_buf(&mut b.content, amr_dec_spec_struc_size)?;
debug!("{:?} (AMRDecSpecStruc)", amr_dec_spec_struc);
codec_specific = Some(AudioCodecSpecific::AMRSpecificBox(amr_dec_spec_struc));
}
_ => {
debug!("Unsupported audio codec, box {:?} found", b.head.name);
skip_box_content(&mut b)?;
}
}
check_parser_state!(b.content);
}
Ok(
codec_specific.map_or(SampleEntry::Unknown, |codec_specific| {
SampleEntry::Audio(AudioSampleEntry {
codec_type,
data_reference_index,
channelcount,
samplesize,
samplerate,
codec_specific,
protection_info,
})
}),
)
}