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
49
  int postproc_cfg_set;
  vp8_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
296
                           "Failed to initialize internal frame buffers");

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

static void set_default_ppflags(vp8_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 },
clang-format's avatar
clang-format committed
1029
  { VP9_INVERT_TILE_DECODE_ORDER, ctrl_set_invert_tile_order },
Adrian Grange's avatar
Adrian Grange committed
1030
  { AOMD_SET_DECRYPTOR, ctrl_set_decryptor },
clang-format's avatar
clang-format committed
1031
1032
  { VP9_SET_BYTE_ALIGNMENT, ctrl_set_byte_alignment },
  { VP9_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 },
clang-format's avatar
clang-format committed
1037
1038
1039
1040
1041
1042
  { VP9_GET_REFERENCE, ctrl_get_reference },
  { VP9D_GET_DISPLAY_SIZE, ctrl_get_render_size },
  { VP9D_GET_BIT_DEPTH, ctrl_get_bit_depth },
  { VP9D_GET_FRAME_SIZE, ctrl_get_frame_size },

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