* add an option to bypass_filtering in VP8Io.

This will make the decoder skip the filtering process if needed,
resulting in speed-up, but also non-compliant (blocky?) output
+ Add a versioning check for VP8InitIo(), since we've adding a field to VP8Io
+ add some more error checks while at it

Change-Id: I4e9899edc24ecf8600cbb27aa4038490b7b2cef3
This commit is contained in:
Pascal Massimino 2011-02-27 10:51:01 -08:00
parent b97a4003c0
commit 5b70b378bd
2 changed files with 37 additions and 7 deletions

View File

@ -20,10 +20,13 @@ static void SetOk(VP8Decoder* const dec) {
dec->error_msg_ = "OK"; dec->error_msg_ = "OK";
} }
void VP8InitIo(VP8Io* const io) { int VP8InitIoInternal(VP8Io* const io, int version) {
if (version != WEBP_DECODER_ABI_VERSION)
return 0; // mismatch error
if (io) { if (io) {
memset(io, 0, sizeof(*io)); memset(io, 0, sizeof(*io));
} }
return 1;
} }
VP8Decoder* VP8New() { VP8Decoder* VP8New() {
@ -100,7 +103,7 @@ static int ParseSegmentHeader(VP8BitReader* br,
} else { } else {
hdr->update_map_ = 0; hdr->update_map_ = 0;
} }
return 1; return !br->eof_;
} }
// Paragraph 9.5 // Paragraph 9.5
@ -170,7 +173,7 @@ static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) {
dec->filter_levels_[0] = hdr->level_; dec->filter_levels_[0] = hdr->level_;
} }
} }
return 1; return !br->eof_;
} }
static inline uint32_t get_le32(const uint8_t* const data) { static inline uint32_t get_le32(const uint8_t* const data) {
@ -214,12 +217,16 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
"RIFF: WEBP signature not found."); "RIFF: WEBP signature not found.");
} }
riff_size = get_le32(buf + 4); riff_size = get_le32(buf + 4);
if (riff_size < 12) {
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
"RIFF: Truncated header.");
}
if (memcmp(buf + 12, "VP8 ", 4)) { if (memcmp(buf + 12, "VP8 ", 4)) {
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
"RIFF: Invalid compression format."); "RIFF: Invalid compression format.");
} }
chunk_size = get_le32(buf + 16); chunk_size = get_le32(buf + 16);
if ((chunk_size > riff_size + 8) || (chunk_size & 1)) { if (chunk_size > riff_size - 12) {
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
"RIFF: Inconsistent size information."); "RIFF: Inconsistent size information.");
} }
@ -235,6 +242,12 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
frm_hdr->profile_ = (bits >> 1) & 7; frm_hdr->profile_ = (bits >> 1) & 7;
frm_hdr->show_ = (bits >> 4) & 1; frm_hdr->show_ = (bits >> 4) & 1;
frm_hdr->partition_length_ = (bits >> 5); frm_hdr->partition_length_ = (bits >> 5);
if (frm_hdr->profile_ > 3)
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
"Incorrect keyframe parameters.");
if (!frm_hdr->show_)
return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE,
"Frame not displayable.");
buf += 3; buf += 3;
buf_size -= 3; buf_size -= 3;
} }
@ -603,13 +616,15 @@ int VP8Decode(VP8Decoder* const dec, VP8Io* const io) {
"Allocation failed"); "Allocation failed");
} }
if (io->setup && !io->setup(io)) { if (io->setup && !io->setup(io)) {
VP8Clear(dec); VP8Clear(dec);
return VP8SetError(dec, VP8_STATUS_USER_ABORT, return VP8SetError(dec, VP8_STATUS_USER_ABORT,
"Frame setup failed"); "Frame setup failed");
} }
// Disable filtering per user request (_after_ setup() is called)
if (io->bypass_filtering) dec->filter_type_ = 0;
// Main decoding loop // Main decoding loop
{ {
const int ret = ParseFrame(dec, io); const int ret = ParseFrame(dec, io);

View File

@ -18,6 +18,8 @@
extern "C" { extern "C" {
#endif #endif
#define WEBP_DECODER_ABI_VERSION 0x0001
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Lower-level API // Lower-level API
// //
@ -72,16 +74,29 @@ struct VP8Io {
// Input buffer. // Input buffer.
uint32_t data_size; uint32_t data_size;
const uint8_t* data; const uint8_t* data;
// If true, in-loop filtering will not be performed even if present in the
// bitstream. Switching off filtering may speed up decoding at the expense
// of more visible blocking. Note that output will also be non-compliant
// with the VP8 specifications.
int bypass_filtering;
}; };
// Internal, version-checked, entry point
extern int VP8InitIoInternal(VP8Io* const, int);
// Main decoding object. This is an opaque structure. // Main decoding object. This is an opaque structure.
typedef struct VP8Decoder VP8Decoder; typedef struct VP8Decoder VP8Decoder;
// Create a new decoder object. // Create a new decoder object.
VP8Decoder* VP8New(); VP8Decoder* VP8New();
// Can be called to make sure 'io' is initialized properly. // Must be called to make sure 'io' is initialized properly.
void VP8InitIo(VP8Io* const io); // Returns false in case of version mismatch. Upon such failure, no other
// decoding function should be called (VP8Decode, VP8GetHeaders, ...)
static inline int VP8InitIo(VP8Io* const io) {
return VP8InitIoInternal(io, WEBP_DECODER_ABI_VERSION);
}
// Start decoding a new picture. Returns true if ok. // Start decoding a new picture. Returns true if ok.
int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io); int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io);