#![allow(
clippy::cast_possible_truncation,
reason = "residual samples (src - pred) lie in -255..=255 and the broadcast DC \
in i16 range, so the casts reproduce the reference encoder's int16_t \
wrapping; the test pattern casts truncate intentionally"
)]
use crate::lossy::bool_enc::BoolEncoder;
use crate::lossy::constants::{
B_DC_PRED, BMODES_PROBA, COEFFS_PROBA_0, CoeffProbas, CoeffStats, CoeffUpdateFlags, DC_PRED,
H_PRED, NUM_BMODES, NUM_MB_SEGMENTS, TM_PRED, V_PRED,
};
use crate::lossy::decode::{FilterHeader, MbData, SegmentHeader};
use crate::lossy::enc_header::{
HeaderParams, SegmentParams, frame_header_bytes, write_control_header,
};
use crate::lossy::fdct::{fdct4x4, fwht};
use crate::lossy::idct::{transform_one, transform_wht};
use crate::lossy::loop_filter::FInfo;
use crate::lossy::predict::{predict_chroma8, predict_luma4, predict_luma16};
use crate::lossy::prelude::*;
use crate::lossy::prob_opt;
use crate::lossy::quant::{QPair, Quantized, Quantizer, quantize_block};
use crate::lossy::reconstruct::{
Planes, compute_fstrengths, fill_top_right_lane, filter_frame, reconstruct_mb_at, resolve_finfo,
};
use crate::lossy::rgb_to_yuv::{self, SourceYuv};
use crate::lossy::tokens::{
Block, MbTokens, NzContext, count_mb_residuals, emit_mb_residuals, put_bmode, put_is_i4x4,
put_segment_id, put_uvmode, put_ymode16,
};
use crate::lossy::trellis::{
RD_DISTO_MULT, block_token_cost, trellis_lambda, trellis_quantize_block,
};
use crate::lossy::work::work;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub(crate) enum Effort {
Fast,
Full,
Best,
}
impl Effort {
const fn search_modes(self) -> bool {
matches!(self, Self::Full | Self::Best)
}
const fn optimize_probas(self) -> bool {
matches!(self, Self::Full | Self::Best)
}
const fn consider_skip(self) -> bool {
matches!(self, Self::Full | Self::Best)
}
const fn apply_filter(self) -> bool {
matches!(self, Self::Full | Self::Best)
}
const fn uses_i4x4(self) -> bool {
matches!(self, Self::Best)
}
const fn uses_trellis(self) -> bool {
matches!(self, Self::Full | Self::Best)
}
const fn uses_segments(self) -> bool {
matches!(self, Self::Full | Self::Best)
}
}
#[must_use]
pub(crate) fn encode_frame(
rgba: &[u8],
width: usize,
height: usize,
base_q: i32,
effort: Effort,
) -> Vec<u8> {
encode_frame_impl(rgba, width, height, base_q, effort).0
}
#[derive(Clone, Copy)]
struct SkipCoding {
use_skip: bool,
skip_p: u8,
}
struct MbPlan {
ymode: u8,
imodes: [u8; 16],
uvmode: u8,
is_i4x4: bool,
skippable: bool,
has_residual: bool,
tokens: MbTokens,
segment: u8,
}
fn encode_frame_impl(
rgba: &[u8],
width: usize,
height: usize,
base_q: i32,
effort: Effort,
) -> (Vec<u8>, Planes) {
let gates = SearchGates {
search_modes: effort.search_modes(),
uses_i4x4: effort.uses_i4x4(),
uses_trellis: effort.uses_trellis(),
};
let FramePlan {
plans: mb_plans,
mut planes,
mb_w,
mb_h,
seg_params,
} = plan_frame(rgba, width, height, base_q, gates, effort.uses_segments());
let skip = resolve_skip(&mb_plans, mb_w * mb_h, effort.consider_skip());
let filter = choose_filter(base_q, effort.apply_filter());
let header = HeaderParams {
base_q,
filter: &filter,
segments: seg_params,
};
let (part0_bytes, token_bytes) = if effort.optimize_probas() {
let (part0, token, _default_total, _optimized_total) =
emit_best_partitions(&mb_plans, mb_w, mb_h, header, skip);
(part0, token)
} else {
emit_partitions(
&mb_plans,
mb_w,
mb_h,
header,
&COEFFS_PROBA_0,
&CoeffUpdateFlags::default(),
skip,
)
};
apply_loop_filter(&mut planes, &mb_plans, mb_w, mb_h, &filter, skip.use_skip);
let fps = u32::try_from(part0_bytes.len()).unwrap_or(0);
let header = frame_header_bytes(
fps,
u16::try_from(width).unwrap_or(0),
u16::try_from(height).unwrap_or(0),
);
let mut payload = Vec::with_capacity(header.len() + part0_bytes.len() + token_bytes.len());
payload.extend_from_slice(&header);
payload.extend_from_slice(&part0_bytes);
payload.extend_from_slice(&token_bytes);
(payload, planes)
}
fn resolve_skip(mb_plans: &[MbPlan], total: usize, consider_skip: bool) -> SkipCoding {
let nb_skip = mb_plans.iter().filter(|p| p.skippable).count();
let skip_p = ((total - nb_skip) * 255)
.checked_div(total)
.and_then(|p| u8::try_from(p).ok())
.unwrap_or(255);
let use_skip = consider_skip && nb_skip > 0 && skip_p < 250;
SkipCoding { use_skip, skip_p }
}
#[derive(Clone, Copy)]
struct SearchGates {
search_modes: bool,
uses_i4x4: bool,
uses_trellis: bool,
}
const KMEANS_ITERS: usize = 6;
const SEG_Q_FINER: i64 = 4;
const SEG_Q_COARSER: i64 = 16;
const SEG_SPREAD_DEN: i64 = 4;
struct Segmentation {
seg_ids: Vec<u8>,
base_q: [i32; 4],
params: Option<SegmentParams>,
}
fn plan_segmentation(src: &SourceYuv, base_q: i32, enabled: bool) -> Segmentation {
let n = src.mb_w * src.mb_h;
let single = || Segmentation {
seg_ids: vec![0u8; n],
base_q: [base_q; 4],
params: None,
};
if !enabled {
return single();
}
let mut complexity = Vec::with_capacity(n);
for mb_y in 0..src.mb_h {
for mb_x in 0..src.mb_w {
complexity.push(mb_complexity(src, mb_x, mb_y));
}
}
let min_c = complexity.iter().copied().min().unwrap_or(0);
let max_c = complexity.iter().copied().max().unwrap_or(0);
if max_c <= 0 || (max_c - min_c) * SEG_SPREAD_DEN < max_c {
return single();
}
let (seg_ids, count, seg_c) = kmeans_segments(&complexity);
if count <= 1 {
return single();
}
let seg_base_q = segment_base_qs(base_q, count, seg_c);
let mut quantizer = [0i32; 4];
for (delta, &bq) in quantizer.iter_mut().zip(&seg_base_q) {
*delta = bq - base_q;
}
let tree_probs = segment_tree_probs(&seg_ids);
Segmentation {
seg_ids,
base_q: seg_base_q,
params: Some(SegmentParams {
quantizer,
tree_probs,
}),
}
}
fn mb_complexity(src: &SourceYuv, mb_x: usize, mb_y: usize) -> i64 {
let stride = src.y_stride();
let base = mb_y * 16 * stride + mb_x * 16;
let mut energy = 0i64;
for n in 0..16usize {
let (bx, by) = ((n % 4) * 4, (n / 4) * 4);
let mut block = [0i16; 16];
for row in 0..4 {
for col in 0..4 {
block[row * 4 + col] = i16::from(src.y[base + (by + row) * stride + (bx + col)]);
}
}
work!(MbComplexityFdct);
for &c in fdct4x4(block).iter().skip(1) {
energy += i64::from(c.unsigned_abs());
}
}
energy
}
fn kmeans_segments(complexity: &[i64]) -> (Vec<u8>, usize, [i64; 4]) {
let n = complexity.len();
let min_c = complexity.iter().copied().min().unwrap_or(0);
let max_c = complexity.iter().copied().max().unwrap_or(0);
if n == 0 || min_c == max_c {
return (vec![0u8; n], 1, [min_c; 4]);
}
let span = max_c - min_c;
let mut centroids = [0i64; 4];
for (k, cen) in centroids.iter_mut().enumerate() {
*cen = min_c + span * i64::try_from(k).unwrap_or(0) / 3;
}
let mut assign = vec![0u8; n];
for _ in 0..KMEANS_ITERS {
assign_nearest(complexity, centroids, &mut assign);
update_centroids(complexity, &assign, &mut centroids);
}
assign_nearest(complexity, centroids, &mut assign);
let (sum, cnt) = cluster_sums(complexity, &assign);
let mut remap = [0u8; 4];
let mut seg_c = [0i64; 4];
let mut count = 0usize;
for k in 0..4 {
if cnt[k] > 0 {
remap[k] = u8::try_from(count).unwrap_or(0);
seg_c[count] = sum[k] / cnt[k];
count += 1;
}
}
let seg_ids = assign.iter().map(|&a| remap[usize::from(a)]).collect();
(seg_ids, count, seg_c)
}
fn assign_nearest(complexity: &[i64], centroids: [i64; 4], assign: &mut [u8]) {
for (&c, a) in complexity.iter().zip(assign.iter_mut()) {
let mut best = 0usize;
let mut best_d = i64::MAX;
for (k, &cen) in centroids.iter().enumerate() {
work!(KmeansCompare);
let d = (c - cen).abs();
if d < best_d {
best_d = d;
best = k;
}
}
*a = u8::try_from(best).unwrap_or(0);
}
}
fn cluster_sums(complexity: &[i64], assign: &[u8]) -> ([i64; 4], [i64; 4]) {
let mut sum = [0i64; 4];
let mut cnt = [0i64; 4];
for (&c, &a) in complexity.iter().zip(assign) {
let k = usize::from(a);
sum[k] += c;
cnt[k] += 1;
}
(sum, cnt)
}
fn update_centroids(complexity: &[i64], assign: &[u8], centroids: &mut [i64; 4]) {
let (sum, cnt) = cluster_sums(complexity, assign);
for (cen, (&s, &c)) in centroids.iter_mut().zip(sum.iter().zip(&cnt)) {
if c > 0 {
*cen = s / c;
}
}
}
fn segment_base_qs(base_q: i32, count: usize, seg_c: [i64; 4]) -> [i32; 4] {
let mut qs = [base_q; 4];
if count <= 1 {
return qs;
}
let used = &seg_c[..count];
let min_c = used.iter().copied().min().unwrap_or(0);
let max_c = used.iter().copied().max().unwrap_or(0);
if max_c == min_c {
return qs;
}
let span = max_c - min_c;
let range = SEG_Q_FINER + SEG_Q_COARSER;
for (q, &c) in qs.iter_mut().zip(used) {
let offset = (c - min_c) * range / span - SEG_Q_FINER;
*q = (base_q + i32::try_from(offset).unwrap_or(0)).clamp(0, 127);
}
qs
}
fn segment_tree_probs(seg_ids: &[u8]) -> [u8; 3] {
let mut cnt = [0u64; 4];
for &s in seg_ids {
cnt[usize::from(s)] += 1;
}
let n01 = cnt[0] + cnt[1];
let n23 = cnt[2] + cnt[3];
[
tree_prob(n01, n01 + n23),
tree_prob(cnt[0], n01),
tree_prob(cnt[2], n23),
]
}
fn tree_prob(zeros: u64, total: u64) -> u8 {
if total == 0 {
return 128;
}
u8::try_from((zeros * 255 / total).clamp(1, 255)).unwrap_or(128)
}
struct FramePlan {
plans: Vec<MbPlan>,
planes: Planes,
mb_w: usize,
mb_h: usize,
seg_params: Option<SegmentParams>,
}
#[allow(
clippy::too_many_lines,
reason = "a cohesive two-pass macroblock planner: the RGB->YUV + segmentation \
setup and the single MB raster loop (mode search, i4x4 RD, skip/residual \
flags, reconstruction) share tightly-threaded `&mut planes` state, so \
splitting it would need a 7+ argument helper and fragment one unit"
)]
fn plan_frame(
rgba: &[u8],
width: usize,
height: usize,
base_q: i32,
gates: SearchGates,
uses_segments: bool,
) -> FramePlan {
let src = rgb_to_yuv::from_rgba(rgba, width, height);
let (mb_w, mb_h) = (src.mb_w, src.mb_h);
let seg = plan_segmentation(&src, base_q, uses_segments);
let quants = seg.base_q.map(Quantizer::new);
let mut planes = Planes::new(mb_w, mb_h);
let mb_plans = run_mb_planning(&mut planes, &src, &seg.seg_ids, &quants, mb_w, mb_h, gates);
FramePlan {
plans: mb_plans,
planes,
mb_w,
mb_h,
seg_params: seg.params,
}
}
#[allow(
clippy::too_many_arguments,
reason = "the per-macroblock plan is a pure function of its position, the three \
independent edge flags, its segment/quantizer and the search gates; \
bundling them would only move the argument list into a struct literal"
)]
fn plan_one_mb(
planes: &mut Planes,
src: &SourceYuv,
mb_x: usize,
mb_y: usize,
has_top: bool,
has_left: bool,
is_rightmost: bool,
segment: u8,
plan: QuantPlan,
gates: SearchGates,
) -> MbPlan {
let y_off = (mb_y * 16 + 1) * planes.y_stride + (mb_x * 16 + 1);
let uv_off = (mb_y * 8 + 1) * planes.uv_stride + (mb_x * 8 + 1);
let (ymode, uvmode, mut coeffs, mut tokens) = if gates.search_modes {
let (ymode, luma) =
select_luma16_mode_rd(planes, y_off, src, (mb_x, mb_y), has_top, has_left, plan);
let (uvmode, chroma) =
select_chroma8_mode_rd(planes, uv_off, src, (mb_x, mb_y), has_top, has_left, plan);
let mut coeffs = [0i16; 384];
coeffs[..256].copy_from_slice(&luma.coeffs);
coeffs[256..].copy_from_slice(&chroma.coeffs);
let tokens = MbTokens {
is_i4x4: false,
y2: luma.y2,
luma: luma.blocks,
chroma: chroma.blocks,
};
(ymode, uvmode, coeffs, tokens)
} else {
let (y_stride, uv_stride) = (planes.y_stride, planes.uv_stride);
predict_luma16(&mut planes.y, y_off, y_stride, DC_PRED, has_top, has_left);
predict_chroma8(&mut planes.u, uv_off, uv_stride, DC_PRED, has_top, has_left);
predict_chroma8(&mut planes.v, uv_off, uv_stride, DC_PRED, has_top, has_left);
let (coeffs, tokens) = encode_mb(src, planes, mb_x, mb_y, plan);
(DC_PRED, DC_PRED, coeffs, tokens)
};
let mut is_i4x4 = false;
let mut imodes = [0u8; 16];
imodes[0] = ymode;
let i4x4 = gates
.uses_i4x4
.then(|| {
try_i4x4_luma(
planes,
&coeffs,
&tokens,
src,
(mb_x, mb_y),
has_top,
is_rightmost,
plan,
)
})
.flatten();
if let Some(i4) = i4x4 {
is_i4x4 = true;
imodes = i4.imodes;
coeffs[..256].copy_from_slice(&i4.coeffs);
tokens.is_i4x4 = true;
tokens.y2 = Block::default();
tokens.luma = i4.luma;
}
let skippable = !is_i4x4
&& tokens.y2.last < 0
&& tokens.luma.iter().all(|b| b.last < 1)
&& tokens.chroma.iter().all(|b| b.last < 0);
let has_residual = coeffs.iter().any(|&c| c != 0);
let mb_data = MbData {
coeffs,
is_i4x4,
imodes,
uvmode,
..MbData::default()
};
reconstruct_mb_at(
planes,
&mb_data,
y_off,
uv_off,
has_top,
has_left,
is_rightmost,
);
MbPlan {
ymode,
imodes,
uvmode,
is_i4x4,
skippable,
has_residual,
tokens,
segment,
}
}
fn plan_frame_serial(
planes: &mut Planes,
src: &SourceYuv,
seg_ids: &[u8],
quants: &[Quantizer; NUM_MB_SEGMENTS],
mb_w: usize,
mb_h: usize,
gates: SearchGates,
) -> Vec<MbPlan> {
let mut mb_plans = Vec::with_capacity(mb_w * mb_h);
for mb_y in 0..mb_h {
for mb_x in 0..mb_w {
let segment = seg_ids[mb_y * mb_w + mb_x];
let plan = QuantPlan {
quant: quants[usize::from(segment)],
uses_trellis: gates.uses_trellis,
};
mb_plans.push(plan_one_mb(
planes,
src,
mb_x,
mb_y,
mb_y > 0,
mb_x > 0,
mb_x == mb_w - 1,
segment,
plan,
gates,
));
}
}
mb_plans
}
#[cfg(not(feature = "rayon"))]
fn run_mb_planning(
planes: &mut Planes,
src: &SourceYuv,
seg_ids: &[u8],
quants: &[Quantizer; NUM_MB_SEGMENTS],
mb_w: usize,
mb_h: usize,
gates: SearchGates,
) -> Vec<MbPlan> {
plan_frame_serial(planes, src, seg_ids, quants, mb_w, mb_h, gates)
}
#[cfg(feature = "rayon")]
const PARALLEL_MB_THRESHOLD: usize = 256;
#[cfg(feature = "rayon")]
struct ReconBlocks {
y: [u8; 256],
u: [u8; 64],
v: [u8; 64],
}
#[cfg(feature = "rayon")]
fn run_mb_planning(
planes: &mut Planes,
src: &SourceYuv,
seg_ids: &[u8],
quants: &[Quantizer; NUM_MB_SEGMENTS],
mb_w: usize,
mb_h: usize,
gates: SearchGates,
) -> Vec<MbPlan> {
use rayon::prelude::*;
let n = mb_w * mb_h;
if n < PARALLEL_MB_THRESHOLD || !gates.search_modes {
return plan_frame_serial(planes, src, seg_ids, quants, mb_w, mb_h, gates);
}
let skew = if gates.uses_i4x4 { 2 } else { 1 };
let mut indexed: Vec<(usize, MbPlan)> = Vec::with_capacity(n);
let num_diagonals = skew * (mb_h - 1) + (mb_w - 1) + 1;
for d in 0..num_diagonals {
let members = diagonal_members(d, mb_w, mb_h, skew);
let results: Vec<(usize, MbPlan, ReconBlocks)> = {
let planes_ref: &Planes = planes;
members
.par_iter()
.with_max_len(1)
.map(|&(mb_x, mb_y)| {
let segment = seg_ids[mb_y * mb_w + mb_x];
let plan = QuantPlan {
quant: quants[usize::from(segment)],
uses_trellis: gates.uses_trellis,
};
SCRATCH.with_borrow_mut(|slot| {
let scratch = slot.get_or_insert_with(MbScratch::new);
scratch.reseed(planes_ref, src, mb_x, mb_y);
let mbplan = plan_one_mb(
&mut scratch.mini,
&scratch.msrc,
0,
0,
mb_y > 0,
mb_x > 0,
mb_x == mb_w - 1,
segment,
plan,
gates,
);
(mb_y * mb_w + mb_x, mbplan, extract_blocks(&scratch.mini))
})
})
.collect()
};
for (idx, mbplan, blocks) in results {
commit_blocks(planes, idx, mb_w, &blocks);
indexed.push((idx, mbplan));
}
}
indexed.sort_by_key(|&(idx, _)| idx);
indexed.into_iter().map(|(_, plan)| plan).collect()
}
#[cfg(feature = "rayon")]
fn diagonal_members(d: usize, mb_w: usize, mb_h: usize, skew: usize) -> Vec<(usize, usize)> {
let mut members = Vec::new();
let mb_y_max = (d / skew).min(mb_h - 1);
for mb_y in 0..=mb_y_max {
let mb_x = d - skew * mb_y;
if mb_x < mb_w {
members.push((mb_x, mb_y));
}
}
members
}
#[cfg(feature = "rayon")]
struct MbScratch {
mini: Planes,
msrc: SourceYuv,
}
#[cfg(feature = "rayon")]
impl MbScratch {
fn new() -> Self {
Self {
mini: Planes::new(1, 1),
msrc: SourceYuv {
y: vec![0u8; 256],
u: vec![0u8; 64],
v: vec![0u8; 64],
mb_w: 1,
mb_h: 1,
},
}
}
fn reseed(&mut self, planes: &Planes, src: &SourceYuv, mb_x: usize, mb_y: usize) {
reseed_mini_planes(&mut self.mini, planes, mb_x, mb_y);
reseed_mini_src(&mut self.msrc, src, mb_x, mb_y);
}
}
#[cfg(feature = "rayon")]
thread_local! {
static SCRATCH: core::cell::RefCell<Option<MbScratch>> =
const { core::cell::RefCell::new(None) };
}
#[cfg(feature = "rayon")]
fn reseed_mini_planes(mini: &mut Planes, planes: &Planes, mb_x: usize, mb_y: usize) {
let ys = planes.y_stride;
let y_off = (mb_y * 16 + 1) * ys + (mb_x * 16 + 1);
let mys = mini.y_stride;
let top = y_off - ys - 1;
mini.y[0..21].copy_from_slice(&planes.y[top..top + 21]);
for j in 0..16 {
mini.y[(j + 1) * mys] = planes.y[y_off + j * ys - 1];
}
let uvs = planes.uv_stride;
let uv_off = (mb_y * 8 + 1) * uvs + (mb_x * 8 + 1);
let muvs = mini.uv_stride;
let ctop = uv_off - uvs - 1;
mini.u[0..9].copy_from_slice(&planes.u[ctop..ctop + 9]);
mini.v[0..9].copy_from_slice(&planes.v[ctop..ctop + 9]);
for j in 0..8 {
mini.u[(j + 1) * muvs] = planes.u[uv_off + j * uvs - 1];
mini.v[(j + 1) * muvs] = planes.v[uv_off + j * uvs - 1];
}
}
#[cfg(feature = "rayon")]
fn reseed_mini_src(msrc: &mut SourceYuv, src: &SourceYuv, mb_x: usize, mb_y: usize) {
let ys = src.y_stride();
for r in 0..16 {
let s = (mb_y * 16 + r) * ys + mb_x * 16;
msrc.y[r * 16..r * 16 + 16].copy_from_slice(&src.y[s..s + 16]);
}
let uvs = src.uv_stride();
for r in 0..8 {
let s = (mb_y * 8 + r) * uvs + mb_x * 8;
msrc.u[r * 8..r * 8 + 8].copy_from_slice(&src.u[s..s + 8]);
msrc.v[r * 8..r * 8 + 8].copy_from_slice(&src.v[s..s + 8]);
}
}
#[cfg(feature = "rayon")]
fn extract_blocks(mini: &Planes) -> ReconBlocks {
let mys = mini.y_stride;
let y_off = mys + 1;
let mut y = [0u8; 256];
for r in 0..16 {
let s = y_off + r * mys;
y[r * 16..r * 16 + 16].copy_from_slice(&mini.y[s..s + 16]);
}
let muvs = mini.uv_stride;
let uv_off = muvs + 1;
let mut u = [0u8; 64];
let mut v = [0u8; 64];
for r in 0..8 {
let s = uv_off + r * muvs;
u[r * 8..r * 8 + 8].copy_from_slice(&mini.u[s..s + 8]);
v[r * 8..r * 8 + 8].copy_from_slice(&mini.v[s..s + 8]);
}
ReconBlocks { y, u, v }
}
#[cfg(feature = "rayon")]
fn commit_blocks(planes: &mut Planes, idx: usize, mb_w: usize, b: &ReconBlocks) {
let (mb_y, mb_x) = (idx / mb_w, idx % mb_w);
let ys = planes.y_stride;
let y_off = (mb_y * 16 + 1) * ys + (mb_x * 16 + 1);
for r in 0..16 {
let dst = y_off + r * ys;
planes.y[dst..dst + 16].copy_from_slice(&b.y[r * 16..r * 16 + 16]);
}
let uvs = planes.uv_stride;
let uv_off = (mb_y * 8 + 1) * uvs + (mb_x * 8 + 1);
for r in 0..8 {
let dst = uv_off + r * uvs;
planes.u[dst..dst + 8].copy_from_slice(&b.u[r * 8..r * 8 + 8]);
planes.v[dst..dst + 8].copy_from_slice(&b.v[r * 8..r * 8 + 8]);
}
}
fn emit_best_partitions(
mb_plans: &[MbPlan],
mb_w: usize,
mb_h: usize,
header: HeaderParams<'_>,
skip: SkipCoding,
) -> (Vec<u8>, Vec<u8>, usize, usize) {
let mut stats = Box::<CoeffStats>::default();
let mut ctx = NzContext::new(mb_w);
work!(TokenPartitionWalk);
for mb_y in 0..mb_h {
for mb_x in 0..mb_w {
let plan = &mb_plans[mb_y * mb_w + mb_x];
if skip.use_skip && plan.skippable {
ctx.skip_mb(mb_x);
} else {
count_mb_residuals(&mut stats, &plan.tokens, &mut ctx, mb_x);
}
}
ctx.init_scanline();
}
let (opt_probas, opt_updated) = prob_opt::optimize_probas(&stats);
let ((part0_d, token_d), (part0_o, token_o)) = emit_partition_candidates(
mb_plans,
mb_w,
mb_h,
header,
skip,
&opt_probas,
&opt_updated,
);
let default_total = part0_d.len() + token_d.len();
let optimized_total = part0_o.len() + token_o.len();
if optimized_total < default_total {
(part0_o, token_o, default_total, optimized_total)
} else {
(part0_d, token_d, default_total, optimized_total)
}
}
#[cfg(not(feature = "rayon"))]
#[allow(
clippy::type_complexity,
reason = "returns the two candidates' (part0, token) byte pairs; naming a \
struct for this one internal call-site would not aid clarity"
)]
fn emit_partition_candidates(
mb_plans: &[MbPlan],
mb_w: usize,
mb_h: usize,
header: HeaderParams<'_>,
skip: SkipCoding,
opt_probas: &CoeffProbas,
opt_updated: &CoeffUpdateFlags,
) -> ((Vec<u8>, Vec<u8>), (Vec<u8>, Vec<u8>)) {
let no_updates = CoeffUpdateFlags::default();
let default = emit_partitions(
mb_plans,
mb_w,
mb_h,
header,
&COEFFS_PROBA_0,
&no_updates,
skip,
);
let optimized = emit_partitions(mb_plans, mb_w, mb_h, header, opt_probas, opt_updated, skip);
(default, optimized)
}
#[cfg(feature = "rayon")]
#[allow(
clippy::type_complexity,
reason = "returns the two candidates' (part0, token) byte pairs; naming a \
struct for this one internal call-site would not aid clarity"
)]
fn emit_partition_candidates(
mb_plans: &[MbPlan],
mb_w: usize,
mb_h: usize,
header: HeaderParams<'_>,
skip: SkipCoding,
opt_probas: &CoeffProbas,
opt_updated: &CoeffUpdateFlags,
) -> ((Vec<u8>, Vec<u8>), (Vec<u8>, Vec<u8>)) {
let no_updates = CoeffUpdateFlags::default();
rayon::join(
|| {
emit_partitions(
mb_plans,
mb_w,
mb_h,
header,
&COEFFS_PROBA_0,
&no_updates,
skip,
)
},
|| emit_partitions(mb_plans, mb_w, mb_h, header, opt_probas, opt_updated, skip),
)
}
fn emit_partitions(
mb_plans: &[MbPlan],
mb_w: usize,
mb_h: usize,
header: HeaderParams<'_>,
probas: &CoeffProbas,
updated: &CoeffUpdateFlags,
skip: SkipCoding,
) -> (Vec<u8>, Vec<u8>) {
work!(TokenPartitionWalk);
let mut part0 = BoolEncoder::new();
write_control_header(
&mut part0,
header,
probas,
updated,
skip.use_skip,
skip.skip_p,
);
let mut token_enc = BoolEncoder::new();
let mut ctx = NzContext::new(mb_w);
let mut intra_t = vec![B_DC_PRED; 4 * mb_w];
let mut intra_l = [B_DC_PRED; 4];
for mb_y in 0..mb_h {
for mb_x in 0..mb_w {
let plan = &mb_plans[mb_y * mb_w + mb_x];
if let Some(seg) = header.segments {
put_segment_id(&mut part0, seg.tree_probs, plan.segment);
}
if skip.use_skip {
part0.put_bool(skip.skip_p, plan.skippable);
}
put_is_i4x4(&mut part0, plan.is_i4x4);
emit_intra_modes(&mut part0, plan, mb_x, &mut intra_t, &mut intra_l);
put_uvmode(&mut part0, plan.uvmode);
if skip.use_skip && plan.skippable {
ctx.skip_mb(mb_x);
} else {
emit_mb_residuals(&mut token_enc, probas, &plan.tokens, &mut ctx, mb_x);
}
}
ctx.init_scanline();
intra_l = [B_DC_PRED; 4];
}
(part0.finish(), token_enc.finish())
}
fn emit_intra_modes(
part0: &mut BoolEncoder,
plan: &MbPlan,
mb_x: usize,
intra_t: &mut [u8],
intra_l: &mut [u8; 4],
) {
let top = 4 * mb_x;
if plan.is_i4x4 {
for (y, left_slot) in intra_l.iter_mut().enumerate() {
let mut left = *left_slot;
for x in 0..4 {
let t = intra_t[top + x];
let mode = plan.imodes[y * 4 + x];
put_bmode(part0, BMODES_PROBA[usize::from(t)][usize::from(left)], mode);
intra_t[top + x] = mode;
left = mode;
}
*left_slot = left;
}
} else {
put_ymode16(part0, plan.ymode);
intra_t[top..top + 4].fill(plan.ymode);
*intra_l = [plan.ymode; 4];
}
}
fn choose_filter(base_q: i32, apply_filter: bool) -> FilterHeader {
let level = if apply_filter {
(base_q * 3 / 8).clamp(0, 63)
} else {
0
};
FilterHeader {
simple: false,
level,
sharpness: 0,
..FilterHeader::default()
}
}
const fn filter_type_of(filter: &FilterHeader) -> u8 {
if filter.level == 0 {
0
} else if filter.simple {
1
} else {
2
}
}
fn apply_loop_filter(
planes: &mut Planes,
mb_plans: &[MbPlan],
mb_w: usize,
mb_h: usize,
filter: &FilterHeader,
use_skip: bool,
) {
let filter_type = filter_type_of(filter);
if filter_type == 0 {
return;
}
let segment = SegmentHeader {
use_segment: false,
update_map: false,
absolute_delta: true,
quantizer: [0; NUM_MB_SEGMENTS],
filter_strength: [0; NUM_MB_SEGMENTS],
};
let fstrengths = compute_fstrengths(&segment, filter);
let finfo: Vec<FInfo> = mb_plans
.iter()
.map(|plan| {
let mb = MbData {
segment: 0,
is_i4x4: plan.is_i4x4,
skip: plan.skippable,
non_zero_y: u32::from(plan.has_residual),
non_zero_uv: 0,
..MbData::default()
};
resolve_finfo(fstrengths, &mb, use_skip)
})
.collect();
filter_frame(planes, &finfo, mb_w, mb_h, filter_type);
}
#[derive(Clone, Copy)]
struct QuantPlan {
quant: Quantizer,
uses_trellis: bool,
}
fn quantize_one(
coeffs: [i16; 16],
pair: QPair,
first: usize,
plane: usize,
uses_trellis: bool,
) -> Quantized {
work!(QuantizeCall);
if uses_trellis {
let lambda = trellis_lambda(pair.ac.q);
trellis_quantize_block(coeffs, pair, first, 0, plane, &COEFFS_PROBA_0, lambda)
} else {
quantize_block(coeffs, pair.dc, pair.ac, first)
}
}
struct Luma16Encode {
coeffs: [i16; 256],
y2: Block,
blocks: [Block; 16],
}
struct Chroma8Encode {
coeffs: [i16; 128],
blocks: [Block; 8],
}
fn encode_luma16_residual(
src: &SourceYuv,
planes: &Planes,
mb_x: usize,
mb_y: usize,
plan: QuantPlan,
) -> Luma16Encode {
let QuantPlan {
quant,
uses_trellis,
} = plan;
let mut coeffs = [0i16; 384];
let y_off = (mb_y * 16 + 1) * planes.y_stride + (mb_x * 16 + 1);
let mut luma_coeffs = [[0i16; 16]; 16];
let mut dcs = [0i16; 16];
for n in 0..16 {
let (bx, by) = ((n % 4) * 4, (n / 4) * 4);
let residual = residual_block(
&src.y,
src.y_stride(),
mb_x * 16 + bx,
mb_y * 16 + by,
&planes.y,
y_off + by * planes.y_stride + bx,
planes.y_stride,
);
luma_coeffs[n] = fdct4x4(residual);
dcs[n] = luma_coeffs[n][0];
}
let y2 = quantize_one(fwht(dcs), quant.y2, 0, 1, uses_trellis);
if y2.last + 1 > 1 {
transform_wht(y2.recon, &mut coeffs);
} else {
let dc0 = ((i32::from(y2.recon[0]) + 3) >> 3) as i16;
for b in 0..16 {
coeffs[b * 16] = dc0;
}
}
let mut blocks = [Block::default(); 16];
for n in 0..16 {
let q = quantize_one(luma_coeffs[n], quant.y1, 1, 0, uses_trellis);
coeffs[n * 16 + 1..n * 16 + 16].copy_from_slice(&q.recon[1..16]);
blocks[n] = Block {
levels: q.levels,
last: q.last,
};
}
let mut luma = [0i16; 256];
luma.copy_from_slice(&coeffs[..256]);
Luma16Encode {
coeffs: luma,
y2: Block {
levels: y2.levels,
last: y2.last,
},
blocks,
}
}
fn encode_chroma8_residual(
src: &SourceYuv,
planes: &Planes,
mb_x: usize,
mb_y: usize,
plan: QuantPlan,
) -> Chroma8Encode {
let QuantPlan {
quant,
uses_trellis,
} = plan;
let uv_off = (mb_y * 8 + 1) * planes.uv_stride + (mb_x * 8 + 1);
let mut coeffs = [0i16; 128];
let mut blocks = [Block::default(); 8];
for (which, plane) in [&planes.u, &planes.v].into_iter().enumerate() {
let src_plane = if which == 0 { &src.u } else { &src.v };
for n in 0..4 {
let (bx, by) = ((n % 2) * 4, (n / 2) * 4);
let residual = residual_block(
src_plane,
src.uv_stride(),
mb_x * 8 + bx,
mb_y * 8 + by,
plane,
uv_off + by * planes.uv_stride + bx,
planes.uv_stride,
);
let q = quantize_one(fdct4x4(residual), quant.uv, 0, 2, uses_trellis);
let idx = which * 4 + n;
coeffs[idx * 16..idx * 16 + 16].copy_from_slice(&q.recon);
blocks[idx] = Block {
levels: q.levels,
last: q.last,
};
}
}
Chroma8Encode { coeffs, blocks }
}
fn encode_mb(
src: &SourceYuv,
planes: &Planes,
mb_x: usize,
mb_y: usize,
plan: QuantPlan,
) -> ([i16; 384], MbTokens) {
let luma = encode_luma16_residual(src, planes, mb_x, mb_y, plan);
let chroma = encode_chroma8_residual(src, planes, mb_x, mb_y, plan);
let mut coeffs = [0i16; 384];
coeffs[..256].copy_from_slice(&luma.coeffs);
coeffs[256..].copy_from_slice(&chroma.coeffs);
(
coeffs,
MbTokens {
is_i4x4: false,
y2: luma.y2,
luma: luma.blocks,
chroma: chroma.blocks,
},
)
}
pub(crate) fn residual_block(
src: &[u8],
src_stride: usize,
src_x: usize,
src_y: usize,
pred: &[u8],
pred_off: usize,
pred_stride: usize,
) -> [i16; 16] {
let mut residual = [0i16; 16];
for row in 0..4 {
let s_row = &src[(src_y + row) * src_stride + src_x..][..4];
let p_row = &pred[pred_off + row * pred_stride..][..4];
for (out, (&s, &p)) in residual[row * 4..][..4]
.iter_mut()
.zip(s_row.iter().zip(p_row))
{
*out = i16::from(s) - i16::from(p);
}
}
residual
}
#[cfg(any(test, feature = "bench"))]
pub(crate) fn residual_block_reference(
src: &[u8],
src_stride: usize,
src_x: usize,
src_y: usize,
pred: &[u8],
pred_off: usize,
pred_stride: usize,
) -> [i16; 16] {
let mut residual = [0i16; 16];
for row in 0..4 {
for col in 0..4 {
let s = i32::from(src[(src_y + row) * src_stride + (src_x + col)]);
let p = i32::from(pred[pred_off + row * pred_stride + col]);
residual[row * 4 + col] = (s - p) as i16;
}
}
residual
}
struct I4x4Luma {
imodes: [u8; 16],
luma: [Block; 16],
coeffs: [i16; 256],
}
const I16X16_MODE_COST: i64 = 2 * 256;
const I4X4_SUBMODE_COST: i64 = 2 * 256;
const I4X4_LAMBDA_SHIFT: u32 = 7;
const LUMA16_LAMBDA_SHIFT: u32 = 7;
const CHROMA_LAMBDA_SHIFT: u32 = 6;
const fn i4x4_lambda(q_ac: i32) -> i64 {
let q = q_ac as i64;
let l = (q * q) >> I4X4_LAMBDA_SHIFT;
if l < 1 { 1 } else { l }
}
const fn luma16_lambda(q_ac: i32) -> i64 {
let q = q_ac as i64;
let l = (3 * q * q) >> LUMA16_LAMBDA_SHIFT;
if l < 1 { 1 } else { l }
}
const fn chroma_lambda(q_ac: i32) -> i64 {
let q = q_ac as i64;
let l = (3 * q * q) >> CHROMA_LAMBDA_SHIFT;
if l < 1 { 1 } else { l }
}
fn luma16_token_bits(y2: Block, luma: &[Block; 16]) -> i64 {
let mut bits = block_token_cost(y2.levels, 0, y2.last, 1, 0, &COEFFS_PROBA_0);
for b in luma {
bits += block_token_cost(b.levels, 1, b.last, 0, 0, &COEFFS_PROBA_0);
}
bits
}
fn chroma8_token_bits(chroma: &[Block; 8]) -> i64 {
chroma
.iter()
.map(|b| block_token_cost(b.levels, 0, b.last, 2, 0, &COEFFS_PROBA_0))
.sum()
}
fn luma16_reconstruction_sse(
planes: &mut Planes,
coeffs: &[i16],
y_off: usize,
src: &SourceYuv,
mb_x: usize,
mb_y: usize,
) -> i64 {
let stride = planes.y_stride;
for n in 0..16 {
let sub = y_off + (n % 4) * 4 + (n / 4) * 4 * stride;
let block = &coeffs[n * 16..n * 16 + 16];
if block.iter().any(|&c| c != 0) {
transform_one(block, &mut planes.y, sub, stride);
}
}
let src_stride = src.y_stride();
let src_off = mb_y * 16 * src_stride + mb_x * 16;
sse_block(&src.y, src_off, src_stride, &planes.y, y_off, stride, 16)
}
#[allow(
clippy::too_many_arguments,
reason = "the i4x4 search needs the plane, its offset, the source, the grid \
position (for source indexing) and the two top-right-lane edge flags; \
these are independent inputs, not a bundle with a natural struct"
)]
fn search_luma_i4x4(
planes: &mut Planes,
y_off: usize,
src: &SourceYuv,
mb_x: usize,
mb_y: usize,
has_top: bool,
is_rightmost: bool,
plan: QuantPlan,
) -> (I4x4Luma, i64, i64) {
let QuantPlan {
quant,
uses_trellis,
} = plan;
let stride = planes.y_stride;
let src_stride = src.y_stride();
fill_top_right_lane(&mut planes.y, y_off, stride, has_top, is_rightmost);
let mut cand = I4x4Luma {
imodes: [0u8; 16],
luma: [Block::default(); 16],
coeffs: [0i16; 256],
};
let mut bits = 0i64;
for n in 0..16 {
let (bx, by) = ((n % 4) * 4, (n / 4) * 4);
let sub = y_off + by * stride + bx;
let src_off = (mb_y * 16 + by) * src_stride + (mb_x * 16 + bx);
let mut best_mode = B_DC_PRED;
let mut best_sse = i64::MAX;
for m in 0..NUM_BMODES {
let mode = m as u8;
predict_luma4(&mut planes.y, sub, stride, mode);
let sse = sse_block(&src.y, src_off, src_stride, &planes.y, sub, stride, 4);
if sse < best_sse {
best_sse = sse;
best_mode = mode;
}
}
predict_luma4(&mut planes.y, sub, stride, best_mode);
let residual = residual_block(
&src.y,
src_stride,
mb_x * 16 + bx,
mb_y * 16 + by,
&planes.y,
sub,
stride,
);
let q = quantize_one(fdct4x4(residual), quant.y1, 0, 3, uses_trellis);
cand.coeffs[n * 16..n * 16 + 16].copy_from_slice(&q.recon);
if q.recon.iter().any(|&c| c != 0) {
transform_one(&q.recon, &mut planes.y, sub, stride);
}
cand.imodes[n] = best_mode;
cand.luma[n] = Block {
levels: q.levels,
last: q.last,
};
bits += block_token_cost(q.levels, 0, q.last, 3, 0, &COEFFS_PROBA_0) + I4X4_SUBMODE_COST;
}
let mb_src_off = mb_y * 16 * src_stride + mb_x * 16;
let dist = sse_block(&src.y, mb_src_off, src_stride, &planes.y, y_off, stride, 16);
(cand, dist, bits)
}
#[allow(
clippy::too_many_arguments,
reason = "the i4x4-vs-16×16 decision needs the plane, the 16×16 coeffs/tokens to \
score against, the source, the grid position and the two top-right-lane \
edge flags — independent inputs, not a bundle with a natural struct"
)]
fn try_i4x4_luma(
planes: &mut Planes,
coeffs: &[i16; 384],
tokens: &MbTokens,
src: &SourceYuv,
mb: (usize, usize),
has_top: bool,
is_rightmost: bool,
plan: QuantPlan,
) -> Option<I4x4Luma> {
let quant = plan.quant;
let (mb_x, mb_y) = mb;
let y_off = (mb_y * 16 + 1) * planes.y_stride + (mb_x * 16 + 1);
let dist16 = luma16_reconstruction_sse(planes, coeffs, y_off, src, mb_x, mb_y);
let bits16 = I16X16_MODE_COST + luma16_token_bits(tokens.y2, &tokens.luma);
let (cand, dist4, bits4) =
search_luma_i4x4(planes, y_off, src, mb_x, mb_y, has_top, is_rightmost, plan);
let lambda = i4x4_lambda(quant.y1.ac.q);
let cost16 = RD_DISTO_MULT * dist16 + lambda * bits16;
let cost4 = RD_DISTO_MULT * dist4 + lambda * bits4;
(cost4 < cost16).then_some(cand)
}
const WHOLE_BLOCK_MODES: [u8; 4] = [DC_PRED, V_PRED, H_PRED, TM_PRED];
const fn mode_available(mode: u8, has_top: bool, has_left: bool) -> bool {
match mode {
V_PRED => has_top,
H_PRED => has_left,
TM_PRED => has_top && has_left,
_ => true,
}
}
pub(crate) fn sse_block(
src: &[u8],
src_off: usize,
src_stride: usize,
pred: &[u8],
pred_off: usize,
pred_stride: usize,
size: usize,
) -> i64 {
work!(SseBlock);
let mut acc = 0i64;
for row in 0..size {
let s_row = &src[src_off + row * src_stride..][..size];
let p_row = &pred[pred_off + row * pred_stride..][..size];
let row_sse: i32 = s_row
.iter()
.zip(p_row)
.map(|(&s, &p)| {
let d = i32::from(s) - i32::from(p);
d * d
})
.sum();
acc += i64::from(row_sse);
}
acc
}
#[cfg(any(test, feature = "bench"))]
pub(crate) fn sse_block_reference(
src: &[u8],
src_off: usize,
src_stride: usize,
pred: &[u8],
pred_off: usize,
pred_stride: usize,
size: usize,
) -> i64 {
let mut acc = 0i64;
for row in 0..size {
for col in 0..size {
let s = i32::from(src[src_off + row * src_stride + col]);
let p = i32::from(pred[pred_off + row * pred_stride + col]);
let d = s - p;
acc += i64::from(d * d);
}
}
acc
}
fn chroma8_reconstruction_sse(
planes: &mut Planes,
coeffs: &[i16; 128],
uv_off: usize,
src: &SourceYuv,
mb_x: usize,
mb_y: usize,
) -> i64 {
let stride = planes.uv_stride;
for n in 0..4 {
let sub = uv_off + (n % 2) * 4 + (n / 2) * 4 * stride;
let u_block = &coeffs[n * 16..n * 16 + 16];
if u_block.iter().any(|&c| c != 0) {
transform_one(u_block, &mut planes.u, sub, stride);
}
let v_block = &coeffs[(4 + n) * 16..(4 + n) * 16 + 16];
if v_block.iter().any(|&c| c != 0) {
transform_one(v_block, &mut planes.v, sub, stride);
}
}
let src_stride = src.uv_stride();
let src_off = mb_y * 8 * src_stride + mb_x * 8;
sse_block(&src.u, src_off, src_stride, &planes.u, uv_off, stride, 8)
+ sse_block(&src.v, src_off, src_stride, &planes.v, uv_off, stride, 8)
}
fn select_luma16_mode_rd(
planes: &mut Planes,
y_off: usize,
src: &SourceYuv,
mb: (usize, usize),
has_top: bool,
has_left: bool,
plan: QuantPlan,
) -> (u8, Luma16Encode) {
let (mb_x, mb_y) = mb;
let stride = planes.y_stride;
let lambda = luma16_lambda(plan.quant.y1.ac.q);
let mut best_mode = DC_PRED;
let mut best_cost = i64::MAX;
let mut best = None;
for &mode in &WHOLE_BLOCK_MODES {
if !mode_available(mode, has_top, has_left) {
continue;
}
predict_luma16(&mut planes.y, y_off, stride, mode, has_top, has_left);
let enc = encode_luma16_residual(src, planes, mb_x, mb_y, plan);
let bits = I16X16_MODE_COST + luma16_token_bits(enc.y2, &enc.blocks);
let sse = luma16_reconstruction_sse(planes, &enc.coeffs, y_off, src, mb_x, mb_y);
let cost = RD_DISTO_MULT * sse + lambda * bits;
if cost < best_cost {
best_cost = cost;
best_mode = mode;
best = Some(enc);
}
}
predict_luma16(&mut planes.y, y_off, stride, best_mode, has_top, has_left);
(
best_mode,
best.unwrap_or_else(|| encode_luma16_residual(src, planes, mb_x, mb_y, plan)),
)
}
fn select_chroma8_mode_rd(
planes: &mut Planes,
uv_off: usize,
src: &SourceYuv,
mb: (usize, usize),
has_top: bool,
has_left: bool,
plan: QuantPlan,
) -> (u8, Chroma8Encode) {
let (mb_x, mb_y) = mb;
let stride = planes.uv_stride;
let lambda = chroma_lambda(plan.quant.uv.ac.q);
let mut best_mode = DC_PRED;
let mut best_cost = i64::MAX;
let mut best = None;
for &mode in &WHOLE_BLOCK_MODES {
if !mode_available(mode, has_top, has_left) {
continue;
}
predict_chroma8(&mut planes.u, uv_off, stride, mode, has_top, has_left);
predict_chroma8(&mut planes.v, uv_off, stride, mode, has_top, has_left);
let enc = encode_chroma8_residual(src, planes, mb_x, mb_y, plan);
let bits = chroma8_token_bits(&enc.blocks);
let sse = chroma8_reconstruction_sse(planes, &enc.coeffs, uv_off, src, mb_x, mb_y);
let cost = RD_DISTO_MULT * sse + lambda * bits;
if cost < best_cost {
best_cost = cost;
best_mode = mode;
best = Some(enc);
}
}
predict_chroma8(&mut planes.u, uv_off, stride, best_mode, has_top, has_left);
predict_chroma8(&mut planes.v, uv_off, stride, best_mode, has_top, has_left);
(
best_mode,
best.unwrap_or_else(|| encode_chroma8_residual(src, planes, mb_x, mb_y, plan)),
)
}
#[cfg(test)]
mod tests {
#![allow(
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::cast_possible_wrap,
reason = "test fixtures build pixel/coefficient inputs with the same bounded, \
in-range casts the codec uses; the values fit their targets by construction"
)]
use super::{
Effort, FramePlan, SearchGates, emit_best_partitions, encode_frame, encode_frame_impl,
plan_frame, residual_block, residual_block_reference, sse_block, sse_block_reference,
};
use crate::lossy::bool_dec::BoolDecoder;
use crate::lossy::constants::{DC_PRED, H_PRED, V_PRED};
use crate::lossy::decode::{self, Frame};
use crate::lossy::frame_header::{FrameHeader, KEY_FRAME_HEADER_LEN};
const FULL_GATES: SearchGates = SearchGates {
search_modes: true,
uses_i4x4: false,
uses_trellis: true,
};
const BALANCED: Effort = Effort::Full;
const FAST: Effort = Effort::Fast;
proptest::proptest! {
#[test]
fn sse_block_matches_reference(
size in 1usize..=16,
extra_src in 0usize..8,
extra_pred in 0usize..8,
src_off in 0usize..32,
pred_off in 0usize..32,
seed in proptest::prelude::any::<u64>(),
) {
let src_stride = size + extra_src;
let pred_stride = size + extra_pred;
let src_len = src_off + (size - 1) * src_stride + size;
let pred_len = pred_off + (size - 1) * pred_stride + size;
let mut st = seed;
let mut next = || {
st = st.wrapping_add(0x9E37_79B9_7F4A_7C15);
let mut z = st;
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
(z ^ (z >> 31)) as u8
};
let src: Vec<u8> = (0..src_len).map(|_| next()).collect();
let pred: Vec<u8> = (0..pred_len).map(|_| next()).collect();
proptest::prop_assert_eq!(
sse_block(&src, src_off, src_stride, &pred, pred_off, pred_stride, size),
sse_block_reference(&src, src_off, src_stride, &pred, pred_off, pred_stride, size),
);
}
#[test]
fn residual_block_matches_reference(
src_x in 0usize..8,
src_y in 0usize..8,
extra_src in 0usize..8,
extra_pred in 0usize..8,
pred_off in 0usize..32,
seed in proptest::prelude::any::<u64>(),
) {
let src_stride = src_x + 4 + extra_src;
let pred_stride = 4 + extra_pred;
let src_len = (src_y + 4) * src_stride;
let pred_len = pred_off + 4 * pred_stride;
let mut st = seed;
let mut next = || {
st = st.wrapping_add(0x9E37_79B9_7F4A_7C15);
let mut z = st;
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
(z ^ (z >> 31)) as u8
};
let src: Vec<u8> = (0..src_len).map(|_| next()).collect();
let pred: Vec<u8> = (0..pred_len).map(|_| next()).collect();
proptest::prop_assert_eq!(
residual_block(&src, src_stride, src_x, src_y, &pred, pred_off, pred_stride),
residual_block_reference(&src, src_stride, src_x, src_y, &pred, pred_off, pred_stride),
);
}
}
#[cfg(feature = "rayon")]
fn assert_wavefront_matches_serial(gates: SearchGates, w: usize, h: usize) {
use super::{
MbPlan, PARALLEL_MB_THRESHOLD, Planes, Quantizer, plan_frame_serial, plan_segmentation,
run_mb_planning,
};
use crate::lossy::rgb_to_yuv;
let mut rgba = vec![0u8; w * h * 4];
let mut s: u8 = 0x11;
for px in rgba.chunks_exact_mut(4) {
s = s.wrapping_mul(37).wrapping_add(0x53);
px[0] = s;
px[1] = s.wrapping_add(40);
px[2] = s.wrapping_add(80);
px[3] = 255;
}
let src = rgb_to_yuv::from_rgba(&rgba, w, h);
let (mb_w, mb_h) = (src.mb_w, src.mb_h);
assert!(
mb_w * mb_h >= PARALLEL_MB_THRESHOLD,
"{w}x{h} must exercise the parallel path"
);
let seg = plan_segmentation(&src, 40, true);
let quants = seg.base_q.map(Quantizer::new);
let mut wave_planes = Planes::new(mb_w, mb_h);
let par_result = run_mb_planning(
&mut wave_planes,
&src,
&seg.seg_ids,
&quants,
mb_w,
mb_h,
gates,
);
let mut serial_planes = Planes::new(mb_w, mb_h);
let ser_result = plan_frame_serial(
&mut serial_planes,
&src,
&seg.seg_ids,
&quants,
mb_w,
mb_h,
gates,
);
let region = |plane: &[u8], stride: usize, rows: usize, cols: usize| -> Vec<u8> {
let mut out = Vec::with_capacity(rows * cols);
for r in 0..rows {
let base = (r + 1) * stride + 1;
out.extend_from_slice(&plane[base..base + cols]);
}
out
};
let ys = wave_planes.y_stride;
let uvs = wave_planes.uv_stride;
assert_eq!(
region(&wave_planes.y, ys, mb_h * 16, mb_w * 16),
region(&serial_planes.y, ys, mb_h * 16, mb_w * 16),
"luma image {w}x{h}"
);
assert_eq!(
region(&wave_planes.u, uvs, mb_h * 8, mb_w * 8),
region(&serial_planes.u, uvs, mb_h * 8, mb_w * 8),
"u image {w}x{h}"
);
assert_eq!(
region(&wave_planes.v, uvs, mb_h * 8, mb_w * 8),
region(&serial_planes.v, uvs, mb_h * 8, mb_w * 8),
"v image {w}x{h}"
);
assert_eq!(par_result.len(), ser_result.len());
for (i, (a, b)) in par_result.iter().zip(&ser_result).enumerate() {
let key = |p: &MbPlan| {
(
p.ymode,
p.uvmode,
p.is_i4x4,
p.skippable,
p.has_residual,
p.segment,
p.imodes,
)
};
assert_eq!(
key(a),
key(b),
"MbPlan scalars diverge at MB {i} of {w}x{h}"
);
}
}
#[cfg(feature = "rayon")]
#[test]
fn wavefront_planner_matches_serial_byte_for_byte() {
let best = SearchGates {
search_modes: true,
uses_i4x4: true,
uses_trellis: true,
};
let balanced = SearchGates {
search_modes: true,
uses_i4x4: false,
uses_trellis: true,
};
for &gates in &[best, balanced] {
for &(w, h) in &[(256usize, 256usize), (272, 256), (256, 272), (512, 256)] {
assert_wavefront_matches_serial(gates, w, h);
}
}
}
fn decoded_mb_modes(payload: &[u8]) -> (usize, usize, Vec<(u8, u8)>) {
let fh = FrameHeader::parse_key_frame(payload).unwrap();
let mut frame = Frame::new(fh).unwrap();
let after_header = &payload[KEY_FRAME_HEADER_LEN..];
let part0_len = usize::try_from(fh.first_partition_size).unwrap();
let part0 = &after_header[..part0_len];
let after_part0 = &after_header[part0_len..];
let mut br = BoolDecoder::new(part0);
frame.parse_headers(&mut br);
frame.parse_partitions(&mut br, after_part0).unwrap();
frame.parse_quant(&mut br);
let _update_proba = br.read_flag();
frame.parse_proba(&mut br);
let (mb_w, mb_h) = (frame.mb_w, frame.mb_h);
let mut modes = Vec::with_capacity(mb_w * mb_h);
for _mb_y in 0..mb_h {
frame.parse_intra_mode_row(&mut br);
for mb_x in 0..mb_w {
let d = &frame.mb_data[mb_x];
modes.push((d.imodes[0], d.uvmode));
}
frame.init_scanline();
}
(mb_w, mb_h, modes)
}
fn decoded_filter_level(payload: &[u8]) -> i32 {
let fh = FrameHeader::parse_key_frame(payload).unwrap();
let mut frame = Frame::new(fh).unwrap();
let part0_len = usize::try_from(fh.first_partition_size).unwrap();
let part0 = &payload[KEY_FRAME_HEADER_LEN..KEY_FRAME_HEADER_LEN + part0_len];
let mut br = BoolDecoder::new(part0);
frame.parse_headers(&mut br);
frame.filter.level
}
fn image(width: usize, height: usize, f: impl Fn(usize, usize) -> [u8; 3]) -> Vec<u8> {
let mut buf = Vec::with_capacity(width * height * 4);
for y in 0..height {
for x in 0..width {
let [r, g, b] = f(x, y);
buf.extend_from_slice(&[r, g, b, 0xff]);
}
}
buf
}
fn assert_self_consistent(rgba: &[u8], w: usize, h: usize, base_q: i32) {
let (payload, enc_planes) = encode_frame_impl(rgba, w, h, base_q, BALANCED);
let (dec_planes, dw, dh) = decode::reconstruct_to_planes(&payload).unwrap();
assert_eq!((dw, dh), (w, h), "dimensions");
assert_eq!(enc_planes.y, dec_planes.y, "luma plane mismatch");
assert_eq!(enc_planes.u, dec_planes.u, "U plane mismatch");
assert_eq!(enc_planes.v, dec_planes.v, "V plane mismatch");
}
#[test]
fn solid_color_is_self_consistent() {
for &q in &[0, 32, 64, 100, 127] {
let rgba = image(16, 16, |_, _| [80, 160, 40]);
assert_self_consistent(&rgba, 16, 16, q);
}
}
#[test]
fn flat_image_uses_skip_and_stays_self_consistent() {
let (w, h) = (64usize, 64usize);
let rgba = image(w, h, |_, _| [120, 90, 200]);
let base_q = 40;
let FramePlan {
plans: mb_plans,
mb_w,
mb_h,
..
} = plan_frame(&rgba, w, h, base_q, FULL_GATES, true);
let nb_skip = mb_plans.iter().filter(|p| p.skippable).count();
assert!(
nb_skip > 0,
"a flat image should have skippable macroblocks"
);
let skip = super::resolve_skip(&mb_plans, mb_w * mb_h, true);
assert!(
skip.use_skip,
"enough skippable macroblocks should enable use_skip"
);
assert_self_consistent(&rgba, w, h, base_q);
}
#[test]
fn gradient_is_self_consistent() {
let rgba = image(48, 32, |x, y| {
let r = (x * 5) as u8;
let g = (y * 7) as u8;
let b = ((x + y) * 3) as u8;
[r, g, b]
});
for &q in &[8, 40, 96] {
assert_self_consistent(&rgba, 48, 32, q);
}
}
#[test]
fn odd_dimensions_are_self_consistent() {
let rgba = image(17, 13, |x, y| [(x * 13) as u8, (y * 17) as u8, 128]);
assert_self_consistent(&rgba, 17, 13, 40);
}
#[test]
fn high_contrast_is_self_consistent() {
let rgba = image(32, 32, |x, y| {
if (x / 4 + y / 4) % 2 == 0 {
[255, 255, 255]
} else {
[0, 0, 0]
}
});
assert_self_consistent(&rgba, 32, 32, 20);
}
#[test]
fn blocky_image_filters_and_stays_self_consistent() {
let (w, h) = (48usize, 48usize);
let rgba = image(w, h, |x, y| {
if (x / 4 + y / 4) % 2 == 0 {
[20, 20, 20]
} else {
[220, 220, 220]
}
});
let base_q = 40; let (payload, _enc) = encode_frame_impl(&rgba, w, h, base_q, BALANCED);
assert!(
decoded_filter_level(&payload) > 0,
"Balanced must enable the loop filter on blocky content"
);
assert_self_consistent(&rgba, w, h, base_q);
}
#[test]
fn fast_emits_filter_level_zero() {
let (w, h) = (48usize, 48usize);
let rgba = image(w, h, |x, y| {
if (x / 4 + y / 4) % 2 == 0 {
[20, 20, 20]
} else {
[220, 220, 220]
}
});
let payload = encode_frame(&rgba, w, h, 40, FAST);
assert_eq!(
decoded_filter_level(&payload),
0,
"Fast must emit filter level 0"
);
}
#[test]
fn output_decodes_to_the_right_dimensions() {
let rgba = image(24, 20, |x, y| [(x * 10) as u8, (y * 12) as u8, 64]);
let payload = encode_frame(&rgba, 24, 20, 40, BALANCED);
let image = decode::decode_frame(&payload).unwrap();
assert_eq!((image.width(), image.height()), (24, 20));
assert_eq!(image.as_bytes().len(), 24 * 20 * 4);
}
#[test]
fn encoding_is_deterministic() {
let rgba = image(32, 24, |x, y| [(x * 8) as u8, (y * 9) as u8, (x ^ y) as u8]);
let a = encode_frame(&rgba, 32, 24, 50, BALANCED);
let b = encode_frame(&rgba, 32, 24, 50, BALANCED);
assert_eq!(a, b, "identical inputs must produce identical bytes");
}
#[test]
fn horizontal_source_selects_horizontal_prediction() {
let rgba = image(48, 48, |_x, y| {
[(y * 7) as u8, (y * 3 + 20) as u8, (y * 11) as u8]
});
let payload = encode_frame(&rgba, 48, 48, 16, BALANCED);
let (mb_w, mb_h, modes) = decoded_mb_modes(&payload);
assert!(mb_w >= 2 && mb_h >= 2, "test needs an interior macroblock");
for mb_y in 0..mb_h {
for mb_x in 0..mb_w {
let (ymode, uvmode) = modes[mb_y * mb_w + mb_x];
if mb_x == 0 {
assert_eq!(ymode, DC_PRED, "left-edge luma at ({mb_x},{mb_y})");
assert_eq!(uvmode, DC_PRED, "left-edge chroma at ({mb_x},{mb_y})");
} else {
assert_eq!(ymode, H_PRED, "luma at ({mb_x},{mb_y})");
assert_eq!(uvmode, H_PRED, "chroma at ({mb_x},{mb_y})");
}
}
}
}
#[test]
fn vertical_source_selects_vertical_prediction() {
let rgba = image(48, 48, |x, _y| {
[(x * 7) as u8, (x * 3 + 20) as u8, (x * 11) as u8]
});
let payload = encode_frame(&rgba, 48, 48, 16, BALANCED);
let (mb_w, mb_h, modes) = decoded_mb_modes(&payload);
assert!(mb_w >= 2 && mb_h >= 2, "test needs an interior macroblock");
for mb_y in 0..mb_h {
for mb_x in 0..mb_w {
let (ymode, uvmode) = modes[mb_y * mb_w + mb_x];
if mb_y == 0 {
assert_eq!(ymode, DC_PRED, "top-edge luma at ({mb_x},{mb_y})");
assert_eq!(uvmode, DC_PRED, "top-edge chroma at ({mb_x},{mb_y})");
} else {
assert_eq!(ymode, V_PRED, "luma at ({mb_x},{mb_y})");
assert_eq!(uvmode, V_PRED, "chroma at ({mb_x},{mb_y})");
}
}
}
}
#[test]
fn fast_skips_mode_search_and_is_self_consistent() {
let rgba = image(48, 48, |_x, y| {
[(y * 7) as u8, (y * 3 + 20) as u8, (y * 11) as u8]
});
let (payload, enc_planes) = encode_frame_impl(&rgba, 48, 48, 16, FAST);
let (dec_planes, dw, dh) = decode::reconstruct_to_planes(&payload).unwrap();
assert_eq!((dw, dh), (48, 48), "dimensions");
assert_eq!(enc_planes.y, dec_planes.y, "luma plane mismatch");
assert_eq!(enc_planes.u, dec_planes.u, "U plane mismatch");
assert_eq!(enc_planes.v, dec_planes.v, "V plane mismatch");
let (mb_w, mb_h, modes) = decoded_mb_modes(&payload);
assert!(mb_w >= 2 && mb_h >= 2, "test needs an interior macroblock");
for mb_y in 0..mb_h {
for mb_x in 0..mb_w {
let (ymode, uvmode) = modes[mb_y * mb_w + mb_x];
assert_eq!(ymode, DC_PRED, "fast luma at ({mb_x},{mb_y}) is not DC");
assert_eq!(uvmode, DC_PRED, "fast chroma at ({mb_x},{mb_y}) is not DC");
}
}
}
fn frame_size_totals(rgba: &[u8], width: usize, height: usize, base_q: i32) -> (usize, usize) {
let FramePlan {
plans: mb_plans,
mb_w,
mb_h,
seg_params: seg,
..
} = plan_frame(rgba, width, height, base_q, FULL_GATES, true);
let skip = super::resolve_skip(&mb_plans, mb_w * mb_h, true);
let filter = super::choose_filter(base_q, true);
let header = super::HeaderParams {
base_q,
filter: &filter,
segments: seg,
};
let (_part0, _token, default_total, optimized_total) =
emit_best_partitions(&mb_plans, mb_w, mb_h, header, skip);
(
default_total + KEY_FRAME_HEADER_LEN,
optimized_total + KEY_FRAME_HEADER_LEN,
)
}
fn noisy_image(width: usize, height: usize) -> Vec<u8> {
image(width, height, |x, y| {
let mut s = (x as u32)
.wrapping_mul(2_654_435_761)
.wrapping_add((y as u32).wrapping_mul(40_503))
.wrapping_add(0x9e37_79b9);
s ^= s >> 13;
s = s.wrapping_mul(0x85eb_ca6b);
s ^= s >> 16;
[
(s & 0xff) as u8,
((s >> 8) & 0xff) as u8,
((s >> 16) & 0xff) as u8,
]
})
}
fn decoded_i4x4_flags(payload: &[u8]) -> (usize, usize, Vec<bool>) {
let fh = FrameHeader::parse_key_frame(payload).unwrap();
let mut frame = Frame::new(fh).unwrap();
let after_header = &payload[KEY_FRAME_HEADER_LEN..];
let part0_len = usize::try_from(fh.first_partition_size).unwrap();
let part0 = &after_header[..part0_len];
let after_part0 = &after_header[part0_len..];
let mut br = BoolDecoder::new(part0);
frame.parse_headers(&mut br);
frame.parse_partitions(&mut br, after_part0).unwrap();
frame.parse_quant(&mut br);
let _u = br.read_flag();
frame.parse_proba(&mut br);
let (mb_w, mb_h) = (frame.mb_w, frame.mb_h);
let mut flags = Vec::with_capacity(mb_w * mb_h);
for _ in 0..mb_h {
frame.parse_intra_mode_row(&mut br);
for mb_x in 0..mb_w {
flags.push(frame.mb_data[mb_x].is_i4x4);
}
frame.init_scanline();
}
(mb_w, mb_h, flags)
}
fn assert_self_consistent_best(rgba: &[u8], w: usize, h: usize, base_q: i32) {
let (payload, enc) = encode_frame_impl(rgba, w, h, base_q, Effort::Best);
let (dec, dw, dh) = decode::reconstruct_to_planes(&payload).unwrap();
assert_eq!((dw, dh), (w, h), "dimensions");
assert_eq!(enc.y_stride, dec.y_stride, "luma stride");
let stride = enc.y_stride;
let mb_w = w.div_ceil(16);
let real_cols = 1 + mb_w * 16; for (i, (&a, &b)) in enc.y.iter().zip(&dec.y).enumerate() {
if i % stride < real_cols {
assert_eq!(
a,
b,
"luma mismatch at row {}, col {}",
i / stride,
i % stride
);
}
}
assert_eq!(enc.u, dec.u, "U plane mismatch");
assert_eq!(enc.v, dec.v, "V plane mismatch");
}
fn stripe_image(w: usize, h: usize) -> Vec<u8> {
image(w, h, |x, _| {
if (x / 2) % 2 == 0 {
[220, 220, 220]
} else {
[20, 20, 20]
}
})
}
#[test]
fn best_uses_i4x4_on_detailed_content_and_stays_self_consistent() {
let (w, h) = (64usize, 64usize);
let rgba = stripe_image(w, h);
let base_q = 40;
let payload = encode_frame(&rgba, w, h, base_q, Effort::Best);
let (_mw, _mh, flags) = decoded_i4x4_flags(&payload);
assert!(
flags.iter().any(|&f| f),
"Best must code at least one i4x4 macroblock on detailed content"
);
assert_self_consistent_best(&rgba, w, h, base_q);
}
#[test]
fn best_mixed_i4x4_and_16x16_stays_self_consistent() {
let (w, h) = (64usize, 48usize);
let rgba = image(w, h, |x, _| {
if x < 32 {
[100, 100, 100]
} else if (x / 2) % 2 == 0 {
[220, 220, 220]
} else {
[20, 20, 20]
}
});
let base_q = 40;
let payload = encode_frame(&rgba, w, h, base_q, Effort::Best);
let (_mw, _mh, flags) = decoded_i4x4_flags(&payload);
assert!(
flags.iter().any(|&f| f),
"the detailed half should use some i4x4"
);
assert!(
flags.iter().any(|&f| !f),
"the flat half should keep some 16×16"
);
assert_self_consistent_best(&rgba, w, h, base_q);
}
#[test]
fn best_i4x4_is_self_consistent_across_qualities_and_dimensions() {
for &q in &[8, 30, 64, 100] {
assert_self_consistent_best(&stripe_image(48, 48), 48, 48, q);
}
assert_self_consistent_best(&stripe_image(17, 13), 17, 13, 40);
assert_self_consistent_best(&stripe_image(16, 16), 16, 16, 40);
}
fn diagonal_image(w: usize, h: usize) -> Vec<u8> {
image(w, h, |x, y| {
let v = u8::try_from(120 + ((x + y) / 4) % 5 * 16).unwrap_or(120);
[v, v, v]
})
}
#[test]
fn best_i4x4_stays_self_consistent_with_the_loop_filter_on() {
let (w, h) = (96usize, 96usize);
let rgba = diagonal_image(w, h);
let mut saw_i4x4 = false;
for &q in &[80, 100, 110, 120, 127] {
let payload = encode_frame(&rgba, w, h, q, Effort::Best);
let (_mw, _mh, flags) = decoded_i4x4_flags(&payload);
saw_i4x4 |= flags.iter().any(|&f| f);
assert_self_consistent_best(&rgba, w, h, q);
}
assert!(
saw_i4x4,
"diagonal content should code some i4x4 macroblock"
);
}
#[test]
fn rd_mode_decision_is_self_consistent_on_varied_content() {
let photo = photo96(96, 96);
let noisy = noisy96(96, 96);
for &bq in &[8, 40, 96] {
assert_self_consistent(&photo, 96, 96, bq);
assert_self_consistent(&noisy, 96, 96, bq);
}
}
#[test]
fn rd_mode_decision_selects_a_non_dc_mode_somewhere() {
let rgba = photo96(96, 96);
let payload = encode_frame(&rgba, 96, 96, 40, BALANCED);
let (_mw, _mh, modes) = decoded_mb_modes(&payload);
assert!(
modes.iter().any(|&(ymode, _uv)| ymode != DC_PRED),
"the RD mode search should pick a non-DC luma mode on banded photo content"
);
}
#[test]
fn balanced_never_uses_i4x4_on_detailed_content() {
let (w, h) = (64usize, 64usize);
let rgba = stripe_image(w, h);
let payload = encode_frame(&rgba, w, h, 40, Effort::Full);
let (_mw, _mh, flags) = decoded_i4x4_flags(&payload);
assert!(flags.iter().all(|&f| !f), "Balanced must never code i4x4");
}
#[test]
fn balanced_output_is_unchanged_by_the_i4x4_feature() {
let (w, h) = (48usize, 48usize);
let rgba = stripe_image(w, h);
let a = encode_frame(&rgba, w, h, 40, Effort::Full);
let b = encode_frame(&rgba, w, h, 40, Effort::Full);
assert_eq!(a, b, "Balanced must be deterministic");
let (_mw, _mh, flags) = decoded_i4x4_flags(&a);
assert!(flags.iter().all(|&f| !f), "Balanced carries no i4x4");
}
#[test]
fn best_is_deterministic() {
let rgba = stripe_image(48, 48);
let a = encode_frame(&rgba, 48, 48, 50, Effort::Best);
let b = encode_frame(&rgba, 48, 48, 50, Effort::Best);
assert_eq!(
a, b,
"Best must produce identical bytes for identical input"
);
}
fn chosen_total(rgba: &[u8], w: usize, h: usize, base_q: i32, uses_trellis: bool) -> usize {
let gates = SearchGates {
search_modes: true,
uses_i4x4: false,
uses_trellis,
};
let FramePlan {
plans: mb_plans,
mb_w,
mb_h,
seg_params: seg,
..
} = plan_frame(rgba, w, h, base_q, gates, true);
let skip = super::resolve_skip(&mb_plans, mb_w * mb_h, true);
let filter = super::choose_filter(base_q, true);
let header = super::HeaderParams {
base_q,
filter: &filter,
segments: seg,
};
let (_p0, _t, d, o) = emit_best_partitions(&mb_plans, mb_w, mb_h, header, skip);
KEY_FRAME_HEADER_LEN + d.min(o)
}
fn noisy96(w: usize, h: usize) -> Vec<u8> {
image(w, h, |x, y| {
let n = (x
.wrapping_mul(2_654_435_761)
.wrapping_add(y.wrapping_mul(40_503)))
>> 8;
[
(n & 0xff) as u8,
((n >> 3) & 0xff) as u8,
((x ^ y) * 3) as u8,
]
})
}
fn photo96(w: usize, h: usize) -> Vec<u8> {
image(w, h, |x, y| {
let band = i32::try_from(x / 8 % 3).unwrap_or(0);
let r = u8::try_from(128 + 40 * band - 30).unwrap_or(0);
[r, (x * 2 + y) as u8, (200 - y) as u8]
})
}
#[test]
fn trellis_shrinks_ac_rich_and_photo_frames() {
use crate::lossy::quant::quality_to_base_q;
let photo = photo96(96, 96);
let noisy = noisy96(96, 96);
for &qual in &[50u8, 75, 90] {
let bq = quality_to_base_q(qual);
for (name, rgba) in [("photo", &photo), ("noisy", &noisy)] {
let before = chosen_total(rgba, 96, 96, bq, false);
let after = chosen_total(rgba, 96, 96, bq, true);
assert!(
after < before,
"{name} q{qual}: trellis {after} did not shrink round-to-nearest {before}"
);
}
}
}
#[test]
fn probability_optimization_never_grows_and_shrinks_ac_rich_frames() {
let grad = image(64, 64, |x, y| {
[(x * 4) as u8, (y * 4) as u8, ((x + y) * 2) as u8]
});
let noisy = noisy_image(64, 64);
let photo = image(96, 96, |x, y| {
[(x * 2 + y) as u8, (128 + x + y) as u8, (x + y * 3) as u8]
});
let cases: [(&[u8], usize, usize); 3] =
[(&grad, 64, 64), (&noisy, 64, 64), (&photo, 96, 96)];
for &base_q in &[40i32, 75, 90] {
for &(rgba, w, h) in &cases {
let (default_total, optimized_total) = frame_size_totals(rgba, w, h, base_q);
assert!(
optimized_total <= default_total,
"q{base_q} {w}x{h}: optimized {optimized_total} > default {default_total}"
);
}
}
let (default_total, optimized_total) = frame_size_totals(&noisy, 64, 64, 40);
assert!(
optimized_total < default_total,
"AC-rich frame did not shrink: optimized {optimized_total} !< default {default_total}"
);
}
fn mixed_image(w: usize, h: usize) -> Vec<u8> {
image(w, h, |x, y| {
if x < w / 2 {
[96, 96, 96]
} else {
let mut s = (x as u32)
.wrapping_mul(2_654_435_761)
.wrapping_add((y as u32).wrapping_mul(40_503))
.wrapping_add(0x9e37_79b9);
s ^= s >> 13;
s = s.wrapping_mul(0x85eb_ca6b);
s ^= s >> 16;
[
(s & 0xff) as u8,
((s >> 8) & 0xff) as u8,
((s >> 16) & 0xff) as u8,
]
}
})
}
fn decoded_segments(payload: &[u8]) -> (bool, Vec<u8>) {
let fh = FrameHeader::parse_key_frame(payload).unwrap();
let mut frame = Frame::new(fh).unwrap();
let after_header = &payload[KEY_FRAME_HEADER_LEN..];
let part0_len = usize::try_from(fh.first_partition_size).unwrap();
let part0 = &after_header[..part0_len];
let after_part0 = &after_header[part0_len..];
let mut br = BoolDecoder::new(part0);
frame.parse_headers(&mut br);
frame.parse_partitions(&mut br, after_part0).unwrap();
frame.parse_quant(&mut br);
let _update_proba = br.read_flag();
frame.parse_proba(&mut br);
let use_segment = frame.segment.use_segment;
let (mb_w, mb_h) = (frame.mb_w, frame.mb_h);
let mut segs = Vec::with_capacity(mb_w * mb_h);
for _mb_y in 0..mb_h {
frame.parse_intra_mode_row(&mut br);
for mb_x in 0..mb_w {
segs.push(frame.mb_data[mb_x].segment);
}
frame.init_scanline();
}
(use_segment, segs)
}
fn distinct_segments(segs: &[u8]) -> usize {
let mut seen = [false; 4];
for &s in segs {
seen[usize::from(s)] = true;
}
seen.iter().filter(|&&b| b).count()
}
#[test]
fn mixed_content_uses_multiple_segments_and_stays_self_consistent() {
let (w, h) = (64usize, 64usize);
let rgba = mixed_image(w, h);
let base_q = 40;
let payload = encode_frame(&rgba, w, h, base_q, BALANCED);
let (use_segment, segs) = decoded_segments(&payload);
assert!(use_segment, "mixed content should enable segmentation");
assert!(
distinct_segments(&segs) >= 2,
"expected >= 2 segments, got {} in {segs:?}",
distinct_segments(&segs)
);
assert_self_consistent(&rgba, w, h, base_q);
}
#[test]
fn uniform_image_falls_back_to_a_single_segment() {
let (w, h) = (32usize, 32usize);
let rgba = image(w, h, |_, _| [100, 100, 100]);
let payload = encode_frame(&rgba, w, h, 40, BALANCED);
let (use_segment, _segs) = decoded_segments(&payload);
assert!(
!use_segment,
"uniform content should fall back to one segment"
);
assert_self_consistent(&rgba, w, h, 40);
}
#[test]
fn fast_uses_a_single_segment() {
let (w, h) = (64usize, 64usize);
let rgba = mixed_image(w, h);
let payload = encode_frame(&rgba, w, h, 40, FAST);
let (use_segment, _segs) = decoded_segments(&payload);
assert!(!use_segment, "Fast must not use segmentation");
}
#[test]
fn segmentation_is_deterministic() {
let rgba = mixed_image(64, 48);
let a = encode_frame(&rgba, 64, 48, 40, BALANCED);
let b = encode_frame(&rgba, 64, 48, 40, BALANCED);
assert_eq!(a, b, "segmentation must be deterministic");
}
#[test]
fn segmented_odd_and_uniform_dimensions_stay_self_consistent() {
assert_self_consistent(&mixed_image(48, 48), 48, 48, 40);
assert_self_consistent(&image(17, 13, |_, _| [70, 70, 70]), 17, 13, 40);
assert_self_consistent(
&image(19, 23, |x, y| [(x * 13) as u8, (y * 17) as u8, 90]),
19,
23,
40,
);
}
fn chosen_total_segmented(
rgba: &[u8],
w: usize,
h: usize,
base_q: i32,
uses_segments: bool,
) -> usize {
let FramePlan {
plans: mb_plans,
mb_w,
mb_h,
seg_params: seg,
..
} = plan_frame(rgba, w, h, base_q, FULL_GATES, uses_segments);
let skip = super::resolve_skip(&mb_plans, mb_w * mb_h, true);
let filter = super::choose_filter(base_q, true);
let header = super::HeaderParams {
base_q,
filter: &filter,
segments: seg,
};
let (_p0, _t, d, o) = emit_best_partitions(&mb_plans, mb_w, mb_h, header, skip);
KEY_FRAME_HEADER_LEN + d.min(o)
}
#[test]
fn segmentation_improves_size_on_mixed_content() {
let rgba = mixed_image(96, 96);
for &base_q in &[24i32, 40, 64] {
let segmented = chosen_total_segmented(&rgba, 96, 96, base_q, true);
let single = chosen_total_segmented(&rgba, 96, 96, base_q, false);
assert!(
segmented < single,
"q{base_q}: segmented {segmented} did not beat single-segment {single}"
);
}
}
fn golden_digest(bytes: &[u8]) -> u64 {
let mut h: u64 = 0xcbf2_9ce4_8422_2325;
for &b in bytes {
h ^= u64::from(b);
h = h.wrapping_mul(0x0000_0100_0000_01b3);
}
h
}
const GOLDEN_EXPECTED: &str = "\
gradient fast 190 fdbe0b6ce4ec645c
gradient balanced 88 c7ce577d895f26b6
gradient best 102 46518c082c50e880
noisy fast 7975 f970e253b081638d
noisy balanced 4544 7f2dffe17d7c8fad
noisy best 4025 ab505fb17bc7592b
flat fast 40 66b6a4ee87e184a3
flat balanced 37 6a59173075c587f1
flat best 37 6a59173075c587f1
checker fast 65 a42deaf46567ecd9
checker balanced 56 39d3ef5ea037e62e
checker best 56 39d3ef5ea037e62e
stripe fast 1680 145aef26907ace38
stripe balanced 322 5b465081386645c0
stripe best 118 7ffbbd64ba73c260
diagonal fast 415 46ac66199192122b
diagonal balanced 171 b4eb4e5cd54c6239
diagonal best 292 3142ea1a996bcdef
mixed fast 4363 13644d2cc4723cd5
mixed balanced 1922 38409a433944177e
mixed best 2014 34de49d21d0f919d
horizontal fast 667 81e58ac967acf023
horizontal balanced 176 6665e53feb38e76f
horizontal best 156 c863e535b5dde61a";
#[test]
fn golden_exact_encode_bytes() {
let cases: [(&str, Vec<u8>, usize, usize, i32); 8] = [
(
"gradient",
image(48, 32, |x, y| {
[(x * 5) as u8, (y * 7) as u8, ((x + y) * 3) as u8]
}),
48,
32,
40,
),
("noisy", noisy96(96, 96), 96, 96, 40),
("flat", image(64, 64, |_, _| [120, 90, 200]), 64, 64, 40),
(
"checker",
image(48, 48, |x, y| {
if (x / 4 + y / 4) % 2 == 0 {
[20, 20, 20]
} else {
[220, 220, 220]
}
}),
48,
48,
40,
),
("stripe", stripe_image(64, 64), 64, 64, 40),
("diagonal", diagonal_image(96, 96), 96, 96, 100),
("mixed", mixed_image(96, 96), 96, 96, 40),
(
"horizontal",
image(48, 48, |_x, y| {
[(y * 7) as u8, (y * 3 + 20) as u8, (y * 11) as u8]
}),
48,
48,
16,
),
];
let efforts = [
("fast", FAST),
("balanced", BALANCED),
("best", Effort::Best),
];
let mut lines = Vec::new();
for (name, rgba, w, h, q) in &cases {
for (ename, effort) in &efforts {
let payload = encode_frame(rgba, *w, *h, *q, *effort);
lines.push(format!(
"{name} {ename} {} {:016x}",
payload.len(),
golden_digest(&payload)
));
}
}
let actual = lines.join("\n");
println!("---GOLDEN ACTUAL---\n{actual}\n---END GOLDEN ACTUAL---");
assert_eq!(actual, GOLDEN_EXPECTED, "golden encode output changed");
}
fn skip_plan(skippable: bool) -> super::MbPlan {
use crate::lossy::tokens::{Block, MbTokens};
super::MbPlan {
ymode: 0,
imodes: [0; 16],
uvmode: 0,
is_i4x4: false,
skippable,
has_residual: false,
tokens: MbTokens {
is_i4x4: false,
y2: Block::default(),
luma: [Block::default(); 16],
chroma: [Block::default(); 8],
},
segment: 0,
}
}
#[test]
fn resolve_skip_probability_and_gate_are_exact() {
let plans = |n: usize, skip: usize| -> Vec<super::MbPlan> {
(0..n).map(|i| skip_plan(i < skip)).collect()
};
let a = super::resolve_skip(&plans(4, 1), 4, true);
assert!(a.use_skip, "A: enough skips should enable use_skip");
assert_eq!(a.skip_p, 191, "A: skip_p = (3*255)/4");
let b = super::resolve_skip(&plans(4, 1), 4, false);
assert!(
!b.use_skip,
"B: consider_skip=false must force use_skip off"
);
let c = super::resolve_skip(&plans(100, 1), 100, true);
assert_eq!(c.skip_p, 252, "C: skip_p = (99*255)/100");
assert!(!c.use_skip, "C: skip_p 252 ≥ 250 must keep use_skip off");
let d = super::resolve_skip(&plans(51, 1), 51, true);
assert_eq!(d.skip_p, 250, "D: skip_p = (50*255)/51 = 250 exactly");
assert!(
!d.use_skip,
"D: skip_p == 250 is not < 250, so use_skip off"
);
}
#[test]
fn mode_decision_lambdas_are_exact() {
assert_eq!(super::i4x4_lambda(64), 32, "i4x4: 64^2 >> 7");
assert_eq!(super::i4x4_lambda(0), 1, "i4x4: clamp 0 -> 1");
assert_eq!(super::luma16_lambda(16), 6, "luma16: 3*16^2 >> 7");
assert_eq!(super::luma16_lambda(0), 1, "luma16: clamp 0 -> 1");
assert_eq!(super::chroma_lambda(8), 3, "chroma: 3*8^2 >> 6");
assert_eq!(super::chroma_lambda(0), 1, "chroma: clamp 0 -> 1");
}
#[test]
fn segment_tree_and_quant_derivation_is_exact() {
assert_eq!(
super::segment_tree_probs(&[0, 1, 2, 2, 3]),
[102, 127, 170],
"segment tree probabilities"
);
assert_eq!(super::tree_prob(1, 2), 127, "tree_prob(1,2)");
assert_eq!(
super::segment_base_qs(40, 2, [100, 900, 0, 0]),
[36, 56, 40, 40],
"per-segment base quantizers"
);
}
#[test]
fn kmeans_assign_and_update_are_exact() {
let mut assign = [9u8];
super::assign_nearest(&[10], [5, 15, 0, 0], &mut assign);
assert_eq!(assign[0], 0, "equidistant tie -> lowest centroid index");
let mut cent = [0i64; 4];
super::update_centroids(&[10, 20], &[0, 0], &mut cent);
assert_eq!(cent[0], 15, "centroid 0 -> mean(10,20)");
}
fn splitmix_bytes(seed: u64, n: usize) -> Vec<u8> {
let mut st = seed.wrapping_add(1);
(0..n)
.map(|_| {
st = st.wrapping_add(0x9E37_79B9_7F4A_7C15);
let mut z = st;
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
((z ^ (z >> 31)) & 0xff) as u8
})
.collect()
}
#[test]
fn i16x16_mode_cost_is_exactly_two_coded_bits() {
assert_eq!(super::I16X16_MODE_COST, 512);
}
#[test]
fn mode_available_requires_all_named_neighbors() {
use crate::lossy::constants::TM_PRED;
assert!(super::mode_available(DC_PRED, false, false));
assert!(super::mode_available(V_PRED, true, false));
assert!(!super::mode_available(V_PRED, false, false));
assert!(super::mode_available(H_PRED, false, true));
assert!(!super::mode_available(H_PRED, false, false));
assert!(!super::mode_available(TM_PRED, true, false));
assert!(!super::mode_available(TM_PRED, false, true));
assert!(super::mode_available(TM_PRED, true, true));
}
#[test]
fn chroma8_reconstruction_transforms_every_dense_block() {
use super::Planes;
use crate::lossy::rgb_to_yuv::SourceYuv;
let mut planes = Planes::new(1, 1);
let uvs = planes.uv_stride;
let uv_off = uvs + 1;
for r in 0..8 {
for c in 0..8 {
planes.u[uv_off + r * uvs + c] = 100;
planes.v[uv_off + r * uvs + c] = 110;
}
}
let mut coeffs = [0i16; 128];
for k in 0..16 {
coeffs[k] = 50; coeffs[64 + k] = 50; }
let src = SourceYuv {
y: vec![0u8; 256],
u: vec![128u8; 64],
v: vec![130u8; 64],
mb_w: 1,
mb_h: 1,
};
let sse = super::chroma8_reconstruction_sse(&mut planes, &coeffs, uv_off, &src, 0, 0);
assert_eq!(
sse, 85896,
"dense U+V blocks must be reconstructed before scoring"
);
}
#[test]
fn has_residual_is_false_for_zero_coefficient_blocks() {
let rgba = image(64, 64, |_, _| [120, 90, 200]);
let FramePlan {
plans: mb_plans, ..
} = plan_frame(&rgba, 64, 64, 40, FULL_GATES, true);
assert!(
mb_plans.iter().any(|p| !p.has_residual),
"a flat frame must contain zero-residual macroblocks"
);
}
#[test]
fn default_partition_total_is_the_byte_length_sum() {
let noisy = noisy96(96, 96);
let FramePlan {
plans: mb_plans,
mb_w,
mb_h,
seg_params: seg,
..
} = plan_frame(&noisy, 96, 96, 40, FULL_GATES, true);
let skip = super::resolve_skip(&mb_plans, mb_w * mb_h, true);
let filter = super::choose_filter(40, true);
let header = super::HeaderParams {
base_q: 40,
filter: &filter,
segments: seg,
};
let (_p0, _t, default_total, optimized_total) =
emit_best_partitions(&mb_plans, mb_w, mb_h, header, skip);
assert_eq!(default_total, 6789, "default candidate byte-length sum");
assert_eq!(optimized_total, 4534, "optimized candidate byte-length sum");
}
#[test]
fn segmentation_spread_threshold_is_strict() {
use crate::lossy::rgb_to_yuv::SourceYuv;
let amps = [6i32, 6, 8, 8]; let mut y = vec![0u8; 4 * 16 * 16]; for (k, &) in amps.iter().enumerate() {
for r in 0..16 {
for lc in 0..16 {
let v = (128 + amp * ((lc % 4) as i32)).clamp(0, 255) as u8;
y[r * 64 + k * 16 + lc] = v;
}
}
}
let src = SourceYuv {
y,
u: vec![128; 4 * 8 * 8],
v: vec![128; 4 * 8 * 8],
mb_w: 4,
mb_h: 1,
};
let seg = super::plan_segmentation(&src, 40, true);
assert!(
seg.params.is_some(),
"an exact-boundary complexity spread must still segment (strict <)"
);
}
#[test]
fn skippable_luma_last_index_boundary_is_strict() {
let rgba = mixed_image(96, 96);
let FramePlan {
plans: mb_plans, ..
} = plan_frame(&rgba, 96, 96, 96, FULL_GATES, true);
let p = &mb_plans[15];
assert!(p.tokens.y2.last < 0, "witness needs an empty Y2");
assert!(
p.tokens.chroma.iter().all(|b| b.last < 0),
"witness needs empty chroma"
);
assert!(
p.tokens.luma.iter().all(|b| b.last <= 1),
"witness needs all luma last <= 1"
);
assert!(
p.tokens.luma.iter().any(|b| b.last == 1),
"witness needs a luma last == 1"
);
assert!(!p.skippable, "a luma last==1 block must not be skippable");
}
#[test]
fn keep_smaller_partition_prefers_default_on_size_ties() {
let rgba = image(16, 16, |x, y| {
[(x * 5) as u8, (y * 7) as u8, ((x + y) * 3) as u8]
});
let payload = encode_frame(&rgba, 16, 16, 24, BALANCED);
assert_eq!(
golden_digest(&payload),
0x58d0_7689_230c_bae4,
"at a size tie the encoder must keep the default probability table"
);
}
#[test]
fn i4x4_search_transforms_dense_subblocks() {
use super::{Planes, QuantPlan, Quantizer};
use crate::lossy::rgb_to_yuv::SourceYuv;
let mut planes = Planes::new(1, 1);
let ys = planes.y_stride;
let y_off = ys + 1;
let src = SourceYuv {
y: splitmix_bytes(0, 256),
u: vec![128; 64],
v: vec![128; 64],
mb_w: 1,
mb_h: 1,
};
let plan = QuantPlan {
quant: Quantizer::new(0),
uses_trellis: false,
};
let (_cand, dist, _bits) =
super::search_luma_i4x4(&mut planes, y_off, &src, 0, 0, false, true, plan);
assert_eq!(
dist, 115,
"dense i4x4 sub-blocks must be reconstructed before scoring"
);
}
#[test]
fn i4x4_vs_16x16_decision_is_strict_at_a_cost_tie() {
use super::{Planes, QuantPlan, Quantizer};
use crate::lossy::rgb_to_yuv::SourceYuv;
use crate::lossy::tokens::{Block, MbTokens};
fn isqrt(n: i64) -> i64 {
let mut x = 0i64;
while (x + 1) * (x + 1) <= n {
x += 1;
}
x
}
let src = SourceYuv {
y: splitmix_bytes(42, 256),
u: vec![128; 64],
v: vec![128; 64],
mb_w: 1,
mb_h: 1,
};
let mut planes = Planes::new(1, 1);
let ys = planes.y_stride;
let y_off = ys + 1;
for r in 0..16 {
for c in 0..16 {
planes.y[y_off + r * ys + c] = src.y[r * 16 + c];
}
}
let mut remaining: i64 = 7280;
let mut idx = 0usize;
while remaining > 0 {
let (row, col) = (idx / 16, idx % 16);
idx += 1;
let s = i32::from(src.y[row * 16 + col]);
let room = (255 - s).max(s);
let d = i32::try_from(isqrt(remaining)).unwrap_or(0).min(room);
let v = if 255 - s >= s { s + d } else { s - d };
planes.y[y_off + row * ys + col] = v as u8;
remaining -= i64::from(d) * i64::from(d);
}
let coeffs = [0i16; 384];
let tokens = MbTokens {
is_i4x4: false,
y2: Block::default(),
luma: [Block::default(); 16],
chroma: [Block::default(); 8],
};
let plan = QuantPlan {
quant: Quantizer::new(12),
uses_trellis: false,
};
let result = super::try_i4x4_luma(
&mut planes,
&coeffs,
&tokens,
&src,
(0, 0),
false,
true,
plan,
);
assert!(
result.is_none(),
"at an exact i4x4/16x16 cost tie the encoder must keep 16x16 (strict <)"
);
}
fn rd_image(rx: i32, ry: i32, damp: i32) -> Vec<u8> {
image(48, 48, |x, y| {
let d = if (x * 7 + y * 13) % 2 == 0 { 0 } else { damp };
let r = (60 + x as i32 * rx + d).clamp(0, 255) as u8;
let g = (120 + y as i32 * ry - d).clamp(0, 255) as u8;
let b = (100 + x as i32 * ry + y as i32 * rx + d).clamp(0, 255) as u8;
[r, g, b]
})
}
const RD_GOLDEN_EXPECTED: &str = "\
rd_rx0_ry5_d0_q48 7636466a29603289
rd_rx1_ry0_d0_q8 61c2b9c1ed64bf8c
rd_rx0_ry2_d0_q24 93e87313480c6866
rd_rx0_ry5_d60_q24 ac767fb717bd3476";
#[test]
fn rd_cost_arithmetic_golden() {
let cases: [(&str, i32, i32, i32, i32); 4] = [
("rd_rx0_ry5_d0_q48", 0, 5, 0, 48),
("rd_rx1_ry0_d0_q8", 1, 0, 0, 8),
("rd_rx0_ry2_d0_q24", 0, 2, 0, 24),
("rd_rx0_ry5_d60_q24", 0, 5, 60, 24),
];
let mut lines = Vec::new();
for (name, rx, ry, damp, q) in &cases {
let payload = encode_frame(&rd_image(*rx, *ry, *damp), 48, 48, *q, BALANCED);
lines.push(format!("{name} {:016x}", golden_digest(&payload)));
}
let actual = lines.join("\n");
println!("---RD GOLDEN ACTUAL---\n{actual}\n---END RD GOLDEN ACTUAL---");
assert_eq!(
actual, RD_GOLDEN_EXPECTED,
"RD cost-arithmetic golden changed"
);
}
#[test]
fn kmeans_segments_partition_is_exact() {
let a = [
100i64, 105, 110, 1100, 1105, 1110, 2100, 2105, 2110, 3100, 3105, 3110,
];
let (ids_a, cnt_a, seg_a) = super::kmeans_segments(&a);
assert_eq!(ids_a, vec![0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3], "A ids");
assert_eq!(cnt_a, 4, "A count");
assert_eq!(seg_a, [105, 1105, 2105, 3105], "A segment means");
let b = [
1000i64, 1010, 1020, 1100, 1110, 1120, 1200, 1210, 1220, 1300, 1310, 1320,
];
let (ids_b, cnt_b, seg_b) = super::kmeans_segments(&b);
assert_eq!(ids_b, vec![0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3], "B ids");
assert_eq!(cnt_b, 4, "B count");
assert_eq!(seg_b, [1010, 1110, 1210, 1310], "B segment means");
}
}