Line data Source code
1 : /*
2 : * Copyright (c) 2016, Alliance for Open Media. All rights reserved
3 : *
4 : * This source code is subject to the terms of the BSD 2 Clause License and
5 : * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 : * was not distributed with this source code in the LICENSE file, you can
7 : * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 : * Media Patent License 1.0 was not distributed with this source code in the
9 : * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10 : */
11 :
12 : #include <stdlib.h>
13 : #include <string.h>
14 :
15 : #include "./aom_config.h"
16 : #include "./aom_version.h"
17 :
18 : #include "aom/internal/aom_codec_internal.h"
19 : #include "aom/aomdx.h"
20 : #include "aom/aom_decoder.h"
21 : #include "aom_dsp/bitreader_buffer.h"
22 : #include "aom_dsp/aom_dsp_common.h"
23 : #include "aom_util/aom_thread.h"
24 :
25 : #include "av1/common/alloccommon.h"
26 : #include "av1/common/frame_buffers.h"
27 : #include "av1/common/enums.h"
28 :
29 : #include "av1/decoder/decoder.h"
30 : #include "av1/decoder/decodeframe.h"
31 :
32 : #include "av1/av1_iface_common.h"
33 :
34 : // This limit is due to framebuffer numbers.
35 : // TODO(hkuang): Remove this limit after implementing ondemand framebuffers.
36 : #define FRAME_CACHE_SIZE 6 // Cache maximum 6 decoded frames.
37 :
38 : typedef struct cache_frame {
39 : int fb_idx;
40 : aom_image_t img;
41 : } cache_frame;
42 :
43 : struct aom_codec_alg_priv {
44 : aom_codec_priv_t base;
45 : aom_codec_dec_cfg_t cfg;
46 : aom_codec_stream_info_t si;
47 : int postproc_cfg_set;
48 : aom_postproc_cfg_t postproc_cfg;
49 : aom_decrypt_cb decrypt_cb;
50 : void *decrypt_state;
51 : aom_image_t img;
52 : int img_avail;
53 : int flushed;
54 : int invert_tile_order;
55 : int last_show_frame; // Index of last output frame.
56 : int byte_alignment;
57 : int skip_loop_filter;
58 : int decode_tile_row;
59 : int decode_tile_col;
60 :
61 : // Frame parallel related.
62 : int frame_parallel_decode; // frame-based threading.
63 : AVxWorker *frame_workers;
64 : int num_frame_workers;
65 : int next_submit_worker_id;
66 : int last_submit_worker_id;
67 : int next_output_worker_id;
68 : int available_threads;
69 : cache_frame frame_cache[FRAME_CACHE_SIZE];
70 : int frame_cache_write;
71 : int frame_cache_read;
72 : int num_cache_frames;
73 : int need_resync; // wait for key/intra-only frame
74 : // BufferPool that holds all reference frames. Shared by all the FrameWorkers.
75 : BufferPool *buffer_pool;
76 :
77 : // External frame buffer info to save for AV1 common.
78 : void *ext_priv; // Private data associated with the external frame buffers.
79 : aom_get_frame_buffer_cb_fn_t get_ext_fb_cb;
80 : aom_release_frame_buffer_cb_fn_t release_ext_fb_cb;
81 :
82 : #if CONFIG_INSPECTION
83 : aom_inspect_cb inspect_cb;
84 : void *inspect_ctx;
85 : #endif
86 : };
87 :
88 0 : static aom_codec_err_t decoder_init(aom_codec_ctx_t *ctx,
89 : aom_codec_priv_enc_mr_cfg_t *data) {
90 : // This function only allocates space for the aom_codec_alg_priv_t
91 : // structure. More memory may be required at the time the stream
92 : // information becomes known.
93 : (void)data;
94 :
95 0 : if (!ctx->priv) {
96 0 : aom_codec_alg_priv_t *const priv =
97 : (aom_codec_alg_priv_t *)aom_calloc(1, sizeof(*priv));
98 0 : if (priv == NULL) return AOM_CODEC_MEM_ERROR;
99 :
100 0 : ctx->priv = (aom_codec_priv_t *)priv;
101 0 : ctx->priv->init_flags = ctx->init_flags;
102 0 : priv->flushed = 0;
103 : // Only do frame parallel decode when threads > 1.
104 0 : priv->frame_parallel_decode =
105 0 : (ctx->config.dec && (ctx->config.dec->threads > 1) &&
106 0 : (ctx->init_flags & AOM_CODEC_USE_FRAME_THREADING))
107 : ? 1
108 0 : : 0;
109 0 : if (ctx->config.dec) {
110 0 : priv->cfg = *ctx->config.dec;
111 0 : ctx->config.dec = &priv->cfg;
112 : }
113 : }
114 :
115 0 : return AOM_CODEC_OK;
116 : }
117 :
118 0 : static aom_codec_err_t decoder_destroy(aom_codec_alg_priv_t *ctx) {
119 0 : if (ctx->frame_workers != NULL) {
120 : int i;
121 0 : for (i = 0; i < ctx->num_frame_workers; ++i) {
122 0 : AVxWorker *const worker = &ctx->frame_workers[i];
123 0 : FrameWorkerData *const frame_worker_data =
124 : (FrameWorkerData *)worker->data1;
125 0 : aom_get_worker_interface()->end(worker);
126 0 : av1_remove_common(&frame_worker_data->pbi->common);
127 : #if CONFIG_LOOP_RESTORATION
128 : av1_free_restoration_buffers(&frame_worker_data->pbi->common);
129 : #endif // CONFIG_LOOP_RESTORATION
130 0 : av1_decoder_remove(frame_worker_data->pbi);
131 0 : aom_free(frame_worker_data->scratch_buffer);
132 : #if CONFIG_MULTITHREAD
133 0 : pthread_mutex_destroy(&frame_worker_data->stats_mutex);
134 0 : pthread_cond_destroy(&frame_worker_data->stats_cond);
135 : #endif
136 0 : aom_free(frame_worker_data);
137 : }
138 : #if CONFIG_MULTITHREAD
139 0 : pthread_mutex_destroy(&ctx->buffer_pool->pool_mutex);
140 : #endif
141 : }
142 :
143 0 : if (ctx->buffer_pool) {
144 0 : av1_free_ref_frame_buffers(ctx->buffer_pool);
145 0 : av1_free_internal_frame_buffers(&ctx->buffer_pool->int_frame_buffers);
146 : }
147 :
148 0 : aom_free(ctx->frame_workers);
149 0 : aom_free(ctx->buffer_pool);
150 0 : aom_free(ctx);
151 0 : return AOM_CODEC_OK;
152 : }
153 :
154 0 : static int parse_bitdepth_colorspace_sampling(BITSTREAM_PROFILE profile,
155 : struct aom_read_bit_buffer *rb) {
156 : aom_color_space_t color_space;
157 0 : if (profile >= PROFILE_2) rb->bit_offset += 1; // Bit-depth 10 or 12.
158 0 : color_space = (aom_color_space_t)aom_rb_read_literal(rb, 3);
159 0 : if (color_space != AOM_CS_SRGB) {
160 0 : rb->bit_offset += 1; // [16,235] (including xvycc) vs [0,255] range.
161 0 : if (profile == PROFILE_1 || profile == PROFILE_3) {
162 0 : rb->bit_offset += 2; // subsampling x/y.
163 0 : rb->bit_offset += 1; // unused.
164 : }
165 : } else {
166 0 : if (profile == PROFILE_1 || profile == PROFILE_3) {
167 0 : rb->bit_offset += 1; // unused
168 : } else {
169 : // RGB is only available in version 1.
170 0 : return 0;
171 : }
172 : }
173 0 : return 1;
174 : }
175 :
176 0 : static aom_codec_err_t decoder_peek_si_internal(
177 : const uint8_t *data, unsigned int data_sz, aom_codec_stream_info_t *si,
178 : int *is_intra_only, aom_decrypt_cb decrypt_cb, void *decrypt_state) {
179 0 : int intra_only_flag = 0;
180 : uint8_t clear_buffer[9];
181 :
182 0 : if (data + data_sz <= data) return AOM_CODEC_INVALID_PARAM;
183 :
184 0 : si->is_kf = 0;
185 0 : si->w = si->h = 0;
186 :
187 0 : if (decrypt_cb) {
188 0 : data_sz = AOMMIN(sizeof(clear_buffer), data_sz);
189 0 : decrypt_cb(decrypt_state, data, clear_buffer, data_sz);
190 0 : data = clear_buffer;
191 : }
192 :
193 : {
194 : int show_frame;
195 : int error_resilient;
196 0 : struct aom_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
197 0 : const int frame_marker = aom_rb_read_literal(&rb, 2);
198 0 : const BITSTREAM_PROFILE profile = av1_read_profile(&rb);
199 :
200 0 : if (frame_marker != AOM_FRAME_MARKER) return AOM_CODEC_UNSUP_BITSTREAM;
201 :
202 0 : if (profile >= MAX_PROFILES) return AOM_CODEC_UNSUP_BITSTREAM;
203 :
204 0 : if ((profile >= 2 && data_sz <= 1) || data_sz < 1)
205 0 : return AOM_CODEC_UNSUP_BITSTREAM;
206 :
207 0 : if (aom_rb_read_bit(&rb)) { // show an existing frame
208 0 : aom_rb_read_literal(&rb, 3); // Frame buffer to show.
209 0 : return AOM_CODEC_OK;
210 : }
211 :
212 0 : if (data_sz <= 8) return AOM_CODEC_UNSUP_BITSTREAM;
213 :
214 0 : si->is_kf = !aom_rb_read_bit(&rb);
215 0 : show_frame = aom_rb_read_bit(&rb);
216 0 : error_resilient = aom_rb_read_bit(&rb);
217 : #if CONFIG_REFERENCE_BUFFER
218 : {
219 : /* TODO: Move outside frame loop or inside key-frame branch */
220 : int frame_id_len;
221 : SequenceHeader seq_params;
222 0 : read_sequence_header(&seq_params);
223 0 : if (seq_params.frame_id_numbers_present_flag) {
224 0 : frame_id_len = seq_params.frame_id_length_minus7 + 7;
225 0 : aom_rb_read_literal(&rb, frame_id_len);
226 : }
227 : }
228 : #endif
229 0 : if (si->is_kf) {
230 0 : if (!av1_read_sync_code(&rb)) return AOM_CODEC_UNSUP_BITSTREAM;
231 :
232 0 : if (!parse_bitdepth_colorspace_sampling(profile, &rb))
233 0 : return AOM_CODEC_UNSUP_BITSTREAM;
234 0 : av1_read_frame_size(&rb, (int *)&si->w, (int *)&si->h);
235 : } else {
236 0 : intra_only_flag = show_frame ? 0 : aom_rb_read_bit(&rb);
237 :
238 0 : rb.bit_offset += error_resilient ? 0 : 2; // reset_frame_context
239 :
240 0 : if (intra_only_flag) {
241 0 : if (!av1_read_sync_code(&rb)) return AOM_CODEC_UNSUP_BITSTREAM;
242 0 : if (profile > PROFILE_0) {
243 0 : if (!parse_bitdepth_colorspace_sampling(profile, &rb))
244 0 : return AOM_CODEC_UNSUP_BITSTREAM;
245 : }
246 0 : rb.bit_offset += REF_FRAMES; // refresh_frame_flags
247 0 : av1_read_frame_size(&rb, (int *)&si->w, (int *)&si->h);
248 : }
249 : }
250 : }
251 0 : if (is_intra_only != NULL) *is_intra_only = intra_only_flag;
252 0 : return AOM_CODEC_OK;
253 : }
254 :
255 0 : static aom_codec_err_t decoder_peek_si(const uint8_t *data,
256 : unsigned int data_sz,
257 : aom_codec_stream_info_t *si) {
258 0 : return decoder_peek_si_internal(data, data_sz, si, NULL, NULL, NULL);
259 : }
260 :
261 0 : static aom_codec_err_t decoder_get_si(aom_codec_alg_priv_t *ctx,
262 : aom_codec_stream_info_t *si) {
263 0 : memcpy(si, &ctx->si, sizeof(*si));
264 :
265 0 : return AOM_CODEC_OK;
266 : }
267 :
268 0 : static void set_error_detail(aom_codec_alg_priv_t *ctx,
269 : const char *const error) {
270 0 : ctx->base.err_detail = error;
271 0 : }
272 :
273 0 : static aom_codec_err_t update_error_state(
274 : aom_codec_alg_priv_t *ctx, const struct aom_internal_error_info *error) {
275 0 : if (error->error_code)
276 0 : set_error_detail(ctx, error->has_detail ? error->detail : NULL);
277 :
278 0 : return error->error_code;
279 : }
280 :
281 0 : static void init_buffer_callbacks(aom_codec_alg_priv_t *ctx) {
282 : int i;
283 :
284 0 : for (i = 0; i < ctx->num_frame_workers; ++i) {
285 0 : AVxWorker *const worker = &ctx->frame_workers[i];
286 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
287 0 : AV1_COMMON *const cm = &frame_worker_data->pbi->common;
288 0 : BufferPool *const pool = cm->buffer_pool;
289 :
290 0 : cm->new_fb_idx = INVALID_IDX;
291 0 : cm->byte_alignment = ctx->byte_alignment;
292 0 : cm->skip_loop_filter = ctx->skip_loop_filter;
293 :
294 0 : if (ctx->get_ext_fb_cb != NULL && ctx->release_ext_fb_cb != NULL) {
295 0 : pool->get_fb_cb = ctx->get_ext_fb_cb;
296 0 : pool->release_fb_cb = ctx->release_ext_fb_cb;
297 0 : pool->cb_priv = ctx->ext_priv;
298 : } else {
299 0 : pool->get_fb_cb = av1_get_frame_buffer;
300 0 : pool->release_fb_cb = av1_release_frame_buffer;
301 :
302 0 : if (av1_alloc_internal_frame_buffers(&pool->int_frame_buffers))
303 0 : aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
304 : "Failed to initialize internal frame buffers");
305 :
306 0 : pool->cb_priv = &pool->int_frame_buffers;
307 : }
308 : }
309 0 : }
310 :
311 0 : static void set_default_ppflags(aom_postproc_cfg_t *cfg) {
312 0 : cfg->post_proc_flag = AOM_DEBLOCK | AOM_DEMACROBLOCK;
313 0 : cfg->deblocking_level = 4;
314 0 : cfg->noise_level = 0;
315 0 : }
316 :
317 0 : static int frame_worker_hook(void *arg1, void *arg2) {
318 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)arg1;
319 0 : const uint8_t *data = frame_worker_data->data;
320 : (void)arg2;
321 :
322 0 : frame_worker_data->result = av1_receive_compressed_data(
323 : frame_worker_data->pbi, frame_worker_data->data_size, &data);
324 0 : frame_worker_data->data_end = data;
325 :
326 0 : if (frame_worker_data->pbi->common.frame_parallel_decode) {
327 : // In frame parallel decoding, a worker thread must successfully decode all
328 : // the compressed data.
329 0 : if (frame_worker_data->result != 0 ||
330 0 : frame_worker_data->data + frame_worker_data->data_size - 1 > data) {
331 0 : AVxWorker *const worker = frame_worker_data->pbi->frame_worker_owner;
332 0 : BufferPool *const pool = frame_worker_data->pbi->common.buffer_pool;
333 : // Signal all the other threads that are waiting for this frame.
334 0 : av1_frameworker_lock_stats(worker);
335 0 : frame_worker_data->frame_context_ready = 1;
336 0 : lock_buffer_pool(pool);
337 0 : frame_worker_data->pbi->cur_buf->buf.corrupted = 1;
338 0 : unlock_buffer_pool(pool);
339 0 : frame_worker_data->pbi->need_resync = 1;
340 0 : av1_frameworker_signal_stats(worker);
341 0 : av1_frameworker_unlock_stats(worker);
342 0 : return 0;
343 : }
344 0 : } else if (frame_worker_data->result != 0) {
345 : // Check decode result in serial decode.
346 0 : frame_worker_data->pbi->cur_buf->buf.corrupted = 1;
347 0 : frame_worker_data->pbi->need_resync = 1;
348 : }
349 0 : return !frame_worker_data->result;
350 : }
351 :
352 0 : static aom_codec_err_t init_decoder(aom_codec_alg_priv_t *ctx) {
353 : int i;
354 0 : const AVxWorkerInterface *const winterface = aom_get_worker_interface();
355 :
356 0 : ctx->last_show_frame = -1;
357 0 : ctx->next_submit_worker_id = 0;
358 0 : ctx->last_submit_worker_id = 0;
359 0 : ctx->next_output_worker_id = 0;
360 0 : ctx->frame_cache_read = 0;
361 0 : ctx->frame_cache_write = 0;
362 0 : ctx->num_cache_frames = 0;
363 0 : ctx->need_resync = 1;
364 0 : ctx->num_frame_workers =
365 0 : (ctx->frame_parallel_decode == 1) ? ctx->cfg.threads : 1;
366 0 : if (ctx->num_frame_workers > MAX_DECODE_THREADS)
367 0 : ctx->num_frame_workers = MAX_DECODE_THREADS;
368 0 : ctx->available_threads = ctx->num_frame_workers;
369 0 : ctx->flushed = 0;
370 :
371 0 : ctx->buffer_pool = (BufferPool *)aom_calloc(1, sizeof(BufferPool));
372 0 : if (ctx->buffer_pool == NULL) return AOM_CODEC_MEM_ERROR;
373 :
374 : #if CONFIG_MULTITHREAD
375 0 : if (pthread_mutex_init(&ctx->buffer_pool->pool_mutex, NULL)) {
376 0 : set_error_detail(ctx, "Failed to allocate buffer pool mutex");
377 0 : return AOM_CODEC_MEM_ERROR;
378 : }
379 : #endif
380 :
381 0 : ctx->frame_workers = (AVxWorker *)aom_malloc(ctx->num_frame_workers *
382 : sizeof(*ctx->frame_workers));
383 0 : if (ctx->frame_workers == NULL) {
384 0 : set_error_detail(ctx, "Failed to allocate frame_workers");
385 0 : return AOM_CODEC_MEM_ERROR;
386 : }
387 :
388 0 : for (i = 0; i < ctx->num_frame_workers; ++i) {
389 0 : AVxWorker *const worker = &ctx->frame_workers[i];
390 0 : FrameWorkerData *frame_worker_data = NULL;
391 0 : winterface->init(worker);
392 0 : worker->data1 = aom_memalign(32, sizeof(FrameWorkerData));
393 0 : if (worker->data1 == NULL) {
394 0 : set_error_detail(ctx, "Failed to allocate frame_worker_data");
395 0 : return AOM_CODEC_MEM_ERROR;
396 : }
397 0 : frame_worker_data = (FrameWorkerData *)worker->data1;
398 0 : frame_worker_data->pbi = av1_decoder_create(ctx->buffer_pool);
399 0 : if (frame_worker_data->pbi == NULL) {
400 0 : set_error_detail(ctx, "Failed to allocate frame_worker_data");
401 0 : return AOM_CODEC_MEM_ERROR;
402 : }
403 0 : frame_worker_data->pbi->frame_worker_owner = worker;
404 0 : frame_worker_data->worker_id = i;
405 0 : frame_worker_data->scratch_buffer = NULL;
406 0 : frame_worker_data->scratch_buffer_size = 0;
407 0 : frame_worker_data->frame_context_ready = 0;
408 0 : frame_worker_data->received_frame = 0;
409 : #if CONFIG_MULTITHREAD
410 0 : if (pthread_mutex_init(&frame_worker_data->stats_mutex, NULL)) {
411 0 : set_error_detail(ctx, "Failed to allocate frame_worker_data mutex");
412 0 : return AOM_CODEC_MEM_ERROR;
413 : }
414 :
415 0 : if (pthread_cond_init(&frame_worker_data->stats_cond, NULL)) {
416 0 : set_error_detail(ctx, "Failed to allocate frame_worker_data cond");
417 0 : return AOM_CODEC_MEM_ERROR;
418 : }
419 : #endif
420 : // If decoding in serial mode, FrameWorker thread could create tile worker
421 : // thread or loopfilter thread.
422 0 : frame_worker_data->pbi->max_threads =
423 0 : (ctx->frame_parallel_decode == 0) ? ctx->cfg.threads : 0;
424 :
425 0 : frame_worker_data->pbi->inv_tile_order = ctx->invert_tile_order;
426 0 : frame_worker_data->pbi->common.frame_parallel_decode =
427 0 : ctx->frame_parallel_decode;
428 0 : worker->hook = (AVxWorkerHook)frame_worker_hook;
429 0 : if (!winterface->reset(worker)) {
430 0 : set_error_detail(ctx, "Frame Worker thread creation failed");
431 0 : return AOM_CODEC_MEM_ERROR;
432 : }
433 : }
434 :
435 : // If postprocessing was enabled by the application and a
436 : // configuration has not been provided, default it.
437 0 : if (!ctx->postproc_cfg_set && (ctx->base.init_flags & AOM_CODEC_USE_POSTPROC))
438 0 : set_default_ppflags(&ctx->postproc_cfg);
439 :
440 0 : init_buffer_callbacks(ctx);
441 :
442 0 : return AOM_CODEC_OK;
443 : }
444 :
445 0 : static INLINE void check_resync(aom_codec_alg_priv_t *const ctx,
446 : const AV1Decoder *const pbi) {
447 : // Clear resync flag if worker got a key frame or intra only frame.
448 0 : if (ctx->need_resync == 1 && pbi->need_resync == 0 &&
449 0 : (pbi->common.intra_only || pbi->common.frame_type == KEY_FRAME))
450 0 : ctx->need_resync = 0;
451 0 : }
452 :
453 0 : static aom_codec_err_t decode_one(aom_codec_alg_priv_t *ctx,
454 : const uint8_t **data, unsigned int data_sz,
455 : void *user_priv, int64_t deadline) {
456 0 : const AVxWorkerInterface *const winterface = aom_get_worker_interface();
457 : (void)deadline;
458 :
459 : // Determine the stream parameters. Note that we rely on peek_si to
460 : // validate that we have a buffer that does not wrap around the top
461 : // of the heap.
462 0 : if (!ctx->si.h) {
463 0 : int is_intra_only = 0;
464 0 : const aom_codec_err_t res =
465 0 : decoder_peek_si_internal(*data, data_sz, &ctx->si, &is_intra_only,
466 : ctx->decrypt_cb, ctx->decrypt_state);
467 0 : if (res != AOM_CODEC_OK) return res;
468 :
469 0 : if (!ctx->si.is_kf && !is_intra_only) return AOM_CODEC_ERROR;
470 : }
471 :
472 0 : if (!ctx->frame_parallel_decode) {
473 0 : AVxWorker *const worker = ctx->frame_workers;
474 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
475 0 : frame_worker_data->data = *data;
476 0 : frame_worker_data->data_size = data_sz;
477 0 : frame_worker_data->user_priv = user_priv;
478 0 : frame_worker_data->received_frame = 1;
479 :
480 : // Set these even if already initialized. The caller may have changed the
481 : // decrypt config between frames.
482 0 : frame_worker_data->pbi->decrypt_cb = ctx->decrypt_cb;
483 0 : frame_worker_data->pbi->decrypt_state = ctx->decrypt_state;
484 : #if CONFIG_INSPECTION
485 : frame_worker_data->pbi->inspect_cb = ctx->inspect_cb;
486 : frame_worker_data->pbi->inspect_ctx = ctx->inspect_ctx;
487 : #endif
488 :
489 : #if CONFIG_EXT_TILE
490 : frame_worker_data->pbi->dec_tile_row = ctx->decode_tile_row;
491 : frame_worker_data->pbi->dec_tile_col = ctx->decode_tile_col;
492 : #endif // CONFIG_EXT_TILE
493 :
494 0 : worker->had_error = 0;
495 0 : winterface->execute(worker);
496 :
497 : // Update data pointer after decode.
498 0 : *data = frame_worker_data->data_end;
499 :
500 0 : if (worker->had_error)
501 0 : return update_error_state(ctx, &frame_worker_data->pbi->common.error);
502 :
503 0 : check_resync(ctx, frame_worker_data->pbi);
504 : } else {
505 0 : AVxWorker *const worker = &ctx->frame_workers[ctx->next_submit_worker_id];
506 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
507 : // Copy context from last worker thread to next worker thread.
508 0 : if (ctx->next_submit_worker_id != ctx->last_submit_worker_id)
509 0 : av1_frameworker_copy_context(
510 0 : &ctx->frame_workers[ctx->next_submit_worker_id],
511 0 : &ctx->frame_workers[ctx->last_submit_worker_id]);
512 :
513 0 : frame_worker_data->pbi->ready_for_new_data = 0;
514 : // Copy the compressed data into worker's internal buffer.
515 : // TODO(hkuang): Will all the workers allocate the same size
516 : // as the size of the first intra frame be better? This will
517 : // avoid too many deallocate and allocate.
518 0 : if (frame_worker_data->scratch_buffer_size < data_sz) {
519 0 : aom_free(frame_worker_data->scratch_buffer);
520 0 : frame_worker_data->scratch_buffer = (uint8_t *)aom_malloc(data_sz);
521 0 : if (frame_worker_data->scratch_buffer == NULL) {
522 0 : set_error_detail(ctx, "Failed to reallocate scratch buffer");
523 0 : return AOM_CODEC_MEM_ERROR;
524 : }
525 0 : frame_worker_data->scratch_buffer_size = data_sz;
526 : }
527 0 : frame_worker_data->data_size = data_sz;
528 0 : memcpy(frame_worker_data->scratch_buffer, *data, data_sz);
529 :
530 0 : frame_worker_data->frame_decoded = 0;
531 0 : frame_worker_data->frame_context_ready = 0;
532 0 : frame_worker_data->received_frame = 1;
533 0 : frame_worker_data->data = frame_worker_data->scratch_buffer;
534 0 : frame_worker_data->user_priv = user_priv;
535 :
536 0 : if (ctx->next_submit_worker_id != ctx->last_submit_worker_id)
537 0 : ctx->last_submit_worker_id =
538 0 : (ctx->last_submit_worker_id + 1) % ctx->num_frame_workers;
539 :
540 0 : ctx->next_submit_worker_id =
541 0 : (ctx->next_submit_worker_id + 1) % ctx->num_frame_workers;
542 0 : --ctx->available_threads;
543 0 : worker->had_error = 0;
544 0 : winterface->launch(worker);
545 : }
546 :
547 0 : return AOM_CODEC_OK;
548 : }
549 :
550 0 : static void wait_worker_and_cache_frame(aom_codec_alg_priv_t *ctx) {
551 : YV12_BUFFER_CONFIG sd;
552 0 : const AVxWorkerInterface *const winterface = aom_get_worker_interface();
553 0 : AVxWorker *const worker = &ctx->frame_workers[ctx->next_output_worker_id];
554 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
555 0 : ctx->next_output_worker_id =
556 0 : (ctx->next_output_worker_id + 1) % ctx->num_frame_workers;
557 : // TODO(hkuang): Add worker error handling here.
558 0 : winterface->sync(worker);
559 0 : frame_worker_data->received_frame = 0;
560 0 : ++ctx->available_threads;
561 :
562 0 : check_resync(ctx, frame_worker_data->pbi);
563 :
564 0 : if (av1_get_raw_frame(frame_worker_data->pbi, &sd) == 0) {
565 0 : AV1_COMMON *const cm = &frame_worker_data->pbi->common;
566 0 : RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
567 0 : ctx->frame_cache[ctx->frame_cache_write].fb_idx = cm->new_fb_idx;
568 0 : yuvconfig2image(&ctx->frame_cache[ctx->frame_cache_write].img, &sd,
569 : frame_worker_data->user_priv);
570 0 : ctx->frame_cache[ctx->frame_cache_write].img.fb_priv =
571 0 : frame_bufs[cm->new_fb_idx].raw_frame_buffer.priv;
572 0 : ctx->frame_cache_write = (ctx->frame_cache_write + 1) % FRAME_CACHE_SIZE;
573 0 : ++ctx->num_cache_frames;
574 : }
575 0 : }
576 :
577 0 : static aom_codec_err_t decoder_decode(aom_codec_alg_priv_t *ctx,
578 : const uint8_t *data, unsigned int data_sz,
579 : void *user_priv, long deadline) {
580 0 : const uint8_t *data_start = data;
581 0 : const uint8_t *const data_end = data + data_sz;
582 : aom_codec_err_t res;
583 : uint32_t frame_sizes[8];
584 : int frame_count;
585 :
586 0 : if (data == NULL && data_sz == 0) {
587 0 : ctx->flushed = 1;
588 0 : return AOM_CODEC_OK;
589 : }
590 :
591 : // Reset flushed when receiving a valid frame.
592 0 : ctx->flushed = 0;
593 :
594 : // Initialize the decoder workers on the first frame.
595 0 : if (ctx->frame_workers == NULL) {
596 0 : res = init_decoder(ctx);
597 0 : if (res != AOM_CODEC_OK) return res;
598 : }
599 :
600 0 : res = av1_parse_superframe_index(data, data_sz, frame_sizes, &frame_count,
601 : ctx->decrypt_cb, ctx->decrypt_state);
602 0 : if (res != AOM_CODEC_OK) return res;
603 :
604 0 : if (ctx->frame_parallel_decode) {
605 : // Decode in frame parallel mode. When decoding in this mode, the frame
606 : // passed to the decoder must be either a normal frame or a superframe with
607 : // superframe index so the decoder could get each frame's start position
608 : // in the superframe.
609 0 : if (frame_count > 0) {
610 : int i;
611 :
612 0 : for (i = 0; i < frame_count; ++i) {
613 0 : const uint8_t *data_start_copy = data_start;
614 0 : const uint32_t frame_size = frame_sizes[i];
615 0 : if (data_start < data ||
616 0 : frame_size > (uint32_t)(data_end - data_start)) {
617 0 : set_error_detail(ctx, "Invalid frame size in index");
618 0 : return AOM_CODEC_CORRUPT_FRAME;
619 : }
620 :
621 0 : if (ctx->available_threads == 0) {
622 : // No more threads for decoding. Wait until the next output worker
623 : // finishes decoding. Then copy the decoded frame into cache.
624 0 : if (ctx->num_cache_frames < FRAME_CACHE_SIZE) {
625 0 : wait_worker_and_cache_frame(ctx);
626 : } else {
627 : // TODO(hkuang): Add unit test to test this path.
628 0 : set_error_detail(ctx, "Frame output cache is full.");
629 0 : return AOM_CODEC_ERROR;
630 : }
631 : }
632 :
633 0 : res =
634 : decode_one(ctx, &data_start_copy, frame_size, user_priv, deadline);
635 0 : if (res != AOM_CODEC_OK) return res;
636 0 : data_start += frame_size;
637 : }
638 : } else {
639 0 : if (ctx->available_threads == 0) {
640 : // No more threads for decoding. Wait until the next output worker
641 : // finishes decoding. Then copy the decoded frame into cache.
642 0 : if (ctx->num_cache_frames < FRAME_CACHE_SIZE) {
643 0 : wait_worker_and_cache_frame(ctx);
644 : } else {
645 : // TODO(hkuang): Add unit test to test this path.
646 0 : set_error_detail(ctx, "Frame output cache is full.");
647 0 : return AOM_CODEC_ERROR;
648 : }
649 : }
650 :
651 0 : res = decode_one(ctx, &data, data_sz, user_priv, deadline);
652 0 : if (res != AOM_CODEC_OK) return res;
653 : }
654 : } else {
655 : // Decode in serial mode.
656 0 : if (frame_count > 0) {
657 : int i;
658 :
659 0 : for (i = 0; i < frame_count; ++i) {
660 0 : const uint8_t *data_start_copy = data_start;
661 0 : const uint32_t frame_size = frame_sizes[i];
662 0 : if (data_start < data ||
663 0 : frame_size > (uint32_t)(data_end - data_start)) {
664 0 : set_error_detail(ctx, "Invalid frame size in index");
665 0 : return AOM_CODEC_CORRUPT_FRAME;
666 : }
667 :
668 0 : res =
669 : decode_one(ctx, &data_start_copy, frame_size, user_priv, deadline);
670 0 : if (res != AOM_CODEC_OK) return res;
671 :
672 0 : data_start += frame_size;
673 : }
674 : } else {
675 0 : while (data_start < data_end) {
676 0 : const uint32_t frame_size = (uint32_t)(data_end - data_start);
677 0 : res = decode_one(ctx, &data_start, frame_size, user_priv, deadline);
678 0 : if (res != AOM_CODEC_OK) return res;
679 :
680 : // Account for suboptimal termination by the encoder.
681 0 : while (data_start < data_end) {
682 0 : const uint8_t marker =
683 0 : read_marker(ctx->decrypt_cb, ctx->decrypt_state, data_start);
684 0 : if (marker) break;
685 0 : ++data_start;
686 : }
687 : }
688 : }
689 : }
690 :
691 0 : return res;
692 : }
693 :
694 0 : static void release_last_output_frame(aom_codec_alg_priv_t *ctx) {
695 0 : RefCntBuffer *const frame_bufs = ctx->buffer_pool->frame_bufs;
696 : // Decrease reference count of last output frame in frame parallel mode.
697 0 : if (ctx->frame_parallel_decode && ctx->last_show_frame >= 0) {
698 0 : BufferPool *const pool = ctx->buffer_pool;
699 0 : lock_buffer_pool(pool);
700 0 : decrease_ref_count(ctx->last_show_frame, frame_bufs, pool);
701 0 : unlock_buffer_pool(pool);
702 : }
703 0 : }
704 :
705 0 : static aom_image_t *decoder_get_frame(aom_codec_alg_priv_t *ctx,
706 : aom_codec_iter_t *iter) {
707 0 : aom_image_t *img = NULL;
708 :
709 : // Only return frame when all the cpu are busy or
710 : // application fluhsed the decoder in frame parallel decode.
711 0 : if (ctx->frame_parallel_decode && ctx->available_threads > 0 &&
712 0 : !ctx->flushed) {
713 0 : return NULL;
714 : }
715 :
716 : // Output the frames in the cache first.
717 0 : if (ctx->num_cache_frames > 0) {
718 0 : release_last_output_frame(ctx);
719 0 : ctx->last_show_frame = ctx->frame_cache[ctx->frame_cache_read].fb_idx;
720 0 : if (ctx->need_resync) return NULL;
721 0 : img = &ctx->frame_cache[ctx->frame_cache_read].img;
722 0 : ctx->frame_cache_read = (ctx->frame_cache_read + 1) % FRAME_CACHE_SIZE;
723 0 : --ctx->num_cache_frames;
724 0 : return img;
725 : }
726 :
727 : // iter acts as a flip flop, so an image is only returned on the first
728 : // call to get_frame.
729 0 : if (*iter == NULL && ctx->frame_workers != NULL) {
730 : do {
731 : YV12_BUFFER_CONFIG sd;
732 0 : const AVxWorkerInterface *const winterface = aom_get_worker_interface();
733 0 : AVxWorker *const worker = &ctx->frame_workers[ctx->next_output_worker_id];
734 0 : FrameWorkerData *const frame_worker_data =
735 : (FrameWorkerData *)worker->data1;
736 0 : ctx->next_output_worker_id =
737 0 : (ctx->next_output_worker_id + 1) % ctx->num_frame_workers;
738 : // Wait for the frame from worker thread.
739 0 : if (winterface->sync(worker)) {
740 : // Check if worker has received any frames.
741 0 : if (frame_worker_data->received_frame == 1) {
742 0 : ++ctx->available_threads;
743 0 : frame_worker_data->received_frame = 0;
744 0 : check_resync(ctx, frame_worker_data->pbi);
745 : }
746 0 : if (av1_get_raw_frame(frame_worker_data->pbi, &sd) == 0) {
747 0 : AV1_COMMON *const cm = &frame_worker_data->pbi->common;
748 0 : RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
749 0 : release_last_output_frame(ctx);
750 0 : ctx->last_show_frame = frame_worker_data->pbi->common.new_fb_idx;
751 0 : if (ctx->need_resync) return NULL;
752 0 : yuvconfig2image(&ctx->img, &sd, frame_worker_data->user_priv);
753 :
754 : #if CONFIG_EXT_TILE
755 : if (cm->tile_encoding_mode &&
756 : frame_worker_data->pbi->dec_tile_row >= 0) {
757 : const int tile_row =
758 : AOMMIN(frame_worker_data->pbi->dec_tile_row, cm->tile_rows - 1);
759 : const int mi_row = tile_row * cm->tile_height;
760 : const int ssy = ctx->img.y_chroma_shift;
761 : int plane;
762 : ctx->img.planes[0] += mi_row * MI_SIZE * ctx->img.stride[0];
763 : for (plane = 1; plane < MAX_MB_PLANE; ++plane) {
764 : ctx->img.planes[plane] +=
765 : mi_row * (MI_SIZE >> ssy) * ctx->img.stride[plane];
766 : }
767 : ctx->img.d_h =
768 : AOMMIN(cm->tile_height, cm->mi_rows - mi_row) * MI_SIZE;
769 : }
770 :
771 : if (cm->tile_encoding_mode &&
772 : frame_worker_data->pbi->dec_tile_col >= 0) {
773 : const int tile_col =
774 : AOMMIN(frame_worker_data->pbi->dec_tile_col, cm->tile_cols - 1);
775 : const int mi_col = tile_col * cm->tile_width;
776 : const int ssx = ctx->img.x_chroma_shift;
777 : int plane;
778 : ctx->img.planes[0] += mi_col * MI_SIZE;
779 : for (plane = 1; plane < MAX_MB_PLANE; ++plane) {
780 : ctx->img.planes[plane] += mi_col * (MI_SIZE >> ssx);
781 : }
782 : ctx->img.d_w =
783 : AOMMIN(cm->tile_width, cm->mi_cols - mi_col) * MI_SIZE;
784 : }
785 : #endif // CONFIG_EXT_TILE
786 :
787 0 : ctx->img.fb_priv = frame_bufs[cm->new_fb_idx].raw_frame_buffer.priv;
788 0 : img = &ctx->img;
789 0 : return img;
790 : }
791 : } else {
792 : // Decoding failed. Release the worker thread.
793 0 : frame_worker_data->received_frame = 0;
794 0 : ++ctx->available_threads;
795 0 : ctx->need_resync = 1;
796 0 : if (ctx->flushed != 1) return NULL;
797 : }
798 0 : } while (ctx->next_output_worker_id != ctx->next_submit_worker_id);
799 : }
800 0 : return NULL;
801 : }
802 :
803 0 : static aom_codec_err_t decoder_set_fb_fn(
804 : aom_codec_alg_priv_t *ctx, aom_get_frame_buffer_cb_fn_t cb_get,
805 : aom_release_frame_buffer_cb_fn_t cb_release, void *cb_priv) {
806 0 : if (cb_get == NULL || cb_release == NULL) {
807 0 : return AOM_CODEC_INVALID_PARAM;
808 0 : } else if (ctx->frame_workers == NULL) {
809 : // If the decoder has already been initialized, do not accept changes to
810 : // the frame buffer functions.
811 0 : ctx->get_ext_fb_cb = cb_get;
812 0 : ctx->release_ext_fb_cb = cb_release;
813 0 : ctx->ext_priv = cb_priv;
814 0 : return AOM_CODEC_OK;
815 : }
816 :
817 0 : return AOM_CODEC_ERROR;
818 : }
819 :
820 0 : static aom_codec_err_t ctrl_set_reference(aom_codec_alg_priv_t *ctx,
821 : va_list args) {
822 0 : aom_ref_frame_t *const data = va_arg(args, aom_ref_frame_t *);
823 :
824 : // Only support this function in serial decode.
825 0 : if (ctx->frame_parallel_decode) {
826 0 : set_error_detail(ctx, "Not supported in frame parallel decode");
827 0 : return AOM_CODEC_INCAPABLE;
828 : }
829 :
830 0 : if (data) {
831 0 : aom_ref_frame_t *const frame = (aom_ref_frame_t *)data;
832 : YV12_BUFFER_CONFIG sd;
833 0 : AVxWorker *const worker = ctx->frame_workers;
834 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
835 0 : image2yuvconfig(&frame->img, &sd);
836 0 : return av1_set_reference_dec(&frame_worker_data->pbi->common,
837 : ref_frame_to_av1_reframe(frame->frame_type),
838 : &sd);
839 : } else {
840 0 : return AOM_CODEC_INVALID_PARAM;
841 : }
842 : }
843 :
844 0 : static aom_codec_err_t ctrl_copy_reference(aom_codec_alg_priv_t *ctx,
845 : va_list args) {
846 0 : const aom_ref_frame_t *const frame = va_arg(args, aom_ref_frame_t *);
847 :
848 : // Only support this function in serial decode.
849 0 : if (ctx->frame_parallel_decode) {
850 0 : set_error_detail(ctx, "Not supported in frame parallel decode");
851 0 : return AOM_CODEC_INCAPABLE;
852 : }
853 :
854 0 : if (frame) {
855 : YV12_BUFFER_CONFIG sd;
856 0 : AVxWorker *const worker = ctx->frame_workers;
857 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
858 0 : image2yuvconfig(&frame->img, &sd);
859 0 : return av1_copy_reference_dec(frame_worker_data->pbi,
860 0 : (AOM_REFFRAME)frame->frame_type, &sd);
861 : } else {
862 0 : return AOM_CODEC_INVALID_PARAM;
863 : }
864 : }
865 :
866 0 : static aom_codec_err_t ctrl_get_reference(aom_codec_alg_priv_t *ctx,
867 : va_list args) {
868 0 : av1_ref_frame_t *data = va_arg(args, av1_ref_frame_t *);
869 :
870 : // Only support this function in serial decode.
871 0 : if (ctx->frame_parallel_decode) {
872 0 : set_error_detail(ctx, "Not supported in frame parallel decode");
873 0 : return AOM_CODEC_INCAPABLE;
874 : }
875 :
876 0 : if (data) {
877 : YV12_BUFFER_CONFIG *fb;
878 0 : AVxWorker *const worker = ctx->frame_workers;
879 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
880 0 : fb = get_ref_frame(&frame_worker_data->pbi->common, data->idx);
881 0 : if (fb == NULL) return AOM_CODEC_ERROR;
882 0 : yuvconfig2image(&data->img, fb, NULL);
883 0 : return AOM_CODEC_OK;
884 : } else {
885 0 : return AOM_CODEC_INVALID_PARAM;
886 : }
887 : }
888 :
889 0 : static aom_codec_err_t ctrl_get_new_frame_image(aom_codec_alg_priv_t *ctx,
890 : va_list args) {
891 0 : aom_image_t *new_img = va_arg(args, aom_image_t *);
892 :
893 : // Only support this function in serial decode.
894 0 : if (ctx->frame_parallel_decode) {
895 0 : set_error_detail(ctx, "Not supported in frame parallel decode");
896 0 : return AOM_CODEC_INCAPABLE;
897 : }
898 :
899 0 : if (new_img) {
900 : YV12_BUFFER_CONFIG new_frame;
901 0 : AVxWorker *const worker = ctx->frame_workers;
902 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
903 :
904 0 : if (av1_get_frame_to_show(frame_worker_data->pbi, &new_frame) == 0) {
905 0 : yuvconfig2image(new_img, &new_frame, NULL);
906 0 : return AOM_CODEC_OK;
907 : } else {
908 0 : return AOM_CODEC_ERROR;
909 : }
910 : } else {
911 0 : return AOM_CODEC_INVALID_PARAM;
912 : }
913 : }
914 :
915 0 : static aom_codec_err_t ctrl_set_postproc(aom_codec_alg_priv_t *ctx,
916 : va_list args) {
917 : (void)ctx;
918 : (void)args;
919 0 : return AOM_CODEC_INCAPABLE;
920 : }
921 :
922 0 : static aom_codec_err_t ctrl_set_dbg_options(aom_codec_alg_priv_t *ctx,
923 : va_list args) {
924 : (void)ctx;
925 : (void)args;
926 0 : return AOM_CODEC_INCAPABLE;
927 : }
928 :
929 0 : static aom_codec_err_t ctrl_get_last_ref_updates(aom_codec_alg_priv_t *ctx,
930 : va_list args) {
931 0 : int *const update_info = va_arg(args, int *);
932 :
933 : // Only support this function in serial decode.
934 0 : if (ctx->frame_parallel_decode) {
935 0 : set_error_detail(ctx, "Not supported in frame parallel decode");
936 0 : return AOM_CODEC_INCAPABLE;
937 : }
938 :
939 0 : if (update_info) {
940 0 : if (ctx->frame_workers) {
941 0 : AVxWorker *const worker = ctx->frame_workers;
942 0 : FrameWorkerData *const frame_worker_data =
943 : (FrameWorkerData *)worker->data1;
944 0 : *update_info = frame_worker_data->pbi->refresh_frame_flags;
945 0 : return AOM_CODEC_OK;
946 : } else {
947 0 : return AOM_CODEC_ERROR;
948 : }
949 : }
950 :
951 0 : return AOM_CODEC_INVALID_PARAM;
952 : }
953 :
954 0 : static aom_codec_err_t ctrl_get_last_quantizer(aom_codec_alg_priv_t *ctx,
955 : va_list args) {
956 0 : int *const arg = va_arg(args, int *);
957 0 : if (arg == NULL) return AOM_CODEC_INVALID_PARAM;
958 0 : *arg =
959 0 : ((FrameWorkerData *)ctx->frame_workers[0].data1)->pbi->common.base_qindex;
960 0 : return AOM_CODEC_OK;
961 : }
962 :
963 0 : static aom_codec_err_t ctrl_get_frame_corrupted(aom_codec_alg_priv_t *ctx,
964 : va_list args) {
965 0 : int *corrupted = va_arg(args, int *);
966 :
967 0 : if (corrupted) {
968 0 : if (ctx->frame_workers) {
969 0 : AVxWorker *const worker = ctx->frame_workers;
970 0 : FrameWorkerData *const frame_worker_data =
971 : (FrameWorkerData *)worker->data1;
972 0 : RefCntBuffer *const frame_bufs =
973 0 : frame_worker_data->pbi->common.buffer_pool->frame_bufs;
974 0 : if (frame_worker_data->pbi->common.frame_to_show == NULL)
975 0 : return AOM_CODEC_ERROR;
976 0 : if (ctx->last_show_frame >= 0)
977 0 : *corrupted = frame_bufs[ctx->last_show_frame].buf.corrupted;
978 0 : return AOM_CODEC_OK;
979 : } else {
980 0 : return AOM_CODEC_ERROR;
981 : }
982 : }
983 :
984 0 : return AOM_CODEC_INVALID_PARAM;
985 : }
986 :
987 0 : static aom_codec_err_t ctrl_get_frame_size(aom_codec_alg_priv_t *ctx,
988 : va_list args) {
989 0 : int *const frame_size = va_arg(args, int *);
990 :
991 : // Only support this function in serial decode.
992 0 : if (ctx->frame_parallel_decode) {
993 0 : set_error_detail(ctx, "Not supported in frame parallel decode");
994 0 : return AOM_CODEC_INCAPABLE;
995 : }
996 :
997 0 : if (frame_size) {
998 0 : if (ctx->frame_workers) {
999 0 : AVxWorker *const worker = ctx->frame_workers;
1000 0 : FrameWorkerData *const frame_worker_data =
1001 : (FrameWorkerData *)worker->data1;
1002 0 : const AV1_COMMON *const cm = &frame_worker_data->pbi->common;
1003 0 : frame_size[0] = cm->width;
1004 0 : frame_size[1] = cm->height;
1005 0 : return AOM_CODEC_OK;
1006 : } else {
1007 0 : return AOM_CODEC_ERROR;
1008 : }
1009 : }
1010 :
1011 0 : return AOM_CODEC_INVALID_PARAM;
1012 : }
1013 :
1014 0 : static aom_codec_err_t ctrl_get_render_size(aom_codec_alg_priv_t *ctx,
1015 : va_list args) {
1016 0 : int *const render_size = va_arg(args, int *);
1017 :
1018 : // Only support this function in serial decode.
1019 0 : if (ctx->frame_parallel_decode) {
1020 0 : set_error_detail(ctx, "Not supported in frame parallel decode");
1021 0 : return AOM_CODEC_INCAPABLE;
1022 : }
1023 :
1024 0 : if (render_size) {
1025 0 : if (ctx->frame_workers) {
1026 0 : AVxWorker *const worker = ctx->frame_workers;
1027 0 : FrameWorkerData *const frame_worker_data =
1028 : (FrameWorkerData *)worker->data1;
1029 0 : const AV1_COMMON *const cm = &frame_worker_data->pbi->common;
1030 0 : render_size[0] = cm->render_width;
1031 0 : render_size[1] = cm->render_height;
1032 0 : return AOM_CODEC_OK;
1033 : } else {
1034 0 : return AOM_CODEC_ERROR;
1035 : }
1036 : }
1037 :
1038 0 : return AOM_CODEC_INVALID_PARAM;
1039 : }
1040 :
1041 0 : static aom_codec_err_t ctrl_get_bit_depth(aom_codec_alg_priv_t *ctx,
1042 : va_list args) {
1043 0 : unsigned int *const bit_depth = va_arg(args, unsigned int *);
1044 0 : AVxWorker *const worker = &ctx->frame_workers[ctx->next_output_worker_id];
1045 :
1046 0 : if (bit_depth) {
1047 0 : if (worker) {
1048 0 : FrameWorkerData *const frame_worker_data =
1049 : (FrameWorkerData *)worker->data1;
1050 0 : const AV1_COMMON *const cm = &frame_worker_data->pbi->common;
1051 0 : *bit_depth = cm->bit_depth;
1052 0 : return AOM_CODEC_OK;
1053 : } else {
1054 0 : return AOM_CODEC_ERROR;
1055 : }
1056 : }
1057 :
1058 0 : return AOM_CODEC_INVALID_PARAM;
1059 : }
1060 :
1061 0 : static aom_codec_err_t ctrl_set_invert_tile_order(aom_codec_alg_priv_t *ctx,
1062 : va_list args) {
1063 0 : ctx->invert_tile_order = va_arg(args, int);
1064 0 : return AOM_CODEC_OK;
1065 : }
1066 :
1067 0 : static aom_codec_err_t ctrl_set_decryptor(aom_codec_alg_priv_t *ctx,
1068 : va_list args) {
1069 0 : aom_decrypt_init *init = va_arg(args, aom_decrypt_init *);
1070 0 : ctx->decrypt_cb = init ? init->decrypt_cb : NULL;
1071 0 : ctx->decrypt_state = init ? init->decrypt_state : NULL;
1072 0 : return AOM_CODEC_OK;
1073 : }
1074 :
1075 0 : static aom_codec_err_t ctrl_set_byte_alignment(aom_codec_alg_priv_t *ctx,
1076 : va_list args) {
1077 0 : const int legacy_byte_alignment = 0;
1078 0 : const int min_byte_alignment = 32;
1079 0 : const int max_byte_alignment = 1024;
1080 0 : const int byte_alignment = va_arg(args, int);
1081 :
1082 0 : if (byte_alignment != legacy_byte_alignment &&
1083 0 : (byte_alignment < min_byte_alignment ||
1084 0 : byte_alignment > max_byte_alignment ||
1085 0 : (byte_alignment & (byte_alignment - 1)) != 0))
1086 0 : return AOM_CODEC_INVALID_PARAM;
1087 :
1088 0 : ctx->byte_alignment = byte_alignment;
1089 0 : if (ctx->frame_workers) {
1090 0 : AVxWorker *const worker = ctx->frame_workers;
1091 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
1092 0 : frame_worker_data->pbi->common.byte_alignment = byte_alignment;
1093 : }
1094 0 : return AOM_CODEC_OK;
1095 : }
1096 :
1097 0 : static aom_codec_err_t ctrl_set_skip_loop_filter(aom_codec_alg_priv_t *ctx,
1098 : va_list args) {
1099 0 : ctx->skip_loop_filter = va_arg(args, int);
1100 :
1101 0 : if (ctx->frame_workers) {
1102 0 : AVxWorker *const worker = ctx->frame_workers;
1103 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
1104 0 : frame_worker_data->pbi->common.skip_loop_filter = ctx->skip_loop_filter;
1105 : }
1106 :
1107 0 : return AOM_CODEC_OK;
1108 : }
1109 :
1110 0 : static aom_codec_err_t ctrl_get_accounting(aom_codec_alg_priv_t *ctx,
1111 : va_list args) {
1112 : #if !CONFIG_ACCOUNTING
1113 : (void)ctx;
1114 : (void)args;
1115 0 : return AOM_CODEC_INCAPABLE;
1116 : #else
1117 : if (ctx->frame_workers) {
1118 : AVxWorker *const worker = ctx->frame_workers;
1119 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
1120 : AV1Decoder *pbi = frame_worker_data->pbi;
1121 : Accounting **acct = va_arg(args, Accounting **);
1122 : *acct = &pbi->accounting;
1123 : return AOM_CODEC_OK;
1124 : }
1125 : return AOM_CODEC_ERROR;
1126 : #endif
1127 : }
1128 0 : static aom_codec_err_t ctrl_set_decode_tile_row(aom_codec_alg_priv_t *ctx,
1129 : va_list args) {
1130 0 : ctx->decode_tile_row = va_arg(args, int);
1131 0 : return AOM_CODEC_OK;
1132 : }
1133 :
1134 0 : static aom_codec_err_t ctrl_set_decode_tile_col(aom_codec_alg_priv_t *ctx,
1135 : va_list args) {
1136 0 : ctx->decode_tile_col = va_arg(args, int);
1137 0 : return AOM_CODEC_OK;
1138 : }
1139 :
1140 0 : static aom_codec_err_t ctrl_set_inspection_callback(aom_codec_alg_priv_t *ctx,
1141 : va_list args) {
1142 : #if !CONFIG_INSPECTION
1143 : (void)ctx;
1144 : (void)args;
1145 0 : return AOM_CODEC_INCAPABLE;
1146 : #else
1147 : aom_inspect_init *init = va_arg(args, aom_inspect_init *);
1148 : ctx->inspect_cb = init->inspect_cb;
1149 : ctx->inspect_ctx = init->inspect_ctx;
1150 : return AOM_CODEC_OK;
1151 : #endif
1152 : }
1153 :
1154 : static aom_codec_ctrl_fn_map_t decoder_ctrl_maps[] = {
1155 : { AOM_COPY_REFERENCE, ctrl_copy_reference },
1156 :
1157 : // Setters
1158 : { AOM_SET_REFERENCE, ctrl_set_reference },
1159 : { AOM_SET_POSTPROC, ctrl_set_postproc },
1160 : { AOM_SET_DBG_COLOR_REF_FRAME, ctrl_set_dbg_options },
1161 : { AOM_SET_DBG_COLOR_MB_MODES, ctrl_set_dbg_options },
1162 : { AOM_SET_DBG_COLOR_B_MODES, ctrl_set_dbg_options },
1163 : { AOM_SET_DBG_DISPLAY_MV, ctrl_set_dbg_options },
1164 : { AV1_INVERT_TILE_DECODE_ORDER, ctrl_set_invert_tile_order },
1165 : { AOMD_SET_DECRYPTOR, ctrl_set_decryptor },
1166 : { AV1_SET_BYTE_ALIGNMENT, ctrl_set_byte_alignment },
1167 : { AV1_SET_SKIP_LOOP_FILTER, ctrl_set_skip_loop_filter },
1168 : { AV1_SET_DECODE_TILE_ROW, ctrl_set_decode_tile_row },
1169 : { AV1_SET_DECODE_TILE_COL, ctrl_set_decode_tile_col },
1170 : { AV1_SET_INSPECTION_CALLBACK, ctrl_set_inspection_callback },
1171 :
1172 : // Getters
1173 : { AOMD_GET_FRAME_CORRUPTED, ctrl_get_frame_corrupted },
1174 : { AOMD_GET_LAST_QUANTIZER, ctrl_get_last_quantizer },
1175 : { AOMD_GET_LAST_REF_UPDATES, ctrl_get_last_ref_updates },
1176 : { AV1D_GET_BIT_DEPTH, ctrl_get_bit_depth },
1177 : { AV1D_GET_DISPLAY_SIZE, ctrl_get_render_size },
1178 : { AV1D_GET_FRAME_SIZE, ctrl_get_frame_size },
1179 : { AV1_GET_ACCOUNTING, ctrl_get_accounting },
1180 : { AV1_GET_NEW_FRAME_IMAGE, ctrl_get_new_frame_image },
1181 : { AV1_GET_REFERENCE, ctrl_get_reference },
1182 :
1183 : { -1, NULL },
1184 : };
1185 :
1186 : #ifndef VERSION_STRING
1187 : #define VERSION_STRING
1188 : #endif
1189 0 : CODEC_INTERFACE(aom_codec_av1_dx) = {
1190 : "AOMedia Project AV1 Decoder" VERSION_STRING,
1191 : AOM_CODEC_INTERNAL_ABI_VERSION,
1192 : AOM_CODEC_CAP_DECODER |
1193 : AOM_CODEC_CAP_EXTERNAL_FRAME_BUFFER, // aom_codec_caps_t
1194 : decoder_init, // aom_codec_init_fn_t
1195 : decoder_destroy, // aom_codec_destroy_fn_t
1196 : decoder_ctrl_maps, // aom_codec_ctrl_fn_map_t
1197 : {
1198 : // NOLINT
1199 : decoder_peek_si, // aom_codec_peek_si_fn_t
1200 : decoder_get_si, // aom_codec_get_si_fn_t
1201 : decoder_decode, // aom_codec_decode_fn_t
1202 : decoder_get_frame, // aom_codec_frame_get_fn_t
1203 : decoder_set_fb_fn, // aom_codec_set_fb_fn_t
1204 : },
1205 : {
1206 : // NOLINT
1207 : 0,
1208 : NULL, // aom_codec_enc_cfg_map_t
1209 : NULL, // aom_codec_encode_fn_t
1210 : NULL, // aom_codec_get_cx_data_fn_t
1211 : NULL, // aom_codec_enc_config_set_fn_t
1212 : NULL, // aom_codec_get_global_headers_fn_t
1213 : NULL, // aom_codec_get_preview_frame_fn_t
1214 : NULL // aom_codec_enc_mr_get_mem_loc_fn_t
1215 : }
1216 : };
|