summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/libwebp/src/dec/idec.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/libwebp/src/dec/idec.c')
-rw-r--r--src/3rdparty/libwebp/src/dec/idec.c123
1 files changed, 68 insertions, 55 deletions
diff --git a/src/3rdparty/libwebp/src/dec/idec.c b/src/3rdparty/libwebp/src/dec/idec.c
index 40d5ff6..e003851 100644
--- a/src/3rdparty/libwebp/src/dec/idec.c
+++ b/src/3rdparty/libwebp/src/dec/idec.c
@@ -72,28 +72,20 @@ struct WebPIDecoder {
MemBuffer mem_; // input memory buffer.
WebPDecBuffer output_; // output buffer (when no external one is supplied)
size_t chunk_size_; // Compressed VP8/VP8L size extracted from Header.
+
+ int last_mb_y_; // last row reached for intra-mode decoding
};
// MB context to restore in case VP8DecodeMB() fails
typedef struct {
VP8MB left_;
VP8MB info_;
- uint8_t intra_t_[4];
- uint8_t intra_l_[4];
- VP8BitReader br_;
VP8BitReader token_br_;
} MBContext;
//------------------------------------------------------------------------------
// MemBuffer: incoming data handling
-static void RemapBitReader(VP8BitReader* const br, ptrdiff_t offset) {
- if (br->buf_ != NULL) {
- br->buf_ += offset;
- br->buf_end_ += offset;
- }
-}
-
static WEBP_INLINE size_t MemDataSize(const MemBuffer* mem) {
return (mem->end_ - mem->start_);
}
@@ -130,12 +122,12 @@ static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
if (offset != 0) {
int p;
for (p = 0; p <= last_part; ++p) {
- RemapBitReader(dec->parts_ + p, offset);
+ VP8RemapBitReader(dec->parts_ + p, offset);
}
// Remap partition #0 data pointer to new offset, but only in MAP
// mode (in APPEND mode, partition #0 is copied into a fixed memory).
if (mem->mode_ == MEM_MODE_MAP) {
- RemapBitReader(&dec->br_, offset);
+ VP8RemapBitReader(&dec->br_, offset);
}
}
assert(last_part >= 0);
@@ -189,7 +181,7 @@ static int AppendToMemBuffer(WebPIDecoder* const idec,
(uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf));
if (new_buf == NULL) return 0;
memcpy(new_buf, old_base, current_size);
- free(mem->buf_);
+ WebPSafeFree(mem->buf_);
mem->buf_ = new_buf;
mem->buf_size_ = (size_t)extra_size;
mem->start_ = new_mem_start;
@@ -231,8 +223,8 @@ static void InitMemBuffer(MemBuffer* const mem) {
static void ClearMemBuffer(MemBuffer* const mem) {
assert(mem);
if (mem->mode_ == MEM_MODE_APPEND) {
- free(mem->buf_);
- free((void*)mem->part0_buf_);
+ WebPSafeFree(mem->buf_);
+ WebPSafeFree((void*)mem->part0_buf_);
}
}
@@ -246,35 +238,36 @@ static int CheckMemBufferMode(MemBuffer* const mem, MemBufferMode expected) {
return 1;
}
+// To be called last.
+static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) {
+#if WEBP_DECODER_ABI_VERSION > 0x0203
+ const WebPDecoderOptions* const options = idec->params_.options;
+ WebPDecBuffer* const output = idec->params_.output;
+
+ idec->state_ = STATE_DONE;
+ if (options != NULL && options->flip) {
+ return WebPFlipBuffer(output);
+ }
+#endif
+ idec->state_ = STATE_DONE;
+ return VP8_STATUS_OK;
+}
+
//------------------------------------------------------------------------------
// Macroblock-decoding contexts
static void SaveContext(const VP8Decoder* dec, const VP8BitReader* token_br,
MBContext* const context) {
- const VP8BitReader* const br = &dec->br_;
- const VP8MB* const left = dec->mb_info_ - 1;
- const VP8MB* const info = dec->mb_info_ + dec->mb_x_;
-
- context->left_ = *left;
- context->info_ = *info;
- context->br_ = *br;
+ context->left_ = dec->mb_info_[-1];
+ context->info_ = dec->mb_info_[dec->mb_x_];
context->token_br_ = *token_br;
- memcpy(context->intra_t_, dec->intra_t_ + 4 * dec->mb_x_, 4);
- memcpy(context->intra_l_, dec->intra_l_, 4);
}
static void RestoreContext(const MBContext* context, VP8Decoder* const dec,
VP8BitReader* const token_br) {
- VP8BitReader* const br = &dec->br_;
- VP8MB* const left = dec->mb_info_ - 1;
- VP8MB* const info = dec->mb_info_ + dec->mb_x_;
-
- *left = context->left_;
- *info = context->info_;
- *br = context->br_;
+ dec->mb_info_[-1] = context->left_;
+ dec->mb_info_[dec->mb_x_] = context->info_;
*token_br = context->token_br_;
- memcpy(dec->intra_t_ + 4 * dec->mb_x_, context->intra_t_, 4);
- memcpy(dec->intra_l_, context->intra_l_, 4);
}
//------------------------------------------------------------------------------
@@ -310,6 +303,7 @@ static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) {
headers.data = data;
headers.data_size = curr_size;
+ headers.have_all_data = 0;
status = WebPParseHeaders(&headers);
if (status == VP8_STATUS_NOT_ENOUGH_DATA) {
return VP8_STATUS_SUSPENDED; // We haven't found a VP8 chunk yet.
@@ -363,30 +357,33 @@ static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) {
}
// Partition #0
-static int CopyParts0Data(WebPIDecoder* const idec) {
+static VP8StatusCode CopyParts0Data(WebPIDecoder* const idec) {
VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
VP8BitReader* const br = &dec->br_;
- const size_t psize = br->buf_end_ - br->buf_;
+ const size_t part_size = br->buf_end_ - br->buf_;
MemBuffer* const mem = &idec->mem_;
assert(!idec->is_lossless_);
assert(mem->part0_buf_ == NULL);
- assert(psize > 0);
- assert(psize <= mem->part0_size_); // Format limit: no need for runtime check
+ // the following is a format limitation, no need for runtime check:
+ assert(part_size <= mem->part0_size_);
+ if (part_size == 0) { // can't have zero-size partition #0
+ return VP8_STATUS_BITSTREAM_ERROR;
+ }
if (mem->mode_ == MEM_MODE_APPEND) {
// We copy and grab ownership of the partition #0 data.
- uint8_t* const part0_buf = (uint8_t*)malloc(psize);
+ uint8_t* const part0_buf = (uint8_t*)WebPSafeMalloc(1ULL, part_size);
if (part0_buf == NULL) {
- return 0;
+ return VP8_STATUS_OUT_OF_MEMORY;
}
- memcpy(part0_buf, br->buf_, psize);
+ memcpy(part0_buf, br->buf_, part_size);
mem->part0_buf_ = part0_buf;
br->buf_ = part0_buf;
- br->buf_end_ = part0_buf + psize;
+ br->buf_end_ = part0_buf + part_size;
} else {
// Else: just keep pointers to the partition #0's data in dec_->br_.
}
- mem->start_ += psize;
- return 1;
+ mem->start_ += part_size;
+ return VP8_STATUS_OK;
}
static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) {
@@ -420,8 +417,10 @@ static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) {
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);
+
+ dec->status_ = CopyParts0Data(idec);
+ if (dec->status_ != VP8_STATUS_OK) {
+ return IDecError(idec, dec->status_);
}
// Finish setting up the decoding parameters. Will call io->setup().
@@ -446,16 +445,26 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
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 (idec->last_mb_y_ != dec->mb_y_) {
+ if (!VP8ParseIntraModeRow(&dec->br_, dec)) {
+ // note: normally, error shouldn't occur since we already have the whole
+ // partition0 available here in DecodeRemaining(). Reaching EOF while
+ // reading intra modes really means a BITSTREAM_ERROR.
+ return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
+ }
+ idec->last_mb_y_ = dec->mb_y_;
+ }
for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) {
+ VP8BitReader* const token_br =
+ &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)];
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
if (dec->num_parts_ == 1 && MemDataSize(&idec->mem_) > MAX_MB_SIZE) {
return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
}
+ RestoreContext(&context, dec, token_br);
return VP8_STATUS_SUSPENDED;
}
// Release buffer only if there is only one partition
@@ -476,9 +485,7 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
return IDecError(idec, VP8_STATUS_USER_ABORT);
}
dec->ready_ = 0;
- idec->state_ = STATE_DONE;
-
- return VP8_STATUS_OK;
+ return FinishDecoding(idec);
}
static VP8StatusCode ErrorStatusLossless(WebPIDecoder* const idec,
@@ -527,12 +534,16 @@ static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) {
}
if (!VP8LDecodeImage(dec)) {
+ // The decoding is called after all the data-bytes are aggregated. Change
+ // the error to VP8_BITSTREAM_ERROR in case lossless decoder fails to decode
+ // all the pixels (VP8_STATUS_SUSPENDED).
+ if (dec->status_ == VP8_STATUS_SUSPENDED) {
+ dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ }
return ErrorStatusLossless(idec, dec->status_);
}
- idec->state_ = STATE_DONE;
-
- return VP8_STATUS_OK;
+ return FinishDecoding(idec);
}
// Main decoding loop
@@ -568,7 +579,7 @@ static VP8StatusCode IDecode(WebPIDecoder* idec) {
// Public functions
WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
- WebPIDecoder* idec = (WebPIDecoder*)calloc(1, sizeof(*idec));
+ WebPIDecoder* idec = (WebPIDecoder*)WebPSafeCalloc(1ULL, sizeof(*idec));
if (idec == NULL) {
return NULL;
}
@@ -576,6 +587,8 @@ WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
idec->state_ = STATE_WEBP_HEADER;
idec->chunk_size_ = 0;
+ idec->last_mb_y_ = -1;
+
InitMemBuffer(&idec->mem_);
WebPInitDecBuffer(&idec->output_);
VP8InitIo(&idec->io_);
@@ -625,7 +638,7 @@ void WebPIDelete(WebPIDecoder* idec) {
}
ClearMemBuffer(&idec->mem_);
WebPFreeDecBuffer(&idec->output_);
- free(idec);
+ WebPSafeFree(idec);
}
//------------------------------------------------------------------------------