shithub: libvpx

Download patch

ref: 24c346dffc3a8b48a6941241485d5bbe49b1a0ee
parent: 272974af361993de7a38896155f9600cbe1c07ba
author: Yunqing Wang <yunqingwang@google.com>
date: Tue Aug 21 06:52:35 EDT 2012

Add biasing to ZEROMV for videos with static background

For videos with big static background(such as video conferencing
clips), the mode decision was biased to ZEROMV in order to
obtain a stable background. The percentage of ZEROMV on last
frame was used to predict if there is static area in current frame,
and checking already-encoded neighboring macroblocks' motion
vectors to make sure the local area has low motion.

Change-Id: I05b3241d3a56a0bda88b6681e5646c1c8baf2e57

--- a/vp8/encoder/onyx_if.c
+++ b/vp8/encoder/onyx_if.c
@@ -1104,6 +1104,7 @@
 
     /* Data used for real time vc mode to see if gf needs refreshing */
     cpi->inter_zz_count = 0;
+    cpi->zeromv_count = 0;
     cpi->gf_bad_count = 0;
     cpi->gf_update_recommended = 0;
 
@@ -4306,6 +4307,7 @@
         MODE_INFO *tmp = cm->mi;
 
         cpi->inter_zz_count = 0;
+        cpi->zeromv_count = 0;
 
         if(cm->frame_type != KEY_FRAME)
         {
@@ -4315,6 +4317,8 @@
                 {
                     if(tmp->mbmi.mode == ZEROMV && tmp->mbmi.ref_frame == LAST_FRAME)
                         cpi->inter_zz_count++;
+                    if(tmp->mbmi.mode == ZEROMV)
+                        cpi->zeromv_count++;
                     tmp++;
                 }
                 tmp++;
@@ -5115,6 +5119,8 @@
         vpx_usec_timer_start(&tsctimer);
         vpx_usec_timer_start(&ticktimer);
     }
+
+    cpi->lf_zeromv_pct = (cpi->zeromv_count * 100)/cm->MBs;
 
 #if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING
     {
--- a/vp8/encoder/onyx_int.h
+++ b/vp8/encoder/onyx_int.h
@@ -515,6 +515,9 @@
      * would be good to update the gf
      */
     int inter_zz_count;
+    /* Count ZEROMV on all reference frames. */
+    int zeromv_count;
+    int lf_zeromv_pct;
     int gf_bad_count;
     int gf_update_recommended;
     int skip_true_count;
--- a/vp8/encoder/pickinter.c
+++ b/vp8/encoder/pickinter.c
@@ -480,7 +480,8 @@
     }
 }
 
-static int evaluate_inter_mode(unsigned int* sse, int rate2, int* distortion2, VP8_COMP *cpi, MACROBLOCK *x)
+static int evaluate_inter_mode(unsigned int* sse, int rate2, int* distortion2,
+                               VP8_COMP *cpi, MACROBLOCK *x, int rd_adj)
 {
     MB_PREDICTION_MODE this_mode = x->e_mbd.mode_info_context->mbmi.mode;
     int_mv mv = x->e_mbd.mode_info_context->mbmi.mv;
@@ -503,10 +504,63 @@
 
     this_rd = RDCOST(x->rdmult, x->rddiv, rate2, *distortion2);
 
+    /* Adjust rd to bias to ZEROMV */
+    if(this_mode == ZEROMV)
+    {
+        /* Bias to ZEROMV on LAST_FRAME reference when it is available. */
+        if ((cpi->ref_frame_flags & VP8_LAST_FRAME &
+            cpi->common.refresh_last_frame)
+            && x->e_mbd.mode_info_context->mbmi.ref_frame != LAST_FRAME)
+            rd_adj = 100;
+
+        this_rd = this_rd * rd_adj/100;
+    }
+
     check_for_encode_breakout(*sse, x);
     return this_rd;
 }
 
+static void calculate_zeromv_rd_adjustment(VP8_COMP *cpi, MACROBLOCK *x,
+                                    int *rd_adjustment)
+{
+    MODE_INFO *mic = x->e_mbd.mode_info_context;
+    int_mv mv_l, mv_a, mv_al;
+    int local_motion_check = 0;
+
+    if (cpi->lf_zeromv_pct > 40)
+    {
+        /* left mb */
+        mic -= 1;
+        mv_l = mic->mbmi.mv;
+
+        if (mic->mbmi.ref_frame != INTRA_FRAME)
+            if( abs(mv_l.as_mv.row) < 8 && abs(mv_l.as_mv.col) < 8)
+                local_motion_check++;
+
+        /* above-left mb */
+        mic -= x->e_mbd.mode_info_stride;
+        mv_al = mic->mbmi.mv;
+
+        if (mic->mbmi.ref_frame != INTRA_FRAME)
+            if( abs(mv_al.as_mv.row) < 8 && abs(mv_al.as_mv.col) < 8)
+                local_motion_check++;
+
+        /* above mb */
+        mic += 1;
+        mv_a = mic->mbmi.mv;
+
+        if (mic->mbmi.ref_frame != INTRA_FRAME)
+            if( abs(mv_a.as_mv.row) < 8 && abs(mv_a.as_mv.col) < 8)
+                local_motion_check++;
+
+        if (((!x->e_mbd.mb_to_top_edge || !x->e_mbd.mb_to_left_edge)
+            && local_motion_check >0) ||  local_motion_check >2 )
+            *rd_adjustment = 80;
+        else if (local_motion_check > 0)
+            *rd_adjustment = 90;
+    }
+}
+
 void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
                          int recon_uvoffset, int *returnrate,
                          int *returndistortion, int *returnintra, int mb_row,
@@ -525,6 +579,7 @@
     int num00;
     int mdcounts[4];
     int best_rd = INT_MAX;
+    int rd_adjustment = 100;
     int best_intra_rd = INT_MAX;
     int mode_index;
     int rate;
@@ -594,6 +649,11 @@
 
     x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME;
 
+    /* If the frame has big static background and current MB is in low
+     * motion area, its mode decision is biased to ZEROMV mode.
+     */
+    calculate_zeromv_rd_adjustment(cpi, x, &rd_adjustment);
+
     /* if we encode a new mv this is important
      * find the best new motion vector
      */
@@ -981,7 +1041,8 @@
             rate2 += vp8_cost_mv_ref(this_mode, mdcounts);
             x->e_mbd.mode_info_context->mbmi.mv.as_int =
                                                     mode_mv[this_mode].as_int;
-            this_rd = evaluate_inter_mode(&sse, rate2, &distortion2, cpi, x);
+            this_rd = evaluate_inter_mode(&sse, rate2, &distortion2, cpi, x,
+                                          rd_adjustment);
 
             break;
         default:
@@ -1119,7 +1180,8 @@
             x->e_mbd.mode_info_context->mbmi.mode = ZEROMV;
             x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED;
             x->e_mbd.mode_info_context->mbmi.mv.as_int = 0;
-            this_rd = evaluate_inter_mode(&sse, rate2, &distortion2, cpi, x);
+            this_rd = evaluate_inter_mode(&sse, rate2, &distortion2, cpi, x,
+                                          rd_adjustment);
 
             if (this_rd < best_rd)
             {