FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavutil/hwcontext_vaapi.c
Date: 2026-08-26 16:21:34
Exec Total Coverage
Lines: 0 925 0.0%
Functions: 0 34 0.0%
Branches: 0 454 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.h"
20
21 #if HAVE_VAAPI_WIN32
22 # include <windows.h>
23 #define COBJMACROS
24 # include <initguid.h>
25 # include <dxgi1_2.h>
26 # include "compat/w32dlfcn.h"
27 # include <va/va_win32.h>
28 typedef HRESULT (WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory);
29 #endif
30 #if HAVE_VAAPI_X11
31 # include <va/va_x11.h>
32 #endif
33 #if HAVE_VAAPI_DRM
34 # include <va/va_drm.h>
35 #endif
36
37 #if CONFIG_LIBDRM
38 # include <va/va_drmcommon.h>
39 # include <xf86drm.h>
40 # include <drm_fourcc.h>
41 # ifndef DRM_FORMAT_MOD_INVALID
42 # define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
43 # endif
44 #endif
45
46 #include <fcntl.h>
47 #if HAVE_UNISTD_H
48 # include <unistd.h>
49 #endif
50
51
52 #include "avassert.h"
53 #include "buffer.h"
54 #include "common.h"
55 #include "hwcontext.h"
56 #include "hwcontext_drm.h"
57 #include "hwcontext_internal.h"
58 #include "hwcontext_vaapi.h"
59 #include "mem.h"
60 #include "pixdesc.h"
61 #include "pixfmt.h"
62
63
64 typedef struct VAAPIDevicePriv {
65 #if HAVE_VAAPI_X11
66 Display *x11_display;
67 #endif
68
69 int drm_fd;
70 } VAAPIDevicePriv;
71
72 typedef struct VAAPISurfaceFormat {
73 enum AVPixelFormat pix_fmt;
74 VAImageFormat image_format;
75 unsigned int fourcc;
76 } VAAPISurfaceFormat;
77
78 typedef struct VAAPIDeviceContext {
79 /**
80 * The public AVVAAPIDeviceContext. See hwcontext_vaapi.h for it.
81 */
82 AVVAAPIDeviceContext p;
83
84 // Surface formats which can be used with this device.
85 VAAPISurfaceFormat *formats;
86 int nb_formats;
87 } VAAPIDeviceContext;
88
89 typedef struct VAAPIFramesContext {
90 /**
91 * The public AVVAAPIFramesContext. See hwcontext_vaapi.h for it.
92 */
93 AVVAAPIFramesContext p;
94
95 // Surface attributes set at create time.
96 VASurfaceAttrib *attributes;
97 int nb_attributes;
98 // RT format of the underlying surface (Intel driver ignores this anyway).
99 unsigned int rt_format;
100 // Whether vaDeriveImage works.
101 int derive_works;
102 // Caches whether VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2 is unsupported for
103 // surface imports.
104 int prime_2_import_unsupported;
105 } VAAPIFramesContext;
106
107 typedef struct VAAPIMapping {
108 // Handle to the derived or copied image which is mapped.
109 VAImage image;
110 // The mapping flags actually used.
111 int flags;
112 } VAAPIMapping;
113
114 typedef struct VAAPIFormat {
115 unsigned int fourcc;
116 unsigned int rt_format;
117 enum AVPixelFormat pix_fmt;
118 int chroma_planes_swapped;
119 } VAAPIFormatDescriptor;
120
121 #define MAP(va, rt, av, swap_uv) { \
122 VA_FOURCC_ ## va, \
123 VA_RT_FORMAT_ ## rt, \
124 AV_PIX_FMT_ ## av, \
125 swap_uv, \
126 }
127 // The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V
128 // plane swap cases. The frame handling below tries to hide these.
129 static const VAAPIFormatDescriptor vaapi_format_map[] = {
130 MAP(NV12, YUV420, NV12, 0),
131 #ifdef VA_FOURCC_I420
132 MAP(I420, YUV420, YUV420P, 0),
133 #endif
134 MAP(YV12, YUV420, YUV420P, 1),
135 MAP(IYUV, YUV420, YUV420P, 0),
136 MAP(422H, YUV422, YUV422P, 0),
137 #ifdef VA_FOURCC_YV16
138 MAP(YV16, YUV422, YUV422P, 1),
139 #endif
140 MAP(UYVY, YUV422, UYVY422, 0),
141 MAP(YUY2, YUV422, YUYV422, 0),
142 #ifdef VA_FOURCC_Y210
143 MAP(Y210, YUV422_10, Y210, 0),
144 #endif
145 #ifdef VA_FOURCC_Y212
146 MAP(Y212, YUV422_12, Y212, 0),
147 #endif
148 MAP(411P, YUV411, YUV411P, 0),
149 MAP(422V, YUV422, YUV440P, 0),
150 MAP(444P, YUV444, YUV444P, 0),
151 #ifdef VA_FOURCC_XYUV
152 MAP(XYUV, YUV444, VUYX, 0),
153 #endif
154 MAP(Y800, YUV400, GRAY8, 0),
155 #ifdef VA_FOURCC_P010
156 MAP(P010, YUV420_10BPP, P010, 0),
157 #endif
158 #ifdef VA_FOURCC_P012
159 MAP(P012, YUV420_12, P012, 0),
160 #endif
161 MAP(BGRA, RGB32, BGRA, 0),
162 MAP(BGRX, RGB32, BGR0, 0),
163 MAP(RGBA, RGB32, RGBA, 0),
164 MAP(RGBX, RGB32, RGB0, 0),
165 #ifdef VA_FOURCC_ABGR
166 MAP(ABGR, RGB32, ABGR, 0),
167 MAP(XBGR, RGB32, 0BGR, 0),
168 #endif
169 MAP(ARGB, RGB32, ARGB, 0),
170 MAP(XRGB, RGB32, 0RGB, 0),
171 #ifdef VA_FOURCC_X2R10G10B10
172 MAP(X2R10G10B10, RGB32_10, X2RGB10, 0),
173 #endif
174 #ifdef VA_FOURCC_Y410
175 // libva doesn't include a fourcc for XV30 and the driver only declares
176 // support for Y410, so we must fudge the mapping here.
177 MAP(Y410, YUV444_10, XV30, 0),
178 #endif
179 #ifdef VA_FOURCC_Y412
180 // libva doesn't include a fourcc for XV36 and the driver only declares
181 // support for Y412, so we must fudge the mapping here.
182 MAP(Y412, YUV444_12, XV36, 0),
183 #endif
184 };
185 #undef MAP
186
187 static const VAAPIFormatDescriptor *
188 vaapi_format_from_fourcc(unsigned int fourcc)
189 {
190 int i;
191 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
192 if (vaapi_format_map[i].fourcc == fourcc)
193 return &vaapi_format_map[i];
194 return NULL;
195 }
196
197 static const VAAPIFormatDescriptor *
198 vaapi_format_from_pix_fmt(enum AVPixelFormat pix_fmt, const VAAPIFormatDescriptor *prev)
199 {
200 const VAAPIFormatDescriptor *end = &vaapi_format_map[FF_ARRAY_ELEMS(vaapi_format_map)];
201 if (!prev)
202 prev = vaapi_format_map;
203 else
204 prev++;
205
206 for (; prev < end; prev++)
207 if (prev->pix_fmt == pix_fmt)
208 return prev;
209 return NULL;
210 }
211
212 static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc)
213 {
214 const VAAPIFormatDescriptor *desc;
215 desc = vaapi_format_from_fourcc(fourcc);
216 if (desc)
217 return desc->pix_fmt;
218 else
219 return AV_PIX_FMT_NONE;
220 }
221
222 static int vaapi_get_img_desc_and_format(AVHWDeviceContext *hwdev,
223 enum AVPixelFormat pix_fmt,
224 const VAAPIFormatDescriptor **_desc,
225 VAImageFormat **image_format)
226 {
227 VAAPIDeviceContext *ctx = hwdev->hwctx;
228 const VAAPIFormatDescriptor *desc = NULL;
229 int i;
230
231 while ((desc = vaapi_format_from_pix_fmt(pix_fmt, desc))) {
232 for (i = 0; i < ctx->nb_formats; i++) {
233 if (ctx->formats[i].fourcc == desc->fourcc) {
234 if (_desc)
235 *_desc = desc;
236 if (image_format)
237 *image_format = &ctx->formats[i].image_format;
238 return 0;
239 }
240 }
241 }
242
243 return AVERROR(ENOSYS);
244 }
245
246 static int vaapi_get_image_format(AVHWDeviceContext *hwdev,
247 enum AVPixelFormat pix_fmt,
248 VAImageFormat **image_format)
249 {
250 if (!image_format)
251 return AVERROR(EINVAL);
252 return vaapi_get_img_desc_and_format(hwdev, pix_fmt, NULL, image_format);
253 }
254
255 static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev,
256 const void *hwconfig,
257 AVHWFramesConstraints *constraints)
258 {
259 VAAPIDeviceContext *ctx = hwdev->hwctx;
260 AVVAAPIDeviceContext *hwctx = &ctx->p;
261 const AVVAAPIHWConfig *config = hwconfig;
262 VASurfaceAttrib *attr_list = NULL;
263 VAStatus vas;
264 enum AVPixelFormat pix_fmt;
265 unsigned int fourcc;
266 int err, i, j, attr_count, pix_fmt_count;
267
268 if (config &&
269 !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {
270 attr_count = 0;
271 vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
272 0, &attr_count);
273 if (vas != VA_STATUS_SUCCESS) {
274 av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
275 "%d (%s).\n", vas, vaErrorStr(vas));
276 err = AVERROR(ENOSYS);
277 goto fail;
278 }
279
280 attr_list = av_malloc(attr_count * sizeof(*attr_list));
281 if (!attr_list) {
282 err = AVERROR(ENOMEM);
283 goto fail;
284 }
285
286 vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
287 attr_list, &attr_count);
288 if (vas != VA_STATUS_SUCCESS) {
289 av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
290 "%d (%s).\n", vas, vaErrorStr(vas));
291 err = AVERROR(ENOSYS);
292 goto fail;
293 }
294
295 pix_fmt_count = 0;
296 for (i = 0; i < attr_count; i++) {
297 switch (attr_list[i].type) {
298 case VASurfaceAttribPixelFormat:
299 fourcc = attr_list[i].value.value.i;
300 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
301 if (pix_fmt != AV_PIX_FMT_NONE) {
302 ++pix_fmt_count;
303 } else {
304 // Something unsupported - ignore.
305 }
306 break;
307 case VASurfaceAttribMinWidth:
308 constraints->min_width = attr_list[i].value.value.i;
309 break;
310 case VASurfaceAttribMinHeight:
311 constraints->min_height = attr_list[i].value.value.i;
312 break;
313 case VASurfaceAttribMaxWidth:
314 constraints->max_width = attr_list[i].value.value.i;
315 break;
316 case VASurfaceAttribMaxHeight:
317 constraints->max_height = attr_list[i].value.value.i;
318 break;
319 }
320 }
321 if (pix_fmt_count == 0) {
322 // Nothing usable found. Presumably there exists something which
323 // works, so leave the set null to indicate unknown.
324 constraints->valid_sw_formats = NULL;
325 } else {
326 constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
327 sizeof(pix_fmt));
328 if (!constraints->valid_sw_formats) {
329 err = AVERROR(ENOMEM);
330 goto fail;
331 }
332
333 for (i = j = 0; i < attr_count; i++) {
334 int k;
335
336 if (attr_list[i].type != VASurfaceAttribPixelFormat)
337 continue;
338 fourcc = attr_list[i].value.value.i;
339 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
340
341 if (pix_fmt == AV_PIX_FMT_NONE)
342 continue;
343
344 for (k = 0; k < j; k++) {
345 if (constraints->valid_sw_formats[k] == pix_fmt)
346 break;
347 }
348
349 if (k == j)
350 constraints->valid_sw_formats[j++] = pix_fmt;
351 }
352 constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
353 }
354 } else {
355 // No configuration supplied.
356 // Return the full set of image formats known by the implementation.
357 constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1,
358 sizeof(pix_fmt));
359 if (!constraints->valid_sw_formats) {
360 err = AVERROR(ENOMEM);
361 goto fail;
362 }
363 for (i = j = 0; i < ctx->nb_formats; i++) {
364 int k;
365
366 for (k = 0; k < j; k++) {
367 if (constraints->valid_sw_formats[k] == ctx->formats[i].pix_fmt)
368 break;
369 }
370
371 if (k == j)
372 constraints->valid_sw_formats[j++] = ctx->formats[i].pix_fmt;
373 }
374
375 constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
376 }
377
378 constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
379 if (!constraints->valid_hw_formats) {
380 err = AVERROR(ENOMEM);
381 goto fail;
382 }
383 constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
384 constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
385
386 err = 0;
387 fail:
388 av_freep(&attr_list);
389 return err;
390 }
391
392 static const struct {
393 const char *friendly_name;
394 const char *match_string;
395 unsigned int quirks;
396 } vaapi_driver_quirks_table[] = {
397 #if !VA_CHECK_VERSION(1, 0, 0)
398 // The i965 driver did not conform before version 2.0.
399 {
400 "Intel i965 (Quick Sync)",
401 "i965",
402 AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS,
403 },
404 #endif
405 {
406 "Intel iHD",
407 "ubit",
408 AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE,
409 },
410 {
411 "VDPAU wrapper",
412 "Splitted-Desktop Systems VDPAU backend for VA-API",
413 AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES,
414 },
415 };
416
417 static int vaapi_device_init(AVHWDeviceContext *hwdev)
418 {
419 VAAPIDeviceContext *ctx = hwdev->hwctx;
420 AVVAAPIDeviceContext *hwctx = &ctx->p;
421 VAImageFormat *image_list = NULL;
422 VAStatus vas;
423 const char *vendor_string;
424 int err, i, image_count;
425 enum AVPixelFormat pix_fmt;
426 unsigned int fourcc;
427
428 image_count = vaMaxNumImageFormats(hwctx->display);
429 if (image_count <= 0) {
430 err = AVERROR(EIO);
431 goto fail;
432 }
433 image_list = av_malloc(image_count * sizeof(*image_list));
434 if (!image_list) {
435 err = AVERROR(ENOMEM);
436 goto fail;
437 }
438 vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
439 if (vas != VA_STATUS_SUCCESS) {
440 err = AVERROR(EIO);
441 goto fail;
442 }
443
444 ctx->formats = av_malloc(image_count * sizeof(*ctx->formats));
445 if (!ctx->formats) {
446 err = AVERROR(ENOMEM);
447 goto fail;
448 }
449 ctx->nb_formats = 0;
450 for (i = 0; i < image_count; i++) {
451 fourcc = image_list[i].fourcc;
452 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
453 if (pix_fmt == AV_PIX_FMT_NONE) {
454 av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n",
455 fourcc);
456 } else {
457 av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",
458 fourcc, av_get_pix_fmt_name(pix_fmt));
459 ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt;
460 ctx->formats[ctx->nb_formats].fourcc = fourcc;
461 ctx->formats[ctx->nb_formats].image_format = image_list[i];
462 ++ctx->nb_formats;
463 }
464 }
465
466 vendor_string = vaQueryVendorString(hwctx->display);
467 if (vendor_string)
468 av_log(hwdev, AV_LOG_VERBOSE, "VAAPI driver: %s.\n", vendor_string);
469
470 if (hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_USER_SET) {
471 av_log(hwdev, AV_LOG_VERBOSE, "Using quirks set by user (%#x).\n",
472 hwctx->driver_quirks);
473 } else {
474 // Detect the driver in use and set quirk flags if necessary.
475 hwctx->driver_quirks = 0;
476 if (vendor_string) {
477 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) {
478 if (strstr(vendor_string,
479 vaapi_driver_quirks_table[i].match_string)) {
480 av_log(hwdev, AV_LOG_VERBOSE, "Matched driver string "
481 "as known nonstandard driver \"%s\", setting "
482 "quirks (%#x).\n",
483 vaapi_driver_quirks_table[i].friendly_name,
484 vaapi_driver_quirks_table[i].quirks);
485 hwctx->driver_quirks |=
486 vaapi_driver_quirks_table[i].quirks;
487 break;
488 }
489 }
490 if (!(i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table))) {
491 av_log(hwdev, AV_LOG_VERBOSE, "Driver not found in known "
492 "nonstandard list, using standard behaviour.\n");
493 }
494 } else {
495 av_log(hwdev, AV_LOG_VERBOSE, "Driver has no vendor string, "
496 "assuming standard behaviour.\n");
497 }
498 }
499
500 av_free(image_list);
501 return 0;
502 fail:
503 av_freep(&ctx->formats);
504 av_free(image_list);
505 return err;
506 }
507
508 static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
509 {
510 VAAPIDeviceContext *ctx = hwdev->hwctx;
511
512 av_freep(&ctx->formats);
513 }
514
515 static void vaapi_buffer_free(void *opaque, uint8_t *data)
516 {
517 AVHWFramesContext *hwfc = opaque;
518 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
519 VASurfaceID surface_id;
520 VAStatus vas;
521
522 surface_id = (VASurfaceID)(uintptr_t)data;
523
524 vas = vaDestroySurfaces(hwctx->display, &surface_id, 1);
525 if (vas != VA_STATUS_SUCCESS) {
526 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: "
527 "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
528 }
529 }
530
531 static AVBufferRef *vaapi_pool_alloc(void *opaque, size_t size)
532 {
533 AVHWFramesContext *hwfc = opaque;
534 VAAPIFramesContext *ctx = hwfc->hwctx;
535 AVVAAPIFramesContext *avfc = &ctx->p;
536 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
537 VASurfaceID surface_id;
538 VAStatus vas;
539 AVBufferRef *ref;
540
541 if (hwfc->initial_pool_size > 0 &&
542 avfc->nb_surfaces >= hwfc->initial_pool_size)
543 return NULL;
544
545 vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
546 hwfc->width, hwfc->height,
547 &surface_id, 1,
548 ctx->attributes, ctx->nb_attributes);
549 if (vas != VA_STATUS_SUCCESS) {
550 av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
551 "%d (%s).\n", vas, vaErrorStr(vas));
552 return NULL;
553 }
554 av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
555
556 ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
557 sizeof(surface_id), &vaapi_buffer_free,
558 hwfc, AV_BUFFER_FLAG_READONLY);
559 if (!ref) {
560 vaDestroySurfaces(hwctx->display, &surface_id, 1);
561 return NULL;
562 }
563
564 if (hwfc->initial_pool_size > 0) {
565 // This is a fixed-size pool, so we must still be in the initial
566 // allocation sequence.
567 av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size);
568 avfc->surface_ids[avfc->nb_surfaces] = surface_id;
569 ++avfc->nb_surfaces;
570 }
571
572 return ref;
573 }
574
575 static int vaapi_frames_init(AVHWFramesContext *hwfc)
576 {
577 VAAPIFramesContext *ctx = hwfc->hwctx;
578 AVVAAPIFramesContext *avfc = &ctx->p;
579 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
580 const VAAPIFormatDescriptor *desc = NULL;
581 VAImageFormat *expected_format = NULL;
582 AVBufferRef *test_surface = NULL;
583 VASurfaceID test_surface_id;
584 VAImage test_image;
585 VAStatus vas;
586 int err, i;
587
588 err = vaapi_get_img_desc_and_format(hwfc->device_ctx, hwfc->sw_format,
589 &desc, &expected_format);
590 if (err < 0) {
591 // Use a relaxed check when pool exist. It can be an external pool.
592 if (!hwfc->pool || !vaapi_format_from_pix_fmt(hwfc->sw_format, NULL)) {
593 av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
594 av_get_pix_fmt_name(hwfc->sw_format));
595 return AVERROR(EINVAL);
596 }
597 }
598
599 if (!hwfc->pool) {
600 if (!(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {
601 int need_memory_type = !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE);
602 int need_pixel_format = 1;
603 for (i = 0; i < avfc->nb_attributes; i++) {
604 if (avfc->attributes[i].type == VASurfaceAttribMemoryType)
605 need_memory_type = 0;
606 if (avfc->attributes[i].type == VASurfaceAttribPixelFormat)
607 need_pixel_format = 0;
608 }
609 ctx->nb_attributes =
610 avfc->nb_attributes + need_memory_type + need_pixel_format;
611
612 ctx->attributes = av_malloc(ctx->nb_attributes *
613 sizeof(*ctx->attributes));
614 if (!ctx->attributes) {
615 err = AVERROR(ENOMEM);
616 goto fail;
617 }
618
619 for (i = 0; i < avfc->nb_attributes; i++)
620 ctx->attributes[i] = avfc->attributes[i];
621 if (need_memory_type) {
622 ctx->attributes[i++] = (VASurfaceAttrib) {
623 .type = VASurfaceAttribMemoryType,
624 .flags = VA_SURFACE_ATTRIB_SETTABLE,
625 .value.type = VAGenericValueTypeInteger,
626 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
627 };
628 }
629 if (need_pixel_format) {
630 ctx->attributes[i++] = (VASurfaceAttrib) {
631 .type = VASurfaceAttribPixelFormat,
632 .flags = VA_SURFACE_ATTRIB_SETTABLE,
633 .value.type = VAGenericValueTypeInteger,
634 .value.value.i = desc->fourcc,
635 };
636 }
637 av_assert0(i == ctx->nb_attributes);
638 } else {
639 ctx->attributes = NULL;
640 ctx->nb_attributes = 0;
641 }
642
643 ctx->rt_format = desc->rt_format;
644
645 if (hwfc->initial_pool_size > 0) {
646 // This pool will be usable as a render target, so we need to store
647 // all of the surface IDs somewhere that vaCreateContext() calls
648 // will be able to access them.
649 avfc->nb_surfaces = 0;
650 avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
651 sizeof(*avfc->surface_ids));
652 if (!avfc->surface_ids) {
653 err = AVERROR(ENOMEM);
654 goto fail;
655 }
656 } else {
657 // This pool allows dynamic sizing, and will not be usable as a
658 // render target.
659 avfc->nb_surfaces = 0;
660 avfc->surface_ids = NULL;
661 }
662
663 ffhwframesctx(hwfc)->pool_internal =
664 av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
665 &vaapi_pool_alloc, NULL);
666 if (!ffhwframesctx(hwfc)->pool_internal) {
667 av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
668 err = AVERROR(ENOMEM);
669 goto fail;
670 }
671 }
672
673 // Allocate a single surface to test whether vaDeriveImage() is going
674 // to work for the specific configuration.
675 if (hwfc->pool) {
676 test_surface = av_buffer_pool_get(hwfc->pool);
677 if (!test_surface) {
678 av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
679 "user-configured buffer pool.\n");
680 err = AVERROR(ENOMEM);
681 goto fail;
682 }
683 } else {
684 test_surface = av_buffer_pool_get(ffhwframesctx(hwfc)->pool_internal);
685 if (!test_surface) {
686 av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
687 "internal buffer pool.\n");
688 err = AVERROR(ENOMEM);
689 goto fail;
690 }
691 }
692 test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
693
694 ctx->derive_works = 0;
695 if (expected_format) {
696 vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
697 if (vas == VA_STATUS_SUCCESS) {
698 if (expected_format->fourcc == test_image.format.fourcc) {
699 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
700 ctx->derive_works = 1;
701 } else {
702 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
703 "derived image format %08x does not match "
704 "expected format %08x.\n",
705 expected_format->fourcc, test_image.format.fourcc);
706 }
707 vaDestroyImage(hwctx->display, test_image.image_id);
708 } else {
709 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
710 "deriving image does not work: "
711 "%d (%s).\n", vas, vaErrorStr(vas));
712 }
713 } else {
714 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
715 "image format is not supported.\n");
716 }
717
718 av_buffer_unref(&test_surface);
719 return 0;
720
721 fail:
722 av_buffer_unref(&test_surface);
723 av_freep(&avfc->surface_ids);
724 av_freep(&ctx->attributes);
725 return err;
726 }
727
728 static void vaapi_frames_uninit(AVHWFramesContext *hwfc)
729 {
730 VAAPIFramesContext *ctx = hwfc->hwctx;
731 AVVAAPIFramesContext *avfc = &ctx->p;
732
733 av_freep(&avfc->surface_ids);
734 av_freep(&ctx->attributes);
735 }
736
737 static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
738 {
739 frame->buf[0] = av_buffer_pool_get(hwfc->pool);
740 if (!frame->buf[0])
741 return AVERROR(ENOMEM);
742
743 frame->data[3] = frame->buf[0]->data;
744 frame->format = AV_PIX_FMT_VAAPI;
745 frame->width = hwfc->width;
746 frame->height = hwfc->height;
747
748 return 0;
749 }
750
751 static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc,
752 enum AVHWFrameTransferDirection dir,
753 enum AVPixelFormat **formats)
754 {
755 VAAPIDeviceContext *ctx = hwfc->device_ctx->hwctx;
756 enum AVPixelFormat *pix_fmts;
757 int i, k, sw_format_available;
758
759 sw_format_available = 0;
760 for (i = 0; i < ctx->nb_formats; i++) {
761 if (ctx->formats[i].pix_fmt == hwfc->sw_format)
762 sw_format_available = 1;
763 }
764
765 pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
766 if (!pix_fmts)
767 return AVERROR(ENOMEM);
768
769 if (sw_format_available) {
770 pix_fmts[0] = hwfc->sw_format;
771 k = 1;
772 } else {
773 k = 0;
774 }
775 for (i = 0; i < ctx->nb_formats; i++) {
776 if (ctx->formats[i].pix_fmt == hwfc->sw_format)
777 continue;
778 av_assert0(k < ctx->nb_formats);
779 pix_fmts[k++] = ctx->formats[i].pix_fmt;
780 }
781 pix_fmts[k] = AV_PIX_FMT_NONE;
782
783 *formats = pix_fmts;
784 return 0;
785 }
786
787 static void vaapi_unmap_frame(AVHWFramesContext *hwfc,
788 HWMapDescriptor *hwmap)
789 {
790 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
791 VAAPIMapping *map = hwmap->priv;
792 VASurfaceID surface_id;
793 VAStatus vas;
794
795 surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
796 av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
797
798 vas = vaUnmapBuffer(hwctx->display, map->image.buf);
799 if (vas != VA_STATUS_SUCCESS) {
800 av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
801 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
802 }
803
804 if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
805 !(map->flags & AV_HWFRAME_MAP_DIRECT)) {
806 vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
807 0, 0, hwfc->width, hwfc->height,
808 0, 0, hwfc->width, hwfc->height);
809 if (vas != VA_STATUS_SUCCESS) {
810 av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
811 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
812 }
813 }
814
815 vas = vaDestroyImage(hwctx->display, map->image.image_id);
816 if (vas != VA_STATUS_SUCCESS) {
817 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
818 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
819 }
820
821 av_free(map);
822 }
823
824 static int vaapi_map_frame(AVHWFramesContext *hwfc,
825 AVFrame *dst, const AVFrame *src, int flags)
826 {
827 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
828 VAAPIFramesContext *ctx = hwfc->hwctx;
829 VASurfaceID surface_id;
830 const VAAPIFormatDescriptor *desc;
831 VAImageFormat *image_format;
832 VAAPIMapping *map;
833 VAStatus vas;
834 void *address = NULL;
835 int err, i;
836 #if VA_CHECK_VERSION(1, 21, 0)
837 uint32_t vaflags = 0;
838 #endif
839
840 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
841 av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
842
843 if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) {
844 // Requested direct mapping but it is not possible.
845 return AVERROR(EINVAL);
846 }
847 if (dst->format == AV_PIX_FMT_NONE)
848 dst->format = hwfc->sw_format;
849 if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) {
850 // Requested direct mapping but the formats do not match.
851 return AVERROR(EINVAL);
852 }
853
854 err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
855 if (err < 0) {
856 // Requested format is not a valid output format.
857 return err;
858 }
859
860 map = av_malloc(sizeof(*map));
861 if (!map)
862 return AVERROR(ENOMEM);
863 map->flags = flags;
864 map->image.image_id = VA_INVALID_ID;
865
866 vas = vaSyncSurface(hwctx->display, surface_id);
867 if (vas != VA_STATUS_SUCCESS) {
868 av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
869 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
870 err = AVERROR(EIO);
871 goto fail;
872 }
873
874 // The memory which we map using derive need not be connected to the CPU
875 // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
876 // memory is mappable but not cached, so normal memcpy()-like access is
877 // very slow to read it (but writing is ok). It is possible to read much
878 // faster with a copy routine which is aware of the limitation, but we
879 // assume for now that the user is not aware of that and would therefore
880 // prefer not to be given direct-mapped memory if they request read access.
881 if (ctx->derive_works && dst->format == hwfc->sw_format &&
882 ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) {
883 vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
884 if (vas != VA_STATUS_SUCCESS) {
885 av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
886 "surface %#x: %d (%s).\n",
887 surface_id, vas, vaErrorStr(vas));
888 err = AVERROR(EIO);
889 goto fail;
890 }
891 if (map->image.format.fourcc != image_format->fourcc) {
892 av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
893 "is in wrong format: expected %#08x, got %#08x.\n",
894 surface_id, image_format->fourcc, map->image.format.fourcc);
895 err = AVERROR(EIO);
896 goto fail;
897 }
898 map->flags |= AV_HWFRAME_MAP_DIRECT;
899 } else {
900 vas = vaCreateImage(hwctx->display, image_format,
901 hwfc->width, hwfc->height, &map->image);
902 if (vas != VA_STATUS_SUCCESS) {
903 av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
904 "surface %#x: %d (%s).\n",
905 surface_id, vas, vaErrorStr(vas));
906 err = AVERROR(EIO);
907 goto fail;
908 }
909 if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) {
910 vas = vaGetImage(hwctx->display, surface_id, 0, 0,
911 hwfc->width, hwfc->height, map->image.image_id);
912 if (vas != VA_STATUS_SUCCESS) {
913 av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
914 "surface %#x: %d (%s).\n",
915 surface_id, vas, vaErrorStr(vas));
916 err = AVERROR(EIO);
917 goto fail;
918 }
919 }
920 }
921
922 #if VA_CHECK_VERSION(1, 21, 0)
923 if (flags & AV_HWFRAME_MAP_READ)
924 vaflags |= VA_MAPBUFFER_FLAG_READ;
925 if (flags & AV_HWFRAME_MAP_WRITE)
926 vaflags |= VA_MAPBUFFER_FLAG_WRITE;
927 // On drivers not implementing vaMapBuffer2 libva calls vaMapBuffer instead.
928 vas = vaMapBuffer2(hwctx->display, map->image.buf, &address, vaflags);
929 #else
930 vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
931 #endif
932 if (vas != VA_STATUS_SUCCESS) {
933 av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
934 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
935 err = AVERROR(EIO);
936 goto fail;
937 }
938
939 err = ff_hwframe_map_create(src->hw_frames_ctx,
940 dst, src, &vaapi_unmap_frame, map);
941 if (err < 0)
942 goto fail;
943
944 dst->width = src->width;
945 dst->height = src->height;
946
947 for (i = 0; i < map->image.num_planes; i++) {
948 dst->data[i] = (uint8_t*)address + map->image.offsets[i];
949 dst->linesize[i] = map->image.pitches[i];
950 }
951
952 desc = vaapi_format_from_fourcc(map->image.format.fourcc);
953 if (desc && desc->chroma_planes_swapped) {
954 // Chroma planes are YVU rather than YUV, so swap them.
955 FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
956 }
957
958 return 0;
959
960 fail:
961 if (map) {
962 if (address)
963 vaUnmapBuffer(hwctx->display, map->image.buf);
964 if (map->image.image_id != VA_INVALID_ID)
965 vaDestroyImage(hwctx->display, map->image.image_id);
966 av_free(map);
967 }
968 return err;
969 }
970
971 static int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
972 AVFrame *dst, const AVFrame *src)
973 {
974 AVFrame *map;
975 int err;
976
977 if (dst->width > hwfc->width || dst->height > hwfc->height)
978 return AVERROR(EINVAL);
979
980 map = av_frame_alloc();
981 if (!map)
982 return AVERROR(ENOMEM);
983 map->format = dst->format;
984
985 err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
986 if (err)
987 goto fail;
988
989 map->width = dst->width;
990 map->height = dst->height;
991
992 err = av_frame_copy(dst, map);
993 if (err)
994 goto fail;
995
996 err = 0;
997 fail:
998 av_frame_free(&map);
999 return err;
1000 }
1001
1002 static int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
1003 AVFrame *dst, const AVFrame *src)
1004 {
1005 AVFrame *map;
1006 int err;
1007
1008 if (src->width > hwfc->width || src->height > hwfc->height)
1009 return AVERROR(EINVAL);
1010
1011 map = av_frame_alloc();
1012 if (!map)
1013 return AVERROR(ENOMEM);
1014 map->format = src->format;
1015
1016 err = vaapi_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE);
1017 if (err)
1018 goto fail;
1019
1020 map->width = src->width;
1021 map->height = src->height;
1022
1023 err = av_frame_copy(map, src);
1024 if (err)
1025 goto fail;
1026
1027 err = 0;
1028 fail:
1029 av_frame_free(&map);
1030 return err;
1031 }
1032
1033 static int vaapi_map_to_memory(AVHWFramesContext *hwfc, AVFrame *dst,
1034 const AVFrame *src, int flags)
1035 {
1036 int err;
1037
1038 err = vaapi_map_frame(hwfc, dst, src, flags);
1039 if (err)
1040 return err;
1041
1042 err = av_frame_copy_props(dst, src);
1043 if (err)
1044 return err;
1045
1046 return 0;
1047 }
1048
1049 #if CONFIG_LIBDRM
1050
1051 #define DRM_MAP(va, layers, ...) { \
1052 VA_FOURCC_ ## va, \
1053 layers, \
1054 { __VA_ARGS__ } \
1055 }
1056 static const struct {
1057 uint32_t va_fourcc;
1058 int nb_layer_formats;
1059 uint32_t layer_formats[AV_DRM_MAX_PLANES];
1060 } vaapi_drm_format_map[] = {
1061 #ifdef DRM_FORMAT_R8
1062 DRM_MAP(NV12, 2, DRM_FORMAT_R8, DRM_FORMAT_RG88),
1063 DRM_MAP(NV12, 2, DRM_FORMAT_R8, DRM_FORMAT_GR88),
1064 #endif
1065 DRM_MAP(NV12, 1, DRM_FORMAT_NV12),
1066 #if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16)
1067 DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
1068 #endif
1069 #if defined(VA_FOURCC_P012) && defined(DRM_FORMAT_R16)
1070 DRM_MAP(P012, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
1071 #endif
1072 DRM_MAP(BGRA, 1, DRM_FORMAT_ARGB8888),
1073 DRM_MAP(BGRX, 1, DRM_FORMAT_XRGB8888),
1074 DRM_MAP(RGBA, 1, DRM_FORMAT_ABGR8888),
1075 DRM_MAP(RGBX, 1, DRM_FORMAT_XBGR8888),
1076 #ifdef VA_FOURCC_ABGR
1077 DRM_MAP(ABGR, 1, DRM_FORMAT_RGBA8888),
1078 DRM_MAP(XBGR, 1, DRM_FORMAT_RGBX8888),
1079 #endif
1080 DRM_MAP(ARGB, 1, DRM_FORMAT_BGRA8888),
1081 DRM_MAP(XRGB, 1, DRM_FORMAT_BGRX8888),
1082 #if defined(VA_FOURCC_XYUV) && defined(DRM_FORMAT_XYUV8888)
1083 DRM_MAP(XYUV, 1, DRM_FORMAT_XYUV8888),
1084 #endif
1085 #if defined(VA_FOURCC_Y412) && defined(DRM_FORMAT_XVYU2101010)
1086 DRM_MAP(Y410, 1, DRM_FORMAT_XVYU2101010),
1087 #endif
1088 #if defined(VA_FOURCC_Y412) && defined(DRM_FORMAT_XVYU12_16161616)
1089 DRM_MAP(Y412, 1, DRM_FORMAT_XVYU12_16161616),
1090 #endif
1091 #if defined(VA_FOURCC_X2R10G10B10) && defined(DRM_FORMAT_XRGB2101010)
1092 DRM_MAP(X2R10G10B10, 1, DRM_FORMAT_XRGB2101010),
1093 #endif
1094 };
1095 #undef DRM_MAP
1096
1097 static void vaapi_unmap_from_drm(AVHWFramesContext *dst_fc,
1098 HWMapDescriptor *hwmap)
1099 {
1100 AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
1101
1102 VASurfaceID surface_id = (VASurfaceID)(uintptr_t)hwmap->priv;
1103
1104 av_log(dst_fc, AV_LOG_DEBUG, "Destroy surface %#x.\n", surface_id);
1105
1106 vaDestroySurfaces(dst_dev->display, &surface_id, 1);
1107 }
1108
1109 static int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst,
1110 const AVFrame *src, int flags)
1111 {
1112 #if VA_CHECK_VERSION(1, 1, 0)
1113 VAAPIFramesContext *src_vafc = src_fc->hwctx;
1114 int use_prime2;
1115 #else
1116 int k;
1117 #endif
1118 AVHWFramesContext *dst_fc =
1119 (AVHWFramesContext*)dst->hw_frames_ctx->data;
1120 AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
1121 const AVDRMFrameDescriptor *desc;
1122 const VAAPIFormatDescriptor *format_desc;
1123 VASurfaceID surface_id;
1124 VAStatus vas = VA_STATUS_SUCCESS;
1125 uint32_t va_fourcc;
1126 int err, i, j;
1127
1128 #if !VA_CHECK_VERSION(1, 1, 0)
1129 unsigned long buffer_handle;
1130 VASurfaceAttribExternalBuffers buffer_desc;
1131 VASurfaceAttrib attrs[2] = {
1132 {
1133 .type = VASurfaceAttribMemoryType,
1134 .flags = VA_SURFACE_ATTRIB_SETTABLE,
1135 .value.type = VAGenericValueTypeInteger,
1136 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
1137 },
1138 {
1139 .type = VASurfaceAttribExternalBufferDescriptor,
1140 .flags = VA_SURFACE_ATTRIB_SETTABLE,
1141 .value.type = VAGenericValueTypePointer,
1142 .value.value.p = &buffer_desc,
1143 }
1144 };
1145 #endif
1146
1147 desc = (AVDRMFrameDescriptor*)src->data[0];
1148
1149 if (desc->nb_objects != 1) {
1150 av_log(dst_fc, AV_LOG_ERROR, "VAAPI can only map frames "
1151 "made from a single DRM object.\n");
1152 return AVERROR(EINVAL);
1153 }
1154
1155 va_fourcc = 0;
1156 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
1157 if (desc->nb_layers != vaapi_drm_format_map[i].nb_layer_formats)
1158 continue;
1159 for (j = 0; j < desc->nb_layers; j++) {
1160 if (desc->layers[j].format !=
1161 vaapi_drm_format_map[i].layer_formats[j])
1162 break;
1163 }
1164 if (j != desc->nb_layers)
1165 continue;
1166 va_fourcc = vaapi_drm_format_map[i].va_fourcc;
1167 break;
1168 }
1169 if (!va_fourcc) {
1170 av_log(dst_fc, AV_LOG_ERROR, "DRM format not supported "
1171 "by VAAPI.\n");
1172 return AVERROR(EINVAL);
1173 }
1174
1175 av_log(dst_fc, AV_LOG_DEBUG, "Map DRM object %d to VAAPI as "
1176 "%08x.\n", desc->objects[0].fd, va_fourcc);
1177
1178 format_desc = vaapi_format_from_fourcc(va_fourcc);
1179 av_assert0(format_desc);
1180
1181 #if VA_CHECK_VERSION(1, 1, 0)
1182 use_prime2 = !src_vafc->prime_2_import_unsupported &&
1183 desc->objects[0].format_modifier != DRM_FORMAT_MOD_INVALID;
1184 if (use_prime2) {
1185 VADRMPRIMESurfaceDescriptor prime_desc;
1186 VASurfaceAttrib prime_attrs[2] = {
1187 {
1188 .type = VASurfaceAttribMemoryType,
1189 .flags = VA_SURFACE_ATTRIB_SETTABLE,
1190 .value.type = VAGenericValueTypeInteger,
1191 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
1192 },
1193 {
1194 .type = VASurfaceAttribExternalBufferDescriptor,
1195 .flags = VA_SURFACE_ATTRIB_SETTABLE,
1196 .value.type = VAGenericValueTypePointer,
1197 .value.value.p = &prime_desc,
1198 }
1199 };
1200 prime_desc.fourcc = va_fourcc;
1201 prime_desc.width = src_fc->width;
1202 prime_desc.height = src_fc->height;
1203 prime_desc.num_objects = desc->nb_objects;
1204 for (i = 0; i < desc->nb_objects; ++i) {
1205 prime_desc.objects[i].fd = desc->objects[i].fd;
1206 prime_desc.objects[i].size = desc->objects[i].size;
1207 prime_desc.objects[i].drm_format_modifier =
1208 desc->objects[i].format_modifier;
1209 }
1210
1211 prime_desc.num_layers = desc->nb_layers;
1212 for (i = 0; i < desc->nb_layers; ++i) {
1213 prime_desc.layers[i].drm_format = desc->layers[i].format;
1214 prime_desc.layers[i].num_planes = desc->layers[i].nb_planes;
1215 for (j = 0; j < desc->layers[i].nb_planes; ++j) {
1216 prime_desc.layers[i].object_index[j] =
1217 desc->layers[i].planes[j].object_index;
1218 prime_desc.layers[i].offset[j] = desc->layers[i].planes[j].offset;
1219 prime_desc.layers[i].pitch[j] = desc->layers[i].planes[j].pitch;
1220 }
1221
1222 if (format_desc->chroma_planes_swapped &&
1223 desc->layers[i].nb_planes == 3) {
1224 FFSWAP(uint32_t, prime_desc.layers[i].pitch[1],
1225 prime_desc.layers[i].pitch[2]);
1226 FFSWAP(uint32_t, prime_desc.layers[i].offset[1],
1227 prime_desc.layers[i].offset[2]);
1228 }
1229 }
1230
1231 /*
1232 * We can query for PRIME_2 support with vaQuerySurfaceAttributes, but that
1233 * that needs the config_id which we don't have here . Both Intel and
1234 * Gallium seem to do the correct error checks, so lets just try the
1235 * PRIME_2 import first.
1236 */
1237 vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format,
1238 src->width, src->height, &surface_id, 1,
1239 prime_attrs, FF_ARRAY_ELEMS(prime_attrs));
1240 if (vas != VA_STATUS_SUCCESS)
1241 src_vafc->prime_2_import_unsupported = 1;
1242 }
1243
1244 if (!use_prime2 || vas != VA_STATUS_SUCCESS) {
1245 int k;
1246 uintptr_t buffer_handle;
1247 VASurfaceAttribExternalBuffers buffer_desc;
1248 VASurfaceAttrib buffer_attrs[2] = {
1249 {
1250 .type = VASurfaceAttribMemoryType,
1251 .flags = VA_SURFACE_ATTRIB_SETTABLE,
1252 .value.type = VAGenericValueTypeInteger,
1253 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
1254 },
1255 {
1256 .type = VASurfaceAttribExternalBufferDescriptor,
1257 .flags = VA_SURFACE_ATTRIB_SETTABLE,
1258 .value.type = VAGenericValueTypePointer,
1259 .value.value.p = &buffer_desc,
1260 }
1261 };
1262
1263 buffer_handle = desc->objects[0].fd;
1264 buffer_desc.pixel_format = va_fourcc;
1265 buffer_desc.width = src_fc->width;
1266 buffer_desc.height = src_fc->height;
1267 buffer_desc.data_size = desc->objects[0].size;
1268 buffer_desc.buffers = &buffer_handle;
1269 buffer_desc.num_buffers = 1;
1270 buffer_desc.flags = 0;
1271
1272 k = 0;
1273 for (i = 0; i < desc->nb_layers; i++) {
1274 for (j = 0; j < desc->layers[i].nb_planes; j++) {
1275 buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch;
1276 buffer_desc.offsets[k] = desc->layers[i].planes[j].offset;
1277 ++k;
1278 }
1279 }
1280 buffer_desc.num_planes = k;
1281
1282 if (format_desc->chroma_planes_swapped &&
1283 buffer_desc.num_planes == 3) {
1284 FFSWAP(uint32_t, buffer_desc.pitches[1], buffer_desc.pitches[2]);
1285 FFSWAP(uint32_t, buffer_desc.offsets[1], buffer_desc.offsets[2]);
1286 }
1287
1288 vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format,
1289 src->width, src->height,
1290 &surface_id, 1,
1291 buffer_attrs, FF_ARRAY_ELEMS(buffer_attrs));
1292 }
1293 #else
1294 buffer_handle = desc->objects[0].fd;
1295 buffer_desc.pixel_format = va_fourcc;
1296 buffer_desc.width = src_fc->width;
1297 buffer_desc.height = src_fc->height;
1298 buffer_desc.data_size = desc->objects[0].size;
1299 buffer_desc.buffers = &buffer_handle;
1300 buffer_desc.num_buffers = 1;
1301 buffer_desc.flags = 0;
1302
1303 k = 0;
1304 for (i = 0; i < desc->nb_layers; i++) {
1305 for (j = 0; j < desc->layers[i].nb_planes; j++) {
1306 buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch;
1307 buffer_desc.offsets[k] = desc->layers[i].planes[j].offset;
1308 ++k;
1309 }
1310 }
1311 buffer_desc.num_planes = k;
1312
1313 if (format_desc->chroma_planes_swapped &&
1314 buffer_desc.num_planes == 3) {
1315 FFSWAP(uint32_t, buffer_desc.pitches[1], buffer_desc.pitches[2]);
1316 FFSWAP(uint32_t, buffer_desc.offsets[1], buffer_desc.offsets[2]);
1317 }
1318
1319 vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format,
1320 src->width, src->height,
1321 &surface_id, 1,
1322 attrs, FF_ARRAY_ELEMS(attrs));
1323 #endif
1324 if (vas != VA_STATUS_SUCCESS) {
1325 av_log(dst_fc, AV_LOG_ERROR, "Failed to create surface from DRM "
1326 "object: %d (%s).\n", vas, vaErrorStr(vas));
1327 return AVERROR(EIO);
1328 }
1329 av_log(dst_fc, AV_LOG_DEBUG, "Create surface %#x.\n", surface_id);
1330
1331 err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
1332 &vaapi_unmap_from_drm,
1333 (void*)(uintptr_t)surface_id);
1334 if (err < 0)
1335 return err;
1336
1337 dst->width = src->width;
1338 dst->height = src->height;
1339 dst->data[3] = (uint8_t*)(uintptr_t)surface_id;
1340
1341 av_log(dst_fc, AV_LOG_DEBUG, "Mapped DRM object %d to "
1342 "surface %#x.\n", desc->objects[0].fd, surface_id);
1343
1344 return 0;
1345 }
1346
1347 #if VA_CHECK_VERSION(1, 1, 0)
1348 static void vaapi_unmap_to_drm_esh(AVHWFramesContext *hwfc,
1349 HWMapDescriptor *hwmap)
1350 {
1351 AVDRMFrameDescriptor *drm_desc = hwmap->priv;
1352 int i;
1353
1354 for (i = 0; i < drm_desc->nb_objects; i++)
1355 close(drm_desc->objects[i].fd);
1356
1357 av_freep(&drm_desc);
1358 }
1359
1360 static int vaapi_map_to_drm_esh(AVHWFramesContext *hwfc, AVFrame *dst,
1361 const AVFrame *src, int flags)
1362 {
1363 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1364 VASurfaceID surface_id;
1365 VAStatus vas;
1366 VADRMPRIMESurfaceDescriptor va_desc;
1367 AVDRMFrameDescriptor *drm_desc = NULL;
1368 uint32_t export_flags;
1369 int err, i, j;
1370
1371 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
1372
1373 export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS;
1374 if (flags & AV_HWFRAME_MAP_READ) {
1375 export_flags |= VA_EXPORT_SURFACE_READ_ONLY;
1376
1377 vas = vaSyncSurface(hwctx->display, surface_id);
1378 if (vas != VA_STATUS_SUCCESS) {
1379 av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
1380 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
1381 return AVERROR(EIO);
1382 }
1383 }
1384
1385 if (flags & AV_HWFRAME_MAP_WRITE)
1386 export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY;
1387
1388 vas = vaExportSurfaceHandle(hwctx->display, surface_id,
1389 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
1390 export_flags, &va_desc);
1391 if (vas != VA_STATUS_SUCCESS) {
1392 if (vas == VA_STATUS_ERROR_UNIMPLEMENTED)
1393 return AVERROR(ENOSYS);
1394 av_log(hwfc, AV_LOG_ERROR, "Failed to export surface %#x: "
1395 "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
1396 return AVERROR(EIO);
1397 }
1398
1399 drm_desc = av_mallocz(sizeof(*drm_desc));
1400 if (!drm_desc) {
1401 err = AVERROR(ENOMEM);
1402 goto fail;
1403 }
1404
1405 // By some bizarre coincidence, these structures are very similar...
1406 drm_desc->nb_objects = va_desc.num_objects;
1407 for (i = 0; i < va_desc.num_objects; i++) {
1408 drm_desc->objects[i].fd = va_desc.objects[i].fd;
1409 drm_desc->objects[i].size = va_desc.objects[i].size;
1410 drm_desc->objects[i].format_modifier =
1411 va_desc.objects[i].drm_format_modifier;
1412 }
1413 drm_desc->nb_layers = va_desc.num_layers;
1414 for (i = 0; i < va_desc.num_layers; i++) {
1415 drm_desc->layers[i].format = va_desc.layers[i].drm_format;
1416 drm_desc->layers[i].nb_planes = va_desc.layers[i].num_planes;
1417 for (j = 0; j < va_desc.layers[i].num_planes; j++) {
1418 drm_desc->layers[i].planes[j].object_index =
1419 va_desc.layers[i].object_index[j];
1420 drm_desc->layers[i].planes[j].offset =
1421 va_desc.layers[i].offset[j];
1422 drm_desc->layers[i].planes[j].pitch =
1423 va_desc.layers[i].pitch[j];
1424 }
1425 }
1426
1427 err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
1428 &vaapi_unmap_to_drm_esh, drm_desc);
1429 if (err < 0)
1430 goto fail;
1431
1432 dst->width = src->width;
1433 dst->height = src->height;
1434 dst->data[0] = (uint8_t*)drm_desc;
1435
1436 return 0;
1437
1438 fail:
1439 for (i = 0; i < va_desc.num_objects; i++)
1440 close(va_desc.objects[i].fd);
1441 av_freep(&drm_desc);
1442 return err;
1443 }
1444 #endif
1445
1446 #if VA_CHECK_VERSION(0, 36, 0)
1447 typedef struct VAAPIDRMImageBufferMapping {
1448 VAImage image;
1449 VABufferInfo buffer_info;
1450
1451 AVDRMFrameDescriptor drm_desc;
1452 } VAAPIDRMImageBufferMapping;
1453
1454 static void vaapi_unmap_to_drm_abh(AVHWFramesContext *hwfc,
1455 HWMapDescriptor *hwmap)
1456 {
1457 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1458 VAAPIDRMImageBufferMapping *mapping = hwmap->priv;
1459 VASurfaceID surface_id;
1460 VAStatus vas;
1461
1462 surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
1463 av_log(hwfc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from DRM.\n",
1464 surface_id);
1465
1466 // DRM PRIME file descriptors are closed by vaReleaseBufferHandle(),
1467 // so we shouldn't close them separately.
1468
1469 vas = vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
1470 if (vas != VA_STATUS_SUCCESS) {
1471 av_log(hwfc, AV_LOG_ERROR, "Failed to release buffer "
1472 "handle of image %#x (derived from surface %#x): "
1473 "%d (%s).\n", mapping->image.buf, surface_id,
1474 vas, vaErrorStr(vas));
1475 }
1476
1477 vas = vaDestroyImage(hwctx->display, mapping->image.image_id);
1478 if (vas != VA_STATUS_SUCCESS) {
1479 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image "
1480 "derived from surface %#x: %d (%s).\n",
1481 surface_id, vas, vaErrorStr(vas));
1482 }
1483
1484 av_free(mapping);
1485 }
1486
1487 static int vaapi_map_to_drm_abh(AVHWFramesContext *hwfc, AVFrame *dst,
1488 const AVFrame *src, int flags)
1489 {
1490 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1491 VAAPIDRMImageBufferMapping *mapping = NULL;
1492 VASurfaceID surface_id;
1493 VAStatus vas;
1494 int err, i, p;
1495
1496 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
1497 av_log(hwfc, AV_LOG_DEBUG, "Map VAAPI surface %#x to DRM.\n",
1498 surface_id);
1499
1500 mapping = av_mallocz(sizeof(*mapping));
1501 if (!mapping)
1502 return AVERROR(ENOMEM);
1503
1504 vas = vaDeriveImage(hwctx->display, surface_id,
1505 &mapping->image);
1506 if (vas != VA_STATUS_SUCCESS) {
1507 av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
1508 "surface %#x: %d (%s).\n",
1509 surface_id, vas, vaErrorStr(vas));
1510 err = AVERROR(EIO);
1511 goto fail;
1512 }
1513
1514 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
1515 if (vaapi_drm_format_map[i].va_fourcc ==
1516 mapping->image.format.fourcc)
1517 break;
1518 }
1519 if (i >= FF_ARRAY_ELEMS(vaapi_drm_format_map)) {
1520 av_log(hwfc, AV_LOG_ERROR, "No matching DRM format for "
1521 "VAAPI format %#x.\n", mapping->image.format.fourcc);
1522 err = AVERROR(EINVAL);
1523 goto fail_derived;
1524 }
1525
1526 mapping->buffer_info.mem_type =
1527 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
1528
1529 mapping->drm_desc.nb_layers =
1530 vaapi_drm_format_map[i].nb_layer_formats;
1531 if (mapping->drm_desc.nb_layers > 1) {
1532 if (mapping->drm_desc.nb_layers != mapping->image.num_planes) {
1533 av_log(hwfc, AV_LOG_ERROR, "Image properties do not match "
1534 "expected format: got %d planes, but expected %d.\n",
1535 mapping->image.num_planes, mapping->drm_desc.nb_layers);
1536 err = AVERROR(EINVAL);
1537 goto fail_derived;
1538 }
1539
1540 for(p = 0; p < mapping->drm_desc.nb_layers; p++) {
1541 mapping->drm_desc.layers[p] = (AVDRMLayerDescriptor) {
1542 .format = vaapi_drm_format_map[i].layer_formats[p],
1543 .nb_planes = 1,
1544 .planes[0] = {
1545 .object_index = 0,
1546 .offset = mapping->image.offsets[p],
1547 .pitch = mapping->image.pitches[p],
1548 },
1549 };
1550 }
1551 } else {
1552 mapping->drm_desc.layers[0].format =
1553 vaapi_drm_format_map[i].layer_formats[0];
1554 mapping->drm_desc.layers[0].nb_planes = mapping->image.num_planes;
1555 for (p = 0; p < mapping->image.num_planes; p++) {
1556 mapping->drm_desc.layers[0].planes[p] = (AVDRMPlaneDescriptor) {
1557 .object_index = 0,
1558 .offset = mapping->image.offsets[p],
1559 .pitch = mapping->image.pitches[p],
1560 };
1561 }
1562 }
1563
1564 vas = vaAcquireBufferHandle(hwctx->display, mapping->image.buf,
1565 &mapping->buffer_info);
1566 if (vas != VA_STATUS_SUCCESS) {
1567 av_log(hwfc, AV_LOG_ERROR, "Failed to get buffer "
1568 "handle from image %#x (derived from surface %#x): "
1569 "%d (%s).\n", mapping->image.buf, surface_id,
1570 vas, vaErrorStr(vas));
1571 err = AVERROR(EIO);
1572 goto fail_derived;
1573 }
1574
1575 av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %"PRIdPTR".\n",
1576 mapping->buffer_info.handle);
1577
1578 mapping->drm_desc.nb_objects = 1;
1579 mapping->drm_desc.objects[0] = (AVDRMObjectDescriptor) {
1580 .fd = mapping->buffer_info.handle,
1581 .size = mapping->image.data_size,
1582 // There is no way to get the format modifier with this API.
1583 .format_modifier = DRM_FORMAT_MOD_INVALID,
1584 };
1585
1586 err = ff_hwframe_map_create(src->hw_frames_ctx,
1587 dst, src, &vaapi_unmap_to_drm_abh,
1588 mapping);
1589 if (err < 0)
1590 goto fail_mapped;
1591
1592 dst->data[0] = (uint8_t*)&mapping->drm_desc;
1593 dst->width = src->width;
1594 dst->height = src->height;
1595
1596 return 0;
1597
1598 fail_mapped:
1599 vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
1600 fail_derived:
1601 vaDestroyImage(hwctx->display, mapping->image.image_id);
1602 fail:
1603 av_freep(&mapping);
1604 return err;
1605 }
1606 #endif
1607
1608 static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
1609 const AVFrame *src, int flags)
1610 {
1611 #if VA_CHECK_VERSION(1, 1, 0)
1612 int err;
1613 err = vaapi_map_to_drm_esh(hwfc, dst, src, flags);
1614 if (err != AVERROR(ENOSYS))
1615 return err;
1616 #endif
1617 #if VA_CHECK_VERSION(0, 36, 0)
1618 return vaapi_map_to_drm_abh(hwfc, dst, src, flags);
1619 #endif
1620 return AVERROR(ENOSYS);
1621 }
1622
1623 #endif /* CONFIG_LIBDRM */
1624
1625 static int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
1626 const AVFrame *src, int flags)
1627 {
1628 switch (src->format) {
1629 #if CONFIG_LIBDRM
1630 case AV_PIX_FMT_DRM_PRIME:
1631 return vaapi_map_from_drm(hwfc, dst, src, flags);
1632 #endif
1633 default:
1634 return AVERROR(ENOSYS);
1635 }
1636 }
1637
1638 static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
1639 const AVFrame *src, int flags)
1640 {
1641 switch (dst->format) {
1642 #if CONFIG_LIBDRM
1643 case AV_PIX_FMT_DRM_PRIME:
1644 return vaapi_map_to_drm(hwfc, dst, src, flags);
1645 #endif
1646 default:
1647 return vaapi_map_to_memory(hwfc, dst, src, flags);
1648 }
1649 }
1650
1651 static void vaapi_device_free(AVHWDeviceContext *ctx)
1652 {
1653 AVVAAPIDeviceContext *hwctx = ctx->hwctx;
1654 VAAPIDevicePriv *priv = ctx->user_opaque;
1655
1656 if (hwctx->display)
1657 vaTerminate(hwctx->display);
1658
1659 #if HAVE_VAAPI_X11
1660 if (priv->x11_display)
1661 XCloseDisplay(priv->x11_display);
1662 #endif
1663
1664 #if HAVE_VAAPI_DRM
1665 if (priv->drm_fd >= 0)
1666 close(priv->drm_fd);
1667 #endif
1668
1669 av_freep(&priv);
1670 }
1671
1672 #if CONFIG_VAAPI_1
1673 static void vaapi_device_log_error(void *context, const char *message)
1674 {
1675 AVHWDeviceContext *ctx = context;
1676
1677 av_log(ctx, AV_LOG_ERROR, "libva: %s", message);
1678 }
1679
1680 static void vaapi_device_log_info(void *context, const char *message)
1681 {
1682 AVHWDeviceContext *ctx = context;
1683
1684 av_log(ctx, AV_LOG_VERBOSE, "libva: %s", message);
1685 }
1686 #endif
1687
1688 static int vaapi_device_connect(AVHWDeviceContext *ctx,
1689 VADisplay display)
1690 {
1691 AVVAAPIDeviceContext *hwctx = ctx->hwctx;
1692 int major, minor;
1693 VAStatus vas;
1694
1695 #if CONFIG_VAAPI_1
1696 vaSetErrorCallback(display, &vaapi_device_log_error, ctx);
1697 vaSetInfoCallback (display, &vaapi_device_log_info, ctx);
1698 #endif
1699
1700 hwctx->display = display;
1701
1702 vas = vaInitialize(display, &major, &minor);
1703 if (vas != VA_STATUS_SUCCESS) {
1704 av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
1705 "connection: %d (%s).\n", vas, vaErrorStr(vas));
1706 return AVERROR(EIO);
1707 }
1708 av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
1709 "version %d.%d\n", major, minor);
1710
1711 return 0;
1712 }
1713
1714 static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
1715 AVDictionary *opts, int flags)
1716 {
1717 VAAPIDevicePriv *priv;
1718 VADisplay display = NULL;
1719 const AVDictionaryEntry *ent;
1720 int try_drm, try_x11, try_win32, try_all av_unused;
1721
1722 priv = av_mallocz(sizeof(*priv));
1723 if (!priv)
1724 return AVERROR(ENOMEM);
1725
1726 priv->drm_fd = -1;
1727
1728 ctx->user_opaque = priv;
1729 ctx->free = vaapi_device_free;
1730
1731 ent = av_dict_get(opts, "connection_type", NULL, 0);
1732 if (ent) {
1733 try_all = try_drm = try_x11 = try_win32 = 0;
1734 if (!strcmp(ent->value, "drm")) {
1735 try_drm = 1;
1736 } else if (!strcmp(ent->value, "x11")) {
1737 try_x11 = 1;
1738 } else if (!strcmp(ent->value, "win32")) {
1739 try_win32 = 1;
1740 } else {
1741 av_log(ctx, AV_LOG_ERROR, "Invalid connection type %s.\n",
1742 ent->value);
1743 return AVERROR(EINVAL);
1744 }
1745 } else {
1746 try_all = 1;
1747 try_drm = HAVE_VAAPI_DRM;
1748 try_x11 = HAVE_VAAPI_X11;
1749 try_win32 = HAVE_VAAPI_WIN32;
1750 }
1751
1752 #if HAVE_VAAPI_DRM
1753 while (!display && try_drm) {
1754 // If the device is specified, try to open it as a DRM device node.
1755 // If not, look for a usable render node, possibly restricted to those
1756 // using a specified kernel driver.
1757 int loglevel = try_all ? AV_LOG_VERBOSE : AV_LOG_ERROR;
1758 if (device) {
1759 priv->drm_fd = open(device, O_RDWR);
1760 if (priv->drm_fd < 0) {
1761 av_log(ctx, loglevel, "Failed to open %s as "
1762 "DRM device node.\n", device);
1763 break;
1764 }
1765 } else {
1766 char path[64];
1767 int n, max_devices = 8;
1768 #if CONFIG_LIBDRM
1769 drmVersion *info;
1770 const AVDictionaryEntry *kernel_driver;
1771 const AVDictionaryEntry *vendor_id;
1772 kernel_driver = av_dict_get(opts, "kernel_driver", NULL, 0);
1773 vendor_id = av_dict_get(opts, "vendor_id", NULL, 0);
1774 #endif
1775 for (n = 0; n < max_devices; n++) {
1776 snprintf(path, sizeof(path),
1777 "/dev/dri/renderD%d", 128 + n);
1778 priv->drm_fd = open(path, O_RDWR);
1779 if (priv->drm_fd < 0) {
1780 if (errno == ENOENT) {
1781 if (n != max_devices - 1) {
1782 av_log(ctx, AV_LOG_VERBOSE,
1783 "No render device %s, try next device for "
1784 "DRM render node.\n", path);
1785 continue;
1786 }
1787
1788 av_log(ctx, AV_LOG_VERBOSE, "No available render device "
1789 "for DRM render node.\n");
1790 } else
1791 av_log(ctx, AV_LOG_VERBOSE, "Cannot open "
1792 "DRM render node for device %d.\n", n);
1793 break;
1794 }
1795 #if CONFIG_LIBDRM
1796 info = drmGetVersion(priv->drm_fd);
1797 if (!info) {
1798 av_log(ctx, AV_LOG_VERBOSE,
1799 "Failed to get DRM version for device %d.\n", n);
1800 close(priv->drm_fd);
1801 priv->drm_fd = -1;
1802 continue;
1803 }
1804 if (kernel_driver) {
1805 if (strcmp(kernel_driver->value, info->name)) {
1806 av_log(ctx, AV_LOG_VERBOSE, "Ignoring device %d "
1807 "with non-matching kernel driver (%s).\n",
1808 n, info->name);
1809 drmFreeVersion(info);
1810 close(priv->drm_fd);
1811 priv->drm_fd = -1;
1812 continue;
1813 }
1814 av_log(ctx, AV_LOG_VERBOSE, "Trying to use "
1815 "DRM render node for device %d, "
1816 "with matching kernel driver (%s).\n",
1817 n, info->name);
1818 drmFreeVersion(info);
1819 break;
1820 // drmGetVersion() ensures |info->name| is 0-terminated.
1821 } else if (!strcmp(info->name, "vgem")) {
1822 av_log(ctx, AV_LOG_VERBOSE,
1823 "Skipping vgem node for device %d.\n", n);
1824 drmFreeVersion(info);
1825 close(priv->drm_fd);
1826 priv->drm_fd = -1;
1827 continue;
1828 } else if (vendor_id) {
1829 drmDevicePtr device;
1830 char drm_vendor[8];
1831 if (drmGetDevice(priv->drm_fd, &device)) {
1832 av_log(ctx, AV_LOG_VERBOSE,
1833 "Failed to get DRM device info for device %d.\n", n);
1834 close(priv->drm_fd);
1835 priv->drm_fd = -1;
1836 drmFreeVersion(info);
1837 continue;
1838 }
1839
1840 snprintf(drm_vendor, sizeof(drm_vendor), "0x%x", device->deviceinfo.pci->vendor_id);
1841 if (strcmp(vendor_id->value, drm_vendor)) {
1842 av_log(ctx, AV_LOG_VERBOSE, "Ignoring device %d "
1843 "with non-matching vendor id (%s).\n",
1844 n, vendor_id->value);
1845 drmFreeDevice(&device);
1846 close(priv->drm_fd);
1847 priv->drm_fd = -1;
1848 drmFreeVersion(info);
1849 continue;
1850 }
1851 av_log(ctx, AV_LOG_VERBOSE, "Trying to use "
1852 "DRM render node for device %d, "
1853 "with matching vendor id (%s).\n",
1854 n, vendor_id->value);
1855 drmFreeDevice(&device);
1856 drmFreeVersion(info);
1857 break;
1858 }
1859 drmFreeVersion(info);
1860 #endif
1861 av_log(ctx, AV_LOG_VERBOSE, "Trying to use "
1862 "DRM render node for device %d.\n", n);
1863 break;
1864 }
1865 if (n >= max_devices)
1866 break;
1867 }
1868
1869 display = vaGetDisplayDRM(priv->drm_fd);
1870 if (!display) {
1871 av_log(ctx, AV_LOG_VERBOSE, "Cannot open a VA display "
1872 "from DRM device %s.\n", device);
1873 return AVERROR_EXTERNAL;
1874 }
1875 break;
1876 }
1877 #endif
1878
1879 #if HAVE_VAAPI_X11
1880 if (!display && try_x11) {
1881 // Try to open the device as an X11 display.
1882 priv->x11_display = XOpenDisplay(device);
1883 if (!priv->x11_display) {
1884 av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
1885 "%s.\n", XDisplayName(device));
1886 } else {
1887 display = vaGetDisplay(priv->x11_display);
1888 if (!display) {
1889 av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
1890 "from X11 display %s.\n", XDisplayName(device));
1891 return AVERROR_UNKNOWN;
1892 }
1893
1894 av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
1895 "X11 display %s.\n", XDisplayName(device));
1896 }
1897 }
1898 #endif
1899
1900 #if HAVE_VAAPI_WIN32
1901 if (!display && try_win32) {
1902 // Try to create a display from the specified device, if any.
1903 if (!device) {
1904 display = vaGetDisplayWin32(NULL);
1905 } else {
1906 IDXGIFactory2 *pDXGIFactory = NULL;
1907 IDXGIAdapter *pAdapter = NULL;
1908 #if !HAVE_UWP
1909 HANDLE dxgi = dlopen("dxgi.dll", 0);
1910 if (!dxgi) {
1911 av_log(ctx, AV_LOG_ERROR, "Failed to load dxgi.dll\n");
1912 return AVERROR_UNKNOWN;
1913 }
1914 PFN_CREATE_DXGI_FACTORY pfnCreateDXGIFactory =
1915 (PFN_CREATE_DXGI_FACTORY)dlsym(dxgi, "CreateDXGIFactory");
1916 if (!pfnCreateDXGIFactory) {
1917 av_log(ctx, AV_LOG_ERROR, "CreateDXGIFactory load failed\n");
1918 dlclose(dxgi);
1919 return AVERROR_UNKNOWN;
1920 }
1921 #else
1922 // In UWP (which lacks LoadLibrary), CreateDXGIFactory isn't
1923 // available, only CreateDXGIFactory1
1924 PFN_CREATE_DXGI_FACTORY pfnCreateDXGIFactory =
1925 (PFN_CREATE_DXGI_FACTORY)CreateDXGIFactory1;
1926 #endif
1927 if (SUCCEEDED(pfnCreateDXGIFactory(&IID_IDXGIFactory2,
1928 (void **)&pDXGIFactory))) {
1929 int adapter = atoi(device);
1930 if (SUCCEEDED(IDXGIFactory2_EnumAdapters(pDXGIFactory,
1931 adapter,
1932 &pAdapter))) {
1933 DXGI_ADAPTER_DESC desc;
1934 if (SUCCEEDED(IDXGIAdapter2_GetDesc(pAdapter, &desc))) {
1935 av_log(ctx, AV_LOG_INFO,
1936 "Using device %04x:%04x (%ls) - LUID %lu %ld.\n",
1937 desc.VendorId, desc.DeviceId, desc.Description,
1938 desc.AdapterLuid.LowPart,
1939 desc.AdapterLuid.HighPart);
1940 display = vaGetDisplayWin32(&desc.AdapterLuid);
1941 }
1942 IDXGIAdapter_Release(pAdapter);
1943 }
1944 IDXGIFactory2_Release(pDXGIFactory);
1945 }
1946 #if !HAVE_UWP
1947 dlclose(dxgi);
1948 #endif
1949 }
1950
1951 if (!display) {
1952 av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
1953 "from Win32 display.\n");
1954 return AVERROR_UNKNOWN;
1955 }
1956
1957 av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
1958 "Win32 display.\n");
1959 }
1960 #endif
1961
1962 if (!display) {
1963 if (device)
1964 av_log(ctx, AV_LOG_ERROR, "No VA display found for "
1965 "device %s.\n", device);
1966 else
1967 av_log(ctx, AV_LOG_ERROR, "No VA display found for "
1968 "any default device.\n");
1969 return AVERROR(EINVAL);
1970 }
1971
1972 ent = av_dict_get(opts, "driver", NULL, 0);
1973 if (ent) {
1974 #if VA_CHECK_VERSION(0, 38, 0)
1975 VAStatus vas;
1976 vas = vaSetDriverName(display, ent->value);
1977 if (vas != VA_STATUS_SUCCESS) {
1978 av_log(ctx, AV_LOG_ERROR, "Failed to set driver name to "
1979 "%s: %d (%s).\n", ent->value, vas, vaErrorStr(vas));
1980 vaTerminate(display);
1981 return AVERROR_EXTERNAL;
1982 }
1983 #else
1984 av_log(ctx, AV_LOG_WARNING, "Driver name setting is not "
1985 "supported with this VAAPI version.\n");
1986 #endif
1987 }
1988
1989 return vaapi_device_connect(ctx, display);
1990 }
1991
1992 static int vaapi_device_derive(AVHWDeviceContext *ctx,
1993 AVHWDeviceContext *src_ctx,
1994 AVDictionary *opts, int flags)
1995 {
1996 #if HAVE_VAAPI_DRM
1997 if (src_ctx->type == AV_HWDEVICE_TYPE_DRM) {
1998 AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
1999 VADisplay *display;
2000 VAAPIDevicePriv *priv;
2001 int fd;
2002
2003 if (src_hwctx->fd < 0) {
2004 av_log(ctx, AV_LOG_ERROR, "DRM instance requires an associated "
2005 "device to derive a VA display from.\n");
2006 return AVERROR(EINVAL);
2007 }
2008
2009 #if CONFIG_LIBDRM
2010 {
2011 int node_type = drmGetNodeTypeFromFd(src_hwctx->fd);
2012 char *render_node;
2013 if (node_type < 0) {
2014 av_log(ctx, AV_LOG_ERROR, "DRM instance fd does not appear "
2015 "to refer to a DRM device.\n");
2016 return AVERROR(EINVAL);
2017 }
2018 if (node_type == DRM_NODE_RENDER) {
2019 fd = src_hwctx->fd;
2020 } else {
2021 render_node = drmGetRenderDeviceNameFromFd(src_hwctx->fd);
2022 if (!render_node) {
2023 av_log(ctx, AV_LOG_VERBOSE, "Using non-render node "
2024 "because the device does not have an "
2025 "associated render node.\n");
2026 fd = src_hwctx->fd;
2027 } else {
2028 fd = open(render_node, O_RDWR);
2029 if (fd < 0) {
2030 av_log(ctx, AV_LOG_VERBOSE, "Using non-render node "
2031 "because the associated render node "
2032 "could not be opened.\n");
2033 fd = src_hwctx->fd;
2034 } else {
2035 av_log(ctx, AV_LOG_VERBOSE, "Using render node %s "
2036 "in place of non-render DRM device.\n",
2037 render_node);
2038 }
2039 free(render_node);
2040 }
2041 }
2042 }
2043 #else
2044 fd = src_hwctx->fd;
2045 #endif
2046
2047 priv = av_mallocz(sizeof(*priv));
2048 if (!priv) {
2049 if (fd != src_hwctx->fd) {
2050 // The fd was opened in this function.
2051 close(fd);
2052 }
2053 return AVERROR(ENOMEM);
2054 }
2055
2056 if (fd == src_hwctx->fd) {
2057 // The fd is inherited from the source context and we are holding
2058 // a reference to that, we don't want to close it from here.
2059 priv->drm_fd = -1;
2060 } else {
2061 priv->drm_fd = fd;
2062 }
2063
2064 ctx->user_opaque = priv;
2065 ctx->free = &vaapi_device_free;
2066
2067 display = vaGetDisplayDRM(fd);
2068 if (!display) {
2069 av_log(ctx, AV_LOG_ERROR, "Failed to open a VA display from "
2070 "DRM device.\n");
2071 return AVERROR(EIO);
2072 }
2073
2074 return vaapi_device_connect(ctx, display);
2075 }
2076 #endif
2077 return AVERROR(ENOSYS);
2078 }
2079
2080 const HWContextType ff_hwcontext_type_vaapi = {
2081 .type = AV_HWDEVICE_TYPE_VAAPI,
2082 .name = "VAAPI",
2083
2084 .device_hwctx_size = sizeof(VAAPIDeviceContext),
2085 .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
2086 .frames_hwctx_size = sizeof(VAAPIFramesContext),
2087
2088 .device_create = &vaapi_device_create,
2089 .device_derive = &vaapi_device_derive,
2090 .device_init = &vaapi_device_init,
2091 .device_uninit = &vaapi_device_uninit,
2092 .frames_get_constraints = &vaapi_frames_get_constraints,
2093 .frames_init = &vaapi_frames_init,
2094 .frames_uninit = &vaapi_frames_uninit,
2095 .frames_get_buffer = &vaapi_get_buffer,
2096 .transfer_get_formats = &vaapi_transfer_get_formats,
2097 .transfer_data_to = &vaapi_transfer_data_to,
2098 .transfer_data_from = &vaapi_transfer_data_from,
2099 .map_to = &vaapi_map_to,
2100 .map_from = &vaapi_map_from,
2101
2102 .pix_fmts = (const enum AVPixelFormat[]) {
2103 AV_PIX_FMT_VAAPI,
2104 AV_PIX_FMT_NONE
2105 },
2106 };
2107