pub const FILTER_BITS: u32 = 7;
pub const SUBPEL_BITS: u32 = 4;
pub const SUBPEL_MASK: u32 = (1 << SUBPEL_BITS) - 1;
pub const SCALE_SUBPEL_BITS: u32 = 10;
pub const REF_SCALE_SHIFT: u32 = 14;
pub const EIGHTTAP: u8 = 0;
pub const EIGHTTAP_SMOOTH: u8 = 1;
pub const EIGHTTAP_SHARP: u8 = 2;
pub const BILINEAR: u8 = 3;
pub const EIGHTTAP_4TAP: u8 = 4;
pub const EIGHTTAP_SMOOTH_4TAP: u8 = 5;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RoundingVars {
pub inter_round0: u32,
pub inter_round1: u32,
pub inter_post_round: u32,
}
pub fn rounding_variables(bit_depth: u8, is_compound: bool) -> Result<RoundingVars, crate::Error> {
if !matches!(bit_depth, 8 | 10 | 12) {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let mut inter_round0: u32 = 3;
let mut inter_round1: u32 = if is_compound { 7 } else { 11 };
if bit_depth == 12 {
inter_round0 += 2;
if !is_compound {
inter_round1 -= 2;
}
}
let inter_post_round = 2 * FILTER_BITS - (inter_round0 + inter_round1);
Ok(RoundingVars {
inter_round0,
inter_round1,
inter_post_round,
})
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MvScale {
pub start_x: i32,
pub start_y: i32,
pub step_x: i32,
pub step_y: i32,
}
#[inline]
pub(crate) fn round2_signed(x: i64, n: u32) -> i64 {
if n == 0 {
x
} else if x >= 0 {
(x + (1i64 << (n - 1))) >> n
} else {
-(((-x) + (1i64 << (n - 1))) >> n)
}
}
#[allow(clippy::too_many_arguments)]
pub fn motion_vector_scaling(
plane: u8,
subsampling_x: u8,
subsampling_y: u8,
frame_width: u32,
frame_height: u32,
ref_upscaled_width: u32,
ref_frame_height: u32,
x: i32,
y: i32,
mv: [i16; 2],
) -> Result<MvScale, crate::Error> {
if plane > 2 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if subsampling_x > 1 || subsampling_y > 1 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if frame_width == 0 || frame_height == 0 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if ref_upscaled_width == 0 || ref_frame_height == 0 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let x_scale: i64 = (((ref_upscaled_width as i64) << REF_SCALE_SHIFT)
+ (frame_width as i64) / 2)
/ (frame_width as i64);
let y_scale: i64 = (((ref_frame_height as i64) << REF_SCALE_SHIFT) + (frame_height as i64) / 2)
/ (frame_height as i64);
let sub_x: u32 = if plane == 0 { 0 } else { subsampling_x as u32 };
let sub_y: u32 = if plane == 0 { 0 } else { subsampling_y as u32 };
let half_sample: i64 = 1i64 << (SUBPEL_BITS - 1);
let orig_x: i64 = ((x as i64) << SUBPEL_BITS) + ((2 * (mv[1] as i64)) >> sub_x) + half_sample;
let orig_y: i64 = ((y as i64) << SUBPEL_BITS) + ((2 * (mv[0] as i64)) >> sub_y) + half_sample;
let base_x: i64 = orig_x * x_scale - (half_sample << REF_SCALE_SHIFT);
let base_y: i64 = orig_y * y_scale - (half_sample << REF_SCALE_SHIFT);
let off: i64 = (1i64 << (SCALE_SUBPEL_BITS - SUBPEL_BITS)) / 2;
let shift = REF_SCALE_SHIFT + SUBPEL_BITS - SCALE_SUBPEL_BITS;
let start_x = round2_signed(base_x, shift) + off;
let start_y = round2_signed(base_y, shift) + off;
let step_x = round2_signed(x_scale, REF_SCALE_SHIFT - SCALE_SUBPEL_BITS);
let step_y = round2_signed(y_scale, REF_SCALE_SHIFT - SCALE_SUBPEL_BITS);
Ok(MvScale {
start_x: start_x as i32,
start_y: start_y as i32,
step_x: step_x as i32,
step_y: step_y as i32,
})
}
#[rustfmt::skip]
pub const SUBPEL_FILTERS: [[[i32; 8]; 16]; 6] = [
[
[ 0, 0, 0, 128, 0, 0, 0, 0 ],
[ 0, 2, -6, 126, 8, -2, 0, 0 ],
[ 0, 2, -10, 122, 18, -4, 0, 0 ],
[ 0, 2, -12, 116, 28, -8, 2, 0 ],
[ 0, 2, -14, 110, 38, -10, 2, 0 ],
[ 0, 2, -14, 102, 48, -12, 2, 0 ],
[ 0, 2, -16, 94, 58, -12, 2, 0 ],
[ 0, 2, -14, 84, 66, -12, 2, 0 ],
[ 0, 2, -14, 76, 76, -14, 2, 0 ],
[ 0, 2, -12, 66, 84, -14, 2, 0 ],
[ 0, 2, -12, 58, 94, -16, 2, 0 ],
[ 0, 2, -12, 48, 102, -14, 2, 0 ],
[ 0, 2, -10, 38, 110, -14, 2, 0 ],
[ 0, 2, -8, 28, 116, -12, 2, 0 ],
[ 0, 0, -4, 18, 122, -10, 2, 0 ],
[ 0, 0, -2, 8, 126, -6, 2, 0 ],
],
[
[ 0, 0, 0, 128, 0, 0, 0, 0 ],
[ 0, 2, 28, 62, 34, 2, 0, 0 ],
[ 0, 0, 26, 62, 36, 4, 0, 0 ],
[ 0, 0, 22, 62, 40, 4, 0, 0 ],
[ 0, 0, 20, 60, 42, 6, 0, 0 ],
[ 0, 0, 18, 58, 44, 8, 0, 0 ],
[ 0, 0, 16, 56, 46, 10, 0, 0 ],
[ 0, -2, 16, 54, 48, 12, 0, 0 ],
[ 0, -2, 14, 52, 52, 14, -2, 0 ],
[ 0, 0, 12, 48, 54, 16, -2, 0 ],
[ 0, 0, 10, 46, 56, 16, 0, 0 ],
[ 0, 0, 8, 44, 58, 18, 0, 0 ],
[ 0, 0, 6, 42, 60, 20, 0, 0 ],
[ 0, 0, 4, 40, 62, 22, 0, 0 ],
[ 0, 0, 4, 36, 62, 26, 0, 0 ],
[ 0, 0, 2, 34, 62, 28, 2, 0 ],
],
[
[ 0, 0, 0, 128, 0, 0, 0, 0 ],
[ -2, 2, -6, 126, 8, -2, 2, 0 ],
[ -2, 6, -12, 124, 16, -6, 4, -2 ],
[ -2, 8, -18, 120, 26, -10, 6, -2 ],
[ -4, 10, -22, 116, 38, -14, 6, -2 ],
[ -4, 10, -22, 108, 48, -18, 8, -2 ],
[ -4, 10, -24, 100, 60, -20, 8, -2 ],
[ -4, 10, -24, 90, 70, -22, 10, -2 ],
[ -4, 12, -24, 80, 80, -24, 12, -4 ],
[ -2, 10, -22, 70, 90, -24, 10, -4 ],
[ -2, 8, -20, 60, 100, -24, 10, -4 ],
[ -2, 8, -18, 48, 108, -22, 10, -4 ],
[ -2, 6, -14, 38, 116, -22, 10, -4 ],
[ -2, 6, -10, 26, 120, -18, 8, -2 ],
[ -2, 4, -6, 16, 124, -12, 6, -2 ],
[ 0, 2, -2, 8, 126, -6, 2, -2 ],
],
[
[ 0, 0, 0, 128, 0, 0, 0, 0 ],
[ 0, 0, 0, 120, 8, 0, 0, 0 ],
[ 0, 0, 0, 112, 16, 0, 0, 0 ],
[ 0, 0, 0, 104, 24, 0, 0, 0 ],
[ 0, 0, 0, 96, 32, 0, 0, 0 ],
[ 0, 0, 0, 88, 40, 0, 0, 0 ],
[ 0, 0, 0, 80, 48, 0, 0, 0 ],
[ 0, 0, 0, 72, 56, 0, 0, 0 ],
[ 0, 0, 0, 64, 64, 0, 0, 0 ],
[ 0, 0, 0, 56, 72, 0, 0, 0 ],
[ 0, 0, 0, 48, 80, 0, 0, 0 ],
[ 0, 0, 0, 40, 88, 0, 0, 0 ],
[ 0, 0, 0, 32, 96, 0, 0, 0 ],
[ 0, 0, 0, 24, 104, 0, 0, 0 ],
[ 0, 0, 0, 16, 112, 0, 0, 0 ],
[ 0, 0, 0, 8, 120, 0, 0, 0 ],
],
[
[ 0, 0, 0, 128, 0, 0, 0, 0 ],
[ 0, 0, -4, 126, 8, -2, 0, 0 ],
[ 0, 0, -8, 122, 18, -4, 0, 0 ],
[ 0, 0, -10, 116, 28, -6, 0, 0 ],
[ 0, 0, -12, 110, 38, -8, 0, 0 ],
[ 0, 0, -12, 102, 48, -10, 0, 0 ],
[ 0, 0, -14, 94, 58, -10, 0, 0 ],
[ 0, 0, -12, 84, 66, -10, 0, 0 ],
[ 0, 0, -12, 76, 76, -12, 0, 0 ],
[ 0, 0, -10, 66, 84, -12, 0, 0 ],
[ 0, 0, -10, 58, 94, -14, 0, 0 ],
[ 0, 0, -10, 48, 102, -12, 0, 0 ],
[ 0, 0, -8, 38, 110, -12, 0, 0 ],
[ 0, 0, -6, 28, 116, -10, 0, 0 ],
[ 0, 0, -4, 18, 122, -8, 0, 0 ],
[ 0, 0, -2, 8, 126, -4, 0, 0 ],
],
[
[ 0, 0, 0, 128, 0, 0, 0, 0 ],
[ 0, 0, 30, 62, 34, 2, 0, 0 ],
[ 0, 0, 26, 62, 36, 4, 0, 0 ],
[ 0, 0, 22, 62, 40, 4, 0, 0 ],
[ 0, 0, 20, 60, 42, 6, 0, 0 ],
[ 0, 0, 18, 58, 44, 8, 0, 0 ],
[ 0, 0, 16, 56, 46, 10, 0, 0 ],
[ 0, 0, 14, 54, 48, 12, 0, 0 ],
[ 0, 0, 12, 52, 52, 12, 0, 0 ],
[ 0, 0, 12, 48, 54, 14, 0, 0 ],
[ 0, 0, 10, 46, 56, 16, 0, 0 ],
[ 0, 0, 8, 44, 58, 18, 0, 0 ],
[ 0, 0, 6, 42, 60, 20, 0, 0 ],
[ 0, 0, 4, 40, 62, 22, 0, 0 ],
[ 0, 0, 4, 36, 62, 26, 0, 0 ],
[ 0, 0, 2, 34, 62, 30, 0, 0 ],
],
];
#[inline]
pub fn select_interp_filter_small_block(interp_filter: u8) -> u8 {
match interp_filter {
EIGHTTAP | EIGHTTAP_SHARP => EIGHTTAP_4TAP,
EIGHTTAP_SMOOTH => EIGHTTAP_SMOOTH_4TAP,
other => other,
}
}
#[inline]
fn round2(x: i64, n: u32) -> i64 {
if n == 0 {
x
} else {
(x + (1i64 << (n - 1))) >> n
}
}
#[inline]
fn clip3_i32(low: i32, high: i32, v: i32) -> i32 {
if v < low {
low
} else if v > high {
high
} else {
v
}
}
#[allow(clippy::too_many_arguments)]
pub fn block_inter_prediction(
plane: u8,
subsampling_x: u8,
subsampling_y: u8,
ref_plane: &[u16],
ref_stride: usize,
ref_width: u32,
ref_height: u32,
start_x: i32,
start_y: i32,
step_x: i32,
step_y: i32,
w: usize,
h: usize,
interp_filter_x: u8,
interp_filter_y: u8,
inter_round0: u32,
inter_round1: u32,
pred: &mut [i32],
) -> Result<(), crate::Error> {
if plane > 2 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if subsampling_x > 1 || subsampling_y > 1 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let guard_sub_x: u32 = if plane == 0 { 0 } else { subsampling_x as u32 };
let guard_sub_y: u32 = if plane == 0 { 0 } else { subsampling_y as u32 };
let plane_w = ((ref_width + guard_sub_x) >> guard_sub_x) as usize;
let plane_h = ((ref_height + guard_sub_y) >> guard_sub_y) as usize;
if ref_width == 0 || ref_height == 0 || ref_stride < plane_w {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if ref_plane.len() < plane_h * ref_stride {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if w == 0 || h == 0 || w > 256 || h > 256 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if step_x <= 0 || step_y <= 0 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let n_filters = SUBPEL_FILTERS.len() as u8;
if interp_filter_x >= n_filters || interp_filter_y >= n_filters {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if pred.len() < h * w {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let last_x: i32 = (plane_w as i32) - 1;
let last_y: i32 = (plane_h as i32) - 1;
let intermediate_height: usize =
((((h as i64) - 1) * (step_y as i64) + (1i64 << SCALE_SUBPEL_BITS) - 1)
>> SCALE_SUBPEL_BITS) as usize
+ 8;
let h_filter = if w <= 4 {
select_interp_filter_small_block(interp_filter_x) as usize
} else {
interp_filter_x as usize
};
let v_filter = if h <= 4 {
select_interp_filter_small_block(interp_filter_y) as usize
} else {
interp_filter_y as usize
};
let mut intermediate: Vec<i32> = vec![0i32; intermediate_height * w];
let y_base = (start_y >> SCALE_SUBPEL_BITS) - 3;
for r in 0..intermediate_height {
let ry = clip3_i32(0, last_y, y_base + (r as i32)) as usize;
let row_base = ry * ref_stride;
for c in 0..w {
let p: i32 = start_x + step_x * (c as i32);
let phase = ((p >> (SCALE_SUBPEL_BITS - SUBPEL_BITS)) as u32 & SUBPEL_MASK) as usize;
let p_int = p >> SCALE_SUBPEL_BITS;
let coeffs = &SUBPEL_FILTERS[h_filter][phase];
let mut s: i64 = 0;
for (t, coef) in coeffs.iter().enumerate() {
let rx = clip3_i32(0, last_x, p_int + (t as i32) - 3) as usize;
let sample = ref_plane[row_base + rx] as i64;
s += (*coef as i64) * sample;
}
intermediate[r * w + c] = round2(s, inter_round0) as i32;
}
}
let y_frac_mask: i32 = (1i32 << SCALE_SUBPEL_BITS) - 1;
for r in 0..h {
let p: i32 = (start_y & y_frac_mask) + step_y * (r as i32);
let phase = ((p >> (SCALE_SUBPEL_BITS - SUBPEL_BITS)) as u32 & SUBPEL_MASK) as usize;
let p_int = (p >> SCALE_SUBPEL_BITS) as usize;
let coeffs = &SUBPEL_FILTERS[v_filter][phase];
for c in 0..w {
let mut s: i64 = 0;
for (t, coef) in coeffs.iter().enumerate() {
let interp_row = p_int + t;
let v = intermediate[interp_row * w + c] as i64;
s += (*coef as i64) * v;
}
pred[r * w + c] = round2(s, inter_round1) as i32;
}
}
Ok(())
}
pub fn clip1_single_ref(bit_depth: u8, pred: &[i32], out: &mut [u16]) -> Result<(), crate::Error> {
if !matches!(bit_depth, 8 | 10 | 12) {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if out.len() < pred.len() {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let max = (1i32 << bit_depth) - 1;
for (dst, src) in out.iter_mut().zip(pred.iter().copied()) {
*dst = clip3_i32(0, max, src) as u16;
}
Ok(())
}
#[derive(Debug, Clone, Copy)]
pub struct PredictInterRef<'a> {
pub ref_plane: &'a [u16],
pub ref_stride: usize,
pub ref_upscaled_width: u32,
pub ref_width: u32,
pub ref_height: u32,
pub mv: [i16; 2],
}
#[derive(Debug)]
pub enum CompoundParams<'a> {
Average,
Distance(DistanceWeights),
Wedge {
mask: &'a [u8],
mask_stride: usize,
},
Diffwtd {
mask_type: u8,
mask: &'a mut [u8],
},
Intra {
mask: &'a [u8],
mask_stride: usize,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InterIntraParams<'a> {
pub interintra_mode: u8,
pub wedge: Option<WedgeInterIntraInfo<'a>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct WedgeInterIntraInfo<'a> {
pub mask: &'a [u8],
pub mask_stride: usize,
}
#[allow(clippy::too_many_arguments)]
fn predict_inter_per_ref(
r: &PredictInterRef<'_>,
plane: u8,
x: i32,
y: i32,
w: usize,
h: usize,
subsampling_x: u8,
subsampling_y: u8,
frame_width: u32,
frame_height: u32,
interp_filter_x: u8,
interp_filter_y: u8,
inter_round0: u32,
inter_round1: u32,
) -> Result<Vec<i32>, crate::Error> {
let mvs = motion_vector_scaling(
plane,
subsampling_x,
subsampling_y,
frame_width,
frame_height,
r.ref_upscaled_width,
r.ref_height,
x,
y,
r.mv,
)?;
let mut pred: Vec<i32> = Vec::new();
if pred.try_reserve_exact(w * h).is_err() {
return Err(crate::Error::PartitionWalkOutOfRange);
}
pred.resize(w * h, 0);
block_inter_prediction(
plane,
subsampling_x,
subsampling_y,
r.ref_plane,
r.ref_stride,
r.ref_width,
r.ref_height,
mvs.start_x,
mvs.start_y,
mvs.step_x,
mvs.step_y,
w,
h,
interp_filter_x,
interp_filter_y,
inter_round0,
inter_round1,
&mut pred,
)?;
Ok(pred)
}
#[allow(clippy::too_many_arguments)]
fn predict_inter_compound_blend(
plane: u8,
bit_depth: u8,
inter_post_round: u32,
subsampling_x: u8,
subsampling_y: u8,
w: usize,
h: usize,
pred0: &[i32],
pred1: &[i32],
params: CompoundParams<'_>,
pred_out: &mut [u16],
) -> Result<(), crate::Error> {
match params {
CompoundParams::Average => {
let max: i32 = (1i32 << bit_depth) - 1;
let shift: u32 = 1 + inter_post_round;
for i in 0..h {
for j in 0..w {
let acc = pred0[i * w + j] as i64 + pred1[i * w + j] as i64;
let rounded = round2(acc, shift) as i32;
pred_out[i * w + j] = clip3_i32(0, max, rounded) as u16;
}
}
Ok(())
}
CompoundParams::Distance(weights) => compound_distance_blend(
bit_depth,
inter_post_round,
weights,
pred0,
pred1,
w,
h,
pred_out,
),
CompoundParams::Wedge { mask, mask_stride }
| CompoundParams::Intra { mask, mask_stride } => mask_blend(
bit_depth,
inter_post_round,
subsampling_x,
subsampling_y,
pred0,
pred1,
w,
h,
mask,
mask_stride,
pred_out,
),
CompoundParams::Diffwtd { mask_type, mask } => {
let luma_w = w << subsampling_x;
let luma_h = h << subsampling_y;
if plane == 0 {
if mask.len() < luma_w * luma_h {
return Err(crate::Error::PartitionWalkOutOfRange);
}
difference_weight_mask(
bit_depth,
inter_post_round,
mask_type,
pred0,
pred1,
luma_w,
luma_h,
mask,
)?;
}
mask_blend(
bit_depth,
inter_post_round,
subsampling_x,
subsampling_y,
pred0,
pred1,
w,
h,
mask,
luma_w,
pred_out,
)
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct WarpDriverParams {
pub y_mode: [u8; 2],
pub gm_type: [u8; 2],
pub gm_params: [[i32; 6]; 2],
pub local_warp_params: [i32; 6],
pub local_valid: bool,
pub ref_is_scaled: [bool; 2],
pub force_integer_mv: bool,
}
#[derive(Debug, Clone, Copy)]
pub struct ObmcNeighbour<'a> {
pub bundle: PredictInterRef<'a>,
pub step4: u8,
pub interp_filter_x: u8,
pub interp_filter_y: u8,
pub axis_pos4: u16,
}
#[derive(Debug, Clone, Copy)]
pub struct ObmcParams<'a, 'n> {
pub mi_row: u32,
pub mi_col: u32,
pub mi_cols: u32,
pub mi_rows: u32,
pub mi_width_log2: u8,
pub mi_height_log2: u8,
pub avail_u: bool,
pub avail_l: bool,
pub plane_residual_size_ge_block_8x8: bool,
pub above_neighbours: &'n [ObmcNeighbour<'a>],
pub left_neighbours: &'n [ObmcNeighbour<'a>],
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum UseWarpDecision {
Translational,
Local,
Global,
}
#[allow(clippy::too_many_arguments)]
fn derive_use_warp(
w: usize,
h: usize,
motion_mode: u8,
y_mode: u8,
gm_type: u8,
ref_is_scaled: bool,
local_valid: bool,
global_valid: bool,
force_integer_mv: bool,
) -> UseWarpDecision {
if w < 8 || h < 8 {
return UseWarpDecision::Translational;
}
if force_integer_mv {
return UseWarpDecision::Translational;
}
if motion_mode == crate::cdf::MOTION_MODE_WARPED_CAUSAL && local_valid {
return UseWarpDecision::Local;
}
let y_is_global = matches!(
y_mode,
crate::cdf::MODE_GLOBALMV | crate::cdf::MODE_GLOBAL_GLOBALMV
);
let gm_is_warp = (gm_type as i32) > crate::cdf::GM_TYPE_TRANSLATION;
if y_is_global && gm_is_warp && !ref_is_scaled && global_valid {
return UseWarpDecision::Global;
}
UseWarpDecision::Translational
}
#[allow(clippy::too_many_arguments)]
fn predict_inter_per_ref_warp(
r: &PredictInterRef<'_>,
use_warp: u8,
plane: u8,
x: i32,
y: i32,
w: usize,
h: usize,
subsampling_x: u8,
subsampling_y: u8,
warp_params: [i32; 6],
inter_round0: u32,
inter_round1: u32,
) -> Result<Vec<i32>, crate::Error> {
let mut pred: Vec<i32> = Vec::new();
if pred.try_reserve_exact(w * h).is_err() {
return Err(crate::Error::PartitionWalkOutOfRange);
}
pred.resize(w * h, 0);
let i_blocks = h.div_ceil(8);
let j_blocks = w.div_ceil(8);
for i8b in 0..i_blocks {
for j8b in 0..j_blocks {
block_warp(
use_warp,
plane,
subsampling_x,
subsampling_y,
x,
y,
i8b as i32,
j8b as i32,
w,
h,
r.ref_plane,
r.ref_stride,
r.ref_upscaled_width,
r.ref_height,
warp_params,
inter_round0,
inter_round1,
w,
&mut pred,
)?;
}
}
Ok(pred)
}
#[allow(clippy::too_many_arguments)]
fn predict_inter_one_ref(
r: &PredictInterRef<'_>,
ref_list: usize,
plane: u8,
x: i32,
y: i32,
w: usize,
h: usize,
motion_mode: u8,
subsampling_x: u8,
subsampling_y: u8,
frame_width: u32,
frame_height: u32,
interp_filter_x: u8,
interp_filter_y: u8,
inter_round0: u32,
inter_round1: u32,
warp: Option<&WarpDriverParams>,
effective_local_valid: bool,
) -> Result<Vec<i32>, crate::Error> {
let decision = if let Some(wp) = warp {
let y_mode = wp.y_mode[ref_list];
let gm_type = wp.gm_type[ref_list];
let ref_is_scaled = wp.ref_is_scaled[ref_list];
let y_is_global = matches!(
y_mode,
crate::cdf::MODE_GLOBALMV | crate::cdf::MODE_GLOBAL_GLOBALMV
);
let gm_is_warp = (gm_type as i32) > crate::cdf::GM_TYPE_TRANSLATION;
let global_valid = if y_is_global && gm_is_warp && !ref_is_scaled {
matches!(setup_shear(wp.gm_params[ref_list]), Some(s) if s.warp_valid)
} else {
false
};
derive_use_warp(
w,
h,
motion_mode,
y_mode,
gm_type,
ref_is_scaled,
effective_local_valid,
global_valid,
wp.force_integer_mv,
)
} else {
UseWarpDecision::Translational
};
match decision {
UseWarpDecision::Translational => predict_inter_per_ref(
r,
plane,
x,
y,
w,
h,
subsampling_x,
subsampling_y,
frame_width,
frame_height,
interp_filter_x,
interp_filter_y,
inter_round0,
inter_round1,
),
UseWarpDecision::Local => {
let wp = warp.expect("Local requires WarpDriverParams");
predict_inter_per_ref_warp(
r,
USE_WARP_LOCAL,
plane,
x,
y,
w,
h,
subsampling_x,
subsampling_y,
wp.local_warp_params,
inter_round0,
inter_round1,
)
}
UseWarpDecision::Global => {
let wp = warp.expect("Global requires WarpDriverParams");
predict_inter_per_ref_warp(
r,
USE_WARP_GLOBAL,
plane,
x,
y,
w,
h,
subsampling_x,
subsampling_y,
wp.gm_params[ref_list],
inter_round0,
inter_round1,
)
}
}
}
#[allow(clippy::too_many_arguments)]
fn obmc_walk_axis(
pass: OverlapPass,
plane: u8,
block_x_plane: i32,
block_y_plane: i32,
block_w: usize,
block_h: usize,
mi_row: u32,
mi_col: u32,
mi_cols: u32,
mi_rows: u32,
mi_width_log2: u8,
mi_height_log2: u8,
subsampling_x: u8,
subsampling_y: u8,
frame_width: u32,
frame_height: u32,
inter_round0: u32,
inter_round1: u32,
bit_depth: u8,
neighbours: &[ObmcNeighbour<'_>],
pred_out: &mut [u16],
) -> Result<(), crate::Error> {
let mi_size: u32 = crate::cdf::MI_SIZE as u32;
let sub_x = subsampling_x as u32;
let sub_y = subsampling_y as u32;
let (axis_limit_log2, frame_limit, axis_start, axis_block_extent) = match pass {
OverlapPass::Above => {
let w4 = 1u32 << (mi_width_log2 as u32);
(
mi_width_log2,
mi_cols.min(mi_col.saturating_add(w4)),
mi_col,
w4,
)
}
OverlapPass::Left => {
let h4 = 1u32 << (mi_height_log2 as u32);
(
mi_height_log2,
mi_rows.min(mi_row.saturating_add(h4)),
mi_row,
h4,
)
}
};
let _ = axis_block_extent;
let n_limit: u32 = 4.min(axis_limit_log2 as u32);
let mut n_count: u32 = 0;
for cand in neighbours {
if n_count >= n_limit {
break;
}
let axis_pos: u32 = cand.axis_pos4 as u32;
if axis_pos < axis_start || axis_pos >= frame_limit {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let step4: u32 = cand.step4 as u32;
if !(2..=16).contains(&step4) {
return Err(crate::Error::PartitionWalkOutOfRange);
}
n_count = n_count.saturating_add(1);
let (pred_x_plane, pred_y_plane): (u32, u32) = match pass {
OverlapPass::Above => {
let px = (axis_pos.saturating_mul(4)) >> sub_x;
let py = (mi_row.saturating_mul(4)) >> sub_y;
(px, py)
}
OverlapPass::Left => {
let px = (mi_col.saturating_mul(4)) >> sub_x;
let py = (axis_pos.saturating_mul(4)) >> sub_y;
(px, py)
}
};
let (pred_w, pred_h, mask_length) = match pass {
OverlapPass::Above => {
let pw = block_w.min(((step4 * mi_size) >> sub_x) as usize);
let ph = (block_h >> 1).min((32u32 >> sub_y) as usize);
(pw, ph, ph)
}
OverlapPass::Left => {
let pw = (block_w >> 1).min((32u32 >> sub_x) as usize);
let ph = block_h.min(((step4 * mi_size) >> sub_y) as usize);
(pw, ph, pw)
}
};
if pred_w == 0 || pred_h == 0 {
continue;
}
let off_x = (pred_x_plane as i64) - (block_x_plane as i64);
let off_y = (pred_y_plane as i64) - (block_y_plane as i64);
if off_x < 0 || off_y < 0 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let off_x = off_x as usize;
let off_y = off_y as usize;
if off_x >= block_w || off_y >= block_h {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let fit_w = pred_w.min(block_w - off_x);
let fit_h = pred_h.min(block_h - off_y);
if fit_w == 0 || fit_h == 0 {
continue;
}
let obmc_pred_i32 = predict_inter_per_ref(
&cand.bundle,
plane,
pred_x_plane as i32,
pred_y_plane as i32,
fit_w,
fit_h,
subsampling_x,
subsampling_y,
frame_width,
frame_height,
cand.interp_filter_x,
cand.interp_filter_y,
inter_round0,
inter_round1,
)?;
let mut obmc_pred_u16 = vec![0u16; fit_w * fit_h];
clip1_single_ref(bit_depth, &obmc_pred_i32, &mut obmc_pred_u16)?;
overlap_neighbour_predict_blend(
pred_out,
block_w,
off_x,
off_y,
fit_w,
fit_h,
pass,
&obmc_pred_u16,
fit_w,
mask_length,
)?;
}
Ok(())
}
#[allow(clippy::too_many_arguments)]
pub fn predict_inter(
plane: u8,
x: i32,
y: i32,
w: usize,
h: usize,
motion_mode: u8,
is_compound: bool,
is_inter_intra: bool,
bit_depth: u8,
subsampling_x: u8,
subsampling_y: u8,
frame_width: u32,
frame_height: u32,
interp_filter_x: u8,
interp_filter_y: u8,
refs: &[PredictInterRef<'_>],
compound: Option<CompoundParams<'_>>,
inter_intra: Option<InterIntraParams<'_>>,
warp: Option<&WarpDriverParams>,
obmc: Option<&ObmcParams<'_, '_>>,
pred_out: &mut [u16],
) -> Result<(), crate::Error> {
if plane > 2 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if subsampling_x > 1 || subsampling_y > 1 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if !matches!(bit_depth, 8 | 10 | 12) {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if frame_width == 0 || frame_height == 0 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if w == 0 || h == 0 || w > 256 || h > 256 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if pred_out.len() < w * h {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if refs.is_empty() {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if is_compound {
if refs.len() < 2 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if compound.is_none() {
return Err(crate::Error::PartitionWalkOutOfRange);
}
} else if compound.is_some() {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if is_inter_intra {
if is_compound {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if inter_intra.is_none() {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if inter_intra
.map(|ii| ii.interintra_mode > II_SMOOTH_PRED)
.unwrap_or(false)
{
return Err(crate::Error::PartitionWalkOutOfRange);
}
} else if inter_intra.is_some() {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if motion_mode == crate::cdf::MOTION_MODE_WARPED_CAUSAL && warp.is_none() {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if motion_mode == crate::cdf::MOTION_MODE_OBMC && obmc.is_none() {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let rv = rounding_variables(bit_depth, is_compound)?;
let mut effective_local_valid: bool = warp.is_some_and(|w| w.local_valid);
if let Some(wp) = warp {
if motion_mode == crate::cdf::MOTION_MODE_WARPED_CAUSAL && wp.local_valid {
match setup_shear(wp.local_warp_params) {
Some(s) if s.warp_valid => {}
_ => effective_local_valid = false,
}
}
}
let pred0 = predict_inter_one_ref(
&refs[0],
0,
plane,
x,
y,
w,
h,
motion_mode,
subsampling_x,
subsampling_y,
frame_width,
frame_height,
interp_filter_x,
interp_filter_y,
rv.inter_round0,
rv.inter_round1,
warp,
effective_local_valid,
)?;
if is_inter_intra {
let ii = inter_intra.expect("inter_intra checked above");
match ii.wedge {
None => {
let mut mask = vec![0u8; w * h];
intra_mode_variant_mask(ii.interintra_mode, w, h, &mut mask)?;
mask_blend_interintra(
bit_depth,
rv.inter_post_round,
0,
0,
&pred0,
w,
h,
&mask,
0,
pred_out,
)?;
}
Some(wi) => {
mask_blend_interintra(
bit_depth,
rv.inter_post_round,
subsampling_x,
subsampling_y,
&pred0,
w,
h,
wi.mask,
wi.mask_stride,
pred_out,
)?;
}
}
} else if is_compound {
let pred1 = predict_inter_one_ref(
&refs[1],
1,
plane,
x,
y,
w,
h,
motion_mode,
subsampling_x,
subsampling_y,
frame_width,
frame_height,
interp_filter_x,
interp_filter_y,
rv.inter_round0,
rv.inter_round1,
warp,
effective_local_valid,
)?;
let cp = compound.expect("compound checked above");
predict_inter_compound_blend(
plane,
bit_depth,
rv.inter_post_round,
subsampling_x,
subsampling_y,
w,
h,
&pred0,
&pred1,
cp,
pred_out,
)?;
} else {
clip1_single_ref(bit_depth, &pred0, pred_out)?;
}
if motion_mode == crate::cdf::MOTION_MODE_OBMC {
let op = obmc.expect("OBMC requires ObmcParams (guarded above)");
if op.avail_u && op.plane_residual_size_ge_block_8x8 {
obmc_walk_axis(
OverlapPass::Above,
plane,
x,
y,
w,
h,
op.mi_row,
op.mi_col,
op.mi_cols,
op.mi_rows,
op.mi_width_log2,
op.mi_height_log2,
subsampling_x,
subsampling_y,
frame_width,
frame_height,
rv.inter_round0,
rv.inter_round1,
bit_depth,
op.above_neighbours,
pred_out,
)?;
}
if op.avail_l {
obmc_walk_axis(
OverlapPass::Left,
plane,
x,
y,
w,
h,
op.mi_row,
op.mi_col,
op.mi_cols,
op.mi_rows,
op.mi_width_log2,
op.mi_height_log2,
subsampling_x,
subsampling_y,
frame_width,
frame_height,
rv.inter_round0,
rv.inter_round1,
bit_depth,
op.left_neighbours,
pred_out,
)?;
}
}
Ok(())
}
pub const MASK_MASTER_SIZE: usize = 64;
pub const MAX_SB_SIZE: usize = 128;
pub const MAX_FRAME_DISTANCE: i32 = 31;
pub const COMPOUND_WEDGE: u8 = 0;
pub const COMPOUND_DIFFWTD: u8 = 1;
pub const COMPOUND_AVERAGE: u8 = 2;
pub const COMPOUND_INTRA: u8 = 3;
pub const COMPOUND_DISTANCE: u8 = 4;
pub const II_DC_PRED: u8 = 0;
pub const II_V_PRED: u8 = 1;
pub const II_H_PRED: u8 = 2;
pub const II_SMOOTH_PRED: u8 = 3;
pub const WEDGE_HORIZONTAL: u8 = 0;
pub const WEDGE_VERTICAL: u8 = 1;
pub const WEDGE_OBLIQUE27: u8 = 2;
pub const WEDGE_OBLIQUE63: u8 = 3;
pub const WEDGE_OBLIQUE117: u8 = 4;
pub const WEDGE_OBLIQUE153: u8 = 5;
pub const WEDGE_DIRECTIONS: usize = 6;
#[rustfmt::skip]
pub const WEDGE_MASTER_OBLIQUE_ODD: [u8; MASK_MASTER_SIZE] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 6, 18,
37, 53, 60, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
];
#[rustfmt::skip]
pub const WEDGE_MASTER_OBLIQUE_EVEN: [u8; MASK_MASTER_SIZE] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 11, 27,
46, 58, 62, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
];
#[rustfmt::skip]
pub const WEDGE_MASTER_VERTICAL: [u8; MASK_MASTER_SIZE] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 7, 21,
43, 57, 62, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
];
#[rustfmt::skip]
pub const WEDGE_CODEBOOK: [[[u8; 3]; 16]; 3] = [
[
[WEDGE_OBLIQUE27, 4, 4], [WEDGE_OBLIQUE63, 4, 4],
[WEDGE_OBLIQUE117, 4, 4], [WEDGE_OBLIQUE153, 4, 4],
[WEDGE_HORIZONTAL, 4, 2], [WEDGE_HORIZONTAL, 4, 4],
[WEDGE_HORIZONTAL, 4, 6], [WEDGE_VERTICAL, 4, 4],
[WEDGE_OBLIQUE27, 4, 2], [WEDGE_OBLIQUE27, 4, 6],
[WEDGE_OBLIQUE153, 4, 2], [WEDGE_OBLIQUE153, 4, 6],
[WEDGE_OBLIQUE63, 2, 4], [WEDGE_OBLIQUE63, 6, 4],
[WEDGE_OBLIQUE117, 2, 4], [WEDGE_OBLIQUE117, 6, 4],
],
[
[WEDGE_OBLIQUE27, 4, 4], [WEDGE_OBLIQUE63, 4, 4],
[WEDGE_OBLIQUE117, 4, 4], [WEDGE_OBLIQUE153, 4, 4],
[WEDGE_VERTICAL, 2, 4], [WEDGE_VERTICAL, 4, 4],
[WEDGE_VERTICAL, 6, 4], [WEDGE_HORIZONTAL, 4, 4],
[WEDGE_OBLIQUE27, 4, 2], [WEDGE_OBLIQUE27, 4, 6],
[WEDGE_OBLIQUE153, 4, 2], [WEDGE_OBLIQUE153, 4, 6],
[WEDGE_OBLIQUE63, 2, 4], [WEDGE_OBLIQUE63, 6, 4],
[WEDGE_OBLIQUE117, 2, 4], [WEDGE_OBLIQUE117, 6, 4],
],
[
[WEDGE_OBLIQUE27, 4, 4], [WEDGE_OBLIQUE63, 4, 4],
[WEDGE_OBLIQUE117, 4, 4], [WEDGE_OBLIQUE153, 4, 4],
[WEDGE_HORIZONTAL, 4, 2], [WEDGE_HORIZONTAL, 4, 6],
[WEDGE_VERTICAL, 2, 4], [WEDGE_VERTICAL, 6, 4],
[WEDGE_OBLIQUE27, 4, 2], [WEDGE_OBLIQUE27, 4, 6],
[WEDGE_OBLIQUE153, 4, 2], [WEDGE_OBLIQUE153, 4, 6],
[WEDGE_OBLIQUE63, 2, 4], [WEDGE_OBLIQUE63, 6, 4],
[WEDGE_OBLIQUE117, 2, 4], [WEDGE_OBLIQUE117, 6, 4],
],
];
#[rustfmt::skip]
pub const WEDGE_BITS: [u8; 22] = [
0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 0,
0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0,
];
#[inline]
#[must_use]
pub fn block_shape(num_4x4_wide: u32, num_4x4_high: u32) -> u8 {
if num_4x4_high > num_4x4_wide {
0
} else if num_4x4_high < num_4x4_wide {
1
} else {
2
}
}
fn build_master_mask() -> Box<[u8; WEDGE_DIRECTIONS * MASK_MASTER_SIZE * MASK_MASTER_SIZE]> {
let master =
vec![0u8; WEDGE_DIRECTIONS * MASK_MASTER_SIZE * MASK_MASTER_SIZE].into_boxed_slice();
let mut m: Box<[u8; WEDGE_DIRECTIONS * MASK_MASTER_SIZE * MASK_MASTER_SIZE]> =
master.try_into().expect("len matches");
let w = MASK_MASTER_SIZE;
let h = MASK_MASTER_SIZE;
for j in 0..w {
let mut shift: i32 = (MASK_MASTER_SIZE / 4) as i32;
let mut i = 0usize;
while i < h {
let idx_even = clip3_i32(0, (MASK_MASTER_SIZE - 1) as i32, j as i32 - shift) as usize;
m[idx3(WEDGE_OBLIQUE63 as usize, i, j)] = WEDGE_MASTER_OBLIQUE_EVEN[idx_even];
shift -= 1;
let idx_odd = clip3_i32(0, (MASK_MASTER_SIZE - 1) as i32, j as i32 - shift) as usize;
m[idx3(WEDGE_OBLIQUE63 as usize, i + 1, j)] = WEDGE_MASTER_OBLIQUE_ODD[idx_odd];
m[idx3(WEDGE_VERTICAL as usize, i, j)] = WEDGE_MASTER_VERTICAL[j];
m[idx3(WEDGE_VERTICAL as usize, i + 1, j)] = WEDGE_MASTER_VERTICAL[j];
i += 2;
}
}
for i in 0..h {
for j in 0..w {
let msk = m[idx3(WEDGE_OBLIQUE63 as usize, i, j)];
m[idx3(WEDGE_OBLIQUE27 as usize, j, i)] = msk;
m[idx3(WEDGE_OBLIQUE117 as usize, i, w - 1 - j)] = 64 - msk;
m[idx3(WEDGE_OBLIQUE153 as usize, w - 1 - j, i)] = 64 - msk;
m[idx3(WEDGE_HORIZONTAL as usize, j, i)] = m[idx3(WEDGE_VERTICAL as usize, i, j)];
}
}
m
}
#[inline(always)]
const fn idx3(dir: usize, i: usize, j: usize) -> usize {
dir * MASK_MASTER_SIZE * MASK_MASTER_SIZE + i * MASK_MASTER_SIZE + j
}
static MASTER_MASK_CACHE: std::sync::OnceLock<
Box<[u8; WEDGE_DIRECTIONS * MASK_MASTER_SIZE * MASK_MASTER_SIZE]>,
> = std::sync::OnceLock::new();
#[must_use]
pub fn master_mask_table() -> &'static [u8; WEDGE_DIRECTIONS * MASK_MASTER_SIZE * MASK_MASTER_SIZE]
{
MASTER_MASK_CACHE.get_or_init(build_master_mask)
}
pub fn wedge_mask(
mi_size: usize,
num_4x4_wide: u32,
num_4x4_high: u32,
wedge_index: u8,
wedge_sign: u8,
mask: &mut [u8],
) -> Result<(), crate::Error> {
if mi_size >= WEDGE_BITS.len() {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if WEDGE_BITS[mi_size] == 0 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if wedge_index >= 16 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if wedge_sign > 1 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if num_4x4_wide == 0 || num_4x4_high == 0 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let w: usize = (num_4x4_wide as usize) * 4;
let h: usize = (num_4x4_high as usize) * 4;
if w > MASK_MASTER_SIZE || h > MASK_MASTER_SIZE {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if mask.len() < w * h {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let shape = block_shape(num_4x4_wide, num_4x4_high) as usize;
let entry = &WEDGE_CODEBOOK[shape][wedge_index as usize];
let dir = entry[0] as usize;
let xoff_codebook = entry[1] as i32;
let yoff_codebook = entry[2] as i32;
let xoff: i32 = (MASK_MASTER_SIZE as i32) / 2 - ((xoff_codebook * (w as i32)) >> 3);
let yoff: i32 = (MASK_MASTER_SIZE as i32) / 2 - ((yoff_codebook * (h as i32)) >> 3);
let master = master_mask_table();
let mut sum: i64 = 0;
for i in 0..w {
sum += master[idx3(dir, yoff as usize, (xoff + i as i32) as usize)] as i64;
}
for i in 1..h {
sum += master[idx3(dir, (yoff + i as i32) as usize, xoff as usize)] as i64;
}
let avg = (sum + ((w + h - 1) as i64) / 2) / ((w + h - 1) as i64);
let flip_sign: u8 = if avg < 32 { 1 } else { 0 };
let invert = wedge_sign != flip_sign;
for i in 0..h {
for j in 0..w {
let raw = master[idx3(dir, (yoff + i as i32) as usize, (xoff + j as i32) as usize)];
mask[i * w + j] = if invert { 64 - raw } else { raw };
}
}
Ok(())
}
#[allow(clippy::too_many_arguments)]
pub fn difference_weight_mask(
bit_depth: u8,
inter_post_round: u32,
mask_type: u8,
preds0: &[i32],
preds1: &[i32],
w: usize,
h: usize,
mask: &mut [u8],
) -> Result<(), crate::Error> {
if !matches!(bit_depth, 8 | 10 | 12) {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if mask_type > 1 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if w == 0 || h == 0 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let n = w * h;
if preds0.len() < n || preds1.len() < n || mask.len() < n {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let shift: u32 = (bit_depth as u32 - 8) + inter_post_round;
for i in 0..h {
for j in 0..w {
let p0 = preds0[i * w + j] as i64;
let p1 = preds1[i * w + j] as i64;
let diff = (p0 - p1).unsigned_abs() as i64;
let scaled = round2(diff, shift);
let m = clip3_i32(0, 64, 38 + (scaled / 16) as i32) as u8;
mask[i * w + j] = if mask_type != 0 { 64 - m } else { m };
}
}
Ok(())
}
#[rustfmt::skip]
pub const II_WEIGHTS_1D: [u8; MAX_SB_SIZE] = [
60, 58, 56, 54, 52, 50, 48, 47, 45, 44, 42, 41, 39, 38, 37, 35, 34, 33, 32,
31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 22, 21, 20, 19, 19, 18, 18, 17, 16,
16, 15, 15, 14, 14, 13, 13, 12, 12, 12, 11, 11, 10, 10, 10, 9, 9, 9, 8,
8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4,
4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
];
pub fn intra_mode_variant_mask(
interintra_mode: u8,
w: usize,
h: usize,
mask: &mut [u8],
) -> Result<(), crate::Error> {
if interintra_mode > II_SMOOTH_PRED {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if w == 0 || h == 0 || w > MAX_SB_SIZE || h > MAX_SB_SIZE {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if mask.len() < w * h {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let larger = w.max(h);
let size_scale: usize = MAX_SB_SIZE / larger;
for i in 0..h {
for j in 0..w {
let m = match interintra_mode {
II_V_PRED => II_WEIGHTS_1D[i * size_scale],
II_H_PRED => II_WEIGHTS_1D[j * size_scale],
II_SMOOTH_PRED => II_WEIGHTS_1D[i.min(j) * size_scale],
_ => 32,
};
mask[i * w + j] = m;
}
}
Ok(())
}
#[allow(clippy::too_many_arguments)]
pub fn mask_blend(
bit_depth: u8,
inter_post_round: u32,
sub_x: u8,
sub_y: u8,
preds0: &[i32],
preds1: &[i32],
w: usize,
h: usize,
mask: &[u8],
mask_stride: usize,
out: &mut [u16],
) -> Result<(), crate::Error> {
if !matches!(bit_depth, 8 | 10 | 12) {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if sub_x > 1 || sub_y > 1 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if w == 0 || h == 0 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let n = w * h;
if preds0.len() < n || preds1.len() < n || out.len() < n {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let mask_w = if sub_x == 1 { 2 * w } else { w };
let mask_h = if sub_y == 1 { 2 * h } else { h };
let stride = if mask_stride == 0 {
mask_w
} else {
mask_stride
};
if stride < mask_w {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if mask.len() < stride * (mask_h - 1) + mask_w {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let shift: u32 = 6 + inter_post_round;
let max: i32 = (1i32 << bit_depth) - 1;
for y in 0..h {
for x in 0..w {
let m: i32 = match (sub_x, sub_y) {
(0, 0) => mask[y * stride + x] as i32,
(1, 0) => round2(
mask[y * stride + 2 * x] as i64 + mask[y * stride + 2 * x + 1] as i64,
1,
) as i32,
(0, 1) => round2(
mask[2 * y * stride + x] as i64 + mask[(2 * y + 1) * stride + x] as i64,
1,
) as i32,
_ => round2(
mask[2 * y * stride + 2 * x] as i64
+ mask[2 * y * stride + 2 * x + 1] as i64
+ mask[(2 * y + 1) * stride + 2 * x] as i64
+ mask[(2 * y + 1) * stride + 2 * x + 1] as i64,
2,
) as i32,
};
let p0 = preds0[y * w + x] as i64;
let p1 = preds1[y * w + x] as i64;
let acc = (m as i64) * p0 + ((64 - m) as i64) * p1;
let blended = round2(acc, shift) as i32;
out[y * w + x] = clip3_i32(0, max, blended) as u16;
}
}
Ok(())
}
#[allow(clippy::too_many_arguments)]
pub fn mask_blend_interintra(
bit_depth: u8,
inter_post_round: u32,
sub_x: u8,
sub_y: u8,
preds0: &[i32],
w: usize,
h: usize,
mask: &[u8],
mask_stride: usize,
dst: &mut [u16],
) -> Result<(), crate::Error> {
if !matches!(bit_depth, 8 | 10 | 12) {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if sub_x > 1 || sub_y > 1 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if w == 0 || h == 0 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let n = w * h;
if preds0.len() < n || dst.len() < n {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let mask_w = if sub_x == 1 { 2 * w } else { w };
let mask_h = if sub_y == 1 { 2 * h } else { h };
let stride = if mask_stride == 0 {
mask_w
} else {
mask_stride
};
if stride < mask_w {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if mask.len() < stride * (mask_h - 1) + mask_w {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let max: i32 = (1i32 << bit_depth) - 1;
for y in 0..h {
for x in 0..w {
let m: i64 = match (sub_x, sub_y) {
(0, 0) => mask[y * stride + x] as i64,
(1, 0) => round2(
mask[y * stride + 2 * x] as i64 + mask[y * stride + 2 * x + 1] as i64,
1,
),
(0, 1) => round2(
mask[2 * y * stride + x] as i64 + mask[(2 * y + 1) * stride + x] as i64,
1,
),
_ => round2(
mask[2 * y * stride + 2 * x] as i64
+ mask[2 * y * stride + 2 * x + 1] as i64
+ mask[(2 * y + 1) * stride + 2 * x] as i64
+ mask[(2 * y + 1) * stride + 2 * x + 1] as i64,
2,
),
};
let raw_pred0 = preds0[y * w + x] as i64;
let clipped = clip3_i32(0, max, round2(raw_pred0, inter_post_round) as i32) as i64;
let pred1 = dst[y * w + x] as i64;
let blended = round2(m * pred1 + (64 - m) * clipped, 6) as i32;
dst[y * w + x] = clip3_i32(0, max, blended) as u16;
}
}
Ok(())
}
pub const QUANT_DIST_WEIGHT: [[i32; 2]; 4] = [[2, 3], [2, 5], [2, 7], [1, MAX_FRAME_DISTANCE]];
pub const QUANT_DIST_LOOKUP: [[i32; 2]; 4] = [[9, 7], [11, 5], [12, 4], [13, 3]];
#[inline]
#[must_use]
pub fn get_relative_dist(a: i32, b: i32, order_hint_bits: u32) -> i32 {
if order_hint_bits == 0 {
return 0;
}
let diff: i32 = a - b;
let m: i32 = 1 << (order_hint_bits - 1);
(diff & (m - 1)) - (diff & m)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DistanceWeights {
pub fwd_weight: i32,
pub bck_weight: i32,
}
pub fn distance_weights(
order_hint_bits: u32,
current_order_hint: i32,
order_hint_ref0: i32,
order_hint_ref1: i32,
) -> DistanceWeights {
let dist0 = clip3_i32(
0,
MAX_FRAME_DISTANCE,
get_relative_dist(order_hint_ref0, current_order_hint, order_hint_bits).abs(),
);
let dist1 = clip3_i32(
0,
MAX_FRAME_DISTANCE,
get_relative_dist(order_hint_ref1, current_order_hint, order_hint_bits).abs(),
);
let d0 = dist1;
let d1 = dist0;
let order_bool = d0 <= d1;
let order: usize = if order_bool { 1 } else { 0 };
let other: usize = 1 - order;
if d0 == 0 || d1 == 0 {
return DistanceWeights {
fwd_weight: QUANT_DIST_LOOKUP[3][order],
bck_weight: QUANT_DIST_LOOKUP[3][other],
};
}
let mut chosen_i = 3usize;
for (i, row) in QUANT_DIST_WEIGHT.iter().enumerate().take(3) {
let c0 = row[order];
let c1 = row[other];
let lhs = d0 * c0;
let rhs = d1 * c1;
let break_now = if order_bool { lhs > rhs } else { lhs < rhs };
if break_now {
chosen_i = i;
break;
}
}
DistanceWeights {
fwd_weight: QUANT_DIST_LOOKUP[chosen_i][order],
bck_weight: QUANT_DIST_LOOKUP[chosen_i][other],
}
}
#[allow(clippy::too_many_arguments)]
pub fn compound_distance_blend(
bit_depth: u8,
inter_post_round: u32,
weights: DistanceWeights,
preds0: &[i32],
preds1: &[i32],
w: usize,
h: usize,
out: &mut [u16],
) -> Result<(), crate::Error> {
if !matches!(bit_depth, 8 | 10 | 12) {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if w == 0 || h == 0 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let n = w * h;
if preds0.len() < n || preds1.len() < n || out.len() < n {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let max: i32 = (1i32 << bit_depth) - 1;
let shift: u32 = 4 + inter_post_round;
for y in 0..h {
for x in 0..w {
let acc = (weights.fwd_weight as i64) * (preds0[y * w + x] as i64)
+ (weights.bck_weight as i64) * (preds1[y * w + x] as i64);
let rounded = round2(acc, shift) as i32;
out[y * w + x] = clip3_i32(0, max, rounded) as u16;
}
}
Ok(())
}
pub const WARP_WARPEDMODEL_PREC_BITS: u32 = 16;
pub const WARP_PARAM_REDUCE_BITS: u32 = 6;
pub const DIV_LUT_PREC_BITS: u32 = 14;
pub const DIV_LUT_BITS: u32 = 8;
pub const DIV_LUT_NUM: usize = 257;
pub const LS_MV_MAX: i32 = 256;
pub const WARPEDMODEL_TRANS_CLAMP: i32 = 1 << 23;
pub const WARPEDMODEL_NONDIAGAFFINE_CLAMP: i32 = 1 << 13;
pub const WARPEDPIXEL_PREC_SHIFTS: usize = 1 << 6;
pub const WARPEDDIFF_PREC_BITS: u32 = 10;
#[rustfmt::skip]
pub const WARPED_FILTERS: [[i32; 8]; WARPEDPIXEL_PREC_SHIFTS * 3 + 1] = [
[ 0, 0, 127, 1, 0, 0, 0, 0],
[ 0, -1, 127, 2, 0, 0, 0, 0],
[ 1, -3, 127, 4, -1, 0, 0, 0],
[ 1, -4, 126, 6, -2, 1, 0, 0],
[ 1, -5, 126, 8, -3, 1, 0, 0],
[ 1, -6, 125, 11, -4, 1, 0, 0],
[ 1, -7, 124, 13, -4, 1, 0, 0],
[ 2, -8, 123, 15, -5, 1, 0, 0],
[ 2, -9, 122, 18, -6, 1, 0, 0],
[ 2, -10, 121, 20, -6, 1, 0, 0],
[ 2, -11, 120, 22, -7, 2, 0, 0],
[ 2, -12, 119, 25, -8, 2, 0, 0],
[ 3, -13, 117, 27, -8, 2, 0, 0],
[ 3, -13, 116, 29, -9, 2, 0, 0],
[ 3, -14, 114, 32, -10, 3, 0, 0],
[ 3, -15, 113, 35, -10, 2, 0, 0],
[ 3, -15, 111, 37, -11, 3, 0, 0],
[ 3, -16, 109, 40, -11, 3, 0, 0],
[ 3, -16, 108, 42, -12, 3, 0, 0],
[ 4, -17, 106, 45, -13, 3, 0, 0],
[ 4, -17, 104, 47, -13, 3, 0, 0],
[ 4, -17, 102, 50, -14, 3, 0, 0],
[ 4, -17, 100, 52, -14, 3, 0, 0],
[ 4, -18, 98, 55, -15, 4, 0, 0],
[ 4, -18, 96, 58, -15, 3, 0, 0],
[ 4, -18, 94, 60, -16, 4, 0, 0],
[ 4, -18, 91, 63, -16, 4, 0, 0],
[ 4, -18, 89, 65, -16, 4, 0, 0],
[ 4, -18, 87, 68, -17, 4, 0, 0],
[ 4, -18, 85, 70, -17, 4, 0, 0],
[ 4, -18, 82, 73, -17, 4, 0, 0],
[ 4, -18, 80, 75, -17, 4, 0, 0],
[ 4, -18, 78, 78, -18, 4, 0, 0],
[ 4, -17, 75, 80, -18, 4, 0, 0],
[ 4, -17, 73, 82, -18, 4, 0, 0],
[ 4, -17, 70, 85, -18, 4, 0, 0],
[ 4, -17, 68, 87, -18, 4, 0, 0],
[ 4, -16, 65, 89, -18, 4, 0, 0],
[ 4, -16, 63, 91, -18, 4, 0, 0],
[ 4, -16, 60, 94, -18, 4, 0, 0],
[ 3, -15, 58, 96, -18, 4, 0, 0],
[ 4, -15, 55, 98, -18, 4, 0, 0],
[ 3, -14, 52, 100, -17, 4, 0, 0],
[ 3, -14, 50, 102, -17, 4, 0, 0],
[ 3, -13, 47, 104, -17, 4, 0, 0],
[ 3, -13, 45, 106, -17, 4, 0, 0],
[ 3, -12, 42, 108, -16, 3, 0, 0],
[ 3, -11, 40, 109, -16, 3, 0, 0],
[ 3, -11, 37, 111, -15, 3, 0, 0],
[ 2, -10, 35, 113, -15, 3, 0, 0],
[ 3, -10, 32, 114, -14, 3, 0, 0],
[ 2, -9, 29, 116, -13, 3, 0, 0],
[ 2, -8, 27, 117, -13, 3, 0, 0],
[ 2, -8, 25, 119, -12, 2, 0, 0],
[ 2, -7, 22, 120, -11, 2, 0, 0],
[ 1, -6, 20, 121, -10, 2, 0, 0],
[ 1, -6, 18, 122, -9, 2, 0, 0],
[ 1, -5, 15, 123, -8, 2, 0, 0],
[ 1, -4, 13, 124, -7, 1, 0, 0],
[ 1, -4, 11, 125, -6, 1, 0, 0],
[ 1, -3, 8, 126, -5, 1, 0, 0],
[ 1, -2, 6, 126, -4, 1, 0, 0],
[ 0, -1, 4, 127, -3, 1, 0, 0],
[ 0, 0, 2, 127, -1, 0, 0, 0],
[ 0, 0, 0, 127, 1, 0, 0, 0],
[ 0, 0, -1, 127, 2, 0, 0, 0],
[ 0, 1, -3, 127, 4, -2, 1, 0],
[ 0, 1, -5, 127, 6, -2, 1, 0],
[ 0, 2, -6, 126, 8, -3, 1, 0],
[ -1, 2, -7, 126, 11, -4, 2, -1],
[ -1, 3, -8, 125, 13, -5, 2, -1],
[ -1, 3, -10, 124, 16, -6, 3, -1],
[ -1, 4, -11, 123, 18, -7, 3, -1],
[ -1, 4, -12, 122, 20, -7, 3, -1],
[ -1, 4, -13, 121, 23, -8, 3, -1],
[ -2, 5, -14, 120, 25, -9, 4, -1],
[ -1, 5, -15, 119, 27, -10, 4, -1],
[ -1, 5, -16, 118, 30, -11, 4, -1],
[ -2, 6, -17, 116, 33, -12, 5, -1],
[ -2, 6, -17, 114, 35, -12, 5, -1],
[ -2, 6, -18, 113, 38, -13, 5, -1],
[ -2, 7, -19, 111, 41, -14, 6, -2],
[ -2, 7, -19, 110, 43, -15, 6, -2],
[ -2, 7, -20, 108, 46, -15, 6, -2],
[ -2, 7, -20, 106, 49, -16, 6, -2],
[ -2, 7, -21, 104, 51, -16, 7, -2],
[ -2, 7, -21, 102, 54, -17, 7, -2],
[ -2, 8, -21, 100, 56, -18, 7, -2],
[ -2, 8, -22, 98, 59, -18, 7, -2],
[ -2, 8, -22, 96, 62, -19, 7, -2],
[ -2, 8, -22, 94, 64, -19, 7, -2],
[ -2, 8, -22, 91, 67, -20, 8, -2],
[ -2, 8, -22, 89, 69, -20, 8, -2],
[ -2, 8, -22, 87, 72, -21, 8, -2],
[ -2, 8, -21, 84, 74, -21, 8, -2],
[ -2, 8, -22, 82, 77, -21, 8, -2],
[ -2, 8, -21, 79, 79, -21, 8, -2],
[ -2, 8, -21, 77, 82, -22, 8, -2],
[ -2, 8, -21, 74, 84, -21, 8, -2],
[ -2, 8, -21, 72, 87, -22, 8, -2],
[ -2, 8, -20, 69, 89, -22, 8, -2],
[ -2, 8, -20, 67, 91, -22, 8, -2],
[ -2, 7, -19, 64, 94, -22, 8, -2],
[ -2, 7, -19, 62, 96, -22, 8, -2],
[ -2, 7, -18, 59, 98, -22, 8, -2],
[ -2, 7, -18, 56, 100, -21, 8, -2],
[ -2, 7, -17, 54, 102, -21, 7, -2],
[ -2, 7, -16, 51, 104, -21, 7, -2],
[ -2, 6, -16, 49, 106, -20, 7, -2],
[ -2, 6, -15, 46, 108, -20, 7, -2],
[ -2, 6, -15, 43, 110, -19, 7, -2],
[ -2, 6, -14, 41, 111, -19, 7, -2],
[ -1, 5, -13, 38, 113, -18, 6, -2],
[ -1, 5, -12, 35, 114, -17, 6, -2],
[ -1, 5, -12, 33, 116, -17, 6, -2],
[ -1, 4, -11, 30, 118, -16, 5, -1],
[ -1, 4, -10, 27, 119, -15, 5, -1],
[ -1, 4, -9, 25, 120, -14, 5, -2],
[ -1, 3, -8, 23, 121, -13, 4, -1],
[ -1, 3, -7, 20, 122, -12, 4, -1],
[ -1, 3, -7, 18, 123, -11, 4, -1],
[ -1, 3, -6, 16, 124, -10, 3, -1],
[ -1, 2, -5, 13, 125, -8, 3, -1],
[ -1, 2, -4, 11, 126, -7, 2, -1],
[ 0, 1, -3, 8, 126, -6, 2, 0],
[ 0, 1, -2, 6, 127, -5, 1, 0],
[ 0, 1, -2, 4, 127, -3, 1, 0],
[ 0, 0, 0, 2, 127, -1, 0, 0],
[ 0, 0, 0, 1, 127, 0, 0, 0],
[ 0, 0, 0, -1, 127, 2, 0, 0],
[ 0, 0, 1, -3, 127, 4, -1, 0],
[ 0, 0, 1, -4, 126, 6, -2, 1],
[ 0, 0, 1, -5, 126, 8, -3, 1],
[ 0, 0, 1, -6, 125, 11, -4, 1],
[ 0, 0, 1, -7, 124, 13, -4, 1],
[ 0, 0, 2, -8, 123, 15, -5, 1],
[ 0, 0, 2, -9, 122, 18, -6, 1],
[ 0, 0, 2, -10, 121, 20, -6, 1],
[ 0, 0, 2, -11, 120, 22, -7, 2],
[ 0, 0, 2, -12, 119, 25, -8, 2],
[ 0, 0, 3, -13, 117, 27, -8, 2],
[ 0, 0, 3, -13, 116, 29, -9, 2],
[ 0, 0, 3, -14, 114, 32, -10, 3],
[ 0, 0, 3, -15, 113, 35, -10, 2],
[ 0, 0, 3, -15, 111, 37, -11, 3],
[ 0, 0, 3, -16, 109, 40, -11, 3],
[ 0, 0, 3, -16, 108, 42, -12, 3],
[ 0, 0, 4, -17, 106, 45, -13, 3],
[ 0, 0, 4, -17, 104, 47, -13, 3],
[ 0, 0, 4, -17, 102, 50, -14, 3],
[ 0, 0, 4, -17, 100, 52, -14, 3],
[ 0, 0, 4, -18, 98, 55, -15, 4],
[ 0, 0, 4, -18, 96, 58, -15, 3],
[ 0, 0, 4, -18, 94, 60, -16, 4],
[ 0, 0, 4, -18, 91, 63, -16, 4],
[ 0, 0, 4, -18, 89, 65, -16, 4],
[ 0, 0, 4, -18, 87, 68, -17, 4],
[ 0, 0, 4, -18, 85, 70, -17, 4],
[ 0, 0, 4, -18, 82, 73, -17, 4],
[ 0, 0, 4, -18, 80, 75, -17, 4],
[ 0, 0, 4, -18, 78, 78, -18, 4],
[ 0, 0, 4, -17, 75, 80, -18, 4],
[ 0, 0, 4, -17, 73, 82, -18, 4],
[ 0, 0, 4, -17, 70, 85, -18, 4],
[ 0, 0, 4, -17, 68, 87, -18, 4],
[ 0, 0, 4, -16, 65, 89, -18, 4],
[ 0, 0, 4, -16, 63, 91, -18, 4],
[ 0, 0, 4, -16, 60, 94, -18, 4],
[ 0, 0, 3, -15, 58, 96, -18, 4],
[ 0, 0, 4, -15, 55, 98, -18, 4],
[ 0, 0, 3, -14, 52, 100, -17, 4],
[ 0, 0, 3, -14, 50, 102, -17, 4],
[ 0, 0, 3, -13, 47, 104, -17, 4],
[ 0, 0, 3, -13, 45, 106, -17, 4],
[ 0, 0, 3, -12, 42, 108, -16, 3],
[ 0, 0, 3, -11, 40, 109, -16, 3],
[ 0, 0, 3, -11, 37, 111, -15, 3],
[ 0, 0, 2, -10, 35, 113, -15, 3],
[ 0, 0, 3, -10, 32, 114, -14, 3],
[ 0, 0, 2, -9, 29, 116, -13, 3],
[ 0, 0, 2, -8, 27, 117, -13, 3],
[ 0, 0, 2, -8, 25, 119, -12, 2],
[ 0, 0, 2, -7, 22, 120, -11, 2],
[ 0, 0, 1, -6, 20, 121, -10, 2],
[ 0, 0, 1, -6, 18, 122, -9, 2],
[ 0, 0, 1, -5, 15, 123, -8, 2],
[ 0, 0, 1, -4, 13, 124, -7, 1],
[ 0, 0, 1, -4, 11, 125, -6, 1],
[ 0, 0, 1, -3, 8, 126, -5, 1],
[ 0, 0, 1, -2, 6, 126, -4, 1],
[ 0, 0, 0, -1, 4, 127, -3, 1],
[ 0, 0, 0, 0, 2, 127, -1, 0],
[ 0, 0, 0, 0, 2, 127, -1, 0],
];
#[rustfmt::skip]
pub const DIV_LUT: [i32; DIV_LUT_NUM] = [
16384, 16320, 16257, 16194, 16132, 16070, 16009, 15948,
15888, 15828, 15768, 15709, 15650, 15592, 15534, 15477,
15420, 15364, 15308, 15252, 15197, 15142, 15087, 15033,
14980, 14926, 14873, 14821, 14769, 14717, 14665, 14614,
14564, 14513, 14463, 14413, 14364, 14315, 14266, 14218,
14170, 14122, 14075, 14028, 13981, 13935, 13888, 13843,
13797, 13752, 13707, 13662, 13618, 13574, 13530, 13487,
13443, 13400, 13358, 13315, 13273, 13231, 13190, 13148,
13107, 13066, 13026, 12985, 12945, 12906, 12866, 12827,
12788, 12749, 12710, 12672, 12633, 12596, 12558, 12520,
12483, 12446, 12409, 12373, 12336, 12300, 12264, 12228,
12193, 12157, 12122, 12087, 12053, 12018, 11984, 11950,
11916, 11882, 11848, 11815, 11782, 11749, 11716, 11683,
11651, 11619, 11586, 11555, 11523, 11491, 11460, 11429,
11398, 11367, 11336, 11305, 11275, 11245, 11215, 11185,
11155, 11125, 11096, 11067, 11038, 11009, 10980, 10951,
10923, 10894, 10866, 10838, 10810, 10782, 10755, 10727,
10700, 10673, 10645, 10618, 10592, 10565, 10538, 10512,
10486, 10460, 10434, 10408, 10382, 10356, 10331, 10305,
10280, 10255, 10230, 10205, 10180, 10156, 10131, 10107,
10082, 10058, 10034, 10010, 9986, 9963, 9939, 9916,
9892, 9869, 9846, 9823, 9800, 9777, 9754, 9732,
9709, 9687, 9664, 9642, 9620, 9598, 9576, 9554,
9533, 9511, 9489, 9468, 9447, 9425, 9404, 9383,
9362, 9341, 9321, 9300, 9279, 9259, 9239, 9218,
9198, 9178, 9158, 9138, 9118, 9098, 9079, 9059,
9039, 9020, 9001, 8981, 8962, 8943, 8924, 8905,
8886, 8867, 8849, 8830, 8812, 8793, 8775, 8756,
8738, 8720, 8702, 8684, 8666, 8648, 8630, 8613,
8595, 8577, 8560, 8542, 8525, 8508, 8490, 8473,
8456, 8439, 8422, 8405, 8389, 8372, 8355, 8339,
8322, 8306, 8289, 8273, 8257, 8240, 8224, 8208,
8192,
];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Divisor {
pub div_factor: i32,
pub div_shift: u32,
}
#[must_use]
pub fn resolve_divisor(d: i32) -> Option<Divisor> {
if d == 0 {
return None;
}
let abs_d: u32 = d.unsigned_abs();
let n: u32 = 31 - abs_d.leading_zeros();
let e: i32 = (abs_d as i32) - (1i32 << n);
let f: usize = if n > DIV_LUT_BITS {
let shift = n - DIV_LUT_BITS;
(((e as i64) + (1i64 << (shift - 1))) >> shift) as usize
} else {
((e as i64) << (DIV_LUT_BITS - n)) as usize
};
let f = f.min(DIV_LUT_NUM - 1);
let factor = DIV_LUT[f];
Some(Divisor {
div_factor: if d < 0 { -factor } else { factor },
div_shift: n + DIV_LUT_PREC_BITS,
})
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ShearParams {
pub warp_valid: bool,
pub alpha: i32,
pub beta: i32,
pub gamma: i32,
pub delta: i32,
}
#[inline]
fn warp_clip3_i32(low: i32, high: i32, v: i32) -> i32 {
if v < low {
low
} else if v > high {
high
} else {
v
}
}
#[must_use]
pub fn setup_shear(warp_params: [i32; 6]) -> Option<ShearParams> {
let alpha0 = warp_clip3_i32(
-32_768,
32_767,
warp_params[2] - (1i32 << WARP_WARPEDMODEL_PREC_BITS),
);
let beta0 = warp_clip3_i32(-32_768, 32_767, warp_params[3]);
let div = resolve_divisor(warp_params[2])?;
let v: i64 = (warp_params[4] as i64) << WARP_WARPEDMODEL_PREC_BITS;
let gamma_raw = round2_signed(v.saturating_mul(div.div_factor as i64), div.div_shift) as i32;
let gamma0 = warp_clip3_i32(-32_768, 32_767, gamma_raw);
let w: i64 = (warp_params[3] as i64) * (warp_params[4] as i64);
let delta_correction =
round2_signed(w.saturating_mul(div.div_factor as i64), div.div_shift) as i32;
let delta_raw = warp_params[5]
.wrapping_sub(delta_correction)
.wrapping_sub(1i32 << WARP_WARPEDMODEL_PREC_BITS);
let delta0 = warp_clip3_i32(-32_768, 32_767, delta_raw);
let reduce = |x: i32| -> i32 {
(round2_signed(x as i64, WARP_PARAM_REDUCE_BITS) as i32) << WARP_PARAM_REDUCE_BITS
};
let alpha = reduce(alpha0);
let beta = reduce(beta0);
let gamma = reduce(gamma0);
let delta = reduce(delta0);
let bound = 1i32 << WARP_WARPEDMODEL_PREC_BITS;
let warp_valid =
4 * alpha.abs() + 7 * beta.abs() < bound && 4 * gamma.abs() + 4 * delta.abs() < bound;
Some(ShearParams {
warp_valid,
alpha,
beta,
gamma,
delta,
})
}
pub const LEAST_SQUARES_SAMPLES_MAX: usize = 8;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct WarpSampleCand {
pub sy: i32,
pub sx: i32,
pub dy: i32,
pub dx: i32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LocalWarp {
pub local_valid: bool,
pub local_warp_params: [i32; 6],
}
#[inline]
fn ls_product(a: i32, b: i32) -> i64 {
(((a as i64) * (b as i64)) >> 2) + (a as i64) + (b as i64)
}
#[allow(clippy::too_many_arguments)]
#[must_use]
pub fn warp_estimation(
cand_list: &[WarpSampleCand],
mi_row: i32,
mi_col: i32,
block_w4: i32,
block_h4: i32,
mv: [i16; 2],
) -> LocalWarp {
let n = cand_list.len().min(LEAST_SQUARES_SAMPLES_MAX);
let cand = &cand_list[..n];
let mid_y: i32 = mi_row * 4 + block_h4 * 2 - 1;
let mid_x: i32 = mi_col * 4 + block_w4 * 2 - 1;
let suy: i32 = mid_y * 8;
let sux: i32 = mid_x * 8;
let duy: i32 = suy.wrapping_add(mv[0] as i32);
let dux: i32 = sux.wrapping_add(mv[1] as i32);
let mut a00: i64 = 0;
let mut a01: i64 = 0;
let mut a11: i64 = 0;
let mut bx0: i64 = 0;
let mut bx1: i64 = 0;
let mut by0: i64 = 0;
let mut by1: i64 = 0;
for c in cand {
let sy = c.sy.wrapping_sub(suy);
let sx = c.sx.wrapping_sub(sux);
let dy = c.dy.wrapping_sub(duy);
let dx = c.dx.wrapping_sub(dux);
if (sx - dx).abs() < LS_MV_MAX && (sy - dy).abs() < LS_MV_MAX {
a00 += ls_product(sx, sx) + 8;
a01 += ls_product(sx, sy) + 4;
a11 += ls_product(sy, sy) + 8;
bx0 += ls_product(sx, dx) + 8;
bx1 += ls_product(sy, dx) + 4;
by0 += ls_product(sx, dy) + 4;
by1 += ls_product(sy, dy) + 8;
}
}
let det: i64 = a00.saturating_mul(a11) - a01.saturating_mul(a01);
if det == 0 {
return LocalWarp {
local_valid: false,
local_warp_params: [0; 6],
};
}
let abs_det: u64 = det.unsigned_abs();
let n_bits: u32 = 63 - abs_det.leading_zeros();
let e: i64 = (abs_det as i64) - (1i64 << n_bits);
let f: usize = if n_bits > DIV_LUT_BITS {
let shift = n_bits - DIV_LUT_BITS;
let half = 1i64 << (shift - 1);
((e + half) >> shift) as usize
} else {
(e << (DIV_LUT_BITS - n_bits)) as usize
};
let f = f.min(DIV_LUT_NUM - 1);
let mut div_factor: i64 = DIV_LUT[f] as i64;
if det < 0 {
div_factor = -div_factor;
}
let mut div_shift: i32 = (n_bits + DIV_LUT_PREC_BITS) as i32;
div_shift -= WARP_WARPEDMODEL_PREC_BITS as i32;
if div_shift < 0 {
div_factor <<= (-div_shift) as u32;
div_shift = 0;
}
let div_shift_u: u32 = div_shift as u32;
let nondiag_clamp_lo = -WARPEDMODEL_NONDIAGAFFINE_CLAMP + 1;
let nondiag_clamp_hi = WARPEDMODEL_NONDIAGAFFINE_CLAMP - 1;
let diag_one: i32 = 1i32 << WARP_WARPEDMODEL_PREC_BITS;
let diag_clamp_lo = diag_one - WARPEDMODEL_NONDIAGAFFINE_CLAMP + 1;
let diag_clamp_hi = diag_one + WARPEDMODEL_NONDIAGAFFINE_CLAMP - 1;
let diag = |v: i64| -> i32 {
let raw = round2_signed(v.saturating_mul(div_factor), div_shift_u);
warp_clip3_i32(diag_clamp_lo, diag_clamp_hi, raw as i32)
};
let nondiag = |v: i64| -> i32 {
let raw = round2_signed(v.saturating_mul(div_factor), div_shift_u);
warp_clip3_i32(nondiag_clamp_lo, nondiag_clamp_hi, raw as i32)
};
let mut params = [0i32; 6];
params[2] = diag(a11 * bx0 - a01 * bx1);
params[3] = nondiag(-a01 * bx0 + a00 * bx1);
params[4] = nondiag(a11 * by0 - a01 * by1);
params[5] = diag(-a01 * by0 + a00 * by1);
let mvx: i32 = mv[1] as i32;
let mvy: i32 = mv[0] as i32;
let shift_3: u32 = WARP_WARPEDMODEL_PREC_BITS - 3;
let vx: i64 = (mvx as i64) * (1i64 << shift_3)
- ((mid_x as i64) * ((params[2] - diag_one) as i64) + (mid_y as i64) * (params[3] as i64));
let vy: i64 = (mvy as i64) * (1i64 << shift_3)
- ((mid_x as i64) * (params[4] as i64) + (mid_y as i64) * ((params[5] - diag_one) as i64));
let vx_clamped = if vx < -(WARPEDMODEL_TRANS_CLAMP as i64) {
-WARPEDMODEL_TRANS_CLAMP
} else if vx > (WARPEDMODEL_TRANS_CLAMP as i64) - 1 {
WARPEDMODEL_TRANS_CLAMP - 1
} else {
vx as i32
};
let vy_clamped = if vy < -(WARPEDMODEL_TRANS_CLAMP as i64) {
-WARPEDMODEL_TRANS_CLAMP
} else if vy > (WARPEDMODEL_TRANS_CLAMP as i64) - 1 {
WARPEDMODEL_TRANS_CLAMP - 1
} else {
vy as i32
};
params[0] = vx_clamped;
params[1] = vy_clamped;
LocalWarp {
local_valid: true,
local_warp_params: params,
}
}
pub const USE_WARP_LOCAL: u8 = 1;
pub const USE_WARP_GLOBAL: u8 = 2;
#[allow(clippy::too_many_arguments)]
pub fn block_warp(
use_warp: u8,
plane: u8,
subsampling_x: u8,
subsampling_y: u8,
x: i32,
y: i32,
i8b: i32,
j8b: i32,
w: usize,
h: usize,
ref_plane: &[u16],
ref_stride: usize,
ref_upscaled_width: u32,
ref_frame_height: u32,
warp_params: [i32; 6],
inter_round0: u32,
inter_round1: u32,
pred_stride: usize,
pred: &mut [i32],
) -> Result<(), crate::Error> {
if !matches!(use_warp, USE_WARP_LOCAL | USE_WARP_GLOBAL) {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if plane > 2 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if subsampling_x > 1 || subsampling_y > 1 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if w == 0 || h == 0 || w > 128 || h > 128 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if i8b < 0 || j8b < 0 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if (i8b as usize) * 8 >= h || (j8b as usize) * 8 >= w {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if ref_upscaled_width == 0 || ref_frame_height == 0 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if pred_stride < w {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if pred.len() < h * pred_stride {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let sub_x: u32 = if plane == 0 { 0 } else { subsampling_x as u32 };
let sub_y: u32 = if plane == 0 { 0 } else { subsampling_y as u32 };
let last_x: i32 = (((ref_upscaled_width as i32) + (sub_x as i32)) >> sub_x) - 1;
let last_y: i32 = (((ref_frame_height as i32) + (sub_y as i32)) >> sub_y) - 1;
if (last_x as usize) >= ref_stride {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if ref_plane.len() < ((last_y as usize) + 1) * ref_stride {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let src_x: i32 = (x + j8b * 8 + 4) << sub_x;
let src_y: i32 = (y + i8b * 8 + 4) << sub_y;
let dst_x: i64 = (warp_params[2] as i64) * (src_x as i64)
+ (warp_params[3] as i64) * (src_y as i64)
+ (warp_params[0] as i64);
let dst_y: i64 = (warp_params[4] as i64) * (src_x as i64)
+ (warp_params[5] as i64) * (src_y as i64)
+ (warp_params[1] as i64);
let shear = setup_shear(warp_params).ok_or(crate::Error::PartitionWalkOutOfRange)?;
let alpha = shear.alpha as i64;
let beta = shear.beta as i64;
let gamma = shear.gamma as i64;
let delta = shear.delta as i64;
let prec_mask: i64 = (1i64 << WARP_WARPEDMODEL_PREC_BITS) - 1;
let x4: i64 = dst_x >> (sub_x as i64);
let y4: i64 = dst_y >> (sub_y as i64);
let ix4: i32 = (x4 >> WARP_WARPEDMODEL_PREC_BITS) as i32;
let sx4: i64 = x4 & prec_mask;
let iy4: i32 = (y4 >> WARP_WARPEDMODEL_PREC_BITS) as i32;
let sy4: i64 = y4 & prec_mask;
const INTER_ROWS: usize = 15;
const INTER_COLS: usize = 8;
let mut intermediate = [[0i32; INTER_COLS]; INTER_ROWS];
for i1 in -7i32..8 {
for i2 in -4i32..4 {
let sx: i64 = sx4 + alpha * (i2 as i64) + beta * (i1 as i64);
let offs_signed: i64 =
round2(sx, WARPEDDIFF_PREC_BITS) + (WARPEDPIXEL_PREC_SHIFTS as i64);
let offs = warp_clip3_i32(
0,
(WARPEDPIXEL_PREC_SHIFTS * 3) as i32,
offs_signed.max(i32::MIN as i64).min(i32::MAX as i64) as i32,
) as usize;
let ry = warp_clip3_i32(0, last_y, iy4 + i1) as usize;
let base = ry * ref_stride;
let mut s: i64 = 0;
for (i3, coef) in WARPED_FILTERS[offs].iter().enumerate() {
let rx = warp_clip3_i32(0, last_x, ix4 + i2 - 3 + (i3 as i32)) as usize;
s += (*coef as i64) * (ref_plane[base + rx] as i64);
}
intermediate[(i1 + 7) as usize][(i2 + 4) as usize] = round2(s, inter_round0) as i32;
}
}
let h_remaining: i32 = (h as i32) - i8b * 8 - 4;
let w_remaining: i32 = (w as i32) - j8b * 8 - 4;
let i_limit: i32 = h_remaining.min(4);
let j_limit: i32 = w_remaining.min(4);
for i1 in -4i32..i_limit {
for i2 in -4i32..j_limit {
let sy: i64 = sy4 + gamma * (i2 as i64) + delta * (i1 as i64);
let offs_signed: i64 =
round2(sy, WARPEDDIFF_PREC_BITS) + (WARPEDPIXEL_PREC_SHIFTS as i64);
let offs = warp_clip3_i32(
0,
(WARPEDPIXEL_PREC_SHIFTS * 3) as i32,
offs_signed.max(i32::MIN as i64).min(i32::MAX as i64) as i32,
) as usize;
let mut s: i64 = 0;
for (i3, coef) in WARPED_FILTERS[offs].iter().enumerate() {
let inter_row = (i1 + (i3 as i32) + 4) as usize;
let v = intermediate[inter_row][(i2 + 4) as usize] as i64;
s += (*coef as i64) * v;
}
let row = (i8b as usize) * 8 + (i1 + 4) as usize;
let col = (j8b as usize) * 8 + (i2 + 4) as usize;
pred[row * pred_stride + col] = round2(s, inter_round1) as i32;
}
}
Ok(())
}
pub const OBMC_MASK_2: [u8; 2] = [45, 64];
pub const OBMC_MASK_4: [u8; 4] = [39, 50, 59, 64];
pub const OBMC_MASK_8: [u8; 8] = [36, 42, 48, 53, 57, 61, 64, 64];
pub const OBMC_MASK_16: [u8; 16] = [
34, 37, 40, 43, 46, 49, 52, 54, 56, 58, 60, 61, 64, 64, 64, 64,
];
pub const OBMC_MASK_32: [u8; 32] = [
33, 35, 36, 38, 40, 41, 43, 44, 45, 47, 48, 50, 51, 52, 53, 55, 56, 57, 58, 59, 60, 60, 61, 62,
64, 64, 64, 64, 64, 64, 64, 64,
];
pub fn get_obmc_mask(length: usize) -> &'static [u8] {
if length == 2 {
&OBMC_MASK_2
} else if length == 4 {
&OBMC_MASK_4
} else if length == 8 {
&OBMC_MASK_8
} else if length == 16 {
&OBMC_MASK_16
} else {
&OBMC_MASK_32
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum OverlapPass {
Above,
Left,
}
#[allow(clippy::too_many_arguments)]
pub fn overlap_blending(
current_plane: &mut [u16],
curr_stride: usize,
pred_x: usize,
pred_y: usize,
pred_w: usize,
pred_h: usize,
pass: OverlapPass,
obmc_pred: &[u16],
obmc_stride: usize,
mask: &[u8],
) -> Result<(), crate::Error> {
if pred_w == 0 || pred_h == 0 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if obmc_stride < pred_w {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if curr_stride < pred_x.saturating_add(pred_w) {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if obmc_pred.len() < pred_h * obmc_stride {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let needed_curr_rows = pred_y.saturating_add(pred_h);
if current_plane.len() < needed_curr_rows.saturating_mul(curr_stride) {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let mask_axis_len = match pass {
OverlapPass::Above => pred_h,
OverlapPass::Left => pred_w,
};
if mask.len() < mask_axis_len {
return Err(crate::Error::PartitionWalkOutOfRange);
}
match pass {
OverlapPass::Above => {
for (i, &mi) in mask.iter().enumerate().take(pred_h) {
let m: u32 = mi as u32;
let curr_row_base = (pred_y + i) * curr_stride;
let obmc_row_base = i * obmc_stride;
for j in 0..pred_w {
let curr_idx = curr_row_base + pred_x + j;
let obmc_idx = obmc_row_base + j;
let curr_sample = current_plane[curr_idx] as u32;
let obmc_sample = obmc_pred[obmc_idx] as u32;
let blended = m * curr_sample + (64 - m) * obmc_sample;
current_plane[curr_idx] = ((blended + (1u32 << 5)) >> 6) as u16;
}
}
}
OverlapPass::Left => {
for i in 0..pred_h {
let curr_row_base = (pred_y + i) * curr_stride;
let obmc_row_base = i * obmc_stride;
for (j, &mj) in mask.iter().enumerate().take(pred_w) {
let m: u32 = mj as u32;
let curr_idx = curr_row_base + pred_x + j;
let obmc_idx = obmc_row_base + j;
let curr_sample = current_plane[curr_idx] as u32;
let obmc_sample = obmc_pred[obmc_idx] as u32;
let blended = m * curr_sample + (64 - m) * obmc_sample;
current_plane[curr_idx] = ((blended + (1u32 << 5)) >> 6) as u16;
}
}
}
}
Ok(())
}
#[allow(clippy::too_many_arguments)]
pub fn overlap_neighbour_predict_blend(
current_plane: &mut [u16],
curr_stride: usize,
pred_x: usize,
pred_y: usize,
pred_w: usize,
pred_h: usize,
pass: OverlapPass,
obmc_pred: &[u16],
obmc_stride: usize,
mask_length: usize,
) -> Result<(), crate::Error> {
let mask = get_obmc_mask(mask_length);
overlap_blending(
current_plane,
curr_stride,
pred_x,
pred_y,
pred_w,
pred_h,
pass,
obmc_pred,
obmc_stride,
mask,
)
}
#[derive(Debug, Clone, Copy)]
pub struct InterModeInfo {
pub ref_frame: u8,
pub mv: [i16; 2],
}
#[derive(Debug, Clone, Copy)]
pub struct RefFrameStoreEntry<'a> {
pub plane: &'a [u16],
pub stride: usize,
pub upscaled_width: u32,
pub width: u32,
pub height: u32,
}
#[allow(clippy::too_many_arguments)]
pub fn reconstruct_inter_block(
mode_info: InterModeInfo,
ref_frame_idx: &[u8],
frame_store: &[RefFrameStoreEntry<'_>],
plane: u8,
x: i32,
y: i32,
w: usize,
h: usize,
bit_depth: u8,
subsampling_x: u8,
subsampling_y: u8,
frame_width: u32,
frame_height: u32,
interp_filter_x: u8,
interp_filter_y: u8,
curr_plane: &mut [u16],
curr_stride: usize,
) -> Result<(), crate::Error> {
let ref_frame = mode_info.ref_frame as usize;
if !(crate::uncompressed_header_tail::LAST_FRAME
..=crate::uncompressed_header_tail::ALTREF_FRAME)
.contains(&ref_frame)
{
return Err(crate::Error::PartitionWalkOutOfRange);
}
let slot = ref_frame - crate::uncompressed_header_tail::LAST_FRAME;
let ref_idx = *ref_frame_idx
.get(slot)
.ok_or(crate::Error::PartitionWalkOutOfRange)? as usize;
let entry = frame_store
.get(ref_idx)
.ok_or(crate::Error::PartitionWalkOutOfRange)?;
let refs = [PredictInterRef {
ref_plane: entry.plane,
ref_stride: entry.stride,
ref_upscaled_width: entry.upscaled_width,
ref_width: entry.width,
ref_height: entry.height,
mv: mode_info.mv,
}];
let mut pred_out = vec![0u16; w * h];
predict_inter(
plane,
x,
y,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
bit_depth,
subsampling_x,
subsampling_y,
frame_width,
frame_height,
interp_filter_x,
interp_filter_y,
&refs,
None,
None,
None,
None,
&mut pred_out,
)?;
if x < 0 || y < 0 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let (px, py) = (x as usize, y as usize);
if curr_stride == 0 || px >= curr_stride {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let plane_rows = curr_plane.len() / curr_stride;
if py >= plane_rows {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let fit_w = w.min(curr_stride - px);
let fit_h = h.min(plane_rows - py);
for i in 0..fit_h {
let dst = (py + i) * curr_stride + px;
let src = i * w;
curr_plane[dst..dst + fit_w].copy_from_slice(&pred_out[src..src + fit_w]);
}
Ok(())
}
#[allow(clippy::too_many_arguments)]
pub fn reconstruct_inter_block_warp(
mode_info: InterModeInfo,
warp: &WarpDriverParams,
ref_frame_idx: &[u8],
frame_store: &[RefFrameStoreEntry<'_>],
plane: u8,
x: i32,
y: i32,
w: usize,
h: usize,
bit_depth: u8,
subsampling_x: u8,
subsampling_y: u8,
frame_width: u32,
frame_height: u32,
interp_filter_x: u8,
interp_filter_y: u8,
curr_plane: &mut [u16],
curr_stride: usize,
) -> Result<(), crate::Error> {
let ref_frame = mode_info.ref_frame as usize;
if !(crate::uncompressed_header_tail::LAST_FRAME
..=crate::uncompressed_header_tail::ALTREF_FRAME)
.contains(&ref_frame)
{
return Err(crate::Error::PartitionWalkOutOfRange);
}
let slot = ref_frame - crate::uncompressed_header_tail::LAST_FRAME;
let ref_idx = *ref_frame_idx
.get(slot)
.ok_or(crate::Error::PartitionWalkOutOfRange)? as usize;
let entry = frame_store
.get(ref_idx)
.ok_or(crate::Error::PartitionWalkOutOfRange)?;
let refs = [PredictInterRef {
ref_plane: entry.plane,
ref_stride: entry.stride,
ref_upscaled_width: entry.upscaled_width,
ref_width: entry.width,
ref_height: entry.height,
mv: mode_info.mv,
}];
let mut pred_out = vec![0u16; w * h];
predict_inter(
plane,
x,
y,
w,
h,
crate::cdf::MOTION_MODE_WARPED_CAUSAL,
false,
false,
bit_depth,
subsampling_x,
subsampling_y,
frame_width,
frame_height,
interp_filter_x,
interp_filter_y,
&refs,
None,
None,
Some(warp),
None,
&mut pred_out,
)?;
if x < 0 || y < 0 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let (px, py) = (x as usize, y as usize);
if curr_stride == 0 || px >= curr_stride {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let plane_rows = curr_plane.len() / curr_stride;
if py >= plane_rows {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let fit_w = w.min(curr_stride - px);
let fit_h = h.min(plane_rows - py);
for i in 0..fit_h {
let dst = (py + i) * curr_stride + px;
let src = i * w;
curr_plane[dst..dst + fit_w].copy_from_slice(&pred_out[src..src + fit_w]);
}
Ok(())
}
#[allow(clippy::too_many_arguments)]
pub fn reconstruct_inter_block_obmc(
mode_info: InterModeInfo,
obmc: &ObmcParams<'_, '_>,
ref_frame_idx: &[u8],
frame_store: &[RefFrameStoreEntry<'_>],
plane: u8,
x: i32,
y: i32,
w: usize,
h: usize,
bit_depth: u8,
subsampling_x: u8,
subsampling_y: u8,
frame_width: u32,
frame_height: u32,
interp_filter_x: u8,
interp_filter_y: u8,
curr_plane: &mut [u16],
curr_stride: usize,
) -> Result<(), crate::Error> {
let ref_frame = mode_info.ref_frame as usize;
if !(crate::uncompressed_header_tail::LAST_FRAME
..=crate::uncompressed_header_tail::ALTREF_FRAME)
.contains(&ref_frame)
{
return Err(crate::Error::PartitionWalkOutOfRange);
}
let slot = ref_frame - crate::uncompressed_header_tail::LAST_FRAME;
let ref_idx = *ref_frame_idx
.get(slot)
.ok_or(crate::Error::PartitionWalkOutOfRange)? as usize;
let entry = frame_store
.get(ref_idx)
.ok_or(crate::Error::PartitionWalkOutOfRange)?;
let refs = [PredictInterRef {
ref_plane: entry.plane,
ref_stride: entry.stride,
ref_upscaled_width: entry.upscaled_width,
ref_width: entry.width,
ref_height: entry.height,
mv: mode_info.mv,
}];
let mut pred_out = vec![0u16; w * h];
predict_inter(
plane,
x,
y,
w,
h,
crate::cdf::MOTION_MODE_OBMC,
false,
false,
bit_depth,
subsampling_x,
subsampling_y,
frame_width,
frame_height,
interp_filter_x,
interp_filter_y,
&refs,
None,
None,
None,
Some(obmc),
&mut pred_out,
)?;
if x < 0 || y < 0 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let (px, py) = (x as usize, y as usize);
if curr_stride == 0 || px >= curr_stride {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let plane_rows = curr_plane.len() / curr_stride;
if py >= plane_rows {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let fit_w = w.min(curr_stride - px);
let fit_h = h.min(plane_rows - py);
for i in 0..fit_h {
let dst = (py + i) * curr_stride + px;
let src = i * w;
curr_plane[dst..dst + fit_w].copy_from_slice(&pred_out[src..src + fit_w]);
}
Ok(())
}
#[derive(Debug, Clone, Copy)]
pub struct CompoundInterModeInfo {
pub ref_frame_0: u8,
pub ref_frame_1: u8,
pub mv0: [i16; 2],
pub mv1: [i16; 2],
pub compound_type: u8,
pub wedge: Option<WedgeModeInfo>,
pub mask_type: u8,
}
#[derive(Debug, Clone, Copy)]
pub struct WedgeModeInfo {
pub mi_size: usize,
pub wedge_index: u8,
pub wedge_sign: u8,
}
#[derive(Debug, Clone, Copy)]
pub struct CompoundOrderHintContext {
pub order_hint_bits: u32,
pub current_order_hint: i32,
pub order_hint_ref0: i32,
pub order_hint_ref1: i32,
}
#[allow(clippy::too_many_arguments)]
pub fn reconstruct_inter_block_compound(
mode_info: CompoundInterModeInfo,
order_hints: CompoundOrderHintContext,
ref_frame_idx: &[u8],
frame_store: &[RefFrameStoreEntry<'_>],
plane: u8,
x: i32,
y: i32,
w: usize,
h: usize,
bit_depth: u8,
subsampling_x: u8,
subsampling_y: u8,
frame_width: u32,
frame_height: u32,
interp_filter_x: u8,
interp_filter_y: u8,
diffwtd_mask: Option<&mut [u8]>,
warp: Option<&WarpDriverParams>,
curr_plane: &mut [u16],
curr_stride: usize,
) -> Result<(), crate::Error> {
if !matches!(
mode_info.compound_type,
COMPOUND_AVERAGE | COMPOUND_DISTANCE | COMPOUND_WEDGE | COMPOUND_DIFFWTD
) {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if mode_info.compound_type == COMPOUND_DIFFWTD && diffwtd_mask.is_none() {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let resolve = |rf: u8| -> Result<&RefFrameStoreEntry<'_>, crate::Error> {
let rf = rf as usize;
if !(crate::uncompressed_header_tail::LAST_FRAME
..=crate::uncompressed_header_tail::ALTREF_FRAME)
.contains(&rf)
{
return Err(crate::Error::PartitionWalkOutOfRange);
}
let slot = rf - crate::uncompressed_header_tail::LAST_FRAME;
let ref_idx = *ref_frame_idx
.get(slot)
.ok_or(crate::Error::PartitionWalkOutOfRange)? as usize;
frame_store
.get(ref_idx)
.ok_or(crate::Error::PartitionWalkOutOfRange)
};
let entry0 = resolve(mode_info.ref_frame_0)?;
let entry1 = resolve(mode_info.ref_frame_1)?;
let refs = [
PredictInterRef {
ref_plane: entry0.plane,
ref_stride: entry0.stride,
ref_upscaled_width: entry0.upscaled_width,
ref_width: entry0.width,
ref_height: entry0.height,
mv: mode_info.mv0,
},
PredictInterRef {
ref_plane: entry1.plane,
ref_stride: entry1.stride,
ref_upscaled_width: entry1.upscaled_width,
ref_width: entry1.width,
ref_height: entry1.height,
mv: mode_info.mv1,
},
];
let wedge_mask_buf: Option<(Vec<u8>, usize)> = if mode_info.compound_type == COMPOUND_WEDGE {
let wedge = mode_info
.wedge
.ok_or(crate::Error::PartitionWalkOutOfRange)?;
if wedge.mi_size >= crate::cdf::BLOCK_SIZES {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let n4w = crate::cdf::num_4x4_blocks_wide(wedge.mi_size) as u32;
let n4h = crate::cdf::num_4x4_blocks_high(wedge.mi_size) as u32;
let luma_w = crate::cdf::block_width(wedge.mi_size);
let luma_h = crate::cdf::block_height(wedge.mi_size);
let mut buf = vec![0u8; luma_w * luma_h];
wedge_mask(
wedge.mi_size,
n4w,
n4h,
wedge.wedge_index,
wedge.wedge_sign,
&mut buf,
)?;
Some((buf, luma_w))
} else {
None
};
let compound = match mode_info.compound_type {
COMPOUND_DISTANCE => {
let weights = distance_weights(
order_hints.order_hint_bits,
order_hints.current_order_hint,
order_hints.order_hint_ref0,
order_hints.order_hint_ref1,
);
CompoundParams::Distance(weights)
}
COMPOUND_WEDGE => {
let (mask, luma_w) = wedge_mask_buf
.as_ref()
.expect("WEDGE arm materialized the mask above");
CompoundParams::Wedge {
mask,
mask_stride: *luma_w,
}
}
COMPOUND_DIFFWTD => {
let mask = diffwtd_mask.expect("DIFFWTD arm requires diffwtd_mask (gated above)");
CompoundParams::Diffwtd {
mask_type: mode_info.mask_type,
mask,
}
}
_ => CompoundParams::Average,
};
let mut pred_out = vec![0u16; w * h];
predict_inter(
plane,
x,
y,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
true,
false,
bit_depth,
subsampling_x,
subsampling_y,
frame_width,
frame_height,
interp_filter_x,
interp_filter_y,
&refs,
Some(compound),
None,
warp,
None,
&mut pred_out,
)?;
if x < 0 || y < 0 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let (px, py) = (x as usize, y as usize);
if curr_stride == 0 || px >= curr_stride {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let plane_rows = curr_plane.len() / curr_stride;
if py >= plane_rows {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let fit_w = w.min(curr_stride - px);
let fit_h = h.min(plane_rows - py);
for i in 0..fit_h {
let dst = (py + i) * curr_stride + px;
let src = i * w;
curr_plane[dst..dst + fit_w].copy_from_slice(&pred_out[src..src + fit_w]);
}
Ok(())
}
#[derive(Debug, Clone, Copy)]
pub struct InterIntraModeInfo {
pub ref_frame: u8,
pub mv: [i16; 2],
pub interintra_mode: u8,
pub wedge: Option<InterIntraWedgeModeInfo>,
}
#[derive(Debug, Clone, Copy)]
pub struct InterIntraWedgeModeInfo {
pub mi_size: usize,
pub wedge_index: u8,
}
#[allow(clippy::too_many_arguments)]
pub fn reconstruct_inter_block_interintra(
mode_info: InterIntraModeInfo,
ref_frame_idx: &[u8],
frame_store: &[RefFrameStoreEntry<'_>],
plane: u8,
x: i32,
y: i32,
w: usize,
h: usize,
bit_depth: u8,
subsampling_x: u8,
subsampling_y: u8,
frame_width: u32,
frame_height: u32,
interp_filter_x: u8,
interp_filter_y: u8,
wedge_mask_buf: Option<&mut [u8]>,
warp: Option<&WarpDriverParams>,
curr_plane: &mut [u16],
curr_stride: usize,
) -> Result<(), crate::Error> {
let ref_frame = mode_info.ref_frame as usize;
if !(crate::uncompressed_header_tail::LAST_FRAME
..=crate::uncompressed_header_tail::ALTREF_FRAME)
.contains(&ref_frame)
{
return Err(crate::Error::PartitionWalkOutOfRange);
}
let slot = ref_frame - crate::uncompressed_header_tail::LAST_FRAME;
let ref_idx = *ref_frame_idx
.get(slot)
.ok_or(crate::Error::PartitionWalkOutOfRange)? as usize;
let entry = frame_store
.get(ref_idx)
.ok_or(crate::Error::PartitionWalkOutOfRange)?;
let refs = [PredictInterRef {
ref_plane: entry.plane,
ref_stride: entry.stride,
ref_upscaled_width: entry.upscaled_width,
ref_width: entry.width,
ref_height: entry.height,
mv: mode_info.mv,
}];
if x < 0 || y < 0 {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let (px, py) = (x as usize, y as usize);
if curr_stride == 0 || px >= curr_stride {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let plane_rows = curr_plane.len() / curr_stride;
if py >= plane_rows {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let fit_w = w.min(curr_stride - px);
let fit_h = h.min(plane_rows - py);
let mut pred_out = vec![0u16; w * h];
for i in 0..fit_h {
let src = (py + i) * curr_stride + px;
let dst = i * w;
pred_out[dst..dst + fit_w].copy_from_slice(&curr_plane[src..src + fit_w]);
}
let wedge_params: Option<InterIntraParams<'_>> = match mode_info.wedge {
None => Some(InterIntraParams {
interintra_mode: mode_info.interintra_mode,
wedge: None,
}),
Some(wi) => {
let buf = wedge_mask_buf.ok_or(crate::Error::PartitionWalkOutOfRange)?;
if wi.mi_size >= crate::cdf::BLOCK_SIZES {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let luma_w = crate::cdf::block_width(wi.mi_size);
let luma_h = crate::cdf::block_height(wi.mi_size);
if buf.len() < luma_w * luma_h {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if plane == 0 {
let n4w = crate::cdf::num_4x4_blocks_wide(wi.mi_size) as u32;
let n4h = crate::cdf::num_4x4_blocks_high(wi.mi_size) as u32;
wedge_mask(
wi.mi_size,
n4w,
n4h,
wi.wedge_index,
0,
&mut buf[..luma_w * luma_h],
)?;
}
Some(InterIntraParams {
interintra_mode: mode_info.interintra_mode,
wedge: Some(WedgeInterIntraInfo {
mask: &buf[..luma_w * luma_h],
mask_stride: luma_w,
}),
})
}
};
predict_inter(
plane,
x,
y,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
true,
bit_depth,
subsampling_x,
subsampling_y,
frame_width,
frame_height,
interp_filter_x,
interp_filter_y,
&refs,
None,
wedge_params,
warp,
None,
&mut pred_out,
)?;
for i in 0..fit_h {
let dst = (py + i) * curr_stride + px;
let src = i * w;
curr_plane[dst..dst + fit_w].copy_from_slice(&pred_out[src..src + fit_w]);
}
Ok(())
}
#[derive(Debug, Clone, Copy)]
pub struct InterIntraLeaf {
pub mode_info: InterIntraModeInfo,
pub mi_size: usize,
pub mi_row: u32,
pub mi_col: u32,
pub interp_filter_x: u8,
pub interp_filter_y: u8,
}
pub fn reconstruct_inter_intra_block(
leaf: &InterIntraLeaf,
ref_frame_idx: &[u8],
bit_depth: u8,
warp: Option<&WarpDriverParams>,
planes: &mut [PlaneReconContext<'_>],
) -> Result<(), crate::Error> {
if leaf.mi_size >= crate::cdf::BLOCK_SIZES {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let mut wedge_buf: Option<Vec<u8>> = if leaf.mode_info.wedge.is_some() {
Some(vec![
0u8;
crate::cdf::block_width(leaf.mi_size)
* crate::cdf::block_height(leaf.mi_size)
])
} else {
None
};
for ctx in planes.iter_mut() {
let sub_x = if ctx.plane > 0 { ctx.subsampling_x } else { 0 };
let sub_y = if ctx.plane > 0 { ctx.subsampling_y } else { 0 };
let base_x = ((leaf.mi_col >> sub_x) * crate::cdf::MI_SIZE as u32) as i32;
let base_y = ((leaf.mi_row >> sub_y) * crate::cdf::MI_SIZE as u32) as i32;
let pred_w = crate::cdf::block_width(leaf.mi_size) >> sub_x;
let pred_h = crate::cdf::block_height(leaf.mi_size) >> sub_y;
reconstruct_inter_block_interintra(
leaf.mode_info,
ref_frame_idx,
ctx.frame_store,
ctx.plane,
base_x,
base_y,
pred_w,
pred_h,
bit_depth,
ctx.subsampling_x,
ctx.subsampling_y,
ctx.frame_width,
ctx.frame_height,
leaf.interp_filter_x,
leaf.interp_filter_y,
wedge_buf.as_deref_mut(),
warp,
ctx.curr,
ctx.curr_stride,
)?;
}
Ok(())
}
pub fn reconstruct_inter_intra_from_dispatch(
readout: &crate::cdf::ComputePredictionReadout,
leaf: &InterIntraLeaf,
ref_frame_idx: &[u8],
bit_depth: u8,
warp: Option<&WarpDriverParams>,
planes: &mut [PlaneReconContext<'_>],
) -> Result<(), crate::Error> {
if !readout.is_inter_intra {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if (readout.num_planes_visited as usize) < planes.len() {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let expected_intra_mode = match leaf.mode_info.interintra_mode {
II_V_PRED => crate::cdf::V_PRED as u8,
II_H_PRED => crate::cdf::H_PRED as u8,
II_DC_PRED => crate::cdf::DC_PRED as u8,
_ => crate::cdf::SMOOTH_PRED as u8,
};
for ctx in planes.iter() {
let intra_half = readout
.tasks
.iter()
.find(|t| t.plane == ctx.plane && t.mode == expected_intra_mode);
if intra_half.is_none() {
return Err(crate::Error::PartitionWalkOutOfRange);
}
}
reconstruct_inter_intra_block(leaf, ref_frame_idx, bit_depth, warp, planes)
}
#[derive(Debug, Clone, Copy)]
pub struct PlaneRefSpec<'a> {
pub plane: u8,
pub subsampling_x: u8,
pub subsampling_y: u8,
pub frame_store: &'a [RefFrameStoreEntry<'a>],
pub frame_width: u32,
pub frame_height: u32,
}
#[derive(Debug)]
pub struct PlaneReconContext<'a> {
pub plane: u8,
pub subsampling_x: u8,
pub subsampling_y: u8,
pub frame_store: &'a [RefFrameStoreEntry<'a>],
pub frame_width: u32,
pub frame_height: u32,
pub curr: &'a mut [u16],
pub curr_stride: usize,
}
#[derive(Debug)]
pub struct InterModeInfoGrid<'a> {
pub mi_sizes: &'a [usize],
pub is_inters: &'a [u8],
pub ref_frames: &'a [i8],
pub mvs: &'a [i16],
pub interp_filters: &'a [u8],
pub compound_types: &'a [u8],
pub wedge_indices: &'a [u8],
pub wedge_signs: &'a [u8],
pub mask_types: &'a [u8],
pub interintra_modes: &'a [u8],
pub wedge_interintras: &'a [u8],
pub interintra_wedge_indices: &'a [u8],
pub order_hint_bits: u32,
pub current_order_hint: i32,
pub order_hints_by_ref: &'a [i32],
pub mi_rows: u32,
pub mi_cols: u32,
pub bit_depth: u8,
pub warp: Option<GridWarpContext<'a>>,
pub obmc: Option<GridObmcContext<'a>>,
}
#[derive(Debug, Clone, Copy)]
pub struct GridWarpContext<'a> {
pub motion_modes: &'a [u8],
pub local_warp_params: &'a [i32],
pub local_warp_valid: &'a [u8],
pub y_modes: &'a [u8],
pub gm_types: &'a [u8],
pub gm_params: &'a [i32],
pub force_integer_mv: bool,
pub is_scaled: &'a [bool],
}
#[derive(Debug, Clone, Copy)]
pub struct GridObmcContext<'a> {
pub motion_modes: &'a [u8],
pub avail_u: &'a [u8],
pub avail_l: &'a [u8],
}
#[allow(clippy::too_many_arguments)]
fn obmc_dispatch_leaf(
grid: &InterModeInfoGrid<'_>,
oc: &GridObmcContext<'_>,
ref_frame_idx: &[u8],
planes: &mut [PlaneReconContext<'_>],
mi_row: usize,
mi_col: usize,
mi_size: usize,
ref_frame0: i8,
) -> Result<(), crate::Error> {
let mi_rows = grid.mi_rows as usize;
let mi_cols = grid.mi_cols as usize;
let origin = mi_row * mi_cols + mi_col;
let block_ref_frame = ref_frame0;
if !(crate::uncompressed_header_tail::LAST_FRAME as i8
..=crate::uncompressed_header_tail::ALTREF_FRAME as i8)
.contains(&block_ref_frame)
{
return Err(crate::Error::PartitionWalkOutOfRange);
}
let block_mode_info = InterModeInfo {
ref_frame: block_ref_frame as u8,
mv: [grid.mvs[origin * 4], grid.mvs[origin * 4 + 1]],
};
let avail_u = oc.avail_u[origin] != 0;
let avail_l = oc.avail_l[origin] != 0;
let interp_x = grid.interp_filters[origin * 2 + 1];
let interp_y = grid.interp_filters[origin * 2];
const INTRA_FRAME_REF0: i8 = crate::uncompressed_header_tail::INTRA_FRAME as i8;
let clip4 = |n: usize| -> usize { n.clamp(2, 16) };
for ctx in planes.iter_mut() {
let p = ctx.plane;
let sub_x = if p > 0 { ctx.subsampling_x } else { 0 };
let sub_y = if p > 0 { ctx.subsampling_y } else { 0 };
let plane_sz = crate::cdf::get_plane_residual_size(mi_size, p, sub_x, sub_y)
.ok_or(crate::Error::PartitionWalkOutOfRange)?;
let above_gate = avail_u && plane_sz >= crate::cdf::BLOCK_8X8;
let mut above: Vec<ObmcNeighbour<'_>> = Vec::new();
if above_gate {
let w4 = crate::cdf::num_4x4_blocks_wide(mi_size);
let n_limit = core::cmp::min(4, crate::cdf::mi_width_log2(mi_size));
let x_end = core::cmp::min(mi_cols, mi_col + w4);
let cand_row = mi_row.wrapping_sub(1); let mut x4 = mi_col;
let mut n_count = 0usize;
while n_count < n_limit && x4 < x_end {
let cand_col = x4 | 1;
let cc = cand_col.min(mi_cols.saturating_sub(1));
let cand = cand_row * mi_cols + cc;
let cand_sz = grid.mi_sizes[cand];
let step4 = if cand_sz < crate::cdf::BLOCK_SIZES {
clip4(crate::cdf::num_4x4_blocks_wide(cand_sz))
} else {
2
};
if grid.ref_frames[cand * 2] > INTRA_FRAME_REF0 {
n_count += 1;
let bundle = resolve_obmc_neighbour_bundle(
grid.ref_frames[cand * 2],
[grid.mvs[cand * 4], grid.mvs[cand * 4 + 1]],
ref_frame_idx,
ctx.frame_store,
)?;
above.push(ObmcNeighbour {
bundle,
step4: step4 as u8,
interp_filter_x: grid.interp_filters[cand * 2 + 1],
interp_filter_y: grid.interp_filters[cand * 2],
axis_pos4: x4 as u16,
});
}
x4 += step4;
}
}
let mut left: Vec<ObmcNeighbour<'_>> = Vec::new();
if avail_l {
let h4 = crate::cdf::num_4x4_blocks_high(mi_size);
let n_limit = core::cmp::min(4, crate::cdf::mi_height_log2(mi_size));
let y_end = core::cmp::min(mi_rows, mi_row + h4);
let cand_col = mi_col.wrapping_sub(1); let mut y4 = mi_row;
let mut n_count = 0usize;
while n_count < n_limit && y4 < y_end {
let cand_row = y4 | 1;
let cr = cand_row.min(mi_rows.saturating_sub(1));
let cand = cr * mi_cols + cand_col;
let cand_sz = grid.mi_sizes[cand];
let step4 = if cand_sz < crate::cdf::BLOCK_SIZES {
clip4(crate::cdf::num_4x4_blocks_high(cand_sz))
} else {
2
};
if grid.ref_frames[cand * 2] > INTRA_FRAME_REF0 {
n_count += 1;
let bundle = resolve_obmc_neighbour_bundle(
grid.ref_frames[cand * 2],
[grid.mvs[cand * 4], grid.mvs[cand * 4 + 1]],
ref_frame_idx,
ctx.frame_store,
)?;
left.push(ObmcNeighbour {
bundle,
step4: step4 as u8,
interp_filter_x: grid.interp_filters[cand * 2 + 1],
interp_filter_y: grid.interp_filters[cand * 2],
axis_pos4: y4 as u16,
});
}
y4 += step4;
}
}
let obmc = ObmcParams {
mi_row: mi_row as u32,
mi_col: mi_col as u32,
mi_cols: grid.mi_cols,
mi_rows: grid.mi_rows,
mi_width_log2: crate::cdf::mi_width_log2(mi_size) as u8,
mi_height_log2: crate::cdf::mi_height_log2(mi_size) as u8,
avail_u,
avail_l,
plane_residual_size_ge_block_8x8: above_gate,
above_neighbours: &above,
left_neighbours: &left,
};
let x = ((mi_col >> sub_x) * crate::cdf::MI_SIZE) as i32;
let y = ((mi_row >> sub_y) * crate::cdf::MI_SIZE) as i32;
let w = crate::cdf::block_width(mi_size) >> sub_x;
let h = crate::cdf::block_height(mi_size) >> sub_y;
reconstruct_inter_block_obmc(
block_mode_info,
&obmc,
ref_frame_idx,
ctx.frame_store,
p,
x,
y,
w,
h,
grid.bit_depth,
ctx.subsampling_x,
ctx.subsampling_y,
ctx.frame_width,
ctx.frame_height,
interp_x,
interp_y,
ctx.curr,
ctx.curr_stride,
)?;
}
Ok(())
}
fn resolve_obmc_neighbour_bundle<'a>(
cand_ref_frame: i8,
mv: [i16; 2],
ref_frame_idx: &[u8],
frame_store: &[RefFrameStoreEntry<'a>],
) -> Result<PredictInterRef<'a>, crate::Error> {
let rf = cand_ref_frame as usize;
if !(crate::uncompressed_header_tail::LAST_FRAME
..=crate::uncompressed_header_tail::ALTREF_FRAME)
.contains(&rf)
{
return Err(crate::Error::PartitionWalkOutOfRange);
}
let slot = rf - crate::uncompressed_header_tail::LAST_FRAME;
let ref_idx = *ref_frame_idx
.get(slot)
.ok_or(crate::Error::PartitionWalkOutOfRange)? as usize;
let entry = frame_store
.get(ref_idx)
.ok_or(crate::Error::PartitionWalkOutOfRange)?;
Ok(PredictInterRef {
ref_plane: entry.plane,
ref_stride: entry.stride,
ref_upscaled_width: entry.upscaled_width,
ref_width: entry.width,
ref_height: entry.height,
mv,
})
}
pub fn reconstruct_inter_frame(
grid: &InterModeInfoGrid<'_>,
ref_frame_idx: &[u8],
planes: &mut [PlaneReconContext<'_>],
) -> Result<(), crate::Error> {
let mi_rows = grid.mi_rows as usize;
let mi_cols = grid.mi_cols as usize;
let cells = mi_rows
.checked_mul(mi_cols)
.ok_or(crate::Error::PartitionWalkOutOfRange)?;
if grid.mi_sizes.len() < cells
|| grid.is_inters.len() < cells
|| grid.ref_frames.len() < cells * 2
|| grid.mvs.len() < cells * 4
|| grid.interp_filters.len() < cells * 2
|| grid.compound_types.len() < cells
|| grid.wedge_indices.len() < cells
|| grid.wedge_signs.len() < cells
|| grid.mask_types.len() < cells
|| grid.interintra_modes.len() < cells
|| grid.wedge_interintras.len() < cells
|| grid.interintra_wedge_indices.len() < cells
{
return Err(crate::Error::PartitionWalkOutOfRange);
}
if grid.order_hints_by_ref.len() <= crate::uncompressed_header_tail::ALTREF_FRAME {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if let Some(wc) = grid.warp.as_ref() {
let refs = crate::uncompressed_header_tail::ALTREF_FRAME + 1;
if wc.motion_modes.len() < cells
|| (!wc.local_warp_params.is_empty() && wc.local_warp_params.len() < cells * 6)
|| wc.local_warp_valid.len() < cells
|| wc.y_modes.len() < cells
|| wc.gm_types.len() < refs
|| wc.gm_params.len() < refs * 6
{
return Err(crate::Error::PartitionWalkOutOfRange);
}
}
if let Some(oc) = grid.obmc.as_ref() {
if oc.motion_modes.len() < cells || oc.avail_u.len() < cells || oc.avail_l.len() < cells {
return Err(crate::Error::PartitionWalkOutOfRange);
}
}
let mut consumed = vec![false; cells];
for mi_row in 0..mi_rows {
for mi_col in 0..mi_cols {
let origin = mi_row * mi_cols + mi_col;
if consumed[origin] {
continue;
}
let mi_size = grid.mi_sizes[origin];
if mi_size == crate::cdf::BLOCK_INVALID {
continue;
}
if mi_size >= crate::cdf::BLOCK_SIZES {
return Err(crate::Error::PartitionWalkOutOfRange);
}
let bw4 = crate::cdf::num_4x4_blocks_wide(mi_size);
let bh4 = crate::cdf::num_4x4_blocks_high(mi_size);
for dr in 0..bh4 {
let rr = mi_row + dr;
if rr >= mi_rows {
break;
}
for dc in 0..bw4 {
let cc = mi_col + dc;
if cc >= mi_cols {
break;
}
consumed[rr * mi_cols + cc] = true;
}
}
reconstruct_inter_leaf_at(grid, ref_frame_idx, planes, mi_row, mi_col)?;
}
}
Ok(())
}
pub(crate) fn reconstruct_inter_leaf_at(
grid: &InterModeInfoGrid<'_>,
ref_frame_idx: &[u8],
planes: &mut [PlaneReconContext<'_>],
mi_row: usize,
mi_col: usize,
) -> Result<(), crate::Error> {
let mi_rows = grid.mi_rows as usize;
let mi_cols = grid.mi_cols as usize;
let origin = mi_row * mi_cols + mi_col;
let mi_size = grid.mi_sizes[origin];
if mi_size >= crate::cdf::BLOCK_SIZES {
return Err(crate::Error::PartitionWalkOutOfRange);
}
if grid.is_inters[origin] == 0 {
return Ok(()); }
let ref_frame0 = grid.ref_frames[origin * 2];
let ref_frame1 = grid.ref_frames[origin * 2 + 1];
const NONE_REF_FRAME: i8 = -1;
const INTRA_FRAME_REF: i8 = crate::uncompressed_header_tail::INTRA_FRAME as i8;
let is_compound_leaf = ref_frame1 >= crate::uncompressed_header_tail::LAST_FRAME as i8;
let interp_x = grid.interp_filters[origin * 2 + 1];
let interp_y = grid.interp_filters[origin * 2];
if ref_frame1 == INTRA_FRAME_REF {
let ii_mode = grid.interintra_modes[origin];
let wedge_on = grid.wedge_interintras[origin] != 0;
let leaf = InterIntraLeaf {
mode_info: InterIntraModeInfo {
ref_frame: ref_frame0 as u8,
mv: [grid.mvs[origin * 4], grid.mvs[origin * 4 + 1]],
interintra_mode: ii_mode,
wedge: if wedge_on {
Some(InterIntraWedgeModeInfo {
mi_size,
wedge_index: grid.interintra_wedge_indices[origin],
})
} else {
None
},
},
mi_size,
mi_row: mi_row as u32,
mi_col: mi_col as u32,
interp_filter_x: interp_x,
interp_filter_y: interp_y,
};
let ii_warp: Option<WarpDriverParams> = grid.warp.as_ref().and_then(|wc| {
let y_mode = wc.y_modes.get(origin).copied().unwrap_or(0);
if !matches!(
y_mode,
crate::cdf::MODE_GLOBALMV | crate::cdf::MODE_GLOBAL_GLOBALMV
) {
return None;
}
let t0 = wc.gm_types.get(ref_frame0 as usize).copied().unwrap_or(0);
if (t0 as i32) <= crate::cdf::GM_TYPE_TRANSLATION {
return None;
}
let b = (ref_frame0 as usize) * 6;
let gm0: [i32; 6] = [
wc.gm_params[b],
wc.gm_params[b + 1],
wc.gm_params[b + 2],
wc.gm_params[b + 3],
wc.gm_params[b + 4],
wc.gm_params[b + 5],
];
const WARP_IDENTITY_MATRIX: [i32; 6] = [
0,
0,
1 << WARP_WARPEDMODEL_PREC_BITS,
0,
0,
1 << WARP_WARPEDMODEL_PREC_BITS,
];
Some(WarpDriverParams {
y_mode: [y_mode, y_mode],
gm_type: [t0, t0],
gm_params: [gm0, gm0],
local_warp_params: WARP_IDENTITY_MATRIX,
local_valid: false,
ref_is_scaled: [
wc.is_scaled
.get(ref_frame0 as usize)
.copied()
.unwrap_or(false),
false,
],
force_integer_mv: wc.force_integer_mv,
})
});
reconstruct_inter_intra_block(
&leaf,
ref_frame_idx,
grid.bit_depth,
ii_warp.as_ref(),
planes,
)?;
return Ok(());
}
if is_compound_leaf {
let comp_type = grid.compound_types[origin];
if !matches!(
comp_type,
COMPOUND_AVERAGE | COMPOUND_DISTANCE | COMPOUND_WEDGE | COMPOUND_DIFFWTD
) {
return Ok(());
}
let wedge = if comp_type == COMPOUND_WEDGE {
Some(WedgeModeInfo {
mi_size,
wedge_index: grid.wedge_indices[origin],
wedge_sign: grid.wedge_signs[origin],
})
} else {
None
};
let mode_info = CompoundInterModeInfo {
ref_frame_0: ref_frame0 as u8,
ref_frame_1: ref_frame1 as u8,
mv0: [grid.mvs[origin * 4], grid.mvs[origin * 4 + 1]],
mv1: [grid.mvs[origin * 4 + 2], grid.mvs[origin * 4 + 3]],
compound_type: comp_type,
wedge,
mask_type: grid.mask_types[origin],
};
let mut diffwtd_mask: Option<Vec<u8>> = if comp_type == COMPOUND_DIFFWTD {
Some(vec![
0u8;
crate::cdf::block_width(mi_size)
* crate::cdf::block_height(mi_size)
])
} else {
None
};
let order_hints = CompoundOrderHintContext {
order_hint_bits: grid.order_hint_bits,
current_order_hint: grid.current_order_hint,
order_hint_ref0: grid.order_hints_by_ref[ref_frame0 as usize],
order_hint_ref1: grid.order_hints_by_ref[ref_frame1 as usize],
};
let comp_warp: Option<WarpDriverParams> = grid.warp.as_ref().and_then(|wc| {
let y_mode = wc.y_modes.get(origin).copied().unwrap_or(0);
if !matches!(
y_mode,
crate::cdf::MODE_GLOBALMV | crate::cdf::MODE_GLOBAL_GLOBALMV
) {
return None;
}
let t0 = wc.gm_types.get(ref_frame0 as usize).copied().unwrap_or(0);
let t1 = wc.gm_types.get(ref_frame1 as usize).copied().unwrap_or(0);
if (t0 as i32) <= crate::cdf::GM_TYPE_TRANSLATION
&& (t1 as i32) <= crate::cdf::GM_TYPE_TRANSLATION
{
return None;
}
let gm_of = |rf: usize| -> [i32; 6] {
let b = rf * 6;
[
wc.gm_params[b],
wc.gm_params[b + 1],
wc.gm_params[b + 2],
wc.gm_params[b + 3],
wc.gm_params[b + 4],
wc.gm_params[b + 5],
]
};
const WARP_IDENTITY_MATRIX: [i32; 6] = [
0,
0,
1 << WARP_WARPEDMODEL_PREC_BITS,
0,
0,
1 << WARP_WARPEDMODEL_PREC_BITS,
];
Some(WarpDriverParams {
y_mode: [y_mode, y_mode],
gm_type: [t0, t1],
gm_params: [gm_of(ref_frame0 as usize), gm_of(ref_frame1 as usize)],
local_warp_params: WARP_IDENTITY_MATRIX,
local_valid: false,
ref_is_scaled: [
wc.is_scaled
.get(ref_frame0 as usize)
.copied()
.unwrap_or(false),
wc.is_scaled
.get(ref_frame1 as usize)
.copied()
.unwrap_or(false),
],
force_integer_mv: wc.force_integer_mv,
})
});
for ctx in planes.iter_mut() {
let sub_x = if ctx.plane > 0 { ctx.subsampling_x } else { 0 };
let sub_y = if ctx.plane > 0 { ctx.subsampling_y } else { 0 };
let base_x = ((mi_col >> sub_x) * crate::cdf::MI_SIZE) as i32;
let base_y = ((mi_row >> sub_y) * crate::cdf::MI_SIZE) as i32;
let pred_w = crate::cdf::block_width(mi_size) >> sub_x;
let pred_h = crate::cdf::block_height(mi_size) >> sub_y;
reconstruct_inter_block_compound(
mode_info,
order_hints,
ref_frame_idx,
ctx.frame_store,
ctx.plane,
base_x,
base_y,
pred_w,
pred_h,
grid.bit_depth,
ctx.subsampling_x,
ctx.subsampling_y,
ctx.frame_width,
ctx.frame_height,
interp_x,
interp_y,
diffwtd_mask.as_deref_mut(),
comp_warp.as_ref(),
ctx.curr,
ctx.curr_stride,
)?;
}
return Ok(());
}
debug_assert_eq!(ref_frame1, NONE_REF_FRAME);
let leaf_warp: Option<WarpDriverParams> = grid.warp.as_ref().and_then(|wc| {
let is_warped_causal =
wc.motion_modes.get(origin).copied() == Some(crate::cdf::MOTION_MODE_WARPED_CAUSAL);
let y_is_global = matches!(
wc.y_modes.get(origin).copied(),
Some(crate::cdf::MODE_GLOBALMV) | Some(crate::cdf::MODE_GLOBAL_GLOBALMV)
);
let gm_is_warp = wc
.gm_types
.get(ref_frame0 as usize)
.map(|&t| (t as i32) > crate::cdf::GM_TYPE_TRANSLATION)
.unwrap_or(false);
if !(is_warped_causal || (y_is_global && gm_is_warp)) {
return None;
}
let lw_base = origin * 6;
let lw_at = |k: usize| wc.local_warp_params.get(lw_base + k).copied().unwrap_or(0);
let lwp: [i32; 6] = [lw_at(0), lw_at(1), lw_at(2), lw_at(3), lw_at(4), lw_at(5)];
let rf0 = ref_frame0 as usize;
let gm_base = rf0 * 6;
let gmp: [i32; 6] = [
wc.gm_params[gm_base],
wc.gm_params[gm_base + 1],
wc.gm_params[gm_base + 2],
wc.gm_params[gm_base + 3],
wc.gm_params[gm_base + 4],
wc.gm_params[gm_base + 5],
];
const WARP_IDENTITY_MATRIX: [i32; 6] = [
0,
0,
1 << WARP_WARPEDMODEL_PREC_BITS,
0,
0,
1 << WARP_WARPEDMODEL_PREC_BITS,
];
Some(WarpDriverParams {
y_mode: [wc.y_modes[origin], 0],
gm_type: [wc.gm_types[rf0], 0],
gm_params: [gmp, WARP_IDENTITY_MATRIX],
local_warp_params: lwp,
local_valid: is_warped_causal && wc.local_warp_valid[origin] != 0,
ref_is_scaled: [
wc.is_scaled
.get(ref_frame0 as usize)
.copied()
.unwrap_or(false),
false,
],
force_integer_mv: wc.force_integer_mv,
})
});
if leaf_warp.is_none() {
if let Some(oc) = grid.obmc.as_ref() {
if oc.motion_modes[origin] == crate::cdf::MOTION_MODE_OBMC {
obmc_dispatch_leaf(
grid,
oc,
ref_frame_idx,
planes,
mi_row,
mi_col,
mi_size,
ref_frame0,
)?;
return Ok(());
}
}
}
for ctx in planes.iter_mut() {
let sub_x = if ctx.plane > 0 { ctx.subsampling_x } else { 0 };
let sub_y = if ctx.plane > 0 { ctx.subsampling_y } else { 0 };
let plane_sz = crate::cdf::get_plane_residual_size(mi_size, ctx.plane, sub_x, sub_y)
.ok_or(crate::Error::PartitionWalkOutOfRange)?;
let num4x4_w = crate::cdf::num_4x4_blocks_wide(plane_sz);
let num4x4_h = crate::cdf::num_4x4_blocks_high(plane_sz);
let base_x = ((mi_col >> sub_x) * crate::cdf::MI_SIZE) as i32;
let base_y = ((mi_row >> sub_y) * crate::cdf::MI_SIZE) as i32;
let mut cand_row = (mi_row >> sub_y) << sub_y;
let mut cand_col = (mi_col >> sub_x) << sub_x;
let mut pred_w = crate::cdf::block_width(mi_size) >> sub_x;
let mut pred_h = crate::cdf::block_height(mi_size) >> sub_y;
const INTRA_FRAME_REF0: i8 = crate::uncompressed_header_tail::INTRA_FRAME as i8;
let mut some_use_intra = false;
'scan: for r in 0..(num4x4_h << sub_y) {
let rr = cand_row + r;
if rr >= mi_rows {
break;
}
for c in 0..(num4x4_w << sub_x) {
let cc = cand_col + c;
if cc >= mi_cols {
break;
}
if grid.ref_frames[(rr * mi_cols + cc) * 2] == INTRA_FRAME_REF0 {
some_use_intra = true;
break 'scan;
}
}
}
if some_use_intra {
pred_w = num4x4_w * 4;
pred_h = num4x4_h * 4;
cand_row = mi_row;
cand_col = mi_col;
}
let region_w = num4x4_w * 4;
let region_h = num4x4_h * 4;
let mut r_idx = 0usize;
let mut y = 0usize;
while y < region_h {
let mut c_idx = 0usize;
let mut x = 0usize;
while x < region_w {
let cr = cand_row + r_idx;
let cc = cand_col + c_idx;
let cr = cr.min(mi_rows.saturating_sub(1));
let cc = cc.min(mi_cols.saturating_sub(1));
let cand = cr * mi_cols + cc;
let mode_info = InterModeInfo {
ref_frame: grid.ref_frames[cand * 2] as u8,
mv: [grid.mvs[cand * 4], grid.mvs[cand * 4 + 1]],
};
let cand_fx = grid.interp_filters[cand * 2 + 1];
let cand_fy = grid.interp_filters[cand * 2];
match leaf_warp.as_ref() {
Some(warp) => {
reconstruct_inter_block_warp(
mode_info,
warp,
ref_frame_idx,
ctx.frame_store,
ctx.plane,
base_x + x as i32,
base_y + y as i32,
pred_w,
pred_h,
grid.bit_depth,
ctx.subsampling_x,
ctx.subsampling_y,
ctx.frame_width,
ctx.frame_height,
cand_fx,
cand_fy,
ctx.curr,
ctx.curr_stride,
)?;
}
None => {
reconstruct_inter_block(
mode_info,
ref_frame_idx,
ctx.frame_store,
ctx.plane,
base_x + x as i32,
base_y + y as i32,
pred_w,
pred_h,
grid.bit_depth,
ctx.subsampling_x,
ctx.subsampling_y,
ctx.frame_width,
ctx.frame_height,
cand_fx,
cand_fy,
ctx.curr,
ctx.curr_stride,
)?;
}
}
c_idx += 1;
x += pred_w;
}
r_idx += 1;
y += pred_h;
}
}
Ok(())
}
#[derive(Debug, Clone, Copy)]
pub struct MotionFieldSlot<'a> {
pub mf_mvs: &'a [i16],
pub mf_ref_frames: &'a [i8],
pub saved_order_hints: [i32; 8],
pub mi_rows: u32,
pub mi_cols: u32,
pub frame_is_intra: bool,
}
#[must_use]
pub fn motion_field_estimation_core(
slots: &[Option<MotionFieldSlot<'_>>; 8],
ref_frame_idx: &[u8; 7],
order_hints: &[i32; 8],
order_hint: i32,
hint_bits: u32,
mi_rows: u32,
mi_cols: u32,
) -> crate::cdf::MotionFieldMvs {
use crate::cdf::MotionFieldMvs;
const MFMV_STACK_SIZE: i32 = 3;
const MAX_FRAME_DISTANCE: i32 = 31;
const MAX_OFFSET_WIDTH: i32 = 8;
const MAX_OFFSET_HEIGHT: i32 = 0;
const DIV_MULT: [i32; 32] = [
0, 16384, 8192, 5461, 4096, 3276, 2730, 2340, 2048, 1820, 1638, 1489, 1365, 1260, 1170,
1092, 1024, 963, 910, 862, 819, 780, 744, 712, 682, 655, 630, 606, 585, 564, 546, 528,
];
const LAST_FRAME: usize = 1;
const LAST2_FRAME: usize = 2;
const GOLDEN_FRAME: usize = 4;
const BWDREF_FRAME: usize = 5;
const ALTREF2_FRAME: usize = 6;
const ALTREF_FRAME: usize = 7;
let mut mfmvs = MotionFieldMvs::new_invalid(mi_rows, mi_cols);
let w8 = (mi_cols >> 1) as i32;
let h8 = (mi_rows >> 1) as i32;
let project_ref = |src: usize, dst_sign: i32, mfmvs: &mut MotionFieldMvs| -> bool {
let src_idx = ref_frame_idx[src - LAST_FRAME] as usize;
let Some(slot) = slots[src_idx].as_ref() else {
return false;
};
if slot.mi_rows != mi_rows || slot.mi_cols != mi_cols || slot.frame_is_intra {
return false;
}
for y8 in 0..h8 {
for x8 in 0..w8 {
let row = (2 * y8 + 1) as usize;
let col = (2 * x8 + 1) as usize;
let cell = row * (mi_cols as usize) + col;
let src_ref = slot.mf_ref_frames[cell];
if src_ref <= 0 {
continue;
}
let ref_to_cur = get_relative_dist(order_hints[src], order_hint, hint_bits);
let ref_offset = get_relative_dist(
order_hints[src],
slot.saved_order_hints[src_ref as usize],
hint_bits,
);
let pos_valid = ref_to_cur.abs() <= MAX_FRAME_DISTANCE
&& ref_offset.abs() <= MAX_FRAME_DISTANCE
&& ref_offset > 0;
if !pos_valid {
continue;
}
let mv = [
i32::from(slot.mf_mvs[cell * 2]),
i32::from(slot.mf_mvs[cell * 2 + 1]),
];
let mv_projection = |mv: [i32; 2], numerator: i32, denominator: i32| -> [i32; 2] {
let clipped_den = denominator.min(MAX_FRAME_DISTANCE);
let clipped_num = numerator.clamp(-MAX_FRAME_DISTANCE, MAX_FRAME_DISTANCE);
let mut out = [0i32; 2];
for i in 0..2 {
let v = mv[i] * clipped_num * DIV_MULT[clipped_den as usize];
let scaled = if v >= 0 {
(v + (1 << 13)) >> 14
} else {
-((-v + (1 << 13)) >> 14)
};
out[i] = scaled.clamp(-(1 << 14) + 1, (1 << 14) - 1);
}
out
};
let proj_mv = mv_projection(mv, ref_to_cur * dst_sign, ref_offset);
let project = |v8: i32, delta: i32, max8: i32, max_off8: i32| -> (i32, bool) {
let base8 = (v8 >> 3) << 3;
let offset8 = if delta >= 0 {
delta >> (3 + 1 + 2)
} else {
-((-delta) >> (3 + 1 + 2))
};
let v8 = v8 + dst_sign * offset8;
let valid = !(v8 < 0
|| v8 >= max8
|| v8 < base8 - max_off8
|| v8 >= base8 + 8 + max_off8);
(v8, valid)
};
let (pos_y8, vy) = project(y8, proj_mv[0], h8, MAX_OFFSET_HEIGHT);
let (pos_x8, vx) = project(x8, proj_mv[1], w8, MAX_OFFSET_WIDTH);
if !(vy && vx) {
continue;
}
for (dst, &dst_hint) in order_hints
.iter()
.enumerate()
.take(ALTREF_FRAME + 1)
.skip(LAST_FRAME)
{
let ref_to_dst = get_relative_dist(order_hint, dst_hint, hint_bits);
let out = mv_projection(mv, ref_to_dst, ref_offset);
mfmvs.set(
dst,
pos_y8 as u32,
pos_x8 as u32,
[out[0] as i16, out[1] as i16],
);
}
}
}
true
};
let last_idx = ref_frame_idx[0] as usize;
let cur_gold_order_hint = order_hints[GOLDEN_FRAME];
let last_alt_order_hint = slots[last_idx]
.as_ref()
.map_or(0, |s| s.saved_order_hints[ALTREF_FRAME]);
let use_last = last_alt_order_hint != cur_gold_order_hint;
if use_last {
project_ref(LAST_FRAME, -1, &mut mfmvs);
}
let mut ref_stamp = MFMV_STACK_SIZE - 2;
let use_bwd = get_relative_dist(order_hints[BWDREF_FRAME], order_hint, hint_bits) > 0;
if use_bwd && project_ref(BWDREF_FRAME, 1, &mut mfmvs) {
ref_stamp -= 1;
}
let use_alt2 = get_relative_dist(order_hints[ALTREF2_FRAME], order_hint, hint_bits) > 0;
if use_alt2 && project_ref(ALTREF2_FRAME, 1, &mut mfmvs) {
ref_stamp -= 1;
}
let use_alt = get_relative_dist(order_hints[ALTREF_FRAME], order_hint, hint_bits) > 0;
if use_alt && ref_stamp >= 0 && project_ref(ALTREF_FRAME, 1, &mut mfmvs) {
ref_stamp -= 1;
}
if ref_stamp >= 0 {
project_ref(LAST2_FRAME, -1, &mut mfmvs);
}
mfmvs
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rounding_variables_matches_spec_table() {
let cases: &[(u8, bool, u32, u32, u32)] = &[
(8, false, 3, 11, 0),
(8, true, 3, 7, 4),
(10, false, 3, 11, 0),
(10, true, 3, 7, 4),
(12, false, 5, 9, 0),
(12, true, 5, 7, 2),
];
for &(bd, ic, r0, r1, pr) in cases {
let got = rounding_variables(bd, ic).unwrap();
assert_eq!(
(got.inter_round0, got.inter_round1, got.inter_post_round),
(r0, r1, pr),
"BD={bd} compound={ic}",
);
}
}
#[test]
fn rounding_variables_rejects_invalid_bit_depth() {
assert!(rounding_variables(7, false).is_err());
assert!(rounding_variables(9, false).is_err());
assert!(rounding_variables(16, false).is_err());
}
#[test]
fn motion_vector_scaling_identity_yields_unit_scale() {
let s = motion_vector_scaling(
0,
0,
0,
640,
360,
640,
360,
16,
8,
[0, 0],
)
.unwrap();
assert_eq!(s.step_x, 1024);
assert_eq!(s.step_y, 1024);
assert_eq!(s.start_x, (16 << 10) + 32);
assert_eq!(s.start_y, (8 << 10) + 32);
}
#[test]
fn motion_vector_scaling_integer_mv_shifts_origin() {
let base = motion_vector_scaling(0, 0, 0, 640, 360, 640, 360, 0, 0, [0, 0]).unwrap();
let shifted = motion_vector_scaling(0, 0, 0, 640, 360, 640, 360, 0, 0, [8, 0]).unwrap();
assert_eq!(shifted.start_y - base.start_y, 1 << SCALE_SUBPEL_BITS);
assert_eq!(shifted.start_x, base.start_x);
}
#[test]
fn motion_vector_scaling_rejects_invalid_inputs() {
assert!(motion_vector_scaling(3, 0, 0, 8, 8, 8, 8, 0, 0, [0, 0]).is_err());
assert!(motion_vector_scaling(0, 2, 0, 8, 8, 8, 8, 0, 0, [0, 0]).is_err());
assert!(motion_vector_scaling(0, 0, 2, 8, 8, 8, 8, 0, 0, [0, 0]).is_err());
assert!(motion_vector_scaling(0, 0, 0, 0, 8, 8, 8, 0, 0, [0, 0]).is_err());
assert!(motion_vector_scaling(0, 0, 0, 8, 0, 8, 8, 0, 0, [0, 0]).is_err());
assert!(motion_vector_scaling(0, 0, 0, 8, 8, 0, 8, 0, 0, [0, 0]).is_err());
assert!(motion_vector_scaling(0, 0, 0, 8, 8, 8, 0, 0, 0, [0, 0]).is_err());
}
#[test]
fn subpel_filters_all_even() {
for (f, phases) in SUBPEL_FILTERS.iter().enumerate() {
for (p, row) in phases.iter().enumerate() {
for (t, &v) in row.iter().enumerate() {
assert_eq!(v & 1, 0, "filter {f} phase {p} tap {t} = {v} (odd)");
}
}
}
}
#[test]
fn subpel_filters_phase_zero_is_unit_copy() {
let unit = [0, 0, 0, 128, 0, 0, 0, 0];
for (f, phases) in SUBPEL_FILTERS.iter().enumerate() {
assert_eq!(phases[0], unit, "filter {f} phase 0 not unit");
}
}
#[test]
fn subpel_filters_taps_sum_to_filter_bits_unity() {
for (f, phases) in SUBPEL_FILTERS.iter().enumerate() {
for (p, row) in phases.iter().enumerate() {
let sum: i32 = row.iter().sum();
assert_eq!(sum, 128, "filter {f} phase {p} taps sum = {sum} != 128");
}
}
}
#[test]
fn small_block_filters_have_4tap_structure() {
for f in [EIGHTTAP_4TAP as usize, EIGHTTAP_SMOOTH_4TAP as usize] {
for (p, row) in SUBPEL_FILTERS[f].iter().enumerate() {
for &t in &[0usize, 1, 6, 7] {
assert_eq!(
row[t], 0,
"filter {f} phase {p} tap {t} = {} (must be 0)",
row[t],
);
}
}
}
}
#[test]
fn select_interp_filter_small_block_remap() {
assert_eq!(select_interp_filter_small_block(EIGHTTAP), EIGHTTAP_4TAP);
assert_eq!(
select_interp_filter_small_block(EIGHTTAP_SHARP),
EIGHTTAP_4TAP,
);
assert_eq!(
select_interp_filter_small_block(EIGHTTAP_SMOOTH),
EIGHTTAP_SMOOTH_4TAP,
);
assert_eq!(select_interp_filter_small_block(BILINEAR), BILINEAR);
assert_eq!(
select_interp_filter_small_block(EIGHTTAP_4TAP),
EIGHTTAP_4TAP,
);
}
#[test]
fn block_inter_prediction_zero_mv_copies_reference() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = (r * 16 + c) as u16;
}
}
let s = motion_vector_scaling(
0,
0,
0,
ref_w as u32,
ref_h as u32,
ref_w as u32,
ref_h as u32,
2,
2,
[0, 0],
)
.unwrap();
let rv = rounding_variables(8, false).unwrap();
let w = 4;
let h = 4;
let mut pred = vec![0i32; h * w];
block_inter_prediction(
0,
0,
0,
&refp,
stride,
ref_w as u32,
ref_h as u32,
s.start_x,
s.start_y,
s.step_x,
s.step_y,
w,
h,
EIGHTTAP,
EIGHTTAP,
rv.inter_round0,
rv.inter_round1,
&mut pred,
)
.unwrap();
let _ = pred;
let mut pred2 = vec![0i32; h * w];
block_inter_prediction(
0,
0,
0,
&refp,
stride,
ref_w as u32,
ref_h as u32,
2 << 10,
2 << 10,
1 << 10,
1 << 10,
w,
h,
EIGHTTAP,
EIGHTTAP,
rv.inter_round0,
rv.inter_round1,
&mut pred2,
)
.unwrap();
for r in 0..h {
for c in 0..w {
let expected = refp[(2 + r) * stride + (2 + c)] as i32;
assert_eq!(
pred2[r * w + c],
expected,
"pred2[{r}][{c}] = {} expected {}",
pred2[r * w + c],
expected,
);
}
}
}
#[test]
fn block_inter_prediction_clamps_at_negative_start() {
let ref_w: usize = 8;
let ref_h: usize = 8;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = 42; }
}
let rv = rounding_variables(8, false).unwrap();
let w = 4;
let h = 4;
let mut pred = vec![0i32; h * w];
block_inter_prediction(
0,
0,
0,
&refp,
stride,
ref_w as u32,
ref_h as u32,
-4i32 << SCALE_SUBPEL_BITS,
0,
1 << SCALE_SUBPEL_BITS,
1 << SCALE_SUBPEL_BITS,
w,
h,
EIGHTTAP,
EIGHTTAP,
rv.inter_round0,
rv.inter_round1,
&mut pred,
)
.unwrap();
for r in 0..h {
for c in 0..w {
assert_eq!(pred[r * w + c], 42);
}
}
}
#[test]
fn block_inter_prediction_rejects_invalid_inputs() {
let refp = vec![0u16; 64];
let mut pred = vec![0i32; 16];
assert!(block_inter_prediction(
3, 0, 0, &refp, 8, 8, 8, 0, 0, 1024, 1024, 4, 4, 0, 0, 3, 11, &mut pred
)
.is_err());
assert!(block_inter_prediction(
0, 2, 0, &refp, 8, 8, 8, 0, 0, 1024, 1024, 4, 4, 0, 0, 3, 11, &mut pred
)
.is_err());
assert!(block_inter_prediction(
0, 0, 0, &refp, 8, 0, 8, 0, 0, 1024, 1024, 4, 4, 0, 0, 3, 11, &mut pred
)
.is_err());
assert!(block_inter_prediction(
0, 0, 0, &refp, 8, 8, 8, 0, 0, 0, 1024, 4, 4, 0, 0, 3, 11, &mut pred
)
.is_err());
assert!(block_inter_prediction(
0, 0, 0, &refp, 8, 8, 8, 0, 0, 1024, 1024, 4, 4, 6, 0, 3, 11, &mut pred
)
.is_err());
let mut tiny = vec![0i32; 8];
assert!(block_inter_prediction(
0, 0, 0, &refp, 8, 8, 8, 0, 0, 1024, 1024, 4, 4, 0, 0, 3, 11, &mut tiny
)
.is_err());
}
#[test]
fn clip1_single_ref_clamps_to_bit_depth() {
let pred = [-3i32, 0, 255, 256, 1023, 4096, -1];
let mut out8 = [0u16; 7];
clip1_single_ref(8, &pred, &mut out8).unwrap();
assert_eq!(out8, [0, 0, 255, 255, 255, 255, 0]);
let mut out10 = [0u16; 7];
clip1_single_ref(10, &pred, &mut out10).unwrap();
assert_eq!(out10, [0, 0, 255, 256, 1023, 1023, 0]);
let mut out12 = [0u16; 7];
clip1_single_ref(12, &pred, &mut out12).unwrap();
assert_eq!(out12, [0, 0, 255, 256, 1023, 4095, 0]);
let mut out = [0u16; 7];
assert!(clip1_single_ref(9, &pred, &mut out).is_err());
}
#[test]
fn r191_wedge_master_1d_values_within_0_64() {
for &v in WEDGE_MASTER_OBLIQUE_ODD.iter() {
assert!(v <= 64, "odd entry {} > 64", v);
}
for &v in WEDGE_MASTER_OBLIQUE_EVEN.iter() {
assert!(v <= 64, "even entry {} > 64", v);
}
for &v in WEDGE_MASTER_VERTICAL.iter() {
assert!(v <= 64, "vertical entry {} > 64", v);
}
assert_eq!(WEDGE_MASTER_OBLIQUE_ODD[0], 0);
assert_eq!(WEDGE_MASTER_OBLIQUE_ODD[63], 64);
assert_eq!(WEDGE_MASTER_OBLIQUE_EVEN[0], 0);
assert_eq!(WEDGE_MASTER_OBLIQUE_EVEN[63], 64);
assert_eq!(WEDGE_MASTER_VERTICAL[0], 0);
assert_eq!(WEDGE_MASTER_VERTICAL[63], 64);
}
#[test]
fn r191_master_mask_table_values_within_0_64() {
let table = master_mask_table();
for (idx, &v) in table.iter().enumerate() {
assert!(v <= 64, "entry {idx} = {v} > 64");
}
}
#[test]
fn r191_master_mask_horizontal_is_vertical_transpose() {
let table = master_mask_table();
for i in 0..MASK_MASTER_SIZE {
for j in 0..MASK_MASTER_SIZE {
let h = table[idx3(WEDGE_HORIZONTAL as usize, j, i)];
let v = table[idx3(WEDGE_VERTICAL as usize, i, j)];
assert_eq!(h, v, "HORIZONTAL[{j}][{i}] != VERTICAL[{i}][{j}]");
}
}
}
#[test]
fn r191_master_mask_oblique27_is_oblique63_transpose() {
let table = master_mask_table();
for i in 0..MASK_MASTER_SIZE {
for j in 0..MASK_MASTER_SIZE {
let m27 = table[idx3(WEDGE_OBLIQUE27 as usize, j, i)];
let m63 = table[idx3(WEDGE_OBLIQUE63 as usize, i, j)];
assert_eq!(m27, m63, "OBLIQUE27[{j}][{i}] != OBLIQUE63[{i}][{j}]");
}
}
}
#[test]
fn r191_block_shape_truth_table() {
assert_eq!(block_shape(1, 2), 0);
assert_eq!(block_shape(2, 4), 0);
assert_eq!(block_shape(2, 1), 1);
assert_eq!(block_shape(4, 2), 1);
assert_eq!(block_shape(2, 2), 2);
assert_eq!(block_shape(4, 4), 2);
}
#[test]
fn r191_wedge_mask_block_8x8_values_within_0_64() {
const BLOCK_8X8: usize = 3;
const NUM_4X4: u32 = 2; let mut mask = vec![0u8; 8 * 8];
for wedge_index in 0..16u8 {
for wedge_sign in 0..2u8 {
wedge_mask(
BLOCK_8X8,
NUM_4X4,
NUM_4X4,
wedge_index,
wedge_sign,
&mut mask,
)
.unwrap();
for (idx, &m) in mask.iter().enumerate() {
assert!(
m <= 64,
"wedge_index={wedge_index} wedge_sign={wedge_sign} mask[{idx}] = {m} > 64"
);
}
}
}
}
#[test]
fn r191_wedge_mask_sign_flip_inverts() {
const BLOCK_16X16: usize = 6;
const NUM_4X4: u32 = 4; let mut m0 = vec![0u8; 16 * 16];
let mut m1 = vec![0u8; 16 * 16];
wedge_mask(BLOCK_16X16, NUM_4X4, NUM_4X4, 5, 0, &mut m0).unwrap();
wedge_mask(BLOCK_16X16, NUM_4X4, NUM_4X4, 5, 1, &mut m1).unwrap();
for i in 0..(16 * 16) {
assert_eq!(
m0[i] + m1[i],
64,
"pixel {i}: m0={} m1={} sum != 64",
m0[i],
m1[i],
);
}
}
#[test]
fn r191_wedge_mask_rejects_invalid_inputs() {
let mut mask = vec![0u8; 64];
assert!(wedge_mask(22, 2, 2, 0, 0, &mut mask).is_err());
assert!(wedge_mask(3, 2, 2, 16, 0, &mut mask).is_err());
assert!(wedge_mask(3, 2, 2, 0, 2, &mut mask).is_err());
assert!(wedge_mask(0, 1, 1, 0, 0, &mut mask).is_err());
assert!(wedge_mask(3, 0, 2, 0, 0, &mut mask).is_err());
let mut tiny = vec![0u8; 32];
assert!(wedge_mask(3, 2, 2, 0, 0, &mut tiny).is_err());
}
#[test]
fn r191_difference_weight_mask_equal_preds_yields_38() {
let preds = vec![100i32; 16];
let mut mask = vec![0u8; 16];
difference_weight_mask(8, 4, 0, &preds, &preds, 4, 4, &mut mask).unwrap();
for &m in mask.iter() {
assert_eq!(m, 38);
}
difference_weight_mask(8, 4, 1, &preds, &preds, 4, 4, &mut mask).unwrap();
for &m in mask.iter() {
assert_eq!(m, 64 - 38);
}
}
#[test]
fn r191_difference_weight_mask_saturates_at_64() {
let preds0 = vec![10000i32; 4];
let preds1 = vec![0i32; 4];
let mut mask = vec![0u8; 4];
difference_weight_mask(8, 4, 0, &preds0, &preds1, 2, 2, &mut mask).unwrap();
for &m in mask.iter() {
assert_eq!(m, 64);
}
difference_weight_mask(8, 4, 1, &preds0, &preds1, 2, 2, &mut mask).unwrap();
for &m in mask.iter() {
assert_eq!(m, 0);
}
}
#[test]
fn r191_difference_weight_mask_rejects_invalid_inputs() {
let preds = vec![0i32; 16];
let mut mask = vec![0u8; 16];
assert!(difference_weight_mask(7, 4, 0, &preds, &preds, 4, 4, &mut mask).is_err());
assert!(difference_weight_mask(8, 4, 2, &preds, &preds, 4, 4, &mut mask).is_err());
assert!(difference_weight_mask(8, 4, 0, &preds, &preds, 0, 4, &mut mask).is_err());
let mut tiny = vec![0u8; 8];
assert!(difference_weight_mask(8, 4, 0, &preds, &preds, 4, 4, &mut tiny).is_err());
let small = vec![0i32; 4];
assert!(difference_weight_mask(8, 4, 0, &small, &preds, 4, 4, &mut mask).is_err());
}
#[test]
fn r191_intra_mode_variant_mask_dc_yields_32() {
let mut mask = vec![0u8; 64];
intra_mode_variant_mask(II_DC_PRED, 8, 8, &mut mask).unwrap();
for &m in mask.iter() {
assert_eq!(m, 32);
}
}
#[test]
fn r191_intra_mode_variant_mask_v_pred_row_uniform() {
let mut mask = vec![0u8; 8 * 8];
intra_mode_variant_mask(II_V_PRED, 8, 8, &mut mask).unwrap();
for i in 0..8 {
let row0 = mask[i * 8];
for j in 0..8 {
assert_eq!(mask[i * 8 + j], row0, "row {i} col {j} differs");
}
}
for i in 1..8 {
assert!(mask[i * 8] <= mask[(i - 1) * 8]);
}
}
#[test]
fn r191_intra_mode_variant_mask_h_pred_col_uniform() {
let mut mask = vec![0u8; 8 * 8];
intra_mode_variant_mask(II_H_PRED, 8, 8, &mut mask).unwrap();
for j in 0..8 {
let col0 = mask[j];
for i in 0..8 {
assert_eq!(mask[i * 8 + j], col0, "col {j} row {i} differs");
}
}
}
#[test]
fn r191_intra_mode_variant_mask_smooth_pred_diagonal_symmetric() {
let mut mask = vec![0u8; 16 * 16];
intra_mode_variant_mask(II_SMOOTH_PRED, 16, 16, &mut mask).unwrap();
for i in 0..16 {
for j in 0..16 {
assert_eq!(
mask[i * 16 + j],
mask[j * 16 + i],
"mask[{i}][{j}] != mask[{j}][{i}]"
);
}
}
}
#[test]
fn r191_ii_weights_1d_monotone_non_increasing() {
for i in 1..MAX_SB_SIZE {
assert!(
II_WEIGHTS_1D[i] <= II_WEIGHTS_1D[i - 1],
"Ii_Weights_1d[{}] = {} > [{}] = {}",
i,
II_WEIGHTS_1D[i],
i - 1,
II_WEIGHTS_1D[i - 1],
);
}
assert_eq!(II_WEIGHTS_1D[0], 60);
assert_eq!(II_WEIGHTS_1D[127], 1);
}
#[test]
fn r191_intra_mode_variant_mask_rejects_invalid_inputs() {
let mut mask = vec![0u8; 64];
assert!(intra_mode_variant_mask(4, 8, 8, &mut mask).is_err());
assert!(intra_mode_variant_mask(II_V_PRED, 0, 8, &mut mask).is_err());
assert!(intra_mode_variant_mask(II_V_PRED, 8, 256, &mut mask).is_err());
let mut tiny = vec![0u8; 32];
assert!(intra_mode_variant_mask(II_V_PRED, 8, 8, &mut tiny).is_err());
}
#[test]
fn r191_mask_blend_full_mask_yields_pred0() {
let rv = rounding_variables(8, true).unwrap();
let preds0 = vec![100i32 << (rv.inter_post_round); 16];
let preds1 = vec![200i32 << (rv.inter_post_round); 16];
let mask = vec![64u8; 16];
let mut out = vec![0u16; 16];
mask_blend(
8,
rv.inter_post_round,
0,
0,
&preds0,
&preds1,
4,
4,
&mask,
0,
&mut out,
)
.unwrap();
for &v in out.iter() {
assert_eq!(v, 100);
}
let mask0 = vec![0u8; 16];
mask_blend(
8,
rv.inter_post_round,
0,
0,
&preds0,
&preds1,
4,
4,
&mask0,
0,
&mut out,
)
.unwrap();
for &v in out.iter() {
assert_eq!(v, 200);
}
}
#[test]
fn r191_mask_blend_chroma_subsample_4x_average() {
let rv = rounding_variables(8, true).unwrap();
let preds0 = vec![100i32 << rv.inter_post_round; 4];
let preds1 = vec![200i32 << rv.inter_post_round; 4];
let mask = vec![32u8; 16];
let mut out = vec![0u16; 4];
mask_blend(
8,
rv.inter_post_round,
1,
1,
&preds0,
&preds1,
2,
2,
&mask,
0,
&mut out,
)
.unwrap();
for &v in out.iter() {
assert_eq!(v, 150);
}
}
#[test]
fn r191_mask_blend_interintra_endpoints() {
let rv = rounding_variables(8, false).unwrap();
assert_eq!(rv.inter_post_round, 0);
let preds0 = vec![100i32; 16];
let mask_full = vec![64u8; 16];
let mut dst_full = vec![50u16; 16];
mask_blend_interintra(
8,
rv.inter_post_round,
0,
0,
&preds0,
4,
4,
&mask_full,
0,
&mut dst_full,
)
.unwrap();
for &v in dst_full.iter() {
assert_eq!(v, 50);
}
let mask_zero = vec![0u8; 16];
let mut dst_zero = vec![50u16; 16];
mask_blend_interintra(
8,
rv.inter_post_round,
0,
0,
&preds0,
4,
4,
&mask_zero,
0,
&mut dst_zero,
)
.unwrap();
for &v in dst_zero.iter() {
assert_eq!(v, 100);
}
}
#[test]
fn r191_mask_blend_rejects_invalid_inputs() {
let preds = vec![0i32; 16];
let mask = vec![0u8; 16];
let mut out = vec![0u16; 16];
assert!(mask_blend(7, 0, 0, 0, &preds, &preds, 4, 4, &mask, 0, &mut out).is_err());
assert!(mask_blend(8, 0, 2, 0, &preds, &preds, 4, 4, &mask, 0, &mut out).is_err());
assert!(mask_blend(8, 0, 0, 0, &preds, &preds, 0, 4, &mask, 0, &mut out).is_err());
let small_mask = vec![0u8; 16];
let preds_c = vec![0i32; 4];
let mut out_c = vec![0u16; 4];
assert!(mask_blend(
8,
0,
1,
1,
&preds_c,
&preds_c,
2,
2,
&small_mask,
0,
&mut out_c
)
.is_ok()); let too_small = vec![0u8; 15];
assert!(
mask_blend(8, 0, 1, 1, &preds_c, &preds_c, 2, 2, &too_small, 0, &mut out_c).is_err()
);
}
#[test]
fn r297_predict_inter_interintra_matches_standalone_composition() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = ((r * 13 + c * 7) & 0xFF) as u16;
}
}
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let w = 8;
let h = 8;
let bit_depth = 8u8;
let intra_seed: Vec<u16> = (0..w * h).map(|k| ((k * 3) & 0xFF) as u16).collect();
let ii_mode = II_SMOOTH_PRED;
let mut driver_out = intra_seed.clone();
predict_inter(
0,
4,
4,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
true,
bit_depth,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
Some(InterIntraParams {
interintra_mode: ii_mode,
wedge: None,
}),
None,
None,
&mut driver_out,
)
.expect("predict_inter interintra arm");
let rv = rounding_variables(bit_depth, false).unwrap();
let pred0 = predict_inter_one_ref(
&refs[0],
0,
0,
4,
4,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
rv.inter_round0,
rv.inter_round1,
None,
false,
)
.unwrap();
let mut mask = vec![0u8; w * h];
intra_mode_variant_mask(ii_mode, w, h, &mut mask).unwrap();
let mut standalone = intra_seed.clone();
mask_blend_interintra(
bit_depth,
rv.inter_post_round,
0,
0,
&pred0,
w,
h,
&mask,
0,
&mut standalone,
)
.unwrap();
assert_eq!(driver_out, standalone);
assert_ne!(driver_out, intra_seed);
}
#[test]
fn r297_predict_inter_interintra_caller_bug_rejections() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let refp = vec![7u16; ref_h * ref_w];
let one = PredictInterRef {
ref_plane: &refp,
ref_stride: ref_w,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
};
let refs1 = [one];
let refs2 = [
PredictInterRef {
ref_plane: &refp,
ref_stride: ref_w,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
},
PredictInterRef {
ref_plane: &refp,
ref_stride: ref_w,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
},
];
let w = 8;
let h = 8;
let call = |is_compound: bool,
is_ii: bool,
refs: &[PredictInterRef<'_>],
compound: Option<CompoundParams<'_>>,
ii: Option<InterIntraParams<'_>>| {
let mut out = vec![0u16; w * h];
predict_inter(
0,
2,
2,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
is_compound,
is_ii,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
refs,
compound,
ii,
None,
None,
&mut out,
)
};
assert!(call(false, true, &refs1, None, None).is_err());
assert!(call(
false,
true,
&refs1,
None,
Some(InterIntraParams {
interintra_mode: 4,
wedge: None,
})
)
.is_err());
assert!(call(
true,
true,
&refs2,
Some(CompoundParams::Average),
Some(InterIntraParams {
interintra_mode: II_DC_PRED,
wedge: None,
})
)
.is_err());
assert!(call(
false,
false,
&refs1,
None,
Some(InterIntraParams {
interintra_mode: II_DC_PRED,
wedge: None,
})
)
.is_err());
assert!(call(
false,
true,
&refs1,
None,
Some(InterIntraParams {
interintra_mode: II_DC_PRED,
wedge: None,
})
)
.is_ok());
}
#[test]
fn r298_predict_inter_wedge_interintra_luma_matches_standalone() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = ((r * 11 + c * 5) & 0xFF) as u16;
}
}
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let w = 8;
let h = 8;
let bit_depth = 8u8;
let intra_seed: Vec<u16> = (0..w * h).map(|k| ((k * 3) & 0xFF) as u16).collect();
let mut wmask = vec![0u8; w * h];
wedge_mask(3, 2, 2, 5, 0, &mut wmask).unwrap();
let ii_mode = II_DC_PRED;
let mut driver_out = intra_seed.clone();
predict_inter(
0,
4,
4,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
true,
bit_depth,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
Some(InterIntraParams {
interintra_mode: ii_mode,
wedge: Some(WedgeInterIntraInfo {
mask: &wmask,
mask_stride: 0,
}),
}),
None,
None,
&mut driver_out,
)
.expect("predict_inter wedge interintra arm");
let rv = rounding_variables(bit_depth, false).unwrap();
let pred0 = predict_inter_one_ref(
&refs[0],
0,
0,
4,
4,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
rv.inter_round0,
rv.inter_round1,
None,
false,
)
.unwrap();
let mut standalone = intra_seed.clone();
mask_blend_interintra(
bit_depth,
rv.inter_post_round,
0,
0,
&pred0,
w,
h,
&wmask,
0,
&mut standalone,
)
.unwrap();
assert_eq!(driver_out, standalone);
assert_ne!(driver_out, intra_seed);
let mut nonwedge = intra_seed.clone();
predict_inter(
0,
4,
4,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
true,
bit_depth,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
Some(InterIntraParams {
interintra_mode: ii_mode,
wedge: None,
}),
None,
None,
&mut nonwedge,
)
.unwrap();
assert_ne!(
driver_out, nonwedge,
"wedge mask must shape the blend differently from the §7.11.3.13 mask"
);
}
#[test]
fn r298_predict_inter_wedge_interintra_chroma_downsamples_mask() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = ((r * 9 + c * 17) & 0xFF) as u16;
}
}
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let cw = 4;
let ch = 4;
let luma_w = 8;
let luma_h = 8;
let bit_depth = 8u8;
let intra_seed: Vec<u16> = (0..cw * ch).map(|k| ((k * 7 + 11) & 0xFF) as u16).collect();
let mut wmask = vec![0u8; luma_w * luma_h];
wedge_mask(3, 2, 2, 5, 0, &mut wmask).unwrap();
let mut driver_out = intra_seed.clone();
predict_inter(
1,
0,
0,
cw,
ch,
crate::cdf::MOTION_MODE_SIMPLE,
false,
true,
bit_depth,
1,
1,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
Some(InterIntraParams {
interintra_mode: II_DC_PRED,
wedge: Some(WedgeInterIntraInfo {
mask: &wmask,
mask_stride: 0,
}),
}),
None,
None,
&mut driver_out,
)
.expect("predict_inter wedge interintra chroma arm");
let rv = rounding_variables(bit_depth, false).unwrap();
let pred0 = predict_inter_one_ref(
&refs[0],
0,
1,
0,
0,
cw,
ch,
crate::cdf::MOTION_MODE_SIMPLE,
1,
1,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
rv.inter_round0,
rv.inter_round1,
None,
false,
)
.unwrap();
let mut standalone = intra_seed.clone();
mask_blend_interintra(
bit_depth,
rv.inter_post_round,
1,
1,
&pred0,
cw,
ch,
&wmask,
0,
&mut standalone,
)
.unwrap();
assert_eq!(driver_out, standalone);
let mut chroma_mask = vec![0u8; cw * ch];
for y in 0..ch {
for x in 0..cw {
let s = wmask[2 * y * luma_w + 2 * x] as i64
+ wmask[2 * y * luma_w + 2 * x + 1] as i64
+ wmask[(2 * y + 1) * luma_w + 2 * x] as i64
+ wmask[(2 * y + 1) * luma_w + 2 * x + 1] as i64;
chroma_mask[y * cw + x] = round2(s, 2) as u8;
}
}
let mut oracle = intra_seed.clone();
mask_blend_interintra(
bit_depth,
rv.inter_post_round,
0,
0,
&pred0,
cw,
ch,
&chroma_mask,
0,
&mut oracle,
)
.unwrap();
assert_eq!(
driver_out, oracle,
"chroma wedge interintra must equal a hand-downsampled non-subsampled blend"
);
}
#[test]
fn r191_get_relative_dist_truth_table() {
assert_eq!(get_relative_dist(5, 3, 0), 0);
assert_eq!(get_relative_dist(-5, 3, 0), 0);
assert_eq!(get_relative_dist(10, 5, 7), 5);
assert_eq!(get_relative_dist(5, 10, 7), -5);
assert_eq!(get_relative_dist(100, 0, 7), -28);
}
#[test]
fn r191_quant_dist_lookup_sums_to_16() {
for (i, row) in QUANT_DIST_LOOKUP.iter().enumerate() {
assert_eq!(row[0] + row[1], 16, "row {i} = {:?}", row);
}
}
#[test]
fn r191_distance_weights_equal_distances() {
let dw = distance_weights(7, 0, 5, 5);
assert_eq!(dw.fwd_weight + dw.bck_weight, 16);
}
#[test]
fn r191_distance_weights_zero_distance_branch() {
let dw = distance_weights(7, 10, 10, 5);
assert_eq!(dw.fwd_weight, 13);
assert_eq!(dw.bck_weight, 3);
}
#[test]
fn r191_distance_weights_no_order_hint() {
let dw = distance_weights(0, 0, 0, 0);
assert_eq!(dw.fwd_weight, 3);
assert_eq!(dw.bck_weight, 13);
}
#[test]
fn r191_distance_weights_asymmetric_far_forward() {
let dw = distance_weights(7, 0, 1, 10);
assert_eq!(dw.fwd_weight, 13);
assert_eq!(dw.bck_weight, 3);
}
#[test]
fn r191_compound_distance_blend_symmetric() {
let rv = rounding_variables(8, true).unwrap();
let preds0 = vec![100i32 << rv.inter_post_round; 16];
let preds1 = vec![200i32 << rv.inter_post_round; 16];
let weights = DistanceWeights {
fwd_weight: 8,
bck_weight: 8,
};
let mut out = vec![0u16; 16];
compound_distance_blend(
8,
rv.inter_post_round,
weights,
&preds0,
&preds1,
4,
4,
&mut out,
)
.unwrap();
for &v in out.iter() {
assert_eq!(v, 150);
}
}
#[test]
fn r191_compound_distance_blend_rejects_invalid_inputs() {
let preds = vec![0i32; 16];
let mut out = vec![0u16; 16];
let w = DistanceWeights {
fwd_weight: 8,
bck_weight: 8,
};
assert!(compound_distance_blend(7, 0, w, &preds, &preds, 4, 4, &mut out).is_err());
assert!(compound_distance_blend(8, 0, w, &preds, &preds, 0, 4, &mut out).is_err());
let mut tiny = vec![0u16; 8];
assert!(compound_distance_blend(8, 0, w, &preds, &preds, 4, 4, &mut tiny).is_err());
}
#[test]
fn r192_resolve_divisor_zero_returns_none() {
assert!(resolve_divisor(0).is_none());
}
#[test]
fn r192_resolve_divisor_basic_inverse() {
let div = resolve_divisor(256).unwrap();
assert_eq!(div.div_factor, 16384);
assert_eq!(div.div_shift, 22);
let lhs: i64 = 256i64 * (div.div_factor as i64);
let approx = round2_signed(lhs, div.div_shift);
assert_eq!(approx, 1);
let div = resolve_divisor(1024).unwrap();
assert_eq!(div.div_factor, 16384);
assert_eq!(div.div_shift, 24);
let div = resolve_divisor(1).unwrap();
let approx = round2_signed(div.div_factor as i64, div.div_shift);
assert_eq!(approx, 1);
}
#[test]
fn r192_resolve_divisor_negative_flips_sign() {
let p = resolve_divisor(256).unwrap();
let n = resolve_divisor(-256).unwrap();
assert_eq!(n.div_factor, -p.div_factor);
assert_eq!(n.div_shift, p.div_shift);
}
#[test]
fn r192_setup_shear_identity_is_zero() {
let one = 1i32 << WARP_WARPEDMODEL_PREC_BITS;
let shear = setup_shear([0, 0, one, 0, 0, one]).unwrap();
assert_eq!(shear.alpha, 0);
assert_eq!(shear.beta, 0);
assert_eq!(shear.gamma, 0);
assert_eq!(shear.delta, 0);
assert!(shear.warp_valid);
}
#[test]
fn r192_setup_shear_zero_diag_is_caller_bug() {
let shear = setup_shear([0, 0, 0, 0, 0, 1 << WARP_WARPEDMODEL_PREC_BITS]);
assert!(shear.is_none());
}
#[test]
fn r192_setup_shear_small_horizontal_shear() {
let one = 1i32 << WARP_WARPEDMODEL_PREC_BITS;
let shear = setup_shear([0, 0, one + 64, 0, 0, one]).unwrap();
assert_eq!(shear.alpha, 64);
assert_eq!(shear.beta, 0);
assert_eq!(shear.gamma, 0);
assert_eq!(shear.delta, 0);
assert!(shear.warp_valid);
}
#[test]
fn r192_setup_shear_rejects_unstable_factorisation() {
let one = 1i32 << WARP_WARPEDMODEL_PREC_BITS;
let shear = setup_shear([0, 0, one + 16384, 0, 0, one]).unwrap();
assert_eq!(shear.alpha, 16384);
assert!(!shear.warp_valid);
}
#[test]
fn r192_warp_estimation_empty_cands_is_invalid() {
let lw = warp_estimation(&[], 0, 0, 4, 4, [0, 0]);
assert!(!lw.local_valid);
}
#[test]
fn r192_warp_estimation_single_cand_is_invalid() {
let lw = warp_estimation(
&[WarpSampleCand {
sy: 0,
sx: 0,
dy: 0,
dx: 0,
}],
0,
0,
4,
4,
[0, 0],
);
assert!(lw.local_valid);
}
#[test]
fn r192_block_warp_rejects_invalid_use_warp() {
let ref_plane = vec![128u16; 64 * 64];
let mut pred = vec![0i32; 16 * 16];
let one = 1i32 << WARP_WARPEDMODEL_PREC_BITS;
let res = block_warp(
0, 0,
0,
0,
0,
0,
0,
0,
16,
16,
&ref_plane,
64,
64,
64,
[0, 0, one, 0, 0, one],
3,
11,
16,
&mut pred,
);
assert!(res.is_err());
}
#[test]
fn r192_block_warp_rejects_invalid_dims() {
let ref_plane = vec![128u16; 64 * 64];
let mut pred = vec![0i32; 16 * 16];
let one = 1i32 << WARP_WARPEDMODEL_PREC_BITS;
assert!(block_warp(
1,
3,
0,
0,
0,
0,
0,
0,
16,
16,
&ref_plane,
64,
64,
64,
[0, 0, one, 0, 0, one],
3,
11,
16,
&mut pred,
)
.is_err());
assert!(block_warp(
1,
0,
0,
0,
0,
0,
0,
0,
0,
16,
&ref_plane,
64,
64,
64,
[0, 0, one, 0, 0, one],
3,
11,
16,
&mut pred,
)
.is_err());
assert!(block_warp(
1,
0,
0,
0,
0,
0,
0,
0,
16,
0,
&ref_plane,
64,
64,
64,
[0, 0, one, 0, 0, one],
3,
11,
16,
&mut pred,
)
.is_err());
assert!(block_warp(
1,
0,
0,
0,
0,
0,
2,
0,
16,
16,
&ref_plane,
64,
64,
64,
[0, 0, one, 0, 0, one],
3,
11,
16,
&mut pred,
)
.is_err());
}
#[test]
fn r192_block_warp_identity_on_constant_ref() {
let cst: u16 = 100;
let ref_plane = vec![cst; 64 * 64];
let mut pred = vec![0i32; 8 * 8];
let one = 1i32 << WARP_WARPEDMODEL_PREC_BITS;
block_warp(
1,
0,
0,
0,
0,
0,
0,
0,
8,
8,
&ref_plane,
64,
64,
64,
[0, 0, one, 0, 0, one],
3, 11, 8,
&mut pred,
)
.unwrap();
for (i, &v) in pred.iter().enumerate() {
assert_eq!(v, cst as i32, "pred[{i}] = {v} != {cst}");
}
}
#[test]
fn r192_warped_filters_table_shape() {
assert_eq!(WARPED_FILTERS.len(), WARPEDPIXEL_PREC_SHIFTS * 3 + 1);
assert_eq!(WARPED_FILTERS.len(), 193);
for row in WARPED_FILTERS.iter() {
assert_eq!(row.len(), 8);
}
}
#[test]
fn r192_warped_filters_rows_sum_to_128() {
for (i, row) in WARPED_FILTERS.iter().enumerate() {
let s: i32 = row.iter().sum();
assert_eq!(s, 128, "row {i} sums to {s}");
}
}
#[test]
fn r192_div_lut_shape() {
assert_eq!(DIV_LUT.len(), 257);
assert_eq!(DIV_LUT[0], 1 << DIV_LUT_PREC_BITS);
assert_eq!(DIV_LUT[256], 8192);
for w in DIV_LUT.windows(2) {
assert!(w[0] >= w[1], "Div_Lut not monotonic at {} > {}", w[0], w[1]);
}
}
#[test]
fn r193_obmc_mask_table_shapes() {
assert_eq!(OBMC_MASK_2.len(), 2);
assert_eq!(OBMC_MASK_4.len(), 4);
assert_eq!(OBMC_MASK_8.len(), 8);
assert_eq!(OBMC_MASK_16.len(), 16);
assert_eq!(OBMC_MASK_32.len(), 32);
for &m in OBMC_MASK_2
.iter()
.chain(OBMC_MASK_4.iter())
.chain(OBMC_MASK_8.iter())
.chain(OBMC_MASK_16.iter())
.chain(OBMC_MASK_32.iter())
{
assert!(m <= 64, "obmc mask entry {m} > 64");
}
}
#[test]
fn r193_obmc_mask_first_and_last_values() {
assert_eq!(OBMC_MASK_2[0], 45);
assert_eq!(OBMC_MASK_2[1], 64);
assert_eq!(OBMC_MASK_4[0], 39);
assert_eq!(*OBMC_MASK_4.last().unwrap(), 64);
assert_eq!(OBMC_MASK_8[0], 36);
assert_eq!(*OBMC_MASK_8.last().unwrap(), 64);
assert_eq!(OBMC_MASK_16[0], 34);
assert_eq!(*OBMC_MASK_16.last().unwrap(), 64);
assert_eq!(OBMC_MASK_32[0], 33);
assert_eq!(*OBMC_MASK_32.last().unwrap(), 64);
}
#[test]
fn r193_get_obmc_mask_dispatches_each_size() {
assert_eq!(get_obmc_mask(2), &OBMC_MASK_2[..]);
assert_eq!(get_obmc_mask(4), &OBMC_MASK_4[..]);
assert_eq!(get_obmc_mask(8), &OBMC_MASK_8[..]);
assert_eq!(get_obmc_mask(16), &OBMC_MASK_16[..]);
assert_eq!(get_obmc_mask(32), &OBMC_MASK_32[..]);
}
#[test]
fn r193_get_obmc_mask_else_returns_mask_32() {
assert_eq!(get_obmc_mask(32), &OBMC_MASK_32[..]);
assert_eq!(get_obmc_mask(33), &OBMC_MASK_32[..]);
assert_eq!(get_obmc_mask(1), &OBMC_MASK_32[..]);
assert_eq!(get_obmc_mask(0), &OBMC_MASK_32[..]);
assert_eq!(get_obmc_mask(7), &OBMC_MASK_32[..]);
}
#[test]
fn r193_overlap_blending_identity_when_obmc_equals_curr() {
let curr_stride = 8usize;
let curr_h = 6usize;
let mut curr: Vec<u16> = (0..(curr_stride * curr_h) as u16).collect();
let pre = curr.clone();
let pred_w = 4usize;
let pred_h = 4usize;
let pred_x = 1usize;
let pred_y = 1usize;
let mut obmc = vec![0u16; pred_w * pred_h];
for i in 0..pred_h {
for j in 0..pred_w {
obmc[i * pred_w + j] = curr[(pred_y + i) * curr_stride + pred_x + j];
}
}
overlap_blending(
&mut curr,
curr_stride,
pred_x,
pred_y,
pred_w,
pred_h,
OverlapPass::Above,
&obmc,
pred_w,
&OBMC_MASK_4,
)
.unwrap();
assert_eq!(curr, pre, "obmc == curr ⇒ blend identity");
}
#[test]
fn r193_overlap_blending_above_uses_row_mask() {
let curr_stride = 4usize;
let mut curr = vec![0u16; curr_stride * 4];
let obmc = vec![64u16; curr_stride * 4];
overlap_blending(
&mut curr,
curr_stride,
0,
0,
4,
4,
OverlapPass::Above,
&obmc,
curr_stride,
&OBMC_MASK_4,
)
.unwrap();
let expected_per_row: [u16; 4] = [64 - 39, 64 - 50, 64 - 59, 64 - 64];
for i in 0..4 {
for j in 0..4 {
assert_eq!(
curr[i * curr_stride + j],
expected_per_row[i],
"above row {i} col {j}",
);
}
}
}
#[test]
fn r193_overlap_blending_left_uses_col_mask() {
let curr_stride = 4usize;
let mut curr = vec![0u16; curr_stride * 4];
let obmc = vec![64u16; curr_stride * 4];
overlap_blending(
&mut curr,
curr_stride,
0,
0,
4,
4,
OverlapPass::Left,
&obmc,
curr_stride,
&OBMC_MASK_4,
)
.unwrap();
let expected_per_col: [u16; 4] = [64 - 39, 64 - 50, 64 - 59, 64 - 64];
for i in 0..4 {
for j in 0..4 {
assert_eq!(
curr[i * curr_stride + j],
expected_per_col[j],
"left row {i} col {j}",
);
}
}
}
#[test]
fn r193_overlap_blending_is_convex_combination() {
let curr_stride = 8usize;
let mut curr = vec![100u16; curr_stride * 8];
let obmc = vec![300u16; curr_stride * 8];
overlap_blending(
&mut curr,
curr_stride,
0,
0,
8,
8,
OverlapPass::Above,
&obmc,
curr_stride,
&OBMC_MASK_8,
)
.unwrap();
for v in &curr {
assert!(*v >= 100 && *v <= 300, "value {v} outside [100, 300]");
}
}
#[test]
fn r193_overlap_blending_above_hand_computed_8tap() {
let curr_stride = 8usize;
let mut curr = vec![200u16; curr_stride * 8];
let obmc = vec![40u16; curr_stride * 8];
overlap_blending(
&mut curr,
curr_stride,
0,
0,
8,
8,
OverlapPass::Above,
&obmc,
curr_stride,
&OBMC_MASK_8,
)
.unwrap();
for (j, v) in curr.iter().enumerate().take(8) {
assert_eq!(*v, 130, "row 0 col {j}");
}
let row7 = &curr[7 * curr_stride..7 * curr_stride + 8];
for (j, v) in row7.iter().enumerate() {
assert_eq!(*v, 200, "row 7 col {j}");
}
}
#[test]
fn r193_overlap_blending_offsets_respected() {
let curr_stride = 8usize;
let mut curr = vec![17u16; curr_stride * 8];
let pre = curr.clone();
let obmc = vec![64u16; 4 * 4];
overlap_blending(
&mut curr,
curr_stride,
2,
3,
4,
4,
OverlapPass::Above,
&obmc,
4,
&OBMC_MASK_4,
)
.unwrap();
for i in 0..8 {
for j in 0..8 {
let in_region = (3..7).contains(&i) && (2..6).contains(&j);
if !in_region {
assert_eq!(
curr[i * curr_stride + j],
pre[i * curr_stride + j],
"outside-region ({i},{j}) modified",
);
}
}
}
}
#[test]
fn r193_overlap_blending_rejects_caller_bugs() {
let mut curr = vec![0u16; 64];
let obmc = vec![0u16; 64];
assert!(overlap_blending(
&mut curr,
8,
0,
0,
0,
4,
OverlapPass::Above,
&obmc,
4,
&OBMC_MASK_4
)
.is_err());
assert!(overlap_blending(
&mut curr,
8,
0,
0,
4,
0,
OverlapPass::Above,
&obmc,
4,
&OBMC_MASK_4
)
.is_err());
assert!(overlap_blending(
&mut curr,
8,
0,
0,
4,
4,
OverlapPass::Above,
&obmc,
3,
&OBMC_MASK_4
)
.is_err());
assert!(overlap_blending(
&mut curr,
4,
2,
0,
4,
4,
OverlapPass::Above,
&obmc,
4,
&OBMC_MASK_4
)
.is_err());
let tiny = vec![0u16; 4];
assert!(overlap_blending(
&mut curr,
8,
0,
0,
4,
4,
OverlapPass::Above,
&tiny,
4,
&OBMC_MASK_4
)
.is_err());
let mut small = vec![0u16; 8];
assert!(overlap_blending(
&mut small,
8,
0,
0,
4,
4,
OverlapPass::Above,
&obmc,
4,
&OBMC_MASK_4
)
.is_err());
let mut curr2 = vec![0u16; 64];
let one = [64u8; 1];
assert!(overlap_blending(
&mut curr2,
8,
0,
0,
4,
4,
OverlapPass::Above,
&obmc,
4,
&one
)
.is_err());
}
#[test]
fn r193_overlap_neighbour_predict_blend_matches_direct() {
let curr_stride = 4usize;
let mut curr_a = vec![0u16; curr_stride * 4];
let mut curr_b = vec![0u16; curr_stride * 4];
let obmc = vec![64u16; curr_stride * 4];
overlap_blending(
&mut curr_a,
curr_stride,
0,
0,
4,
4,
OverlapPass::Above,
&obmc,
curr_stride,
&OBMC_MASK_4,
)
.unwrap();
overlap_neighbour_predict_blend(
&mut curr_b,
curr_stride,
0,
0,
4,
4,
OverlapPass::Above,
&obmc,
curr_stride,
4,
)
.unwrap();
assert_eq!(curr_a, curr_b);
}
#[test]
fn r193_overlap_neighbour_predict_blend_falls_back_to_mask_32() {
let curr_stride = 8usize;
let mut curr = vec![0u16; curr_stride * 8];
let obmc = vec![64u16; curr_stride * 8];
overlap_neighbour_predict_blend(
&mut curr,
curr_stride,
0,
0,
8,
8,
OverlapPass::Above,
&obmc,
curr_stride,
100,
)
.unwrap();
for (j, v) in curr.iter().enumerate().take(8) {
assert_eq!(*v, 64 - 33, "row 0 col {j}");
}
}
#[test]
fn r194_predict_inter_simple_runs_to_completion_on_translational_path() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = (r * 16 + c) as u16;
}
}
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let w = 4;
let h = 4;
let mut pred_out = vec![0u16; w * h];
predict_inter(
0,
2,
2,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
None,
&mut pred_out,
)
.expect("predict_inter SIMPLE single-ref translational path");
let mvs = motion_vector_scaling(
0,
0,
0,
ref_w as u32,
ref_h as u32,
ref_w as u32,
ref_h as u32,
2,
2,
[0, 0],
)
.unwrap();
let rv = rounding_variables(8, false).unwrap();
let mut leaf_pred = vec![0i32; w * h];
block_inter_prediction(
0,
0,
0,
&refp,
stride,
ref_w as u32,
ref_h as u32,
mvs.start_x,
mvs.start_y,
mvs.step_x,
mvs.step_y,
w,
h,
EIGHTTAP,
EIGHTTAP,
rv.inter_round0,
rv.inter_round1,
&mut leaf_pred,
)
.unwrap();
let mut leaf_out = vec![0u16; w * h];
clip1_single_ref(8, &leaf_pred, &mut leaf_out).unwrap();
assert_eq!(
pred_out, leaf_out,
"driver output must equal direct leaf composition"
);
}
#[test]
fn r291_predict_inter_half_sample_mv_matches_hand_built_reference() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = (r * 16 + c) as u16;
}
}
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 4], }];
let w = 4;
let h = 4;
let mut pred_out = vec![0u16; w * h];
predict_inter(
0,
4,
4,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
None,
&mut pred_out,
)
.expect("predict_inter SIMPLE single-ref half-sample MC");
#[rustfmt::skip]
let expected: [u16; 16] = [
69, 70, 71, 72,
85, 86, 87, 88,
101, 102, 103, 104,
117, 118, 119, 120,
];
assert_eq!(
pred_out, expected,
"predict_inter half-sample MV must match the hand-built \
§7.11.3.4 EIGHTTAP oracle"
);
let mut differs = false;
for i in 0..h {
for j in 0..w {
let integer = refp[(4 + i) * stride + (4 + j)];
if pred_out[i * w + j] != integer {
differs = true;
}
}
}
assert!(
differs,
"half-sample MV must interpolate, not copy the integer grid"
);
}
#[test]
fn r292_reconstruct_inter_block_drives_modeinfo_through_predict_inter() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = (r * 16 + c) as u16;
}
}
let decoy = vec![0u16; ref_h * stride];
let frame_store = [
RefFrameStoreEntry {
plane: &decoy,
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
},
RefFrameStoreEntry {
plane: &decoy,
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
},
RefFrameStoreEntry {
plane: &decoy,
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
},
RefFrameStoreEntry {
plane: &refp,
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
},
];
let ref_frame_idx: [u8; 7] = [3, 0, 1, 2, 0, 1, 2];
let w = 4;
let h = 4;
let curr_w = 8;
let curr_h = 8;
let sentinel = 999u16;
let mut curr = vec![sentinel; curr_w * curr_h];
let mode_info = InterModeInfo {
ref_frame: crate::uncompressed_header_tail::LAST_FRAME as u8,
mv: [0, 4],
};
reconstruct_inter_block(
mode_info,
&ref_frame_idx,
&frame_store,
0,
4,
4,
w,
h,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&mut curr,
curr_w,
)
.expect("reconstruct_inter_block SIMPLE single-ref half-sample");
#[rustfmt::skip]
let expected: [u16; 16] = [
69, 70, 71, 72,
85, 86, 87, 88,
101, 102, 103, 104,
117, 118, 119, 120,
];
for i in 0..h {
for j in 0..w {
assert_eq!(
curr[(4 + i) * curr_w + (4 + j)],
expected[i * w + j],
"reconstructed sample ({}, {}) must match the oracle",
4 + j,
4 + i,
);
}
}
for r in 0..curr_h {
for c in 0..curr_w {
let inside = (4..8).contains(&r) && (4..8).contains(&c);
if !inside {
assert_eq!(
curr[r * curr_w + c],
sentinel,
"sample ({c}, {r}) outside the write region must be untouched"
);
}
}
}
}
#[test]
fn r292_reconstruct_inter_block_rejects_caller_bugs() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let refp = vec![0u16; ref_w * ref_h];
let store = [RefFrameStoreEntry {
plane: &refp,
stride: ref_w,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
}];
let ref_frame_idx: [u8; 7] = [0, 0, 0, 0, 0, 0, 0];
let w = 4;
let h = 4;
let mut curr = vec![0u16; ref_w * ref_h];
let call = |ref_frame: u8,
rfi: &[u8],
fs: &[RefFrameStoreEntry<'_>],
curr: &mut [u16],
curr_stride: usize| {
reconstruct_inter_block(
InterModeInfo {
ref_frame,
mv: [0, 0],
},
rfi,
fs,
0,
0,
0,
w,
h,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
curr,
curr_stride,
)
};
assert_eq!(
call(
crate::uncompressed_header_tail::INTRA_FRAME as u8,
&ref_frame_idx,
&store,
&mut curr,
ref_w
)
.unwrap_err(),
crate::Error::PartitionWalkOutOfRange
);
assert_eq!(
call(8, &ref_frame_idx, &store, &mut curr, ref_w).unwrap_err(),
crate::Error::PartitionWalkOutOfRange
);
let bad_idx: [u8; 7] = [5, 0, 0, 0, 0, 0, 0];
assert_eq!(
call(
crate::uncompressed_header_tail::LAST_FRAME as u8,
&bad_idx,
&store,
&mut curr,
ref_w
)
.unwrap_err(),
crate::Error::PartitionWalkOutOfRange
);
let mut tiny = vec![9999u16; 4];
call(
crate::uncompressed_header_tail::LAST_FRAME as u8,
&ref_frame_idx,
&store,
&mut tiny,
2,
)
.expect("overhanging write clips instead of erroring");
assert!(
tiny.iter().all(|&v| v <= 255),
"the clipped 2×2 window (all four samples of the stride-2 plane) is written"
);
let mut empty: Vec<u16> = Vec::new();
assert_eq!(
call(
crate::uncompressed_header_tail::LAST_FRAME as u8,
&ref_frame_idx,
&store,
&mut empty,
2
)
.unwrap_err(),
crate::Error::PartitionWalkOutOfRange
);
}
#[test]
fn r293_reconstruct_inter_frame_walks_grid_single_ref_translational() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = (r * 16 + c) as u16;
}
}
let decoy = vec![0u16; ref_h * stride];
let decoy_entry = || RefFrameStoreEntry {
plane: &decoy[..],
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let real_entry = RefFrameStoreEntry {
plane: &refp[..],
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let store = [decoy_entry(), decoy_entry(), decoy_entry(), real_entry];
let store2 = store;
let ref_frame_idx: [u8; 7] = [3, 0, 1, 2, 0, 1, 2];
let mi_rows: u32 = 2;
let mi_cols: u32 = 4;
let cells = (mi_rows * mi_cols) as usize;
let last = crate::uncompressed_header_tail::LAST_FRAME as i8;
use crate::cdf::{BLOCK_4X4, BLOCK_8X8, BLOCK_INVALID};
let mut mi_sizes = vec![BLOCK_INVALID; cells];
let mut is_inters = vec![0u8; cells];
let mut ref_frames = vec![0i8; cells * 2];
for cell in 0..cells {
ref_frames[cell * 2 + 1] = -1;
}
let mut mvs = vec![0i16; cells * 4];
let interp_filters = vec![EIGHTTAP; cells * 2];
let mut compound_types = vec![COMPOUND_AVERAGE; cells];
let set_cell = |mi_sizes: &mut [usize], r: usize, c: usize, sz: usize| {
mi_sizes[r * mi_cols as usize + c] = sz;
};
let stamp_inter = |is_inters: &mut [u8],
ref_frames: &mut [i8],
mvs: &mut [i16],
r: usize,
c: usize,
rf0: i8,
rf1: i8,
mv: [i16; 2]| {
let cell = r * mi_cols as usize + c;
is_inters[cell] = 1;
ref_frames[cell * 2] = rf0;
ref_frames[cell * 2 + 1] = rf1;
mvs[cell * 4] = mv[0];
mvs[cell * 4 + 1] = mv[1];
};
set_cell(&mut mi_sizes, 0, 0, BLOCK_4X4);
stamp_inter(
&mut is_inters,
&mut ref_frames,
&mut mvs,
0,
0,
last,
-1,
[0, 4],
);
set_cell(&mut mi_sizes, 0, 1, BLOCK_4X4);
for (r, c) in [(0usize, 2usize), (0, 3), (1, 2), (1, 3)] {
set_cell(&mut mi_sizes, r, c, BLOCK_8X8);
}
for (r, c) in [(0usize, 2usize), (0, 3), (1, 2), (1, 3)] {
stamp_inter(
&mut is_inters,
&mut ref_frames,
&mut mvs,
r,
c,
last,
-1,
[0, 4],
);
}
set_cell(&mut mi_sizes, 1, 0, BLOCK_4X4);
set_cell(&mut mi_sizes, 1, 1, BLOCK_4X4);
stamp_inter(
&mut is_inters,
&mut ref_frames,
&mut mvs,
1,
1,
last,
last,
[0, 4],
);
compound_types[mi_cols as usize + 1] = COMPOUND_INTRA;
let curr_w = (mi_cols * 4) as usize; let curr_h = (mi_rows * 4) as usize; let sentinel = 7000u16;
let mut curr = vec![sentinel; curr_w * curr_h];
let order_hints_by_ref = [0i32; 8];
let wedge_zeros = vec![0u8; cells];
let grid = InterModeInfoGrid {
mi_sizes: &mi_sizes,
is_inters: &is_inters,
ref_frames: &ref_frames,
mvs: &mvs,
interp_filters: &interp_filters,
compound_types: &compound_types,
wedge_indices: &wedge_zeros,
wedge_signs: &wedge_zeros,
mask_types: &wedge_zeros,
interintra_modes: &wedge_zeros,
wedge_interintras: &wedge_zeros,
interintra_wedge_indices: &wedge_zeros,
order_hint_bits: 7,
current_order_hint: 0,
order_hints_by_ref: &order_hints_by_ref,
mi_rows,
mi_cols,
bit_depth: 8,
warp: None,
obmc: None,
};
{
let mut planes = [PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut curr,
curr_stride: curr_w,
}];
reconstruct_inter_frame(&grid, &ref_frame_idx, &mut planes)
.expect("frame-level inter reconstruction");
}
let mut oracle = vec![sentinel; curr_w * curr_h];
reconstruct_inter_block(
InterModeInfo {
ref_frame: last as u8,
mv: [0, 4],
},
&ref_frame_idx,
&store2,
0,
0,
0,
4,
4,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&mut oracle,
curr_w,
)
.unwrap();
reconstruct_inter_block(
InterModeInfo {
ref_frame: last as u8,
mv: [0, 4],
},
&ref_frame_idx,
&store2,
0,
8,
0,
8,
8,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&mut oracle,
curr_w,
)
.unwrap();
assert_eq!(
curr, oracle,
"frame-level walk must dispatch identically to the per-block driver"
);
for &(x0, y0, x1, y1) in &[(4usize, 0usize, 8usize, 4usize), (0, 4, 4, 8), (4, 4, 8, 8)] {
for r in y0..y1 {
for c in x0..x1 {
assert_eq!(
curr[r * curr_w + c],
sentinel,
"skipped-leaf plane sample ({c}, {r}) must stay the sentinel"
);
}
}
}
assert_ne!(
curr[0], sentinel,
"the (0,0) inter leaf must have been reconstructed"
);
assert_ne!(
curr[8], sentinel,
"the (0,2) inter leaf must have been reconstructed"
);
}
#[test]
fn r308_reconstruct_inter_frame_chroma_some_use_intra_uses_bottom_right_mv() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = (r * 16 + c) as u16;
}
}
let entry = RefFrameStoreEntry {
plane: &refp[..],
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let store = [entry];
let store2 = store;
let ref_frame_idx: [u8; 7] = [0; 7];
let mi_rows: u32 = 2;
let mi_cols: u32 = 2;
let cells = (mi_rows * mi_cols) as usize;
let last = crate::uncompressed_header_tail::LAST_FRAME as i8;
use crate::cdf::{BLOCK_4X4, BLOCK_INVALID};
let mut mi_sizes = vec![BLOCK_INVALID; cells];
let mut is_inters = vec![0u8; cells];
let mut ref_frames = vec![0i8; cells * 2];
for cell in 0..cells {
ref_frames[cell * 2 + 1] = -1; }
let mut mvs = vec![0i16; cells * 4];
let interp_filters = vec![EIGHTTAP; cells * 2];
let comp_types = vec![COMPOUND_AVERAGE; cells];
let wedge_zeros = vec![0u8; cells];
let order_hints_by_ref = [0i32; 8];
let idx = |r: usize, c: usize| r * mi_cols as usize + c;
let mv_a: [i16; 2] = [0, 8]; let mv_b: [i16; 2] = [8, 0];
mi_sizes[idx(0, 0)] = BLOCK_4X4;
is_inters[idx(0, 0)] = 1;
ref_frames[idx(0, 0) * 2] = last;
mvs[idx(0, 0) * 4] = mv_a[0];
mvs[idx(0, 0) * 4 + 1] = mv_a[1];
mi_sizes[idx(0, 1)] = BLOCK_4X4;
mi_sizes[idx(1, 0)] = BLOCK_4X4;
mi_sizes[idx(1, 1)] = BLOCK_4X4;
is_inters[idx(1, 1)] = 1;
ref_frames[idx(1, 1) * 2] = last;
mvs[idx(1, 1) * 4] = mv_b[0];
mvs[idx(1, 1) * 4 + 1] = mv_b[1];
let grid = InterModeInfoGrid {
mi_sizes: &mi_sizes,
is_inters: &is_inters,
ref_frames: &ref_frames,
mvs: &mvs,
interp_filters: &interp_filters,
compound_types: &comp_types,
wedge_indices: &wedge_zeros,
wedge_signs: &wedge_zeros,
mask_types: &wedge_zeros,
interintra_modes: &wedge_zeros,
wedge_interintras: &wedge_zeros,
interintra_wedge_indices: &wedge_zeros,
order_hint_bits: 7,
current_order_hint: 0,
order_hints_by_ref: &order_hints_by_ref,
mi_rows,
mi_cols,
bit_depth: 8,
warp: None,
obmc: None,
};
let chroma_w = ((mi_cols * 4) >> 1) as usize; let chroma_h = ((mi_rows * 4) >> 1) as usize; let sentinel = 5000u16;
let mut chroma = vec![sentinel; chroma_w * chroma_h];
let luma_w = (mi_cols * 4) as usize;
let luma_h = (mi_rows * 4) as usize;
let mut luma = vec![sentinel; luma_w * luma_h];
let mut cr = vec![sentinel; chroma_w * chroma_h];
{
let mut planes = [
PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut luma,
curr_stride: luma_w,
},
PlaneReconContext {
plane: 1,
subsampling_x: 1,
subsampling_y: 1,
frame_store: &store,
frame_width: (ref_w as u32) >> 1,
frame_height: (ref_h as u32) >> 1,
curr: &mut chroma,
curr_stride: chroma_w,
},
PlaneReconContext {
plane: 2,
subsampling_x: 1,
subsampling_y: 1,
frame_store: &store,
frame_width: (ref_w as u32) >> 1,
frame_height: (ref_h as u32) >> 1,
curr: &mut cr,
curr_stride: chroma_w,
},
];
reconstruct_inter_frame(&grid, &ref_frame_idx, &mut planes)
.expect("frame-level inter reconstruction (3-plane 420)");
}
let mut oracle_b = vec![sentinel; chroma_w * chroma_h];
reconstruct_inter_block(
InterModeInfo {
ref_frame: last as u8,
mv: mv_b,
},
&ref_frame_idx,
&store2,
1,
0,
0,
4,
4,
8,
1,
1,
(ref_w as u32) >> 1,
(ref_h as u32) >> 1,
EIGHTTAP,
EIGHTTAP,
&mut oracle_b,
chroma_w,
)
.unwrap();
assert_eq!(
chroma, oracle_b,
"someUseIntra chroma split must predict from the bottom-right block's MV"
);
let mut oracle_a = vec![sentinel; chroma_w * chroma_h];
reconstruct_inter_block(
InterModeInfo {
ref_frame: last as u8,
mv: mv_a,
},
&ref_frame_idx,
&store2,
1,
0,
0,
4,
4,
8,
1,
1,
(ref_w as u32) >> 1,
(ref_h as u32) >> 1,
EIGHTTAP,
EIGHTTAP,
&mut oracle_a,
chroma_w,
)
.unwrap();
assert_ne!(
chroma, oracle_a,
"someUseIntra split must NOT use the top-left subsampled candidate's MV"
);
}
#[test]
fn r293_reconstruct_inter_frame_rejects_caller_bugs() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let refp = vec![0u16; ref_w * ref_h];
let store = [RefFrameStoreEntry {
plane: &refp[..],
stride: ref_w,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
}];
let ref_frame_idx: [u8; 7] = [0; 7];
let mi_rows: u32 = 1;
let mi_cols: u32 = 1;
let cells = 1usize;
let mut curr = vec![0u16; ref_w * ref_h];
let comp_types = vec![COMPOUND_AVERAGE; cells];
let wedge_zeros = vec![0u8; cells];
let order_hints_by_ref = [0i32; 8];
let run = |mi_sizes: &[usize],
is_inters: &[u8],
ref_frames: &[i8],
mvs: &[i16],
interp_filters: &[u8],
curr: &mut [u16]| {
let grid = InterModeInfoGrid {
mi_sizes,
is_inters,
ref_frames,
mvs,
interp_filters,
compound_types: &comp_types,
wedge_indices: &wedge_zeros,
wedge_signs: &wedge_zeros,
mask_types: &wedge_zeros,
interintra_modes: &wedge_zeros,
wedge_interintras: &wedge_zeros,
interintra_wedge_indices: &wedge_zeros,
order_hint_bits: 7,
current_order_hint: 0,
order_hints_by_ref: &order_hints_by_ref,
mi_rows,
mi_cols,
bit_depth: 8,
warp: None,
obmc: None,
};
let mut planes = [PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr,
curr_stride: ref_w,
}];
reconstruct_inter_frame(&grid, &ref_frame_idx, &mut planes)
};
let good_sizes = vec![crate::cdf::BLOCK_4X4; cells];
let good_is = vec![0u8; cells];
let good_rf = {
let mut v = vec![0i8; cells * 2];
v[1] = -1;
v
};
let good_mv = vec![0i16; cells * 4];
let good_if = vec![EIGHTTAP; cells * 2];
assert_eq!(
run(
&good_sizes[..0],
&good_is,
&good_rf,
&good_mv,
&good_if,
&mut curr
)
.unwrap_err(),
crate::Error::PartitionWalkOutOfRange
);
assert_eq!(
run(
&good_sizes,
&good_is[..0],
&good_rf,
&good_mv,
&good_if,
&mut curr
)
.unwrap_err(),
crate::Error::PartitionWalkOutOfRange
);
assert_eq!(
run(
&good_sizes,
&good_is,
&good_rf[..1],
&good_mv,
&good_if,
&mut curr
)
.unwrap_err(),
crate::Error::PartitionWalkOutOfRange
);
assert_eq!(
run(
&good_sizes,
&good_is,
&good_rf,
&good_mv[..3],
&good_if,
&mut curr
)
.unwrap_err(),
crate::Error::PartitionWalkOutOfRange
);
assert_eq!(
run(
&good_sizes,
&good_is,
&good_rf,
&good_mv,
&good_if[..1],
&mut curr
)
.unwrap_err(),
crate::Error::PartitionWalkOutOfRange
);
let bad_sizes = vec![crate::cdf::BLOCK_SIZES + 5; cells];
assert_eq!(
run(&bad_sizes, &good_is, &good_rf, &good_mv, &good_if, &mut curr).unwrap_err(),
crate::Error::PartitionWalkOutOfRange
);
}
#[test]
fn r338_reconstruct_inter_frame_drives_warped_causal_leaf() {
let ref_w: usize = 32;
let ref_h: usize = 32;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = (((r * 37) ^ (c * 53)) & 0xFF) as u16;
}
}
let real = RefFrameStoreEntry {
plane: &refp[..],
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let store = [real, real, real, real, real, real, real, real];
let ref_frame_idx: [u8; 7] = [0, 1, 2, 3, 4, 5, 6];
let mi_rows: u32 = 4;
let mi_cols: u32 = 4;
let cells = (mi_rows * mi_cols) as usize;
let last = crate::uncompressed_header_tail::LAST_FRAME as i8;
use crate::cdf::{BLOCK_8X8, BLOCK_INVALID};
let mut mi_sizes = vec![BLOCK_INVALID; cells];
let mut is_inters = vec![0u8; cells];
let mut ref_frames = vec![0i8; cells * 2];
for cell in 0..cells {
ref_frames[cell * 2 + 1] = -1;
}
let mvs = vec![0i16; cells * 4];
let interp_filters = vec![EIGHTTAP; cells * 2];
let zeros = vec![0u8; cells];
let mc = mi_cols as usize;
for (r, c) in [
(0, 0),
(0, 1),
(1, 0),
(1, 1),
(2, 0),
(2, 1),
(3, 0),
(3, 1),
] {
let cell = r * mc + c;
mi_sizes[cell] = BLOCK_8X8;
is_inters[cell] = 1;
ref_frames[cell * 2] = last;
}
let mut motion_modes = vec![crate::cdf::MOTION_MODE_SIMPLE; cells];
motion_modes[0] = crate::cdf::MOTION_MODE_WARPED_CAUSAL;
const WARP_ID: [i32; 6] = [0, 0, 1 << 16, 0, 0, 1 << 16];
const WARP_SHEAR: [i32; 6] = [0, 0, (1 << 16) + 4096, 0, 0, 1 << 16];
let mut local_warp_params = vec![0i32; cells * 6];
for cell in 0..cells {
local_warp_params[cell * 6..cell * 6 + 6].copy_from_slice(&WARP_ID);
}
local_warp_params[0..6].copy_from_slice(&WARP_SHEAR);
let local_warp_valid = vec![1u8; cells];
let y_modes = vec![crate::cdf::MODE_NEWMV; cells];
let gm_types = vec![crate::cdf::GM_TYPE_IDENTITY as u8; 8];
let mut gm_params = vec![0i32; 8 * 6];
for rf in 0..8 {
gm_params[rf * 6..rf * 6 + 6].copy_from_slice(&WARP_ID);
}
let order_hints_by_ref = [0i32; 8];
let warp_ctx = GridWarpContext {
motion_modes: &motion_modes,
local_warp_params: &local_warp_params,
local_warp_valid: &local_warp_valid,
y_modes: &y_modes,
gm_types: &gm_types,
gm_params: &gm_params,
force_integer_mv: false,
is_scaled: &[false; 8],
};
macro_rules! build_grid {
($warp:expr) => {
InterModeInfoGrid {
mi_sizes: &mi_sizes,
is_inters: &is_inters,
ref_frames: &ref_frames,
mvs: &mvs,
interp_filters: &interp_filters,
compound_types: &zeros,
wedge_indices: &zeros,
wedge_signs: &zeros,
mask_types: &zeros,
interintra_modes: &zeros,
wedge_interintras: &zeros,
interintra_wedge_indices: &zeros,
order_hint_bits: 7,
current_order_hint: 0,
order_hints_by_ref: &order_hints_by_ref,
mi_rows,
mi_cols,
bit_depth: 8,
warp: $warp,
obmc: None,
}
};
}
let curr_w = (mi_cols * 4) as usize; let curr_h = (mi_rows * 4) as usize; let sentinel = 9000u16;
let mut curr_warp = vec![sentinel; curr_w * curr_h];
{
let grid = build_grid!(Some(warp_ctx));
let mut planes = [PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut curr_warp,
curr_stride: curr_w,
}];
reconstruct_inter_frame(&grid, &ref_frame_idx, &mut planes).unwrap();
}
let mut curr_simple = vec![sentinel; curr_w * curr_h];
{
let grid = build_grid!(None);
let mut planes = [PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut curr_simple,
curr_stride: curr_w,
}];
reconstruct_inter_frame(&grid, &ref_frame_idx, &mut planes).unwrap();
}
let mut oracle = vec![sentinel; curr_w * curr_h];
let warp_params = WarpDriverParams {
y_mode: [crate::cdf::MODE_NEWMV, 0],
gm_type: [crate::cdf::GM_TYPE_IDENTITY as u8, 0],
gm_params: [WARP_ID, WARP_ID],
local_warp_params: WARP_SHEAR,
local_valid: true,
ref_is_scaled: [false, false],
force_integer_mv: false,
};
reconstruct_inter_block_warp(
InterModeInfo {
ref_frame: last as u8,
mv: [0, 0],
},
&warp_params,
&ref_frame_idx,
&store,
0,
0,
0,
8,
8,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&mut oracle,
curr_w,
)
.unwrap();
reconstruct_inter_block(
InterModeInfo {
ref_frame: last as u8,
mv: [0, 0],
},
&ref_frame_idx,
&store,
0,
0,
8,
8,
8,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&mut oracle,
curr_w,
)
.unwrap();
assert_eq!(
curr_warp, oracle,
"warp-enabled frame walk vs per-block oracle"
);
let warp_block_differs = (0..8)
.any(|i| (0..8).any(|j| curr_warp[i * curr_w + j] != curr_simple[i * curr_w + j]));
assert!(
warp_block_differs,
"WARPED_CAUSAL leaf must differ from the translational fallback"
);
for i in 8..16 {
for j in 0..8 {
assert_eq!(
curr_warp[i * curr_w + j],
curr_simple[i * curr_w + j],
"SIMPLE leaf must be identical regardless of warp ctx"
);
}
}
}
#[test]
fn r338_reconstruct_inter_frame_warp_ctx_slice_guards() {
let refp = vec![5u16; 32 * 32];
let entry = RefFrameStoreEntry {
plane: &refp[..],
stride: 32,
upscaled_width: 32,
width: 32,
height: 32,
};
let store = [entry; 8];
let ref_frame_idx = [0u8; 7];
let mi_rows: u32 = 2;
let mi_cols: u32 = 2;
let cells = (mi_rows * mi_cols) as usize;
let mi_sizes = vec![crate::cdf::BLOCK_INVALID; cells];
let is_inters = vec![0u8; cells];
let mut ref_frames = vec![0i8; cells * 2];
for cell in 0..cells {
ref_frames[cell * 2 + 1] = -1;
}
let mvs = vec![0i16; cells * 4];
let interp_filters = vec![EIGHTTAP; cells * 2];
let zeros = vec![0u8; cells];
let order_hints_by_ref = [0i32; 8];
let full_mm = vec![0u8; cells];
let full_lwp = vec![0i32; cells * 6];
let full_v = vec![0u8; cells];
let full_ym = vec![0u8; cells];
let full_gt = vec![0u8; 8];
let full_gp = vec![0i32; 8 * 6];
let short_mm = vec![0u8; cells - 1];
let warp_short = GridWarpContext {
motion_modes: &short_mm,
local_warp_params: &full_lwp,
local_warp_valid: &full_v,
y_modes: &full_ym,
gm_types: &full_gt,
gm_params: &full_gp,
force_integer_mv: false,
is_scaled: &[false; 8],
};
let _ = &full_mm;
let grid = InterModeInfoGrid {
mi_sizes: &mi_sizes,
is_inters: &is_inters,
ref_frames: &ref_frames,
mvs: &mvs,
interp_filters: &interp_filters,
compound_types: &zeros,
wedge_indices: &zeros,
wedge_signs: &zeros,
mask_types: &zeros,
interintra_modes: &zeros,
wedge_interintras: &zeros,
interintra_wedge_indices: &zeros,
order_hint_bits: 7,
current_order_hint: 0,
order_hints_by_ref: &order_hints_by_ref,
mi_rows,
mi_cols,
bit_depth: 8,
warp: Some(warp_short),
obmc: None,
};
let mut curr = vec![0u16; 64];
let mut planes = [PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: 32,
frame_height: 32,
curr: &mut curr,
curr_stride: 8,
}];
assert_eq!(
reconstruct_inter_frame(&grid, &ref_frame_idx, &mut planes).unwrap_err(),
crate::Error::PartitionWalkOutOfRange
);
}
#[test]
fn r378_reconstruct_inter_frame_obmc_dispatch_matches_per_block() {
let ref_w = 32usize;
let ref_h = 32usize;
let mut refp = vec![0u16; ref_w * ref_h];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * ref_w + c] = ((r * 32 + c) & 0xff) as u16;
}
}
let entry = RefFrameStoreEntry {
plane: &refp[..],
stride: ref_w,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let store = [entry; 8];
let ref_frame_idx = [0u8; 7];
let last = crate::uncompressed_header_tail::LAST_FRAME as u8;
let mi_rows: u32 = 4;
let mi_cols: u32 = 4;
let cells = (mi_rows * mi_cols) as usize;
let bw8x8 = crate::cdf::BLOCK_8X8;
let mut mi_sizes = vec![crate::cdf::BLOCK_INVALID; cells];
let mut is_inters = vec![0u8; cells];
let mut ref_frames = vec![0i8; cells * 2];
let mut mvs = vec![0i16; cells * 4];
let interp_filters = vec![EIGHTTAP; cells * 2];
let stamp = |mi_sizes: &mut [usize],
is_inters: &mut [u8],
ref_frames: &mut [i8],
mvs: &mut [i16],
r0: usize,
c0: usize,
mv: [i16; 2]| {
for dr in 0..2 {
for dc in 0..2 {
let cell = (r0 + dr) * mi_cols as usize + (c0 + dc);
mi_sizes[cell] = bw8x8;
is_inters[cell] = 1;
ref_frames[cell * 2] = last as i8;
ref_frames[cell * 2 + 1] = -1; mvs[cell * 4] = mv[0];
mvs[cell * 4 + 1] = mv[1];
}
}
};
stamp(
&mut mi_sizes,
&mut is_inters,
&mut ref_frames,
&mut mvs,
0,
0,
[0, 8],
);
stamp(
&mut mi_sizes,
&mut is_inters,
&mut ref_frames,
&mut mvs,
0,
2,
[8, 0],
);
stamp(
&mut mi_sizes,
&mut is_inters,
&mut ref_frames,
&mut mvs,
2,
0,
[4, 4],
);
stamp(
&mut mi_sizes,
&mut is_inters,
&mut ref_frames,
&mut mvs,
2,
2,
[2, 6],
);
let zeros = vec![0u8; cells];
let order_hints_by_ref = [0i32; 8];
let mut motion_modes = vec![crate::cdf::MOTION_MODE_SIMPLE; cells];
motion_modes[2 * mi_cols as usize + 2] = crate::cdf::MOTION_MODE_OBMC;
let mut avail_u = vec![0u8; cells];
let mut avail_l = vec![0u8; cells];
for r in 0..mi_rows as usize {
for c in 0..mi_cols as usize {
avail_u[r * mi_cols as usize + c] = (r > 0) as u8;
avail_l[r * mi_cols as usize + c] = (c > 0) as u8;
}
}
macro_rules! make_grid {
($obmc:expr) => {
InterModeInfoGrid {
mi_sizes: &mi_sizes,
is_inters: &is_inters,
ref_frames: &ref_frames,
mvs: &mvs,
interp_filters: &interp_filters,
compound_types: &zeros,
wedge_indices: &zeros,
wedge_signs: &zeros,
mask_types: &zeros,
interintra_modes: &zeros,
wedge_interintras: &zeros,
interintra_wedge_indices: &zeros,
order_hint_bits: 7,
current_order_hint: 0,
order_hints_by_ref: &order_hints_by_ref,
mi_rows,
mi_cols,
bit_depth: 8,
warp: None,
obmc: $obmc,
}
};
}
let curr_w = 16usize;
let curr_h = 16usize;
let mut curr_obmc = vec![0u16; curr_w * curr_h];
{
let grid = make_grid!(Some(GridObmcContext {
motion_modes: &motion_modes,
avail_u: &avail_u,
avail_l: &avail_l,
}));
let mut planes = [PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut curr_obmc,
curr_stride: curr_w,
}];
reconstruct_inter_frame(&grid, &ref_frame_idx, &mut planes)
.expect("OBMC-enabled frame walk");
}
let mut curr_simple = vec![0u16; curr_w * curr_h];
{
let grid = make_grid!(None);
let mut planes = [PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut curr_simple,
curr_stride: curr_w,
}];
reconstruct_inter_frame(&grid, &ref_frame_idx, &mut planes)
.expect("translational frame walk");
}
let above_idx = mi_cols as usize + 3;
let above_ref_frame = ref_frames[above_idx * 2];
let above_mv = [mvs[above_idx * 4], mvs[above_idx * 4 + 1]];
let left_ref_frame = ref_frames[(3 * mi_cols as usize + 1) * 2];
let left_mv = [
mvs[(3 * mi_cols as usize + 1) * 4],
mvs[(3 * mi_cols as usize + 1) * 4 + 1],
];
let nb_bundle = |_rf: i8, mv: [i16; 2]| PredictInterRef {
ref_plane: &refp[..],
ref_stride: ref_w,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv,
};
let _ = (above_ref_frame, left_ref_frame);
let above_nb = [ObmcNeighbour {
bundle: nb_bundle(above_ref_frame, above_mv),
step4: 2,
interp_filter_x: EIGHTTAP,
interp_filter_y: EIGHTTAP,
axis_pos4: 2,
}];
let left_nb = [ObmcNeighbour {
bundle: nb_bundle(left_ref_frame, left_mv),
step4: 2,
interp_filter_x: EIGHTTAP,
interp_filter_y: EIGHTTAP,
axis_pos4: 2,
}];
let obmc_params = ObmcParams {
mi_row: 2,
mi_col: 2,
mi_cols,
mi_rows,
mi_width_log2: crate::cdf::mi_width_log2(bw8x8) as u8,
mi_height_log2: crate::cdf::mi_height_log2(bw8x8) as u8,
avail_u: true,
avail_l: true,
plane_residual_size_ge_block_8x8: true,
above_neighbours: &above_nb,
left_neighbours: &left_nb,
};
let mut oracle = curr_simple.clone();
reconstruct_inter_block_obmc(
InterModeInfo {
ref_frame: last,
mv: [2, 6],
},
&obmc_params,
&ref_frame_idx,
&store,
0,
8,
8,
8,
8,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&mut oracle,
curr_w,
)
.expect("per-block OBMC oracle");
assert_eq!(
curr_obmc, oracle,
"OBMC frame-walk dispatch must equal the hand-resolved per-block OBMC oracle"
);
let mut obmc_differs = false;
for r in 8..16 {
for c in 8..16 {
if curr_obmc[r * curr_w + c] != curr_simple[r * curr_w + c] {
obmc_differs = true;
}
}
}
assert!(
obmc_differs,
"OBMC leaf must differ from the translational fallback"
);
for r in 0..16 {
for c in 0..16 {
if (8..16).contains(&r) && (8..16).contains(&c) {
continue;
}
assert_eq!(
curr_obmc[r * curr_w + c],
curr_simple[r * curr_w + c],
"non-OBMC leaf sample ({c},{r}) must be identical regardless of OBMC ctx"
);
}
}
}
#[test]
fn r378_reconstruct_inter_frame_obmc_ctx_slice_guards() {
let refp = vec![5u16; 32 * 32];
let entry = RefFrameStoreEntry {
plane: &refp[..],
stride: 32,
upscaled_width: 32,
width: 32,
height: 32,
};
let store = [entry; 8];
let ref_frame_idx = [0u8; 7];
let mi_rows: u32 = 2;
let mi_cols: u32 = 2;
let cells = (mi_rows * mi_cols) as usize;
let mi_sizes = vec![crate::cdf::BLOCK_INVALID; cells];
let is_inters = vec![0u8; cells];
let mut ref_frames = vec![0i8; cells * 2];
for cell in 0..cells {
ref_frames[cell * 2 + 1] = -1;
}
let mvs = vec![0i16; cells * 4];
let interp_filters = vec![EIGHTTAP; cells * 2];
let zeros = vec![0u8; cells];
let order_hints_by_ref = [0i32; 8];
let full = vec![0u8; cells];
let short = vec![0u8; cells - 1];
let grid = InterModeInfoGrid {
mi_sizes: &mi_sizes,
is_inters: &is_inters,
ref_frames: &ref_frames,
mvs: &mvs,
interp_filters: &interp_filters,
compound_types: &zeros,
wedge_indices: &zeros,
wedge_signs: &zeros,
mask_types: &zeros,
interintra_modes: &zeros,
wedge_interintras: &zeros,
interintra_wedge_indices: &zeros,
order_hint_bits: 7,
current_order_hint: 0,
order_hints_by_ref: &order_hints_by_ref,
mi_rows,
mi_cols,
bit_depth: 8,
warp: None,
obmc: Some(GridObmcContext {
motion_modes: &full,
avail_u: &short,
avail_l: &full,
}),
};
let mut curr = vec![0u16; 64];
let mut planes = [PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: 32,
frame_height: 32,
curr: &mut curr,
curr_stride: 8,
}];
assert_eq!(
reconstruct_inter_frame(&grid, &ref_frame_idx, &mut planes).unwrap_err(),
crate::Error::PartitionWalkOutOfRange
);
}
#[test]
fn r378_reconstruct_inter_frame_obmc_top_left_leaf_equals_simple() {
let ref_w = 32usize;
let ref_h = 32usize;
let mut refp = vec![0u16; ref_w * ref_h];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * ref_w + c] = ((r * 9 + c * 3) & 0xff) as u16;
}
}
let entry = RefFrameStoreEntry {
plane: &refp[..],
stride: ref_w,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let store = [entry; 8];
let ref_frame_idx = [0u8; 7];
let last = crate::uncompressed_header_tail::LAST_FRAME as u8;
let mi_rows: u32 = 2;
let mi_cols: u32 = 2;
let cells = (mi_rows * mi_cols) as usize;
let bw8x8 = crate::cdf::BLOCK_8X8;
let mut mi_sizes = vec![crate::cdf::BLOCK_INVALID; cells];
let mut is_inters = vec![0u8; cells];
let mut ref_frames = vec![0i8; cells * 2];
let mut mvs = vec![0i16; cells * 4];
let interp_filters = vec![EIGHTTAP; cells * 2];
for cell in 0..cells {
mi_sizes[cell] = bw8x8;
is_inters[cell] = 1;
ref_frames[cell * 2] = last as i8;
ref_frames[cell * 2 + 1] = -1;
mvs[cell * 4] = 2;
mvs[cell * 4 + 1] = 6;
}
let zeros = vec![0u8; cells];
let order_hints_by_ref = [0i32; 8];
let motion_modes = vec![crate::cdf::MOTION_MODE_OBMC; cells];
let avail_u = vec![0u8; cells];
let avail_l = vec![0u8; cells];
let curr_w = 8usize;
let mut curr_obmc = vec![0u16; curr_w * curr_w];
let mut curr_simple = vec![0u16; curr_w * curr_w];
macro_rules! grid {
($obmc:expr) => {
InterModeInfoGrid {
mi_sizes: &mi_sizes,
is_inters: &is_inters,
ref_frames: &ref_frames,
mvs: &mvs,
interp_filters: &interp_filters,
compound_types: &zeros,
wedge_indices: &zeros,
wedge_signs: &zeros,
mask_types: &zeros,
interintra_modes: &zeros,
wedge_interintras: &zeros,
interintra_wedge_indices: &zeros,
order_hint_bits: 7,
current_order_hint: 0,
order_hints_by_ref: &order_hints_by_ref,
mi_rows,
mi_cols,
bit_depth: 8,
warp: None,
obmc: $obmc,
}
};
}
{
let g = grid!(Some(GridObmcContext {
motion_modes: &motion_modes,
avail_u: &avail_u,
avail_l: &avail_l,
}));
let mut planes = [PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut curr_obmc,
curr_stride: curr_w,
}];
reconstruct_inter_frame(&g, &ref_frame_idx, &mut planes).expect("OBMC top-left walk");
}
{
let g = grid!(None);
let mut planes = [PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut curr_simple,
curr_stride: curr_w,
}];
reconstruct_inter_frame(&g, &ref_frame_idx, &mut planes).expect("SIMPLE walk");
}
assert_eq!(
curr_obmc, curr_simple,
"a top-left OBMC leaf has no §7.11.3.9 neighbour ⇒ the blend is a \
no-op ⇒ identical to the SIMPLE translational prediction"
);
assert!(curr_obmc.iter().any(|&s| s != 0));
}
#[test]
fn r378_reconstruct_inter_frame_obmc_dispatch_multiplane_420() {
let ref_w = 32usize;
let ref_h = 32usize;
let mut refp = vec![0u16; ref_w * ref_h];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * ref_w + c] = ((r * 32 + c) & 0xff) as u16;
}
}
let entry = RefFrameStoreEntry {
plane: &refp[..],
stride: ref_w,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let store = [entry; 8];
let ref_frame_idx = [0u8; 7];
let last = crate::uncompressed_header_tail::LAST_FRAME as u8;
let mi_rows: u32 = 4;
let mi_cols: u32 = 4;
let cells = (mi_rows * mi_cols) as usize;
let bw8x8 = crate::cdf::BLOCK_8X8;
let mut mi_sizes = vec![crate::cdf::BLOCK_INVALID; cells];
let mut is_inters = vec![0u8; cells];
let mut ref_frames = vec![0i8; cells * 2];
let mut mvs = vec![0i16; cells * 4];
let interp_filters = vec![EIGHTTAP; cells * 2];
let stamp = |mi_sizes: &mut [usize],
is_inters: &mut [u8],
ref_frames: &mut [i8],
mvs: &mut [i16],
r0: usize,
c0: usize,
mv: [i16; 2]| {
for dr in 0..2 {
for dc in 0..2 {
let cell = (r0 + dr) * mi_cols as usize + (c0 + dc);
mi_sizes[cell] = bw8x8;
is_inters[cell] = 1;
ref_frames[cell * 2] = last as i8;
ref_frames[cell * 2 + 1] = -1;
mvs[cell * 4] = mv[0];
mvs[cell * 4 + 1] = mv[1];
}
}
};
stamp(
&mut mi_sizes,
&mut is_inters,
&mut ref_frames,
&mut mvs,
0,
2,
[0, 8],
);
stamp(
&mut mi_sizes,
&mut is_inters,
&mut ref_frames,
&mut mvs,
2,
0,
[8, 0],
);
stamp(
&mut mi_sizes,
&mut is_inters,
&mut ref_frames,
&mut mvs,
0,
0,
[4, 4],
);
stamp(
&mut mi_sizes,
&mut is_inters,
&mut ref_frames,
&mut mvs,
2,
2,
[2, 6],
);
let zeros = vec![0u8; cells];
let order_hints_by_ref = [0i32; 8];
let mut motion_modes = vec![crate::cdf::MOTION_MODE_SIMPLE; cells];
motion_modes[2 * mi_cols as usize + 2] = crate::cdf::MOTION_MODE_OBMC;
let mut avail_u = vec![0u8; cells];
let mut avail_l = vec![0u8; cells];
for r in 0..mi_rows as usize {
for c in 0..mi_cols as usize {
avail_u[r * mi_cols as usize + c] = (r > 0) as u8;
avail_l[r * mi_cols as usize + c] = (c > 0) as u8;
}
}
let luma_w = 16usize;
let chroma_w = 8usize;
let mut y = vec![0u16; luma_w * luma_w];
let mut u = vec![0u16; chroma_w * chroma_w];
let mut v = vec![0u16; chroma_w * chroma_w];
let mut y_or = vec![0u16; luma_w * luma_w];
let mut u_or = vec![0u16; chroma_w * chroma_w];
let mut v_or = vec![0u16; chroma_w * chroma_w];
let grid = InterModeInfoGrid {
mi_sizes: &mi_sizes,
is_inters: &is_inters,
ref_frames: &ref_frames,
mvs: &mvs,
interp_filters: &interp_filters,
compound_types: &zeros,
wedge_indices: &zeros,
wedge_signs: &zeros,
mask_types: &zeros,
interintra_modes: &zeros,
wedge_interintras: &zeros,
interintra_wedge_indices: &zeros,
order_hint_bits: 7,
current_order_hint: 0,
order_hints_by_ref: &order_hints_by_ref,
mi_rows,
mi_cols,
bit_depth: 8,
warp: None,
obmc: Some(GridObmcContext {
motion_modes: &motion_modes,
avail_u: &avail_u,
avail_l: &avail_l,
}),
};
{
let mut planes = [
PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut y,
curr_stride: luma_w,
},
PlaneReconContext {
plane: 1,
subsampling_x: 1,
subsampling_y: 1,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut u,
curr_stride: chroma_w,
},
PlaneReconContext {
plane: 2,
subsampling_x: 1,
subsampling_y: 1,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut v,
curr_stride: chroma_w,
},
];
reconstruct_inter_frame(&grid, &ref_frame_idx, &mut planes)
.expect("multiplane OBMC frame walk");
}
{
let grid_simple = InterModeInfoGrid {
mi_sizes: &mi_sizes,
is_inters: &is_inters,
ref_frames: &ref_frames,
mvs: &mvs,
interp_filters: &interp_filters,
compound_types: &zeros,
wedge_indices: &zeros,
wedge_signs: &zeros,
mask_types: &zeros,
interintra_modes: &zeros,
wedge_interintras: &zeros,
interintra_wedge_indices: &zeros,
order_hint_bits: 7,
current_order_hint: 0,
order_hints_by_ref: &order_hints_by_ref,
mi_rows,
mi_cols,
bit_depth: 8,
warp: None,
obmc: None,
};
let mut planes = [
PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut y_or,
curr_stride: luma_w,
},
PlaneReconContext {
plane: 1,
subsampling_x: 1,
subsampling_y: 1,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut u_or,
curr_stride: chroma_w,
},
PlaneReconContext {
plane: 2,
subsampling_x: 1,
subsampling_y: 1,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut v_or,
curr_stride: chroma_w,
},
];
reconstruct_inter_frame(&grid_simple, &ref_frame_idx, &mut planes)
.expect("simple oracle walk");
}
let above_mv = [
mvs[(mi_cols as usize + 3) * 4],
mvs[(mi_cols as usize + 3) * 4 + 1],
];
let left_mv = [
mvs[(3 * mi_cols as usize + 1) * 4],
mvs[(3 * mi_cols as usize + 1) * 4 + 1],
];
let nb = |mv: [i16; 2]| PredictInterRef {
ref_plane: &refp[..],
ref_stride: ref_w,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv,
};
for (plane, (orc, cstride)) in [
(&mut y_or, luma_w),
(&mut u_or, chroma_w),
(&mut v_or, chroma_w),
]
.into_iter()
.enumerate()
{
let sub = if plane > 0 { 1u8 } else { 0 };
let above_gate = sub == 0; let above_nb = [ObmcNeighbour {
bundle: nb(above_mv),
step4: 2,
interp_filter_x: EIGHTTAP,
interp_filter_y: EIGHTTAP,
axis_pos4: 2,
}];
let left_nb = [ObmcNeighbour {
bundle: nb(left_mv),
step4: 2,
interp_filter_x: EIGHTTAP,
interp_filter_y: EIGHTTAP,
axis_pos4: 2,
}];
let op = ObmcParams {
mi_row: 2,
mi_col: 2,
mi_cols,
mi_rows,
mi_width_log2: crate::cdf::mi_width_log2(bw8x8) as u8,
mi_height_log2: crate::cdf::mi_height_log2(bw8x8) as u8,
avail_u: true,
avail_l: true,
plane_residual_size_ge_block_8x8: above_gate,
above_neighbours: if above_gate { &above_nb } else { &[] },
left_neighbours: &left_nb,
};
let w = 8usize >> sub;
let h = 8usize >> sub;
let x = 8i32 >> sub;
let yy = 8i32 >> sub;
reconstruct_inter_block_obmc(
InterModeInfo {
ref_frame: last,
mv: [2, 6],
},
&op,
&ref_frame_idx,
&store,
plane as u8,
x,
yy,
w,
h,
8,
sub,
sub,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
orc.as_mut_slice(),
cstride,
)
.expect("per-block OBMC oracle plane");
}
assert_eq!(y, y_or, "luma OBMC frame walk vs per-block oracle");
assert_eq!(u, u_or, "Cb OBMC frame walk vs per-block oracle");
assert_eq!(v, v_or, "Cr OBMC frame walk vs per-block oracle");
}
fn r294_ref_plane(ref_w: usize, ref_h: usize) -> Vec<u16> {
let mut refp = vec![0u16; ref_w * ref_h];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * ref_w + c] = (r * 16 + c) as u16;
}
}
refp
}
#[test]
fn r294_reconstruct_inter_block_compound_average_matches_predict_inter() {
let ref_w = 16usize;
let ref_h = 16usize;
let stride = ref_w;
let refp = r294_ref_plane(ref_w, ref_h);
let decoy = vec![0u16; ref_w * ref_h];
let real = RefFrameStoreEntry {
plane: &refp[..],
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let dec = RefFrameStoreEntry {
plane: &decoy[..],
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let store = [dec, dec, real, dec];
let ref_frame_idx: [u8; 7] = [2, 0, 1, 3, 0, 1, 2];
let last = crate::uncompressed_header_tail::LAST_FRAME as u8;
let altref = crate::uncompressed_header_tail::ALTREF_FRAME as u8;
let w = 4;
let h = 4;
let mode_info = CompoundInterModeInfo {
ref_frame_0: last,
ref_frame_1: altref,
mv0: [0, 4],
mv1: [8, 0],
compound_type: COMPOUND_AVERAGE,
wedge: None,
mask_type: 0,
};
let curr_w = 8;
let curr_h = 8;
let sentinel = 6000u16;
let mut curr = vec![sentinel; curr_w * curr_h];
reconstruct_inter_block_compound(
mode_info,
CompoundOrderHintContext {
order_hint_bits: 7,
current_order_hint: 0,
order_hint_ref0: 0,
order_hint_ref1: 0,
},
&ref_frame_idx,
&store,
0,
2,
2,
w,
h,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
None,
None,
&mut curr,
curr_w,
)
.expect("compound AVERAGE block driver");
let refs = [
PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 4],
},
PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [8, 0],
},
];
let mut expected = vec![0u16; w * h];
predict_inter(
0,
2,
2,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
true,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
Some(CompoundParams::Average),
None,
None,
None,
&mut expected,
)
.unwrap();
for i in 0..h {
for j in 0..w {
assert_eq!(
curr[(2 + i) * curr_w + (2 + j)],
expected[i * w + j],
"compound AVERAGE stitch mismatch at ({j}, {i})"
);
}
}
assert_eq!(curr[0], sentinel);
assert_eq!(curr[curr_w * curr_h - 1], sentinel);
}
#[test]
fn r294_reconstruct_inter_block_compound_distance_derives_weights() {
let ref_w = 16usize;
let ref_h = 16usize;
let stride = ref_w;
let refp = r294_ref_plane(ref_w, ref_h);
let real = RefFrameStoreEntry {
plane: &refp[..],
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let store = [real, real];
let ref_frame_idx: [u8; 7] = [0, 1, 0, 0, 0, 0, 0];
let last = crate::uncompressed_header_tail::LAST_FRAME as u8;
let ref1 = last + 1;
let ohc = CompoundOrderHintContext {
order_hint_bits: 7,
current_order_hint: 8,
order_hint_ref0: 4, order_hint_ref1: 2, };
let weights = distance_weights(
ohc.order_hint_bits,
ohc.current_order_hint,
ohc.order_hint_ref0,
ohc.order_hint_ref1,
);
assert_ne!(
weights.fwd_weight, weights.bck_weight,
"test premise: order hints chosen for asymmetric weights"
);
let w = 4;
let h = 4;
let mut curr = vec![0u16; w * h];
reconstruct_inter_block_compound(
CompoundInterModeInfo {
ref_frame_0: last,
ref_frame_1: ref1,
mv0: [0, 4],
mv1: [8, 0],
compound_type: COMPOUND_DISTANCE,
wedge: None,
mask_type: 0,
},
ohc,
&ref_frame_idx,
&store,
0,
0,
0,
w,
h,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
None,
None,
&mut curr,
w,
)
.expect("compound DISTANCE block driver");
let refs = [
PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 4],
},
PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [8, 0],
},
];
let mut expected = vec![0u16; w * h];
predict_inter(
0,
0,
0,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
true,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
Some(CompoundParams::Distance(weights)),
None,
None,
None,
&mut expected,
)
.unwrap();
assert_eq!(
curr, expected,
"compound DISTANCE driver must derive the same weights and blend"
);
}
#[test]
fn r294_reconstruct_inter_block_compound_rejects_caller_bugs() {
let ref_w = 16usize;
let ref_h = 16usize;
let refp = r294_ref_plane(ref_w, ref_h);
let entry = RefFrameStoreEntry {
plane: &refp[..],
stride: ref_w,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let store = [entry, entry];
let ref_frame_idx: [u8; 7] = [0, 1, 0, 0, 0, 0, 0];
let last = crate::uncompressed_header_tail::LAST_FRAME as u8;
let ohc = CompoundOrderHintContext {
order_hint_bits: 7,
current_order_hint: 0,
order_hint_ref0: 0,
order_hint_ref1: 0,
};
let w = 4;
let h = 4;
let mk = |rf0: u8, rf1: u8, ct: u8, curr: &mut [u16], stride: usize| {
reconstruct_inter_block_compound(
CompoundInterModeInfo {
ref_frame_0: rf0,
ref_frame_1: rf1,
mv0: [0, 0],
mv1: [0, 0],
compound_type: ct,
wedge: None,
mask_type: 0,
},
ohc,
&ref_frame_idx,
&store,
0,
0,
0,
w,
h,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
None,
None,
curr,
stride,
)
};
let mut curr = vec![0u16; w * h];
assert_eq!(
mk(last, last + 1, COMPOUND_WEDGE, &mut curr, w).unwrap_err(),
crate::Error::PartitionWalkOutOfRange
);
assert_eq!(
mk(last, last + 1, COMPOUND_DIFFWTD, &mut curr, w).unwrap_err(),
crate::Error::PartitionWalkOutOfRange
);
assert_eq!(
mk(0, last + 1, COMPOUND_AVERAGE, &mut curr, w).unwrap_err(),
crate::Error::PartitionWalkOutOfRange
);
assert_eq!(
mk(last, 0, COMPOUND_AVERAGE, &mut curr, w).unwrap_err(),
crate::Error::PartitionWalkOutOfRange
);
assert_eq!(
mk(last, 99, COMPOUND_AVERAGE, &mut curr, w).unwrap_err(),
crate::Error::PartitionWalkOutOfRange
);
let mut tiny = vec![0u16; w * h - 1];
mk(last, last + 1, COMPOUND_AVERAGE, &mut tiny, w)
.expect("overhanging compound write clips instead of erroring");
}
#[test]
fn r294_reconstruct_inter_frame_drives_average_and_distance_compound() {
let ref_w = 16usize;
let ref_h = 16usize;
let stride = ref_w;
let refp = r294_ref_plane(ref_w, ref_h);
let real = RefFrameStoreEntry {
plane: &refp[..],
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let store = [real, real, real, real];
let store2 = store;
let ref_frame_idx: [u8; 7] = [0, 1, 2, 3, 0, 1, 2];
let last = crate::uncompressed_header_tail::LAST_FRAME as i8;
let mi_rows: u32 = 1;
let mi_cols: u32 = 4;
let cells = (mi_rows * mi_cols) as usize;
use crate::cdf::{BLOCK_4X4, BLOCK_INVALID};
let mut mi_sizes = vec![BLOCK_INVALID; cells];
let mut is_inters = vec![0u8; cells];
let mut ref_frames = vec![0i8; cells * 2];
for cell in 0..cells {
ref_frames[cell * 2 + 1] = -1;
}
let mut mvs = vec![0i16; cells * 4];
let interp_filters = vec![EIGHTTAP; cells * 2];
let mut compound_types = vec![COMPOUND_AVERAGE; cells];
for sz in mi_sizes.iter_mut() {
*sz = BLOCK_4X4;
}
let mut stamp = |c: usize, rf1: i8, ct: u8, mv0: [i16; 2], mv1: [i16; 2]| {
is_inters[c] = 1;
ref_frames[c * 2] = last;
ref_frames[c * 2 + 1] = rf1;
mvs[c * 4] = mv0[0];
mvs[c * 4 + 1] = mv0[1];
mvs[c * 4 + 2] = mv1[0];
mvs[c * 4 + 3] = mv1[1];
compound_types[c] = ct;
};
stamp(0, last + 1, COMPOUND_AVERAGE, [0, 4], [8, 0]);
stamp(1, last + 2, COMPOUND_DISTANCE, [4, 0], [0, 8]);
stamp(2, last + 1, COMPOUND_INTRA, [0, 4], [8, 0]);
is_inters[3] = 0;
let mut order_hints_by_ref = [0i32; 8];
order_hints_by_ref[last as usize] = 4; order_hints_by_ref[(last + 1) as usize] = 6;
order_hints_by_ref[(last + 2) as usize] = 2;
let current_order_hint = 8;
let curr_w = (mi_cols * 4) as usize; let curr_h = 4usize;
let sentinel = 5000u16;
let mut curr = vec![sentinel; curr_w * curr_h];
let wedge_zeros = vec![0u8; cells];
let grid = InterModeInfoGrid {
mi_sizes: &mi_sizes,
is_inters: &is_inters,
ref_frames: &ref_frames,
mvs: &mvs,
interp_filters: &interp_filters,
compound_types: &compound_types,
wedge_indices: &wedge_zeros,
wedge_signs: &wedge_zeros,
mask_types: &wedge_zeros,
interintra_modes: &wedge_zeros,
wedge_interintras: &wedge_zeros,
interintra_wedge_indices: &wedge_zeros,
order_hint_bits: 7,
current_order_hint,
order_hints_by_ref: &order_hints_by_ref,
mi_rows,
mi_cols,
bit_depth: 8,
warp: None,
obmc: None,
};
{
let mut planes = [PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut curr,
curr_stride: curr_w,
}];
reconstruct_inter_frame(&grid, &ref_frame_idx, &mut planes)
.expect("frame-level compound reconstruction");
}
let mut oracle = vec![sentinel; curr_w * curr_h];
reconstruct_inter_block_compound(
CompoundInterModeInfo {
ref_frame_0: last as u8,
ref_frame_1: (last + 1) as u8,
mv0: [0, 4],
mv1: [8, 0],
compound_type: COMPOUND_AVERAGE,
wedge: None,
mask_type: 0,
},
CompoundOrderHintContext {
order_hint_bits: 7,
current_order_hint,
order_hint_ref0: order_hints_by_ref[last as usize],
order_hint_ref1: order_hints_by_ref[(last + 1) as usize],
},
&ref_frame_idx,
&store2,
0,
0,
0,
4,
4,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
None,
None,
&mut oracle,
curr_w,
)
.unwrap();
reconstruct_inter_block_compound(
CompoundInterModeInfo {
ref_frame_0: last as u8,
ref_frame_1: (last + 2) as u8,
mv0: [4, 0],
mv1: [0, 8],
compound_type: COMPOUND_DISTANCE,
wedge: None,
mask_type: 0,
},
CompoundOrderHintContext {
order_hint_bits: 7,
current_order_hint,
order_hint_ref0: order_hints_by_ref[last as usize],
order_hint_ref1: order_hints_by_ref[(last + 2) as usize],
},
&ref_frame_idx,
&store2,
0,
4,
0,
4,
4,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
None,
None,
&mut oracle,
curr_w,
)
.unwrap();
assert_eq!(
curr, oracle,
"frame walk must dispatch compound leaves identically to the per-block driver"
);
for c in 8..16 {
for r in 0..curr_h {
assert_eq!(
curr[r * curr_w + c],
sentinel,
"skipped compound/inter-intra sample ({c}, {r}) must stay sentinel"
);
}
}
assert_ne!(curr[0], sentinel, "AVERAGE leaf reconstructed");
assert_ne!(curr[4], sentinel, "DISTANCE leaf reconstructed");
}
#[test]
fn r295_reconstruct_inter_block_compound_wedge_matches_predict_inter() {
const BLOCK_8X8: usize = 3;
let ref_w = 24usize;
let ref_h = 24usize;
let stride = ref_w;
let refp = r294_ref_plane(ref_w, ref_h);
let real = RefFrameStoreEntry {
plane: &refp[..],
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let store = [real, real, real, real];
let ref_frame_idx: [u8; 7] = [0, 1, 2, 3, 0, 1, 2];
let last = crate::uncompressed_header_tail::LAST_FRAME as u8;
let ohc = CompoundOrderHintContext {
order_hint_bits: 7,
current_order_hint: 0,
order_hint_ref0: 0,
order_hint_ref1: 0,
};
let wedge_index = 5u8;
let wedge_sign = 1u8;
let mode_info = CompoundInterModeInfo {
ref_frame_0: last,
ref_frame_1: last + 1,
mv0: [0, 4],
mv1: [8, 0],
compound_type: COMPOUND_WEDGE,
wedge: Some(WedgeModeInfo {
mi_size: BLOCK_8X8,
wedge_index,
wedge_sign,
}),
mask_type: 0,
};
let luma_w = crate::cdf::block_width(BLOCK_8X8);
let luma_h = crate::cdf::block_height(BLOCK_8X8);
let mut mask = vec![0u8; luma_w * luma_h];
wedge_mask(
BLOCK_8X8,
crate::cdf::num_4x4_blocks_wide(BLOCK_8X8) as u32,
crate::cdf::num_4x4_blocks_high(BLOCK_8X8) as u32,
wedge_index,
wedge_sign,
&mut mask,
)
.unwrap();
assert!(
mask.iter().any(|&m| m != mask[0]),
"test premise: wedge mask must be non-constant"
);
let drive = |plane: u8, sub_x: u8, sub_y: u8, x: i32, y: i32, w: usize, h: usize| {
let curr_w = ref_w;
let curr_h = ref_h;
let mut got = vec![0u16; curr_w * curr_h];
reconstruct_inter_block_compound(
mode_info,
ohc,
&ref_frame_idx,
&store,
plane,
x,
y,
w,
h,
8,
sub_x,
sub_y,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
None,
None,
&mut got,
curr_w,
)
.expect("WEDGE block driver");
let refs = [
PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 4],
},
PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [8, 0],
},
];
let mut pred = vec![0u16; w * h];
predict_inter(
plane,
x,
y,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
true,
false,
8,
sub_x,
sub_y,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
Some(CompoundParams::Wedge {
mask: &mask,
mask_stride: luma_w,
}),
None,
None,
None,
&mut pred,
)
.expect("WEDGE oracle predict_inter");
for i in 0..h {
for j in 0..w {
let dst = (y as usize + i) * curr_w + (x as usize + j);
assert_eq!(
got[dst],
pred[i * w + j],
"WEDGE mismatch plane={plane} at ({j},{i})"
);
}
}
};
drive(0, 0, 0, 0, 0, luma_w, luma_h);
drive(1, 1, 1, 0, 0, luma_w / 2, luma_h / 2);
}
#[test]
fn r295_reconstruct_inter_frame_drives_wedge_compound() {
const BLOCK_8X8: usize = 3;
let ref_w = 16usize;
let ref_h = 16usize;
let stride = ref_w;
let refp = r294_ref_plane(ref_w, ref_h);
let real = RefFrameStoreEntry {
plane: &refp[..],
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let store = [real, real, real, real];
let store2 = store;
let ref_frame_idx: [u8; 7] = [0, 1, 2, 3, 0, 1, 2];
let last = crate::uncompressed_header_tail::LAST_FRAME as i8;
let mi_rows: u32 = 2;
let mi_cols: u32 = 2;
let cells = (mi_rows * mi_cols) as usize;
use crate::cdf::BLOCK_INVALID;
let mut mi_sizes = vec![BLOCK_INVALID; cells];
mi_sizes[0] = BLOCK_8X8; let mut is_inters = vec![0u8; cells];
is_inters[0] = 1;
let mut ref_frames = vec![0i8; cells * 2];
for cell in 0..cells {
ref_frames[cell * 2 + 1] = -1;
}
ref_frames[0] = last; ref_frames[1] = last + 1; let mut mvs = vec![0i16; cells * 4];
mvs[0] = 0;
mvs[1] = 4;
mvs[2] = 8;
mvs[3] = 0;
let interp_filters = vec![EIGHTTAP; cells * 2];
let mut compound_types = vec![COMPOUND_AVERAGE; cells];
compound_types[0] = COMPOUND_WEDGE;
let wedge_index = 7u8;
let wedge_sign = 0u8;
let mut wedge_indices = vec![0u8; cells];
wedge_indices[0] = wedge_index;
let mut wedge_signs = vec![0u8; cells];
wedge_signs[0] = wedge_sign;
let mask_types = vec![0u8; cells];
let zeros_ii = vec![0u8; cells];
let order_hints_by_ref = [0i32; 8];
let curr_w = (mi_cols * 4) as usize; let curr_h = (mi_rows * 4) as usize; let sentinel = 5000u16;
let mut curr = vec![sentinel; curr_w * curr_h];
let grid = InterModeInfoGrid {
mi_sizes: &mi_sizes,
is_inters: &is_inters,
ref_frames: &ref_frames,
mvs: &mvs,
interp_filters: &interp_filters,
compound_types: &compound_types,
wedge_indices: &wedge_indices,
wedge_signs: &wedge_signs,
mask_types: &mask_types,
interintra_modes: &zeros_ii,
wedge_interintras: &zeros_ii,
interintra_wedge_indices: &zeros_ii,
order_hint_bits: 7,
current_order_hint: 0,
order_hints_by_ref: &order_hints_by_ref,
mi_rows,
mi_cols,
bit_depth: 8,
warp: None,
obmc: None,
};
{
let mut planes = [PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut curr,
curr_stride: curr_w,
}];
reconstruct_inter_frame(&grid, &ref_frame_idx, &mut planes)
.expect("frame-level WEDGE reconstruction");
}
let mut oracle = vec![sentinel; curr_w * curr_h];
reconstruct_inter_block_compound(
CompoundInterModeInfo {
ref_frame_0: last as u8,
ref_frame_1: (last + 1) as u8,
mv0: [0, 4],
mv1: [8, 0],
compound_type: COMPOUND_WEDGE,
wedge: Some(WedgeModeInfo {
mi_size: BLOCK_8X8,
wedge_index,
wedge_sign,
}),
mask_type: 0,
},
CompoundOrderHintContext {
order_hint_bits: 7,
current_order_hint: 0,
order_hint_ref0: 0,
order_hint_ref1: 0,
},
&ref_frame_idx,
&store2,
0,
0,
0,
8,
8,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
None,
None,
&mut oracle,
curr_w,
)
.unwrap();
assert_eq!(
curr, oracle,
"frame walk must drive the WEDGE leaf identically to the per-block driver"
);
assert!(
curr.iter().all(|&s| s != sentinel),
"all WEDGE samples reconstructed"
);
}
#[test]
fn r296_reconstruct_inter_frame_drives_diffwtd_compound() {
const BLOCK_8X8: usize = 3;
let ref_w = 16usize;
let ref_h = 16usize;
let stride = ref_w;
let refp = r294_ref_plane(ref_w, ref_h);
let real = RefFrameStoreEntry {
plane: &refp[..],
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let store = [real, real, real, real];
let store2 = store;
let ref_frame_idx: [u8; 7] = [0, 1, 2, 3, 0, 1, 2];
let last = crate::uncompressed_header_tail::LAST_FRAME as i8;
let mi_rows: u32 = 2;
let mi_cols: u32 = 2;
let cells = (mi_rows * mi_cols) as usize;
use crate::cdf::BLOCK_INVALID;
let mut mi_sizes = vec![BLOCK_INVALID; cells];
mi_sizes[0] = BLOCK_8X8;
let mut is_inters = vec![0u8; cells];
is_inters[0] = 1;
let mut ref_frames = vec![0i8; cells * 2];
for cell in 0..cells {
ref_frames[cell * 2 + 1] = -1;
}
ref_frames[0] = last;
ref_frames[1] = last + 1;
let mv0 = [0i16, 4];
let mv1 = [8i16, 0];
let mut mvs = vec![0i16; cells * 4];
mvs[0] = mv0[0];
mvs[1] = mv0[1];
mvs[2] = mv1[0];
mvs[3] = mv1[1];
let interp_filters = vec![EIGHTTAP; cells * 2];
let mut compound_types = vec![COMPOUND_AVERAGE; cells];
compound_types[0] = COMPOUND_DIFFWTD;
let mask_type = 1u8; let mut mask_types = vec![0u8; cells];
mask_types[0] = mask_type;
let zeros = vec![0u8; cells];
let zeros_ii = vec![0u8; cells];
let order_hints_by_ref = [0i32; 8];
let curr_w = (mi_cols * 4) as usize; let curr_h = (mi_rows * 4) as usize; let sentinel = 5000u16;
let mut curr = vec![sentinel; curr_w * curr_h];
let grid = InterModeInfoGrid {
mi_sizes: &mi_sizes,
is_inters: &is_inters,
ref_frames: &ref_frames,
mvs: &mvs,
interp_filters: &interp_filters,
compound_types: &compound_types,
wedge_indices: &zeros,
wedge_signs: &zeros,
mask_types: &mask_types,
interintra_modes: &zeros_ii,
wedge_interintras: &zeros_ii,
interintra_wedge_indices: &zeros_ii,
order_hint_bits: 7,
current_order_hint: 0,
order_hints_by_ref: &order_hints_by_ref,
mi_rows,
mi_cols,
bit_depth: 8,
warp: None,
obmc: None,
};
{
let mut planes = [PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut curr,
curr_stride: curr_w,
}];
reconstruct_inter_frame(&grid, &ref_frame_idx, &mut planes)
.expect("frame-level DIFFWTD reconstruction");
}
let mut oracle = vec![sentinel; curr_w * curr_h];
let mut oracle_mask = vec![0u8; 8 * 8];
reconstruct_inter_block_compound(
CompoundInterModeInfo {
ref_frame_0: last as u8,
ref_frame_1: (last + 1) as u8,
mv0,
mv1,
compound_type: COMPOUND_DIFFWTD,
wedge: None,
mask_type,
},
CompoundOrderHintContext {
order_hint_bits: 7,
current_order_hint: 0,
order_hint_ref0: 0,
order_hint_ref1: 0,
},
&ref_frame_idx,
&store2,
0,
0,
0,
8,
8,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
Some(&mut oracle_mask),
None,
&mut oracle,
curr_w,
)
.unwrap();
assert_eq!(
curr, oracle,
"frame walk must drive the DIFFWTD leaf identically to the per-block driver"
);
assert!(
curr.iter().all(|&s| s != sentinel),
"all DIFFWTD samples reconstructed"
);
let mut avg = vec![sentinel; curr_w * curr_h];
reconstruct_inter_block_compound(
CompoundInterModeInfo {
ref_frame_0: last as u8,
ref_frame_1: (last + 1) as u8,
mv0,
mv1,
compound_type: COMPOUND_AVERAGE,
wedge: None,
mask_type: 0,
},
CompoundOrderHintContext {
order_hint_bits: 7,
current_order_hint: 0,
order_hint_ref0: 0,
order_hint_ref1: 0,
},
&ref_frame_idx,
&store2,
0,
0,
0,
8,
8,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
None,
None,
&mut avg,
curr_w,
)
.unwrap();
assert_ne!(
curr, avg,
"DIFFWTD mask blend must differ from a plain AVERAGE blend"
);
}
#[test]
fn r194_predict_inter_stub_arms_each_surface_dedicated_error() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let refp = vec![0u16; ref_w * ref_h];
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: ref_w,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let mut pred_out = vec![0u16; 16];
let mut pred_out_8x8 = vec![0u16; 64];
let e = predict_inter(
0,
0,
0,
8,
8,
crate::cdf::MOTION_MODE_WARPED_CAUSAL,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
None,
&mut pred_out_8x8,
)
.unwrap_err();
assert_eq!(e, crate::Error::PartitionWalkOutOfRange);
let e = predict_inter(
0,
0,
0,
4,
4,
crate::cdf::MOTION_MODE_OBMC,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
None,
&mut pred_out,
)
.unwrap_err();
assert_eq!(e, crate::Error::PartitionWalkOutOfRange);
}
#[test]
fn r194_predict_inter_rejects_caller_bugs() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let refp = vec![0u16; ref_w * ref_h];
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: ref_w,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let mut pred_out = vec![0u16; 16];
let empty_refs: [PredictInterRef<'_>; 0] = [];
let e = predict_inter(
0,
0,
0,
4,
4,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&empty_refs,
None,
None,
None,
None,
&mut pred_out,
)
.unwrap_err();
assert_eq!(e, crate::Error::PartitionWalkOutOfRange);
let mut small = vec![0u16; 8];
let e = predict_inter(
0,
0,
0,
4,
4,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
None,
&mut small,
)
.unwrap_err();
assert_eq!(e, crate::Error::PartitionWalkOutOfRange);
let e = predict_inter(
0,
0,
0,
4,
4,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
9,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
None,
&mut pred_out,
)
.unwrap_err();
assert_eq!(e, crate::Error::PartitionWalkOutOfRange);
}
#[test]
fn r201_predict_inter_compound_average_matches_hand_blend() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = (r * 16 + c) as u16;
}
}
let refs = [
PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
},
PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
},
];
let w = 4;
let h = 4;
let mut pred_out = vec![0u16; w * h];
predict_inter(
0,
2,
2,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
true,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
Some(CompoundParams::Average),
None,
None,
None,
&mut pred_out,
)
.expect("compound AVERAGE arm");
let rv = rounding_variables(8, true).unwrap();
let mvs = motion_vector_scaling(
0,
0,
0,
ref_w as u32,
ref_h as u32,
ref_w as u32,
ref_h as u32,
2,
2,
[0, 0],
)
.unwrap();
let mut leaf = vec![0i32; w * h];
block_inter_prediction(
0,
0,
0,
&refp,
stride,
ref_w as u32,
ref_h as u32,
mvs.start_x,
mvs.start_y,
mvs.step_x,
mvs.step_y,
w,
h,
EIGHTTAP,
EIGHTTAP,
rv.inter_round0,
rv.inter_round1,
&mut leaf,
)
.unwrap();
let shift: u32 = 1 + rv.inter_post_round;
let max: i32 = (1i32 << 8) - 1;
let mut expected = vec![0u16; w * h];
for i in 0..h {
for j in 0..w {
let acc = leaf[i * w + j] as i64 + leaf[i * w + j] as i64;
let r = ((acc + (1i64 << (shift - 1))) >> shift) as i32;
expected[i * w + j] = r.clamp(0, max) as u16;
}
}
assert_eq!(pred_out, expected, "AVERAGE arm pixel mismatch");
}
#[test]
fn r201_predict_inter_compound_distance_matches_hand_blend() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = ((r * 17 + c * 5) & 0xFF) as u16;
}
}
let refs = [
PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
},
PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
},
];
let weights = DistanceWeights {
fwd_weight: 9,
bck_weight: 7,
};
let w = 4;
let h = 4;
let mut pred_out = vec![0u16; w * h];
predict_inter(
0,
2,
2,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
true,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
Some(CompoundParams::Distance(weights)),
None,
None,
None,
&mut pred_out,
)
.expect("compound DISTANCE arm");
let rv = rounding_variables(8, true).unwrap();
let mvs = motion_vector_scaling(
0,
0,
0,
ref_w as u32,
ref_h as u32,
ref_w as u32,
ref_h as u32,
2,
2,
[0, 0],
)
.unwrap();
let mut leaf = vec![0i32; w * h];
block_inter_prediction(
0,
0,
0,
&refp,
stride,
ref_w as u32,
ref_h as u32,
mvs.start_x,
mvs.start_y,
mvs.step_x,
mvs.step_y,
w,
h,
EIGHTTAP,
EIGHTTAP,
rv.inter_round0,
rv.inter_round1,
&mut leaf,
)
.unwrap();
let mut expected = vec![0u16; w * h];
compound_distance_blend(
8,
rv.inter_post_round,
weights,
&leaf,
&leaf,
w,
h,
&mut expected,
)
.unwrap();
assert_eq!(pred_out, expected, "DISTANCE arm pixel mismatch");
}
#[test]
fn r201_predict_inter_compound_wedge_routes_to_mask_blend() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = ((r + c) & 0xFF) as u16;
}
}
let refs = [
PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
},
PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
},
];
let w = 8;
let h = 8;
let mut mask = vec![0u8; w * h];
wedge_mask(3, 2, 2, 0, 0, &mut mask).unwrap();
let mut pred_out = vec![0u16; w * h];
predict_inter(
0,
0,
0,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
true,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
Some(CompoundParams::Wedge {
mask: &mask,
mask_stride: 0,
}),
None,
None,
None,
&mut pred_out,
)
.expect("compound WEDGE arm");
let rv = rounding_variables(8, true).unwrap();
let mvs = motion_vector_scaling(
0,
0,
0,
ref_w as u32,
ref_h as u32,
ref_w as u32,
ref_h as u32,
0,
0,
[0, 0],
)
.unwrap();
let mut leaf = vec![0i32; w * h];
block_inter_prediction(
0,
0,
0,
&refp,
stride,
ref_w as u32,
ref_h as u32,
mvs.start_x,
mvs.start_y,
mvs.step_x,
mvs.step_y,
w,
h,
EIGHTTAP,
EIGHTTAP,
rv.inter_round0,
rv.inter_round1,
&mut leaf,
)
.unwrap();
let mut expected = vec![0u16; w * h];
mask_blend(
8,
rv.inter_post_round,
0,
0,
&leaf,
&leaf,
w,
h,
&mask,
0,
&mut expected,
)
.unwrap();
assert_eq!(pred_out, expected, "WEDGE arm pixel mismatch");
}
#[test]
fn r296_predict_inter_compound_diffwtd_derives_mask_from_preds() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let stride = ref_w;
let mut refp0 = vec![0u16; ref_h * stride];
let mut refp1 = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp0[r * stride + c] = ((r * 9 + c) & 0xFF) as u16;
refp1[r * stride + c] = ((r * 3 + c * 5 + 17) & 0xFF) as u16;
}
}
let refs = [
PredictInterRef {
ref_plane: &refp0,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
},
PredictInterRef {
ref_plane: &refp1,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
},
];
let w = 8;
let h = 8;
let rv = rounding_variables(8, true).unwrap();
let mask_type = 1u8;
let mut pred_out = vec![0u16; w * h];
let mut persistent_mask = vec![0u8; w * h];
predict_inter(
0,
0,
0,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
true,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
Some(CompoundParams::Diffwtd {
mask_type,
mask: &mut persistent_mask,
}),
None,
None,
None,
&mut pred_out,
)
.expect("compound DIFFWTD arm");
let mvs = motion_vector_scaling(
0,
0,
0,
ref_w as u32,
ref_h as u32,
ref_w as u32,
ref_h as u32,
0,
0,
[0, 0],
)
.unwrap();
let leaf = |rp: &[u16]| -> Vec<i32> {
let mut out = vec![0i32; w * h];
block_inter_prediction(
0,
0,
0,
rp,
stride,
ref_w as u32,
ref_h as u32,
mvs.start_x,
mvs.start_y,
mvs.step_x,
mvs.step_y,
w,
h,
EIGHTTAP,
EIGHTTAP,
rv.inter_round0,
rv.inter_round1,
&mut out,
)
.unwrap();
out
};
let leaf0 = leaf(&refp0);
let leaf1 = leaf(&refp1);
let mut oracle_mask = vec![0u8; w * h];
difference_weight_mask(
8,
rv.inter_post_round,
mask_type,
&leaf0,
&leaf1,
w,
h,
&mut oracle_mask,
)
.unwrap();
assert_eq!(
persistent_mask, oracle_mask,
"DIFFWTD persistent mask mismatch"
);
let mut expected = vec![0u16; w * h];
mask_blend(
8,
rv.inter_post_round,
0,
0,
&leaf0,
&leaf1,
w,
h,
&oracle_mask,
0,
&mut expected,
)
.unwrap();
assert_eq!(pred_out, expected, "DIFFWTD arm pixel mismatch");
assert!(
oracle_mask.iter().any(|&m| m != oracle_mask[0]),
"DIFFWTD mask should vary across the block"
);
}
#[test]
fn r201_predict_inter_compound_intra_routes_to_mask_blend() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = ((r + c * 2) & 0xFF) as u16;
}
}
let refs = [
PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
},
PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
},
];
let w = 8;
let h = 8;
let mut mask = vec![0u8; w * h];
intra_mode_variant_mask(II_SMOOTH_PRED, w, h, &mut mask).unwrap();
let mut pred_out = vec![0u16; w * h];
predict_inter(
0,
0,
0,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
true,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
Some(CompoundParams::Intra {
mask: &mask,
mask_stride: 0,
}),
None,
None,
None,
&mut pred_out,
)
.expect("compound INTRA arm");
let rv = rounding_variables(8, true).unwrap();
let mvs = motion_vector_scaling(
0,
0,
0,
ref_w as u32,
ref_h as u32,
ref_w as u32,
ref_h as u32,
0,
0,
[0, 0],
)
.unwrap();
let mut leaf = vec![0i32; w * h];
block_inter_prediction(
0,
0,
0,
&refp,
stride,
ref_w as u32,
ref_h as u32,
mvs.start_x,
mvs.start_y,
mvs.step_x,
mvs.step_y,
w,
h,
EIGHTTAP,
EIGHTTAP,
rv.inter_round0,
rv.inter_round1,
&mut leaf,
)
.unwrap();
let mut expected = vec![0u16; w * h];
mask_blend(
8,
rv.inter_post_round,
0,
0,
&leaf,
&leaf,
w,
h,
&mask,
0,
&mut expected,
)
.unwrap();
assert_eq!(pred_out, expected, "INTRA arm pixel mismatch");
}
#[test]
fn r201_predict_inter_compound_rejects_caller_bugs() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let refp = vec![0u16; ref_w * ref_h];
let single = [PredictInterRef {
ref_plane: &refp,
ref_stride: ref_w,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let double = [single[0]; 2];
let mut pred_out = vec![0u16; 16];
let e = predict_inter(
0,
0,
0,
4,
4,
crate::cdf::MOTION_MODE_SIMPLE,
true,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&single,
Some(CompoundParams::Average),
None,
None,
None,
&mut pred_out,
)
.unwrap_err();
assert_eq!(e, crate::Error::PartitionWalkOutOfRange);
let e = predict_inter(
0,
0,
0,
4,
4,
crate::cdf::MOTION_MODE_SIMPLE,
true,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&double,
None,
None,
None,
None,
&mut pred_out,
)
.unwrap_err();
assert_eq!(e, crate::Error::PartitionWalkOutOfRange);
let e = predict_inter(
0,
0,
0,
4,
4,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&single,
Some(CompoundParams::Average),
None,
None,
None,
&mut pred_out,
)
.unwrap_err();
assert_eq!(e, crate::Error::PartitionWalkOutOfRange);
}
const WARP_IDENTITY: [i32; 6] = [0, 0, 1 << 16, 0, 0, 1 << 16];
#[test]
fn r202_predict_inter_localwarp_routes_to_block_warp() {
let ref_w: usize = 32;
let ref_h: usize = 32;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = ((r * 19 + c * 7) & 0xFF) as u16;
}
}
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let warp = WarpDriverParams {
y_mode: [crate::cdf::MODE_GLOBALMV, 0],
gm_type: [crate::cdf::GM_TYPE_IDENTITY as u8, 0],
gm_params: [WARP_IDENTITY, WARP_IDENTITY],
local_warp_params: WARP_IDENTITY,
local_valid: true,
ref_is_scaled: [false, false],
force_integer_mv: false,
};
let w = 8;
let h = 8;
let mut pred_out = vec![0u16; w * h];
predict_inter(
0,
8,
8,
w,
h,
crate::cdf::MOTION_MODE_WARPED_CAUSAL,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
Some(&warp),
None,
&mut pred_out,
)
.expect("predict_inter LOCALWARP arm");
let rv = rounding_variables(8, false).unwrap();
let mut leaf = vec![0i32; w * h];
block_warp(
USE_WARP_LOCAL,
0,
0,
0,
8,
8,
0,
0,
w,
h,
&refp,
stride,
ref_w as u32,
ref_h as u32,
WARP_IDENTITY,
rv.inter_round0,
rv.inter_round1,
w,
&mut leaf,
)
.unwrap();
let mut expected = vec![0u16; w * h];
clip1_single_ref(8, &leaf, &mut expected).unwrap();
assert_eq!(
pred_out, expected,
"LOCALWARP driver output must equal hand-composed block_warp"
);
}
#[test]
fn r202_predict_inter_global_warp_routes_to_block_warp() {
let ref_w: usize = 32;
let ref_h: usize = 32;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = ((r * 13 + c * 11) & 0xFF) as u16;
}
}
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let warp = WarpDriverParams {
y_mode: [crate::cdf::MODE_GLOBAL_GLOBALMV, 0],
gm_type: [crate::cdf::GM_TYPE_ROTZOOM as u8, 0],
gm_params: [WARP_IDENTITY, WARP_IDENTITY],
local_warp_params: WARP_IDENTITY,
local_valid: false,
ref_is_scaled: [false, false],
force_integer_mv: false,
};
let w = 8;
let h = 8;
let mut pred_out = vec![0u16; w * h];
predict_inter(
0,
8,
8,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
Some(&warp),
None,
&mut pred_out,
)
.expect("predict_inter GLOBAL_WARP arm");
let rv = rounding_variables(8, false).unwrap();
let mut leaf = vec![0i32; w * h];
block_warp(
USE_WARP_GLOBAL,
0,
0,
0,
8,
8,
0,
0,
w,
h,
&refp,
stride,
ref_w as u32,
ref_h as u32,
WARP_IDENTITY,
rv.inter_round0,
rv.inter_round1,
w,
&mut leaf,
)
.unwrap();
let mut expected = vec![0u16; w * h];
clip1_single_ref(8, &leaf, &mut expected).unwrap();
assert_eq!(
pred_out, expected,
"GLOBAL_WARP driver output must equal hand-composed block_warp"
);
}
#[test]
fn r338_reconstruct_inter_block_warp_localwarp_stitches_into_curr() {
let ref_w: usize = 32;
let ref_h: usize = 32;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = ((r * 23 + c * 5) & 0xFF) as u16;
}
}
let store = [RefFrameStoreEntry {
plane: &refp,
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
}];
let ref_frame_idx = [0u8; 7];
let warp = WarpDriverParams {
y_mode: [crate::cdf::MODE_NEWMV, 0],
gm_type: [crate::cdf::GM_TYPE_IDENTITY as u8, 0],
gm_params: [WARP_IDENTITY, WARP_IDENTITY],
local_warp_params: WARP_IDENTITY,
local_valid: true,
ref_is_scaled: [false, false],
force_integer_mv: false,
};
let mode_info = InterModeInfo {
ref_frame: crate::uncompressed_header_tail::LAST_FRAME as u8,
mv: [0, 0],
};
let (w, h) = (8usize, 8usize);
let mut curr = vec![0u16; ref_h * stride];
reconstruct_inter_block_warp(
mode_info,
&warp,
&ref_frame_idx,
&store,
0,
8,
8,
w,
h,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&mut curr,
stride,
)
.expect("reconstruct_inter_block_warp LOCALWARP");
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let mut pred = vec![0u16; w * h];
predict_inter(
0,
8,
8,
w,
h,
crate::cdf::MOTION_MODE_WARPED_CAUSAL,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
Some(&warp),
None,
&mut pred,
)
.unwrap();
for i in 0..h {
for j in 0..w {
assert_eq!(
curr[(8 + i) * stride + (8 + j)],
pred[i * w + j],
"warp bridge sample ({i},{j}) must match predict_inter WARP arm"
);
}
}
}
#[test]
fn r338_reconstruct_inter_block_warp_arg_guards() {
let refp = vec![7u16; 32 * 32];
let store = [RefFrameStoreEntry {
plane: &refp,
stride: 32,
upscaled_width: 32,
width: 32,
height: 32,
}];
let ref_frame_idx = [0u8; 7];
let warp = WarpDriverParams {
y_mode: [crate::cdf::MODE_NEWMV, 0],
gm_type: [crate::cdf::GM_TYPE_IDENTITY as u8, 0],
gm_params: [WARP_IDENTITY, WARP_IDENTITY],
local_warp_params: WARP_IDENTITY,
local_valid: true,
ref_is_scaled: [false, false],
force_integer_mv: false,
};
let mut curr = vec![0u16; 32 * 32];
let mi_intra = InterModeInfo {
ref_frame: crate::uncompressed_header_tail::INTRA_FRAME as u8,
mv: [0, 0],
};
assert!(reconstruct_inter_block_warp(
mi_intra,
&warp,
&ref_frame_idx,
&store,
0,
0,
0,
8,
8,
8,
0,
0,
32,
32,
EIGHTTAP,
EIGHTTAP,
&mut curr,
32,
)
.is_err());
let mi = InterModeInfo {
ref_frame: crate::uncompressed_header_tail::LAST_FRAME as u8,
mv: [0, 0],
};
let bad_idx = [9u8; 7];
assert!(reconstruct_inter_block_warp(
mi, &warp, &bad_idx, &store, 0, 0, 0, 8, 8, 8, 0, 0, 32, 32, EIGHTTAP, EIGHTTAP,
&mut curr, 32,
)
.is_err());
let mut tiny = vec![0u16; 8];
assert!(reconstruct_inter_block_warp(
mi,
&warp,
&ref_frame_idx,
&store,
0,
0,
0,
8,
8,
8,
0,
0,
32,
32,
EIGHTTAP,
EIGHTTAP,
&mut tiny,
32,
)
.is_err());
assert!(reconstruct_inter_block_warp(
mi,
&warp,
&ref_frame_idx,
&store,
0,
-4,
0,
8,
8,
8,
0,
0,
32,
32,
EIGHTTAP,
EIGHTTAP,
&mut curr,
32,
)
.is_err());
}
#[test]
fn r202_predict_inter_use_warp_small_block_falls_back_to_translational() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = ((r + c * 3) & 0xFF) as u16;
}
}
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let warp = WarpDriverParams {
y_mode: [0, 0],
gm_type: [0, 0],
gm_params: [WARP_IDENTITY, WARP_IDENTITY],
local_warp_params: WARP_IDENTITY,
local_valid: true,
ref_is_scaled: [false, false],
force_integer_mv: false,
};
let w = 4;
let h = 4;
let mut warp_out = vec![0u16; w * h];
predict_inter(
0,
2,
2,
w,
h,
crate::cdf::MOTION_MODE_WARPED_CAUSAL,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
Some(&warp),
None,
&mut warp_out,
)
.expect("WARP arm with w<8 must fall back to translational");
let mut simple_out = vec![0u16; w * h];
predict_inter(
0,
2,
2,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
None,
&mut simple_out,
)
.expect("SIMPLE arm baseline");
assert_eq!(
warp_out, simple_out,
"step-7 ◦ 1 (w/h < 8) must produce the SIMPLE translational output"
);
}
#[test]
fn r202_predict_inter_force_integer_mv_disables_warp() {
let ref_w: usize = 32;
let ref_h: usize = 32;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = ((r * 5 + c * 3) & 0xFF) as u16;
}
}
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let warp_force_int = WarpDriverParams {
y_mode: [0, 0],
gm_type: [0, 0],
gm_params: [WARP_IDENTITY, WARP_IDENTITY],
local_warp_params: WARP_IDENTITY,
local_valid: true,
ref_is_scaled: [false, false],
force_integer_mv: true,
};
let w = 8;
let h = 8;
let mut force_int_out = vec![0u16; w * h];
predict_inter(
0,
8,
8,
w,
h,
crate::cdf::MOTION_MODE_WARPED_CAUSAL,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
Some(&warp_force_int),
None,
&mut force_int_out,
)
.expect("WARP arm with force_integer_mv must fall back to translational");
let mut simple_out = vec![0u16; w * h];
predict_inter(
0,
8,
8,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
None,
&mut simple_out,
)
.expect("SIMPLE arm baseline");
assert_eq!(
force_int_out, simple_out,
"step-7 ◦ 2 (force_integer_mv) must produce SIMPLE translational output"
);
}
#[test]
fn r202_predict_inter_local_invalid_falls_back_to_translational() {
let ref_w: usize = 32;
let ref_h: usize = 32;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = ((r * 7 + c * 17) & 0xFF) as u16;
}
}
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let warp = WarpDriverParams {
y_mode: [0, 0],
gm_type: [crate::cdf::GM_TYPE_IDENTITY as u8, 0],
gm_params: [WARP_IDENTITY, WARP_IDENTITY],
local_warp_params: WARP_IDENTITY,
local_valid: false,
ref_is_scaled: [false, false],
force_integer_mv: false,
};
let w = 8;
let h = 8;
let mut warp_out = vec![0u16; w * h];
predict_inter(
0,
8,
8,
w,
h,
crate::cdf::MOTION_MODE_WARPED_CAUSAL,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
Some(&warp),
None,
&mut warp_out,
)
.expect("LOCALWARP+!LocalValid must fall back to translational");
let mut simple_out = vec![0u16; w * h];
predict_inter(
0,
8,
8,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
None,
&mut simple_out,
)
.expect("SIMPLE arm baseline");
assert_eq!(warp_out, simple_out);
}
#[test]
fn r202_predict_inter_global_blocked_by_is_scaled() {
let ref_w: usize = 32;
let ref_h: usize = 32;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = ((r + c) & 0xFF) as u16;
}
}
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let warp = WarpDriverParams {
y_mode: [crate::cdf::MODE_GLOBAL_GLOBALMV, 0],
gm_type: [crate::cdf::GM_TYPE_ROTZOOM as u8, 0],
gm_params: [WARP_IDENTITY, WARP_IDENTITY],
local_warp_params: WARP_IDENTITY,
local_valid: false,
ref_is_scaled: [true, false], force_integer_mv: false,
};
let w = 8;
let h = 8;
let mut warp_out = vec![0u16; w * h];
predict_inter(
0,
8,
8,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
Some(&warp),
None,
&mut warp_out,
)
.expect("is_scaled must block step-7 ◦ 4");
let mut simple_out = vec![0u16; w * h];
predict_inter(
0,
8,
8,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
None,
&mut simple_out,
)
.expect("SIMPLE baseline");
assert_eq!(warp_out, simple_out);
}
#[test]
fn r202_predict_inter_step3_shear_revalidates_localwarp() {
let ref_w: usize = 32;
let ref_h: usize = 32;
let stride = ref_w;
let refp = vec![0u16; ref_h * stride];
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let bad_local = [0, 0, 0, 0, 0, 1 << 16];
let warp = WarpDriverParams {
y_mode: [0, 0],
gm_type: [0, 0],
gm_params: [WARP_IDENTITY, WARP_IDENTITY],
local_warp_params: bad_local,
local_valid: true,
ref_is_scaled: [false, false],
force_integer_mv: false,
};
let w = 8;
let h = 8;
let mut warp_out = vec![0u16; w * h];
predict_inter(
0,
8,
8,
w,
h,
crate::cdf::MOTION_MODE_WARPED_CAUSAL,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
Some(&warp),
None,
&mut warp_out,
)
.expect("step-3 must demote bad_local to translational fallback");
assert!(warp_out.iter().all(|&v| v == 0));
}
#[test]
fn r202_derive_use_warp_truth_table() {
assert_eq!(
derive_use_warp(
4,
8,
crate::cdf::MOTION_MODE_WARPED_CAUSAL,
0,
0,
false,
true,
true,
false
),
UseWarpDecision::Translational
);
assert_eq!(
derive_use_warp(
8,
8,
crate::cdf::MOTION_MODE_WARPED_CAUSAL,
0,
0,
false,
true,
true,
true
),
UseWarpDecision::Translational
);
assert_eq!(
derive_use_warp(
8,
8,
crate::cdf::MOTION_MODE_WARPED_CAUSAL,
0,
0,
false,
true,
false,
false
),
UseWarpDecision::Local
);
assert_eq!(
derive_use_warp(
8,
8,
crate::cdf::MOTION_MODE_SIMPLE,
crate::cdf::MODE_GLOBAL_GLOBALMV,
crate::cdf::GM_TYPE_ROTZOOM as u8,
false,
false,
true,
false
),
UseWarpDecision::Global
);
assert_eq!(
derive_use_warp(
8,
8,
crate::cdf::MOTION_MODE_SIMPLE,
crate::cdf::MODE_GLOBAL_GLOBALMV,
crate::cdf::GM_TYPE_TRANSLATION as u8,
false,
false,
true,
false
),
UseWarpDecision::Translational
);
assert_eq!(
derive_use_warp(
8,
8,
crate::cdf::MOTION_MODE_SIMPLE,
crate::cdf::MODE_GLOBAL_GLOBALMV,
crate::cdf::GM_TYPE_AFFINE as u8,
false,
false,
false,
false
),
UseWarpDecision::Translational
);
assert_eq!(
derive_use_warp(
16,
16,
crate::cdf::MOTION_MODE_SIMPLE,
crate::cdf::MODE_GLOBALMV,
crate::cdf::GM_TYPE_TRANSLATION as u8,
false,
false,
false,
false
),
UseWarpDecision::Translational
);
}
#[test]
fn r203_predict_inter_obmc_no_neighbours_matches_simple() {
let ref_w: usize = 32;
let ref_h: usize = 32;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = ((r * 16 + c) & 0xff) as u16;
}
}
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let w = 8;
let h = 8;
let mut simple_out = vec![0u16; w * h];
predict_inter(
0,
4,
4,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
None,
&mut simple_out,
)
.expect("SIMPLE baseline");
let obmc = ObmcParams {
mi_row: 1,
mi_col: 1,
mi_cols: 8,
mi_rows: 8,
mi_width_log2: 1,
mi_height_log2: 1,
avail_u: true,
avail_l: true,
plane_residual_size_ge_block_8x8: true,
above_neighbours: &[],
left_neighbours: &[],
};
let mut obmc_out = vec![0u16; w * h];
predict_inter(
0,
4,
4,
w,
h,
crate::cdf::MOTION_MODE_OBMC,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
Some(&obmc),
&mut obmc_out,
)
.expect("OBMC with no neighbours");
assert_eq!(
simple_out, obmc_out,
"OBMC with no qualifying neighbours must match SIMPLE translational"
);
}
#[test]
fn r203_predict_inter_obmc_unavailable_neighbours_noops() {
let ref_w: usize = 32;
let ref_h: usize = 32;
let mut refp = vec![0u16; ref_w * ref_h];
for v in refp.iter_mut().enumerate() {
*v.1 = (v.0 & 0xff) as u16;
}
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: ref_w,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let w = 8;
let h = 8;
let mut simple_out = vec![0u16; w * h];
predict_inter(
0,
4,
4,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
None,
&mut simple_out,
)
.unwrap();
let nb = ObmcNeighbour {
bundle: refs[0],
step4: 2,
interp_filter_x: EIGHTTAP,
interp_filter_y: EIGHTTAP,
axis_pos4: 2,
};
let obmc = ObmcParams {
mi_row: 1,
mi_col: 1,
mi_cols: 8,
mi_rows: 8,
mi_width_log2: 1,
mi_height_log2: 1,
avail_u: false,
avail_l: false,
plane_residual_size_ge_block_8x8: true,
above_neighbours: &[nb],
left_neighbours: &[nb],
};
let mut obmc_out = vec![0u16; w * h];
predict_inter(
0,
4,
4,
w,
h,
crate::cdf::MOTION_MODE_OBMC,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
Some(&obmc),
&mut obmc_out,
)
.unwrap();
assert_eq!(simple_out, obmc_out);
}
#[test]
fn r203_predict_inter_obmc_identical_above_neighbour_idempotent() {
let ref_w: usize = 32;
let ref_h: usize = 32;
let mut refp = vec![0u16; ref_w * ref_h];
for (i, v) in refp.iter_mut().enumerate() {
*v = ((i * 7) & 0xff) as u16;
}
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: ref_w,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let w = 8;
let h = 8;
let mut simple_out = vec![0u16; w * h];
predict_inter(
0,
8,
8,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
None,
&mut simple_out,
)
.unwrap();
let above_nb = ObmcNeighbour {
bundle: refs[0],
step4: 2,
interp_filter_x: EIGHTTAP,
interp_filter_y: EIGHTTAP,
axis_pos4: 2,
};
let obmc = ObmcParams {
mi_row: 2,
mi_col: 2,
mi_cols: 8,
mi_rows: 8,
mi_width_log2: 1,
mi_height_log2: 1,
avail_u: true,
avail_l: false,
plane_residual_size_ge_block_8x8: true,
above_neighbours: &[above_nb],
left_neighbours: &[],
};
let mut obmc_out = vec![0u16; w * h];
predict_inter(
0,
8,
8,
w,
h,
crate::cdf::MOTION_MODE_OBMC,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
Some(&obmc),
&mut obmc_out,
)
.unwrap();
assert_eq!(
simple_out, obmc_out,
"identical-neighbour OBMC blend must be identity"
);
}
#[test]
fn r203_predict_inter_obmc_identical_left_neighbour_idempotent() {
let ref_w: usize = 32;
let ref_h: usize = 32;
let mut refp = vec![0u16; ref_w * ref_h];
for (i, v) in refp.iter_mut().enumerate() {
*v = ((i * 11) & 0xff) as u16;
}
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: ref_w,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let w = 8;
let h = 8;
let mut simple_out = vec![0u16; w * h];
predict_inter(
0,
8,
8,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
None,
&mut simple_out,
)
.unwrap();
let left_nb = ObmcNeighbour {
bundle: refs[0],
step4: 2,
interp_filter_x: EIGHTTAP,
interp_filter_y: EIGHTTAP,
axis_pos4: 2,
};
let obmc = ObmcParams {
mi_row: 2,
mi_col: 2,
mi_cols: 8,
mi_rows: 8,
mi_width_log2: 1,
mi_height_log2: 1,
avail_u: false,
avail_l: true,
plane_residual_size_ge_block_8x8: true,
above_neighbours: &[],
left_neighbours: &[left_nb],
};
let mut obmc_out = vec![0u16; w * h];
predict_inter(
0,
8,
8,
w,
h,
crate::cdf::MOTION_MODE_OBMC,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
Some(&obmc),
&mut obmc_out,
)
.unwrap();
assert_eq!(simple_out, obmc_out);
}
#[test]
fn r203_predict_inter_obmc_above_modifies_top_half_only() {
let ref_w: usize = 48;
let ref_h: usize = 48;
let mut refp = vec![0u16; ref_w * ref_h];
for (i, v) in refp.iter_mut().enumerate() {
*v = ((i * 3) & 0xff) as u16;
}
let curr_ref = PredictInterRef {
ref_plane: &refp,
ref_stride: ref_w,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
};
let refs = [curr_ref];
let w = 8;
let h = 8;
let bx = 8;
let by = 8;
let mut simple_out = vec![0u16; w * h];
predict_inter(
0,
bx,
by,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
None,
&mut simple_out,
)
.unwrap();
let nb_ref = PredictInterRef {
ref_plane: &refp,
ref_stride: ref_w,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [8, 0],
};
let above_nb = ObmcNeighbour {
bundle: nb_ref,
step4: 2,
interp_filter_x: EIGHTTAP,
interp_filter_y: EIGHTTAP,
axis_pos4: 2,
};
let obmc = ObmcParams {
mi_row: 2,
mi_col: 2,
mi_cols: 16,
mi_rows: 16,
mi_width_log2: 1,
mi_height_log2: 1,
avail_u: true,
avail_l: false,
plane_residual_size_ge_block_8x8: true,
above_neighbours: &[above_nb],
left_neighbours: &[],
};
let mut obmc_out = vec![0u16; w * h];
predict_inter(
0,
bx,
by,
w,
h,
crate::cdf::MOTION_MODE_OBMC,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
Some(&obmc),
&mut obmc_out,
)
.unwrap();
for row in 4..h {
for col in 0..w {
assert_eq!(
simple_out[row * w + col],
obmc_out[row * w + col],
"row {row} col {col} below the above-pass extent must equal SIMPLE"
);
}
}
let differs = (0..4)
.any(|row| (0..w).any(|col| simple_out[row * w + col] != obmc_out[row * w + col]));
assert!(
differs,
"above-pass with a different MV must change the top half"
);
}
#[test]
fn r203_predict_inter_obmc_above_gated_by_plane_residual_size() {
let ref_w: usize = 32;
let ref_h: usize = 32;
let mut refp = vec![0u16; ref_w * ref_h];
for (i, v) in refp.iter_mut().enumerate() {
*v = ((i * 5) & 0xff) as u16;
}
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: ref_w,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let w = 8;
let h = 8;
let mut simple_out = vec![0u16; w * h];
predict_inter(
0,
8,
8,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
None,
&mut simple_out,
)
.unwrap();
let nb_ref = PredictInterRef {
ref_plane: &refp,
ref_stride: ref_w,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [16, 0],
};
let above_nb = ObmcNeighbour {
bundle: nb_ref,
step4: 2,
interp_filter_x: EIGHTTAP,
interp_filter_y: EIGHTTAP,
axis_pos4: 2,
};
let obmc = ObmcParams {
mi_row: 2,
mi_col: 2,
mi_cols: 8,
mi_rows: 8,
mi_width_log2: 1,
mi_height_log2: 1,
avail_u: true,
avail_l: false,
plane_residual_size_ge_block_8x8: false,
above_neighbours: &[above_nb],
left_neighbours: &[],
};
let mut obmc_out = vec![0u16; w * h];
predict_inter(
0,
8,
8,
w,
h,
crate::cdf::MOTION_MODE_OBMC,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
Some(&obmc),
&mut obmc_out,
)
.unwrap();
assert_eq!(
simple_out, obmc_out,
"above-pass must be gated off when plane_residual_size < BLOCK_8X8"
);
}
#[test]
fn r203_predict_inter_obmc_n_limit_caps_above_walk() {
let ref_w: usize = 32;
let ref_h: usize = 32;
let mut refp = vec![0u16; ref_w * ref_h];
for (i, v) in refp.iter_mut().enumerate() {
*v = ((i * 13) & 0xff) as u16;
}
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: ref_w,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let w = 4;
let h = 8;
let bx = 8;
let by = 8;
let mut simple_out = vec![0u16; w * h];
predict_inter(
0,
bx,
by,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
None,
&mut simple_out,
)
.unwrap();
let nb_ref = PredictInterRef {
ref_plane: &refp,
ref_stride: ref_w,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [8, 0],
};
let above_nb = ObmcNeighbour {
bundle: nb_ref,
step4: 2,
interp_filter_x: EIGHTTAP,
interp_filter_y: EIGHTTAP,
axis_pos4: 2,
};
let obmc = ObmcParams {
mi_row: 2,
mi_col: 2,
mi_cols: 8,
mi_rows: 8,
mi_width_log2: 0,
mi_height_log2: 0,
avail_u: true,
avail_l: false,
plane_residual_size_ge_block_8x8: true,
above_neighbours: &[above_nb],
left_neighbours: &[],
};
let mut obmc_out = vec![0u16; w * h];
predict_inter(
0,
bx,
by,
w,
h,
crate::cdf::MOTION_MODE_OBMC,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
Some(&obmc),
&mut obmc_out,
)
.unwrap();
assert_eq!(simple_out, obmc_out);
}
#[test]
fn r203_predict_inter_obmc_multi_above_neighbours_walk_correctly() {
let ref_w: usize = 32;
let ref_h: usize = 32;
let mut refp = vec![0u16; ref_w * ref_h];
for (i, v) in refp.iter_mut().enumerate() {
*v = ((i * 17) & 0xff) as u16;
}
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: ref_w,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let w = 16;
let h = 16;
let mut simple_out = vec![0u16; w * h];
predict_inter(
0,
8,
8,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
None,
&mut simple_out,
)
.unwrap();
let nb = ObmcNeighbour {
bundle: refs[0],
step4: 2,
interp_filter_x: EIGHTTAP,
interp_filter_y: EIGHTTAP,
axis_pos4: 2,
};
let nb2 = ObmcNeighbour { axis_pos4: 4, ..nb };
let obmc = ObmcParams {
mi_row: 2,
mi_col: 2,
mi_cols: 8,
mi_rows: 8,
mi_width_log2: 2,
mi_height_log2: 2,
avail_u: true,
avail_l: false,
plane_residual_size_ge_block_8x8: true,
above_neighbours: &[nb, nb2],
left_neighbours: &[],
};
let mut obmc_out = vec![0u16; w * h];
predict_inter(
0,
8,
8,
w,
h,
crate::cdf::MOTION_MODE_OBMC,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
None,
None,
Some(&obmc),
&mut obmc_out,
)
.unwrap();
assert_eq!(simple_out, obmc_out);
}
#[test]
fn r355_reconstruct_inter_block_obmc_matches_predict_inter() {
let ref_w: usize = 48;
let ref_h: usize = 48;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = ((r * 9 + c * 5 + 1) & 0xFF) as u16;
}
}
let entry = RefFrameStoreEntry {
plane: &refp[..],
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let store = [entry, entry, entry, entry];
let ref_frame_idx: [u8; 7] = [2, 1, 3, 0, 0, 1, 2];
let last = crate::uncompressed_header_tail::LAST_FRAME as u8;
let w = 8usize;
let h = 8usize;
let (bx, by) = (8i32, 8i32);
let mode_info = InterModeInfo {
ref_frame: last,
mv: [0, 0],
};
let nb_bundle = PredictInterRef {
ref_plane: &refp[..],
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [8, 0],
};
let above_nb = ObmcNeighbour {
bundle: nb_bundle,
step4: 2,
interp_filter_x: EIGHTTAP,
interp_filter_y: EIGHTTAP,
axis_pos4: 2,
};
let obmc = ObmcParams {
mi_row: 2,
mi_col: 2,
mi_cols: 16,
mi_rows: 16,
mi_width_log2: 1,
mi_height_log2: 1,
avail_u: true,
avail_l: false,
plane_residual_size_ge_block_8x8: true,
above_neighbours: &[above_nb],
left_neighbours: &[],
};
let own = [PredictInterRef {
ref_plane: &refp[..],
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv: [0, 0],
}];
let mut scratch = vec![0u16; w * h];
predict_inter(
0,
bx,
by,
w,
h,
crate::cdf::MOTION_MODE_OBMC,
false,
false,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&own,
None,
None,
None,
Some(&obmc),
&mut scratch,
)
.unwrap();
let plane_stride = 16usize;
let mut plane = vec![0u16; plane_stride * 16];
reconstruct_inter_block_obmc(
mode_info,
&obmc,
&ref_frame_idx,
&store,
0,
bx,
by,
w,
h,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&mut plane,
plane_stride,
)
.unwrap();
for i in 0..h {
for j in 0..w {
assert_eq!(
plane[(by as usize + i) * plane_stride + (bx as usize + j)],
scratch[i * w + j],
"driver row {i} col {j} must match the predict_inter OBMC oracle"
);
}
}
}
#[test]
fn r355_reconstruct_inter_block_obmc_rejects_intra_ref() {
let refp = vec![5u16; 16 * 16];
let entry = RefFrameStoreEntry {
plane: &refp[..],
stride: 16,
upscaled_width: 16,
width: 16,
height: 16,
};
let store = [entry, entry, entry, entry];
let ref_frame_idx: [u8; 7] = [0, 1, 2, 3, 0, 1, 2];
let obmc = ObmcParams {
mi_row: 0,
mi_col: 0,
mi_cols: 4,
mi_rows: 4,
mi_width_log2: 1,
mi_height_log2: 1,
avail_u: false,
avail_l: false,
plane_residual_size_ge_block_8x8: true,
above_neighbours: &[],
left_neighbours: &[],
};
let mut plane = vec![0u16; 16 * 16];
let intra_ref = crate::uncompressed_header_tail::INTRA_FRAME as u8; assert!(matches!(
reconstruct_inter_block_obmc(
InterModeInfo {
ref_frame: intra_ref,
mv: [0, 0],
},
&obmc,
&ref_frame_idx,
&store,
0,
0,
0,
8,
8,
8,
0,
0,
16,
16,
EIGHTTAP,
EIGHTTAP,
&mut plane,
16,
),
Err(crate::Error::PartitionWalkOutOfRange)
));
}
#[test]
fn r299_reconstruct_inter_block_interintra_matches_predict_inter() {
let ref_w: usize = 24;
let ref_h: usize = 24;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = ((r * 9 + c * 5) & 0xFF) as u16;
}
}
let entry = RefFrameStoreEntry {
plane: &refp[..],
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let store = [entry, entry, entry, entry];
let ref_frame_idx: [u8; 7] = [0, 1, 2, 3, 0, 1, 2];
let last = crate::uncompressed_header_tail::LAST_FRAME as u8;
let w = 8usize;
let h = 8usize;
let bit_depth = 8u8;
let mv = [4i16, 2];
let ii_mode = II_SMOOTH_PRED;
let curr_w = 16usize;
let curr_h = 16usize;
let (px, py) = (4usize, 4usize);
let mut curr = vec![0u16; curr_w * curr_h];
for i in 0..h {
for j in 0..w {
curr[(py + i) * curr_w + (px + j)] = ((i * 7 + j * 3 + 11) & 0xFF) as u16;
}
}
let intra_window: Vec<u16> = (0..h)
.flat_map(|i| (0..w).map(move |j| ((i * 7 + j * 3 + 11) & 0xFF) as u16))
.collect();
reconstruct_inter_block_interintra(
InterIntraModeInfo {
ref_frame: last,
mv,
interintra_mode: ii_mode,
wedge: None,
},
&ref_frame_idx,
&store,
0,
px as i32,
py as i32,
w,
h,
bit_depth,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
None,
None,
&mut curr,
curr_w,
)
.expect("inter-intra per-block driver");
let refs = [PredictInterRef {
ref_plane: &refp,
ref_stride: stride,
ref_upscaled_width: ref_w as u32,
ref_width: ref_w as u32,
ref_height: ref_h as u32,
mv,
}];
let mut oracle = intra_window.clone();
predict_inter(
0,
px as i32,
py as i32,
w,
h,
crate::cdf::MOTION_MODE_SIMPLE,
false,
true,
bit_depth,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
&refs,
None,
Some(InterIntraParams {
interintra_mode: ii_mode,
wedge: None,
}),
None,
None,
&mut oracle,
)
.unwrap();
let mut expected = vec![0u16; curr_w * curr_h];
for i in 0..h {
for j in 0..w {
expected[(py + i) * curr_w + (px + j)] = ((i * 7 + j * 3 + 11) & 0xFF) as u16;
}
}
for i in 0..h {
for j in 0..w {
expected[(py + i) * curr_w + (px + j)] = oracle[i * w + j];
}
}
assert_eq!(curr, expected);
assert_ne!(
&curr[(py) * curr_w + px..(py) * curr_w + px + w],
&intra_window[..w]
);
}
#[test]
fn r299_frame_walk_drives_interintra_leaf_like_per_block() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = ((r * 13 + c * 7) & 0xFF) as u16;
}
}
let entry = RefFrameStoreEntry {
plane: &refp[..],
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let store = [entry, entry, entry, entry];
let store2 = store;
let ref_frame_idx: [u8; 7] = [0, 1, 2, 3, 0, 1, 2];
let last = crate::uncompressed_header_tail::LAST_FRAME as i8;
let intra_frame = crate::uncompressed_header_tail::INTRA_FRAME as i8;
let mi_rows: u32 = 2;
let mi_cols: u32 = 2;
let cells = (mi_rows * mi_cols) as usize;
const BLOCK_8X8: usize = 3;
use crate::cdf::BLOCK_INVALID;
let mut mi_sizes = vec![BLOCK_INVALID; cells];
mi_sizes[0] = BLOCK_8X8;
let mut is_inters = vec![0u8; cells];
is_inters[0] = 1;
let mut ref_frames = vec![0i8; cells * 2];
for cell in 0..cells {
ref_frames[cell * 2 + 1] = -1;
}
ref_frames[0] = last;
ref_frames[1] = intra_frame; let mv = [4i16, 6];
let mut mvs = vec![0i16; cells * 4];
mvs[0] = mv[0];
mvs[1] = mv[1];
let interp_filters = vec![EIGHTTAP; cells * 2];
let compound_types = vec![COMPOUND_AVERAGE; cells];
let zeros = vec![0u8; cells];
let ii_mode = II_H_PRED;
let mut interintra_modes = vec![0u8; cells];
interintra_modes[0] = ii_mode;
let curr_w = (mi_cols * 4) as usize; let curr_h = (mi_rows * 4) as usize; let mut curr = vec![0u16; curr_w * curr_h];
for i in 0..8usize {
for j in 0..8usize {
curr[i * curr_w + j] = ((i * 5 + j * 11 + 3) & 0xFF) as u16;
}
}
let seed = curr.clone();
let order_hints_by_ref = [0i32; 8];
let grid = InterModeInfoGrid {
mi_sizes: &mi_sizes,
is_inters: &is_inters,
ref_frames: &ref_frames,
mvs: &mvs,
interp_filters: &interp_filters,
compound_types: &compound_types,
wedge_indices: &zeros,
wedge_signs: &zeros,
mask_types: &zeros,
interintra_modes: &interintra_modes,
wedge_interintras: &zeros,
interintra_wedge_indices: &zeros,
order_hint_bits: 7,
current_order_hint: 0,
order_hints_by_ref: &order_hints_by_ref,
mi_rows,
mi_cols,
bit_depth: 8,
warp: None,
obmc: None,
};
{
let mut planes = [PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut curr,
curr_stride: curr_w,
}];
reconstruct_inter_frame(&grid, &ref_frame_idx, &mut planes)
.expect("frame-level inter-intra reconstruction");
}
let mut oracle = seed.clone();
reconstruct_inter_block_interintra(
InterIntraModeInfo {
ref_frame: last as u8,
mv,
interintra_mode: ii_mode,
wedge: None,
},
&ref_frame_idx,
&store2,
0,
0,
0,
8,
8,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
None,
None,
&mut oracle,
curr_w,
)
.unwrap();
assert_eq!(
curr, oracle,
"frame walk must drive the inter-intra leaf identically to the per-block driver"
);
assert_ne!(curr, seed, "the inter-intra blend must modify the plane");
}
#[test]
fn r299_frame_walk_interintra_wedge_differs_from_non_wedge() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = ((r * 11 + c * 5) & 0xFF) as u16;
}
}
let entry = RefFrameStoreEntry {
plane: &refp[..],
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let store = [entry, entry, entry, entry];
let ref_frame_idx: [u8; 7] = [0, 1, 2, 3, 0, 1, 2];
let last = crate::uncompressed_header_tail::LAST_FRAME as i8;
let intra_frame = crate::uncompressed_header_tail::INTRA_FRAME as i8;
let mi_rows: u32 = 2;
let mi_cols: u32 = 2;
let cells = (mi_rows * mi_cols) as usize;
const BLOCK_8X8: usize = 3;
use crate::cdf::BLOCK_INVALID;
let mut mi_sizes = vec![BLOCK_INVALID; cells];
mi_sizes[0] = BLOCK_8X8;
let mut is_inters = vec![0u8; cells];
is_inters[0] = 1;
let mut ref_frames = vec![0i8; cells * 2];
for cell in 0..cells {
ref_frames[cell * 2 + 1] = -1;
}
ref_frames[0] = last;
ref_frames[1] = intra_frame;
let mv = [2i16, 2];
let mut mvs = vec![0i16; cells * 4];
mvs[0] = mv[0];
mvs[1] = mv[1];
let interp_filters = vec![EIGHTTAP; cells * 2];
let compound_types = vec![COMPOUND_AVERAGE; cells];
let zeros = vec![0u8; cells];
let ii_mode = II_DC_PRED;
let mut interintra_modes = vec![0u8; cells];
interintra_modes[0] = ii_mode;
let mut wedge_interintras = vec![0u8; cells];
let mut interintra_wedge_indices = vec![0u8; cells];
interintra_wedge_indices[0] = 5;
let curr_w = (mi_cols * 4) as usize;
let curr_h = (mi_rows * 4) as usize;
let mut seed = vec![0u16; curr_w * curr_h];
for i in 0..8usize {
for j in 0..8usize {
seed[i * curr_w + j] = ((i * 5 + j * 11 + 3) & 0xFF) as u16;
}
}
let order_hints_by_ref = [0i32; 8];
let wii_non_wedge = wedge_interintras.clone();
wedge_interintras[0] = 1;
let wii_wedge = wedge_interintras.clone();
let mut non_wedge = seed.clone();
{
let grid = InterModeInfoGrid {
mi_sizes: &mi_sizes,
is_inters: &is_inters,
ref_frames: &ref_frames,
mvs: &mvs,
interp_filters: &interp_filters,
compound_types: &compound_types,
wedge_indices: &zeros,
wedge_signs: &zeros,
mask_types: &zeros,
interintra_modes: &interintra_modes,
wedge_interintras: &wii_non_wedge,
interintra_wedge_indices: &interintra_wedge_indices,
order_hint_bits: 7,
current_order_hint: 0,
order_hints_by_ref: &order_hints_by_ref,
mi_rows,
mi_cols,
bit_depth: 8,
warp: None,
obmc: None,
};
let mut planes = [PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut non_wedge,
curr_stride: curr_w,
}];
reconstruct_inter_frame(&grid, &ref_frame_idx, &mut planes).unwrap();
}
let mut wedge = seed.clone();
{
let grid = InterModeInfoGrid {
mi_sizes: &mi_sizes,
is_inters: &is_inters,
ref_frames: &ref_frames,
mvs: &mvs,
interp_filters: &interp_filters,
compound_types: &compound_types,
wedge_indices: &zeros,
wedge_signs: &zeros,
mask_types: &zeros,
interintra_modes: &interintra_modes,
wedge_interintras: &wii_wedge,
interintra_wedge_indices: &interintra_wedge_indices,
order_hint_bits: 7,
current_order_hint: 0,
order_hints_by_ref: &order_hints_by_ref,
mi_rows,
mi_cols,
bit_depth: 8,
warp: None,
obmc: None,
};
let mut planes = [PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut wedge,
curr_stride: curr_w,
}];
reconstruct_inter_frame(&grid, &ref_frame_idx, &mut planes).unwrap();
}
assert_ne!(
non_wedge, seed,
"non-wedge interintra blend must modify the plane"
);
assert_ne!(wedge, seed, "wedge interintra blend must modify the plane");
assert_ne!(
wedge, non_wedge,
"the §7.11.3.11 wedge mask must produce a different blend from the §7.11.3.13 mask"
);
}
#[test]
fn r301_dispatch_bridge_drives_interintra_like_frame_walk() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let stride = ref_w;
let mut refp = vec![0u16; ref_h * stride];
for r in 0..ref_h {
for c in 0..ref_w {
refp[r * stride + c] = ((r * 13 + c * 7) & 0xFF) as u16;
}
}
let entry = RefFrameStoreEntry {
plane: &refp[..],
stride,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let store = [entry, entry, entry, entry];
let ref_frame_idx: [u8; 7] = [0, 1, 2, 3, 0, 1, 2];
let last = crate::uncompressed_header_tail::LAST_FRAME as u8;
const BLOCK_8X8: usize = 3;
let ii_mode = II_H_PRED;
let mv = [4i16, 6];
let curr_w = 8usize;
let curr_h = 8usize;
let mut seed = vec![0u16; curr_w * curr_h];
for i in 0..curr_h {
for j in 0..curr_w {
seed[i * curr_w + j] = ((i * 5 + j * 11 + 3) & 0xFF) as u16;
}
}
let leaf = InterIntraLeaf {
mode_info: InterIntraModeInfo {
ref_frame: last,
mv,
interintra_mode: ii_mode,
wedge: None,
},
mi_size: BLOCK_8X8,
mi_row: 0,
mi_col: 0,
interp_filter_x: EIGHTTAP,
interp_filter_y: EIGHTTAP,
};
let mut oracle = seed.clone();
reconstruct_inter_block_interintra(
leaf.mode_info,
&ref_frame_idx,
&store,
0,
0,
0,
8,
8,
8,
0,
0,
ref_w as u32,
ref_h as u32,
EIGHTTAP,
EIGHTTAP,
None,
None,
&mut oracle,
curr_w,
)
.unwrap();
let readout = crate::cdf::ComputePredictionReadout {
is_inter_intra: true,
is_inter: true,
num_planes_visited: 1,
tasks: vec![crate::cdf::PlanePredictionTask {
plane: 0,
start_x: 0,
start_y: 0,
log2_w: 3,
log2_h: 3,
mode: crate::cdf::H_PRED as u8, have_left: false,
have_above: false,
}],
};
let mut bridged = seed.clone();
{
let mut planes = [PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut bridged,
curr_stride: curr_w,
}];
reconstruct_inter_intra_from_dispatch(
&readout,
&leaf,
&ref_frame_idx,
8,
None,
&mut planes,
)
.expect("dispatch-bridge inter-intra reconstruction");
}
assert_eq!(
bridged, oracle,
"the dispatch bridge must drive the shared inter-intra driver identically to the per-block driver"
);
assert_ne!(bridged, seed, "the inter-intra blend must modify the plane");
}
#[test]
fn r301_dispatch_bridge_rejects_inconsistent_readout() {
let ref_w: usize = 16;
let ref_h: usize = 16;
let refp = vec![7u16; ref_h * ref_w];
let entry = RefFrameStoreEntry {
plane: &refp[..],
stride: ref_w,
upscaled_width: ref_w as u32,
width: ref_w as u32,
height: ref_h as u32,
};
let store = [entry, entry, entry, entry];
let ref_frame_idx: [u8; 7] = [0, 1, 2, 3, 0, 1, 2];
let last = crate::uncompressed_header_tail::LAST_FRAME as u8;
const BLOCK_8X8: usize = 3;
let leaf = InterIntraLeaf {
mode_info: InterIntraModeInfo {
ref_frame: last,
mv: [0, 0],
interintra_mode: II_DC_PRED,
wedge: None,
},
mi_size: BLOCK_8X8,
mi_row: 0,
mi_col: 0,
interp_filter_x: EIGHTTAP,
interp_filter_y: EIGHTTAP,
};
let mk_task = |mode: u8| crate::cdf::PlanePredictionTask {
plane: 0,
start_x: 0,
start_y: 0,
log2_w: 3,
log2_h: 3,
mode,
have_left: false,
have_above: false,
};
let not_ii = crate::cdf::ComputePredictionReadout {
is_inter_intra: false,
is_inter: true,
num_planes_visited: 1,
tasks: vec![mk_task(crate::cdf::DC_PRED as u8)],
};
let short_cov = crate::cdf::ComputePredictionReadout {
is_inter_intra: true,
is_inter: true,
num_planes_visited: 0,
tasks: vec![],
};
let mode_mismatch = crate::cdf::ComputePredictionReadout {
is_inter_intra: true,
is_inter: true,
num_planes_visited: 1,
tasks: vec![mk_task(crate::cdf::H_PRED as u8)],
};
for bad in [¬_ii, &short_cov, &mode_mismatch] {
let mut curr = vec![0u16; 8 * 8];
let mut planes = [PlaneReconContext {
plane: 0,
subsampling_x: 0,
subsampling_y: 0,
frame_store: &store,
frame_width: ref_w as u32,
frame_height: ref_h as u32,
curr: &mut curr,
curr_stride: 8,
}];
assert!(matches!(
reconstruct_inter_intra_from_dispatch(
bad,
&leaf,
&ref_frame_idx,
8,
None,
&mut planes
),
Err(crate::Error::PartitionWalkOutOfRange)
));
}
}
}