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
13
 */


#include <stdlib.h>
#include <string.h>
14
15
16
#include "vpx/vpx_decoder.h"
#include "vpx/vp8dx.h"
#include "vpx/internal/vpx_codec_internal.h"
17
#include "./vpx_version.h"
18
19
20
#include "vp9/decoder/vp9_onyxd.h"
#include "vp9/decoder/vp9_onyxd_int.h"
#include "vp9/decoder/vp9_read_bit_buffer.h"
John Koleszar's avatar
John Koleszar committed
21
#include "vp9/vp9_iface_common.h"
John Koleszar's avatar
John Koleszar committed
22

23
#define VP9_CAP_POSTPROC (CONFIG_VP9_POSTPROC ? VPX_CODEC_CAP_POSTPROC : 0)
24
typedef vpx_codec_stream_info_t  vp9_stream_info_t;
John Koleszar's avatar
John Koleszar committed
25
26

/* Structures for handling memory allocations */
John Koleszar's avatar
John Koleszar committed
27
typedef enum {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
28
  VP9_SEG_ALG_PRIV = 256,
29
  VP9_SEG_MAX
John Koleszar's avatar
John Koleszar committed
30
} mem_seg_id_t;
31
#define NELEMENTS(x) ((int)(sizeof(x)/sizeof(x[0])))
John Koleszar's avatar
John Koleszar committed
32

33
34
static unsigned long priv_sz(const vpx_codec_dec_cfg_t *si,
                             vpx_codec_flags_t flags);
John Koleszar's avatar
John Koleszar committed
35

36
37
38
static const mem_req_t vp9_mem_req_segs[] = {
  {VP9_SEG_ALG_PRIV, 0, 8, VPX_CODEC_MEM_ZERO, priv_sz},
  {VP9_SEG_MAX, 0, 0, 0, NULL}
John Koleszar's avatar
John Koleszar committed
39
40
};

John Koleszar's avatar
John Koleszar committed
41
42
struct vpx_codec_alg_priv {
  vpx_codec_priv_t        base;
43
  vpx_codec_mmap_t        mmaps[NELEMENTS(vp9_mem_req_segs) - 1];
John Koleszar's avatar
John Koleszar committed
44
  vpx_codec_dec_cfg_t     cfg;
45
  vp9_stream_info_t       si;
John Koleszar's avatar
John Koleszar committed
46
47
  int                     defer_alloc;
  int                     decoder_init;
48
  VP9D_PTR                pbi;
John Koleszar's avatar
John Koleszar committed
49
50
  int                     postproc_cfg_set;
  vp8_postproc_cfg_t      postproc_cfg;
51
#if CONFIG_POSTPROC_VISUALIZER
John Koleszar's avatar
John Koleszar committed
52
53
54
55
56
  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;
57
#endif
John Koleszar's avatar
John Koleszar committed
58
59
60
  vpx_image_t             img;
  int                     img_setup;
  int                     img_avail;
61
  int                     invert_tile_order;
John Koleszar's avatar
John Koleszar committed
62
63
};

64
65
static unsigned long priv_sz(const vpx_codec_dec_cfg_t *si,
                             vpx_codec_flags_t flags) {
John Koleszar's avatar
John Koleszar committed
66
67
68
69
70
71
72
  /* Although this declaration is constant, we can't use it in the requested
   * segments list because we want to define the requested segments list
   * before defining the private type (so that the number of memory maps is
   * known)
   */
  (void)si;
  return sizeof(vpx_codec_alg_priv_t);
John Koleszar's avatar
John Koleszar committed
73
74
}

75
static void vp9_init_ctx(vpx_codec_ctx_t *ctx, const vpx_codec_mmap_t *mmap) {
John Koleszar's avatar
John Koleszar committed
76
  int i;
John Koleszar's avatar
John Koleszar committed
77

John Koleszar's avatar
John Koleszar committed
78
79
80
81
  ctx->priv = mmap->base;
  ctx->priv->sz = sizeof(*ctx->priv);
  ctx->priv->iface = ctx->iface;
  ctx->priv->alg_priv = mmap->base;
John Koleszar's avatar
John Koleszar committed
82

John Koleszar's avatar
John Koleszar committed
83
  for (i = 0; i < NELEMENTS(ctx->priv->alg_priv->mmaps); i++)
84
    ctx->priv->alg_priv->mmaps[i].id = vp9_mem_req_segs[i].id;
John Koleszar's avatar
John Koleszar committed
85

John Koleszar's avatar
John Koleszar committed
86
87
88
  ctx->priv->alg_priv->mmaps[0] = *mmap;
  ctx->priv->alg_priv->si.sz = sizeof(ctx->priv->alg_priv->si);
  ctx->priv->init_flags = ctx->init_flags;
John Koleszar's avatar
John Koleszar committed
89

John Koleszar's avatar
John Koleszar committed
90
91
92
93
94
  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
95
96
}

97
static void vp9_finalize_mmaps(vpx_codec_alg_priv_t *ctx) {
John Koleszar's avatar
John Koleszar committed
98
  /* nothing to clean up */
John Koleszar's avatar
John Koleszar committed
99
100
}

101
static vpx_codec_err_t vp9_init(vpx_codec_ctx_t *ctx,
John Koleszar's avatar
John Koleszar committed
102
                                vpx_codec_priv_enc_mr_cfg_t *data) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
103
  vpx_codec_err_t res = VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
104

Dmitry Kovalev's avatar
Dmitry Kovalev committed
105
106
107
  // 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
108
109
  if (!ctx->priv) {
    vpx_codec_mmap_t mmap;
John Koleszar's avatar
John Koleszar committed
110

111
    mmap.id = vp9_mem_req_segs[0].id;
John Koleszar's avatar
John Koleszar committed
112
    mmap.sz = sizeof(vpx_codec_alg_priv_t);
113
114
    mmap.align = vp9_mem_req_segs[0].align;
    mmap.flags = vp9_mem_req_segs[0].flags;
John Koleszar's avatar
John Koleszar committed
115

116
    res = vpx_mmap_alloc(&mmap);
John Koleszar's avatar
John Koleszar committed
117
    if (!res) {
118
      vp9_init_ctx(ctx, &mmap);
John Koleszar's avatar
John Koleszar committed
119

John Koleszar's avatar
John Koleszar committed
120
      ctx->priv->alg_priv->defer_alloc = 1;
John Koleszar's avatar
John Koleszar committed
121
    }
John Koleszar's avatar
John Koleszar committed
122
  }
John Koleszar's avatar
John Koleszar committed
123

John Koleszar's avatar
John Koleszar committed
124
  return res;
John Koleszar's avatar
John Koleszar committed
125
126
}

127
static vpx_codec_err_t vp9_destroy(vpx_codec_alg_priv_t *ctx) {
John Koleszar's avatar
John Koleszar committed
128
  int i;
John Koleszar's avatar
John Koleszar committed
129

130
  vp9_remove_decompressor(ctx->pbi);
John Koleszar's avatar
John Koleszar committed
131

John Koleszar's avatar
John Koleszar committed
132
133
134
135
  for (i = NELEMENTS(ctx->mmaps) - 1; i >= 0; i--) {
    if (ctx->mmaps[i].dtor)
      ctx->mmaps[i].dtor(&ctx->mmaps[i]);
  }
John Koleszar's avatar
John Koleszar committed
136

John Koleszar's avatar
John Koleszar committed
137
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
138
139
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
140
static vpx_codec_err_t vp9_peek_si(const uint8_t *data, unsigned int data_sz,
John Koleszar's avatar
John Koleszar committed
141
                                   vpx_codec_stream_info_t *si) {
James Zern's avatar
James Zern committed
142
  if (data_sz <= 8) return VPX_CODEC_UNSUP_BITSTREAM;
143
144
145
146
  if (data + data_sz <= data) return VPX_CODEC_INVALID_PARAM;

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

148
149
150
  {
    struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
    const int frame_marker = vp9_rb_read_literal(&rb, 2);
151
152
153
    const int version = vp9_rb_read_bit(&rb);
    (void) vp9_rb_read_bit(&rb);  // unused version bit

154
155
    if (frame_marker != VP9_FRAME_MARKER)
      return VPX_CODEC_UNSUP_BITSTREAM;
156
157
158
#if CONFIG_NON420
    if (version > 1) return VPX_CODEC_UNSUP_BITSTREAM;
#else
James Zern's avatar
James Zern committed
159
    if (version != 0) return VPX_CODEC_UNSUP_BITSTREAM;
160
161
162
163
164
#endif

    if (vp9_rb_read_bit(&rb)) {  // show an existing frame
      return VPX_CODEC_OK;
    }
James Zern's avatar
James Zern committed
165

166
    si->is_kf = !vp9_rb_read_bit(&rb);
James Zern's avatar
James Zern committed
167
    if (si->is_kf) {
168
169
      const int sRGB = 7;
      int colorspace;
John Koleszar's avatar
John Koleszar committed
170

171
172
      rb.bit_offset += 1;  // show frame
      rb.bit_offset += 1;  // error resilient
John Koleszar's avatar
John Koleszar committed
173

174
175
176
      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) {
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
        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
199
    }
John Koleszar's avatar
John Koleszar committed
200
201
  }

202
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
203
204
}

205
static vpx_codec_err_t vp9_get_si(vpx_codec_alg_priv_t    *ctx,
John Koleszar's avatar
John Koleszar committed
206
                                  vpx_codec_stream_info_t *si) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
207
208
209
  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
210
211
  memcpy(si, &ctx->si, sz);
  si->sz = sz;
John Koleszar's avatar
John Koleszar committed
212

John Koleszar's avatar
John Koleszar committed
213
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
214
215
216
}


Dmitry Kovalev's avatar
Dmitry Kovalev committed
217
218
219
220
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
221

Dmitry Kovalev's avatar
Dmitry Kovalev committed
222
  return error->error_code;
John Koleszar's avatar
John Koleszar committed
223
224
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
225
226
227
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) {
John Koleszar's avatar
John Koleszar committed
228
  vpx_codec_err_t res = VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
229

John Koleszar's avatar
John Koleszar committed
230
  ctx->img_avail = 0;
John Koleszar's avatar
John Koleszar committed
231

John Koleszar's avatar
John Koleszar committed
232
233
234
235
236
  /* 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.
   */
  if (!ctx->si.h)
237
    res = ctx->base.iface->dec.peek_si(*data, data_sz, &ctx->si);
John Koleszar's avatar
John Koleszar committed
238
239


John Koleszar's avatar
John Koleszar committed
240
241
242
  /* Perform deferred allocations, if required */
  if (!res && ctx->defer_alloc) {
    int i;
John Koleszar's avatar
John Koleszar committed
243

John Koleszar's avatar
John Koleszar committed
244
245
    for (i = 1; !res && i < NELEMENTS(ctx->mmaps); i++) {
      vpx_codec_dec_cfg_t cfg;
John Koleszar's avatar
John Koleszar committed
246

John Koleszar's avatar
John Koleszar committed
247
248
      cfg.w = ctx->si.w;
      cfg.h = ctx->si.h;
249
250
251
252
      ctx->mmaps[i].id = vp9_mem_req_segs[i].id;
      ctx->mmaps[i].sz = vp9_mem_req_segs[i].sz;
      ctx->mmaps[i].align = vp9_mem_req_segs[i].align;
      ctx->mmaps[i].flags = vp9_mem_req_segs[i].flags;
John Koleszar's avatar
John Koleszar committed
253

John Koleszar's avatar
John Koleszar committed
254
      if (!ctx->mmaps[i].sz)
255
        ctx->mmaps[i].sz = vp9_mem_req_segs[i].calc_sz(&cfg,
John Koleszar's avatar
John Koleszar committed
256
                                                       ctx->base.init_flags);
John Koleszar's avatar
John Koleszar committed
257

258
      res = vpx_mmap_alloc(&ctx->mmaps[i]);
John Koleszar's avatar
John Koleszar committed
259
260
    }

John Koleszar's avatar
John Koleszar committed
261
    if (!res)
262
      vp9_finalize_mmaps(ctx);
John Koleszar's avatar
John Koleszar committed
263
264
265
266
267
268

    ctx->defer_alloc = 0;
  }

  /* Initialize the decoder instance on the first frame*/
  if (!res && !ctx->decoder_init) {
269
    res = vpx_validate_mmaps(&ctx->si, ctx->mmaps,
270
                             vp9_mem_req_segs, NELEMENTS(vp9_mem_req_segs),
271
                             ctx->base.init_flags);
John Koleszar's avatar
John Koleszar committed
272
273

    if (!res) {
274
275
      VP9D_CONFIG oxcf;
      VP9D_PTR optr;
John Koleszar's avatar
John Koleszar committed
276

277
      vp9_initialize_dec();
John Koleszar's avatar
John Koleszar committed
278

279
280
281
      oxcf.width = ctx->si.w;
      oxcf.height = ctx->si.h;
      oxcf.version = 9;
John Koleszar's avatar
John Koleszar committed
282
283
      oxcf.postprocess = 0;
      oxcf.max_threads = ctx->cfg.threads;
284
      oxcf.inv_tile_order = ctx->invert_tile_order;
285
      optr = vp9_create_decompressor(&oxcf);
John Koleszar's avatar
John Koleszar committed
286

Dmitry Kovalev's avatar
Dmitry Kovalev committed
287
288
289
290
291
      // 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)) {
        ctx->postproc_cfg.post_proc_flag = VP8_DEBLOCK | VP8_DEMACROBLOCK;
John Koleszar's avatar
John Koleszar committed
292
293
294
295
        ctx->postproc_cfg.deblocking_level = 4;
        ctx->postproc_cfg.noise_level = 0;
      }

296
      if (!optr)
John Koleszar's avatar
John Koleszar committed
297
        res = VPX_CODEC_ERROR;
298
      else
John Koleszar's avatar
John Koleszar committed
299
        ctx->pbi = optr;
John Koleszar's avatar
John Koleszar committed
300
301
    }

John Koleszar's avatar
John Koleszar committed
302
303
304
305
306
307
    ctx->decoder_init = 1;
  }

  if (!res && ctx->pbi) {
    YV12_BUFFER_CONFIG sd;
    int64_t time_stamp = 0, time_end_stamp = 0;
308
    vp9_ppflags_t flags = {0};
John Koleszar's avatar
John Koleszar committed
309

John Koleszar's avatar
John Koleszar committed
310
    if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) {
311
      flags.post_proc_flag =
312
#if CONFIG_POSTPROC_VISUALIZER
Dmitry Kovalev's avatar
Dmitry Kovalev committed
313
314
315
316
          (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) |
317
#endif
318
319
          ctx->postproc_cfg.post_proc_flag;

Dmitry Kovalev's avatar
Dmitry Kovalev committed
320
321
      flags.deblocking_level = ctx->postproc_cfg.deblocking_level;
      flags.noise_level = ctx->postproc_cfg.noise_level;
322
#if CONFIG_POSTPROC_VISUALIZER
John Koleszar's avatar
John Koleszar committed
323
324
      flags.display_ref_frame_flag = ctx->dbg_color_ref_frame_flag;
      flags.display_mb_modes_flag = ctx->dbg_color_mb_modes_flag;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
325
326
      flags.display_b_modes_flag = ctx->dbg_color_b_modes_flag;
      flags.display_mv_flag = ctx->dbg_display_mv_flag;
327
#endif
John Koleszar's avatar
John Koleszar committed
328
    }
John Koleszar's avatar
John Koleszar committed
329

330
    if (vp9_receive_compressed_data(ctx->pbi, data_sz, data, deadline)) {
331
      VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
John Koleszar's avatar
John Koleszar committed
332
333
      res = update_error_state(ctx, &pbi->common.error);
    }
John Koleszar's avatar
John Koleszar committed
334

335
336
    if (!res && 0 == vp9_get_raw_frame(ctx->pbi, &sd, &time_stamp,
                                       &time_end_stamp, &flags)) {
John Koleszar's avatar
John Koleszar committed
337
338
      yuvconfig2image(&ctx->img, &sd, user_priv);
      ctx->img_avail = 1;
John Koleszar's avatar
John Koleszar committed
339
    }
John Koleszar's avatar
John Koleszar committed
340
  }
John Koleszar's avatar
John Koleszar committed
341

John Koleszar's avatar
John Koleszar committed
342
  return res;
John Koleszar's avatar
John Koleszar committed
343
344
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
345
346
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
347
348
349
350
351
352
  uint8_t marker;

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

353
  if ((marker & 0xe0) == 0xc0) {
Johann's avatar
Johann committed
354
355
356
    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
357
358
359

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

      for (i = 0; i < frames; i++) {
Johann's avatar
Johann committed
364
        uint32_t this_sz = 0;
John Koleszar's avatar
John Koleszar committed
365
366
367
368
369
370
371
372
373
374
375

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

      *count = frames;
    }
  }
}

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

387
388
  if (data == NULL || data_sz == 0) return VPX_CODEC_INVALID_PARAM;

John Koleszar's avatar
John Koleszar committed
389
  parse_superframe_index(data, data_sz, sizes, &frames_this_pts);
390
391

  do {
John Koleszar's avatar
John Koleszar committed
392
    // Skip over the superframe index, if present
393
    if (data_sz && (*data_start & 0xe0) == 0xc0) {
John Koleszar's avatar
John Koleszar committed
394
      const uint8_t marker = *data_start;
Johann's avatar
Johann committed
395
396
397
      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
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421

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

422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
    res = decode_one(ctx, &data_start, data_sz, user_priv, deadline);
    assert(data_start >= data);
    assert(data_start <= data_end);

    /* Early exit if there was a decode error */
    if (res)
      break;

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

    data_sz = data_end - data_start;
  } while (data_start < data_end);
  return res;
}

439
static vpx_image_t *vp9_get_frame(vpx_codec_alg_priv_t  *ctx,
John Koleszar's avatar
John Koleszar committed
440
441
442
443
444
445
446
447
448
449
                                  vpx_codec_iter_t      *iter) {
  vpx_image_t *img = NULL;

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

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

Dmitry Kovalev's avatar
Dmitry Kovalev committed
457
458
459
460
461
static vpx_codec_err_t vp9_xma_get_mmap(const vpx_codec_ctx_t *ctx,
                                        vpx_codec_mmap_t *mmap,
                                        vpx_codec_iter_t *iter) {
  vpx_codec_err_t res;
  const mem_req_t *seg_iter = *iter;
John Koleszar's avatar
John Koleszar committed
462
463
464
465

  /* Get address of next segment request */
  do {
    if (!seg_iter)
466
467
      seg_iter = vp9_mem_req_segs;
    else if (seg_iter->id != VP9_SEG_MAX)
John Koleszar's avatar
John Koleszar committed
468
469
470
471
      seg_iter++;

    *iter = (vpx_codec_iter_t)seg_iter;

472
    if (seg_iter->id != VP9_SEG_MAX) {
John Koleszar's avatar
John Koleszar committed
473
474
475
476
477
478
479
480
481
      mmap->id = seg_iter->id;
      mmap->sz = seg_iter->sz;
      mmap->align = seg_iter->align;
      mmap->flags = seg_iter->flags;

      if (!seg_iter->sz)
        mmap->sz = seg_iter->calc_sz(ctx->config.dec, ctx->init_flags);

      res = VPX_CODEC_OK;
482
    } else {
John Koleszar's avatar
John Koleszar committed
483
      res = VPX_CODEC_LIST_END;
484
    }
John Koleszar's avatar
John Koleszar committed
485
486
487
  } while (!mmap->sz && res != VPX_CODEC_LIST_END);

  return res;
John Koleszar's avatar
John Koleszar committed
488
489
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
490
static vpx_codec_err_t vp9_xma_set_mmap(vpx_codec_ctx_t *ctx,
John Koleszar's avatar
John Koleszar committed
491
492
493
494
495
                                        const vpx_codec_mmap_t  *mmap) {
  vpx_codec_err_t res = VPX_CODEC_MEM_ERROR;
  int i, done;

  if (!ctx->priv) {
496
    if (mmap->id == VP9_SEG_ALG_PRIV) {
John Koleszar's avatar
John Koleszar committed
497
      if (!ctx->priv) {
498
        vp9_init_ctx(ctx, mmap);
John Koleszar's avatar
John Koleszar committed
499
500
        res = VPX_CODEC_OK;
      }
John Koleszar's avatar
John Koleszar committed
501
    }
John Koleszar's avatar
John Koleszar committed
502
  }
John Koleszar's avatar
John Koleszar committed
503

John Koleszar's avatar
John Koleszar committed
504
  done = 1;
John Koleszar's avatar
John Koleszar committed
505

John Koleszar's avatar
John Koleszar committed
506
507
508
509
510
511
  if (!res && ctx->priv->alg_priv) {
    for (i = 0; i < NELEMENTS(ctx->priv->alg_priv->mmaps); i++) {
      if (ctx->priv->alg_priv->mmaps[i].id == mmap->id)
        if (!ctx->priv->alg_priv->mmaps[i].base) {
          ctx->priv->alg_priv->mmaps[i] = *mmap;
          res = VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
512
513
        }

John Koleszar's avatar
John Koleszar committed
514
      done &= (ctx->priv->alg_priv->mmaps[i].base != NULL);
John Koleszar's avatar
John Koleszar committed
515
    }
John Koleszar's avatar
John Koleszar committed
516
517
518
  }

  if (done && !res) {
519
    vp9_finalize_mmaps(ctx->priv->alg_priv);
John Koleszar's avatar
John Koleszar committed
520
    res = ctx->iface->init(ctx, NULL);
John Koleszar's avatar
John Koleszar committed
521
  }
John Koleszar's avatar
John Koleszar committed
522

John Koleszar's avatar
John Koleszar committed
523
  return res;
John Koleszar's avatar
John Koleszar committed
524
525
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
526
static vpx_codec_err_t set_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
527
                                     va_list args) {
John Koleszar's avatar
John Koleszar committed
528
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
529

John Koleszar's avatar
John Koleszar committed
530
531
532
  if (data) {
    vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
533

John Koleszar's avatar
John Koleszar committed
534
    image2yuvconfig(&frame->img, &sd);
535
536
    return vp9_set_reference_dec(ctx->pbi,
                                 (VP9_REFFRAME)frame->frame_type, &sd);
537
  } else {
John Koleszar's avatar
John Koleszar committed
538
    return VPX_CODEC_INVALID_PARAM;
539
  }
John Koleszar's avatar
John Koleszar committed
540
541
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
542
static vpx_codec_err_t copy_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
543
                                      va_list args) {
John Koleszar's avatar
John Koleszar committed
544
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
545

John Koleszar's avatar
John Koleszar committed
546
547
548
  if (data) {
    vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
549

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

John Koleszar's avatar
John Koleszar committed
552
553
    return vp9_copy_reference_dec(ctx->pbi,
                                  (VP9_REFFRAME)frame->frame_type, &sd);
554
  } else {
John Koleszar's avatar
John Koleszar committed
555
    return VPX_CODEC_INVALID_PARAM;
556
  }
John Koleszar's avatar
John Koleszar committed
557
558
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
559
static vpx_codec_err_t get_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
John Koleszar's avatar
John Koleszar committed
560
561
562
563
564
565
566
567
568
569
570
571
572
573
                                     va_list args) {
  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;
  }
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
574
static vpx_codec_err_t set_postproc(vpx_codec_alg_priv_t *ctx, int ctr_id,
575
                                    va_list args) {
576
#if CONFIG_VP9_POSTPROC
John Koleszar's avatar
John Koleszar committed
577
  vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
John Koleszar's avatar
John Koleszar committed
578

John Koleszar's avatar
John Koleszar committed
579
580
581
582
  if (data) {
    ctx->postproc_cfg_set = 1;
    ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data);
    return VPX_CODEC_OK;
583
  } else {
John Koleszar's avatar
John Koleszar committed
584
    return VPX_CODEC_INVALID_PARAM;
585
  }
John Koleszar's avatar
John Koleszar committed
586
#else
John Koleszar's avatar
John Koleszar committed
587
  return VPX_CODEC_INCAPABLE;
John Koleszar's avatar
John Koleszar committed
588
589
590
#endif
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
591
static vpx_codec_err_t set_dbg_options(vpx_codec_alg_priv_t *ctx, int ctrl_id,
592
                                       va_list args) {
593
#if CONFIG_POSTPROC_VISUALIZER && CONFIG_POSTPROC
John Koleszar's avatar
John Koleszar committed
594
  int data = va_arg(args, int);
595
596
597

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

John Koleszar's avatar
John Koleszar committed
598
599
600
601
602
603
  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);
  }
604

John Koleszar's avatar
John Koleszar committed
605
  return VPX_CODEC_OK;
606
#else
John Koleszar's avatar
John Koleszar committed
607
  return VPX_CODEC_INCAPABLE;
608
609
#endif
}
John Koleszar's avatar
John Koleszar committed
610

611
static vpx_codec_err_t get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
612
                                            int ctrl_id, va_list args) {
John Koleszar's avatar
John Koleszar committed
613
  int *update_info = va_arg(args, int *);
614
  VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
615

John Koleszar's avatar
John Koleszar committed
616
  if (update_info) {
617
    *update_info = pbi->refresh_frame_flags;
618

John Koleszar's avatar
John Koleszar committed
619
    return VPX_CODEC_OK;
620
  } else {
John Koleszar's avatar
John Koleszar committed
621
    return VPX_CODEC_INVALID_PARAM;
622
  }
623
624
625
}


626
static vpx_codec_err_t get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
627
                                           int ctrl_id, va_list args) {
John Koleszar's avatar
John Koleszar committed
628
  int *corrupted = va_arg(args, int *);
629

John Koleszar's avatar
John Koleszar committed
630
  if (corrupted) {
631
    VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
Yaowu Xu's avatar
Yaowu Xu committed
632
633
634
635
    if (pbi)
      *corrupted = pbi->common.frame_to_show->corrupted;
    else
      return VPX_CODEC_ERROR;
John Koleszar's avatar
John Koleszar committed
636
    return VPX_CODEC_OK;
637
  } else {
John Koleszar's avatar
John Koleszar committed
638
    return VPX_CODEC_INVALID_PARAM;
639
  }
640
641
}

642
static vpx_codec_err_t get_display_size(vpx_codec_alg_priv_t *ctx,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
643
                                        int ctrl_id, va_list args) {
644
645
646
  int *const display_size = va_arg(args, int *);

  if (display_size) {
647
    const VP9D_COMP *const pbi = (VP9D_COMP*)ctx->pbi;
648
649
650
651
652
653
654
655
656
657
658
659
    if (pbi) {
      display_size[0] = pbi->common.display_width;
      display_size[1] = pbi->common.display_height;
    } else {
      return VPX_CODEC_ERROR;
    }
    return VPX_CODEC_OK;
  } else {
    return VPX_CODEC_INVALID_PARAM;
  }
}

660
661
662
663
664
665
666
static vpx_codec_err_t set_invert_tile_order(vpx_codec_alg_priv_t *ctx,
                                             int ctr_id,
                                             va_list args) {
  ctx->invert_tile_order = va_arg(args, int);
  return VPX_CODEC_OK;
}

667
static vpx_codec_ctrl_fn_map_t ctf_maps[] = {
668
669
670
671
672
673
674
675
676
  {VP8_SET_REFERENCE,             set_reference},
  {VP8_COPY_REFERENCE,            copy_reference},
  {VP8_SET_POSTPROC,              set_postproc},
  {VP8_SET_DBG_COLOR_REF_FRAME,   set_dbg_options},
  {VP8_SET_DBG_COLOR_MB_MODES,    set_dbg_options},
  {VP8_SET_DBG_COLOR_B_MODES,     set_dbg_options},
  {VP8_SET_DBG_DISPLAY_MV,        set_dbg_options},
  {VP8D_GET_LAST_REF_UPDATES,     get_last_ref_updates},
  {VP8D_GET_FRAME_CORRUPTED,      get_frame_corrupted},
John Koleszar's avatar
John Koleszar committed
677
  {VP9_GET_REFERENCE,             get_reference},
678
  {VP9D_GET_DISPLAY_SIZE,         get_display_size},
679
  {VP9_INVERT_TILE_DECODE_ORDER,  set_invert_tile_order},
John Koleszar's avatar
John Koleszar committed
680
  { -1, NULL},
John Koleszar's avatar
John Koleszar committed
681
682
683
684
685
686
};


#ifndef VERSION_STRING
#define VERSION_STRING
#endif
687
688
CODEC_INTERFACE(vpx_codec_vp9_dx) = {
  "WebM Project VP9 Decoder" VERSION_STRING,
John Koleszar's avatar
John Koleszar committed
689
  VPX_CODEC_INTERNAL_ABI_VERSION,
690
  VPX_CODEC_CAP_DECODER | VP9_CAP_POSTPROC,
John Koleszar's avatar
John Koleszar committed
691
  /* vpx_codec_caps_t          caps; */
692
693
  vp9_init,         /* vpx_codec_init_fn_t       init; */
  vp9_destroy,      /* vpx_codec_destroy_fn_t    destroy; */
694
  ctf_maps,         /* vpx_codec_ctrl_fn_map_t  *ctrl_maps; */
695
696
  vp9_xma_get_mmap, /* vpx_codec_get_mmap_fn_t   get_mmap; */
  vp9_xma_set_mmap, /* vpx_codec_set_mmap_fn_t   set_mmap; */
697
  { // NOLINT
698
699
    vp9_peek_si,      /* vpx_codec_peek_si_fn_t    peek_si; */
    vp9_get_si,       /* vpx_codec_get_si_fn_t     get_si; */
700
    vp9_decode,       /* vpx_codec_decode_fn_t     decode; */
701
    vp9_get_frame,    /* vpx_codec_frame_get_fn_t  frame_get; */
John Koleszar's avatar
John Koleszar committed
702
  },
703
  { // NOLINT
John Koleszar's avatar
John Koleszar committed
704
705
706
707
708
709
710
711
    /* encoder functions */
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED
  }
John Koleszar's avatar
John Koleszar committed
712
};