#[cfg(all(test, feature = "std"))]
use super::*;
#[cfg(all(test, feature = "std"))]
pub(super) fn solid_ayuv64_frame(
width: u32,
height: u32,
a: u16,
y: u16,
u: u16,
v: u16,
) -> Vec<u16> {
let quad = [a, y, u, v];
(0..(width as usize) * (height as usize))
.flat_map(|_| quad)
.collect()
}
#[cfg(all(test, feature = "std"))]
fn pack_yuva444p16_to_ayuv64(
y: &[u16],
u: &[u16],
v: &[u16],
a: &[u16],
width: usize,
height: usize,
) -> Vec<u16> {
let mut out = vec![0u16; width * height * 4];
for row in 0..height {
for x in 0..width {
let i = row * width + x;
let off = i * 4;
out[off] = a[i]; out[off + 1] = y[i]; out[off + 2] = u[i]; out[off + 3] = v[i]; }
}
out
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn ayuv64_with_rgb_smoke() {
let buf = solid_ayuv64_frame(4, 1, 0xFFFF, 60160, 32768, 32768);
let src = Ayuv64Frame::try_new(&buf, 4, 1, 16).unwrap();
let mut rgb = std::vec![0u8; 4 * 3];
let mut sink = MixedSinker::<Ayuv64>::new(4, 1).with_rgb(&mut rgb).unwrap();
ayuv64_to(&src, false, ColorMatrix::Bt709, &mut sink).unwrap();
for px in rgb.chunks(3) {
assert!(
px[0] >= 220,
"expected near-white (>=220), got R={}, G={}, B={}",
px[0],
px[1],
px[2],
);
assert_eq!(px[0], px[1], "R != G");
assert_eq!(px[1], px[2], "G != B");
}
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn ayuv64_with_rgba_passes_source_alpha_depth_converted() {
let buf = solid_ayuv64_frame(4, 1, 0xABCD, 32768, 32768, 32768);
let src = Ayuv64Frame::try_new(&buf, 4, 1, 16).unwrap();
let mut rgba = std::vec![0u8; 4 * 4];
let mut sink = MixedSinker::<Ayuv64>::new(4, 1)
.with_rgba(&mut rgba)
.unwrap();
ayuv64_to(&src, true, ColorMatrix::Bt709, &mut sink).unwrap();
for px in rgba.chunks(4) {
assert_eq!(
px[3], 0xABu8,
"expected alpha 0xAB (0xABCD >> 8), got {:#X}",
px[3]
);
}
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn ayuv64_with_rgb_u16_smoke() {
let buf = solid_ayuv64_frame(4, 1, 0xFFFF, 32768, 32768, 32768);
let src = Ayuv64Frame::try_new(&buf, 4, 1, 16).unwrap();
let mut rgb = std::vec![0u16; 4 * 3];
let mut sink = MixedSinker::<Ayuv64>::new(4, 1)
.with_rgb_u16(&mut rgb)
.unwrap();
ayuv64_to(&src, true, ColorMatrix::Bt709, &mut sink).unwrap();
for px in rgb.chunks(3) {
assert!(
px[0].abs_diff(32768) <= 0x200,
"expected ~32768, got {:#X}",
px[0]
);
assert_eq!(px[0], px[1], "R u16 != G u16");
assert_eq!(px[1], px[2], "G u16 != B u16");
}
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn ayuv64_with_rgba_u16_passes_source_alpha_direct() {
let buf = solid_ayuv64_frame(4, 1, 0xABCD, 32768, 32768, 32768);
let src = Ayuv64Frame::try_new(&buf, 4, 1, 16).unwrap();
let mut rgba = std::vec![0u16; 4 * 4];
let mut sink = MixedSinker::<Ayuv64>::new(4, 1)
.with_rgba_u16(&mut rgba)
.unwrap();
ayuv64_to(&src, true, ColorMatrix::Bt709, &mut sink).unwrap();
for px in rgba.chunks(4) {
assert_eq!(
px[3], 0xABCDu16,
"expected alpha 0xABCD (direct pass-through), got {:#X}",
px[3]
);
}
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn ayuv64_with_luma_extracts_y_high_byte() {
let buf = solid_ayuv64_frame(8, 2, 0xFFFF, 0xABCD, 32768, 32768);
let src = Ayuv64Frame::try_new(&buf, 8, 2, 32).unwrap();
let mut luma = std::vec![0u8; 8 * 2];
let mut sink = MixedSinker::<Ayuv64>::new(8, 2)
.with_luma(&mut luma)
.unwrap();
ayuv64_to(&src, false, ColorMatrix::Bt709, &mut sink).unwrap();
assert!(
luma.iter().all(|&y| y == 0xABu8),
"luma expected 0xAB (0xABCD >> 8), got {:?}",
&luma[..8]
);
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn ayuv64_with_luma_u16_extracts_y_native() {
let buf = solid_ayuv64_frame(8, 2, 0xFFFF, 0xABCD, 32768, 32768);
let src = Ayuv64Frame::try_new(&buf, 8, 2, 32).unwrap();
let mut luma = std::vec![0u16; 8 * 2];
let mut sink = MixedSinker::<Ayuv64>::new(8, 2)
.with_luma_u16(&mut luma)
.unwrap();
ayuv64_to(&src, false, ColorMatrix::Bt709, &mut sink).unwrap();
assert!(
luma.iter().all(|&y| y == 0xABCDu16),
"luma_u16 expected 0xABCD, got {:?}",
&luma[..8]
);
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn ayuv64_with_hsv_smoke() {
let buf = solid_ayuv64_frame(6, 2, 0xFFFF, 32768, 32768, 32768);
let src = Ayuv64Frame::try_new(&buf, 6, 2, 24).unwrap();
let n = 6 * 2;
let mut h = std::vec![0u8; n];
let mut s = std::vec![0u8; n];
let mut v = std::vec![0u8; n];
let mut sink = MixedSinker::<Ayuv64>::new(6, 2)
.with_hsv(&mut h, &mut s, &mut v)
.unwrap();
ayuv64_to(&src, true, ColorMatrix::Bt709, &mut sink).unwrap();
for &sat in &s {
assert_eq!(sat, 0, "gray must have S=0 in HSV");
}
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn ayuv64_with_rgb_and_rgba_preserves_source_alpha() {
let width = 8usize;
let height = 1usize;
let mut packed = std::vec![0u16; width * 4];
for n in 0..width {
let a_val = ((n as u16) + 1) << 8;
packed[n * 4] = a_val; packed[n * 4 + 1] = 32768; packed[n * 4 + 2] = 32768; packed[n * 4 + 3] = 32768; }
let frame =
Ayuv64Frame::try_new(&packed, width as u32, height as u32, (width * 4) as u32).unwrap();
let mut rgb = std::vec![0u8; width * height * 3];
let mut rgba = std::vec![0u8; width * height * 4];
let mut sinker = MixedSinker::<Ayuv64>::new(width, height)
.with_rgb(&mut rgb)
.unwrap()
.with_rgba(&mut rgba)
.unwrap();
ayuv64_to(&frame, true, ColorMatrix::Bt709, &mut sinker).unwrap();
for n in 0..width {
assert_eq!(
&rgb[n * 3..n * 3 + 3],
&rgba[n * 4..n * 4 + 3],
"pixel {n}: RGB and RGBA RGB-channels diverge"
);
let a_u16 = ((n as u16) + 1) << 8;
let expected_alpha = (a_u16 >> 8) as u8;
assert_eq!(
rgba[n * 4 + 3],
expected_alpha,
"pixel {n}: source alpha was discarded (got {}, expected {})",
rgba[n * 4 + 3],
expected_alpha
);
}
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn ayuv64_with_rgb_u16_and_rgba_u16_preserves_source_alpha() {
let width = 8usize;
let height = 1usize;
let mut packed = std::vec![0u16; width * 4];
for n in 0..width {
let a_val = 0x1000u16 + (n as u16 * 0x1111); packed[n * 4] = a_val; packed[n * 4 + 1] = 32768; packed[n * 4 + 2] = 32768; packed[n * 4 + 3] = 32768; }
let frame =
Ayuv64Frame::try_new(&packed, width as u32, height as u32, (width * 4) as u32).unwrap();
let mut rgb = std::vec![0u16; width * height * 3];
let mut rgba = std::vec![0u16; width * height * 4];
let mut sinker = MixedSinker::<Ayuv64>::new(width, height)
.with_rgb_u16(&mut rgb)
.unwrap()
.with_rgba_u16(&mut rgba)
.unwrap();
ayuv64_to(&frame, true, ColorMatrix::Bt709, &mut sinker).unwrap();
for n in 0..width {
assert_eq!(
&rgb[n * 3..n * 3 + 3],
&rgba[n * 4..n * 4 + 3],
"pixel {n}: RGB u16 and RGBA u16 RGB-channels diverge"
);
let expected_alpha = 0x1000u16 + (n as u16 * 0x1111);
assert_eq!(
rgba[n * 4 + 3],
expected_alpha,
"pixel {n}: source u16 alpha was not preserved (got {:#X}, expected {:#X})",
rgba[n * 4 + 3],
expected_alpha
);
}
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn ayuv64_simd_vs_scalar_parity_at_1922_u8() {
let w = 1922usize;
let h = 2usize;
let mut buf = std::vec![0u16; w * h * 4];
pseudo_random_u16_low_n_bits(&mut buf, 0xBEEF_DEAD, 16);
let src = Ayuv64Frame::try_new(&buf, w as u32, h as u32, (w * 4) as u32).unwrap();
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::<Ayuv64>::new(w, h)
.with_rgb(&mut rgb_simd)
.unwrap();
ayuv64_to(&src, false, ColorMatrix::Bt709, &mut sink_simd).unwrap();
let mut sink_scalar = MixedSinker::<Ayuv64>::new(w, h)
.with_rgb(&mut rgb_scalar)
.unwrap()
.with_simd(false);
ayuv64_to(&src, false, ColorMatrix::Bt709, &mut sink_scalar).unwrap();
assert_eq!(
rgb_simd, rgb_scalar,
"AYUV64 SIMD != scalar (u8) at width {w}"
);
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn ayuv64_simd_vs_scalar_parity_at_1922_u16() {
let w = 1922usize;
let h = 2usize;
let mut buf = std::vec![0u16; w * h * 4];
pseudo_random_u16_low_n_bits(&mut buf, 0xC0DE_FEED, 16);
let src = Ayuv64Frame::try_new(&buf, w as u32, h as u32, (w * 4) as u32).unwrap();
let mut rgb_simd = std::vec![0u16; w * h * 3];
let mut rgb_scalar = std::vec![0u16; w * h * 3];
let mut sink_simd = MixedSinker::<Ayuv64>::new(w, h)
.with_rgb_u16(&mut rgb_simd)
.unwrap();
ayuv64_to(&src, false, ColorMatrix::Bt709, &mut sink_simd).unwrap();
let mut sink_scalar = MixedSinker::<Ayuv64>::new(w, h)
.with_rgb_u16(&mut rgb_scalar)
.unwrap()
.with_simd(false);
ayuv64_to(&src, false, ColorMatrix::Bt709, &mut sink_scalar).unwrap();
assert_eq!(
rgb_simd, rgb_scalar,
"AYUV64 SIMD != scalar (u16) at width {w}"
);
}
#[test]
#[cfg(all(test, feature = "std"))]
fn ayuv64_rgb_buffer_too_short_returns_error() {
let mut rgb = std::vec![0u8; 95];
let result = MixedSinker::<Ayuv64>::new(8, 4).with_rgb(&mut rgb);
let Err(err) = result else {
panic!("expected InsufficientRgbBuffer");
};
assert_eq!(
err,
MixedSinkerError::InsufficientRgbBuffer(InsufficientBuffer::new(96, 95))
);
}
#[test]
#[cfg(all(test, feature = "std"))]
fn ayuv64_rgba_buffer_too_short_returns_error() {
let mut rgba = std::vec![0u8; 90];
let result = MixedSinker::<Ayuv64>::new(6, 4).with_rgba(&mut rgba);
let Err(err) = result else {
panic!("expected InsufficientRgbaBuffer");
};
assert_eq!(
err,
MixedSinkerError::InsufficientRgbaBuffer(InsufficientBuffer::new(96, 90))
);
}
#[test]
#[cfg(all(test, feature = "std"))]
fn ayuv64_rgb_u16_buffer_too_short_returns_error() {
let mut rgb = std::vec![0u16; 90];
let result = MixedSinker::<Ayuv64>::new(8, 4).with_rgb_u16(&mut rgb);
let Err(err) = result else {
panic!("expected InsufficientRgbU16Buffer");
};
assert_eq!(
err,
MixedSinkerError::InsufficientRgbU16Buffer(InsufficientBuffer::new(96, 90))
);
}
#[test]
#[cfg(all(test, feature = "std"))]
fn ayuv64_rgba_u16_buffer_too_short_returns_error() {
let mut rgba = std::vec![0u16; 88];
let result = MixedSinker::<Ayuv64>::new(6, 4).with_rgba_u16(&mut rgba);
let Err(err) = result else {
panic!("expected InsufficientRgbaU16Buffer");
};
assert_eq!(
err,
MixedSinkerError::InsufficientRgbaU16Buffer(InsufficientBuffer::new(96, 88))
);
}
#[test]
#[cfg(all(test, feature = "std"))]
fn ayuv64_luma_buffer_too_short_returns_error() {
let mut luma = std::vec![0u8; 20];
let result = MixedSinker::<Ayuv64>::new(8, 3).with_luma(&mut luma);
let Err(err) = result else {
panic!("expected InsufficientLumaBuffer");
};
assert_eq!(
err,
MixedSinkerError::InsufficientLumaBuffer(InsufficientBuffer::new(24, 20))
);
}
#[test]
#[cfg(all(test, feature = "std"))]
fn ayuv64_luma_u16_buffer_too_short_returns_error() {
let mut luma = std::vec![0u16; 20];
let result = MixedSinker::<Ayuv64>::new(8, 3).with_luma_u16(&mut luma);
let Err(err) = result else {
panic!("expected InsufficientLumaU16Buffer");
};
assert_eq!(
err,
MixedSinkerError::InsufficientLumaU16Buffer(InsufficientBuffer::new(24, 20))
);
}
#[test]
#[cfg(all(test, feature = "std"))]
fn ayuv64_hsv_buffer_too_short_returns_error() {
let mut h = std::vec![0u8; 15];
let mut s = std::vec![0u8; 16];
let mut v = std::vec![0u8; 16];
let result = MixedSinker::<Ayuv64>::new(4, 4).with_hsv(&mut h, &mut s, &mut v);
let Err(err) = result else {
panic!("expected InsufficientHsvPlane");
};
assert!(matches!(
&err,
MixedSinkerError::InsufficientHsvPlane(e)
if matches!(e.which(), HsvPlane::H) && e.expected() == 16 && e.actual() == 15
));
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn ayuv64_planar_parity_with_yuva444p16() {
let width = 64usize;
let height = 4usize;
let n = width * height;
let mut yp = std::vec![0u16; n];
let mut up = std::vec![0u16; n];
let mut vp = std::vec![0u16; n];
let mut ap = std::vec![0u16; n];
pseudo_random_u16_low_n_bits(&mut yp, 0xC0FFEE_u32, 16);
pseudo_random_u16_low_n_bits(&mut up, 0xBADF00D_u32, 16);
pseudo_random_u16_low_n_bits(&mut vp, 0xFEEDFACE_u32, 16);
pseudo_random_u16_low_n_bits(&mut ap, 0xA1FA5EED_u32, 16);
let planar = Yuva444p16Frame::try_new(
&yp,
&up,
&vp,
&ap,
width as u32,
height as u32,
width as u32,
width as u32,
width as u32,
width as u32,
)
.unwrap();
let ayuv64_buf = pack_yuva444p16_to_ayuv64(&yp, &up, &vp, &ap, width, height);
let packed_frame =
Ayuv64Frame::try_new(&ayuv64_buf, width as u32, height as u32, (width * 4) as u32).unwrap();
let full_range = false;
let mut p_rgb = std::vec![0u8; n * 3];
let mut a_rgb = std::vec![0u8; n * 3];
let mut p_sink = MixedSinker::<Yuva444p16>::new(width, height)
.with_rgb(&mut p_rgb)
.unwrap();
yuva444p16_to(&planar, full_range, ColorMatrix::Bt709, &mut p_sink).unwrap();
let mut a_sink = MixedSinker::<Ayuv64>::new(width, height)
.with_rgb(&mut a_rgb)
.unwrap();
ayuv64_to(&packed_frame, full_range, ColorMatrix::Bt709, &mut a_sink).unwrap();
assert_eq!(
p_rgb, a_rgb,
"AYUV64 <-> Yuva444p16 u8 RGB diverges at limited range"
);
let mut p_rgba = std::vec![0u8; n * 4];
let mut a_rgba = std::vec![0u8; n * 4];
let mut p_sink2 = MixedSinker::<Yuva444p16>::new(width, height)
.with_rgba(&mut p_rgba)
.unwrap();
yuva444p16_to(&planar, full_range, ColorMatrix::Bt709, &mut p_sink2).unwrap();
let mut a_sink2 = MixedSinker::<Ayuv64>::new(width, height)
.with_rgba(&mut a_rgba)
.unwrap();
ayuv64_to(&packed_frame, full_range, ColorMatrix::Bt709, &mut a_sink2).unwrap();
assert_eq!(
p_rgba, a_rgba,
"AYUV64 <-> Yuva444p16 u8 RGBA diverges at limited range (source-alpha path)"
);
for (i, &src_a) in ap.iter().enumerate() {
let expected_alpha = (src_a >> 8) as u8;
let ayuv64_alpha = a_rgba[i * 4 + 3];
assert_eq!(
ayuv64_alpha, expected_alpha,
"AYUV64 u8 RGBA alpha at pixel {i}: expected {expected_alpha:#X} (src {src_a:#X} >> 8), got {ayuv64_alpha:#X}"
);
}
let mut p_rgb_u16 = std::vec![0u16; n * 3];
let mut a_rgb_u16 = std::vec![0u16; n * 3];
let mut p_sink3 = MixedSinker::<Yuva444p16>::new(width, height)
.with_rgb_u16(&mut p_rgb_u16)
.unwrap();
yuva444p16_to(&planar, full_range, ColorMatrix::Bt709, &mut p_sink3).unwrap();
let mut a_sink3 = MixedSinker::<Ayuv64>::new(width, height)
.with_rgb_u16(&mut a_rgb_u16)
.unwrap();
ayuv64_to(&packed_frame, full_range, ColorMatrix::Bt709, &mut a_sink3).unwrap();
assert_eq!(
p_rgb_u16, a_rgb_u16,
"AYUV64 <-> Yuva444p16 u16 RGB diverges at limited range"
);
let mut p_rgba_u16 = std::vec![0u16; n * 4];
let mut a_rgba_u16 = std::vec![0u16; n * 4];
let mut p_sink4 = MixedSinker::<Yuva444p16>::new(width, height)
.with_rgba_u16(&mut p_rgba_u16)
.unwrap();
yuva444p16_to(&planar, full_range, ColorMatrix::Bt709, &mut p_sink4).unwrap();
let mut a_sink4 = MixedSinker::<Ayuv64>::new(width, height)
.with_rgba_u16(&mut a_rgba_u16)
.unwrap();
ayuv64_to(&packed_frame, full_range, ColorMatrix::Bt709, &mut a_sink4).unwrap();
assert_eq!(
p_rgba_u16, a_rgba_u16,
"AYUV64 <-> Yuva444p16 u16 RGBA diverges at limited range (headline u16 parity)"
);
for (i, &src_a) in ap.iter().enumerate() {
let ayuv64_alpha = a_rgba_u16[i * 4 + 3];
assert_eq!(
ayuv64_alpha, src_a,
"AYUV64 u16 RGBA alpha at pixel {i}: expected {src_a:#X}, got {ayuv64_alpha:#X}"
);
}
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn ayuv64_strategy_a_plus_matches_independent_kernel() {
let width = 128usize;
let height = 4usize;
let mut packed = std::vec![0u16; width * height * 4];
pseudo_random_u16_low_n_bits(&mut packed, 0xC0FFEE, 16);
let frame =
Ayuv64Frame::try_new(&packed, width as u32, height as u32, (width * 4) as u32).unwrap();
for full_range in [true, false] {
for matrix in [
ColorMatrix::Bt601,
ColorMatrix::Bt709,
ColorMatrix::Bt2020Ncl,
ColorMatrix::Smpte240m,
ColorMatrix::Fcc,
ColorMatrix::YCgCo,
] {
let mut sinker_rgb = std::vec![0u8; width * height * 3];
let mut sinker_rgba = std::vec![0u8; width * height * 4];
{
let mut sink = MixedSinker::<Ayuv64>::new(width, height)
.with_rgb(&mut sinker_rgb)
.unwrap()
.with_rgba(&mut sinker_rgba)
.unwrap();
ayuv64_to(&frame, full_range, matrix, &mut sink).unwrap();
}
let mut inline_rgb = std::vec![0u8; width * height * 3];
let mut inline_rgba = std::vec![0u8; width * height * 4];
for r in 0..height {
let row_off_packed = r * width * 4;
let row_off_rgb = r * width * 3;
let row_off_rgba = r * width * 4;
crate::row::scalar::ayuv64_to_rgb_row::<false>(
&packed[row_off_packed..row_off_packed + width * 4],
&mut inline_rgb[row_off_rgb..row_off_rgb + width * 3],
width,
matrix,
full_range,
);
crate::row::scalar::ayuv64_to_rgba_row::<false>(
&packed[row_off_packed..row_off_packed + width * 4],
&mut inline_rgba[row_off_rgba..row_off_rgba + width * 4],
width,
matrix,
full_range,
);
}
assert_eq!(
sinker_rgb, inline_rgb,
"AYUV64 A+ u8 RGB diverges (range={full_range}, matrix={matrix:?})"
);
assert_eq!(
sinker_rgba, inline_rgba,
"AYUV64 A+ u8 RGBA diverges from scalar inline-α (range={full_range}, matrix={matrix:?})"
);
}
}
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn ayuv64_strategy_a_plus_u16_matches_independent_kernel() {
let width = 128usize;
let height = 4usize;
let mut packed = std::vec![0u16; width * height * 4];
pseudo_random_u16_low_n_bits(&mut packed, 0xDEADBEEF, 16);
let frame =
Ayuv64Frame::try_new(&packed, width as u32, height as u32, (width * 4) as u32).unwrap();
for full_range in [true, false] {
for matrix in [
ColorMatrix::Bt601,
ColorMatrix::Bt709,
ColorMatrix::Bt2020Ncl,
ColorMatrix::Smpte240m,
ColorMatrix::Fcc,
ColorMatrix::YCgCo,
] {
let mut sinker_rgb = std::vec![0u16; width * height * 3];
let mut sinker_rgba = std::vec![0u16; width * height * 4];
{
let mut sink = MixedSinker::<Ayuv64>::new(width, height)
.with_rgb_u16(&mut sinker_rgb)
.unwrap()
.with_rgba_u16(&mut sinker_rgba)
.unwrap();
ayuv64_to(&frame, full_range, matrix, &mut sink).unwrap();
}
let mut inline_rgb = std::vec![0u16; width * height * 3];
let mut inline_rgba = std::vec![0u16; width * height * 4];
for r in 0..height {
let row_off_packed = r * width * 4;
let row_off_rgb = r * width * 3;
let row_off_rgba = r * width * 4;
crate::row::scalar::ayuv64_to_rgb_u16_row::<false>(
&packed[row_off_packed..row_off_packed + width * 4],
&mut inline_rgb[row_off_rgb..row_off_rgb + width * 3],
width,
matrix,
full_range,
);
crate::row::scalar::ayuv64_to_rgba_u16_row::<false>(
&packed[row_off_packed..row_off_packed + width * 4],
&mut inline_rgba[row_off_rgba..row_off_rgba + width * 4],
width,
matrix,
full_range,
);
}
assert_eq!(
sinker_rgb, inline_rgb,
"AYUV64 A+ u16 RGB diverges (range={full_range}, matrix={matrix:?})"
);
assert_eq!(
sinker_rgba, inline_rgba,
"AYUV64 A+ u16 RGBA diverges from inline-α (range={full_range}, matrix={matrix:?})"
);
}
}
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn ayuv64_le_be_roundtrip_byte_identical() {
let logical: std::vec::Vec<u16> = (0..8 * 4 * 4)
.map(|i| match i % 4 {
0 => 0xABCDu16, 1 => 0x8000u16, 2 => 0x4000u16, _ => 0xC000u16, })
.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 = Ayuv64LeFrame::try_new(&pix_le, 8, 4, 8 * 4).unwrap();
let mut out_le_rgba = std::vec![0u8; 8 * 4 * 4];
let mut sink_le = MixedSinker::<Ayuv64>::new(8, 4)
.with_simd(false)
.with_rgba(&mut out_le_rgba)
.unwrap();
ayuv64_to(&frame_le, true, ColorMatrix::Bt709, &mut sink_le).unwrap();
let frame_be = Ayuv64BeFrame::try_new(&pix_be, 8, 4, 8 * 4).unwrap();
let mut out_be_rgba = std::vec![0u8; 8 * 4 * 4];
let mut sink_be = MixedSinker::<Ayuv64<true>>::new(8, 4)
.with_simd(false)
.with_rgba(&mut out_be_rgba)
.unwrap();
ayuv64_to_endian(&frame_be, true, ColorMatrix::Bt709, &mut sink_be).unwrap();
assert_eq!(
out_le_rgba, out_be_rgba,
"AYUV64 RGBA u8 LE/BE outputs diverge — `<const BE>` propagation broken"
);
let mut out_le_rgba_u16 = std::vec![0u16; 8 * 4 * 4];
let mut sink_le_u16 = MixedSinker::<Ayuv64>::new(8, 4)
.with_simd(false)
.with_rgba_u16(&mut out_le_rgba_u16)
.unwrap();
ayuv64_to(&frame_le, true, ColorMatrix::Bt709, &mut sink_le_u16).unwrap();
let mut out_be_rgba_u16 = std::vec![0u16; 8 * 4 * 4];
let mut sink_be_u16 = MixedSinker::<Ayuv64<true>>::new(8, 4)
.with_simd(false)
.with_rgba_u16(&mut out_be_rgba_u16)
.unwrap();
ayuv64_to_endian(&frame_be, true, ColorMatrix::Bt709, &mut sink_be_u16).unwrap();
assert_eq!(
out_le_rgba_u16, out_be_rgba_u16,
"AYUV64 RGBA u16 LE/BE outputs diverge — `<const BE>` propagation broken"
);
}
#[test]
#[cfg(all(test, feature = "std"))]
#[cfg_attr(
miri,
ignore = "SIMD-dispatched row kernels use intrinsics unsupported by Miri"
)]
fn ayuv64_le_be_roundtrip_strategy_a_plus_byte_identical() {
let logical: std::vec::Vec<u16> = (0..8 * 4 * 4)
.map(|i| match i % 4 {
0 => 0x55AAu16, 1 => 0x8000u16, 2 => 0x4000u16, _ => 0xC000u16, })
.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 = Ayuv64LeFrame::try_new(&pix_le, 8, 4, 8 * 4).unwrap();
let mut out_le_rgb = std::vec![0u8; 8 * 4 * 3];
let mut out_le_rgba = std::vec![0u8; 8 * 4 * 4];
let mut out_le_rgb_u16 = std::vec![0u16; 8 * 4 * 3];
let mut out_le_rgba_u16 = std::vec![0u16; 8 * 4 * 4];
let mut sink_le = MixedSinker::<Ayuv64>::new(8, 4)
.with_simd(false)
.with_rgb(&mut out_le_rgb)
.unwrap()
.with_rgba(&mut out_le_rgba)
.unwrap()
.with_rgb_u16(&mut out_le_rgb_u16)
.unwrap()
.with_rgba_u16(&mut out_le_rgba_u16)
.unwrap();
ayuv64_to(&frame_le, true, ColorMatrix::Bt709, &mut sink_le).unwrap();
let frame_be = Ayuv64BeFrame::try_new(&pix_be, 8, 4, 8 * 4).unwrap();
let mut out_be_rgb = std::vec![0u8; 8 * 4 * 3];
let mut out_be_rgba = std::vec![0u8; 8 * 4 * 4];
let mut out_be_rgb_u16 = std::vec![0u16; 8 * 4 * 3];
let mut out_be_rgba_u16 = std::vec![0u16; 8 * 4 * 4];
let mut sink_be = MixedSinker::<Ayuv64<true>>::new(8, 4)
.with_simd(false)
.with_rgb(&mut out_be_rgb)
.unwrap()
.with_rgba(&mut out_be_rgba)
.unwrap()
.with_rgb_u16(&mut out_be_rgb_u16)
.unwrap()
.with_rgba_u16(&mut out_be_rgba_u16)
.unwrap();
ayuv64_to_endian(&frame_be, true, ColorMatrix::Bt709, &mut sink_be).unwrap();
assert_eq!(out_le_rgb, out_be_rgb, "AYUV64 A+ RGB u8 LE/BE diverge");
assert_eq!(out_le_rgba, out_be_rgba, "AYUV64 A+ RGBA u8 LE/BE diverge");
assert_eq!(
out_le_rgb_u16, out_be_rgb_u16,
"AYUV64 A+ RGB u16 LE/BE diverge"
);
assert_eq!(
out_le_rgba_u16, out_be_rgba_u16,
"AYUV64 A+ RGBA u16 LE/BE diverge"
);
}