media: ffmpeg: Add helpers for determining line and plane sizes.

These are wrappers of av_image_get_linesize and
av_image_fill_plane_sizes, and will be used for bounds checking and
mmap bounds calculation purposes.

It's kind of weird that one is singular and the other is plural, but
we should probably blame FFmpeg for not having a singular version of
av_image_fill_plane_sizes.

BUG=b:239897269
TEST=cargo test --features "video-decoder,ffmpeg" -p ffmpeg -p devices

Change-Id: I34104f5062089377aeab0d4a4ab0534837e56d6f
Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/3868595
Reviewed-by: Alexandre Courbot <acourbot@chromium.org>
This commit is contained in:
Tatsuyuki Ishi 2022-09-02 11:44:11 +09:00 committed by crosvm LUCI
parent 40ba620f0a
commit 55d8d9b4eb
2 changed files with 62 additions and 0 deletions

View file

@ -329,6 +329,22 @@ impl AvPixelFormat {
// handles any value passed as argument.
unsafe { ffi::avcodec_pix_fmt_to_codec_tag(self.0) }.to_le_bytes()
}
/// Given the width and plane index, returns the line size (data pointer increment per row) in
/// bytes.
pub fn line_size(&self, width: u32, plane: usize) -> Result<usize, AvError> {
av_image_line_size(*self, width, plane)
}
/// Given an iterator of line sizes and height, return the size required for each plane's buffer
/// in bytes.
pub fn plane_sizes<I: IntoIterator<Item = u32>>(
&self,
linesizes: I,
height: u32,
) -> Result<Vec<usize>, AvError> {
av_image_plane_sizes(*self, linesizes, height)
}
}
impl Display for AvPixelFormat {

View file

@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::avcodec::AvError;
use crate::avcodec::AvPixelFormat;
use crate::ffi;
pub const AV_NOPTS_VALUE: u64 = 0x8000000000000000;
const MAX_FFMPEG_PLANES: usize = 4;
/// Get the maximum data alignment that may be required by FFmpeg.
/// This could change depending on FFmpeg's build configuration (AVX etc.).
@ -12,3 +15,46 @@ pub fn max_buffer_alignment() -> usize {
// Safe because this function has no side effects and just returns an integer.
unsafe { ffi::av_cpu_max_align() as usize }
}
// See AvPixelFormat::line_size.
pub(crate) fn av_image_line_size(
format: AvPixelFormat,
width: u32,
plane: usize,
) -> Result<usize, AvError> {
// Safe because format is a valid format and this function is pure computation.
match unsafe { ffi::av_image_get_linesize(format.pix_fmt(), width as _, plane as _) } {
i if i >= 0 => Ok(i as _),
err => Err(AvError(err)),
}
}
// See AvPixelFormat::plane_sizes.
pub(crate) fn av_image_plane_sizes<I: IntoIterator<Item = u32>>(
format: AvPixelFormat,
linesizes: I,
height: u32,
) -> Result<Vec<usize>, AvError> {
let mut linesizes_buf = [0; MAX_FFMPEG_PLANES];
let mut planes = 0;
for (i, linesize) in linesizes.into_iter().take(MAX_FFMPEG_PLANES).enumerate() {
linesizes_buf[i] = linesize as _;
planes += 1;
}
let mut plane_sizes_buf = [0; MAX_FFMPEG_PLANES];
// Safe because plane_sizes_buf and linesizes_buf have the size specified by the API, format is
// valid, and this function doesn't have any side effects other than writing to plane_sizes_buf.
AvError::result(unsafe {
ffi::av_image_fill_plane_sizes(
plane_sizes_buf.as_mut_ptr(),
format.pix_fmt(),
height as _,
linesizes_buf.as_ptr(),
)
})?;
Ok(plane_sizes_buf
.into_iter()
.map(|x| x as _)
.take(planes)
.collect())
}