From 9ef322830146d0b8bbc47e2ac2f39f17cfe5f7c4 Mon Sep 17 00:00:00 2001 From: Urvang Joshi Date: Thu, 31 May 2012 11:16:32 +0530 Subject: [PATCH] Add support for raw lossless bitstream in decoder. Previously, it used to assume any raw bitstream is a VP8 one. Also, - Factor out VP8CheckSignature() & VP8LCheckSignature(). - Use a local var for *data_ptr in ParseVP8Header() for readability. Change-Id: I0fa8aa177dad7865e00c8898f7e7ce76a9db19d5 --- src/dec/vp8.c | 9 +++++++-- src/dec/vp8i.h | 3 +++ src/dec/vp8l.c | 10 +++++++--- src/dec/vp8li.h | 3 +++ src/dec/webp.c | 28 +++++++++++++++++----------- 5 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/dec/vp8.c b/src/dec/vp8.c index fb9e63d8..6fe46531 100644 --- a/src/dec/vp8.c +++ b/src/dec/vp8.c @@ -82,13 +82,18 @@ int VP8SetError(VP8Decoder* const dec, //------------------------------------------------------------------------------ +int VP8CheckSignature(const uint8_t* const data, size_t data_size) { + return (data_size >= 3 && + data[0] == 0x9d && data[1] == 0x01 && data[2] == 0x2a); +} + int VP8GetInfo(const uint8_t* data, size_t data_size, size_t chunk_size, int* width, int* height) { if (data == NULL || data_size < VP8_FRAME_HEADER_SIZE) { return 0; // not enough data } // check signature - if (data[3] != 0x9d || data[4] != 0x01 || data[5] != 0x2a) { + if (!VP8CheckSignature(data + 3, data_size - 3)) { return 0; // Wrong signature. } else { const uint32_t bits = data[0] | (data[1] << 8) | (data[2] << 16); @@ -316,7 +321,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, "cannot parse picture header"); } - if (buf[0] != 0x9d || buf[1] != 0x01 || buf[2] != 0x2a) { + if (!VP8CheckSignature(buf, buf_size)) { return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, "Bad code word"); } diff --git a/src/dec/vp8i.h b/src/dec/vp8i.h index 9b4ba7e7..d811ca51 100644 --- a/src/dec/vp8i.h +++ b/src/dec/vp8i.h @@ -290,6 +290,9 @@ struct VP8Decoder { int VP8SetError(VP8Decoder* const dec, VP8StatusCode error, const char* const msg); +// Returns true if the next 3 bytes in data contain the VP8 signature. +int VP8CheckSignature(const uint8_t* const data, size_t data_size); + // Validates the VP8 data-header and retrieves basic header information viz // width and height. Returns 0 in case of formatting error. *width/*height // can be passed NULL. diff --git a/src/dec/vp8l.c b/src/dec/vp8l.c index daf22969..f6e255ce 100644 --- a/src/dec/vp8l.c +++ b/src/dec/vp8l.c @@ -78,11 +78,15 @@ static int DecodeImageStream(int xsize, int ysize, //------------------------------------------------------------------------------ +int VP8LCheckSignature(const uint8_t* const data, size_t size) { + return (size >= 1) && + (data[0] == VP8L_MAGIC_BYTE || data[0] == VP8L_MAGIC_BYTE_RSVD); +} + static int ReadImageSize(VP8LBitReader* const br, int* const width, int* const height) { - const int signature = VP8LReadBits(br, 8); - if (signature != VP8L_MAGIC_BYTE && - signature != VP8L_MAGIC_BYTE_RSVD) { + const uint8_t signature = VP8LReadBits(br, 8); + if (!VP8LCheckSignature(&signature, 1)) { return 0; } *width = VP8LReadBits(br, VP8L_IMAGE_SIZE_BITS) + 1; diff --git a/src/dec/vp8li.h b/src/dec/vp8li.h index 2332b513..f275c862 100644 --- a/src/dec/vp8li.h +++ b/src/dec/vp8li.h @@ -87,6 +87,9 @@ typedef struct { // in vp8l.c +// Returns true if the next byte(s) in data is a VP8L signature. +int VP8LCheckSignature(const uint8_t* const data, size_t size); + // Validates the VP8L data-header and retrieves basic header information viz // width and height. Returns 0 in case of formatting error. width/height // can be passed NULL. diff --git a/src/dec/webp.c b/src/dec/webp.c index 2b5a5695..fd9cc7ab 100644 --- a/src/dec/webp.c +++ b/src/dec/webp.c @@ -187,43 +187,49 @@ static VP8StatusCode ParseOptionalChunks(const uint8_t** data, } } -// Validates the VP8 Header ("VP8 nnnn" or "VP8L nnnn") and skips over it. +// Validates the VP8/VP8L Header ("VP8 nnnn" or "VP8L nnnn") and skips over it. // Returns VP8_STATUS_BITSTREAM_ERROR for invalid (chunk larger than -// riff_size) VP8 header, +// riff_size) VP8/VP8L header, // VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and // VP8_STATUS_OK otherwise. // If a VP8/VP8L chunk is found, chunk_size is set to the total number of bytes // extracted from the VP8/VP8L chunk header. -// The flag 'is_lossless' is set to 1 in case of VP8L chunk. -static VP8StatusCode ParseVP8Header(const uint8_t** data, size_t* data_size, +// The flag 'is_lossless' is set to 1 in case of VP8L chunk / raw VP8L data. +static VP8StatusCode ParseVP8Header(const uint8_t** data_ptr, size_t* data_size, size_t riff_size, size_t* chunk_size, int* is_lossless) { - const int is_vp8 = !memcmp(*data, "VP8 ", TAG_SIZE); - const int is_vp8l = !memcmp(*data, "VP8L", TAG_SIZE); + const uint8_t* const data = *data_ptr; + const int is_vp8 = !memcmp(data, "VP8 ", TAG_SIZE); + const int is_vp8l = !memcmp(data, "VP8L", TAG_SIZE); const uint32_t minimal_size = - TAG_SIZE + CHUNK_HEADER_SIZE; // "WEBP" + "VP8 nnnn" + TAG_SIZE + CHUNK_HEADER_SIZE; // "WEBP" + "VP8 nnnn" OR + // "WEBP" + "VP8Lnnnn" assert(data); assert(data_size); assert(chunk_size); assert(is_lossless); - *chunk_size = *data_size; // default: raw data - if (*data_size < CHUNK_HEADER_SIZE) { return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data. } if (is_vp8 || is_vp8l) { - const uint32_t size = get_le32(*data + TAG_SIZE); + // Bitstream contains VP8/VP8L header. + const uint32_t size = get_le32(data + TAG_SIZE); if ((riff_size >= minimal_size) && (size > riff_size - minimal_size)) { return VP8_STATUS_BITSTREAM_ERROR; // Inconsistent size information. } // Skip over CHUNK_HEADER_SIZE bytes from VP8/VP8L Header. *chunk_size = size; - *data += CHUNK_HEADER_SIZE; + *data_ptr += CHUNK_HEADER_SIZE; *data_size -= CHUNK_HEADER_SIZE; *is_lossless = is_vp8l; + } else { + // Raw VP8/VP8L bitstream (no header). + *is_lossless = VP8LCheckSignature(data, *data_size); + *chunk_size = *data_size; } + return VP8_STATUS_OK; }