2 * This file is part of FFmpeg.
4 * FFmpeg 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.
9 * FFmpeg 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.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 #include "config_components.h"
21 #include "libavutil/avassert.h"
22 #include "libavutil/common.h"
23 #include "libavutil/pixdesc.h"
28 #include "vaapi_decode.h"
29 #include "vaapi_hevc.h"
32 int ff_vaapi_decode_make_param_buffer(AVCodecContext
*avctx
,
33 VAAPIDecodePicture
*pic
,
38 VAAPIDecodeContext
*ctx
= avctx
->internal
->hwaccel_priv_data
;
42 av_assert0(pic
->nb_param_buffers
+ 1 <= MAX_PARAM_BUFFERS
);
44 vas
= vaCreateBuffer(ctx
->hwctx
->display
, ctx
->va_context
,
45 type
, size
, 1, (void*)data
, &buffer
);
46 if (vas
!= VA_STATUS_SUCCESS
) {
47 av_log(avctx
, AV_LOG_ERROR
, "Failed to create parameter "
48 "buffer (type %d): %d (%s).\n",
49 type
, vas
, vaErrorStr(vas
));
53 pic
->param_buffers
[pic
->nb_param_buffers
++] = buffer
;
55 av_log(avctx
, AV_LOG_DEBUG
, "Param buffer (type %d, %zu bytes) "
56 "is %#x.\n", type
, size
, buffer
);
61 int ff_vaapi_decode_make_slice_buffer(AVCodecContext
*avctx
,
62 VAAPIDecodePicture
*pic
,
63 const void *params_data
,
65 const void *slice_data
,
68 VAAPIDecodeContext
*ctx
= avctx
->internal
->hwaccel_priv_data
;
72 av_assert0(pic
->nb_slices
<= pic
->slices_allocated
);
73 if (pic
->nb_slices
== pic
->slices_allocated
) {
74 if (pic
->slices_allocated
> 0)
75 pic
->slices_allocated
*= 2;
77 pic
->slices_allocated
= 64;
80 av_realloc_array(pic
->slice_buffers
,
81 pic
->slices_allocated
,
82 2 * sizeof(*pic
->slice_buffers
));
83 if (!pic
->slice_buffers
)
84 return AVERROR(ENOMEM
);
86 av_assert0(pic
->nb_slices
+ 1 <= pic
->slices_allocated
);
88 index
= 2 * pic
->nb_slices
;
90 vas
= vaCreateBuffer(ctx
->hwctx
->display
, ctx
->va_context
,
91 VASliceParameterBufferType
,
92 params_size
, 1, (void*)params_data
,
93 &pic
->slice_buffers
[index
]);
94 if (vas
!= VA_STATUS_SUCCESS
) {
95 av_log(avctx
, AV_LOG_ERROR
, "Failed to create slice "
96 "parameter buffer: %d (%s).\n", vas
, vaErrorStr(vas
));
100 av_log(avctx
, AV_LOG_DEBUG
, "Slice %d param buffer (%zu bytes) "
101 "is %#x.\n", pic
->nb_slices
, params_size
,
102 pic
->slice_buffers
[index
]);
104 vas
= vaCreateBuffer(ctx
->hwctx
->display
, ctx
->va_context
,
105 VASliceDataBufferType
,
106 slice_size
, 1, (void*)slice_data
,
107 &pic
->slice_buffers
[index
+ 1]);
108 if (vas
!= VA_STATUS_SUCCESS
) {
109 av_log(avctx
, AV_LOG_ERROR
, "Failed to create slice "
110 "data buffer (size %zu): %d (%s).\n",
111 slice_size
, vas
, vaErrorStr(vas
));
112 vaDestroyBuffer(ctx
->hwctx
->display
,
113 pic
->slice_buffers
[index
]);
117 av_log(avctx
, AV_LOG_DEBUG
, "Slice %d data buffer (%zu bytes) "
118 "is %#x.\n", pic
->nb_slices
, slice_size
,
119 pic
->slice_buffers
[index
+ 1]);
125 static void ff_vaapi_decode_destroy_buffers(AVCodecContext
*avctx
,
126 VAAPIDecodePicture
*pic
)
128 VAAPIDecodeContext
*ctx
= avctx
->internal
->hwaccel_priv_data
;
132 for (i
= 0; i
< pic
->nb_param_buffers
; i
++) {
133 vas
= vaDestroyBuffer(ctx
->hwctx
->display
,
134 pic
->param_buffers
[i
]);
135 if (vas
!= VA_STATUS_SUCCESS
) {
136 av_log(avctx
, AV_LOG_ERROR
, "Failed to destroy "
137 "parameter buffer %#x: %d (%s).\n",
138 pic
->param_buffers
[i
], vas
, vaErrorStr(vas
));
142 for (i
= 0; i
< 2 * pic
->nb_slices
; i
++) {
143 vas
= vaDestroyBuffer(ctx
->hwctx
->display
,
144 pic
->slice_buffers
[i
]);
145 if (vas
!= VA_STATUS_SUCCESS
) {
146 av_log(avctx
, AV_LOG_ERROR
, "Failed to destroy slice "
147 "slice buffer %#x: %d (%s).\n",
148 pic
->slice_buffers
[i
], vas
, vaErrorStr(vas
));
153 int ff_vaapi_decode_issue(AVCodecContext
*avctx
,
154 VAAPIDecodePicture
*pic
)
156 VAAPIDecodeContext
*ctx
= avctx
->internal
->hwaccel_priv_data
;
160 av_log(avctx
, AV_LOG_DEBUG
, "Decode to surface %#x.\n",
161 pic
->output_surface
);
163 vas
= vaBeginPicture(ctx
->hwctx
->display
, ctx
->va_context
,
164 pic
->output_surface
);
165 if (vas
!= VA_STATUS_SUCCESS
) {
166 av_log(avctx
, AV_LOG_ERROR
, "Failed to begin picture decode "
167 "issue: %d (%s).\n", vas
, vaErrorStr(vas
));
169 goto fail_with_picture
;
172 vas
= vaRenderPicture(ctx
->hwctx
->display
, ctx
->va_context
,
173 pic
->param_buffers
, pic
->nb_param_buffers
);
174 if (vas
!= VA_STATUS_SUCCESS
) {
175 av_log(avctx
, AV_LOG_ERROR
, "Failed to upload decode "
176 "parameters: %d (%s).\n", vas
, vaErrorStr(vas
));
178 goto fail_with_picture
;
181 vas
= vaRenderPicture(ctx
->hwctx
->display
, ctx
->va_context
,
182 pic
->slice_buffers
, 2 * pic
->nb_slices
);
183 if (vas
!= VA_STATUS_SUCCESS
) {
184 av_log(avctx
, AV_LOG_ERROR
, "Failed to upload slices: "
185 "%d (%s).\n", vas
, vaErrorStr(vas
));
187 goto fail_with_picture
;
190 vas
= vaEndPicture(ctx
->hwctx
->display
, ctx
->va_context
);
191 if (vas
!= VA_STATUS_SUCCESS
) {
192 av_log(avctx
, AV_LOG_ERROR
, "Failed to end picture decode "
193 "issue: %d (%s).\n", vas
, vaErrorStr(vas
));
195 if (CONFIG_VAAPI_1
|| ctx
->hwctx
->driver_quirks
&
196 AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS
)
202 if (CONFIG_VAAPI_1
|| ctx
->hwctx
->driver_quirks
&
203 AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS
)
204 ff_vaapi_decode_destroy_buffers(avctx
, pic
);
210 vas
= vaEndPicture(ctx
->hwctx
->display
, ctx
->va_context
);
211 if (vas
!= VA_STATUS_SUCCESS
) {
212 av_log(avctx
, AV_LOG_ERROR
, "Failed to end picture decode "
213 "after error: %d (%s).\n", vas
, vaErrorStr(vas
));
216 ff_vaapi_decode_destroy_buffers(avctx
, pic
);
219 pic
->nb_param_buffers
= 0;
221 pic
->slices_allocated
= 0;
222 av_freep(&pic
->slice_buffers
);
227 int ff_vaapi_decode_cancel(AVCodecContext
*avctx
,
228 VAAPIDecodePicture
*pic
)
230 ff_vaapi_decode_destroy_buffers(avctx
, pic
);
232 pic
->nb_param_buffers
= 0;
234 pic
->slices_allocated
= 0;
235 av_freep(&pic
->slice_buffers
);
240 static const struct {
242 enum AVPixelFormat pix_fmt
;
243 } vaapi_format_map
[] = {
244 #define MAP(va, av) { VA_FOURCC_ ## va, AV_PIX_FMT_ ## av }
251 #ifdef VA_FOURCC_I420
259 #ifdef VA_FOURCC_YV16
263 #ifdef VA_FOURCC_Y210
271 #ifdef VA_FOURCC_P010
274 #ifdef VA_FOURCC_I010
275 MAP(I010
, YUV420P10
),
280 static int vaapi_decode_find_best_format(AVCodecContext
*avctx
,
281 AVHWDeviceContext
*device
,
282 VAConfigID config_id
,
283 AVHWFramesContext
*frames
)
285 AVVAAPIDeviceContext
*hwctx
= device
->hwctx
;
287 VASurfaceAttrib
*attr
;
288 enum AVPixelFormat source_format
, best_format
, format
;
289 uint32_t best_fourcc
, fourcc
;
292 source_format
= avctx
->sw_pix_fmt
;
293 av_assert0(source_format
!= AV_PIX_FMT_NONE
);
295 vas
= vaQuerySurfaceAttributes(hwctx
->display
, config_id
,
297 if (vas
!= VA_STATUS_SUCCESS
) {
298 av_log(avctx
, AV_LOG_ERROR
, "Failed to query surface attributes: "
299 "%d (%s).\n", vas
, vaErrorStr(vas
));
300 return AVERROR(ENOSYS
);
303 attr
= av_malloc_array(nb_attr
, sizeof(*attr
));
305 return AVERROR(ENOMEM
);
307 vas
= vaQuerySurfaceAttributes(hwctx
->display
, config_id
,
309 if (vas
!= VA_STATUS_SUCCESS
) {
310 av_log(avctx
, AV_LOG_ERROR
, "Failed to query surface attributes: "
311 "%d (%s).\n", vas
, vaErrorStr(vas
));
313 return AVERROR(ENOSYS
);
316 best_format
= AV_PIX_FMT_NONE
;
318 for (i
= 0; i
< nb_attr
; i
++) {
319 if (attr
[i
].type
!= VASurfaceAttribPixelFormat
)
322 fourcc
= attr
[i
].value
.value
.i
;
323 for (j
= 0; j
< FF_ARRAY_ELEMS(vaapi_format_map
); j
++) {
324 if (fourcc
== vaapi_format_map
[j
].fourcc
)
327 if (j
>= FF_ARRAY_ELEMS(vaapi_format_map
)) {
328 av_log(avctx
, AV_LOG_DEBUG
, "Ignoring unknown format %#x.\n",
332 format
= vaapi_format_map
[j
].pix_fmt
;
333 av_log(avctx
, AV_LOG_DEBUG
, "Considering format %#x -> %s.\n",
334 fourcc
, av_get_pix_fmt_name(format
));
336 best_format
= av_find_best_pix_fmt_of_2(format
, best_format
,
337 source_format
, 0, NULL
);
338 if (format
== best_format
)
339 best_fourcc
= fourcc
;
344 if (best_format
== AV_PIX_FMT_NONE
) {
345 av_log(avctx
, AV_LOG_ERROR
, "No usable formats for decoding!\n");
346 return AVERROR(EINVAL
);
349 av_log(avctx
, AV_LOG_DEBUG
, "Picked %s (%#x) as best match for %s.\n",
350 av_get_pix_fmt_name(best_format
), best_fourcc
,
351 av_get_pix_fmt_name(source_format
));
353 frames
->sw_format
= best_format
;
354 if (avctx
->internal
->hwaccel_priv_data
) {
355 VAAPIDecodeContext
*ctx
= avctx
->internal
->hwaccel_priv_data
;
356 AVVAAPIFramesContext
*avfc
= frames
->hwctx
;
358 ctx
->pixel_format_attribute
= (VASurfaceAttrib
) {
359 .type
= VASurfaceAttribPixelFormat
,
360 .value
.value
.i
= best_fourcc
,
363 avfc
->attributes
= &ctx
->pixel_format_attribute
;
364 avfc
->nb_attributes
= 1;
370 static const struct {
371 enum AVCodecID codec_id
;
373 VAProfile va_profile
;
374 VAProfile (*profile_parser
)(AVCodecContext
*avctx
);
375 } vaapi_profile_map
[] = {
376 #define MAP(c, p, v, ...) { AV_CODEC_ID_ ## c, FF_PROFILE_ ## p, VAProfile ## v, __VA_ARGS__ }
377 MAP(MPEG2VIDEO
, MPEG2_SIMPLE
, MPEG2Simple
),
378 MAP(MPEG2VIDEO
, MPEG2_MAIN
, MPEG2Main
),
379 MAP(H263
, UNKNOWN
, H263Baseline
),
380 MAP(MPEG4
, MPEG4_SIMPLE
, MPEG4Simple
),
381 MAP(MPEG4
, MPEG4_ADVANCED_SIMPLE
,
382 MPEG4AdvancedSimple
),
383 MAP(MPEG4
, MPEG4_MAIN
, MPEG4Main
),
384 MAP(H264
, H264_CONSTRAINED_BASELINE
,
385 H264ConstrainedBaseline
),
386 MAP(H264
, H264_MAIN
, H264Main
),
387 MAP(H264
, H264_HIGH
, H264High
),
388 #if VA_CHECK_VERSION(0, 37, 0)
389 MAP(HEVC
, HEVC_MAIN
, HEVCMain
),
390 MAP(HEVC
, HEVC_MAIN_10
, HEVCMain10
),
391 MAP(HEVC
, HEVC_MAIN_STILL_PICTURE
,
394 #if VA_CHECK_VERSION(1, 2, 0) && CONFIG_HEVC_VAAPI_HWACCEL
395 MAP(HEVC
, HEVC_REXT
, None
,
396 ff_vaapi_parse_hevc_rext_profile
),
398 MAP(MJPEG
, MJPEG_HUFFMAN_BASELINE_DCT
,
400 MAP(WMV3
, VC1_SIMPLE
, VC1Simple
),
401 MAP(WMV3
, VC1_MAIN
, VC1Main
),
402 MAP(WMV3
, VC1_COMPLEX
, VC1Advanced
),
403 MAP(WMV3
, VC1_ADVANCED
, VC1Advanced
),
404 MAP(VC1
, VC1_SIMPLE
, VC1Simple
),
405 MAP(VC1
, VC1_MAIN
, VC1Main
),
406 MAP(VC1
, VC1_COMPLEX
, VC1Advanced
),
407 MAP(VC1
, VC1_ADVANCED
, VC1Advanced
),
408 MAP(VP8
, UNKNOWN
, VP8Version0_3
),
409 #if VA_CHECK_VERSION(0, 38, 0)
410 MAP(VP9
, VP9_0
, VP9Profile0
),
412 #if VA_CHECK_VERSION(0, 39, 0)
413 MAP(VP9
, VP9_2
, VP9Profile2
),
415 #if VA_CHECK_VERSION(1, 8, 0)
416 MAP(AV1
, AV1_MAIN
, AV1Profile0
),
417 MAP(AV1
, AV1_HIGH
, AV1Profile1
),
424 * Set *va_config and the frames_ref fields from the current codec parameters
427 static int vaapi_decode_make_config(AVCodecContext
*avctx
,
428 AVBufferRef
*device_ref
,
429 VAConfigID
*va_config
,
430 AVBufferRef
*frames_ref
)
432 AVVAAPIHWConfig
*hwconfig
= NULL
;
433 AVHWFramesConstraints
*constraints
= NULL
;
436 const AVCodecDescriptor
*codec_desc
;
437 VAProfile
*profile_list
= NULL
, matched_va_profile
, va_profile
;
438 int profile_count
, exact_match
, matched_ff_profile
, codec_profile
;
440 AVHWDeviceContext
*device
= (AVHWDeviceContext
*)device_ref
->data
;
441 AVVAAPIDeviceContext
*hwctx
= device
->hwctx
;
443 codec_desc
= avcodec_descriptor_get(avctx
->codec_id
);
445 err
= AVERROR(EINVAL
);
449 profile_count
= vaMaxNumProfiles(hwctx
->display
);
450 profile_list
= av_malloc_array(profile_count
,
453 err
= AVERROR(ENOMEM
);
457 vas
= vaQueryConfigProfiles(hwctx
->display
,
458 profile_list
, &profile_count
);
459 if (vas
!= VA_STATUS_SUCCESS
) {
460 av_log(avctx
, AV_LOG_ERROR
, "Failed to query profiles: "
461 "%d (%s).\n", vas
, vaErrorStr(vas
));
462 err
= AVERROR(ENOSYS
);
466 matched_va_profile
= VAProfileNone
;
469 for (i
= 0; i
< FF_ARRAY_ELEMS(vaapi_profile_map
); i
++) {
470 int profile_match
= 0;
471 if (avctx
->codec_id
!= vaapi_profile_map
[i
].codec_id
)
473 if (avctx
->profile
== vaapi_profile_map
[i
].codec_profile
||
474 vaapi_profile_map
[i
].codec_profile
== FF_PROFILE_UNKNOWN
)
477 va_profile
= vaapi_profile_map
[i
].profile_parser
?
478 vaapi_profile_map
[i
].profile_parser(avctx
) :
479 vaapi_profile_map
[i
].va_profile
;
480 codec_profile
= vaapi_profile_map
[i
].codec_profile
;
482 for (j
= 0; j
< profile_count
; j
++) {
483 if (va_profile
== profile_list
[j
]) {
484 exact_match
= profile_match
;
488 if (j
< profile_count
) {
489 matched_va_profile
= va_profile
;
490 matched_ff_profile
= codec_profile
;
495 av_freep(&profile_list
);
497 if (matched_va_profile
== VAProfileNone
) {
498 av_log(avctx
, AV_LOG_ERROR
, "No support for codec %s "
499 "profile %d.\n", codec_desc
->name
, avctx
->profile
);
500 err
= AVERROR(ENOSYS
);
504 if (avctx
->hwaccel_flags
&
505 AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH
) {
506 av_log(avctx
, AV_LOG_VERBOSE
, "Codec %s profile %d not "
507 "supported for hardware decode.\n",
508 codec_desc
->name
, avctx
->profile
);
509 av_log(avctx
, AV_LOG_WARNING
, "Using possibly-"
510 "incompatible profile %d instead.\n",
513 av_log(avctx
, AV_LOG_VERBOSE
, "Codec %s profile %d not "
514 "supported for hardware decode.\n",
515 codec_desc
->name
, avctx
->profile
);
516 err
= AVERROR(EINVAL
);
521 vas
= vaCreateConfig(hwctx
->display
, matched_va_profile
,
522 VAEntrypointVLD
, NULL
, 0,
524 if (vas
!= VA_STATUS_SUCCESS
) {
525 av_log(avctx
, AV_LOG_ERROR
, "Failed to create decode "
526 "configuration: %d (%s).\n", vas
, vaErrorStr(vas
));
531 hwconfig
= av_hwdevice_hwconfig_alloc(device_ref
);
533 err
= AVERROR(ENOMEM
);
536 hwconfig
->config_id
= *va_config
;
539 av_hwdevice_get_hwframe_constraints(device_ref
, hwconfig
);
541 err
= AVERROR(ENOMEM
);
545 if (avctx
->coded_width
< constraints
->min_width
||
546 avctx
->coded_height
< constraints
->min_height
||
547 avctx
->coded_width
> constraints
->max_width
||
548 avctx
->coded_height
> constraints
->max_height
) {
549 av_log(avctx
, AV_LOG_ERROR
, "Hardware does not support image "
550 "size %dx%d (constraints: width %d-%d height %d-%d).\n",
551 avctx
->coded_width
, avctx
->coded_height
,
552 constraints
->min_width
, constraints
->max_width
,
553 constraints
->min_height
, constraints
->max_height
);
554 err
= AVERROR(EINVAL
);
557 if (!constraints
->valid_sw_formats
||
558 constraints
->valid_sw_formats
[0] == AV_PIX_FMT_NONE
) {
559 av_log(avctx
, AV_LOG_ERROR
, "Hardware does not offer any "
560 "usable surface formats.\n");
561 err
= AVERROR(EINVAL
);
566 AVHWFramesContext
*frames
= (AVHWFramesContext
*)frames_ref
->data
;
568 frames
->format
= AV_PIX_FMT_VAAPI
;
569 frames
->width
= avctx
->coded_width
;
570 frames
->height
= avctx
->coded_height
;
572 err
= vaapi_decode_find_best_format(avctx
, device
,
577 frames
->initial_pool_size
= 1;
578 // Add per-codec number of surfaces used for storing reference frames.
579 switch (avctx
->codec_id
) {
580 case AV_CODEC_ID_H264
:
581 case AV_CODEC_ID_HEVC
:
582 case AV_CODEC_ID_AV1
:
583 frames
->initial_pool_size
+= 16;
585 case AV_CODEC_ID_VP9
:
586 frames
->initial_pool_size
+= 8;
588 case AV_CODEC_ID_VP8
:
589 frames
->initial_pool_size
+= 3;
592 frames
->initial_pool_size
+= 2;
596 av_hwframe_constraints_free(&constraints
);
602 av_hwframe_constraints_free(&constraints
);
604 if (*va_config
!= VA_INVALID_ID
) {
605 vaDestroyConfig(hwctx
->display
, *va_config
);
606 *va_config
= VA_INVALID_ID
;
608 av_freep(&profile_list
);
612 int ff_vaapi_common_frame_params(AVCodecContext
*avctx
,
613 AVBufferRef
*hw_frames_ctx
)
615 AVHWFramesContext
*hw_frames
= (AVHWFramesContext
*)hw_frames_ctx
->data
;
616 AVHWDeviceContext
*device_ctx
= hw_frames
->device_ctx
;
617 AVVAAPIDeviceContext
*hwctx
;
618 VAConfigID va_config
= VA_INVALID_ID
;
621 if (device_ctx
->type
!= AV_HWDEVICE_TYPE_VAAPI
)
622 return AVERROR(EINVAL
);
623 hwctx
= device_ctx
->hwctx
;
625 err
= vaapi_decode_make_config(avctx
, hw_frames
->device_ref
, &va_config
,
630 if (va_config
!= VA_INVALID_ID
)
631 vaDestroyConfig(hwctx
->display
, va_config
);
636 int ff_vaapi_decode_init(AVCodecContext
*avctx
)
638 VAAPIDecodeContext
*ctx
= avctx
->internal
->hwaccel_priv_data
;
642 ctx
->va_config
= VA_INVALID_ID
;
643 ctx
->va_context
= VA_INVALID_ID
;
645 err
= ff_decode_get_hw_frames_ctx(avctx
, AV_HWDEVICE_TYPE_VAAPI
);
649 ctx
->frames
= (AVHWFramesContext
*)avctx
->hw_frames_ctx
->data
;
650 ctx
->hwfc
= ctx
->frames
->hwctx
;
651 ctx
->device
= ctx
->frames
->device_ctx
;
652 ctx
->hwctx
= ctx
->device
->hwctx
;
654 err
= vaapi_decode_make_config(avctx
, ctx
->frames
->device_ref
,
655 &ctx
->va_config
, NULL
);
659 vas
= vaCreateContext(ctx
->hwctx
->display
, ctx
->va_config
,
660 avctx
->coded_width
, avctx
->coded_height
,
662 ctx
->hwfc
->surface_ids
,
663 ctx
->hwfc
->nb_surfaces
,
665 if (vas
!= VA_STATUS_SUCCESS
) {
666 av_log(avctx
, AV_LOG_ERROR
, "Failed to create decode "
667 "context: %d (%s).\n", vas
, vaErrorStr(vas
));
672 av_log(avctx
, AV_LOG_DEBUG
, "Decode context initialised: "
673 "%#x/%#x.\n", ctx
->va_config
, ctx
->va_context
);
678 ff_vaapi_decode_uninit(avctx
);
682 int ff_vaapi_decode_uninit(AVCodecContext
*avctx
)
684 VAAPIDecodeContext
*ctx
= avctx
->internal
->hwaccel_priv_data
;
687 if (ctx
->va_context
!= VA_INVALID_ID
) {
688 vas
= vaDestroyContext(ctx
->hwctx
->display
, ctx
->va_context
);
689 if (vas
!= VA_STATUS_SUCCESS
) {
690 av_log(avctx
, AV_LOG_ERROR
, "Failed to destroy decode "
691 "context %#x: %d (%s).\n",
692 ctx
->va_context
, vas
, vaErrorStr(vas
));
695 if (ctx
->va_config
!= VA_INVALID_ID
) {
696 vas
= vaDestroyConfig(ctx
->hwctx
->display
, ctx
->va_config
);
697 if (vas
!= VA_STATUS_SUCCESS
) {
698 av_log(avctx
, AV_LOG_ERROR
, "Failed to destroy decode "
699 "configuration %#x: %d (%s).\n",
700 ctx
->va_config
, vas
, vaErrorStr(vas
));