From c4ae53c8b3678d6c10b156e242ad697f2b83c449 Mon Sep 17 00:00:00 2001 From: James Zern Date: Tue, 10 Apr 2012 17:23:38 -0700 Subject: [PATCH] add utils/bit_reader.[hc] changes from experimental Pulled from the parent of the current version (5529a2e^). The history of this and related files is a bit entangled so rather trying to split the changes and introduce some noise in master's history we'll start with a fresh snapshot. The file progression is still available in the experimental branch. Change-Id: I6dae97fc381cd6c1d1640c4c565b2084a41ec955 --- src/utils/bit_reader.c | 123 +++++++++++++++++++++++++++++++++++++++++ src/utils/bit_reader.h | 49 ++++++++++++++++ 2 files changed, 172 insertions(+) diff --git a/src/utils/bit_reader.c b/src/utils/bit_reader.c index 7c2d2544..993068b8 100644 --- a/src/utils/bit_reader.c +++ b/src/utils/bit_reader.c @@ -94,6 +94,129 @@ int32_t VP8GetSignedValue(VP8BitReader* const br, int bits) { return VP8Get(br) ? -value : value; } +//------------------------------------------------------------------------------ +// BitReader + +static const uint32_t kBitMask[MAX_NUM_BIT_READ] = { + 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, + 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215 +}; + +void VP8LInitBitReader(BitReader* const br, + const uint8_t* const start, + size_t length) { + size_t i; + assert(br); + assert(start); + + br->buf_ = start; + br->len_ = length; + br->val_ = 0; + br->pos_ = 0; + br->bit_pos_ = 0; + br->eos_ = 0; + br->error_ = 0; + for (i = 0; i < sizeof(br->val_) && i < br->len_; ++i) { + br->val_ |= ((uint64_t)br->buf_[br->pos_]) << (8 * i); + ++br->pos_; + } +} + +void VP8LBitReaderResize(BitReader* const br, + const uint8_t* const new_start, + size_t new_length) { + if (new_length > br->len_) br->eos_ = 0; + br->buf_ = new_start; + br->len_ = new_length; +} + +static void ShiftBytes(BitReader* const br) { + while (br->bit_pos_ >= 8 && br->pos_ < br->len_) { + br->val_ >>= 8; + br->val_ |= ((uint64_t)br->buf_[br->pos_]) << 56; + ++br->pos_; + br->bit_pos_ -= 8; + } +} + +void VP8LFillBitWindow(BitReader* const br) { + if (br->bit_pos_ >= 32) { +#if defined(__x86_64__) + if (br->pos_ < br->len_ - 8) { + br->val_ >>= 32; + // The expression below needs a little-endian arch to work correctly. + // This gives a large speedup for decoding speed. + br->val_ |= *(const uint64_t *)(br->buf_ + br->pos_) << 32; + br->pos_ += 4; + br->bit_pos_ -= 32; + } else { + // Slow path. + ShiftBytes(br); + } +#else + // Always the slow path. + ShiftBytes(br); +#endif + } + if (br->pos_ == br->len_ && br->bit_pos_ == 64) { + br->eos_ = 1; + } +} + +uint32_t VP8LReadOneBit(BitReader* const br) { + const uint32_t val = (br->val_ >> br->bit_pos_) & 1; + // Flag an error at end_of_stream. + if (!br->eos_) { + ++br->bit_pos_; + if (br->bit_pos_ >= 32) { + ShiftBytes(br); + } + // After this last bit is read, check if eos needs to be flagged. + if (br->pos_ == br->len_ && br->bit_pos_ == 64) { + br->eos_ = 1; + } + } else { + br->error_ = 1; + } + return val; +} + +uint32_t VP8LReadBits(BitReader* const br, int n_bits) { + uint32_t val = 0; + assert(n_bits >= 0); + // Flag an error if end_of_stream or n_bits is more than allowed limit. + if (!br->eos_ && n_bits < MAX_NUM_BIT_READ) { + // If this read is going to cross the read buffer, set the eos flag. + if (br->pos_ == br->len_) { + if ((br->bit_pos_ + n_bits) >= 64) { + br->eos_ = 1; + if ((br->bit_pos_ + n_bits) > 64) return val; + } + } + val = (br->val_ >> br->bit_pos_) & kBitMask[n_bits]; + br->bit_pos_ += n_bits; + if (br->bit_pos_ >= 40) { + if (br->pos_ < br->len_ - 5) { + br->val_ >>= 40; + br->val_ |= + (((uint64_t)br->buf_[br->pos_ + 0]) << 24) | + (((uint64_t)br->buf_[br->pos_ + 1]) << 32) | + (((uint64_t)br->buf_[br->pos_ + 2]) << 40) | + (((uint64_t)br->buf_[br->pos_ + 3]) << 48) | + (((uint64_t)br->buf_[br->pos_ + 4]) << 56); + br->pos_ += 5; + br->bit_pos_ -= 40; + } + if (br->bit_pos_ >= 8) { + ShiftBytes(br); + } + } + } else { + br->error_ = 1; + } + return val; +} + //------------------------------------------------------------------------------ #if defined(__cplusplus) || defined(c_plusplus) diff --git a/src/utils/bit_reader.h b/src/utils/bit_reader.h index 86848bb4..165cb359 100644 --- a/src/utils/bit_reader.h +++ b/src/utils/bit_reader.h @@ -8,14 +8,17 @@ // Boolean decoder // // Author: Skal (pascal.massimino@gmail.com) +// Vikas Arora (vikaas.arora@gmail.com) #ifndef WEBP_UTILS_BIT_READER_H_ #define WEBP_UTILS_BIT_READER_H_ #include +#include // For size_t #ifdef _MSC_VER #include // _byteswap_ulong #endif +#include // For memcpy #include "../webp/decode_vp8.h" #if defined(__cplusplus) || defined(c_plusplus) @@ -145,6 +148,52 @@ static WEBP_INLINE int VP8GetSigned(VP8BitReader* const br, int v) { return bit ? -v : v; } + +// ----------------------------------------------------------------------------- +// Bitreader + +#define MAX_NUM_BIT_READ 25 + +typedef struct { + uint64_t val_; + const uint8_t* buf_; + size_t len_; + size_t pos_; + int bit_pos_; + int eos_; + int error_; +} BitReader; + +void VP8LInitBitReader(BitReader* const br, + const uint8_t* const start, + size_t length); + +// Resizes the BitReader corresponding to resized read buffer. +void VP8LBitReaderResize(BitReader* const br, + const uint8_t* const new_start, + size_t new_length); + +// Reads the specified number of bits from Read Buffer. +// Flags an error in case end_of_stream or n_bits is more than allowed limit. +// Flags eos if this read attempt is going to cross the read buffer. +uint32_t VP8LReadBits(BitReader* const br, int n_bits); + +// Reads one bit from Read Buffer. Flags an error in case end_of_stream. +// Flags eos after reading last bit from the buffer. +uint32_t VP8LReadOneBit(BitReader* const br); + +// VP8LReadOneBitUnsafe is faster than VP8LReadOneBit, but it can be called only +// 32 times after the last VP8LFillBitWindow. Any subsequent calls +// (without VP8LFillBitWindow) will return invalid data. +static WEBP_INLINE uint32_t VP8LReadOneBitUnsafe(BitReader* const br) { + const uint32_t val = (br->val_ >> br->bit_pos_) & 1; + ++br->bit_pos_; + return val; +} + +// Advances the Read buffer by 4 bytes to make room for reading next 32 bits. +void VP8LFillBitWindow(BitReader* const br); + #if defined(__cplusplus) || defined(c_plusplus) } // extern "C" #endif