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 <assert.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include "./vp8_rtcd.h"
15 #include "./vpx_dsp_rtcd.h"
16 #include "./vpx_scale_rtcd.h"
17 #include "vpx/vpx_decoder.h"
18 #include "vpx/vp8dx.h"
19 #include "vpx/internal/vpx_codec_internal.h"
20 #include "vpx_version.h"
21 #include "common/alloccommon.h"
22 #include "common/common.h"
23 #include "common/onyxc_int.h"
24 #include "common/onyxd.h"
25 #include "decoder/onyxd_int.h"
26 #include "vpx_dsp/vpx_dsp_common.h"
27 #include "vpx_mem/vpx_mem.h"
28 #include "vpx_ports/system_state.h"
29 #if CONFIG_ERROR_CONCEALMENT
30 #include "decoder/error_concealment.h"
31 #endif
32 #include "decoder/decoderthreading.h"
33
34 #define VP8_CAP_POSTPROC (CONFIG_POSTPROC ? VPX_CODEC_CAP_POSTPROC : 0)
35 #define VP8_CAP_ERROR_CONCEALMENT \
36 (CONFIG_ERROR_CONCEALMENT ? VPX_CODEC_CAP_ERROR_CONCEALMENT : 0)
37
38 typedef vpx_codec_stream_info_t vp8_stream_info_t;
39
40 /* Structures for handling memory allocations */
41 typedef enum { VP8_SEG_ALG_PRIV = 256, VP8_SEG_MAX } mem_seg_id_t;
42 #define NELEMENTS(x) ((int)(sizeof(x) / sizeof((x)[0])))
43
44 struct vpx_codec_alg_priv {
45 vpx_codec_priv_t base;
46 vpx_codec_dec_cfg_t cfg;
47 vp8_stream_info_t si;
48 int decoder_init;
49 #if CONFIG_MULTITHREAD
50 // Restart threads on next frame if set to 1.
51 // This is set when error happens in multithreaded decoding and all threads
52 // are shut down.
53 int restart_threads;
54 #endif
55 int postproc_cfg_set;
56 vp8_postproc_cfg_t postproc_cfg;
57 vpx_decrypt_cb decrypt_cb;
58 void *decrypt_state;
59 vpx_image_t img;
60 int img_setup;
61 struct frame_buffers yv12_frame_buffers;
62 void *user_priv;
63 FRAGMENT_DATA fragments;
64 };
65
vp8_init_ctx(vpx_codec_ctx_t * ctx)66 static int vp8_init_ctx(vpx_codec_ctx_t *ctx) {
67 vpx_codec_alg_priv_t *priv =
68 (vpx_codec_alg_priv_t *)vpx_calloc(1, sizeof(*priv));
69 if (!priv) return 1;
70
71 ctx->priv = (vpx_codec_priv_t *)priv;
72 ctx->priv->init_flags = ctx->init_flags;
73
74 priv->si.sz = sizeof(priv->si);
75 priv->decrypt_cb = NULL;
76 priv->decrypt_state = NULL;
77
78 if (ctx->config.dec) {
79 /* Update the reference to the config structure to an internal copy. */
80 priv->cfg = *ctx->config.dec;
81 ctx->config.dec = &priv->cfg;
82 }
83
84 return 0;
85 }
86
vp8_init(vpx_codec_ctx_t * ctx,vpx_codec_priv_enc_mr_cfg_t * data)87 static vpx_codec_err_t vp8_init(vpx_codec_ctx_t *ctx,
88 vpx_codec_priv_enc_mr_cfg_t *data) {
89 vpx_codec_err_t res = VPX_CODEC_OK;
90 (void)data;
91
92 vp8_rtcd();
93 vpx_dsp_rtcd();
94 vpx_scale_rtcd();
95
96 /* This function only allocates space for the vpx_codec_alg_priv_t
97 * structure. More memory may be required at the time the stream
98 * information becomes known.
99 */
100 if (!ctx->priv) {
101 vpx_codec_alg_priv_t *priv;
102
103 if (vp8_init_ctx(ctx)) return VPX_CODEC_MEM_ERROR;
104
105 priv = (vpx_codec_alg_priv_t *)ctx->priv;
106
107 /* initialize number of fragments to zero */
108 priv->fragments.count = 0;
109 /* is input fragments enabled? */
110 priv->fragments.enabled =
111 (priv->base.init_flags & VPX_CODEC_USE_INPUT_FRAGMENTS);
112
113 /*post processing level initialized to do nothing */
114 }
115
116 return res;
117 }
118
vp8_destroy(vpx_codec_alg_priv_t * ctx)119 static vpx_codec_err_t vp8_destroy(vpx_codec_alg_priv_t *ctx) {
120 vp8_remove_decoder_instances(&ctx->yv12_frame_buffers);
121
122 vpx_free(ctx);
123
124 return VPX_CODEC_OK;
125 }
126
vp8_peek_si_internal(const uint8_t * data,unsigned int data_sz,vpx_codec_stream_info_t * si,vpx_decrypt_cb decrypt_cb,void * decrypt_state)127 static vpx_codec_err_t vp8_peek_si_internal(const uint8_t *data,
128 unsigned int data_sz,
129 vpx_codec_stream_info_t *si,
130 vpx_decrypt_cb decrypt_cb,
131 void *decrypt_state) {
132 vpx_codec_err_t res = VPX_CODEC_OK;
133
134 assert(data != NULL);
135
136 if (data + data_sz <= data) {
137 res = VPX_CODEC_INVALID_PARAM;
138 } else {
139 /* Parse uncompresssed part of key frame header.
140 * 3 bytes:- including version, frame type and an offset
141 * 3 bytes:- sync code (0x9d, 0x01, 0x2a)
142 * 4 bytes:- including image width and height in the lowest 14 bits
143 * of each 2-byte value.
144 */
145 uint8_t clear_buffer[10];
146 const uint8_t *clear = data;
147 if (decrypt_cb) {
148 int n = VPXMIN(sizeof(clear_buffer), data_sz);
149 decrypt_cb(decrypt_state, data, clear_buffer, n);
150 clear = clear_buffer;
151 }
152 si->is_kf = 0;
153
154 if (data_sz >= 10 && !(clear[0] & 0x01)) { /* I-Frame */
155 si->is_kf = 1;
156
157 /* vet via sync code */
158 if (clear[3] != 0x9d || clear[4] != 0x01 || clear[5] != 0x2a) {
159 return VPX_CODEC_UNSUP_BITSTREAM;
160 }
161
162 si->w = (clear[6] | (clear[7] << 8)) & 0x3fff;
163 si->h = (clear[8] | (clear[9] << 8)) & 0x3fff;
164
165 /*printf("w=%d, h=%d\n", si->w, si->h);*/
166 if (!(si->h && si->w)) {
167 si->w = si->h = 0;
168 res = VPX_CODEC_CORRUPT_FRAME;
169 }
170 } else {
171 res = VPX_CODEC_UNSUP_BITSTREAM;
172 }
173 }
174
175 return res;
176 }
177
vp8_peek_si(const uint8_t * data,unsigned int data_sz,vpx_codec_stream_info_t * si)178 static vpx_codec_err_t vp8_peek_si(const uint8_t *data, unsigned int data_sz,
179 vpx_codec_stream_info_t *si) {
180 return vp8_peek_si_internal(data, data_sz, si, NULL, NULL);
181 }
182
vp8_get_si(vpx_codec_alg_priv_t * ctx,vpx_codec_stream_info_t * si)183 static vpx_codec_err_t vp8_get_si(vpx_codec_alg_priv_t *ctx,
184 vpx_codec_stream_info_t *si) {
185 unsigned int sz;
186
187 if (si->sz >= sizeof(vp8_stream_info_t)) {
188 sz = sizeof(vp8_stream_info_t);
189 } else {
190 sz = sizeof(vpx_codec_stream_info_t);
191 }
192
193 memcpy(si, &ctx->si, sz);
194 si->sz = sz;
195
196 return VPX_CODEC_OK;
197 }
198
update_error_state(vpx_codec_alg_priv_t * ctx,const struct vpx_internal_error_info * error)199 static vpx_codec_err_t update_error_state(
200 vpx_codec_alg_priv_t *ctx, const struct vpx_internal_error_info *error) {
201 vpx_codec_err_t res;
202
203 if ((res = error->error_code)) {
204 ctx->base.err_detail = error->has_detail ? error->detail : NULL;
205 }
206
207 return res;
208 }
209
yuvconfig2image(vpx_image_t * img,const YV12_BUFFER_CONFIG * yv12,void * user_priv)210 static void yuvconfig2image(vpx_image_t *img, const YV12_BUFFER_CONFIG *yv12,
211 void *user_priv) {
212 /** vpx_img_wrap() doesn't allow specifying independent strides for
213 * the Y, U, and V planes, nor other alignment adjustments that
214 * might be representable by a YV12_BUFFER_CONFIG, so we just
215 * initialize all the fields.*/
216 img->fmt = VPX_IMG_FMT_I420;
217 img->w = yv12->y_stride;
218 img->h = (yv12->y_height + 2 * VP8BORDERINPIXELS + 15) & ~15;
219 img->d_w = img->r_w = yv12->y_width;
220 img->d_h = img->r_h = yv12->y_height;
221 img->x_chroma_shift = 1;
222 img->y_chroma_shift = 1;
223 img->planes[VPX_PLANE_Y] = yv12->y_buffer;
224 img->planes[VPX_PLANE_U] = yv12->u_buffer;
225 img->planes[VPX_PLANE_V] = yv12->v_buffer;
226 img->planes[VPX_PLANE_ALPHA] = NULL;
227 img->stride[VPX_PLANE_Y] = yv12->y_stride;
228 img->stride[VPX_PLANE_U] = yv12->uv_stride;
229 img->stride[VPX_PLANE_V] = yv12->uv_stride;
230 img->stride[VPX_PLANE_ALPHA] = yv12->y_stride;
231 img->bit_depth = 8;
232 img->bps = 12;
233 img->user_priv = user_priv;
234 img->img_data = yv12->buffer_alloc;
235 img->img_data_owner = 0;
236 img->self_allocd = 0;
237 }
238
update_fragments(vpx_codec_alg_priv_t * ctx,const uint8_t * data,unsigned int data_sz,volatile vpx_codec_err_t * res)239 static int update_fragments(vpx_codec_alg_priv_t *ctx, const uint8_t *data,
240 unsigned int data_sz,
241 volatile vpx_codec_err_t *res) {
242 *res = VPX_CODEC_OK;
243
244 if (ctx->fragments.count == 0) {
245 /* New frame, reset fragment pointers and sizes */
246 memset((void *)ctx->fragments.ptrs, 0, sizeof(ctx->fragments.ptrs));
247 memset(ctx->fragments.sizes, 0, sizeof(ctx->fragments.sizes));
248 }
249 if (ctx->fragments.enabled && !(data == NULL && data_sz == 0)) {
250 /* Store a pointer to this fragment and return. We haven't
251 * received the complete frame yet, so we will wait with decoding.
252 */
253 if (ctx->fragments.count >= MAX_PARTITIONS) {
254 ctx->fragments.count = 0;
255 *res = VPX_CODEC_INVALID_PARAM;
256 return -1;
257 }
258 ctx->fragments.ptrs[ctx->fragments.count] = data;
259 ctx->fragments.sizes[ctx->fragments.count] = data_sz;
260 ctx->fragments.count++;
261 return 0;
262 }
263
264 if (!ctx->fragments.enabled && (data == NULL && data_sz == 0)) {
265 return 0;
266 }
267
268 if (!ctx->fragments.enabled) {
269 ctx->fragments.ptrs[0] = data;
270 ctx->fragments.sizes[0] = data_sz;
271 ctx->fragments.count = 1;
272 }
273
274 return 1;
275 }
276
vp8_decode(vpx_codec_alg_priv_t * ctx,const uint8_t * data,unsigned int data_sz,void * user_priv)277 static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx,
278 const uint8_t *data, unsigned int data_sz,
279 void *user_priv) {
280 volatile vpx_codec_err_t res;
281 volatile unsigned int resolution_change = 0;
282 volatile unsigned int w, h;
283
284 if (!ctx->fragments.enabled && (data == NULL && data_sz == 0)) {
285 return 0;
286 }
287
288 /* Update the input fragment data */
289 if (update_fragments(ctx, data, data_sz, &res) <= 0) return res;
290
291 /* Determine the stream parameters. Note that we rely on peek_si to
292 * validate that we have a buffer that does not wrap around the top
293 * of the heap.
294 */
295 w = ctx->si.w;
296 h = ctx->si.h;
297
298 res = vp8_peek_si_internal(ctx->fragments.ptrs[0], ctx->fragments.sizes[0],
299 &ctx->si, ctx->decrypt_cb, ctx->decrypt_state);
300
301 if ((res == VPX_CODEC_UNSUP_BITSTREAM) && !ctx->si.is_kf) {
302 /* the peek function returns an error for non keyframes, however for
303 * this case, it is not an error */
304 res = VPX_CODEC_OK;
305 }
306
307 if (!ctx->decoder_init && !ctx->si.is_kf) res = VPX_CODEC_UNSUP_BITSTREAM;
308 if (!res && ctx->decoder_init && w == 0 && h == 0 && ctx->si.h == 0 &&
309 ctx->si.w == 0) {
310 VP8D_COMP *pbi = ctx->yv12_frame_buffers.pbi[0];
311 assert(pbi != NULL);
312 assert(!pbi->common.error.setjmp);
313 res = VPX_CODEC_CORRUPT_FRAME;
314 vpx_internal_error(&pbi->common.error, res,
315 "Keyframe / intra-only frame required to reset decoder"
316 " state");
317 }
318
319 if ((ctx->si.h != h) || (ctx->si.w != w)) resolution_change = 1;
320
321 #if CONFIG_MULTITHREAD
322 if (!res && ctx->restart_threads) {
323 VP8D_COMP *pbi = ctx->yv12_frame_buffers.pbi[0];
324 VP8_COMMON *const pc = &pbi->common;
325 if (setjmp(pbi->common.error.jmp)) {
326 pbi->common.error.setjmp = 0;
327 vp8_decoder_remove_threads(pbi);
328 vpx_clear_system_state();
329 return VPX_CODEC_ERROR;
330 }
331 pbi->common.error.setjmp = 1;
332 pbi->max_threads = ctx->cfg.threads;
333 vp8_decoder_create_threads(pbi);
334 if (vpx_atomic_load_acquire(&pbi->b_multithreaded_rd)) {
335 vp8mt_alloc_temp_buffers(pbi, pc->Width, pc->mb_rows);
336 }
337 ctx->restart_threads = 0;
338 pbi->common.error.setjmp = 0;
339 }
340 #endif
341 /* Initialize the decoder instance on the first frame*/
342 if (!res && !ctx->decoder_init) {
343 VP8D_CONFIG oxcf;
344
345 oxcf.Width = ctx->si.w;
346 oxcf.Height = ctx->si.h;
347 oxcf.Version = 9;
348 oxcf.postprocess = 0;
349 oxcf.max_threads = ctx->cfg.threads;
350 oxcf.error_concealment =
351 (ctx->base.init_flags & VPX_CODEC_USE_ERROR_CONCEALMENT);
352
353 /* If postprocessing was enabled by the application and a
354 * configuration has not been provided, default it.
355 */
356 if (!ctx->postproc_cfg_set &&
357 (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)) {
358 ctx->postproc_cfg.post_proc_flag =
359 VP8_DEBLOCK | VP8_DEMACROBLOCK | VP8_MFQE;
360 ctx->postproc_cfg.deblocking_level = 4;
361 ctx->postproc_cfg.noise_level = 0;
362 }
363
364 res = vp8_create_decoder_instances(&ctx->yv12_frame_buffers, &oxcf);
365 if (res == VPX_CODEC_OK) {
366 ctx->decoder_init = 1;
367 } else {
368 /* on failure clear the cached resolution to ensure a full
369 * reallocation is attempted on resync. */
370 ctx->si.w = 0;
371 ctx->si.h = 0;
372 }
373 }
374
375 /* Set these even if already initialized. The caller may have changed the
376 * decrypt config between frames.
377 */
378 if (ctx->decoder_init) {
379 ctx->yv12_frame_buffers.pbi[0]->decrypt_cb = ctx->decrypt_cb;
380 ctx->yv12_frame_buffers.pbi[0]->decrypt_state = ctx->decrypt_state;
381 }
382
383 if (!res) {
384 VP8D_COMP *pbi = ctx->yv12_frame_buffers.pbi[0];
385 VP8_COMMON *const pc = &pbi->common;
386 if (resolution_change) {
387 MACROBLOCKD *const xd = &pbi->mb;
388 #if CONFIG_MULTITHREAD
389 int i;
390 #endif
391 pc->Width = ctx->si.w;
392 pc->Height = ctx->si.h;
393 {
394 if (setjmp(pbi->common.error.jmp)) {
395 pbi->common.error.setjmp = 0;
396 /* on failure clear the cached resolution to ensure a full
397 * reallocation is attempted on resync. */
398 ctx->si.w = 0;
399 ctx->si.h = 0;
400 vpx_clear_system_state();
401 /* same return value as used in vp8dx_receive_compressed_data */
402 return -1;
403 }
404
405 pbi->common.error.setjmp = 1;
406
407 if (pc->Width <= 0) {
408 pc->Width = w;
409 vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
410 "Invalid frame width");
411 }
412
413 if (pc->Height <= 0) {
414 pc->Height = h;
415 vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
416 "Invalid frame height");
417 }
418
419 #if CONFIG_MULTITHREAD
420 if (vpx_atomic_load_acquire(&pbi->b_multithreaded_rd)) {
421 vp8mt_de_alloc_temp_buffers(pbi, pc->mb_rows);
422 }
423 #endif
424
425 if (vp8_alloc_frame_buffers(pc, pc->Width, pc->Height)) {
426 vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR,
427 "Failed to allocate frame buffers");
428 }
429
430 xd->pre = pc->yv12_fb[pc->lst_fb_idx];
431 xd->dst = pc->yv12_fb[pc->new_fb_idx];
432
433 #if CONFIG_MULTITHREAD
434 for (i = 0; i < pbi->allocated_decoding_thread_count; ++i) {
435 pbi->mb_row_di[i].mbd.dst = pc->yv12_fb[pc->new_fb_idx];
436 vp8_build_block_doffsets(&pbi->mb_row_di[i].mbd);
437 }
438 #endif
439 vp8_build_block_doffsets(&pbi->mb);
440
441 /* allocate memory for last frame MODE_INFO array */
442 #if CONFIG_ERROR_CONCEALMENT
443
444 if (pbi->ec_enabled) {
445 /* old prev_mip was released by vp8_de_alloc_frame_buffers()
446 * called in vp8_alloc_frame_buffers() */
447 pc->prev_mip = vpx_calloc((pc->mb_cols + 1) * (pc->mb_rows + 1),
448 sizeof(MODE_INFO));
449
450 if (!pc->prev_mip) {
451 vp8_de_alloc_frame_buffers(pc);
452 vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR,
453 "Failed to allocate"
454 "last frame MODE_INFO array");
455 }
456
457 pc->prev_mi = pc->prev_mip + pc->mode_info_stride + 1;
458
459 if (vp8_alloc_overlap_lists(pbi))
460 vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR,
461 "Failed to allocate overlap lists "
462 "for error concealment");
463 }
464
465 #endif
466
467 #if CONFIG_MULTITHREAD
468 if (vpx_atomic_load_acquire(&pbi->b_multithreaded_rd)) {
469 vp8mt_alloc_temp_buffers(pbi, pc->Width, 0);
470 }
471 #endif
472 }
473
474 pbi->common.error.setjmp = 0;
475
476 /* required to get past the first get_free_fb() call */
477 pbi->common.fb_idx_ref_cnt[0] = 0;
478 }
479
480 if (setjmp(pbi->common.error.jmp)) {
481 vpx_clear_system_state();
482 /* We do not know if the missing frame(s) was supposed to update
483 * any of the reference buffers, but we act conservative and
484 * mark only the last buffer as corrupted.
485 */
486 pc->yv12_fb[pc->lst_fb_idx].corrupted = 1;
487
488 if (pc->fb_idx_ref_cnt[pc->new_fb_idx] > 0) {
489 pc->fb_idx_ref_cnt[pc->new_fb_idx]--;
490 }
491 pbi->common.error.setjmp = 0;
492 #if CONFIG_MULTITHREAD
493 if (pbi->restart_threads) {
494 ctx->si.w = 0;
495 ctx->si.h = 0;
496 ctx->restart_threads = 1;
497 }
498 #endif
499 res = update_error_state(ctx, &pbi->common.error);
500 return res;
501 }
502
503 pbi->common.error.setjmp = 1;
504
505 /* update the pbi fragment data */
506 pbi->fragments = ctx->fragments;
507 #if CONFIG_MULTITHREAD
508 pbi->restart_threads = 0;
509 #endif
510 ctx->user_priv = user_priv;
511 if (vp8dx_receive_compressed_data(pbi)) {
512 res = update_error_state(ctx, &pbi->common.error);
513 }
514
515 /* get ready for the next series of fragments */
516 ctx->fragments.count = 0;
517 pbi->common.error.setjmp = 0;
518 }
519
520 return res;
521 }
522
vp8_get_frame(vpx_codec_alg_priv_t * ctx,vpx_codec_iter_t * iter)523 static vpx_image_t *vp8_get_frame(vpx_codec_alg_priv_t *ctx,
524 vpx_codec_iter_t *iter) {
525 vpx_image_t *img = NULL;
526
527 /* iter acts as a flip flop, so an image is only returned on the first
528 * call to get_frame.
529 */
530 if (!(*iter) && ctx->yv12_frame_buffers.pbi[0]) {
531 YV12_BUFFER_CONFIG sd;
532 vp8_ppflags_t flags;
533 vp8_zero(flags);
534
535 if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) {
536 flags.post_proc_flag = ctx->postproc_cfg.post_proc_flag;
537 flags.deblocking_level = ctx->postproc_cfg.deblocking_level;
538 flags.noise_level = ctx->postproc_cfg.noise_level;
539 }
540
541 if (0 == vp8dx_get_raw_frame(ctx->yv12_frame_buffers.pbi[0], &sd, &flags)) {
542 yuvconfig2image(&ctx->img, &sd, ctx->user_priv);
543
544 img = &ctx->img;
545 *iter = img;
546 }
547 }
548
549 return img;
550 }
551
image2yuvconfig(const vpx_image_t * img,YV12_BUFFER_CONFIG * yv12)552 static vpx_codec_err_t image2yuvconfig(const vpx_image_t *img,
553 YV12_BUFFER_CONFIG *yv12) {
554 const int y_w = img->d_w;
555 const int y_h = img->d_h;
556 const int uv_w = (img->d_w + 1) / 2;
557 const int uv_h = (img->d_h + 1) / 2;
558 vpx_codec_err_t res = VPX_CODEC_OK;
559 yv12->y_buffer = img->planes[VPX_PLANE_Y];
560 yv12->u_buffer = img->planes[VPX_PLANE_U];
561 yv12->v_buffer = img->planes[VPX_PLANE_V];
562
563 yv12->y_crop_width = y_w;
564 yv12->y_crop_height = y_h;
565 yv12->y_width = y_w;
566 yv12->y_height = y_h;
567 yv12->uv_crop_width = uv_w;
568 yv12->uv_crop_height = uv_h;
569 yv12->uv_width = uv_w;
570 yv12->uv_height = uv_h;
571
572 yv12->y_stride = img->stride[VPX_PLANE_Y];
573 yv12->uv_stride = img->stride[VPX_PLANE_U];
574
575 yv12->border = (img->stride[VPX_PLANE_Y] - img->d_w) / 2;
576 return res;
577 }
578
vp8_set_reference(vpx_codec_alg_priv_t * ctx,va_list args)579 static vpx_codec_err_t vp8_set_reference(vpx_codec_alg_priv_t *ctx,
580 va_list args) {
581 vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
582
583 if (data) {
584 vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
585 YV12_BUFFER_CONFIG sd;
586
587 image2yuvconfig(&frame->img, &sd);
588
589 return vp8dx_set_reference(ctx->yv12_frame_buffers.pbi[0],
590 frame->frame_type, &sd);
591 } else {
592 return VPX_CODEC_INVALID_PARAM;
593 }
594 }
595
vp8_get_reference(vpx_codec_alg_priv_t * ctx,va_list args)596 static vpx_codec_err_t vp8_get_reference(vpx_codec_alg_priv_t *ctx,
597 va_list args) {
598 vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
599
600 if (data) {
601 vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
602 YV12_BUFFER_CONFIG sd;
603
604 image2yuvconfig(&frame->img, &sd);
605
606 return vp8dx_get_reference(ctx->yv12_frame_buffers.pbi[0],
607 frame->frame_type, &sd);
608 } else {
609 return VPX_CODEC_INVALID_PARAM;
610 }
611 }
612
vp8_get_quantizer(vpx_codec_alg_priv_t * ctx,va_list args)613 static vpx_codec_err_t vp8_get_quantizer(vpx_codec_alg_priv_t *ctx,
614 va_list args) {
615 int *const arg = va_arg(args, int *);
616 VP8D_COMP *pbi = ctx->yv12_frame_buffers.pbi[0];
617 if (arg == NULL) return VPX_CODEC_INVALID_PARAM;
618 if (pbi == NULL) return VPX_CODEC_CORRUPT_FRAME;
619 *arg = vp8dx_get_quantizer(pbi);
620 return VPX_CODEC_OK;
621 }
622
vp8_set_postproc(vpx_codec_alg_priv_t * ctx,va_list args)623 static vpx_codec_err_t vp8_set_postproc(vpx_codec_alg_priv_t *ctx,
624 va_list args) {
625 #if CONFIG_POSTPROC
626 vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
627
628 if (data) {
629 ctx->postproc_cfg_set = 1;
630 ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data);
631 return VPX_CODEC_OK;
632 } else {
633 return VPX_CODEC_INVALID_PARAM;
634 }
635
636 #else
637 (void)ctx;
638 (void)args;
639 return VPX_CODEC_INCAPABLE;
640 #endif
641 }
642
vp8_get_last_ref_updates(vpx_codec_alg_priv_t * ctx,va_list args)643 static vpx_codec_err_t vp8_get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
644 va_list args) {
645 int *update_info = va_arg(args, int *);
646
647 if (update_info) {
648 VP8D_COMP *pbi = (VP8D_COMP *)ctx->yv12_frame_buffers.pbi[0];
649 if (pbi == NULL) return VPX_CODEC_CORRUPT_FRAME;
650
651 *update_info = pbi->common.refresh_alt_ref_frame * (int)VP8_ALTR_FRAME +
652 pbi->common.refresh_golden_frame * (int)VP8_GOLD_FRAME +
653 pbi->common.refresh_last_frame * (int)VP8_LAST_FRAME;
654
655 return VPX_CODEC_OK;
656 } else {
657 return VPX_CODEC_INVALID_PARAM;
658 }
659 }
660
vp8_get_last_ref_frame(vpx_codec_alg_priv_t * ctx,va_list args)661 static vpx_codec_err_t vp8_get_last_ref_frame(vpx_codec_alg_priv_t *ctx,
662 va_list args) {
663 int *ref_info = va_arg(args, int *);
664
665 if (ref_info) {
666 VP8D_COMP *pbi = (VP8D_COMP *)ctx->yv12_frame_buffers.pbi[0];
667 if (pbi) {
668 VP8_COMMON *oci = &pbi->common;
669 *ref_info =
670 (vp8dx_references_buffer(oci, ALTREF_FRAME) ? VP8_ALTR_FRAME : 0) |
671 (vp8dx_references_buffer(oci, GOLDEN_FRAME) ? VP8_GOLD_FRAME : 0) |
672 (vp8dx_references_buffer(oci, LAST_FRAME) ? VP8_LAST_FRAME : 0);
673 return VPX_CODEC_OK;
674 } else {
675 return VPX_CODEC_CORRUPT_FRAME;
676 }
677 } else {
678 return VPX_CODEC_INVALID_PARAM;
679 }
680 }
681
vp8_get_frame_corrupted(vpx_codec_alg_priv_t * ctx,va_list args)682 static vpx_codec_err_t vp8_get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
683 va_list args) {
684 int *corrupted = va_arg(args, int *);
685 VP8D_COMP *pbi = (VP8D_COMP *)ctx->yv12_frame_buffers.pbi[0];
686
687 if (corrupted && pbi) {
688 const YV12_BUFFER_CONFIG *const frame = pbi->common.frame_to_show;
689 if (frame == NULL) return VPX_CODEC_ERROR;
690 *corrupted = frame->corrupted;
691 return VPX_CODEC_OK;
692 } else {
693 return VPX_CODEC_INVALID_PARAM;
694 }
695 }
696
vp8_set_decryptor(vpx_codec_alg_priv_t * ctx,va_list args)697 static vpx_codec_err_t vp8_set_decryptor(vpx_codec_alg_priv_t *ctx,
698 va_list args) {
699 vpx_decrypt_init *init = va_arg(args, vpx_decrypt_init *);
700
701 if (init) {
702 ctx->decrypt_cb = init->decrypt_cb;
703 ctx->decrypt_state = init->decrypt_state;
704 } else {
705 ctx->decrypt_cb = NULL;
706 ctx->decrypt_state = NULL;
707 }
708 return VPX_CODEC_OK;
709 }
710
711 static vpx_codec_ctrl_fn_map_t vp8_ctf_maps[] = {
712 { VP8_SET_REFERENCE, vp8_set_reference },
713 { VP8_COPY_REFERENCE, vp8_get_reference },
714 { VP8_SET_POSTPROC, vp8_set_postproc },
715 { VP8D_GET_LAST_REF_UPDATES, vp8_get_last_ref_updates },
716 { VP8D_GET_FRAME_CORRUPTED, vp8_get_frame_corrupted },
717 { VP8D_GET_LAST_REF_USED, vp8_get_last_ref_frame },
718 { VPXD_GET_LAST_QUANTIZER, vp8_get_quantizer },
719 { VPXD_SET_DECRYPTOR, vp8_set_decryptor },
720 { -1, NULL },
721 };
722
723 #ifndef VERSION_STRING
724 #define VERSION_STRING
725 #endif
726 CODEC_INTERFACE(vpx_codec_vp8_dx) = {
727 "WebM Project VP8 Decoder" VERSION_STRING,
728 VPX_CODEC_INTERNAL_ABI_VERSION,
729 VPX_CODEC_CAP_DECODER | VP8_CAP_POSTPROC | VP8_CAP_ERROR_CONCEALMENT |
730 VPX_CODEC_CAP_INPUT_FRAGMENTS,
731 /* vpx_codec_caps_t caps; */
732 vp8_init, /* vpx_codec_init_fn_t init; */
733 vp8_destroy, /* vpx_codec_destroy_fn_t destroy; */
734 vp8_ctf_maps, /* vpx_codec_ctrl_fn_map_t *ctrl_maps; */
735 {
736 vp8_peek_si, /* vpx_codec_peek_si_fn_t peek_si; */
737 vp8_get_si, /* vpx_codec_get_si_fn_t get_si; */
738 vp8_decode, /* vpx_codec_decode_fn_t decode; */
739 vp8_get_frame, /* vpx_codec_frame_get_fn_t frame_get; */
740 NULL,
741 },
742 {
743 /* encoder functions */
744 0, NULL, /* vpx_codec_enc_cfg_map_t */
745 NULL, /* vpx_codec_encode_fn_t */
746 NULL, /* vpx_codec_get_cx_data_fn_t */
747 NULL, /* vpx_codec_enc_config_set_fn_t */
748 NULL, /* vpx_codec_get_global_headers_fn_t */
749 NULL, /* vpx_codec_get_preview_frame_fn_t */
750 NULL /* vpx_codec_enc_mr_get_mem_loc_fn_t */
751 }
752 };
753