in mp4parse/src/lib.rs [5451:5622]
fn read_video_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleEntry> {
let name = src.get_header().name;
let codec_type = match name {
BoxType::AVCSampleEntry | BoxType::AVC3SampleEntry => CodecType::H264,
BoxType::MP4VideoSampleEntry => CodecType::MP4V,
BoxType::VP8SampleEntry => CodecType::VP8,
BoxType::VP9SampleEntry => CodecType::VP9,
BoxType::AV1SampleEntry => CodecType::AV1,
BoxType::ProtectedVisualSampleEntry => CodecType::EncryptedVideo,
BoxType::H263SampleEntry => CodecType::H263,
BoxType::HEV1SampleEntry | BoxType::HVC1SampleEntry => CodecType::HEVC,
_ => {
debug!("Unsupported video codec, box {:?} found", name);
CodecType::Unknown
}
};
// Skip uninteresting fields.
skip(src, 6)?;
let data_reference_index = be_u16(src)?;
// Skip uninteresting fields.
skip(src, 16)?;
let width = be_u16(src)?;
let height = be_u16(src)?;
// Skip uninteresting fields.
skip(src, 50)?;
// Skip clap/pasp/etc. for now.
let mut codec_specific = None;
let mut pixel_aspect_ratio = 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::AVCConfigurationBox => {
if (name != BoxType::AVCSampleEntry
&& name != BoxType::AVC3SampleEntry
&& name != BoxType::ProtectedVisualSampleEntry)
|| codec_specific.is_some()
{
return Status::StsdBadVideoSampleEntry.into();
}
let avcc_size = b
.head
.size
.checked_sub(b.head.offset)
.expect("offset invalid");
let avcc = read_buf(&mut b.content, avcc_size)?;
debug!("{:?} (avcc)", avcc);
// TODO(kinetik): Parse avcC box? For now we just stash the data.
codec_specific = Some(VideoCodecSpecific::AVCConfig(avcc));
}
BoxType::H263SpecificBox => {
if (name != BoxType::H263SampleEntry) || codec_specific.is_some() {
return Status::StsdBadVideoSampleEntry.into();
}
let h263_dec_spec_struc_size = b
.head
.size
.checked_sub(b.head.offset)
.expect("offset invalid");
let h263_dec_spec_struc = read_buf(&mut b.content, h263_dec_spec_struc_size)?;
debug!("{:?} (h263DecSpecStruc)", h263_dec_spec_struc);
codec_specific = Some(VideoCodecSpecific::H263Config(h263_dec_spec_struc));
}
BoxType::VPCodecConfigurationBox => {
// vpcC
if (name != BoxType::VP8SampleEntry
&& name != BoxType::VP9SampleEntry
&& name != BoxType::ProtectedVisualSampleEntry)
|| codec_specific.is_some()
{
return Status::StsdBadVideoSampleEntry.into();
}
let vpcc = read_vpcc(&mut b)?;
codec_specific = Some(VideoCodecSpecific::VPxConfig(vpcc));
}
BoxType::AV1CodecConfigurationBox => {
if name != BoxType::AV1SampleEntry && name != BoxType::ProtectedVisualSampleEntry {
return Status::StsdBadVideoSampleEntry.into();
}
let av1c = read_av1c(&mut b)?;
codec_specific = Some(VideoCodecSpecific::AV1Config(av1c));
}
BoxType::ESDBox => {
if name != BoxType::MP4VideoSampleEntry || codec_specific.is_some() {
return Status::StsdBadVideoSampleEntry.into();
}
#[cfg(not(feature = "mp4v"))]
{
let (_, _) = read_fullbox_extra(&mut b.content)?;
// Subtract 4 extra to offset the members of fullbox not
// accounted for in head.offset
let esds_size = b
.head
.size
.checked_sub(b.head.offset + 4)
.expect("offset invalid");
let esds = read_buf(&mut b.content, esds_size)?;
codec_specific = Some(VideoCodecSpecific::ESDSConfig(esds));
}
#[cfg(feature = "mp4v")]
{
// Read ES_Descriptor inside an esds box.
// See ISOBMFF (ISO 14496-1:2010) § 7.2.6.5
let esds = read_esds(&mut b)?;
codec_specific =
Some(VideoCodecSpecific::ESDSConfig(esds.decoder_specific_data));
}
}
BoxType::ProtectionSchemeInfoBox => {
if name != BoxType::ProtectedVisualSampleEntry {
return Status::StsdBadVideoSampleEntry.into();
}
let sinf = read_sinf(&mut b)?;
debug!("{:?} (sinf)", sinf);
protection_info.push(sinf)?;
}
BoxType::HEVCConfigurationBox => {
if (name != BoxType::HEV1SampleEntry
&& name != BoxType::HVC1SampleEntry
&& name != BoxType::ProtectedVisualSampleEntry)
|| codec_specific.is_some()
{
return Status::StsdBadVideoSampleEntry.into();
}
let hvcc_size = b
.head
.size
.checked_sub(b.head.offset)
.expect("offset invalid");
let hvcc = read_buf(&mut b.content, hvcc_size)?;
debug!("{:?} (hvcc)", hvcc);
codec_specific = Some(VideoCodecSpecific::HEVCConfig(hvcc));
}
BoxType::PixelAspectRatioBox => {
let pasp = read_pasp(&mut b)?;
let aspect_ratio = pasp.h_spacing as f32 / pasp.v_spacing as f32;
let is_valid_aspect_ratio = |value: f32| -> bool { value > 0.0 && value < 10.0 };
// Only set pixel_aspect_ratio if it is valid
if is_valid_aspect_ratio(aspect_ratio) {
pixel_aspect_ratio = Some(aspect_ratio);
}
debug!("Parsed pasp box: {:?}, PAR {:?}", pasp, pixel_aspect_ratio);
}
_ => {
debug!("Unsupported video 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::Video(VideoSampleEntry {
codec_type,
data_reference_index,
width,
height,
codec_specific,
protection_info,
pixel_aspect_ratio,
})
}),
)
}