FFmpeg coverage


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