mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-20 04:18:26 +01:00
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:
parent
541784c710
commit
176fda2650
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user