shithub: libvpx

Download patch

ref: 76feb965d3340cfe38a06ee017ff02e4a493cecf
parent: b1823a7dd290b233739fa437673d9ff385d5f273
author: Yaowu Xu <yaowu@google.com>
date: Tue Dec 6 07:03:42 EST 2011

made vp8_mode_context adaptive

vp8_mode_contexts[] is an entropy table used to code inter mode
choices. It was a fixed constant table. This commit made the entropy
context adaptive. Tests on derf set showed very good consistent gains
on all metrics: avg psnr .47%, overall psnr .46% and ssim .40%.

http://www.corp.google.com/~yaowu/no_crawl/newModeContext.html

Change-Id: Ia62b14485c948e2b74586118619c5eb2068b43b2

--- a/vp8/common/alloccommon.c
+++ b/vp8/common/alloccommon.c
@@ -190,6 +190,13 @@
     vp8_machine_specific_config(oci);
 
     vp8_init_mbmode_probs(oci);
+#if CONFIG_NEWNEAR
+    vp8_init_mv_ref_counts(oci);
+#endif
+    vpx_memcpy( oci->vp8_mode_contexts,
+                default_vp8_mode_contexts,
+                sizeof(default_vp8_mode_contexts));
+
     vp8_default_bmode_probs(oci->fc.bmode_prob);
 
     oci->mb_no_coeff_skip = 1;
--- a/vp8/common/entropymode.c
+++ b/vp8/common/entropymode.c
@@ -385,3 +385,103 @@
 
     vp8_tokens_from_tree(vp8_small_mvencodings, vp8_small_mvtree);
 }
+
+#if CONFIG_NEWNEAR
+void vp8_init_mv_ref_counts(VP8_COMMON *pc)
+{
+    vpx_memset(pc->mv_ref_ct, 0, sizeof(pc->mv_ref_ct));
+}
+
+void vp8_accum_mv_refs(VP8_COMMON *pc,
+                       MB_PREDICTION_MODE m,
+                       const int ct[4])
+{
+    if (m == ZEROMV)
+    {
+        ++pc->mv_ref_ct [ct[0]] [0] [0];
+    }
+    else
+    {
+        ++pc->mv_ref_ct [ct[0]] [0] [1];
+        if (m == NEARESTMV)
+        {
+            ++pc->mv_ref_ct [ct[1]] [1] [0];
+        }
+        else
+        {
+            ++pc->mv_ref_ct [ct[1]] [1] [1];
+            if (m == NEARMV)
+            {
+                ++pc->mv_ref_ct [ct[2]] [2] [0];
+            }
+            else
+            {
+                ++pc->mv_ref_ct [ct[2]] [2] [1];
+                if (m == NEWMV)
+                {
+                    ++pc->mv_ref_ct [ct[3]] [3] [0];
+                }
+                else
+                {
+                    ++pc->mv_ref_ct [ct[3]] [3] [1];
+                }
+            }
+        }
+    }
+}
+
+void vp8_update_mode_context(VP8_COMMON *pc)
+{
+    int i, j;
+    for (j = 0; j < 6; j++)
+    {
+        for (i = 0; i < 4; i++)
+        {
+            int this_prob;
+            int count;
+            // context probs
+            count = pc->mv_ref_ct[j][i][0] + pc->mv_ref_ct[j][i][1];
+            if (count)
+                this_prob = 256 * pc->mv_ref_ct[j][i][0] / count;
+            else
+                this_prob = 128;
+            if (this_prob == 0)
+                this_prob = 1;
+            if (this_prob == 256)
+                this_prob = 255;
+
+            pc->mode_context[j][i] = this_prob;
+        }
+    }
+}
+#include "vp8/common/modecont.h"
+void print_mode_contexts(VP8_COMMON *pc)
+{
+    int j, i;
+    for(j=0; j<6; j++)
+    {
+        for (i = 0; i < 4; i++)
+        {
+            printf( "%4d ", pc->vp8_mode_contexts[j][i]);
+        }
+        printf("\n");
+    }
+}
+void print_mv_ref_cts(VP8_COMMON *pc)
+{
+    int j, i;
+    for(j=0; j<6; j++)
+    {
+        for (i = 0; i < 4; i++)
+        {
+            printf("(%4d:%4d) ",
+                    pc->mv_ref_ct[j][i][0],
+                    pc->mv_ref_ct[j][i][1]);
+        }
+        printf("\n");
+    }
+}
+
+
+#endif
+
--- a/vp8/common/findnearmv.c
+++ b/vp8/common/findnearmv.c
@@ -278,14 +278,14 @@
 }
 #endif
 
-vp8_prob *vp8_mv_ref_probs(
+vp8_prob *vp8_mv_ref_probs(VP8_COMMON *pc,
     vp8_prob p[VP8_MVREFS-1], const int near_mv_ref_ct[4]
 )
 {
-    p[0] = vp8_mode_contexts [near_mv_ref_ct[0]] [0];
-    p[1] = vp8_mode_contexts [near_mv_ref_ct[1]] [1];
-    p[2] = vp8_mode_contexts [near_mv_ref_ct[2]] [2];
-    p[3] = vp8_mode_contexts [near_mv_ref_ct[3]] [3];
+    p[0] = pc->vp8_mode_contexts [near_mv_ref_ct[0]] [0];
+    p[1] = pc->vp8_mode_contexts [near_mv_ref_ct[1]] [1];
+    p[2] = pc->vp8_mode_contexts [near_mv_ref_ct[2]] [2];
+    p[3] = pc->vp8_mode_contexts [near_mv_ref_ct[3]] [3];
     return p;
 }
 
--- a/vp8/common/findnearmv.h
+++ b/vp8/common/findnearmv.h
@@ -16,6 +16,7 @@
 #include "blockd.h"
 #include "modecont.h"
 #include "treecoder.h"
+#include "onyxc_int.h"
 
 
 static void mv_bias(int refmb_ref_frame_sign_bias, int refframe, int_mv *mvp, const int *ref_frame_sign_bias)
@@ -84,7 +85,7 @@
     int *ref_frame_sign_bias
 );
 
-vp8_prob *vp8_mv_ref_probs(
+vp8_prob *vp8_mv_ref_probs(VP8_COMMON *pc,
     vp8_prob p[VP8_MVREFS-1], const int near_mv_ref_ct[4]
 );
 
--- a/vp8/common/modecont.c
+++ b/vp8/common/modecont.c
@@ -11,7 +11,7 @@
 
 #include "entropy.h"
 
-const int vp8_mode_contexts[6][4] =
+const int default_vp8_mode_contexts[6][4] =
 {
     {
         /* 0 */
--- a/vp8/common/modecont.h
+++ b/vp8/common/modecont.h
@@ -12,6 +12,6 @@
 #ifndef __INC_MODECONT_H
 #define __INC_MODECONT_H
 
-extern const int vp8_mode_contexts[6][4];
+extern const int default_vp8_mode_contexts[6][4];
 
 #endif
--- a/vp8/common/onyxc_int.h
+++ b/vp8/common/onyxc_int.h
@@ -218,6 +218,13 @@
     FRAME_CONTEXT lfc; /* last frame entropy */
     FRAME_CONTEXT fc;  /* this frame entropy */
 
+#if CONFIG_NEWNEAR
+    int mv_ref_ct[6][4][2];
+    int mode_context[6][4];
+#endif
+
+    int vp8_mode_contexts[6][4];
+
     unsigned int current_video_frame;
 
     int near_boffset[3];
--- a/vp8/decoder/decodemv.c
+++ b/vp8/decoder/decodemv.c
@@ -548,7 +548,7 @@
 #endif
             &nearest, &nearby, &best_mv, rct,
                           mbmi->ref_frame, pbi->common.ref_frame_sign_bias);
-        vp8_mv_ref_probs(mv_ref_p, rct);
+        vp8_mv_ref_probs(&pbi->common, mv_ref_p, rct);
 
 //#if CONFIG_SEGFEATURES
         // Is the segment level mode feature enabled for this segment
@@ -560,6 +560,10 @@
         else
         {
             mbmi->mode = read_mv_ref(bc, mv_ref_p);
+
+#if CONFIG_NEWNEAR
+            vp8_accum_mv_refs(&pbi->common, mbmi->mode, rct);
+#endif
         }
 
         mbmi->uv_mode = DC_PRED;
--- a/vp8/decoder/decodframe.c
+++ b/vp8/decoder/decodframe.c
@@ -27,6 +27,7 @@
 
 #include "decodemv.h"
 #include "vp8/common/extend.h"
+#include "vp8/common/modecont.h"
 #if CONFIG_ERROR_CONCEALMENT
 #include "error_concealment.h"
 #endif
@@ -862,7 +863,9 @@
         vpx_memcpy(&pc->lfc, &pc->fc, sizeof(pc->fc));
         vpx_memcpy(&pc->lfc_a, &pc->fc, sizeof(pc->fc));
 #endif
-
+#if CONFIG_NEWNEAR
+        vp8_init_mv_ref_counts(&pbi->common);
+#endif
     }
     else
     {
@@ -1364,8 +1367,30 @@
     /* Read the mb_no_coeff_skip flag */
     pc->mb_no_coeff_skip = (int)vp8_read_bit(bc);
 
-
     vp8_decode_mode_mvs(pbi);
+#if CONFIG_NEWNEAR
+    if(!pbi->common.refresh_alt_ref_frame)
+    {
+        vp8_update_mode_context(&pbi->common);
+        vpx_memcpy( pc->vp8_mode_contexts,
+                    pbi->common.mode_context,
+                    sizeof(pbi->common.mode_context));
+
+            if(0) //pbi->common.current_video_frame<2)
+            {
+                printf("mv_ref_ct on frame %d:\n",
+                        pbi->common.current_video_frame);
+                print_mv_ref_cts(&pbi->common);
+
+                printf("mode_contexts on frame %d:\n",
+                        pbi->common.current_video_frame);
+                print_mode_contexts();
+            }
+
+
+    }
+#endif
+
 
 #if CONFIG_ERROR_CONCEALMENT
     if (pbi->ec_active &&
--- a/vp8/encoder/bitstream.c
+++ b/vp8/encoder/bitstream.c
@@ -1156,11 +1156,12 @@
             else
             {
                 int_mv best_mv;
+                int ct[4];
+
                 vp8_prob mv_ref_p [VP8_MVREFS-1];
 
                 {
                     int_mv n1, n2;
-                    int ct[4];
 
                     vp8_find_near_mvs(xd, m,
 #if CONFIG_NEWNEAR
@@ -1167,8 +1168,9 @@
                         prev_m,
 #endif
                         &n1, &n2, &best_mv, ct, rf, cpi->common.ref_frame_sign_bias);
-                    vp8_mv_ref_probs(mv_ref_p, ct);
+                    vp8_mv_ref_probs(&cpi->common, mv_ref_p, ct);
 
+
 #ifdef ENTROPY_STATS
                     accum_mv_refs(mode, ct);
 #endif
@@ -1183,6 +1185,9 @@
                 if ( !segfeature_active( xd, segment_id, SEG_LVL_MODE ) )
                 {
                     write_mv_ref(w, mode, mv_ref_p);
+#if CONFIG_NEWNEAR
+                    vp8_accum_mv_refs(&cpi->common, mode, ct);
+#endif
                 }
 
                 {
@@ -2325,6 +2330,28 @@
     else
     {
         pack_inter_mode_mvs(cpi);
+
+#if CONFIG_NEWNEAR
+        if(!cpi->common.refresh_alt_ref_frame)
+        {
+            vp8_update_mode_context(&cpi->common);
+            vpx_memcpy( pc->vp8_mode_contexts,
+                        cpi->common.mode_context,
+                        sizeof(cpi->common.mode_context));
+
+            if(0) //(cpi->common.current_video_frame<2)
+            {
+
+                printf("mv_ref_ct on frame %d:\n",
+                        cpi->common.current_video_frame);
+                print_mv_ref_cts(&cpi->common);
+
+                printf("mode_contexts on frame %d:\n",
+                        cpi->common.current_video_frame);
+                print_mode_contexts();
+            }
+        }
+#endif
 
 #ifdef ENTROPY_STATS
         active_section = 1;
--- a/vp8/encoder/mcomp.c
+++ b/vp8/encoder/mcomp.c
@@ -1852,41 +1852,28 @@
         return INT_MAX;
 }
 
+
+
 #ifdef ENTROPY_STATS
 void print_mode_context(void)
 {
-    FILE *f = fopen("modecont.c", "w");
+    FILE *f = fopen("modecont.c", "a");
     int i, j;
 
     fprintf(f, "#include \"entropy.h\"\n");
-    fprintf(f, "const int vp8_mode_contexts[6][4] =\n");
+    fprintf(f, "const int vp8_mode_contexts[6][4] =");
     fprintf(f, "{\n");
-
     for (j = 0; j < 6; j++)
     {
-        fprintf(f, "  { // %d \n", j);
+        fprintf(f, "  {/* %d */ ", j);
         fprintf(f, "    ");
-
         for (i = 0; i < 4; i++)
         {
-            int overal_prob;
             int this_prob;
-            int count; // = mv_ref_ct[j][i][0]+mv_ref_ct[j][i][1];
+            int count;
 
-            // Overall probs
-            count = mv_mode_cts[i][0] + mv_mode_cts[i][1];
-
-            if (count)
-                overal_prob = 256 * mv_mode_cts[i][0] / count;
-            else
-                overal_prob = 128;
-
-            if (overal_prob == 0)
-                overal_prob = 1;
-
             // context probs
             count = mv_ref_ct[j][i][0] + mv_ref_ct[j][i][1];
-
             if (count)
                 this_prob = 256 * mv_ref_ct[j][i][0] / count;
             else
@@ -1894,12 +1881,8 @@
 
             if (this_prob == 0)
                 this_prob = 1;
-
             fprintf(f, "%5d, ", this_prob);
-            //fprintf(f,"%5d, %5d, %8d,", this_prob, overal_prob, (this_prob << 10)/overal_prob);
-            //fprintf(f,"%8d, ", (this_prob << 10)/overal_prob);
         }
-
         fprintf(f, "  },\n");
     }
 
@@ -1908,7 +1891,6 @@
 }
 
 /* MV ref count ENTROPY_STATS stats code */
-#ifdef ENTROPY_STATS
 void init_mv_ref_counts()
 {
     vpx_memset(mv_ref_ct, 0, sizeof(mv_ref_ct));
@@ -1964,4 +1946,4 @@
 
 #endif/* END MV ref count ENTROPY_STATS stats code */
 
-#endif
+
--- a/vp8/encoder/pickinter.c
+++ b/vp8/encoder/pickinter.c
@@ -47,7 +47,8 @@
 extern const MV_REFERENCE_FRAME vp8_second_ref_frame_order[MAX_MODES];
 
 extern unsigned int (*vp8_get4x4sse_cs)(unsigned char *src_ptr, int  source_stride, unsigned char *ref_ptr, int  recon_stride);
-extern int vp8_cost_mv_ref(MB_PREDICTION_MODE m, const int near_mv_ref_ct[4]);
+extern int vp8_cost_mv_ref(VP8_COMMON *pc,
+                           MB_PREDICTION_MODE m, const int near_mv_ref_ct[4]);
 
 
 int vp8_skip_fractional_mv_step(MACROBLOCK *mb, BLOCK *b, BLOCKD *d,
@@ -811,7 +812,7 @@
                 ((mode_mv[this_mode].as_mv.col >> 3) < x->mv_col_min) || ((mode_mv[this_mode].as_mv.col >> 3) > x->mv_col_max))
                 continue;
 
-            rate2 += vp8_cost_mv_ref(this_mode, mdcounts);
+            rate2 += vp8_cost_mv_ref(&cpi->common, this_mode, mdcounts);
             x->e_mbd.mode_info_context->mbmi.mv.as_int =
                                                     mode_mv[this_mode].as_int;
 
--- a/vp8/encoder/ratectrl.c
+++ b/vp8/encoder/ratectrl.c
@@ -267,6 +267,9 @@
     vpx_memcpy(&cpi->common.lfc_a, &cpi->common.fc, sizeof(cpi->common.fc));
 #endif
 
+#if CONFIG_NEWNEAR
+    vp8_init_mv_ref_counts(&cpi->common);
+#endif
 }
 #if CONFIG_MULCONTEXT
 void vp8_setup_inter_frame(VP8_COMP *cpi)
--- a/vp8/encoder/rdopt.c
+++ b/vp8/encoder/rdopt.c
@@ -1142,11 +1142,13 @@
     x->e_mbd.mode_info_context->mbmi.uv_mode = mode_selected;
 }
 
-int vp8_cost_mv_ref(MB_PREDICTION_MODE m, const int near_mv_ref_ct[4])
+int vp8_cost_mv_ref(VP8_COMMON *pc,
+                    MB_PREDICTION_MODE m,
+                    const int near_mv_ref_ct[4])
 {
     vp8_prob p [VP8_MVREFS-1];
     assert(NEARESTMV <= m  &&  m <= SPLITMV);
-    vp8_mv_ref_probs(p, near_mv_ref_ct);
+    vp8_mv_ref_probs(pc, p, near_mv_ref_ct);
     return vp8_cost_token(vp8_mv_ref_tree, p,
                           vp8_mv_ref_encoding_array - NEARESTMV + m);
 }
@@ -1362,7 +1364,7 @@
 
     // Segmentation method overheads
     rate = vp8_cost_token(vp8_mbsplit_tree, vp8_mbsplit_probs, vp8_mbsplit_encodings + segmentation);
-    rate += vp8_cost_mv_ref(SPLITMV, bsi->mdcounts);
+    rate += vp8_cost_mv_ref(&cpi->common, SPLITMV, bsi->mdcounts);
     this_segment_rd += RDCOST(x->rdmult, x->rddiv, rate, 0);
     br += rate;
 
@@ -2613,7 +2615,7 @@
             //intermodecost[mode_index] = vp8_cost_mv_ref(this_mode, mdcounts);   // Experimental debug code
 
             // Add in the Mv/mode cost
-            rate2 += vp8_cost_mv_ref(this_mode, mdcounts);
+            rate2 += vp8_cost_mv_ref(&cpi->common, this_mode, mdcounts);
 
             // Y cost and distortion
             macro_block_yrd(x, &rate_y, &distortion, IF_RTCD(&cpi->rtcd.encodemb));
@@ -2674,7 +2676,7 @@
             }
 
             /* Add in the Mv/mode cost */
-            rate2 += vp8_cost_mv_ref(this_mode, mdcounts);
+            rate2 += vp8_cost_mv_ref(&cpi->common,this_mode, mdcounts);
 
             vp8_clamp_mv2(&x->e_mbd.mode_info_context->mbmi.mv, xd);
             vp8_clamp_mv2(&x->e_mbd.mode_info_context->mbmi.second_mv, xd);
--