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

#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;
John Koleszar's avatar
John Koleszar committed
35
  int                     decoder_init;
36
  struct VP9Decoder *pbi;
John Koleszar's avatar
John Koleszar committed
37 38
  int                     postproc_cfg_set;
  vp8_postproc_cfg_t      postproc_cfg;
39
#if CONFIG_POSTPROC_VISUALIZER
John Koleszar's avatar
John Koleszar committed
40 41 42 43 44
  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;
45
#endif
46 47
  vpx_decrypt_cb          decrypt_cb;
  void                   *decrypt_state;
John Koleszar's avatar
John Koleszar committed
48 49
  vpx_image_t             img;
  int                     img_avail;
50
  int                     invert_tile_order;
51 52 53 54 55

  // 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
56 57
};

58 59
static vpx_codec_err_t decoder_init(vpx_codec_ctx_t *ctx,
                            vpx_codec_priv_enc_mr_cfg_t *data) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
60 61 62
  // 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
63
  if (!ctx->priv) {
64 65
    vpx_codec_alg_priv_t *alg_priv = vpx_memalign(32, sizeof(*alg_priv));
    if (alg_priv == NULL)
66 67
      return VPX_CODEC_MEM_ERROR;

68 69 70
    vp9_zero(*alg_priv);

    ctx->priv = (vpx_codec_priv_t *)alg_priv;
71 72
    ctx->priv->sz = sizeof(*ctx->priv);
    ctx->priv->iface = ctx->iface;
73
    ctx->priv->alg_priv = alg_priv;
74 75 76 77 78 79 80
    ctx->priv->alg_priv->si.sz = sizeof(ctx->priv->alg_priv->si);
    ctx->priv->init_flags = ctx->init_flags;

    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 235 236 237 238 239 240 241 242 243 244 245 246

  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 =
#if CONFIG_POSTPROC_VISUALIZER
      (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) |
#endif
      ctx->postproc_cfg.post_proc_flag;

  flags->deblocking_level = ctx->postproc_cfg.deblocking_level;
  flags->noise_level = ctx->postproc_cfg.noise_level;
#if CONFIG_POSTPROC_VISUALIZER
  flags->display_ref_frame_flag = ctx->dbg_color_ref_frame_flag;
  flags->display_mb_modes_flag = ctx->dbg_color_mb_modes_flag;
  flags->display_b_modes_flag = ctx->dbg_color_b_modes_flag;
  flags->display_mv_flag = ctx->dbg_display_mv_flag;
#endif
}

static void init_decoder(vpx_codec_alg_priv_t *ctx) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
247
  ctx->pbi = vp9_decoder_create();
248 249 250
  if (ctx->pbi == NULL)
    return;

Dmitry Kovalev's avatar
Dmitry Kovalev committed
251 252 253
  ctx->pbi->max_threads = ctx->cfg.threads;
  ctx->pbi->inv_tile_order = ctx->invert_tile_order;

254 255 256 257 258 259 260 261 262 263 264
  vp9_initialize_dec();

  // 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
265 266 267
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) {
268 269 270 271
  YV12_BUFFER_CONFIG sd = { 0 };
  int64_t time_stamp = 0, time_end_stamp = 0;
  vp9_ppflags_t flags = {0};
  VP9_COMMON *cm = NULL;
John Koleszar's avatar
John Koleszar committed
272

John Koleszar's avatar
John Koleszar committed
273
  ctx->img_avail = 0;
John Koleszar's avatar
John Koleszar committed
274

275 276 277
  // 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.
278 279
  if (!ctx->si.h) {
    const vpx_codec_err_t res =
280 281
        decoder_peek_si_internal(*data, data_sz, &ctx->si, ctx->decrypt_cb,
                                 ctx->decrypt_state);
282 283 284
    if (res != VPX_CODEC_OK)
      return res;
  }
285

286 287 288 289 290
  // Initialize the decoder instance on the first frame
  if (!ctx->decoder_init) {
    init_decoder(ctx);
    if (ctx->pbi == NULL)
      return VPX_CODEC_ERROR;
John Koleszar's avatar
John Koleszar committed
291

John Koleszar's avatar
John Koleszar committed
292 293 294
    ctx->decoder_init = 1;
  }

295 296 297 298 299
  // 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;

300
  cm = &ctx->pbi->common;
John Koleszar's avatar
John Koleszar committed
301

302 303
  if (vp9_receive_compressed_data(ctx->pbi, data_sz, data, deadline))
    return update_error_state(ctx, &cm->error);
John Koleszar's avatar
John Koleszar committed
304

305 306
  if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)
    set_ppflags(ctx, &flags);
John Koleszar's avatar
John Koleszar committed
307

308 309
  if (vp9_get_raw_frame(ctx->pbi, &sd, &time_stamp, &time_end_stamp, &flags))
    return update_error_state(ctx, &cm->error);
310

311 312 313
  yuvconfig2image(&ctx->img, &sd, user_priv);
  ctx->img.fb_priv = cm->frame_bufs[cm->new_fb_idx].raw_frame_buffer.priv;
  ctx->img_avail = 1;
John Koleszar's avatar
John Koleszar committed
314

315
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
316 317
}

318 319 320 321 322 323 324 325 326 327 328
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
329
static void parse_superframe_index(const uint8_t *data, size_t data_sz,
330 331 332
                                   uint32_t sizes[8], int *count,
                                   vpx_decrypt_cb decrypt_cb,
                                   void *decrypt_state) {
John Koleszar's avatar
John Koleszar committed
333 334 335
  uint8_t marker;

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

339
  if ((marker & 0xe0) == 0xc0) {
Johann's avatar
Johann committed
340 341 342
    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
343

344 345 346 347
    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
348
      // found a valid superframe index
Johann's avatar
Johann committed
349
      uint32_t i, j;
350
      const uint8_t *x = &data[data_sz - index_sz + 1];
John Koleszar's avatar
John Koleszar committed
351

352 353 354 355 356 357 358 359
      // 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
360
      for (i = 0; i < frames; i++) {
Johann's avatar
Johann committed
361
        uint32_t this_sz = 0;
John Koleszar's avatar
John Koleszar committed
362 363 364 365 366 367 368 369 370 371 372

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

      *count = frames;
    }
  }
}

373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
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;
}

395 396 397
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) {
398
  const uint8_t *data_start = data;
399 400 401 402
  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
403

404 405
  if (data == NULL || data_sz == 0)
    return VPX_CODEC_INVALID_PARAM;
406

407
  parse_superframe_index(data, data_sz, frame_sizes, &frame_count,
408
                         ctx->decrypt_cb, ctx->decrypt_state);
409

410 411
  if (frame_count > 0) {
    int i;
John Koleszar's avatar
John Koleszar committed
412

413 414
    for (i = 0; i < frame_count; ++i) {
      const uint32_t frame_size = frame_sizes[i];
415 416
      if (data_start < data ||
          frame_size > (uint32_t)(data_end - data_start)) {
John Koleszar's avatar
John Koleszar committed
417 418 419 420
        ctx->base.err_detail = "Invalid frame size in index";
        return VPX_CODEC_CORRUPT_FRAME;
      }

421 422 423 424
      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
425
    }
426
  } else {
427
    while (data_start < data_end) {
428 429
      res = decode_one_iter(ctx, &data_start, data_end,
                            (uint32_t)(data_end - data_start),
430 431 432
                            user_priv, deadline);
      if (res != VPX_CODEC_OK)
        return res;
433
    }
434
  }
435

436
  return VPX_CODEC_OK;
437 438
}

439 440
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
441 442 443
  vpx_image_t *img = NULL;

  if (ctx->img_avail) {
444 445
    // iter acts as a flip flop, so an image is only returned on the first
    // call to get_frame.
John Koleszar's avatar
John Koleszar committed
446 447 448
    if (!(*iter)) {
      img = &ctx->img;
      *iter = img;
John Koleszar's avatar
John Koleszar committed
449
    }
John Koleszar's avatar
John Koleszar committed
450
  }
451
  ctx->img_avail = 0;
John Koleszar's avatar
John Koleszar committed
452

John Koleszar's avatar
John Koleszar committed
453
  return img;
John Koleszar's avatar
John Koleszar committed
454 455
}

456
static vpx_codec_err_t decoder_set_fb_fn(
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
    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;
}

474 475
static vpx_codec_err_t ctrl_set_reference(vpx_codec_alg_priv_t *ctx,
                                          int ctr_id, va_list args) {
476
  vpx_ref_frame_t *const data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
477

John Koleszar's avatar
John Koleszar committed
478
  if (data) {
479
    vpx_ref_frame_t *const frame = (vpx_ref_frame_t *)data;
John Koleszar's avatar
John Koleszar committed
480
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
481

John Koleszar's avatar
John Koleszar committed
482
    image2yuvconfig(&frame->img, &sd);
483
    return vp9_set_reference_dec(&ctx->pbi->common,
484
                                 (VP9_REFFRAME)frame->frame_type, &sd);
485
  } else {
John Koleszar's avatar
John Koleszar committed
486
    return VPX_CODEC_INVALID_PARAM;
487
  }
John Koleszar's avatar
John Koleszar committed
488 489
}

490 491
static vpx_codec_err_t ctrl_copy_reference(vpx_codec_alg_priv_t *ctx,
                                           int ctr_id, va_list args) {
John Koleszar's avatar
John Koleszar committed
492
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
493

John Koleszar's avatar
John Koleszar committed
494 495 496
  if (data) {
    vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
497

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

John Koleszar's avatar
John Koleszar committed
500 501
    return vp9_copy_reference_dec(ctx->pbi,
                                  (VP9_REFFRAME)frame->frame_type, &sd);
502
  } else {
John Koleszar's avatar
John Koleszar committed
503
    return VPX_CODEC_INVALID_PARAM;
504
  }
John Koleszar's avatar
John Koleszar committed
505 506
}

507 508
static vpx_codec_err_t ctrl_get_reference(vpx_codec_alg_priv_t *ctx,
                                          int ctr_id, va_list args) {
John Koleszar's avatar
John Koleszar committed
509 510 511 512 513 514 515 516 517 518 519 520 521
  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;
  }
}

522 523
static vpx_codec_err_t ctrl_set_postproc(vpx_codec_alg_priv_t *ctx,
                                         int ctr_id, va_list args) {
524
#if CONFIG_VP9_POSTPROC
John Koleszar's avatar
John Koleszar committed
525
  vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
John Koleszar's avatar
John Koleszar committed
526

John Koleszar's avatar
John Koleszar committed
527 528 529 530
  if (data) {
    ctx->postproc_cfg_set = 1;
    ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data);
    return VPX_CODEC_OK;
531
  } else {
John Koleszar's avatar
John Koleszar committed
532
    return VPX_CODEC_INVALID_PARAM;
533
  }
John Koleszar's avatar
John Koleszar committed
534
#else
John Koleszar's avatar
John Koleszar committed
535
  return VPX_CODEC_INCAPABLE;
John Koleszar's avatar
John Koleszar committed
536 537 538
#endif
}

539 540
static vpx_codec_err_t ctrl_set_dbg_options(vpx_codec_alg_priv_t *ctx,
                                            int ctrl_id, va_list args) {
541
#if CONFIG_POSTPROC_VISUALIZER && CONFIG_POSTPROC
John Koleszar's avatar
John Koleszar committed
542
  int data = va_arg(args, int);
543 544 545

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

John Koleszar's avatar
John Koleszar committed
546 547 548 549 550 551
  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);
  }
552

John Koleszar's avatar
John Koleszar committed
553
  return VPX_CODEC_OK;
554
#else
John Koleszar's avatar
John Koleszar committed
555
  return VPX_CODEC_INCAPABLE;
556 557
#endif
}
John Koleszar's avatar
John Koleszar committed
558

559 560
static vpx_codec_err_t ctrl_get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
                                                 int ctrl_id, va_list args) {
561
  int *const update_info = va_arg(args, int *);
562

John Koleszar's avatar
John Koleszar committed
563
  if (update_info) {
564 565 566 567
    if (ctx->pbi)
      *update_info = ctx->pbi->refresh_frame_flags;
    else
      return VPX_CODEC_ERROR;
John Koleszar's avatar
John Koleszar committed
568
    return VPX_CODEC_OK;
569
  } else {
John Koleszar's avatar
John Koleszar committed
570
    return VPX_CODEC_INVALID_PARAM;
571
  }
572 573 574
}


575 576
static vpx_codec_err_t ctrl_get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
                                                int ctrl_id, va_list args) {
John Koleszar's avatar
John Koleszar committed
577
  int *corrupted = va_arg(args, int *);
578

John Koleszar's avatar
John Koleszar committed
579
  if (corrupted) {
580 581
    if (ctx->pbi)
      *corrupted = ctx->pbi->common.frame_to_show->corrupted;
Yaowu Xu's avatar
Yaowu Xu committed
582 583
    else
      return VPX_CODEC_ERROR;
John Koleszar's avatar
John Koleszar committed
584
    return VPX_CODEC_OK;
585
  } else {
John Koleszar's avatar
John Koleszar committed
586
    return VPX_CODEC_INVALID_PARAM;
587
  }
588 589
}

590 591
static vpx_codec_err_t ctrl_get_display_size(vpx_codec_alg_priv_t *ctx,
                                             int ctrl_id, va_list args) {
592 593 594
  int *const display_size = va_arg(args, int *);

  if (display_size) {
595 596 597 598
    if (ctx->pbi) {
      const VP9_COMMON *const cm = &ctx->pbi->common;
      display_size[0] = cm->display_width;
      display_size[1] = cm->display_height;
599 600 601 602 603 604 605 606 607
    } else {
      return VPX_CODEC_ERROR;
    }
    return VPX_CODEC_OK;
  } else {
    return VPX_CODEC_INVALID_PARAM;
  }
}

608 609
static vpx_codec_err_t ctrl_set_invert_tile_order(vpx_codec_alg_priv_t *ctx,
                                                  int ctr_id, va_list args) {
610 611 612 613
  ctx->invert_tile_order = va_arg(args, int);
  return VPX_CODEC_OK;
}

614 615 616 617 618 619 620 621 622
static vpx_codec_err_t ctrl_set_decryptor(vpx_codec_alg_priv_t *ctx,
                                          int ctrl_id,
                                          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;
}

623 624 625 626 627 628 629 630 631 632 633
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},
634
  {VPXD_SET_DECRYPTOR,            ctrl_set_decryptor},
635 636 637 638 639 640 641

  // 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
642
  { -1, NULL},
John Koleszar's avatar
John Koleszar committed
643 644 645 646 647
};

#ifndef VERSION_STRING
#define VERSION_STRING
#endif
648 649
CODEC_INTERFACE(vpx_codec_vp9_dx) = {
  "WebM Project VP9 Decoder" VERSION_STRING,
John Koleszar's avatar
John Koleszar committed
650
  VPX_CODEC_INTERNAL_ABI_VERSION,
651
  VPX_CODEC_CAP_DECODER | VP9_CAP_POSTPROC |
652 653 654 655 656 657
      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
658
  { // NOLINT
659 660 661 662 663
    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
664
  },
665
  { // NOLINT
John Koleszar's avatar
John Koleszar committed
666 667 668 669 670 671 672
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED
  }
John Koleszar's avatar
John Koleszar committed
673
};