summaryrefslogtreecommitdiff
path: root/drivers/webp/dec/webp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/webp/dec/webp.c')
-rw-r--r--drivers/webp/dec/webp.c155
1 files changed, 52 insertions, 103 deletions
diff --git a/drivers/webp/dec/webp.c b/drivers/webp/dec/webp.c
index fda88bda26..edd348cbe7 100644
--- a/drivers/webp/dec/webp.c
+++ b/drivers/webp/dec/webp.c
@@ -1,10 +1,8 @@
// Copyright 2010 Google Inc. All Rights Reserved.
//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the COPYING file in the root of the source
-// tree. An additional intellectual property rights grant can be found
-// in the file PATENTS. All contributing project authors may
-// be found in the AUTHORS file in the root of the source tree.
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
// -----------------------------------------------------------------------------
//
// Main decoding functions for WEBP images.
@@ -16,7 +14,11 @@
#include "./vp8i.h"
#include "./vp8li.h"
#include "./webpi.h"
-#include "../webp/mux_types.h" // ALPHA_FLAG
+#include "../webp/format_constants.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
//------------------------------------------------------------------------------
// RIFF layout is:
@@ -38,8 +40,8 @@
// 20..23 VP8X flags bit-map corresponding to the chunk-types present.
// 24..26 Width of the Canvas Image.
// 27..29 Height of the Canvas Image.
-// There can be extra chunks after the "VP8X" chunk (ICCP, FRGM, ANMF, VP8,
-// VP8L, XMP, EXIF ...)
+// There can be extra chunks after the "VP8X" chunk (ICCP, TILE, FRM, VP8,
+// META ...)
// All sizes are in little-endian order.
// Note: chunk data size must be padded to multiple of 2 when written.
@@ -74,9 +76,6 @@ static VP8StatusCode ParseRIFF(const uint8_t** const data,
if (size < TAG_SIZE + CHUNK_HEADER_SIZE) {
return VP8_STATUS_BITSTREAM_ERROR;
}
- if (size > MAX_CHUNK_PAYLOAD) {
- return VP8_STATUS_BITSTREAM_ERROR;
- }
// We have a RIFF container. Skip it.
*riff_size = size;
*data += RIFF_HEADER_SIZE;
@@ -178,9 +177,6 @@ static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
}
chunk_size = get_le32(buf + TAG_SIZE);
- if (chunk_size > MAX_CHUNK_PAYLOAD) {
- return VP8_STATUS_BITSTREAM_ERROR; // Not a valid chunk size.
- }
// For odd-sized chunk-payload, there's one byte padding at the end.
disk_chunk_size = (CHUNK_HEADER_SIZE + chunk_size + 1) & ~1;
total_size += disk_chunk_size;
@@ -190,15 +186,6 @@ static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
return VP8_STATUS_BITSTREAM_ERROR; // Not a valid chunk size.
}
- // Start of a (possibly incomplete) VP8/VP8L chunk implies that we have
- // parsed all the optional chunks.
- // Note: This check must occur before the check 'buf_size < disk_chunk_size'
- // below to allow incomplete VP8/VP8L chunks.
- if (!memcmp(buf, "VP8 ", TAG_SIZE) ||
- !memcmp(buf, "VP8L", TAG_SIZE)) {
- return VP8_STATUS_OK;
- }
-
if (buf_size < disk_chunk_size) { // Insufficient data.
return VP8_STATUS_NOT_ENOUGH_DATA;
}
@@ -206,6 +193,9 @@ static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
if (!memcmp(buf, "ALPH", TAG_SIZE)) { // A valid ALPH header.
*alpha_data = buf + CHUNK_HEADER_SIZE;
*alpha_size = chunk_size;
+ } else if (!memcmp(buf, "VP8 ", TAG_SIZE) ||
+ !memcmp(buf, "VP8L", TAG_SIZE)) { // A valid VP8/VP8L header.
+ return VP8_STATUS_OK; // Found.
}
// We have a full and valid chunk; skip it.
@@ -280,18 +270,9 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
int* const width,
int* const height,
int* const has_alpha,
- int* const has_animation,
- int* const format,
WebPHeaderStructure* const headers) {
- int canvas_width = 0;
- int canvas_height = 0;
- int image_width = 0;
- int image_height = 0;
int found_riff = 0;
int found_vp8x = 0;
- int animation_present = 0;
- int fragments_present = 0;
-
VP8StatusCode status;
WebPHeaderStructure hdrs;
@@ -312,35 +293,22 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
// Skip over VP8X.
{
uint32_t flags = 0;
- status = ParseVP8X(&data, &data_size, &found_vp8x,
- &canvas_width, &canvas_height, &flags);
+ status = ParseVP8X(&data, &data_size, &found_vp8x, width, height, &flags);
if (status != VP8_STATUS_OK) {
return status; // Wrong VP8X / insufficient data.
}
- animation_present = !!(flags & ANIMATION_FLAG);
- fragments_present = !!(flags & FRAGMENTS_FLAG);
if (!found_riff && found_vp8x) {
// Note: This restriction may be removed in the future, if it becomes
// necessary to send VP8X chunk to the decoder.
return VP8_STATUS_BITSTREAM_ERROR;
}
- if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG);
- if (has_animation != NULL) *has_animation = animation_present;
- if (format != NULL) *format = 0; // default = undefined
-
- image_width = canvas_width;
- image_height = canvas_height;
- if (found_vp8x && (animation_present || fragments_present) &&
- headers == NULL) {
- status = VP8_STATUS_OK;
- goto ReturnWidthHeight; // Just return features from VP8X header.
+ 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) {
- status = VP8_STATUS_NOT_ENOUGH_DATA;
- goto ReturnWidthHeight;
- }
+ if (data_size < TAG_SIZE) return VP8_STATUS_NOT_ENOUGH_DATA;
// Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH".
if ((found_riff && found_vp8x) ||
@@ -348,7 +316,7 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size,
&hdrs.alpha_data, &hdrs.alpha_data_size);
if (status != VP8_STATUS_OK) {
- goto ReturnWidthHeight; // Invalid chunk size / insufficient data.
+ return status; // Found an invalid chunk size / insufficient data.
}
}
@@ -356,41 +324,35 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
status = ParseVP8Header(&data, &data_size, hdrs.riff_size,
&hdrs.compressed_size, &hdrs.is_lossless);
if (status != VP8_STATUS_OK) {
- goto ReturnWidthHeight; // Wrong VP8/VP8L chunk-header / insufficient data.
+ return status; // Wrong VP8/VP8L chunk-header / insufficient data.
}
if (hdrs.compressed_size > MAX_CHUNK_PAYLOAD) {
return VP8_STATUS_BITSTREAM_ERROR;
}
- if (format != NULL && !(animation_present || fragments_present)) {
- *format = hdrs.is_lossless ? 2 : 1;
- }
-
if (!hdrs.is_lossless) {
if (data_size < VP8_FRAME_HEADER_SIZE) {
- status = VP8_STATUS_NOT_ENOUGH_DATA;
- goto ReturnWidthHeight;
+ return VP8_STATUS_NOT_ENOUGH_DATA;
}
// Validates raw VP8 data.
- if (!VP8GetInfo(data, data_size, (uint32_t)hdrs.compressed_size,
- &image_width, &image_height)) {
+ 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) {
- status = VP8_STATUS_NOT_ENOUGH_DATA;
- goto ReturnWidthHeight;
+ return VP8_STATUS_NOT_ENOUGH_DATA;
}
// Validates raw VP8L data.
- if (!VP8LGetInfo(data, data_size, &image_width, &image_height, has_alpha)) {
+ if (!VP8LGetInfo(data, data_size, width, height, has_alpha)) {
return VP8_STATUS_BITSTREAM_ERROR;
}
}
- // Validates image size coherency.
- if (found_vp8x) {
- if (canvas_width != image_width || canvas_height != image_height) {
- 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;
@@ -398,44 +360,21 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
assert((uint64_t)(data - headers->data) < MAX_CHUNK_PAYLOAD);
assert(headers->offset == headers->data_size - data_size);
}
- ReturnWidthHeight:
- if (status == VP8_STATUS_OK ||
- (status == VP8_STATUS_NOT_ENOUGH_DATA && found_vp8x && headers == NULL)) {
- 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 (width != NULL) *width = image_width;
- if (height != NULL) *height = image_height;
- return VP8_STATUS_OK;
- } else {
- return status;
- }
+ return VP8_STATUS_OK; // Return features from VP8 header.
}
VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) {
- VP8StatusCode status;
- int has_animation = 0;
assert(headers != NULL);
// fill out headers, ignore width/height/has_alpha.
- status = ParseHeadersInternal(headers->data, headers->data_size,
- NULL, NULL, NULL, &has_animation,
- NULL, headers);
- if (status == VP8_STATUS_OK || status == VP8_STATUS_NOT_ENOUGH_DATA) {
- // TODO(jzern): full support of animation frames will require API additions.
- if (has_animation) {
- status = VP8_STATUS_UNSUPPORTED_FEATURE;
- }
- }
- return status;
+ return ParseHeadersInternal(headers->data, headers->data_size,
+ NULL, NULL, NULL, headers);
}
//------------------------------------------------------------------------------
// WebPDecParams
void WebPResetDecParams(WebPDecParams* const params) {
- if (params != NULL) {
+ if (params) {
memset(params, 0, sizeof(*params));
}
}
@@ -468,6 +407,11 @@ static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
if (dec == NULL) {
return VP8_STATUS_OUT_OF_MEMORY;
}
+#ifdef WEBP_USE_THREAD
+ dec->use_threads_ = params->options && (params->options->use_threads > 0);
+#else
+ dec->use_threads_ = 0;
+#endif
dec->alpha_data_ = headers.alpha_data;
dec->alpha_data_size_ = headers.alpha_data_size;
@@ -479,10 +423,6 @@ static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
status = WebPAllocateDecBuffer(io.width, io.height, params->options,
params->output);
if (status == VP8_STATUS_OK) { // Decode
- // This change must be done before calling VP8Decode()
- dec->mt_method_ = VP8GetThreadMethod(params->options, &headers,
- io.width, io.height);
- VP8InitDithering(params->options, dec);
if (!VP8Decode(dec, &io)) {
status = dec->status_;
}
@@ -669,6 +609,7 @@ uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size,
static void DefaultFeatures(WebPBitstreamFeatures* const features) {
assert(features != NULL);
memset(features, 0, sizeof(*features));
+ features->bitstream_version = 0;
}
static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size,
@@ -678,11 +619,10 @@ static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size,
}
DefaultFeatures(features);
- // Only parse enough of the data to retrieve the features.
+ // Only parse enough of the data to retrieve width/height/has_alpha.
return ParseHeadersInternal(data, data_size,
&features->width, &features->height,
- &features->has_alpha, &features->has_animation,
- &features->format, NULL);
+ &features->has_alpha, NULL);
}
//------------------------------------------------------------------------------
@@ -726,13 +666,19 @@ int WebPInitDecoderConfigInternal(WebPDecoderConfig* config,
VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size,
WebPBitstreamFeatures* features,
int version) {
+ VP8StatusCode status;
if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
return VP8_STATUS_INVALID_PARAM; // version mismatch
}
if (features == NULL) {
return VP8_STATUS_INVALID_PARAM;
}
- return GetFeatures(data, data_size, features);
+
+ status = GetFeatures(data, data_size, features);
+ if (status == VP8_STATUS_NOT_ENOUGH_DATA) {
+ return VP8_STATUS_BITSTREAM_ERROR; // Not-enough-data treated as error.
+ }
+ return status;
}
VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
@@ -820,3 +766,6 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
//------------------------------------------------------------------------------
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif