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