use super::{
GeometryOverflow, InsufficientPlane, InsufficientStride, UnsupportedBits, WidthAlignment,
ZeroDimension,
};
use derive_more::{Display, IsVariant, TryUnwrap, Unwrap};
use thiserror::Error;
#[derive(Debug, Clone, Copy)]
pub struct Yuv420pFrame16<'a, const BITS: u32, const BE: bool = false> {
y: &'a [u16],
u: &'a [u16],
v: &'a [u16],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
}
impl<'a, const BITS: u32, const BE: bool> Yuv420pFrame16<'a, BITS, BE> {
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn try_new(
y: &'a [u16],
u: &'a [u16],
v: &'a [u16],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Result<Self, Yuv420pFrame16Error> {
if BITS != 9 && BITS != 10 && BITS != 12 && BITS != 14 && BITS != 16 {
return Err(Yuv420pFrame16Error::UnsupportedBits(UnsupportedBits::new(
BITS,
)));
}
if width == 0 || height == 0 {
return Err(Yuv420pFrame16Error::ZeroDimension(ZeroDimension::new(
width, height,
)));
}
if width & 1 != 0 {
return Err(Yuv420pFrame16Error::WidthAlignment(WidthAlignment::odd(
width as usize,
)));
}
if y_stride < width {
return Err(Yuv420pFrame16Error::InsufficientYStride(
InsufficientStride::new(y_stride, width),
));
}
let chroma_width = width.div_ceil(2);
if u_stride < chroma_width {
return Err(Yuv420pFrame16Error::InsufficientUStride(
InsufficientStride::new(u_stride, chroma_width),
));
}
if v_stride < chroma_width {
return Err(Yuv420pFrame16Error::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(Yuv420pFrame16Error::GeometryOverflow(
GeometryOverflow::new(y_stride, height),
));
}
};
if y.len() < y_min {
return Err(Yuv420pFrame16Error::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(Yuv420pFrame16Error::GeometryOverflow(
GeometryOverflow::new(u_stride, chroma_height),
));
}
};
if u.len() < u_min {
return Err(Yuv420pFrame16Error::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(Yuv420pFrame16Error::GeometryOverflow(
GeometryOverflow::new(v_stride, chroma_height),
));
}
};
if v.len() < v_min {
return Err(Yuv420pFrame16Error::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 [u16],
u: &'a [u16],
v: &'a [u16],
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 Yuv420pFrame16 dimensions or plane lengths"),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub fn try_new_checked(
y: &'a [u16],
u: &'a [u16],
v: &'a [u16],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Result<Self, Yuv420pFrame16Error> {
let frame = Self::try_new(y, u, v, width, height, y_stride, u_stride, v_stride)?;
let max_valid: u16 = ((1u32 << BITS) - 1) as u16;
let w = width as usize;
let h = height as usize;
let chroma_w = w / 2;
let chroma_h = height.div_ceil(2) as usize;
for row in 0..h {
let start = row * y_stride as usize;
for (col, &s) in y[start..start + w].iter().enumerate() {
let logical = if BE { u16::from_be(s) } else { u16::from_le(s) };
if logical > max_valid {
return Err(Yuv420pFrame16Error::SampleOutOfRange(
Yuv420pFrame16SampleOutOfRange::new(
Yuv420pFrame16Plane::Y,
start + col,
logical,
max_valid,
),
));
}
}
}
for row in 0..chroma_h {
let start = row * u_stride as usize;
for (col, &s) in u[start..start + chroma_w].iter().enumerate() {
let logical = if BE { u16::from_be(s) } else { u16::from_le(s) };
if logical > max_valid {
return Err(Yuv420pFrame16Error::SampleOutOfRange(
Yuv420pFrame16SampleOutOfRange::new(
Yuv420pFrame16Plane::U,
start + col,
logical,
max_valid,
),
));
}
}
}
for row in 0..chroma_h {
let start = row * v_stride as usize;
for (col, &s) in v[start..start + chroma_w].iter().enumerate() {
let logical = if BE { u16::from_be(s) } else { u16::from_le(s) };
if logical > max_valid {
return Err(Yuv420pFrame16Error::SampleOutOfRange(
Yuv420pFrame16SampleOutOfRange::new(
Yuv420pFrame16Plane::V,
start + col,
logical,
max_valid,
),
));
}
}
}
Ok(frame)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn y(&self) -> &'a [u16] {
self.y
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn u(&self) -> &'a [u16] {
self.u
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn v(&self) -> &'a [u16] {
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
}
#[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
}
}
pub type Yuv420p10Frame<'a> = Yuv420pFrame16<'a, 10>;
pub type Yuv420p9Frame<'a> = Yuv420pFrame16<'a, 9>;
pub type Yuv420p12Frame<'a> = Yuv420pFrame16<'a, 12>;
pub type Yuv420p14Frame<'a> = Yuv420pFrame16<'a, 14>;
pub type Yuv420p16Frame<'a> = Yuv420pFrame16<'a, 16>;
pub type Yuv420p9LeFrame<'a> = Yuv420pFrame16<'a, 9, false>;
pub type Yuv420p9BeFrame<'a> = Yuv420pFrame16<'a, 9, true>;
pub type Yuv420p10LeFrame<'a> = Yuv420pFrame16<'a, 10, false>;
pub type Yuv420p10BeFrame<'a> = Yuv420pFrame16<'a, 10, true>;
pub type Yuv420p12LeFrame<'a> = Yuv420pFrame16<'a, 12, false>;
pub type Yuv420p12BeFrame<'a> = Yuv420pFrame16<'a, 12, true>;
pub type Yuv420p14LeFrame<'a> = Yuv420pFrame16<'a, 14, false>;
pub type Yuv420p14BeFrame<'a> = Yuv420pFrame16<'a, 14, true>;
pub type Yuv420p16LeFrame<'a> = Yuv420pFrame16<'a, 16, false>;
pub type Yuv420p16BeFrame<'a> = Yuv420pFrame16<'a, 16, true>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, IsVariant, TryUnwrap, Unwrap, Error)]
#[non_exhaustive]
#[unwrap(ref, ref_mut)]
#[try_unwrap(ref, ref_mut)]
pub enum Yuv420pFrame16Error {
#[error(transparent)]
UnsupportedBits(UnsupportedBits),
#[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),
#[error(
"sample {} on plane {} at element {} exceeds {} ((1 << BITS) - 1)",
.0.value(), .0.plane(), .0.index(), .0.max_valid()
)]
SampleOutOfRange(Yuv420pFrame16SampleOutOfRange),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Yuv420pFrame16SampleOutOfRange {
plane: Yuv420pFrame16Plane,
index: usize,
value: u16,
max_valid: u16,
}
impl Yuv420pFrame16SampleOutOfRange {
#[inline]
pub const fn new(plane: Yuv420pFrame16Plane, index: usize, value: u16, max_valid: u16) -> Self {
Self {
plane,
index,
value,
max_valid,
}
}
#[inline]
pub const fn plane(&self) -> Yuv420pFrame16Plane {
self.plane
}
#[inline]
pub const fn index(&self) -> usize {
self.index
}
#[inline]
pub const fn value(&self) -> u16 {
self.value
}
#[inline]
pub const fn max_valid(&self) -> u16 {
self.max_valid
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Display)]
pub enum Yuv420pFrame16Plane {
Y,
U,
V,
}
#[derive(Debug, Clone, Copy)]
pub struct Yuv422pFrame16<'a, const BITS: u32, const BE: bool = false> {
y: &'a [u16],
u: &'a [u16],
v: &'a [u16],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
}
impl<'a, const BITS: u32, const BE: bool> Yuv422pFrame16<'a, BITS, BE> {
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn try_new(
y: &'a [u16],
u: &'a [u16],
v: &'a [u16],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Result<Self, Yuv420pFrame16Error> {
if BITS != 9 && BITS != 10 && BITS != 12 && BITS != 14 && BITS != 16 {
return Err(Yuv420pFrame16Error::UnsupportedBits(UnsupportedBits::new(
BITS,
)));
}
if width == 0 || height == 0 {
return Err(Yuv420pFrame16Error::ZeroDimension(ZeroDimension::new(
width, height,
)));
}
if width & 1 != 0 {
return Err(Yuv420pFrame16Error::WidthAlignment(WidthAlignment::odd(
width as usize,
)));
}
if y_stride < width {
return Err(Yuv420pFrame16Error::InsufficientYStride(
InsufficientStride::new(y_stride, width),
));
}
let chroma_width = width.div_ceil(2);
if u_stride < chroma_width {
return Err(Yuv420pFrame16Error::InsufficientUStride(
InsufficientStride::new(u_stride, chroma_width),
));
}
if v_stride < chroma_width {
return Err(Yuv420pFrame16Error::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(Yuv420pFrame16Error::GeometryOverflow(
GeometryOverflow::new(y_stride, height),
));
}
};
if y.len() < y_min {
return Err(Yuv420pFrame16Error::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(Yuv420pFrame16Error::GeometryOverflow(
GeometryOverflow::new(u_stride, height),
));
}
};
if u.len() < u_min {
return Err(Yuv420pFrame16Error::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(Yuv420pFrame16Error::GeometryOverflow(
GeometryOverflow::new(v_stride, height),
));
}
};
if v.len() < v_min {
return Err(Yuv420pFrame16Error::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 [u16],
u: &'a [u16],
v: &'a [u16],
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 Yuv422pFrame16 dimensions or plane lengths"),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub fn try_new_checked(
y: &'a [u16],
u: &'a [u16],
v: &'a [u16],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Result<Self, Yuv420pFrame16Error> {
let frame = Self::try_new(y, u, v, width, height, y_stride, u_stride, v_stride)?;
if BITS == 16 {
return Ok(frame);
}
let max_valid: u16 = ((1u32 << BITS) - 1) as u16;
let w = width as usize;
let h = height as usize;
let chroma_w = w / 2;
let chroma_h = h;
for row in 0..h {
let start = row * y_stride as usize;
for (col, &s) in y[start..start + w].iter().enumerate() {
let logical = if BE { u16::from_be(s) } else { u16::from_le(s) };
if logical > max_valid {
return Err(Yuv420pFrame16Error::SampleOutOfRange(
Yuv420pFrame16SampleOutOfRange::new(
Yuv420pFrame16Plane::Y,
start + col,
logical,
max_valid,
),
));
}
}
}
for row in 0..chroma_h {
let start = row * u_stride as usize;
for (col, &s) in u[start..start + chroma_w].iter().enumerate() {
let logical = if BE { u16::from_be(s) } else { u16::from_le(s) };
if logical > max_valid {
return Err(Yuv420pFrame16Error::SampleOutOfRange(
Yuv420pFrame16SampleOutOfRange::new(
Yuv420pFrame16Plane::U,
start + col,
logical,
max_valid,
),
));
}
}
}
for row in 0..chroma_h {
let start = row * v_stride as usize;
for (col, &s) in v[start..start + chroma_w].iter().enumerate() {
let logical = if BE { u16::from_be(s) } else { u16::from_le(s) };
if logical > max_valid {
return Err(Yuv420pFrame16Error::SampleOutOfRange(
Yuv420pFrame16SampleOutOfRange::new(
Yuv420pFrame16Plane::V,
start + col,
logical,
max_valid,
),
));
}
}
}
Ok(frame)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn y(&self) -> &'a [u16] {
self.y
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn u(&self) -> &'a [u16] {
self.u
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn v(&self) -> &'a [u16] {
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
}
#[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
}
}
pub type Yuv422p9Frame<'a> = Yuv422pFrame16<'a, 9>;
pub type Yuv422p10Frame<'a> = Yuv422pFrame16<'a, 10>;
pub type Yuv422p12Frame<'a> = Yuv422pFrame16<'a, 12>;
pub type Yuv422p14Frame<'a> = Yuv422pFrame16<'a, 14>;
pub type Yuv422p16Frame<'a> = Yuv422pFrame16<'a, 16>;
pub type Yuv422p9LeFrame<'a> = Yuv422pFrame16<'a, 9, false>;
pub type Yuv422p9BeFrame<'a> = Yuv422pFrame16<'a, 9, true>;
pub type Yuv422p10LeFrame<'a> = Yuv422pFrame16<'a, 10, false>;
pub type Yuv422p10BeFrame<'a> = Yuv422pFrame16<'a, 10, true>;
pub type Yuv422p12LeFrame<'a> = Yuv422pFrame16<'a, 12, false>;
pub type Yuv422p12BeFrame<'a> = Yuv422pFrame16<'a, 12, true>;
pub type Yuv422p14LeFrame<'a> = Yuv422pFrame16<'a, 14, false>;
pub type Yuv422p14BeFrame<'a> = Yuv422pFrame16<'a, 14, true>;
pub type Yuv422p16LeFrame<'a> = Yuv422pFrame16<'a, 16, false>;
pub type Yuv422p16BeFrame<'a> = Yuv422pFrame16<'a, 16, true>;
#[derive(Debug, Clone, Copy)]
pub struct Yuv444pFrame16<'a, const BITS: u32, const BE: bool = false> {
y: &'a [u16],
u: &'a [u16],
v: &'a [u16],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
}
impl<'a, const BITS: u32, const BE: bool> Yuv444pFrame16<'a, BITS, BE> {
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn try_new(
y: &'a [u16],
u: &'a [u16],
v: &'a [u16],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Result<Self, Yuv420pFrame16Error> {
if BITS != 9 && BITS != 10 && BITS != 12 && BITS != 14 && BITS != 16 {
return Err(Yuv420pFrame16Error::UnsupportedBits(UnsupportedBits::new(
BITS,
)));
}
if width == 0 || height == 0 {
return Err(Yuv420pFrame16Error::ZeroDimension(ZeroDimension::new(
width, height,
)));
}
if y_stride < width {
return Err(Yuv420pFrame16Error::InsufficientYStride(
InsufficientStride::new(y_stride, width),
));
}
if u_stride < width {
return Err(Yuv420pFrame16Error::InsufficientUStride(
InsufficientStride::new(u_stride, width),
));
}
if v_stride < width {
return Err(Yuv420pFrame16Error::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(Yuv420pFrame16Error::GeometryOverflow(
GeometryOverflow::new(y_stride, height),
));
}
};
if y.len() < y_min {
return Err(Yuv420pFrame16Error::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(Yuv420pFrame16Error::GeometryOverflow(
GeometryOverflow::new(u_stride, height),
));
}
};
if u.len() < u_min {
return Err(Yuv420pFrame16Error::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(Yuv420pFrame16Error::GeometryOverflow(
GeometryOverflow::new(v_stride, height),
));
}
};
if v.len() < v_min {
return Err(Yuv420pFrame16Error::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 [u16],
u: &'a [u16],
v: &'a [u16],
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 Yuv444pFrame16 dimensions or plane lengths"),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub fn try_new_checked(
y: &'a [u16],
u: &'a [u16],
v: &'a [u16],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Result<Self, Yuv420pFrame16Error> {
let frame = Self::try_new(y, u, v, width, height, y_stride, u_stride, v_stride)?;
if BITS == 16 {
return Ok(frame);
}
let max_valid: u16 = ((1u32 << BITS) - 1) as u16;
let w = width as usize;
let h = height as usize;
for row in 0..h {
let start = row * y_stride as usize;
for (col, &s) in y[start..start + w].iter().enumerate() {
let logical = if BE { u16::from_be(s) } else { u16::from_le(s) };
if logical > max_valid {
return Err(Yuv420pFrame16Error::SampleOutOfRange(
Yuv420pFrame16SampleOutOfRange::new(
Yuv420pFrame16Plane::Y,
start + col,
logical,
max_valid,
),
));
}
}
}
for row in 0..h {
let start = row * u_stride as usize;
for (col, &s) in u[start..start + w].iter().enumerate() {
let logical = if BE { u16::from_be(s) } else { u16::from_le(s) };
if logical > max_valid {
return Err(Yuv420pFrame16Error::SampleOutOfRange(
Yuv420pFrame16SampleOutOfRange::new(
Yuv420pFrame16Plane::U,
start + col,
logical,
max_valid,
),
));
}
}
}
for row in 0..h {
let start = row * v_stride as usize;
for (col, &s) in v[start..start + w].iter().enumerate() {
let logical = if BE { u16::from_be(s) } else { u16::from_le(s) };
if logical > max_valid {
return Err(Yuv420pFrame16Error::SampleOutOfRange(
Yuv420pFrame16SampleOutOfRange::new(
Yuv420pFrame16Plane::V,
start + col,
logical,
max_valid,
),
));
}
}
}
Ok(frame)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn y(&self) -> &'a [u16] {
self.y
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn u(&self) -> &'a [u16] {
self.u
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn v(&self) -> &'a [u16] {
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
}
#[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
}
}
pub type Yuv444p9Frame<'a> = Yuv444pFrame16<'a, 9>;
pub type Yuv444p10Frame<'a> = Yuv444pFrame16<'a, 10>;
pub type Yuv444p12Frame<'a> = Yuv444pFrame16<'a, 12>;
pub type Yuv444p14Frame<'a> = Yuv444pFrame16<'a, 14>;
pub type Yuv444p16Frame<'a> = Yuv444pFrame16<'a, 16>;
pub type Yuv444p9LeFrame<'a> = Yuv444pFrame16<'a, 9, false>;
pub type Yuv444p9BeFrame<'a> = Yuv444pFrame16<'a, 9, true>;
pub type Yuv444p10LeFrame<'a> = Yuv444pFrame16<'a, 10, false>;
pub type Yuv444p10BeFrame<'a> = Yuv444pFrame16<'a, 10, true>;
pub type Yuv444p12LeFrame<'a> = Yuv444pFrame16<'a, 12, false>;
pub type Yuv444p12BeFrame<'a> = Yuv444pFrame16<'a, 12, true>;
pub type Yuv444p14LeFrame<'a> = Yuv444pFrame16<'a, 14, false>;
pub type Yuv444p14BeFrame<'a> = Yuv444pFrame16<'a, 14, true>;
pub type Yuv444p16LeFrame<'a> = Yuv444pFrame16<'a, 16, false>;
pub type Yuv444p16BeFrame<'a> = Yuv444pFrame16<'a, 16, true>;
pub type Yuv440pFrame16Error = Yuv420pFrame16Error;
#[derive(Debug, Clone, Copy)]
pub struct Yuv440pFrame16<'a, const BITS: u32, const BE: bool = false> {
y: &'a [u16],
u: &'a [u16],
v: &'a [u16],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
}
impl<'a, const BITS: u32, const BE: bool> Yuv440pFrame16<'a, BITS, BE> {
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn try_new(
y: &'a [u16],
u: &'a [u16],
v: &'a [u16],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Result<Self, Yuv440pFrame16Error> {
if BITS != 10 && BITS != 12 {
return Err(Yuv420pFrame16Error::UnsupportedBits(UnsupportedBits::new(
BITS,
)));
}
if width == 0 || height == 0 {
return Err(Yuv420pFrame16Error::ZeroDimension(ZeroDimension::new(
width, height,
)));
}
if y_stride < width {
return Err(Yuv420pFrame16Error::InsufficientYStride(
InsufficientStride::new(y_stride, width),
));
}
if u_stride < width {
return Err(Yuv420pFrame16Error::InsufficientUStride(
InsufficientStride::new(u_stride, width),
));
}
if v_stride < width {
return Err(Yuv420pFrame16Error::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(Yuv420pFrame16Error::GeometryOverflow(
GeometryOverflow::new(y_stride, height),
));
}
};
if y.len() < y_min {
return Err(Yuv420pFrame16Error::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(Yuv420pFrame16Error::GeometryOverflow(
GeometryOverflow::new(u_stride, chroma_height),
));
}
};
if u.len() < u_min {
return Err(Yuv420pFrame16Error::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(Yuv420pFrame16Error::GeometryOverflow(
GeometryOverflow::new(v_stride, chroma_height),
));
}
};
if v.len() < v_min {
return Err(Yuv420pFrame16Error::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 [u16],
u: &'a [u16],
v: &'a [u16],
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 Yuv440pFrame16 dimensions or plane lengths"),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub fn try_new_checked(
y: &'a [u16],
u: &'a [u16],
v: &'a [u16],
width: u32,
height: u32,
y_stride: u32,
u_stride: u32,
v_stride: u32,
) -> Result<Self, Yuv440pFrame16Error> {
let frame = Self::try_new(y, u, v, width, height, y_stride, u_stride, v_stride)?;
let max_valid: u16 = ((1u32 << BITS) - 1) as u16;
let w = width as usize;
let h = height as usize;
let chroma_h = (height as usize).div_ceil(2);
for row in 0..h {
let start = row * y_stride as usize;
for (col, &s) in y[start..start + w].iter().enumerate() {
let logical = if BE { u16::from_be(s) } else { u16::from_le(s) };
if logical > max_valid {
return Err(Yuv420pFrame16Error::SampleOutOfRange(
Yuv420pFrame16SampleOutOfRange::new(
Yuv420pFrame16Plane::Y,
start + col,
logical,
max_valid,
),
));
}
}
}
for row in 0..chroma_h {
let start = row * u_stride as usize;
for (col, &s) in u[start..start + w].iter().enumerate() {
let logical = if BE { u16::from_be(s) } else { u16::from_le(s) };
if logical > max_valid {
return Err(Yuv420pFrame16Error::SampleOutOfRange(
Yuv420pFrame16SampleOutOfRange::new(
Yuv420pFrame16Plane::U,
start + col,
logical,
max_valid,
),
));
}
}
}
for row in 0..chroma_h {
let start = row * v_stride as usize;
for (col, &s) in v[start..start + w].iter().enumerate() {
let logical = if BE { u16::from_be(s) } else { u16::from_le(s) };
if logical > max_valid {
return Err(Yuv420pFrame16Error::SampleOutOfRange(
Yuv420pFrame16SampleOutOfRange::new(
Yuv420pFrame16Plane::V,
start + col,
logical,
max_valid,
),
));
}
}
}
Ok(frame)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn y(&self) -> &'a [u16] {
self.y
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn u(&self) -> &'a [u16] {
self.u
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn v(&self) -> &'a [u16] {
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
}
#[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
}
}
pub type Yuv440p10Frame<'a> = Yuv440pFrame16<'a, 10>;
pub type Yuv440p12Frame<'a> = Yuv440pFrame16<'a, 12>;
pub type Yuv440p10LeFrame<'a> = Yuv440pFrame16<'a, 10, false>;
pub type Yuv440p10BeFrame<'a> = Yuv440pFrame16<'a, 10, true>;
pub type Yuv440p12LeFrame<'a> = Yuv440pFrame16<'a, 12, false>;
pub type Yuv440p12BeFrame<'a> = Yuv440pFrame16<'a, 12, true>;