#[derive(Debug, Clone, Copy)]
pub struct MvdCostParams {
pub mag_weight: f32,
pub optimality_weight: f32,
}
impl Default for MvdCostParams {
fn default() -> Self {
Self {
mag_weight: 0.1,
optimality_weight: 2.0,
}
}
}
#[inline]
pub fn compute_mvd_cost(
mvd_value: i32,
mb_residual_energy: f32,
temporal_weight: f32,
i_frame_mult: f32,
params: &MvdCostParams,
) -> f32 {
let mvd_sq = (mvd_value as f32) * (mvd_value as f32);
let magnitude_factor = 1.0 / (1.0 + params.mag_weight * mvd_sq);
let optimality = 1.0 / (1.0 + mb_residual_energy.max(0.0));
let optimality_factor = 1.0 + params.optimality_weight * optimality;
magnitude_factor * optimality_factor * temporal_weight * i_frame_mult
}
#[inline]
pub fn mb_luma_residual_energy(block_ac_energies: &[f32], mb_idx: u32) -> f32 {
let start = mb_idx as usize * 26;
let end = start + 16;
if end <= block_ac_energies.len() {
block_ac_energies[start..end].iter().copied().sum()
} else {
0.0
}
}
#[cfg(test)]
mod tests {
use super::*;
fn default_params() -> MvdCostParams {
MvdCostParams::default()
}
#[test]
fn cost_decreases_as_mvd_magnitude_increases() {
let p = default_params();
let c1 = compute_mvd_cost(1, 10.0, 1.0, 1.0, &p);
let c2 = compute_mvd_cost(2, 10.0, 1.0, 1.0, &p);
let c5 = compute_mvd_cost(5, 10.0, 1.0, 1.0, &p);
let c10 = compute_mvd_cost(10, 10.0, 1.0, 1.0, &p);
assert!(c1 > c2, "|mvd|=1 should cost more than |mvd|=2");
assert!(c2 > c5, "|mvd|=2 should cost more than |mvd|=5");
assert!(c5 > c10, "|mvd|=5 should cost more than |mvd|=10");
}
#[test]
fn cost_symmetric_in_mvd_sign() {
let p = default_params();
let c_pos = compute_mvd_cost(3, 10.0, 1.0, 1.0, &p);
let c_neg = compute_mvd_cost(-3, 10.0, 1.0, 1.0, &p);
assert_eq!(c_pos, c_neg);
}
#[test]
fn cost_decreases_as_residual_energy_grows() {
let p = default_params();
let c_low = compute_mvd_cost(3, 0.0, 1.0, 1.0, &p);
let c_mid = compute_mvd_cost(3, 10.0, 1.0, 1.0, &p);
let c_high = compute_mvd_cost(3, 100.0, 1.0, 1.0, &p);
assert!(c_low > c_mid);
assert!(c_mid > c_high);
}
#[test]
fn cost_factors_temporal_weight_and_i_frame() {
let p = default_params();
let base = compute_mvd_cost(3, 10.0, 1.0, 1.0, &p);
let halved = compute_mvd_cost(3, 10.0, 0.5, 1.0, &p);
let doubled_iframe = compute_mvd_cost(3, 10.0, 1.0, 2.0, &p);
assert!((halved - base * 0.5).abs() < 1e-6);
assert!((doubled_iframe - base * 2.0).abs() < 1e-6);
}
#[test]
fn cost_matches_reference_formula_at_defaults() {
let p = default_params();
let c = compute_mvd_cost(3, 10.0, 1.0, 1.0, &p);
assert!((c - 0.62201).abs() < 1e-4, "got {c}");
}
#[test]
fn cost_stays_finite_for_extreme_inputs() {
let p = default_params();
let c = compute_mvd_cost(1000, 1e9, 1.0, 1.0, &p);
assert!(c.is_finite());
assert!(c >= 0.0);
}
#[test]
fn cost_zero_residual_gives_maximum_optimality_factor() {
let p = default_params();
let c_hot = compute_mvd_cost(3, 0.0, 1.0, 1.0, &p);
let magnitude = 1.0 / (1.0 + 0.1 * 9.0); let expected = magnitude * 3.0;
assert!((c_hot - expected).abs() < 1e-4);
}
#[test]
fn mb_luma_residual_energy_sums_slots_zero_through_fifteen() {
let mut energies = vec![0.0f32; 2 * 26];
for slot in 0..16 {
energies[slot] = 1.0;
}
for slot in 16..26 {
energies[slot] = 99.0;
}
assert!(
(mb_luma_residual_energy(&energies, 0) - 16.0).abs() < 1e-5,
"expected 16.0, got {}",
mb_luma_residual_energy(&energies, 0)
);
assert_eq!(mb_luma_residual_energy(&energies, 1), 0.0);
}
#[test]
fn mb_luma_residual_energy_out_of_bounds_returns_zero() {
let energies = vec![1.0f32; 10]; assert_eq!(mb_luma_residual_energy(&energies, 0), 0.0);
assert_eq!(mb_luma_residual_energy(&energies, 99), 0.0);
}
}