summaryrefslogtreecommitdiff
path: root/drivers/webp/dec/idec.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/webp/dec/idec.c')
-rw-r--r--drivers/webp/dec/idec.c168
1 files changed, 52 insertions, 116 deletions
diff --git a/drivers/webp/dec/idec.c b/drivers/webp/dec/idec.c
index 40d5ff6e0d..7df790ced8 100644
--- a/drivers/webp/dec/idec.c
+++ b/drivers/webp/dec/idec.c
@@ -1,10 +1,8 @@
// Copyright 2011 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/
// -----------------------------------------------------------------------------
//
// Incremental decoding
@@ -15,11 +13,14 @@
#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
@@ -28,13 +29,11 @@
//------------------------------------------------------------------------------
// Data structures for memory and states
-// 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.
+// Decoding states. State normally flows like HEADER->PARTS0->DATA->DONE.
// If there is any error the decoder goes into state ERROR.
typedef enum {
- 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_PRE_VP8, // All data before that of the first VP8 chunk.
+ STATE_VP8_FRAME_HEADER, // For VP8 Frame header (within VP8 chunk).
STATE_VP8_PARTS0,
STATE_VP8_DATA,
STATE_VP8L_HEADER,
@@ -98,23 +97,6 @@ static WEBP_INLINE size_t MemDataSize(const MemBuffer* mem) {
return (mem->end_ - mem->start_);
}
-// 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_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;
- }
- if (idec->is_lossless_) {
- 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_WEBP_HEADER.
- return (dec->alpha_data_ != NULL) && !dec->is_alpha_decoded_;
- }
-}
-
static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
MemBuffer* const mem = &idec->mem_;
const uint8_t* const new_base = mem->buf_ + mem->start_;
@@ -140,22 +122,6 @@ 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)) {
- 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));
@@ -167,12 +133,8 @@ static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
// size if required and also updates VP8BitReader's if new memory is allocated.
static int AppendToMemBuffer(WebPIDecoder* const idec,
const uint8_t* const data, size_t data_size) {
- VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
MemBuffer* const mem = &idec->mem_;
- const int need_compressed_alpha = NeedCompressedAlpha(idec);
- const uint8_t* const old_start = mem->buf_ + mem->start_;
- const uint8_t* const old_base =
- need_compressed_alpha ? dec->alpha_data_ : old_start;
+ const uint8_t* const old_base = mem->buf_ + mem->start_;
assert(mem->mode_ == MEM_MODE_APPEND);
if (data_size > MAX_CHUNK_PAYLOAD) {
// security safeguard: trying to allocate more than what the format
@@ -181,8 +143,7 @@ static int AppendToMemBuffer(WebPIDecoder* const idec,
}
if (mem->end_ + data_size > mem->buf_size_) { // Need some free memory
- const size_t new_mem_start = old_start - old_base;
- const size_t current_size = MemDataSize(mem) + new_mem_start;
+ const size_t current_size = MemDataSize(mem);
const uint64_t new_size = (uint64_t)current_size + data_size;
const uint64_t extra_size = (new_size + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1);
uint8_t* const new_buf =
@@ -192,7 +153,7 @@ static int AppendToMemBuffer(WebPIDecoder* const idec,
free(mem->buf_);
mem->buf_ = new_buf;
mem->buf_size_ = (size_t)extra_size;
- mem->start_ = new_mem_start;
+ mem->start_ = 0;
mem->end_ = current_size;
}
@@ -200,15 +161,14 @@ static int AppendToMemBuffer(WebPIDecoder* const idec,
mem->end_ += data_size;
assert(mem->end_ <= mem->buf_size_);
- DoRemap(idec, mem->buf_ + mem->start_ - old_start);
+ DoRemap(idec, mem->buf_ + mem->start_ - old_base);
return 1;
}
static int RemapMemBuffer(WebPIDecoder* const idec,
const uint8_t* const data, size_t data_size) {
MemBuffer* const mem = &idec->mem_;
- const uint8_t* const old_buf = mem->buf_;
- const uint8_t* const old_start = old_buf + mem->start_;
+ const uint8_t* const old_base = mem->buf_ + mem->start_;
assert(mem->mode_ == MEM_MODE_MAP);
if (data_size < mem->buf_size_) return 0; // can't remap to a shorter buffer!
@@ -216,7 +176,7 @@ static int RemapMemBuffer(WebPIDecoder* const idec,
mem->buf_ = (uint8_t*)data;
mem->end_ = mem->buf_size_ = data_size;
- DoRemap(idec, mem->buf_ + mem->start_ - old_start);
+ DoRemap(idec, mem->buf_ + mem->start_ - old_base);
return 1;
}
@@ -282,7 +242,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 != NULL) {
+ if (io->teardown) {
io->teardown(io);
}
}
@@ -325,9 +285,15 @@ 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_HEADER, headers.offset);
+ ChangeState(idec, STATE_VP8_FRAME_HEADER, headers.offset);
} else {
VP8LDecoder* const dec = VP8LNew();
if (dec == NULL) {
@@ -342,14 +308,13 @@ 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_, &width, &height)) {
+ if (!VP8GetInfo(data, curr_size, idec->chunk_size_, NULL, NULL)) {
return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
}
@@ -416,10 +381,7 @@ 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);
}
@@ -445,11 +407,16 @@ 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)];
- for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) {
+ if (dec->mb_x_ == 0) {
+ VP8InitScanline(dec);
+ }
+ 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
@@ -458,18 +425,20 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
}
return VP8_STATUS_SUSPENDED;
}
+ VP8ReconstructBlock(dec);
+ // Store data and save block's filtering params
+ VP8StoreBlock(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)) {
@@ -481,8 +450,7 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
return VP8_STATUS_OK;
}
-static VP8StatusCode ErrorStatusLossless(WebPIDecoder* const idec,
- VP8StatusCode status) {
+static int ErrorStatusLossless(WebPIDecoder* const idec, VP8StatusCode status) {
if (status == VP8_STATUS_SUSPENDED || status == VP8_STATUS_NOT_ENOUGH_DATA) {
return VP8_STATUS_SUSPENDED;
}
@@ -539,14 +507,14 @@ static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) {
static VP8StatusCode IDecode(WebPIDecoder* idec) {
VP8StatusCode status = VP8_STATUS_SUSPENDED;
- if (idec->state_ == STATE_WEBP_HEADER) {
+ if (idec->state_ == STATE_PRE_VP8) {
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_HEADER) {
+ if (idec->state_ == STATE_VP8_FRAME_HEADER) {
status = DecodeVP8FrameHeader(idec);
}
if (idec->state_ == STATE_VP8_PARTS0) {
@@ -573,7 +541,7 @@ WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
return NULL;
}
- idec->state_ = STATE_WEBP_HEADER;
+ idec->state_ = STATE_PRE_VP8;
idec->chunk_size_ = 0;
InitMemBuffer(&idec->mem_);
@@ -581,8 +549,7 @@ WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
VP8InitIo(&idec->io_);
WebPResetDecParams(&idec->params_);
- idec->params_.output = (output_buffer != NULL) ? output_buffer
- : &idec->output_;
+ idec->params_.output = output_buffer ? output_buffer : &idec->output_;
WebPInitCustomIo(&idec->params_, &idec->io_); // Plug the I/O functions.
return idec;
@@ -614,13 +581,9 @@ void WebPIDelete(WebPIDecoder* idec) {
if (idec == NULL) return;
if (idec->dec_ != NULL) {
if (!idec->is_lossless_) {
- if (idec->state_ == STATE_VP8_DATA) {
- // Synchronize the thread, clean-up and check for errors.
- VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_);
- }
- VP8Delete((VP8Decoder*)idec->dec_);
+ VP8Delete(idec->dec_);
} else {
- VP8LDelete((VP8LDecoder*)idec->dec_);
+ VP8LDelete(idec->dec_);
}
}
ClearMemBuffer(&idec->mem_);
@@ -633,22 +596,12 @@ void WebPIDelete(WebPIDecoder* idec) {
WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE mode, uint8_t* output_buffer,
size_t output_buffer_size, int output_stride) {
- const int is_external_memory = (output_buffer != NULL);
WebPIDecoder* idec;
-
if (mode >= MODE_YUV) return NULL;
- if (!is_external_memory) { // Overwrite parameters to sane values.
- output_buffer_size = 0;
- output_stride = 0;
- } else { // A buffer was passed. Validate the other params.
- if (output_stride == 0 || output_buffer_size == 0) {
- return NULL; // invalid parameter.
- }
- }
idec = WebPINewDecoder(NULL);
if (idec == NULL) return NULL;
idec->output_.colorspace = mode;
- idec->output_.is_external_memory = is_external_memory;
+ idec->output_.is_external_memory = 1;
idec->output_.u.RGBA.rgba = output_buffer;
idec->output_.u.RGBA.stride = output_stride;
idec->output_.u.RGBA.size = output_buffer_size;
@@ -659,30 +612,10 @@ WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride,
uint8_t* u, size_t u_size, int u_stride,
uint8_t* v, size_t v_size, int v_stride,
uint8_t* a, size_t a_size, int a_stride) {
- const int is_external_memory = (luma != NULL);
- WebPIDecoder* idec;
- WEBP_CSP_MODE colorspace;
-
- if (!is_external_memory) { // Overwrite parameters to sane values.
- luma_size = u_size = v_size = a_size = 0;
- luma_stride = u_stride = v_stride = a_stride = 0;
- u = v = a = NULL;
- colorspace = MODE_YUVA;
- } else { // A luma buffer was passed. Validate the other parameters.
- if (u == NULL || v == NULL) return NULL;
- if (luma_size == 0 || u_size == 0 || v_size == 0) return NULL;
- if (luma_stride == 0 || u_stride == 0 || v_stride == 0) return NULL;
- if (a != NULL) {
- if (a_size == 0 || a_stride == 0) return NULL;
- }
- colorspace = (a == NULL) ? MODE_YUV : MODE_YUVA;
- }
-
- idec = WebPINewDecoder(NULL);
+ WebPIDecoder* const idec = WebPINewDecoder(NULL);
if (idec == NULL) return NULL;
-
- idec->output_.colorspace = colorspace;
- idec->output_.is_external_memory = is_external_memory;
+ idec->output_.colorspace = (a == NULL) ? MODE_YUV : MODE_YUVA;
+ idec->output_.is_external_memory = 1;
idec->output_.u.YUVA.y = luma;
idec->output_.u.YUVA.y_stride = luma_stride;
idec->output_.u.YUVA.y_size = luma_size;
@@ -835,7 +768,7 @@ int WebPISetIOHooks(WebPIDecoder* const idec,
VP8IoSetupHook setup,
VP8IoTeardownHook teardown,
void* user_data) {
- if (idec == NULL || idec->state_ > STATE_WEBP_HEADER) {
+ if (idec == NULL || idec->state_ > STATE_PRE_VP8) {
return 0;
}
@@ -847,3 +780,6 @@ int WebPISetIOHooks(WebPIDecoder* const idec,
return 1;
}
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif