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
#include "vp9/decoder/vp9_decoder.h"
20
#include "vp9/decoder/vp9_read_bit_buffer.h"
John Koleszar's avatar
John Koleszar committed
21
#include "vp9/vp9_iface_common.h"
John Koleszar's avatar
John Koleszar committed
22

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

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

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

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

John Koleszar's avatar
John Koleszar committed
41
42
struct vpx_codec_alg_priv {
  vpx_codec_priv_t        base;
43
  vpx_codec_mmap_t        mmaps[NELEMENTS(vp9_mem_req_segs) - 1];
John Koleszar's avatar
John Koleszar committed
44
  vpx_codec_dec_cfg_t     cfg;
45
  vp9_stream_info_t       si;
John Koleszar's avatar
John Koleszar committed
46
47
  int                     defer_alloc;
  int                     decoder_init;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
48
  struct VP9Decompressor *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;
62
63
64
65
66

  // 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
67
68
};

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

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

83
  ctx->priv = (vpx_codec_priv_t *)mmap->base;
John Koleszar's avatar
John Koleszar committed
84
85
  ctx->priv->sz = sizeof(*ctx->priv);
  ctx->priv->iface = ctx->iface;
86
  ctx->priv->alg_priv = (struct vpx_codec_alg_priv *)mmap->base;
John Koleszar's avatar
John Koleszar committed
87

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

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

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

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

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

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

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

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

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

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

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

135
136
  if (ctx->pbi)
    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
165
166
    if (version > 1) return VPX_CODEC_UNSUP_BITSTREAM;

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

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

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

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

204
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
205
206
}

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

John Koleszar's avatar
John Koleszar committed
215
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
216
217
218
}


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

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

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

John Koleszar's avatar
John Koleszar committed
232
  ctx->img_avail = 0;
John Koleszar's avatar
John Koleszar committed
233

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


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

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

John Koleszar's avatar
John Koleszar committed
249
250
      cfg.w = ctx->si.w;
      cfg.h = ctx->si.h;
251
252
253
254
      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
255

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

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

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

    ctx->defer_alloc = 0;
  }

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

    if (!res) {
276
      VP9D_CONFIG oxcf;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
277
      struct VP9Decompressor *optr;
John Koleszar's avatar
John Koleszar committed
278

279
      vp9_initialize_dec();
John Koleszar's avatar
John Koleszar committed
280

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

Dmitry Kovalev's avatar
Dmitry Kovalev committed
288
289
290
291
292
      // 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
293
294
295
296
        ctx->postproc_cfg.deblocking_level = 4;
        ctx->postproc_cfg.noise_level = 0;
      }

297
      if (!optr) {
John Koleszar's avatar
John Koleszar committed
298
        res = VPX_CODEC_ERROR;
299
300
301
302
      } else {
        VP9D_COMP *const pbi = (VP9D_COMP*)optr;
        VP9_COMMON *const cm = &pbi->common;

303
304
305
        // Set index to not initialized.
        cm->new_fb_idx = -1;

306
307
308
309
310
311
312
313
314
315
316
317
318
        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;
        }
319

John Koleszar's avatar
John Koleszar committed
320
        ctx->pbi = optr;
321
      }
John Koleszar's avatar
John Koleszar committed
322
323
    }

John Koleszar's avatar
John Koleszar committed
324
325
326
327
328
329
    ctx->decoder_init = 1;
  }

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

John Koleszar's avatar
John Koleszar committed
332
    if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) {
333
      flags.post_proc_flag =
334
#if CONFIG_POSTPROC_VISUALIZER
Dmitry Kovalev's avatar
Dmitry Kovalev committed
335
336
337
338
          (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) |
339
#endif
340
341
          ctx->postproc_cfg.post_proc_flag;

Dmitry Kovalev's avatar
Dmitry Kovalev committed
342
343
      flags.deblocking_level = ctx->postproc_cfg.deblocking_level;
      flags.noise_level = ctx->postproc_cfg.noise_level;
344
#if CONFIG_POSTPROC_VISUALIZER
John Koleszar's avatar
John Koleszar committed
345
346
      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
347
348
      flags.display_b_modes_flag = ctx->dbg_color_b_modes_flag;
      flags.display_mv_flag = ctx->dbg_display_mv_flag;
349
#endif
John Koleszar's avatar
John Koleszar committed
350
    }
John Koleszar's avatar
John Koleszar committed
351

352
    if (vp9_receive_compressed_data(ctx->pbi, data_sz, data, deadline)) {
353
      VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
John Koleszar's avatar
John Koleszar committed
354
355
      res = update_error_state(ctx, &pbi->common.error);
    }
John Koleszar's avatar
John Koleszar committed
356

357
358
    if (!res && 0 == vp9_get_raw_frame(ctx->pbi, &sd, &time_stamp,
                                       &time_end_stamp, &flags)) {
359
360
      VP9D_COMP *const pbi = (VP9D_COMP*)ctx->pbi;
      VP9_COMMON *const cm = &pbi->common;
John Koleszar's avatar
John Koleszar committed
361
      yuvconfig2image(&ctx->img, &sd, user_priv);
362
363

      ctx->img.fb_priv = cm->frame_bufs[cm->new_fb_idx].raw_frame_buffer.priv;
John Koleszar's avatar
John Koleszar committed
364
      ctx->img_avail = 1;
John Koleszar's avatar
John Koleszar committed
365
    }
John Koleszar's avatar
John Koleszar committed
366
  }
John Koleszar's avatar
John Koleszar committed
367

John Koleszar's avatar
John Koleszar committed
368
  return res;
John Koleszar's avatar
John Koleszar committed
369
370
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
371
372
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
373
374
375
376
377
378
  uint8_t marker;

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

379
  if ((marker & 0xe0) == 0xc0) {
Johann's avatar
Johann committed
380
381
382
    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
383
384
385

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

      for (i = 0; i < frames; i++) {
Johann's avatar
Johann committed
390
        uint32_t this_sz = 0;
John Koleszar's avatar
John Koleszar committed
391
392
393
394
395
396
397
398
399
400
401

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

      *count = frames;
    }
  }
}

402
403
404
405
406
407
408
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;
409
  vpx_codec_err_t res = VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
410
411
412
  uint32_t sizes[8];
  int frames_this_pts, frame_count = 0;

413
414
  if (data == NULL || data_sz == 0) return VPX_CODEC_INVALID_PARAM;

John Koleszar's avatar
John Koleszar committed
415
  parse_superframe_index(data, data_sz, sizes, &frames_this_pts);
416
417

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

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

448
449
450
451
452
453
454
455
456
457
458
459
    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++;

460
    data_sz = (unsigned int)(data_end - data_start);
461
462
463
464
  } while (data_start < data_end);
  return res;
}

465
static vpx_image_t *vp9_get_frame(vpx_codec_alg_priv_t  *ctx,
John Koleszar's avatar
John Koleszar committed
466
467
468
469
470
471
472
473
474
475
                                  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
476
    }
John Koleszar's avatar
John Koleszar committed
477
  }
478
  ctx->img_avail = 0;
John Koleszar's avatar
John Koleszar committed
479

John Koleszar's avatar
John Koleszar committed
480
  return img;
John Koleszar's avatar
John Koleszar committed
481
482
}

483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
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
501
502
503
504
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;
505
  const mem_req_t *seg_iter = (const mem_req_t *)*iter;
John Koleszar's avatar
John Koleszar committed
506
507
508
509

  /* Get address of next segment request */
  do {
    if (!seg_iter)
510
511
      seg_iter = vp9_mem_req_segs;
    else if (seg_iter->id != VP9_SEG_MAX)
John Koleszar's avatar
John Koleszar committed
512
513
514
515
      seg_iter++;

    *iter = (vpx_codec_iter_t)seg_iter;

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

  return res;
John Koleszar's avatar
John Koleszar committed
532
533
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
534
static vpx_codec_err_t vp9_xma_set_mmap(vpx_codec_ctx_t *ctx,
John Koleszar's avatar
John Koleszar committed
535
536
537
538
539
                                        const vpx_codec_mmap_t  *mmap) {
  vpx_codec_err_t res = VPX_CODEC_MEM_ERROR;
  int i, done;

  if (!ctx->priv) {
540
    if (mmap->id == VP9_SEG_ALG_PRIV) {
John Koleszar's avatar
John Koleszar committed
541
      if (!ctx->priv) {
542
        vp9_init_ctx(ctx, mmap);
John Koleszar's avatar
John Koleszar committed
543
544
        res = VPX_CODEC_OK;
      }
John Koleszar's avatar
John Koleszar committed
545
    }
John Koleszar's avatar
John Koleszar committed
546
  }
John Koleszar's avatar
John Koleszar committed
547

John Koleszar's avatar
John Koleszar committed
548
  done = 1;
John Koleszar's avatar
John Koleszar committed
549

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

John Koleszar's avatar
John Koleszar committed
558
      done &= (ctx->priv->alg_priv->mmaps[i].base != NULL);
John Koleszar's avatar
John Koleszar committed
559
    }
John Koleszar's avatar
John Koleszar committed
560
561
562
  }

  if (done && !res) {
563
    vp9_finalize_mmaps(ctx->priv->alg_priv);
John Koleszar's avatar
John Koleszar committed
564
    res = ctx->iface->init(ctx, NULL);
John Koleszar's avatar
John Koleszar committed
565
  }
John Koleszar's avatar
John Koleszar committed
566

John Koleszar's avatar
John Koleszar committed
567
  return res;
John Koleszar's avatar
John Koleszar committed
568
569
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
570
static vpx_codec_err_t set_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
571
                                     va_list args) {
572
  vpx_ref_frame_t *const data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
573

John Koleszar's avatar
John Koleszar committed
574
  if (data) {
575
    vpx_ref_frame_t *const frame = (vpx_ref_frame_t *)data;
John Koleszar's avatar
John Koleszar committed
576
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
577

John Koleszar's avatar
John Koleszar committed
578
    image2yuvconfig(&frame->img, &sd);
579
    return vp9_set_reference_dec(&ctx->pbi->common,
580
                                 (VP9_REFFRAME)frame->frame_type, &sd);
581
  } else {
John Koleszar's avatar
John Koleszar committed
582
    return VPX_CODEC_INVALID_PARAM;
583
  }
John Koleszar's avatar
John Koleszar committed
584
585
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
586
static vpx_codec_err_t copy_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
587
                                      va_list args) {
John Koleszar's avatar
John Koleszar committed
588
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
589

John Koleszar's avatar
John Koleszar committed
590
591
592
  if (data) {
    vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
593

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

John Koleszar's avatar
John Koleszar committed
596
597
    return vp9_copy_reference_dec(ctx->pbi,
                                  (VP9_REFFRAME)frame->frame_type, &sd);
598
  } else {
John Koleszar's avatar
John Koleszar committed
599
    return VPX_CODEC_INVALID_PARAM;
600
  }
John Koleszar's avatar
John Koleszar committed
601
602
}

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

John Koleszar's avatar
John Koleszar committed
623
624
625
626
  if (data) {
    ctx->postproc_cfg_set = 1;
    ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data);
    return VPX_CODEC_OK;
627
  } else {
John Koleszar's avatar
John Koleszar committed
628
    return VPX_CODEC_INVALID_PARAM;
629
  }
John Koleszar's avatar
John Koleszar committed
630
#else
John Koleszar's avatar
John Koleszar committed
631
  return VPX_CODEC_INCAPABLE;
John Koleszar's avatar
John Koleszar committed
632
633
634
#endif
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
635
static vpx_codec_err_t set_dbg_options(vpx_codec_alg_priv_t *ctx, int ctrl_id,
636
                                       va_list args) {
637
#if CONFIG_POSTPROC_VISUALIZER && CONFIG_POSTPROC
John Koleszar's avatar
John Koleszar committed
638
  int data = va_arg(args, int);
639
640
641

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

John Koleszar's avatar
John Koleszar committed
642
643
644
645
646
647
  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);
  }
648

John Koleszar's avatar
John Koleszar committed
649
  return VPX_CODEC_OK;
650
#else
John Koleszar's avatar
John Koleszar committed
651
  return VPX_CODEC_INCAPABLE;
652
653
#endif
}
John Koleszar's avatar
John Koleszar committed
654

655
static vpx_codec_err_t get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
656
                                            int ctrl_id, va_list args) {
John Koleszar's avatar
John Koleszar committed
657
  int *update_info = va_arg(args, int *);
658
  VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
659

John Koleszar's avatar
John Koleszar committed
660
  if (update_info) {
661
    *update_info = pbi->refresh_frame_flags;
662

John Koleszar's avatar
John Koleszar committed
663
    return VPX_CODEC_OK;
664
  } else {
John Koleszar's avatar
John Koleszar committed
665
    return VPX_CODEC_INVALID_PARAM;
666
  }
667
668
669
}


670
static vpx_codec_err_t get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
671
                                           int ctrl_id, va_list args) {
John Koleszar's avatar
John Koleszar committed
672
  int *corrupted = va_arg(args, int *);
673

John Koleszar's avatar
John Koleszar committed
674
  if (corrupted) {
675
    VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
Yaowu Xu's avatar
Yaowu Xu committed
676
677
678
679
    if (pbi)
      *corrupted = pbi->common.frame_to_show->corrupted;
    else
      return VPX_CODEC_ERROR;
John Koleszar's avatar
John Koleszar committed
680
    return VPX_CODEC_OK;
681
  } else {
John Koleszar's avatar
John Koleszar committed
682
    return VPX_CODEC_INVALID_PARAM;
683
  }
684
685
}

686
static vpx_codec_err_t get_display_size(vpx_codec_alg_priv_t *ctx,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
687
                                        int ctrl_id, va_list args) {
688
689
690
  int *const display_size = va_arg(args, int *);

  if (display_size) {
691
    const VP9D_COMP *const pbi = (VP9D_COMP*)ctx->pbi;
692
693
694
695
696
697
698
699
700
701
702
703
    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;
  }
}

704
705
706
707
708
709
710
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;
}

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


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