| Index: third_party/libwebp/dec/idec.c
|
| diff --git a/third_party/libwebp/dec/idec.c b/third_party/libwebp/dec/idec.c
|
| index 61635ec99c47987648a8af965c02ace9de7f4ed8..40d5ff6e0d3d855ad71ee9000b9c92260baefbe4 100644
|
| --- a/third_party/libwebp/dec/idec.c
|
| +++ b/third_party/libwebp/dec/idec.c
|
| @@ -15,14 +15,11 @@
|
| #include <string.h>
|
| #include <stdlib.h>
|
|
|
| +#include "./alphai.h"
|
| #include "./webpi.h"
|
| #include "./vp8i.h"
|
| #include "../utils/utils.h"
|
|
|
| -#if defined(__cplusplus) || defined(c_plusplus)
|
| -extern "C" {
|
| -#endif
|
| -
|
| // In append mode, buffer allocations increase as multiples of this value.
|
| // Needs to be a power of 2.
|
| #define CHUNK_SIZE 4096
|
| @@ -31,11 +28,13 @@ extern "C" {
|
| //------------------------------------------------------------------------------
|
| // Data structures for memory and states
|
|
|
| -// Decoding states. State normally flows like HEADER->PARTS0->DATA->DONE.
|
| +// Decoding states. State normally flows as:
|
| +// WEBP_HEADER->VP8_HEADER->VP8_PARTS0->VP8_DATA->DONE for a lossy image, and
|
| +// WEBP_HEADER->VP8L_HEADER->VP8L_DATA->DONE for a lossless image.
|
| // If there is any error the decoder goes into state ERROR.
|
| typedef enum {
|
| - STATE_PRE_VP8, // All data before that of the first VP8 chunk.
|
| - STATE_VP8_FRAME_HEADER, // For VP8 Frame header (within VP8 chunk).
|
| + STATE_WEBP_HEADER, // All the data before that of the VP8/VP8L chunk.
|
| + STATE_VP8_HEADER, // The VP8 Frame header (within the VP8 chunk).
|
| STATE_VP8_PARTS0,
|
| STATE_VP8_DATA,
|
| STATE_VP8L_HEADER,
|
| @@ -102,7 +101,7 @@ static WEBP_INLINE size_t MemDataSize(const MemBuffer* mem) {
|
| // Check if we need to preserve the compressed alpha data, as it may not have
|
| // been decoded yet.
|
| static int NeedCompressedAlpha(const WebPIDecoder* const idec) {
|
| - if (idec->state_ == STATE_PRE_VP8) {
|
| + if (idec->state_ == STATE_WEBP_HEADER) {
|
| // We haven't parsed the headers yet, so we don't know whether the image is
|
| // lossy or lossless. This also means that we haven't parsed the ALPH chunk.
|
| return 0;
|
| @@ -111,7 +110,7 @@ static int NeedCompressedAlpha(const WebPIDecoder* const idec) {
|
| return 0; // ALPH chunk is not present for lossless images.
|
| } else {
|
| const VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
|
| - assert(dec != NULL); // Must be true as idec->state_ != STATE_PRE_VP8.
|
| + assert(dec != NULL); // Must be true as idec->state_ != STATE_WEBP_HEADER.
|
| return (dec->alpha_data_ != NULL) && !dec->is_alpha_decoded_;
|
| }
|
| }
|
| @@ -141,7 +140,22 @@ static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
|
| }
|
| assert(last_part >= 0);
|
| dec->parts_[last_part].buf_end_ = mem->buf_ + mem->end_;
|
| - if (NeedCompressedAlpha(idec)) dec->alpha_data_ += offset;
|
| + if (NeedCompressedAlpha(idec)) {
|
| + ALPHDecoder* const alph_dec = dec->alph_dec_;
|
| + dec->alpha_data_ += offset;
|
| + if (alph_dec != NULL) {
|
| + if (alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION) {
|
| + VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec_;
|
| + assert(alph_vp8l_dec != NULL);
|
| + assert(dec->alpha_data_size_ >= ALPHA_HEADER_LEN);
|
| + VP8LBitReaderSetBuffer(&alph_vp8l_dec->br_,
|
| + dec->alpha_data_ + ALPHA_HEADER_LEN,
|
| + dec->alpha_data_size_ - ALPHA_HEADER_LEN);
|
| + } else { // alph_dec->method_ == ALPHA_NO_COMPRESSION
|
| + // Nothing special to do in this case.
|
| + }
|
| + }
|
| + }
|
| } else { // Resize lossless bitreader
|
| VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_;
|
| VP8LBitReaderSetBuffer(&dec->br_, new_base, MemDataSize(mem));
|
| @@ -268,7 +282,7 @@ static void RestoreContext(const MBContext* context, VP8Decoder* const dec,
|
| static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) {
|
| if (idec->state_ == STATE_VP8_DATA) {
|
| VP8Io* const io = &idec->io_;
|
| - if (io->teardown) {
|
| + if (io->teardown != NULL) {
|
| io->teardown(io);
|
| }
|
| }
|
| @@ -311,15 +325,9 @@ static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) {
|
| return VP8_STATUS_OUT_OF_MEMORY;
|
| }
|
| idec->dec_ = dec;
|
| -#ifdef WEBP_USE_THREAD
|
| - dec->use_threads_ = (idec->params_.options != NULL) &&
|
| - (idec->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;
|
| - ChangeState(idec, STATE_VP8_FRAME_HEADER, headers.offset);
|
| + ChangeState(idec, STATE_VP8_HEADER, headers.offset);
|
| } else {
|
| VP8LDecoder* const dec = VP8LNew();
|
| if (dec == NULL) {
|
| @@ -334,13 +342,14 @@ static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) {
|
| static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) {
|
| const uint8_t* data = idec->mem_.buf_ + idec->mem_.start_;
|
| const size_t curr_size = MemDataSize(&idec->mem_);
|
| + int width, height;
|
| uint32_t bits;
|
|
|
| if (curr_size < VP8_FRAME_HEADER_SIZE) {
|
| // Not enough data bytes to extract VP8 Frame Header.
|
| return VP8_STATUS_SUSPENDED;
|
| }
|
| - if (!VP8GetInfo(data, curr_size, idec->chunk_size_, NULL, NULL)) {
|
| + if (!VP8GetInfo(data, curr_size, idec->chunk_size_, &width, &height)) {
|
| return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
|
| }
|
|
|
| @@ -407,7 +416,10 @@ static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) {
|
| if (dec->status_ != VP8_STATUS_OK) {
|
| return IDecError(idec, dec->status_);
|
| }
|
| -
|
| + // This change must be done before calling VP8InitFrame()
|
| + dec->mt_method_ = VP8GetThreadMethod(params->options, NULL,
|
| + io->width, io->height);
|
| + VP8InitDithering(params->options, dec);
|
| if (!CopyParts0Data(idec)) {
|
| return IDecError(idec, VP8_STATUS_OUT_OF_MEMORY);
|
| }
|
| @@ -433,16 +445,11 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
|
| VP8Io* const io = &idec->io_;
|
|
|
| assert(dec->ready_);
|
| -
|
| for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) {
|
| VP8BitReader* token_br = &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)];
|
| - if (dec->mb_x_ == 0) {
|
| - VP8InitScanline(dec);
|
| - }
|
| - for (; dec->mb_x_ < dec->mb_w_; dec->mb_x_++) {
|
| + for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) {
|
| MBContext context;
|
| SaveContext(dec, token_br, &context);
|
| -
|
| if (!VP8DecodeMB(dec, token_br)) {
|
| RestoreContext(&context, dec, token_br);
|
| // We shouldn't fail when MAX_MB data was available
|
| @@ -451,19 +458,18 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
|
| }
|
| return VP8_STATUS_SUSPENDED;
|
| }
|
| - // Reconstruct and emit samples.
|
| - VP8ReconstructBlock(dec);
|
| -
|
| // Release buffer only if there is only one partition
|
| if (dec->num_parts_ == 1) {
|
| idec->mem_.start_ = token_br->buf_ - idec->mem_.buf_;
|
| assert(idec->mem_.start_ <= idec->mem_.end_);
|
| }
|
| }
|
| + VP8InitScanline(dec); // Prepare for next scanline
|
| +
|
| + // Reconstruct, filter and emit the row.
|
| if (!VP8ProcessRow(dec, io)) {
|
| return IDecError(idec, VP8_STATUS_USER_ABORT);
|
| }
|
| - dec->mb_x_ = 0;
|
| }
|
| // Synchronize the thread and check for errors.
|
| if (!VP8ExitCritical(dec, io)) {
|
| @@ -475,7 +481,8 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
|
| return VP8_STATUS_OK;
|
| }
|
|
|
| -static int ErrorStatusLossless(WebPIDecoder* const idec, VP8StatusCode status) {
|
| +static VP8StatusCode ErrorStatusLossless(WebPIDecoder* const idec,
|
| + VP8StatusCode status) {
|
| if (status == VP8_STATUS_SUSPENDED || status == VP8_STATUS_NOT_ENOUGH_DATA) {
|
| return VP8_STATUS_SUSPENDED;
|
| }
|
| @@ -532,14 +539,14 @@ static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) {
|
| static VP8StatusCode IDecode(WebPIDecoder* idec) {
|
| VP8StatusCode status = VP8_STATUS_SUSPENDED;
|
|
|
| - if (idec->state_ == STATE_PRE_VP8) {
|
| + if (idec->state_ == STATE_WEBP_HEADER) {
|
| status = DecodeWebPHeaders(idec);
|
| } else {
|
| if (idec->dec_ == NULL) {
|
| return VP8_STATUS_SUSPENDED; // can't continue if we have no decoder.
|
| }
|
| }
|
| - if (idec->state_ == STATE_VP8_FRAME_HEADER) {
|
| + if (idec->state_ == STATE_VP8_HEADER) {
|
| status = DecodeVP8FrameHeader(idec);
|
| }
|
| if (idec->state_ == STATE_VP8_PARTS0) {
|
| @@ -566,7 +573,7 @@ WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
|
| return NULL;
|
| }
|
|
|
| - idec->state_ = STATE_PRE_VP8;
|
| + idec->state_ = STATE_WEBP_HEADER;
|
| idec->chunk_size_ = 0;
|
|
|
| InitMemBuffer(&idec->mem_);
|
| @@ -574,7 +581,8 @@ WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
|
| VP8InitIo(&idec->io_);
|
|
|
| WebPResetDecParams(&idec->params_);
|
| - idec->params_.output = output_buffer ? output_buffer : &idec->output_;
|
| + idec->params_.output = (output_buffer != NULL) ? output_buffer
|
| + : &idec->output_;
|
| WebPInitCustomIo(&idec->params_, &idec->io_); // Plug the I/O functions.
|
|
|
| return idec;
|
| @@ -608,11 +616,11 @@ void WebPIDelete(WebPIDecoder* idec) {
|
| if (!idec->is_lossless_) {
|
| if (idec->state_ == STATE_VP8_DATA) {
|
| // Synchronize the thread, clean-up and check for errors.
|
| - VP8ExitCritical(idec->dec_, &idec->io_);
|
| + VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_);
|
| }
|
| - VP8Delete(idec->dec_);
|
| + VP8Delete((VP8Decoder*)idec->dec_);
|
| } else {
|
| - VP8LDelete(idec->dec_);
|
| + VP8LDelete((VP8LDecoder*)idec->dec_);
|
| }
|
| }
|
| ClearMemBuffer(&idec->mem_);
|
| @@ -827,7 +835,7 @@ int WebPISetIOHooks(WebPIDecoder* const idec,
|
| VP8IoSetupHook setup,
|
| VP8IoTeardownHook teardown,
|
| void* user_data) {
|
| - if (idec == NULL || idec->state_ > STATE_PRE_VP8) {
|
| + if (idec == NULL || idec->state_ > STATE_WEBP_HEADER) {
|
| return 0;
|
| }
|
|
|
| @@ -839,6 +847,3 @@ int WebPISetIOHooks(WebPIDecoder* const idec,
|
| return 1;
|
| }
|
|
|
| -#if defined(__cplusplus) || defined(c_plusplus)
|
| -} // extern "C"
|
| -#endif
|
|
|