| /* |
| * VP9 compatible video decoder |
| * |
| * Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com> |
| * Copyright (C) 2013 Clément Bœsch <u pkh me> |
| * |
| * This file is part of FFmpeg. |
| * |
| * FFmpeg is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * FFmpeg is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with FFmpeg; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| #include "avcodec.h" |
| #include "get_bits.h" |
| #include "internal.h" |
| #include "profiles.h" |
| #include "thread.h" |
| #include "videodsp.h" |
| #include "vp56.h" |
| #include "vp9.h" |
| #include "vp9data.h" |
| #include "vp9dsp.h" |
| #include "libavutil/avassert.h" |
| #include "libavutil/pixdesc.h" |
| |
| #define VP9_SYNCCODE 0x498342 |
| |
| struct VP9Filter { |
| uint8_t level[8 * 8]; |
| uint8_t /* bit=col */ mask[2 /* 0=y, 1=uv */][2 /* 0=col, 1=row */] |
| [8 /* rows */][4 /* 0=16, 1=8, 2=4, 3=inner4 */]; |
| }; |
| |
| typedef struct VP9Block { |
| uint8_t seg_id, intra, comp, ref[2], mode[4], uvmode, skip; |
| enum FilterMode filter; |
| VP56mv mv[4 /* b_idx */][2 /* ref */]; |
| enum BlockSize bs; |
| enum TxfmMode tx, uvtx; |
| enum BlockLevel bl; |
| enum BlockPartition bp; |
| } VP9Block; |
| |
| typedef struct VP9Context { |
| VP9SharedContext s; |
| |
| VP9DSPContext dsp; |
| VideoDSPContext vdsp; |
| GetBitContext gb; |
| VP56RangeCoder c; |
| VP56RangeCoder *c_b; |
| unsigned c_b_size; |
| VP9Block *b_base, *b; |
| int pass; |
| int row, row7, col, col7; |
| uint8_t *dst[3]; |
| ptrdiff_t y_stride, uv_stride; |
| |
| uint8_t ss_h, ss_v; |
| uint8_t last_bpp, bpp, bpp_index, bytesperpixel; |
| uint8_t last_keyframe; |
| // sb_cols/rows, rows/cols and last_fmt are used for allocating all internal |
| // arrays, and are thus per-thread. w/h and gf_fmt are synced between threads |
| // and are therefore per-stream. pix_fmt represents the value in the header |
| // of the currently processed frame. |
| int w, h; |
| enum AVPixelFormat pix_fmt, last_fmt, gf_fmt; |
| unsigned sb_cols, sb_rows, rows, cols; |
| ThreadFrame next_refs[8]; |
| |
| struct { |
| uint8_t lim_lut[64]; |
| uint8_t mblim_lut[64]; |
| } filter_lut; |
| unsigned tile_row_start, tile_row_end, tile_col_start, tile_col_end; |
| struct { |
| prob_context p; |
| uint8_t coef[4][2][2][6][6][3]; |
| } prob_ctx[4]; |
| struct { |
| prob_context p; |
| uint8_t coef[4][2][2][6][6][11]; |
| } prob; |
| struct { |
| unsigned y_mode[4][10]; |
| unsigned uv_mode[10][10]; |
| unsigned filter[4][3]; |
| unsigned mv_mode[7][4]; |
| unsigned intra[4][2]; |
| unsigned comp[5][2]; |
| unsigned single_ref[5][2][2]; |
| unsigned comp_ref[5][2]; |
| unsigned tx32p[2][4]; |
| unsigned tx16p[2][3]; |
| unsigned tx8p[2][2]; |
| unsigned skip[3][2]; |
| unsigned mv_joint[4]; |
| struct { |
| unsigned sign[2]; |
| unsigned classes[11]; |
| unsigned class0[2]; |
| unsigned bits[10][2]; |
| unsigned class0_fp[2][4]; |
| unsigned fp[4]; |
| unsigned class0_hp[2]; |
| unsigned hp[2]; |
| } mv_comp[2]; |
| unsigned partition[4][4][4]; |
| unsigned coef[4][2][2][6][6][3]; |
| unsigned eob[4][2][2][6][6][2]; |
| } counts; |
| |
| // contextual (left/above) cache |
| DECLARE_ALIGNED(16, uint8_t, left_y_nnz_ctx)[16]; |
| DECLARE_ALIGNED(16, uint8_t, left_mode_ctx)[16]; |
| DECLARE_ALIGNED(16, VP56mv, left_mv_ctx)[16][2]; |
| DECLARE_ALIGNED(16, uint8_t, left_uv_nnz_ctx)[2][16]; |
| DECLARE_ALIGNED(8, uint8_t, left_partition_ctx)[8]; |
| DECLARE_ALIGNED(8, uint8_t, left_skip_ctx)[8]; |
| DECLARE_ALIGNED(8, uint8_t, left_txfm_ctx)[8]; |
| DECLARE_ALIGNED(8, uint8_t, left_segpred_ctx)[8]; |
| DECLARE_ALIGNED(8, uint8_t, left_intra_ctx)[8]; |
| DECLARE_ALIGNED(8, uint8_t, left_comp_ctx)[8]; |
| DECLARE_ALIGNED(8, uint8_t, left_ref_ctx)[8]; |
| DECLARE_ALIGNED(8, uint8_t, left_filter_ctx)[8]; |
| uint8_t *above_partition_ctx; |
| uint8_t *above_mode_ctx; |
| // FIXME maybe merge some of the below in a flags field? |
| uint8_t *above_y_nnz_ctx; |
| uint8_t *above_uv_nnz_ctx[2]; |
| uint8_t *above_skip_ctx; // 1bit |
| uint8_t *above_txfm_ctx; // 2bit |
| uint8_t *above_segpred_ctx; // 1bit |
| uint8_t *above_intra_ctx; // 1bit |
| uint8_t *above_comp_ctx; // 1bit |
| uint8_t *above_ref_ctx; // 2bit |
| uint8_t *above_filter_ctx; |
| VP56mv (*above_mv_ctx)[2]; |
| |
| // whole-frame cache |
| uint8_t *intra_pred_data[3]; |
| struct VP9Filter *lflvl; |
| DECLARE_ALIGNED(32, uint8_t, edge_emu_buffer)[135 * 144 * 2]; |
| |
| // block reconstruction intermediates |
| int block_alloc_using_2pass; |
| int16_t *block_base, *block, *uvblock_base[2], *uvblock[2]; |
| uint8_t *eob_base, *uveob_base[2], *eob, *uveob[2]; |
| struct { int x, y; } min_mv, max_mv; |
| DECLARE_ALIGNED(32, uint8_t, tmp_y)[64 * 64 * 2]; |
| DECLARE_ALIGNED(32, uint8_t, tmp_uv)[2][64 * 64 * 2]; |
| uint16_t mvscale[3][2]; |
| uint8_t mvstep[3][2]; |
| } VP9Context; |
| |
| static const uint8_t bwh_tab[2][N_BS_SIZES][2] = { |
| { |
| { 16, 16 }, { 16, 8 }, { 8, 16 }, { 8, 8 }, { 8, 4 }, { 4, 8 }, |
| { 4, 4 }, { 4, 2 }, { 2, 4 }, { 2, 2 }, { 2, 1 }, { 1, 2 }, { 1, 1 }, |
| }, { |
| { 8, 8 }, { 8, 4 }, { 4, 8 }, { 4, 4 }, { 4, 2 }, { 2, 4 }, |
| { 2, 2 }, { 2, 1 }, { 1, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 }, { 1, 1 }, |
| } |
| }; |
| |
| static void vp9_unref_frame(AVCodecContext *ctx, VP9Frame *f) |
| { |
| ff_thread_release_buffer(ctx, &f->tf); |
| av_buffer_unref(&f->extradata); |
| av_buffer_unref(&f->hwaccel_priv_buf); |
| f->segmentation_map = NULL; |
| f->hwaccel_picture_private = NULL; |
| } |
| |
| static int vp9_alloc_frame(AVCodecContext *ctx, VP9Frame *f) |
| { |
| VP9Context *s = ctx->priv_data; |
| int ret, sz; |
| |
| if ((ret = ff_thread_get_buffer(ctx, &f->tf, AV_GET_BUFFER_FLAG_REF)) < 0) |
| return ret; |
| sz = 64 * s->sb_cols * s->sb_rows; |
| if (!(f->extradata = av_buffer_allocz(sz * (1 + sizeof(struct VP9mvrefPair))))) { |
| goto fail; |
| } |
| |
| f->segmentation_map = f->extradata->data; |
| f->mv = (struct VP9mvrefPair *) (f->extradata->data + sz); |
| |
| if (ctx->hwaccel) { |
| const AVHWAccel *hwaccel = ctx->hwaccel; |
| av_assert0(!f->hwaccel_picture_private); |
| if (hwaccel->frame_priv_data_size) { |
| f->hwaccel_priv_buf = av_buffer_allocz(hwaccel->frame_priv_data_size); |
| if (!f->hwaccel_priv_buf) |
| goto fail; |
| f->hwaccel_picture_private = f->hwaccel_priv_buf->data; |
| } |
| } |
| |
| return 0; |
| |
| fail: |
| vp9_unref_frame(ctx, f); |
| return AVERROR(ENOMEM); |
| } |
| |
| static int vp9_ref_frame(AVCodecContext *ctx, VP9Frame *dst, VP9Frame *src) |
| { |
| int res; |
| |
| if ((res = ff_thread_ref_frame(&dst->tf, &src->tf)) < 0) { |
| return res; |
| } else if (!(dst->extradata = av_buffer_ref(src->extradata))) { |
| goto fail; |
| } |
| |
| dst->segmentation_map = src->segmentation_map; |
| dst->mv = src->mv; |
| dst->uses_2pass = src->uses_2pass; |
| |
| if (src->hwaccel_picture_private) { |
| dst->hwaccel_priv_buf = av_buffer_ref(src->hwaccel_priv_buf); |
| if (!dst->hwaccel_priv_buf) |
| goto fail; |
| dst->hwaccel_picture_private = dst->hwaccel_priv_buf->data; |
| } |
| |
| return 0; |
| |
| fail: |
| vp9_unref_frame(ctx, dst); |
| return AVERROR(ENOMEM); |
| } |
| |
| static int update_size(AVCodecContext *ctx, int w, int h) |
| { |
| #define HWACCEL_MAX (CONFIG_VP9_DXVA2_HWACCEL + CONFIG_VP9_D3D11VA_HWACCEL + CONFIG_VP9_VAAPI_HWACCEL) |
| enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmtp = pix_fmts; |
| VP9Context *s = ctx->priv_data; |
| uint8_t *p; |
| int bytesperpixel = s->bytesperpixel, res, cols, rows; |
| |
| av_assert0(w > 0 && h > 0); |
| |
| if (!(s->pix_fmt == s->gf_fmt && w == s->w && h == s->h)) { |
| if ((res = ff_set_dimensions(ctx, w, h)) < 0) |
| return res; |
| |
| if (s->pix_fmt == AV_PIX_FMT_YUV420P) { |
| #if CONFIG_VP9_DXVA2_HWACCEL |
| *fmtp++ = AV_PIX_FMT_DXVA2_VLD; |
| #endif |
| #if CONFIG_VP9_D3D11VA_HWACCEL |
| *fmtp++ = AV_PIX_FMT_D3D11VA_VLD; |
| #endif |
| #if CONFIG_VP9_VAAPI_HWACCEL |
| *fmtp++ = AV_PIX_FMT_VAAPI; |
| #endif |
| } |
| |
| *fmtp++ = s->pix_fmt; |
| *fmtp = AV_PIX_FMT_NONE; |
| |
| res = ff_thread_get_format(ctx, pix_fmts); |
| if (res < 0) |
| return res; |
| |
| ctx->pix_fmt = res; |
| s->gf_fmt = s->pix_fmt; |
| s->w = w; |
| s->h = h; |
| } |
| |
| cols = (w + 7) >> 3; |
| rows = (h + 7) >> 3; |
| |
| if (s->intra_pred_data[0] && cols == s->cols && rows == s->rows && s->pix_fmt == s->last_fmt) |
| return 0; |
| |
| s->last_fmt = s->pix_fmt; |
| s->sb_cols = (w + 63) >> 6; |
| s->sb_rows = (h + 63) >> 6; |
| s->cols = (w + 7) >> 3; |
| s->rows = (h + 7) >> 3; |
| |
| #define assign(var, type, n) var = (type) p; p += s->sb_cols * (n) * sizeof(*var) |
| av_freep(&s->intra_pred_data[0]); |
| // FIXME we slightly over-allocate here for subsampled chroma, but a little |
| // bit of padding shouldn't affect performance... |
| p = av_malloc(s->sb_cols * (128 + 192 * bytesperpixel + |
| sizeof(*s->lflvl) + 16 * sizeof(*s->above_mv_ctx))); |
| if (!p) |
| return AVERROR(ENOMEM); |
| assign(s->intra_pred_data[0], uint8_t *, 64 * bytesperpixel); |
| assign(s->intra_pred_data[1], uint8_t *, 64 * bytesperpixel); |
| assign(s->intra_pred_data[2], uint8_t *, 64 * bytesperpixel); |
| assign(s->above_y_nnz_ctx, uint8_t *, 16); |
| assign(s->above_mode_ctx, uint8_t *, 16); |
| assign(s->above_mv_ctx, VP56mv(*)[2], 16); |
| assign(s->above_uv_nnz_ctx[0], uint8_t *, 16); |
| assign(s->above_uv_nnz_ctx[1], uint8_t *, 16); |
| assign(s->above_partition_ctx, uint8_t *, 8); |
| assign(s->above_skip_ctx, uint8_t *, 8); |
| assign(s->above_txfm_ctx, uint8_t *, 8); |
| assign(s->above_segpred_ctx, uint8_t *, 8); |
| assign(s->above_intra_ctx, uint8_t *, 8); |
| assign(s->above_comp_ctx, uint8_t *, 8); |
| assign(s->above_ref_ctx, uint8_t *, 8); |
| assign(s->above_filter_ctx, uint8_t *, 8); |
| assign(s->lflvl, struct VP9Filter *, 1); |
| #undef assign |
| |
| // these will be re-allocated a little later |
| av_freep(&s->b_base); |
| av_freep(&s->block_base); |
| |
| if (s->bpp != s->last_bpp) { |
| ff_vp9dsp_init(&s->dsp, s->bpp, ctx->flags & AV_CODEC_FLAG_BITEXACT); |
| ff_videodsp_init(&s->vdsp, s->bpp); |
| s->last_bpp = s->bpp; |
| } |
| |
| return 0; |
| } |
| |
| static int update_block_buffers(AVCodecContext *ctx) |
| { |
| VP9Context *s = ctx->priv_data; |
| int chroma_blocks, chroma_eobs, bytesperpixel = s->bytesperpixel; |
| |
| if (s->b_base && s->block_base && s->block_alloc_using_2pass == s->s.frames[CUR_FRAME].uses_2pass) |
| return 0; |
| |
| av_free(s->b_base); |
| av_free(s->block_base); |
| chroma_blocks = 64 * 64 >> (s->ss_h + s->ss_v); |
| chroma_eobs = 16 * 16 >> (s->ss_h + s->ss_v); |
| if (s->s.frames[CUR_FRAME].uses_2pass) { |
| int sbs = s->sb_cols * s->sb_rows; |
| |
| s->b_base = av_malloc_array(s->cols * s->rows, sizeof(VP9Block)); |
| s->block_base = av_mallocz(((64 * 64 + 2 * chroma_blocks) * bytesperpixel * sizeof(int16_t) + |
| 16 * 16 + 2 * chroma_eobs) * sbs); |
| if (!s->b_base || !s->block_base) |
| return AVERROR(ENOMEM); |
| s->uvblock_base[0] = s->block_base + sbs * 64 * 64 * bytesperpixel; |
| s->uvblock_base[1] = s->uvblock_base[0] + sbs * chroma_blocks * bytesperpixel; |
| s->eob_base = (uint8_t *) (s->uvblock_base[1] + sbs * chroma_blocks * bytesperpixel); |
| s->uveob_base[0] = s->eob_base + 16 * 16 * sbs; |
| s->uveob_base[1] = s->uveob_base[0] + chroma_eobs * sbs; |
| } else { |
| s->b_base = av_malloc(sizeof(VP9Block)); |
| s->block_base = av_mallocz((64 * 64 + 2 * chroma_blocks) * bytesperpixel * sizeof(int16_t) + |
| 16 * 16 + 2 * chroma_eobs); |
| if (!s->b_base || !s->block_base) |
| return AVERROR(ENOMEM); |
| s->uvblock_base[0] = s->block_base + 64 * 64 * bytesperpixel; |
| s->uvblock_base[1] = s->uvblock_base[0] + chroma_blocks * bytesperpixel; |
| s->eob_base = (uint8_t *) (s->uvblock_base[1] + chroma_blocks * bytesperpixel); |
| s->uveob_base[0] = s->eob_base + 16 * 16; |
| s->uveob_base[1] = s->uveob_base[0] + chroma_eobs; |
| } |
| s->block_alloc_using_2pass = s->s.frames[CUR_FRAME].uses_2pass; |
| |
| return 0; |
| } |
| |
| // for some reason the sign bit is at the end, not the start, of a bit sequence |
| static av_always_inline int get_sbits_inv(GetBitContext *gb, int n) |
| { |
| int v = get_bits(gb, n); |
| return get_bits1(gb) ? -v : v; |
| } |
| |
| static av_always_inline int inv_recenter_nonneg(int v, int m) |
| { |
| return v > 2 * m ? v : v & 1 ? m - ((v + 1) >> 1) : m + (v >> 1); |
| } |
| |
| // differential forward probability updates |
| static int update_prob(VP56RangeCoder *c, int p) |
| { |
| static const int inv_map_table[255] = { |
| 7, 20, 33, 46, 59, 72, 85, 98, 111, 124, 137, 150, 163, 176, |
| 189, 202, 215, 228, 241, 254, 1, 2, 3, 4, 5, 6, 8, 9, |
| 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, |
| 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, |
| 40, 41, 42, 43, 44, 45, 47, 48, 49, 50, 51, 52, 53, 54, |
| 55, 56, 57, 58, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, |
| 70, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, |
| 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 99, 100, |
| 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 112, 113, 114, 115, |
| 116, 117, 118, 119, 120, 121, 122, 123, 125, 126, 127, 128, 129, 130, |
| 131, 132, 133, 134, 135, 136, 138, 139, 140, 141, 142, 143, 144, 145, |
| 146, 147, 148, 149, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, |
| 161, 162, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, |
| 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 190, 191, |
| 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 203, 204, 205, 206, |
| 207, 208, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219, 220, 221, |
| 222, 223, 224, 225, 226, 227, 229, 230, 231, 232, 233, 234, 235, 236, |
| 237, 238, 239, 240, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, |
| 252, 253, 253, |
| }; |
| int d; |
| |
| /* This code is trying to do a differential probability update. For a |
| * current probability A in the range [1, 255], the difference to a new |
| * probability of any value can be expressed differentially as 1-A,255-A |
| * where some part of this (absolute range) exists both in positive as |
| * well as the negative part, whereas another part only exists in one |
| * half. We're trying to code this shared part differentially, i.e. |
| * times two where the value of the lowest bit specifies the sign, and |
| * the single part is then coded on top of this. This absolute difference |
| * then again has a value of [0,254], but a bigger value in this range |
| * indicates that we're further away from the original value A, so we |
| * can code this as a VLC code, since higher values are increasingly |
| * unlikely. The first 20 values in inv_map_table[] allow 'cheap, rough' |
| * updates vs. the 'fine, exact' updates further down the range, which |
| * adds one extra dimension to this differential update model. */ |
| |
| if (!vp8_rac_get(c)) { |
| d = vp8_rac_get_uint(c, 4) + 0; |
| } else if (!vp8_rac_get(c)) { |
| d = vp8_rac_get_uint(c, 4) + 16; |
| } else if (!vp8_rac_get(c)) { |
| d = vp8_rac_get_uint(c, 5) + 32; |
| } else { |
| d = vp8_rac_get_uint(c, 7); |
| if (d >= 65) |
| d = (d << 1) - 65 + vp8_rac_get(c); |
| d += 64; |
| av_assert2(d < FF_ARRAY_ELEMS(inv_map_table)); |
| } |
| |
| return p <= 128 ? 1 + inv_recenter_nonneg(inv_map_table[d], p - 1) : |
| 255 - inv_recenter_nonneg(inv_map_table[d], 255 - p); |
| } |
| |
| static int read_colorspace_details(AVCodecContext *ctx) |
| { |
| static const enum AVColorSpace colorspaces[8] = { |
| AVCOL_SPC_UNSPECIFIED, AVCOL_SPC_BT470BG, AVCOL_SPC_BT709, AVCOL_SPC_SMPTE170M, |
| AVCOL_SPC_SMPTE240M, AVCOL_SPC_BT2020_NCL, AVCOL_SPC_RESERVED, AVCOL_SPC_RGB, |
| }; |
| VP9Context *s = ctx->priv_data; |
| int bits = ctx->profile <= 1 ? 0 : 1 + get_bits1(&s->gb); // 0:8, 1:10, 2:12 |
| |
| s->bpp_index = bits; |
| s->bpp = 8 + bits * 2; |
| s->bytesperpixel = (7 + s->bpp) >> 3; |
| ctx->colorspace = colorspaces[get_bits(&s->gb, 3)]; |
| if (ctx->colorspace == AVCOL_SPC_RGB) { // RGB = profile 1 |
| static const enum AVPixelFormat pix_fmt_rgb[3] = { |
| AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12 |
| }; |
| s->ss_h = s->ss_v = 0; |
| ctx->color_range = AVCOL_RANGE_JPEG; |
| s->pix_fmt = pix_fmt_rgb[bits]; |
| if (ctx->profile & 1) { |
| if (get_bits1(&s->gb)) { |
| av_log(ctx, AV_LOG_ERROR, "Reserved bit set in RGB\n"); |
| return AVERROR_INVALIDDATA; |
| } |
| } else { |
| av_log(ctx, AV_LOG_ERROR, "RGB not supported in profile %d\n", |
| ctx->profile); |
| return AVERROR_INVALIDDATA; |
| } |
| } else { |
| static const enum AVPixelFormat pix_fmt_for_ss[3][2 /* v */][2 /* h */] = { |
| { { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P }, |
| { AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV420P } }, |
| { { AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10 }, |
| { AV_PIX_FMT_YUV440P10, AV_PIX_FMT_YUV420P10 } }, |
| { { AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12 }, |
| { AV_PIX_FMT_YUV440P12, AV_PIX_FMT_YUV420P12 } } |
| }; |
| ctx->color_range = get_bits1(&s->gb) ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; |
| if (ctx->profile & 1) { |
| s->ss_h = get_bits1(&s->gb); |
| s->ss_v = get_bits1(&s->gb); |
| s->pix_fmt = pix_fmt_for_ss[bits][s->ss_v][s->ss_h]; |
| if (s->pix_fmt == AV_PIX_FMT_YUV420P) { |
| av_log(ctx, AV_LOG_ERROR, "YUV 4:2:0 not supported in profile %d\n", |
| ctx->profile); |
| return AVERROR_INVALIDDATA; |
| } else if (get_bits1(&s->gb)) { |
| av_log(ctx, AV_LOG_ERROR, "Profile %d color details reserved bit set\n", |
| ctx->profile); |
| return AVERROR_INVALIDDATA; |
| } |
| } else { |
| s->ss_h = s->ss_v = 1; |
| s->pix_fmt = pix_fmt_for_ss[bits][1][1]; |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int decode_frame_header(AVCodecContext *ctx, |
| const uint8_t *data, int size, int *ref) |
| { |
| VP9Context *s = ctx->priv_data; |
| int c, i, j, k, l, m, n, w, h, max, size2, res, sharp; |
| int last_invisible; |
| const uint8_t *data2; |
| |
| /* general header */ |
| if ((res = init_get_bits8(&s->gb, data, size)) < 0) { |
| av_log(ctx, AV_LOG_ERROR, "Failed to initialize bitstream reader\n"); |
| return res; |
| } |
| if (get_bits(&s->gb, 2) != 0x2) { // frame marker |
| av_log(ctx, AV_LOG_ERROR, "Invalid frame marker\n"); |
| return AVERROR_INVALIDDATA; |
| } |
| ctx->profile = get_bits1(&s->gb); |
| ctx->profile |= get_bits1(&s->gb) << 1; |
| if (ctx->profile == 3) ctx->profile += get_bits1(&s->gb); |
| if (ctx->profile > 3) { |
| av_log(ctx, AV_LOG_ERROR, "Profile %d is not yet supported\n", ctx->profile); |
| return AVERROR_INVALIDDATA; |
| } |
| s->s.h.profile = ctx->profile; |
| if (get_bits1(&s->gb)) { |
| *ref = get_bits(&s->gb, 3); |
| return 0; |
| } |
| s->last_keyframe = s->s.h.keyframe; |
| s->s.h.keyframe = !get_bits1(&s->gb); |
| last_invisible = s->s.h.invisible; |
| s->s.h.invisible = !get_bits1(&s->gb); |
| s->s.h.errorres = get_bits1(&s->gb); |
| s->s.h.use_last_frame_mvs = !s->s.h.errorres && !last_invisible; |
| if (s->s.h.keyframe) { |
| if (get_bits_long(&s->gb, 24) != VP9_SYNCCODE) { // synccode |
| av_log(ctx, AV_LOG_ERROR, "Invalid sync code\n"); |
| return AVERROR_INVALIDDATA; |
| } |
| if ((res = read_colorspace_details(ctx)) < 0) |
| return res; |
| // for profile 1, here follows the subsampling bits |
| s->s.h.refreshrefmask = 0xff; |
| w = get_bits(&s->gb, 16) + 1; |
| h = get_bits(&s->gb, 16) + 1; |
| if (get_bits1(&s->gb)) // display size |
| skip_bits(&s->gb, 32); |
| } else { |
| s->s.h.intraonly = s->s.h.invisible ? get_bits1(&s->gb) : 0; |
| s->s.h.resetctx = s->s.h.errorres ? 0 : get_bits(&s->gb, 2); |
| if (s->s.h.intraonly) { |
| if (get_bits_long(&s->gb, 24) != VP9_SYNCCODE) { // synccode |
| av_log(ctx, AV_LOG_ERROR, "Invalid sync code\n"); |
| return AVERROR_INVALIDDATA; |
| } |
| if (ctx->profile >= 1) { |
| if ((res = read_colorspace_details(ctx)) < 0) |
| return res; |
| } else { |
| s->ss_h = s->ss_v = 1; |
| s->bpp = 8; |
| s->bpp_index = 0; |
| s->bytesperpixel = 1; |
| s->pix_fmt = AV_PIX_FMT_YUV420P; |
| ctx->colorspace = AVCOL_SPC_BT470BG; |
| ctx->color_range = AVCOL_RANGE_JPEG; |
| } |
| s->s.h.refreshrefmask = get_bits(&s->gb, 8); |
| w = get_bits(&s->gb, 16) + 1; |
| h = get_bits(&s->gb, 16) + 1; |
| if (get_bits1(&s->gb)) // display size |
| skip_bits(&s->gb, 32); |
| } else { |
| s->s.h.refreshrefmask = get_bits(&s->gb, 8); |
| s->s.h.refidx[0] = get_bits(&s->gb, 3); |
| s->s.h.signbias[0] = get_bits1(&s->gb) && !s->s.h.errorres; |
| s->s.h.refidx[1] = get_bits(&s->gb, 3); |
| s->s.h.signbias[1] = get_bits1(&s->gb) && !s->s.h.errorres; |
| s->s.h.refidx[2] = get_bits(&s->gb, 3); |
| s->s.h.signbias[2] = get_bits1(&s->gb) && !s->s.h.errorres; |
| if (!s->s.refs[s->s.h.refidx[0]].f->buf[0] || |
| !s->s.refs[s->s.h.refidx[1]].f->buf[0] || |
| !s->s.refs[s->s.h.refidx[2]].f->buf[0]) { |
| av_log(ctx, AV_LOG_ERROR, "Not all references are available\n"); |
| return AVERROR_INVALIDDATA; |
| } |
| if (get_bits1(&s->gb)) { |
| w = s->s.refs[s->s.h.refidx[0]].f->width; |
| h = s->s.refs[s->s.h.refidx[0]].f->height; |
| } else if (get_bits1(&s->gb)) { |
| w = s->s.refs[s->s.h.refidx[1]].f->width; |
| h = s->s.refs[s->s.h.refidx[1]].f->height; |
| } else if (get_bits1(&s->gb)) { |
| w = s->s.refs[s->s.h.refidx[2]].f->width; |
| h = s->s.refs[s->s.h.refidx[2]].f->height; |
| } else { |
| w = get_bits(&s->gb, 16) + 1; |
| h = get_bits(&s->gb, 16) + 1; |
| } |
| // Note that in this code, "CUR_FRAME" is actually before we |
| // have formally allocated a frame, and thus actually represents |
| // the _last_ frame |
| s->s.h.use_last_frame_mvs &= s->s.frames[CUR_FRAME].tf.f->width == w && |
| s->s.frames[CUR_FRAME].tf.f->height == h; |
| if (get_bits1(&s->gb)) // display size |
| skip_bits(&s->gb, 32); |
| s->s.h.highprecisionmvs = get_bits1(&s->gb); |
| s->s.h.filtermode = get_bits1(&s->gb) ? FILTER_SWITCHABLE : |
| get_bits(&s->gb, 2); |
| s->s.h.allowcompinter = s->s.h.signbias[0] != s->s.h.signbias[1] || |
| s->s.h.signbias[0] != s->s.h.signbias[2]; |
| if (s->s.h.allowcompinter) { |
| if (s->s.h.signbias[0] == s->s.h.signbias[1]) { |
| s->s.h.fixcompref = 2; |
| s->s.h.varcompref[0] = 0; |
| s->s.h.varcompref[1] = 1; |
| } else if (s->s.h.signbias[0] == s->s.h.signbias[2]) { |
| s->s.h.fixcompref = 1; |
| s->s.h.varcompref[0] = 0; |
| s->s.h.varcompref[1] = 2; |
| } else { |
| s->s.h.fixcompref = 0; |
| s->s.h.varcompref[0] = 1; |
| s->s.h.varcompref[1] = 2; |
| } |
| } |
| } |
| } |
| s->s.h.refreshctx = s->s.h.errorres ? 0 : get_bits1(&s->gb); |
| s->s.h.parallelmode = s->s.h.errorres ? 1 : get_bits1(&s->gb); |
| s->s.h.framectxid = c = get_bits(&s->gb, 2); |
| |
| /* loopfilter header data */ |
| if (s->s.h.keyframe || s->s.h.errorres || s->s.h.intraonly) { |
| // reset loopfilter defaults |
| s->s.h.lf_delta.ref[0] = 1; |
| s->s.h.lf_delta.ref[1] = 0; |
| s->s.h.lf_delta.ref[2] = -1; |
| s->s.h.lf_delta.ref[3] = -1; |
| s->s.h.lf_delta.mode[0] = 0; |
| s->s.h.lf_delta.mode[1] = 0; |
| memset(s->s.h.segmentation.feat, 0, sizeof(s->s.h.segmentation.feat)); |
| } |
| s->s.h.filter.level = get_bits(&s->gb, 6); |
| sharp = get_bits(&s->gb, 3); |
| // if sharpness changed, reinit lim/mblim LUTs. if it didn't change, keep |
| // the old cache values since they are still valid |
| if (s->s.h.filter.sharpness != sharp) |
| memset(s->filter_lut.lim_lut, 0, sizeof(s->filter_lut.lim_lut)); |
| s->s.h.filter.sharpness = sharp; |
| if ((s->s.h.lf_delta.enabled = get_bits1(&s->gb))) { |
| if ((s->s.h.lf_delta.updated = get_bits1(&s->gb))) { |
| for (i = 0; i < 4; i++) |
| if (get_bits1(&s->gb)) |
| s->s.h.lf_delta.ref[i] = get_sbits_inv(&s->gb, 6); |
| for (i = 0; i < 2; i++) |
| if (get_bits1(&s->gb)) |
| s->s.h.lf_delta.mode[i] = get_sbits_inv(&s->gb, 6); |
| } |
| } |
| |
| /* quantization header data */ |
| s->s.h.yac_qi = get_bits(&s->gb, 8); |
| s->s.h.ydc_qdelta = get_bits1(&s->gb) ? get_sbits_inv(&s->gb, 4) : 0; |
| s->s.h.uvdc_qdelta = get_bits1(&s->gb) ? get_sbits_inv(&s->gb, 4) : 0; |
| s->s.h.uvac_qdelta = get_bits1(&s->gb) ? get_sbits_inv(&s->gb, 4) : 0; |
| s->s.h.lossless = s->s.h.yac_qi == 0 && s->s.h.ydc_qdelta == 0 && |
| s->s.h.uvdc_qdelta == 0 && s->s.h.uvac_qdelta == 0; |
| if (s->s.h.lossless) |
| ctx->properties |= FF_CODEC_PROPERTY_LOSSLESS; |
| |
| /* segmentation header info */ |
| if ((s->s.h.segmentation.enabled = get_bits1(&s->gb))) { |
| if ((s->s.h.segmentation.update_map = get_bits1(&s->gb))) { |
| for (i = 0; i < 7; i++) |
| s->s.h.segmentation.prob[i] = get_bits1(&s->gb) ? |
| get_bits(&s->gb, 8) : 255; |
| if ((s->s.h.segmentation.temporal = get_bits1(&s->gb))) { |
| for (i = 0; i < 3; i++) |
| s->s.h.segmentation.pred_prob[i] = get_bits1(&s->gb) ? |
| get_bits(&s->gb, 8) : 255; |
| } |
| } |
| |
| if (get_bits1(&s->gb)) { |
| s->s.h.segmentation.absolute_vals = get_bits1(&s->gb); |
| for (i = 0; i < 8; i++) { |
| if ((s->s.h.segmentation.feat[i].q_enabled = get_bits1(&s->gb))) |
| s->s.h.segmentation.feat[i].q_val = get_sbits_inv(&s->gb, 8); |
| if ((s->s.h.segmentation.feat[i].lf_enabled = get_bits1(&s->gb))) |
| s->s.h.segmentation.feat[i].lf_val = get_sbits_inv(&s->gb, 6); |
| if ((s->s.h.segmentation.feat[i].ref_enabled = get_bits1(&s->gb))) |
| s->s.h.segmentation.feat[i].ref_val = get_bits(&s->gb, 2); |
| s->s.h.segmentation.feat[i].skip_enabled = get_bits1(&s->gb); |
| } |
| } |
| } |
| |
| // set qmul[] based on Y/UV, AC/DC and segmentation Q idx deltas |
| for (i = 0; i < (s->s.h.segmentation.enabled ? 8 : 1); i++) { |
| int qyac, qydc, quvac, quvdc, lflvl, sh; |
| |
| if (s->s.h.segmentation.enabled && s->s.h.segmentation.feat[i].q_enabled) { |
| if (s->s.h.segmentation.absolute_vals) |
| qyac = av_clip_uintp2(s->s.h.segmentation.feat[i].q_val, 8); |
| else |
| qyac = av_clip_uintp2(s->s.h.yac_qi + s->s.h.segmentation.feat[i].q_val, 8); |
| } else { |
| qyac = s->s.h.yac_qi; |
| } |
| qydc = av_clip_uintp2(qyac + s->s.h.ydc_qdelta, 8); |
| quvdc = av_clip_uintp2(qyac + s->s.h.uvdc_qdelta, 8); |
| quvac = av_clip_uintp2(qyac + s->s.h.uvac_qdelta, 8); |
| qyac = av_clip_uintp2(qyac, 8); |
| |
| s->s.h.segmentation.feat[i].qmul[0][0] = vp9_dc_qlookup[s->bpp_index][qydc]; |
| s->s.h.segmentation.feat[i].qmul[0][1] = vp9_ac_qlookup[s->bpp_index][qyac]; |
| s->s.h.segmentation.feat[i].qmul[1][0] = vp9_dc_qlookup[s->bpp_index][quvdc]; |
| s->s.h.segmentation.feat[i].qmul[1][1] = vp9_ac_qlookup[s->bpp_index][quvac]; |
| |
| sh = s->s.h.filter.level >= 32; |
| if (s->s.h.segmentation.enabled && s->s.h.segmentation.feat[i].lf_enabled) { |
| if (s->s.h.segmentation.absolute_vals) |
| lflvl = av_clip_uintp2(s->s.h.segmentation.feat[i].lf_val, 6); |
| else |
| lflvl = av_clip_uintp2(s->s.h.filter.level + s->s.h.segmentation.feat[i].lf_val, 6); |
| } else { |
| lflvl = s->s.h.filter.level; |
| } |
| if (s->s.h.lf_delta.enabled) { |
| s->s.h.segmentation.feat[i].lflvl[0][0] = |
| s->s.h.segmentation.feat[i].lflvl[0][1] = |
| av_clip_uintp2(lflvl + (s->s.h.lf_delta.ref[0] << sh), 6); |
| for (j = 1; j < 4; j++) { |
| s->s.h.segmentation.feat[i].lflvl[j][0] = |
| av_clip_uintp2(lflvl + ((s->s.h.lf_delta.ref[j] + |
| s->s.h.lf_delta.mode[0]) * (1 << sh)), 6); |
| s->s.h.segmentation.feat[i].lflvl[j][1] = |
| av_clip_uintp2(lflvl + ((s->s.h.lf_delta.ref[j] + |
| s->s.h.lf_delta.mode[1]) * (1 << sh)), 6); |
| } |
| } else { |
| memset(s->s.h.segmentation.feat[i].lflvl, lflvl, |
| sizeof(s->s.h.segmentation.feat[i].lflvl)); |
| } |
| } |
| |
| /* tiling info */ |
| if ((res = update_size(ctx, w, h)) < 0) { |
| av_log(ctx, AV_LOG_ERROR, "Failed to initialize decoder for %dx%d @ %d\n", |
| w, h, s->pix_fmt); |
| return res; |
| } |
| for (s->s.h.tiling.log2_tile_cols = 0; |
| s->sb_cols > (64 << s->s.h.tiling.log2_tile_cols); |
| s->s.h.tiling.log2_tile_cols++) ; |
| for (max = 0; (s->sb_cols >> max) >= 4; max++) ; |
| max = FFMAX(0, max - 1); |
| while (max > s->s.h.tiling.log2_tile_cols) { |
| if (get_bits1(&s->gb)) |
| s->s.h.tiling.log2_tile_cols++; |
| else |
| break; |
| } |
| s->s.h.tiling.log2_tile_rows = decode012(&s->gb); |
| s->s.h.tiling.tile_rows = 1 << s->s.h.tiling.log2_tile_rows; |
| if (s->s.h.tiling.tile_cols != (1 << s->s.h.tiling.log2_tile_cols)) { |
| s->s.h.tiling.tile_cols = 1 << s->s.h.tiling.log2_tile_cols; |
| s->c_b = av_fast_realloc(s->c_b, &s->c_b_size, |
| sizeof(VP56RangeCoder) * s->s.h.tiling.tile_cols); |
| if (!s->c_b) { |
| av_log(ctx, AV_LOG_ERROR, "Ran out of memory during range coder init\n"); |
| return AVERROR(ENOMEM); |
| } |
| } |
| |
| /* check reference frames */ |
| if (!s->s.h.keyframe && !s->s.h.intraonly) { |
| for (i = 0; i < 3; i++) { |
| AVFrame *ref = s->s.refs[s->s.h.refidx[i]].f; |
| int refw = ref->width, refh = ref->height; |
| |
| if (ref->format != ctx->pix_fmt) { |
| av_log(ctx, AV_LOG_ERROR, |
| "Ref pixfmt (%s) did not match current frame (%s)", |
| av_get_pix_fmt_name(ref->format), |
| av_get_pix_fmt_name(ctx->pix_fmt)); |
| return AVERROR_INVALIDDATA; |
| } else if (refw == w && refh == h) { |
| s->mvscale[i][0] = s->mvscale[i][1] = 0; |
| } else { |
| if (w * 2 < refw || h * 2 < refh || w > 16 * refw || h > 16 * refh) { |
| av_log(ctx, AV_LOG_ERROR, |
| "Invalid ref frame dimensions %dx%d for frame size %dx%d\n", |
| refw, refh, w, h); |
| return AVERROR_INVALIDDATA; |
| } |
| s->mvscale[i][0] = (refw << 14) / w; |
| s->mvscale[i][1] = (refh << 14) / h; |
| s->mvstep[i][0] = 16 * s->mvscale[i][0] >> 14; |
| s->mvstep[i][1] = 16 * s->mvscale[i][1] >> 14; |
| } |
| } |
| } |
| |
| if (s->s.h.keyframe || s->s.h.errorres || (s->s.h.intraonly && s->s.h.resetctx == 3)) { |
| s->prob_ctx[0].p = s->prob_ctx[1].p = s->prob_ctx[2].p = |
| s->prob_ctx[3].p = vp9_default_probs; |
| memcpy(s->prob_ctx[0].coef, vp9_default_coef_probs, |
| sizeof(vp9_default_coef_probs)); |
| memcpy(s->prob_ctx[1].coef, vp9_default_coef_probs, |
| sizeof(vp9_default_coef_probs)); |
| memcpy(s->prob_ctx[2].coef, vp9_default_coef_probs, |
| sizeof(vp9_default_coef_probs)); |
| memcpy(s->prob_ctx[3].coef, vp9_default_coef_probs, |
| sizeof(vp9_default_coef_probs)); |
| } else if (s->s.h.intraonly && s->s.h.resetctx == 2) { |
| s->prob_ctx[c].p = vp9_default_probs; |
| memcpy(s->prob_ctx[c].coef, vp9_default_coef_probs, |
| sizeof(vp9_default_coef_probs)); |
| } |
| |
| // next 16 bits is size of the rest of the header (arith-coded) |
| s->s.h.compressed_header_size = size2 = get_bits(&s->gb, 16); |
| s->s.h.uncompressed_header_size = (get_bits_count(&s->gb) + 7) / 8; |
| |
| data2 = align_get_bits(&s->gb); |
| if (size2 > size - (data2 - data)) { |
| av_log(ctx, AV_LOG_ERROR, "Invalid compressed header size\n"); |
| return AVERROR_INVALIDDATA; |
| } |
| ff_vp56_init_range_decoder(&s->c, data2, size2); |
| if (vp56_rac_get_prob_branchy(&s->c, 128)) { // marker bit |
| av_log(ctx, AV_LOG_ERROR, "Marker bit was set\n"); |
| return AVERROR_INVALIDDATA; |
| } |
| |
| if (s->s.h.keyframe || s->s.h.intraonly) { |
| memset(s->counts.coef, 0, sizeof(s->counts.coef)); |
| memset(s->counts.eob, 0, sizeof(s->counts.eob)); |
| } else { |
| memset(&s->counts, 0, sizeof(s->counts)); |
| } |
| // FIXME is it faster to not copy here, but do it down in the fw updates |
| // as explicit copies if the fw update is missing (and skip the copy upon |
| // fw update)? |
| s->prob.p = s->prob_ctx[c].p; |
| |
| // txfm updates |
| if (s->s.h.lossless) { |
| s->s.h.txfmmode = TX_4X4; |
| } else { |
| s->s.h.txfmmode = vp8_rac_get_uint(&s->c, 2); |
| if (s->s.h.txfmmode == 3) |
| s->s.h.txfmmode += vp8_rac_get(&s->c); |
| |
| if (s->s.h.txfmmode == TX_SWITCHABLE) { |
| for (i = 0; i < 2; i++) |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.tx8p[i] = update_prob(&s->c, s->prob.p.tx8p[i]); |
| for (i = 0; i < 2; i++) |
| for (j = 0; j < 2; j++) |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.tx16p[i][j] = |
| update_prob(&s->c, s->prob.p.tx16p[i][j]); |
| for (i = 0; i < 2; i++) |
| for (j = 0; j < 3; j++) |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.tx32p[i][j] = |
| update_prob(&s->c, s->prob.p.tx32p[i][j]); |
| } |
| } |
| |
| // coef updates |
| for (i = 0; i < 4; i++) { |
| uint8_t (*ref)[2][6][6][3] = s->prob_ctx[c].coef[i]; |
| if (vp8_rac_get(&s->c)) { |
| for (j = 0; j < 2; j++) |
| for (k = 0; k < 2; k++) |
| for (l = 0; l < 6; l++) |
| for (m = 0; m < 6; m++) { |
| uint8_t *p = s->prob.coef[i][j][k][l][m]; |
| uint8_t *r = ref[j][k][l][m]; |
| if (m >= 3 && l == 0) // dc only has 3 pt |
| break; |
| for (n = 0; n < 3; n++) { |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) { |
| p[n] = update_prob(&s->c, r[n]); |
| } else { |
| p[n] = r[n]; |
| } |
| } |
| p[3] = 0; |
| } |
| } else { |
| for (j = 0; j < 2; j++) |
| for (k = 0; k < 2; k++) |
| for (l = 0; l < 6; l++) |
| for (m = 0; m < 6; m++) { |
| uint8_t *p = s->prob.coef[i][j][k][l][m]; |
| uint8_t *r = ref[j][k][l][m]; |
| if (m > 3 && l == 0) // dc only has 3 pt |
| break; |
| memcpy(p, r, 3); |
| p[3] = 0; |
| } |
| } |
| if (s->s.h.txfmmode == i) |
| break; |
| } |
| |
| // mode updates |
| for (i = 0; i < 3; i++) |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.skip[i] = update_prob(&s->c, s->prob.p.skip[i]); |
| if (!s->s.h.keyframe && !s->s.h.intraonly) { |
| for (i = 0; i < 7; i++) |
| for (j = 0; j < 3; j++) |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.mv_mode[i][j] = |
| update_prob(&s->c, s->prob.p.mv_mode[i][j]); |
| |
| if (s->s.h.filtermode == FILTER_SWITCHABLE) |
| for (i = 0; i < 4; i++) |
| for (j = 0; j < 2; j++) |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.filter[i][j] = |
| update_prob(&s->c, s->prob.p.filter[i][j]); |
| |
| for (i = 0; i < 4; i++) |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.intra[i] = update_prob(&s->c, s->prob.p.intra[i]); |
| |
| if (s->s.h.allowcompinter) { |
| s->s.h.comppredmode = vp8_rac_get(&s->c); |
| if (s->s.h.comppredmode) |
| s->s.h.comppredmode += vp8_rac_get(&s->c); |
| if (s->s.h.comppredmode == PRED_SWITCHABLE) |
| for (i = 0; i < 5; i++) |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.comp[i] = |
| update_prob(&s->c, s->prob.p.comp[i]); |
| } else { |
| s->s.h.comppredmode = PRED_SINGLEREF; |
| } |
| |
| if (s->s.h.comppredmode != PRED_COMPREF) { |
| for (i = 0; i < 5; i++) { |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.single_ref[i][0] = |
| update_prob(&s->c, s->prob.p.single_ref[i][0]); |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.single_ref[i][1] = |
| update_prob(&s->c, s->prob.p.single_ref[i][1]); |
| } |
| } |
| |
| if (s->s.h.comppredmode != PRED_SINGLEREF) { |
| for (i = 0; i < 5; i++) |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.comp_ref[i] = |
| update_prob(&s->c, s->prob.p.comp_ref[i]); |
| } |
| |
| for (i = 0; i < 4; i++) |
| for (j = 0; j < 9; j++) |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.y_mode[i][j] = |
| update_prob(&s->c, s->prob.p.y_mode[i][j]); |
| |
| for (i = 0; i < 4; i++) |
| for (j = 0; j < 4; j++) |
| for (k = 0; k < 3; k++) |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.partition[3 - i][j][k] = |
| update_prob(&s->c, s->prob.p.partition[3 - i][j][k]); |
| |
| // mv fields don't use the update_prob subexp model for some reason |
| for (i = 0; i < 3; i++) |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.mv_joint[i] = (vp8_rac_get_uint(&s->c, 7) << 1) | 1; |
| |
| for (i = 0; i < 2; i++) { |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.mv_comp[i].sign = (vp8_rac_get_uint(&s->c, 7) << 1) | 1; |
| |
| for (j = 0; j < 10; j++) |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.mv_comp[i].classes[j] = |
| (vp8_rac_get_uint(&s->c, 7) << 1) | 1; |
| |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.mv_comp[i].class0 = (vp8_rac_get_uint(&s->c, 7) << 1) | 1; |
| |
| for (j = 0; j < 10; j++) |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.mv_comp[i].bits[j] = |
| (vp8_rac_get_uint(&s->c, 7) << 1) | 1; |
| } |
| |
| for (i = 0; i < 2; i++) { |
| for (j = 0; j < 2; j++) |
| for (k = 0; k < 3; k++) |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.mv_comp[i].class0_fp[j][k] = |
| (vp8_rac_get_uint(&s->c, 7) << 1) | 1; |
| |
| for (j = 0; j < 3; j++) |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.mv_comp[i].fp[j] = |
| (vp8_rac_get_uint(&s->c, 7) << 1) | 1; |
| } |
| |
| if (s->s.h.highprecisionmvs) { |
| for (i = 0; i < 2; i++) { |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.mv_comp[i].class0_hp = |
| (vp8_rac_get_uint(&s->c, 7) << 1) | 1; |
| |
| if (vp56_rac_get_prob_branchy(&s->c, 252)) |
| s->prob.p.mv_comp[i].hp = |
| (vp8_rac_get_uint(&s->c, 7) << 1) | 1; |
| } |
| } |
| } |
| |
| return (data2 - data) + size2; |
| } |
| |
| static av_always_inline void clamp_mv(VP56mv *dst, const VP56mv *src, |
| VP9Context *s) |
| { |
| dst->x = av_clip(src->x, s->min_mv.x, s->max_mv.x); |
| dst->y = av_clip(src->y, s->min_mv.y, s->max_mv.y); |
| } |
| |
| static void find_ref_mvs(VP9Context *s, |
| VP56mv *pmv, int ref, int z, int idx, int sb) |
| { |
| static const int8_t mv_ref_blk_off[N_BS_SIZES][8][2] = { |
| [BS_64x64] = {{ 3, -1 }, { -1, 3 }, { 4, -1 }, { -1, 4 }, |
| { -1, -1 }, { 0, -1 }, { -1, 0 }, { 6, -1 }}, |
| [BS_64x32] = {{ 0, -1 }, { -1, 0 }, { 4, -1 }, { -1, 2 }, |
| { -1, -1 }, { 0, -3 }, { -3, 0 }, { 2, -1 }}, |
| [BS_32x64] = {{ -1, 0 }, { 0, -1 }, { -1, 4 }, { 2, -1 }, |
| { -1, -1 }, { -3, 0 }, { 0, -3 }, { -1, 2 }}, |
| [BS_32x32] = {{ 1, -1 }, { -1, 1 }, { 2, -1 }, { -1, 2 }, |
| { -1, -1 }, { 0, -3 }, { -3, 0 }, { -3, -3 }}, |
| [BS_32x16] = {{ 0, -1 }, { -1, 0 }, { 2, -1 }, { -1, -1 }, |
| { -1, 1 }, { 0, -3 }, { -3, 0 }, { -3, -3 }}, |
| [BS_16x32] = {{ -1, 0 }, { 0, -1 }, { -1, 2 }, { -1, -1 }, |
| { 1, -1 }, { -3, 0 }, { 0, -3 }, { -3, -3 }}, |
| [BS_16x16] = {{ 0, -1 }, { -1, 0 }, { 1, -1 }, { -1, 1 }, |
| { -1, -1 }, { 0, -3 }, { -3, 0 }, { -3, -3 }}, |
| [BS_16x8] = {{ 0, -1 }, { -1, 0 }, { 1, -1 }, { -1, -1 }, |
| { 0, -2 }, { -2, 0 }, { -2, -1 }, { -1, -2 }}, |
| [BS_8x16] = {{ -1, 0 }, { 0, -1 }, { -1, 1 }, { -1, -1 }, |
| { -2, 0 }, { 0, -2 }, { -1, -2 }, { -2, -1 }}, |
| [BS_8x8] = {{ 0, -1 }, { -1, 0 }, { -1, -1 }, { 0, -2 }, |
| { -2, 0 }, { -1, -2 }, { -2, -1 }, { -2, -2 }}, |
| [BS_8x4] = {{ 0, -1 }, { -1, 0 }, { -1, -1 }, { 0, -2 }, |
| { -2, 0 }, { -1, -2 }, { -2, -1 }, { -2, -2 }}, |
| [BS_4x8] = {{ 0, -1 }, { -1, 0 }, { -1, -1 }, { 0, -2 }, |
| { -2, 0 }, { -1, -2 }, { -2, -1 }, { -2, -2 }}, |
| [BS_4x4] = {{ 0, -1 }, { -1, 0 }, { -1, -1 }, { 0, -2 }, |
| { -2, 0 }, { -1, -2 }, { -2, -1 }, { -2, -2 }}, |
| }; |
| VP9Block *b = s->b; |
| int row = s->row, col = s->col, row7 = s->row7; |
| const int8_t (*p)[2] = mv_ref_blk_off[b->bs]; |
| #define INVALID_MV 0x80008000U |
| uint32_t mem = INVALID_MV, mem_sub8x8 = INVALID_MV; |
| int i; |
| |
| #define RETURN_DIRECT_MV(mv) \ |
| do { \ |
| uint32_t m = AV_RN32A(&mv); \ |
| if (!idx) { \ |
| AV_WN32A(pmv, m); \ |
| return; \ |
| } else if (mem == INVALID_MV) { \ |
| mem = m; \ |
| } else if (m != mem) { \ |
| AV_WN32A(pmv, m); \ |
| return; \ |
| } \ |
| } while (0) |
| |
| if (sb >= 0) { |
| if (sb == 2 || sb == 1) { |
| RETURN_DIRECT_MV(b->mv[0][z]); |
| } else if (sb == 3) { |
| RETURN_DIRECT_MV(b->mv[2][z]); |
| RETURN_DIRECT_MV(b->mv[1][z]); |
| RETURN_DIRECT_MV(b->mv[0][z]); |
| } |
| |
| #define RETURN_MV(mv) \ |
| do { \ |
| if (sb > 0) { \ |
| VP56mv tmp; \ |
| uint32_t m; \ |
| av_assert2(idx == 1); \ |
| av_assert2(mem != INVALID_MV); \ |
| if (mem_sub8x8 == INVALID_MV) { \ |
| clamp_mv(&tmp, &mv, s); \ |
| m = AV_RN32A(&tmp); \ |
| if (m != mem) { \ |
| AV_WN32A(pmv, m); \ |
| return; \ |
| } \ |
| mem_sub8x8 = AV_RN32A(&mv); \ |
| } else if (mem_sub8x8 != AV_RN32A(&mv)) { \ |
| clamp_mv(&tmp, &mv, s); \ |
| m = AV_RN32A(&tmp); \ |
| if (m != mem) { \ |
| AV_WN32A(pmv, m); \ |
| } else { \ |
| /* BUG I'm pretty sure this isn't the intention */ \ |
| AV_WN32A(pmv, 0); \ |
| } \ |
| return; \ |
| } \ |
| } else { \ |
| uint32_t m = AV_RN32A(&mv); \ |
| if (!idx) { \ |
| clamp_mv(pmv, &mv, s); \ |
| return; \ |
| } else if (mem == INVALID_MV) { \ |
| mem = m; \ |
| } else if (m != mem) { \ |
| clamp_mv(pmv, &mv, s); \ |
| return; \ |
| } \ |
| } \ |
| } while (0) |
| |
| if (row > 0) { |
| struct VP9mvrefPair *mv = &s->s.frames[CUR_FRAME].mv[(row - 1) * s->sb_cols * 8 + col]; |
| if (mv->ref[0] == ref) { |
| RETURN_MV(s->above_mv_ctx[2 * col + (sb & 1)][0]); |
| } else if (mv->ref[1] == ref) { |
| RETURN_MV(s->above_mv_ctx[2 * col + (sb & 1)][1]); |
| } |
| } |
| if (col > s->tile_col_start) { |
| struct VP9mvrefPair *mv = &s->s.frames[CUR_FRAME].mv[row * s->sb_cols * 8 + col - 1]; |
| if (mv->ref[0] == ref) { |
| RETURN_MV(s->left_mv_ctx[2 * row7 + (sb >> 1)][0]); |
| } else if (mv->ref[1] == ref) { |
| RETURN_MV(s->left_mv_ctx[2 * row7 + (sb >> 1)][1]); |
| } |
| } |
| i = 2; |
| } else { |
| i = 0; |
| } |
| |
| // previously coded MVs in this neighbourhood, using same reference frame |
| for (; i < 8; i++) { |
| int c = p[i][0] + col, r = p[i][1] + row; |
| |
| if (c >= s->tile_col_start && c < s->cols && r >= 0 && r < s->rows) { |
| struct VP9mvrefPair *mv = &s->s.frames[CUR_FRAME].mv[r * s->sb_cols * 8 + c]; |
| |
| if (mv->ref[0] == ref) { |
| RETURN_MV(mv->mv[0]); |
| } else if (mv->ref[1] == ref) { |
| RETURN_MV(mv->mv[1]); |
| } |
| } |
| } |
| |
| // MV at this position in previous frame, using same reference frame |
| if (s->s.h.use_last_frame_mvs) { |
| struct VP9mvrefPair *mv = &s->s.frames[REF_FRAME_MVPAIR].mv[row * s->sb_cols * 8 + col]; |
| |
| if (!s->s.frames[REF_FRAME_MVPAIR].uses_2pass) |
| ff_thread_await_progress(&s->s.frames[REF_FRAME_MVPAIR].tf, row >> 3, 0); |
| if (mv->ref[0] == ref) { |
| RETURN_MV(mv->mv[0]); |
| } else if (mv->ref[1] == ref) { |
| RETURN_MV(mv->mv[1]); |
| } |
| } |
| |
| #define RETURN_SCALE_MV(mv, scale) \ |
| do { \ |
| if (scale) { \ |
| VP56mv mv_temp = { -mv.x, -mv.y }; \ |
| RETURN_MV(mv_temp); \ |
| } else { \ |
| RETURN_MV(mv); \ |
| } \ |
| } while (0) |
| |
| // previously coded MVs in this neighbourhood, using different reference frame |
| for (i = 0; i < 8; i++) { |
| int c = p[i][0] + col, r = p[i][1] + row; |
| |
| if (c >= s->tile_col_start && c < s->cols && r >= 0 && r < s->rows) { |
| struct VP9mvrefPair *mv = &s->s.frames[CUR_FRAME].mv[r * s->sb_cols * 8 + c]; |
| |
| if (mv->ref[0] != ref && mv->ref[0] >= 0) { |
| RETURN_SCALE_MV(mv->mv[0], s->s.h.signbias[mv->ref[0]] != s->s.h.signbias[ref]); |
| } |
| if (mv->ref[1] != ref && mv->ref[1] >= 0 && |
| // BUG - libvpx has this condition regardless of whether |
| // we used the first ref MV and pre-scaling |
| AV_RN32A(&mv->mv[0]) != AV_RN32A(&mv->mv[1])) { |
| RETURN_SCALE_MV(mv->mv[1], s->s.h.signbias[mv->ref[1]] != s->s.h.signbias[ref]); |
| } |
| } |
| } |
| |
| // MV at this position in previous frame, using different reference frame |
| if (s->s.h.use_last_frame_mvs) { |
| struct VP9mvrefPair *mv = &s->s.frames[REF_FRAME_MVPAIR].mv[row * s->sb_cols * 8 + col]; |
| |
| // no need to await_progress, because we already did that above |
| if (mv->ref[0] != ref && mv->ref[0] >= 0) { |
| RETURN_SCALE_MV(mv->mv[0], s->s.h.signbias[mv->ref[0]] != s->s.h.signbias[ref]); |
| } |
| if (mv->ref[1] != ref && mv->ref[1] >= 0 && |
| // BUG - libvpx has this condition regardless of whether |
| // we used the first ref MV and pre-scaling |
| AV_RN32A(&mv->mv[0]) != AV_RN32A(&mv->mv[1])) { |
| RETURN_SCALE_MV(mv->mv[1], s->s.h.signbias[mv->ref[1]] != s->s.h.signbias[ref]); |
| } |
| } |
| |
| AV_ZERO32(pmv); |
| clamp_mv(pmv, pmv, s); |
| #undef INVALID_MV |
| #undef RETURN_MV |
| #undef RETURN_SCALE_MV |
| } |
| |
| static av_always_inline int read_mv_component(VP9Context *s, int idx, int hp) |
| { |
| int bit, sign = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].sign); |
| int n, c = vp8_rac_get_tree(&s->c, vp9_mv_class_tree, |
| s->prob.p.mv_comp[idx].classes); |
| |
| s->counts.mv_comp[idx].sign[sign]++; |
| s->counts.mv_comp[idx].classes[c]++; |
| if (c) { |
| int m; |
| |
| for (n = 0, m = 0; m < c; m++) { |
| bit = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].bits[m]); |
| n |= bit << m; |
| s->counts.mv_comp[idx].bits[m][bit]++; |
| } |
| n <<= 3; |
| bit = vp8_rac_get_tree(&s->c, vp9_mv_fp_tree, s->prob.p.mv_comp[idx].fp); |
| n |= bit << 1; |
| s->counts.mv_comp[idx].fp[bit]++; |
| if (hp) { |
| bit = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].hp); |
| s->counts.mv_comp[idx].hp[bit]++; |
| n |= bit; |
| } else { |
| n |= 1; |
| // bug in libvpx - we count for bw entropy purposes even if the |
| // bit wasn't coded |
| s->counts.mv_comp[idx].hp[1]++; |
| } |
| n += 8 << c; |
| } else { |
| n = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].class0); |
| s->counts.mv_comp[idx].class0[n]++; |
| bit = vp8_rac_get_tree(&s->c, vp9_mv_fp_tree, |
| s->prob.p.mv_comp[idx].class0_fp[n]); |
| s->counts.mv_comp[idx].class0_fp[n][bit]++; |
| n = (n << 3) | (bit << 1); |
| if (hp) { |
| bit = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].class0_hp); |
| s->counts.mv_comp[idx].class0_hp[bit]++; |
| n |= bit; |
| } else { |
| n |= 1; |
| // bug in libvpx - we count for bw entropy purposes even if the |
| // bit wasn't coded |
| s->counts.mv_comp[idx].class0_hp[1]++; |
| } |
| } |
| |
| return sign ? -(n + 1) : (n + 1); |
| } |
| |
| static void fill_mv(VP9Context *s, |
| VP56mv *mv, int mode, int sb) |
| { |
| VP9Block *b = s->b; |
| |
| if (mode == ZEROMV) { |
| AV_ZERO64(mv); |
| } else { |
| int hp; |
| |
| // FIXME cache this value and reuse for other subblocks |
| find_ref_mvs(s, &mv[0], b->ref[0], 0, mode == NEARMV, |
| mode == NEWMV ? -1 : sb); |
| // FIXME maybe move this code into find_ref_mvs() |
| if ((mode == NEWMV || sb == -1) && |
| !(hp = s->s.h.highprecisionmvs && abs(mv[0].x) < 64 && abs(mv[0].y) < 64)) { |
| if (mv[0].y & 1) { |
| if (mv[0].y < 0) |
| mv[0].y++; |
| else |
| mv[0].y--; |
| } |
| if (mv[0].x & 1) { |
| if (mv[0].x < 0) |
| mv[0].x++; |
| else |
| mv[0].x--; |
| } |
| } |
| if (mode == NEWMV) { |
| enum MVJoint j = vp8_rac_get_tree(&s->c, vp9_mv_joint_tree, |
| s->prob.p.mv_joint); |
| |
| s->counts.mv_joint[j]++; |
| if (j >= MV_JOINT_V) |
| mv[0].y += read_mv_component(s, 0, hp); |
| if (j & 1) |
| mv[0].x += read_mv_component(s, 1, hp); |
| } |
| |
| if (b->comp) { |
| // FIXME cache this value and reuse for other subblocks |
| find_ref_mvs(s, &mv[1], b->ref[1], 1, mode == NEARMV, |
| mode == NEWMV ? -1 : sb); |
| if ((mode == NEWMV || sb == -1) && |
| !(hp = s->s.h.highprecisionmvs && abs(mv[1].x) < 64 && abs(mv[1].y) < 64)) { |
| if (mv[1].y & 1) { |
| if (mv[1].y < 0) |
| mv[1].y++; |
| else |
| mv[1].y--; |
| } |
| if (mv[1].x & 1) { |
| if (mv[1].x < 0) |
| mv[1].x++; |
| else |
| mv[1].x--; |
| } |
| } |
| if (mode == NEWMV) { |
| enum MVJoint j = vp8_rac_get_tree(&s->c, vp9_mv_joint_tree, |
| s->prob.p.mv_joint); |
| |
| s->counts.mv_joint[j]++; |
| if (j >= MV_JOINT_V) |
| mv[1].y += read_mv_component(s, 0, hp); |
| if (j & 1) |
| mv[1].x += read_mv_component(s, 1, hp); |
| } |
| } |
| } |
| } |
| |
| static av_always_inline void setctx_2d(uint8_t *ptr, int w, int h, |
| ptrdiff_t stride, int v) |
| { |
| switch (w) { |
| case 1: |
| do { |
| *ptr = v; |
| ptr += stride; |
| } while (--h); |
| break; |
| case 2: { |
| int v16 = v * 0x0101; |
| do { |
| AV_WN16A(ptr, v16); |
| ptr += stride; |
| } while (--h); |
| break; |
| } |
| case 4: { |
| uint32_t v32 = v * 0x01010101; |
| do { |
| AV_WN32A(ptr, v32); |
| ptr += stride; |
| } while (--h); |
| break; |
| } |
| case 8: { |
| #if HAVE_FAST_64BIT |
| uint64_t v64 = v * 0x0101010101010101ULL; |
| do { |
| AV_WN64A(ptr, v64); |
| ptr += stride; |
| } while (--h); |
| #else |
| uint32_t v32 = v * 0x01010101; |
| do { |
| AV_WN32A(ptr, v32); |
| AV_WN32A(ptr + 4, v32); |
| ptr += stride; |
| } while (--h); |
| #endif |
| break; |
| } |
| } |
| } |
| |
| static void decode_mode(AVCodecContext *ctx) |
| { |
| static const uint8_t left_ctx[N_BS_SIZES] = { |
| 0x0, 0x8, 0x0, 0x8, 0xc, 0x8, 0xc, 0xe, 0xc, 0xe, 0xf, 0xe, 0xf |
| }; |
| static const uint8_t above_ctx[N_BS_SIZES] = { |
| 0x0, 0x0, 0x8, 0x8, 0x8, 0xc, 0xc, 0xc, 0xe, 0xe, 0xe, 0xf, 0xf |
| }; |
| static const uint8_t max_tx_for_bl_bp[N_BS_SIZES] = { |
| TX_32X32, TX_32X32, TX_32X32, TX_32X32, TX_16X16, TX_16X16, |
| TX_16X16, TX_8X8, TX_8X8, TX_8X8, TX_4X4, TX_4X4, TX_4X4 |
| }; |
| VP9Context *s = ctx->priv_data; |
| VP9Block *b = s->b; |
| int row = s->row, col = s->col, row7 = s->row7; |
| enum TxfmMode max_tx = max_tx_for_bl_bp[b->bs]; |
| int bw4 = bwh_tab[1][b->bs][0], w4 = FFMIN(s->cols - col, bw4); |
| int bh4 = bwh_tab[1][b->bs][1], h4 = FFMIN(s->rows - row, bh4), y; |
| int have_a = row > 0, have_l = col > s->tile_col_start; |
| int vref, filter_id; |
| |
| if (!s->s.h.segmentation.enabled) { |
| b->seg_id = 0; |
| } else if (s->s.h.keyframe || s->s.h.intraonly) { |
| b->seg_id = !s->s.h.segmentation.update_map ? 0 : |
| vp8_rac_get_tree(&s->c, vp9_segmentation_tree, s->s.h.segmentation.prob); |
| } else if (!s->s.h.segmentation.update_map || |
| (s->s.h.segmentation.temporal && |
| vp56_rac_get_prob_branchy(&s->c, |
| s->s.h.segmentation.pred_prob[s->above_segpred_ctx[col] + |
| s->left_segpred_ctx[row7]]))) { |
| if (!s->s.h.errorres && s->s.frames[REF_FRAME_SEGMAP].segmentation_map) { |
| int pred = 8, x; |
| uint8_t *refsegmap = s->s.frames[REF_FRAME_SEGMAP].segmentation_map; |
| |
| if (!s->s.frames[REF_FRAME_SEGMAP].uses_2pass) |
| ff_thread_await_progress(&s->s.frames[REF_FRAME_SEGMAP].tf, row >> 3, 0); |
| for (y = 0; y < h4; y++) { |
| int idx_base = (y + row) * 8 * s->sb_cols + col; |
| for (x = 0; x < w4; x++) |
| pred = FFMIN(pred, refsegmap[idx_base + x]); |
| } |
| av_assert1(pred < 8); |
| b->seg_id = pred; |
| } else { |
| b->seg_id = 0; |
| } |
| |
| memset(&s->above_segpred_ctx[col], 1, w4); |
| memset(&s->left_segpred_ctx[row7], 1, h4); |
| } else { |
| b->seg_id = vp8_rac_get_tree(&s->c, vp9_segmentation_tree, |
| s->s.h.segmentation.prob); |
| |
| memset(&s->above_segpred_ctx[col], 0, w4); |
| memset(&s->left_segpred_ctx[row7], 0, h4); |
| } |
| if (s->s.h.segmentation.enabled && |
| (s->s.h.segmentation.update_map || s->s.h.keyframe || s->s.h.intraonly)) { |
| setctx_2d(&s->s.frames[CUR_FRAME].segmentation_map[row * 8 * s->sb_cols + col], |
| bw4, bh4, 8 * s->sb_cols, b->seg_id); |
| } |
| |
| b->skip = s->s.h.segmentation.enabled && |
| s->s.h.segmentation.feat[b->seg_id].skip_enabled; |
| if (!b->skip) { |
| int c = s->left_skip_ctx[row7] + s->above_skip_ctx[col]; |
| b->skip = vp56_rac_get_prob(&s->c, s->prob.p.skip[c]); |
| s->counts.skip[c][b->skip]++; |
| } |
| |
| if (s->s.h.keyframe || s->s.h.intraonly) { |
| b->intra = 1; |
| } else if (s->s.h.segmentation.enabled && s->s.h.segmentation.feat[b->seg_id].ref_enabled) { |
| b->intra = !s->s.h.segmentation.feat[b->seg_id].ref_val; |
| } else { |
| int c, bit; |
| |
| if (have_a && have_l) { |
| c = s->above_intra_ctx[col] + s->left_intra_ctx[row7]; |
| c += (c == 2); |
| } else { |
| c = have_a ? 2 * s->above_intra_ctx[col] : |
| have_l ? 2 * s->left_intra_ctx[row7] : 0; |
| } |
| bit = vp56_rac_get_prob(&s->c, s->prob.p.intra[c]); |
| s->counts.intra[c][bit]++; |
| b->intra = !bit; |
| } |
| |
| if ((b->intra || !b->skip) && s->s.h.txfmmode == TX_SWITCHABLE) { |
| int c; |
| if (have_a) { |
| if (have_l) { |
| c = (s->above_skip_ctx[col] ? max_tx : |
| s->above_txfm_ctx[col]) + |
| (s->left_skip_ctx[row7] ? max_tx : |
| s->left_txfm_ctx[row7]) > max_tx; |
| } else { |
| c = s->above_skip_ctx[col] ? 1 : |
| (s->above_txfm_ctx[col] * 2 > max_tx); |
| } |
| } else if (have_l) { |
| c = s->left_skip_ctx[row7] ? 1 : |
| (s->left_txfm_ctx[row7] * 2 > max_tx); |
| } else { |
| c = 1; |
| } |
| switch (max_tx) { |
| case TX_32X32: |
| b->tx = vp56_rac_get_prob(&s->c, s->prob.p.tx32p[c][0]); |
| if (b->tx) { |
| b->tx += vp56_rac_get_prob(&s->c, s->prob.p.tx32p[c][1]); |
| if (b->tx == 2) |
| b->tx += vp56_rac_get_prob(&s->c, s->prob.p.tx32p[c][2]); |
| } |
| s->counts.tx32p[c][b->tx]++; |
| break; |
| case TX_16X16: |
| b->tx = vp56_rac_get_prob(&s->c, s->prob.p.tx16p[c][0]); |
| if (b->tx) |
| b->tx += vp56_rac_get_prob(&s->c, s->prob.p.tx16p[c][1]); |
| s->counts.tx16p[c][b->tx]++; |
| break; |
| case TX_8X8: |
| b->tx = vp56_rac_get_prob(&s->c, s->prob.p.tx8p[c]); |
| s->counts.tx8p[c][b->tx]++; |
| break; |
| case TX_4X4: |
| b->tx = TX_4X4; |
| break; |
| } |
| } else { |
| b->tx = FFMIN(max_tx, s->s.h.txfmmode); |
| } |
| |
| if (s->s.h.keyframe || s->s.h.intraonly) { |
| uint8_t *a = &s->above_mode_ctx[col * 2]; |
| uint8_t *l = &s->left_mode_ctx[(row7) << 1]; |
| |
| b->comp = 0; |
| if (b->bs > BS_8x8) { |
| // FIXME the memory storage intermediates here aren't really |
| // necessary, they're just there to make the code slightly |
| // simpler for now |
| b->mode[0] = a[0] = vp8_rac_get_tree(&s->c, vp9_intramode_tree, |
| vp9_default_kf_ymode_probs[a[0]][l[0]]); |
| if (b->bs != BS_8x4) { |
| b->mode[1] = vp8_rac_get_tree(&s->c, vp9_intramode_tree, |
| vp9_default_kf_ymode_probs[a[1]][b->mode[0]]); |
| l[0] = a[1] = b->mode[1]; |
| } else { |
| l[0] = a[1] = b->mode[1] = b->mode[0]; |
| } |
| if (b->bs != BS_4x8) { |
| b->mode[2] = a[0] = vp8_rac_get_tree(&s->c, vp9_intramode_tree, |
| vp9_default_kf_ymode_probs[a[0]][l[1]]); |
| if (b->bs != BS_8x4) { |
| b->mode[3] = vp8_rac_get_tree(&s->c, vp9_intramode_tree, |
| vp9_default_kf_ymode_probs[a[1]][b->mode[2]]); |
| l[1] = a[1] = b->mode[3]; |
| } else { |
| l[1] = a[1] = b->mode[3] = b->mode[2]; |
| } |
| } else { |
| b->mode[2] = b->mode[0]; |
| l[1] = a[1] = b->mode[3] = b->mode[1]; |
| } |
| } else { |
| b->mode[0] = vp8_rac_get_tree(&s->c, vp9_intramode_tree, |
| vp9_default_kf_ymode_probs[*a][*l]); |
| b->mode[3] = b->mode[2] = b->mode[1] = b->mode[0]; |
| // FIXME this can probably be optimized |
| memset(a, b->mode[0], bwh_tab[0][b->bs][0]); |
| memset(l, b->mode[0], bwh_tab[0][b->bs][1]); |
| } |
| b->uvmode = vp8_rac_get_tree(&s->c, vp9_intramode_tree, |
| vp9_default_kf_uvmode_probs[b->mode[3]]); |
| } else if (b->intra) { |
| b->comp = 0; |
| if (b->bs > BS_8x8) { |
| b->mode[0] = vp8_rac_get_tree(&s->c, vp9_intramode_tree, |
| s->prob.p.y_mode[0]); |
| s->counts.y_mode[0][b->mode[0]]++; |
| if (b->bs != BS_8x4) { |
| b->mode[1] = vp8_rac_get_tree(&s->c, vp9_intramode_tree, |
| s->prob.p.y_mode[0]); |
| s->counts.y_mode[0][b->mode[1]]++; |
| } else { |
| b->mode[1] = b->mode[0]; |
| } |
| if (b->bs != BS_4x8) { |
| b->mode[2] = vp8_rac_get_tree(&s->c, vp9_intramode_tree, |
| s->prob.p.y_mode[0]); |
| s->counts.y_mode[0][b->mode[2]]++; |
| if (b->bs != BS_8x4) { |
| b->mode[3] = vp8_rac_get_tree(&s->c, vp9_intramode_tree, |
| s->prob.p.y_mode[0]); |
| s->counts.y_mode[0][b->mode[3]]++; |
| } else { |
| b->mode[3] = b->mode[2]; |
| } |
| } else { |
| b->mode[2] = b->mode[0]; |
| b->mode[3] = b->mode[1]; |
| } |
| } else { |
| static const uint8_t size_group[10] = { |
| 3, 3, 3, 3, 2, 2, 2, 1, 1, 1 |
| }; |
| int sz = size_group[b->bs]; |
| |
| b->mode[0] = vp8_rac_get_tree(&s->c, vp9_intramode_tree, |
| s->prob.p.y_mode[sz]); |
| b->mode[1] = b->mode[2] = b->mode[3] = b->mode[0]; |
| s->counts.y_mode[sz][b->mode[3]]++; |
| } |
| b->uvmode = vp8_rac_get_tree(&s->c, vp9_intramode_tree, |
| s->prob.p.uv_mode[b->mode[3]]); |
| s->counts.uv_mode[b->mode[3]][b->uvmode]++; |
| } else { |
| static const uint8_t inter_mode_ctx_lut[14][14] = { |
| { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 }, |
| { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 }, |
| { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 }, |
| { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 }, |
| { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 }, |
| { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 }, |
| { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 }, |
| { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 }, |
| { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 }, |
| { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 }, |
| { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 1, 3 }, |
| { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 1, 3 }, |
| { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 0, 3 }, |
| { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 4 }, |
| }; |
| |
| if (s->s.h.segmentation.enabled && s->s.h.segmentation.feat[b->seg_id].ref_enabled) { |
| av_assert2(s->s.h.segmentation.feat[b->seg_id].ref_val != 0); |
| b->comp = 0; |
| b->ref[0] = s->s.h.segmentation.feat[b->seg_id].ref_val - 1; |
| } else { |
| // read comp_pred flag |
| if (s->s.h.comppredmode != PRED_SWITCHABLE) { |
| b->comp = s->s.h.comppredmode == PRED_COMPREF; |
| } else { |
| int c; |
| |
| // FIXME add intra as ref=0xff (or -1) to make these easier? |
| if (have_a) { |
| if (have_l) { |
| if (s->above_comp_ctx[col] && s->left_comp_ctx[row7]) { |
| c = 4; |
| } else if (s->above_comp_ctx[col]) { |
| c = 2 + (s->left_intra_ctx[row7] || |
| s->left_ref_ctx[row7] == s->s.h.fixcompref); |
| } else if (s->left_comp_ctx[row7]) { |
| c = 2 + (s->above_intra_ctx[col] || |
| s->above_ref_ctx[col] == s->s.h.fixcompref); |
| } else { |
| c = (!s->above_intra_ctx[col] && |
| s->above_ref_ctx[col] == s->s.h.fixcompref) ^ |
| (!s->left_intra_ctx[row7] && |
| s->left_ref_ctx[row & 7] == s->s.h.fixcompref); |
| } |
| } else { |
| c = s->above_comp_ctx[col] ? 3 : |
| (!s->above_intra_ctx[col] && s->above_ref_ctx[col] == s->s.h.fixcompref); |
| } |
| } else if (have_l) { |
| c = s->left_comp_ctx[row7] ? 3 : |
| (!s->left_intra_ctx[row7] && s->left_ref_ctx[row7] == s->s.h.fixcompref); |
| } else { |
| c = 1; |
| } |
| b->comp = vp56_rac_get_prob(&s->c, s->prob.p.comp[c]); |
| s->counts.comp[c][b->comp]++; |
| } |
| |
| // read actual references |
| // FIXME probably cache a few variables here to prevent repetitive |
| // memory accesses below |
| if (b->comp) /* two references */ { |
| int fix_idx = s->s.h.signbias[s->s.h.fixcompref], var_idx = !fix_idx, c, bit; |
| |
| b->ref[fix_idx] = s->s.h.fixcompref; |
| // FIXME can this codeblob be replaced by some sort of LUT? |
| if (have_a) { |
| if (have_l) { |
| if (s->above_intra_ctx[col]) { |
| if (s->left_intra_ctx[row7]) { |
| c = 2; |
| } else { |
| c = 1 + 2 * (s->left_ref_ctx[row7] != s->s.h.varcompref[1]); |
| } |
| } else if (s->left_intra_ctx[row7]) { |
| c = 1 + 2 * (s->above_ref_ctx[col] != s->s.h.varcompref[1]); |
| } else { |
| int refl = s->left_ref_ctx[row7], refa = s->above_ref_ctx[col]; |
| |
| if (refl == refa && refa == s->s.h.varcompref[1]) { |
| c = 0; |
| } else if (!s->left_comp_ctx[row7] && !s->above_comp_ctx[col]) { |
| if ((refa == s->s.h.fixcompref && refl == s->s.h.varcompref[0]) || |
| (refl == s->s.h.fixcompref && refa == s->s.h.varcompref[0])) { |
| c = 4; |
| } else { |
| c = (refa == refl) ? 3 : 1; |
| } |
| } else if (!s->left_comp_ctx[row7]) { |
| if (refa == s->s.h.varcompref[1] && refl != s->s.h.varcompref[1]) { |
| c = 1; |
| } else { |
| c = (refl == s->s.h.varcompref[1] && |
| refa != s->s.h.varcompref[1]) ? 2 : 4; |
| } |
| } else if (!s->above_comp_ctx[col]) { |
| if (refl == s->s.h.varcompref[1] && refa != s->s.h.varcompref[1]) { |
| c = 1; |
| } else { |
| c = (refa == s->s.h.varcompref[1] && |
| refl != s->s.h.varcompref[1]) ? 2 : 4; |
| } |
| } else { |
| c = (refl == refa) ? 4 : 2; |
| } |
| } |
| } else { |
| if (s->above_intra_ctx[col]) { |
| c = 2; |
| } else if (s->above_comp_ctx[col]) { |
| c = 4 * (s->above_ref_ctx[col] != s->s.h.varcompref[1]); |
| } else { |
| c = 3 * (s->above_ref_ctx[col] != s->s.h.varcompref[1]); |
| } |
| } |
| } else if (have_l) { |
| if (s->left_intra_ctx[row7]) { |
| c = 2; |
| } else if (s->left_comp_ctx[row7]) { |
| c = 4 * (s->left_ref_ctx[row7] != s->s.h.varcompref[1]); |
| } else { |
| c = 3 * (s->left_ref_ctx[row7] != s->s.h.varcompref[1]); |
| } |
| } else { |
| c = 2; |
| } |
| bit = vp56_rac_get_prob(&s->c, s->prob.p.comp_ref[c]); |
| b->ref[var_idx] = s->s.h.varcompref[bit]; |
| s->counts.comp_ref[c][bit]++; |
| } else /* single reference */ { |
| int bit, c; |
| |
| if (have_a && !s->above_intra_ctx[col]) { |
| if (have_l && !s->left_intra_ctx[row7]) { |
| if (s->left_comp_ctx[row7]) { |
| if (s->above_comp_ctx[col]) { |
| c = 1 + (!s->s.h.fixcompref || !s->left_ref_ctx[row7] || |
| !s->above_ref_ctx[col]); |
| } else { |
| c = (3 * !s->above_ref_ctx[col]) + |
| (!s->s.h.fixcompref || !s->left_ref_ctx[row7]); |
| } |
| } else if (s->above_comp_ctx[col]) { |
| c = (3 * !s->left_ref_ctx[row7]) + |
| (!s->s.h.fixcompref || !s->above_ref_ctx[col]); |
| } else { |
| c = 2 * !s->left_ref_ctx[row7] + 2 * !s->above_ref_ctx[col]; |
| } |
| } else if (s->above_intra_ctx[col]) { |
| c = 2; |
| } else if (s->above_comp_ctx[col]) { |
| c = 1 + (!s->s.h.fixcompref || !s->above_ref_ctx[col]); |
| } else { |
| c = 4 * (!s->above_ref_ctx[col]); |
| } |
| } else if (have_l && !s->left_intra_ctx[row7]) { |
| if (s->left_intra_ctx[row7]) { |
| c = 2; |
| } else if (s->left_comp_ctx[row7]) { |
| c = 1 + (!s->s.h.fixcompref || !s->left_ref_ctx[row7]); |
| } else { |
| c = 4 * (!s->left_ref_ctx[row7]); |
| } |
| } else { |
| c = 2; |
| } |
| bit = vp56_rac_get_prob(&s->c, s->prob.p.single_ref[c][0]); |
| s->counts.single_ref[c][0][bit]++; |
| if (!bit) { |
| b->ref[0] = 0; |
| } else { |
| // FIXME can this codeblob be replaced by some sort of LUT? |
| if (have_a) { |
| if (have_l) { |
| if (s->left_intra_ctx[row7]) { |
| if (s->above_intra_ctx[col]) { |
| c = 2; |
| } else if (s->above_comp_ctx[col]) { |
| c = 1 + 2 * (s->s.h.fixcompref == 1 || |
| s->above_ref_ctx[col] == 1); |
| } else if (!s->above_ref_ctx[col]) { |
| c = 3; |
| } else { |
| c = 4 * (s->above_ref_ctx[col] == 1); |
| } |
| } else if (s->above_intra_ctx[col]) { |
| if (s->left_intra_ctx[row7]) { |
| c = 2; |
| } else if (s->left_comp_ctx[row7]) { |
| c = 1 + 2 * (s->s.h.fixcompref == 1 || |
| s->left_ref_ctx[row7] == 1); |
| } else if (!s->left_ref_ctx[row7]) { |
| c = 3; |
| } else { |
| c = 4 * (s->left_ref_ctx[row7] == 1); |
| } |
| } else if (s->above_comp_ctx[col]) { |
| if (s->left_comp_ctx[row7]) { |
| if (s->left_ref_ctx[row7] == s->above_ref_ctx[col]) { |
| c = 3 * (s->s.h.fixcompref == 1 || |
| s->left_ref_ctx[row7] == 1); |
| } else { |
| c = 2; |
| } |
| } else if (!s->left_ref_ctx[row7]) { |
| c = 1 + 2 * (s->s.h.fixcompref == 1 || |
| s->above_ref_ctx[col] == 1); |
| } else { |
| c = 3 * (s->left_ref_ctx[row7] == 1) + |
| (s->s.h.fixcompref == 1 || s->above_ref_ctx[col] == 1); |
| } |
| } else if (s->left_comp_ctx[row7]) { |
| if (!s->above_ref_ctx[col]) { |
| c = 1 + 2 * (s->s.h.fixcompref == 1 || |
| s->left_ref_ctx[row7] == 1); |
| } else { |
| c = 3 * (s->above_ref_ctx[col] == 1) + |
| (s->s.h.fixcompref == 1 || s->left_ref_ctx[row7] == 1); |
| } |
| } else if (!s->above_ref_ctx[col]) { |
| if (!s->left_ref_ctx[row7]) { |
| c = 3; |
| } else { |
| c = 4 * (s->left_ref_ctx[row7] == 1); |
| } |
| } else if (!s->left_ref_ctx[row7]) { |
| c = 4 * (s->above_ref_ctx[col] == 1); |
| } else { |
| c = 2 * (s->left_ref_ctx[row7] == 1) + |
| 2 * (s->above_ref_ctx[col] == 1); |
| } |
| } else { |
| if (s->above_intra_ctx[col] || |
| (!s->above_comp_ctx[col] && !s->above_ref_ctx[col])) { |
| c = 2; |
| } else if (s->above_comp_ctx[col]) { |
| c = 3 * (s->s.h.fixcompref == 1 || s->above_ref_ctx[col] == 1); |
| } else { |
| c = 4 * (s->above_ref_ctx[col] == 1); |
| } |
| } |
| } else if (have_l) { |
| if (s->left_intra_ctx[row7] || |
| (!s->left_comp_ctx[row7] && !s->left_ref_ctx[row7])) { |
| c = 2; |
| } else if (s->left_comp_ctx[row7]) { |
| c = 3 * (s->s.h.fixcompref == 1 || s->left_ref_ctx[row7] == 1); |
| } else { |
| c = 4 * (s->left_ref_ctx[row7] == 1); |
| } |
| } else { |
| c = 2; |
| } |
| bit = vp56_rac_get_prob(&s->c, s->prob.p.single_ref[c][1]); |
| s->counts.single_ref[c][1][bit]++; |
| b->ref[0] = 1 + bit; |
| } |
| } |
| } |
| |
| if (b->bs <= BS_8x8) { |
| if (s->s.h.segmentation.enabled && s->s.h.segmentation.feat[b->seg_id].skip_enabled) { |
| b->mode[0] = b->mode[1] = b->mode[2] = b->mode[3] = ZEROMV; |
| } else { |
| static const uint8_t off[10] = { |
| 3, 0, 0, 1, 0, 0, 0, 0, 0, 0 |
| }; |
| |
| // FIXME this needs to use the LUT tables from find_ref_mvs |
| // because not all are -1,0/0,-1 |
| int c = inter_mode_ctx_lut[s->above_mode_ctx[col + off[b->bs]]] |
| [s->left_mode_ctx[row7 + off[b->bs]]]; |
| |
| b->mode[0] = vp8_rac_get_tree(&s->c, vp9_inter_mode_tree, |
| s->prob.p.mv_mode[c]); |
| b->mode[1] = b->mode[2] = b->mode[3] = b->mode[0]; |
| s->counts.mv_mode[c][b->mode[0] - 10]++; |
| } |
| } |
| |
| if (s->s.h.filtermode == FILTER_SWITCHABLE) { |
| int c; |
| |
| if (have_a && s->above_mode_ctx[col] >= NEARESTMV) { |
| if (have_l && s->left_mode_ctx[row7] >= NEARESTMV) { |
| c = s->above_filter_ctx[col] == s->left_filter_ctx[row7] ? |
| s->left_filter_ctx[row7] : 3; |
| } else { |
| c = s->above_filter_ctx[col]; |
| } |
| } else if (have_l && s->left_mode_ctx[row7] >= NEARESTMV) { |
| c = s->left_filter_ctx[row7]; |
| } else { |
| c = 3; |
| } |
| |
| filter_id = vp8_rac_get_tree(&s->c, vp9_filter_tree, |
| s->prob.p.filter[c]); |
| s->counts.filter[c][filter_id]++; |
| b->filter = vp9_filter_lut[filter_id]; |
| } else { |
| b->filter = s->s.h.filtermode; |
| } |
| |
| if (b->bs > BS_8x8) { |
| int c = inter_mode_ctx_lut[s->above_mode_ctx[col]][s->left_mode_ctx[row7]]; |
| |
| b->mode[0] = vp8_rac_get_tree(&s->c, vp9_inter_mode_tree, |
| s->prob.p.mv_mode[c]); |
| s->counts.mv_mode[c][b->mode[0] - 10]++; |
| fill_mv(s, b->mv[0], b->mode[0], 0); |
| |
| if (b->bs != BS_8x4) { |
| b->mode[1] = vp8_rac_get_tree(&s->c, vp9_inter_mode_tree, |
| s->prob.p.mv_mode[c]); |
| s->counts.mv_mode[c][b->mode[1] - 10]++; |
| fill_mv(s, b->mv[1], b->mode[1], 1); |
| } else { |
| b->mode[1] = b->mode[0]; |
| AV_COPY32(&b->mv[1][0], &b->mv[0][0]); |
| AV_COPY32(&b->mv[1][1], &b->mv[0][1]); |
| } |
| |
| if (b->bs != BS_4x8) { |
| b->mode[2] = vp8_rac_get_tree(&s->c, vp9_inter_mode_tree, |
| s->prob.p.mv_mode[c]); |
| s->counts.mv_mode[c][b->mode[2] - 10]++; |
| fill_mv(s, b->mv[2], b->mode[2], 2); |
| |
| if (b->bs != BS_8x4) { |
| b->mode[3] = vp8_rac_get_tree(&s->c, vp9_inter_mode_tree, |
| s->prob.p.mv_mode[c]); |
| s->counts.mv_mode[c][b->mode[3] - 10]++; |
| fill_mv(s, b->mv[3], b->mode[3], 3); |
| } else { |
| b->mode[3] = b->mode[2]; |
| AV_COPY32(&b->mv[3][0], &b->mv[2][0]); |
| AV_COPY32(&b->mv[3][1], &b->mv[2][1]); |
| } |
| } else { |
| b->mode[2] = b->mode[0]; |
| AV_COPY32(&b->mv[2][0], &b->mv[0][0]); |
| AV_COPY32(&b->mv[2][1], &b->mv[0][1]); |
| b->mode[3] = b->mode[1]; |
| AV_COPY32(&b->mv[3][0], &b->mv[1][0]); |
| AV_COPY32(&b->mv[3][1], &b->mv[1][1]); |
| } |
| } else { |
| fill_mv(s, b->mv[0], b->mode[0], -1); |
| AV_COPY32(&b->mv[1][0], &b->mv[0][0]); |
| AV_COPY32(&b->mv[2][0], &b->mv[0][0]); |
| AV_COPY32(&b->mv[3][0], &b->mv[0][0]); |
| AV_COPY32(&b->mv[1][1], &b->mv[0][1]); |
| AV_COPY32(&b->mv[2][1], &b->mv[0][1]); |
| AV_COPY32(&b->mv[3][1], &b->mv[0][1]); |
| } |
| |
| vref = b->ref[b->comp ? s->s.h.signbias[s->s.h.varcompref[0]] : 0]; |
| } |
| |
| #if HAVE_FAST_64BIT |
| #define SPLAT_CTX(var, val, n) \ |
| switch (n) { \ |
| case 1: var = val; break; \ |
| case 2: AV_WN16A(&var, val * 0x0101); break; \ |
| case 4: AV_WN32A(&var, val * 0x01010101); break; \ |
| case 8: AV_WN64A(&var, val * 0x0101010101010101ULL); break; \ |
| case 16: { \ |
| uint64_t v64 = val * 0x0101010101010101ULL; \ |
| AV_WN64A( &var, v64); \ |
| AV_WN64A(&((uint8_t *) &var)[8], v64); \ |
| break; \ |
| } \ |
| } |
| #else |
| #define SPLAT_CTX(var, val, n) \ |
| switch (n) { \ |
| case 1: var = val; break; \ |
| case 2: AV_WN16A(&var, val * 0x0101); break; \ |
| case 4: AV_WN32A(&var, val * 0x01010101); break; \ |
| case 8: { \ |
| uint32_t v32 = val * 0x01010101; \ |
| AV_WN32A( &var, v32); \ |
| AV_WN32A(&((uint8_t *) &var)[4], v32); \ |
|