intrabc: Add initial skeleton

Missing features:
* RDOPT (Forced on for certain blocks)
* Any form of border extension
* Non MI sized right and bottom edges
* MV prediction

Present features:
* Force intrabc for some blocks
* Carry intrabc in the bitstream
* Validate DV is causal
* Reconstruct intrabc block assuming border extension is unnecessary

Change-Id: Ib1f6868e89bfacc2a4edfc876485bad1b347263b
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 91b140d..8d14095 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -1728,13 +1728,24 @@
 
     for (ref = 0; ref < 1 + has_second_ref(mbmi); ++ref) {
       const MV_REFERENCE_FRAME frame = mbmi->ref_frame[ref];
-      RefBuffer *ref_buf = &cm->frame_refs[frame - LAST_FRAME];
+      if (frame < LAST_FRAME) {
+#if CONFIG_INTRABC
+        assert(is_intrabc_block(mbmi));
+        assert(frame == INTRA_FRAME);
+        assert(ref == 0);
+#else
+        assert(0);
+#endif  // CONFIG_INTRABC
+      } else {
+        RefBuffer *ref_buf = &cm->frame_refs[frame - LAST_FRAME];
 
-      xd->block_refs[ref] = ref_buf;
-      if ((!av1_is_valid_scale(&ref_buf->sf)))
-        aom_internal_error(xd->error_info, AOM_CODEC_UNSUP_BITSTREAM,
-                           "Reference frame has invalid dimensions");
-      av1_setup_pre_planes(xd, ref, ref_buf->buf, mi_row, mi_col, &ref_buf->sf);
+        xd->block_refs[ref] = ref_buf;
+        if ((!av1_is_valid_scale(&ref_buf->sf)))
+          aom_internal_error(xd->error_info, AOM_CODEC_UNSUP_BITSTREAM,
+                             "Reference frame has invalid dimensions");
+        av1_setup_pre_planes(xd, ref, ref_buf->buf, mi_row, mi_col,
+                             &ref_buf->sf);
+      }
     }
 
 #if CONFIG_CB4X4
diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c
index 3a2ab56..24e7cee 100644
--- a/av1/decoder/decodemv.c
+++ b/av1/decoder/decodemv.c
@@ -902,6 +902,32 @@
   }
 }
 
+#if CONFIG_INTRABC
+static INLINE void read_mv(aom_reader *r, MV *mv, const MV *ref,
+                           nmv_context *ctx, nmv_context_counts *counts,
+                           int allow_hp);
+
+static INLINE int is_mv_valid(const MV *mv);
+
+static INLINE int assign_dv(AV1_COMMON *cm, MACROBLOCKD *xd, int_mv *mv,
+                            const int_mv *ref_mv, int mi_row, int mi_col,
+                            BLOCK_SIZE bsize, aom_reader *r) {
+#if CONFIG_EC_ADAPT
+  FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
+  (void)cm;
+#else
+  FRAME_CONTEXT *ec_ctx = cm->fc;
+#endif
+  FRAME_COUNTS *counts = xd->counts;
+  nmv_context_counts *const dv_counts = counts ? &counts->dv : NULL;
+  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
+
 static void read_intra_frame_mode_info(AV1_COMMON *const cm,
                                        MACROBLOCKD *const xd, int mi_row,
                                        int mi_col, aom_reader *r) {
@@ -942,6 +968,21 @@
   mbmi->ref_frame[0] = INTRA_FRAME;
   mbmi->ref_frame[1] = NONE_FRAME;
 
+#if CONFIG_INTRABC
+  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;
+      mbmi->interp_filter = BILINEAR;
+      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);
+      return;
+    }
+  }
+#endif  // CONFIG_INTRABC
+
 #if CONFIG_CB4X4
   (void)i;
   mbmi->mode =
@@ -2283,6 +2324,10 @@
   MV_REF *frame_mvs = cm->cur_frame->mvs + mi_row * cm->mi_cols + mi_col;
   int w, h;
 
+#if CONFIG_INTRABC
+  mi->mbmi.use_intrabc = 0;
+#endif  // CONFIG_INTRABC
+
   if (frame_is_intra_only(cm)) {
     read_intra_frame_mode_info(cm, xd, mi_row, mi_col, r);
 #if CONFIG_REF_MV