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]
