FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/vaapi_decode.c
Date: 2026-09-28 04:46:15
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