]> granicus.if.org Git - libvpx/commitdiff
Generate compound reference motion vector
authorJingning Han <jingning@google.com>
Tue, 12 Jan 2016 23:06:59 +0000 (15:06 -0800)
committerJingning Han <jingning@google.com>
Tue, 12 Jan 2016 23:28:47 +0000 (15:28 -0800)
This commit allows the codec to add motion vector pairs into
the candidate list. It further improves the compression performance
by 0.1% across derf, hevcmr, stdhd, and hevchr sets without adding
encode/decode time.

Change-Id: I88d36da25a2a89bb506d411844af667081eba98b

vp10/common/blockd.h
vp10/common/mvref_common.c
vp10/common/mvref_common.h
vp10/decoder/decodemv.c
vp10/encoder/block.h
vp10/encoder/encoder.c
vp10/encoder/rdopt.c

index 7b951486bf36a2712c9426277bfa9eb20ac444bb..de54141b1b9abc8902906344142c95511bf0bf13 100644 (file)
@@ -85,6 +85,8 @@ typedef int8_t MV_REFERENCE_FRAME;
 
 #if CONFIG_REF_MV
 #define MODE_CTX_REF_FRAMES (MAX_REF_FRAMES + (ALTREF_FRAME - LAST_FRAME))
+#else
+#define MODE_CTX_REF_FRAMES MAX_REF_FRAMES
 #endif
 
 typedef struct {
@@ -263,8 +265,8 @@ typedef struct macroblockd {
   uint8_t n8_w, n8_h;
 
 #if CONFIG_REF_MV
-  uint8_t ref_mv_count[MAX_REF_FRAMES];
-  CANDIDATE_MV ref_mv_stack[MAX_REF_FRAMES][MAX_REF_MV_STACK_SIZE];
+  uint8_t ref_mv_count[MODE_CTX_REF_FRAMES];
+  CANDIDATE_MV ref_mv_stack[MODE_CTX_REF_FRAMES][MAX_REF_MV_STACK_SIZE];
   uint8_t is_sec_rect;
 #endif
 
index cd1ea38b659272a20e98c3358f59d9df4cbf7036..e6db8187abba6495a6f09d0f02b7b8e3400a1a83 100644 (file)
@@ -313,7 +313,8 @@ static void setup_ref_mv_list(const VP10_COMMON *cm, const MACROBLOCKD *xd,
 
   nearest_refmv_count = *refmv_count;
 
-  if (prev_frame_mvs_base && cm->show_frame && cm->last_show_frame) {
+  if (prev_frame_mvs_base && cm->show_frame && cm->last_show_frame
+      && rf[1] == NONE) {
     int ref;
     int blk_row, blk_col;
 
@@ -460,10 +461,19 @@ static void setup_ref_mv_list(const VP10_COMMON *cm, const MACROBLOCKD *xd,
     }
   }
 
-  for (idx = 0; idx < VPXMIN(MAX_MV_REF_CANDIDATES, *refmv_count); ++idx) {
-    mv_ref_list[idx].as_int = ref_mv_stack[idx].this_mv.as_int;
-    clamp_mv_ref(&mv_ref_list[idx].as_mv,
-                 xd->n8_w << 3, xd->n8_h << 3, xd);
+  if (rf[1] > NONE) {
+    for (idx = 0; idx < *refmv_count; ++idx) {
+      clamp_mv_ref(&ref_mv_stack[idx].this_mv.as_mv,
+                   xd->n8_w << 3 , xd->n8_h << 3, xd);
+      clamp_mv_ref(&ref_mv_stack[idx].comp_mv.as_mv,
+                   xd->n8_w << 3 , xd->n8_h << 3, xd);
+    }
+  } else {
+    for (idx = 0; idx < VPXMIN(MAX_MV_REF_CANDIDATES, *refmv_count); ++idx) {
+      mv_ref_list[idx].as_int = ref_mv_stack[idx].this_mv.as_int;
+      clamp_mv_ref(&mv_ref_list[idx].as_mv,
+                   xd->n8_w << 3, xd->n8_h << 3, xd);
+    }
   }
 }
 #endif
@@ -632,16 +642,6 @@ void vp10_find_mv_refs(const VP10_COMMON *cm, const MACROBLOCKD *xd,
 #endif
 }
 
-static void lower_mv_precision(MV *mv, int allow_hp) {
-  const int use_hp = allow_hp && vp10_use_mv_hp(mv);
-  if (!use_hp) {
-    if (mv->row & 1)
-      mv->row += (mv->row > 0 ? -1 : 1);
-    if (mv->col & 1)
-      mv->col += (mv->col > 0 ? -1 : 1);
-  }
-}
-
 void vp10_find_best_ref_mvs(int allow_hp,
                            int_mv *mvlist, int_mv *nearest_mv,
                            int_mv *near_mv) {
index 1f388c19e4e29529fe6d540b19a02f6682a74694..24bde6cbc64072540fff243d336963086c3060bf 100644 (file)
@@ -195,6 +195,16 @@ static INLINE int is_inside(const TileInfo *const tile,
            mi_col + mi_pos->col >= tile->mi_col_end);
 }
 
+static INLINE void lower_mv_precision(MV *mv, int allow_hp) {
+  const int use_hp = allow_hp && vp10_use_mv_hp(mv);
+  if (!use_hp) {
+    if (mv->row & 1)
+      mv->row += (mv->row > 0 ? -1 : 1);
+    if (mv->col & 1)
+      mv->col += (mv->col > 0 ? -1 : 1);
+  }
+}
+
 #if CONFIG_REF_MV
 static int8_t vp10_ref_frame_type(const MV_REFERENCE_FRAME *const rf) {
   if (rf[1] > INTRA_FRAME)
index f4386e488f5fb8e05eff0a1b0de2758333ed5b03..997c19e676c242e78684126f72c17d2d9d6ff768 100644 (file)
@@ -824,9 +824,9 @@ static void read_inter_block_mode_info(VP10Decoder *const pbi,
   const BLOCK_SIZE bsize = mbmi->sb_type;
   const int allow_hp = cm->allow_high_precision_mv;
   int_mv nearestmv[2], nearmv[2];
-  int_mv ref_mvs[MAX_REF_FRAMES][MAX_MV_REF_CANDIDATES];
+  int_mv ref_mvs[MODE_CTX_REF_FRAMES][MAX_MV_REF_CANDIDATES];
   int ref, is_compound;
-  int16_t inter_mode_ctx[MAX_REF_FRAMES];
+  int16_t inter_mode_ctx[MODE_CTX_REF_FRAMES];
   int16_t mode_ctx = 0;
   MV_REFERENCE_FRAME ref_frame;
 
@@ -845,7 +845,7 @@ static void read_inter_block_mode_info(VP10Decoder *const pbi,
                          &ref_buf->sf);
   }
 
-  for (ref_frame = LAST_FRAME; ref_frame < MAX_REF_FRAMES; ++ref_frame) {
+  for (ref_frame = LAST_FRAME; ref_frame < MODE_CTX_REF_FRAMES; ++ref_frame) {
     vp10_find_mv_refs(cm, xd, mi, ref_frame,
 #if CONFIG_REF_MV
                       &xd->ref_mv_count[ref_frame],
@@ -855,11 +855,11 @@ static void read_inter_block_mode_info(VP10Decoder *const pbi,
                       mi_row, mi_col, fpm_sync, (void *)pbi, inter_mode_ctx);
   }
 
-  mode_ctx = inter_mode_ctx[mbmi->ref_frame[0]];
-
 #if CONFIG_REF_MV
   mode_ctx = vp10_mode_context_analyzer(inter_mode_ctx,
                                         mbmi->ref_frame, bsize, -1);
+#else
+  mode_ctx = inter_mode_ctx[mbmi->ref_frame[0]];
 #endif
 
   if (segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) {
@@ -881,6 +881,26 @@ static void read_inter_block_mode_info(VP10Decoder *const pbi,
     }
   }
 
+#if CONFIG_REF_MV
+  if (is_compound && bsize >= BLOCK_8X8 && mbmi->mode != NEWMV &&
+      mbmi->mode != ZEROMV) {
+    uint8_t ref_frame_type = vp10_ref_frame_type(mbmi->ref_frame);
+
+    if (xd->ref_mv_count[ref_frame_type] > 1) {
+      int i;
+      nearestmv[0] = xd->ref_mv_stack[ref_frame_type][0].this_mv;
+      nearestmv[1] = xd->ref_mv_stack[ref_frame_type][0].comp_mv;
+      nearmv[0] = xd->ref_mv_stack[ref_frame_type][1].this_mv;
+      nearmv[1] = xd->ref_mv_stack[ref_frame_type][1].comp_mv;
+
+      for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) {
+        lower_mv_precision(&nearestmv[i].as_mv, allow_hp);
+        lower_mv_precision(&nearmv[i].as_mv, allow_hp);
+      }
+    }
+  }
+#endif
+
 #if !CONFIG_EXT_INTERP
   mbmi->interp_filter = (cm->interp_filter == SWITCHABLE)
                         ? read_switchable_interp_filter(cm, xd, r)
index 1383c19e2c429c858219a3dd8999fd0727ea477f..597f0d7d68ef98cb06d750d4705d9d1813b5f1ef 100644 (file)
@@ -51,11 +51,11 @@ typedef unsigned int vp10_coeff_cost[PLANE_TYPES][REF_TYPES][COEF_BANDS][2]
                                    [COEFF_CONTEXTS][ENTROPY_TOKENS];
 
 typedef struct {
-  int_mv ref_mvs[MAX_REF_FRAMES][MAX_MV_REF_CANDIDATES];
-  int16_t mode_context[MAX_REF_FRAMES];
+  int_mv ref_mvs[MODE_CTX_REF_FRAMES][MAX_MV_REF_CANDIDATES];
+  int16_t mode_context[MODE_CTX_REF_FRAMES];
 #if CONFIG_REF_MV
-  uint8_t ref_mv_count[MAX_REF_FRAMES];
-  CANDIDATE_MV ref_mv_stack[MAX_REF_FRAMES][MAX_REF_MV_STACK_SIZE];
+  uint8_t ref_mv_count[MODE_CTX_REF_FRAMES];
+  CANDIDATE_MV ref_mv_stack[MODE_CTX_REF_FRAMES][MAX_REF_MV_STACK_SIZE];
 #endif
 } MB_MODE_INFO_EXT;
 
index 6d0fd197f3a53f33cafb3ac8cb44d53a1dc91564..a3982e3cef5281fc8030c2ceaacec70519560eba 100644 (file)
@@ -3340,6 +3340,7 @@ static void encode_with_recode_loop(VP10_COMP *cpi,
     // update_base_skip_probs(cpi);
 
     vpx_clear_system_state();
+
     // Dummy pack of the bitstream using up to date stats to get an
     // accurate estimate of output frame size to determine if we need
     // to recode.
index d457199cca59a551f5618e36f0c6193059dfa834..f98382595a33dc60c9d90eadc6454d02608c73ed 100644 (file)
@@ -4461,6 +4461,40 @@ static int64_t handle_inter_mode(VP10_COMP *cpi, MACROBLOCK *x,
     mbmi->mv[i].as_int = cur_mv[i].as_int;
   }
 
+#if CONFIG_REF_MV
+  if (this_mode == NEARESTMV && is_comp_pred) {
+    uint8_t ref_frame_type = vp10_ref_frame_type(mbmi->ref_frame);
+    if (mbmi_ext->ref_mv_count[ref_frame_type] > 1) {
+      cur_mv[0] = mbmi_ext->ref_mv_stack[ref_frame_type][0].this_mv;
+      cur_mv[1] = mbmi_ext->ref_mv_stack[ref_frame_type][0].comp_mv;
+
+      for (i = 0; i < 2; ++i) {
+        lower_mv_precision(&cur_mv[i].as_mv, cm->allow_high_precision_mv);
+        clamp_mv2(&cur_mv[i].as_mv, xd);
+        if (mv_check_bounds(x, &cur_mv[i].as_mv))
+          return INT64_MAX;
+        mbmi->mv[i].as_int = cur_mv[i].as_int;
+      }
+    }
+  }
+
+  if (this_mode == NEARMV && is_comp_pred) {
+    uint8_t ref_frame_type = vp10_ref_frame_type(mbmi->ref_frame);
+    if (mbmi_ext->ref_mv_count[ref_frame_type] > 1) {
+      cur_mv[0] = mbmi_ext->ref_mv_stack[ref_frame_type][1].this_mv;
+      cur_mv[1] = mbmi_ext->ref_mv_stack[ref_frame_type][1].comp_mv;
+
+      for (i = 0; i < 2; ++i) {
+        lower_mv_precision(&cur_mv[i].as_mv, cm->allow_high_precision_mv);
+        clamp_mv2(&cur_mv[i].as_mv, xd);
+        if (mv_check_bounds(x, &cur_mv[i].as_mv))
+          return INT64_MAX;
+        mbmi->mv[i].as_int = cur_mv[i].as_int;
+      }
+    }
+  }
+#endif
+
   // do first prediction into the destination buffer. Do the next
   // prediction into a temporary buffer. Then keep track of which one
   // of these currently holds the best predictor, and use the other
@@ -5035,6 +5069,21 @@ void vp10_rd_pick_inter_mode_sb(VP10_COMP *cpi,
     frame_mv[ZEROMV][ref_frame].as_int = 0;
   }
 
+#if CONFIG_REF_MV
+  for (; ref_frame < MODE_CTX_REF_FRAMES; ++ref_frame) {
+    MODE_INFO *const mi = xd->mi[0];
+    int_mv *const candidates = x->mbmi_ext->ref_mvs[ref_frame];
+    x->mbmi_ext->mode_context[ref_frame] = 0;
+    vp10_find_mv_refs(cm, xd, mi, ref_frame,
+#if CONFIG_REF_MV
+                      &mbmi_ext->ref_mv_count[ref_frame],
+                      mbmi_ext->ref_mv_stack[ref_frame],
+#endif
+                      candidates, mi_row, mi_col,
+                      NULL, NULL, mbmi_ext->mode_context);
+  }
+#endif
+
   for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
     if (!(cpi->ref_frame_flags & flag_list[ref_frame])) {
       // Skip checking missing references in both single and compound reference
@@ -5625,7 +5674,51 @@ void vp10_rd_pick_inter_mode_sb(VP10_COMP *cpi,
     const MV_REFERENCE_FRAME refs[2] = {best_mbmode.ref_frame[0],
         best_mbmode.ref_frame[1]};
     int comp_pred_mode = refs[1] > INTRA_FRAME;
+#if CONFIG_REF_MV
+    if (!comp_pred_mode) {
+      if (frame_mv[NEARESTMV][refs[0]].as_int == best_mbmode.mv[0].as_int)
+        best_mbmode.mode = NEARESTMV;
+      else if (frame_mv[NEARMV][refs[0]].as_int == best_mbmode.mv[0].as_int)
+        best_mbmode.mode = NEARMV;
+      else if (best_mbmode.mv[0].as_int == 0)
+        best_mbmode.mode = ZEROMV;
+    } else {
+      uint8_t rf_type = vp10_ref_frame_type(best_mbmode.ref_frame);
+      if (mbmi_ext->ref_mv_count[rf_type] > 1) {
+        int i;
+        int_mv nearestmv[2], nearmv[2];
+        const int allow_hp = cm->allow_high_precision_mv;
+
+        nearestmv[0] = mbmi_ext->ref_mv_stack[rf_type][0].this_mv;
+        nearestmv[1] = mbmi_ext->ref_mv_stack[rf_type][0].comp_mv;
+        nearmv[0] = mbmi_ext->ref_mv_stack[rf_type][1].this_mv;
+        nearmv[1] = mbmi_ext->ref_mv_stack[rf_type][1].comp_mv;
+
+        for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) {
+          lower_mv_precision(&nearestmv[i].as_mv, allow_hp);
+          lower_mv_precision(&nearmv[i].as_mv, allow_hp);
+        }
 
+        if (nearestmv[0].as_int == best_mbmode.mv[0].as_int &&
+            nearestmv[1].as_int == best_mbmode.mv[1].as_int)
+          best_mbmode.mode = NEARESTMV;
+        else if (nearmv[0].as_int == best_mbmode.mv[0].as_int &&
+            nearmv[1].as_int == best_mbmode.mv[1].as_int)
+          best_mbmode.mode = NEARMV;
+        else if (best_mbmode.mv[0].as_int == 0 && best_mbmode.mv[1].as_int == 0)
+          best_mbmode.mode = ZEROMV;
+      } else {
+        if (frame_mv[NEARESTMV][refs[0]].as_int == best_mbmode.mv[0].as_int &&
+            (frame_mv[NEARESTMV][refs[1]].as_int == best_mbmode.mv[1].as_int))
+          best_mbmode.mode = NEARESTMV;
+        else if (frame_mv[NEARMV][refs[0]].as_int == best_mbmode.mv[0].as_int &&
+            (frame_mv[NEARMV][refs[1]].as_int == best_mbmode.mv[1].as_int))
+          best_mbmode.mode = NEARMV;
+        else if (best_mbmode.mv[0].as_int == 0 && best_mbmode.mv[1].as_int == 0)
+          best_mbmode.mode = ZEROMV;
+      }
+    }
+#else
     if (frame_mv[NEARESTMV][refs[0]].as_int == best_mbmode.mv[0].as_int &&
         ((comp_pred_mode && frame_mv[NEARESTMV][refs[1]].as_int ==
             best_mbmode.mv[1].as_int) || !comp_pred_mode))
@@ -5637,6 +5730,7 @@ void vp10_rd_pick_inter_mode_sb(VP10_COMP *cpi,
     else if (best_mbmode.mv[0].as_int == 0 &&
         ((comp_pred_mode && best_mbmode.mv[1].as_int == 0) || !comp_pred_mode))
       best_mbmode.mode = ZEROMV;
+#endif
   }
 
 #if CONFIG_REF_MV