Commit 20f44593be for aom
commit 20f44593bea8b2ce834098fe5c623075b77d0dbc
Author: Ihor Buhaiov <freedbrt@gmail.com>
Date: Mon Oct 19 23:30:03 2026 +0200
rtc: Build both MV cost tables at frame level
The frame level MV cost update only builds the table for the current
MV precision. With nonrd pick mode and the MV cost update level off,
the realtime only default, it runs only on key frames and on the first
inter frame after them. av1_pick_and_set_high_precision_mv() still
picks the precision from q on every inter frame. So if the first inter
frame has q below HIGH_PRECISION_MV_QTHRESH and a later frame goes
above it, that frame codes with the 1/4 pel table, which was never
built and is still all zeros. MV components then cost no rate. The
default build updates the costs per superblock row, but frames that
skip CDF updates skip that too and can hit the same zero table.
Build the table for the other precision as well whenever the frame
level update runs. In realtime that is two more table builds per key
frame interval.
Found with VBR at 30 fps and max q 63, where the first inter frame
gets q around 100. For example niklas 640x480 at speed 9, 3000 kbps
dropping to 400 kbps at frame 100: 194 of 299 inter frames used the
zero table. In 570 test encodes (camera and screen clips, speeds 7 to
11, CBR and VBR, bitrate drops, 1 and 4 threads) 69 hit it, none of
them CBR. With this change none do, and the encodes that never hit it
give the same output. On the 19 rate curves where 3 or 4 of the 4
points changed, BD rate is -1.56% to +0.15%, median -0.43%.
Change-Id: I4089f07e5bbce77fe574ffea65ddcca47455423c
diff --git a/av1/encoder/rd.c b/av1/encoder/rd.c
index 9a6e89bf01..d379858a3b 100644
--- a/av1/encoder/rd.c
+++ b/av1/encoder/rd.c
@@ -825,9 +825,16 @@ void av1_initialize_rd_consts(AV1_COMP *cpi) {
const INTER_MODE_SPEED_FEATURES *const inter_sf = &cpi->sf.inter_sf;
// Frame level mv cost update
if (is_frame_level_cost_upd_freq_set(cm, inter_sf->mv_cost_upd_level,
- use_nonrd_pick_mode, frames_since_key))
+ use_nonrd_pick_mode, frames_since_key)) {
+ // Also build the table for the other precision. A later frame that skips
+ // this update can switch to it in av1_pick_and_set_high_precision_mv().
+ if (!cm->features.cur_frame_force_integer_mv) {
+ av1_fill_mv_costs(&cm->fc->nmvc, 0, !cm->features.allow_high_precision_mv,
+ x->mv_costs);
+ }
av1_fill_mv_costs(&cm->fc->nmvc, cm->features.cur_frame_force_integer_mv,
cm->features.allow_high_precision_mv, x->mv_costs);
+ }
// Frame level coefficient cost update
if (is_frame_level_cost_upd_freq_set(cm, inter_sf->coeff_cost_upd_level,