func: static int vp9_decode_frame(AVCodecContext *ctx, void *frame,
  
                              int *got_frame, AVPacket *pkt)
  
  {
  
      const uint8_t *data = pkt->data;
  
      int size = pkt->size;
  
      VP9Context *s = ctx->priv_data;
  
      int res, tile_row, tile_col, i, ref, row, col;
  
      int retain_segmap_ref = s->s.frames[REF_FRAME_SEGMAP].segmentation_map &&
  
                              (!s->s.h.segmentation.enabled || !s->s.h.segmentation.update_map);
  
      ptrdiff_t yoff, uvoff, ls_y, ls_uv;
  
      AVFrame *f;
  
      int bytesperpixel;
  
  
  
      if ((res = decode_frame_header(ctx, data, size, &ref)) < 0) {
  
          return res;
  
      } else if (res == 0) {
  
          if (!s->s.refs[ref].f->buf[0]) {
  
              av_log(ctx, AV_LOG_ERROR, "Requested reference %d not available\n", ref);
  
              return AVERROR_INVALIDDATA;
  
          }
  
          if ((res = av_frame_ref(frame, s->s.refs[ref].f)) < 0)
  
              return res;
  
          ((AVFrame *)frame)->pts = pkt->pts;
  
  #if FF_API_PKT_PTS
  
  FF_DISABLE_DEPRECATION_WARNINGS
  
          ((AVFrame *)frame)->pkt_pts = pkt->pts;
  
  FF_ENABLE_DEPRECATION_WARNINGS
  
  #endif
  
          ((AVFrame *)frame)->pkt_dts = pkt->dts;
  
          for (i = 0; i < 8; i++) {
  
              if (s->next_refs[i].f->buf[0])
  
                  ff_thread_release_buffer(ctx, &s->next_refs[i]);
  
              if (s->s.refs[i].f->buf[0] &&
  
                  (res = ff_thread_ref_frame(&s->next_refs[i], &s->s.refs[i])) < 0)
  
                  return res;
  
          }
  
          *got_frame = 1;
  
          return pkt->size;
  
      }
  
      data += res;
  
      size -= res;
  
  
  
      if (!retain_segmap_ref || s->s.h.keyframe || s->s.h.intraonly) {
  
          if (s->s.frames[REF_FRAME_SEGMAP].tf.f->buf[0])
  
              vp9_unref_frame(ctx, &s->s.frames[REF_FRAME_SEGMAP]);
  
          if (!s->s.h.keyframe && !s->s.h.intraonly && !s->s.h.errorres && s->s.frames[CUR_FRAME].tf.f->buf[0] &&
  
              (res = vp9_ref_frame(ctx, &s->s.frames[REF_FRAME_SEGMAP], &s->s.frames[CUR_FRAME])) < 0)
  
              return res;
  
      }
  
      if (s->s.frames[REF_FRAME_MVPAIR].tf.f->buf[0])
  
          vp9_unref_frame(ctx, &s->s.frames[REF_FRAME_MVPAIR]);
  
      if (!s->s.h.intraonly && !s->s.h.keyframe && !s->s.h.errorres && s->s.frames[CUR_FRAME].tf.f->buf[0] &&
  
          (res = vp9_ref_frame(ctx, &s->s.frames[REF_FRAME_MVPAIR], &s->s.frames[CUR_FRAME])) < 0)
  
          return res;
  
      if (s->s.frames[CUR_FRAME].tf.f->buf[0])
  
          vp9_unref_frame(ctx, &s->s.frames[CUR_FRAME]);
  
      if ((res = vp9_alloc_frame(ctx, &s->s.frames[CUR_FRAME])) < 0)
  
          return res;
  
      f = s->s.frames[CUR_FRAME].tf.f;
  
      f->key_frame = s->s.h.keyframe;
  
      f->pict_type = (s->s.h.keyframe || s->s.h.intraonly) ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
  
      ls_y = f->linesize[0];
  
      ls_uv =f->linesize[1];
  
  
  
      if (s->s.frames[REF_FRAME_SEGMAP].tf.f->buf[0] &&
  
          (s->s.frames[REF_FRAME_MVPAIR].tf.f->width  != s->s.frames[CUR_FRAME].tf.f->width ||
  
           s->s.frames[REF_FRAME_MVPAIR].tf.f->height != s->s.frames[CUR_FRAME].tf.f->height)) {
  
          vp9_unref_frame(ctx, &s->s.frames[REF_FRAME_SEGMAP]);
  
      }
  
  
  
      // ref frame setup
  
      for (i = 0; i < 8; i++) {
  
          if (s->next_refs[i].f->buf[0])
  
              ff_thread_release_buffer(ctx, &s->next_refs[i]);
  
          if (s->s.h.refreshrefmask & (1 << i)) {
  
              res = ff_thread_ref_frame(&s->next_refs[i], &s->s.frames[CUR_FRAME].tf);
  
          } else if (s->s.refs[i].f->buf[0]) {
  
              res = ff_thread_ref_frame(&s->next_refs[i], &s->s.refs[i]);
  
          }
  
          if (res < 0)
  
              return res;
  
      }
  
  
  
      if (ctx->hwaccel) {
  
          res = ctx->hwaccel->start_frame(ctx, NULL, 0);
  
          if (res < 0)
  
              return res;
  
          res = ctx->hwaccel->decode_slice(ctx, pkt->data, pkt->size);
  
          if (res < 0)
  
              return res;
  
          res = ctx->hwaccel->end_frame(ctx);
  
          if (res < 0)
  
              return res;
  
          goto finish;
  
      }
  
  
  
      // main tile decode loop
  
      bytesperpixel = s->bytesperpixel;
  
      memset(s->above_partition_ctx, 0, s->cols);
  
      memset(s->above_skip_ctx, 0, s->cols);
  
      if (s->s.h.keyframe || s->s.h.intraonly) {
  
          memset(s->above_mode_ctx, DC_PRED, s->cols * 2);
  
      } else {
  
          memset(s->above_mode_ctx, NEARESTMV, s->cols);
  
      }
  
      memset(s->above_y_nnz_ctx, 0, s->sb_cols * 16);
  
      memset(s->above_uv_nnz_ctx[0], 0, s->sb_cols * 16 >> s->ss_h);
  
      memset(s->above_uv_nnz_ctx[1], 0, s->sb_cols * 16 >> s->ss_h);
  
      memset(s->above_segpred_ctx, 0, s->cols);
  
      s->pass = s->s.frames[CUR_FRAME].uses_2pass =
  
          ctx->active_thread_type == FF_THREAD_FRAME && s->s.h.refreshctx && !s->s.h.parallelmode;
  
      if ((res = update_block_buffers(ctx)) < 0) {
  
          av_log(ctx, AV_LOG_ERROR,
  
                 "Failed to allocate block buffers\n");
  
          return res;
  
      }
  
      if (s->s.h.refreshctx && s->s.h.parallelmode) {
  
          int j, k, l, m;
  
  
  
          for (i = 0; i < 4; i++) {
  
              for (j = 0; j < 2; j++)
  
                  for (k = 0; k < 2; k++)
  
                      for (l = 0; l < 6; l++)
  
                          for (m = 0; m < 6; m++)
  
                              memcpy(s->prob_ctx[s->s.h.framectxid].coef[i][j][k][l][m],
  
                                     s->prob.coef[i][j][k][l][m], 3);
  
              if (s->s.h.txfmmode == i)
  
                  break;
  
          }
  
          s->prob_ctx[s->s.h.framectxid].p = s->prob.p;
  
          ff_thread_finish_setup(ctx);
  
      } else if (!s->s.h.refreshctx) {
  
          ff_thread_finish_setup(ctx);
  
      }
  
  
  
      do {
  
          yoff = uvoff = 0;
  
          s->b = s->b_base;
  
          s->block = s->block_base;
  
          s->uvblock[0] = s->uvblock_base[0];
  
          s->uvblock[1] = s->uvblock_base[1];
  
          s->eob = s->eob_base;
  
          s->uveob[0] = s->uveob_base[0];
  
          s->uveob[1] = s->uveob_base[1];
  
  
  
          for (tile_row = 0; tile_row < s->s.h.tiling.tile_rows; tile_row++) {
  
              set_tile_offset(&s->tile_row_start, &s->tile_row_end,
  
                              tile_row, s->s.h.tiling.log2_tile_rows, s->sb_rows);
  
              if (s->pass != 2) {
  
                  for (tile_col = 0; tile_col < s->s.h.tiling.tile_cols; tile_col++) {
  
                      int64_t tile_size;
  
  
  
                      if (tile_col == s->s.h.tiling.tile_cols - 1 &&
  
                          tile_row == s->s.h.tiling.tile_rows - 1) {
  
                          tile_size = size;
  
                      } else {
  
                          tile_size = AV_RB32(data);
  
                          data += 4;
  
                          size -= 4;
  
                      }
  
                      if (tile_size > size) {
  
                          ff_thread_report_progress(&s->s.frames[CUR_FRAME].tf, INT_MAX, 0);
  
                          return AVERROR_INVALIDDATA;
  
                      }
  
                      ff_vp56_init_range_decoder(&s->c_b[tile_col], data, tile_size);
  
                      if (vp56_rac_get_prob_branchy(&s->c_b[tile_col], 128)) { // marker bit
  
                          ff_thread_report_progress(&s->s.frames[CUR_FRAME].tf, INT_MAX, 0);
  
                          return AVERROR_INVALIDDATA;
  
                      }
  
                      data += tile_size;
  
                      size -= tile_size;
  
                  }
  
              }
  
  
  
              for (row = s->tile_row_start; row < s->tile_row_end;
  
                   row += 8, yoff += ls_y * 64, uvoff += ls_uv * 64 >> s->ss_v) {
  
                  struct VP9Filter *lflvl_ptr = s->lflvl;
  
                  ptrdiff_t yoff2 = yoff, uvoff2 = uvoff;
  
  
  
                  for (tile_col = 0; tile_col < s->s.h.tiling.tile_cols; tile_col++) {
  
                      set_tile_offset(&s->tile_col_start, &s->tile_col_end,
  
                                      tile_col, s->s.h.tiling.log2_tile_cols, s->sb_cols);
  
  
  
                      if (s->pass != 2) {
  
                          memset(s->left_partition_ctx, 0, 8);
  
                          memset(s->left_skip_ctx, 0, 8);
  
                          if (s->s.h.keyframe || s->s.h.intraonly) {
  
                              memset(s->left_mode_ctx, DC_PRED, 16);
  
                          } else {
  
                              memset(s->left_mode_ctx, NEARESTMV, 8);
  
                          }
  
                          memset(s->left_y_nnz_ctx, 0, 16);
  
                          memset(s->left_uv_nnz_ctx, 0, 32);
  
                          memset(s->left_segpred_ctx, 0, 8);
  
  
  
                          memcpy(&s->c, &s->c_b[tile_col], sizeof(s->c));
  
                      }
  
  
  
                      for (col = s->tile_col_start;
  
                           col < s->tile_col_end;
  
                           col += 8, yoff2 += 64 * bytesperpixel,
  
                           uvoff2 += 64 * bytesperpixel >> s->ss_h, lflvl_ptr++) {
  
                          // FIXME integrate with lf code (i.e. zero after each
  
                          // use, similar to invtxfm coefficients, or similar)
  
                          if (s->pass != 1) {
  
                              memset(lflvl_ptr->mask, 0, sizeof(lflvl_ptr->mask));
  
                          }
  
  
  
                          if (s->pass == 2) {
  
                              decode_sb_mem(ctx, row, col, lflvl_ptr,
  
                                            yoff2, uvoff2, BL_64X64);
  
                          } else {
  
                              decode_sb(ctx, row, col, lflvl_ptr,
  
                                        yoff2, uvoff2, BL_64X64);
  
                          }
  
                      }
  
                      if (s->pass != 2) {
  
                          memcpy(&s->c_b[tile_col], &s->c, sizeof(s->c));
  
                      }
  
                  }
  
  
  
                  if (s->pass == 1) {
  
                      continue;
  
                  }
  
  
  
                  // backup pre-loopfilter reconstruction data for intra
  
                  // prediction of next row of sb64s
  
                  if (row + 8 < s->rows) {
  
                      memcpy(s->intra_pred_data[0],
  
                             f->data[0] + yoff + 63 * ls_y,
  
                             8 * s->cols * bytesperpixel);
  
                      memcpy(s->intra_pred_data[1],
  
                             f->data[1] + uvoff + ((64 >> s->ss_v) - 1) * ls_uv,
  
                             8 * s->cols * bytesperpixel >> s->ss_h);
  
                      memcpy(s->intra_pred_data[2],
  
                             f->data[2] + uvoff + ((64 >> s->ss_v) - 1) * ls_uv,
  
                             8 * s->cols * bytesperpixel >> s->ss_h);
  
                  }
  
  
  
                  // loopfilter one row
  
                  if (s->s.h.filter.level) {
  
                      yoff2 = yoff;
  
                      uvoff2 = uvoff;
  
                      lflvl_ptr = s->lflvl;
  
                      for (col = 0; col < s->cols;
  
                           col += 8, yoff2 += 64 * bytesperpixel,
  
                           uvoff2 += 64 * bytesperpixel >> s->ss_h, lflvl_ptr++) {
  
                          loopfilter_sb(ctx, lflvl_ptr, row, col, yoff2, uvoff2);
  
                      }
  
                  }
  
  
  
                  // FIXME maybe we can make this more finegrained by running the
  
                  // loopfilter per-block instead of after each sbrow
  
                  // In fact that would also make intra pred left preparation easier?
  
                  ff_thread_report_progress(&s->s.frames[CUR_FRAME].tf, row >> 3, 0);
  
              }
  
          }
  
  
  
          if (s->pass < 2 && s->s.h.refreshctx && !s->s.h.parallelmode) {
  
              adapt_probs(s);
  
              ff_thread_finish_setup(ctx);
  
          }
  
      } while (s->pass++ == 1);
  
      ff_thread_report_progress(&s->s.frames[CUR_FRAME].tf, INT_MAX, 0);
  
  
  
  finish:
  
      // ref frame setup
  
      for (i = 0; i < 8; i++) {
  
          if (s->s.refs[i].f->buf[0])
  
              ff_thread_release_buffer(ctx, &s->s.refs[i]);
  
          if (s->next_refs[i].f->buf[0] &&
  
              (res = ff_thread_ref_frame(&s->s.refs[i], &s->next_refs[i])) < 0)
  
              return res;
  
      }
  
  
  
      if (!s->s.h.invisible) {
  
          if ((res = av_frame_ref(frame, s->s.frames[CUR_FRAME].tf.f)) < 0)
  
              return res;
  
          *got_frame = 1;
  
      }
  
  
  
      return pkt->size;
  
  }
  