vp9_dx_iface.c 18.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;
John Koleszar's avatar
John Koleszar committed
35
  int                     decoder_init;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
36
  struct VP9Decompressor *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
John Koleszar's avatar
John Koleszar committed
46
47
48
  vpx_image_t             img;
  int                     img_setup;
  int                     img_avail;
49
  int                     invert_tile_order;
50
51
52
53
54

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

57
58
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
59
60
61
  // 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
62
  if (!ctx->priv) {
63
64
    vpx_codec_alg_priv_t *alg_priv = vpx_memalign(32, sizeof(*alg_priv));
    if (alg_priv == NULL)
65
66
      return VPX_CODEC_MEM_ERROR;

67
68
69
    vp9_zero(*alg_priv);

    ctx->priv = (vpx_codec_priv_t *)alg_priv;
70
71
    ctx->priv->sz = sizeof(*ctx->priv);
    ctx->priv->iface = ctx->iface;
72
    ctx->priv->alg_priv = alg_priv;
73
74
75
76
77
78
79
    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
80
    }
John Koleszar's avatar
John Koleszar committed
81
  }
John Koleszar's avatar
John Koleszar committed
82

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

86
87
88
89
90
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
91

92
93
  vpx_free(ctx);

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

97
98
99
100
101
102
103
104
static vpx_codec_err_t decoder_peek_si(const uint8_t *data,
                                       unsigned int data_sz,
                                       vpx_codec_stream_info_t *si) {
  if (data_sz <= 8)
    return VPX_CODEC_UNSUP_BITSTREAM;

  if (data + data_sz <= data)
    return VPX_CODEC_INVALID_PARAM;
105
106
107

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

109
110
111
  {
    struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
    const int frame_marker = vp9_rb_read_literal(&rb, 2);
112
113
114
    const int version = vp9_rb_read_bit(&rb);
    (void) vp9_rb_read_bit(&rb);  // unused version bit

115
116
    if (frame_marker != VP9_FRAME_MARKER)
      return VPX_CODEC_UNSUP_BITSTREAM;
117
118
119
120
121
    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
122

123
    si->is_kf = !vp9_rb_read_bit(&rb);
James Zern's avatar
James Zern committed
124
    if (si->is_kf) {
125
126
      const int sRGB = 7;
      int colorspace;
John Koleszar's avatar
John Koleszar committed
127

128
129
      rb.bit_offset += 1;  // show frame
      rb.bit_offset += 1;  // error resilient
John Koleszar's avatar
John Koleszar committed
130

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

159
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
160
161
}

162
163
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
164
165
166
  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
167
  memcpy(si, &ctx->si, sz);
168
  si->sz = (unsigned int)sz;
John Koleszar's avatar
John Koleszar committed
169

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

Dmitry Kovalev's avatar
Dmitry Kovalev committed
173
174
175
176
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
177

Dmitry Kovalev's avatar
Dmitry Kovalev committed
178
  return error->error_code;
John Koleszar's avatar
John Koleszar committed
179
180
}

181
182
183
static void init_buffer_callbacks(vpx_codec_alg_priv_t *ctx) {
  VP9_COMMON *const cm = &ctx->pbi->common;

184
  cm->new_fb_idx = -1;
185
186
187
188
189
190
191
192
193
194
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
228
229
230
231
232
233
234
235
236

  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) {
  VP9D_CONFIG oxcf;
  oxcf.width = ctx->si.w;
  oxcf.height = ctx->si.h;
  oxcf.version = 9;
  oxcf.max_threads = ctx->cfg.threads;
  oxcf.inv_tile_order = ctx->invert_tile_order;

237
  ctx->pbi = vp9_decoder_create(&oxcf);
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  if (ctx->pbi == NULL)
    return;

  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
252
253
254
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) {
255
256
257
258
  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
259

John Koleszar's avatar
John Koleszar committed
260
  ctx->img_avail = 0;
John Koleszar's avatar
John Koleszar committed
261

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

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

John Koleszar's avatar
John Koleszar committed
278
279
280
    ctx->decoder_init = 1;
  }

281
  cm = &ctx->pbi->common;
John Koleszar's avatar
John Koleszar committed
282

283
284
  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
285

286
287
  if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)
    set_ppflags(ctx, &flags);
John Koleszar's avatar
John Koleszar committed
288

289
290
  if (vp9_get_raw_frame(ctx->pbi, &sd, &time_stamp, &time_end_stamp, &flags))
    return update_error_state(ctx, &cm->error);
291

292
293
294
  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
295

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

Dmitry Kovalev's avatar
Dmitry Kovalev committed
299
300
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
301
302
303
304
305
306
  uint8_t marker;

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

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

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

      for (i = 0; i < frames; i++) {
Johann's avatar
Johann committed
318
        uint32_t this_sz = 0;
John Koleszar's avatar
John Koleszar committed
319
320
321
322
323
324
325
326
327
328
329

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

      *count = frames;
    }
  }
}

330
331
332
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) {
333
334
  const uint8_t *data_start = data;
  const uint8_t *data_end = data + data_sz;
335
  vpx_codec_err_t res = VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
336
337
338
  uint32_t sizes[8];
  int frames_this_pts, frame_count = 0;

339
340
  if (data == NULL || data_sz == 0)
    return VPX_CODEC_INVALID_PARAM;
341

John Koleszar's avatar
John Koleszar committed
342
  parse_superframe_index(data, data_sz, sizes, &frames_this_pts);
343
344

  do {
John Koleszar's avatar
John Koleszar committed
345
    // Skip over the superframe index, if present
346
    if (data_sz && (*data_start & 0xe0) == 0xc0) {
John Koleszar's avatar
John Koleszar committed
347
      const uint8_t marker = *data_start;
Johann's avatar
Johann committed
348
349
350
      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
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374

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

375
376
377
378
    res = decode_one(ctx, &data_start, data_sz, user_priv, deadline);
    assert(data_start >= data);
    assert(data_start <= data_end);

379
    // Early exit if there was a decode error
380
381
382
    if (res)
      break;

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

387
    data_sz = (unsigned int)(data_end - data_start);
388
  } while (data_start < data_end);
389

390
391
392
  return res;
}

393
394
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
395
396
397
  vpx_image_t *img = NULL;

  if (ctx->img_avail) {
398
399
    // 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
400
401
402
    if (!(*iter)) {
      img = &ctx->img;
      *iter = img;
John Koleszar's avatar
John Koleszar committed
403
    }
John Koleszar's avatar
John Koleszar committed
404
  }
405
  ctx->img_avail = 0;
John Koleszar's avatar
John Koleszar committed
406

John Koleszar's avatar
John Koleszar committed
407
  return img;
John Koleszar's avatar
John Koleszar committed
408
409
}

410
static vpx_codec_err_t decoder_set_fb_fn(
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
    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;
}

428
429
static vpx_codec_err_t ctrl_set_reference(vpx_codec_alg_priv_t *ctx,
                                          int ctr_id, va_list args) {
430
  vpx_ref_frame_t *const data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
431

John Koleszar's avatar
John Koleszar committed
432
  if (data) {
433
    vpx_ref_frame_t *const frame = (vpx_ref_frame_t *)data;
John Koleszar's avatar
John Koleszar committed
434
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
435

John Koleszar's avatar
John Koleszar committed
436
    image2yuvconfig(&frame->img, &sd);
437
    return vp9_set_reference_dec(&ctx->pbi->common,
438
                                 (VP9_REFFRAME)frame->frame_type, &sd);
439
  } else {
John Koleszar's avatar
John Koleszar committed
440
    return VPX_CODEC_INVALID_PARAM;
441
  }
John Koleszar's avatar
John Koleszar committed
442
443
}

444
445
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
446
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
447

John Koleszar's avatar
John Koleszar committed
448
449
450
  if (data) {
    vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
451

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

John Koleszar's avatar
John Koleszar committed
454
455
    return vp9_copy_reference_dec(ctx->pbi,
                                  (VP9_REFFRAME)frame->frame_type, &sd);
456
  } else {
John Koleszar's avatar
John Koleszar committed
457
    return VPX_CODEC_INVALID_PARAM;
458
  }
John Koleszar's avatar
John Koleszar committed
459
460
}

461
462
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
463
464
465
466
467
468
469
470
471
472
473
474
475
  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;
  }
}

476
477
static vpx_codec_err_t ctrl_set_postproc(vpx_codec_alg_priv_t *ctx,
                                         int ctr_id, va_list args) {
478
#if CONFIG_VP9_POSTPROC
John Koleszar's avatar
John Koleszar committed
479
  vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
John Koleszar's avatar
John Koleszar committed
480

John Koleszar's avatar
John Koleszar committed
481
482
483
484
  if (data) {
    ctx->postproc_cfg_set = 1;
    ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data);
    return VPX_CODEC_OK;
485
  } else {
John Koleszar's avatar
John Koleszar committed
486
    return VPX_CODEC_INVALID_PARAM;
487
  }
John Koleszar's avatar
John Koleszar committed
488
#else
John Koleszar's avatar
John Koleszar committed
489
  return VPX_CODEC_INCAPABLE;
John Koleszar's avatar
John Koleszar committed
490
491
492
#endif
}

493
494
static vpx_codec_err_t ctrl_set_dbg_options(vpx_codec_alg_priv_t *ctx,
                                            int ctrl_id, va_list args) {
495
#if CONFIG_POSTPROC_VISUALIZER && CONFIG_POSTPROC
John Koleszar's avatar
John Koleszar committed
496
  int data = va_arg(args, int);
497
498
499

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

John Koleszar's avatar
John Koleszar committed
500
501
502
503
504
505
  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);
  }
506

John Koleszar's avatar
John Koleszar committed
507
  return VPX_CODEC_OK;
508
#else
John Koleszar's avatar
John Koleszar committed
509
  return VPX_CODEC_INCAPABLE;
510
511
#endif
}
John Koleszar's avatar
John Koleszar committed
512

513
514
static vpx_codec_err_t ctrl_get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
                                                 int ctrl_id, va_list args) {
515
  int *const update_info = va_arg(args, int *);
516

John Koleszar's avatar
John Koleszar committed
517
  if (update_info) {
518
519
520
521
    if (ctx->pbi)
      *update_info = ctx->pbi->refresh_frame_flags;
    else
      return VPX_CODEC_ERROR;
John Koleszar's avatar
John Koleszar committed
522
    return VPX_CODEC_OK;
523
  } else {
John Koleszar's avatar
John Koleszar committed
524
    return VPX_CODEC_INVALID_PARAM;
525
  }
526
527
528
}


529
530
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
531
  int *corrupted = va_arg(args, int *);
532

John Koleszar's avatar
John Koleszar committed
533
  if (corrupted) {
534
535
    if (ctx->pbi)
      *corrupted = ctx->pbi->common.frame_to_show->corrupted;
Yaowu Xu's avatar
Yaowu Xu committed
536
537
    else
      return VPX_CODEC_ERROR;
John Koleszar's avatar
John Koleszar committed
538
    return VPX_CODEC_OK;
539
  } else {
John Koleszar's avatar
John Koleszar committed
540
    return VPX_CODEC_INVALID_PARAM;
541
  }
542
543
}

544
545
static vpx_codec_err_t ctrl_get_display_size(vpx_codec_alg_priv_t *ctx,
                                             int ctrl_id, va_list args) {
546
547
548
  int *const display_size = va_arg(args, int *);

  if (display_size) {
549
550
551
552
    if (ctx->pbi) {
      const VP9_COMMON *const cm = &ctx->pbi->common;
      display_size[0] = cm->display_width;
      display_size[1] = cm->display_height;
553
554
555
556
557
558
559
560
561
    } else {
      return VPX_CODEC_ERROR;
    }
    return VPX_CODEC_OK;
  } else {
    return VPX_CODEC_INVALID_PARAM;
  }
}

562
563
static vpx_codec_err_t ctrl_set_invert_tile_order(vpx_codec_alg_priv_t *ctx,
                                                  int ctr_id, va_list args) {
564
565
566
567
  ctx->invert_tile_order = va_arg(args, int);
  return VPX_CODEC_OK;
}

568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
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},

  // 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
586
  { -1, NULL},
John Koleszar's avatar
John Koleszar committed
587
588
589
590
591
};

#ifndef VERSION_STRING
#define VERSION_STRING
#endif
592
593
CODEC_INTERFACE(vpx_codec_vp9_dx) = {
  "WebM Project VP9 Decoder" VERSION_STRING,
John Koleszar's avatar
John Koleszar committed
594
  VPX_CODEC_INTERNAL_ABI_VERSION,
595
  VPX_CODEC_CAP_DECODER | VP9_CAP_POSTPROC |
596
597
598
599
600
601
      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
602
  { // NOLINT
603
604
605
606
607
    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
608
  },
609
  { // NOLINT
John Koleszar's avatar
John Koleszar committed
610
611
612
613
614
615
616
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED
  }
John Koleszar's avatar
John Koleszar committed
617
};