FFmpeg coverage


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