pub const MAX_NUMBER_OF_PLANES: usize = 4;
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub enum PixelFormat {
Argb,
Bgra,
Bgr,
Rgba,
Rgb,
I444,
I422,
I420,
Nv12,
}
impl PixelFormat {
#[cfg(not(tarpaulin_include))]
pub(crate) const fn depth(pixel_format: PixelFormat) -> usize {
match pixel_format {
PixelFormat::Argb | PixelFormat::Bgra | PixelFormat::Rgba => 4,
PixelFormat::Bgr | PixelFormat::Rgb => 3,
_ => 0,
}
}
#[cfg(not(tarpaulin_include))]
pub(crate) const fn reversed(pixel_format: PixelFormat) -> bool {
matches!(pixel_format, PixelFormat::Rgba)
}
}
#[cfg(not(tarpaulin_include))]
impl std::fmt::Display for PixelFormat {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
PixelFormat::Argb => write!(f, "argb"),
PixelFormat::Bgra => write!(f, "bgra"),
PixelFormat::Bgr => write!(f, "bgr"),
PixelFormat::Rgba => write!(f, "rgba"),
PixelFormat::Rgb => write!(f, "rgb"),
PixelFormat::I444 => write!(f, "i444"),
PixelFormat::I422 => write!(f, "i422"),
PixelFormat::I420 => write!(f, "i420"),
PixelFormat::Nv12 => write!(f, "nv12"),
}
}
}
pub const STRIDE_AUTO: usize = 0;
pub const DEFAULT_STRIDES: [usize; MAX_NUMBER_OF_PLANES] = [STRIDE_AUTO; MAX_NUMBER_OF_PLANES];
#[cfg(not(tarpaulin_include))]
const fn make_pf_spec(planes: u32, width: u32, height: u32) -> u32 {
(height << 3) | (width << 2) | planes
}
#[cfg(not(tarpaulin_include))]
const fn make_plane_spec(plane0: u32, plane1: u32, plane2: u32, plane3: u32) -> u32 {
(plane3 << 18) | (plane2 << 12) | (plane1 << 6) | plane0
}
const INVALID_PLANE: u32 = 32;
const PF_SPECS: [u32; 9] = [
make_pf_spec(0, 0, 0),
make_pf_spec(0, 0, 0),
make_pf_spec(0, 0, 0),
make_pf_spec(0, 0, 0),
make_pf_spec(0, 0, 0),
make_pf_spec(2, 0, 0),
make_pf_spec(2, 1, 0),
make_pf_spec(2, 1, 1),
make_pf_spec(1, 1, 1),
];
const STRIDE_SPECS: [u32; 9] = [
make_plane_spec(0, 0, 0, 0),
make_plane_spec(0, 0, 0, 0),
make_plane_spec(0, 0, 0, INVALID_PLANE),
make_plane_spec(0, 0, 0, 0),
make_plane_spec(0, 0, 0, INVALID_PLANE),
make_plane_spec(0, 0, 0, INVALID_PLANE),
make_plane_spec(0, 1, 1, INVALID_PLANE),
make_plane_spec(0, 1, 1, INVALID_PLANE),
make_plane_spec(0, 0, INVALID_PLANE, INVALID_PLANE),
];
const HEIGHT_SPECS: [u32; 9] = [
make_plane_spec(0, 0, 0, 0),
make_plane_spec(0, 0, 0, 0),
make_plane_spec(0, 0, 0, INVALID_PLANE),
make_plane_spec(0, 0, 0, 0),
make_plane_spec(0, 0, 0, INVALID_PLANE),
make_plane_spec(0, 0, 0, INVALID_PLANE),
make_plane_spec(0, 0, 0, INVALID_PLANE),
make_plane_spec(0, 1, 1, INVALID_PLANE),
make_plane_spec(0, 1, INVALID_PLANE, INVALID_PLANE),
];
fn get_pf_width(pf: u32) -> u32 {
(pf >> 2) & 1
}
fn get_pf_height(pf: u32) -> u32 {
pf >> 3
}
fn get_pf_planes(pf: u32) -> u32 {
pf & 3
}
fn get_plane_value(bpp: u32, plane: usize) -> u32 {
(bpp >> (6 * plane)) & 0x3F
}
fn get_plane_mask(bpp: u32, plane: usize) -> usize {
usize::from(INVALID_PLANE != get_plane_value(bpp, plane))
}
fn get_plane_spec(dimension: u32, bpp: u32, plane: usize) -> usize {
(dimension.wrapping_shr(get_plane_value(bpp, plane))) as usize
}
pub fn is_compatible(pixel_format: u32, width: u32, height: u32, last_plane: u32) -> bool {
let spec = PF_SPECS[pixel_format as usize];
let planes = get_pf_planes(spec);
let matches_exact = last_plane.wrapping_sub(planes);
let last_plane = if pixel_format == (PixelFormat::Nv12 as u32) {
last_plane
} else {
1
};
((width & get_pf_width(spec))
| (height & get_pf_height(spec))
| (last_plane.wrapping_mul(matches_exact)))
== 0
}
pub fn get_buffers_size(
pixel_format: u32,
width: u32,
height: u32,
last_plane: u32,
strides: &[usize],
buffers_size: &mut [usize],
) -> bool {
let last_plane = last_plane as usize;
if last_plane >= MAX_NUMBER_OF_PLANES
|| last_plane >= strides.len()
|| last_plane >= buffers_size.len()
{
return false;
}
let stride = &mut [0_usize; MAX_NUMBER_OF_PLANES];
let pixel_format = pixel_format as usize;
let stride_spec = STRIDE_SPECS[pixel_format];
for i in 0..MAX_NUMBER_OF_PLANES {
stride[i] = if i >= strides.len() || strides[i] == STRIDE_AUTO {
get_plane_mask(stride_spec, i) * get_plane_spec(width, stride_spec, i)
} else {
strides[i]
};
}
let height_spec = HEIGHT_SPECS[pixel_format];
if last_plane == 0 {
buffers_size[0] = ((stride[0] * get_plane_spec(height, height_spec, 0))
+ (stride[1] * get_plane_spec(height, height_spec, 1)))
+ ((stride[2] * get_plane_spec(height, height_spec, 2))
+ (stride[3] * get_plane_spec(height, height_spec, 3)));
} else {
let buffer_array = &mut buffers_size[..=last_plane];
let stride_array = &stride[..=last_plane];
for (buffer_size, (i, stride)) in
buffer_array.iter_mut().zip(stride_array.iter().enumerate())
{
*buffer_size = *stride * get_plane_spec(height, height_spec, i);
}
}
true
}
#[cfg(not(feature = "test_instruction_sets"))]
pub fn are_planes_compatible(pixel_format: u32, num_planes: u32) -> bool {
let last_plane = num_planes.wrapping_sub(1);
let spec = PF_SPECS[pixel_format as usize];
let matches_exact = last_plane.wrapping_sub(get_pf_planes(spec));
let last_plane = if pixel_format == (PixelFormat::Nv12 as u32) {
last_plane
} else {
1
};
last_plane.wrapping_mul(matches_exact) == 0
}