use std::cell::RefCell;
use std::sync::OnceLock;
#[rustfmt::skip]
pub(crate) static DCT32_FWD_KERNEL: [i8; 1024] = [
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
90, 90, 88, 85, 82, 78, 73, 67, 61, 54, 47, 39, 30, 22, 13, 4, -4, -13, -22, -30, -39, -47, -54, -61, -67, -73, -78, -82, -85, -88, -90, -90,
90, 87, 80, 70, 57, 43, 26, 9, -9, -26, -43, -57, -70, -80, -87, -90, -90, -87, -80, -70, -57, -43, -26, -9, 9, 26, 43, 57, 70, 80, 87, 90,
90, 82, 67, 47, 22, -4, -30, -54, -73, -85, -90, -88, -78, -61, -39, -13, 13, 39, 61, 78, 88, 90, 85, 73, 54, 30, 4, -22, -47, -67, -82, -90,
89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89, 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89,
88, 67, 30, -13, -54, -82, -90, -78, -47, -4, 39, 73, 90, 85, 61, 22, -22, -61, -85, -90, -73, -39, 4, 47, 78, 90, 82, 54, 13, -30, -67, -88,
87, 57, 9, -43, -80, -90, -70, -26, 26, 70, 90, 80, 43, -9, -57, -87, -87, -57, -9, 43, 80, 90, 70, 26, -26, -70, -90, -80, -43, 9, 57, 87,
85, 47, -13, -67, -90, -73, -22, 39, 82, 88, 54, -4, -61, -90, -78, -30, 30, 78, 90, 61, 4, -54, -88, -82, -39, 22, 73, 90, 67, 13, -47, -85,
83, 35, -35, -83, -83, -35, 35, 83, 83, 35, -35, -83, -83, -35, 35, 83, 83, 35, -35, -83, -83, -35, 35, 83, 83, 35, -35, -83, -83, -35, 35, 83,
82, 22, -54, -90, -61, 13, 78, 85, 30, -47, -90, -67, 4, 73, 88, 39, -39, -88, -73, -4, 67, 90, 47, -30, -85, -78, -13, 61, 90, 54, -22, -82,
80, 9, -70, -87, -26, 57, 90, 43, -43, -90, -57, 26, 87, 70, -9, -80, -80, -9, 70, 87, 26, -57, -90, -43, 43, 90, 57, -26, -87, -70, 9, 80,
78, -4, -82, -73, 13, 85, 67, -22, -88, -61, 30, 90, 54, -39, -90, -47, 47, 90, 39, -54, -90, -30, 61, 88, 22, -67, -85, -13, 73, 82, 4, -78,
75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75, 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75,
73, -30, -90, -22, 78, 67, -39, -90, -13, 82, 61, -47, -88, -4, 85, 54, -54, -85, 4, 88, 47, -61, -82, 13, 90, 39, -67, -78, 22, 90, 30, -73,
70, -43, -87, 9, 90, 26, -80, -57, 57, 80, -26, -90, -9, 87, 43, -70, -70, 43, 87, -9, -90, -26, 80, 57, -57, -80, 26, 90, 9, -87, -43, 70,
67, -54, -78, 39, 85, -22, -90, 4, 90, 13, -88, -30, 82, 47, -73, -61, 61, 73, -47, -82, 30, 88, -13, -90, -4, 90, 22, -85, -39, 78, 54, -67,
64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64,
61, -73, -47, 82, 30, -88, -13, 90, -4, -90, 22, 85, -39, -78, 54, 67, -67, -54, 78, 39, -85, -22, 90, 4, -90, 13, 88, -30, -82, 47, 73, -61,
57, -80, -26, 90, -9, -87, 43, 70, -70, -43, 87, 9, -90, 26, 80, -57, -57, 80, 26, -90, 9, 87, -43, -70, 70, 43, -87, -9, 90, -26, -80, 57,
54, -85, -4, 88, -47, -61, 82, 13, -90, 39, 67, -78, -22, 90, -30, -73, 73, 30, -90, 22, 78, -67, -39, 90, -13, -82, 61, 47, -88, 4, 85, -54,
50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50, 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50,
47, -90, 39, 54, -90, 30, 61, -88, 22, 67, -85, 13, 73, -82, 4, 78, -78, -4, 82, -73, -13, 85, -67, -22, 88, -61, -30, 90, -54, -39, 90, -47,
43, -90, 57, 26, -87, 70, 9, -80, 80, -9, -70, 87, -26, -57, 90, -43, -43, 90, -57, -26, 87, -70, -9, 80, -80, 9, 70, -87, 26, 57, -90, 43,
39, -88, 73, -4, -67, 90, -47, -30, 85, -78, 13, 61, -90, 54, 22, -82, 82, -22, -54, 90, -61, -13, 78, -85, 30, 47, -90, 67, 4, -73, 88, -39,
35, -83, 83, -35, -35, 83, -83, 35, 35, -83, 83, -35, -35, 83, -83, 35, 35, -83, 83, -35, -35, 83, -83, 35, 35, -83, 83, -35, -35, 83, -83, 35,
30, -78, 90, -61, 4, 54, -88, 82, -39, -22, 73, -90, 67, -13, -47, 85, -85, 47, 13, -67, 90, -73, 22, 39, -82, 88, -54, -4, 61, -90, 78, -30,
26, -70, 90, -80, 43, 9, -57, 87, -87, 57, -9, -43, 80, -90, 70, -26, -26, 70, -90, 80, -43, -9, 57, -87, 87, -57, 9, 43, -80, 90, -70, 26,
22, -61, 85, -90, 73, -39, -4, 47, -78, 90, -82, 54, -13, -30, 67, -88, 88, -67, 30, 13, -54, 82, -90, 78, -47, 4, 39, -73, 90, -85, 61, -22,
18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18, 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18,
13, -39, 61, -78, 88, -90, 85, -73, 54, -30, 4, 22, -47, 67, -82, 90, -90, 82, -67, 47, -22, -4, 30, -54, 73, -85, 90, -88, 78, -61, 39, -13,
9, -26, 43, -57, 70, -80, 87, -90, 90, -87, 80, -70, 57, -43, 26, -9, -9, 26, -43, 57, -70, 80, -87, 90, -90, 87, -80, 70, -57, 43, -26, 9,
4, -13, 22, -30, 39, -47, 54, -61, 67, -73, 78, -82, 85, -88, 90, -90, 90, -90, 88, -85, 82, -78, 73, -67, 61, -54, 47, -39, 30, -22, 13, -4,
];
fn fdct32_1d(src: &[i32], dst: &mut [i32], shift: i32, line: usize) {
debug_assert!(shift > 0);
let add = 1 << (shift - 1);
let m = |k: usize, col: usize| DCT32_FWD_KERNEL[k * 32 + col] as i32;
for j in 0..line {
let col = |k: usize| src[k * line + j];
let mut a = [0i32; 16];
let mut b = [0i32; 16];
for k in 0..16 {
a[k] = col(k) + col(31 - k);
b[k] = col(k) - col(31 - k);
}
let mut c = [0i32; 8];
let mut d = [0i32; 8];
for k in 0..8 {
c[k] = a[k] + a[15 - k];
d[k] = a[k] - a[15 - k];
}
let mut e = [0i32; 4];
let mut f = [0i32; 4];
for k in 0..4 {
e[k] = c[k] + c[7 - k];
f[k] = c[k] - c[7 - k];
}
let g = [e[0] + e[3], e[1] + e[2]];
let h = [e[0] - e[3], e[1] - e[2]];
let o = &mut dst[j * 32..j * 32 + 32];
o[0] = (m(0, 0) * g[0] + m(0, 1) * g[1] + add) >> shift;
o[16] = (m(16, 0) * g[0] + m(16, 1) * g[1] + add) >> shift;
o[8] = (m(8, 0) * h[0] + m(8, 1) * h[1] + add) >> shift;
o[24] = (m(24, 0) * h[0] + m(24, 1) * h[1] + add) >> shift;
for k in (4..32).step_by(8) {
let acc = (0..4).map(|i| m(k, i) * f[i]).sum::<i32>();
o[k] = (acc + add) >> shift;
}
for k in (2..32).step_by(4) {
let acc = (0..8).map(|i| m(k, i) * d[i]).sum::<i32>();
o[k] = (acc + add) >> shift;
}
for k in (1..32).step_by(2) {
let acc = (0..16).map(|i| m(k, i) * b[i]).sum::<i32>();
o[k] = (acc + add) >> shift;
}
}
}
#[rustfmt::skip]
pub(crate) static DCT64_FWD_KERNEL: [i8; 4096] = [
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
90, 90, 90, 89, 88, 87, 86, 84, 83, 81, 79, 76, 74, 71, 69, 66, 62, 59, 56, 52, 48, 45, 41, 37, 33, 28, 24, 20, 15, 11, 7, 2, -2, -7, -11, -15, -20, -24, -28, -33, -37, -41, -45, -48, -52, -56, -59, -62, -66, -69, -71, -74, -76, -79, -81, -83, -84, -86, -87, -88, -89, -90, -90, -90,
90, 90, 88, 85, 82, 78, 73, 67, 61, 54, 47, 39, 30, 22, 13, 4, -4, -13, -22, -30, -39, -47, -54, -61, -67, -73, -78, -82, -85, -88, -90, -90, -90, -90, -88, -85, -82, -78, -73, -67, -61, -54, -47, -39, -30, -22, -13, -4, 4, 13, 22, 30, 39, 47, 54, 61, 67, 73, 78, 82, 85, 88, 90, 90,
90, 88, 84, 79, 71, 62, 52, 41, 28, 15, 2, -11, -24, -37, -48, -59, -69, -76, -83, -87, -90, -90, -89, -86, -81, -74, -66, -56, -45, -33, -20, -7, 7, 20, 33, 45, 56, 66, 74, 81, 86, 89, 90, 90, 87, 83, 76, 69, 59, 48, 37, 24, 11, -2, -15, -28, -41, -52, -62, -71, -79, -84, -88, -90,
90, 87, 80, 70, 57, 43, 26, 9, -9, -26, -43, -57, -70, -80, -87, -90, -90, -87, -80, -70, -57, -43, -26, -9, 9, 26, 43, 57, 70, 80, 87, 90, 90, 87, 80, 70, 57, 43, 26, 9, -9, -26, -43, -57, -70, -80, -87, -90, -90, -87, -80, -70, -57, -43, -26, -9, 9, 26, 43, 57, 70, 80, 87, 90,
90, 84, 74, 59, 41, 20, -2, -24, -45, -62, -76, -86, -90, -89, -83, -71, -56, -37, -15, 7, 28, 48, 66, 79, 87, 90, 88, 81, 69, 52, 33, 11, -11, -33, -52, -69, -81, -88, -90, -87, -79, -66, -48, -28, -7, 15, 37, 56, 71, 83, 89, 90, 86, 76, 62, 45, 24, 2, -20, -41, -59, -74, -84, -90,
90, 82, 67, 47, 22, -4, -30, -54, -73, -85, -90, -88, -78, -61, -39, -13, 13, 39, 61, 78, 88, 90, 85, 73, 54, 30, 4, -22, -47, -67, -82, -90, -90, -82, -67, -47, -22, 4, 30, 54, 73, 85, 90, 88, 78, 61, 39, 13, -13, -39, -61, -78, -88, -90, -85, -73, -54, -30, -4, 22, 47, 67, 82, 90,
89, 79, 59, 33, 2, -28, -56, -76, -88, -90, -81, -62, -37, -7, 24, 52, 74, 87, 90, 83, 66, 41, 11, -20, -48, -71, -86, -90, -84, -69, -45, -15, 15, 45, 69, 84, 90, 86, 71, 48, 20, -11, -41, -66, -83, -90, -87, -74, -52, -24, 7, 37, 62, 81, 90, 88, 76, 56, 28, -2, -33, -59, -79, -89,
89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89, 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89, 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89, 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89,
88, 71, 41, 2, -37, -69, -87, -89, -74, -45, -7, 33, 66, 86, 90, 76, 48, 11, -28, -62, -84, -90, -79, -52, -15, 24, 59, 83, 90, 81, 56, 20, -20, -56, -81, -90, -83, -59, -24, 15, 52, 79, 90, 84, 62, 28, -11, -48, -76, -90, -86, -66, -33, 7, 45, 74, 89, 87, 69, 37, -2, -41, -71, -88,
88, 67, 30, -13, -54, -82, -90, -78, -47, -4, 39, 73, 90, 85, 61, 22, -22, -61, -85, -90, -73, -39, 4, 47, 78, 90, 82, 54, 13, -30, -67, -88, -88, -67, -30, 13, 54, 82, 90, 78, 47, 4, -39, -73, -90, -85, -61, -22, 22, 61, 85, 90, 73, 39, -4, -47, -78, -90, -82, -54, -13, 30, 67, 88,
87, 62, 20, -28, -69, -89, -84, -56, -11, 37, 74, 90, 81, 48, 2, -45, -79, -90, -76, -41, 7, 52, 83, 90, 71, 33, -15, -59, -86, -88, -66, -24, 24, 66, 88, 86, 59, 15, -33, -71, -90, -83, -52, -7, 41, 76, 90, 79, 45, -2, -48, -81, -90, -74, -37, 11, 56, 84, 89, 69, 28, -20, -62, -87,
87, 57, 9, -43, -80, -90, -70, -26, 26, 70, 90, 80, 43, -9, -57, -87, -87, -57, -9, 43, 80, 90, 70, 26, -26, -70, -90, -80, -43, 9, 57, 87, 87, 57, 9, -43, -80, -90, -70, -26, 26, 70, 90, 80, 43, -9, -57, -87, -87, -57, -9, 43, 80, 90, 70, 26, -26, -70, -90, -80, -43, 9, 57, 87,
86, 52, -2, -56, -87, -84, -48, 7, 59, 88, 83, 45, -11, -62, -89, -81, -41, 15, 66, 90, 79, 37, -20, -69, -90, -76, -33, 24, 71, 90, 74, 28, -28, -74, -90, -71, -24, 33, 76, 90, 69, 20, -37, -79, -90, -66, -15, 41, 81, 89, 62, 11, -45, -83, -88, -59, -7, 48, 84, 87, 56, 2, -52, -86,
85, 47, -13, -67, -90, -73, -22, 39, 82, 88, 54, -4, -61, -90, -78, -30, 30, 78, 90, 61, 4, -54, -88, -82, -39, 22, 73, 90, 67, 13, -47, -85, -85, -47, 13, 67, 90, 73, 22, -39, -82, -88, -54, 4, 61, 90, 78, 30, -30, -78, -90, -61, -4, 54, 88, 82, 39, -22, -73, -90, -67, -13, 47, 85,
84, 41, -24, -76, -89, -56, 7, 66, 90, 69, 11, -52, -88, -79, -28, 37, 83, 86, 45, -20, -74, -90, -59, 2, 62, 90, 71, 15, -48, -87, -81, -33, 33, 81, 87, 48, -15, -71, -90, -62, -2, 59, 90, 74, 20, -45, -86, -83, -37, 28, 79, 88, 52, -11, -69, -90, -66, -7, 56, 89, 76, 24, -41, -84,
83, 35, -35, -83, -83, -35, 35, 83, 83, 35, -35, -83, -83, -35, 35, 83, 83, 35, -35, -83, -83, -35, 35, 83, 83, 35, -35, -83, -83, -35, 35, 83, 83, 35, -35, -83, -83, -35, 35, 83, 83, 35, -35, -83, -83, -35, 35, 83, 83, 35, -35, -83, -83, -35, 35, 83, 83, 35, -35, -83, -83, -35, 35, 83,
83, 28, -45, -88, -74, -11, 59, 90, 62, -7, -71, -89, -48, 24, 81, 84, 33, -41, -87, -76, -15, 56, 90, 66, -2, -69, -90, -52, 20, 79, 86, 37, -37, -86, -79, -20, 52, 90, 69, 2, -66, -90, -56, 15, 76, 87, 41, -33, -84, -81, -24, 48, 89, 71, 7, -62, -90, -59, 11, 74, 88, 45, -28, -83,
82, 22, -54, -90, -61, 13, 78, 85, 30, -47, -90, -67, 4, 73, 88, 39, -39, -88, -73, -4, 67, 90, 47, -30, -85, -78, -13, 61, 90, 54, -22, -82, -82, -22, 54, 90, 61, -13, -78, -85, -30, 47, 90, 67, -4, -73, -88, -39, 39, 88, 73, 4, -67, -90, -47, 30, 85, 78, 13, -61, -90, -54, 22, 82,
81, 15, -62, -90, -45, 37, 88, 69, -7, -76, -84, -24, 56, 90, 52, -28, -86, -74, -2, 71, 87, 33, -48, -90, -59, 20, 83, 79, 11, -66, -89, -41, 41, 89, 66, -11, -79, -83, -20, 59, 90, 48, -33, -87, -71, 2, 74, 86, 28, -52, -90, -56, 24, 84, 76, 7, -69, -88, -37, 45, 90, 62, -15, -81,
80, 9, -70, -87, -26, 57, 90, 43, -43, -90, -57, 26, 87, 70, -9, -80, -80, -9, 70, 87, 26, -57, -90, -43, 43, 90, 57, -26, -87, -70, 9, 80, 80, 9, -70, -87, -26, 57, 90, 43, -43, -90, -57, 26, 87, 70, -9, -80, -80, -9, 70, 87, 26, -57, -90, -43, 43, 90, 57, -26, -87, -70, 9, 80,
79, 2, -76, -81, -7, 74, 83, 11, -71, -84, -15, 69, 86, 20, -66, -87, -24, 62, 88, 28, -59, -89, -33, 56, 90, 37, -52, -90, -41, 48, 90, 45, -45, -90, -48, 41, 90, 52, -37, -90, -56, 33, 89, 59, -28, -88, -62, 24, 87, 66, -20, -86, -69, 15, 84, 71, -11, -83, -74, 7, 81, 76, -2, -79,
78, -4, -82, -73, 13, 85, 67, -22, -88, -61, 30, 90, 54, -39, -90, -47, 47, 90, 39, -54, -90, -30, 61, 88, 22, -67, -85, -13, 73, 82, 4, -78, -78, 4, 82, 73, -13, -85, -67, 22, 88, 61, -30, -90, -54, 39, 90, 47, -47, -90, -39, 54, 90, 30, -61, -88, -22, 67, 85, 13, -73, -82, -4, 78,
76, -11, -86, -62, 33, 90, 45, -52, -89, -24, 69, 83, 2, -81, -71, 20, 88, 56, -41, -90, -37, 59, 87, 15, -74, -79, 7, 84, 66, -28, -90, -48, 48, 90, 28, -66, -84, -7, 79, 74, -15, -87, -59, 37, 90, 41, -56, -88, -20, 71, 81, -2, -83, -69, 24, 89, 52, -45, -90, -33, 62, 86, 11, -76,
75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75, 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75, 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75, 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75,
74, -24, -90, -37, 66, 81, -11, -88, -48, 56, 86, 2, -84, -59, 45, 89, 15, -79, -69, 33, 90, 28, -71, -76, 20, 90, 41, -62, -83, 7, 87, 52, -52, -87, -7, 83, 62, -41, -90, -20, 76, 71, -28, -90, -33, 69, 79, -15, -89, -45, 59, 84, -2, -86, -56, 48, 88, 11, -81, -66, 37, 90, 24, -74,
73, -30, -90, -22, 78, 67, -39, -90, -13, 82, 61, -47, -88, -4, 85, 54, -54, -85, 4, 88, 47, -61, -82, 13, 90, 39, -67, -78, 22, 90, 30, -73, -73, 30, 90, 22, -78, -67, 39, 90, 13, -82, -61, 47, 88, 4, -85, -54, 54, 85, -4, -88, -47, 61, 82, -13, -90, -39, 67, 78, -22, -90, -30, 73,
71, -37, -89, -7, 86, 48, -62, -79, 24, 90, 20, -81, -59, 52, 84, -11, -90, -33, 74, 69, -41, -88, -2, 87, 45, -66, -76, 28, 90, 15, -83, -56, 56, 83, -15, -90, -28, 76, 66, -45, -87, 2, 88, 41, -69, -74, 33, 90, 11, -84, -52, 59, 81, -20, -90, -24, 79, 62, -48, -86, 7, 89, 37, -71,
70, -43, -87, 9, 90, 26, -80, -57, 57, 80, -26, -90, -9, 87, 43, -70, -70, 43, 87, -9, -90, -26, 80, 57, -57, -80, 26, 90, 9, -87, -43, 70, 70, -43, -87, 9, 90, 26, -80, -57, 57, 80, -26, -90, -9, 87, 43, -70, -70, 43, 87, -9, -90, -26, 80, 57, -57, -80, 26, 90, 9, -87, -43, 70,
69, -48, -83, 24, 90, 2, -89, -28, 81, 52, -66, -71, 45, 84, -20, -90, -7, 88, 33, -79, -56, 62, 74, -41, -86, 15, 90, 11, -87, -37, 76, 59, -59, -76, 37, 87, -11, -90, -15, 86, 41, -74, -62, 56, 79, -33, -88, 7, 90, 20, -84, -45, 71, 66, -52, -81, 28, 89, -2, -90, -24, 83, 48, -69,
67, -54, -78, 39, 85, -22, -90, 4, 90, 13, -88, -30, 82, 47, -73, -61, 61, 73, -47, -82, 30, 88, -13, -90, -4, 90, 22, -85, -39, 78, 54, -67, -67, 54, 78, -39, -85, 22, 90, -4, -90, -13, 88, 30, -82, -47, 73, 61, -61, -73, 47, 82, -30, -88, 13, 90, 4, -90, -22, 85, 39, -78, -54, 67,
66, -59, -71, 52, 76, -45, -81, 37, 84, -28, -87, 20, 89, -11, -90, 2, 90, 7, -90, -15, 88, 24, -86, -33, 83, 41, -79, -48, 74, 56, -69, -62, 62, 69, -56, -74, 48, 79, -41, -83, 33, 86, -24, -88, 15, 90, -7, -90, -2, 90, 11, -89, -20, 87, 28, -84, -37, 81, 45, -76, -52, 71, 59, -66,
64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64,
62, -69, -56, 74, 48, -79, -41, 83, 33, -86, -24, 88, 15, -90, -7, 90, -2, -90, 11, 89, -20, -87, 28, 84, -37, -81, 45, 76, -52, -71, 59, 66, -66, -59, 71, 52, -76, -45, 81, 37, -84, -28, 87, 20, -89, -11, 90, 2, -90, 7, 90, -15, -88, 24, 86, -33, -83, 41, 79, -48, -74, 56, 69, -62,
61, -73, -47, 82, 30, -88, -13, 90, -4, -90, 22, 85, -39, -78, 54, 67, -67, -54, 78, 39, -85, -22, 90, 4, -90, 13, 88, -30, -82, 47, 73, -61, -61, 73, 47, -82, -30, 88, 13, -90, 4, 90, -22, -85, 39, 78, -54, -67, 67, 54, -78, -39, 85, 22, -90, -4, 90, -13, -88, 30, 82, -47, -73, 61,
59, -76, -37, 87, 11, -90, 15, 86, -41, -74, 62, 56, -79, -33, 88, 7, -90, 20, 84, -45, -71, 66, 52, -81, -28, 89, 2, -90, 24, 83, -48, -69, 69, 48, -83, -24, 90, -2, -89, 28, 81, -52, -66, 71, 45, -84, -20, 90, -7, -88, 33, 79, -56, -62, 74, 41, -86, -15, 90, -11, -87, 37, 76, -59,
57, -80, -26, 90, -9, -87, 43, 70, -70, -43, 87, 9, -90, 26, 80, -57, -57, 80, 26, -90, 9, 87, -43, -70, 70, 43, -87, -9, 90, -26, -80, 57, 57, -80, -26, 90, -9, -87, 43, 70, -70, -43, 87, 9, -90, 26, 80, -57, -57, 80, 26, -90, 9, 87, -43, -70, 70, 43, -87, -9, 90, -26, -80, 57,
56, -83, -15, 90, -28, -76, 66, 45, -87, -2, 88, -41, -69, 74, 33, -90, 11, 84, -52, -59, 81, 20, -90, 24, 79, -62, -48, 86, 7, -89, 37, 71, -71, -37, 89, -7, -86, 48, 62, -79, -24, 90, -20, -81, 59, 52, -84, -11, 90, -33, -74, 69, 41, -88, 2, 87, -45, -66, 76, 28, -90, 15, 83, -56,
54, -85, -4, 88, -47, -61, 82, 13, -90, 39, 67, -78, -22, 90, -30, -73, 73, 30, -90, 22, 78, -67, -39, 90, -13, -82, 61, 47, -88, 4, 85, -54, -54, 85, 4, -88, 47, 61, -82, -13, 90, -39, -67, 78, 22, -90, 30, 73, -73, -30, 90, -22, -78, 67, 39, -90, 13, 82, -61, -47, 88, -4, -85, 54,
52, -87, 7, 83, -62, -41, 90, -20, -76, 71, 28, -90, 33, 69, -79, -15, 89, -45, -59, 84, 2, -86, 56, 48, -88, 11, 81, -66, -37, 90, -24, -74, 74, 24, -90, 37, 66, -81, -11, 88, -48, -56, 86, -2, -84, 59, 45, -89, 15, 79, -69, -33, 90, -28, -71, 76, 20, -90, 41, 62, -83, -7, 87, -52,
50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50, 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50, 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50, 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50,
48, -90, 28, 66, -84, 7, 79, -74, -15, 87, -59, -37, 90, -41, -56, 88, -20, -71, 81, 2, -83, 69, 24, -89, 52, 45, -90, 33, 62, -86, 11, 76, -76, -11, 86, -62, -33, 90, -45, -52, 89, -24, -69, 83, -2, -81, 71, 20, -88, 56, 41, -90, 37, 59, -87, 15, 74, -79, -7, 84, -66, -28, 90, -48,
47, -90, 39, 54, -90, 30, 61, -88, 22, 67, -85, 13, 73, -82, 4, 78, -78, -4, 82, -73, -13, 85, -67, -22, 88, -61, -30, 90, -54, -39, 90, -47, -47, 90, -39, -54, 90, -30, -61, 88, -22, -67, 85, -13, -73, 82, -4, -78, 78, 4, -82, 73, 13, -85, 67, 22, -88, 61, 30, -90, 54, 39, -90, 47,
45, -90, 48, 41, -90, 52, 37, -90, 56, 33, -89, 59, 28, -88, 62, 24, -87, 66, 20, -86, 69, 15, -84, 71, 11, -83, 74, 7, -81, 76, 2, -79, 79, -2, -76, 81, -7, -74, 83, -11, -71, 84, -15, -69, 86, -20, -66, 87, -24, -62, 88, -28, -59, 89, -33, -56, 90, -37, -52, 90, -41, -48, 90, -45,
43, -90, 57, 26, -87, 70, 9, -80, 80, -9, -70, 87, -26, -57, 90, -43, -43, 90, -57, -26, 87, -70, -9, 80, -80, 9, 70, -87, 26, 57, -90, 43, 43, -90, 57, 26, -87, 70, 9, -80, 80, -9, -70, 87, -26, -57, 90, -43, -43, 90, -57, -26, 87, -70, -9, 80, -80, 9, 70, -87, 26, 57, -90, 43,
41, -89, 66, 11, -79, 83, -20, -59, 90, -48, -33, 87, -71, -2, 74, -86, 28, 52, -90, 56, 24, -84, 76, -7, -69, 88, -37, -45, 90, -62, -15, 81, -81, 15, 62, -90, 45, 37, -88, 69, 7, -76, 84, -24, -56, 90, -52, -28, 86, -74, 2, 71, -87, 33, 48, -90, 59, 20, -83, 79, -11, -66, 89, -41,
39, -88, 73, -4, -67, 90, -47, -30, 85, -78, 13, 61, -90, 54, 22, -82, 82, -22, -54, 90, -61, -13, 78, -85, 30, 47, -90, 67, 4, -73, 88, -39, -39, 88, -73, 4, 67, -90, 47, 30, -85, 78, -13, -61, 90, -54, -22, 82, -82, 22, 54, -90, 61, 13, -78, 85, -30, -47, 90, -67, -4, 73, -88, 39,
37, -86, 79, -20, -52, 90, -69, 2, 66, -90, 56, 15, -76, 87, -41, -33, 84, -81, 24, 48, -89, 71, -7, -62, 90, -59, -11, 74, -88, 45, 28, -83, 83, -28, -45, 88, -74, 11, 59, -90, 62, 7, -71, 89, -48, -24, 81, -84, 33, 41, -87, 76, -15, -56, 90, -66, -2, 69, -90, 52, 20, -79, 86, -37,
35, -83, 83, -35, -35, 83, -83, 35, 35, -83, 83, -35, -35, 83, -83, 35, 35, -83, 83, -35, -35, 83, -83, 35, 35, -83, 83, -35, -35, 83, -83, 35, 35, -83, 83, -35, -35, 83, -83, 35, 35, -83, 83, -35, -35, 83, -83, 35, 35, -83, 83, -35, -35, 83, -83, 35, 35, -83, 83, -35, -35, 83, -83, 35,
33, -81, 87, -48, -15, 71, -90, 62, -2, -59, 90, -74, 20, 45, -86, 83, -37, -28, 79, -88, 52, 11, -69, 90, -66, 7, 56, -89, 76, -24, -41, 84, -84, 41, 24, -76, 89, -56, -7, 66, -90, 69, -11, -52, 88, -79, 28, 37, -83, 86, -45, -20, 74, -90, 59, 2, -62, 90, -71, 15, 48, -87, 81, -33,
30, -78, 90, -61, 4, 54, -88, 82, -39, -22, 73, -90, 67, -13, -47, 85, -85, 47, 13, -67, 90, -73, 22, 39, -82, 88, -54, -4, 61, -90, 78, -30, -30, 78, -90, 61, -4, -54, 88, -82, 39, 22, -73, 90, -67, 13, 47, -85, 85, -47, -13, 67, -90, 73, -22, -39, 82, -88, 54, 4, -61, 90, -78, 30,
28, -74, 90, -71, 24, 33, -76, 90, -69, 20, 37, -79, 90, -66, 15, 41, -81, 89, -62, 11, 45, -83, 88, -59, 7, 48, -84, 87, -56, 2, 52, -86, 86, -52, -2, 56, -87, 84, -48, -7, 59, -88, 83, -45, -11, 62, -89, 81, -41, -15, 66, -90, 79, -37, -20, 69, -90, 76, -33, -24, 71, -90, 74, -28,
26, -70, 90, -80, 43, 9, -57, 87, -87, 57, -9, -43, 80, -90, 70, -26, -26, 70, -90, 80, -43, -9, 57, -87, 87, -57, 9, 43, -80, 90, -70, 26, 26, -70, 90, -80, 43, 9, -57, 87, -87, 57, -9, -43, 80, -90, 70, -26, -26, 70, -90, 80, -43, -9, 57, -87, 87, -57, 9, 43, -80, 90, -70, 26,
24, -66, 88, -86, 59, -15, -33, 71, -90, 83, -52, 7, 41, -76, 90, -79, 45, 2, -48, 81, -90, 74, -37, -11, 56, -84, 89, -69, 28, 20, -62, 87, -87, 62, -20, -28, 69, -89, 84, -56, 11, 37, -74, 90, -81, 48, -2, -45, 79, -90, 76, -41, -7, 52, -83, 90, -71, 33, 15, -59, 86, -88, 66, -24,
22, -61, 85, -90, 73, -39, -4, 47, -78, 90, -82, 54, -13, -30, 67, -88, 88, -67, 30, 13, -54, 82, -90, 78, -47, 4, 39, -73, 90, -85, 61, -22, -22, 61, -85, 90, -73, 39, 4, -47, 78, -90, 82, -54, 13, 30, -67, 88, -88, 67, -30, -13, 54, -82, 90, -78, 47, -4, -39, 73, -90, 85, -61, 22,
20, -56, 81, -90, 83, -59, 24, 15, -52, 79, -90, 84, -62, 28, 11, -48, 76, -90, 86, -66, 33, 7, -45, 74, -89, 87, -69, 37, 2, -41, 71, -88, 88, -71, 41, -2, -37, 69, -87, 89, -74, 45, -7, -33, 66, -86, 90, -76, 48, -11, -28, 62, -84, 90, -79, 52, -15, -24, 59, -83, 90, -81, 56, -20,
18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18, 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18, 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18, 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18,
15, -45, 69, -84, 90, -86, 71, -48, 20, 11, -41, 66, -83, 90, -87, 74, -52, 24, 7, -37, 62, -81, 90, -88, 76, -56, 28, 2, -33, 59, -79, 89, -89, 79, -59, 33, -2, -28, 56, -76, 88, -90, 81, -62, 37, -7, -24, 52, -74, 87, -90, 83, -66, 41, -11, -20, 48, -71, 86, -90, 84, -69, 45, -15,
13, -39, 61, -78, 88, -90, 85, -73, 54, -30, 4, 22, -47, 67, -82, 90, -90, 82, -67, 47, -22, -4, 30, -54, 73, -85, 90, -88, 78, -61, 39, -13, -13, 39, -61, 78, -88, 90, -85, 73, -54, 30, -4, -22, 47, -67, 82, -90, 90, -82, 67, -47, 22, 4, -30, 54, -73, 85, -90, 88, -78, 61, -39, 13,
11, -33, 52, -69, 81, -88, 90, -87, 79, -66, 48, -28, 7, 15, -37, 56, -71, 83, -89, 90, -86, 76, -62, 45, -24, 2, 20, -41, 59, -74, 84, -90, 90, -84, 74, -59, 41, -20, -2, 24, -45, 62, -76, 86, -90, 89, -83, 71, -56, 37, -15, -7, 28, -48, 66, -79, 87, -90, 88, -81, 69, -52, 33, -11,
9, -26, 43, -57, 70, -80, 87, -90, 90, -87, 80, -70, 57, -43, 26, -9, -9, 26, -43, 57, -70, 80, -87, 90, -90, 87, -80, 70, -57, 43, -26, 9, 9, -26, 43, -57, 70, -80, 87, -90, 90, -87, 80, -70, 57, -43, 26, -9, -9, 26, -43, 57, -70, 80, -87, 90, -90, 87, -80, 70, -57, 43, -26, 9,
7, -20, 33, -45, 56, -66, 74, -81, 86, -89, 90, -90, 87, -83, 76, -69, 59, -48, 37, -24, 11, 2, -15, 28, -41, 52, -62, 71, -79, 84, -88, 90, -90, 88, -84, 79, -71, 62, -52, 41, -28, 15, -2, -11, 24, -37, 48, -59, 69, -76, 83, -87, 90, -90, 89, -86, 81, -74, 66, -56, 45, -33, 20, -7,
4, -13, 22, -30, 39, -47, 54, -61, 67, -73, 78, -82, 85, -88, 90, -90, 90, -90, 88, -85, 82, -78, 73, -67, 61, -54, 47, -39, 30, -22, 13, -4, -4, 13, -22, 30, -39, 47, -54, 61, -67, 73, -78, 82, -85, 88, -90, 90, -90, 90, -88, 85, -82, 78, -73, 67, -61, 54, -47, 39, -30, 22, -13, 4,
2, -7, 11, -15, 20, -24, 28, -33, 37, -41, 45, -48, 52, -56, 59, -62, 66, -69, 71, -74, 76, -79, 81, -83, 84, -86, 87, -88, 89, -90, 90, -90, 90, -90, 90, -89, 88, -87, 86, -84, 83, -81, 79, -76, 74, -71, 69, -66, 62, -59, 56, -52, 48, -45, 41, -37, 33, -28, 24, -20, 15, -11, 7, -2,
];
fn fdct64_1d(
src: &[i32],
dst: &mut [i32],
shift: i32,
line: usize,
skip_line: usize,
zero_line: usize,
) {
let add = if shift > 0 { 1 << (shift - 1) } else { 0 };
let m = |k: usize, c: usize| DCT64_FWD_KERNEL[k * 64 + c] as i32;
let zo = zero_line != 0;
let top = if zo { 32 } else { 64 };
for j in 0..(line - skip_line) {
let col = |k: usize| src[k * line + j];
let mut a = [0i32; 32];
let mut b = [0i32; 32];
for k in 0..32 {
a[k] = col(k) + col(63 - k);
b[k] = col(k) - col(63 - k);
}
let mut c = [0i32; 16];
let mut d = [0i32; 16];
for k in 0..16 {
c[k] = a[k] + a[31 - k];
d[k] = a[k] - a[31 - k];
}
let mut e = [0i32; 8];
let mut f = [0i32; 8];
for k in 0..8 {
e[k] = c[k] + c[15 - k];
f[k] = c[k] - c[15 - k];
}
let mut g = [0i32; 4];
let mut h = [0i32; 4];
for k in 0..4 {
g[k] = e[k] + e[7 - k];
h[k] = e[k] - e[7 - k];
}
let i0 = [g[0] + g[3], g[1] + g[2]];
let u0 = [g[0] - g[3], g[1] - g[2]];
let o = &mut dst[j * 64..j * 64 + 64];
o[0] = (m(0, 0) * i0[0] + m(0, 1) * i0[1] + add) >> shift;
o[16] = (m(16, 0) * u0[0] + m(16, 1) * u0[1] + add) >> shift;
if !zo {
o[32] = (m(32, 0) * i0[0] + m(32, 1) * i0[1] + add) >> shift;
o[48] = (m(48, 0) * u0[0] + m(48, 1) * u0[1] + add) >> shift;
}
let mut k = 8;
while k < top {
o[k] =
(m(k, 0) * h[0] + m(k, 1) * h[1] + m(k, 2) * h[2] + m(k, 3) * h[3] + add) >> shift;
k += 16;
}
let mut k = 4;
while k < top {
let acc: i32 = (0..8).map(|t| m(k, t) * f[t]).sum();
o[k] = (acc + add) >> shift;
k += 8;
}
let mut k = 2;
while k < top {
let acc: i32 = (0..16).map(|t| m(k, t) * d[t]).sum();
o[k] = (acc + add) >> shift;
k += 4;
}
let mut k = 1;
while k < top {
let acc: i32 = (0..32).map(|t| m(k, t) * b[t]).sum();
o[k] = (acc + add) >> shift;
k += 2;
}
}
}
pub(crate) fn quantize_to_levels(
coeff: &[i32],
n: usize,
qstep: i32,
factor: f32,
thresh: f32,
scan: &[u16],
) -> (Vec<f32>, Vec<f32>) {
let inv_q = factor / qstep as f32;
let th = thresh;
let dz: f32 = 0.5;
let mut lev = vec![0f32; scan.len()];
let mut prm = vec![0f32; scan.len()];
let wscan = !scan.is_empty() && scan.get(1).is_some_and(|&v| v as usize == n);
for ((&rc, prm), lev) in scan.iter().zip(prm.iter_mut()).zip(lev.iter_mut()) {
let rc = rc as usize;
let idx = if wscan { rc } else { (rc & 31) * n + (rc >> 5) };
let pr = coeff[idx] as f32 * inv_q;
let a = pr.abs();
*prm = a;
if a >= th {
*lev = pr.signum() * (a + (dz - 0.5)).max(0.0).round();
}
}
(lev, prm)
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub(crate) enum FwdKind {
Proj,
Dct(usize, usize),
AdstAdst16, AdstDct16, DctAdst16, }
pub(crate) static DCT16_FWD_KERNEL: [i8; 256] = [
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 90, 87, 80, 70, 57, 43, 26, 9,
-9, -26, -43, -57, -70, -80, -87, -90, 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18,
18, 50, 75, 89, 87, 57, 9, -43, -80, -90, -70, -26, 26, 70, 90, 80, 43, -9, -57, -87, 83, 35,
-35, -83, -83, -35, 35, 83, 83, 35, -35, -83, -83, -35, 35, 83, 80, 9, -70, -87, -26, 57, 90,
43, -43, -90, -57, 26, 87, 70, -9, -80, 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50,
-50, -89, -18, 75, 70, -43, -87, 9, 90, 26, -80, -57, 57, 80, -26, -90, -9, 87, 43, -70, 64,
-64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 57, -80, -26, 90, -9, -87,
43, 70, -70, -43, 87, 9, -90, 26, 80, -57, 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18,
-75, 75, 18, -89, 50, 43, -90, 57, 26, -87, 70, 9, -80, 80, -9, -70, 87, -26, -57, 90, -43, 35,
-83, 83, -35, -35, 83, -83, 35, 35, -83, 83, -35, -35, 83, -83, 35, 26, -70, 90, -80, 43, 9,
-57, 87, -87, 57, -9, -43, 80, -90, 70, -26, 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75,
89, -89, 75, -50, 18, 9, -26, 43, -57, 70, -80, 87, -90, 90, -87, 80, -70, 57, -43, 26, -9,
];
fn fdct16_1d(src: &[i32], dst: &mut [i32], shift: i32, line: usize) {
let add = if shift > 0 { 1 << (shift - 1) } else { 0 };
let m = |k: usize, c: usize| DCT16_FWD_KERNEL[k * 16 + c] as i32;
for j in 0..line {
let s = |k: usize| src[k * line + j];
let mut a = [0i32; 8];
let mut b = [0i32; 8];
for k in 0..8 {
a[k] = s(k) + s(15 - k);
b[k] = s(k) - s(15 - k);
}
let mut c = [0i32; 4];
let mut d = [0i32; 4];
for k in 0..4 {
c[k] = a[k] + a[7 - k];
d[k] = a[k] - a[7 - k];
}
let e = [c[0] + c[3], c[1] + c[2]];
let f = [c[0] - c[3], c[1] - c[2]];
let o = &mut dst[j * 16..j * 16 + 16];
o[0] = (m(0, 0) * e[0] + m(0, 1) * e[1] + add) >> shift;
o[8] = (m(8, 0) * e[0] + m(8, 1) * e[1] + add) >> shift;
o[4] = (m(4, 0) * f[0] + m(4, 1) * f[1] + add) >> shift;
o[12] = (m(12, 0) * f[0] + m(12, 1) * f[1] + add) >> shift;
let mut k = 2;
while k < 16 {
let acc: i32 = (0..4).map(|t| m(k, t) * d[t]).sum();
o[k] = (acc + add) >> shift;
k += 4;
}
let mut k = 1;
while k < 16 {
let acc: i32 = (0..8).map(|t| m(k, t) * b[t]).sum();
o[k] = (acc + add) >> shift;
k += 2;
}
}
}
pub(crate) static ADST16_FWD_KERNEL: [i8; 256] = [
8, 17, 25, 33, 41, 48, 55, 62, 67, 73, 77, 81, 84, 87, 88, 89, 25, 48, 67, 81, 88, 88, 81, 67,
48, 25, 0, -25, -48, -67, -81, -88, 41, 73, 88, 84, 62, 25, -17, -55, -81, -89, -77, -48, -8,
33, 67, 87, 55, 87, 81, 41, -17, -67, -89, -73, -25, 33, 77, 88, 62, 8, -48, -84, 67, 88, 48,
-25, -81, -81, -25, 48, 88, 67, 0, -67, -88, -48, 25, 81, 77, 77, 0, -77, -77, 0, 77, 77, 0,
-77, -77, 0, 77, 77, 0, -77, 84, 55, -48, -87, -8, 81, 62, -41, -88, -17, 77, 67, -33, -89,
-25, 73, 88, 25, -81, -48, 67, 67, -48, -81, 25, 88, 0, -88, -25, 81, 48, -67, 89, -8, -88, 17,
87, -25, -84, 33, 81, -41, -77, 48, 73, -55, -67, 62, 87, -41, -67, 73, 33, -88, 8, 84, -48,
-62, 77, 25, -89, 17, 81, -55, 81, -67, -25, 88, -48, -48, 88, -25, -67, 81, 0, -81, 67, 25,
-88, 48, 73, -84, 25, 55, -89, 48, 33, -87, 67, 8, -77, 81, -17, -62, 88, -41, 62, -89, 67, -8,
-55, 88, -73, 17, 48, -87, 77, -25, -41, 84, -81, 33, 48, -81, 88, -67, 25, 25, -67, 88, -81,
48, 0, -48, 81, -88, 67, -25, 33, -62, 81, -89, 84, -67, 41, -8, -25, 55, -77, 88, -87, 73,
-48, 17, 17, -33, 48, -62, 73, -81, 87, -89, 88, -84, 77, -67, 55, -41, 25, -8,
];
fn fadst16_1d(src: &[i32], dst: &mut [i32], shift: i32, line: usize) {
let add = if shift > 0 { 1 << (shift - 1) } else { 0 };
for i in 0..line {
let o = &mut dst[i * 16..i * 16 + 16];
for j in 0..16 {
let mut sum = 0i32;
for k in 0..16 {
sum += src[k * line + i] * ADST16_FWD_KERNEL[j * 16 + k] as i32;
}
o[j] = (sum + add) >> shift;
}
}
}
pub(crate) fn fwd16x16(resid: &[i32; 256], col_adst: bool, row_adst: bool) -> [i32; 256] {
let mut buf = [0i32; 256];
let mut coeff = [0i32; 256];
if col_adst {
fadst16_1d(resid, &mut buf, 2, 16);
} else {
fdct16_1d(resid, &mut buf, 2, 16);
}
if row_adst {
fadst16_1d(&buf, &mut coeff, 11, 16);
} else {
fdct16_1d(&buf, &mut coeff, 11, 16);
}
coeff
}
#[rustfmt::skip]
pub(crate) static DCT8_FWD_KERNEL: [i8; 64] = [
64, 64, 64, 64, 64, 64, 64, 64,
89, 75, 50, 18, -18, -50, -75, -89,
83, 35, -35, -83, -83, -35, 35, 83,
75, -18, -89, -50, 50, 89, 18, -75,
64, -64, -64, 64, 64, -64, -64, 64,
50, -89, 18, 75, -75, -18, 89, -50,
35, -83, 83, -35, -35, 83, -83, 35,
18, -50, 75, -89, 89, -75, 50, -18,
];
#[rustfmt::skip]
pub(crate) static DCT4_FWD_KERNEL: [i8; 16] = [
64, 64, 64, 64,
83, 35, -35, -83,
64, -64, -64, 64,
35, -83, 83, -35,
];
fn fdct8_1d(src: &[i32], dst: &mut [i32], shift: i32, line: usize) {
let add = if shift > 0 { 1 << (shift - 1) } else { 0 };
let m = |k: usize, c: usize| DCT8_FWD_KERNEL[k * 8 + c] as i32;
for j in 0..line {
let s = |k: usize| src[k * line + j];
let mut a = [0i32; 4];
let mut b = [0i32; 4];
for k in 0..4 {
a[k] = s(k) + s(7 - k);
b[k] = s(k) - s(7 - k);
}
let c = [a[0] + a[3], a[1] + a[2]];
let d = [a[0] - a[3], a[1] - a[2]];
let o = &mut dst[j * 8..j * 8 + 8];
o[0] = (m(0, 0) * c[0] + m(0, 1) * c[1] + add) >> shift;
o[4] = (m(4, 0) * c[0] + m(4, 1) * c[1] + add) >> shift;
o[2] = (m(2, 0) * d[0] + m(2, 1) * d[1] + add) >> shift;
o[6] = (m(6, 0) * d[0] + m(6, 1) * d[1] + add) >> shift;
let mut k = 1;
while k < 8 {
let acc: i32 = (0..4).map(|t| m(k, t) * b[t]).sum();
o[k] = (acc + add) >> shift;
k += 2;
}
}
}
fn fdct4_1d(src: &[i32], dst: &mut [i32], shift: i32, line: usize) {
let add = if shift > 0 { 1 << (shift - 1) } else { 0 };
let km = &DCT4_FWD_KERNEL;
let m = |k: usize, c: usize| km[k * 4 + c] as i32;
for j in 0..line {
let s = |k: usize| src[k * line + j];
let a = [s(0) + s(3), s(1) + s(2)];
let b = [s(0) - s(3), s(1) - s(2)];
let o = &mut dst[j * 4..j * 4 + 4];
o[0] = (m(0, 0) * a[0] + m(0, 1) * a[1] + add) >> shift;
o[2] = (m(2, 0) * a[0] + m(2, 1) * a[1] + add) >> shift;
o[1] = (m(1, 0) * b[0] + m(1, 1) * b[1] + add) >> shift;
o[3] = (m(3, 0) * b[0] + m(3, 1) * b[1] + add) >> shift;
}
}
pub(crate) fn fwd_shifts(w: usize, h: usize) -> (i32, i32) {
match (w, h) {
(4, 4) => (1, 10),
(8, 8) => (2, 10),
(16, 16) => (2, 11),
(32, 32) => (3, 12),
(64, 64) => (3, 14),
(4, 8) => (1, 11),
(8, 4) => (1, 11),
(8, 16) => (1, 12),
(16, 8) => (2, 11),
(16, 32) => (2, 13),
(32, 16) => (3, 12),
(32, 64) => (3, 14),
(64, 32) => (3, 14),
(4, 16) => (1, 11),
(16, 4) => (1, 11),
(8, 32) => (1, 12),
(32, 8) => (3, 10),
(16, 64) => (2, 13),
(64, 16) => (3, 12),
(4, 32) => (1, 12),
(32, 4) => (1, 12),
(8, 64) => (2, 13),
(64, 8) => (4, 11),
(4, 64) => (1, 12),
(64, 4) => (1, 12),
_ => unreachable!("unsupported tx {w}x{h}"),
}
}
pub(crate) fn dc_tx_scale(w: usize, h: usize) -> u32 {
let s = w.trailing_zeros() + h.trailing_zeros();
if s <= 8 { 0 } else { (s - 7) / 2 }
}
fn fdct_1d_n(n: usize, src: &[i32], dst: &mut [i32], shift: i32, line: usize, zero: usize) {
match n {
4 => fdct4_1d(src, dst, shift, line),
8 => fdct8_1d(src, dst, shift, line),
16 => fdct16_1d(src, dst, shift, line),
32 => fdct32_1d(src, dst, shift, line),
64 => fdct64_1d(src, dst, shift, line, 0, zero),
_ => unreachable!("unsupported 1D size {n}"),
}
}
struct PassScratch {
buf: Box<[i32; 4096]>,
coeff: Box<[i32; 4096]>,
}
thread_local! {
static PASS_SCRATCH: RefCell<PassScratch> =
RefCell::new(PassScratch { buf: Box::new([0; 4096]), coeff: Box::new([0; 4096]) });
}
pub(crate) type FdctRectFn = unsafe fn(&[i32], usize, usize, &mut [i32]) -> usize;
static FDCT_RECT: OnceLock<FdctRectFn> = OnceLock::new();
unsafe fn fdct_rect_scalar(resid: &[i32], w: usize, h: usize, out: &mut [i32]) -> usize {
let (s1, s2) = fwd_shifts(w, h);
let zh = if h > 32 { 32 } else { 0 };
let zw = if w > 32 { 32 } else { 0 };
let (cw, ch) = (w.min(32), h.min(32));
PASS_SCRATCH.with(|cell| {
let s = &mut *cell.borrow_mut();
fdct_1d_n(h, resid, &mut s.buf[..w * h], s1, w, zh); fdct_1d_n(w, &s.buf[..w * h], &mut s.coeff[..w * h], s2, h, zw); for (dst_row, src_row) in out[..cw * ch]
.chunks_exact_mut(cw)
.zip(s.coeff.chunks_exact(w).take(ch))
{
dst_row.copy_from_slice(&src_row[..cw]);
}
});
if (w.trailing_zeros() + h.trailing_zeros()) & 1 == 1 {
for v in out[..cw * ch].iter_mut() {
*v = (((*v as i64) * 5793 + 2048) >> 12) as i32;
}
}
cw * ch
}
#[inline]
fn resolve_fdct_rect() -> FdctRectFn {
*FDCT_RECT.get_or_init(|| {
let mut _f = fdct_rect_scalar as FdctRectFn;
#[cfg(all(target_arch = "aarch64", feature = "neon"))]
{
_f = crate::av2::neon::fdct_rect_neon as FdctRectFn;
}
#[cfg(all(target_arch = "x86_64", feature = "avx"))]
{
if std::is_x86_feature_detected!("avx2") {
_f = crate::av2::avx::fdct_rect_avx2 as FdctRectFn;
}
}
_f
})
}
pub(crate) fn fdct_rect(resid: &[i32], w: usize, h: usize, out: &mut [i32]) -> usize {
let f = resolve_fdct_rect();
unsafe { f(resid, w, h, out) }
}
#[cfg(test)]
mod tests {
use super::*;
const TX_SIZES: &[(usize, usize)] = &[
(4, 4),
(8, 8),
(16, 16),
(32, 32),
(64, 64),
(4, 8),
(8, 4),
(8, 16),
(16, 8),
(16, 32),
(32, 16),
(32, 64),
(64, 32),
(4, 16),
(16, 4),
(8, 32),
(32, 8),
(16, 64),
(64, 16),
(4, 32),
(32, 4),
(8, 64),
(64, 8),
(4, 64),
(64, 4),
];
fn residual_case(w: usize, h: usize, seed: u32) -> Vec<i32> {
let mut state = seed
.wrapping_mul(747_796_405)
.wrapping_add((w as u32) << 16)
.wrapping_add(h as u32);
let mut out = vec![0i32; w * h];
for y in 0..h {
for x in 0..w {
state = state.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
let noise = ((state >> 21) as i32) - 1024;
let gradient = (x as i32 * 11) - (y as i32 * 7) + ((x ^ y) as i32 * 3);
out[y * w + x] = (noise + gradient).clamp(-2048, 2047);
}
}
out
}
unsafe fn assert_fdct_impl_matches_scalar(name: &str, simd: FdctRectFn) {
for seed in 0..8u32 {
for &(w, h) in TX_SIZES.iter().rev().chain(TX_SIZES.iter()) {
let resid = residual_case(w, h, seed);
let mut expected = [0i32; 1024];
let mut actual = [0i32; 1024];
let expected_n = unsafe { fdct_rect_scalar(&resid, w, h, &mut expected) };
let actual_n = unsafe { simd(&resid, w, h, &mut actual) };
assert_eq!(
actual_n, expected_n,
"{name} size mismatch for {w}x{h} seed {seed}"
);
assert_eq!(
&actual[..actual_n],
&expected[..expected_n],
"{name} coeff mismatch for {w}x{h} seed {seed}"
);
}
}
}
#[cfg(all(target_arch = "aarch64", feature = "neon"))]
#[test]
fn fdct_neon_matches_scalar() {
unsafe { assert_fdct_impl_matches_scalar("neon", crate::av2::neon::fdct_rect_neon) };
}
#[cfg(all(target_arch = "x86_64", feature = "avx"))]
#[test]
fn fdct_avx2_matches_scalar() {
if !std::is_x86_feature_detected!("avx2") {
return;
}
unsafe { assert_fdct_impl_matches_scalar("avx2", crate::av2::avx::fdct_rect_avx2) };
}
}