#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, thiserror::Error)]
#[error("width ({width}) or height ({height}) is zero")]
pub struct ZeroDimension {
width: u32,
height: u32,
}
impl ZeroDimension {
#[inline]
pub const fn new(width: u32, height: u32) -> Self {
Self { width, height }
}
#[inline]
pub const fn width(&self) -> u32 {
self.width
}
#[inline]
pub const fn height(&self) -> u32 {
self.height
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, thiserror::Error)]
#[error("dimensions {width} × {height} overflow")]
pub struct DimensionOverflow {
width: u32,
height: u32,
}
impl DimensionOverflow {
#[inline]
pub const fn new(width: u32, height: u32) -> Self {
Self { width, height }
}
#[inline]
pub const fn width(&self) -> u32 {
self.width
}
#[inline]
pub const fn height(&self) -> u32 {
self.height
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, thiserror::Error)]
#[error("stride ({stride}) is smaller than minimum ({min})")]
pub struct InsufficientStride {
stride: u32,
min: u32,
}
impl InsufficientStride {
#[inline]
pub const fn new(stride: u32, min: u32) -> Self {
Self { stride, min }
}
#[inline]
pub const fn stride(&self) -> u32 {
self.stride
}
#[inline]
pub const fn min(&self) -> u32 {
self.min
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, thiserror::Error)]
#[error("plane has {actual} bytes/samples but at least {expected} are required")]
pub struct InsufficientPlane {
expected: usize,
actual: usize,
}
impl InsufficientPlane {
#[inline]
pub const fn new(expected: usize, actual: usize) -> Self {
Self { expected, actual }
}
#[inline]
pub const fn expected(&self) -> usize {
self.expected
}
#[inline]
pub const fn actual(&self) -> usize {
self.actual
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, thiserror::Error)]
#[error("declared geometry overflows usize: stride={stride} * rows={rows}")]
pub struct GeometryOverflow {
stride: u32,
rows: u32,
}
impl GeometryOverflow {
#[inline]
pub const fn new(stride: u32, rows: u32) -> Self {
Self { stride, rows }
}
#[inline]
pub const fn stride(&self) -> u32 {
self.stride
}
#[inline]
pub const fn rows(&self) -> u32 {
self.rows
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, thiserror::Error)]
#[error("width ({width}) {required}")]
pub struct WidthAlignment {
width: usize,
required: WidthAlignmentRequirement,
}
impl WidthAlignment {
#[inline]
const fn new(width: usize, required: WidthAlignmentRequirement) -> Self {
Self { width, required }
}
#[inline]
pub const fn odd(width: usize) -> Self {
Self::new(width, WidthAlignmentRequirement::Even)
}
#[inline]
pub const fn multiple_of_four(width: usize) -> Self {
Self::new(width, WidthAlignmentRequirement::MultipleOfFour)
}
#[inline]
pub const fn width(&self) -> usize {
self.width
}
#[inline]
pub const fn required(&self) -> WidthAlignmentRequirement {
self.required
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, IsVariant, Display)]
#[non_exhaustive]
pub enum WidthAlignmentRequirement {
#[display("is odd")]
Even,
#[display("is not a multiple of 4")]
MultipleOfFour,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, thiserror::Error)]
#[error("width ({width}) overflow")]
pub struct WidthOverflow {
width: u32,
}
impl WidthOverflow {
#[inline]
pub const fn new(width: u32) -> Self {
Self { width }
}
#[inline]
pub const fn width(&self) -> u32 {
self.width
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, thiserror::Error)]
#[error("unsupported BITS ({bits})")]
pub struct UnsupportedBits {
bits: u32,
}
impl UnsupportedBits {
#[inline]
pub const fn new(bits: u32) -> Self {
Self { bits }
}
#[inline]
pub const fn bits(&self) -> u32 {
self.bits
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "quickcheck",
derive(::quickcheck_richderive::Arbitrary),
quickcheck(arbitrary = "crate::quickcheck_helpers::coded::dimensions")
)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Dimensions {
width: u32,
height: u32,
}
impl Dimensions {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(width: u32, height: u32) -> Self {
Self { width, height }
}
#[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
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_width(mut self, width: u32) -> Self {
self.width = width;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_width(&mut self, width: u32) -> &mut Self {
self.width = width;
self
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_height(mut self, height: u32) -> Self {
self.height = height;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_height(&mut self, height: u32) -> &mut Self {
self.height = height;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn is_zero(&self) -> bool {
self.width == 0 && self.height == 0
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn aspect_ratio(&self) -> Option<Rational> {
match core::num::NonZeroI64::new(self.height as i64) {
Some(den) => Rational::try_new(self.width as i64, den),
None => None,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn display_size(&self, sar: SampleAspectRatio) -> Option<Self> {
let num = sar.num() as i128;
if num == 0 {
return None;
}
let den = sar.den().get() as i128;
let scaled = (self.width as i128 * num + den / 2) / den;
if scaled > u32::MAX as i128 {
return None;
}
Some(Self::new(scaled as u32, self.height))
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn contains(&self, rect: &Rect) -> bool {
match (
rect.x().checked_add(rect.width()),
rect.y().checked_add(rect.height()),
) {
(Some(right), Some(bottom)) => right <= self.width && bottom <= self.height,
_ => false,
}
}
}
impl core::fmt::Display for Dimensions {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}x{}", self.width, self.height)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, thiserror::Error)]
#[error("not a WIDTHxHEIGHT dimension pair")]
#[non_exhaustive]
pub struct ParseDimensionsError;
impl core::str::FromStr for Dimensions {
type Err = ParseDimensionsError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (w, h) = s.split_once('x').ok_or(ParseDimensionsError)?;
let width = w.parse().map_err(|_| ParseDimensionsError)?;
let height = h.parse().map_err(|_| ParseDimensionsError)?;
Ok(Self::new(width, height))
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "quickcheck",
derive(::quickcheck_richderive::Arbitrary),
quickcheck(arbitrary = "crate::quickcheck_helpers::coded::rect")
)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Rect {
x: u32,
y: u32,
width: u32,
height: u32,
}
impl Rect {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(x: u32, y: u32, width: u32, height: u32) -> Self {
Self {
x,
y,
width,
height,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn x(&self) -> u32 {
self.x
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn y(&self) -> u32 {
self.y
}
#[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
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_x(mut self, x: u32) -> Self {
self.x = x;
self
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_y(mut self, y: u32) -> Self {
self.y = y;
self
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_width(mut self, w: u32) -> Self {
self.width = w;
self
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_height(mut self, h: u32) -> Self {
self.height = h;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_x(&mut self, x: u32) -> &mut Self {
self.x = x;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_y(&mut self, y: u32) -> &mut Self {
self.y = y;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_width(&mut self, w: u32) -> &mut Self {
self.width = w;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_height(&mut self, h: u32) -> &mut Self {
self.height = h;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn aspect_ratio(&self) -> Option<Rational> {
match core::num::NonZeroI64::new(self.height as i64) {
Some(den) => Rational::try_new(self.width as i64, den),
None => None,
}
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Display, IsVariant)]
#[display("{}", self.as_str())]
#[non_exhaustive]
#[cfg_attr(
feature = "quickcheck",
derive(::quickcheck_richderive::Arbitrary),
quickcheck(arbitrary = "crate::quickcheck_helpers::coded::rotation")
)]
pub enum Rotation {
#[default]
D0,
D90,
D180,
D270,
#[cfg(any(feature = "std", feature = "alloc"))]
Other(SmolStr),
}
impl Rotation {
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn as_str(&self) -> &str {
match self {
Self::D0 => "0",
Self::D90 => "90",
Self::D180 => "180",
Self::D270 => "270",
#[cfg(any(feature = "std", feature = "alloc"))]
Self::Other(s) => s.as_str(),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn to_u32(&self) -> Option<u32> {
Some(match self {
Self::D0 => 0,
Self::D90 => 1,
Self::D180 => 2,
Self::D270 => 3,
#[cfg(any(feature = "std", feature = "alloc"))]
Self::Other(_) => return None,
})
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn from_u32(v: u32) -> Option<Self> {
Some(match v {
0 => Self::D0,
1 => Self::D90,
2 => Self::D180,
3 => Self::D270,
_ => return None,
})
}
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn other(slug: impl AsRef<str>) -> Self {
Self::Other(crate::parse::fold_owned(slug.as_ref()))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, thiserror::Error)]
#[error("not a rotation")]
#[non_exhaustive]
pub struct ParseRotationError;
impl core::str::FromStr for Rotation {
type Err = ParseRotationError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut buf = [0u8; crate::parse::FOLD_CAP];
let folded = crate::parse::fold(s, &mut buf).unwrap_or(s.as_bytes());
Ok(match folded {
b"0" => Self::D0,
b"90" => Self::D90,
b"180" => Self::D180,
b"270" => Self::D270,
#[cfg(any(feature = "std", feature = "alloc"))]
_ => Self::other(s),
#[cfg(not(any(feature = "std", feature = "alloc")))]
_ => return Err(ParseRotationError),
})
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "quickcheck",
derive(::quickcheck_richderive::Arbitrary),
quickcheck(arbitrary = "crate::quickcheck_helpers::coded::sample_aspect_ratio")
)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SampleAspectRatio(Rational);
impl Default for SampleAspectRatio {
#[cfg_attr(not(tarpaulin), inline(always))]
fn default() -> Self {
Self(Rational::default())
}
}
impl SampleAspectRatio {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(num: i64, den: core::num::NonZeroI64) -> Self {
Self(Rational::new(num, den))
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn num(&self) -> i64 {
self.0.num()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn den(&self) -> core::num::NonZeroI64 {
self.0.den()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn is_square(&self) -> bool {
self.0.num() == self.0.den().get()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn rational(&self) -> Rational {
self.0
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn as_rational(&self) -> Rational {
self.rational()
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_num(mut self, num: i64) -> Self {
self.0 = self.0.with_num(num);
self
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_den(mut self, den: core::num::NonZeroI64) -> Self {
self.0 = self.0.with_den(den);
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_num(&mut self, num: i64) -> &mut Self {
self.0.set_num(num);
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_den(&mut self, den: core::num::NonZeroI64) -> &mut Self {
self.0.set_den(den);
self
}
}
impl core::fmt::Display for SampleAspectRatio {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}:{}", self.0.num(), self.0.den())
}
}
impl core::str::FromStr for SampleAspectRatio {
type Err = ParseSampleAspectRatioError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
parse_ratio(s, ':')
.map(Self)
.map_err(|kind| ParseSampleAspectRatioError { kind })
}
}
impl From<SampleAspectRatio> for Rational {
#[cfg_attr(not(tarpaulin), inline(always))]
fn from(sar: SampleAspectRatio) -> Self {
sar.0
}
}
impl From<Rational> for SampleAspectRatio {
#[cfg_attr(not(tarpaulin), inline(always))]
fn from(rate: Rational) -> Self {
Self(rate)
}
}
pub(crate) const DEN_ONE: core::num::NonZeroI64 = match core::num::NonZeroI64::new(1) {
Some(v) => v,
None => unreachable!(),
};
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "quickcheck",
derive(::quickcheck_richderive::Arbitrary),
quickcheck(arbitrary = "crate::quickcheck_helpers::coded::rational")
)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Rational {
#[cfg_attr(feature = "serde", serde(deserialize_with = "de_num"))]
num: i64,
#[cfg_attr(feature = "serde", serde(deserialize_with = "de_den"))]
den: core::num::NonZeroI64,
}
impl Default for Rational {
#[cfg_attr(not(tarpaulin), inline(always))]
fn default() -> Self {
Self {
num: 1,
den: DEN_ONE,
}
}
}
impl Rational {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(num: i64, den: core::num::NonZeroI64) -> Self {
assert!(num >= 0, "rational numerator must not be negative");
assert!(den.get() > 0, "rational denominator must be positive");
Self { num, den }
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn try_new(num: i64, den: core::num::NonZeroI64) -> Option<Self> {
if num >= 0 && den.get() > 0 {
Some(Self { num, den })
} else {
None
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn num(&self) -> i64 {
self.num
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn den(&self) -> core::num::NonZeroI64 {
self.den
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn is_zero(&self) -> bool {
self.num == 0
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_num(mut self, num: i64) -> Self {
self.set_num(num);
self
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_den(mut self, den: core::num::NonZeroI64) -> Self {
self.set_den(den);
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_num(&mut self, num: i64) -> &mut Self {
*self = Self::new(num, self.den);
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_den(&mut self, den: core::num::NonZeroI64) -> &mut Self {
*self = Self::new(self.num, den);
self
}
}
#[cfg(feature = "serde")]
mod de {
use core::num::NonZeroI64;
use serde::{Deserialize, Deserializer, de::Error};
pub(super) fn de_num<'de, D: Deserializer<'de>>(d: D) -> Result<i64, D::Error> {
let v = i64::deserialize(d)?;
if v < 0 {
return Err(D::Error::custom("rational numerator must not be negative"));
}
Ok(v)
}
pub(super) fn de_den<'de, D: Deserializer<'de>>(d: D) -> Result<NonZeroI64, D::Error> {
let v = NonZeroI64::deserialize(d)?;
if v.get() < 0 {
return Err(D::Error::custom("rational denominator must be positive"));
}
Ok(v)
}
}
#[cfg(feature = "serde")]
use de::{de_den, de_num};
impl core::fmt::Display for Rational {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}/{}", self.num, self.den)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum RatioParseKind {
Malformed,
OutOfRange,
}
impl core::fmt::Display for RatioParseKind {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(match self {
Self::Malformed => "malformed",
Self::OutOfRange => "value out of range",
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, thiserror::Error)]
#[error("not a NUM/DEN rational: {kind}")]
pub struct ParseRationalError {
kind: RatioParseKind,
}
impl ParseRationalError {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn kind(&self) -> RatioParseKind {
self.kind
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, thiserror::Error)]
#[error("not a NUM:DEN sample aspect ratio: {kind}")]
pub struct ParseSampleAspectRatioError {
kind: RatioParseKind,
}
impl ParseSampleAspectRatioError {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn kind(&self) -> RatioParseKind {
self.kind
}
}
fn parse_ratio(s: &str, sep: char) -> Result<Rational, RatioParseKind> {
let (n, d) = s.split_once(sep).ok_or(RatioParseKind::Malformed)?;
let num: i64 = n.parse().map_err(|_| RatioParseKind::Malformed)?;
let den: i64 = d.parse().map_err(|_| RatioParseKind::Malformed)?;
let den = core::num::NonZeroI64::new(den).ok_or(RatioParseKind::OutOfRange)?;
Rational::try_new(num, den).ok_or(RatioParseKind::OutOfRange)
}
impl core::str::FromStr for Rational {
type Err = ParseRationalError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
parse_ratio(s, '/').map_err(|kind| ParseRationalError { kind })
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "quickcheck",
derive(::quickcheck_richderive::Arbitrary),
quickcheck(arbitrary = "crate::quickcheck_helpers::coded::frame_rate")
)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FrameRate {
rate: Rational,
is_vfr: bool,
}
impl FrameRate {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(rate: Rational, is_vfr: bool) -> Self {
Self { rate, is_vfr }
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn rate(&self) -> Rational {
self.rate
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn is_vfr(&self) -> bool {
self.is_vfr
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_rate(mut self, rate: Rational) -> Self {
self.rate = rate;
self
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_is_vfr(mut self) -> Self {
self.is_vfr = true;
self
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn maybe_is_vfr(mut self, is_vfr: bool) -> Self {
self.is_vfr = is_vfr;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_rate(&mut self, rate: Rational) -> &mut Self {
self.rate = rate;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_is_vfr(&mut self) -> &mut Self {
self.is_vfr = true;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn update_is_vfr(&mut self, is_vfr: bool) -> &mut Self {
self.is_vfr = is_vfr;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn clear_is_vfr(&mut self) -> &mut Self {
self.is_vfr = false;
self
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Display, IsVariant)]
#[display("{}", self.as_str())]
#[non_exhaustive]
#[cfg_attr(
feature = "quickcheck",
derive(::quickcheck_richderive::Arbitrary),
quickcheck(arbitrary = "crate::quickcheck_helpers::coded::field_order")
)]
pub enum FieldOrder {
Unknown,
Progressive,
Tt,
Bb,
Tb,
Bt,
#[cfg(any(feature = "std", feature = "alloc"))]
Other(SmolStr),
}
impl Default for FieldOrder {
#[cfg_attr(not(tarpaulin), inline(always))]
fn default() -> Self {
Self::Unknown
}
}
impl FieldOrder {
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn as_str(&self) -> &str {
match self {
Self::Unknown => "unknown",
Self::Progressive => "progressive",
Self::Tt => "tt",
Self::Bb => "bb",
Self::Tb => "tb",
Self::Bt => "bt",
#[cfg(any(feature = "std", feature = "alloc"))]
Self::Other(s) => s.as_str(),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn to_u32(&self) -> Option<u32> {
Some(match self {
Self::Unknown => 0,
Self::Progressive => 1,
Self::Tt => 2,
Self::Bb => 3,
Self::Tb => 4,
Self::Bt => 5,
#[cfg(any(feature = "std", feature = "alloc"))]
Self::Other(_) => return None,
})
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn from_u32(v: u32) -> Option<Self> {
Some(match v {
0 => Self::Unknown,
1 => Self::Progressive,
2 => Self::Tt,
3 => Self::Bb,
4 => Self::Tb,
5 => Self::Bt,
_ => return None,
})
}
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn other(slug: impl AsRef<str>) -> Self {
Self::Other(crate::parse::fold_owned(slug.as_ref()))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, thiserror::Error)]
#[error("not a field-order name")]
#[non_exhaustive]
pub struct ParseFieldOrderError;
impl core::str::FromStr for FieldOrder {
type Err = ParseFieldOrderError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut buf = [0u8; crate::parse::FOLD_CAP];
let folded = crate::parse::fold(s, &mut buf).unwrap_or(s.as_bytes());
Ok(match folded {
b"unknown" => Self::Unknown,
b"progressive" => Self::Progressive,
b"tt" => Self::Tt,
b"bb" => Self::Bb,
b"tb" => Self::Tb,
b"bt" => Self::Bt,
#[cfg(any(feature = "std", feature = "alloc"))]
_ => Self::other(s),
#[cfg(not(any(feature = "std", feature = "alloc")))]
_ => return Err(ParseFieldOrderError),
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Display, IsVariant)]
#[display("{}", self.as_str())]
#[non_exhaustive]
#[cfg_attr(
feature = "quickcheck",
derive(::quickcheck_richderive::Arbitrary),
quickcheck(arbitrary = "crate::quickcheck_helpers::coded::stereo_mode")
)]
pub enum StereoMode {
Mono,
SideBySide,
TopBottom,
FrameSequence,
Checkerboard,
SideBySideQuincunx,
Lines,
Columns,
#[cfg(any(feature = "std", feature = "alloc"))]
Other(SmolStr),
}
impl Default for StereoMode {
#[cfg_attr(not(tarpaulin), inline(always))]
fn default() -> Self {
Self::Mono
}
}
impl StereoMode {
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn as_str(&self) -> &str {
match self {
Self::Mono => "mono",
Self::SideBySide => "side-by-side",
Self::TopBottom => "top-bottom",
Self::FrameSequence => "frame-sequence",
Self::Checkerboard => "checkerboard",
Self::SideBySideQuincunx => "side-by-side-quincunx",
Self::Lines => "lines",
Self::Columns => "columns",
#[cfg(any(feature = "std", feature = "alloc"))]
Self::Other(s) => s.as_str(),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn to_u32(&self) -> Option<u32> {
Some(match self {
Self::Mono => 0,
Self::SideBySide => 1,
Self::TopBottom => 2,
Self::FrameSequence => 3,
Self::Checkerboard => 4,
Self::SideBySideQuincunx => 5,
Self::Lines => 6,
Self::Columns => 7,
#[cfg(any(feature = "std", feature = "alloc"))]
Self::Other(_) => return None,
})
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn from_u32(v: u32) -> Option<Self> {
Some(match v {
0 => Self::Mono,
1 => Self::SideBySide,
2 => Self::TopBottom,
3 => Self::FrameSequence,
4 => Self::Checkerboard,
5 => Self::SideBySideQuincunx,
6 => Self::Lines,
7 => Self::Columns,
_ => return None,
})
}
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn other(slug: impl AsRef<str>) -> Self {
Self::Other(crate::parse::fold_owned(slug.as_ref()))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, thiserror::Error)]
#[error("not a stereo-mode name")]
#[non_exhaustive]
pub struct ParseStereoModeError;
impl core::str::FromStr for StereoMode {
type Err = ParseStereoModeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut buf = [0u8; crate::parse::FOLD_CAP];
let folded = crate::parse::fold(s, &mut buf).unwrap_or(s.as_bytes());
Ok(match folded {
b"mono" => Self::Mono,
b"side-by-side" => Self::SideBySide,
b"top-bottom" => Self::TopBottom,
b"frame-sequence" => Self::FrameSequence,
b"checkerboard" => Self::Checkerboard,
b"side-by-side-quincunx" => Self::SideBySideQuincunx,
b"lines" => Self::Lines,
b"columns" => Self::Columns,
#[cfg(any(feature = "std", feature = "alloc"))]
_ => Self::other(s),
#[cfg(not(any(feature = "std", feature = "alloc")))]
_ => return Err(ParseStereoModeError),
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Plane<B> {
data: B,
stride: u32,
}
impl<B> Plane<B> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(data: B, stride: u32) -> Self {
Self { data, stride }
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn stride(&self) -> u32 {
self.stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn data_ref(&self) -> &B {
&self.data
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn data_mut(&mut self) -> &mut B {
&mut self.data
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn into_data(self) -> B {
self.data
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_stride(mut self, stride: u32) -> Self {
self.stride = stride;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_stride(&mut self, stride: u32) -> &mut Self {
self.stride = stride;
self
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct VideoFrame<P, B> {
dimensions: Dimensions,
visible_rect: Option<Rect>,
pixel_format: P,
plane_count: u8,
planes: [Plane<B>; 4],
color: crate::color::Info,
}
impl<P, B> VideoFrame<P, B> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(
dimensions: Dimensions,
pixel_format: P,
planes: [Plane<B>; 4],
plane_count: u8,
) -> Self {
assert!(
plane_count as usize <= 4,
"VideoFrame::new: plane_count exceeds the fixed 4-plane array",
);
Self {
dimensions,
visible_rect: None,
pixel_format,
plane_count,
planes,
color: crate::color::Info::UNSPECIFIED,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn dimensions(&self) -> Dimensions {
self.dimensions
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn width(&self) -> u32 {
self.dimensions.width()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn height(&self) -> u32 {
self.dimensions.height()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn visible_rect(&self) -> Option<Rect> {
self.visible_rect
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn pixel_format_ref(&self) -> &P {
&self.pixel_format
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn plane_count(&self) -> u8 {
self.plane_count
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn planes(&self) -> &[Plane<B>] {
&self.planes[..self.plane_count as usize]
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn plane(&self, i: usize) -> Option<&Plane<B>> {
if i < self.plane_count as usize {
self.planes.get(i)
} else {
None
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn color(&self) -> crate::color::Info {
self.color.clone()
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_visible_rect(mut self, v: Rect) -> Self {
self.visible_rect = Some(v);
self
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn maybe_visible_rect(mut self, v: Option<Rect>) -> Self {
self.visible_rect = v;
self
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn with_color(mut self, v: crate::color::Info) -> Self {
self.color = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_visible_rect(&mut self, v: Rect) -> &mut Self {
self.visible_rect = Some(v);
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn update_visible_rect(&mut self, v: Option<Rect>) -> &mut Self {
self.visible_rect = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn clear_visible_rect(&mut self) -> &mut Self {
self.visible_rect = None;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn set_color(&mut self, v: crate::color::Info) -> &mut Self {
self.color = v;
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TimestampedFrame<F> {
pts: Option<mediatime::Timestamp>,
duration: Option<mediatime::Timestamp>,
frame: F,
}
impl<F> TimestampedFrame<F> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(frame: F) -> Self {
Self {
pts: None,
duration: None,
frame,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn pts(&self) -> Option<mediatime::Timestamp> {
self.pts
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn duration(&self) -> Option<mediatime::Timestamp> {
self.duration
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn frame_ref(&self) -> &F {
&self.frame
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn frame_mut(&mut self) -> &mut F {
&mut self.frame
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn into_frame(self) -> F {
self.frame
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_pts(mut self, v: mediatime::Timestamp) -> Self {
self.pts = Some(v);
self
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn maybe_pts(mut self, v: Option<mediatime::Timestamp>) -> Self {
self.pts = v;
self
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn with_duration(mut self, v: mediatime::Timestamp) -> Self {
self.duration = Some(v);
self
}
#[must_use]
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn maybe_duration(mut self, v: Option<mediatime::Timestamp>) -> Self {
self.duration = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_pts(&mut self, v: mediatime::Timestamp) -> &mut Self {
self.pts = Some(v);
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn update_pts(&mut self, v: Option<mediatime::Timestamp>) -> &mut Self {
self.pts = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn clear_pts(&mut self) -> &mut Self {
self.pts = None;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn set_duration(&mut self, v: mediatime::Timestamp) -> &mut Self {
self.duration = Some(v);
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn update_duration(&mut self, v: Option<mediatime::Timestamp>) -> &mut Self {
self.duration = v;
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn clear_duration(&mut self) -> &mut Self {
self.duration = None;
self
}
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(docsrs, doc(cfg(feature = "yuv-planar")))]
mod planar_8bit;
#[cfg(feature = "yuv-planar")]
#[cfg_attr(docsrs, doc(cfg(feature = "yuv-planar")))]
mod subsampled_high_bit_planar;
use derive_more::{Display, IsVariant};
#[cfg(feature = "yuv-planar")]
pub use planar_8bit::*;
#[cfg(any(feature = "std", feature = "alloc"))]
use smol_str::SmolStr;
#[cfg(feature = "yuv-planar")]
pub use subsampled_high_bit_planar::*;
#[cfg(feature = "yuv-semi-planar")]
#[cfg_attr(docsrs, doc(cfg(feature = "yuv-semi-planar")))]
mod nv20;
#[cfg(feature = "yuv-semi-planar")]
#[cfg_attr(docsrs, doc(cfg(feature = "yuv-semi-planar")))]
mod semi_planar_8bit;
#[cfg(feature = "yuv-semi-planar")]
#[cfg_attr(docsrs, doc(cfg(feature = "yuv-semi-planar")))]
mod subsampled_high_bit_pn;
#[cfg(feature = "yuv-semi-planar")]
pub use nv20::*;
#[cfg(feature = "yuv-semi-planar")]
pub use semi_planar_8bit::*;
#[cfg(feature = "yuv-semi-planar")]
pub use subsampled_high_bit_pn::*;
#[cfg(feature = "yuva")]
#[cfg_attr(docsrs, doc(cfg(feature = "yuva")))]
mod yuva;
#[cfg(feature = "yuva")]
pub use yuva::*;
#[cfg(feature = "yuv-packed")]
#[cfg_attr(docsrs, doc(cfg(feature = "yuv-packed")))]
mod packed_yuv_4_1_1;
#[cfg(feature = "yuv-packed")]
#[cfg_attr(docsrs, doc(cfg(feature = "yuv-packed")))]
mod packed_yuv_8bit;
#[cfg(feature = "yuv-packed")]
pub use packed_yuv_4_1_1::*;
#[cfg(feature = "yuv-packed")]
pub use packed_yuv_8bit::*;
#[cfg(feature = "yuv-444-packed")]
#[cfg_attr(docsrs, doc(cfg(feature = "yuv-444-packed")))]
mod packed_yuv_4_4_4;
#[cfg(feature = "yuv-444-packed")]
pub use packed_yuv_4_4_4::*;
#[cfg(feature = "y2xx")]
#[cfg_attr(docsrs, doc(cfg(feature = "y2xx")))]
mod y2xx;
#[cfg(feature = "y2xx")]
pub use y2xx::*;
#[cfg(feature = "v210")]
#[cfg_attr(docsrs, doc(cfg(feature = "v210")))]
mod v210;
#[cfg(feature = "v210")]
pub use v210::*;
#[cfg(feature = "rgb")]
#[cfg_attr(docsrs, doc(cfg(feature = "rgb")))]
mod packed_rgb_10bit;
#[cfg(feature = "rgb")]
#[cfg_attr(docsrs, doc(cfg(feature = "rgb")))]
mod packed_rgb_16bit;
#[cfg(feature = "rgb")]
#[cfg_attr(docsrs, doc(cfg(feature = "rgb")))]
mod packed_rgb_32bit;
#[cfg(feature = "rgb")]
#[cfg_attr(docsrs, doc(cfg(feature = "rgb")))]
mod packed_rgb_8bit;
#[cfg(feature = "rgb")]
pub use packed_rgb_8bit::*;
#[cfg(feature = "rgb")]
pub use packed_rgb_10bit::*;
#[cfg(feature = "rgb")]
pub use packed_rgb_16bit::*;
#[cfg(feature = "rgb")]
pub use packed_rgb_32bit::*;
#[cfg(feature = "rgb-float")]
#[cfg_attr(docsrs, doc(cfg(feature = "rgb-float")))]
mod packed_rgb_f16;
#[cfg(feature = "rgb-float")]
#[cfg_attr(docsrs, doc(cfg(feature = "rgb-float")))]
mod packed_rgb_float;
#[cfg(feature = "rgb-float")]
pub use packed_rgb_f16::*;
#[cfg(feature = "rgb-float")]
pub use packed_rgb_float::*;
#[cfg(feature = "rgb-legacy")]
#[cfg_attr(docsrs, doc(cfg(feature = "rgb-legacy")))]
mod legacy_rgb;
#[cfg(feature = "rgb-legacy")]
pub use legacy_rgb::*;
#[cfg(feature = "gbr")]
#[cfg_attr(docsrs, doc(cfg(feature = "gbr")))]
mod planar_gbr_8bit;
#[cfg(feature = "gbr")]
#[cfg_attr(docsrs, doc(cfg(feature = "gbr")))]
mod planar_gbr_float;
#[cfg(feature = "gbr")]
#[cfg_attr(docsrs, doc(cfg(feature = "gbr")))]
mod planar_gbr_high_bit;
#[cfg(feature = "gbr")]
pub use planar_gbr_8bit::*;
#[cfg(feature = "gbr")]
pub use planar_gbr_float::*;
#[cfg(feature = "gbr")]
pub use planar_gbr_high_bit::*;
#[cfg(feature = "gray")]
#[cfg_attr(docsrs, doc(cfg(feature = "gray")))]
mod gray;
#[cfg(feature = "gray")]
pub use gray::*;
#[cfg(feature = "bayer")]
#[cfg_attr(docsrs, doc(cfg(feature = "bayer")))]
mod bayer;
#[cfg(feature = "bayer")]
pub use bayer::*;
#[cfg(feature = "xyz")]
#[cfg_attr(docsrs, doc(cfg(feature = "xyz")))]
mod xyz12;
#[cfg(feature = "xyz")]
pub use xyz12::*;
#[cfg(feature = "mono")]
#[cfg_attr(docsrs, doc(cfg(feature = "mono")))]
mod mono1bit;
#[cfg(feature = "mono")]
#[cfg_attr(docsrs, doc(cfg(feature = "mono")))]
mod pal8;
#[cfg(feature = "mono")]
pub use mono1bit::*;
#[cfg(feature = "mono")]
pub use pal8::*;
#[cfg(test)]
mod aspect_tests;
#[cfg(test)]
mod contains_tests;
#[cfg(test)]
mod tests_primitives;
#[cfg(all(test, any(feature = "std", feature = "alloc")))]
mod tests;