use derive_more::{IsVariant, TryUnwrap, Unwrap};
use thiserror::Error;
use super::{
GeometryOverflow, InsufficientPlane, InsufficientStride, WidthAlignment, ZeroDimension,
};
#[derive(Debug, Clone, Copy)]
pub struct Yuv420pFrame<'a> {
y: &'a [u8],
u: &'a [u8],
v: &'a [u8],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
}
impl<'a> Yuv420pFrame<'a> {
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn try_new(
y: &'a [u8],
u: &'a [u8],
v: &'a [u8],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Result<Self, Yuv420pFrameError> {
if width == 0 || height == 0 {
return Err(Yuv420pFrameError::ZeroDimension(ZeroDimension::new(
width, height,
)));
}
if width & 1 != 0 {
return Err(Yuv420pFrameError::WidthAlignment(WidthAlignment::odd(
width as usize,
)));
}
if y_stride < width {
return Err(Yuv420pFrameError::InsufficientYStride(
InsufficientStride::new(y_stride, width),
));
}
let chroma_width = width.div_ceil(2);
if u_stride < chroma_width {
return Err(Yuv420pFrameError::InsufficientUStride(
InsufficientStride::new(u_stride, chroma_width),
));
}
if v_stride < chroma_width {
return Err(Yuv420pFrameError::InsufficientVStride(
InsufficientStride::new(v_stride, chroma_width),
));
}
let y_min = match (y_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(Yuv420pFrameError::GeometryOverflow(GeometryOverflow::new(
y_stride, height,
)));
}
};
if y.len() < y_min {
return Err(Yuv420pFrameError::InsufficientYPlane(
InsufficientPlane::new(y_min, y.len()),
));
}
let chroma_height = height.div_ceil(2);
let u_min = match (u_stride as usize).checked_mul(chroma_height as usize) {
Some(v) => v,
None => {
return Err(Yuv420pFrameError::GeometryOverflow(GeometryOverflow::new(
u_stride,
chroma_height,
)));
}
};
if u.len() < u_min {
return Err(Yuv420pFrameError::InsufficientUPlane(
InsufficientPlane::new(u_min, u.len()),
));
}
let v_min = match (v_stride as usize).checked_mul(chroma_height as usize) {
Some(v) => v,
None => {
return Err(Yuv420pFrameError::GeometryOverflow(GeometryOverflow::new(
v_stride,
chroma_height,
)));
}
};
if v.len() < v_min {
return Err(Yuv420pFrameError::InsufficientVPlane(
InsufficientPlane::new(v_min, v.len()),
));
}
Ok(Self {
y,
u,
v,
width,
height,
y_stride,
u_stride,
v_stride,
})
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn new(
y: &'a [u8],
u: &'a [u8],
v: &'a [u8],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Self {
match Self::try_new(y, u, v, width, height, y_stride, u_stride, v_stride) {
Ok(frame) => frame,
Err(_) => panic!("invalid Yuv420pFrame dimensions or plane lengths"),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn y(&self) -> &'a [u8] {
self.y
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn u(&self) -> &'a [u8] {
self.u
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn v(&self) -> &'a [u8] {
self.v
}
#[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 y_stride(&self) -> u32 {
self.y_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn u_stride(&self) -> u32 {
self.u_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn v_stride(&self) -> u32 {
self.v_stride
}
}
#[derive(Debug, Clone, Copy)]
pub struct Yuv422pFrame<'a> {
y: &'a [u8],
u: &'a [u8],
v: &'a [u8],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
}
impl<'a> Yuv422pFrame<'a> {
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn try_new(
y: &'a [u8],
u: &'a [u8],
v: &'a [u8],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Result<Self, Yuv422pFrameError> {
if width == 0 || height == 0 {
return Err(Yuv422pFrameError::ZeroDimension(ZeroDimension::new(
width, height,
)));
}
if width & 1 != 0 {
return Err(Yuv422pFrameError::WidthAlignment(WidthAlignment::odd(
width as usize,
)));
}
if y_stride < width {
return Err(Yuv422pFrameError::InsufficientYStride(
InsufficientStride::new(y_stride, width),
));
}
let chroma_width = width.div_ceil(2);
if u_stride < chroma_width {
return Err(Yuv422pFrameError::InsufficientUStride(
InsufficientStride::new(u_stride, chroma_width),
));
}
if v_stride < chroma_width {
return Err(Yuv422pFrameError::InsufficientVStride(
InsufficientStride::new(v_stride, chroma_width),
));
}
let y_min = match (y_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(Yuv422pFrameError::GeometryOverflow(GeometryOverflow::new(
y_stride, height,
)));
}
};
if y.len() < y_min {
return Err(Yuv422pFrameError::InsufficientYPlane(
InsufficientPlane::new(y_min, y.len()),
));
}
let u_min = match (u_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(Yuv422pFrameError::GeometryOverflow(GeometryOverflow::new(
u_stride, height,
)));
}
};
if u.len() < u_min {
return Err(Yuv422pFrameError::InsufficientUPlane(
InsufficientPlane::new(u_min, u.len()),
));
}
let v_min = match (v_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(Yuv422pFrameError::GeometryOverflow(GeometryOverflow::new(
v_stride, height,
)));
}
};
if v.len() < v_min {
return Err(Yuv422pFrameError::InsufficientVPlane(
InsufficientPlane::new(v_min, v.len()),
));
}
Ok(Self {
y,
u,
v,
width,
height,
y_stride,
u_stride,
v_stride,
})
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn new(
y: &'a [u8],
u: &'a [u8],
v: &'a [u8],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Self {
match Self::try_new(y, u, v, width, height, y_stride, u_stride, v_stride) {
Ok(frame) => frame,
Err(_) => panic!("invalid Yuv422pFrame dimensions or plane lengths"),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn y(&self) -> &'a [u8] {
self.y
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn u(&self) -> &'a [u8] {
self.u
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn v(&self) -> &'a [u8] {
self.v
}
#[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 y_stride(&self) -> u32 {
self.y_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn u_stride(&self) -> u32 {
self.u_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn v_stride(&self) -> u32 {
self.v_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 Yuv422pFrameError {
#[error(transparent)]
ZeroDimension(ZeroDimension),
#[error(transparent)]
WidthAlignment(WidthAlignment),
#[error(transparent)]
InsufficientYStride(InsufficientStride),
#[error(transparent)]
InsufficientUStride(InsufficientStride),
#[error(transparent)]
InsufficientVStride(InsufficientStride),
#[error(transparent)]
InsufficientYPlane(InsufficientPlane),
#[error(transparent)]
InsufficientUPlane(InsufficientPlane),
#[error(transparent)]
InsufficientVPlane(InsufficientPlane),
#[error(transparent)]
GeometryOverflow(GeometryOverflow),
}
#[derive(Debug, Clone, Copy)]
pub struct Yuv444pFrame<'a> {
y: &'a [u8],
u: &'a [u8],
v: &'a [u8],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
}
impl<'a> Yuv444pFrame<'a> {
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn try_new(
y: &'a [u8],
u: &'a [u8],
v: &'a [u8],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Result<Self, Yuv444pFrameError> {
if width == 0 || height == 0 {
return Err(Yuv444pFrameError::ZeroDimension(ZeroDimension::new(
width, height,
)));
}
if y_stride < width {
return Err(Yuv444pFrameError::InsufficientYStride(
InsufficientStride::new(y_stride, width),
));
}
if u_stride < width {
return Err(Yuv444pFrameError::InsufficientUStride(
InsufficientStride::new(u_stride, width),
));
}
if v_stride < width {
return Err(Yuv444pFrameError::InsufficientVStride(
InsufficientStride::new(v_stride, width),
));
}
let y_min = match (y_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(Yuv444pFrameError::GeometryOverflow(GeometryOverflow::new(
y_stride, height,
)));
}
};
if y.len() < y_min {
return Err(Yuv444pFrameError::InsufficientYPlane(
InsufficientPlane::new(y_min, y.len()),
));
}
let u_min = match (u_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(Yuv444pFrameError::GeometryOverflow(GeometryOverflow::new(
u_stride, height,
)));
}
};
if u.len() < u_min {
return Err(Yuv444pFrameError::InsufficientUPlane(
InsufficientPlane::new(u_min, u.len()),
));
}
let v_min = match (v_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(Yuv444pFrameError::GeometryOverflow(GeometryOverflow::new(
v_stride, height,
)));
}
};
if v.len() < v_min {
return Err(Yuv444pFrameError::InsufficientVPlane(
InsufficientPlane::new(v_min, v.len()),
));
}
Ok(Self {
y,
u,
v,
width,
height,
y_stride,
u_stride,
v_stride,
})
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn new(
y: &'a [u8],
u: &'a [u8],
v: &'a [u8],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Self {
match Self::try_new(y, u, v, width, height, y_stride, u_stride, v_stride) {
Ok(frame) => frame,
Err(_) => panic!("invalid Yuv444pFrame dimensions or plane lengths"),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn y(&self) -> &'a [u8] {
self.y
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn u(&self) -> &'a [u8] {
self.u
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn v(&self) -> &'a [u8] {
self.v
}
#[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 y_stride(&self) -> u32 {
self.y_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn u_stride(&self) -> u32 {
self.u_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn v_stride(&self) -> u32 {
self.v_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 Yuv444pFrameError {
#[error(transparent)]
ZeroDimension(ZeroDimension),
#[error(transparent)]
InsufficientYStride(InsufficientStride),
#[error(transparent)]
InsufficientUStride(InsufficientStride),
#[error(transparent)]
InsufficientVStride(InsufficientStride),
#[error(transparent)]
InsufficientYPlane(InsufficientPlane),
#[error(transparent)]
InsufficientUPlane(InsufficientPlane),
#[error(transparent)]
InsufficientVPlane(InsufficientPlane),
#[error(transparent)]
GeometryOverflow(GeometryOverflow),
}
#[derive(Debug, Clone, Copy)]
pub struct Yuv440pFrame<'a> {
y: &'a [u8],
u: &'a [u8],
v: &'a [u8],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
}
impl<'a> Yuv440pFrame<'a> {
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn try_new(
y: &'a [u8],
u: &'a [u8],
v: &'a [u8],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Result<Self, Yuv440pFrameError> {
if width == 0 || height == 0 {
return Err(Yuv444pFrameError::ZeroDimension(ZeroDimension::new(
width, height,
)));
}
if y_stride < width {
return Err(Yuv444pFrameError::InsufficientYStride(
InsufficientStride::new(y_stride, width),
));
}
if u_stride < width {
return Err(Yuv444pFrameError::InsufficientUStride(
InsufficientStride::new(u_stride, width),
));
}
if v_stride < width {
return Err(Yuv444pFrameError::InsufficientVStride(
InsufficientStride::new(v_stride, width),
));
}
let y_min = match (y_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(Yuv444pFrameError::GeometryOverflow(GeometryOverflow::new(
y_stride, height,
)));
}
};
if y.len() < y_min {
return Err(Yuv444pFrameError::InsufficientYPlane(
InsufficientPlane::new(y_min, y.len()),
));
}
let chroma_height = height.div_ceil(2);
let u_min = match (u_stride as usize).checked_mul(chroma_height as usize) {
Some(v) => v,
None => {
return Err(Yuv444pFrameError::GeometryOverflow(GeometryOverflow::new(
u_stride,
chroma_height,
)));
}
};
if u.len() < u_min {
return Err(Yuv444pFrameError::InsufficientUPlane(
InsufficientPlane::new(u_min, u.len()),
));
}
let v_min = match (v_stride as usize).checked_mul(chroma_height as usize) {
Some(v) => v,
None => {
return Err(Yuv444pFrameError::GeometryOverflow(GeometryOverflow::new(
v_stride,
chroma_height,
)));
}
};
if v.len() < v_min {
return Err(Yuv444pFrameError::InsufficientVPlane(
InsufficientPlane::new(v_min, v.len()),
));
}
Ok(Self {
y,
u,
v,
width,
height,
y_stride,
u_stride,
v_stride,
})
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn new(
y: &'a [u8],
u: &'a [u8],
v: &'a [u8],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Self {
match Self::try_new(y, u, v, width, height, y_stride, u_stride, v_stride) {
Ok(frame) => frame,
Err(_) => panic!("invalid Yuv440pFrame dimensions or plane lengths"),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn y(&self) -> &'a [u8] {
self.y
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn u(&self) -> &'a [u8] {
self.u
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn v(&self) -> &'a [u8] {
self.v
}
#[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 y_stride(&self) -> u32 {
self.y_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn u_stride(&self) -> u32 {
self.u_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn v_stride(&self) -> u32 {
self.v_stride
}
}
pub type Yuv440pFrameError = Yuv444pFrameError;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, IsVariant, TryUnwrap, Unwrap, Error)]
#[non_exhaustive]
#[unwrap(ref, ref_mut)]
#[try_unwrap(ref, ref_mut)]
pub enum Yuv420pFrameError {
#[error(transparent)]
ZeroDimension(ZeroDimension),
#[error(transparent)]
WidthAlignment(WidthAlignment),
#[error(transparent)]
InsufficientYStride(InsufficientStride),
#[error(transparent)]
InsufficientUStride(InsufficientStride),
#[error(transparent)]
InsufficientVStride(InsufficientStride),
#[error(transparent)]
InsufficientYPlane(InsufficientPlane),
#[error(transparent)]
InsufficientUPlane(InsufficientPlane),
#[error(transparent)]
InsufficientVPlane(InsufficientPlane),
#[error(transparent)]
GeometryOverflow(GeometryOverflow),
}
#[derive(Debug, Clone, Copy)]
pub struct Yuv410pFrame<'a> {
y: &'a [u8],
u: &'a [u8],
v: &'a [u8],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
}
impl<'a> Yuv410pFrame<'a> {
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn try_new(
y: &'a [u8],
u: &'a [u8],
v: &'a [u8],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Result<Self, Yuv410pFrameError> {
if width == 0 || height == 0 {
return Err(Yuv410pFrameError::ZeroDimension(ZeroDimension::new(
width, height,
)));
}
if width & 3 != 0 {
return Err(Yuv410pFrameError::WidthAlignment(
WidthAlignment::multiple_of_four(width as usize),
));
}
if y_stride < width {
return Err(Yuv410pFrameError::InsufficientYStride(
InsufficientStride::new(y_stride, width),
));
}
let chroma_width = width / 4;
if u_stride < chroma_width {
return Err(Yuv410pFrameError::InsufficientUStride(
InsufficientStride::new(u_stride, chroma_width),
));
}
if v_stride < chroma_width {
return Err(Yuv410pFrameError::InsufficientVStride(
InsufficientStride::new(v_stride, chroma_width),
));
}
let y_min = match (y_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(Yuv410pFrameError::GeometryOverflow(GeometryOverflow::new(
y_stride, height,
)));
}
};
if y.len() < y_min {
return Err(Yuv410pFrameError::InsufficientYPlane(
InsufficientPlane::new(y_min, y.len()),
));
}
let chroma_height = height.div_ceil(4);
let u_min = match (u_stride as usize).checked_mul(chroma_height as usize) {
Some(v) => v,
None => {
return Err(Yuv410pFrameError::GeometryOverflow(GeometryOverflow::new(
u_stride,
chroma_height,
)));
}
};
if u.len() < u_min {
return Err(Yuv410pFrameError::InsufficientUPlane(
InsufficientPlane::new(u_min, u.len()),
));
}
let v_min = match (v_stride as usize).checked_mul(chroma_height as usize) {
Some(v) => v,
None => {
return Err(Yuv410pFrameError::GeometryOverflow(GeometryOverflow::new(
v_stride,
chroma_height,
)));
}
};
if v.len() < v_min {
return Err(Yuv410pFrameError::InsufficientVPlane(
InsufficientPlane::new(v_min, v.len()),
));
}
Ok(Self {
y,
u,
v,
width,
height,
y_stride,
u_stride,
v_stride,
})
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn new(
y: &'a [u8],
u: &'a [u8],
v: &'a [u8],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Self {
match Self::try_new(y, u, v, width, height, y_stride, u_stride, v_stride) {
Ok(frame) => frame,
Err(_) => panic!("invalid Yuv410pFrame dimensions or plane lengths"),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn y(&self) -> &'a [u8] {
self.y
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn u(&self) -> &'a [u8] {
self.u
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn v(&self) -> &'a [u8] {
self.v
}
#[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 y_stride(&self) -> u32 {
self.y_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn u_stride(&self) -> u32 {
self.u_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn v_stride(&self) -> u32 {
self.v_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 Yuv410pFrameError {
#[error(transparent)]
ZeroDimension(ZeroDimension),
#[error(transparent)]
WidthAlignment(WidthAlignment),
#[error(transparent)]
InsufficientYStride(InsufficientStride),
#[error(transparent)]
InsufficientUStride(InsufficientStride),
#[error(transparent)]
InsufficientVStride(InsufficientStride),
#[error(transparent)]
InsufficientYPlane(InsufficientPlane),
#[error(transparent)]
InsufficientUPlane(InsufficientPlane),
#[error(transparent)]
InsufficientVPlane(InsufficientPlane),
#[error(transparent)]
GeometryOverflow(GeometryOverflow),
}
#[derive(Debug, Clone, Copy)]
pub struct Yuv411pFrame<'a> {
y: &'a [u8],
u: &'a [u8],
v: &'a [u8],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
}
impl<'a> Yuv411pFrame<'a> {
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn try_new(
y: &'a [u8],
u: &'a [u8],
v: &'a [u8],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Result<Self, Yuv411pFrameError> {
if width == 0 || height == 0 {
return Err(Yuv411pFrameError::ZeroDimension(ZeroDimension::new(
width, height,
)));
}
if y_stride < width {
return Err(Yuv411pFrameError::InsufficientYStride(
InsufficientStride::new(y_stride, width),
));
}
let chroma_width = width.div_ceil(4);
if u_stride < chroma_width {
return Err(Yuv411pFrameError::InsufficientUStride(
InsufficientStride::new(u_stride, chroma_width),
));
}
if v_stride < chroma_width {
return Err(Yuv411pFrameError::InsufficientVStride(
InsufficientStride::new(v_stride, chroma_width),
));
}
let y_min = match (y_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(Yuv411pFrameError::GeometryOverflow(GeometryOverflow::new(
y_stride, height,
)));
}
};
if y.len() < y_min {
return Err(Yuv411pFrameError::InsufficientYPlane(
InsufficientPlane::new(y_min, y.len()),
));
}
let u_min = match (u_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(Yuv411pFrameError::GeometryOverflow(GeometryOverflow::new(
u_stride, height,
)));
}
};
if u.len() < u_min {
return Err(Yuv411pFrameError::InsufficientUPlane(
InsufficientPlane::new(u_min, u.len()),
));
}
let v_min = match (v_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(Yuv411pFrameError::GeometryOverflow(GeometryOverflow::new(
v_stride, height,
)));
}
};
if v.len() < v_min {
return Err(Yuv411pFrameError::InsufficientVPlane(
InsufficientPlane::new(v_min, v.len()),
));
}
Ok(Self {
y,
u,
v,
width,
height,
y_stride,
u_stride,
v_stride,
})
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn new(
y: &'a [u8],
u: &'a [u8],
v: &'a [u8],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Self {
match Self::try_new(y, u, v, width, height, y_stride, u_stride, v_stride) {
Ok(frame) => frame,
Err(_) => panic!("invalid Yuv411pFrame dimensions or plane lengths"),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn y(&self) -> &'a [u8] {
self.y
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn u(&self) -> &'a [u8] {
self.u
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn v(&self) -> &'a [u8] {
self.v
}
#[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 y_stride(&self) -> u32 {
self.y_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn u_stride(&self) -> u32 {
self.u_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn v_stride(&self) -> u32 {
self.v_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 Yuv411pFrameError {
#[error(transparent)]
ZeroDimension(ZeroDimension),
#[error(transparent)]
WidthAlignment(WidthAlignment),
#[error(transparent)]
InsufficientYStride(InsufficientStride),
#[error(transparent)]
InsufficientUStride(InsufficientStride),
#[error(transparent)]
InsufficientVStride(InsufficientStride),
#[error(transparent)]
InsufficientYPlane(InsufficientPlane),
#[error(transparent)]
InsufficientUPlane(InsufficientPlane),
#[error(transparent)]
InsufficientVPlane(InsufficientPlane),
#[error(transparent)]
GeometryOverflow(GeometryOverflow),
}