#[doc(hidden)] pub mod uyvy_to_i420;
pub mod frame;
pub use uyvy_to_i420::convert as convert_uyvy_to_i420;
pub use arrayvec;
pub const MAX_PLANES: usize = 3;
#[derive(Clone, Debug)]
pub struct ConversionError(&'static str);
impl std::fmt::Display for ConversionError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl std::error::Error for ConversionError {}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum PixelFormat {
UYVY422,
I420,
BGRA,
}
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct PlaneDims {
pub stride: usize,
pub rows: usize,
}
impl PixelFormat {
#[inline]
pub fn num_planes(self) -> usize {
match self {
PixelFormat::UYVY422 => 1,
PixelFormat::I420 => 3,
PixelFormat::BGRA => 1,
}
}
pub fn min_plane_dims(self, width: usize, height: usize) -> impl Iterator<Item = PlaneDims> {
let mut sizes = arrayvec::ArrayVec::<PlaneDims, MAX_PLANES>::new();
match self {
PixelFormat::UYVY422 => {
sizes.push(PlaneDims {
stride: width
.checked_add(width & 1)
.and_then(|w| w.checked_shl(1))
.expect("stride should not overflow"),
rows: height,
});
}
PixelFormat::I420 => {
sizes.push(PlaneDims {
stride: width,
rows: height,
});
let chroma_plane_size = PlaneDims {
stride: (width >> 1) + (width & 1),
rows: (height >> 1) + (height & 1),
};
sizes.push(chroma_plane_size);
sizes.push(chroma_plane_size);
}
PixelFormat::BGRA => {
sizes.push(PlaneDims {
stride: width.checked_shl(2).expect("stride should not overflow"),
rows: height,
});
}
}
debug_assert_eq!(sizes.len(), self.num_planes());
sizes.into_iter()
}
pub fn plane_names(self) -> &'static [&'static str] {
match self {
PixelFormat::UYVY422 => &["YUYV"],
PixelFormat::I420 => &["Y", "U", "V"],
PixelFormat::BGRA => &["BGRA"],
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn odd_sizes() {
assert_eq!(
super::PixelFormat::UYVY422
.min_plane_dims(1, 1)
.collect::<Vec<_>>(),
vec![super::PlaneDims { stride: 4, rows: 1 }]
);
assert_eq!(
super::PixelFormat::UYVY422
.min_plane_dims(2, 2)
.collect::<Vec<_>>(),
vec![super::PlaneDims { stride: 4, rows: 2 }]
);
assert_eq!(
super::PixelFormat::UYVY422
.min_plane_dims(3, 3)
.collect::<Vec<_>>(),
vec![super::PlaneDims { stride: 8, rows: 3 }]
);
assert_eq!(
super::PixelFormat::I420
.min_plane_dims(1, 1)
.collect::<Vec<_>>(),
vec![
super::PlaneDims { stride: 1, rows: 1 },
super::PlaneDims { stride: 1, rows: 1 },
super::PlaneDims { stride: 1, rows: 1 }
]
);
assert_eq!(
super::PixelFormat::I420
.min_plane_dims(2, 2)
.collect::<Vec<_>>(),
vec![
super::PlaneDims { stride: 2, rows: 2 },
super::PlaneDims { stride: 1, rows: 1 },
super::PlaneDims { stride: 1, rows: 1 }
]
);
assert_eq!(
super::PixelFormat::I420
.min_plane_dims(3, 3)
.collect::<Vec<_>>(),
vec![
super::PlaneDims { stride: 3, rows: 3 },
super::PlaneDims { stride: 2, rows: 2 },
super::PlaneDims { stride: 2, rows: 2 }
]
);
}
}