in mp4parse_capi/src/lib.rs [907:1051]
fn mp4parse_get_track_video_info_safe(
parser: &mut Mp4parseParser,
track_index: u32,
info: &mut Mp4parseTrackVideoInfo,
) -> Result<(), Mp4parseStatus> {
let context = parser.context();
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::Video {
return Err(Mp4parseStatus::Invalid);
}
// Handle track.tkhd
if let Some(ref tkhd) = track.tkhd {
info.display_width = tkhd.width >> 16; // 16.16 fixed point
info.display_height = tkhd.height >> 16; // 16.16 fixed point
let matrix = (
tkhd.matrix.a >> 16,
tkhd.matrix.b >> 16,
tkhd.matrix.c >> 16,
tkhd.matrix.d >> 16,
);
info.rotation = match matrix {
(0, 1, -1, 0) => 90, // rotate 90 degrees
(-1, 0, 0, -1) => 180, // rotate 180 degrees
(0, -1, 1, 0) => 270, // rotate 270 degrees
_ => 0,
};
} else {
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 video_sample_infos = TryVec::with_capacity(stsd.descriptions.len())?;
for description in stsd.descriptions.iter() {
let mut sample_info = Mp4parseTrackVideoSampleInfo::default();
let video = match description {
SampleEntry::Video(v) => v,
_ => return Err(Mp4parseStatus::Invalid),
};
// UNKNOWN for unsupported format.
sample_info.codec_type = match video.codec_specific {
VideoCodecSpecific::VPxConfig(_) => Mp4parseCodec::Vp9,
VideoCodecSpecific::AV1Config(_) => Mp4parseCodec::Av1,
VideoCodecSpecific::AVCConfig(_) => Mp4parseCodec::Avc,
VideoCodecSpecific::H263Config(_) => Mp4parseCodec::H263,
VideoCodecSpecific::HEVCConfig(_) => Mp4parseCodec::Hevc,
#[cfg(feature = "mp4v")]
VideoCodecSpecific::ESDSConfig(_) => Mp4parseCodec::Mp4v,
#[cfg(not(feature = "mp4v"))]
VideoCodecSpecific::ESDSConfig(_) =>
// MP4V (14496-2) video is unsupported.
{
Mp4parseCodec::Unknown
}
};
sample_info.image_width = video.width;
sample_info.image_height = video.height;
if let Some(ratio) = video.pixel_aspect_ratio {
info.pixel_aspect_ratio = ratio;
}
match video.codec_specific {
VideoCodecSpecific::AV1Config(ref config) => {
sample_info.extra_data.set_data(&config.raw_config);
}
VideoCodecSpecific::AVCConfig(ref data)
| VideoCodecSpecific::ESDSConfig(ref data)
| VideoCodecSpecific::HEVCConfig(ref data) => {
sample_info.extra_data.set_data(data);
}
_ => {}
}
if let Some(p) = video
.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);
};
}
}
video_sample_infos.push(sample_info)?;
}
parser
.video_track_sample_descriptions
.insert(track_index, video_sample_infos)?;
match parser.video_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(())
}