shithub: libvpx

Download patch

ref: 2d1ead342cbaaba5f5fd07c3165f48e1029d327c
parent: 21108d800c605a1e63cfa9f27a333e7b46924d84
author: Yaowu Xu <yaowu@google.com>
date: Mon Feb 6 10:10:13 EST 2012

Changed how coefficient probability table is updated

Added a frame level flag to indicate if coef probabilities are updated
at all for the frame.

During the experimental work with 8x8 transform, it is discovered that
even in the case of no probability is ever update, cost of transmitting
"no update" for each of probabilities can run up to become a significant
overhead cost. A single bit to indicate no-update for all coef probs
is therefore helpful, which is also demonstrated by the test results:

1. On Cif set:
http://www.corp.google.com/~yaowu/no_crawl/t8x8/cif_t8x8_updprob.html
(avg psnr: .14%, glb psnr: .14% SSIM: .13%)

2. On HD set:
http://www.corp.google.com/~yaowu/no_crawl/t8x8/HD_t8x8_updprob.html
(avg psnr: .02%  glb psnr: .01% SSIM: .02%)
It should be noted that the gain on HD is smaller because the average bit
rate is much higher in contrast to the overhead bit cost.

Change-Id: I46db270e693ee8799fef34a14d8260868ce4cd16

--- a/vp8/decoder/decodframe.c
+++ b/vp8/decoder/decodframe.c
@@ -1399,6 +1399,8 @@
     {
         pbi->independent_partitions = 1;
 
+        if(vp8_read_bit(bc))
+        {
         /* read coef probability tree */
         for (i = 0; i < BLOCK_TYPES; i++)
             for (j = 0; j < COEF_BANDS; j++)
@@ -1405,7 +1407,6 @@
                 for (k = 0; k < PREV_COEF_CONTEXTS; k++)
                     for (l = 0; l < ENTROPY_NODES; l++)
                     {
-
                         vp8_prob *const p = pc->fc.coef_probs [i][j][k] + l;
 
                         if (vp8_read(bc, vp8_coef_update_probs [i][j][k][l]))
@@ -1415,14 +1416,13 @@
                         }
                         if (k > 0 && *p != pc->fc.coef_probs[i][j][k-1][l])
                             pbi->independent_partitions = 0;
-
                     }
+        }
     }
 #if CONFIG_T8X8
-    if(pbi->common.txfm_mode == ALLOW_8X8)
+    if(pbi->common.txfm_mode == ALLOW_8X8 && vp8_read_bit(bc))
     {
         // read coef probability tree
-
         for (i = 0; i < BLOCK_TYPES; i++)
             for (j = 0; j < COEF_BANDS; j++)
                 for (k = 0; k < PREV_COEF_CONTEXTS; k++)
--- a/vp8/encoder/bitstream.c
+++ b/vp8/encoder/bitstream.c
@@ -2210,14 +2210,13 @@
 {
     int i = 0;
     vp8_writer *const w = & cpi->bc;
-    int savings = 0;
+    int update = 0;
 
     vp8_clear_system_state(); //__asm emms;
-
+    /* dry run to see if there is any udpate at all needed */
     do
     {
         int j = 0;
-
         do
         {
             int k = 0;
@@ -2235,7 +2234,6 @@
                         const vp8_prob oldp = cpi->common.fc.coef_probs[i][j]
                                                                        [k][t];
                         const vp8_prob upd = vp8_coef_update_probs[i][j][k][t];
-
                         prev_coef_savings[t] +=
                                 prob_update_savings(ct, oldp, newp, upd);
                     }
@@ -2246,29 +2244,22 @@
             {
                 //note: use result from vp8_estimate_entropy_savings, so no need to call vp8_tree_probs_from_distribution here.
                 /* at every context */
-
                 /* calc probs and branch cts for this frame only */
                 //vp8_prob new_p           [ENTROPY_NODES];
                 //unsigned int branch_ct   [ENTROPY_NODES] [2];
-
                 int t = 0;      /* token/prob index */
-
                 //vp8_tree_probs_from_distribution(
                 //    MAX_ENTROPY_TOKENS, vp8_coef_encodings, vp8_coef_tree,
                 //    new_p, branch_ct, (unsigned int *)cpi->coef_counts [i][j][k],
                 //    256, 1
                 //    );
-
                 do
                 {
                     const vp8_prob newp = cpi->frame_coef_probs [i][j][k][t];
-
                     vp8_prob *Pold = cpi->common.fc.coef_probs [i][j][k] + t;
                     const vp8_prob upd = vp8_coef_update_probs [i][j][k][t];
-
                     int s = prev_coef_savings[t];
                     int u = 0;
-
                     if (!(cpi->oxcf.error_resilient_mode &
                             VPX_ERROR_RESILIENT_PARTITIONS))
                     {
@@ -2276,10 +2267,8 @@
                                 cpi->frame_branch_ct [i][j][k][t],
                                 *Pold, newp, upd);
                     }
-
                     if (s > 0)
                         u = 1;
-
                     /* Force updates on key frames if the new is different,
                      * so that we can be sure we end up with equal probabilities
                      * over the prev coef contexts.
@@ -2288,113 +2277,162 @@
                             VPX_ERROR_RESILIENT_PARTITIONS) &&
                         cpi->common.frame_type == KEY_FRAME && newp != *Pold)
                         u = 1;
-
-                    vp8_write(w, u, upd);
-
-
-#ifdef ENTROPY_STATS
-                    ++ tree_update_hist [i][j][k][t] [u];
-#endif
-
-                    if (u)
-                    {
-                        /* send/use new probability */
-
-                        *Pold = newp;
-                        vp8_write_literal(w, newp, 8);
-
-                        savings += s;
-
-                    }
-
+                    update += u;
                 }
                 while (++t < ENTROPY_NODES);
-
                 /* Accum token counts for generation of default statistics */
-#ifdef ENTROPY_STATS
-                t = 0;
-
-                do
+            }
+            while (++k < PREV_COEF_CONTEXTS);
+        }
+        while (++j < COEF_BANDS);
+    }
+    while (++i < BLOCK_TYPES);
+    /* Is coef updated at all */
+    if(update==0)
+    {
+        vp8_write_bit(w, 0);
+    }
+    else
+    {
+        vp8_write_bit(w, 1);
+        i=0;
+        do
+        {
+            int j = 0;
+            do
+            {
+                int k = 0;
+                int prev_coef_savings[ENTROPY_NODES] = {0};
+                if (cpi->oxcf.error_resilient_mode & VPX_ERROR_RESILIENT_PARTITIONS)
                 {
-                    context_counters [i][j][k][t] += cpi->coef_counts [i][j][k][t];
+                    for (k = 0; k < PREV_COEF_CONTEXTS; ++k)
+                    {
+                        int t;      /* token/prob index */
+                        for (t = 0; t < ENTROPY_NODES; ++t)
+                        {
+                            const unsigned int *ct = cpi->frame_branch_ct [i][j]
+                            [k][t];
+                            const vp8_prob newp = cpi->frame_coef_probs[i][j][k][t];
+                            const vp8_prob oldp = cpi->common.fc.coef_probs[i][j]
+                            [k][t];
+                            const vp8_prob upd = vp8_coef_update_probs[i][j][k][t];
+                            prev_coef_savings[t] +=
+                                prob_update_savings(ct, oldp, newp, upd);
+                        }
+                    }
+                    k = 0;
                 }
-                while (++t < MAX_ENTROPY_TOKENS);
+                do
+                {
+                    //note: use result from vp8_estimate_entropy_savings, so no need to call vp8_tree_probs_from_distribution here.
+                    /* at every context */
 
+                    /* calc probs and branch cts for this frame only */
+                    //vp8_prob new_p           [ENTROPY_NODES];
+                    //unsigned int branch_ct   [ENTROPY_NODES] [2];
+                    int t = 0;      /* token/prob index */
+                    //vp8_tree_probs_from_distribution(
+                    //    MAX_ENTROPY_TOKENS, vp8_coef_encodings, vp8_coef_tree,
+                    //    new_p, branch_ct, (unsigned int *)cpi->coef_counts [i][j][k],
+                    //    256, 1
+                    //    );
+                    do
+                    {
+                        const vp8_prob newp = cpi->frame_coef_probs [i][j][k][t];
+                        vp8_prob *Pold = cpi->common.fc.coef_probs [i][j][k] + t;
+                        const vp8_prob upd = vp8_coef_update_probs [i][j][k][t];
+                        int s = prev_coef_savings[t];
+                        int u = 0;
+                        if (!(cpi->oxcf.error_resilient_mode &
+                            VPX_ERROR_RESILIENT_PARTITIONS))
+                        {
+                            s = prob_update_savings(
+                                cpi->frame_branch_ct [i][j][k][t],
+                                *Pold, newp, upd);
+                        }
+                        if (s > 0)
+                            u = 1;
+                        /* Force updates on key frames if the new is different,
+                        * so that we can be sure we end up with equal probabilities
+                        * over the prev coef contexts.
+                        */
+                        if ((cpi->oxcf.error_resilient_mode &
+                            VPX_ERROR_RESILIENT_PARTITIONS) &&
+                            cpi->common.frame_type == KEY_FRAME && newp != *Pold)
+                            u = 1;
+                        vp8_write(w, u, upd);
+#ifdef ENTROPY_STATS
+                        ++ tree_update_hist [i][j][k][t] [u];
 #endif
-
+                        if (u)
+                        {
+                            /* send/use new probability */
+                            *Pold = newp;
+                            vp8_write_literal(w, newp, 8);
+                        }
+                    }
+                    while (++t < ENTROPY_NODES);
+                    /* Accum token counts for generation of default statistics */
+#ifdef ENTROPY_STATS
+                    t = 0;
+                    do
+                    {
+                        context_counters [i][j][k][t] += cpi->coef_counts [i][j][k][t];
+                    }
+                    while (++t < MAX_ENTROPY_TOKENS);
+#endif
+                }
+                while (++k < PREV_COEF_CONTEXTS);
             }
-            while (++k < PREV_COEF_CONTEXTS);
+            while (++j < COEF_BANDS);
         }
-        while (++j < COEF_BANDS);
+        while (++i < BLOCK_TYPES);
     }
-    while (++i < BLOCK_TYPES);
 
+
 #if CONFIG_T8X8
     /* do not do this if not evena allowed */
     if(cpi->common.txfm_mode == ALLOW_8X8)
     {
+        update = 1;
+        /* dry run to see if update is necessary */
         i = 0;
         do
         {
             int j = 0;
-
             do
             {
                 int k = 0;
-
                 do
                 {
                     //note: use result from vp8_estimate_entropy_savings, so no need to call vp8_tree_probs_from_distribution here.
                     /* at every context */
-
                     /* calc probs and branch cts for this frame only */
                     //vp8_prob new_p           [ENTROPY_NODES];
                     //unsigned int branch_ct   [ENTROPY_NODES] [2];
-
                     int t = 0;      /* token/prob index */
-
                     //vp8_tree_probs_from_distribution(
                     //    MAX_ENTROPY_TOKENS, vp8_coef_encodings, vp8_coef_tree,
                     //    new_p, branch_ct, (unsigned int *)cpi->coef_counts [i][j][k],
                     //    256, 1
                     //    );
-
                     do
                     {
                         const unsigned int *ct  = cpi->frame_branch_ct_8x8 [i][j][k][t];
                         const vp8_prob newp = cpi->frame_coef_probs_8x8 [i][j][k][t];
-
                         vp8_prob *Pold = cpi->common.fc.coef_probs_8x8 [i][j][k] + t;
                         const vp8_prob old = *Pold;
                         const vp8_prob upd = vp8_coef_update_probs_8x8 [i][j][k][t];
-
                         const int old_b = vp8_cost_branch(ct, old);
                         const int new_b = vp8_cost_branch(ct, newp);
-
                         const int update_b = 8 +
                             ((vp8_cost_one(upd) - vp8_cost_zero(upd)) >> 8);
-
                         const int s = old_b - new_b - update_b;
                         const int u = s > 0 ? 1 : 0;
-
-                        vp8_write(w, u, upd);
-
-
 #ifdef ENTROPY_STATS
                         ++ tree_update_hist_8x8 [i][j][k][t] [u];
 #endif
-
-                        if (u)
-                        {
-                            /* send/use new probability */
-
-                            *Pold = newp;
-                            vp8_write_literal(w, newp, 8);
-
-                            savings += s;
-
-                        }
-
+                        update += u;
                     }
                     while (++t < MAX_ENTROPY_TOKENS - 1);
 
@@ -2415,6 +2453,76 @@
             while (++j < COEF_BANDS);
         }
         while (++i < BLOCK_TYPES);
+
+        if(update == 0)
+        {
+            vp8_write_bit(w, 0);
+
+        }
+        else
+        {
+            vp8_write_bit(w, 1);
+            i = 0;
+            do
+            {
+                int j = 0;
+                do
+                {
+                    int k = 0;
+                    do
+                    {
+                        //note: use result from vp8_estimate_entropy_savings, so no need to call vp8_tree_probs_from_distribution here.
+                        /* at every context */
+                        /* calc probs and branch cts for this frame only */
+                        //vp8_prob new_p           [ENTROPY_NODES];
+                        //unsigned int branch_ct   [ENTROPY_NODES] [2];
+                        int t = 0;      /* token/prob index */
+                        //vp8_tree_probs_from_distribution(
+                        //    MAX_ENTROPY_TOKENS, vp8_coef_encodings, vp8_coef_tree,
+                        //    new_p, branch_ct, (unsigned int *)cpi->coef_counts [i][j][k],
+                        //    256, 1
+                        //    );
+                        do
+                        {
+                            const unsigned int *ct  = cpi->frame_branch_ct_8x8 [i][j][k][t];
+                            const vp8_prob newp = cpi->frame_coef_probs_8x8 [i][j][k][t];
+                            vp8_prob *Pold = cpi->common.fc.coef_probs_8x8 [i][j][k] + t;
+                            const vp8_prob old = *Pold;
+                            const vp8_prob upd = vp8_coef_update_probs_8x8 [i][j][k][t];
+                            const int old_b = vp8_cost_branch(ct, old);
+                            const int new_b = vp8_cost_branch(ct, newp);
+                            const int update_b = 8 +
+                                ((vp8_cost_one(upd) - vp8_cost_zero(upd)) >> 8);
+                            const int s = old_b - new_b - update_b;
+                            const int u = s > 0 ? 1 : 0;
+                            vp8_write(w, u, upd);
+#ifdef ENTROPY_STATS
+                            ++ tree_update_hist_8x8 [i][j][k][t] [u];
+#endif
+                            if (u)
+                            {
+                                /* send/use new probability */
+                                *Pold = newp;
+                                vp8_write_literal(w, newp, 8);
+                            }
+                        }
+                        while (++t < MAX_ENTROPY_TOKENS - 1);
+                        /* Accum token counts for generation of default statistics */
+#ifdef ENTROPY_STATS
+                        t = 0;
+                        do
+                        {
+                            context_counters_8x8 [i][j][k][t] += cpi->coef_counts_8x8 [i][j][k][t];
+                        }
+                        while (++t < MAX_ENTROPY_TOKENS);
+#endif
+                    }
+                    while (++k < PREV_COEF_CONTEXTS);
+                }
+                while (++j < COEF_BANDS);
+            }
+            while (++i < BLOCK_TYPES);
+        }
     }
 
 #endif