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