| Index: third_party/libwebp/dec/vp8.c
|
| diff --git a/third_party/libwebp/dec/vp8.c b/third_party/libwebp/dec/vp8.c
|
| index 8632e48e572e5fe6d10c384757c259450550697c..bfd0e8f9d3827ad77469d9ef8137acfadddcd7ab 100644
|
| --- a/third_party/libwebp/dec/vp8.c
|
| +++ b/third_party/libwebp/dec/vp8.c
|
| @@ -13,15 +13,12 @@
|
|
|
| #include <stdlib.h>
|
|
|
| +#include "./alphai.h"
|
| #include "./vp8i.h"
|
| #include "./vp8li.h"
|
| #include "./webpi.h"
|
| #include "../utils/bit_reader.h"
|
|
|
| -#if defined(__cplusplus) || defined(c_plusplus)
|
| -extern "C" {
|
| -#endif
|
| -
|
| //------------------------------------------------------------------------------
|
|
|
| int WebPGetDecoderVersion(void) {
|
| @@ -123,6 +120,9 @@ int VP8GetInfo(const uint8_t* data, size_t data_size, size_t chunk_size,
|
| 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;
|
| @@ -249,7 +249,6 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
| VP8PictureHeader* pic_hdr;
|
| VP8BitReader* br;
|
| VP8StatusCode status;
|
| - WebPHeaderStructure headers;
|
|
|
| if (dec == NULL) {
|
| return 0;
|
| @@ -259,33 +258,8 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
| return VP8SetError(dec, VP8_STATUS_INVALID_PARAM,
|
| "null VP8Io passed to VP8GetHeaders()");
|
| }
|
| -
|
| - // Process Pre-VP8 chunks.
|
| - headers.data = io->data;
|
| - headers.data_size = io->data_size;
|
| - status = WebPParseHeaders(&headers);
|
| - if (status != VP8_STATUS_OK) {
|
| - return VP8SetError(dec, status, "Incorrect/incomplete header.");
|
| - }
|
| - if (headers.is_lossless) {
|
| - return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
|
| - "Unexpected lossless format encountered.");
|
| - }
|
| -
|
| - if (dec->alpha_data_ == NULL) {
|
| - assert(dec->alpha_data_size_ == 0);
|
| - // We have NOT set alpha data yet. Set it now.
|
| - // (This is to ensure that dec->alpha_data_ is NOT reset to NULL if
|
| - // WebPParseHeaders() is called more than once, as in incremental decoding
|
| - // case.)
|
| - dec->alpha_data_ = headers.alpha_data;
|
| - dec->alpha_data_size_ = headers.alpha_data_size;
|
| - }
|
| -
|
| - // Process the VP8 frame header.
|
| - buf = headers.data + headers.offset;
|
| - buf_size = headers.data_size - headers.offset;
|
| - assert(headers.data_size >= headers.offset); // WebPParseHeaders' guarantee
|
| + buf = io->data;
|
| + buf_size = io->data_size;
|
| if (buf_size < 4) {
|
| return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
|
| "Truncated header.");
|
| @@ -381,38 +355,11 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
|
|
| // Frame buffer marking
|
| if (!frm_hdr->key_frame_) {
|
| - // Paragraph 9.7
|
| -#ifndef ONLY_KEYFRAME_CODE
|
| - dec->buffer_flags_ = VP8Get(br) << 0; // update golden
|
| - dec->buffer_flags_ |= VP8Get(br) << 1; // update alt ref
|
| - if (!(dec->buffer_flags_ & 1)) {
|
| - dec->buffer_flags_ |= VP8GetValue(br, 2) << 2;
|
| - }
|
| - if (!(dec->buffer_flags_ & 2)) {
|
| - dec->buffer_flags_ |= VP8GetValue(br, 2) << 4;
|
| - }
|
| - dec->buffer_flags_ |= VP8Get(br) << 6; // sign bias golden
|
| - dec->buffer_flags_ |= VP8Get(br) << 7; // sign bias alt ref
|
| -#else
|
| return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE,
|
| "Not a key frame.");
|
| -#endif
|
| - } else {
|
| - dec->buffer_flags_ = 0x003 | 0x100;
|
| }
|
|
|
| - // Paragraph 9.8
|
| -#ifndef ONLY_KEYFRAME_CODE
|
| - dec->update_proba_ = VP8Get(br);
|
| - if (!dec->update_proba_) { // save for later restore
|
| - dec->proba_saved_ = dec->proba_;
|
| - }
|
| - dec->buffer_flags_ &= 1 << 8;
|
| - dec->buffer_flags_ |=
|
| - (frm_hdr->key_frame_ || VP8Get(br)) << 8; // refresh last frame
|
| -#else
|
| - VP8Get(br); // just ignore the value of update_proba_
|
| -#endif
|
| + VP8Get(br); // ignore the value of update_proba_
|
|
|
| VP8ParseProba(br, dec);
|
|
|
| @@ -461,9 +408,6 @@ static const uint8_t kZigzag[16] = {
|
| 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15
|
| };
|
|
|
| -typedef const uint8_t (*ProbaArray)[NUM_CTX][NUM_PROBAS]; // for const-casting
|
| -typedef const uint8_t (*ProbaCtxArray)[NUM_PROBAS];
|
| -
|
| // 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;
|
| @@ -497,19 +441,20 @@ static int GetLargeValue(VP8BitReader* const br, const uint8_t* const p) {
|
| }
|
|
|
| // Returns the position of the last non-zero coeff plus one
|
| -// (and 0 if there's no coeff at all)
|
| -static int GetCoeffs(VP8BitReader* const br, ProbaArray prob,
|
| +static int GetCoeffs(VP8BitReader* const br, const VP8BandProbas* const prob,
|
| int ctx, const quant_t dq, int n, int16_t* out) {
|
| // n is either 0 or 1 here. kBands[n] is not necessary for extracting '*p'.
|
| - const uint8_t* p = prob[n][ctx];
|
| - if (!VP8GetBit(br, p[0])) { // first EOB is more a 'CBP' bit.
|
| - return 0;
|
| - }
|
| + const uint8_t* p = prob[n].probas_[ctx];
|
| for (; n < 16; ++n) {
|
| - const ProbaCtxArray p_ctx = prob[kBands[n + 1]];
|
| - if (!VP8GetBit(br, p[1])) {
|
| - p = p_ctx[0];
|
| - } else { // non zero coeff
|
| + 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[kBands[++n]].probas_[0];
|
| + if (n == 16) return 16;
|
| + }
|
| + { // non zero coeff
|
| + const VP8ProbaArray* const p_ctx = &prob[kBands[n + 1]].probas_[0];
|
| int v;
|
| if (!VP8GetBit(br, p[2])) {
|
| v = 1;
|
| @@ -519,115 +464,107 @@ static int GetCoeffs(VP8BitReader* const br, ProbaArray prob,
|
| p = p_ctx[2];
|
| }
|
| out[kZigzag[n]] = VP8GetSigned(br, v) * dq[n > 0];
|
| - if (n < 15 && !VP8GetBit(br, p[0])) { // EOB
|
| - return n + 1;
|
| - }
|
| }
|
| }
|
| return 16;
|
| }
|
|
|
| -// Alias-safe way of converting 4bytes to 32bits.
|
| -typedef union {
|
| - uint8_t i8[4];
|
| - uint32_t i32;
|
| -} PackedNz;
|
| -
|
| -// Table to unpack four bits into four bytes
|
| -static const PackedNz kUnpackTab[16] = {
|
| - {{0, 0, 0, 0}}, {{1, 0, 0, 0}}, {{0, 1, 0, 0}}, {{1, 1, 0, 0}},
|
| - {{0, 0, 1, 0}}, {{1, 0, 1, 0}}, {{0, 1, 1, 0}}, {{1, 1, 1, 0}},
|
| - {{0, 0, 0, 1}}, {{1, 0, 0, 1}}, {{0, 1, 0, 1}}, {{1, 1, 0, 1}},
|
| - {{0, 0, 1, 1}}, {{1, 0, 1, 1}}, {{0, 1, 1, 1}}, {{1, 1, 1, 1}} };
|
| -
|
| -// Macro to pack four LSB of four bytes into four bits.
|
| -#if defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || \
|
| - defined(__BIG_ENDIAN__)
|
| -#define PACK_CST 0x08040201U
|
| -#else
|
| -#define PACK_CST 0x01020408U
|
| -#endif
|
| -#define PACK(X, S) ((((X).i32 * PACK_CST) & 0xff000000) >> (S))
|
| -
|
| -static void ParseResiduals(VP8Decoder* const dec,
|
| - VP8MB* const mb, VP8BitReader* const token_br) {
|
| - int out_t_nz, out_l_nz, first;
|
| - ProbaArray ac_prob;
|
| - const VP8QuantMatrix* q = &dec->dqm_[dec->segment_];
|
| - int16_t* dst = dec->coeffs_;
|
| +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) {
|
| + VP8BandProbas (* const bands)[NUM_BANDS] = dec->proba_.bands_;
|
| + const VP8BandProbas* ac_proba;
|
| + const VP8QuantMatrix* const q = &dec->dqm_[dec->segment_];
|
| + VP8MBData* const block = dec->mb_data_ + dec->mb_x_;
|
| + int16_t* dst = block->coeffs_;
|
| VP8MB* const left_mb = dec->mb_info_ - 1;
|
| - PackedNz nz_ac, nz_dc;
|
| - PackedNz tnz, lnz;
|
| - uint32_t non_zero_ac = 0;
|
| - uint32_t non_zero_dc = 0;
|
| + 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;
|
|
|
| - nz_dc.i32 = nz_ac.i32 = 0;
|
| memset(dst, 0, 384 * sizeof(*dst));
|
| - if (!dec->is_i4x4_) { // parse DC
|
| + if (!block->is_i4x4_) { // parse DC
|
| int16_t dc[16] = { 0 };
|
| - const int ctx = mb->dc_nz_ + left_mb->dc_nz_;
|
| - mb->dc_nz_ = left_mb->dc_nz_ =
|
| - (GetCoeffs(token_br, (ProbaArray)dec->proba_.coeffs_[1],
|
| - ctx, q->y2_mat_, 0, dc) > 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_prob = (ProbaArray)dec->proba_.coeffs_[0];
|
| - VP8TransformWHT(dc, dst);
|
| + ac_proba = bands[0];
|
| } else {
|
| first = 0;
|
| - ac_prob = (ProbaArray)dec->proba_.coeffs_[3];
|
| + ac_proba = bands[3];
|
| }
|
|
|
| - tnz = kUnpackTab[mb->nz_ & 0xf];
|
| - lnz = kUnpackTab[left_mb->nz_ & 0xf];
|
| + tnz = mb->nz_ & 0x0f;
|
| + lnz = left_mb->nz_ & 0x0f;
|
| for (y = 0; y < 4; ++y) {
|
| - int l = lnz.i8[y];
|
| + int l = lnz & 1;
|
| + uint32_t nz_coeffs = 0;
|
| for (x = 0; x < 4; ++x) {
|
| - const int ctx = l + tnz.i8[x];
|
| - const int nz = GetCoeffs(token_br, ac_prob, ctx,
|
| - q->y1_mat_, first, dst);
|
| - tnz.i8[x] = l = (nz > 0);
|
| - nz_dc.i8[x] = (dst[0] != 0);
|
| - nz_ac.i8[x] = (nz > 1);
|
| + 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;
|
| }
|
| - lnz.i8[y] = l;
|
| - non_zero_dc |= PACK(nz_dc, 24 - y * 4);
|
| - non_zero_ac |= PACK(nz_ac, 24 - y * 4);
|
| + tnz >>= 4;
|
| + lnz = (lnz >> 1) | (l << 7);
|
| + non_zero_y = (non_zero_y << 8) | nz_coeffs;
|
| }
|
| - out_t_nz = PACK(tnz, 24);
|
| - out_l_nz = PACK(lnz, 24);
|
| + out_t_nz = tnz;
|
| + out_l_nz = lnz >> 4;
|
|
|
| - tnz = kUnpackTab[mb->nz_ >> 4];
|
| - lnz = kUnpackTab[left_mb->nz_ >> 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.i8[ch + y];
|
| + int l = lnz & 1;
|
| for (x = 0; x < 2; ++x) {
|
| - const int ctx = l + tnz.i8[ch + x];
|
| - const int nz =
|
| - GetCoeffs(token_br, (ProbaArray)dec->proba_.coeffs_[2],
|
| - ctx, q->uv_mat_, 0, dst);
|
| - tnz.i8[ch + x] = l = (nz > 0);
|
| - nz_dc.i8[y * 2 + x] = (dst[0] != 0);
|
| - nz_ac.i8[y * 2 + x] = (nz > 1);
|
| + 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;
|
| }
|
| - lnz.i8[ch + y] = l;
|
| + tnz >>= 2;
|
| + lnz = (lnz >> 1) | (l << 5);
|
| }
|
| - non_zero_dc |= PACK(nz_dc, 8 - ch * 2);
|
| - non_zero_ac |= PACK(nz_ac, 8 - ch * 2);
|
| + // 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;
|
| }
|
| - out_t_nz |= PACK(tnz, 20);
|
| - out_l_nz |= PACK(lnz, 20);
|
| mb->nz_ = out_t_nz;
|
| left_mb->nz_ = out_l_nz;
|
|
|
| - dec->non_zero_ac_ = non_zero_ac;
|
| - dec->non_zero_ = non_zero_ac | non_zero_dc;
|
| - mb->skip_ = !dec->non_zero_;
|
| + 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
|
| }
|
| -#undef PACK
|
|
|
| //------------------------------------------------------------------------------
|
| // Main loop
|
| @@ -635,7 +572,9 @@ static void ParseResiduals(VP8Decoder* const dec,
|
| int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br) {
|
| VP8BitReader* const br = &dec->br_;
|
| VP8MB* const left = dec->mb_info_ - 1;
|
| - VP8MB* const info = dec->mb_info_ + dec->mb_x_;
|
| + VP8MB* const mb = dec->mb_info_ + dec->mb_x_;
|
| + VP8MBData* const block = dec->mb_data_ + dec->mb_x_;
|
| + int skip;
|
|
|
| // Note: we don't save segment map (yet), as we don't expect
|
| // to decode more than 1 keyframe.
|
| @@ -645,71 +584,64 @@ int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br) {
|
| VP8GetBit(br, dec->proba_.segments_[1]) :
|
| 2 + VP8GetBit(br, dec->proba_.segments_[2]);
|
| }
|
| - info->skip_ = dec->use_skip_proba_ ? VP8GetBit(br, dec->skip_p_) : 0;
|
| + skip = dec->use_skip_proba_ ? VP8GetBit(br, dec->skip_p_) : 0;
|
|
|
| VP8ParseIntraMode(br, dec);
|
| if (br->eof_) {
|
| return 0;
|
| }
|
|
|
| - if (!info->skip_) {
|
| - ParseResiduals(dec, info, token_br);
|
| + if (!skip) {
|
| + skip = ParseResiduals(dec, mb, token_br);
|
| } else {
|
| - left->nz_ = info->nz_ = 0;
|
| - if (!dec->is_i4x4_) {
|
| - left->dc_nz_ = info->dc_nz_ = 0;
|
| + left->nz_ = mb->nz_ = 0;
|
| + if (!block->is_i4x4_) {
|
| + left->nz_dc_ = mb->nz_dc_ = 0;
|
| }
|
| - dec->non_zero_ = 0;
|
| - dec->non_zero_ac_ = 0;
|
| + block->non_zero_y_ = 0;
|
| + block->non_zero_uv_ = 0;
|
| }
|
|
|
| if (dec->filter_type_ > 0) { // store filter info
|
| VP8FInfo* const finfo = dec->f_info_ + dec->mb_x_;
|
| - *finfo = dec->fstrengths_[dec->segment_][dec->is_i4x4_];
|
| - finfo->f_inner_ = (!info->skip_ || dec->is_i4x4_);
|
| + *finfo = dec->fstrengths_[dec->segment_][block->is_i4x4_];
|
| + finfo->f_inner_ |= !skip;
|
| }
|
|
|
| - return (!token_br->eof_);
|
| + return !token_br->eof_;
|
| }
|
|
|
| void VP8InitScanline(VP8Decoder* const dec) {
|
| VP8MB* const left = dec->mb_info_ - 1;
|
| left->nz_ = 0;
|
| - left->dc_nz_ = 0;
|
| + left->nz_dc_ = 0;
|
| memset(dec->intra_l_, B_DC_PRED, sizeof(dec->intra_l_));
|
| - dec->filter_row_ =
|
| - (dec->filter_type_ > 0) &&
|
| - (dec->mb_y_ >= dec->tl_mb_y_) && (dec->mb_y_ <= dec->br_mb_y_);
|
| + 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_ - 1)];
|
| - VP8InitScanline(dec);
|
| - for (dec->mb_x_ = 0; dec->mb_x_ < dec->mb_w_; dec->mb_x_++) {
|
| + 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.");
|
| }
|
| - // Reconstruct and emit samples.
|
| - VP8ReconstructBlock(dec);
|
| }
|
| + 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->use_threads_ && !WebPWorkerSync(&dec->worker_)) {
|
| - return 0;
|
| + if (dec->mt_method_ > 0) {
|
| + if (!WebPWorkerSync(&dec->worker_)) return 0;
|
| }
|
|
|
| // Finish
|
| -#ifndef ONLY_KEYFRAME_CODE
|
| - if (!dec->update_proba_) {
|
| - dec->proba_ = dec->proba_saved_;
|
| - }
|
| -#endif
|
| -
|
| #ifdef WEBP_EXPERIMENTAL_FEATURES
|
| if (dec->layer_data_size_ > 0) {
|
| if (!VP8DecodeLayer(dec)) {
|
| @@ -765,12 +697,12 @@ void VP8Clear(VP8Decoder* const dec) {
|
| if (dec == NULL) {
|
| return;
|
| }
|
| - if (dec->use_threads_) {
|
| + if (dec->mt_method_ > 0) {
|
| WebPWorkerEnd(&dec->worker_);
|
| }
|
| - if (dec->mem_) {
|
| - free(dec->mem_);
|
| - }
|
| + ALPHDelete(dec->alph_dec_);
|
| + dec->alph_dec_ = NULL;
|
| + free(dec->mem_);
|
| dec->mem_ = NULL;
|
| dec->mem_size_ = 0;
|
| memset(&dec->br_, 0, sizeof(dec->br_));
|
| @@ -779,6 +711,3 @@ void VP8Clear(VP8Decoder* const dec) {
|
|
|
| //------------------------------------------------------------------------------
|
|
|
| -#if defined(__cplusplus) || defined(c_plusplus)
|
| -} // extern "C"
|
| -#endif
|
|
|