#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct AvifPlane {
pub stride: usize,
pub data: Vec<u8>,
}
impl AvifPlane {
#[allow(clippy::too_many_arguments)]
pub fn new(stride: usize, data: Vec<u8>) -> Self {
Self { stride, data }
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct AvifFrame {
pub pts: Option<i64>,
pub planes: Vec<AvifPlane>,
}
impl AvifFrame {
#[allow(clippy::too_many_arguments)]
pub fn new(pts: Option<i64>, planes: Vec<AvifPlane>) -> Self {
Self { pts, planes }
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AvifPixelFormat {
Yuv420P,
Yuv422P,
Yuv444P,
Gray8,
Yuva420P,
Yuva422P,
Yuva444P,
Ya8,
Yuv420P10Le,
Yuv422P10Le,
Yuv444P10Le,
Yuv420P12Le,
Yuv422P12Le,
Yuv444P12Le,
Gray10Le,
Gray12Le,
Yuva420P10Le,
Yuva422P10Le,
Yuva444P10Le,
Yuva420P12Le,
Yuva422P12Le,
Yuva444P12Le,
Ya16Le,
}
impl AvifPixelFormat {
pub fn plane_count(&self) -> usize {
match self {
Self::Gray8 | Self::Ya8 | Self::Gray10Le | Self::Gray12Le | Self::Ya16Le => 1,
Self::Yuv420P
| Self::Yuv422P
| Self::Yuv444P
| Self::Yuv420P10Le
| Self::Yuv422P10Le
| Self::Yuv444P10Le
| Self::Yuv420P12Le
| Self::Yuv422P12Le
| Self::Yuv444P12Le => 3,
Self::Yuva420P
| Self::Yuva422P
| Self::Yuva444P
| Self::Yuva420P10Le
| Self::Yuva422P10Le
| Self::Yuva444P10Le
| Self::Yuva420P12Le
| Self::Yuva422P12Le
| Self::Yuva444P12Le => 4,
}
}
pub fn bytes_per_sample(&self) -> usize {
match self {
Self::Yuv420P
| Self::Yuv422P
| Self::Yuv444P
| Self::Gray8
| Self::Yuva420P
| Self::Yuva422P
| Self::Yuva444P
| Self::Ya8 => 1,
_ => 2,
}
}
pub fn bit_depth(&self) -> u8 {
match self {
Self::Yuv420P
| Self::Yuv422P
| Self::Yuv444P
| Self::Gray8
| Self::Yuva420P
| Self::Yuva422P
| Self::Yuva444P
| Self::Ya8 => 8,
Self::Yuv420P10Le
| Self::Yuv422P10Le
| Self::Yuv444P10Le
| Self::Gray10Le
| Self::Yuva420P10Le
| Self::Yuva422P10Le
| Self::Yuva444P10Le => 10,
Self::Yuv420P12Le
| Self::Yuv422P12Le
| Self::Yuv444P12Le
| Self::Gray12Le
| Self::Yuva420P12Le
| Self::Yuva422P12Le
| Self::Yuva444P12Le => 12,
Self::Ya16Le => 16,
}
}
pub fn chroma_subsampling(&self) -> (u8, u8) {
match self {
Self::Yuv420P
| Self::Yuva420P
| Self::Yuv420P10Le
| Self::Yuv420P12Le
| Self::Yuva420P10Le
| Self::Yuva420P12Le => (1, 1),
Self::Yuv422P
| Self::Yuva422P
| Self::Yuv422P10Le
| Self::Yuv422P12Le
| Self::Yuva422P10Le
| Self::Yuva422P12Le => (1, 0),
_ => (0, 0),
}
}
pub fn is_packed_ya(&self) -> bool {
matches!(self, Self::Ya8 | Self::Ya16Le)
}
pub fn has_alpha(&self) -> bool {
self.is_packed_ya() || self.plane_count() == 4
}
pub fn from_layout(bit_depth: u8, sx: u8, sy: u8, gray: bool, alpha: bool) -> Option<Self> {
let base = match (gray, bit_depth, sx, sy) {
(true, 8, _, _) => Self::Gray8,
(true, 10, _, _) => Self::Gray10Le,
(true, 12, _, _) => Self::Gray12Le,
(false, 8, 1, 1) => Self::Yuv420P,
(false, 8, 1, 0) => Self::Yuv422P,
(false, 8, 0, 0) => Self::Yuv444P,
(false, 10, 1, 1) => Self::Yuv420P10Le,
(false, 10, 1, 0) => Self::Yuv422P10Le,
(false, 10, 0, 0) => Self::Yuv444P10Le,
(false, 12, 1, 1) => Self::Yuv420P12Le,
(false, 12, 1, 0) => Self::Yuv422P12Le,
(false, 12, 0, 0) => Self::Yuv444P12Le,
_ => return None,
};
if alpha {
base.with_alpha()
} else {
Some(base)
}
}
pub fn without_alpha(&self, bit_depth: u8) -> Self {
match self {
Self::Yuva420P => Self::Yuv420P,
Self::Yuva422P => Self::Yuv422P,
Self::Yuva444P => Self::Yuv444P,
Self::Ya8 => Self::Gray8,
Self::Yuva420P10Le => Self::Yuv420P10Le,
Self::Yuva422P10Le => Self::Yuv422P10Le,
Self::Yuva444P10Le => Self::Yuv444P10Le,
Self::Yuva420P12Le => Self::Yuv420P12Le,
Self::Yuva422P12Le => Self::Yuv422P12Le,
Self::Yuva444P12Le => Self::Yuv444P12Le,
Self::Ya16Le => {
if bit_depth == 12 {
Self::Gray12Le
} else {
Self::Gray10Le
}
}
other => *other,
}
}
pub fn with_alpha(&self) -> Option<Self> {
match self {
Self::Yuv420P => Some(Self::Yuva420P),
Self::Yuv422P => Some(Self::Yuva422P),
Self::Yuv444P => Some(Self::Yuva444P),
Self::Gray8 => Some(Self::Ya8),
Self::Yuv420P10Le => Some(Self::Yuva420P10Le),
Self::Yuv422P10Le => Some(Self::Yuva422P10Le),
Self::Yuv444P10Le => Some(Self::Yuva444P10Le),
Self::Yuv420P12Le => Some(Self::Yuva420P12Le),
Self::Yuv422P12Le => Some(Self::Yuva422P12Le),
Self::Yuv444P12Le => Some(Self::Yuva444P12Le),
Self::Gray10Le | Self::Gray12Le => Some(Self::Ya16Le),
_ => None,
}
}
}
#[cfg(feature = "registry")]
impl From<AvifPlane> for oxideav_core::frame::VideoPlane {
fn from(p: AvifPlane) -> Self {
oxideav_core::frame::VideoPlane {
stride: p.stride,
data: p.data,
}
}
}
#[cfg(feature = "registry")]
impl From<oxideav_core::frame::VideoPlane> for AvifPlane {
fn from(p: oxideav_core::frame::VideoPlane) -> Self {
AvifPlane {
stride: p.stride,
data: p.data,
}
}
}
#[cfg(feature = "registry")]
impl From<AvifFrame> for oxideav_core::frame::VideoFrame {
fn from(af: AvifFrame) -> Self {
oxideav_core::frame::VideoFrame {
pts: af.pts,
planes: af.planes.into_iter().map(Into::into).collect(),
}
}
}
#[cfg(feature = "registry")]
impl From<oxideav_core::frame::VideoFrame> for AvifFrame {
fn from(vf: oxideav_core::frame::VideoFrame) -> Self {
let image_planes = vf.image_plane_count();
AvifFrame {
pts: vf.pts,
planes: vf
.planes
.into_iter()
.take(image_planes)
.map(Into::into)
.collect(),
}
}
}
#[cfg(feature = "registry")]
impl From<AvifPixelFormat> for oxideav_core::PixelFormat {
fn from(fmt: AvifPixelFormat) -> Self {
match fmt {
AvifPixelFormat::Yuv420P => oxideav_core::PixelFormat::Yuv420P,
AvifPixelFormat::Yuv422P => oxideav_core::PixelFormat::Yuv422P,
AvifPixelFormat::Yuv444P => oxideav_core::PixelFormat::Yuv444P,
AvifPixelFormat::Gray8 => oxideav_core::PixelFormat::Gray8,
AvifPixelFormat::Yuva420P => oxideav_core::PixelFormat::Yuva420P,
AvifPixelFormat::Yuva422P => oxideav_core::PixelFormat::Yuva422P,
AvifPixelFormat::Yuva444P => oxideav_core::PixelFormat::Yuva444P,
AvifPixelFormat::Ya8 => oxideav_core::PixelFormat::Ya8,
AvifPixelFormat::Yuv420P10Le => oxideav_core::PixelFormat::Yuv420P10Le,
AvifPixelFormat::Yuv422P10Le => oxideav_core::PixelFormat::Yuv422P10Le,
AvifPixelFormat::Yuv444P10Le => oxideav_core::PixelFormat::Yuv444P10Le,
AvifPixelFormat::Yuv420P12Le => oxideav_core::PixelFormat::Yuv420P12Le,
AvifPixelFormat::Yuv422P12Le => oxideav_core::PixelFormat::Yuv422P12Le,
AvifPixelFormat::Yuv444P12Le => oxideav_core::PixelFormat::Yuv444P12Le,
AvifPixelFormat::Gray10Le => oxideav_core::PixelFormat::Gray10Le,
AvifPixelFormat::Gray12Le => oxideav_core::PixelFormat::Gray12Le,
AvifPixelFormat::Yuva420P10Le => oxideav_core::PixelFormat::Yuva420P10Le,
AvifPixelFormat::Yuva422P10Le => oxideav_core::PixelFormat::Yuva422P10Le,
AvifPixelFormat::Yuva444P10Le => oxideav_core::PixelFormat::Yuva444P10Le,
AvifPixelFormat::Yuva420P12Le => oxideav_core::PixelFormat::Yuva420P12Le,
AvifPixelFormat::Yuva422P12Le => oxideav_core::PixelFormat::Yuva422P12Le,
AvifPixelFormat::Yuva444P12Le => oxideav_core::PixelFormat::Yuva444P12Le,
AvifPixelFormat::Ya16Le => oxideav_core::PixelFormat::Ya16Le,
}
}
}
#[cfg(feature = "registry")]
impl TryFrom<oxideav_core::PixelFormat> for AvifPixelFormat {
type Error = crate::error::AvifError;
fn try_from(fmt: oxideav_core::PixelFormat) -> Result<Self, Self::Error> {
match fmt {
oxideav_core::PixelFormat::Yuv420P => Ok(AvifPixelFormat::Yuv420P),
oxideav_core::PixelFormat::Yuv422P => Ok(AvifPixelFormat::Yuv422P),
oxideav_core::PixelFormat::Yuv444P => Ok(AvifPixelFormat::Yuv444P),
oxideav_core::PixelFormat::Gray8 => Ok(AvifPixelFormat::Gray8),
oxideav_core::PixelFormat::Yuva420P => Ok(AvifPixelFormat::Yuva420P),
oxideav_core::PixelFormat::Yuva422P => Ok(AvifPixelFormat::Yuva422P),
oxideav_core::PixelFormat::Yuva444P => Ok(AvifPixelFormat::Yuva444P),
oxideav_core::PixelFormat::Ya8 => Ok(AvifPixelFormat::Ya8),
oxideav_core::PixelFormat::Yuv420P10Le => Ok(AvifPixelFormat::Yuv420P10Le),
oxideav_core::PixelFormat::Yuv422P10Le => Ok(AvifPixelFormat::Yuv422P10Le),
oxideav_core::PixelFormat::Yuv444P10Le => Ok(AvifPixelFormat::Yuv444P10Le),
oxideav_core::PixelFormat::Yuv420P12Le => Ok(AvifPixelFormat::Yuv420P12Le),
oxideav_core::PixelFormat::Yuv422P12Le => Ok(AvifPixelFormat::Yuv422P12Le),
oxideav_core::PixelFormat::Yuv444P12Le => Ok(AvifPixelFormat::Yuv444P12Le),
oxideav_core::PixelFormat::Gray10Le => Ok(AvifPixelFormat::Gray10Le),
oxideav_core::PixelFormat::Gray12Le => Ok(AvifPixelFormat::Gray12Le),
oxideav_core::PixelFormat::Yuva420P10Le => Ok(AvifPixelFormat::Yuva420P10Le),
oxideav_core::PixelFormat::Yuva422P10Le => Ok(AvifPixelFormat::Yuva422P10Le),
oxideav_core::PixelFormat::Yuva444P10Le => Ok(AvifPixelFormat::Yuva444P10Le),
oxideav_core::PixelFormat::Yuva420P12Le => Ok(AvifPixelFormat::Yuva420P12Le),
oxideav_core::PixelFormat::Yuva422P12Le => Ok(AvifPixelFormat::Yuva422P12Le),
oxideav_core::PixelFormat::Yuva444P12Le => Ok(AvifPixelFormat::Yuva444P12Le),
oxideav_core::PixelFormat::Ya16Le => Ok(AvifPixelFormat::Ya16Le),
other => Err(crate::error::AvifError::unsupported(format!(
"avif: unsupported PixelFormat {other:?}"
))),
}
}
}