[FFmpeg-devel] [PATCH 7/8] avcodec/rangecoder: Implement reading and writing upto 8 bits raw

Michael Niedermayer michael at niedermayer.cc
Wed Oct 16 22:49:54 EEST 2024


This is much faster than doing 1 bit and updating a state

Signed-off-by: Michael Niedermayer <michael at niedermayer.cc>
---
 libavcodec/rangecoder.h       | 46 +++++++++++++++++++++++++++++++++++
 libavcodec/tests/rangecoder.c | 13 ++++++++++
 2 files changed, 59 insertions(+)

diff --git a/libavcodec/rangecoder.h b/libavcodec/rangecoder.h
index 15217a99a3c..39eb5987ca8 100644
--- a/libavcodec/rangecoder.h
+++ b/libavcodec/rangecoder.h
@@ -76,6 +76,22 @@ static inline void renorm_encoder(RangeCoder *c)
         c->range <<= 8;
 }
 
+static inline void renorm_encoder_raw(RangeCoder *c)
+{
+    if (c->low - 0xFF0001 >= 0x1000000 - 0xFF0001U) {
+        int mask = c->low - 0xFF0001 >> 31;
+        *c->bytestream = c->outstanding_byte + 1 + mask;
+        c->bytestream += c->outstanding_byte >= 0;
+        for (; c->outstanding_count; c->outstanding_count--)
+            *c->bytestream++ = mask;
+        c->outstanding_byte = c->low >> 16;
+    } else {
+        c->outstanding_count++;
+    }
+
+    c->low &= 0xFFFF;
+}
+
 static inline int get_rac_count(RangeCoder *c)
 {
     int x = c->bytestream - c->bytestream_start + c->outstanding_count;
@@ -104,6 +120,20 @@ static inline void put_rac(RangeCoder *c, uint8_t *const state, int bit)
         renorm_encoder(c);
 }
 
+static inline void put_rac_raw(RangeCoder *c, int bits, int len)
+{
+    int r = c->range >> len;
+
+    if (r < 0x100) {
+        c->range <<= 8 - len;
+        c->low     = (c->low << 8) + c->range * bits;
+        renorm_encoder_raw(c);
+    } else {
+        c->low += r * bits;
+        c->range = r;
+    }
+}
+
 static inline void refill(RangeCoder *c)
 {
         c->range <<= 8;
@@ -135,4 +165,20 @@ static inline int get_rac(RangeCoder *c, uint8_t *const state)
     }
 }
 
+static inline int get_rac_raw(RangeCoder *c, int len)
+{
+    int bits;
+    int r = c->range >> len;
+    av_assert2(len <= 8);
+
+    if (r < 0x100) {
+        refill(c);
+        r = c->range >> len;
+    }
+    bits = c->low / r;
+    c->low -= r * bits;
+    c->range = r;
+    return bits;
+}
+
 #endif /* AVCODEC_RANGECODER_H */
diff --git a/libavcodec/tests/rangecoder.c b/libavcodec/tests/rangecoder.c
index fd858535a5b..7634953585d 100644
--- a/libavcodec/tests/rangecoder.c
+++ b/libavcodec/tests/rangecoder.c
@@ -76,6 +76,11 @@ int main(void)
             for (i = 0; i < SIZE; i++)
                 put_rac(&c, state, r[i] & 1);
 
+            for (i = 0; i < SIZE; i++) {
+                int len = r[i++] % 7 + 1;
+                put_rac_raw(&c, r[i]&((1<<len) - 1), len);
+            }
+
             actual_length = ff_rac_terminate(&c, version);
 
             ff_init_range_decoder(&c, b, version ? SIZE : actual_length);
@@ -87,6 +92,14 @@ int main(void)
                     av_log(NULL, AV_LOG_ERROR, "rac failure at %d pass %d version %d\n", i, p, version);
                     return 1;
                 }
+            for (i = 0; i < SIZE; i++) {
+                int len = r[i++] % 7 + 1;
+                int mask = (1<<len) - 1;
+                if ((r[i] & mask) != get_rac_raw(&c, len)) {
+                    av_log(NULL, AV_LOG_ERROR, "rac raw failure at %d pass %d version %d\n", i, p, version);
+                    return 1;
+                }
+            }
 
             if (rac_check_termination(&c, version) < 0) {
                 av_log(NULL, AV_LOG_ERROR, "rac failure at termination pass %d version %d\n", p, version);
-- 
2.47.0



More information about the ffmpeg-devel mailing list