FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/vaapi_decode.c
Date: 2024-11-20 23:03:26
Exec Total Coverage
Lines: 0 319 0.0%
Functions: 0 10 0.0%
Branches: 0 144 0.0%

Line Branch Exec Source
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/mem.h"
24 #include "libavutil/pixdesc.h"
25
26 #include "avcodec.h"
27 #include "codec_desc.h"
28 #include "decode.h"
29 #include "internal.h"
30 #include "vaapi_decode.h"
31 #include "vaapi_hevc.h"
32
33
34 int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx,
35 VAAPIDecodePicture *pic,
36 int type,
37 const void *data,
38 size_t size)
39 {
40 VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
41 VAStatus vas;
42
43 av_assert0(pic->nb_param_buffers <= pic->nb_param_buffers_allocated);
44 if (pic->nb_param_buffers == pic->nb_param_buffers_allocated) {
45 VABufferID *tmp =
46 av_realloc_array(pic->param_buffers,
47 pic->nb_param_buffers_allocated + 16,
48 sizeof(*pic->param_buffers));
49 if (!tmp)
50 return AVERROR(ENOMEM);
51
52 pic->param_buffers = tmp;
53 pic->nb_param_buffers_allocated += 16;
54 }
55 av_assert0(pic->nb_param_buffers + 1 <= pic->nb_param_buffers_allocated);
56
57 vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
58 type, size, 1, (void*)data,
59 &pic->param_buffers[pic->nb_param_buffers]);
60 if (vas != VA_STATUS_SUCCESS) {
61 av_log(avctx, AV_LOG_ERROR, "Failed to create parameter "
62 "buffer (type %d): %d (%s).\n",
63 type, vas, vaErrorStr(vas));
64 return AVERROR(EIO);
65 }
66
67 av_log(avctx, AV_LOG_DEBUG, "Param buffer (type %d, %zu bytes) "
68 "is %#x.\n", type, size, pic->param_buffers[pic->nb_param_buffers]);
69
70 ++pic->nb_param_buffers;
71
72 return 0;
73 }
74
75 int ff_vaapi_decode_make_slice_buffer(AVCodecContext *avctx,
76 VAAPIDecodePicture *pic,
77 const void *params_data,
78 int nb_params,
79 size_t params_size,
80 const void *slice_data,
81 size_t slice_size)
82 {
83 VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
84 VAStatus vas;
85 int index;
86
87 av_assert0(pic->nb_slices <= pic->nb_slice_buffers_allocated);
88 if (pic->nb_slices == pic->nb_slice_buffers_allocated) {
89 VABufferID *tmp =
90 av_realloc_array(pic->slice_buffers,
91 pic->nb_slice_buffers_allocated ? pic->nb_slice_buffers_allocated * 2 : 64,
92 2 * sizeof(*pic->slice_buffers));
93 if (!tmp)
94 return AVERROR(ENOMEM);
95
96 pic->slice_buffers = tmp;
97 pic->nb_slice_buffers_allocated = pic->nb_slice_buffers_allocated ? pic->nb_slice_buffers_allocated * 2 : 64;
98 }
99 av_assert0(pic->nb_slices + 1 <= pic->nb_slice_buffers_allocated);
100
101 index = 2 * pic->nb_slices;
102
103 vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
104 VASliceParameterBufferType,
105 params_size, nb_params, (void*)params_data,
106 &pic->slice_buffers[index]);
107 if (vas != VA_STATUS_SUCCESS) {
108 av_log(avctx, AV_LOG_ERROR, "Failed to create slice "
109 "parameter buffer: %d (%s).\n", vas, vaErrorStr(vas));
110 return AVERROR(EIO);
111 }
112
113 av_log(avctx, AV_LOG_DEBUG, "Slice %d param buffer (%zu bytes) "
114 "is %#x.\n", pic->nb_slices, params_size,
115 pic->slice_buffers[index]);
116
117 vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
118 VASliceDataBufferType,
119 slice_size, 1, (void*)slice_data,
120 &pic->slice_buffers[index + 1]);
121 if (vas != VA_STATUS_SUCCESS) {
122 av_log(avctx, AV_LOG_ERROR, "Failed to create slice "
123 "data buffer (size %zu): %d (%s).\n",
124 slice_size, vas, vaErrorStr(vas));
125 vaDestroyBuffer(ctx->hwctx->display,
126 pic->slice_buffers[index]);
127 return AVERROR(EIO);
128 }
129
130 av_log(avctx, AV_LOG_DEBUG, "Slice %d data buffer (%zu bytes) "
131 "is %#x.\n", pic->nb_slices, slice_size,
132 pic->slice_buffers[index + 1]);
133
134 ++pic->nb_slices;
135 return 0;
136 }
137
138 static void ff_vaapi_decode_destroy_buffers(AVCodecContext *avctx,
139 VAAPIDecodePicture *pic)
140 {
141 VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
142 VAStatus vas;
143 int i;
144
145 for (i = 0; i < pic->nb_param_buffers; i++) {
146 vas = vaDestroyBuffer(ctx->hwctx->display,
147 pic->param_buffers[i]);
148 if (vas != VA_STATUS_SUCCESS) {
149 av_log(avctx, AV_LOG_ERROR, "Failed to destroy "
150 "parameter buffer %#x: %d (%s).\n",
151 pic->param_buffers[i], vas, vaErrorStr(vas));
152 }
153 }
154
155 for (i = 0; i < 2 * pic->nb_slices; i++) {
156 vas = vaDestroyBuffer(ctx->hwctx->display,
157 pic->slice_buffers[i]);
158 if (vas != VA_STATUS_SUCCESS) {
159 av_log(avctx, AV_LOG_ERROR, "Failed to destroy slice "
160 "slice buffer %#x: %d (%s).\n",
161 pic->slice_buffers[i], vas, vaErrorStr(vas));
162 }
163 }
164 }
165
166 int ff_vaapi_decode_issue(AVCodecContext *avctx,
167 VAAPIDecodePicture *pic)
168 {
169 VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
170 VAStatus vas;
171 int err;
172
173 if (pic->nb_slices <= 0) {
174 err = AVERROR(EINVAL);
175 goto fail;
176 }
177
178 av_log(avctx, AV_LOG_DEBUG, "Decode to surface %#x.\n",
179 pic->output_surface);
180
181 vas = vaBeginPicture(ctx->hwctx->display, ctx->va_context,
182 pic->output_surface);
183 if (vas != VA_STATUS_SUCCESS) {
184 av_log(avctx, AV_LOG_ERROR, "Failed to begin picture decode "
185 "issue: %d (%s).\n", vas, vaErrorStr(vas));
186 err = AVERROR(EIO);
187 goto fail_with_picture;
188 }
189
190 vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context,
191 pic->param_buffers, pic->nb_param_buffers);
192 if (vas != VA_STATUS_SUCCESS) {
193 av_log(avctx, AV_LOG_ERROR, "Failed to upload decode "
194 "parameters: %d (%s).\n", vas, vaErrorStr(vas));
195 err = AVERROR(EIO);
196 goto fail_with_picture;
197 }
198
199 vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context,
200 pic->slice_buffers, 2 * pic->nb_slices);
201 if (vas != VA_STATUS_SUCCESS) {
202 av_log(avctx, AV_LOG_ERROR, "Failed to upload slices: "
203 "%d (%s).\n", vas, vaErrorStr(vas));
204 err = AVERROR(EIO);
205 goto fail_with_picture;
206 }
207
208 vas = vaEndPicture(ctx->hwctx->display, ctx->va_context);
209 if (vas != VA_STATUS_SUCCESS) {
210 av_log(avctx, AV_LOG_ERROR, "Failed to end picture decode "
211 "issue: %d (%s).\n", vas, vaErrorStr(vas));
212 err = AVERROR(EIO);
213 if (CONFIG_VAAPI_1 || ctx->hwctx->driver_quirks &
214 AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS)
215 goto fail;
216 else
217 goto fail_at_end;
218 }
219
220 if (CONFIG_VAAPI_1 || ctx->hwctx->driver_quirks &
221 AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS)
222 ff_vaapi_decode_destroy_buffers(avctx, pic);
223
224 err = 0;
225 goto exit;
226
227 fail_with_picture:
228 vas = vaEndPicture(ctx->hwctx->display, ctx->va_context);
229 if (vas != VA_STATUS_SUCCESS) {
230 av_log(avctx, AV_LOG_ERROR, "Failed to end picture decode "
231 "after error: %d (%s).\n", vas, vaErrorStr(vas));
232 }
233 fail:
234 ff_vaapi_decode_destroy_buffers(avctx, pic);
235 fail_at_end:
236 exit:
237 pic->nb_param_buffers = 0;
238 pic->nb_param_buffers_allocated = 0;
239 av_freep(&pic->param_buffers);
240 pic->nb_slices = 0;
241 pic->nb_slice_buffers_allocated = 0;
242 av_freep(&pic->slice_buffers);
243
244 return err;
245 }
246
247 int ff_vaapi_decode_cancel(AVCodecContext *avctx,
248 VAAPIDecodePicture *pic)
249 {
250 ff_vaapi_decode_destroy_buffers(avctx, pic);
251
252 pic->nb_param_buffers = 0;
253 pic->nb_param_buffers_allocated = 0;
254 av_freep(&pic->param_buffers);
255 pic->nb_slices = 0;
256 pic->nb_slice_buffers_allocated = 0;
257 av_freep(&pic->slice_buffers);
258
259 return 0;
260 }
261
262 static const struct {
263 uint32_t fourcc;
264 enum AVPixelFormat pix_fmt;
265 } vaapi_format_map[] = {
266 #define MAP(va, av) { VA_FOURCC_ ## va, AV_PIX_FMT_ ## av }
267 // 4:0:0
268 MAP(Y800, GRAY8),
269 // 4:2:0
270 MAP(NV12, NV12),
271 MAP(YV12, YUV420P),
272 MAP(IYUV, YUV420P),
273 #ifdef VA_FOURCC_I420
274 MAP(I420, YUV420P),
275 #endif
276 MAP(IMC3, YUV420P),
277 // 4:1:1
278 MAP(411P, YUV411P),
279 // 4:2:2
280 MAP(422H, YUV422P),
281 #ifdef VA_FOURCC_YV16
282 MAP(YV16, YUV422P),
283 #endif
284 MAP(YUY2, YUYV422),
285 #ifdef VA_FOURCC_Y210
286 MAP(Y210, Y210),
287 #endif
288 #ifdef VA_FOURCC_Y212
289 MAP(Y212, Y212),
290 #endif
291 // 4:4:0
292 MAP(422V, YUV440P),
293 // 4:4:4
294 MAP(444P, YUV444P),
295 #ifdef VA_FOURCC_XYUV
296 MAP(XYUV, VUYX),
297 #endif
298 #ifdef VA_FOURCC_Y410
299 MAP(Y410, XV30),
300 #endif
301 #ifdef VA_FOURCC_Y412
302 MAP(Y412, XV36),
303 #endif
304 // 4:2:0 10-bit
305 #ifdef VA_FOURCC_P010
306 MAP(P010, P010),
307 #endif
308 #ifdef VA_FOURCC_P012
309 MAP(P012, P012),
310 #endif
311 #ifdef VA_FOURCC_I010
312 MAP(I010, YUV420P10),
313 #endif
314 #undef MAP
315 };
316
317 static int vaapi_decode_find_best_format(AVCodecContext *avctx,
318 AVHWDeviceContext *device,
319 VAConfigID config_id,
320 AVHWFramesContext *frames)
321 {
322 AVVAAPIDeviceContext *hwctx = device->hwctx;
323 VAStatus vas;
324 VASurfaceAttrib *attr;
325 enum AVPixelFormat source_format, best_format, format;
326 uint32_t best_fourcc, fourcc;
327 int i, j, nb_attr;
328
329 source_format = avctx->sw_pix_fmt;
330 av_assert0(source_format != AV_PIX_FMT_NONE);
331
332 vas = vaQuerySurfaceAttributes(hwctx->display, config_id,
333 NULL, &nb_attr);
334 if (vas != VA_STATUS_SUCCESS) {
335 av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: "
336 "%d (%s).\n", vas, vaErrorStr(vas));
337 return AVERROR(ENOSYS);
338 }
339
340 attr = av_malloc_array(nb_attr, sizeof(*attr));
341 if (!attr)
342 return AVERROR(ENOMEM);
343
344 vas = vaQuerySurfaceAttributes(hwctx->display, config_id,
345 attr, &nb_attr);
346 if (vas != VA_STATUS_SUCCESS) {
347 av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: "
348 "%d (%s).\n", vas, vaErrorStr(vas));
349 av_freep(&attr);
350 return AVERROR(ENOSYS);
351 }
352
353 best_format = AV_PIX_FMT_NONE;
354
355 for (i = 0; i < nb_attr; i++) {
356 if (attr[i].type != VASurfaceAttribPixelFormat)
357 continue;
358
359 fourcc = attr[i].value.value.i;
360 for (j = 0; j < FF_ARRAY_ELEMS(vaapi_format_map); j++) {
361 if (fourcc == vaapi_format_map[j].fourcc)
362 break;
363 }
364 if (j >= FF_ARRAY_ELEMS(vaapi_format_map)) {
365 av_log(avctx, AV_LOG_DEBUG, "Ignoring unknown format %#x.\n",
366 fourcc);
367 continue;
368 }
369 format = vaapi_format_map[j].pix_fmt;
370 av_log(avctx, AV_LOG_DEBUG, "Considering format %#x -> %s.\n",
371 fourcc, av_get_pix_fmt_name(format));
372
373 best_format = av_find_best_pix_fmt_of_2(format, best_format,
374 source_format, 0, NULL);
375 if (format == best_format)
376 best_fourcc = fourcc;
377 }
378
379 av_freep(&attr);
380
381 if (best_format == AV_PIX_FMT_NONE) {
382 av_log(avctx, AV_LOG_ERROR, "No usable formats for decoding!\n");
383 return AVERROR(EINVAL);
384 }
385
386 av_log(avctx, AV_LOG_DEBUG, "Picked %s (%#x) as best match for %s.\n",
387 av_get_pix_fmt_name(best_format), best_fourcc,
388 av_get_pix_fmt_name(source_format));
389
390 frames->sw_format = best_format;
391 if (avctx->internal->hwaccel_priv_data) {
392 VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
393 AVVAAPIFramesContext *avfc = frames->hwctx;
394
395 ctx->pixel_format_attribute = (VASurfaceAttrib) {
396 .type = VASurfaceAttribPixelFormat,
397 .flags = VA_SURFACE_ATTRIB_SETTABLE,
398 .value.type = VAGenericValueTypeInteger,
399 .value.value.i = best_fourcc,
400 };
401
402 avfc->attributes = &ctx->pixel_format_attribute;
403 avfc->nb_attributes = 1;
404 }
405
406 return 0;
407 }
408
409 static const struct {
410 enum AVCodecID codec_id;
411 int codec_profile;
412 VAProfile va_profile;
413 VAProfile (*profile_parser)(AVCodecContext *avctx);
414 } vaapi_profile_map[] = {
415 #define MAP(c, p, v, ...) { AV_CODEC_ID_ ## c, AV_PROFILE_ ## p, VAProfile ## v, __VA_ARGS__ }
416 MAP(MPEG2VIDEO, MPEG2_SIMPLE, MPEG2Simple ),
417 MAP(MPEG2VIDEO, MPEG2_MAIN, MPEG2Main ),
418 MAP(H263, UNKNOWN, H263Baseline),
419 MAP(MPEG4, MPEG4_SIMPLE, MPEG4Simple ),
420 MAP(MPEG4, MPEG4_ADVANCED_SIMPLE,
421 MPEG4AdvancedSimple),
422 MAP(MPEG4, MPEG4_MAIN, MPEG4Main ),
423 #if VA_CHECK_VERSION(1, 18, 0)
424 MAP(H264, H264_HIGH_10_INTRA,
425 H264High10 ),
426 MAP(H264, H264_HIGH_10, H264High10 ),
427 #endif
428 MAP(H264, H264_CONSTRAINED_BASELINE,
429 H264ConstrainedBaseline),
430 MAP(H264, H264_MAIN, H264Main ),
431 MAP(H264, H264_HIGH, H264High ),
432 #if VA_CHECK_VERSION(0, 37, 0)
433 MAP(HEVC, HEVC_MAIN, HEVCMain ),
434 MAP(HEVC, HEVC_MAIN_10, HEVCMain10 ),
435 MAP(HEVC, HEVC_MAIN_STILL_PICTURE,
436 HEVCMain ),
437 #endif
438 #if VA_CHECK_VERSION(1, 2, 0) && CONFIG_HEVC_VAAPI_HWACCEL
439 MAP(HEVC, HEVC_REXT, None,
440 ff_vaapi_parse_hevc_rext_scc_profile ),
441 MAP(HEVC, HEVC_SCC, None,
442 ff_vaapi_parse_hevc_rext_scc_profile ),
443 #endif
444 MAP(MJPEG, MJPEG_HUFFMAN_BASELINE_DCT,
445 JPEGBaseline),
446 MAP(WMV3, VC1_SIMPLE, VC1Simple ),
447 MAP(WMV3, VC1_MAIN, VC1Main ),
448 MAP(WMV3, VC1_COMPLEX, VC1Advanced ),
449 MAP(WMV3, VC1_ADVANCED, VC1Advanced ),
450 MAP(VC1, VC1_SIMPLE, VC1Simple ),
451 MAP(VC1, VC1_MAIN, VC1Main ),
452 MAP(VC1, VC1_COMPLEX, VC1Advanced ),
453 MAP(VC1, VC1_ADVANCED, VC1Advanced ),
454 MAP(VP8, UNKNOWN, VP8Version0_3 ),
455 #if VA_CHECK_VERSION(0, 38, 0)
456 MAP(VP9, VP9_0, VP9Profile0 ),
457 #endif
458 #if VA_CHECK_VERSION(0, 39, 0)
459 MAP(VP9, VP9_1, VP9Profile1 ),
460 MAP(VP9, VP9_2, VP9Profile2 ),
461 MAP(VP9, VP9_3, VP9Profile3 ),
462 #endif
463 #if VA_CHECK_VERSION(1, 8, 0)
464 MAP(AV1, AV1_MAIN, AV1Profile0),
465 MAP(AV1, AV1_HIGH, AV1Profile1),
466 #endif
467 #if VA_CHECK_VERSION(1, 22, 0)
468 MAP(H266, VVC_MAIN_10, VVCMain10),
469 #endif
470
471 #undef MAP
472 };
473
474 /*
475 * Set *va_config and the frames_ref fields from the current codec parameters
476 * in avctx.
477 */
478 static int vaapi_decode_make_config(AVCodecContext *avctx,
479 AVBufferRef *device_ref,
480 VAConfigID *va_config,
481 AVBufferRef *frames_ref)
482 {
483 AVVAAPIHWConfig *hwconfig = NULL;
484 AVHWFramesConstraints *constraints = NULL;
485 VAStatus vas;
486 int err, i, j;
487 const AVCodecDescriptor *codec_desc;
488 VAProfile *profile_list = NULL, matched_va_profile, va_profile;
489 int profile_count, exact_match, matched_ff_profile, codec_profile;
490
491 AVHWDeviceContext *device = (AVHWDeviceContext*)device_ref->data;
492 AVVAAPIDeviceContext *hwctx = device->hwctx;
493
494 codec_desc = avcodec_descriptor_get(avctx->codec_id);
495 if (!codec_desc) {
496 err = AVERROR(EINVAL);
497 goto fail;
498 }
499
500 profile_count = vaMaxNumProfiles(hwctx->display);
501 profile_list = av_malloc_array(profile_count,
502 sizeof(VAProfile));
503 if (!profile_list) {
504 err = AVERROR(ENOMEM);
505 goto fail;
506 }
507
508 vas = vaQueryConfigProfiles(hwctx->display,
509 profile_list, &profile_count);
510 if (vas != VA_STATUS_SUCCESS) {
511 av_log(avctx, AV_LOG_ERROR, "Failed to query profiles: "
512 "%d (%s).\n", vas, vaErrorStr(vas));
513 err = AVERROR(ENOSYS);
514 goto fail;
515 }
516
517 matched_va_profile = VAProfileNone;
518 exact_match = 0;
519
520 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_profile_map); i++) {
521 int profile_match = 0;
522 if (avctx->codec_id != vaapi_profile_map[i].codec_id)
523 continue;
524 if (avctx->profile == vaapi_profile_map[i].codec_profile ||
525 vaapi_profile_map[i].codec_profile == AV_PROFILE_UNKNOWN)
526 profile_match = 1;
527
528 va_profile = vaapi_profile_map[i].profile_parser ?
529 vaapi_profile_map[i].profile_parser(avctx) :
530 vaapi_profile_map[i].va_profile;
531 codec_profile = vaapi_profile_map[i].codec_profile;
532
533 for (j = 0; j < profile_count; j++) {
534 if (va_profile == profile_list[j]) {
535 exact_match = profile_match;
536 break;
537 }
538 }
539 if (j < profile_count) {
540 matched_va_profile = va_profile;
541 matched_ff_profile = codec_profile;
542 if (exact_match)
543 break;
544 }
545 }
546 av_freep(&profile_list);
547
548 if (matched_va_profile == VAProfileNone) {
549 av_log(avctx, AV_LOG_ERROR, "No support for codec %s "
550 "profile %d.\n", codec_desc->name, avctx->profile);
551 err = AVERROR(ENOSYS);
552 goto fail;
553 }
554 if (!exact_match) {
555 if (avctx->hwaccel_flags &
556 AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH) {
557 av_log(avctx, AV_LOG_VERBOSE, "Codec %s profile %d not "
558 "supported for hardware decode.\n",
559 codec_desc->name, avctx->profile);
560 av_log(avctx, AV_LOG_WARNING, "Using possibly-"
561 "incompatible profile %d instead.\n",
562 matched_ff_profile);
563 } else {
564 av_log(avctx, AV_LOG_VERBOSE, "Codec %s profile %d not "
565 "supported for hardware decode.\n",
566 codec_desc->name, avctx->profile);
567 err = AVERROR(EINVAL);
568 goto fail;
569 }
570 }
571
572 vas = vaCreateConfig(hwctx->display, matched_va_profile,
573 VAEntrypointVLD, NULL, 0,
574 va_config);
575 if (vas != VA_STATUS_SUCCESS) {
576 av_log(avctx, AV_LOG_ERROR, "Failed to create decode "
577 "configuration: %d (%s).\n", vas, vaErrorStr(vas));
578 err = AVERROR(EIO);
579 goto fail;
580 }
581
582 hwconfig = av_hwdevice_hwconfig_alloc(device_ref);
583 if (!hwconfig) {
584 err = AVERROR(ENOMEM);
585 goto fail;
586 }
587 hwconfig->config_id = *va_config;
588
589 constraints =
590 av_hwdevice_get_hwframe_constraints(device_ref, hwconfig);
591 if (!constraints) {
592 err = AVERROR(ENOMEM);
593 goto fail;
594 }
595
596 if (avctx->coded_width < constraints->min_width ||
597 avctx->coded_height < constraints->min_height ||
598 avctx->coded_width > constraints->max_width ||
599 avctx->coded_height > constraints->max_height) {
600 av_log(avctx, AV_LOG_ERROR, "Hardware does not support image "
601 "size %dx%d (constraints: width %d-%d height %d-%d).\n",
602 avctx->coded_width, avctx->coded_height,
603 constraints->min_width, constraints->max_width,
604 constraints->min_height, constraints->max_height);
605 err = AVERROR(EINVAL);
606 goto fail;
607 }
608 if (!constraints->valid_sw_formats ||
609 constraints->valid_sw_formats[0] == AV_PIX_FMT_NONE) {
610 av_log(avctx, AV_LOG_ERROR, "Hardware does not offer any "
611 "usable surface formats.\n");
612 err = AVERROR(EINVAL);
613 goto fail;
614 }
615
616 if (frames_ref) {
617 AVHWFramesContext *frames = (AVHWFramesContext *)frames_ref->data;
618
619 frames->format = AV_PIX_FMT_VAAPI;
620 frames->width = avctx->coded_width;
621 frames->height = avctx->coded_height;
622
623 err = vaapi_decode_find_best_format(avctx, device,
624 *va_config, frames);
625 if (err < 0)
626 goto fail;
627
628 if (CONFIG_VAAPI_1)
629 frames->initial_pool_size = 0;
630 else {
631 frames->initial_pool_size = 1;
632 // Add per-codec number of surfaces used for storing reference frames.
633 switch (avctx->codec_id) {
634 case AV_CODEC_ID_H264:
635 case AV_CODEC_ID_H266:
636 case AV_CODEC_ID_HEVC:
637 case AV_CODEC_ID_AV1:
638 frames->initial_pool_size += 16;
639 break;
640 case AV_CODEC_ID_VP9:
641 frames->initial_pool_size += 8;
642 break;
643 case AV_CODEC_ID_VP8:
644 frames->initial_pool_size += 3;
645 break;
646 default:
647 frames->initial_pool_size += 2;
648 }
649 }
650 }
651
652 av_hwframe_constraints_free(&constraints);
653 av_freep(&hwconfig);
654
655 return 0;
656
657 fail:
658 av_hwframe_constraints_free(&constraints);
659 av_freep(&hwconfig);
660 if (*va_config != VA_INVALID_ID) {
661 vaDestroyConfig(hwctx->display, *va_config);
662 *va_config = VA_INVALID_ID;
663 }
664 av_freep(&profile_list);
665 return err;
666 }
667
668 int ff_vaapi_common_frame_params(AVCodecContext *avctx,
669 AVBufferRef *hw_frames_ctx)
670 {
671 AVHWFramesContext *hw_frames = (AVHWFramesContext *)hw_frames_ctx->data;
672 AVHWDeviceContext *device_ctx = hw_frames->device_ctx;
673 AVVAAPIDeviceContext *hwctx;
674 VAConfigID va_config = VA_INVALID_ID;
675 int err;
676
677 if (device_ctx->type != AV_HWDEVICE_TYPE_VAAPI)
678 return AVERROR(EINVAL);
679 hwctx = device_ctx->hwctx;
680
681 err = vaapi_decode_make_config(avctx, hw_frames->device_ref, &va_config,
682 hw_frames_ctx);
683 if (err)
684 return err;
685
686 if (va_config != VA_INVALID_ID)
687 vaDestroyConfig(hwctx->display, va_config);
688
689 return 0;
690 }
691
692 int ff_vaapi_decode_init(AVCodecContext *avctx)
693 {
694 VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
695 VAStatus vas;
696 int err;
697
698 ctx->va_config = VA_INVALID_ID;
699 ctx->va_context = VA_INVALID_ID;
700
701 err = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_VAAPI);
702 if (err < 0)
703 goto fail;
704
705 ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
706 ctx->hwfc = ctx->frames->hwctx;
707 ctx->device = ctx->frames->device_ctx;
708 ctx->hwctx = ctx->device->hwctx;
709
710 err = vaapi_decode_make_config(avctx, ctx->frames->device_ref,
711 &ctx->va_config, NULL);
712 if (err)
713 goto fail;
714
715 vas = vaCreateContext(ctx->hwctx->display, ctx->va_config,
716 avctx->coded_width, avctx->coded_height,
717 VA_PROGRESSIVE,
718 ctx->hwfc->surface_ids,
719 ctx->hwfc->nb_surfaces,
720 &ctx->va_context);
721 if (vas != VA_STATUS_SUCCESS) {
722 av_log(avctx, AV_LOG_ERROR, "Failed to create decode "
723 "context: %d (%s).\n", vas, vaErrorStr(vas));
724 err = AVERROR(EIO);
725 goto fail;
726 }
727
728 av_log(avctx, AV_LOG_DEBUG, "Decode context initialised: "
729 "%#x/%#x.\n", ctx->va_config, ctx->va_context);
730
731 return 0;
732
733 fail:
734 ff_vaapi_decode_uninit(avctx);
735 return err;
736 }
737
738 int ff_vaapi_decode_uninit(AVCodecContext *avctx)
739 {
740 VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
741 VAStatus vas;
742
743 if (ctx->va_context != VA_INVALID_ID) {
744 vas = vaDestroyContext(ctx->hwctx->display, ctx->va_context);
745 if (vas != VA_STATUS_SUCCESS) {
746 av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode "
747 "context %#x: %d (%s).\n",
748 ctx->va_context, vas, vaErrorStr(vas));
749 }
750 }
751 if (ctx->va_config != VA_INVALID_ID) {
752 vas = vaDestroyConfig(ctx->hwctx->display, ctx->va_config);
753 if (vas != VA_STATUS_SUCCESS) {
754 av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode "
755 "configuration %#x: %d (%s).\n",
756 ctx->va_config, vas, vaErrorStr(vas));
757 }
758 }
759
760 return 0;
761 }
762