Commit | Line | Data |
---|---|---|
123ccd07 MT |
1 | /* |
2 | * This file is part of Libav. | |
3 | * | |
4 | * Libav is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU Lesser General Public | |
6 | * License as published by the Free Software Foundation; either | |
7 | * version 2.1 of the License, or (at your option) any later version. | |
8 | * | |
9 | * Libav is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 | * Lesser General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU Lesser General Public | |
15 | * License along with Libav; if not, write to the Free Software | |
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
17 | */ | |
18 | ||
19 | #include "libavutil/avassert.h" | |
20 | #include "libavutil/common.h" | |
21 | ||
22 | #include "avcodec.h" | |
23 | #include "internal.h" | |
24 | #include "vaapi_decode.h" | |
25 | ||
26 | ||
27 | int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx, | |
28 | VAAPIDecodePicture *pic, | |
29 | int type, | |
30 | const void *data, | |
31 | size_t size) | |
32 | { | |
33 | VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; | |
34 | VAStatus vas; | |
35 | VABufferID buffer; | |
36 | ||
37 | av_assert0(pic->nb_param_buffers + 1 <= MAX_PARAM_BUFFERS); | |
38 | ||
39 | vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, | |
40 | type, size, 1, (void*)data, &buffer); | |
41 | if (vas != VA_STATUS_SUCCESS) { | |
42 | av_log(avctx, AV_LOG_ERROR, "Failed to create parameter " | |
43 | "buffer (type %d): %d (%s).\n", | |
44 | type, vas, vaErrorStr(vas)); | |
45 | return AVERROR(EIO); | |
46 | } | |
47 | ||
48 | pic->param_buffers[pic->nb_param_buffers++] = buffer; | |
49 | ||
50 | av_log(avctx, AV_LOG_DEBUG, "Param buffer (type %d, %zu bytes) " | |
51 | "is %#x.\n", type, size, buffer); | |
52 | return 0; | |
53 | } | |
54 | ||
55 | ||
56 | int ff_vaapi_decode_make_slice_buffer(AVCodecContext *avctx, | |
57 | VAAPIDecodePicture *pic, | |
58 | const void *params_data, | |
59 | size_t params_size, | |
60 | const void *slice_data, | |
61 | size_t slice_size) | |
62 | { | |
63 | VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; | |
64 | VAStatus vas; | |
65 | int index; | |
66 | ||
67 | av_assert0(pic->nb_slices <= pic->slices_allocated); | |
68 | if (pic->nb_slices == pic->slices_allocated) { | |
69 | if (pic->slices_allocated > 0) | |
70 | pic->slices_allocated *= 2; | |
71 | else | |
72 | pic->slices_allocated = 64; | |
73 | ||
74 | pic->slice_buffers = | |
75 | av_realloc_array(pic->slice_buffers, | |
76 | pic->slices_allocated, | |
77 | 2 * sizeof(*pic->slice_buffers)); | |
78 | if (!pic->slice_buffers) | |
79 | return AVERROR(ENOMEM); | |
80 | } | |
81 | av_assert0(pic->nb_slices + 1 <= pic->slices_allocated); | |
82 | ||
83 | index = 2 * pic->nb_slices; | |
84 | ||
85 | vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, | |
86 | VASliceParameterBufferType, | |
87 | params_size, 1, (void*)params_data, | |
88 | &pic->slice_buffers[index]); | |
89 | if (vas != VA_STATUS_SUCCESS) { | |
90 | av_log(avctx, AV_LOG_ERROR, "Failed to create slice " | |
91 | "parameter buffer: %d (%s).\n", vas, vaErrorStr(vas)); | |
92 | return AVERROR(EIO); | |
93 | } | |
94 | ||
95 | av_log(avctx, AV_LOG_DEBUG, "Slice %d param buffer (%zu bytes) " | |
96 | "is %#x.\n", pic->nb_slices, params_size, | |
97 | pic->slice_buffers[index]); | |
98 | ||
99 | vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, | |
100 | VASliceDataBufferType, | |
101 | slice_size, 1, (void*)slice_data, | |
102 | &pic->slice_buffers[index + 1]); | |
103 | if (vas != VA_STATUS_SUCCESS) { | |
104 | av_log(avctx, AV_LOG_ERROR, "Failed to create slice " | |
105 | "data buffer (size %zu): %d (%s).\n", | |
106 | slice_size, vas, vaErrorStr(vas)); | |
107 | vaDestroyBuffer(ctx->hwctx->display, | |
108 | pic->slice_buffers[index]); | |
109 | return AVERROR(EIO); | |
110 | } | |
111 | ||
112 | av_log(avctx, AV_LOG_DEBUG, "Slice %d data buffer (%zu bytes) " | |
113 | "is %#x.\n", pic->nb_slices, slice_size, | |
114 | pic->slice_buffers[index + 1]); | |
115 | ||
116 | ++pic->nb_slices; | |
117 | return 0; | |
118 | } | |
119 | ||
120 | static void ff_vaapi_decode_destroy_buffers(AVCodecContext *avctx, | |
121 | VAAPIDecodePicture *pic) | |
122 | { | |
123 | VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; | |
124 | VAStatus vas; | |
125 | int i; | |
126 | ||
127 | for (i = 0; i < pic->nb_param_buffers; i++) { | |
128 | vas = vaDestroyBuffer(ctx->hwctx->display, | |
129 | pic->param_buffers[i]); | |
130 | if (vas != VA_STATUS_SUCCESS) { | |
131 | av_log(avctx, AV_LOG_ERROR, "Failed to destroy " | |
132 | "parameter buffer %#x: %d (%s).\n", | |
133 | pic->param_buffers[i], vas, vaErrorStr(vas)); | |
134 | } | |
135 | } | |
136 | ||
137 | for (i = 0; i < 2 * pic->nb_slices; i++) { | |
138 | vas = vaDestroyBuffer(ctx->hwctx->display, | |
139 | pic->slice_buffers[i]); | |
140 | if (vas != VA_STATUS_SUCCESS) { | |
141 | av_log(avctx, AV_LOG_ERROR, "Failed to destroy slice " | |
142 | "slice buffer %#x: %d (%s).\n", | |
143 | pic->slice_buffers[i], vas, vaErrorStr(vas)); | |
144 | } | |
145 | } | |
146 | } | |
147 | ||
148 | int ff_vaapi_decode_issue(AVCodecContext *avctx, | |
149 | VAAPIDecodePicture *pic) | |
150 | { | |
151 | VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; | |
152 | VAStatus vas; | |
0aec37e6 | 153 | int err; |
123ccd07 MT |
154 | |
155 | av_log(avctx, AV_LOG_DEBUG, "Decode to surface %#x.\n", | |
156 | pic->output_surface); | |
157 | ||
123ccd07 MT |
158 | vas = vaBeginPicture(ctx->hwctx->display, ctx->va_context, |
159 | pic->output_surface); | |
160 | if (vas != VA_STATUS_SUCCESS) { | |
161 | av_log(avctx, AV_LOG_ERROR, "Failed to begin picture decode " | |
162 | "issue: %d (%s).\n", vas, vaErrorStr(vas)); | |
163 | err = AVERROR(EIO); | |
164 | goto fail_with_picture; | |
165 | } | |
166 | ||
167 | vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context, | |
168 | pic->param_buffers, pic->nb_param_buffers); | |
169 | if (vas != VA_STATUS_SUCCESS) { | |
170 | av_log(avctx, AV_LOG_ERROR, "Failed to upload decode " | |
171 | "parameters: %d (%s).\n", vas, vaErrorStr(vas)); | |
172 | err = AVERROR(EIO); | |
173 | goto fail_with_picture; | |
174 | } | |
175 | ||
176 | vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context, | |
177 | pic->slice_buffers, 2 * pic->nb_slices); | |
178 | if (vas != VA_STATUS_SUCCESS) { | |
179 | av_log(avctx, AV_LOG_ERROR, "Failed to upload slices: " | |
180 | "%d (%s).\n", vas, vaErrorStr(vas)); | |
181 | err = AVERROR(EIO); | |
182 | goto fail_with_picture; | |
183 | } | |
184 | ||
185 | vas = vaEndPicture(ctx->hwctx->display, ctx->va_context); | |
186 | if (vas != VA_STATUS_SUCCESS) { | |
187 | av_log(avctx, AV_LOG_ERROR, "Failed to end picture decode " | |
188 | "issue: %d (%s).\n", vas, vaErrorStr(vas)); | |
189 | err = AVERROR(EIO); | |
190 | if (ctx->hwctx->driver_quirks & | |
191 | AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS) | |
192 | goto fail; | |
193 | else | |
194 | goto fail_at_end; | |
195 | } | |
196 | ||
197 | if (ctx->hwctx->driver_quirks & | |
198 | AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS) | |
199 | ff_vaapi_decode_destroy_buffers(avctx, pic); | |
200 | ||
5e879b54 | 201 | pic->nb_param_buffers = 0; |
123ccd07 MT |
202 | pic->nb_slices = 0; |
203 | pic->slices_allocated = 0; | |
204 | av_freep(&pic->slice_buffers); | |
205 | ||
206 | return 0; | |
207 | ||
208 | fail_with_picture: | |
209 | vas = vaEndPicture(ctx->hwctx->display, ctx->va_context); | |
210 | if (vas != VA_STATUS_SUCCESS) { | |
211 | av_log(avctx, AV_LOG_ERROR, "Failed to end picture decode " | |
212 | "after error: %d (%s).\n", vas, vaErrorStr(vas)); | |
213 | } | |
214 | fail: | |
215 | ff_vaapi_decode_destroy_buffers(avctx, pic); | |
216 | fail_at_end: | |
217 | return err; | |
218 | } | |
219 | ||
220 | int ff_vaapi_decode_cancel(AVCodecContext *avctx, | |
221 | VAAPIDecodePicture *pic) | |
222 | { | |
223 | ff_vaapi_decode_destroy_buffers(avctx, pic); | |
224 | ||
225 | pic->nb_param_buffers = 0; | |
226 | pic->nb_slices = 0; | |
227 | pic->slices_allocated = 0; | |
228 | av_freep(&pic->slice_buffers); | |
229 | ||
230 | return 0; | |
231 | } | |
232 | ||
233 | static const struct { | |
234 | enum AVCodecID codec_id; | |
235 | int codec_profile; | |
236 | VAProfile va_profile; | |
237 | } vaapi_profile_map[] = { | |
238 | #define MAP(c, p, v) { AV_CODEC_ID_ ## c, FF_PROFILE_ ## p, VAProfile ## v } | |
239 | MAP(MPEG2VIDEO, MPEG2_SIMPLE, MPEG2Simple ), | |
240 | MAP(MPEG2VIDEO, MPEG2_MAIN, MPEG2Main ), | |
241 | MAP(H263, UNKNOWN, H263Baseline), | |
242 | MAP(MPEG4, MPEG4_SIMPLE, MPEG4Simple ), | |
243 | MAP(MPEG4, MPEG4_ADVANCED_SIMPLE, | |
244 | MPEG4AdvancedSimple), | |
245 | MAP(MPEG4, MPEG4_MAIN, MPEG4Main ), | |
246 | MAP(H264, H264_CONSTRAINED_BASELINE, | |
247 | H264ConstrainedBaseline), | |
248 | MAP(H264, H264_BASELINE, H264Baseline), | |
249 | MAP(H264, H264_MAIN, H264Main ), | |
250 | MAP(H264, H264_HIGH, H264High ), | |
251 | #if VA_CHECK_VERSION(0, 37, 0) | |
252 | MAP(HEVC, HEVC_MAIN, HEVCMain ), | |
253 | #endif | |
254 | MAP(WMV3, VC1_SIMPLE, VC1Simple ), | |
255 | MAP(WMV3, VC1_MAIN, VC1Main ), | |
256 | MAP(WMV3, VC1_COMPLEX, VC1Advanced ), | |
257 | MAP(WMV3, VC1_ADVANCED, VC1Advanced ), | |
258 | MAP(VC1, VC1_SIMPLE, VC1Simple ), | |
259 | MAP(VC1, VC1_MAIN, VC1Main ), | |
260 | MAP(VC1, VC1_COMPLEX, VC1Advanced ), | |
261 | MAP(VC1, VC1_ADVANCED, VC1Advanced ), | |
262 | #if VA_CHECK_VERSION(0, 35, 0) | |
263 | MAP(VP8, UNKNOWN, VP8Version0_3 ), | |
264 | #endif | |
265 | #if VA_CHECK_VERSION(0, 38, 0) | |
266 | MAP(VP9, VP9_0, VP9Profile0 ), | |
267 | #endif | |
268 | #undef MAP | |
269 | }; | |
270 | ||
271 | static int vaapi_decode_make_config(AVCodecContext *avctx) | |
272 | { | |
273 | VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; | |
274 | ||
275 | AVVAAPIHWConfig *hwconfig = NULL; | |
276 | AVHWFramesConstraints *constraints = NULL; | |
277 | VAStatus vas; | |
278 | int err, i, j; | |
279 | const AVCodecDescriptor *codec_desc; | |
280 | VAProfile profile, *profile_list = NULL; | |
281 | int profile_count, exact_match, alt_profile; | |
282 | ||
283 | // Allowing a profile mismatch can be useful because streams may | |
284 | // over-declare their required capabilities - in particular, many | |
285 | // H.264 baseline profile streams (notably some of those in FATE) | |
286 | // only use the feature set of constrained baseline. This flag | |
287 | // would have to be be set by some external means in order to | |
288 | // actually be useful. (AV_HWACCEL_FLAG_IGNORE_PROFILE?) | |
289 | int allow_profile_mismatch = 0; | |
290 | ||
291 | codec_desc = avcodec_descriptor_get(avctx->codec_id); | |
292 | if (!codec_desc) { | |
293 | err = AVERROR(EINVAL); | |
294 | goto fail; | |
295 | } | |
296 | ||
297 | profile_count = vaMaxNumProfiles(ctx->hwctx->display); | |
298 | profile_list = av_malloc_array(profile_count, | |
299 | sizeof(VAProfile)); | |
300 | if (!profile_list) { | |
301 | err = AVERROR(ENOMEM); | |
302 | goto fail; | |
303 | } | |
304 | ||
305 | vas = vaQueryConfigProfiles(ctx->hwctx->display, | |
306 | profile_list, &profile_count); | |
307 | if (vas != VA_STATUS_SUCCESS) { | |
308 | av_log(ctx, AV_LOG_ERROR, "Failed to query profiles: " | |
309 | "%d (%s).\n", vas, vaErrorStr(vas)); | |
310 | err = AVERROR(ENOSYS); | |
311 | goto fail; | |
312 | } | |
313 | ||
314 | profile = VAProfileNone; | |
315 | exact_match = 0; | |
316 | ||
317 | for (i = 0; i < FF_ARRAY_ELEMS(vaapi_profile_map); i++) { | |
318 | int profile_match = 0; | |
319 | if (avctx->codec_id != vaapi_profile_map[i].codec_id) | |
320 | continue; | |
11c191b5 MT |
321 | if (avctx->profile == vaapi_profile_map[i].codec_profile || |
322 | vaapi_profile_map[i].codec_profile == FF_PROFILE_UNKNOWN) | |
123ccd07 MT |
323 | profile_match = 1; |
324 | profile = vaapi_profile_map[i].va_profile; | |
325 | for (j = 0; j < profile_count; j++) { | |
326 | if (profile == profile_list[j]) { | |
327 | exact_match = profile_match; | |
328 | break; | |
329 | } | |
330 | } | |
331 | if (j < profile_count) { | |
332 | if (exact_match) | |
333 | break; | |
334 | alt_profile = vaapi_profile_map[i].codec_profile; | |
335 | } | |
336 | } | |
337 | av_freep(&profile_list); | |
338 | ||
339 | if (profile == VAProfileNone) { | |
340 | av_log(ctx, AV_LOG_ERROR, "No support for codec %s " | |
341 | "profile %d.\n", codec_desc->name, avctx->profile); | |
342 | err = AVERROR(ENOSYS); | |
343 | goto fail; | |
344 | } | |
345 | if (!exact_match) { | |
346 | if (allow_profile_mismatch) { | |
347 | av_log(avctx, AV_LOG_VERBOSE, "Codec %s profile %d not " | |
348 | "supported for hardware decode.\n", | |
349 | codec_desc->name, avctx->profile); | |
350 | av_log(avctx, AV_LOG_WARNING, "Using possibly-" | |
351 | "incompatible profile %d instead.\n", | |
352 | alt_profile); | |
353 | } else { | |
354 | av_log(avctx, AV_LOG_VERBOSE, "Codec %s profile %d not " | |
355 | "supported for hardware decode.\n", | |
356 | codec_desc->name, avctx->profile); | |
357 | err = AVERROR(EINVAL); | |
358 | goto fail; | |
359 | } | |
360 | } | |
361 | ||
362 | ctx->va_profile = profile; | |
363 | ctx->va_entrypoint = VAEntrypointVLD; | |
364 | ||
365 | vas = vaCreateConfig(ctx->hwctx->display, ctx->va_profile, | |
366 | ctx->va_entrypoint, NULL, 0, | |
367 | &ctx->va_config); | |
368 | if (vas != VA_STATUS_SUCCESS) { | |
369 | av_log(avctx, AV_LOG_ERROR, "Failed to create decode " | |
370 | "configuration: %d (%s).\n", vas, vaErrorStr(vas)); | |
371 | err = AVERROR(EIO); | |
372 | goto fail; | |
373 | } | |
374 | ||
375 | hwconfig = av_hwdevice_hwconfig_alloc(ctx->frames->device_ref); | |
376 | if (!hwconfig) { | |
377 | err = AVERROR(ENOMEM); | |
378 | goto fail; | |
379 | } | |
380 | hwconfig->config_id = ctx->va_config; | |
381 | ||
382 | constraints = | |
383 | av_hwdevice_get_hwframe_constraints(ctx->frames->device_ref, | |
384 | hwconfig); | |
385 | if (!constraints) { | |
386 | // Ignore. | |
387 | } else { | |
388 | if (avctx->coded_width < constraints->min_width || | |
389 | avctx->coded_height < constraints->min_height || | |
390 | avctx->coded_width > constraints->max_width || | |
391 | avctx->coded_height > constraints->max_height) { | |
392 | av_log(ctx, AV_LOG_ERROR, "Hardware does not support image " | |
393 | "size %dx%d (constraints: width %d-%d height %d-%d).\n", | |
394 | avctx->coded_width, avctx->coded_height, | |
395 | constraints->min_width, constraints->max_width, | |
396 | constraints->min_height, constraints->max_height); | |
397 | err = AVERROR(EINVAL); | |
398 | goto fail; | |
399 | } | |
400 | } | |
401 | ||
402 | av_hwframe_constraints_free(&constraints); | |
403 | av_freep(&hwconfig); | |
404 | ||
405 | return 0; | |
406 | ||
407 | fail: | |
408 | av_hwframe_constraints_free(&constraints); | |
409 | av_freep(&hwconfig); | |
410 | if (ctx->va_config != VA_INVALID_ID) { | |
411 | vaDestroyConfig(ctx->hwctx->display, ctx->va_config); | |
412 | ctx->va_config = VA_INVALID_ID; | |
413 | } | |
414 | av_freep(&profile_list); | |
415 | return err; | |
416 | } | |
417 | ||
418 | int ff_vaapi_decode_init(AVCodecContext *avctx) | |
419 | { | |
420 | VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; | |
421 | VAStatus vas; | |
422 | int err; | |
423 | ||
424 | ctx->va_config = VA_INVALID_ID; | |
425 | ctx->va_context = VA_INVALID_ID; | |
426 | ||
851960f6 | 427 | #if FF_API_VAAPI_CONTEXT |
123ccd07 MT |
428 | if (avctx->hwaccel_context) { |
429 | av_log(avctx, AV_LOG_WARNING, "Using deprecated struct " | |
430 | "vaapi_context in decode.\n"); | |
431 | ||
432 | ctx->have_old_context = 1; | |
433 | ctx->old_context = avctx->hwaccel_context; | |
434 | ||
435 | // Really we only want the VAAPI device context, but this | |
436 | // allocates a whole generic device context because we don't | |
437 | // have any other way to determine how big it should be. | |
438 | ctx->device_ref = | |
439 | av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VAAPI); | |
440 | if (!ctx->device_ref) { | |
441 | err = AVERROR(ENOMEM); | |
442 | goto fail; | |
443 | } | |
444 | ctx->device = (AVHWDeviceContext*)ctx->device_ref->data; | |
445 | ctx->hwctx = ctx->device->hwctx; | |
446 | ||
447 | ctx->hwctx->display = ctx->old_context->display; | |
448 | ||
449 | // The old VAAPI decode setup assumed this quirk was always | |
450 | // present, so set it here to avoid the behaviour changing. | |
451 | ctx->hwctx->driver_quirks = | |
452 | AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS; | |
453 | ||
851960f6 MT |
454 | } else |
455 | #endif | |
456 | if (avctx->hw_frames_ctx) { | |
123ccd07 MT |
457 | // This structure has a shorter lifetime than the enclosing |
458 | // AVCodecContext, so we inherit the references from there | |
459 | // and do not need to make separate ones. | |
460 | ||
461 | ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data; | |
462 | ctx->hwfc = ctx->frames->hwctx; | |
463 | ||
464 | ctx->device = ctx->frames->device_ctx; | |
465 | ctx->hwctx = ctx->device->hwctx; | |
466 | ||
467 | } else { | |
468 | av_log(avctx, AV_LOG_ERROR, "A hardware frames context is " | |
469 | "required for VAAPI decoding.\n"); | |
470 | err = AVERROR(EINVAL); | |
471 | goto fail; | |
472 | } | |
473 | ||
851960f6 | 474 | #if FF_API_VAAPI_CONTEXT |
123ccd07 MT |
475 | if (ctx->have_old_context) { |
476 | ctx->va_config = ctx->old_context->config_id; | |
477 | ctx->va_context = ctx->old_context->context_id; | |
478 | ||
479 | av_log(avctx, AV_LOG_DEBUG, "Using user-supplied decoder " | |
480 | "context: %#x/%#x.\n", ctx->va_config, ctx->va_context); | |
481 | } else { | |
851960f6 | 482 | #endif |
123ccd07 | 483 | |
851960f6 MT |
484 | err = vaapi_decode_make_config(avctx); |
485 | if (err) | |
486 | goto fail; | |
123ccd07 | 487 | |
851960f6 MT |
488 | vas = vaCreateContext(ctx->hwctx->display, ctx->va_config, |
489 | avctx->coded_width, avctx->coded_height, | |
490 | VA_PROGRESSIVE, | |
491 | ctx->hwfc->surface_ids, | |
492 | ctx->hwfc->nb_surfaces, | |
493 | &ctx->va_context); | |
494 | if (vas != VA_STATUS_SUCCESS) { | |
495 | av_log(avctx, AV_LOG_ERROR, "Failed to create decode " | |
496 | "context: %d (%s).\n", vas, vaErrorStr(vas)); | |
497 | err = AVERROR(EIO); | |
498 | goto fail; | |
123ccd07 MT |
499 | } |
500 | ||
851960f6 MT |
501 | av_log(avctx, AV_LOG_DEBUG, "Decode context initialised: " |
502 | "%#x/%#x.\n", ctx->va_config, ctx->va_context); | |
503 | #if FF_API_VAAPI_CONTEXT | |
504 | } | |
505 | #endif | |
506 | ||
123ccd07 MT |
507 | return 0; |
508 | ||
509 | fail: | |
510 | ff_vaapi_decode_uninit(avctx); | |
511 | return err; | |
512 | } | |
513 | ||
514 | int ff_vaapi_decode_uninit(AVCodecContext *avctx) | |
515 | { | |
516 | VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; | |
517 | VAStatus vas; | |
518 | ||
851960f6 | 519 | #if FF_API_VAAPI_CONTEXT |
123ccd07 MT |
520 | if (ctx->have_old_context) { |
521 | av_buffer_unref(&ctx->device_ref); | |
522 | } else { | |
851960f6 MT |
523 | #endif |
524 | ||
525 | if (ctx->va_context != VA_INVALID_ID) { | |
526 | vas = vaDestroyContext(ctx->hwctx->display, ctx->va_context); | |
527 | if (vas != VA_STATUS_SUCCESS) { | |
528 | av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode " | |
529 | "context %#x: %d (%s).\n", | |
530 | ctx->va_context, vas, vaErrorStr(vas)); | |
123ccd07 | 531 | } |
851960f6 MT |
532 | } |
533 | if (ctx->va_config != VA_INVALID_ID) { | |
534 | vas = vaDestroyConfig(ctx->hwctx->display, ctx->va_config); | |
535 | if (vas != VA_STATUS_SUCCESS) { | |
536 | av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode " | |
537 | "configuration %#x: %d (%s).\n", | |
538 | ctx->va_config, vas, vaErrorStr(vas)); | |
123ccd07 MT |
539 | } |
540 | } | |
541 | ||
851960f6 MT |
542 | #if FF_API_VAAPI_CONTEXT |
543 | } | |
544 | #endif | |
545 | ||
123ccd07 MT |
546 | return 0; |
547 | } |