mirror of
https://github.com/webmproject/libwebp.git
synced 2025-02-13 07:22:52 +01:00
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:
parent
7cbee29afa
commit
9ef3228301
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user