use crate::util::FastRound;
fn dc_tx_scale(w: usize, h: usize) -> i32 {
let s = (w.trailing_zeros() + h.trailing_zeros()) as i32;
if s <= 8 { 0 } else { (s - 7) / 2 }
}
fn dc_tx_index(w: usize, h: usize) -> usize {
use crate::av2::av2_itx::tx_size::*;
match (w, h) {
(4, 4) => TX_4X4,
(8, 8) => TX_8X8,
(16, 16) => TX_16X16,
(32, 32) => TX_32X32,
(64, 64) => TX_64X64,
(4, 8) => RTX_4X8,
(8, 4) => RTX_8X4,
(8, 16) => RTX_8X16,
(16, 8) => RTX_16X8,
(16, 32) => RTX_16X32,
(32, 16) => RTX_32X16,
(32, 64) => RTX_32X64,
(64, 32) => RTX_64X32,
(4, 16) => RTX_4X16,
(16, 4) => RTX_16X4,
(8, 32) => RTX_8X32,
(32, 8) => RTX_32X8,
(16, 64) => RTX_16X64,
(64, 16) => RTX_64X16,
(4, 32) => RTX_4X32,
(32, 4) => RTX_32X4,
(8, 64) => RTX_8X64,
(64, 8) => RTX_64X8,
(4, 64) => RTX_4X64,
(64, 4) => RTX_64X4,
_ => unreachable!("unsupported chroma/DC tx {w}x{h}"),
}
}
pub(crate) fn reconstruct_chroma(
pred: f32,
lev: &[f32],
qstep: i32,
scan: &[u16],
w: usize,
h: usize,
bd: i32,
) -> Vec<f32> {
let (cw, ch) = (w.min(32), h.min(32));
let txs = dc_tx_scale(w, h);
let tx = dc_tx_index(w, h);
let mut coeff = vec![0i32; cw * ch];
let wscan = scan.get(1).is_some_and(|&v| v as usize == cw);
let sh = (cw as u32).trailing_zeros();
let smask = cw - 1;
for (&l, &rc) in lev.iter().zip(scan.iter()) {
if l != 0.0 {
let rc = rc as usize;
let (row, col) = if wscan {
(rc >> sh, rc & smask)
} else {
(rc & 31, rc >> 5)
};
let li = l as i64;
let mag = (li.abs() * qstep as i64) & 0xffffff;
let rounded = (mag + (1 << 2)) >> 3; let dqmag = (rounded >> txs) as i32;
coeff[col * ch + row] = if li < 0 { -dqmag } else { dqmag };
}
}
let p = pred.fast_round() as i32;
let mut out = vec![0f32; w * h];
crate::av2::av2_itx::inv_txfm_recon_f32(&mut out, &coeff, 0, tx, bd, |_| p);
out
}
pub(crate) fn reconstruct_chroma_cfl(
pred: &[i32],
lev: &[f32],
qstep: i32,
scan: &[u16],
w: usize,
h: usize,
bd: i32,
) -> Vec<f32> {
let (cw, ch) = (w.min(32), h.min(32));
let txs = dc_tx_scale(w, h);
let tx = dc_tx_index(w, h);
let mut coeff = vec![0i32; cw * ch];
for (&l, &rc) in lev.iter().zip(scan.iter()) {
if l != 0.0 {
let (col, row) = (rc as usize >> 5, rc as usize & 31);
let li = l as i64;
let mag = (li.abs() * qstep as i64) & 0xffffff;
let rounded = (mag + (1 << 2)) >> 3;
let dqmag = (rounded >> txs) as i32;
coeff[col * ch + row] = if li < 0 { -dqmag } else { dqmag };
}
}
let mut out = vec![0f32; w * h];
crate::av2::av2_itx::inv_txfm_recon_f32(&mut out, &coeff, 0, tx, bd, |i| pred[i]);
out
}
#[rustfmt::skip]
pub(crate) fn reconstruct_luma16_adst(
pred: &[f32],
lev: &[f32],
qstep: i32,
scan: &[u16],
row_adst: bool,
col_adst: bool,
bd: i32,
) -> [f32; 256] {
let mut coeff = [0i32; 256];
for (&l, &rc) in lev[..256].iter().zip(scan.iter()) {
if l != 0.0 {
let (col, row) = (rc as usize >> 5, rc as usize & 31);
let li = l as i64;
let mag = (li.abs() * qstep as i64) & 0xffffff;
let rounded = (mag + (1 << 2)) >> 3;
let dqmag = rounded as i32;
coeff[col * 16 + row] = if li < 0 { -dqmag } else { dqmag };
}
}
let txtp = (if row_adst { 2 } else { 0 }) | ((if col_adst { 2 } else { 0 }) << 5);
let mut out = [0f32; 256];
crate::av2::av2_itx::inv_txfm_recon_f32(
&mut out,
&coeff,
txtp,
crate::av2::av2_itx::tx_size::TX_16X16,
bd,
|i| (pred[i] + 0.5) as i32,
);
out
}
pub(crate) fn reconstruct_luma16(
pred: &[f32],
lev: &[f32],
qstep: i32,
scan: &[u16],
bd: i32,
) -> [f32; 256] {
let mut coeff = [0i32; 256];
for (&l, &rc) in lev[..256].iter().zip(scan[..256].iter()) {
if l != 0.0 {
let (col, row) = (rc as usize >> 5, rc as usize & 31);
let li = l as i64;
let mag = (li.abs() * qstep as i64) & 0xffffff;
let rounded = (mag + (1 << 2)) >> 3; let dqmag = rounded as i32; coeff[col * 16 + row] = if li < 0 { -dqmag } else { dqmag };
}
}
let mut out = [0f32; 256];
crate::av2::av2_itx::inv_txfm_recon_f32(
&mut out,
&coeff,
0,
crate::av2::av2_itx::tx_size::TX_16X16,
bd,
|i| (pred[i] + 0.5) as i32,
);
out
}
pub(crate) fn reconstruct_luma_64x16(
pred: &[f32],
lev: &[f32],
qstep: i32,
scan: &[u16],
bd: i32,
) -> [f32; 1024] {
let h = 16usize;
let mut coeff = [0i32; 512];
for (&l, &rc) in lev[..512].iter().zip(scan[..512].iter()) {
if l != 0.0 {
let (col, row) = (rc as usize >> 5, rc as usize & 31);
let li = l as i64;
let mag = (li.abs() * qstep as i64) & 0xffffff;
let rounded = (mag + (1 << 2)) >> 3;
let dqmag = (rounded >> 1) as i32; coeff[col * h + row] = if li < 0 { -dqmag } else { dqmag };
}
}
let mut out = [0f32; 1024];
crate::av2::av2_itx::inv_txfm_recon_f32(
&mut out,
&coeff,
0,
crate::av2::av2_itx::tx_size::RTX_64X16,
bd,
|i| (pred[i] + 0.5) as i32,
);
out
}
pub(crate) fn reconstruct_luma_16x64(
pred: &[f32],
lev: &[f32],
qstep: i32,
scan: &[u16],
bd: i32,
) -> [f32; 1024] {
let ch = 32usize;
let mut coeff = [0i32; 512];
for (&l, &rc) in lev[..512].iter().zip(scan[..512].iter()) {
if l != 0.0 {
let (row, col) = (rc as usize >> 4, rc as usize & 15);
let li = l as i64;
let mag = (li.abs() * qstep as i64) & 0xffffff;
let rounded = (mag + (1 << 2)) >> 3;
let dqmag = (rounded >> 1) as i32; coeff[col * ch + row] = if li < 0 { -dqmag } else { dqmag };
}
}
let mut out = [0f32; 1024];
crate::av2::av2_itx::inv_txfm_recon_f32(
&mut out,
&coeff,
0,
crate::av2::av2_itx::tx_size::RTX_16X64,
bd,
|i| (pred[i] + 0.5) as i32,
);
out
}
pub(crate) fn reconstruct_luma(
pred: &[f32],
lev: &[f32],
qstep: i32,
scan: &[u16],
bd: i32,
) -> [f32; 1024] {
let mut coeff = [0i32; 1024];
for (&l, &rc) in lev[..1024].iter().zip(scan[..1024].iter()) {
if l != 0.0 {
let (col, row) = (rc as usize >> 5, rc as usize & 31);
let li = l as i64;
let mag = (li.abs() * qstep as i64) & 0xffffff;
let rounded = (mag + (1 << 2)) >> 3; let dqmag = (rounded >> 1) as i32; coeff[col * 32 + row] = if li < 0 { -dqmag } else { dqmag };
}
}
let mut out = [0f32; 1024];
crate::av2::av2_itx::inv_txfm_recon_f32(
&mut out,
&coeff,
0,
crate::av2::av2_itx::tx_size::TX_32X32,
bd,
|i| (pred[i] + 0.5) as i32,
);
out
}