PR #24412 opened by Kyle Swanson (kylophone)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24412
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24412.patch

Speedup is around 34% on an AMD EPYC 9R14, single threaded 4K 422 HQ.

Signed-off-by: Kyle Swanson <[email protected]>

# Summary of changes

`decode_dc_coeffs()`/`decode_ac_coeffs()` had been loading 32 bits from the 
bitstream for every codeword via UPDATE_CACHE_32. Since the mean codeword seems 
to be something like ~4 bits, using CACHED_BITSTREAM_READER means 64 bits are 
cached and refilled 32 bits at a time, so a dozen codewords come out of one 
refill instead of one. I wrote this whole thing from scratch before I realized 
CACHED_BITSTREAM_READER was a thing, and results were similar. Speedup is 
around 34% on an AMD EPYC 9R14, single threaded 4K 422 HQ. If you are 
interested, please test.


>From ea302379b992250326a1847db2147df4c878cbf1 Mon Sep 17 00:00:00 2001
From: Kyle Swanson <[email protected]>
Date: Mon, 31 Aug 2026 18:00:37 +0000
Subject: [PATCH] avcodec/proresdec: use the cached bitstream reader for
 coefficient parsing

Speedup is around 34% on an AMD EPYC 9R14, single threaded 4K 422 HQ.

Signed-off-by: Kyle Swanson <[email protected]>
---
 libavcodec/proresdec.c | 42 ++++++++++++++++++------------------------
 1 file changed, 18 insertions(+), 24 deletions(-)

diff --git a/libavcodec/proresdec.c b/libavcodec/proresdec.c
index b971d17972..cfcc866885 100644
--- a/libavcodec/proresdec.c
+++ b/libavcodec/proresdec.c
@@ -35,6 +35,7 @@
 #include "avcodec.h"
 #include "codec_internal.h"
 #include "decode.h"
+#define CACHED_BITSTREAM_READER 1
 #include "get_bits.h"
 #include "hwaccel_internal.h"
 #include "hwconfig.h"
@@ -420,13 +421,12 @@ static int decode_picture_header(AVCodecContext *avctx, 
const uint8_t *buf, cons
     return pic_data_size;
 }
 
-#define DECODE_CODEWORD(val, codebook, SKIP)                            \
+#define DECODE_CODEWORD(val, codebook, gb)                              \
     do {                                                                \
         unsigned int rice_order, exp_order, switch_bits;                \
         unsigned int q, buf, bits;                                      \
                                                                         \
-        UPDATE_CACHE_32(re, gb); /* We really need 32 bits */           \
-        buf = GET_CACHE(re, gb);                                        \
+        buf = show_bits(gb, 32); /* We really need 32 bits */           \
                                                                         \
         /* number of bits to switch between rice and exp golomb */      \
         switch_bits =  codebook & 3;                                    \
@@ -439,16 +439,17 @@ static int decode_picture_header(AVCodecContext *avctx, 
const uint8_t *buf, cons
             bits = exp_order - switch_bits + (q<<1);                    \
             if (bits > 31)                                              \
                 return AVERROR_INVALIDDATA;                             \
-            val = SHOW_UBITS(re, gb, bits) - (1 << exp_order) +         \
+            val = (buf >> (32 - bits)) - (1 << exp_order) +             \
                 ((switch_bits + 1) << rice_order);                      \
-            SKIP(re, gb, bits);                                         \
+            skip_bits(gb, bits);                                        \
         } else if (rice_order) {                                        \
-            SKIP_BITS(re, gb, q+1);                                     \
-            val = (q << rice_order) + SHOW_UBITS(re, gb, rice_order);   \
-            SKIP(re, gb, rice_order);                                   \
+            bits = q + 1 + rice_order;                                  \
+            val = (q << rice_order) +                                   \
+                ((buf >> (32 - bits)) & ((1u << rice_order) - 1));      \
+            skip_bits(gb, bits);                                        \
         } else {                                                        \
             val = q;                                                    \
-            SKIP(re, gb, q+1);                                          \
+            skip_bits(gb, q + 1);                                       \
         }                                                               \
     } while (0)
 
@@ -464,9 +465,7 @@ static av_always_inline int decode_dc_coeffs(GetBitContext 
*gb, int16_t *out,
     int16_t prev_dc;
     int code, i, sign;
 
-    OPEN_READER(re, gb);
-
-    DECODE_CODEWORD(code, FIRST_DC_CB, LAST_SKIP_BITS);
+    DECODE_CODEWORD(code, FIRST_DC_CB, gb);
     prev_dc = TOSIGNED(code);
     out[0] = prev_dc;
 
@@ -475,13 +474,12 @@ static av_always_inline int 
decode_dc_coeffs(GetBitContext *gb, int16_t *out,
     code = 5;
     sign = 0;
     for (i = 1; i < blocks_per_slice; i++, out += 64) {
-        DECODE_CODEWORD(code, dc_codebook[FFMIN(code, 6U)], LAST_SKIP_BITS);
+        DECODE_CODEWORD(code, dc_codebook[FFMIN(code, 6U)], gb);
         if(code) sign ^= -(code & 1);
         else     sign  = 0;
         prev_dc += (((code + 1) >> 1) ^ sign) - sign;
         out[0] = prev_dc;
     }
-    CLOSE_READER(re, gb);
     return 0;
 }
 
@@ -495,11 +493,9 @@ static av_always_inline int 
decode_ac_coeffs(AVCodecContext *avctx, GetBitContex
     const ProresContext *ctx = avctx->priv_data;
     int block_mask, sign;
     unsigned pos, run, level;
-    int max_coeffs, i, bits_left;
+    int max_coeffs, i, left_bits;
     int log2_block_count = av_log2(blocks_per_slice);
 
-    OPEN_READER(re, gb);
-    UPDATE_CACHE_32(re, gb);
     run   = 4;
     level = 2;
 
@@ -507,28 +503,26 @@ static av_always_inline int 
decode_ac_coeffs(AVCodecContext *avctx, GetBitContex
     block_mask = blocks_per_slice - 1;
 
     for (pos = block_mask;;) {
-        bits_left = gb->size_in_bits - re_index;
-        if (bits_left <= 0 || (bits_left < 32 && !SHOW_UBITS(re, gb, 
bits_left)))
+        left_bits = get_bits_left(gb);
+        if (left_bits <= 0 || (left_bits < 32 && !show_bits(gb, left_bits)))
             break;
 
-        DECODE_CODEWORD(run, run_to_cb[FFMIN(run,  15)], LAST_SKIP_BITS);
+        DECODE_CODEWORD(run, run_to_cb[FFMIN(run,  15)], gb);
         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;
         }
 
-        DECODE_CODEWORD(level, lev_to_cb[FFMIN(level, 9)], SKIP_BITS);
+        DECODE_CODEWORD(level, lev_to_cb[FFMIN(level, 9)], gb);
         level += 1;
 
         i = pos >> log2_block_count;
 
-        sign = SHOW_SBITS(re, gb, 1);
-        SKIP_BITS(re, gb, 1);
+        sign = -(int)get_bits1(gb);
         out[((pos & block_mask) << 6) + ctx->scan[i]] = ((level ^ sign) - 
sign);
     }
 
-    CLOSE_READER(re, gb);
     return 0;
 }
 
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to