vp9_dx_iface.c 38.6 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
 */

#include <stdlib.h>
#include <string.h>
13

14
#include "./vpx_config.h"
15
#include "./vpx_version.h"
16 17 18 19 20

#include "vpx/internal/vpx_codec_internal.h"
#include "vpx/vp8dx.h"
#include "vpx/vpx_decoder.h"

21
#include "vp9/common/vp9_alloccommon.h"
22
#include "vp9/common/vp9_frame_buffers.h"
23
#include "vp9/common/vp9_thread.h"
24

25
#include "vp9/decoder/vp9_decoder.h"
26
#include "vp9/decoder/vp9_decodeframe.h"
27
#include "vp9/decoder/vp9_read_bit_buffer.h"
28

29
#include "vp9/vp9_iface_common.h"
John Koleszar's avatar
John Koleszar committed
30

31
#define VP9_CAP_POSTPROC (CONFIG_VP9_POSTPROC ? VPX_CODEC_CAP_POSTPROC : 0)
32 33

typedef vpx_codec_stream_info_t vp9_stream_info_t;
John Koleszar's avatar
John Koleszar committed
34

35 36 37 38 39 40 41 42 43
// This limit is due to framebuffer numbers.
// TODO(hkuang): Remove this limit after implementing ondemand framebuffers.
#define FRAME_CACHE_SIZE 6   // Cache maximum 6 decoded frames.

typedef struct cache_frame {
  int fb_idx;
  vpx_image_t img;
} cache_frame;

John Koleszar's avatar
John Koleszar committed
44 45 46
struct vpx_codec_alg_priv {
  vpx_codec_priv_t        base;
  vpx_codec_dec_cfg_t     cfg;
47
  vp9_stream_info_t       si;
John Koleszar's avatar
John Koleszar committed
48 49
  int                     postproc_cfg_set;
  vp8_postproc_cfg_t      postproc_cfg;
50
  vpx_decrypt_cb          decrypt_cb;
51
  void                    *decrypt_state;
John Koleszar's avatar
John Koleszar committed
52
  vpx_image_t             img;
53
  int                     img_avail;
54
  int                     flushed;
55
  int                     invert_tile_order;
56
  int                     last_show_frame;  // Index of last output frame.
57
  int                     byte_alignment;
58 59

  // Frame parallel related.
60
  int                     frame_parallel_decode;  // frame-based threading.
61 62 63 64 65 66 67 68 69 70
  VP9Worker               *frame_workers;
  int                     num_frame_workers;
  int                     next_submit_worker_id;
  int                     last_submit_worker_id;
  int                     next_output_worker_id;
  int                     available_threads;
  cache_frame             frame_cache[FRAME_CACHE_SIZE];
  int                     frame_cache_write;
  int                     frame_cache_read;
  int                     num_cache_frames;
71
  int                     need_resync;      // wait for key/intra-only frame
72 73
  // BufferPool that holds all reference frames. Shared by all the FrameWorkers.
  BufferPool              *buffer_pool;
74

75 76 77 78
  // 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
79 80
};

81
static vpx_codec_err_t decoder_init(vpx_codec_ctx_t *ctx,
82
                                    vpx_codec_priv_enc_mr_cfg_t *data) {
83 84 85
  // 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.
86 87
  (void)data;

John Koleszar's avatar
John Koleszar committed
88
  if (!ctx->priv) {
89 90
    vpx_codec_alg_priv_t *const priv = vpx_calloc(1, sizeof(*priv));
    if (priv == NULL)
91 92
      return VPX_CODEC_MEM_ERROR;

93
    ctx->priv = (vpx_codec_priv_t *)priv;
94
    ctx->priv->init_flags = ctx->init_flags;
95 96
    priv->si.sz = sizeof(priv->si);
    priv->flushed = 0;
97
    // Only do frame parallel decode when threads > 1.
98
    priv->frame_parallel_decode =
99 100
        (ctx->config.dec && (ctx->config.dec->threads > 1) &&
         (ctx->init_flags & VPX_CODEC_USE_FRAME_THREADING)) ? 1 : 0;
101
    if (ctx->config.dec) {
102 103
      priv->cfg = *ctx->config.dec;
      ctx->config.dec = &priv->cfg;
John Koleszar's avatar
John Koleszar committed
104
    }
John Koleszar's avatar
John Koleszar committed
105
  }
John Koleszar's avatar
John Koleszar committed
106

107
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
108 109
}

110
static vpx_codec_err_t decoder_destroy(vpx_codec_alg_priv_t *ctx) {
111 112 113 114 115 116 117 118
  if (ctx->frame_workers != NULL) {
    int i;
    for (i = 0; i < ctx->num_frame_workers; ++i) {
      VP9Worker *const worker = &ctx->frame_workers[i];
      FrameWorkerData *const frame_worker_data =
          (FrameWorkerData *)worker->data1;
      vp9_get_worker_interface()->end(worker);
      vp9_remove_common(&frame_worker_data->pbi->common);
119 120 121
#if CONFIG_VP9_POSTPROC
      vp9_free_postproc_buffers(&frame_worker_data->pbi->common);
#endif
122 123 124 125 126 127 128 129 130 131 132
      vp9_decoder_remove(frame_worker_data->pbi);
      vpx_free(frame_worker_data->scratch_buffer);
#if CONFIG_MULTITHREAD
      pthread_mutex_destroy(&frame_worker_data->stats_mutex);
      pthread_cond_destroy(&frame_worker_data->stats_cond);
#endif
      vpx_free(frame_worker_data);
    }
#if CONFIG_MULTITHREAD
    pthread_mutex_destroy(&ctx->buffer_pool->pool_mutex);
#endif
133
  }
John Koleszar's avatar
John Koleszar committed
134

135 136
  if (ctx->buffer_pool) {
    vp9_free_ref_frame_buffers(ctx->buffer_pool);
137
    vp9_free_internal_frame_buffers(&ctx->buffer_pool->int_frame_buffers);
138
  }
139

140 141 142
  vpx_free(ctx->frame_workers);
  vpx_free(ctx->buffer_pool);
  vpx_free(ctx);
John Koleszar's avatar
John Koleszar committed
143
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
144 145
}

146 147
static int parse_bitdepth_colorspace_sampling(
    BITSTREAM_PROFILE profile, struct vp9_read_bit_buffer *rb) {
148
  vpx_color_space_t color_space;
149 150
  if (profile >= PROFILE_2)
    rb->bit_offset += 1;  // Bit-depth 10 or 12.
151 152
  color_space = (vpx_color_space_t)vp9_rb_read_literal(rb, 3);
  if (color_space != VPX_CS_SRGB) {
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
    rb->bit_offset += 1;  // [16,235] (including xvycc) vs [0,255] range.
    if (profile == PROFILE_1 || profile == PROFILE_3) {
      rb->bit_offset += 2;  // subsampling x/y.
      rb->bit_offset += 1;  // unused.
    }
  } else {
    if (profile == PROFILE_1 || profile == PROFILE_3) {
      rb->bit_offset += 1;  // unused
    } else {
      // RGB is only available in version 1.
      return 0;
    }
  }
  return 1;
}

169 170 171
static vpx_codec_err_t decoder_peek_si_internal(const uint8_t *data,
                                                unsigned int data_sz,
                                                vpx_codec_stream_info_t *si,
172
                                                int *is_intra_only,
173 174
                                                vpx_decrypt_cb decrypt_cb,
                                                void *decrypt_state) {
175
  int intra_only_flag = 0;
176 177
  uint8_t clear_buffer[9];

178 179
  if (data + data_sz <= data)
    return VPX_CODEC_INVALID_PARAM;
180 181 182

  si->is_kf = 0;
  si->w = si->h = 0;
John Koleszar's avatar
John Koleszar committed
183

184 185 186 187 188 189
  if (decrypt_cb) {
    data_sz = MIN(sizeof(clear_buffer), data_sz);
    decrypt_cb(decrypt_state, data, clear_buffer, data_sz);
    data = clear_buffer;
  }

190
  {
191 192
    int show_frame;
    int error_resilient;
193 194
    struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
    const int frame_marker = vp9_rb_read_literal(&rb, 2);
195
    const BITSTREAM_PROFILE profile = vp9_read_profile(&rb);
196

197 198
    if (frame_marker != VP9_FRAME_MARKER)
      return VPX_CODEC_UNSUP_BITSTREAM;
199

Yaowu Xu's avatar
Yaowu Xu committed
200 201 202 203 204
    if (profile >= MAX_PROFILES)
      return VPX_CODEC_UNSUP_BITSTREAM;

    if ((profile >= 2 && data_sz <= 1) || data_sz < 1)
      return VPX_CODEC_UNSUP_BITSTREAM;
205 206

    if (vp9_rb_read_bit(&rb)) {  // show an existing frame
207
      vp9_rb_read_literal(&rb, 3);  // Frame buffer to show.
208 209
      return VPX_CODEC_OK;
    }
210

211 212 213
    if (data_sz <= 8)
      return VPX_CODEC_UNSUP_BITSTREAM;

214
    si->is_kf = !vp9_rb_read_bit(&rb);
215 216 217
    show_frame = vp9_rb_read_bit(&rb);
    error_resilient = vp9_rb_read_bit(&rb);

218
    if (si->is_kf) {
219
      if (!vp9_read_sync_code(&rb))
220 221
        return VPX_CODEC_UNSUP_BITSTREAM;

222 223
      if (!parse_bitdepth_colorspace_sampling(profile, &rb))
        return VPX_CODEC_UNSUP_BITSTREAM;
224 225 226
      vp9_read_frame_size(&rb, (int *)&si->w, (int *)&si->h);
    } else {
      intra_only_flag = show_frame ? 0 : vp9_rb_read_bit(&rb);
227

228
      rb.bit_offset += error_resilient ? 0 : 2;  // reset_frame_context
229

230 231 232
      if (intra_only_flag) {
        if (!vp9_read_sync_code(&rb))
          return VPX_CODEC_UNSUP_BITSTREAM;
233 234 235 236
        if (profile > PROFILE_0) {
          if (!parse_bitdepth_colorspace_sampling(profile, &rb))
            return VPX_CODEC_UNSUP_BITSTREAM;
        }
237 238 239
        rb.bit_offset += REF_FRAMES;  // refresh_frame_flags
        vp9_read_frame_size(&rb, (int *)&si->w, (int *)&si->h);
      }
240
    }
John Koleszar's avatar
John Koleszar committed
241
  }
242 243
  if (is_intra_only != NULL)
    *is_intra_only = intra_only_flag;
244
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
245 246
}

247 248 249
static vpx_codec_err_t decoder_peek_si(const uint8_t *data,
                                       unsigned int data_sz,
                                       vpx_codec_stream_info_t *si) {
250
  return decoder_peek_si_internal(data, data_sz, si, NULL, NULL, NULL);
251 252
}

253 254
static vpx_codec_err_t decoder_get_si(vpx_codec_alg_priv_t *ctx,
                                      vpx_codec_stream_info_t *si) {
255 256 257
  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
258
  memcpy(si, &ctx->si, sz);
259
  si->sz = (unsigned int)sz;
John Koleszar's avatar
John Koleszar committed
260

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

264 265 266 267 268
static void set_error_detail(vpx_codec_alg_priv_t *ctx,
                             const char *const error) {
  ctx->base.err_detail = error;
}

269 270 271
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)
272
    set_error_detail(ctx, error->has_detail ? error->detail : NULL);
John Koleszar's avatar
John Koleszar committed
273

274
  return error->error_code;
John Koleszar's avatar
John Koleszar committed
275 276
}

277
static void init_buffer_callbacks(vpx_codec_alg_priv_t *ctx) {
278
  int i;
279

280 281 282 283 284
  for (i = 0; i < ctx->num_frame_workers; ++i) {
    VP9Worker *const worker = &ctx->frame_workers[i];
    FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
    VP9_COMMON *const cm = &frame_worker_data->pbi->common;
    BufferPool *const pool = cm->buffer_pool;
285

286
    cm->new_fb_idx = INVALID_IDX;
287
    cm->byte_alignment = ctx->byte_alignment;
288

289 290 291 292 293 294 295
    if (ctx->get_ext_fb_cb != NULL && ctx->release_ext_fb_cb != NULL) {
      pool->get_fb_cb = ctx->get_ext_fb_cb;
      pool->release_fb_cb = ctx->release_ext_fb_cb;
      pool->cb_priv = ctx->ext_priv;
    } else {
      pool->get_fb_cb = vp9_get_frame_buffer;
      pool->release_fb_cb = vp9_release_frame_buffer;
296

297 298 299 300 301 302
      if (vp9_alloc_internal_frame_buffers(&pool->int_frame_buffers))
        vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
                           "Failed to initialize internal frame buffers");

      pool->cb_priv = &pool->int_frame_buffers;
    }
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
  }
}

static void set_default_ppflags(vp8_postproc_cfg_t *cfg) {
  cfg->post_proc_flag = VP8_DEBLOCK | VP8_DEMACROBLOCK;
  cfg->deblocking_level = 4;
  cfg->noise_level = 0;
}

static void set_ppflags(const vpx_codec_alg_priv_t *ctx,
                        vp9_ppflags_t *flags) {
  flags->post_proc_flag =
      ctx->postproc_cfg.post_proc_flag;

  flags->deblocking_level = ctx->postproc_cfg.deblocking_level;
  flags->noise_level = ctx->postproc_cfg.noise_level;
}

321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
static int frame_worker_hook(void *arg1, void *arg2) {
  FrameWorkerData *const frame_worker_data = (FrameWorkerData *)arg1;
  const uint8_t *data = frame_worker_data->data;
  (void)arg2;

  frame_worker_data->result =
      vp9_receive_compressed_data(frame_worker_data->pbi,
                                  frame_worker_data->data_size,
                                  &data);
  frame_worker_data->data_end = data;

  if (frame_worker_data->pbi->frame_parallel_decode) {
    // In frame parallel decoding, a worker thread must successfully decode all
    // the compressed data.
    if (frame_worker_data->result != 0 ||
        frame_worker_data->data + frame_worker_data->data_size - 1 > data) {
      VP9Worker *const worker = frame_worker_data->pbi->frame_worker_owner;
      BufferPool *const pool = frame_worker_data->pbi->common.buffer_pool;
      // Signal all the other threads that are waiting for this frame.
      vp9_frameworker_lock_stats(worker);
      frame_worker_data->frame_context_ready = 1;
      lock_buffer_pool(pool);
      frame_worker_data->pbi->cur_buf->buf.corrupted = 1;
      unlock_buffer_pool(pool);
      frame_worker_data->pbi->need_resync = 1;
      vp9_frameworker_signal_stats(worker);
      vp9_frameworker_unlock_stats(worker);
      return 0;
    }
  } else if (frame_worker_data->result != 0) {
    // Check decode result in serial decode.
    frame_worker_data->pbi->cur_buf->buf.corrupted = 1;
    frame_worker_data->pbi->need_resync = 1;
  }
  return !frame_worker_data->result;
}

static vpx_codec_err_t init_decoder(vpx_codec_alg_priv_t *ctx) {
  int i;
  const VP9WorkerInterface *const winterface = vp9_get_worker_interface();

  ctx->last_show_frame = -1;
  ctx->next_submit_worker_id = 0;
  ctx->last_submit_worker_id = 0;
  ctx->next_output_worker_id = 0;
  ctx->frame_cache_read = 0;
  ctx->frame_cache_write = 0;
  ctx->num_cache_frames = 0;
369
  ctx->need_resync = 1;
370 371
  ctx->num_frame_workers =
      (ctx->frame_parallel_decode == 1) ? ctx->cfg.threads: 1;
372 373
  if (ctx->num_frame_workers > MAX_DECODE_THREADS)
    ctx->num_frame_workers = MAX_DECODE_THREADS;
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
  ctx->available_threads = ctx->num_frame_workers;
  ctx->flushed = 0;

  ctx->buffer_pool = (BufferPool *)vpx_calloc(1, sizeof(BufferPool));
  if (ctx->buffer_pool == NULL)
    return VPX_CODEC_MEM_ERROR;

#if CONFIG_MULTITHREAD
    if (pthread_mutex_init(&ctx->buffer_pool->pool_mutex, NULL)) {
      set_error_detail(ctx, "Failed to allocate buffer pool mutex");
      return VPX_CODEC_MEM_ERROR;
    }
#endif

  ctx->frame_workers = (VP9Worker *)
      vpx_malloc(ctx->num_frame_workers * sizeof(*ctx->frame_workers));
  if (ctx->frame_workers == NULL) {
    set_error_detail(ctx, "Failed to allocate frame_workers");
    return VPX_CODEC_MEM_ERROR;
  }
394

395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
  for (i = 0; i < ctx->num_frame_workers; ++i) {
    VP9Worker *const worker = &ctx->frame_workers[i];
    FrameWorkerData *frame_worker_data = NULL;
    winterface->init(worker);
    worker->data1 = vpx_memalign(32, sizeof(FrameWorkerData));
    if (worker->data1 == NULL) {
      set_error_detail(ctx, "Failed to allocate frame_worker_data");
      return VPX_CODEC_MEM_ERROR;
    }
    frame_worker_data = (FrameWorkerData *)worker->data1;
    frame_worker_data->pbi = vp9_decoder_create(ctx->buffer_pool);
    if (frame_worker_data->pbi == NULL) {
      set_error_detail(ctx, "Failed to allocate frame_worker_data");
      return VPX_CODEC_MEM_ERROR;
    }
    frame_worker_data->pbi->frame_worker_owner = worker;
    frame_worker_data->worker_id = i;
    frame_worker_data->scratch_buffer = NULL;
    frame_worker_data->scratch_buffer_size = 0;
    frame_worker_data->frame_context_ready = 0;
415
    frame_worker_data->received_frame = 0;
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
#if CONFIG_MULTITHREAD
    if (pthread_mutex_init(&frame_worker_data->stats_mutex, NULL)) {
      set_error_detail(ctx, "Failed to allocate frame_worker_data mutex");
      return VPX_CODEC_MEM_ERROR;
    }

    if (pthread_cond_init(&frame_worker_data->stats_cond, NULL)) {
      set_error_detail(ctx, "Failed to allocate frame_worker_data cond");
      return VPX_CODEC_MEM_ERROR;
    }
#endif
    // If decoding in serial mode, FrameWorker thread could create tile worker
    // thread or loopfilter thread.
    frame_worker_data->pbi->max_threads =
        (ctx->frame_parallel_decode == 0) ? ctx->cfg.threads : 0;

    frame_worker_data->pbi->inv_tile_order = ctx->invert_tile_order;
    frame_worker_data->pbi->frame_parallel_decode = ctx->frame_parallel_decode;
    frame_worker_data->pbi->common.frame_parallel_decode =
        ctx->frame_parallel_decode;
    worker->hook = (VP9WorkerHook)frame_worker_hook;
    if (!winterface->reset(worker)) {
      set_error_detail(ctx, "Frame Worker thread creation failed");
      return VPX_CODEC_MEM_ERROR;
    }
  }
442

443 444 445 446 447 448 449
  // 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))
    set_default_ppflags(&ctx->postproc_cfg);

  init_buffer_callbacks(ctx);
450 451

  return VPX_CODEC_OK;
452 453
}

454 455 456 457 458 459 460 461
static INLINE void check_resync(vpx_codec_alg_priv_t *const ctx,
                                const VP9Decoder *const pbi) {
  // Clear resync flag if worker got a key frame or intra only frame.
  if (ctx->need_resync == 1 && pbi->need_resync == 0 &&
      (pbi->common.intra_only || pbi->common.frame_type == KEY_FRAME))
    ctx->need_resync = 0;
}

462 463 464
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) {
465
  const VP9WorkerInterface *const winterface = vp9_get_worker_interface();
466 467
  (void)deadline;

468 469 470
  // 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.
471
  if (!ctx->si.h) {
472
    int is_intra_only = 0;
473
    const vpx_codec_err_t res =
474 475
        decoder_peek_si_internal(*data, data_sz, &ctx->si, &is_intra_only,
                                 ctx->decrypt_cb, ctx->decrypt_state);
476 477
    if (res != VPX_CODEC_OK)
      return res;
478

479
    if (!ctx->si.is_kf && !is_intra_only)
480
      return VPX_CODEC_ERROR;
481
  }
482

483 484 485 486 487 488
  if (!ctx->frame_parallel_decode) {
    VP9Worker *const worker = ctx->frame_workers;
    FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
    frame_worker_data->data = *data;
    frame_worker_data->data_size = data_sz;
    frame_worker_data->user_priv = user_priv;
489
    frame_worker_data->received_frame = 1;
490 491 492 493 494

    // Set these even if already initialized.  The caller may have changed the
    // decrypt config between frames.
    frame_worker_data->pbi->decrypt_cb = ctx->decrypt_cb;
    frame_worker_data->pbi->decrypt_state = ctx->decrypt_state;
John Koleszar's avatar
John Koleszar committed
495

496 497
    worker->had_error = 0;
    winterface->execute(worker);
498

499 500
    // Update data pointer after decode.
    *data = frame_worker_data->data_end;
501

502 503
    if (worker->had_error)
      return update_error_state(ctx, &frame_worker_data->pbi->common.error);
504 505

    check_resync(ctx, frame_worker_data->pbi);
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529
  } else {
    VP9Worker *const worker = &ctx->frame_workers[ctx->next_submit_worker_id];
    FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
    // Copy context from last worker thread to next worker thread.
    if (ctx->next_submit_worker_id != ctx->last_submit_worker_id)
      vp9_frameworker_copy_context(
          &ctx->frame_workers[ctx->next_submit_worker_id],
          &ctx->frame_workers[ctx->last_submit_worker_id]);

    frame_worker_data->pbi->ready_for_new_data = 0;
    // Copy the compressed data into worker's internal buffer.
    // TODO(hkuang): Will all the workers allocate the same size
    // as the size of the first intra frame be better? This will
    // avoid too many deallocate and allocate.
    if (frame_worker_data->scratch_buffer_size < data_sz) {
      frame_worker_data->scratch_buffer =
          (uint8_t *)vpx_realloc(frame_worker_data->scratch_buffer, data_sz);
      if (frame_worker_data->scratch_buffer == NULL) {
        set_error_detail(ctx, "Failed to reallocate scratch buffer");
        return VPX_CODEC_MEM_ERROR;
      }
      frame_worker_data->scratch_buffer_size = data_sz;
    }
    frame_worker_data->data_size = data_sz;
James Zern's avatar
James Zern committed
530
    memcpy(frame_worker_data->scratch_buffer, *data, data_sz);
531 532 533

    frame_worker_data->frame_decoded = 0;
    frame_worker_data->frame_context_ready = 0;
534
    frame_worker_data->received_frame = 1;
535 536 537 538 539 540 541 542 543 544 545 546 547
    frame_worker_data->data = frame_worker_data->scratch_buffer;
    frame_worker_data->user_priv = user_priv;

    if (ctx->next_submit_worker_id != ctx->last_submit_worker_id)
      ctx->last_submit_worker_id =
          (ctx->last_submit_worker_id + 1) % ctx->num_frame_workers;

    ctx->next_submit_worker_id =
        (ctx->next_submit_worker_id + 1) % ctx->num_frame_workers;
    --ctx->available_threads;
    worker->had_error = 0;
    winterface->launch(worker);
  }
548

549
  return VPX_CODEC_OK;
550 551
}

552 553 554 555 556 557 558 559
static void wait_worker_and_cache_frame(vpx_codec_alg_priv_t *ctx) {
  YV12_BUFFER_CONFIG sd;
  vp9_ppflags_t flags = {0, 0, 0};
  const VP9WorkerInterface *const winterface = vp9_get_worker_interface();
  VP9Worker *const worker = &ctx->frame_workers[ctx->next_output_worker_id];
  FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
  ctx->next_output_worker_id =
      (ctx->next_output_worker_id + 1) % ctx->num_frame_workers;
560
  // TODO(hkuang): Add worker error handling here.
561
  winterface->sync(worker);
562
  frame_worker_data->received_frame = 0;
563
  ++ctx->available_threads;
564 565 566

  check_resync(ctx, frame_worker_data->pbi);

567 568 569 570 571 572 573 574 575 576 577 578 579 580
  if (vp9_get_raw_frame(frame_worker_data->pbi, &sd, &flags) == 0) {
    VP9_COMMON *const cm = &frame_worker_data->pbi->common;
    RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
    ctx->frame_cache[ctx->frame_cache_write].fb_idx = cm->new_fb_idx;
    yuvconfig2image(&ctx->frame_cache[ctx->frame_cache_write].img, &sd,
                    frame_worker_data->user_priv);
    ctx->frame_cache[ctx->frame_cache_write].img.fb_priv =
        frame_bufs[cm->new_fb_idx].raw_frame_buffer.priv;
    ctx->frame_cache_write =
        (ctx->frame_cache_write + 1) % FRAME_CACHE_SIZE;
    ++ctx->num_cache_frames;
  }
}

581 582 583
static vpx_codec_err_t decoder_decode(vpx_codec_alg_priv_t *ctx,
                                      const uint8_t *data, unsigned int data_sz,
                                      void *user_priv, long deadline) {
584
  const uint8_t *data_start = data;
585 586
  const uint8_t * const data_end = data + data_sz;
  vpx_codec_err_t res;
587 588
  uint32_t frame_sizes[8];
  int frame_count;
John Koleszar's avatar
John Koleszar committed
589

590 591 592 593 594 595 596
  if (data == NULL && data_sz == 0) {
    ctx->flushed = 1;
    return VPX_CODEC_OK;
  }

  // Reset flushed when receiving a valid frame.
  ctx->flushed = 0;
597

598 599 600 601 602 603 604
  // Initialize the decoder workers on the first frame.
  if (ctx->frame_workers == NULL) {
    const vpx_codec_err_t res = init_decoder(ctx);
    if (res != VPX_CODEC_OK)
      return res;
  }

605 606
  res = vp9_parse_superframe_index(data, data_sz, frame_sizes, &frame_count,
                                   ctx->decrypt_cb, ctx->decrypt_state);
607 608
  if (res != VPX_CODEC_OK)
    return res;
609

610 611 612 613 614 615 616 617 618 619 620 621 622
  if (ctx->frame_parallel_decode) {
    // Decode in frame parallel mode. When decoding in this mode, the frame
    // passed to the decoder must be either a normal frame or a superframe with
    // superframe index so the decoder could get each frame's start position
    // in the superframe.
    if (frame_count > 0) {
      int i;

      for (i = 0; i < frame_count; ++i) {
        const uint8_t *data_start_copy = data_start;
        const uint32_t frame_size = frame_sizes[i];
        if (data_start < data
            || frame_size > (uint32_t) (data_end - data_start)) {
623
          set_error_detail(ctx, "Invalid frame size in index");
624 625 626
          return VPX_CODEC_CORRUPT_FRAME;
        }

627 628 629 630 631 632 633 634 635 636 637 638
        if (ctx->available_threads == 0) {
          // No more threads for decoding. Wait until the next output worker
          // finishes decoding. Then copy the decoded frame into cache.
          if (ctx->num_cache_frames < FRAME_CACHE_SIZE) {
            wait_worker_and_cache_frame(ctx);
          } else {
            // TODO(hkuang): Add unit test to test this path.
            set_error_detail(ctx, "Frame output cache is full.");
            return VPX_CODEC_ERROR;
          }
        }

639 640 641 642 643 644 645
        res = decode_one(ctx, &data_start_copy, frame_size, user_priv,
                         deadline);
        if (res != VPX_CODEC_OK)
          return res;
        data_start += frame_size;
      }
    } else {
646 647 648 649 650 651 652 653 654 655 656 657 658
      if (ctx->available_threads == 0) {
        // No more threads for decoding. Wait until the next output worker
        // finishes decoding. Then copy the decoded frame into cache.
        if (ctx->num_cache_frames < FRAME_CACHE_SIZE) {
          wait_worker_and_cache_frame(ctx);
        } else {
          // TODO(hkuang): Add unit test to test this path.
          set_error_detail(ctx, "Frame output cache is full.");
          return VPX_CODEC_ERROR;
        }
      }

      res = decode_one(ctx, &data, data_sz, user_priv, deadline);
659 660
      if (res != VPX_CODEC_OK)
        return res;
John Koleszar's avatar
John Koleszar committed
661
    }
662
  } else {
663 664 665 666 667 668 669 670 671 672
    // Decode in serial mode.
    if (frame_count > 0) {
      int i;

      for (i = 0; i < frame_count; ++i) {
        const uint8_t *data_start_copy = data_start;
        const uint32_t frame_size = frame_sizes[i];
        vpx_codec_err_t res;
        if (data_start < data
            || frame_size > (uint32_t) (data_end - data_start)) {
673
          set_error_detail(ctx, "Invalid frame size in index");
674 675 676 677 678 679 680
          return VPX_CODEC_CORRUPT_FRAME;
        }

        res = decode_one(ctx, &data_start_copy, frame_size, user_priv,
                         deadline);
        if (res != VPX_CODEC_OK)
          return res;
681

682 683 684
        data_start += frame_size;
      }
    } else {
685
      while (data_start < data_end) {
686 687 688 689 690 691 692 693 694 695 696 697 698 699
        const uint32_t frame_size = (uint32_t) (data_end - data_start);
        const vpx_codec_err_t res = decode_one(ctx, &data_start, frame_size,
                                               user_priv, deadline);
        if (res != VPX_CODEC_OK)
          return res;

        // Account for suboptimal termination by the encoder.
        while (data_start < data_end) {
          const uint8_t marker = read_marker(ctx->decrypt_cb,
                                             ctx->decrypt_state, data_start);
          if (marker)
            break;
          ++data_start;
        }
700
      }
701
    }
702
  }
703

704 705 706 707 708 709 710 711 712 713 714 715
  return res;
}

static void release_last_output_frame(vpx_codec_alg_priv_t *ctx) {
  RefCntBuffer *const frame_bufs = ctx->buffer_pool->frame_bufs;
  // Decrease reference count of last output frame in frame parallel mode.
  if (ctx->frame_parallel_decode && ctx->last_show_frame >= 0) {
    BufferPool *const pool = ctx->buffer_pool;
    lock_buffer_pool(pool);
    decrease_ref_count(ctx->last_show_frame, frame_bufs, pool);
    unlock_buffer_pool(pool);
  }
716 717
}

718 719
static vpx_image_t *decoder_get_frame(vpx_codec_alg_priv_t *ctx,
                                      vpx_codec_iter_t *iter) {
John Koleszar's avatar
John Koleszar committed
720 721
  vpx_image_t *img = NULL;

722 723 724 725
  // Only return frame when all the cpu are busy or
  // application fluhsed the decoder in frame parallel decode.
  if (ctx->frame_parallel_decode && ctx->available_threads > 0 &&
      !ctx->flushed) {
726
    return NULL;
727 728 729 730 731 732
  }

  // Output the frames in the cache first.
  if (ctx->num_cache_frames > 0) {
    release_last_output_frame(ctx);
    ctx->last_show_frame  = ctx->frame_cache[ctx->frame_cache_read].fb_idx;
733 734
    if (ctx->need_resync)
      return NULL;
735 736 737 738
    img = &ctx->frame_cache[ctx->frame_cache_read].img;
    ctx->frame_cache_read = (ctx->frame_cache_read + 1) % FRAME_CACHE_SIZE;
    --ctx->num_cache_frames;
    return img;
739 740
  }

741 742 743 744 745 746 747 748 749 750 751 752 753
  // iter acts as a flip flop, so an image is only returned on the first
  // call to get_frame.
  if (*iter == NULL && ctx->frame_workers != NULL) {
    do {
      YV12_BUFFER_CONFIG sd;
      vp9_ppflags_t flags = {0, 0, 0};
      const VP9WorkerInterface *const winterface = vp9_get_worker_interface();
      VP9Worker *const worker =
          &ctx->frame_workers[ctx->next_output_worker_id];
      FrameWorkerData *const frame_worker_data =
          (FrameWorkerData *)worker->data1;
      ctx->next_output_worker_id =
          (ctx->next_output_worker_id + 1) % ctx->num_frame_workers;
754 755
      if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)
        set_ppflags(ctx, &flags);
756
      // Wait for the frame from worker thread.
757 758
      if (winterface->sync(worker)) {
        // Check if worker has received any frames.
759
        if (frame_worker_data->received_frame == 1) {
760
          ++ctx->available_threads;
761 762 763
          frame_worker_data->received_frame = 0;
          check_resync(ctx, frame_worker_data->pbi);
        }
764 765 766 767 768
        if (vp9_get_raw_frame(frame_worker_data->pbi, &sd, &flags) == 0) {
          VP9_COMMON *const cm = &frame_worker_data->pbi->common;
          RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
          release_last_output_frame(ctx);
          ctx->last_show_frame = frame_worker_data->pbi->common.new_fb_idx;
769 770
          if (ctx->need_resync)
            return NULL;
771 772 773 774 775 776
          yuvconfig2image(&ctx->img, &sd, frame_worker_data->user_priv);
          ctx->img.fb_priv = frame_bufs[cm->new_fb_idx].raw_frame_buffer.priv;
          img = &ctx->img;
          return img;
        }
      } else {
777
        // Decoding failed. Release the worker thread.
778
        frame_worker_data->received_frame = 0;
779
        ++ctx->available_threads;
780
        ctx->need_resync = 1;
781
        if (ctx->flushed != 1)
782
          return NULL;
783 784 785
      }
    } while (ctx->next_output_worker_id != ctx->next_submit_worker_id);
  }
786
  return NULL;
John Koleszar's avatar
John Koleszar committed
787 788
}

789
static vpx_codec_err_t decoder_set_fb_fn(
790 791 792 793 794
    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;
795
  } else if (ctx->frame_workers == NULL) {
796 797 798 799 800 801 802 803 804 805 806
    // 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;
}

807
static vpx_codec_err_t ctrl_set_reference(vpx_codec_alg_priv_t *ctx,
808
                                          va_list args) {
809
  vpx_ref_frame_t *const data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
810

811 812 813 814 815 816
  // Only support this function in serial decode.
  if (ctx->frame_parallel_decode) {
    set_error_detail(ctx, "Not supported in frame parallel decode");
    return VPX_CODEC_INCAPABLE;
  }

John Koleszar's avatar
John Koleszar committed
817
  if (data) {
818
    vpx_ref_frame_t *const frame = (vpx_ref_frame_t *)data;
John Koleszar's avatar
John Koleszar committed
819
    YV12_BUFFER_CONFIG sd;
820 821
    VP9Worker *const worker = ctx->frame_workers;
    FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
John Koleszar's avatar
John Koleszar committed
822
    image2yuvconfig(&frame->img, &sd);
823
    return vp9_set_reference_dec(&frame_worker_data->pbi->common,
824
                                 (VP9_REFFRAME)frame->frame_type, &sd);
825
  } else {
John Koleszar's avatar
John Koleszar committed
826
    return VPX_CODEC_INVALID_PARAM;
827
  }
John Koleszar's avatar
John Koleszar committed
828 829
}

830
static vpx_codec_err_t ctrl_copy_reference(vpx_codec_alg_priv_t *ctx,
831
                                           va_list args) {
John Koleszar's avatar
John Koleszar committed
832
  vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
833

834 835 836 837 838 839
  // Only support this function in serial decode.
  if (ctx->frame_parallel_decode) {
    set_error_detail(ctx, "Not supported in frame parallel decode");
    return VPX_CODEC_INCAPABLE;
  }

John Koleszar's avatar
John Koleszar committed
840
  if (data) {
841
    vpx_ref_frame_t *frame = (vpx_ref_frame_t *) data;
John Koleszar's avatar
John Koleszar committed
842
    YV12_BUFFER_CONFIG sd;
843 844
    VP9Worker *const worker = ctx->frame_workers;
    FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
John Koleszar's avatar
John Koleszar committed
845
    image2yuvconfig(&frame->img, &sd);
846
    return vp9_copy_reference_dec(frame_worker_data->pbi,
847
                                  (VP9_REFFRAME)frame->frame_type, &sd);
848
  } else {
John Koleszar's avatar
John Koleszar committed
849
    return VPX_CODEC_INVALID_PARAM;
850
  }
John Koleszar's avatar
John Koleszar committed
851 852
}

853
static vpx_codec_err_t ctrl_get_reference(vpx_codec_alg_priv_t *ctx,
854
                                          va_list args) {
855 856
  vp9_ref_frame_t *data = va_arg(args, vp9_ref_frame_t *);

857 858 859 860 861 862
  // Only support this function in serial decode.
  if (ctx->frame_parallel_decode) {
    set_error_detail(ctx, "Not supported in frame parallel decode");
    return VPX_CODEC_INCAPABLE;
  }

863
  if (data) {
864 865 866 867
    YV12_BUFFER_CONFIG* fb;
    VP9Worker *const worker = ctx->frame_workers;
    FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
    fb = get_ref_frame(&frame_worker_data->pbi->common, data->idx);
868
    if (fb == NULL) return VPX_CODEC_ERROR;
869
    yuvconfig2image(&data->img, fb, NULL);
870 871 872 873 874 875
    return VPX_CODEC_OK;
  } else {
    return VPX_CODEC_INVALID_PARAM;
  }
}

876
static vpx_codec_err_t ctrl_set_postproc(vpx_codec_alg_priv_t *ctx,
877
                                         va_list args) {
878
#if CONFIG_VP9_POSTPROC
John Koleszar's avatar
John Koleszar committed
879
  vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
John Koleszar's avatar
John Koleszar committed
880

John Koleszar's avatar
John Koleszar committed
881 882 883 884
  if (data) {
    ctx->postproc_cfg_set = 1;
    ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data);
    return VPX_CODEC_OK;
885
  } else {
John Koleszar's avatar
John Koleszar committed
886
    return VPX_CODEC_INVALID_PARAM;
887
  }
John Koleszar's avatar
John Koleszar committed
888
#else
889 890
  (void)ctx;
  (void)args;
John Koleszar's avatar
John Koleszar committed
891
  return VPX_CODEC_INCAPABLE;
John Koleszar's avatar
John Koleszar committed
892 893 894
#endif
}

895
static vpx_codec_err_t ctrl_set_dbg_options(vpx_codec_alg_priv_t *ctx,
896 897 898
                                            va_list args) {
  (void)ctx;
  (void)args;
John Koleszar's avatar
John Koleszar committed
899
  return VPX_CODEC_INCAPABLE;
900
}
John Koleszar's avatar
John Koleszar committed
901

902
static vpx_codec_err_t ctrl_get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
903
                                                 va_list args) {
904
  int *const update_info = va_arg(args, int *);
905

906 907 908 909 910 911
  // Only support this function in serial decode.
  if (ctx->frame_parallel_decode) {
    set_error_detail(ctx, "Not supported in frame parallel decode");
    return VPX_CODEC_INCAPABLE;
  }

John Koleszar's avatar
John Koleszar committed
912
  if (update_info) {
913 914 915 916 917
    if (ctx->frame_workers) {
      VP9Worker *const worker = ctx->frame_workers;
      FrameWorkerData *const frame_worker_data =
          (FrameWorkerData *)worker->data1;
      *update_info = frame_worker_data->pbi->refresh_frame_flags;
918
      return VPX_CODEC_OK;
919
    } else {
920
      return VPX_CODEC_ERROR;
921
    }
922
  }
923 924

  return VPX_CODEC_INVALID_PARAM;
925 926
}

927
static vpx_codec_err_t ctrl_get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
928
                                                va_list args) {
John Koleszar's avatar
John Koleszar committed
929
  int *corrupted = va_arg(args, int *);
930

931 932 933 934 935 936 937 938 939
  if (corrupted) {
    if (ctx->frame_workers) {
      VP9Worker *const worker = ctx->frame_workers;
      FrameWorkerData *const frame_worker_data =
          (FrameWorkerData *)worker->data1;
      RefCntBuffer *const frame_bufs =
          frame_worker_data->pbi->common.buffer_pool->frame_bufs;
      if (frame_worker_data->pbi->common.frame_to_show == NULL)
        return VPX_CODEC_ERROR;
940 941
      if (ctx->last_show_frame >= 0)
        *corrupted = frame_bufs[ctx->last_show_frame].buf.corrupted;
942
      return VPX_CODEC_OK;
943 944 945
    } else {
      return VPX_CODEC_ERROR;
    }
946
  }
947 948

  return VPX_CODEC_INVALID_PARAM;
949 950
}

951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973
static vpx_codec_err_t ctrl_get_frame_size(vpx_codec_alg_priv_t *ctx,
                                           va_list args) {
  int *const frame_size = va_arg(args, int *);

  // Only support this function in serial decode.
  if (ctx->frame_parallel_decode) {
    set_error_detail(ctx, "Not supported in frame parallel decode");
    return VPX_CODEC_INCAPABLE;
  }

  if (frame_size) {
    if (ctx->frame_workers) {
      VP9Worker *const worker = ctx->frame_workers;
      FrameWorkerData *const frame_worker_data =
          (FrameWorkerData *)worker->data1;
      const VP9_COMMON *const cm = &frame_worker_data->pbi->common;
      frame_size[0] = cm->width;
      frame_size[1] = cm->height;
      return VPX_CODEC_OK;
    } else {
      return VPX_CODEC_ERROR;
    }
  }
974 975

  return VPX_CODEC_INVALID_PARAM;
976 977
}

978
static vpx_codec_err_t ctrl_get_display_size(vpx_codec_alg_priv_t *ctx,
979
                                             va_list args) {
980 981
  int *const display_size = va_arg(args, int *);

982 983 984 985 986 987
  // Only support this function in serial decode.
  if (ctx->frame_parallel_decode) {
    set_error_detail(ctx, "Not supported in frame parallel decode");
    return VPX_CODEC_INCAPABLE;
  }

988
  if (display_size) {
989 990 991 992 993
    if (ctx->frame_workers) {
      VP9Worker *const worker = ctx->frame_workers;
      FrameWorkerData *const frame_worker_data =
          (FrameWorkerData *)worker->data1;
      const VP9_COMMON *const cm = &frame_worker_data->pbi->common;
994 995
      display_size[0] = cm->display_width;
      display_size[1] = cm->display_height;
996
      return VPX_CODEC_OK;
997 998 999 1000
    } else {
      return VPX_CODEC_ERROR;
    }
  }
1001 1002

  return VPX_CODEC_INVALID_PARAM;
1003 1004
}

1005 1006 1007
static vpx_codec_err_t ctrl_get_bit_depth(vpx_codec_alg_priv_t *ctx,
                                          va_list args) {
  unsigned int *const bit_depth = va_arg(args, unsigned int *);
1008
  VP9Worker *const worker = &ctx->frame_workers[ctx->next_output_worker_id];
1009 1010

  if (bit_depth) {
1011 1012 1013 1014
    if (worker) {
      FrameWorkerData *const frame_worker_data =
          (FrameWorkerData *)worker->data1;
      const VP9_COMMON *const cm = &frame_worker_data->pbi->common;
1015 1016 1017 1018 1019 1020
      *bit_depth = cm->bit_depth;
      return VPX_CODEC_OK;
    } else {
      return VPX_CODEC_ERROR;
    }
  }
1021 1022

  return VPX_CODEC_INVALID_PARAM;
1023 1024
}

1025
static vpx_codec_err_t ctrl_set_invert_tile_order(vpx_codec_alg_priv_t *ctx,
1026
                                                  va_list args) {
1027 1028 1029 1030
  ctx->invert_tile_order = va_arg(args, int);
  return VPX_CODEC_OK;
}

1031 1032 1033 1034 1035 1036 1037 1038
static vpx_codec_err_t ctrl_set_decryptor(vpx_codec_alg_priv_t *ctx,
                                          va_list args) {
  vpx_decrypt_init *init = va_arg(args, vpx_decrypt_init *);
  ctx->decrypt_cb = init ? init->decrypt_cb : NULL;
  ctx->decrypt_state = init ? init->decrypt_state : NULL;
  return VPX_CODEC_OK;
}

1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052
static vpx_codec_err_t ctrl_set_byte_alignment(vpx_codec_alg_priv_t *ctx,
                                               va_list args) {
  const int legacy_byte_alignment = 0;
  const int min_byte_alignment = 32;
  const int max_byte_alignment = 1024;
  const int byte_alignment = va_arg(args, int);

  if (byte_alignment != legacy_byte_alignment &&
      (byte_alignment < min_byte_alignment ||
       byte_alignment > max_byte_alignment ||
       (byte_alignment & (byte_alignment - 1)) != 0))
    return VPX_CODEC_INVALID_PARAM;

  ctx->byte_alignment = byte_alignment;
1053 1054 1055 1056 1057
  if (ctx->frame_workers) {
    VP9Worker *const worker = ctx->frame_workers;
    FrameWorkerData *const frame_worker_data =
        (FrameWorkerData *)worker->data1;
    frame_worker_data->pbi->common.byte_alignment = byte_alignment;
1058 1059 1060 1061
  }
  return VPX_CODEC_OK;
}

1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
static vpx_codec_ctrl_fn_map_t decoder_ctrl_maps[] = {
  {VP8_COPY_REFERENCE,            ctrl_copy_reference},

  // Setters
  {VP8_SET_REFERENCE,             ctrl_set_reference},
  {VP8_SET_POSTPROC,              ctrl_set_postproc},
  {VP8_SET_DBG_COLOR_REF_FRAME,   ctrl_set_dbg_options},
  {VP8_SET_DBG_COLOR_MB_MODES,    ctrl_set_dbg_options},
  {VP8_SET_DBG_COLOR_B_MODES,     ctrl_set_dbg_options},
  {VP8_SET_DBG_DISPLAY_MV,        ctrl_set_dbg_options},
  {VP9_INVERT_TILE_DECODE_ORDER,  ctrl_set_invert_tile_order},
1073
  {VPXD_SET_DECRYPTOR,            ctrl_set_decryptor},
1074
  {VP9_SET_BYTE_ALIGNMENT,        ctrl_set_byte_alignment},
1075 1076 1077 1078 1079 1080

  // Getters
  {VP8D_GET_LAST_REF_UPDATES,     ctrl_get_last_ref_updates},
  {VP8D_GET_FRAME_CORRUPTED,      ctrl_get_frame_corrupted},
  {VP9_GET_REFERENCE,             ctrl_get_reference},
  {VP9D_GET_DISPLAY_SIZE,         ctrl_get_display_size},
1081
  {VP9D_GET_BIT_DEPTH,            ctrl_get_bit_depth},
1082
  {VP9D_GET_FRAME_SIZE,           ctrl_get_frame_size},
1083

John Koleszar's avatar
John Koleszar committed
1084
  { -1, NULL},
John Koleszar's avatar
John Koleszar committed
1085 1086 1087 1088 1089
};

#ifndef VERSION_STRING
#define VERSION_STRING
#endif
1090 1091
CODEC_INTERFACE(vpx_codec_vp9_dx) = {
  "WebM Project VP9 Decoder" VERSION_STRING,
John Koleszar's avatar
John Koleszar committed
1092
  VPX_CODEC_INTERNAL_ABI_VERSION,
1093
  VPX_CODEC_CAP_DECODER | VP9_CAP_POSTPROC |
1094 1095 1096 1097
      VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER,  // vpx_codec_caps_t
  decoder_init,       // vpx_codec_init_fn_t
  decoder_destroy,    // vpx_codec_destroy_fn_t
  decoder_ctrl_maps,  // vpx_codec_ctrl_fn_map_t
1098
  { // NOLINT
1099 1100 1101 1102 1103
    decoder_peek_si,    // vpx_codec_peek_si_fn_t
    decoder_get_si,     // vpx_codec_get_si_fn_t
    decoder_decode,     // vpx_codec_decode_fn_t
    decoder_get_frame,  // vpx_codec_frame_get_fn_t
    decoder_set_fb_fn,  // vpx_codec_set_fb_fn_t
John Koleszar's avatar
John Koleszar committed
1104
  },
1105
  { // NOLINT
1106
    0,
1107 1108 1109 1110 1111 1112 1113
    NULL,  // vpx_codec_enc_cfg_map_t
    NULL,  // vpx_codec_encode_fn_t
    NULL,  // vpx_codec_get_cx_data_fn_t
    NULL,  // vpx_codec_enc_config_set_fn_t
    NULL,  // vpx_codec_get_global_headers_fn_t
    NULL,  // vpx_codec_get_preview_frame_fn_t
    NULL   // vpx_codec_enc_mr_get_mem_loc_fn_t
John Koleszar's avatar
John Koleszar committed
1114
  }
John Koleszar's avatar
John Koleszar committed
1115
};