media: ffmpeg: add proper wrapper for AVProfile

Our ffmpeg crate should avoid returning native C avcodec types if
possible, as this means client code could have to resort to unsafe code.
Fix this for AVProfile by introducing a safe wrapper type that provides
us all the useful methods we may need.

BUG=b:169295147
TEST=cargo build --features "video-decoder,ffmpeg"

Change-Id: I2436857d3878b5b6cf4eab35f5b3b0c57c8db60e
Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/3782039
Commit-Queue: Alexandre Courbot <acourbot@chromium.org>
Reviewed-by: Keiichi Watanabe <keiichiw@chromium.org>
Tested-by: Alexandre Courbot <acourbot@chromium.org>
Auto-Submit: Alexandre Courbot <acourbot@chromium.org>
This commit is contained in:
Alexandre Courbot 2022-07-22 11:54:51 +09:00 committed by crosvm LUCI
parent 4f8a3ac153
commit 89b7ba4512
2 changed files with 36 additions and 5 deletions

View file

@ -633,7 +633,7 @@ impl DecoderBackend for FfmpegDecoder {
profile_iter
.filter_map(|p| {
match p.profile as u32 {
match p.profile() {
FF_PROFILE_H264_BASELINE => Some(Profile::H264Baseline),
FF_PROFILE_H264_MAIN => Some(Profile::H264Main),
FF_PROFILE_H264_EXTENDED => Some(Profile::H264Extended),
@ -662,7 +662,7 @@ impl DecoderBackend for FfmpegDecoder {
]
}
Format::VP9 => profile_iter
.filter_map(|p| match p.profile as u32 {
.filter_map(|p| match p.profile() {
FF_PROFILE_VP9_0 => Some(Profile::VP9Profile0),
FF_PROFILE_VP9_1 => Some(Profile::VP9Profile1),
FF_PROFILE_VP9_2 => Some(Profile::VP9Profile2),
@ -671,7 +671,7 @@ impl DecoderBackend for FfmpegDecoder {
})
.collect(),
Format::Hevc => profile_iter
.filter_map(|p| match p.profile as u32 {
.filter_map(|p| match p.profile() {
FF_PROFILE_HEVC_MAIN => Some(Profile::HevcMain),
FF_PROFILE_HEVC_MAIN_10 => Some(Profile::HevcMain10),
FF_PROFILE_HEVC_MAIN_STILL_PICTURE => Some(Profile::HevcMainStillPicture),

View file

@ -7,6 +7,7 @@
//! low-level access as the libavcodec functions do.
use std::ffi::CStr;
use std::fmt::Debug;
use std::fmt::Display;
use std::marker::PhantomData;
use std::ops::Deref;
@ -139,11 +140,41 @@ impl Iterator for AvCodecIterator {
}
}
/// Simple wrapper over `AVProfile` that provides helpful methods.
pub struct AvProfile(&'static ffi::AVProfile);
impl AvProfile {
/// Return the profile id, which can be matched against FF_PROFILE_*.
pub fn profile(&self) -> u32 {
self.0.profile as u32
}
/// Return the name of this profile.
pub fn name(&self) -> &'static str {
const INVALID_PROFILE_STR: &str = "invalid profile";
// Safe because `CStr::from_ptr` is called on a valid zero-terminated C string.
unsafe { CStr::from_ptr(self.0.name).to_str() }.unwrap_or(INVALID_PROFILE_STR)
}
}
impl Display for AvProfile {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.name())
}
}
impl Debug for AvProfile {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(self, f)
}
}
/// Lightweight abstraction over the array of supported profiles for a given codec.
pub struct AvProfileIterator(*const ffi::AVProfile);
impl Iterator for AvProfileIterator {
type Item = &'static ffi::AVProfile;
type Item = AvProfile;
fn next(&mut self) -> Option<Self::Item> {
// Safe because the contract of `new` stipulates we have received a valid `AVCodec`
@ -158,7 +189,7 @@ impl Iterator for AvProfileIterator {
// Safe because we have been initialized to a static, valid profiles array
// which is terminated by FF_PROFILE_UNKNOWN.
self.0 = unsafe { self.0.offset(1) };
Some(profile)
Some(AvProfile(profile))
}
}
}