vp9_dx_iface.c 21.4 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 20 21
#include "vp9/decoder/vp9_onyxd.h"
#include "vp9/decoder/vp9_onyxd_int.h"
#include "vp9/decoder/vp9_read_bit_buffer.h"
22
#include "vp9/vp9_iface_common.h"
John Koleszar's avatar
John Koleszar committed
23

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

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

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

37 38 39
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
40 41
};

John Koleszar's avatar
John Koleszar committed
42 43
struct vpx_codec_alg_priv {
  vpx_codec_priv_t        base;
44
  vpx_codec_mmap_t        mmaps[NELEMENTS(vp9_mem_req_segs) - 1];
John Koleszar's avatar
John Koleszar committed
45
  vpx_codec_dec_cfg_t     cfg;
46
  vp9_stream_info_t       si;
John Koleszar's avatar
John Koleszar committed
47 48
  int                     defer_alloc;
  int                     decoder_init;
49
  VP9D_PTR                pbi;
John Koleszar's avatar
John Koleszar committed
50 51
  int                     postproc_cfg_set;
  vp8_postproc_cfg_t      postproc_cfg;
52
#if CONFIG_POSTPROC_VISUALIZER
John Koleszar's avatar
John Koleszar committed
53 54 55 56 57
  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;
58
#endif
John Koleszar's avatar
John Koleszar committed
59 60 61
  vpx_image_t             img;
  int                     img_setup;
  int                     img_avail;
62
  int                     invert_tile_order;
John Koleszar's avatar
John Koleszar committed
63 64
};

65 66
static unsigned long priv_sz(const vpx_codec_dec_cfg_t *si,
                             vpx_codec_flags_t flags) {
John Koleszar's avatar
John Koleszar committed
67 68 69 70 71 72 73
  /* 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
74 75
}

76
static void vp9_init_ctx(vpx_codec_ctx_t *ctx, const vpx_codec_mmap_t *mmap) {
John Koleszar's avatar
John Koleszar committed
77
  int i;
John Koleszar's avatar
John Koleszar committed
78

John Koleszar's avatar
John Koleszar committed
79 80 81 82
  ctx->priv = mmap->base;
  ctx->priv->sz = sizeof(*ctx->priv);
  ctx->priv->iface = ctx->iface;
  ctx->priv->alg_priv = mmap->base;
John Koleszar's avatar
John Koleszar committed
83

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

John Koleszar's avatar
John Koleszar committed
87 88 89
  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
90

John Koleszar's avatar
John Koleszar committed
91 92 93 94 95
  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
96 97
}

98
static void vp9_finalize_mmaps(vpx_codec_alg_priv_t *ctx) {
John Koleszar's avatar
John Koleszar committed
99
  /* nothing to clean up */
John Koleszar's avatar
John Koleszar committed
100 101
}

102
static vpx_codec_err_t vp9_init(vpx_codec_ctx_t *ctx,
John Koleszar's avatar
John Koleszar committed
103
                                vpx_codec_priv_enc_mr_cfg_t *data) {
104
  vpx_codec_err_t res = VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
105

106 107 108
  // 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
109 110
  if (!ctx->priv) {
    vpx_codec_mmap_t mmap;
John Koleszar's avatar
John Koleszar committed
111

112
    mmap.id = vp9_mem_req_segs[0].id;
John Koleszar's avatar
John Koleszar committed
113
    mmap.sz = sizeof(vpx_codec_alg_priv_t);
114 115
    mmap.align = vp9_mem_req_segs[0].align;
    mmap.flags = vp9_mem_req_segs[0].flags;
John Koleszar's avatar
John Koleszar committed
116

117
    res = vpx_mmap_alloc(&mmap);
John Koleszar's avatar
John Koleszar committed
118
    if (!res) {
119
      vp9_init_ctx(ctx, &mmap);
John Koleszar's avatar
John Koleszar committed
120

John Koleszar's avatar
John Koleszar committed
121
      ctx->priv->alg_priv->defer_alloc = 1;
John Koleszar's avatar
John Koleszar committed
122
    }
John Koleszar's avatar
John Koleszar committed
123
  }
John Koleszar's avatar
John Koleszar committed
124

John Koleszar's avatar
John Koleszar committed
125
  return res;
John Koleszar's avatar
John Koleszar committed
126 127
}

128
static vpx_codec_err_t vp9_destroy(vpx_codec_alg_priv_t *ctx) {
John Koleszar's avatar
John Koleszar committed
129
  int i;
John Koleszar's avatar
John Koleszar committed
130

131
  vp9_remove_decompressor(ctx->pbi);
John Koleszar's avatar
John Koleszar committed
132

John Koleszar's avatar
John Koleszar committed
133 134 135 136
  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
137

John Koleszar's avatar
John Koleszar committed
138
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
139 140
}

141
static vpx_codec_err_t vp9_peek_si(const uint8_t *data, unsigned int data_sz,
John Koleszar's avatar
John Koleszar committed
142
                                   vpx_codec_stream_info_t *si) {
143
  if (data_sz <= 8) return VPX_CODEC_UNSUP_BITSTREAM;
144 145 146 147
  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
148

149 150 151 152
  {
    struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
    const int frame_marker = vp9_rb_read_literal(&rb, 2);
    const int version = vp9_rb_read_bit(&rb) | (vp9_rb_read_bit(&rb) << 1);
153 154
    if (frame_marker != VP9_FRAME_MARKER)
      return VPX_CODEC_UNSUP_BITSTREAM;
155 156 157
#if CONFIG_NON420
    if (version > 1) return VPX_CODEC_UNSUP_BITSTREAM;
#else
158
    if (version != 0) return VPX_CODEC_UNSUP_BITSTREAM;
159 160 161 162 163
#endif

    if (vp9_rb_read_bit(&rb)) {  // show an existing frame
      return VPX_CODEC_OK;
    }
164

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

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

173 174 175
      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) {
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
        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;
198
    }
John Koleszar's avatar
John Koleszar committed
199 200
  }

201
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
202 203
}

204
static vpx_codec_err_t vp9_get_si(vpx_codec_alg_priv_t    *ctx,
John Koleszar's avatar
John Koleszar committed
205
                                  vpx_codec_stream_info_t *si) {
206 207 208
  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
209 210
  memcpy(si, &ctx->si, sz);
  si->sz = sz;
John Koleszar's avatar
John Koleszar committed
211

John Koleszar's avatar
John Koleszar committed
212
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
213 214 215
}


216 217 218 219
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
220

221
  return error->error_code;
John Koleszar's avatar
John Koleszar committed
222 223
}

224 225 226
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
227
  vpx_codec_err_t res = VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
228

John Koleszar's avatar
John Koleszar committed
229
  ctx->img_avail = 0;
John Koleszar's avatar
John Koleszar committed
230

John Koleszar's avatar
John Koleszar committed
231 232 233 234 235
  /* 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)
236
    res = ctx->base.iface->dec.peek_si(*data, data_sz, &ctx->si);
John Koleszar's avatar
John Koleszar committed
237 238


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

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

John Koleszar's avatar
John Koleszar committed
246 247
      cfg.w = ctx->si.w;
      cfg.h = ctx->si.h;
248 249 250 251
      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
252

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

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

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

    ctx->defer_alloc = 0;
  }

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

    if (!res) {
273 274
      VP9D_CONFIG oxcf;
      VP9D_PTR optr;
John Koleszar's avatar
John Koleszar committed
275

276
      vp9_initialize_dec();
John Koleszar's avatar
John Koleszar committed
277

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

286 287 288 289 290
      // 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
291 292 293 294
        ctx->postproc_cfg.deblocking_level = 4;
        ctx->postproc_cfg.noise_level = 0;
      }

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

        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;

John Koleszar's avatar
John Koleszar committed
309
        ctx->pbi = optr;
310
      }
John Koleszar's avatar
John Koleszar committed
311 312
    }

John Koleszar's avatar
John Koleszar committed
313 314 315 316 317 318
    ctx->decoder_init = 1;
  }

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

John Koleszar's avatar
John Koleszar committed
321
    if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) {
322
      flags.post_proc_flag =
323
#if CONFIG_POSTPROC_VISUALIZER
324 325 326 327
          (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) |
328
#endif
329 330
          ctx->postproc_cfg.post_proc_flag;

331 332
      flags.deblocking_level = ctx->postproc_cfg.deblocking_level;
      flags.noise_level = ctx->postproc_cfg.noise_level;
333
#if CONFIG_POSTPROC_VISUALIZER
John Koleszar's avatar
John Koleszar committed
334 335
      flags.display_ref_frame_flag = ctx->dbg_color_ref_frame_flag;
      flags.display_mb_modes_flag = ctx->dbg_color_mb_modes_flag;
336 337
      flags.display_b_modes_flag = ctx->dbg_color_b_modes_flag;
      flags.display_mv_flag = ctx->dbg_display_mv_flag;
338
#endif
John Koleszar's avatar
John Koleszar committed
339
    }
John Koleszar's avatar
John Koleszar committed
340

341
    if (vp9_receive_compressed_data(ctx->pbi, data_sz, data, deadline)) {
342
      VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
John Koleszar's avatar
John Koleszar committed
343 344
      res = update_error_state(ctx, &pbi->common.error);
    }
John Koleszar's avatar
John Koleszar committed
345

346 347
    if (!res && 0 == vp9_get_raw_frame(ctx->pbi, &sd, &time_stamp,
                                       &time_end_stamp, &flags)) {
John Koleszar's avatar
John Koleszar committed
348 349
      yuvconfig2image(&ctx->img, &sd, user_priv);
      ctx->img_avail = 1;
John Koleszar's avatar
John Koleszar committed
350
    }
John Koleszar's avatar
John Koleszar committed
351
  }
John Koleszar's avatar
John Koleszar committed
352

John Koleszar's avatar
John Koleszar committed
353
  return res;
John Koleszar's avatar
John Koleszar committed
354 355
}

356 357
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
358 359 360 361 362 363
  uint8_t marker;

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

364
  if ((marker & 0xe0) == 0xc0) {
Johann's avatar
Johann committed
365 366 367
    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
368 369 370

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

      for (i = 0; i < frames; i++) {
Johann's avatar
Johann committed
375
        uint32_t this_sz = 0;
John Koleszar's avatar
John Koleszar committed
376 377 378 379 380 381 382 383 384 385 386

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

      *count = frames;
    }
  }
}

387 388 389 390 391 392 393
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;
394
  vpx_codec_err_t res = 0;
John Koleszar's avatar
John Koleszar committed
395 396 397
  uint32_t sizes[8];
  int frames_this_pts, frame_count = 0;

398 399
  if (data == NULL || data_sz == 0) return VPX_CODEC_INVALID_PARAM;

John Koleszar's avatar
John Koleszar committed
400
  parse_superframe_index(data, data_sz, sizes, &frames_this_pts);
401 402

  do {
John Koleszar's avatar
John Koleszar committed
403
    // Skip over the superframe index, if present
404
    if (data_sz && (*data_start & 0xe0) == 0xc0) {
John Koleszar's avatar
John Koleszar committed
405
      const uint8_t marker = *data_start;
Johann's avatar
Johann committed
406 407 408
      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
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432

      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++;
    }

433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
    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++;

    data_sz = data_end - data_start;
  } while (data_start < data_end);
  return res;
}

450
static vpx_image_t *vp9_get_frame(vpx_codec_alg_priv_t  *ctx,
John Koleszar's avatar
John Koleszar committed
451 452 453 454 455 456 457 458 459 460
                                  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
461
    }
John Koleszar's avatar
John Koleszar committed
462
  }
463
  ctx->img_avail = 0;
John Koleszar's avatar
John Koleszar committed
464

John Koleszar's avatar
John Koleszar committed
465
  return img;
John Koleszar's avatar
John Koleszar committed
466 467
}

468 469 470 471 472
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;
  const mem_req_t *seg_iter = *iter;
John Koleszar's avatar
John Koleszar committed
473 474 475 476

  /* Get address of next segment request */
  do {
    if (!seg_iter)
477 478
      seg_iter = vp9_mem_req_segs;
    else if (seg_iter->id != VP9_SEG_MAX)
John Koleszar's avatar
John Koleszar committed
479 480 481 482
      seg_iter++;

    *iter = (vpx_codec_iter_t)seg_iter;

483
    if (seg_iter->id != VP9_SEG_MAX) {
John Koleszar's avatar
John Koleszar committed
484 485 486 487 488 489 490 491 492
      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;
493
    } else {
John Koleszar's avatar
John Koleszar committed
494
      res = VPX_CODEC_LIST_END;
495
    }
John Koleszar's avatar
John Koleszar committed
496 497 498
  } while (!mmap->sz && res != VPX_CODEC_LIST_END);

  return res;
John Koleszar's avatar
John Koleszar committed
499 500
}

501
static vpx_codec_err_t vp9_xma_set_mmap(vpx_codec_ctx_t *ctx,
John Koleszar's avatar
John Koleszar committed
502 503 504 505 506
                                        const vpx_codec_mmap_t  *mmap) {
  vpx_codec_err_t res = VPX_CODEC_MEM_ERROR;
  int i, done;

  if (!ctx->priv) {
507
    if (mmap->id == VP9_SEG_ALG_PRIV) {
John Koleszar's avatar
John Koleszar committed
508
      if (!ctx->priv) {
509
        vp9_init_ctx(ctx, mmap);
John Koleszar's avatar
John Koleszar committed
510 511
        res = VPX_CODEC_OK;
      }
John Koleszar's avatar
John Koleszar committed
512
    }
John Koleszar's avatar
John Koleszar committed
513
  }
John Koleszar's avatar
John Koleszar committed
514

John Koleszar's avatar
John Koleszar committed
515
  done = 1;
John Koleszar's avatar
John Koleszar committed
516

John Koleszar's avatar
John Koleszar committed
517 518 519 520 521 522
  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
523 524
        }

John Koleszar's avatar
John Koleszar committed
525
      done &= (ctx->priv->alg_priv->mmaps[i].base != NULL);
John Koleszar's avatar
John Koleszar committed
526
    }
John Koleszar's avatar
John Koleszar committed
527 528 529
  }

  if (done && !res) {
530
    vp9_finalize_mmaps(ctx->priv->alg_priv);
John Koleszar's avatar
John Koleszar committed
531
    res = ctx->iface->init(ctx, NULL);
John Koleszar's avatar
John Koleszar committed
532
  }
John Koleszar's avatar
John Koleszar committed
533

John Koleszar's avatar
John Koleszar committed
534
  return res;
John Koleszar's avatar
John Koleszar committed
535 536
}

537
static vpx_codec_err_t set_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
538
                                     va_list args) {
John Koleszar's avatar
John Koleszar committed
539
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
540

John Koleszar's avatar
John Koleszar committed
541 542 543
  if (data) {
    vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
544

John Koleszar's avatar
John Koleszar committed
545
    image2yuvconfig(&frame->img, &sd);
546 547
    return vp9_set_reference_dec(ctx->pbi,
                                 (VP9_REFFRAME)frame->frame_type, &sd);
548
  } else {
John Koleszar's avatar
John Koleszar committed
549
    return VPX_CODEC_INVALID_PARAM;
550
  }
John Koleszar's avatar
John Koleszar committed
551 552
}

553
static vpx_codec_err_t copy_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
554
                                      va_list args) {
John Koleszar's avatar
John Koleszar committed
555
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
556

John Koleszar's avatar
John Koleszar committed
557 558 559
  if (data) {
    vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
560

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

563 564
    return vp9_copy_reference_dec(ctx->pbi,
                                  (VP9_REFFRAME)frame->frame_type, &sd);
565
  } else {
John Koleszar's avatar
John Koleszar committed
566
    return VPX_CODEC_INVALID_PARAM;
567
  }
John Koleszar's avatar
John Koleszar committed
568 569
}

570
static vpx_codec_err_t get_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
571 572 573 574 575 576 577 578 579 580 581 582 583 584
                                     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;
  }
}

585
static vpx_codec_err_t set_postproc(vpx_codec_alg_priv_t *ctx, int ctr_id,
586
                                    va_list args) {
587
#if CONFIG_VP9_POSTPROC
John Koleszar's avatar
John Koleszar committed
588
  vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
John Koleszar's avatar
John Koleszar committed
589

John Koleszar's avatar
John Koleszar committed
590 591 592 593
  if (data) {
    ctx->postproc_cfg_set = 1;
    ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data);
    return VPX_CODEC_OK;
594
  } else {
John Koleszar's avatar
John Koleszar committed
595
    return VPX_CODEC_INVALID_PARAM;
596
  }
John Koleszar's avatar
John Koleszar committed
597
#else
John Koleszar's avatar
John Koleszar committed
598
  return VPX_CODEC_INCAPABLE;
John Koleszar's avatar
John Koleszar committed
599 600 601
#endif
}

602
static vpx_codec_err_t set_dbg_options(vpx_codec_alg_priv_t *ctx, int ctrl_id,
603
                                       va_list args) {
604
#if CONFIG_POSTPROC_VISUALIZER && CONFIG_POSTPROC
John Koleszar's avatar
John Koleszar committed
605
  int data = va_arg(args, int);
606 607 608

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

John Koleszar's avatar
John Koleszar committed
609 610 611 612 613 614
  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);
  }
615

John Koleszar's avatar
John Koleszar committed
616
  return VPX_CODEC_OK;
617
#else
John Koleszar's avatar
John Koleszar committed
618
  return VPX_CODEC_INCAPABLE;
619 620
#endif
}
John Koleszar's avatar
John Koleszar committed
621

622
static vpx_codec_err_t get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
623
                                            int ctrl_id, va_list args) {
John Koleszar's avatar
John Koleszar committed
624
  int *update_info = va_arg(args, int *);
625
  VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
626

John Koleszar's avatar
John Koleszar committed
627
  if (update_info) {
628
    *update_info = pbi->refresh_frame_flags;
629

John Koleszar's avatar
John Koleszar committed
630
    return VPX_CODEC_OK;
631
  } else {
John Koleszar's avatar
John Koleszar committed
632
    return VPX_CODEC_INVALID_PARAM;
633
  }
634 635 636
}


637
static vpx_codec_err_t get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
638
                                           int ctrl_id, va_list args) {
John Koleszar's avatar
John Koleszar committed
639
  int *corrupted = va_arg(args, int *);
640

John Koleszar's avatar
John Koleszar committed
641
  if (corrupted) {
642
    VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
643 644 645 646
    if (pbi)
      *corrupted = pbi->common.frame_to_show->corrupted;
    else
      return VPX_CODEC_ERROR;
John Koleszar's avatar
John Koleszar committed
647
    return VPX_CODEC_OK;
648
  } else {
John Koleszar's avatar
John Koleszar committed
649
    return VPX_CODEC_INVALID_PARAM;
650
  }
651 652
}

653
static vpx_codec_err_t get_display_size(vpx_codec_alg_priv_t *ctx,
654
                                        int ctrl_id, va_list args) {
655 656 657
  int *const display_size = va_arg(args, int *);

  if (display_size) {
658
    const VP9D_COMP *const pbi = (VP9D_COMP*)ctx->pbi;
659 660 661 662 663 664 665 666 667 668 669 670
    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;
  }
}

671 672 673 674 675 676 677
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;
}

678
static vpx_codec_ctrl_fn_map_t ctf_maps[] = {
679 680 681 682 683 684 685 686 687
  {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},
688
  {VP9_GET_REFERENCE,             get_reference},
689
  {VP9D_GET_DISPLAY_SIZE,         get_display_size},
690
  {VP9_INVERT_TILE_DECODE_ORDER,  set_invert_tile_order},
John Koleszar's avatar
John Koleszar committed
691
  { -1, NULL},
John Koleszar's avatar
John Koleszar committed
692 693 694 695 696 697
};


#ifndef VERSION_STRING
#define VERSION_STRING
#endif
698 699
CODEC_INTERFACE(vpx_codec_vp9_dx) = {
  "WebM Project VP9 Decoder" VERSION_STRING,
John Koleszar's avatar
John Koleszar committed
700
  VPX_CODEC_INTERNAL_ABI_VERSION,
701
  VPX_CODEC_CAP_DECODER | VP9_CAP_POSTPROC,
John Koleszar's avatar
John Koleszar committed
702
  /* vpx_codec_caps_t          caps; */
703 704
  vp9_init,         /* vpx_codec_init_fn_t       init; */
  vp9_destroy,      /* vpx_codec_destroy_fn_t    destroy; */
705
  ctf_maps,         /* vpx_codec_ctrl_fn_map_t  *ctrl_maps; */
706 707
  vp9_xma_get_mmap, /* vpx_codec_get_mmap_fn_t   get_mmap; */
  vp9_xma_set_mmap, /* vpx_codec_set_mmap_fn_t   set_mmap; */
708
  { // NOLINT
709 710
    vp9_peek_si,      /* vpx_codec_peek_si_fn_t    peek_si; */
    vp9_get_si,       /* vpx_codec_get_si_fn_t     get_si; */
711
    vp9_decode,       /* vpx_codec_decode_fn_t     decode; */
712
    vp9_get_frame,    /* vpx_codec_frame_get_fn_t  frame_get; */
John Koleszar's avatar
John Koleszar committed
713
  },
714
  { // NOLINT
John Koleszar's avatar
John Koleszar committed
715 716 717 718 719 720 721 722
    /* encoder functions */
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED
  }
John Koleszar's avatar
John Koleszar committed
723
};