vp9_dx_iface.c 20.9 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
50
  vpx_image_t             img;
  int                     img_setup;
  int                     img_avail;
51
  int                     invert_tile_order;
52
53
54
55
56

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

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

69
70
71
    vp9_zero(*alg_priv);

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

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

88
89
90
91
92
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
93

94
95
  vpx_free(ctx);

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

99
100
101
102
103
104
105
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];

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

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

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

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

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

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

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

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

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

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

174
175
176
177
178
179
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);
}

180
181
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
182
183
184
  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
185
  memcpy(si, &ctx->si, sz);
186
  si->sz = (unsigned int)sz;
John Koleszar's avatar
John Koleszar committed
187

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

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

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

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

202
  cm->new_fb_idx = -1;
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
247

  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) {
248
  VP9DecoderConfig oxcf;
249
250
251
252
253
254
  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;

255
  ctx->pbi = vp9_decoder_create(&oxcf);
256
257
258
259
260
261
262
263
264
265
266
267
268
269
  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
270
271
272
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) {
273
274
275
276
  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
277

John Koleszar's avatar
John Koleszar committed
278
  ctx->img_avail = 0;
John Koleszar's avatar
John Koleszar committed
279

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

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

John Koleszar's avatar
John Koleszar committed
297
298
299
    ctx->decoder_init = 1;
  }

300
301
302
303
304
  // 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;

305
  cm = &ctx->pbi->common;
John Koleszar's avatar
John Koleszar committed
306

307
308
  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
309

310
311
  if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)
    set_ppflags(ctx, &flags);
John Koleszar's avatar
John Koleszar committed
312

313
314
  if (vp9_get_raw_frame(ctx->pbi, &sd, &time_stamp, &time_end_stamp, &flags))
    return update_error_state(ctx, &cm->error);
315

316
317
318
  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
319

320
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
321
322
}

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

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

344
  if ((marker & 0xe0) == 0xc0) {
Johann's avatar
Johann committed
345
346
347
    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
348

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

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

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

      *count = frames;
    }
  }
}

378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
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;
}

400
401
402
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) {
403
  const uint8_t *data_start = data;
404
405
406
407
  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
408

409
410
  if (data == NULL || data_sz == 0)
    return VPX_CODEC_INVALID_PARAM;
411

412
  parse_superframe_index(data, data_sz, frame_sizes, &frame_count,
413
                         ctx->decrypt_cb, ctx->decrypt_state);
414

415
416
  if (frame_count > 0) {
    int i;
John Koleszar's avatar
John Koleszar committed
417

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

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

440
  return VPX_CODEC_OK;
441
442
}

443
444
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
445
446
447
  vpx_image_t *img = NULL;

  if (ctx->img_avail) {
448
449
    // 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
450
451
452
    if (!(*iter)) {
      img = &ctx->img;
      *iter = img;
John Koleszar's avatar
John Koleszar committed
453
    }
John Koleszar's avatar
John Koleszar committed
454
  }
455
  ctx->img_avail = 0;
John Koleszar's avatar
John Koleszar committed
456

John Koleszar's avatar
John Koleszar committed
457
  return img;
John Koleszar's avatar
John Koleszar committed
458
459
}

460
static vpx_codec_err_t decoder_set_fb_fn(
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
    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;
}

478
479
static vpx_codec_err_t ctrl_set_reference(vpx_codec_alg_priv_t *ctx,
                                          int ctr_id, va_list args) {
480
  vpx_ref_frame_t *const data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
481

John Koleszar's avatar
John Koleszar committed
482
  if (data) {
483
    vpx_ref_frame_t *const frame = (vpx_ref_frame_t *)data;
John Koleszar's avatar
John Koleszar committed
484
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
485

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

494
495
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
496
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
497

John Koleszar's avatar
John Koleszar committed
498
499
500
  if (data) {
    vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
501

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

John Koleszar's avatar
John Koleszar committed
504
505
    return vp9_copy_reference_dec(ctx->pbi,
                                  (VP9_REFFRAME)frame->frame_type, &sd);
506
  } else {
John Koleszar's avatar
John Koleszar committed
507
    return VPX_CODEC_INVALID_PARAM;
508
  }
John Koleszar's avatar
John Koleszar committed
509
510
}

511
512
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
513
514
515
516
517
518
519
520
521
522
523
524
525
  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;
  }
}

526
527
static vpx_codec_err_t ctrl_set_postproc(vpx_codec_alg_priv_t *ctx,
                                         int ctr_id, va_list args) {
528
#if CONFIG_VP9_POSTPROC
John Koleszar's avatar
John Koleszar committed
529
  vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
John Koleszar's avatar
John Koleszar committed
530

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

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

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

John Koleszar's avatar
John Koleszar committed
550
551
552
553
554
555
  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);
  }
556

John Koleszar's avatar
John Koleszar committed
557
  return VPX_CODEC_OK;
558
#else
John Koleszar's avatar
John Koleszar committed
559
  return VPX_CODEC_INCAPABLE;
560
561
#endif
}
John Koleszar's avatar
John Koleszar committed
562

563
564
static vpx_codec_err_t ctrl_get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
                                                 int ctrl_id, va_list args) {
565
  int *const update_info = va_arg(args, int *);
566

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


579
580
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
581
  int *corrupted = va_arg(args, int *);
582

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

594
595
static vpx_codec_err_t ctrl_get_display_size(vpx_codec_alg_priv_t *ctx,
                                             int ctrl_id, va_list args) {
596
597
598
  int *const display_size = va_arg(args, int *);

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

612
613
static vpx_codec_err_t ctrl_set_invert_tile_order(vpx_codec_alg_priv_t *ctx,
                                                  int ctr_id, va_list args) {
614
615
616
617
  ctx->invert_tile_order = va_arg(args, int);
  return VPX_CODEC_OK;
}

618
619
620
621
622
623
624
625
626
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;
}

627
628
629
630
631
632
633
634
635
636
637
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},
638
  {VPXD_SET_DECRYPTOR,            ctrl_set_decryptor},
639
640
641
642
643
644
645

  // 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
646
  { -1, NULL},
John Koleszar's avatar
John Koleszar committed
647
648
649
650
651
};

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