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 // 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(br);
assert(buf); assert(start);
br->range_ = 255 - 1; assert(start <= end);
br->buf_ = buf; br->range_ = 255 - 1;
br->buf_end_ = buf + size; br->buf_ = start;
// Need two initial bytes. br->buf_end_ = end;
br->value_ = (VP8GetByte(br) << 8) | VP8GetByte(br); br->value_ = 0;
br->left_ = -8; br->missing_ = 8;
br->eof_ = 0; br->eof_ = 0;
} }
const uint8_t kVP8Log2Range[128] = { const uint8_t kVP8Log2Range[128] = {

View File

@ -30,11 +30,12 @@ typedef struct {
// boolean decoder // boolean decoder
uint32_t range_; // current range minus 1. In [127, 254] interval. uint32_t range_; // current range minus 1. In [127, 254] interval.
uint32_t value_; // current value uint32_t value_; // current value
int left_; // how many unused bits (negated) int missing_; // number of missing bits in value_ (8bit)
} VP8BitReader; } VP8BitReader;
// Initialize the bit reader and the boolean decoder. // 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 // return the next value made of 'num_bits' bits
uint32_t VP8GetValue(VP8BitReader* const br, int num_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_++; return *br->buf_++;
} }
br->eof_ = 1; 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) { static inline void VP8Shift(VP8BitReader* const br) {
@ -63,22 +81,12 @@ static inline void VP8Shift(VP8BitReader* const br) {
const int shift = kVP8Log2Range[br->range_]; const int shift = kVP8Log2Range[br->range_];
br->range_ = kVP8NewRange[br->range_]; br->range_ = kVP8NewRange[br->range_];
br->value_ <<= shift; br->value_ <<= shift;
br->left_ += shift; br->missing_ += shift;
if (br->left_ > 0) {
br->value_ |= VP8GetByte(br) << br->left_;
br->left_ -= 8;
}
} }
static inline uint32_t VP8GetBit(VP8BitReader* const br, int prob) { static inline uint32_t VP8GetBit(VP8BitReader* const br, int prob) {
const uint32_t split = (br->range_ * prob) >> 8; const uint32_t split = (br->range_ * prob) >> 8;
const uint32_t bit = ((br->value_ >> 8) > split); const uint32_t bit = VP8BitUpdate(br, split);
if (bit) {
br->range_ -= split + 1;
br->value_ -= (split + 1) << 8;
} else {
br->range_ = split;
}
if (br->range_ < 0x7f) { if (br->range_ < 0x7f) {
VP8Shift(br); 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) { static inline int VP8GetSigned(VP8BitReader* const br, int v) {
const uint32_t split = br->range_ >> 1; const uint32_t split = br->range_ >> 1;
const uint32_t bit = ((br->value_ >> 8) > split); const uint32_t bit = VP8BitUpdate(br, split);
if (bit) {
br->range_ -= split + 1;
br->value_ -= (split + 1) << 8;
v = -v;
} else {
br->range_ = split;
}
VP8Shift(br); VP8Shift(br);
return v; return bit ? -v : v;
} }
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)

View File

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