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 
ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx, VAAPIDecodePicture *pic, int type, const void *data, size_t size)32 int 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 
ff_vaapi_decode_make_slice_buffer(AVCodecContext *avctx, VAAPIDecodePicture *pic, const void *params_data, size_t params_size, const void *slice_data, size_t slice_size)61 int 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 
ff_vaapi_decode_destroy_buffers(AVCodecContext *avctx, VAAPIDecodePicture *pic)125 static 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 
ff_vaapi_decode_issue(AVCodecContext *avctx, VAAPIDecodePicture *pic)153 int 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 
209 fail_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     }
215 fail:
216     ff_vaapi_decode_destroy_buffers(avctx, pic);
217 fail_at_end:
218 exit:
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 
ff_vaapi_decode_cancel(AVCodecContext *avctx, VAAPIDecodePicture *pic)227 int 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 
240 static 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 
vaapi_decode_find_best_format(AVCodecContext *avctx, AVHWDeviceContext *device, VAConfigID config_id, AVHWFramesContext *frames)280 static 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 
370 static 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  */
vaapi_decode_make_config(AVCodecContext *avctx, AVBufferRef *device_ref, VAConfigID *va_config, AVBufferRef *frames_ref)427 static 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 
601 fail:
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 
ff_vaapi_common_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx)612 int 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 
ff_vaapi_decode_init(AVCodecContext *avctx)636 int 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 
677 fail:
678     ff_vaapi_decode_uninit(avctx);
679     return err;
680 }
681 
ff_vaapi_decode_uninit(AVCodecContext *avctx)682 int 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