use super::{GeometryOverflow, InsufficientPlane, InsufficientStride, ZeroDimension};
use derive_more::{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>;