make the bitreader preload at least 8bits, instead of post-load them

(this makes initialization easier and will be helpful for incremental
decoding).
Modify ParsePartitions() to accommodate for truncated input.

Change-Id: I62f52078d6b7a2314a11880a20d9eac5b4714bd0
This commit is contained in:
Pascal Massimino 2011-03-10 15:05:59 -08:00
parent f4888f7702
commit 13e50da6f8
3 changed files with 65 additions and 52 deletions

View File

@ -18,16 +18,17 @@ extern "C" {
//-----------------------------------------------------------------------------
// VP8BitReader
void VP8Init(VP8BitReader* const br, const uint8_t* buf, uint32_t size) {
void VP8InitBitReader(VP8BitReader* const br,
const uint8_t* const start, const uint8_t* const end) {
assert(br);
assert(buf);
br->range_ = 255 - 1;
br->buf_ = buf;
br->buf_end_ = buf + size;
// Need two initial bytes.
br->value_ = (VP8GetByte(br) << 8) | VP8GetByte(br);
br->left_ = -8;
br->eof_ = 0;
assert(start);
assert(start <= end);
br->range_ = 255 - 1;
br->buf_ = start;
br->buf_end_ = end;
br->value_ = 0;
br->missing_ = 8;
br->eof_ = 0;
}
const uint8_t kVP8Log2Range[128] = {

View File

@ -30,11 +30,12 @@ typedef struct {
// boolean decoder
uint32_t range_; // current range minus 1. In [127, 254] interval.
uint32_t value_; // current value
int left_; // how many unused bits (negated)
int missing_; // number of missing bits in value_ (8bit)
} VP8BitReader;
// Initialize the bit reader and the boolean decoder.
void VP8Init(VP8BitReader* const br, const uint8_t* buf, uint32_t size);
void VP8InitBitReader(VP8BitReader* const br,
const uint8_t* const start, const uint8_t* const end);
// return the next value made of 'num_bits' bits
uint32_t VP8GetValue(VP8BitReader* const br, int num_bits);
@ -55,7 +56,24 @@ static inline uint32_t VP8GetByte(VP8BitReader* const br) {
return *br->buf_++;
}
br->eof_ = 1;
return 0x80;
return 0xff;
}
static inline uint32_t VP8BitUpdate(VP8BitReader* const br, uint32_t split) {
uint32_t bit;
// Make sure we have a least 8 bits in 'value_'
if (br->missing_ > 0) {
br->value_ |= VP8GetByte(br) << br->missing_;
br->missing_ -= 8;
}
bit = ((br->value_ >> 8) > split);
if (bit) {
br->range_ -= split + 1;
br->value_ -= (split + 1) << 8;
} else {
br->range_ = split;
}
return bit;
}
static inline void VP8Shift(VP8BitReader* const br) {
@ -63,22 +81,12 @@ static inline void VP8Shift(VP8BitReader* const br) {
const int shift = kVP8Log2Range[br->range_];
br->range_ = kVP8NewRange[br->range_];
br->value_ <<= shift;
br->left_ += shift;
if (br->left_ > 0) {
br->value_ |= VP8GetByte(br) << br->left_;
br->left_ -= 8;
}
br->missing_ += shift;
}
static inline uint32_t VP8GetBit(VP8BitReader* const br, int prob) {
const uint32_t split = (br->range_ * prob) >> 8;
const uint32_t bit = ((br->value_ >> 8) > split);
if (bit) {
br->range_ -= split + 1;
br->value_ -= (split + 1) << 8;
} else {
br->range_ = split;
}
const uint32_t bit = VP8BitUpdate(br, split);
if (br->range_ < 0x7f) {
VP8Shift(br);
}
@ -87,16 +95,9 @@ static inline uint32_t VP8GetBit(VP8BitReader* const br, int prob) {
static inline int VP8GetSigned(VP8BitReader* const br, int v) {
const uint32_t split = br->range_ >> 1;
const uint32_t bit = ((br->value_ >> 8) > split);
if (bit) {
br->range_ -= split + 1;
br->value_ -= (split + 1) << 8;
v = -v;
} else {
br->range_ = split;
}
const uint32_t bit = VP8BitUpdate(br, split);
VP8Shift(br);
return v;
return bit ? -v : v;
}
#if defined(__cplusplus) || defined(c_plusplus)

View File

@ -111,33 +111,41 @@ static int ParseSegmentHeader(VP8BitReader* br,
}
// Paragraph 9.5
static int ParsePartitions(VP8Decoder* const dec,
const uint8_t* buf, uint32_t size) {
// This function returns VP8_STATUS_SUSPENDED if we don't have all the
// necessary data in 'buf'.
// This case is not necessarily an error (for incremental decoding).
// Still, no bitreader is ever initialized to make it possible to read
// unavailable memory.
// If we don't even have the partitions' sizes, than VP8_STATUS_NOT_ENOUGH_DATA
// is returned, and this is an unrecoverable error.
// If the partitions were positioned ok, VP8_STATUS_OK is returned.
static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
const uint8_t* buf, uint32_t size) {
VP8BitReader* const br = &dec->br_;
const uint8_t* sz = buf;
const uint8_t* buf_end = buf + size;
const uint8_t* part_start;
int last_part;
uint32_t offset;
int p;
dec->num_parts_ = 1 << VP8GetValue(br, 2);
last_part = dec->num_parts_ - 1;
offset = last_part * 3;
if (size <= offset) {
return 0;
part_start = buf + last_part * 3;
if (buf_end < part_start) {
// we can't even read the sizes with sz[]! That's a failure.
return VP8_STATUS_NOT_ENOUGH_DATA;
}
for (p = 0; p < last_part; ++p) {
const uint32_t psize = sz[0] | (sz[1] << 8) | (sz[2] << 16);
if (offset + psize > size) {
return 0;
}
VP8Init(dec->parts_ + p, buf + offset, psize);
offset += psize;
const uint8_t* part_end = part_start + psize;
if (part_end > buf_end) part_end = buf_end;
VP8InitBitReader(dec->parts_ + p, part_start, part_end);
part_start = part_end;
sz += 3;
}
size -= offset;
VP8Init(dec->parts_ + last_part, buf + offset, size);
return 1;
VP8InitBitReader(dec->parts_ + last_part, part_start, buf_end);
return (part_start < buf_end) ? VP8_STATUS_OK :
VP8_STATUS_SUSPENDED; // Init is ok, but there's not enough data
}
// Paragraph 9.4
@ -284,14 +292,17 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
dec->segment_ = 0; // default for intra
}
br = &dec->br_;
VP8Init(br, buf, buf_size);
// Check if we have all the partition #0 available, and initialize dec->br_
// to read this partition (and this partition only).
if (frm_hdr->partition_length_ > buf_size) {
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
"bad partition length");
}
}
br = &dec->br_;
VP8InitBitReader(br, buf, buf + frm_hdr->partition_length_);
buf += frm_hdr->partition_length_;
buf_size -= frm_hdr->partition_length_;
if (frm_hdr->key_frame_) {
pic_hdr->colorspace_ = VP8Get(br);
pic_hdr->clamp_type_ = VP8Get(br);
@ -305,7 +316,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
"cannot parse filter header");
}
if (!ParsePartitions(dec, buf, buf_size)) {
if (ParsePartitions(dec, buf, buf_size) != VP8_STATUS_OK) {
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
"cannot parse partitions");
}