use crate::config::EncoderConfig;
use crate::RefFrame;
use rusty_h264_common::inter::mc_luma;
use rusty_h264_common::transform::hadamard_4x4;
use rusty_h264_common::YuvFrame;
fn satd4(res: &[i32; 16]) -> i64 {
hadamard_4x4(res).iter().map(|&v| v.unsigned_abs() as i64).sum()
}
fn coded_luma(cfg: &EncoderConfig, frame: &YuvFrame) -> (Vec<u8>, usize, usize) {
let (cw, ch) = (cfg.mb_width() * 16, cfg.mb_height() * 16);
let (w, h) = (frame.width, frame.height);
let mut y = vec![0u8; cw * ch];
for j in 0..ch {
for i in 0..cw {
y[j * cw + i] = frame.y[j.min(h - 1) * w + i.min(w - 1)];
}
}
(y, cw, ch)
}
pub fn complexity(cfg: &EncoderConfig, frame: &YuvFrame, reference: Option<&RefFrame>) -> f64 {
let (sy, cw, ch) = coded_luma(cfg, frame);
let (mb_w, mb_h) = (cfg.mb_width(), cfg.mb_height());
let mut total = 0i64;
for mb_y in 0..mb_h {
for mb_x in 0..mb_w {
total += match reference {
None => intra_activity(&sy, cw, mb_x, mb_y),
Some(r) => inter_activity(&sy, cw, ch, &r.y, mb_x, mb_y),
};
}
}
(total as f64).max(1.0)
}
fn intra_activity(sy: &[u8], cw: usize, mb_x: usize, mb_y: usize) -> i64 {
let mut s = 0;
for by in 0..4 {
for bx in 0..4 {
let mut blk = [0i32; 16];
for dy in 0..4 {
for dx in 0..4 {
blk[dy * 4 + dx] =
sy[(mb_y * 16 + by * 4 + dy) * cw + mb_x * 16 + bx * 4 + dx] as i32;
}
}
let h = hadamard_4x4(&blk);
s += h[1..].iter().map(|&v| v.unsigned_abs() as i64).sum::<i64>();
}
}
s
}
fn inter_activity(sy: &[u8], cw: usize, ch: usize, ref_y: &[u8], mb_x: usize, mb_y: usize) -> i64 {
const CANDS: [(i32, i32); 9] = [
(0, 0), (4, 0), (-4, 0), (0, 4), (0, -4), (8, 0), (-8, 0), (0, 8), (0, -8),
];
let mut best = i64::MAX;
for &(mvx, mvy) in &CANDS {
let mut pred = [0u8; 256];
mc_luma(ref_y, cw, ch, mb_x * 16, mb_y * 16, 16, 16, mvx, mvy, &mut pred);
let mut s = 0;
for by in 0..4 {
for bx in 0..4 {
let mut res = [0i32; 16];
for dy in 0..4 {
for dx in 0..4 {
res[dy * 4 + dx] = sy
[(mb_y * 16 + by * 4 + dy) * cw + mb_x * 16 + bx * 4 + dx]
as i32
- pred[(by * 4 + dy) * 16 + (bx * 4 + dx)] as i32;
}
}
s += satd4(&res);
}
}
best = best.min(s);
}
best
}