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