use crate::intrapred::DC_PRED;
use crate::tables::{COEFF_BASE_RANGE, EOB_BITW, NUM_BASE_LEVELS};
pub(crate) fn est_block_bits(cf: &[i32], scan: &[usize]) -> u32 {
let mut eob_idx: i32 = -1;
for (i, &rc) in scan.iter().enumerate() {
if cf[rc] != 0 {
eob_idx = i as i32;
}
}
if eob_idx < 0 {
return 1;
}
let mag: u32 = cf.iter().map(|&c| c.unsigned_abs()).sum();
mag + EOB_BITW * (eob_idx as u32 + 1)
}
pub(crate) fn coef_rate_bits(level: u32) -> f64 {
match level {
0 => 0.9, 1 => 1.7 + 1.0,
2 => 2.6 + 1.0,
_ => {
let mut b = 3.0 + 1.0; let total_br = ((level as i32) - 3).min(COEFF_BASE_RANGE); let steps = (total_br / 3 + 1) as f64; b += steps * 1.3;
if level >= 15 {
let v = level - 15;
b += 2.0 * ((32 - (v + 1).leading_zeros()) as f64) - 1.0; }
b
}
}
}
pub(crate) const TRELLIS_LAMBDA0: f64 = 0.05;
pub(crate) const ADST_ADST_TX8_IDX: usize = 4;
pub(crate) const ADST_DCT_TX8_IDX: usize = 5;
pub(crate) const DCT_ADST_TX8_IDX: usize = 6;
pub(crate) const ADST_ADST_TX16_IDX: usize = 2;
pub(crate) const ADST_DCT_TX16_IDX: usize = 3;
pub(crate) const DCT_ADST_TX16_IDX: usize = 4;
pub(crate) fn trellis_lambda() -> f64 {
TRELLIS_LAMBDA0
}
#[allow(dead_code)]
#[inline]
fn def_kf_rd_multiplier(q: f64) -> f64 {
3.3 + 0.0015 * q
}
#[inline]
pub(crate) fn aom_ssimulacra2_rdmult_weight(qindex: u8) -> f64 {
let w = (((255i32 - qindex as i32) * 3) / 4).clamp(0, 72) + 128;
w as f64 / 128.0
}
#[allow(dead_code)]
pub(crate) const AOM_RDMULT_CALIB: f64 = 1.0 / (1 << 4) as f64;
#[allow(dead_code)]
#[inline]
pub(crate) fn mode_lambda_aom(dc_q: f64, qindex: u8, bd: u8, tune_ssimulacra2: bool) -> f64 {
let mut rdmult = dc_q * dc_q * def_kf_rd_multiplier(dc_q);
if tune_ssimulacra2 {
rdmult *= aom_ssimulacra2_rdmult_weight(qindex);
}
rdmult *= match bd {
10 => 1.0 / (1 << 4) as f64,
12 => 1.0 / (1 << 8) as f64,
_ => 1.0,
};
rdmult * (1.0 / 1024.0) * AOM_RDMULT_CALIB
}
#[inline]
pub(crate) fn mode_lambda_weight(qindex: u8, tune: bool) -> f64 {
if tune {
aom_ssimulacra2_rdmult_weight(qindex)
} else {
1.0
}
}
pub(crate) const COST_Q_FRAC: u32 = 22;
pub(crate) const COST_Q_SCALE_INV: f64 = 1.0 / (1u32 << COST_Q_FRAC) as f64;
pub(crate) fn cost_q_table() -> &'static [u32; 32769] {
static TABLE: std::sync::OnceLock<Box<[u32; 32769]>> = std::sync::OnceLock::new();
TABLE.get_or_init(|| {
let mut t = Box::new([0u32; 32769]);
for (p, slot) in t.iter_mut().enumerate().skip(1) {
let bits = -((p as f64) * (1.0 / 32768.0)).log2();
*slot = (bits * (1u32 << COST_Q_FRAC) as f64).round() as u32;
}
t
})
}
#[inline]
pub(crate) fn cdf_cost(cdf: &[u16], s: usize) -> f64 {
let fl = if s > 0 { cdf[s - 1] as i32 } else { 32768 };
let fh = cdf[s] as i32;
let p = (fl - fh).max(1) as usize;
cost_q_table()[p] as f64 * COST_Q_SCALE_INV
}
#[inline]
pub(crate) fn golomb_cost(v: u32) -> f64 {
let len = 32 - (v + 1).leading_zeros();
(2 * len - 1) as f64
}
pub(crate) fn hi_tok_cost(m: u32, br_cdf: &[u16]) -> f64 {
let total_br = (m as i32 - (NUM_BASE_LEVELS + 1)).min(COEFF_BASE_RANGE);
let mut coded = 0i32;
let mut bits = 0.0;
for _ in 0..(COEFF_BASE_RANGE / 3) {
let s = (total_br - coded).min(3);
bits += cdf_cost(br_cdf, s as usize);
coded += s;
if s < 3 {
break;
}
}
if m >= 15 {
bits += golomb_cost(m - 15);
}
bits
}
pub(crate) fn block_rate_bits(cf: &[i32], scan: &[usize]) -> f64 {
let mut eob: i32 = -1;
for (i, &rc) in scan.iter().enumerate() {
if cf[rc] != 0 {
eob = i as i32;
}
}
if eob < 0 {
return 1.0; }
let mut bits = 2.0; for &rc in scan.iter().take(eob as usize + 1) {
bits += coef_rate_bits(cf[rc].unsigned_abs());
}
bits
}
pub(crate) const MODE_LAMBDA0: f64 = 0.02;
#[inline]
pub(crate) fn mode_lambda() -> f64 {
MODE_LAMBDA0
}
#[inline]
pub(crate) fn mode_signal_bits(m: usize) -> f64 {
if m == DC_PRED { 0.0 } else { MODE_SIGNAL_BITS }
}
pub(crate) const MODE_SIGNAL_BITS: f64 = 30.0;