fn read_video_sample_entry()

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,
            })
        }),
    )
}