vp9_dx_iface.c 22.7 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"
John Koleszar's avatar
John Koleszar committed
17
#include "vpx_version.h"
18
#include "decoder/vp9_onyxd.h"
19
#include "decoder/vp9_onyxd_int.h"
John Koleszar's avatar
John Koleszar committed
20
21
22
23
24

#define VP8_CAP_POSTPROC (CONFIG_POSTPROC ? VPX_CODEC_CAP_POSTPROC : 0)
typedef vpx_codec_stream_info_t  vp8_stream_info_t;

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

static unsigned long vp8_priv_sz(const vpx_codec_dec_cfg_t *si, vpx_codec_flags_t);

John Koleszar's avatar
John Koleszar committed
33
34
35
36
37
38
typedef struct {
  unsigned int   id;
  unsigned long  sz;
  unsigned int   align;
  unsigned int   flags;
  unsigned long(*calc_sz)(const vpx_codec_dec_cfg_t *, vpx_codec_flags_t);
John Koleszar's avatar
John Koleszar committed
39
40
} mem_req_t;

John Koleszar's avatar
John Koleszar committed
41
42
43
static const mem_req_t vp8_mem_req_segs[] = {
  {VP8_SEG_ALG_PRIV,    0, 8, VPX_CODEC_MEM_ZERO, vp8_priv_sz},
  {VP8_SEG_MAX, 0, 0, 0, NULL}
John Koleszar's avatar
John Koleszar committed
44
45
};

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

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


John Koleszar's avatar
John Koleszar committed
80
81
static void vp8_mmap_dtor(vpx_codec_mmap_t *mmap) {
  free(mmap->priv);
John Koleszar's avatar
John Koleszar committed
82
83
}

John Koleszar's avatar
John Koleszar committed
84
85
86
static vpx_codec_err_t vp8_mmap_alloc(vpx_codec_mmap_t *mmap) {
  vpx_codec_err_t  res;
  unsigned int   align;
John Koleszar's avatar
John Koleszar committed
87

John Koleszar's avatar
John Koleszar committed
88
  align = mmap->align ? mmap->align - 1 : 0;
John Koleszar's avatar
John Koleszar committed
89

John Koleszar's avatar
John Koleszar committed
90
91
92
93
  if (mmap->flags & VPX_CODEC_MEM_ZERO)
    mmap->priv = calloc(1, mmap->sz + align);
  else
    mmap->priv = malloc(mmap->sz + align);
John Koleszar's avatar
John Koleszar committed
94

John Koleszar's avatar
John Koleszar committed
95
96
97
98
  res = (mmap->priv) ? VPX_CODEC_OK : VPX_CODEC_MEM_ERROR;
  mmap->base = (void *)((((uintptr_t)mmap->priv) + align) & ~(uintptr_t)align);
  mmap->dtor = vp8_mmap_dtor;
  return res;
John Koleszar's avatar
John Koleszar committed
99
100
101
}

static vpx_codec_err_t vp8_validate_mmaps(const vp8_stream_info_t *si,
102
103
                                          const vpx_codec_mmap_t *mmaps,
                                          vpx_codec_flags_t init_flags) {
John Koleszar's avatar
John Koleszar committed
104
105
106
107
108
109
110
111
112
  int i;
  vpx_codec_err_t res = VPX_CODEC_OK;

  for (i = 0; i < NELEMENTS(vp8_mem_req_segs) - 1; i++) {
    /* Ensure the segment has been allocated */
    if (!mmaps[i].base) {
      res = VPX_CODEC_MEM_ERROR;
      break;
    }
John Koleszar's avatar
John Koleszar committed
113

John Koleszar's avatar
John Koleszar committed
114
115
116
    /* Verify variable size segment is big enough for the current si. */
    if (vp8_mem_req_segs[i].calc_sz) {
      vpx_codec_dec_cfg_t cfg;
John Koleszar's avatar
John Koleszar committed
117

John Koleszar's avatar
John Koleszar committed
118
119
      cfg.w = si->w;
      cfg.h = si->h;
John Koleszar's avatar
John Koleszar committed
120

John Koleszar's avatar
John Koleszar committed
121
122
123
124
      if (mmaps[i].sz < vp8_mem_req_segs[i].calc_sz(&cfg, init_flags)) {
        res = VPX_CODEC_MEM_ERROR;
        break;
      }
John Koleszar's avatar
John Koleszar committed
125
    }
John Koleszar's avatar
John Koleszar committed
126
  }
John Koleszar's avatar
John Koleszar committed
127

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

John Koleszar's avatar
John Koleszar committed
131
132
static void vp8_init_ctx(vpx_codec_ctx_t *ctx, const vpx_codec_mmap_t *mmap) {
  int i;
John Koleszar's avatar
John Koleszar committed
133

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

John Koleszar's avatar
John Koleszar committed
139
140
  for (i = 0; i < NELEMENTS(ctx->priv->alg_priv->mmaps); i++)
    ctx->priv->alg_priv->mmaps[i].id = vp8_mem_req_segs[i].id;
John Koleszar's avatar
John Koleszar committed
141

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

John Koleszar's avatar
John Koleszar committed
146
147
148
149
150
  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
151
152
}

John Koleszar's avatar
John Koleszar committed
153
154
static void *mmap_lkup(vpx_codec_alg_priv_t *ctx, unsigned int id) {
  int i;
John Koleszar's avatar
John Koleszar committed
155

John Koleszar's avatar
John Koleszar committed
156
157
158
  for (i = 0; i < NELEMENTS(ctx->mmaps); i++)
    if (ctx->mmaps[i].id == id)
      return ctx->mmaps[i].base;
John Koleszar's avatar
John Koleszar committed
159

John Koleszar's avatar
John Koleszar committed
160
  return NULL;
John Koleszar's avatar
John Koleszar committed
161
}
John Koleszar's avatar
John Koleszar committed
162
163
static void vp8_finalize_mmaps(vpx_codec_alg_priv_t *ctx) {
  /* nothing to clean up */
John Koleszar's avatar
John Koleszar committed
164
165
}

John Koleszar's avatar
John Koleszar committed
166
167
static vpx_codec_err_t vp8_init(vpx_codec_ctx_t *ctx,
                                vpx_codec_priv_enc_mr_cfg_t *data) {
John Koleszar's avatar
John Koleszar committed
168
  vpx_codec_err_t        res = VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
169

John Koleszar's avatar
John Koleszar committed
170
171
172
173
174
175
  /* This function only allocates space for the vpx_codec_alg_priv_t
   * structure. More memory may be required at the time the stream
   * information becomes known.
   */
  if (!ctx->priv) {
    vpx_codec_mmap_t mmap;
John Koleszar's avatar
John Koleszar committed
176

John Koleszar's avatar
John Koleszar committed
177
178
179
180
    mmap.id = vp8_mem_req_segs[0].id;
    mmap.sz = sizeof(vpx_codec_alg_priv_t);
    mmap.align = vp8_mem_req_segs[0].align;
    mmap.flags = vp8_mem_req_segs[0].flags;
John Koleszar's avatar
John Koleszar committed
181

John Koleszar's avatar
John Koleszar committed
182
    res = vp8_mmap_alloc(&mmap);
John Koleszar's avatar
John Koleszar committed
183

John Koleszar's avatar
John Koleszar committed
184
185
    if (!res) {
      vp8_init_ctx(ctx, &mmap);
John Koleszar's avatar
John Koleszar committed
186

John Koleszar's avatar
John Koleszar committed
187
188
      ctx->priv->alg_priv->defer_alloc = 1;
      /*post processing level initialized to do nothing */
John Koleszar's avatar
John Koleszar committed
189
    }
John Koleszar's avatar
John Koleszar committed
190
  }
John Koleszar's avatar
John Koleszar committed
191

John Koleszar's avatar
John Koleszar committed
192
  return res;
John Koleszar's avatar
John Koleszar committed
193
194
}

John Koleszar's avatar
John Koleszar committed
195
196
static vpx_codec_err_t vp8_destroy(vpx_codec_alg_priv_t *ctx) {
  int i;
John Koleszar's avatar
John Koleszar committed
197

198
  vp9_remove_decompressor(ctx->pbi);
John Koleszar's avatar
John Koleszar committed
199

John Koleszar's avatar
John Koleszar committed
200
201
202
203
  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
204

John Koleszar's avatar
John Koleszar committed
205
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
206
207
208
209
}

static vpx_codec_err_t vp8_peek_si(const uint8_t         *data,
                                   unsigned int           data_sz,
John Koleszar's avatar
John Koleszar committed
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
                                   vpx_codec_stream_info_t *si) {
  vpx_codec_err_t res = VPX_CODEC_OK;

  if (data + data_sz <= data)
    res = VPX_CODEC_INVALID_PARAM;
  else {
    /* Parse uncompresssed part of key frame header.
     * 3 bytes:- including version, frame type and an offset
     * 3 bytes:- sync code (0x9d, 0x01, 0x2a)
     * 4 bytes:- including image width and height in the lowest 14 bits
     *           of each 2-byte value.
     */
    si->is_kf = 0;

    if (data_sz >= 10 && !(data[0] & 0x01)) { /* I-Frame */
      const uint8_t *c = data + 3;
      si->is_kf = 1;

      /* vet via sync code */
      if (c[0] != 0x9d || c[1] != 0x01 || c[2] != 0x2a)
        res = VPX_CODEC_UNSUP_BITSTREAM;

Jingning Han's avatar
Jingning Han committed
232
233
      si->w = (c[3] | (c[4] << 8));
      si->h = (c[5] | (c[6] << 8));
John Koleszar's avatar
John Koleszar committed
234

John Koleszar's avatar
John Koleszar committed
235
236
237
238
239
240
241
242
      /*printf("w=%d, h=%d\n", si->w, si->h);*/
      if (!(si->h | si->w))
        res = VPX_CODEC_UNSUP_BITSTREAM;
    } else
      res = VPX_CODEC_UNSUP_BITSTREAM;
  }

  return res;
John Koleszar's avatar
John Koleszar committed
243
244
245
246

}

static vpx_codec_err_t vp8_get_si(vpx_codec_alg_priv_t    *ctx,
John Koleszar's avatar
John Koleszar committed
247
                                  vpx_codec_stream_info_t *si) {
John Koleszar's avatar
John Koleszar committed
248

John Koleszar's avatar
John Koleszar committed
249
  unsigned int sz;
John Koleszar's avatar
John Koleszar committed
250

John Koleszar's avatar
John Koleszar committed
251
252
253
254
  if (si->sz >= sizeof(vp8_stream_info_t))
    sz = sizeof(vp8_stream_info_t);
  else
    sz = sizeof(vpx_codec_stream_info_t);
John Koleszar's avatar
John Koleszar committed
255

John Koleszar's avatar
John Koleszar committed
256
257
  memcpy(si, &ctx->si, sz);
  si->sz = sz;
John Koleszar's avatar
John Koleszar committed
258

John Koleszar's avatar
John Koleszar committed
259
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
260
261
262
263
264
}


static vpx_codec_err_t
update_error_state(vpx_codec_alg_priv_t                 *ctx,
John Koleszar's avatar
John Koleszar committed
265
266
                   const struct vpx_internal_error_info *error) {
  vpx_codec_err_t res;
John Koleszar's avatar
John Koleszar committed
267

John Koleszar's avatar
John Koleszar committed
268
269
270
271
  if ((res = error->error_code))
    ctx->base.err_detail = error->has_detail
                           ? error->detail
                           : NULL;
John Koleszar's avatar
John Koleszar committed
272

John Koleszar's avatar
John Koleszar committed
273
  return res;
John Koleszar's avatar
John Koleszar committed
274
275
}

276
277
static void yuvconfig2image(vpx_image_t               *img,
                            const YV12_BUFFER_CONFIG  *yv12,
John Koleszar's avatar
John Koleszar committed
278
279
280
281
282
283
284
285
                            void                      *user_priv) {
  /** vpx_img_wrap() doesn't allow specifying independent strides for
    * the Y, U, and V planes, nor other alignment adjustments that
    * might be representable by a YV12_BUFFER_CONFIG, so we just
    * initialize all the fields.*/
  img->fmt = yv12->clrtype == REG_YUV ?
             VPX_IMG_FMT_I420 : VPX_IMG_FMT_VPXI420;
  img->w = yv12->y_stride;
John Koleszar's avatar
John Koleszar committed
286
  img->h = (yv12->y_height + 2 * VP9BORDERINPIXELS + 15) & ~15;
John Koleszar's avatar
John Koleszar committed
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
  img->d_w = yv12->y_width;
  img->d_h = yv12->y_height;
  img->x_chroma_shift = 1;
  img->y_chroma_shift = 1;
  img->planes[VPX_PLANE_Y] = yv12->y_buffer;
  img->planes[VPX_PLANE_U] = yv12->u_buffer;
  img->planes[VPX_PLANE_V] = yv12->v_buffer;
  img->planes[VPX_PLANE_ALPHA] = NULL;
  img->stride[VPX_PLANE_Y] = yv12->y_stride;
  img->stride[VPX_PLANE_U] = yv12->uv_stride;
  img->stride[VPX_PLANE_V] = yv12->uv_stride;
  img->stride[VPX_PLANE_ALPHA] = yv12->y_stride;
  img->bps = 12;
  img->user_priv = user_priv;
  img->img_data = yv12->buffer_alloc;
  img->img_data_owner = 0;
  img->self_allocd = 0;
304
}
John Koleszar's avatar
John Koleszar committed
305

306
307
308
309
310
static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t  *ctx,
                                  const uint8_t        **data,
                                  unsigned int           data_sz,
                                  void                  *user_priv,
                                  long                   deadline) {
John Koleszar's avatar
John Koleszar committed
311
  vpx_codec_err_t res = VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
312

John Koleszar's avatar
John Koleszar committed
313
  ctx->img_avail = 0;
John Koleszar's avatar
John Koleszar committed
314

John Koleszar's avatar
John Koleszar committed
315
316
317
318
319
  /* 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)
320
    res = ctx->base.iface->dec.peek_si(*data, data_sz, &ctx->si);
John Koleszar's avatar
John Koleszar committed
321
322


John Koleszar's avatar
John Koleszar committed
323
324
325
  /* Perform deferred allocations, if required */
  if (!res && ctx->defer_alloc) {
    int i;
John Koleszar's avatar
John Koleszar committed
326

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

John Koleszar's avatar
John Koleszar committed
330
331
332
333
334
335
      cfg.w = ctx->si.w;
      cfg.h = ctx->si.h;
      ctx->mmaps[i].id = vp8_mem_req_segs[i].id;
      ctx->mmaps[i].sz = vp8_mem_req_segs[i].sz;
      ctx->mmaps[i].align = vp8_mem_req_segs[i].align;
      ctx->mmaps[i].flags = vp8_mem_req_segs[i].flags;
John Koleszar's avatar
John Koleszar committed
336

John Koleszar's avatar
John Koleszar committed
337
338
339
      if (!ctx->mmaps[i].sz)
        ctx->mmaps[i].sz = vp8_mem_req_segs[i].calc_sz(&cfg,
                                                       ctx->base.init_flags);
John Koleszar's avatar
John Koleszar committed
340

John Koleszar's avatar
John Koleszar committed
341
      res = vp8_mmap_alloc(&ctx->mmaps[i]);
John Koleszar's avatar
John Koleszar committed
342
343
    }

John Koleszar's avatar
John Koleszar committed
344
345
346
347
348
349
350
351
352
353
354
    if (!res)
      vp8_finalize_mmaps(ctx);

    ctx->defer_alloc = 0;
  }

  /* Initialize the decoder instance on the first frame*/
  if (!res && !ctx->decoder_init) {
    res = vp8_validate_mmaps(&ctx->si, ctx->mmaps, ctx->base.init_flags);

    if (!res) {
355
356
      VP9D_CONFIG oxcf;
      VP9D_PTR optr;
John Koleszar's avatar
John Koleszar committed
357

358
      vp9_initialize_dec();
John Koleszar's avatar
John Koleszar committed
359
360
361
362
363
364

      oxcf.Width = ctx->si.w;
      oxcf.Height = ctx->si.h;
      oxcf.Version = 9;
      oxcf.postprocess = 0;
      oxcf.max_threads = ctx->cfg.threads;
365
      oxcf.inv_tile_order = ctx->cfg.inv_tile_order;
366
      optr = vp9_create_decompressor(&oxcf);
John Koleszar's avatar
John Koleszar committed
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382

      /* If postprocessing was enabled by the application and a
       * configuration has not been provided, default it.
       */
      if (!ctx->postproc_cfg_set
          && (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)) {
        ctx->postproc_cfg.post_proc_flag =
          VP8_DEBLOCK | VP8_DEMACROBLOCK;
        ctx->postproc_cfg.deblocking_level = 4;
        ctx->postproc_cfg.noise_level = 0;
      }

      if (!optr)
        res = VPX_CODEC_ERROR;
      else
        ctx->pbi = optr;
John Koleszar's avatar
John Koleszar committed
383
384
    }

John Koleszar's avatar
John Koleszar committed
385
386
387
388
389
390
    ctx->decoder_init = 1;
  }

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

John Koleszar's avatar
John Koleszar committed
393
394
    if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) {
      flags.post_proc_flag = ctx->postproc_cfg.post_proc_flag
395
396
#if CONFIG_POSTPROC_VISUALIZER

397
398
399
400
                             | ((ctx->dbg_color_ref_frame_flag != 0) ? VP9D_DEBUG_CLR_FRM_REF_BLKS : 0)
                             | ((ctx->dbg_color_mb_modes_flag != 0) ? VP9D_DEBUG_CLR_BLK_MODES : 0)
                             | ((ctx->dbg_color_b_modes_flag != 0) ? VP9D_DEBUG_CLR_BLK_MODES : 0)
                             | ((ctx->dbg_display_mv_flag != 0) ? VP9D_DEBUG_DRAW_MV : 0)
401
#endif
John Koleszar's avatar
John Koleszar committed
402
403
404
;
      flags.deblocking_level      = ctx->postproc_cfg.deblocking_level;
      flags.noise_level           = ctx->postproc_cfg.noise_level;
405
#if CONFIG_POSTPROC_VISUALIZER
John Koleszar's avatar
John Koleszar committed
406
407
408
409
      flags.display_ref_frame_flag = ctx->dbg_color_ref_frame_flag;
      flags.display_mb_modes_flag = ctx->dbg_color_mb_modes_flag;
      flags.display_b_modes_flag  = ctx->dbg_color_b_modes_flag;
      flags.display_mv_flag       = ctx->dbg_display_mv_flag;
410
#endif
John Koleszar's avatar
John Koleszar committed
411
    }
John Koleszar's avatar
John Koleszar committed
412

413
    if (vp9_receive_compressed_data(ctx->pbi, data_sz, data, deadline)) {
414
      VP9D_COMP *pbi = (VP9D_COMP *)ctx->pbi;
John Koleszar's avatar
John Koleszar committed
415
416
      res = update_error_state(ctx, &pbi->common.error);
    }
John Koleszar's avatar
John Koleszar committed
417

418
419
    if (!res && 0 == vp9_get_raw_frame(ctx->pbi, &sd, &time_stamp,
                                       &time_end_stamp, &flags)) {
John Koleszar's avatar
John Koleszar committed
420
421
      yuvconfig2image(&ctx->img, &sd, user_priv);
      ctx->img_avail = 1;
John Koleszar's avatar
John Koleszar committed
422
    }
John Koleszar's avatar
John Koleszar committed
423
  }
John Koleszar's avatar
John Koleszar committed
424

John Koleszar's avatar
John Koleszar committed
425
  return res;
John Koleszar's avatar
John Koleszar committed
426
427
}

John Koleszar's avatar
John Koleszar committed
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
static void parse_superframe_index(const uint8_t *data,
                                   size_t         data_sz,
                                   uint32_t       sizes[8],
                                   int           *count) {
  uint8_t marker;

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

  if ((marker & 0xf0) == 0xc0) {
    const int frames = (marker & 0x7) + 1;
    const int mag = ((marker >> 3) & 3) + 1;
    const int index_sz = 2 + mag  * frames;

    if (data_sz >= index_sz && data[data_sz - index_sz] == marker) {
      // found a valid superframe index
      int i, j;
      const uint8_t *x = data + data_sz - index_sz + 1;

      for (i = 0; i < frames; i++) {
        int this_sz = 0;

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

      *count = frames;
    }
  }
}

461
462
463
464
465
466
467
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;
468
  vpx_codec_err_t res = 0;
John Koleszar's avatar
John Koleszar committed
469
470
471
472
  uint32_t sizes[8];
  int frames_this_pts, frame_count = 0;

  parse_superframe_index(data, data_sz, sizes, &frames_this_pts);
473
474

  do {
John Koleszar's avatar
John Koleszar committed
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
    // Skip over the superframe index, if present
    if (data_sz && (*data_start & 0xf0) == 0xc0) {
      const uint8_t marker = *data_start;
      const int frames = (marker & 0x7) + 1;
      const int mag = ((marker >> 3) & 3) + 1;
      const int index_sz = 2 + mag  * frames;

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

505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
    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;
}

John Koleszar's avatar
John Koleszar committed
522
static vpx_image_t *vp8_get_frame(vpx_codec_alg_priv_t  *ctx,
John Koleszar's avatar
John Koleszar committed
523
524
525
526
527
528
529
530
531
532
                                  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
533
    }
John Koleszar's avatar
John Koleszar committed
534
  }
John Koleszar's avatar
John Koleszar committed
535

John Koleszar's avatar
John Koleszar committed
536
  return img;
John Koleszar's avatar
John Koleszar committed
537
538
539
540
541
542
}


static
vpx_codec_err_t vp8_xma_get_mmap(const vpx_codec_ctx_t      *ctx,
                                 vpx_codec_mmap_t           *mmap,
John Koleszar's avatar
John Koleszar committed
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
                                 vpx_codec_iter_t           *iter) {
  vpx_codec_err_t     res;
  const mem_req_t  *seg_iter = *iter;

  /* Get address of next segment request */
  do {
    if (!seg_iter)
      seg_iter = vp8_mem_req_segs;
    else if (seg_iter->id != VP8_SEG_MAX)
      seg_iter++;

    *iter = (vpx_codec_iter_t)seg_iter;

    if (seg_iter->id != VP8_SEG_MAX) {
      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;
    } else
      res = VPX_CODEC_LIST_END;
  } while (!mmap->sz && res != VPX_CODEC_LIST_END);

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

static vpx_codec_err_t vp8_xma_set_mmap(vpx_codec_ctx_t         *ctx,
John Koleszar's avatar
John Koleszar committed
574
575
576
577
578
579
580
581
582
583
                                        const vpx_codec_mmap_t  *mmap) {
  vpx_codec_err_t res = VPX_CODEC_MEM_ERROR;
  int i, done;

  if (!ctx->priv) {
    if (mmap->id == VP8_SEG_ALG_PRIV) {
      if (!ctx->priv) {
        vp8_init_ctx(ctx, mmap);
        res = VPX_CODEC_OK;
      }
John Koleszar's avatar
John Koleszar committed
584
    }
John Koleszar's avatar
John Koleszar committed
585
  }
John Koleszar's avatar
John Koleszar committed
586

John Koleszar's avatar
John Koleszar committed
587
  done = 1;
John Koleszar's avatar
John Koleszar committed
588

John Koleszar's avatar
John Koleszar committed
589
590
591
592
593
594
  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
595
596
        }

John Koleszar's avatar
John Koleszar committed
597
      done &= (ctx->priv->alg_priv->mmaps[i].base != NULL);
John Koleszar's avatar
John Koleszar committed
598
    }
John Koleszar's avatar
John Koleszar committed
599
600
601
602
  }

  if (done && !res) {
    vp8_finalize_mmaps(ctx->priv->alg_priv);
John Koleszar's avatar
John Koleszar committed
603
    res = ctx->iface->init(ctx, NULL);
John Koleszar's avatar
John Koleszar committed
604
  }
John Koleszar's avatar
John Koleszar committed
605

John Koleszar's avatar
John Koleszar committed
606
  return res;
John Koleszar's avatar
John Koleszar committed
607
608
609
}

static vpx_codec_err_t image2yuvconfig(const vpx_image_t   *img,
John Koleszar's avatar
John Koleszar committed
610
611
612
613
614
                                       YV12_BUFFER_CONFIG  *yv12) {
  vpx_codec_err_t        res = VPX_CODEC_OK;
  yv12->y_buffer = img->planes[VPX_PLANE_Y];
  yv12->u_buffer = img->planes[VPX_PLANE_U];
  yv12->v_buffer = img->planes[VPX_PLANE_V];
John Koleszar's avatar
John Koleszar committed
615

John Koleszar's avatar
John Koleszar committed
616
617
618
619
  yv12->y_width  = img->d_w;
  yv12->y_height = img->d_h;
  yv12->uv_width = yv12->y_width / 2;
  yv12->uv_height = yv12->y_height / 2;
John Koleszar's avatar
John Koleszar committed
620

John Koleszar's avatar
John Koleszar committed
621
622
  yv12->y_stride = img->stride[VPX_PLANE_Y];
  yv12->uv_stride = img->stride[VPX_PLANE_U];
John Koleszar's avatar
John Koleszar committed
623

John Koleszar's avatar
John Koleszar committed
624
  yv12->border  = (img->stride[VPX_PLANE_Y] - img->d_w) / 2;
625
626
  yv12->clrtype = (img->fmt == VPX_IMG_FMT_VPXI420 ||
                   img->fmt == VPX_IMG_FMT_VPXYV12);
John Koleszar's avatar
John Koleszar committed
627

John Koleszar's avatar
John Koleszar committed
628
  return res;
John Koleszar's avatar
John Koleszar committed
629
630
631
}


632
static vpx_codec_err_t vp9_set_reference(vpx_codec_alg_priv_t *ctx,
John Koleszar's avatar
John Koleszar committed
633
634
                                         int ctr_id,
                                         va_list args) {
John Koleszar's avatar
John Koleszar committed
635

John Koleszar's avatar
John Koleszar committed
636
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
637

John Koleszar's avatar
John Koleszar committed
638
639
640
  if (data) {
    vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
641

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

644
645
    return vp9_set_reference_dec(ctx->pbi,
                                 (VP9_REFFRAME)frame->frame_type, &sd);
John Koleszar's avatar
John Koleszar committed
646
647
  } else
    return VPX_CODEC_INVALID_PARAM;
John Koleszar's avatar
John Koleszar committed
648
649
650

}

651
static vpx_codec_err_t vp9_get_reference(vpx_codec_alg_priv_t *ctx,
John Koleszar's avatar
John Koleszar committed
652
653
                                         int ctr_id,
                                         va_list args) {
John Koleszar's avatar
John Koleszar committed
654

John Koleszar's avatar
John Koleszar committed
655
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
656

John Koleszar's avatar
John Koleszar committed
657
658
659
  if (data) {
    vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
660

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

663
664
    return vp9_get_reference_dec(ctx->pbi,
                                 (VP9_REFFRAME)frame->frame_type, &sd);
John Koleszar's avatar
John Koleszar committed
665
666
  } else
    return VPX_CODEC_INVALID_PARAM;
John Koleszar's avatar
John Koleszar committed
667
668
669
670
671

}

static vpx_codec_err_t vp8_set_postproc(vpx_codec_alg_priv_t *ctx,
                                        int ctr_id,
John Koleszar's avatar
John Koleszar committed
672
                                        va_list args) {
John Koleszar's avatar
John Koleszar committed
673
#if CONFIG_POSTPROC
John Koleszar's avatar
John Koleszar committed
674
  vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
John Koleszar's avatar
John Koleszar committed
675

John Koleszar's avatar
John Koleszar committed
676
677
678
679
680
681
  if (data) {
    ctx->postproc_cfg_set = 1;
    ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data);
    return VPX_CODEC_OK;
  } else
    return VPX_CODEC_INVALID_PARAM;
John Koleszar's avatar
John Koleszar committed
682
683

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

688
static vpx_codec_err_t vp8_set_dbg_options(vpx_codec_alg_priv_t *ctx,
John Koleszar's avatar
John Koleszar committed
689
690
                                           int ctrl_id,
                                           va_list args) {
691
#if CONFIG_POSTPROC_VISUALIZER && CONFIG_POSTPROC
John Koleszar's avatar
John Koleszar committed
692
  int data = va_arg(args, int);
693
694
695

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

John Koleszar's avatar
John Koleszar committed
696
697
698
699
700
701
  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);
  }
702

John Koleszar's avatar
John Koleszar committed
703
  return VPX_CODEC_OK;
704
#else
John Koleszar's avatar
John Koleszar committed
705
  return VPX_CODEC_INCAPABLE;
706
707
#endif
}
John Koleszar's avatar
John Koleszar committed
708

709
710
static vpx_codec_err_t vp8_get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
                                                int ctrl_id,
John Koleszar's avatar
John Koleszar committed
711
712
                                                va_list args) {
  int *update_info = va_arg(args, int *);
713
  VP9D_COMP *pbi = (VP9D_COMP *)ctx->pbi;
714

John Koleszar's avatar
John Koleszar committed
715
  if (update_info) {
716
    *update_info = pbi->refresh_frame_flags;
717

John Koleszar's avatar
John Koleszar committed
718
719
720
    return VPX_CODEC_OK;
  } else
    return VPX_CODEC_INVALID_PARAM;
721
722
723
}


724
725
static vpx_codec_err_t vp8_get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
                                               int ctrl_id,
John Koleszar's avatar
John Koleszar committed
726
                                               va_list args) {
727

John Koleszar's avatar
John Koleszar committed
728
  int *corrupted = va_arg(args, int *);
729

John Koleszar's avatar
John Koleszar committed
730
  if (corrupted) {
731
    VP9D_COMP *pbi = (VP9D_COMP *)ctx->pbi;
John Koleszar's avatar
John Koleszar committed
732
    *corrupted = pbi->common.frame_to_show->corrupted;
733

John Koleszar's avatar
John Koleszar committed
734
735
736
    return VPX_CODEC_OK;
  } else
    return VPX_CODEC_INVALID_PARAM;
737
738
739

}

740
static vpx_codec_ctrl_fn_map_t ctf_maps[] = {
741
742
  {VP8_SET_REFERENCE,             vp9_set_reference},
  {VP8_COPY_REFERENCE,            vp9_get_reference},
John Koleszar's avatar
John Koleszar committed
743
744
745
746
747
748
749
750
  {VP8_SET_POSTPROC,              vp8_set_postproc},
  {VP8_SET_DBG_COLOR_REF_FRAME,   vp8_set_dbg_options},
  {VP8_SET_DBG_COLOR_MB_MODES,    vp8_set_dbg_options},
  {VP8_SET_DBG_COLOR_B_MODES,     vp8_set_dbg_options},
  {VP8_SET_DBG_DISPLAY_MV,        vp8_set_dbg_options},
  {VP8D_GET_LAST_REF_UPDATES,     vp8_get_last_ref_updates},
  {VP8D_GET_FRAME_CORRUPTED,      vp8_get_frame_corrupted},
  { -1, NULL},
John Koleszar's avatar
John Koleszar committed
751
752
753
754
755
756
};


#ifndef VERSION_STRING
#define VERSION_STRING
#endif
757
758
CODEC_INTERFACE(vpx_codec_vp9_dx) = {
  "WebM Project VP9 Decoder" VERSION_STRING,
John Koleszar's avatar
John Koleszar committed
759
760
761
762
763
  VPX_CODEC_INTERNAL_ABI_VERSION,
  VPX_CODEC_CAP_DECODER | VP8_CAP_POSTPROC,
  /* vpx_codec_caps_t          caps; */
  vp8_init,         /* vpx_codec_init_fn_t       init; */
  vp8_destroy,      /* vpx_codec_destroy_fn_t    destroy; */
764
  ctf_maps,         /* vpx_codec_ctrl_fn_map_t  *ctrl_maps; */
John Koleszar's avatar
John Koleszar committed
765
766
767
768
769
  vp8_xma_get_mmap, /* vpx_codec_get_mmap_fn_t   get_mmap; */
  vp8_xma_set_mmap, /* vpx_codec_set_mmap_fn_t   set_mmap; */
  {
    vp8_peek_si,      /* vpx_codec_peek_si_fn_t    peek_si; */
    vp8_get_si,       /* vpx_codec_get_si_fn_t     get_si; */
770
    vp9_decode,       /* vpx_codec_decode_fn_t     decode; */
John Koleszar's avatar
John Koleszar committed
771
772
773
774
775
776
777
778
779
780
781
    vp8_get_frame,    /* vpx_codec_frame_get_fn_t  frame_get; */
  },
  {
    /* encoder functions */
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED,
    NOT_IMPLEMENTED
  }
John Koleszar's avatar
John Koleszar committed
782
};