Add motion selection to ext_skip

A new block mode, referred to as skip_mode is added. If a block is
coded as skip_mode, it will be inter-coded, with its references and
motion vectors derived from its neighboring blocks with zero-residue.
Otherwise, the block can be coded in the current intra or inter mode.

The computational load on skip_mode evaluation at the encoder should
be kept minimum. No transform size / type evaluations are needed.

Change-Id: I5aef0159c7d5ecd64258510835903375d6c536d6
diff --git a/av1/common/mvref_common.c b/av1/common/mvref_common.c
index 10dc769..51d80dd 100644
--- a/av1/common/mvref_common.c
+++ b/av1/common/mvref_common.c
@@ -1415,62 +1415,9 @@
   }
 }
 #endif  // CONFIG_FRAME_SIGN_BIAS
-
-#if CONFIG_EXT_SKIP
-void av1_setup_skip_mode_allowed(AV1_COMMON *const cm) {
-  cm->is_skip_mode_allowed = 0;
-  cm->ref_frame_idx_0 = cm->ref_frame_idx_1 = INVALID_IDX;
-
-  if (cm->frame_type == KEY_FRAME || cm->intra_only) return;
-
-  BufferPool *const pool = cm->buffer_pool;
-  RefCntBuffer *const frame_bufs = pool->frame_bufs;
-
-  int ref_frame_offset_0 = -1;
-  int ref_frame_offset_1 = INT_MAX;
-  int ref_idx_0 = INVALID_IDX;
-  int ref_idx_1 = INVALID_IDX;
-
-  // Identify the nearest forward and backward references
-  for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) {
-    RefBuffer *const ref_frame = &cm->frame_refs[i];
-    const int buf_idx = ref_frame->idx;
-
-    // Invalid reference frame buffer
-    if (buf_idx == INVALID_IDX) continue;
-
-    const int ref_offset = frame_bufs[buf_idx].cur_frame_offset;
-    if (ref_offset < (int)cm->frame_offset) {
-      // Forward reference
-      if (ref_offset > ref_frame_offset_0) {
-        ref_frame_offset_0 = ref_offset;
-        ref_idx_0 = i;
-      }
-    } else if (ref_offset > (int)cm->frame_offset) {
-      // Backward reference
-      if (ref_offset < ref_frame_offset_1) {
-        ref_frame_offset_1 = ref_offset;
-        ref_idx_1 = i;
-      }
-    }
-  }
-
-  // Flag is set when and only when both forward and backward references
-  // are available and their distance is no greater than 3, i.e. as
-  // opposed to the current frame position, the reference distance pair are
-  // either: (1, 1), (1, 2), or (2, 1).
-  if (ref_idx_0 != INVALID_IDX && ref_idx_1 != INVALID_IDX) {
-    if ((ref_frame_offset_1 - ref_frame_offset_0) <= 3) {
-      cm->is_skip_mode_allowed = 1;
-      cm->ref_frame_idx_0 = ref_idx_0;
-      cm->ref_frame_idx_1 = ref_idx_1;
-    }
-  }
-}
-#endif  // CONFIG_EXT_SKIP
 #endif  // CONFIG_FRAME_MARKER
 
-#if CONFIG_MFMV
+#if CONFIG_MFMV || CONFIG_EXT_SKIP
 // Although we assign 32 bit integers, all the values are strictly under 14
 // bits.
 static int div_mult[32] = {
@@ -1487,7 +1434,9 @@
   output->col =
       (int16_t)(ROUND_POWER_OF_TWO_SIGNED(ref.col * num * div_mult[den], 14));
 }
+#endif  // CONFIG_MFMV || CONFIG_EXT_SKIP
 
+#if CONFIG_MFMV
 #define MAX_OFFSET_WIDTH 64
 #define MAX_OFFSET_HEIGHT 0
 
@@ -2240,3 +2189,271 @@
   return np;
 }
 #endif  // CONFIG_EXT_WARPED_MOTION
+
+#if CONFIG_EXT_SKIP
+void av1_setup_skip_mode_allowed(AV1_COMMON *const cm) {
+  cm->is_skip_mode_allowed = 0;
+  cm->ref_frame_idx_0 = cm->ref_frame_idx_1 = INVALID_IDX;
+
+  if (cm->frame_type == KEY_FRAME || cm->intra_only) return;
+
+  RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
+  const int cur_frame_offset = cm->frame_offset;
+  int ref_frame_offset[2] = { -1, INT_MAX };
+  int ref_idx[2] = { INVALID_IDX, INVALID_IDX };
+  int ref_buf_idx[2] = { INVALID_IDX, INVALID_IDX };
+
+  // Identify the nearest forward and backward references
+  for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) {
+    const int buf_idx = cm->frame_refs[i].idx;
+    if (buf_idx == INVALID_IDX) continue;
+
+    const int ref_offset = frame_bufs[buf_idx].cur_frame_offset;
+    if (ref_offset < cur_frame_offset) {
+      // Forward reference
+      if (ref_offset > ref_frame_offset[0]) {
+        ref_frame_offset[0] = ref_offset;
+        ref_idx[0] = i;
+        ref_buf_idx[0] = buf_idx;
+      }
+    } else if (ref_offset > cur_frame_offset) {
+      // Backward reference
+      if (ref_offset < ref_frame_offset[1]) {
+        ref_frame_offset[1] = ref_offset;
+        ref_idx[1] = i;
+        ref_buf_idx[1] = buf_idx;
+      }
+    }
+  }
+
+  // Flag is set when and only when both forward and backward references
+  // are available and their distance is no greater than 3, i.e. as
+  // opposed to the current frame position, the reference distance pair are
+  // either: (1, 1), (1, 2), or (2, 1).
+  if (ref_idx[0] != INVALID_IDX && ref_idx[1] != INVALID_IDX) {
+    const int cur_to_fwd = cm->frame_offset - ref_frame_offset[0];
+    const int cur_to_bwd = ref_frame_offset[1] - cm->frame_offset;
+#if 0
+    if ((ref_frame_offset[1] - ref_frame_offset[0]) <= 3)
+#endif  // 0
+    if (abs(cur_to_fwd - cur_to_bwd) <= 1) {
+      cm->is_skip_mode_allowed = 1;
+      cm->ref_frame_idx_0 = ref_idx[0];
+      cm->ref_frame_idx_1 = ref_idx[1];
+    }
+  }
+
+  // Set up the temporal mv candidates for skip mode.
+  cm->tpl_frame_ref0_idx = INVALID_IDX;
+  if (cm->is_skip_mode_allowed && cm->use_ref_frame_mvs) {
+    const int tpl_ref1_buf_idx = ref_buf_idx[1];
+    const int tpl_ref1_ref_offsets[INTER_REFS_PER_FRAME] = {
+      frame_bufs[tpl_ref1_buf_idx].lst_frame_offset,
+      frame_bufs[tpl_ref1_buf_idx].lst2_frame_offset,
+      frame_bufs[tpl_ref1_buf_idx].lst3_frame_offset,
+      frame_bufs[tpl_ref1_buf_idx].gld_frame_offset,
+      frame_bufs[tpl_ref1_buf_idx].bwd_frame_offset,
+      frame_bufs[tpl_ref1_buf_idx].alt2_frame_offset,
+      frame_bufs[tpl_ref1_buf_idx].alt_frame_offset
+    };
+
+    for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) {
+      if (tpl_ref1_ref_offsets[i] == ref_frame_offset[0]) {
+        cm->tpl_frame_ref0_idx = i;
+        break;
+      }
+    }
+  }
+}
+
+// Identify mvs for skip mode in the following order:
+// (1) Search the spatial two neighboring blocks (left/top);
+// (2) Search the temporal neighboring blocks;
+// (3) Consider NEAREST_NEARESTMV.
+
+#define SKIP_MODE_MV_LISTS 3
+#define SPATIAL_CANDIDATES 2
+#define TEMPORAL_CANDIDATES 2
+#define TOTAL_CANDIDATES (SPATIAL_CANDIDATES + TEMPORAL_CANDIDATES)
+
+void av1_setup_skip_mode_mvs(const AV1_COMMON *cm, const MACROBLOCKD *xd,
+                             MB_MODE_INFO *mbmi, int mi_row, int mi_col,
+                             const int_mv nearest_mv[2], find_mv_refs_sync sync,
+                             void *const data) {
+#if 0
+  const int sb_mi_size = mi_size_wide[cm->sb_size];
+#endif  // 0
+  const TileInfo *const tile = &xd->tile;
+  int i;
+
+  const MV_REFERENCE_FRAME skip_mode_refs[2] = {
+    LAST_FRAME + cm->ref_frame_idx_0, LAST_FRAME + cm->ref_frame_idx_1
+  };
+  const int8_t ref_frame_types[SKIP_MODE_MV_LISTS] = {
+    skip_mode_refs[0], skip_mode_refs[1], av1_ref_frame_type(skip_mode_refs)
+  };
+  int_mv mv_list[SKIP_MODE_MV_LISTS][TOTAL_CANDIDATES][2];
+  int mv_list_count[SKIP_MODE_MV_LISTS] = { 0 };
+
+  const BLOCK_SIZE bsize = mbmi->sb_type;
+  const int bw = block_size_wide[AOMMAX(bsize, BLOCK_8X8)];
+  const int bh = block_size_high[AOMMAX(bsize, BLOCK_8X8)];
+  const int num_8x8_blocks_wide = num_8x8_blocks_wide_lookup[bsize];
+  const int num_8x8_blocks_high = num_8x8_blocks_high_lookup[bsize];
+
+  // === Search mv candidate(s) over spatial neighboring blocks.
+  POSITION mv_search_pos_cur[SPATIAL_CANDIDATES];
+  mv_search_pos_cur[0].row = num_8x8_blocks_high - 1;  // LEFT
+  mv_search_pos_cur[0].col = -1;
+  mv_search_pos_cur[1].row = -1;  // TOP
+  mv_search_pos_cur[1].col = num_8x8_blocks_wide - 1;
+
+  MB_MODE_INFO *candidate_mbmi[SPATIAL_CANDIDATES] = { NULL };
+  for (i = 0; i < SPATIAL_CANDIDATES; ++i) {
+    const POSITION *const mv_pos = &mv_search_pos_cur[i];
+    if (is_inside(tile, mi_col, mi_row, cm->mi_rows, cm, mv_pos)) {
+      candidate_mbmi[i] =
+          !xd->mi[mv_pos->col + mv_pos->row * xd->mi_stride]
+              ? NULL
+              : &(xd->mi[mv_pos->col + mv_pos->row * xd->mi_stride]->mbmi);
+#if 0
+      if (candidate_mbmi[i] == NULL) continue;
+      // TODO(zoeliu): To investigate whether following sanity check is needed.
+      if ((mi_row & (sb_mi_size - 1)) + mv_pos->row >= sb_mi_size ||
+          (mi_col & (sb_mi_size - 1)) + mv_pos->col >= sb_mi_size)
+        continue;
+#endif  // 0
+    }
+  }
+
+  // First scan on the spatial neighbors, considering both reference frames
+  // matched for compound mode.
+  for (i = 0; i < SPATIAL_CANDIDATES; ++i) {
+    if (candidate_mbmi[i]) {
+      if (has_second_ref(candidate_mbmi[i])) {  // comp
+        if (av1_ref_frame_type(candidate_mbmi[i]->ref_frame) ==
+            ref_frame_types[2])
+          SKIP_MODE_MV_LIST_ADD(candidate_mbmi[i]->mv, mv_list, mv_list_count,
+                                2, bw, bh, xd);
+      } else {  // single
+        if (candidate_mbmi[i]->ref_frame[0] == ref_frame_types[0])
+          SKIP_MODE_MV_LIST_ADD(candidate_mbmi[i]->mv, mv_list, mv_list_count,
+                                0, bw, bh, xd);
+        else if (candidate_mbmi[i]->ref_frame[0] == ref_frame_types[1])
+          SKIP_MODE_MV_LIST_ADD(candidate_mbmi[i]->mv, mv_list, mv_list_count,
+                                1, bw, bh, xd);
+      }
+    }
+  }
+
+  // Re-scan mv candidate(s) over spatial neighboring blocks of compound mode,
+  // with only one reference frame matching the skip mode.
+  for (i = 0; i < SPATIAL_CANDIDATES; ++i) {
+    if (candidate_mbmi[i] && has_second_ref(candidate_mbmi[i])) {  // comp
+      if (candidate_mbmi[i]->ref_frame[0] == ref_frame_types[0] ||
+          candidate_mbmi[i]->ref_frame[1] == ref_frame_types[1]) {
+        const int rf_idx =
+            (candidate_mbmi[i]->ref_frame[1] == ref_frame_types[1]);
+        const int_mv rf_mv[2] = { candidate_mbmi[i]->mv[rf_idx],
+                                  candidate_mbmi[i]->mv[1 - rf_idx] };
+
+        SKIP_MODE_MV_LIST_ADD(rf_mv, mv_list, mv_list_count, rf_idx, bw, bh,
+                              xd);
+      }
+    }
+  }
+
+// TODO(hkuang): Remove this sync after fixing pthread_cond_broadcast
+// on windows platform. The sync here is unncessary if use_perv_frame_mvs
+// is 0. But after removing it, there will be hang in the unit test on windows
+// due to several threads waiting for a thread's signal.
+#if defined(_WIN32) && !HAVE_PTHREAD_H
+  if (cm->frame_parallel_decode && sync != NULL) sync(data, mi_row);
+#endif
+
+  // === Search mv candidate(s) over temporal neighboring blocks.
+  if (cm->tpl_frame_ref0_idx != INVALID_IDX) {
+    // Synchronize here for frame parallel decode if sync function is provided.
+    if (cm->frame_parallel_decode && sync != NULL) {
+      sync(data, mi_row);
+    }
+
+    POSITION mv_search_pos_tpl[TEMPORAL_CANDIDATES];
+    mv_search_pos_tpl[0].row = num_8x8_blocks_high - 1;  // current
+    mv_search_pos_tpl[0].col = num_8x8_blocks_wide - 1;
+    mv_search_pos_tpl[1].row = num_8x8_blocks_high;  // bottom-right
+    mv_search_pos_tpl[1].col = num_8x8_blocks_wide;
+
+    const int mvs_rows = (cm->mi_rows + 1) >> 1;
+    const int mvs_cols = (cm->mi_cols + 1) >> 1;
+
+    RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
+
+    const int tpl_ref0_buf_idx = cm->frame_refs[cm->ref_frame_idx_0].idx;
+    const int tpl_ref0_offset = frame_bufs[tpl_ref0_buf_idx].cur_frame_offset;
+    const int tpl_ref1_buf_idx = cm->frame_refs[cm->ref_frame_idx_1].idx;
+    const int tpl_ref1_offset = frame_bufs[tpl_ref1_buf_idx].cur_frame_offset;
+
+    MV_REF *const tpl_mvs_base = frame_bufs[tpl_ref1_buf_idx].mvs;
+
+    for (i = 0; i < TEMPORAL_CANDIDATES; ++i) {
+      const POSITION *const mv_pos = &mv_search_pos_tpl[i];
+      const int tpl_mvs_row = (mi_row + mv_pos->row + 1) >> 1;
+      const int tpl_mvs_col = (mi_col + mv_pos->col + 1) >> 1;
+
+      if (tpl_mvs_row >= 0 && tpl_mvs_row < mvs_rows && tpl_mvs_col >= 0 &&
+          tpl_mvs_col < mvs_cols) {
+        MV_REF *mv_ref = &tpl_mvs_base[tpl_mvs_row * mvs_cols + tpl_mvs_col];
+        MV_REFERENCE_FRAME tpl_frame_rf[2] = { mv_ref->ref_frame[0],
+                                               mv_ref->ref_frame[1] };
+
+        // Check whether the temporal candidate block has its reference frame 0
+        // point to the same forward reference most recent to the current frame.
+        if (tpl_frame_rf[0] <= INTRA_FRAME ||
+            FWD_RF_OFFSET(tpl_frame_rf[0]) != cm->tpl_frame_ref0_idx)
+          continue;
+
+        // Scale the temporal candiate mv of the same forward reference frame
+        // for the current frame.
+        const int cur_to_ref0 = AOMMAX(1, cm->frame_offset - tpl_ref0_offset);
+        const int ref1_to_ref0 = AOMMAX(1, tpl_ref1_offset - tpl_ref0_offset);
+
+        MV tpl_frame_mv[2] = { mv_ref->mv[0].as_mv, mv_ref->mv[1].as_mv };
+        int_mv candidate_mv;
+        get_mv_projection(&candidate_mv.as_mv, tpl_frame_mv[0], cur_to_ref0,
+                          ref1_to_ref0);
+
+        const int_mv tpl_mv[2] = { candidate_mv, mv_ref->mv[1] };
+        SKIP_MODE_MV_LIST_ADD(tpl_mv, mv_list, mv_list_count, 0, bw, bh, xd);
+      }
+    }
+  }
+
+  // === Finalize the mv/ref selection for the current block of skip mode.
+  // TODO(zoeliu): Several items to consider for possibly improving the coding
+  // performance further:
+  // (1) Consider more spatial / temporal neighboring blocks;
+  // (2) Signal the selection to differentiate between single or compoud mode;
+  // (3) May allow the use of the most recent forward reference of the temporal
+  //     neighboring block.
+  if (mv_list_count[2] > 0) {  // comp
+    mbmi->ref_frame[0] = cm->ref_frame_idx_0 + LAST_FRAME;
+    mbmi->ref_frame[1] = cm->ref_frame_idx_1 + LAST_FRAME;
+    mbmi->mv[0].as_int = mv_list[2][0][0].as_int;
+    mbmi->mv[1].as_int = mv_list[2][0][1].as_int;
+  } else if (mv_list_count[0] > 0) {  // single - forward
+    mbmi->ref_frame[0] = cm->ref_frame_idx_0 + LAST_FRAME;
+    mbmi->ref_frame[1] = -1;
+    mbmi->mv[0].as_int = mv_list[0][0][0].as_int;
+  } else if (mv_list_count[1] > 0) {  // single - backward
+    mbmi->ref_frame[0] = cm->ref_frame_idx_1 + LAST_FRAME;
+    mbmi->ref_frame[1] = -1;
+    mbmi->mv[0].as_int = mv_list[1][0][0].as_int;
+  } else {
+    mbmi->ref_frame[0] = cm->ref_frame_idx_0 + LAST_FRAME;
+    mbmi->ref_frame[1] = cm->ref_frame_idx_1 + LAST_FRAME;
+    mbmi->mv[0].as_int = nearest_mv[0].as_int;
+    mbmi->mv[1].as_int = nearest_mv[1].as_int;
+  }
+}
+#endif  // CONFIG_EXT_SKIP
diff --git a/av1/common/mvref_common.h b/av1/common/mvref_common.h
index f0640ef..608e220 100644
--- a/av1/common/mvref_common.h
+++ b/av1/common/mvref_common.h
@@ -174,6 +174,22 @@
     }                                                                         \
   } while (0)
 
+#if CONFIG_EXT_SKIP
+// This macro is used to add a motion vector pair to the skip mode mv list.
+#define SKIP_MODE_MV_LIST_ADD(mv, mv_list, mv_list_count, mv_list_idx, bw, bh, \
+                              xd)                                              \
+  do {                                                                         \
+    const int mv_idx = (mv_list_count)[mv_list_idx];                           \
+    (mv_list)[mv_list_idx][mv_idx][0] = (mv)[0];                               \
+    CLIP_IN_ADD(&(mv_list)[mv_list_idx][mv_idx][0].as_mv, (bw), (bh), (xd));   \
+    if (mv_list_idx == 2) {                                                    \
+      (mv_list)[mv_list_idx][mv_idx][1] = (mv)[1];                             \
+      CLIP_IN_ADD(&(mv_list)[mv_list_idx][mv_idx][1].as_mv, (bw), (bh), (xd)); \
+    }                                                                          \
+    (mv_list_count)[mv_list_idx]++;                                            \
+  } while (0)
+#endif  // CONFIG_EXT_SKIP
+
 // Checks that the given mi_row, mi_col and search point
 // are inside the borders of the tile.
 static INLINE int is_inside(const TileInfo *const tile, int mi_col, int mi_row,
@@ -389,6 +405,12 @@
                       int16_t *compound_mode_context, int_mv *mv_ref_list,
                       int mi_row, int mi_col, find_mv_refs_sync sync,
                       void *const data, int16_t *mode_context);
+#if CONFIG_EXT_SKIP
+void av1_setup_skip_mode_mvs(const AV1_COMMON *cm, const MACROBLOCKD *xd,
+                             MB_MODE_INFO *mbmi, int mi_row, int mi_col,
+                             const int_mv nearest_mv[2], find_mv_refs_sync sync,
+                             void *const data);
+#endif  // CONFIG_EXT_SKIP
 
 // check a list of motion vectors by sad score using a number rows of pixels
 // above and a number cols of pixels in the left to select the one with best
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h
index 3952256..3755268 100644
--- a/av1/common/onyxc_int.h
+++ b/av1/common/onyxc_int.h
@@ -271,8 +271,10 @@
   RefBuffer frame_refs[INTER_REFS_PER_FRAME];
 #if CONFIG_EXT_SKIP
   int is_skip_mode_allowed;
+  int skip_mode_flag;
   int ref_frame_idx_0;
   int ref_frame_idx_1;
+  int tpl_frame_ref0_idx;
 #endif  // CONFIG_EXT_SKIP
 
   int new_fb_idx;
diff --git a/av1/common/reconinter.h b/av1/common/reconinter.h
index 272e4f6..f1e1ab1 100644
--- a/av1/common/reconinter.h
+++ b/av1/common/reconinter.h
@@ -448,10 +448,10 @@
 static INLINE int av1_is_interp_needed(const MACROBLOCKD *const xd) {
   (void)xd;
   const MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
-  if (mbmi->motion_mode == WARPED_CAUSAL) return 0;
 #if CONFIG_EXT_SKIP
   if (mbmi->skip_mode) return 0;
 #endif  // CONFIG_EXT_SKIP
+  if (mbmi->motion_mode == WARPED_CAUSAL) return 0;
   if (is_nontrans_global_motion(xd)) return 0;
   return 1;
 }
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 650a053..91b14ad 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -3008,6 +3008,22 @@
   }
   av1_setup_frame_buf_refs(cm);
 
+#if CONFIG_EXT_SKIP
+  av1_setup_skip_mode_allowed(cm);
+  cm->skip_mode_flag = cm->is_skip_mode_allowed ? aom_rb_read_bit(rb) : 0;
+#if 0
+  printf(
+      "DECODER: Frame=%d, frame_offset=%d, show_frame=%d, "
+      "show_existing_frame=%d, is_skip_mode_allowed=%d, "
+      "ref_frame_idx=(%d,%d), frame_reference_mode=%d, "
+      "tpl_frame_ref0_idx=%d, skip_mode_flag=%d\n\n",
+      cm->current_video_frame, cm->frame_offset, cm->show_frame,
+      cm->show_existing_frame, cm->is_skip_mode_allowed, cm->ref_frame_idx_0,
+      cm->ref_frame_idx_1, cm->reference_mode, cm->tpl_frame_ref0_idx,
+      cm->skip_mode_flag);
+#endif  // 0
+#endif  // CONFIG_EXT_SKIP
+
 #if CONFIG_FRAME_SIGN_BIAS
 #if CONFIG_OBU
   if (cm->frame_type != S_FRAME)
@@ -3516,16 +3532,6 @@
                            (cm->last_frame_type != KEY_FRAME);
 #endif  // CONFIG_TEMPMV_SIGNALING
 
-#if CONFIG_EXT_SKIP
-  av1_setup_skip_mode_allowed(cm);
-#if 0
-  printf("\nDECODER: Frame=%d, frame_offset=%d, show_frame=%d, "
-         "is_skip_mode_allowed=%d, ref_frame_idx=(%d,%d)\n",
-         cm->current_video_frame, cm->frame_offset, cm->show_frame,
-         cm->is_skip_mode_allowed, cm->ref_frame_idx_0, cm->ref_frame_idx_1);
-#endif  // 0
-#endif  // CONFIG_EXT_SKIP
-
 #if CONFIG_MFMV
   av1_setup_motion_field(cm);
 #endif  // CONFIG_MFMV
diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c
index 5e06b37..8b17582 100644
--- a/av1/decoder/decodemv.c
+++ b/av1/decoder/decodemv.c
@@ -254,6 +254,10 @@
   MB_MODE_INFO *mbmi = &mi->mbmi;
   (void)cm;
 
+#if CONFIG_EXT_SKIP
+  if (mbmi->skip_mode) return SIMPLE_TRANSLATION;
+#endif  // CONFIG_EXT_SKIP
+
   const MOTION_MODE last_motion_mode_allowed =
       motion_mode_allowed(0, xd->global_motion, xd, mi);
   int motion_mode;
@@ -278,22 +282,9 @@
 static PREDICTION_MODE read_inter_compound_mode(AV1_COMMON *cm, MACROBLOCKD *xd,
                                                 aom_reader *r, int16_t ctx) {
   (void)cm;
-#if CONFIG_EXT_SKIP
-  FRAME_CONTEXT *const ec_ctx = xd->tile_ctx;
-  const int mode =
-      xd->mi[0]->mbmi.skip_mode
-          ? (NEAREST_NEARESTMV - NEAREST_NEARESTMV)
-          : aom_read_symbol(r, ec_ctx->inter_compound_mode_cdf[ctx],
-                            INTER_COMPOUND_MODES, ACCT_STR);
-  if (xd->mi[0]->mbmi.skip_mode && r->allow_update_cdf)
-    update_cdf(ec_ctx->inter_compound_mode_cdf[ctx], mode,
-               INTER_COMPOUND_MODES);
-#else
   const int mode =
       aom_read_symbol(r, xd->tile_ctx->inter_compound_mode_cdf[ctx],
                       INTER_COMPOUND_MODES, ACCT_STR);
-#endif  // CONFIG_EXT_SKIP
-
   FRAME_COUNTS *counts = xd->counts;
   if (counts) ++counts->inter_compound_mode[ctx][mode];
   assert(is_inter_compound_mode(NEAREST_NEARESTMV + mode));
@@ -602,23 +593,23 @@
 #if CONFIG_EXT_SKIP
 static int read_skip_mode(AV1_COMMON *cm, const MACROBLOCKD *xd, int segment_id,
                           aom_reader *r) {
-  if (!cm->is_skip_mode_allowed) return 0;
+  if (!cm->skip_mode_flag) return 0;
 
   if (segfeature_active(&cm->seg, segment_id, SEG_LVL_SKIP)) {
     // TODO(zoeliu): To revisit the handling of this scenario.
     return 0;
-  } else {
-    const int ctx = av1_get_skip_mode_context(xd);
-    FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
-    const int skip_mode =
-        aom_read_symbol(r, ec_ctx->skip_mode_cdfs[ctx], 2, ACCT_STR);
-    FRAME_COUNTS *counts = xd->counts;
-    if (counts) ++counts->skip_mode[ctx][skip_mode];
-
-    // TODO(zoeliu): To handle:
-    //               if (!is_comp_ref_allowed(xd->mi[0]->mbmi.sb_type))
-    return skip_mode;
   }
+
+  if (!is_comp_ref_allowed(xd->mi[0]->mbmi.sb_type)) return 0;
+
+  const int ctx = av1_get_skip_mode_context(xd);
+  FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
+  const int skip_mode =
+      aom_read_symbol(r, ec_ctx->skip_mode_cdfs[ctx], 2, ACCT_STR);
+  FRAME_COUNTS *counts = xd->counts;
+  if (counts) ++counts->skip_mode[ctx][skip_mode];
+
+  return skip_mode;
 }
 #endif  // CONFIG_EXT_SKIP
 
@@ -1258,21 +1249,6 @@
   }
 }
 
-#if CONFIG_EXT_SKIP
-static void update_block_reference_mode(AV1_COMMON *cm, const MACROBLOCKD *xd,
-                                        REFERENCE_MODE mode,
-                                        uint8_t allow_update_cdf) {
-  if (cm->reference_mode == REFERENCE_MODE_SELECT) {
-    assert(mode == SINGLE_REFERENCE || mode == COMPOUND_REFERENCE);
-    const int ctx = av1_get_reference_mode_context(cm, xd);
-    if (allow_update_cdf)
-      update_cdf(xd->tile_ctx->comp_inter_cdf[ctx], mode, 2);
-    FRAME_COUNTS *counts = xd->counts;
-    if (counts) ++counts->comp_inter[ctx][mode];
-  }
-}
-#endif  // CONFIG_EXT_SKIP
-
 #define READ_REF_BIT(pname) \
   aom_read_symbol(r, av1_get_pred_cdf_##pname(cm, xd), 2, ACCT_STR)
 #define READ_REF_BIT2(pname) \
@@ -1294,60 +1270,10 @@
 #endif  // CONFIG_EXT_COMP_REFS
 
 #if CONFIG_EXT_SKIP
-#if CONFIG_EXT_COMP_REFS
-static void update_comp_reference_type(AV1_COMMON *cm, const MACROBLOCKD *xd,
-                                       COMP_REFERENCE_TYPE comp_ref_type,
-                                       uint8_t allow_update_cdf) {
-  assert(comp_ref_type == UNIDIR_COMP_REFERENCE ||
-         comp_ref_type == BIDIR_COMP_REFERENCE);
-  (void)cm;
-  const int ctx = av1_get_comp_reference_type_context(xd);
-  if (allow_update_cdf)
-    update_cdf(xd->tile_ctx->comp_ref_type_cdf[ctx], comp_ref_type, 2);
-  FRAME_COUNTS *counts = xd->counts;
-  if (counts) ++counts->comp_ref_type[ctx][comp_ref_type];
-}
-#endif  // CONFIG_EXT_COMP_REFS
-
 static void set_ref_frames_for_skip_mode(AV1_COMMON *const cm,
-                                         MACROBLOCKD *const xd,
-                                         MV_REFERENCE_FRAME ref_frame[2],
-                                         uint8_t allow_update_cdf) {
-  assert(xd->mi[0]->mbmi.skip_mode);
-
+                                         MV_REFERENCE_FRAME ref_frame[2]) {
   ref_frame[0] = LAST_FRAME + cm->ref_frame_idx_0;
   ref_frame[1] = LAST_FRAME + cm->ref_frame_idx_1;
-
-  const REFERENCE_MODE mode = COMPOUND_REFERENCE;
-  update_block_reference_mode(cm, xd, mode, allow_update_cdf);
-
-#if CONFIG_EXT_COMP_REFS
-  const COMP_REFERENCE_TYPE comp_ref_type = BIDIR_COMP_REFERENCE;
-  update_comp_reference_type(cm, xd, comp_ref_type, allow_update_cdf);
-#endif  // CONFIG_EXT_COMP_REFS
-
-// Update stats for both forward and backward references
-#define UPDATE_REF_BIT(bname, pname, cname, iname)          \
-  if (allow_update_cdf)                                     \
-    update_cdf(av1_get_pred_cdf_##pname(cm, xd), bname, 2); \
-  if (counts)                                               \
-    ++counts->comp_##cname[av1_get_pred_context_##pname(cm, xd)][iname][bname];
-
-  FRAME_COUNTS *counts = xd->counts;
-
-  const int bit = (ref_frame[0] == GOLDEN_FRAME || ref_frame[0] == LAST3_FRAME);
-  UPDATE_REF_BIT(bit, comp_ref_p, ref, 0)
-  if (!bit) {
-    UPDATE_REF_BIT(ref_frame[0] == LAST_FRAME, comp_ref_p1, ref, 1)
-  } else {
-    UPDATE_REF_BIT(ref_frame[0] == GOLDEN_FRAME, comp_ref_p2, ref, 2)
-  }
-
-  const int bit_bwd = ref_frame[1] == ALTREF_FRAME;
-  UPDATE_REF_BIT(bit_bwd, comp_bwdref_p, bwdref, 0)
-  if (!bit_bwd) {
-    UPDATE_REF_BIT(ref_frame[1] == ALTREF2_FRAME, comp_bwdref_p1, bwdref, 1)
-  }
 }
 #endif  // CONFIG_EXT_SKIP
 
@@ -1374,7 +1300,7 @@
   } else {
 #if CONFIG_EXT_SKIP
     if (xd->mi[0]->mbmi.skip_mode) {
-      set_ref_frames_for_skip_mode(cm, xd, ref_frame, r->allow_update_cdf);
+      set_ref_frames_for_skip_mode(cm, ref_frame);
       return;
     }
 #endif  // CONFIG_EXT_SKIP
@@ -1793,21 +1719,6 @@
   }
 }
 
-#if CONFIG_EXT_SKIP
-static void update_block_intra_inter(AV1_COMMON *const cm,
-                                     MACROBLOCKD *const xd, int segment_id,
-                                     const int is_inter,
-                                     uint8_t allow_update_cdf) {
-  if (!segfeature_active(&cm->seg, segment_id, SEG_LVL_REF_FRAME)) {
-    const int ctx = av1_get_intra_inter_context(xd);
-    FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
-    if (allow_update_cdf) update_cdf(ec_ctx->intra_inter_cdf[ctx], is_inter, 2);
-    FRAME_COUNTS *counts = xd->counts;
-    if (counts) ++counts->intra_inter[ctx][is_inter];
-  }
-}
-#endif  // CONFIG_EXT_SKIP
-
 static void fpm_sync(void *const data, int mi_row) {
   AV1Decoder *const pbi = (AV1Decoder *)data;
   av1_frameworker_wait(pbi->frame_worker_owner, pbi->common.prev_frame,
@@ -1837,19 +1748,34 @@
     }
   }
 
-#define FRAME_TO_CHECK 1
+#define FRAME_TO_CHECK 11
+#if CONFIG_EXT_SKIP
   if (cm->current_video_frame == FRAME_TO_CHECK && cm->show_frame == 1) {
     printf(
         "=== DECODER ===: "
         "Frame=%d, (mi_row,mi_col)=(%d,%d), skip_mode=%d, mode=%d, bsize=%d, "
         "show_frame=%d, mv[0]=(%d,%d), mv[1]=(%d,%d), ref[0]=%d, "
         "ref[1]=%d, motion_mode=%d, mode_ctx=%d, "
-        "newmv_ctx=%d, zeromv_ctx=%d, refmv_ctx=%d\n",
+        "newmv_ctx=%d, zeromv_ctx=%d, refmv_ctx=%d, tx_size=%d\n",
         cm->current_video_frame, mi_row, mi_col, mbmi->skip_mode, mbmi->mode,
         mbmi->sb_type, cm->show_frame, mv[0].as_mv.row, mv[0].as_mv.col,
         mv[1].as_mv.row, mv[1].as_mv.col, mbmi->ref_frame[0],
         mbmi->ref_frame[1], mbmi->motion_mode, mode_ctx, newmv_ctx, zeromv_ctx,
-        refmv_ctx);
+        refmv_ctx, mbmi->tx_size);
+#else
+  if (cm->current_video_frame == FRAME_TO_CHECK && cm->show_frame == 1) {
+    printf(
+        "=== DECODER ===: "
+        "Frame=%d, (mi_row,mi_col)=(%d,%d), mode=%d, bsize=%d, "
+        "show_frame=%d, mv[0]=(%d,%d), mv[1]=(%d,%d), ref[0]=%d, "
+        "ref[1]=%d, motion_mode=%d, mode_ctx=%d, "
+        "newmv_ctx=%d, zeromv_ctx=%d, refmv_ctx=%d, tx_size=%d\n",
+        cm->current_video_frame, mi_row, mi_col, mbmi->mode, mbmi->sb_type,
+        cm->show_frame, mv[0].as_mv.row, mv[0].as_mv.col, mv[1].as_mv.row,
+        mv[1].as_mv.col, mbmi->ref_frame[0], mbmi->ref_frame[1],
+        mbmi->motion_mode, mode_ctx, newmv_ctx, zeromv_ctx, refmv_ctx,
+        mbmi->tx_size);
+#endif  // CONFIG_EXT_SKIP
   }
 }
 #endif  // DEC_MISMATCH_DEBUG
@@ -1885,6 +1811,10 @@
   read_ref_frames(cm, xd, r, mbmi->segment_id, mbmi->ref_frame);
   is_compound = has_second_ref(mbmi);
 
+#if CONFIG_EXT_SKIP
+// TODO(zoeliu): To work with JNT_COMP
+#endif  // CONFIG_EXT_SKIP
+
 #if CONFIG_JNT_COMP
   if (is_compound) {
     const int comp_index_ctx = get_comp_index_context(cm, xd);
@@ -1969,6 +1899,11 @@
 #endif
   {
     mbmi->mode = GLOBALMV;
+#if CONFIG_EXT_SKIP
+  } else if (mbmi->skip_mode) {
+    assert(is_compound);
+    mbmi->mode = NEAREST_NEARESTMV;
+#endif  // CONFIG_EXT_SKIP
   } else {
     if (is_compound)
       mbmi->mode = read_inter_compound_mode(cm, xd, r, mode_ctx);
@@ -2098,13 +2033,36 @@
     }
   }
 
-  int mv_corrupted_flag =
-      !assign_mv(cm, xd, mbmi->mode, mbmi->ref_frame, 0, mbmi->mv, ref_mv,
-                 nearestmv, nearmv, mi_row, mi_col, is_compound, allow_hp, r);
-  aom_merge_corrupted_flag(&xd->corrupted, mv_corrupted_flag);
+#if CONFIG_EXT_SKIP
+  if (mbmi->skip_mode) {
+#define USE_MV_SELECTION 0
+#if USE_MV_SELECTION
+    // NOTE: For skip mode, above reference selection has been set as compound,
+    // in order to obtain the two nearest mvs, but after the following mv setup,
+    // skip mode may choose either single reference or compound reference mode.
+    av1_setup_skip_mode_mvs(cm, xd, mbmi, mi_row, mi_col, nearestmv, NULL,
+                            NULL);
+#else   // !USE_MV_SELECTION
+    assert(mbmi->mode == NEAREST_NEARESTMV);
+    mbmi->mv[0].as_int = nearestmv[0].as_int;
+    mbmi->mv[1].as_int = nearestmv[1].as_int;
+#endif  // USE_MV_SELECTION
+#undef USE_MV_SELECTION
+  } else {
+#endif  // CONFIG_EXT_SKIP
+    int mv_corrupted_flag =
+        !assign_mv(cm, xd, mbmi->mode, mbmi->ref_frame, 0, mbmi->mv, ref_mv,
+                   nearestmv, nearmv, mi_row, mi_col, is_compound, allow_hp, r);
+    aom_merge_corrupted_flag(&xd->corrupted, mv_corrupted_flag);
+#if CONFIG_EXT_SKIP
+  }
+#endif  // CONFIG_EXT_SKIP
 
   mbmi->use_wedge_interintra = 0;
   if (cm->reference_mode != COMPOUND_REFERENCE &&
+#if CONFIG_EXT_SKIP
+      !mbmi->skip_mode &&
+#endif  // CONFIG_EXT_SKIP
       cm->allow_interintra_compound && is_interintra_allowed(mbmi)) {
     const int bsize_group = size_group_lookup[bsize];
     const int interintra =
@@ -2146,7 +2104,11 @@
   }
 
   mbmi->motion_mode = SIMPLE_TRANSLATION;
-  if (mbmi->sb_type >= BLOCK_8X8 && !has_second_ref(mbmi))
+  if (mbmi->sb_type >= BLOCK_8X8 &&
+#if CONFIG_EXT_SKIP
+      !mbmi->skip_mode &&
+#endif  // CONFIG_EXT_SKIP
+      !has_second_ref(mbmi))
 #if CONFIG_EXT_WARPED_MOTION
     mbmi->num_proj_ref[0] =
         findSamples(cm, xd, mi_row, mi_col, pts, pts_inref, pts_mv, pts_wm);
@@ -2267,85 +2229,62 @@
            mbmi->skip_mode);
 #endif  // 0
 
-  if (mbmi->skip_mode) {
+  if (mbmi->skip_mode)
     mbmi->skip = 1;
-#if CONFIG_Q_SEGMENTATION
-    mbmi->q_segment_id = read_q_segment_id(cm, xd, mi_row, mi_col, r);
-#endif
-
-    if (cm->delta_q_present_flag) {
-      xd->current_qindex = xd->prev_qindex;
-#if CONFIG_EXT_DELTA_Q
-      if (cm->delta_lf_present_flag) {
-#if CONFIG_LOOPFILTER_LEVEL
-        if (cm->delta_lf_multi)
-          for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id)
-            mbmi->curr_delta_lf[lf_id] = xd->curr_delta_lf[lf_id] =
-                xd->prev_delta_lf[lf_id];
-        else
-#endif  // CONFIG_LOOPFILTER_LEVEL
-          mbmi->current_delta_lf_from_base = xd->current_delta_lf_from_base =
-              xd->prev_delta_lf_from_base;
-      }
-#endif  // CONFIG_EXT_DELTA_Q
-    }
-
-    update_block_intra_inter(cm, xd, mbmi->segment_id, inter_block,
-                             r->allow_update_cdf);
-  } else {
+  else
 #endif  // CONFIG_EXT_SKIP
     mbmi->skip = read_skip(cm, xd, mbmi->segment_id, r);
-#if CONFIG_Q_SEGMENTATION
-    mbmi->q_segment_id = read_q_segment_id(cm, xd, mi_row, mi_col, r);
-#endif
 
-    if (cm->delta_q_present_flag) {
-      xd->current_qindex =
-          xd->prev_qindex +
-          read_delta_qindex(cm, xd, r, mbmi, mi_col, mi_row) * cm->delta_q_res;
-      /* Normative: Clamp to [1,MAXQ] to not interfere with lossless mode */
-      xd->current_qindex = clamp(xd->current_qindex, 1, MAXQ);
-      xd->prev_qindex = xd->current_qindex;
+#if CONFIG_Q_SEGMENTATION
+  mbmi->q_segment_id = read_q_segment_id(cm, xd, mi_row, mi_col, r);
+#endif  // CONFIG_Q_SEGMENTATION
+
+  if (cm->delta_q_present_flag) {
+    xd->current_qindex =
+        xd->prev_qindex +
+        read_delta_qindex(cm, xd, r, mbmi, mi_col, mi_row) * cm->delta_q_res;
+    /* Normative: Clamp to [1,MAXQ] to not interfere with lossless mode */
+    xd->current_qindex = clamp(xd->current_qindex, 1, MAXQ);
+    xd->prev_qindex = xd->current_qindex;
 #if CONFIG_EXT_DELTA_Q
-      if (cm->delta_lf_present_flag) {
+    if (cm->delta_lf_present_flag) {
 #if CONFIG_LOOPFILTER_LEVEL
-        if (cm->delta_lf_multi) {
-          for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
-            const int tmp_lvl =
-                xd->prev_delta_lf[lf_id] +
-                read_delta_lflevel(cm, xd, r, lf_id, mbmi, mi_col, mi_row) *
-                    cm->delta_lf_res;
-            mbmi->curr_delta_lf[lf_id] = xd->curr_delta_lf[lf_id] =
-                clamp(tmp_lvl, -MAX_LOOP_FILTER, MAX_LOOP_FILTER);
-            xd->prev_delta_lf[lf_id] = xd->curr_delta_lf[lf_id];
-          }
-        } else {
+      if (cm->delta_lf_multi) {
+        for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
           const int tmp_lvl =
-              xd->prev_delta_lf_from_base +
-              read_delta_lflevel(cm, xd, r, -1, mbmi, mi_col, mi_row) *
+              xd->prev_delta_lf[lf_id] +
+              read_delta_lflevel(cm, xd, r, lf_id, mbmi, mi_col, mi_row) *
                   cm->delta_lf_res;
-          mbmi->current_delta_lf_from_base = xd->current_delta_lf_from_base =
+          mbmi->curr_delta_lf[lf_id] = xd->curr_delta_lf[lf_id] =
               clamp(tmp_lvl, -MAX_LOOP_FILTER, MAX_LOOP_FILTER);
-          xd->prev_delta_lf_from_base = xd->current_delta_lf_from_base;
+          xd->prev_delta_lf[lf_id] = xd->curr_delta_lf[lf_id];
         }
-#else
-        const int current_delta_lf_from_base =
+      } else {
+        const int tmp_lvl =
             xd->prev_delta_lf_from_base +
-            read_delta_lflevel(cm, xd, r, mbmi, mi_col, mi_row) *
+            read_delta_lflevel(cm, xd, r, -1, mbmi, mi_col, mi_row) *
                 cm->delta_lf_res;
         mbmi->current_delta_lf_from_base = xd->current_delta_lf_from_base =
-            clamp(current_delta_lf_from_base, -MAX_LOOP_FILTER,
-                  MAX_LOOP_FILTER);
+            clamp(tmp_lvl, -MAX_LOOP_FILTER, MAX_LOOP_FILTER);
         xd->prev_delta_lf_from_base = xd->current_delta_lf_from_base;
-#endif  // CONFIG_LOOPFILTER_LEVEL
       }
-#endif  // CONFIG_EXT_DELTA_Q
+#else
+      const int current_delta_lf_from_base =
+          xd->prev_delta_lf_from_base +
+          read_delta_lflevel(cm, xd, r, mbmi, mi_col, mi_row) *
+              cm->delta_lf_res;
+      mbmi->current_delta_lf_from_base = xd->current_delta_lf_from_base =
+          clamp(current_delta_lf_from_base, -MAX_LOOP_FILTER, MAX_LOOP_FILTER);
+      xd->prev_delta_lf_from_base = xd->current_delta_lf_from_base;
+#endif  // CONFIG_LOOPFILTER_LEVEL
     }
-
-    inter_block = read_is_inter_block(cm, xd, mbmi->segment_id, r);
-#if CONFIG_EXT_SKIP
+#endif  // CONFIG_EXT_DELTA_Q
   }
+
+#if CONFIG_EXT_SKIP
+  if (!mbmi->skip_mode)
 #endif  // CONFIG_EXT_SKIP
+    inter_block = read_is_inter_block(cm, xd, mbmi->segment_id, r);
 
   mbmi->current_q_index = xd->current_qindex;
 
@@ -2371,22 +2310,16 @@
   } else {
     mbmi->tx_size = read_tx_size(cm, xd, inter_block, !mbmi->skip, r);
 
-#if CONFIG_EXT_SKIP
-    if (!mbmi->skip_mode) {
-#endif  // CONFIG_EXT_SKIP
-      if (inter_block) {
-        const int width = block_size_wide[bsize] >> tx_size_wide_log2[0];
-        const int height = block_size_high[bsize] >> tx_size_high_log2[0];
-        int idx, idy;
-        for (idy = 0; idy < height; ++idy)
-          for (idx = 0; idx < width; ++idx)
-            mbmi->inter_tx_size[idy >> 1][idx >> 1] = mbmi->tx_size;
-      }
-      mbmi->min_tx_size = get_min_tx_size(mbmi->tx_size);
-      set_txfm_ctxs(mbmi->tx_size, xd->n8_w, xd->n8_h, mbmi->skip, xd);
-#if CONFIG_EXT_SKIP
+    if (inter_block) {
+      const int width = block_size_wide[bsize] >> tx_size_wide_log2[0];
+      const int height = block_size_high[bsize] >> tx_size_high_log2[0];
+      int idx, idy;
+      for (idy = 0; idy < height; ++idy)
+        for (idx = 0; idx < width; ++idx)
+          mbmi->inter_tx_size[idy >> 1][idx >> 1] = mbmi->tx_size;
     }
-#endif  // CONFIG_EXT_SKIP
+    mbmi->min_tx_size = get_min_tx_size(mbmi->tx_size);
+    set_txfm_ctxs(mbmi->tx_size, xd->n8_w, xd->n8_h, mbmi->skip, xd);
   }
 
   if (inter_block)
@@ -2395,7 +2328,10 @@
     read_intra_block_mode_info(cm, mi_row, mi_col, xd, mi, r);
 
 #if !CONFIG_TXK_SEL
-  av1_read_tx_type(cm, xd, r);
+#if CONFIG_EXT_SKIP
+  if (!mbmi->skip_mode)
+#endif  // CONFIG_EXT_SKIP
+    av1_read_tx_type(cm, xd, r);
 #endif  // !CONFIG_TXK_SEL
 }
 
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index d8965c3..de693dc 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -282,6 +282,24 @@
   }
 }
 
+#if CONFIG_EXT_SKIP
+static int write_skip_mode(const AV1_COMMON *cm, const MACROBLOCKD *xd,
+                           int segment_id, const MODE_INFO *mi, aom_writer *w) {
+  if (!cm->skip_mode_flag) return 0;
+  if (segfeature_active(&cm->seg, segment_id, SEG_LVL_SKIP)) {
+    return 0;
+  }
+  const int skip_mode = mi->mbmi.skip_mode;
+  if (!is_comp_ref_allowed(mi->mbmi.sb_type)) {
+    assert(!skip_mode);
+    return 0;
+  }
+  const int ctx = av1_get_skip_mode_context(xd);
+  aom_write_symbol(w, skip_mode, xd->tile_ctx->skip_mode_cdfs[ctx], 2);
+  return skip_mode;
+}
+#endif  // CONFIG_EXT_SKIP
+
 static void write_is_inter(const AV1_COMMON *cm, const MACROBLOCKD *xd,
                            int segment_id, aom_writer *w, const int is_inter) {
   if (!segfeature_active(&cm->seg, segment_id, SEG_LVL_REF_FRAME)) {
@@ -1207,10 +1225,23 @@
     }
   }
 
-  skip = write_skip(cm, xd, segment_id, mi, w);
+#if CONFIG_EXT_SKIP
+  write_skip_mode(cm, xd, segment_id, mi, w);
+
+  if (mbmi->skip_mode) {
+    skip = mbmi->skip;
+    assert(skip);
+  } else {
+#endif  // CONFIG_EXT_SKIP
+    skip = write_skip(cm, xd, segment_id, mi, w);
+#if CONFIG_EXT_SKIP
+  }
+#endif  // CONFIG_EXT_SKIP
+
 #if CONFIG_Q_SEGMENTATION
   write_q_segment_id(cm, skip, mbmi, w, seg, segp, bsize, mi_row, mi_col);
-#endif
+#endif  // CONFIG_Q_SEGMENTATION
+
   if (cm->delta_q_present_flag) {
     int super_block_upper_left = ((mi_row & (cm->mib_size - 1)) == 0) &&
                                  ((mi_col & (cm->mib_size - 1)) == 0);
@@ -1252,7 +1283,10 @@
     }
   }
 
-  write_is_inter(cm, xd, mbmi->segment_id, w, is_inter);
+#if CONFIG_EXT_SKIP
+  if (!mbmi->skip_mode)
+#endif  // CONFIG_EXT_SKIP
+    write_is_inter(cm, xd, mbmi->segment_id, w, is_inter);
 
   if (cm->tx_mode == TX_MODE_SELECT && block_signals_txsize(bsize) &&
       !(is_inter && skip) && !xd->lossless[segment_id]) {
@@ -1274,6 +1308,10 @@
     set_txfm_ctxs(mbmi->tx_size, xd->n8_w, xd->n8_h, skip, xd);
   }
 
+#if CONFIG_EXT_SKIP
+  if (mbmi->skip_mode) return;
+#endif  // CONFIG_EXT_SKIP
+
   if (!is_inter) {
     write_intra_mode(ec_ctx, bsize, mode, w);
     if (is_chroma_reference(mi_row, mi_col, bsize, xd->plane[1].subsampling_x,
@@ -1310,7 +1348,6 @@
     if (is_compound)
       mode_ctx = mbmi_ext->compound_mode_context[mbmi->ref_frame[0]];
     else
-
       mode_ctx = av1_mode_context_analyzer(mbmi_ext->mode_context,
                                            mbmi->ref_frame, bsize, -1);
 
@@ -1607,7 +1644,7 @@
   xd->mi = cm->mi_grid_visible + (mi_row * cm->mi_stride + mi_col);
   m = xd->mi[0];
   if (is_inter_block(&m->mbmi)) {
-#define FRAME_TO_CHECK 1
+#define FRAME_TO_CHECK 11
     if (cm->current_video_frame == FRAME_TO_CHECK && cm->show_frame == 1) {
       const MB_MODE_INFO *const mbmi = &m->mbmi;
       const BLOCK_SIZE bsize = mbmi->sb_type;
@@ -1625,11 +1662,15 @@
 
       MACROBLOCK *const x = &cpi->td.mb;
       const MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
-      const int16_t mode_ctx = av1_mode_context_analyzer(
-          mbmi_ext->mode_context, mbmi->ref_frame, bsize, -1);
+      const int16_t mode_ctx =
+          is_comp_ref ? mbmi_ext->compound_mode_context[mbmi->ref_frame[0]]
+                      : av1_mode_context_analyzer(mbmi_ext->mode_context,
+                                                  mbmi->ref_frame, bsize, -1);
+
       const int16_t newmv_ctx = mode_ctx & NEWMV_CTX_MASK;
       int16_t zeromv_ctx = -1;
       int16_t refmv_ctx = -1;
+
       if (mbmi->mode != NEWMV) {
         zeromv_ctx = (mode_ctx >> GLOBALMV_OFFSET) & GLOBALMV_CTX_MASK;
         if (mode_ctx & (1 << ALL_ZERO_FLAG_OFFSET)) {
@@ -1643,18 +1684,31 @@
         }
       }
 
-      int8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
+#if CONFIG_EXT_SKIP
+      printf(
+          "=== ENCODER ===: "
+          "Frame=%d, (mi_row,mi_col)=(%d,%d), skip_mode=%d, mode=%d, bsize=%d, "
+          "show_frame=%d, mv[0]=(%d,%d), mv[1]=(%d,%d), ref[0]=%d, "
+          "ref[1]=%d, motion_mode=%d, mode_ctx=%d, "
+          "newmv_ctx=%d, zeromv_ctx=%d, refmv_ctx=%d, tx_size=%d\n",
+          cm->current_video_frame, mi_row, mi_col, mbmi->skip_mode, mbmi->mode,
+          bsize, cm->show_frame, mv[0].as_mv.row, mv[0].as_mv.col,
+          mv[1].as_mv.row, mv[1].as_mv.col, mbmi->ref_frame[0],
+          mbmi->ref_frame[1], mbmi->motion_mode, mode_ctx, newmv_ctx,
+          zeromv_ctx, refmv_ctx, mbmi->tx_size);
+#else
       printf(
           "=== ENCODER ===: "
           "Frame=%d, (mi_row,mi_col)=(%d,%d), mode=%d, bsize=%d, "
           "show_frame=%d, mv[0]=(%d,%d), mv[1]=(%d,%d), ref[0]=%d, "
-          "ref[1]=%d, motion_mode=%d, inter_mode_ctx=%d, mode_ctx=%d, "
-          "newmv_ctx=%d, zeromv_ctx=%d, refmv_ctx=%d\n",
+          "ref[1]=%d, motion_mode=%d, mode_ctx=%d, "
+          "newmv_ctx=%d, zeromv_ctx=%d, refmv_ctx=%d, tx_size=%d\n",
           cm->current_video_frame, mi_row, mi_col, mbmi->mode, bsize,
           cm->show_frame, mv[0].as_mv.row, mv[0].as_mv.col, mv[1].as_mv.row,
           mv[1].as_mv.col, mbmi->ref_frame[0], mbmi->ref_frame[1],
-          mbmi->motion_mode, mbmi_ext->mode_context[ref_frame_type], mode_ctx,
-          newmv_ctx, zeromv_ctx, refmv_ctx);
+          mbmi->motion_mode, mode_ctx, newmv_ctx, zeromv_ctx, refmv_ctx,
+          mbmi->tx_size);
+#endif  // CONFIG_EXT_SKIP
     }
   }
 }
@@ -1750,6 +1804,9 @@
   for (plane = 0; plane < AOMMIN(2, num_planes); ++plane) {
     const uint8_t palette_size_plane =
         mbmi->palette_mode_info.palette_size[plane];
+#if CONFIG_EXT_SKIP
+    assert(!mbmi->skip_mode || !palette_size_plane);
+#endif  // CONFIG_EXT_SKIP
     if (palette_size_plane > 0) {
 #if CONFIG_INTRABC
       assert(mbmi->use_intrabc == 0);
@@ -3669,8 +3726,6 @@
       aom_wb_write_literal(wb, cpi->common.ans_window_size_log2 - 8, 4);
 #endif  // CONFIG_ANS && ANS_MAX_SYMBOLS
     } else {
-      MV_REFERENCE_FRAME ref_frame;
-
       aom_wb_write_literal(wb, cpi->refresh_frame_mask, REF_FRAMES);
 
       if (!cpi->refresh_frame_mask) {
@@ -3679,7 +3734,8 @@
         cm->is_reference_frame = 0;
       }
 
-      for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
+      for (MV_REFERENCE_FRAME ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME;
+           ++ref_frame) {
         assert(get_ref_frame_map_idx(cpi, ref_frame) != INVALID_IDX);
         aom_wb_write_literal(wb, get_ref_frame_map_idx(cpi, ref_frame),
                              REF_FRAMES_LOG2);
@@ -3750,7 +3806,11 @@
     arf_offset = AOMMIN((MAX_GF_INTERVAL - 1), arf_offset + brf_offset);
     aom_wb_write_literal(wb, arf_offset, 4);
   }
-#endif
+
+#if CONFIG_EXT_SKIP
+  if (cm->is_skip_mode_allowed) aom_wb_write_bit(wb, cm->skip_mode_flag);
+#endif  // CONFIG_EXT_SKIP
+#endif  // CONFIG_FRAME_MARKER
 
 #if CONFIG_REFERENCE_BUFFER
   if (cm->seq_params.frame_id_numbers_present_flag) {
diff --git a/av1/encoder/block.h b/av1/encoder/block.h
index 8c50017..b9fd22c 100644
--- a/av1/encoder/block.h
+++ b/av1/encoder/block.h
@@ -207,6 +207,20 @@
   int skip_chroma_rd;
   int skip_cost[SKIP_CONTEXTS][2];
 
+#if CONFIG_EXT_SKIP
+  int skip_mode;  // 0: off; 1: on
+  int skip_mode_cost[SKIP_CONTEXTS][2];
+
+  int64_t skip_mode_rdcost;  // -1: Not set
+  int skip_mode_rate;
+  int64_t skip_mode_sse;
+  int64_t skip_mode_dist;
+  MV_REFERENCE_FRAME skip_mode_ref_frame[2];
+  int_mv skip_mode_mv[2];
+  int skip_mode_index_candidate;
+  int skip_mode_index;
+#endif  // CONFIG_EXT_SKIP
+
 #if CONFIG_LV_MAP
   LV_MAP_COEFF_COST coeff_costs[TX_SIZES][PLANE_TYPES];
   uint16_t cb_offset;
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index a5c59c8..a380330 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -1020,12 +1020,25 @@
   const int seg_ref_active =
       segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_REF_FRAME);
 
-  if (!seg_ref_active) {
-    const int skip_ctx = av1_get_skip_context(xd);
-    td->counts->skip[skip_ctx][mbmi->skip]++;
-    if (allow_update_cdf) update_cdf(fc->skip_cdfs[skip_ctx], mbmi->skip, 2);
+#if CONFIG_EXT_SKIP
+  if (cm->skip_mode_flag && !seg_ref_active && is_comp_ref_allowed(bsize)) {
+    const int skip_mode_ctx = av1_get_skip_mode_context(xd);
+    td->counts->skip_mode[skip_mode_ctx][mbmi->skip_mode]++;
+    if (allow_update_cdf)
+      update_cdf(fc->skip_mode_cdfs[skip_mode_ctx], mbmi->skip_mode, 2);
   }
 
+  if (!mbmi->skip_mode) {
+#endif  // CONFIG_EXT_SKIP
+    if (!seg_ref_active) {
+      const int skip_ctx = av1_get_skip_context(xd);
+      td->counts->skip[skip_ctx][mbmi->skip]++;
+      if (allow_update_cdf) update_cdf(fc->skip_cdfs[skip_ctx], mbmi->skip, 2);
+    }
+#if CONFIG_EXT_SKIP
+  }
+#endif  // CONFIG_EXT_SKIP
+
   if (cm->delta_q_present_flag && (bsize != cm->sb_size || !mbmi->skip) &&
       super_block_upper_left) {
     const int dq = (mbmi->current_q_index - xd->prev_qindex) / cm->delta_q_res;
@@ -1080,10 +1093,24 @@
 #endif  // CONFIG_LOOPFILTER_LEVEL
 #endif
   }
+
   if (!frame_is_intra_only(cm)) {
-    FRAME_COUNTS *const counts = td->counts;
     RD_COUNTS *rdc = &td->rd_counts;
+
+#if CONFIG_EXT_SKIP
+    if (mbmi->skip_mode) {
+      if (cm->reference_mode == REFERENCE_MODE_SELECT) {
+        assert(has_second_ref(mbmi));
+        rdc->compound_ref_used_flag = 1;
+      }
+      set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
+      return;
+    }
+#endif  // CONFIG_EXT_SKIP
+
+    FRAME_COUNTS *const counts = td->counts;
     const int inter_block = is_inter_block(mbmi);
+
     if (!seg_ref_active) {
       counts->intra_inter[av1_get_intra_inter_context(xd)][inter_block]++;
       if (allow_update_cdf)
@@ -4194,6 +4221,41 @@
   av1_setup_motion_field(cm);
 #endif  // CONFIG_MFMV
 
+#if CONFIG_EXT_SKIP
+  av1_setup_skip_mode_allowed(cm);
+  cm->skip_mode_flag = cm->is_skip_mode_allowed;
+  if (cm->skip_mode_flag) {
+    if (cm->reference_mode == SINGLE_REFERENCE) {
+      cm->skip_mode_flag = 0;
+    } else {
+      static const int flag_list[TOTAL_REFS_PER_FRAME] = { 0,
+                                                           AOM_LAST_FLAG,
+                                                           AOM_LAST2_FLAG,
+                                                           AOM_LAST3_FLAG,
+                                                           AOM_GOLD_FLAG,
+                                                           AOM_BWD_FLAG,
+                                                           AOM_ALT2_FLAG,
+                                                           AOM_ALT_FLAG };
+      const int ref_frame[2] = { cm->ref_frame_idx_0 + LAST_FRAME,
+                                 cm->ref_frame_idx_1 + LAST_FRAME };
+      if (!(cpi->ref_frame_flags & flag_list[ref_frame[0]]) ||
+          !(cpi->ref_frame_flags & flag_list[ref_frame[1]]))
+        cm->skip_mode_flag = 0;
+    }
+  }
+#if 0
+  printf(
+      "\nENCODER: Frame=%d, frame_offset=%d, show_frame=%d, "
+      "show_existing_frame=%d, is_skip_mode_allowed=%d, "
+      "ref_frame_idx=(%d,%d), frame_reference_mode=%d, "
+      "tpl_frame_ref0_idx=%d, skip_mode_flag=%d\n",
+      cm->current_video_frame, cm->frame_offset, cm->show_frame,
+      cm->show_existing_frame, cm->is_skip_mode_allowed, cm->ref_frame_idx_0,
+      cm->ref_frame_idx_1, cm->reference_mode, cm->tpl_frame_ref0_idx,
+      cm->skip_mode_flag);
+#endif  // 0
+#endif  // CONFIG_EXT_SKIP
+
 #if CONFIG_FRAME_MARKER
   cpi->all_one_sided_refs = refs_are_one_sided(cm);
 #endif  // CONFIG_FRAME_MARKER
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 44c48d2..33605d6 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -5273,16 +5273,31 @@
       return;
     }
   }
+#if CONFIG_FRAME_MARKER
   printf(
-      "\nFrame=%5d, encode_update_type[%5d]=%1d, show_existing_frame=%d, "
-      "source_alt_ref_active=%d, refresh_alt_ref_frame=%d, rf_level=%d, "
-      "y_stride=%4d, uv_stride=%4d, cm->width=%4d, cm->height=%4d\n",
+      "\nFrame=%5d, encode_update_type[%5d]=%1d, frame_offset=%d, "
+      "show_frame=%d, show_existing_frame=%d, source_alt_ref_active=%d, "
+      "refresh_alt_ref_frame=%d, rf_level=%d, "
+      "y_stride=%4d, uv_stride=%4d, cm->width=%4d, cm->height=%4d\n\n",
       cm->current_video_frame, cpi->twopass.gf_group.index,
       cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index],
-      cm->show_existing_frame, cpi->rc.source_alt_ref_active,
+      cm->frame_offset, cm->show_frame, cm->show_existing_frame,
+      cpi->rc.source_alt_ref_active, cpi->refresh_alt_ref_frame,
+      cpi->twopass.gf_group.rf_level[cpi->twopass.gf_group.index],
+      recon_buf->y_stride, recon_buf->uv_stride, cm->width, cm->height);
+#else
+  printf(
+      "\nFrame=%5d, encode_update_type[%5d]=%1d, "
+      "show_frame=%d, show_existing_frame=%d, source_alt_ref_active=%d, "
+      "refresh_alt_ref_frame=%d, rf_level=%d, "
+      "y_stride=%4d, uv_stride=%4d, cm->width=%4d, cm->height=%4d\n\n",
+      cm->current_video_frame, cpi->twopass.gf_group.index,
+      cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index],
+      cm->show_frame, cm->show_existing_frame, cpi->rc.source_alt_ref_active,
       cpi->refresh_alt_ref_frame,
       cpi->twopass.gf_group.rf_level[cpi->twopass.gf_group.index],
       recon_buf->y_stride, recon_buf->uv_stride, cm->width, cm->height);
+#endif  // CONFIG_FRAME_MARKER
 #if 0
   int ref_frame;
   printf("get_ref_frame_map_idx: [");
diff --git a/av1/encoder/rd.c b/av1/encoder/rd.c
index d511812..800d7fb 100644
--- a/av1/encoder/rd.c
+++ b/av1/encoder/rd.c
@@ -93,6 +93,15 @@
                                NULL);
   }
 
+#if CONFIG_EXT_SKIP
+  if (cm->skip_mode_flag) {
+    for (i = 0; i < SKIP_CONTEXTS; ++i) {
+      av1_cost_tokens_from_cdf(x->skip_mode_cost[i], fc->skip_mode_cdfs[i],
+                               NULL);
+    }
+  }
+#endif  // CONFIG_EXT_SKIP
+
   for (i = 0; i < SKIP_CONTEXTS; ++i) {
     av1_cost_tokens_from_cdf(x->skip_cost[i], fc->skip_cdfs[i], NULL);
   }
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index db7fa25..2f3ee0d 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -7685,6 +7685,51 @@
   return 0;
 }
 
+#if CONFIG_EXT_SKIP
+static int64_t skip_mode_rd(const AV1_COMP *const cpi, MACROBLOCK *const x,
+                            BLOCK_SIZE bsize, int mi_row, int mi_col,
+                            BUFFER_SET *const orig_dst) {
+  const AV1_COMMON *cm = &cpi->common;
+  MACROBLOCKD *const xd = &x->e_mbd;
+  MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
+
+  InterpFilter assign_filter =
+      (cm->interp_filter == SWITCHABLE) ? EIGHTTAP_REGULAR : cm->interp_filter;
+  set_default_interp_filters(mbmi, assign_filter);
+  av1_build_inter_predictors_sb(cm, xd, mi_row, mi_col, orig_dst, bsize);
+
+  int64_t total_sse = 0;
+
+  for (int plane = 0; plane < MAX_MB_PLANE; ++plane) {
+    const struct macroblock_plane *const p = &x->plane[plane];
+    const struct macroblockd_plane *const pd = &xd->plane[plane];
+    const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, pd);
+    const int bw = block_size_wide[plane_bsize];
+    const int bh = block_size_high[plane_bsize];
+
+    av1_subtract_plane(x, bsize, plane);
+    int64_t sse = aom_sum_squares_2d_i16(p->src_diff, bw, bw, bh);
+    sse = sse << 4;
+    total_sse += sse;
+  }
+  x->skip_mode_dist = x->skip_mode_sse = total_sse;
+  x->skip_mode_rate = 0;
+  x->skip_mode_rdcost = RDCOST(x->rdmult, x->skip_mode_rate, x->skip_mode_dist);
+
+  // Save the ref frames / motion vectors
+  x->skip_mode_ref_frame[0] = mbmi->ref_frame[0];
+  x->skip_mode_ref_frame[1] = mbmi->ref_frame[1];
+  x->skip_mode_mv[0].as_int = mbmi->mv[0].as_int;
+  x->skip_mode_mv[1].as_int = mbmi->mv[1].as_int;
+
+  // Save the mode index
+  x->skip_mode_index = x->skip_mode_index_candidate;
+
+  restore_dst_buf(xd, *orig_dst);
+  return 0;
+}
+#endif  // CONFIG_EXT_SKIP
+
 static int64_t handle_inter_mode(
     const AV1_COMP *const cpi, MACROBLOCK *x, BLOCK_SIZE bsize,
     RD_STATS *rd_stats, RD_STATS *rd_stats_y, RD_STATS *rd_stats_uv,
@@ -8634,6 +8679,127 @@
                                       int above_stride, const uint8_t *left,
                                       int left_stride);
 
+#if CONFIG_EXT_SKIP
+static void estimate_skip_mode_rdcost(
+    const AV1_COMP *const cpi, TileDataEnc *tile_data, MACROBLOCK *const x,
+    BLOCK_SIZE bsize, int mi_row, int mi_col,
+    int_mv frame_mv[MB_MODE_COUNT][TOTAL_REFS_PER_FRAME],
+    struct buf_2d yv12_mb[TOTAL_REFS_PER_FRAME][MAX_MB_PLANE]) {
+  const AV1_COMMON *const cm = &cpi->common;
+  MACROBLOCKD *const xd = &x->e_mbd;
+  MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
+  MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
+
+  int *mode_map = tile_data->mode_map[bsize];
+  static const int flag_list[TOTAL_REFS_PER_FRAME] = { 0,
+                                                       AOM_LAST_FLAG,
+                                                       AOM_LAST2_FLAG,
+                                                       AOM_LAST3_FLAG,
+                                                       AOM_GOLD_FLAG,
+                                                       AOM_BWD_FLAG,
+                                                       AOM_ALT2_FLAG,
+                                                       AOM_ALT_FLAG };
+  int i;
+
+  for (int midx = 0; midx < MAX_MODES; ++midx) {
+    const int mode_index = mode_map[midx];
+    x->skip_mode_index_candidate = mode_index;
+
+    const MV_REFERENCE_FRAME ref_frame =
+        av1_mode_order[mode_index].ref_frame[0];
+    const MV_REFERENCE_FRAME second_ref_frame =
+        av1_mode_order[mode_index].ref_frame[1];
+    const int comp_pred = second_ref_frame > INTRA_FRAME;
+
+    if (!comp_pred) continue;
+
+    const PREDICTION_MODE this_mode = av1_mode_order[mode_index].mode;
+
+    if (!(cpi->ref_frame_flags & flag_list[ref_frame])) continue;
+    if (comp_pred && !(cpi->ref_frame_flags & flag_list[second_ref_frame]))
+      continue;
+    // Check whether current refs/mode align with skip_mode
+    if (!(ref_frame == (LAST_FRAME + cm->ref_frame_idx_0) &&
+          second_ref_frame == (LAST_FRAME + cm->ref_frame_idx_1) &&
+          this_mode == NEAREST_NEARESTMV)) {
+      continue;
+    }
+
+    frame_mv[this_mode][ref_frame].as_int =
+        frame_mv[compound_ref0_mode(this_mode)][ref_frame].as_int;
+    frame_mv[this_mode][second_ref_frame].as_int =
+        frame_mv[compound_ref1_mode(this_mode)][second_ref_frame].as_int;
+
+    if (frame_mv[this_mode][ref_frame].as_int == INVALID_MV ||
+        frame_mv[this_mode][second_ref_frame].as_int == INVALID_MV)
+      break;
+
+    // TODO(zoeliu): To work with JNT_COMP
+
+    mbmi->mode = this_mode;
+    mbmi->uv_mode = UV_DC_PRED;
+    mbmi->ref_frame[0] = ref_frame;
+    mbmi->ref_frame[1] = second_ref_frame;
+
+    // Obtain NEAREST_NEARESTMV.
+    {
+      for (i = 0; i < 2; ++i) {
+        int_mv cur_mv = frame_mv[mbmi->mode][mbmi->ref_frame[i]];
+        clamp_mv2(&cur_mv.as_mv, xd);
+        if (mv_check_bounds(&x->mv_limits, &cur_mv.as_mv)) {
+          x->skip_mode_rdcost = INT64_MAX;
+          break;
+        }
+        mbmi->mv[i].as_int = cur_mv.as_int;
+      }
+      if (x->skip_mode_rdcost == INT64_MAX) break;
+
+      const uint8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
+      if (mbmi_ext->ref_mv_count[ref_frame_type] > 0) {
+        for (i = 0; i < 2; ++i) {
+          int_mv cur_mv =
+              (i == 0) ? mbmi_ext->ref_mv_stack[ref_frame_type][0].this_mv
+                       : mbmi_ext->ref_mv_stack[ref_frame_type][0].comp_mv;
+          clamp_mv2(&cur_mv.as_mv, xd);
+          if (mv_check_bounds(&x->mv_limits, &cur_mv.as_mv)) {
+            x->skip_mode_rdcost = INT64_MAX;
+            break;
+          }
+          mbmi->mv[i].as_int = cur_mv.as_int;
+        }
+        if (x->skip_mode_rdcost == INT64_MAX) break;
+      }
+    }
+
+#if CONFIG_FILTER_INTRA
+    mbmi->filter_intra_mode_info.use_filter_intra_mode[0] = 0;
+    mbmi->filter_intra_mode_info.use_filter_intra_mode[1] = 0;
+#endif  // CONFIG_FILTER_INTRA
+    mbmi->interintra_mode = (INTERINTRA_MODE)(II_DC_PRED - 1);
+    mbmi->interinter_compound_type = COMPOUND_AVERAGE;
+    mbmi->motion_mode = SIMPLE_TRANSLATION;
+    mbmi->ref_mv_idx = 0;
+    mbmi->skip_mode = mbmi->skip = 1;
+
+    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];
+      xd->plane[i].pre[1] = yv12_mb[mbmi->ref_frame[1]][i];
+    }
+
+    BUFFER_SET orig_dst;
+    for (i = 0; i < MAX_MB_PLANE; i++) {
+      orig_dst.plane[i] = xd->plane[i].dst.buf;
+      orig_dst.stride[i] = xd->plane[i].dst.stride;
+    }
+
+    // Obtain the rdcost for skip_mode.
+    skip_mode_rd(cpi, x, bsize, mi_row, mi_col, &orig_dst);
+    break;
+  }
+}
+#endif  // CONFIG_EXT_SKIP
+
 void av1_rd_pick_inter_mode_sb(const AV1_COMP *cpi, TileDataEnc *tile_data,
                                MACROBLOCK *x, int mi_row, int mi_col,
                                RD_STATS *rd_cost, BLOCK_SIZE bsize,
@@ -8972,6 +9138,11 @@
     for (ref_frame = 0; ref_frame < TOTAL_REFS_PER_FRAME; ++ref_frame)
       modelled_rd[i][ref_frame] = INT64_MAX;
 
+#if CONFIG_EXT_SKIP
+  x->skip_mode_rdcost = -1;
+  x->skip_mode_index = -1;
+#endif  // CONFIG_EXT_SKIP
+
   for (midx = 0; midx < MAX_MODES; ++midx) {
     int mode_index;
     int mode_excluded = 0;
@@ -8986,6 +9157,9 @@
     uint8_t ref_frame_type;
 
     mode_index = mode_map[midx];
+#if CONFIG_EXT_SKIP
+    x->skip_mode_index_candidate = mode_index;
+#endif  // CONFIG_EXT_SKIP
     this_mode = av1_mode_order[mode_index].mode;
     ref_frame = av1_mode_order[mode_index].ref_frame[0];
     second_ref_frame = av1_mode_order[mode_index].ref_frame[1];
@@ -9520,7 +9694,6 @@
         this_rd = handle_inter_mode(cpi, x, bsize, &rd_stats, &rd_stats_y,
                                     &rd_stats_uv, &disable_skip, frame_mv,
                                     mi_row, mi_col, &args, best_rd);
-
         rate2 = rd_stats.rate;
         skippable = rd_stats.skip;
         distortion2 = rd_stats.dist;
@@ -10024,6 +10197,102 @@
     }
   }
 PALETTE_EXIT:
+
+#if CONFIG_EXT_SKIP
+  // Obtain the rdcost for skip_mode if it has not been calculated yet
+  if (x->skip_mode_rdcost < 0 && cm->skip_mode_flag &&
+      !segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME) &&
+      is_comp_ref_allowed(bsize)) {
+    x->skip_mode_rdcost = INT64_MAX;
+    estimate_skip_mode_rdcost(cpi, tile_data, x, bsize, mi_row, mi_col,
+                              frame_mv, yv12_mb);
+  }
+
+  // Compare the use of skip_mode with the best intra/inter mode obtained so far
+  best_mbmode.skip_mode = 0;
+  if (x->skip_mode_rdcost >= 0 && x->skip_mode_rdcost < INT64_MAX) {
+    const int skip_mode_ctx = av1_get_skip_mode_context(xd);
+    const int64_t best_intra_inter_mode_cost =
+        RDCOST(x->rdmult, rd_cost->rate + x->skip_mode_cost[skip_mode_ctx][0],
+               rd_cost->dist);
+    const int64_t skip_mode_cost = RDCOST(
+        x->rdmult, x->skip_mode_rate + x->skip_mode_cost[skip_mode_ctx][1],
+        x->skip_mode_dist);
+
+    if (skip_mode_cost <= best_intra_inter_mode_cost) {
+      best_mbmode = *mbmi;
+
+      best_mbmode.skip_mode = best_mbmode.skip = 1;
+      best_mbmode.mode = NEAREST_NEARESTMV;
+      best_mbmode.ref_frame[0] = x->skip_mode_ref_frame[0];
+      best_mbmode.ref_frame[1] = x->skip_mode_ref_frame[1];
+      best_mbmode.mv[0].as_int = x->skip_mode_mv[0].as_int;
+      best_mbmode.mv[1].as_int = x->skip_mode_mv[1].as_int;
+
+      // Set up tx_size related variables for skip-specific loop filtering.
+      best_mbmode.tx_size = block_signals_txsize(bsize)
+                                ? tx_size_from_tx_mode(bsize, cm->tx_mode, 1)
+                                : max_txsize_rect_lookup[bsize];
+      {
+        const int width = block_size_wide[bsize] >> tx_size_wide_log2[0];
+        const int height = block_size_high[bsize] >> tx_size_high_log2[0];
+        for (int idy = 0; idy < height; ++idy)
+          for (int idx = 0; idx < width; ++idx)
+            best_mbmode.inter_tx_size[idy >> 1][idx >> 1] = best_mbmode.tx_size;
+      }
+      best_mbmode.min_tx_size = get_min_tx_size(best_mbmode.tx_size);
+      set_txfm_ctxs(best_mbmode.tx_size, xd->n8_w, xd->n8_h, best_mbmode.skip,
+                    xd);
+
+      // Set up color-related variables for skip mode.
+      best_mbmode.uv_mode = UV_DC_PRED;
+      best_mbmode.palette_mode_info.palette_size[0] = 0;
+      best_mbmode.palette_mode_info.palette_size[1] = 0;
+
+      best_mbmode.interintra_mode = (INTERINTRA_MODE)(II_DC_PRED - 1);
+      best_mbmode.interinter_compound_type = COMPOUND_AVERAGE;
+      best_mbmode.motion_mode = SIMPLE_TRANSLATION;
+      best_mbmode.ref_mv_idx = 0;
+
+#if CONFIG_FILTER_INTRA
+      best_mbmode.filter_intra_mode_info.use_filter_intra_mode[0] = 0;
+      best_mbmode.filter_intra_mode_info.use_filter_intra_mode[1] = 0;
+#endif  // CONFIG_FILTER_INTRA
+
+#if 0
+      set_ref_ptrs(cm, xd, best_mbmode.ref_frame[0], best_mbmode.ref_frame[1]);
+      // Select prediction reference frames.
+      for (i = 0; i < MAX_MB_PLANE; i++) {
+        xd->plane[i].pre[0] = yv12_mb[best_mbmode.ref_frame[0]][i];
+        xd->plane[i].pre[1] = yv12_mb[best_mbmode.ref_frame[1]][i];
+      }
+#endif
+
+      best_mode_index = x->skip_mode_index;
+      best_skip2 = 1;
+      // TODO(zoeliu): To further determine the setup for best_mode_skippable
+      // best_mode_skippable = 1;
+      best_mode_skippable = (x->skip_mode_sse == 0);
+
+      set_default_interp_filters(&best_mbmode, cm->interp_filter);
+
+      // Update rd_cost
+      rd_cost->rate = x->skip_mode_rate + x->skip_mode_cost[skip_mode_ctx][1];
+      rd_cost->dist = rd_cost->sse = x->skip_mode_dist;
+      rd_cost->rdcost = RDCOST(x->rdmult, rd_cost->rate, rd_cost->dist);
+      best_rd = rd_cost->rdcost;
+
+      x->skip = 1;
+#if 0
+      // TODO(zoeliu): To understand what ctx->blk_skip[] for?
+      for (i = 0; i < MAX_MB_PLANE; ++i)
+        memset(ctx->blk_skip[i], 0
+               sizeof(uint8_t) * ctx->num_4x4_blk);
+#endif  // 0
+    }
+  }
+#endif  // CONFIG_EXT_SKIP
+
   // The inter modes' rate costs are not calculated precisely in some cases.
   // Therefore, sometimes, NEWMV is chosen instead of NEARESTMV, NEARMV, and
   // GLOBALMV. Here, checks are added for those cases, and the mode decisions
@@ -10135,6 +10404,9 @@
 #if CONFIG_EXT_WARPED_MOTION
       && best_mbmode.motion_mode != WARPED_CAUSAL
 #endif  // CONFIG_EXT_WARPED_MOTION
+#if CONFIG_EXT_SKIP
+      && !best_mbmode.skip_mode
+#endif  // CONFIG_EXT_SKIP
       ) {
     int8_t ref_frame_type = av1_ref_frame_type(best_mbmode.ref_frame);
     int16_t mode_ctx = mbmi_ext->mode_context[ref_frame_type];