Line data Source code
1 : /*
2 : * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3 : *
4 : * Use of this source code is governed by a BSD-style license
5 : * that can be found in the LICENSE file in the root of the source
6 : * tree. An additional intellectual property rights grant can be found
7 : * in the file PATENTS. All contributing project authors may
8 : * be found in the AUTHORS file in the root of the source tree.
9 : */
10 :
11 : #include <stdlib.h>
12 : #include <string.h>
13 :
14 : #include "./vpx_config.h"
15 : #include "./vpx_version.h"
16 :
17 : #include "vpx/internal/vpx_codec_internal.h"
18 : #include "vpx/vp8dx.h"
19 : #include "vpx/vpx_decoder.h"
20 : #include "vpx_dsp/bitreader_buffer.h"
21 : #include "vpx_dsp/vpx_dsp_common.h"
22 : #include "vpx_util/vpx_thread.h"
23 :
24 : #include "vp9/common/vp9_alloccommon.h"
25 : #include "vp9/common/vp9_frame_buffers.h"
26 :
27 : #include "vp9/decoder/vp9_decodeframe.h"
28 :
29 : #include "vp9/vp9_dx_iface.h"
30 : #include "vp9/vp9_iface_common.h"
31 :
32 : #define VP9_CAP_POSTPROC (CONFIG_VP9_POSTPROC ? VPX_CODEC_CAP_POSTPROC : 0)
33 :
34 0 : static vpx_codec_err_t decoder_init(vpx_codec_ctx_t *ctx,
35 : vpx_codec_priv_enc_mr_cfg_t *data) {
36 : // This function only allocates space for the vpx_codec_alg_priv_t
37 : // structure. More memory may be required at the time the stream
38 : // information becomes known.
39 : (void)data;
40 :
41 0 : if (!ctx->priv) {
42 0 : vpx_codec_alg_priv_t *const priv =
43 : (vpx_codec_alg_priv_t *)vpx_calloc(1, sizeof(*priv));
44 0 : if (priv == NULL) return VPX_CODEC_MEM_ERROR;
45 :
46 0 : ctx->priv = (vpx_codec_priv_t *)priv;
47 0 : ctx->priv->init_flags = ctx->init_flags;
48 0 : priv->si.sz = sizeof(priv->si);
49 0 : priv->flushed = 0;
50 : // Only do frame parallel decode when threads > 1.
51 0 : priv->frame_parallel_decode =
52 0 : (ctx->config.dec && (ctx->config.dec->threads > 1) &&
53 0 : (ctx->init_flags & VPX_CODEC_USE_FRAME_THREADING))
54 : ? 1
55 0 : : 0;
56 0 : if (ctx->config.dec) {
57 0 : priv->cfg = *ctx->config.dec;
58 0 : ctx->config.dec = &priv->cfg;
59 : }
60 : }
61 :
62 0 : return VPX_CODEC_OK;
63 : }
64 :
65 0 : static vpx_codec_err_t decoder_destroy(vpx_codec_alg_priv_t *ctx) {
66 0 : if (ctx->frame_workers != NULL) {
67 : int i;
68 : // Shutdown all threads before reclaiming any memory. The frame-level
69 : // parallel decoder may access data from another worker.
70 0 : for (i = 0; i < ctx->num_frame_workers; ++i) {
71 0 : VPxWorker *const worker = &ctx->frame_workers[i];
72 0 : vpx_get_worker_interface()->end(worker);
73 : }
74 0 : for (i = 0; i < ctx->num_frame_workers; ++i) {
75 0 : VPxWorker *const worker = &ctx->frame_workers[i];
76 0 : FrameWorkerData *const frame_worker_data =
77 : (FrameWorkerData *)worker->data1;
78 0 : vp9_remove_common(&frame_worker_data->pbi->common);
79 : #if CONFIG_VP9_POSTPROC
80 0 : vp9_free_postproc_buffers(&frame_worker_data->pbi->common);
81 : #endif
82 0 : vp9_decoder_remove(frame_worker_data->pbi);
83 0 : vpx_free(frame_worker_data->scratch_buffer);
84 : #if CONFIG_MULTITHREAD
85 0 : pthread_mutex_destroy(&frame_worker_data->stats_mutex);
86 0 : pthread_cond_destroy(&frame_worker_data->stats_cond);
87 : #endif
88 0 : vpx_free(frame_worker_data);
89 : }
90 : #if CONFIG_MULTITHREAD
91 0 : pthread_mutex_destroy(&ctx->buffer_pool->pool_mutex);
92 : #endif
93 : }
94 :
95 0 : if (ctx->buffer_pool) {
96 0 : vp9_free_ref_frame_buffers(ctx->buffer_pool);
97 0 : vp9_free_internal_frame_buffers(&ctx->buffer_pool->int_frame_buffers);
98 : }
99 :
100 0 : vpx_free(ctx->frame_workers);
101 0 : vpx_free(ctx->buffer_pool);
102 0 : vpx_free(ctx);
103 0 : return VPX_CODEC_OK;
104 : }
105 :
106 0 : static int parse_bitdepth_colorspace_sampling(BITSTREAM_PROFILE profile,
107 : struct vpx_read_bit_buffer *rb) {
108 : vpx_color_space_t color_space;
109 0 : if (profile >= PROFILE_2) rb->bit_offset += 1; // Bit-depth 10 or 12.
110 0 : color_space = (vpx_color_space_t)vpx_rb_read_literal(rb, 3);
111 0 : if (color_space != VPX_CS_SRGB) {
112 0 : rb->bit_offset += 1; // [16,235] (including xvycc) vs [0,255] range.
113 0 : if (profile == PROFILE_1 || profile == PROFILE_3) {
114 0 : rb->bit_offset += 2; // subsampling x/y.
115 0 : rb->bit_offset += 1; // unused.
116 : }
117 : } else {
118 0 : if (profile == PROFILE_1 || profile == PROFILE_3) {
119 0 : rb->bit_offset += 1; // unused
120 : } else {
121 : // RGB is only available in version 1.
122 0 : return 0;
123 : }
124 : }
125 0 : return 1;
126 : }
127 :
128 0 : static vpx_codec_err_t decoder_peek_si_internal(
129 : const uint8_t *data, unsigned int data_sz, vpx_codec_stream_info_t *si,
130 : int *is_intra_only, vpx_decrypt_cb decrypt_cb, void *decrypt_state) {
131 0 : int intra_only_flag = 0;
132 : uint8_t clear_buffer[10];
133 :
134 0 : if (data + data_sz <= data) return VPX_CODEC_INVALID_PARAM;
135 :
136 0 : si->is_kf = 0;
137 0 : si->w = si->h = 0;
138 :
139 0 : if (decrypt_cb) {
140 0 : data_sz = VPXMIN(sizeof(clear_buffer), data_sz);
141 0 : decrypt_cb(decrypt_state, data, clear_buffer, data_sz);
142 0 : data = clear_buffer;
143 : }
144 :
145 : // A maximum of 6 bits are needed to read the frame marker, profile and
146 : // show_existing_frame.
147 0 : if (data_sz < 1) return VPX_CODEC_UNSUP_BITSTREAM;
148 :
149 : {
150 : int show_frame;
151 : int error_resilient;
152 0 : struct vpx_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
153 0 : const int frame_marker = vpx_rb_read_literal(&rb, 2);
154 0 : const BITSTREAM_PROFILE profile = vp9_read_profile(&rb);
155 :
156 0 : if (frame_marker != VP9_FRAME_MARKER) return VPX_CODEC_UNSUP_BITSTREAM;
157 :
158 0 : if (profile >= MAX_PROFILES) return VPX_CODEC_UNSUP_BITSTREAM;
159 :
160 0 : if (vpx_rb_read_bit(&rb)) { // show an existing frame
161 : // If profile is > 2 and show_existing_frame is true, then at least 1 more
162 : // byte (6+3=9 bits) is needed.
163 0 : if (profile > 2 && data_sz < 2) return VPX_CODEC_UNSUP_BITSTREAM;
164 0 : vpx_rb_read_literal(&rb, 3); // Frame buffer to show.
165 0 : return VPX_CODEC_OK;
166 : }
167 :
168 : // For the rest of the function, a maximum of 9 more bytes are needed
169 : // (computed by taking the maximum possible bits needed in each case). Note
170 : // that this has to be updated if we read any more bits in this function.
171 0 : if (data_sz < 10) return VPX_CODEC_UNSUP_BITSTREAM;
172 :
173 0 : si->is_kf = !vpx_rb_read_bit(&rb);
174 0 : show_frame = vpx_rb_read_bit(&rb);
175 0 : error_resilient = vpx_rb_read_bit(&rb);
176 :
177 0 : if (si->is_kf) {
178 0 : if (!vp9_read_sync_code(&rb)) return VPX_CODEC_UNSUP_BITSTREAM;
179 :
180 0 : if (!parse_bitdepth_colorspace_sampling(profile, &rb))
181 0 : return VPX_CODEC_UNSUP_BITSTREAM;
182 0 : vp9_read_frame_size(&rb, (int *)&si->w, (int *)&si->h);
183 : } else {
184 0 : intra_only_flag = show_frame ? 0 : vpx_rb_read_bit(&rb);
185 :
186 0 : rb.bit_offset += error_resilient ? 0 : 2; // reset_frame_context
187 :
188 0 : if (intra_only_flag) {
189 0 : if (!vp9_read_sync_code(&rb)) return VPX_CODEC_UNSUP_BITSTREAM;
190 0 : if (profile > PROFILE_0) {
191 0 : if (!parse_bitdepth_colorspace_sampling(profile, &rb))
192 0 : return VPX_CODEC_UNSUP_BITSTREAM;
193 : }
194 0 : rb.bit_offset += REF_FRAMES; // refresh_frame_flags
195 0 : vp9_read_frame_size(&rb, (int *)&si->w, (int *)&si->h);
196 : }
197 : }
198 : }
199 0 : if (is_intra_only != NULL) *is_intra_only = intra_only_flag;
200 0 : return VPX_CODEC_OK;
201 : }
202 :
203 0 : static vpx_codec_err_t decoder_peek_si(const uint8_t *data,
204 : unsigned int data_sz,
205 : vpx_codec_stream_info_t *si) {
206 0 : return decoder_peek_si_internal(data, data_sz, si, NULL, NULL, NULL);
207 : }
208 :
209 0 : static vpx_codec_err_t decoder_get_si(vpx_codec_alg_priv_t *ctx,
210 : vpx_codec_stream_info_t *si) {
211 0 : const size_t sz = (si->sz >= sizeof(vp9_stream_info_t))
212 : ? sizeof(vp9_stream_info_t)
213 : : sizeof(vpx_codec_stream_info_t);
214 0 : memcpy(si, &ctx->si, sz);
215 0 : si->sz = (unsigned int)sz;
216 :
217 0 : return VPX_CODEC_OK;
218 : }
219 :
220 0 : static void set_error_detail(vpx_codec_alg_priv_t *ctx,
221 : const char *const error) {
222 0 : ctx->base.err_detail = error;
223 0 : }
224 :
225 0 : static vpx_codec_err_t update_error_state(
226 : vpx_codec_alg_priv_t *ctx, const struct vpx_internal_error_info *error) {
227 0 : if (error->error_code)
228 0 : set_error_detail(ctx, error->has_detail ? error->detail : NULL);
229 :
230 0 : return error->error_code;
231 : }
232 :
233 0 : static void init_buffer_callbacks(vpx_codec_alg_priv_t *ctx) {
234 : int i;
235 :
236 0 : for (i = 0; i < ctx->num_frame_workers; ++i) {
237 0 : VPxWorker *const worker = &ctx->frame_workers[i];
238 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
239 0 : VP9_COMMON *const cm = &frame_worker_data->pbi->common;
240 0 : BufferPool *const pool = cm->buffer_pool;
241 :
242 0 : cm->new_fb_idx = INVALID_IDX;
243 0 : cm->byte_alignment = ctx->byte_alignment;
244 0 : cm->skip_loop_filter = ctx->skip_loop_filter;
245 :
246 0 : if (ctx->get_ext_fb_cb != NULL && ctx->release_ext_fb_cb != NULL) {
247 0 : pool->get_fb_cb = ctx->get_ext_fb_cb;
248 0 : pool->release_fb_cb = ctx->release_ext_fb_cb;
249 0 : pool->cb_priv = ctx->ext_priv;
250 : } else {
251 0 : pool->get_fb_cb = vp9_get_frame_buffer;
252 0 : pool->release_fb_cb = vp9_release_frame_buffer;
253 :
254 0 : if (vp9_alloc_internal_frame_buffers(&pool->int_frame_buffers))
255 0 : vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
256 : "Failed to initialize internal frame buffers");
257 :
258 0 : pool->cb_priv = &pool->int_frame_buffers;
259 : }
260 : }
261 0 : }
262 :
263 0 : static void set_default_ppflags(vp8_postproc_cfg_t *cfg) {
264 0 : cfg->post_proc_flag = VP8_DEBLOCK | VP8_DEMACROBLOCK;
265 0 : cfg->deblocking_level = 4;
266 0 : cfg->noise_level = 0;
267 0 : }
268 :
269 0 : static void set_ppflags(const vpx_codec_alg_priv_t *ctx, vp9_ppflags_t *flags) {
270 0 : flags->post_proc_flag = ctx->postproc_cfg.post_proc_flag;
271 :
272 0 : flags->deblocking_level = ctx->postproc_cfg.deblocking_level;
273 0 : flags->noise_level = ctx->postproc_cfg.noise_level;
274 0 : }
275 :
276 0 : static int frame_worker_hook(void *arg1, void *arg2) {
277 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)arg1;
278 0 : const uint8_t *data = frame_worker_data->data;
279 : (void)arg2;
280 :
281 0 : frame_worker_data->result = vp9_receive_compressed_data(
282 : frame_worker_data->pbi, frame_worker_data->data_size, &data);
283 0 : frame_worker_data->data_end = data;
284 :
285 0 : if (frame_worker_data->pbi->frame_parallel_decode) {
286 : // In frame parallel decoding, a worker thread must successfully decode all
287 : // the compressed data.
288 0 : if (frame_worker_data->result != 0 ||
289 0 : frame_worker_data->data + frame_worker_data->data_size - 1 > data) {
290 0 : VPxWorker *const worker = frame_worker_data->pbi->frame_worker_owner;
291 0 : BufferPool *const pool = frame_worker_data->pbi->common.buffer_pool;
292 : // Signal all the other threads that are waiting for this frame.
293 0 : vp9_frameworker_lock_stats(worker);
294 0 : frame_worker_data->frame_context_ready = 1;
295 0 : lock_buffer_pool(pool);
296 0 : frame_worker_data->pbi->cur_buf->buf.corrupted = 1;
297 0 : unlock_buffer_pool(pool);
298 0 : frame_worker_data->pbi->need_resync = 1;
299 0 : vp9_frameworker_signal_stats(worker);
300 0 : vp9_frameworker_unlock_stats(worker);
301 0 : return 0;
302 : }
303 0 : } else if (frame_worker_data->result != 0) {
304 : // Check decode result in serial decode.
305 0 : frame_worker_data->pbi->cur_buf->buf.corrupted = 1;
306 0 : frame_worker_data->pbi->need_resync = 1;
307 : }
308 0 : return !frame_worker_data->result;
309 : }
310 :
311 0 : static vpx_codec_err_t init_decoder(vpx_codec_alg_priv_t *ctx) {
312 : int i;
313 0 : const VPxWorkerInterface *const winterface = vpx_get_worker_interface();
314 :
315 0 : ctx->last_show_frame = -1;
316 0 : ctx->next_submit_worker_id = 0;
317 0 : ctx->last_submit_worker_id = 0;
318 0 : ctx->next_output_worker_id = 0;
319 0 : ctx->frame_cache_read = 0;
320 0 : ctx->frame_cache_write = 0;
321 0 : ctx->num_cache_frames = 0;
322 0 : ctx->need_resync = 1;
323 0 : ctx->num_frame_workers =
324 0 : (ctx->frame_parallel_decode == 1) ? ctx->cfg.threads : 1;
325 0 : if (ctx->num_frame_workers > MAX_DECODE_THREADS)
326 0 : ctx->num_frame_workers = MAX_DECODE_THREADS;
327 0 : ctx->available_threads = ctx->num_frame_workers;
328 0 : ctx->flushed = 0;
329 :
330 0 : ctx->buffer_pool = (BufferPool *)vpx_calloc(1, sizeof(BufferPool));
331 0 : if (ctx->buffer_pool == NULL) return VPX_CODEC_MEM_ERROR;
332 :
333 : #if CONFIG_MULTITHREAD
334 0 : if (pthread_mutex_init(&ctx->buffer_pool->pool_mutex, NULL)) {
335 0 : set_error_detail(ctx, "Failed to allocate buffer pool mutex");
336 0 : return VPX_CODEC_MEM_ERROR;
337 : }
338 : #endif
339 :
340 0 : ctx->frame_workers = (VPxWorker *)vpx_malloc(ctx->num_frame_workers *
341 : sizeof(*ctx->frame_workers));
342 0 : if (ctx->frame_workers == NULL) {
343 0 : set_error_detail(ctx, "Failed to allocate frame_workers");
344 0 : return VPX_CODEC_MEM_ERROR;
345 : }
346 :
347 0 : for (i = 0; i < ctx->num_frame_workers; ++i) {
348 0 : VPxWorker *const worker = &ctx->frame_workers[i];
349 0 : FrameWorkerData *frame_worker_data = NULL;
350 0 : winterface->init(worker);
351 0 : worker->data1 = vpx_memalign(32, sizeof(FrameWorkerData));
352 0 : if (worker->data1 == NULL) {
353 0 : set_error_detail(ctx, "Failed to allocate frame_worker_data");
354 0 : return VPX_CODEC_MEM_ERROR;
355 : }
356 0 : frame_worker_data = (FrameWorkerData *)worker->data1;
357 0 : frame_worker_data->pbi = vp9_decoder_create(ctx->buffer_pool);
358 0 : if (frame_worker_data->pbi == NULL) {
359 0 : set_error_detail(ctx, "Failed to allocate frame_worker_data");
360 0 : return VPX_CODEC_MEM_ERROR;
361 : }
362 0 : frame_worker_data->pbi->frame_worker_owner = worker;
363 0 : frame_worker_data->worker_id = i;
364 0 : frame_worker_data->scratch_buffer = NULL;
365 0 : frame_worker_data->scratch_buffer_size = 0;
366 0 : frame_worker_data->frame_context_ready = 0;
367 0 : frame_worker_data->received_frame = 0;
368 : #if CONFIG_MULTITHREAD
369 0 : if (pthread_mutex_init(&frame_worker_data->stats_mutex, NULL)) {
370 0 : set_error_detail(ctx, "Failed to allocate frame_worker_data mutex");
371 0 : return VPX_CODEC_MEM_ERROR;
372 : }
373 :
374 0 : if (pthread_cond_init(&frame_worker_data->stats_cond, NULL)) {
375 0 : set_error_detail(ctx, "Failed to allocate frame_worker_data cond");
376 0 : return VPX_CODEC_MEM_ERROR;
377 : }
378 : #endif
379 : // If decoding in serial mode, FrameWorker thread could create tile worker
380 : // thread or loopfilter thread.
381 0 : frame_worker_data->pbi->max_threads =
382 0 : (ctx->frame_parallel_decode == 0) ? ctx->cfg.threads : 0;
383 :
384 0 : frame_worker_data->pbi->inv_tile_order = ctx->invert_tile_order;
385 0 : frame_worker_data->pbi->frame_parallel_decode = ctx->frame_parallel_decode;
386 0 : frame_worker_data->pbi->common.frame_parallel_decode =
387 0 : ctx->frame_parallel_decode;
388 0 : worker->hook = (VPxWorkerHook)frame_worker_hook;
389 0 : if (!winterface->reset(worker)) {
390 0 : set_error_detail(ctx, "Frame Worker thread creation failed");
391 0 : return VPX_CODEC_MEM_ERROR;
392 : }
393 : }
394 :
395 : // If postprocessing was enabled by the application and a
396 : // configuration has not been provided, default it.
397 0 : if (!ctx->postproc_cfg_set && (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC))
398 0 : set_default_ppflags(&ctx->postproc_cfg);
399 :
400 0 : init_buffer_callbacks(ctx);
401 :
402 0 : return VPX_CODEC_OK;
403 : }
404 :
405 0 : static INLINE void check_resync(vpx_codec_alg_priv_t *const ctx,
406 : const VP9Decoder *const pbi) {
407 : // Clear resync flag if worker got a key frame or intra only frame.
408 0 : if (ctx->need_resync == 1 && pbi->need_resync == 0 &&
409 0 : (pbi->common.intra_only || pbi->common.frame_type == KEY_FRAME))
410 0 : ctx->need_resync = 0;
411 0 : }
412 :
413 0 : static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx,
414 : const uint8_t **data, unsigned int data_sz,
415 : void *user_priv, int64_t deadline) {
416 0 : const VPxWorkerInterface *const winterface = vpx_get_worker_interface();
417 : (void)deadline;
418 :
419 : // Determine the stream parameters. Note that we rely on peek_si to
420 : // validate that we have a buffer that does not wrap around the top
421 : // of the heap.
422 0 : if (!ctx->si.h) {
423 0 : int is_intra_only = 0;
424 0 : const vpx_codec_err_t res =
425 0 : decoder_peek_si_internal(*data, data_sz, &ctx->si, &is_intra_only,
426 : ctx->decrypt_cb, ctx->decrypt_state);
427 0 : if (res != VPX_CODEC_OK) return res;
428 :
429 0 : if (!ctx->si.is_kf && !is_intra_only) return VPX_CODEC_ERROR;
430 : }
431 :
432 0 : if (!ctx->frame_parallel_decode) {
433 0 : VPxWorker *const worker = ctx->frame_workers;
434 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
435 0 : frame_worker_data->data = *data;
436 0 : frame_worker_data->data_size = data_sz;
437 0 : frame_worker_data->user_priv = user_priv;
438 0 : frame_worker_data->received_frame = 1;
439 :
440 : // Set these even if already initialized. The caller may have changed the
441 : // decrypt config between frames.
442 0 : frame_worker_data->pbi->decrypt_cb = ctx->decrypt_cb;
443 0 : frame_worker_data->pbi->decrypt_state = ctx->decrypt_state;
444 :
445 0 : worker->had_error = 0;
446 0 : winterface->execute(worker);
447 :
448 : // Update data pointer after decode.
449 0 : *data = frame_worker_data->data_end;
450 :
451 0 : if (worker->had_error)
452 0 : return update_error_state(ctx, &frame_worker_data->pbi->common.error);
453 :
454 0 : check_resync(ctx, frame_worker_data->pbi);
455 : } else {
456 0 : VPxWorker *const worker = &ctx->frame_workers[ctx->next_submit_worker_id];
457 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
458 : // Copy context from last worker thread to next worker thread.
459 0 : if (ctx->next_submit_worker_id != ctx->last_submit_worker_id)
460 0 : vp9_frameworker_copy_context(
461 0 : &ctx->frame_workers[ctx->next_submit_worker_id],
462 0 : &ctx->frame_workers[ctx->last_submit_worker_id]);
463 :
464 0 : frame_worker_data->pbi->ready_for_new_data = 0;
465 : // Copy the compressed data into worker's internal buffer.
466 : // TODO(hkuang): Will all the workers allocate the same size
467 : // as the size of the first intra frame be better? This will
468 : // avoid too many deallocate and allocate.
469 0 : if (frame_worker_data->scratch_buffer_size < data_sz) {
470 0 : vpx_free(frame_worker_data->scratch_buffer);
471 0 : frame_worker_data->scratch_buffer = (uint8_t *)vpx_malloc(data_sz);
472 0 : if (frame_worker_data->scratch_buffer == NULL) {
473 0 : set_error_detail(ctx, "Failed to reallocate scratch buffer");
474 0 : return VPX_CODEC_MEM_ERROR;
475 : }
476 0 : frame_worker_data->scratch_buffer_size = data_sz;
477 : }
478 0 : frame_worker_data->data_size = data_sz;
479 0 : memcpy(frame_worker_data->scratch_buffer, *data, data_sz);
480 :
481 0 : frame_worker_data->frame_decoded = 0;
482 0 : frame_worker_data->frame_context_ready = 0;
483 0 : frame_worker_data->received_frame = 1;
484 0 : frame_worker_data->data = frame_worker_data->scratch_buffer;
485 0 : frame_worker_data->user_priv = user_priv;
486 :
487 0 : if (ctx->next_submit_worker_id != ctx->last_submit_worker_id)
488 0 : ctx->last_submit_worker_id =
489 0 : (ctx->last_submit_worker_id + 1) % ctx->num_frame_workers;
490 :
491 0 : ctx->next_submit_worker_id =
492 0 : (ctx->next_submit_worker_id + 1) % ctx->num_frame_workers;
493 0 : --ctx->available_threads;
494 0 : worker->had_error = 0;
495 0 : winterface->launch(worker);
496 : }
497 :
498 0 : return VPX_CODEC_OK;
499 : }
500 :
501 0 : static void wait_worker_and_cache_frame(vpx_codec_alg_priv_t *ctx) {
502 : YV12_BUFFER_CONFIG sd;
503 0 : vp9_ppflags_t flags = { 0, 0, 0 };
504 0 : const VPxWorkerInterface *const winterface = vpx_get_worker_interface();
505 0 : VPxWorker *const worker = &ctx->frame_workers[ctx->next_output_worker_id];
506 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
507 0 : ctx->next_output_worker_id =
508 0 : (ctx->next_output_worker_id + 1) % ctx->num_frame_workers;
509 : // TODO(hkuang): Add worker error handling here.
510 0 : winterface->sync(worker);
511 0 : frame_worker_data->received_frame = 0;
512 0 : ++ctx->available_threads;
513 :
514 0 : check_resync(ctx, frame_worker_data->pbi);
515 :
516 0 : if (vp9_get_raw_frame(frame_worker_data->pbi, &sd, &flags) == 0) {
517 0 : VP9_COMMON *const cm = &frame_worker_data->pbi->common;
518 0 : RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
519 0 : ctx->frame_cache[ctx->frame_cache_write].fb_idx = cm->new_fb_idx;
520 0 : yuvconfig2image(&ctx->frame_cache[ctx->frame_cache_write].img, &sd,
521 : frame_worker_data->user_priv);
522 0 : ctx->frame_cache[ctx->frame_cache_write].img.fb_priv =
523 0 : frame_bufs[cm->new_fb_idx].raw_frame_buffer.priv;
524 0 : ctx->frame_cache_write = (ctx->frame_cache_write + 1) % FRAME_CACHE_SIZE;
525 0 : ++ctx->num_cache_frames;
526 : }
527 0 : }
528 :
529 0 : static vpx_codec_err_t decoder_decode(vpx_codec_alg_priv_t *ctx,
530 : const uint8_t *data, unsigned int data_sz,
531 : void *user_priv, long deadline) {
532 0 : const uint8_t *data_start = data;
533 0 : const uint8_t *const data_end = data + data_sz;
534 : vpx_codec_err_t res;
535 : uint32_t frame_sizes[8];
536 : int frame_count;
537 :
538 0 : if (data == NULL && data_sz == 0) {
539 0 : ctx->flushed = 1;
540 0 : return VPX_CODEC_OK;
541 : }
542 :
543 : // Reset flushed when receiving a valid frame.
544 0 : ctx->flushed = 0;
545 :
546 : // Initialize the decoder workers on the first frame.
547 0 : if (ctx->frame_workers == NULL) {
548 0 : const vpx_codec_err_t res = init_decoder(ctx);
549 0 : if (res != VPX_CODEC_OK) return res;
550 : }
551 :
552 0 : res = vp9_parse_superframe_index(data, data_sz, frame_sizes, &frame_count,
553 : ctx->decrypt_cb, ctx->decrypt_state);
554 0 : if (res != VPX_CODEC_OK) return res;
555 :
556 0 : if (ctx->svc_decoding && ctx->svc_spatial_layer < frame_count - 1)
557 0 : frame_count = ctx->svc_spatial_layer + 1;
558 :
559 0 : if (ctx->frame_parallel_decode) {
560 : // Decode in frame parallel mode. When decoding in this mode, the frame
561 : // passed to the decoder must be either a normal frame or a superframe with
562 : // superframe index so the decoder could get each frame's start position
563 : // in the superframe.
564 0 : if (frame_count > 0) {
565 : int i;
566 :
567 0 : for (i = 0; i < frame_count; ++i) {
568 0 : const uint8_t *data_start_copy = data_start;
569 0 : const uint32_t frame_size = frame_sizes[i];
570 0 : if (data_start < data ||
571 0 : frame_size > (uint32_t)(data_end - data_start)) {
572 0 : set_error_detail(ctx, "Invalid frame size in index");
573 0 : return VPX_CODEC_CORRUPT_FRAME;
574 : }
575 :
576 0 : if (ctx->available_threads == 0) {
577 : // No more threads for decoding. Wait until the next output worker
578 : // finishes decoding. Then copy the decoded frame into cache.
579 0 : if (ctx->num_cache_frames < FRAME_CACHE_SIZE) {
580 0 : wait_worker_and_cache_frame(ctx);
581 : } else {
582 : // TODO(hkuang): Add unit test to test this path.
583 0 : set_error_detail(ctx, "Frame output cache is full.");
584 0 : return VPX_CODEC_ERROR;
585 : }
586 : }
587 :
588 0 : res =
589 : decode_one(ctx, &data_start_copy, frame_size, user_priv, deadline);
590 0 : if (res != VPX_CODEC_OK) return res;
591 0 : data_start += frame_size;
592 : }
593 : } else {
594 0 : if (ctx->available_threads == 0) {
595 : // No more threads for decoding. Wait until the next output worker
596 : // finishes decoding. Then copy the decoded frame into cache.
597 0 : if (ctx->num_cache_frames < FRAME_CACHE_SIZE) {
598 0 : wait_worker_and_cache_frame(ctx);
599 : } else {
600 : // TODO(hkuang): Add unit test to test this path.
601 0 : set_error_detail(ctx, "Frame output cache is full.");
602 0 : return VPX_CODEC_ERROR;
603 : }
604 : }
605 :
606 0 : res = decode_one(ctx, &data, data_sz, user_priv, deadline);
607 0 : if (res != VPX_CODEC_OK) return res;
608 : }
609 : } else {
610 : // Decode in serial mode.
611 0 : if (frame_count > 0) {
612 : int i;
613 :
614 0 : for (i = 0; i < frame_count; ++i) {
615 0 : const uint8_t *data_start_copy = data_start;
616 0 : const uint32_t frame_size = frame_sizes[i];
617 : vpx_codec_err_t res;
618 0 : if (data_start < data ||
619 0 : frame_size > (uint32_t)(data_end - data_start)) {
620 0 : set_error_detail(ctx, "Invalid frame size in index");
621 0 : return VPX_CODEC_CORRUPT_FRAME;
622 : }
623 :
624 0 : res =
625 : decode_one(ctx, &data_start_copy, frame_size, user_priv, deadline);
626 0 : if (res != VPX_CODEC_OK) return res;
627 :
628 0 : data_start += frame_size;
629 : }
630 : } else {
631 0 : while (data_start < data_end) {
632 0 : const uint32_t frame_size = (uint32_t)(data_end - data_start);
633 0 : const vpx_codec_err_t res =
634 : decode_one(ctx, &data_start, frame_size, user_priv, deadline);
635 0 : if (res != VPX_CODEC_OK) return res;
636 :
637 : // Account for suboptimal termination by the encoder.
638 0 : while (data_start < data_end) {
639 0 : const uint8_t marker =
640 0 : read_marker(ctx->decrypt_cb, ctx->decrypt_state, data_start);
641 0 : if (marker) break;
642 0 : ++data_start;
643 : }
644 : }
645 : }
646 : }
647 :
648 0 : return res;
649 : }
650 :
651 0 : static void release_last_output_frame(vpx_codec_alg_priv_t *ctx) {
652 0 : RefCntBuffer *const frame_bufs = ctx->buffer_pool->frame_bufs;
653 : // Decrease reference count of last output frame in frame parallel mode.
654 0 : if (ctx->frame_parallel_decode && ctx->last_show_frame >= 0) {
655 0 : BufferPool *const pool = ctx->buffer_pool;
656 0 : lock_buffer_pool(pool);
657 0 : decrease_ref_count(ctx->last_show_frame, frame_bufs, pool);
658 0 : unlock_buffer_pool(pool);
659 : }
660 0 : }
661 :
662 0 : static vpx_image_t *decoder_get_frame(vpx_codec_alg_priv_t *ctx,
663 : vpx_codec_iter_t *iter) {
664 0 : vpx_image_t *img = NULL;
665 :
666 : // Only return frame when all the cpu are busy or
667 : // application fluhsed the decoder in frame parallel decode.
668 0 : if (ctx->frame_parallel_decode && ctx->available_threads > 0 &&
669 0 : !ctx->flushed) {
670 0 : return NULL;
671 : }
672 :
673 : // Output the frames in the cache first.
674 0 : if (ctx->num_cache_frames > 0) {
675 0 : release_last_output_frame(ctx);
676 0 : ctx->last_show_frame = ctx->frame_cache[ctx->frame_cache_read].fb_idx;
677 0 : if (ctx->need_resync) return NULL;
678 0 : img = &ctx->frame_cache[ctx->frame_cache_read].img;
679 0 : ctx->frame_cache_read = (ctx->frame_cache_read + 1) % FRAME_CACHE_SIZE;
680 0 : --ctx->num_cache_frames;
681 0 : return img;
682 : }
683 :
684 : // iter acts as a flip flop, so an image is only returned on the first
685 : // call to get_frame.
686 0 : if (*iter == NULL && ctx->frame_workers != NULL) {
687 : do {
688 : YV12_BUFFER_CONFIG sd;
689 0 : vp9_ppflags_t flags = { 0, 0, 0 };
690 0 : const VPxWorkerInterface *const winterface = vpx_get_worker_interface();
691 0 : VPxWorker *const worker = &ctx->frame_workers[ctx->next_output_worker_id];
692 0 : FrameWorkerData *const frame_worker_data =
693 : (FrameWorkerData *)worker->data1;
694 0 : ctx->next_output_worker_id =
695 0 : (ctx->next_output_worker_id + 1) % ctx->num_frame_workers;
696 0 : if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)
697 0 : set_ppflags(ctx, &flags);
698 : // Wait for the frame from worker thread.
699 0 : if (winterface->sync(worker)) {
700 : // Check if worker has received any frames.
701 0 : if (frame_worker_data->received_frame == 1) {
702 0 : ++ctx->available_threads;
703 0 : frame_worker_data->received_frame = 0;
704 0 : check_resync(ctx, frame_worker_data->pbi);
705 : }
706 0 : if (vp9_get_raw_frame(frame_worker_data->pbi, &sd, &flags) == 0) {
707 0 : VP9_COMMON *const cm = &frame_worker_data->pbi->common;
708 0 : RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
709 0 : release_last_output_frame(ctx);
710 0 : ctx->last_show_frame = frame_worker_data->pbi->common.new_fb_idx;
711 0 : if (ctx->need_resync) return NULL;
712 0 : yuvconfig2image(&ctx->img, &sd, frame_worker_data->user_priv);
713 0 : ctx->img.fb_priv = frame_bufs[cm->new_fb_idx].raw_frame_buffer.priv;
714 0 : img = &ctx->img;
715 0 : return img;
716 : }
717 : } else {
718 : // Decoding failed. Release the worker thread.
719 0 : frame_worker_data->received_frame = 0;
720 0 : ++ctx->available_threads;
721 0 : ctx->need_resync = 1;
722 0 : if (ctx->flushed != 1) return NULL;
723 : }
724 0 : } while (ctx->next_output_worker_id != ctx->next_submit_worker_id);
725 : }
726 0 : return NULL;
727 : }
728 :
729 0 : static vpx_codec_err_t decoder_set_fb_fn(
730 : vpx_codec_alg_priv_t *ctx, vpx_get_frame_buffer_cb_fn_t cb_get,
731 : vpx_release_frame_buffer_cb_fn_t cb_release, void *cb_priv) {
732 0 : if (cb_get == NULL || cb_release == NULL) {
733 0 : return VPX_CODEC_INVALID_PARAM;
734 0 : } else if (ctx->frame_workers == NULL) {
735 : // If the decoder has already been initialized, do not accept changes to
736 : // the frame buffer functions.
737 0 : ctx->get_ext_fb_cb = cb_get;
738 0 : ctx->release_ext_fb_cb = cb_release;
739 0 : ctx->ext_priv = cb_priv;
740 0 : return VPX_CODEC_OK;
741 : }
742 :
743 0 : return VPX_CODEC_ERROR;
744 : }
745 :
746 0 : static vpx_codec_err_t ctrl_set_reference(vpx_codec_alg_priv_t *ctx,
747 : va_list args) {
748 0 : vpx_ref_frame_t *const data = va_arg(args, vpx_ref_frame_t *);
749 :
750 : // Only support this function in serial decode.
751 0 : if (ctx->frame_parallel_decode) {
752 0 : set_error_detail(ctx, "Not supported in frame parallel decode");
753 0 : return VPX_CODEC_INCAPABLE;
754 : }
755 :
756 0 : if (data) {
757 0 : vpx_ref_frame_t *const frame = (vpx_ref_frame_t *)data;
758 : YV12_BUFFER_CONFIG sd;
759 0 : VPxWorker *const worker = ctx->frame_workers;
760 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
761 0 : image2yuvconfig(&frame->img, &sd);
762 0 : return vp9_set_reference_dec(&frame_worker_data->pbi->common,
763 : ref_frame_to_vp9_reframe(frame->frame_type),
764 : &sd);
765 : } else {
766 0 : return VPX_CODEC_INVALID_PARAM;
767 : }
768 : }
769 :
770 0 : static vpx_codec_err_t ctrl_copy_reference(vpx_codec_alg_priv_t *ctx,
771 : va_list args) {
772 0 : vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
773 :
774 : // Only support this function in serial decode.
775 0 : if (ctx->frame_parallel_decode) {
776 0 : set_error_detail(ctx, "Not supported in frame parallel decode");
777 0 : return VPX_CODEC_INCAPABLE;
778 : }
779 :
780 0 : if (data) {
781 0 : vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
782 : YV12_BUFFER_CONFIG sd;
783 0 : VPxWorker *const worker = ctx->frame_workers;
784 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
785 0 : image2yuvconfig(&frame->img, &sd);
786 0 : return vp9_copy_reference_dec(frame_worker_data->pbi,
787 0 : (VP9_REFFRAME)frame->frame_type, &sd);
788 : } else {
789 0 : return VPX_CODEC_INVALID_PARAM;
790 : }
791 : }
792 :
793 0 : static vpx_codec_err_t ctrl_get_reference(vpx_codec_alg_priv_t *ctx,
794 : va_list args) {
795 0 : vp9_ref_frame_t *data = va_arg(args, vp9_ref_frame_t *);
796 :
797 : // Only support this function in serial decode.
798 0 : if (ctx->frame_parallel_decode) {
799 0 : set_error_detail(ctx, "Not supported in frame parallel decode");
800 0 : return VPX_CODEC_INCAPABLE;
801 : }
802 :
803 0 : if (data) {
804 : YV12_BUFFER_CONFIG *fb;
805 0 : VPxWorker *const worker = ctx->frame_workers;
806 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
807 0 : fb = get_ref_frame(&frame_worker_data->pbi->common, data->idx);
808 0 : if (fb == NULL) return VPX_CODEC_ERROR;
809 0 : yuvconfig2image(&data->img, fb, NULL);
810 0 : return VPX_CODEC_OK;
811 : } else {
812 0 : return VPX_CODEC_INVALID_PARAM;
813 : }
814 : }
815 :
816 0 : static vpx_codec_err_t ctrl_set_postproc(vpx_codec_alg_priv_t *ctx,
817 : va_list args) {
818 : #if CONFIG_VP9_POSTPROC
819 0 : vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
820 :
821 0 : if (data) {
822 0 : ctx->postproc_cfg_set = 1;
823 0 : ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data);
824 0 : return VPX_CODEC_OK;
825 : } else {
826 0 : return VPX_CODEC_INVALID_PARAM;
827 : }
828 : #else
829 : (void)ctx;
830 : (void)args;
831 : return VPX_CODEC_INCAPABLE;
832 : #endif
833 : }
834 :
835 0 : static vpx_codec_err_t ctrl_get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
836 : va_list args) {
837 0 : int *const update_info = va_arg(args, int *);
838 :
839 : // Only support this function in serial decode.
840 0 : if (ctx->frame_parallel_decode) {
841 0 : set_error_detail(ctx, "Not supported in frame parallel decode");
842 0 : return VPX_CODEC_INCAPABLE;
843 : }
844 :
845 0 : if (update_info) {
846 0 : if (ctx->frame_workers) {
847 0 : VPxWorker *const worker = ctx->frame_workers;
848 0 : FrameWorkerData *const frame_worker_data =
849 : (FrameWorkerData *)worker->data1;
850 0 : *update_info = frame_worker_data->pbi->refresh_frame_flags;
851 0 : return VPX_CODEC_OK;
852 : } else {
853 0 : return VPX_CODEC_ERROR;
854 : }
855 : }
856 :
857 0 : return VPX_CODEC_INVALID_PARAM;
858 : }
859 :
860 0 : static vpx_codec_err_t ctrl_get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
861 : va_list args) {
862 0 : int *corrupted = va_arg(args, int *);
863 :
864 0 : if (corrupted) {
865 0 : if (ctx->frame_workers) {
866 0 : VPxWorker *const worker = ctx->frame_workers;
867 0 : FrameWorkerData *const frame_worker_data =
868 : (FrameWorkerData *)worker->data1;
869 0 : RefCntBuffer *const frame_bufs =
870 0 : frame_worker_data->pbi->common.buffer_pool->frame_bufs;
871 0 : if (frame_worker_data->pbi->common.frame_to_show == NULL)
872 0 : return VPX_CODEC_ERROR;
873 0 : if (ctx->last_show_frame >= 0)
874 0 : *corrupted = frame_bufs[ctx->last_show_frame].buf.corrupted;
875 0 : return VPX_CODEC_OK;
876 : } else {
877 0 : return VPX_CODEC_ERROR;
878 : }
879 : }
880 :
881 0 : return VPX_CODEC_INVALID_PARAM;
882 : }
883 :
884 0 : static vpx_codec_err_t ctrl_get_frame_size(vpx_codec_alg_priv_t *ctx,
885 : va_list args) {
886 0 : int *const frame_size = va_arg(args, int *);
887 :
888 : // Only support this function in serial decode.
889 0 : if (ctx->frame_parallel_decode) {
890 0 : set_error_detail(ctx, "Not supported in frame parallel decode");
891 0 : return VPX_CODEC_INCAPABLE;
892 : }
893 :
894 0 : if (frame_size) {
895 0 : if (ctx->frame_workers) {
896 0 : VPxWorker *const worker = ctx->frame_workers;
897 0 : FrameWorkerData *const frame_worker_data =
898 : (FrameWorkerData *)worker->data1;
899 0 : const VP9_COMMON *const cm = &frame_worker_data->pbi->common;
900 0 : frame_size[0] = cm->width;
901 0 : frame_size[1] = cm->height;
902 0 : return VPX_CODEC_OK;
903 : } else {
904 0 : return VPX_CODEC_ERROR;
905 : }
906 : }
907 :
908 0 : return VPX_CODEC_INVALID_PARAM;
909 : }
910 :
911 0 : static vpx_codec_err_t ctrl_get_render_size(vpx_codec_alg_priv_t *ctx,
912 : va_list args) {
913 0 : int *const render_size = va_arg(args, int *);
914 :
915 : // Only support this function in serial decode.
916 0 : if (ctx->frame_parallel_decode) {
917 0 : set_error_detail(ctx, "Not supported in frame parallel decode");
918 0 : return VPX_CODEC_INCAPABLE;
919 : }
920 :
921 0 : if (render_size) {
922 0 : if (ctx->frame_workers) {
923 0 : VPxWorker *const worker = ctx->frame_workers;
924 0 : FrameWorkerData *const frame_worker_data =
925 : (FrameWorkerData *)worker->data1;
926 0 : const VP9_COMMON *const cm = &frame_worker_data->pbi->common;
927 0 : render_size[0] = cm->render_width;
928 0 : render_size[1] = cm->render_height;
929 0 : return VPX_CODEC_OK;
930 : } else {
931 0 : return VPX_CODEC_ERROR;
932 : }
933 : }
934 :
935 0 : return VPX_CODEC_INVALID_PARAM;
936 : }
937 :
938 0 : static vpx_codec_err_t ctrl_get_bit_depth(vpx_codec_alg_priv_t *ctx,
939 : va_list args) {
940 0 : unsigned int *const bit_depth = va_arg(args, unsigned int *);
941 0 : VPxWorker *const worker = &ctx->frame_workers[ctx->next_output_worker_id];
942 :
943 0 : if (bit_depth) {
944 0 : if (worker) {
945 0 : FrameWorkerData *const frame_worker_data =
946 : (FrameWorkerData *)worker->data1;
947 0 : const VP9_COMMON *const cm = &frame_worker_data->pbi->common;
948 0 : *bit_depth = cm->bit_depth;
949 0 : return VPX_CODEC_OK;
950 : } else {
951 0 : return VPX_CODEC_ERROR;
952 : }
953 : }
954 :
955 0 : return VPX_CODEC_INVALID_PARAM;
956 : }
957 :
958 0 : static vpx_codec_err_t ctrl_set_invert_tile_order(vpx_codec_alg_priv_t *ctx,
959 : va_list args) {
960 0 : ctx->invert_tile_order = va_arg(args, int);
961 0 : return VPX_CODEC_OK;
962 : }
963 :
964 0 : static vpx_codec_err_t ctrl_set_decryptor(vpx_codec_alg_priv_t *ctx,
965 : va_list args) {
966 0 : vpx_decrypt_init *init = va_arg(args, vpx_decrypt_init *);
967 0 : ctx->decrypt_cb = init ? init->decrypt_cb : NULL;
968 0 : ctx->decrypt_state = init ? init->decrypt_state : NULL;
969 0 : return VPX_CODEC_OK;
970 : }
971 :
972 0 : static vpx_codec_err_t ctrl_set_byte_alignment(vpx_codec_alg_priv_t *ctx,
973 : va_list args) {
974 0 : const int legacy_byte_alignment = 0;
975 0 : const int min_byte_alignment = 32;
976 0 : const int max_byte_alignment = 1024;
977 0 : const int byte_alignment = va_arg(args, int);
978 :
979 0 : if (byte_alignment != legacy_byte_alignment &&
980 0 : (byte_alignment < min_byte_alignment ||
981 0 : byte_alignment > max_byte_alignment ||
982 0 : (byte_alignment & (byte_alignment - 1)) != 0))
983 0 : return VPX_CODEC_INVALID_PARAM;
984 :
985 0 : ctx->byte_alignment = byte_alignment;
986 0 : if (ctx->frame_workers) {
987 0 : VPxWorker *const worker = ctx->frame_workers;
988 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
989 0 : frame_worker_data->pbi->common.byte_alignment = byte_alignment;
990 : }
991 0 : return VPX_CODEC_OK;
992 : }
993 :
994 0 : static vpx_codec_err_t ctrl_set_skip_loop_filter(vpx_codec_alg_priv_t *ctx,
995 : va_list args) {
996 0 : ctx->skip_loop_filter = va_arg(args, int);
997 :
998 0 : if (ctx->frame_workers) {
999 0 : VPxWorker *const worker = ctx->frame_workers;
1000 0 : FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
1001 0 : frame_worker_data->pbi->common.skip_loop_filter = ctx->skip_loop_filter;
1002 : }
1003 :
1004 0 : return VPX_CODEC_OK;
1005 : }
1006 :
1007 0 : static vpx_codec_err_t ctrl_set_spatial_layer_svc(vpx_codec_alg_priv_t *ctx,
1008 : va_list args) {
1009 0 : ctx->svc_decoding = 1;
1010 0 : ctx->svc_spatial_layer = va_arg(args, int);
1011 0 : if (ctx->svc_spatial_layer < 0)
1012 0 : return VPX_CODEC_INVALID_PARAM;
1013 : else
1014 0 : return VPX_CODEC_OK;
1015 : }
1016 :
1017 : static vpx_codec_ctrl_fn_map_t decoder_ctrl_maps[] = {
1018 : { VP8_COPY_REFERENCE, ctrl_copy_reference },
1019 :
1020 : // Setters
1021 : { VP8_SET_REFERENCE, ctrl_set_reference },
1022 : { VP8_SET_POSTPROC, ctrl_set_postproc },
1023 : { VP9_INVERT_TILE_DECODE_ORDER, ctrl_set_invert_tile_order },
1024 : { VPXD_SET_DECRYPTOR, ctrl_set_decryptor },
1025 : { VP9_SET_BYTE_ALIGNMENT, ctrl_set_byte_alignment },
1026 : { VP9_SET_SKIP_LOOP_FILTER, ctrl_set_skip_loop_filter },
1027 : { VP9_DECODE_SVC_SPATIAL_LAYER, ctrl_set_spatial_layer_svc },
1028 :
1029 : // Getters
1030 : { VP8D_GET_LAST_REF_UPDATES, ctrl_get_last_ref_updates },
1031 : { VP8D_GET_FRAME_CORRUPTED, ctrl_get_frame_corrupted },
1032 : { VP9_GET_REFERENCE, ctrl_get_reference },
1033 : { VP9D_GET_DISPLAY_SIZE, ctrl_get_render_size },
1034 : { VP9D_GET_BIT_DEPTH, ctrl_get_bit_depth },
1035 : { VP9D_GET_FRAME_SIZE, ctrl_get_frame_size },
1036 :
1037 : { -1, NULL },
1038 : };
1039 :
1040 : #ifndef VERSION_STRING
1041 : #define VERSION_STRING
1042 : #endif
1043 0 : CODEC_INTERFACE(vpx_codec_vp9_dx) = {
1044 : "WebM Project VP9 Decoder" VERSION_STRING,
1045 : VPX_CODEC_INTERNAL_ABI_VERSION,
1046 : VPX_CODEC_CAP_DECODER | VP9_CAP_POSTPROC |
1047 : VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER, // vpx_codec_caps_t
1048 : decoder_init, // vpx_codec_init_fn_t
1049 : decoder_destroy, // vpx_codec_destroy_fn_t
1050 : decoder_ctrl_maps, // vpx_codec_ctrl_fn_map_t
1051 : {
1052 : // NOLINT
1053 : decoder_peek_si, // vpx_codec_peek_si_fn_t
1054 : decoder_get_si, // vpx_codec_get_si_fn_t
1055 : decoder_decode, // vpx_codec_decode_fn_t
1056 : decoder_get_frame, // vpx_codec_frame_get_fn_t
1057 : decoder_set_fb_fn, // vpx_codec_set_fb_fn_t
1058 : },
1059 : {
1060 : // NOLINT
1061 : 0,
1062 : NULL, // vpx_codec_enc_cfg_map_t
1063 : NULL, // vpx_codec_encode_fn_t
1064 : NULL, // vpx_codec_get_cx_data_fn_t
1065 : NULL, // vpx_codec_enc_config_set_fn_t
1066 : NULL, // vpx_codec_get_global_headers_fn_t
1067 : NULL, // vpx_codec_get_preview_frame_fn_t
1068 : NULL // vpx_codec_enc_mr_get_mem_loc_fn_t
1069 : }
1070 : };
|