[FFmpeg-devel] [PATCH 5/7] proresdec2: use VLC for small runs and levels

Christophe Gisquet christophe.gisquet at gmail.com
Fri Sep 8 11:15:06 EEST 2023


Basically, the catch-all codebook is for on average long codewords,
and with a distribution such that the 3-step VLC reading is not
efficient. Furthermore, the complete unrolling make the actual code
smaller than the macro, and as the maximum codelength is smaller,
smaller amounts of bits, optimized for run and for level, can be read.
---
 libavcodec/proresdec2.c | 53 +++++++++++++++++++----------------------
 1 file changed, 24 insertions(+), 29 deletions(-)

diff --git a/libavcodec/proresdec2.c b/libavcodec/proresdec2.c
index e3cef402d7..02e1d82d00 100644
--- a/libavcodec/proresdec2.c
+++ b/libavcodec/proresdec2.c
@@ -132,7 +132,7 @@ static void unpack_alpha_12(GetBitContext *gb, uint16_t *dst, int num_coeffs,
 #define AC_BITS 12
 #define PRORES_LEV_BITS 9
 
-static const uint8_t ac_info[] = { 0x04, 0x0A, 0x05, 0x06, 0x28, 0x4C };
+static const uint8_t ac_info[] = { 0x04, 0x0A, 0x05, 0x06, 0x28, 0x29 };
 static VLC ac_vlc[6];
 
 static av_cold void init_vlcs(void)
@@ -152,9 +152,7 @@ static av_cold void init_vlcs(void)
         switch_val  = (switch_bits+1) << rice_order;
 
         // Values are actually transformed, but this is more a wrapping
-        ac_codes[0] = 0;
-        ac_bits[0] = 0;
-        for (ac = 0; ac < (1<<AC_BITS)-1; ac++) {
+        for (ac = 0; ac <1<<AC_BITS; ac++) {
             int exponent, bits, val = ac;
             unsigned int code;
 
@@ -171,8 +169,8 @@ static av_cold void init_vlcs(void)
                 code = 1;
             }
             if (bits > max_bits) max_bits = bits;
-            ac_bits [ac+1] = bits;
-            ac_codes[ac+1] = code;
+            ac_bits [ac] = bits;
+            ac_codes[ac] = code;
         }
 
         ff_free_vlc(ac_vlc+i);
@@ -507,12 +505,9 @@ static int decode_picture_header(AVCodecContext *avctx, const uint8_t *buf, cons
             bits = exp_order - switch_bits + (q<<1);                    \
             val = READ_BITS(gb, bits) - (1 << exp_order) +              \
                 ((switch_bits + 1) << rice_order);                      \
-        } else if (rice_order) {                                        \
-            skip_remaining(gb, q+1);                                    \
-            val = (q << rice_order) + get_bits(gb, rice_order);         \
         } else {                                                        \
-            val = q;                                                    \
             skip_remaining(gb, q+1);                                    \
+            val = rice_order ? (q << rice_order) + get_bits(gb, rice_order) : q;\
         }                                                               \
     } while (0)
 
@@ -527,12 +522,10 @@ static int decode_picture_header(AVCodecContext *avctx, const uint8_t *buf, cons
         if (q > switch_bits) { /* exp golomb */                         \
             bits = (q<<1) + (int)diff;                                  \
             val = READ_BITS(gb, bits) + (int)offset;                    \
-        } else if (rice_order) {                                        \
-            skip_remaining(gb, q+1);                                    \
-            val = (q << rice_order) + get_bits(gb, rice_order);         \
         } else {                                                        \
-            val = q;                                                    \
             skip_remaining(gb, q+1);                                    \
+            val = rice_order ? (q << rice_order) + show_bits(gb, rice_order) : q;   \
+            skip_remaining(gb, rice_order);                             \
         }                                                               \
     } while (0)
 
@@ -571,14 +564,6 @@ static av_always_inline int decode_dc_coeffs(GetBitContext *gb, int16_t *out,
     return 0;
 }
 
-// adaptive codebook switching lut according to previous run values
-static const char run_to_cb[16][4] = {
-    { 2, 0, -1,  1 }, { 2, 0, -1,  1 }, { 1, 0, 0,  0 }, { 1, 0,  0,  0 }, { 0, 0, 1, -1 },
-    { 1, 1,  1,  0 }, { 1, 1,  1,  0 }, { 1, 1, 1,  0 }, { 1, 1,  1,  0 },
-    { 0, 1,  2, -2 }, { 0, 1,  2, -2 }, { 0, 1, 2, -2 }, { 0, 1,  2, -2 }, { 0, 1, 2, -2 }, { 0, 1, 2, -2 },
-    { 0, 2,  3, -4 }
-};
-
 static av_always_inline int decode_ac_coeffs(AVCodecContext *avctx, GetBitContext *gb,
                                              int16_t *out, int blocks_per_slice)
 {
@@ -595,22 +580,32 @@ static av_always_inline int decode_ac_coeffs(AVCodecContext *avctx, GetBitContex
     block_mask = blocks_per_slice - 1;
 
     for (pos = block_mask;;) {
-        static const uint8_t ctx_to_tbl[] = { 0, 1, 2, 3, 0, 4, 4, 4, 4, 5 };
-        const VLC* tbl = ac_vlc + ctx_to_tbl[FFMIN(level, 9)];
-        unsigned int runcb = FFMIN(run,  15);
         bits_rem = get_bits_left(gb);
-        if (!bits_rem || (bits_rem < 16 && !show_bits(gb, bits_rem)))
+        if (!bits_rem || (bits_rem < 14 && !show_bits(gb, bits_rem)))
             break;
 
-        DECODE_CODEWORD2(run, run_to_cb[runcb][0], run_to_cb[runcb][1],
-                              run_to_cb[runcb][2], run_to_cb[runcb][3]);
+        if (run < 15) {
+            static const uint8_t ctx_to_tbl[] = { 3, 3, 2, 2, 0, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4 };
+            const VLC* tbl = ac_vlc + ctx_to_tbl[run];
+            run = get_vlc2(gb, tbl->table, PRORES_LEV_BITS, 3);
+        } else {
+            unsigned int bits = 21 - 2*av_log2(show_bits(gb, 10));
+            run = READ_BITS(gb, bits) - 4; // up to 17 bits
+        }
         pos += run + 1;
         if (pos >= max_coeffs) {
             av_log(avctx, AV_LOG_ERROR, "ac tex damaged %d, %d\n", pos, max_coeffs);
             return AVERROR_INVALIDDATA;
         }
 
-        level = get_vlc2(gb, tbl->table, PRORES_LEV_BITS, 3);
+        if (level < 9) {
+            static const uint8_t ctx_to_tbl[] = { 0, 1, 2, 3, 0, 4, 4, 4, 4 };
+            const VLC* tbl = ac_vlc + ctx_to_tbl[level];
+            level = 1+get_vlc2(gb, tbl->table, PRORES_LEV_BITS, 3);
+        } else {
+            unsigned int bits = 25 - 2*av_log2(show_bits(gb, 12));
+            level = READ_BITS(gb, bits) - 4 + 1; // up to 21 bits
+        }
 
         i = pos >> log2_block_count;
 
-- 
2.42.0



More information about the ffmpeg-devel mailing list