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* 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");
}

View File

@ -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.

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,
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;

View File

@ -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.

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
// 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;
}