vp9_dx_iface.c 19.5 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 43 44 45 46

  // 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
47 48
};

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

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

61 62 63
    vp9_zero(*alg_priv);

    ctx->priv = (vpx_codec_priv_t *)alg_priv;
64 65
    ctx->priv->sz = sizeof(*ctx->priv);
    ctx->priv->iface = ctx->iface;
66
    ctx->priv->alg_priv = alg_priv;
67 68 69 70 71 72 73
    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
74
    }
John Koleszar's avatar
John Koleszar committed
75
  }
John Koleszar's avatar
John Koleszar committed
76

77
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
78 79
}

80 81 82 83 84
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
85

86 87
  vpx_free(ctx);

John Koleszar's avatar
John Koleszar committed
88
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
89 90
}

91 92 93 94 95 96 97
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];

98 99 100 101 102
  if (data_sz <= 8)
    return VPX_CODEC_UNSUP_BITSTREAM;

  if (data + data_sz <= data)
    return VPX_CODEC_INVALID_PARAM;
103 104 105

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

107 108 109 110 111 112
  if (decrypt_cb) {
    data_sz = MIN(sizeof(clear_buffer), data_sz);
    decrypt_cb(decrypt_state, data, clear_buffer, data_sz);
    data = clear_buffer;
  }

113 114 115
  {
    struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
    const int frame_marker = vp9_rb_read_literal(&rb, 2);
116 117 118
    const int version = vp9_rb_read_bit(&rb);
    (void) vp9_rb_read_bit(&rb);  // unused version bit

119 120
    if (frame_marker != VP9_FRAME_MARKER)
      return VPX_CODEC_UNSUP_BITSTREAM;
121 122 123 124 125
    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
126

127
    si->is_kf = !vp9_rb_read_bit(&rb);
James Zern's avatar
James Zern committed
128
    if (si->is_kf) {
129 130
      const int sRGB = 7;
      int colorspace;
John Koleszar's avatar
John Koleszar committed
131

132 133
      rb.bit_offset += 1;  // show frame
      rb.bit_offset += 1;  // error resilient
John Koleszar's avatar
John Koleszar committed
134

135 136 137
      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) {
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
        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
160
    }
John Koleszar's avatar
John Koleszar committed
161 162
  }

163
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
164 165
}

166 167 168 169 170 171
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);
}

172 173
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
174 175 176
  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
177
  memcpy(si, &ctx->si, sz);
178
  si->sz = (unsigned int)sz;
John Koleszar's avatar
John Koleszar committed
179

John Koleszar's avatar
John Koleszar committed
180
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
181 182
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
183 184 185 186
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
187

Dmitry Kovalev's avatar
Dmitry Kovalev committed
188
  return error->error_code;
John Koleszar's avatar
John Koleszar committed
189 190
}

191 192 193
static void init_buffer_callbacks(vpx_codec_alg_priv_t *ctx) {
  VP9_COMMON *const cm = &ctx->pbi->common;

194
  cm->new_fb_idx = -1;
195 196 197 198 199 200 201 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

  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
228
  ctx->pbi = vp9_decoder_create();
229 230 231
  if (ctx->pbi == NULL)
    return;

Dmitry Kovalev's avatar
Dmitry Kovalev committed
232 233 234
  ctx->pbi->max_threads = ctx->cfg.threads;
  ctx->pbi->inv_tile_order = ctx->invert_tile_order;

235 236 237 238 239 240 241 242 243
  // 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
244 245 246
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) {
247
  vp9_ppflags_t flags = {0};
248
  VP9_COMMON *cm = NULL;
John Koleszar's avatar
John Koleszar committed
249

250 251
  (void)deadline;

252 253 254
  // 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.
255 256
  if (!ctx->si.h) {
    const vpx_codec_err_t res =
257 258
        decoder_peek_si_internal(*data, data_sz, &ctx->si, ctx->decrypt_cb,
                                 ctx->decrypt_state);
259 260
    if (res != VPX_CODEC_OK)
      return res;
261 262 263

    if (!ctx->si.is_kf)
      return VPX_CODEC_ERROR;
264
  }
265

266
  // Initialize the decoder instance on the first frame
267
  if (ctx->pbi == NULL) {
268 269 270
    init_decoder(ctx);
    if (ctx->pbi == NULL)
      return VPX_CODEC_ERROR;
John Koleszar's avatar
John Koleszar committed
271 272
  }

273 274 275 276 277
  // 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;

278
  cm = &ctx->pbi->common;
John Koleszar's avatar
John Koleszar committed
279

280
  if (vp9_receive_compressed_data(ctx->pbi, data_sz, data))
281
    return update_error_state(ctx, &cm->error);
John Koleszar's avatar
John Koleszar committed
282

283 284
  if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)
    set_ppflags(ctx, &flags);
John Koleszar's avatar
John Koleszar committed
285

286
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
287 288
}

289 290 291 292 293 294 295 296 297 298 299
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
300
static void parse_superframe_index(const uint8_t *data, size_t data_sz,
301 302 303
                                   uint32_t sizes[8], int *count,
                                   vpx_decrypt_cb decrypt_cb,
                                   void *decrypt_state) {
John Koleszar's avatar
John Koleszar committed
304 305 306
  uint8_t marker;

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

310
  if ((marker & 0xe0) == 0xc0) {
Johann's avatar
Johann committed
311 312 313
    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
314

315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
    if (data_sz >= index_sz) {
      uint8_t marker2 = read_marker(decrypt_cb, decrypt_state,
                                    data + data_sz - index_sz);

      if (marker == marker2) {
        // Found a valid superframe index.
        uint32_t i, j;
        const uint8_t *x = &data[data_sz - index_sz + 1];

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

332 333
        for (i = 0; i < frames; ++i) {
          uint32_t this_sz = 0;
John Koleszar's avatar
John Koleszar committed
334

335 336 337 338
          for (j = 0; j < mag; ++j)
            this_sz |= (*x++) << (j * 8);
          sizes[i] = this_sz;
        }
John Koleszar's avatar
John Koleszar committed
339

340 341
        *count = frames;
      }
John Koleszar's avatar
John Koleszar committed
342 343 344 345
    }
  }
}

346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
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;
}

368 369 370
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) {
371
  const uint8_t *data_start = data;
372 373 374 375
  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
376

377 378
  if (data == NULL || data_sz == 0)
    return VPX_CODEC_INVALID_PARAM;
379

380
  parse_superframe_index(data, data_sz, frame_sizes, &frame_count,
381
                         ctx->decrypt_cb, ctx->decrypt_state);
382

383 384
  if (frame_count > 0) {
    int i;
John Koleszar's avatar
John Koleszar committed
385

386 387
    for (i = 0; i < frame_count; ++i) {
      const uint32_t frame_size = frame_sizes[i];
388 389
      if (data_start < data ||
          frame_size > (uint32_t)(data_end - data_start)) {
John Koleszar's avatar
John Koleszar committed
390 391 392 393
        ctx->base.err_detail = "Invalid frame size in index";
        return VPX_CODEC_CORRUPT_FRAME;
      }

394 395 396 397
      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
398
    }
399
  } else {
400
    while (data_start < data_end) {
401 402
      res = decode_one_iter(ctx, &data_start, data_end,
                            (uint32_t)(data_end - data_start),
403 404 405
                            user_priv, deadline);
      if (res != VPX_CODEC_OK)
        return res;
406
    }
407
  }
408

409
  return VPX_CODEC_OK;
410 411
}

412 413
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
414 415
  vpx_image_t *img = NULL;

416 417 418 419 420 421 422 423 424 425
  // 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
426 427
      img = &ctx->img;
      *iter = img;
John Koleszar's avatar
John Koleszar committed
428
    }
John Koleszar's avatar
John Koleszar committed
429
  }
John Koleszar's avatar
John Koleszar committed
430

John Koleszar's avatar
John Koleszar committed
431
  return img;
John Koleszar's avatar
John Koleszar committed
432 433
}

434
static vpx_codec_err_t decoder_set_fb_fn(
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
    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;
}

452
static vpx_codec_err_t ctrl_set_reference(vpx_codec_alg_priv_t *ctx,
453
                                          va_list args) {
454
  vpx_ref_frame_t *const data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
455

John Koleszar's avatar
John Koleszar committed
456
  if (data) {
457
    vpx_ref_frame_t *const frame = (vpx_ref_frame_t *)data;
John Koleszar's avatar
John Koleszar committed
458
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
459

John Koleszar's avatar
John Koleszar committed
460
    image2yuvconfig(&frame->img, &sd);
461
    return vp9_set_reference_dec(&ctx->pbi->common,
462
                                 (VP9_REFFRAME)frame->frame_type, &sd);
463
  } else {
John Koleszar's avatar
John Koleszar committed
464
    return VPX_CODEC_INVALID_PARAM;
465
  }
John Koleszar's avatar
John Koleszar committed
466 467
}

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

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

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

John Koleszar's avatar
John Koleszar committed
478 479
    return vp9_copy_reference_dec(ctx->pbi,
                                  (VP9_REFFRAME)frame->frame_type, &sd);
480
  } else {
John Koleszar's avatar
John Koleszar committed
481
    return VPX_CODEC_INVALID_PARAM;
482
  }
John Koleszar's avatar
John Koleszar committed
483 484
}

485
static vpx_codec_err_t ctrl_get_reference(vpx_codec_alg_priv_t *ctx,
486
                                          va_list args) {
John Koleszar's avatar
John Koleszar committed
487 488 489 490 491 492 493 494 495 496 497 498 499
  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;
  }
}

500
static vpx_codec_err_t ctrl_set_postproc(vpx_codec_alg_priv_t *ctx,
501
                                         va_list args) {
502
#if CONFIG_VP9_POSTPROC
John Koleszar's avatar
John Koleszar committed
503
  vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
John Koleszar's avatar
John Koleszar committed
504

John Koleszar's avatar
John Koleszar committed
505 506 507 508
  if (data) {
    ctx->postproc_cfg_set = 1;
    ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data);
    return VPX_CODEC_OK;
509
  } else {
John Koleszar's avatar
John Koleszar committed
510
    return VPX_CODEC_INVALID_PARAM;
511
  }
John Koleszar's avatar
John Koleszar committed
512
#else
513 514
  (void)ctx;
  (void)args;
John Koleszar's avatar
John Koleszar committed
515
  return VPX_CODEC_INCAPABLE;
John Koleszar's avatar
John Koleszar committed
516 517 518
#endif
}

519
static vpx_codec_err_t ctrl_set_dbg_options(vpx_codec_alg_priv_t *ctx,
520 521 522
                                            va_list args) {
  (void)ctx;
  (void)args;
John Koleszar's avatar
John Koleszar committed
523
  return VPX_CODEC_INCAPABLE;
524
}
John Koleszar's avatar
John Koleszar committed
525

526
static vpx_codec_err_t ctrl_get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
527
                                                 va_list args) {
528
  int *const update_info = va_arg(args, int *);
529

John Koleszar's avatar
John Koleszar committed
530
  if (update_info) {
531 532 533 534
    if (ctx->pbi)
      *update_info = ctx->pbi->refresh_frame_flags;
    else
      return VPX_CODEC_ERROR;
John Koleszar's avatar
John Koleszar committed
535
    return VPX_CODEC_OK;
536
  } else {
John Koleszar's avatar
John Koleszar committed
537
    return VPX_CODEC_INVALID_PARAM;
538
  }
539 540 541
}


542
static vpx_codec_err_t ctrl_get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
543
                                                va_list args) {
John Koleszar's avatar
John Koleszar committed
544
  int *corrupted = va_arg(args, int *);
545

John Koleszar's avatar
John Koleszar committed
546
  if (corrupted) {
547 548
    if (ctx->pbi)
      *corrupted = ctx->pbi->common.frame_to_show->corrupted;
Yaowu Xu's avatar
Yaowu Xu committed
549 550
    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
static vpx_codec_err_t ctrl_get_display_size(vpx_codec_alg_priv_t *ctx,
558
                                             va_list args) {
559 560 561
  int *const display_size = va_arg(args, int *);

  if (display_size) {
562 563 564 565
    if (ctx->pbi) {
      const VP9_COMMON *const cm = &ctx->pbi->common;
      display_size[0] = cm->display_width;
      display_size[1] = cm->display_height;
566 567 568 569 570 571 572 573 574
    } else {
      return VPX_CODEC_ERROR;
    }
    return VPX_CODEC_OK;
  } else {
    return VPX_CODEC_INVALID_PARAM;
  }
}

575
static vpx_codec_err_t ctrl_set_invert_tile_order(vpx_codec_alg_priv_t *ctx,
576
                                                  va_list args) {
577 578 579 580
  ctx->invert_tile_order = va_arg(args, int);
  return VPX_CODEC_OK;
}

581 582 583 584 585 586 587 588
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;
}

589 590 591 592 593 594 595 596 597 598 599
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},
600
  {VPXD_SET_DECRYPTOR,            ctrl_set_decryptor},
601 602 603 604 605 606 607

  // 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
608
  { -1, NULL},
John Koleszar's avatar
John Koleszar committed
609 610 611 612 613
};

#ifndef VERSION_STRING
#define VERSION_STRING
#endif
614 615
CODEC_INTERFACE(vpx_codec_vp9_dx) = {
  "WebM Project VP9 Decoder" VERSION_STRING,
John Koleszar's avatar
John Koleszar committed
616
  VPX_CODEC_INTERNAL_ABI_VERSION,
617
  VPX_CODEC_CAP_DECODER | VP9_CAP_POSTPROC |
618 619 620 621 622 623
      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
624
  { // NOLINT
625 626 627 628 629
    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
630
  },
631
  { // NOLINT
632 633 634 635 636 637 638
    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
639
  }
John Koleszar's avatar
John Koleszar committed
640
};