diff options
Diffstat (limited to 'drivers/webp/dec/vp8.c')
-rw-r--r-- | drivers/webp/dec/vp8.c | 398 |
1 files changed, 236 insertions, 162 deletions
diff --git a/drivers/webp/dec/vp8.c b/drivers/webp/dec/vp8.c index bfd0e8f9d3..b0ccfa2a06 100644 --- a/drivers/webp/dec/vp8.c +++ b/drivers/webp/dec/vp8.c @@ -1,10 +1,8 @@ // 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. +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ // ----------------------------------------------------------------------------- // // main entry for the decoder @@ -13,12 +11,15 @@ #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) { @@ -120,9 +121,6 @@ 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; @@ -238,6 +236,20 @@ static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) { } } dec->filter_type_ = (hdr->level_ == 0) ? 0 : hdr->simple_ ? 1 : 2; + if (dec->filter_type_ > 0) { // precompute filter levels per segment + if (dec->segment_hdr_.use_segment_) { + int s; + for (s = 0; s < NUM_MB_SEGMENTS; ++s) { + int strength = dec->segment_hdr_.filter_strength_[s]; + if (!dec->segment_hdr_.absolute_delta_) { + strength += hdr->level_; + } + dec->filter_levels_[s] = strength; + } + } else { + dec->filter_levels_[0] = hdr->level_; + } + } return !br->eof_; } @@ -249,6 +261,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { VP8PictureHeader* pic_hdr; VP8BitReader* br; VP8StatusCode status; + WebPHeaderStructure headers; if (dec == NULL) { return 0; @@ -258,8 +271,33 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { return VP8SetError(dec, VP8_STATUS_INVALID_PARAM, "null VP8Io passed to VP8GetHeaders()"); } - buf = io->data; - buf_size = io->data_size; + + // 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 if (buf_size < 4) { return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, "Truncated header."); @@ -355,11 +393,38 @@ 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; } - VP8Get(br); // ignore the value of update_proba_ + // 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 VP8ParseProba(br, dec); @@ -393,7 +458,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { //------------------------------------------------------------------------------ // Residual decoding (Paragraph 13.2 / 13.3) -static const int kBands[16 + 1] = { +static const uint8_t kBands[16 + 1] = { 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 0 // extra entry as sentinel }; @@ -408,163 +473,168 @@ 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; -} +typedef const uint8_t (*ProbaArray)[NUM_CTX][NUM_PROBAS]; // for const-casting // Returns the position of the last non-zero coeff plus one -static int GetCoeffs(VP8BitReader* const br, const VP8BandProbas* const prob, +// (and 0 if there's no coeff at all) +static int GetCoeffs(VP8BitReader* const br, ProbaArray 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].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[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; + const uint8_t* p = prob[n][ctx]; + if (!VP8GetBit(br, p[0])) { // first EOB is more a 'CBP' bit. + return 0; + } + while (1) { + ++n; + if (!VP8GetBit(br, p[1])) { + p = prob[kBands[n]][0]; + } else { // non zero coeff + int v, j; if (!VP8GetBit(br, p[2])) { + p = prob[kBands[n]][1]; v = 1; - p = p_ctx[1]; } else { - v = GetLargeValue(br, p); - p = p_ctx[2]; + 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); + } + } + p = prob[kBands[n]][2]; } - out[kZigzag[n]] = VP8GetSigned(br, v) * dq[n > 0]; + j = kZigzag[n - 1]; + out[j] = VP8GetSigned(br, v) * dq[j > 0]; + if (n == 16 || !VP8GetBit(br, p[0])) { // EOB + return n; + } + } + if (n == 16) { + return 16; } } - return 16; } -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_; +// 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_; VP8MB* const left_mb = dec->mb_info_ - 1; - uint8_t tnz, lnz; - uint32_t non_zero_y = 0; - uint32_t non_zero_uv = 0; + PackedNz nz_ac, nz_dc; + PackedNz tnz, lnz; + uint32_t non_zero_ac = 0; + uint32_t non_zero_dc = 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 (!block->is_i4x4_) { // parse DC + if (!dec->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; - } + 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); first = 1; - ac_proba = bands[0]; + ac_prob = (ProbaArray)dec->proba_.coeffs_[0]; + VP8TransformWHT(dc, dst); } else { first = 0; - ac_proba = bands[3]; + ac_prob = (ProbaArray)dec->proba_.coeffs_[3]; } - tnz = mb->nz_ & 0x0f; - lnz = left_mb->nz_ & 0x0f; + tnz = kUnpackTab[mb->nz_ & 0xf]; + lnz = kUnpackTab[left_mb->nz_ & 0xf]; for (y = 0; y < 4; ++y) { - int l = lnz & 1; - uint32_t nz_coeffs = 0; + int l = lnz.i8[y]; 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); + 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); dst += 16; } - tnz >>= 4; - lnz = (lnz >> 1) | (l << 7); - non_zero_y = (non_zero_y << 8) | nz_coeffs; + lnz.i8[y] = l; + non_zero_dc |= PACK(nz_dc, 24 - y * 4); + non_zero_ac |= PACK(nz_ac, 24 - y * 4); } - out_t_nz = tnz; - out_l_nz = lnz >> 4; + out_t_nz = PACK(tnz, 24); + out_l_nz = PACK(lnz, 24); + 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 & 1; + int l = lnz.i8[ch + y]; 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); + 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); dst += 16; } - tnz >>= 2; - lnz = (lnz >> 1) | (l << 5); + lnz.i8[ch + y] = l; } - // 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; + non_zero_dc |= PACK(nz_dc, 8 - ch * 2); + non_zero_ac |= PACK(nz_ac, 8 - ch * 2); } + out_t_nz |= PACK(tnz, 20); + out_l_nz |= PACK(lnz, 20); 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 + dec->non_zero_ac_ = non_zero_ac; + dec->non_zero_ = non_zero_ac | non_zero_dc; + mb->skip_ = !dec->non_zero_; } +#undef PACK //------------------------------------------------------------------------------ // Main loop @@ -572,9 +642,7 @@ static int 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 mb = dec->mb_info_ + dec->mb_x_; - VP8MBData* const block = dec->mb_data_ + dec->mb_x_; - int skip; + VP8MB* const info = dec->mb_info_ + dec->mb_x_; // Note: we don't save segment map (yet), as we don't expect // to decode more than 1 keyframe. @@ -584,64 +652,67 @@ int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br) { VP8GetBit(br, dec->proba_.segments_[1]) : 2 + VP8GetBit(br, dec->proba_.segments_[2]); } - skip = dec->use_skip_proba_ ? VP8GetBit(br, dec->skip_p_) : 0; + info->skip_ = dec->use_skip_proba_ ? VP8GetBit(br, dec->skip_p_) : 0; VP8ParseIntraMode(br, dec); if (br->eof_) { return 0; } - if (!skip) { - skip = ParseResiduals(dec, mb, token_br); + if (!info->skip_) { + ParseResiduals(dec, info, token_br); } else { - left->nz_ = mb->nz_ = 0; - if (!block->is_i4x4_) { - left->nz_dc_ = mb->nz_dc_ = 0; + left->nz_ = info->nz_ = 0; + if (!dec->is_i4x4_) { + left->dc_nz_ = info->dc_nz_ = 0; } - block->non_zero_y_ = 0; - block->non_zero_uv_ = 0; + dec->non_zero_ = 0; + dec->non_zero_ac_ = 0; } - if (dec->filter_type_ > 0) { // store filter info - VP8FInfo* const finfo = dec->f_info_ + dec->mb_x_; - *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->nz_dc_ = 0; + left->dc_nz_ = 0; memset(dec->intra_l_, B_DC_PRED, sizeof(dec->intra_l_)); - dec->mb_x_ = 0; + dec->filter_row_ = + (dec->filter_type_ > 0) && + (dec->mb_y_ >= dec->tl_mb_y_) && (dec->mb_y_ <= dec->br_mb_y_); } 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)]; - for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) { + VP8InitScanline(dec); + for (dec->mb_x_ = 0; 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 + VP8ReconstructBlock(dec); - // Reconstruct, filter and emit the row. + // Store data and save block's filtering params + VP8StoreBlock(dec); + } if (!VP8ProcessRow(dec, io)) { return VP8SetError(dec, VP8_STATUS_USER_ABORT, "Output aborted."); } } - if (dec->mt_method_ > 0) { - if (!WebPWorkerSync(&dec->worker_)) return 0; + if (dec->use_threads_ && !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)) { @@ -697,12 +768,12 @@ void VP8Clear(VP8Decoder* const dec) { if (dec == NULL) { return; } - if (dec->mt_method_ > 0) { + if (dec->use_threads_) { WebPWorkerEnd(&dec->worker_); } - ALPHDelete(dec->alph_dec_); - dec->alph_dec_ = NULL; - free(dec->mem_); + if (dec->mem_) { + free(dec->mem_); + } dec->mem_ = NULL; dec->mem_size_ = 0; memset(&dec->br_, 0, sizeof(dec->br_)); @@ -711,3 +782,6 @@ void VP8Clear(VP8Decoder* const dec) { //------------------------------------------------------------------------------ +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif |