mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-27 22:28:22 +01:00
Merge "modify WebPParseHeaders to allow reuse by GetFeatures"
This commit is contained in:
commit
2f66668882
@ -22,7 +22,6 @@ extern "C" {
|
|||||||
|
|
||||||
#define NUM_ARGB_CACHE_ROWS 16
|
#define NUM_ARGB_CACHE_ROWS 16
|
||||||
|
|
||||||
static const size_t kHeaderBytes = 5;
|
|
||||||
static const int kCodeLengthLiterals = 16;
|
static const int kCodeLengthLiterals = 16;
|
||||||
static const int kCodeLengthRepeatCode = 16;
|
static const int kCodeLengthRepeatCode = 16;
|
||||||
static const int kCodeLengthExtraBits[3] = { 2, 3, 7 };
|
static const int kCodeLengthExtraBits[3] = { 2, 3, 7 };
|
||||||
@ -98,7 +97,7 @@ static int ReadImageInfo(VP8LBitReader* const br,
|
|||||||
|
|
||||||
int VP8LGetInfo(const uint8_t* data, size_t data_size,
|
int VP8LGetInfo(const uint8_t* data, size_t data_size,
|
||||||
int* const width, int* const height, int* const has_alpha) {
|
int* const width, int* const height, int* const has_alpha) {
|
||||||
if (data == NULL || data_size < kHeaderBytes) {
|
if (data == NULL || data_size < VP8L_FRAME_HEADER_SIZE) {
|
||||||
return 0; // not enough data
|
return 0; // not enough data
|
||||||
} else {
|
} else {
|
||||||
int w, h, a;
|
int w, h, a;
|
||||||
|
179
src/dec/webp.c
179
src/dec/webp.c
@ -241,58 +241,117 @@ static VP8StatusCode ParseVP8Header(const uint8_t** data_ptr, size_t* data_size,
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) {
|
// Returns true if 'fourcc' matches a chunk that can appear in a 'VP8X' file.
|
||||||
const uint8_t* buf;
|
// Image chunks are dealt with separately so are not included here.
|
||||||
size_t buf_size;
|
static int IsExtendedFormatChunk(const uint8_t fourcc[4]) {
|
||||||
int found_vp8x;
|
return (!memcmp(fourcc, "ALPH", TAG_SIZE) ||
|
||||||
|
!memcmp(fourcc, "FRM ", TAG_SIZE) ||
|
||||||
|
!memcmp(fourcc, "ICCP", TAG_SIZE) ||
|
||||||
|
!memcmp(fourcc, "LOOP", TAG_SIZE) ||
|
||||||
|
!memcmp(fourcc, "META", TAG_SIZE) ||
|
||||||
|
!memcmp(fourcc, "TILE", TAG_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch 'width', 'height', 'has_alpha' and fill out 'headers' based on 'data'.
|
||||||
|
// All the output parameters may be NULL. If 'headers' is NULL only the minimal
|
||||||
|
// amount will be read to fetch the remaining parameters.
|
||||||
|
// If 'headers' is non-NULL this function will attempt to locate both alpha
|
||||||
|
// data (with or without a VP8X chunk) and the bitstream chunk (VP8/VP8L).
|
||||||
|
static VP8StatusCode ParseHeadersInternal(
|
||||||
|
const uint8_t* data, size_t data_size,
|
||||||
|
int* const width, int* const height, int* const has_alpha,
|
||||||
|
WebPHeaderStructure* const headers) {
|
||||||
|
int found_vp8x = 0;
|
||||||
VP8StatusCode status;
|
VP8StatusCode status;
|
||||||
|
WebPHeaderStructure hdrs;
|
||||||
|
|
||||||
assert(headers);
|
if (data == NULL || data_size < RIFF_HEADER_SIZE) {
|
||||||
|
|
||||||
buf = headers->data;
|
|
||||||
buf_size = headers->data_size;
|
|
||||||
headers->alpha_data = NULL;
|
|
||||||
headers->alpha_data_size = 0;
|
|
||||||
headers->compressed_size = 0;
|
|
||||||
headers->is_lossless = 0;
|
|
||||||
headers->offset = 0;
|
|
||||||
headers->riff_size = 0;
|
|
||||||
|
|
||||||
if (buf == NULL || buf_size < RIFF_HEADER_SIZE) {
|
|
||||||
return VP8_STATUS_NOT_ENOUGH_DATA;
|
return VP8_STATUS_NOT_ENOUGH_DATA;
|
||||||
}
|
}
|
||||||
|
memset(&hdrs, 0, sizeof(hdrs));
|
||||||
|
hdrs.data = data;
|
||||||
|
hdrs.data_size = data_size;
|
||||||
|
|
||||||
// Skip over RIFF header.
|
// Skip over RIFF header.
|
||||||
if (ParseRIFF(&buf, &buf_size, &headers->riff_size) != VP8_STATUS_OK) {
|
status = ParseRIFF(&data, &data_size, &hdrs.riff_size);
|
||||||
return VP8_STATUS_BITSTREAM_ERROR; // Wrong RIFF header.
|
if (status != VP8_STATUS_OK) {
|
||||||
|
return status; // Wrong RIFF header / insufficient data.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip over VP8X header.
|
// Skip over VP8X.
|
||||||
status = ParseVP8X(&buf, &buf_size, &found_vp8x, NULL, NULL, NULL);
|
{
|
||||||
|
uint32_t flags = 0;
|
||||||
|
status = ParseVP8X(&data, &data_size, &found_vp8x, width, height, &flags);
|
||||||
if (status != VP8_STATUS_OK) {
|
if (status != VP8_STATUS_OK) {
|
||||||
return status; // Wrong VP8X chunk / insufficient data.
|
return status; // Wrong VP8X / insufficient data.
|
||||||
}
|
}
|
||||||
if (found_vp8x) {
|
if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG_BIT);
|
||||||
|
if (found_vp8x && headers == NULL) {
|
||||||
|
return VP8_STATUS_OK; // Return features from VP8X header.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data_size < TAG_SIZE) return VP8_STATUS_NOT_ENOUGH_DATA;
|
||||||
|
|
||||||
// Skip over optional chunks.
|
// Skip over optional chunks.
|
||||||
status = ParseOptionalChunks(&buf, &buf_size, headers->riff_size,
|
// If a VP8X chunk was not found look for chunks that may be contained within
|
||||||
&headers->alpha_data,
|
// one to initiate the parse.
|
||||||
&headers->alpha_data_size);
|
if (found_vp8x || IsExtendedFormatChunk(data)) {
|
||||||
|
status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size,
|
||||||
|
&hdrs.alpha_data, &hdrs.alpha_data_size);
|
||||||
if (status != VP8_STATUS_OK) {
|
if (status != VP8_STATUS_OK) {
|
||||||
return status; // Found an invalid chunk size / insufficient data.
|
return status; // Found an invalid chunk size / insufficient data.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip over VP8/VP8L chunk header.
|
// Skip over VP8/VP8L header.
|
||||||
status = ParseVP8Header(&buf, &buf_size, headers->riff_size,
|
status = ParseVP8Header(&data, &data_size, hdrs.riff_size,
|
||||||
&headers->compressed_size, &headers->is_lossless);
|
&hdrs.compressed_size, &hdrs.is_lossless);
|
||||||
if (status != VP8_STATUS_OK) {
|
if (status != VP8_STATUS_OK) {
|
||||||
return status; // Invalid VP8/VP8L header / insufficient data.
|
return status; // Wrong VP8/VP8L chunk-header / insufficient data.
|
||||||
|
}
|
||||||
|
if (hdrs.compressed_size > MAX_CHUNK_PAYLOAD) {
|
||||||
|
return VP8_STATUS_BITSTREAM_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
headers->offset = (uint32_t)(buf - headers->data);
|
if (!hdrs.is_lossless) {
|
||||||
assert((uint64_t)(buf - headers->data) < MAX_CHUNK_PAYLOAD);
|
if (data_size < VP8_FRAME_HEADER_SIZE) {
|
||||||
assert(headers->offset == headers->data_size - buf_size);
|
return VP8_STATUS_NOT_ENOUGH_DATA;
|
||||||
return VP8_STATUS_OK;
|
}
|
||||||
|
// Validates raw VP8 data.
|
||||||
|
if (!VP8GetInfo(data, data_size,
|
||||||
|
(uint32_t)hdrs.compressed_size, width, height)) {
|
||||||
|
return VP8_STATUS_BITSTREAM_ERROR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (data_size < VP8L_FRAME_HEADER_SIZE) {
|
||||||
|
return VP8_STATUS_NOT_ENOUGH_DATA;
|
||||||
|
}
|
||||||
|
// Validates raw VP8L data.
|
||||||
|
if (!VP8LGetInfo(data, data_size, width, height, has_alpha)) {
|
||||||
|
return VP8_STATUS_BITSTREAM_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_alpha != NULL) {
|
||||||
|
// If the data did not contain a VP8X/VP8L chunk the only definitive way
|
||||||
|
// to set this is by looking for alpha data (from an ALPH chunk).
|
||||||
|
*has_alpha |= (hdrs.alpha_data != NULL);
|
||||||
|
}
|
||||||
|
if (headers != NULL) {
|
||||||
|
*headers = hdrs;
|
||||||
|
headers->offset = data - headers->data;
|
||||||
|
assert((uint64_t)(data - headers->data) < MAX_CHUNK_PAYLOAD);
|
||||||
|
assert(headers->offset == headers->data_size - data_size);
|
||||||
|
}
|
||||||
|
return VP8_STATUS_OK; // Return features from VP8 header.
|
||||||
|
}
|
||||||
|
|
||||||
|
VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) {
|
||||||
|
assert(headers != NULL);
|
||||||
|
// fill out headers, ignore width/height/has_alpha.
|
||||||
|
return ParseHeadersInternal(headers->data, headers->data_size,
|
||||||
|
NULL, NULL, NULL, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@ -537,61 +596,15 @@ static void DefaultFeatures(WebPBitstreamFeatures* const features) {
|
|||||||
|
|
||||||
static VP8StatusCode GetFeatures(const uint8_t* data, size_t data_size,
|
static VP8StatusCode GetFeatures(const uint8_t* data, size_t data_size,
|
||||||
WebPBitstreamFeatures* const features) {
|
WebPBitstreamFeatures* const features) {
|
||||||
size_t chunk_size = 0;
|
|
||||||
size_t riff_size = 0;
|
|
||||||
int* const width = &features->width;
|
|
||||||
int* const height = &features->height;
|
|
||||||
int found_vp8x;
|
|
||||||
int is_lossless = 0;
|
|
||||||
VP8StatusCode status;
|
|
||||||
|
|
||||||
if (features == NULL || data == NULL) {
|
if (features == NULL || data == NULL) {
|
||||||
return VP8_STATUS_INVALID_PARAM;
|
return VP8_STATUS_INVALID_PARAM;
|
||||||
}
|
}
|
||||||
DefaultFeatures(features);
|
DefaultFeatures(features);
|
||||||
|
|
||||||
// Skip over RIFF header.
|
// Only parse enough of the data to retrieve width/height/has_alpha.
|
||||||
status = ParseRIFF(&data, &data_size, &riff_size);
|
return ParseHeadersInternal(data, data_size,
|
||||||
if (status != VP8_STATUS_OK) {
|
&features->width, &features->height,
|
||||||
return status; // Wrong RIFF header / insufficient data.
|
&features->has_alpha, NULL);
|
||||||
}
|
|
||||||
|
|
||||||
// Skip over VP8X.
|
|
||||||
{
|
|
||||||
uint32_t flags = 0;
|
|
||||||
status = ParseVP8X(&data, &data_size, &found_vp8x, width, height, &flags);
|
|
||||||
if (status != VP8_STATUS_OK) {
|
|
||||||
return status; // Wrong VP8X / insufficient data.
|
|
||||||
}
|
|
||||||
features->has_alpha = !!(flags & ALPHA_FLAG_BIT);
|
|
||||||
if (found_vp8x) {
|
|
||||||
return VP8_STATUS_OK; // Return features from VP8X header.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip over VP8/VP8L header.
|
|
||||||
status = ParseVP8Header(&data, &data_size, riff_size,
|
|
||||||
&chunk_size, &is_lossless);
|
|
||||||
if (status != VP8_STATUS_OK) {
|
|
||||||
return status; // Wrong VP8/VP8L chunk-header / insufficient data.
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_lossless) {
|
|
||||||
// Validates raw VP8 data.
|
|
||||||
if (chunk_size != (uint32_t)chunk_size ||
|
|
||||||
!VP8GetInfo(data, data_size, (uint32_t)chunk_size, width, height)) {
|
|
||||||
return VP8_STATUS_BITSTREAM_ERROR;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int has_alpha;
|
|
||||||
// Validates raw VP8L data.
|
|
||||||
if (!VP8LGetInfo(data, data_size, width, height, &has_alpha)) {
|
|
||||||
return VP8_STATUS_BITSTREAM_ERROR;
|
|
||||||
}
|
|
||||||
features->has_alpha = has_alpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
return VP8_STATUS_OK; // Return features from VP8 header.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
// width and height.
|
// width and height.
|
||||||
#define VP8L_VERSION_BITS 3 // 3 bits reserved for version.
|
#define VP8L_VERSION_BITS 3 // 3 bits reserved for version.
|
||||||
#define VP8L_VERSION 0 // version 0
|
#define VP8L_VERSION 0 // version 0
|
||||||
|
#define VP8L_FRAME_HEADER_SIZE 5 // Size of the VP8L frame header.
|
||||||
|
|
||||||
#define MAX_PALETTE_SIZE 256
|
#define MAX_PALETTE_SIZE 256
|
||||||
#define MAX_CACHE_BITS 11
|
#define MAX_CACHE_BITS 11
|
||||||
|
Loading…
Reference in New Issue
Block a user