This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

commit 5d6f409cdd65c3943d1b7447524008bba4ac36c9
Author:     Charly Morgand-Poyac <[email protected]>
AuthorDate: Sun Jul 5 22:45:39 2026 +0200
Commit:     charlymp <[email protected]>
CommitDate: Sat Jul 11 14:23:12 2026 +0000

    lavc/hevcdec: decode runs of bypass bins with one integer division
    
    Reading a bypass bin doubles the offset and conditionally subtracts
    range << 17, which is one step of a binary long division: a run of n
    bins is the quotient of the offset, shifted and refilled upfront, by
    range << 17, and the new offset is its remainder. Decisions only
    depend on multiples of 2^17, so the reordered refill cannot change
    any of them; a quotient overflowing n bits, which needs an offset
    closer to the range than the pending low bits can distinguish, falls
    back to the serial loop.
    
    Use it for the coefficient sign runs, the Golomb-Rice suffixes and
    the unary prefixes, whose length is the number of leading ones of a
    quotient peeked without committing the bins past the terminating
    zero. Sign bins are equiprobable by construction, so on top of the
    saved renormalisation work this removes data dependent branch
    mispredictions. About 3% faster single threaded decoding on high
    bitrate streams.
    
    Signed-off-by: Charly Morgand-Poyac <[email protected]>
---
 libavcodec/hevc/cabac.c | 94 +++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 87 insertions(+), 7 deletions(-)

diff --git a/libavcodec/hevc/cabac.c b/libavcodec/hevc/cabac.c
index fe637acbaa..cbf774fae4 100644
--- a/libavcodec/hevc/cabac.c
+++ b/libavcodec/hevc/cabac.c
@@ -938,30 +938,107 @@ static av_always_inline int 
coeff_abs_level_greater2_flag_decode(HEVCLocalContex
     return GET_CABAC(COEFF_ABS_LEVEL_GREATER2_FLAG_OFFSET + inc);
 }
 
-static av_always_inline int coeff_abs_level_remaining_decode(HEVCLocalContext 
*lc, int rc_rice_param)
+/* a run of bypass bins is the quotient of the offset by range << 17 */
+static int cabac_bypass_bits(CABACContext *c, int n)
+{
+    int avail = CABAC_BITS - ff_ctz(c->low);
+    uint64_t x, r = (uint64_t)c->range << (CABAC_BITS + 1);
+    const uint8_t *bytestream = c->bytestream;
+
+    if (n < avail) {
+        x = (uint64_t)c->low << n;
+    } else {
+        int fill = (bytestream[0] << 9) + (bytestream[1] << 1) - CABAC_MASK;
+
+        x = (uint64_t)((((int64_t)c->low << avail) + fill)) << (n - avail);
+#if !UNCHECKED_BITSTREAM_READER
+        if (bytestream < c->bytestream_end)
+#endif
+            bytestream += CABAC_BITS / 8;
+    }
+
+    if (x < r << n) {
+        c->low = x % r;
+        c->bytestream = bytestream;
+        return x / r;
+    } else {
+        int ret = 0;
+
+        for (int i = 0; i < n; i++)
+            ret = (ret << 1) | get_cabac_bypass(c);
+        return ret;
+    }
+}
+
+/* leading ones of the quotient, consumed only up to the first zero */
+static int cabac_unary_prefix(CABACContext *c, int max)
 {
     int prefix = 0;
+
+    while (prefix < max) {
+        int avail = CABAC_BITS - ff_ctz(c->low);
+        int n = FFMIN(avail - 1, max - prefix);
+        uint64_t r = (uint64_t)c->range << (CABAC_BITS + 1);
+        uint64_t x = (uint64_t)c->low << n;
+        int q, t;
+
+        if (n < 1 || x >= r << n) {
+            if (!get_cabac_bypass(c))
+                return prefix;
+            prefix++;
+            continue;
+        }
+
+        q = x / r;
+        t = ~q & ((1 << n) - 1);
+        if (t) {
+            int p = n - 1 - av_log2(t);
+            int k = n - (p + 1);
+
+            c->low = (x >> k) - ((uint64_t)(q >> k) * r);
+            return prefix + p;
+        }
+        c->low = x - (uint64_t)q * r;
+        prefix += n;
+    }
+    return prefix;
+}
+
+static av_always_inline int coeff_abs_level_remaining_decode(HEVCLocalContext 
*lc, int rc_rice_param)
+{
+    int prefix;
     int suffix = 0;
     int last_coeff_abs_level_remaining;
     int i;
 
-    while (prefix < CABAC_MAX_BIN && get_cabac_bypass(&lc->cc))
-        prefix++;
+    prefix = cabac_unary_prefix(&lc->cc, CABAC_MAX_BIN);
 
     if (prefix < 3) {
-        for (i = 0; i < rc_rice_param; i++)
-            suffix = (suffix << 1) | get_cabac_bypass(&lc->cc);
+        if (rc_rice_param > 2)
+            suffix = cabac_bypass_bits(&lc->cc, rc_rice_param);
+        else
+            for (i = 0; i < rc_rice_param; i++)
+                suffix = (suffix << 1) | get_cabac_bypass(&lc->cc);
         last_coeff_abs_level_remaining = (prefix << rc_rice_param) + suffix;
     } else {
         int prefix_minus3 = prefix - 3;
+        int k;
 
         if (prefix == CABAC_MAX_BIN || prefix_minus3 + rc_rice_param > 16 + 6) 
{
             av_log(lc->logctx, AV_LOG_ERROR, "CABAC_MAX_BIN : %d\n", prefix);
             return 0;
         }
 
-        for (i = 0; i < prefix_minus3 + rc_rice_param; i++)
-            suffix = (suffix << 1) | get_cabac_bypass(&lc->cc);
+        k = prefix_minus3 + rc_rice_param;
+        if (k > 16) {
+            suffix  = cabac_bypass_bits(&lc->cc, 16) << (k - 16);
+            suffix |= cabac_bypass_bits(&lc->cc, k - 16);
+        } else if (k > 2) {
+            suffix = cabac_bypass_bits(&lc->cc, k);
+        } else {
+            for (i = 0; i < k; i++)
+                suffix = (suffix << 1) | get_cabac_bypass(&lc->cc);
+        }
         last_coeff_abs_level_remaining = (((1 << prefix_minus3) + 3 - 1)
                                               << rc_rice_param) + suffix;
     }
@@ -973,6 +1050,9 @@ static av_always_inline int 
coeff_sign_flag_decode(HEVCLocalContext *lc, uint8_t
     int i;
     int ret = 0;
 
+    if (nb > 2)
+        return cabac_bypass_bits(&lc->cc, nb);
+
     for (i = 0; i < nb; i++)
         ret = (ret << 1) | get_cabac_bypass(&lc->cc);
     return ret;

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

Reply via email to