]> granicus.if.org Git - libvpx/commitdiff
Adds a copy mode experiment
authorDeb Mukherjee <debargha@google.com>
Tue, 16 Dec 2014 00:39:52 +0000 (16:39 -0800)
committerDeb Mukherjee <debargha@google.com>
Thu, 25 Dec 2014 01:52:55 +0000 (17:52 -0800)
Experiment to copy motion and mode from block neighbors.

Results:
--------
--enable-experimental --enable-copy-mode:
derflr: +0.727%

With other expts:
--enable-experimental --enable-copy-mode --enable-supertx
--enable-ext-tx --enable-filterintra --enable-tx-skip --enable-tx64x64
derflr: +3.43%

Change-Id: Iae74b9a855a1a690bf76131b42d247bbc54dec17

15 files changed:
configure
vp9/common/vp9_blockd.h
vp9/common/vp9_entropymode.c
vp9/common/vp9_entropymode.h
vp9/common/vp9_mvref_common.c
vp9/common/vp9_mvref_common.h
vp9/common/vp9_pred_common.c
vp9/common/vp9_pred_common.h
vp9/decoder/vp9_decodeframe.c
vp9/decoder/vp9_decodemv.c
vp9/encoder/vp9_bitstream.c
vp9/encoder/vp9_encodeframe.c
vp9/encoder/vp9_encoder.h
vp9/encoder/vp9_rd.c
vp9/encoder/vp9_rdopt.c

index 7695c281d3faae160440c8d615ad4c2d200797e6..6d0c9763960805e7f4833eea52566c1d2e26841d 100755 (executable)
--- a/configure
+++ b/configure
@@ -287,6 +287,7 @@ EXPERIMENT_LIST="
     ext_tx
     tx_skip
     supertx
+    copy_mode
 "
 CONFIG_LIST="
     external_build
index 6037d93d06528c0563d32bb12ccce118a94adb45..e174f6aeb380c9378b1c7e17849f89ef4bb5e9e1 100644 (file)
@@ -30,6 +30,10 @@ extern "C" {
 #define SKIP_CONTEXTS 3
 #define INTER_MODE_CONTEXTS 7
 
+#if CONFIG_COPY_MODE
+#define COPY_MODE_CONTEXTS 5
+#endif  // CONFIG_COPY_MODE
+
 /* Segment Feature Masks */
 #define MAX_MV_REF_CANDIDATES 2
 
@@ -76,6 +80,16 @@ typedef enum {
   MB_MODE_COUNT
 } PREDICTION_MODE;
 
+#if CONFIG_COPY_MODE
+typedef enum {
+  NOREF,
+  REF0,
+  REF1,
+  REF2,
+  COPY_MODE_COUNT
+} COPY_MODE;
+#endif  // CONFIG_COPY_MODE
+
 static INLINE int is_inter_mode(PREDICTION_MODE mode) {
   return mode >= NEARESTMV && mode <= NEWMV;
 }
@@ -143,6 +157,10 @@ typedef struct {
   int tx_skip[PLANE_TYPES];
   int tx_skip_shift;
 #endif
+#if CONFIG_COPY_MODE
+  COPY_MODE copy_mode;
+  int inter_ref_count;
+#endif  // CONFIG_COPY_MODE
 } MB_MODE_INFO;
 
 typedef struct MODE_INFO {
index a017c4a55c187a58b86604679e1372875422f8b7..e44bd59feca7129323095130b4cda1ab4087c34d 100644 (file)
@@ -259,7 +259,11 @@ const vp9_tree_index vp9_partition_tree[TREE_SIZE(PARTITION_TYPES)] = {
 };
 
 static const vp9_prob default_intra_inter_p[INTRA_INTER_CONTEXTS] = {
+#if CONFIG_COPY_MODE
+  35, 112, 187, 225
+#else
   9, 102, 187, 225
+#endif
 };
 
 static const vp9_prob default_comp_inter_p[COMP_INTER_CONTEXTS] = {
@@ -326,6 +330,43 @@ static const vp9_prob default_supertx_prob[PARTITION_SUPERTX_CONTEXTS]
 };
 #endif  // CONFIG_SUPERTX
 
+#if CONFIG_COPY_MODE
+static const vp9_prob default_copy_noref_prob[COPY_MODE_CONTEXTS]
+                                             [BLOCK_SIZES] = {
+  {255, 255, 255,  82, 148, 182,  65, 193, 158,  70, 138, 101,  23},
+  {255, 255, 255, 118, 153, 161, 123, 169, 157,  82, 101, 123,  88},
+  {255, 255, 255, 130, 178, 226, 194, 196, 174, 173, 135, 144, 141},
+  {255, 255, 255, 178, 218, 225, 197, 230, 222, 215, 220, 220, 220},
+  {255, 255, 255, 243, 248, 241, 233, 249, 249, 249, 249, 249, 249}
+};
+
+static const vp9_prob default_copy_mode_probs_l2[COPY_MODE_CONTEXTS][1] = {
+  {207},
+  {135},
+  {141},
+  {189},
+  {209}
+};
+
+const vp9_tree_index vp9_copy_mode_tree_l2[TREE_SIZE(2)] = {
+  -(REF0 - REF0), -(REF1 - REF0)
+};
+
+static const vp9_prob default_copy_mode_probs[COPY_MODE_CONTEXTS]
+                                             [COPY_MODE_COUNT - 2] = {
+  {130, 159},
+  {126, 176},
+  {120, 150},
+  {158, 183},
+  {149, 125}
+};
+
+const vp9_tree_index vp9_copy_mode_tree[TREE_SIZE(COPY_MODE_COUNT - 1)] = {
+  -(REF0 - REF0),  2,
+  -(REF1 - REF0),  -(REF2 - REF0)
+};
+#endif  // CONFIG_COPY_MODE
+
 #if CONFIG_TX64X64
 void tx_counts_to_branch_counts_64x64(const unsigned int *tx_count_64x64p,
                                       unsigned int (*ct_64x64p)[2]) {
@@ -399,17 +440,22 @@ void vp9_init_mode_probs(FRAME_CONTEXT *fc) {
   vp9_copy(fc->inter_mode_probs, default_inter_mode_probs);
 #if CONFIG_FILTERINTRA
   vp9_copy(fc->filterintra_prob, default_filterintra_prob);
-#endif
+#endif  // CONFIG_FILTERINTRA
 #if CONFIG_EXT_TX
   vp9_copy(fc->ext_tx_prob, default_ext_tx_prob);
-#endif
+#endif  // CONFIG_EXT_TX
 #if CONFIG_SUPERTX
   vp9_copy(fc->supertx_prob, default_supertx_prob);
-#endif
+#endif  // CONFIG_SUPERTX
 #if CONFIG_TX_SKIP
   vp9_copy(fc->y_tx_skip_prob, default_y_tx_skip_prob);
   vp9_copy(fc->uv_tx_skip_prob, default_uv_tx_skip_prob);
-#endif
+#endif  // CONFIG_TX_SKIP
+#if CONFIG_COPY_MODE
+  vp9_copy(fc->copy_noref_prob, default_copy_noref_prob);
+  vp9_copy(fc->copy_mode_probs_l2, default_copy_mode_probs_l2);
+  vp9_copy(fc->copy_mode_probs, default_copy_mode_probs);
+#endif  // CONFIG_COPY_MODE
 }
 
 const vp9_tree_index vp9_switchable_interp_tree
@@ -540,6 +586,18 @@ void vp9_adapt_mode_probs(VP9_COMMON *cm) {
     fc->uv_tx_skip_prob[i] = adapt_prob(pre_fc->uv_tx_skip_prob[i],
                                         counts->uv_tx_skip[i]);
 #endif  // CONFIG_TX_SKIP
+#if CONFIG_COPY_MODE
+  for (i = 0; i < COPY_MODE_CONTEXTS; i++) {
+    for (j = BLOCK_8X8; j < BLOCK_SIZES; j++) {
+      fc->copy_noref_prob[i][j] =
+          adapt_prob(pre_fc->copy_noref_prob[i][j], counts->copy_noref[i][j]);
+    }
+    adapt_probs(vp9_copy_mode_tree_l2, pre_fc->copy_mode_probs_l2[i],
+                counts->copy_mode_l2[i], fc->copy_mode_probs_l2[i]);
+    adapt_probs(vp9_copy_mode_tree, pre_fc->copy_mode_probs[i],
+                counts->copy_mode[i], fc->copy_mode_probs[i]);
+  }
+#endif  // CONFIG_COPY_MODE
 }
 
 static void set_default_lf_deltas(struct loopfilter *lf) {
index ccb70f85a717ac6c76b30ca9d9bee67b7a871966..068f95e553d41a0c01ab78f08e066f70e163b59c 100644 (file)
@@ -58,17 +58,22 @@ typedef struct frame_contexts {
   nmv_context nmvc;
 #if CONFIG_FILTERINTRA
   vp9_prob filterintra_prob[TX_SIZES][INTRA_MODES];
-#endif
+#endif  // CONFIG_FILTERINTRA
 #if CONFIG_EXT_TX
   vp9_prob ext_tx_prob[3][EXT_TX_TYPES - 1];
-#endif
+#endif  // CONFIG_EXT_TX
 #if CONFIG_SUPERTX
   vp9_prob supertx_prob[PARTITION_SUPERTX_CONTEXTS][TX_SIZES];
-#endif
+#endif  // CONFIG_SUPERTX
 #if CONFIG_TX_SKIP
   vp9_prob y_tx_skip_prob[2];
   vp9_prob uv_tx_skip_prob[2];
-#endif
+#endif  // CONFIG_TX_SKIP
+#if CONFIG_COPY_MODE
+  vp9_prob copy_noref_prob[COPY_MODE_CONTEXTS][BLOCK_SIZES];
+  vp9_prob copy_mode_probs_l2[COPY_MODE_CONTEXTS][1];
+  vp9_prob copy_mode_probs[COPY_MODE_CONTEXTS][COPY_MODE_COUNT - 2];
+#endif  // CONFIG_COPY_MODE
 } FRAME_CONTEXT;
 
 typedef struct {
@@ -102,6 +107,11 @@ typedef struct {
   unsigned int y_tx_skip[2][2];
   unsigned int uv_tx_skip[2][2];
 #endif
+#if CONFIG_COPY_MODE
+  unsigned int copy_noref[COPY_MODE_CONTEXTS][BLOCK_SIZES][2];
+  unsigned int copy_mode_l2[COPY_MODE_CONTEXTS][2];
+  unsigned int copy_mode[COPY_MODE_CONTEXTS][COPY_MODE_COUNT - 1];
+#endif  // CONFIG_COPY_MODE
 } FRAME_COUNTS;
 
 extern const vp9_prob vp9_kf_uv_mode_prob[INTRA_MODES][INTRA_MODES - 1];
@@ -117,6 +127,10 @@ extern const vp9_tree_index vp9_switchable_interp_tree
 #if CONFIG_EXT_TX
 extern const vp9_tree_index vp9_ext_tx_tree[TREE_SIZE(EXT_TX_TYPES)];
 #endif
+#if CONFIG_COPY_MODE
+extern const vp9_tree_index vp9_copy_mode_tree_l2[TREE_SIZE(2)];
+extern const vp9_tree_index vp9_copy_mode_tree[TREE_SIZE(COPY_MODE_COUNT - 1)];
+#endif  // CONFIG_COPY_MODE
 
 void vp9_setup_past_independence(struct VP9Common *cm);
 
index 3b34050a840a17353e2ae9de71ef5bcbf4016989..9f044be33210ca506d2283ba05c37f71094c2525 100644 (file)
@@ -184,3 +184,164 @@ void vp9_append_sub8x8_mvs_for_idx(VP9_COMMON *cm, MACROBLOCKD *xd,
       assert("Invalid block index.");
   }
 }
+
+#if CONFIG_COPY_MODE
+static int compare_interinfo(MB_MODE_INFO *mbmi, MB_MODE_INFO *ref_mbmi) {
+  if (mbmi == ref_mbmi) {
+    return 1;
+  } else {
+    int is_same;
+    if (mbmi->ref_frame[0] == ref_mbmi->ref_frame[0] &&
+        mbmi->ref_frame[1] == ref_mbmi->ref_frame[1]) {
+      if (mbmi->ref_frame[1] > INTRA_FRAME)
+        is_same = mbmi->mv[0].as_int == ref_mbmi->mv[0].as_int &&
+                  mbmi->mv[1].as_int == ref_mbmi->mv[1].as_int &&
+                  mbmi->interp_filter == ref_mbmi->interp_filter;
+      else
+        is_same = mbmi->mv[0].as_int == ref_mbmi->mv[0].as_int &&
+                  mbmi->interp_filter == ref_mbmi->interp_filter;
+    } else {
+      is_same = 0;
+    }
+
+    return is_same;
+  }
+}
+
+static int check_inside(VP9_COMMON *cm, int mi_row, int mi_col) {
+  return mi_row >= 0 && mi_col >= 0 &&
+         mi_row < cm->mi_rows && mi_col < cm->mi_cols;
+}
+
+static int is_right_available(BLOCK_SIZE bsize, int mi_row, int mi_col) {
+  int depth, max_depth = 4 - MIN(b_width_log2_lookup[bsize],
+                                 b_height_log2_lookup[bsize]);
+  int block[4] = {0};
+
+  if (bsize == BLOCK_64X64)
+    return 1;
+  mi_row = mi_row % 8;
+  mi_col = mi_col % 8;
+  for (depth = 1; depth <= max_depth; depth++) {
+    block[depth] = (mi_row >> (3 - depth)) * 2 + (mi_col >> (3 - depth));
+    mi_row = mi_row % (8 >> depth);
+    mi_col = mi_col % (8 >> depth);
+  }
+
+  if (b_width_log2_lookup[bsize] < b_height_log2_lookup[bsize]) {
+    if (block[max_depth] == 0)
+      return 1;
+  } else if (b_width_log2_lookup[bsize] > b_height_log2_lookup[bsize]) {
+    if (block[max_depth] > 0)
+      return 0;
+  } else {
+    if (block[max_depth] == 0 || block[max_depth] == 2)
+      return 1;
+    else if (block[max_depth] == 3)
+      return 0;
+  }
+
+  for (depth = max_depth - 1; depth > 0; depth--) {
+    if (block[depth] == 0 || block[depth] == 2)
+      return 1;
+    else if (block[depth] == 3)
+      return 0;
+  }
+  return 1;
+}
+
+static int is_second_rec(int mi_row, int mi_col, BLOCK_SIZE bsize) {
+  int bw = 4 << b_width_log2_lookup[bsize];
+  int bh = 4 << b_height_log2_lookup[bsize];
+
+  if (bw < bh)
+    return (mi_col << 3) % (bw << 1) == 0 ? 0 : 1;
+  else if (bh < bw)
+    return (mi_row << 3) % (bh << 1) == 0 ? 0 : 2;
+  else
+    return 0;
+}
+
+int vp9_construct_ref_inter_list(VP9_COMMON *cm,  MACROBLOCKD *xd,
+                                 BLOCK_SIZE bsize, int mi_row, int mi_col,
+                                 MB_MODE_INFO *ref_list[18]) {
+  int bw = 4 << b_width_log2_lookup[bsize];
+  int bh = 4 << b_height_log2_lookup[bsize];
+  int row_offset, col_offset;
+  int mi_offset;
+  MB_MODE_INFO *ref_mbmi;
+  int ref_index, ref_num = 0;
+  int row_offset_cand[18], col_offset_cand[18];
+  int offset_num = 0, i, switchflag;
+  int is_sec_rec = is_second_rec(mi_row, mi_col, bsize);
+
+  if (is_sec_rec != 2) {
+    row_offset_cand[offset_num] = -1; col_offset_cand[offset_num] = 0;
+    offset_num++;
+  }
+  if (is_sec_rec != 1) {
+    row_offset_cand[offset_num] = bh / 16; col_offset_cand[offset_num] = -1;
+    offset_num++;
+  }
+
+  row_offset = bh / 8 - 1;
+  col_offset = 1;
+  if (is_sec_rec < 2)
+    switchflag = 1;
+  else
+    switchflag = 0;
+  while ((is_sec_rec == 0 && ((row_offset >=0) || col_offset < (bw / 8 + 1))) ||
+         (is_sec_rec == 1 && col_offset < (bw / 8 + 1)) ||
+         (is_sec_rec == 2 && row_offset >=0)) {
+    switch (switchflag) {
+      case 0:
+        if (row_offset >= 0) {
+          if (row_offset != bh / 16) {
+            row_offset_cand[offset_num] = row_offset;
+            col_offset_cand[offset_num] = -1;
+            offset_num++;
+          }
+          row_offset--;
+        }
+        break;
+      case 1:
+        if (col_offset < (bw / 8 + 1)) {
+          row_offset_cand[offset_num] = -1;
+          col_offset_cand[offset_num] = col_offset;
+          offset_num++;
+          col_offset++;
+        }
+        break;
+      default:
+        assert(0);
+    }
+    if (is_sec_rec == 0)
+      switchflag = 1 - switchflag;
+  }
+  row_offset_cand[offset_num] = -1;
+  col_offset_cand[offset_num] = -1;
+  offset_num++;
+
+  for (i = 0; i < offset_num; i++) {
+    row_offset = row_offset_cand[i];
+    col_offset = col_offset_cand[i];
+    if ((col_offset < (bw / 8) ||
+        (col_offset == (bw / 8) && is_right_available(bsize, mi_row, mi_col)))
+        && check_inside(cm, mi_row + row_offset, mi_col + col_offset)) {
+      mi_offset = row_offset * cm->mi_stride + col_offset;
+      ref_mbmi = &xd->mi[mi_offset].src_mi->mbmi;
+      if (is_inter_block(ref_mbmi)) {
+        for (ref_index = 0; ref_index < ref_num; ref_index++) {
+          if (compare_interinfo(ref_mbmi, ref_list[ref_index]))
+            break;
+        }
+        if (ref_index == ref_num) {
+          ref_list[ref_num] = ref_mbmi;
+          ref_num++;
+        }
+      }
+    }
+  }
+  return ref_num;
+}
+#endif  // CONFIG_COPY_MODE
index a937b7823a5102f1312a805c4e1638689833ed25..a6103d99d713f54d4cdcaf04a55d86fdd803d23d 100644 (file)
@@ -220,6 +220,12 @@ void vp9_append_sub8x8_mvs_for_idx(VP9_COMMON *cm, MACROBLOCKD *xd,
                                    int block, int ref, int mi_row, int mi_col,
                                    int_mv *nearest, int_mv *near);
 
+#if CONFIG_COPY_MODE
+int vp9_construct_ref_inter_list(VP9_COMMON *cm,  MACROBLOCKD *xd,
+                                 BLOCK_SIZE bsize, int mi_row, int mi_col,
+                                 MB_MODE_INFO *ref_list[18]);
+#endif  // CONFIG_COPY_MODE
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
index 901a043f69b43e2a2a833208cbe74f2fa8a054ac..90f8f56bc66aef051b59d9fd98434d822bfb850e 100644 (file)
@@ -383,3 +383,47 @@ int vp9_get_segment_id(const VP9_COMMON *cm, const uint8_t *segment_ids,
   assert(segment_id >= 0 && segment_id < MAX_SEGMENTS);
   return segment_id;
 }
+
+#if CONFIG_COPY_MODE
+int vp9_get_copy_mode_context(const MACROBLOCKD *xd) {
+  const MB_MODE_INFO *const above_mbmi = get_mbmi(get_above_mi(xd));
+  const MB_MODE_INFO *const left_mbmi = get_mbmi(get_left_mi(xd));
+  const int has_above = above_mbmi != NULL;
+  const int has_left = left_mbmi != NULL;
+
+  if (has_above && has_left) {
+    const int above_intra = !is_inter_block(above_mbmi);
+    const int left_intra = !is_inter_block(left_mbmi);
+
+    if (above_intra && left_intra) {
+      return 4;
+    } else if (above_intra || left_intra) {
+      return 3;
+    } else {
+      const int above_predict = above_mbmi->copy_mode != NOREF;
+      const int left_predict = left_mbmi->copy_mode != NOREF;
+      if (above_predict && left_predict)
+        return 0;
+      else if (above_predict || left_predict)
+        return 1;
+      else
+        return 2;
+    }
+  } else if (has_above || has_left) {
+    const MB_MODE_INFO *const ref_mbmi = has_above ? above_mbmi : left_mbmi;
+    const int ref_intra = !is_inter_block(ref_mbmi);
+
+    if (ref_intra) {
+      return 3;
+    } else {
+     const int ref_predict = ref_mbmi != NOREF;
+      if (ref_predict)
+        return 0;
+      else
+        return 1;
+    }
+  } else {
+    return 0;
+  }
+}
+#endif  // CONFIG_COPY_MODE
index 5738d5063416345325dd78534570dfdfb5e89af3..4a5e2026f1c691b628fd7eeb21c576a3d6c7a36e 100644 (file)
@@ -142,6 +142,10 @@ static INLINE unsigned int *get_tx_counts(TX_SIZE max_tx_size, int ctx,
   }
 }
 
+#if CONFIG_COPY_MODE
+int vp9_get_copy_mode_context(const MACROBLOCKD *xd);
+#endif  // CONFIG_COPY_MODE
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
index 057a622911bbbe984ce71de9c6f7829267de573b..c92fe65ba5b3dc9911b77ad82dd1c5b7e791f0cb 100644 (file)
@@ -2100,6 +2100,14 @@ static int read_compressed_header(VP9Decoder *pbi, const uint8_t *data,
     vp9_diff_update_prob(&r, &fc->y_tx_skip_prob[i]);
   for (i = 0; i < 2; i++)
     vp9_diff_update_prob(&r, &fc->uv_tx_skip_prob[i]);
+#endif
+#if CONFIG_COPY_MODE
+    for (j = 0; j < COPY_MODE_CONTEXTS; j++) {
+      for (i = 0; i < 1; i++)
+        vp9_diff_update_prob(&r, &fc->copy_mode_probs_l2[j][i]);
+      for (i = 0; i < COPY_MODE_COUNT - 2; i++)
+        vp9_diff_update_prob(&r, &fc->copy_mode_probs[j][i]);
+    }
 #endif
   }
 
index 9fae177239d6ad46726e06d79b64d3d0e9ecf891..4e9cc6430a29813d9e83410bd7bc9217f3704b7e 100644 (file)
@@ -54,6 +54,36 @@ static PREDICTION_MODE read_inter_mode(VP9_COMMON *cm, vp9_reader *r, int ctx) {
   return NEARESTMV + mode;
 }
 
+#if CONFIG_COPY_MODE
+static COPY_MODE read_copy_mode(VP9_COMMON *cm, vp9_reader *r,
+                                int num_candidate, int ctx) {
+  COPY_MODE mode;
+
+  switch (num_candidate) {
+    case 0:
+      assert(0);
+      break;
+    case 1:
+      mode = REF0;
+      break;
+    case 2:
+      mode = REF0 + vp9_read_tree(r, vp9_copy_mode_tree_l2,
+                                  cm->fc.copy_mode_probs_l2[ctx]);
+      if (!cm->frame_parallel_decoding_mode)
+          ++cm->counts.copy_mode_l2[ctx][mode - REF0];
+      break;
+    default:
+      mode = REF0 + vp9_read_tree(r, vp9_copy_mode_tree,
+                                  cm->fc.copy_mode_probs[ctx]);
+      if (!cm->frame_parallel_decoding_mode)
+          ++cm->counts.copy_mode[ctx][mode - REF0];
+      break;
+  }
+
+  return mode;
+}
+#endif  // CONFIG_COPY_MODE
+
 static int read_segment_id(vp9_reader *r, const struct segmentation *seg) {
   return vp9_read_tree(r, vp9_segment_tree, seg->tree_probs);
 }
@@ -587,7 +617,10 @@ static void read_inter_block_mode_info(VP9_COMMON *const cm,
   int_mv nearestmv[2], nearmv[2];
   int inter_mode_ctx, ref, is_compound;
 
-  read_ref_frames(cm, xd, r, mbmi->segment_id, mbmi->ref_frame);
+#if CONFIG_COPY_MODE
+  if (mbmi->copy_mode == NOREF)
+#endif
+    read_ref_frames(cm, xd, r, mbmi->segment_id, mbmi->ref_frame);
   is_compound = has_second_ref(mbmi);
 
   for (ref = 0; ref < 1 + is_compound; ++ref) {
@@ -602,9 +635,16 @@ static void read_inter_block_mode_info(VP9_COMMON *const cm,
                          "Block reference is corrupt");
     vp9_setup_pre_planes(xd, ref, ref_buf->buf, mi_row, mi_col,
                          &ref_buf->sf);
-    vp9_find_mv_refs(cm, xd, tile, mi, frame, mbmi->ref_mvs[frame],
-                     mi_row, mi_col);
+#if CONFIG_COPY_MODE
+    if (mbmi->copy_mode == NOREF)
+#endif
+      vp9_find_mv_refs(cm, xd, tile, mi, frame, mbmi->ref_mvs[frame],
+                       mi_row, mi_col);
   }
+#if CONFIG_COPY_MODE
+  if (mbmi->copy_mode != NOREF)
+    return;
+#endif
 
   inter_mode_ctx = mbmi->mode_context[mbmi->ref_frame[0]];
 
@@ -687,16 +727,66 @@ static void read_inter_frame_mode_info(VP9_COMMON *const cm,
   MODE_INFO *const mi = xd->mi[0].src_mi;
   MB_MODE_INFO *const mbmi = &mi->mbmi;
   int inter_block;
+#if CONFIG_COPY_MODE
+  int num_candidate = 0;
+  MB_MODE_INFO *inter_ref_list[18] = {NULL};
+#endif
 
   mbmi->mv[0].as_int = 0;
   mbmi->mv[1].as_int = 0;
 
+#if CONFIG_COPY_MODE
+  if (mbmi->sb_type >= BLOCK_8X8)
+    num_candidate = vp9_construct_ref_inter_list(
+        cm, xd, mbmi->sb_type, mi_row, mi_col, inter_ref_list);
+  if (mbmi->sb_type >= BLOCK_8X8 && num_candidate > 0) {
+    int ctx = vp9_get_copy_mode_context(xd);
+    int is_copy = vp9_read(r, cm->fc.copy_noref_prob[ctx][mbmi->sb_type]);
+
+    ++cm->counts.copy_noref[ctx][mbmi->sb_type][is_copy];
+    if (!is_copy) {
+      mbmi->copy_mode = NOREF;
+    } else {
+      mbmi->copy_mode = read_copy_mode(cm, r, num_candidate, ctx);
+    }
+  } else {
+    mbmi->copy_mode = NOREF;
+  }
+  if (mbmi->copy_mode != NOREF) {
+    BLOCK_SIZE bsize_backup = mbmi->sb_type;
+    int skip_backup = mbmi->skip;
+    COPY_MODE copy_mode_backup = mbmi->copy_mode;
+#if CONFIG_SUPERTX
+    TX_SIZE tx_size_backup = mbmi->tx_size;
+#endif
+#if CONFIG_EXT_TX
+    EXT_TX_TYPE ext_txfrm_backup = mbmi->ext_txfrm;
+#endif
+
+    inter_block = 1;
+    *mbmi = *inter_ref_list[mbmi->copy_mode - REF0];
+#if CONFIG_SUPERTX
+    mbmi->tx_size = tx_size_backup;
+#endif
+#if CONFIG_EXT_TX
+    mbmi->ext_txfrm = ext_txfrm_backup;
+#endif
+    mbmi->sb_type = bsize_backup;
+    mbmi->mode = NEARESTMV;
+    mbmi->skip = skip_backup;
+    mbmi->copy_mode = copy_mode_backup;
+  }
+#endif  // CONFIG_COPY_MODE
+
 #if CONFIG_SUPERTX
   if (!supertx_enabled) {
 #endif
     mbmi->segment_id = read_inter_segment_id(cm, xd, mi_row, mi_col, r);
     mbmi->skip = read_skip(cm, xd, mbmi->segment_id, r);
-    inter_block = read_is_inter_block(cm, xd, mbmi->segment_id, r);
+#if CONFIG_COPY_MODE
+    if (mbmi->copy_mode == NOREF)
+#endif
+      inter_block = read_is_inter_block(cm, xd, mbmi->segment_id, r);
     mbmi->tx_size = read_tx_size(cm, xd, cm->tx_mode, mbmi->sb_type,
                                  !mbmi->skip || !inter_block, r);
 #if CONFIG_EXT_TX
@@ -720,7 +810,10 @@ static void read_inter_frame_mode_info(VP9_COMMON *const cm,
     mbmi->segment_id = 0;
     inter_block = 1;
     if (!cm->frame_parallel_decoding_mode)
-      ++cm->counts.intra_inter[ctx][1];
+#if CONFIG_COPY_MODE
+      if (mbmi->copy_mode == NOREF)
+#endif
+        ++cm->counts.intra_inter[ctx][1];
   }
 #endif  // CONFIG_SUPERTX
 
index 919789ffede96852a4ead55d8c8e2907b5cb5f0b..92682dc9feecd0ac5dac11e10ba05e9f5b92ff2a 100644 (file)
@@ -41,6 +41,10 @@ static struct vp9_token inter_mode_encodings[INTER_MODES];
 #if CONFIG_EXT_TX
 static struct vp9_token ext_tx_encodings[EXT_TX_TYPES];
 #endif
+#if CONFIG_COPY_MODE
+static struct vp9_token copy_mode_encodings_l2[2];
+static struct vp9_token copy_mode_encodings[COPY_MODE_COUNT - 1];
+#endif
 
 #if CONFIG_SUPERTX
 static int vp9_check_supertx(VP9_COMMON *cm, int mi_row, int mi_col,
@@ -62,6 +66,10 @@ void vp9_entropy_mode_init() {
 #if CONFIG_EXT_TX
   vp9_tokens_from_tree(ext_tx_encodings, vp9_ext_tx_tree);
 #endif
+#if CONFIG_COPY_MODE
+  vp9_tokens_from_tree(copy_mode_encodings_l2, vp9_copy_mode_tree_l2);
+  vp9_tokens_from_tree(copy_mode_encodings, vp9_copy_mode_tree);
+#endif  // CONFIG_COPY_MODE
 }
 
 static void write_intra_mode(vp9_writer *w, PREDICTION_MODE mode,
@@ -76,6 +84,21 @@ static void write_inter_mode(vp9_writer *w, PREDICTION_MODE mode,
                   &inter_mode_encodings[INTER_OFFSET(mode)]);
 }
 
+#if CONFIG_COPY_MODE
+static void write_copy_mode(VP9_COMMON *cm, vp9_writer *w, COPY_MODE mode,
+                            int inter_ref_count, int copy_mode_context) {
+  if (inter_ref_count == 2) {
+    vp9_write_token(w, vp9_copy_mode_tree_l2,
+                    cm->fc.copy_mode_probs_l2[copy_mode_context],
+                    &copy_mode_encodings_l2[mode - REF0]);
+  } else if (inter_ref_count > 2) {
+    vp9_write_token(w, vp9_copy_mode_tree,
+                    cm->fc.copy_mode_probs[copy_mode_context],
+                    &copy_mode_encodings[mode - REF0]);
+  }
+}
+#endif  // CONFIG_COPY_MODE
+
 static void encode_unsigned_max(struct vp9_write_bit_buffer *wb,
                                 int data, int max) {
   vp9_wb_write_literal(wb, data, get_unsigned_bits(max));
@@ -341,6 +364,16 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, const MODE_INFO *mi,
   const int is_inter = is_inter_block(mbmi);
   const int is_compound = has_second_ref(mbmi);
   int skip, ref;
+#if CONFIG_COPY_MODE
+  int copy_mode_context = vp9_get_copy_mode_context(xd);
+  if (bsize >= BLOCK_8X8 && mbmi->inter_ref_count > 0) {
+    vp9_write(w, mbmi->copy_mode != NOREF,
+              cm->fc.copy_noref_prob[copy_mode_context][bsize]);
+    if (mbmi->copy_mode != NOREF)
+      write_copy_mode(cm, w, mbmi->copy_mode, mbmi->inter_ref_count,
+                      copy_mode_context);
+  }
+#endif
 
   if (seg->update_map) {
     if (seg->temporal_update) {
@@ -366,8 +399,11 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, const MODE_INFO *mi,
 #if CONFIG_SUPERTX
   if (!supertx_enabled) {
 #endif
-  if (!vp9_segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME))
-    vp9_write(w, is_inter, vp9_get_intra_inter_prob(cm, xd));
+#if CONFIG_COPY_MODE
+  if (mbmi->copy_mode == NOREF)
+#endif
+    if (!vp9_segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME))
+      vp9_write(w, is_inter, vp9_get_intra_inter_prob(cm, xd));
 #if CONFIG_SUPERTX
   }
 #endif
@@ -409,7 +445,7 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, const MODE_INFO *mi,
       vp9_write(w, mbmi->tx_skip[1], cm->fc.uv_tx_skip_prob[mbmi->tx_skip[0]]);
     }
   }
-#endif
+#endif  // CONFIG_TX_SKIP
 
   if (!is_inter) {
     if (bsize >= BLOCK_8X8) {
@@ -445,7 +481,11 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, const MODE_INFO *mi,
                 cm->fc.filterintra_prob[get_uv_tx_size(mbmi, &xd->plane[1])][mbmi->uv_mode]);
     }
 #endif
+#if CONFIG_COPY_MODE
+  } else if (mbmi->copy_mode == NOREF) {
+#else
   } else {
+#endif
     const int mode_ctx = mbmi->mode_context[mbmi->ref_frame[0]];
     const vp9_prob *const inter_probs = cm->fc.inter_mode_probs[mode_ctx];
     write_ref_frames(cm, xd, w);
@@ -1534,6 +1574,15 @@ static size_t write_compressed_header(VP9_COMP *cpi, uint8_t *data) {
     for (i = 0; i < 2; i++)
       vp9_cond_prob_diff_update(&header_bc, &fc->uv_tx_skip_prob[i],
                                 cm->counts.uv_tx_skip[i]);
+#endif
+#if CONFIG_COPY_MODE
+    for (i = 0; i < COPY_MODE_CONTEXTS; i++) {
+      prob_diff_update(vp9_copy_mode_tree_l2, cm->fc.copy_mode_probs_l2[i],
+                       cm->counts.copy_mode_l2[i], 2, &header_bc);
+      prob_diff_update(vp9_copy_mode_tree, cm->fc.copy_mode_probs[i],
+                       cm->counts.copy_mode[i], COPY_MODE_COUNT - 1,
+                       &header_bc);
+    }
 #endif
   }
 
index 7b2bf698f3e7f91c2de5433a44fad845abb7c2ae..505654125b9c4dde8ff71eb31b7497a8c019931e 100644 (file)
@@ -832,7 +832,25 @@ static void update_state(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx,
   }
 #endif
   if (!frame_is_intra_only(cm)) {
+#if CONFIG_COPY_MODE
+    COPY_MODE copy_mode = mbmi->copy_mode;
+    if (mbmi->sb_type >= BLOCK_8X8) {
+      int copy_mode_context = vp9_get_copy_mode_context(xd);
+      if (mbmi->inter_ref_count > 0) {
+        ++cm->counts.copy_noref[copy_mode_context][mbmi->sb_type]
+                               [copy_mode != NOREF];
+        if (copy_mode != NOREF) {
+          if (mbmi->inter_ref_count == 2)
+            ++cm->counts.copy_mode_l2[copy_mode_context][copy_mode - REF0];
+          else if (mbmi->inter_ref_count > 2)
+            ++cm->counts.copy_mode[copy_mode_context][copy_mode - REF0];
+        }
+      }
+    }
+    if (is_inter_block(mbmi) && copy_mode == NOREF) {
+#else
     if (is_inter_block(mbmi)) {
+#endif  // CONFIG_COPY_MODE
       vp9_update_mv_count(cm, xd);
 
       if (cm->interp_filter == SWITCHABLE) {
@@ -913,7 +931,25 @@ static void update_state_supertx(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx,
     return;
 
   if (!frame_is_intra_only(cm)) {
+#if CONFIG_COPY_MODE
+    COPY_MODE copy_mode = mbmi->copy_mode;
+    if (mbmi->sb_type >= BLOCK_8X8) {
+      int copy_mode_context = vp9_get_copy_mode_context(xd);
+      if (mbmi->inter_ref_count > 0) {
+        ++cm->counts.copy_noref[copy_mode_context][mbmi->sb_type]
+                               [copy_mode != NOREF];
+        if (copy_mode != NOREF) {
+          if (mbmi->inter_ref_count == 2)
+            ++cm->counts.copy_mode_l2[copy_mode_context][copy_mode - REF0];
+          else if (mbmi->inter_ref_count > 2)
+            ++cm->counts.copy_mode[copy_mode_context][copy_mode - REF0];
+        }
+      }
+    }
+    if (is_inter_block(mbmi) && copy_mode == NOREF) {
+#else
     if (is_inter_block(mbmi)) {
+#endif  // CONFIG_COPY_MODE
       vp9_update_mv_count(cm, xd);
 
       if (cm->interp_filter == SWITCHABLE) {
@@ -1300,7 +1336,11 @@ static void update_stats(VP9_COMMON *cm, const MACROBLOCK *x) {
   const MODE_INFO *const mi = xd->mi[0].src_mi;
   const MB_MODE_INFO *const mbmi = &mi->mbmi;
 
+#if CONFIG_COPY_MODE
+  if (!frame_is_intra_only(cm) && mbmi->copy_mode == NOREF) {
+#else
   if (!frame_is_intra_only(cm)) {
+#endif
     const int seg_ref_active = vp9_segfeature_active(&cm->seg, mbmi->segment_id,
                                                      SEG_LVL_REF_FRAME);
     if (!seg_ref_active) {
index 144431a8edf52ba231b60ce3ef7dfdda0281029f..a1545cbeadb2b87ae97f46b69ee76d194ed09f08 100644 (file)
@@ -397,6 +397,10 @@ typedef struct VP9_COMP {
 #if CONFIG_EXT_TX
   int ext_tx_costs[3][EXT_TX_TYPES];
 #endif
+#if CONFIG_COPY_MODE
+  int copy_mode_cost_l2[COPY_MODE_CONTEXTS][2];
+  int copy_mode_cost[COPY_MODE_CONTEXTS][COPY_MODE_COUNT - 1];
+#endif
 
   PICK_MODE_CONTEXT *leaf_tree;
   PC_TREE *pc_tree;
index f1c7d9e3e3bc26071a76880abecac56b08e983e6..1a43d134e8cad59ece61094ca3cd49ca2f1e1876 100644 (file)
@@ -306,6 +306,15 @@ void vp9_initialize_rd_consts(VP9_COMP *cpi) {
                         cm->fc.inter_mode_probs[i], vp9_inter_mode_tree);
     }
   }
+
+#if CONFIG_COPY_MODE
+  for (i = 0; i < COPY_MODE_CONTEXTS; ++i) {
+    vp9_cost_tokens((int *)cpi->copy_mode_cost_l2[i],
+                    cm->fc.copy_mode_probs_l2[i], vp9_copy_mode_tree_l2);
+    vp9_cost_tokens((int *)cpi->copy_mode_cost[i],
+                    cm->fc.copy_mode_probs[i], vp9_copy_mode_tree);
+  }
+#endif  // CONFIG_COPY_MODE
 }
 
 static void model_rd_norm(int xsq_q10, int *r_q10, int *d_q10) {
index 6cfb06987647c73b8e12bb3d81c4341b84099c28..914d1fa68affc6b6f3145ca959893dd9ba8a4876 100644 (file)
 
 #define MIN_EARLY_TERM_INDEX    3
 
+#if CONFIG_EXT_TX
+const double ext_tx_th = 0.99;
+#endif
+
 typedef struct {
   PREDICTION_MODE mode;
   MV_REFERENCE_FRAME ref_frame[2];
@@ -3035,7 +3039,6 @@ static int64_t handle_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
       int dummy;
       int64_t best_rdcost_tx = INT64_MAX;
       int best_ext_tx = NORM;
-      double th = 0.99;
 
       for (i = 0; i < EXT_TX_TYPES; i++) {
         mbmi->ext_txfrm = i;
@@ -3046,7 +3049,7 @@ static int64_t handle_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
         rdcost_tx = RDCOST(x->rdmult, x->rddiv, rate_y_tx, distortion_y_tx);
         rdcost_tx = MIN(rdcost_tx, RDCOST(x->rdmult, x->rddiv, 0, *psse));
         assert(rdcost_tx >= 0);
-        if (rdcost_tx < best_rdcost_tx * th) {
+        if (rdcost_tx < best_rdcost_tx * ext_tx_th) {
           best_ext_tx = i;
           best_rdcost_tx = rdcost_tx;
         }
@@ -3306,12 +3309,23 @@ void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x,
   int q_idx = vp9_get_qindex(seg, segment_id, cm->base_qindex);
   int try_tx_skip = q_idx <= TX_SKIP_Q_THRESH_INTRA;
 #endif
+#if CONFIG_COPY_MODE
+  COPY_MODE copy_mode;
+  int inter_ref_count;
+  MB_MODE_INFO *inter_ref_list[18];
+  int copy_mode_context = vp9_get_copy_mode_context(xd);
+#endif  // CONFIG_COPY_MODE
   vp9_zero(best_mbmode);
 
   x->skip_encode = sf->skip_encode_frame && x->q_index < QIDX_SKIP_THRESH;
 
   estimate_ref_frame_costs(cm, xd, segment_id, ref_costs_single, ref_costs_comp,
                            &comp_mode_p);
+#if CONFIG_COPY_MODE
+  inter_ref_count =
+    vp9_construct_ref_inter_list(cm, xd, bsize, mi_row, mi_col, inter_ref_list);
+  mbmi->inter_ref_count = inter_ref_count;
+#endif  // CONFIG_COPY_MODE
 
   for (i = 0; i < REFERENCE_MODES; ++i)
     best_pred_rd[i] = INT64_MAX;
@@ -3603,6 +3617,9 @@ void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x,
 #if CONFIG_TX_SKIP
     mbmi->tx_skip[0] = 0;
     mbmi->tx_skip[1] = 0;
+#endif
+#if CONFIG_COPY_MODE
+    mbmi->copy_mode = NOREF;
 #endif
     // Evaluate all sub-pel filters irrespective of whether we can use
     // them for this frame.
@@ -3766,6 +3783,11 @@ void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x,
     } else {
       rate2 += ref_costs_single[ref_frame];
     }
+#if CONFIG_COPY_MODE
+    if (inter_ref_count > 0)
+      rate2 += vp9_cost_bit(cm->fc.copy_noref_prob[copy_mode_context][bsize],
+                            0);
+#endif
 
     if (!disable_skip) {
       if (skippable) {
@@ -3971,89 +3993,262 @@ void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x,
   }
 
   if (best_mode_index < 0 || best_rd >= best_rd_so_far) {
+#if !CONFIG_COPY_MODE
     rd_cost->rate = INT_MAX;
     rd_cost->rdcost = INT64_MAX;
     return;
-  }
+#endif
+  } else {
+    // If we used an estimate for the uv intra rd in the loop above...
+    if (sf->use_uv_intra_rd_estimate) {
+      // Do Intra UV best rd mode selection if best mode choice above was intra.
+      if (best_mbmode.ref_frame[0] == INTRA_FRAME) {
+        TX_SIZE uv_tx_size;
+        *mbmi = best_mbmode;
+        uv_tx_size = get_uv_tx_size(mbmi, &xd->plane[1]);
+        rd_pick_intra_sbuv_mode(cpi, x, ctx, &rate_uv_intra[uv_tx_size],
+                                &rate_uv_tokenonly[uv_tx_size],
+                                &dist_uv[uv_tx_size],
+                                &skip_uv[uv_tx_size],
+                                bsize < BLOCK_8X8 ? BLOCK_8X8 : bsize,
+                                uv_tx_size);
+      }
+    }
 
-  // If we used an estimate for the uv intra rd in the loop above...
-  if (sf->use_uv_intra_rd_estimate) {
-    // Do Intra UV best rd mode selection if best mode choice above was intra.
-    if (best_mbmode.ref_frame[0] == INTRA_FRAME) {
-      TX_SIZE uv_tx_size;
-      *mbmi = best_mbmode;
-      uv_tx_size = get_uv_tx_size(mbmi, &xd->plane[1]);
-      rd_pick_intra_sbuv_mode(cpi, x, ctx, &rate_uv_intra[uv_tx_size],
-                              &rate_uv_tokenonly[uv_tx_size],
-                              &dist_uv[uv_tx_size],
-                              &skip_uv[uv_tx_size],
-                              bsize < BLOCK_8X8 ? BLOCK_8X8 : bsize,
-                              uv_tx_size);
+    assert((cm->interp_filter == SWITCHABLE) ||
+           (cm->interp_filter == best_mbmode.interp_filter) ||
+           !is_inter_block(&best_mbmode));
+
+    if (!cpi->rc.is_src_frame_alt_ref)
+      update_rd_thresh_fact(cpi, bsize, best_mode_index);
+
+    // macroblock modes
+    *mbmi = best_mbmode;
+    x->skip |= best_skip2;
+
+    for (i = 0; i < REFERENCE_MODES; ++i) {
+      if (best_pred_rd[i] == INT64_MAX)
+        best_pred_diff[i] = INT_MIN;
+      else
+        best_pred_diff[i] = best_rd - best_pred_rd[i];
+    }
+
+    if (!x->skip) {
+      for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; i++) {
+        if (best_filter_rd[i] == INT64_MAX)
+          best_filter_diff[i] = 0;
+        else
+          best_filter_diff[i] = best_rd - best_filter_rd[i];
+      }
+      if (cm->interp_filter == SWITCHABLE)
+        assert(best_filter_diff[SWITCHABLE_FILTERS] == 0);
+      for (i = 0; i < TX_MODES; i++) {
+        if (best_tx_rd[i] == INT64_MAX)
+          best_tx_diff[i] = 0;
+        else
+          best_tx_diff[i] = best_rd - best_tx_rd[i];
+      }
+    } else {
+      vp9_zero(best_filter_diff);
+      vp9_zero(best_tx_diff);
+    }
+
+    // TODO(yunqingwang): Moving this line in front of the above
+    // best_filter_diff updating code causes PSNR loss. Need to
+    // figure out the confliction.
+    x->skip |= best_mode_skippable;
+
+    if (!x->skip && !x->select_tx_size) {
+      int has_high_freq_coeff = 0;
+      int plane;
+      int max_plane = is_inter_block(&xd->mi[0].src_mi->mbmi)
+          ? MAX_MB_PLANE : 1;
+      for (plane = 0; plane < max_plane; ++plane) {
+        x->plane[plane].eobs = ctx->eobs_pbuf[plane][1];
+        has_high_freq_coeff |= vp9_has_high_freq_in_plane(x, bsize, plane);
+      }
+
+      for (plane = max_plane; plane < MAX_MB_PLANE; ++plane) {
+        x->plane[plane].eobs = ctx->eobs_pbuf[plane][2];
+        has_high_freq_coeff |= vp9_has_high_freq_in_plane(x, bsize, plane);
+      }
+
+      best_mode_skippable |= !has_high_freq_coeff;
     }
+
+    store_coding_context(x, ctx, best_mode_index, best_pred_diff,
+                         best_tx_diff, best_filter_diff, best_mode_skippable);
   }
+#if CONFIG_COPY_MODE
+  for (copy_mode = REF0;
+       copy_mode < (COPY_MODE)(MIN(REF0 + inter_ref_count, COPY_MODE_COUNT));
+       copy_mode++) {
+    int i, rate2, rate_y, rate_uv, rate_copy_mode, this_skip2,
+        skippable, skippable_y, skippable_uv;
+    int64_t distortion2, distortion_y, distortion_uv, this_rd,
+            ssey, sseuv, total_sse, tx_cache[TX_MODES];
+#if CONFIG_EXT_TX
+    EXT_TX_TYPE tx_type, best_tx_type;
+    TX_SIZE best_tx_size;
+    int rate2_tx, this_skip2_tx;
+    int64_t distortion2_tx, bestrd_tx = INT64_MAX;
+    uint8_t tmp_zcoeff_blk[256];
+#endif
 
-  assert((cm->interp_filter == SWITCHABLE) ||
-         (cm->interp_filter == best_mbmode.interp_filter) ||
-         !is_inter_block(&best_mbmode));
+    *mbmi = *inter_ref_list[copy_mode - REF0];
+    mbmi->sb_type = bsize;
+    mbmi->inter_ref_count = inter_ref_count;
+    mbmi->copy_mode = copy_mode;
+    mbmi->mode = NEARESTMV;
+    x->skip = 0;
+    set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
+    for (i = 0; i < MAX_MB_PLANE; i++) {
+      xd->plane[i].pre[0] = yv12_mb[mbmi->ref_frame[0]][i];
+      if (mbmi->ref_frame[1] > INTRA_FRAME)
+        xd->plane[i].pre[1] = yv12_mb[mbmi->ref_frame[1]][i];
+    }
+    vp9_build_inter_predictors_sb(xd, mi_row, mi_col, bsize);
+    vp9_subtract_plane(x, bsize, 0);
 
-  if (!cpi->rc.is_src_frame_alt_ref)
-    update_rd_thresh_fact(cpi, bsize, best_mode_index);
+    for (i = 0; i < TX_MODES; ++i)
+      tx_cache[i] = INT64_MAX;
+#if CONFIG_EXT_TX
+    for (tx_type = NORM; tx_type < EXT_TX_TYPES; tx_type++) {
+      mbmi->ext_txfrm = tx_type;
+#endif
+      super_block_yrd(cpi, x, &rate_y, &distortion_y, &skippable_y, &ssey,
+                      bsize, tx_cache, INT64_MAX);
+      super_block_uvrd(cpi, x, &rate_uv, &distortion_uv, &skippable_uv, &sseuv,
+                       bsize, INT64_MAX);
 
-  // macroblock modes
-  *mbmi = best_mbmode;
-  x->skip |= best_skip2;
+      rate2 = rate_y + rate_uv;
+      distortion2 = distortion_y + distortion_uv;
+      skippable = skippable_y && skippable_uv;
+      total_sse = ssey + sseuv;
 
-  for (i = 0; i < REFERENCE_MODES; ++i) {
-    if (best_pred_rd[i] == INT64_MAX)
-      best_pred_diff[i] = INT_MIN;
+      if (skippable) {
+        rate2 -= (rate_y + rate_uv);
+        rate_y = 0;
+        rate_uv = 0;
+        rate2 += vp9_cost_bit(vp9_get_skip_prob(cm, xd), 1);
+        this_skip2 = 1;
+      } else if (!xd->lossless) {
+#if CONFIG_EXT_TX
+        if (mbmi->tx_size < TX_32X32)
+          rate2 += cpi->ext_tx_costs[mbmi->tx_size][mbmi->ext_txfrm];
+#endif  // CONFIG_EXT_TX
+        if (RDCOST(x->rdmult, x->rddiv, rate2, distortion2) <
+            RDCOST(x->rdmult, x->rddiv, 0, total_sse)) {
+          rate2 += vp9_cost_bit(vp9_get_skip_prob(cm, xd), 0);
+          this_skip2 = 0;
+        } else {
+          rate2 = vp9_cost_bit(vp9_get_skip_prob(cm, xd), 1);
+          distortion2 = total_sse;
+          rate_y = 0;
+          rate_uv = 0;
+          this_skip2 = 1;
+        }
+      } else {
+        rate2 += vp9_cost_bit(vp9_get_skip_prob(cm, xd), 0);
+        this_skip2 = 0;
+      }
+#if CONFIG_EXT_TX
+      this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2);
+      if (tx_type == NORM || this_rd < (bestrd_tx * ext_tx_th)) {
+        bestrd_tx = this_rd;
+        best_tx_type = tx_type;
+        best_tx_size = mbmi->tx_size;
+        rate2_tx = rate2;
+        distortion2_tx = distortion2;
+        this_skip2_tx = this_skip2;
+        vpx_memcpy(tmp_zcoeff_blk, x->zcoeff_blk[mbmi->tx_size],
+                   sizeof(uint8_t) * ctx->num_4x4_blk);
+      }
+    }
+    if (best_tx_size < TX_32X32)
+      mbmi->ext_txfrm = best_tx_type;
     else
-      best_pred_diff[i] = best_rd - best_pred_rd[i];
+      mbmi->ext_txfrm = NORM;
+    mbmi->tx_size = best_tx_size;
+    vpx_memcpy(x->zcoeff_blk[mbmi->tx_size], tmp_zcoeff_blk,
+               sizeof(uint8_t) * ctx->num_4x4_blk);
+
+    rate2 = rate2_tx;
+    distortion2 = distortion2_tx;
+    this_skip2 = this_skip2_tx;
+#endif  // CONFIG_EXT_TX
+
+    rate_copy_mode =
+        vp9_cost_bit(cm->fc.copy_noref_prob[copy_mode_context][bsize], 1);
+    if (inter_ref_count == 2)
+      rate_copy_mode +=
+          cpi->copy_mode_cost_l2[copy_mode_context][copy_mode - REF0];
+    else if (inter_ref_count > 2)
+      rate_copy_mode +=
+          cpi->copy_mode_cost[copy_mode_context][copy_mode - REF0];
+    rate2 += rate_copy_mode;
+    this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2);
+
+    if (this_rd < best_rd) {
+      rd_cost->rate = rate2;
+      rd_cost->dist = distortion2;
+      rd_cost->rdcost = this_rd;
+#if CONFIG_SUPERTX
+      *returnrate_nocoef = rate_copy_mode;
+#endif
+      best_rd = this_rd;
+      best_mbmode = *mbmi;
+      best_skip2 = this_skip2;
+      best_mode_skippable = skippable;
+      // if (!x->select_tx_size) swap_block_ptr(x, ctx, 1, 0, 0, MAX_MB_PLANE);
+      vpx_memcpy(ctx->zcoeff_blk, x->zcoeff_blk[mbmi->tx_size],
+                 sizeof(uint8_t) * ctx->num_4x4_blk);
+    }
+
+    if (bsize < BLOCK_32X32) {
+      if (bsize < BLOCK_16X16)
+        tx_cache[ALLOW_16X16] = tx_cache[ALLOW_8X8];
+      tx_cache[ALLOW_32X32] = tx_cache[ALLOW_16X16];
+    }
+    if (this_rd != INT64_MAX) {
+      for (i = 0; i < TX_MODES && tx_cache[i] < INT64_MAX; i++) {
+        int64_t adj_rd = INT64_MAX;
+        adj_rd = this_rd + tx_cache[i] - tx_cache[cm->tx_mode];
+
+        if (adj_rd < best_tx_rd[i])
+          best_tx_rd[i] = adj_rd;
+      }
+    }
+  }
+  if ((best_mode_index < 0 && best_mbmode.copy_mode == NOREF)
+      || best_rd >= best_rd_so_far) {
+    rd_cost->rate = INT_MAX;
+    rd_cost->rdcost = INT64_MAX;
+    return;
+  }
+
+  *mbmi = best_mbmode;
+  if (mbmi->copy_mode != NOREF) {
+    x->skip = best_skip2;
+    ctx->skip = x->skip;
+    ctx->skippable = best_mode_skippable;
+    ctx->mic = *xd->mi[0].src_mi;
   }
+  set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
 
   if (!x->skip) {
-    for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; i++) {
-      if (best_filter_rd[i] == INT64_MAX)
-        best_filter_diff[i] = 0;
-      else
-        best_filter_diff[i] = best_rd - best_filter_rd[i];
-    }
-    if (cm->interp_filter == SWITCHABLE)
-      assert(best_filter_diff[SWITCHABLE_FILTERS] == 0);
     for (i = 0; i < TX_MODES; i++) {
       if (best_tx_rd[i] == INT64_MAX)
         best_tx_diff[i] = 0;
       else
         best_tx_diff[i] = best_rd - best_tx_rd[i];
     }
+    vpx_memcpy(ctx->tx_rd_diff, best_tx_diff, sizeof(ctx->tx_rd_diff));
   } else {
     vp9_zero(best_filter_diff);
     vp9_zero(best_tx_diff);
   }
-
-  // TODO(yunqingwang): Moving this line in front of the above best_filter_diff
-  // updating code causes PSNR loss. Need to figure out the confliction.
-  x->skip |= best_mode_skippable;
-
-  if (!x->skip && !x->select_tx_size) {
-    int has_high_freq_coeff = 0;
-    int plane;
-    int max_plane = is_inter_block(&xd->mi[0].src_mi->mbmi)
-                        ? MAX_MB_PLANE : 1;
-    for (plane = 0; plane < max_plane; ++plane) {
-      x->plane[plane].eobs = ctx->eobs_pbuf[plane][1];
-      has_high_freq_coeff |= vp9_has_high_freq_in_plane(x, bsize, plane);
-    }
-
-    for (plane = max_plane; plane < MAX_MB_PLANE; ++plane) {
-      x->plane[plane].eobs = ctx->eobs_pbuf[plane][2];
-      has_high_freq_coeff |= vp9_has_high_freq_in_plane(x, bsize, plane);
-    }
-
-    best_mode_skippable |= !has_high_freq_coeff;
-  }
-
-  store_coding_context(x, ctx, best_mode_index, best_pred_diff,
-                       best_tx_diff, best_filter_diff, best_mode_skippable);
+#endif
 }
 
 void vp9_rd_pick_inter_mode_sb_seg_skip(VP9_COMP *cpi, MACROBLOCK *x,
@@ -4218,6 +4413,9 @@ void vp9_rd_pick_inter_mode_sub8x8(VP9_COMP *cpi, MACROBLOCK *x,
   best_rd = best_rd_so_far;
   best_yrd = best_rd_so_far;
 #endif
+#if CONFIG_COPY_MODE
+  mbmi->copy_mode = NOREF;
+#endif
 
   x->skip_encode = sf->skip_encode_frame && x->q_index < QIDX_SKIP_THRESH;
   vpx_memset(x->zcoeff_blk[TX_4X4], 0, 4);