diff --git a/src/utils/bit_reader.c b/src/utils/bit_reader.c index e236b687..1c012b0a 100644 --- a/src/utils/bit_reader.c +++ b/src/utils/bit_reader.c @@ -116,13 +116,11 @@ int32_t VP8GetSignedValue(VP8BitReader* const br, int bits) { //------------------------------------------------------------------------------ // VP8LBitReader -#define MAX_NUM_BIT_READ 25 - #define LBITS 64 // Number of bits prefetched. #define WBITS 32 // Minimum number of bytes needed after VP8LFillBitWindow. #define LOG8_WBITS 4 // Number of bytes needed to store WBITS bits. -static const uint32_t kBitMask[MAX_NUM_BIT_READ] = { +static const uint32_t kBitMask[VP8L_MAX_NUM_BIT_READ + 1] = { 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 }; @@ -199,7 +197,7 @@ void VP8LFillBitWindow(VP8LBitReader* const br) { uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits) { 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 (!br->eos_ && n_bits <= VP8L_MAX_NUM_BIT_READ) { const uint32_t val = (uint32_t)(br->val_ >> br->bit_pos_) & kBitMask[n_bits]; const int new_bits = br->bit_pos_ + n_bits; diff --git a/src/utils/bit_reader.h b/src/utils/bit_reader.h index 7865e7b9..f03c3ba8 100644 --- a/src/utils/bit_reader.h +++ b/src/utils/bit_reader.h @@ -316,6 +316,9 @@ static WEBP_INLINE int VP8GetSigned(VP8BitReader* const br, int v) { // ----------------------------------------------------------------------------- // Bitreader for lossless format +// maximum number of bits (inclusive) the bit-reader can handle: +#define VP8L_MAX_NUM_BIT_READ 24 + typedef uint64_t vp8l_val_t; // right now, this bit-reader can only use 64bit. typedef struct { @@ -336,9 +339,10 @@ void VP8LInitBitReader(VP8LBitReader* const br, void VP8LBitReaderSetBuffer(VP8LBitReader* const br, const uint8_t* const buffer, size_t 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. +// Reads the specified number of bits from read buffer. +// Flags an error in case end_of_stream or n_bits is more than the allowed limit +// of VP8L_MAX_NUM_BIT_READ (inclusive). +// Flags eos_ if this read attempt is going to cross the read buffer. uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits); // Return the prefetched bits, so they can be looked up. diff --git a/src/utils/bit_writer.c b/src/utils/bit_writer.c index 07465c10..0138b54d 100644 --- a/src/utils/bit_writer.c +++ b/src/utils/bit_writer.c @@ -202,6 +202,7 @@ void VP8BitWriterWipeOut(VP8BitWriter* const bw) { #define VP8L_WRITER_BYTES ((int)sizeof(vp8l_wtype_t)) #define VP8L_WRITER_BITS (VP8L_WRITER_BYTES * 8) +#define VP8L_WRITER_MAX_BITS (8 * (int)sizeof(vp8l_atype_t)) // endian-specific htoleXX() definition // TODO(skal): move this to config.h, and collect all the endian-related code @@ -226,6 +227,8 @@ void VP8BitWriterWipeOut(VP8BitWriter* const bw) { // NaCl without glibc is assumed to be little-endian #define htole32(x) (x) #define htole16(x) (x) +#elif defined(__QNX__) +#include #else // pretty much all linux and/or glibc #include #endif @@ -275,23 +278,44 @@ void VP8LBitWriterDestroy(VP8LBitWriter* const bw) { } void VP8LWriteBits(VP8LBitWriter* const bw, int n_bits, uint32_t bits) { - if (n_bits <= 0) return; - bw->bits_ |= (vp8l_atype_t)bits << bw->used_; - bw->used_ += n_bits; - if (bw->used_ > VP8L_WRITER_BITS) { - if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) { - const uint64_t extra_size = (bw->end_ - bw->buf_) + MIN_EXTRA_SIZE; - if (extra_size != (size_t)extra_size || - !VP8LBitWriterResize(bw, (size_t)extra_size)) { - bw->cur_ = bw->buf_; - bw->error_ = 1; - return; + assert(n_bits <= 32); + // That's the max we can handle: + assert(bw->used_ + n_bits <= 2 * VP8L_WRITER_MAX_BITS); + if (n_bits > 0) { + // Local field copy. + vp8l_atype_t lbits = bw->bits_; + int used = bw->used_; + // Special case of overflow handling for 32bit accumulator (2-steps flush). + if (VP8L_WRITER_BITS == 16) { + if (used + n_bits >= VP8L_WRITER_MAX_BITS) { + // Fill up all the VP8L_WRITER_MAX_BITS so it can be flushed out below. + const int shift = VP8L_WRITER_MAX_BITS - used; + lbits |= (vp8l_atype_t)bits << used; + used = VP8L_WRITER_MAX_BITS; + n_bits -= shift; + bits >>= shift; + assert(n_bits <= VP8L_WRITER_MAX_BITS); } } - *(vp8l_wtype_t*)bw->cur_ = (vp8l_wtype_t)WSWAP((vp8l_wtype_t)bw->bits_); - bw->cur_ += VP8L_WRITER_BYTES; - bw->bits_ >>= VP8L_WRITER_BITS; - bw->used_ -= VP8L_WRITER_BITS; + // If needed, make some room by flushing some bits out. + while (used >= VP8L_WRITER_BITS) { + if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) { + const uint64_t extra_size = (bw->end_ - bw->buf_) + MIN_EXTRA_SIZE; + if (extra_size != (size_t)extra_size || + !VP8LBitWriterResize(bw, (size_t)extra_size)) { + bw->cur_ = bw->buf_; + bw->error_ = 1; + return; + } + } + *(vp8l_wtype_t*)bw->cur_ = (vp8l_wtype_t)WSWAP((vp8l_wtype_t)lbits); + bw->cur_ += VP8L_WRITER_BYTES; + lbits >>= VP8L_WRITER_BITS; + used -= VP8L_WRITER_BITS; + } + // Eventually, insert new bits. + bw->bits_ = lbits | ((vp8l_atype_t)bits << used); + bw->used_ = used + n_bits; } } diff --git a/src/utils/bit_writer.h b/src/utils/bit_writer.h index 274de6ba..2cb5c573 100644 --- a/src/utils/bit_writer.h +++ b/src/utils/bit_writer.h @@ -106,7 +106,8 @@ void VP8LBitWriterDestroy(VP8LBitWriter* const bw); // This function writes bits into bytes in increasing addresses (little endian), // and within a byte least-significant-bit first. -// The function can write up to 8*sizeof(vp8l_wtype_t) bits in one go. +// This function can write up to 32 bits in one go, but VP8LBitReader can only +// read 24 bits max (VP8L_MAX_NUM_BIT_READ). // VP8LBitWriter's error_ flag is set in case of memory allocation error. void VP8LWriteBits(VP8LBitWriter* const bw, int n_bits, uint32_t bits);