2 * This file is part of FFmpeg.
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.
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.
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
22 # include <va/va_x11.h>
25 # include <va/va_drm.h>
29 # include <va/va_drmcommon.h>
30 # include <drm_fourcc.h>
31 # ifndef DRM_FORMAT_MOD_INVALID
32 # define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
45 #include "hwcontext.h"
46 #include "hwcontext_drm.h"
47 #include "hwcontext_internal.h"
48 #include "hwcontext_vaapi.h"
54 typedef struct VAAPIDevicePriv {
62 typedef struct VAAPISurfaceFormat {
63 enum AVPixelFormat pix_fmt;
64 VAImageFormat image_format;
67 typedef struct VAAPIDeviceContext {
68 // Surface formats which can be used with this device.
69 VAAPISurfaceFormat *formats;
73 typedef struct VAAPIFramesContext {
74 // Surface attributes set at create time.
75 VASurfaceAttrib *attributes;
77 // RT format of the underlying surface (Intel driver ignores this anyway).
78 unsigned int rt_format;
79 // Whether vaDeriveImage works.
83 typedef struct VAAPIMapping {
84 // Handle to the derived or copied image which is mapped.
86 // The mapping flags actually used.
90 #define MAP(va, rt, av) { \
92 VA_RT_FORMAT_ ## rt, \
95 // The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V
96 // plane swap cases. The frame handling below tries to hide these.
99 unsigned int rt_format;
100 enum AVPixelFormat pix_fmt;
101 } vaapi_format_map[] = {
102 MAP(NV12, YUV420, NV12),
103 MAP(YV12, YUV420, YUV420P), // With U/V planes swapped.
104 MAP(IYUV, YUV420, YUV420P),
105 #ifdef VA_FOURCC_I420
106 MAP(I420, YUV420, YUV420P),
108 #ifdef VA_FOURCC_YV16
109 MAP(YV16, YUV422, YUV422P), // With U/V planes swapped.
111 MAP(422H, YUV422, YUV422P),
112 MAP(UYVY, YUV422, UYVY422),
113 MAP(YUY2, YUV422, YUYV422),
114 MAP(411P, YUV411, YUV411P),
115 MAP(422V, YUV422, YUV440P),
116 MAP(444P, YUV444, YUV444P),
117 MAP(Y800, YUV400, GRAY8),
118 #ifdef VA_FOURCC_P010
119 MAP(P010, YUV420_10BPP, P010),
121 MAP(BGRA, RGB32, BGRA),
122 MAP(BGRX, RGB32, BGR0),
123 MAP(RGBA, RGB32, RGBA),
124 MAP(RGBX, RGB32, RGB0),
125 #ifdef VA_FOURCC_ABGR
126 MAP(ABGR, RGB32, ABGR),
127 MAP(XBGR, RGB32, 0BGR),
129 MAP(ARGB, RGB32, ARGB),
130 MAP(XRGB, RGB32, 0RGB),
134 static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc)
137 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
138 if (vaapi_format_map[i].fourcc == fourcc)
139 return vaapi_format_map[i].pix_fmt;
140 return AV_PIX_FMT_NONE;
143 static int vaapi_get_image_format(AVHWDeviceContext *hwdev,
144 enum AVPixelFormat pix_fmt,
145 VAImageFormat **image_format)
147 VAAPIDeviceContext *ctx = hwdev->internal->priv;
150 for (i = 0; i < ctx->nb_formats; i++) {
151 if (ctx->formats[i].pix_fmt == pix_fmt) {
153 *image_format = &ctx->formats[i].image_format;
157 return AVERROR(EINVAL);
160 static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev,
161 const void *hwconfig,
162 AVHWFramesConstraints *constraints)
164 AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
165 const AVVAAPIHWConfig *config = hwconfig;
166 VAAPIDeviceContext *ctx = hwdev->internal->priv;
167 VASurfaceAttrib *attr_list = NULL;
169 enum AVPixelFormat pix_fmt;
171 int err, i, j, attr_count, pix_fmt_count;
174 !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {
176 vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
178 if (vas != VA_STATUS_SUCCESS) {
179 av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
180 "%d (%s).\n", vas, vaErrorStr(vas));
181 err = AVERROR(ENOSYS);
185 attr_list = av_malloc(attr_count * sizeof(*attr_list));
187 err = AVERROR(ENOMEM);
191 vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
192 attr_list, &attr_count);
193 if (vas != VA_STATUS_SUCCESS) {
194 av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
195 "%d (%s).\n", vas, vaErrorStr(vas));
196 err = AVERROR(ENOSYS);
201 for (i = 0; i < attr_count; i++) {
202 switch (attr_list[i].type) {
203 case VASurfaceAttribPixelFormat:
204 fourcc = attr_list[i].value.value.i;
205 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
206 if (pix_fmt != AV_PIX_FMT_NONE) {
209 // Something unsupported - ignore.
212 case VASurfaceAttribMinWidth:
213 constraints->min_width = attr_list[i].value.value.i;
215 case VASurfaceAttribMinHeight:
216 constraints->min_height = attr_list[i].value.value.i;
218 case VASurfaceAttribMaxWidth:
219 constraints->max_width = attr_list[i].value.value.i;
221 case VASurfaceAttribMaxHeight:
222 constraints->max_height = attr_list[i].value.value.i;
226 if (pix_fmt_count == 0) {
227 // Nothing usable found. Presumably there exists something which
228 // works, so leave the set null to indicate unknown.
229 constraints->valid_sw_formats = NULL;
231 constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
233 if (!constraints->valid_sw_formats) {
234 err = AVERROR(ENOMEM);
238 for (i = j = 0; i < attr_count; i++) {
239 if (attr_list[i].type != VASurfaceAttribPixelFormat)
241 fourcc = attr_list[i].value.value.i;
242 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
243 if (pix_fmt != AV_PIX_FMT_NONE)
244 constraints->valid_sw_formats[j++] = pix_fmt;
246 av_assert0(j == pix_fmt_count);
247 constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
250 // No configuration supplied.
251 // Return the full set of image formats known by the implementation.
252 constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1,
254 if (!constraints->valid_sw_formats) {
255 err = AVERROR(ENOMEM);
258 for (i = 0; i < ctx->nb_formats; i++)
259 constraints->valid_sw_formats[i] = ctx->formats[i].pix_fmt;
260 constraints->valid_sw_formats[i] = AV_PIX_FMT_NONE;
263 constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
264 if (!constraints->valid_hw_formats) {
265 err = AVERROR(ENOMEM);
268 constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
269 constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
273 av_freep(&attr_list);
277 static const struct {
278 const char *friendly_name;
279 const char *match_string;
281 } vaapi_driver_quirks_table[] = {
282 #if !VA_CHECK_VERSION(1, 0, 0)
283 // The i965 driver did not conform before version 2.0.
285 "Intel i965 (Quick Sync)",
287 AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS,
293 AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE,
297 "Splitted-Desktop Systems VDPAU backend for VA-API",
298 AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES,
302 static int vaapi_device_init(AVHWDeviceContext *hwdev)
304 VAAPIDeviceContext *ctx = hwdev->internal->priv;
305 AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
306 VAImageFormat *image_list = NULL;
308 const char *vendor_string;
309 int err, i, image_count;
310 enum AVPixelFormat pix_fmt;
313 image_count = vaMaxNumImageFormats(hwctx->display);
314 if (image_count <= 0) {
318 image_list = av_malloc(image_count * sizeof(*image_list));
320 err = AVERROR(ENOMEM);
323 vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
324 if (vas != VA_STATUS_SUCCESS) {
329 ctx->formats = av_malloc(image_count * sizeof(*ctx->formats));
331 err = AVERROR(ENOMEM);
335 for (i = 0; i < image_count; i++) {
336 fourcc = image_list[i].fourcc;
337 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
338 if (pix_fmt == AV_PIX_FMT_NONE) {
339 av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n",
342 av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",
343 fourcc, av_get_pix_fmt_name(pix_fmt));
344 ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt;
345 ctx->formats[ctx->nb_formats].image_format = image_list[i];
350 vendor_string = vaQueryVendorString(hwctx->display);
352 av_log(hwdev, AV_LOG_VERBOSE, "VAAPI driver: %s.\n", vendor_string);
354 if (hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_USER_SET) {
355 av_log(hwdev, AV_LOG_VERBOSE, "Using quirks set by user (%#x).\n",
356 hwctx->driver_quirks);
358 // Detect the driver in use and set quirk flags if necessary.
359 hwctx->driver_quirks = 0;
361 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) {
362 if (strstr(vendor_string,
363 vaapi_driver_quirks_table[i].match_string)) {
364 av_log(hwdev, AV_LOG_VERBOSE, "Matched driver string "
365 "as known nonstandard driver \"%s\", setting "
367 vaapi_driver_quirks_table[i].friendly_name,
368 vaapi_driver_quirks_table[i].quirks);
369 hwctx->driver_quirks |=
370 vaapi_driver_quirks_table[i].quirks;
374 if (!(i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table))) {
375 av_log(hwdev, AV_LOG_VERBOSE, "Driver not found in known "
376 "nonstandard list, using standard behaviour.\n");
379 av_log(hwdev, AV_LOG_VERBOSE, "Driver has no vendor string, "
380 "assuming standard behaviour.\n");
387 av_freep(&ctx->formats);
392 static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
394 VAAPIDeviceContext *ctx = hwdev->internal->priv;
396 av_freep(&ctx->formats);
399 static void vaapi_buffer_free(void *opaque, uint8_t *data)
401 AVHWFramesContext *hwfc = opaque;
402 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
403 VASurfaceID surface_id;
406 surface_id = (VASurfaceID)(uintptr_t)data;
408 vas = vaDestroySurfaces(hwctx->display, &surface_id, 1);
409 if (vas != VA_STATUS_SUCCESS) {
410 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: "
411 "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
415 static AVBufferRef *vaapi_pool_alloc(void *opaque, int size)
417 AVHWFramesContext *hwfc = opaque;
418 VAAPIFramesContext *ctx = hwfc->internal->priv;
419 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
420 AVVAAPIFramesContext *avfc = hwfc->hwctx;
421 VASurfaceID surface_id;
425 if (hwfc->initial_pool_size > 0 &&
426 avfc->nb_surfaces >= hwfc->initial_pool_size)
429 vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
430 hwfc->width, hwfc->height,
432 ctx->attributes, ctx->nb_attributes);
433 if (vas != VA_STATUS_SUCCESS) {
434 av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
435 "%d (%s).\n", vas, vaErrorStr(vas));
438 av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
440 ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
441 sizeof(surface_id), &vaapi_buffer_free,
442 hwfc, AV_BUFFER_FLAG_READONLY);
444 vaDestroySurfaces(hwctx->display, &surface_id, 1);
448 if (hwfc->initial_pool_size > 0) {
449 // This is a fixed-size pool, so we must still be in the initial
450 // allocation sequence.
451 av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size);
452 avfc->surface_ids[avfc->nb_surfaces] = surface_id;
459 static int vaapi_frames_init(AVHWFramesContext *hwfc)
461 AVVAAPIFramesContext *avfc = hwfc->hwctx;
462 VAAPIFramesContext *ctx = hwfc->internal->priv;
463 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
464 VAImageFormat *expected_format;
465 AVBufferRef *test_surface = NULL;
466 VASurfaceID test_surface_id;
470 unsigned int fourcc, rt_format;
472 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
473 if (vaapi_format_map[i].pix_fmt == hwfc->sw_format) {
474 fourcc = vaapi_format_map[i].fourcc;
475 rt_format = vaapi_format_map[i].rt_format;
479 if (i >= FF_ARRAY_ELEMS(vaapi_format_map)) {
480 av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
481 av_get_pix_fmt_name(hwfc->sw_format));
482 return AVERROR(EINVAL);
486 if (!(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {
487 int need_memory_type = !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE);
488 int need_pixel_format = 1;
489 for (i = 0; i < avfc->nb_attributes; i++) {
490 if (avfc->attributes[i].type == VASurfaceAttribMemoryType)
491 need_memory_type = 0;
492 if (avfc->attributes[i].type == VASurfaceAttribPixelFormat)
493 need_pixel_format = 0;
496 avfc->nb_attributes + need_memory_type + need_pixel_format;
498 ctx->attributes = av_malloc(ctx->nb_attributes *
499 sizeof(*ctx->attributes));
500 if (!ctx->attributes) {
501 err = AVERROR(ENOMEM);
505 for (i = 0; i < avfc->nb_attributes; i++)
506 ctx->attributes[i] = avfc->attributes[i];
507 if (need_memory_type) {
508 ctx->attributes[i++] = (VASurfaceAttrib) {
509 .type = VASurfaceAttribMemoryType,
510 .flags = VA_SURFACE_ATTRIB_SETTABLE,
511 .value.type = VAGenericValueTypeInteger,
512 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
515 if (need_pixel_format) {
516 ctx->attributes[i++] = (VASurfaceAttrib) {
517 .type = VASurfaceAttribPixelFormat,
518 .flags = VA_SURFACE_ATTRIB_SETTABLE,
519 .value.type = VAGenericValueTypeInteger,
520 .value.value.i = fourcc,
523 av_assert0(i == ctx->nb_attributes);
525 ctx->attributes = NULL;
526 ctx->nb_attributes = 0;
529 ctx->rt_format = rt_format;
531 if (hwfc->initial_pool_size > 0) {
532 // This pool will be usable as a render target, so we need to store
533 // all of the surface IDs somewhere that vaCreateContext() calls
534 // will be able to access them.
535 avfc->nb_surfaces = 0;
536 avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
537 sizeof(*avfc->surface_ids));
538 if (!avfc->surface_ids) {
539 err = AVERROR(ENOMEM);
543 // This pool allows dynamic sizing, and will not be usable as a
545 avfc->nb_surfaces = 0;
546 avfc->surface_ids = NULL;
549 hwfc->internal->pool_internal =
550 av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
551 &vaapi_pool_alloc, NULL);
552 if (!hwfc->internal->pool_internal) {
553 av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
554 err = AVERROR(ENOMEM);
559 // Allocate a single surface to test whether vaDeriveImage() is going
560 // to work for the specific configuration.
562 test_surface = av_buffer_pool_get(hwfc->pool);
564 av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
565 "user-configured buffer pool.\n");
566 err = AVERROR(ENOMEM);
570 test_surface = av_buffer_pool_get(hwfc->internal->pool_internal);
572 av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
573 "internal buffer pool.\n");
574 err = AVERROR(ENOMEM);
578 test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
580 ctx->derive_works = 0;
582 err = vaapi_get_image_format(hwfc->device_ctx,
583 hwfc->sw_format, &expected_format);
585 vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
586 if (vas == VA_STATUS_SUCCESS) {
587 if (expected_format->fourcc == test_image.format.fourcc) {
588 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
589 ctx->derive_works = 1;
591 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
592 "derived image format %08x does not match "
593 "expected format %08x.\n",
594 expected_format->fourcc, test_image.format.fourcc);
596 vaDestroyImage(hwctx->display, test_image.image_id);
598 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
599 "deriving image does not work: "
600 "%d (%s).\n", vas, vaErrorStr(vas));
603 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
604 "image format is not supported.\n");
607 av_buffer_unref(&test_surface);
611 av_buffer_unref(&test_surface);
612 av_freep(&avfc->surface_ids);
613 av_freep(&ctx->attributes);
617 static void vaapi_frames_uninit(AVHWFramesContext *hwfc)
619 AVVAAPIFramesContext *avfc = hwfc->hwctx;
620 VAAPIFramesContext *ctx = hwfc->internal->priv;
622 av_freep(&avfc->surface_ids);
623 av_freep(&ctx->attributes);
626 static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
628 frame->buf[0] = av_buffer_pool_get(hwfc->pool);
630 return AVERROR(ENOMEM);
632 frame->data[3] = frame->buf[0]->data;
633 frame->format = AV_PIX_FMT_VAAPI;
634 frame->width = hwfc->width;
635 frame->height = hwfc->height;
640 static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc,
641 enum AVHWFrameTransferDirection dir,
642 enum AVPixelFormat **formats)
644 VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv;
645 enum AVPixelFormat *pix_fmts;
646 int i, k, sw_format_available;
648 sw_format_available = 0;
649 for (i = 0; i < ctx->nb_formats; i++) {
650 if (ctx->formats[i].pix_fmt == hwfc->sw_format)
651 sw_format_available = 1;
654 pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
656 return AVERROR(ENOMEM);
658 if (sw_format_available) {
659 pix_fmts[0] = hwfc->sw_format;
664 for (i = 0; i < ctx->nb_formats; i++) {
665 if (ctx->formats[i].pix_fmt == hwfc->sw_format)
667 av_assert0(k < ctx->nb_formats);
668 pix_fmts[k++] = ctx->formats[i].pix_fmt;
670 pix_fmts[k] = AV_PIX_FMT_NONE;
676 static void vaapi_unmap_frame(AVHWFramesContext *hwfc,
677 HWMapDescriptor *hwmap)
679 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
680 VAAPIMapping *map = hwmap->priv;
681 VASurfaceID surface_id;
684 surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
685 av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
687 vas = vaUnmapBuffer(hwctx->display, map->image.buf);
688 if (vas != VA_STATUS_SUCCESS) {
689 av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
690 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
693 if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
694 !(map->flags & AV_HWFRAME_MAP_DIRECT)) {
695 vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
696 0, 0, hwfc->width, hwfc->height,
697 0, 0, hwfc->width, hwfc->height);
698 if (vas != VA_STATUS_SUCCESS) {
699 av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
700 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
704 vas = vaDestroyImage(hwctx->display, map->image.image_id);
705 if (vas != VA_STATUS_SUCCESS) {
706 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
707 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
713 static int vaapi_map_frame(AVHWFramesContext *hwfc,
714 AVFrame *dst, const AVFrame *src, int flags)
716 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
717 VAAPIFramesContext *ctx = hwfc->internal->priv;
718 VASurfaceID surface_id;
719 VAImageFormat *image_format;
722 void *address = NULL;
725 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
726 av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
728 if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) {
729 // Requested direct mapping but it is not possible.
730 return AVERROR(EINVAL);
732 if (dst->format == AV_PIX_FMT_NONE)
733 dst->format = hwfc->sw_format;
734 if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) {
735 // Requested direct mapping but the formats do not match.
736 return AVERROR(EINVAL);
739 err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
741 // Requested format is not a valid output format.
742 return AVERROR(EINVAL);
745 map = av_malloc(sizeof(*map));
747 return AVERROR(ENOMEM);
749 map->image.image_id = VA_INVALID_ID;
751 vas = vaSyncSurface(hwctx->display, surface_id);
752 if (vas != VA_STATUS_SUCCESS) {
753 av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
754 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
759 // The memory which we map using derive need not be connected to the CPU
760 // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
761 // memory is mappable but not cached, so normal memcpy()-like access is
762 // very slow to read it (but writing is ok). It is possible to read much
763 // faster with a copy routine which is aware of the limitation, but we
764 // assume for now that the user is not aware of that and would therefore
765 // prefer not to be given direct-mapped memory if they request read access.
766 if (ctx->derive_works && dst->format == hwfc->sw_format &&
767 ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) {
768 vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
769 if (vas != VA_STATUS_SUCCESS) {
770 av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
771 "surface %#x: %d (%s).\n",
772 surface_id, vas, vaErrorStr(vas));
776 if (map->image.format.fourcc != image_format->fourcc) {
777 av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
778 "is in wrong format: expected %#08x, got %#08x.\n",
779 surface_id, image_format->fourcc, map->image.format.fourcc);
783 map->flags |= AV_HWFRAME_MAP_DIRECT;
785 vas = vaCreateImage(hwctx->display, image_format,
786 hwfc->width, hwfc->height, &map->image);
787 if (vas != VA_STATUS_SUCCESS) {
788 av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
789 "surface %#x: %d (%s).\n",
790 surface_id, vas, vaErrorStr(vas));
794 if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) {
795 vas = vaGetImage(hwctx->display, surface_id, 0, 0,
796 hwfc->width, hwfc->height, map->image.image_id);
797 if (vas != VA_STATUS_SUCCESS) {
798 av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
799 "surface %#x: %d (%s).\n",
800 surface_id, vas, vaErrorStr(vas));
807 vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
808 if (vas != VA_STATUS_SUCCESS) {
809 av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
810 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
815 err = ff_hwframe_map_create(src->hw_frames_ctx,
816 dst, src, &vaapi_unmap_frame, map);
820 dst->width = src->width;
821 dst->height = src->height;
823 for (i = 0; i < map->image.num_planes; i++) {
824 dst->data[i] = (uint8_t*)address + map->image.offsets[i];
825 dst->linesize[i] = map->image.pitches[i];
828 #ifdef VA_FOURCC_YV16
829 map->image.format.fourcc == VA_FOURCC_YV16 ||
831 map->image.format.fourcc == VA_FOURCC_YV12) {
832 // Chroma planes are YVU rather than YUV, so swap them.
833 FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
841 vaUnmapBuffer(hwctx->display, map->image.buf);
842 if (map->image.image_id != VA_INVALID_ID)
843 vaDestroyImage(hwctx->display, map->image.image_id);
849 static int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
850 AVFrame *dst, const AVFrame *src)
855 if (dst->width > hwfc->width || dst->height > hwfc->height)
856 return AVERROR(EINVAL);
858 map = av_frame_alloc();
860 return AVERROR(ENOMEM);
861 map->format = dst->format;
863 err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
867 map->width = dst->width;
868 map->height = dst->height;
870 err = av_frame_copy(dst, map);
880 static int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
881 AVFrame *dst, const AVFrame *src)
886 if (src->width > hwfc->width || src->height > hwfc->height)
887 return AVERROR(EINVAL);
889 map = av_frame_alloc();
891 return AVERROR(ENOMEM);
892 map->format = src->format;
894 err = vaapi_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE);
898 map->width = src->width;
899 map->height = src->height;
901 err = av_frame_copy(map, src);
911 static int vaapi_map_to_memory(AVHWFramesContext *hwfc, AVFrame *dst,
912 const AVFrame *src, int flags)
916 if (dst->format != AV_PIX_FMT_NONE) {
917 err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL);
919 return AVERROR(ENOSYS);
922 err = vaapi_map_frame(hwfc, dst, src, flags);
926 err = av_frame_copy_props(dst, src);
935 #define DRM_MAP(va, layers, ...) { \
940 static const struct {
942 int nb_layer_formats;
943 uint32_t layer_formats[AV_DRM_MAX_PLANES];
944 } vaapi_drm_format_map[] = {
946 DRM_MAP(NV12, 2, DRM_FORMAT_R8, DRM_FORMAT_RG88),
948 DRM_MAP(NV12, 1, DRM_FORMAT_NV12),
949 #if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16)
950 DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
952 DRM_MAP(BGRA, 1, DRM_FORMAT_ARGB8888),
953 DRM_MAP(BGRX, 1, DRM_FORMAT_XRGB8888),
954 DRM_MAP(RGBA, 1, DRM_FORMAT_ABGR8888),
955 DRM_MAP(RGBX, 1, DRM_FORMAT_XBGR8888),
956 #ifdef VA_FOURCC_ABGR
957 DRM_MAP(ABGR, 1, DRM_FORMAT_RGBA8888),
958 DRM_MAP(XBGR, 1, DRM_FORMAT_RGBX8888),
960 DRM_MAP(ARGB, 1, DRM_FORMAT_BGRA8888),
961 DRM_MAP(XRGB, 1, DRM_FORMAT_BGRX8888),
965 static void vaapi_unmap_from_drm(AVHWFramesContext *dst_fc,
966 HWMapDescriptor *hwmap)
968 AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
970 VASurfaceID surface_id = (VASurfaceID)(uintptr_t)hwmap->priv;
972 av_log(dst_fc, AV_LOG_DEBUG, "Destroy surface %#x.\n", surface_id);
974 vaDestroySurfaces(dst_dev->display, &surface_id, 1);
977 static int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst,
978 const AVFrame *src, int flags)
980 AVHWFramesContext *dst_fc =
981 (AVHWFramesContext*)dst->hw_frames_ctx->data;
982 AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
983 const AVDRMFrameDescriptor *desc;
984 VASurfaceID surface_id;
986 uint32_t va_fourcc, va_rt_format;
989 unsigned long buffer_handle;
990 VASurfaceAttribExternalBuffers buffer_desc;
991 VASurfaceAttrib attrs[2] = {
993 .type = VASurfaceAttribMemoryType,
994 .flags = VA_SURFACE_ATTRIB_SETTABLE,
995 .value.type = VAGenericValueTypeInteger,
996 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
999 .type = VASurfaceAttribExternalBufferDescriptor,
1000 .flags = VA_SURFACE_ATTRIB_SETTABLE,
1001 .value.type = VAGenericValueTypePointer,
1002 .value.value.p = &buffer_desc,
1006 desc = (AVDRMFrameDescriptor*)src->data[0];
1008 if (desc->nb_objects != 1) {
1009 av_log(dst_fc, AV_LOG_ERROR, "VAAPI can only map frames "
1010 "made from a single DRM object.\n");
1011 return AVERROR(EINVAL);
1015 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
1016 if (desc->nb_layers != vaapi_drm_format_map[i].nb_layer_formats)
1018 for (j = 0; j < desc->nb_layers; j++) {
1019 if (desc->layers[j].format !=
1020 vaapi_drm_format_map[i].layer_formats[j])
1023 if (j != desc->nb_layers)
1025 va_fourcc = vaapi_drm_format_map[i].va_fourcc;
1029 av_log(dst_fc, AV_LOG_ERROR, "DRM format not supported "
1031 return AVERROR(EINVAL);
1034 av_log(dst_fc, AV_LOG_DEBUG, "Map DRM object %d to VAAPI as "
1035 "%08x.\n", desc->objects[0].fd, va_fourcc);
1037 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
1038 if (vaapi_format_map[i].fourcc == va_fourcc) {
1039 va_rt_format = vaapi_format_map[i].rt_format;
1044 av_assert0(i < FF_ARRAY_ELEMS(vaapi_format_map));
1046 buffer_handle = desc->objects[0].fd;
1047 buffer_desc.pixel_format = va_fourcc;
1048 buffer_desc.width = src_fc->width;
1049 buffer_desc.height = src_fc->height;
1050 buffer_desc.data_size = desc->objects[0].size;
1051 buffer_desc.buffers = &buffer_handle;
1052 buffer_desc.num_buffers = 1;
1053 buffer_desc.flags = 0;
1056 for (i = 0; i < desc->nb_layers; i++) {
1057 for (j = 0; j < desc->layers[i].nb_planes; j++) {
1058 buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch;
1059 buffer_desc.offsets[k] = desc->layers[i].planes[j].offset;
1063 buffer_desc.num_planes = k;
1065 vas = vaCreateSurfaces(dst_dev->display, va_rt_format,
1066 src->width, src->height,
1068 attrs, FF_ARRAY_ELEMS(attrs));
1069 if (vas != VA_STATUS_SUCCESS) {
1070 av_log(dst_fc, AV_LOG_ERROR, "Failed to create surface from DRM "
1071 "object: %d (%s).\n", vas, vaErrorStr(vas));
1072 return AVERROR(EIO);
1074 av_log(dst_fc, AV_LOG_DEBUG, "Create surface %#x.\n", surface_id);
1076 err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
1077 &vaapi_unmap_from_drm,
1078 (void*)(uintptr_t)surface_id);
1082 dst->width = src->width;
1083 dst->height = src->height;
1084 dst->data[3] = (uint8_t*)(uintptr_t)surface_id;
1086 av_log(dst_fc, AV_LOG_DEBUG, "Mapped DRM object %d to "
1087 "surface %#x.\n", desc->objects[0].fd, surface_id);
1092 #if VA_CHECK_VERSION(1, 1, 0)
1093 static void vaapi_unmap_to_drm_esh(AVHWFramesContext *hwfc,
1094 HWMapDescriptor *hwmap)
1096 AVDRMFrameDescriptor *drm_desc = hwmap->priv;
1099 for (i = 0; i < drm_desc->nb_objects; i++)
1100 close(drm_desc->objects[i].fd);
1102 av_freep(&drm_desc);
1105 static int vaapi_map_to_drm_esh(AVHWFramesContext *hwfc, AVFrame *dst,
1106 const AVFrame *src, int flags)
1108 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1109 VASurfaceID surface_id;
1111 VADRMPRIMESurfaceDescriptor va_desc;
1112 AVDRMFrameDescriptor *drm_desc = NULL;
1113 uint32_t export_flags;
1116 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
1118 export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS;
1119 if (flags & AV_HWFRAME_MAP_READ)
1120 export_flags |= VA_EXPORT_SURFACE_READ_ONLY;
1121 if (flags & AV_HWFRAME_MAP_WRITE)
1122 export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY;
1124 vas = vaExportSurfaceHandle(hwctx->display, surface_id,
1125 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
1126 export_flags, &va_desc);
1127 if (vas != VA_STATUS_SUCCESS) {
1128 if (vas == VA_STATUS_ERROR_UNIMPLEMENTED)
1129 return AVERROR(ENOSYS);
1130 av_log(hwfc, AV_LOG_ERROR, "Failed to export surface %#x: "
1131 "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
1132 return AVERROR(EIO);
1135 drm_desc = av_mallocz(sizeof(*drm_desc));
1137 err = AVERROR(ENOMEM);
1141 // By some bizarre coincidence, these structures are very similar...
1142 drm_desc->nb_objects = va_desc.num_objects;
1143 for (i = 0; i < va_desc.num_objects; i++) {
1144 drm_desc->objects[i].fd = va_desc.objects[i].fd;
1145 drm_desc->objects[i].size = va_desc.objects[i].size;
1146 drm_desc->objects[i].format_modifier =
1147 va_desc.objects[i].drm_format_modifier;
1149 drm_desc->nb_layers = va_desc.num_layers;
1150 for (i = 0; i < va_desc.num_layers; i++) {
1151 drm_desc->layers[i].format = va_desc.layers[i].drm_format;
1152 drm_desc->layers[i].nb_planes = va_desc.layers[i].num_planes;
1153 for (j = 0; j < va_desc.layers[i].num_planes; j++) {
1154 drm_desc->layers[i].planes[j].object_index =
1155 va_desc.layers[i].object_index[j];
1156 drm_desc->layers[i].planes[j].offset =
1157 va_desc.layers[i].offset[j];
1158 drm_desc->layers[i].planes[j].pitch =
1159 va_desc.layers[i].pitch[j];
1163 err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
1164 &vaapi_unmap_to_drm_esh, drm_desc);
1168 dst->width = src->width;
1169 dst->height = src->height;
1170 dst->data[0] = (uint8_t*)drm_desc;
1175 for (i = 0; i < va_desc.num_objects; i++)
1176 close(va_desc.objects[i].fd);
1177 av_freep(&drm_desc);
1182 #if VA_CHECK_VERSION(0, 36, 0)
1183 typedef struct VAAPIDRMImageBufferMapping {
1185 VABufferInfo buffer_info;
1187 AVDRMFrameDescriptor drm_desc;
1188 } VAAPIDRMImageBufferMapping;
1190 static void vaapi_unmap_to_drm_abh(AVHWFramesContext *hwfc,
1191 HWMapDescriptor *hwmap)
1193 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1194 VAAPIDRMImageBufferMapping *mapping = hwmap->priv;
1195 VASurfaceID surface_id;
1198 surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
1199 av_log(hwfc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from DRM.\n",
1202 // DRM PRIME file descriptors are closed by vaReleaseBufferHandle(),
1203 // so we shouldn't close them separately.
1205 vas = vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
1206 if (vas != VA_STATUS_SUCCESS) {
1207 av_log(hwfc, AV_LOG_ERROR, "Failed to release buffer "
1208 "handle of image %#x (derived from surface %#x): "
1209 "%d (%s).\n", mapping->image.buf, surface_id,
1210 vas, vaErrorStr(vas));
1213 vas = vaDestroyImage(hwctx->display, mapping->image.image_id);
1214 if (vas != VA_STATUS_SUCCESS) {
1215 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image "
1216 "derived from surface %#x: %d (%s).\n",
1217 surface_id, vas, vaErrorStr(vas));
1223 static int vaapi_map_to_drm_abh(AVHWFramesContext *hwfc, AVFrame *dst,
1224 const AVFrame *src, int flags)
1226 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1227 VAAPIDRMImageBufferMapping *mapping = NULL;
1228 VASurfaceID surface_id;
1232 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
1233 av_log(hwfc, AV_LOG_DEBUG, "Map VAAPI surface %#x to DRM.\n",
1236 mapping = av_mallocz(sizeof(*mapping));
1238 return AVERROR(ENOMEM);
1240 vas = vaDeriveImage(hwctx->display, surface_id,
1242 if (vas != VA_STATUS_SUCCESS) {
1243 av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
1244 "surface %#x: %d (%s).\n",
1245 surface_id, vas, vaErrorStr(vas));
1250 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
1251 if (vaapi_drm_format_map[i].va_fourcc ==
1252 mapping->image.format.fourcc)
1255 if (i >= FF_ARRAY_ELEMS(vaapi_drm_format_map)) {
1256 av_log(hwfc, AV_LOG_ERROR, "No matching DRM format for "
1257 "VAAPI format %#x.\n", mapping->image.format.fourcc);
1258 err = AVERROR(EINVAL);
1262 mapping->buffer_info.mem_type =
1263 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
1265 mapping->drm_desc.nb_layers =
1266 vaapi_drm_format_map[i].nb_layer_formats;
1267 if (mapping->drm_desc.nb_layers > 1) {
1268 if (mapping->drm_desc.nb_layers != mapping->image.num_planes) {
1269 av_log(hwfc, AV_LOG_ERROR, "Image properties do not match "
1270 "expected format: got %d planes, but expected %d.\n",
1271 mapping->image.num_planes, mapping->drm_desc.nb_layers);
1272 err = AVERROR(EINVAL);
1276 for(p = 0; p < mapping->drm_desc.nb_layers; p++) {
1277 mapping->drm_desc.layers[p] = (AVDRMLayerDescriptor) {
1278 .format = vaapi_drm_format_map[i].layer_formats[p],
1282 .offset = mapping->image.offsets[p],
1283 .pitch = mapping->image.pitches[p],
1288 mapping->drm_desc.layers[0].format =
1289 vaapi_drm_format_map[i].layer_formats[0];
1290 mapping->drm_desc.layers[0].nb_planes = mapping->image.num_planes;
1291 for (p = 0; p < mapping->image.num_planes; p++) {
1292 mapping->drm_desc.layers[0].planes[p] = (AVDRMPlaneDescriptor) {
1294 .offset = mapping->image.offsets[p],
1295 .pitch = mapping->image.pitches[p],
1300 vas = vaAcquireBufferHandle(hwctx->display, mapping->image.buf,
1301 &mapping->buffer_info);
1302 if (vas != VA_STATUS_SUCCESS) {
1303 av_log(hwfc, AV_LOG_ERROR, "Failed to get buffer "
1304 "handle from image %#x (derived from surface %#x): "
1305 "%d (%s).\n", mapping->image.buf, surface_id,
1306 vas, vaErrorStr(vas));
1311 av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n",
1312 mapping->buffer_info.handle);
1314 mapping->drm_desc.nb_objects = 1;
1315 mapping->drm_desc.objects[0] = (AVDRMObjectDescriptor) {
1316 .fd = mapping->buffer_info.handle,
1317 .size = mapping->image.data_size,
1318 // There is no way to get the format modifier with this API.
1319 .format_modifier = DRM_FORMAT_MOD_INVALID,
1322 err = ff_hwframe_map_create(src->hw_frames_ctx,
1323 dst, src, &vaapi_unmap_to_drm_abh,
1328 dst->data[0] = (uint8_t*)&mapping->drm_desc;
1329 dst->width = src->width;
1330 dst->height = src->height;
1335 vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
1337 vaDestroyImage(hwctx->display, mapping->image.image_id);
1344 static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
1345 const AVFrame *src, int flags)
1347 #if VA_CHECK_VERSION(1, 1, 0)
1349 err = vaapi_map_to_drm_esh(hwfc, dst, src, flags);
1350 if (err != AVERROR(ENOSYS))
1353 #if VA_CHECK_VERSION(0, 36, 0)
1354 return vaapi_map_to_drm_abh(hwfc, dst, src, flags);
1356 return AVERROR(ENOSYS);
1359 #endif /* CONFIG_LIBDRM */
1361 static int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
1362 const AVFrame *src, int flags)
1364 switch (src->format) {
1366 case AV_PIX_FMT_DRM_PRIME:
1367 return vaapi_map_from_drm(hwfc, dst, src, flags);
1370 return AVERROR(ENOSYS);
1374 static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
1375 const AVFrame *src, int flags)
1377 switch (dst->format) {
1379 case AV_PIX_FMT_DRM_PRIME:
1380 return vaapi_map_to_drm(hwfc, dst, src, flags);
1383 return vaapi_map_to_memory(hwfc, dst, src, flags);
1387 static void vaapi_device_free(AVHWDeviceContext *ctx)
1389 AVVAAPIDeviceContext *hwctx = ctx->hwctx;
1390 VAAPIDevicePriv *priv = ctx->user_opaque;
1393 vaTerminate(hwctx->display);
1396 if (priv->x11_display)
1397 XCloseDisplay(priv->x11_display);
1400 if (priv->drm_fd >= 0)
1401 close(priv->drm_fd);
1407 static void vaapi_device_log_error(void *context, const char *message)
1409 AVHWDeviceContext *ctx = context;
1411 av_log(ctx, AV_LOG_ERROR, "libva: %s", message);
1414 static void vaapi_device_log_info(void *context, const char *message)
1416 AVHWDeviceContext *ctx = context;
1418 av_log(ctx, AV_LOG_VERBOSE, "libva: %s", message);
1422 static int vaapi_device_connect(AVHWDeviceContext *ctx,
1425 AVVAAPIDeviceContext *hwctx = ctx->hwctx;
1430 vaSetErrorCallback(display, &vaapi_device_log_error, ctx);
1431 vaSetInfoCallback (display, &vaapi_device_log_info, ctx);
1434 hwctx->display = display;
1436 vas = vaInitialize(display, &major, &minor);
1437 if (vas != VA_STATUS_SUCCESS) {
1438 av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
1439 "connection: %d (%s).\n", vas, vaErrorStr(vas));
1440 return AVERROR(EIO);
1442 av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
1443 "version %d.%d\n", major, minor);
1448 static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
1449 AVDictionary *opts, int flags)
1451 VAAPIDevicePriv *priv;
1452 VADisplay display = NULL;
1454 priv = av_mallocz(sizeof(*priv));
1456 return AVERROR(ENOMEM);
1460 ctx->user_opaque = priv;
1461 ctx->free = vaapi_device_free;
1464 if (!display && !(device && device[0] == '/')) {
1465 // Try to open the device as an X11 display.
1466 priv->x11_display = XOpenDisplay(device);
1467 if (!priv->x11_display) {
1468 av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
1469 "%s.\n", XDisplayName(device));
1471 display = vaGetDisplay(priv->x11_display);
1473 av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
1474 "from X11 display %s.\n", XDisplayName(device));
1475 return AVERROR_UNKNOWN;
1478 av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
1479 "X11 display %s.\n", XDisplayName(device));
1486 // Try to open the device as a DRM path.
1487 // Default to using the first render node if the user did not
1489 const char *path = device ? device : "/dev/dri/renderD128";
1490 priv->drm_fd = open(path, O_RDWR);
1491 if (priv->drm_fd < 0) {
1492 av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n",
1495 display = vaGetDisplayDRM(priv->drm_fd);
1497 av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
1498 "from DRM device %s.\n", path);
1499 return AVERROR_UNKNOWN;
1502 av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
1503 "DRM device %s.\n", path);
1509 av_log(ctx, AV_LOG_ERROR, "No VA display found for "
1510 "device: %s.\n", device ? device : "");
1511 return AVERROR(EINVAL);
1514 return vaapi_device_connect(ctx, display);
1517 static int vaapi_device_derive(AVHWDeviceContext *ctx,
1518 AVHWDeviceContext *src_ctx, int flags)
1521 if (src_ctx->type == AV_HWDEVICE_TYPE_DRM) {
1522 AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
1524 VAAPIDevicePriv *priv;
1526 if (src_hwctx->fd < 0) {
1527 av_log(ctx, AV_LOG_ERROR, "DRM instance requires an associated "
1528 "device to derive a VA display from.\n");
1529 return AVERROR(EINVAL);
1532 priv = av_mallocz(sizeof(*priv));
1534 return AVERROR(ENOMEM);
1536 // Inherits the fd from the source context, which will close it.
1539 ctx->user_opaque = priv;
1540 ctx->free = &vaapi_device_free;
1542 display = vaGetDisplayDRM(src_hwctx->fd);
1544 av_log(ctx, AV_LOG_ERROR, "Failed to open a VA display from "
1546 return AVERROR(EIO);
1549 return vaapi_device_connect(ctx, display);
1552 return AVERROR(ENOSYS);
1555 const HWContextType ff_hwcontext_type_vaapi = {
1556 .type = AV_HWDEVICE_TYPE_VAAPI,
1559 .device_hwctx_size = sizeof(AVVAAPIDeviceContext),
1560 .device_priv_size = sizeof(VAAPIDeviceContext),
1561 .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
1562 .frames_hwctx_size = sizeof(AVVAAPIFramesContext),
1563 .frames_priv_size = sizeof(VAAPIFramesContext),
1565 .device_create = &vaapi_device_create,
1566 .device_derive = &vaapi_device_derive,
1567 .device_init = &vaapi_device_init,
1568 .device_uninit = &vaapi_device_uninit,
1569 .frames_get_constraints = &vaapi_frames_get_constraints,
1570 .frames_init = &vaapi_frames_init,
1571 .frames_uninit = &vaapi_frames_uninit,
1572 .frames_get_buffer = &vaapi_get_buffer,
1573 .transfer_get_formats = &vaapi_transfer_get_formats,
1574 .transfer_data_to = &vaapi_transfer_data_to,
1575 .transfer_data_from = &vaapi_transfer_data_from,
1576 .map_to = &vaapi_map_to,
1577 .map_from = &vaapi_map_from,
1579 .pix_fmts = (const enum AVPixelFormat[]) {