LCOV - code coverage report
Current view: top level - third_party/aom/av1 - av1_dx_iface.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 575 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 40 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13