summaryrefslogtreecommitdiffstats
path: root/third_party/libwebp
diff options
context:
space:
mode:
authorabarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-05 07:16:54 +0000
committerabarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-05 07:16:54 +0000
commita6e603e0d0e60c9ac7470871106e5c984fa25694 (patch)
treeb507ca7a1858ca0c37a40322f37a4a5d59137853 /third_party/libwebp
parentfe245ae465ec8fa8919d31545bb5ddae0b8bd79c (diff)
downloadchromium_src-a6e603e0d0e60c9ac7470871106e5c984fa25694.zip
chromium_src-a6e603e0d0e60c9ac7470871106e5c984fa25694.tar.gz
chromium_src-a6e603e0d0e60c9ac7470871106e5c984fa25694.tar.bz2
Update libwebp to libwebp-0.1.2.
Patch originally by Pascal Massimino: http://codereview.chromium.org/6760004/ Review URL: http://codereview.chromium.org/6793035 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@80421 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/libwebp')
-rw-r--r--third_party/libwebp/README.chromium12
-rw-r--r--third_party/libwebp/dec/bits.h2
-rw-r--r--third_party/libwebp/dec/dsp.c8
-rw-r--r--third_party/libwebp/dec/idec.c577
-rw-r--r--third_party/libwebp/dec/tree.c1
-rw-r--r--third_party/libwebp/dec/vp8.c40
-rw-r--r--third_party/libwebp/dec/vp8i.h9
-rw-r--r--third_party/libwebp/dec/webp.c129
-rw-r--r--third_party/libwebp/dec/webpi.h26
-rw-r--r--third_party/libwebp/dec/yuv.c2
-rw-r--r--third_party/libwebp/dec/yuv.h4
-rw-r--r--third_party/libwebp/enc/config.c2
-rw-r--r--third_party/libwebp/enc/dsp.c43
-rw-r--r--third_party/libwebp/enc/filter.c2
-rw-r--r--third_party/libwebp/enc/iterator.c2
-rw-r--r--third_party/libwebp/enc/picture.c4
-rw-r--r--third_party/libwebp/enc/quant.c55
-rw-r--r--third_party/libwebp/enc/vp8enci.h32
-rw-r--r--third_party/libwebp/enc/webpenc.c10
-rw-r--r--third_party/libwebp/libwebp.gyp3
-rw-r--r--third_party/libwebp/webp/decode.h102
-rw-r--r--third_party/libwebp/webp/decode_vp8.h18
-rw-r--r--third_party/libwebp/webp/encode.h6
23 files changed, 921 insertions, 168 deletions
diff --git a/third_party/libwebp/README.chromium b/third_party/libwebp/README.chromium
index 349ef7b..5e6b403 100644
--- a/third_party/libwebp/README.chromium
+++ b/third_party/libwebp/README.chromium
@@ -2,15 +2,15 @@ Name: libwebpdecode
Short Name: libwebp
URL: http://code.google.com/speed/webp
Version: unknown
-Revision: I943a335b92b5ee6c2980c2ba9d4092f0b79f9a6b
+Revision: 0.1.2
+Included In Release: Yes
Description:
-Here is a copy of libwebp-decode, from the repository:
- git://review.webmproject.org/libwebp.git
-This code was pulled from MASTER on March 13th 2011, with the most recent
-Change-Id: I68194cb510760dd82a2ae83359154bf622502991 "fix bigger-by-1 array"
+Here is a copy of libwebp-decode, from the upstream project:
+ http://code.google.com/p/webp/downloads/detail?name=libwebp-0.1.2.tar.gz
The project files do not include from the distribution:
examples/
-Changed the include path from webp/ to ../webp/ \ No newline at end of file
+Local changes:
+ * Removed from types.h the risky: #ifdef ANSI / #define inline /#endif
diff --git a/third_party/libwebp/dec/bits.h b/third_party/libwebp/dec/bits.h
index e0572e4..82e4c3a 100644
--- a/third_party/libwebp/dec/bits.h
+++ b/third_party/libwebp/dec/bits.h
@@ -13,7 +13,7 @@
#define WEBP_DEC_BITS_H_
#include <assert.h>
-#include "../webp/decode_vp8.h"
+#include "webp/decode_vp8.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
diff --git a/third_party/libwebp/dec/dsp.c b/third_party/libwebp/dec/dsp.c
index 2737cb4..efde49d 100644
--- a/third_party/libwebp/dec/dsp.c
+++ b/third_party/libwebp/dec/dsp.c
@@ -28,9 +28,11 @@ static int8_t sclip1[1020 + 1020 + 1]; // clips [-1020, 1020] to [-128, 127]
static int8_t sclip2[112 + 112 + 1]; // clips [-112, 112] to [-16, 15]
static uint8_t clip1[255 + 510 + 1]; // clips [-255,510] to [0,255]
-static int tables_ok = 0;
+// We declare this variable 'volatile' to prevent instruction reordering
+// and make sure it's set to true _last_ (so as to be thread-safe)
+static volatile int tables_ok = 0;
-void VP8DspInitTables() {
+void VP8DspInitTables(void) {
if (!tables_ok) {
int i;
for (i = -255; i <= 255; ++i) {
@@ -685,7 +687,7 @@ void (*VP8SimpleHFilter16i)(uint8_t*, int, int) = SimpleHFilter16i;
//-----------------------------------------------------------------------------
-void VP8DspInit() {
+void VP8DspInit(void) {
// later we'll plug some SSE2 variant here
}
diff --git a/third_party/libwebp/dec/idec.c b/third_party/libwebp/dec/idec.c
new file mode 100644
index 0000000..d49ceb0
--- /dev/null
+++ b/third_party/libwebp/dec/idec.c
@@ -0,0 +1,577 @@
+// Copyright 2011 Google Inc.
+//
+// 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
+//
+// Author: somnath@google.com (Somnath Banerjee)
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "webpi.h"
+#include "vp8i.h"
+#include "yuv.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define RIFF_HEADER_SIZE 20
+#define VP8_HEADER_SIZE 10
+#define WEBP_HEADER_SIZE (RIFF_HEADER_SIZE + VP8_HEADER_SIZE)
+#define CHUNK_SIZE 4096
+#define MAX_MB_SIZE 4096
+
+//------------------------------------------------------------------------------
+// Data structures for memory and states
+
+// Decoding states. State normally flows like HEADER->PARTS0->DATA->DONE.
+// If there is any error the decoder goes into state ERROR.
+typedef enum { STATE_HEADER = 0, STATE_PARTS0 = 1,
+ STATE_DATA = 2, STATE_DONE = 3,
+ STATE_ERROR = 4
+} DecState;
+
+// Operating state for the MemBuffer
+typedef enum { MEM_MODE_NONE = 0,
+ MEM_MODE_APPEND, MEM_MODE_MAP
+} MemBufferMode;
+
+// storage for partition #0 and partial data (in a rolling fashion)
+typedef struct {
+ MemBufferMode mode_; // Operation mode
+ uint32_t start_; // start location of the data to be decoded
+ uint32_t end_; // end location
+ size_t buf_size_; // size of the allocated buffer
+ uint8_t* buf_; // We don't own this buffer in case WebPIUpdate()
+
+ size_t part0_size_; // size of partition #0
+ const uint8_t* part0_buf_; // buffer to store partition #0
+} MemBuffer;
+
+struct WebPIDecoder {
+ DecState state_; // current decoding state
+ int w_, h_; // width and height
+ WebPDecParams params_; // Params to store output info
+ VP8Decoder* dec_;
+ VP8Io io_;
+
+ MemBuffer mem_; // memory buffer
+};
+
+// 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
+
+#define REMAP(PTR, OLD_BASE, NEW_BASE) (PTR) = (NEW_BASE) + ((PTR) - OLD_BASE)
+
+static inline size_t MemDataSize(const MemBuffer* mem) {
+ return (mem->end_ - mem->start_);
+}
+
+// Appends data to the end of MemBuffer->buf_. It expands the allocated memory
+// 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) {
+ MemBuffer* const mem = &idec->mem_;
+ VP8Decoder* const dec = idec->dec_;
+ const int last_part = dec->num_parts_ - 1;
+ assert(mem->mode_ == MEM_MODE_APPEND);
+
+ if (mem->end_ + data_size > mem->buf_size_) { // Need some free memory
+ int p;
+ uint8_t* new_buf = NULL;
+ const int num_chunks = (MemDataSize(mem) + data_size + CHUNK_SIZE - 1)
+ / CHUNK_SIZE;
+ const size_t new_size = num_chunks * CHUNK_SIZE;
+ const uint8_t* const base = mem->buf_ + mem->start_;
+
+ new_buf = (uint8_t*)malloc(new_size);
+ if (!new_buf) return 0;
+ memcpy(new_buf, base, MemDataSize(mem));
+
+ // adjust VP8BitReader pointers
+ for (p = 0; p <= last_part; ++p) {
+ if (dec->parts_[p].buf_) {
+ REMAP(dec->parts_[p].buf_, base, new_buf);
+ REMAP(dec->parts_[p].buf_end_, base, new_buf);
+ }
+ }
+
+ // adjust memory pointers
+ free(mem->buf_);
+ mem->buf_ = new_buf;
+ mem->buf_size_ = new_size;
+
+ mem->end_ = MemDataSize(mem);
+ mem->start_ = 0;
+ }
+
+ memcpy(mem->buf_ + mem->end_, data, data_size);
+ mem->end_ += data_size;
+ assert(mem->end_ <= mem->buf_size_);
+ dec->parts_[last_part].buf_end_ = mem->buf_ + mem->end_;
+
+ // note: setting up idec->io_ is only really needed at the beginning
+ // of the decoding, till partition #0 is complete.
+ idec->io_.data = mem->buf_ + mem->start_;
+ idec->io_.data_size = MemDataSize(mem);
+ return 1;
+}
+
+static int RemapMemBuffer(WebPIDecoder* const idec,
+ const uint8_t* const data, size_t data_size) {
+ int p;
+ MemBuffer* const mem = &idec->mem_;
+ VP8Decoder* const dec = idec->dec_;
+ const int last_part = dec->num_parts_ - 1;
+ const uint8_t* base = mem->buf_;
+
+ assert(mem->mode_ == MEM_MODE_MAP);
+ if (data_size < mem->buf_size_) {
+ return 0; // we cannot remap to a shorter buffer!
+ }
+
+ for (p = 0; p <= last_part; ++p) {
+ if (dec->parts_[p].buf_) {
+ REMAP(dec->parts_[p].buf_, base, data);
+ REMAP(dec->parts_[p].buf_end_, base, data);
+ }
+ }
+ dec->parts_[last_part].buf_end_ = data + data_size;
+
+ // Remap partition #0 data pointer to new offset.
+ if (dec->br_.buf_) {
+ REMAP(dec->br_.buf_, base, data);
+ REMAP(dec->br_.buf_end_, base, data);
+ }
+
+ mem->buf_ = (uint8_t*)data;
+ mem->end_ = mem->buf_size_ = data_size;
+
+ idec->io_.data = data;
+ idec->io_.data_size = data_size;
+ return 1;
+}
+
+static void InitMemBuffer(MemBuffer* const mem) {
+ mem->mode_ = MEM_MODE_NONE;
+ mem->buf_ = 0;
+ mem->buf_size_ = 0;
+ mem->part0_buf_ = 0;
+ mem->part0_size_ = 0;
+}
+
+static void ClearMemBuffer(MemBuffer* const mem) {
+ assert(mem);
+ if (mem->mode_ == MEM_MODE_APPEND) {
+ free(mem->buf_);
+ free((void*)mem->part0_buf_);
+ }
+}
+
+static int CheckMemBufferMode(MemBuffer* const mem, MemBufferMode expected) {
+ if (mem->mode_ == MEM_MODE_NONE) {
+ mem->mode_ = expected; // switch to the expected mode
+ } else if (mem->mode_ != expected) {
+ return 0; // we mixed the modes => error
+ }
+ assert(mem->mode_ == expected); // mode is ok
+ return 1;
+}
+
+#undef REMAP
+
+//------------------------------------------------------------------------------
+// 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->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_;
+ *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);
+}
+
+//------------------------------------------------------------------------------
+
+static VP8StatusCode IDecError(WebPIDecoder* idec, VP8StatusCode error) {
+ idec->state_ = STATE_ERROR;
+ return error;
+}
+
+// Header
+static VP8StatusCode DecodeHeader(WebPIDecoder* const idec) {
+ int width, height;
+ uint32_t curr_size, riff_header_size, bits;
+ WebPDecParams* params = &idec->params_;
+ const uint8_t* data = idec->mem_.buf_ + idec->mem_.start_;
+
+ if (MemDataSize(&idec->mem_) < WEBP_HEADER_SIZE) {
+ return VP8_STATUS_SUSPENDED;
+ }
+
+ if (!WebPInitDecParams(data, idec->mem_.end_, &width, &height, params)) {
+ return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
+ }
+
+ // Validate and Skip over RIFF header
+ curr_size = MemDataSize(&idec->mem_);
+ if (!WebPCheckRIFFHeader(&data, &curr_size)) {
+ return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
+ }
+ riff_header_size = idec->mem_.end_ - curr_size;
+ bits = data[0] | (data[1] << 8) | (data[2] << 16);
+
+ idec->mem_.part0_size_ = (bits >> 5) + VP8_HEADER_SIZE;
+ idec->mem_.start_ += riff_header_size;
+ assert(idec->mem_.start_ <= idec->mem_.end_);
+
+ idec->w_ = width;
+ idec->h_ = height;
+ idec->io_.data_size -= riff_header_size;
+ idec->io_.data = data;
+ idec->state_ = STATE_PARTS0;
+ return VP8_STATUS_OK;
+}
+
+// Partition #0
+static int CopyParts0Data(WebPIDecoder* idec) {
+ VP8BitReader* const br = &idec->dec_->br_;
+ const size_t psize = br->buf_end_ - br->buf_;
+ MemBuffer* const mem = &idec->mem_;
+ assert(!mem->part0_buf_);
+ assert(psize > 0);
+ assert(psize <= mem->part0_size_);
+ 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);
+ if (!part0_buf) {
+ return 0;
+ }
+ memcpy(part0_buf, br->buf_, psize);
+ mem->part0_buf_ = part0_buf;
+ mem->start_ += psize;
+ br->buf_ = part0_buf;
+ br->buf_end_ = part0_buf + psize;
+ } else {
+ // Else: just keep pointers to the partition #0's data in dec_->br_.
+ }
+ return 1;
+}
+
+static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) {
+ VP8Decoder* const dec = idec->dec_;
+ VP8Io* const io = &idec->io_;
+ const WebPDecParams* const params = &idec->params_;
+ const WEBP_CSP_MODE mode = params->mode;
+
+ // Wait till we have enough data for the whole partition #0
+ if (MemDataSize(&idec->mem_) < idec->mem_.part0_size_) {
+ return VP8_STATUS_SUSPENDED;
+ }
+
+ io->opaque = &idec->params_;
+ if (!VP8GetHeaders(dec, io)) {
+ const VP8StatusCode status = dec->status_;
+ if (status == VP8_STATUS_SUSPENDED ||
+ status == VP8_STATUS_NOT_ENOUGH_DATA) {
+ // treating NOT_ENOUGH_DATA as SUSPENDED state
+ return VP8_STATUS_SUSPENDED;
+ }
+ return IDecError(idec, status);
+ }
+
+ if (!WebPCheckDecParams(io, params)) {
+ return IDecError(idec, VP8_STATUS_INVALID_PARAM);
+ }
+
+ if (mode != MODE_YUV) {
+ VP8YUVInit();
+ }
+
+ // allocate memory and prepare everything.
+ if (!VP8InitFrame(dec, io)) {
+ return IDecError(idec, VP8_STATUS_OUT_OF_MEMORY);
+ }
+ if (io->setup && !io->setup(io)) {
+ return IDecError(idec, VP8_STATUS_USER_ABORT);
+ }
+
+ // disable filtering per user request (_after_ setup() is called)
+ if (io->bypass_filtering) dec->filter_type_ = 0;
+
+ if (!CopyParts0Data(idec)) {
+ return IDecError(idec, VP8_STATUS_OUT_OF_MEMORY);
+ }
+
+ idec->state_ = STATE_DATA;
+ return VP8_STATUS_OK;
+}
+
+// Remaining partitions
+static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
+ VP8BitReader* br;
+ VP8Decoder* const dec = idec->dec_;
+ VP8Io* const io = &idec->io_;
+
+ assert(dec->ready_);
+
+ br = &dec->br_;
+ 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) {
+ VP8MB* const left = dec->mb_info_ - 1;
+ left->nz_ = 0;
+ left->dc_nz_ = 0;
+ memset(dec->intra_l_, B_DC_PRED, sizeof(dec->intra_l_));
+ }
+
+ 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
+ if (dec->num_parts_ == 1 && MemDataSize(&idec->mem_) > MAX_MB_SIZE) {
+ return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
+ }
+ 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_);
+ }
+ }
+ if (!VP8FinishRow(dec, io)) {
+ return IDecError(idec, VP8_STATUS_USER_ABORT);
+ }
+ dec->mb_x_ = 0;
+ }
+
+ if (io->teardown) {
+ io->teardown(io);
+ }
+ dec->ready_ = 0;
+ idec->state_ = STATE_DONE;
+
+ return VP8_STATUS_OK;
+}
+
+ // Main decoding loop
+static VP8StatusCode IDecode(WebPIDecoder* idec) {
+ VP8StatusCode status = VP8_STATUS_SUSPENDED;
+ assert(idec->dec_);
+
+ if (idec->state_ == STATE_HEADER) {
+ status = DecodeHeader(idec);
+ }
+ if (idec->state_ == STATE_PARTS0) {
+ status = DecodePartition0(idec);
+ }
+ if (idec->state_ == STATE_DATA) {
+ return DecodeRemaining(idec);
+ }
+ return status;
+}
+
+//------------------------------------------------------------------------------
+// Public functions
+
+WebPIDecoder* WebPINew(WEBP_CSP_MODE mode) {
+ WebPIDecoder* idec = (WebPIDecoder*)calloc(1, sizeof(WebPIDecoder));
+ if (!idec) return NULL;
+
+ idec->dec_ = VP8New();
+ if (idec->dec_ == NULL) {
+ free(idec);
+ return NULL;
+ }
+
+ idec->state_ = STATE_HEADER;
+ idec->params_.mode = mode;
+
+ InitMemBuffer(&idec->mem_);
+ VP8InitIo(&idec->io_);
+ WebPInitCustomIo(&idec->io_);
+ return idec;
+}
+
+void WebPIDelete(WebPIDecoder* const idec) {
+ if (!idec) return;
+ VP8Delete(idec->dec_);
+ WebPClearDecParams(&idec->params_);
+ ClearMemBuffer(&idec->mem_);
+ free(idec);
+}
+
+//------------------------------------------------------------------------------
+
+WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE mode, uint8_t* output_buffer,
+ int output_buffer_size, int output_stride) {
+ WebPIDecoder* idec;
+ if (mode == MODE_YUV) return NULL;
+ idec = WebPINew(mode);
+ if (idec == NULL) return NULL;
+ idec->params_.output = output_buffer;
+ idec->params_.stride = output_stride;
+ idec->params_.output_size = output_buffer_size;
+ idec->params_.external_buffer = 1;
+ return idec;
+}
+
+WebPIDecoder* WebPINewYUV(uint8_t* luma, int luma_size, int luma_stride,
+ uint8_t* u, int u_size, int u_stride,
+ uint8_t* v, int v_size, int v_stride) {
+ WebPIDecoder* idec = WebPINew(MODE_YUV);
+ if (idec == NULL) return NULL;
+ idec->params_.output = luma;
+ idec->params_.stride = luma_stride;
+ idec->params_.output_size = luma_size;
+ idec->params_.u = u;
+ idec->params_.u_stride = u_stride;
+ idec->params_.output_u_size = u_size;
+ idec->params_.v = v;
+ idec->params_.v_stride = v_stride;
+ idec->params_.output_v_size = v_size;
+ idec->params_.external_buffer = 1;
+ return idec;
+}
+
+//------------------------------------------------------------------------------
+
+static VP8StatusCode IDecCheckStatus(const WebPIDecoder* const idec) {
+ assert(idec);
+ if (idec->dec_ == NULL) {
+ return VP8_STATUS_USER_ABORT;
+ }
+ if (idec->state_ == STATE_ERROR) {
+ return VP8_STATUS_BITSTREAM_ERROR;
+ }
+ if (idec->state_ == STATE_DONE) {
+ return VP8_STATUS_OK;
+ }
+ return VP8_STATUS_SUSPENDED;
+}
+
+VP8StatusCode WebPIAppend(WebPIDecoder* const idec, const uint8_t* data,
+ uint32_t data_size) {
+ VP8StatusCode status;
+ if (idec == NULL || data == NULL) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
+ status = IDecCheckStatus(idec);
+ if (status != VP8_STATUS_SUSPENDED) {
+ return status;
+ }
+ // Check mixed calls between RemapMemBuffer and AppendToMemBuffer.
+ if (!CheckMemBufferMode(&idec->mem_, MEM_MODE_APPEND)) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
+ // Append data to memory buffer
+ if (!AppendToMemBuffer(idec, data, data_size)) {
+ return VP8_STATUS_OUT_OF_MEMORY;
+ }
+ return IDecode(idec);
+}
+
+VP8StatusCode WebPIUpdate(WebPIDecoder* const idec, const uint8_t* data,
+ uint32_t data_size) {
+ VP8StatusCode status;
+ if (idec == NULL || data == NULL) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
+ status = IDecCheckStatus(idec);
+ if (status != VP8_STATUS_SUSPENDED) {
+ return status;
+ }
+ // Check mixed calls between RemapMemBuffer and AppendToMemBuffer.
+ if (!CheckMemBufferMode(&idec->mem_, MEM_MODE_MAP)) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
+ // Make the memory buffer point to the new buffer
+ if (!RemapMemBuffer(idec, data, data_size)) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
+ return IDecode(idec);
+}
+
+//------------------------------------------------------------------------------
+
+uint8_t* WebPIDecGetRGB(const WebPIDecoder* const idec, int *last_y,
+ int* width, int* height, int* stride) {
+ if (!idec || !idec->dec_ || idec->params_.mode != MODE_RGB ||
+ idec->state_ <= STATE_PARTS0) {
+ return NULL;
+ }
+
+ if (last_y) *last_y = idec->params_.last_y;
+ if (width) *width = idec->w_;
+ if (height) *height = idec->h_;
+ if (stride) *stride = idec->params_.stride;
+
+ return idec->params_.output;
+}
+
+uint8_t* WebPIDecGetYUV(const WebPIDecoder* const idec, int *last_y,
+ uint8_t** u, uint8_t** v, int* width, int* height,
+ int *stride, int* uv_stride) {
+ if (!idec || !idec->dec_ || idec->params_.mode != MODE_YUV ||
+ idec->state_ <= STATE_PARTS0) {
+ return NULL;
+ }
+
+ if (last_y) *last_y = idec->params_.last_y;
+ if (u) *u = idec->params_.u;
+ if (v) *v = idec->params_.v;
+ if (width) *width = idec->w_;
+ if (height) *height = idec->h_;
+ if (stride) *stride = idec->params_.stride;
+ if (uv_stride) *uv_stride = idec->params_.u_stride;
+
+ return idec->params_.output;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/third_party/libwebp/dec/tree.c b/third_party/libwebp/dec/tree.c
index 9c7074b..ed6caad 100644
--- a/third_party/libwebp/dec/tree.c
+++ b/third_party/libwebp/dec/tree.c
@@ -9,7 +9,6 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#include <stdio.h>
#include "vp8i.h"
#define USE_GENERIC_TREE
diff --git a/third_party/libwebp/dec/vp8.c b/third_party/libwebp/dec/vp8.c
index 43319b5..43a0c35 100644
--- a/third_party/libwebp/dec/vp8.c
+++ b/third_party/libwebp/dec/vp8.c
@@ -17,6 +17,12 @@ extern "C" {
#endif
//-----------------------------------------------------------------------------
+
+int WebPGetDecoderVersion(void) {
+ return (DEC_MAJ_VERSION << 16) | (DEC_MIN_VERSION << 8) | DEC_REV_VERSION;
+}
+
+//-----------------------------------------------------------------------------
// VP8Decoder
static void SetOk(VP8Decoder* const dec) {
@@ -33,7 +39,7 @@ int VP8InitIoInternal(VP8Io* const io, int version) {
return 1;
}
-VP8Decoder* VP8New() {
+VP8Decoder* VP8New(void) {
VP8Decoder* dec = (VP8Decoder*)calloc(1, sizeof(VP8Decoder));
if (dec) {
SetOk(dec);
@@ -199,6 +205,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
VP8FrameHeader* frm_hdr;
VP8PictureHeader* pic_hdr;
VP8BitReader* br;
+ VP8StatusCode status;
if (dec == NULL) {
return 0;
@@ -316,9 +323,9 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
"cannot parse filter header");
}
- if (ParsePartitions(dec, buf, buf_size) != VP8_STATUS_OK) {
- return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
- "cannot parse partitions");
+ status = ParsePartitions(dec, buf, buf_size);
+ if (status != VP8_STATUS_OK) {
+ return VP8SetError(dec, status, "cannot parse partitions");
}
// quantizer change
@@ -386,7 +393,8 @@ static const uint8_t kZigzag[16] = {
typedef const uint8_t (*ProbaArray)[NUM_CTX][NUM_PROBAS]; // for const-casting
-// Returns 1 if there's non-zero coeffs, 0 otherwise
+// Returns the position of the last non-zero coeff plus one
+// (and 0 if there's no coeff at all)
static int GetCoeffs(VP8BitReader* const br, ProbaArray prob,
int ctx, const uint16_t dq[2], int n, int16_t* out) {
const uint8_t* p = prob[kBands[n]][ctx];
@@ -433,14 +441,13 @@ static int GetCoeffs(VP8BitReader* const br, ProbaArray prob,
j = kZigzag[n - 1];
out[j] = VP8GetSigned(br, v) * dq[j > 0];
if (n == 16 || !VP8GetBit(br, p[0])) { // EOB
- return 1;
+ return n;
}
}
if (n == 16) {
- return 1;
+ return 16;
}
}
- return 0;
}
// Alias-safe way of converting 4bytes to 32bits.
@@ -483,8 +490,8 @@ static void ParseResiduals(VP8Decoder* const dec,
int16_t dc[16] = { 0 };
const int ctx = mb->dc_nz_ + left_mb->dc_nz_;
mb->dc_nz_ = left_mb->dc_nz_ =
- GetCoeffs(token_br, (ProbaArray)dec->proba_.coeffs_[1],
- ctx, q->y2_mat_, 0, dc);
+ (GetCoeffs(token_br, (ProbaArray)dec->proba_.coeffs_[1],
+ ctx, q->y2_mat_, 0, dc) > 0);
first = 1;
ac_prob = (ProbaArray)dec->proba_.coeffs_[0];
VP8TransformWHT(dc, dst);
@@ -499,10 +506,11 @@ static void ParseResiduals(VP8Decoder* const dec,
int l = lnz.i8[y];
for (x = 0; x < 4; ++x) {
const int ctx = l + tnz.i8[x];
- l = GetCoeffs(token_br, ac_prob, ctx,
- q->y1_mat_, first, dst);
+ const int nz = GetCoeffs(token_br, ac_prob, ctx,
+ q->y1_mat_, first, dst);
+ tnz.i8[x] = l = (nz > 0);
nz_dc.i8[x] = (dst[0] != 0);
- nz_ac.i8[x] = tnz.i8[x] = l;
+ nz_ac.i8[x] = (nz > 1);
dst += 16;
}
lnz.i8[y] = l;
@@ -519,10 +527,12 @@ static void ParseResiduals(VP8Decoder* const dec,
int l = lnz.i8[ch + y];
for (x = 0; x < 2; ++x) {
const int ctx = l + tnz.i8[ch + x];
- l = GetCoeffs(token_br, (ProbaArray)dec->proba_.coeffs_[2],
+ const int nz =
+ GetCoeffs(token_br, (ProbaArray)dec->proba_.coeffs_[2],
ctx, q->uv_mat_, 0, dst);
+ tnz.i8[ch + x] = l = (nz > 0);
nz_dc.i8[y * 2 + x] = (dst[0] != 0);
- nz_ac.i8[y * 2 + x] = tnz.i8[ch + x] = l;
+ nz_ac.i8[y * 2 + x] = (nz > 1);
dst += 16;
}
lnz.i8[ch + y] = l;
diff --git a/third_party/libwebp/dec/vp8i.h b/third_party/libwebp/dec/vp8i.h
index 9cfee04..b2ad9a3 100644
--- a/third_party/libwebp/dec/vp8i.h
+++ b/third_party/libwebp/dec/vp8i.h
@@ -22,6 +22,11 @@ extern "C" {
//-----------------------------------------------------------------------------
// Various defines and enums
+// version numbers
+#define DEC_MAJ_VERSION 0
+#define DEC_MIN_VERSION 1
+#define DEC_REV_VERSION 2
+
#define ONLY_KEYFRAME_CODE // to remove any code related to P-Frames
// intra prediction modes
@@ -284,8 +289,8 @@ extern VP8PredFunc VP8PredLuma16[NUM_B_DC_MODES];
extern VP8PredFunc VP8PredChroma8[NUM_B_DC_MODES];
extern VP8PredFunc VP8PredLuma4[NUM_BMODES];
-void VP8DspInit(); // must be called before anything using the above
-void VP8DspInitTables(); // needs to be called no matter what.
+void VP8DspInit(void); // must be called before anything using the above
+void VP8DspInitTables(void); // needs to be called no matter what.
// simple filter (only for luma)
typedef void (*VP8SimpleFilterFunc)(uint8_t* p, int stride, int thresh);
diff --git a/third_party/libwebp/dec/webp.c b/third_party/libwebp/dec/webp.c
index 823eafe641..3bf6f55 100644
--- a/third_party/libwebp/dec/webp.c
+++ b/third_party/libwebp/dec/webp.c
@@ -186,6 +186,7 @@ static int CustomPut(const VP8Io* io) {
return 0;
}
+ p->last_y = io->mb_y + io->mb_h; // a priori guess
if (p->mode == MODE_YUV) {
uint8_t* const y_dst = p->output + io->mb_y * p->stride;
uint8_t* const u_dst = p->u + (io->mb_y >> 1) * p->u_stride;
@@ -237,6 +238,9 @@ static int CustomPut(const VP8Io* io) {
memcpy(p->top_y, cur_y, w * sizeof(*p->top_y));
memcpy(p->top_u, cur_u, uv_w * sizeof(*p->top_u));
memcpy(p->top_v, cur_v, uv_w * sizeof(*p->top_v));
+ // The fancy upscaler leaves a row unfinished behind
+ // (except for the very last row)
+ p->last_y -= 1;
} else {
// Process the very last row of even-sized picture
if (!(y_end & 1)) {
@@ -315,12 +319,7 @@ void WebPInitCustomIo(VP8Io* const io) {
int WebPInitDecParams(const uint8_t* data, uint32_t data_size, int* width,
int* height, WebPDecParams* const params) {
- int w, h, stride;
- int uv_size = 0;
- int uv_stride = 0;
- int size;
- uint8_t* output;
- WEBP_CSP_MODE mode = params->mode;
+ int w, h;
if (!WebPGetInfo(data, data_size, &w, &h)) {
return 0;
@@ -328,38 +327,49 @@ int WebPInitDecParams(const uint8_t* data, uint32_t data_size, int* width,
if (width) *width = w;
if (height) *height = h;
- // initialize output buffer, now that dimensions are known.
- stride = (mode == MODE_RGB || mode == MODE_BGR) ? 3 * w
- : (mode == MODE_RGBA || mode == MODE_BGRA) ? 4 * w
- : w;
- size = stride * h;
-
- if (mode == MODE_YUV) {
- uv_stride = (w + 1) / 2;
- uv_size = uv_stride * ((h + 1) / 2);
- }
+ if (!params->external_buffer) {
+ int stride;
+ int uv_stride = 0;
+ int size;
+ int uv_size = 0;
+ uint8_t* output;
+ WEBP_CSP_MODE mode = params->mode;
+
+ // initialize output buffer, now that dimensions are known.
+ stride = (mode == MODE_RGB || mode == MODE_BGR) ? 3 * w
+ : (mode == MODE_RGBA || mode == MODE_BGRA) ? 4 * w
+ : w;
+ size = stride * h;
+
+ if (mode == MODE_YUV) {
+ uv_stride = (w + 1) / 2;
+ uv_size = uv_stride * ((h + 1) / 2);
+ }
- output = (uint8_t*)malloc(size + 2 * uv_size);
- if (!output) {
- return 0;
- }
+ output = (uint8_t*)malloc(size + 2 * uv_size);
+ if (!output) {
+ return 0;
+ }
- params->output = output;
- params->stride = stride;
- if (mode == MODE_YUV) {
- params->u = output + size;
- params->u_stride = uv_stride;
- params->v = output + size + uv_size;
- params->v_stride = uv_stride;
+ params->output = output;
+ params->stride = stride;
+ params->output_size = size;
+ if (mode == MODE_YUV) {
+ params->u = output + size;
+ params->u_stride = uv_stride;
+ params->output_u_size = uv_size;
+ params->v = output + size + uv_size;
+ params->v_stride = uv_stride;
+ params->output_v_size = uv_size;
+ }
}
return 1;
}
-int WebPCheckDecParams(const VP8Io* io, const WebPDecParams* params,
- int output_size, int output_u_size, int output_v_size) {
+int WebPCheckDecParams(const VP8Io* io, const WebPDecParams* params) {
int ok = 1;
WEBP_CSP_MODE mode = params->mode;
- ok &= (params->stride * io->height <= output_size);
+ ok &= (params->stride * io->height <= params->output_size);
if (mode == MODE_RGB || mode == MODE_BGR) {
ok &= (params->stride >= io->width * 3);
} else if (mode == MODE_RGBA || mode == MODE_BGRA) {
@@ -371,13 +381,16 @@ int WebPCheckDecParams(const VP8Io* io, const WebPDecParams* params,
ok &= (params->stride >= io->width);
ok &= (params->u_stride >= (io->width + 1) / 2) &&
(params->v_stride >= (io->width + 1) / 2);
- ok &= (u_size <= output_u_size && v_size <= output_v_size);
+ ok &= (u_size <= params->output_u_size &&
+ v_size <= params->output_v_size);
}
return ok;
}
void WebPClearDecParams(WebPDecParams* params) {
- free(params->output);
+ if (!params->external_buffer) {
+ free(params->output);
+ }
memset(params, 0, sizeof(*params));
}
@@ -386,8 +399,7 @@ void WebPClearDecParams(WebPDecParams* params) {
static uint8_t* DecodeInto(WEBP_CSP_MODE mode,
const uint8_t* data, uint32_t data_size,
- WebPDecParams* params, int output_size,
- int output_u_size, int output_v_size) {
+ WebPDecParams* params) {
VP8Decoder* dec = VP8New();
VP8Io io;
int ok = 1;
@@ -410,8 +422,7 @@ static uint8_t* DecodeInto(WEBP_CSP_MODE mode,
}
// check output buffers
- ok = WebPCheckDecParams(&io, params, output_size,
- output_u_size, output_v_size);
+ ok = WebPCheckDecParams(&io, params);
if (!ok) {
VP8Delete(dec);
return NULL;
@@ -437,7 +448,10 @@ uint8_t* WebPDecodeRGBInto(const uint8_t* data, uint32_t data_size,
params.output = output;
params.stride = output_stride;
- return DecodeInto(MODE_RGB, data, data_size, &params, output_size, 0, 0);
+ params.output_size = output_size;
+ params.output_u_size = 0;
+ params.output_v_size = 0;
+ return DecodeInto(MODE_RGB, data, data_size, &params);
}
uint8_t* WebPDecodeRGBAInto(const uint8_t* data, uint32_t data_size,
@@ -451,7 +465,10 @@ uint8_t* WebPDecodeRGBAInto(const uint8_t* data, uint32_t data_size,
params.output = output;
params.stride = output_stride;
- return DecodeInto(MODE_RGBA, data, data_size, &params, output_size, 0, 0);
+ params.output_size = output_size;
+ params.output_u_size = 0;
+ params.output_v_size = 0;
+ return DecodeInto(MODE_RGBA, data, data_size, &params);
}
uint8_t* WebPDecodeBGRInto(const uint8_t* data, uint32_t data_size,
@@ -465,7 +482,10 @@ uint8_t* WebPDecodeBGRInto(const uint8_t* data, uint32_t data_size,
params.output = output;
params.stride = output_stride;
- return DecodeInto(MODE_BGR, data, data_size, &params, output_size, 0, 0);
+ params.output_size = output_size;
+ params.output_u_size = 0;
+ params.output_v_size = 0;
+ return DecodeInto(MODE_BGR, data, data_size, &params);
}
uint8_t* WebPDecodeBGRAInto(const uint8_t* data, uint32_t data_size,
@@ -479,7 +499,10 @@ uint8_t* WebPDecodeBGRAInto(const uint8_t* data, uint32_t data_size,
params.output = output;
params.stride = output_stride;
- return DecodeInto(MODE_BGRA, data, data_size, &params, output_size, 0, 0);
+ params.output_size = output_size;
+ params.output_u_size = 0;
+ params.output_v_size = 0;
+ return DecodeInto(MODE_BGRA, data, data_size, &params);
}
uint8_t* WebPDecodeYUVInto(const uint8_t* data, uint32_t data_size,
@@ -494,12 +517,14 @@ uint8_t* WebPDecodeYUVInto(const uint8_t* data, uint32_t data_size,
params.output = luma;
params.stride = luma_stride;
+ params.output_size = luma_size;
params.u = u;
params.u_stride = u_stride;
+ params.output_u_size = u_size;
params.v = v;
params.v_stride = v_stride;
- return DecodeInto(MODE_YUV, data, data_size, &params,
- luma_size, u_size, v_size);
+ params.output_v_size = v_size;
+ return DecodeInto(MODE_YUV, data, data_size, &params);
}
//-----------------------------------------------------------------------------
@@ -507,22 +532,26 @@ uint8_t* WebPDecodeYUVInto(const uint8_t* data, uint32_t data_size,
static uint8_t* Decode(WEBP_CSP_MODE mode, const uint8_t* data,
uint32_t data_size, int* width, int* height,
WebPDecParams* params_out) {
- int size = 0;
- int uv_size = 0;
- WebPDecParams params = { 0 };
+ uint8_t* output;
+ WebPDecParams params;
+ memset(&params, 0, sizeof(params));
params.mode = mode;
if (!WebPInitDecParams(data, data_size, width, height, &params)) {
return NULL;
}
- size = params.stride * (*height);
- uv_size = params.u_stride * ((*height + 1) / 2);
- if (!DecodeInto(mode, data, data_size, &params, size, uv_size, uv_size)) {
+ params.output_size = params.stride * (*height);
+ params.output_u_size = params.output_v_size =
+ params.u_stride * ((*height + 1) / 2);
+ output = DecodeInto(mode, data, data_size, &params);
+ if (!output) {
WebPClearDecParams(&params);
}
- if (params_out) *params_out = params;
- return params.output;
+ if (params_out) {
+ *params_out = params;
+ }
+ return output;
}
uint8_t* WebPDecodeRGB(const uint8_t* data, uint32_t data_size,
diff --git a/third_party/libwebp/dec/webpi.h b/third_party/libwebp/dec/webpi.h
index 7bbe4cf..cf5bc0e 100644
--- a/third_party/libwebp/dec/webpi.h
+++ b/third_party/libwebp/dec/webpi.h
@@ -16,21 +16,22 @@
extern "C" {
#endif
-#include "../webp/decode_vp8.h"
+#include "webp/decode_vp8.h"
-typedef enum { MODE_RGB = 0, MODE_RGBA = 1,
- MODE_BGR = 2, MODE_BGRA = 3,
- MODE_YUV = 4 } WEBP_CSP_MODE;
-
- // Decoding output parameters.
+// Decoding output parameters.
typedef struct {
uint8_t* output; // rgb(a) or luma
- uint8_t *u, *v;
- uint8_t *top_y, *top_u, *top_v;
+ uint8_t *u, *v; // chroma u/v
+ uint8_t *top_y, *top_u, *top_v; // cache for the fancy upscaler
int stride; // rgb(a) stride or luma stride
- int u_stride;
- int v_stride;
- WEBP_CSP_MODE mode;
+ int u_stride; // chroma-u stride
+ int v_stride; // chroma-v stride
+ WEBP_CSP_MODE mode; // rgb(a) or yuv
+ int last_y; // coordinate of the line that was last output
+ int output_size; // size of 'output' buffer
+ int output_u_size; // size of 'u' buffer
+ int output_v_size; // size of 'v' buffer
+ int external_buffer; // If true, the output buffers are externally owned
} WebPDecParams;
// If a RIFF container is detected, validate it and skip over it. Returns
@@ -49,8 +50,7 @@ int WebPInitDecParams(const uint8_t* data, uint32_t data_size, int* width,
// Verifies various size configurations (e.g stride >= width, specified
// output size <= stride * height etc.). Returns 0 if checks fail.
-int WebPCheckDecParams(const VP8Io* io, const WebPDecParams* params,
- int output_size, int output_u_size, int output_v_size);
+int WebPCheckDecParams(const VP8Io* io, const WebPDecParams* params);
// Deallocate memory allocated by WebPInitDecParams() and reset the
// WebPDecParams object.
diff --git a/third_party/libwebp/dec/yuv.c b/third_party/libwebp/dec/yuv.c
index 30f59c1..ac448ee 100644
--- a/third_party/libwebp/dec/yuv.c
+++ b/third_party/libwebp/dec/yuv.c
@@ -23,7 +23,7 @@ uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
static int done = 0;
-void VP8YUVInit() {
+void VP8YUVInit(void) {
int i;
if (done) {
return;
diff --git a/third_party/libwebp/dec/yuv.h b/third_party/libwebp/dec/yuv.h
index db31453..50e63f9 100644
--- a/third_party/libwebp/dec/yuv.h
+++ b/third_party/libwebp/dec/yuv.h
@@ -12,7 +12,7 @@
#ifndef WEBP_DEC_YUV_H_
#define WEBP_DEC_YUV_H_
-#include "../webp/decode_vp8.h"
+#include "webp/decode_vp8.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
@@ -57,7 +57,7 @@ inline static void VP8YuvToBgra(int y, int u, int v, uint8_t* const bgra) {
}
// Must be called before everything, to initialize the tables.
-void VP8YUVInit();
+void VP8YUVInit(void);
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
diff --git a/third_party/libwebp/enc/config.c b/third_party/libwebp/enc/config.c
index e79ba08..86ef5ce2 100644
--- a/third_party/libwebp/enc/config.c
+++ b/third_party/libwebp/enc/config.c
@@ -10,7 +10,7 @@
// Author: Skal (pascal.massimino@gmail.com)
#include <assert.h>
-#include "../webp/encode.h"
+#include "webp/encode.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
diff --git a/third_party/libwebp/enc/dsp.c b/third_party/libwebp/enc/dsp.c
index 1365a23..45f977c 100644
--- a/third_party/libwebp/enc/dsp.c
+++ b/third_party/libwebp/enc/dsp.c
@@ -21,9 +21,11 @@ extern "C" {
static uint8_t clip1[255 + 510 + 1]; // clips [-255,510] to [0,255]
-static int tables_ok = 0;
+// We declare this variable 'volatile' to prevent instruction reordering
+// and make sure it's set to true _last_ (so as to be thread-safe)
+static volatile int tables_ok = 0;
-static void InitTables() {
+static void InitTables(void) {
if (!tables_ok) {
int i;
for (i = -255; i <= 255 + 255; ++i) {
@@ -79,7 +81,7 @@ static void ITransform(const uint8_t* ref, const int16_t* in, uint8_t* dst) {
}
}
-void FTransform(const uint8_t* src, const uint8_t* ref, int16_t* out) {
+static void FTransform(const uint8_t* src, const uint8_t* ref, int16_t* out) {
int i;
int tmp[16];
for (i = 0; i < 4; ++i, src += BPS, ref += BPS) {
@@ -582,6 +584,38 @@ VP8WMetric VP8TDisto4x4 = Disto4x4;
VP8WMetric VP8TDisto16x16 = Disto16x16;
//-----------------------------------------------------------------------------
+// Quantization
+//
+
+// Simple quantization
+static int QuantizeBlock(int16_t in[16], int16_t out[16],
+ int n, const VP8Matrix* const mtx) {
+ int last = -1;
+ for (; n < 16; ++n) {
+ const int j = VP8Zigzag[n];
+ const int sign = (in[j] < 0);
+ int coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j];
+ if (coeff > 2047) coeff = 2047;
+ if (coeff > mtx->zthresh_[j]) {
+ const int Q = mtx->q_[j];
+ const int iQ = mtx->iq_[j];
+ const int B = mtx->bias_[j];
+ out[n] = QUANTDIV(coeff, iQ, B);
+ if (sign) out[n] = -out[n];
+ in[j] = out[n] * Q;
+ if (out[n]) last = n;
+ } else {
+ out[n] = 0;
+ in[j] = 0;
+ }
+ }
+ return (last >= 0);
+}
+
+// default C implementation
+VP8QuantizeBlock VP8EncQuantizeBlock = QuantizeBlock;
+
+//-----------------------------------------------------------------------------
// Block copy
static inline void Copy(const uint8_t* src, uint8_t* dst, int size) {
@@ -604,9 +638,8 @@ VP8BlockCopy VP8Copy16x16 = Copy16x16;
//-----------------------------------------------------------------------------
-void VP8EncDspInit() {
+void VP8EncDspInit(void) {
InitTables();
- // later we'll plug some SSE2 variant here
}
#if defined(__cplusplus) || defined(c_plusplus)
diff --git a/third_party/libwebp/enc/filter.c b/third_party/libwebp/enc/filter.c
index 5a243b1..a0a42b0 100644
--- a/third_party/libwebp/enc/filter.c
+++ b/third_party/libwebp/enc/filter.c
@@ -25,7 +25,7 @@ static uint8_t clip1[255 + 510 + 1]; // clips [-255,510] to [0,255]
static int tables_ok = 0;
-static void InitTables() {
+static void InitTables(void) {
if (!tables_ok) {
int i;
for (i = -255; i <= 255; ++i) {
diff --git a/third_party/libwebp/enc/iterator.c b/third_party/libwebp/enc/iterator.c
index 7cd9f06..991644d 100644
--- a/third_party/libwebp/enc/iterator.c
+++ b/third_party/libwebp/enc/iterator.c
@@ -270,7 +270,7 @@ int VP8IteratorNext(VP8EncIterator* const it,
//-----------------------------------------------------------------------------
// Helper function to set mode properties
-void VP8SetIntra16Mode(const VP8EncIterator* it, int mode) {
+void VP8SetIntra16Mode(const VP8EncIterator* const it, int mode) {
int y;
uint8_t* preds = it->preds_;
for (y = 0; y < 4; ++y) {
diff --git a/third_party/libwebp/enc/picture.c b/third_party/libwebp/enc/picture.c
index 5b8d98b..6c12ea4 100644
--- a/third_party/libwebp/enc/picture.c
+++ b/third_party/libwebp/enc/picture.c
@@ -38,7 +38,7 @@ int WebPPictureAlloc(WebPPicture* const picture) {
picture->y_stride = width;
picture->uv_stride = uv_width;
WebPPictureFree(picture); // erase previous buffer
- picture->y = (uint8_t*)malloc(total_size);
+ picture->y = (uint8_t*)malloc((size_t)total_size);
if (picture->y == NULL) return 0;
picture->u = picture->y + y_size;
picture->v = picture->u + uv_size;
@@ -163,7 +163,7 @@ enum { YUV_FRAC = 16 };
static inline int clip_uv(int v) {
v = (v + (257 << (YUV_FRAC + 2 - 1))) >> (YUV_FRAC + 2);
- return ((v & ~0xff) == 0) ? v : (v < 0) ? 0u : 255u;
+ return ((v & ~0xff) == 0) ? v : (v < 0) ? 0 : 255;
}
static inline int rgb_to_y(int r, int g, int b) {
diff --git a/third_party/libwebp/enc/quant.c b/third_party/libwebp/enc/quant.c
index f3b99a0..e439919 100644
--- a/third_party/libwebp/enc/quant.c
+++ b/third_party/libwebp/enc/quant.c
@@ -39,7 +39,7 @@ static inline int clip(int v, int m, int M) {
return v < m ? m : v > M ? M : v;
}
-static const uint8_t kZigzag[16] = {
+const uint8_t VP8Zigzag[16] = {
0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15
};
@@ -100,8 +100,6 @@ static const uint16_t kAcTable2[128] = {
385, 393, 401, 409, 416, 424, 432, 440
};
-#define QFIX 17
-#define BIAS(b) ((b) << (QFIX - 8))
static const uint16_t kCoeffThresh[16] = {
0, 10, 20, 30,
10, 20, 30, 30,
@@ -145,7 +143,7 @@ static int ExpandMatrix(VP8Matrix* const m, int type) {
m->q_[i] = m->q_[1];
}
for (i = 0; i < 16; ++i) {
- const int j = kZigzag[i];
+ const int j = VP8Zigzag[i];
const int bias = kBiasMatrices[type][j];
m->iq_[j] = (1 << QFIX) / m->q_[j];
m->bias_[j] = BIAS(bias);
@@ -387,38 +385,7 @@ static void AddScore(VP8ModeScore* const dst, const VP8ModeScore* const src) {
}
//-----------------------------------------------------------------------------
-// Performs simple and trellis-optimized quantization.
-
-// Fun fact: this is the _only_ line where we're actually being lossy and
-// discarding bits.
-static int DIV(int n, int iQ, int B) {
- return (n * iQ + B) >> QFIX;
-}
-
-// Simple quantization
-static int QuantizeBlock(int16_t in[16], int16_t out[16],
- int n, const VP8Matrix* const mtx) {
- int last = -1;
- for (; n < 16; ++n) {
- const int j = kZigzag[n];
- const int sign = (in[j] < 0);
- int coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j];
- if (coeff > 2047) coeff = 2047;
- if (coeff > mtx->zthresh_[j]) {
- const int Q = mtx->q_[j];
- const int iQ = mtx->iq_[j];
- const int B = mtx->bias_[j];
- out[n] = DIV(coeff, iQ, B);
- if (sign) out[n] = -out[n];
- in[j] = out[n] * Q;
- if (out[n]) last = n;
- } else {
- out[n] = 0;
- in[j] = 0;
- }
- }
- return (last >= 0);
-}
+// Performs trellis-optimized quantization.
// Trellis
@@ -473,7 +440,7 @@ static int TrellisQuantizeBlock(const VP8EncIterator* const it,
// compute maximal distortion.
max_error = 0;
for (n = first; n < 16; ++n) {
- const int j = kZigzag[n];
+ const int j = VP8Zigzag[n];
const int err = in[j] * in[j];
max_error += kWeightTrellis[j] * err;
if (err > thresh) last = n;
@@ -497,7 +464,7 @@ static int TrellisQuantizeBlock(const VP8EncIterator* const it,
// traverse trellis.
for (n = first; n <= last; ++n) {
- const int j = kZigzag[n];
+ const int j = VP8Zigzag[n];
const int Q = mtx->q_[j];
const int iQ = mtx->iq_[j];
const int B = BIAS(0x00); // neutral bias
@@ -508,7 +475,7 @@ static int TrellisQuantizeBlock(const VP8EncIterator* const it,
int level0;
if (coeff0 > 2047) coeff0 = 2047;
- level0 = DIV(coeff0, iQ, B);
+ level0 = QUANTDIV(coeff0, iQ, B);
// test all alternate level values around level0.
for (m = -MIN_DELTA; m <= MAX_DELTA; ++m) {
Node* const cur = &NODE(n, m);
@@ -593,7 +560,7 @@ static int TrellisQuantizeBlock(const VP8EncIterator* const it,
for (; n >= first; --n) {
const Node* const node = &NODE(n, best_node);
- const int j = kZigzag[n];
+ const int j = VP8Zigzag[n];
out[n] = node->sign ? -node->level : node->level;
nz |= (node->level != 0);
in[j] = out[n] * mtx->q_[j];
@@ -625,7 +592,7 @@ static int ReconstructIntra16(VP8EncIterator* const it,
VP8FTransform(src + VP8Scan[n], ref + VP8Scan[n], tmp[n]);
}
VP8FTransformWHT(tmp[0], dc_tmp);
- nz |= QuantizeBlock(dc_tmp, rd->y_dc_levels, 0, &dqm->y2_) << 24;
+ nz |= VP8EncQuantizeBlock(dc_tmp, rd->y_dc_levels, 0, &dqm->y2_) << 24;
if (DO_TRELLIS_I16 && it->do_trellis_) {
int x, y;
@@ -642,7 +609,7 @@ static int ReconstructIntra16(VP8EncIterator* const it,
}
} else {
for (n = 0; n < 16; ++n) {
- nz |= QuantizeBlock(tmp[n], rd->y_ac_levels[n], 1, &dqm->y1_) << n;
+ nz |= VP8EncQuantizeBlock(tmp[n], rd->y_ac_levels[n], 1, &dqm->y1_) << n;
}
}
@@ -673,7 +640,7 @@ static int ReconstructIntra4(VP8EncIterator* const it,
nz = TrellisQuantizeBlock(it, tmp, levels, ctx, 3, &dqm->y1_,
dqm->lambda_trellis_i4_);
} else {
- nz = QuantizeBlock(tmp, levels, 0, &dqm->y1_);
+ nz = VP8EncQuantizeBlock(tmp, levels, 0, &dqm->y1_);
}
VP8ITransform(ref, tmp, yuv_out);
return nz;
@@ -708,7 +675,7 @@ static int ReconstructUV(VP8EncIterator* const it, VP8ModeScore* const rd,
}
} else {
for (n = 0; n < 8; ++n) {
- nz |= QuantizeBlock(tmp[n], rd->uv_levels[n], 0, &dqm->uv_) << n;
+ nz |= VP8EncQuantizeBlock(tmp[n], rd->uv_levels[n], 0, &dqm->uv_) << n;
}
}
diff --git a/third_party/libwebp/enc/vp8enci.h b/third_party/libwebp/enc/vp8enci.h
index b488922..b19450d 100644
--- a/third_party/libwebp/enc/vp8enci.h
+++ b/third_party/libwebp/enc/vp8enci.h
@@ -13,7 +13,7 @@
#define WEBP_ENC_VP8ENCI_H_
#include "string.h" // for memcpy()
-#include "../webp/encode.h"
+#include "webp/encode.h"
#include "bit_writer.h"
#if defined(__cplusplus) || defined(c_plusplus)
@@ -23,6 +23,11 @@ extern "C" {
//-----------------------------------------------------------------------------
// Various defines and enums
+// version numbers
+#define ENC_MAJ_VERSION 0
+#define ENC_MIN_VERSION 1
+#define ENC_REV_VERSION 2
+
// intra prediction modes
enum { B_DC_PRED = 0, // 4x4 modes
B_TM_PRED = 1,
@@ -144,6 +149,15 @@ extern const int VP8I4ModeOffsets[NUM_BMODES];
typedef int64_t score_t; // type used for scores, rate, distortion
#define MAX_COST ((score_t)0x7fffffffffffffLL)
+#define QFIX 17
+#define BIAS(b) ((b) << (QFIX - 8))
+// Fun fact: this is the _only_ line where we're actually being lossy and
+// discarding bits.
+static inline int QUANTDIV(int n, int iQ, int B) {
+ return (n * iQ + B) >> QFIX;
+}
+extern const uint8_t VP8Zigzag[16];
+
//-----------------------------------------------------------------------------
// Headers
@@ -428,8 +442,20 @@ typedef void (*VP8BlockCopy)(const uint8_t* src, uint8_t* dst);
extern VP8BlockCopy VP8Copy4x4;
extern VP8BlockCopy VP8Copy8x8;
extern VP8BlockCopy VP8Copy16x16;
-
-void VP8EncDspInit(); // must be called before using anything from the above.
+// Quantization
+typedef int (*VP8QuantizeBlock)(int16_t in[16], int16_t out[16],
+ int n, const VP8Matrix* const mtx);
+extern VP8QuantizeBlock VP8EncQuantizeBlock;
+
+typedef enum {
+ kSSE2,
+ kSSE3
+} CPUFeature;
+// returns true if the CPU supports the feature.
+typedef int (*VP8CPUInfo)(CPUFeature feature);
+extern VP8CPUInfo CPUInfo;
+
+void VP8EncDspInit(void); // must be called before using any of the above
// in filter.c
extern void VP8InitFilter(VP8EncIterator* const it);
diff --git a/third_party/libwebp/enc/webpenc.c b/third_party/libwebp/enc/webpenc.c
index 5ca445e..59221d7 100644
--- a/third_party/libwebp/enc/webpenc.c
+++ b/third_party/libwebp/enc/webpenc.c
@@ -28,11 +28,21 @@ extern "C" {
#define MAX_DIMENSION 16384 // maximum width/height allowed by the spec
//-----------------------------------------------------------------------------
+
+int WebPGetEncoderVersion(void) {
+ return (ENC_MAJ_VERSION << 16) | (ENC_MIN_VERSION << 8) | ENC_REV_VERSION;
+}
+
+//-----------------------------------------------------------------------------
// WebPPicture
//-----------------------------------------------------------------------------
static int DummyWriter(const uint8_t* data, size_t data_size,
const WebPPicture* const picture) {
+ // The following are to prevent 'unused variable' error message.
+ (void)data;
+ (void)data_size;
+ (void)picture;
return 1;
}
diff --git a/third_party/libwebp/libwebp.gyp b/third_party/libwebp/libwebp.gyp
index 7a50332..a43f79d 100644
--- a/third_party/libwebp/libwebp.gyp
+++ b/third_party/libwebp/libwebp.gyp
@@ -12,6 +12,7 @@
{
'target_name': 'libwebp_enc',
'type': '<(library)',
+ 'include_dirs': ['.'],
'sources': [
'enc/analysis.c',
'enc/bit_writer.c',
@@ -31,10 +32,12 @@
{
'target_name': 'libwebp_dec',
'type': '<(library)',
+ 'include_dirs': ['.'],
'sources': [
'dec/bits.c',
'dec/dsp.c',
'dec/frame.c',
+ 'dec/idec.c',
'dec/quant.c',
'dec/tree.c',
'dec/vp8.c',
diff --git a/third_party/libwebp/webp/decode.h b/third_party/libwebp/webp/decode.h
index 78b9016..6c63d54 100644
--- a/third_party/libwebp/webp/decode.h
+++ b/third_party/libwebp/webp/decode.h
@@ -12,12 +12,16 @@
#ifndef WEBP_WEBP_DECODE_H_
#define WEBP_WEBP_DECODE_H_
-#include "../webp/types.h"
+#include "webp/types.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
+// Return the decoder's version number, packed in hexadecimal using 8bits for
+// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
+int WebPGetDecoderVersion(void);
+
// Retrieve basic header information: width, height.
// This function will also validate the header and return 0 in
// case of formatting error.
@@ -92,6 +96,102 @@ uint8_t* WebPDecodeYUVInto(const uint8_t* data, uint32_t data_size,
//-----------------------------------------------------------------------------
+// Output colorspaces
+typedef enum { MODE_RGB = 0, MODE_RGBA = 1,
+ MODE_BGR = 2, MODE_BGRA = 3,
+ MODE_YUV = 4 } WEBP_CSP_MODE;
+
+// Enumeration of the status codes
+typedef enum {
+ VP8_STATUS_OK = 0,
+ VP8_STATUS_OUT_OF_MEMORY,
+ VP8_STATUS_INVALID_PARAM,
+ VP8_STATUS_BITSTREAM_ERROR,
+ VP8_STATUS_UNSUPPORTED_FEATURE,
+ VP8_STATUS_SUSPENDED,
+ VP8_STATUS_USER_ABORT,
+ VP8_STATUS_NOT_ENOUGH_DATA
+} VP8StatusCode;
+
+//-----------------------------------------------------------------------------
+// Incremental decoding
+//
+// This API allows streamlined decoding of partial data.
+// Picture can be incrementally decoded as data become available thanks to the
+// WebPIDecoder object. This object can be left in a SUSPENDED state if the
+// picture is only partially decoded, pending additional input.
+// Code example:
+//
+// WebPIDecoder* const idec = WebPINew(mode);
+// while (has_more_data) {
+// // ... (get additional data)
+// status = WebPIAppend(idec, new_data, new_data_size);
+// if (status != VP8_STATUS_SUSPENDED ||
+// break;
+// }
+//
+// // The above call decodes the current available buffer.
+// // Part of the image can now be refreshed by calling to
+// // WebPIDecGetRGB()/WebPIDecGetYUV() etc.
+// }
+// WebPIDelete(idec);
+
+typedef struct WebPIDecoder WebPIDecoder;
+
+// Creates a WebPIDecoder object. Returns NULL in case of failure.
+WebPIDecoder* WebPINew(WEBP_CSP_MODE mode);
+
+// This function allocates and initializes an incremental-decoder object, which
+// will output the r/g/b(/a) samples specified by 'mode' into a preallocated
+// buffer 'output_buffer'. The size of this buffer is at least
+// 'output_buffer_size' and the stride (distance in bytes between two scanlines)
+// is specified by 'output_stride'. Returns NULL if the allocation failed.
+WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE mode, uint8_t* output_buffer,
+ int output_buffer_size, int output_stride);
+
+// This function allocates and initializes an incremental-decoder object, which
+// will output the raw luma/chroma samples into a preallocated planes. The luma
+// plane is specified by its pointer 'luma', its size 'luma_size' and its stride
+// 'luma_stride'. Similarly, the chroma-u plane is specified by the 'u',
+// 'u_size' and 'u_stride' parameters, and the chroma-v plane by 'v', 'v_size'
+// and 'v_size'.
+// Returns NULL if the allocation failed.
+WebPIDecoder* WebPINewYUV(uint8_t* luma, int luma_size, int luma_stride,
+ uint8_t* u, int u_size, int u_stride,
+ uint8_t* v, int v_size, int v_stride);
+
+// Deletes the WebpBuffer object and associated memory. Must always be called
+// if WebPINew, WebPINewRGB or WebPINewYUV succeeded.
+void WebPIDelete(WebPIDecoder* const idec);
+
+// Copies and decodes the next available data. Returns VP8_STATUS_OK when
+// the image is successfully decoded. Returns VP8_STATUS_SUSPENDED when more
+// data is expected. Returns error in other cases.
+VP8StatusCode WebPIAppend(WebPIDecoder* const idec, const uint8_t* data,
+ uint32_t data_size);
+
+// A variant of the above function to be used when data buffer contains
+// partial data from the beginning. In this case data buffer is not copied
+// to the internal memory.
+// Note that the value of the 'data' pointer can change between calls to
+// WebPIUpdate, for instance when the data buffer is resized to fit larger data.
+VP8StatusCode WebPIUpdate(WebPIDecoder* const idec, const uint8_t* data,
+ uint32_t data_size);
+
+// Returns the RGB image decoded so far. Returns NULL if output params are not
+// initialized yet. *last_y is the index of last decoded row in raster scan
+// order. Some pointers (*last_y, *width etc.) can be NULL if corresponding
+// information is not needed.
+uint8_t* WebPIDecGetRGB(const WebPIDecoder* const idec, int *last_y,
+ int* width, int* height, int* stride);
+
+// Same as above function to get YUV image. Returns pointer to the luma plane
+// or NULL in case of error.
+uint8_t* WebPIDecGetYUV(const WebPIDecoder* const idec, int* last_y,
+ uint8_t** u, uint8_t** v,
+ int* width, int* height, int* stride, int* uv_stride);
+
+
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif
diff --git a/third_party/libwebp/webp/decode_vp8.h b/third_party/libwebp/webp/decode_vp8.h
index 08c6f69..153a4c5 100644
--- a/third_party/libwebp/webp/decode_vp8.h
+++ b/third_party/libwebp/webp/decode_vp8.h
@@ -12,7 +12,7 @@
#ifndef WEBP_WEBP_DECODE_VP8_H_
#define WEBP_WEBP_DECODE_VP8_H_
-#include "decode.h"
+#include "webp/decode.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
@@ -83,13 +83,13 @@ struct VP8Io {
};
// Internal, version-checked, entry point
-extern int VP8InitIoInternal(VP8Io* const, int);
+int VP8InitIoInternal(VP8Io* const, int);
// Main decoding object. This is an opaque structure.
typedef struct VP8Decoder VP8Decoder;
// Create a new decoder object.
-VP8Decoder* VP8New();
+VP8Decoder* VP8New(void);
// Must be called to make sure 'io' is initialized properly.
// Returns false in case of version mismatch. Upon such failure, no other
@@ -105,18 +105,6 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io);
// Returns false in case of error.
int VP8Decode(VP8Decoder* const dec, VP8Io* const io);
-// Enumeration of the codes returned by VP8Status()
-typedef enum {
- VP8_STATUS_OK = 0,
- VP8_STATUS_OUT_OF_MEMORY,
- VP8_STATUS_INVALID_PARAM,
- VP8_STATUS_BITSTREAM_ERROR,
- VP8_STATUS_UNSUPPORTED_FEATURE,
- VP8_STATUS_SUSPENDED,
- VP8_STATUS_USER_ABORT,
- VP8_STATUS_NOT_ENOUGH_DATA,
-} VP8StatusCode;
-
// Return current status of the decoder:
VP8StatusCode VP8Status(VP8Decoder* const dec);
diff --git a/third_party/libwebp/webp/encode.h b/third_party/libwebp/webp/encode.h
index 8fb8ff4..e0cc5dc 100644
--- a/third_party/libwebp/webp/encode.h
+++ b/third_party/libwebp/webp/encode.h
@@ -14,7 +14,7 @@
#include <stdlib.h>
-#include "../webp/types.h"
+#include "webp/types.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
@@ -22,6 +22,10 @@ extern "C" {
#define WEBP_ENCODER_ABI_VERSION 0x0001
+// Return the encoder's version number, packed in hexadecimal using 8bits for
+// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
+int WebPGetEncoderVersion(void);
+
//-----------------------------------------------------------------------------
// One-stop-shop call! No questions asked: