vp9_dx_iface.c 21.5 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;
John Koleszar's avatar
John Koleszar committed
63
64
};

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

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

John Koleszar's avatar
John Koleszar committed
79
80
81
82
  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
83

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

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

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

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

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

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

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

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

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

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

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

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

John Koleszar's avatar
John Koleszar committed
133
134
135
136
  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
137

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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


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

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

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

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

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

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

    ctx->defer_alloc = 0;
  }

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

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

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

280
281
282
      oxcf.width = ctx->si.w;
      oxcf.height = ctx->si.h;
      oxcf.version = 9;
John Koleszar's avatar
John Koleszar committed
283
284
      oxcf.postprocess = 0;
      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
303
304
305
      } else {
        VP9D_COMP *const pbi = (VP9D_COMP*)optr;
        VP9_COMMON *const cm = &pbi->common;

        cm->get_fb_cb = vp9_get_frame_buffer;
        cm->release_fb_cb = vp9_release_frame_buffer;

306
307
308
        // Set index to not initialized.
        cm->new_fb_idx = -1;

309
310
311
312
313
        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;

John Koleszar's avatar
John Koleszar committed
314
        ctx->pbi = optr;
315
      }
John Koleszar's avatar
John Koleszar committed
316
317
    }

John Koleszar's avatar
John Koleszar committed
318
319
320
321
322
323
    ctx->decoder_init = 1;
  }

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

John Koleszar's avatar
John Koleszar committed
326
    if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) {
327
      flags.post_proc_flag =
328
#if CONFIG_POSTPROC_VISUALIZER
Dmitry Kovalev's avatar
Dmitry Kovalev committed
329
330
331
332
          (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) |
333
#endif
334
335
          ctx->postproc_cfg.post_proc_flag;

Dmitry Kovalev's avatar
Dmitry Kovalev committed
336
337
      flags.deblocking_level = ctx->postproc_cfg.deblocking_level;
      flags.noise_level = ctx->postproc_cfg.noise_level;
338
#if CONFIG_POSTPROC_VISUALIZER
John Koleszar's avatar
John Koleszar committed
339
340
      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
341
342
      flags.display_b_modes_flag = ctx->dbg_color_b_modes_flag;
      flags.display_mv_flag = ctx->dbg_display_mv_flag;
343
#endif
John Koleszar's avatar
John Koleszar committed
344
    }
John Koleszar's avatar
John Koleszar committed
345

346
    if (vp9_receive_compressed_data(ctx->pbi, data_sz, data, deadline)) {
347
      VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
John Koleszar's avatar
John Koleszar committed
348
349
      res = update_error_state(ctx, &pbi->common.error);
    }
John Koleszar's avatar
John Koleszar committed
350

351
352
    if (!res && 0 == vp9_get_raw_frame(ctx->pbi, &sd, &time_stamp,
                                       &time_end_stamp, &flags)) {
John Koleszar's avatar
John Koleszar committed
353
354
      yuvconfig2image(&ctx->img, &sd, user_priv);
      ctx->img_avail = 1;
John Koleszar's avatar
John Koleszar committed
355
    }
John Koleszar's avatar
John Koleszar committed
356
  }
John Koleszar's avatar
John Koleszar committed
357

John Koleszar's avatar
John Koleszar committed
358
  return res;
John Koleszar's avatar
John Koleszar committed
359
360
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
361
362
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
363
364
365
366
367
368
  uint8_t marker;

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

369
  if ((marker & 0xe0) == 0xc0) {
Johann's avatar
Johann committed
370
371
372
    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
373
374
375

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

      for (i = 0; i < frames; i++) {
Johann's avatar
Johann committed
380
        uint32_t this_sz = 0;
John Koleszar's avatar
John Koleszar committed
381
382
383
384
385
386
387
388
389
390
391

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

      *count = frames;
    }
  }
}

392
393
394
395
396
397
398
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;
399
  vpx_codec_err_t res = 0;
John Koleszar's avatar
John Koleszar committed
400
401
402
  uint32_t sizes[8];
  int frames_this_pts, frame_count = 0;

403
404
  if (data == NULL || data_sz == 0) return VPX_CODEC_INVALID_PARAM;

John Koleszar's avatar
John Koleszar committed
405
  parse_superframe_index(data, data_sz, sizes, &frames_this_pts);
406
407

  do {
John Koleszar's avatar
John Koleszar committed
408
    // Skip over the superframe index, if present
409
    if (data_sz && (*data_start & 0xe0) == 0xc0) {
John Koleszar's avatar
John Koleszar committed
410
      const uint8_t marker = *data_start;
Johann's avatar
Johann committed
411
412
413
      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
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437

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

438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
    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;
}

455
static vpx_image_t *vp9_get_frame(vpx_codec_alg_priv_t  *ctx,
John Koleszar's avatar
John Koleszar committed
456
457
458
459
460
461
462
463
464
465
                                  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
466
    }
John Koleszar's avatar
John Koleszar committed
467
  }
468
  ctx->img_avail = 0;
John Koleszar's avatar
John Koleszar committed
469

John Koleszar's avatar
John Koleszar committed
470
  return img;
John Koleszar's avatar
John Koleszar committed
471
472
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
473
474
475
476
477
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
478
479
480
481

  /* Get address of next segment request */
  do {
    if (!seg_iter)
482
483
      seg_iter = vp9_mem_req_segs;
    else if (seg_iter->id != VP9_SEG_MAX)
John Koleszar's avatar
John Koleszar committed
484
485
486
487
      seg_iter++;

    *iter = (vpx_codec_iter_t)seg_iter;

488
    if (seg_iter->id != VP9_SEG_MAX) {
John Koleszar's avatar
John Koleszar committed
489
490
491
492
493
494
495
496
497
      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;
498
    } else {
John Koleszar's avatar
John Koleszar committed
499
      res = VPX_CODEC_LIST_END;
500
    }
John Koleszar's avatar
John Koleszar committed
501
502
503
  } while (!mmap->sz && res != VPX_CODEC_LIST_END);

  return res;
John Koleszar's avatar
John Koleszar committed
504
505
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
506
static vpx_codec_err_t vp9_xma_set_mmap(vpx_codec_ctx_t *ctx,
John Koleszar's avatar
John Koleszar committed
507
508
509
510
511
                                        const vpx_codec_mmap_t  *mmap) {
  vpx_codec_err_t res = VPX_CODEC_MEM_ERROR;
  int i, done;

  if (!ctx->priv) {
512
    if (mmap->id == VP9_SEG_ALG_PRIV) {
John Koleszar's avatar
John Koleszar committed
513
      if (!ctx->priv) {
514
        vp9_init_ctx(ctx, mmap);
John Koleszar's avatar
John Koleszar committed
515
516
        res = VPX_CODEC_OK;
      }
John Koleszar's avatar
John Koleszar committed
517
    }
John Koleszar's avatar
John Koleszar committed
518
  }
John Koleszar's avatar
John Koleszar committed
519

John Koleszar's avatar
John Koleszar committed
520
  done = 1;
John Koleszar's avatar
John Koleszar committed
521

John Koleszar's avatar
John Koleszar committed
522
523
524
525
526
527
  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
528
529
        }

John Koleszar's avatar
John Koleszar committed
530
      done &= (ctx->priv->alg_priv->mmaps[i].base != NULL);
John Koleszar's avatar
John Koleszar committed
531
    }
John Koleszar's avatar
John Koleszar committed
532
533
534
  }

  if (done && !res) {
535
    vp9_finalize_mmaps(ctx->priv->alg_priv);
John Koleszar's avatar
John Koleszar committed
536
    res = ctx->iface->init(ctx, NULL);
John Koleszar's avatar
John Koleszar committed
537
  }
John Koleszar's avatar
John Koleszar committed
538

John Koleszar's avatar
John Koleszar committed
539
  return res;
John Koleszar's avatar
John Koleszar committed
540
541
}

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

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

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

Dmitry Kovalev's avatar
Dmitry Kovalev committed
558
static vpx_codec_err_t copy_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
559
                                      va_list args) {
John Koleszar's avatar
John Koleszar committed
560
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
561

John Koleszar's avatar
John Koleszar committed
562
563
564
  if (data) {
    vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
565

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

John Koleszar's avatar
John Koleszar committed
568
569
    return vp9_copy_reference_dec(ctx->pbi,
                                  (VP9_REFFRAME)frame->frame_type, &sd);
570
  } else {
John Koleszar's avatar
John Koleszar committed
571
    return VPX_CODEC_INVALID_PARAM;
572
  }
John Koleszar's avatar
John Koleszar committed
573
574
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
575
static vpx_codec_err_t get_reference(vpx_codec_alg_priv_t *ctx, int ctr_id,
John Koleszar's avatar
John Koleszar committed
576
577
578
579
580
581
582
583
584
585
586
587
588
589
                                     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
590
static vpx_codec_err_t set_postproc(vpx_codec_alg_priv_t *ctx, int ctr_id,
591
                                    va_list args) {
592
#if CONFIG_VP9_POSTPROC
John Koleszar's avatar
John Koleszar committed
593
  vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
John Koleszar's avatar
John Koleszar committed
594

John Koleszar's avatar
John Koleszar committed
595
596
597
598
  if (data) {
    ctx->postproc_cfg_set = 1;
    ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data);
    return VPX_CODEC_OK;
599
  } else {
John Koleszar's avatar
John Koleszar committed
600
    return VPX_CODEC_INVALID_PARAM;
601
  }
John Koleszar's avatar
John Koleszar committed
602
#else
John Koleszar's avatar
John Koleszar committed
603
  return VPX_CODEC_INCAPABLE;
John Koleszar's avatar
John Koleszar committed
604
605
606
#endif
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
607
static vpx_codec_err_t set_dbg_options(vpx_codec_alg_priv_t *ctx, int ctrl_id,
608
                                       va_list args) {
609
#if CONFIG_POSTPROC_VISUALIZER && CONFIG_POSTPROC
John Koleszar's avatar
John Koleszar committed
610
  int data = va_arg(args, int);
611
612
613

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

John Koleszar's avatar
John Koleszar committed
614
615
616
617
618
619
  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);
  }
620

John Koleszar's avatar
John Koleszar committed
621
  return VPX_CODEC_OK;
622
#else
John Koleszar's avatar
John Koleszar committed
623
  return VPX_CODEC_INCAPABLE;
624
625
#endif
}
John Koleszar's avatar
John Koleszar committed
626

627
static vpx_codec_err_t get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
628
                                            int ctrl_id, va_list args) {
John Koleszar's avatar
John Koleszar committed
629
  int *update_info = va_arg(args, int *);
630
  VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
631

John Koleszar's avatar
John Koleszar committed
632
  if (update_info) {
633
    *update_info = pbi->refresh_frame_flags;
634

John Koleszar's avatar
John Koleszar committed
635
    return VPX_CODEC_OK;
636
  } else {
John Koleszar's avatar
John Koleszar committed
637
    return VPX_CODEC_INVALID_PARAM;
638
  }
639
640
641
}


642
static vpx_codec_err_t get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
643
                                           int ctrl_id, va_list args) {
John Koleszar's avatar
John Koleszar committed
644
  int *corrupted = va_arg(args, int *);
645

John Koleszar's avatar
John Koleszar committed
646
  if (corrupted) {
647
    VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
Yaowu Xu's avatar
Yaowu Xu committed
648
649
650
651
    if (pbi)
      *corrupted = pbi->common.frame_to_show->corrupted;
    else
      return VPX_CODEC_ERROR;
John Koleszar's avatar
John Koleszar committed
652
    return VPX_CODEC_OK;
653
  } else {
John Koleszar's avatar
John Koleszar committed
654
    return VPX_CODEC_INVALID_PARAM;
655
  }
656
657
}

658
static vpx_codec_err_t get_display_size(vpx_codec_alg_priv_t *ctx,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
659
                                        int ctrl_id, va_list args) {
660
661
662
  int *const display_size = va_arg(args, int *);

  if (display_size) {
663
    const VP9D_COMP *const pbi = (VP9D_COMP*)ctx->pbi;
664
665
666
667
668
669
670
671
672
673
674
675
    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;
  }
}

676
677
678
679
680
681
682
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;
}

683
static vpx_codec_ctrl_fn_map_t ctf_maps[] = {
684
685
686
687
688
689
690
691
692
  {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
693
  {VP9_GET_REFERENCE,             get_reference},
694
  {VP9D_GET_DISPLAY_SIZE,         get_display_size},
695
  {VP9_INVERT_TILE_DECODE_ORDER,  set_invert_tile_order},
John Koleszar's avatar
John Koleszar committed
696
  { -1, NULL},
John Koleszar's avatar
John Koleszar committed
697
698
699
700
701
702
};


#ifndef VERSION_STRING
#define VERSION_STRING
#endif
703
704
CODEC_INTERFACE(vpx_codec_vp9_dx) = {
  "WebM Project VP9 Decoder" VERSION_STRING,
John Koleszar's avatar
John Koleszar committed
705
  VPX_CODEC_INTERNAL_ABI_VERSION,
706
  VPX_CODEC_CAP_DECODER | VP9_CAP_POSTPROC,
John Koleszar's avatar
John Koleszar committed
707
  /* vpx_codec_caps_t          caps; */
708
709
  vp9_init,         /* vpx_codec_init_fn_t       init; */
  vp9_destroy,      /* vpx_codec_destroy_fn_t    destroy; */
710
  ctf_maps,         /* vpx_codec_ctrl_fn_map_t  *ctrl_maps; */
711
712
  vp9_xma_get_mmap, /* vpx_codec_get_mmap_fn_t   get_mmap; */
  vp9_xma_set_mmap, /* vpx_codec_set_mmap_fn_t   set_mmap; */
713
  { // NOLINT
714
715
    vp9_peek_si,      /* vpx_codec_peek_si_fn_t    peek_si; */
    vp9_get_si,       /* vpx_codec_get_si_fn_t     get_si; */
716
    vp9_decode,       /* vpx_codec_decode_fn_t     decode; */
717
    vp9_get_frame,    /* vpx_codec_frame_get_fn_t  frame_get; */
John Koleszar's avatar
John Koleszar committed
718
  },
719
  { // NOLINT
John Koleszar's avatar
John Koleszar committed
720
721
722
723
724
725
726
727
    /* encoder functions */
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED
  }
John Koleszar's avatar
John Koleszar committed
728
};