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[] = {
283 "Intel i965 (Quick Sync)",
285 AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS,
290 AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE,
294 "Splitted-Desktop Systems VDPAU backend for VA-API",
295 AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES,
299 static int vaapi_device_init(AVHWDeviceContext *hwdev)
301 VAAPIDeviceContext *ctx = hwdev->internal->priv;
302 AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
303 VAImageFormat *image_list = NULL;
305 const char *vendor_string;
306 int err, i, image_count;
307 enum AVPixelFormat pix_fmt;
310 image_count = vaMaxNumImageFormats(hwctx->display);
311 if (image_count <= 0) {
315 image_list = av_malloc(image_count * sizeof(*image_list));
317 err = AVERROR(ENOMEM);
320 vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
321 if (vas != VA_STATUS_SUCCESS) {
326 ctx->formats = av_malloc(image_count * sizeof(*ctx->formats));
328 err = AVERROR(ENOMEM);
332 for (i = 0; i < image_count; i++) {
333 fourcc = image_list[i].fourcc;
334 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
335 if (pix_fmt == AV_PIX_FMT_NONE) {
336 av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n",
339 av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",
340 fourcc, av_get_pix_fmt_name(pix_fmt));
341 ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt;
342 ctx->formats[ctx->nb_formats].image_format = image_list[i];
347 if (hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_USER_SET) {
348 av_log(hwdev, AV_LOG_VERBOSE, "Not detecting driver: "
349 "quirks set by user.\n");
351 // Detect the driver in use and set quirk flags if necessary.
352 vendor_string = vaQueryVendorString(hwctx->display);
353 hwctx->driver_quirks = 0;
355 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) {
356 if (strstr(vendor_string,
357 vaapi_driver_quirks_table[i].match_string)) {
358 av_log(hwdev, AV_LOG_VERBOSE, "Matched \"%s\" as known "
359 "driver \"%s\".\n", vendor_string,
360 vaapi_driver_quirks_table[i].friendly_name);
361 hwctx->driver_quirks |=
362 vaapi_driver_quirks_table[i].quirks;
366 if (!(i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table))) {
367 av_log(hwdev, AV_LOG_VERBOSE, "Unknown driver \"%s\", "
368 "assuming standard behaviour.\n", vendor_string);
376 av_freep(&ctx->formats);
381 static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
383 VAAPIDeviceContext *ctx = hwdev->internal->priv;
385 av_freep(&ctx->formats);
388 static void vaapi_buffer_free(void *opaque, uint8_t *data)
390 AVHWFramesContext *hwfc = opaque;
391 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
392 VASurfaceID surface_id;
395 surface_id = (VASurfaceID)(uintptr_t)data;
397 vas = vaDestroySurfaces(hwctx->display, &surface_id, 1);
398 if (vas != VA_STATUS_SUCCESS) {
399 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: "
400 "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
404 static AVBufferRef *vaapi_pool_alloc(void *opaque, int size)
406 AVHWFramesContext *hwfc = opaque;
407 VAAPIFramesContext *ctx = hwfc->internal->priv;
408 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
409 AVVAAPIFramesContext *avfc = hwfc->hwctx;
410 VASurfaceID surface_id;
414 if (hwfc->initial_pool_size > 0 &&
415 avfc->nb_surfaces >= hwfc->initial_pool_size)
418 vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
419 hwfc->width, hwfc->height,
421 ctx->attributes, ctx->nb_attributes);
422 if (vas != VA_STATUS_SUCCESS) {
423 av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
424 "%d (%s).\n", vas, vaErrorStr(vas));
427 av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
429 ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
430 sizeof(surface_id), &vaapi_buffer_free,
431 hwfc, AV_BUFFER_FLAG_READONLY);
433 vaDestroySurfaces(hwctx->display, &surface_id, 1);
437 if (hwfc->initial_pool_size > 0) {
438 // This is a fixed-size pool, so we must still be in the initial
439 // allocation sequence.
440 av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size);
441 avfc->surface_ids[avfc->nb_surfaces] = surface_id;
448 static int vaapi_frames_init(AVHWFramesContext *hwfc)
450 AVVAAPIFramesContext *avfc = hwfc->hwctx;
451 VAAPIFramesContext *ctx = hwfc->internal->priv;
452 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
453 VAImageFormat *expected_format;
454 AVBufferRef *test_surface = NULL;
455 VASurfaceID test_surface_id;
459 unsigned int fourcc, rt_format;
461 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
462 if (vaapi_format_map[i].pix_fmt == hwfc->sw_format) {
463 fourcc = vaapi_format_map[i].fourcc;
464 rt_format = vaapi_format_map[i].rt_format;
468 if (i >= FF_ARRAY_ELEMS(vaapi_format_map)) {
469 av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
470 av_get_pix_fmt_name(hwfc->sw_format));
471 return AVERROR(EINVAL);
475 if (!(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {
476 int need_memory_type = !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE);
477 int need_pixel_format = 1;
478 for (i = 0; i < avfc->nb_attributes; i++) {
479 if (avfc->attributes[i].type == VASurfaceAttribMemoryType)
480 need_memory_type = 0;
481 if (avfc->attributes[i].type == VASurfaceAttribPixelFormat)
482 need_pixel_format = 0;
485 avfc->nb_attributes + need_memory_type + need_pixel_format;
487 ctx->attributes = av_malloc(ctx->nb_attributes *
488 sizeof(*ctx->attributes));
489 if (!ctx->attributes) {
490 err = AVERROR(ENOMEM);
494 for (i = 0; i < avfc->nb_attributes; i++)
495 ctx->attributes[i] = avfc->attributes[i];
496 if (need_memory_type) {
497 ctx->attributes[i++] = (VASurfaceAttrib) {
498 .type = VASurfaceAttribMemoryType,
499 .flags = VA_SURFACE_ATTRIB_SETTABLE,
500 .value.type = VAGenericValueTypeInteger,
501 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
504 if (need_pixel_format) {
505 ctx->attributes[i++] = (VASurfaceAttrib) {
506 .type = VASurfaceAttribPixelFormat,
507 .flags = VA_SURFACE_ATTRIB_SETTABLE,
508 .value.type = VAGenericValueTypeInteger,
509 .value.value.i = fourcc,
512 av_assert0(i == ctx->nb_attributes);
514 ctx->attributes = NULL;
515 ctx->nb_attributes = 0;
518 ctx->rt_format = rt_format;
520 if (hwfc->initial_pool_size > 0) {
521 // This pool will be usable as a render target, so we need to store
522 // all of the surface IDs somewhere that vaCreateContext() calls
523 // will be able to access them.
524 avfc->nb_surfaces = 0;
525 avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
526 sizeof(*avfc->surface_ids));
527 if (!avfc->surface_ids) {
528 err = AVERROR(ENOMEM);
532 // This pool allows dynamic sizing, and will not be usable as a
534 avfc->nb_surfaces = 0;
535 avfc->surface_ids = NULL;
538 hwfc->internal->pool_internal =
539 av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
540 &vaapi_pool_alloc, NULL);
541 if (!hwfc->internal->pool_internal) {
542 av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
543 err = AVERROR(ENOMEM);
548 // Allocate a single surface to test whether vaDeriveImage() is going
549 // to work for the specific configuration.
551 test_surface = av_buffer_pool_get(hwfc->pool);
553 av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
554 "user-configured buffer pool.\n");
555 err = AVERROR(ENOMEM);
559 test_surface = av_buffer_pool_get(hwfc->internal->pool_internal);
561 av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
562 "internal buffer pool.\n");
563 err = AVERROR(ENOMEM);
567 test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
569 ctx->derive_works = 0;
571 err = vaapi_get_image_format(hwfc->device_ctx,
572 hwfc->sw_format, &expected_format);
574 vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
575 if (vas == VA_STATUS_SUCCESS) {
576 if (expected_format->fourcc == test_image.format.fourcc) {
577 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
578 ctx->derive_works = 1;
580 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
581 "derived image format %08x does not match "
582 "expected format %08x.\n",
583 expected_format->fourcc, test_image.format.fourcc);
585 vaDestroyImage(hwctx->display, test_image.image_id);
587 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
588 "deriving image does not work: "
589 "%d (%s).\n", vas, vaErrorStr(vas));
592 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
593 "image format is not supported.\n");
596 av_buffer_unref(&test_surface);
600 av_buffer_unref(&test_surface);
601 av_freep(&avfc->surface_ids);
602 av_freep(&ctx->attributes);
606 static void vaapi_frames_uninit(AVHWFramesContext *hwfc)
608 AVVAAPIFramesContext *avfc = hwfc->hwctx;
609 VAAPIFramesContext *ctx = hwfc->internal->priv;
611 av_freep(&avfc->surface_ids);
612 av_freep(&ctx->attributes);
615 static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
617 frame->buf[0] = av_buffer_pool_get(hwfc->pool);
619 return AVERROR(ENOMEM);
621 frame->data[3] = frame->buf[0]->data;
622 frame->format = AV_PIX_FMT_VAAPI;
623 frame->width = hwfc->width;
624 frame->height = hwfc->height;
629 static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc,
630 enum AVHWFrameTransferDirection dir,
631 enum AVPixelFormat **formats)
633 VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv;
634 enum AVPixelFormat *pix_fmts;
635 int i, k, sw_format_available;
637 sw_format_available = 0;
638 for (i = 0; i < ctx->nb_formats; i++) {
639 if (ctx->formats[i].pix_fmt == hwfc->sw_format)
640 sw_format_available = 1;
643 pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
645 return AVERROR(ENOMEM);
647 if (sw_format_available) {
648 pix_fmts[0] = hwfc->sw_format;
653 for (i = 0; i < ctx->nb_formats; i++) {
654 if (ctx->formats[i].pix_fmt == hwfc->sw_format)
656 av_assert0(k < ctx->nb_formats);
657 pix_fmts[k++] = ctx->formats[i].pix_fmt;
659 pix_fmts[k] = AV_PIX_FMT_NONE;
665 static void vaapi_unmap_frame(AVHWFramesContext *hwfc,
666 HWMapDescriptor *hwmap)
668 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
669 VAAPIMapping *map = hwmap->priv;
670 VASurfaceID surface_id;
673 surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
674 av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
676 vas = vaUnmapBuffer(hwctx->display, map->image.buf);
677 if (vas != VA_STATUS_SUCCESS) {
678 av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
679 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
682 if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
683 !(map->flags & AV_HWFRAME_MAP_DIRECT)) {
684 vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
685 0, 0, hwfc->width, hwfc->height,
686 0, 0, hwfc->width, hwfc->height);
687 if (vas != VA_STATUS_SUCCESS) {
688 av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
689 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
693 vas = vaDestroyImage(hwctx->display, map->image.image_id);
694 if (vas != VA_STATUS_SUCCESS) {
695 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
696 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
702 static int vaapi_map_frame(AVHWFramesContext *hwfc,
703 AVFrame *dst, const AVFrame *src, int flags)
705 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
706 VAAPIFramesContext *ctx = hwfc->internal->priv;
707 VASurfaceID surface_id;
708 VAImageFormat *image_format;
711 void *address = NULL;
714 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
715 av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
717 if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) {
718 // Requested direct mapping but it is not possible.
719 return AVERROR(EINVAL);
721 if (dst->format == AV_PIX_FMT_NONE)
722 dst->format = hwfc->sw_format;
723 if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) {
724 // Requested direct mapping but the formats do not match.
725 return AVERROR(EINVAL);
728 err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
730 // Requested format is not a valid output format.
731 return AVERROR(EINVAL);
734 map = av_malloc(sizeof(*map));
736 return AVERROR(ENOMEM);
738 map->image.image_id = VA_INVALID_ID;
740 vas = vaSyncSurface(hwctx->display, surface_id);
741 if (vas != VA_STATUS_SUCCESS) {
742 av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
743 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
748 // The memory which we map using derive need not be connected to the CPU
749 // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
750 // memory is mappable but not cached, so normal memcpy()-like access is
751 // very slow to read it (but writing is ok). It is possible to read much
752 // faster with a copy routine which is aware of the limitation, but we
753 // assume for now that the user is not aware of that and would therefore
754 // prefer not to be given direct-mapped memory if they request read access.
755 if (ctx->derive_works && dst->format == hwfc->sw_format &&
756 ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) {
757 vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
758 if (vas != VA_STATUS_SUCCESS) {
759 av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
760 "surface %#x: %d (%s).\n",
761 surface_id, vas, vaErrorStr(vas));
765 if (map->image.format.fourcc != image_format->fourcc) {
766 av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
767 "is in wrong format: expected %#08x, got %#08x.\n",
768 surface_id, image_format->fourcc, map->image.format.fourcc);
772 map->flags |= AV_HWFRAME_MAP_DIRECT;
774 vas = vaCreateImage(hwctx->display, image_format,
775 hwfc->width, hwfc->height, &map->image);
776 if (vas != VA_STATUS_SUCCESS) {
777 av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
778 "surface %#x: %d (%s).\n",
779 surface_id, vas, vaErrorStr(vas));
783 if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) {
784 vas = vaGetImage(hwctx->display, surface_id, 0, 0,
785 hwfc->width, hwfc->height, map->image.image_id);
786 if (vas != VA_STATUS_SUCCESS) {
787 av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
788 "surface %#x: %d (%s).\n",
789 surface_id, vas, vaErrorStr(vas));
796 vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
797 if (vas != VA_STATUS_SUCCESS) {
798 av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
799 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
804 err = ff_hwframe_map_create(src->hw_frames_ctx,
805 dst, src, &vaapi_unmap_frame, map);
809 dst->width = src->width;
810 dst->height = src->height;
812 for (i = 0; i < map->image.num_planes; i++) {
813 dst->data[i] = (uint8_t*)address + map->image.offsets[i];
814 dst->linesize[i] = map->image.pitches[i];
817 #ifdef VA_FOURCC_YV16
818 map->image.format.fourcc == VA_FOURCC_YV16 ||
820 map->image.format.fourcc == VA_FOURCC_YV12) {
821 // Chroma planes are YVU rather than YUV, so swap them.
822 FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
830 vaUnmapBuffer(hwctx->display, map->image.buf);
831 if (map->image.image_id != VA_INVALID_ID)
832 vaDestroyImage(hwctx->display, map->image.image_id);
838 static int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
839 AVFrame *dst, const AVFrame *src)
844 if (dst->width > hwfc->width || dst->height > hwfc->height)
845 return AVERROR(EINVAL);
847 map = av_frame_alloc();
849 return AVERROR(ENOMEM);
850 map->format = dst->format;
852 err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
856 map->width = dst->width;
857 map->height = dst->height;
859 err = av_frame_copy(dst, map);
869 static int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
870 AVFrame *dst, const AVFrame *src)
875 if (src->width > hwfc->width || src->height > hwfc->height)
876 return AVERROR(EINVAL);
878 map = av_frame_alloc();
880 return AVERROR(ENOMEM);
881 map->format = src->format;
883 err = vaapi_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE);
887 map->width = src->width;
888 map->height = src->height;
890 err = av_frame_copy(map, src);
900 static int vaapi_map_to_memory(AVHWFramesContext *hwfc, AVFrame *dst,
901 const AVFrame *src, int flags)
905 if (dst->format != AV_PIX_FMT_NONE) {
906 err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL);
908 return AVERROR(ENOSYS);
911 err = vaapi_map_frame(hwfc, dst, src, flags);
915 err = av_frame_copy_props(dst, src);
924 #define DRM_MAP(va, layers, ...) { \
929 static const struct {
931 int nb_layer_formats;
932 uint32_t layer_formats[AV_DRM_MAX_PLANES];
933 } vaapi_drm_format_map[] = {
935 DRM_MAP(NV12, 2, DRM_FORMAT_R8, DRM_FORMAT_RG88),
937 DRM_MAP(NV12, 1, DRM_FORMAT_NV12),
938 #if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16)
939 DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
941 DRM_MAP(BGRA, 1, DRM_FORMAT_ARGB8888),
942 DRM_MAP(BGRX, 1, DRM_FORMAT_XRGB8888),
943 DRM_MAP(RGBA, 1, DRM_FORMAT_ABGR8888),
944 DRM_MAP(RGBX, 1, DRM_FORMAT_XBGR8888),
945 #ifdef VA_FOURCC_ABGR
946 DRM_MAP(ABGR, 1, DRM_FORMAT_RGBA8888),
947 DRM_MAP(XBGR, 1, DRM_FORMAT_RGBX8888),
949 DRM_MAP(ARGB, 1, DRM_FORMAT_BGRA8888),
950 DRM_MAP(XRGB, 1, DRM_FORMAT_BGRX8888),
954 static void vaapi_unmap_from_drm(AVHWFramesContext *dst_fc,
955 HWMapDescriptor *hwmap)
957 AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
959 VASurfaceID surface_id = (VASurfaceID)(uintptr_t)hwmap->priv;
961 av_log(dst_fc, AV_LOG_DEBUG, "Destroy surface %#x.\n", surface_id);
963 vaDestroySurfaces(dst_dev->display, &surface_id, 1);
966 static int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst,
967 const AVFrame *src, int flags)
969 AVHWFramesContext *dst_fc =
970 (AVHWFramesContext*)dst->hw_frames_ctx->data;
971 AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
972 const AVDRMFrameDescriptor *desc;
973 VASurfaceID surface_id;
975 uint32_t va_fourcc, va_rt_format;
978 unsigned long buffer_handle;
979 VASurfaceAttribExternalBuffers buffer_desc;
980 VASurfaceAttrib attrs[2] = {
982 .type = VASurfaceAttribMemoryType,
983 .flags = VA_SURFACE_ATTRIB_SETTABLE,
984 .value.type = VAGenericValueTypeInteger,
985 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
988 .type = VASurfaceAttribExternalBufferDescriptor,
989 .flags = VA_SURFACE_ATTRIB_SETTABLE,
990 .value.type = VAGenericValueTypePointer,
991 .value.value.p = &buffer_desc,
995 desc = (AVDRMFrameDescriptor*)src->data[0];
997 if (desc->nb_objects != 1) {
998 av_log(dst_fc, AV_LOG_ERROR, "VAAPI can only map frames "
999 "made from a single DRM object.\n");
1000 return AVERROR(EINVAL);
1004 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
1005 if (desc->nb_layers != vaapi_drm_format_map[i].nb_layer_formats)
1007 for (j = 0; j < desc->nb_layers; j++) {
1008 if (desc->layers[j].format !=
1009 vaapi_drm_format_map[i].layer_formats[j])
1012 if (j != desc->nb_layers)
1014 va_fourcc = vaapi_drm_format_map[i].va_fourcc;
1018 av_log(dst_fc, AV_LOG_ERROR, "DRM format not supported "
1020 return AVERROR(EINVAL);
1023 av_log(dst_fc, AV_LOG_DEBUG, "Map DRM object %d to VAAPI as "
1024 "%08x.\n", desc->objects[0].fd, va_fourcc);
1026 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
1027 if (vaapi_format_map[i].fourcc == va_fourcc) {
1028 va_rt_format = vaapi_format_map[i].rt_format;
1033 av_assert0(i < FF_ARRAY_ELEMS(vaapi_format_map));
1035 buffer_handle = desc->objects[0].fd;
1036 buffer_desc.pixel_format = va_fourcc;
1037 buffer_desc.width = src_fc->width;
1038 buffer_desc.height = src_fc->height;
1039 buffer_desc.data_size = desc->objects[0].size;
1040 buffer_desc.buffers = &buffer_handle;
1041 buffer_desc.num_buffers = 1;
1042 buffer_desc.flags = 0;
1045 for (i = 0; i < desc->nb_layers; i++) {
1046 for (j = 0; j < desc->layers[i].nb_planes; j++) {
1047 buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch;
1048 buffer_desc.offsets[k] = desc->layers[i].planes[j].offset;
1052 buffer_desc.num_planes = k;
1054 vas = vaCreateSurfaces(dst_dev->display, va_rt_format,
1055 src->width, src->height,
1057 attrs, FF_ARRAY_ELEMS(attrs));
1058 if (vas != VA_STATUS_SUCCESS) {
1059 av_log(dst_fc, AV_LOG_ERROR, "Failed to create surface from DRM "
1060 "object: %d (%s).\n", vas, vaErrorStr(vas));
1061 return AVERROR(EIO);
1063 av_log(dst_fc, AV_LOG_DEBUG, "Create surface %#x.\n", surface_id);
1065 err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
1066 &vaapi_unmap_from_drm,
1067 (void*)(uintptr_t)surface_id);
1071 dst->width = src->width;
1072 dst->height = src->height;
1073 dst->data[3] = (uint8_t*)(uintptr_t)surface_id;
1075 av_log(dst_fc, AV_LOG_DEBUG, "Mapped DRM object %d to "
1076 "surface %#x.\n", desc->objects[0].fd, surface_id);
1081 #if VA_CHECK_VERSION(1, 1, 0)
1082 static void vaapi_unmap_to_drm_esh(AVHWFramesContext *hwfc,
1083 HWMapDescriptor *hwmap)
1085 AVDRMFrameDescriptor *drm_desc = hwmap->priv;
1088 for (i = 0; i < drm_desc->nb_objects; i++)
1089 close(drm_desc->objects[i].fd);
1091 av_freep(&drm_desc);
1094 static int vaapi_map_to_drm_esh(AVHWFramesContext *hwfc, AVFrame *dst,
1095 const AVFrame *src, int flags)
1097 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1098 VASurfaceID surface_id;
1100 VADRMPRIMESurfaceDescriptor va_desc;
1101 AVDRMFrameDescriptor *drm_desc = NULL;
1102 uint32_t export_flags;
1105 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
1107 export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS;
1108 if (flags & AV_HWFRAME_MAP_READ)
1109 export_flags |= VA_EXPORT_SURFACE_READ_ONLY;
1110 if (flags & AV_HWFRAME_MAP_WRITE)
1111 export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY;
1113 vas = vaExportSurfaceHandle(hwctx->display, surface_id,
1114 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
1115 export_flags, &va_desc);
1116 if (vas != VA_STATUS_SUCCESS) {
1117 if (vas == VA_STATUS_ERROR_UNIMPLEMENTED)
1118 return AVERROR(ENOSYS);
1119 av_log(hwfc, AV_LOG_ERROR, "Failed to export surface %#x: "
1120 "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
1121 return AVERROR(EIO);
1124 drm_desc = av_mallocz(sizeof(*drm_desc));
1126 err = AVERROR(ENOMEM);
1130 // By some bizarre coincidence, these structures are very similar...
1131 drm_desc->nb_objects = va_desc.num_objects;
1132 for (i = 0; i < va_desc.num_objects; i++) {
1133 drm_desc->objects[i].fd = va_desc.objects[i].fd;
1134 drm_desc->objects[i].size = va_desc.objects[i].size;
1135 drm_desc->objects[i].format_modifier =
1136 va_desc.objects[i].drm_format_modifier;
1138 drm_desc->nb_layers = va_desc.num_layers;
1139 for (i = 0; i < va_desc.num_layers; i++) {
1140 drm_desc->layers[i].format = va_desc.layers[i].drm_format;
1141 drm_desc->layers[i].nb_planes = va_desc.layers[i].num_planes;
1142 for (j = 0; j < va_desc.layers[i].num_planes; j++) {
1143 drm_desc->layers[i].planes[j].object_index =
1144 va_desc.layers[i].object_index[j];
1145 drm_desc->layers[i].planes[j].offset =
1146 va_desc.layers[i].offset[j];
1147 drm_desc->layers[i].planes[j].pitch =
1148 va_desc.layers[i].pitch[j];
1152 err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
1153 &vaapi_unmap_to_drm_esh, drm_desc);
1157 dst->width = src->width;
1158 dst->height = src->height;
1159 dst->data[0] = (uint8_t*)drm_desc;
1164 for (i = 0; i < va_desc.num_objects; i++)
1165 close(va_desc.objects[i].fd);
1166 av_freep(&drm_desc);
1171 #if VA_CHECK_VERSION(0, 36, 0)
1172 typedef struct VAAPIDRMImageBufferMapping {
1174 VABufferInfo buffer_info;
1176 AVDRMFrameDescriptor drm_desc;
1177 } VAAPIDRMImageBufferMapping;
1179 static void vaapi_unmap_to_drm_abh(AVHWFramesContext *hwfc,
1180 HWMapDescriptor *hwmap)
1182 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1183 VAAPIDRMImageBufferMapping *mapping = hwmap->priv;
1184 VASurfaceID surface_id;
1187 surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
1188 av_log(hwfc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from DRM.\n",
1191 // DRM PRIME file descriptors are closed by vaReleaseBufferHandle(),
1192 // so we shouldn't close them separately.
1194 vas = vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
1195 if (vas != VA_STATUS_SUCCESS) {
1196 av_log(hwfc, AV_LOG_ERROR, "Failed to release buffer "
1197 "handle of image %#x (derived from surface %#x): "
1198 "%d (%s).\n", mapping->image.buf, surface_id,
1199 vas, vaErrorStr(vas));
1202 vas = vaDestroyImage(hwctx->display, mapping->image.image_id);
1203 if (vas != VA_STATUS_SUCCESS) {
1204 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image "
1205 "derived from surface %#x: %d (%s).\n",
1206 surface_id, vas, vaErrorStr(vas));
1212 static int vaapi_map_to_drm_abh(AVHWFramesContext *hwfc, AVFrame *dst,
1213 const AVFrame *src, int flags)
1215 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1216 VAAPIDRMImageBufferMapping *mapping = NULL;
1217 VASurfaceID surface_id;
1221 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
1222 av_log(hwfc, AV_LOG_DEBUG, "Map VAAPI surface %#x to DRM.\n",
1225 mapping = av_mallocz(sizeof(*mapping));
1227 return AVERROR(ENOMEM);
1229 vas = vaDeriveImage(hwctx->display, surface_id,
1231 if (vas != VA_STATUS_SUCCESS) {
1232 av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
1233 "surface %#x: %d (%s).\n",
1234 surface_id, vas, vaErrorStr(vas));
1239 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
1240 if (vaapi_drm_format_map[i].va_fourcc ==
1241 mapping->image.format.fourcc)
1244 if (i >= FF_ARRAY_ELEMS(vaapi_drm_format_map)) {
1245 av_log(hwfc, AV_LOG_ERROR, "No matching DRM format for "
1246 "VAAPI format %#x.\n", mapping->image.format.fourcc);
1247 err = AVERROR(EINVAL);
1251 mapping->buffer_info.mem_type =
1252 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
1254 mapping->drm_desc.nb_layers =
1255 vaapi_drm_format_map[i].nb_layer_formats;
1256 if (mapping->drm_desc.nb_layers > 1) {
1257 if (mapping->drm_desc.nb_layers != mapping->image.num_planes) {
1258 av_log(hwfc, AV_LOG_ERROR, "Image properties do not match "
1259 "expected format: got %d planes, but expected %d.\n",
1260 mapping->image.num_planes, mapping->drm_desc.nb_layers);
1261 err = AVERROR(EINVAL);
1265 for(p = 0; p < mapping->drm_desc.nb_layers; p++) {
1266 mapping->drm_desc.layers[p] = (AVDRMLayerDescriptor) {
1267 .format = vaapi_drm_format_map[i].layer_formats[p],
1271 .offset = mapping->image.offsets[p],
1272 .pitch = mapping->image.pitches[p],
1277 mapping->drm_desc.layers[0].format =
1278 vaapi_drm_format_map[i].layer_formats[0];
1279 mapping->drm_desc.layers[0].nb_planes = mapping->image.num_planes;
1280 for (p = 0; p < mapping->image.num_planes; p++) {
1281 mapping->drm_desc.layers[0].planes[p] = (AVDRMPlaneDescriptor) {
1283 .offset = mapping->image.offsets[p],
1284 .pitch = mapping->image.pitches[p],
1289 vas = vaAcquireBufferHandle(hwctx->display, mapping->image.buf,
1290 &mapping->buffer_info);
1291 if (vas != VA_STATUS_SUCCESS) {
1292 av_log(hwfc, AV_LOG_ERROR, "Failed to get buffer "
1293 "handle from image %#x (derived from surface %#x): "
1294 "%d (%s).\n", mapping->image.buf, surface_id,
1295 vas, vaErrorStr(vas));
1300 av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n",
1301 mapping->buffer_info.handle);
1303 mapping->drm_desc.nb_objects = 1;
1304 mapping->drm_desc.objects[0] = (AVDRMObjectDescriptor) {
1305 .fd = mapping->buffer_info.handle,
1306 .size = mapping->image.data_size,
1307 // There is no way to get the format modifier with this API.
1308 .format_modifier = DRM_FORMAT_MOD_INVALID,
1311 err = ff_hwframe_map_create(src->hw_frames_ctx,
1312 dst, src, &vaapi_unmap_to_drm_abh,
1317 dst->data[0] = (uint8_t*)&mapping->drm_desc;
1318 dst->width = src->width;
1319 dst->height = src->height;
1324 vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
1326 vaDestroyImage(hwctx->display, mapping->image.image_id);
1333 static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
1334 const AVFrame *src, int flags)
1336 #if VA_CHECK_VERSION(1, 1, 0)
1338 err = vaapi_map_to_drm_esh(hwfc, dst, src, flags);
1339 if (err != AVERROR(ENOSYS))
1342 #if VA_CHECK_VERSION(0, 36, 0)
1343 return vaapi_map_to_drm_abh(hwfc, dst, src, flags);
1345 return AVERROR(ENOSYS);
1348 #endif /* CONFIG_LIBDRM */
1350 static int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
1351 const AVFrame *src, int flags)
1353 switch (src->format) {
1355 case AV_PIX_FMT_DRM_PRIME:
1356 return vaapi_map_from_drm(hwfc, dst, src, flags);
1359 return AVERROR(ENOSYS);
1363 static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
1364 const AVFrame *src, int flags)
1366 switch (dst->format) {
1368 case AV_PIX_FMT_DRM_PRIME:
1369 return vaapi_map_to_drm(hwfc, dst, src, flags);
1372 return vaapi_map_to_memory(hwfc, dst, src, flags);
1376 static void vaapi_device_free(AVHWDeviceContext *ctx)
1378 AVVAAPIDeviceContext *hwctx = ctx->hwctx;
1379 VAAPIDevicePriv *priv = ctx->user_opaque;
1382 vaTerminate(hwctx->display);
1385 if (priv->x11_display)
1386 XCloseDisplay(priv->x11_display);
1389 if (priv->drm_fd >= 0)
1390 close(priv->drm_fd);
1396 static void vaapi_device_log_error(void *context, const char *message)
1398 AVHWDeviceContext *ctx = context;
1400 av_log(ctx, AV_LOG_ERROR, "libva: %s", message);
1403 static void vaapi_device_log_info(void *context, const char *message)
1405 AVHWDeviceContext *ctx = context;
1407 av_log(ctx, AV_LOG_VERBOSE, "libva: %s", message);
1411 static int vaapi_device_connect(AVHWDeviceContext *ctx,
1414 AVVAAPIDeviceContext *hwctx = ctx->hwctx;
1419 vaSetErrorCallback(display, &vaapi_device_log_error, ctx);
1420 vaSetInfoCallback (display, &vaapi_device_log_info, ctx);
1423 hwctx->display = display;
1425 vas = vaInitialize(display, &major, &minor);
1426 if (vas != VA_STATUS_SUCCESS) {
1427 av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
1428 "connection: %d (%s).\n", vas, vaErrorStr(vas));
1429 return AVERROR(EIO);
1431 av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
1432 "version %d.%d\n", major, minor);
1437 static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
1438 AVDictionary *opts, int flags)
1440 VAAPIDevicePriv *priv;
1441 VADisplay display = NULL;
1443 priv = av_mallocz(sizeof(*priv));
1445 return AVERROR(ENOMEM);
1449 ctx->user_opaque = priv;
1450 ctx->free = vaapi_device_free;
1453 if (!display && !(device && device[0] == '/')) {
1454 // Try to open the device as an X11 display.
1455 priv->x11_display = XOpenDisplay(device);
1456 if (!priv->x11_display) {
1457 av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
1458 "%s.\n", XDisplayName(device));
1460 display = vaGetDisplay(priv->x11_display);
1462 av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
1463 "from X11 display %s.\n", XDisplayName(device));
1464 return AVERROR_UNKNOWN;
1467 av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
1468 "X11 display %s.\n", XDisplayName(device));
1475 // Try to open the device as a DRM path.
1476 // Default to using the first render node if the user did not
1478 const char *path = device ? device : "/dev/dri/renderD128";
1479 priv->drm_fd = open(path, O_RDWR);
1480 if (priv->drm_fd < 0) {
1481 av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n",
1484 display = vaGetDisplayDRM(priv->drm_fd);
1486 av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
1487 "from DRM device %s.\n", path);
1488 return AVERROR_UNKNOWN;
1491 av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
1492 "DRM device %s.\n", path);
1498 av_log(ctx, AV_LOG_ERROR, "No VA display found for "
1499 "device: %s.\n", device ? device : "");
1500 return AVERROR(EINVAL);
1503 return vaapi_device_connect(ctx, display);
1506 static int vaapi_device_derive(AVHWDeviceContext *ctx,
1507 AVHWDeviceContext *src_ctx, int flags)
1510 if (src_ctx->type == AV_HWDEVICE_TYPE_DRM) {
1511 AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
1513 VAAPIDevicePriv *priv;
1515 if (src_hwctx->fd < 0) {
1516 av_log(ctx, AV_LOG_ERROR, "DRM instance requires an associated "
1517 "device to derive a VA display from.\n");
1518 return AVERROR(EINVAL);
1521 priv = av_mallocz(sizeof(*priv));
1523 return AVERROR(ENOMEM);
1525 // Inherits the fd from the source context, which will close it.
1528 ctx->user_opaque = priv;
1529 ctx->free = &vaapi_device_free;
1531 display = vaGetDisplayDRM(src_hwctx->fd);
1533 av_log(ctx, AV_LOG_ERROR, "Failed to open a VA display from "
1535 return AVERROR(EIO);
1538 return vaapi_device_connect(ctx, display);
1541 return AVERROR(ENOSYS);
1544 const HWContextType ff_hwcontext_type_vaapi = {
1545 .type = AV_HWDEVICE_TYPE_VAAPI,
1548 .device_hwctx_size = sizeof(AVVAAPIDeviceContext),
1549 .device_priv_size = sizeof(VAAPIDeviceContext),
1550 .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
1551 .frames_hwctx_size = sizeof(AVVAAPIFramesContext),
1552 .frames_priv_size = sizeof(VAAPIFramesContext),
1554 .device_create = &vaapi_device_create,
1555 .device_derive = &vaapi_device_derive,
1556 .device_init = &vaapi_device_init,
1557 .device_uninit = &vaapi_device_uninit,
1558 .frames_get_constraints = &vaapi_frames_get_constraints,
1559 .frames_init = &vaapi_frames_init,
1560 .frames_uninit = &vaapi_frames_uninit,
1561 .frames_get_buffer = &vaapi_get_buffer,
1562 .transfer_get_formats = &vaapi_transfer_get_formats,
1563 .transfer_data_to = &vaapi_transfer_data_to,
1564 .transfer_data_from = &vaapi_transfer_data_from,
1565 .map_to = &vaapi_map_to,
1566 .map_from = &vaapi_map_from,
1568 .pix_fmts = (const enum AVPixelFormat[]) {