use super::*;
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn yuv422_packed_to_rgb_or_rgba_row<const Y_LSB: bool, const SWAP_UV: bool>(
packed: &[u8],
out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
alpha: bool,
) {
debug_assert_eq!(width & 1, 0, "packed YUV 4:2:2 requires even width");
debug_assert!(packed.len() >= width * 2, "packed row too short");
let (y0_idx, y1_idx, c0_idx, c1_idx) = if Y_LSB { (0, 2, 1, 3) } else { (1, 3, 0, 2) };
let (u_idx, v_idx) = if SWAP_UV {
(c1_idx, c0_idx)
} else {
(c0_idx, c1_idx)
};
let bpp: usize = if alpha { 4 } else { 3 };
debug_assert!(out.len() >= width * bpp, "out row too short for {bpp}bpp");
let coeffs = Coefficients::for_matrix(matrix);
let (y_off, y_scale, c_scale) = range_params_n::<8, 8>(full_range);
const RND: i32 = 1 << 14;
let mut x = 0;
while x < width {
let block = (x / 2) * 4;
let y0 = packed[block + y0_idx] as i32;
let y1 = packed[block + y1_idx] as i32;
let u = packed[block + u_idx] as i32;
let v = packed[block + v_idx] as i32;
let u_d = ((u - 128) * c_scale + RND) >> 15;
let v_d = ((v - 128) * c_scale + RND) >> 15;
let r_chroma = (coeffs.r_u() * u_d + coeffs.r_v() * v_d + RND) >> 15;
let g_chroma = (coeffs.g_u() * u_d + coeffs.g_v() * v_d + RND) >> 15;
let b_chroma = (coeffs.b_u() * u_d + coeffs.b_v() * v_d + RND) >> 15;
let y0_s = ((y0 - y_off) * y_scale + RND) >> 15;
out[x * bpp] = clamp_u8(y0_s + r_chroma);
out[x * bpp + 1] = clamp_u8(y0_s + g_chroma);
out[x * bpp + 2] = clamp_u8(y0_s + b_chroma);
if alpha {
out[x * bpp + 3] = 0xFF;
}
let y1_s = ((y1 - y_off) * y_scale + RND) >> 15;
out[(x + 1) * bpp] = clamp_u8(y1_s + r_chroma);
out[(x + 1) * bpp + 1] = clamp_u8(y1_s + g_chroma);
out[(x + 1) * bpp + 2] = clamp_u8(y1_s + b_chroma);
if alpha {
out[(x + 1) * bpp + 3] = 0xFF;
}
x += 2;
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn yuyv422_to_rgb_row(
packed: &[u8],
rgb_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
yuv422_packed_to_rgb_or_rgba_row::<true, false>(
packed, rgb_out, width, matrix, full_range, false,
);
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn yuyv422_to_rgba_row(
packed: &[u8],
rgba_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
yuv422_packed_to_rgb_or_rgba_row::<true, false>(
packed, rgba_out, width, matrix, full_range, true,
);
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn uyvy422_to_rgb_row(
packed: &[u8],
rgb_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
yuv422_packed_to_rgb_or_rgba_row::<false, false>(
packed, rgb_out, width, matrix, full_range, false,
);
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn uyvy422_to_rgba_row(
packed: &[u8],
rgba_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
yuv422_packed_to_rgb_or_rgba_row::<false, false>(
packed, rgba_out, width, matrix, full_range, true,
);
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn yvyu422_to_rgb_row(
packed: &[u8],
rgb_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
yuv422_packed_to_rgb_or_rgba_row::<true, true>(packed, rgb_out, width, matrix, full_range, false);
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn yvyu422_to_rgba_row(
packed: &[u8],
rgba_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
yuv422_packed_to_rgb_or_rgba_row::<true, true>(packed, rgba_out, width, matrix, full_range, true);
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn yuv422_packed_to_luma_row<const Y_LSB: bool>(
packed: &[u8],
luma_out: &mut [u8],
width: usize,
) {
debug_assert_eq!(width & 1, 0, "packed YUV 4:2:2 requires even width");
debug_assert!(packed.len() >= width * 2, "packed row too short");
debug_assert!(luma_out.len() >= width, "luma row too short");
let (y0_idx, y1_idx) = if Y_LSB { (0, 2) } else { (1, 3) };
let mut x = 0;
while x < width {
let block = (x / 2) * 4;
luma_out[x] = packed[block + y0_idx];
luma_out[x + 1] = packed[block + y1_idx];
x += 2;
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn yuyv422_to_luma_row(packed: &[u8], luma_out: &mut [u8], width: usize) {
yuv422_packed_to_luma_row::<true>(packed, luma_out, width);
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn uyvy422_to_luma_row(packed: &[u8], luma_out: &mut [u8], width: usize) {
yuv422_packed_to_luma_row::<false>(packed, luma_out, width);
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn yvyu422_to_luma_row(packed: &[u8], luma_out: &mut [u8], width: usize) {
yuv422_packed_to_luma_row::<true>(packed, luma_out, width);
}
#[cfg_attr(not(any(feature = "std", feature = "alloc")), allow(dead_code))]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn yuyv422_to_luma_u16_row(packed: &[u8], out: &mut [u16], width: usize) {
debug_assert!(packed.len() >= width * 2, "packed too short");
debug_assert!(out.len() >= width, "out too short");
for x in 0..width {
out[x] = packed[x * 2] as u16;
}
}
#[cfg_attr(not(any(feature = "std", feature = "alloc")), allow(dead_code))]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn uyvy422_to_luma_u16_row(packed: &[u8], out: &mut [u16], width: usize) {
debug_assert!(packed.len() >= width * 2, "packed too short");
debug_assert!(out.len() >= width, "out too short");
for x in 0..width {
out[x] = packed[x * 2 + 1] as u16;
}
}
#[cfg_attr(not(any(feature = "std", feature = "alloc")), allow(dead_code))]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn yvyu422_to_luma_u16_row(packed: &[u8], out: &mut [u16], width: usize) {
debug_assert!(packed.len() >= width * 2, "packed too short");
debug_assert!(out.len() >= width, "out too short");
for x in 0..width {
out[x] = packed[x * 2] as u16;
}
}