/src/libvpx/vp8/vp8_dx_iface.c
Line | Count | Source (jump to first uncovered line) |
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 | | |
66 | 7.95k | static int vp8_init_ctx(vpx_codec_ctx_t *ctx) { |
67 | 7.95k | vpx_codec_alg_priv_t *priv = |
68 | 7.95k | (vpx_codec_alg_priv_t *)vpx_calloc(1, sizeof(*priv)); |
69 | 7.95k | if (!priv) return 1; |
70 | | |
71 | 7.95k | ctx->priv = (vpx_codec_priv_t *)priv; |
72 | 7.95k | ctx->priv->init_flags = ctx->init_flags; |
73 | | |
74 | 7.95k | priv->si.sz = sizeof(priv->si); |
75 | 7.95k | priv->decrypt_cb = NULL; |
76 | 7.95k | priv->decrypt_state = NULL; |
77 | | |
78 | 7.95k | if (ctx->config.dec) { |
79 | | /* Update the reference to the config structure to an internal copy. */ |
80 | 7.95k | priv->cfg = *ctx->config.dec; |
81 | 7.95k | ctx->config.dec = &priv->cfg; |
82 | 7.95k | } |
83 | | |
84 | 7.95k | return 0; |
85 | 7.95k | } |
86 | | |
87 | | static vpx_codec_err_t vp8_init(vpx_codec_ctx_t *ctx, |
88 | 7.95k | vpx_codec_priv_enc_mr_cfg_t *data) { |
89 | 7.95k | vpx_codec_err_t res = VPX_CODEC_OK; |
90 | 7.95k | (void)data; |
91 | | |
92 | 7.95k | vp8_rtcd(); |
93 | 7.95k | vpx_dsp_rtcd(); |
94 | 7.95k | 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 | 7.95k | if (!ctx->priv) { |
101 | 7.95k | vpx_codec_alg_priv_t *priv; |
102 | | |
103 | 7.95k | if (vp8_init_ctx(ctx)) return VPX_CODEC_MEM_ERROR; |
104 | | |
105 | 7.95k | priv = (vpx_codec_alg_priv_t *)ctx->priv; |
106 | | |
107 | | /* initialize number of fragments to zero */ |
108 | 7.95k | priv->fragments.count = 0; |
109 | | /* is input fragments enabled? */ |
110 | 7.95k | priv->fragments.enabled = |
111 | 7.95k | (priv->base.init_flags & VPX_CODEC_USE_INPUT_FRAGMENTS); |
112 | | |
113 | | /*post processing level initialized to do nothing */ |
114 | 7.95k | } |
115 | | |
116 | 7.95k | return res; |
117 | 7.95k | } |
118 | | |
119 | 7.95k | static vpx_codec_err_t vp8_destroy(vpx_codec_alg_priv_t *ctx) { |
120 | 7.95k | vp8_remove_decoder_instances(&ctx->yv12_frame_buffers); |
121 | | |
122 | 7.95k | vpx_free(ctx); |
123 | | |
124 | 7.95k | return VPX_CODEC_OK; |
125 | 7.95k | } |
126 | | |
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 | 175k | void *decrypt_state) { |
132 | 175k | vpx_codec_err_t res = VPX_CODEC_OK; |
133 | | |
134 | 175k | assert(data != NULL); |
135 | | |
136 | 175k | if (data + data_sz <= data) { |
137 | 0 | res = VPX_CODEC_INVALID_PARAM; |
138 | 175k | } 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 | 175k | uint8_t clear_buffer[10]; |
146 | 175k | const uint8_t *clear = data; |
147 | 175k | if (decrypt_cb) { |
148 | 0 | int n = VPXMIN(sizeof(clear_buffer), data_sz); |
149 | 0 | decrypt_cb(decrypt_state, data, clear_buffer, n); |
150 | 0 | clear = clear_buffer; |
151 | 0 | } |
152 | 175k | si->is_kf = 0; |
153 | | |
154 | 175k | if (data_sz >= 10 && !(clear[0] & 0x01)) { /* I-Frame */ |
155 | 73.8k | si->is_kf = 1; |
156 | | |
157 | | /* vet via sync code */ |
158 | 73.8k | if (clear[3] != 0x9d || clear[4] != 0x01 || clear[5] != 0x2a) { |
159 | 18.5k | return VPX_CODEC_UNSUP_BITSTREAM; |
160 | 18.5k | } |
161 | | |
162 | 55.2k | si->w = (clear[6] | (clear[7] << 8)) & 0x3fff; |
163 | 55.2k | si->h = (clear[8] | (clear[9] << 8)) & 0x3fff; |
164 | | |
165 | | /*printf("w=%d, h=%d\n", si->w, si->h);*/ |
166 | 55.2k | if (!(si->h && si->w)) { |
167 | 90 | si->w = si->h = 0; |
168 | 90 | res = VPX_CODEC_CORRUPT_FRAME; |
169 | 90 | } |
170 | 101k | } else { |
171 | 101k | res = VPX_CODEC_UNSUP_BITSTREAM; |
172 | 101k | } |
173 | 175k | } |
174 | | |
175 | 156k | return res; |
176 | 175k | } |
177 | | |
178 | | static vpx_codec_err_t vp8_peek_si(const uint8_t *data, unsigned int data_sz, |
179 | 92.8k | vpx_codec_stream_info_t *si) { |
180 | 92.8k | return vp8_peek_si_internal(data, data_sz, si, NULL, NULL); |
181 | 92.8k | } |
182 | | |
183 | | static vpx_codec_err_t vp8_get_si(vpx_codec_alg_priv_t *ctx, |
184 | 0 | vpx_codec_stream_info_t *si) { |
185 | 0 | unsigned int sz; |
186 | |
|
187 | 0 | if (si->sz >= sizeof(vp8_stream_info_t)) { |
188 | 0 | sz = sizeof(vp8_stream_info_t); |
189 | 0 | } else { |
190 | 0 | sz = sizeof(vpx_codec_stream_info_t); |
191 | 0 | } |
192 | |
|
193 | 0 | memcpy(si, &ctx->si, sz); |
194 | 0 | si->sz = sz; |
195 | |
|
196 | 0 | return VPX_CODEC_OK; |
197 | 0 | } |
198 | | |
199 | | static vpx_codec_err_t update_error_state( |
200 | 22.3k | vpx_codec_alg_priv_t *ctx, const struct vpx_internal_error_info *error) { |
201 | 22.3k | vpx_codec_err_t res; |
202 | | |
203 | 22.3k | if ((res = error->error_code)) { |
204 | 22.3k | ctx->base.err_detail = error->has_detail ? error->detail : NULL; |
205 | 22.3k | } |
206 | | |
207 | 22.3k | return res; |
208 | 22.3k | } |
209 | | |
210 | | static void yuvconfig2image(vpx_image_t *img, const YV12_BUFFER_CONFIG *yv12, |
211 | 26.1k | 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 | 26.1k | img->fmt = VPX_IMG_FMT_I420; |
217 | 26.1k | img->w = yv12->y_stride; |
218 | 26.1k | img->h = (yv12->y_height + 2 * VP8BORDERINPIXELS + 15) & ~15; |
219 | 26.1k | img->d_w = img->r_w = yv12->y_width; |
220 | 26.1k | img->d_h = img->r_h = yv12->y_height; |
221 | 26.1k | img->x_chroma_shift = 1; |
222 | 26.1k | img->y_chroma_shift = 1; |
223 | 26.1k | img->planes[VPX_PLANE_Y] = yv12->y_buffer; |
224 | 26.1k | img->planes[VPX_PLANE_U] = yv12->u_buffer; |
225 | 26.1k | img->planes[VPX_PLANE_V] = yv12->v_buffer; |
226 | 26.1k | img->planes[VPX_PLANE_ALPHA] = NULL; |
227 | 26.1k | img->stride[VPX_PLANE_Y] = yv12->y_stride; |
228 | 26.1k | img->stride[VPX_PLANE_U] = yv12->uv_stride; |
229 | 26.1k | img->stride[VPX_PLANE_V] = yv12->uv_stride; |
230 | 26.1k | img->stride[VPX_PLANE_ALPHA] = yv12->y_stride; |
231 | 26.1k | img->bit_depth = 8; |
232 | 26.1k | img->bps = 12; |
233 | 26.1k | img->user_priv = user_priv; |
234 | 26.1k | img->img_data = yv12->buffer_alloc; |
235 | 26.1k | img->img_data_owner = 0; |
236 | 26.1k | img->self_allocd = 0; |
237 | 26.1k | } |
238 | | |
239 | | static int update_fragments(vpx_codec_alg_priv_t *ctx, const uint8_t *data, |
240 | | unsigned int data_sz, |
241 | 82.4k | volatile vpx_codec_err_t *res) { |
242 | 82.4k | *res = VPX_CODEC_OK; |
243 | | |
244 | 82.4k | if (ctx->fragments.count == 0) { |
245 | | /* New frame, reset fragment pointers and sizes */ |
246 | 60.6k | memset((void *)ctx->fragments.ptrs, 0, sizeof(ctx->fragments.ptrs)); |
247 | 60.6k | memset(ctx->fragments.sizes, 0, sizeof(ctx->fragments.sizes)); |
248 | 60.6k | } |
249 | 82.4k | 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 | 0 | if (ctx->fragments.count >= MAX_PARTITIONS) { |
254 | 0 | ctx->fragments.count = 0; |
255 | 0 | *res = VPX_CODEC_INVALID_PARAM; |
256 | 0 | return -1; |
257 | 0 | } |
258 | 0 | ctx->fragments.ptrs[ctx->fragments.count] = data; |
259 | 0 | ctx->fragments.sizes[ctx->fragments.count] = data_sz; |
260 | 0 | ctx->fragments.count++; |
261 | 0 | return 0; |
262 | 0 | } |
263 | | |
264 | 82.4k | if (!ctx->fragments.enabled && (data == NULL && data_sz == 0)) { |
265 | 0 | return 0; |
266 | 0 | } |
267 | | |
268 | 82.4k | if (!ctx->fragments.enabled) { |
269 | 82.4k | ctx->fragments.ptrs[0] = data; |
270 | 82.4k | ctx->fragments.sizes[0] = data_sz; |
271 | 82.4k | ctx->fragments.count = 1; |
272 | 82.4k | } |
273 | | |
274 | 82.4k | return 1; |
275 | 82.4k | } |
276 | | |
277 | | static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx, |
278 | | const uint8_t *data, unsigned int data_sz, |
279 | 82.4k | void *user_priv) { |
280 | 82.4k | volatile vpx_codec_err_t res; |
281 | 82.4k | volatile unsigned int resolution_change = 0; |
282 | 82.4k | volatile unsigned int w, h; |
283 | | |
284 | 82.4k | if (!ctx->fragments.enabled && (data == NULL && data_sz == 0)) { |
285 | 0 | return 0; |
286 | 0 | } |
287 | | |
288 | | /* Update the input fragment data */ |
289 | 82.4k | 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 | 82.4k | w = ctx->si.w; |
296 | 82.4k | h = ctx->si.h; |
297 | | |
298 | 82.4k | res = vp8_peek_si_internal(ctx->fragments.ptrs[0], ctx->fragments.sizes[0], |
299 | 82.4k | &ctx->si, ctx->decrypt_cb, ctx->decrypt_state); |
300 | | |
301 | 82.4k | 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 | 51.1k | res = VPX_CODEC_OK; |
305 | 51.1k | } |
306 | | |
307 | 82.4k | if (!ctx->decoder_init && !ctx->si.is_kf) res = VPX_CODEC_UNSUP_BITSTREAM; |
308 | 82.4k | if (!res && ctx->decoder_init && w == 0 && h == 0 && ctx->si.h == 0 && |
309 | 82.4k | ctx->si.w == 0) { |
310 | 555 | VP8D_COMP *pbi = ctx->yv12_frame_buffers.pbi[0]; |
311 | 555 | assert(pbi != NULL); |
312 | 555 | assert(!pbi->common.error.setjmp); |
313 | 555 | res = VPX_CODEC_CORRUPT_FRAME; |
314 | 555 | vpx_internal_error(&pbi->common.error, res, |
315 | 555 | "Keyframe / intra-only frame required to reset decoder" |
316 | 555 | " state"); |
317 | 555 | } |
318 | | |
319 | 82.4k | if ((ctx->si.h != h) || (ctx->si.w != w)) resolution_change = 1; |
320 | | |
321 | 82.4k | #if CONFIG_MULTITHREAD |
322 | 82.4k | if (!res && ctx->restart_threads) { |
323 | 2.09k | VP8D_COMP *pbi = ctx->yv12_frame_buffers.pbi[0]; |
324 | 2.09k | VP8_COMMON *const pc = &pbi->common; |
325 | 2.09k | if (setjmp(pbi->common.error.jmp)) { |
326 | 0 | pbi->common.error.setjmp = 0; |
327 | 0 | vp8_decoder_remove_threads(pbi); |
328 | 0 | vpx_clear_system_state(); |
329 | 0 | return VPX_CODEC_ERROR; |
330 | 0 | } |
331 | 2.09k | pbi->common.error.setjmp = 1; |
332 | 2.09k | pbi->max_threads = ctx->cfg.threads; |
333 | 2.09k | vp8_decoder_create_threads(pbi); |
334 | 2.09k | if (vpx_atomic_load_acquire(&pbi->b_multithreaded_rd)) { |
335 | 2.09k | vp8mt_alloc_temp_buffers(pbi, pc->Width, pc->mb_rows); |
336 | 2.09k | } |
337 | 2.09k | ctx->restart_threads = 0; |
338 | 2.09k | pbi->common.error.setjmp = 0; |
339 | 2.09k | } |
340 | 82.4k | #endif |
341 | | /* Initialize the decoder instance on the first frame*/ |
342 | 82.4k | if (!res && !ctx->decoder_init) { |
343 | 7.81k | VP8D_CONFIG oxcf; |
344 | | |
345 | 7.81k | oxcf.Width = ctx->si.w; |
346 | 7.81k | oxcf.Height = ctx->si.h; |
347 | 7.81k | oxcf.Version = 9; |
348 | 7.81k | oxcf.postprocess = 0; |
349 | 7.81k | oxcf.max_threads = ctx->cfg.threads; |
350 | 7.81k | oxcf.error_concealment = |
351 | 7.81k | (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 | 7.81k | if (!ctx->postproc_cfg_set && |
357 | 7.81k | (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)) { |
358 | 0 | ctx->postproc_cfg.post_proc_flag = |
359 | 0 | VP8_DEBLOCK | VP8_DEMACROBLOCK | VP8_MFQE; |
360 | 0 | ctx->postproc_cfg.deblocking_level = 4; |
361 | 0 | ctx->postproc_cfg.noise_level = 0; |
362 | 0 | } |
363 | | |
364 | 7.81k | res = vp8_create_decoder_instances(&ctx->yv12_frame_buffers, &oxcf); |
365 | 7.81k | if (res == VPX_CODEC_OK) { |
366 | 7.81k | ctx->decoder_init = 1; |
367 | 7.81k | } else { |
368 | | /* on failure clear the cached resolution to ensure a full |
369 | | * reallocation is attempted on resync. */ |
370 | 0 | ctx->si.w = 0; |
371 | 0 | ctx->si.h = 0; |
372 | 0 | } |
373 | 7.81k | } |
374 | | |
375 | | /* Set these even if already initialized. The caller may have changed the |
376 | | * decrypt config between frames. |
377 | | */ |
378 | 82.4k | if (ctx->decoder_init) { |
379 | 81.7k | ctx->yv12_frame_buffers.pbi[0]->decrypt_cb = ctx->decrypt_cb; |
380 | 81.7k | ctx->yv12_frame_buffers.pbi[0]->decrypt_state = ctx->decrypt_state; |
381 | 81.7k | } |
382 | | |
383 | 82.4k | if (!res) { |
384 | 77.7k | VP8D_COMP *pbi = ctx->yv12_frame_buffers.pbi[0]; |
385 | 77.7k | VP8_COMMON *const pc = &pbi->common; |
386 | 77.7k | if (resolution_change) { |
387 | 18.3k | MACROBLOCKD *const xd = &pbi->mb; |
388 | 18.3k | #if CONFIG_MULTITHREAD |
389 | 18.3k | int i; |
390 | 18.3k | #endif |
391 | 18.3k | pc->Width = ctx->si.w; |
392 | 18.3k | pc->Height = ctx->si.h; |
393 | 18.3k | { |
394 | 18.3k | if (setjmp(pbi->common.error.jmp)) { |
395 | 0 | pbi->common.error.setjmp = 0; |
396 | | /* on failure clear the cached resolution to ensure a full |
397 | | * reallocation is attempted on resync. */ |
398 | 0 | ctx->si.w = 0; |
399 | 0 | ctx->si.h = 0; |
400 | 0 | vpx_clear_system_state(); |
401 | | /* same return value as used in vp8dx_receive_compressed_data */ |
402 | 0 | return -1; |
403 | 0 | } |
404 | | |
405 | 18.3k | pbi->common.error.setjmp = 1; |
406 | | |
407 | 18.3k | if (pc->Width <= 0) { |
408 | 0 | pc->Width = w; |
409 | 0 | vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, |
410 | 0 | "Invalid frame width"); |
411 | 0 | } |
412 | | |
413 | 18.3k | if (pc->Height <= 0) { |
414 | 0 | pc->Height = h; |
415 | 0 | vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, |
416 | 0 | "Invalid frame height"); |
417 | 0 | } |
418 | | |
419 | 18.3k | #if CONFIG_MULTITHREAD |
420 | 18.3k | if (vpx_atomic_load_acquire(&pbi->b_multithreaded_rd)) { |
421 | 16.7k | vp8mt_de_alloc_temp_buffers(pbi, pc->mb_rows); |
422 | 16.7k | } |
423 | 18.3k | #endif |
424 | | |
425 | 18.3k | if (vp8_alloc_frame_buffers(pc, pc->Width, pc->Height)) { |
426 | 0 | vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR, |
427 | 0 | "Failed to allocate frame buffers"); |
428 | 0 | } |
429 | | |
430 | 18.3k | xd->pre = pc->yv12_fb[pc->lst_fb_idx]; |
431 | 18.3k | xd->dst = pc->yv12_fb[pc->new_fb_idx]; |
432 | | |
433 | 18.3k | #if CONFIG_MULTITHREAD |
434 | 133k | for (i = 0; i < pbi->allocated_decoding_thread_count; ++i) { |
435 | 114k | pbi->mb_row_di[i].mbd.dst = pc->yv12_fb[pc->new_fb_idx]; |
436 | 114k | vp8_build_block_doffsets(&pbi->mb_row_di[i].mbd); |
437 | 114k | } |
438 | 18.3k | #endif |
439 | 18.3k | 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 | 18.3k | #if CONFIG_MULTITHREAD |
468 | 18.3k | if (vpx_atomic_load_acquire(&pbi->b_multithreaded_rd)) { |
469 | 16.7k | vp8mt_alloc_temp_buffers(pbi, pc->Width, 0); |
470 | 16.7k | } |
471 | 18.3k | #endif |
472 | 18.3k | } |
473 | | |
474 | 0 | pbi->common.error.setjmp = 0; |
475 | | |
476 | | /* required to get past the first get_free_fb() call */ |
477 | 18.3k | pbi->common.fb_idx_ref_cnt[0] = 0; |
478 | 18.3k | } |
479 | | |
480 | 77.7k | if (setjmp(pbi->common.error.jmp)) { |
481 | 21.9k | 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 | 21.9k | pc->yv12_fb[pc->lst_fb_idx].corrupted = 1; |
487 | | |
488 | 21.9k | if (pc->fb_idx_ref_cnt[pc->new_fb_idx] > 0) { |
489 | 21.9k | pc->fb_idx_ref_cnt[pc->new_fb_idx]--; |
490 | 21.9k | } |
491 | 21.9k | pbi->common.error.setjmp = 0; |
492 | 21.9k | #if CONFIG_MULTITHREAD |
493 | 21.9k | if (pbi->restart_threads) { |
494 | 2.58k | ctx->si.w = 0; |
495 | 2.58k | ctx->si.h = 0; |
496 | 2.58k | ctx->restart_threads = 1; |
497 | 2.58k | } |
498 | 21.9k | #endif |
499 | 21.9k | res = update_error_state(ctx, &pbi->common.error); |
500 | 21.9k | return res; |
501 | 21.9k | } |
502 | | |
503 | 55.8k | pbi->common.error.setjmp = 1; |
504 | | |
505 | | /* update the pbi fragment data */ |
506 | 55.8k | pbi->fragments = ctx->fragments; |
507 | 55.8k | #if CONFIG_MULTITHREAD |
508 | 55.8k | pbi->restart_threads = 0; |
509 | 55.8k | #endif |
510 | 55.8k | ctx->user_priv = user_priv; |
511 | 55.8k | if (vp8dx_receive_compressed_data(pbi)) { |
512 | 457 | res = update_error_state(ctx, &pbi->common.error); |
513 | 457 | } |
514 | | |
515 | | /* get ready for the next series of fragments */ |
516 | 55.8k | ctx->fragments.count = 0; |
517 | 55.8k | pbi->common.error.setjmp = 0; |
518 | 55.8k | } |
519 | | |
520 | 60.5k | return res; |
521 | 82.4k | } |
522 | | |
523 | | static vpx_image_t *vp8_get_frame(vpx_codec_alg_priv_t *ctx, |
524 | 119k | vpx_codec_iter_t *iter) { |
525 | 119k | 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 | 119k | if (!(*iter) && ctx->yv12_frame_buffers.pbi[0]) { |
531 | 91.4k | YV12_BUFFER_CONFIG sd; |
532 | 91.4k | vp8_ppflags_t flags; |
533 | 91.4k | vp8_zero(flags); |
534 | | |
535 | 91.4k | if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) { |
536 | 0 | flags.post_proc_flag = ctx->postproc_cfg.post_proc_flag; |
537 | 0 | flags.deblocking_level = ctx->postproc_cfg.deblocking_level; |
538 | 0 | flags.noise_level = ctx->postproc_cfg.noise_level; |
539 | 0 | } |
540 | | |
541 | 91.4k | if (0 == vp8dx_get_raw_frame(ctx->yv12_frame_buffers.pbi[0], &sd, &flags)) { |
542 | 26.1k | yuvconfig2image(&ctx->img, &sd, ctx->user_priv); |
543 | | |
544 | 26.1k | img = &ctx->img; |
545 | 26.1k | *iter = img; |
546 | 26.1k | } |
547 | 91.4k | } |
548 | | |
549 | 119k | return img; |
550 | 119k | } |
551 | | |
552 | | static vpx_codec_err_t image2yuvconfig(const vpx_image_t *img, |
553 | 0 | YV12_BUFFER_CONFIG *yv12) { |
554 | 0 | const int y_w = img->d_w; |
555 | 0 | const int y_h = img->d_h; |
556 | 0 | const int uv_w = (img->d_w + 1) / 2; |
557 | 0 | const int uv_h = (img->d_h + 1) / 2; |
558 | 0 | vpx_codec_err_t res = VPX_CODEC_OK; |
559 | 0 | yv12->y_buffer = img->planes[VPX_PLANE_Y]; |
560 | 0 | yv12->u_buffer = img->planes[VPX_PLANE_U]; |
561 | 0 | yv12->v_buffer = img->planes[VPX_PLANE_V]; |
562 | |
|
563 | 0 | yv12->y_crop_width = y_w; |
564 | 0 | yv12->y_crop_height = y_h; |
565 | 0 | yv12->y_width = y_w; |
566 | 0 | yv12->y_height = y_h; |
567 | 0 | yv12->uv_crop_width = uv_w; |
568 | 0 | yv12->uv_crop_height = uv_h; |
569 | 0 | yv12->uv_width = uv_w; |
570 | 0 | yv12->uv_height = uv_h; |
571 | |
|
572 | 0 | yv12->y_stride = img->stride[VPX_PLANE_Y]; |
573 | 0 | yv12->uv_stride = img->stride[VPX_PLANE_U]; |
574 | |
|
575 | 0 | yv12->border = (img->stride[VPX_PLANE_Y] - img->d_w) / 2; |
576 | 0 | return res; |
577 | 0 | } |
578 | | |
579 | | static vpx_codec_err_t vp8_set_reference(vpx_codec_alg_priv_t *ctx, |
580 | 0 | va_list args) { |
581 | 0 | vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *); |
582 | |
|
583 | 0 | if (data) { |
584 | 0 | vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data; |
585 | 0 | YV12_BUFFER_CONFIG sd; |
586 | |
|
587 | 0 | image2yuvconfig(&frame->img, &sd); |
588 | |
|
589 | 0 | return vp8dx_set_reference(ctx->yv12_frame_buffers.pbi[0], |
590 | 0 | frame->frame_type, &sd); |
591 | 0 | } else { |
592 | 0 | return VPX_CODEC_INVALID_PARAM; |
593 | 0 | } |
594 | 0 | } |
595 | | |
596 | | static vpx_codec_err_t vp8_get_reference(vpx_codec_alg_priv_t *ctx, |
597 | 0 | va_list args) { |
598 | 0 | vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *); |
599 | |
|
600 | 0 | if (data) { |
601 | 0 | vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data; |
602 | 0 | YV12_BUFFER_CONFIG sd; |
603 | |
|
604 | 0 | image2yuvconfig(&frame->img, &sd); |
605 | |
|
606 | 0 | return vp8dx_get_reference(ctx->yv12_frame_buffers.pbi[0], |
607 | 0 | frame->frame_type, &sd); |
608 | 0 | } else { |
609 | 0 | return VPX_CODEC_INVALID_PARAM; |
610 | 0 | } |
611 | 0 | } |
612 | | |
613 | | static vpx_codec_err_t vp8_get_quantizer(vpx_codec_alg_priv_t *ctx, |
614 | 0 | va_list args) { |
615 | 0 | int *const arg = va_arg(args, int *); |
616 | 0 | VP8D_COMP *pbi = ctx->yv12_frame_buffers.pbi[0]; |
617 | 0 | if (arg == NULL) return VPX_CODEC_INVALID_PARAM; |
618 | 0 | if (pbi == NULL) return VPX_CODEC_CORRUPT_FRAME; |
619 | 0 | *arg = vp8dx_get_quantizer(pbi); |
620 | 0 | return VPX_CODEC_OK; |
621 | 0 | } |
622 | | |
623 | | static vpx_codec_err_t vp8_set_postproc(vpx_codec_alg_priv_t *ctx, |
624 | 0 | va_list args) { |
625 | 0 | #if CONFIG_POSTPROC |
626 | 0 | vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *); |
627 | |
|
628 | 0 | if (data) { |
629 | 0 | ctx->postproc_cfg_set = 1; |
630 | 0 | ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data); |
631 | 0 | return VPX_CODEC_OK; |
632 | 0 | } else { |
633 | 0 | return VPX_CODEC_INVALID_PARAM; |
634 | 0 | } |
635 | |
|
636 | | #else |
637 | | (void)ctx; |
638 | | (void)args; |
639 | | return VPX_CODEC_INCAPABLE; |
640 | | #endif |
641 | 0 | } |
642 | | |
643 | | static vpx_codec_err_t vp8_get_last_ref_updates(vpx_codec_alg_priv_t *ctx, |
644 | 0 | va_list args) { |
645 | 0 | int *update_info = va_arg(args, int *); |
646 | |
|
647 | 0 | if (update_info) { |
648 | 0 | VP8D_COMP *pbi = (VP8D_COMP *)ctx->yv12_frame_buffers.pbi[0]; |
649 | 0 | if (pbi == NULL) return VPX_CODEC_CORRUPT_FRAME; |
650 | | |
651 | 0 | *update_info = pbi->common.refresh_alt_ref_frame * (int)VP8_ALTR_FRAME + |
652 | 0 | pbi->common.refresh_golden_frame * (int)VP8_GOLD_FRAME + |
653 | 0 | pbi->common.refresh_last_frame * (int)VP8_LAST_FRAME; |
654 | |
|
655 | 0 | return VPX_CODEC_OK; |
656 | 0 | } else { |
657 | 0 | return VPX_CODEC_INVALID_PARAM; |
658 | 0 | } |
659 | 0 | } |
660 | | |
661 | | static vpx_codec_err_t vp8_get_last_ref_frame(vpx_codec_alg_priv_t *ctx, |
662 | 0 | va_list args) { |
663 | 0 | int *ref_info = va_arg(args, int *); |
664 | |
|
665 | 0 | if (ref_info) { |
666 | 0 | VP8D_COMP *pbi = (VP8D_COMP *)ctx->yv12_frame_buffers.pbi[0]; |
667 | 0 | if (pbi) { |
668 | 0 | VP8_COMMON *oci = &pbi->common; |
669 | 0 | *ref_info = |
670 | 0 | (vp8dx_references_buffer(oci, ALTREF_FRAME) ? VP8_ALTR_FRAME : 0) | |
671 | 0 | (vp8dx_references_buffer(oci, GOLDEN_FRAME) ? VP8_GOLD_FRAME : 0) | |
672 | 0 | (vp8dx_references_buffer(oci, LAST_FRAME) ? VP8_LAST_FRAME : 0); |
673 | 0 | return VPX_CODEC_OK; |
674 | 0 | } else { |
675 | 0 | return VPX_CODEC_CORRUPT_FRAME; |
676 | 0 | } |
677 | 0 | } else { |
678 | 0 | return VPX_CODEC_INVALID_PARAM; |
679 | 0 | } |
680 | 0 | } |
681 | | |
682 | | static vpx_codec_err_t vp8_get_frame_corrupted(vpx_codec_alg_priv_t *ctx, |
683 | 0 | va_list args) { |
684 | 0 | int *corrupted = va_arg(args, int *); |
685 | 0 | VP8D_COMP *pbi = (VP8D_COMP *)ctx->yv12_frame_buffers.pbi[0]; |
686 | |
|
687 | 0 | if (corrupted && pbi) { |
688 | 0 | const YV12_BUFFER_CONFIG *const frame = pbi->common.frame_to_show; |
689 | 0 | if (frame == NULL) return VPX_CODEC_ERROR; |
690 | 0 | *corrupted = frame->corrupted; |
691 | 0 | return VPX_CODEC_OK; |
692 | 0 | } else { |
693 | 0 | return VPX_CODEC_INVALID_PARAM; |
694 | 0 | } |
695 | 0 | } |
696 | | |
697 | | static vpx_codec_err_t vp8_set_decryptor(vpx_codec_alg_priv_t *ctx, |
698 | 0 | va_list args) { |
699 | 0 | vpx_decrypt_init *init = va_arg(args, vpx_decrypt_init *); |
700 | |
|
701 | 0 | if (init) { |
702 | 0 | ctx->decrypt_cb = init->decrypt_cb; |
703 | 0 | ctx->decrypt_state = init->decrypt_state; |
704 | 0 | } else { |
705 | 0 | ctx->decrypt_cb = NULL; |
706 | 0 | ctx->decrypt_state = NULL; |
707 | 0 | } |
708 | 0 | return VPX_CODEC_OK; |
709 | 0 | } |
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 | | NULL /* vpx_codec_enc_mr_free_mem_loc_fn_t */ |
752 | | } |
753 | | }; |