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 |