Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH v4 1/4] lavc: add standalone cached bitstream reader
@ 2022-10-22 10:32 Anton Khirnov
  2022-10-22 10:32 ` [FFmpeg-devel] [PATCH v4 2/4] lavc/bitstream: templatize for BE/LE Anton Khirnov
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Anton Khirnov @ 2022-10-22 10:32 UTC (permalink / raw)
  To: ffmpeg-devel

From: Alexandra Hájková <alexandra.khirnova@gmail.com>

The cached bitstream reader was originally written by Alexandra Hájková
for Libav, with significant input from Kostya Shishkov and Luca Barbato.
It was then committed to FFmpeg in ca079b09549, by merging it with the
implementation of the current bitstream reader.

This merge makes the code of get_bits.h significantly harder to read,
since it now contains two different bitstream readers interleaved with
 #ifdefs. Additionally, the code was committed without proper authorship
attribution.

This commit re-adds the cached bitstream reader as a standalone header,
as it was originally developed. It will be made useful in following
commits.

Integration by Anton Khirnov.

Signed-off-by: Anton Khirnov <anton@khirnov.net>
---
 libavcodec/bitstream.h | 529 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 529 insertions(+)
 create mode 100644 libavcodec/bitstream.h

diff --git a/libavcodec/bitstream.h b/libavcodec/bitstream.h
new file mode 100644
index 0000000000..6fd321dba5
--- /dev/null
+++ b/libavcodec/bitstream.h
@@ -0,0 +1,529 @@
+/*
+ * Copyright (c) 2016 Alexandra Hájková
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * bitstream reader API header.
+ */
+
+#ifndef AVCODEC_BITSTREAM_H
+#define AVCODEC_BITSTREAM_H
+
+#include <stdint.h>
+
+#include "config.h"
+
+#include "libavutil/avassert.h"
+#include "libavutil/common.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/log.h"
+
+#include "mathops.h"
+#include "vlc.h"
+
+#ifndef UNCHECKED_BITSTREAM_READER
+#define UNCHECKED_BITSTREAM_READER !CONFIG_SAFE_BITSTREAM_READER
+#endif
+
+typedef struct BitstreamContext {
+    uint64_t bits;       // stores bits read from the buffer
+    const uint8_t *buffer, *buffer_end;
+    const uint8_t *ptr;  // pointer to the position inside a buffer
+    unsigned bits_valid; // number of bits left in bits field
+    unsigned size_in_bits;
+} BitstreamContext;
+
+/**
+ * @return
+ * - 0 on successful refill
+ * - a negative number when bitstream end is hit
+ *
+ * Always succeeds when UNCHECKED_BITSTREAM_READER is enabled.
+ */
+static inline int bits_priv_refill_64(BitstreamContext *bc)
+{
+#if !UNCHECKED_BITSTREAM_READER
+    if (bc->ptr >= bc->buffer_end)
+        return -1;
+#endif
+
+#ifdef BITSTREAM_READER_LE
+    bc->bits       = AV_RL64(bc->ptr);
+#else
+    bc->bits       = AV_RB64(bc->ptr);
+#endif
+    bc->ptr       += 8;
+    bc->bits_valid = 64;
+
+    return 0;
+}
+
+/**
+ * @return
+ * - 0 on successful refill
+ * - a negative number when bitstream end is hit
+ *
+ * Always succeeds when UNCHECKED_BITSTREAM_READER is enabled.
+ */
+static inline int bits_priv_refill_32(BitstreamContext *bc)
+{
+#if !UNCHECKED_BITSTREAM_READER
+    if (bc->ptr >= bc->buffer_end)
+        return -1;
+#endif
+
+#ifdef BITSTREAM_READER_LE
+    bc->bits      |= (uint64_t)AV_RL32(bc->ptr) << bc->bits_valid;
+#else
+    bc->bits      |= (uint64_t)AV_RB32(bc->ptr) << (32 - bc->bits_valid);
+#endif
+    bc->ptr        += 4;
+    bc->bits_valid += 32;
+
+    return 0;
+}
+
+/**
+ * Initialize BitstreamContext.
+ * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes
+ *        larger than the actual read bits because some optimized bitstream
+ *        readers read 32 or 64 bits at once and could read over the end
+ * @param bit_size the size of the buffer in bits
+ * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow.
+ */
+static inline int bits_init(BitstreamContext *bc, const uint8_t *buffer,
+                            unsigned int bit_size)
+{
+    unsigned int buffer_size;
+
+    if (bit_size > INT_MAX - 7 || !buffer) {
+        bc->buffer     = NULL;
+        bc->ptr        = NULL;
+        bc->bits_valid = 0;
+        return AVERROR_INVALIDDATA;
+    }
+
+    buffer_size = (bit_size + 7) >> 3;
+
+    bc->buffer       = buffer;
+    bc->buffer_end   = buffer + buffer_size;
+    bc->ptr          = bc->buffer;
+    bc->size_in_bits = bit_size;
+    bc->bits_valid   = 0;
+    bc->bits         = 0;
+
+    bits_priv_refill_64(bc);
+
+    return 0;
+}
+
+/**
+ * Initialize BitstreamContext.
+ * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes
+ *        larger than the actual read bits because some optimized bitstream
+ *        readers read 32 or 64 bits at once and could read over the end
+ * @param byte_size the size of the buffer in bytes
+ * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow
+ */
+static inline int bits_init8(BitstreamContext *bc, const uint8_t *buffer,
+                             unsigned int byte_size)
+{
+    if (byte_size > INT_MAX / 8)
+        return AVERROR_INVALIDDATA;
+    return bits_init(bc, buffer, byte_size * 8);
+}
+
+/**
+ * Return number of bits already read.
+ */
+static inline int bits_tell(const BitstreamContext *bc)
+{
+    return (bc->ptr - bc->buffer) * 8 - bc->bits_valid;
+}
+
+/**
+ * Return buffer size in bits.
+ */
+static inline int bits_size(const BitstreamContext *bc)
+{
+    return bc->size_in_bits;
+}
+
+/**
+ * Return the number of the bits left in a buffer.
+ */
+static inline int bits_left(const BitstreamContext *bc)
+{
+    return (bc->buffer - bc->ptr) * 8 + bc->size_in_bits + bc->bits_valid;
+}
+
+static inline uint64_t bits_priv_val_show(BitstreamContext *bc, unsigned int n)
+{
+    av_assert2(n > 0 && n <= 64);
+
+#ifdef BITSTREAM_READER_LE
+    return bc->bits & (UINT64_MAX >> (64 - n));
+#else
+    return bc->bits >> (64 - n);
+#endif
+}
+
+static inline void bits_priv_skip_remaining(BitstreamContext *bc, unsigned int n)
+{
+#ifdef BITSTREAM_READER_LE
+    bc->bits >>= n;
+#else
+    bc->bits <<= n;
+#endif
+    bc->bits_valid -= n;
+}
+
+static inline uint64_t bits_priv_val_get(BitstreamContext *bc, unsigned int n)
+{
+    uint64_t ret;
+
+    av_assert2(n > 0 && n < 64);
+
+    ret = bits_priv_val_show(bc, n);
+    bits_priv_skip_remaining(bc, n);
+
+    return ret;
+}
+
+/**
+ * Return one bit from the buffer.
+ */
+static inline unsigned int bits_read_bit(BitstreamContext *bc)
+{
+    if (!bc->bits_valid && bits_priv_refill_64(bc) < 0)
+        return 0;
+
+    return bits_priv_val_get(bc, 1);
+}
+
+/**
+ * Return n bits from the buffer, n has to be in the 1-32 range.
+ * May be faster than bits_read() when n is not a compile-time constant and is
+ * known to be non-zero;
+ */
+static inline uint32_t bits_read_nz(BitstreamContext *bc, unsigned int n)
+{
+    av_assert2(n > 0 && n <= 32);
+
+    if (n > bc->bits_valid) {
+        if (bits_priv_refill_32(bc) < 0)
+            bc->bits_valid = n;
+    }
+
+    return bits_priv_val_get(bc, n);
+}
+
+/**
+ * Return n bits from the buffer, n has to be in the 0-32  range.
+ */
+static inline uint32_t bits_read(BitstreamContext *bc, unsigned int n)
+{
+    av_assert2(n <= 32);
+
+    if (!n)
+        return 0;
+
+    return bits_read_nz(bc, n);
+}
+
+/**
+ * Return n bits from the buffer, n has to be in the 0-63 range.
+ */
+static inline uint64_t bits_read_63(BitstreamContext *bc, unsigned int n)
+{
+    uint64_t ret = 0;
+    unsigned left = 0;
+
+    av_assert2(n <= 63);
+
+    if (!n)
+        return 0;
+
+    if (n > bc->bits_valid) {
+        left = bc->bits_valid;
+        n   -= left;
+
+        if (left)
+            ret = bits_priv_val_get(bc, left);
+
+        if (bits_priv_refill_64(bc) < 0)
+            bc->bits_valid = n;
+
+    }
+
+#ifdef BITSTREAM_READER_LE
+    ret = bits_priv_val_get(bc, n) << left | ret;
+#else
+    ret = bits_priv_val_get(bc, n) | ret << n;
+#endif
+
+    return ret;
+}
+
+/**
+ * Return n bits from the buffer, n has to be in the 0-64 range.
+ */
+static inline uint64_t bits_read_64(BitstreamContext *bc, unsigned int n)
+{
+    av_assert2(n <= 64);
+
+    if (n == 64) {
+        uint64_t ret = bits_read_63(bc, 63);
+#ifdef BITSTREAM_READER_LE
+        return ret | ((uint64_t)bits_read_bit(bc) << 63);
+#else
+        return (ret << 1) | (uint64_t)bits_read_bit(bc);
+#endif
+    }
+    return bits_read_63(bc, n);
+}
+
+/**
+ * Return n bits from the buffer as a signed integer.
+ * n has to be in the 0-32 range.
+ */
+static inline int32_t bits_read_signed(BitstreamContext *bc, unsigned int n)
+{
+    return sign_extend(bits_read(bc, n), n);
+}
+
+/**
+ * Return n bits from the buffer but do not change the buffer state.
+ * n has to be in the 1-32 range. May
+ */
+static inline uint32_t bits_peek_nz(BitstreamContext *bc, unsigned int n)
+{
+    av_assert2(n > 0 && n <= 32);
+
+    if (n > bc->bits_valid)
+        bits_priv_refill_32(bc);
+
+    return bits_priv_val_show(bc, n);
+}
+
+/**
+ * Return n bits from the buffer but do not change the buffer state.
+ * n has to be in the 0-32 range.
+ */
+static inline uint32_t bits_peek(BitstreamContext *bc, unsigned int n)
+{
+    av_assert2(n <= 32);
+
+    if (!n)
+        return 0;
+
+    return bits_peek_nz(bc, n);
+}
+
+/**
+ * Return n bits from the buffer as a signed integer,
+ * do not change the buffer state.
+ * n has to be in the 0-32 range.
+ */
+static inline int bits_peek_signed(BitstreamContext *bc, unsigned int n)
+{
+    return sign_extend(bits_peek(bc, n), n);
+}
+
+/**
+ * Skip n bits in the buffer.
+ */
+static inline void bits_skip(BitstreamContext *bc, unsigned int n)
+{
+    if (n < bc->bits_valid)
+        bits_priv_skip_remaining(bc, n);
+    else {
+        n -= bc->bits_valid;
+        bc->bits       = 0;
+        bc->bits_valid = 0;
+
+        if (n >= 64) {
+            unsigned int skip = n / 8;
+
+            n -= skip * 8;
+            bc->ptr += skip;
+        }
+        bits_priv_refill_64(bc);
+        if (n)
+            bits_priv_skip_remaining(bc, n);
+    }
+}
+
+/**
+ * Seek to the given bit position.
+ */
+static inline void bits_seek(BitstreamContext *bc, unsigned pos)
+{
+    bc->ptr        = bc->buffer;
+    bc->bits       = 0;
+    bc->bits_valid = 0;
+
+    bits_skip(bc, pos);
+}
+
+/**
+ * Skip bits to a byte boundary.
+ */
+static inline const uint8_t *bits_align(BitstreamContext *bc)
+{
+    unsigned int n = -bits_tell(bc) & 7;
+    if (n)
+        bits_skip(bc, n);
+    return bc->buffer + (bits_tell(bc) >> 3);
+}
+
+/**
+ * Read MPEG-1 dc-style VLC (sign bit + mantissa with no MSB).
+ * If MSB not set it is negative.
+ * @param n length in bits
+ */
+static inline int bits_read_xbits(BitstreamContext *bc, unsigned int n)
+{
+    int32_t cache = bits_peek(bc, 32);
+    int sign = ~cache >> 31;
+    bits_priv_skip_remaining(bc, n);
+
+    return ((((uint32_t)(sign ^ cache)) >> (32 - n)) ^ sign) - sign;
+}
+
+/**
+ * Return decoded truncated unary code for the values 0, 1, 2.
+ */
+static inline int bits_decode012(BitstreamContext *bc)
+{
+    if (!bits_read_bit(bc))
+        return 0;
+    else
+        return bits_read_bit(bc) + 1;
+}
+
+/**
+ * Return decoded truncated unary code for the values 2, 1, 0.
+ */
+static inline int bits_decode210(BitstreamContext *bc)
+{
+    if (bits_read_bit(bc))
+        return 0;
+    else
+        return 2 - bits_read_bit(bc);
+}
+
+/* Read sign bit and flip the sign of the provided value accordingly. */
+static inline int bits_apply_sign(BitstreamContext *bc, int val)
+{
+    int sign = bits_read_signed(bc, 1);
+    return (val ^ sign) - sign;
+}
+
+static inline int bits_skip_1stop_8data(BitstreamContext *s)
+{
+    if (bits_left(s) <= 0)
+        return AVERROR_INVALIDDATA;
+
+    while (bits_read_bit(s)) {
+        bits_skip(s, 8);
+        if (bits_left(s) <= 0)
+            return AVERROR_INVALIDDATA;
+    }
+
+    return 0;
+}
+
+/**
+ * Return the LUT element for the given bitstream configuration.
+ */
+static inline int bits_priv_set_idx(BitstreamContext *bc, int code, int *n, int *nb_bits,
+                                    const VLCElem *table)
+{
+    unsigned idx;
+
+    *nb_bits = -*n;
+    idx = bits_peek(bc, *nb_bits) + code;
+    *n = table[idx].len;
+
+    return table[idx].sym;
+}
+
+/**
+ * Parse a vlc code.
+ * @param bits is the number of bits which will be read at once, must be
+ *             identical to nb_bits in init_vlc()
+ * @param max_depth is the number of times bits bits must be read to completely
+ *                  read the longest vlc code
+ *                  = (max_vlc_length + bits - 1) / bits
+ * If the vlc code is invalid and max_depth=1, then no bits will be removed.
+ * If the vlc code is invalid and max_depth>1, then the number of bits removed
+ * is undefined.
+ */
+static inline int bits_read_vlc(BitstreamContext *bc, const VLCElem *table,
+                                int bits, int max_depth)
+{
+    int nb_bits;
+    unsigned idx = bits_peek(bc, bits);
+    int code     = table[idx].sym;
+    int n        = table[idx].len;
+
+    if (max_depth > 1 && n < 0) {
+        bits_priv_skip_remaining(bc, bits);
+        code = bits_priv_set_idx(bc, code, &n, &nb_bits, table);
+        if (max_depth > 2 && n < 0) {
+            bits_priv_skip_remaining(bc, nb_bits);
+            code = bits_priv_set_idx(bc, code, &n, &nb_bits, table);
+        }
+    }
+    bits_priv_skip_remaining(bc, n);
+
+    return code;
+}
+
+#define BITS_RL_VLC(level, run, bc, table, bits, max_depth) \
+    do {                                                    \
+        int n, nb_bits;                                     \
+        unsigned int index = bits_peek(bc, bits);           \
+        level = table[index].level;                         \
+        n     = table[index].len;                           \
+                                                            \
+        if (max_depth > 1 && n < 0) {                       \
+            bits_skip(bc, bits);                            \
+                                                            \
+            nb_bits = -n;                                   \
+                                                            \
+            index = bits_peek(bc, nb_bits) + level;         \
+            level = table[index].level;                     \
+            n     = table[index].len;                       \
+            if (max_depth > 2 && n < 0) {                   \
+                bits_skip(bc, nb_bits);                     \
+                nb_bits = -n;                               \
+                                                            \
+                index = bits_peek(bc, nb_bits) + level;     \
+                level = table[index].level;                 \
+                n     = table[index].len;                   \
+            }                                               \
+        }                                                   \
+        run = table[index].run;                             \
+        bits_skip(bc, n);                                   \
+    } while (0)
+
+#endif /* AVCODEC_BITSTREAM_H */
-- 
2.35.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [FFmpeg-devel] [PATCH v4 2/4] lavc/bitstream: templatize for BE/LE
  2022-10-22 10:32 [FFmpeg-devel] [PATCH v4 1/4] lavc: add standalone cached bitstream reader Anton Khirnov
@ 2022-10-22 10:32 ` Anton Khirnov
  2022-10-22 10:32 ` [FFmpeg-devel] [PATCH v4 3/4] lavc/tests: add a cached bitstream reader test Anton Khirnov
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Anton Khirnov @ 2022-10-22 10:32 UTC (permalink / raw)
  To: ffmpeg-devel

Allows using both BE and LE bitstream readers in the same file.
---
 libavcodec/Makefile                           |   1 +
 libavcodec/bitstream.h                        | 563 ++++--------------
 .../{bitstream.h => bitstream_template.h}     | 243 ++++----
 tests/ref/fate/source                         |   1 +
 4 files changed, 220 insertions(+), 588 deletions(-)
 copy libavcodec/{bitstream.h => bitstream_template.h} (54%)

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 8fa83c72b2..b77fe0db8e 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1238,6 +1238,7 @@ SKIPHEADERS                            += %_tablegen.h                  \
                                           aaccoder_trellis.h            \
                                           aacenc_quantization.h         \
                                           aacenc_quantization_misc.h    \
+                                          bitstream_template.h          \
                                           $(ARCH)/vpx_arith.h          \
 
 SKIPHEADERS-$(CONFIG_AMF)              += amfenc.h
diff --git a/libavcodec/bitstream.h b/libavcodec/bitstream.h
index 6fd321dba5..ef7d8d55c2 100644
--- a/libavcodec/bitstream.h
+++ b/libavcodec/bitstream.h
@@ -23,6 +23,21 @@
  * bitstream reader API header.
  */
 
+/*
+ * Bit order (endianness) is controlled by #defining BITSTREAM_BE and/or
+ * BITSTREAM_LE before #including this header. The corresponding bitreading
+ * functions are provided as bits_*_be()/bits_*_le() respectively.
+ *
+ * If neither or only BITSTREAM_BE is defined, then the default (unsuffixed)
+ * bits_*() will resolve to the big-endian implementation. If only BITSTREAM_LE
+ * is defined, little-endian will be the default.
+ *
+ * If both are defined, then the default can be controlled by defining at most
+ * one of BITSTREAM_DEFAULT_LE/BE. When BITSTREAM_DEFAULT_* is not defined, no
+ * default is provided and you must always explicitly use the _be() or _le()
+ * variants.
+ */
+
 #ifndef AVCODEC_BITSTREAM_H
 #define AVCODEC_BITSTREAM_H
 
@@ -42,461 +57,80 @@
 #define UNCHECKED_BITSTREAM_READER !CONFIG_SAFE_BITSTREAM_READER
 #endif
 
-typedef struct BitstreamContext {
-    uint64_t bits;       // stores bits read from the buffer
-    const uint8_t *buffer, *buffer_end;
-    const uint8_t *ptr;  // pointer to the position inside a buffer
-    unsigned bits_valid; // number of bits left in bits field
-    unsigned size_in_bits;
-} BitstreamContext;
-
-/**
- * @return
- * - 0 on successful refill
- * - a negative number when bitstream end is hit
- *
- * Always succeeds when UNCHECKED_BITSTREAM_READER is enabled.
- */
-static inline int bits_priv_refill_64(BitstreamContext *bc)
-{
-#if !UNCHECKED_BITSTREAM_READER
-    if (bc->ptr >= bc->buffer_end)
-        return -1;
-#endif
-
-#ifdef BITSTREAM_READER_LE
-    bc->bits       = AV_RL64(bc->ptr);
-#else
-    bc->bits       = AV_RB64(bc->ptr);
-#endif
-    bc->ptr       += 8;
-    bc->bits_valid = 64;
-
-    return 0;
-}
-
-/**
- * @return
- * - 0 on successful refill
- * - a negative number when bitstream end is hit
- *
- * Always succeeds when UNCHECKED_BITSTREAM_READER is enabled.
- */
-static inline int bits_priv_refill_32(BitstreamContext *bc)
-{
-#if !UNCHECKED_BITSTREAM_READER
-    if (bc->ptr >= bc->buffer_end)
-        return -1;
-#endif
-
-#ifdef BITSTREAM_READER_LE
-    bc->bits      |= (uint64_t)AV_RL32(bc->ptr) << bc->bits_valid;
-#else
-    bc->bits      |= (uint64_t)AV_RB32(bc->ptr) << (32 - bc->bits_valid);
-#endif
-    bc->ptr        += 4;
-    bc->bits_valid += 32;
-
-    return 0;
-}
-
-/**
- * Initialize BitstreamContext.
- * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes
- *        larger than the actual read bits because some optimized bitstream
- *        readers read 32 or 64 bits at once and could read over the end
- * @param bit_size the size of the buffer in bits
- * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow.
- */
-static inline int bits_init(BitstreamContext *bc, const uint8_t *buffer,
-                            unsigned int bit_size)
-{
-    unsigned int buffer_size;
-
-    if (bit_size > INT_MAX - 7 || !buffer) {
-        bc->buffer     = NULL;
-        bc->ptr        = NULL;
-        bc->bits_valid = 0;
-        return AVERROR_INVALIDDATA;
-    }
-
-    buffer_size = (bit_size + 7) >> 3;
-
-    bc->buffer       = buffer;
-    bc->buffer_end   = buffer + buffer_size;
-    bc->ptr          = bc->buffer;
-    bc->size_in_bits = bit_size;
-    bc->bits_valid   = 0;
-    bc->bits         = 0;
-
-    bits_priv_refill_64(bc);
-
-    return 0;
-}
-
-/**
- * Initialize BitstreamContext.
- * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes
- *        larger than the actual read bits because some optimized bitstream
- *        readers read 32 or 64 bits at once and could read over the end
- * @param byte_size the size of the buffer in bytes
- * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow
- */
-static inline int bits_init8(BitstreamContext *bc, const uint8_t *buffer,
-                             unsigned int byte_size)
-{
-    if (byte_size > INT_MAX / 8)
-        return AVERROR_INVALIDDATA;
-    return bits_init(bc, buffer, byte_size * 8);
-}
-
-/**
- * Return number of bits already read.
- */
-static inline int bits_tell(const BitstreamContext *bc)
-{
-    return (bc->ptr - bc->buffer) * 8 - bc->bits_valid;
-}
-
-/**
- * Return buffer size in bits.
- */
-static inline int bits_size(const BitstreamContext *bc)
-{
-    return bc->size_in_bits;
-}
-
-/**
- * Return the number of the bits left in a buffer.
- */
-static inline int bits_left(const BitstreamContext *bc)
-{
-    return (bc->buffer - bc->ptr) * 8 + bc->size_in_bits + bc->bits_valid;
-}
-
-static inline uint64_t bits_priv_val_show(BitstreamContext *bc, unsigned int n)
-{
-    av_assert2(n > 0 && n <= 64);
-
-#ifdef BITSTREAM_READER_LE
-    return bc->bits & (UINT64_MAX >> (64 - n));
-#else
-    return bc->bits >> (64 - n);
-#endif
-}
-
-static inline void bits_priv_skip_remaining(BitstreamContext *bc, unsigned int n)
-{
-#ifdef BITSTREAM_READER_LE
-    bc->bits >>= n;
-#else
-    bc->bits <<= n;
-#endif
-    bc->bits_valid -= n;
-}
-
-static inline uint64_t bits_priv_val_get(BitstreamContext *bc, unsigned int n)
-{
-    uint64_t ret;
-
-    av_assert2(n > 0 && n < 64);
-
-    ret = bits_priv_val_show(bc, n);
-    bits_priv_skip_remaining(bc, n);
-
-    return ret;
-}
-
-/**
- * Return one bit from the buffer.
- */
-static inline unsigned int bits_read_bit(BitstreamContext *bc)
-{
-    if (!bc->bits_valid && bits_priv_refill_64(bc) < 0)
-        return 0;
-
-    return bits_priv_val_get(bc, 1);
-}
-
-/**
- * Return n bits from the buffer, n has to be in the 1-32 range.
- * May be faster than bits_read() when n is not a compile-time constant and is
- * known to be non-zero;
- */
-static inline uint32_t bits_read_nz(BitstreamContext *bc, unsigned int n)
-{
-    av_assert2(n > 0 && n <= 32);
-
-    if (n > bc->bits_valid) {
-        if (bits_priv_refill_32(bc) < 0)
-            bc->bits_valid = n;
-    }
-
-    return bits_priv_val_get(bc, n);
-}
-
-/**
- * Return n bits from the buffer, n has to be in the 0-32  range.
- */
-static inline uint32_t bits_read(BitstreamContext *bc, unsigned int n)
-{
-    av_assert2(n <= 32);
-
-    if (!n)
-        return 0;
-
-    return bits_read_nz(bc, n);
-}
-
-/**
- * Return n bits from the buffer, n has to be in the 0-63 range.
- */
-static inline uint64_t bits_read_63(BitstreamContext *bc, unsigned int n)
-{
-    uint64_t ret = 0;
-    unsigned left = 0;
-
-    av_assert2(n <= 63);
-
-    if (!n)
-        return 0;
-
-    if (n > bc->bits_valid) {
-        left = bc->bits_valid;
-        n   -= left;
-
-        if (left)
-            ret = bits_priv_val_get(bc, left);
-
-        if (bits_priv_refill_64(bc) < 0)
-            bc->bits_valid = n;
-
-    }
-
-#ifdef BITSTREAM_READER_LE
-    ret = bits_priv_val_get(bc, n) << left | ret;
-#else
-    ret = bits_priv_val_get(bc, n) | ret << n;
+// select the default endianness, if any
+#if defined(BITSTREAM_LE) && defined(BITSTREAM_BE)
+
+# if defined(BITSTREAM_DEFAULT_BE) && defined(BITSTREAM_DEFAULT_LE)
+#  error "At most one of BITSTREAM_DEFAULT_BE/LE must be defined"
+# elif   defined(BITSTREAM_DEFAULT_BE)
+#  define BITS_DEFAULT_BE
+# elif   defined(BITSTREAM_DEFAULT_LE)
+#  define BITS_DEFAULT_LE
+# endif
+
+#elif defined(BITSTREAM_LE)
+# define BITS_DEFAULT_LE
+#else // select BE if nothing is requested explicitly
+# define BITS_DEFAULT_BE
+# define BITSTREAM_WANT_BE
 #endif
 
-    return ret;
-}
+#if defined(BITS_DEFAULT_LE)
+
+# define BitstreamContext   BitstreamContextLE
+# define bits_init          bits_init_le
+# define bits_init8         bits_init8_le
+# define bits_tell          bits_tell_le
+# define bits_size          bits_size_le
+# define bits_left          bits_left_le
+# define bits_read_bit      bits_read_bit_le
+# define bits_read_nz       bits_read_nz_le
+# define bits_read          bits_read_le
+# define bits_read_63       bits_read_63_le
+# define bits_read_64       bits_read_64_le
+# define bits_read_signed   bits_read_signed_le
+# define bits_peek_nz       bits_peek_nz_le
+# define bits_peek          bits_peek_le
+# define bits_peek_signed   bits_peek_signed_le
+# define bits_skip          bits_skip_le
+# define bits_seek          bits_seek_le
+# define bits_align         bits_align_le
+# define bits_read_xbits    bits_read_xbits_le
+# define bits_decode012     bits_decode012_le
+# define bits_decode210     bits_decode210_le
+# define bits_apply_sign    bits_apply_sign_le
+# define bits_read_vlc      bits_read_vlc_le
+
+#elif defined(BITS_DEFAULT_BE)
+
+# define BitstreamContext   BitstreamContextBE
+# define bits_init          bits_init_be
+# define bits_init8         bits_init8_be
+# define bits_tell          bits_tell_be
+# define bits_size          bits_size_be
+# define bits_left          bits_left_be
+# define bits_read_bit      bits_read_bit_be
+# define bits_read_nz       bits_read_nz_be
+# define bits_read          bits_read_be
+# define bits_read_63       bits_read_63_be
+# define bits_read_64       bits_read_64_be
+# define bits_read_signed   bits_read_signed_be
+# define bits_peek_nz       bits_peek_nz_be
+# define bits_peek          bits_peek_be
+# define bits_peek_signed   bits_peek_signed_be
+# define bits_skip          bits_skip_be
+# define bits_seek          bits_seek_be
+# define bits_align         bits_align_be
+# define bits_read_xbits    bits_read_xbits_be
+# define bits_decode012     bits_decode012_be
+# define bits_decode210     bits_decode210_be
+# define bits_apply_sign    bits_apply_sign_be
+# define bits_read_vlc      bits_read_vlc_be
 
-/**
- * Return n bits from the buffer, n has to be in the 0-64 range.
- */
-static inline uint64_t bits_read_64(BitstreamContext *bc, unsigned int n)
-{
-    av_assert2(n <= 64);
-
-    if (n == 64) {
-        uint64_t ret = bits_read_63(bc, 63);
-#ifdef BITSTREAM_READER_LE
-        return ret | ((uint64_t)bits_read_bit(bc) << 63);
-#else
-        return (ret << 1) | (uint64_t)bits_read_bit(bc);
 #endif
-    }
-    return bits_read_63(bc, n);
-}
-
-/**
- * Return n bits from the buffer as a signed integer.
- * n has to be in the 0-32 range.
- */
-static inline int32_t bits_read_signed(BitstreamContext *bc, unsigned int n)
-{
-    return sign_extend(bits_read(bc, n), n);
-}
-
-/**
- * Return n bits from the buffer but do not change the buffer state.
- * n has to be in the 1-32 range. May
- */
-static inline uint32_t bits_peek_nz(BitstreamContext *bc, unsigned int n)
-{
-    av_assert2(n > 0 && n <= 32);
-
-    if (n > bc->bits_valid)
-        bits_priv_refill_32(bc);
-
-    return bits_priv_val_show(bc, n);
-}
-
-/**
- * Return n bits from the buffer but do not change the buffer state.
- * n has to be in the 0-32 range.
- */
-static inline uint32_t bits_peek(BitstreamContext *bc, unsigned int n)
-{
-    av_assert2(n <= 32);
-
-    if (!n)
-        return 0;
 
-    return bits_peek_nz(bc, n);
-}
-
-/**
- * Return n bits from the buffer as a signed integer,
- * do not change the buffer state.
- * n has to be in the 0-32 range.
- */
-static inline int bits_peek_signed(BitstreamContext *bc, unsigned int n)
-{
-    return sign_extend(bits_peek(bc, n), n);
-}
-
-/**
- * Skip n bits in the buffer.
- */
-static inline void bits_skip(BitstreamContext *bc, unsigned int n)
-{
-    if (n < bc->bits_valid)
-        bits_priv_skip_remaining(bc, n);
-    else {
-        n -= bc->bits_valid;
-        bc->bits       = 0;
-        bc->bits_valid = 0;
-
-        if (n >= 64) {
-            unsigned int skip = n / 8;
-
-            n -= skip * 8;
-            bc->ptr += skip;
-        }
-        bits_priv_refill_64(bc);
-        if (n)
-            bits_priv_skip_remaining(bc, n);
-    }
-}
-
-/**
- * Seek to the given bit position.
- */
-static inline void bits_seek(BitstreamContext *bc, unsigned pos)
-{
-    bc->ptr        = bc->buffer;
-    bc->bits       = 0;
-    bc->bits_valid = 0;
-
-    bits_skip(bc, pos);
-}
-
-/**
- * Skip bits to a byte boundary.
- */
-static inline const uint8_t *bits_align(BitstreamContext *bc)
-{
-    unsigned int n = -bits_tell(bc) & 7;
-    if (n)
-        bits_skip(bc, n);
-    return bc->buffer + (bits_tell(bc) >> 3);
-}
-
-/**
- * Read MPEG-1 dc-style VLC (sign bit + mantissa with no MSB).
- * If MSB not set it is negative.
- * @param n length in bits
- */
-static inline int bits_read_xbits(BitstreamContext *bc, unsigned int n)
-{
-    int32_t cache = bits_peek(bc, 32);
-    int sign = ~cache >> 31;
-    bits_priv_skip_remaining(bc, n);
-
-    return ((((uint32_t)(sign ^ cache)) >> (32 - n)) ^ sign) - sign;
-}
-
-/**
- * Return decoded truncated unary code for the values 0, 1, 2.
- */
-static inline int bits_decode012(BitstreamContext *bc)
-{
-    if (!bits_read_bit(bc))
-        return 0;
-    else
-        return bits_read_bit(bc) + 1;
-}
-
-/**
- * Return decoded truncated unary code for the values 2, 1, 0.
- */
-static inline int bits_decode210(BitstreamContext *bc)
-{
-    if (bits_read_bit(bc))
-        return 0;
-    else
-        return 2 - bits_read_bit(bc);
-}
-
-/* Read sign bit and flip the sign of the provided value accordingly. */
-static inline int bits_apply_sign(BitstreamContext *bc, int val)
-{
-    int sign = bits_read_signed(bc, 1);
-    return (val ^ sign) - sign;
-}
-
-static inline int bits_skip_1stop_8data(BitstreamContext *s)
-{
-    if (bits_left(s) <= 0)
-        return AVERROR_INVALIDDATA;
-
-    while (bits_read_bit(s)) {
-        bits_skip(s, 8);
-        if (bits_left(s) <= 0)
-            return AVERROR_INVALIDDATA;
-    }
-
-    return 0;
-}
-
-/**
- * Return the LUT element for the given bitstream configuration.
- */
-static inline int bits_priv_set_idx(BitstreamContext *bc, int code, int *n, int *nb_bits,
-                                    const VLCElem *table)
-{
-    unsigned idx;
-
-    *nb_bits = -*n;
-    idx = bits_peek(bc, *nb_bits) + code;
-    *n = table[idx].len;
-
-    return table[idx].sym;
-}
-
-/**
- * Parse a vlc code.
- * @param bits is the number of bits which will be read at once, must be
- *             identical to nb_bits in init_vlc()
- * @param max_depth is the number of times bits bits must be read to completely
- *                  read the longest vlc code
- *                  = (max_vlc_length + bits - 1) / bits
- * If the vlc code is invalid and max_depth=1, then no bits will be removed.
- * If the vlc code is invalid and max_depth>1, then the number of bits removed
- * is undefined.
- */
-static inline int bits_read_vlc(BitstreamContext *bc, const VLCElem *table,
-                                int bits, int max_depth)
-{
-    int nb_bits;
-    unsigned idx = bits_peek(bc, bits);
-    int code     = table[idx].sym;
-    int n        = table[idx].len;
-
-    if (max_depth > 1 && n < 0) {
-        bits_priv_skip_remaining(bc, bits);
-        code = bits_priv_set_idx(bc, code, &n, &nb_bits, table);
-        if (max_depth > 2 && n < 0) {
-            bits_priv_skip_remaining(bc, nb_bits);
-            code = bits_priv_set_idx(bc, code, &n, &nb_bits, table);
-        }
-    }
-    bits_priv_skip_remaining(bc, n);
-
-    return code;
-}
+#undef BITS_DEFAULT_LE
+#undef BITS_DEFAULT_BE
 
 #define BITS_RL_VLC(level, run, bc, table, bits, max_depth) \
     do {                                                    \
@@ -527,3 +161,32 @@ static inline int bits_read_vlc(BitstreamContext *bc, const VLCElem *table,
     } while (0)
 
 #endif /* AVCODEC_BITSTREAM_H */
+
+// the following is deliberately outside of the standard #include guards
+
+#if  defined(BITSTREAM_LE) && !defined(BITSTREAM_WANT_LE)
+# define BITSTREAM_WANT_LE
+#endif
+
+#if defined(BITSTREAM_BE) && !defined(BITSTREAM_WANT_BE)
+# define BITSTREAM_WANT_BE
+#endif
+
+#if defined(BITSTREAM_WANT_LE) && !defined(AVCODEC_BITSTREAM_LE)
+#define AVCODEC_BITSTREAM_LE
+
+#define BITSTREAM_TEMPLATE_LE
+#include "bitstream_template.h"
+#undef BITSTREAM_TEMPLATE_LE
+
+#endif
+
+#if defined(BITSTREAM_WANT_BE) && !defined(AVCODEC_BITSTREAM_BE)
+#define AVCODEC_BITSTREAM_BE
+
+#include "bitstream_template.h"
+
+#endif
+
+#undef BITSTREAM_WANT_LE
+#undef BITSTREAM_WANT_BE
diff --git a/libavcodec/bitstream.h b/libavcodec/bitstream_template.h
similarity index 54%
copy from libavcodec/bitstream.h
copy to libavcodec/bitstream_template.h
index 6fd321dba5..f2c14fc4d3 100644
--- a/libavcodec/bitstream.h
+++ b/libavcodec/bitstream_template.h
@@ -18,37 +18,27 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-/**
- * @file
- * bitstream reader API header.
- */
-
-#ifndef AVCODEC_BITSTREAM_H
-#define AVCODEC_BITSTREAM_H
-
-#include <stdint.h>
-
-#include "config.h"
-
-#include "libavutil/avassert.h"
-#include "libavutil/common.h"
-#include "libavutil/intreadwrite.h"
-#include "libavutil/log.h"
+#ifdef BITSTREAM_TEMPLATE_LE
+#   define BS_SUFFIX_LOWER _le
+#   define BS_SUFFIX_UPPER LE
+#else
+#   define BS_SUFFIX_LOWER _be
+#   define BS_SUFFIX_UPPER BE
+#endif
 
-#include "mathops.h"
-#include "vlc.h"
+#define BS_JOIN(x, y, z) x ## y ## z
+#define BS_JOIN3(x, y, z) BS_JOIN(x, y, z)
+#define BS_FUNC(x) BS_JOIN3(bits_, x, BS_SUFFIX_LOWER)
 
-#ifndef UNCHECKED_BITSTREAM_READER
-#define UNCHECKED_BITSTREAM_READER !CONFIG_SAFE_BITSTREAM_READER
-#endif
+#define BSCTX BS_JOIN3(Bitstream, Context, BS_SUFFIX_UPPER)
 
-typedef struct BitstreamContext {
+typedef struct BSCTX {
     uint64_t bits;       // stores bits read from the buffer
     const uint8_t *buffer, *buffer_end;
     const uint8_t *ptr;  // pointer to the position inside a buffer
     unsigned bits_valid; // number of bits left in bits field
     unsigned size_in_bits;
-} BitstreamContext;
+} BSCTX;
 
 /**
  * @return
@@ -57,14 +47,14 @@ typedef struct BitstreamContext {
  *
  * Always succeeds when UNCHECKED_BITSTREAM_READER is enabled.
  */
-static inline int bits_priv_refill_64(BitstreamContext *bc)
+static inline int BS_FUNC(priv_refill_64)(BSCTX *bc)
 {
 #if !UNCHECKED_BITSTREAM_READER
     if (bc->ptr >= bc->buffer_end)
         return -1;
 #endif
 
-#ifdef BITSTREAM_READER_LE
+#ifdef BITSTREAM_TEMPLATE_LE
     bc->bits       = AV_RL64(bc->ptr);
 #else
     bc->bits       = AV_RB64(bc->ptr);
@@ -82,14 +72,14 @@ static inline int bits_priv_refill_64(BitstreamContext *bc)
  *
  * Always succeeds when UNCHECKED_BITSTREAM_READER is enabled.
  */
-static inline int bits_priv_refill_32(BitstreamContext *bc)
+static inline int BS_FUNC(priv_refill_32)(BSCTX *bc)
 {
 #if !UNCHECKED_BITSTREAM_READER
     if (bc->ptr >= bc->buffer_end)
         return -1;
 #endif
 
-#ifdef BITSTREAM_READER_LE
+#ifdef BITSTREAM_TEMPLATE_LE
     bc->bits      |= (uint64_t)AV_RL32(bc->ptr) << bc->bits_valid;
 #else
     bc->bits      |= (uint64_t)AV_RB32(bc->ptr) << (32 - bc->bits_valid);
@@ -108,8 +98,8 @@ static inline int bits_priv_refill_32(BitstreamContext *bc)
  * @param bit_size the size of the buffer in bits
  * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow.
  */
-static inline int bits_init(BitstreamContext *bc, const uint8_t *buffer,
-                            unsigned int bit_size)
+static inline int BS_FUNC(init)(BSCTX *bc, const uint8_t *buffer,
+                                     unsigned int bit_size)
 {
     unsigned int buffer_size;
 
@@ -129,7 +119,7 @@ static inline int bits_init(BitstreamContext *bc, const uint8_t *buffer,
     bc->bits_valid   = 0;
     bc->bits         = 0;
 
-    bits_priv_refill_64(bc);
+    BS_FUNC(priv_refill_64)(bc);
 
     return 0;
 }
@@ -142,18 +132,18 @@ static inline int bits_init(BitstreamContext *bc, const uint8_t *buffer,
  * @param byte_size the size of the buffer in bytes
  * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow
  */
-static inline int bits_init8(BitstreamContext *bc, const uint8_t *buffer,
-                             unsigned int byte_size)
+static inline int BS_FUNC(init8)(BSCTX *bc, const uint8_t *buffer,
+                                      unsigned int byte_size)
 {
     if (byte_size > INT_MAX / 8)
         return AVERROR_INVALIDDATA;
-    return bits_init(bc, buffer, byte_size * 8);
+    return BS_FUNC(init)(bc, buffer, byte_size * 8);
 }
 
 /**
  * Return number of bits already read.
  */
-static inline int bits_tell(const BitstreamContext *bc)
+static inline int BS_FUNC(tell)(const BSCTX *bc)
 {
     return (bc->ptr - bc->buffer) * 8 - bc->bits_valid;
 }
@@ -161,7 +151,7 @@ static inline int bits_tell(const BitstreamContext *bc)
 /**
  * Return buffer size in bits.
  */
-static inline int bits_size(const BitstreamContext *bc)
+static inline int BS_FUNC(size)(const BSCTX *bc)
 {
     return bc->size_in_bits;
 }
@@ -169,25 +159,25 @@ static inline int bits_size(const BitstreamContext *bc)
 /**
  * Return the number of the bits left in a buffer.
  */
-static inline int bits_left(const BitstreamContext *bc)
+static inline int BS_FUNC(left)(const BSCTX *bc)
 {
     return (bc->buffer - bc->ptr) * 8 + bc->size_in_bits + bc->bits_valid;
 }
 
-static inline uint64_t bits_priv_val_show(BitstreamContext *bc, unsigned int n)
+static inline uint64_t BS_FUNC(priv_val_show)(BSCTX *bc, unsigned int n)
 {
     av_assert2(n > 0 && n <= 64);
 
-#ifdef BITSTREAM_READER_LE
+#ifdef BITSTREAM_TEMPLATE_LE
     return bc->bits & (UINT64_MAX >> (64 - n));
 #else
     return bc->bits >> (64 - n);
 #endif
 }
 
-static inline void bits_priv_skip_remaining(BitstreamContext *bc, unsigned int n)
+static inline void BS_FUNC(priv_skip_remaining)(BSCTX *bc, unsigned int n)
 {
-#ifdef BITSTREAM_READER_LE
+#ifdef BITSTREAM_TEMPLATE_LE
     bc->bits >>= n;
 #else
     bc->bits <<= n;
@@ -195,14 +185,14 @@ static inline void bits_priv_skip_remaining(BitstreamContext *bc, unsigned int n
     bc->bits_valid -= n;
 }
 
-static inline uint64_t bits_priv_val_get(BitstreamContext *bc, unsigned int n)
+static inline uint64_t BS_FUNC(priv_val_get)(BSCTX *bc, unsigned int n)
 {
     uint64_t ret;
 
     av_assert2(n > 0 && n < 64);
 
-    ret = bits_priv_val_show(bc, n);
-    bits_priv_skip_remaining(bc, n);
+    ret = BS_FUNC(priv_val_show)(bc, n);
+    BS_FUNC(priv_skip_remaining)(bc, n);
 
     return ret;
 }
@@ -210,12 +200,12 @@ static inline uint64_t bits_priv_val_get(BitstreamContext *bc, unsigned int n)
 /**
  * Return one bit from the buffer.
  */
-static inline unsigned int bits_read_bit(BitstreamContext *bc)
+static inline unsigned int BS_FUNC(read_bit)(BSCTX *bc)
 {
-    if (!bc->bits_valid && bits_priv_refill_64(bc) < 0)
+    if (!bc->bits_valid && BS_FUNC(priv_refill_64)(bc) < 0)
         return 0;
 
-    return bits_priv_val_get(bc, 1);
+    return BS_FUNC(priv_val_get)(bc, 1);
 }
 
 /**
@@ -223,35 +213,35 @@ static inline unsigned int bits_read_bit(BitstreamContext *bc)
  * May be faster than bits_read() when n is not a compile-time constant and is
  * known to be non-zero;
  */
-static inline uint32_t bits_read_nz(BitstreamContext *bc, unsigned int n)
+static inline uint32_t BS_FUNC(read_nz)(BSCTX *bc, unsigned int n)
 {
     av_assert2(n > 0 && n <= 32);
 
     if (n > bc->bits_valid) {
-        if (bits_priv_refill_32(bc) < 0)
+        if (BS_FUNC(priv_refill_32)(bc) < 0)
             bc->bits_valid = n;
     }
 
-    return bits_priv_val_get(bc, n);
+    return BS_FUNC(priv_val_get)(bc, n);
 }
 
 /**
  * Return n bits from the buffer, n has to be in the 0-32  range.
  */
-static inline uint32_t bits_read(BitstreamContext *bc, unsigned int n)
+static inline uint32_t BS_FUNC(read)(BSCTX *bc, unsigned int n)
 {
     av_assert2(n <= 32);
 
     if (!n)
         return 0;
 
-    return bits_read_nz(bc, n);
+    return BS_FUNC(read_nz)(bc, n);
 }
 
 /**
  * Return n bits from the buffer, n has to be in the 0-63 range.
  */
-static inline uint64_t bits_read_63(BitstreamContext *bc, unsigned int n)
+static inline uint64_t BS_FUNC(read_63)(BSCTX *bc, unsigned int n)
 {
     uint64_t ret = 0;
     unsigned left = 0;
@@ -266,17 +256,17 @@ static inline uint64_t bits_read_63(BitstreamContext *bc, unsigned int n)
         n   -= left;
 
         if (left)
-            ret = bits_priv_val_get(bc, left);
+            ret = BS_FUNC(priv_val_get)(bc, left);
 
-        if (bits_priv_refill_64(bc) < 0)
+        if (BS_FUNC(priv_refill_64)(bc) < 0)
             bc->bits_valid = n;
 
     }
 
-#ifdef BITSTREAM_READER_LE
-    ret = bits_priv_val_get(bc, n) << left | ret;
+#ifdef BITSTREAM_TEMPLATE_LE
+    ret = BS_FUNC(priv_val_get)(bc, n) << left | ret;
 #else
-    ret = bits_priv_val_get(bc, n) | ret << n;
+    ret = BS_FUNC(priv_val_get)(bc, n) | ret << n;
 #endif
 
     return ret;
@@ -285,56 +275,56 @@ static inline uint64_t bits_read_63(BitstreamContext *bc, unsigned int n)
 /**
  * Return n bits from the buffer, n has to be in the 0-64 range.
  */
-static inline uint64_t bits_read_64(BitstreamContext *bc, unsigned int n)
+static inline uint64_t BS_FUNC(read_64)(BSCTX *bc, unsigned int n)
 {
     av_assert2(n <= 64);
 
     if (n == 64) {
-        uint64_t ret = bits_read_63(bc, 63);
-#ifdef BITSTREAM_READER_LE
-        return ret | ((uint64_t)bits_read_bit(bc) << 63);
+        uint64_t ret = BS_FUNC(read_63)(bc, 63);
+#ifdef BITSTREAM_TEMPLATE_LE
+        return ret | ((uint64_t)BS_FUNC(read_bit)(bc) << 63);
 #else
-        return (ret << 1) | (uint64_t)bits_read_bit(bc);
+        return (ret << 1) | (uint64_t)BS_FUNC(read_bit)(bc);
 #endif
     }
-    return bits_read_63(bc, n);
+    return BS_FUNC(read_63)(bc, n);
 }
 
 /**
  * Return n bits from the buffer as a signed integer.
  * n has to be in the 0-32 range.
  */
-static inline int32_t bits_read_signed(BitstreamContext *bc, unsigned int n)
+static inline int32_t BS_FUNC(read_signed)(BSCTX *bc, unsigned int n)
 {
-    return sign_extend(bits_read(bc, n), n);
+    return sign_extend(BS_FUNC(read)(bc, n), n);
 }
 
 /**
  * Return n bits from the buffer but do not change the buffer state.
  * n has to be in the 1-32 range. May
  */
-static inline uint32_t bits_peek_nz(BitstreamContext *bc, unsigned int n)
+static inline uint32_t BS_FUNC(peek_nz)(BSCTX *bc, unsigned int n)
 {
     av_assert2(n > 0 && n <= 32);
 
     if (n > bc->bits_valid)
-        bits_priv_refill_32(bc);
+        BS_FUNC(priv_refill_32)(bc);
 
-    return bits_priv_val_show(bc, n);
+    return BS_FUNC(priv_val_show)(bc, n);
 }
 
 /**
  * Return n bits from the buffer but do not change the buffer state.
  * n has to be in the 0-32 range.
  */
-static inline uint32_t bits_peek(BitstreamContext *bc, unsigned int n)
+static inline uint32_t BS_FUNC(peek)(BSCTX *bc, unsigned int n)
 {
     av_assert2(n <= 32);
 
     if (!n)
         return 0;
 
-    return bits_peek_nz(bc, n);
+    return BS_FUNC(peek_nz)(bc, n);
 }
 
 /**
@@ -342,18 +332,18 @@ static inline uint32_t bits_peek(BitstreamContext *bc, unsigned int n)
  * do not change the buffer state.
  * n has to be in the 0-32 range.
  */
-static inline int bits_peek_signed(BitstreamContext *bc, unsigned int n)
+static inline int BS_FUNC(peek_signed)(BSCTX *bc, unsigned int n)
 {
-    return sign_extend(bits_peek(bc, n), n);
+    return sign_extend(BS_FUNC(peek)(bc, n), n);
 }
 
 /**
  * Skip n bits in the buffer.
  */
-static inline void bits_skip(BitstreamContext *bc, unsigned int n)
+static inline void BS_FUNC(skip)(BSCTX *bc, unsigned int n)
 {
     if (n < bc->bits_valid)
-        bits_priv_skip_remaining(bc, n);
+        BS_FUNC(priv_skip_remaining)(bc, n);
     else {
         n -= bc->bits_valid;
         bc->bits       = 0;
@@ -365,33 +355,33 @@ static inline void bits_skip(BitstreamContext *bc, unsigned int n)
             n -= skip * 8;
             bc->ptr += skip;
         }
-        bits_priv_refill_64(bc);
+        BS_FUNC(priv_refill_64)(bc);
         if (n)
-            bits_priv_skip_remaining(bc, n);
+            BS_FUNC(priv_skip_remaining)(bc, n);
     }
 }
 
 /**
  * Seek to the given bit position.
  */
-static inline void bits_seek(BitstreamContext *bc, unsigned pos)
+static inline void BS_FUNC(seek)(BSCTX *bc, unsigned pos)
 {
     bc->ptr        = bc->buffer;
     bc->bits       = 0;
     bc->bits_valid = 0;
 
-    bits_skip(bc, pos);
+    BS_FUNC(skip)(bc, pos);
 }
 
 /**
  * Skip bits to a byte boundary.
  */
-static inline const uint8_t *bits_align(BitstreamContext *bc)
+static inline const uint8_t *BS_FUNC(align)(BSCTX *bc)
 {
-    unsigned int n = -bits_tell(bc) & 7;
+    unsigned int n = -BS_FUNC(tell)(bc) & 7;
     if (n)
-        bits_skip(bc, n);
-    return bc->buffer + (bits_tell(bc) >> 3);
+        BS_FUNC(skip)(bc, n);
+    return bc->buffer + (BS_FUNC(tell)(bc) >> 3);
 }
 
 /**
@@ -399,11 +389,11 @@ static inline const uint8_t *bits_align(BitstreamContext *bc)
  * If MSB not set it is negative.
  * @param n length in bits
  */
-static inline int bits_read_xbits(BitstreamContext *bc, unsigned int n)
+static inline int BS_FUNC(read_xbits)(BSCTX *bc, unsigned int n)
 {
-    int32_t cache = bits_peek(bc, 32);
+    int32_t cache = BS_FUNC(peek)(bc, 32);
     int sign = ~cache >> 31;
-    bits_priv_skip_remaining(bc, n);
+    BS_FUNC(priv_skip_remaining)(bc, n);
 
     return ((((uint32_t)(sign ^ cache)) >> (32 - n)) ^ sign) - sign;
 }
@@ -411,40 +401,40 @@ static inline int bits_read_xbits(BitstreamContext *bc, unsigned int n)
 /**
  * Return decoded truncated unary code for the values 0, 1, 2.
  */
-static inline int bits_decode012(BitstreamContext *bc)
+static inline int BS_FUNC(decode012)(BSCTX *bc)
 {
-    if (!bits_read_bit(bc))
+    if (!BS_FUNC(read_bit)(bc))
         return 0;
     else
-        return bits_read_bit(bc) + 1;
+        return BS_FUNC(read_bit)(bc) + 1;
 }
 
 /**
  * Return decoded truncated unary code for the values 2, 1, 0.
  */
-static inline int bits_decode210(BitstreamContext *bc)
+static inline int BS_FUNC(decode210)(BSCTX *bc)
 {
-    if (bits_read_bit(bc))
+    if (BS_FUNC(read_bit)(bc))
         return 0;
     else
-        return 2 - bits_read_bit(bc);
+        return 2 - BS_FUNC(read_bit)(bc);
 }
 
 /* Read sign bit and flip the sign of the provided value accordingly. */
-static inline int bits_apply_sign(BitstreamContext *bc, int val)
+static inline int BS_FUNC(apply_sign)(BSCTX *bc, int val)
 {
-    int sign = bits_read_signed(bc, 1);
+    int sign = BS_FUNC(read_signed)(bc, 1);
     return (val ^ sign) - sign;
 }
 
-static inline int bits_skip_1stop_8data(BitstreamContext *s)
+static inline int BS_FUNC(skip_1stop_8data)(BSCTX *s)
 {
-    if (bits_left(s) <= 0)
+    if (BS_FUNC(left)(s) <= 0)
         return AVERROR_INVALIDDATA;
 
-    while (bits_read_bit(s)) {
-        bits_skip(s, 8);
-        if (bits_left(s) <= 0)
+    while (BS_FUNC(read_bit)(s)) {
+        BS_FUNC(skip)(s, 8);
+        if (BS_FUNC(left)(s) <= 0)
             return AVERROR_INVALIDDATA;
     }
 
@@ -454,13 +444,13 @@ static inline int bits_skip_1stop_8data(BitstreamContext *s)
 /**
  * Return the LUT element for the given bitstream configuration.
  */
-static inline int bits_priv_set_idx(BitstreamContext *bc, int code, int *n, int *nb_bits,
-                                    const VLCElem *table)
+static inline int BS_FUNC(priv_set_idx)(BSCTX *bc, int code, int *n,
+                                             int *nb_bits, const VLCElem *table)
 {
     unsigned idx;
 
     *nb_bits = -*n;
-    idx = bits_peek(bc, *nb_bits) + code;
+    idx = BS_FUNC(peek)(bc, *nb_bits) + code;
     *n = table[idx].len;
 
     return table[idx].sym;
@@ -477,53 +467,30 @@ static inline int bits_priv_set_idx(BitstreamContext *bc, int code, int *n, int
  * If the vlc code is invalid and max_depth>1, then the number of bits removed
  * is undefined.
  */
-static inline int bits_read_vlc(BitstreamContext *bc, const VLCElem *table,
-                                int bits, int max_depth)
+static inline int BS_FUNC(read_vlc)(BSCTX *bc, const VLCElem *table,
+                                         int bits, int max_depth)
 {
     int nb_bits;
-    unsigned idx = bits_peek(bc, bits);
+    unsigned idx = BS_FUNC(peek)(bc, bits);
     int code     = table[idx].sym;
     int n        = table[idx].len;
 
     if (max_depth > 1 && n < 0) {
-        bits_priv_skip_remaining(bc, bits);
-        code = bits_priv_set_idx(bc, code, &n, &nb_bits, table);
+        BS_FUNC(priv_skip_remaining)(bc, bits);
+        code = BS_FUNC(priv_set_idx)(bc, code, &n, &nb_bits, table);
         if (max_depth > 2 && n < 0) {
-            bits_priv_skip_remaining(bc, nb_bits);
-            code = bits_priv_set_idx(bc, code, &n, &nb_bits, table);
+            BS_FUNC(priv_skip_remaining)(bc, nb_bits);
+            code = BS_FUNC(priv_set_idx)(bc, code, &n, &nb_bits, table);
         }
     }
-    bits_priv_skip_remaining(bc, n);
+    BS_FUNC(priv_skip_remaining)(bc, n);
 
     return code;
 }
 
-#define BITS_RL_VLC(level, run, bc, table, bits, max_depth) \
-    do {                                                    \
-        int n, nb_bits;                                     \
-        unsigned int index = bits_peek(bc, bits);           \
-        level = table[index].level;                         \
-        n     = table[index].len;                           \
-                                                            \
-        if (max_depth > 1 && n < 0) {                       \
-            bits_skip(bc, bits);                            \
-                                                            \
-            nb_bits = -n;                                   \
-                                                            \
-            index = bits_peek(bc, nb_bits) + level;         \
-            level = table[index].level;                     \
-            n     = table[index].len;                       \
-            if (max_depth > 2 && n < 0) {                   \
-                bits_skip(bc, nb_bits);                     \
-                nb_bits = -n;                               \
-                                                            \
-                index = bits_peek(bc, nb_bits) + level;     \
-                level = table[index].level;                 \
-                n     = table[index].len;                   \
-            }                                               \
-        }                                                   \
-        run = table[index].run;                             \
-        bits_skip(bc, n);                                   \
-    } while (0)
-
-#endif /* AVCODEC_BITSTREAM_H */
+#undef BSCTX
+#undef BS_FUNC
+#undef BS_JOIN3
+#undef BS_JOIN
+#undef BS_SUFFIX_UPPER
+#undef BS_SUFFIX_LOWER
diff --git a/tests/ref/fate/source b/tests/ref/fate/source
index 16ea7ef9c1..3b7ea9c379 100644
--- a/tests/ref/fate/source
+++ b/tests/ref/fate/source
@@ -21,6 +21,7 @@ Headers without standard inclusion guards:
 compat/djgpp/math.h
 compat/float/float.h
 compat/float/limits.h
+libavcodec/bitstream_template.h
 tools/decode_simple.h
 Use of av_clip() where av_clip_uintp2() could be used:
 Use of av_clip() where av_clip_intp2() could be used:
-- 
2.35.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [FFmpeg-devel] [PATCH v4 3/4] lavc/tests: add a cached bitstream reader test
  2022-10-22 10:32 [FFmpeg-devel] [PATCH v4 1/4] lavc: add standalone cached bitstream reader Anton Khirnov
  2022-10-22 10:32 ` [FFmpeg-devel] [PATCH v4 2/4] lavc/bitstream: templatize for BE/LE Anton Khirnov
@ 2022-10-22 10:32 ` Anton Khirnov
  2022-10-22 10:32 ` [FFmpeg-devel] [PATCH v4 4/4] lavc/get_bits: add a compat wrapper for the cached bitstream reader Anton Khirnov
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Anton Khirnov @ 2022-10-22 10:32 UTC (permalink / raw)
  To: ffmpeg-devel

---
 libavcodec/Makefile                   |   2 +
 libavcodec/tests/bitstream_be.c       |  19 +++
 libavcodec/tests/bitstream_le.c       |  20 +++
 libavcodec/tests/bitstream_template.c | 183 ++++++++++++++++++++++++++
 tests/fate/libavcodec.mak             |  10 ++
 5 files changed, 234 insertions(+)
 create mode 100644 libavcodec/tests/bitstream_be.c
 create mode 100644 libavcodec/tests/bitstream_le.c
 create mode 100644 libavcodec/tests/bitstream_template.c

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index b77fe0db8e..4314b47d65 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1265,6 +1265,8 @@ SKIPHEADERS-$(CONFIG_ZLIB)             += zlib_wrapper.h
 
 TESTPROGS = avcodec                                                     \
             avpacket                                                    \
+            bitstream_be                                                \
+            bitstream_le                                                \
             celp_math                                                   \
             codec_desc                                                  \
             htmlsubtitles                                               \
diff --git a/libavcodec/tests/bitstream_be.c b/libavcodec/tests/bitstream_be.c
new file mode 100644
index 0000000000..bc562ed3b1
--- /dev/null
+++ b/libavcodec/tests/bitstream_be.c
@@ -0,0 +1,19 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "bitstream_template.c"
diff --git a/libavcodec/tests/bitstream_le.c b/libavcodec/tests/bitstream_le.c
new file mode 100644
index 0000000000..ba9296c95a
--- /dev/null
+++ b/libavcodec/tests/bitstream_le.c
@@ -0,0 +1,20 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define BITSTREAM_LE
+#include "bitstream_template.c"
diff --git a/libavcodec/tests/bitstream_template.c b/libavcodec/tests/bitstream_template.c
new file mode 100644
index 0000000000..13e92a31c6
--- /dev/null
+++ b/libavcodec/tests/bitstream_template.c
@@ -0,0 +1,183 @@
+/*
+ * cached bitstream reader test
+ * copyright (c) 2022 Anton Khirnov <anton@khirnov.net>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define ASSERT_LEVEL 2
+
+#include "libavutil/avassert.h"
+#include "libavutil/lfg.h"
+#include "libavutil/random_seed.h"
+
+#include "libavcodec/bitstream.h"
+#include "libavcodec/defs.h"
+
+#ifdef BITSTREAM_LE
+#define BITSTREAM_WRITER_LE
+#endif
+#include "libavcodec/put_bits.h"
+
+#define SIZE 157
+
+enum Op {
+    OP_READ,
+    OP_READ_NZ,
+    OP_READ_BIT,
+    OP_READ_63,
+    OP_READ_64,
+    OP_READ_SIGNED,
+    OP_APPLY_SIGN,
+    OP_ALIGN,
+    OP_NB,
+};
+
+int main(int argc, char **argv)
+{
+    BitstreamContext bc;
+    PutBitContext    pb;
+    AVLFG            lfg;
+
+    uint8_t buf[SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
+    uint8_t dst[SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
+
+    uint32_t random_seed;
+    uint64_t val, val1;
+    int32_t  sval;
+    unsigned count;
+
+    /* generate random input, using a given or random seed */
+    if (argc > 1)
+        random_seed = strtoul(argv[1], NULL, 0);
+    else
+        random_seed = av_get_random_seed();
+
+    fprintf(stderr, "Testing with LFG seed: %"PRIu32"\n", random_seed);
+    av_lfg_init(&lfg, random_seed);
+
+    for (unsigned i = 0; i < SIZE; i++)
+        buf[i] = av_lfg_get(&lfg);
+
+    bits_init8   (&bc, buf, SIZE);
+    init_put_bits(&pb, dst, SIZE);
+
+    /* use a random sequence of bitreading operations to transfer data
+     * from BitstreamContext to PutBitContext */
+    while (bits_left(&bc) > 0) {
+        enum Op op = av_lfg_get(&lfg) % OP_NB;
+
+        switch (op) {
+        case OP_READ:
+            count = av_lfg_get(&lfg) % FFMIN(33, bits_left(&bc) + 1);
+            val1  = bits_peek(&bc, count);
+            val   = bits_read(&bc, count);
+
+            fprintf(stderr, "%d read %u: %"PRIu64"\n", bits_tell(&bc) - count, count, val);
+
+            av_assert0(val == val1);
+
+            put_bits64(&pb, count, val);
+            break;
+        case OP_READ_NZ:
+            count = av_lfg_get(&lfg) % FFMIN(33, bits_left(&bc) + 1);
+            count = FFMAX(count, 1);
+            val1  = bits_peek_nz(&bc, count);
+            val   = bits_read_nz(&bc, count);
+
+            fprintf(stderr, "%d read_nz %u: %"PRIu64"\n", bits_tell(&bc) - count, count, val);
+
+            av_assert0(val == val1);
+
+            put_bits64(&pb, count, val);
+            break;
+        case OP_READ_BIT:
+            val = bits_read_bit(&bc);
+
+            fprintf(stderr, "%d read_bit: %"PRIu64"\n", bits_tell(&bc) - 1, val);
+
+            put_bits(&pb, 1, val);
+            break;
+        case OP_READ_63:
+            count = av_lfg_get(&lfg) % FFMIN(64, bits_left(&bc) + 1);
+            val   = bits_read_63(&bc, count);
+
+            fprintf(stderr, "%d read_63 %u: %"PRIu64"\n", bits_tell(&bc) - count, count, val);
+
+            put_bits64(&pb, count, val);
+            break;
+        case OP_READ_64:
+            count = av_lfg_get(&lfg) % FFMIN(65, bits_left(&bc) + 1);
+            val   = bits_read_64(&bc, count);
+
+            fprintf(stderr, "%d read_64 %u: %"PRIu64"\n", bits_tell(&bc) - count, count, val);
+
+            put_bits64(&pb, count, val);
+            break;
+        case OP_READ_SIGNED:
+            count = av_lfg_get(&lfg) % FFMIN(33, bits_left(&bc) + 1);
+            sval  = bits_read_signed(&bc, count);
+
+            fprintf(stderr, "%d read_signed %u: %"PRId32"\n", bits_tell(&bc) - count, count, sval);
+
+            if (count == 32) put_bits32(&pb, sval);
+            else             put_sbits(&pb, count, sval);
+            break;
+        case OP_ALIGN:
+            count = (bits_tell(&bc) + 7) / 8 * 8 - bits_tell(&bc);
+
+            fprintf(stderr, "%d align %u\n", bits_tell(&bc), count);
+
+            put_bits(&pb, count, bits_peek(&bc, count));
+            bits_align(&bc);
+            break;
+        case OP_APPLY_SIGN:
+            if (bits_left(&bc) < 2)
+                continue;
+
+            count = av_lfg_get(&lfg) % FFMIN(32, bits_left(&bc));
+            count = FFMAX(count, 1);
+
+            if (!bits_peek(&bc, count))
+                continue;
+
+            val   = bits_read(&bc, count);
+            sval  = bits_apply_sign(&bc, val);
+
+            fprintf(stderr, "%d apply_sign %u %"PRId32"\n",
+                    bits_tell(&bc) - count - 1, count, sval);
+
+            put_bits64(&pb, count, FFABS(sval));
+            put_bits(&pb, 1, sval < 0);
+
+            break;
+        default:
+            av_assert0(0);
+        }
+    }
+
+    flush_put_bits(&pb);
+
+    for (unsigned i = 0; i < SIZE; i++)
+        if (buf[i] != dst[i]) {
+            fprintf(stderr, "Mismatch at byte %u: %hhu %hhu; seed %"PRIu32"\n",
+                    i, buf[i], dst[i], random_seed);
+            return 1;
+        }
+
+    return 0;
+}
diff --git a/tests/fate/libavcodec.mak b/tests/fate/libavcodec.mak
index aa199e0308..8f56fae3a8 100644
--- a/tests/fate/libavcodec.mak
+++ b/tests/fate/libavcodec.mak
@@ -3,6 +3,16 @@ fate-avpacket: libavcodec/tests/avpacket$(EXESUF)
 fate-avpacket: CMD = run libavcodec/tests/avpacket$(EXESUF)
 fate-avpacket: CMP = null
 
+FATE_LIBAVCODEC-yes += fate-bitstream-be
+fate-bitstream-be: libavcodec/tests/bitstream_be$(EXESUF)
+fate-bitstream-be: CMD = run libavcodec/tests/bitstream_be$(EXESUF)
+fate-bitstream-be: CMP = null
+
+FATE_LIBAVCODEC-yes += fate-bitstream-le
+fate-bitstream-le: libavcodec/tests/bitstream_le$(EXESUF)
+fate-bitstream-le: CMD = run libavcodec/tests/bitstream_le$(EXESUF)
+fate-bitstream-le: CMP = null
+
 FATE_LIBAVCODEC-$(CONFIG_CABAC) += fate-cabac
 fate-cabac: libavcodec/tests/cabac$(EXESUF)
 fate-cabac: CMD = run libavcodec/tests/cabac$(EXESUF)
-- 
2.35.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [FFmpeg-devel] [PATCH v4 4/4] lavc/get_bits: add a compat wrapper for the cached bitstream reader
  2022-10-22 10:32 [FFmpeg-devel] [PATCH v4 1/4] lavc: add standalone cached bitstream reader Anton Khirnov
  2022-10-22 10:32 ` [FFmpeg-devel] [PATCH v4 2/4] lavc/bitstream: templatize for BE/LE Anton Khirnov
  2022-10-22 10:32 ` [FFmpeg-devel] [PATCH v4 3/4] lavc/tests: add a cached bitstream reader test Anton Khirnov
@ 2022-10-22 10:32 ` Anton Khirnov
  2022-10-22 10:37 ` [FFmpeg-devel] [PATCH v4 1/4] lavc: add standalone " Paul B Mahol
  2023-01-03 11:19 ` Anton Khirnov
  4 siblings, 0 replies; 7+ messages in thread
From: Anton Khirnov @ 2022-10-22 10:32 UTC (permalink / raw)
  To: ffmpeg-devel

Use that instead of the merged version.
---
 libavcodec/get_bits.h | 309 +++++++++---------------------------------
 1 file changed, 62 insertions(+), 247 deletions(-)

diff --git a/libavcodec/get_bits.h b/libavcodec/get_bits.h
index 992765dc92..a50469b427 100644
--- a/libavcodec/get_bits.h
+++ b/libavcodec/get_bits.h
@@ -1,6 +1,5 @@
 /*
  * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
- * Copyright (c) 2016 Alexandra Hájková
  *
  * This file is part of FFmpeg.
  *
@@ -58,12 +57,55 @@
 #define CACHED_BITSTREAM_READER 0
 #endif
 
-typedef struct GetBitContext {
-    const uint8_t *buffer, *buffer_end;
 #if CACHED_BITSTREAM_READER
-    uint64_t cache;
-    unsigned bits_left;
+
+// we always want the LE implementation, to provide get_bits_le()
+#define BITSTREAM_LE
+
+#ifndef BITSTREAM_READER_LE
+# define BITSTREAM_BE
+# define BITSTREAM_DEFAULT_BE
 #endif
+
+#include "bitstream.h"
+
+#undef BITSTREAM_LE
+#undef BITSTREAM_BE
+#undef BITSTREAM_DEFAULT_BE
+
+typedef BitstreamContext GetBitContext;
+
+#define get_bits_count      bits_tell
+#define get_bits_left       bits_left
+#define skip_bits_long      bits_skip
+#define skip_bits           bits_skip
+#define get_bits            bits_read_nz
+#define get_bitsz           bits_read
+#define get_bits_long       bits_read
+#define get_bits1           bits_read_bit
+#define get_bits64          bits_read_64
+#define get_xbits           bits_read_xbits
+#define get_sbits           bits_read_signed
+#define get_sbits_long      bits_read_signed
+#define show_bits           bits_peek
+#define show_bits_long      bits_peek
+#define init_get_bits       bits_init
+#define init_get_bits8      bits_init8
+#define align_get_bits      bits_align
+#define get_vlc2            bits_read_vlc
+
+#define init_get_bits8_le(s, buffer, byte_size) bits_init8_le((BitstreamContextLE*)s, buffer, byte_size)
+#define get_bits_le(s, n)                       bits_read_le((BitstreamContextLE*)s, n)
+
+#define show_bits1(s)       bits_peek(s, 1)
+#define skip_bits1(s)       bits_skip(s, 1)
+
+#define skip_1stop_8data_bits bits_skip_1stop_8data
+
+#else   // CACHED_BITSTREAM_READER
+
+typedef struct GetBitContext {
+    const uint8_t *buffer, *buffer_end;
     int index;
     int size_in_bits;
     int size_in_bits_plus8;
@@ -120,16 +162,12 @@ static inline unsigned int show_bits(GetBitContext *s, int n);
  * For examples see get_bits, show_bits, skip_bits, get_vlc.
  */
 
-#if CACHED_BITSTREAM_READER
-#   define MIN_CACHE_BITS 64
-#elif defined LONG_BITSTREAM_READER
+#if defined LONG_BITSTREAM_READER
 #   define MIN_CACHE_BITS 32
 #else
 #   define MIN_CACHE_BITS 25
 #endif
 
-#if !CACHED_BITSTREAM_READER
-
 #define OPEN_READER_NOSIZE(name, gb)            \
     unsigned int name ## _index = (gb)->index;  \
     unsigned int av_unused name ## _cache
@@ -214,73 +252,12 @@ static inline unsigned int show_bits(GetBitContext *s, int n);
 
 #define GET_CACHE(name, gb) ((uint32_t) name ## _cache)
 
-#endif
 
 static inline int get_bits_count(const GetBitContext *s)
 {
-#if CACHED_BITSTREAM_READER
-    return s->index - s->bits_left;
-#else
     return s->index;
-#endif
-}
-
-#if CACHED_BITSTREAM_READER
-static inline void refill_32(GetBitContext *s, int is_le)
-{
-#if !UNCHECKED_BITSTREAM_READER
-    if (s->index >> 3 >= s->buffer_end - s->buffer)
-        return;
-#endif
-
-    if (is_le)
-        s->cache = (uint64_t)AV_RL32(s->buffer + (s->index >> 3)) << s->bits_left | s->cache;
-    else
-        s->cache = s->cache | (uint64_t)AV_RB32(s->buffer + (s->index >> 3)) << (32 - s->bits_left);
-    s->index     += 32;
-    s->bits_left += 32;
-}
-
-static inline void refill_64(GetBitContext *s, int is_le)
-{
-#if !UNCHECKED_BITSTREAM_READER
-    if (s->index >> 3 >= s->buffer_end - s->buffer)
-        return;
-#endif
-
-    if (is_le)
-        s->cache = AV_RL64(s->buffer + (s->index >> 3));
-    else
-        s->cache = AV_RB64(s->buffer + (s->index >> 3));
-    s->index += 64;
-    s->bits_left = 64;
 }
 
-static inline uint64_t get_val(GetBitContext *s, unsigned n, int is_le)
-{
-    uint64_t ret;
-    av_assert2(n>0 && n<=63);
-    if (is_le) {
-        ret = s->cache & ((UINT64_C(1) << n) - 1);
-        s->cache >>= n;
-    } else {
-        ret = s->cache >> (64 - n);
-        s->cache <<= n;
-    }
-    s->bits_left -= n;
-    return ret;
-}
-
-static inline unsigned show_val(const GetBitContext *s, unsigned n)
-{
-#ifdef BITSTREAM_READER_LE
-    return s->cache & ((UINT64_C(1) << n) - 1);
-#else
-    return s->cache >> (64 - n);
-#endif
-}
-#endif
-
 /**
  * Skips the specified number of bits.
  * @param n the number of bits to skip,
@@ -290,28 +267,12 @@ static inline unsigned show_val(const GetBitContext *s, unsigned n)
  */
 static inline void skip_bits_long(GetBitContext *s, int n)
 {
-#if CACHED_BITSTREAM_READER
-    skip_bits(s, n);
-#else
 #if UNCHECKED_BITSTREAM_READER
     s->index += n;
 #else
     s->index += av_clip(n, -s->index, s->size_in_bits_plus8 - s->index);
 #endif
-#endif
-}
-
-#if CACHED_BITSTREAM_READER
-static inline void skip_remaining(GetBitContext *s, unsigned n)
-{
-#ifdef BITSTREAM_READER_LE
-    s->cache >>= n;
-#else
-    s->cache <<= n;
-#endif
-    s->bits_left -= n;
 }
-#endif
 
 /**
  * Read MPEG-1 dc-style VLC (sign bit + mantissa with no MSB).
@@ -320,13 +281,6 @@ static inline void skip_remaining(GetBitContext *s, unsigned n)
  */
 static inline int get_xbits(GetBitContext *s, int n)
 {
-#if CACHED_BITSTREAM_READER
-    int32_t cache = show_bits(s, 32);
-    int sign = ~cache >> 31;
-    skip_remaining(s, n);
-
-    return ((((uint32_t)(sign ^ cache)) >> (32 - n)) ^ sign) - sign;
-#else
     register int sign;
     register int32_t cache;
     OPEN_READER(re, s);
@@ -337,10 +291,8 @@ static inline int get_xbits(GetBitContext *s, int n)
     LAST_SKIP_BITS(re, s, n);
     CLOSE_READER(re, s);
     return (NEG_USR32(sign ^ cache, n) ^ sign) - sign;
-#endif
 }
 
-#if !CACHED_BITSTREAM_READER
 static inline int get_xbits_le(GetBitContext *s, int n)
 {
     register int sign;
@@ -354,22 +306,16 @@ static inline int get_xbits_le(GetBitContext *s, int n)
     CLOSE_READER(re, s);
     return (zero_extend(sign ^ cache, n) ^ sign) - sign;
 }
-#endif
 
 static inline int get_sbits(GetBitContext *s, int n)
 {
     register int tmp;
-#if CACHED_BITSTREAM_READER
-    av_assert2(n>0 && n<=25);
-    tmp = sign_extend(get_bits(s, n), n);
-#else
     OPEN_READER(re, s);
     av_assert2(n>0 && n<=25);
     UPDATE_CACHE(re, s);
     tmp = SHOW_SBITS(re, s, n);
     LAST_SKIP_BITS(re, s, n);
     CLOSE_READER(re, s);
-#endif
     return tmp;
 }
 
@@ -379,32 +325,12 @@ static inline int get_sbits(GetBitContext *s, int n)
 static inline unsigned int get_bits(GetBitContext *s, int n)
 {
     register unsigned int tmp;
-#if CACHED_BITSTREAM_READER
-
-    av_assert2(n>0 && n<=32);
-    if (n > s->bits_left) {
-#ifdef BITSTREAM_READER_LE
-        refill_32(s, 1);
-#else
-        refill_32(s, 0);
-#endif
-        if (s->bits_left < 32)
-            s->bits_left = n;
-    }
-
-#ifdef BITSTREAM_READER_LE
-    tmp = get_val(s, n, 1);
-#else
-    tmp = get_val(s, n, 0);
-#endif
-#else
     OPEN_READER(re, s);
     av_assert2(n>0 && n<=25);
     UPDATE_CACHE(re, s);
     tmp = SHOW_UBITS(re, s, n);
     LAST_SKIP_BITS(re, s, n);
     CLOSE_READER(re, s);
-#endif
     av_assert2(tmp < UINT64_C(1) << n);
     return tmp;
 }
@@ -419,16 +345,6 @@ static av_always_inline int get_bitsz(GetBitContext *s, int n)
 
 static inline unsigned int get_bits_le(GetBitContext *s, int n)
 {
-#if CACHED_BITSTREAM_READER
-    av_assert2(n>0 && n<=32);
-    if (n > s->bits_left) {
-        refill_32(s, 1);
-        if (s->bits_left < 32)
-            s->bits_left = n;
-    }
-
-    return get_val(s, n, 1);
-#else
     register int tmp;
     OPEN_READER(re, s);
     av_assert2(n>0 && n<=25);
@@ -437,7 +353,6 @@ static inline unsigned int get_bits_le(GetBitContext *s, int n)
     LAST_SKIP_BITS(re, s, n);
     CLOSE_READER(re, s);
     return tmp;
-#endif
 }
 
 /**
@@ -446,71 +361,22 @@ static inline unsigned int get_bits_le(GetBitContext *s, int n)
 static inline unsigned int show_bits(GetBitContext *s, int n)
 {
     register unsigned int tmp;
-#if CACHED_BITSTREAM_READER
-    if (n > s->bits_left)
-#ifdef BITSTREAM_READER_LE
-        refill_32(s, 1);
-#else
-        refill_32(s, 0);
-#endif
-
-    tmp = show_val(s, n);
-#else
     OPEN_READER_NOSIZE(re, s);
     av_assert2(n>0 && n<=25);
     UPDATE_CACHE(re, s);
     tmp = SHOW_UBITS(re, s, n);
-#endif
     return tmp;
 }
 
 static inline void skip_bits(GetBitContext *s, int n)
 {
-#if CACHED_BITSTREAM_READER
-    if (n < s->bits_left)
-        skip_remaining(s, n);
-    else {
-        n -= s->bits_left;
-        s->cache = 0;
-        s->bits_left = 0;
-
-        if (n >= 64) {
-            unsigned skip = (n / 8) * 8;
-
-            n -= skip;
-            s->index += skip;
-        }
-#ifdef BITSTREAM_READER_LE
-        refill_64(s, 1);
-#else
-        refill_64(s, 0);
-#endif
-        if (n)
-            skip_remaining(s, n);
-    }
-#else
     OPEN_READER(re, s);
     LAST_SKIP_BITS(re, s, n);
     CLOSE_READER(re, s);
-#endif
 }
 
 static inline unsigned int get_bits1(GetBitContext *s)
 {
-#if CACHED_BITSTREAM_READER
-    if (!s->bits_left)
-#ifdef BITSTREAM_READER_LE
-        refill_64(s, 1);
-#else
-        refill_64(s, 0);
-#endif
-
-#ifdef BITSTREAM_READER_LE
-    return get_val(s, 1, 1);
-#else
-    return get_val(s, 1, 0);
-#endif
-#else
     unsigned int index = s->index;
     uint8_t result     = s->buffer[index >> 3];
 #ifdef BITSTREAM_READER_LE
@@ -527,7 +393,6 @@ static inline unsigned int get_bits1(GetBitContext *s)
     s->index = index;
 
     return result;
-#endif
 }
 
 static inline unsigned int show_bits1(GetBitContext *s)
@@ -548,10 +413,6 @@ static inline unsigned int get_bits_long(GetBitContext *s, int n)
     av_assert2(n>=0 && n<=32);
     if (!n) {
         return 0;
-#if CACHED_BITSTREAM_READER
-    }
-    return get_bits(s, n);
-#else
     } else if (n <= MIN_CACHE_BITS) {
         return get_bits(s, n);
     } else {
@@ -563,7 +424,6 @@ static inline unsigned int get_bits_long(GetBitContext *s, int n)
         return ret | get_bits(s, n - 16);
 #endif
     }
-#endif
 }
 
 /**
@@ -609,8 +469,17 @@ static inline unsigned int show_bits_long(GetBitContext *s, int n)
     }
 }
 
-static inline int init_get_bits_xe(GetBitContext *s, const uint8_t *buffer,
-                                   int bit_size, int is_le)
+
+/**
+ * Initialize GetBitContext.
+ * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes
+ *        larger than the actual read bits because some optimized bitstream
+ *        readers read 32 or 64 bit at once and could read over the end
+ * @param bit_size the size of the buffer in bits
+ * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow.
+ */
+static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer,
+                                int bit_size)
 {
     int buffer_size;
     int ret = 0;
@@ -629,33 +498,9 @@ static inline int init_get_bits_xe(GetBitContext *s, const uint8_t *buffer,
     s->buffer_end         = buffer + buffer_size;
     s->index              = 0;
 
-#if CACHED_BITSTREAM_READER
-    s->cache              = 0;
-    s->bits_left          = 0;
-    refill_64(s, is_le);
-#endif
-
     return ret;
 }
 
-/**
- * Initialize GetBitContext.
- * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes
- *        larger than the actual read bits because some optimized bitstream
- *        readers read 32 or 64 bit at once and could read over the end
- * @param bit_size the size of the buffer in bits
- * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow.
- */
-static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer,
-                                int bit_size)
-{
-#ifdef BITSTREAM_READER_LE
-    return init_get_bits_xe(s, buffer, bit_size, 1);
-#else
-    return init_get_bits_xe(s, buffer, bit_size, 0);
-#endif
-}
-
 /**
  * Initialize GetBitContext.
  * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes
@@ -677,7 +522,7 @@ static inline int init_get_bits8_le(GetBitContext *s, const uint8_t *buffer,
 {
     if (byte_size > INT_MAX / 8 || byte_size < 0)
         byte_size = -1;
-    return init_get_bits_xe(s, buffer, byte_size * 8, 1);
+    return init_get_bits(s, buffer, byte_size * 8);
 }
 
 static inline const uint8_t *align_get_bits(GetBitContext *s)
@@ -762,19 +607,6 @@ static inline const uint8_t *align_get_bits(GetBitContext *s)
         SKIP_BITS(name, gb, n);                                 \
     } while (0)
 
-/* Return the LUT element for the given bitstream configuration. */
-static inline int set_idx(GetBitContext *s, int code, int *n, int *nb_bits,
-                          const VLCElem *table)
-{
-    unsigned idx;
-
-    *nb_bits = -*n;
-    idx = show_bits(s, *nb_bits) + code;
-    *n = table[idx].len;
-
-    return table[idx].sym;
-}
-
 /**
  * Parse a vlc code.
  * @param bits is the number of bits which will be read at once, must be
@@ -787,24 +619,6 @@ static inline int set_idx(GetBitContext *s, int code, int *n, int *nb_bits,
 static av_always_inline int get_vlc2(GetBitContext *s, const VLCElem *table,
                                      int bits, int max_depth)
 {
-#if CACHED_BITSTREAM_READER
-    int nb_bits;
-    unsigned idx = show_bits(s, bits);
-    int code = table[idx].sym;
-    int n    = table[idx].len;
-
-    if (max_depth > 1 && n < 0) {
-        skip_remaining(s, bits);
-        code = set_idx(s, code, &n, &nb_bits, table);
-        if (max_depth > 2 && n < 0) {
-            skip_remaining(s, nb_bits);
-            code = set_idx(s, code, &n, &nb_bits, table);
-        }
-    }
-    skip_remaining(s, n);
-
-    return code;
-#else
     int code;
 
     OPEN_READER(re, s);
@@ -815,7 +629,6 @@ static av_always_inline int get_vlc2(GetBitContext *s, const VLCElem *table,
     CLOSE_READER(re, s);
 
     return code;
-#endif
 }
 
 static inline int decode012(GetBitContext *gb)
@@ -855,4 +668,6 @@ static inline int skip_1stop_8data_bits(GetBitContext *gb)
     return 0;
 }
 
+#endif // CACHED_BITSTREAM_READER
+
 #endif /* AVCODEC_GET_BITS_H */
-- 
2.35.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [FFmpeg-devel] [PATCH v4 1/4] lavc: add standalone cached bitstream reader
  2022-10-22 10:32 [FFmpeg-devel] [PATCH v4 1/4] lavc: add standalone cached bitstream reader Anton Khirnov
                   ` (2 preceding siblings ...)
  2022-10-22 10:32 ` [FFmpeg-devel] [PATCH v4 4/4] lavc/get_bits: add a compat wrapper for the cached bitstream reader Anton Khirnov
@ 2022-10-22 10:37 ` Paul B Mahol
  2023-01-03 11:19 ` Anton Khirnov
  4 siblings, 0 replies; 7+ messages in thread
From: Paul B Mahol @ 2022-10-22 10:37 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

On 10/22/22, Anton Khirnov <anton@khirnov.net> wrote:
> From: Alexandra Hájková <alexandra.khirnova@gmail.com>
>
> The cached bitstream reader was originally written by Alexandra Hájková
> for Libav, with significant input from Kostya Shishkov and Luca Barbato.
> It was then committed to FFmpeg in ca079b09549, by merging it with the
> implementation of the current bitstream reader.
>
> This merge makes the code of get_bits.h significantly harder to read,
> since it now contains two different bitstream readers interleaved with
>  #ifdefs. Additionally, the code was committed without proper authorship
> attribution.
>
> This commit re-adds the cached bitstream reader as a standalone header,
> as it was originally developed. It will be made useful in following
> commits.
>
> Integration by Anton Khirnov.
>
> Signed-off-by: Anton Khirnov <anton@khirnov.net>
> ---
>  libavcodec/bitstream.h | 529 +++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 529 insertions(+)
>  create mode 100644 libavcodec/bitstream.h
>
> diff --git a/libavcodec/bitstream.h b/libavcodec/bitstream.h
> new file mode 100644
> index 0000000000..6fd321dba5
> --- /dev/null
> +++ b/libavcodec/bitstream.h
> @@ -0,0 +1,529 @@
> +/*
> + * Copyright (c) 2016 Alexandra Hájková
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
> USA
> + */
> +
> +/**
> + * @file
> + * bitstream reader API header.
> + */
> +
> +#ifndef AVCODEC_BITSTREAM_H
> +#define AVCODEC_BITSTREAM_H
> +
> +#include <stdint.h>
> +
> +#include "config.h"
> +
> +#include "libavutil/avassert.h"
> +#include "libavutil/common.h"
> +#include "libavutil/intreadwrite.h"
> +#include "libavutil/log.h"
> +
> +#include "mathops.h"
> +#include "vlc.h"
> +
> +#ifndef UNCHECKED_BITSTREAM_READER
> +#define UNCHECKED_BITSTREAM_READER !CONFIG_SAFE_BITSTREAM_READER
> +#endif
> +
> +typedef struct BitstreamContext {
> +    uint64_t bits;       // stores bits read from the buffer
> +    const uint8_t *buffer, *buffer_end;
> +    const uint8_t *ptr;  // pointer to the position inside a buffer
> +    unsigned bits_valid; // number of bits left in bits field
> +    unsigned size_in_bits;
> +} BitstreamContext;
> +
> +/**
> + * @return
> + * - 0 on successful refill
> + * - a negative number when bitstream end is hit
> + *
> + * Always succeeds when UNCHECKED_BITSTREAM_READER is enabled.
> + */
> +static inline int bits_priv_refill_64(BitstreamContext *bc)
> +{
> +#if !UNCHECKED_BITSTREAM_READER
> +    if (bc->ptr >= bc->buffer_end)
> +        return -1;
> +#endif
> +
> +#ifdef BITSTREAM_READER_LE
> +    bc->bits       = AV_RL64(bc->ptr);
> +#else
> +    bc->bits       = AV_RB64(bc->ptr);
> +#endif
> +    bc->ptr       += 8;
> +    bc->bits_valid = 64;
> +
> +    return 0;
> +}
> +
> +/**
> + * @return
> + * - 0 on successful refill
> + * - a negative number when bitstream end is hit
> + *
> + * Always succeeds when UNCHECKED_BITSTREAM_READER is enabled.
> + */
> +static inline int bits_priv_refill_32(BitstreamContext *bc)
> +{
> +#if !UNCHECKED_BITSTREAM_READER
> +    if (bc->ptr >= bc->buffer_end)
> +        return -1;
> +#endif
> +
> +#ifdef BITSTREAM_READER_LE
> +    bc->bits      |= (uint64_t)AV_RL32(bc->ptr) << bc->bits_valid;
> +#else
> +    bc->bits      |= (uint64_t)AV_RB32(bc->ptr) << (32 - bc->bits_valid);
> +#endif
> +    bc->ptr        += 4;
> +    bc->bits_valid += 32;
> +
> +    return 0;
> +}
> +
> +/**
> + * Initialize BitstreamContext.
> + * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE
> bytes
> + *        larger than the actual read bits because some optimized bitstream
> + *        readers read 32 or 64 bits at once and could read over the end
> + * @param bit_size the size of the buffer in bits
> + * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would
> overflow.
> + */
> +static inline int bits_init(BitstreamContext *bc, const uint8_t *buffer,
> +                            unsigned int bit_size)
> +{
> +    unsigned int buffer_size;
> +
> +    if (bit_size > INT_MAX - 7 || !buffer) {
> +        bc->buffer     = NULL;
> +        bc->ptr        = NULL;
> +        bc->bits_valid = 0;
> +        return AVERROR_INVALIDDATA;
> +    }
> +
> +    buffer_size = (bit_size + 7) >> 3;
> +
> +    bc->buffer       = buffer;
> +    bc->buffer_end   = buffer + buffer_size;
> +    bc->ptr          = bc->buffer;
> +    bc->size_in_bits = bit_size;
> +    bc->bits_valid   = 0;
> +    bc->bits         = 0;
> +
> +    bits_priv_refill_64(bc);
> +
> +    return 0;
> +}
> +
> +/**
> + * Initialize BitstreamContext.
> + * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE
> bytes
> + *        larger than the actual read bits because some optimized bitstream
> + *        readers read 32 or 64 bits at once and could read over the end
> + * @param byte_size the size of the buffer in bytes
> + * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would
> overflow
> + */
> +static inline int bits_init8(BitstreamContext *bc, const uint8_t *buffer,
> +                             unsigned int byte_size)
> +{
> +    if (byte_size > INT_MAX / 8)
> +        return AVERROR_INVALIDDATA;
> +    return bits_init(bc, buffer, byte_size * 8);
> +}
> +
> +/**
> + * Return number of bits already read.
> + */
> +static inline int bits_tell(const BitstreamContext *bc)
> +{
> +    return (bc->ptr - bc->buffer) * 8 - bc->bits_valid;
> +}
> +
> +/**
> + * Return buffer size in bits.
> + */
> +static inline int bits_size(const BitstreamContext *bc)
> +{
> +    return bc->size_in_bits;
> +}
> +
> +/**
> + * Return the number of the bits left in a buffer.
> + */
> +static inline int bits_left(const BitstreamContext *bc)
> +{
> +    return (bc->buffer - bc->ptr) * 8 + bc->size_in_bits + bc->bits_valid;
> +}
> +
> +static inline uint64_t bits_priv_val_show(BitstreamContext *bc, unsigned
> int n)
> +{
> +    av_assert2(n > 0 && n <= 64);
> +
> +#ifdef BITSTREAM_READER_LE
> +    return bc->bits & (UINT64_MAX >> (64 - n));
> +#else
> +    return bc->bits >> (64 - n);
> +#endif
> +}
> +
> +static inline void bits_priv_skip_remaining(BitstreamContext *bc, unsigned
> int n)
> +{
> +#ifdef BITSTREAM_READER_LE
> +    bc->bits >>= n;
> +#else
> +    bc->bits <<= n;
> +#endif
> +    bc->bits_valid -= n;
> +}
> +
> +static inline uint64_t bits_priv_val_get(BitstreamContext *bc, unsigned int
> n)
> +{
> +    uint64_t ret;
> +
> +    av_assert2(n > 0 && n < 64);
> +
> +    ret = bits_priv_val_show(bc, n);
> +    bits_priv_skip_remaining(bc, n);
> +
> +    return ret;
> +}
> +
> +/**
> + * Return one bit from the buffer.
> + */
> +static inline unsigned int bits_read_bit(BitstreamContext *bc)
> +{
> +    if (!bc->bits_valid && bits_priv_refill_64(bc) < 0)
> +        return 0;
> +
> +    return bits_priv_val_get(bc, 1);
> +}
> +
> +/**
> + * Return n bits from the buffer, n has to be in the 1-32 range.
> + * May be faster than bits_read() when n is not a compile-time constant and
> is
> + * known to be non-zero;
> + */
> +static inline uint32_t bits_read_nz(BitstreamContext *bc, unsigned int n)
> +{
> +    av_assert2(n > 0 && n <= 32);
> +
> +    if (n > bc->bits_valid) {
> +        if (bits_priv_refill_32(bc) < 0)
> +            bc->bits_valid = n;
> +    }
> +
> +    return bits_priv_val_get(bc, n);
> +}
> +
> +/**
> + * Return n bits from the buffer, n has to be in the 0-32  range.
> + */
> +static inline uint32_t bits_read(BitstreamContext *bc, unsigned int n)
> +{
> +    av_assert2(n <= 32);
> +
> +    if (!n)
> +        return 0;
> +
> +    return bits_read_nz(bc, n);
> +}
> +
> +/**
> + * Return n bits from the buffer, n has to be in the 0-63 range.
> + */
> +static inline uint64_t bits_read_63(BitstreamContext *bc, unsigned int n)
> +{
> +    uint64_t ret = 0;
> +    unsigned left = 0;
> +
> +    av_assert2(n <= 63);
> +
> +    if (!n)
> +        return 0;
> +
> +    if (n > bc->bits_valid) {
> +        left = bc->bits_valid;
> +        n   -= left;
> +
> +        if (left)
> +            ret = bits_priv_val_get(bc, left);
> +
> +        if (bits_priv_refill_64(bc) < 0)
> +            bc->bits_valid = n;
> +
> +    }
> +
> +#ifdef BITSTREAM_READER_LE
> +    ret = bits_priv_val_get(bc, n) << left | ret;
> +#else
> +    ret = bits_priv_val_get(bc, n) | ret << n;
> +#endif
> +
> +    return ret;
> +}
> +
> +/**
> + * Return n bits from the buffer, n has to be in the 0-64 range.
> + */
> +static inline uint64_t bits_read_64(BitstreamContext *bc, unsigned int n)
> +{
> +    av_assert2(n <= 64);
> +
> +    if (n == 64) {
> +        uint64_t ret = bits_read_63(bc, 63);
> +#ifdef BITSTREAM_READER_LE
> +        return ret | ((uint64_t)bits_read_bit(bc) << 63);
> +#else
> +        return (ret << 1) | (uint64_t)bits_read_bit(bc);
> +#endif
> +    }
> +    return bits_read_63(bc, n);
> +}
> +
> +/**
> + * Return n bits from the buffer as a signed integer.
> + * n has to be in the 0-32 range.
> + */
> +static inline int32_t bits_read_signed(BitstreamContext *bc, unsigned int
> n)
> +{
> +    return sign_extend(bits_read(bc, n), n);
> +}
> +
> +/**
> + * Return n bits from the buffer but do not change the buffer state.
> + * n has to be in the 1-32 range. May
> + */
> +static inline uint32_t bits_peek_nz(BitstreamContext *bc, unsigned int n)
> +{
> +    av_assert2(n > 0 && n <= 32);
> +
> +    if (n > bc->bits_valid)
> +        bits_priv_refill_32(bc);
> +
> +    return bits_priv_val_show(bc, n);
> +}
> +
> +/**
> + * Return n bits from the buffer but do not change the buffer state.
> + * n has to be in the 0-32 range.
> + */
> +static inline uint32_t bits_peek(BitstreamContext *bc, unsigned int n)
> +{
> +    av_assert2(n <= 32);
> +
> +    if (!n)
> +        return 0;
> +
> +    return bits_peek_nz(bc, n);
> +}
> +
> +/**
> + * Return n bits from the buffer as a signed integer,
> + * do not change the buffer state.
> + * n has to be in the 0-32 range.
> + */
> +static inline int bits_peek_signed(BitstreamContext *bc, unsigned int n)
> +{
> +    return sign_extend(bits_peek(bc, n), n);
> +}
> +
> +/**
> + * Skip n bits in the buffer.
> + */
> +static inline void bits_skip(BitstreamContext *bc, unsigned int n)
> +{
> +    if (n < bc->bits_valid)
> +        bits_priv_skip_remaining(bc, n);
> +    else {
> +        n -= bc->bits_valid;
> +        bc->bits       = 0;
> +        bc->bits_valid = 0;
> +
> +        if (n >= 64) {
> +            unsigned int skip = n / 8;
> +
> +            n -= skip * 8;
> +            bc->ptr += skip;
> +        }
> +        bits_priv_refill_64(bc);
> +        if (n)
> +            bits_priv_skip_remaining(bc, n);
> +    }
> +}
> +
> +/**
> + * Seek to the given bit position.
> + */
> +static inline void bits_seek(BitstreamContext *bc, unsigned pos)
> +{
> +    bc->ptr        = bc->buffer;
> +    bc->bits       = 0;
> +    bc->bits_valid = 0;
> +
> +    bits_skip(bc, pos);
> +}
> +
> +/**
> + * Skip bits to a byte boundary.
> + */
> +static inline const uint8_t *bits_align(BitstreamContext *bc)
> +{
> +    unsigned int n = -bits_tell(bc) & 7;
> +    if (n)
> +        bits_skip(bc, n);
> +    return bc->buffer + (bits_tell(bc) >> 3);
> +}
> +
> +/**
> + * Read MPEG-1 dc-style VLC (sign bit + mantissa with no MSB).
> + * If MSB not set it is negative.
> + * @param n length in bits
> + */
> +static inline int bits_read_xbits(BitstreamContext *bc, unsigned int n)
> +{
> +    int32_t cache = bits_peek(bc, 32);
> +    int sign = ~cache >> 31;
> +    bits_priv_skip_remaining(bc, n);
> +
> +    return ((((uint32_t)(sign ^ cache)) >> (32 - n)) ^ sign) - sign;
> +}
> +
> +/**
> + * Return decoded truncated unary code for the values 0, 1, 2.
> + */
> +static inline int bits_decode012(BitstreamContext *bc)
> +{
> +    if (!bits_read_bit(bc))
> +        return 0;
> +    else
> +        return bits_read_bit(bc) + 1;
> +}
> +
> +/**
> + * Return decoded truncated unary code for the values 2, 1, 0.
> + */
> +static inline int bits_decode210(BitstreamContext *bc)
> +{
> +    if (bits_read_bit(bc))
> +        return 0;
> +    else
> +        return 2 - bits_read_bit(bc);
> +}
> +
> +/* Read sign bit and flip the sign of the provided value accordingly. */
> +static inline int bits_apply_sign(BitstreamContext *bc, int val)
> +{
> +    int sign = bits_read_signed(bc, 1);
> +    return (val ^ sign) - sign;
> +}
> +
> +static inline int bits_skip_1stop_8data(BitstreamContext *s)
> +{
> +    if (bits_left(s) <= 0)
> +        return AVERROR_INVALIDDATA;
> +
> +    while (bits_read_bit(s)) {
> +        bits_skip(s, 8);
> +        if (bits_left(s) <= 0)
> +            return AVERROR_INVALIDDATA;
> +    }
> +
> +    return 0;
> +}
> +
> +/**
> + * Return the LUT element for the given bitstream configuration.
> + */
> +static inline int bits_priv_set_idx(BitstreamContext *bc, int code, int *n,
> int *nb_bits,
> +                                    const VLCElem *table)
> +{
> +    unsigned idx;
> +
> +    *nb_bits = -*n;
> +    idx = bits_peek(bc, *nb_bits) + code;
> +    *n = table[idx].len;
> +
> +    return table[idx].sym;
> +}
> +
> +/**
> + * Parse a vlc code.
> + * @param bits is the number of bits which will be read at once, must be
> + *             identical to nb_bits in init_vlc()
> + * @param max_depth is the number of times bits bits must be read to
> completely
> + *                  read the longest vlc code
> + *                  = (max_vlc_length + bits - 1) / bits
> + * If the vlc code is invalid and max_depth=1, then no bits will be
> removed.
> + * If the vlc code is invalid and max_depth>1, then the number of bits
> removed
> + * is undefined.
> + */
> +static inline int bits_read_vlc(BitstreamContext *bc, const VLCElem *table,
> +                                int bits, int max_depth)
> +{
> +    int nb_bits;
> +    unsigned idx = bits_peek(bc, bits);
> +    int code     = table[idx].sym;
> +    int n        = table[idx].len;
> +
> +    if (max_depth > 1 && n < 0) {
> +        bits_priv_skip_remaining(bc, bits);
> +        code = bits_priv_set_idx(bc, code, &n, &nb_bits, table);
> +        if (max_depth > 2 && n < 0) {
> +            bits_priv_skip_remaining(bc, nb_bits);
> +            code = bits_priv_set_idx(bc, code, &n, &nb_bits, table);
> +        }
> +    }
> +    bits_priv_skip_remaining(bc, n);
> +
> +    return code;
> +}
> +
> +#define BITS_RL_VLC(level, run, bc, table, bits, max_depth) \
> +    do {                                                    \
> +        int n, nb_bits;                                     \
> +        unsigned int index = bits_peek(bc, bits);           \
> +        level = table[index].level;                         \
> +        n     = table[index].len;                           \
> +                                                            \
> +        if (max_depth > 1 && n < 0) {                       \
> +            bits_skip(bc, bits);                            \
> +                                                            \
> +            nb_bits = -n;                                   \
> +                                                            \
> +            index = bits_peek(bc, nb_bits) + level;         \
> +            level = table[index].level;                     \
> +            n     = table[index].len;                       \
> +            if (max_depth > 2 && n < 0) {                   \
> +                bits_skip(bc, nb_bits);                     \
> +                nb_bits = -n;                               \
> +                                                            \
> +                index = bits_peek(bc, nb_bits) + level;     \
> +                level = table[index].level;                 \
> +                n     = table[index].len;                   \
> +            }                                               \
> +        }                                                   \
> +        run = table[index].run;                             \
> +        bits_skip(bc, n);                                   \
> +    } while (0)
> +
> +#endif /* AVCODEC_BITSTREAM_H */
> --
> 2.35.1
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
>


NAK
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [FFmpeg-devel] [PATCH v4 1/4] lavc: add standalone cached bitstream reader
  2022-10-22 10:32 [FFmpeg-devel] [PATCH v4 1/4] lavc: add standalone cached bitstream reader Anton Khirnov
                   ` (3 preceding siblings ...)
  2022-10-22 10:37 ` [FFmpeg-devel] [PATCH v4 1/4] lavc: add standalone " Paul B Mahol
@ 2023-01-03 11:19 ` Anton Khirnov
  2023-01-06 10:09   ` Anton Khirnov
  4 siblings, 1 reply; 7+ messages in thread
From: Anton Khirnov @ 2023-01-03 11:19 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Will push in a few days if nobody has further comments.

-- 
Anton Khirnov
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [FFmpeg-devel] [PATCH v4 1/4] lavc: add standalone cached bitstream reader
  2023-01-03 11:19 ` Anton Khirnov
@ 2023-01-06 10:09   ` Anton Khirnov
  0 siblings, 0 replies; 7+ messages in thread
From: Anton Khirnov @ 2023-01-06 10:09 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Quoting Anton Khirnov (2023-01-03 12:19:40)
> Will push in a few days if nobody has further comments.

pushed

-- 
Anton Khirnov
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2023-01-06 10:09 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-22 10:32 [FFmpeg-devel] [PATCH v4 1/4] lavc: add standalone cached bitstream reader Anton Khirnov
2022-10-22 10:32 ` [FFmpeg-devel] [PATCH v4 2/4] lavc/bitstream: templatize for BE/LE Anton Khirnov
2022-10-22 10:32 ` [FFmpeg-devel] [PATCH v4 3/4] lavc/tests: add a cached bitstream reader test Anton Khirnov
2022-10-22 10:32 ` [FFmpeg-devel] [PATCH v4 4/4] lavc/get_bits: add a compat wrapper for the cached bitstream reader Anton Khirnov
2022-10-22 10:37 ` [FFmpeg-devel] [PATCH v4 1/4] lavc: add standalone " Paul B Mahol
2023-01-03 11:19 ` Anton Khirnov
2023-01-06 10:09   ` Anton Khirnov

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git