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