#[cfg(feature = "yuv-planar")]
use super::{load_u16, *};
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn yuv_420p16_to_rgb_row<const BE: bool>(
y: &[u16],
u_half: &[u16],
v_half: &[u16],
rgb_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
yuv_420p16_to_rgb_or_rgba_row::<false, false, BE>(
y, u_half, v_half, None, rgb_out, width, matrix, full_range,
);
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn yuv_420p16_to_rgba_row<const BE: bool>(
y: &[u16],
u_half: &[u16],
v_half: &[u16],
rgba_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
yuv_420p16_to_rgb_or_rgba_row::<true, false, BE>(
y, u_half, v_half, None, rgba_out, width, matrix, full_range,
);
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub(crate) fn yuv_420p16_to_rgba_with_alpha_src_row<const BE: bool>(
y: &[u16],
u_half: &[u16],
v_half: &[u16],
a_src: &[u16],
rgba_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
yuv_420p16_to_rgb_or_rgba_row::<true, true, BE>(
y,
u_half,
v_half,
Some(a_src),
rgba_out,
width,
matrix,
full_range,
);
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub(crate) fn yuv_420p16_to_rgb_or_rgba_row<
const ALPHA: bool,
const ALPHA_SRC: bool,
const BE: bool,
>(
y: &[u16],
u_half: &[u16],
v_half: &[u16],
a_src: Option<&[u16]>,
out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
const { assert!(!ALPHA_SRC || ALPHA) };
let bpp: usize = if ALPHA { 4 } else { 3 };
debug_assert_eq!(width & 1, 0, "YUV 4:2:0 requires even width");
debug_assert!(y.len() >= width, "y row too short");
debug_assert!(u_half.len() >= width / 2, "u_half row too short");
debug_assert!(v_half.len() >= width / 2, "v_half row too short");
debug_assert!(out.len() >= width * bpp, "out row too short");
if ALPHA_SRC {
debug_assert!(
a_src.as_ref().is_some_and(|s| s.len() >= width),
"a_src row too short"
);
}
let coeffs = Coefficients::for_matrix(matrix);
let (y_off, y_scale, c_scale) = range_params_n::<16, 8>(full_range);
let bias = chroma_bias::<16>();
let mut x = 0;
while x < width {
let c_idx = x / 2;
let u_d = q15_scale(load_u16::<BE>(u_half[c_idx]) as i32 - bias, c_scale);
let v_d = q15_scale(load_u16::<BE>(v_half[c_idx]) as i32 - bias, c_scale);
let r_chroma = q15_chroma(coeffs.r_u(), u_d, coeffs.r_v(), v_d);
let g_chroma = q15_chroma(coeffs.g_u(), u_d, coeffs.g_v(), v_d);
let b_chroma = q15_chroma(coeffs.b_u(), u_d, coeffs.b_v(), v_d);
let y0 = q15_scale(load_u16::<BE>(y[x]) as i32 - y_off, y_scale);
out[x * bpp] = clamp_u8(y0 + r_chroma);
out[x * bpp + 1] = clamp_u8(y0 + g_chroma);
out[x * bpp + 2] = clamp_u8(y0 + b_chroma);
if ALPHA_SRC {
out[x * bpp + 3] = (load_u16::<BE>(a_src.as_ref().unwrap()[x]) >> 8) as u8;
} else if ALPHA {
out[x * bpp + 3] = 0xFF;
}
let y1 = q15_scale(load_u16::<BE>(y[x + 1]) as i32 - y_off, y_scale);
out[(x + 1) * bpp] = clamp_u8(y1 + r_chroma);
out[(x + 1) * bpp + 1] = clamp_u8(y1 + g_chroma);
out[(x + 1) * bpp + 2] = clamp_u8(y1 + b_chroma);
if ALPHA_SRC {
out[(x + 1) * bpp + 3] = (load_u16::<BE>(a_src.as_ref().unwrap()[x + 1]) >> 8) as u8;
} else if ALPHA {
out[(x + 1) * bpp + 3] = 0xFF;
}
x += 2;
}
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn yuv_420p16_to_rgb_u16_row<const BE: bool>(
y: &[u16],
u_half: &[u16],
v_half: &[u16],
rgb_out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
yuv_420p16_to_rgb_or_rgba_u16_row::<false, false, BE>(
y, u_half, v_half, None, rgb_out, width, matrix, full_range,
);
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn yuv_420p16_to_rgba_u16_row<const BE: bool>(
y: &[u16],
u_half: &[u16],
v_half: &[u16],
rgba_out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
yuv_420p16_to_rgb_or_rgba_u16_row::<true, false, BE>(
y, u_half, v_half, None, rgba_out, width, matrix, full_range,
);
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub(crate) fn yuv_420p16_to_rgba_u16_with_alpha_src_row<const BE: bool>(
y: &[u16],
u_half: &[u16],
v_half: &[u16],
a_src: &[u16],
rgba_out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
yuv_420p16_to_rgb_or_rgba_u16_row::<true, true, BE>(
y,
u_half,
v_half,
Some(a_src),
rgba_out,
width,
matrix,
full_range,
);
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub(crate) fn yuv_420p16_to_rgb_or_rgba_u16_row<
const ALPHA: bool,
const ALPHA_SRC: bool,
const BE: bool,
>(
y: &[u16],
u_half: &[u16],
v_half: &[u16],
a_src: Option<&[u16]>,
out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
const { assert!(!ALPHA_SRC || ALPHA) };
let bpp: usize = if ALPHA { 4 } else { 3 };
debug_assert_eq!(width & 1, 0, "YUV 4:2:0 requires even width");
debug_assert!(y.len() >= width, "y row too short");
debug_assert!(u_half.len() >= width / 2, "u_half row too short");
debug_assert!(v_half.len() >= width / 2, "v_half row too short");
debug_assert!(out.len() >= width * bpp, "out row too short");
if ALPHA_SRC {
debug_assert!(
a_src.as_ref().is_some_and(|s| s.len() >= width),
"a_src row too short"
);
}
let coeffs = Coefficients::for_matrix(matrix);
let (y_off, y_scale, c_scale) = range_params_n::<16, 16>(full_range);
let bias = chroma_bias::<16>();
let out_max: i32 = 0xFFFF;
let mut x = 0;
while x < width {
let c_idx = x / 2;
let u_d = q15_scale(load_u16::<BE>(u_half[c_idx]) as i32 - bias, c_scale);
let v_d = q15_scale(load_u16::<BE>(v_half[c_idx]) as i32 - bias, c_scale);
let r_chroma = q15_chroma64(coeffs.r_u(), u_d, coeffs.r_v(), v_d);
let g_chroma = q15_chroma64(coeffs.g_u(), u_d, coeffs.g_v(), v_d);
let b_chroma = q15_chroma64(coeffs.b_u(), u_d, coeffs.b_v(), v_d);
let y0 = q15_scale64(load_u16::<BE>(y[x]) as i32 - y_off, y_scale);
out[x * bpp] = (y0 + r_chroma).clamp(0, out_max) as u16;
out[x * bpp + 1] = (y0 + g_chroma).clamp(0, out_max) as u16;
out[x * bpp + 2] = (y0 + b_chroma).clamp(0, out_max) as u16;
if ALPHA_SRC {
out[x * bpp + 3] = load_u16::<BE>(a_src.as_ref().unwrap()[x]);
} else if ALPHA {
out[x * bpp + 3] = 0xFFFF;
}
let y1 = q15_scale64(load_u16::<BE>(y[x + 1]) as i32 - y_off, y_scale);
out[(x + 1) * bpp] = (y1 + r_chroma).clamp(0, out_max) as u16;
out[(x + 1) * bpp + 1] = (y1 + g_chroma).clamp(0, out_max) as u16;
out[(x + 1) * bpp + 2] = (y1 + b_chroma).clamp(0, out_max) as u16;
if ALPHA_SRC {
out[(x + 1) * bpp + 3] = load_u16::<BE>(a_src.as_ref().unwrap()[x + 1]);
} else if ALPHA {
out[(x + 1) * bpp + 3] = 0xFFFF;
}
x += 2;
}
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn yuv_444p16_to_rgb_row<const BE: bool>(
y: &[u16],
u: &[u16],
v: &[u16],
rgb_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
yuv_444p16_to_rgb_or_rgba_row::<false, false, BE>(
y, u, v, None, rgb_out, width, matrix, full_range,
);
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn yuv_444p16_to_rgba_row<const BE: bool>(
y: &[u16],
u: &[u16],
v: &[u16],
rgba_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
yuv_444p16_to_rgb_or_rgba_row::<true, false, BE>(
y, u, v, None, rgba_out, width, matrix, full_range,
);
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub(crate) fn yuv_444p16_to_rgba_with_alpha_src_row<const BE: bool>(
y: &[u16],
u: &[u16],
v: &[u16],
a_src: &[u16],
rgba_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
yuv_444p16_to_rgb_or_rgba_row::<true, true, BE>(
y,
u,
v,
Some(a_src),
rgba_out,
width,
matrix,
full_range,
);
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub(crate) fn yuv_444p16_to_rgb_or_rgba_row<
const ALPHA: bool,
const ALPHA_SRC: bool,
const BE: bool,
>(
y: &[u16],
u: &[u16],
v: &[u16],
a_src: Option<&[u16]>,
out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
const { assert!(!ALPHA_SRC || ALPHA) };
let bpp: usize = if ALPHA { 4 } else { 3 };
debug_assert!(y.len() >= width, "y row too short");
debug_assert!(u.len() >= width, "u row too short");
debug_assert!(v.len() >= width, "v row too short");
debug_assert!(out.len() >= width * bpp, "out row too short");
if ALPHA_SRC {
debug_assert!(
a_src.as_ref().is_some_and(|s| s.len() >= width),
"a_src row too short"
);
}
let coeffs = Coefficients::for_matrix(matrix);
let (y_off, y_scale, c_scale) = range_params_n::<16, 8>(full_range);
let bias = chroma_bias::<16>();
for x in 0..width {
let u_d = q15_scale(load_u16::<BE>(u[x]) as i32 - bias, c_scale);
let v_d = q15_scale(load_u16::<BE>(v[x]) as i32 - bias, c_scale);
let r_chroma = q15_chroma(coeffs.r_u(), u_d, coeffs.r_v(), v_d);
let g_chroma = q15_chroma(coeffs.g_u(), u_d, coeffs.g_v(), v_d);
let b_chroma = q15_chroma(coeffs.b_u(), u_d, coeffs.b_v(), v_d);
let y0 = q15_scale(load_u16::<BE>(y[x]) as i32 - y_off, y_scale);
out[x * bpp] = clamp_u8(y0 + r_chroma);
out[x * bpp + 1] = clamp_u8(y0 + g_chroma);
out[x * bpp + 2] = clamp_u8(y0 + b_chroma);
if ALPHA_SRC {
out[x * bpp + 3] = (load_u16::<BE>(a_src.as_ref().unwrap()[x]) >> 8) as u8;
} else if ALPHA {
out[x * bpp + 3] = 0xFF;
}
}
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn yuv_444p16_to_rgb_u16_row<const BE: bool>(
y: &[u16],
u: &[u16],
v: &[u16],
rgb_out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
yuv_444p16_to_rgb_or_rgba_u16_row::<false, false, BE>(
y, u, v, None, rgb_out, width, matrix, full_range,
);
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn yuv_444p16_to_rgba_u16_row<const BE: bool>(
y: &[u16],
u: &[u16],
v: &[u16],
rgba_out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
yuv_444p16_to_rgb_or_rgba_u16_row::<true, false, BE>(
y, u, v, None, rgba_out, width, matrix, full_range,
);
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub(crate) fn yuv_444p16_to_rgba_u16_with_alpha_src_row<const BE: bool>(
y: &[u16],
u: &[u16],
v: &[u16],
a_src: &[u16],
rgba_out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
yuv_444p16_to_rgb_or_rgba_u16_row::<true, true, BE>(
y,
u,
v,
Some(a_src),
rgba_out,
width,
matrix,
full_range,
);
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub(crate) fn yuv_444p16_to_rgb_or_rgba_u16_row<
const ALPHA: bool,
const ALPHA_SRC: bool,
const BE: bool,
>(
y: &[u16],
u: &[u16],
v: &[u16],
a_src: Option<&[u16]>,
out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
const { assert!(!ALPHA_SRC || ALPHA) };
let bpp: usize = if ALPHA { 4 } else { 3 };
debug_assert!(y.len() >= width, "y row too short");
debug_assert!(u.len() >= width, "u row too short");
debug_assert!(v.len() >= width, "v row too short");
debug_assert!(out.len() >= width * bpp, "out row too short");
if ALPHA_SRC {
debug_assert!(
a_src.as_ref().is_some_and(|s| s.len() >= width),
"a_src row too short"
);
}
let coeffs = Coefficients::for_matrix(matrix);
let (y_off, y_scale, c_scale) = range_params_n::<16, 16>(full_range);
let bias = chroma_bias::<16>();
let out_max: i32 = 0xFFFF;
for x in 0..width {
let u_d = q15_scale(load_u16::<BE>(u[x]) as i32 - bias, c_scale);
let v_d = q15_scale(load_u16::<BE>(v[x]) as i32 - bias, c_scale);
let r_chroma = q15_chroma64(coeffs.r_u(), u_d, coeffs.r_v(), v_d);
let g_chroma = q15_chroma64(coeffs.g_u(), u_d, coeffs.g_v(), v_d);
let b_chroma = q15_chroma64(coeffs.b_u(), u_d, coeffs.b_v(), v_d);
let y0 = q15_scale64(load_u16::<BE>(y[x]) as i32 - y_off, y_scale);
out[x * bpp] = (y0 + r_chroma).clamp(0, out_max) as u16;
out[x * bpp + 1] = (y0 + g_chroma).clamp(0, out_max) as u16;
out[x * bpp + 2] = (y0 + b_chroma).clamp(0, out_max) as u16;
if ALPHA_SRC {
out[x * bpp + 3] = load_u16::<BE>(a_src.as_ref().unwrap()[x]);
} else if ALPHA {
out[x * bpp + 3] = 0xFFFF;
}
}
}
#[cfg(all(feature = "yuv-planar", feature = "yuv-semi-planar"))]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p16_to_rgb_row<const BE: bool>(
y: &[u16],
uv_half: &[u16],
rgb_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
p16_to_rgb_or_rgba_row::<false, BE>(y, uv_half, rgb_out, width, matrix, full_range);
}
#[cfg(all(feature = "yuv-planar", feature = "yuv-semi-planar"))]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p16_to_rgba_row<const BE: bool>(
y: &[u16],
uv_half: &[u16],
rgba_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
p16_to_rgb_or_rgba_row::<true, BE>(y, uv_half, rgba_out, width, matrix, full_range);
}
#[cfg(all(feature = "yuv-planar", feature = "yuv-semi-planar"))]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p16_to_rgb_or_rgba_row<const ALPHA: bool, const BE: bool>(
y: &[u16],
uv_half: &[u16],
out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
let bpp: usize = if ALPHA { 4 } else { 3 };
debug_assert_eq!(width & 1, 0, "semi-planar 4:2:0 requires even width");
debug_assert!(y.len() >= width, "y row too short");
debug_assert!(uv_half.len() >= width, "uv row too short");
debug_assert!(out.len() >= width * bpp, "out row too short");
let coeffs = Coefficients::for_matrix(matrix);
let (y_off, y_scale, c_scale) = range_params_n::<16, 8>(full_range);
let bias = chroma_bias::<16>();
let mut x = 0;
while x < width {
let c_idx = x / 2;
let u_sample = load_u16::<BE>(uv_half[c_idx * 2]);
let v_sample = load_u16::<BE>(uv_half[c_idx * 2 + 1]);
let u_d = q15_scale(u_sample as i32 - bias, c_scale);
let v_d = q15_scale(v_sample as i32 - bias, c_scale);
let r_chroma = q15_chroma(coeffs.r_u(), u_d, coeffs.r_v(), v_d);
let g_chroma = q15_chroma(coeffs.g_u(), u_d, coeffs.g_v(), v_d);
let b_chroma = q15_chroma(coeffs.b_u(), u_d, coeffs.b_v(), v_d);
let y0 = q15_scale(load_u16::<BE>(y[x]) as i32 - y_off, y_scale);
out[x * bpp] = clamp_u8(y0 + r_chroma);
out[x * bpp + 1] = clamp_u8(y0 + g_chroma);
out[x * bpp + 2] = clamp_u8(y0 + b_chroma);
if ALPHA {
out[x * bpp + 3] = 0xFF;
}
let y1 = q15_scale(load_u16::<BE>(y[x + 1]) as i32 - y_off, y_scale);
out[(x + 1) * bpp] = clamp_u8(y1 + r_chroma);
out[(x + 1) * bpp + 1] = clamp_u8(y1 + g_chroma);
out[(x + 1) * bpp + 2] = clamp_u8(y1 + b_chroma);
if ALPHA {
out[(x + 1) * bpp + 3] = 0xFF;
}
x += 2;
}
}
#[cfg(all(feature = "yuv-planar", feature = "yuv-semi-planar"))]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p16_to_rgb_u16_row<const BE: bool>(
y: &[u16],
uv_half: &[u16],
rgb_out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
p16_to_rgb_or_rgba_u16_row::<false, BE>(y, uv_half, rgb_out, width, matrix, full_range);
}
#[cfg(all(feature = "yuv-planar", feature = "yuv-semi-planar"))]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p16_to_rgba_u16_row<const BE: bool>(
y: &[u16],
uv_half: &[u16],
rgba_out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
p16_to_rgb_or_rgba_u16_row::<true, BE>(y, uv_half, rgba_out, width, matrix, full_range);
}
#[cfg(all(feature = "yuv-planar", feature = "yuv-semi-planar"))]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p16_to_rgb_or_rgba_u16_row<const ALPHA: bool, const BE: bool>(
y: &[u16],
uv_half: &[u16],
out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
let bpp: usize = if ALPHA { 4 } else { 3 };
debug_assert_eq!(width & 1, 0, "semi-planar 4:2:0 requires even width");
debug_assert!(y.len() >= width, "y row too short");
debug_assert!(uv_half.len() >= width, "uv row too short");
debug_assert!(out.len() >= width * bpp, "out row too short");
let coeffs = Coefficients::for_matrix(matrix);
let (y_off, y_scale, c_scale) = range_params_n::<16, 16>(full_range);
let bias = chroma_bias::<16>();
let out_max: i32 = 0xFFFF;
let mut x = 0;
while x < width {
let c_idx = x / 2;
let u_sample = load_u16::<BE>(uv_half[c_idx * 2]);
let v_sample = load_u16::<BE>(uv_half[c_idx * 2 + 1]);
let u_d = q15_scale(u_sample as i32 - bias, c_scale);
let v_d = q15_scale(v_sample as i32 - bias, c_scale);
let r_chroma = q15_chroma64(coeffs.r_u(), u_d, coeffs.r_v(), v_d);
let g_chroma = q15_chroma64(coeffs.g_u(), u_d, coeffs.g_v(), v_d);
let b_chroma = q15_chroma64(coeffs.b_u(), u_d, coeffs.b_v(), v_d);
let y0 = q15_scale64(load_u16::<BE>(y[x]) as i32 - y_off, y_scale);
out[x * bpp] = (y0 + r_chroma).clamp(0, out_max) as u16;
out[x * bpp + 1] = (y0 + g_chroma).clamp(0, out_max) as u16;
out[x * bpp + 2] = (y0 + b_chroma).clamp(0, out_max) as u16;
if ALPHA {
out[x * bpp + 3] = 0xFFFF;
}
let y1 = q15_scale64(load_u16::<BE>(y[x + 1]) as i32 - y_off, y_scale);
out[(x + 1) * bpp] = (y1 + r_chroma).clamp(0, out_max) as u16;
out[(x + 1) * bpp + 1] = (y1 + g_chroma).clamp(0, out_max) as u16;
out[(x + 1) * bpp + 2] = (y1 + b_chroma).clamp(0, out_max) as u16;
if ALPHA {
out[(x + 1) * bpp + 3] = 0xFFFF;
}
x += 2;
}
}