vp9_dx_iface.c 20.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
 */

#include <stdlib.h>
#include <string.h>
13

14
#include "./vpx_version.h"
15 16 17 18 19

#include "vpx/internal/vpx_codec_internal.h"
#include "vpx/vp8dx.h"
#include "vpx/vpx_decoder.h"

20
#include "vp9/common/vp9_frame_buffers.h"
21

22
#include "vp9/decoder/vp9_decoder.h"
23
#include "vp9/decoder/vp9_read_bit_buffer.h"
24

John Koleszar's avatar
John Koleszar committed
25
#include "vp9/vp9_iface_common.h"
John Koleszar's avatar
John Koleszar committed
26

27
#define VP9_CAP_POSTPROC (CONFIG_VP9_POSTPROC ? VPX_CODEC_CAP_POSTPROC : 0)
28 29

typedef vpx_codec_stream_info_t vp9_stream_info_t;
John Koleszar's avatar
John Koleszar committed
30

John Koleszar's avatar
John Koleszar committed
31 32 33
struct vpx_codec_alg_priv {
  vpx_codec_priv_t        base;
  vpx_codec_dec_cfg_t     cfg;
34
  vp9_stream_info_t       si;
35
  struct VP9Decoder *pbi;
John Koleszar's avatar
John Koleszar committed
36 37
  int                     postproc_cfg_set;
  vp8_postproc_cfg_t      postproc_cfg;
38 39
  vpx_decrypt_cb          decrypt_cb;
  void                   *decrypt_state;
John Koleszar's avatar
John Koleszar committed
40
  vpx_image_t             img;
41
  int                     invert_tile_order;
42
  int                     frame_parallel_decode;  // frame-based threading.
43
  int                     last_show_frame;  // Index of last output frame.
44 45 46 47 48

  // 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
49 50
};

51
static vpx_codec_err_t decoder_init(vpx_codec_ctx_t *ctx,
52
                                    vpx_codec_priv_enc_mr_cfg_t *data) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
53 54 55
  // 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.
56 57
  (void)data;

John Koleszar's avatar
John Koleszar committed
58
  if (!ctx->priv) {
59 60
    vpx_codec_alg_priv_t *alg_priv = vpx_memalign(32, sizeof(*alg_priv));
    if (alg_priv == NULL)
61 62
      return VPX_CODEC_MEM_ERROR;

63 64 65
    vp9_zero(*alg_priv);

    ctx->priv = (vpx_codec_priv_t *)alg_priv;
66 67
    ctx->priv->sz = sizeof(*ctx->priv);
    ctx->priv->iface = ctx->iface;
68
    ctx->priv->alg_priv = alg_priv;
69 70
    ctx->priv->alg_priv->si.sz = sizeof(ctx->priv->alg_priv->si);
    ctx->priv->init_flags = ctx->init_flags;
71 72 73 74 75
    ctx->priv->alg_priv->frame_parallel_decode =
        (ctx->init_flags & VPX_CODEC_USE_FRAME_THREADING);

    // Disable frame parallel decoding for now.
    ctx->priv->alg_priv->frame_parallel_decode = 0;
76 77 78 79 80

    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
81
    }
John Koleszar's avatar
John Koleszar committed
82
  }
John Koleszar's avatar
John Koleszar committed
83

84
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
85 86
}

87 88 89 90 91
static vpx_codec_err_t decoder_destroy(vpx_codec_alg_priv_t *ctx) {
  if (ctx->pbi) {
    vp9_decoder_remove(ctx->pbi);
    ctx->pbi = NULL;
  }
John Koleszar's avatar
John Koleszar committed
92

93 94
  vpx_free(ctx);

John Koleszar's avatar
John Koleszar committed
95
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
96 97
}

98 99 100 101 102 103 104
static vpx_codec_err_t decoder_peek_si_internal(const uint8_t *data,
                                                unsigned int data_sz,
                                                vpx_codec_stream_info_t *si,
                                                vpx_decrypt_cb decrypt_cb,
                                                void *decrypt_state) {
  uint8_t clear_buffer[9];

105 106 107 108 109
  if (data_sz <= 8)
    return VPX_CODEC_UNSUP_BITSTREAM;

  if (data + data_sz <= data)
    return VPX_CODEC_INVALID_PARAM;
110 111 112

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

114 115 116 117 118 119
  if (decrypt_cb) {
    data_sz = MIN(sizeof(clear_buffer), data_sz);
    decrypt_cb(decrypt_state, data, clear_buffer, data_sz);
    data = clear_buffer;
  }

120 121 122
  {
    struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
    const int frame_marker = vp9_rb_read_literal(&rb, 2);
123 124 125
    const int version = vp9_rb_read_bit(&rb);
    (void) vp9_rb_read_bit(&rb);  // unused version bit

126 127
    if (frame_marker != VP9_FRAME_MARKER)
      return VPX_CODEC_UNSUP_BITSTREAM;
128 129 130 131 132
    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
133

134
    si->is_kf = !vp9_rb_read_bit(&rb);
James Zern's avatar
James Zern committed
135
    if (si->is_kf) {
136 137
      const int sRGB = 7;
      int colorspace;
John Koleszar's avatar
John Koleszar committed
138

139 140
      rb.bit_offset += 1;  // show frame
      rb.bit_offset += 1;  // error resilient
John Koleszar's avatar
John Koleszar committed
141

142 143 144
      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) {
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
        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
167
    }
John Koleszar's avatar
John Koleszar committed
168 169
  }

170
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
171 172
}

173 174 175 176 177 178
static vpx_codec_err_t decoder_peek_si(const uint8_t *data,
                                       unsigned int data_sz,
                                       vpx_codec_stream_info_t *si) {
  return decoder_peek_si_internal(data, data_sz, si, NULL, NULL);
}

179 180
static vpx_codec_err_t decoder_get_si(vpx_codec_alg_priv_t *ctx,
                                      vpx_codec_stream_info_t *si) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
181 182 183
  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
184
  memcpy(si, &ctx->si, sz);
185
  si->sz = (unsigned int)sz;
John Koleszar's avatar
John Koleszar committed
186

John Koleszar's avatar
John Koleszar committed
187
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
188 189
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
190 191 192 193
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
194

Dmitry Kovalev's avatar
Dmitry Kovalev committed
195
  return error->error_code;
John Koleszar's avatar
John Koleszar committed
196 197
}

198 199 200
static void init_buffer_callbacks(vpx_codec_alg_priv_t *ctx) {
  VP9_COMMON *const cm = &ctx->pbi->common;

201
  cm->new_fb_idx = -1;
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234

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

static void set_default_ppflags(vp8_postproc_cfg_t *cfg) {
  cfg->post_proc_flag = VP8_DEBLOCK | VP8_DEMACROBLOCK;
  cfg->deblocking_level = 4;
  cfg->noise_level = 0;
}

static void set_ppflags(const vpx_codec_alg_priv_t *ctx,
                        vp9_ppflags_t *flags) {
  flags->post_proc_flag =
      ctx->postproc_cfg.post_proc_flag;

  flags->deblocking_level = ctx->postproc_cfg.deblocking_level;
  flags->noise_level = ctx->postproc_cfg.noise_level;
}

static void init_decoder(vpx_codec_alg_priv_t *ctx) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
235
  ctx->pbi = vp9_decoder_create();
236 237 238
  if (ctx->pbi == NULL)
    return;

Dmitry Kovalev's avatar
Dmitry Kovalev committed
239 240
  ctx->pbi->max_threads = ctx->cfg.threads;
  ctx->pbi->inv_tile_order = ctx->invert_tile_order;
241
  ctx->pbi->frame_parallel_decode = ctx->frame_parallel_decode;
242
  ctx->last_show_frame = -1;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
243

244 245 246 247 248 249 250 251 252
  // 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))
    set_default_ppflags(&ctx->postproc_cfg);

  init_buffer_callbacks(ctx);
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
253 254 255
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) {
256
  vp9_ppflags_t flags = {0};
257
  VP9_COMMON *cm = NULL;
John Koleszar's avatar
John Koleszar committed
258

259 260
  (void)deadline;

261 262 263
  // 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.
264 265
  if (!ctx->si.h) {
    const vpx_codec_err_t res =
266 267
        decoder_peek_si_internal(*data, data_sz, &ctx->si, ctx->decrypt_cb,
                                 ctx->decrypt_state);
268 269
    if (res != VPX_CODEC_OK)
      return res;
270 271 272

    if (!ctx->si.is_kf)
      return VPX_CODEC_ERROR;
273
  }
274

275
  // Initialize the decoder instance on the first frame
276
  if (ctx->pbi == NULL) {
277 278 279
    init_decoder(ctx);
    if (ctx->pbi == NULL)
      return VPX_CODEC_ERROR;
John Koleszar's avatar
John Koleszar committed
280 281
  }

282 283 284 285 286
  // Set these even if already initialized.  The caller may have changed the
  // decrypt config between frames.
  ctx->pbi->decrypt_cb = ctx->decrypt_cb;
  ctx->pbi->decrypt_state = ctx->decrypt_state;

287
  cm = &ctx->pbi->common;
John Koleszar's avatar
John Koleszar committed
288

289
  if (vp9_receive_compressed_data(ctx->pbi, data_sz, data))
290
    return update_error_state(ctx, &cm->error);
John Koleszar's avatar
John Koleszar committed
291

292 293
  if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)
    set_ppflags(ctx, &flags);
John Koleszar's avatar
John Koleszar committed
294

295
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
296 297
}

298 299 300 301 302 303 304 305 306 307 308
static INLINE uint8_t read_marker(vpx_decrypt_cb decrypt_cb,
                                  void *decrypt_state,
                                  const uint8_t *data) {
  if (decrypt_cb) {
    uint8_t marker;
    decrypt_cb(decrypt_state, data, &marker, 1);
    return marker;
  }
  return *data;
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
309
static void parse_superframe_index(const uint8_t *data, size_t data_sz,
310 311 312
                                   uint32_t sizes[8], int *count,
                                   vpx_decrypt_cb decrypt_cb,
                                   void *decrypt_state) {
John Koleszar's avatar
John Koleszar committed
313 314 315
  uint8_t marker;

  assert(data_sz);
316
  marker = read_marker(decrypt_cb, decrypt_state, data + data_sz - 1);
John Koleszar's avatar
John Koleszar committed
317 318
  *count = 0;

319
  if ((marker & 0xe0) == 0xc0) {
Johann's avatar
Johann committed
320 321 322
    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
323

324 325 326 327
    uint8_t marker2 = read_marker(decrypt_cb, decrypt_state,
                                  data + data_sz - index_sz);

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

332 333 334 335 336 337 338 339
      // frames has a maximum of 8 and mag has a maximum of 4.
      uint8_t clear_buffer[32];
      assert(sizeof(clear_buffer) >= frames * mag);
      if (decrypt_cb) {
        decrypt_cb(decrypt_state, x, clear_buffer, frames * mag);
        x = clear_buffer;
      }

John Koleszar's avatar
John Koleszar committed
340
      for (i = 0; i < frames; i++) {
Johann's avatar
Johann committed
341
        uint32_t this_sz = 0;
John Koleszar's avatar
John Koleszar committed
342 343 344 345 346 347 348 349 350 351 352

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

      *count = frames;
    }
  }
}

353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
static vpx_codec_err_t decode_one_iter(vpx_codec_alg_priv_t *ctx,
                                       const uint8_t **data_start_ptr,
                                       const uint8_t *data_end,
                                       uint32_t frame_size, void *user_priv,
                                       long deadline) {
  const vpx_codec_err_t res = decode_one(ctx, data_start_ptr, frame_size,
                                         user_priv, deadline);
  if (res != VPX_CODEC_OK)
    return res;

  // Account for suboptimal termination by the encoder.
  while (*data_start_ptr < data_end) {
    const uint8_t marker = read_marker(ctx->decrypt_cb, ctx->decrypt_state,
                                       *data_start_ptr);
    if (marker)
      break;
    (*data_start_ptr)++;
  }

  return VPX_CODEC_OK;
}

375 376 377
static vpx_codec_err_t decoder_decode(vpx_codec_alg_priv_t *ctx,
                                      const uint8_t *data, unsigned int data_sz,
                                      void *user_priv, long deadline) {
378
  const uint8_t *data_start = data;
379 380 381 382
  const uint8_t *const data_end = data + data_sz;
  vpx_codec_err_t res;
  uint32_t frame_sizes[8];
  int frame_count;
John Koleszar's avatar
John Koleszar committed
383

384 385
  if (data == NULL || data_sz == 0)
    return VPX_CODEC_INVALID_PARAM;
386

387
  parse_superframe_index(data, data_sz, frame_sizes, &frame_count,
388
                         ctx->decrypt_cb, ctx->decrypt_state);
389

390 391
  if (frame_count > 0) {
    int i;
John Koleszar's avatar
John Koleszar committed
392

393 394
    for (i = 0; i < frame_count; ++i) {
      const uint32_t frame_size = frame_sizes[i];
395 396
      if (data_start < data ||
          frame_size > (uint32_t)(data_end - data_start)) {
John Koleszar's avatar
John Koleszar committed
397 398 399 400
        ctx->base.err_detail = "Invalid frame size in index";
        return VPX_CODEC_CORRUPT_FRAME;
      }

401 402 403 404
      res = decode_one_iter(ctx, &data_start, data_end, frame_size,
                            user_priv, deadline);
      if (res != VPX_CODEC_OK)
        return res;
John Koleszar's avatar
John Koleszar committed
405
    }
406
  } else {
407
    while (data_start < data_end) {
408 409
      res = decode_one_iter(ctx, &data_start, data_end,
                            (uint32_t)(data_end - data_start),
410 411 412
                            user_priv, deadline);
      if (res != VPX_CODEC_OK)
        return res;
413
    }
414
  }
415

416
  return VPX_CODEC_OK;
417 418
}

419 420
static vpx_image_t *decoder_get_frame(vpx_codec_alg_priv_t *ctx,
                                      vpx_codec_iter_t *iter) {
John Koleszar's avatar
John Koleszar committed
421 422
  vpx_image_t *img = NULL;

423 424 425 426 427 428 429 430 431 432
  // iter acts as a flip flop, so an image is only returned on the first
  // call to get_frame.
  if (*iter == NULL && ctx->pbi != NULL) {
    YV12_BUFFER_CONFIG sd;
    vp9_ppflags_t flags = {0, 0, 0};

    if (vp9_get_raw_frame(ctx->pbi, &sd, &flags) == 0) {
      VP9_COMMON *cm = &ctx->pbi->common;
      yuvconfig2image(&ctx->img, &sd, NULL);
      ctx->img.fb_priv = cm->frame_bufs[cm->new_fb_idx].raw_frame_buffer.priv;
John Koleszar's avatar
John Koleszar committed
433 434
      img = &ctx->img;
      *iter = img;
435 436 437 438 439 440 441 442 443
      // Decrease reference count of last output frame in frame parallel mode.
      if (ctx->frame_parallel_decode && ctx->last_show_frame >= 0) {
        --cm->frame_bufs[ctx->last_show_frame].ref_count;
        if (cm->frame_bufs[ctx->last_show_frame].ref_count == 0) {
          cm->release_fb_cb(cm->cb_priv,
              &cm->frame_bufs[ctx->last_show_frame].raw_frame_buffer);
        }
      }
      ctx->last_show_frame = ctx->pbi->common.new_fb_idx;
John Koleszar's avatar
John Koleszar committed
444
    }
John Koleszar's avatar
John Koleszar committed
445
  }
John Koleszar's avatar
John Koleszar committed
446

John Koleszar's avatar
John Koleszar committed
447
  return img;
John Koleszar's avatar
John Koleszar committed
448 449
}

450
static vpx_codec_err_t decoder_set_fb_fn(
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
    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;
}

468
static vpx_codec_err_t ctrl_set_reference(vpx_codec_alg_priv_t *ctx,
469
                                          va_list args) {
470
  vpx_ref_frame_t *const data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
471

John Koleszar's avatar
John Koleszar committed
472
  if (data) {
473
    vpx_ref_frame_t *const frame = (vpx_ref_frame_t *)data;
John Koleszar's avatar
John Koleszar committed
474
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
475

John Koleszar's avatar
John Koleszar committed
476
    image2yuvconfig(&frame->img, &sd);
477
    return vp9_set_reference_dec(&ctx->pbi->common,
478
                                 (VP9_REFFRAME)frame->frame_type, &sd);
479
  } else {
John Koleszar's avatar
John Koleszar committed
480
    return VPX_CODEC_INVALID_PARAM;
481
  }
John Koleszar's avatar
John Koleszar committed
482 483
}

484
static vpx_codec_err_t ctrl_copy_reference(vpx_codec_alg_priv_t *ctx,
485
                                           va_list args) {
John Koleszar's avatar
John Koleszar committed
486
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
487

John Koleszar's avatar
John Koleszar committed
488 489 490
  if (data) {
    vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
491

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

John Koleszar's avatar
John Koleszar committed
494 495
    return vp9_copy_reference_dec(ctx->pbi,
                                  (VP9_REFFRAME)frame->frame_type, &sd);
496
  } else {
John Koleszar's avatar
John Koleszar committed
497
    return VPX_CODEC_INVALID_PARAM;
498
  }
John Koleszar's avatar
John Koleszar committed
499 500
}

501
static vpx_codec_err_t ctrl_get_reference(vpx_codec_alg_priv_t *ctx,
502
                                          va_list args) {
John Koleszar's avatar
John Koleszar committed
503 504 505 506 507 508 509 510 511 512 513 514 515
  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;
  }
}

516
static vpx_codec_err_t ctrl_set_postproc(vpx_codec_alg_priv_t *ctx,
517
                                         va_list args) {
518
#if CONFIG_VP9_POSTPROC
John Koleszar's avatar
John Koleszar committed
519
  vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
John Koleszar's avatar
John Koleszar committed
520

John Koleszar's avatar
John Koleszar committed
521 522 523 524
  if (data) {
    ctx->postproc_cfg_set = 1;
    ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data);
    return VPX_CODEC_OK;
525
  } else {
John Koleszar's avatar
John Koleszar committed
526
    return VPX_CODEC_INVALID_PARAM;
527
  }
John Koleszar's avatar
John Koleszar committed
528
#else
529 530
  (void)ctx;
  (void)args;
John Koleszar's avatar
John Koleszar committed
531
  return VPX_CODEC_INCAPABLE;
John Koleszar's avatar
John Koleszar committed
532 533 534
#endif
}

535
static vpx_codec_err_t ctrl_set_dbg_options(vpx_codec_alg_priv_t *ctx,
536 537 538
                                            va_list args) {
  (void)ctx;
  (void)args;
John Koleszar's avatar
John Koleszar committed
539
  return VPX_CODEC_INCAPABLE;
540
}
John Koleszar's avatar
John Koleszar committed
541

542
static vpx_codec_err_t ctrl_get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
543
                                                 va_list args) {
544
  int *const update_info = va_arg(args, int *);
545

John Koleszar's avatar
John Koleszar committed
546
  if (update_info) {
547 548 549 550
    if (ctx->pbi)
      *update_info = ctx->pbi->refresh_frame_flags;
    else
      return VPX_CODEC_ERROR;
John Koleszar's avatar
John Koleszar committed
551
    return VPX_CODEC_OK;
552
  } else {
John Koleszar's avatar
John Koleszar committed
553
    return VPX_CODEC_INVALID_PARAM;
554
  }
555 556 557
}


558
static vpx_codec_err_t ctrl_get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
559
                                                va_list args) {
John Koleszar's avatar
John Koleszar committed
560
  int *corrupted = va_arg(args, int *);
561

John Koleszar's avatar
John Koleszar committed
562
  if (corrupted) {
563 564
    if (ctx->pbi)
      *corrupted = ctx->pbi->common.frame_to_show->corrupted;
Yaowu Xu's avatar
Yaowu Xu committed
565 566
    else
      return VPX_CODEC_ERROR;
John Koleszar's avatar
John Koleszar committed
567
    return VPX_CODEC_OK;
568
  } else {
John Koleszar's avatar
John Koleszar committed
569
    return VPX_CODEC_INVALID_PARAM;
570
  }
571 572
}

573
static vpx_codec_err_t ctrl_get_display_size(vpx_codec_alg_priv_t *ctx,
574
                                             va_list args) {
575 576 577
  int *const display_size = va_arg(args, int *);

  if (display_size) {
578 579 580 581
    if (ctx->pbi) {
      const VP9_COMMON *const cm = &ctx->pbi->common;
      display_size[0] = cm->display_width;
      display_size[1] = cm->display_height;
582 583 584 585 586 587 588 589 590
    } else {
      return VPX_CODEC_ERROR;
    }
    return VPX_CODEC_OK;
  } else {
    return VPX_CODEC_INVALID_PARAM;
  }
}

591
static vpx_codec_err_t ctrl_set_invert_tile_order(vpx_codec_alg_priv_t *ctx,
592
                                                  va_list args) {
593 594 595 596
  ctx->invert_tile_order = va_arg(args, int);
  return VPX_CODEC_OK;
}

597 598 599 600 601 602 603 604
static vpx_codec_err_t ctrl_set_decryptor(vpx_codec_alg_priv_t *ctx,
                                          va_list args) {
  vpx_decrypt_init *init = va_arg(args, vpx_decrypt_init *);
  ctx->decrypt_cb = init ? init->decrypt_cb : NULL;
  ctx->decrypt_state = init ? init->decrypt_state : NULL;
  return VPX_CODEC_OK;
}

605 606 607 608 609 610 611 612 613 614 615
static vpx_codec_ctrl_fn_map_t decoder_ctrl_maps[] = {
  {VP8_COPY_REFERENCE,            ctrl_copy_reference},

  // Setters
  {VP8_SET_REFERENCE,             ctrl_set_reference},
  {VP8_SET_POSTPROC,              ctrl_set_postproc},
  {VP8_SET_DBG_COLOR_REF_FRAME,   ctrl_set_dbg_options},
  {VP8_SET_DBG_COLOR_MB_MODES,    ctrl_set_dbg_options},
  {VP8_SET_DBG_COLOR_B_MODES,     ctrl_set_dbg_options},
  {VP8_SET_DBG_DISPLAY_MV,        ctrl_set_dbg_options},
  {VP9_INVERT_TILE_DECODE_ORDER,  ctrl_set_invert_tile_order},
616
  {VPXD_SET_DECRYPTOR,            ctrl_set_decryptor},
617 618 619 620 621 622 623

  // Getters
  {VP8D_GET_LAST_REF_UPDATES,     ctrl_get_last_ref_updates},
  {VP8D_GET_FRAME_CORRUPTED,      ctrl_get_frame_corrupted},
  {VP9_GET_REFERENCE,             ctrl_get_reference},
  {VP9D_GET_DISPLAY_SIZE,         ctrl_get_display_size},

John Koleszar's avatar
John Koleszar committed
624
  { -1, NULL},
John Koleszar's avatar
John Koleszar committed
625 626 627 628 629
};

#ifndef VERSION_STRING
#define VERSION_STRING
#endif
630 631
CODEC_INTERFACE(vpx_codec_vp9_dx) = {
  "WebM Project VP9 Decoder" VERSION_STRING,
John Koleszar's avatar
John Koleszar committed
632
  VPX_CODEC_INTERNAL_ABI_VERSION,
633
  VPX_CODEC_CAP_DECODER | VP9_CAP_POSTPROC |
634 635 636 637 638 639
      VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER,  // vpx_codec_caps_t
  decoder_init,       // vpx_codec_init_fn_t
  decoder_destroy,    // vpx_codec_destroy_fn_t
  decoder_ctrl_maps,  // vpx_codec_ctrl_fn_map_t
  NOT_IMPLEMENTED,    // vpx_codec_get_mmap_fn_t
  NOT_IMPLEMENTED,    // vpx_codec_set_mmap_fn_t
640
  { // NOLINT
641 642 643 644 645
    decoder_peek_si,    // vpx_codec_peek_si_fn_t
    decoder_get_si,     // vpx_codec_get_si_fn_t
    decoder_decode,     // vpx_codec_decode_fn_t
    decoder_get_frame,  // vpx_codec_frame_get_fn_t
    decoder_set_fb_fn,  // vpx_codec_set_fb_fn_t
John Koleszar's avatar
John Koleszar committed
646
  },
647
  { // NOLINT
648 649 650 651 652 653 654
    NOT_IMPLEMENTED,  // vpx_codec_enc_cfg_map_t
    NOT_IMPLEMENTED,  // vpx_codec_encode_fn_t
    NOT_IMPLEMENTED,  // vpx_codec_get_cx_data_fn_t
    NOT_IMPLEMENTED,  // vpx_codec_enc_config_set_fn_t
    NOT_IMPLEMENTED,  // vpx_codec_get_global_headers_fn_t
    NOT_IMPLEMENTED,  // vpx_codec_get_preview_frame_fn_t
    NOT_IMPLEMENTED   // vpx_codec_enc_mr_get_mem_loc_fn_t
John Koleszar's avatar
John Koleszar committed
655
  }
John Koleszar's avatar
John Koleszar committed
656
};