Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion av2/encoder/motion_search_facade.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,8 @@ void av2_single_motion_search(const AV2_COMP *const cpi, MACROBLOCK *x,
switch (mbmi->motion_mode) {
case SIMPLE_TRANSLATION:
if (cpi->sf.mv_sf.subpel_search_type) {
const int try_second = second_best_mv.as_int != INVALID_MV &&
const int try_second = !cpi->sf.mv_sf.skip_second_best_subpel &&
second_best_mv.as_int != INVALID_MV &&
second_best_mv.as_int != best_mv->as_int;
const int best_mv_var = mv_search_params->find_fractional_mv_step(
xd, cm, &ms_params, subpel_start_mv, &best_mv->as_mv, &dis,
Expand Down
66 changes: 66 additions & 0 deletions av2/encoder/rdopt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1428,6 +1428,72 @@ static int64_t handle_newmv(const AV2_COMP *const cpi, MACROBLOCK *const x,
mode_info, &start_mv, &best_mv);

} else {
// Predictive NEWMV reuse across the DRL. Two triggers select a match:
// Tier 1 (predict_repeated_newmv): match when reference MVs are
// within one full pel.
// Tier 2 (newmv_drl_search_limit): once ref_mv_idx reaches the limit,
// reuse the nearest searched result regardless of distance.
const int t1_active = cpi->sf.mv_sf.predict_repeated_newmv != 0;
const int drl_limit = cpi->sf.mv_sf.newmv_drl_search_limit;
const int t2_active =
drl_limit > 0 && mbmi->ref_mv_idx[ref_idx] >= drl_limit;
if ((t1_active || t2_active) && !mbmi->use_amvd &&
mbmi->ref_mv_idx[ref_idx] > 0) {
const MV ref_mv = av2_get_ref_mv(x, ref_idx).as_mv;
int near_diff = INT_MAX;
int near_idx = -1;
for (int idx = 0; idx < mbmi->ref_mv_idx[ref_idx]; ++idx) {
if (!args->single_newmv_valid[pb_mv_precision][idx][refs[0]])
continue;
const MV prev_ref_mv =
av2_get_ref_mv_from_stack(ref_idx, mbmi->ref_frame, idx,
x->mbmi_ext, mbmi)
.as_mv;
const int ref_mv_diff = AVMMAX(abs(ref_mv.row - prev_ref_mv.row),
abs(ref_mv.col - prev_ref_mv.col));
if (ref_mv_diff < near_diff) {
near_diff = ref_mv_diff;
near_idx = idx;
}
}
int best_match = -1;
// Reuse the nearest previously-searched ref-mv when Tier 1 (within
// one full pel -- (1 << 3) in 1/8-pel units) or Tier 2 (no distance
// cap) fires.
if (near_idx >= 0 &&
((t1_active && near_diff <= (1 << 3)) || t2_active)) {
best_match = near_idx;
}
if (best_match >= 0) {
const int_mv reuse_mv =
args->single_newmv[pb_mv_precision][best_match][refs[0]];
SubpelMvLimits mv_limits;
av2_set_subpel_mv_search_range(&mv_limits, &x->mv_limits, &ref_mv,
pb_mv_precision);
const int is_adaptive_mvd = enable_adaptive_mvd_resolution(cm, mbmi);
// The reused MV was searched against a different reference MV, so
// check that its MVD relative to the *current* reference MV is
// representable at pb_mv_precision (otherwise the decoder would
// reconstruct a different MV -- bitstream mismatch).
MV reuse_mvd;
get_mvd_from_ref_mv(reuse_mv.as_mv, ref_mv, is_adaptive_mvd,
pb_mv_precision, &reuse_mvd);
if (av2_is_subpelmv_in_range(&mv_limits, reuse_mv.as_mv) &&
is_this_mv_precision_compliant(reuse_mvd, pb_mv_precision)) {
*rate_mv =
av2_mv_bit_cost(&reuse_mv.as_mv, &ref_mv, pb_mv_precision,
&x->mv_costs, MV_COST_WEIGHT, is_adaptive_mvd);
const int cur_idx = get_ref_mv_idx(mbmi, 0);
args->single_newmv[pb_mv_precision][cur_idx][refs[0]] = reuse_mv;
args->single_newmv_rate[pb_mv_precision][cur_idx][refs[0]] =
*rate_mv;
args->single_newmv_valid[pb_mv_precision][cur_idx][refs[0]] = 1;
cur_mv[0].as_int = reuse_mv.as_int;
return 0;
}
}
}

int search_range = INT_MAX;
if (cpi->sf.mv_sf.reduce_search_range && mbmi->ref_mv_idx[0] > 0) {
const MV ref_mv = av2_get_ref_mv(x, ref_idx).as_mv;
Expand Down
14 changes: 14 additions & 0 deletions av2/encoder/speed_features.c
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,17 @@ static void set_good_speed_features_framesize_independent(
sf->tx_sf.adaptive_tx_partition_type_search_idx = 4;

sf->inter_sf.prune_comp_search_by_single_result = boosted ? 2 : 1;

// Skip the second-best full-pel candidate's subpel refinement in the
// single-ref NEWMV search.
sf->mv_sf.skip_second_best_subpel = 1;

// Predictive single-ref NEWMV reuse across the DRL.
sf->mv_sf.predict_repeated_newmv = 1;

// Cap the DRL depth for a fresh single-ref NEWMV search; reuse the
// nearest searched result beyond the cap.
sf->mv_sf.newmv_drl_search_limit = 2;
}

if (speed >= 2) {
Expand Down Expand Up @@ -655,6 +666,9 @@ static AVM_INLINE void init_mv_sf(MV_SPEED_FEATURES *mv_sf) {
mv_sf->exhaustive_searches_thresh = 0;
mv_sf->prune_mesh_search = 0;
mv_sf->reduce_search_range = 0;
mv_sf->skip_second_best_subpel = 0;
mv_sf->predict_repeated_newmv = 0;
mv_sf->newmv_drl_search_limit = 0;
mv_sf->search_method = NSTEP;
mv_sf->simple_motion_subpel_force_stop = EIGHTH_PEL;
mv_sf->subpel_force_stop = EIGHTH_PEL;
Expand Down
15 changes: 15 additions & 0 deletions av2/encoder/speed_features.h
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,21 @@ typedef struct MV_SPEED_FEATURES {
// Reduce single motion search range based on MV result of prior ref_mv_idx.
int reduce_search_range;

// When set, skip the second-best full-pel candidate's subpel refinement in
// the single-ref NEWMV search.
int skip_second_best_subpel;

// Predictively reuse single-ref NEWMV results across the DRL.
// 0: off
// 1: reuse when reference MVs are within one full pel.
int predict_repeated_newmv;

// Cap the DRL depth that runs a fresh single-ref NEWMV motion search;
// beyond the cap, reuse the nearest searched result.
// 0: off (no cap).
// K: search ref_mv_idx 0..K-1, reuse for ref_mv_idx >= K.
int newmv_drl_search_limit;

// Prune mesh search.
int prune_mesh_search;

Expand Down