Conduct less complex second MV search
When cpi->sf.mv_sf.disable_second_mv = 1, use var to decide the better
MV instead of rd cost. Set it to 1 for < 720p encoding to achieve a good
speed/quality tradeoff.
Borg test results at speed 2:
avg_psnr: ovr_psnr: ssim: speedup:
midres2: 0.037 0.037 0.047 2.8%
STATS_CHANGED
Change-Id: If3f222ff9c7a56e6d90037bdd5d3358538614812
diff --git a/av1/encoder/motion_search_facade.c b/av1/encoder/motion_search_facade.c
index 14050f2..96b77b7 100644
--- a/av1/encoder/motion_search_facade.c
+++ b/av1/encoder/motion_search_facade.c
@@ -304,8 +304,8 @@
if (cpi->sf.mv_sf.use_accurate_subpel_search) {
const int try_second = second_best_mv.as_int != INVALID_MV &&
second_best_mv.as_int != best_mv->as_int &&
- !cpi->sf.mv_sf.disable_second_mv;
- mv_search_params->find_fractional_mv_step(
+ (cpi->sf.mv_sf.disable_second_mv <= 1);
+ const int best_mv_var = mv_search_params->find_fractional_mv_step(
xd, cm, &ms_params, subpel_start_mv, &best_mv->as_mv, &dis,
&x->pred_sse[ref], fractional_ms_list);
@@ -315,42 +315,55 @@
{ p[0].dst.buf, p[1].dst.buf, p[2].dst.buf },
{ p[0].dst.stride, p[1].dst.stride, p[2].dst.stride },
};
- mbmi->mv[0].as_mv = best_mv->as_mv;
- av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst,
- bsize, 0, 0);
- av1_subtract_plane(x, bsize, 0);
- RD_STATS this_rd_stats;
- av1_init_rd_stats(&this_rd_stats);
- av1_estimate_txfm_yrd(cpi, x, &this_rd_stats, INT64_MAX, bsize,
- max_txsize_rect_lookup[bsize]);
- int this_mv_rate = av1_mv_bit_cost(
- &best_mv->as_mv, &ref_mv, mv_costs->nmv_joint_cost,
- mv_costs->mv_cost_stack, MV_COST_WEIGHT);
- int64_t rd = RDCOST(x->rdmult, this_mv_rate + this_rd_stats.rate,
- this_rd_stats.dist);
+ int64_t rd = INT64_MAX;
+ if (!cpi->sf.mv_sf.disable_second_mv) {
+ // Calculate actual rd cost.
+ mbmi->mv[0].as_mv = best_mv->as_mv;
+ av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst,
+ bsize, 0, 0);
+ av1_subtract_plane(x, bsize, 0);
+ RD_STATS this_rd_stats;
+ av1_init_rd_stats(&this_rd_stats);
+ av1_estimate_txfm_yrd(cpi, x, &this_rd_stats, INT64_MAX, bsize,
+ max_txsize_rect_lookup[bsize]);
+ int this_mv_rate = av1_mv_bit_cost(
+ &best_mv->as_mv, &ref_mv, mv_costs->nmv_joint_cost,
+ mv_costs->mv_cost_stack, MV_COST_WEIGHT);
+ rd = RDCOST(x->rdmult, this_mv_rate + this_rd_stats.rate,
+ this_rd_stats.dist);
+ }
MV this_best_mv;
subpel_start_mv = get_mv_from_fullmv(&second_best_mv.as_fullmv);
if (av1_is_subpelmv_in_range(&ms_params.mv_limits,
subpel_start_mv)) {
- mv_search_params->find_fractional_mv_step(
+ const int this_var = mv_search_params->find_fractional_mv_step(
xd, cm, &ms_params, subpel_start_mv, &this_best_mv, &dis,
&x->pred_sse[ref], fractional_ms_list);
- mbmi->mv[0].as_mv = this_best_mv;
- av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst,
- bsize, 0, 0);
- av1_subtract_plane(x, bsize, 0);
- RD_STATS tmp_rd_stats;
- av1_init_rd_stats(&tmp_rd_stats);
- av1_estimate_txfm_yrd(cpi, x, &tmp_rd_stats, INT64_MAX, bsize,
- max_txsize_rect_lookup[bsize]);
- int tmp_mv_rate = av1_mv_bit_cost(
- &this_best_mv, &ref_mv, mv_costs->nmv_joint_cost,
- mv_costs->mv_cost_stack, MV_COST_WEIGHT);
- int64_t tmp_rd =
- RDCOST(x->rdmult, tmp_rd_stats.rate + tmp_mv_rate,
- tmp_rd_stats.dist);
- if (tmp_rd < rd) best_mv->as_mv = this_best_mv;
+
+ if (!cpi->sf.mv_sf.disable_second_mv) {
+ // If cpi->sf.mv_sf.disable_second_mv is 0, use actual rd cost
+ // to choose the better MV.
+ mbmi->mv[0].as_mv = this_best_mv;
+ av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst,
+ bsize, 0, 0);
+ av1_subtract_plane(x, bsize, 0);
+ RD_STATS tmp_rd_stats;
+ av1_init_rd_stats(&tmp_rd_stats);
+ av1_estimate_txfm_yrd(cpi, x, &tmp_rd_stats, INT64_MAX, bsize,
+ max_txsize_rect_lookup[bsize]);
+ int tmp_mv_rate = av1_mv_bit_cost(
+ &this_best_mv, &ref_mv, mv_costs->nmv_joint_cost,
+ mv_costs->mv_cost_stack, MV_COST_WEIGHT);
+ int64_t tmp_rd =
+ RDCOST(x->rdmult, tmp_rd_stats.rate + tmp_mv_rate,
+ tmp_rd_stats.dist);
+ if (tmp_rd < rd) best_mv->as_mv = this_best_mv;
+ } else {
+ // If cpi->sf.mv_sf.disable_second_mv = 1, use var to decide the
+ // best MV.
+ if (this_var < best_mv_var) best_mv->as_mv = this_best_mv;
+ }
}
}
} else {
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index d04f1ec..7afba22 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -372,6 +372,8 @@
} else {
if (use_hbd) sf->tx_sf.prune_tx_size_level = 3;
}
+
+ if (!is_720p_or_larger) sf->mv_sf.disable_second_mv = 1;
}
if (speed >= 3) {
@@ -859,7 +861,7 @@
sf->mv_sf.full_pixel_search_level = 1;
sf->mv_sf.subpel_search_method = SUBPEL_TREE_PRUNED;
sf->mv_sf.search_method = DIAMOND;
- sf->mv_sf.disable_second_mv = 1;
+ sf->mv_sf.disable_second_mv = 2;
sf->inter_sf.mv_cost_upd_level = 1;
sf->inter_sf.disable_onesided_comp = 1;
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h
index 275cf02..a09a326 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -576,6 +576,9 @@
int disable_extensive_joint_motion_search;
// Enable second best mv check in joint mv search.
+ // 0: allow second MV (use rd cost as the metric)
+ // 1: use var as the metric
+ // 2: disable second MV
int disable_second_mv;
} MV_SPEED_FEATURES;