use super::{GeometryOverflow, InsufficientPlane, InsufficientStride, ZeroDimension};
use derive_more::{Display, IsVariant, TryUnwrap, Unwrap};
use thiserror::Error;
#[derive(Debug, Clone, Copy)]
pub struct GbrpHighBitFrame<'a, const BITS: u32, const BE: bool = false> {
g: &'a [u16],
b: &'a [u16],
r: &'a [u16],
width: u32,
height: u32,
g_stride: u32,
b_stride: u32,
r_stride: u32,
}
impl<'a, const BITS: u32, const BE: bool> GbrpHighBitFrame<'a, BITS, BE> {
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn try_new(
g: &'a [u16],
b: &'a [u16],
r: &'a [u16],
width: u32,
height: u32,
g_stride: u32,
b_stride: u32,
r_stride: u32,
) -> Result<Self, GbrpHighBitFrameError> {
const {
assert!(
matches!(BITS, 9 | 10 | 12 | 14 | 16),
"BITS must be one of 9, 10, 12, 14, or 16",
);
}
if width == 0 || height == 0 {
return Err(GbrpHighBitFrameError::ZeroDimension(ZeroDimension::new(
width, height,
)));
}
if g_stride < width {
return Err(GbrpHighBitFrameError::InsufficientGStride(
InsufficientStride::new(g_stride, width),
));
}
if b_stride < width {
return Err(GbrpHighBitFrameError::InsufficientBStride(
InsufficientStride::new(b_stride, width),
));
}
if r_stride < width {
return Err(GbrpHighBitFrameError::InsufficientRStride(
InsufficientStride::new(r_stride, width),
));
}
let g_min = match (g_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(GbrpHighBitFrameError::GeometryOverflow(
GeometryOverflow::new(g_stride, height),
));
}
};
if g.len() < g_min {
return Err(GbrpHighBitFrameError::InsufficientGPlane(
InsufficientPlane::new(g_min, g.len()),
));
}
let b_min = match (b_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(GbrpHighBitFrameError::GeometryOverflow(
GeometryOverflow::new(b_stride, height),
));
}
};
if b.len() < b_min {
return Err(GbrpHighBitFrameError::InsufficientBPlane(
InsufficientPlane::new(b_min, b.len()),
));
}
let r_min = match (r_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(GbrpHighBitFrameError::GeometryOverflow(
GeometryOverflow::new(r_stride, height),
));
}
};
if r.len() < r_min {
return Err(GbrpHighBitFrameError::InsufficientRPlane(
InsufficientPlane::new(r_min, r.len()),
));
}
Ok(Self {
g,
b,
r,
width,
height,
g_stride,
b_stride,
r_stride,
})
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn new(
g: &'a [u16],
b: &'a [u16],
r: &'a [u16],
width: u32,
height: u32,
g_stride: u32,
b_stride: u32,
r_stride: u32,
) -> Self {
match Self::try_new(g, b, r, width, height, g_stride, b_stride, r_stride) {
Ok(frame) => frame,
Err(_) => panic!("invalid GbrpHighBitFrame dimensions or plane lengths"),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn g(&self) -> &'a [u16] {
self.g
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn b(&self) -> &'a [u16] {
self.b
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn r(&self) -> &'a [u16] {
self.r
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn width(&self) -> u32 {
self.width
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn height(&self) -> u32 {
self.height
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn g_stride(&self) -> u32 {
self.g_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn b_stride(&self) -> u32 {
self.b_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn r_stride(&self) -> u32 {
self.r_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn bits(&self) -> u32 {
BITS
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn is_be(&self) -> bool {
BE
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn y(&self) -> &'a [u16] {
self.g
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn u(&self) -> &'a [u16] {
self.b
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn v(&self) -> &'a [u16] {
self.r
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn y_stride(&self) -> u32 {
self.g_stride
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn u_stride(&self) -> u32 {
self.b_stride
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn v_stride(&self) -> u32 {
self.r_stride
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, IsVariant, TryUnwrap, Unwrap, Error)]
#[non_exhaustive]
#[unwrap(ref, ref_mut)]
#[try_unwrap(ref, ref_mut)]
pub enum GbrpHighBitFrameError {
#[error(transparent)]
ZeroDimension(ZeroDimension),
#[error(transparent)]
InsufficientGStride(InsufficientStride),
#[error(transparent)]
InsufficientBStride(InsufficientStride),
#[error(transparent)]
InsufficientRStride(InsufficientStride),
#[error(transparent)]
InsufficientGPlane(InsufficientPlane),
#[error(transparent)]
InsufficientBPlane(InsufficientPlane),
#[error(transparent)]
InsufficientRPlane(InsufficientPlane),
#[error(transparent)]
GeometryOverflow(GeometryOverflow),
}
pub type Gbrp9Frame<'a, const BE: bool = false> = GbrpHighBitFrame<'a, 9, BE>;
pub type Gbrp9LeFrame<'a> = GbrpHighBitFrame<'a, 9, false>;
pub type Gbrp9BeFrame<'a> = GbrpHighBitFrame<'a, 9, true>;
pub type Gbrp10Frame<'a, const BE: bool = false> = GbrpHighBitFrame<'a, 10, BE>;
pub type Gbrp10LeFrame<'a> = GbrpHighBitFrame<'a, 10, false>;
pub type Gbrp10BeFrame<'a> = GbrpHighBitFrame<'a, 10, true>;
pub type Gbrp12Frame<'a, const BE: bool = false> = GbrpHighBitFrame<'a, 12, BE>;
pub type Gbrp12LeFrame<'a> = GbrpHighBitFrame<'a, 12, false>;
pub type Gbrp12BeFrame<'a> = GbrpHighBitFrame<'a, 12, true>;
pub type Gbrp14Frame<'a, const BE: bool = false> = GbrpHighBitFrame<'a, 14, BE>;
pub type Gbrp14LeFrame<'a> = GbrpHighBitFrame<'a, 14, false>;
pub type Gbrp14BeFrame<'a> = GbrpHighBitFrame<'a, 14, true>;
pub type Gbrp16Frame<'a, const BE: bool = false> = GbrpHighBitFrame<'a, 16, BE>;
pub type Gbrp16LeFrame<'a> = GbrpHighBitFrame<'a, 16, false>;
pub type Gbrp16BeFrame<'a> = GbrpHighBitFrame<'a, 16, true>;
#[derive(Debug, Clone, Copy)]
pub struct GbrapHighBitFrame<'a, const BITS: u32, const BE: bool = false> {
g: &'a [u16],
b: &'a [u16],
r: &'a [u16],
a: &'a [u16],
width: u32,
height: u32,
g_stride: u32,
b_stride: u32,
r_stride: u32,
a_stride: u32,
}
impl<'a, const BITS: u32, const BE: bool> GbrapHighBitFrame<'a, BITS, BE> {
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn try_new(
g: &'a [u16],
b: &'a [u16],
r: &'a [u16],
a: &'a [u16],
width: u32,
height: u32,
g_stride: u32,
b_stride: u32,
r_stride: u32,
a_stride: u32,
) -> Result<Self, GbrapHighBitFrameError> {
const {
assert!(
matches!(BITS, 10 | 12 | 14 | 16),
"BITS must be one of 10, 12, 14, or 16 (FFmpeg has no GBRAP9 variant)",
);
}
if width == 0 || height == 0 {
return Err(GbrapHighBitFrameError::ZeroDimension(ZeroDimension::new(
width, height,
)));
}
if g_stride < width {
return Err(GbrapHighBitFrameError::InsufficientGStride(
InsufficientStride::new(g_stride, width),
));
}
if b_stride < width {
return Err(GbrapHighBitFrameError::InsufficientBStride(
InsufficientStride::new(b_stride, width),
));
}
if r_stride < width {
return Err(GbrapHighBitFrameError::InsufficientRStride(
InsufficientStride::new(r_stride, width),
));
}
if a_stride < width {
return Err(GbrapHighBitFrameError::InsufficientAStride(
InsufficientStride::new(a_stride, width),
));
}
let g_min = match (g_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(GbrapHighBitFrameError::GeometryOverflow(
GeometryOverflow::new(g_stride, height),
));
}
};
if g.len() < g_min {
return Err(GbrapHighBitFrameError::InsufficientGPlane(
InsufficientPlane::new(g_min, g.len()),
));
}
let b_min = match (b_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(GbrapHighBitFrameError::GeometryOverflow(
GeometryOverflow::new(b_stride, height),
));
}
};
if b.len() < b_min {
return Err(GbrapHighBitFrameError::InsufficientBPlane(
InsufficientPlane::new(b_min, b.len()),
));
}
let r_min = match (r_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(GbrapHighBitFrameError::GeometryOverflow(
GeometryOverflow::new(r_stride, height),
));
}
};
if r.len() < r_min {
return Err(GbrapHighBitFrameError::InsufficientRPlane(
InsufficientPlane::new(r_min, r.len()),
));
}
let a_min = match (a_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(GbrapHighBitFrameError::GeometryOverflow(
GeometryOverflow::new(a_stride, height),
));
}
};
if a.len() < a_min {
return Err(GbrapHighBitFrameError::InsufficientAPlane(
InsufficientPlane::new(a_min, a.len()),
));
}
Ok(Self {
g,
b,
r,
a,
width,
height,
g_stride,
b_stride,
r_stride,
a_stride,
})
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn new(
g: &'a [u16],
b: &'a [u16],
r: &'a [u16],
a: &'a [u16],
width: u32,
height: u32,
g_stride: u32,
b_stride: u32,
r_stride: u32,
a_stride: u32,
) -> Self {
match Self::try_new(
g, b, r, a, width, height, g_stride, b_stride, r_stride, a_stride,
) {
Ok(frame) => frame,
Err(_) => panic!("invalid GbrapHighBitFrame dimensions or plane lengths"),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn g(&self) -> &'a [u16] {
self.g
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn b(&self) -> &'a [u16] {
self.b
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn r(&self) -> &'a [u16] {
self.r
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn a(&self) -> &'a [u16] {
self.a
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn width(&self) -> u32 {
self.width
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn height(&self) -> u32 {
self.height
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn g_stride(&self) -> u32 {
self.g_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn b_stride(&self) -> u32 {
self.b_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn r_stride(&self) -> u32 {
self.r_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn a_stride(&self) -> u32 {
self.a_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn bits(&self) -> u32 {
BITS
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn is_be(&self) -> bool {
BE
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn y(&self) -> &'a [u16] {
self.g
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn u(&self) -> &'a [u16] {
self.b
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn v(&self) -> &'a [u16] {
self.r
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn y_stride(&self) -> u32 {
self.g_stride
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn u_stride(&self) -> u32 {
self.b_stride
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn v_stride(&self) -> u32 {
self.r_stride
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, IsVariant, TryUnwrap, Unwrap, Error)]
#[non_exhaustive]
#[unwrap(ref, ref_mut)]
#[try_unwrap(ref, ref_mut)]
pub enum GbrapHighBitFrameError {
#[error(transparent)]
ZeroDimension(ZeroDimension),
#[error(transparent)]
InsufficientGStride(InsufficientStride),
#[error(transparent)]
InsufficientBStride(InsufficientStride),
#[error(transparent)]
InsufficientRStride(InsufficientStride),
#[error(transparent)]
InsufficientAStride(InsufficientStride),
#[error(transparent)]
InsufficientGPlane(InsufficientPlane),
#[error(transparent)]
InsufficientBPlane(InsufficientPlane),
#[error(transparent)]
InsufficientRPlane(InsufficientPlane),
#[error(transparent)]
InsufficientAPlane(InsufficientPlane),
#[error(transparent)]
GeometryOverflow(GeometryOverflow),
}
pub type Gbrap10Frame<'a, const BE: bool = false> = GbrapHighBitFrame<'a, 10, BE>;
pub type Gbrap10LeFrame<'a> = GbrapHighBitFrame<'a, 10, false>;
pub type Gbrap10BeFrame<'a> = GbrapHighBitFrame<'a, 10, true>;
pub type Gbrap12Frame<'a, const BE: bool = false> = GbrapHighBitFrame<'a, 12, BE>;
pub type Gbrap12LeFrame<'a> = GbrapHighBitFrame<'a, 12, false>;
pub type Gbrap12BeFrame<'a> = GbrapHighBitFrame<'a, 12, true>;
pub type Gbrap14Frame<'a, const BE: bool = false> = GbrapHighBitFrame<'a, 14, BE>;
pub type Gbrap14LeFrame<'a> = GbrapHighBitFrame<'a, 14, false>;
pub type Gbrap14BeFrame<'a> = GbrapHighBitFrame<'a, 14, true>;
pub type Gbrap16Frame<'a, const BE: bool = false> = GbrapHighBitFrame<'a, 16, BE>;
pub type Gbrap16LeFrame<'a> = GbrapHighBitFrame<'a, 16, false>;
pub type Gbrap16BeFrame<'a> = GbrapHighBitFrame<'a, 16, true>;
#[derive(Debug, Clone, Copy)]
pub struct GbrpMsbFrame<'a, const BITS: u32, const BE: bool = false> {
g: &'a [u16],
b: &'a [u16],
r: &'a [u16],
width: u32,
height: u32,
g_stride: u32,
b_stride: u32,
r_stride: u32,
}
impl<'a, const BITS: u32, const BE: bool> GbrpMsbFrame<'a, BITS, BE> {
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn try_new(
g: &'a [u16],
b: &'a [u16],
r: &'a [u16],
width: u32,
height: u32,
g_stride: u32,
b_stride: u32,
r_stride: u32,
) -> Result<Self, GbrpMsbFrameError> {
const {
assert!(
matches!(BITS, 10 | 12),
"BITS must be one of 10 or 12 (FFmpeg defines GBRP MSB variants only at 10 and 12 bits)",
);
}
if width == 0 || height == 0 {
return Err(GbrpMsbFrameError::ZeroDimension(ZeroDimension::new(
width, height,
)));
}
if g_stride < width {
return Err(GbrpMsbFrameError::InsufficientGStride(
InsufficientStride::new(g_stride, width),
));
}
if b_stride < width {
return Err(GbrpMsbFrameError::InsufficientBStride(
InsufficientStride::new(b_stride, width),
));
}
if r_stride < width {
return Err(GbrpMsbFrameError::InsufficientRStride(
InsufficientStride::new(r_stride, width),
));
}
let g_min = match (g_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(GbrpMsbFrameError::GeometryOverflow(GeometryOverflow::new(
g_stride, height,
)));
}
};
if g.len() < g_min {
return Err(GbrpMsbFrameError::InsufficientGPlane(
InsufficientPlane::new(g_min, g.len()),
));
}
let b_min = match (b_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(GbrpMsbFrameError::GeometryOverflow(GeometryOverflow::new(
b_stride, height,
)));
}
};
if b.len() < b_min {
return Err(GbrpMsbFrameError::InsufficientBPlane(
InsufficientPlane::new(b_min, b.len()),
));
}
let r_min = match (r_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(GbrpMsbFrameError::GeometryOverflow(GeometryOverflow::new(
r_stride, height,
)));
}
};
if r.len() < r_min {
return Err(GbrpMsbFrameError::InsufficientRPlane(
InsufficientPlane::new(r_min, r.len()),
));
}
Ok(Self {
g,
b,
r,
width,
height,
g_stride,
b_stride,
r_stride,
})
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn new(
g: &'a [u16],
b: &'a [u16],
r: &'a [u16],
width: u32,
height: u32,
g_stride: u32,
b_stride: u32,
r_stride: u32,
) -> Self {
match Self::try_new(g, b, r, width, height, g_stride, b_stride, r_stride) {
Ok(frame) => frame,
Err(_) => panic!("invalid GbrpMsbFrame dimensions or plane lengths"),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub fn try_new_checked(
g: &'a [u16],
b: &'a [u16],
r: &'a [u16],
width: u32,
height: u32,
g_stride: u32,
b_stride: u32,
r_stride: u32,
) -> Result<Self, GbrpMsbFrameError> {
let frame = Self::try_new(g, b, r, width, height, g_stride, b_stride, r_stride)?;
const {
assert!(
BITS < 16,
"MSB low-bit mask is only meaningful for BITS < 16"
)
};
let low_mask: u16 = (1u16 << (16 - BITS)) - 1;
let w = width as usize;
let h = height as usize;
let planes: [(&[u16], u32, GbrpMsbFramePlane); 3] = [
(g, g_stride, GbrpMsbFramePlane::G),
(b, b_stride, GbrpMsbFramePlane::B),
(r, r_stride, GbrpMsbFramePlane::R),
];
for (plane, stride, which) in planes {
let stride = stride as usize;
for row in 0..h {
let start = row * stride;
for (col, &s) in plane[start..start + w].iter().enumerate() {
let logical = if BE { u16::from_be(s) } else { u16::from_le(s) };
if logical & low_mask != 0 {
return Err(GbrpMsbFrameError::StrayLowBits(GbrpMsbStrayLowBits::new(
which,
start + col,
logical,
)));
}
}
}
}
Ok(frame)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn g(&self) -> &'a [u16] {
self.g
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn b(&self) -> &'a [u16] {
self.b
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn r(&self) -> &'a [u16] {
self.r
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn width(&self) -> u32 {
self.width
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn height(&self) -> u32 {
self.height
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn g_stride(&self) -> u32 {
self.g_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn b_stride(&self) -> u32 {
self.b_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn r_stride(&self) -> u32 {
self.r_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn bits(&self) -> u32 {
BITS
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn is_be(&self) -> bool {
BE
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn y(&self) -> &'a [u16] {
self.g
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn u(&self) -> &'a [u16] {
self.b
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn v(&self) -> &'a [u16] {
self.r
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn y_stride(&self) -> u32 {
self.g_stride
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn u_stride(&self) -> u32 {
self.b_stride
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn v_stride(&self) -> u32 {
self.r_stride
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Display)]
pub enum GbrpMsbFramePlane {
G,
B,
R,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct GbrpMsbStrayLowBits {
plane: GbrpMsbFramePlane,
index: usize,
value: u16,
}
impl GbrpMsbStrayLowBits {
#[inline]
pub const fn new(plane: GbrpMsbFramePlane, index: usize, value: u16) -> Self {
Self {
plane,
index,
value,
}
}
#[inline]
pub const fn plane(&self) -> GbrpMsbFramePlane {
self.plane
}
#[inline]
pub const fn index(&self) -> usize {
self.index
}
#[inline]
pub const fn value(&self) -> u16 {
self.value
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, IsVariant, TryUnwrap, Unwrap, Error)]
#[non_exhaustive]
#[unwrap(ref, ref_mut)]
#[try_unwrap(ref, ref_mut)]
pub enum GbrpMsbFrameError {
#[error(transparent)]
ZeroDimension(ZeroDimension),
#[error(transparent)]
InsufficientGStride(InsufficientStride),
#[error(transparent)]
InsufficientBStride(InsufficientStride),
#[error(transparent)]
InsufficientRStride(InsufficientStride),
#[error(transparent)]
InsufficientGPlane(InsufficientPlane),
#[error(transparent)]
InsufficientBPlane(InsufficientPlane),
#[error(transparent)]
InsufficientRPlane(InsufficientPlane),
#[error(transparent)]
GeometryOverflow(GeometryOverflow),
#[error(
"sample {:#06x} on plane {} at element {} has non-zero low bits (not a valid GBRP MSB-packed sample)", .0.value(), .0.plane(), .0.index()
)]
StrayLowBits(GbrpMsbStrayLowBits),
}
pub type Gbrp10MsbFrame<'a, const BE: bool = false> = GbrpMsbFrame<'a, 10, BE>;
pub type Gbrp10MsbLeFrame<'a> = GbrpMsbFrame<'a, 10, false>;
pub type Gbrp10MsbBeFrame<'a> = GbrpMsbFrame<'a, 10, true>;
pub type Gbrp12MsbFrame<'a, const BE: bool = false> = GbrpMsbFrame<'a, 12, BE>;
pub type Gbrp12MsbLeFrame<'a> = GbrpMsbFrame<'a, 12, false>;
pub type Gbrp12MsbBeFrame<'a> = GbrpMsbFrame<'a, 12, true>;
#[derive(Debug, Clone, Copy)]
pub struct Gbrap32Frame<'a, const BE: bool = false> {
g: &'a [u32],
b: &'a [u32],
r: &'a [u32],
a: &'a [u32],
width: u32,
height: u32,
g_stride: u32,
b_stride: u32,
r_stride: u32,
a_stride: u32,
}
pub type Gbrap32LeFrame<'a> = Gbrap32Frame<'a, false>;
pub type Gbrap32BeFrame<'a> = Gbrap32Frame<'a, true>;
impl<'a, const BE: bool> Gbrap32Frame<'a, BE> {
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn try_new(
g: &'a [u32],
b: &'a [u32],
r: &'a [u32],
a: &'a [u32],
width: u32,
height: u32,
g_stride: u32,
b_stride: u32,
r_stride: u32,
a_stride: u32,
) -> Result<Self, Gbrap32FrameError> {
if width == 0 || height == 0 {
return Err(Gbrap32FrameError::ZeroDimension(ZeroDimension::new(
width, height,
)));
}
if g_stride < width {
return Err(Gbrap32FrameError::InsufficientGStride(
InsufficientStride::new(g_stride, width),
));
}
if b_stride < width {
return Err(Gbrap32FrameError::InsufficientBStride(
InsufficientStride::new(b_stride, width),
));
}
if r_stride < width {
return Err(Gbrap32FrameError::InsufficientRStride(
InsufficientStride::new(r_stride, width),
));
}
if a_stride < width {
return Err(Gbrap32FrameError::InsufficientAStride(
InsufficientStride::new(a_stride, width),
));
}
let g_min = match (g_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(Gbrap32FrameError::GeometryOverflow(GeometryOverflow::new(
g_stride, height,
)));
}
};
if g.len() < g_min {
return Err(Gbrap32FrameError::InsufficientGPlane(
InsufficientPlane::new(g_min, g.len()),
));
}
let b_min = match (b_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(Gbrap32FrameError::GeometryOverflow(GeometryOverflow::new(
b_stride, height,
)));
}
};
if b.len() < b_min {
return Err(Gbrap32FrameError::InsufficientBPlane(
InsufficientPlane::new(b_min, b.len()),
));
}
let r_min = match (r_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(Gbrap32FrameError::GeometryOverflow(GeometryOverflow::new(
r_stride, height,
)));
}
};
if r.len() < r_min {
return Err(Gbrap32FrameError::InsufficientRPlane(
InsufficientPlane::new(r_min, r.len()),
));
}
let a_min = match (a_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(Gbrap32FrameError::GeometryOverflow(GeometryOverflow::new(
a_stride, height,
)));
}
};
if a.len() < a_min {
return Err(Gbrap32FrameError::InsufficientAPlane(
InsufficientPlane::new(a_min, a.len()),
));
}
Ok(Self {
g,
b,
r,
a,
width,
height,
g_stride,
b_stride,
r_stride,
a_stride,
})
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn new(
g: &'a [u32],
b: &'a [u32],
r: &'a [u32],
a: &'a [u32],
width: u32,
height: u32,
g_stride: u32,
b_stride: u32,
r_stride: u32,
a_stride: u32,
) -> Self {
match Self::try_new(
g, b, r, a, width, height, g_stride, b_stride, r_stride, a_stride,
) {
Ok(frame) => frame,
Err(_) => panic!("invalid Gbrap32Frame dimensions or plane lengths"),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn g(&self) -> &'a [u32] {
self.g
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn b(&self) -> &'a [u32] {
self.b
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn r(&self) -> &'a [u32] {
self.r
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn a(&self) -> &'a [u32] {
self.a
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn width(&self) -> u32 {
self.width
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn height(&self) -> u32 {
self.height
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn g_stride(&self) -> u32 {
self.g_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn b_stride(&self) -> u32 {
self.b_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn r_stride(&self) -> u32 {
self.r_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn a_stride(&self) -> u32 {
self.a_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn is_be(&self) -> bool {
BE
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn y(&self) -> &'a [u32] {
self.g
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn u(&self) -> &'a [u32] {
self.b
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn v(&self) -> &'a [u32] {
self.r
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn y_stride(&self) -> u32 {
self.g_stride
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn u_stride(&self) -> u32 {
self.b_stride
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn v_stride(&self) -> u32 {
self.r_stride
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, IsVariant, TryUnwrap, Unwrap, Error)]
#[non_exhaustive]
#[unwrap(ref, ref_mut)]
#[try_unwrap(ref, ref_mut)]
pub enum Gbrap32FrameError {
#[error(transparent)]
ZeroDimension(ZeroDimension),
#[error(transparent)]
InsufficientGStride(InsufficientStride),
#[error(transparent)]
InsufficientBStride(InsufficientStride),
#[error(transparent)]
InsufficientRStride(InsufficientStride),
#[error(transparent)]
InsufficientAStride(InsufficientStride),
#[error(transparent)]
InsufficientGPlane(InsufficientPlane),
#[error(transparent)]
InsufficientBPlane(InsufficientPlane),
#[error(transparent)]
InsufficientRPlane(InsufficientPlane),
#[error(transparent)]
InsufficientAPlane(InsufficientPlane),
#[error(transparent)]
GeometryOverflow(GeometryOverflow),
}