av1_dx_iface.c 37.5 KB
Newer Older
Jingning Han's avatar
Jingning Han committed
1
/*
2
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
Jingning Han's avatar
Jingning Han committed
3
 *
4 5 6 7 8 9
 * This source code is subject to the terms of the BSD 2 Clause License and
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
 * was not distributed with this source code in the LICENSE file, you can
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
 * Media Patent License 1.0 was not distributed with this source code in the
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
Jingning Han's avatar
Jingning Han committed
10 11 12 13 14
 */

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

Adrian Grange's avatar
Adrian Grange committed
15 16
#include "./aom_config.h"
#include "./aom_version.h"
Jingning Han's avatar
Jingning Han committed
17

Adrian Grange's avatar
Adrian Grange committed
18
#include "aom/internal/aom_codec_internal.h"
Adrian Grange's avatar
Adrian Grange committed
19
#include "aom/aomdx.h"
Adrian Grange's avatar
Adrian Grange committed
20
#include "aom/aom_decoder.h"
Yaowu Xu's avatar
Yaowu Xu committed
21
#include "aom_dsp/bitreader_buffer.h"
Adrian Grange's avatar
Adrian Grange committed
22 23
#include "aom_dsp/aom_dsp_common.h"
#include "aom_util/aom_thread.h"
Jingning Han's avatar
Jingning Han committed
24

Yaowu Xu's avatar
Yaowu Xu committed
25 26
#include "av1/common/alloccommon.h"
#include "av1/common/frame_buffers.h"
Jingning Han's avatar
Jingning Han committed
27

Yaowu Xu's avatar
Yaowu Xu committed
28 29
#include "av1/decoder/decoder.h"
#include "av1/decoder/decodeframe.h"
Jingning Han's avatar
Jingning Han committed
30

Yaowu Xu's avatar
Yaowu Xu committed
31
#include "av1/av1_iface_common.h"
Jingning Han's avatar
Jingning Han committed
32

33
typedef aom_codec_stream_info_t av1_stream_info_t;
Jingning Han's avatar
Jingning Han committed
34 35 36

// This limit is due to framebuffer numbers.
// TODO(hkuang): Remove this limit after implementing ondemand framebuffers.
clang-format's avatar
clang-format committed
37
#define FRAME_CACHE_SIZE 6  // Cache maximum 6 decoded frames.
Jingning Han's avatar
Jingning Han committed
38 39 40

typedef struct cache_frame {
  int fb_idx;
Adrian Grange's avatar
Adrian Grange committed
41
  aom_image_t img;
Jingning Han's avatar
Jingning Han committed
42 43
} cache_frame;

Adrian Grange's avatar
Adrian Grange committed
44 45 46
struct aom_codec_alg_priv {
  aom_codec_priv_t base;
  aom_codec_dec_cfg_t cfg;
47
  av1_stream_info_t si;
clang-format's avatar
clang-format committed
48
  int postproc_cfg_set;
Adrian Grange's avatar
Adrian Grange committed
49
  aom_postproc_cfg_t postproc_cfg;
Adrian Grange's avatar
Adrian Grange committed
50
  aom_decrypt_cb decrypt_cb;
clang-format's avatar
clang-format committed
51
  void *decrypt_state;
Adrian Grange's avatar
Adrian Grange committed
52
  aom_image_t img;
clang-format's avatar
clang-format committed
53 54 55 56 57 58
  int img_avail;
  int flushed;
  int invert_tile_order;
  int last_show_frame;  // Index of last output frame.
  int byte_alignment;
  int skip_loop_filter;
Jingning Han's avatar
Jingning Han committed
59 60

  // Frame parallel related.
clang-format's avatar
clang-format committed
61 62 63 64 65 66 67 68 69 70 71 72
  int frame_parallel_decode;  // frame-based threading.
  VPxWorker *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;
  int need_resync;  // wait for key/intra-only frame
Jingning Han's avatar
Jingning Han committed
73
  // BufferPool that holds all reference frames. Shared by all the FrameWorkers.
clang-format's avatar
clang-format committed
74
  BufferPool *buffer_pool;
Jingning Han's avatar
Jingning Han committed
75

76
  // External frame buffer info to save for AV1 common.
Jingning Han's avatar
Jingning Han committed
77
  void *ext_priv;  // Private data associated with the external frame buffers.
Adrian Grange's avatar
Adrian Grange committed
78 79
  aom_get_frame_buffer_cb_fn_t get_ext_fb_cb;
  aom_release_frame_buffer_cb_fn_t release_ext_fb_cb;
Jingning Han's avatar
Jingning Han committed
80 81
};

Adrian Grange's avatar
Adrian Grange committed
82 83 84
static aom_codec_err_t decoder_init(aom_codec_ctx_t *ctx,
                                    aom_codec_priv_enc_mr_cfg_t *data) {
  // This function only allocates space for the aom_codec_alg_priv_t
Jingning Han's avatar
Jingning Han committed
85 86 87 88 89
  // structure. More memory may be required at the time the stream
  // information becomes known.
  (void)data;

  if (!ctx->priv) {
Adrian Grange's avatar
Adrian Grange committed
90 91
    aom_codec_alg_priv_t *const priv =
        (aom_codec_alg_priv_t *)aom_calloc(1, sizeof(*priv));
Adrian Grange's avatar
Adrian Grange committed
92
    if (priv == NULL) return AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
93

Adrian Grange's avatar
Adrian Grange committed
94
    ctx->priv = (aom_codec_priv_t *)priv;
Jingning Han's avatar
Jingning Han committed
95 96 97 98 99 100
    ctx->priv->init_flags = ctx->init_flags;
    priv->si.sz = sizeof(priv->si);
    priv->flushed = 0;
    // Only do frame parallel decode when threads > 1.
    priv->frame_parallel_decode =
        (ctx->config.dec && (ctx->config.dec->threads > 1) &&
Adrian Grange's avatar
Adrian Grange committed
101
         (ctx->init_flags & AOM_CODEC_USE_FRAME_THREADING))
clang-format's avatar
clang-format committed
102 103
            ? 1
            : 0;
Jingning Han's avatar
Jingning Han committed
104 105 106 107 108 109
    if (ctx->config.dec) {
      priv->cfg = *ctx->config.dec;
      ctx->config.dec = &priv->cfg;
    }
  }

Adrian Grange's avatar
Adrian Grange committed
110
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
111 112
}

Adrian Grange's avatar
Adrian Grange committed
113
static aom_codec_err_t decoder_destroy(aom_codec_alg_priv_t *ctx) {
Jingning Han's avatar
Jingning Han committed
114 115 116 117 118 119
  if (ctx->frame_workers != NULL) {
    int i;
    for (i = 0; i < ctx->num_frame_workers; ++i) {
      VPxWorker *const worker = &ctx->frame_workers[i];
      FrameWorkerData *const frame_worker_data =
          (FrameWorkerData *)worker->data1;
Adrian Grange's avatar
Adrian Grange committed
120
      aom_get_worker_interface()->end(worker);
121 122
      av1_remove_common(&frame_worker_data->pbi->common);
      av1_decoder_remove(frame_worker_data->pbi);
Adrian Grange's avatar
Adrian Grange committed
123
      aom_free(frame_worker_data->scratch_buffer);
Jingning Han's avatar
Jingning Han committed
124 125 126 127
#if CONFIG_MULTITHREAD
      pthread_mutex_destroy(&frame_worker_data->stats_mutex);
      pthread_cond_destroy(&frame_worker_data->stats_cond);
#endif
Adrian Grange's avatar
Adrian Grange committed
128
      aom_free(frame_worker_data);
Jingning Han's avatar
Jingning Han committed
129 130 131 132 133 134 135
    }
#if CONFIG_MULTITHREAD
    pthread_mutex_destroy(&ctx->buffer_pool->pool_mutex);
#endif
  }

  if (ctx->buffer_pool) {
136 137
    av1_free_ref_frame_buffers(ctx->buffer_pool);
    av1_free_internal_frame_buffers(&ctx->buffer_pool->int_frame_buffers);
Jingning Han's avatar
Jingning Han committed
138 139
  }

Adrian Grange's avatar
Adrian Grange committed
140 141 142
  aom_free(ctx->frame_workers);
  aom_free(ctx->buffer_pool);
  aom_free(ctx);
Adrian Grange's avatar
Adrian Grange committed
143
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
144 145
}

clang-format's avatar
clang-format committed
146
static int parse_bitdepth_colorspace_sampling(BITSTREAM_PROFILE profile,
Adrian Grange's avatar
Adrian Grange committed
147 148
                                              struct aom_read_bit_buffer *rb) {
  aom_color_space_t color_space;
clang-format's avatar
clang-format committed
149
  if (profile >= PROFILE_2) rb->bit_offset += 1;  // Bit-depth 10 or 12.
Adrian Grange's avatar
Adrian Grange committed
150
  color_space = (aom_color_space_t)aom_rb_read_literal(rb, 3);
Adrian Grange's avatar
Adrian Grange committed
151
  if (color_space != AOM_CS_SRGB) {
Jingning Han's avatar
Jingning Han committed
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
    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;
}

Adrian Grange's avatar
Adrian Grange committed
168 169 170
static aom_codec_err_t decoder_peek_si_internal(
    const uint8_t *data, unsigned int data_sz, aom_codec_stream_info_t *si,
    int *is_intra_only, aom_decrypt_cb decrypt_cb, void *decrypt_state) {
Jingning Han's avatar
Jingning Han committed
171 172 173
  int intra_only_flag = 0;
  uint8_t clear_buffer[9];

Adrian Grange's avatar
Adrian Grange committed
174
  if (data + data_sz <= data) return AOM_CODEC_INVALID_PARAM;
Jingning Han's avatar
Jingning Han committed
175 176 177 178 179

  si->is_kf = 0;
  si->w = si->h = 0;

  if (decrypt_cb) {
Adrian Grange's avatar
Adrian Grange committed
180
    data_sz = AOMMIN(sizeof(clear_buffer), data_sz);
Jingning Han's avatar
Jingning Han committed
181 182 183 184 185 186 187
    decrypt_cb(decrypt_state, data, clear_buffer, data_sz);
    data = clear_buffer;
  }

  {
    int show_frame;
    int error_resilient;
Adrian Grange's avatar
Adrian Grange committed
188 189
    struct aom_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
    const int frame_marker = aom_rb_read_literal(&rb, 2);
190
    const BITSTREAM_PROFILE profile = av1_read_profile(&rb);
Jingning Han's avatar
Jingning Han committed
191

Adrian Grange's avatar
Adrian Grange committed
192
    if (frame_marker != AOM_FRAME_MARKER) return AOM_CODEC_UNSUP_BITSTREAM;
Jingning Han's avatar
Jingning Han committed
193

Adrian Grange's avatar
Adrian Grange committed
194
    if (profile >= MAX_PROFILES) return AOM_CODEC_UNSUP_BITSTREAM;
Jingning Han's avatar
Jingning Han committed
195 196

    if ((profile >= 2 && data_sz <= 1) || data_sz < 1)
Adrian Grange's avatar
Adrian Grange committed
197
      return AOM_CODEC_UNSUP_BITSTREAM;
Jingning Han's avatar
Jingning Han committed
198

Adrian Grange's avatar
Adrian Grange committed
199 200
    if (aom_rb_read_bit(&rb)) {     // show an existing frame
      aom_rb_read_literal(&rb, 3);  // Frame buffer to show.
Adrian Grange's avatar
Adrian Grange committed
201
      return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
202 203
    }

Adrian Grange's avatar
Adrian Grange committed
204
    if (data_sz <= 8) return AOM_CODEC_UNSUP_BITSTREAM;
Jingning Han's avatar
Jingning Han committed
205

Adrian Grange's avatar
Adrian Grange committed
206 207 208
    si->is_kf = !aom_rb_read_bit(&rb);
    show_frame = aom_rb_read_bit(&rb);
    error_resilient = aom_rb_read_bit(&rb);
Jingning Han's avatar
Jingning Han committed
209 210

    if (si->is_kf) {
Adrian Grange's avatar
Adrian Grange committed
211
      if (!av1_read_sync_code(&rb)) return AOM_CODEC_UNSUP_BITSTREAM;
Jingning Han's avatar
Jingning Han committed
212 213

      if (!parse_bitdepth_colorspace_sampling(profile, &rb))
Adrian Grange's avatar
Adrian Grange committed
214
        return AOM_CODEC_UNSUP_BITSTREAM;
215
      av1_read_frame_size(&rb, (int *)&si->w, (int *)&si->h);
Jingning Han's avatar
Jingning Han committed
216
    } else {
Adrian Grange's avatar
Adrian Grange committed
217
      intra_only_flag = show_frame ? 0 : aom_rb_read_bit(&rb);
Jingning Han's avatar
Jingning Han committed
218 219 220 221

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

      if (intra_only_flag) {
Adrian Grange's avatar
Adrian Grange committed
222
        if (!av1_read_sync_code(&rb)) return AOM_CODEC_UNSUP_BITSTREAM;
Jingning Han's avatar
Jingning Han committed
223 224
        if (profile > PROFILE_0) {
          if (!parse_bitdepth_colorspace_sampling(profile, &rb))
Adrian Grange's avatar
Adrian Grange committed
225
            return AOM_CODEC_UNSUP_BITSTREAM;
Jingning Han's avatar
Jingning Han committed
226 227
        }
        rb.bit_offset += REF_FRAMES;  // refresh_frame_flags
228
        av1_read_frame_size(&rb, (int *)&si->w, (int *)&si->h);
Jingning Han's avatar
Jingning Han committed
229 230 231
      }
    }
  }
clang-format's avatar
clang-format committed
232
  if (is_intra_only != NULL) *is_intra_only = intra_only_flag;
Adrian Grange's avatar
Adrian Grange committed
233
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
234 235
}

Adrian Grange's avatar
Adrian Grange committed
236
static aom_codec_err_t decoder_peek_si(const uint8_t *data,
Jingning Han's avatar
Jingning Han committed
237
                                       unsigned int data_sz,
Adrian Grange's avatar
Adrian Grange committed
238
                                       aom_codec_stream_info_t *si) {
Jingning Han's avatar
Jingning Han committed
239 240 241
  return decoder_peek_si_internal(data, data_sz, si, NULL, NULL, NULL);
}

Adrian Grange's avatar
Adrian Grange committed
242 243
static aom_codec_err_t decoder_get_si(aom_codec_alg_priv_t *ctx,
                                      aom_codec_stream_info_t *si) {
244 245
  const size_t sz = (si->sz >= sizeof(av1_stream_info_t))
                        ? sizeof(av1_stream_info_t)
Adrian Grange's avatar
Adrian Grange committed
246
                        : sizeof(aom_codec_stream_info_t);
Jingning Han's avatar
Jingning Han committed
247 248 249
  memcpy(si, &ctx->si, sz);
  si->sz = (unsigned int)sz;

Adrian Grange's avatar
Adrian Grange committed
250
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
251 252
}

Adrian Grange's avatar
Adrian Grange committed
253
static void set_error_detail(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
254 255 256 257
                             const char *const error) {
  ctx->base.err_detail = error;
}

Adrian Grange's avatar
Adrian Grange committed
258 259
static aom_codec_err_t update_error_state(
    aom_codec_alg_priv_t *ctx, const struct aom_internal_error_info *error) {
Jingning Han's avatar
Jingning Han committed
260 261 262 263 264 265
  if (error->error_code)
    set_error_detail(ctx, error->has_detail ? error->detail : NULL);

  return error->error_code;
}

Adrian Grange's avatar
Adrian Grange committed
266
static void init_buffer_callbacks(aom_codec_alg_priv_t *ctx) {
Jingning Han's avatar
Jingning Han committed
267 268 269 270 271
  int i;

  for (i = 0; i < ctx->num_frame_workers; ++i) {
    VPxWorker *const worker = &ctx->frame_workers[i];
    FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
272
    AV1_COMMON *const cm = &frame_worker_data->pbi->common;
Jingning Han's avatar
Jingning Han committed
273 274 275 276 277 278 279 280 281 282 283
    BufferPool *const pool = cm->buffer_pool;

    cm->new_fb_idx = INVALID_IDX;
    cm->byte_alignment = ctx->byte_alignment;
    cm->skip_loop_filter = ctx->skip_loop_filter;

    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 {
284 285
      pool->get_fb_cb = av1_get_frame_buffer;
      pool->release_fb_cb = av1_release_frame_buffer;
Jingning Han's avatar
Jingning Han committed
286

287
      if (av1_alloc_internal_frame_buffers(&pool->int_frame_buffers))
Adrian Grange's avatar
Adrian Grange committed
288
        aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
Jingning Han's avatar
Jingning Han committed
289 290 291 292 293 294 295
                           "Failed to initialize internal frame buffers");

      pool->cb_priv = &pool->int_frame_buffers;
    }
  }
}

Adrian Grange's avatar
Adrian Grange committed
296
static void set_default_ppflags(aom_postproc_cfg_t *cfg) {
Adrian Grange's avatar
Adrian Grange committed
297
  cfg->post_proc_flag = AOM_DEBLOCK | AOM_DEMACROBLOCK;
Jingning Han's avatar
Jingning Han committed
298 299 300 301 302 303 304 305 306
  cfg->deblocking_level = 4;
  cfg->noise_level = 0;
}

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;

307
  frame_worker_data->result = av1_receive_compressed_data(
clang-format's avatar
clang-format committed
308
      frame_worker_data->pbi, frame_worker_data->data_size, &data);
Jingning Han's avatar
Jingning Han committed
309 310
  frame_worker_data->data_end = data;

311
  if (frame_worker_data->pbi->common.frame_parallel_decode) {
Jingning Han's avatar
Jingning Han committed
312 313 314 315 316 317 318
    // 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) {
      VPxWorker *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.
319
      av1_frameworker_lock_stats(worker);
Jingning Han's avatar
Jingning Han committed
320 321 322 323 324
      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;
325 326
      av1_frameworker_signal_stats(worker);
      av1_frameworker_unlock_stats(worker);
Jingning Han's avatar
Jingning Han committed
327 328 329 330 331 332 333 334 335 336
      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;
}

Adrian Grange's avatar
Adrian Grange committed
337
static aom_codec_err_t init_decoder(aom_codec_alg_priv_t *ctx) {
Jingning Han's avatar
Jingning Han committed
338
  int i;
Adrian Grange's avatar
Adrian Grange committed
339
  const VPxWorkerInterface *const winterface = aom_get_worker_interface();
Jingning Han's avatar
Jingning Han committed
340 341 342 343 344 345 346 347 348 349

  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;
  ctx->need_resync = 1;
  ctx->num_frame_workers =
clang-format's avatar
clang-format committed
350
      (ctx->frame_parallel_decode == 1) ? ctx->cfg.threads : 1;
Jingning Han's avatar
Jingning Han committed
351 352 353 354 355
  if (ctx->num_frame_workers > MAX_DECODE_THREADS)
    ctx->num_frame_workers = MAX_DECODE_THREADS;
  ctx->available_threads = ctx->num_frame_workers;
  ctx->flushed = 0;

Adrian Grange's avatar
Adrian Grange committed
356
  ctx->buffer_pool = (BufferPool *)aom_calloc(1, sizeof(BufferPool));
Adrian Grange's avatar
Adrian Grange committed
357
  if (ctx->buffer_pool == NULL) return AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
358 359

#if CONFIG_MULTITHREAD
clang-format's avatar
clang-format committed
360 361
  if (pthread_mutex_init(&ctx->buffer_pool->pool_mutex, NULL)) {
    set_error_detail(ctx, "Failed to allocate buffer pool mutex");
Adrian Grange's avatar
Adrian Grange committed
362
    return AOM_CODEC_MEM_ERROR;
clang-format's avatar
clang-format committed
363
  }
Jingning Han's avatar
Jingning Han committed
364 365
#endif

Adrian Grange's avatar
Adrian Grange committed
366
  ctx->frame_workers = (VPxWorker *)aom_malloc(ctx->num_frame_workers *
clang-format's avatar
clang-format committed
367
                                               sizeof(*ctx->frame_workers));
Jingning Han's avatar
Jingning Han committed
368 369
  if (ctx->frame_workers == NULL) {
    set_error_detail(ctx, "Failed to allocate frame_workers");
Adrian Grange's avatar
Adrian Grange committed
370
    return AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
371 372 373 374 375 376
  }

  for (i = 0; i < ctx->num_frame_workers; ++i) {
    VPxWorker *const worker = &ctx->frame_workers[i];
    FrameWorkerData *frame_worker_data = NULL;
    winterface->init(worker);
Adrian Grange's avatar
Adrian Grange committed
377
    worker->data1 = aom_memalign(32, sizeof(FrameWorkerData));
Jingning Han's avatar
Jingning Han committed
378 379
    if (worker->data1 == NULL) {
      set_error_detail(ctx, "Failed to allocate frame_worker_data");
Adrian Grange's avatar
Adrian Grange committed
380
      return AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
381 382
    }
    frame_worker_data = (FrameWorkerData *)worker->data1;
383
    frame_worker_data->pbi = av1_decoder_create(ctx->buffer_pool);
Jingning Han's avatar
Jingning Han committed
384 385
    if (frame_worker_data->pbi == NULL) {
      set_error_detail(ctx, "Failed to allocate frame_worker_data");
Adrian Grange's avatar
Adrian Grange committed
386
      return AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
387 388 389 390 391 392 393 394 395 396
    }
    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;
    frame_worker_data->received_frame = 0;
#if CONFIG_MULTITHREAD
    if (pthread_mutex_init(&frame_worker_data->stats_mutex, NULL)) {
      set_error_detail(ctx, "Failed to allocate frame_worker_data mutex");
Adrian Grange's avatar
Adrian Grange committed
397
      return AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
398 399 400 401
    }

    if (pthread_cond_init(&frame_worker_data->stats_cond, NULL)) {
      set_error_detail(ctx, "Failed to allocate frame_worker_data cond");
Adrian Grange's avatar
Adrian Grange committed
402
      return AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
403 404 405 406 407 408 409 410 411 412 413 414 415
    }
#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->common.frame_parallel_decode =
        ctx->frame_parallel_decode;
    worker->hook = (VPxWorkerHook)frame_worker_hook;
    if (!winterface->reset(worker)) {
      set_error_detail(ctx, "Frame Worker thread creation failed");
Adrian Grange's avatar
Adrian Grange committed
416
      return AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
417 418 419 420 421
    }
  }

  // If postprocessing was enabled by the application and a
  // configuration has not been provided, default it.
Adrian Grange's avatar
Adrian Grange committed
422
  if (!ctx->postproc_cfg_set && (ctx->base.init_flags & AOM_CODEC_USE_POSTPROC))
Jingning Han's avatar
Jingning Han committed
423 424 425 426
    set_default_ppflags(&ctx->postproc_cfg);

  init_buffer_callbacks(ctx);

Adrian Grange's avatar
Adrian Grange committed
427
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
428 429
}

Adrian Grange's avatar
Adrian Grange committed
430
static INLINE void check_resync(aom_codec_alg_priv_t *const ctx,
431
                                const AV1Decoder *const pbi) {
Jingning Han's avatar
Jingning Han committed
432 433 434 435 436 437
  // 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;
}

Adrian Grange's avatar
Adrian Grange committed
438
static aom_codec_err_t decode_one(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
439 440
                                  const uint8_t **data, unsigned int data_sz,
                                  void *user_priv, int64_t deadline) {
Adrian Grange's avatar
Adrian Grange committed
441
  const VPxWorkerInterface *const winterface = aom_get_worker_interface();
Jingning Han's avatar
Jingning Han committed
442 443 444 445 446 447 448
  (void)deadline;

  // 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) {
    int is_intra_only = 0;
Adrian Grange's avatar
Adrian Grange committed
449
    const aom_codec_err_t res =
Jingning Han's avatar
Jingning Han committed
450 451
        decoder_peek_si_internal(*data, data_sz, &ctx->si, &is_intra_only,
                                 ctx->decrypt_cb, ctx->decrypt_state);
Adrian Grange's avatar
Adrian Grange committed
452
    if (res != AOM_CODEC_OK) return res;
Jingning Han's avatar
Jingning Han committed
453

Adrian Grange's avatar
Adrian Grange committed
454
    if (!ctx->si.is_kf && !is_intra_only) return AOM_CODEC_ERROR;
Jingning Han's avatar
Jingning Han committed
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
  }

  if (!ctx->frame_parallel_decode) {
    VPxWorker *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;
    frame_worker_data->received_frame = 1;

    // 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;

    worker->had_error = 0;
    winterface->execute(worker);

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

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

    check_resync(ctx, frame_worker_data->pbi);
  } else {
    VPxWorker *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)
485
      av1_frameworker_copy_context(
Jingning Han's avatar
Jingning Han committed
486 487 488 489 490 491 492 493 494 495
          &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 =
Adrian Grange's avatar
Adrian Grange committed
496
          (uint8_t *)aom_realloc(frame_worker_data->scratch_buffer, data_sz);
Jingning Han's avatar
Jingning Han committed
497 498
      if (frame_worker_data->scratch_buffer == NULL) {
        set_error_detail(ctx, "Failed to reallocate scratch buffer");
Adrian Grange's avatar
Adrian Grange committed
499
        return AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
      }
      frame_worker_data->scratch_buffer_size = data_sz;
    }
    frame_worker_data->data_size = data_sz;
    memcpy(frame_worker_data->scratch_buffer, *data, data_sz);

    frame_worker_data->frame_decoded = 0;
    frame_worker_data->frame_context_ready = 0;
    frame_worker_data->received_frame = 1;
    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);
  }

Adrian Grange's avatar
Adrian Grange committed
523
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
524 525
}

Adrian Grange's avatar
Adrian Grange committed
526
static void wait_worker_and_cache_frame(aom_codec_alg_priv_t *ctx) {
Jingning Han's avatar
Jingning Han committed
527
  YV12_BUFFER_CONFIG sd;
Adrian Grange's avatar
Adrian Grange committed
528
  const VPxWorkerInterface *const winterface = aom_get_worker_interface();
Jingning Han's avatar
Jingning Han committed
529 530 531 532 533 534 535 536 537 538 539
  VPxWorker *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;
  // TODO(hkuang): Add worker error handling here.
  winterface->sync(worker);
  frame_worker_data->received_frame = 0;
  ++ctx->available_threads;

  check_resync(ctx, frame_worker_data->pbi);

540 541
  if (av1_get_raw_frame(frame_worker_data->pbi, &sd) == 0) {
    AV1_COMMON *const cm = &frame_worker_data->pbi->common;
Jingning Han's avatar
Jingning Han committed
542 543 544 545 546 547
    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;
clang-format's avatar
clang-format committed
548
    ctx->frame_cache_write = (ctx->frame_cache_write + 1) % FRAME_CACHE_SIZE;
Jingning Han's avatar
Jingning Han committed
549 550 551 552
    ++ctx->num_cache_frames;
  }
}

Adrian Grange's avatar
Adrian Grange committed
553
static aom_codec_err_t decoder_decode(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
554 555 556
                                      const uint8_t *data, unsigned int data_sz,
                                      void *user_priv, long deadline) {
  const uint8_t *data_start = data;
clang-format's avatar
clang-format committed
557
  const uint8_t *const data_end = data + data_sz;
Adrian Grange's avatar
Adrian Grange committed
558
  aom_codec_err_t res;
Jingning Han's avatar
Jingning Han committed
559 560 561 562 563
  uint32_t frame_sizes[8];
  int frame_count;

  if (data == NULL && data_sz == 0) {
    ctx->flushed = 1;
Adrian Grange's avatar
Adrian Grange committed
564
    return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
565 566 567 568 569 570 571
  }

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

  // Initialize the decoder workers on the first frame.
  if (ctx->frame_workers == NULL) {
Adrian Grange's avatar
Adrian Grange committed
572
    const aom_codec_err_t res = init_decoder(ctx);
Adrian Grange's avatar
Adrian Grange committed
573
    if (res != AOM_CODEC_OK) return res;
Jingning Han's avatar
Jingning Han committed
574 575
  }

576
  res = av1_parse_superframe_index(data, data_sz, frame_sizes, &frame_count,
clang-format's avatar
clang-format committed
577
                                    ctx->decrypt_cb, ctx->decrypt_state);
Adrian Grange's avatar
Adrian Grange committed
578
  if (res != AOM_CODEC_OK) return res;
Jingning Han's avatar
Jingning Han committed
579 580 581 582 583 584 585 586 587 588 589 590

  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];
clang-format's avatar
clang-format committed
591 592
        if (data_start < data ||
            frame_size > (uint32_t)(data_end - data_start)) {
Jingning Han's avatar
Jingning Han committed
593
          set_error_detail(ctx, "Invalid frame size in index");
Adrian Grange's avatar
Adrian Grange committed
594
          return AOM_CODEC_CORRUPT_FRAME;
Jingning Han's avatar
Jingning Han committed
595 596 597 598 599 600 601 602 603 604
        }

        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.");
Adrian Grange's avatar
Adrian Grange committed
605
            return AOM_CODEC_ERROR;
Jingning Han's avatar
Jingning Han committed
606 607 608
          }
        }

clang-format's avatar
clang-format committed
609 610
        res =
            decode_one(ctx, &data_start_copy, frame_size, user_priv, deadline);
Adrian Grange's avatar
Adrian Grange committed
611
        if (res != AOM_CODEC_OK) return res;
Jingning Han's avatar
Jingning Han committed
612 613 614 615 616 617 618 619 620 621 622
        data_start += frame_size;
      }
    } else {
      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.");
Adrian Grange's avatar
Adrian Grange committed
623
          return AOM_CODEC_ERROR;
Jingning Han's avatar
Jingning Han committed
624 625 626 627
        }
      }

      res = decode_one(ctx, &data, data_sz, user_priv, deadline);
Adrian Grange's avatar
Adrian Grange committed
628
      if (res != AOM_CODEC_OK) return res;
Jingning Han's avatar
Jingning Han committed
629 630 631 632 633 634 635 636 637
    }
  } else {
    // 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];
Adrian Grange's avatar
Adrian Grange committed
638
        aom_codec_err_t res;
clang-format's avatar
clang-format committed
639 640
        if (data_start < data ||
            frame_size > (uint32_t)(data_end - data_start)) {
Jingning Han's avatar
Jingning Han committed
641
          set_error_detail(ctx, "Invalid frame size in index");
Adrian Grange's avatar
Adrian Grange committed
642
          return AOM_CODEC_CORRUPT_FRAME;
Jingning Han's avatar
Jingning Han committed
643 644
        }

clang-format's avatar
clang-format committed
645 646
        res =
            decode_one(ctx, &data_start_copy, frame_size, user_priv, deadline);
Adrian Grange's avatar
Adrian Grange committed
647
        if (res != AOM_CODEC_OK) return res;
Jingning Han's avatar
Jingning Han committed
648 649 650 651 652

        data_start += frame_size;
      }
    } else {
      while (data_start < data_end) {
clang-format's avatar
clang-format committed
653
        const uint32_t frame_size = (uint32_t)(data_end - data_start);
Adrian Grange's avatar
Adrian Grange committed
654
        const aom_codec_err_t res =
clang-format's avatar
clang-format committed
655
            decode_one(ctx, &data_start, frame_size, user_priv, deadline);
Adrian Grange's avatar
Adrian Grange committed
656
        if (res != AOM_CODEC_OK) return res;
Jingning Han's avatar
Jingning Han committed
657 658 659

        // Account for suboptimal termination by the encoder.
        while (data_start < data_end) {
clang-format's avatar
clang-format committed
660 661 662
          const uint8_t marker =
              read_marker(ctx->decrypt_cb, ctx->decrypt_state, data_start);
          if (marker) break;
Jingning Han's avatar
Jingning Han committed
663 664 665 666 667 668 669 670 671
          ++data_start;
        }
      }
    }
  }

  return res;
}

Adrian Grange's avatar
Adrian Grange committed
672
static void release_last_output_frame(aom_codec_alg_priv_t *ctx) {
Jingning Han's avatar
Jingning Han committed
673 674 675 676 677 678 679 680 681 682
  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);
  }
}

Adrian Grange's avatar
Adrian Grange committed
683 684 685
static aom_image_t *decoder_get_frame(aom_codec_alg_priv_t *ctx,
                                      aom_codec_iter_t *iter) {
  aom_image_t *img = NULL;
Jingning Han's avatar
Jingning Han committed
686 687 688 689 690 691 692 693 694 695 696

  // 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) {
    return NULL;
  }

  // Output the frames in the cache first.
  if (ctx->num_cache_frames > 0) {
    release_last_output_frame(ctx);
clang-format's avatar
clang-format committed
697 698
    ctx->last_show_frame = ctx->frame_cache[ctx->frame_cache_read].fb_idx;
    if (ctx->need_resync) return NULL;
Jingning Han's avatar
Jingning Han committed
699 700 701 702 703 704 705 706 707 708 709
    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;
  }

  // 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;
Adrian Grange's avatar
Adrian Grange committed
710
      const VPxWorkerInterface *const winterface = aom_get_worker_interface();
clang-format's avatar
clang-format committed
711
      VPxWorker *const worker = &ctx->frame_workers[ctx->next_output_worker_id];
Jingning Han's avatar
Jingning Han committed
712 713 714 715 716 717 718 719 720 721 722 723
      FrameWorkerData *const frame_worker_data =
          (FrameWorkerData *)worker->data1;
      ctx->next_output_worker_id =
          (ctx->next_output_worker_id + 1) % ctx->num_frame_workers;
      // Wait for the frame from worker thread.
      if (winterface->sync(worker)) {
        // Check if worker has received any frames.
        if (frame_worker_data->received_frame == 1) {
          ++ctx->available_threads;
          frame_worker_data->received_frame = 0;
          check_resync(ctx, frame_worker_data->pbi);
        }
724 725
        if (av1_get_raw_frame(frame_worker_data->pbi, &sd) == 0) {
          AV1_COMMON *const cm = &frame_worker_data->pbi->common;
Jingning Han's avatar
Jingning Han committed
726 727 728
          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;
clang-format's avatar
clang-format committed
729
          if (ctx->need_resync) return NULL;
Jingning Han's avatar
Jingning Han committed
730 731 732 733 734 735 736 737 738 739
          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 {
        // Decoding failed. Release the worker thread.
        frame_worker_data->received_frame = 0;
        ++ctx->available_threads;
        ctx->need_resync = 1;
clang-format's avatar
clang-format committed
740
        if (ctx->flushed != 1) return NULL;
Jingning Han's avatar
Jingning Han committed
741 742 743 744 745 746
      }
    } while (ctx->next_output_worker_id != ctx->next_submit_worker_id);
  }
  return NULL;
}

Adrian Grange's avatar
Adrian Grange committed
747 748 749
static aom_codec_err_t decoder_set_fb_fn(
    aom_codec_alg_priv_t *ctx, aom_get_frame_buffer_cb_fn_t cb_get,
    aom_release_frame_buffer_cb_fn_t cb_release, void *cb_priv) {
Jingning Han's avatar
Jingning Han committed
750
  if (cb_get == NULL || cb_release == NULL) {
Adrian Grange's avatar
Adrian Grange committed
751
    return AOM_CODEC_INVALID_PARAM;
Jingning Han's avatar
Jingning Han committed
752 753 754 755 756 757
  } else if (ctx->frame_workers == NULL) {
    // If the decoder has already been initialized, do not accept changes to
    // the frame buffer functions.
    ctx->get_ext_fb_cb = cb_get;
    ctx->release_ext_fb_cb = cb_release;
    ctx->ext_priv = cb_priv;
Adrian Grange's avatar
Adrian Grange committed
758
    return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
759 760
  }

Adrian Grange's avatar
Adrian Grange committed
761
  return AOM_CODEC_ERROR;
Jingning Han's avatar
Jingning Han committed
762 763
}

Adrian Grange's avatar
Adrian Grange committed
764
static aom_codec_err_t ctrl_set_reference(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
765
                                          va_list args) {
Adrian Grange's avatar
Adrian Grange committed
766
  aom_ref_frame_t *const data = va_arg(args, aom_ref_frame_t *);
Jingning Han's avatar
Jingning Han committed
767 768 769 770

  // Only support this function in serial decode.
  if (ctx->frame_parallel_decode) {
    set_error_detail(ctx, "Not supported in frame parallel decode");
Adrian Grange's avatar
Adrian Grange committed
771
    return AOM_CODEC_INCAPABLE;
Jingning Han's avatar
Jingning Han committed
772 773 774
  }

  if (data) {
Adrian Grange's avatar
Adrian Grange committed
775
    aom_ref_frame_t *const frame = (aom_ref_frame_t *)data;
Jingning Han's avatar
Jingning Han committed
776 777 778 779
    YV12_BUFFER_CONFIG sd;
    VPxWorker *const worker = ctx->frame_workers;
    FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
    image2yuvconfig(&frame->img, &sd);
780
    return av1_set_reference_dec(&frame_worker_data->pbi->common,
Adrian Grange's avatar
Adrian Grange committed
781
                                  (AOM_REFFRAME)frame->frame_type, &sd);
Jingning Han's avatar
Jingning Han committed
782
  } else {
Adrian Grange's avatar
Adrian Grange committed
783
    return AOM_CODEC_INVALID_PARAM;
Jingning Han's avatar
Jingning Han committed
784 785 786
  }
}

Adrian Grange's avatar
Adrian Grange committed
787
static aom_codec_err_t ctrl_copy_reference(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
788
                                           va_list args) {
Adrian Grange's avatar
Adrian Grange committed
789
  aom_ref_frame_t *data = va_arg(args, aom_ref_frame_t *);
Jingning Han's avatar
Jingning Han committed
790 791 792 793

  // Only support this function in serial decode.
  if (ctx->frame_parallel_decode) {
    set_error_detail(ctx, "Not supported in frame parallel decode");
Adrian Grange's avatar
Adrian Grange committed
794
    return AOM_CODEC_INCAPABLE;
Jingning Han's avatar
Jingning Han committed
795 796 797
  }

  if (data) {
Adrian Grange's avatar
Adrian Grange committed
798
    aom_ref_frame_t *frame = (aom_ref_frame_t *)data;
Jingning Han's avatar
Jingning Han committed
799 800 801 802
    YV12_BUFFER_CONFIG sd;
    VPxWorker *const worker = ctx->frame_workers;
    FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
    image2yuvconfig(&frame->img, &sd);
803
    return av1_copy_reference_dec(frame_worker_data->pbi,
Adrian Grange's avatar
Adrian Grange committed
804
                                   (AOM_REFFRAME)frame->frame_type, &sd);
Jingning Han's avatar
Jingning Han committed
805
  } else {
Adrian Grange's avatar
Adrian Grange committed
806
    return AOM_CODEC_INVALID_PARAM;
Jingning Han's avatar
Jingning Han committed
807 808 809
  }
}

Adrian Grange's avatar
Adrian Grange committed
810
static aom_codec_err_t ctrl_get_reference(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
811 812 813 814 815 816
                                          va_list args) {
  vp9_ref_frame_t *data = va_arg(args, vp9_ref_frame_t *);

  // Only support this function in serial decode.
  if (ctx->frame_parallel_decode) {
    set_error_detail(ctx, "Not supported in frame parallel decode");
Adrian Grange's avatar
Adrian Grange committed
817
    return AOM_CODEC_INCAPABLE;
Jingning Han's avatar
Jingning Han committed
818 819 820
  }

  if (data) {
clang-format's avatar
clang-format committed
821
    YV12_BUFFER_CONFIG *fb;
Jingning Han's avatar
Jingning Han committed
822 823 824
    VPxWorker *const worker = ctx->frame_workers;
    FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
    fb = get_ref_frame(&frame_worker_data->pbi->common, data->idx);
Adrian Grange's avatar
Adrian Grange committed
825
    if (fb == NULL) return AOM_CODEC_ERROR;
Jingning Han's avatar
Jingning Han committed
826
    yuvconfig2image(&data->img, fb, NULL);
Adrian Grange's avatar
Adrian Grange committed
827
    return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
828
  } else {
Adrian Grange's avatar
Adrian Grange committed
829
    return AOM_CODEC_INVALID_PARAM;
Jingning Han's avatar
Jingning Han committed
830 831 832
  }
}

Adrian Grange's avatar
Adrian Grange committed
833
static aom_codec_err_t ctrl_set_postproc(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
834 835 836
                                         va_list args) {
  (void)ctx;
  (void)args;
Adrian Grange's avatar
Adrian Grange committed
837
  return AOM_CODEC_INCAPABLE;
Jingning Han's avatar
Jingning Han committed
838 839
}

Adrian Grange's avatar
Adrian Grange committed
840
static aom_codec_err_t ctrl_set_dbg_options(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
841 842 843
                                            va_list args) {
  (void)ctx;
  (void)args;
Adrian Grange's avatar
Adrian Grange committed
844
  return AOM_CODEC_INCAPABLE;
Jingning Han's avatar
Jingning Han committed
845 846
}

Adrian Grange's avatar
Adrian Grange committed
847
static aom_codec_err_t ctrl_get_last_ref_updates(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
848 849 850 851 852 853
                                                 va_list args) {
  int *const update_info = 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");
Adrian Grange's avatar
Adrian Grange committed
854
    return AOM_CODEC_INCAPABLE;
Jingning Han's avatar
Jingning Han committed
855 856 857 858 859 860 861 862
  }

  if (update_info) {
    if (ctx->frame_workers) {
      VPxWorker *const worker = ctx->frame_workers;
      FrameWorkerData *const frame_worker_data =
          (FrameWorkerData *)worker->data1;
      *update_info = frame_worker_data->pbi->refresh_frame_flags;
Adrian Grange's avatar
Adrian Grange committed
863
      return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
864
    } else {
Adrian Grange's avatar
Adrian Grange committed
865
      return AOM_CODEC_ERROR;
Jingning Han's avatar
Jingning Han committed
866 867 868
    }
  }

Adrian Grange's avatar
Adrian Grange committed
869
  return AOM_CODEC_INVALID_PARAM;
Jingning Han's avatar
Jingning Han committed
870 871
}

Adrian Grange's avatar
Adrian Grange committed
872
static aom_codec_err_t ctrl_get_frame_corrupted(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
873 874 875 876 877 878 879 880 881 882 883
                                                va_list args) {
  int *corrupted = va_arg(args, int *);

  if (corrupted) {
    if (ctx->frame_workers) {
      VPxWorker *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)
Adrian Grange's avatar
Adrian Grange committed
884
        return AOM_CODEC_ERROR;
Jingning Han's avatar
Jingning Han committed
885 886
      if (ctx->last_show_frame >= 0)
        *corrupted = frame_bufs[ctx->last_show_frame].buf.corrupted;
Adrian Grange's avatar
Adrian Grange committed
887
      return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
888
    } else {
Adrian Grange's avatar
Adrian Grange committed
889
      return AOM_CODEC_ERROR;
Jingning Han's avatar
Jingning Han committed
890 891 892
    }
  }

Adrian Grange's avatar
Adrian Grange committed
893
  return AOM_CODEC_INVALID_PARAM;
Jingning Han's avatar
Jingning Han committed
894 895
}

Adrian Grange's avatar
Adrian Grange committed
896
static aom_codec_err_t ctrl_get_frame_size(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
897 898 899 900 901 902
                                           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");
Adrian Grange's avatar
Adrian Grange committed
903
    return AOM_CODEC_INCAPABLE;
Jingning Han's avatar
Jingning Han committed
904 905 906 907 908 909 910
  }

  if (frame_size) {
    if (ctx->frame_workers) {
      VPxWorker *const worker = ctx->frame_workers;
      FrameWorkerData *const frame_worker_data =
          (FrameWorkerData *)worker->data1;
911
      const AV1_COMMON *const cm = &frame_worker_data->pbi->common;
Jingning Han's avatar
Jingning Han committed
912 913
      frame_size[0] = cm->width;
      frame_size[1] = cm->height;
Adrian Grange's avatar
Adrian Grange committed
914
      return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
915
    } else {
Adrian Grange's avatar
Adrian Grange committed
916
      return AOM_CODEC_ERROR;
Jingning Han's avatar
Jingning Han committed
917 918 919
    }
  }

Adrian Grange's avatar
Adrian Grange committed
920
  return AOM_CODEC_INVALID_PARAM;
Jingning Han's avatar
Jingning Han committed
921 922
}

Adrian Grange's avatar
Adrian Grange committed
923
static aom_codec_err_t ctrl_get_render_size(aom_codec_alg_priv_t *ctx,
924 925
                                            va_list args) {
  int *const render_size = va_arg(args, int *);
Jingning Han's avatar
Jingning Han committed
926 927 928 929

  // Only support this function in serial decode.
  if (ctx->frame_parallel_decode) {
    set_error_detail(ctx, "Not supported in frame parallel decode");
Adrian Grange's avatar
Adrian Grange committed
930
    return AOM_CODEC_INCAPABLE;
Jingning Han's avatar
Jingning Han committed
931 932
  }

933
  if (render_size) {
Jingning Han's avatar
Jingning Han committed
934 935 936 937
    if (ctx->frame_workers) {
      VPxWorker *const worker = ctx->frame_workers;
      FrameWorkerData *const frame_worker_data =
          (FrameWorkerData *)worker->data1;
938
      const AV1_COMMON *const cm = &frame_worker_data->pbi->common;
939 940
      render_size[0] = cm->render_width;
      render_size[1] = cm->render_height;
Adrian Grange's avatar
Adrian Grange committed
941
      return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
942
    } else {
Adrian Grange's avatar
Adrian Grange committed
943
      return AOM_CODEC_ERROR;
Jingning Han's avatar
Jingning Han committed
944 945 946
    }
  }

Adrian Grange's avatar
Adrian Grange committed
947
  return AOM_CODEC_INVALID_PARAM;
Jingning Han's avatar
Jingning Han committed
948 949
}

Adrian Grange's avatar
Adrian Grange committed
950
static aom_codec_err_t ctrl_get_bit_depth(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
951 952 953 954 955 956 957 958
                                          va_list args) {
  unsigned int *const bit_depth = va_arg(args, unsigned int *);
  VPxWorker *const worker = &ctx->frame_workers[ctx->next_output_worker_id];

  if (bit_depth) {
    if (worker) {
      FrameWorkerData *const frame_worker_data =
          (FrameWorkerData *)worker->data1;
959
      const AV1_COMMON *const cm = &frame_worker_data->pbi->common;
Jingning Han's avatar
Jingning Han committed
960
      *bit_depth = cm->bit_depth;
Adrian Grange's avatar
Adrian Grange committed
961
      return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
962
    } else {
Adrian Grange's avatar
Adrian Grange committed
963
      return AOM_CODEC_ERROR;
Jingning Han's avatar
Jingning Han committed
964 965 966
    }
  }

Adrian Grange's avatar
Adrian Grange committed
967
  return AOM_CODEC_INVALID_PARAM;
Jingning Han's avatar
Jingning Han committed
968 969
}

Adrian Grange's avatar
Adrian Grange committed
970
static aom_codec_err_t ctrl_set_invert_tile_order(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
971 972
                                                  va_list args) {
  ctx->invert_tile_order = va_arg(args, int);
Adrian Grange's avatar
Adrian Grange committed
973
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
974 975
}

Adrian Grange's avatar
Adrian Grange committed
976
static aom_codec_err_t ctrl_set_decryptor(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
977
                                          va_list args) {
Adrian Grange's avatar
Adrian Grange committed
978
  aom_decrypt_init *init = va_arg(args, aom_decrypt_init *);
Jingning Han's avatar
Jingning Han committed
979 980
  ctx->decrypt_cb = init ? init->decrypt_cb : NULL;
  ctx->decrypt_state = init ? init->decrypt_state : NULL;
Adrian Grange's avatar
Adrian Grange committed
981
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
982 983
}

Adrian Grange's avatar
Adrian Grange committed
984
static aom_codec_err_t ctrl_set_byte_alignment(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
985 986 987 988 989 990 991 992 993 994
                                               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))
Adrian Grange's avatar
Adrian Grange committed
995
    return AOM_CODEC_INVALID_PARAM;
Jingning Han's avatar
Jingning Han committed
996 997 998 999

  ctx->byte_alignment = byte_alignment;
  if (ctx->frame_workers) {
    VPxWorker *const worker = ctx->frame_workers;
clang-format's avatar
clang-format committed
1000
    FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
Jingning Han's avatar
Jingning Han committed
1001 1002
    frame_worker_data->pbi->common.byte_alignment = byte_alignment;
  }
Adrian Grange's avatar
Adrian Grange committed
1003
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
1004 1005
}

Adrian Grange's avatar
Adrian Grange committed
1006
static aom_codec_err_t ctrl_set_skip_loop_filter(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
1007 1008 1009 1010 1011 1012 1013 1014 1015
                                                 va_list args) {
  ctx->skip_loop_filter = va_arg(args, int);

  if (ctx->frame_workers) {
    VPxWorker *const worker = ctx->frame_workers;
    FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
    frame_worker_data->pbi->common.skip_loop_filter = ctx->skip_loop_filter;
  }

Adrian Grange's avatar
Adrian Grange committed
1016
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
1017 1018
}

Adrian Grange's avatar
Adrian Grange committed
1019
static aom_codec_ctrl_fn_map_t decoder_ctrl_maps[] = {
Adrian Grange's avatar
Adrian Grange committed
1020
  { AOM_COPY_REFERENCE, ctrl_copy_reference },
Jingning Han's avatar
Jingning Han committed
1021 1022

  // Setters
Adrian Grange's avatar
Adrian Grange committed
1023 1024 1025 1026 1027 1028
  { AOM_SET_REFERENCE, ctrl_set_reference },
  { AOM_SET_POSTPROC, ctrl_set_postproc },
  { AOM_SET_DBG_COLOR_REF_FRAME, ctrl_set_dbg_options },
  { AOM_SET_DBG_COLOR_MB_MODES, ctrl_set_dbg_options },
  { AOM_SET_DBG_COLOR_B_MODES, ctrl_set_dbg_options },
  { AOM_SET_DBG_DISPLAY_MV, ctrl_set_dbg_options },
Adrian Grange's avatar
Adrian Grange committed
1029
  { AV1_INVERT_TILE_DECODE_ORDER, ctrl_set_invert_tile_order },
Adrian Grange's avatar
Adrian Grange committed
1030
  { AOMD_SET_DECRYPTOR, ctrl_set_decryptor },
Adrian Grange's avatar
Adrian Grange committed
1031 1032
  { AV1_SET_BYTE_ALIGNMENT, ctrl_set_byte_alignment },
  { AV1_SET_SKIP_LOOP_FILTER, ctrl_set_skip_loop_filter },
Jingning Han's avatar
Jingning Han committed
1033 1034

  // Getters
Adrian Grange's avatar
Adrian Grange committed
1035 1036
  { AOMD_GET_LAST_REF_UPDATES, ctrl_get_last_ref_updates },
  { AOMD_GET_FRAME_CORRUPTED, ctrl_get_frame_corrupted },
Adrian Grange's avatar
Adrian Grange committed
1037 1038 1039 1040
  { AV1_GET_REFERENCE, ctrl_get_reference },
  { AV1D_GET_DISPLAY_SIZE, ctrl_get_render_size },
  { AV1D_GET_BIT_DEPTH, ctrl_get_bit_depth },
  { AV1D_GET_FRAME_SIZE, ctrl_get_frame_size },
clang-format's avatar
clang-format committed
1041 1042

  { -1, NULL },
Jingning Han's avatar
Jingning Han committed
1043 1044 1045 1046 1047
};

#ifndef VERSION_STRING
#define VERSION_STRING
#endif
1048 1049
CODEC_INTERFACE(aom_codec_av1_dx) = {
  "WebM Project AV1 Decoder" VERSION_STRING,
Adrian Grange's avatar
Adrian Grange committed
1050 1051 1052
  AOM_CODEC_INTERNAL_ABI_VERSION,
  AOM_CODEC_CAP_DECODER |
      AOM_CODEC_CAP_EXTERNAL_FRAME_BUFFER,  // aom_codec_caps_t
Adrian Grange's avatar
Adrian Grange committed
1053 1054 1055
  decoder_init,                             // aom_codec_init_fn_t
  decoder_destroy,                          // aom_codec_destroy_fn_t
  decoder_ctrl_maps,                        // aom_codec_ctrl_fn_map_t
clang-format's avatar
clang-format committed
1056 1057
  {
      // NOLINT
Adrian Grange's avatar
Adrian Grange committed
1058 1059 1060 1061 1062
      decoder_peek_si,    // aom_codec_peek_si_fn_t
      decoder_get_si,     // aom_codec_get_si_fn_t
      decoder_decode,     // aom_codec_decode_fn_t
      decoder_get_frame,  // aom_codec_frame_get_fn_t
      decoder_set_fb_fn,  // aom_codec_set_fb_fn_t
Jingning Han's avatar
Jingning Han committed
1063
  },
clang-format's avatar
clang-format committed
1064 1065 1066
  {
      // NOLINT
      0,
Adrian Grange's avatar
Adrian Grange committed
1067 1068 1069 1070 1071 1072 1073
      NULL,  // aom_codec_enc_cfg_map_t
      NULL,  // aom_codec_encode_fn_t
      NULL,  // aom_codec_get_cx_data_fn_t
      NULL,  // aom_codec_enc_config_set_fn_t
      NULL,  // aom_codec_get_global_headers_fn_t
      NULL,  // aom_codec_get_preview_frame_fn_t
      NULL   // aom_codec_enc_mr_get_mem_loc_fn_t
Jingning Han's avatar
Jingning Han committed
1074 1075
  }
};