use crate::formats::yuv422::{Yuv422Block, Yuv422Src};
use crate::planes::read_planes;
use crate::primitive::Primitive;
use crate::vector::Vector;
use crate::{ConvertError, ImageRef, ImageRefExt};
use std::marker::PhantomData;
pub(crate) struct Read1Plane<'a, P: Primitive> {
yuyv: &'a [u8],
yuyv_stride: usize,
max_value: f32,
_m: PhantomData<&'a [P]>,
}
impl<'a, P: Primitive> Read1Plane<'a, P> {
pub(crate) fn new(src: &'a dyn ImageRef) -> Result<Self, ConvertError> {
src.bounds_check()?;
let [(yuyv, yuyv_stride)] = read_planes(src.planes())?;
Ok(Self {
yuyv,
yuyv_stride,
max_value: crate::formats::max_value_for_bits(src.format().bits_per_component()),
_m: PhantomData,
})
}
unsafe fn read_yuyv<V: Vector>(&mut self, offset: usize) -> (V, V) {
let yuyv00 = P::load::<V>(&self.yuyv[offset..]);
let yuyv01 = P::load::<V>(&self.yuyv[offset + V::LEN * P::SIZE..]);
yuyv00.unzip(yuyv01)
}
}
impl<P: Primitive> Yuv422Src for Read1Plane<'_, P> {
#[inline(always)]
unsafe fn read<V: Vector>(&mut self, x: usize, y: usize) -> Yuv422Block<V> {
let offset0 = y * self.yuyv_stride + x * 2 * P::SIZE;
let offset1 = (y + 1) * self.yuyv_stride + x * 2 * P::SIZE;
let (y00, uv00) = self.read_yuyv::<V>(offset0);
let (y01, uv01) = self.read_yuyv::<V>(offset0 + V::LEN * 2 * P::SIZE);
let (y10, uv10) = self.read_yuyv::<V>(offset1);
let (y11, uv11) = self.read_yuyv::<V>(offset1 + V::LEN * 2 * P::SIZE);
let (u0, v0) = uv00.unzip(uv01);
let (u1, v1) = uv10.unzip(uv11);
let y00 = y00.vdivf(self.max_value);
let y01 = y01.vdivf(self.max_value);
let y10 = y10.vdivf(self.max_value);
let y11 = y11.vdivf(self.max_value);
let u0 = u0.vdivf(self.max_value);
let u1 = u1.vdivf(self.max_value);
let v0 = v0.vdivf(self.max_value);
let v1 = v1.vdivf(self.max_value);
Yuv422Block {
y00,
y01,
y10,
y11,
u0,
u1,
v0,
v1,
}
}
}