Store and use single_newmv correctly
The motion vector search result at single reference frame mode is stored
for later use. There are some issues in current implementation.
1. single_newmv is only stored for 1st ref_mv, but not for other ref_mv
values tested.
2. If single reference mode is skipped and not tested, single_newmv is
not available.
3. Interintra mode always use single_newmv as its MV, which may not be
available as mentioned above.
To fix it, we store single_newmv for every ref_mv tested. In interintra
mode, if single_newmv is not available, do motion search to find a MV.
This was revealed by a motion vector unit test failure.
BUG=aomedia:1190
Change-Id: I3e690587644d4c8c31337f37380b796a3d71a3f6
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index d14000d..31ab422 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -6049,8 +6049,6 @@
av1_setup_pre_planes(xd, ref_idx, scaled_ref_frame, mi_row, mi_col, NULL);
}
- av1_set_mv_search_range(&x->mv_limits, &ref_mv);
-
av1_set_mvcost(
x, ref, ref_idx,
mbmi->ref_mv_idx + (have_nearmv_in_inter_mode(mbmi->mode) ? 1 : 0));
@@ -6105,6 +6103,8 @@
}
}
+ // Note: MV limits are modified here. Always restore the original values
+ // after full-pixel motion search.
av1_set_mv_search_range(&x->mv_limits, &ref_mv);
if (mbmi->motion_mode != SIMPLE_TRANSLATION)
@@ -7011,6 +7011,7 @@
// Pointer to array of motion vectors to use for each ref and their rates
// Should point to first of 2 arrays in 2D array
int *single_newmv_rate;
+ int *single_newmv_valid;
// Pointer to array of predicted rate-distortion
// Should point to first of 2 arrays in 2D array
int64_t (*modelled_rd)[TOTAL_REFS_PER_FRAME];
@@ -7088,17 +7089,18 @@
}
}
} else {
- if (is_comp_interintra_pred) {
+ if (is_comp_interintra_pred && args->single_newmv_valid[refs[0]]) {
x->best_mv = args->single_newmv[refs[0]];
*rate_mv = args->single_newmv_rate[refs[0]];
} else {
single_motion_search(cpi, x, bsize, mi_row, mi_col, 0, rate_mv);
+ if (x->best_mv.as_int == INVALID_MV) return INT64_MAX;
+
args->single_newmv[refs[0]] = x->best_mv;
args->single_newmv_rate[refs[0]] = *rate_mv;
+ args->single_newmv_valid[refs[0]] = 1;
}
- if (x->best_mv.as_int == INVALID_MV) return INT64_MAX;
-
frame_mv[refs[0]] = x->best_mv;
// Estimate the rate implications of a new mv but discount this
@@ -7310,9 +7312,8 @@
int mi_col, HandleInterModeArgs *const args, const int64_t ref_best_rd,
const int *refs, int rate_mv,
// only used when WARPED_MOTION is on?
- int_mv *const single_newmv, int rate2_bmc_nocoeff,
- MB_MODE_INFO *best_bmc_mbmi, int rate_mv_bmc, int rs, int *skip_txfm_sb,
- int64_t *skip_sse_sb, BUFFER_SET *orig_dst) {
+ int rate2_bmc_nocoeff, MB_MODE_INFO *best_bmc_mbmi, int rate_mv_bmc, int rs,
+ int *skip_txfm_sb, int64_t *skip_sse_sb, BUFFER_SET *orig_dst) {
const AV1_COMMON *const cm = &cpi->common;
MACROBLOCKD *xd = &x->e_mbd;
MODE_INFO *mi = xd->mi[0];
@@ -7455,8 +7456,6 @@
if (cpi->sf.adaptive_motion_search)
x->pred_mv[ref] = mbmi->mv[0].as_mv;
- single_newmv[ref] = mbmi->mv[0];
-
if (discount_newmv_test(cpi, this_mode, mbmi->mv[0], mode_mv,
refs[0])) {
tmp_rate_mv = AOMMAX((tmp_rate_mv / NEW_MV_DISCOUNT_FACTOR), 1);
@@ -8381,11 +8380,11 @@
rd_stats->rate += compmode_interinter_cost;
- ret_val = motion_mode_rd(cpi, x, bsize, rd_stats, rd_stats_y, rd_stats_uv,
- disable_skip, mode_mv, mi_row, mi_col, args,
- ref_best_rd, refs, rate_mv, single_newmv,
- rate2_bmc_nocoeff, &best_bmc_mbmi, rate_mv_bmc, rs,
- &skip_txfm_sb, &skip_sse_sb, &orig_dst);
+ ret_val =
+ motion_mode_rd(cpi, x, bsize, rd_stats, rd_stats_y, rd_stats_uv,
+ disable_skip, mode_mv, mi_row, mi_col, args, ref_best_rd,
+ refs, rate_mv, rate2_bmc_nocoeff, &best_bmc_mbmi,
+ rate_mv_bmc, rs, &skip_txfm_sb, &skip_sse_sb, &orig_dst);
#if CONFIG_JNT_COMP
if (is_comp_pred && ret_val != INT64_MAX) {
int64_t tmp_rd;
@@ -8975,8 +8974,10 @@
int comp_pred, i, k;
int_mv frame_mv[MB_MODE_COUNT][TOTAL_REFS_PER_FRAME];
struct buf_2d yv12_mb[TOTAL_REFS_PER_FRAME][MAX_MB_PLANE];
- int_mv single_newmv[TOTAL_REFS_PER_FRAME] = { { 0 } };
- int single_newmv_rate[TOTAL_REFS_PER_FRAME] = { 0 };
+ // Save a set of single_newmv for each checked ref_mv.
+ int_mv single_newmv[MAX_REF_MV_SERCH][TOTAL_REFS_PER_FRAME] = { { { 0 } } };
+ int single_newmv_rate[MAX_REF_MV_SERCH][TOTAL_REFS_PER_FRAME] = { { 0 } };
+ int single_newmv_valid[MAX_REF_MV_SERCH][TOTAL_REFS_PER_FRAME] = { { 0 } };
int64_t modelled_rd[MB_MODE_COUNT][TOTAL_REFS_PER_FRAME];
static const int flag_list[TOTAL_REFS_PER_FRAME] = { 0,
AOM_LAST_FLAG,
@@ -9031,10 +9032,11 @@
const int mode_search_skip_flags = sf->mode_search_skip_flags;
HandleInterModeArgs args = {
- { NULL }, { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE },
- { NULL }, { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE },
- NULL, NULL,
- NULL, { { 0 } },
+ { NULL }, { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE },
+ { NULL }, { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE },
+ NULL, NULL,
+ NULL, NULL,
+ { { 0 } },
};
const int rows = block_size_high[bsize];
@@ -9785,8 +9787,9 @@
rd_stats.rate = rate2;
// Point to variables that are maintained between loop iterations
- args.single_newmv = single_newmv;
- args.single_newmv_rate = single_newmv_rate;
+ args.single_newmv = single_newmv[0];
+ args.single_newmv_rate = single_newmv_rate[0];
+ args.single_newmv_valid = single_newmv_valid[0];
args.modelled_rd = modelled_rd;
this_rd = handle_inter_mode(cpi, x, bsize, &rd_stats, &rd_stats_y,
&rd_stats_uv, &disable_skip, frame_mv,
@@ -9814,7 +9817,8 @@
// TODO(jingning): This should be deprecated shortly.
int idx_offset = have_nearmv_in_inter_mode(mbmi->mode) ? 1 : 0;
int ref_set =
- AOMMIN(2, mbmi_ext->ref_mv_count[ref_frame_type] - 1 - idx_offset);
+ AOMMIN(MAX_REF_MV_SERCH - 1,
+ mbmi_ext->ref_mv_count[ref_frame_type] - 1 - idx_offset);
uint8_t drl_ctx =
av1_drl_ctx(mbmi_ext->ref_mv_stack[ref_frame_type], idx_offset);
@@ -9904,22 +9908,21 @@
clamp_mv2(&cur_mv.as_mv, xd);
if (!mv_check_bounds(&x->mv_limits, &cur_mv.as_mv)) {
- int_mv dummy_single_newmv[TOTAL_REFS_PER_FRAME] = { { 0 } };
- int dummy_single_newmv_rate[TOTAL_REFS_PER_FRAME] = { 0 };
-
frame_mv[NEARMV][ref_frame] = cur_mv;
av1_init_rd_stats(&tmp_rd_stats);
- // Point to variables that are not maintained between iterations
- args.single_newmv = dummy_single_newmv;
- args.single_newmv_rate = dummy_single_newmv_rate;
args.modelled_rd = NULL;
+ args.single_newmv = single_newmv[mbmi->ref_mv_idx];
+ args.single_newmv_rate = single_newmv_rate[mbmi->ref_mv_idx];
+ args.single_newmv_valid = single_newmv_valid[mbmi->ref_mv_idx];
+
tmp_alt_rd = handle_inter_mode(
cpi, x, bsize, &tmp_rd_stats, &tmp_rd_stats_y, &tmp_rd_stats_uv,
&dummy_disable_skip, frame_mv, mi_row, mi_col, &args, best_rd);
// Prevent pointers from escaping local scope
- args.single_newmv = NULL;
- args.single_newmv_rate = NULL;
+ args.single_newmv = single_newmv[0];
+ args.single_newmv_rate = single_newmv_rate[0];
+ args.single_newmv_valid = single_newmv_valid[0];
}
for (i = 0; i < mbmi->ref_mv_idx; ++i) {