Commit 72030e86dd for aom
commit 72030e86dd631921628417d0d34c3820eb948c7a
Author: Ranjit Kumar Tulabandu <ranjit.tulabandu@ittiam.com>
Date: Tue Jul 7 21:32:23 2026 +0530
lc-dec: Bias against GLOBALMV and GLOBAL_GLOBALMV modes
In this CL, RD_STATS of GLOBALMV and GLOBAL_GLOBALMV modes are scaled
if transformation wrt either of reference frames is non-translation.
The Performance results of encoder and decoder for streams
generated with low complexity decode enabled is given below:
Decode Time BD-Rate Loss(%)
cpu Reduction(%) avg.psnr ssim vmaf vmaf_neg uvq_1p5
1 0.605 0.0270 0.0251 0.0670 0.0515 0.2203
2 0.590 0.0339 0.0457 0.0603 0.0516 0.1501
3 0.356 0.0210 0.0143 0.0260 0.0358 -0.1295
STATS_CHANGED for low complexity decode
Change-Id: I328356ed2556aadea92109cfeb8a0ce269afba3f
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index a11d58e4d0..e805c2c3a4 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -1456,22 +1456,24 @@ static inline void scale_rdstats(RD_STATS *rd_stats, double rd_scale_pct) {
// Increase rate, distortion and SSE in RD_STATS structure of warp and obmc
// motion modes for low complexity decoding.
-static inline void increase_motion_mode_rdstats(const MB_MODE_INFO *this_mbmi,
+static inline void increase_motion_mode_rdstats(const AV1_COMP *cpi,
+ const MB_MODE_INFO *this_mbmi,
RD_STATS *rd_stats,
RD_STATS *rd_stats_y,
- RD_STATS *rd_stats_uv,
- float rd_warp_bias_scale_pct,
- float rd_obmc_bias_scale_pct) {
+ RD_STATS *rd_stats_uv) {
if (rd_stats->rate == INT_MAX ||
(rd_stats_y != NULL && rd_stats_y->rate == INT_MAX) ||
(rd_stats_uv != NULL && rd_stats_uv->rate == INT_MAX))
return;
-
+ const INTER_MODE_SPEED_FEATURES *const inter_sf = &cpi->sf.inter_sf;
double rd_bias_scale = 0.0;
if (this_mbmi->motion_mode == WARPED_CAUSAL) {
- rd_bias_scale = rd_warp_bias_scale_pct / 100.0;
+ rd_bias_scale = inter_sf->bias_warp_mode_rd_scale_pct / 100.0;
} else if (this_mbmi->motion_mode == OBMC_CAUSAL) {
- rd_bias_scale = rd_obmc_bias_scale_pct / 100.0;
+ rd_bias_scale = inter_sf->bias_obmc_mode_rd_scale_pct / 100.0;
+ } else if (this_mbmi->mode == GLOBALMV ||
+ this_mbmi->mode == GLOBAL_GLOBALMV) {
+ rd_bias_scale = get_global_mv_mode_bias(cpi, this_mbmi);
}
if (rd_bias_scale <= 0.0) return;
@@ -1848,10 +1850,7 @@ static int64_t motion_mode_rd(
rd_stats_uv, mbmi);
}
mbmi->skip_txfm = 0;
- increase_motion_mode_rdstats(
- mbmi, rd_stats, NULL, NULL,
- cpi->sf.inter_sf.bias_warp_mode_rd_scale_pct,
- cpi->sf.inter_sf.bias_obmc_mode_rd_scale_pct);
+ increase_motion_mode_rdstats(cpi, mbmi, rd_stats, NULL, NULL);
} else {
// Perform full transform search
@@ -1888,16 +1887,13 @@ static int64_t motion_mode_rd(
}
// Scale RD_STATS after mode stats are collected. Thus unscaled metrics
// are used for model generation
- increase_motion_mode_rdstats(
- mbmi, rd_stats, rd_stats_y, rd_stats_uv,
- cpi->sf.inter_sf.bias_warp_mode_rd_scale_pct,
- cpi->sf.inter_sf.bias_obmc_mode_rd_scale_pct);
+ increase_motion_mode_rdstats(cpi, mbmi, rd_stats, rd_stats_y,
+ rd_stats_uv);
const int skip_rate =
rd_stats->skip_txfm ? skip_txfm_cost_ptr[1] : skip_txfm_cost_ptr[0];
- const int32_t scaled_skip_rate = increase_motion_mode_rate(
- mbmi, skip_rate, cpi->sf.inter_sf.bias_warp_mode_rd_scale_pct,
- cpi->sf.inter_sf.bias_obmc_mode_rd_scale_pct);
+ const int32_t scaled_skip_rate =
+ increase_motion_mode_rate(cpi, mbmi, skip_rate);
const int y_rate =
scaled_skip_rate + (rd_stats->skip_txfm ? 0 : rd_stats_y->rate);
this_yrd = RDCOST(x->rdmult, y_rate + mode_rate, rd_stats_y->dist);
@@ -4013,10 +4009,8 @@ static inline void refine_winner_mode_tx(
skip_blk = 0;
rd_stats_y.rate += mode_costs->skip_txfm_cost[skip_ctx][0];
}
- increase_motion_mode_rdstats(
- mbmi, &rd_stats, &rd_stats_y, &rd_stats_uv,
- cpi->sf.inter_sf.bias_warp_mode_rd_scale_pct,
- cpi->sf.inter_sf.bias_obmc_mode_rd_scale_pct);
+ increase_motion_mode_rdstats(cpi, mbmi, &rd_stats, &rd_stats_y,
+ &rd_stats_uv);
int this_rate = rd_stats.rate + rd_stats_y.rate + rd_stats_uv.rate -
winner_rate_y - winner_rate_uv;
int64_t this_rd = RDCOST(x->rdmult, this_rate, this_dist);
@@ -5209,9 +5203,8 @@ static inline void update_search_state(
const int32_t skip_rate =
x->mode_costs.skip_txfm_cost[skip_ctx]
[new_best_rd_stats->skip_txfm || skip_txfm];
- const int32_t scaled_skip_rate = increase_motion_mode_rate(
- mbmi, skip_rate, cpi->sf.inter_sf.bias_warp_mode_rd_scale_pct,
- cpi->sf.inter_sf.bias_obmc_mode_rd_scale_pct);
+ const int32_t scaled_skip_rate =
+ increase_motion_mode_rate(cpi, mbmi, skip_rate);
search_state->best_rate_y = new_best_rd_stats_y->rate + scaled_skip_rate;
search_state->best_rate_uv = new_best_rd_stats_uv->rate;
}
@@ -5634,16 +5627,13 @@ static void tx_search_best_inter_candidates(
rd_stats_y.rate + rd_stats_uv.rate +
mode_costs->skip_txfm_cost[skip_ctx][mbmi->skip_txfm]);
}
- increase_motion_mode_rdstats(
- mbmi, &rd_stats, &rd_stats_y, &rd_stats_uv,
- cpi->sf.inter_sf.bias_warp_mode_rd_scale_pct,
- cpi->sf.inter_sf.bias_obmc_mode_rd_scale_pct);
+ increase_motion_mode_rdstats(cpi, mbmi, &rd_stats, &rd_stats_y,
+ &rd_stats_uv);
const int *skip_txfm_cost_ptr = mode_costs->skip_txfm_cost[skip_ctx];
const int skip_rate =
rd_stats.skip_txfm ? skip_txfm_cost_ptr[1] : skip_txfm_cost_ptr[0];
- const int32_t scaled_skip_rate = increase_motion_mode_rate(
- mbmi, skip_rate, cpi->sf.inter_sf.bias_warp_mode_rd_scale_pct,
- cpi->sf.inter_sf.bias_obmc_mode_rd_scale_pct);
+ const int32_t scaled_skip_rate =
+ increase_motion_mode_rate(cpi, mbmi, skip_rate);
const int y_rate =
scaled_skip_rate + (rd_stats.skip_txfm ? 0 : rd_stats_y.rate);
this_yrd = RDCOST(x->rdmult, y_rate + mode_rate, rd_stats_y.dist);
diff --git a/av1/encoder/rdopt_utils.h b/av1/encoder/rdopt_utils.h
index 89d9c93592..04d46d01b5 100644
--- a/av1/encoder/rdopt_utils.h
+++ b/av1/encoder/rdopt_utils.h
@@ -709,15 +709,43 @@ static inline void set_mode_eval_params(const struct AV1_COMP *cpi,
txfm_params->mode_eval_type = mode_eval_type;
}
-static inline int increase_motion_mode_rate(const MB_MODE_INFO *this_mbmi,
- int rate,
- float rd_warp_bias_scale_pct,
- float rd_obmc_bias_scale_pct) {
+// Calculate global motion weight and transformation types for RD bias.
+// Returns the weight to apply to scaled RD cost for global motion blocks.
+static inline float get_global_mv_mode_bias(const AV1_COMP *cpi,
+ const MB_MODE_INFO *mbmi) {
+ if (cpi->sf.inter_sf.bias_gm_mode_rd_scale_pct <= 0.0f) return 0.0f;
+ if (cpi->common.features.cur_frame_force_integer_mv) return 0.0f;
+
+ assert(mbmi->mode == GLOBALMV || mbmi->mode == GLOBAL_GLOBALMV);
+
+ TransformationType ref_trans_type =
+ cpi->common.global_motion[mbmi->ref_frame[0]].wmtype;
+ if (is_global_mv_block(mbmi, ref_trans_type)) {
+ return cpi->sf.inter_sf.bias_gm_mode_rd_scale_pct / 100.0f;
+ }
+
+ if (has_second_ref(mbmi)) {
+ ref_trans_type = cpi->common.global_motion[mbmi->ref_frame[1]].wmtype;
+ if (is_global_mv_block(mbmi, ref_trans_type)) {
+ return cpi->sf.inter_sf.bias_gm_mode_rd_scale_pct / 100.0f;
+ }
+ }
+
+ return 0.0f;
+}
+
+static inline int increase_motion_mode_rate(const AV1_COMP *cpi,
+ const MB_MODE_INFO *this_mbmi,
+ int rate) {
+ const INTER_MODE_SPEED_FEATURES *const inter_sf = &cpi->sf.inter_sf;
double rd_bias_scale = 0.0;
if (this_mbmi->motion_mode == WARPED_CAUSAL) {
- rd_bias_scale = rd_warp_bias_scale_pct / 100.0;
+ rd_bias_scale = inter_sf->bias_warp_mode_rd_scale_pct / 100.0;
} else if (this_mbmi->motion_mode == OBMC_CAUSAL) {
- rd_bias_scale = rd_obmc_bias_scale_pct / 100.0;
+ rd_bias_scale = inter_sf->bias_obmc_mode_rd_scale_pct / 100.0;
+ } else if (this_mbmi->mode == GLOBALMV ||
+ this_mbmi->mode == GLOBAL_GLOBALMV) {
+ rd_bias_scale = get_global_mv_mode_bias(cpi, this_mbmi);
}
if (rd_bias_scale <= 0.0) return rate;
@@ -807,9 +835,8 @@ static inline void store_winner_mode_stats(
const int skip_rate =
x->mode_costs
.skip_txfm_cost[skip_ctx][rd_cost->skip_txfm || skip_txfm];
- const int scaled_skip_rate = increase_motion_mode_rate(
- mbmi, skip_rate, cpi->sf.inter_sf.bias_warp_mode_rd_scale_pct,
- cpi->sf.inter_sf.bias_obmc_mode_rd_scale_pct);
+ const int scaled_skip_rate =
+ increase_motion_mode_rate(cpi, mbmi, skip_rate);
winner_mode_stats[mode_idx].rate_y = rd_cost_y->rate + scaled_skip_rate;
winner_mode_stats[mode_idx].rate_uv = rd_cost_uv->rate;
}
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index d9add56561..6904276930 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -656,6 +656,7 @@ static void set_good_speed_features_lc_dec_framesize_dependent(
sf->inter_sf.bias_warp_mode_rd_scale_pct = 2.5f;
sf->inter_sf.bias_obmc_mode_rd_scale_pct = 1.5f;
+ sf->inter_sf.bias_gm_mode_rd_scale_pct = 2.0f;
sf->part_sf.split_partition_penalty_level = is_key_frame ? 0 : 2;
@@ -680,6 +681,7 @@ static void set_good_speed_features_lc_dec_framesize_dependent(
sf->inter_sf.bias_warp_mode_rd_scale_pct = 2.5f;
sf->inter_sf.bias_obmc_mode_rd_scale_pct = 1.5f;
+ sf->inter_sf.bias_gm_mode_rd_scale_pct = 2.0f;
sf->part_sf.split_partition_penalty_level = is_key_frame ? 0 : 2;
@@ -2417,6 +2419,7 @@ static inline void init_inter_sf(INTER_MODE_SPEED_FEATURES *inter_sf) {
inter_sf->skip_arf_compound = 0;
inter_sf->bias_warp_mode_rd_scale_pct = 0.0f;
inter_sf->bias_obmc_mode_rd_scale_pct = 0.0f;
+ inter_sf->bias_gm_mode_rd_scale_pct = 0.0f;
inter_sf->skip_cmp_using_top_cmp_avg_est_rd_lvl = 0;
inter_sf->skip_interinter_wedge_search_based_on_mse = 0;
inter_sf->enable_comp_wedge_search_using_model_rd = 0;
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h
index d1667ea64a..dd5cf57f84 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -1255,6 +1255,11 @@ typedef struct INTER_MODE_SPEED_FEATURES {
// complexity modes.
float bias_obmc_mode_rd_scale_pct;
+ // Percentage of scaling used to increase the rd cost of GLOBALMV and
+ // GLOBAL_GLOBALMV modes of type ROTZOOM so that encoder decisions are biased
+ // against these modes, favoring low complexity modes.
+ float bias_gm_mode_rd_scale_pct;
+
// Avoid further evaluation of compound modes using top estimate RD Costs of
// compound average.
// Values are 0 (not used),1 - 3 with progressively increasing