#[must_use]
pub fn quantize_block(coeffs: &[i32; 64], matrix: &[u8; 64], qscale: u8) -> [i16; 64] {
let qs = i32::from(if qscale == 0 { 1 } else { qscale });
let mut out = [0i16; 64];
for i in 0..64 {
let m = i32::from(matrix[i]);
let step = m * qs;
let c = coeffs[i];
if step == 0 || c == 0 {
out[i] = 0;
continue;
}
let sign = if c > 0 { 1i32 } else { -1i32 };
let biased = c + sign * (step / 2);
let q = biased / step;
out[i] = q.clamp(i16::MIN as i32, i16::MAX as i32) as i16;
}
out
}
#[cfg(test)]
mod tests {
use super::*;
use crate::prores::dequant::dequantize_block;
#[test]
fn quantize_zero_block_stays_zero() {
let coeffs = [0i32; 64];
let matrix = [4u8; 64];
let q = quantize_block(&coeffs, &matrix, 6);
assert!(q.iter().all(|&v| v == 0));
}
#[test]
fn quantize_then_dequantize_small_error() {
let coeffs: [i32; 64] = std::array::from_fn(|i| (i as i32 * 7) - 224);
let matrix: [u8; 64] = crate::prores::quant::DEFAULT_LUMA_QUANT_MATRIX;
let qscale = 4u8;
let quantized = quantize_block(&coeffs, &matrix, qscale);
let quantized_i32: [i32; 64] = std::array::from_fn(|i| quantized[i] as i32);
let dequantized = dequantize_block(&quantized_i32, &matrix, qscale);
for i in 0..64 {
let step = i32::from(matrix[i]) * i32::from(qscale);
let err = (dequantized[i] - coeffs[i]).abs();
assert!(
err <= step,
"quant/dequant error at [{i}]: orig={}, dequant={}, step={}",
coeffs[i],
dequantized[i],
step
);
}
}
#[test]
fn quantize_preserves_sign() {
let mut coeffs = [0i32; 64];
coeffs[0] = 200;
coeffs[1] = -200;
let matrix = [4u8; 64];
let q = quantize_block(&coeffs, &matrix, 4);
assert!(q[0] > 0, "positive coeff should stay positive");
assert!(q[1] < 0, "negative coeff should stay negative");
}
#[test]
fn quantize_rounds_toward_zero() {
let mut coeffs = [0i32; 64];
coeffs[0] = 1;
let matrix = [4u8; 64];
let q = quantize_block(&coeffs, &matrix, 16);
assert_eq!(q[0], 0, "small coeff should quantize to 0");
}
#[test]
fn quantize_qscale_zero_treated_as_one() {
let coeffs: [i32; 64] = std::array::from_fn(|i| i as i32 * 10);
let matrix = [4u8; 64];
let q0 = quantize_block(&coeffs, &matrix, 0);
let q1 = quantize_block(&coeffs, &matrix, 1);
assert_eq!(q0, q1, "qscale=0 should behave like qscale=1");
}
}