use super::*;
pub struct YCbCrImage<'a> {
pub planes: Planes<'a>,
pub width: u32,
pub height: u32,
}
impl<'a> YCbCrImage<'a> {
pub(crate) fn luma_bit_depth(&self) -> BitDepth {
match &self.planes {
Planes::Mono(y) => y.bit_depth,
Planes::YCbCr((y, _, _)) => y.bit_depth,
}
}
}
pub enum Planes<'a> {
Mono(DataPlane<'a>),
YCbCr((DataPlane<'a>, DataPlane<'a>, DataPlane<'a>)),
}
pub struct DataPlane<'a> {
pub data: &'a [u8],
pub stride: usize,
pub bit_depth: BitDepth,
}
impl<'a> YCbCrImage<'a> {
pub(crate) fn check_sizes(&self) -> Result<()> {
match &self.planes {
Planes::Mono(y_plane) | Planes::YCbCr((y_plane, _, _)) => {
y_plane.check_sizes(self.width, self.height, 16)?;
}
}
match &self.planes {
Planes::Mono(_) => {}
Planes::YCbCr((_, cb_plane, cr_plane)) => {
for chroma_plane in [cb_plane, cr_plane] {
chroma_plane.check_sizes(self.width / 2, self.height / 2, 8)?;
}
}
}
Ok(())
}
}
impl<'a> DataPlane<'a> {
pub(crate) fn check_sizes(&self, width: u32, height: u32, mb_sz: u32) -> Result<()> {
let (width_factor_num, width_factor_denom) = match self.bit_depth {
BitDepth::Depth8 => (1, 1),
BitDepth::Depth12 => (3, 2),
};
if self.stride
< next_multiple(width, mb_sz) as usize * width_factor_num / width_factor_denom
{
return Err(Error::DataShapeProblem {
msg: "stride too small",
#[cfg(feature = "backtrace")]
backtrace: Backtrace::capture(),
});
}
let num_rows = div_ceil(
self.data.len().try_into().unwrap(),
self.stride.try_into().unwrap(),
);
if num_rows < next_multiple(height, mb_sz) {
return Err(Error::DataShapeProblem {
msg: "number of rows too small",
#[cfg(feature = "backtrace")]
backtrace: Backtrace::capture(),
});
}
Ok(())
}
}