intrabc: Add a DV prediction scheme derived from ref_mv

wikipedia_420.y4m
PSNR: -1.5035 PSNR-HVS: -1.2607 SSIM: -1.1581

Change-Id: I6e6c4bd9671427b99299df39ff0f42af7daf8ce7
diff --git a/av1/common/mvref_common.c b/av1/common/mvref_common.c
index db36b64..d558111 100644
--- a/av1/common/mvref_common.c
+++ b/av1/common/mvref_common.c
@@ -586,6 +586,9 @@
           ? cm->prev_frame->mvs + mi_row * cm->mi_cols + mi_col
           : NULL;
 #endif
+#if CONFIG_INTRABC
+  assert(IMPLIES(ref_frame == INTRA_FRAME, cm->use_prev_frame_mvs == 0));
+#endif
   const TileInfo *const tile = &xd->tile;
   const BLOCK_SIZE bsize = mi->mbmi.sb_type;
   const int bw = block_size_wide[AOMMAX(bsize, BLOCK_8X8)];
diff --git a/av1/common/mvref_common.h b/av1/common/mvref_common.h
index b4747c6..7ed836e 100644
--- a/av1/common/mvref_common.h
+++ b/av1/common/mvref_common.h
@@ -267,8 +267,12 @@
   } else {
     rf[0] = ref_frame_type;
     rf[1] = NONE_FRAME;
-    assert(ref_frame_type > INTRA_FRAME &&
-           ref_frame_type < TOTAL_REFS_PER_FRAME);
+#if CONFIG_INTRABC
+    assert(ref_frame_type > NONE_FRAME);
+#else
+    assert(ref_frame_type > INTRA_FRAME);
+#endif
+    assert(ref_frame_type < TOTAL_REFS_PER_FRAME);
   }
 }
 
diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c
index af226fa..d155435 100644
--- a/av1/decoder/decodemv.c
+++ b/av1/decoder/decodemv.c
@@ -1045,7 +1045,6 @@
   read_mv(r, &mv->as_mv, &ref_mv->as_mv, &ec_ctx->ndvc, dv_counts, 0);
   int valid = is_mv_valid(&mv->as_mv) &&
               is_dv_valid(mv->as_mv, &xd->tile, mi_row, mi_col, bsize);
-  // TODO(aconverse@google.com): additional validation
   return valid;
 }
 #endif  // CONFIG_INTRABC
@@ -1103,14 +1102,29 @@
   if (bsize >= BLOCK_8X8 && cm->allow_screen_content_tools) {
     mbmi->use_intrabc = aom_read(r, INTRABC_PROB, ACCT_STR);
     if (mbmi->use_intrabc) {
-      int_mv dv_ref;
       mbmi->mode = mbmi->uv_mode = DC_PRED;
 #if CONFIG_DUAL_FILTER
       for (int idx = 0; idx < 4; ++idx) mbmi->interp_filter[idx] = BILINEAR;
 #else
       mbmi->interp_filter = BILINEAR;
 #endif
-      av1_find_ref_dv(&dv_ref, mi_row, mi_col);
+
+      int16_t inter_mode_ctx[MODE_CTX_REF_FRAMES];
+      int_mv ref_mvs[MAX_MV_REF_CANDIDATES] = {};
+
+      av1_find_mv_refs(cm, xd, mi, INTRA_FRAME, &xd->ref_mv_count[INTRA_FRAME],
+                       xd->ref_mv_stack[INTRA_FRAME],
+#if CONFIG_EXT_INTER
+                       compound_inter_mode_ctx,
+#endif  // CONFIG_EXT_INTER
+                       ref_mvs, mi_row, mi_col, NULL, NULL, inter_mode_ctx);
+
+      int_mv nearestmv, nearmv;
+      av1_find_best_ref_mvs(0, ref_mvs, &nearestmv, &nearmv);
+
+      int_mv dv_ref = nearestmv.as_int == 0 ? nearmv : nearestmv;
+      if (dv_ref.as_int == 0) av1_find_ref_dv(&dv_ref, mi_row, mi_col);
+
       xd->corrupted |=
           !assign_dv(cm, xd, &mbmi->mv[0], &dv_ref, mi_row, mi_col, bsize, r);
 #if CONFIG_EXT_TX && !CONFIG_TXK_SEL
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index 52d95d7..4be8557 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -2144,6 +2144,9 @@
 #else
                               const MACROBLOCKD *xd,
 #endif  // CONFIG_DELTA_Q
+#if CONFIG_INTRABC
+                              const MB_MODE_INFO_EXT *mbmi_ext,
+#endif  // CONFIG_INTRABC
                               const int mi_row, const int mi_col,
                               aom_writer *w) {
   const struct segmentation *const seg = &cm->seg;
@@ -2215,8 +2218,7 @@
     if (use_intrabc) {
       assert(mbmi->mode == DC_PRED);
       assert(mbmi->uv_mode == DC_PRED);
-      int_mv dv_ref;
-      av1_find_ref_dv(&dv_ref, mi_row, mi_col);
+      int_mv dv_ref = mbmi_ext->ref_mvs[INTRA_FRAME][0];
       av1_encode_dv(w, &mbmi->mv[0].as_mv, &dv_ref.as_mv, &ec_ctx->ndvc);
 #if CONFIG_EXT_TX && !CONFIG_TXK_SEL
       av1_write_tx_type(cm, xd,
@@ -2365,7 +2367,11 @@
                  cm->mi_rows, cm->mi_cols);
 
   if (frame_is_intra_only(cm)) {
-    write_mb_modes_kf(cm, xd, mi_row, mi_col, w);
+    write_mb_modes_kf(cm, xd,
+#if CONFIG_INTRABC
+                      cpi->td.mb.mbmi_ext,
+#endif  // CONFIG_INTRABC
+                      mi_row, mi_col, w);
   } else {
 #if CONFIG_VAR_TX
     xd->above_txfm_context = cm->above_txfm_context + mi_col;
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index 61c3404..28c9138 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -9065,11 +9065,25 @@
   const int h = block_size_high[bsize];
   const int sb_row = mi_row / MAX_MIB_SIZE;
 
-  int_mv dv_ref;
-  av1_find_ref_dv(&dv_ref, mi_row, mi_col);
+  MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
+  MV_REFERENCE_FRAME ref_frame = INTRA_FRAME;
+  int_mv *const candidates = x->mbmi_ext->ref_mvs[ref_frame];
+  av1_find_mv_refs(cm, xd, mi, ref_frame, &mbmi_ext->ref_mv_count[ref_frame],
+                   mbmi_ext->ref_mv_stack[ref_frame],
+#if CONFIG_EXT_INTER
+                   mbmi_ext->compound_mode_context,
+#endif  // CONFIG_EXT_INTER
+                   candidates, mi_row, mi_col, NULL, NULL,
+                   mbmi_ext->mode_context);
+
+  int_mv nearestmv, nearmv;
+  av1_find_best_ref_mvs(0, candidates, &nearestmv, &nearmv);
+
+  int_mv dv_ref = nearestmv.as_int == 0 ? nearmv : nearestmv;
+  if (dv_ref.as_int == 0) av1_find_ref_dv(&dv_ref, mi_row, mi_col);
+  mbmi_ext->ref_mvs[INTRA_FRAME][0] = dv_ref;
 
   const MvLimits tmp_mv_limits = x->mv_limits;
-
   // TODO(aconverse@google.com): Handle same row DV.
   x->mv_limits.col_min = (tile->mi_col_start - mi_col) * MI_SIZE;
   x->mv_limits.col_max = (tile->mi_col_end - mi_col) * MI_SIZE - w;
@@ -9198,6 +9212,7 @@
   xd->mi[0]->mbmi.ref_frame[1] = NONE_FRAME;
 #if CONFIG_INTRABC
   xd->mi[0]->mbmi.use_intrabc = 0;
+  xd->mi[0]->mbmi.mv[0].as_int = 0;
 #endif  // CONFIG_INTRABC
 
   const int64_t intra_yrd =