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);
163
164
    if (frame_marker != VP9_FRAME_MARKER)
      return VPX_CODEC_UNSUP_BITSTREAM;
165
166
167
#if CONFIG_NON420
    if (version > 1) return VPX_CODEC_UNSUP_BITSTREAM;
#else
James Zern's avatar
James Zern committed
168
    if (version != 0) return VPX_CODEC_UNSUP_BITSTREAM;
169
170
171
172
173
#endif

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

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

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

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

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

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

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

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

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


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

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

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

243
244
245
246
247
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
248
  vpx_codec_err_t res = VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
249

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

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


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

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

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

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

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

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

    ctx->defer_alloc = 0;
  }

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

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

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

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

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

318
      if (!optr) {
John Koleszar's avatar
John Koleszar committed
319
        res = VPX_CODEC_ERROR;
320
321
322
323
324
325
326
327
328
329
330
331
      } 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
332
        cm->fb_lru = ctx->fb_lru;
333
334
335
336
        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
337
338
339
340
341
        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
342
        ctx->pbi = optr;
343
      }
John Koleszar's avatar
John Koleszar committed
344
345
    }

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

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

John Koleszar's avatar
John Koleszar committed
354
    if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) {
355
      flags.post_proc_flag =
356
#if CONFIG_POSTPROC_VISUALIZER
357
358
359
360
361
362
363
364
365
          ((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)
          |
366
#endif
367
368
          ctx->postproc_cfg.post_proc_flag;

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

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

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

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

John Koleszar's avatar
John Koleszar committed
394
395
396
397
398
399
400
401
402
403
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;

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

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

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

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

      *count = frames;
    }
  }
}

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

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

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

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

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

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

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

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

508
509
510
511
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) {
512
513
514
  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. */
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
    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;
}

530
531
532
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
533
534
535
536
537
538
  vpx_codec_err_t     res;
  const mem_req_t  *seg_iter = *iter;

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

    *iter = (vpx_codec_iter_t)seg_iter;

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

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

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

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

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

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

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

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

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

599
600
601
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
602
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
603

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

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

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

617
618
619
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
620
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
621

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

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

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

John Koleszar's avatar
John Koleszar committed
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
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;
  }
}

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

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

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

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

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

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

690
691
692
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
693
  int *update_info = va_arg(args, int *);
694
  VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
695

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

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


706
707
708
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
709
  int *corrupted = va_arg(args, int *);
710

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

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

742
743
744
745
746
747
748
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
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
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;
}

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


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