* [FFmpeg-devel] [PATCH 1/4] get_bits: move check_marker() to mpegvideodec.h
@ 2022-06-23 12:26 Anton Khirnov
2022-06-23 12:26 ` [FFmpeg-devel] [PATCH 2/4] lavc: add standalone cached bitstream reader Anton Khirnov
` (4 more replies)
0 siblings, 5 replies; 15+ messages in thread
From: Anton Khirnov @ 2022-06-23 12:26 UTC (permalink / raw)
To: ffmpeg-devel
It is only used by mpegvideo-based decoders - specifically mpeg12, intelh263,
ituh263, mpeg4video.
---
Resending the set rebased against current master (there conflicts with
2d764069be3b4092dc986467660607d922023332) and with patch 04 skipped, as
Andreas pointed out issues with it. It is not needed by the other
patches, so can be left out for now.
Apparently Paul has withrawn his objections and Lynne approved the
previous iteration on IRC, so will push this in a few days if nobody
objects.
---
libavcodec/get_bits.h | 10 ----------
libavcodec/intelh263dec.c | 1 +
libavcodec/ituh263dec.c | 1 +
libavcodec/mpegvideodec.h | 10 ++++++++++
4 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/libavcodec/get_bits.h b/libavcodec/get_bits.h
index 16f8af5107..9f2b1784d5 100644
--- a/libavcodec/get_bits.h
+++ b/libavcodec/get_bits.h
@@ -610,16 +610,6 @@ static inline unsigned int show_bits_long(GetBitContext *s, int n)
}
}
-static inline int check_marker(void *logctx, GetBitContext *s, const char *msg)
-{
- int bit = get_bits1(s);
- if (!bit)
- av_log(logctx, AV_LOG_INFO, "Marker bit missing at %d of %d %s\n",
- get_bits_count(s) - 1, s->size_in_bits, msg);
-
- return bit;
-}
-
static inline int init_get_bits_xe(GetBitContext *s, const uint8_t *buffer,
int bit_size, int is_le)
{
diff --git a/libavcodec/intelh263dec.c b/libavcodec/intelh263dec.c
index e7e821d3b3..ded0a7f618 100644
--- a/libavcodec/intelh263dec.c
+++ b/libavcodec/intelh263dec.c
@@ -21,6 +21,7 @@
#include "codec_internal.h"
#include "mpegutils.h"
#include "mpegvideo.h"
+#include "mpegvideodec.h"
#include "h263data.h"
#include "h263dec.h"
#include "mpegvideodata.h"
diff --git a/libavcodec/ituh263dec.c b/libavcodec/ituh263dec.c
index f01c942f04..af054360d8 100644
--- a/libavcodec/ituh263dec.c
+++ b/libavcodec/ituh263dec.c
@@ -48,6 +48,7 @@
#include "rv10dec.h"
#include "mpeg4video.h"
#include "mpegvideodata.h"
+#include "mpegvideodec.h"
#include "mpeg4videodec.h"
// The defines below define the number of bits that are read at once for
diff --git a/libavcodec/mpegvideodec.h b/libavcodec/mpegvideodec.h
index 1af8ebac36..10394a616c 100644
--- a/libavcodec/mpegvideodec.h
+++ b/libavcodec/mpegvideodec.h
@@ -67,4 +67,14 @@ static inline int mpeg_get_qscale(MpegEncContext *s)
return qscale << 1;
}
+static inline int check_marker(void *logctx, GetBitContext *s, const char *msg)
+{
+ int bit = get_bits1(s);
+ if (!bit)
+ av_log(logctx, AV_LOG_INFO, "Marker bit missing at %d of %d %s\n",
+ get_bits_count(s) - 1, s->size_in_bits, msg);
+
+ return bit;
+}
+
#endif /* AVCODEC_MPEGVIDEODEC_H */
--
2.34.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] 15+ messages in thread
* [FFmpeg-devel] [PATCH 2/4] lavc: add standalone cached bitstream reader
2022-06-23 12:26 [FFmpeg-devel] [PATCH 1/4] get_bits: move check_marker() to mpegvideodec.h Anton Khirnov
@ 2022-06-23 12:26 ` Anton Khirnov
2022-06-23 18:56 ` Andreas Rheinhardt
` (4 more replies)
2022-06-23 12:26 ` [FFmpeg-devel] [PATCH 3/4] lavc/bitstream: templatize for BE/LE Anton Khirnov
` (3 subsequent siblings)
4 siblings, 5 replies; 15+ messages in thread
From: Anton Khirnov @ 2022-06-23 12:26 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 | 490 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 490 insertions(+)
create mode 100644 libavcodec/bitstream.h
diff --git a/libavcodec/bitstream.h b/libavcodec/bitstream.h
new file mode 100644
index 0000000000..8a710bcecc
--- /dev/null
+++ b/libavcodec/bitstream.h
@@ -0,0 +1,490 @@
+/*
+ * 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/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_left; // number of bits left in bits field
+ unsigned size_in_bits;
+} BitstreamContext;
+
+static inline void refill_64(BitstreamContext *bc)
+{
+#if !UNCHECKED_BITSTREAM_READER
+ if (bc->ptr >= bc->buffer_end)
+ return;
+#endif
+
+#ifdef BITSTREAM_READER_LE
+ bc->bits = AV_RL64(bc->ptr);
+#else
+ bc->bits = AV_RB64(bc->ptr);
+#endif
+ bc->ptr += 8;
+ bc->bits_left = 64;
+}
+
+static inline void refill_32(BitstreamContext *bc)
+{
+#if !UNCHECKED_BITSTREAM_READER
+ if (bc->ptr >= bc->buffer_end)
+ return;
+#endif
+
+#ifdef BITSTREAM_READER_LE
+ bc->bits = (uint64_t)AV_RL32(bc->ptr) << bc->bits_left | bc->bits;
+#else
+ bc->bits = bc->bits | (uint64_t)AV_RB32(bc->ptr) << (32 - bc->bits_left);
+#endif
+ bc->ptr += 4;
+ bc->bits_left += 32;
+}
+
+/**
+ * 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 bitstream_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_left = 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_left = 0;
+ bc->bits = 0;
+
+ 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 bitstream_init8(BitstreamContext *bc, const uint8_t *buffer,
+ unsigned int byte_size)
+{
+ if (byte_size > INT_MAX / 8)
+ return AVERROR_INVALIDDATA;
+ return bitstream_init(bc, buffer, byte_size * 8);
+}
+
+/**
+ * Return number of bits already read.
+ */
+static inline int bitstream_tell(const BitstreamContext *bc)
+{
+ return (bc->ptr - bc->buffer) * 8 - bc->bits_left;
+}
+
+/**
+ * Return buffer size in bits.
+ */
+static inline int bitstream_tell_size(const BitstreamContext *bc)
+{
+ return bc->size_in_bits;
+}
+
+/**
+ * Return the number of the bits left in a buffer.
+ */
+static inline int bitstream_bits_left(const BitstreamContext *bc)
+{
+ return (bc->buffer - bc->ptr) * 8 + bc->size_in_bits + bc->bits_left;
+}
+
+static inline uint64_t get_val(BitstreamContext *bc, unsigned int n)
+{
+ uint64_t ret;
+
+#ifdef BITSTREAM_READER_LE
+ ret = bc->bits & ((UINT64_C(1) << n) - 1);
+ bc->bits >>= n;
+#else
+ ret = bc->bits >> (64 - n);
+ bc->bits <<= n;
+#endif
+ bc->bits_left -= n;
+
+ return ret;
+}
+
+/**
+ * Return one bit from the buffer.
+ */
+static inline unsigned int bitstream_read_bit(BitstreamContext *bc)
+{
+ if (!bc->bits_left)
+ refill_64(bc);
+
+ return get_val(bc, 1);
+}
+
+/**
+ * Return n bits from the buffer, n has to be in the 0-63 range.
+ */
+static inline uint64_t bitstream_read_63(BitstreamContext *bc, unsigned int n)
+{
+ uint64_t ret = 0;
+#ifdef BITSTREAM_READER_LE
+ uint64_t left = 0;
+#endif
+
+ if (!n)
+ return 0;
+
+ if (n > bc->bits_left) {
+ n -= bc->bits_left;
+#ifdef BITSTREAM_READER_LE
+ left = bc->bits_left;
+#endif
+ ret = get_val(bc, bc->bits_left);
+ refill_64(bc);
+ }
+
+#ifdef BITSTREAM_READER_LE
+ ret = get_val(bc, n) << left | ret;
+#else
+ ret = get_val(bc, n) | ret << n;
+#endif
+
+ return ret;
+}
+
+/**
+ * Return n bits from the buffer, n has to be in the 0-32 range.
+ */
+static inline uint32_t bitstream_read(BitstreamContext *bc, unsigned int n)
+{
+ if (!n)
+ return 0;
+
+ if (n > bc->bits_left) {
+ refill_32(bc);
+ if (bc->bits_left < 32)
+ bc->bits_left = n;
+ }
+
+ return get_val(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 bitstream_read_signed(BitstreamContext *bc, unsigned int n)
+{
+ return sign_extend(bitstream_read(bc, n), n);
+}
+
+static inline unsigned int show_val(BitstreamContext *bc, unsigned int n)
+{
+#ifdef BITSTREAM_READER_LE
+ return bc->bits & ((UINT64_C(1) << n) - 1);
+#else
+ return bc->bits >> (64 - n);
+#endif
+}
+
+/**
+ * Return n bits from the buffer but do not change the buffer state.
+ * n has to be in the 0-32 range.
+ */
+static inline unsigned int bitstream_peek(BitstreamContext *bc, unsigned int n)
+{
+ if (n > bc->bits_left)
+ refill_32(bc);
+
+ return show_val(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 bitstream_peek_signed(BitstreamContext *bc, unsigned int n)
+{
+ return sign_extend(bitstream_peek(bc, n), n);
+}
+
+static inline void skip_remaining(BitstreamContext *bc, unsigned int n)
+{
+#ifdef BITSTREAM_READER_LE
+ bc->bits >>= n;
+#else
+ bc->bits <<= n;
+#endif
+ bc->bits_left -= n;
+}
+
+/**
+ * Skip n bits in the buffer.
+ */
+static inline void bitstream_skip(BitstreamContext *bc, unsigned int n)
+{
+ if (n < bc->bits_left)
+ skip_remaining(bc, n);
+ else {
+ n -= bc->bits_left;
+ bc->bits = 0;
+ bc->bits_left = 0;
+
+ if (n >= 64) {
+ unsigned int skip = n / 8;
+
+ n -= skip * 8;
+ bc->ptr += skip;
+ }
+ refill_64(bc);
+ if (n)
+ skip_remaining(bc, n);
+ }
+}
+
+/**
+ * Seek to the given bit position.
+ */
+static inline void bitstream_seek(BitstreamContext *bc, unsigned pos)
+{
+ bc->ptr = bc->buffer;
+ bc->bits = 0;
+ bc->bits_left = 0;
+
+ bitstream_skip(bc, pos);
+}
+
+/**
+ * Skip bits to a byte boundary.
+ */
+static inline const uint8_t *bitstream_align(BitstreamContext *bc)
+{
+ unsigned int n = -bitstream_tell(bc) & 7;
+ if (n)
+ bitstream_skip(bc, n);
+ return bc->buffer + (bitstream_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 bitstream_read_xbits(BitstreamContext *bc, unsigned int n)
+{
+ int32_t cache = bitstream_peek(bc, 32);
+ int sign = ~cache >> 31;
+ 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 bitstream_decode012(BitstreamContext *bc)
+{
+ if (!bitstream_read_bit(bc))
+ return 0;
+ else
+ return bitstream_read_bit(bc) + 1;
+}
+
+/**
+ * Return decoded truncated unary code for the values 2, 1, 0.
+ */
+static inline int bitstream_decode210(BitstreamContext *bc)
+{
+ if (bitstream_read_bit(bc))
+ return 0;
+ else
+ return 2 - bitstream_read_bit(bc);
+}
+
+/* Read sign bit and flip the sign of the provided value accordingly. */
+static inline int bitstream_apply_sign(BitstreamContext *bc, int val)
+{
+ int sign = bitstream_read_signed(bc, 1);
+ return (val ^ sign) - sign;
+}
+
+static inline int bitstream_skip_1stop_8data(BitstreamContext *s)
+{
+ if (bitstream_bits_left(s) <= 0)
+ return AVERROR_INVALIDDATA;
+
+ while (bitstream_read(s, 1)) {
+ bitstream_skip(s, 8);
+ if (bitstream_bits_left(s) <= 0)
+ return AVERROR_INVALIDDATA;
+ }
+
+ return 0;
+}
+
+/* Unwind the cache so a refill_32 can fill it again. */
+static inline void bitstream_unwind(BitstreamContext *bc)
+{
+ int unwind = 4;
+ int unwind_bits = unwind * 8;
+
+ if (bc->bits_left < unwind_bits)
+ return;
+
+ bc->bits >>= unwind_bits;
+ bc->bits <<= unwind_bits;
+ bc->bits_left -= unwind_bits;
+ bc->ptr -= unwind;
+}
+
+/* Unget up to 32 bits. */
+static inline void bitstream_unget(BitstreamContext *bc, uint64_t value,
+ size_t amount)
+{
+ size_t cache_size = sizeof(bc->bits) * 8;
+
+ if (bc->bits_left + amount > cache_size)
+ bitstream_unwind(bc);
+
+ bc->bits = (bc->bits >> amount) | (value << (cache_size - amount));
+ bc->bits_left += amount;
+}
+
+/**
+ * Return the LUT element for the given bitstream configuration.
+ */
+static inline int set_idx(BitstreamContext *bc, int code, int *n, int *nb_bits,
+ const VLCElem *table)
+{
+ unsigned idx;
+
+ *nb_bits = -*n;
+ idx = bitstream_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 bitstream_read_vlc(BitstreamContext *bc, const VLCElem *table,
+ int bits, int max_depth)
+{
+ int nb_bits;
+ unsigned idx = bitstream_peek(bc, bits);
+ int code = table[idx].sym;
+ int n = table[idx].len;
+
+ if (max_depth > 1 && n < 0) {
+ skip_remaining(bc, bits);
+ code = set_idx(bc, code, &n, &nb_bits, table);
+ if (max_depth > 2 && n < 0) {
+ skip_remaining(bc, nb_bits);
+ code = set_idx(bc, code, &n, &nb_bits, table);
+ }
+ }
+ skip_remaining(bc, n);
+
+ return code;
+}
+
+#define BITSTREAM_RL_VLC(level, run, bc, table, bits, max_depth) \
+ do { \
+ int n, nb_bits; \
+ unsigned int index = bitstream_peek(bc, bits); \
+ level = table[index].level; \
+ n = table[index].len; \
+ \
+ if (max_depth > 1 && n < 0) { \
+ bitstream_skip(bc, bits); \
+ \
+ nb_bits = -n; \
+ \
+ index = bitstream_peek(bc, nb_bits) + level; \
+ level = table[index].level; \
+ n = table[index].len; \
+ if (max_depth > 2 && n < 0) { \
+ bitstream_skip(bc, nb_bits); \
+ nb_bits = -n; \
+ \
+ index = bitstream_peek(bc, nb_bits) + level; \
+ level = table[index].level; \
+ n = table[index].len; \
+ } \
+ } \
+ run = table[index].run; \
+ bitstream_skip(bc, n); \
+ } while (0)
+
+#endif /* AVCODEC_BITSTREAM_H */
--
2.34.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] 15+ messages in thread
* [FFmpeg-devel] [PATCH 3/4] lavc/bitstream: templatize for BE/LE
2022-06-23 12:26 [FFmpeg-devel] [PATCH 1/4] get_bits: move check_marker() to mpegvideodec.h Anton Khirnov
2022-06-23 12:26 ` [FFmpeg-devel] [PATCH 2/4] lavc: add standalone cached bitstream reader Anton Khirnov
@ 2022-06-23 12:26 ` Anton Khirnov
2022-06-23 17:43 ` Andreas Rheinhardt
2022-06-23 12:26 ` [FFmpeg-devel] [PATCH 4/4] lavc/get_bits: add a compat wrapper for the cached bitstream reader Anton Khirnov
` (2 subsequent siblings)
4 siblings, 1 reply; 15+ messages in thread
From: Anton Khirnov @ 2022-06-23 12:26 UTC (permalink / raw)
To: ffmpeg-devel
Allows using both BE and LE bitstream readers in the same file.
---
libavcodec/bitstream.h | 379 ++----------------------------
libavcodec/bitstream_template.h | 392 ++++++++++++++++++++++++++++++++
tests/ref/fate/source | 1 +
3 files changed, 415 insertions(+), 357 deletions(-)
create mode 100644 libavcodec/bitstream_template.h
diff --git a/libavcodec/bitstream.h b/libavcodec/bitstream.h
index 8a710bcecc..3fa63695d3 100644
--- a/libavcodec/bitstream.h
+++ b/libavcodec/bitstream.h
@@ -49,88 +49,6 @@ typedef struct BitstreamContext {
unsigned size_in_bits;
} BitstreamContext;
-static inline void refill_64(BitstreamContext *bc)
-{
-#if !UNCHECKED_BITSTREAM_READER
- if (bc->ptr >= bc->buffer_end)
- return;
-#endif
-
-#ifdef BITSTREAM_READER_LE
- bc->bits = AV_RL64(bc->ptr);
-#else
- bc->bits = AV_RB64(bc->ptr);
-#endif
- bc->ptr += 8;
- bc->bits_left = 64;
-}
-
-static inline void refill_32(BitstreamContext *bc)
-{
-#if !UNCHECKED_BITSTREAM_READER
- if (bc->ptr >= bc->buffer_end)
- return;
-#endif
-
-#ifdef BITSTREAM_READER_LE
- bc->bits = (uint64_t)AV_RL32(bc->ptr) << bc->bits_left | bc->bits;
-#else
- bc->bits = bc->bits | (uint64_t)AV_RB32(bc->ptr) << (32 - bc->bits_left);
-#endif
- bc->ptr += 4;
- bc->bits_left += 32;
-}
-
-/**
- * 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 bitstream_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_left = 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_left = 0;
- bc->bits = 0;
-
- 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 bitstream_init8(BitstreamContext *bc, const uint8_t *buffer,
- unsigned int byte_size)
-{
- if (byte_size > INT_MAX / 8)
- return AVERROR_INVALIDDATA;
- return bitstream_init(bc, buffer, byte_size * 8);
-}
-
/**
* Return number of bits already read.
*/
@@ -155,235 +73,6 @@ static inline int bitstream_bits_left(const BitstreamContext *bc)
return (bc->buffer - bc->ptr) * 8 + bc->size_in_bits + bc->bits_left;
}
-static inline uint64_t get_val(BitstreamContext *bc, unsigned int n)
-{
- uint64_t ret;
-
-#ifdef BITSTREAM_READER_LE
- ret = bc->bits & ((UINT64_C(1) << n) - 1);
- bc->bits >>= n;
-#else
- ret = bc->bits >> (64 - n);
- bc->bits <<= n;
-#endif
- bc->bits_left -= n;
-
- return ret;
-}
-
-/**
- * Return one bit from the buffer.
- */
-static inline unsigned int bitstream_read_bit(BitstreamContext *bc)
-{
- if (!bc->bits_left)
- refill_64(bc);
-
- return get_val(bc, 1);
-}
-
-/**
- * Return n bits from the buffer, n has to be in the 0-63 range.
- */
-static inline uint64_t bitstream_read_63(BitstreamContext *bc, unsigned int n)
-{
- uint64_t ret = 0;
-#ifdef BITSTREAM_READER_LE
- uint64_t left = 0;
-#endif
-
- if (!n)
- return 0;
-
- if (n > bc->bits_left) {
- n -= bc->bits_left;
-#ifdef BITSTREAM_READER_LE
- left = bc->bits_left;
-#endif
- ret = get_val(bc, bc->bits_left);
- refill_64(bc);
- }
-
-#ifdef BITSTREAM_READER_LE
- ret = get_val(bc, n) << left | ret;
-#else
- ret = get_val(bc, n) | ret << n;
-#endif
-
- return ret;
-}
-
-/**
- * Return n bits from the buffer, n has to be in the 0-32 range.
- */
-static inline uint32_t bitstream_read(BitstreamContext *bc, unsigned int n)
-{
- if (!n)
- return 0;
-
- if (n > bc->bits_left) {
- refill_32(bc);
- if (bc->bits_left < 32)
- bc->bits_left = n;
- }
-
- return get_val(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 bitstream_read_signed(BitstreamContext *bc, unsigned int n)
-{
- return sign_extend(bitstream_read(bc, n), n);
-}
-
-static inline unsigned int show_val(BitstreamContext *bc, unsigned int n)
-{
-#ifdef BITSTREAM_READER_LE
- return bc->bits & ((UINT64_C(1) << n) - 1);
-#else
- return bc->bits >> (64 - n);
-#endif
-}
-
-/**
- * Return n bits from the buffer but do not change the buffer state.
- * n has to be in the 0-32 range.
- */
-static inline unsigned int bitstream_peek(BitstreamContext *bc, unsigned int n)
-{
- if (n > bc->bits_left)
- refill_32(bc);
-
- return show_val(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 bitstream_peek_signed(BitstreamContext *bc, unsigned int n)
-{
- return sign_extend(bitstream_peek(bc, n), n);
-}
-
-static inline void skip_remaining(BitstreamContext *bc, unsigned int n)
-{
-#ifdef BITSTREAM_READER_LE
- bc->bits >>= n;
-#else
- bc->bits <<= n;
-#endif
- bc->bits_left -= n;
-}
-
-/**
- * Skip n bits in the buffer.
- */
-static inline void bitstream_skip(BitstreamContext *bc, unsigned int n)
-{
- if (n < bc->bits_left)
- skip_remaining(bc, n);
- else {
- n -= bc->bits_left;
- bc->bits = 0;
- bc->bits_left = 0;
-
- if (n >= 64) {
- unsigned int skip = n / 8;
-
- n -= skip * 8;
- bc->ptr += skip;
- }
- refill_64(bc);
- if (n)
- skip_remaining(bc, n);
- }
-}
-
-/**
- * Seek to the given bit position.
- */
-static inline void bitstream_seek(BitstreamContext *bc, unsigned pos)
-{
- bc->ptr = bc->buffer;
- bc->bits = 0;
- bc->bits_left = 0;
-
- bitstream_skip(bc, pos);
-}
-
-/**
- * Skip bits to a byte boundary.
- */
-static inline const uint8_t *bitstream_align(BitstreamContext *bc)
-{
- unsigned int n = -bitstream_tell(bc) & 7;
- if (n)
- bitstream_skip(bc, n);
- return bc->buffer + (bitstream_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 bitstream_read_xbits(BitstreamContext *bc, unsigned int n)
-{
- int32_t cache = bitstream_peek(bc, 32);
- int sign = ~cache >> 31;
- 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 bitstream_decode012(BitstreamContext *bc)
-{
- if (!bitstream_read_bit(bc))
- return 0;
- else
- return bitstream_read_bit(bc) + 1;
-}
-
-/**
- * Return decoded truncated unary code for the values 2, 1, 0.
- */
-static inline int bitstream_decode210(BitstreamContext *bc)
-{
- if (bitstream_read_bit(bc))
- return 0;
- else
- return 2 - bitstream_read_bit(bc);
-}
-
-/* Read sign bit and flip the sign of the provided value accordingly. */
-static inline int bitstream_apply_sign(BitstreamContext *bc, int val)
-{
- int sign = bitstream_read_signed(bc, 1);
- return (val ^ sign) - sign;
-}
-
-static inline int bitstream_skip_1stop_8data(BitstreamContext *s)
-{
- if (bitstream_bits_left(s) <= 0)
- return AVERROR_INVALIDDATA;
-
- while (bitstream_read(s, 1)) {
- bitstream_skip(s, 8);
- if (bitstream_bits_left(s) <= 0)
- return AVERROR_INVALIDDATA;
- }
-
- return 0;
-}
-
/* Unwind the cache so a refill_32 can fill it again. */
static inline void bitstream_unwind(BitstreamContext *bc)
{
@@ -412,52 +101,28 @@ static inline void bitstream_unget(BitstreamContext *bc, uint64_t value,
bc->bits_left += amount;
}
-/**
- * Return the LUT element for the given bitstream configuration.
- */
-static inline int set_idx(BitstreamContext *bc, int code, int *n, int *nb_bits,
- const VLCElem *table)
-{
- unsigned idx;
-
- *nb_bits = -*n;
- idx = bitstream_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 bitstream_read_vlc(BitstreamContext *bc, const VLCElem *table,
- int bits, int max_depth)
-{
- int nb_bits;
- unsigned idx = bitstream_peek(bc, bits);
- int code = table[idx].sym;
- int n = table[idx].len;
-
- if (max_depth > 1 && n < 0) {
- skip_remaining(bc, bits);
- code = set_idx(bc, code, &n, &nb_bits, table);
- if (max_depth > 2 && n < 0) {
- skip_remaining(bc, nb_bits);
- code = set_idx(bc, code, &n, &nb_bits, table);
- }
- }
- skip_remaining(bc, n);
-
- return code;
-}
+#define BITSTREAM_LE
+#include "bitstream_template.h"
+
+#undef BITSTREAM_LE
+#include "bitstream_template.h"
+
+#define bitstream_init bitstream_init_be
+#define bitstream_init8 bitstream_init8_be
+#define bitstream_read_bit bitstream_read_bit_be
+#define bitstream_read_63 bitstream_read_63_be
+#define bitstream_read bitstream_read_be
+#define bitstream_read_signed bitstream_read_signed_be
+#define bitstream_peek bitstream_peek_be
+#define bitstream_peek_signed bitstream_peek_signed_be
+#define bitstream_skip bitstream_skip_be
+#define bitstream_seek bitstream_seek_be
+#define bitstream_align bitstream_align_be
+#define bitstream_read_xbits bitstream_read_xbits_be
+#define bitstream_decode012 bitstream_decode012_be
+#define bitstream_decode210 bitstream_decode210_be
+#define bitstream_apply_sign bitstream_apply_sign_be
+#define bitstream_read_vlc bitstream_read_vlc_be
#define BITSTREAM_RL_VLC(level, run, bc, table, bits, max_depth) \
do { \
diff --git a/libavcodec/bitstream_template.h b/libavcodec/bitstream_template.h
new file mode 100644
index 0000000000..6b31bc53a2
--- /dev/null
+++ b/libavcodec/bitstream_template.h
@@ -0,0 +1,392 @@
+/*
+ * 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
+ */
+
+#ifdef BITSTREAM_LE
+# define BS_SUFFIX le
+#else
+# define BS_SUFFIX be
+#endif
+
+#define BS_JOIN(x, y) x ## _ ## y
+#define BS_FUNC2(x, y) BS_JOIN(x, y)
+#define BS_FUNC(x) BS_FUNC2(x, BS_SUFFIX)
+
+static inline void BS_FUNC(refill_64)(BitstreamContext *bc)
+{
+#if !UNCHECKED_BITSTREAM_READER
+ if (bc->ptr >= bc->buffer_end)
+ return;
+#endif
+
+#ifdef BITSTREAM_LE
+ bc->bits = AV_RL64(bc->ptr);
+#else
+ bc->bits = AV_RB64(bc->ptr);
+#endif
+ bc->ptr += 8;
+ bc->bits_left = 64;
+}
+
+static inline void BS_FUNC(refill_32)(BitstreamContext *bc)
+{
+#if !UNCHECKED_BITSTREAM_READER
+ if (bc->ptr >= bc->buffer_end)
+ return;
+#endif
+
+#ifdef BITSTREAM_LE
+ bc->bits = (uint64_t)AV_RL32(bc->ptr) << bc->bits_left | bc->bits;
+#else
+ bc->bits = bc->bits | (uint64_t)AV_RB32(bc->ptr) << (32 - bc->bits_left);
+#endif
+ bc->ptr += 4;
+ bc->bits_left += 32;
+}
+
+/**
+ * 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 BS_FUNC(bitstream_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_left = 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_left = 0;
+ bc->bits = 0;
+
+ BS_FUNC(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 BS_FUNC(bitstream_init8)(BitstreamContext *bc, const uint8_t *buffer,
+ unsigned int byte_size)
+{
+ if (byte_size > INT_MAX / 8)
+ return AVERROR_INVALIDDATA;
+ return BS_FUNC(bitstream_init)(bc, buffer, byte_size * 8);
+}
+
+static inline uint64_t BS_FUNC(get_val)(BitstreamContext *bc, unsigned int n)
+{
+ uint64_t ret;
+
+#ifdef BITSTREAM_LE
+ ret = bc->bits & ((UINT64_C(1) << n) - 1);
+ bc->bits >>= n;
+#else
+ ret = bc->bits >> (64 - n);
+ bc->bits <<= n;
+#endif
+ bc->bits_left -= n;
+
+ return ret;
+}
+
+/**
+ * Return one bit from the buffer.
+ */
+static inline unsigned int BS_FUNC(bitstream_read_bit)(BitstreamContext *bc)
+{
+ if (!bc->bits_left)
+ BS_FUNC(refill_64)(bc);
+
+ return BS_FUNC(get_val)(bc, 1);
+}
+
+/**
+ * Return n bits from the buffer, n has to be in the 0-63 range.
+ */
+static inline uint64_t BS_FUNC(bitstream_read_63)(BitstreamContext *bc, unsigned int n)
+{
+ uint64_t ret = 0;
+#ifdef BITSTREAM_LE
+ uint64_t left = 0;
+#endif
+
+ if (!n)
+ return 0;
+
+ if (n > bc->bits_left) {
+ n -= bc->bits_left;
+#ifdef BITSTREAM_LE
+ left = bc->bits_left;
+#endif
+ ret = BS_FUNC(get_val)(bc, bc->bits_left);
+ BS_FUNC(refill_64)(bc);
+ }
+
+#ifdef BITSTREAM_LE
+ ret = get_val_le(bc, n) << left | ret;
+#else
+ ret = get_val_be(bc, n) | ret << n;
+#endif
+
+ return ret;
+}
+
+/**
+ * Return n bits from the buffer, n has to be in the 0-32 range.
+ */
+static inline uint32_t BS_FUNC(bitstream_read)(BitstreamContext *bc, unsigned int n)
+{
+ if (!n)
+ return 0;
+
+ if (n > bc->bits_left) {
+ BS_FUNC(refill_32)(bc);
+ if (bc->bits_left < 32)
+ bc->bits_left = n;
+ }
+
+ return BS_FUNC(get_val)(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 BS_FUNC(bitstream_read_signed)(BitstreamContext *bc, unsigned int n)
+{
+ return sign_extend(BS_FUNC(bitstream_read)(bc, n), n);
+}
+
+static inline unsigned int BS_FUNC(show_val)(BitstreamContext *bc, unsigned int n)
+{
+#ifdef BITSTREAM_LE
+ return bc->bits & ((UINT64_C(1) << n) - 1);
+#else
+ return bc->bits >> (64 - n);
+#endif
+}
+
+/**
+ * Return n bits from the buffer but do not change the buffer state.
+ * n has to be in the 0-32 range.
+ */
+static inline unsigned int BS_FUNC(bitstream_peek)(BitstreamContext *bc, unsigned int n)
+{
+ if (n > bc->bits_left)
+ BS_FUNC(refill_32)(bc);
+
+ return BS_FUNC(show_val)(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 BS_FUNC(bitstream_peek_signed)(BitstreamContext *bc, unsigned int n)
+{
+ return sign_extend(BS_FUNC(bitstream_peek)(bc, n), n);
+}
+
+static inline void BS_FUNC(skip_remaining)(BitstreamContext *bc, unsigned int n)
+{
+#ifdef BITSTREAM_LE
+ bc->bits >>= n;
+#else
+ bc->bits <<= n;
+#endif
+ bc->bits_left -= n;
+}
+
+/**
+ * Skip n bits in the buffer.
+ */
+static inline void BS_FUNC(bitstream_skip)(BitstreamContext *bc, unsigned int n)
+{
+ if (n < bc->bits_left)
+ BS_FUNC(skip_remaining)(bc, n);
+ else {
+ n -= bc->bits_left;
+ bc->bits = 0;
+ bc->bits_left = 0;
+
+ if (n >= 64) {
+ unsigned int skip = n / 8;
+
+ n -= skip * 8;
+ bc->ptr += skip;
+ }
+ BS_FUNC(refill_64)(bc);
+ if (n)
+ BS_FUNC(skip_remaining)(bc, n);
+ }
+}
+
+/**
+ * Seek to the given bit position.
+ */
+static inline void BS_FUNC(bitstream_seek)(BitstreamContext *bc, unsigned pos)
+{
+ bc->ptr = bc->buffer;
+ bc->bits = 0;
+ bc->bits_left = 0;
+
+ BS_FUNC(bitstream_skip)(bc, pos);
+}
+
+/**
+ * Skip bits to a byte boundary.
+ */
+static inline const uint8_t *BS_FUNC(bitstream_align)(BitstreamContext *bc)
+{
+ unsigned int n = -bitstream_tell(bc) & 7;
+ if (n)
+ BS_FUNC(bitstream_skip)(bc, n);
+ return bc->buffer + (bitstream_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 BS_FUNC(bitstream_read_xbits)(BitstreamContext *bc, unsigned int n)
+{
+ int32_t cache = BS_FUNC(bitstream_peek)(bc, 32);
+ int sign = ~cache >> 31;
+ BS_FUNC(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 BS_FUNC(bitstream_decode012)(BitstreamContext *bc)
+{
+ if (!BS_FUNC(bitstream_read_bit)(bc))
+ return 0;
+ else
+ return BS_FUNC(bitstream_read_bit)(bc) + 1;
+}
+
+/**
+ * Return decoded truncated unary code for the values 2, 1, 0.
+ */
+static inline int BS_FUNC(bitstream_decode210)(BitstreamContext *bc)
+{
+ if (BS_FUNC(bitstream_read_bit)(bc))
+ return 0;
+ else
+ return 2 - BS_FUNC(bitstream_read_bit)(bc);
+}
+
+/* Read sign bit and flip the sign of the provided value accordingly. */
+static inline int BS_FUNC(bitstream_apply_sign)(BitstreamContext *bc, int val)
+{
+ int sign = BS_FUNC(bitstream_read_signed)(bc, 1);
+ return (val ^ sign) - sign;
+}
+
+static inline int BS_FUNC(bitstream_skip_1stop_8data)(BitstreamContext *s)
+{
+ if (bitstream_bits_left(s) <= 0)
+ return AVERROR_INVALIDDATA;
+
+ while (BS_FUNC(bitstream_read)(s, 1)) {
+ BS_FUNC(bitstream_skip)(s, 8);
+ if (bitstream_bits_left(s) <= 0)
+ return AVERROR_INVALIDDATA;
+ }
+
+ return 0;
+}
+
+/**
+ * Return the LUT element for the given bitstream configuration.
+ */
+static inline int BS_FUNC(set_idx)(BitstreamContext *bc, int code, int *n, int *nb_bits,
+ const VLCElem *table)
+{
+ unsigned idx;
+
+ *nb_bits = -*n;
+ idx = BS_FUNC(bitstream_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 BS_FUNC(bitstream_read_vlc)(BitstreamContext *bc, const VLCElem *table,
+ int bits, int max_depth)
+{
+ int nb_bits;
+ unsigned idx = BS_FUNC(bitstream_peek)(bc, bits);
+ int code = table[idx].sym;
+ int n = table[idx].len;
+
+ if (max_depth > 1 && n < 0) {
+ BS_FUNC(skip_remaining)(bc, bits);
+ code = BS_FUNC(set_idx)(bc, code, &n, &nb_bits, table);
+ if (max_depth > 2 && n < 0) {
+ BS_FUNC(skip_remaining)(bc, nb_bits);
+ code = BS_FUNC(set_idx)(bc, code, &n, &nb_bits, table);
+ }
+ }
+ BS_FUNC(skip_remaining)(bc, n);
+
+ return code;
+}
+
+#undef BS_FUNC
+#undef BS_FUNC2
+#undef BS_JOIN
+#undef BS_SUFFIX
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.34.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] 15+ messages in thread
* [FFmpeg-devel] [PATCH 4/4] lavc/get_bits: add a compat wrapper for the cached bitstream reader
2022-06-23 12:26 [FFmpeg-devel] [PATCH 1/4] get_bits: move check_marker() to mpegvideodec.h Anton Khirnov
2022-06-23 12:26 ` [FFmpeg-devel] [PATCH 2/4] lavc: add standalone cached bitstream reader Anton Khirnov
2022-06-23 12:26 ` [FFmpeg-devel] [PATCH 3/4] lavc/bitstream: templatize for BE/LE Anton Khirnov
@ 2022-06-23 12:26 ` Anton Khirnov
2022-06-23 18:04 ` Andreas Rheinhardt
2022-06-23 17:07 ` [FFmpeg-devel] [PATCH 1/4] get_bits: move check_marker() to mpegvideodec.h Andreas Rheinhardt
2022-06-25 4:43 ` Andreas Rheinhardt
4 siblings, 1 reply; 15+ messages in thread
From: Anton Khirnov @ 2022-06-23 12:26 UTC (permalink / raw)
To: ffmpeg-devel
Use that instead of the merged version.
---
libavcodec/get_bits.h | 297 +++++++-----------------------------------
1 file changed, 50 insertions(+), 247 deletions(-)
diff --git a/libavcodec/get_bits.h b/libavcodec/get_bits.h
index 9f2b1784d5..d9fc794c8c 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.
*
@@ -59,12 +58,43 @@
#define CACHED_BITSTREAM_READER 0
#endif
+#if CACHED_BITSTREAM_READER
+#include "bitstream.h"
+
+#define MIN_CACHE_BITS 64
+
+typedef BitstreamContext GetBitContext;
+
+#define get_bits_count bitstream_tell
+#define get_bits_left bitstream_bits_left
+#define skip_bits_long bitstream_skip
+#define skip_bits bitstream_skip
+#define get_bits bitstream_read
+#define get_bitsz bitstream_read
+#define get_bits_le bitstream_read
+#define get_bits_long bitstream_read
+#define get_bits64 bitstream_read_63
+#define get_xbits bitstream_read_xbits
+#define get_sbits bitstream_read_signed
+#define get_sbits_long bitstream_read_signed
+#define show_bits bitstream_peek
+#define show_bits_long bitstream_peek
+#define init_get_bits bitstream_init
+#define init_get_bits8 bitstream_init8
+#define init_get_bits8_le bitstream_init8_le
+#define align_get_bits bitstream_align
+#define get_vlc2 bitstream_read_vlc
+
+#define get_bits1(s) bitstream_read(s, 1)
+#define show_bits1(s) bitstream_peek(s, 1)
+#define skip_bits1(s) bitstream_skip(s, 1)
+
+#define skip_1stop_8data_bits bitstream_skip_1stop_8data
+
+#else // CACHED_BITSTREAM_READER
+
typedef struct GetBitContext {
const uint8_t *buffer, *buffer_end;
-#if CACHED_BITSTREAM_READER
- uint64_t cache;
- unsigned bits_left;
-#endif
int index;
int size_in_bits;
int size_in_bits_plus8;
@@ -121,16 +151,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
@@ -215,73 +241,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,
@@ -291,28 +256,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).
@@ -321,13 +270,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);
@@ -338,10 +280,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;
@@ -355,22 +295,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;
}
@@ -380,32 +314,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;
}
@@ -420,16 +334,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);
@@ -438,7 +342,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
}
/**
@@ -447,71 +350,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
@@ -528,7 +382,6 @@ static inline unsigned int get_bits1(GetBitContext *s)
s->index = index;
return result;
-#endif
}
static inline unsigned int show_bits1(GetBitContext *s)
@@ -549,10 +402,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 {
@@ -564,7 +413,6 @@ static inline unsigned int get_bits_long(GetBitContext *s, int n)
return ret | get_bits(s, n - 16);
#endif
}
-#endif
}
/**
@@ -610,8 +458,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;
@@ -630,33 +487,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
@@ -678,7 +511,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)
@@ -763,19 +596,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
@@ -788,24 +608,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);
@@ -816,7 +618,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)
@@ -856,4 +657,6 @@ static inline int skip_1stop_8data_bits(GetBitContext *gb)
return 0;
}
+#endif // CACHED_BITSTREAM_READER
+
#endif /* AVCODEC_GET_BITS_H */
--
2.34.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] 15+ messages in thread
* Re: [FFmpeg-devel] [PATCH 1/4] get_bits: move check_marker() to mpegvideodec.h
2022-06-23 12:26 [FFmpeg-devel] [PATCH 1/4] get_bits: move check_marker() to mpegvideodec.h Anton Khirnov
` (2 preceding siblings ...)
2022-06-23 12:26 ` [FFmpeg-devel] [PATCH 4/4] lavc/get_bits: add a compat wrapper for the cached bitstream reader Anton Khirnov
@ 2022-06-23 17:07 ` Andreas Rheinhardt
2022-06-25 4:43 ` Andreas Rheinhardt
4 siblings, 0 replies; 15+ messages in thread
From: Andreas Rheinhardt @ 2022-06-23 17:07 UTC (permalink / raw)
To: ffmpeg-devel
Anton Khirnov:
> It is only used by mpegvideo-based decoders - specifically mpeg12, intelh263,
> ituh263, mpeg4video.
> ---
> Resending the set rebased against current master (there conflicts with
> 2d764069be3b4092dc986467660607d922023332) and with patch 04 skipped, as
> Andreas pointed out issues with it. It is not needed by the other
> patches, so can be left out for now.
>
> Apparently Paul has withrawn his objections and Lynne approved the
> previous iteration on IRC, so will push this in a few days if nobody
> objects.
> ---
> libavcodec/get_bits.h | 10 ----------
> libavcodec/intelh263dec.c | 1 +
> libavcodec/ituh263dec.c | 1 +
> libavcodec/mpegvideodec.h | 10 ++++++++++
> 4 files changed, 12 insertions(+), 10 deletions(-)
>
> diff --git a/libavcodec/get_bits.h b/libavcodec/get_bits.h
> index 16f8af5107..9f2b1784d5 100644
> --- a/libavcodec/get_bits.h
> +++ b/libavcodec/get_bits.h
> @@ -610,16 +610,6 @@ static inline unsigned int show_bits_long(GetBitContext *s, int n)
> }
> }
>
> -static inline int check_marker(void *logctx, GetBitContext *s, const char *msg)
> -{
> - int bit = get_bits1(s);
> - if (!bit)
> - av_log(logctx, AV_LOG_INFO, "Marker bit missing at %d of %d %s\n",
> - get_bits_count(s) - 1, s->size_in_bits, msg);
> -
> - return bit;
> -}
> -
> static inline int init_get_bits_xe(GetBitContext *s, const uint8_t *buffer,
> int bit_size, int is_le)
> {
> diff --git a/libavcodec/intelh263dec.c b/libavcodec/intelh263dec.c
> index e7e821d3b3..ded0a7f618 100644
> --- a/libavcodec/intelh263dec.c
> +++ b/libavcodec/intelh263dec.c
> @@ -21,6 +21,7 @@
> #include "codec_internal.h"
> #include "mpegutils.h"
> #include "mpegvideo.h"
> +#include "mpegvideodec.h"
> #include "h263data.h"
> #include "h263dec.h"
> #include "mpegvideodata.h"
> diff --git a/libavcodec/ituh263dec.c b/libavcodec/ituh263dec.c
> index f01c942f04..af054360d8 100644
> --- a/libavcodec/ituh263dec.c
> +++ b/libavcodec/ituh263dec.c
> @@ -48,6 +48,7 @@
> #include "rv10dec.h"
> #include "mpeg4video.h"
> #include "mpegvideodata.h"
> +#include "mpegvideodec.h"
> #include "mpeg4videodec.h"
>
> // The defines below define the number of bits that are read at once for
> diff --git a/libavcodec/mpegvideodec.h b/libavcodec/mpegvideodec.h
> index 1af8ebac36..10394a616c 100644
> --- a/libavcodec/mpegvideodec.h
> +++ b/libavcodec/mpegvideodec.h
> @@ -67,4 +67,14 @@ static inline int mpeg_get_qscale(MpegEncContext *s)
> return qscale << 1;
> }
>
> +static inline int check_marker(void *logctx, GetBitContext *s, const char *msg)
> +{
> + int bit = get_bits1(s);
> + if (!bit)
> + av_log(logctx, AV_LOG_INFO, "Marker bit missing at %d of %d %s\n",
> + get_bits_count(s) - 1, s->size_in_bits, msg);
> +
> + return bit;
> +}
> +
> #endif /* AVCODEC_MPEGVIDEODEC_H */
LGTM.
- Andreas
_______________________________________________
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] 15+ messages in thread
* Re: [FFmpeg-devel] [PATCH 3/4] lavc/bitstream: templatize for BE/LE
2022-06-23 12:26 ` [FFmpeg-devel] [PATCH 3/4] lavc/bitstream: templatize for BE/LE Anton Khirnov
@ 2022-06-23 17:43 ` Andreas Rheinhardt
2022-06-25 7:53 ` Andreas Rheinhardt
0 siblings, 1 reply; 15+ messages in thread
From: Andreas Rheinhardt @ 2022-06-23 17:43 UTC (permalink / raw)
To: ffmpeg-devel
Anton Khirnov:
> Allows using both BE and LE bitstream readers in the same file.
> ---
> libavcodec/bitstream.h | 379 ++----------------------------
> libavcodec/bitstream_template.h | 392 ++++++++++++++++++++++++++++++++
> tests/ref/fate/source | 1 +
> 3 files changed, 415 insertions(+), 357 deletions(-)
> create mode 100644 libavcodec/bitstream_template.h
>
> diff --git a/libavcodec/bitstream.h b/libavcodec/bitstream.h
> index 8a710bcecc..3fa63695d3 100644
> --- a/libavcodec/bitstream.h
> +++ b/libavcodec/bitstream.h
> @@ -49,88 +49,6 @@ typedef struct BitstreamContext {
> unsigned size_in_bits;
> } BitstreamContext;
You are not templatizing the struct itself. What do you think of the
idea to use two different structs (with the same layout) called
BitstreamContextLE/BE to enable the compiler to warn when one uses a
function with wrong endianness on a given BitstreamContext?
>
> -static inline void refill_64(BitstreamContext *bc)
> -{
> -#if !UNCHECKED_BITSTREAM_READER
> - if (bc->ptr >= bc->buffer_end)
> - return;
> -#endif
> -
> -#ifdef BITSTREAM_READER_LE
> - bc->bits = AV_RL64(bc->ptr);
> -#else
> - bc->bits = AV_RB64(bc->ptr);
> -#endif
> - bc->ptr += 8;
> - bc->bits_left = 64;
> -}
> -
> -static inline void refill_32(BitstreamContext *bc)
> -{
> -#if !UNCHECKED_BITSTREAM_READER
> - if (bc->ptr >= bc->buffer_end)
> - return;
> -#endif
> -
> -#ifdef BITSTREAM_READER_LE
> - bc->bits = (uint64_t)AV_RL32(bc->ptr) << bc->bits_left | bc->bits;
> -#else
> - bc->bits = bc->bits | (uint64_t)AV_RB32(bc->ptr) << (32 - bc->bits_left);
> -#endif
> - bc->ptr += 4;
> - bc->bits_left += 32;
> -}
> -
> -/**
> - * 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 bitstream_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_left = 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_left = 0;
> - bc->bits = 0;
> -
> - 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 bitstream_init8(BitstreamContext *bc, const uint8_t *buffer,
> - unsigned int byte_size)
> -{
> - if (byte_size > INT_MAX / 8)
> - return AVERROR_INVALIDDATA;
> - return bitstream_init(bc, buffer, byte_size * 8);
> -}
> -
> /**
> * Return number of bits already read.
> */
> @@ -155,235 +73,6 @@ static inline int bitstream_bits_left(const BitstreamContext *bc)
> return (bc->buffer - bc->ptr) * 8 + bc->size_in_bits + bc->bits_left;
> }
>
> -static inline uint64_t get_val(BitstreamContext *bc, unsigned int n)
> -{
> - uint64_t ret;
> -
> -#ifdef BITSTREAM_READER_LE
> - ret = bc->bits & ((UINT64_C(1) << n) - 1);
> - bc->bits >>= n;
> -#else
> - ret = bc->bits >> (64 - n);
> - bc->bits <<= n;
> -#endif
> - bc->bits_left -= n;
> -
> - return ret;
> -}
> -
> -/**
> - * Return one bit from the buffer.
> - */
> -static inline unsigned int bitstream_read_bit(BitstreamContext *bc)
> -{
> - if (!bc->bits_left)
> - refill_64(bc);
> -
> - return get_val(bc, 1);
> -}
> -
> -/**
> - * Return n bits from the buffer, n has to be in the 0-63 range.
> - */
> -static inline uint64_t bitstream_read_63(BitstreamContext *bc, unsigned int n)
> -{
> - uint64_t ret = 0;
> -#ifdef BITSTREAM_READER_LE
> - uint64_t left = 0;
> -#endif
> -
> - if (!n)
> - return 0;
> -
> - if (n > bc->bits_left) {
> - n -= bc->bits_left;
> -#ifdef BITSTREAM_READER_LE
> - left = bc->bits_left;
> -#endif
> - ret = get_val(bc, bc->bits_left);
> - refill_64(bc);
> - }
> -
> -#ifdef BITSTREAM_READER_LE
> - ret = get_val(bc, n) << left | ret;
> -#else
> - ret = get_val(bc, n) | ret << n;
> -#endif
> -
> - return ret;
> -}
> -
> -/**
> - * Return n bits from the buffer, n has to be in the 0-32 range.
> - */
> -static inline uint32_t bitstream_read(BitstreamContext *bc, unsigned int n)
> -{
> - if (!n)
> - return 0;
> -
> - if (n > bc->bits_left) {
> - refill_32(bc);
> - if (bc->bits_left < 32)
> - bc->bits_left = n;
> - }
> -
> - return get_val(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 bitstream_read_signed(BitstreamContext *bc, unsigned int n)
> -{
> - return sign_extend(bitstream_read(bc, n), n);
> -}
> -
> -static inline unsigned int show_val(BitstreamContext *bc, unsigned int n)
> -{
> -#ifdef BITSTREAM_READER_LE
> - return bc->bits & ((UINT64_C(1) << n) - 1);
> -#else
> - return bc->bits >> (64 - n);
> -#endif
> -}
> -
> -/**
> - * Return n bits from the buffer but do not change the buffer state.
> - * n has to be in the 0-32 range.
> - */
> -static inline unsigned int bitstream_peek(BitstreamContext *bc, unsigned int n)
> -{
> - if (n > bc->bits_left)
> - refill_32(bc);
> -
> - return show_val(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 bitstream_peek_signed(BitstreamContext *bc, unsigned int n)
> -{
> - return sign_extend(bitstream_peek(bc, n), n);
> -}
> -
> -static inline void skip_remaining(BitstreamContext *bc, unsigned int n)
> -{
> -#ifdef BITSTREAM_READER_LE
> - bc->bits >>= n;
> -#else
> - bc->bits <<= n;
> -#endif
> - bc->bits_left -= n;
> -}
> -
> -/**
> - * Skip n bits in the buffer.
> - */
> -static inline void bitstream_skip(BitstreamContext *bc, unsigned int n)
> -{
> - if (n < bc->bits_left)
> - skip_remaining(bc, n);
> - else {
> - n -= bc->bits_left;
> - bc->bits = 0;
> - bc->bits_left = 0;
> -
> - if (n >= 64) {
> - unsigned int skip = n / 8;
> -
> - n -= skip * 8;
> - bc->ptr += skip;
> - }
> - refill_64(bc);
> - if (n)
> - skip_remaining(bc, n);
> - }
> -}
> -
> -/**
> - * Seek to the given bit position.
> - */
> -static inline void bitstream_seek(BitstreamContext *bc, unsigned pos)
> -{
> - bc->ptr = bc->buffer;
> - bc->bits = 0;
> - bc->bits_left = 0;
> -
> - bitstream_skip(bc, pos);
> -}
> -
> -/**
> - * Skip bits to a byte boundary.
> - */
> -static inline const uint8_t *bitstream_align(BitstreamContext *bc)
> -{
> - unsigned int n = -bitstream_tell(bc) & 7;
> - if (n)
> - bitstream_skip(bc, n);
> - return bc->buffer + (bitstream_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 bitstream_read_xbits(BitstreamContext *bc, unsigned int n)
> -{
> - int32_t cache = bitstream_peek(bc, 32);
> - int sign = ~cache >> 31;
> - 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 bitstream_decode012(BitstreamContext *bc)
> -{
> - if (!bitstream_read_bit(bc))
> - return 0;
> - else
> - return bitstream_read_bit(bc) + 1;
> -}
> -
> -/**
> - * Return decoded truncated unary code for the values 2, 1, 0.
> - */
> -static inline int bitstream_decode210(BitstreamContext *bc)
> -{
> - if (bitstream_read_bit(bc))
> - return 0;
> - else
> - return 2 - bitstream_read_bit(bc);
> -}
> -
> -/* Read sign bit and flip the sign of the provided value accordingly. */
> -static inline int bitstream_apply_sign(BitstreamContext *bc, int val)
> -{
> - int sign = bitstream_read_signed(bc, 1);
> - return (val ^ sign) - sign;
> -}
> -
> -static inline int bitstream_skip_1stop_8data(BitstreamContext *s)
> -{
> - if (bitstream_bits_left(s) <= 0)
> - return AVERROR_INVALIDDATA;
> -
> - while (bitstream_read(s, 1)) {
> - bitstream_skip(s, 8);
> - if (bitstream_bits_left(s) <= 0)
> - return AVERROR_INVALIDDATA;
> - }
> -
> - return 0;
> -}
> -
> /* Unwind the cache so a refill_32 can fill it again. */
> static inline void bitstream_unwind(BitstreamContext *bc)
> {
> @@ -412,52 +101,28 @@ static inline void bitstream_unget(BitstreamContext *bc, uint64_t value,
> bc->bits_left += amount;
> }
>
> -/**
> - * Return the LUT element for the given bitstream configuration.
> - */
> -static inline int set_idx(BitstreamContext *bc, int code, int *n, int *nb_bits,
> - const VLCElem *table)
> -{
> - unsigned idx;
> -
> - *nb_bits = -*n;
> - idx = bitstream_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 bitstream_read_vlc(BitstreamContext *bc, const VLCElem *table,
> - int bits, int max_depth)
> -{
> - int nb_bits;
> - unsigned idx = bitstream_peek(bc, bits);
> - int code = table[idx].sym;
> - int n = table[idx].len;
> -
> - if (max_depth > 1 && n < 0) {
> - skip_remaining(bc, bits);
> - code = set_idx(bc, code, &n, &nb_bits, table);
> - if (max_depth > 2 && n < 0) {
> - skip_remaining(bc, nb_bits);
> - code = set_idx(bc, code, &n, &nb_bits, table);
> - }
> - }
> - skip_remaining(bc, n);
> -
> - return code;
> -}
> +#define BITSTREAM_LE
> +#include "bitstream_template.h"
> +
> +#undef BITSTREAM_LE
> +#include "bitstream_template.h"
This will compile both version and for the overwhelming majority of
files one of them is enough. I think which one should be compiled should
be left to the user, see below.
> +
> +#define bitstream_init bitstream_init_be
> +#define bitstream_init8 bitstream_init8_be
> +#define bitstream_read_bit bitstream_read_bit_be
> +#define bitstream_read_63 bitstream_read_63_be
> +#define bitstream_read bitstream_read_be
> +#define bitstream_read_signed bitstream_read_signed_be
> +#define bitstream_peek bitstream_peek_be
> +#define bitstream_peek_signed bitstream_peek_signed_be
> +#define bitstream_skip bitstream_skip_be
> +#define bitstream_seek bitstream_seek_be
> +#define bitstream_align bitstream_align_be
> +#define bitstream_read_xbits bitstream_read_xbits_be
> +#define bitstream_decode012 bitstream_decode012_be
> +#define bitstream_decode210 bitstream_decode210_be
> +#define bitstream_apply_sign bitstream_apply_sign_be
> +#define bitstream_read_vlc bitstream_read_vlc_be
You are unconditionally making the big-endian version the default
version. This is wrong. Instead you should let the user decide this (by
using an appropriate define that the user can set before including this
header). I'd implement is as follows: The user can set flags
BITSTREAM_LE and/or BITSTREAM_BE to signal which endianness to compile;
if none is set, it is treated as if BITSTREAM_BE were set in line with
the current default. If both are set, the user must define
BITSTREAM_DEFAULT_BE/LE to indicate what shall be the default.
To accomplish this, the part of bitstream.h that includes the template
will have to be outside of ordinary inclusion guards and instead be
guarded by inclusion guards of its own (one for each endianness).
>
> #define BITSTREAM_RL_VLC(level, run, bc, table, bits, max_depth) \
> do { \
> diff --git a/libavcodec/bitstream_template.h b/libavcodec/bitstream_template.h
> new file mode 100644
> index 0000000000..6b31bc53a2
> --- /dev/null
> +++ b/libavcodec/bitstream_template.h
> @@ -0,0 +1,392 @@
> +/*
> + * 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
> + */
> +
> +#ifdef BITSTREAM_LE
> +# define BS_SUFFIX le
> +#else
> +# define BS_SUFFIX be
> +#endif
> +
> +#define BS_JOIN(x, y) x ## _ ## y
> +#define BS_FUNC2(x, y) BS_JOIN(x, y)
> +#define BS_FUNC(x) BS_FUNC2(x, BS_SUFFIX)
> +
> +static inline void BS_FUNC(refill_64)(BitstreamContext *bc)
> +{
> +#if !UNCHECKED_BITSTREAM_READER
> + if (bc->ptr >= bc->buffer_end)
> + return;
> +#endif
> +
> +#ifdef BITSTREAM_LE
> + bc->bits = AV_RL64(bc->ptr);
> +#else
> + bc->bits = AV_RB64(bc->ptr);
> +#endif
> + bc->ptr += 8;
> + bc->bits_left = 64;
> +}
> +
> +static inline void BS_FUNC(refill_32)(BitstreamContext *bc)
> +{
> +#if !UNCHECKED_BITSTREAM_READER
> + if (bc->ptr >= bc->buffer_end)
> + return;
> +#endif
> +
> +#ifdef BITSTREAM_LE
> + bc->bits = (uint64_t)AV_RL32(bc->ptr) << bc->bits_left | bc->bits;
> +#else
> + bc->bits = bc->bits | (uint64_t)AV_RB32(bc->ptr) << (32 - bc->bits_left);
> +#endif
> + bc->ptr += 4;
> + bc->bits_left += 32;
> +}
> +
> +/**
> + * 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 BS_FUNC(bitstream_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_left = 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_left = 0;
> + bc->bits = 0;
> +
> + BS_FUNC(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 BS_FUNC(bitstream_init8)(BitstreamContext *bc, const uint8_t *buffer,
> + unsigned int byte_size)
> +{
> + if (byte_size > INT_MAX / 8)
> + return AVERROR_INVALIDDATA;
> + return BS_FUNC(bitstream_init)(bc, buffer, byte_size * 8);
> +}
> +
> +static inline uint64_t BS_FUNC(get_val)(BitstreamContext *bc, unsigned int n)
> +{
> + uint64_t ret;
> +
> +#ifdef BITSTREAM_LE
> + ret = bc->bits & ((UINT64_C(1) << n) - 1);
> + bc->bits >>= n;
> +#else
> + ret = bc->bits >> (64 - n);
> + bc->bits <<= n;
> +#endif
> + bc->bits_left -= n;
> +
> + return ret;
> +}
> +
> +/**
> + * Return one bit from the buffer.
> + */
> +static inline unsigned int BS_FUNC(bitstream_read_bit)(BitstreamContext *bc)
> +{
> + if (!bc->bits_left)
> + BS_FUNC(refill_64)(bc);
> +
> + return BS_FUNC(get_val)(bc, 1);
> +}
> +
> +/**
> + * Return n bits from the buffer, n has to be in the 0-63 range.
> + */
> +static inline uint64_t BS_FUNC(bitstream_read_63)(BitstreamContext *bc, unsigned int n)
> +{
> + uint64_t ret = 0;
> +#ifdef BITSTREAM_LE
> + uint64_t left = 0;
> +#endif
> +
> + if (!n)
> + return 0;
> +
> + if (n > bc->bits_left) {
> + n -= bc->bits_left;
> +#ifdef BITSTREAM_LE
> + left = bc->bits_left;
> +#endif
> + ret = BS_FUNC(get_val)(bc, bc->bits_left);
> + BS_FUNC(refill_64)(bc);
> + }
> +
> +#ifdef BITSTREAM_LE
> + ret = get_val_le(bc, n) << left | ret;
> +#else
> + ret = get_val_be(bc, n) | ret << n;
> +#endif
> +
> + return ret;
> +}
> +
> +/**
> + * Return n bits from the buffer, n has to be in the 0-32 range.
> + */
> +static inline uint32_t BS_FUNC(bitstream_read)(BitstreamContext *bc, unsigned int n)
> +{
> + if (!n)
> + return 0;
> +
> + if (n > bc->bits_left) {
> + BS_FUNC(refill_32)(bc);
> + if (bc->bits_left < 32)
> + bc->bits_left = n;
> + }
> +
> + return BS_FUNC(get_val)(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 BS_FUNC(bitstream_read_signed)(BitstreamContext *bc, unsigned int n)
> +{
> + return sign_extend(BS_FUNC(bitstream_read)(bc, n), n);
> +}
> +
> +static inline unsigned int BS_FUNC(show_val)(BitstreamContext *bc, unsigned int n)
> +{
> +#ifdef BITSTREAM_LE
> + return bc->bits & ((UINT64_C(1) << n) - 1);
> +#else
> + return bc->bits >> (64 - n);
> +#endif
> +}
> +
> +/**
> + * Return n bits from the buffer but do not change the buffer state.
> + * n has to be in the 0-32 range.
> + */
> +static inline unsigned int BS_FUNC(bitstream_peek)(BitstreamContext *bc, unsigned int n)
> +{
> + if (n > bc->bits_left)
> + BS_FUNC(refill_32)(bc);
> +
> + return BS_FUNC(show_val)(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 BS_FUNC(bitstream_peek_signed)(BitstreamContext *bc, unsigned int n)
> +{
> + return sign_extend(BS_FUNC(bitstream_peek)(bc, n), n);
> +}
> +
> +static inline void BS_FUNC(skip_remaining)(BitstreamContext *bc, unsigned int n)
> +{
> +#ifdef BITSTREAM_LE
> + bc->bits >>= n;
> +#else
> + bc->bits <<= n;
> +#endif
> + bc->bits_left -= n;
> +}
> +
> +/**
> + * Skip n bits in the buffer.
> + */
> +static inline void BS_FUNC(bitstream_skip)(BitstreamContext *bc, unsigned int n)
> +{
> + if (n < bc->bits_left)
> + BS_FUNC(skip_remaining)(bc, n);
> + else {
> + n -= bc->bits_left;
> + bc->bits = 0;
> + bc->bits_left = 0;
> +
> + if (n >= 64) {
> + unsigned int skip = n / 8;
> +
> + n -= skip * 8;
> + bc->ptr += skip;
> + }
> + BS_FUNC(refill_64)(bc);
> + if (n)
> + BS_FUNC(skip_remaining)(bc, n);
> + }
> +}
> +
> +/**
> + * Seek to the given bit position.
> + */
> +static inline void BS_FUNC(bitstream_seek)(BitstreamContext *bc, unsigned pos)
> +{
> + bc->ptr = bc->buffer;
> + bc->bits = 0;
> + bc->bits_left = 0;
> +
> + BS_FUNC(bitstream_skip)(bc, pos);
> +}
> +
> +/**
> + * Skip bits to a byte boundary.
> + */
> +static inline const uint8_t *BS_FUNC(bitstream_align)(BitstreamContext *bc)
> +{
> + unsigned int n = -bitstream_tell(bc) & 7;
> + if (n)
> + BS_FUNC(bitstream_skip)(bc, n);
> + return bc->buffer + (bitstream_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 BS_FUNC(bitstream_read_xbits)(BitstreamContext *bc, unsigned int n)
> +{
> + int32_t cache = BS_FUNC(bitstream_peek)(bc, 32);
> + int sign = ~cache >> 31;
> + BS_FUNC(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 BS_FUNC(bitstream_decode012)(BitstreamContext *bc)
> +{
> + if (!BS_FUNC(bitstream_read_bit)(bc))
> + return 0;
> + else
> + return BS_FUNC(bitstream_read_bit)(bc) + 1;
> +}
> +
> +/**
> + * Return decoded truncated unary code for the values 2, 1, 0.
> + */
> +static inline int BS_FUNC(bitstream_decode210)(BitstreamContext *bc)
> +{
> + if (BS_FUNC(bitstream_read_bit)(bc))
> + return 0;
> + else
> + return 2 - BS_FUNC(bitstream_read_bit)(bc);
> +}
> +
> +/* Read sign bit and flip the sign of the provided value accordingly. */
> +static inline int BS_FUNC(bitstream_apply_sign)(BitstreamContext *bc, int val)
> +{
> + int sign = BS_FUNC(bitstream_read_signed)(bc, 1);
> + return (val ^ sign) - sign;
> +}
> +
> +static inline int BS_FUNC(bitstream_skip_1stop_8data)(BitstreamContext *s)
> +{
> + if (bitstream_bits_left(s) <= 0)
> + return AVERROR_INVALIDDATA;
> +
> + while (BS_FUNC(bitstream_read)(s, 1)) {
> + BS_FUNC(bitstream_skip)(s, 8);
> + if (bitstream_bits_left(s) <= 0)
> + return AVERROR_INVALIDDATA;
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * Return the LUT element for the given bitstream configuration.
> + */
> +static inline int BS_FUNC(set_idx)(BitstreamContext *bc, int code, int *n, int *nb_bits,
> + const VLCElem *table)
> +{
> + unsigned idx;
> +
> + *nb_bits = -*n;
> + idx = BS_FUNC(bitstream_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 BS_FUNC(bitstream_read_vlc)(BitstreamContext *bc, const VLCElem *table,
> + int bits, int max_depth)
> +{
> + int nb_bits;
> + unsigned idx = BS_FUNC(bitstream_peek)(bc, bits);
> + int code = table[idx].sym;
> + int n = table[idx].len;
> +
> + if (max_depth > 1 && n < 0) {
> + BS_FUNC(skip_remaining)(bc, bits);
> + code = BS_FUNC(set_idx)(bc, code, &n, &nb_bits, table);
> + if (max_depth > 2 && n < 0) {
> + BS_FUNC(skip_remaining)(bc, nb_bits);
> + code = BS_FUNC(set_idx)(bc, code, &n, &nb_bits, table);
> + }
> + }
> + BS_FUNC(skip_remaining)(bc, n);
> +
> + return code;
> +}
> +
> +#undef BS_FUNC
> +#undef BS_FUNC2
> +#undef BS_JOIN
> +#undef BS_SUFFIX
> 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:
_______________________________________________
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] 15+ messages in thread
* Re: [FFmpeg-devel] [PATCH 4/4] lavc/get_bits: add a compat wrapper for the cached bitstream reader
2022-06-23 12:26 ` [FFmpeg-devel] [PATCH 4/4] lavc/get_bits: add a compat wrapper for the cached bitstream reader Anton Khirnov
@ 2022-06-23 18:04 ` Andreas Rheinhardt
0 siblings, 0 replies; 15+ messages in thread
From: Andreas Rheinhardt @ 2022-06-23 18:04 UTC (permalink / raw)
To: ffmpeg-devel
Anton Khirnov:
> Use that instead of the merged version.
> ---
> libavcodec/get_bits.h | 297 +++++++-----------------------------------
> 1 file changed, 50 insertions(+), 247 deletions(-)
>
> diff --git a/libavcodec/get_bits.h b/libavcodec/get_bits.h
> index 9f2b1784d5..d9fc794c8c 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.
> *
> @@ -59,12 +58,43 @@
> #define CACHED_BITSTREAM_READER 0
> #endif
>
> +#if CACHED_BITSTREAM_READER
> +#include "bitstream.h"
> +
> +#define MIN_CACHE_BITS 64
Please don't define this. It makes no sense for the cached bitstream reader.
(And several of the uses of this macro for the other bitstream readers
seem highly dubious for me. The worst is bit_copy() in dvdec.c which
would simply not work (or even assert) when one uses a nondefault
getbit-API. apedec, eatgv, proresdec2, tta and wma use this to check
their input for compliance instead of basing their limits on the
underlying specifications.)
> +
> +typedef BitstreamContext GetBitContext;
> +
> +#define get_bits_count bitstream_tell
> +#define get_bits_left bitstream_bits_left
> +#define skip_bits_long bitstream_skip
> +#define skip_bits bitstream_skip
> +#define get_bits bitstream_read
This will add a check for bits == 0 to every get_bits() for which the
compiler can't infer that it is not zero at compile-time. This is
unacceptable.
> +#define get_bitsz bitstream_read
> +#define get_bits_le bitstream_read
Patch 3/4 intended to make it possible to use both LE and BE in the same
file; and now you define this here. This is wrong and will break the
parts of utvideodec.c that use get_bits_le() (they are uncovered by FATE).
> +#define get_bits_long bitstream_read
> +#define get_bits64 bitstream_read_63
> +#define get_xbits bitstream_read_xbits
> +#define get_sbits bitstream_read_signed
> +#define get_sbits_long bitstream_read_signed
> +#define show_bits bitstream_peek
> +#define show_bits_long bitstream_peek
> +#define init_get_bits bitstream_init
> +#define init_get_bits8 bitstream_init8
> +#define init_get_bits8_le bitstream_init8_le
> +#define align_get_bits bitstream_align
> +#define get_vlc2 bitstream_read_vlc
> +
> +#define get_bits1(s) bitstream_read(s, 1)
Why not bitstream_read_bit?
> +#define show_bits1(s) bitstream_peek(s, 1)
> +#define skip_bits1(s) bitstream_skip(s, 1)
> +
> +#define skip_1stop_8data_bits bitstream_skip_1stop_8data
> +
> +#else // CACHED_BITSTREAM_READER
> +
> typedef struct GetBitContext {
> const uint8_t *buffer, *buffer_end;
> -#if CACHED_BITSTREAM_READER
> - uint64_t cache;
> - unsigned bits_left;
> -#endif
> int index;
> int size_in_bits;
> int size_in_bits_plus8;
> @@ -121,16 +151,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
> @@ -215,73 +241,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,
> @@ -291,28 +256,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).
> @@ -321,13 +270,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);
> @@ -338,10 +280,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;
> @@ -355,22 +295,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;
> }
>
> @@ -380,32 +314,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;
> }
> @@ -420,16 +334,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);
> @@ -438,7 +342,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
> }
>
> /**
> @@ -447,71 +350,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
> @@ -528,7 +382,6 @@ static inline unsigned int get_bits1(GetBitContext *s)
> s->index = index;
>
> return result;
> -#endif
> }
>
> static inline unsigned int show_bits1(GetBitContext *s)
> @@ -549,10 +402,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 {
> @@ -564,7 +413,6 @@ static inline unsigned int get_bits_long(GetBitContext *s, int n)
> return ret | get_bits(s, n - 16);
> #endif
> }
> -#endif
> }
>
> /**
> @@ -610,8 +458,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;
> @@ -630,33 +487,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
> @@ -678,7 +511,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)
> @@ -763,19 +596,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
> @@ -788,24 +608,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);
> @@ -816,7 +618,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)
> @@ -856,4 +657,6 @@ static inline int skip_1stop_8data_bits(GetBitContext *gb)
> return 0;
> }
>
> +#endif // CACHED_BITSTREAM_READER
> +
> #endif /* AVCODEC_GET_BITS_H */
_______________________________________________
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] 15+ messages in thread
* Re: [FFmpeg-devel] [PATCH 2/4] lavc: add standalone cached bitstream reader
2022-06-23 12:26 ` [FFmpeg-devel] [PATCH 2/4] lavc: add standalone cached bitstream reader Anton Khirnov
@ 2022-06-23 18:56 ` Andreas Rheinhardt
2022-06-24 12:08 ` Andreas Rheinhardt
2022-06-24 10:18 ` Andreas Rheinhardt
` (3 subsequent siblings)
4 siblings, 1 reply; 15+ messages in thread
From: Andreas Rheinhardt @ 2022-06-23 18:56 UTC (permalink / raw)
To: ffmpeg-devel
Anton Khirnov:
> 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 | 490 +++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 490 insertions(+)
> create mode 100644 libavcodec/bitstream.h
>
> diff --git a/libavcodec/bitstream.h b/libavcodec/bitstream.h
> new file mode 100644
> index 0000000000..8a710bcecc
> --- /dev/null
> +++ b/libavcodec/bitstream.h
> @@ -0,0 +1,490 @@
> +/*
> + * 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/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_left; // number of bits left in bits field
> + unsigned size_in_bits;
> +} BitstreamContext;
> +
> +static inline void refill_64(BitstreamContext *bc)
> +{
> +#if !UNCHECKED_BITSTREAM_READER
> + if (bc->ptr >= bc->buffer_end)
> + return;
> +#endif
> +
> +#ifdef BITSTREAM_READER_LE
> + bc->bits = AV_RL64(bc->ptr);
> +#else
> + bc->bits = AV_RB64(bc->ptr);
> +#endif
> + bc->ptr += 8;
> + bc->bits_left = 64;
> +}
> +
> +static inline void refill_32(BitstreamContext *bc)
> +{
> +#if !UNCHECKED_BITSTREAM_READER
> + if (bc->ptr >= bc->buffer_end)
> + return;
> +#endif
> +
> +#ifdef BITSTREAM_READER_LE
> + bc->bits = (uint64_t)AV_RL32(bc->ptr) << bc->bits_left | bc->bits;
> +#else
> + bc->bits = bc->bits | (uint64_t)AV_RB32(bc->ptr) << (32 - bc->bits_left);
> +#endif
> + bc->ptr += 4;
> + bc->bits_left += 32;
> +}
> +
> +/**
> + * 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 bitstream_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_left = 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_left = 0;
> + bc->bits = 0;
> +
> + 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 bitstream_init8(BitstreamContext *bc, const uint8_t *buffer,
> + unsigned int byte_size)
> +{
> + if (byte_size > INT_MAX / 8)
> + return AVERROR_INVALIDDATA;
> + return bitstream_init(bc, buffer, byte_size * 8);
> +}
> +
> +/**
> + * Return number of bits already read.
> + */
> +static inline int bitstream_tell(const BitstreamContext *bc)
> +{
> + return (bc->ptr - bc->buffer) * 8 - bc->bits_left;
> +}
> +
> +/**
> + * Return buffer size in bits.
> + */
> +static inline int bitstream_tell_size(const BitstreamContext *bc)
> +{
> + return bc->size_in_bits;
> +}
> +
> +/**
> + * Return the number of the bits left in a buffer.
> + */
> +static inline int bitstream_bits_left(const BitstreamContext *bc)
> +{
> + return (bc->buffer - bc->ptr) * 8 + bc->size_in_bits + bc->bits_left;
> +}
> +
> +static inline uint64_t get_val(BitstreamContext *bc, unsigned int n)
> +{
> + uint64_t ret;
> +
> +#ifdef BITSTREAM_READER_LE
> + ret = bc->bits & ((UINT64_C(1) << n) - 1);
> + bc->bits >>= n;
> +#else
> + ret = bc->bits >> (64 - n);
> + bc->bits <<= n;
> +#endif
> + bc->bits_left -= n;
> +
> + return ret;
> +}
> +
> +/**
> + * Return one bit from the buffer.
> + */
> +static inline unsigned int bitstream_read_bit(BitstreamContext *bc)
> +{
> + if (!bc->bits_left)
> + refill_64(bc);
> +
> + return get_val(bc, 1);
> +}
> +
> +/**
> + * Return n bits from the buffer, n has to be in the 0-63 range.
get_bits64() can read up to 64 bits. This discrepancy won't lead to
immediate trouble as no caller calls it with 64 bits. But it's not nice.
> + */
> +static inline uint64_t bitstream_read_63(BitstreamContext *bc, unsigned int n)
> +{
> + uint64_t ret = 0;
> +#ifdef BITSTREAM_READER_LE
> + uint64_t left = 0;
uint64_t for something that is supposed to be 0..64 range.
> +#endif
> +
> + if (!n)
> + return 0;
> +
> + if (n > bc->bits_left) {
> + n -= bc->bits_left;
> +#ifdef BITSTREAM_READER_LE
> + left = bc->bits_left;
> +#endif
> + ret = get_val(bc, bc->bits_left);
> + refill_64(bc);
> + }
> +
> +#ifdef BITSTREAM_READER_LE
> + ret = get_val(bc, n) << left | ret;
> +#else
> + ret = get_val(bc, n) | ret << n;
If the above refill_64 fails due to eos, then get_val() is called
despite there being less than n bits left. get_bits64() does not suffer
from this.
> +#endif
> +
> + return ret;
> +}
> +
> +/**
> + * Return n bits from the buffer, n has to be in the 0-32 range.
Why doesn't this whole patch(set) not use av_assert2s to check all these
restrictions?
> + */
> +static inline uint32_t bitstream_read(BitstreamContext *bc, unsigned int n)
> +{
> + if (!n)
> + return 0;
This makes this function a get_bitsz equivalent. Why is there no
get_bits() equivalent for the cases where it is known that n is not
zero, but where it is impossible for the compiler to know?
> +
> + if (n > bc->bits_left) {
> + refill_32(bc);
> + if (bc->bits_left < 32)
> + bc->bits_left = n;
> + }
> +
> + return get_val(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 bitstream_read_signed(BitstreamContext *bc, unsigned int n)
> +{
> + return sign_extend(bitstream_read(bc, n), n);
> +}
> +
> +static inline unsigned int show_val(BitstreamContext *bc, unsigned int n)
> +{
> +#ifdef BITSTREAM_READER_LE
> + return bc->bits & ((UINT64_C(1) << n) - 1);
> +#else
> + return bc->bits >> (64 - n);
> +#endif
> +}
> +
> +/**
> + * Return n bits from the buffer but do not change the buffer state.
> + * n has to be in the 0-32 range.
> + */
> +static inline unsigned int bitstream_peek(BitstreamContext *bc, unsigned int n)
> +{
> + if (n > bc->bits_left)
> + refill_32(bc);
> +
> + return show_val(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 bitstream_peek_signed(BitstreamContext *bc, unsigned int n)
> +{
> + return sign_extend(bitstream_peek(bc, n), n);
> +}
> +
> +static inline void skip_remaining(BitstreamContext *bc, unsigned int n)
> +{
> +#ifdef BITSTREAM_READER_LE
> + bc->bits >>= n;
> +#else
> + bc->bits <<= n;
> +#endif
> + bc->bits_left -= n;
> +}
> +
> +/**
> + * Skip n bits in the buffer.
> + */
> +static inline void bitstream_skip(BitstreamContext *bc, unsigned int n)
> +{
> + if (n < bc->bits_left)
> + skip_remaining(bc, n);
> + else {
> + n -= bc->bits_left;
> + bc->bits = 0;
> + bc->bits_left = 0;
> +
> + if (n >= 64) {
> + unsigned int skip = n / 8;
> +
> + n -= skip * 8;
> + bc->ptr += skip;
> + }
> + refill_64(bc);
> + if (n)
> + skip_remaining(bc, n);
> + }
> +}
> +
> +/**
> + * Seek to the given bit position.
> + */
> +static inline void bitstream_seek(BitstreamContext *bc, unsigned pos)
> +{
> + bc->ptr = bc->buffer;
> + bc->bits = 0;
> + bc->bits_left = 0;
> +
> + bitstream_skip(bc, pos);
> +}
> +
> +/**
> + * Skip bits to a byte boundary.
> + */
> +static inline const uint8_t *bitstream_align(BitstreamContext *bc)
> +{
> + unsigned int n = -bitstream_tell(bc) & 7;
> + if (n)
> + bitstream_skip(bc, n);
> + return bc->buffer + (bitstream_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 bitstream_read_xbits(BitstreamContext *bc, unsigned int n)
> +{
> + int32_t cache = bitstream_peek(bc, 32);
> + int sign = ~cache >> 31;
> + 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 bitstream_decode012(BitstreamContext *bc)
> +{
> + if (!bitstream_read_bit(bc))
> + return 0;
> + else
> + return bitstream_read_bit(bc) + 1;
> +}
> +
> +/**
> + * Return decoded truncated unary code for the values 2, 1, 0.
> + */
> +static inline int bitstream_decode210(BitstreamContext *bc)
> +{
> + if (bitstream_read_bit(bc))
> + return 0;
> + else
> + return 2 - bitstream_read_bit(bc);
> +}
> +
> +/* Read sign bit and flip the sign of the provided value accordingly. */
> +static inline int bitstream_apply_sign(BitstreamContext *bc, int val)
> +{
> + int sign = bitstream_read_signed(bc, 1);
> + return (val ^ sign) - sign;
> +}
> +
> +static inline int bitstream_skip_1stop_8data(BitstreamContext *s)
> +{
> + if (bitstream_bits_left(s) <= 0)
> + return AVERROR_INVALIDDATA;
> +
> + while (bitstream_read(s, 1)) {
> + bitstream_skip(s, 8);
> + if (bitstream_bits_left(s) <= 0)
> + return AVERROR_INVALIDDATA;
> + }
> +
> + return 0;
> +}
> +
> +/* Unwind the cache so a refill_32 can fill it again. */
> +static inline void bitstream_unwind(BitstreamContext *bc)
> +{
> + int unwind = 4;
> + int unwind_bits = unwind * 8;
I'm surprised that you used signed types here.
> +
> + if (bc->bits_left < unwind_bits)
> + return;
> +
> + bc->bits >>= unwind_bits;
> + bc->bits <<= unwind_bits;
The above won't work in LE. Best to call skip_remaining here. And you
need to templatize this function in 3/4.
> + bc->bits_left -= unwind_bits;
> + bc->ptr -= unwind;
> +}
> +
> +/* Unget up to 32 bits. */
> +static inline void bitstream_unget(BitstreamContext *bc, uint64_t value,
> + size_t amount)
size_t is the natural type for the bytesize of objects, but not for
bitsizes. A plane unsigned would be more natural here.
> +{
> + size_t cache_size = sizeof(bc->bits) * 8;
> +
> + if (bc->bits_left + amount > cache_size)
> + bitstream_unwind(bc);
> +
> + bc->bits = (bc->bits >> amount) | (value << (cache_size - amount));
This is big-endian only, too.
> + bc->bits_left += amount;
> +}
> +
> +/**
> + * Return the LUT element for the given bitstream configuration.
> + */
> +static inline int set_idx(BitstreamContext *bc, int code, int *n, int *nb_bits,
> + const VLCElem *table)
> +{
> + unsigned idx;
> +
> + *nb_bits = -*n;
> + idx = bitstream_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 bitstream_read_vlc(BitstreamContext *bc, const VLCElem *table,
> + int bits, int max_depth)
> +{
> + int nb_bits;
> + unsigned idx = bitstream_peek(bc, bits);
> + int code = table[idx].sym;
> + int n = table[idx].len;
> +
> + if (max_depth > 1 && n < 0) {
> + skip_remaining(bc, bits);
> + code = set_idx(bc, code, &n, &nb_bits, table);
> + if (max_depth > 2 && n < 0) {
> + skip_remaining(bc, nb_bits);
> + code = set_idx(bc, code, &n, &nb_bits, table);
> + }
> + }
> + skip_remaining(bc, n);
> +
> + return code;
> +}
> +
> +#define BITSTREAM_RL_VLC(level, run, bc, table, bits, max_depth) \
> + do { \
> + int n, nb_bits; \
> + unsigned int index = bitstream_peek(bc, bits); \
> + level = table[index].level; \
> + n = table[index].len; \
> + \
> + if (max_depth > 1 && n < 0) { \
> + bitstream_skip(bc, bits); \
> + \
> + nb_bits = -n; \
> + \
> + index = bitstream_peek(bc, nb_bits) + level; \
> + level = table[index].level; \
> + n = table[index].len; \
> + if (max_depth > 2 && n < 0) { \
> + bitstream_skip(bc, nb_bits); \
> + nb_bits = -n; \
> + \
> + index = bitstream_peek(bc, nb_bits) + level; \
> + level = table[index].level; \
> + n = table[index].len; \
> + } \
> + } \
> + run = table[index].run; \
> + bitstream_skip(bc, n); \
> + } while (0)
> +
> +#endif /* AVCODEC_BITSTREAM_H */
_______________________________________________
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] 15+ messages in thread
* Re: [FFmpeg-devel] [PATCH 2/4] lavc: add standalone cached bitstream reader
2022-06-23 12:26 ` [FFmpeg-devel] [PATCH 2/4] lavc: add standalone cached bitstream reader Anton Khirnov
2022-06-23 18:56 ` Andreas Rheinhardt
@ 2022-06-24 10:18 ` Andreas Rheinhardt
2022-06-24 12:30 ` Andreas Rheinhardt
` (2 subsequent siblings)
4 siblings, 0 replies; 15+ messages in thread
From: Andreas Rheinhardt @ 2022-06-24 10:18 UTC (permalink / raw)
To: ffmpeg-devel
Anton Khirnov:
> +/**
> + * Return n bits from the buffer, n has to be in the 0-32 range.
> + */
> +static inline uint32_t bitstream_read(BitstreamContext *bc, unsigned int n)
> +{
> + if (!n)
> + return 0;
> +
> + if (n > bc->bits_left) {
> + refill_32(bc);
> + if (bc->bits_left < 32)
> + bc->bits_left = n;
This branch should be under #if !UNCHECKED_BITSTREAM_READER.
> + }
> +
> + return get_val(bc, n);
> +}
> +
_______________________________________________
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] 15+ messages in thread
* Re: [FFmpeg-devel] [PATCH 2/4] lavc: add standalone cached bitstream reader
2022-06-23 18:56 ` Andreas Rheinhardt
@ 2022-06-24 12:08 ` Andreas Rheinhardt
0 siblings, 0 replies; 15+ messages in thread
From: Andreas Rheinhardt @ 2022-06-24 12:08 UTC (permalink / raw)
To: ffmpeg-devel
Andreas Rheinhardt:
> Anton Khirnov:
>> +/* Unwind the cache so a refill_32 can fill it again. */
>> +static inline void bitstream_unwind(BitstreamContext *bc)
>> +{
>> + int unwind = 4;
>> + int unwind_bits = unwind * 8;
>
> I'm surprised that you used signed types here.
>
>> +
>> + if (bc->bits_left < unwind_bits)
>> + return;
>> +
>> + bc->bits >>= unwind_bits;
>> + bc->bits <<= unwind_bits;
>
> The above won't work in LE. Best to call skip_remaining here. And you
> need to templatize this function in 3/4.
Calling skip_remaining is wrong either. Both the above (for BE) as well
as skip_remaining would skip the oldest 32 bits in the cache, but we
need to skip the newest 32 bits in the cache. So the following should do it:
bc->bits_left -= unwind_bits;
bc->ptr -= unwind;
#ifdef BITSTREAM_READER_LE
bc->bits &= ((UINT64_C(1) << bc->bits_left) - 1);
#else
bc->bits &= ~(UINT64_T_MAX >> bc->bits_left);
#endif
(Given that bc->bits_left can be 0 one can't simply shift by 64 -
bits_left. I also don't know whether there should be any check before
decrementing ptr.)
>
>> + bc->bits_left -= unwind_bits;
>> + bc->ptr -= unwind;
>> +}
>> +
>> +/* Unget up to 32 bits. */
>> +static inline void bitstream_unget(BitstreamContext *bc, uint64_t value,
>> + size_t amount)
>
> size_t is the natural type for the bytesize of objects, but not for
> bitsizes. A plane unsigned would be more natural here.
>
>> +{
>> + size_t cache_size = sizeof(bc->bits) * 8;
>> +
>> + if (bc->bits_left + amount > cache_size)
>> + bitstream_unwind(bc);
>> +
>> + bc->bits = (bc->bits >> amount) | (value << (cache_size - amount));
>
> This is big-endian only, too.
>
>> + bc->bits_left += amount;
>> +}
>> +
_______________________________________________
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] 15+ messages in thread
* Re: [FFmpeg-devel] [PATCH 2/4] lavc: add standalone cached bitstream reader
2022-06-23 12:26 ` [FFmpeg-devel] [PATCH 2/4] lavc: add standalone cached bitstream reader Anton Khirnov
2022-06-23 18:56 ` Andreas Rheinhardt
2022-06-24 10:18 ` Andreas Rheinhardt
@ 2022-06-24 12:30 ` Andreas Rheinhardt
2022-06-30 9:18 ` Anton Khirnov
2022-06-30 12:16 ` Anton Khirnov
4 siblings, 0 replies; 15+ messages in thread
From: Andreas Rheinhardt @ 2022-06-24 12:30 UTC (permalink / raw)
To: ffmpeg-devel
Anton Khirnov:
> 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>
> ---
One thing I wanted to tell in all my previous mails, but forgot: The
bitstream prefix is way too long. Why not use just e.g. bits? The only
function whose name starts with "bits_" is bits_to_store in
lavc/sonic.c, so clashes are not an issue.
- Andreas
_______________________________________________
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] 15+ messages in thread
* Re: [FFmpeg-devel] [PATCH 1/4] get_bits: move check_marker() to mpegvideodec.h
2022-06-23 12:26 [FFmpeg-devel] [PATCH 1/4] get_bits: move check_marker() to mpegvideodec.h Anton Khirnov
` (3 preceding siblings ...)
2022-06-23 17:07 ` [FFmpeg-devel] [PATCH 1/4] get_bits: move check_marker() to mpegvideodec.h Andreas Rheinhardt
@ 2022-06-25 4:43 ` Andreas Rheinhardt
4 siblings, 0 replies; 15+ messages in thread
From: Andreas Rheinhardt @ 2022-06-25 4:43 UTC (permalink / raw)
To: ffmpeg-devel
Anton Khirnov:
> It is only used by mpegvideo-based decoders - specifically mpeg12, intelh263,
> ituh263, mpeg4video.
> ---
> Resending the set rebased against current master (there conflicts with
> 2d764069be3b4092dc986467660607d922023332) and with patch 04 skipped, as
> Andreas pointed out issues with it. It is not needed by the other
> patches, so can be left out for now.
>
> Apparently Paul has withrawn his objections and Lynne approved the
> previous iteration on IRC, so will push this in a few days if nobody
> objects.
> ---
> libavcodec/get_bits.h | 10 ----------
> libavcodec/intelh263dec.c | 1 +
> libavcodec/ituh263dec.c | 1 +
> libavcodec/mpegvideodec.h | 10 ++++++++++
> 4 files changed, 12 insertions(+), 10 deletions(-)
>
> diff --git a/libavcodec/get_bits.h b/libavcodec/get_bits.h
> index 16f8af5107..9f2b1784d5 100644
> --- a/libavcodec/get_bits.h
> +++ b/libavcodec/get_bits.h
> @@ -610,16 +610,6 @@ static inline unsigned int show_bits_long(GetBitContext *s, int n)
> }
> }
>
> -static inline int check_marker(void *logctx, GetBitContext *s, const char *msg)
> -{
> - int bit = get_bits1(s);
> - if (!bit)
> - av_log(logctx, AV_LOG_INFO, "Marker bit missing at %d of %d %s\n",
> - get_bits_count(s) - 1, s->size_in_bits, msg);
> -
> - return bit;
> -}
> -
> static inline int init_get_bits_xe(GetBitContext *s, const uint8_t *buffer,
> int bit_size, int is_le)
> {
> diff --git a/libavcodec/intelh263dec.c b/libavcodec/intelh263dec.c
> index e7e821d3b3..ded0a7f618 100644
> --- a/libavcodec/intelh263dec.c
> +++ b/libavcodec/intelh263dec.c
> @@ -21,6 +21,7 @@
> #include "codec_internal.h"
> #include "mpegutils.h"
> #include "mpegvideo.h"
> +#include "mpegvideodec.h"
> #include "h263data.h"
> #include "h263dec.h"
> #include "mpegvideodata.h"
> diff --git a/libavcodec/ituh263dec.c b/libavcodec/ituh263dec.c
> index f01c942f04..af054360d8 100644
> --- a/libavcodec/ituh263dec.c
> +++ b/libavcodec/ituh263dec.c
> @@ -48,6 +48,7 @@
> #include "rv10dec.h"
> #include "mpeg4video.h"
> #include "mpegvideodata.h"
> +#include "mpegvideodec.h"
> #include "mpeg4videodec.h"
>
> // The defines below define the number of bits that are read at once for
> diff --git a/libavcodec/mpegvideodec.h b/libavcodec/mpegvideodec.h
> index 1af8ebac36..10394a616c 100644
> --- a/libavcodec/mpegvideodec.h
> +++ b/libavcodec/mpegvideodec.h
> @@ -67,4 +67,14 @@ static inline int mpeg_get_qscale(MpegEncContext *s)
> return qscale << 1;
> }
>
> +static inline int check_marker(void *logctx, GetBitContext *s, const char *msg)
> +{
> + int bit = get_bits1(s);
> + if (!bit)
> + av_log(logctx, AV_LOG_INFO, "Marker bit missing at %d of %d %s\n",
> + get_bits_count(s) - 1, s->size_in_bits, msg);
> +
> + return bit;
> +}
> +
> #endif /* AVCODEC_MPEGVIDEODEC_H */
I think you can now remove log.h from get_bits.h. That always bothered me.
- Andreas
_______________________________________________
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] 15+ messages in thread
* Re: [FFmpeg-devel] [PATCH 3/4] lavc/bitstream: templatize for BE/LE
2022-06-23 17:43 ` Andreas Rheinhardt
@ 2022-06-25 7:53 ` Andreas Rheinhardt
0 siblings, 0 replies; 15+ messages in thread
From: Andreas Rheinhardt @ 2022-06-25 7:53 UTC (permalink / raw)
To: ffmpeg-devel
Andreas Rheinhardt:
> Anton Khirnov:
>> Allows using both BE and LE bitstream readers in the same file.
>> ---
>> libavcodec/bitstream.h | 379 ++----------------------------
>> libavcodec/bitstream_template.h | 392 ++++++++++++++++++++++++++++++++
>> tests/ref/fate/source | 1 +
>> 3 files changed, 415 insertions(+), 357 deletions(-)
>> create mode 100644 libavcodec/bitstream_template.h
>>
>> diff --git a/libavcodec/bitstream.h b/libavcodec/bitstream.h
>> index 8a710bcecc..3fa63695d3 100644
>> --- a/libavcodec/bitstream.h
>> +++ b/libavcodec/bitstream.h
>> @@ -49,88 +49,6 @@ typedef struct BitstreamContext {
>> unsigned size_in_bits;
>> } BitstreamContext;
>
> You are not templatizing the struct itself. What do you think of the
> idea to use two different structs (with the same layout) called
> BitstreamContextLE/BE to enable the compiler to warn when one uses a
> function with wrong endianness on a given BitstreamContext?
>
>>
>> -static inline void refill_64(BitstreamContext *bc)
>> -{
>> -#if !UNCHECKED_BITSTREAM_READER
>> - if (bc->ptr >= bc->buffer_end)
>> - return;
>> -#endif
>> -
>> -#ifdef BITSTREAM_READER_LE
>> - bc->bits = AV_RL64(bc->ptr);
>> -#else
>> - bc->bits = AV_RB64(bc->ptr);
>> -#endif
>> - bc->ptr += 8;
>> - bc->bits_left = 64;
>> -}
>> -
>> -static inline void refill_32(BitstreamContext *bc)
>> -{
>> -#if !UNCHECKED_BITSTREAM_READER
>> - if (bc->ptr >= bc->buffer_end)
>> - return;
>> -#endif
>> -
>> -#ifdef BITSTREAM_READER_LE
>> - bc->bits = (uint64_t)AV_RL32(bc->ptr) << bc->bits_left | bc->bits;
>> -#else
>> - bc->bits = bc->bits | (uint64_t)AV_RB32(bc->ptr) << (32 - bc->bits_left);
>> -#endif
>> - bc->ptr += 4;
>> - bc->bits_left += 32;
>> -}
>> -
>> -/**
>> - * 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 bitstream_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_left = 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_left = 0;
>> - bc->bits = 0;
>> -
>> - 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 bitstream_init8(BitstreamContext *bc, const uint8_t *buffer,
>> - unsigned int byte_size)
>> -{
>> - if (byte_size > INT_MAX / 8)
>> - return AVERROR_INVALIDDATA;
>> - return bitstream_init(bc, buffer, byte_size * 8);
>> -}
>> -
>> /**
>> * Return number of bits already read.
>> */
>> @@ -155,235 +73,6 @@ static inline int bitstream_bits_left(const BitstreamContext *bc)
>> return (bc->buffer - bc->ptr) * 8 + bc->size_in_bits + bc->bits_left;
>> }
>>
>> -static inline uint64_t get_val(BitstreamContext *bc, unsigned int n)
>> -{
>> - uint64_t ret;
>> -
>> -#ifdef BITSTREAM_READER_LE
>> - ret = bc->bits & ((UINT64_C(1) << n) - 1);
>> - bc->bits >>= n;
>> -#else
>> - ret = bc->bits >> (64 - n);
>> - bc->bits <<= n;
>> -#endif
>> - bc->bits_left -= n;
>> -
>> - return ret;
>> -}
>> -
>> -/**
>> - * Return one bit from the buffer.
>> - */
>> -static inline unsigned int bitstream_read_bit(BitstreamContext *bc)
>> -{
>> - if (!bc->bits_left)
>> - refill_64(bc);
>> -
>> - return get_val(bc, 1);
>> -}
>> -
>> -/**
>> - * Return n bits from the buffer, n has to be in the 0-63 range.
>> - */
>> -static inline uint64_t bitstream_read_63(BitstreamContext *bc, unsigned int n)
>> -{
>> - uint64_t ret = 0;
>> -#ifdef BITSTREAM_READER_LE
>> - uint64_t left = 0;
>> -#endif
>> -
>> - if (!n)
>> - return 0;
>> -
>> - if (n > bc->bits_left) {
>> - n -= bc->bits_left;
>> -#ifdef BITSTREAM_READER_LE
>> - left = bc->bits_left;
>> -#endif
>> - ret = get_val(bc, bc->bits_left);
>> - refill_64(bc);
>> - }
>> -
>> -#ifdef BITSTREAM_READER_LE
>> - ret = get_val(bc, n) << left | ret;
>> -#else
>> - ret = get_val(bc, n) | ret << n;
>> -#endif
>> -
>> - return ret;
>> -}
>> -
>> -/**
>> - * Return n bits from the buffer, n has to be in the 0-32 range.
>> - */
>> -static inline uint32_t bitstream_read(BitstreamContext *bc, unsigned int n)
>> -{
>> - if (!n)
>> - return 0;
>> -
>> - if (n > bc->bits_left) {
>> - refill_32(bc);
>> - if (bc->bits_left < 32)
>> - bc->bits_left = n;
>> - }
>> -
>> - return get_val(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 bitstream_read_signed(BitstreamContext *bc, unsigned int n)
>> -{
>> - return sign_extend(bitstream_read(bc, n), n);
>> -}
>> -
>> -static inline unsigned int show_val(BitstreamContext *bc, unsigned int n)
>> -{
>> -#ifdef BITSTREAM_READER_LE
>> - return bc->bits & ((UINT64_C(1) << n) - 1);
>> -#else
>> - return bc->bits >> (64 - n);
>> -#endif
>> -}
>> -
>> -/**
>> - * Return n bits from the buffer but do not change the buffer state.
>> - * n has to be in the 0-32 range.
>> - */
>> -static inline unsigned int bitstream_peek(BitstreamContext *bc, unsigned int n)
>> -{
>> - if (n > bc->bits_left)
>> - refill_32(bc);
>> -
>> - return show_val(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 bitstream_peek_signed(BitstreamContext *bc, unsigned int n)
>> -{
>> - return sign_extend(bitstream_peek(bc, n), n);
>> -}
>> -
>> -static inline void skip_remaining(BitstreamContext *bc, unsigned int n)
>> -{
>> -#ifdef BITSTREAM_READER_LE
>> - bc->bits >>= n;
>> -#else
>> - bc->bits <<= n;
>> -#endif
>> - bc->bits_left -= n;
>> -}
>> -
>> -/**
>> - * Skip n bits in the buffer.
>> - */
>> -static inline void bitstream_skip(BitstreamContext *bc, unsigned int n)
>> -{
>> - if (n < bc->bits_left)
>> - skip_remaining(bc, n);
>> - else {
>> - n -= bc->bits_left;
>> - bc->bits = 0;
>> - bc->bits_left = 0;
>> -
>> - if (n >= 64) {
>> - unsigned int skip = n / 8;
>> -
>> - n -= skip * 8;
>> - bc->ptr += skip;
>> - }
>> - refill_64(bc);
>> - if (n)
>> - skip_remaining(bc, n);
>> - }
>> -}
>> -
>> -/**
>> - * Seek to the given bit position.
>> - */
>> -static inline void bitstream_seek(BitstreamContext *bc, unsigned pos)
>> -{
>> - bc->ptr = bc->buffer;
>> - bc->bits = 0;
>> - bc->bits_left = 0;
>> -
>> - bitstream_skip(bc, pos);
>> -}
>> -
>> -/**
>> - * Skip bits to a byte boundary.
>> - */
>> -static inline const uint8_t *bitstream_align(BitstreamContext *bc)
>> -{
>> - unsigned int n = -bitstream_tell(bc) & 7;
>> - if (n)
>> - bitstream_skip(bc, n);
>> - return bc->buffer + (bitstream_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 bitstream_read_xbits(BitstreamContext *bc, unsigned int n)
>> -{
>> - int32_t cache = bitstream_peek(bc, 32);
>> - int sign = ~cache >> 31;
>> - 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 bitstream_decode012(BitstreamContext *bc)
>> -{
>> - if (!bitstream_read_bit(bc))
>> - return 0;
>> - else
>> - return bitstream_read_bit(bc) + 1;
>> -}
>> -
>> -/**
>> - * Return decoded truncated unary code for the values 2, 1, 0.
>> - */
>> -static inline int bitstream_decode210(BitstreamContext *bc)
>> -{
>> - if (bitstream_read_bit(bc))
>> - return 0;
>> - else
>> - return 2 - bitstream_read_bit(bc);
>> -}
>> -
>> -/* Read sign bit and flip the sign of the provided value accordingly. */
>> -static inline int bitstream_apply_sign(BitstreamContext *bc, int val)
>> -{
>> - int sign = bitstream_read_signed(bc, 1);
>> - return (val ^ sign) - sign;
>> -}
>> -
>> -static inline int bitstream_skip_1stop_8data(BitstreamContext *s)
>> -{
>> - if (bitstream_bits_left(s) <= 0)
>> - return AVERROR_INVALIDDATA;
>> -
>> - while (bitstream_read(s, 1)) {
>> - bitstream_skip(s, 8);
>> - if (bitstream_bits_left(s) <= 0)
>> - return AVERROR_INVALIDDATA;
>> - }
>> -
>> - return 0;
>> -}
>> -
>> /* Unwind the cache so a refill_32 can fill it again. */
>> static inline void bitstream_unwind(BitstreamContext *bc)
>> {
>> @@ -412,52 +101,28 @@ static inline void bitstream_unget(BitstreamContext *bc, uint64_t value,
>> bc->bits_left += amount;
>> }
>>
>> -/**
>> - * Return the LUT element for the given bitstream configuration.
>> - */
>> -static inline int set_idx(BitstreamContext *bc, int code, int *n, int *nb_bits,
>> - const VLCElem *table)
>> -{
>> - unsigned idx;
>> -
>> - *nb_bits = -*n;
>> - idx = bitstream_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 bitstream_read_vlc(BitstreamContext *bc, const VLCElem *table,
>> - int bits, int max_depth)
>> -{
>> - int nb_bits;
>> - unsigned idx = bitstream_peek(bc, bits);
>> - int code = table[idx].sym;
>> - int n = table[idx].len;
>> -
>> - if (max_depth > 1 && n < 0) {
>> - skip_remaining(bc, bits);
>> - code = set_idx(bc, code, &n, &nb_bits, table);
>> - if (max_depth > 2 && n < 0) {
>> - skip_remaining(bc, nb_bits);
>> - code = set_idx(bc, code, &n, &nb_bits, table);
>> - }
>> - }
>> - skip_remaining(bc, n);
>> -
>> - return code;
>> -}
>> +#define BITSTREAM_LE
>> +#include "bitstream_template.h"
>> +
>> +#undef BITSTREAM_LE
>> +#include "bitstream_template.h"
>
> This will compile both version and for the overwhelming majority of
> files one of them is enough. I think which one should be compiled should
> be left to the user, see below.
>
>> +
>> +#define bitstream_init bitstream_init_be
>> +#define bitstream_init8 bitstream_init8_be
>> +#define bitstream_read_bit bitstream_read_bit_be
>> +#define bitstream_read_63 bitstream_read_63_be
>> +#define bitstream_read bitstream_read_be
>> +#define bitstream_read_signed bitstream_read_signed_be
>> +#define bitstream_peek bitstream_peek_be
>> +#define bitstream_peek_signed bitstream_peek_signed_be
>> +#define bitstream_skip bitstream_skip_be
>> +#define bitstream_seek bitstream_seek_be
>> +#define bitstream_align bitstream_align_be
>> +#define bitstream_read_xbits bitstream_read_xbits_be
>> +#define bitstream_decode012 bitstream_decode012_be
>> +#define bitstream_decode210 bitstream_decode210_be
>> +#define bitstream_apply_sign bitstream_apply_sign_be
>> +#define bitstream_read_vlc bitstream_read_vlc_be
>
> You are unconditionally making the big-endian version the default
> version. This is wrong. Instead you should let the user decide this (by
> using an appropriate define that the user can set before including this
> header). I'd implement is as follows: The user can set flags
> BITSTREAM_LE and/or BITSTREAM_BE to signal which endianness to compile;
> if none is set, it is treated as if BITSTREAM_BE were set in line with
> the current default. If both are set, the user must define
> BITSTREAM_DEFAULT_BE/LE to indicate what shall be the default.
>
> To accomplish this, the part of bitstream.h that includes the template
> will have to be outside of ordinary inclusion guards and instead be
> guarded by inclusion guards of its own (one for each endianness).
>
A bit more context for this: You seem to believe that there can be only
two versions of the cached bitstream reader; yet there can be more.
Several codecs treat their input as 32-bit words and swap the endianness
of said words before reading them via the ordinary BE-bitreader. Yet
this is unnecessary, as one can swap the words upon reading when using
the cached bitstream reader (because the cached bitstream reader reads
32bit words by default and so automatically maintains alignment).
Here is a branch where this is implemented for fraps:
https://github.com/mkver/FFmpeg/commits/aligned32_le_bitstream_reader
If there are more than two, then compiling every bitreader for every
file that needs a bitreader becomes excessive.
- Andreas
_______________________________________________
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] 15+ messages in thread
* Re: [FFmpeg-devel] [PATCH 2/4] lavc: add standalone cached bitstream reader
2022-06-23 12:26 ` [FFmpeg-devel] [PATCH 2/4] lavc: add standalone cached bitstream reader Anton Khirnov
` (2 preceding siblings ...)
2022-06-24 12:30 ` Andreas Rheinhardt
@ 2022-06-30 9:18 ` Anton Khirnov
2022-06-30 12:16 ` Anton Khirnov
4 siblings, 0 replies; 15+ messages in thread
From: Anton Khirnov @ 2022-06-30 9:18 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Quoting Andreas Rheinhardt (2022-06-24 14:30:58)
> Anton Khirnov:
> > 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>
> > ---
>
> One thing I wanted to tell in all my previous mails, but forgot: The
> bitstream prefix is way too long. Why not use just e.g. bits? The only
> function whose name starts with "bits_" is bits_to_store in
> lavc/sonic.c, so clashes are not an issue.
Fine with me.
--
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] 15+ messages in thread
* Re: [FFmpeg-devel] [PATCH 2/4] lavc: add standalone cached bitstream reader
2022-06-23 12:26 ` [FFmpeg-devel] [PATCH 2/4] lavc: add standalone cached bitstream reader Anton Khirnov
` (3 preceding siblings ...)
2022-06-30 9:18 ` Anton Khirnov
@ 2022-06-30 12:16 ` Anton Khirnov
4 siblings, 0 replies; 15+ messages in thread
From: Anton Khirnov @ 2022-06-30 12:16 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Quoting Andreas Rheinhardt (2022-06-23 20:56:00)
> Anton Khirnov:
> > + */
> > +static inline uint32_t bitstream_read(BitstreamContext *bc, unsigned int n)
> > +{
> > + if (!n)
> > + return 0;
>
> This makes this function a get_bitsz equivalent. Why is there no
> get_bits() equivalent for the cases where it is known that n is not
> zero, but where it is impossible for the compiler to know?
I did not write this code, but I suppose because there were many bugs in
the past where get_bits(0) was called and the advantage did not seem
worth the risk.
If you think such a function would be useful, I'd prefer it to be a
non-default variant, e.g. bits_read_nz.
--
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] 15+ messages in thread
end of thread, other threads:[~2022-06-30 12:16 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-23 12:26 [FFmpeg-devel] [PATCH 1/4] get_bits: move check_marker() to mpegvideodec.h Anton Khirnov
2022-06-23 12:26 ` [FFmpeg-devel] [PATCH 2/4] lavc: add standalone cached bitstream reader Anton Khirnov
2022-06-23 18:56 ` Andreas Rheinhardt
2022-06-24 12:08 ` Andreas Rheinhardt
2022-06-24 10:18 ` Andreas Rheinhardt
2022-06-24 12:30 ` Andreas Rheinhardt
2022-06-30 9:18 ` Anton Khirnov
2022-06-30 12:16 ` Anton Khirnov
2022-06-23 12:26 ` [FFmpeg-devel] [PATCH 3/4] lavc/bitstream: templatize for BE/LE Anton Khirnov
2022-06-23 17:43 ` Andreas Rheinhardt
2022-06-25 7:53 ` Andreas Rheinhardt
2022-06-23 12:26 ` [FFmpeg-devel] [PATCH 4/4] lavc/get_bits: add a compat wrapper for the cached bitstream reader Anton Khirnov
2022-06-23 18:04 ` Andreas Rheinhardt
2022-06-23 17:07 ` [FFmpeg-devel] [PATCH 1/4] get_bits: move check_marker() to mpegvideodec.h Andreas Rheinhardt
2022-06-25 4:43 ` Andreas Rheinhardt
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