summaryrefslogtreecommitdiff
path: root/thirdparty/libwebp/dec
diff options
context:
space:
mode:
authorvolzhs <volzhs@gmail.com>2017-12-12 02:11:11 +0900
committervolzhs <volzhs@gmail.com>2017-12-12 02:55:47 +0900
commit043103fe6a1168729abf74dd56b8982ce54eea43 (patch)
treef3311c0442fba0ff565d9de0ad9fee3f0002295e /thirdparty/libwebp/dec
parent64d104756c04f4d5c4e8140271d5e8049e5f8371 (diff)
Update libwebp to 0.6.1
* lossless performance and compression improvements + a new 'cruncher' mode (-m 6 -q 100) * ARM performance improvements with clang (15-20% w/ndk r15c) * webp-js: emscripten/webassembly based javascript decoder * miscellaneous bug & build fixes
Diffstat (limited to 'thirdparty/libwebp/dec')
-rw-r--r--thirdparty/libwebp/dec/alpha_dec.c232
-rw-r--r--thirdparty/libwebp/dec/alphai_dec.h54
-rw-r--r--thirdparty/libwebp/dec/buffer_dec.c300
-rw-r--r--thirdparty/libwebp/dec/common_dec.h54
-rw-r--r--thirdparty/libwebp/dec/frame_dec.c812
-rw-r--r--thirdparty/libwebp/dec/idec_dec.c892
-rw-r--r--thirdparty/libwebp/dec/io_dec.c645
-rw-r--r--thirdparty/libwebp/dec/quant_dec.c110
-rw-r--r--thirdparty/libwebp/dec/tree_dec.c528
-rw-r--r--thirdparty/libwebp/dec/vp8_dec.c721
-rw-r--r--thirdparty/libwebp/dec/vp8_dec.h185
-rw-r--r--thirdparty/libwebp/dec/vp8i_dec.h320
-rw-r--r--thirdparty/libwebp/dec/vp8l_dec.c1671
-rw-r--r--thirdparty/libwebp/dec/vp8li_dec.h135
-rw-r--r--thirdparty/libwebp/dec/webp_dec.c843
-rw-r--r--thirdparty/libwebp/dec/webpi_dec.h133
16 files changed, 0 insertions, 7635 deletions
diff --git a/thirdparty/libwebp/dec/alpha_dec.c b/thirdparty/libwebp/dec/alpha_dec.c
deleted file mode 100644
index 83ffd4b609..0000000000
--- a/thirdparty/libwebp/dec/alpha_dec.c
+++ /dev/null
@@ -1,232 +0,0 @@
-// 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.
-// -----------------------------------------------------------------------------
-//
-// Alpha-plane decompression.
-//
-// Author: Skal (pascal.massimino@gmail.com)
-
-#include <stdlib.h>
-#include "./alphai_dec.h"
-#include "./vp8i_dec.h"
-#include "./vp8li_dec.h"
-#include "../dsp/dsp.h"
-#include "../utils/quant_levels_dec_utils.h"
-#include "../utils/utils.h"
-#include "../webp/format_constants.h"
-
-//------------------------------------------------------------------------------
-// ALPHDecoder object.
-
-// Allocates a new alpha decoder instance.
-static ALPHDecoder* ALPHNew(void) {
- ALPHDecoder* const dec = (ALPHDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
- return dec;
-}
-
-// Clears and deallocates an alpha decoder instance.
-static void ALPHDelete(ALPHDecoder* const dec) {
- if (dec != NULL) {
- VP8LDelete(dec->vp8l_dec_);
- dec->vp8l_dec_ = NULL;
- WebPSafeFree(dec);
- }
-}
-
-//------------------------------------------------------------------------------
-// Decoding.
-
-// Initialize alpha decoding by parsing the alpha header and decoding the image
-// header for alpha data stored using lossless compression.
-// Returns false in case of error in alpha header (data too short, invalid
-// compression method or filter, error in lossless header data etc).
-static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
- size_t data_size, const VP8Io* const src_io,
- uint8_t* output) {
- int ok = 0;
- const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN;
- const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN;
- int rsrv;
- VP8Io* const io = &dec->io_;
-
- assert(data != NULL && output != NULL && src_io != NULL);
-
- VP8FiltersInit();
- dec->output_ = output;
- dec->width_ = src_io->width;
- dec->height_ = src_io->height;
- assert(dec->width_ > 0 && dec->height_ > 0);
-
- if (data_size <= ALPHA_HEADER_LEN) {
- return 0;
- }
-
- dec->method_ = (data[0] >> 0) & 0x03;
- dec->filter_ = (WEBP_FILTER_TYPE)((data[0] >> 2) & 0x03);
- dec->pre_processing_ = (data[0] >> 4) & 0x03;
- rsrv = (data[0] >> 6) & 0x03;
- if (dec->method_ < ALPHA_NO_COMPRESSION ||
- dec->method_ > ALPHA_LOSSLESS_COMPRESSION ||
- dec->filter_ >= WEBP_FILTER_LAST ||
- dec->pre_processing_ > ALPHA_PREPROCESSED_LEVELS ||
- rsrv != 0) {
- return 0;
- }
-
- // Copy the necessary parameters from src_io to io
- VP8InitIo(io);
- WebPInitCustomIo(NULL, io);
- io->opaque = dec;
- io->width = src_io->width;
- io->height = src_io->height;
-
- io->use_cropping = src_io->use_cropping;
- io->crop_left = src_io->crop_left;
- io->crop_right = src_io->crop_right;
- io->crop_top = src_io->crop_top;
- io->crop_bottom = src_io->crop_bottom;
- // No need to copy the scaling parameters.
-
- if (dec->method_ == ALPHA_NO_COMPRESSION) {
- const size_t alpha_decoded_size = dec->width_ * dec->height_;
- ok = (alpha_data_size >= alpha_decoded_size);
- } else {
- assert(dec->method_ == ALPHA_LOSSLESS_COMPRESSION);
- ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size);
- }
-
- return ok;
-}
-
-// Decodes, unfilters and dequantizes *at least* 'num_rows' rows of alpha
-// starting from row number 'row'. It assumes that rows up to (row - 1) have
-// already been decoded.
-// Returns false in case of bitstream error.
-static int ALPHDecode(VP8Decoder* const dec, int row, int num_rows) {
- ALPHDecoder* const alph_dec = dec->alph_dec_;
- const int width = alph_dec->width_;
- const int height = alph_dec->io_.crop_bottom;
- if (alph_dec->method_ == ALPHA_NO_COMPRESSION) {
- int y;
- const uint8_t* prev_line = dec->alpha_prev_line_;
- const uint8_t* deltas = dec->alpha_data_ + ALPHA_HEADER_LEN + row * width;
- uint8_t* dst = dec->alpha_plane_ + row * width;
- assert(deltas <= &dec->alpha_data_[dec->alpha_data_size_]);
- if (alph_dec->filter_ != WEBP_FILTER_NONE) {
- assert(WebPUnfilters[alph_dec->filter_] != NULL);
- for (y = 0; y < num_rows; ++y) {
- WebPUnfilters[alph_dec->filter_](prev_line, deltas, dst, width);
- prev_line = dst;
- dst += width;
- deltas += width;
- }
- } else {
- for (y = 0; y < num_rows; ++y) {
- memcpy(dst, deltas, width * sizeof(*dst));
- prev_line = dst;
- dst += width;
- deltas += width;
- }
- }
- dec->alpha_prev_line_ = prev_line;
- } else { // alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION
- assert(alph_dec->vp8l_dec_ != NULL);
- if (!VP8LDecodeAlphaImageStream(alph_dec, row + num_rows)) {
- return 0;
- }
- }
-
- if (row + num_rows >= height) {
- dec->is_alpha_decoded_ = 1;
- }
- return 1;
-}
-
-static int AllocateAlphaPlane(VP8Decoder* const dec, const VP8Io* const io) {
- const int stride = io->width;
- const int height = io->crop_bottom;
- const uint64_t alpha_size = (uint64_t)stride * height;
- assert(dec->alpha_plane_mem_ == NULL);
- dec->alpha_plane_mem_ =
- (uint8_t*)WebPSafeMalloc(alpha_size, sizeof(*dec->alpha_plane_));
- if (dec->alpha_plane_mem_ == NULL) {
- return 0;
- }
- dec->alpha_plane_ = dec->alpha_plane_mem_;
- dec->alpha_prev_line_ = NULL;
- return 1;
-}
-
-void WebPDeallocateAlphaMemory(VP8Decoder* const dec) {
- assert(dec != NULL);
- WebPSafeFree(dec->alpha_plane_mem_);
- dec->alpha_plane_mem_ = NULL;
- dec->alpha_plane_ = NULL;
- ALPHDelete(dec->alph_dec_);
- dec->alph_dec_ = NULL;
-}
-
-//------------------------------------------------------------------------------
-// Main entry point.
-
-const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
- const VP8Io* const io,
- int row, int num_rows) {
- const int width = io->width;
- const int height = io->crop_bottom;
-
- assert(dec != NULL && io != NULL);
-
- if (row < 0 || num_rows <= 0 || row + num_rows > height) {
- return NULL; // sanity check.
- }
-
- if (!dec->is_alpha_decoded_) {
- if (dec->alph_dec_ == NULL) { // Initialize decoder.
- dec->alph_dec_ = ALPHNew();
- if (dec->alph_dec_ == NULL) return NULL;
- if (!AllocateAlphaPlane(dec, io)) goto Error;
- if (!ALPHInit(dec->alph_dec_, dec->alpha_data_, dec->alpha_data_size_,
- io, dec->alpha_plane_)) {
- goto Error;
- }
- // if we allowed use of alpha dithering, check whether it's needed at all
- if (dec->alph_dec_->pre_processing_ != ALPHA_PREPROCESSED_LEVELS) {
- dec->alpha_dithering_ = 0; // disable dithering
- } else {
- num_rows = height - row; // decode everything in one pass
- }
- }
-
- assert(dec->alph_dec_ != NULL);
- assert(row + num_rows <= height);
- if (!ALPHDecode(dec, row, num_rows)) goto Error;
-
- if (dec->is_alpha_decoded_) { // finished?
- ALPHDelete(dec->alph_dec_);
- dec->alph_dec_ = NULL;
- if (dec->alpha_dithering_ > 0) {
- uint8_t* const alpha = dec->alpha_plane_ + io->crop_top * width
- + io->crop_left;
- if (!WebPDequantizeLevels(alpha,
- io->crop_right - io->crop_left,
- io->crop_bottom - io->crop_top,
- width, dec->alpha_dithering_)) {
- goto Error;
- }
- }
- }
- }
-
- // Return a pointer to the current decoded row.
- return dec->alpha_plane_ + row * width;
-
- Error:
- WebPDeallocateAlphaMemory(dec);
- return NULL;
-}
diff --git a/thirdparty/libwebp/dec/alphai_dec.h b/thirdparty/libwebp/dec/alphai_dec.h
deleted file mode 100644
index 561e8151ee..0000000000
--- a/thirdparty/libwebp/dec/alphai_dec.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2013 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.
-// -----------------------------------------------------------------------------
-//
-// Alpha decoder: internal header.
-//
-// Author: Urvang (urvang@google.com)
-
-#ifndef WEBP_DEC_ALPHAI_H_
-#define WEBP_DEC_ALPHAI_H_
-
-#include "./webpi_dec.h"
-#include "../utils/filters_utils.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct VP8LDecoder; // Defined in dec/vp8li.h.
-
-typedef struct ALPHDecoder ALPHDecoder;
-struct ALPHDecoder {
- int width_;
- int height_;
- int method_;
- WEBP_FILTER_TYPE filter_;
- int pre_processing_;
- struct VP8LDecoder* vp8l_dec_;
- VP8Io io_;
- int use_8b_decode_; // Although alpha channel requires only 1 byte per
- // pixel, sometimes VP8LDecoder may need to allocate
- // 4 bytes per pixel internally during decode.
- uint8_t* output_;
- const uint8_t* prev_line_; // last output row (or NULL)
-};
-
-//------------------------------------------------------------------------------
-// internal functions. Not public.
-
-// Deallocate memory associated to dec->alpha_plane_ decoding
-void WebPDeallocateAlphaMemory(VP8Decoder* const dec);
-
-//------------------------------------------------------------------------------
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif /* WEBP_DEC_ALPHAI_H_ */
diff --git a/thirdparty/libwebp/dec/buffer_dec.c b/thirdparty/libwebp/dec/buffer_dec.c
deleted file mode 100644
index c685fd5646..0000000000
--- a/thirdparty/libwebp/dec/buffer_dec.c
+++ /dev/null
@@ -1,300 +0,0 @@
-// 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.
-// -----------------------------------------------------------------------------
-//
-// Everything about WebPDecBuffer
-//
-// Author: Skal (pascal.massimino@gmail.com)
-
-#include <stdlib.h>
-
-#include "./vp8i_dec.h"
-#include "./webpi_dec.h"
-#include "../utils/utils.h"
-
-//------------------------------------------------------------------------------
-// WebPDecBuffer
-
-// Number of bytes per pixel for the different color-spaces.
-static const int kModeBpp[MODE_LAST] = {
- 3, 4, 3, 4, 4, 2, 2,
- 4, 4, 4, 2, // pre-multiplied modes
- 1, 1 };
-
-// Check that webp_csp_mode is within the bounds of WEBP_CSP_MODE.
-// Convert to an integer to handle both the unsigned/signed enum cases
-// without the need for casting to remove type limit warnings.
-static int IsValidColorspace(int webp_csp_mode) {
- return (webp_csp_mode >= MODE_RGB && webp_csp_mode < MODE_LAST);
-}
-
-// strictly speaking, the very last (or first, if flipped) row
-// doesn't require padding.
-#define MIN_BUFFER_SIZE(WIDTH, HEIGHT, STRIDE) \
- (uint64_t)(STRIDE) * ((HEIGHT) - 1) + (WIDTH)
-
-static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
- int ok = 1;
- const WEBP_CSP_MODE mode = buffer->colorspace;
- const int width = buffer->width;
- const int height = buffer->height;
- if (!IsValidColorspace(mode)) {
- ok = 0;
- } else if (!WebPIsRGBMode(mode)) { // YUV checks
- const WebPYUVABuffer* const buf = &buffer->u.YUVA;
- const int uv_width = (width + 1) / 2;
- const int uv_height = (height + 1) / 2;
- const int y_stride = abs(buf->y_stride);
- const int u_stride = abs(buf->u_stride);
- const int v_stride = abs(buf->v_stride);
- const int a_stride = abs(buf->a_stride);
- const uint64_t y_size = MIN_BUFFER_SIZE(width, height, y_stride);
- const uint64_t u_size = MIN_BUFFER_SIZE(uv_width, uv_height, u_stride);
- const uint64_t v_size = MIN_BUFFER_SIZE(uv_width, uv_height, v_stride);
- const uint64_t a_size = MIN_BUFFER_SIZE(width, height, a_stride);
- ok &= (y_size <= buf->y_size);
- ok &= (u_size <= buf->u_size);
- ok &= (v_size <= buf->v_size);
- ok &= (y_stride >= width);
- ok &= (u_stride >= uv_width);
- ok &= (v_stride >= uv_width);
- ok &= (buf->y != NULL);
- ok &= (buf->u != NULL);
- ok &= (buf->v != NULL);
- if (mode == MODE_YUVA) {
- ok &= (a_stride >= width);
- ok &= (a_size <= buf->a_size);
- ok &= (buf->a != NULL);
- }
- } else { // RGB checks
- const WebPRGBABuffer* const buf = &buffer->u.RGBA;
- const int stride = abs(buf->stride);
- const uint64_t size = MIN_BUFFER_SIZE(width, height, stride);
- ok &= (size <= buf->size);
- ok &= (stride >= width * kModeBpp[mode]);
- ok &= (buf->rgba != NULL);
- }
- return ok ? VP8_STATUS_OK : VP8_STATUS_INVALID_PARAM;
-}
-#undef MIN_BUFFER_SIZE
-
-static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
- const int w = buffer->width;
- const int h = buffer->height;
- const WEBP_CSP_MODE mode = buffer->colorspace;
-
- if (w <= 0 || h <= 0 || !IsValidColorspace(mode)) {
- return VP8_STATUS_INVALID_PARAM;
- }
-
- if (buffer->is_external_memory <= 0 && buffer->private_memory == NULL) {
- uint8_t* output;
- int uv_stride = 0, a_stride = 0;
- uint64_t uv_size = 0, a_size = 0, total_size;
- // We need memory and it hasn't been allocated yet.
- // => initialize output buffer, now that dimensions are known.
- const int stride = w * kModeBpp[mode];
- const uint64_t size = (uint64_t)stride * h;
-
- if (!WebPIsRGBMode(mode)) {
- uv_stride = (w + 1) / 2;
- uv_size = (uint64_t)uv_stride * ((h + 1) / 2);
- if (mode == MODE_YUVA) {
- a_stride = w;
- a_size = (uint64_t)a_stride * h;
- }
- }
- total_size = size + 2 * uv_size + a_size;
-
- // Security/sanity checks
- output = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*output));
- if (output == NULL) {
- return VP8_STATUS_OUT_OF_MEMORY;
- }
- buffer->private_memory = output;
-
- if (!WebPIsRGBMode(mode)) { // YUVA initialization
- WebPYUVABuffer* const buf = &buffer->u.YUVA;
- buf->y = output;
- buf->y_stride = stride;
- buf->y_size = (size_t)size;
- buf->u = output + size;
- buf->u_stride = uv_stride;
- buf->u_size = (size_t)uv_size;
- buf->v = output + size + uv_size;
- buf->v_stride = uv_stride;
- buf->v_size = (size_t)uv_size;
- if (mode == MODE_YUVA) {
- buf->a = output + size + 2 * uv_size;
- }
- buf->a_size = (size_t)a_size;
- buf->a_stride = a_stride;
- } else { // RGBA initialization
- WebPRGBABuffer* const buf = &buffer->u.RGBA;
- buf->rgba = output;
- buf->stride = stride;
- buf->size = (size_t)size;
- }
- }
- return CheckDecBuffer(buffer);
-}
-
-VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer) {
- if (buffer == NULL) {
- return VP8_STATUS_INVALID_PARAM;
- }
- if (WebPIsRGBMode(buffer->colorspace)) {
- WebPRGBABuffer* const buf = &buffer->u.RGBA;
- buf->rgba += (buffer->height - 1) * buf->stride;
- buf->stride = -buf->stride;
- } else {
- WebPYUVABuffer* const buf = &buffer->u.YUVA;
- const int H = buffer->height;
- buf->y += (H - 1) * buf->y_stride;
- buf->y_stride = -buf->y_stride;
- buf->u += ((H - 1) >> 1) * buf->u_stride;
- buf->u_stride = -buf->u_stride;
- buf->v += ((H - 1) >> 1) * buf->v_stride;
- buf->v_stride = -buf->v_stride;
- if (buf->a != NULL) {
- buf->a += (H - 1) * buf->a_stride;
- buf->a_stride = -buf->a_stride;
- }
- }
- return VP8_STATUS_OK;
-}
-
-VP8StatusCode WebPAllocateDecBuffer(int w, int h,
- const WebPDecoderOptions* const options,
- WebPDecBuffer* const out) {
- VP8StatusCode status;
- if (out == NULL || w <= 0 || h <= 0) {
- return VP8_STATUS_INVALID_PARAM;
- }
- if (options != NULL) { // First, apply options if there is any.
- if (options->use_cropping) {
- const int cw = options->crop_width;
- const int ch = options->crop_height;
- const int x = options->crop_left & ~1;
- const int y = options->crop_top & ~1;
- if (x < 0 || y < 0 || cw <= 0 || ch <= 0 || x + cw > w || y + ch > h) {
- return VP8_STATUS_INVALID_PARAM; // out of frame boundary.
- }
- w = cw;
- h = ch;
- }
- if (options->use_scaling) {
- int scaled_width = options->scaled_width;
- int scaled_height = options->scaled_height;
- if (!WebPRescalerGetScaledDimensions(
- w, h, &scaled_width, &scaled_height)) {
- return VP8_STATUS_INVALID_PARAM;
- }
- w = scaled_width;
- h = scaled_height;
- }
- }
- out->width = w;
- out->height = h;
-
- // Then, allocate buffer for real.
- status = AllocateBuffer(out);
- if (status != VP8_STATUS_OK) return status;
-
- // Use the stride trick if vertical flip is needed.
- if (options != NULL && options->flip) {
- status = WebPFlipBuffer(out);
- }
- return status;
-}
-
-//------------------------------------------------------------------------------
-// constructors / destructors
-
-int WebPInitDecBufferInternal(WebPDecBuffer* buffer, int version) {
- if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
- return 0; // version mismatch
- }
- if (buffer == NULL) return 0;
- memset(buffer, 0, sizeof(*buffer));
- return 1;
-}
-
-void WebPFreeDecBuffer(WebPDecBuffer* buffer) {
- if (buffer != NULL) {
- if (buffer->is_external_memory <= 0) {
- WebPSafeFree(buffer->private_memory);
- }
- buffer->private_memory = NULL;
- }
-}
-
-void WebPCopyDecBuffer(const WebPDecBuffer* const src,
- WebPDecBuffer* const dst) {
- if (src != NULL && dst != NULL) {
- *dst = *src;
- if (src->private_memory != NULL) {
- dst->is_external_memory = 1; // dst buffer doesn't own the memory.
- dst->private_memory = NULL;
- }
- }
-}
-
-// Copy and transfer ownership from src to dst (beware of parameter order!)
-void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst) {
- if (src != NULL && dst != NULL) {
- *dst = *src;
- if (src->private_memory != NULL) {
- src->is_external_memory = 1; // src relinquishes ownership
- src->private_memory = NULL;
- }
- }
-}
-
-VP8StatusCode WebPCopyDecBufferPixels(const WebPDecBuffer* const src_buf,
- WebPDecBuffer* const dst_buf) {
- assert(src_buf != NULL && dst_buf != NULL);
- assert(src_buf->colorspace == dst_buf->colorspace);
-
- dst_buf->width = src_buf->width;
- dst_buf->height = src_buf->height;
- if (CheckDecBuffer(dst_buf) != VP8_STATUS_OK) {
- return VP8_STATUS_INVALID_PARAM;
- }
- if (WebPIsRGBMode(src_buf->colorspace)) {
- const WebPRGBABuffer* const src = &src_buf->u.RGBA;
- const WebPRGBABuffer* const dst = &dst_buf->u.RGBA;
- WebPCopyPlane(src->rgba, src->stride, dst->rgba, dst->stride,
- src_buf->width * kModeBpp[src_buf->colorspace],
- src_buf->height);
- } else {
- const WebPYUVABuffer* const src = &src_buf->u.YUVA;
- const WebPYUVABuffer* const dst = &dst_buf->u.YUVA;
- WebPCopyPlane(src->y, src->y_stride, dst->y, dst->y_stride,
- src_buf->width, src_buf->height);
- WebPCopyPlane(src->u, src->u_stride, dst->u, dst->u_stride,
- (src_buf->width + 1) / 2, (src_buf->height + 1) / 2);
- WebPCopyPlane(src->v, src->v_stride, dst->v, dst->v_stride,
- (src_buf->width + 1) / 2, (src_buf->height + 1) / 2);
- if (WebPIsAlphaMode(src_buf->colorspace)) {
- WebPCopyPlane(src->a, src->a_stride, dst->a, dst->a_stride,
- src_buf->width, src_buf->height);
- }
- }
- return VP8_STATUS_OK;
-}
-
-int WebPAvoidSlowMemory(const WebPDecBuffer* const output,
- const WebPBitstreamFeatures* const features) {
- assert(output != NULL);
- return (output->is_external_memory >= 2) &&
- WebPIsPremultipliedMode(output->colorspace) &&
- (features != NULL && features->has_alpha);
-}
-
-//------------------------------------------------------------------------------
diff --git a/thirdparty/libwebp/dec/common_dec.h b/thirdparty/libwebp/dec/common_dec.h
deleted file mode 100644
index 6961e22470..0000000000
--- a/thirdparty/libwebp/dec/common_dec.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2015 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.
-// -----------------------------------------------------------------------------
-//
-// Definitions and macros common to encoding and decoding
-//
-// Author: Skal (pascal.massimino@gmail.com)
-
-#ifndef WEBP_DEC_COMMON_H_
-#define WEBP_DEC_COMMON_H_
-
-// intra prediction modes
-enum { B_DC_PRED = 0, // 4x4 modes
- B_TM_PRED = 1,
- B_VE_PRED = 2,
- B_HE_PRED = 3,
- B_RD_PRED = 4,
- B_VR_PRED = 5,
- B_LD_PRED = 6,
- B_VL_PRED = 7,
- B_HD_PRED = 8,
- B_HU_PRED = 9,
- NUM_BMODES = B_HU_PRED + 1 - B_DC_PRED, // = 10
-
- // Luma16 or UV modes
- DC_PRED = B_DC_PRED, V_PRED = B_VE_PRED,
- H_PRED = B_HE_PRED, TM_PRED = B_TM_PRED,
- B_PRED = NUM_BMODES, // refined I4x4 mode
- NUM_PRED_MODES = 4,
-
- // special modes
- B_DC_PRED_NOTOP = 4,
- B_DC_PRED_NOLEFT = 5,
- B_DC_PRED_NOTOPLEFT = 6,
- NUM_B_DC_MODES = 7 };
-
-enum { MB_FEATURE_TREE_PROBS = 3,
- NUM_MB_SEGMENTS = 4,
- NUM_REF_LF_DELTAS = 4,
- NUM_MODE_LF_DELTAS = 4, // I4x4, ZERO, *, SPLIT
- MAX_NUM_PARTITIONS = 8,
- // Probabilities
- NUM_TYPES = 4, // 0: i16-AC, 1: i16-DC, 2:chroma-AC, 3:i4-AC
- NUM_BANDS = 8,
- NUM_CTX = 3,
- NUM_PROBAS = 11
- };
-
-#endif // WEBP_DEC_COMMON_H_
diff --git a/thirdparty/libwebp/dec/frame_dec.c b/thirdparty/libwebp/dec/frame_dec.c
deleted file mode 100644
index f91e27f7c8..0000000000
--- a/thirdparty/libwebp/dec/frame_dec.c
+++ /dev/null
@@ -1,812 +0,0 @@
-// Copyright 2010 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.
-// -----------------------------------------------------------------------------
-//
-// Frame-reconstruction function. Memory allocation.
-//
-// Author: Skal (pascal.massimino@gmail.com)
-
-#include <stdlib.h>
-#include "./vp8i_dec.h"
-#include "../utils/utils.h"
-
-//------------------------------------------------------------------------------
-// Main reconstruction function.
-
-static const int kScan[16] = {
- 0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS,
- 0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS,
- 0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS,
- 0 + 12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS
-};
-
-static int CheckMode(int mb_x, int mb_y, int mode) {
- if (mode == B_DC_PRED) {
- if (mb_x == 0) {
- return (mb_y == 0) ? B_DC_PRED_NOTOPLEFT : B_DC_PRED_NOLEFT;
- } else {
- return (mb_y == 0) ? B_DC_PRED_NOTOP : B_DC_PRED;
- }
- }
- return mode;
-}
-
-static void Copy32b(uint8_t* const dst, const uint8_t* const src) {
- memcpy(dst, src, 4);
-}
-
-static WEBP_INLINE void DoTransform(uint32_t bits, const int16_t* const src,
- uint8_t* const dst) {
- switch (bits >> 30) {
- case 3:
- VP8Transform(src, dst, 0);
- break;
- case 2:
- VP8TransformAC3(src, dst);
- break;
- case 1:
- VP8TransformDC(src, dst);
- break;
- default:
- break;
- }
-}
-
-static void DoUVTransform(uint32_t bits, const int16_t* const src,
- uint8_t* const dst) {
- if (bits & 0xff) { // any non-zero coeff at all?
- if (bits & 0xaa) { // any non-zero AC coefficient?
- VP8TransformUV(src, dst); // note we don't use the AC3 variant for U/V
- } else {
- VP8TransformDCUV(src, dst);
- }
- }
-}
-
-static void ReconstructRow(const VP8Decoder* const dec,
- const VP8ThreadContext* ctx) {
- int j;
- int mb_x;
- const int mb_y = ctx->mb_y_;
- const int cache_id = ctx->id_;
- uint8_t* const y_dst = dec->yuv_b_ + Y_OFF;
- uint8_t* const u_dst = dec->yuv_b_ + U_OFF;
- uint8_t* const v_dst = dec->yuv_b_ + V_OFF;
-
- // Initialize left-most block.
- for (j = 0; j < 16; ++j) {
- y_dst[j * BPS - 1] = 129;
- }
- for (j = 0; j < 8; ++j) {
- u_dst[j * BPS - 1] = 129;
- v_dst[j * BPS - 1] = 129;
- }
-
- // Init top-left sample on left column too.
- if (mb_y > 0) {
- y_dst[-1 - BPS] = u_dst[-1 - BPS] = v_dst[-1 - BPS] = 129;
- } else {
- // we only need to do this init once at block (0,0).
- // Afterward, it remains valid for the whole topmost row.
- memset(y_dst - BPS - 1, 127, 16 + 4 + 1);
- memset(u_dst - BPS - 1, 127, 8 + 1);
- memset(v_dst - BPS - 1, 127, 8 + 1);
- }
-
- // Reconstruct one row.
- for (mb_x = 0; mb_x < dec->mb_w_; ++mb_x) {
- const VP8MBData* const block = ctx->mb_data_ + mb_x;
-
- // Rotate in the left samples from previously decoded block. We move four
- // pixels at a time for alignment reason, and because of in-loop filter.
- if (mb_x > 0) {
- for (j = -1; j < 16; ++j) {
- Copy32b(&y_dst[j * BPS - 4], &y_dst[j * BPS + 12]);
- }
- for (j = -1; j < 8; ++j) {
- Copy32b(&u_dst[j * BPS - 4], &u_dst[j * BPS + 4]);
- Copy32b(&v_dst[j * BPS - 4], &v_dst[j * BPS + 4]);
- }
- }
- {
- // bring top samples into the cache
- VP8TopSamples* const top_yuv = dec->yuv_t_ + mb_x;
- const int16_t* const coeffs = block->coeffs_;
- uint32_t bits = block->non_zero_y_;
- int n;
-
- if (mb_y > 0) {
- memcpy(y_dst - BPS, top_yuv[0].y, 16);
- memcpy(u_dst - BPS, top_yuv[0].u, 8);
- memcpy(v_dst - BPS, top_yuv[0].v, 8);
- }
-
- // predict and add residuals
- if (block->is_i4x4_) { // 4x4
- uint32_t* const top_right = (uint32_t*)(y_dst - BPS + 16);
-
- if (mb_y > 0) {
- if (mb_x >= dec->mb_w_ - 1) { // on rightmost border
- memset(top_right, top_yuv[0].y[15], sizeof(*top_right));
- } else {
- memcpy(top_right, top_yuv[1].y, sizeof(*top_right));
- }
- }
- // replicate the top-right pixels below
- top_right[BPS] = top_right[2 * BPS] = top_right[3 * BPS] = top_right[0];
-
- // predict and add residuals for all 4x4 blocks in turn.
- for (n = 0; n < 16; ++n, bits <<= 2) {
- uint8_t* const dst = y_dst + kScan[n];
- VP8PredLuma4[block->imodes_[n]](dst);
- DoTransform(bits, coeffs + n * 16, dst);
- }
- } else { // 16x16
- const int pred_func = CheckMode(mb_x, mb_y, block->imodes_[0]);
- VP8PredLuma16[pred_func](y_dst);
- if (bits != 0) {
- for (n = 0; n < 16; ++n, bits <<= 2) {
- DoTransform(bits, coeffs + n * 16, y_dst + kScan[n]);
- }
- }
- }
- {
- // Chroma
- const uint32_t bits_uv = block->non_zero_uv_;
- const int pred_func = CheckMode(mb_x, mb_y, block->uvmode_);
- VP8PredChroma8[pred_func](u_dst);
- VP8PredChroma8[pred_func](v_dst);
- DoUVTransform(bits_uv >> 0, coeffs + 16 * 16, u_dst);
- DoUVTransform(bits_uv >> 8, coeffs + 20 * 16, v_dst);
- }
-
- // stash away top samples for next block
- if (mb_y < dec->mb_h_ - 1) {
- memcpy(top_yuv[0].y, y_dst + 15 * BPS, 16);
- memcpy(top_yuv[0].u, u_dst + 7 * BPS, 8);
- memcpy(top_yuv[0].v, v_dst + 7 * BPS, 8);
- }
- }
- // Transfer reconstructed samples from yuv_b_ cache to final destination.
- {
- const int y_offset = cache_id * 16 * dec->cache_y_stride_;
- const int uv_offset = cache_id * 8 * dec->cache_uv_stride_;
- uint8_t* const y_out = dec->cache_y_ + mb_x * 16 + y_offset;
- uint8_t* const u_out = dec->cache_u_ + mb_x * 8 + uv_offset;
- uint8_t* const v_out = dec->cache_v_ + mb_x * 8 + uv_offset;
- for (j = 0; j < 16; ++j) {
- memcpy(y_out + j * dec->cache_y_stride_, y_dst + j * BPS, 16);
- }
- for (j = 0; j < 8; ++j) {
- memcpy(u_out + j * dec->cache_uv_stride_, u_dst + j * BPS, 8);
- memcpy(v_out + j * dec->cache_uv_stride_, v_dst + j * BPS, 8);
- }
- }
- }
-}
-
-//------------------------------------------------------------------------------
-// Filtering
-
-// kFilterExtraRows[] = How many extra lines are needed on the MB boundary
-// for caching, given a filtering level.
-// Simple filter: up to 2 luma samples are read and 1 is written.
-// Complex filter: up to 4 luma samples are read and 3 are written. Same for
-// U/V, so it's 8 samples total (because of the 2x upsampling).
-static const uint8_t kFilterExtraRows[3] = { 0, 2, 8 };
-
-static void DoFilter(const VP8Decoder* const dec, int mb_x, int mb_y) {
- const VP8ThreadContext* const ctx = &dec->thread_ctx_;
- const int cache_id = ctx->id_;
- const int y_bps = dec->cache_y_stride_;
- const VP8FInfo* const f_info = ctx->f_info_ + mb_x;
- uint8_t* const y_dst = dec->cache_y_ + cache_id * 16 * y_bps + mb_x * 16;
- const int ilevel = f_info->f_ilevel_;
- const int limit = f_info->f_limit_;
- if (limit == 0) {
- return;
- }
- assert(limit >= 3);
- if (dec->filter_type_ == 1) { // simple
- if (mb_x > 0) {
- VP8SimpleHFilter16(y_dst, y_bps, limit + 4);
- }
- if (f_info->f_inner_) {
- VP8SimpleHFilter16i(y_dst, y_bps, limit);
- }
- if (mb_y > 0) {
- VP8SimpleVFilter16(y_dst, y_bps, limit + 4);
- }
- if (f_info->f_inner_) {
- VP8SimpleVFilter16i(y_dst, y_bps, limit);
- }
- } else { // complex
- const int uv_bps = dec->cache_uv_stride_;
- uint8_t* const u_dst = dec->cache_u_ + cache_id * 8 * uv_bps + mb_x * 8;
- uint8_t* const v_dst = dec->cache_v_ + cache_id * 8 * uv_bps + mb_x * 8;
- const int hev_thresh = f_info->hev_thresh_;
- if (mb_x > 0) {
- VP8HFilter16(y_dst, y_bps, limit + 4, ilevel, hev_thresh);
- VP8HFilter8(u_dst, v_dst, uv_bps, limit + 4, ilevel, hev_thresh);
- }
- if (f_info->f_inner_) {
- VP8HFilter16i(y_dst, y_bps, limit, ilevel, hev_thresh);
- VP8HFilter8i(u_dst, v_dst, uv_bps, limit, ilevel, hev_thresh);
- }
- if (mb_y > 0) {
- VP8VFilter16(y_dst, y_bps, limit + 4, ilevel, hev_thresh);
- VP8VFilter8(u_dst, v_dst, uv_bps, limit + 4, ilevel, hev_thresh);
- }
- if (f_info->f_inner_) {
- VP8VFilter16i(y_dst, y_bps, limit, ilevel, hev_thresh);
- VP8VFilter8i(u_dst, v_dst, uv_bps, limit, ilevel, hev_thresh);
- }
- }
-}
-
-// Filter the decoded macroblock row (if needed)
-static void FilterRow(const VP8Decoder* const dec) {
- int mb_x;
- const int mb_y = dec->thread_ctx_.mb_y_;
- assert(dec->thread_ctx_.filter_row_);
- for (mb_x = dec->tl_mb_x_; mb_x < dec->br_mb_x_; ++mb_x) {
- DoFilter(dec, mb_x, mb_y);
- }
-}
-
-//------------------------------------------------------------------------------
-// Precompute the filtering strength for each segment and each i4x4/i16x16 mode.
-
-static void PrecomputeFilterStrengths(VP8Decoder* const dec) {
- if (dec->filter_type_ > 0) {
- int s;
- const VP8FilterHeader* const hdr = &dec->filter_hdr_;
- for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
- int i4x4;
- // First, compute the initial level
- int base_level;
- if (dec->segment_hdr_.use_segment_) {
- base_level = dec->segment_hdr_.filter_strength_[s];
- if (!dec->segment_hdr_.absolute_delta_) {
- base_level += hdr->level_;
- }
- } else {
- base_level = hdr->level_;
- }
- for (i4x4 = 0; i4x4 <= 1; ++i4x4) {
- VP8FInfo* const info = &dec->fstrengths_[s][i4x4];
- int level = base_level;
- if (hdr->use_lf_delta_) {
- level += hdr->ref_lf_delta_[0];
- if (i4x4) {
- level += hdr->mode_lf_delta_[0];
- }
- }
- level = (level < 0) ? 0 : (level > 63) ? 63 : level;
- if (level > 0) {
- int ilevel = level;
- if (hdr->sharpness_ > 0) {
- if (hdr->sharpness_ > 4) {
- ilevel >>= 2;
- } else {
- ilevel >>= 1;
- }
- if (ilevel > 9 - hdr->sharpness_) {
- ilevel = 9 - hdr->sharpness_;
- }
- }
- if (ilevel < 1) ilevel = 1;
- info->f_ilevel_ = ilevel;
- info->f_limit_ = 2 * level + ilevel;
- info->hev_thresh_ = (level >= 40) ? 2 : (level >= 15) ? 1 : 0;
- } else {
- info->f_limit_ = 0; // no filtering
- }
- info->f_inner_ = i4x4;
- }
- }
- }
-}
-
-//------------------------------------------------------------------------------
-// Dithering
-
-// minimal amp that will provide a non-zero dithering effect
-#define MIN_DITHER_AMP 4
-
-#define DITHER_AMP_TAB_SIZE 12
-static const int kQuantToDitherAmp[DITHER_AMP_TAB_SIZE] = {
- // roughly, it's dqm->uv_mat_[1]
- 8, 7, 6, 4, 4, 2, 2, 2, 1, 1, 1, 1
-};
-
-void VP8InitDithering(const WebPDecoderOptions* const options,
- VP8Decoder* const dec) {
- assert(dec != NULL);
- if (options != NULL) {
- const int d = options->dithering_strength;
- const int max_amp = (1 << VP8_RANDOM_DITHER_FIX) - 1;
- const int f = (d < 0) ? 0 : (d > 100) ? max_amp : (d * max_amp / 100);
- if (f > 0) {
- int s;
- int all_amp = 0;
- for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
- VP8QuantMatrix* const dqm = &dec->dqm_[s];
- if (dqm->uv_quant_ < DITHER_AMP_TAB_SIZE) {
- // TODO(skal): should we specially dither more for uv_quant_ < 0?
- const int idx = (dqm->uv_quant_ < 0) ? 0 : dqm->uv_quant_;
- dqm->dither_ = (f * kQuantToDitherAmp[idx]) >> 3;
- }
- all_amp |= dqm->dither_;
- }
- if (all_amp != 0) {
- VP8InitRandom(&dec->dithering_rg_, 1.0f);
- dec->dither_ = 1;
- }
- }
- // potentially allow alpha dithering
- dec->alpha_dithering_ = options->alpha_dithering_strength;
- if (dec->alpha_dithering_ > 100) {
- dec->alpha_dithering_ = 100;
- } else if (dec->alpha_dithering_ < 0) {
- dec->alpha_dithering_ = 0;
- }
- }
-}
-
-// Convert to range: [-2,2] for dither=50, [-4,4] for dither=100
-static void Dither8x8(VP8Random* const rg, uint8_t* dst, int bps, int amp) {
- uint8_t dither[64];
- int i;
- for (i = 0; i < 8 * 8; ++i) {
- dither[i] = VP8RandomBits2(rg, VP8_DITHER_AMP_BITS + 1, amp);
- }
- VP8DitherCombine8x8(dither, dst, bps);
-}
-
-static void DitherRow(VP8Decoder* const dec) {
- int mb_x;
- assert(dec->dither_);
- for (mb_x = dec->tl_mb_x_; mb_x < dec->br_mb_x_; ++mb_x) {
- const VP8ThreadContext* const ctx = &dec->thread_ctx_;
- const VP8MBData* const data = ctx->mb_data_ + mb_x;
- const int cache_id = ctx->id_;
- const int uv_bps = dec->cache_uv_stride_;
- if (data->dither_ >= MIN_DITHER_AMP) {
- uint8_t* const u_dst = dec->cache_u_ + cache_id * 8 * uv_bps + mb_x * 8;
- uint8_t* const v_dst = dec->cache_v_ + cache_id * 8 * uv_bps + mb_x * 8;
- Dither8x8(&dec->dithering_rg_, u_dst, uv_bps, data->dither_);
- Dither8x8(&dec->dithering_rg_, v_dst, uv_bps, data->dither_);
- }
- }
-}
-
-//------------------------------------------------------------------------------
-// This function is called after a row of macroblocks is finished decoding.
-// It also takes into account the following restrictions:
-// * In case of in-loop filtering, we must hold off sending some of the bottom
-// pixels as they are yet unfiltered. They will be when the next macroblock
-// row is decoded. Meanwhile, we must preserve them by rotating them in the
-// cache area. This doesn't hold for the very bottom row of the uncropped
-// picture of course.
-// * we must clip the remaining pixels against the cropping area. The VP8Io
-// struct must have the following fields set correctly before calling put():
-
-#define MACROBLOCK_VPOS(mb_y) ((mb_y) * 16) // vertical position of a MB
-
-// Finalize and transmit a complete row. Return false in case of user-abort.
-static int FinishRow(VP8Decoder* const dec, VP8Io* const io) {
- int ok = 1;
- const VP8ThreadContext* const ctx = &dec->thread_ctx_;
- const int cache_id = ctx->id_;
- const int extra_y_rows = kFilterExtraRows[dec->filter_type_];
- const int ysize = extra_y_rows * dec->cache_y_stride_;
- const int uvsize = (extra_y_rows / 2) * dec->cache_uv_stride_;
- const int y_offset = cache_id * 16 * dec->cache_y_stride_;
- const int uv_offset = cache_id * 8 * dec->cache_uv_stride_;
- uint8_t* const ydst = dec->cache_y_ - ysize + y_offset;
- uint8_t* const udst = dec->cache_u_ - uvsize + uv_offset;
- uint8_t* const vdst = dec->cache_v_ - uvsize + uv_offset;
- const int mb_y = ctx->mb_y_;
- const int is_first_row = (mb_y == 0);
- const int is_last_row = (mb_y >= dec->br_mb_y_ - 1);
-
- if (dec->mt_method_ == 2) {
- ReconstructRow(dec, ctx);
- }
-
- if (ctx->filter_row_) {
- FilterRow(dec);
- }
-
- if (dec->dither_) {
- DitherRow(dec);
- }
-
- if (io->put != NULL) {
- int y_start = MACROBLOCK_VPOS(mb_y);
- int y_end = MACROBLOCK_VPOS(mb_y + 1);
- if (!is_first_row) {
- y_start -= extra_y_rows;
- io->y = ydst;
- io->u = udst;
- io->v = vdst;
- } else {
- io->y = dec->cache_y_ + y_offset;
- io->u = dec->cache_u_ + uv_offset;
- io->v = dec->cache_v_ + uv_offset;
- }
-
- if (!is_last_row) {
- y_end -= extra_y_rows;
- }
- if (y_end > io->crop_bottom) {
- y_end = io->crop_bottom; // make sure we don't overflow on last row.
- }
- io->a = NULL;
- if (dec->alpha_data_ != NULL && y_start < y_end) {
- // TODO(skal): testing presence of alpha with dec->alpha_data_ is not a
- // good idea.
- io->a = VP8DecompressAlphaRows(dec, io, y_start, y_end - y_start);
- if (io->a == NULL) {
- return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
- "Could not decode alpha data.");
- }
- }
- if (y_start < io->crop_top) {
- const int delta_y = io->crop_top - y_start;
- y_start = io->crop_top;
- assert(!(delta_y & 1));
- io->y += dec->cache_y_stride_ * delta_y;
- io->u += dec->cache_uv_stride_ * (delta_y >> 1);
- io->v += dec->cache_uv_stride_ * (delta_y >> 1);
- if (io->a != NULL) {
- io->a += io->width * delta_y;
- }
- }
- if (y_start < y_end) {
- io->y += io->crop_left;
- io->u += io->crop_left >> 1;
- io->v += io->crop_left >> 1;
- if (io->a != NULL) {
- io->a += io->crop_left;
- }
- io->mb_y = y_start - io->crop_top;
- io->mb_w = io->crop_right - io->crop_left;
- io->mb_h = y_end - y_start;
- ok = io->put(io);
- }
- }
- // rotate top samples if needed
- if (cache_id + 1 == dec->num_caches_) {
- if (!is_last_row) {
- memcpy(dec->cache_y_ - ysize, ydst + 16 * dec->cache_y_stride_, ysize);
- memcpy(dec->cache_u_ - uvsize, udst + 8 * dec->cache_uv_stride_, uvsize);
- memcpy(dec->cache_v_ - uvsize, vdst + 8 * dec->cache_uv_stride_, uvsize);
- }
- }
-
- return ok;
-}
-
-#undef MACROBLOCK_VPOS
-
-//------------------------------------------------------------------------------
-
-int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io) {
- int ok = 1;
- VP8ThreadContext* const ctx = &dec->thread_ctx_;
- const int filter_row =
- (dec->filter_type_ > 0) &&
- (dec->mb_y_ >= dec->tl_mb_y_) && (dec->mb_y_ <= dec->br_mb_y_);
- if (dec->mt_method_ == 0) {
- // ctx->id_ and ctx->f_info_ are already set
- ctx->mb_y_ = dec->mb_y_;
- ctx->filter_row_ = filter_row;
- ReconstructRow(dec, ctx);
- ok = FinishRow(dec, io);
- } else {
- WebPWorker* const worker = &dec->worker_;
- // Finish previous job *before* updating context
- ok &= WebPGetWorkerInterface()->Sync(worker);
- assert(worker->status_ == OK);
- if (ok) { // spawn a new deblocking/output job
- ctx->io_ = *io;
- ctx->id_ = dec->cache_id_;
- ctx->mb_y_ = dec->mb_y_;
- ctx->filter_row_ = filter_row;
- if (dec->mt_method_ == 2) { // swap macroblock data
- VP8MBData* const tmp = ctx->mb_data_;
- ctx->mb_data_ = dec->mb_data_;
- dec->mb_data_ = tmp;
- } else {
- // perform reconstruction directly in main thread
- ReconstructRow(dec, ctx);
- }
- if (filter_row) { // swap filter info
- VP8FInfo* const tmp = ctx->f_info_;
- ctx->f_info_ = dec->f_info_;
- dec->f_info_ = tmp;
- }
- // (reconstruct)+filter in parallel
- WebPGetWorkerInterface()->Launch(worker);
- if (++dec->cache_id_ == dec->num_caches_) {
- dec->cache_id_ = 0;
- }
- }
- }
- return ok;
-}
-
-//------------------------------------------------------------------------------
-// Finish setting up the decoding parameter once user's setup() is called.
-
-VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) {
- // Call setup() first. This may trigger additional decoding features on 'io'.
- // Note: Afterward, we must call teardown() no matter what.
- if (io->setup != NULL && !io->setup(io)) {
- VP8SetError(dec, VP8_STATUS_USER_ABORT, "Frame setup failed");
- return dec->status_;
- }
-
- // Disable filtering per user request
- if (io->bypass_filtering) {
- dec->filter_type_ = 0;
- }
- // TODO(skal): filter type / strength / sharpness forcing
-
- // Define the area where we can skip in-loop filtering, in case of cropping.
- //
- // 'Simple' filter reads two luma samples outside of the macroblock
- // and filters one. It doesn't filter the chroma samples. Hence, we can
- // avoid doing the in-loop filtering before crop_top/crop_left position.
- // For the 'Complex' filter, 3 samples are read and up to 3 are filtered.
- // Means: there's a dependency chain that goes all the way up to the
- // top-left corner of the picture (MB #0). We must filter all the previous
- // macroblocks.
- // TODO(skal): add an 'approximate_decoding' option, that won't produce
- // a 1:1 bit-exactness for complex filtering?
- {
- const int extra_pixels = kFilterExtraRows[dec->filter_type_];
- if (dec->filter_type_ == 2) {
- // For complex filter, we need to preserve the dependency chain.
- dec->tl_mb_x_ = 0;
- dec->tl_mb_y_ = 0;
- } else {
- // For simple filter, we can filter only the cropped region.
- // We include 'extra_pixels' on the other side of the boundary, since
- // vertical or horizontal filtering of the previous macroblock can
- // modify some abutting pixels.
- dec->tl_mb_x_ = (io->crop_left - extra_pixels) >> 4;
- dec->tl_mb_y_ = (io->crop_top - extra_pixels) >> 4;
- if (dec->tl_mb_x_ < 0) dec->tl_mb_x_ = 0;
- if (dec->tl_mb_y_ < 0) dec->tl_mb_y_ = 0;
- }
- // We need some 'extra' pixels on the right/bottom.
- dec->br_mb_y_ = (io->crop_bottom + 15 + extra_pixels) >> 4;
- dec->br_mb_x_ = (io->crop_right + 15 + extra_pixels) >> 4;
- if (dec->br_mb_x_ > dec->mb_w_) {
- dec->br_mb_x_ = dec->mb_w_;
- }
- if (dec->br_mb_y_ > dec->mb_h_) {
- dec->br_mb_y_ = dec->mb_h_;
- }
- }
- PrecomputeFilterStrengths(dec);
- return VP8_STATUS_OK;
-}
-
-int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io) {
- int ok = 1;
- if (dec->mt_method_ > 0) {
- ok = WebPGetWorkerInterface()->Sync(&dec->worker_);
- }
-
- if (io->teardown != NULL) {
- io->teardown(io);
- }
- return ok;
-}
-
-//------------------------------------------------------------------------------
-// For multi-threaded decoding we need to use 3 rows of 16 pixels as delay line.
-//
-// Reason is: the deblocking filter cannot deblock the bottom horizontal edges
-// immediately, and needs to wait for first few rows of the next macroblock to
-// be decoded. Hence, deblocking is lagging behind by 4 or 8 pixels (depending
-// on strength).
-// With two threads, the vertical positions of the rows being decoded are:
-// Decode: [ 0..15][16..31][32..47][48..63][64..79][...
-// Deblock: [ 0..11][12..27][28..43][44..59][...
-// If we use two threads and two caches of 16 pixels, the sequence would be:
-// Decode: [ 0..15][16..31][ 0..15!!][16..31][ 0..15][...
-// Deblock: [ 0..11][12..27!!][-4..11][12..27][...
-// The problem occurs during row [12..15!!] that both the decoding and
-// deblocking threads are writing simultaneously.
-// With 3 cache lines, one get a safe write pattern:
-// Decode: [ 0..15][16..31][32..47][ 0..15][16..31][32..47][0..
-// Deblock: [ 0..11][12..27][28..43][-4..11][12..27][28...
-// Note that multi-threaded output _without_ deblocking can make use of two
-// cache lines of 16 pixels only, since there's no lagging behind. The decoding
-// and output process have non-concurrent writing:
-// Decode: [ 0..15][16..31][ 0..15][16..31][...
-// io->put: [ 0..15][16..31][ 0..15][...
-
-#define MT_CACHE_LINES 3
-#define ST_CACHE_LINES 1 // 1 cache row only for single-threaded case
-
-// Initialize multi/single-thread worker
-static int InitThreadContext(VP8Decoder* const dec) {
- dec->cache_id_ = 0;
- if (dec->mt_method_ > 0) {
- WebPWorker* const worker = &dec->worker_;
- if (!WebPGetWorkerInterface()->Reset(worker)) {
- return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
- "thread initialization failed.");
- }
- worker->data1 = dec;
- worker->data2 = (void*)&dec->thread_ctx_.io_;
- worker->hook = (WebPWorkerHook)FinishRow;
- dec->num_caches_ =
- (dec->filter_type_ > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1;
- } else {
- dec->num_caches_ = ST_CACHE_LINES;
- }
- return 1;
-}
-
-int VP8GetThreadMethod(const WebPDecoderOptions* const options,
- const WebPHeaderStructure* const headers,
- int width, int height) {
- if (options == NULL || options->use_threads == 0) {
- return 0;
- }
- (void)headers;
- (void)width;
- (void)height;
- assert(headers == NULL || !headers->is_lossless);
-#if defined(WEBP_USE_THREAD)
- if (width < MIN_WIDTH_FOR_THREADS) return 0;
- // TODO(skal): tune the heuristic further
-#if 0
- if (height < 2 * width) return 2;
-#endif
- return 2;
-#else // !WEBP_USE_THREAD
- return 0;
-#endif
-}
-
-#undef MT_CACHE_LINES
-#undef ST_CACHE_LINES
-
-//------------------------------------------------------------------------------
-// Memory setup
-
-static int AllocateMemory(VP8Decoder* const dec) {
- const int num_caches = dec->num_caches_;
- const int mb_w = dec->mb_w_;
- // Note: we use 'size_t' when there's no overflow risk, uint64_t otherwise.
- const size_t intra_pred_mode_size = 4 * mb_w * sizeof(uint8_t);
- const size_t top_size = sizeof(VP8TopSamples) * mb_w;
- const size_t mb_info_size = (mb_w + 1) * sizeof(VP8MB);
- const size_t f_info_size =
- (dec->filter_type_ > 0) ?
- mb_w * (dec->mt_method_ > 0 ? 2 : 1) * sizeof(VP8FInfo)
- : 0;
- const size_t yuv_size = YUV_SIZE * sizeof(*dec->yuv_b_);
- const size_t mb_data_size =
- (dec->mt_method_ == 2 ? 2 : 1) * mb_w * sizeof(*dec->mb_data_);
- const size_t cache_height = (16 * num_caches
- + kFilterExtraRows[dec->filter_type_]) * 3 / 2;
- const size_t cache_size = top_size * cache_height;
- // alpha_size is the only one that scales as width x height.
- const uint64_t alpha_size = (dec->alpha_data_ != NULL) ?
- (uint64_t)dec->pic_hdr_.width_ * dec->pic_hdr_.height_ : 0ULL;
- const uint64_t needed = (uint64_t)intra_pred_mode_size
- + top_size + mb_info_size + f_info_size
- + yuv_size + mb_data_size
- + cache_size + alpha_size + WEBP_ALIGN_CST;
- uint8_t* mem;
-
- if (needed != (size_t)needed) return 0; // check for overflow
- if (needed > dec->mem_size_) {
- WebPSafeFree(dec->mem_);
- dec->mem_size_ = 0;
- dec->mem_ = WebPSafeMalloc(needed, sizeof(uint8_t));
- if (dec->mem_ == NULL) {
- return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
- "no memory during frame initialization.");
- }
- // down-cast is ok, thanks to WebPSafeMalloc() above.
- dec->mem_size_ = (size_t)needed;
- }
-
- mem = (uint8_t*)dec->mem_;
- dec->intra_t_ = (uint8_t*)mem;
- mem += intra_pred_mode_size;
-
- dec->yuv_t_ = (VP8TopSamples*)mem;
- mem += top_size;
-
- dec->mb_info_ = ((VP8MB*)mem) + 1;
- mem += mb_info_size;
-
- dec->f_info_ = f_info_size ? (VP8FInfo*)mem : NULL;
- mem += f_info_size;
- dec->thread_ctx_.id_ = 0;
- dec->thread_ctx_.f_info_ = dec->f_info_;
- if (dec->mt_method_ > 0) {
- // secondary cache line. The deblocking process need to make use of the
- // filtering strength from previous macroblock row, while the new ones
- // are being decoded in parallel. We'll just swap the pointers.
- dec->thread_ctx_.f_info_ += mb_w;
- }
-
- mem = (uint8_t*)WEBP_ALIGN(mem);
- assert((yuv_size & WEBP_ALIGN_CST) == 0);
- dec->yuv_b_ = (uint8_t*)mem;
- mem += yuv_size;
-
- dec->mb_data_ = (VP8MBData*)mem;
- dec->thread_ctx_.mb_data_ = (VP8MBData*)mem;
- if (dec->mt_method_ == 2) {
- dec->thread_ctx_.mb_data_ += mb_w;
- }
- mem += mb_data_size;
-
- dec->cache_y_stride_ = 16 * mb_w;
- dec->cache_uv_stride_ = 8 * mb_w;
- {
- const int extra_rows = kFilterExtraRows[dec->filter_type_];
- const int extra_y = extra_rows * dec->cache_y_stride_;
- const int extra_uv = (extra_rows / 2) * dec->cache_uv_stride_;
- dec->cache_y_ = ((uint8_t*)mem) + extra_y;
- dec->cache_u_ = dec->cache_y_
- + 16 * num_caches * dec->cache_y_stride_ + extra_uv;
- dec->cache_v_ = dec->cache_u_
- + 8 * num_caches * dec->cache_uv_stride_ + extra_uv;
- dec->cache_id_ = 0;
- }
- mem += cache_size;
-
- // alpha plane
- dec->alpha_plane_ = alpha_size ? (uint8_t*)mem : NULL;
- mem += alpha_size;
- assert(mem <= (uint8_t*)dec->mem_ + dec->mem_size_);
-
- // note: left/top-info is initialized once for all.
- memset(dec->mb_info_ - 1, 0, mb_info_size);
- VP8InitScanline(dec); // initialize left too.
-
- // initialize top
- memset(dec->intra_t_, B_DC_PRED, intra_pred_mode_size);
-
- return 1;
-}
-
-static void InitIo(VP8Decoder* const dec, VP8Io* io) {
- // prepare 'io'
- io->mb_y = 0;
- io->y = dec->cache_y_;
- io->u = dec->cache_u_;
- io->v = dec->cache_v_;
- io->y_stride = dec->cache_y_stride_;
- io->uv_stride = dec->cache_uv_stride_;
- io->a = NULL;
-}
-
-int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io) {
- if (!InitThreadContext(dec)) return 0; // call first. Sets dec->num_caches_.
- if (!AllocateMemory(dec)) return 0;
- InitIo(dec, io);
- VP8DspInit(); // Init critical function pointers and look-up tables.
- return 1;
-}
-
-//------------------------------------------------------------------------------
diff --git a/thirdparty/libwebp/dec/idec_dec.c b/thirdparty/libwebp/dec/idec_dec.c
deleted file mode 100644
index 78fb2e7186..0000000000
--- a/thirdparty/libwebp/dec/idec_dec.c
+++ /dev/null
@@ -1,892 +0,0 @@
-// 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.
-// -----------------------------------------------------------------------------
-//
-// Incremental decoding
-//
-// Author: somnath@google.com (Somnath Banerjee)
-
-#include <assert.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "./alphai_dec.h"
-#include "./webpi_dec.h"
-#include "./vp8i_dec.h"
-#include "../utils/utils.h"
-
-// In append mode, buffer allocations increase as multiples of this value.
-// Needs to be a power of 2.
-#define CHUNK_SIZE 4096
-#define MAX_MB_SIZE 4096
-
-//------------------------------------------------------------------------------
-// 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.
-// 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_VP8_PARTS0,
- STATE_VP8_DATA,
- STATE_VP8L_HEADER,
- STATE_VP8L_DATA,
- STATE_DONE,
- STATE_ERROR
-} 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
- size_t start_; // start location of the data to be decoded
- size_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
- WebPDecParams params_; // Params to store output info
- int is_lossless_; // for down-casting 'dec_'.
- void* dec_; // either a VP8Decoder or a VP8LDecoder instance
- VP8Io io_;
-
- MemBuffer mem_; // input memory buffer.
- WebPDecBuffer output_; // output buffer (when no external one is supplied,
- // or if the external one has slow-memory)
- WebPDecBuffer* final_output_; // Slow-memory output to copy to eventually.
- 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_;
- VP8BitReader token_br_;
-} MBContext;
-
-//------------------------------------------------------------------------------
-// MemBuffer: incoming data handling
-
-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_;
- // note: for VP8, setting up idec->io_ is only really needed at the beginning
- // of the decoding, till partition #0 is complete.
- idec->io_.data = new_base;
- idec->io_.data_size = MemDataSize(mem);
-
- if (idec->dec_ != NULL) {
- if (!idec->is_lossless_) {
- VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
- const uint32_t last_part = dec->num_parts_minus_one_;
- if (offset != 0) {
- uint32_t p;
- for (p = 0; p <= last_part; ++p) {
- 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) {
- VP8RemapBitReader(&dec->br_, offset);
- }
- }
- {
- const uint8_t* const last_start = dec->parts_[last_part].buf_;
- VP8BitReaderSetBuffer(&dec->parts_[last_part], last_start,
- mem->buf_ + mem->end_ - last_start);
- }
- 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));
- }
- }
-}
-
-// 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) {
- 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;
- assert(mem->mode_ == MEM_MODE_APPEND);
- if (data_size > MAX_CHUNK_PAYLOAD) {
- // security safeguard: trying to allocate more than what the format
- // allows for a chunk should be considered a smoke smell.
- return 0;
- }
-
- 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 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 =
- (uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf));
- if (new_buf == NULL) return 0;
- memcpy(new_buf, old_base, current_size);
- WebPSafeFree(mem->buf_);
- mem->buf_ = new_buf;
- mem->buf_size_ = (size_t)extra_size;
- mem->start_ = new_mem_start;
- mem->end_ = current_size;
- }
-
- memcpy(mem->buf_ + mem->end_, data, data_size);
- mem->end_ += data_size;
- assert(mem->end_ <= mem->buf_size_);
-
- DoRemap(idec, mem->buf_ + mem->start_ - old_start);
- 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_;
- assert(mem->mode_ == MEM_MODE_MAP);
-
- if (data_size < mem->buf_size_) return 0; // can't remap to a shorter buffer!
-
- mem->buf_ = (uint8_t*)data;
- mem->end_ = mem->buf_size_ = data_size;
-
- DoRemap(idec, mem->buf_ + mem->start_ - old_start);
- return 1;
-}
-
-static void InitMemBuffer(MemBuffer* const mem) {
- mem->mode_ = MEM_MODE_NONE;
- mem->buf_ = NULL;
- mem->buf_size_ = 0;
- mem->part0_buf_ = NULL;
- mem->part0_size_ = 0;
-}
-
-static void ClearMemBuffer(MemBuffer* const mem) {
- assert(mem);
- if (mem->mode_ == MEM_MODE_APPEND) {
- WebPSafeFree(mem->buf_);
- WebPSafeFree((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;
-}
-
-// To be called last.
-static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) {
- const WebPDecoderOptions* const options = idec->params_.options;
- WebPDecBuffer* const output = idec->params_.output;
-
- idec->state_ = STATE_DONE;
- if (options != NULL && options->flip) {
- const VP8StatusCode status = WebPFlipBuffer(output);
- if (status != VP8_STATUS_OK) return status;
- }
- if (idec->final_output_ != NULL) {
- WebPCopyDecBufferPixels(output, idec->final_output_); // do the slow-copy
- WebPFreeDecBuffer(&idec->output_);
- *output = *idec->final_output_;
- idec->final_output_ = NULL;
- }
- return VP8_STATUS_OK;
-}
-
-//------------------------------------------------------------------------------
-// Macroblock-decoding contexts
-
-static void SaveContext(const VP8Decoder* dec, const VP8BitReader* token_br,
- MBContext* const context) {
- context->left_ = dec->mb_info_[-1];
- context->info_ = dec->mb_info_[dec->mb_x_];
- context->token_br_ = *token_br;
-}
-
-static void RestoreContext(const MBContext* context, VP8Decoder* const dec,
- VP8BitReader* const token_br) {
- dec->mb_info_[-1] = context->left_;
- dec->mb_info_[dec->mb_x_] = context->info_;
- *token_br = context->token_br_;
-}
-
-//------------------------------------------------------------------------------
-
-static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) {
- if (idec->state_ == STATE_VP8_DATA) {
- VP8Io* const io = &idec->io_;
- if (io->teardown != NULL) {
- io->teardown(io);
- }
- }
- idec->state_ = STATE_ERROR;
- return error;
-}
-
-static void ChangeState(WebPIDecoder* const idec, DecState new_state,
- size_t consumed_bytes) {
- MemBuffer* const mem = &idec->mem_;
- idec->state_ = new_state;
- mem->start_ += consumed_bytes;
- assert(mem->start_ <= mem->end_);
- idec->io_.data = mem->buf_ + mem->start_;
- idec->io_.data_size = MemDataSize(mem);
-}
-
-// Headers
-static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) {
- MemBuffer* const mem = &idec->mem_;
- const uint8_t* data = mem->buf_ + mem->start_;
- size_t curr_size = MemDataSize(mem);
- VP8StatusCode status;
- WebPHeaderStructure headers;
-
- 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.
- } else if (status != VP8_STATUS_OK) {
- return IDecError(idec, status);
- }
-
- idec->chunk_size_ = headers.compressed_size;
- idec->is_lossless_ = headers.is_lossless;
- if (!idec->is_lossless_) {
- VP8Decoder* const dec = VP8New();
- if (dec == NULL) {
- return VP8_STATUS_OUT_OF_MEMORY;
- }
- idec->dec_ = dec;
- dec->alpha_data_ = headers.alpha_data;
- dec->alpha_data_size_ = headers.alpha_data_size;
- ChangeState(idec, STATE_VP8_HEADER, headers.offset);
- } else {
- VP8LDecoder* const dec = VP8LNew();
- if (dec == NULL) {
- return VP8_STATUS_OUT_OF_MEMORY;
- }
- idec->dec_ = dec;
- ChangeState(idec, STATE_VP8L_HEADER, headers.offset);
- }
- return VP8_STATUS_OK;
-}
-
-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)) {
- return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
- }
-
- bits = data[0] | (data[1] << 8) | (data[2] << 16);
- idec->mem_.part0_size_ = (bits >> 5) + VP8_FRAME_HEADER_SIZE;
-
- idec->io_.data = data;
- idec->io_.data_size = curr_size;
- idec->state_ = STATE_VP8_PARTS0;
- return VP8_STATUS_OK;
-}
-
-// Partition #0
-static VP8StatusCode CopyParts0Data(WebPIDecoder* const idec) {
- VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
- VP8BitReader* const br = &dec->br_;
- const size_t part_size = br->buf_end_ - br->buf_;
- MemBuffer* const mem = &idec->mem_;
- assert(!idec->is_lossless_);
- assert(mem->part0_buf_ == NULL);
- // 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*)WebPSafeMalloc(1ULL, part_size);
- if (part0_buf == NULL) {
- return VP8_STATUS_OUT_OF_MEMORY;
- }
- memcpy(part0_buf, br->buf_, part_size);
- mem->part0_buf_ = part0_buf;
- VP8BitReaderSetBuffer(br, part0_buf, part_size);
- } else {
- // Else: just keep pointers to the partition #0's data in dec_->br_.
- }
- mem->start_ += part_size;
- return VP8_STATUS_OK;
-}
-
-static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) {
- VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
- VP8Io* const io = &idec->io_;
- const WebPDecParams* const params = &idec->params_;
- WebPDecBuffer* const output = params->output;
-
- // Wait till we have enough data for the whole partition #0
- if (MemDataSize(&idec->mem_) < idec->mem_.part0_size_) {
- return VP8_STATUS_SUSPENDED;
- }
-
- 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);
- }
-
- // Allocate/Verify output buffer now
- dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options,
- output);
- 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);
-
- 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().
- if (VP8EnterCritical(dec, io) != VP8_STATUS_OK) {
- return IDecError(idec, dec->status_);
- }
-
- // Note: past this point, teardown() must always be called
- // in case of error.
- idec->state_ = STATE_VP8_DATA;
- // Allocate memory and prepare everything.
- if (!VP8InitFrame(dec, io)) {
- return IDecError(idec, dec->status_);
- }
- return VP8_STATUS_OK;
-}
-
-// Remaining partitions
-static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
- VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
- VP8Io* const io = &idec->io_;
-
- assert(dec->ready_);
- for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) {
- 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_minus_one_];
- MBContext context;
- SaveContext(dec, token_br, &context);
- if (!VP8DecodeMB(dec, token_br)) {
- // We shouldn't fail when MAX_MB data was available
- if (dec->num_parts_minus_one_ == 0 &&
- 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
- if (dec->num_parts_minus_one_ == 0) {
- 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);
- }
- }
- // Synchronize the thread and check for errors.
- if (!VP8ExitCritical(dec, io)) {
- return IDecError(idec, VP8_STATUS_USER_ABORT);
- }
- dec->ready_ = 0;
- return FinishDecoding(idec);
-}
-
-static VP8StatusCode ErrorStatusLossless(WebPIDecoder* const idec,
- VP8StatusCode status) {
- if (status == VP8_STATUS_SUSPENDED || status == VP8_STATUS_NOT_ENOUGH_DATA) {
- return VP8_STATUS_SUSPENDED;
- }
- return IDecError(idec, status);
-}
-
-static VP8StatusCode DecodeVP8LHeader(WebPIDecoder* const idec) {
- VP8Io* const io = &idec->io_;
- VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_;
- const WebPDecParams* const params = &idec->params_;
- WebPDecBuffer* const output = params->output;
- size_t curr_size = MemDataSize(&idec->mem_);
- assert(idec->is_lossless_);
-
- // Wait until there's enough data for decoding header.
- if (curr_size < (idec->chunk_size_ >> 3)) {
- dec->status_ = VP8_STATUS_SUSPENDED;
- return ErrorStatusLossless(idec, dec->status_);
- }
-
- if (!VP8LDecodeHeader(dec, io)) {
- if (dec->status_ == VP8_STATUS_BITSTREAM_ERROR &&
- curr_size < idec->chunk_size_) {
- dec->status_ = VP8_STATUS_SUSPENDED;
- }
- return ErrorStatusLossless(idec, dec->status_);
- }
- // Allocate/verify output buffer now.
- dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options,
- output);
- if (dec->status_ != VP8_STATUS_OK) {
- return IDecError(idec, dec->status_);
- }
-
- idec->state_ = STATE_VP8L_DATA;
- return VP8_STATUS_OK;
-}
-
-static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) {
- VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_;
- const size_t curr_size = MemDataSize(&idec->mem_);
- assert(idec->is_lossless_);
-
- // Switch to incremental decoding if we don't have all the bytes available.
- dec->incremental_ = (curr_size < idec->chunk_size_);
-
- if (!VP8LDecodeImage(dec)) {
- return ErrorStatusLossless(idec, dec->status_);
- }
- assert(dec->status_ == VP8_STATUS_OK || dec->status_ == VP8_STATUS_SUSPENDED);
- return (dec->status_ == VP8_STATUS_SUSPENDED) ? dec->status_
- : FinishDecoding(idec);
-}
-
- // Main decoding loop
-static VP8StatusCode IDecode(WebPIDecoder* idec) {
- VP8StatusCode status = VP8_STATUS_SUSPENDED;
-
- 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_HEADER) {
- status = DecodeVP8FrameHeader(idec);
- }
- if (idec->state_ == STATE_VP8_PARTS0) {
- status = DecodePartition0(idec);
- }
- if (idec->state_ == STATE_VP8_DATA) {
- status = DecodeRemaining(idec);
- }
- if (idec->state_ == STATE_VP8L_HEADER) {
- status = DecodeVP8LHeader(idec);
- }
- if (idec->state_ == STATE_VP8L_DATA) {
- status = DecodeVP8LData(idec);
- }
- return status;
-}
-
-//------------------------------------------------------------------------------
-// Internal constructor
-
-static WebPIDecoder* NewDecoder(WebPDecBuffer* const output_buffer,
- const WebPBitstreamFeatures* const features) {
- WebPIDecoder* idec = (WebPIDecoder*)WebPSafeCalloc(1ULL, sizeof(*idec));
- if (idec == NULL) {
- return NULL;
- }
-
- idec->state_ = STATE_WEBP_HEADER;
- idec->chunk_size_ = 0;
-
- idec->last_mb_y_ = -1;
-
- InitMemBuffer(&idec->mem_);
- WebPInitDecBuffer(&idec->output_);
- VP8InitIo(&idec->io_);
-
- WebPResetDecParams(&idec->params_);
- if (output_buffer == NULL || WebPAvoidSlowMemory(output_buffer, features)) {
- idec->params_.output = &idec->output_;
- idec->final_output_ = output_buffer;
- if (output_buffer != NULL) {
- idec->params_.output->colorspace = output_buffer->colorspace;
- }
- } else {
- idec->params_.output = output_buffer;
- idec->final_output_ = NULL;
- }
- WebPInitCustomIo(&idec->params_, &idec->io_); // Plug the I/O functions.
-
- return idec;
-}
-
-//------------------------------------------------------------------------------
-// Public functions
-
-WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
- return NewDecoder(output_buffer, NULL);
-}
-
-WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size,
- WebPDecoderConfig* config) {
- WebPIDecoder* idec;
- WebPBitstreamFeatures tmp_features;
- WebPBitstreamFeatures* const features =
- (config == NULL) ? &tmp_features : &config->input;
- memset(&tmp_features, 0, sizeof(tmp_features));
-
- // Parse the bitstream's features, if requested:
- if (data != NULL && data_size > 0) {
- if (WebPGetFeatures(data, data_size, features) != VP8_STATUS_OK) {
- return NULL;
- }
- }
-
- // Create an instance of the incremental decoder
- idec = (config != NULL) ? NewDecoder(&config->output, features)
- : NewDecoder(NULL, features);
- if (idec == NULL) {
- return NULL;
- }
- // Finish initialization
- if (config != NULL) {
- idec->params_.options = &config->options;
- }
- return idec;
-}
-
-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_);
- } else {
- VP8LDelete((VP8LDecoder*)idec->dec_);
- }
- }
- ClearMemBuffer(&idec->mem_);
- WebPFreeDecBuffer(&idec->output_);
- WebPSafeFree(idec);
-}
-
-//------------------------------------------------------------------------------
-// Wrapper toward WebPINewDecoder
-
-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) ? 1 : 0;
- WebPIDecoder* idec;
-
- if (mode >= MODE_YUV) return NULL;
- if (is_external_memory == 0) { // 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_.u.RGBA.rgba = output_buffer;
- idec->output_.u.RGBA.stride = output_stride;
- idec->output_.u.RGBA.size = output_buffer_size;
- return idec;
-}
-
-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) ? 1 : 0;
- WebPIDecoder* idec;
- WEBP_CSP_MODE colorspace;
-
- if (is_external_memory == 0) { // 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);
- if (idec == NULL) return NULL;
-
- idec->output_.colorspace = colorspace;
- idec->output_.is_external_memory = is_external_memory;
- idec->output_.u.YUVA.y = luma;
- idec->output_.u.YUVA.y_stride = luma_stride;
- idec->output_.u.YUVA.y_size = luma_size;
- idec->output_.u.YUVA.u = u;
- idec->output_.u.YUVA.u_stride = u_stride;
- idec->output_.u.YUVA.u_size = u_size;
- idec->output_.u.YUVA.v = v;
- idec->output_.u.YUVA.v_stride = v_stride;
- idec->output_.u.YUVA.v_size = v_size;
- idec->output_.u.YUVA.a = a;
- idec->output_.u.YUVA.a_stride = a_stride;
- idec->output_.u.YUVA.a_size = a_size;
- return idec;
-}
-
-WebPIDecoder* WebPINewYUV(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) {
- return WebPINewYUVA(luma, luma_size, luma_stride,
- u, u_size, u_stride,
- v, v_size, v_stride,
- NULL, 0, 0);
-}
-
-//------------------------------------------------------------------------------
-
-static VP8StatusCode IDecCheckStatus(const WebPIDecoder* const idec) {
- assert(idec);
- 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* idec,
- const uint8_t* data, size_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* idec,
- const uint8_t* data, size_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);
-}
-
-//------------------------------------------------------------------------------
-
-static const WebPDecBuffer* GetOutputBuffer(const WebPIDecoder* const idec) {
- if (idec == NULL || idec->dec_ == NULL) {
- return NULL;
- }
- if (idec->state_ <= STATE_VP8_PARTS0) {
- return NULL;
- }
- if (idec->final_output_ != NULL) {
- return NULL; // not yet slow-copied
- }
- return idec->params_.output;
-}
-
-const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec,
- int* left, int* top,
- int* width, int* height) {
- const WebPDecBuffer* const src = GetOutputBuffer(idec);
- if (left != NULL) *left = 0;
- if (top != NULL) *top = 0;
- if (src != NULL) {
- if (width != NULL) *width = src->width;
- if (height != NULL) *height = idec->params_.last_y;
- } else {
- if (width != NULL) *width = 0;
- if (height != NULL) *height = 0;
- }
- return src;
-}
-
-uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y,
- int* width, int* height, int* stride) {
- const WebPDecBuffer* const src = GetOutputBuffer(idec);
- if (src == NULL) return NULL;
- if (src->colorspace >= MODE_YUV) {
- return NULL;
- }
-
- if (last_y != NULL) *last_y = idec->params_.last_y;
- if (width != NULL) *width = src->width;
- if (height != NULL) *height = src->height;
- if (stride != NULL) *stride = src->u.RGBA.stride;
-
- return src->u.RGBA.rgba;
-}
-
-uint8_t* WebPIDecGetYUVA(const WebPIDecoder* idec, int* last_y,
- uint8_t** u, uint8_t** v, uint8_t** a,
- int* width, int* height,
- int* stride, int* uv_stride, int* a_stride) {
- const WebPDecBuffer* const src = GetOutputBuffer(idec);
- if (src == NULL) return NULL;
- if (src->colorspace < MODE_YUV) {
- return NULL;
- }
-
- if (last_y != NULL) *last_y = idec->params_.last_y;
- if (u != NULL) *u = src->u.YUVA.u;
- if (v != NULL) *v = src->u.YUVA.v;
- if (a != NULL) *a = src->u.YUVA.a;
- if (width != NULL) *width = src->width;
- if (height != NULL) *height = src->height;
- if (stride != NULL) *stride = src->u.YUVA.y_stride;
- if (uv_stride != NULL) *uv_stride = src->u.YUVA.u_stride;
- if (a_stride != NULL) *a_stride = src->u.YUVA.a_stride;
-
- return src->u.YUVA.y;
-}
-
-int WebPISetIOHooks(WebPIDecoder* const idec,
- VP8IoPutHook put,
- VP8IoSetupHook setup,
- VP8IoTeardownHook teardown,
- void* user_data) {
- if (idec == NULL || idec->state_ > STATE_WEBP_HEADER) {
- return 0;
- }
-
- idec->io_.put = put;
- idec->io_.setup = setup;
- idec->io_.teardown = teardown;
- idec->io_.opaque = user_data;
-
- return 1;
-}
diff --git a/thirdparty/libwebp/dec/io_dec.c b/thirdparty/libwebp/dec/io_dec.c
deleted file mode 100644
index 8bfab86959..0000000000
--- a/thirdparty/libwebp/dec/io_dec.c
+++ /dev/null
@@ -1,645 +0,0 @@
-// 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.
-// -----------------------------------------------------------------------------
-//
-// functions for sample output.
-//
-// Author: Skal (pascal.massimino@gmail.com)
-
-#include <assert.h>
-#include <stdlib.h>
-#include "../dec/vp8i_dec.h"
-#include "./webpi_dec.h"
-#include "../dsp/dsp.h"
-#include "../dsp/yuv.h"
-#include "../utils/utils.h"
-
-//------------------------------------------------------------------------------
-// Main YUV<->RGB conversion functions
-
-static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) {
- WebPDecBuffer* output = p->output;
- const WebPYUVABuffer* const buf = &output->u.YUVA;
- uint8_t* const y_dst = buf->y + io->mb_y * buf->y_stride;
- uint8_t* const u_dst = buf->u + (io->mb_y >> 1) * buf->u_stride;
- uint8_t* const v_dst = buf->v + (io->mb_y >> 1) * buf->v_stride;
- const int mb_w = io->mb_w;
- const int mb_h = io->mb_h;
- const int uv_w = (mb_w + 1) / 2;
- const int uv_h = (mb_h + 1) / 2;
- int j;
- for (j = 0; j < mb_h; ++j) {
- memcpy(y_dst + j * buf->y_stride, io->y + j * io->y_stride, mb_w);
- }
- for (j = 0; j < uv_h; ++j) {
- memcpy(u_dst + j * buf->u_stride, io->u + j * io->uv_stride, uv_w);
- memcpy(v_dst + j * buf->v_stride, io->v + j * io->uv_stride, uv_w);
- }
- return io->mb_h;
-}
-
-// Point-sampling U/V sampler.
-static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) {
- WebPDecBuffer* const output = p->output;
- WebPRGBABuffer* const buf = &output->u.RGBA;
- uint8_t* const dst = buf->rgba + io->mb_y * buf->stride;
- WebPSamplerProcessPlane(io->y, io->y_stride,
- io->u, io->v, io->uv_stride,
- dst, buf->stride, io->mb_w, io->mb_h,
- WebPSamplers[output->colorspace]);
- return io->mb_h;
-}
-
-//------------------------------------------------------------------------------
-// Fancy upsampling
-
-#ifdef FANCY_UPSAMPLING
-static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) {
- int num_lines_out = io->mb_h; // a priori guess
- const WebPRGBABuffer* const buf = &p->output->u.RGBA;
- uint8_t* dst = buf->rgba + io->mb_y * buf->stride;
- WebPUpsampleLinePairFunc upsample = WebPUpsamplers[p->output->colorspace];
- const uint8_t* cur_y = io->y;
- const uint8_t* cur_u = io->u;
- const uint8_t* cur_v = io->v;
- const uint8_t* top_u = p->tmp_u;
- const uint8_t* top_v = p->tmp_v;
- int y = io->mb_y;
- const int y_end = io->mb_y + io->mb_h;
- const int mb_w = io->mb_w;
- const int uv_w = (mb_w + 1) / 2;
-
- if (y == 0) {
- // First line is special cased. We mirror the u/v samples at boundary.
- upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, mb_w);
- } else {
- // We can finish the left-over line from previous call.
- upsample(p->tmp_y, cur_y, top_u, top_v, cur_u, cur_v,
- dst - buf->stride, dst, mb_w);
- ++num_lines_out;
- }
- // Loop over each output pairs of row.
- for (; y + 2 < y_end; y += 2) {
- top_u = cur_u;
- top_v = cur_v;
- cur_u += io->uv_stride;
- cur_v += io->uv_stride;
- dst += 2 * buf->stride;
- cur_y += 2 * io->y_stride;
- upsample(cur_y - io->y_stride, cur_y,
- top_u, top_v, cur_u, cur_v,
- dst - buf->stride, dst, mb_w);
- }
- // move to last row
- cur_y += io->y_stride;
- if (io->crop_top + y_end < io->crop_bottom) {
- // Save the unfinished samples for next call (as we're not done yet).
- memcpy(p->tmp_y, cur_y, mb_w * sizeof(*p->tmp_y));
- memcpy(p->tmp_u, cur_u, uv_w * sizeof(*p->tmp_u));
- memcpy(p->tmp_v, cur_v, uv_w * sizeof(*p->tmp_v));
- // The fancy upsampler leaves a row unfinished behind
- // (except for the very last row)
- num_lines_out--;
- } else {
- // Process the very last row of even-sized picture
- if (!(y_end & 1)) {
- upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v,
- dst + buf->stride, NULL, mb_w);
- }
- }
- return num_lines_out;
-}
-
-#endif /* FANCY_UPSAMPLING */
-
-//------------------------------------------------------------------------------
-
-static void FillAlphaPlane(uint8_t* dst, int w, int h, int stride) {
- int j;
- for (j = 0; j < h; ++j) {
- memset(dst, 0xff, w * sizeof(*dst));
- dst += stride;
- }
-}
-
-static int EmitAlphaYUV(const VP8Io* const io, WebPDecParams* const p,
- int expected_num_lines_out) {
- const uint8_t* alpha = io->a;
- const WebPYUVABuffer* const buf = &p->output->u.YUVA;
- const int mb_w = io->mb_w;
- const int mb_h = io->mb_h;
- uint8_t* dst = buf->a + io->mb_y * buf->a_stride;
- int j;
- (void)expected_num_lines_out;
- assert(expected_num_lines_out == mb_h);
- if (alpha != NULL) {
- for (j = 0; j < mb_h; ++j) {
- memcpy(dst, alpha, mb_w * sizeof(*dst));
- alpha += io->width;
- dst += buf->a_stride;
- }
- } else if (buf->a != NULL) {
- // the user requested alpha, but there is none, set it to opaque.
- FillAlphaPlane(dst, mb_w, mb_h, buf->a_stride);
- }
- return 0;
-}
-
-static int GetAlphaSourceRow(const VP8Io* const io,
- const uint8_t** alpha, int* const num_rows) {
- int start_y = io->mb_y;
- *num_rows = io->mb_h;
-
- // Compensate for the 1-line delay of the fancy upscaler.
- // This is similar to EmitFancyRGB().
- if (io->fancy_upsampling) {
- if (start_y == 0) {
- // We don't process the last row yet. It'll be done during the next call.
- --*num_rows;
- } else {
- --start_y;
- // Fortunately, *alpha data is persistent, so we can go back
- // one row and finish alpha blending, now that the fancy upscaler
- // completed the YUV->RGB interpolation.
- *alpha -= io->width;
- }
- if (io->crop_top + io->mb_y + io->mb_h == io->crop_bottom) {
- // If it's the very last call, we process all the remaining rows!
- *num_rows = io->crop_bottom - io->crop_top - start_y;
- }
- }
- return start_y;
-}
-
-static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p,
- int expected_num_lines_out) {
- const uint8_t* alpha = io->a;
- if (alpha != NULL) {
- const int mb_w = io->mb_w;
- const WEBP_CSP_MODE colorspace = p->output->colorspace;
- const int alpha_first =
- (colorspace == MODE_ARGB || colorspace == MODE_Argb);
- const WebPRGBABuffer* const buf = &p->output->u.RGBA;
- int num_rows;
- const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
- uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
- uint8_t* const dst = base_rgba + (alpha_first ? 0 : 3);
- const int has_alpha = WebPDispatchAlpha(alpha, io->width, mb_w,
- num_rows, dst, buf->stride);
- (void)expected_num_lines_out;
- assert(expected_num_lines_out == num_rows);
- // has_alpha is true if there's non-trivial alpha to premultiply with.
- if (has_alpha && WebPIsPremultipliedMode(colorspace)) {
- WebPApplyAlphaMultiply(base_rgba, alpha_first,
- mb_w, num_rows, buf->stride);
- }
- }
- return 0;
-}
-
-static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p,
- int expected_num_lines_out) {
- const uint8_t* alpha = io->a;
- if (alpha != NULL) {
- const int mb_w = io->mb_w;
- const WEBP_CSP_MODE colorspace = p->output->colorspace;
- const WebPRGBABuffer* const buf = &p->output->u.RGBA;
- int num_rows;
- const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
- uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
-#ifdef WEBP_SWAP_16BIT_CSP
- uint8_t* alpha_dst = base_rgba;
-#else
- uint8_t* alpha_dst = base_rgba + 1;
-#endif
- uint32_t alpha_mask = 0x0f;
- int i, j;
- for (j = 0; j < num_rows; ++j) {
- for (i = 0; i < mb_w; ++i) {
- // Fill in the alpha value (converted to 4 bits).
- const uint32_t alpha_value = alpha[i] >> 4;
- alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value;
- alpha_mask &= alpha_value;
- }
- alpha += io->width;
- alpha_dst += buf->stride;
- }
- (void)expected_num_lines_out;
- assert(expected_num_lines_out == num_rows);
- if (alpha_mask != 0x0f && WebPIsPremultipliedMode(colorspace)) {
- WebPApplyAlphaMultiply4444(base_rgba, mb_w, num_rows, buf->stride);
- }
- }
- return 0;
-}
-
-//------------------------------------------------------------------------------
-// YUV rescaling (no final RGB conversion needed)
-
-static int Rescale(const uint8_t* src, int src_stride,
- int new_lines, WebPRescaler* const wrk) {
- int num_lines_out = 0;
- while (new_lines > 0) { // import new contributions of source rows.
- const int lines_in = WebPRescalerImport(wrk, new_lines, src, src_stride);
- src += lines_in * src_stride;
- new_lines -= lines_in;
- num_lines_out += WebPRescalerExport(wrk); // emit output row(s)
- }
- return num_lines_out;
-}
-
-static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
- const int mb_h = io->mb_h;
- const int uv_mb_h = (mb_h + 1) >> 1;
- WebPRescaler* const scaler = p->scaler_y;
- int num_lines_out = 0;
- if (WebPIsAlphaMode(p->output->colorspace) && io->a != NULL) {
- // Before rescaling, we premultiply the luma directly into the io->y
- // internal buffer. This is OK since these samples are not used for
- // intra-prediction (the top samples are saved in cache_y_/u_/v_).
- // But we need to cast the const away, though.
- WebPMultRows((uint8_t*)io->y, io->y_stride,
- io->a, io->width, io->mb_w, mb_h, 0);
- }
- num_lines_out = Rescale(io->y, io->y_stride, mb_h, scaler);
- Rescale(io->u, io->uv_stride, uv_mb_h, p->scaler_u);
- Rescale(io->v, io->uv_stride, uv_mb_h, p->scaler_v);
- return num_lines_out;
-}
-
-static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p,
- int expected_num_lines_out) {
- const WebPYUVABuffer* const buf = &p->output->u.YUVA;
- uint8_t* const dst_a = buf->a + p->last_y * buf->a_stride;
- if (io->a != NULL) {
- uint8_t* const dst_y = buf->y + p->last_y * buf->y_stride;
- const int num_lines_out = Rescale(io->a, io->width, io->mb_h, p->scaler_a);
- assert(expected_num_lines_out == num_lines_out);
- if (num_lines_out > 0) { // unmultiply the Y
- WebPMultRows(dst_y, buf->y_stride, dst_a, buf->a_stride,
- p->scaler_a->dst_width, num_lines_out, 1);
- }
- } else if (buf->a != NULL) {
- // the user requested alpha, but there is none, set it to opaque.
- assert(p->last_y + expected_num_lines_out <= io->scaled_height);
- FillAlphaPlane(dst_a, io->scaled_width, expected_num_lines_out,
- buf->a_stride);
- }
- return 0;
-}
-
-static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
- const int has_alpha = WebPIsAlphaMode(p->output->colorspace);
- const WebPYUVABuffer* const buf = &p->output->u.YUVA;
- const int out_width = io->scaled_width;
- const int out_height = io->scaled_height;
- const int uv_out_width = (out_width + 1) >> 1;
- const int uv_out_height = (out_height + 1) >> 1;
- const int uv_in_width = (io->mb_w + 1) >> 1;
- const int uv_in_height = (io->mb_h + 1) >> 1;
- const size_t work_size = 2 * out_width; // scratch memory for luma rescaler
- const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones
- size_t tmp_size, rescaler_size;
- rescaler_t* work;
- WebPRescaler* scalers;
- const int num_rescalers = has_alpha ? 4 : 3;
-
- tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work);
- if (has_alpha) {
- tmp_size += work_size * sizeof(*work);
- }
- rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST;
-
- p->memory = WebPSafeMalloc(1ULL, tmp_size + rescaler_size);
- if (p->memory == NULL) {
- return 0; // memory error
- }
- work = (rescaler_t*)p->memory;
-
- scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + tmp_size);
- p->scaler_y = &scalers[0];
- p->scaler_u = &scalers[1];
- p->scaler_v = &scalers[2];
- p->scaler_a = has_alpha ? &scalers[3] : NULL;
-
- WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
- buf->y, out_width, out_height, buf->y_stride, 1,
- work);
- WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
- buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
- work + work_size);
- WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
- buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
- work + work_size + uv_work_size);
- p->emit = EmitRescaledYUV;
-
- if (has_alpha) {
- WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
- buf->a, out_width, out_height, buf->a_stride, 1,
- work + work_size + 2 * uv_work_size);
- p->emit_alpha = EmitRescaledAlphaYUV;
- WebPInitAlphaProcessing();
- }
- return 1;
-}
-
-//------------------------------------------------------------------------------
-// RGBA rescaling
-
-static int ExportRGB(WebPDecParams* const p, int y_pos) {
- const WebPYUV444Converter convert =
- WebPYUV444Converters[p->output->colorspace];
- const WebPRGBABuffer* const buf = &p->output->u.RGBA;
- uint8_t* dst = buf->rgba + y_pos * buf->stride;
- int num_lines_out = 0;
- // For RGB rescaling, because of the YUV420, current scan position
- // U/V can be +1/-1 line from the Y one. Hence the double test.
- while (WebPRescalerHasPendingOutput(p->scaler_y) &&
- WebPRescalerHasPendingOutput(p->scaler_u)) {
- assert(y_pos + num_lines_out < p->output->height);
- assert(p->scaler_u->y_accum == p->scaler_v->y_accum);
- WebPRescalerExportRow(p->scaler_y);
- WebPRescalerExportRow(p->scaler_u);
- WebPRescalerExportRow(p->scaler_v);
- convert(p->scaler_y->dst, p->scaler_u->dst, p->scaler_v->dst,
- dst, p->scaler_y->dst_width);
- dst += buf->stride;
- ++num_lines_out;
- }
- return num_lines_out;
-}
-
-static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) {
- const int mb_h = io->mb_h;
- const int uv_mb_h = (mb_h + 1) >> 1;
- int j = 0, uv_j = 0;
- int num_lines_out = 0;
- while (j < mb_h) {
- const int y_lines_in =
- WebPRescalerImport(p->scaler_y, mb_h - j,
- io->y + j * io->y_stride, io->y_stride);
- j += y_lines_in;
- if (WebPRescaleNeededLines(p->scaler_u, uv_mb_h - uv_j)) {
- const int u_lines_in =
- WebPRescalerImport(p->scaler_u, uv_mb_h - uv_j,
- io->u + uv_j * io->uv_stride, io->uv_stride);
- const int v_lines_in =
- WebPRescalerImport(p->scaler_v, uv_mb_h - uv_j,
- io->v + uv_j * io->uv_stride, io->uv_stride);
- (void)v_lines_in; // remove a gcc warning
- assert(u_lines_in == v_lines_in);
- uv_j += u_lines_in;
- }
- num_lines_out += ExportRGB(p, p->last_y + num_lines_out);
- }
- return num_lines_out;
-}
-
-static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) {
- const WebPRGBABuffer* const buf = &p->output->u.RGBA;
- uint8_t* const base_rgba = buf->rgba + y_pos * buf->stride;
- const WEBP_CSP_MODE colorspace = p->output->colorspace;
- const int alpha_first =
- (colorspace == MODE_ARGB || colorspace == MODE_Argb);
- uint8_t* dst = base_rgba + (alpha_first ? 0 : 3);
- int num_lines_out = 0;
- const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
- uint32_t non_opaque = 0;
- const int width = p->scaler_a->dst_width;
-
- while (WebPRescalerHasPendingOutput(p->scaler_a) &&
- num_lines_out < max_lines_out) {
- assert(y_pos + num_lines_out < p->output->height);
- WebPRescalerExportRow(p->scaler_a);
- non_opaque |= WebPDispatchAlpha(p->scaler_a->dst, 0, width, 1, dst, 0);
- dst += buf->stride;
- ++num_lines_out;
- }
- if (is_premult_alpha && non_opaque) {
- WebPApplyAlphaMultiply(base_rgba, alpha_first,
- width, num_lines_out, buf->stride);
- }
- return num_lines_out;
-}
-
-static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos,
- int max_lines_out) {
- const WebPRGBABuffer* const buf = &p->output->u.RGBA;
- uint8_t* const base_rgba = buf->rgba + y_pos * buf->stride;
-#ifdef WEBP_SWAP_16BIT_CSP
- uint8_t* alpha_dst = base_rgba;
-#else
- uint8_t* alpha_dst = base_rgba + 1;
-#endif
- int num_lines_out = 0;
- const WEBP_CSP_MODE colorspace = p->output->colorspace;
- const int width = p->scaler_a->dst_width;
- const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
- uint32_t alpha_mask = 0x0f;
-
- while (WebPRescalerHasPendingOutput(p->scaler_a) &&
- num_lines_out < max_lines_out) {
- int i;
- assert(y_pos + num_lines_out < p->output->height);
- WebPRescalerExportRow(p->scaler_a);
- for (i = 0; i < width; ++i) {
- // Fill in the alpha value (converted to 4 bits).
- const uint32_t alpha_value = p->scaler_a->dst[i] >> 4;
- alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value;
- alpha_mask &= alpha_value;
- }
- alpha_dst += buf->stride;
- ++num_lines_out;
- }
- if (is_premult_alpha && alpha_mask != 0x0f) {
- WebPApplyAlphaMultiply4444(base_rgba, width, num_lines_out, buf->stride);
- }
- return num_lines_out;
-}
-
-static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p,
- int expected_num_out_lines) {
- if (io->a != NULL) {
- WebPRescaler* const scaler = p->scaler_a;
- int lines_left = expected_num_out_lines;
- const int y_end = p->last_y + lines_left;
- while (lines_left > 0) {
- const int row_offset = scaler->src_y - io->mb_y;
- WebPRescalerImport(scaler, io->mb_h + io->mb_y - scaler->src_y,
- io->a + row_offset * io->width, io->width);
- lines_left -= p->emit_alpha_row(p, y_end - lines_left, lines_left);
- }
- }
- return 0;
-}
-
-static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
- const int has_alpha = WebPIsAlphaMode(p->output->colorspace);
- const int out_width = io->scaled_width;
- const int out_height = io->scaled_height;
- const int uv_in_width = (io->mb_w + 1) >> 1;
- const int uv_in_height = (io->mb_h + 1) >> 1;
- const size_t work_size = 2 * out_width; // scratch memory for one rescaler
- rescaler_t* work; // rescalers work area
- uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion
- size_t tmp_size1, tmp_size2, total_size, rescaler_size;
- WebPRescaler* scalers;
- const int num_rescalers = has_alpha ? 4 : 3;
-
- tmp_size1 = 3 * work_size;
- tmp_size2 = 3 * out_width;
- if (has_alpha) {
- tmp_size1 += work_size;
- tmp_size2 += out_width;
- }
- total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp);
- rescaler_size = num_rescalers * sizeof(*p->scaler_y) + WEBP_ALIGN_CST;
-
- p->memory = WebPSafeMalloc(1ULL, total_size + rescaler_size);
- if (p->memory == NULL) {
- return 0; // memory error
- }
- work = (rescaler_t*)p->memory;
- tmp = (uint8_t*)(work + tmp_size1);
-
- scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + total_size);
- p->scaler_y = &scalers[0];
- p->scaler_u = &scalers[1];
- p->scaler_v = &scalers[2];
- p->scaler_a = has_alpha ? &scalers[3] : NULL;
-
- WebPRescalerInit(p->scaler_y, io->mb_w, io->mb_h,
- tmp + 0 * out_width, out_width, out_height, 0, 1,
- work + 0 * work_size);
- WebPRescalerInit(p->scaler_u, uv_in_width, uv_in_height,
- tmp + 1 * out_width, out_width, out_height, 0, 1,
- work + 1 * work_size);
- WebPRescalerInit(p->scaler_v, uv_in_width, uv_in_height,
- tmp + 2 * out_width, out_width, out_height, 0, 1,
- work + 2 * work_size);
- p->emit = EmitRescaledRGB;
- WebPInitYUV444Converters();
-
- if (has_alpha) {
- WebPRescalerInit(p->scaler_a, io->mb_w, io->mb_h,
- tmp + 3 * out_width, out_width, out_height, 0, 1,
- work + 3 * work_size);
- p->emit_alpha = EmitRescaledAlphaRGB;
- if (p->output->colorspace == MODE_RGBA_4444 ||
- p->output->colorspace == MODE_rgbA_4444) {
- p->emit_alpha_row = ExportAlphaRGBA4444;
- } else {
- p->emit_alpha_row = ExportAlpha;
- }
- WebPInitAlphaProcessing();
- }
- return 1;
-}
-
-//------------------------------------------------------------------------------
-// Default custom functions
-
-static int CustomSetup(VP8Io* io) {
- WebPDecParams* const p = (WebPDecParams*)io->opaque;
- const WEBP_CSP_MODE colorspace = p->output->colorspace;
- const int is_rgb = WebPIsRGBMode(colorspace);
- const int is_alpha = WebPIsAlphaMode(colorspace);
-
- p->memory = NULL;
- p->emit = NULL;
- p->emit_alpha = NULL;
- p->emit_alpha_row = NULL;
- if (!WebPIoInitFromOptions(p->options, io, is_alpha ? MODE_YUV : MODE_YUVA)) {
- return 0;
- }
- if (is_alpha && WebPIsPremultipliedMode(colorspace)) {
- WebPInitUpsamplers();
- }
- if (io->use_scaling) {
- const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p);
- if (!ok) {
- return 0; // memory error
- }
- } else {
- if (is_rgb) {
- WebPInitSamplers();
- p->emit = EmitSampledRGB; // default
- if (io->fancy_upsampling) {
-#ifdef FANCY_UPSAMPLING
- const int uv_width = (io->mb_w + 1) >> 1;
- p->memory = WebPSafeMalloc(1ULL, (size_t)(io->mb_w + 2 * uv_width));
- if (p->memory == NULL) {
- return 0; // memory error.
- }
- p->tmp_y = (uint8_t*)p->memory;
- p->tmp_u = p->tmp_y + io->mb_w;
- p->tmp_v = p->tmp_u + uv_width;
- p->emit = EmitFancyRGB;
- WebPInitUpsamplers();
-#endif
- }
- } else {
- p->emit = EmitYUV;
- }
- if (is_alpha) { // need transparency output
- p->emit_alpha =
- (colorspace == MODE_RGBA_4444 || colorspace == MODE_rgbA_4444) ?
- EmitAlphaRGBA4444
- : is_rgb ? EmitAlphaRGB
- : EmitAlphaYUV;
- if (is_rgb) {
- WebPInitAlphaProcessing();
- }
- }
- }
-
- if (is_rgb) {
- VP8YUVInit();
- }
- return 1;
-}
-
-//------------------------------------------------------------------------------
-
-static int CustomPut(const VP8Io* io) {
- WebPDecParams* const p = (WebPDecParams*)io->opaque;
- const int mb_w = io->mb_w;
- const int mb_h = io->mb_h;
- int num_lines_out;
- assert(!(io->mb_y & 1));
-
- if (mb_w <= 0 || mb_h <= 0) {
- return 0;
- }
- num_lines_out = p->emit(io, p);
- if (p->emit_alpha != NULL) {
- p->emit_alpha(io, p, num_lines_out);
- }
- p->last_y += num_lines_out;
- return 1;
-}
-
-//------------------------------------------------------------------------------
-
-static void CustomTeardown(const VP8Io* io) {
- WebPDecParams* const p = (WebPDecParams*)io->opaque;
- WebPSafeFree(p->memory);
- p->memory = NULL;
-}
-
-//------------------------------------------------------------------------------
-// Main entry point
-
-void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io) {
- io->put = CustomPut;
- io->setup = CustomSetup;
- io->teardown = CustomTeardown;
- io->opaque = params;
-}
-
-//------------------------------------------------------------------------------
diff --git a/thirdparty/libwebp/dec/quant_dec.c b/thirdparty/libwebp/dec/quant_dec.c
deleted file mode 100644
index 14e3198946..0000000000
--- a/thirdparty/libwebp/dec/quant_dec.c
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2010 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.
-// -----------------------------------------------------------------------------
-//
-// Quantizer initialization
-//
-// Author: Skal (pascal.massimino@gmail.com)
-
-#include "./vp8i_dec.h"
-
-static WEBP_INLINE int clip(int v, int M) {
- return v < 0 ? 0 : v > M ? M : v;
-}
-
-// Paragraph 14.1
-static const uint8_t kDcTable[128] = {
- 4, 5, 6, 7, 8, 9, 10, 10,
- 11, 12, 13, 14, 15, 16, 17, 17,
- 18, 19, 20, 20, 21, 21, 22, 22,
- 23, 23, 24, 25, 25, 26, 27, 28,
- 29, 30, 31, 32, 33, 34, 35, 36,
- 37, 37, 38, 39, 40, 41, 42, 43,
- 44, 45, 46, 46, 47, 48, 49, 50,
- 51, 52, 53, 54, 55, 56, 57, 58,
- 59, 60, 61, 62, 63, 64, 65, 66,
- 67, 68, 69, 70, 71, 72, 73, 74,
- 75, 76, 76, 77, 78, 79, 80, 81,
- 82, 83, 84, 85, 86, 87, 88, 89,
- 91, 93, 95, 96, 98, 100, 101, 102,
- 104, 106, 108, 110, 112, 114, 116, 118,
- 122, 124, 126, 128, 130, 132, 134, 136,
- 138, 140, 143, 145, 148, 151, 154, 157
-};
-
-static const uint16_t kAcTable[128] = {
- 4, 5, 6, 7, 8, 9, 10, 11,
- 12, 13, 14, 15, 16, 17, 18, 19,
- 20, 21, 22, 23, 24, 25, 26, 27,
- 28, 29, 30, 31, 32, 33, 34, 35,
- 36, 37, 38, 39, 40, 41, 42, 43,
- 44, 45, 46, 47, 48, 49, 50, 51,
- 52, 53, 54, 55, 56, 57, 58, 60,
- 62, 64, 66, 68, 70, 72, 74, 76,
- 78, 80, 82, 84, 86, 88, 90, 92,
- 94, 96, 98, 100, 102, 104, 106, 108,
- 110, 112, 114, 116, 119, 122, 125, 128,
- 131, 134, 137, 140, 143, 146, 149, 152,
- 155, 158, 161, 164, 167, 170, 173, 177,
- 181, 185, 189, 193, 197, 201, 205, 209,
- 213, 217, 221, 225, 229, 234, 239, 245,
- 249, 254, 259, 264, 269, 274, 279, 284
-};
-
-//------------------------------------------------------------------------------
-// Paragraph 9.6
-
-void VP8ParseQuant(VP8Decoder* const dec) {
- VP8BitReader* const br = &dec->br_;
- const int base_q0 = VP8GetValue(br, 7);
- const int dqy1_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
- const int dqy2_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
- const int dqy2_ac = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
- const int dquv_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
- const int dquv_ac = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
-
- const VP8SegmentHeader* const hdr = &dec->segment_hdr_;
- int i;
-
- for (i = 0; i < NUM_MB_SEGMENTS; ++i) {
- int q;
- if (hdr->use_segment_) {
- q = hdr->quantizer_[i];
- if (!hdr->absolute_delta_) {
- q += base_q0;
- }
- } else {
- if (i > 0) {
- dec->dqm_[i] = dec->dqm_[0];
- continue;
- } else {
- q = base_q0;
- }
- }
- {
- VP8QuantMatrix* const m = &dec->dqm_[i];
- m->y1_mat_[0] = kDcTable[clip(q + dqy1_dc, 127)];
- m->y1_mat_[1] = kAcTable[clip(q + 0, 127)];
-
- m->y2_mat_[0] = kDcTable[clip(q + dqy2_dc, 127)] * 2;
- // For all x in [0..284], x*155/100 is bitwise equal to (x*101581) >> 16.
- // The smallest precision for that is '(x*6349) >> 12' but 16 is a good
- // word size.
- m->y2_mat_[1] = (kAcTable[clip(q + dqy2_ac, 127)] * 101581) >> 16;
- if (m->y2_mat_[1] < 8) m->y2_mat_[1] = 8;
-
- m->uv_mat_[0] = kDcTable[clip(q + dquv_dc, 117)];
- m->uv_mat_[1] = kAcTable[clip(q + dquv_ac, 127)];
-
- m->uv_quant_ = q + dquv_ac; // for dithering strength evaluation
- }
- }
-}
-
-//------------------------------------------------------------------------------
-
diff --git a/thirdparty/libwebp/dec/tree_dec.c b/thirdparty/libwebp/dec/tree_dec.c
deleted file mode 100644
index 9e805f60f3..0000000000
--- a/thirdparty/libwebp/dec/tree_dec.c
+++ /dev/null
@@ -1,528 +0,0 @@
-// Copyright 2010 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.
-// -----------------------------------------------------------------------------
-//
-// Coding trees and probas
-//
-// Author: Skal (pascal.massimino@gmail.com)
-
-#include "./vp8i_dec.h"
-#include "../utils/bit_reader_inl_utils.h"
-
-#if !defined(__arm__) && !defined(_M_ARM) && !defined(__aarch64__)
-// using a table is ~1-2% slower on ARM. Prefer the coded-tree approach then.
-#define USE_GENERIC_TREE
-#endif
-
-#ifdef USE_GENERIC_TREE
-static const int8_t kYModesIntra4[18] = {
- -B_DC_PRED, 1,
- -B_TM_PRED, 2,
- -B_VE_PRED, 3,
- 4, 6,
- -B_HE_PRED, 5,
- -B_RD_PRED, -B_VR_PRED,
- -B_LD_PRED, 7,
- -B_VL_PRED, 8,
- -B_HD_PRED, -B_HU_PRED
-};
-#endif
-
-//------------------------------------------------------------------------------
-// Default probabilities
-
-// Paragraph 13.5
-static const uint8_t
- CoeffsProba0[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = {
- { { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
- { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
- { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
- },
- { { 253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128 },
- { 189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128 },
- { 106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128 }
- },
- { { 1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128 },
- { 181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128 },
- { 78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128 },
- },
- { { 1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128 },
- { 184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128 },
- { 77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128 },
- },
- { { 1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128 },
- { 170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128 },
- { 37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128 }
- },
- { { 1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128 },
- { 207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128 },
- { 102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128 }
- },
- { { 1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128 },
- { 177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128 },
- { 80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128 }
- },
- { { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
- { 246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
- { 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
- }
- },
- { { { 198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62 },
- { 131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1 },
- { 68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128 }
- },
- { { 1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128 },
- { 184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128 },
- { 81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128 }
- },
- { { 1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128 },
- { 99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128 },
- { 23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128 }
- },
- { { 1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128 },
- { 109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128 },
- { 44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128 }
- },
- { { 1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128 },
- { 94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128 },
- { 22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128 }
- },
- { { 1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128 },
- { 124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128 },
- { 35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128 }
- },
- { { 1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128 },
- { 121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128 },
- { 45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128 }
- },
- { { 1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128 },
- { 203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128 },
- { 137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128 }
- }
- },
- { { { 253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128 },
- { 175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128 },
- { 73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128 }
- },
- { { 1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128 },
- { 239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128 },
- { 155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128 }
- },
- { { 1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128 },
- { 201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128 },
- { 69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128 }
- },
- { { 1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128 },
- { 223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128 },
- { 141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128 }
- },
- { { 1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128 },
- { 190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128 },
- { 149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
- },
- { { 1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
- { 247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
- { 240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
- },
- { { 1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128 },
- { 213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128 },
- { 55, 93, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
- },
- { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
- { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
- { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
- }
- },
- { { { 202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255 },
- { 126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128 },
- { 61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128 }
- },
- { { 1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128 },
- { 166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128 },
- { 39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128 }
- },
- { { 1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128 },
- { 124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128 },
- { 24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128 }
- },
- { { 1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128 },
- { 149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128 },
- { 28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128 }
- },
- { { 1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128 },
- { 123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128 },
- { 20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128 }
- },
- { { 1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128 },
- { 168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128 },
- { 47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128 }
- },
- { { 1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128 },
- { 141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128 },
- { 42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128 }
- },
- { { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
- { 244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
- { 238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
- }
- }
-};
-
-// Paragraph 11.5
-static const uint8_t kBModesProba[NUM_BMODES][NUM_BMODES][NUM_BMODES - 1] = {
- { { 231, 120, 48, 89, 115, 113, 120, 152, 112 },
- { 152, 179, 64, 126, 170, 118, 46, 70, 95 },
- { 175, 69, 143, 80, 85, 82, 72, 155, 103 },
- { 56, 58, 10, 171, 218, 189, 17, 13, 152 },
- { 114, 26, 17, 163, 44, 195, 21, 10, 173 },
- { 121, 24, 80, 195, 26, 62, 44, 64, 85 },
- { 144, 71, 10, 38, 171, 213, 144, 34, 26 },
- { 170, 46, 55, 19, 136, 160, 33, 206, 71 },
- { 63, 20, 8, 114, 114, 208, 12, 9, 226 },
- { 81, 40, 11, 96, 182, 84, 29, 16, 36 } },
- { { 134, 183, 89, 137, 98, 101, 106, 165, 148 },
- { 72, 187, 100, 130, 157, 111, 32, 75, 80 },
- { 66, 102, 167, 99, 74, 62, 40, 234, 128 },
- { 41, 53, 9, 178, 241, 141, 26, 8, 107 },
- { 74, 43, 26, 146, 73, 166, 49, 23, 157 },
- { 65, 38, 105, 160, 51, 52, 31, 115, 128 },
- { 104, 79, 12, 27, 217, 255, 87, 17, 7 },
- { 87, 68, 71, 44, 114, 51, 15, 186, 23 },
- { 47, 41, 14, 110, 182, 183, 21, 17, 194 },
- { 66, 45, 25, 102, 197, 189, 23, 18, 22 } },
- { { 88, 88, 147, 150, 42, 46, 45, 196, 205 },
- { 43, 97, 183, 117, 85, 38, 35, 179, 61 },
- { 39, 53, 200, 87, 26, 21, 43, 232, 171 },
- { 56, 34, 51, 104, 114, 102, 29, 93, 77 },
- { 39, 28, 85, 171, 58, 165, 90, 98, 64 },
- { 34, 22, 116, 206, 23, 34, 43, 166, 73 },
- { 107, 54, 32, 26, 51, 1, 81, 43, 31 },
- { 68, 25, 106, 22, 64, 171, 36, 225, 114 },
- { 34, 19, 21, 102, 132, 188, 16, 76, 124 },
- { 62, 18, 78, 95, 85, 57, 50, 48, 51 } },
- { { 193, 101, 35, 159, 215, 111, 89, 46, 111 },
- { 60, 148, 31, 172, 219, 228, 21, 18, 111 },
- { 112, 113, 77, 85, 179, 255, 38, 120, 114 },
- { 40, 42, 1, 196, 245, 209, 10, 25, 109 },
- { 88, 43, 29, 140, 166, 213, 37, 43, 154 },
- { 61, 63, 30, 155, 67, 45, 68, 1, 209 },
- { 100, 80, 8, 43, 154, 1, 51, 26, 71 },
- { 142, 78, 78, 16, 255, 128, 34, 197, 171 },
- { 41, 40, 5, 102, 211, 183, 4, 1, 221 },
- { 51, 50, 17, 168, 209, 192, 23, 25, 82 } },
- { { 138, 31, 36, 171, 27, 166, 38, 44, 229 },
- { 67, 87, 58, 169, 82, 115, 26, 59, 179 },
- { 63, 59, 90, 180, 59, 166, 93, 73, 154 },
- { 40, 40, 21, 116, 143, 209, 34, 39, 175 },
- { 47, 15, 16, 183, 34, 223, 49, 45, 183 },
- { 46, 17, 33, 183, 6, 98, 15, 32, 183 },
- { 57, 46, 22, 24, 128, 1, 54, 17, 37 },
- { 65, 32, 73, 115, 28, 128, 23, 128, 205 },
- { 40, 3, 9, 115, 51, 192, 18, 6, 223 },
- { 87, 37, 9, 115, 59, 77, 64, 21, 47 } },
- { { 104, 55, 44, 218, 9, 54, 53, 130, 226 },
- { 64, 90, 70, 205, 40, 41, 23, 26, 57 },
- { 54, 57, 112, 184, 5, 41, 38, 166, 213 },
- { 30, 34, 26, 133, 152, 116, 10, 32, 134 },
- { 39, 19, 53, 221, 26, 114, 32, 73, 255 },
- { 31, 9, 65, 234, 2, 15, 1, 118, 73 },
- { 75, 32, 12, 51, 192, 255, 160, 43, 51 },
- { 88, 31, 35, 67, 102, 85, 55, 186, 85 },
- { 56, 21, 23, 111, 59, 205, 45, 37, 192 },
- { 55, 38, 70, 124, 73, 102, 1, 34, 98 } },
- { { 125, 98, 42, 88, 104, 85, 117, 175, 82 },
- { 95, 84, 53, 89, 128, 100, 113, 101, 45 },
- { 75, 79, 123, 47, 51, 128, 81, 171, 1 },
- { 57, 17, 5, 71, 102, 57, 53, 41, 49 },
- { 38, 33, 13, 121, 57, 73, 26, 1, 85 },
- { 41, 10, 67, 138, 77, 110, 90, 47, 114 },
- { 115, 21, 2, 10, 102, 255, 166, 23, 6 },
- { 101, 29, 16, 10, 85, 128, 101, 196, 26 },
- { 57, 18, 10, 102, 102, 213, 34, 20, 43 },
- { 117, 20, 15, 36, 163, 128, 68, 1, 26 } },
- { { 102, 61, 71, 37, 34, 53, 31, 243, 192 },
- { 69, 60, 71, 38, 73, 119, 28, 222, 37 },
- { 68, 45, 128, 34, 1, 47, 11, 245, 171 },
- { 62, 17, 19, 70, 146, 85, 55, 62, 70 },
- { 37, 43, 37, 154, 100, 163, 85, 160, 1 },
- { 63, 9, 92, 136, 28, 64, 32, 201, 85 },
- { 75, 15, 9, 9, 64, 255, 184, 119, 16 },
- { 86, 6, 28, 5, 64, 255, 25, 248, 1 },
- { 56, 8, 17, 132, 137, 255, 55, 116, 128 },
- { 58, 15, 20, 82, 135, 57, 26, 121, 40 } },
- { { 164, 50, 31, 137, 154, 133, 25, 35, 218 },
- { 51, 103, 44, 131, 131, 123, 31, 6, 158 },
- { 86, 40, 64, 135, 148, 224, 45, 183, 128 },
- { 22, 26, 17, 131, 240, 154, 14, 1, 209 },
- { 45, 16, 21, 91, 64, 222, 7, 1, 197 },
- { 56, 21, 39, 155, 60, 138, 23, 102, 213 },
- { 83, 12, 13, 54, 192, 255, 68, 47, 28 },
- { 85, 26, 85, 85, 128, 128, 32, 146, 171 },
- { 18, 11, 7, 63, 144, 171, 4, 4, 246 },
- { 35, 27, 10, 146, 174, 171, 12, 26, 128 } },
- { { 190, 80, 35, 99, 180, 80, 126, 54, 45 },
- { 85, 126, 47, 87, 176, 51, 41, 20, 32 },
- { 101, 75, 128, 139, 118, 146, 116, 128, 85 },
- { 56, 41, 15, 176, 236, 85, 37, 9, 62 },
- { 71, 30, 17, 119, 118, 255, 17, 18, 138 },
- { 101, 38, 60, 138, 55, 70, 43, 26, 142 },
- { 146, 36, 19, 30, 171, 255, 97, 27, 20 },
- { 138, 45, 61, 62, 219, 1, 81, 188, 64 },
- { 32, 41, 20, 117, 151, 142, 20, 21, 163 },
- { 112, 19, 12, 61, 195, 128, 48, 4, 24 } }
-};
-
-void VP8ResetProba(VP8Proba* const proba) {
- memset(proba->segments_, 255u, sizeof(proba->segments_));
- // proba->bands_[][] is initialized later
-}
-
-static void ParseIntraMode(VP8BitReader* const br,
- VP8Decoder* const dec, int mb_x) {
- uint8_t* const top = dec->intra_t_ + 4 * mb_x;
- uint8_t* const left = dec->intra_l_;
- VP8MBData* const block = dec->mb_data_ + mb_x;
-
- // Note: we don't save segment map (yet), as we don't expect
- // to decode more than 1 keyframe.
- if (dec->segment_hdr_.update_map_) {
- // Hardcoded tree parsing
- block->segment_ = !VP8GetBit(br, dec->proba_.segments_[0])
- ? VP8GetBit(br, dec->proba_.segments_[1])
- : 2 + VP8GetBit(br, dec->proba_.segments_[2]);
- } else {
- block->segment_ = 0; // default for intra
- }
- if (dec->use_skip_proba_) block->skip_ = VP8GetBit(br, dec->skip_p_);
-
- block->is_i4x4_ = !VP8GetBit(br, 145); // decide for B_PRED first
- if (!block->is_i4x4_) {
- // Hardcoded 16x16 intra-mode decision tree.
- const int ymode =
- VP8GetBit(br, 156) ? (VP8GetBit(br, 128) ? TM_PRED : H_PRED)
- : (VP8GetBit(br, 163) ? V_PRED : DC_PRED);
- block->imodes_[0] = ymode;
- memset(top, ymode, 4 * sizeof(*top));
- memset(left, ymode, 4 * sizeof(*left));
- } else {
- uint8_t* modes = block->imodes_;
- int y;
- for (y = 0; y < 4; ++y) {
- int ymode = left[y];
- int x;
- for (x = 0; x < 4; ++x) {
- const uint8_t* const prob = kBModesProba[top[x]][ymode];
-#ifdef USE_GENERIC_TREE
- // Generic tree-parsing
- int i = kYModesIntra4[VP8GetBit(br, prob[0])];
- while (i > 0) {
- i = kYModesIntra4[2 * i + VP8GetBit(br, prob[i])];
- }
- ymode = -i;
-#else
- // Hardcoded tree parsing
- ymode = !VP8GetBit(br, prob[0]) ? B_DC_PRED :
- !VP8GetBit(br, prob[1]) ? B_TM_PRED :
- !VP8GetBit(br, prob[2]) ? B_VE_PRED :
- !VP8GetBit(br, prob[3]) ?
- (!VP8GetBit(br, prob[4]) ? B_HE_PRED :
- (!VP8GetBit(br, prob[5]) ? B_RD_PRED : B_VR_PRED)) :
- (!VP8GetBit(br, prob[6]) ? B_LD_PRED :
- (!VP8GetBit(br, prob[7]) ? B_VL_PRED :
- (!VP8GetBit(br, prob[8]) ? B_HD_PRED : B_HU_PRED)));
-#endif // USE_GENERIC_TREE
- top[x] = ymode;
- }
- memcpy(modes, top, 4 * sizeof(*top));
- modes += 4;
- left[y] = ymode;
- }
- }
- // Hardcoded UVMode decision tree
- block->uvmode_ = !VP8GetBit(br, 142) ? DC_PRED
- : !VP8GetBit(br, 114) ? V_PRED
- : VP8GetBit(br, 183) ? TM_PRED : H_PRED;
-}
-
-int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec) {
- int mb_x;
- for (mb_x = 0; mb_x < dec->mb_w_; ++mb_x) {
- ParseIntraMode(br, dec, mb_x);
- }
- return !dec->br_.eof_;
-}
-
-//------------------------------------------------------------------------------
-// Paragraph 13
-
-static const uint8_t
- CoeffsUpdateProba[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = {
- { { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255 },
- { 250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255 },
- { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- }
- },
- { { { 217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255 },
- { 234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255 }
- },
- { { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- }
- },
- { { { 186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255 },
- { 251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255 }
- },
- { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- }
- },
- { { { 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255 },
- { 248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- },
- { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
- { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
- }
- }
-};
-
-// Paragraph 9.9
-
-static const int kBands[16 + 1] = {
- 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7,
- 0 // extra entry as sentinel
-};
-
-void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) {
- VP8Proba* const proba = &dec->proba_;
- int t, b, c, p;
- for (t = 0; t < NUM_TYPES; ++t) {
- for (b = 0; b < NUM_BANDS; ++b) {
- for (c = 0; c < NUM_CTX; ++c) {
- for (p = 0; p < NUM_PROBAS; ++p) {
- const int v = VP8GetBit(br, CoeffsUpdateProba[t][b][c][p]) ?
- VP8GetValue(br, 8) : CoeffsProba0[t][b][c][p];
- proba->bands_[t][b].probas_[c][p] = v;
- }
- }
- }
- for (b = 0; b < 16 + 1; ++b) {
- proba->bands_ptr_[t][b] = &proba->bands_[t][kBands[b]];
- }
- }
- dec->use_skip_proba_ = VP8Get(br);
- if (dec->use_skip_proba_) {
- dec->skip_p_ = VP8GetValue(br, 8);
- }
-}
-
diff --git a/thirdparty/libwebp/dec/vp8_dec.c b/thirdparty/libwebp/dec/vp8_dec.c
deleted file mode 100644
index fad8d9cf35..0000000000
--- a/thirdparty/libwebp/dec/vp8_dec.c
+++ /dev/null
@@ -1,721 +0,0 @@
-// Copyright 2010 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.
-// -----------------------------------------------------------------------------
-//
-// main entry for the decoder
-//
-// Author: Skal (pascal.massimino@gmail.com)
-
-#include <stdlib.h>
-
-#include "./alphai_dec.h"
-#include "./vp8i_dec.h"
-#include "./vp8li_dec.h"
-#include "./webpi_dec.h"
-#include "../utils/bit_reader_inl_utils.h"
-#include "../utils/utils.h"
-
-//------------------------------------------------------------------------------
-
-int WebPGetDecoderVersion(void) {
- return (DEC_MAJ_VERSION << 16) | (DEC_MIN_VERSION << 8) | DEC_REV_VERSION;
-}
-
-//------------------------------------------------------------------------------
-// Signature and pointer-to-function for GetCoeffs() variants below.
-
-typedef int (*GetCoeffsFunc)(VP8BitReader* const br,
- const VP8BandProbas* const prob[],
- int ctx, const quant_t dq, int n, int16_t* out);
-static volatile GetCoeffsFunc GetCoeffs = NULL;
-
-static void InitGetCoeffs(void);
-
-//------------------------------------------------------------------------------
-// VP8Decoder
-
-static void SetOk(VP8Decoder* const dec) {
- dec->status_ = VP8_STATUS_OK;
- dec->error_msg_ = "OK";
-}
-
-int VP8InitIoInternal(VP8Io* const io, int version) {
- if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
- return 0; // mismatch error
- }
- if (io != NULL) {
- memset(io, 0, sizeof(*io));
- }
- return 1;
-}
-
-VP8Decoder* VP8New(void) {
- VP8Decoder* const dec = (VP8Decoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
- if (dec != NULL) {
- SetOk(dec);
- WebPGetWorkerInterface()->Init(&dec->worker_);
- dec->ready_ = 0;
- dec->num_parts_minus_one_ = 0;
- InitGetCoeffs();
- }
- return dec;
-}
-
-VP8StatusCode VP8Status(VP8Decoder* const dec) {
- if (!dec) return VP8_STATUS_INVALID_PARAM;
- return dec->status_;
-}
-
-const char* VP8StatusMessage(VP8Decoder* const dec) {
- if (dec == NULL) return "no object";
- if (!dec->error_msg_) return "OK";
- return dec->error_msg_;
-}
-
-void VP8Delete(VP8Decoder* const dec) {
- if (dec != NULL) {
- VP8Clear(dec);
- WebPSafeFree(dec);
- }
-}
-
-int VP8SetError(VP8Decoder* const dec,
- VP8StatusCode error, const char* const msg) {
- // The oldest error reported takes precedence over the new one.
- if (dec->status_ == VP8_STATUS_OK) {
- dec->status_ = error;
- dec->error_msg_ = msg;
- dec->ready_ = 0;
- }
- return 0;
-}
-
-//------------------------------------------------------------------------------
-
-int VP8CheckSignature(const uint8_t* const data, size_t data_size) {
- return (data_size >= 3 &&
- data[0] == 0x9d && data[1] == 0x01 && data[2] == 0x2a);
-}
-
-int VP8GetInfo(const uint8_t* data, size_t data_size, size_t chunk_size,
- int* const width, int* const height) {
- if (data == NULL || data_size < VP8_FRAME_HEADER_SIZE) {
- return 0; // not enough data
- }
- // check signature
- if (!VP8CheckSignature(data + 3, data_size - 3)) {
- return 0; // Wrong signature.
- } else {
- const uint32_t bits = data[0] | (data[1] << 8) | (data[2] << 16);
- const int key_frame = !(bits & 1);
- const int w = ((data[7] << 8) | data[6]) & 0x3fff;
- const int h = ((data[9] << 8) | data[8]) & 0x3fff;
-
- if (!key_frame) { // Not a keyframe.
- return 0;
- }
-
- if (((bits >> 1) & 7) > 3) {
- return 0; // unknown profile
- }
- if (!((bits >> 4) & 1)) {
- return 0; // first frame is invisible!
- }
- if (((bits >> 5)) >= chunk_size) { // partition_length
- return 0; // inconsistent size information.
- }
- if (w == 0 || h == 0) {
- return 0; // We don't support both width and height to be zero.
- }
-
- if (width) {
- *width = w;
- }
- if (height) {
- *height = h;
- }
-
- return 1;
- }
-}
-
-//------------------------------------------------------------------------------
-// Header parsing
-
-static void ResetSegmentHeader(VP8SegmentHeader* const hdr) {
- assert(hdr != NULL);
- hdr->use_segment_ = 0;
- hdr->update_map_ = 0;
- hdr->absolute_delta_ = 1;
- memset(hdr->quantizer_, 0, sizeof(hdr->quantizer_));
- memset(hdr->filter_strength_, 0, sizeof(hdr->filter_strength_));
-}
-
-// Paragraph 9.3
-static int ParseSegmentHeader(VP8BitReader* br,
- VP8SegmentHeader* hdr, VP8Proba* proba) {
- assert(br != NULL);
- assert(hdr != NULL);
- hdr->use_segment_ = VP8Get(br);
- if (hdr->use_segment_) {
- hdr->update_map_ = VP8Get(br);
- if (VP8Get(br)) { // update data
- int s;
- hdr->absolute_delta_ = VP8Get(br);
- for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
- hdr->quantizer_[s] = VP8Get(br) ? VP8GetSignedValue(br, 7) : 0;
- }
- for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
- hdr->filter_strength_[s] = VP8Get(br) ? VP8GetSignedValue(br, 6) : 0;
- }
- }
- if (hdr->update_map_) {
- int s;
- for (s = 0; s < MB_FEATURE_TREE_PROBS; ++s) {
- proba->segments_[s] = VP8Get(br) ? VP8GetValue(br, 8) : 255u;
- }
- }
- } else {
- hdr->update_map_ = 0;
- }
- return !br->eof_;
-}
-
-// Paragraph 9.5
-// This function returns VP8_STATUS_SUSPENDED if we don't have all the
-// necessary data in 'buf'.
-// This case is not necessarily an error (for incremental decoding).
-// Still, no bitreader is ever initialized to make it possible to read
-// unavailable memory.
-// If we don't even have the partitions' sizes, than VP8_STATUS_NOT_ENOUGH_DATA
-// is returned, and this is an unrecoverable error.
-// If the partitions were positioned ok, VP8_STATUS_OK is returned.
-static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
- const uint8_t* buf, size_t size) {
- VP8BitReader* const br = &dec->br_;
- const uint8_t* sz = buf;
- const uint8_t* buf_end = buf + size;
- const uint8_t* part_start;
- size_t size_left = size;
- size_t last_part;
- size_t p;
-
- dec->num_parts_minus_one_ = (1 << VP8GetValue(br, 2)) - 1;
- last_part = dec->num_parts_minus_one_;
- if (size < 3 * last_part) {
- // we can't even read the sizes with sz[]! That's a failure.
- return VP8_STATUS_NOT_ENOUGH_DATA;
- }
- part_start = buf + last_part * 3;
- size_left -= last_part * 3;
- for (p = 0; p < last_part; ++p) {
- size_t psize = sz[0] | (sz[1] << 8) | (sz[2] << 16);
- if (psize > size_left) psize = size_left;
- VP8InitBitReader(dec->parts_ + p, part_start, psize);
- part_start += psize;
- size_left -= psize;
- sz += 3;
- }
- VP8InitBitReader(dec->parts_ + last_part, part_start, size_left);
- return (part_start < buf_end) ? VP8_STATUS_OK :
- VP8_STATUS_SUSPENDED; // Init is ok, but there's not enough data
-}
-
-// Paragraph 9.4
-static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) {
- VP8FilterHeader* const hdr = &dec->filter_hdr_;
- hdr->simple_ = VP8Get(br);
- hdr->level_ = VP8GetValue(br, 6);
- hdr->sharpness_ = VP8GetValue(br, 3);
- hdr->use_lf_delta_ = VP8Get(br);
- if (hdr->use_lf_delta_) {
- if (VP8Get(br)) { // update lf-delta?
- int i;
- for (i = 0; i < NUM_REF_LF_DELTAS; ++i) {
- if (VP8Get(br)) {
- hdr->ref_lf_delta_[i] = VP8GetSignedValue(br, 6);
- }
- }
- for (i = 0; i < NUM_MODE_LF_DELTAS; ++i) {
- if (VP8Get(br)) {
- hdr->mode_lf_delta_[i] = VP8GetSignedValue(br, 6);
- }
- }
- }
- }
- dec->filter_type_ = (hdr->level_ == 0) ? 0 : hdr->simple_ ? 1 : 2;
- return !br->eof_;
-}
-
-// Topmost call
-int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
- const uint8_t* buf;
- size_t buf_size;
- VP8FrameHeader* frm_hdr;
- VP8PictureHeader* pic_hdr;
- VP8BitReader* br;
- VP8StatusCode status;
-
- if (dec == NULL) {
- return 0;
- }
- SetOk(dec);
- if (io == NULL) {
- return VP8SetError(dec, VP8_STATUS_INVALID_PARAM,
- "null VP8Io passed to VP8GetHeaders()");
- }
- buf = io->data;
- buf_size = io->data_size;
- if (buf_size < 4) {
- return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
- "Truncated header.");
- }
-
- // Paragraph 9.1
- {
- const uint32_t bits = buf[0] | (buf[1] << 8) | (buf[2] << 16);
- frm_hdr = &dec->frm_hdr_;
- frm_hdr->key_frame_ = !(bits & 1);
- frm_hdr->profile_ = (bits >> 1) & 7;
- frm_hdr->show_ = (bits >> 4) & 1;
- frm_hdr->partition_length_ = (bits >> 5);
- if (frm_hdr->profile_ > 3) {
- return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
- "Incorrect keyframe parameters.");
- }
- if (!frm_hdr->show_) {
- return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE,
- "Frame not displayable.");
- }
- buf += 3;
- buf_size -= 3;
- }
-
- pic_hdr = &dec->pic_hdr_;
- if (frm_hdr->key_frame_) {
- // Paragraph 9.2
- if (buf_size < 7) {
- return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
- "cannot parse picture header");
- }
- if (!VP8CheckSignature(buf, buf_size)) {
- return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
- "Bad code word");
- }
- pic_hdr->width_ = ((buf[4] << 8) | buf[3]) & 0x3fff;
- pic_hdr->xscale_ = buf[4] >> 6; // ratio: 1, 5/4 5/3 or 2
- pic_hdr->height_ = ((buf[6] << 8) | buf[5]) & 0x3fff;
- pic_hdr->yscale_ = buf[6] >> 6;
- buf += 7;
- buf_size -= 7;
-
- dec->mb_w_ = (pic_hdr->width_ + 15) >> 4;
- dec->mb_h_ = (pic_hdr->height_ + 15) >> 4;
-
- // Setup default output area (can be later modified during io->setup())
- io->width = pic_hdr->width_;
- io->height = pic_hdr->height_;
- // IMPORTANT! use some sane dimensions in crop_* and scaled_* fields.
- // So they can be used interchangeably without always testing for
- // 'use_cropping'.
- io->use_cropping = 0;
- io->crop_top = 0;
- io->crop_left = 0;
- io->crop_right = io->width;
- io->crop_bottom = io->height;
- io->use_scaling = 0;
- io->scaled_width = io->width;
- io->scaled_height = io->height;
-
- io->mb_w = io->width; // sanity check
- io->mb_h = io->height; // ditto
-
- VP8ResetProba(&dec->proba_);
- ResetSegmentHeader(&dec->segment_hdr_);
- }
-
- // Check if we have all the partition #0 available, and initialize dec->br_
- // to read this partition (and this partition only).
- if (frm_hdr->partition_length_ > buf_size) {
- return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
- "bad partition length");
- }
-
- br = &dec->br_;
- VP8InitBitReader(br, buf, frm_hdr->partition_length_);
- buf += frm_hdr->partition_length_;
- buf_size -= frm_hdr->partition_length_;
-
- if (frm_hdr->key_frame_) {
- pic_hdr->colorspace_ = VP8Get(br);
- pic_hdr->clamp_type_ = VP8Get(br);
- }
- if (!ParseSegmentHeader(br, &dec->segment_hdr_, &dec->proba_)) {
- return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
- "cannot parse segment header");
- }
- // Filter specs
- if (!ParseFilterHeader(br, dec)) {
- return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
- "cannot parse filter header");
- }
- status = ParsePartitions(dec, buf, buf_size);
- if (status != VP8_STATUS_OK) {
- return VP8SetError(dec, status, "cannot parse partitions");
- }
-
- // quantizer change
- VP8ParseQuant(dec);
-
- // Frame buffer marking
- if (!frm_hdr->key_frame_) {
- return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE,
- "Not a key frame.");
- }
-
- VP8Get(br); // ignore the value of update_proba_
-
- VP8ParseProba(br, dec);
-
- // sanitized state
- dec->ready_ = 1;
- return 1;
-}
-
-//------------------------------------------------------------------------------
-// Residual decoding (Paragraph 13.2 / 13.3)
-
-static const uint8_t kCat3[] = { 173, 148, 140, 0 };
-static const uint8_t kCat4[] = { 176, 155, 140, 135, 0 };
-static const uint8_t kCat5[] = { 180, 157, 141, 134, 130, 0 };
-static const uint8_t kCat6[] =
- { 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129, 0 };
-static const uint8_t* const kCat3456[] = { kCat3, kCat4, kCat5, kCat6 };
-static const uint8_t kZigzag[16] = {
- 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15
-};
-
-// See section 13-2: http://tools.ietf.org/html/rfc6386#section-13.2
-static int GetLargeValue(VP8BitReader* const br, const uint8_t* const p) {
- int v;
- if (!VP8GetBit(br, p[3])) {
- if (!VP8GetBit(br, p[4])) {
- v = 2;
- } else {
- v = 3 + VP8GetBit(br, p[5]);
- }
- } else {
- if (!VP8GetBit(br, p[6])) {
- if (!VP8GetBit(br, p[7])) {
- v = 5 + VP8GetBit(br, 159);
- } else {
- v = 7 + 2 * VP8GetBit(br, 165);
- v += VP8GetBit(br, 145);
- }
- } else {
- const uint8_t* tab;
- const int bit1 = VP8GetBit(br, p[8]);
- const int bit0 = VP8GetBit(br, p[9 + bit1]);
- const int cat = 2 * bit1 + bit0;
- v = 0;
- for (tab = kCat3456[cat]; *tab; ++tab) {
- v += v + VP8GetBit(br, *tab);
- }
- v += 3 + (8 << cat);
- }
- }
- return v;
-}
-
-// Returns the position of the last non-zero coeff plus one
-static int GetCoeffsFast(VP8BitReader* const br,
- const VP8BandProbas* const prob[],
- int ctx, const quant_t dq, int n, int16_t* out) {
- const uint8_t* p = prob[n]->probas_[ctx];
- for (; n < 16; ++n) {
- if (!VP8GetBit(br, p[0])) {
- return n; // previous coeff was last non-zero coeff
- }
- while (!VP8GetBit(br, p[1])) { // sequence of zero coeffs
- p = prob[++n]->probas_[0];
- if (n == 16) return 16;
- }
- { // non zero coeff
- const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0];
- int v;
- if (!VP8GetBit(br, p[2])) {
- v = 1;
- p = p_ctx[1];
- } else {
- v = GetLargeValue(br, p);
- p = p_ctx[2];
- }
- out[kZigzag[n]] = VP8GetSigned(br, v) * dq[n > 0];
- }
- }
- return 16;
-}
-
-// This version of GetCoeffs() uses VP8GetBitAlt() which is an alternate version
-// of VP8GetBitAlt() targeting specific platforms.
-static int GetCoeffsAlt(VP8BitReader* const br,
- const VP8BandProbas* const prob[],
- int ctx, const quant_t dq, int n, int16_t* out) {
- const uint8_t* p = prob[n]->probas_[ctx];
- for (; n < 16; ++n) {
- if (!VP8GetBitAlt(br, p[0])) {
- return n; // previous coeff was last non-zero coeff
- }
- while (!VP8GetBitAlt(br, p[1])) { // sequence of zero coeffs
- p = prob[++n]->probas_[0];
- if (n == 16) return 16;
- }
- { // non zero coeff
- const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0];
- int v;
- if (!VP8GetBitAlt(br, p[2])) {
- v = 1;
- p = p_ctx[1];
- } else {
- v = GetLargeValue(br, p);
- p = p_ctx[2];
- }
- out[kZigzag[n]] = VP8GetSigned(br, v) * dq[n > 0];
- }
- }
- return 16;
-}
-
-WEBP_TSAN_IGNORE_FUNCTION static void InitGetCoeffs(void) {
- if (GetCoeffs == NULL) {
- if (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kSlowSSSE3)) {
- GetCoeffs = GetCoeffsAlt;
- } else {
- GetCoeffs = GetCoeffsFast;
- }
- }
-}
-
-static WEBP_INLINE uint32_t NzCodeBits(uint32_t nz_coeffs, int nz, int dc_nz) {
- nz_coeffs <<= 2;
- nz_coeffs |= (nz > 3) ? 3 : (nz > 1) ? 2 : dc_nz;
- return nz_coeffs;
-}
-
-static int ParseResiduals(VP8Decoder* const dec,
- VP8MB* const mb, VP8BitReader* const token_br) {
- const VP8BandProbas* (* const bands)[16 + 1] = dec->proba_.bands_ptr_;
- const VP8BandProbas* const * ac_proba;
- VP8MBData* const block = dec->mb_data_ + dec->mb_x_;
- const VP8QuantMatrix* const q = &dec->dqm_[block->segment_];
- int16_t* dst = block->coeffs_;
- VP8MB* const left_mb = dec->mb_info_ - 1;
- uint8_t tnz, lnz;
- uint32_t non_zero_y = 0;
- uint32_t non_zero_uv = 0;
- int x, y, ch;
- uint32_t out_t_nz, out_l_nz;
- int first;
-
- memset(dst, 0, 384 * sizeof(*dst));
- if (!block->is_i4x4_) { // parse DC
- int16_t dc[16] = { 0 };
- const int ctx = mb->nz_dc_ + left_mb->nz_dc_;
- const int nz = GetCoeffs(token_br, bands[1], ctx, q->y2_mat_, 0, dc);
- mb->nz_dc_ = left_mb->nz_dc_ = (nz > 0);
- if (nz > 1) { // more than just the DC -> perform the full transform
- VP8TransformWHT(dc, dst);
- } else { // only DC is non-zero -> inlined simplified transform
- int i;
- const int dc0 = (dc[0] + 3) >> 3;
- for (i = 0; i < 16 * 16; i += 16) dst[i] = dc0;
- }
- first = 1;
- ac_proba = bands[0];
- } else {
- first = 0;
- ac_proba = bands[3];
- }
-
- tnz = mb->nz_ & 0x0f;
- lnz = left_mb->nz_ & 0x0f;
- for (y = 0; y < 4; ++y) {
- int l = lnz & 1;
- uint32_t nz_coeffs = 0;
- for (x = 0; x < 4; ++x) {
- const int ctx = l + (tnz & 1);
- const int nz = GetCoeffs(token_br, ac_proba, ctx, q->y1_mat_, first, dst);
- l = (nz > first);
- tnz = (tnz >> 1) | (l << 7);
- nz_coeffs = NzCodeBits(nz_coeffs, nz, dst[0] != 0);
- dst += 16;
- }
- tnz >>= 4;
- lnz = (lnz >> 1) | (l << 7);
- non_zero_y = (non_zero_y << 8) | nz_coeffs;
- }
- out_t_nz = tnz;
- out_l_nz = lnz >> 4;
-
- for (ch = 0; ch < 4; ch += 2) {
- uint32_t nz_coeffs = 0;
- tnz = mb->nz_ >> (4 + ch);
- lnz = left_mb->nz_ >> (4 + ch);
- for (y = 0; y < 2; ++y) {
- int l = lnz & 1;
- for (x = 0; x < 2; ++x) {
- const int ctx = l + (tnz & 1);
- const int nz = GetCoeffs(token_br, bands[2], ctx, q->uv_mat_, 0, dst);
- l = (nz > 0);
- tnz = (tnz >> 1) | (l << 3);
- nz_coeffs = NzCodeBits(nz_coeffs, nz, dst[0] != 0);
- dst += 16;
- }
- tnz >>= 2;
- lnz = (lnz >> 1) | (l << 5);
- }
- // Note: we don't really need the per-4x4 details for U/V blocks.
- non_zero_uv |= nz_coeffs << (4 * ch);
- out_t_nz |= (tnz << 4) << ch;
- out_l_nz |= (lnz & 0xf0) << ch;
- }
- mb->nz_ = out_t_nz;
- left_mb->nz_ = out_l_nz;
-
- block->non_zero_y_ = non_zero_y;
- block->non_zero_uv_ = non_zero_uv;
-
- // We look at the mode-code of each block and check if some blocks have less
- // than three non-zero coeffs (code < 2). This is to avoid dithering flat and
- // empty blocks.
- block->dither_ = (non_zero_uv & 0xaaaa) ? 0 : q->dither_;
-
- return !(non_zero_y | non_zero_uv); // will be used for further optimization
-}
-
-//------------------------------------------------------------------------------
-// Main loop
-
-int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br) {
- VP8MB* const left = dec->mb_info_ - 1;
- VP8MB* const mb = dec->mb_info_ + dec->mb_x_;
- VP8MBData* const block = dec->mb_data_ + dec->mb_x_;
- int skip = dec->use_skip_proba_ ? block->skip_ : 0;
-
- if (!skip) {
- skip = ParseResiduals(dec, mb, token_br);
- } else {
- left->nz_ = mb->nz_ = 0;
- if (!block->is_i4x4_) {
- left->nz_dc_ = mb->nz_dc_ = 0;
- }
- block->non_zero_y_ = 0;
- block->non_zero_uv_ = 0;
- block->dither_ = 0;
- }
-
- if (dec->filter_type_ > 0) { // store filter info
- VP8FInfo* const finfo = dec->f_info_ + dec->mb_x_;
- *finfo = dec->fstrengths_[block->segment_][block->is_i4x4_];
- finfo->f_inner_ |= !skip;
- }
-
- return !token_br->eof_;
-}
-
-void VP8InitScanline(VP8Decoder* const dec) {
- VP8MB* const left = dec->mb_info_ - 1;
- left->nz_ = 0;
- left->nz_dc_ = 0;
- memset(dec->intra_l_, B_DC_PRED, sizeof(dec->intra_l_));
- dec->mb_x_ = 0;
-}
-
-static int ParseFrame(VP8Decoder* const dec, VP8Io* io) {
- for (dec->mb_y_ = 0; dec->mb_y_ < dec->br_mb_y_; ++dec->mb_y_) {
- // Parse bitstream for this row.
- VP8BitReader* const token_br =
- &dec->parts_[dec->mb_y_ & dec->num_parts_minus_one_];
- if (!VP8ParseIntraModeRow(&dec->br_, dec)) {
- return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
- "Premature end-of-partition0 encountered.");
- }
- for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) {
- if (!VP8DecodeMB(dec, token_br)) {
- return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
- "Premature end-of-file encountered.");
- }
- }
- VP8InitScanline(dec); // Prepare for next scanline
-
- // Reconstruct, filter and emit the row.
- if (!VP8ProcessRow(dec, io)) {
- return VP8SetError(dec, VP8_STATUS_USER_ABORT, "Output aborted.");
- }
- }
- if (dec->mt_method_ > 0) {
- if (!WebPGetWorkerInterface()->Sync(&dec->worker_)) return 0;
- }
-
- return 1;
-}
-
-// Main entry point
-int VP8Decode(VP8Decoder* const dec, VP8Io* const io) {
- int ok = 0;
- if (dec == NULL) {
- return 0;
- }
- if (io == NULL) {
- return VP8SetError(dec, VP8_STATUS_INVALID_PARAM,
- "NULL VP8Io parameter in VP8Decode().");
- }
-
- if (!dec->ready_) {
- if (!VP8GetHeaders(dec, io)) {
- return 0;
- }
- }
- assert(dec->ready_);
-
- // Finish setting up the decoding parameter. Will call io->setup().
- ok = (VP8EnterCritical(dec, io) == VP8_STATUS_OK);
- if (ok) { // good to go.
- // Will allocate memory and prepare everything.
- if (ok) ok = VP8InitFrame(dec, io);
-
- // Main decoding loop
- if (ok) ok = ParseFrame(dec, io);
-
- // Exit.
- ok &= VP8ExitCritical(dec, io);
- }
-
- if (!ok) {
- VP8Clear(dec);
- return 0;
- }
-
- dec->ready_ = 0;
- return ok;
-}
-
-void VP8Clear(VP8Decoder* const dec) {
- if (dec == NULL) {
- return;
- }
- WebPGetWorkerInterface()->End(&dec->worker_);
- WebPDeallocateAlphaMemory(dec);
- WebPSafeFree(dec->mem_);
- dec->mem_ = NULL;
- dec->mem_size_ = 0;
- memset(&dec->br_, 0, sizeof(dec->br_));
- dec->ready_ = 0;
-}
-
-//------------------------------------------------------------------------------
diff --git a/thirdparty/libwebp/dec/vp8_dec.h b/thirdparty/libwebp/dec/vp8_dec.h
deleted file mode 100644
index b9337bbec0..0000000000
--- a/thirdparty/libwebp/dec/vp8_dec.h
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright 2010 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.
-// -----------------------------------------------------------------------------
-//
-// Low-level API for VP8 decoder
-//
-// Author: Skal (pascal.massimino@gmail.com)
-
-#ifndef WEBP_WEBP_DECODE_VP8_H_
-#define WEBP_WEBP_DECODE_VP8_H_
-
-#include "../webp/decode.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//------------------------------------------------------------------------------
-// Lower-level API
-//
-// These functions provide fine-grained control of the decoding process.
-// The call flow should resemble:
-//
-// VP8Io io;
-// VP8InitIo(&io);
-// io.data = data;
-// io.data_size = size;
-// /* customize io's functions (setup()/put()/teardown()) if needed. */
-//
-// VP8Decoder* dec = VP8New();
-// bool ok = VP8Decode(dec);
-// if (!ok) printf("Error: %s\n", VP8StatusMessage(dec));
-// VP8Delete(dec);
-// return ok;
-
-// Input / Output
-typedef struct VP8Io VP8Io;
-typedef int (*VP8IoPutHook)(const VP8Io* io);
-typedef int (*VP8IoSetupHook)(VP8Io* io);
-typedef void (*VP8IoTeardownHook)(const VP8Io* io);
-
-struct VP8Io {
- // set by VP8GetHeaders()
- int width, height; // picture dimensions, in pixels (invariable).
- // These are the original, uncropped dimensions.
- // The actual area passed to put() is stored
- // in mb_w / mb_h fields.
-
- // set before calling put()
- int mb_y; // position of the current rows (in pixels)
- int mb_w; // number of columns in the sample
- int mb_h; // number of rows in the sample
- const uint8_t* y, *u, *v; // rows to copy (in yuv420 format)
- int y_stride; // row stride for luma
- int uv_stride; // row stride for chroma
-
- void* opaque; // user data
-
- // called when fresh samples are available. Currently, samples are in
- // YUV420 format, and can be up to width x 24 in size (depending on the
- // in-loop filtering level, e.g.). Should return false in case of error
- // or abort request. The actual size of the area to update is mb_w x mb_h
- // in size, taking cropping into account.
- VP8IoPutHook put;
-
- // called just before starting to decode the blocks.
- // Must return false in case of setup error, true otherwise. If false is
- // returned, teardown() will NOT be called. But if the setup succeeded
- // and true is returned, then teardown() will always be called afterward.
- VP8IoSetupHook setup;
-
- // Called just after block decoding is finished (or when an error occurred
- // during put()). Is NOT called if setup() failed.
- VP8IoTeardownHook teardown;
-
- // this is a recommendation for the user-side yuv->rgb converter. This flag
- // is set when calling setup() hook and can be overwritten by it. It then
- // can be taken into consideration during the put() method.
- int fancy_upsampling;
-
- // Input buffer.
- size_t data_size;
- const uint8_t* data;
-
- // If true, in-loop filtering will not be performed even if present in the
- // bitstream. Switching off filtering may speed up decoding at the expense
- // of more visible blocking. Note that output will also be non-compliant
- // with the VP8 specifications.
- int bypass_filtering;
-
- // Cropping parameters.
- int use_cropping;
- int crop_left, crop_right, crop_top, crop_bottom;
-
- // Scaling parameters.
- int use_scaling;
- int scaled_width, scaled_height;
-
- // If non NULL, pointer to the alpha data (if present) corresponding to the
- // start of the current row (That is: it is pre-offset by mb_y and takes
- // cropping into account).
- const uint8_t* a;
-};
-
-// Internal, version-checked, entry point
-int VP8InitIoInternal(VP8Io* const, int);
-
-// Set the custom IO function pointers and user-data. The setter for IO hooks
-// should be called before initiating incremental decoding. Returns true if
-// WebPIDecoder object is successfully modified, false otherwise.
-int WebPISetIOHooks(WebPIDecoder* const idec,
- VP8IoPutHook put,
- VP8IoSetupHook setup,
- VP8IoTeardownHook teardown,
- void* user_data);
-
-// Main decoding object. This is an opaque structure.
-typedef struct VP8Decoder VP8Decoder;
-
-// Create a new decoder object.
-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
-// decoding function should be called (VP8Decode, VP8GetHeaders, ...)
-static WEBP_INLINE int VP8InitIo(VP8Io* const io) {
- return VP8InitIoInternal(io, WEBP_DECODER_ABI_VERSION);
-}
-
-// Decode the VP8 frame header. Returns true if ok.
-// Note: 'io->data' must be pointing to the start of the VP8 frame header.
-int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io);
-
-// Decode a picture. Will call VP8GetHeaders() if it wasn't done already.
-// Returns false in case of error.
-int VP8Decode(VP8Decoder* const dec, VP8Io* const io);
-
-// Return current status of the decoder:
-VP8StatusCode VP8Status(VP8Decoder* const dec);
-
-// return readable string corresponding to the last status.
-const char* VP8StatusMessage(VP8Decoder* const dec);
-
-// Resets the decoder in its initial state, reclaiming memory.
-// Not a mandatory call between calls to VP8Decode().
-void VP8Clear(VP8Decoder* const dec);
-
-// Destroy the decoder object.
-void VP8Delete(VP8Decoder* const dec);
-
-//------------------------------------------------------------------------------
-// Miscellaneous VP8/VP8L bitstream probing functions.
-
-// Returns true if the next 3 bytes in data contain the VP8 signature.
-WEBP_EXTERN(int) VP8CheckSignature(const uint8_t* const data, size_t data_size);
-
-// Validates the VP8 data-header and retrieves basic header information viz
-// width and height. Returns 0 in case of formatting error. *width/*height
-// can be passed NULL.
-WEBP_EXTERN(int) VP8GetInfo(
- const uint8_t* data,
- size_t data_size, // data available so far
- size_t chunk_size, // total data size expected in the chunk
- int* const width, int* const height);
-
-// Returns true if the next byte(s) in data is a VP8L signature.
-WEBP_EXTERN(int) VP8LCheckSignature(const uint8_t* const data, size_t size);
-
-// Validates the VP8L data-header and retrieves basic header information viz
-// width, height and alpha. Returns 0 in case of formatting error.
-// width/height/has_alpha can be passed NULL.
-WEBP_EXTERN(int) VP8LGetInfo(
- const uint8_t* data, size_t data_size, // data available so far
- int* const width, int* const height, int* const has_alpha);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif /* WEBP_WEBP_DECODE_VP8_H_ */
diff --git a/thirdparty/libwebp/dec/vp8i_dec.h b/thirdparty/libwebp/dec/vp8i_dec.h
deleted file mode 100644
index 555853e8f8..0000000000
--- a/thirdparty/libwebp/dec/vp8i_dec.h
+++ /dev/null
@@ -1,320 +0,0 @@
-// Copyright 2010 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.
-// -----------------------------------------------------------------------------
-//
-// VP8 decoder: internal header.
-//
-// Author: Skal (pascal.massimino@gmail.com)
-
-#ifndef WEBP_DEC_VP8I_H_
-#define WEBP_DEC_VP8I_H_
-
-#include <string.h> // for memcpy()
-#include "./common_dec.h"
-#include "./vp8li_dec.h"
-#include "../utils/bit_reader_utils.h"
-#include "../utils/random_utils.h"
-#include "../utils/thread_utils.h"
-#include "../dsp/dsp.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//------------------------------------------------------------------------------
-// Various defines and enums
-
-// version numbers
-#define DEC_MAJ_VERSION 0
-#define DEC_MIN_VERSION 6
-#define DEC_REV_VERSION 0
-
-// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
-// Constraints are: We need to store one 16x16 block of luma samples (y),
-// and two 8x8 chroma blocks (u/v). These are better be 16-bytes aligned,
-// in order to be SIMD-friendly. We also need to store the top, left and
-// top-left samples (from previously decoded blocks), along with four
-// extra top-right samples for luma (intra4x4 prediction only).
-// One possible layout is, using 32 * (17 + 9) bytes:
-//
-// .+------ <- only 1 pixel high
-// .|yyyyt.
-// .|yyyyt.
-// .|yyyyt.
-// .|yyyy..
-// .+--.+-- <- only 1 pixel high
-// .|uu.|vv
-// .|uu.|vv
-//
-// Every character is a 4x4 block, with legend:
-// '.' = unused
-// 'y' = y-samples 'u' = u-samples 'v' = u-samples
-// '|' = left sample, '-' = top sample, '+' = top-left sample
-// 't' = extra top-right sample for 4x4 modes
-#define YUV_SIZE (BPS * 17 + BPS * 9)
-#define Y_SIZE (BPS * 17)
-#define Y_OFF (BPS * 1 + 8)
-#define U_OFF (Y_OFF + BPS * 16 + BPS)
-#define V_OFF (U_OFF + 16)
-
-// minimal width under which lossy multi-threading is always disabled
-#define MIN_WIDTH_FOR_THREADS 512
-
-//------------------------------------------------------------------------------
-// Headers
-
-typedef struct {
- uint8_t key_frame_;
- uint8_t profile_;
- uint8_t show_;
- uint32_t partition_length_;
-} VP8FrameHeader;
-
-typedef struct {
- uint16_t width_;
- uint16_t height_;
- uint8_t xscale_;
- uint8_t yscale_;
- uint8_t colorspace_; // 0 = YCbCr
- uint8_t clamp_type_;
-} VP8PictureHeader;
-
-// segment features
-typedef struct {
- int use_segment_;
- int update_map_; // whether to update the segment map or not
- int absolute_delta_; // absolute or delta values for quantizer and filter
- int8_t quantizer_[NUM_MB_SEGMENTS]; // quantization changes
- int8_t filter_strength_[NUM_MB_SEGMENTS]; // filter strength for segments
-} VP8SegmentHeader;
-
-// probas associated to one of the contexts
-typedef uint8_t VP8ProbaArray[NUM_PROBAS];
-
-typedef struct { // all the probas associated to one band
- VP8ProbaArray probas_[NUM_CTX];
-} VP8BandProbas;
-
-// Struct collecting all frame-persistent probabilities.
-typedef struct {
- uint8_t segments_[MB_FEATURE_TREE_PROBS];
- // Type: 0:Intra16-AC 1:Intra16-DC 2:Chroma 3:Intra4
- VP8BandProbas bands_[NUM_TYPES][NUM_BANDS];
- const VP8BandProbas* bands_ptr_[NUM_TYPES][16 + 1];
-} VP8Proba;
-
-// Filter parameters
-typedef struct {
- int simple_; // 0=complex, 1=simple
- int level_; // [0..63]
- int sharpness_; // [0..7]
- int use_lf_delta_;
- int ref_lf_delta_[NUM_REF_LF_DELTAS];
- int mode_lf_delta_[NUM_MODE_LF_DELTAS];
-} VP8FilterHeader;
-
-//------------------------------------------------------------------------------
-// Informations about the macroblocks.
-
-typedef struct { // filter specs
- uint8_t f_limit_; // filter limit in [3..189], or 0 if no filtering
- uint8_t f_ilevel_; // inner limit in [1..63]
- uint8_t f_inner_; // do inner filtering?
- uint8_t hev_thresh_; // high edge variance threshold in [0..2]
-} VP8FInfo;
-
-typedef struct { // Top/Left Contexts used for syntax-parsing
- uint8_t nz_; // non-zero AC/DC coeffs (4bit for luma + 4bit for chroma)
- uint8_t nz_dc_; // non-zero DC coeff (1bit)
-} VP8MB;
-
-// Dequantization matrices
-typedef int quant_t[2]; // [DC / AC]. Can be 'uint16_t[2]' too (~slower).
-typedef struct {
- quant_t y1_mat_, y2_mat_, uv_mat_;
-
- int uv_quant_; // U/V quantizer value
- int dither_; // dithering amplitude (0 = off, max=255)
-} VP8QuantMatrix;
-
-// Data needed to reconstruct a macroblock
-typedef struct {
- int16_t coeffs_[384]; // 384 coeffs = (16+4+4) * 4*4
- uint8_t is_i4x4_; // true if intra4x4
- uint8_t imodes_[16]; // one 16x16 mode (#0) or sixteen 4x4 modes
- uint8_t uvmode_; // chroma prediction mode
- // bit-wise info about the content of each sub-4x4 blocks (in decoding order).
- // Each of the 4x4 blocks for y/u/v is associated with a 2b code according to:
- // code=0 -> no coefficient
- // code=1 -> only DC
- // code=2 -> first three coefficients are non-zero
- // code=3 -> more than three coefficients are non-zero
- // This allows to call specialized transform functions.
- uint32_t non_zero_y_;
- uint32_t non_zero_uv_;
- uint8_t dither_; // local dithering strength (deduced from non_zero_*)
- uint8_t skip_;
- uint8_t segment_;
-} VP8MBData;
-
-// Persistent information needed by the parallel processing
-typedef struct {
- int id_; // cache row to process (in [0..2])
- int mb_y_; // macroblock position of the row
- int filter_row_; // true if row-filtering is needed
- VP8FInfo* f_info_; // filter strengths (swapped with dec->f_info_)
- VP8MBData* mb_data_; // reconstruction data (swapped with dec->mb_data_)
- VP8Io io_; // copy of the VP8Io to pass to put()
-} VP8ThreadContext;
-
-// Saved top samples, per macroblock. Fits into a cache-line.
-typedef struct {
- uint8_t y[16], u[8], v[8];
-} VP8TopSamples;
-
-//------------------------------------------------------------------------------
-// VP8Decoder: the main opaque structure handed over to user
-
-struct VP8Decoder {
- VP8StatusCode status_;
- int ready_; // true if ready to decode a picture with VP8Decode()
- const char* error_msg_; // set when status_ is not OK.
-
- // Main data source
- VP8BitReader br_;
-
- // headers
- VP8FrameHeader frm_hdr_;
- VP8PictureHeader pic_hdr_;
- VP8FilterHeader filter_hdr_;
- VP8SegmentHeader segment_hdr_;
-
- // Worker
- WebPWorker worker_;
- int mt_method_; // multi-thread method: 0=off, 1=[parse+recon][filter]
- // 2=[parse][recon+filter]
- int cache_id_; // current cache row
- int num_caches_; // number of cached rows of 16 pixels (1, 2 or 3)
- VP8ThreadContext thread_ctx_; // Thread context
-
- // dimension, in macroblock units.
- int mb_w_, mb_h_;
-
- // Macroblock to process/filter, depending on cropping and filter_type.
- int tl_mb_x_, tl_mb_y_; // top-left MB that must be in-loop filtered
- int br_mb_x_, br_mb_y_; // last bottom-right MB that must be decoded
-
- // number of partitions minus one.
- uint32_t num_parts_minus_one_;
- // per-partition boolean decoders.
- VP8BitReader parts_[MAX_NUM_PARTITIONS];
-
- // Dithering strength, deduced from decoding options
- int dither_; // whether to use dithering or not
- VP8Random dithering_rg_; // random generator for dithering
-
- // dequantization (one set of DC/AC dequant factor per segment)
- VP8QuantMatrix dqm_[NUM_MB_SEGMENTS];
-
- // probabilities
- VP8Proba proba_;
- int use_skip_proba_;
- uint8_t skip_p_;
-
- // Boundary data cache and persistent buffers.
- uint8_t* intra_t_; // top intra modes values: 4 * mb_w_
- uint8_t intra_l_[4]; // left intra modes values
-
- VP8TopSamples* yuv_t_; // top y/u/v samples
-
- VP8MB* mb_info_; // contextual macroblock info (mb_w_ + 1)
- VP8FInfo* f_info_; // filter strength info
- uint8_t* yuv_b_; // main block for Y/U/V (size = YUV_SIZE)
-
- uint8_t* cache_y_; // macroblock row for storing unfiltered samples
- uint8_t* cache_u_;
- uint8_t* cache_v_;
- int cache_y_stride_;
- int cache_uv_stride_;
-
- // main memory chunk for the above data. Persistent.
- void* mem_;
- size_t mem_size_;
-
- // Per macroblock non-persistent infos.
- int mb_x_, mb_y_; // current position, in macroblock units
- VP8MBData* mb_data_; // parsed reconstruction data
-
- // Filtering side-info
- int filter_type_; // 0=off, 1=simple, 2=complex
- VP8FInfo fstrengths_[NUM_MB_SEGMENTS][2]; // precalculated per-segment/type
-
- // Alpha
- struct ALPHDecoder* alph_dec_; // alpha-plane decoder object
- const uint8_t* alpha_data_; // compressed alpha data (if present)
- size_t alpha_data_size_;
- int is_alpha_decoded_; // true if alpha_data_ is decoded in alpha_plane_
- uint8_t* alpha_plane_mem_; // memory allocated for alpha_plane_
- uint8_t* alpha_plane_; // output. Persistent, contains the whole data.
- const uint8_t* alpha_prev_line_; // last decoded alpha row (or NULL)
- int alpha_dithering_; // derived from decoding options (0=off, 100=full)
-};
-
-//------------------------------------------------------------------------------
-// internal functions. Not public.
-
-// in vp8.c
-int VP8SetError(VP8Decoder* const dec,
- VP8StatusCode error, const char* const msg);
-
-// in tree.c
-void VP8ResetProba(VP8Proba* const proba);
-void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec);
-// parses one row of intra mode data in partition 0, returns !eof
-int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec);
-
-// in quant.c
-void VP8ParseQuant(VP8Decoder* const dec);
-
-// in frame.c
-int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io);
-// Call io->setup() and finish setting up scan parameters.
-// After this call returns, one must always call VP8ExitCritical() with the
-// same parameters. Both functions should be used in pair. Returns VP8_STATUS_OK
-// if ok, otherwise sets and returns the error status on *dec.
-VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io);
-// Must always be called in pair with VP8EnterCritical().
-// Returns false in case of error.
-int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io);
-// Return the multi-threading method to use (0=off), depending
-// on options and bitstream size. Only for lossy decoding.
-int VP8GetThreadMethod(const WebPDecoderOptions* const options,
- const WebPHeaderStructure* const headers,
- int width, int height);
-// Initialize dithering post-process if needed.
-void VP8InitDithering(const WebPDecoderOptions* const options,
- VP8Decoder* const dec);
-// Process the last decoded row (filtering + output).
-int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io);
-// To be called at the start of a new scanline, to initialize predictors.
-void VP8InitScanline(VP8Decoder* const dec);
-// Decode one macroblock. Returns false if there is not enough data.
-int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br);
-
-// in alpha.c
-const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
- const VP8Io* const io,
- int row, int num_rows);
-
-//------------------------------------------------------------------------------
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif /* WEBP_DEC_VP8I_H_ */
diff --git a/thirdparty/libwebp/dec/vp8l_dec.c b/thirdparty/libwebp/dec/vp8l_dec.c
deleted file mode 100644
index ef359a91f0..0000000000
--- a/thirdparty/libwebp/dec/vp8l_dec.c
+++ /dev/null
@@ -1,1671 +0,0 @@
-// Copyright 2012 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.
-// -----------------------------------------------------------------------------
-//
-// main entry for the decoder
-//
-// Authors: Vikas Arora (vikaas.arora@gmail.com)
-// Jyrki Alakuijala (jyrki@google.com)
-
-#include <stdlib.h>
-
-#include "./alphai_dec.h"
-#include "./vp8li_dec.h"
-#include "../dsp/dsp.h"
-#include "../dsp/lossless.h"
-#include "../dsp/lossless_common.h"
-#include "../dsp/yuv.h"
-#include "../utils/endian_inl_utils.h"
-#include "../utils/huffman_utils.h"
-#include "../utils/utils.h"
-
-#define NUM_ARGB_CACHE_ROWS 16
-
-static const int kCodeLengthLiterals = 16;
-static const int kCodeLengthRepeatCode = 16;
-static const int kCodeLengthExtraBits[3] = { 2, 3, 7 };
-static const int kCodeLengthRepeatOffsets[3] = { 3, 3, 11 };
-
-// -----------------------------------------------------------------------------
-// Five Huffman codes are used at each meta code:
-// 1. green + length prefix codes + color cache codes,
-// 2. alpha,
-// 3. red,
-// 4. blue, and,
-// 5. distance prefix codes.
-typedef enum {
- GREEN = 0,
- RED = 1,
- BLUE = 2,
- ALPHA = 3,
- DIST = 4
-} HuffIndex;
-
-static const uint16_t kAlphabetSize[HUFFMAN_CODES_PER_META_CODE] = {
- NUM_LITERAL_CODES + NUM_LENGTH_CODES,
- NUM_LITERAL_CODES, NUM_LITERAL_CODES, NUM_LITERAL_CODES,
- NUM_DISTANCE_CODES
-};
-
-static const uint8_t kLiteralMap[HUFFMAN_CODES_PER_META_CODE] = {
- 0, 1, 1, 1, 0
-};
-
-#define NUM_CODE_LENGTH_CODES 19
-static const uint8_t kCodeLengthCodeOrder[NUM_CODE_LENGTH_CODES] = {
- 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
-};
-
-#define CODE_TO_PLANE_CODES 120
-static const uint8_t kCodeToPlane[CODE_TO_PLANE_CODES] = {
- 0x18, 0x07, 0x17, 0x19, 0x28, 0x06, 0x27, 0x29, 0x16, 0x1a,
- 0x26, 0x2a, 0x38, 0x05, 0x37, 0x39, 0x15, 0x1b, 0x36, 0x3a,
- 0x25, 0x2b, 0x48, 0x04, 0x47, 0x49, 0x14, 0x1c, 0x35, 0x3b,
- 0x46, 0x4a, 0x24, 0x2c, 0x58, 0x45, 0x4b, 0x34, 0x3c, 0x03,
- 0x57, 0x59, 0x13, 0x1d, 0x56, 0x5a, 0x23, 0x2d, 0x44, 0x4c,
- 0x55, 0x5b, 0x33, 0x3d, 0x68, 0x02, 0x67, 0x69, 0x12, 0x1e,
- 0x66, 0x6a, 0x22, 0x2e, 0x54, 0x5c, 0x43, 0x4d, 0x65, 0x6b,
- 0x32, 0x3e, 0x78, 0x01, 0x77, 0x79, 0x53, 0x5d, 0x11, 0x1f,
- 0x64, 0x6c, 0x42, 0x4e, 0x76, 0x7a, 0x21, 0x2f, 0x75, 0x7b,
- 0x31, 0x3f, 0x63, 0x6d, 0x52, 0x5e, 0x00, 0x74, 0x7c, 0x41,
- 0x4f, 0x10, 0x20, 0x62, 0x6e, 0x30, 0x73, 0x7d, 0x51, 0x5f,
- 0x40, 0x72, 0x7e, 0x61, 0x6f, 0x50, 0x71, 0x7f, 0x60, 0x70
-};
-
-// Memory needed for lookup tables of one Huffman tree group. Red, blue, alpha
-// and distance alphabets are constant (256 for red, blue and alpha, 40 for
-// distance) and lookup table sizes for them in worst case are 630 and 410
-// respectively. Size of green alphabet depends on color cache size and is equal
-// to 256 (green component values) + 24 (length prefix values)
-// + color_cache_size (between 0 and 2048).
-// All values computed for 8-bit first level lookup with Mark Adler's tool:
-// http://www.hdfgroup.org/ftp/lib-external/zlib/zlib-1.2.5/examples/enough.c
-#define FIXED_TABLE_SIZE (630 * 3 + 410)
-static const int kTableSize[12] = {
- FIXED_TABLE_SIZE + 654,
- FIXED_TABLE_SIZE + 656,
- FIXED_TABLE_SIZE + 658,
- FIXED_TABLE_SIZE + 662,
- FIXED_TABLE_SIZE + 670,
- FIXED_TABLE_SIZE + 686,
- FIXED_TABLE_SIZE + 718,
- FIXED_TABLE_SIZE + 782,
- FIXED_TABLE_SIZE + 912,
- FIXED_TABLE_SIZE + 1168,
- FIXED_TABLE_SIZE + 1680,
- FIXED_TABLE_SIZE + 2704
-};
-
-static int DecodeImageStream(int xsize, int ysize,
- int is_level0,
- VP8LDecoder* const dec,
- uint32_t** const decoded_data);
-
-//------------------------------------------------------------------------------
-
-int VP8LCheckSignature(const uint8_t* const data, size_t size) {
- return (size >= VP8L_FRAME_HEADER_SIZE &&
- data[0] == VP8L_MAGIC_BYTE &&
- (data[4] >> 5) == 0); // version
-}
-
-static int ReadImageInfo(VP8LBitReader* const br,
- int* const width, int* const height,
- int* const has_alpha) {
- if (VP8LReadBits(br, 8) != VP8L_MAGIC_BYTE) return 0;
- *width = VP8LReadBits(br, VP8L_IMAGE_SIZE_BITS) + 1;
- *height = VP8LReadBits(br, VP8L_IMAGE_SIZE_BITS) + 1;
- *has_alpha = VP8LReadBits(br, 1);
- if (VP8LReadBits(br, VP8L_VERSION_BITS) != 0) return 0;
- return !br->eos_;
-}
-
-int VP8LGetInfo(const uint8_t* data, size_t data_size,
- int* const width, int* const height, int* const has_alpha) {
- if (data == NULL || data_size < VP8L_FRAME_HEADER_SIZE) {
- return 0; // not enough data
- } else if (!VP8LCheckSignature(data, data_size)) {
- return 0; // bad signature
- } else {
- int w, h, a;
- VP8LBitReader br;
- VP8LInitBitReader(&br, data, data_size);
- if (!ReadImageInfo(&br, &w, &h, &a)) {
- return 0;
- }
- if (width != NULL) *width = w;
- if (height != NULL) *height = h;
- if (has_alpha != NULL) *has_alpha = a;
- return 1;
- }
-}
-
-//------------------------------------------------------------------------------
-
-static WEBP_INLINE int GetCopyDistance(int distance_symbol,
- VP8LBitReader* const br) {
- int extra_bits, offset;
- if (distance_symbol < 4) {
- return distance_symbol + 1;
- }
- extra_bits = (distance_symbol - 2) >> 1;
- offset = (2 + (distance_symbol & 1)) << extra_bits;
- return offset + VP8LReadBits(br, extra_bits) + 1;
-}
-
-static WEBP_INLINE int GetCopyLength(int length_symbol,
- VP8LBitReader* const br) {
- // Length and distance prefixes are encoded the same way.
- return GetCopyDistance(length_symbol, br);
-}
-
-static WEBP_INLINE int PlaneCodeToDistance(int xsize, int plane_code) {
- if (plane_code > CODE_TO_PLANE_CODES) {
- return plane_code - CODE_TO_PLANE_CODES;
- } else {
- const int dist_code = kCodeToPlane[plane_code - 1];
- const int yoffset = dist_code >> 4;
- const int xoffset = 8 - (dist_code & 0xf);
- const int dist = yoffset * xsize + xoffset;
- return (dist >= 1) ? dist : 1; // dist<1 can happen if xsize is very small
- }
-}
-
-//------------------------------------------------------------------------------
-// Decodes the next Huffman code from bit-stream.
-// FillBitWindow(br) needs to be called at minimum every second call
-// to ReadSymbol, in order to pre-fetch enough bits.
-static WEBP_INLINE int ReadSymbol(const HuffmanCode* table,
- VP8LBitReader* const br) {
- int nbits;
- uint32_t val = VP8LPrefetchBits(br);
- table += val & HUFFMAN_TABLE_MASK;
- nbits = table->bits - HUFFMAN_TABLE_BITS;
- if (nbits > 0) {
- VP8LSetBitPos(br, br->bit_pos_ + HUFFMAN_TABLE_BITS);
- val = VP8LPrefetchBits(br);
- table += table->value;
- table += val & ((1 << nbits) - 1);
- }
- VP8LSetBitPos(br, br->bit_pos_ + table->bits);
- return table->value;
-}
-
-// Reads packed symbol depending on GREEN channel
-#define BITS_SPECIAL_MARKER 0x100 // something large enough (and a bit-mask)
-#define PACKED_NON_LITERAL_CODE 0 // must be < NUM_LITERAL_CODES
-static WEBP_INLINE int ReadPackedSymbols(const HTreeGroup* group,
- VP8LBitReader* const br,
- uint32_t* const dst) {
- const uint32_t val = VP8LPrefetchBits(br) & (HUFFMAN_PACKED_TABLE_SIZE - 1);
- const HuffmanCode32 code = group->packed_table[val];
- assert(group->use_packed_table);
- if (code.bits < BITS_SPECIAL_MARKER) {
- VP8LSetBitPos(br, br->bit_pos_ + code.bits);
- *dst = code.value;
- return PACKED_NON_LITERAL_CODE;
- } else {
- VP8LSetBitPos(br, br->bit_pos_ + code.bits - BITS_SPECIAL_MARKER);
- assert(code.value >= NUM_LITERAL_CODES);
- return code.value;
- }
-}
-
-static int AccumulateHCode(HuffmanCode hcode, int shift,
- HuffmanCode32* const huff) {
- huff->bits += hcode.bits;
- huff->value |= (uint32_t)hcode.value << shift;
- assert(huff->bits <= HUFFMAN_TABLE_BITS);
- return hcode.bits;
-}
-
-static void BuildPackedTable(HTreeGroup* const htree_group) {
- uint32_t code;
- for (code = 0; code < HUFFMAN_PACKED_TABLE_SIZE; ++code) {
- uint32_t bits = code;
- HuffmanCode32* const huff = &htree_group->packed_table[bits];
- HuffmanCode hcode = htree_group->htrees[GREEN][bits];
- if (hcode.value >= NUM_LITERAL_CODES) {
- huff->bits = hcode.bits + BITS_SPECIAL_MARKER;
- huff->value = hcode.value;
- } else {
- huff->bits = 0;
- huff->value = 0;
- bits >>= AccumulateHCode(hcode, 8, huff);
- bits >>= AccumulateHCode(htree_group->htrees[RED][bits], 16, huff);
- bits >>= AccumulateHCode(htree_group->htrees[BLUE][bits], 0, huff);
- bits >>= AccumulateHCode(htree_group->htrees[ALPHA][bits], 24, huff);
- (void)bits;
- }
- }
-}
-
-static int ReadHuffmanCodeLengths(
- VP8LDecoder* const dec, const int* const code_length_code_lengths,
- int num_symbols, int* const code_lengths) {
- int ok = 0;
- VP8LBitReader* const br = &dec->br_;
- int symbol;
- int max_symbol;
- int prev_code_len = DEFAULT_CODE_LENGTH;
- HuffmanCode table[1 << LENGTHS_TABLE_BITS];
-
- if (!VP8LBuildHuffmanTable(table, LENGTHS_TABLE_BITS,
- code_length_code_lengths,
- NUM_CODE_LENGTH_CODES)) {
- goto End;
- }
-
- if (VP8LReadBits(br, 1)) { // use length
- const int length_nbits = 2 + 2 * VP8LReadBits(br, 3);
- max_symbol = 2 + VP8LReadBits(br, length_nbits);
- if (max_symbol > num_symbols) {
- goto End;
- }
- } else {
- max_symbol = num_symbols;
- }
-
- symbol = 0;
- while (symbol < num_symbols) {
- const HuffmanCode* p;
- int code_len;
- if (max_symbol-- == 0) break;
- VP8LFillBitWindow(br);
- p = &table[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK];
- VP8LSetBitPos(br, br->bit_pos_ + p->bits);
- code_len = p->value;
- if (code_len < kCodeLengthLiterals) {
- code_lengths[symbol++] = code_len;
- if (code_len != 0) prev_code_len = code_len;
- } else {
- const int use_prev = (code_len == kCodeLengthRepeatCode);
- const int slot = code_len - kCodeLengthLiterals;
- const int extra_bits = kCodeLengthExtraBits[slot];
- const int repeat_offset = kCodeLengthRepeatOffsets[slot];
- int repeat = VP8LReadBits(br, extra_bits) + repeat_offset;
- if (symbol + repeat > num_symbols) {
- goto End;
- } else {
- const int length = use_prev ? prev_code_len : 0;
- while (repeat-- > 0) code_lengths[symbol++] = length;
- }
- }
- }
- ok = 1;
-
- End:
- if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
- return ok;
-}
-
-// 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman
-// tree.
-static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
- int* const code_lengths, HuffmanCode* const table) {
- int ok = 0;
- int size = 0;
- VP8LBitReader* const br = &dec->br_;
- const int simple_code = VP8LReadBits(br, 1);
-
- memset(code_lengths, 0, alphabet_size * sizeof(*code_lengths));
-
- if (simple_code) { // Read symbols, codes & code lengths directly.
- const int num_symbols = VP8LReadBits(br, 1) + 1;
- const int first_symbol_len_code = VP8LReadBits(br, 1);
- // The first code is either 1 bit or 8 bit code.
- int symbol = VP8LReadBits(br, (first_symbol_len_code == 0) ? 1 : 8);
- code_lengths[symbol] = 1;
- // The second code (if present), is always 8 bit long.
- if (num_symbols == 2) {
- symbol = VP8LReadBits(br, 8);
- code_lengths[symbol] = 1;
- }
- ok = 1;
- } else { // Decode Huffman-coded code lengths.
- int i;
- int code_length_code_lengths[NUM_CODE_LENGTH_CODES] = { 0 };
- const int num_codes = VP8LReadBits(br, 4) + 4;
- if (num_codes > NUM_CODE_LENGTH_CODES) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
- return 0;
- }
-
- for (i = 0; i < num_codes; ++i) {
- code_length_code_lengths[kCodeLengthCodeOrder[i]] = VP8LReadBits(br, 3);
- }
- ok = ReadHuffmanCodeLengths(dec, code_length_code_lengths, alphabet_size,
- code_lengths);
- }
-
- ok = ok && !br->eos_;
- if (ok) {
- size = VP8LBuildHuffmanTable(table, HUFFMAN_TABLE_BITS,
- code_lengths, alphabet_size);
- }
- if (!ok || size == 0) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
- return 0;
- }
- return size;
-}
-
-static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
- int color_cache_bits, int allow_recursion) {
- int i, j;
- VP8LBitReader* const br = &dec->br_;
- VP8LMetadata* const hdr = &dec->hdr_;
- uint32_t* huffman_image = NULL;
- HTreeGroup* htree_groups = NULL;
- HuffmanCode* huffman_tables = NULL;
- HuffmanCode* next = NULL;
- int num_htree_groups = 1;
- int max_alphabet_size = 0;
- int* code_lengths = NULL;
- const int table_size = kTableSize[color_cache_bits];
-
- if (allow_recursion && VP8LReadBits(br, 1)) {
- // use meta Huffman codes.
- const int huffman_precision = VP8LReadBits(br, 3) + 2;
- const int huffman_xsize = VP8LSubSampleSize(xsize, huffman_precision);
- const int huffman_ysize = VP8LSubSampleSize(ysize, huffman_precision);
- const int huffman_pixs = huffman_xsize * huffman_ysize;
- if (!DecodeImageStream(huffman_xsize, huffman_ysize, 0, dec,
- &huffman_image)) {
- goto Error;
- }
- hdr->huffman_subsample_bits_ = huffman_precision;
- for (i = 0; i < huffman_pixs; ++i) {
- // The huffman data is stored in red and green bytes.
- const int group = (huffman_image[i] >> 8) & 0xffff;
- huffman_image[i] = group;
- if (group >= num_htree_groups) {
- num_htree_groups = group + 1;
- }
- }
- }
-
- if (br->eos_) goto Error;
-
- // Find maximum alphabet size for the htree group.
- for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
- int alphabet_size = kAlphabetSize[j];
- if (j == 0 && color_cache_bits > 0) {
- alphabet_size += 1 << color_cache_bits;
- }
- if (max_alphabet_size < alphabet_size) {
- max_alphabet_size = alphabet_size;
- }
- }
-
- huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
- sizeof(*huffman_tables));
- htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
- code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
- sizeof(*code_lengths));
-
- if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- goto Error;
- }
-
- next = huffman_tables;
- for (i = 0; i < num_htree_groups; ++i) {
- HTreeGroup* const htree_group = &htree_groups[i];
- HuffmanCode** const htrees = htree_group->htrees;
- int size;
- int total_size = 0;
- int is_trivial_literal = 1;
- int max_bits = 0;
- for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
- int alphabet_size = kAlphabetSize[j];
- htrees[j] = next;
- if (j == 0 && color_cache_bits > 0) {
- alphabet_size += 1 << color_cache_bits;
- }
- size = ReadHuffmanCode(alphabet_size, dec, code_lengths, next);
- if (size == 0) {
- goto Error;
- }
- if (is_trivial_literal && kLiteralMap[j] == 1) {
- is_trivial_literal = (next->bits == 0);
- }
- total_size += next->bits;
- next += size;
- if (j <= ALPHA) {
- int local_max_bits = code_lengths[0];
- int k;
- for (k = 1; k < alphabet_size; ++k) {
- if (code_lengths[k] > local_max_bits) {
- local_max_bits = code_lengths[k];
- }
- }
- max_bits += local_max_bits;
- }
- }
- htree_group->is_trivial_literal = is_trivial_literal;
- htree_group->is_trivial_code = 0;
- if (is_trivial_literal) {
- const int red = htrees[RED][0].value;
- const int blue = htrees[BLUE][0].value;
- const int alpha = htrees[ALPHA][0].value;
- htree_group->literal_arb =
- ((uint32_t)alpha << 24) | (red << 16) | blue;
- if (total_size == 0 && htrees[GREEN][0].value < NUM_LITERAL_CODES) {
- htree_group->is_trivial_code = 1;
- htree_group->literal_arb |= htrees[GREEN][0].value << 8;
- }
- }
- htree_group->use_packed_table = !htree_group->is_trivial_code &&
- (max_bits < HUFFMAN_PACKED_BITS);
- if (htree_group->use_packed_table) BuildPackedTable(htree_group);
- }
- WebPSafeFree(code_lengths);
-
- // All OK. Finalize pointers and return.
- hdr->huffman_image_ = huffman_image;
- hdr->num_htree_groups_ = num_htree_groups;
- hdr->htree_groups_ = htree_groups;
- hdr->huffman_tables_ = huffman_tables;
- return 1;
-
- Error:
- WebPSafeFree(code_lengths);
- WebPSafeFree(huffman_image);
- WebPSafeFree(huffman_tables);
- VP8LHtreeGroupsFree(htree_groups);
- return 0;
-}
-
-//------------------------------------------------------------------------------
-// Scaling.
-
-static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
- const int num_channels = 4;
- const int in_width = io->mb_w;
- const int out_width = io->scaled_width;
- const int in_height = io->mb_h;
- const int out_height = io->scaled_height;
- const uint64_t work_size = 2 * num_channels * (uint64_t)out_width;
- rescaler_t* work; // Rescaler work area.
- const uint64_t scaled_data_size = (uint64_t)out_width;
- uint32_t* scaled_data; // Temporary storage for scaled BGRA data.
- const uint64_t memory_size = sizeof(*dec->rescaler) +
- work_size * sizeof(*work) +
- scaled_data_size * sizeof(*scaled_data);
- uint8_t* memory = (uint8_t*)WebPSafeMalloc(memory_size, sizeof(*memory));
- if (memory == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- return 0;
- }
- assert(dec->rescaler_memory == NULL);
- dec->rescaler_memory = memory;
-
- dec->rescaler = (WebPRescaler*)memory;
- memory += sizeof(*dec->rescaler);
- work = (rescaler_t*)memory;
- memory += work_size * sizeof(*work);
- scaled_data = (uint32_t*)memory;
-
- WebPRescalerInit(dec->rescaler, in_width, in_height, (uint8_t*)scaled_data,
- out_width, out_height, 0, num_channels, work);
- return 1;
-}
-
-//------------------------------------------------------------------------------
-// Export to ARGB
-
-// We have special "export" function since we need to convert from BGRA
-static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace,
- int rgba_stride, uint8_t* const rgba) {
- uint32_t* const src = (uint32_t*)rescaler->dst;
- const int dst_width = rescaler->dst_width;
- int num_lines_out = 0;
- while (WebPRescalerHasPendingOutput(rescaler)) {
- uint8_t* const dst = rgba + num_lines_out * rgba_stride;
- WebPRescalerExportRow(rescaler);
- WebPMultARGBRow(src, dst_width, 1);
- VP8LConvertFromBGRA(src, dst_width, colorspace, dst);
- ++num_lines_out;
- }
- return num_lines_out;
-}
-
-// Emit scaled rows.
-static int EmitRescaledRowsRGBA(const VP8LDecoder* const dec,
- uint8_t* in, int in_stride, int mb_h,
- uint8_t* const out, int out_stride) {
- const WEBP_CSP_MODE colorspace = dec->output_->colorspace;
- int num_lines_in = 0;
- int num_lines_out = 0;
- while (num_lines_in < mb_h) {
- uint8_t* const row_in = in + num_lines_in * in_stride;
- uint8_t* const row_out = out + num_lines_out * out_stride;
- const int lines_left = mb_h - num_lines_in;
- const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left);
- int lines_imported;
- assert(needed_lines > 0 && needed_lines <= lines_left);
- WebPMultARGBRows(row_in, in_stride,
- dec->rescaler->src_width, needed_lines, 0);
- lines_imported =
- WebPRescalerImport(dec->rescaler, lines_left, row_in, in_stride);
- assert(lines_imported == needed_lines);
- num_lines_in += lines_imported;
- num_lines_out += Export(dec->rescaler, colorspace, out_stride, row_out);
- }
- return num_lines_out;
-}
-
-// Emit rows without any scaling.
-static int EmitRows(WEBP_CSP_MODE colorspace,
- const uint8_t* row_in, int in_stride,
- int mb_w, int mb_h,
- uint8_t* const out, int out_stride) {
- int lines = mb_h;
- uint8_t* row_out = out;
- while (lines-- > 0) {
- VP8LConvertFromBGRA((const uint32_t*)row_in, mb_w, colorspace, row_out);
- row_in += in_stride;
- row_out += out_stride;
- }
- return mb_h; // Num rows out == num rows in.
-}
-
-//------------------------------------------------------------------------------
-// Export to YUVA
-
-static void ConvertToYUVA(const uint32_t* const src, int width, int y_pos,
- const WebPDecBuffer* const output) {
- const WebPYUVABuffer* const buf = &output->u.YUVA;
-
- // first, the luma plane
- WebPConvertARGBToY(src, buf->y + y_pos * buf->y_stride, width);
-
- // then U/V planes
- {
- uint8_t* const u = buf->u + (y_pos >> 1) * buf->u_stride;
- uint8_t* const v = buf->v + (y_pos >> 1) * buf->v_stride;
- // even lines: store values
- // odd lines: average with previous values
- WebPConvertARGBToUV(src, u, v, width, !(y_pos & 1));
- }
- // Lastly, store alpha if needed.
- if (buf->a != NULL) {
- uint8_t* const a = buf->a + y_pos * buf->a_stride;
-#if defined(WORDS_BIGENDIAN)
- WebPExtractAlpha((uint8_t*)src + 0, 0, width, 1, a, 0);
-#else
- WebPExtractAlpha((uint8_t*)src + 3, 0, width, 1, a, 0);
-#endif
- }
-}
-
-static int ExportYUVA(const VP8LDecoder* const dec, int y_pos) {
- WebPRescaler* const rescaler = dec->rescaler;
- uint32_t* const src = (uint32_t*)rescaler->dst;
- const int dst_width = rescaler->dst_width;
- int num_lines_out = 0;
- while (WebPRescalerHasPendingOutput(rescaler)) {
- WebPRescalerExportRow(rescaler);
- WebPMultARGBRow(src, dst_width, 1);
- ConvertToYUVA(src, dst_width, y_pos, dec->output_);
- ++y_pos;
- ++num_lines_out;
- }
- return num_lines_out;
-}
-
-static int EmitRescaledRowsYUVA(const VP8LDecoder* const dec,
- uint8_t* in, int in_stride, int mb_h) {
- int num_lines_in = 0;
- int y_pos = dec->last_out_row_;
- while (num_lines_in < mb_h) {
- const int lines_left = mb_h - num_lines_in;
- const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left);
- int lines_imported;
- WebPMultARGBRows(in, in_stride, dec->rescaler->src_width, needed_lines, 0);
- lines_imported =
- WebPRescalerImport(dec->rescaler, lines_left, in, in_stride);
- assert(lines_imported == needed_lines);
- num_lines_in += lines_imported;
- in += needed_lines * in_stride;
- y_pos += ExportYUVA(dec, y_pos);
- }
- return y_pos;
-}
-
-static int EmitRowsYUVA(const VP8LDecoder* const dec,
- const uint8_t* in, int in_stride,
- int mb_w, int num_rows) {
- int y_pos = dec->last_out_row_;
- while (num_rows-- > 0) {
- ConvertToYUVA((const uint32_t*)in, mb_w, y_pos, dec->output_);
- in += in_stride;
- ++y_pos;
- }
- return y_pos;
-}
-
-//------------------------------------------------------------------------------
-// Cropping.
-
-// Sets io->mb_y, io->mb_h & io->mb_w according to start row, end row and
-// crop options. Also updates the input data pointer, so that it points to the
-// start of the cropped window. Note that pixels are in ARGB format even if
-// 'in_data' is uint8_t*.
-// Returns true if the crop window is not empty.
-static int SetCropWindow(VP8Io* const io, int y_start, int y_end,
- uint8_t** const in_data, int pixel_stride) {
- assert(y_start < y_end);
- assert(io->crop_left < io->crop_right);
- if (y_end > io->crop_bottom) {
- y_end = io->crop_bottom; // make sure we don't overflow on last row.
- }
- if (y_start < io->crop_top) {
- const int delta = io->crop_top - y_start;
- y_start = io->crop_top;
- *in_data += delta * pixel_stride;
- }
- if (y_start >= y_end) return 0; // Crop window is empty.
-
- *in_data += io->crop_left * sizeof(uint32_t);
-
- io->mb_y = y_start - io->crop_top;
- io->mb_w = io->crop_right - io->crop_left;
- io->mb_h = y_end - y_start;
- return 1; // Non-empty crop window.
-}
-
-//------------------------------------------------------------------------------
-
-static WEBP_INLINE int GetMetaIndex(
- const uint32_t* const image, int xsize, int bits, int x, int y) {
- if (bits == 0) return 0;
- return image[xsize * (y >> bits) + (x >> bits)];
-}
-
-static WEBP_INLINE HTreeGroup* GetHtreeGroupForPos(VP8LMetadata* const hdr,
- int x, int y) {
- const int meta_index = GetMetaIndex(hdr->huffman_image_, hdr->huffman_xsize_,
- hdr->huffman_subsample_bits_, x, y);
- assert(meta_index < hdr->num_htree_groups_);
- return hdr->htree_groups_ + meta_index;
-}
-
-//------------------------------------------------------------------------------
-// Main loop, with custom row-processing function
-
-typedef void (*ProcessRowsFunc)(VP8LDecoder* const dec, int row);
-
-static void ApplyInverseTransforms(VP8LDecoder* const dec, int num_rows,
- const uint32_t* const rows) {
- int n = dec->next_transform_;
- const int cache_pixs = dec->width_ * num_rows;
- const int start_row = dec->last_row_;
- const int end_row = start_row + num_rows;
- const uint32_t* rows_in = rows;
- uint32_t* const rows_out = dec->argb_cache_;
-
- // Inverse transforms.
- while (n-- > 0) {
- VP8LTransform* const transform = &dec->transforms_[n];
- VP8LInverseTransform(transform, start_row, end_row, rows_in, rows_out);
- rows_in = rows_out;
- }
- if (rows_in != rows_out) {
- // No transform called, hence just copy.
- memcpy(rows_out, rows_in, cache_pixs * sizeof(*rows_out));
- }
-}
-
-// Processes (transforms, scales & color-converts) the rows decoded after the
-// last call.
-static void ProcessRows(VP8LDecoder* const dec, int row) {
- const uint32_t* const rows = dec->pixels_ + dec->width_ * dec->last_row_;
- const int num_rows = row - dec->last_row_;
-
- assert(row <= dec->io_->crop_bottom);
- // We can't process more than NUM_ARGB_CACHE_ROWS at a time (that's the size
- // of argb_cache_), but we currently don't need more than that.
- assert(num_rows <= NUM_ARGB_CACHE_ROWS);
- if (num_rows > 0) { // Emit output.
- VP8Io* const io = dec->io_;
- uint8_t* rows_data = (uint8_t*)dec->argb_cache_;
- const int in_stride = io->width * sizeof(uint32_t); // in unit of RGBA
-
- ApplyInverseTransforms(dec, num_rows, rows);
- if (!SetCropWindow(io, dec->last_row_, row, &rows_data, in_stride)) {
- // Nothing to output (this time).
- } else {
- const WebPDecBuffer* const output = dec->output_;
- if (WebPIsRGBMode(output->colorspace)) { // convert to RGBA
- const WebPRGBABuffer* const buf = &output->u.RGBA;
- uint8_t* const rgba = buf->rgba + dec->last_out_row_ * buf->stride;
- const int num_rows_out = io->use_scaling ?
- EmitRescaledRowsRGBA(dec, rows_data, in_stride, io->mb_h,
- rgba, buf->stride) :
- EmitRows(output->colorspace, rows_data, in_stride,
- io->mb_w, io->mb_h, rgba, buf->stride);
- // Update 'last_out_row_'.
- dec->last_out_row_ += num_rows_out;
- } else { // convert to YUVA
- dec->last_out_row_ = io->use_scaling ?
- EmitRescaledRowsYUVA(dec, rows_data, in_stride, io->mb_h) :
- EmitRowsYUVA(dec, rows_data, in_stride, io->mb_w, io->mb_h);
- }
- assert(dec->last_out_row_ <= output->height);
- }
- }
-
- // Update 'last_row_'.
- dec->last_row_ = row;
- assert(dec->last_row_ <= dec->height_);
-}
-
-// Row-processing for the special case when alpha data contains only one
-// transform (color indexing), and trivial non-green literals.
-static int Is8bOptimizable(const VP8LMetadata* const hdr) {
- int i;
- if (hdr->color_cache_size_ > 0) return 0;
- // When the Huffman tree contains only one symbol, we can skip the
- // call to ReadSymbol() for red/blue/alpha channels.
- for (i = 0; i < hdr->num_htree_groups_; ++i) {
- HuffmanCode** const htrees = hdr->htree_groups_[i].htrees;
- if (htrees[RED][0].bits > 0) return 0;
- if (htrees[BLUE][0].bits > 0) return 0;
- if (htrees[ALPHA][0].bits > 0) return 0;
- }
- return 1;
-}
-
-static void AlphaApplyFilter(ALPHDecoder* const alph_dec,
- int first_row, int last_row,
- uint8_t* out, int stride) {
- if (alph_dec->filter_ != WEBP_FILTER_NONE) {
- int y;
- const uint8_t* prev_line = alph_dec->prev_line_;
- assert(WebPUnfilters[alph_dec->filter_] != NULL);
- for (y = first_row; y < last_row; ++y) {
- WebPUnfilters[alph_dec->filter_](prev_line, out, out, stride);
- prev_line = out;
- out += stride;
- }
- alph_dec->prev_line_ = prev_line;
- }
-}
-
-static void ExtractPalettedAlphaRows(VP8LDecoder* const dec, int last_row) {
- // For vertical and gradient filtering, we need to decode the part above the
- // crop_top row, in order to have the correct spatial predictors.
- ALPHDecoder* const alph_dec = (ALPHDecoder*)dec->io_->opaque;
- const int top_row =
- (alph_dec->filter_ == WEBP_FILTER_NONE ||
- alph_dec->filter_ == WEBP_FILTER_HORIZONTAL) ? dec->io_->crop_top
- : dec->last_row_;
- const int first_row = (dec->last_row_ < top_row) ? top_row : dec->last_row_;
- assert(last_row <= dec->io_->crop_bottom);
- if (last_row > first_row) {
- // Special method for paletted alpha data. We only process the cropped area.
- const int width = dec->io_->width;
- uint8_t* out = alph_dec->output_ + width * first_row;
- const uint8_t* const in =
- (uint8_t*)dec->pixels_ + dec->width_ * first_row;
- VP8LTransform* const transform = &dec->transforms_[0];
- assert(dec->next_transform_ == 1);
- assert(transform->type_ == COLOR_INDEXING_TRANSFORM);
- VP8LColorIndexInverseTransformAlpha(transform, first_row, last_row,
- in, out);
- AlphaApplyFilter(alph_dec, first_row, last_row, out, width);
- }
- dec->last_row_ = dec->last_out_row_ = last_row;
-}
-
-//------------------------------------------------------------------------------
-// Helper functions for fast pattern copy (8b and 32b)
-
-// cyclic rotation of pattern word
-static WEBP_INLINE uint32_t Rotate8b(uint32_t V) {
-#if defined(WORDS_BIGENDIAN)
- return ((V & 0xff000000u) >> 24) | (V << 8);
-#else
- return ((V & 0xffu) << 24) | (V >> 8);
-#endif
-}
-
-// copy 1, 2 or 4-bytes pattern
-static WEBP_INLINE void CopySmallPattern8b(const uint8_t* src, uint8_t* dst,
- int length, uint32_t pattern) {
- int i;
- // align 'dst' to 4-bytes boundary. Adjust the pattern along the way.
- while ((uintptr_t)dst & 3) {
- *dst++ = *src++;
- pattern = Rotate8b(pattern);
- --length;
- }
- // Copy the pattern 4 bytes at a time.
- for (i = 0; i < (length >> 2); ++i) {
- ((uint32_t*)dst)[i] = pattern;
- }
- // Finish with left-overs. 'pattern' is still correctly positioned,
- // so no Rotate8b() call is needed.
- for (i <<= 2; i < length; ++i) {
- dst[i] = src[i];
- }
-}
-
-static WEBP_INLINE void CopyBlock8b(uint8_t* const dst, int dist, int length) {
- const uint8_t* src = dst - dist;
- if (length >= 8) {
- uint32_t pattern = 0;
- switch (dist) {
- case 1:
- pattern = src[0];
-#if defined(__arm__) || defined(_M_ARM) // arm doesn't like multiply that much
- pattern |= pattern << 8;
- pattern |= pattern << 16;
-#elif defined(WEBP_USE_MIPS_DSP_R2)
- __asm__ volatile ("replv.qb %0, %0" : "+r"(pattern));
-#else
- pattern = 0x01010101u * pattern;
-#endif
- break;
- case 2:
- memcpy(&pattern, src, sizeof(uint16_t));
-#if defined(__arm__) || defined(_M_ARM)
- pattern |= pattern << 16;
-#elif defined(WEBP_USE_MIPS_DSP_R2)
- __asm__ volatile ("replv.ph %0, %0" : "+r"(pattern));
-#else
- pattern = 0x00010001u * pattern;
-#endif
- break;
- case 4:
- memcpy(&pattern, src, sizeof(uint32_t));
- break;
- default:
- goto Copy;
- break;
- }
- CopySmallPattern8b(src, dst, length, pattern);
- return;
- }
- Copy:
- if (dist >= length) { // no overlap -> use memcpy()
- memcpy(dst, src, length * sizeof(*dst));
- } else {
- int i;
- for (i = 0; i < length; ++i) dst[i] = src[i];
- }
-}
-
-// copy pattern of 1 or 2 uint32_t's
-static WEBP_INLINE void CopySmallPattern32b(const uint32_t* src,
- uint32_t* dst,
- int length, uint64_t pattern) {
- int i;
- if ((uintptr_t)dst & 4) { // Align 'dst' to 8-bytes boundary.
- *dst++ = *src++;
- pattern = (pattern >> 32) | (pattern << 32);
- --length;
- }
- assert(0 == ((uintptr_t)dst & 7));
- for (i = 0; i < (length >> 1); ++i) {
- ((uint64_t*)dst)[i] = pattern; // Copy the pattern 8 bytes at a time.
- }
- if (length & 1) { // Finish with left-over.
- dst[i << 1] = src[i << 1];
- }
-}
-
-static WEBP_INLINE void CopyBlock32b(uint32_t* const dst,
- int dist, int length) {
- const uint32_t* const src = dst - dist;
- if (dist <= 2 && length >= 4 && ((uintptr_t)dst & 3) == 0) {
- uint64_t pattern;
- if (dist == 1) {
- pattern = (uint64_t)src[0];
- pattern |= pattern << 32;
- } else {
- memcpy(&pattern, src, sizeof(pattern));
- }
- CopySmallPattern32b(src, dst, length, pattern);
- } else if (dist >= length) { // no overlap
- memcpy(dst, src, length * sizeof(*dst));
- } else {
- int i;
- for (i = 0; i < length; ++i) dst[i] = src[i];
- }
-}
-
-//------------------------------------------------------------------------------
-
-static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
- int width, int height, int last_row) {
- int ok = 1;
- int row = dec->last_pixel_ / width;
- int col = dec->last_pixel_ % width;
- VP8LBitReader* const br = &dec->br_;
- VP8LMetadata* const hdr = &dec->hdr_;
- int pos = dec->last_pixel_; // current position
- const int end = width * height; // End of data
- const int last = width * last_row; // Last pixel to decode
- const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES;
- const int mask = hdr->huffman_mask_;
- const HTreeGroup* htree_group =
- (pos < last) ? GetHtreeGroupForPos(hdr, col, row) : NULL;
- assert(pos <= end);
- assert(last_row <= height);
- assert(Is8bOptimizable(hdr));
-
- while (!br->eos_ && pos < last) {
- int code;
- // Only update when changing tile.
- if ((col & mask) == 0) {
- htree_group = GetHtreeGroupForPos(hdr, col, row);
- }
- assert(htree_group != NULL);
- VP8LFillBitWindow(br);
- code = ReadSymbol(htree_group->htrees[GREEN], br);
- if (code < NUM_LITERAL_CODES) { // Literal
- data[pos] = code;
- ++pos;
- ++col;
- if (col >= width) {
- col = 0;
- ++row;
- if (row <= last_row && (row % NUM_ARGB_CACHE_ROWS == 0)) {
- ExtractPalettedAlphaRows(dec, row);
- }
- }
- } else if (code < len_code_limit) { // Backward reference
- int dist_code, dist;
- const int length_sym = code - NUM_LITERAL_CODES;
- const int length = GetCopyLength(length_sym, br);
- const int dist_symbol = ReadSymbol(htree_group->htrees[DIST], br);
- VP8LFillBitWindow(br);
- dist_code = GetCopyDistance(dist_symbol, br);
- dist = PlaneCodeToDistance(width, dist_code);
- if (pos >= dist && end - pos >= length) {
- CopyBlock8b(data + pos, dist, length);
- } else {
- ok = 0;
- goto End;
- }
- pos += length;
- col += length;
- while (col >= width) {
- col -= width;
- ++row;
- if (row <= last_row && (row % NUM_ARGB_CACHE_ROWS == 0)) {
- ExtractPalettedAlphaRows(dec, row);
- }
- }
- if (pos < last && (col & mask)) {
- htree_group = GetHtreeGroupForPos(hdr, col, row);
- }
- } else { // Not reached
- ok = 0;
- goto End;
- }
- assert(br->eos_ == VP8LIsEndOfStream(br));
- }
- // Process the remaining rows corresponding to last row-block.
- ExtractPalettedAlphaRows(dec, row > last_row ? last_row : row);
-
- End:
- if (!ok || (br->eos_ && pos < end)) {
- ok = 0;
- dec->status_ = br->eos_ ? VP8_STATUS_SUSPENDED
- : VP8_STATUS_BITSTREAM_ERROR;
- } else {
- dec->last_pixel_ = pos;
- }
- return ok;
-}
-
-static void SaveState(VP8LDecoder* const dec, int last_pixel) {
- assert(dec->incremental_);
- dec->saved_br_ = dec->br_;
- dec->saved_last_pixel_ = last_pixel;
- if (dec->hdr_.color_cache_size_ > 0) {
- VP8LColorCacheCopy(&dec->hdr_.color_cache_, &dec->hdr_.saved_color_cache_);
- }
-}
-
-static void RestoreState(VP8LDecoder* const dec) {
- assert(dec->br_.eos_);
- dec->status_ = VP8_STATUS_SUSPENDED;
- dec->br_ = dec->saved_br_;
- dec->last_pixel_ = dec->saved_last_pixel_;
- if (dec->hdr_.color_cache_size_ > 0) {
- VP8LColorCacheCopy(&dec->hdr_.saved_color_cache_, &dec->hdr_.color_cache_);
- }
-}
-
-#define SYNC_EVERY_N_ROWS 8 // minimum number of rows between check-points
-static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
- int width, int height, int last_row,
- ProcessRowsFunc process_func) {
- int row = dec->last_pixel_ / width;
- int col = dec->last_pixel_ % width;
- VP8LBitReader* const br = &dec->br_;
- VP8LMetadata* const hdr = &dec->hdr_;
- uint32_t* src = data + dec->last_pixel_;
- uint32_t* last_cached = src;
- uint32_t* const src_end = data + width * height; // End of data
- uint32_t* const src_last = data + width * last_row; // Last pixel to decode
- const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES;
- const int color_cache_limit = len_code_limit + hdr->color_cache_size_;
- int next_sync_row = dec->incremental_ ? row : 1 << 24;
- VP8LColorCache* const color_cache =
- (hdr->color_cache_size_ > 0) ? &hdr->color_cache_ : NULL;
- const int mask = hdr->huffman_mask_;
- const HTreeGroup* htree_group =
- (src < src_last) ? GetHtreeGroupForPos(hdr, col, row) : NULL;
- assert(dec->last_row_ < last_row);
- assert(src_last <= src_end);
-
- while (src < src_last) {
- int code;
- if (row >= next_sync_row) {
- SaveState(dec, (int)(src - data));
- next_sync_row = row + SYNC_EVERY_N_ROWS;
- }
- // Only update when changing tile. Note we could use this test:
- // if "((((prev_col ^ col) | prev_row ^ row)) > mask)" -> tile changed
- // but that's actually slower and needs storing the previous col/row.
- if ((col & mask) == 0) {
- htree_group = GetHtreeGroupForPos(hdr, col, row);
- }
- assert(htree_group != NULL);
- if (htree_group->is_trivial_code) {
- *src = htree_group->literal_arb;
- goto AdvanceByOne;
- }
- VP8LFillBitWindow(br);
- if (htree_group->use_packed_table) {
- code = ReadPackedSymbols(htree_group, br, src);
- if (code == PACKED_NON_LITERAL_CODE) goto AdvanceByOne;
- } else {
- code = ReadSymbol(htree_group->htrees[GREEN], br);
- }
- if (br->eos_) break; // early out
- if (code < NUM_LITERAL_CODES) { // Literal
- if (htree_group->is_trivial_literal) {
- *src = htree_group->literal_arb | (code << 8);
- } else {
- int red, blue, alpha;
- red = ReadSymbol(htree_group->htrees[RED], br);
- VP8LFillBitWindow(br);
- blue = ReadSymbol(htree_group->htrees[BLUE], br);
- alpha = ReadSymbol(htree_group->htrees[ALPHA], br);
- if (br->eos_) break;
- *src = ((uint32_t)alpha << 24) | (red << 16) | (code << 8) | blue;
- }
- AdvanceByOne:
- ++src;
- ++col;
- if (col >= width) {
- col = 0;
- ++row;
- if (process_func != NULL) {
- if (row <= last_row && (row % NUM_ARGB_CACHE_ROWS == 0)) {
- process_func(dec, row);
- }
- }
- if (color_cache != NULL) {
- while (last_cached < src) {
- VP8LColorCacheInsert(color_cache, *last_cached++);
- }
- }
- }
- } else if (code < len_code_limit) { // Backward reference
- int dist_code, dist;
- const int length_sym = code - NUM_LITERAL_CODES;
- const int length = GetCopyLength(length_sym, br);
- const int dist_symbol = ReadSymbol(htree_group->htrees[DIST], br);
- VP8LFillBitWindow(br);
- dist_code = GetCopyDistance(dist_symbol, br);
- dist = PlaneCodeToDistance(width, dist_code);
- if (br->eos_) break;
- if (src - data < (ptrdiff_t)dist || src_end - src < (ptrdiff_t)length) {
- goto Error;
- } else {
- CopyBlock32b(src, dist, length);
- }
- src += length;
- col += length;
- while (col >= width) {
- col -= width;
- ++row;
- if (process_func != NULL) {
- if (row <= last_row && (row % NUM_ARGB_CACHE_ROWS == 0)) {
- process_func(dec, row);
- }
- }
- }
- // Because of the check done above (before 'src' was incremented by
- // 'length'), the following holds true.
- assert(src <= src_end);
- if (col & mask) htree_group = GetHtreeGroupForPos(hdr, col, row);
- if (color_cache != NULL) {
- while (last_cached < src) {
- VP8LColorCacheInsert(color_cache, *last_cached++);
- }
- }
- } else if (code < color_cache_limit) { // Color cache
- const int key = code - len_code_limit;
- assert(color_cache != NULL);
- while (last_cached < src) {
- VP8LColorCacheInsert(color_cache, *last_cached++);
- }
- *src = VP8LColorCacheLookup(color_cache, key);
- goto AdvanceByOne;
- } else { // Not reached
- goto Error;
- }
- assert(br->eos_ == VP8LIsEndOfStream(br));
- }
-
- if (dec->incremental_ && br->eos_ && src < src_end) {
- RestoreState(dec);
- } else if (!br->eos_) {
- // Process the remaining rows corresponding to last row-block.
- if (process_func != NULL) {
- process_func(dec, row > last_row ? last_row : row);
- }
- dec->status_ = VP8_STATUS_OK;
- dec->last_pixel_ = (int)(src - data); // end-of-scan marker
- } else {
- // if not incremental, and we are past the end of buffer (eos_=1), then this
- // is a real bitstream error.
- goto Error;
- }
- return 1;
-
- Error:
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
- return 0;
-}
-
-// -----------------------------------------------------------------------------
-// VP8LTransform
-
-static void ClearTransform(VP8LTransform* const transform) {
- WebPSafeFree(transform->data_);
- transform->data_ = NULL;
-}
-
-// For security reason, we need to remap the color map to span
-// the total possible bundled values, and not just the num_colors.
-static int ExpandColorMap(int num_colors, VP8LTransform* const transform) {
- int i;
- const int final_num_colors = 1 << (8 >> transform->bits_);
- uint32_t* const new_color_map =
- (uint32_t*)WebPSafeMalloc((uint64_t)final_num_colors,
- sizeof(*new_color_map));
- if (new_color_map == NULL) {
- return 0;
- } else {
- uint8_t* const data = (uint8_t*)transform->data_;
- uint8_t* const new_data = (uint8_t*)new_color_map;
- new_color_map[0] = transform->data_[0];
- for (i = 4; i < 4 * num_colors; ++i) {
- // Equivalent to AddPixelEq(), on a byte-basis.
- new_data[i] = (data[i] + new_data[i - 4]) & 0xff;
- }
- for (; i < 4 * final_num_colors; ++i) {
- new_data[i] = 0; // black tail.
- }
- WebPSafeFree(transform->data_);
- transform->data_ = new_color_map;
- }
- return 1;
-}
-
-static int ReadTransform(int* const xsize, int const* ysize,
- VP8LDecoder* const dec) {
- int ok = 1;
- VP8LBitReader* const br = &dec->br_;
- VP8LTransform* transform = &dec->transforms_[dec->next_transform_];
- const VP8LImageTransformType type =
- (VP8LImageTransformType)VP8LReadBits(br, 2);
-
- // Each transform type can only be present once in the stream.
- if (dec->transforms_seen_ & (1U << type)) {
- return 0; // Already there, let's not accept the second same transform.
- }
- dec->transforms_seen_ |= (1U << type);
-
- transform->type_ = type;
- transform->xsize_ = *xsize;
- transform->ysize_ = *ysize;
- transform->data_ = NULL;
- ++dec->next_transform_;
- assert(dec->next_transform_ <= NUM_TRANSFORMS);
-
- switch (type) {
- case PREDICTOR_TRANSFORM:
- case CROSS_COLOR_TRANSFORM:
- transform->bits_ = VP8LReadBits(br, 3) + 2;
- ok = DecodeImageStream(VP8LSubSampleSize(transform->xsize_,
- transform->bits_),
- VP8LSubSampleSize(transform->ysize_,
- transform->bits_),
- 0, dec, &transform->data_);
- break;
- case COLOR_INDEXING_TRANSFORM: {
- const int num_colors = VP8LReadBits(br, 8) + 1;
- const int bits = (num_colors > 16) ? 0
- : (num_colors > 4) ? 1
- : (num_colors > 2) ? 2
- : 3;
- *xsize = VP8LSubSampleSize(transform->xsize_, bits);
- transform->bits_ = bits;
- ok = DecodeImageStream(num_colors, 1, 0, dec, &transform->data_);
- ok = ok && ExpandColorMap(num_colors, transform);
- break;
- }
- case SUBTRACT_GREEN:
- break;
- default:
- assert(0); // can't happen
- break;
- }
-
- return ok;
-}
-
-// -----------------------------------------------------------------------------
-// VP8LMetadata
-
-static void InitMetadata(VP8LMetadata* const hdr) {
- assert(hdr != NULL);
- memset(hdr, 0, sizeof(*hdr));
-}
-
-static void ClearMetadata(VP8LMetadata* const hdr) {
- assert(hdr != NULL);
-
- WebPSafeFree(hdr->huffman_image_);
- WebPSafeFree(hdr->huffman_tables_);
- VP8LHtreeGroupsFree(hdr->htree_groups_);
- VP8LColorCacheClear(&hdr->color_cache_);
- VP8LColorCacheClear(&hdr->saved_color_cache_);
- InitMetadata(hdr);
-}
-
-// -----------------------------------------------------------------------------
-// VP8LDecoder
-
-VP8LDecoder* VP8LNew(void) {
- VP8LDecoder* const dec = (VP8LDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
- if (dec == NULL) return NULL;
- dec->status_ = VP8_STATUS_OK;
- dec->state_ = READ_DIM;
-
- VP8LDspInit(); // Init critical function pointers.
-
- return dec;
-}
-
-void VP8LClear(VP8LDecoder* const dec) {
- int i;
- if (dec == NULL) return;
- ClearMetadata(&dec->hdr_);
-
- WebPSafeFree(dec->pixels_);
- dec->pixels_ = NULL;
- for (i = 0; i < dec->next_transform_; ++i) {
- ClearTransform(&dec->transforms_[i]);
- }
- dec->next_transform_ = 0;
- dec->transforms_seen_ = 0;
-
- WebPSafeFree(dec->rescaler_memory);
- dec->rescaler_memory = NULL;
-
- dec->output_ = NULL; // leave no trace behind
-}
-
-void VP8LDelete(VP8LDecoder* const dec) {
- if (dec != NULL) {
- VP8LClear(dec);
- WebPSafeFree(dec);
- }
-}
-
-static void UpdateDecoder(VP8LDecoder* const dec, int width, int height) {
- VP8LMetadata* const hdr = &dec->hdr_;
- const int num_bits = hdr->huffman_subsample_bits_;
- dec->width_ = width;
- dec->height_ = height;
-
- hdr->huffman_xsize_ = VP8LSubSampleSize(width, num_bits);
- hdr->huffman_mask_ = (num_bits == 0) ? ~0 : (1 << num_bits) - 1;
-}
-
-static int DecodeImageStream(int xsize, int ysize,
- int is_level0,
- VP8LDecoder* const dec,
- uint32_t** const decoded_data) {
- int ok = 1;
- int transform_xsize = xsize;
- int transform_ysize = ysize;
- VP8LBitReader* const br = &dec->br_;
- VP8LMetadata* const hdr = &dec->hdr_;
- uint32_t* data = NULL;
- int color_cache_bits = 0;
-
- // Read the transforms (may recurse).
- if (is_level0) {
- while (ok && VP8LReadBits(br, 1)) {
- ok = ReadTransform(&transform_xsize, &transform_ysize, dec);
- }
- }
-
- // Color cache
- if (ok && VP8LReadBits(br, 1)) {
- color_cache_bits = VP8LReadBits(br, 4);
- ok = (color_cache_bits >= 1 && color_cache_bits <= MAX_CACHE_BITS);
- if (!ok) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
- goto End;
- }
- }
-
- // Read the Huffman codes (may recurse).
- ok = ok && ReadHuffmanCodes(dec, transform_xsize, transform_ysize,
- color_cache_bits, is_level0);
- if (!ok) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
- goto End;
- }
-
- // Finish setting up the color-cache
- if (color_cache_bits > 0) {
- hdr->color_cache_size_ = 1 << color_cache_bits;
- if (!VP8LColorCacheInit(&hdr->color_cache_, color_cache_bits)) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- ok = 0;
- goto End;
- }
- } else {
- hdr->color_cache_size_ = 0;
- }
- UpdateDecoder(dec, transform_xsize, transform_ysize);
-
- if (is_level0) { // level 0 complete
- dec->state_ = READ_HDR;
- goto End;
- }
-
- {
- const uint64_t total_size = (uint64_t)transform_xsize * transform_ysize;
- data = (uint32_t*)WebPSafeMalloc(total_size, sizeof(*data));
- if (data == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- ok = 0;
- goto End;
- }
- }
-
- // Use the Huffman trees to decode the LZ77 encoded data.
- ok = DecodeImageData(dec, data, transform_xsize, transform_ysize,
- transform_ysize, NULL);
- ok = ok && !br->eos_;
-
- End:
- if (!ok) {
- WebPSafeFree(data);
- ClearMetadata(hdr);
- } else {
- if (decoded_data != NULL) {
- *decoded_data = data;
- } else {
- // We allocate image data in this function only for transforms. At level 0
- // (that is: not the transforms), we shouldn't have allocated anything.
- assert(data == NULL);
- assert(is_level0);
- }
- dec->last_pixel_ = 0; // Reset for future DECODE_DATA_FUNC() calls.
- if (!is_level0) ClearMetadata(hdr); // Clean up temporary data behind.
- }
- return ok;
-}
-
-//------------------------------------------------------------------------------
-// Allocate internal buffers dec->pixels_ and dec->argb_cache_.
-static int AllocateInternalBuffers32b(VP8LDecoder* const dec, int final_width) {
- const uint64_t num_pixels = (uint64_t)dec->width_ * dec->height_;
- // Scratch buffer corresponding to top-prediction row for transforming the
- // first row in the row-blocks. Not needed for paletted alpha.
- const uint64_t cache_top_pixels = (uint16_t)final_width;
- // Scratch buffer for temporary BGRA storage. Not needed for paletted alpha.
- const uint64_t cache_pixels = (uint64_t)final_width * NUM_ARGB_CACHE_ROWS;
- const uint64_t total_num_pixels =
- num_pixels + cache_top_pixels + cache_pixels;
-
- assert(dec->width_ <= final_width);
- dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint32_t));
- if (dec->pixels_ == NULL) {
- dec->argb_cache_ = NULL; // for sanity check
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- return 0;
- }
- dec->argb_cache_ = dec->pixels_ + num_pixels + cache_top_pixels;
- return 1;
-}
-
-static int AllocateInternalBuffers8b(VP8LDecoder* const dec) {
- const uint64_t total_num_pixels = (uint64_t)dec->width_ * dec->height_;
- dec->argb_cache_ = NULL; // for sanity check
- dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint8_t));
- if (dec->pixels_ == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- return 0;
- }
- return 1;
-}
-
-//------------------------------------------------------------------------------
-
-// Special row-processing that only stores the alpha data.
-static void ExtractAlphaRows(VP8LDecoder* const dec, int last_row) {
- int cur_row = dec->last_row_;
- int num_rows = last_row - cur_row;
- const uint32_t* in = dec->pixels_ + dec->width_ * cur_row;
-
- assert(last_row <= dec->io_->crop_bottom);
- while (num_rows > 0) {
- const int num_rows_to_process =
- (num_rows > NUM_ARGB_CACHE_ROWS) ? NUM_ARGB_CACHE_ROWS : num_rows;
- // Extract alpha (which is stored in the green plane).
- ALPHDecoder* const alph_dec = (ALPHDecoder*)dec->io_->opaque;
- uint8_t* const output = alph_dec->output_;
- const int width = dec->io_->width; // the final width (!= dec->width_)
- const int cache_pixs = width * num_rows_to_process;
- uint8_t* const dst = output + width * cur_row;
- const uint32_t* const src = dec->argb_cache_;
- ApplyInverseTransforms(dec, num_rows_to_process, in);
- WebPExtractGreen(src, dst, cache_pixs);
- AlphaApplyFilter(alph_dec,
- cur_row, cur_row + num_rows_to_process, dst, width);
- num_rows -= num_rows_to_process;
- in += num_rows_to_process * dec->width_;
- cur_row += num_rows_to_process;
- }
- assert(cur_row == last_row);
- dec->last_row_ = dec->last_out_row_ = last_row;
-}
-
-int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
- const uint8_t* const data, size_t data_size) {
- int ok = 0;
- VP8LDecoder* dec = VP8LNew();
-
- if (dec == NULL) return 0;
-
- assert(alph_dec != NULL);
- alph_dec->vp8l_dec_ = dec;
-
- dec->width_ = alph_dec->width_;
- dec->height_ = alph_dec->height_;
- dec->io_ = &alph_dec->io_;
- dec->io_->opaque = alph_dec;
- dec->io_->width = alph_dec->width_;
- dec->io_->height = alph_dec->height_;
-
- dec->status_ = VP8_STATUS_OK;
- VP8LInitBitReader(&dec->br_, data, data_size);
-
- if (!DecodeImageStream(alph_dec->width_, alph_dec->height_, 1, dec, NULL)) {
- goto Err;
- }
-
- // Special case: if alpha data uses only the color indexing transform and
- // doesn't use color cache (a frequent case), we will use DecodeAlphaData()
- // method that only needs allocation of 1 byte per pixel (alpha channel).
- if (dec->next_transform_ == 1 &&
- dec->transforms_[0].type_ == COLOR_INDEXING_TRANSFORM &&
- Is8bOptimizable(&dec->hdr_)) {
- alph_dec->use_8b_decode_ = 1;
- ok = AllocateInternalBuffers8b(dec);
- } else {
- // Allocate internal buffers (note that dec->width_ may have changed here).
- alph_dec->use_8b_decode_ = 0;
- ok = AllocateInternalBuffers32b(dec, alph_dec->width_);
- }
-
- if (!ok) goto Err;
-
- return 1;
-
- Err:
- VP8LDelete(alph_dec->vp8l_dec_);
- alph_dec->vp8l_dec_ = NULL;
- return 0;
-}
-
-int VP8LDecodeAlphaImageStream(ALPHDecoder* const alph_dec, int last_row) {
- VP8LDecoder* const dec = alph_dec->vp8l_dec_;
- assert(dec != NULL);
- assert(last_row <= dec->height_);
-
- if (dec->last_row_ >= last_row) {
- return 1; // done
- }
-
- if (!alph_dec->use_8b_decode_) WebPInitAlphaProcessing();
-
- // Decode (with special row processing).
- return alph_dec->use_8b_decode_ ?
- DecodeAlphaData(dec, (uint8_t*)dec->pixels_, dec->width_, dec->height_,
- last_row) :
- DecodeImageData(dec, dec->pixels_, dec->width_, dec->height_,
- last_row, ExtractAlphaRows);
-}
-
-//------------------------------------------------------------------------------
-
-int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io) {
- int width, height, has_alpha;
-
- if (dec == NULL) return 0;
- if (io == NULL) {
- dec->status_ = VP8_STATUS_INVALID_PARAM;
- return 0;
- }
-
- dec->io_ = io;
- dec->status_ = VP8_STATUS_OK;
- VP8LInitBitReader(&dec->br_, io->data, io->data_size);
- if (!ReadImageInfo(&dec->br_, &width, &height, &has_alpha)) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
- goto Error;
- }
- dec->state_ = READ_DIM;
- io->width = width;
- io->height = height;
-
- if (!DecodeImageStream(width, height, 1, dec, NULL)) goto Error;
- return 1;
-
- Error:
- VP8LClear(dec);
- assert(dec->status_ != VP8_STATUS_OK);
- return 0;
-}
-
-int VP8LDecodeImage(VP8LDecoder* const dec) {
- VP8Io* io = NULL;
- WebPDecParams* params = NULL;
-
- // Sanity checks.
- if (dec == NULL) return 0;
-
- assert(dec->hdr_.huffman_tables_ != NULL);
- assert(dec->hdr_.htree_groups_ != NULL);
- assert(dec->hdr_.num_htree_groups_ > 0);
-
- io = dec->io_;
- assert(io != NULL);
- params = (WebPDecParams*)io->opaque;
- assert(params != NULL);
-
- // Initialization.
- if (dec->state_ != READ_DATA) {
- dec->output_ = params->output;
- assert(dec->output_ != NULL);
-
- if (!WebPIoInitFromOptions(params->options, io, MODE_BGRA)) {
- dec->status_ = VP8_STATUS_INVALID_PARAM;
- goto Err;
- }
-
- if (!AllocateInternalBuffers32b(dec, io->width)) goto Err;
-
- if (io->use_scaling && !AllocateAndInitRescaler(dec, io)) goto Err;
-
- if (io->use_scaling || WebPIsPremultipliedMode(dec->output_->colorspace)) {
- // need the alpha-multiply functions for premultiplied output or rescaling
- WebPInitAlphaProcessing();
- }
- if (!WebPIsRGBMode(dec->output_->colorspace)) {
- WebPInitConvertARGBToYUV();
- if (dec->output_->u.YUVA.a != NULL) WebPInitAlphaProcessing();
- }
- if (dec->incremental_) {
- if (dec->hdr_.color_cache_size_ > 0 &&
- dec->hdr_.saved_color_cache_.colors_ == NULL) {
- if (!VP8LColorCacheInit(&dec->hdr_.saved_color_cache_,
- dec->hdr_.color_cache_.hash_bits_)) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- goto Err;
- }
- }
- }
- dec->state_ = READ_DATA;
- }
-
- // Decode.
- if (!DecodeImageData(dec, dec->pixels_, dec->width_, dec->height_,
- io->crop_bottom, ProcessRows)) {
- goto Err;
- }
-
- params->last_y = dec->last_out_row_;
- return 1;
-
- Err:
- VP8LClear(dec);
- assert(dec->status_ != VP8_STATUS_OK);
- return 0;
-}
-
-//------------------------------------------------------------------------------
diff --git a/thirdparty/libwebp/dec/vp8li_dec.h b/thirdparty/libwebp/dec/vp8li_dec.h
deleted file mode 100644
index 097a9d0589..0000000000
--- a/thirdparty/libwebp/dec/vp8li_dec.h
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright 2012 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.
-// -----------------------------------------------------------------------------
-//
-// Lossless decoder: internal header.
-//
-// Author: Skal (pascal.massimino@gmail.com)
-// Vikas Arora(vikaas.arora@gmail.com)
-
-#ifndef WEBP_DEC_VP8LI_H_
-#define WEBP_DEC_VP8LI_H_
-
-#include <string.h> // for memcpy()
-#include "./webpi_dec.h"
-#include "../utils/bit_reader_utils.h"
-#include "../utils/color_cache_utils.h"
-#include "../utils/huffman_utils.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum {
- READ_DATA = 0,
- READ_HDR = 1,
- READ_DIM = 2
-} VP8LDecodeState;
-
-typedef struct VP8LTransform VP8LTransform;
-struct VP8LTransform {
- VP8LImageTransformType type_; // transform type.
- int bits_; // subsampling bits defining transform window.
- int xsize_; // transform window X index.
- int ysize_; // transform window Y index.
- uint32_t *data_; // transform data.
-};
-
-typedef struct {
- int color_cache_size_;
- VP8LColorCache color_cache_;
- VP8LColorCache saved_color_cache_; // for incremental
-
- int huffman_mask_;
- int huffman_subsample_bits_;
- int huffman_xsize_;
- uint32_t *huffman_image_;
- int num_htree_groups_;
- HTreeGroup *htree_groups_;
- HuffmanCode *huffman_tables_;
-} VP8LMetadata;
-
-typedef struct VP8LDecoder VP8LDecoder;
-struct VP8LDecoder {
- VP8StatusCode status_;
- VP8LDecodeState state_;
- VP8Io *io_;
-
- const WebPDecBuffer *output_; // shortcut to io->opaque->output
-
- uint32_t *pixels_; // Internal data: either uint8_t* for alpha
- // or uint32_t* for BGRA.
- uint32_t *argb_cache_; // Scratch buffer for temporary BGRA storage.
-
- VP8LBitReader br_;
- int incremental_; // if true, incremental decoding is expected
- VP8LBitReader saved_br_; // note: could be local variables too
- int saved_last_pixel_;
-
- int width_;
- int height_;
- int last_row_; // last input row decoded so far.
- int last_pixel_; // last pixel decoded so far. However, it may
- // not be transformed, scaled and
- // color-converted yet.
- int last_out_row_; // last row output so far.
-
- VP8LMetadata hdr_;
-
- int next_transform_;
- VP8LTransform transforms_[NUM_TRANSFORMS];
- // or'd bitset storing the transforms types.
- uint32_t transforms_seen_;
-
- uint8_t *rescaler_memory; // Working memory for rescaling work.
- WebPRescaler *rescaler; // Common rescaler for all channels.
-};
-
-//------------------------------------------------------------------------------
-// internal functions. Not public.
-
-struct ALPHDecoder; // Defined in dec/alphai.h.
-
-// in vp8l.c
-
-// Decodes image header for alpha data stored using lossless compression.
-// Returns false in case of error.
-int VP8LDecodeAlphaHeader(struct ALPHDecoder* const alph_dec,
- const uint8_t* const data, size_t data_size);
-
-// Decodes *at least* 'last_row' rows of alpha. If some of the initial rows are
-// already decoded in previous call(s), it will resume decoding from where it
-// was paused.
-// Returns false in case of bitstream error.
-int VP8LDecodeAlphaImageStream(struct ALPHDecoder* const alph_dec,
- int last_row);
-
-// Allocates and initialize a new lossless decoder instance.
-VP8LDecoder* VP8LNew(void);
-
-// Decodes the image header. Returns false in case of error.
-int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io);
-
-// Decodes an image. It's required to decode the lossless header before calling
-// this function. Returns false in case of error, with updated dec->status_.
-int VP8LDecodeImage(VP8LDecoder* const dec);
-
-// Resets the decoder in its initial state, reclaiming memory.
-// Preserves the dec->status_ value.
-void VP8LClear(VP8LDecoder* const dec);
-
-// Clears and deallocate a lossless decoder instance.
-void VP8LDelete(VP8LDecoder* const dec);
-
-//------------------------------------------------------------------------------
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif /* WEBP_DEC_VP8LI_H_ */
diff --git a/thirdparty/libwebp/dec/webp_dec.c b/thirdparty/libwebp/dec/webp_dec.c
deleted file mode 100644
index a8e9c2c510..0000000000
--- a/thirdparty/libwebp/dec/webp_dec.c
+++ /dev/null
@@ -1,843 +0,0 @@
-// Copyright 2010 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.
-// -----------------------------------------------------------------------------
-//
-// Main decoding functions for WEBP images.
-//
-// Author: Skal (pascal.massimino@gmail.com)
-
-#include <stdlib.h>
-
-#include "./vp8i_dec.h"
-#include "./vp8li_dec.h"
-#include "./webpi_dec.h"
-#include "../utils/utils.h"
-#include "../webp/mux_types.h" // ALPHA_FLAG
-
-//------------------------------------------------------------------------------
-// RIFF layout is:
-// Offset tag
-// 0...3 "RIFF" 4-byte tag
-// 4...7 size of image data (including metadata) starting at offset 8
-// 8...11 "WEBP" our form-type signature
-// The RIFF container (12 bytes) is followed by appropriate chunks:
-// 12..15 "VP8 ": 4-bytes tags, signaling the use of VP8 video format
-// 16..19 size of the raw VP8 image data, starting at offset 20
-// 20.... the VP8 bytes
-// Or,
-// 12..15 "VP8L": 4-bytes tags, signaling the use of VP8L lossless format
-// 16..19 size of the raw VP8L image data, starting at offset 20
-// 20.... the VP8L bytes
-// Or,
-// 12..15 "VP8X": 4-bytes tags, describing the extended-VP8 chunk.
-// 16..19 size of the VP8X chunk starting at offset 20.
-// 20..23 VP8X flags bit-map corresponding to the chunk-types present.
-// 24..26 Width of the Canvas Image.
-// 27..29 Height of the Canvas Image.
-// There can be extra chunks after the "VP8X" chunk (ICCP, ANMF, VP8, VP8L,
-// XMP, EXIF ...)
-// All sizes are in little-endian order.
-// Note: chunk data size must be padded to multiple of 2 when written.
-
-// Validates the RIFF container (if detected) and skips over it.
-// If a RIFF container is detected, returns:
-// VP8_STATUS_BITSTREAM_ERROR for invalid header,
-// VP8_STATUS_NOT_ENOUGH_DATA for truncated data if have_all_data is true,
-// and VP8_STATUS_OK otherwise.
-// In case there are not enough bytes (partial RIFF container), return 0 for
-// *riff_size. Else return the RIFF size extracted from the header.
-static VP8StatusCode ParseRIFF(const uint8_t** const data,
- size_t* const data_size, int have_all_data,
- size_t* const riff_size) {
- assert(data != NULL);
- assert(data_size != NULL);
- assert(riff_size != NULL);
-
- *riff_size = 0; // Default: no RIFF present.
- if (*data_size >= RIFF_HEADER_SIZE && !memcmp(*data, "RIFF", TAG_SIZE)) {
- if (memcmp(*data + 8, "WEBP", TAG_SIZE)) {
- return VP8_STATUS_BITSTREAM_ERROR; // Wrong image file signature.
- } else {
- const uint32_t size = GetLE32(*data + TAG_SIZE);
- // Check that we have at least one chunk (i.e "WEBP" + "VP8?nnnn").
- if (size < TAG_SIZE + CHUNK_HEADER_SIZE) {
- return VP8_STATUS_BITSTREAM_ERROR;
- }
- if (size > MAX_CHUNK_PAYLOAD) {
- return VP8_STATUS_BITSTREAM_ERROR;
- }
- if (have_all_data && (size > *data_size - CHUNK_HEADER_SIZE)) {
- return VP8_STATUS_NOT_ENOUGH_DATA; // Truncated bitstream.
- }
- // We have a RIFF container. Skip it.
- *riff_size = size;
- *data += RIFF_HEADER_SIZE;
- *data_size -= RIFF_HEADER_SIZE;
- }
- }
- return VP8_STATUS_OK;
-}
-
-// Validates the VP8X header and skips over it.
-// Returns VP8_STATUS_BITSTREAM_ERROR for invalid VP8X header,
-// VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
-// VP8_STATUS_OK otherwise.
-// If a VP8X chunk is found, found_vp8x is set to true and *width_ptr,
-// *height_ptr and *flags_ptr are set to the corresponding values extracted
-// from the VP8X chunk.
-static VP8StatusCode ParseVP8X(const uint8_t** const data,
- size_t* const data_size,
- int* const found_vp8x,
- int* const width_ptr, int* const height_ptr,
- uint32_t* const flags_ptr) {
- const uint32_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE;
- assert(data != NULL);
- assert(data_size != NULL);
- assert(found_vp8x != NULL);
-
- *found_vp8x = 0;
-
- if (*data_size < CHUNK_HEADER_SIZE) {
- return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data.
- }
-
- if (!memcmp(*data, "VP8X", TAG_SIZE)) {
- int width, height;
- uint32_t flags;
- const uint32_t chunk_size = GetLE32(*data + TAG_SIZE);
- if (chunk_size != VP8X_CHUNK_SIZE) {
- return VP8_STATUS_BITSTREAM_ERROR; // Wrong chunk size.
- }
-
- // Verify if enough data is available to validate the VP8X chunk.
- if (*data_size < vp8x_size) {
- return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data.
- }
- flags = GetLE32(*data + 8);
- width = 1 + GetLE24(*data + 12);
- height = 1 + GetLE24(*data + 15);
- if (width * (uint64_t)height >= MAX_IMAGE_AREA) {
- return VP8_STATUS_BITSTREAM_ERROR; // image is too large
- }
-
- if (flags_ptr != NULL) *flags_ptr = flags;
- if (width_ptr != NULL) *width_ptr = width;
- if (height_ptr != NULL) *height_ptr = height;
- // Skip over VP8X header bytes.
- *data += vp8x_size;
- *data_size -= vp8x_size;
- *found_vp8x = 1;
- }
- return VP8_STATUS_OK;
-}
-
-// Skips to the next VP8/VP8L chunk header in the data given the size of the
-// RIFF chunk 'riff_size'.
-// Returns VP8_STATUS_BITSTREAM_ERROR if any invalid chunk size is encountered,
-// VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
-// VP8_STATUS_OK otherwise.
-// If an alpha chunk is found, *alpha_data and *alpha_size are set
-// appropriately.
-static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
- size_t* const data_size,
- size_t const riff_size,
- const uint8_t** const alpha_data,
- size_t* const alpha_size) {
- const uint8_t* buf;
- size_t buf_size;
- uint32_t total_size = TAG_SIZE + // "WEBP".
- CHUNK_HEADER_SIZE + // "VP8Xnnnn".
- VP8X_CHUNK_SIZE; // data.
- assert(data != NULL);
- assert(data_size != NULL);
- buf = *data;
- buf_size = *data_size;
-
- assert(alpha_data != NULL);
- assert(alpha_size != NULL);
- *alpha_data = NULL;
- *alpha_size = 0;
-
- while (1) {
- uint32_t chunk_size;
- uint32_t disk_chunk_size; // chunk_size with padding
-
- *data = buf;
- *data_size = buf_size;
-
- if (buf_size < CHUNK_HEADER_SIZE) { // Insufficient data.
- return VP8_STATUS_NOT_ENOUGH_DATA;
- }
-
- chunk_size = GetLE32(buf + TAG_SIZE);
- if (chunk_size > MAX_CHUNK_PAYLOAD) {
- return VP8_STATUS_BITSTREAM_ERROR; // Not a valid chunk size.
- }
- // For odd-sized chunk-payload, there's one byte padding at the end.
- disk_chunk_size = (CHUNK_HEADER_SIZE + chunk_size + 1) & ~1;
- total_size += disk_chunk_size;
-
- // Check that total bytes skipped so far does not exceed riff_size.
- if (riff_size > 0 && (total_size > riff_size)) {
- return VP8_STATUS_BITSTREAM_ERROR; // Not a valid chunk size.
- }
-
- // Start of a (possibly incomplete) VP8/VP8L chunk implies that we have
- // parsed all the optional chunks.
- // Note: This check must occur before the check 'buf_size < disk_chunk_size'
- // below to allow incomplete VP8/VP8L chunks.
- if (!memcmp(buf, "VP8 ", TAG_SIZE) ||
- !memcmp(buf, "VP8L", TAG_SIZE)) {
- return VP8_STATUS_OK;
- }
-
- if (buf_size < disk_chunk_size) { // Insufficient data.
- return VP8_STATUS_NOT_ENOUGH_DATA;
- }
-
- if (!memcmp(buf, "ALPH", TAG_SIZE)) { // A valid ALPH header.
- *alpha_data = buf + CHUNK_HEADER_SIZE;
- *alpha_size = chunk_size;
- }
-
- // We have a full and valid chunk; skip it.
- buf += disk_chunk_size;
- buf_size -= disk_chunk_size;
- }
-}
-
-// Validates the VP8/VP8L Header ("VP8 nnnn" or "VP8L nnnn") and skips over it.
-// Returns VP8_STATUS_BITSTREAM_ERROR for invalid (chunk larger than
-// riff_size) VP8/VP8L header,
-// VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
-// VP8_STATUS_OK otherwise.
-// If a VP8/VP8L chunk is found, *chunk_size is set to the total number of bytes
-// extracted from the VP8/VP8L chunk header.
-// The flag '*is_lossless' is set to 1 in case of VP8L chunk / raw VP8L data.
-static VP8StatusCode ParseVP8Header(const uint8_t** const data_ptr,
- size_t* const data_size, int have_all_data,
- size_t riff_size, size_t* const chunk_size,
- int* const is_lossless) {
- const uint8_t* const data = *data_ptr;
- const int is_vp8 = !memcmp(data, "VP8 ", TAG_SIZE);
- const int is_vp8l = !memcmp(data, "VP8L", TAG_SIZE);
- const uint32_t minimal_size =
- TAG_SIZE + CHUNK_HEADER_SIZE; // "WEBP" + "VP8 nnnn" OR
- // "WEBP" + "VP8Lnnnn"
- assert(data != NULL);
- assert(data_size != NULL);
- assert(chunk_size != NULL);
- assert(is_lossless != NULL);
-
- if (*data_size < CHUNK_HEADER_SIZE) {
- return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data.
- }
-
- if (is_vp8 || is_vp8l) {
- // Bitstream contains VP8/VP8L header.
- const uint32_t size = GetLE32(data + TAG_SIZE);
- if ((riff_size >= minimal_size) && (size > riff_size - minimal_size)) {
- return VP8_STATUS_BITSTREAM_ERROR; // Inconsistent size information.
- }
- if (have_all_data && (size > *data_size - CHUNK_HEADER_SIZE)) {
- return VP8_STATUS_NOT_ENOUGH_DATA; // Truncated bitstream.
- }
- // Skip over CHUNK_HEADER_SIZE bytes from VP8/VP8L Header.
- *chunk_size = size;
- *data_ptr += CHUNK_HEADER_SIZE;
- *data_size -= CHUNK_HEADER_SIZE;
- *is_lossless = is_vp8l;
- } else {
- // Raw VP8/VP8L bitstream (no header).
- *is_lossless = VP8LCheckSignature(data, *data_size);
- *chunk_size = *data_size;
- }
-
- return VP8_STATUS_OK;
-}
-
-//------------------------------------------------------------------------------
-
-// Fetch '*width', '*height', '*has_alpha' and fill out 'headers' based on
-// 'data'. All the output parameters may be NULL. If 'headers' is NULL only the
-// minimal amount will be read to fetch the remaining parameters.
-// If 'headers' is non-NULL this function will attempt to locate both alpha
-// data (with or without a VP8X chunk) and the bitstream chunk (VP8/VP8L).
-// Note: The following chunk sequences (before the raw VP8/VP8L data) are
-// considered valid by this function:
-// RIFF + VP8(L)
-// RIFF + VP8X + (optional chunks) + VP8(L)
-// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
-// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
-static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
- size_t data_size,
- int* const width,
- int* const height,
- int* const has_alpha,
- int* const has_animation,
- int* const format,
- WebPHeaderStructure* const headers) {
- int canvas_width = 0;
- int canvas_height = 0;
- int image_width = 0;
- int image_height = 0;
- int found_riff = 0;
- int found_vp8x = 0;
- int animation_present = 0;
- const int have_all_data = (headers != NULL) ? headers->have_all_data : 0;
-
- VP8StatusCode status;
- WebPHeaderStructure hdrs;
-
- if (data == NULL || data_size < RIFF_HEADER_SIZE) {
- return VP8_STATUS_NOT_ENOUGH_DATA;
- }
- memset(&hdrs, 0, sizeof(hdrs));
- hdrs.data = data;
- hdrs.data_size = data_size;
-
- // Skip over RIFF header.
- status = ParseRIFF(&data, &data_size, have_all_data, &hdrs.riff_size);
- if (status != VP8_STATUS_OK) {
- return status; // Wrong RIFF header / insufficient data.
- }
- found_riff = (hdrs.riff_size > 0);
-
- // Skip over VP8X.
- {
- uint32_t flags = 0;
- status = ParseVP8X(&data, &data_size, &found_vp8x,
- &canvas_width, &canvas_height, &flags);
- if (status != VP8_STATUS_OK) {
- return status; // Wrong VP8X / insufficient data.
- }
- animation_present = !!(flags & ANIMATION_FLAG);
- if (!found_riff && found_vp8x) {
- // Note: This restriction may be removed in the future, if it becomes
- // necessary to send VP8X chunk to the decoder.
- return VP8_STATUS_BITSTREAM_ERROR;
- }
- if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG);
- if (has_animation != NULL) *has_animation = animation_present;
- if (format != NULL) *format = 0; // default = undefined
-
- image_width = canvas_width;
- image_height = canvas_height;
- if (found_vp8x && animation_present && headers == NULL) {
- status = VP8_STATUS_OK;
- goto ReturnWidthHeight; // Just return features from VP8X header.
- }
- }
-
- if (data_size < TAG_SIZE) {
- status = VP8_STATUS_NOT_ENOUGH_DATA;
- goto ReturnWidthHeight;
- }
-
- // Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH".
- if ((found_riff && found_vp8x) ||
- (!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) {
- status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size,
- &hdrs.alpha_data, &hdrs.alpha_data_size);
- if (status != VP8_STATUS_OK) {
- goto ReturnWidthHeight; // Invalid chunk size / insufficient data.
- }
- }
-
- // Skip over VP8/VP8L header.
- status = ParseVP8Header(&data, &data_size, have_all_data, hdrs.riff_size,
- &hdrs.compressed_size, &hdrs.is_lossless);
- if (status != VP8_STATUS_OK) {
- goto ReturnWidthHeight; // Wrong VP8/VP8L chunk-header / insufficient data.
- }
- if (hdrs.compressed_size > MAX_CHUNK_PAYLOAD) {
- return VP8_STATUS_BITSTREAM_ERROR;
- }
-
- if (format != NULL && !animation_present) {
- *format = hdrs.is_lossless ? 2 : 1;
- }
-
- if (!hdrs.is_lossless) {
- if (data_size < VP8_FRAME_HEADER_SIZE) {
- status = VP8_STATUS_NOT_ENOUGH_DATA;
- goto ReturnWidthHeight;
- }
- // Validates raw VP8 data.
- if (!VP8GetInfo(data, data_size, (uint32_t)hdrs.compressed_size,
- &image_width, &image_height)) {
- return VP8_STATUS_BITSTREAM_ERROR;
- }
- } else {
- if (data_size < VP8L_FRAME_HEADER_SIZE) {
- status = VP8_STATUS_NOT_ENOUGH_DATA;
- goto ReturnWidthHeight;
- }
- // Validates raw VP8L data.
- if (!VP8LGetInfo(data, data_size, &image_width, &image_height, has_alpha)) {
- return VP8_STATUS_BITSTREAM_ERROR;
- }
- }
- // Validates image size coherency.
- if (found_vp8x) {
- if (canvas_width != image_width || canvas_height != image_height) {
- return VP8_STATUS_BITSTREAM_ERROR;
- }
- }
- if (headers != NULL) {
- *headers = hdrs;
- headers->offset = data - headers->data;
- assert((uint64_t)(data - headers->data) < MAX_CHUNK_PAYLOAD);
- assert(headers->offset == headers->data_size - data_size);
- }
- ReturnWidthHeight:
- if (status == VP8_STATUS_OK ||
- (status == VP8_STATUS_NOT_ENOUGH_DATA && found_vp8x && headers == NULL)) {
- if (has_alpha != NULL) {
- // If the data did not contain a VP8X/VP8L chunk the only definitive way
- // to set this is by looking for alpha data (from an ALPH chunk).
- *has_alpha |= (hdrs.alpha_data != NULL);
- }
- if (width != NULL) *width = image_width;
- if (height != NULL) *height = image_height;
- return VP8_STATUS_OK;
- } else {
- return status;
- }
-}
-
-VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) {
- // status is marked volatile as a workaround for a clang-3.8 (aarch64) bug
- volatile VP8StatusCode status;
- int has_animation = 0;
- assert(headers != NULL);
- // fill out headers, ignore width/height/has_alpha.
- status = ParseHeadersInternal(headers->data, headers->data_size,
- NULL, NULL, NULL, &has_animation,
- NULL, headers);
- if (status == VP8_STATUS_OK || status == VP8_STATUS_NOT_ENOUGH_DATA) {
- // TODO(jzern): full support of animation frames will require API additions.
- if (has_animation) {
- status = VP8_STATUS_UNSUPPORTED_FEATURE;
- }
- }
- return status;
-}
-
-//------------------------------------------------------------------------------
-// WebPDecParams
-
-void WebPResetDecParams(WebPDecParams* const params) {
- if (params != NULL) {
- memset(params, 0, sizeof(*params));
- }
-}
-
-//------------------------------------------------------------------------------
-// "Into" decoding variants
-
-// Main flow
-static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
- WebPDecParams* const params) {
- VP8StatusCode status;
- VP8Io io;
- WebPHeaderStructure headers;
-
- headers.data = data;
- headers.data_size = data_size;
- headers.have_all_data = 1;
- status = WebPParseHeaders(&headers); // Process Pre-VP8 chunks.
- if (status != VP8_STATUS_OK) {
- return status;
- }
-
- assert(params != NULL);
- VP8InitIo(&io);
- io.data = headers.data + headers.offset;
- io.data_size = headers.data_size - headers.offset;
- WebPInitCustomIo(params, &io); // Plug the I/O functions.
-
- if (!headers.is_lossless) {
- VP8Decoder* const dec = VP8New();
- if (dec == NULL) {
- return VP8_STATUS_OUT_OF_MEMORY;
- }
- dec->alpha_data_ = headers.alpha_data;
- dec->alpha_data_size_ = headers.alpha_data_size;
-
- // Decode bitstream header, update io->width/io->height.
- if (!VP8GetHeaders(dec, &io)) {
- status = dec->status_; // An error occurred. Grab error status.
- } else {
- // Allocate/check output buffers.
- status = WebPAllocateDecBuffer(io.width, io.height, params->options,
- params->output);
- if (status == VP8_STATUS_OK) { // Decode
- // This change must be done before calling VP8Decode()
- dec->mt_method_ = VP8GetThreadMethod(params->options, &headers,
- io.width, io.height);
- VP8InitDithering(params->options, dec);
- if (!VP8Decode(dec, &io)) {
- status = dec->status_;
- }
- }
- }
- VP8Delete(dec);
- } else {
- VP8LDecoder* const dec = VP8LNew();
- if (dec == NULL) {
- return VP8_STATUS_OUT_OF_MEMORY;
- }
- if (!VP8LDecodeHeader(dec, &io)) {
- status = dec->status_; // An error occurred. Grab error status.
- } else {
- // Allocate/check output buffers.
- status = WebPAllocateDecBuffer(io.width, io.height, params->options,
- params->output);
- if (status == VP8_STATUS_OK) { // Decode
- if (!VP8LDecodeImage(dec)) {
- status = dec->status_;
- }
- }
- }
- VP8LDelete(dec);
- }
-
- if (status != VP8_STATUS_OK) {
- WebPFreeDecBuffer(params->output);
- } else {
- if (params->options != NULL && params->options->flip) {
- // This restores the original stride values if options->flip was used
- // during the call to WebPAllocateDecBuffer above.
- status = WebPFlipBuffer(params->output);
- }
- }
- return status;
-}
-
-// Helpers
-static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace,
- const uint8_t* const data,
- size_t data_size,
- uint8_t* const rgba,
- int stride, size_t size) {
- WebPDecParams params;
- WebPDecBuffer buf;
- if (rgba == NULL) {
- return NULL;
- }
- WebPInitDecBuffer(&buf);
- WebPResetDecParams(&params);
- params.output = &buf;
- buf.colorspace = colorspace;
- buf.u.RGBA.rgba = rgba;
- buf.u.RGBA.stride = stride;
- buf.u.RGBA.size = size;
- buf.is_external_memory = 1;
- if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) {
- return NULL;
- }
- return rgba;
-}
-
-uint8_t* WebPDecodeRGBInto(const uint8_t* data, size_t data_size,
- uint8_t* output, size_t size, int stride) {
- return DecodeIntoRGBABuffer(MODE_RGB, data, data_size, output, stride, size);
-}
-
-uint8_t* WebPDecodeRGBAInto(const uint8_t* data, size_t data_size,
- uint8_t* output, size_t size, int stride) {
- return DecodeIntoRGBABuffer(MODE_RGBA, data, data_size, output, stride, size);
-}
-
-uint8_t* WebPDecodeARGBInto(const uint8_t* data, size_t data_size,
- uint8_t* output, size_t size, int stride) {
- return DecodeIntoRGBABuffer(MODE_ARGB, data, data_size, output, stride, size);
-}
-
-uint8_t* WebPDecodeBGRInto(const uint8_t* data, size_t data_size,
- uint8_t* output, size_t size, int stride) {
- return DecodeIntoRGBABuffer(MODE_BGR, data, data_size, output, stride, size);
-}
-
-uint8_t* WebPDecodeBGRAInto(const uint8_t* data, size_t data_size,
- uint8_t* output, size_t size, int stride) {
- return DecodeIntoRGBABuffer(MODE_BGRA, data, data_size, output, stride, size);
-}
-
-uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size,
- 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) {
- WebPDecParams params;
- WebPDecBuffer output;
- if (luma == NULL) return NULL;
- WebPInitDecBuffer(&output);
- WebPResetDecParams(&params);
- params.output = &output;
- output.colorspace = MODE_YUV;
- output.u.YUVA.y = luma;
- output.u.YUVA.y_stride = luma_stride;
- output.u.YUVA.y_size = luma_size;
- output.u.YUVA.u = u;
- output.u.YUVA.u_stride = u_stride;
- output.u.YUVA.u_size = u_size;
- output.u.YUVA.v = v;
- output.u.YUVA.v_stride = v_stride;
- output.u.YUVA.v_size = v_size;
- output.is_external_memory = 1;
- if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) {
- return NULL;
- }
- return luma;
-}
-
-//------------------------------------------------------------------------------
-
-static uint8_t* Decode(WEBP_CSP_MODE mode, const uint8_t* const data,
- size_t data_size, int* const width, int* const height,
- WebPDecBuffer* const keep_info) {
- WebPDecParams params;
- WebPDecBuffer output;
-
- WebPInitDecBuffer(&output);
- WebPResetDecParams(&params);
- params.output = &output;
- output.colorspace = mode;
-
- // Retrieve (and report back) the required dimensions from bitstream.
- if (!WebPGetInfo(data, data_size, &output.width, &output.height)) {
- return NULL;
- }
- if (width != NULL) *width = output.width;
- if (height != NULL) *height = output.height;
-
- // Decode
- if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) {
- return NULL;
- }
- if (keep_info != NULL) { // keep track of the side-info
- WebPCopyDecBuffer(&output, keep_info);
- }
- // return decoded samples (don't clear 'output'!)
- return WebPIsRGBMode(mode) ? output.u.RGBA.rgba : output.u.YUVA.y;
-}
-
-uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size,
- int* width, int* height) {
- return Decode(MODE_RGB, data, data_size, width, height, NULL);
-}
-
-uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size,
- int* width, int* height) {
- return Decode(MODE_RGBA, data, data_size, width, height, NULL);
-}
-
-uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size,
- int* width, int* height) {
- return Decode(MODE_ARGB, data, data_size, width, height, NULL);
-}
-
-uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size,
- int* width, int* height) {
- return Decode(MODE_BGR, data, data_size, width, height, NULL);
-}
-
-uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size,
- int* width, int* height) {
- return Decode(MODE_BGRA, data, data_size, width, height, NULL);
-}
-
-uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size,
- int* width, int* height, uint8_t** u, uint8_t** v,
- int* stride, int* uv_stride) {
- WebPDecBuffer output; // only to preserve the side-infos
- uint8_t* const out = Decode(MODE_YUV, data, data_size,
- width, height, &output);
-
- if (out != NULL) {
- const WebPYUVABuffer* const buf = &output.u.YUVA;
- *u = buf->u;
- *v = buf->v;
- *stride = buf->y_stride;
- *uv_stride = buf->u_stride;
- assert(buf->u_stride == buf->v_stride);
- }
- return out;
-}
-
-static void DefaultFeatures(WebPBitstreamFeatures* const features) {
- assert(features != NULL);
- memset(features, 0, sizeof(*features));
-}
-
-static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size,
- WebPBitstreamFeatures* const features) {
- if (features == NULL || data == NULL) {
- return VP8_STATUS_INVALID_PARAM;
- }
- DefaultFeatures(features);
-
- // Only parse enough of the data to retrieve the features.
- return ParseHeadersInternal(data, data_size,
- &features->width, &features->height,
- &features->has_alpha, &features->has_animation,
- &features->format, NULL);
-}
-
-//------------------------------------------------------------------------------
-// WebPGetInfo()
-
-int WebPGetInfo(const uint8_t* data, size_t data_size,
- int* width, int* height) {
- WebPBitstreamFeatures features;
-
- if (GetFeatures(data, data_size, &features) != VP8_STATUS_OK) {
- return 0;
- }
-
- if (width != NULL) {
- *width = features.width;
- }
- if (height != NULL) {
- *height = features.height;
- }
-
- return 1;
-}
-
-//------------------------------------------------------------------------------
-// Advance decoding API
-
-int WebPInitDecoderConfigInternal(WebPDecoderConfig* config,
- int version) {
- if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
- return 0; // version mismatch
- }
- if (config == NULL) {
- return 0;
- }
- memset(config, 0, sizeof(*config));
- DefaultFeatures(&config->input);
- WebPInitDecBuffer(&config->output);
- return 1;
-}
-
-VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size,
- WebPBitstreamFeatures* features,
- int version) {
- if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
- return VP8_STATUS_INVALID_PARAM; // version mismatch
- }
- if (features == NULL) {
- return VP8_STATUS_INVALID_PARAM;
- }
- return GetFeatures(data, data_size, features);
-}
-
-VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
- WebPDecoderConfig* config) {
- WebPDecParams params;
- VP8StatusCode status;
-
- if (config == NULL) {
- return VP8_STATUS_INVALID_PARAM;
- }
-
- status = GetFeatures(data, data_size, &config->input);
- if (status != VP8_STATUS_OK) {
- if (status == VP8_STATUS_NOT_ENOUGH_DATA) {
- return VP8_STATUS_BITSTREAM_ERROR; // Not-enough-data treated as error.
- }
- return status;
- }
-
- WebPResetDecParams(&params);
- params.options = &config->options;
- params.output = &config->output;
- if (WebPAvoidSlowMemory(params.output, &config->input)) {
- // decoding to slow memory: use a temporary in-mem buffer to decode into.
- WebPDecBuffer in_mem_buffer;
- WebPInitDecBuffer(&in_mem_buffer);
- in_mem_buffer.colorspace = config->output.colorspace;
- in_mem_buffer.width = config->input.width;
- in_mem_buffer.height = config->input.height;
- params.output = &in_mem_buffer;
- status = DecodeInto(data, data_size, &params);
- if (status == VP8_STATUS_OK) { // do the slow-copy
- status = WebPCopyDecBufferPixels(&in_mem_buffer, &config->output);
- }
- WebPFreeDecBuffer(&in_mem_buffer);
- } else {
- status = DecodeInto(data, data_size, &params);
- }
-
- return status;
-}
-
-//------------------------------------------------------------------------------
-// Cropping and rescaling.
-
-int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
- VP8Io* const io, WEBP_CSP_MODE src_colorspace) {
- const int W = io->width;
- const int H = io->height;
- int x = 0, y = 0, w = W, h = H;
-
- // Cropping
- io->use_cropping = (options != NULL) && (options->use_cropping > 0);
- if (io->use_cropping) {
- w = options->crop_width;
- h = options->crop_height;
- x = options->crop_left;
- y = options->crop_top;
- if (!WebPIsRGBMode(src_colorspace)) { // only snap for YUV420
- x &= ~1;
- y &= ~1;
- }
- if (x < 0 || y < 0 || w <= 0 || h <= 0 || x + w > W || y + h > H) {
- return 0; // out of frame boundary error
- }
- }
- io->crop_left = x;
- io->crop_top = y;
- io->crop_right = x + w;
- io->crop_bottom = y + h;
- io->mb_w = w;
- io->mb_h = h;
-
- // Scaling
- io->use_scaling = (options != NULL) && (options->use_scaling > 0);
- if (io->use_scaling) {
- int scaled_width = options->scaled_width;
- int scaled_height = options->scaled_height;
- if (!WebPRescalerGetScaledDimensions(w, h, &scaled_width, &scaled_height)) {
- return 0;
- }
- io->scaled_width = scaled_width;
- io->scaled_height = scaled_height;
- }
-
- // Filter
- io->bypass_filtering = (options != NULL) && options->bypass_filtering;
-
- // Fancy upsampler
-#ifdef FANCY_UPSAMPLING
- io->fancy_upsampling = (options == NULL) || (!options->no_fancy_upsampling);
-#endif
-
- if (io->use_scaling) {
- // disable filter (only for large downscaling ratio).
- io->bypass_filtering = (io->scaled_width < W * 3 / 4) &&
- (io->scaled_height < H * 3 / 4);
- io->fancy_upsampling = 0;
- }
- return 1;
-}
-
-//------------------------------------------------------------------------------
diff --git a/thirdparty/libwebp/dec/webpi_dec.h b/thirdparty/libwebp/dec/webpi_dec.h
deleted file mode 100644
index 696abc1958..0000000000
--- a/thirdparty/libwebp/dec/webpi_dec.h
+++ /dev/null
@@ -1,133 +0,0 @@
-// 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.
-// -----------------------------------------------------------------------------
-//
-// Internal header: WebP decoding parameters and custom IO on buffer
-//
-// Author: somnath@google.com (Somnath Banerjee)
-
-#ifndef WEBP_DEC_WEBPI_H_
-#define WEBP_DEC_WEBPI_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "../utils/rescaler_utils.h"
-#include "./vp8_dec.h"
-
-//------------------------------------------------------------------------------
-// WebPDecParams: Decoding output parameters. Transient internal object.
-
-typedef struct WebPDecParams WebPDecParams;
-typedef int (*OutputFunc)(const VP8Io* const io, WebPDecParams* const p);
-typedef int (*OutputAlphaFunc)(const VP8Io* const io, WebPDecParams* const p,
- int expected_num_out_lines);
-typedef int (*OutputRowFunc)(WebPDecParams* const p, int y_pos,
- int max_out_lines);
-
-struct WebPDecParams {
- WebPDecBuffer* output; // output buffer.
- uint8_t* tmp_y, *tmp_u, *tmp_v; // cache for the fancy upsampler
- // or used for tmp rescaling
-
- int last_y; // coordinate of the line that was last output
- const WebPDecoderOptions* options; // if not NULL, use alt decoding features
-
- WebPRescaler* scaler_y, *scaler_u, *scaler_v, *scaler_a; // rescalers
- void* memory; // overall scratch memory for the output work.
-
- OutputFunc emit; // output RGB or YUV samples
- OutputAlphaFunc emit_alpha; // output alpha channel
- OutputRowFunc emit_alpha_row; // output one line of rescaled alpha values
-};
-
-// Should be called first, before any use of the WebPDecParams object.
-void WebPResetDecParams(WebPDecParams* const params);
-
-//------------------------------------------------------------------------------
-// Header parsing helpers
-
-// Structure storing a description of the RIFF headers.
-typedef struct {
- const uint8_t* data; // input buffer
- size_t data_size; // input buffer size
- int have_all_data; // true if all data is known to be available
- size_t offset; // offset to main data chunk (VP8 or VP8L)
- const uint8_t* alpha_data; // points to alpha chunk (if present)
- size_t alpha_data_size; // alpha chunk size
- size_t compressed_size; // VP8/VP8L compressed data size
- size_t riff_size; // size of the riff payload (or 0 if absent)
- int is_lossless; // true if a VP8L chunk is present
-} WebPHeaderStructure;
-
-// Skips over all valid chunks prior to the first VP8/VP8L frame header.
-// Returns: VP8_STATUS_OK, VP8_STATUS_BITSTREAM_ERROR (invalid header/chunk),
-// VP8_STATUS_NOT_ENOUGH_DATA (partial input) or VP8_STATUS_UNSUPPORTED_FEATURE
-// in the case of non-decodable features (animation for instance).
-// In 'headers', compressed_size, offset, alpha_data, alpha_size, and lossless
-// fields are updated appropriately upon success.
-VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers);
-
-//------------------------------------------------------------------------------
-// Misc utils
-
-// Initializes VP8Io with custom setup, io and teardown functions. The default
-// hooks will use the supplied 'params' as io->opaque handle.
-void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io);
-
-// Setup crop_xxx fields, mb_w and mb_h in io. 'src_colorspace' refers
-// to the *compressed* format, not the output one.
-int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
- VP8Io* const io, WEBP_CSP_MODE src_colorspace);
-
-//------------------------------------------------------------------------------
-// Internal functions regarding WebPDecBuffer memory (in buffer.c).
-// Don't really need to be externally visible for now.
-
-// Prepare 'buffer' with the requested initial dimensions width/height.
-// If no external storage is supplied, initializes buffer by allocating output
-// memory and setting up the stride information. Validate the parameters. Return
-// an error code in case of problem (no memory, or invalid stride / size /
-// dimension / etc.). If *options is not NULL, also verify that the options'
-// parameters are valid and apply them to the width/height dimensions of the
-// output buffer. This takes cropping / scaling / rotation into account.
-// Also incorporates the options->flip flag to flip the buffer parameters if
-// needed.
-VP8StatusCode WebPAllocateDecBuffer(int width, int height,
- const WebPDecoderOptions* const options,
- WebPDecBuffer* const buffer);
-
-// Flip buffer vertically by negating the various strides.
-VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer);
-
-// Copy 'src' into 'dst' buffer, making sure 'dst' is not marked as owner of the
-// memory (still held by 'src'). No pixels are copied.
-void WebPCopyDecBuffer(const WebPDecBuffer* const src,
- WebPDecBuffer* const dst);
-
-// Copy and transfer ownership from src to dst (beware of parameter order!)
-void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst);
-
-// Copy pixels from 'src' into a *preallocated* 'dst' buffer. Returns
-// VP8_STATUS_INVALID_PARAM if the 'dst' is not set up correctly for the copy.
-VP8StatusCode WebPCopyDecBufferPixels(const WebPDecBuffer* const src,
- WebPDecBuffer* const dst);
-
-// Returns true if decoding will be slow with the current configuration
-// and bitstream features.
-int WebPAvoidSlowMemory(const WebPDecBuffer* const output,
- const WebPBitstreamFeatures* const features);
-
-//------------------------------------------------------------------------------
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif /* WEBP_DEC_WEBPI_H_ */