vp9_dx_iface.c 22.8 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
#include "vp9/common/vp9_frame_buffers.h"
19
20
21
#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
22
#include "vp9/vp9_iface_common.h"
John Koleszar's avatar
John Koleszar committed
23

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

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

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

37
38
39
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
40
41
};

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

  // External frame buffer info to save for VP9 common.
  void *ext_priv;  // Private data associated with the external frame buffers.
  vpx_get_frame_buffer_cb_fn_t get_ext_fb_cb;
  vpx_release_frame_buffer_cb_fn_t release_ext_fb_cb;
John Koleszar's avatar
John Koleszar committed
68
69
};

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

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

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

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

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

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

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

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

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

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

122
    res = vpx_mmap_alloc(&mmap);
John Koleszar's avatar
John Koleszar committed
123
    if (!res) {
124
      vp9_init_ctx(ctx, &mmap);
John Koleszar's avatar
John Koleszar committed
125

John Koleszar's avatar
John Koleszar committed
126
      ctx->priv->alg_priv->defer_alloc = 1;
John Koleszar's avatar
John Koleszar committed
127
    }
John Koleszar's avatar
John Koleszar committed
128
  }
John Koleszar's avatar
John Koleszar committed
129

John Koleszar's avatar
John Koleszar committed
130
  return res;
John Koleszar's avatar
John Koleszar committed
131
132
}

133
static vpx_codec_err_t vp9_destroy(vpx_codec_alg_priv_t *ctx) {
John Koleszar's avatar
John Koleszar committed
134
  int i;
John Koleszar's avatar
John Koleszar committed
135

136
  vp9_remove_decompressor(ctx->pbi);
John Koleszar's avatar
John Koleszar committed
137

John Koleszar's avatar
John Koleszar committed
138
139
140
141
  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
142

John Koleszar's avatar
John Koleszar committed
143
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
144
145
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
146
static vpx_codec_err_t vp9_peek_si(const uint8_t *data, unsigned int data_sz,
John Koleszar's avatar
John Koleszar committed
147
                                   vpx_codec_stream_info_t *si) {
James Zern's avatar
James Zern committed
148
  if (data_sz <= 8) return VPX_CODEC_UNSUP_BITSTREAM;
149
150
151
152
  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
153

154
155
156
  {
    struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
    const int frame_marker = vp9_rb_read_literal(&rb, 2);
157
158
159
    const int version = vp9_rb_read_bit(&rb);
    (void) vp9_rb_read_bit(&rb);  // unused version bit

160
161
    if (frame_marker != VP9_FRAME_MARKER)
      return VPX_CODEC_UNSUP_BITSTREAM;
162
163
164
#if CONFIG_NON420
    if (version > 1) return VPX_CODEC_UNSUP_BITSTREAM;
#else
James Zern's avatar
James Zern committed
165
    if (version != 0) return VPX_CODEC_UNSUP_BITSTREAM;
166
167
168
169
170
#endif

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

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

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

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

208
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
209
210
}

211
static vpx_codec_err_t vp9_get_si(vpx_codec_alg_priv_t    *ctx,
John Koleszar's avatar
John Koleszar committed
212
                                  vpx_codec_stream_info_t *si) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
213
214
215
  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
216
217
  memcpy(si, &ctx->si, sz);
  si->sz = sz;
John Koleszar's avatar
John Koleszar committed
218

John Koleszar's avatar
John Koleszar committed
219
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
220
221
222
}


Dmitry Kovalev's avatar
Dmitry Kovalev committed
223
224
225
226
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
227

Dmitry Kovalev's avatar
Dmitry Kovalev committed
228
  return error->error_code;
John Koleszar's avatar
John Koleszar committed
229
230
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
231
232
233
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
234
  vpx_codec_err_t res = VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
235

John Koleszar's avatar
John Koleszar committed
236
  ctx->img_avail = 0;
John Koleszar's avatar
John Koleszar committed
237

John Koleszar's avatar
John Koleszar committed
238
239
240
241
242
  /* 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)
243
    res = ctx->base.iface->dec.peek_si(*data, data_sz, &ctx->si);
John Koleszar's avatar
John Koleszar committed
244
245


John Koleszar's avatar
John Koleszar committed
246
247
248
  /* Perform deferred allocations, if required */
  if (!res && ctx->defer_alloc) {
    int i;
John Koleszar's avatar
John Koleszar committed
249

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

John Koleszar's avatar
John Koleszar committed
253
254
      cfg.w = ctx->si.w;
      cfg.h = ctx->si.h;
255
256
257
258
      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
259

John Koleszar's avatar
John Koleszar committed
260
      if (!ctx->mmaps[i].sz)
261
        ctx->mmaps[i].sz = vp9_mem_req_segs[i].calc_sz(&cfg,
John Koleszar's avatar
John Koleszar committed
262
                                                       ctx->base.init_flags);
John Koleszar's avatar
John Koleszar committed
263

264
      res = vpx_mmap_alloc(&ctx->mmaps[i]);
John Koleszar's avatar
John Koleszar committed
265
266
    }

John Koleszar's avatar
John Koleszar committed
267
    if (!res)
268
      vp9_finalize_mmaps(ctx);
John Koleszar's avatar
John Koleszar committed
269
270
271
272
273
274

    ctx->defer_alloc = 0;
  }

  /* Initialize the decoder instance on the first frame*/
  if (!res && !ctx->decoder_init) {
275
    res = vpx_validate_mmaps(&ctx->si, ctx->mmaps,
276
                             vp9_mem_req_segs, NELEMENTS(vp9_mem_req_segs),
277
                             ctx->base.init_flags);
John Koleszar's avatar
John Koleszar committed
278
279

    if (!res) {
280
281
      VP9D_CONFIG oxcf;
      VP9D_PTR optr;
John Koleszar's avatar
John Koleszar committed
282

283
      vp9_initialize_dec();
John Koleszar's avatar
John Koleszar committed
284

285
286
287
      oxcf.width = ctx->si.w;
      oxcf.height = ctx->si.h;
      oxcf.version = 9;
John Koleszar's avatar
John Koleszar committed
288
289
      oxcf.postprocess = 0;
      oxcf.max_threads = ctx->cfg.threads;
290
      oxcf.inv_tile_order = ctx->invert_tile_order;
291
      optr = vp9_create_decompressor(&oxcf);
John Koleszar's avatar
John Koleszar committed
292

Dmitry Kovalev's avatar
Dmitry Kovalev committed
293
294
295
296
297
      // 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
298
299
300
301
        ctx->postproc_cfg.deblocking_level = 4;
        ctx->postproc_cfg.noise_level = 0;
      }

302
      if (!optr) {
John Koleszar's avatar
John Koleszar committed
303
        res = VPX_CODEC_ERROR;
304
305
306
307
      } else {
        VP9D_COMP *const pbi = (VP9D_COMP*)optr;
        VP9_COMMON *const cm = &pbi->common;

308
309
310
        // Set index to not initialized.
        cm->new_fb_idx = -1;

311
312
313
314
315
316
317
318
319
320
321
322
323
        if (ctx->get_ext_fb_cb != NULL && ctx->release_ext_fb_cb != NULL) {
          cm->get_fb_cb = ctx->get_ext_fb_cb;
          cm->release_fb_cb = ctx->release_ext_fb_cb;
          cm->cb_priv = ctx->ext_priv;
        } else {
          cm->get_fb_cb = vp9_get_frame_buffer;
          cm->release_fb_cb = vp9_release_frame_buffer;

          if (vp9_alloc_internal_frame_buffers(&cm->int_frame_buffers))
            vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
                               "Failed to initialize internal frame buffers");
          cm->cb_priv = &cm->int_frame_buffers;
        }
324

John Koleszar's avatar
John Koleszar committed
325
        ctx->pbi = optr;
326
      }
John Koleszar's avatar
John Koleszar committed
327
328
    }

John Koleszar's avatar
John Koleszar committed
329
330
331
332
333
334
    ctx->decoder_init = 1;
  }

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

John Koleszar's avatar
John Koleszar committed
337
    if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) {
338
      flags.post_proc_flag =
339
#if CONFIG_POSTPROC_VISUALIZER
Dmitry Kovalev's avatar
Dmitry Kovalev committed
340
341
342
343
          (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) |
344
#endif
345
346
          ctx->postproc_cfg.post_proc_flag;

Dmitry Kovalev's avatar
Dmitry Kovalev committed
347
348
      flags.deblocking_level = ctx->postproc_cfg.deblocking_level;
      flags.noise_level = ctx->postproc_cfg.noise_level;
349
#if CONFIG_POSTPROC_VISUALIZER
John Koleszar's avatar
John Koleszar committed
350
351
      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
352
353
      flags.display_b_modes_flag = ctx->dbg_color_b_modes_flag;
      flags.display_mv_flag = ctx->dbg_display_mv_flag;
354
#endif
John Koleszar's avatar
John Koleszar committed
355
    }
John Koleszar's avatar
John Koleszar committed
356

357
    if (vp9_receive_compressed_data(ctx->pbi, data_sz, data, deadline)) {
358
      VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
John Koleszar's avatar
John Koleszar committed
359
360
      res = update_error_state(ctx, &pbi->common.error);
    }
John Koleszar's avatar
John Koleszar committed
361

362
363
    if (!res && 0 == vp9_get_raw_frame(ctx->pbi, &sd, &time_stamp,
                                       &time_end_stamp, &flags)) {
364
365
      VP9D_COMP *const pbi = (VP9D_COMP*)ctx->pbi;
      VP9_COMMON *const cm = &pbi->common;
John Koleszar's avatar
John Koleszar committed
366
      yuvconfig2image(&ctx->img, &sd, user_priv);
367
368

      ctx->img.fb_priv = cm->frame_bufs[cm->new_fb_idx].raw_frame_buffer.priv;
John Koleszar's avatar
John Koleszar committed
369
      ctx->img_avail = 1;
John Koleszar's avatar
John Koleszar committed
370
    }
John Koleszar's avatar
John Koleszar committed
371
  }
John Koleszar's avatar
John Koleszar committed
372

John Koleszar's avatar
John Koleszar committed
373
  return res;
John Koleszar's avatar
John Koleszar committed
374
375
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
376
377
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
378
379
380
381
382
383
  uint8_t marker;

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

384
  if ((marker & 0xe0) == 0xc0) {
Johann's avatar
Johann committed
385
386
387
    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
388
389
390

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

      for (i = 0; i < frames; i++) {
Johann's avatar
Johann committed
395
        uint32_t this_sz = 0;
John Koleszar's avatar
John Koleszar committed
396
397
398
399
400
401
402
403
404
405
406

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

      *count = frames;
    }
  }
}

407
408
409
410
411
412
413
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;
414
  vpx_codec_err_t res = 0;
John Koleszar's avatar
John Koleszar committed
415
416
417
  uint32_t sizes[8];
  int frames_this_pts, frame_count = 0;

418
419
  if (data == NULL || data_sz == 0) return VPX_CODEC_INVALID_PARAM;

John Koleszar's avatar
John Koleszar committed
420
  parse_superframe_index(data, data_sz, sizes, &frames_this_pts);
421
422

  do {
John Koleszar's avatar
John Koleszar committed
423
    // Skip over the superframe index, if present
424
    if (data_sz && (*data_start & 0xe0) == 0xc0) {
John Koleszar's avatar
John Koleszar committed
425
      const uint8_t marker = *data_start;
Johann's avatar
Johann committed
426
427
428
      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
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452

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

453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
    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;
}

470
static vpx_image_t *vp9_get_frame(vpx_codec_alg_priv_t  *ctx,
John Koleszar's avatar
John Koleszar committed
471
472
473
474
475
476
477
478
479
480
                                  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
481
    }
John Koleszar's avatar
John Koleszar committed
482
  }
483
  ctx->img_avail = 0;
John Koleszar's avatar
John Koleszar committed
484

John Koleszar's avatar
John Koleszar committed
485
  return img;
John Koleszar's avatar
John Koleszar committed
486
487
}

488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
static vpx_codec_err_t vp9_set_fb_fn(
    vpx_codec_alg_priv_t *ctx,
    vpx_get_frame_buffer_cb_fn_t cb_get,
    vpx_release_frame_buffer_cb_fn_t cb_release, void *cb_priv) {
  if (cb_get == NULL || cb_release == NULL) {
    return VPX_CODEC_INVALID_PARAM;
  } else if (ctx->pbi == NULL) {
    // If the decoder has already been initialized, do not accept changes to
    // the frame buffer functions.
    ctx->get_ext_fb_cb = cb_get;
    ctx->release_ext_fb_cb = cb_release;
    ctx->ext_priv = cb_priv;
    return VPX_CODEC_OK;
  }

  return VPX_CODEC_ERROR;
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
506
507
508
509
510
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
511
512
513
514

  /* Get address of next segment request */
  do {
    if (!seg_iter)
515
516
      seg_iter = vp9_mem_req_segs;
    else if (seg_iter->id != VP9_SEG_MAX)
John Koleszar's avatar
John Koleszar committed
517
518
519
520
      seg_iter++;

    *iter = (vpx_codec_iter_t)seg_iter;

521
    if (seg_iter->id != VP9_SEG_MAX) {
John Koleszar's avatar
John Koleszar committed
522
523
524
525
526
527
528
529
530
      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;
531
    } else {
John Koleszar's avatar
John Koleszar committed
532
      res = VPX_CODEC_LIST_END;
533
    }
John Koleszar's avatar
John Koleszar committed
534
535
536
  } while (!mmap->sz && res != VPX_CODEC_LIST_END);

  return res;
John Koleszar's avatar
John Koleszar committed
537
538
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
539
static vpx_codec_err_t vp9_xma_set_mmap(vpx_codec_ctx_t *ctx,
John Koleszar's avatar
John Koleszar committed
540
541
542
543
544
                                        const vpx_codec_mmap_t  *mmap) {
  vpx_codec_err_t res = VPX_CODEC_MEM_ERROR;
  int i, done;

  if (!ctx->priv) {
545
    if (mmap->id == VP9_SEG_ALG_PRIV) {
John Koleszar's avatar
John Koleszar committed
546
      if (!ctx->priv) {
547
        vp9_init_ctx(ctx, mmap);
John Koleszar's avatar
John Koleszar committed
548
549
        res = VPX_CODEC_OK;
      }
John Koleszar's avatar
John Koleszar committed
550
    }
John Koleszar's avatar
John Koleszar committed
551
  }
John Koleszar's avatar
John Koleszar committed
552

John Koleszar's avatar
John Koleszar committed
553
  done = 1;
John Koleszar's avatar
John Koleszar committed
554

John Koleszar's avatar
John Koleszar committed
555
556
557
558
559
560
  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
561
562
        }

John Koleszar's avatar
John Koleszar committed
563
      done &= (ctx->priv->alg_priv->mmaps[i].base != NULL);
John Koleszar's avatar
John Koleszar committed
564
    }
John Koleszar's avatar
John Koleszar committed
565
566
567
  }

  if (done && !res) {
568
    vp9_finalize_mmaps(ctx->priv->alg_priv);
John Koleszar's avatar
John Koleszar committed
569
    res = ctx->iface->init(ctx, NULL);
John Koleszar's avatar
John Koleszar committed
570
  }
John Koleszar's avatar
John Koleszar committed
571

John Koleszar's avatar
John Koleszar committed
572
  return res;
John Koleszar's avatar
John Koleszar committed
573
574
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
575
static vpx_codec_err_t set_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
576
                                     va_list args) {
John Koleszar's avatar
John Koleszar committed
577
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
578

John Koleszar's avatar
John Koleszar committed
579
580
581
  if (data) {
    vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
582

John Koleszar's avatar
John Koleszar committed
583
    image2yuvconfig(&frame->img, &sd);
584
585
    return vp9_set_reference_dec(ctx->pbi,
                                 (VP9_REFFRAME)frame->frame_type, &sd);
586
  } else {
John Koleszar's avatar
John Koleszar committed
587
    return VPX_CODEC_INVALID_PARAM;
588
  }
John Koleszar's avatar
John Koleszar committed
589
590
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
591
static vpx_codec_err_t copy_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
592
                                      va_list args) {
John Koleszar's avatar
John Koleszar committed
593
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
594

John Koleszar's avatar
John Koleszar committed
595
596
597
  if (data) {
    vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
598

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

John Koleszar's avatar
John Koleszar committed
601
602
    return vp9_copy_reference_dec(ctx->pbi,
                                  (VP9_REFFRAME)frame->frame_type, &sd);
603
  } else {
John Koleszar's avatar
John Koleszar committed
604
    return VPX_CODEC_INVALID_PARAM;
605
  }
John Koleszar's avatar
John Koleszar committed
606
607
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
608
static vpx_codec_err_t get_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
John Koleszar's avatar
John Koleszar committed
609
610
611
612
613
614
615
616
617
618
619
620
621
622
                                     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
623
static vpx_codec_err_t set_postproc(vpx_codec_alg_priv_t *ctx, int ctr_id,
624
                                    va_list args) {
625
#if CONFIG_VP9_POSTPROC
John Koleszar's avatar
John Koleszar committed
626
  vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
John Koleszar's avatar
John Koleszar committed
627

John Koleszar's avatar
John Koleszar committed
628
629
630
631
  if (data) {
    ctx->postproc_cfg_set = 1;
    ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data);
    return VPX_CODEC_OK;
632
  } else {
John Koleszar's avatar
John Koleszar committed
633
    return VPX_CODEC_INVALID_PARAM;
634
  }
John Koleszar's avatar
John Koleszar committed
635
#else
John Koleszar's avatar
John Koleszar committed
636
  return VPX_CODEC_INCAPABLE;
John Koleszar's avatar
John Koleszar committed
637
638
639
#endif
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
640
static vpx_codec_err_t set_dbg_options(vpx_codec_alg_priv_t *ctx, int ctrl_id,
641
                                       va_list args) {
642
#if CONFIG_POSTPROC_VISUALIZER && CONFIG_POSTPROC
John Koleszar's avatar
John Koleszar committed
643
  int data = va_arg(args, int);
644
645
646

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

John Koleszar's avatar
John Koleszar committed
647
648
649
650
651
652
  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);
  }
653

John Koleszar's avatar
John Koleszar committed
654
  return VPX_CODEC_OK;
655
#else
John Koleszar's avatar
John Koleszar committed
656
  return VPX_CODEC_INCAPABLE;
657
658
#endif
}
John Koleszar's avatar
John Koleszar committed
659

660
static vpx_codec_err_t get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
661
                                            int ctrl_id, va_list args) {
John Koleszar's avatar
John Koleszar committed
662
  int *update_info = va_arg(args, int *);
663
  VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
664

John Koleszar's avatar
John Koleszar committed
665
  if (update_info) {
666
    *update_info = pbi->refresh_frame_flags;
667

John Koleszar's avatar
John Koleszar committed
668
    return VPX_CODEC_OK;
669
  } else {
John Koleszar's avatar
John Koleszar committed
670
    return VPX_CODEC_INVALID_PARAM;
671
  }
672
673
674
}


675
static vpx_codec_err_t get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
676
                                           int ctrl_id, va_list args) {
John Koleszar's avatar
John Koleszar committed
677
  int *corrupted = va_arg(args, int *);
678

John Koleszar's avatar
John Koleszar committed
679
  if (corrupted) {
680
    VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
Yaowu Xu's avatar
Yaowu Xu committed
681
682
683
684
    if (pbi)
      *corrupted = pbi->common.frame_to_show->corrupted;
    else
      return VPX_CODEC_ERROR;
John Koleszar's avatar
John Koleszar committed
685
    return VPX_CODEC_OK;
686
  } else {
John Koleszar's avatar
John Koleszar committed
687
    return VPX_CODEC_INVALID_PARAM;
688
  }
689
690
}

691
static vpx_codec_err_t get_display_size(vpx_codec_alg_priv_t *ctx,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
692
                                        int ctrl_id, va_list args) {
693
694
695
  int *const display_size = va_arg(args, int *);

  if (display_size) {
696
    const VP9D_COMP *const pbi = (VP9D_COMP*)ctx->pbi;
697
698
699
700
701
702
703
704
705
706
707
708
    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;
  }
}

709
710
711
712
713
714
715
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;
}

716
static vpx_codec_ctrl_fn_map_t ctf_maps[] = {
717
718
719
720
721
722
723
724
725
  {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
726
  {VP9_GET_REFERENCE,             get_reference},
727
  {VP9D_GET_DISPLAY_SIZE,         get_display_size},
728
  {VP9_INVERT_TILE_DECODE_ORDER,  set_invert_tile_order},
John Koleszar's avatar
John Koleszar committed
729
  { -1, NULL},
John Koleszar's avatar
John Koleszar committed
730
731
732
733
734
735
};


#ifndef VERSION_STRING
#define VERSION_STRING
#endif
736
737
CODEC_INTERFACE(vpx_codec_vp9_dx) = {
  "WebM Project VP9 Decoder" VERSION_STRING,
John Koleszar's avatar
John Koleszar committed
738
  VPX_CODEC_INTERNAL_ABI_VERSION,
739
740
  VPX_CODEC_CAP_DECODER | VP9_CAP_POSTPROC |
      VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER,
John Koleszar's avatar
John Koleszar committed
741
  /* vpx_codec_caps_t          caps; */
742
743
  vp9_init,         /* vpx_codec_init_fn_t       init; */
  vp9_destroy,      /* vpx_codec_destroy_fn_t    destroy; */
744
  ctf_maps,         /* vpx_codec_ctrl_fn_map_t  *ctrl_maps; */
745
746
  vp9_xma_get_mmap, /* vpx_codec_get_mmap_fn_t   get_mmap; */
  vp9_xma_set_mmap, /* vpx_codec_set_mmap_fn_t   set_mmap; */
747
  { // NOLINT
748
749
    vp9_peek_si,      /* vpx_codec_peek_si_fn_t    peek_si; */
    vp9_get_si,       /* vpx_codec_get_si_fn_t     get_si; */
750
    vp9_decode,       /* vpx_codec_decode_fn_t     decode; */
751
    vp9_get_frame,    /* vpx_codec_frame_get_fn_t  frame_get; */
752
    vp9_set_fb_fn,    /* vpx_codec_set_fb_fn_t     set_fb_fn; */
John Koleszar's avatar
John Koleszar committed
753
  },
754
  { // NOLINT
John Koleszar's avatar
John Koleszar committed
755
756
757
758
759
760
761
762
    /* encoder functions */
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED
  }
John Koleszar's avatar
John Koleszar committed
763
};