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 typedef struct VAAPIFormat {
92 unsigned int rt_format;
93 enum AVPixelFormat pix_fmt;
94 int chroma_planes_swapped;
95 } VAAPIFormatDescriptor;
97 #define MAP(va, rt, av, swap_uv) { \
99 VA_RT_FORMAT_ ## rt, \
103 // The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V
104 // plane swap cases. The frame handling below tries to hide these.
105 static const VAAPIFormatDescriptor vaapi_format_map[] = {
106 MAP(NV12, YUV420, NV12, 0),
107 #ifdef VA_FOURCC_I420
108 MAP(I420, YUV420, YUV420P, 0),
110 MAP(YV12, YUV420, YUV420P, 1),
111 MAP(IYUV, YUV420, YUV420P, 0),
112 MAP(422H, YUV422, YUV422P, 0),
113 #ifdef VA_FOURCC_YV16
114 MAP(YV16, YUV422, YUV422P, 1),
116 MAP(UYVY, YUV422, UYVY422, 0),
117 MAP(YUY2, YUV422, YUYV422, 0),
118 MAP(411P, YUV411, YUV411P, 0),
119 MAP(422V, YUV422, YUV440P, 0),
120 MAP(444P, YUV444, YUV444P, 0),
121 MAP(Y800, YUV400, GRAY8, 0),
122 #ifdef VA_FOURCC_P010
123 MAP(P010, YUV420_10BPP, P010, 0),
125 MAP(BGRA, RGB32, BGRA, 0),
126 MAP(BGRX, RGB32, BGR0, 0),
127 MAP(RGBA, RGB32, RGBA, 0),
128 MAP(RGBX, RGB32, RGB0, 0),
129 #ifdef VA_FOURCC_ABGR
130 MAP(ABGR, RGB32, ABGR, 0),
131 MAP(XBGR, RGB32, 0BGR, 0),
133 MAP(ARGB, RGB32, ARGB, 0),
134 MAP(XRGB, RGB32, 0RGB, 0),
138 static const VAAPIFormatDescriptor *
139 vaapi_format_from_fourcc(unsigned int fourcc)
142 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
143 if (vaapi_format_map[i].fourcc == fourcc)
144 return &vaapi_format_map[i];
148 static const VAAPIFormatDescriptor *
149 vaapi_format_from_pix_fmt(enum AVPixelFormat pix_fmt)
152 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
153 if (vaapi_format_map[i].pix_fmt == pix_fmt)
154 return &vaapi_format_map[i];
158 static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc)
160 const VAAPIFormatDescriptor *desc;
161 desc = vaapi_format_from_fourcc(fourcc);
163 return desc->pix_fmt;
165 return AV_PIX_FMT_NONE;
168 static int vaapi_get_image_format(AVHWDeviceContext *hwdev,
169 enum AVPixelFormat pix_fmt,
170 VAImageFormat **image_format)
172 VAAPIDeviceContext *ctx = hwdev->internal->priv;
175 for (i = 0; i < ctx->nb_formats; i++) {
176 if (ctx->formats[i].pix_fmt == pix_fmt) {
178 *image_format = &ctx->formats[i].image_format;
182 return AVERROR(EINVAL);
185 static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev,
186 const void *hwconfig,
187 AVHWFramesConstraints *constraints)
189 AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
190 const AVVAAPIHWConfig *config = hwconfig;
191 VAAPIDeviceContext *ctx = hwdev->internal->priv;
192 VASurfaceAttrib *attr_list = NULL;
194 enum AVPixelFormat pix_fmt;
196 int err, i, j, attr_count, pix_fmt_count;
199 !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {
201 vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
203 if (vas != VA_STATUS_SUCCESS) {
204 av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
205 "%d (%s).\n", vas, vaErrorStr(vas));
206 err = AVERROR(ENOSYS);
210 attr_list = av_malloc(attr_count * sizeof(*attr_list));
212 err = AVERROR(ENOMEM);
216 vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
217 attr_list, &attr_count);
218 if (vas != VA_STATUS_SUCCESS) {
219 av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
220 "%d (%s).\n", vas, vaErrorStr(vas));
221 err = AVERROR(ENOSYS);
226 for (i = 0; i < attr_count; i++) {
227 switch (attr_list[i].type) {
228 case VASurfaceAttribPixelFormat:
229 fourcc = attr_list[i].value.value.i;
230 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
231 if (pix_fmt != AV_PIX_FMT_NONE) {
234 // Something unsupported - ignore.
237 case VASurfaceAttribMinWidth:
238 constraints->min_width = attr_list[i].value.value.i;
240 case VASurfaceAttribMinHeight:
241 constraints->min_height = attr_list[i].value.value.i;
243 case VASurfaceAttribMaxWidth:
244 constraints->max_width = attr_list[i].value.value.i;
246 case VASurfaceAttribMaxHeight:
247 constraints->max_height = attr_list[i].value.value.i;
251 if (pix_fmt_count == 0) {
252 // Nothing usable found. Presumably there exists something which
253 // works, so leave the set null to indicate unknown.
254 constraints->valid_sw_formats = NULL;
256 constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
258 if (!constraints->valid_sw_formats) {
259 err = AVERROR(ENOMEM);
263 for (i = j = 0; i < attr_count; i++) {
264 if (attr_list[i].type != VASurfaceAttribPixelFormat)
266 fourcc = attr_list[i].value.value.i;
267 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
268 if (pix_fmt != AV_PIX_FMT_NONE)
269 constraints->valid_sw_formats[j++] = pix_fmt;
271 av_assert0(j == pix_fmt_count);
272 constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
275 // No configuration supplied.
276 // Return the full set of image formats known by the implementation.
277 constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1,
279 if (!constraints->valid_sw_formats) {
280 err = AVERROR(ENOMEM);
283 for (i = 0; i < ctx->nb_formats; i++)
284 constraints->valid_sw_formats[i] = ctx->formats[i].pix_fmt;
285 constraints->valid_sw_formats[i] = AV_PIX_FMT_NONE;
288 constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
289 if (!constraints->valid_hw_formats) {
290 err = AVERROR(ENOMEM);
293 constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
294 constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
298 av_freep(&attr_list);
302 static const struct {
303 const char *friendly_name;
304 const char *match_string;
306 } vaapi_driver_quirks_table[] = {
307 #if !VA_CHECK_VERSION(1, 0, 0)
308 // The i965 driver did not conform before version 2.0.
310 "Intel i965 (Quick Sync)",
312 AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS,
318 AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE,
322 "Splitted-Desktop Systems VDPAU backend for VA-API",
323 AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES,
327 static int vaapi_device_init(AVHWDeviceContext *hwdev)
329 VAAPIDeviceContext *ctx = hwdev->internal->priv;
330 AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
331 VAImageFormat *image_list = NULL;
333 const char *vendor_string;
334 int err, i, image_count;
335 enum AVPixelFormat pix_fmt;
338 image_count = vaMaxNumImageFormats(hwctx->display);
339 if (image_count <= 0) {
343 image_list = av_malloc(image_count * sizeof(*image_list));
345 err = AVERROR(ENOMEM);
348 vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
349 if (vas != VA_STATUS_SUCCESS) {
354 ctx->formats = av_malloc(image_count * sizeof(*ctx->formats));
356 err = AVERROR(ENOMEM);
360 for (i = 0; i < image_count; i++) {
361 fourcc = image_list[i].fourcc;
362 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
363 if (pix_fmt == AV_PIX_FMT_NONE) {
364 av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n",
367 av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",
368 fourcc, av_get_pix_fmt_name(pix_fmt));
369 ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt;
370 ctx->formats[ctx->nb_formats].image_format = image_list[i];
375 vendor_string = vaQueryVendorString(hwctx->display);
377 av_log(hwdev, AV_LOG_VERBOSE, "VAAPI driver: %s.\n", vendor_string);
379 if (hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_USER_SET) {
380 av_log(hwdev, AV_LOG_VERBOSE, "Using quirks set by user (%#x).\n",
381 hwctx->driver_quirks);
383 // Detect the driver in use and set quirk flags if necessary.
384 hwctx->driver_quirks = 0;
386 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) {
387 if (strstr(vendor_string,
388 vaapi_driver_quirks_table[i].match_string)) {
389 av_log(hwdev, AV_LOG_VERBOSE, "Matched driver string "
390 "as known nonstandard driver \"%s\", setting "
392 vaapi_driver_quirks_table[i].friendly_name,
393 vaapi_driver_quirks_table[i].quirks);
394 hwctx->driver_quirks |=
395 vaapi_driver_quirks_table[i].quirks;
399 if (!(i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table))) {
400 av_log(hwdev, AV_LOG_VERBOSE, "Driver not found in known "
401 "nonstandard list, using standard behaviour.\n");
404 av_log(hwdev, AV_LOG_VERBOSE, "Driver has no vendor string, "
405 "assuming standard behaviour.\n");
412 av_freep(&ctx->formats);
417 static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
419 VAAPIDeviceContext *ctx = hwdev->internal->priv;
421 av_freep(&ctx->formats);
424 static void vaapi_buffer_free(void *opaque, uint8_t *data)
426 AVHWFramesContext *hwfc = opaque;
427 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
428 VASurfaceID surface_id;
431 surface_id = (VASurfaceID)(uintptr_t)data;
433 vas = vaDestroySurfaces(hwctx->display, &surface_id, 1);
434 if (vas != VA_STATUS_SUCCESS) {
435 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: "
436 "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
440 static AVBufferRef *vaapi_pool_alloc(void *opaque, int size)
442 AVHWFramesContext *hwfc = opaque;
443 VAAPIFramesContext *ctx = hwfc->internal->priv;
444 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
445 AVVAAPIFramesContext *avfc = hwfc->hwctx;
446 VASurfaceID surface_id;
450 if (hwfc->initial_pool_size > 0 &&
451 avfc->nb_surfaces >= hwfc->initial_pool_size)
454 vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
455 hwfc->width, hwfc->height,
457 ctx->attributes, ctx->nb_attributes);
458 if (vas != VA_STATUS_SUCCESS) {
459 av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
460 "%d (%s).\n", vas, vaErrorStr(vas));
463 av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
465 ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
466 sizeof(surface_id), &vaapi_buffer_free,
467 hwfc, AV_BUFFER_FLAG_READONLY);
469 vaDestroySurfaces(hwctx->display, &surface_id, 1);
473 if (hwfc->initial_pool_size > 0) {
474 // This is a fixed-size pool, so we must still be in the initial
475 // allocation sequence.
476 av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size);
477 avfc->surface_ids[avfc->nb_surfaces] = surface_id;
484 static int vaapi_frames_init(AVHWFramesContext *hwfc)
486 AVVAAPIFramesContext *avfc = hwfc->hwctx;
487 VAAPIFramesContext *ctx = hwfc->internal->priv;
488 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
489 const VAAPIFormatDescriptor *desc;
490 VAImageFormat *expected_format;
491 AVBufferRef *test_surface = NULL;
492 VASurfaceID test_surface_id;
497 desc = vaapi_format_from_pix_fmt(hwfc->sw_format);
499 av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
500 av_get_pix_fmt_name(hwfc->sw_format));
501 return AVERROR(EINVAL);
505 if (!(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {
506 int need_memory_type = !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE);
507 int need_pixel_format = 1;
508 for (i = 0; i < avfc->nb_attributes; i++) {
509 if (avfc->attributes[i].type == VASurfaceAttribMemoryType)
510 need_memory_type = 0;
511 if (avfc->attributes[i].type == VASurfaceAttribPixelFormat)
512 need_pixel_format = 0;
515 avfc->nb_attributes + need_memory_type + need_pixel_format;
517 ctx->attributes = av_malloc(ctx->nb_attributes *
518 sizeof(*ctx->attributes));
519 if (!ctx->attributes) {
520 err = AVERROR(ENOMEM);
524 for (i = 0; i < avfc->nb_attributes; i++)
525 ctx->attributes[i] = avfc->attributes[i];
526 if (need_memory_type) {
527 ctx->attributes[i++] = (VASurfaceAttrib) {
528 .type = VASurfaceAttribMemoryType,
529 .flags = VA_SURFACE_ATTRIB_SETTABLE,
530 .value.type = VAGenericValueTypeInteger,
531 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
534 if (need_pixel_format) {
535 ctx->attributes[i++] = (VASurfaceAttrib) {
536 .type = VASurfaceAttribPixelFormat,
537 .flags = VA_SURFACE_ATTRIB_SETTABLE,
538 .value.type = VAGenericValueTypeInteger,
539 .value.value.i = desc->fourcc,
542 av_assert0(i == ctx->nb_attributes);
544 ctx->attributes = NULL;
545 ctx->nb_attributes = 0;
548 ctx->rt_format = desc->rt_format;
550 if (hwfc->initial_pool_size > 0) {
551 // This pool will be usable as a render target, so we need to store
552 // all of the surface IDs somewhere that vaCreateContext() calls
553 // will be able to access them.
554 avfc->nb_surfaces = 0;
555 avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
556 sizeof(*avfc->surface_ids));
557 if (!avfc->surface_ids) {
558 err = AVERROR(ENOMEM);
562 // This pool allows dynamic sizing, and will not be usable as a
564 avfc->nb_surfaces = 0;
565 avfc->surface_ids = NULL;
568 hwfc->internal->pool_internal =
569 av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
570 &vaapi_pool_alloc, NULL);
571 if (!hwfc->internal->pool_internal) {
572 av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
573 err = AVERROR(ENOMEM);
578 // Allocate a single surface to test whether vaDeriveImage() is going
579 // to work for the specific configuration.
581 test_surface = av_buffer_pool_get(hwfc->pool);
583 av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
584 "user-configured buffer pool.\n");
585 err = AVERROR(ENOMEM);
589 test_surface = av_buffer_pool_get(hwfc->internal->pool_internal);
591 av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
592 "internal buffer pool.\n");
593 err = AVERROR(ENOMEM);
597 test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
599 ctx->derive_works = 0;
601 err = vaapi_get_image_format(hwfc->device_ctx,
602 hwfc->sw_format, &expected_format);
604 vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
605 if (vas == VA_STATUS_SUCCESS) {
606 if (expected_format->fourcc == test_image.format.fourcc) {
607 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
608 ctx->derive_works = 1;
610 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
611 "derived image format %08x does not match "
612 "expected format %08x.\n",
613 expected_format->fourcc, test_image.format.fourcc);
615 vaDestroyImage(hwctx->display, test_image.image_id);
617 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
618 "deriving image does not work: "
619 "%d (%s).\n", vas, vaErrorStr(vas));
622 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
623 "image format is not supported.\n");
626 av_buffer_unref(&test_surface);
630 av_buffer_unref(&test_surface);
631 av_freep(&avfc->surface_ids);
632 av_freep(&ctx->attributes);
636 static void vaapi_frames_uninit(AVHWFramesContext *hwfc)
638 AVVAAPIFramesContext *avfc = hwfc->hwctx;
639 VAAPIFramesContext *ctx = hwfc->internal->priv;
641 av_freep(&avfc->surface_ids);
642 av_freep(&ctx->attributes);
645 static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
647 frame->buf[0] = av_buffer_pool_get(hwfc->pool);
649 return AVERROR(ENOMEM);
651 frame->data[3] = frame->buf[0]->data;
652 frame->format = AV_PIX_FMT_VAAPI;
653 frame->width = hwfc->width;
654 frame->height = hwfc->height;
659 static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc,
660 enum AVHWFrameTransferDirection dir,
661 enum AVPixelFormat **formats)
663 VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv;
664 enum AVPixelFormat *pix_fmts;
665 int i, k, sw_format_available;
667 sw_format_available = 0;
668 for (i = 0; i < ctx->nb_formats; i++) {
669 if (ctx->formats[i].pix_fmt == hwfc->sw_format)
670 sw_format_available = 1;
673 pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
675 return AVERROR(ENOMEM);
677 if (sw_format_available) {
678 pix_fmts[0] = hwfc->sw_format;
683 for (i = 0; i < ctx->nb_formats; i++) {
684 if (ctx->formats[i].pix_fmt == hwfc->sw_format)
686 av_assert0(k < ctx->nb_formats);
687 pix_fmts[k++] = ctx->formats[i].pix_fmt;
689 pix_fmts[k] = AV_PIX_FMT_NONE;
695 static void vaapi_unmap_frame(AVHWFramesContext *hwfc,
696 HWMapDescriptor *hwmap)
698 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
699 VAAPIMapping *map = hwmap->priv;
700 VASurfaceID surface_id;
703 surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
704 av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
706 vas = vaUnmapBuffer(hwctx->display, map->image.buf);
707 if (vas != VA_STATUS_SUCCESS) {
708 av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
709 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
712 if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
713 !(map->flags & AV_HWFRAME_MAP_DIRECT)) {
714 vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
715 0, 0, hwfc->width, hwfc->height,
716 0, 0, hwfc->width, hwfc->height);
717 if (vas != VA_STATUS_SUCCESS) {
718 av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
719 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
723 vas = vaDestroyImage(hwctx->display, map->image.image_id);
724 if (vas != VA_STATUS_SUCCESS) {
725 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
726 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
732 static int vaapi_map_frame(AVHWFramesContext *hwfc,
733 AVFrame *dst, const AVFrame *src, int flags)
735 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
736 VAAPIFramesContext *ctx = hwfc->internal->priv;
737 VASurfaceID surface_id;
738 const VAAPIFormatDescriptor *desc;
739 VAImageFormat *image_format;
742 void *address = NULL;
745 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
746 av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
748 if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) {
749 // Requested direct mapping but it is not possible.
750 return AVERROR(EINVAL);
752 if (dst->format == AV_PIX_FMT_NONE)
753 dst->format = hwfc->sw_format;
754 if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) {
755 // Requested direct mapping but the formats do not match.
756 return AVERROR(EINVAL);
759 err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
761 // Requested format is not a valid output format.
762 return AVERROR(EINVAL);
765 map = av_malloc(sizeof(*map));
767 return AVERROR(ENOMEM);
769 map->image.image_id = VA_INVALID_ID;
771 vas = vaSyncSurface(hwctx->display, surface_id);
772 if (vas != VA_STATUS_SUCCESS) {
773 av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
774 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
779 // The memory which we map using derive need not be connected to the CPU
780 // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
781 // memory is mappable but not cached, so normal memcpy()-like access is
782 // very slow to read it (but writing is ok). It is possible to read much
783 // faster with a copy routine which is aware of the limitation, but we
784 // assume for now that the user is not aware of that and would therefore
785 // prefer not to be given direct-mapped memory if they request read access.
786 if (ctx->derive_works && dst->format == hwfc->sw_format &&
787 ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) {
788 vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
789 if (vas != VA_STATUS_SUCCESS) {
790 av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
791 "surface %#x: %d (%s).\n",
792 surface_id, vas, vaErrorStr(vas));
796 if (map->image.format.fourcc != image_format->fourcc) {
797 av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
798 "is in wrong format: expected %#08x, got %#08x.\n",
799 surface_id, image_format->fourcc, map->image.format.fourcc);
803 map->flags |= AV_HWFRAME_MAP_DIRECT;
805 vas = vaCreateImage(hwctx->display, image_format,
806 hwfc->width, hwfc->height, &map->image);
807 if (vas != VA_STATUS_SUCCESS) {
808 av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
809 "surface %#x: %d (%s).\n",
810 surface_id, vas, vaErrorStr(vas));
814 if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) {
815 vas = vaGetImage(hwctx->display, surface_id, 0, 0,
816 hwfc->width, hwfc->height, map->image.image_id);
817 if (vas != VA_STATUS_SUCCESS) {
818 av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
819 "surface %#x: %d (%s).\n",
820 surface_id, vas, vaErrorStr(vas));
827 vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
828 if (vas != VA_STATUS_SUCCESS) {
829 av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
830 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
835 err = ff_hwframe_map_create(src->hw_frames_ctx,
836 dst, src, &vaapi_unmap_frame, map);
840 dst->width = src->width;
841 dst->height = src->height;
843 for (i = 0; i < map->image.num_planes; i++) {
844 dst->data[i] = (uint8_t*)address + map->image.offsets[i];
845 dst->linesize[i] = map->image.pitches[i];
848 desc = vaapi_format_from_fourcc(map->image.format.fourcc);
849 if (desc && desc->chroma_planes_swapped) {
850 // Chroma planes are YVU rather than YUV, so swap them.
851 FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
859 vaUnmapBuffer(hwctx->display, map->image.buf);
860 if (map->image.image_id != VA_INVALID_ID)
861 vaDestroyImage(hwctx->display, map->image.image_id);
867 static int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
868 AVFrame *dst, const AVFrame *src)
873 if (dst->width > hwfc->width || dst->height > hwfc->height)
874 return AVERROR(EINVAL);
876 map = av_frame_alloc();
878 return AVERROR(ENOMEM);
879 map->format = dst->format;
881 err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
885 map->width = dst->width;
886 map->height = dst->height;
888 err = av_frame_copy(dst, map);
898 static int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
899 AVFrame *dst, const AVFrame *src)
904 if (src->width > hwfc->width || src->height > hwfc->height)
905 return AVERROR(EINVAL);
907 map = av_frame_alloc();
909 return AVERROR(ENOMEM);
910 map->format = src->format;
912 err = vaapi_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE);
916 map->width = src->width;
917 map->height = src->height;
919 err = av_frame_copy(map, src);
929 static int vaapi_map_to_memory(AVHWFramesContext *hwfc, AVFrame *dst,
930 const AVFrame *src, int flags)
934 if (dst->format != AV_PIX_FMT_NONE) {
935 err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL);
937 return AVERROR(ENOSYS);
940 err = vaapi_map_frame(hwfc, dst, src, flags);
944 err = av_frame_copy_props(dst, src);
953 #define DRM_MAP(va, layers, ...) { \
958 static const struct {
960 int nb_layer_formats;
961 uint32_t layer_formats[AV_DRM_MAX_PLANES];
962 } vaapi_drm_format_map[] = {
964 DRM_MAP(NV12, 2, DRM_FORMAT_R8, DRM_FORMAT_RG88),
966 DRM_MAP(NV12, 1, DRM_FORMAT_NV12),
967 #if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16)
968 DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
970 DRM_MAP(BGRA, 1, DRM_FORMAT_ARGB8888),
971 DRM_MAP(BGRX, 1, DRM_FORMAT_XRGB8888),
972 DRM_MAP(RGBA, 1, DRM_FORMAT_ABGR8888),
973 DRM_MAP(RGBX, 1, DRM_FORMAT_XBGR8888),
974 #ifdef VA_FOURCC_ABGR
975 DRM_MAP(ABGR, 1, DRM_FORMAT_RGBA8888),
976 DRM_MAP(XBGR, 1, DRM_FORMAT_RGBX8888),
978 DRM_MAP(ARGB, 1, DRM_FORMAT_BGRA8888),
979 DRM_MAP(XRGB, 1, DRM_FORMAT_BGRX8888),
983 static void vaapi_unmap_from_drm(AVHWFramesContext *dst_fc,
984 HWMapDescriptor *hwmap)
986 AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
988 VASurfaceID surface_id = (VASurfaceID)(uintptr_t)hwmap->priv;
990 av_log(dst_fc, AV_LOG_DEBUG, "Destroy surface %#x.\n", surface_id);
992 vaDestroySurfaces(dst_dev->display, &surface_id, 1);
995 static int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst,
996 const AVFrame *src, int flags)
998 AVHWFramesContext *dst_fc =
999 (AVHWFramesContext*)dst->hw_frames_ctx->data;
1000 AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
1001 const AVDRMFrameDescriptor *desc;
1002 const VAAPIFormatDescriptor *format_desc;
1003 VASurfaceID surface_id;
1008 unsigned long buffer_handle;
1009 VASurfaceAttribExternalBuffers buffer_desc;
1010 VASurfaceAttrib attrs[2] = {
1012 .type = VASurfaceAttribMemoryType,
1013 .flags = VA_SURFACE_ATTRIB_SETTABLE,
1014 .value.type = VAGenericValueTypeInteger,
1015 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
1018 .type = VASurfaceAttribExternalBufferDescriptor,
1019 .flags = VA_SURFACE_ATTRIB_SETTABLE,
1020 .value.type = VAGenericValueTypePointer,
1021 .value.value.p = &buffer_desc,
1025 desc = (AVDRMFrameDescriptor*)src->data[0];
1027 if (desc->nb_objects != 1) {
1028 av_log(dst_fc, AV_LOG_ERROR, "VAAPI can only map frames "
1029 "made from a single DRM object.\n");
1030 return AVERROR(EINVAL);
1034 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
1035 if (desc->nb_layers != vaapi_drm_format_map[i].nb_layer_formats)
1037 for (j = 0; j < desc->nb_layers; j++) {
1038 if (desc->layers[j].format !=
1039 vaapi_drm_format_map[i].layer_formats[j])
1042 if (j != desc->nb_layers)
1044 va_fourcc = vaapi_drm_format_map[i].va_fourcc;
1048 av_log(dst_fc, AV_LOG_ERROR, "DRM format not supported "
1050 return AVERROR(EINVAL);
1053 av_log(dst_fc, AV_LOG_DEBUG, "Map DRM object %d to VAAPI as "
1054 "%08x.\n", desc->objects[0].fd, va_fourcc);
1056 format_desc = vaapi_format_from_fourcc(va_fourcc);
1057 av_assert0(format_desc);
1059 buffer_handle = desc->objects[0].fd;
1060 buffer_desc.pixel_format = va_fourcc;
1061 buffer_desc.width = src_fc->width;
1062 buffer_desc.height = src_fc->height;
1063 buffer_desc.data_size = desc->objects[0].size;
1064 buffer_desc.buffers = &buffer_handle;
1065 buffer_desc.num_buffers = 1;
1066 buffer_desc.flags = 0;
1069 for (i = 0; i < desc->nb_layers; i++) {
1070 for (j = 0; j < desc->layers[i].nb_planes; j++) {
1071 buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch;
1072 buffer_desc.offsets[k] = desc->layers[i].planes[j].offset;
1076 buffer_desc.num_planes = k;
1078 if (format_desc->chroma_planes_swapped &&
1079 buffer_desc.num_planes == 3) {
1080 FFSWAP(uint32_t, buffer_desc.pitches[1], buffer_desc.pitches[2]);
1081 FFSWAP(uint32_t, buffer_desc.offsets[1], buffer_desc.offsets[2]);
1084 vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format,
1085 src->width, src->height,
1087 attrs, FF_ARRAY_ELEMS(attrs));
1088 if (vas != VA_STATUS_SUCCESS) {
1089 av_log(dst_fc, AV_LOG_ERROR, "Failed to create surface from DRM "
1090 "object: %d (%s).\n", vas, vaErrorStr(vas));
1091 return AVERROR(EIO);
1093 av_log(dst_fc, AV_LOG_DEBUG, "Create surface %#x.\n", surface_id);
1095 err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
1096 &vaapi_unmap_from_drm,
1097 (void*)(uintptr_t)surface_id);
1101 dst->width = src->width;
1102 dst->height = src->height;
1103 dst->data[3] = (uint8_t*)(uintptr_t)surface_id;
1105 av_log(dst_fc, AV_LOG_DEBUG, "Mapped DRM object %d to "
1106 "surface %#x.\n", desc->objects[0].fd, surface_id);
1111 #if VA_CHECK_VERSION(1, 1, 0)
1112 static void vaapi_unmap_to_drm_esh(AVHWFramesContext *hwfc,
1113 HWMapDescriptor *hwmap)
1115 AVDRMFrameDescriptor *drm_desc = hwmap->priv;
1118 for (i = 0; i < drm_desc->nb_objects; i++)
1119 close(drm_desc->objects[i].fd);
1121 av_freep(&drm_desc);
1124 static int vaapi_map_to_drm_esh(AVHWFramesContext *hwfc, AVFrame *dst,
1125 const AVFrame *src, int flags)
1127 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1128 VASurfaceID surface_id;
1130 VADRMPRIMESurfaceDescriptor va_desc;
1131 AVDRMFrameDescriptor *drm_desc = NULL;
1132 uint32_t export_flags;
1135 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
1137 export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS;
1138 if (flags & AV_HWFRAME_MAP_READ)
1139 export_flags |= VA_EXPORT_SURFACE_READ_ONLY;
1140 if (flags & AV_HWFRAME_MAP_WRITE)
1141 export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY;
1143 vas = vaExportSurfaceHandle(hwctx->display, surface_id,
1144 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
1145 export_flags, &va_desc);
1146 if (vas != VA_STATUS_SUCCESS) {
1147 if (vas == VA_STATUS_ERROR_UNIMPLEMENTED)
1148 return AVERROR(ENOSYS);
1149 av_log(hwfc, AV_LOG_ERROR, "Failed to export surface %#x: "
1150 "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
1151 return AVERROR(EIO);
1154 drm_desc = av_mallocz(sizeof(*drm_desc));
1156 err = AVERROR(ENOMEM);
1160 // By some bizarre coincidence, these structures are very similar...
1161 drm_desc->nb_objects = va_desc.num_objects;
1162 for (i = 0; i < va_desc.num_objects; i++) {
1163 drm_desc->objects[i].fd = va_desc.objects[i].fd;
1164 drm_desc->objects[i].size = va_desc.objects[i].size;
1165 drm_desc->objects[i].format_modifier =
1166 va_desc.objects[i].drm_format_modifier;
1168 drm_desc->nb_layers = va_desc.num_layers;
1169 for (i = 0; i < va_desc.num_layers; i++) {
1170 drm_desc->layers[i].format = va_desc.layers[i].drm_format;
1171 drm_desc->layers[i].nb_planes = va_desc.layers[i].num_planes;
1172 for (j = 0; j < va_desc.layers[i].num_planes; j++) {
1173 drm_desc->layers[i].planes[j].object_index =
1174 va_desc.layers[i].object_index[j];
1175 drm_desc->layers[i].planes[j].offset =
1176 va_desc.layers[i].offset[j];
1177 drm_desc->layers[i].planes[j].pitch =
1178 va_desc.layers[i].pitch[j];
1182 err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
1183 &vaapi_unmap_to_drm_esh, drm_desc);
1187 dst->width = src->width;
1188 dst->height = src->height;
1189 dst->data[0] = (uint8_t*)drm_desc;
1194 for (i = 0; i < va_desc.num_objects; i++)
1195 close(va_desc.objects[i].fd);
1196 av_freep(&drm_desc);
1201 #if VA_CHECK_VERSION(0, 36, 0)
1202 typedef struct VAAPIDRMImageBufferMapping {
1204 VABufferInfo buffer_info;
1206 AVDRMFrameDescriptor drm_desc;
1207 } VAAPIDRMImageBufferMapping;
1209 static void vaapi_unmap_to_drm_abh(AVHWFramesContext *hwfc,
1210 HWMapDescriptor *hwmap)
1212 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1213 VAAPIDRMImageBufferMapping *mapping = hwmap->priv;
1214 VASurfaceID surface_id;
1217 surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
1218 av_log(hwfc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from DRM.\n",
1221 // DRM PRIME file descriptors are closed by vaReleaseBufferHandle(),
1222 // so we shouldn't close them separately.
1224 vas = vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
1225 if (vas != VA_STATUS_SUCCESS) {
1226 av_log(hwfc, AV_LOG_ERROR, "Failed to release buffer "
1227 "handle of image %#x (derived from surface %#x): "
1228 "%d (%s).\n", mapping->image.buf, surface_id,
1229 vas, vaErrorStr(vas));
1232 vas = vaDestroyImage(hwctx->display, mapping->image.image_id);
1233 if (vas != VA_STATUS_SUCCESS) {
1234 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image "
1235 "derived from surface %#x: %d (%s).\n",
1236 surface_id, vas, vaErrorStr(vas));
1242 static int vaapi_map_to_drm_abh(AVHWFramesContext *hwfc, AVFrame *dst,
1243 const AVFrame *src, int flags)
1245 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1246 VAAPIDRMImageBufferMapping *mapping = NULL;
1247 VASurfaceID surface_id;
1251 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
1252 av_log(hwfc, AV_LOG_DEBUG, "Map VAAPI surface %#x to DRM.\n",
1255 mapping = av_mallocz(sizeof(*mapping));
1257 return AVERROR(ENOMEM);
1259 vas = vaDeriveImage(hwctx->display, surface_id,
1261 if (vas != VA_STATUS_SUCCESS) {
1262 av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
1263 "surface %#x: %d (%s).\n",
1264 surface_id, vas, vaErrorStr(vas));
1269 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
1270 if (vaapi_drm_format_map[i].va_fourcc ==
1271 mapping->image.format.fourcc)
1274 if (i >= FF_ARRAY_ELEMS(vaapi_drm_format_map)) {
1275 av_log(hwfc, AV_LOG_ERROR, "No matching DRM format for "
1276 "VAAPI format %#x.\n", mapping->image.format.fourcc);
1277 err = AVERROR(EINVAL);
1281 mapping->buffer_info.mem_type =
1282 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
1284 mapping->drm_desc.nb_layers =
1285 vaapi_drm_format_map[i].nb_layer_formats;
1286 if (mapping->drm_desc.nb_layers > 1) {
1287 if (mapping->drm_desc.nb_layers != mapping->image.num_planes) {
1288 av_log(hwfc, AV_LOG_ERROR, "Image properties do not match "
1289 "expected format: got %d planes, but expected %d.\n",
1290 mapping->image.num_planes, mapping->drm_desc.nb_layers);
1291 err = AVERROR(EINVAL);
1295 for(p = 0; p < mapping->drm_desc.nb_layers; p++) {
1296 mapping->drm_desc.layers[p] = (AVDRMLayerDescriptor) {
1297 .format = vaapi_drm_format_map[i].layer_formats[p],
1301 .offset = mapping->image.offsets[p],
1302 .pitch = mapping->image.pitches[p],
1307 mapping->drm_desc.layers[0].format =
1308 vaapi_drm_format_map[i].layer_formats[0];
1309 mapping->drm_desc.layers[0].nb_planes = mapping->image.num_planes;
1310 for (p = 0; p < mapping->image.num_planes; p++) {
1311 mapping->drm_desc.layers[0].planes[p] = (AVDRMPlaneDescriptor) {
1313 .offset = mapping->image.offsets[p],
1314 .pitch = mapping->image.pitches[p],
1319 vas = vaAcquireBufferHandle(hwctx->display, mapping->image.buf,
1320 &mapping->buffer_info);
1321 if (vas != VA_STATUS_SUCCESS) {
1322 av_log(hwfc, AV_LOG_ERROR, "Failed to get buffer "
1323 "handle from image %#x (derived from surface %#x): "
1324 "%d (%s).\n", mapping->image.buf, surface_id,
1325 vas, vaErrorStr(vas));
1330 av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n",
1331 mapping->buffer_info.handle);
1333 mapping->drm_desc.nb_objects = 1;
1334 mapping->drm_desc.objects[0] = (AVDRMObjectDescriptor) {
1335 .fd = mapping->buffer_info.handle,
1336 .size = mapping->image.data_size,
1337 // There is no way to get the format modifier with this API.
1338 .format_modifier = DRM_FORMAT_MOD_INVALID,
1341 err = ff_hwframe_map_create(src->hw_frames_ctx,
1342 dst, src, &vaapi_unmap_to_drm_abh,
1347 dst->data[0] = (uint8_t*)&mapping->drm_desc;
1348 dst->width = src->width;
1349 dst->height = src->height;
1354 vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
1356 vaDestroyImage(hwctx->display, mapping->image.image_id);
1363 static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
1364 const AVFrame *src, int flags)
1366 #if VA_CHECK_VERSION(1, 1, 0)
1368 err = vaapi_map_to_drm_esh(hwfc, dst, src, flags);
1369 if (err != AVERROR(ENOSYS))
1372 #if VA_CHECK_VERSION(0, 36, 0)
1373 return vaapi_map_to_drm_abh(hwfc, dst, src, flags);
1375 return AVERROR(ENOSYS);
1378 #endif /* CONFIG_LIBDRM */
1380 static int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
1381 const AVFrame *src, int flags)
1383 switch (src->format) {
1385 case AV_PIX_FMT_DRM_PRIME:
1386 return vaapi_map_from_drm(hwfc, dst, src, flags);
1389 return AVERROR(ENOSYS);
1393 static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
1394 const AVFrame *src, int flags)
1396 switch (dst->format) {
1398 case AV_PIX_FMT_DRM_PRIME:
1399 return vaapi_map_to_drm(hwfc, dst, src, flags);
1402 return vaapi_map_to_memory(hwfc, dst, src, flags);
1406 static void vaapi_device_free(AVHWDeviceContext *ctx)
1408 AVVAAPIDeviceContext *hwctx = ctx->hwctx;
1409 VAAPIDevicePriv *priv = ctx->user_opaque;
1412 vaTerminate(hwctx->display);
1415 if (priv->x11_display)
1416 XCloseDisplay(priv->x11_display);
1419 if (priv->drm_fd >= 0)
1420 close(priv->drm_fd);
1426 static void vaapi_device_log_error(void *context, const char *message)
1428 AVHWDeviceContext *ctx = context;
1430 av_log(ctx, AV_LOG_ERROR, "libva: %s", message);
1433 static void vaapi_device_log_info(void *context, const char *message)
1435 AVHWDeviceContext *ctx = context;
1437 av_log(ctx, AV_LOG_VERBOSE, "libva: %s", message);
1441 static int vaapi_device_connect(AVHWDeviceContext *ctx,
1444 AVVAAPIDeviceContext *hwctx = ctx->hwctx;
1449 vaSetErrorCallback(display, &vaapi_device_log_error, ctx);
1450 vaSetInfoCallback (display, &vaapi_device_log_info, ctx);
1453 hwctx->display = display;
1455 vas = vaInitialize(display, &major, &minor);
1456 if (vas != VA_STATUS_SUCCESS) {
1457 av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
1458 "connection: %d (%s).\n", vas, vaErrorStr(vas));
1459 return AVERROR(EIO);
1461 av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
1462 "version %d.%d\n", major, minor);
1467 static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
1468 AVDictionary *opts, int flags)
1470 VAAPIDevicePriv *priv;
1471 VADisplay display = NULL;
1473 priv = av_mallocz(sizeof(*priv));
1475 return AVERROR(ENOMEM);
1479 ctx->user_opaque = priv;
1480 ctx->free = vaapi_device_free;
1483 if (!display && !(device && device[0] == '/')) {
1484 // Try to open the device as an X11 display.
1485 priv->x11_display = XOpenDisplay(device);
1486 if (!priv->x11_display) {
1487 av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
1488 "%s.\n", XDisplayName(device));
1490 display = vaGetDisplay(priv->x11_display);
1492 av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
1493 "from X11 display %s.\n", XDisplayName(device));
1494 return AVERROR_UNKNOWN;
1497 av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
1498 "X11 display %s.\n", XDisplayName(device));
1505 // Try to open the device as a DRM path.
1506 // Default to using the first render node if the user did not
1508 const char *path = device ? device : "/dev/dri/renderD128";
1509 priv->drm_fd = open(path, O_RDWR);
1510 if (priv->drm_fd < 0) {
1511 av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n",
1514 display = vaGetDisplayDRM(priv->drm_fd);
1516 av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
1517 "from DRM device %s.\n", path);
1518 return AVERROR_UNKNOWN;
1521 av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
1522 "DRM device %s.\n", path);
1528 av_log(ctx, AV_LOG_ERROR, "No VA display found for "
1529 "device: %s.\n", device ? device : "");
1530 return AVERROR(EINVAL);
1533 return vaapi_device_connect(ctx, display);
1536 static int vaapi_device_derive(AVHWDeviceContext *ctx,
1537 AVHWDeviceContext *src_ctx, int flags)
1540 if (src_ctx->type == AV_HWDEVICE_TYPE_DRM) {
1541 AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
1543 VAAPIDevicePriv *priv;
1545 if (src_hwctx->fd < 0) {
1546 av_log(ctx, AV_LOG_ERROR, "DRM instance requires an associated "
1547 "device to derive a VA display from.\n");
1548 return AVERROR(EINVAL);
1551 priv = av_mallocz(sizeof(*priv));
1553 return AVERROR(ENOMEM);
1555 // Inherits the fd from the source context, which will close it.
1558 ctx->user_opaque = priv;
1559 ctx->free = &vaapi_device_free;
1561 display = vaGetDisplayDRM(src_hwctx->fd);
1563 av_log(ctx, AV_LOG_ERROR, "Failed to open a VA display from "
1565 return AVERROR(EIO);
1568 return vaapi_device_connect(ctx, display);
1571 return AVERROR(ENOSYS);
1574 const HWContextType ff_hwcontext_type_vaapi = {
1575 .type = AV_HWDEVICE_TYPE_VAAPI,
1578 .device_hwctx_size = sizeof(AVVAAPIDeviceContext),
1579 .device_priv_size = sizeof(VAAPIDeviceContext),
1580 .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
1581 .frames_hwctx_size = sizeof(AVVAAPIFramesContext),
1582 .frames_priv_size = sizeof(VAAPIFramesContext),
1584 .device_create = &vaapi_device_create,
1585 .device_derive = &vaapi_device_derive,
1586 .device_init = &vaapi_device_init,
1587 .device_uninit = &vaapi_device_uninit,
1588 .frames_get_constraints = &vaapi_frames_get_constraints,
1589 .frames_init = &vaapi_frames_init,
1590 .frames_uninit = &vaapi_frames_uninit,
1591 .frames_get_buffer = &vaapi_get_buffer,
1592 .transfer_get_formats = &vaapi_transfer_get_formats,
1593 .transfer_data_to = &vaapi_transfer_data_to,
1594 .transfer_data_from = &vaapi_transfer_data_from,
1595 .map_to = &vaapi_map_to,
1596 .map_from = &vaapi_map_from,
1598 .pix_fmts = (const enum AVPixelFormat[]) {