vp9_dx_iface.c 24.3 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 {
28
29
  VP9_SEG_ALG_PRIV     = 256,
  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;
Frank Galligan's avatar
Frank Galligan committed
62
  int                     fb_lru;
63
64
65
66
67
68

  /* External buffer info to save for VP9 common. */
  vpx_codec_frame_buffer_t *fb_list;  // External frame buffers
  int fb_count;  // Total number of frame buffers
  vpx_realloc_frame_buffer_cb_fn_t realloc_fb_cb;
  void *user_priv;  // Private data associated with the external frame buffers.
John Koleszar's avatar
John Koleszar committed
69
70
};

71
72
static unsigned long priv_sz(const vpx_codec_dec_cfg_t *si,
                             vpx_codec_flags_t flags) {
John Koleszar's avatar
John Koleszar committed
73
74
75
76
77
78
79
  /* 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
80
81
}

82
static void vp9_init_ctx(vpx_codec_ctx_t *ctx, const vpx_codec_mmap_t *mmap) {
John Koleszar's avatar
John Koleszar committed
83
  int i;
John Koleszar's avatar
John Koleszar committed
84

John Koleszar's avatar
John Koleszar committed
85
86
87
88
  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
89

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

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

John Koleszar's avatar
John Koleszar committed
97
98
99
100
101
  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
102
103
}

104
static void vp9_finalize_mmaps(vpx_codec_alg_priv_t *ctx) {
John Koleszar's avatar
John Koleszar committed
105
  /* nothing to clean up */
John Koleszar's avatar
John Koleszar committed
106
107
}

108
static vpx_codec_err_t vp9_init(vpx_codec_ctx_t *ctx,
John Koleszar's avatar
John Koleszar committed
109
                                vpx_codec_priv_enc_mr_cfg_t *data) {
John Koleszar's avatar
John Koleszar committed
110
  vpx_codec_err_t        res = VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
111

John Koleszar's avatar
John Koleszar committed
112
113
114
115
116
117
  /* 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.
   */
  if (!ctx->priv) {
    vpx_codec_mmap_t mmap;
John Koleszar's avatar
John Koleszar committed
118

119
    mmap.id = vp9_mem_req_segs[0].id;
John Koleszar's avatar
John Koleszar committed
120
    mmap.sz = sizeof(vpx_codec_alg_priv_t);
121
122
    mmap.align = vp9_mem_req_segs[0].align;
    mmap.flags = vp9_mem_req_segs[0].flags;
John Koleszar's avatar
John Koleszar committed
123

124
    res = vpx_mmap_alloc(&mmap);
John Koleszar's avatar
John Koleszar committed
125

John Koleszar's avatar
John Koleszar committed
126
    if (!res) {
127
      vp9_init_ctx(ctx, &mmap);
John Koleszar's avatar
John Koleszar committed
128

John Koleszar's avatar
John Koleszar committed
129
130
      ctx->priv->alg_priv->defer_alloc = 1;
      /*post processing level initialized to do nothing */
John Koleszar's avatar
John Koleszar committed
131
    }
John Koleszar's avatar
John Koleszar committed
132
  }
John Koleszar's avatar
John Koleszar committed
133

John Koleszar's avatar
John Koleszar committed
134
  return res;
John Koleszar's avatar
John Koleszar committed
135
136
}

137
static vpx_codec_err_t vp9_destroy(vpx_codec_alg_priv_t *ctx) {
John Koleszar's avatar
John Koleszar committed
138
  int i;
John Koleszar's avatar
John Koleszar committed
139

140
  vp9_remove_decompressor(ctx->pbi);
John Koleszar's avatar
John Koleszar committed
141

John Koleszar's avatar
John Koleszar committed
142
143
144
145
  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
146

John Koleszar's avatar
John Koleszar committed
147
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
148
149
}

150
static vpx_codec_err_t vp9_peek_si(const uint8_t         *data,
John Koleszar's avatar
John Koleszar committed
151
                                   unsigned int           data_sz,
John Koleszar's avatar
John Koleszar committed
152
                                   vpx_codec_stream_info_t *si) {
James Zern's avatar
James Zern committed
153
  if (data_sz <= 8) return VPX_CODEC_UNSUP_BITSTREAM;
154
155
156
157
  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
158

159
160
161
162
  {
    struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
    const int frame_marker = vp9_rb_read_literal(&rb, 2);
    const int version = vp9_rb_read_bit(&rb) | (vp9_rb_read_bit(&rb) << 1);
James Zern's avatar
James Zern committed
163
    if (frame_marker != 0x2) return VPX_CODEC_UNSUP_BITSTREAM;
164
165
166
#if CONFIG_NON420
    if (version > 1) return VPX_CODEC_UNSUP_BITSTREAM;
#else
James Zern's avatar
James Zern committed
167
    if (version != 0) return VPX_CODEC_UNSUP_BITSTREAM;
168
169
170
171
172
#endif

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

174
    si->is_kf = !vp9_rb_read_bit(&rb);
James Zern's avatar
James Zern committed
175
    if (si->is_kf) {
176
177
      const int sRGB = 7;
      int colorspace;
John Koleszar's avatar
John Koleszar committed
178

179
180
      rb.bit_offset += 1;  // show frame
      rb.bit_offset += 1;  // error resilient
John Koleszar's avatar
John Koleszar committed
181

182
183
184
      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) {
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
        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
207
    }
John Koleszar's avatar
John Koleszar committed
208
209
  }

210
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
211
212
}

213
static vpx_codec_err_t vp9_get_si(vpx_codec_alg_priv_t    *ctx,
John Koleszar's avatar
John Koleszar committed
214
215
                                  vpx_codec_stream_info_t *si) {
  unsigned int sz;
John Koleszar's avatar
John Koleszar committed
216

217
218
  if (si->sz >= sizeof(vp9_stream_info_t))
    sz = sizeof(vp9_stream_info_t);
John Koleszar's avatar
John Koleszar committed
219
220
  else
    sz = sizeof(vpx_codec_stream_info_t);
John Koleszar's avatar
John Koleszar committed
221

John Koleszar's avatar
John Koleszar committed
222
223
  memcpy(si, &ctx->si, sz);
  si->sz = sz;
John Koleszar's avatar
John Koleszar committed
224

John Koleszar's avatar
John Koleszar committed
225
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
226
227
228
229
230
}


static vpx_codec_err_t
update_error_state(vpx_codec_alg_priv_t                 *ctx,
John Koleszar's avatar
John Koleszar committed
231
232
                   const struct vpx_internal_error_info *error) {
  vpx_codec_err_t res;
John Koleszar's avatar
John Koleszar committed
233

John Koleszar's avatar
John Koleszar committed
234
235
236
237
  if ((res = error->error_code))
    ctx->base.err_detail = error->has_detail
                           ? error->detail
                           : NULL;
John Koleszar's avatar
John Koleszar committed
238

John Koleszar's avatar
John Koleszar committed
239
  return res;
John Koleszar's avatar
John Koleszar committed
240
241
}

242
243
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,
                                  long                   deadline) {
John Koleszar's avatar
John Koleszar committed
247
  vpx_codec_err_t res = VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
248

John Koleszar's avatar
John Koleszar committed
249
  ctx->img_avail = 0;
John Koleszar's avatar
John Koleszar committed
250

John Koleszar's avatar
John Koleszar committed
251
252
253
254
255
  /* 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)
256
    res = ctx->base.iface->dec.peek_si(*data, data_sz, &ctx->si);
John Koleszar's avatar
John Koleszar committed
257
258


John Koleszar's avatar
John Koleszar committed
259
260
261
  /* Perform deferred allocations, if required */
  if (!res && ctx->defer_alloc) {
    int i;
John Koleszar's avatar
John Koleszar committed
262

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

John Koleszar's avatar
John Koleszar committed
266
267
      cfg.w = ctx->si.w;
      cfg.h = ctx->si.h;
268
269
270
271
      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
272

John Koleszar's avatar
John Koleszar committed
273
      if (!ctx->mmaps[i].sz)
274
        ctx->mmaps[i].sz = vp9_mem_req_segs[i].calc_sz(&cfg,
John Koleszar's avatar
John Koleszar committed
275
                                                       ctx->base.init_flags);
John Koleszar's avatar
John Koleszar committed
276

277
      res = vpx_mmap_alloc(&ctx->mmaps[i]);
John Koleszar's avatar
John Koleszar committed
278
279
    }

John Koleszar's avatar
John Koleszar committed
280
    if (!res)
281
      vp9_finalize_mmaps(ctx);
John Koleszar's avatar
John Koleszar committed
282
283
284
285
286
287

    ctx->defer_alloc = 0;
  }

  /* Initialize the decoder instance on the first frame*/
  if (!res && !ctx->decoder_init) {
288
    res = vpx_validate_mmaps(&ctx->si, ctx->mmaps,
289
                             vp9_mem_req_segs, NELEMENTS(vp9_mem_req_segs),
290
                             ctx->base.init_flags);
John Koleszar's avatar
John Koleszar committed
291
292

    if (!res) {
293
294
      VP9D_CONFIG oxcf;
      VP9D_PTR optr;
John Koleszar's avatar
John Koleszar committed
295

296
      vp9_initialize_dec();
John Koleszar's avatar
John Koleszar committed
297

298
299
300
      oxcf.width = ctx->si.w;
      oxcf.height = ctx->si.h;
      oxcf.version = 9;
John Koleszar's avatar
John Koleszar committed
301
302
      oxcf.postprocess = 0;
      oxcf.max_threads = ctx->cfg.threads;
303
      oxcf.inv_tile_order = ctx->invert_tile_order;
304
      optr = vp9_create_decompressor(&oxcf);
John Koleszar's avatar
John Koleszar committed
305
306
307
308
309
310
311
312
313
314
315
316

      /* 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;
        ctx->postproc_cfg.deblocking_level = 4;
        ctx->postproc_cfg.noise_level = 0;
      }

317
      if (!optr) {
John Koleszar's avatar
John Koleszar committed
318
        res = VPX_CODEC_ERROR;
319
320
321
322
323
324
325
326
327
328
329
330
      } else {
        VP9D_COMP *const pbi = (VP9D_COMP*)optr;
        VP9_COMMON *const cm = &pbi->common;
        if (ctx->fb_list != NULL && ctx->realloc_fb_cb != NULL &&
            ctx->fb_count > 0) {
          cm->fb_list = ctx->fb_list;
          cm->fb_count = ctx->fb_count;
          cm->realloc_fb_cb = ctx->realloc_fb_cb;
          cm->user_priv = ctx->user_priv;
        } else {
          cm->fb_count = FRAME_BUFFERS;
        }
Frank Galligan's avatar
Frank Galligan committed
331
        cm->fb_lru = ctx->fb_lru;
332
333
334
335
        CHECK_MEM_ERROR(cm, cm->yv12_fb,
                        vpx_calloc(cm->fb_count, sizeof(*cm->yv12_fb)));
        CHECK_MEM_ERROR(cm, cm->fb_idx_ref_cnt,
                        vpx_calloc(cm->fb_count, sizeof(*cm->fb_idx_ref_cnt)));
Frank Galligan's avatar
Frank Galligan committed
336
337
338
339
340
        if (cm->fb_lru) {
          CHECK_MEM_ERROR(cm, cm->fb_idx_ref_lru,
                          vpx_calloc(cm->fb_count,
                                     sizeof(*cm->fb_idx_ref_lru)));
        }
John Koleszar's avatar
John Koleszar committed
341
        ctx->pbi = optr;
342
      }
John Koleszar's avatar
John Koleszar committed
343
344
    }

John Koleszar's avatar
John Koleszar committed
345
346
347
348
349
350
    ctx->decoder_init = 1;
  }

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

John Koleszar's avatar
John Koleszar committed
353
    if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) {
354
      flags.post_proc_flag =
355
#if CONFIG_POSTPROC_VISUALIZER
356
357
358
359
360
361
362
363
364
          ((ctx->dbg_color_ref_frame_flag != 0) ?
              VP9D_DEBUG_CLR_FRM_REF_BLKS : 0)
          | ((ctx->dbg_color_mb_modes_flag != 0) ?
              VP9D_DEBUG_CLR_BLK_MODES : 0)
          | ((ctx->dbg_color_b_modes_flag != 0) ?
              VP9D_DEBUG_CLR_BLK_MODES : 0)
          | ((ctx->dbg_display_mv_flag != 0) ?
              VP9D_DEBUG_DRAW_MV : 0)
          |
365
#endif
366
367
          ctx->postproc_cfg.post_proc_flag;

John Koleszar's avatar
John Koleszar committed
368
369
      flags.deblocking_level      = ctx->postproc_cfg.deblocking_level;
      flags.noise_level           = ctx->postproc_cfg.noise_level;
370
#if CONFIG_POSTPROC_VISUALIZER
John Koleszar's avatar
John Koleszar committed
371
372
373
374
      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;
375
#endif
John Koleszar's avatar
John Koleszar committed
376
    }
John Koleszar's avatar
John Koleszar committed
377

378
    if (vp9_receive_compressed_data(ctx->pbi, data_sz, data, deadline)) {
379
      VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
John Koleszar's avatar
John Koleszar committed
380
381
      res = update_error_state(ctx, &pbi->common.error);
    }
John Koleszar's avatar
John Koleszar committed
382

383
384
    if (!res && 0 == vp9_get_raw_frame(ctx->pbi, &sd, &time_stamp,
                                       &time_end_stamp, &flags)) {
John Koleszar's avatar
John Koleszar committed
385
386
      yuvconfig2image(&ctx->img, &sd, user_priv);
      ctx->img_avail = 1;
John Koleszar's avatar
John Koleszar committed
387
    }
John Koleszar's avatar
John Koleszar committed
388
  }
John Koleszar's avatar
John Koleszar committed
389

John Koleszar's avatar
John Koleszar committed
390
  return res;
John Koleszar's avatar
John Koleszar committed
391
392
}

John Koleszar's avatar
John Koleszar committed
393
394
395
396
397
398
399
400
401
402
static void parse_superframe_index(const uint8_t *data,
                                   size_t         data_sz,
                                   uint32_t       sizes[8],
                                   int           *count) {
  uint8_t marker;

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

403
  if ((marker & 0xe0) == 0xc0) {
Johann's avatar
Johann committed
404
405
406
    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
407
408
409

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

      for (i = 0; i < frames; i++) {
Johann's avatar
Johann committed
414
        uint32_t this_sz = 0;
John Koleszar's avatar
John Koleszar committed
415
416
417
418
419
420
421
422
423
424
425

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

      *count = frames;
    }
  }
}

426
427
428
429
430
431
432
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;
433
  vpx_codec_err_t res = 0;
John Koleszar's avatar
John Koleszar committed
434
435
436
  uint32_t sizes[8];
  int frames_this_pts, frame_count = 0;

437
438
  if (data == NULL || data_sz == 0) return VPX_CODEC_INVALID_PARAM;

John Koleszar's avatar
John Koleszar committed
439
  parse_superframe_index(data, data_sz, sizes, &frames_this_pts);
440
441

  do {
John Koleszar's avatar
John Koleszar committed
442
    // Skip over the superframe index, if present
443
    if (data_sz && (*data_start & 0xe0) == 0xc0) {
John Koleszar's avatar
John Koleszar committed
444
      const uint8_t marker = *data_start;
Johann's avatar
Johann committed
445
446
447
      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
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471

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

472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
    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;
}

489
static vpx_image_t *vp9_get_frame(vpx_codec_alg_priv_t  *ctx,
John Koleszar's avatar
John Koleszar committed
490
491
492
493
494
495
496
497
498
499
                                  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
500
    }
John Koleszar's avatar
John Koleszar committed
501
  }
502
  ctx->img_avail = 0;
John Koleszar's avatar
John Koleszar committed
503

John Koleszar's avatar
John Koleszar committed
504
  return img;
John Koleszar's avatar
John Koleszar committed
505
506
}

507
508
509
510
static vpx_codec_err_t vp9_set_frame_buffers(
    vpx_codec_alg_priv_t *ctx,
    vpx_codec_frame_buffer_t *fb_list, int fb_count,
    vpx_realloc_frame_buffer_cb_fn_t cb, void *user_priv) {
511
512
513
  if (fb_count < (VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS)) {
    /* The application must pass in at least VP9_MAXIMUM_REF_BUFFERS +
     * VPX_MAXIMUM_WORK_BUFFERS frame buffers. */
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
    return VPX_CODEC_INVALID_PARAM;
  } else if (!ctx->pbi) {
    /* If the decoder has already been initialized, do not accept external
     * frame buffers.
     */
    ctx->fb_list = fb_list;
    ctx->fb_count = fb_count;
    ctx->realloc_fb_cb = cb;
    ctx->user_priv = user_priv;
    return VPX_CODEC_OK;
  }

  return VPX_CODEC_ERROR;
}

529
530
531
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) {
John Koleszar's avatar
John Koleszar committed
532
533
534
535
536
537
  vpx_codec_err_t     res;
  const mem_req_t  *seg_iter = *iter;

  /* Get address of next segment request */
  do {
    if (!seg_iter)
538
539
      seg_iter = vp9_mem_req_segs;
    else if (seg_iter->id != VP9_SEG_MAX)
John Koleszar's avatar
John Koleszar committed
540
541
542
543
      seg_iter++;

    *iter = (vpx_codec_iter_t)seg_iter;

544
    if (seg_iter->id != VP9_SEG_MAX) {
John Koleszar's avatar
John Koleszar committed
545
546
547
548
549
550
551
552
553
      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;
554
    } else {
John Koleszar's avatar
John Koleszar committed
555
      res = VPX_CODEC_LIST_END;
556
    }
John Koleszar's avatar
John Koleszar committed
557
558
559
  } while (!mmap->sz && res != VPX_CODEC_LIST_END);

  return res;
John Koleszar's avatar
John Koleszar committed
560
561
}

562
static vpx_codec_err_t vp9_xma_set_mmap(vpx_codec_ctx_t         *ctx,
John Koleszar's avatar
John Koleszar committed
563
564
565
566
567
                                        const vpx_codec_mmap_t  *mmap) {
  vpx_codec_err_t res = VPX_CODEC_MEM_ERROR;
  int i, done;

  if (!ctx->priv) {
568
    if (mmap->id == VP9_SEG_ALG_PRIV) {
John Koleszar's avatar
John Koleszar committed
569
      if (!ctx->priv) {
570
        vp9_init_ctx(ctx, mmap);
John Koleszar's avatar
John Koleszar committed
571
572
        res = VPX_CODEC_OK;
      }
John Koleszar's avatar
John Koleszar committed
573
    }
John Koleszar's avatar
John Koleszar committed
574
  }
John Koleszar's avatar
John Koleszar committed
575

John Koleszar's avatar
John Koleszar committed
576
  done = 1;
John Koleszar's avatar
John Koleszar committed
577

John Koleszar's avatar
John Koleszar committed
578
579
580
581
582
583
  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
584
585
        }

John Koleszar's avatar
John Koleszar committed
586
      done &= (ctx->priv->alg_priv->mmaps[i].base != NULL);
John Koleszar's avatar
John Koleszar committed
587
    }
John Koleszar's avatar
John Koleszar committed
588
589
590
  }

  if (done && !res) {
591
    vp9_finalize_mmaps(ctx->priv->alg_priv);
John Koleszar's avatar
John Koleszar committed
592
    res = ctx->iface->init(ctx, NULL);
John Koleszar's avatar
John Koleszar committed
593
  }
John Koleszar's avatar
John Koleszar committed
594

John Koleszar's avatar
John Koleszar committed
595
  return res;
John Koleszar's avatar
John Koleszar committed
596
597
}

598
599
600
static vpx_codec_err_t set_reference(vpx_codec_alg_priv_t *ctx,
                                     int ctr_id,
                                     va_list args) {
John Koleszar's avatar
John Koleszar committed
601
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
602

John Koleszar's avatar
John Koleszar committed
603
604
605
  if (data) {
    vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
606

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

609
610
    return vp9_set_reference_dec(ctx->pbi,
                                 (VP9_REFFRAME)frame->frame_type, &sd);
611
  } else {
John Koleszar's avatar
John Koleszar committed
612
    return VPX_CODEC_INVALID_PARAM;
613
  }
John Koleszar's avatar
John Koleszar committed
614
615
}

616
617
618
static vpx_codec_err_t copy_reference(vpx_codec_alg_priv_t *ctx,
                                      int ctr_id,
                                      va_list args) {
John Koleszar's avatar
John Koleszar committed
619
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
620

John Koleszar's avatar
John Koleszar committed
621
622
623
  if (data) {
    vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
624

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

John Koleszar's avatar
John Koleszar committed
627
628
    return vp9_copy_reference_dec(ctx->pbi,
                                  (VP9_REFFRAME)frame->frame_type, &sd);
629
  } else {
John Koleszar's avatar
John Koleszar committed
630
    return VPX_CODEC_INVALID_PARAM;
631
  }
John Koleszar's avatar
John Koleszar committed
632
633
}

John Koleszar's avatar
John Koleszar committed
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
static vpx_codec_err_t get_reference(vpx_codec_alg_priv_t *ctx,
                                     int ctr_id,
                                     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;
  }
}

650
651
652
static vpx_codec_err_t set_postproc(vpx_codec_alg_priv_t *ctx,
                                    int ctr_id,
                                    va_list args) {
653
#if CONFIG_VP9_POSTPROC
John Koleszar's avatar
John Koleszar committed
654
  vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
John Koleszar's avatar
John Koleszar committed
655

John Koleszar's avatar
John Koleszar committed
656
657
658
659
  if (data) {
    ctx->postproc_cfg_set = 1;
    ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data);
    return VPX_CODEC_OK;
660
  } else {
John Koleszar's avatar
John Koleszar committed
661
    return VPX_CODEC_INVALID_PARAM;
662
  }
John Koleszar's avatar
John Koleszar committed
663
#else
John Koleszar's avatar
John Koleszar committed
664
  return VPX_CODEC_INCAPABLE;
John Koleszar's avatar
John Koleszar committed
665
666
667
#endif
}

668
669
670
static vpx_codec_err_t set_dbg_options(vpx_codec_alg_priv_t *ctx,
                                       int ctrl_id,
                                       va_list args) {
671
#if CONFIG_POSTPROC_VISUALIZER && CONFIG_POSTPROC
John Koleszar's avatar
John Koleszar committed
672
  int data = va_arg(args, int);
673
674
675

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

John Koleszar's avatar
John Koleszar committed
676
677
678
679
680
681
  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);
  }
682

John Koleszar's avatar
John Koleszar committed
683
  return VPX_CODEC_OK;
684
#else
John Koleszar's avatar
John Koleszar committed
685
  return VPX_CODEC_INCAPABLE;
686
687
#endif
}
John Koleszar's avatar
John Koleszar committed
688

689
690
691
static vpx_codec_err_t get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
                                            int ctrl_id,
                                            va_list args) {
John Koleszar's avatar
John Koleszar committed
692
  int *update_info = va_arg(args, int *);
693
  VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
694

John Koleszar's avatar
John Koleszar committed
695
  if (update_info) {
696
    *update_info = pbi->refresh_frame_flags;
697

John Koleszar's avatar
John Koleszar committed
698
    return VPX_CODEC_OK;
699
  } else {
John Koleszar's avatar
John Koleszar committed
700
    return VPX_CODEC_INVALID_PARAM;
701
  }
702
703
704
}


705
706
707
static vpx_codec_err_t get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
                                           int ctrl_id,
                                           va_list args) {
John Koleszar's avatar
John Koleszar committed
708
  int *corrupted = va_arg(args, int *);
709

John Koleszar's avatar
John Koleszar committed
710
  if (corrupted) {
711
    VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
Yaowu Xu's avatar
Yaowu Xu committed
712
713
714
715
    if (pbi)
      *corrupted = pbi->common.frame_to_show->corrupted;
    else
      return VPX_CODEC_ERROR;
John Koleszar's avatar
John Koleszar committed
716
    return VPX_CODEC_OK;
717
  } else {
John Koleszar's avatar
John Koleszar committed
718
    return VPX_CODEC_INVALID_PARAM;
719
  }
720
721
}

722
723
724
725
726
727
static vpx_codec_err_t get_display_size(vpx_codec_alg_priv_t *ctx,
                                        int ctrl_id,
                                        va_list args) {
  int *const display_size = va_arg(args, int *);

  if (display_size) {
728
    const VP9D_COMP *const pbi = (VP9D_COMP*)ctx->pbi;
729
730
731
732
733
734
735
736
737
738
739
740
    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;
  }
}

741
742
743
744
745
746
747
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;
}

Frank Galligan's avatar
Frank Galligan committed
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
static vpx_codec_err_t set_frame_buffer_lru_cache(vpx_codec_alg_priv_t *ctx,
                                                  int ctr_id,
                                                  va_list args) {
  VP9D_COMP *const pbi = (VP9D_COMP*)ctx->pbi;

  // Save for later to pass into vp9 common.
  ctx->fb_lru = va_arg(args, int);

  if (pbi) {
    VP9_COMMON *const cm = &pbi->common;
    cm->fb_lru = ctx->fb_lru;
  }
  return VPX_CODEC_OK;
}

763
static vpx_codec_ctrl_fn_map_t ctf_maps[] = {
764
765
766
767
768
769
770
771
772
  {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
773
  {VP9_GET_REFERENCE,             get_reference},
774
  {VP9D_GET_DISPLAY_SIZE,         get_display_size},
775
  {VP9_INVERT_TILE_DECODE_ORDER,  set_invert_tile_order},
Frank Galligan's avatar
Frank Galligan committed
776
  {VP9D_SET_FRAME_BUFFER_LRU_CACHE, set_frame_buffer_lru_cache},
John Koleszar's avatar
John Koleszar committed
777
  { -1, NULL},
John Koleszar's avatar
John Koleszar committed
778
779
780
781
782
783
};


#ifndef VERSION_STRING
#define VERSION_STRING
#endif
784
785
CODEC_INTERFACE(vpx_codec_vp9_dx) = {
  "WebM Project VP9 Decoder" VERSION_STRING,
John Koleszar's avatar
John Koleszar committed
786
  VPX_CODEC_INTERNAL_ABI_VERSION,
787
788
  VPX_CODEC_CAP_DECODER | VP9_CAP_POSTPROC |
      VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER,
John Koleszar's avatar
John Koleszar committed
789
  /* vpx_codec_caps_t          caps; */
790
791
  vp9_init,         /* vpx_codec_init_fn_t       init; */
  vp9_destroy,      /* vpx_codec_destroy_fn_t    destroy; */
792
  ctf_maps,         /* vpx_codec_ctrl_fn_map_t  *ctrl_maps; */
793
794
  vp9_xma_get_mmap, /* vpx_codec_get_mmap_fn_t   get_mmap; */
  vp9_xma_set_mmap, /* vpx_codec_set_mmap_fn_t   set_mmap; */
795
  { // NOLINT
796
797
    vp9_peek_si,      /* vpx_codec_peek_si_fn_t    peek_si; */
    vp9_get_si,       /* vpx_codec_get_si_fn_t     get_si; */
798
    vp9_decode,       /* vpx_codec_decode_fn_t     decode; */
799
    vp9_get_frame,    /* vpx_codec_frame_get_fn_t  frame_get; */
800
    vp9_set_frame_buffers,    /* vpx_codec_set_frame_buffers_fn_t  set_fb; */
John Koleszar's avatar
John Koleszar committed
801
  },
802
  { // NOLINT
John Koleszar's avatar
John Koleszar committed
803
804
805
806
807
808
809
810
    /* encoder functions */
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED
  }
John Koleszar's avatar
John Koleszar committed
811
};