diff options
Diffstat (limited to 'drivers/webp/dec/webp.c')
-rw-r--r-- | drivers/webp/dec/webp.c | 155 |
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 |