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;
1031 buffer_handle = desc->objects[0].fd;
1032 buffer_desc.pixel_format = va_fourcc;
1033 buffer_desc.width = src_fc->width;
1034 buffer_desc.height = src_fc->height;
1035 buffer_desc.data_size = desc->objects[0].size;
1036 buffer_desc.buffers = &buffer_handle;
1037 buffer_desc.num_buffers = 1;
1038 buffer_desc.flags = 0;
1041 for (i = 0; i < desc->nb_layers; i++) {
1042 for (j = 0; j < desc->layers[i].nb_planes; j++) {
1043 buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch;
1044 buffer_desc.offsets[k] = desc->layers[i].planes[j].offset;
1048 buffer_desc.num_planes = k;
1050 vas = vaCreateSurfaces(dst_dev->display, va_rt_format,
1051 src->width, src->height,
1053 attrs, FF_ARRAY_ELEMS(attrs));
1054 if (vas != VA_STATUS_SUCCESS) {
1055 av_log(dst_fc, AV_LOG_ERROR, "Failed to create surface from DRM "
1056 "object: %d (%s).\n", vas, vaErrorStr(vas));
1057 return AVERROR(EIO);
1059 av_log(dst_fc, AV_LOG_DEBUG, "Create surface %#x.\n", surface_id);
1061 err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
1062 &vaapi_unmap_from_drm,
1063 (void*)(uintptr_t)surface_id);
1067 dst->width = src->width;
1068 dst->height = src->height;
1069 dst->data[3] = (uint8_t*)(uintptr_t)surface_id;
1071 av_log(dst_fc, AV_LOG_DEBUG, "Mapped DRM object %d to "
1072 "surface %#x.\n", desc->objects[0].fd, surface_id);
1077 #if VA_CHECK_VERSION(1, 1, 0)
1078 static void vaapi_unmap_to_drm_esh(AVHWFramesContext *hwfc,
1079 HWMapDescriptor *hwmap)
1081 AVDRMFrameDescriptor *drm_desc = hwmap->priv;
1084 for (i = 0; i < drm_desc->nb_objects; i++)
1085 close(drm_desc->objects[i].fd);
1087 av_freep(&drm_desc);
1090 static int vaapi_map_to_drm_esh(AVHWFramesContext *hwfc, AVFrame *dst,
1091 const AVFrame *src, int flags)
1093 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1094 VASurfaceID surface_id;
1096 VADRMPRIMESurfaceDescriptor va_desc;
1097 AVDRMFrameDescriptor *drm_desc = NULL;
1098 uint32_t export_flags;
1101 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
1103 export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS;
1104 if (flags & AV_HWFRAME_MAP_READ)
1105 export_flags |= VA_EXPORT_SURFACE_READ_ONLY;
1106 if (flags & AV_HWFRAME_MAP_WRITE)
1107 export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY;
1109 vas = vaExportSurfaceHandle(hwctx->display, surface_id,
1110 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
1111 export_flags, &va_desc);
1112 if (vas != VA_STATUS_SUCCESS) {
1113 if (vas == VA_STATUS_ERROR_UNIMPLEMENTED)
1114 return AVERROR(ENOSYS);
1115 av_log(hwfc, AV_LOG_ERROR, "Failed to export surface %#x: "
1116 "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
1117 return AVERROR(EIO);
1120 drm_desc = av_mallocz(sizeof(*drm_desc));
1122 err = AVERROR(ENOMEM);
1126 // By some bizarre coincidence, these structures are very similar...
1127 drm_desc->nb_objects = va_desc.num_objects;
1128 for (i = 0; i < va_desc.num_objects; i++) {
1129 drm_desc->objects[i].fd = va_desc.objects[i].fd;
1130 drm_desc->objects[i].size = va_desc.objects[i].size;
1131 drm_desc->objects[i].format_modifier =
1132 va_desc.objects[i].drm_format_modifier;
1134 drm_desc->nb_layers = va_desc.num_layers;
1135 for (i = 0; i < va_desc.num_layers; i++) {
1136 drm_desc->layers[i].format = va_desc.layers[i].drm_format;
1137 drm_desc->layers[i].nb_planes = va_desc.layers[i].num_planes;
1138 for (j = 0; j < va_desc.layers[i].num_planes; j++) {
1139 drm_desc->layers[i].planes[j].object_index =
1140 va_desc.layers[i].object_index[j];
1141 drm_desc->layers[i].planes[j].offset =
1142 va_desc.layers[i].offset[j];
1143 drm_desc->layers[i].planes[j].pitch =
1144 va_desc.layers[i].pitch[j];
1148 err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
1149 &vaapi_unmap_to_drm_esh, drm_desc);
1153 dst->width = src->width;
1154 dst->height = src->height;
1155 dst->data[0] = (uint8_t*)drm_desc;
1160 for (i = 0; i < va_desc.num_objects; i++)
1161 close(va_desc.objects[i].fd);
1162 av_freep(&drm_desc);
1167 typedef struct VAAPIDRMImageBufferMapping {
1169 VABufferInfo buffer_info;
1171 AVDRMFrameDescriptor drm_desc;
1172 } VAAPIDRMImageBufferMapping;
1174 static void vaapi_unmap_to_drm_abh(AVHWFramesContext *hwfc,
1175 HWMapDescriptor *hwmap)
1177 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1178 VAAPIDRMImageBufferMapping *mapping = hwmap->priv;
1179 VASurfaceID surface_id;
1182 surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
1183 av_log(hwfc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from DRM.\n",
1186 // DRM PRIME file descriptors are closed by vaReleaseBufferHandle(),
1187 // so we shouldn't close them separately.
1189 vas = vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
1190 if (vas != VA_STATUS_SUCCESS) {
1191 av_log(hwfc, AV_LOG_ERROR, "Failed to release buffer "
1192 "handle of image %#x (derived from surface %#x): "
1193 "%d (%s).\n", mapping->image.buf, surface_id,
1194 vas, vaErrorStr(vas));
1197 vas = vaDestroyImage(hwctx->display, mapping->image.image_id);
1198 if (vas != VA_STATUS_SUCCESS) {
1199 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image "
1200 "derived from surface %#x: %d (%s).\n",
1201 surface_id, vas, vaErrorStr(vas));
1207 static int vaapi_map_to_drm_abh(AVHWFramesContext *hwfc, AVFrame *dst,
1208 const AVFrame *src, int flags)
1210 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1211 VAAPIDRMImageBufferMapping *mapping = NULL;
1212 VASurfaceID surface_id;
1216 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
1217 av_log(hwfc, AV_LOG_DEBUG, "Map VAAPI surface %#x to DRM.\n",
1220 mapping = av_mallocz(sizeof(*mapping));
1222 return AVERROR(ENOMEM);
1224 vas = vaDeriveImage(hwctx->display, surface_id,
1226 if (vas != VA_STATUS_SUCCESS) {
1227 av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
1228 "surface %#x: %d (%s).\n",
1229 surface_id, vas, vaErrorStr(vas));
1234 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
1235 if (vaapi_drm_format_map[i].va_fourcc ==
1236 mapping->image.format.fourcc)
1239 if (i >= FF_ARRAY_ELEMS(vaapi_drm_format_map)) {
1240 av_log(hwfc, AV_LOG_ERROR, "No matching DRM format for "
1241 "VAAPI format %#x.\n", mapping->image.format.fourcc);
1242 err = AVERROR(EINVAL);
1246 mapping->buffer_info.mem_type =
1247 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
1249 mapping->drm_desc.nb_layers =
1250 vaapi_drm_format_map[i].nb_layer_formats;
1251 if (mapping->drm_desc.nb_layers > 1) {
1252 if (mapping->drm_desc.nb_layers != mapping->image.num_planes) {
1253 av_log(hwfc, AV_LOG_ERROR, "Image properties do not match "
1254 "expected format: got %d planes, but expected %d.\n",
1255 mapping->image.num_planes, mapping->drm_desc.nb_layers);
1256 err = AVERROR(EINVAL);
1260 for(p = 0; p < mapping->drm_desc.nb_layers; p++) {
1261 mapping->drm_desc.layers[p] = (AVDRMLayerDescriptor) {
1262 .format = vaapi_drm_format_map[i].layer_formats[p],
1266 .offset = mapping->image.offsets[p],
1267 .pitch = mapping->image.pitches[p],
1272 mapping->drm_desc.layers[0].format =
1273 vaapi_drm_format_map[i].layer_formats[0];
1274 mapping->drm_desc.layers[0].nb_planes = mapping->image.num_planes;
1275 for (p = 0; p < mapping->image.num_planes; p++) {
1276 mapping->drm_desc.layers[0].planes[p] = (AVDRMPlaneDescriptor) {
1278 .offset = mapping->image.offsets[p],
1279 .pitch = mapping->image.pitches[p],
1284 vas = vaAcquireBufferHandle(hwctx->display, mapping->image.buf,
1285 &mapping->buffer_info);
1286 if (vas != VA_STATUS_SUCCESS) {
1287 av_log(hwfc, AV_LOG_ERROR, "Failed to get buffer "
1288 "handle from image %#x (derived from surface %#x): "
1289 "%d (%s).\n", mapping->image.buf, surface_id,
1290 vas, vaErrorStr(vas));
1295 av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n",
1296 mapping->buffer_info.handle);
1298 mapping->drm_desc.nb_objects = 1;
1299 mapping->drm_desc.objects[0] = (AVDRMObjectDescriptor) {
1300 .fd = mapping->buffer_info.handle,
1301 .size = mapping->image.data_size,
1302 // There is no way to get the format modifier with this API.
1303 .format_modifier = DRM_FORMAT_MOD_INVALID,
1306 err = ff_hwframe_map_create(src->hw_frames_ctx,
1307 dst, src, &vaapi_unmap_to_drm_abh,
1312 dst->data[0] = (uint8_t*)&mapping->drm_desc;
1313 dst->width = src->width;
1314 dst->height = src->height;
1319 vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
1321 vaDestroyImage(hwctx->display, mapping->image.image_id);
1327 static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
1328 const AVFrame *src, int flags)
1330 #if VA_CHECK_VERSION(1, 1, 0)
1332 err = vaapi_map_to_drm_esh(hwfc, dst, src, flags);
1333 if (err != AVERROR(ENOSYS))
1336 return vaapi_map_to_drm_abh(hwfc, dst, src, flags);
1339 #endif /* CONFIG_LIBDRM */
1341 static int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
1342 const AVFrame *src, int flags)
1344 switch (src->format) {
1346 case AV_PIX_FMT_DRM_PRIME:
1347 return vaapi_map_from_drm(hwfc, dst, src, flags);
1350 return AVERROR(ENOSYS);
1354 static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
1355 const AVFrame *src, int flags)
1357 switch (dst->format) {
1359 case AV_PIX_FMT_DRM_PRIME:
1360 return vaapi_map_to_drm(hwfc, dst, src, flags);
1363 return vaapi_map_to_memory(hwfc, dst, src, flags);
1367 static void vaapi_device_free(AVHWDeviceContext *ctx)
1369 AVVAAPIDeviceContext *hwctx = ctx->hwctx;
1370 VAAPIDevicePriv *priv = ctx->user_opaque;
1373 vaTerminate(hwctx->display);
1376 if (priv->x11_display)
1377 XCloseDisplay(priv->x11_display);
1380 if (priv->drm_fd >= 0)
1381 close(priv->drm_fd);
1387 static void vaapi_device_log_error(void *context, const char *message)
1389 AVHWDeviceContext *ctx = context;
1391 av_log(ctx, AV_LOG_ERROR, "libva: %s", message);
1394 static void vaapi_device_log_info(void *context, const char *message)
1396 AVHWDeviceContext *ctx = context;
1398 av_log(ctx, AV_LOG_VERBOSE, "libva: %s", message);
1402 static int vaapi_device_connect(AVHWDeviceContext *ctx,
1405 AVVAAPIDeviceContext *hwctx = ctx->hwctx;
1410 vaSetErrorCallback(display, &vaapi_device_log_error, ctx);
1411 vaSetInfoCallback (display, &vaapi_device_log_info, ctx);
1414 hwctx->display = display;
1416 vas = vaInitialize(display, &major, &minor);
1417 if (vas != VA_STATUS_SUCCESS) {
1418 av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
1419 "connection: %d (%s).\n", vas, vaErrorStr(vas));
1420 return AVERROR(EIO);
1422 av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
1423 "version %d.%d\n", major, minor);
1428 static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
1429 AVDictionary *opts, int flags)
1431 VAAPIDevicePriv *priv;
1432 VADisplay display = NULL;
1434 priv = av_mallocz(sizeof(*priv));
1436 return AVERROR(ENOMEM);
1440 ctx->user_opaque = priv;
1441 ctx->free = vaapi_device_free;
1444 if (!display && !(device && device[0] == '/')) {
1445 // Try to open the device as an X11 display.
1446 priv->x11_display = XOpenDisplay(device);
1447 if (!priv->x11_display) {
1448 av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
1449 "%s.\n", XDisplayName(device));
1451 display = vaGetDisplay(priv->x11_display);
1453 av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
1454 "from X11 display %s.\n", XDisplayName(device));
1455 return AVERROR_UNKNOWN;
1458 av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
1459 "X11 display %s.\n", XDisplayName(device));
1466 // Try to open the device as a DRM path.
1467 // Default to using the first render node if the user did not
1469 const char *path = device ? device : "/dev/dri/renderD128";
1470 priv->drm_fd = open(path, O_RDWR);
1471 if (priv->drm_fd < 0) {
1472 av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n",
1475 display = vaGetDisplayDRM(priv->drm_fd);
1477 av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
1478 "from DRM device %s.\n", path);
1479 return AVERROR_UNKNOWN;
1482 av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
1483 "DRM device %s.\n", path);
1489 av_log(ctx, AV_LOG_ERROR, "No VA display found for "
1490 "device: %s.\n", device ? device : "");
1491 return AVERROR(EINVAL);
1494 return vaapi_device_connect(ctx, display);
1497 static int vaapi_device_derive(AVHWDeviceContext *ctx,
1498 AVHWDeviceContext *src_ctx, int flags)
1501 if (src_ctx->type == AV_HWDEVICE_TYPE_DRM) {
1502 AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
1504 VAAPIDevicePriv *priv;
1506 if (src_hwctx->fd < 0) {
1507 av_log(ctx, AV_LOG_ERROR, "DRM instance requires an associated "
1508 "device to derive a VA display from.\n");
1509 return AVERROR(EINVAL);
1512 priv = av_mallocz(sizeof(*priv));
1514 return AVERROR(ENOMEM);
1516 // Inherits the fd from the source context, which will close it.
1519 ctx->user_opaque = priv;
1520 ctx->free = &vaapi_device_free;
1522 display = vaGetDisplayDRM(src_hwctx->fd);
1524 av_log(ctx, AV_LOG_ERROR, "Failed to open a VA display from "
1526 return AVERROR(EIO);
1529 return vaapi_device_connect(ctx, display);
1532 return AVERROR(ENOSYS);
1535 const HWContextType ff_hwcontext_type_vaapi = {
1536 .type = AV_HWDEVICE_TYPE_VAAPI,
1539 .device_hwctx_size = sizeof(AVVAAPIDeviceContext),
1540 .device_priv_size = sizeof(VAAPIDeviceContext),
1541 .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
1542 .frames_hwctx_size = sizeof(AVVAAPIFramesContext),
1543 .frames_priv_size = sizeof(VAAPIFramesContext),
1545 .device_create = &vaapi_device_create,
1546 .device_derive = &vaapi_device_derive,
1547 .device_init = &vaapi_device_init,
1548 .device_uninit = &vaapi_device_uninit,
1549 .frames_get_constraints = &vaapi_frames_get_constraints,
1550 .frames_init = &vaapi_frames_init,
1551 .frames_uninit = &vaapi_frames_uninit,
1552 .frames_get_buffer = &vaapi_get_buffer,
1553 .transfer_get_formats = &vaapi_transfer_get_formats,
1554 .transfer_data_to = &vaapi_transfer_data_to,
1555 .transfer_data_from = &vaapi_transfer_data_from,
1556 .map_to = &vaapi_map_to,
1557 .map_from = &vaapi_map_from,
1559 .pix_fmts = (const enum AVPixelFormat[]) {