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
This commit is contained in:
Urvang Joshi 2012-05-31 11:16:32 +05:30
parent 7cbee29afa
commit 9ef3228301
5 changed files with 37 additions and 16 deletions

View File

@ -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 VP8GetInfo(const uint8_t* data, size_t data_size, size_t chunk_size,
int* width, int* height) { int* width, int* height) {
if (data == NULL || data_size < VP8_FRAME_HEADER_SIZE) { if (data == NULL || data_size < VP8_FRAME_HEADER_SIZE) {
return 0; // not enough data return 0; // not enough data
} }
// check signature // check signature
if (data[3] != 0x9d || data[4] != 0x01 || data[5] != 0x2a) { if (!VP8CheckSignature(data + 3, data_size - 3)) {
return 0; // Wrong signature. return 0; // Wrong signature.
} else { } else {
const uint32_t bits = data[0] | (data[1] << 8) | (data[2] << 16); 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, return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
"cannot parse picture header"); "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, return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
"Bad code word"); "Bad code word");
} }

View File

@ -290,6 +290,9 @@ struct VP8Decoder {
int VP8SetError(VP8Decoder* const dec, int VP8SetError(VP8Decoder* const dec,
VP8StatusCode error, const char* const msg); 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 // Validates the VP8 data-header and retrieves basic header information viz
// width and height. Returns 0 in case of formatting error. *width/*height // width and height. Returns 0 in case of formatting error. *width/*height
// can be passed NULL. // can be passed NULL.

View File

@ -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, static int ReadImageSize(VP8LBitReader* const br,
int* const width, int* const height) { int* const width, int* const height) {
const int signature = VP8LReadBits(br, 8); const uint8_t signature = VP8LReadBits(br, 8);
if (signature != VP8L_MAGIC_BYTE && if (!VP8LCheckSignature(&signature, 1)) {
signature != VP8L_MAGIC_BYTE_RSVD) {
return 0; return 0;
} }
*width = VP8LReadBits(br, VP8L_IMAGE_SIZE_BITS) + 1; *width = VP8LReadBits(br, VP8L_IMAGE_SIZE_BITS) + 1;

View File

@ -87,6 +87,9 @@ typedef struct {
// in vp8l.c // 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 // Validates the VP8L data-header and retrieves basic header information viz
// width and height. Returns 0 in case of formatting error. width/height // width and height. Returns 0 in case of formatting error. width/height
// can be passed NULL. // can be passed NULL.

View File

@ -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 // 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_NOT_ENOUGH_DATA in case of insufficient data, and
// VP8_STATUS_OK otherwise. // VP8_STATUS_OK otherwise.
// If a VP8/VP8L chunk is found, chunk_size is set to the total number of bytes // If a VP8/VP8L chunk is found, chunk_size is set to the total number of bytes
// extracted from the VP8/VP8L chunk header. // extracted from the VP8/VP8L chunk header.
// The flag 'is_lossless' is set to 1 in case of VP8L chunk. // The flag 'is_lossless' is set to 1 in case of VP8L chunk / raw VP8L data.
static VP8StatusCode ParseVP8Header(const uint8_t** data, size_t* data_size, static VP8StatusCode ParseVP8Header(const uint8_t** data_ptr, size_t* data_size,
size_t riff_size, size_t riff_size,
size_t* chunk_size, int* is_lossless) { size_t* chunk_size, int* is_lossless) {
const int is_vp8 = !memcmp(*data, "VP8 ", TAG_SIZE); const uint8_t* const data = *data_ptr;
const int is_vp8l = !memcmp(*data, "VP8L", TAG_SIZE); const int is_vp8 = !memcmp(data, "VP8 ", TAG_SIZE);
const int is_vp8l = !memcmp(data, "VP8L", TAG_SIZE);
const uint32_t minimal_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);
assert(data_size); assert(data_size);
assert(chunk_size); assert(chunk_size);
assert(is_lossless); assert(is_lossless);
*chunk_size = *data_size; // default: raw data
if (*data_size < CHUNK_HEADER_SIZE) { if (*data_size < CHUNK_HEADER_SIZE) {
return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data. return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data.
} }
if (is_vp8 || is_vp8l) { 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)) { if ((riff_size >= minimal_size) && (size > riff_size - minimal_size)) {
return VP8_STATUS_BITSTREAM_ERROR; // Inconsistent size information. return VP8_STATUS_BITSTREAM_ERROR; // Inconsistent size information.
} }
// Skip over CHUNK_HEADER_SIZE bytes from VP8/VP8L Header. // Skip over CHUNK_HEADER_SIZE bytes from VP8/VP8L Header.
*chunk_size = size; *chunk_size = size;
*data += CHUNK_HEADER_SIZE; *data_ptr += CHUNK_HEADER_SIZE;
*data_size -= CHUNK_HEADER_SIZE; *data_size -= CHUNK_HEADER_SIZE;
*is_lossless = is_vp8l; *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; return VP8_STATUS_OK;
} }