Commit ea30b63756 for aom
commit ea30b63756ed70c67d496ad4fba6c33177a88ce8
Author: Ranjit Kumar Tulabandu <ranjit.tulabandu@ittiam.com>
Date: Thu Jun 4 11:00:11 2026 +0530
lc-dec: Improve the logic of biasing against motion modes
In parent version, OBMC, WARP motion modes were biased against by
increasing rd cost locally. Hence these motion modes were biased
against limitedly. In this CL, bias is introduced on rate,
distortion and sse members of RD_STATS structure after transform
search so that biased metrics are used in the calculation of rd
cost for subsequent rd decisions.
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.693 0.0427 0.0740 0.0576 0.0633 0.5793
2 0.619 0.0653 0.0754 0.0537 0.0419 0.0887
3 0.127 0.0001 -0.0091 -0.0245 -0.0253 0.2953
STATS_CHANGED for low complexity decode
Change-Id: Ia4d23f1fdd5bbba8573cf7860fd98e1f410fcd52
diff --git a/av1/encoder/intra_mode_search.c b/av1/encoder/intra_mode_search.c
index 26e47c9add..db8d9c87ae 100644
--- a/av1/encoder/intra_mode_search.c
+++ b/av1/encoder/intra_mode_search.c
@@ -291,7 +291,7 @@ static int rd_pick_filter_intra_sby(const AV1_COMP *const cpi, MACROBLOCK *x,
// Collect mode stats for multiwinner mode processing
const int txfm_search_done = 1;
store_winner_mode_stats(
- &cpi->common, x, mbmi, NULL, NULL, NULL, 0, NULL, bsize, this_rd,
+ cpi, x, mbmi, NULL, NULL, NULL, 0, NULL, bsize, this_rd,
cpi->sf.winner_mode_sf.multi_winner_mode_type, txfm_search_done);
if (this_rd < *best_rd) {
*best_rd = this_rd;
@@ -1646,7 +1646,7 @@ int64_t av1_rd_pick_intra_sby_mode(const AV1_COMP *const cpi, MACROBLOCK *x,
// Collect mode stats for multiwinner mode processing
const int txfm_search_done = 1;
store_winner_mode_stats(
- &cpi->common, x, mbmi, NULL, NULL, NULL, 0, NULL, bsize, this_rd,
+ cpi, x, mbmi, NULL, NULL, NULL, 0, NULL, bsize, this_rd,
cpi->sf.winner_mode_sf.multi_winner_mode_type, txfm_search_done);
if (this_rd < best_rd) {
best_mbmi = *mbmi;
diff --git a/av1/encoder/palette.c b/av1/encoder/palette.c
index cab15e86a4..3946943668 100644
--- a/av1/encoder/palette.c
+++ b/av1/encoder/palette.c
@@ -304,8 +304,8 @@ static inline void palette_rd_y(
// Collect mode stats for multiwinner mode processing
const int txfm_search_done = 1;
store_winner_mode_stats(
- &cpi->common, x, mbmi, NULL, NULL, NULL, THR_DC, color_map, bsize,
- this_rd, cpi->sf.winner_mode_sf.multi_winner_mode_type, txfm_search_done);
+ cpi, x, mbmi, NULL, NULL, NULL, THR_DC, color_map, bsize, this_rd,
+ cpi->sf.winner_mode_sf.multi_winner_mode_type, txfm_search_done);
if (this_rd < *best_rd) {
*best_rd = this_rd;
// Setting beat_best_rd flag because current mode rd is better than best_rd.
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index 62ef4815af..e6acfe98e6 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -1445,34 +1445,39 @@ static inline void update_mode_start_end_index(
*mode_index_end = SIMPLE_TRANSLATION;
}
-// Increase rd cost of warp and obmc motion modes for low complexity decoding.
-static inline void increase_motion_mode_rd(const MB_MODE_INFO *const best_mbmi,
- const MB_MODE_INFO *const this_mbmi,
- int64_t *const best_scaled_rd,
- int64_t *const this_scaled_rd,
- int rd_warp_bias_scale_pct,
- float rd_obmc_bias_scale_pct) {
- if (*best_scaled_rd == INT64_MAX || *this_scaled_rd == INT64_MAX) return;
-
- // Experiments have been performed with increasing the RD cost of warp and
- // obmc motion modes at the below locations of inter mode evaluation.
- // (1). Inter mode evaluation loop in av1_rd_pick_inter_mode().
- // (2). Motion mode evaluation during handle_inter_mode() call.
- // (3). Motion mode evaluation for winner motion modes.
- // (4). Tx search for best inter candidates.
- // Based on the speed quality trade-off results of this speed feature, the rd
- // bias logic is enabled only at (2), (3) and (4).
- const double rd_warp_bias_scale = rd_warp_bias_scale_pct / 100.0;
- const double rd_obmc_bias_scale = rd_obmc_bias_scale_pct / 100.0;
- if (best_mbmi->motion_mode == WARPED_CAUSAL)
- *best_scaled_rd += (int64_t)(rd_warp_bias_scale * *best_scaled_rd);
- else if (best_mbmi->motion_mode == OBMC_CAUSAL)
- *best_scaled_rd += (int64_t)(rd_obmc_bias_scale * *best_scaled_rd);
-
- if (this_mbmi->motion_mode == WARPED_CAUSAL)
- *this_scaled_rd += (int64_t)(rd_warp_bias_scale * *this_scaled_rd);
- else if (this_mbmi->motion_mode == OBMC_CAUSAL)
- *this_scaled_rd += (int64_t)(rd_obmc_bias_scale * *this_scaled_rd);
+// Scale rate, dist and sse of RD_STATS as per the given bias percentage
+static inline void scale_rdstats(RD_STATS *rd_stats, double rd_scale_pct) {
+ if (rd_stats == NULL) return;
+ rd_stats->rate += (int)(rd_scale_pct * rd_stats->rate + 0.5);
+ rd_stats->dist += (int64_t)(rd_scale_pct * rd_stats->dist + 0.5);
+ rd_stats->sse += (int64_t)(rd_scale_pct * rd_stats->sse + 0.5);
+ rd_stats->zero_rate += (int)(rd_scale_pct * rd_stats->zero_rate + 0.5);
+}
+
+// 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,
+ 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) {
+ 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;
+
+ double rd_bias_scale = 0.0;
+ if (this_mbmi->motion_mode == WARPED_CAUSAL) {
+ rd_bias_scale = rd_warp_bias_scale_pct / 100.0;
+ } else if (this_mbmi->motion_mode == OBMC_CAUSAL) {
+ rd_bias_scale = rd_obmc_bias_scale_pct / 100.0;
+ }
+ if (rd_bias_scale <= 0.0) return;
+
+ scale_rdstats(rd_stats, rd_bias_scale);
+ scale_rdstats(rd_stats_y, rd_bias_scale);
+ scale_rdstats(rd_stats_uv, rd_bias_scale);
}
/*!\brief AV1 motion mode search
@@ -1843,6 +1848,11 @@ 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);
+
} else {
// Perform full transform search
int64_t skip_rd = INT64_MAX;
@@ -1868,10 +1878,28 @@ static int64_t motion_mode_rd(
continue;
}
const int skip_ctx = av1_get_skip_txfm_context(xd);
+ const int *skip_txfm_cost_ptr = mode_costs->skip_txfm_cost[skip_ctx];
+
+ if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1) {
+ inter_mode_data_push(tile_data, mbmi->bsize, rd_stats->sse,
+ rd_stats->dist,
+ rd_stats_y->rate + rd_stats_uv->rate +
+ skip_txfm_cost_ptr[mbmi->skip_txfm]);
+ }
+ // 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);
+ 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 int y_rate =
- rd_stats->skip_txfm
- ? x->mode_costs.skip_txfm_cost[skip_ctx][1]
- : (rd_stats_y->rate + x->mode_costs.skip_txfm_cost[skip_ctx][0]);
+ 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);
const int64_t curr_rd = RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist);
@@ -1880,12 +1908,6 @@ static int64_t motion_mode_rd(
ref_skip_rd[0] = skip_rd;
ref_skip_rd[1] = skip_rdy;
}
- if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1) {
- inter_mode_data_push(
- tile_data, mbmi->bsize, rd_stats->sse, rd_stats->dist,
- rd_stats_y->rate + rd_stats_uv->rate +
- mode_costs->skip_txfm_cost[skip_ctx][mbmi->skip_txfm]);
- }
}
if (this_mode == GLOBALMV || this_mode == GLOBAL_GLOBALMV) {
@@ -1909,15 +1931,7 @@ static int64_t motion_mode_rd(
if (mode_index == 0) {
args->simple_rd[this_mode][mbmi->ref_mv_idx][mbmi->ref_frame[0]] = tmp_rd;
}
- int64_t best_scaled_rd = best_rd;
- int64_t this_scaled_rd = tmp_rd;
- if (mode_index != 0)
- increase_motion_mode_rd(&best_mbmi, mbmi, &best_scaled_rd,
- &this_scaled_rd,
- cpi->sf.inter_sf.bias_warp_mode_rd_scale_pct,
- cpi->sf.inter_sf.bias_obmc_mode_rd_scale_pct);
-
- if (mode_index == 0 || this_scaled_rd < best_scaled_rd) {
+ if (mode_index == 0 || tmp_rd < best_rd) {
// Update best_rd data if this is the best motion mode so far
best_mbmi = *mbmi;
best_rd = tmp_rd;
@@ -3377,8 +3391,8 @@ static int64_t handle_inter_mode(
const THR_MODES mode_enum = get_prediction_mode_idx(
mbmi->mode, mbmi->ref_frame[0], mbmi->ref_frame[1]);
// Collect mode stats for multiwinner mode processing
- store_winner_mode_stats(&cpi->common, x, mbmi, rd_stats, rd_stats_y,
- rd_stats_uv, mode_enum, NULL, bsize, tmp_rd,
+ store_winner_mode_stats(cpi, x, mbmi, rd_stats, rd_stats_y, rd_stats_uv,
+ mode_enum, NULL, bsize, tmp_rd,
cpi->sf.winner_mode_sf.multi_winner_mode_type,
do_tx_search);
if (tmp_rd < best_rd) {
@@ -3999,6 +4013,10 @@ 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);
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);
@@ -5166,10 +5184,11 @@ static int compare_int64(const void *a, const void *b) {
}
static inline void update_search_state(
- InterModeSearchState *search_state, RD_STATS *best_rd_stats_dst,
- PICK_MODE_CONTEXT *ctx, const RD_STATS *new_best_rd_stats,
- const RD_STATS *new_best_rd_stats_y, const RD_STATS *new_best_rd_stats_uv,
- THR_MODES new_best_mode, const MACROBLOCK *x, int txfm_search_done) {
+ const AV1_COMP *cpi, InterModeSearchState *search_state,
+ RD_STATS *best_rd_stats_dst, PICK_MODE_CONTEXT *ctx,
+ const RD_STATS *new_best_rd_stats, const RD_STATS *new_best_rd_stats_y,
+ const RD_STATS *new_best_rd_stats_uv, THR_MODES new_best_mode,
+ const MACROBLOCK *x, int txfm_search_done) {
const MACROBLOCKD *xd = &x->e_mbd;
const MB_MODE_INFO *mbmi = xd->mi[0];
const int skip_ctx = av1_get_skip_txfm_context(xd);
@@ -5187,10 +5206,13 @@ static inline void update_search_state(
// Therefore, we should avoid updating best_rate_y and best_rate_uv here.
// These two values will be updated when av1_txfm_search is called.
if (txfm_search_done) {
- search_state->best_rate_y =
- new_best_rd_stats_y->rate +
+ 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);
+ 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;
}
search_state->best_y_rdcost = *new_best_rd_stats_y;
@@ -5289,22 +5311,15 @@ static inline void evaluate_motion_mode_for_winner_candidates(
mbmi->mode, mbmi->ref_frame[0], mbmi->ref_frame[1]);
// Collect mode stats for multiwinner mode processing
store_winner_mode_stats(
- &cpi->common, x, mbmi, &rd_stats, &rd_stats_y, &rd_stats_uv,
- mode_enum, NULL, bsize, rd_stats.rdcost,
- cpi->sf.winner_mode_sf.multi_winner_mode_type, do_tx_search);
-
- int64_t best_scaled_rd = search_state->best_rd;
- int64_t this_scaled_rd = rd_stats.rdcost;
- if (search_state->best_mode_index != THR_INVALID)
- increase_motion_mode_rd(&search_state->best_mbmode, mbmi,
- &best_scaled_rd, &this_scaled_rd,
- cpi->sf.inter_sf.bias_warp_mode_rd_scale_pct,
- cpi->sf.inter_sf.bias_obmc_mode_rd_scale_pct);
-
- if (this_scaled_rd < best_scaled_rd) {
+ cpi, x, mbmi, &rd_stats, &rd_stats_y, &rd_stats_uv, mode_enum, NULL,
+ bsize, rd_stats.rdcost, cpi->sf.winner_mode_sf.multi_winner_mode_type,
+ do_tx_search);
+
+ if (rd_stats.rdcost < search_state->best_rd) {
*yrd = this_yrd;
- update_search_state(search_state, rd_cost, ctx, &rd_stats, &rd_stats_y,
- &rd_stats_uv, mode_enum, x, do_tx_search);
+ update_search_state(cpi, search_state, rd_cost, ctx, &rd_stats,
+ &rd_stats_y, &rd_stats_uv, mode_enum, x,
+ do_tx_search);
if (do_tx_search) search_state->best_skip_rd[0] = skip_rd[0];
}
}
@@ -5509,8 +5524,8 @@ static void tx_search_best_inter_candidates(
search_state->best_mode_index = THR_INVALID;
// Initialize best mode stats for winner mode processing
x->winner_mode_count = 0;
- store_winner_mode_stats(&cpi->common, x, mbmi, NULL, NULL, NULL, THR_INVALID,
- NULL, bsize, best_rd_so_far,
+ store_winner_mode_stats(cpi, x, mbmi, NULL, NULL, NULL, THR_INVALID, NULL,
+ bsize, best_rd_so_far,
cpi->sf.winner_mode_sf.multi_winner_mode_type, 0);
inter_modes_info->num =
inter_modes_info->num < cpi->sf.rt_sf.num_inter_modes_for_tx_search
@@ -5613,18 +5628,25 @@ static void tx_search_best_inter_candidates(
mode_rate, search_state->best_rd)) {
continue;
} else {
- const int y_rate =
- rd_stats.skip_txfm
- ? mode_costs->skip_txfm_cost[skip_ctx][1]
- : (rd_stats_y.rate + mode_costs->skip_txfm_cost[skip_ctx][0]);
- this_yrd = RDCOST(x->rdmult, y_rate + mode_rate, rd_stats_y.dist);
-
if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1) {
inter_mode_data_push(
tile_data, mbmi->bsize, rd_stats.sse, rd_stats.dist,
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);
+ 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 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);
}
rd_stats.rdcost = RDCOST(x->rdmult, rd_stats.rate, rd_stats.dist);
@@ -5634,25 +5656,20 @@ static void tx_search_best_inter_candidates(
// Collect mode stats for multiwinner mode processing
const int txfm_search_done = 1;
- store_winner_mode_stats(
- &cpi->common, x, mbmi, &rd_stats, &rd_stats_y, &rd_stats_uv, mode_enum,
- NULL, bsize, rd_stats.rdcost,
- cpi->sf.winner_mode_sf.multi_winner_mode_type, txfm_search_done);
-
- int64_t best_scaled_rd = search_state->best_rd;
- int64_t this_scaled_rd = rd_stats.rdcost;
- increase_motion_mode_rd(&search_state->best_mbmode, mbmi, &best_scaled_rd,
- &this_scaled_rd,
- cpi->sf.inter_sf.bias_warp_mode_rd_scale_pct,
- cpi->sf.inter_sf.bias_obmc_mode_rd_scale_pct);
- if (this_scaled_rd < best_rd_in_this_partition) {
+ store_winner_mode_stats(cpi, x, mbmi, &rd_stats, &rd_stats_y, &rd_stats_uv,
+ mode_enum, NULL, bsize, rd_stats.rdcost,
+ cpi->sf.winner_mode_sf.multi_winner_mode_type,
+ txfm_search_done);
+
+ if (rd_stats.rdcost < best_rd_in_this_partition) {
best_rd_in_this_partition = rd_stats.rdcost;
*yrd = this_yrd;
}
- if (this_scaled_rd < best_scaled_rd) {
- update_search_state(search_state, rd_cost, ctx, &rd_stats, &rd_stats_y,
- &rd_stats_uv, mode_enum, x, txfm_search_done);
+ if (rd_stats.rdcost < search_state->best_rd) {
+ update_search_state(cpi, search_state, rd_cost, ctx, &rd_stats,
+ &rd_stats_y, &rd_stats_uv, mode_enum, x,
+ txfm_search_done);
search_state->best_skip_rd[0] = skip_rd;
// Limit the total number of modes to be evaluated if the first is valid
// and transform skip or compound
@@ -5948,11 +5965,11 @@ static inline void search_intra_modes_in_interframe(
// Collect mode stats for multiwinner mode processing
const int txfm_search_done = 1;
store_winner_mode_stats(
- &cpi->common, x, mbmi, &intra_rd_stats, &best_intra_rd_stats_y,
- &intra_rd_stats_uv, best_mode_enum, NULL, bsize, intra_rd_stats.rdcost,
+ cpi, x, mbmi, &intra_rd_stats, &best_intra_rd_stats_y, &intra_rd_stats_uv,
+ best_mode_enum, NULL, bsize, intra_rd_stats.rdcost,
cpi->sf.winner_mode_sf.multi_winner_mode_type, txfm_search_done);
if (intra_rd_stats.rdcost < search_state->best_rd) {
- update_search_state(search_state, rd_cost, ctx, &intra_rd_stats,
+ update_search_state(cpi, search_state, rd_cost, ctx, &intra_rd_stats,
&best_intra_rd_stats_y, &intra_rd_stats_uv,
best_mode_enum, x, txfm_search_done);
}
@@ -6293,8 +6310,8 @@ void av1_rd_pick_inter_mode(struct AV1_COMP *cpi, struct TileDataEnc *tile_data,
winner_mode_count_allowed[sf->winner_mode_sf.multi_winner_mode_type];
zero_winner_mode_stats(bsize, max_winner_mode_count, x->winner_mode_stats);
x->winner_mode_count = 0;
- store_winner_mode_stats(&cpi->common, x, mbmi, NULL, NULL, NULL, THR_INVALID,
- NULL, bsize, best_rd_so_far,
+ store_winner_mode_stats(cpi, x, mbmi, NULL, NULL, NULL, THR_INVALID, NULL,
+ bsize, best_rd_so_far,
sf->winner_mode_sf.multi_winner_mode_type, 0);
int mode_thresh_mul_fact = (1 << MODE_THRESH_QBITS);
@@ -6440,8 +6457,9 @@ void av1_rd_pick_inter_mode(struct AV1_COMP *cpi, struct TileDataEnc *tile_data,
cm->current_frame.reference_mode != SINGLE_REFERENCE));
search_state.best_pred_sse = x->pred_sse[ref_frame];
best_inter_yrd = this_yrd;
- update_search_state(&search_state, rd_cost, ctx, &rd_stats, &rd_stats_y,
- &rd_stats_uv, mode_enum, x, do_tx_search);
+ update_search_state(cpi, &search_state, rd_cost, ctx, &rd_stats,
+ &rd_stats_y, &rd_stats_uv, mode_enum, x,
+ do_tx_search);
if (do_tx_search) search_state.best_skip_rd[0] = skip_rd[0];
// skip_rd[0] is the best total rd for a skip mode so far.
// skip_rd[1] is the best total rd for a skip mode so far in luma.
diff --git a/av1/encoder/rdopt_utils.h b/av1/encoder/rdopt_utils.h
index 1474be981a..9e93fa246b 100644
--- a/av1/encoder/rdopt_utils.h
+++ b/av1/encoder/rdopt_utils.h
@@ -689,6 +689,23 @@ 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) {
+ double rd_bias_scale = 0.0;
+ if (this_mbmi->motion_mode == WARPED_CAUSAL) {
+ rd_bias_scale = rd_warp_bias_scale_pct / 100.0;
+ } else if (this_mbmi->motion_mode == OBMC_CAUSAL) {
+ rd_bias_scale = rd_obmc_bias_scale_pct / 100.0;
+ }
+ if (rd_bias_scale <= 0.0) return rate;
+
+ int scaled_rate = rate;
+ scaled_rate += (int)(rd_bias_scale * rate + 0.5);
+ return scaled_rate;
+}
+
// Similar to store_cfl_required(), but for use during the RDO process,
// where we haven't yet determined whether this block uses CfL.
static inline CFL_ALLOWED_TYPE store_cfl_required_rdo(const AV1_COMMON *cm,
@@ -718,10 +735,11 @@ static inline void init_sbuv_mode(MB_MODE_INFO *const mbmi) {
// Store best mode stats for winner mode processing
static inline void store_winner_mode_stats(
- const AV1_COMMON *const cm, MACROBLOCK *x, const MB_MODE_INFO *mbmi,
+ const AV1_COMP *cpi, MACROBLOCK *x, const MB_MODE_INFO *mbmi,
RD_STATS *rd_cost, RD_STATS *rd_cost_y, RD_STATS *rd_cost_uv,
THR_MODES mode_index, uint8_t *color_map, BLOCK_SIZE bsize, int64_t this_rd,
int multi_winner_mode_type, int txfm_search_done) {
+ const AV1_COMMON *const cm = &cpi->common;
WinnerModeStats *winner_mode_stats = x->winner_mode_stats;
int mode_idx = 0;
int is_palette_mode = mbmi->palette_mode_info.palette_size[PLANE_TYPE_Y] > 0;
@@ -766,10 +784,13 @@ static inline void store_winner_mode_stats(
winner_mode_stats[mode_idx].rd_cost = *rd_cost;
if (txfm_search_done) {
- winner_mode_stats[mode_idx].rate_y =
- rd_cost_y->rate +
+ 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);
+ 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 7773464867..c2db5c295f 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -654,7 +654,7 @@ static void set_good_speed_features_lc_dec_framesize_dependent(
? 1
: 0;
- sf->inter_sf.bias_warp_mode_rd_scale_pct = 4;
+ sf->inter_sf.bias_warp_mode_rd_scale_pct = 2.5f;
sf->inter_sf.bias_obmc_mode_rd_scale_pct = 1.5f;
sf->part_sf.split_partition_penalty_level = is_key_frame ? 0 : 2;
@@ -678,7 +678,7 @@ static void set_good_speed_features_lc_dec_framesize_dependent(
? 1
: 0;
- sf->inter_sf.bias_warp_mode_rd_scale_pct = 4;
+ sf->inter_sf.bias_warp_mode_rd_scale_pct = 2.5f;
sf->inter_sf.bias_obmc_mode_rd_scale_pct = 1.5f;
sf->part_sf.split_partition_penalty_level = is_key_frame ? 0 : 2;
@@ -2414,7 +2414,7 @@ static inline void init_inter_sf(INTER_MODE_SPEED_FEATURES *inter_sf) {
inter_sf->limit_inter_mode_cands = 0;
inter_sf->limit_txfm_eval_per_mode = 0;
inter_sf->skip_arf_compound = 0;
- inter_sf->bias_warp_mode_rd_scale_pct = 0;
+ inter_sf->bias_warp_mode_rd_scale_pct = 0.0f;
inter_sf->bias_obmc_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;
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h
index 3b35fc21e7..1d5161ba61 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -1248,7 +1248,7 @@ typedef struct INTER_MODE_SPEED_FEATURES {
// Percentage of scaling used to increase the rd cost of warp mode so that
// encoder decisions are biased against local warp, favoring low complexity
// modes.
- int bias_warp_mode_rd_scale_pct;
+ float bias_warp_mode_rd_scale_pct;
// Percentage of scaling used to increase the rd cost of obmc motion mode so
// that encoder decisions are biased against local obmc, favoring low