#[cfg(all(test, feature = "std"))]
use super::*;
#[cfg(all(test, feature = "std"))]
pub(super) fn solid_xv36_frame(
width: u32,
height: u32,
u: u16,
y: u16,
v: u16,
a: u16,
) -> Vec<u16> {
debug_assert!(u <= 0xFFF && y <= 0xFFF && v <= 0xFFF && a <= 0xFFF);
let quad = [u << 4, y << 4, v << 4, a << 4];
(0..(width as usize) * (height as usize))
.flat_map(|_| quad)
.collect()
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn xv36_rgb_only_converts_gray_to_gray() {
let buf = solid_xv36_frame(12, 4, 0x800, 0x800, 0x800, 0);
let src = Xv36Frame::new(&buf, 12, 4, 48);
let mut rgb = std::vec![0u8; 12 * 4 * 3];
let mut sink = MixedSinker::<Xv36>::new(12, 4).with_rgb(&mut rgb).unwrap();
xv36_to(&src, true, ColorMatrix::Bt601, &mut sink).unwrap();
for px in rgb.chunks(3) {
assert!(px[0].abs_diff(128) <= 4, "expected ~128, got {}", px[0]);
assert_eq!(px[0], px[1]);
assert_eq!(px[1], px[2]);
}
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn xv36_rgba_only_converts_gray_to_gray_with_opaque_alpha() {
let buf = solid_xv36_frame(12, 4, 0x800, 0x800, 0x800, 0);
let src = Xv36Frame::new(&buf, 12, 4, 48);
let mut rgba = std::vec![0u8; 12 * 4 * 4];
let mut sink = MixedSinker::<Xv36>::new(12, 4)
.with_rgba(&mut rgba)
.unwrap();
xv36_to(&src, true, ColorMatrix::Bt601, &mut sink).unwrap();
for px in rgba.chunks(4) {
assert_eq!(px[3], 0xFF, "alpha must be 0xFF for XV36");
}
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn xv36_rgb_u16_only_converts_gray_to_gray_native_depth() {
let buf = solid_xv36_frame(12, 4, 0x800, 0x800, 0x800, 0);
let src = Xv36Frame::new(&buf, 12, 4, 48);
let mut rgb = std::vec![0u16; 12 * 4 * 3];
let mut sink = MixedSinker::<Xv36>::new(12, 4)
.with_rgb_u16(&mut rgb)
.unwrap();
xv36_to(&src, true, ColorMatrix::Bt601, &mut sink).unwrap();
for px in rgb.chunks(3) {
assert!(
px[0].abs_diff(0x800) <= 0x10,
"expected ~0x800, got {:#X}",
px[0]
);
}
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn xv36_rgba_u16_alpha_is_max() {
let buf = solid_xv36_frame(12, 4, 0x800, 0x800, 0x800, 0);
let src = Xv36Frame::new(&buf, 12, 4, 48);
let mut rgba = std::vec![0u16; 12 * 4 * 4];
let mut sink = MixedSinker::<Xv36>::new(12, 4)
.with_rgba_u16(&mut rgba)
.unwrap();
xv36_to(&src, true, ColorMatrix::Bt601, &mut sink).unwrap();
for px in rgba.chunks(4) {
assert_eq!(px[3], 0x0FFF, "u16 alpha must be 0x0FFF for XV36");
}
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn xv36_luma_only_extracts_y_bytes_downshifted() {
let buf = solid_xv36_frame(6, 8, 0x800, 0xF00, 0x800, 0);
let src = Xv36Frame::new(&buf, 6, 8, 24);
let mut luma = std::vec![0u8; 6 * 8];
let mut sink = MixedSinker::<Xv36>::new(6, 8).with_luma(&mut luma).unwrap();
xv36_to(&src, true, ColorMatrix::Bt601, &mut sink).unwrap();
assert!(luma.iter().all(|&y| y == 0xF0), "luma {luma:?}");
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn xv36_luma_u16_only_extracts_y_native_depth() {
let buf = solid_xv36_frame(6, 8, 0x800, 0xABC, 0x800, 0);
let src = Xv36Frame::new(&buf, 6, 8, 24);
let mut luma = std::vec![0u16; 6 * 8];
let mut sink = MixedSinker::<Xv36>::new(6, 8)
.with_luma_u16(&mut luma)
.unwrap();
xv36_to(&src, true, ColorMatrix::Bt601, &mut sink).unwrap();
assert!(
luma.iter().all(|&y| y == 0xABC),
"luma_u16 expected 0xABC, got {:?}",
&luma[..8]
);
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn xv36_with_rgb_and_with_rgba_byte_identical_u8() {
let w = 12u32;
let h = 4u32;
let buf = solid_xv36_frame(w, h, 0x300, 0x700, 0x500, 0);
let src = Xv36Frame::new(&buf, w, h, w * 4);
let mut rgb = std::vec![0u8; (w * h) as usize * 3];
let mut rgba = std::vec![0u8; (w * h) as usize * 4];
let mut sink = MixedSinker::<Xv36>::new(w as usize, h as usize)
.with_rgb(&mut rgb)
.unwrap()
.with_rgba(&mut rgba)
.unwrap();
xv36_to(&src, true, ColorMatrix::Bt601, &mut sink).unwrap();
for i in 0..(w * h) as usize {
assert_eq!(rgba[i * 4], rgb[i * 3], "R mismatch at pixel {i}");
assert_eq!(rgba[i * 4 + 1], rgb[i * 3 + 1], "G mismatch at pixel {i}");
assert_eq!(rgba[i * 4 + 2], rgb[i * 3 + 2], "B mismatch at pixel {i}");
assert_eq!(rgba[i * 4 + 3], 0xFF, "alpha must be 0xFF at pixel {i}");
}
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn xv36_with_rgb_u16_and_with_rgba_u16_byte_identical() {
let w = 12u32;
let h = 4u32;
let buf = solid_xv36_frame(w, h, 0x300, 0x700, 0x500, 0);
let src = Xv36Frame::new(&buf, w, h, w * 4);
let mut rgb = std::vec![0u16; (w * h) as usize * 3];
let mut rgba = std::vec![0u16; (w * h) as usize * 4];
let mut sink = MixedSinker::<Xv36>::new(w as usize, h as usize)
.with_rgb_u16(&mut rgb)
.unwrap()
.with_rgba_u16(&mut rgba)
.unwrap();
xv36_to(&src, true, ColorMatrix::Bt601, &mut sink).unwrap();
for i in 0..(w * h) as usize {
assert_eq!(rgba[i * 4], rgb[i * 3], "R u16 mismatch at pixel {i}");
assert_eq!(
rgba[i * 4 + 1],
rgb[i * 3 + 1],
"G u16 mismatch at pixel {i}"
);
assert_eq!(
rgba[i * 4 + 2],
rgb[i * 3 + 2],
"B u16 mismatch at pixel {i}"
);
assert_eq!(rgba[i * 4 + 3], 0x0FFF, "alpha must be 0x0FFF at pixel {i}");
}
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn xv36_with_simd_false_matches_with_simd_true() {
for w in [1usize, 2, 4, 7, 8, 15, 16, 17, 31, 32, 33, 1920, 1922] {
let h = 2usize;
let mut buf = std::vec![0u16; w * h * 4];
let mut state = 0xC0FFEE_u32;
for slot in &mut buf {
state = state.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
let val = ((state >> 4) as u16) & 0xFFF0; *slot = val;
}
let src = Xv36Frame::new(&buf, w as u32, h as u32, (w * 4) as u32);
let mut rgb_simd = std::vec![0u8; w * h * 3];
let mut rgb_scalar = std::vec![0u8; w * h * 3];
let mut sink_simd = MixedSinker::<Xv36>::new(w, h)
.with_rgb(&mut rgb_simd)
.unwrap();
let mut sink_scalar = MixedSinker::<Xv36>::new(w, h)
.with_rgb(&mut rgb_scalar)
.unwrap()
.with_simd(false);
xv36_to(&src, false, ColorMatrix::Bt709, &mut sink_simd).unwrap();
xv36_to(&src, false, ColorMatrix::Bt709, &mut sink_scalar).unwrap();
assert_eq!(rgb_simd, rgb_scalar, "XV36 SIMD≠scalar at width {w}");
}
}
fn pack_yuv444p12_to_xv36(
y_plane: &[u16],
u_plane: &[u16],
v_plane: &[u16],
width: usize,
height: usize,
) -> Vec<u16> {
let mut packed = Vec::with_capacity(width * 4 * height);
for r in 0..height {
for c in 0..width {
let y = (y_plane[r * width + c] & 0x0FFF) << 4;
let u = (u_plane[r * width + c] & 0x0FFF) << 4;
let v = (v_plane[r * width + c] & 0x0FFF) << 4;
packed.push(u);
packed.push(y);
packed.push(v);
packed.push(0); }
}
packed
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn xv36_planar_parity_with_yuv444p12() {
let width = 16usize;
let height = 4usize;
let mut yp = std::vec![0u16; width * height];
let mut up = std::vec![0u16; width * height];
let mut vp = std::vec![0u16; width * height];
pseudo_random_u16_low_n_bits(&mut yp, 0xC0FFEE, 12);
pseudo_random_u16_low_n_bits(&mut up, 0xBADF00D, 12);
pseudo_random_u16_low_n_bits(&mut vp, 0xFEEDFACE, 12);
let planar = Yuv444p12Frame::new(
&yp,
&up,
&vp,
width as u32,
height as u32,
width as u32,
width as u32,
width as u32,
);
let packed = pack_yuv444p12_to_xv36(&yp, &up, &vp, width, height);
let xv36 = Xv36Frame::new(&packed, width as u32, height as u32, (width * 4) as u32);
let mut p_rgb = std::vec![0u8; width * height * 3];
let mut x_rgb = std::vec![0u8; width * height * 3];
let mut p_sink = MixedSinker::<Yuv444p12>::new(width, height)
.with_rgb(&mut p_rgb)
.unwrap();
let mut x_sink = MixedSinker::<Xv36>::new(width, height)
.with_rgb(&mut x_rgb)
.unwrap();
yuv444p12_to(&planar, false, ColorMatrix::Bt709, &mut p_sink).unwrap();
xv36_to(&xv36, false, ColorMatrix::Bt709, &mut x_sink).unwrap();
assert_eq!(p_rgb, x_rgb, "XV36 ↔ Yuv444p12 u8 RGB diverges");
let mut p_rgb_u16 = std::vec![0u16; width * height * 3];
let mut x_rgb_u16 = std::vec![0u16; width * height * 3];
let mut p_sink2 = MixedSinker::<Yuv444p12>::new(width, height)
.with_rgb_u16(&mut p_rgb_u16)
.unwrap();
let mut x_sink2 = MixedSinker::<Xv36>::new(width, height)
.with_rgb_u16(&mut x_rgb_u16)
.unwrap();
yuv444p12_to(&planar, false, ColorMatrix::Bt709, &mut p_sink2).unwrap();
xv36_to(&xv36, false, ColorMatrix::Bt709, &mut x_sink2).unwrap();
assert_eq!(p_rgb_u16, x_rgb_u16, "XV36 ↔ Yuv444p12 u16 RGB diverges");
}
#[test]
#[cfg(all(test, feature = "std"))]
fn xv36_buffer_too_short_for_rgba_u16_returns_err() {
let mut rgba = std::vec![0u16; 6 * 7 * 4];
let result = MixedSinker::<Xv36>::new(6, 8).with_rgba_u16(&mut rgba);
let Err(err) = result else {
panic!("expected InsufficientRgbaU16Buffer");
};
assert_eq!(
err,
MixedSinkerError::InsufficientRgbaU16Buffer(InsufficientBuffer::new(192, 168))
);
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn xv36_le_be_roundtrip_byte_identical() {
let logical: std::vec::Vec<u16> = (0..8 * 4 * 4)
.map(|i| match i % 4 {
0 => 0x0800u16, 1 => 0x4000u16, 2 => 0xA000u16, _ => 0x0000u16, })
.collect();
let pix_le: std::vec::Vec<u16> = logical.iter().map(|&v| as_le_u16(v)).collect();
let pix_be: std::vec::Vec<u16> = logical.iter().map(|&v| as_be_u16(v)).collect();
let frame_le = Xv36LeFrame::try_new(&pix_le, 8, 4, 8 * 4).unwrap();
let mut out_le = std::vec![0u8; 8 * 4 * 4];
let mut sink_le = MixedSinker::<Xv36>::new(8, 4)
.with_simd(false)
.with_rgba(&mut out_le)
.unwrap();
xv36_to(&frame_le, true, ColorMatrix::Bt709, &mut sink_le).unwrap();
let frame_be = Xv36BeFrame::try_new(&pix_be, 8, 4, 8 * 4).unwrap();
let mut out_be = std::vec![0u8; 8 * 4 * 4];
let mut sink_be = MixedSinker::<Xv36<true>>::new(8, 4)
.with_simd(false)
.with_rgba(&mut out_be)
.unwrap();
xv36_to_endian(&frame_be, true, ColorMatrix::Bt709, &mut sink_be).unwrap();
assert_eq!(
out_le, out_be,
"Xv36 LE/BE outputs diverge — `<const BE>` propagation broken"
);
}