fix the bit-writer for lossless in 32bit mode

Sometimes, we can write 18bit or more at time, and it would
overflow the 32bit accumulator.

Also clarified the num-bits limitations (and exposed
VP8L_MAX_NUM_BIT_READ in bit_reader.h)

fixes http://code.google.com/p/webp/issues/detail?id=200

Seems a bit faster (use of local fields for bits_ / used_)

also: added the __QNX__ bswap while at it.

Change-Id: I876db93a931db15b083cf1d838c70105effa7167
This commit is contained in:
skal 2014-05-22 07:17:24 +02:00
parent 541784c710
commit 176fda2650
4 changed files with 50 additions and 23 deletions

View File

@ -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;

View File

@ -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.

View File

@ -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 <net/netbyte.h>
#else // pretty much all linux and/or glibc
#include <endian.h>
#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;
}
}

View File

@ -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);