Enable dynamic motion vector referencing for newmv mode
This commit enables the dynamic motion vector predictor for NEWMV
mode. It allows the codec to select the best motion vector predictor
in a rate-distortion optimization framework for motion vector
residual coding. The compression performance is improved:
lowres 0.14%
midres 0.27%
hdres 0.24%
Change-Id: I6a601c74eb6cb0b71a613336d40363359f2edecd
diff --git a/vp10/decoder/decodemv.c b/vp10/decoder/decodemv.c
index eb336be..890f0e9 100644
--- a/vp10/decoder/decodemv.c
+++ b/vp10/decoder/decodemv.c
@@ -155,7 +155,29 @@
uint8_t ref_frame_type = vp10_ref_frame_type(mbmi->ref_frame);
mbmi->ref_mv_idx = 0;
- if (xd->ref_mv_count[ref_frame_type] > 2) {
+ if (xd->ref_mv_count[ref_frame_type] > 1 && mbmi->mode == NEWMV) {
+ uint8_t drl_ctx = vp10_drl_ctx(xd->ref_mv_stack[ref_frame_type], 0);
+ vpx_prob drl_prob = cm->fc->drl_prob0[drl_ctx];
+
+ if (!vpx_read(r, drl_prob)) {
+ mbmi->ref_mv_idx = 0;
+ return;
+ }
+ mbmi->ref_mv_idx = 1;
+
+ if (xd->ref_mv_count[ref_frame_type] > 2) {
+ drl_ctx = vp10_drl_ctx(xd->ref_mv_stack[ref_frame_type], 1);
+ drl_prob = cm->fc->drl_prob0[drl_ctx];
+ if (!vpx_read(r, drl_prob)) {
+ mbmi->ref_mv_idx = 1;
+ return;
+ }
+ mbmi->ref_mv_idx = 2;
+ }
+ return;
+ }
+
+ if (xd->ref_mv_count[ref_frame_type] > 2 && mbmi->mode == NEARMV) {
uint8_t drl0_ctx = vp10_drl_ctx(xd->ref_mv_stack[ref_frame_type], 1);
vpx_prob drl0_prob = cm->fc->drl_prob0[drl0_ctx];
if (vpx_read(r, drl0_prob)) {
@@ -1243,7 +1265,7 @@
#endif // CONFIG_REF_MV && CONFIG_EXT_INTER
r, mode_ctx);
#if CONFIG_REF_MV
- if (mbmi->mode == NEARMV)
+ if (mbmi->mode == NEARMV || mbmi->mode == NEWMV)
read_drl_idx(cm, xd, mbmi, r);
#endif
}
@@ -1436,6 +1458,22 @@
mbmi->mv[0].as_int = mi->bmi[3].as_mv[0].as_int;
mbmi->mv[1].as_int = mi->bmi[3].as_mv[1].as_int;
} else {
+ int ref;
+ for (ref = 0; ref < 1 + is_compound && mbmi->mode == NEWMV; ++ref) {
+ int_mv ref_mv = nearestmv[ref];
+#if CONFIG_REF_MV
+ uint8_t ref_frame_type = vp10_ref_frame_type(mbmi->ref_frame);
+ if (xd->ref_mv_count[ref_frame_type] > 1) {
+ ref_mv = (ref == 0) ?
+ xd->ref_mv_stack[ref_frame_type][mbmi->ref_mv_idx].this_mv :
+ xd->ref_mv_stack[ref_frame_type][mbmi->ref_mv_idx].comp_mv;
+ clamp_mv_ref(&ref_mv.as_mv, xd->n8_w << 3, xd->n8_h << 3, xd);
+ lower_mv_precision(&ref_mv.as_mv, allow_hp);
+ }
+#endif
+ nearestmv[ref] = ref_mv;
+ }
+
xd->corrupted |= !assign_mv(cm, xd, mbmi->mode,
#if CONFIG_REF_MV
0,
diff --git a/vp10/encoder/bitstream.c b/vp10/encoder/bitstream.c
index f20c224..56d4c4b 100644
--- a/vp10/encoder/bitstream.c
+++ b/vp10/encoder/bitstream.c
@@ -193,7 +193,31 @@
const MB_MODE_INFO_EXT *mbmi_ext,
vpx_writer *w) {
uint8_t ref_frame_type = vp10_ref_frame_type(mbmi->ref_frame);
- if (mbmi_ext->ref_mv_count[ref_frame_type] > 2) {
+
+ assert(mbmi->ref_mv_idx < 3);
+
+ if (mbmi_ext->ref_mv_count[ref_frame_type] > 1 && mbmi->mode == NEWMV) {
+ uint8_t drl_ctx =
+ vp10_drl_ctx(mbmi_ext->ref_mv_stack[ref_frame_type], 0);
+ vpx_prob drl_prob = cm->fc->drl_prob0[drl_ctx];
+
+ vpx_write(w, mbmi->ref_mv_idx != 0, drl_prob);
+ if (mbmi->ref_mv_idx == 0)
+ return;
+
+ if (mbmi_ext->ref_mv_count[ref_frame_type] > 2) {
+ drl_ctx = vp10_drl_ctx(mbmi_ext->ref_mv_stack[ref_frame_type], 1);
+ drl_prob = cm->fc->drl_prob0[drl_ctx];
+ vpx_write(w, mbmi->ref_mv_idx != 1, drl_prob);
+ }
+ if (mbmi->ref_mv_idx == 1)
+ return;
+
+ assert(mbmi->ref_mv_idx == 2);
+ return;
+ }
+
+ if (mbmi_ext->ref_mv_count[ref_frame_type] > 2 && mbmi->mode == NEARMV) {
uint8_t drl0_ctx =
vp10_drl_ctx(mbmi_ext->ref_mv_stack[ref_frame_type], 1);
vpx_prob drl0_prob = cm->fc->drl_prob0[drl0_ctx];
@@ -1088,7 +1112,7 @@
mode_ctx);
#if CONFIG_REF_MV
- if (mode == NEARMV)
+ if (mode == NEARMV || mode == NEWMV)
write_drl_idx(cm, mbmi, mbmi_ext, w);
#endif
}
@@ -1175,13 +1199,15 @@
#else
if (mode == NEWMV) {
#endif // CONFIG_EXT_INTER
+ int_mv ref_mv;
for (ref = 0; ref < 1 + is_compound; ++ref) {
#if CONFIG_REF_MV
- int nmv_ctx =
- vp10_nmv_ctx(mbmi_ext->ref_mv_count[mbmi->ref_frame[ref]],
- mbmi_ext->ref_mv_stack[mbmi->ref_frame[ref]]);
- const nmv_context *nmvc = &cm->fc->nmvc[nmv_ctx];
+ int nmv_ctx =
+ vp10_nmv_ctx(mbmi_ext->ref_mv_count[mbmi->ref_frame[ref]],
+ mbmi_ext->ref_mv_stack[mbmi->ref_frame[ref]]);
+ const nmv_context *nmvc = &cm->fc->nmvc[nmv_ctx];
#endif
+ ref_mv = mbmi_ext->ref_mvs[mbmi->ref_frame[ref]][0];
#if CONFIG_EXT_INTER
if (mode == NEWFROMNEARMV)
vp10_encode_mv(cpi, w, &mbmi->mv[ref].as_mv,
@@ -1190,8 +1216,8 @@
else
#endif // CONFIG_EXT_INTER
vp10_encode_mv(cpi, w, &mbmi->mv[ref].as_mv,
- &mbmi_ext->ref_mvs[mbmi->ref_frame[ref]][0].as_mv, nmvc,
- allow_hp);
+ &ref_mv.as_mv, nmvc,
+ allow_hp);
}
#if CONFIG_EXT_INTER
} else if (mode == NEAREST_NEWMV || mode == NEAR_NEWMV) {
diff --git a/vp10/encoder/encodeframe.c b/vp10/encoder/encodeframe.c
index ec00b62..1bae266 100644
--- a/vp10/encoder/encodeframe.c
+++ b/vp10/encoder/encodeframe.c
@@ -1085,6 +1085,10 @@
const int mi_height = num_8x8_blocks_high_lookup[bsize];
int max_plane;
+#if CONFIG_REF_MV
+ int8_t rf_type;
+#endif
+
#if !CONFIG_SUPERTX
assert(mi->mbmi.sb_type == bsize);
#endif
@@ -1092,6 +1096,23 @@
*mi_addr = *mi;
*x->mbmi_ext = ctx->mbmi_ext;
+#if CONFIG_REF_MV
+ rf_type = vp10_ref_frame_type(mbmi->ref_frame);
+ if (x->mbmi_ext->ref_mv_count[rf_type] > 1 &&
+ mbmi->sb_type >= BLOCK_8X8 &&
+ mbmi->mode == NEWMV) {
+ for (i = 0; i < 1 + has_second_ref(mbmi); ++i) {
+ int_mv this_mv = (i == 0) ?
+ x->mbmi_ext->ref_mv_stack[rf_type][mbmi->ref_mv_idx].this_mv :
+ x->mbmi_ext->ref_mv_stack[rf_type][mbmi->ref_mv_idx].comp_mv;
+ clamp_mv_ref(&this_mv.as_mv, xd->n8_w << 3, xd->n8_h << 3, xd);
+ lower_mv_precision(&this_mv.as_mv, cm->allow_high_precision_mv);
+ x->mbmi_ext->ref_mvs[mbmi->ref_frame[i]][0] = this_mv;
+ mbmi->pred_mv[i] = this_mv;
+ }
+ }
+#endif
+
// If segmentation in use
if (seg->enabled) {
// For in frame complexity AQ copy the segment id from the segment map.
@@ -1231,11 +1252,32 @@
cm->cur_frame->mvs + mi_row * cm->mi_cols + mi_col;
int w, h;
+#if CONFIG_REF_MV
+ int8_t rf_type;
+#endif
+
*mi_addr = *mi;
*x->mbmi_ext = ctx->mbmi_ext;
assert(is_inter_block(mbmi));
assert(mbmi->tx_size == ctx->mic.mbmi.tx_size);
+#if CONFIG_REF_MV
+ rf_type = vp10_ref_frame_type(mbmi->ref_frame);
+ if (x->mbmi_ext->ref_mv_count[rf_type] > 1 &&
+ mbmi->sb_type >= BLOCK_8X8 &&
+ mbmi->mode == NEWMV) {
+ for (i = 0; i < 1 + has_second_ref(mbmi); ++i) {
+ int_mv this_mv = (i == 0) ?
+ x->mbmi_ext->ref_mv_stack[rf_type][mbmi->ref_mv_idx].this_mv :
+ x->mbmi_ext->ref_mv_stack[rf_type][mbmi->ref_mv_idx].comp_mv;
+ clamp_mv_ref(&this_mv.as_mv, xd->n8_w << 3, xd->n8_h << 3, xd);
+ lower_mv_precision(&this_mv.as_mv, cm->allow_high_precision_mv);
+ x->mbmi_ext->ref_mvs[mbmi->ref_frame[i]][0] = this_mv;
+ mbmi->pred_mv[i] = this_mv;
+ }
+ }
+#endif
+
// If segmentation in use
if (seg->enabled && output_enabled) {
// For in frame complexity AQ copy the segment id from the segment map.
diff --git a/vp10/encoder/rdopt.c b/vp10/encoder/rdopt.c
index 2b7d8f5..4ecfdd1 100644
--- a/vp10/encoder/rdopt.c
+++ b/vp10/encoder/rdopt.c
@@ -8015,6 +8015,13 @@
rate2 += intra_cost_penalty;
distortion2 = distortion_y + distortion_uv;
} else {
+#if CONFIG_REF_MV
+ int_mv backup_ref_mv[2];
+
+ backup_ref_mv[0] = mbmi_ext->ref_mvs[ref_frame][0];
+ if (comp_pred)
+ backup_ref_mv[1] = mbmi_ext->ref_mvs[second_ref_frame][0];
+#endif
#if CONFIG_EXT_INTER
if (second_ref_frame == INTRA_FRAME) {
mbmi->interintra_mode = best_intra_mode;
@@ -8033,6 +8040,19 @@
#if CONFIG_REF_MV
mbmi->ref_mv_idx = 0;
ref_frame_type = vp10_ref_frame_type(mbmi->ref_frame);
+
+ if (this_mode == NEWMV &&
+ mbmi_ext->ref_mv_count[ref_frame_type] > 1) {
+ int ref;
+ for (ref = 0; ref < 1 + comp_pred; ++ref) {
+ int_mv this_mv = (ref == 0) ?
+ mbmi_ext->ref_mv_stack[ref_frame_type][0].this_mv :
+ mbmi_ext->ref_mv_stack[ref_frame_type][0].comp_mv;
+ clamp_mv_ref(&this_mv.as_mv, xd->n8_w << 3, xd->n8_h << 3, xd);
+ lower_mv_precision(&this_mv.as_mv, cm->allow_high_precision_mv);
+ mbmi_ext->ref_mvs[mbmi->ref_frame[ref]][0] = this_mv;
+ }
+ }
#endif
this_rd = handle_inter_mode(cpi, x, bsize,
&rate2, &distortion2, &skippable,
@@ -8058,20 +8078,38 @@
#if CONFIG_REF_MV
// TODO(jingning): This needs some refactoring to improve code quality
// and reduce redundant steps.
- if (mbmi->mode == NEARMV &&
- mbmi_ext->ref_mv_count[ref_frame_type] > 2) {
+ if ((mbmi->mode == NEARMV &&
+ mbmi_ext->ref_mv_count[ref_frame_type] > 2) ||
+ (mbmi->mode == NEWMV &&
+ mbmi_ext->ref_mv_count[ref_frame_type] > 1)) {
int_mv backup_mv = frame_mv[NEARMV][ref_frame];
- int_mv cur_mv = mbmi_ext->ref_mv_stack[ref_frame][2].this_mv;
MB_MODE_INFO backup_mbmi = *mbmi;
int backup_skip = x->skip;
-
int64_t tmp_ref_rd = this_rd;
int ref_idx;
- int ref_set = VPXMIN(2, mbmi_ext->ref_mv_count[ref_frame_type] - 2);
- uint8_t drl0_ctx =
- vp10_drl_ctx(mbmi_ext->ref_mv_stack[ref_frame_type], 1);
- rate2 += cpi->drl_mode_cost0[drl0_ctx][0];
+ // TODO(jingning): This should be deprecated shortly.
+ int idx_offset = (mbmi->mode == NEARMV) ? 1 : 0;
+
+ int ref_set =
+ VPXMIN(2, mbmi_ext->ref_mv_count[ref_frame_type] - 1 - idx_offset);
+
+ uint8_t drl0_ctx = 0;
+ uint8_t drl_ctx = 0;
+
+ // Dummy
+ int_mv backup_fmv[2];
+ backup_fmv[0] = frame_mv[NEWMV][ref_frame];
+ if (comp_pred)
+ backup_fmv[1] = frame_mv[NEWMV][second_ref_frame];
+
+ if (mbmi->mode == NEARMV) {
+ drl0_ctx = vp10_drl_ctx(mbmi_ext->ref_mv_stack[ref_frame_type], 1);
+ rate2 += cpi->drl_mode_cost0[drl0_ctx][0];
+ } else {
+ drl_ctx = vp10_drl_ctx(mbmi_ext->ref_mv_stack[ref_frame_type], 0);
+ rate2 += cpi->drl_mode_cost0[drl_ctx][0];
+ }
if (this_rd < INT64_MAX) {
if (RDCOST(x->rdmult, x->rddiv, rate_y + rate_uv, distortion2) <
@@ -8097,8 +8135,24 @@
int tmp_skip = 1;
int64_t tmp_dist = 0, tmp_sse = 0;
int dummy_disable_skip = 0;
+ int ref;
+ int_mv cur_mv;
- cur_mv = mbmi_ext->ref_mv_stack[ref_frame][2 + ref_idx].this_mv;
+ mbmi->ref_mv_idx = 1 + ref_idx;
+
+ for (ref = 0; ref < 1 + comp_pred; ++ref) {
+ int_mv this_mv = (ref == 0) ?
+ mbmi_ext->ref_mv_stack[ref_frame_type]
+ [mbmi->ref_mv_idx].this_mv :
+ mbmi_ext->ref_mv_stack[ref_frame_type]
+ [mbmi->ref_mv_idx].comp_mv;
+ clamp_mv_ref(&this_mv.as_mv, xd->n8_w << 3, xd->n8_h << 3, xd);
+ lower_mv_precision(&this_mv.as_mv, cm->allow_high_precision_mv);
+ mbmi_ext->ref_mvs[mbmi->ref_frame[ref]][0] = this_mv;
+ }
+
+ cur_mv = mbmi_ext->ref_mv_stack[ref_frame]
+ [mbmi->ref_mv_idx + idx_offset].this_mv;
lower_mv_precision(&cur_mv.as_mv, cm->allow_high_precision_mv);
clamp_mv2(&cur_mv.as_mv, xd);
@@ -8117,7 +8171,6 @@
#else
int_mv dummy_single_newmv[MAX_REF_FRAMES] = { { 0 } };
#endif
- mbmi->ref_mv_idx = 1 + ref_idx;
frame_mv[NEARMV][ref_frame] = cur_mv;
tmp_alt_rd = handle_inter_mode(cpi, x, bsize,
@@ -8142,12 +8195,23 @@
&tmp_sse, best_rd);
}
- tmp_rate += cpi->drl_mode_cost0[drl0_ctx][1];
+ if (this_mode == NEARMV) {
+ tmp_rate += cpi->drl_mode_cost0[drl0_ctx][1];
+ if (mbmi_ext->ref_mv_count[ref_frame_type] > 3) {
+ uint8_t drl1_ctx =
+ vp10_drl_ctx(mbmi_ext->ref_mv_stack[ref_frame_type], 2);
+ tmp_rate += cpi->drl_mode_cost1[drl1_ctx][ref_idx];
+ }
+ }
- if (mbmi_ext->ref_mv_count[ref_frame_type] > 3) {
- uint8_t drl1_ctx =
- vp10_drl_ctx(mbmi_ext->ref_mv_stack[ref_frame_type], 2);
- tmp_rate += cpi->drl_mode_cost1[drl1_ctx][ref_idx];
+ if (this_mode == NEWMV) {
+ tmp_rate += cpi->drl_mode_cost0[drl_ctx][1];
+
+ if (mbmi_ext->ref_mv_count[ref_frame_type] > 2) {
+ uint8_t this_drl_ctx =
+ vp10_drl_ctx(mbmi_ext->ref_mv_stack[ref_frame_type], 1);
+ tmp_rate += cpi->drl_mode_cost0[this_drl_ctx][ref_idx];
+ }
}
if (tmp_alt_rd < INT64_MAX) {
@@ -8192,12 +8256,18 @@
}
frame_mv[NEARMV][ref_frame] = backup_mv;
+ frame_mv[NEWMV][ref_frame] = backup_fmv[0];
+ if (comp_pred)
+ frame_mv[NEWMV][second_ref_frame] = backup_fmv[1];
#if CONFIG_VAR_TX
for (i = 0; i < MAX_MB_PLANE; ++i)
memcpy(x->blk_skip[i], x->blk_skip_drl[i],
sizeof(uint8_t) * ctx->num_4x4_blk);
#endif
}
+ mbmi_ext->ref_mvs[ref_frame][0] = backup_ref_mv[0];
+ if (comp_pred)
+ mbmi_ext->ref_mvs[second_ref_frame][0] = backup_ref_mv[1];
#endif // CONFIG_REF_MV
if (this_rd == INT64_MAX)
@@ -8506,17 +8576,21 @@
#if CONFIG_REF_MV
const uint8_t rf_type = vp10_ref_frame_type(best_mbmode.ref_frame);
if (!comp_pred_mode) {
- if (best_mbmode.ref_mv_idx > 0 && refs[1] == NONE) {
- int idx = best_mbmode.ref_mv_idx + 1;
- int_mv cur_mv = mbmi_ext->ref_mv_stack[refs[0]][idx].this_mv;
+ int i;
+ int ref_set = (mbmi_ext->ref_mv_count[rf_type] >= 2) ?
+ VPXMIN(2, mbmi_ext->ref_mv_count[rf_type] - 2) : INT_MAX;
+
+ for (i = 0; i <= ref_set && ref_set != INT_MAX; ++i) {
+ int_mv cur_mv = mbmi_ext->ref_mv_stack[rf_type][i + 1].this_mv;
lower_mv_precision(&cur_mv.as_mv, cm->allow_high_precision_mv);
- frame_mv[NEARMV][refs[0]] = cur_mv;
+ if (cur_mv.as_int == best_mbmode.mv[0].as_int) {
+ best_mbmode.mode = NEARMV;
+ best_mbmode.ref_mv_idx = i;
+ }
}
if (frame_mv[NEARESTMV][refs[0]].as_int == best_mbmode.mv[0].as_int)
best_mbmode.mode = NEARESTMV;
- else if (frame_mv[NEARMV][refs[0]].as_int == best_mbmode.mv[0].as_int)
- best_mbmode.mode = NEARMV;
else if (best_mbmode.mv[0].as_int == 0)
best_mbmode.mode = ZEROMV;
} else {
@@ -8524,21 +8598,37 @@
const int allow_hp = cm->allow_high_precision_mv;
int_mv nearestmv[2] = { frame_mv[NEARESTMV][refs[0]],
frame_mv[NEARESTMV][refs[1]] };
-
int_mv nearmv[2] = { frame_mv[NEARMV][refs[0]],
frame_mv[NEARMV][refs[1]] };
+#if CONFIG_EXT_INTER
+ if (mbmi_ext->ref_mv_count[rf_type] > 1) {
+ nearmv[0] = mbmi_ext->ref_mv_stack[rf_type][1].this_mv;
+ nearmv[1] = mbmi_ext->ref_mv_stack[rf_type][1].comp_mv;
+ }
+#else
+ int ref_set = (mbmi_ext->ref_mv_count[rf_type] >= 2) ?
+ VPXMIN(2, mbmi_ext->ref_mv_count[rf_type] - 2) : INT_MAX;
+
+ for (i = 0; i <= ref_set && ref_set != INT_MAX; ++i) {
+ nearmv[0] = mbmi_ext->ref_mv_stack[rf_type][i + 1].this_mv;
+ nearmv[1] = mbmi_ext->ref_mv_stack[rf_type][i + 1].comp_mv;
+ lower_mv_precision(&nearmv[0].as_mv, allow_hp);
+ lower_mv_precision(&nearmv[1].as_mv, allow_hp);
+
+ if (nearmv[0].as_int == best_mbmode.mv[0].as_int &&
+ nearmv[1].as_int == best_mbmode.mv[1].as_int) {
+ best_mbmode.mode = NEARMV;
+ best_mbmode.ref_mv_idx = i;
+ }
+ }
+#endif
+
if (mbmi_ext->ref_mv_count[rf_type] >= 1) {
nearestmv[0] = mbmi_ext->ref_mv_stack[rf_type][0].this_mv;
nearestmv[1] = mbmi_ext->ref_mv_stack[rf_type][0].comp_mv;
}
- if (mbmi_ext->ref_mv_count[rf_type] > 1) {
- int ref_mv_idx = best_mbmode.ref_mv_idx + 1;
- nearmv[0] = mbmi_ext->ref_mv_stack[rf_type][ref_mv_idx].this_mv;
- nearmv[1] = mbmi_ext->ref_mv_stack[rf_type][ref_mv_idx].comp_mv;
- }
-
for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) {
lower_mv_precision(&nearestmv[i].as_mv, allow_hp);
lower_mv_precision(&nearmv[i].as_mv, allow_hp);
@@ -8558,9 +8648,6 @@
best_mbmode.mode = ZERO_ZEROMV;
#else
best_mbmode.mode = NEARESTMV;
- else if (nearmv[0].as_int == best_mbmode.mv[0].as_int &&
- nearmv[1].as_int == best_mbmode.mv[1].as_int)
- best_mbmode.mode = NEARMV;
else if (best_mbmode.mv[0].as_int == 0 && best_mbmode.mv[1].as_int == 0)
best_mbmode.mode = ZEROMV;
#endif // CONFIG_EXT_INTER