use super::{load_u16, *};
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p_n_to_rgb_row<const BITS: u32, const BE: bool>(
y: &[u16],
uv_half: &[u16],
rgb_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
p_n_to_rgb_or_rgba_row::<BITS, false, BE>(y, uv_half, rgb_out, width, matrix, full_range);
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p_n_to_rgba_row<const BITS: u32, const BE: bool>(
y: &[u16],
uv_half: &[u16],
rgba_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
p_n_to_rgb_or_rgba_row::<BITS, true, BE>(y, uv_half, rgba_out, width, matrix, full_range);
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p_n_to_rgb_or_rgba_row<const BITS: u32, const ALPHA: bool, const BE: bool>(
y: &[u16],
uv_half: &[u16],
out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
const { assert!(BITS == 10 || BITS == 12) };
let bpp: usize = if ALPHA { 4 } else { 3 };
debug_assert_eq!(width & 1, 0, "semi-planar high-bit 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::<BITS, 8>(full_range);
let bias = chroma_bias::<BITS>();
let shift = 16 - BITS;
let mut x = 0;
while x < width {
let c_idx = x / 2;
let u_sample = load_u16::<BE>(uv_half[c_idx * 2]) >> shift;
let v_sample = load_u16::<BE>(uv_half[c_idx * 2 + 1]) >> shift;
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]) >> shift) 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]) >> shift) 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(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p_n_to_rgb_u16_row<const BITS: u32, const BE: bool>(
y: &[u16],
uv_half: &[u16],
rgb_out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
p_n_to_rgb_or_rgba_u16_row::<BITS, false, BE>(y, uv_half, rgb_out, width, matrix, full_range);
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p_n_to_rgba_u16_row<const BITS: u32, const BE: bool>(
y: &[u16],
uv_half: &[u16],
rgba_out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
p_n_to_rgb_or_rgba_u16_row::<BITS, true, BE>(y, uv_half, rgba_out, width, matrix, full_range);
}
#[cfg(feature = "yuv-planar")]
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p_n_to_rgb_or_rgba_u16_row<const BITS: u32, const ALPHA: bool, const BE: bool>(
y: &[u16],
uv_half: &[u16],
out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
const { assert!(BITS == 10 || BITS == 12) };
let bpp: usize = if ALPHA { 4 } else { 3 };
debug_assert_eq!(width & 1, 0, "semi-planar high-bit 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::<BITS, BITS>(full_range);
let bias = chroma_bias::<BITS>();
let out_max: i32 = (1i32 << BITS) - 1;
let shift = 16 - BITS;
let alpha_max: u16 = out_max as u16;
let mut x = 0;
while x < width {
let c_idx = x / 2;
let u_sample = load_u16::<BE>(uv_half[c_idx * 2]) >> shift;
let v_sample = load_u16::<BE>(uv_half[c_idx * 2 + 1]) >> shift;
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]) >> shift) 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] = alpha_max;
}
let y1 = q15_scale((load_u16::<BE>(y[x + 1]) >> shift) 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] = alpha_max;
}
x += 2;
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p_n_444_to_rgb_row<const BITS: u32, const BE: bool>(
y: &[u16],
uv_full: &[u16],
rgb_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
p_n_444_to_rgb_or_rgba_row::<BITS, false, BE>(y, uv_full, rgb_out, width, matrix, full_range);
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p_n_444_to_rgba_row<const BITS: u32, const BE: bool>(
y: &[u16],
uv_full: &[u16],
rgba_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
p_n_444_to_rgb_or_rgba_row::<BITS, true, BE>(y, uv_full, rgba_out, width, matrix, full_range);
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p_n_444_to_rgb_or_rgba_row<const BITS: u32, const ALPHA: bool, const BE: bool>(
y: &[u16],
uv_full: &[u16],
out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
const { assert!(BITS == 10 || BITS == 12) };
let bpp: usize = if ALPHA { 4 } else { 3 };
debug_assert!(y.len() >= width, "y row too short");
debug_assert!(uv_full.len() >= 2 * width, "uv_full 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::<BITS, 8>(full_range);
let bias = chroma_bias::<BITS>();
let shift = 16 - BITS;
for x in 0..width {
let u_sample = load_u16::<BE>(uv_full[x * 2]) >> shift;
let v_sample = load_u16::<BE>(uv_full[x * 2 + 1]) >> shift;
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]) >> shift) 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;
}
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p_n_444_to_rgb_u16_row<const BITS: u32, const BE: bool>(
y: &[u16],
uv_full: &[u16],
rgb_out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
p_n_444_to_rgb_or_rgba_u16_row::<BITS, false, BE>(y, uv_full, rgb_out, width, matrix, full_range);
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p_n_444_to_rgba_u16_row<const BITS: u32, const BE: bool>(
y: &[u16],
uv_full: &[u16],
rgba_out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
p_n_444_to_rgb_or_rgba_u16_row::<BITS, true, BE>(y, uv_full, rgba_out, width, matrix, full_range);
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p_n_444_to_rgb_or_rgba_u16_row<const BITS: u32, const ALPHA: bool, const BE: bool>(
y: &[u16],
uv_full: &[u16],
out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
const { assert!(BITS == 10 || BITS == 12) };
let bpp: usize = if ALPHA { 4 } else { 3 };
debug_assert!(y.len() >= width, "y row too short");
debug_assert!(uv_full.len() >= 2 * width, "uv_full 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::<BITS, BITS>(full_range);
let bias = chroma_bias::<BITS>();
let out_max: i32 = (1i32 << BITS) - 1;
let shift = 16 - BITS;
let alpha_max: u16 = out_max as u16;
for x in 0..width {
let u_sample = load_u16::<BE>(uv_full[x * 2]) >> shift;
let v_sample = load_u16::<BE>(uv_full[x * 2 + 1]) >> shift;
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]) >> shift) 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] = alpha_max;
}
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p_n_444_16_to_rgb_row<const BE: bool>(
y: &[u16],
uv_full: &[u16],
rgb_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
p_n_444_16_to_rgb_or_rgba_row::<false, BE>(y, uv_full, rgb_out, width, matrix, full_range);
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p_n_444_16_to_rgba_row<const BE: bool>(
y: &[u16],
uv_full: &[u16],
rgba_out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
p_n_444_16_to_rgb_or_rgba_row::<true, BE>(y, uv_full, rgba_out, width, matrix, full_range);
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p_n_444_16_to_rgb_or_rgba_row<const ALPHA: bool, const BE: bool>(
y: &[u16],
uv_full: &[u16],
out: &mut [u8],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
let bpp: usize = if ALPHA { 4 } else { 3 };
debug_assert!(y.len() >= width, "y row too short");
debug_assert!(uv_full.len() >= 2 * width, "uv_full 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>();
for x in 0..width {
let u_sample = load_u16::<BE>(uv_full[x * 2]);
let v_sample = load_u16::<BE>(uv_full[x * 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;
}
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p_n_444_16_to_rgb_u16_row<const BE: bool>(
y: &[u16],
uv_full: &[u16],
rgb_out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
p_n_444_16_to_rgb_or_rgba_u16_row::<false, BE>(y, uv_full, rgb_out, width, matrix, full_range);
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p_n_444_16_to_rgba_u16_row<const BE: bool>(
y: &[u16],
uv_full: &[u16],
rgba_out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
p_n_444_16_to_rgb_or_rgba_u16_row::<true, BE>(y, uv_full, rgba_out, width, matrix, full_range);
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn p_n_444_16_to_rgb_or_rgba_u16_row<const ALPHA: bool, const BE: bool>(
y: &[u16],
uv_full: &[u16],
out: &mut [u16],
width: usize,
matrix: ColorMatrix,
full_range: bool,
) {
let bpp: usize = if ALPHA { 4 } else { 3 };
debug_assert!(y.len() >= width, "y row too short");
debug_assert!(uv_full.len() >= 2 * width, "uv_full 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;
for x in 0..width {
let u_sample = load_u16::<BE>(uv_full[x * 2]);
let v_sample = load_u16::<BE>(uv_full[x * 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;
}
}
}