[FFmpeg-devel] [PATCH 3/4] lavc/bitstream: templatize for BE/LE
Andreas Rheinhardt
andreas.rheinhardt at outlook.com
Thu Jun 23 20:43:44 EEST 2022
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:
More information about the ffmpeg-devel
mailing list