const RDMULT_Q2_NUM_LD: i64 = 82;
const RDMULT_Q2_DEN: i64 = 32;
#[inline]
pub(crate) fn rd_mult(qstep: u32) -> f32 {
let q = qstep as i64;
(q * q * RDMULT_Q2_NUM_LD / RDMULT_Q2_DEN) as f32
}
#[inline]
pub(crate) fn rd_cost(distortion: f32, rate_bits: f32, qstep: u32) -> f32 {
distortion + rate_bits * rd_mult(qstep) / 512.0
}
pub(crate) const SS2_INTER_DIST_W: f32 = 16.0;
#[inline]
pub(crate) fn inter_syntax_bits(
enc: &crate::av2::entropy::RangeEncoder,
skip_ctx: usize,
mode_ctx: usize,
skip_txfm: bool,
mode: usize,
mvd: Option<crate::av2::video::mv::Mv>,
) -> f32 {
let mut bits = enc.estimate_intra_inter_bits(1)
+ enc.estimate_skip_txfm_bits(skip_ctx, usize::from(skip_txfm))
+ enc.estimate_single_ref_bits(enc.ref_rank)
+ enc.estimate_inter_mode_bits(mode_ctx, mode);
if mode != 1 {
bits += enc.estimate_drl_bits(mode_ctx, 0);
}
if let Some(delta) = mvd {
bits += crate::av2::video::mvd::estimate_mvd_qtr_bits(enc, delta.row, delta.col);
}
bits
}
pub(crate) struct NearMvRdSpec {
pub(crate) skip_ctx: usize,
pub(crate) mode_ctx: usize,
pub(crate) skip_txfm: bool,
pub(crate) near_distortion: f32,
pub(crate) new_distortion: f32,
pub(crate) new_mvd: crate::av2::video::mv::Mv,
pub(crate) qstep: u32,
}
#[inline]
pub(crate) fn prefer_nearmv(enc: &crate::av2::entropy::RangeEncoder, spec: NearMvRdSpec) -> bool {
let NearMvRdSpec {
skip_ctx,
mode_ctx,
skip_txfm,
near_distortion,
new_distortion,
new_mvd,
qstep,
} = spec;
let near_rate = inter_syntax_bits(enc, skip_ctx, mode_ctx, skip_txfm, 0, None);
let new_rate = inter_syntax_bits(enc, skip_ctx, mode_ctx, skip_txfm, 2, Some(new_mvd));
rd_cost(near_distortion, near_rate, qstep) <= rd_cost(new_distortion, new_rate, qstep)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::av2::{entropy::RangeEncoder, video::mv::Mv};
#[test]
fn live_inter_syntax_rate_is_finite_and_charges_newmv() {
let mut enc = RangeEncoder::new();
enc.inter_tile = true;
enc.enable_adaptive_cdf(1);
let global = inter_syntax_bits(&enc, 0, 0, true, 1, None);
let newmv = inter_syntax_bits(&enc, 0, 0, false, 2, Some(Mv { row: 8, col: -4 }));
assert!(global.is_finite() && global > 0.0);
assert!(newmv.is_finite() && newmv > global);
}
#[test]
fn live_rate_can_prefer_a_slightly_worse_nearmv_predictor() {
let mut enc = RangeEncoder::new();
enc.inter_tile = true;
enc.enable_adaptive_cdf(1);
assert!(prefer_nearmv(
&enc,
NearMvRdSpec {
skip_ctx: 0,
mode_ctx: 0,
skip_txfm: true,
near_distortion: 101.0,
new_distortion: 100.0,
new_mvd: Mv { row: 24, col: -16 },
qstep: 64,
},
));
}
}