static void decode_b(AVCodecContext *ctx, int row, int col, struct VP9Filter *lflvl, ptrdiff_t yoff, ptrdiff_t uvoff, enum BlockLevel bl, enum BlockPartition bp) { VP9Context *s = ctx->priv_data; VP9Block *b = s->b; enum BlockSize bs = bl * 3 + bp; int bytesperpixel = s->bytesperpixel; int w4 = bwh_tab[1][bs][0], h4 = bwh_tab[1][bs][1], lvl; int emu[2]; AVFrame *f = s->frames[CUR_FRAME].tf.f; s->row = row; s->row7 = row & 7; s->col = col; s->col7 = col & 7; s->min_mv.x = -(128 + col * 64); s->min_mv.y = -(128 + row * 64); s->max_mv.x = 128 + (s->cols - col - w4) * 64; s->max_mv.y = 128 + (s->rows - row - h4) * 64; if (s->pass < 2) { b->bs = bs; b->bl = bl; b->bp = bp; decode_mode(ctx); b->uvtx = b->tx - ((s->ss_h && w4 * 2 == (1 << b->tx)) || (s->ss_v && h4 * 2 == (1 << b->tx))); if (!b->skip) { int has_coeffs; if (bytesperpixel == 1) { has_coeffs = decode_coeffs_8bpp(ctx); } else { has_coeffs = decode_coeffs_16bpp(ctx); } if (!has_coeffs && b->bs <= BS_8x8 && !b->intra) { b->skip = 1; memset(&s->above_skip_ctx[col], 1, w4); memset(&s->left_skip_ctx[s->row7], 1, h4); } } else { int row7 = s->row7; #define SPLAT_ZERO_CTX(v, n) \ switch (n) { \ case 1: v = 0; break; \ case 2: AV_ZERO16(&v); break; \ case 4: AV_ZERO32(&v); break; \ case 8: AV_ZERO64(&v); break; \ case 16: AV_ZERO128(&v); break; \ } #define SPLAT_ZERO_YUV(dir, var, off, n, dir2) \ do { \ SPLAT_ZERO_CTX(s->dir##_y_##var[off * 2], n * 2); \ if (s->ss_##dir2) { \ SPLAT_ZERO_CTX(s->dir##_uv_##var[0][off], n); \ SPLAT_ZERO_CTX(s->dir##_uv_##var[1][off], n); \ } else { \ SPLAT_ZERO_CTX(s->dir##_uv_##var[0][off * 2], n * 2); \ SPLAT_ZERO_CTX(s->dir##_uv_##var[1][off * 2], n * 2); \ } \ } while (0) switch (w4) { case 1: SPLAT_ZERO_YUV(above, nnz_ctx, col, 1, h); break; case 2: SPLAT_ZERO_YUV(above, nnz_ctx, col, 2, h); break; case 4: SPLAT_ZERO_YUV(above, nnz_ctx, col, 4, h); break; case 8: SPLAT_ZERO_YUV(above, nnz_ctx, col, 8, h); break; } switch (h4) { case 1: SPLAT_ZERO_YUV(left, nnz_ctx, row7, 1, v); break; case 2: SPLAT_ZERO_YUV(left, nnz_ctx, row7, 2, v); break; case 4: SPLAT_ZERO_YUV(left, nnz_ctx, row7, 4, v); break; case 8: SPLAT_ZERO_YUV(left, nnz_ctx, row7, 8, v); break; } } if (s->pass == 1) { s->b++; s->block += w4 * h4 * 64 * bytesperpixel; s->uvblock[0] += w4 * h4 * 64 * bytesperpixel >> (s->ss_h + s->ss_v); s->uvblock[1] += w4 * h4 * 64 * bytesperpixel >> (s->ss_h + s->ss_v); s->eob += 4 * w4 * h4; s->uveob[0] += 4 * w4 * h4 >> (s->ss_h + s->ss_v); s->uveob[1] += 4 * w4 * h4 >> (s->ss_h + s->ss_v); return; } } // emulated overhangs if the stride of the target buffer can't hold. This // makes it possible to support emu-edge and so on even if we have large block // overhangs emu[0] = (col + w4) * 8 > f->linesize[0] || (row + h4) > s->rows; emu[1] = (col + w4) * 4 > f->linesize[1] || (row + h4) > s->rows; if (emu[0]) { s->dst[0] = s->tmp_y; s->y_stride = 128; } else { s->dst[0] = f->data[0] + yoff; s->y_stride = f->linesize[0]; } if (emu[1]) { s->dst[1] = s->tmp_uv[0]; s->dst[2] = s->tmp_uv[1]; s->uv_stride = 128; } else { s->dst[1] = f->data[1] + uvoff; s->dst[2] = f->data[2] + uvoff; s->uv_stride = f->linesize[1]; } if (b->intra) { if (s->bpp > 8) { intra_recon_16bpp(ctx, yoff, uvoff); } else { intra_recon_8bpp(ctx, yoff, uvoff); } } else { if (s->bpp > 8) { inter_recon_16bpp(ctx); } else { inter_recon_8bpp(ctx); } } if (emu[0]) { int w = FFMIN(s->cols - col, w4) * 8, h = FFMIN(s->rows - row, h4) * 8, n, o = 0; for (n = 0; o < w; n++) { int bw = 64 >> n; av_assert2(n <= 4); if (w & bw) { s->dsp.mc[n][0][0][0][0](f->data[0] + yoff + o * bytesperpixel, f->linesize[0], s->tmp_y + o * bytesperpixel, 128, h, 0, 0); o += bw; } } } if (emu[1]) { int w = FFMIN(s->cols - col, w4) * 8 >> s->ss_h; int h = FFMIN(s->rows - row, h4) * 8 >> s->ss_v, n, o = 0; for (n = s->ss_h; o < w; n++) { int bw = 64 >> n; av_assert2(n <= 4); if (w & bw) { s->dsp.mc[n][0][0][0][0](f->data[1] + uvoff + o * bytesperpixel, f->linesize[1], s->tmp_uv[0] + o * bytesperpixel, 128, h, 0, 0); s->dsp.mc[n][0][0][0][0](f->data[2] + uvoff + o * bytesperpixel, f->linesize[2], s->tmp_uv[1] + o * bytesperpixel, 128, h, 0, 0); o += bw; } } } // pick filter level and find edges to apply filter to if (s->filter.level && (lvl = s->segmentation.feat[b->seg_id].lflvl[b->intra ? 0 : b->ref[0] + 1] [b->mode[3] != ZEROMV]) > 0) { int x_end = FFMIN(s->cols - col, w4), y_end = FFMIN(s->rows - row, h4); int skip_inter = !b->intra && b->skip, col7 = s->col7, row7 = s->row7; setctx_2d(&lflvl->level[row7 * 8 + col7], w4, h4, 8, lvl); mask_edges(lflvl->mask[0], 0, 0, row7, col7, x_end, y_end, 0, 0, b->tx, skip_inter); if (s->ss_h || s->ss_v) mask_edges(lflvl->mask[1], s->ss_h, s->ss_v, row7, col7, x_end, y_end, s->cols & 1 && col + w4 >= s->cols ? s->cols & 7 : 0, s->rows & 1 && row + h4 >= s->rows ? s->rows & 7 : 0, b->uvtx, skip_inter); if (!s->filter.lim_lut[lvl]) { int sharp = s->filter.sharpness; int limit = lvl; if (sharp > 0) { limit >>= (sharp + 3) >> 2; limit = FFMIN(limit, 9 - sharp); } limit = FFMAX(limit, 1); s->filter.lim_lut[lvl] = limit; s->filter.mblim_lut[lvl] = 2 * (lvl + 2) + limit; } } if (s->pass == 2) { s->b++; s->block += w4 * h4 * 64 * bytesperpixel; s->uvblock[0] += w4 * h4 * 64 * bytesperpixel >> (s->ss_v + s->ss_h); s->uvblock[1] += w4 * h4 * 64 * bytesperpixel >> (s->ss_v + s->ss_h); s->eob += 4 * w4 * h4; s->uveob[0] += 4 * w4 * h4 >> (s->ss_v + s->ss_h); s->uveob[1] += 4 * w4 * h4 >> (s->ss_v + s->ss_h); } }