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
24 # include <initguid.h>
26 # include "compat/w32dlfcn.h"
27 # include <va/va_win32.h>
28 typedef HRESULT (WINAPI
*PFN_CREATE_DXGI_FACTORY
)(REFIID riid
, void **ppFactory
);
31 # include <va/va_x11.h>
34 # include <va/va_drm.h>
38 # include <va/va_drmcommon.h>
40 # include <drm_fourcc.h>
41 # ifndef DRM_FORMAT_MOD_INVALID
42 # define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
55 #include "hwcontext.h"
56 #include "hwcontext_drm.h"
57 #include "hwcontext_internal.h"
58 #include "hwcontext_vaapi.h"
64 typedef struct VAAPIDevicePriv
{
72 typedef struct VAAPISurfaceFormat
{
73 enum AVPixelFormat pix_fmt
;
74 VAImageFormat image_format
;
78 typedef struct VAAPIDeviceContext
{
80 * The public AVVAAPIDeviceContext. See hwcontext_vaapi.h for it.
82 AVVAAPIDeviceContext p
;
84 // Surface formats which can be used with this device.
85 VAAPISurfaceFormat
*formats
;
89 typedef struct VAAPIFramesContext
{
91 * The public AVVAAPIFramesContext. See hwcontext_vaapi.h for it.
93 AVVAAPIFramesContext p
;
95 // Surface attributes set at create time.
96 VASurfaceAttrib
*attributes
;
98 // RT format of the underlying surface (Intel driver ignores this anyway).
99 unsigned int rt_format
;
100 // Whether vaDeriveImage works.
102 // Caches whether VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2 is unsupported for
104 int prime_2_import_unsupported
;
105 } VAAPIFramesContext
;
107 typedef struct VAAPIMapping
{
108 // Handle to the derived or copied image which is mapped.
110 // The mapping flags actually used.
114 typedef struct VAAPIFormat
{
116 unsigned int rt_format
;
117 enum AVPixelFormat pix_fmt
;
118 int chroma_planes_swapped
;
119 } VAAPIFormatDescriptor
;
121 #define MAP(va, rt, av, swap_uv) { \
123 VA_RT_FORMAT_ ## rt, \
127 // The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V
128 // plane swap cases. The frame handling below tries to hide these.
129 static const VAAPIFormatDescriptor vaapi_format_map
[] = {
130 MAP(NV12
, YUV420
, NV12
, 0),
131 #ifdef VA_FOURCC_I420
132 MAP(I420
, YUV420
, YUV420P
, 0),
134 MAP(YV12
, YUV420
, YUV420P
, 1),
135 MAP(IYUV
, YUV420
, YUV420P
, 0),
136 MAP(422H
, YUV422
, YUV422P
, 0),
137 #ifdef VA_FOURCC_YV16
138 MAP(YV16
, YUV422
, YUV422P
, 1),
140 MAP(UYVY
, YUV422
, UYVY422
, 0),
141 MAP(YUY2
, YUV422
, YUYV422
, 0),
142 #ifdef VA_FOURCC_Y210
143 MAP(Y210
, YUV422_10
, Y210
, 0),
145 #ifdef VA_FOURCC_Y212
146 MAP(Y212
, YUV422_12
, Y212
, 0),
148 MAP(411P
, YUV411
, YUV411P
, 0),
149 MAP(422V
, YUV422
, YUV440P
, 0),
150 MAP(444P
, YUV444
, YUV444P
, 0),
151 #ifdef VA_FOURCC_XYUV
152 MAP(XYUV
, YUV444
, VUYX
, 0),
154 MAP(Y800
, YUV400
, GRAY8
, 0),
155 #ifdef VA_FOURCC_P010
156 MAP(P010
, YUV420_10BPP
, P010
, 0),
158 #ifdef VA_FOURCC_P012
159 MAP(P012
, YUV420_12
, P012
, 0),
161 MAP(BGRA
, RGB32
, BGRA
, 0),
162 MAP(BGRX
, RGB32
, BGR0
, 0),
163 MAP(RGBA
, RGB32
, RGBA
, 0),
164 MAP(RGBX
, RGB32
, RGB0
, 0),
165 #ifdef VA_FOURCC_ABGR
166 MAP(ABGR
, RGB32
, ABGR
, 0),
167 MAP(XBGR
, RGB32
, 0BGR
, 0),
169 MAP(ARGB
, RGB32
, ARGB
, 0),
170 MAP(XRGB
, RGB32
, 0RGB
, 0),
171 #ifdef VA_FOURCC_X2R10G10B10
172 MAP(X2R10G10B10
, RGB32_10
, X2RGB10
, 0),
174 #ifdef VA_FOURCC_Y410
175 // libva doesn't include a fourcc for XV30 and the driver only declares
176 // support for Y410, so we must fudge the mapping here.
177 MAP(Y410
, YUV444_10
, XV30
, 0),
179 #ifdef VA_FOURCC_Y412
180 // libva doesn't include a fourcc for XV36 and the driver only declares
181 // support for Y412, so we must fudge the mapping here.
182 MAP(Y412
, YUV444_12
, XV36
, 0),
187 static const VAAPIFormatDescriptor
*
188 vaapi_format_from_fourcc(unsigned int fourcc
)
191 for (i
= 0; i
< FF_ARRAY_ELEMS(vaapi_format_map
); i
++)
192 if (vaapi_format_map
[i
].fourcc
== fourcc
)
193 return &vaapi_format_map
[i
];
197 static const VAAPIFormatDescriptor
*
198 vaapi_format_from_pix_fmt(enum AVPixelFormat pix_fmt
, const VAAPIFormatDescriptor
*prev
)
200 const VAAPIFormatDescriptor
*end
= &vaapi_format_map
[FF_ARRAY_ELEMS(vaapi_format_map
)];
202 prev
= vaapi_format_map
;
206 for (; prev
< end
; prev
++)
207 if (prev
->pix_fmt
== pix_fmt
)
212 static enum AVPixelFormat
vaapi_pix_fmt_from_fourcc(unsigned int fourcc
)
214 const VAAPIFormatDescriptor
*desc
;
215 desc
= vaapi_format_from_fourcc(fourcc
);
217 return desc
->pix_fmt
;
219 return AV_PIX_FMT_NONE
;
222 static int vaapi_get_img_desc_and_format(AVHWDeviceContext
*hwdev
,
223 enum AVPixelFormat pix_fmt
,
224 const VAAPIFormatDescriptor
**_desc
,
225 VAImageFormat
**image_format
)
227 VAAPIDeviceContext
*ctx
= hwdev
->hwctx
;
228 const VAAPIFormatDescriptor
*desc
= NULL
;
231 while ((desc
= vaapi_format_from_pix_fmt(pix_fmt
, desc
))) {
232 for (i
= 0; i
< ctx
->nb_formats
; i
++) {
233 if (ctx
->formats
[i
].fourcc
== desc
->fourcc
) {
237 *image_format
= &ctx
->formats
[i
].image_format
;
243 return AVERROR(ENOSYS
);
246 static int vaapi_get_image_format(AVHWDeviceContext
*hwdev
,
247 enum AVPixelFormat pix_fmt
,
248 VAImageFormat
**image_format
)
251 return AVERROR(EINVAL
);
252 return vaapi_get_img_desc_and_format(hwdev
, pix_fmt
, NULL
, image_format
);
255 static int vaapi_frames_get_constraints(AVHWDeviceContext
*hwdev
,
256 const void *hwconfig
,
257 AVHWFramesConstraints
*constraints
)
259 VAAPIDeviceContext
*ctx
= hwdev
->hwctx
;
260 AVVAAPIDeviceContext
*hwctx
= &ctx
->p
;
261 const AVVAAPIHWConfig
*config
= hwconfig
;
262 VASurfaceAttrib
*attr_list
= NULL
;
264 enum AVPixelFormat pix_fmt
;
266 int err
, i
, j
, attr_count
, pix_fmt_count
;
269 !(hwctx
->driver_quirks
& AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES
)) {
271 vas
= vaQuerySurfaceAttributes(hwctx
->display
, config
->config_id
,
273 if (vas
!= VA_STATUS_SUCCESS
) {
274 av_log(hwdev
, AV_LOG_ERROR
, "Failed to query surface attributes: "
275 "%d (%s).\n", vas
, vaErrorStr(vas
));
276 err
= AVERROR(ENOSYS
);
280 attr_list
= av_malloc(attr_count
* sizeof(*attr_list
));
282 err
= AVERROR(ENOMEM
);
286 vas
= vaQuerySurfaceAttributes(hwctx
->display
, config
->config_id
,
287 attr_list
, &attr_count
);
288 if (vas
!= VA_STATUS_SUCCESS
) {
289 av_log(hwdev
, AV_LOG_ERROR
, "Failed to query surface attributes: "
290 "%d (%s).\n", vas
, vaErrorStr(vas
));
291 err
= AVERROR(ENOSYS
);
296 for (i
= 0; i
< attr_count
; i
++) {
297 switch (attr_list
[i
].type
) {
298 case VASurfaceAttribPixelFormat
:
299 fourcc
= attr_list
[i
].value
.value
.i
;
300 pix_fmt
= vaapi_pix_fmt_from_fourcc(fourcc
);
301 if (pix_fmt
!= AV_PIX_FMT_NONE
) {
304 // Something unsupported - ignore.
307 case VASurfaceAttribMinWidth
:
308 constraints
->min_width
= attr_list
[i
].value
.value
.i
;
310 case VASurfaceAttribMinHeight
:
311 constraints
->min_height
= attr_list
[i
].value
.value
.i
;
313 case VASurfaceAttribMaxWidth
:
314 constraints
->max_width
= attr_list
[i
].value
.value
.i
;
316 case VASurfaceAttribMaxHeight
:
317 constraints
->max_height
= attr_list
[i
].value
.value
.i
;
321 if (pix_fmt_count
== 0) {
322 // Nothing usable found. Presumably there exists something which
323 // works, so leave the set null to indicate unknown.
324 constraints
->valid_sw_formats
= NULL
;
326 constraints
->valid_sw_formats
= av_malloc_array(pix_fmt_count
+ 1,
328 if (!constraints
->valid_sw_formats
) {
329 err
= AVERROR(ENOMEM
);
333 for (i
= j
= 0; i
< attr_count
; i
++) {
336 if (attr_list
[i
].type
!= VASurfaceAttribPixelFormat
)
338 fourcc
= attr_list
[i
].value
.value
.i
;
339 pix_fmt
= vaapi_pix_fmt_from_fourcc(fourcc
);
341 if (pix_fmt
== AV_PIX_FMT_NONE
)
344 for (k
= 0; k
< j
; k
++) {
345 if (constraints
->valid_sw_formats
[k
] == pix_fmt
)
350 constraints
->valid_sw_formats
[j
++] = pix_fmt
;
352 constraints
->valid_sw_formats
[j
] = AV_PIX_FMT_NONE
;
355 // No configuration supplied.
356 // Return the full set of image formats known by the implementation.
357 constraints
->valid_sw_formats
= av_malloc_array(ctx
->nb_formats
+ 1,
359 if (!constraints
->valid_sw_formats
) {
360 err
= AVERROR(ENOMEM
);
363 for (i
= j
= 0; i
< ctx
->nb_formats
; i
++) {
366 for (k
= 0; k
< j
; k
++) {
367 if (constraints
->valid_sw_formats
[k
] == ctx
->formats
[i
].pix_fmt
)
372 constraints
->valid_sw_formats
[j
++] = ctx
->formats
[i
].pix_fmt
;
375 constraints
->valid_sw_formats
[j
] = AV_PIX_FMT_NONE
;
378 constraints
->valid_hw_formats
= av_malloc_array(2, sizeof(pix_fmt
));
379 if (!constraints
->valid_hw_formats
) {
380 err
= AVERROR(ENOMEM
);
383 constraints
->valid_hw_formats
[0] = AV_PIX_FMT_VAAPI
;
384 constraints
->valid_hw_formats
[1] = AV_PIX_FMT_NONE
;
388 av_freep(&attr_list
);
392 static const struct {
393 const char *friendly_name
;
394 const char *match_string
;
396 } vaapi_driver_quirks_table
[] = {
397 #if !VA_CHECK_VERSION(1, 0, 0)
398 // The i965 driver did not conform before version 2.0.
400 "Intel i965 (Quick Sync)",
402 AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS
,
408 AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE
,
412 "Splitted-Desktop Systems VDPAU backend for VA-API",
413 AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES
,
417 static int vaapi_device_init(AVHWDeviceContext
*hwdev
)
419 VAAPIDeviceContext
*ctx
= hwdev
->hwctx
;
420 AVVAAPIDeviceContext
*hwctx
= &ctx
->p
;
421 VAImageFormat
*image_list
= NULL
;
423 const char *vendor_string
;
424 int err
, i
, image_count
;
425 enum AVPixelFormat pix_fmt
;
428 image_count
= vaMaxNumImageFormats(hwctx
->display
);
429 if (image_count
<= 0) {
433 image_list
= av_malloc(image_count
* sizeof(*image_list
));
435 err
= AVERROR(ENOMEM
);
438 vas
= vaQueryImageFormats(hwctx
->display
, image_list
, &image_count
);
439 if (vas
!= VA_STATUS_SUCCESS
) {
444 ctx
->formats
= av_malloc(image_count
* sizeof(*ctx
->formats
));
446 err
= AVERROR(ENOMEM
);
450 for (i
= 0; i
< image_count
; i
++) {
451 fourcc
= image_list
[i
].fourcc
;
452 pix_fmt
= vaapi_pix_fmt_from_fourcc(fourcc
);
453 if (pix_fmt
== AV_PIX_FMT_NONE
) {
454 av_log(hwdev
, AV_LOG_DEBUG
, "Format %#x -> unknown.\n",
457 av_log(hwdev
, AV_LOG_DEBUG
, "Format %#x -> %s.\n",
458 fourcc
, av_get_pix_fmt_name(pix_fmt
));
459 ctx
->formats
[ctx
->nb_formats
].pix_fmt
= pix_fmt
;
460 ctx
->formats
[ctx
->nb_formats
].fourcc
= fourcc
;
461 ctx
->formats
[ctx
->nb_formats
].image_format
= image_list
[i
];
466 vendor_string
= vaQueryVendorString(hwctx
->display
);
468 av_log(hwdev
, AV_LOG_VERBOSE
, "VAAPI driver: %s.\n", vendor_string
);
470 if (hwctx
->driver_quirks
& AV_VAAPI_DRIVER_QUIRK_USER_SET
) {
471 av_log(hwdev
, AV_LOG_VERBOSE
, "Using quirks set by user (%#x).\n",
472 hwctx
->driver_quirks
);
474 // Detect the driver in use and set quirk flags if necessary.
475 hwctx
->driver_quirks
= 0;
477 for (i
= 0; i
< FF_ARRAY_ELEMS(vaapi_driver_quirks_table
); i
++) {
478 if (strstr(vendor_string
,
479 vaapi_driver_quirks_table
[i
].match_string
)) {
480 av_log(hwdev
, AV_LOG_VERBOSE
, "Matched driver string "
481 "as known nonstandard driver \"%s\", setting "
483 vaapi_driver_quirks_table
[i
].friendly_name
,
484 vaapi_driver_quirks_table
[i
].quirks
);
485 hwctx
->driver_quirks
|=
486 vaapi_driver_quirks_table
[i
].quirks
;
490 if (!(i
< FF_ARRAY_ELEMS(vaapi_driver_quirks_table
))) {
491 av_log(hwdev
, AV_LOG_VERBOSE
, "Driver not found in known "
492 "nonstandard list, using standard behaviour.\n");
495 av_log(hwdev
, AV_LOG_VERBOSE
, "Driver has no vendor string, "
496 "assuming standard behaviour.\n");
503 av_freep(&ctx
->formats
);
508 static void vaapi_device_uninit(AVHWDeviceContext
*hwdev
)
510 VAAPIDeviceContext
*ctx
= hwdev
->hwctx
;
512 av_freep(&ctx
->formats
);
515 static void vaapi_buffer_free(void *opaque
, uint8_t *data
)
517 AVHWFramesContext
*hwfc
= opaque
;
518 AVVAAPIDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
519 VASurfaceID surface_id
;
522 surface_id
= (VASurfaceID
)(uintptr_t)data
;
524 vas
= vaDestroySurfaces(hwctx
->display
, &surface_id
, 1);
525 if (vas
!= VA_STATUS_SUCCESS
) {
526 av_log(hwfc
, AV_LOG_ERROR
, "Failed to destroy surface %#x: "
527 "%d (%s).\n", surface_id
, vas
, vaErrorStr(vas
));
531 static AVBufferRef
*vaapi_pool_alloc(void *opaque
, size_t size
)
533 AVHWFramesContext
*hwfc
= opaque
;
534 VAAPIFramesContext
*ctx
= hwfc
->hwctx
;
535 AVVAAPIFramesContext
*avfc
= &ctx
->p
;
536 AVVAAPIDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
537 VASurfaceID surface_id
;
541 if (hwfc
->initial_pool_size
> 0 &&
542 avfc
->nb_surfaces
>= hwfc
->initial_pool_size
)
545 vas
= vaCreateSurfaces(hwctx
->display
, ctx
->rt_format
,
546 hwfc
->width
, hwfc
->height
,
548 ctx
->attributes
, ctx
->nb_attributes
);
549 if (vas
!= VA_STATUS_SUCCESS
) {
550 av_log(hwfc
, AV_LOG_ERROR
, "Failed to create surface: "
551 "%d (%s).\n", vas
, vaErrorStr(vas
));
554 av_log(hwfc
, AV_LOG_DEBUG
, "Created surface %#x.\n", surface_id
);
556 ref
= av_buffer_create((uint8_t*)(uintptr_t)surface_id
,
557 sizeof(surface_id
), &vaapi_buffer_free
,
558 hwfc
, AV_BUFFER_FLAG_READONLY
);
560 vaDestroySurfaces(hwctx
->display
, &surface_id
, 1);
564 if (hwfc
->initial_pool_size
> 0) {
565 // This is a fixed-size pool, so we must still be in the initial
566 // allocation sequence.
567 av_assert0(avfc
->nb_surfaces
< hwfc
->initial_pool_size
);
568 avfc
->surface_ids
[avfc
->nb_surfaces
] = surface_id
;
575 static int vaapi_frames_init(AVHWFramesContext
*hwfc
)
577 VAAPIFramesContext
*ctx
= hwfc
->hwctx
;
578 AVVAAPIFramesContext
*avfc
= &ctx
->p
;
579 AVVAAPIDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
580 const VAAPIFormatDescriptor
*desc
= NULL
;
581 VAImageFormat
*expected_format
= NULL
;
582 AVBufferRef
*test_surface
= NULL
;
583 VASurfaceID test_surface_id
;
588 err
= vaapi_get_img_desc_and_format(hwfc
->device_ctx
, hwfc
->sw_format
,
589 &desc
, &expected_format
);
591 // Use a relaxed check when pool exist. It can be an external pool.
592 if (!hwfc
->pool
|| !vaapi_format_from_pix_fmt(hwfc
->sw_format
, NULL
)) {
593 av_log(hwfc
, AV_LOG_ERROR
, "Unsupported format: %s.\n",
594 av_get_pix_fmt_name(hwfc
->sw_format
));
595 return AVERROR(EINVAL
);
600 if (!(hwctx
->driver_quirks
& AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES
)) {
601 int need_memory_type
= !(hwctx
->driver_quirks
& AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE
);
602 int need_pixel_format
= 1;
603 for (i
= 0; i
< avfc
->nb_attributes
; i
++) {
604 if (avfc
->attributes
[i
].type
== VASurfaceAttribMemoryType
)
605 need_memory_type
= 0;
606 if (avfc
->attributes
[i
].type
== VASurfaceAttribPixelFormat
)
607 need_pixel_format
= 0;
610 avfc
->nb_attributes
+ need_memory_type
+ need_pixel_format
;
612 ctx
->attributes
= av_malloc(ctx
->nb_attributes
*
613 sizeof(*ctx
->attributes
));
614 if (!ctx
->attributes
) {
615 err
= AVERROR(ENOMEM
);
619 for (i
= 0; i
< avfc
->nb_attributes
; i
++)
620 ctx
->attributes
[i
] = avfc
->attributes
[i
];
621 if (need_memory_type
) {
622 ctx
->attributes
[i
++] = (VASurfaceAttrib
) {
623 .type
= VASurfaceAttribMemoryType
,
624 .flags
= VA_SURFACE_ATTRIB_SETTABLE
,
625 .value
.type
= VAGenericValueTypeInteger
,
626 .value
.value
.i
= VA_SURFACE_ATTRIB_MEM_TYPE_VA
,
629 if (need_pixel_format
) {
630 ctx
->attributes
[i
++] = (VASurfaceAttrib
) {
631 .type
= VASurfaceAttribPixelFormat
,
632 .flags
= VA_SURFACE_ATTRIB_SETTABLE
,
633 .value
.type
= VAGenericValueTypeInteger
,
634 .value
.value
.i
= desc
->fourcc
,
637 av_assert0(i
== ctx
->nb_attributes
);
639 ctx
->attributes
= NULL
;
640 ctx
->nb_attributes
= 0;
643 ctx
->rt_format
= desc
->rt_format
;
645 if (hwfc
->initial_pool_size
> 0) {
646 // This pool will be usable as a render target, so we need to store
647 // all of the surface IDs somewhere that vaCreateContext() calls
648 // will be able to access them.
649 avfc
->nb_surfaces
= 0;
650 avfc
->surface_ids
= av_malloc(hwfc
->initial_pool_size
*
651 sizeof(*avfc
->surface_ids
));
652 if (!avfc
->surface_ids
) {
653 err
= AVERROR(ENOMEM
);
657 // This pool allows dynamic sizing, and will not be usable as a
659 avfc
->nb_surfaces
= 0;
660 avfc
->surface_ids
= NULL
;
663 ffhwframesctx(hwfc
)->pool_internal
=
664 av_buffer_pool_init2(sizeof(VASurfaceID
), hwfc
,
665 &vaapi_pool_alloc
, NULL
);
666 if (!ffhwframesctx(hwfc
)->pool_internal
) {
667 av_log(hwfc
, AV_LOG_ERROR
, "Failed to create VAAPI surface pool.\n");
668 err
= AVERROR(ENOMEM
);
673 // Allocate a single surface to test whether vaDeriveImage() is going
674 // to work for the specific configuration.
676 test_surface
= av_buffer_pool_get(hwfc
->pool
);
678 av_log(hwfc
, AV_LOG_ERROR
, "Unable to allocate a surface from "
679 "user-configured buffer pool.\n");
680 err
= AVERROR(ENOMEM
);
684 test_surface
= av_buffer_pool_get(ffhwframesctx(hwfc
)->pool_internal
);
686 av_log(hwfc
, AV_LOG_ERROR
, "Unable to allocate a surface from "
687 "internal buffer pool.\n");
688 err
= AVERROR(ENOMEM
);
692 test_surface_id
= (VASurfaceID
)(uintptr_t)test_surface
->data
;
694 ctx
->derive_works
= 0;
695 if (expected_format
) {
696 vas
= vaDeriveImage(hwctx
->display
, test_surface_id
, &test_image
);
697 if (vas
== VA_STATUS_SUCCESS
) {
698 if (expected_format
->fourcc
== test_image
.format
.fourcc
) {
699 av_log(hwfc
, AV_LOG_DEBUG
, "Direct mapping possible.\n");
700 ctx
->derive_works
= 1;
702 av_log(hwfc
, AV_LOG_DEBUG
, "Direct mapping disabled: "
703 "derived image format %08x does not match "
704 "expected format %08x.\n",
705 expected_format
->fourcc
, test_image
.format
.fourcc
);
707 vaDestroyImage(hwctx
->display
, test_image
.image_id
);
709 av_log(hwfc
, AV_LOG_DEBUG
, "Direct mapping disabled: "
710 "deriving image does not work: "
711 "%d (%s).\n", vas
, vaErrorStr(vas
));
714 av_log(hwfc
, AV_LOG_DEBUG
, "Direct mapping disabled: "
715 "image format is not supported.\n");
718 av_buffer_unref(&test_surface
);
722 av_buffer_unref(&test_surface
);
723 av_freep(&avfc
->surface_ids
);
724 av_freep(&ctx
->attributes
);
728 static void vaapi_frames_uninit(AVHWFramesContext
*hwfc
)
730 VAAPIFramesContext
*ctx
= hwfc
->hwctx
;
731 AVVAAPIFramesContext
*avfc
= &ctx
->p
;
733 av_freep(&avfc
->surface_ids
);
734 av_freep(&ctx
->attributes
);
737 static int vaapi_get_buffer(AVHWFramesContext
*hwfc
, AVFrame
*frame
)
739 frame
->buf
[0] = av_buffer_pool_get(hwfc
->pool
);
741 return AVERROR(ENOMEM
);
743 frame
->data
[3] = frame
->buf
[0]->data
;
744 frame
->format
= AV_PIX_FMT_VAAPI
;
745 frame
->width
= hwfc
->width
;
746 frame
->height
= hwfc
->height
;
751 static int vaapi_transfer_get_formats(AVHWFramesContext
*hwfc
,
752 enum AVHWFrameTransferDirection dir
,
753 enum AVPixelFormat
**formats
)
755 VAAPIDeviceContext
*ctx
= hwfc
->device_ctx
->hwctx
;
756 enum AVPixelFormat
*pix_fmts
;
757 int i
, k
, sw_format_available
;
759 sw_format_available
= 0;
760 for (i
= 0; i
< ctx
->nb_formats
; i
++) {
761 if (ctx
->formats
[i
].pix_fmt
== hwfc
->sw_format
)
762 sw_format_available
= 1;
765 pix_fmts
= av_malloc((ctx
->nb_formats
+ 1) * sizeof(*pix_fmts
));
767 return AVERROR(ENOMEM
);
769 if (sw_format_available
) {
770 pix_fmts
[0] = hwfc
->sw_format
;
775 for (i
= 0; i
< ctx
->nb_formats
; i
++) {
776 if (ctx
->formats
[i
].pix_fmt
== hwfc
->sw_format
)
778 av_assert0(k
< ctx
->nb_formats
);
779 pix_fmts
[k
++] = ctx
->formats
[i
].pix_fmt
;
781 pix_fmts
[k
] = AV_PIX_FMT_NONE
;
787 static void vaapi_unmap_frame(AVHWFramesContext
*hwfc
,
788 HWMapDescriptor
*hwmap
)
790 AVVAAPIDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
791 VAAPIMapping
*map
= hwmap
->priv
;
792 VASurfaceID surface_id
;
795 surface_id
= (VASurfaceID
)(uintptr_t)hwmap
->source
->data
[3];
796 av_log(hwfc
, AV_LOG_DEBUG
, "Unmap surface %#x.\n", surface_id
);
798 vas
= vaUnmapBuffer(hwctx
->display
, map
->image
.buf
);
799 if (vas
!= VA_STATUS_SUCCESS
) {
800 av_log(hwfc
, AV_LOG_ERROR
, "Failed to unmap image from surface "
801 "%#x: %d (%s).\n", surface_id
, vas
, vaErrorStr(vas
));
804 if ((map
->flags
& AV_HWFRAME_MAP_WRITE
) &&
805 !(map
->flags
& AV_HWFRAME_MAP_DIRECT
)) {
806 vas
= vaPutImage(hwctx
->display
, surface_id
, map
->image
.image_id
,
807 0, 0, hwfc
->width
, hwfc
->height
,
808 0, 0, hwfc
->width
, hwfc
->height
);
809 if (vas
!= VA_STATUS_SUCCESS
) {
810 av_log(hwfc
, AV_LOG_ERROR
, "Failed to write image to surface "
811 "%#x: %d (%s).\n", surface_id
, vas
, vaErrorStr(vas
));
815 vas
= vaDestroyImage(hwctx
->display
, map
->image
.image_id
);
816 if (vas
!= VA_STATUS_SUCCESS
) {
817 av_log(hwfc
, AV_LOG_ERROR
, "Failed to destroy image from surface "
818 "%#x: %d (%s).\n", surface_id
, vas
, vaErrorStr(vas
));
824 static int vaapi_map_frame(AVHWFramesContext
*hwfc
,
825 AVFrame
*dst
, const AVFrame
*src
, int flags
)
827 AVVAAPIDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
828 VAAPIFramesContext
*ctx
= hwfc
->hwctx
;
829 VASurfaceID surface_id
;
830 const VAAPIFormatDescriptor
*desc
;
831 VAImageFormat
*image_format
;
834 void *address
= NULL
;
836 #if VA_CHECK_VERSION(1, 21, 0)
837 uint32_t vaflags
= 0;
840 surface_id
= (VASurfaceID
)(uintptr_t)src
->data
[3];
841 av_log(hwfc
, AV_LOG_DEBUG
, "Map surface %#x.\n", surface_id
);
843 if (!ctx
->derive_works
&& (flags
& AV_HWFRAME_MAP_DIRECT
)) {
844 // Requested direct mapping but it is not possible.
845 return AVERROR(EINVAL
);
847 if (dst
->format
== AV_PIX_FMT_NONE
)
848 dst
->format
= hwfc
->sw_format
;
849 if (dst
->format
!= hwfc
->sw_format
&& (flags
& AV_HWFRAME_MAP_DIRECT
)) {
850 // Requested direct mapping but the formats do not match.
851 return AVERROR(EINVAL
);
854 err
= vaapi_get_image_format(hwfc
->device_ctx
, dst
->format
, &image_format
);
856 // Requested format is not a valid output format.
860 map
= av_malloc(sizeof(*map
));
862 return AVERROR(ENOMEM
);
864 map
->image
.image_id
= VA_INVALID_ID
;
866 vas
= vaSyncSurface(hwctx
->display
, surface_id
);
867 if (vas
!= VA_STATUS_SUCCESS
) {
868 av_log(hwfc
, AV_LOG_ERROR
, "Failed to sync surface "
869 "%#x: %d (%s).\n", surface_id
, vas
, vaErrorStr(vas
));
874 // The memory which we map using derive need not be connected to the CPU
875 // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
876 // memory is mappable but not cached, so normal memcpy()-like access is
877 // very slow to read it (but writing is ok). It is possible to read much
878 // faster with a copy routine which is aware of the limitation, but we
879 // assume for now that the user is not aware of that and would therefore
880 // prefer not to be given direct-mapped memory if they request read access.
881 if (ctx
->derive_works
&& dst
->format
== hwfc
->sw_format
&&
882 ((flags
& AV_HWFRAME_MAP_DIRECT
) || !(flags
& AV_HWFRAME_MAP_READ
))) {
883 vas
= vaDeriveImage(hwctx
->display
, surface_id
, &map
->image
);
884 if (vas
!= VA_STATUS_SUCCESS
) {
885 av_log(hwfc
, AV_LOG_ERROR
, "Failed to derive image from "
886 "surface %#x: %d (%s).\n",
887 surface_id
, vas
, vaErrorStr(vas
));
891 if (map
->image
.format
.fourcc
!= image_format
->fourcc
) {
892 av_log(hwfc
, AV_LOG_ERROR
, "Derive image of surface %#x "
893 "is in wrong format: expected %#08x, got %#08x.\n",
894 surface_id
, image_format
->fourcc
, map
->image
.format
.fourcc
);
898 map
->flags
|= AV_HWFRAME_MAP_DIRECT
;
900 vas
= vaCreateImage(hwctx
->display
, image_format
,
901 hwfc
->width
, hwfc
->height
, &map
->image
);
902 if (vas
!= VA_STATUS_SUCCESS
) {
903 av_log(hwfc
, AV_LOG_ERROR
, "Failed to create image for "
904 "surface %#x: %d (%s).\n",
905 surface_id
, vas
, vaErrorStr(vas
));
909 if (!(flags
& AV_HWFRAME_MAP_OVERWRITE
)) {
910 vas
= vaGetImage(hwctx
->display
, surface_id
, 0, 0,
911 hwfc
->width
, hwfc
->height
, map
->image
.image_id
);
912 if (vas
!= VA_STATUS_SUCCESS
) {
913 av_log(hwfc
, AV_LOG_ERROR
, "Failed to read image from "
914 "surface %#x: %d (%s).\n",
915 surface_id
, vas
, vaErrorStr(vas
));
922 #if VA_CHECK_VERSION(1, 21, 0)
923 if (flags
& AV_HWFRAME_MAP_READ
)
924 vaflags
|= VA_MAPBUFFER_FLAG_READ
;
925 if (flags
& AV_HWFRAME_MAP_WRITE
)
926 vaflags
|= VA_MAPBUFFER_FLAG_WRITE
;
927 // On drivers not implementing vaMapBuffer2 libva calls vaMapBuffer instead.
928 vas
= vaMapBuffer2(hwctx
->display
, map
->image
.buf
, &address
, vaflags
);
930 vas
= vaMapBuffer(hwctx
->display
, map
->image
.buf
, &address
);
932 if (vas
!= VA_STATUS_SUCCESS
) {
933 av_log(hwfc
, AV_LOG_ERROR
, "Failed to map image from surface "
934 "%#x: %d (%s).\n", surface_id
, vas
, vaErrorStr(vas
));
939 err
= ff_hwframe_map_create(src
->hw_frames_ctx
,
940 dst
, src
, &vaapi_unmap_frame
, map
);
944 dst
->width
= src
->width
;
945 dst
->height
= src
->height
;
947 for (i
= 0; i
< map
->image
.num_planes
; i
++) {
948 dst
->data
[i
] = (uint8_t*)address
+ map
->image
.offsets
[i
];
949 dst
->linesize
[i
] = map
->image
.pitches
[i
];
952 desc
= vaapi_format_from_fourcc(map
->image
.format
.fourcc
);
953 if (desc
&& desc
->chroma_planes_swapped
) {
954 // Chroma planes are YVU rather than YUV, so swap them.
955 FFSWAP(uint8_t*, dst
->data
[1], dst
->data
[2]);
963 vaUnmapBuffer(hwctx
->display
, map
->image
.buf
);
964 if (map
->image
.image_id
!= VA_INVALID_ID
)
965 vaDestroyImage(hwctx
->display
, map
->image
.image_id
);
971 static int vaapi_transfer_data_from(AVHWFramesContext
*hwfc
,
972 AVFrame
*dst
, const AVFrame
*src
)
977 if (dst
->width
> hwfc
->width
|| dst
->height
> hwfc
->height
)
978 return AVERROR(EINVAL
);
980 map
= av_frame_alloc();
982 return AVERROR(ENOMEM
);
983 map
->format
= dst
->format
;
985 err
= vaapi_map_frame(hwfc
, map
, src
, AV_HWFRAME_MAP_READ
);
989 map
->width
= dst
->width
;
990 map
->height
= dst
->height
;
992 err
= av_frame_copy(dst
, map
);
1002 static int vaapi_transfer_data_to(AVHWFramesContext
*hwfc
,
1003 AVFrame
*dst
, const AVFrame
*src
)
1008 if (src
->width
> hwfc
->width
|| src
->height
> hwfc
->height
)
1009 return AVERROR(EINVAL
);
1011 map
= av_frame_alloc();
1013 return AVERROR(ENOMEM
);
1014 map
->format
= src
->format
;
1016 err
= vaapi_map_frame(hwfc
, map
, dst
, AV_HWFRAME_MAP_WRITE
| AV_HWFRAME_MAP_OVERWRITE
);
1020 map
->width
= src
->width
;
1021 map
->height
= src
->height
;
1023 err
= av_frame_copy(map
, src
);
1029 av_frame_free(&map
);
1033 static int vaapi_map_to_memory(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
1034 const AVFrame
*src
, int flags
)
1038 err
= vaapi_map_frame(hwfc
, dst
, src
, flags
);
1042 err
= av_frame_copy_props(dst
, src
);
1051 #define DRM_MAP(va, layers, ...) { \
1056 static const struct {
1058 int nb_layer_formats
;
1059 uint32_t layer_formats
[AV_DRM_MAX_PLANES
];
1060 } vaapi_drm_format_map
[] = {
1061 #ifdef DRM_FORMAT_R8
1062 DRM_MAP(NV12
, 2, DRM_FORMAT_R8
, DRM_FORMAT_RG88
),
1063 DRM_MAP(NV12
, 2, DRM_FORMAT_R8
, DRM_FORMAT_GR88
),
1065 DRM_MAP(NV12
, 1, DRM_FORMAT_NV12
),
1066 #if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16)
1067 DRM_MAP(P010
, 2, DRM_FORMAT_R16
, DRM_FORMAT_RG1616
),
1069 #if defined(VA_FOURCC_P012) && defined(DRM_FORMAT_R16)
1070 DRM_MAP(P012
, 2, DRM_FORMAT_R16
, DRM_FORMAT_RG1616
),
1072 DRM_MAP(BGRA
, 1, DRM_FORMAT_ARGB8888
),
1073 DRM_MAP(BGRX
, 1, DRM_FORMAT_XRGB8888
),
1074 DRM_MAP(RGBA
, 1, DRM_FORMAT_ABGR8888
),
1075 DRM_MAP(RGBX
, 1, DRM_FORMAT_XBGR8888
),
1076 #ifdef VA_FOURCC_ABGR
1077 DRM_MAP(ABGR
, 1, DRM_FORMAT_RGBA8888
),
1078 DRM_MAP(XBGR
, 1, DRM_FORMAT_RGBX8888
),
1080 DRM_MAP(ARGB
, 1, DRM_FORMAT_BGRA8888
),
1081 DRM_MAP(XRGB
, 1, DRM_FORMAT_BGRX8888
),
1082 #if defined(VA_FOURCC_XYUV) && defined(DRM_FORMAT_XYUV8888)
1083 DRM_MAP(XYUV
, 1, DRM_FORMAT_XYUV8888
),
1085 #if defined(VA_FOURCC_Y412) && defined(DRM_FORMAT_XVYU2101010)
1086 DRM_MAP(Y410
, 1, DRM_FORMAT_XVYU2101010
),
1088 #if defined(VA_FOURCC_Y412) && defined(DRM_FORMAT_XVYU12_16161616)
1089 DRM_MAP(Y412
, 1, DRM_FORMAT_XVYU12_16161616
),
1091 #if defined(VA_FOURCC_X2R10G10B10) && defined(DRM_FORMAT_XRGB2101010)
1092 DRM_MAP(X2R10G10B10
, 1, DRM_FORMAT_XRGB2101010
),
1097 static void vaapi_unmap_from_drm(AVHWFramesContext
*dst_fc
,
1098 HWMapDescriptor
*hwmap
)
1100 AVVAAPIDeviceContext
*dst_dev
= dst_fc
->device_ctx
->hwctx
;
1102 VASurfaceID surface_id
= (VASurfaceID
)(uintptr_t)hwmap
->priv
;
1104 av_log(dst_fc
, AV_LOG_DEBUG
, "Destroy surface %#x.\n", surface_id
);
1106 vaDestroySurfaces(dst_dev
->display
, &surface_id
, 1);
1109 static int vaapi_map_from_drm(AVHWFramesContext
*src_fc
, AVFrame
*dst
,
1110 const AVFrame
*src
, int flags
)
1112 #if VA_CHECK_VERSION(1, 1, 0)
1113 VAAPIFramesContext
*src_vafc
= src_fc
->hwctx
;
1118 AVHWFramesContext
*dst_fc
=
1119 (AVHWFramesContext
*)dst
->hw_frames_ctx
->data
;
1120 AVVAAPIDeviceContext
*dst_dev
= dst_fc
->device_ctx
->hwctx
;
1121 const AVDRMFrameDescriptor
*desc
;
1122 const VAAPIFormatDescriptor
*format_desc
;
1123 VASurfaceID surface_id
;
1124 VAStatus vas
= VA_STATUS_SUCCESS
;
1128 #if !VA_CHECK_VERSION(1, 1, 0)
1129 unsigned long buffer_handle
;
1130 VASurfaceAttribExternalBuffers buffer_desc
;
1131 VASurfaceAttrib attrs
[2] = {
1133 .type
= VASurfaceAttribMemoryType
,
1134 .flags
= VA_SURFACE_ATTRIB_SETTABLE
,
1135 .value
.type
= VAGenericValueTypeInteger
,
1136 .value
.value
.i
= VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME
,
1139 .type
= VASurfaceAttribExternalBufferDescriptor
,
1140 .flags
= VA_SURFACE_ATTRIB_SETTABLE
,
1141 .value
.type
= VAGenericValueTypePointer
,
1142 .value
.value
.p
= &buffer_desc
,
1147 desc
= (AVDRMFrameDescriptor
*)src
->data
[0];
1149 if (desc
->nb_objects
!= 1) {
1150 av_log(dst_fc
, AV_LOG_ERROR
, "VAAPI can only map frames "
1151 "made from a single DRM object.\n");
1152 return AVERROR(EINVAL
);
1156 for (i
= 0; i
< FF_ARRAY_ELEMS(vaapi_drm_format_map
); i
++) {
1157 if (desc
->nb_layers
!= vaapi_drm_format_map
[i
].nb_layer_formats
)
1159 for (j
= 0; j
< desc
->nb_layers
; j
++) {
1160 if (desc
->layers
[j
].format
!=
1161 vaapi_drm_format_map
[i
].layer_formats
[j
])
1164 if (j
!= desc
->nb_layers
)
1166 va_fourcc
= vaapi_drm_format_map
[i
].va_fourcc
;
1170 av_log(dst_fc
, AV_LOG_ERROR
, "DRM format not supported "
1172 return AVERROR(EINVAL
);
1175 av_log(dst_fc
, AV_LOG_DEBUG
, "Map DRM object %d to VAAPI as "
1176 "%08x.\n", desc
->objects
[0].fd
, va_fourcc
);
1178 format_desc
= vaapi_format_from_fourcc(va_fourcc
);
1179 av_assert0(format_desc
);
1181 #if VA_CHECK_VERSION(1, 1, 0)
1182 use_prime2
= !src_vafc
->prime_2_import_unsupported
&&
1183 desc
->objects
[0].format_modifier
!= DRM_FORMAT_MOD_INVALID
;
1185 VADRMPRIMESurfaceDescriptor prime_desc
;
1186 VASurfaceAttrib prime_attrs
[2] = {
1188 .type
= VASurfaceAttribMemoryType
,
1189 .flags
= VA_SURFACE_ATTRIB_SETTABLE
,
1190 .value
.type
= VAGenericValueTypeInteger
,
1191 .value
.value
.i
= VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2
,
1194 .type
= VASurfaceAttribExternalBufferDescriptor
,
1195 .flags
= VA_SURFACE_ATTRIB_SETTABLE
,
1196 .value
.type
= VAGenericValueTypePointer
,
1197 .value
.value
.p
= &prime_desc
,
1200 prime_desc
.fourcc
= va_fourcc
;
1201 prime_desc
.width
= src_fc
->width
;
1202 prime_desc
.height
= src_fc
->height
;
1203 prime_desc
.num_objects
= desc
->nb_objects
;
1204 for (i
= 0; i
< desc
->nb_objects
; ++i
) {
1205 prime_desc
.objects
[i
].fd
= desc
->objects
[i
].fd
;
1206 prime_desc
.objects
[i
].size
= desc
->objects
[i
].size
;
1207 prime_desc
.objects
[i
].drm_format_modifier
=
1208 desc
->objects
[i
].format_modifier
;
1211 prime_desc
.num_layers
= desc
->nb_layers
;
1212 for (i
= 0; i
< desc
->nb_layers
; ++i
) {
1213 prime_desc
.layers
[i
].drm_format
= desc
->layers
[i
].format
;
1214 prime_desc
.layers
[i
].num_planes
= desc
->layers
[i
].nb_planes
;
1215 for (j
= 0; j
< desc
->layers
[i
].nb_planes
; ++j
) {
1216 prime_desc
.layers
[i
].object_index
[j
] =
1217 desc
->layers
[i
].planes
[j
].object_index
;
1218 prime_desc
.layers
[i
].offset
[j
] = desc
->layers
[i
].planes
[j
].offset
;
1219 prime_desc
.layers
[i
].pitch
[j
] = desc
->layers
[i
].planes
[j
].pitch
;
1222 if (format_desc
->chroma_planes_swapped
&&
1223 desc
->layers
[i
].nb_planes
== 3) {
1224 FFSWAP(uint32_t, prime_desc
.layers
[i
].pitch
[1],
1225 prime_desc
.layers
[i
].pitch
[2]);
1226 FFSWAP(uint32_t, prime_desc
.layers
[i
].offset
[1],
1227 prime_desc
.layers
[i
].offset
[2]);
1232 * We can query for PRIME_2 support with vaQuerySurfaceAttributes, but that
1233 * that needs the config_id which we don't have here . Both Intel and
1234 * Gallium seem to do the correct error checks, so lets just try the
1235 * PRIME_2 import first.
1237 vas
= vaCreateSurfaces(dst_dev
->display
, format_desc
->rt_format
,
1238 src
->width
, src
->height
, &surface_id
, 1,
1239 prime_attrs
, FF_ARRAY_ELEMS(prime_attrs
));
1240 if (vas
!= VA_STATUS_SUCCESS
)
1241 src_vafc
->prime_2_import_unsupported
= 1;
1244 if (!use_prime2
|| vas
!= VA_STATUS_SUCCESS
) {
1246 uintptr_t buffer_handle
;
1247 VASurfaceAttribExternalBuffers buffer_desc
;
1248 VASurfaceAttrib buffer_attrs
[2] = {
1250 .type
= VASurfaceAttribMemoryType
,
1251 .flags
= VA_SURFACE_ATTRIB_SETTABLE
,
1252 .value
.type
= VAGenericValueTypeInteger
,
1253 .value
.value
.i
= VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME
,
1256 .type
= VASurfaceAttribExternalBufferDescriptor
,
1257 .flags
= VA_SURFACE_ATTRIB_SETTABLE
,
1258 .value
.type
= VAGenericValueTypePointer
,
1259 .value
.value
.p
= &buffer_desc
,
1263 buffer_handle
= desc
->objects
[0].fd
;
1264 buffer_desc
.pixel_format
= va_fourcc
;
1265 buffer_desc
.width
= src_fc
->width
;
1266 buffer_desc
.height
= src_fc
->height
;
1267 buffer_desc
.data_size
= desc
->objects
[0].size
;
1268 buffer_desc
.buffers
= &buffer_handle
;
1269 buffer_desc
.num_buffers
= 1;
1270 buffer_desc
.flags
= 0;
1273 for (i
= 0; i
< desc
->nb_layers
; i
++) {
1274 for (j
= 0; j
< desc
->layers
[i
].nb_planes
; j
++) {
1275 buffer_desc
.pitches
[k
] = desc
->layers
[i
].planes
[j
].pitch
;
1276 buffer_desc
.offsets
[k
] = desc
->layers
[i
].planes
[j
].offset
;
1280 buffer_desc
.num_planes
= k
;
1282 if (format_desc
->chroma_planes_swapped
&&
1283 buffer_desc
.num_planes
== 3) {
1284 FFSWAP(uint32_t, buffer_desc
.pitches
[1], buffer_desc
.pitches
[2]);
1285 FFSWAP(uint32_t, buffer_desc
.offsets
[1], buffer_desc
.offsets
[2]);
1288 vas
= vaCreateSurfaces(dst_dev
->display
, format_desc
->rt_format
,
1289 src
->width
, src
->height
,
1291 buffer_attrs
, FF_ARRAY_ELEMS(buffer_attrs
));
1294 buffer_handle
= desc
->objects
[0].fd
;
1295 buffer_desc
.pixel_format
= va_fourcc
;
1296 buffer_desc
.width
= src_fc
->width
;
1297 buffer_desc
.height
= src_fc
->height
;
1298 buffer_desc
.data_size
= desc
->objects
[0].size
;
1299 buffer_desc
.buffers
= &buffer_handle
;
1300 buffer_desc
.num_buffers
= 1;
1301 buffer_desc
.flags
= 0;
1304 for (i
= 0; i
< desc
->nb_layers
; i
++) {
1305 for (j
= 0; j
< desc
->layers
[i
].nb_planes
; j
++) {
1306 buffer_desc
.pitches
[k
] = desc
->layers
[i
].planes
[j
].pitch
;
1307 buffer_desc
.offsets
[k
] = desc
->layers
[i
].planes
[j
].offset
;
1311 buffer_desc
.num_planes
= k
;
1313 if (format_desc
->chroma_planes_swapped
&&
1314 buffer_desc
.num_planes
== 3) {
1315 FFSWAP(uint32_t, buffer_desc
.pitches
[1], buffer_desc
.pitches
[2]);
1316 FFSWAP(uint32_t, buffer_desc
.offsets
[1], buffer_desc
.offsets
[2]);
1319 vas
= vaCreateSurfaces(dst_dev
->display
, format_desc
->rt_format
,
1320 src
->width
, src
->height
,
1322 attrs
, FF_ARRAY_ELEMS(attrs
));
1324 if (vas
!= VA_STATUS_SUCCESS
) {
1325 av_log(dst_fc
, AV_LOG_ERROR
, "Failed to create surface from DRM "
1326 "object: %d (%s).\n", vas
, vaErrorStr(vas
));
1327 return AVERROR(EIO
);
1329 av_log(dst_fc
, AV_LOG_DEBUG
, "Create surface %#x.\n", surface_id
);
1331 err
= ff_hwframe_map_create(dst
->hw_frames_ctx
, dst
, src
,
1332 &vaapi_unmap_from_drm
,
1333 (void*)(uintptr_t)surface_id
);
1337 dst
->width
= src
->width
;
1338 dst
->height
= src
->height
;
1339 dst
->data
[3] = (uint8_t*)(uintptr_t)surface_id
;
1341 av_log(dst_fc
, AV_LOG_DEBUG
, "Mapped DRM object %d to "
1342 "surface %#x.\n", desc
->objects
[0].fd
, surface_id
);
1347 #if VA_CHECK_VERSION(1, 1, 0)
1348 static void vaapi_unmap_to_drm_esh(AVHWFramesContext
*hwfc
,
1349 HWMapDescriptor
*hwmap
)
1351 AVDRMFrameDescriptor
*drm_desc
= hwmap
->priv
;
1354 for (i
= 0; i
< drm_desc
->nb_objects
; i
++)
1355 close(drm_desc
->objects
[i
].fd
);
1357 av_freep(&drm_desc
);
1360 static int vaapi_map_to_drm_esh(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
1361 const AVFrame
*src
, int flags
)
1363 AVVAAPIDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
1364 VASurfaceID surface_id
;
1366 VADRMPRIMESurfaceDescriptor va_desc
;
1367 AVDRMFrameDescriptor
*drm_desc
= NULL
;
1368 uint32_t export_flags
;
1371 surface_id
= (VASurfaceID
)(uintptr_t)src
->data
[3];
1373 export_flags
= VA_EXPORT_SURFACE_SEPARATE_LAYERS
;
1374 if (flags
& AV_HWFRAME_MAP_READ
) {
1375 export_flags
|= VA_EXPORT_SURFACE_READ_ONLY
;
1377 vas
= vaSyncSurface(hwctx
->display
, surface_id
);
1378 if (vas
!= VA_STATUS_SUCCESS
) {
1379 av_log(hwfc
, AV_LOG_ERROR
, "Failed to sync surface "
1380 "%#x: %d (%s).\n", surface_id
, vas
, vaErrorStr(vas
));
1381 return AVERROR(EIO
);
1385 if (flags
& AV_HWFRAME_MAP_WRITE
)
1386 export_flags
|= VA_EXPORT_SURFACE_WRITE_ONLY
;
1388 vas
= vaExportSurfaceHandle(hwctx
->display
, surface_id
,
1389 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2
,
1390 export_flags
, &va_desc
);
1391 if (vas
!= VA_STATUS_SUCCESS
) {
1392 if (vas
== VA_STATUS_ERROR_UNIMPLEMENTED
)
1393 return AVERROR(ENOSYS
);
1394 av_log(hwfc
, AV_LOG_ERROR
, "Failed to export surface %#x: "
1395 "%d (%s).\n", surface_id
, vas
, vaErrorStr(vas
));
1396 return AVERROR(EIO
);
1399 drm_desc
= av_mallocz(sizeof(*drm_desc
));
1401 err
= AVERROR(ENOMEM
);
1405 // By some bizarre coincidence, these structures are very similar...
1406 drm_desc
->nb_objects
= va_desc
.num_objects
;
1407 for (i
= 0; i
< va_desc
.num_objects
; i
++) {
1408 drm_desc
->objects
[i
].fd
= va_desc
.objects
[i
].fd
;
1409 drm_desc
->objects
[i
].size
= va_desc
.objects
[i
].size
;
1410 drm_desc
->objects
[i
].format_modifier
=
1411 va_desc
.objects
[i
].drm_format_modifier
;
1413 drm_desc
->nb_layers
= va_desc
.num_layers
;
1414 for (i
= 0; i
< va_desc
.num_layers
; i
++) {
1415 drm_desc
->layers
[i
].format
= va_desc
.layers
[i
].drm_format
;
1416 drm_desc
->layers
[i
].nb_planes
= va_desc
.layers
[i
].num_planes
;
1417 for (j
= 0; j
< va_desc
.layers
[i
].num_planes
; j
++) {
1418 drm_desc
->layers
[i
].planes
[j
].object_index
=
1419 va_desc
.layers
[i
].object_index
[j
];
1420 drm_desc
->layers
[i
].planes
[j
].offset
=
1421 va_desc
.layers
[i
].offset
[j
];
1422 drm_desc
->layers
[i
].planes
[j
].pitch
=
1423 va_desc
.layers
[i
].pitch
[j
];
1427 err
= ff_hwframe_map_create(src
->hw_frames_ctx
, dst
, src
,
1428 &vaapi_unmap_to_drm_esh
, drm_desc
);
1432 dst
->width
= src
->width
;
1433 dst
->height
= src
->height
;
1434 dst
->data
[0] = (uint8_t*)drm_desc
;
1439 for (i
= 0; i
< va_desc
.num_objects
; i
++)
1440 close(va_desc
.objects
[i
].fd
);
1441 av_freep(&drm_desc
);
1446 #if VA_CHECK_VERSION(0, 36, 0)
1447 typedef struct VAAPIDRMImageBufferMapping
{
1449 VABufferInfo buffer_info
;
1451 AVDRMFrameDescriptor drm_desc
;
1452 } VAAPIDRMImageBufferMapping
;
1454 static void vaapi_unmap_to_drm_abh(AVHWFramesContext
*hwfc
,
1455 HWMapDescriptor
*hwmap
)
1457 AVVAAPIDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
1458 VAAPIDRMImageBufferMapping
*mapping
= hwmap
->priv
;
1459 VASurfaceID surface_id
;
1462 surface_id
= (VASurfaceID
)(uintptr_t)hwmap
->source
->data
[3];
1463 av_log(hwfc
, AV_LOG_DEBUG
, "Unmap VAAPI surface %#x from DRM.\n",
1466 // DRM PRIME file descriptors are closed by vaReleaseBufferHandle(),
1467 // so we shouldn't close them separately.
1469 vas
= vaReleaseBufferHandle(hwctx
->display
, mapping
->image
.buf
);
1470 if (vas
!= VA_STATUS_SUCCESS
) {
1471 av_log(hwfc
, AV_LOG_ERROR
, "Failed to release buffer "
1472 "handle of image %#x (derived from surface %#x): "
1473 "%d (%s).\n", mapping
->image
.buf
, surface_id
,
1474 vas
, vaErrorStr(vas
));
1477 vas
= vaDestroyImage(hwctx
->display
, mapping
->image
.image_id
);
1478 if (vas
!= VA_STATUS_SUCCESS
) {
1479 av_log(hwfc
, AV_LOG_ERROR
, "Failed to destroy image "
1480 "derived from surface %#x: %d (%s).\n",
1481 surface_id
, vas
, vaErrorStr(vas
));
1487 static int vaapi_map_to_drm_abh(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
1488 const AVFrame
*src
, int flags
)
1490 AVVAAPIDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
1491 VAAPIDRMImageBufferMapping
*mapping
= NULL
;
1492 VASurfaceID surface_id
;
1496 surface_id
= (VASurfaceID
)(uintptr_t)src
->data
[3];
1497 av_log(hwfc
, AV_LOG_DEBUG
, "Map VAAPI surface %#x to DRM.\n",
1500 mapping
= av_mallocz(sizeof(*mapping
));
1502 return AVERROR(ENOMEM
);
1504 vas
= vaDeriveImage(hwctx
->display
, surface_id
,
1506 if (vas
!= VA_STATUS_SUCCESS
) {
1507 av_log(hwfc
, AV_LOG_ERROR
, "Failed to derive image from "
1508 "surface %#x: %d (%s).\n",
1509 surface_id
, vas
, vaErrorStr(vas
));
1514 for (i
= 0; i
< FF_ARRAY_ELEMS(vaapi_drm_format_map
); i
++) {
1515 if (vaapi_drm_format_map
[i
].va_fourcc
==
1516 mapping
->image
.format
.fourcc
)
1519 if (i
>= FF_ARRAY_ELEMS(vaapi_drm_format_map
)) {
1520 av_log(hwfc
, AV_LOG_ERROR
, "No matching DRM format for "
1521 "VAAPI format %#x.\n", mapping
->image
.format
.fourcc
);
1522 err
= AVERROR(EINVAL
);
1526 mapping
->buffer_info
.mem_type
=
1527 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME
;
1529 mapping
->drm_desc
.nb_layers
=
1530 vaapi_drm_format_map
[i
].nb_layer_formats
;
1531 if (mapping
->drm_desc
.nb_layers
> 1) {
1532 if (mapping
->drm_desc
.nb_layers
!= mapping
->image
.num_planes
) {
1533 av_log(hwfc
, AV_LOG_ERROR
, "Image properties do not match "
1534 "expected format: got %d planes, but expected %d.\n",
1535 mapping
->image
.num_planes
, mapping
->drm_desc
.nb_layers
);
1536 err
= AVERROR(EINVAL
);
1540 for(p
= 0; p
< mapping
->drm_desc
.nb_layers
; p
++) {
1541 mapping
->drm_desc
.layers
[p
] = (AVDRMLayerDescriptor
) {
1542 .format
= vaapi_drm_format_map
[i
].layer_formats
[p
],
1546 .offset
= mapping
->image
.offsets
[p
],
1547 .pitch
= mapping
->image
.pitches
[p
],
1552 mapping
->drm_desc
.layers
[0].format
=
1553 vaapi_drm_format_map
[i
].layer_formats
[0];
1554 mapping
->drm_desc
.layers
[0].nb_planes
= mapping
->image
.num_planes
;
1555 for (p
= 0; p
< mapping
->image
.num_planes
; p
++) {
1556 mapping
->drm_desc
.layers
[0].planes
[p
] = (AVDRMPlaneDescriptor
) {
1558 .offset
= mapping
->image
.offsets
[p
],
1559 .pitch
= mapping
->image
.pitches
[p
],
1564 vas
= vaAcquireBufferHandle(hwctx
->display
, mapping
->image
.buf
,
1565 &mapping
->buffer_info
);
1566 if (vas
!= VA_STATUS_SUCCESS
) {
1567 av_log(hwfc
, AV_LOG_ERROR
, "Failed to get buffer "
1568 "handle from image %#x (derived from surface %#x): "
1569 "%d (%s).\n", mapping
->image
.buf
, surface_id
,
1570 vas
, vaErrorStr(vas
));
1575 av_log(hwfc
, AV_LOG_DEBUG
, "DRM PRIME fd is %"PRIdPTR
".\n",
1576 mapping
->buffer_info
.handle
);
1578 mapping
->drm_desc
.nb_objects
= 1;
1579 mapping
->drm_desc
.objects
[0] = (AVDRMObjectDescriptor
) {
1580 .fd
= mapping
->buffer_info
.handle
,
1581 .size
= mapping
->image
.data_size
,
1582 // There is no way to get the format modifier with this API.
1583 .format_modifier
= DRM_FORMAT_MOD_INVALID
,
1586 err
= ff_hwframe_map_create(src
->hw_frames_ctx
,
1587 dst
, src
, &vaapi_unmap_to_drm_abh
,
1592 dst
->data
[0] = (uint8_t*)&mapping
->drm_desc
;
1593 dst
->width
= src
->width
;
1594 dst
->height
= src
->height
;
1599 vaReleaseBufferHandle(hwctx
->display
, mapping
->image
.buf
);
1601 vaDestroyImage(hwctx
->display
, mapping
->image
.image_id
);
1608 static int vaapi_map_to_drm(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
1609 const AVFrame
*src
, int flags
)
1611 #if VA_CHECK_VERSION(1, 1, 0)
1613 err
= vaapi_map_to_drm_esh(hwfc
, dst
, src
, flags
);
1614 if (err
!= AVERROR(ENOSYS
))
1617 #if VA_CHECK_VERSION(0, 36, 0)
1618 return vaapi_map_to_drm_abh(hwfc
, dst
, src
, flags
);
1620 return AVERROR(ENOSYS
);
1623 #endif /* CONFIG_LIBDRM */
1625 static int vaapi_map_to(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
1626 const AVFrame
*src
, int flags
)
1628 switch (src
->format
) {
1630 case AV_PIX_FMT_DRM_PRIME
:
1631 return vaapi_map_from_drm(hwfc
, dst
, src
, flags
);
1634 return AVERROR(ENOSYS
);
1638 static int vaapi_map_from(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
1639 const AVFrame
*src
, int flags
)
1641 switch (dst
->format
) {
1643 case AV_PIX_FMT_DRM_PRIME
:
1644 return vaapi_map_to_drm(hwfc
, dst
, src
, flags
);
1647 return vaapi_map_to_memory(hwfc
, dst
, src
, flags
);
1651 static void vaapi_device_free(AVHWDeviceContext
*ctx
)
1653 AVVAAPIDeviceContext
*hwctx
= ctx
->hwctx
;
1654 VAAPIDevicePriv
*priv
= ctx
->user_opaque
;
1657 vaTerminate(hwctx
->display
);
1660 if (priv
->x11_display
)
1661 XCloseDisplay(priv
->x11_display
);
1664 if (priv
->drm_fd
>= 0)
1665 close(priv
->drm_fd
);
1671 static void vaapi_device_log_error(void *context
, const char *message
)
1673 AVHWDeviceContext
*ctx
= context
;
1675 av_log(ctx
, AV_LOG_ERROR
, "libva: %s", message
);
1678 static void vaapi_device_log_info(void *context
, const char *message
)
1680 AVHWDeviceContext
*ctx
= context
;
1682 av_log(ctx
, AV_LOG_VERBOSE
, "libva: %s", message
);
1686 static int vaapi_device_connect(AVHWDeviceContext
*ctx
,
1689 AVVAAPIDeviceContext
*hwctx
= ctx
->hwctx
;
1694 vaSetErrorCallback(display
, &vaapi_device_log_error
, ctx
);
1695 vaSetInfoCallback (display
, &vaapi_device_log_info
, ctx
);
1698 hwctx
->display
= display
;
1700 vas
= vaInitialize(display
, &major
, &minor
);
1701 if (vas
!= VA_STATUS_SUCCESS
) {
1702 av_log(ctx
, AV_LOG_ERROR
, "Failed to initialise VAAPI "
1703 "connection: %d (%s).\n", vas
, vaErrorStr(vas
));
1704 return AVERROR(EIO
);
1706 av_log(ctx
, AV_LOG_VERBOSE
, "Initialised VAAPI connection: "
1707 "version %d.%d\n", major
, minor
);
1712 static int vaapi_device_create(AVHWDeviceContext
*ctx
, const char *device
,
1713 AVDictionary
*opts
, int flags
)
1715 VAAPIDevicePriv
*priv
;
1716 VADisplay display
= NULL
;
1717 const AVDictionaryEntry
*ent
;
1718 int try_drm
, try_x11
, try_win32
, try_all
;
1720 priv
= av_mallocz(sizeof(*priv
));
1722 return AVERROR(ENOMEM
);
1726 ctx
->user_opaque
= priv
;
1727 ctx
->free
= vaapi_device_free
;
1729 ent
= av_dict_get(opts
, "connection_type", NULL
, 0);
1731 try_all
= try_drm
= try_x11
= try_win32
= 0;
1732 if (!strcmp(ent
->value
, "drm")) {
1734 } else if (!strcmp(ent
->value
, "x11")) {
1736 } else if (!strcmp(ent
->value
, "win32")) {
1739 av_log(ctx
, AV_LOG_ERROR
, "Invalid connection type %s.\n",
1741 return AVERROR(EINVAL
);
1745 try_drm
= HAVE_VAAPI_DRM
;
1746 try_x11
= HAVE_VAAPI_X11
;
1747 try_win32
= HAVE_VAAPI_WIN32
;
1751 while (!display
&& try_drm
) {
1752 // If the device is specified, try to open it as a DRM device node.
1753 // If not, look for a usable render node, possibly restricted to those
1754 // using a specified kernel driver.
1755 int loglevel
= try_all
? AV_LOG_VERBOSE
: AV_LOG_ERROR
;
1757 priv
->drm_fd
= open(device
, O_RDWR
);
1758 if (priv
->drm_fd
< 0) {
1759 av_log(ctx
, loglevel
, "Failed to open %s as "
1760 "DRM device node.\n", device
);
1765 int n
, max_devices
= 8;
1768 const AVDictionaryEntry
*kernel_driver
;
1769 const AVDictionaryEntry
*vendor_id
;
1770 kernel_driver
= av_dict_get(opts
, "kernel_driver", NULL
, 0);
1771 vendor_id
= av_dict_get(opts
, "vendor_id", NULL
, 0);
1773 for (n
= 0; n
< max_devices
; n
++) {
1774 snprintf(path
, sizeof(path
),
1775 "/dev/dri/renderD%d", 128 + n
);
1776 priv
->drm_fd
= open(path
, O_RDWR
);
1777 if (priv
->drm_fd
< 0) {
1778 if (errno
== ENOENT
) {
1779 if (n
!= max_devices
- 1) {
1780 av_log(ctx
, AV_LOG_VERBOSE
,
1781 "No render device %s, try next device for "
1782 "DRM render node.\n", path
);
1786 av_log(ctx
, AV_LOG_VERBOSE
, "No available render device "
1787 "for DRM render node.\n");
1789 av_log(ctx
, AV_LOG_VERBOSE
, "Cannot open "
1790 "DRM render node for device %d.\n", n
);
1794 info
= drmGetVersion(priv
->drm_fd
);
1796 av_log(ctx
, AV_LOG_VERBOSE
,
1797 "Failed to get DRM version for device %d.\n", n
);
1798 close(priv
->drm_fd
);
1802 if (kernel_driver
) {
1803 if (strcmp(kernel_driver
->value
, info
->name
)) {
1804 av_log(ctx
, AV_LOG_VERBOSE
, "Ignoring device %d "
1805 "with non-matching kernel driver (%s).\n",
1807 drmFreeVersion(info
);
1808 close(priv
->drm_fd
);
1812 av_log(ctx
, AV_LOG_VERBOSE
, "Trying to use "
1813 "DRM render node for device %d, "
1814 "with matching kernel driver (%s).\n",
1816 drmFreeVersion(info
);
1818 // drmGetVersion() ensures |info->name| is 0-terminated.
1819 } else if (!strcmp(info
->name
, "vgem")) {
1820 av_log(ctx
, AV_LOG_VERBOSE
,
1821 "Skipping vgem node for device %d.\n", n
);
1822 drmFreeVersion(info
);
1823 close(priv
->drm_fd
);
1826 } else if (vendor_id
) {
1827 drmDevicePtr device
;
1829 if (drmGetDevice(priv
->drm_fd
, &device
)) {
1830 av_log(ctx
, AV_LOG_VERBOSE
,
1831 "Failed to get DRM device info for device %d.\n", n
);
1832 close(priv
->drm_fd
);
1834 drmFreeVersion(info
);
1838 snprintf(drm_vendor
, sizeof(drm_vendor
), "0x%x", device
->deviceinfo
.pci
->vendor_id
);
1839 if (strcmp(vendor_id
->value
, drm_vendor
)) {
1840 av_log(ctx
, AV_LOG_VERBOSE
, "Ignoring device %d "
1841 "with non-matching vendor id (%s).\n",
1842 n
, vendor_id
->value
);
1843 drmFreeDevice(&device
);
1844 close(priv
->drm_fd
);
1846 drmFreeVersion(info
);
1849 av_log(ctx
, AV_LOG_VERBOSE
, "Trying to use "
1850 "DRM render node for device %d, "
1851 "with matching vendor id (%s).\n",
1852 n
, vendor_id
->value
);
1853 drmFreeDevice(&device
);
1854 drmFreeVersion(info
);
1857 drmFreeVersion(info
);
1859 av_log(ctx
, AV_LOG_VERBOSE
, "Trying to use "
1860 "DRM render node for device %d.\n", n
);
1863 if (n
>= max_devices
)
1867 display
= vaGetDisplayDRM(priv
->drm_fd
);
1869 av_log(ctx
, AV_LOG_VERBOSE
, "Cannot open a VA display "
1870 "from DRM device %s.\n", device
);
1871 return AVERROR_EXTERNAL
;
1878 if (!display
&& try_x11
) {
1879 // Try to open the device as an X11 display.
1880 priv
->x11_display
= XOpenDisplay(device
);
1881 if (!priv
->x11_display
) {
1882 av_log(ctx
, AV_LOG_VERBOSE
, "Cannot open X11 display "
1883 "%s.\n", XDisplayName(device
));
1885 display
= vaGetDisplay(priv
->x11_display
);
1887 av_log(ctx
, AV_LOG_ERROR
, "Cannot open a VA display "
1888 "from X11 display %s.\n", XDisplayName(device
));
1889 return AVERROR_UNKNOWN
;
1892 av_log(ctx
, AV_LOG_VERBOSE
, "Opened VA display via "
1893 "X11 display %s.\n", XDisplayName(device
));
1898 #if HAVE_VAAPI_WIN32
1899 if (!display
&& try_win32
) {
1900 // Try to create a display from the specified device, if any.
1902 display
= vaGetDisplayWin32(NULL
);
1904 IDXGIFactory2
*pDXGIFactory
= NULL
;
1905 IDXGIAdapter
*pAdapter
= NULL
;
1907 HANDLE dxgi
= dlopen("dxgi.dll", 0);
1909 av_log(ctx
, AV_LOG_ERROR
, "Failed to load dxgi.dll\n");
1910 return AVERROR_UNKNOWN
;
1912 PFN_CREATE_DXGI_FACTORY pfnCreateDXGIFactory
=
1913 (PFN_CREATE_DXGI_FACTORY
)dlsym(dxgi
, "CreateDXGIFactory");
1914 if (!pfnCreateDXGIFactory
) {
1915 av_log(ctx
, AV_LOG_ERROR
, "CreateDXGIFactory load failed\n");
1917 return AVERROR_UNKNOWN
;
1920 // In UWP (which lacks LoadLibrary), CreateDXGIFactory isn't
1921 // available, only CreateDXGIFactory1
1922 PFN_CREATE_DXGI_FACTORY pfnCreateDXGIFactory
=
1923 (PFN_CREATE_DXGI_FACTORY
)CreateDXGIFactory1
;
1925 if (SUCCEEDED(pfnCreateDXGIFactory(&IID_IDXGIFactory2
,
1926 (void **)&pDXGIFactory
))) {
1927 int adapter
= atoi(device
);
1928 if (SUCCEEDED(IDXGIFactory2_EnumAdapters(pDXGIFactory
,
1931 DXGI_ADAPTER_DESC desc
;
1932 if (SUCCEEDED(IDXGIAdapter2_GetDesc(pAdapter
, &desc
))) {
1933 av_log(ctx
, AV_LOG_INFO
,
1934 "Using device %04x:%04x (%ls) - LUID %lu %ld.\n",
1935 desc
.VendorId
, desc
.DeviceId
, desc
.Description
,
1936 desc
.AdapterLuid
.LowPart
,
1937 desc
.AdapterLuid
.HighPart
);
1938 display
= vaGetDisplayWin32(&desc
.AdapterLuid
);
1940 IDXGIAdapter_Release(pAdapter
);
1942 IDXGIFactory2_Release(pDXGIFactory
);
1950 av_log(ctx
, AV_LOG_ERROR
, "Cannot open a VA display "
1951 "from Win32 display.\n");
1952 return AVERROR_UNKNOWN
;
1955 av_log(ctx
, AV_LOG_VERBOSE
, "Opened VA display via "
1956 "Win32 display.\n");
1962 av_log(ctx
, AV_LOG_ERROR
, "No VA display found for "
1963 "device %s.\n", device
);
1965 av_log(ctx
, AV_LOG_ERROR
, "No VA display found for "
1966 "any default device.\n");
1967 return AVERROR(EINVAL
);
1970 ent
= av_dict_get(opts
, "driver", NULL
, 0);
1972 #if VA_CHECK_VERSION(0, 38, 0)
1974 vas
= vaSetDriverName(display
, ent
->value
);
1975 if (vas
!= VA_STATUS_SUCCESS
) {
1976 av_log(ctx
, AV_LOG_ERROR
, "Failed to set driver name to "
1977 "%s: %d (%s).\n", ent
->value
, vas
, vaErrorStr(vas
));
1978 vaTerminate(display
);
1979 return AVERROR_EXTERNAL
;
1982 av_log(ctx
, AV_LOG_WARNING
, "Driver name setting is not "
1983 "supported with this VAAPI version.\n");
1987 return vaapi_device_connect(ctx
, display
);
1990 static int vaapi_device_derive(AVHWDeviceContext
*ctx
,
1991 AVHWDeviceContext
*src_ctx
,
1992 AVDictionary
*opts
, int flags
)
1995 if (src_ctx
->type
== AV_HWDEVICE_TYPE_DRM
) {
1996 AVDRMDeviceContext
*src_hwctx
= src_ctx
->hwctx
;
1998 VAAPIDevicePriv
*priv
;
2001 if (src_hwctx
->fd
< 0) {
2002 av_log(ctx
, AV_LOG_ERROR
, "DRM instance requires an associated "
2003 "device to derive a VA display from.\n");
2004 return AVERROR(EINVAL
);
2009 int node_type
= drmGetNodeTypeFromFd(src_hwctx
->fd
);
2011 if (node_type
< 0) {
2012 av_log(ctx
, AV_LOG_ERROR
, "DRM instance fd does not appear "
2013 "to refer to a DRM device.\n");
2014 return AVERROR(EINVAL
);
2016 if (node_type
== DRM_NODE_RENDER
) {
2019 render_node
= drmGetRenderDeviceNameFromFd(src_hwctx
->fd
);
2021 av_log(ctx
, AV_LOG_VERBOSE
, "Using non-render node "
2022 "because the device does not have an "
2023 "associated render node.\n");
2026 fd
= open(render_node
, O_RDWR
);
2028 av_log(ctx
, AV_LOG_VERBOSE
, "Using non-render node "
2029 "because the associated render node "
2030 "could not be opened.\n");
2033 av_log(ctx
, AV_LOG_VERBOSE
, "Using render node %s "
2034 "in place of non-render DRM device.\n",
2045 priv
= av_mallocz(sizeof(*priv
));
2047 if (fd
!= src_hwctx
->fd
) {
2048 // The fd was opened in this function.
2051 return AVERROR(ENOMEM
);
2054 if (fd
== src_hwctx
->fd
) {
2055 // The fd is inherited from the source context and we are holding
2056 // a reference to that, we don't want to close it from here.
2062 ctx
->user_opaque
= priv
;
2063 ctx
->free
= &vaapi_device_free
;
2065 display
= vaGetDisplayDRM(fd
);
2067 av_log(ctx
, AV_LOG_ERROR
, "Failed to open a VA display from "
2069 return AVERROR(EIO
);
2072 return vaapi_device_connect(ctx
, display
);
2075 return AVERROR(ENOSYS
);
2078 const HWContextType ff_hwcontext_type_vaapi
= {
2079 .type
= AV_HWDEVICE_TYPE_VAAPI
,
2082 .device_hwctx_size
= sizeof(VAAPIDeviceContext
),
2083 .device_hwconfig_size
= sizeof(AVVAAPIHWConfig
),
2084 .frames_hwctx_size
= sizeof(VAAPIFramesContext
),
2086 .device_create
= &vaapi_device_create
,
2087 .device_derive
= &vaapi_device_derive
,
2088 .device_init
= &vaapi_device_init
,
2089 .device_uninit
= &vaapi_device_uninit
,
2090 .frames_get_constraints
= &vaapi_frames_get_constraints
,
2091 .frames_init
= &vaapi_frames_init
,
2092 .frames_uninit
= &vaapi_frames_uninit
,
2093 .frames_get_buffer
= &vaapi_get_buffer
,
2094 .transfer_get_formats
= &vaapi_transfer_get_formats
,
2095 .transfer_data_to
= &vaapi_transfer_data_to
,
2096 .transfer_data_from
= &vaapi_transfer_data_from
,
2097 .map_to
= &vaapi_map_to
,
2098 .map_from
= &vaapi_map_from
,
2100 .pix_fmts
= (const enum AVPixelFormat
[]) {