vp9_dx_iface.c 22.8 KB
Newer Older
John Koleszar's avatar
John Koleszar committed
1
/*
2
 *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
John Koleszar's avatar
John Koleszar committed
3
 *
4
 *  Use of this source code is governed by a BSD-style license
5 6
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
7
 *  in the file PATENTS.  All contributing project authors may
8
 *  be found in the AUTHORS file in the root of the source tree.
John Koleszar's avatar
John Koleszar committed
9 10 11 12 13
 */


#include <stdlib.h>
#include <string.h>
14 15 16
#include "vpx/vpx_decoder.h"
#include "vpx/vp8dx.h"
#include "vpx/internal/vpx_codec_internal.h"
17
#include "./vpx_version.h"
18
#include "vp9/common/vp9_frame_buffers.h"
19
#include "vp9/decoder/vp9_decoder.h"
20
#include "vp9/decoder/vp9_read_bit_buffer.h"
John Koleszar's avatar
John Koleszar committed
21
#include "vp9/vp9_iface_common.h"
John Koleszar's avatar
John Koleszar committed
22

23
#define VP9_CAP_POSTPROC (CONFIG_VP9_POSTPROC ? VPX_CODEC_CAP_POSTPROC : 0)
24
typedef vpx_codec_stream_info_t  vp9_stream_info_t;
John Koleszar's avatar
John Koleszar committed
25 26

/* Structures for handling memory allocations */
John Koleszar's avatar
John Koleszar committed
27
typedef enum {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
28
  VP9_SEG_ALG_PRIV = 256,
29
  VP9_SEG_MAX
John Koleszar's avatar
John Koleszar committed
30
} mem_seg_id_t;
31
#define NELEMENTS(x) ((int)(sizeof(x)/sizeof(x[0])))
John Koleszar's avatar
John Koleszar committed
32

33 34
static unsigned long priv_sz(const vpx_codec_dec_cfg_t *si,
                             vpx_codec_flags_t flags);
John Koleszar's avatar
John Koleszar committed
35

36 37 38
static const mem_req_t vp9_mem_req_segs[] = {
  {VP9_SEG_ALG_PRIV, 0, 8, VPX_CODEC_MEM_ZERO, priv_sz},
  {VP9_SEG_MAX, 0, 0, 0, NULL}
John Koleszar's avatar
John Koleszar committed
39 40
};

John Koleszar's avatar
John Koleszar committed
41 42
struct vpx_codec_alg_priv {
  vpx_codec_priv_t        base;
43
  vpx_codec_mmap_t        mmaps[NELEMENTS(vp9_mem_req_segs) - 1];
John Koleszar's avatar
John Koleszar committed
44
  vpx_codec_dec_cfg_t     cfg;
45
  vp9_stream_info_t       si;
John Koleszar's avatar
John Koleszar committed
46 47
  int                     defer_alloc;
  int                     decoder_init;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
48
  struct VP9Decompressor *pbi;
John Koleszar's avatar
John Koleszar committed
49 50
  int                     postproc_cfg_set;
  vp8_postproc_cfg_t      postproc_cfg;
51
#if CONFIG_POSTPROC_VISUALIZER
John Koleszar's avatar
John Koleszar committed
52 53 54 55 56
  unsigned int            dbg_postproc_flag;
  int                     dbg_color_ref_frame_flag;
  int                     dbg_color_mb_modes_flag;
  int                     dbg_color_b_modes_flag;
  int                     dbg_display_mv_flag;
57
#endif
John Koleszar's avatar
John Koleszar committed
58 59 60
  vpx_image_t             img;
  int                     img_setup;
  int                     img_avail;
61
  int                     invert_tile_order;
62 63 64 65 66

  // External frame buffer info to save for VP9 common.
  void *ext_priv;  // Private data associated with the external frame buffers.
  vpx_get_frame_buffer_cb_fn_t get_ext_fb_cb;
  vpx_release_frame_buffer_cb_fn_t release_ext_fb_cb;
John Koleszar's avatar
John Koleszar committed
67 68
};

69 70
static unsigned long priv_sz(const vpx_codec_dec_cfg_t *si,
                             vpx_codec_flags_t flags) {
John Koleszar's avatar
John Koleszar committed
71 72 73 74 75 76 77
  /* Although this declaration is constant, we can't use it in the requested
   * segments list because we want to define the requested segments list
   * before defining the private type (so that the number of memory maps is
   * known)
   */
  (void)si;
  return sizeof(vpx_codec_alg_priv_t);
John Koleszar's avatar
John Koleszar committed
78 79
}

80
static void vp9_init_ctx(vpx_codec_ctx_t *ctx, const vpx_codec_mmap_t *mmap) {
John Koleszar's avatar
John Koleszar committed
81
  int i;
John Koleszar's avatar
John Koleszar committed
82

83
  ctx->priv = (vpx_codec_priv_t *)mmap->base;
John Koleszar's avatar
John Koleszar committed
84 85
  ctx->priv->sz = sizeof(*ctx->priv);
  ctx->priv->iface = ctx->iface;
86
  ctx->priv->alg_priv = (struct vpx_codec_alg_priv *)mmap->base;
John Koleszar's avatar
John Koleszar committed
87

John Koleszar's avatar
John Koleszar committed
88
  for (i = 0; i < NELEMENTS(ctx->priv->alg_priv->mmaps); i++)
89
    ctx->priv->alg_priv->mmaps[i].id = vp9_mem_req_segs[i].id;
John Koleszar's avatar
John Koleszar committed
90

John Koleszar's avatar
John Koleszar committed
91 92 93
  ctx->priv->alg_priv->mmaps[0] = *mmap;
  ctx->priv->alg_priv->si.sz = sizeof(ctx->priv->alg_priv->si);
  ctx->priv->init_flags = ctx->init_flags;
John Koleszar's avatar
John Koleszar committed
94

John Koleszar's avatar
John Koleszar committed
95 96 97 98 99
  if (ctx->config.dec) {
    /* Update the reference to the config structure to an internal copy. */
    ctx->priv->alg_priv->cfg = *ctx->config.dec;
    ctx->config.dec = &ctx->priv->alg_priv->cfg;
  }
John Koleszar's avatar
John Koleszar committed
100 101
}

102
static void vp9_finalize_mmaps(vpx_codec_alg_priv_t *ctx) {
John Koleszar's avatar
John Koleszar committed
103
  /* nothing to clean up */
John Koleszar's avatar
John Koleszar committed
104 105
}

106
static vpx_codec_err_t vp9_init(vpx_codec_ctx_t *ctx,
John Koleszar's avatar
John Koleszar committed
107
                                vpx_codec_priv_enc_mr_cfg_t *data) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
108
  vpx_codec_err_t res = VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
109

Dmitry Kovalev's avatar
Dmitry Kovalev committed
110 111 112
  // This function only allocates space for the vpx_codec_alg_priv_t
  // structure. More memory may be required at the time the stream
  // information becomes known.
John Koleszar's avatar
John Koleszar committed
113 114
  if (!ctx->priv) {
    vpx_codec_mmap_t mmap;
John Koleszar's avatar
John Koleszar committed
115

116
    mmap.id = vp9_mem_req_segs[0].id;
John Koleszar's avatar
John Koleszar committed
117
    mmap.sz = sizeof(vpx_codec_alg_priv_t);
118 119
    mmap.align = vp9_mem_req_segs[0].align;
    mmap.flags = vp9_mem_req_segs[0].flags;
John Koleszar's avatar
John Koleszar committed
120

121
    res = vpx_mmap_alloc(&mmap);
John Koleszar's avatar
John Koleszar committed
122
    if (!res) {
123
      vp9_init_ctx(ctx, &mmap);
John Koleszar's avatar
John Koleszar committed
124

John Koleszar's avatar
John Koleszar committed
125
      ctx->priv->alg_priv->defer_alloc = 1;
John Koleszar's avatar
John Koleszar committed
126
    }
John Koleszar's avatar
John Koleszar committed
127
  }
John Koleszar's avatar
John Koleszar committed
128

John Koleszar's avatar
John Koleszar committed
129
  return res;
John Koleszar's avatar
John Koleszar committed
130 131
}

132
static vpx_codec_err_t vp9_destroy(vpx_codec_alg_priv_t *ctx) {
John Koleszar's avatar
John Koleszar committed
133
  int i;
John Koleszar's avatar
John Koleszar committed
134

135
  vp9_remove_decompressor(ctx->pbi);
John Koleszar's avatar
John Koleszar committed
136

John Koleszar's avatar
John Koleszar committed
137 138 139 140
  for (i = NELEMENTS(ctx->mmaps) - 1; i >= 0; i--) {
    if (ctx->mmaps[i].dtor)
      ctx->mmaps[i].dtor(&ctx->mmaps[i]);
  }
John Koleszar's avatar
John Koleszar committed
141

John Koleszar's avatar
John Koleszar committed
142
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
143 144
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
145
static vpx_codec_err_t vp9_peek_si(const uint8_t *data, unsigned int data_sz,
John Koleszar's avatar
John Koleszar committed
146
                                   vpx_codec_stream_info_t *si) {
James Zern's avatar
James Zern committed
147
  if (data_sz <= 8) return VPX_CODEC_UNSUP_BITSTREAM;
148 149 150 151
  if (data + data_sz <= data) return VPX_CODEC_INVALID_PARAM;

  si->is_kf = 0;
  si->w = si->h = 0;
John Koleszar's avatar
John Koleszar committed
152

153 154 155
  {
    struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
    const int frame_marker = vp9_rb_read_literal(&rb, 2);
156 157 158
    const int version = vp9_rb_read_bit(&rb);
    (void) vp9_rb_read_bit(&rb);  // unused version bit

159 160
    if (frame_marker != VP9_FRAME_MARKER)
      return VPX_CODEC_UNSUP_BITSTREAM;
161 162 163 164 165
    if (version > 1) return VPX_CODEC_UNSUP_BITSTREAM;

    if (vp9_rb_read_bit(&rb)) {  // show an existing frame
      return VPX_CODEC_OK;
    }
James Zern's avatar
James Zern committed
166

167
    si->is_kf = !vp9_rb_read_bit(&rb);
James Zern's avatar
James Zern committed
168
    if (si->is_kf) {
169 170
      const int sRGB = 7;
      int colorspace;
John Koleszar's avatar
John Koleszar committed
171

172 173
      rb.bit_offset += 1;  // show frame
      rb.bit_offset += 1;  // error resilient
John Koleszar's avatar
John Koleszar committed
174

175 176 177
      if (vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_0 ||
          vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_1 ||
          vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_2) {
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
        return VPX_CODEC_UNSUP_BITSTREAM;
      }

      colorspace = vp9_rb_read_literal(&rb, 3);
      if (colorspace != sRGB) {
        rb.bit_offset += 1;  // [16,235] (including xvycc) vs [0,255] range
        if (version == 1) {
          rb.bit_offset += 2;  // subsampling x/y
          rb.bit_offset += 1;  // has extra plane
        }
      } else {
        if (version == 1) {
          rb.bit_offset += 1;  // has extra plane
        } else {
          // RGB is only available in version 1
          return VPX_CODEC_UNSUP_BITSTREAM;
        }
      }

      // TODO(jzern): these are available on non-keyframes in intra only mode.
      si->w = vp9_rb_read_literal(&rb, 16) + 1;
      si->h = vp9_rb_read_literal(&rb, 16) + 1;
James Zern's avatar
James Zern committed
200
    }
John Koleszar's avatar
John Koleszar committed
201 202
  }

203
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
204 205
}

206
static vpx_codec_err_t vp9_get_si(vpx_codec_alg_priv_t    *ctx,
John Koleszar's avatar
John Koleszar committed
207
                                  vpx_codec_stream_info_t *si) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
208 209 210
  const size_t sz = (si->sz >= sizeof(vp9_stream_info_t))
                       ? sizeof(vp9_stream_info_t)
                       : sizeof(vpx_codec_stream_info_t);
John Koleszar's avatar
John Koleszar committed
211
  memcpy(si, &ctx->si, sz);
212
  si->sz = (unsigned int)sz;
John Koleszar's avatar
John Koleszar committed
213

John Koleszar's avatar
John Koleszar committed
214
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
215 216 217
}


Dmitry Kovalev's avatar
Dmitry Kovalev committed
218 219 220 221
static vpx_codec_err_t update_error_state(vpx_codec_alg_priv_t *ctx,
                           const struct vpx_internal_error_info *error) {
  if (error->error_code)
    ctx->base.err_detail = error->has_detail ? error->detail : NULL;
John Koleszar's avatar
John Koleszar committed
222

Dmitry Kovalev's avatar
Dmitry Kovalev committed
223
  return error->error_code;
John Koleszar's avatar
John Koleszar committed
224 225
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
226 227 228
static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx,
                                  const uint8_t **data, unsigned int data_sz,
                                  void *user_priv, int64_t deadline) {
John Koleszar's avatar
John Koleszar committed
229
  vpx_codec_err_t res = VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
230

John Koleszar's avatar
John Koleszar committed
231
  ctx->img_avail = 0;
John Koleszar's avatar
John Koleszar committed
232

John Koleszar's avatar
John Koleszar committed
233 234 235 236 237
  /* Determine the stream parameters. Note that we rely on peek_si to
   * validate that we have a buffer that does not wrap around the top
   * of the heap.
   */
  if (!ctx->si.h)
238
    res = ctx->base.iface->dec.peek_si(*data, data_sz, &ctx->si);
John Koleszar's avatar
John Koleszar committed
239 240


John Koleszar's avatar
John Koleszar committed
241 242 243
  /* Perform deferred allocations, if required */
  if (!res && ctx->defer_alloc) {
    int i;
John Koleszar's avatar
John Koleszar committed
244

John Koleszar's avatar
John Koleszar committed
245 246
    for (i = 1; !res && i < NELEMENTS(ctx->mmaps); i++) {
      vpx_codec_dec_cfg_t cfg;
John Koleszar's avatar
John Koleszar committed
247

John Koleszar's avatar
John Koleszar committed
248 249
      cfg.w = ctx->si.w;
      cfg.h = ctx->si.h;
250 251 252 253
      ctx->mmaps[i].id = vp9_mem_req_segs[i].id;
      ctx->mmaps[i].sz = vp9_mem_req_segs[i].sz;
      ctx->mmaps[i].align = vp9_mem_req_segs[i].align;
      ctx->mmaps[i].flags = vp9_mem_req_segs[i].flags;
John Koleszar's avatar
John Koleszar committed
254

John Koleszar's avatar
John Koleszar committed
255
      if (!ctx->mmaps[i].sz)
256
        ctx->mmaps[i].sz = vp9_mem_req_segs[i].calc_sz(&cfg,
John Koleszar's avatar
John Koleszar committed
257
                                                       ctx->base.init_flags);
John Koleszar's avatar
John Koleszar committed
258

259
      res = vpx_mmap_alloc(&ctx->mmaps[i]);
John Koleszar's avatar
John Koleszar committed
260 261
    }

John Koleszar's avatar
John Koleszar committed
262
    if (!res)
263
      vp9_finalize_mmaps(ctx);
John Koleszar's avatar
John Koleszar committed
264 265 266 267 268 269

    ctx->defer_alloc = 0;
  }

  /* Initialize the decoder instance on the first frame*/
  if (!res && !ctx->decoder_init) {
270
    res = vpx_validate_mmaps(&ctx->si, ctx->mmaps,
271
                             vp9_mem_req_segs, NELEMENTS(vp9_mem_req_segs),
272
                             ctx->base.init_flags);
John Koleszar's avatar
John Koleszar committed
273 274

    if (!res) {
275
      VP9D_CONFIG oxcf;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
276
      struct VP9Decompressor *optr;
John Koleszar's avatar
John Koleszar committed
277

278
      vp9_initialize_dec();
John Koleszar's avatar
John Koleszar committed
279

280 281 282
      oxcf.width = ctx->si.w;
      oxcf.height = ctx->si.h;
      oxcf.version = 9;
John Koleszar's avatar
John Koleszar committed
283
      oxcf.max_threads = ctx->cfg.threads;
284
      oxcf.inv_tile_order = ctx->invert_tile_order;
285
      optr = vp9_create_decompressor(&oxcf);
John Koleszar's avatar
John Koleszar committed
286

Dmitry Kovalev's avatar
Dmitry Kovalev committed
287 288 289 290 291
      // If postprocessing was enabled by the application and a
      // configuration has not been provided, default it.
      if (!ctx->postproc_cfg_set &&
          (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)) {
        ctx->postproc_cfg.post_proc_flag = VP8_DEBLOCK | VP8_DEMACROBLOCK;
John Koleszar's avatar
John Koleszar committed
292 293 294 295
        ctx->postproc_cfg.deblocking_level = 4;
        ctx->postproc_cfg.noise_level = 0;
      }

296
      if (!optr) {
John Koleszar's avatar
John Koleszar committed
297
        res = VPX_CODEC_ERROR;
298 299 300 301
      } else {
        VP9D_COMP *const pbi = (VP9D_COMP*)optr;
        VP9_COMMON *const cm = &pbi->common;

302 303 304
        // Set index to not initialized.
        cm->new_fb_idx = -1;

305 306 307 308 309 310 311 312 313 314 315 316 317
        if (ctx->get_ext_fb_cb != NULL && ctx->release_ext_fb_cb != NULL) {
          cm->get_fb_cb = ctx->get_ext_fb_cb;
          cm->release_fb_cb = ctx->release_ext_fb_cb;
          cm->cb_priv = ctx->ext_priv;
        } else {
          cm->get_fb_cb = vp9_get_frame_buffer;
          cm->release_fb_cb = vp9_release_frame_buffer;

          if (vp9_alloc_internal_frame_buffers(&cm->int_frame_buffers))
            vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
                               "Failed to initialize internal frame buffers");
          cm->cb_priv = &cm->int_frame_buffers;
        }
318

John Koleszar's avatar
John Koleszar committed
319
        ctx->pbi = optr;
320
      }
John Koleszar's avatar
John Koleszar committed
321 322
    }

John Koleszar's avatar
John Koleszar committed
323 324 325 326 327 328
    ctx->decoder_init = 1;
  }

  if (!res && ctx->pbi) {
    YV12_BUFFER_CONFIG sd;
    int64_t time_stamp = 0, time_end_stamp = 0;
329
    vp9_ppflags_t flags = {0};
John Koleszar's avatar
John Koleszar committed
330

John Koleszar's avatar
John Koleszar committed
331
    if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) {
332
      flags.post_proc_flag =
333
#if CONFIG_POSTPROC_VISUALIZER
Dmitry Kovalev's avatar
Dmitry Kovalev committed
334 335 336 337
          (ctx->dbg_color_ref_frame_flag ? VP9D_DEBUG_CLR_FRM_REF_BLKS : 0) |
          (ctx->dbg_color_mb_modes_flag ? VP9D_DEBUG_CLR_BLK_MODES : 0) |
          (ctx->dbg_color_b_modes_flag ? VP9D_DEBUG_CLR_BLK_MODES : 0) |
          (ctx->dbg_display_mv_flag ? VP9D_DEBUG_DRAW_MV : 0) |
338
#endif
339 340
          ctx->postproc_cfg.post_proc_flag;

Dmitry Kovalev's avatar
Dmitry Kovalev committed
341 342
      flags.deblocking_level = ctx->postproc_cfg.deblocking_level;
      flags.noise_level = ctx->postproc_cfg.noise_level;
343
#if CONFIG_POSTPROC_VISUALIZER
John Koleszar's avatar
John Koleszar committed
344 345
      flags.display_ref_frame_flag = ctx->dbg_color_ref_frame_flag;
      flags.display_mb_modes_flag = ctx->dbg_color_mb_modes_flag;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
346 347
      flags.display_b_modes_flag = ctx->dbg_color_b_modes_flag;
      flags.display_mv_flag = ctx->dbg_display_mv_flag;
348
#endif
John Koleszar's avatar
John Koleszar committed
349
    }
John Koleszar's avatar
John Koleszar committed
350

351
    if (vp9_receive_compressed_data(ctx->pbi, data_sz, data, deadline)) {
352
      VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
John Koleszar's avatar
John Koleszar committed
353 354
      res = update_error_state(ctx, &pbi->common.error);
    }
John Koleszar's avatar
John Koleszar committed
355

356 357
    if (!res && 0 == vp9_get_raw_frame(ctx->pbi, &sd, &time_stamp,
                                       &time_end_stamp, &flags)) {
358 359
      VP9D_COMP *const pbi = (VP9D_COMP*)ctx->pbi;
      VP9_COMMON *const cm = &pbi->common;
John Koleszar's avatar
John Koleszar committed
360
      yuvconfig2image(&ctx->img, &sd, user_priv);
361 362

      ctx->img.fb_priv = cm->frame_bufs[cm->new_fb_idx].raw_frame_buffer.priv;
John Koleszar's avatar
John Koleszar committed
363
      ctx->img_avail = 1;
John Koleszar's avatar
John Koleszar committed
364
    }
John Koleszar's avatar
John Koleszar committed
365
  }
John Koleszar's avatar
John Koleszar committed
366

John Koleszar's avatar
John Koleszar committed
367
  return res;
John Koleszar's avatar
John Koleszar committed
368 369
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
370 371
static void parse_superframe_index(const uint8_t *data, size_t data_sz,
                                   uint32_t sizes[8], int *count) {
John Koleszar's avatar
John Koleszar committed
372 373 374 375 376 377
  uint8_t marker;

  assert(data_sz);
  marker = data[data_sz - 1];
  *count = 0;

378
  if ((marker & 0xe0) == 0xc0) {
Johann's avatar
Johann committed
379 380 381
    const uint32_t frames = (marker & 0x7) + 1;
    const uint32_t mag = ((marker >> 3) & 0x3) + 1;
    const size_t index_sz = 2 + mag * frames;
John Koleszar's avatar
John Koleszar committed
382 383 384

    if (data_sz >= index_sz && data[data_sz - index_sz] == marker) {
      // found a valid superframe index
Johann's avatar
Johann committed
385
      uint32_t i, j;
John Koleszar's avatar
John Koleszar committed
386 387 388
      const uint8_t *x = data + data_sz - index_sz + 1;

      for (i = 0; i < frames; i++) {
Johann's avatar
Johann committed
389
        uint32_t this_sz = 0;
John Koleszar's avatar
John Koleszar committed
390 391 392 393 394 395 396 397 398 399 400

        for (j = 0; j < mag; j++)
          this_sz |= (*x++) << (j * 8);
        sizes[i] = this_sz;
      }

      *count = frames;
    }
  }
}

401 402 403 404 405 406 407
static vpx_codec_err_t vp9_decode(vpx_codec_alg_priv_t  *ctx,
                                  const uint8_t         *data,
                                  unsigned int           data_sz,
                                  void                  *user_priv,
                                  long                   deadline) {
  const uint8_t *data_start = data;
  const uint8_t *data_end = data + data_sz;
408
  vpx_codec_err_t res = VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
409 410 411
  uint32_t sizes[8];
  int frames_this_pts, frame_count = 0;

412 413
  if (data == NULL || data_sz == 0) return VPX_CODEC_INVALID_PARAM;

John Koleszar's avatar
John Koleszar committed
414
  parse_superframe_index(data, data_sz, sizes, &frames_this_pts);
415 416

  do {
John Koleszar's avatar
John Koleszar committed
417
    // Skip over the superframe index, if present
418
    if (data_sz && (*data_start & 0xe0) == 0xc0) {
John Koleszar's avatar
John Koleszar committed
419
      const uint8_t marker = *data_start;
Johann's avatar
Johann committed
420 421 422
      const uint32_t frames = (marker & 0x7) + 1;
      const uint32_t mag = ((marker >> 3) & 0x3) + 1;
      const uint32_t index_sz = 2 + mag * frames;
John Koleszar's avatar
John Koleszar committed
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446

      if (data_sz >= index_sz && data_start[index_sz - 1] == marker) {
        data_start += index_sz;
        data_sz -= index_sz;
        if (data_start < data_end)
          continue;
        else
          break;
      }
    }

    // Use the correct size for this frame, if an index is present.
    if (frames_this_pts) {
      uint32_t this_sz = sizes[frame_count];

      if (data_sz < this_sz) {
        ctx->base.err_detail = "Invalid frame size in index";
        return VPX_CODEC_CORRUPT_FRAME;
      }

      data_sz = this_sz;
      frame_count++;
    }

447 448 449 450 451 452 453 454 455 456 457 458
    res = decode_one(ctx, &data_start, data_sz, user_priv, deadline);
    assert(data_start >= data);
    assert(data_start <= data_end);

    /* Early exit if there was a decode error */
    if (res)
      break;

    /* Account for suboptimal termination by the encoder. */
    while (data_start < data_end && *data_start == 0)
      data_start++;

459
    data_sz = (unsigned int)(data_end - data_start);
460 461 462 463
  } while (data_start < data_end);
  return res;
}

464
static vpx_image_t *vp9_get_frame(vpx_codec_alg_priv_t  *ctx,
John Koleszar's avatar
John Koleszar committed
465 466 467 468 469 470 471 472 473 474
                                  vpx_codec_iter_t      *iter) {
  vpx_image_t *img = NULL;

  if (ctx->img_avail) {
    /* iter acts as a flip flop, so an image is only returned on the first
     * call to get_frame.
     */
    if (!(*iter)) {
      img = &ctx->img;
      *iter = img;
John Koleszar's avatar
John Koleszar committed
475
    }
John Koleszar's avatar
John Koleszar committed
476
  }
477
  ctx->img_avail = 0;
John Koleszar's avatar
John Koleszar committed
478

John Koleszar's avatar
John Koleszar committed
479
  return img;
John Koleszar's avatar
John Koleszar committed
480 481
}

482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
static vpx_codec_err_t vp9_set_fb_fn(
    vpx_codec_alg_priv_t *ctx,
    vpx_get_frame_buffer_cb_fn_t cb_get,
    vpx_release_frame_buffer_cb_fn_t cb_release, void *cb_priv) {
  if (cb_get == NULL || cb_release == NULL) {
    return VPX_CODEC_INVALID_PARAM;
  } else if (ctx->pbi == NULL) {
    // If the decoder has already been initialized, do not accept changes to
    // the frame buffer functions.
    ctx->get_ext_fb_cb = cb_get;
    ctx->release_ext_fb_cb = cb_release;
    ctx->ext_priv = cb_priv;
    return VPX_CODEC_OK;
  }

  return VPX_CODEC_ERROR;
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
500 501 502 503
static vpx_codec_err_t vp9_xma_get_mmap(const vpx_codec_ctx_t *ctx,
                                        vpx_codec_mmap_t *mmap,
                                        vpx_codec_iter_t *iter) {
  vpx_codec_err_t res;
504
  const mem_req_t *seg_iter = (const mem_req_t *)*iter;
John Koleszar's avatar
John Koleszar committed
505 506 507 508

  /* Get address of next segment request */
  do {
    if (!seg_iter)
509 510
      seg_iter = vp9_mem_req_segs;
    else if (seg_iter->id != VP9_SEG_MAX)
John Koleszar's avatar
John Koleszar committed
511 512 513 514
      seg_iter++;

    *iter = (vpx_codec_iter_t)seg_iter;

515
    if (seg_iter->id != VP9_SEG_MAX) {
John Koleszar's avatar
John Koleszar committed
516 517 518 519 520 521 522 523 524
      mmap->id = seg_iter->id;
      mmap->sz = seg_iter->sz;
      mmap->align = seg_iter->align;
      mmap->flags = seg_iter->flags;

      if (!seg_iter->sz)
        mmap->sz = seg_iter->calc_sz(ctx->config.dec, ctx->init_flags);

      res = VPX_CODEC_OK;
525
    } else {
John Koleszar's avatar
John Koleszar committed
526
      res = VPX_CODEC_LIST_END;
527
    }
John Koleszar's avatar
John Koleszar committed
528 529 530
  } while (!mmap->sz && res != VPX_CODEC_LIST_END);

  return res;
John Koleszar's avatar
John Koleszar committed
531 532
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
533
static vpx_codec_err_t vp9_xma_set_mmap(vpx_codec_ctx_t *ctx,
John Koleszar's avatar
John Koleszar committed
534 535 536 537 538
                                        const vpx_codec_mmap_t  *mmap) {
  vpx_codec_err_t res = VPX_CODEC_MEM_ERROR;
  int i, done;

  if (!ctx->priv) {
539
    if (mmap->id == VP9_SEG_ALG_PRIV) {
John Koleszar's avatar
John Koleszar committed
540
      if (!ctx->priv) {
541
        vp9_init_ctx(ctx, mmap);
John Koleszar's avatar
John Koleszar committed
542 543
        res = VPX_CODEC_OK;
      }
John Koleszar's avatar
John Koleszar committed
544
    }
John Koleszar's avatar
John Koleszar committed
545
  }
John Koleszar's avatar
John Koleszar committed
546

John Koleszar's avatar
John Koleszar committed
547
  done = 1;
John Koleszar's avatar
John Koleszar committed
548

John Koleszar's avatar
John Koleszar committed
549 550 551 552 553 554
  if (!res && ctx->priv->alg_priv) {
    for (i = 0; i < NELEMENTS(ctx->priv->alg_priv->mmaps); i++) {
      if (ctx->priv->alg_priv->mmaps[i].id == mmap->id)
        if (!ctx->priv->alg_priv->mmaps[i].base) {
          ctx->priv->alg_priv->mmaps[i] = *mmap;
          res = VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
555 556
        }

John Koleszar's avatar
John Koleszar committed
557
      done &= (ctx->priv->alg_priv->mmaps[i].base != NULL);
John Koleszar's avatar
John Koleszar committed
558
    }
John Koleszar's avatar
John Koleszar committed
559 560 561
  }

  if (done && !res) {
562
    vp9_finalize_mmaps(ctx->priv->alg_priv);
John Koleszar's avatar
John Koleszar committed
563
    res = ctx->iface->init(ctx, NULL);
John Koleszar's avatar
John Koleszar committed
564
  }
John Koleszar's avatar
John Koleszar committed
565

John Koleszar's avatar
John Koleszar committed
566
  return res;
John Koleszar's avatar
John Koleszar committed
567 568
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
569
static vpx_codec_err_t set_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
570
                                     va_list args) {
John Koleszar's avatar
John Koleszar committed
571
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
572

John Koleszar's avatar
John Koleszar committed
573 574 575
  if (data) {
    vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
576

John Koleszar's avatar
John Koleszar committed
577
    image2yuvconfig(&frame->img, &sd);
578 579
    return vp9_set_reference_dec(ctx->pbi,
                                 (VP9_REFFRAME)frame->frame_type, &sd);
580
  } else {
John Koleszar's avatar
John Koleszar committed
581
    return VPX_CODEC_INVALID_PARAM;
582
  }
John Koleszar's avatar
John Koleszar committed
583 584
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
585
static vpx_codec_err_t copy_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
586
                                      va_list args) {
John Koleszar's avatar
John Koleszar committed
587
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
588

John Koleszar's avatar
John Koleszar committed
589 590 591
  if (data) {
    vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
592

John Koleszar's avatar
John Koleszar committed
593
    image2yuvconfig(&frame->img, &sd);
John Koleszar's avatar
John Koleszar committed
594

John Koleszar's avatar
John Koleszar committed
595 596
    return vp9_copy_reference_dec(ctx->pbi,
                                  (VP9_REFFRAME)frame->frame_type, &sd);
597
  } else {
John Koleszar's avatar
John Koleszar committed
598
    return VPX_CODEC_INVALID_PARAM;
599
  }
John Koleszar's avatar
John Koleszar committed
600 601
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
602
static vpx_codec_err_t get_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
John Koleszar's avatar
John Koleszar committed
603 604 605 606 607 608 609 610 611 612 613 614 615 616
                                     va_list args) {
  vp9_ref_frame_t *data = va_arg(args, vp9_ref_frame_t *);

  if (data) {
    YV12_BUFFER_CONFIG* fb;

    vp9_get_reference_dec(ctx->pbi, data->idx, &fb);
    yuvconfig2image(&data->img, fb, NULL);
    return VPX_CODEC_OK;
  } else {
    return VPX_CODEC_INVALID_PARAM;
  }
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
617
static vpx_codec_err_t set_postproc(vpx_codec_alg_priv_t *ctx, int ctr_id,
618
                                    va_list args) {
619
#if CONFIG_VP9_POSTPROC
John Koleszar's avatar
John Koleszar committed
620
  vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
John Koleszar's avatar
John Koleszar committed
621

John Koleszar's avatar
John Koleszar committed
622 623 624 625
  if (data) {
    ctx->postproc_cfg_set = 1;
    ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data);
    return VPX_CODEC_OK;
626
  } else {
John Koleszar's avatar
John Koleszar committed
627
    return VPX_CODEC_INVALID_PARAM;
628
  }
John Koleszar's avatar
John Koleszar committed
629
#else
John Koleszar's avatar
John Koleszar committed
630
  return VPX_CODEC_INCAPABLE;
John Koleszar's avatar
John Koleszar committed
631 632 633
#endif
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
634
static vpx_codec_err_t set_dbg_options(vpx_codec_alg_priv_t *ctx, int ctrl_id,
635
                                       va_list args) {
636
#if CONFIG_POSTPROC_VISUALIZER && CONFIG_POSTPROC
John Koleszar's avatar
John Koleszar committed
637
  int data = va_arg(args, int);
638 639 640

#define MAP(id, var) case id: var = data; break;

John Koleszar's avatar
John Koleszar committed
641 642 643 644 645 646
  switch (ctrl_id) {
      MAP(VP8_SET_DBG_COLOR_REF_FRAME,   ctx->dbg_color_ref_frame_flag);
      MAP(VP8_SET_DBG_COLOR_MB_MODES,    ctx->dbg_color_mb_modes_flag);
      MAP(VP8_SET_DBG_COLOR_B_MODES,     ctx->dbg_color_b_modes_flag);
      MAP(VP8_SET_DBG_DISPLAY_MV,        ctx->dbg_display_mv_flag);
  }
647

John Koleszar's avatar
John Koleszar committed
648
  return VPX_CODEC_OK;
649
#else
John Koleszar's avatar
John Koleszar committed
650
  return VPX_CODEC_INCAPABLE;
651 652
#endif
}
John Koleszar's avatar
John Koleszar committed
653

654
static vpx_codec_err_t get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
655
                                            int ctrl_id, va_list args) {
John Koleszar's avatar
John Koleszar committed
656
  int *update_info = va_arg(args, int *);
657
  VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
658

John Koleszar's avatar
John Koleszar committed
659
  if (update_info) {
660
    *update_info = pbi->refresh_frame_flags;
661

John Koleszar's avatar
John Koleszar committed
662
    return VPX_CODEC_OK;
663
  } else {
John Koleszar's avatar
John Koleszar committed
664
    return VPX_CODEC_INVALID_PARAM;
665
  }
666 667 668
}


669
static vpx_codec_err_t get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
670
                                           int ctrl_id, va_list args) {
John Koleszar's avatar
John Koleszar committed
671
  int *corrupted = va_arg(args, int *);
672

John Koleszar's avatar
John Koleszar committed
673
  if (corrupted) {
674
    VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
Yaowu Xu's avatar
Yaowu Xu committed
675 676 677 678
    if (pbi)
      *corrupted = pbi->common.frame_to_show->corrupted;
    else
      return VPX_CODEC_ERROR;
John Koleszar's avatar
John Koleszar committed
679
    return VPX_CODEC_OK;
680
  } else {
John Koleszar's avatar
John Koleszar committed
681
    return VPX_CODEC_INVALID_PARAM;
682
  }
683 684
}

685
static vpx_codec_err_t get_display_size(vpx_codec_alg_priv_t *ctx,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
686
                                        int ctrl_id, va_list args) {
687 688 689
  int *const display_size = va_arg(args, int *);

  if (display_size) {
690
    const VP9D_COMP *const pbi = (VP9D_COMP*)ctx->pbi;
691 692 693 694 695 696 697 698 699 700 701 702
    if (pbi) {
      display_size[0] = pbi->common.display_width;
      display_size[1] = pbi->common.display_height;
    } else {
      return VPX_CODEC_ERROR;
    }
    return VPX_CODEC_OK;
  } else {
    return VPX_CODEC_INVALID_PARAM;
  }
}

703 704 705 706 707 708 709
static vpx_codec_err_t set_invert_tile_order(vpx_codec_alg_priv_t *ctx,
                                             int ctr_id,
                                             va_list args) {
  ctx->invert_tile_order = va_arg(args, int);
  return VPX_CODEC_OK;
}

710
static vpx_codec_ctrl_fn_map_t ctf_maps[] = {
711 712 713 714 715 716 717 718 719
  {VP8_SET_REFERENCE,             set_reference},
  {VP8_COPY_REFERENCE,            copy_reference},
  {VP8_SET_POSTPROC,              set_postproc},
  {VP8_SET_DBG_COLOR_REF_FRAME,   set_dbg_options},
  {VP8_SET_DBG_COLOR_MB_MODES,    set_dbg_options},
  {VP8_SET_DBG_COLOR_B_MODES,     set_dbg_options},
  {VP8_SET_DBG_DISPLAY_MV,        set_dbg_options},
  {VP8D_GET_LAST_REF_UPDATES,     get_last_ref_updates},
  {VP8D_GET_FRAME_CORRUPTED,      get_frame_corrupted},
John Koleszar's avatar
John Koleszar committed
720
  {VP9_GET_REFERENCE,             get_reference},
721
  {VP9D_GET_DISPLAY_SIZE,         get_display_size},
722
  {VP9_INVERT_TILE_DECODE_ORDER,  set_invert_tile_order},
John Koleszar's avatar
John Koleszar committed
723
  { -1, NULL},
John Koleszar's avatar
John Koleszar committed
724 725 726 727 728 729
};


#ifndef VERSION_STRING
#define VERSION_STRING
#endif
730 731
CODEC_INTERFACE(vpx_codec_vp9_dx) = {
  "WebM Project VP9 Decoder" VERSION_STRING,
John Koleszar's avatar
John Koleszar committed
732
  VPX_CODEC_INTERNAL_ABI_VERSION,
733 734
  VPX_CODEC_CAP_DECODER | VP9_CAP_POSTPROC |
      VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER,
John Koleszar's avatar
John Koleszar committed
735
  /* vpx_codec_caps_t          caps; */
736 737
  vp9_init,         /* vpx_codec_init_fn_t       init; */
  vp9_destroy,      /* vpx_codec_destroy_fn_t    destroy; */
738
  ctf_maps,         /* vpx_codec_ctrl_fn_map_t  *ctrl_maps; */
739 740
  vp9_xma_get_mmap, /* vpx_codec_get_mmap_fn_t   get_mmap; */
  vp9_xma_set_mmap, /* vpx_codec_set_mmap_fn_t   set_mmap; */
741
  { // NOLINT
742 743
    vp9_peek_si,      /* vpx_codec_peek_si_fn_t    peek_si; */
    vp9_get_si,       /* vpx_codec_get_si_fn_t     get_si; */
744
    vp9_decode,       /* vpx_codec_decode_fn_t     decode; */
745
    vp9_get_frame,    /* vpx_codec_frame_get_fn_t  frame_get; */
746
    vp9_set_fb_fn,    /* vpx_codec_set_fb_fn_t     set_fb_fn; */
John Koleszar's avatar
John Koleszar committed
747
  },
748
  { // NOLINT
John Koleszar's avatar
John Koleszar committed
749 750 751 752 753 754 755 756
    /* encoder functions */
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED
  }
John Koleszar's avatar
John Koleszar committed
757
};