FFmpeg coverage


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