1/*
2 * This file is part of FFmpeg.
3 *
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.
8 *
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.
13 *
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
17 */
18
19#include "config_components.h"
20
21#include "libavutil/avassert.h"
22#include "libavutil/common.h"
23#include "libavutil/pixdesc.h"
24
25#include "avcodec.h"
26#include "decode.h"
27#include "internal.h"
28#include "vaapi_decode.h"
29#include "vaapi_hevc.h"
30
31
32int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx,
33                                      VAAPIDecodePicture *pic,
34                                      int type,
35                                      const void *data,
36                                      size_t size)
37{
38    VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
39    VAStatus vas;
40    VABufferID buffer;
41
42    av_assert0(pic->nb_param_buffers + 1 <= MAX_PARAM_BUFFERS);
43
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));
50        return AVERROR(EIO);
51    }
52
53    pic->param_buffers[pic->nb_param_buffers++] = buffer;
54
55    av_log(avctx, AV_LOG_DEBUG, "Param buffer (type %d, %zu bytes) "
56           "is %#x.\n", type, size, buffer);
57    return 0;
58}
59
60
61int ff_vaapi_decode_make_slice_buffer(AVCodecContext *avctx,
62                                      VAAPIDecodePicture *pic,
63                                      const void *params_data,
64                                      size_t params_size,
65                                      const void *slice_data,
66                                      size_t slice_size)
67{
68    VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
69    VAStatus vas;
70    int index;
71
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;
76        else
77            pic->slices_allocated = 64;
78
79        pic->slice_buffers =
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);
85    }
86    av_assert0(pic->nb_slices + 1 <= pic->slices_allocated);
87
88    index = 2 * pic->nb_slices;
89
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));
97        return AVERROR(EIO);
98    }
99
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]);
103
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]);
114        return AVERROR(EIO);
115    }
116
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]);
120
121    ++pic->nb_slices;
122    return 0;
123}
124
125static void ff_vaapi_decode_destroy_buffers(AVCodecContext *avctx,
126                                            VAAPIDecodePicture *pic)
127{
128    VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
129    VAStatus vas;
130    int i;
131
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));
139        }
140    }
141
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));
149        }
150    }
151}
152
153int ff_vaapi_decode_issue(AVCodecContext *avctx,
154                          VAAPIDecodePicture *pic)
155{
156    VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
157    VAStatus vas;
158    int err;
159
160    av_log(avctx, AV_LOG_DEBUG, "Decode to surface %#x.\n",
161           pic->output_surface);
162
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));
168        err = AVERROR(EIO);
169        goto fail_with_picture;
170    }
171
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));
177        err = AVERROR(EIO);
178        goto fail_with_picture;
179    }
180
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));
186        err = AVERROR(EIO);
187        goto fail_with_picture;
188    }
189
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));
194        err = AVERROR(EIO);
195        if (CONFIG_VAAPI_1 || ctx->hwctx->driver_quirks &
196            AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS)
197            goto fail;
198        else
199            goto fail_at_end;
200    }
201
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);
205
206    err = 0;
207    goto exit;
208
209fail_with_picture:
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));
214    }
215fail:
216    ff_vaapi_decode_destroy_buffers(avctx, pic);
217fail_at_end:
218exit:
219    pic->nb_param_buffers = 0;
220    pic->nb_slices        = 0;
221    pic->slices_allocated = 0;
222    av_freep(&pic->slice_buffers);
223
224    return err;
225}
226
227int ff_vaapi_decode_cancel(AVCodecContext *avctx,
228                           VAAPIDecodePicture *pic)
229{
230    ff_vaapi_decode_destroy_buffers(avctx, pic);
231
232    pic->nb_param_buffers = 0;
233    pic->nb_slices        = 0;
234    pic->slices_allocated = 0;
235    av_freep(&pic->slice_buffers);
236
237    return 0;
238}
239
240static const struct {
241    uint32_t fourcc;
242    enum AVPixelFormat pix_fmt;
243} vaapi_format_map[] = {
244#define MAP(va, av) { VA_FOURCC_ ## va, AV_PIX_FMT_ ## av }
245    // 4:0:0
246    MAP(Y800, GRAY8),
247    // 4:2:0
248    MAP(NV12, NV12),
249    MAP(YV12, YUV420P),
250    MAP(IYUV, YUV420P),
251#ifdef VA_FOURCC_I420
252    MAP(I420, YUV420P),
253#endif
254    MAP(IMC3, YUV420P),
255    // 4:1:1
256    MAP(411P, YUV411P),
257    // 4:2:2
258    MAP(422H, YUV422P),
259#ifdef VA_FOURCC_YV16
260    MAP(YV16, YUV422P),
261#endif
262    MAP(YUY2, YUYV422),
263#ifdef VA_FOURCC_Y210
264    MAP(Y210,    Y210),
265#endif
266    // 4:4:0
267    MAP(422V, YUV440P),
268    // 4:4:4
269    MAP(444P, YUV444P),
270    // 4:2:0 10-bit
271#ifdef VA_FOURCC_P010
272    MAP(P010, P010),
273#endif
274#ifdef VA_FOURCC_I010
275    MAP(I010, YUV420P10),
276#endif
277#undef MAP
278};
279
280static int vaapi_decode_find_best_format(AVCodecContext *avctx,
281                                         AVHWDeviceContext *device,
282                                         VAConfigID config_id,
283                                         AVHWFramesContext *frames)
284{
285    AVVAAPIDeviceContext *hwctx = device->hwctx;
286    VAStatus vas;
287    VASurfaceAttrib *attr;
288    enum AVPixelFormat source_format, best_format, format;
289    uint32_t best_fourcc, fourcc;
290    int i, j, nb_attr;
291
292    source_format = avctx->sw_pix_fmt;
293    av_assert0(source_format != AV_PIX_FMT_NONE);
294
295    vas = vaQuerySurfaceAttributes(hwctx->display, config_id,
296                                   NULL, &nb_attr);
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);
301    }
302
303    attr = av_malloc_array(nb_attr, sizeof(*attr));
304    if (!attr)
305        return AVERROR(ENOMEM);
306
307    vas = vaQuerySurfaceAttributes(hwctx->display, config_id,
308                                   attr, &nb_attr);
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));
312        av_freep(&attr);
313        return AVERROR(ENOSYS);
314    }
315
316    best_format = AV_PIX_FMT_NONE;
317
318    for (i = 0; i < nb_attr; i++) {
319        if (attr[i].type != VASurfaceAttribPixelFormat)
320            continue;
321
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)
325                break;
326        }
327        if (j >= FF_ARRAY_ELEMS(vaapi_format_map)) {
328            av_log(avctx, AV_LOG_DEBUG, "Ignoring unknown format %#x.\n",
329                   fourcc);
330            continue;
331        }
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));
335
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;
340    }
341
342    av_freep(&attr);
343
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);
347    }
348
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));
352
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;
357
358        ctx->pixel_format_attribute = (VASurfaceAttrib) {
359            .type          = VASurfaceAttribPixelFormat,
360            .value.value.i = best_fourcc,
361        };
362
363        avfc->attributes    = &ctx->pixel_format_attribute;
364        avfc->nb_attributes = 1;
365    }
366
367    return 0;
368}
369
370static const struct {
371    enum AVCodecID codec_id;
372    int codec_profile;
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,
392                                      HEVCMain    ),
393#endif
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 ),
397#endif
398    MAP(MJPEG,       MJPEG_HUFFMAN_BASELINE_DCT,
399                                      JPEGBaseline),
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 ),
411#endif
412#if VA_CHECK_VERSION(0, 39, 0)
413    MAP(VP9,         VP9_2,           VP9Profile2 ),
414#endif
415#if VA_CHECK_VERSION(1, 8, 0)
416    MAP(AV1,         AV1_MAIN,        AV1Profile0),
417    MAP(AV1,         AV1_HIGH,        AV1Profile1),
418#endif
419
420#undef MAP
421};
422
423/*
424 * Set *va_config and the frames_ref fields from the current codec parameters
425 * in avctx.
426 */
427static int vaapi_decode_make_config(AVCodecContext *avctx,
428                                    AVBufferRef *device_ref,
429                                    VAConfigID *va_config,
430                                    AVBufferRef *frames_ref)
431{
432    AVVAAPIHWConfig       *hwconfig    = NULL;
433    AVHWFramesConstraints *constraints = NULL;
434    VAStatus vas;
435    int err, i, j;
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;
439
440    AVHWDeviceContext    *device = (AVHWDeviceContext*)device_ref->data;
441    AVVAAPIDeviceContext *hwctx = device->hwctx;
442
443    codec_desc = avcodec_descriptor_get(avctx->codec_id);
444    if (!codec_desc) {
445        err = AVERROR(EINVAL);
446        goto fail;
447    }
448
449    profile_count = vaMaxNumProfiles(hwctx->display);
450    profile_list  = av_malloc_array(profile_count,
451                                    sizeof(VAProfile));
452    if (!profile_list) {
453        err = AVERROR(ENOMEM);
454        goto fail;
455    }
456
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);
463        goto fail;
464    }
465
466    matched_va_profile = VAProfileNone;
467    exact_match = 0;
468
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)
472            continue;
473        if (avctx->profile == vaapi_profile_map[i].codec_profile ||
474            vaapi_profile_map[i].codec_profile == FF_PROFILE_UNKNOWN)
475            profile_match = 1;
476
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;
481
482        for (j = 0; j < profile_count; j++) {
483            if (va_profile == profile_list[j]) {
484                exact_match = profile_match;
485                break;
486            }
487        }
488        if (j < profile_count) {
489            matched_va_profile = va_profile;
490            matched_ff_profile = codec_profile;
491            if (exact_match)
492                break;
493        }
494    }
495    av_freep(&profile_list);
496
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);
501        goto fail;
502    }
503    if (!exact_match) {
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",
511                   matched_ff_profile);
512        } else {
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);
517            goto fail;
518        }
519    }
520
521    vas = vaCreateConfig(hwctx->display, matched_va_profile,
522                         VAEntrypointVLD, NULL, 0,
523                         va_config);
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));
527        err = AVERROR(EIO);
528        goto fail;
529    }
530
531    hwconfig = av_hwdevice_hwconfig_alloc(device_ref);
532    if (!hwconfig) {
533        err = AVERROR(ENOMEM);
534        goto fail;
535    }
536    hwconfig->config_id = *va_config;
537
538    constraints =
539        av_hwdevice_get_hwframe_constraints(device_ref, hwconfig);
540    if (!constraints) {
541        err = AVERROR(ENOMEM);
542        goto fail;
543    }
544
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);
555        goto fail;
556    }
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);
562        goto fail;
563    }
564
565    if (frames_ref) {
566        AVHWFramesContext *frames = (AVHWFramesContext *)frames_ref->data;
567
568        frames->format = AV_PIX_FMT_VAAPI;
569        frames->width = avctx->coded_width;
570        frames->height = avctx->coded_height;
571
572        err = vaapi_decode_find_best_format(avctx, device,
573                                            *va_config, frames);
574        if (err < 0)
575            goto fail;
576
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;
584            break;
585        case AV_CODEC_ID_VP9:
586            frames->initial_pool_size += 8;
587            break;
588        case AV_CODEC_ID_VP8:
589            frames->initial_pool_size += 3;
590            break;
591        default:
592            frames->initial_pool_size += 2;
593        }
594    }
595
596    av_hwframe_constraints_free(&constraints);
597    av_freep(&hwconfig);
598
599    return 0;
600
601fail:
602    av_hwframe_constraints_free(&constraints);
603    av_freep(&hwconfig);
604    if (*va_config != VA_INVALID_ID) {
605        vaDestroyConfig(hwctx->display, *va_config);
606        *va_config = VA_INVALID_ID;
607    }
608    av_freep(&profile_list);
609    return err;
610}
611
612int ff_vaapi_common_frame_params(AVCodecContext *avctx,
613                                 AVBufferRef *hw_frames_ctx)
614{
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;
619    int err;
620
621    if (device_ctx->type != AV_HWDEVICE_TYPE_VAAPI)
622        return AVERROR(EINVAL);
623    hwctx = device_ctx->hwctx;
624
625    err = vaapi_decode_make_config(avctx, hw_frames->device_ref, &va_config,
626                                   hw_frames_ctx);
627    if (err)
628        return err;
629
630    if (va_config != VA_INVALID_ID)
631        vaDestroyConfig(hwctx->display, va_config);
632
633    return 0;
634}
635
636int ff_vaapi_decode_init(AVCodecContext *avctx)
637{
638    VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
639    VAStatus vas;
640    int err;
641
642    ctx->va_config  = VA_INVALID_ID;
643    ctx->va_context = VA_INVALID_ID;
644
645    err = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_VAAPI);
646    if (err < 0)
647        goto fail;
648
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;
653
654    err = vaapi_decode_make_config(avctx, ctx->frames->device_ref,
655                                   &ctx->va_config, NULL);
656    if (err)
657        goto fail;
658
659    vas = vaCreateContext(ctx->hwctx->display, ctx->va_config,
660                          avctx->coded_width, avctx->coded_height,
661                          VA_PROGRESSIVE,
662                          ctx->hwfc->surface_ids,
663                          ctx->hwfc->nb_surfaces,
664                          &ctx->va_context);
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));
668        err = AVERROR(EIO);
669        goto fail;
670    }
671
672    av_log(avctx, AV_LOG_DEBUG, "Decode context initialised: "
673           "%#x/%#x.\n", ctx->va_config, ctx->va_context);
674
675    return 0;
676
677fail:
678    ff_vaapi_decode_uninit(avctx);
679    return err;
680}
681
682int ff_vaapi_decode_uninit(AVCodecContext *avctx)
683{
684    VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
685    VAStatus vas;
686
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));
693        }
694    }
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));
701        }
702    }
703
704    return 0;
705}
706