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
This commit is contained in:
James Zern 2012-04-10 17:23:38 -07:00
parent 514d008921
commit c4ae53c8b3
2 changed files with 172 additions and 0 deletions

View File

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

View File

@ -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 <assert.h>
#include <stddef.h> // For size_t
#ifdef _MSC_VER
#include <stdlib.h> // _byteswap_ulong
#endif
#include <string.h> // 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