static int ParseResiduals()

in Extended/libwebp/src/dec/vp8_dec.c [513:602]


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
}