[FFmpeg-devel] [PATCH] Faster CABAC H.264 residual decoding

Jason Garrett-Glaser darkshikari
Sat Apr 26 11:28:10 CEST 2008


x264 uses a CABAC transition table (basically a finite-state machine)
for handling CABAC contexts in residual encoding.  This was ported by
me from x264's trellis code, which was originally the only place to
use such a table.  The original code was written by Loren Merrit.
Fortunately, this transition method can be used equivalently in
decoding, allowing us to completely avoid all context calculation and
merely use the transition table.  On a relatively high-bitrate clip,
the benefit of this change was about 0.85% overall decoding speed.  I
didn't measure the exact performance improvement in the function
itself.  I have done some testing of this, but I can't guarantee its
perfect (though theoretically it should work just fine).

Dark Shikari

Index: libavcodec/h264.c
===================================================================
--- libavcodec/h264.c	(revision 12977)
+++ libavcodec/h264.c	(working copy)
@@ -5394,14 +5394,26 @@
         9, 9,10,10, 8,11,12,11, 9, 9,10,10, 8,13,13, 9,
         9,10,10, 8,13,13, 9, 9,10,10,14,14,14,14,14 }
     };
+
+    // node ctx: 0..3: abslevel1 (with abslevelgt1 == 0).
+    //           4..7: abslevelgt1 + 3 (and abslevel1 doesn't matter).
+    /* map node ctx => cabac ctx for level=1 */
+    static const int coeff_abs_level1_ctx[8] = { 1, 2, 3, 4, 0, 0, 0, 0 };
+    /* map node ctx => cabac ctx for level>1 */
+    static const int coeff_abs_levelgt1_ctx[8] = { 5, 5, 5, 5, 6, 7, 8, 9 };
+    static const int coeff_abs_level_transition[2][8] = {
+    /* update node ctx after coding a level=1 */
+        { 1, 2, 3, 3, 4, 5, 6, 7 },
+    /* update node ctx after coding a level>1 */
+        { 4, 4, 4, 4, 5, 6, 7, 7 }
+    };

     int index[64];

     int av_unused last;
     int coeff_count = 0;

-    int abslevel1 = 1;
-    int abslevelgt1 = 0;
+    int node_ctx = 0;

     uint8_t *significant_coeff_ctx_base;
     uint8_t *last_coeff_ctx_base;
@@ -5495,7 +5507,8 @@
     }

     for( coeff_count--; coeff_count >= 0; coeff_count-- ) {
-        uint8_t *ctx = (abslevelgt1 != 0 ? 0 : FFMIN( 4, abslevel1 ))
+ abs_level_m1_ctx_base;
+        uint8_t *ctx = coeff_abs_level1_ctx[node_ctx] + abs_level_m1_ctx_base;
+
         int j= scantable[index[coeff_count]];

         if( get_cabac( CC, ctx ) == 0 ) {
@@ -5505,10 +5518,11 @@
                 block[j] = (get_cabac_bypass_sign( CC, -qmul[j]) + 32) >> 6;
             }

-            abslevel1++;
+            node_ctx = coeff_abs_level_transition[0][node_ctx];
         } else {
             int coeff_abs = 2;
-            ctx = 5 + FFMIN( 4, abslevelgt1 ) + abs_level_m1_ctx_base;
+            ctx = coeff_abs_levelgt1_ctx[node_ctx] + abs_level_m1_ctx_base;
+
             while( coeff_abs < 15 && get_cabac( CC, ctx ) ) {
                 coeff_abs++;
             }
@@ -5534,7 +5548,7 @@
                 else                                block[j] = (
coeff_abs * qmul[j] + 32) >> 6;
             }

-            abslevelgt1++;
+            node_ctx = coeff_abs_level_transition[1][node_ctx];
         }
     }
 #ifdef CABAC_ON_STACK




More information about the ffmpeg-devel mailing list