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>
31 # include <drm_fourcc.h>
32 # ifndef DRM_FORMAT_MOD_INVALID
33 # define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
46 #include "hwcontext.h"
47 #include "hwcontext_drm.h"
48 #include "hwcontext_internal.h"
49 #include "hwcontext_vaapi.h"
55 typedef struct VAAPIDevicePriv
{
63 typedef struct VAAPISurfaceFormat
{
64 enum AVPixelFormat pix_fmt
;
65 VAImageFormat image_format
;
68 typedef struct VAAPIDeviceContext
{
69 // Surface formats which can be used with this device.
70 VAAPISurfaceFormat
*formats
;
74 typedef struct VAAPIFramesContext
{
75 // Surface attributes set at create time.
76 VASurfaceAttrib
*attributes
;
78 // RT format of the underlying surface (Intel driver ignores this anyway).
79 unsigned int rt_format
;
80 // Whether vaDeriveImage works.
82 // Caches whether VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2 is unsupported for
84 int prime_2_import_unsupported
;
87 typedef struct VAAPIMapping
{
88 // Handle to the derived or copied image which is mapped.
90 // The mapping flags actually used.
94 typedef struct VAAPIFormat
{
96 unsigned int rt_format
;
97 enum AVPixelFormat pix_fmt
;
98 int chroma_planes_swapped
;
99 } VAAPIFormatDescriptor
;
101 #define MAP(va, rt, av, swap_uv) { \
103 VA_RT_FORMAT_ ## rt, \
107 // The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V
108 // plane swap cases. The frame handling below tries to hide these.
109 static const VAAPIFormatDescriptor vaapi_format_map
[] = {
110 MAP(NV12
, YUV420
, NV12
, 0),
111 #ifdef VA_FOURCC_I420
112 MAP(I420
, YUV420
, YUV420P
, 0),
114 MAP(YV12
, YUV420
, YUV420P
, 1),
115 MAP(IYUV
, YUV420
, YUV420P
, 0),
116 MAP(422H
, YUV422
, YUV422P
, 0),
117 #ifdef VA_FOURCC_YV16
118 MAP(YV16
, YUV422
, YUV422P
, 1),
120 MAP(UYVY
, YUV422
, UYVY422
, 0),
121 MAP(YUY2
, YUV422
, YUYV422
, 0),
122 #ifdef VA_FOURCC_Y210
123 MAP(Y210
, YUV422_10
, Y210
, 0),
125 MAP(411P
, YUV411
, YUV411P
, 0),
126 MAP(422V
, YUV422
, YUV440P
, 0),
127 MAP(444P
, YUV444
, YUV444P
, 0),
128 MAP(Y800
, YUV400
, GRAY8
, 0),
129 #ifdef VA_FOURCC_P010
130 MAP(P010
, YUV420_10BPP
, P010
, 0),
132 MAP(BGRA
, RGB32
, BGRA
, 0),
133 MAP(BGRX
, RGB32
, BGR0
, 0),
134 MAP(RGBA
, RGB32
, RGBA
, 0),
135 MAP(RGBX
, RGB32
, RGB0
, 0),
136 #ifdef VA_FOURCC_ABGR
137 MAP(ABGR
, RGB32
, ABGR
, 0),
138 MAP(XBGR
, RGB32
, 0BGR
, 0),
140 MAP(ARGB
, RGB32
, ARGB
, 0),
141 MAP(XRGB
, RGB32
, 0RGB
, 0),
142 #ifdef VA_FOURCC_X2R10G10B10
143 MAP(X2R10G10B10
, RGB32_10
, X2RGB10
, 0),
148 static const VAAPIFormatDescriptor
*
149 vaapi_format_from_fourcc(unsigned int fourcc
)
152 for (i
= 0; i
< FF_ARRAY_ELEMS(vaapi_format_map
); i
++)
153 if (vaapi_format_map
[i
].fourcc
== fourcc
)
154 return &vaapi_format_map
[i
];
158 static const VAAPIFormatDescriptor
*
159 vaapi_format_from_pix_fmt(enum AVPixelFormat pix_fmt
)
162 for (i
= 0; i
< FF_ARRAY_ELEMS(vaapi_format_map
); i
++)
163 if (vaapi_format_map
[i
].pix_fmt
== pix_fmt
)
164 return &vaapi_format_map
[i
];
168 static enum AVPixelFormat
vaapi_pix_fmt_from_fourcc(unsigned int fourcc
)
170 const VAAPIFormatDescriptor
*desc
;
171 desc
= vaapi_format_from_fourcc(fourcc
);
173 return desc
->pix_fmt
;
175 return AV_PIX_FMT_NONE
;
178 static int vaapi_get_image_format(AVHWDeviceContext
*hwdev
,
179 enum AVPixelFormat pix_fmt
,
180 VAImageFormat
**image_format
)
182 VAAPIDeviceContext
*ctx
= hwdev
->internal
->priv
;
185 for (i
= 0; i
< ctx
->nb_formats
; i
++) {
186 if (ctx
->formats
[i
].pix_fmt
== pix_fmt
) {
188 *image_format
= &ctx
->formats
[i
].image_format
;
192 return AVERROR(EINVAL
);
195 static int vaapi_frames_get_constraints(AVHWDeviceContext
*hwdev
,
196 const void *hwconfig
,
197 AVHWFramesConstraints
*constraints
)
199 AVVAAPIDeviceContext
*hwctx
= hwdev
->hwctx
;
200 const AVVAAPIHWConfig
*config
= hwconfig
;
201 VAAPIDeviceContext
*ctx
= hwdev
->internal
->priv
;
202 VASurfaceAttrib
*attr_list
= NULL
;
204 enum AVPixelFormat pix_fmt
;
206 int err
, i
, j
, attr_count
, pix_fmt_count
;
209 !(hwctx
->driver_quirks
& AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES
)) {
211 vas
= vaQuerySurfaceAttributes(hwctx
->display
, config
->config_id
,
213 if (vas
!= VA_STATUS_SUCCESS
) {
214 av_log(hwdev
, AV_LOG_ERROR
, "Failed to query surface attributes: "
215 "%d (%s).\n", vas
, vaErrorStr(vas
));
216 err
= AVERROR(ENOSYS
);
220 attr_list
= av_malloc(attr_count
* sizeof(*attr_list
));
222 err
= AVERROR(ENOMEM
);
226 vas
= vaQuerySurfaceAttributes(hwctx
->display
, config
->config_id
,
227 attr_list
, &attr_count
);
228 if (vas
!= VA_STATUS_SUCCESS
) {
229 av_log(hwdev
, AV_LOG_ERROR
, "Failed to query surface attributes: "
230 "%d (%s).\n", vas
, vaErrorStr(vas
));
231 err
= AVERROR(ENOSYS
);
236 for (i
= 0; i
< attr_count
; i
++) {
237 switch (attr_list
[i
].type
) {
238 case VASurfaceAttribPixelFormat
:
239 fourcc
= attr_list
[i
].value
.value
.i
;
240 pix_fmt
= vaapi_pix_fmt_from_fourcc(fourcc
);
241 if (pix_fmt
!= AV_PIX_FMT_NONE
) {
244 // Something unsupported - ignore.
247 case VASurfaceAttribMinWidth
:
248 constraints
->min_width
= attr_list
[i
].value
.value
.i
;
250 case VASurfaceAttribMinHeight
:
251 constraints
->min_height
= attr_list
[i
].value
.value
.i
;
253 case VASurfaceAttribMaxWidth
:
254 constraints
->max_width
= attr_list
[i
].value
.value
.i
;
256 case VASurfaceAttribMaxHeight
:
257 constraints
->max_height
= attr_list
[i
].value
.value
.i
;
261 if (pix_fmt_count
== 0) {
262 // Nothing usable found. Presumably there exists something which
263 // works, so leave the set null to indicate unknown.
264 constraints
->valid_sw_formats
= NULL
;
266 constraints
->valid_sw_formats
= av_malloc_array(pix_fmt_count
+ 1,
268 if (!constraints
->valid_sw_formats
) {
269 err
= AVERROR(ENOMEM
);
273 for (i
= j
= 0; i
< attr_count
; i
++) {
276 if (attr_list
[i
].type
!= VASurfaceAttribPixelFormat
)
278 fourcc
= attr_list
[i
].value
.value
.i
;
279 pix_fmt
= vaapi_pix_fmt_from_fourcc(fourcc
);
281 if (pix_fmt
== AV_PIX_FMT_NONE
)
284 for (k
= 0; k
< j
; k
++) {
285 if (constraints
->valid_sw_formats
[k
] == pix_fmt
)
290 constraints
->valid_sw_formats
[j
++] = pix_fmt
;
292 constraints
->valid_sw_formats
[j
] = AV_PIX_FMT_NONE
;
295 // No configuration supplied.
296 // Return the full set of image formats known by the implementation.
297 constraints
->valid_sw_formats
= av_malloc_array(ctx
->nb_formats
+ 1,
299 if (!constraints
->valid_sw_formats
) {
300 err
= AVERROR(ENOMEM
);
303 for (i
= j
= 0; i
< ctx
->nb_formats
; i
++) {
306 for (k
= 0; k
< j
; k
++) {
307 if (constraints
->valid_sw_formats
[k
] == ctx
->formats
[i
].pix_fmt
)
312 constraints
->valid_sw_formats
[j
++] = ctx
->formats
[i
].pix_fmt
;
315 constraints
->valid_sw_formats
[j
] = AV_PIX_FMT_NONE
;
318 constraints
->valid_hw_formats
= av_malloc_array(2, sizeof(pix_fmt
));
319 if (!constraints
->valid_hw_formats
) {
320 err
= AVERROR(ENOMEM
);
323 constraints
->valid_hw_formats
[0] = AV_PIX_FMT_VAAPI
;
324 constraints
->valid_hw_formats
[1] = AV_PIX_FMT_NONE
;
328 av_freep(&attr_list
);
332 static const struct {
333 const char *friendly_name
;
334 const char *match_string
;
336 } vaapi_driver_quirks_table
[] = {
337 #if !VA_CHECK_VERSION(1, 0, 0)
338 // The i965 driver did not conform before version 2.0.
340 "Intel i965 (Quick Sync)",
342 AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS
,
348 AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE
,
352 "Splitted-Desktop Systems VDPAU backend for VA-API",
353 AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES
,
357 static int vaapi_device_init(AVHWDeviceContext
*hwdev
)
359 VAAPIDeviceContext
*ctx
= hwdev
->internal
->priv
;
360 AVVAAPIDeviceContext
*hwctx
= hwdev
->hwctx
;
361 VAImageFormat
*image_list
= NULL
;
363 const char *vendor_string
;
364 int err
, i
, image_count
;
365 enum AVPixelFormat pix_fmt
;
368 image_count
= vaMaxNumImageFormats(hwctx
->display
);
369 if (image_count
<= 0) {
373 image_list
= av_malloc(image_count
* sizeof(*image_list
));
375 err
= AVERROR(ENOMEM
);
378 vas
= vaQueryImageFormats(hwctx
->display
, image_list
, &image_count
);
379 if (vas
!= VA_STATUS_SUCCESS
) {
384 ctx
->formats
= av_malloc(image_count
* sizeof(*ctx
->formats
));
386 err
= AVERROR(ENOMEM
);
390 for (i
= 0; i
< image_count
; i
++) {
391 fourcc
= image_list
[i
].fourcc
;
392 pix_fmt
= vaapi_pix_fmt_from_fourcc(fourcc
);
393 if (pix_fmt
== AV_PIX_FMT_NONE
) {
394 av_log(hwdev
, AV_LOG_DEBUG
, "Format %#x -> unknown.\n",
397 av_log(hwdev
, AV_LOG_DEBUG
, "Format %#x -> %s.\n",
398 fourcc
, av_get_pix_fmt_name(pix_fmt
));
399 ctx
->formats
[ctx
->nb_formats
].pix_fmt
= pix_fmt
;
400 ctx
->formats
[ctx
->nb_formats
].image_format
= image_list
[i
];
405 vendor_string
= vaQueryVendorString(hwctx
->display
);
407 av_log(hwdev
, AV_LOG_VERBOSE
, "VAAPI driver: %s.\n", vendor_string
);
409 if (hwctx
->driver_quirks
& AV_VAAPI_DRIVER_QUIRK_USER_SET
) {
410 av_log(hwdev
, AV_LOG_VERBOSE
, "Using quirks set by user (%#x).\n",
411 hwctx
->driver_quirks
);
413 // Detect the driver in use and set quirk flags if necessary.
414 hwctx
->driver_quirks
= 0;
416 for (i
= 0; i
< FF_ARRAY_ELEMS(vaapi_driver_quirks_table
); i
++) {
417 if (strstr(vendor_string
,
418 vaapi_driver_quirks_table
[i
].match_string
)) {
419 av_log(hwdev
, AV_LOG_VERBOSE
, "Matched driver string "
420 "as known nonstandard driver \"%s\", setting "
422 vaapi_driver_quirks_table
[i
].friendly_name
,
423 vaapi_driver_quirks_table
[i
].quirks
);
424 hwctx
->driver_quirks
|=
425 vaapi_driver_quirks_table
[i
].quirks
;
429 if (!(i
< FF_ARRAY_ELEMS(vaapi_driver_quirks_table
))) {
430 av_log(hwdev
, AV_LOG_VERBOSE
, "Driver not found in known "
431 "nonstandard list, using standard behaviour.\n");
434 av_log(hwdev
, AV_LOG_VERBOSE
, "Driver has no vendor string, "
435 "assuming standard behaviour.\n");
442 av_freep(&ctx
->formats
);
447 static void vaapi_device_uninit(AVHWDeviceContext
*hwdev
)
449 VAAPIDeviceContext
*ctx
= hwdev
->internal
->priv
;
451 av_freep(&ctx
->formats
);
454 static void vaapi_buffer_free(void *opaque
, uint8_t *data
)
456 AVHWFramesContext
*hwfc
= opaque
;
457 AVVAAPIDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
458 VASurfaceID surface_id
;
461 surface_id
= (VASurfaceID
)(uintptr_t)data
;
463 vas
= vaDestroySurfaces(hwctx
->display
, &surface_id
, 1);
464 if (vas
!= VA_STATUS_SUCCESS
) {
465 av_log(hwfc
, AV_LOG_ERROR
, "Failed to destroy surface %#x: "
466 "%d (%s).\n", surface_id
, vas
, vaErrorStr(vas
));
470 static AVBufferRef
*vaapi_pool_alloc(void *opaque
, size_t size
)
472 AVHWFramesContext
*hwfc
= opaque
;
473 VAAPIFramesContext
*ctx
= hwfc
->internal
->priv
;
474 AVVAAPIDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
475 AVVAAPIFramesContext
*avfc
= hwfc
->hwctx
;
476 VASurfaceID surface_id
;
480 if (hwfc
->initial_pool_size
> 0 &&
481 avfc
->nb_surfaces
>= hwfc
->initial_pool_size
)
484 vas
= vaCreateSurfaces(hwctx
->display
, ctx
->rt_format
,
485 hwfc
->width
, hwfc
->height
,
487 ctx
->attributes
, ctx
->nb_attributes
);
488 if (vas
!= VA_STATUS_SUCCESS
) {
489 av_log(hwfc
, AV_LOG_ERROR
, "Failed to create surface: "
490 "%d (%s).\n", vas
, vaErrorStr(vas
));
493 av_log(hwfc
, AV_LOG_DEBUG
, "Created surface %#x.\n", surface_id
);
495 ref
= av_buffer_create((uint8_t*)(uintptr_t)surface_id
,
496 sizeof(surface_id
), &vaapi_buffer_free
,
497 hwfc
, AV_BUFFER_FLAG_READONLY
);
499 vaDestroySurfaces(hwctx
->display
, &surface_id
, 1);
503 if (hwfc
->initial_pool_size
> 0) {
504 // This is a fixed-size pool, so we must still be in the initial
505 // allocation sequence.
506 av_assert0(avfc
->nb_surfaces
< hwfc
->initial_pool_size
);
507 avfc
->surface_ids
[avfc
->nb_surfaces
] = surface_id
;
514 static int vaapi_frames_init(AVHWFramesContext
*hwfc
)
516 AVVAAPIFramesContext
*avfc
= hwfc
->hwctx
;
517 VAAPIFramesContext
*ctx
= hwfc
->internal
->priv
;
518 AVVAAPIDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
519 const VAAPIFormatDescriptor
*desc
;
520 VAImageFormat
*expected_format
;
521 AVBufferRef
*test_surface
= NULL
;
522 VASurfaceID test_surface_id
;
527 desc
= vaapi_format_from_pix_fmt(hwfc
->sw_format
);
529 av_log(hwfc
, AV_LOG_ERROR
, "Unsupported format: %s.\n",
530 av_get_pix_fmt_name(hwfc
->sw_format
));
531 return AVERROR(EINVAL
);
535 if (!(hwctx
->driver_quirks
& AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES
)) {
536 int need_memory_type
= !(hwctx
->driver_quirks
& AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE
);
537 int need_pixel_format
= 1;
538 for (i
= 0; i
< avfc
->nb_attributes
; i
++) {
539 if (avfc
->attributes
[i
].type
== VASurfaceAttribMemoryType
)
540 need_memory_type
= 0;
541 if (avfc
->attributes
[i
].type
== VASurfaceAttribPixelFormat
)
542 need_pixel_format
= 0;
545 avfc
->nb_attributes
+ need_memory_type
+ need_pixel_format
;
547 ctx
->attributes
= av_malloc(ctx
->nb_attributes
*
548 sizeof(*ctx
->attributes
));
549 if (!ctx
->attributes
) {
550 err
= AVERROR(ENOMEM
);
554 for (i
= 0; i
< avfc
->nb_attributes
; i
++)
555 ctx
->attributes
[i
] = avfc
->attributes
[i
];
556 if (need_memory_type
) {
557 ctx
->attributes
[i
++] = (VASurfaceAttrib
) {
558 .type
= VASurfaceAttribMemoryType
,
559 .flags
= VA_SURFACE_ATTRIB_SETTABLE
,
560 .value
.type
= VAGenericValueTypeInteger
,
561 .value
.value
.i
= VA_SURFACE_ATTRIB_MEM_TYPE_VA
,
564 if (need_pixel_format
) {
565 ctx
->attributes
[i
++] = (VASurfaceAttrib
) {
566 .type
= VASurfaceAttribPixelFormat
,
567 .flags
= VA_SURFACE_ATTRIB_SETTABLE
,
568 .value
.type
= VAGenericValueTypeInteger
,
569 .value
.value
.i
= desc
->fourcc
,
572 av_assert0(i
== ctx
->nb_attributes
);
574 ctx
->attributes
= NULL
;
575 ctx
->nb_attributes
= 0;
578 ctx
->rt_format
= desc
->rt_format
;
580 if (hwfc
->initial_pool_size
> 0) {
581 // This pool will be usable as a render target, so we need to store
582 // all of the surface IDs somewhere that vaCreateContext() calls
583 // will be able to access them.
584 avfc
->nb_surfaces
= 0;
585 avfc
->surface_ids
= av_malloc(hwfc
->initial_pool_size
*
586 sizeof(*avfc
->surface_ids
));
587 if (!avfc
->surface_ids
) {
588 err
= AVERROR(ENOMEM
);
592 // This pool allows dynamic sizing, and will not be usable as a
594 avfc
->nb_surfaces
= 0;
595 avfc
->surface_ids
= NULL
;
598 hwfc
->internal
->pool_internal
=
599 av_buffer_pool_init2(sizeof(VASurfaceID
), hwfc
,
600 &vaapi_pool_alloc
, NULL
);
601 if (!hwfc
->internal
->pool_internal
) {
602 av_log(hwfc
, AV_LOG_ERROR
, "Failed to create VAAPI surface pool.\n");
603 err
= AVERROR(ENOMEM
);
608 // Allocate a single surface to test whether vaDeriveImage() is going
609 // to work for the specific configuration.
611 test_surface
= av_buffer_pool_get(hwfc
->pool
);
613 av_log(hwfc
, AV_LOG_ERROR
, "Unable to allocate a surface from "
614 "user-configured buffer pool.\n");
615 err
= AVERROR(ENOMEM
);
619 test_surface
= av_buffer_pool_get(hwfc
->internal
->pool_internal
);
621 av_log(hwfc
, AV_LOG_ERROR
, "Unable to allocate a surface from "
622 "internal buffer pool.\n");
623 err
= AVERROR(ENOMEM
);
627 test_surface_id
= (VASurfaceID
)(uintptr_t)test_surface
->data
;
629 ctx
->derive_works
= 0;
631 err
= vaapi_get_image_format(hwfc
->device_ctx
,
632 hwfc
->sw_format
, &expected_format
);
634 vas
= vaDeriveImage(hwctx
->display
, test_surface_id
, &test_image
);
635 if (vas
== VA_STATUS_SUCCESS
) {
636 if (expected_format
->fourcc
== test_image
.format
.fourcc
) {
637 av_log(hwfc
, AV_LOG_DEBUG
, "Direct mapping possible.\n");
638 ctx
->derive_works
= 1;
640 av_log(hwfc
, AV_LOG_DEBUG
, "Direct mapping disabled: "
641 "derived image format %08x does not match "
642 "expected format %08x.\n",
643 expected_format
->fourcc
, test_image
.format
.fourcc
);
645 vaDestroyImage(hwctx
->display
, test_image
.image_id
);
647 av_log(hwfc
, AV_LOG_DEBUG
, "Direct mapping disabled: "
648 "deriving image does not work: "
649 "%d (%s).\n", vas
, vaErrorStr(vas
));
652 av_log(hwfc
, AV_LOG_DEBUG
, "Direct mapping disabled: "
653 "image format is not supported.\n");
656 av_buffer_unref(&test_surface
);
660 av_buffer_unref(&test_surface
);
661 av_freep(&avfc
->surface_ids
);
662 av_freep(&ctx
->attributes
);
666 static void vaapi_frames_uninit(AVHWFramesContext
*hwfc
)
668 AVVAAPIFramesContext
*avfc
= hwfc
->hwctx
;
669 VAAPIFramesContext
*ctx
= hwfc
->internal
->priv
;
671 av_freep(&avfc
->surface_ids
);
672 av_freep(&ctx
->attributes
);
675 static int vaapi_get_buffer(AVHWFramesContext
*hwfc
, AVFrame
*frame
)
677 frame
->buf
[0] = av_buffer_pool_get(hwfc
->pool
);
679 return AVERROR(ENOMEM
);
681 frame
->data
[3] = frame
->buf
[0]->data
;
682 frame
->format
= AV_PIX_FMT_VAAPI
;
683 frame
->width
= hwfc
->width
;
684 frame
->height
= hwfc
->height
;
689 static int vaapi_transfer_get_formats(AVHWFramesContext
*hwfc
,
690 enum AVHWFrameTransferDirection dir
,
691 enum AVPixelFormat
**formats
)
693 VAAPIDeviceContext
*ctx
= hwfc
->device_ctx
->internal
->priv
;
694 enum AVPixelFormat
*pix_fmts
;
695 int i
, k
, sw_format_available
;
697 sw_format_available
= 0;
698 for (i
= 0; i
< ctx
->nb_formats
; i
++) {
699 if (ctx
->formats
[i
].pix_fmt
== hwfc
->sw_format
)
700 sw_format_available
= 1;
703 pix_fmts
= av_malloc((ctx
->nb_formats
+ 1) * sizeof(*pix_fmts
));
705 return AVERROR(ENOMEM
);
707 if (sw_format_available
) {
708 pix_fmts
[0] = hwfc
->sw_format
;
713 for (i
= 0; i
< ctx
->nb_formats
; i
++) {
714 if (ctx
->formats
[i
].pix_fmt
== hwfc
->sw_format
)
716 av_assert0(k
< ctx
->nb_formats
);
717 pix_fmts
[k
++] = ctx
->formats
[i
].pix_fmt
;
719 pix_fmts
[k
] = AV_PIX_FMT_NONE
;
725 static void vaapi_unmap_frame(AVHWFramesContext
*hwfc
,
726 HWMapDescriptor
*hwmap
)
728 AVVAAPIDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
729 VAAPIMapping
*map
= hwmap
->priv
;
730 VASurfaceID surface_id
;
733 surface_id
= (VASurfaceID
)(uintptr_t)hwmap
->source
->data
[3];
734 av_log(hwfc
, AV_LOG_DEBUG
, "Unmap surface %#x.\n", surface_id
);
736 vas
= vaUnmapBuffer(hwctx
->display
, map
->image
.buf
);
737 if (vas
!= VA_STATUS_SUCCESS
) {
738 av_log(hwfc
, AV_LOG_ERROR
, "Failed to unmap image from surface "
739 "%#x: %d (%s).\n", surface_id
, vas
, vaErrorStr(vas
));
742 if ((map
->flags
& AV_HWFRAME_MAP_WRITE
) &&
743 !(map
->flags
& AV_HWFRAME_MAP_DIRECT
)) {
744 vas
= vaPutImage(hwctx
->display
, surface_id
, map
->image
.image_id
,
745 0, 0, hwfc
->width
, hwfc
->height
,
746 0, 0, hwfc
->width
, hwfc
->height
);
747 if (vas
!= VA_STATUS_SUCCESS
) {
748 av_log(hwfc
, AV_LOG_ERROR
, "Failed to write image to surface "
749 "%#x: %d (%s).\n", surface_id
, vas
, vaErrorStr(vas
));
753 vas
= vaDestroyImage(hwctx
->display
, map
->image
.image_id
);
754 if (vas
!= VA_STATUS_SUCCESS
) {
755 av_log(hwfc
, AV_LOG_ERROR
, "Failed to destroy image from surface "
756 "%#x: %d (%s).\n", surface_id
, vas
, vaErrorStr(vas
));
762 static int vaapi_map_frame(AVHWFramesContext
*hwfc
,
763 AVFrame
*dst
, const AVFrame
*src
, int flags
)
765 AVVAAPIDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
766 VAAPIFramesContext
*ctx
= hwfc
->internal
->priv
;
767 VASurfaceID surface_id
;
768 const VAAPIFormatDescriptor
*desc
;
769 VAImageFormat
*image_format
;
772 void *address
= NULL
;
775 surface_id
= (VASurfaceID
)(uintptr_t)src
->data
[3];
776 av_log(hwfc
, AV_LOG_DEBUG
, "Map surface %#x.\n", surface_id
);
778 if (!ctx
->derive_works
&& (flags
& AV_HWFRAME_MAP_DIRECT
)) {
779 // Requested direct mapping but it is not possible.
780 return AVERROR(EINVAL
);
782 if (dst
->format
== AV_PIX_FMT_NONE
)
783 dst
->format
= hwfc
->sw_format
;
784 if (dst
->format
!= hwfc
->sw_format
&& (flags
& AV_HWFRAME_MAP_DIRECT
)) {
785 // Requested direct mapping but the formats do not match.
786 return AVERROR(EINVAL
);
789 err
= vaapi_get_image_format(hwfc
->device_ctx
, dst
->format
, &image_format
);
791 // Requested format is not a valid output format.
792 return AVERROR(EINVAL
);
795 map
= av_malloc(sizeof(*map
));
797 return AVERROR(ENOMEM
);
799 map
->image
.image_id
= VA_INVALID_ID
;
801 vas
= vaSyncSurface(hwctx
->display
, surface_id
);
802 if (vas
!= VA_STATUS_SUCCESS
) {
803 av_log(hwfc
, AV_LOG_ERROR
, "Failed to sync surface "
804 "%#x: %d (%s).\n", surface_id
, vas
, vaErrorStr(vas
));
809 // The memory which we map using derive need not be connected to the CPU
810 // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
811 // memory is mappable but not cached, so normal memcpy()-like access is
812 // very slow to read it (but writing is ok). It is possible to read much
813 // faster with a copy routine which is aware of the limitation, but we
814 // assume for now that the user is not aware of that and would therefore
815 // prefer not to be given direct-mapped memory if they request read access.
816 if (ctx
->derive_works
&& dst
->format
== hwfc
->sw_format
&&
817 ((flags
& AV_HWFRAME_MAP_DIRECT
) || !(flags
& AV_HWFRAME_MAP_READ
))) {
818 vas
= vaDeriveImage(hwctx
->display
, surface_id
, &map
->image
);
819 if (vas
!= VA_STATUS_SUCCESS
) {
820 av_log(hwfc
, AV_LOG_ERROR
, "Failed to derive image from "
821 "surface %#x: %d (%s).\n",
822 surface_id
, vas
, vaErrorStr(vas
));
826 if (map
->image
.format
.fourcc
!= image_format
->fourcc
) {
827 av_log(hwfc
, AV_LOG_ERROR
, "Derive image of surface %#x "
828 "is in wrong format: expected %#08x, got %#08x.\n",
829 surface_id
, image_format
->fourcc
, map
->image
.format
.fourcc
);
833 map
->flags
|= AV_HWFRAME_MAP_DIRECT
;
835 vas
= vaCreateImage(hwctx
->display
, image_format
,
836 hwfc
->width
, hwfc
->height
, &map
->image
);
837 if (vas
!= VA_STATUS_SUCCESS
) {
838 av_log(hwfc
, AV_LOG_ERROR
, "Failed to create image for "
839 "surface %#x: %d (%s).\n",
840 surface_id
, vas
, vaErrorStr(vas
));
844 if (!(flags
& AV_HWFRAME_MAP_OVERWRITE
)) {
845 vas
= vaGetImage(hwctx
->display
, surface_id
, 0, 0,
846 hwfc
->width
, hwfc
->height
, map
->image
.image_id
);
847 if (vas
!= VA_STATUS_SUCCESS
) {
848 av_log(hwfc
, AV_LOG_ERROR
, "Failed to read image from "
849 "surface %#x: %d (%s).\n",
850 surface_id
, vas
, vaErrorStr(vas
));
857 vas
= vaMapBuffer(hwctx
->display
, map
->image
.buf
, &address
);
858 if (vas
!= VA_STATUS_SUCCESS
) {
859 av_log(hwfc
, AV_LOG_ERROR
, "Failed to map image from surface "
860 "%#x: %d (%s).\n", surface_id
, vas
, vaErrorStr(vas
));
865 err
= ff_hwframe_map_create(src
->hw_frames_ctx
,
866 dst
, src
, &vaapi_unmap_frame
, map
);
870 dst
->width
= src
->width
;
871 dst
->height
= src
->height
;
873 for (i
= 0; i
< map
->image
.num_planes
; i
++) {
874 dst
->data
[i
] = (uint8_t*)address
+ map
->image
.offsets
[i
];
875 dst
->linesize
[i
] = map
->image
.pitches
[i
];
878 desc
= vaapi_format_from_fourcc(map
->image
.format
.fourcc
);
879 if (desc
&& desc
->chroma_planes_swapped
) {
880 // Chroma planes are YVU rather than YUV, so swap them.
881 FFSWAP(uint8_t*, dst
->data
[1], dst
->data
[2]);
889 vaUnmapBuffer(hwctx
->display
, map
->image
.buf
);
890 if (map
->image
.image_id
!= VA_INVALID_ID
)
891 vaDestroyImage(hwctx
->display
, map
->image
.image_id
);
897 static int vaapi_transfer_data_from(AVHWFramesContext
*hwfc
,
898 AVFrame
*dst
, const AVFrame
*src
)
903 if (dst
->width
> hwfc
->width
|| dst
->height
> hwfc
->height
)
904 return AVERROR(EINVAL
);
906 map
= av_frame_alloc();
908 return AVERROR(ENOMEM
);
909 map
->format
= dst
->format
;
911 err
= vaapi_map_frame(hwfc
, map
, src
, AV_HWFRAME_MAP_READ
);
915 map
->width
= dst
->width
;
916 map
->height
= dst
->height
;
918 err
= av_frame_copy(dst
, map
);
928 static int vaapi_transfer_data_to(AVHWFramesContext
*hwfc
,
929 AVFrame
*dst
, const AVFrame
*src
)
934 if (src
->width
> hwfc
->width
|| src
->height
> hwfc
->height
)
935 return AVERROR(EINVAL
);
937 map
= av_frame_alloc();
939 return AVERROR(ENOMEM
);
940 map
->format
= src
->format
;
942 err
= vaapi_map_frame(hwfc
, map
, dst
, AV_HWFRAME_MAP_WRITE
| AV_HWFRAME_MAP_OVERWRITE
);
946 map
->width
= src
->width
;
947 map
->height
= src
->height
;
949 err
= av_frame_copy(map
, src
);
959 static int vaapi_map_to_memory(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
960 const AVFrame
*src
, int flags
)
964 if (dst
->format
!= AV_PIX_FMT_NONE
) {
965 err
= vaapi_get_image_format(hwfc
->device_ctx
, dst
->format
, NULL
);
967 return AVERROR(ENOSYS
);
970 err
= vaapi_map_frame(hwfc
, dst
, src
, flags
);
974 err
= av_frame_copy_props(dst
, src
);
983 #define DRM_MAP(va, layers, ...) { \
988 static const struct {
990 int nb_layer_formats
;
991 uint32_t layer_formats
[AV_DRM_MAX_PLANES
];
992 } vaapi_drm_format_map
[] = {
994 DRM_MAP(NV12
, 2, DRM_FORMAT_R8
, DRM_FORMAT_RG88
),
995 DRM_MAP(NV12
, 2, DRM_FORMAT_R8
, DRM_FORMAT_GR88
),
997 DRM_MAP(NV12
, 1, DRM_FORMAT_NV12
),
998 #if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16)
999 DRM_MAP(P010
, 2, DRM_FORMAT_R16
, DRM_FORMAT_RG1616
),
1001 DRM_MAP(BGRA
, 1, DRM_FORMAT_ARGB8888
),
1002 DRM_MAP(BGRX
, 1, DRM_FORMAT_XRGB8888
),
1003 DRM_MAP(RGBA
, 1, DRM_FORMAT_ABGR8888
),
1004 DRM_MAP(RGBX
, 1, DRM_FORMAT_XBGR8888
),
1005 #ifdef VA_FOURCC_ABGR
1006 DRM_MAP(ABGR
, 1, DRM_FORMAT_RGBA8888
),
1007 DRM_MAP(XBGR
, 1, DRM_FORMAT_RGBX8888
),
1009 DRM_MAP(ARGB
, 1, DRM_FORMAT_BGRA8888
),
1010 DRM_MAP(XRGB
, 1, DRM_FORMAT_BGRX8888
),
1014 static void vaapi_unmap_from_drm(AVHWFramesContext
*dst_fc
,
1015 HWMapDescriptor
*hwmap
)
1017 AVVAAPIDeviceContext
*dst_dev
= dst_fc
->device_ctx
->hwctx
;
1019 VASurfaceID surface_id
= (VASurfaceID
)(uintptr_t)hwmap
->priv
;
1021 av_log(dst_fc
, AV_LOG_DEBUG
, "Destroy surface %#x.\n", surface_id
);
1023 vaDestroySurfaces(dst_dev
->display
, &surface_id
, 1);
1026 static int vaapi_map_from_drm(AVHWFramesContext
*src_fc
, AVFrame
*dst
,
1027 const AVFrame
*src
, int flags
)
1029 #if VA_CHECK_VERSION(1, 1, 0)
1030 VAAPIFramesContext
*src_vafc
= src_fc
->internal
->priv
;
1035 AVHWFramesContext
*dst_fc
=
1036 (AVHWFramesContext
*)dst
->hw_frames_ctx
->data
;
1037 AVVAAPIDeviceContext
*dst_dev
= dst_fc
->device_ctx
->hwctx
;
1038 const AVDRMFrameDescriptor
*desc
;
1039 const VAAPIFormatDescriptor
*format_desc
;
1040 VASurfaceID surface_id
;
1041 VAStatus vas
= VA_STATUS_SUCCESS
;
1045 #if !VA_CHECK_VERSION(1, 1, 0)
1046 unsigned long buffer_handle
;
1047 VASurfaceAttribExternalBuffers buffer_desc
;
1048 VASurfaceAttrib attrs
[2] = {
1050 .type
= VASurfaceAttribMemoryType
,
1051 .flags
= VA_SURFACE_ATTRIB_SETTABLE
,
1052 .value
.type
= VAGenericValueTypeInteger
,
1053 .value
.value
.i
= VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME
,
1056 .type
= VASurfaceAttribExternalBufferDescriptor
,
1057 .flags
= VA_SURFACE_ATTRIB_SETTABLE
,
1058 .value
.type
= VAGenericValueTypePointer
,
1059 .value
.value
.p
= &buffer_desc
,
1064 desc
= (AVDRMFrameDescriptor
*)src
->data
[0];
1066 if (desc
->nb_objects
!= 1) {
1067 av_log(dst_fc
, AV_LOG_ERROR
, "VAAPI can only map frames "
1068 "made from a single DRM object.\n");
1069 return AVERROR(EINVAL
);
1073 for (i
= 0; i
< FF_ARRAY_ELEMS(vaapi_drm_format_map
); i
++) {
1074 if (desc
->nb_layers
!= vaapi_drm_format_map
[i
].nb_layer_formats
)
1076 for (j
= 0; j
< desc
->nb_layers
; j
++) {
1077 if (desc
->layers
[j
].format
!=
1078 vaapi_drm_format_map
[i
].layer_formats
[j
])
1081 if (j
!= desc
->nb_layers
)
1083 va_fourcc
= vaapi_drm_format_map
[i
].va_fourcc
;
1087 av_log(dst_fc
, AV_LOG_ERROR
, "DRM format not supported "
1089 return AVERROR(EINVAL
);
1092 av_log(dst_fc
, AV_LOG_DEBUG
, "Map DRM object %d to VAAPI as "
1093 "%08x.\n", desc
->objects
[0].fd
, va_fourcc
);
1095 format_desc
= vaapi_format_from_fourcc(va_fourcc
);
1096 av_assert0(format_desc
);
1098 #if VA_CHECK_VERSION(1, 1, 0)
1099 use_prime2
= !src_vafc
->prime_2_import_unsupported
&&
1100 desc
->objects
[0].format_modifier
!= DRM_FORMAT_MOD_INVALID
;
1102 VADRMPRIMESurfaceDescriptor prime_desc
;
1103 VASurfaceAttrib prime_attrs
[2] = {
1105 .type
= VASurfaceAttribMemoryType
,
1106 .flags
= VA_SURFACE_ATTRIB_SETTABLE
,
1107 .value
.type
= VAGenericValueTypeInteger
,
1108 .value
.value
.i
= VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2
,
1111 .type
= VASurfaceAttribExternalBufferDescriptor
,
1112 .flags
= VA_SURFACE_ATTRIB_SETTABLE
,
1113 .value
.type
= VAGenericValueTypePointer
,
1114 .value
.value
.p
= &prime_desc
,
1117 prime_desc
.fourcc
= va_fourcc
;
1118 prime_desc
.width
= src_fc
->width
;
1119 prime_desc
.height
= src_fc
->height
;
1120 prime_desc
.num_objects
= desc
->nb_objects
;
1121 for (i
= 0; i
< desc
->nb_objects
; ++i
) {
1122 prime_desc
.objects
[i
].fd
= desc
->objects
[i
].fd
;
1123 prime_desc
.objects
[i
].size
= desc
->objects
[i
].size
;
1124 prime_desc
.objects
[i
].drm_format_modifier
=
1125 desc
->objects
[i
].format_modifier
;
1128 prime_desc
.num_layers
= desc
->nb_layers
;
1129 for (i
= 0; i
< desc
->nb_layers
; ++i
) {
1130 prime_desc
.layers
[i
].drm_format
= desc
->layers
[i
].format
;
1131 prime_desc
.layers
[i
].num_planes
= desc
->layers
[i
].nb_planes
;
1132 for (j
= 0; j
< desc
->layers
[i
].nb_planes
; ++j
) {
1133 prime_desc
.layers
[i
].object_index
[j
] =
1134 desc
->layers
[i
].planes
[j
].object_index
;
1135 prime_desc
.layers
[i
].offset
[j
] = desc
->layers
[i
].planes
[j
].offset
;
1136 prime_desc
.layers
[i
].pitch
[j
] = desc
->layers
[i
].planes
[j
].pitch
;
1139 if (format_desc
->chroma_planes_swapped
&&
1140 desc
->layers
[i
].nb_planes
== 3) {
1141 FFSWAP(uint32_t, prime_desc
.layers
[i
].pitch
[1],
1142 prime_desc
.layers
[i
].pitch
[2]);
1143 FFSWAP(uint32_t, prime_desc
.layers
[i
].offset
[1],
1144 prime_desc
.layers
[i
].offset
[2]);
1149 * We can query for PRIME_2 support with vaQuerySurfaceAttributes, but that
1150 * that needs the config_id which we don't have here . Both Intel and
1151 * Gallium seem to do the correct error checks, so lets just try the
1152 * PRIME_2 import first.
1154 vas
= vaCreateSurfaces(dst_dev
->display
, format_desc
->rt_format
,
1155 src
->width
, src
->height
, &surface_id
, 1,
1156 prime_attrs
, FF_ARRAY_ELEMS(prime_attrs
));
1157 if (vas
!= VA_STATUS_SUCCESS
)
1158 src_vafc
->prime_2_import_unsupported
= 1;
1161 if (!use_prime2
|| vas
!= VA_STATUS_SUCCESS
) {
1163 unsigned long buffer_handle
;
1164 VASurfaceAttribExternalBuffers buffer_desc
;
1165 VASurfaceAttrib buffer_attrs
[2] = {
1167 .type
= VASurfaceAttribMemoryType
,
1168 .flags
= VA_SURFACE_ATTRIB_SETTABLE
,
1169 .value
.type
= VAGenericValueTypeInteger
,
1170 .value
.value
.i
= VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME
,
1173 .type
= VASurfaceAttribExternalBufferDescriptor
,
1174 .flags
= VA_SURFACE_ATTRIB_SETTABLE
,
1175 .value
.type
= VAGenericValueTypePointer
,
1176 .value
.value
.p
= &buffer_desc
,
1180 buffer_handle
= desc
->objects
[0].fd
;
1181 buffer_desc
.pixel_format
= va_fourcc
;
1182 buffer_desc
.width
= src_fc
->width
;
1183 buffer_desc
.height
= src_fc
->height
;
1184 buffer_desc
.data_size
= desc
->objects
[0].size
;
1185 buffer_desc
.buffers
= &buffer_handle
;
1186 buffer_desc
.num_buffers
= 1;
1187 buffer_desc
.flags
= 0;
1190 for (i
= 0; i
< desc
->nb_layers
; i
++) {
1191 for (j
= 0; j
< desc
->layers
[i
].nb_planes
; j
++) {
1192 buffer_desc
.pitches
[k
] = desc
->layers
[i
].planes
[j
].pitch
;
1193 buffer_desc
.offsets
[k
] = desc
->layers
[i
].planes
[j
].offset
;
1197 buffer_desc
.num_planes
= k
;
1199 if (format_desc
->chroma_planes_swapped
&&
1200 buffer_desc
.num_planes
== 3) {
1201 FFSWAP(uint32_t, buffer_desc
.pitches
[1], buffer_desc
.pitches
[2]);
1202 FFSWAP(uint32_t, buffer_desc
.offsets
[1], buffer_desc
.offsets
[2]);
1205 vas
= vaCreateSurfaces(dst_dev
->display
, format_desc
->rt_format
,
1206 src
->width
, src
->height
,
1208 buffer_attrs
, FF_ARRAY_ELEMS(buffer_attrs
));
1211 buffer_handle
= desc
->objects
[0].fd
;
1212 buffer_desc
.pixel_format
= va_fourcc
;
1213 buffer_desc
.width
= src_fc
->width
;
1214 buffer_desc
.height
= src_fc
->height
;
1215 buffer_desc
.data_size
= desc
->objects
[0].size
;
1216 buffer_desc
.buffers
= &buffer_handle
;
1217 buffer_desc
.num_buffers
= 1;
1218 buffer_desc
.flags
= 0;
1221 for (i
= 0; i
< desc
->nb_layers
; i
++) {
1222 for (j
= 0; j
< desc
->layers
[i
].nb_planes
; j
++) {
1223 buffer_desc
.pitches
[k
] = desc
->layers
[i
].planes
[j
].pitch
;
1224 buffer_desc
.offsets
[k
] = desc
->layers
[i
].planes
[j
].offset
;
1228 buffer_desc
.num_planes
= k
;
1230 if (format_desc
->chroma_planes_swapped
&&
1231 buffer_desc
.num_planes
== 3) {
1232 FFSWAP(uint32_t, buffer_desc
.pitches
[1], buffer_desc
.pitches
[2]);
1233 FFSWAP(uint32_t, buffer_desc
.offsets
[1], buffer_desc
.offsets
[2]);
1236 vas
= vaCreateSurfaces(dst_dev
->display
, format_desc
->rt_format
,
1237 src
->width
, src
->height
,
1239 attrs
, FF_ARRAY_ELEMS(attrs
));
1241 if (vas
!= VA_STATUS_SUCCESS
) {
1242 av_log(dst_fc
, AV_LOG_ERROR
, "Failed to create surface from DRM "
1243 "object: %d (%s).\n", vas
, vaErrorStr(vas
));
1244 return AVERROR(EIO
);
1246 av_log(dst_fc
, AV_LOG_DEBUG
, "Create surface %#x.\n", surface_id
);
1248 err
= ff_hwframe_map_create(dst
->hw_frames_ctx
, dst
, src
,
1249 &vaapi_unmap_from_drm
,
1250 (void*)(uintptr_t)surface_id
);
1254 dst
->width
= src
->width
;
1255 dst
->height
= src
->height
;
1256 dst
->data
[3] = (uint8_t*)(uintptr_t)surface_id
;
1258 av_log(dst_fc
, AV_LOG_DEBUG
, "Mapped DRM object %d to "
1259 "surface %#x.\n", desc
->objects
[0].fd
, surface_id
);
1264 #if VA_CHECK_VERSION(1, 1, 0)
1265 static void vaapi_unmap_to_drm_esh(AVHWFramesContext
*hwfc
,
1266 HWMapDescriptor
*hwmap
)
1268 AVDRMFrameDescriptor
*drm_desc
= hwmap
->priv
;
1271 for (i
= 0; i
< drm_desc
->nb_objects
; i
++)
1272 close(drm_desc
->objects
[i
].fd
);
1274 av_freep(&drm_desc
);
1277 static int vaapi_map_to_drm_esh(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
1278 const AVFrame
*src
, int flags
)
1280 AVVAAPIDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
1281 VASurfaceID surface_id
;
1283 VADRMPRIMESurfaceDescriptor va_desc
;
1284 AVDRMFrameDescriptor
*drm_desc
= NULL
;
1285 uint32_t export_flags
;
1288 surface_id
= (VASurfaceID
)(uintptr_t)src
->data
[3];
1290 export_flags
= VA_EXPORT_SURFACE_SEPARATE_LAYERS
;
1291 if (flags
& AV_HWFRAME_MAP_READ
)
1292 export_flags
|= VA_EXPORT_SURFACE_READ_ONLY
;
1293 if (flags
& AV_HWFRAME_MAP_WRITE
)
1294 export_flags
|= VA_EXPORT_SURFACE_WRITE_ONLY
;
1296 vas
= vaExportSurfaceHandle(hwctx
->display
, surface_id
,
1297 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2
,
1298 export_flags
, &va_desc
);
1299 if (vas
!= VA_STATUS_SUCCESS
) {
1300 if (vas
== VA_STATUS_ERROR_UNIMPLEMENTED
)
1301 return AVERROR(ENOSYS
);
1302 av_log(hwfc
, AV_LOG_ERROR
, "Failed to export surface %#x: "
1303 "%d (%s).\n", surface_id
, vas
, vaErrorStr(vas
));
1304 return AVERROR(EIO
);
1307 drm_desc
= av_mallocz(sizeof(*drm_desc
));
1309 err
= AVERROR(ENOMEM
);
1313 // By some bizarre coincidence, these structures are very similar...
1314 drm_desc
->nb_objects
= va_desc
.num_objects
;
1315 for (i
= 0; i
< va_desc
.num_objects
; i
++) {
1316 drm_desc
->objects
[i
].fd
= va_desc
.objects
[i
].fd
;
1317 drm_desc
->objects
[i
].size
= va_desc
.objects
[i
].size
;
1318 drm_desc
->objects
[i
].format_modifier
=
1319 va_desc
.objects
[i
].drm_format_modifier
;
1321 drm_desc
->nb_layers
= va_desc
.num_layers
;
1322 for (i
= 0; i
< va_desc
.num_layers
; i
++) {
1323 drm_desc
->layers
[i
].format
= va_desc
.layers
[i
].drm_format
;
1324 drm_desc
->layers
[i
].nb_planes
= va_desc
.layers
[i
].num_planes
;
1325 for (j
= 0; j
< va_desc
.layers
[i
].num_planes
; j
++) {
1326 drm_desc
->layers
[i
].planes
[j
].object_index
=
1327 va_desc
.layers
[i
].object_index
[j
];
1328 drm_desc
->layers
[i
].planes
[j
].offset
=
1329 va_desc
.layers
[i
].offset
[j
];
1330 drm_desc
->layers
[i
].planes
[j
].pitch
=
1331 va_desc
.layers
[i
].pitch
[j
];
1335 err
= ff_hwframe_map_create(src
->hw_frames_ctx
, dst
, src
,
1336 &vaapi_unmap_to_drm_esh
, drm_desc
);
1340 dst
->width
= src
->width
;
1341 dst
->height
= src
->height
;
1342 dst
->data
[0] = (uint8_t*)drm_desc
;
1347 for (i
= 0; i
< va_desc
.num_objects
; i
++)
1348 close(va_desc
.objects
[i
].fd
);
1349 av_freep(&drm_desc
);
1354 #if VA_CHECK_VERSION(0, 36, 0)
1355 typedef struct VAAPIDRMImageBufferMapping
{
1357 VABufferInfo buffer_info
;
1359 AVDRMFrameDescriptor drm_desc
;
1360 } VAAPIDRMImageBufferMapping
;
1362 static void vaapi_unmap_to_drm_abh(AVHWFramesContext
*hwfc
,
1363 HWMapDescriptor
*hwmap
)
1365 AVVAAPIDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
1366 VAAPIDRMImageBufferMapping
*mapping
= hwmap
->priv
;
1367 VASurfaceID surface_id
;
1370 surface_id
= (VASurfaceID
)(uintptr_t)hwmap
->source
->data
[3];
1371 av_log(hwfc
, AV_LOG_DEBUG
, "Unmap VAAPI surface %#x from DRM.\n",
1374 // DRM PRIME file descriptors are closed by vaReleaseBufferHandle(),
1375 // so we shouldn't close them separately.
1377 vas
= vaReleaseBufferHandle(hwctx
->display
, mapping
->image
.buf
);
1378 if (vas
!= VA_STATUS_SUCCESS
) {
1379 av_log(hwfc
, AV_LOG_ERROR
, "Failed to release buffer "
1380 "handle of image %#x (derived from surface %#x): "
1381 "%d (%s).\n", mapping
->image
.buf
, surface_id
,
1382 vas
, vaErrorStr(vas
));
1385 vas
= vaDestroyImage(hwctx
->display
, mapping
->image
.image_id
);
1386 if (vas
!= VA_STATUS_SUCCESS
) {
1387 av_log(hwfc
, AV_LOG_ERROR
, "Failed to destroy image "
1388 "derived from surface %#x: %d (%s).\n",
1389 surface_id
, vas
, vaErrorStr(vas
));
1395 static int vaapi_map_to_drm_abh(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
1396 const AVFrame
*src
, int flags
)
1398 AVVAAPIDeviceContext
*hwctx
= hwfc
->device_ctx
->hwctx
;
1399 VAAPIDRMImageBufferMapping
*mapping
= NULL
;
1400 VASurfaceID surface_id
;
1404 surface_id
= (VASurfaceID
)(uintptr_t)src
->data
[3];
1405 av_log(hwfc
, AV_LOG_DEBUG
, "Map VAAPI surface %#x to DRM.\n",
1408 mapping
= av_mallocz(sizeof(*mapping
));
1410 return AVERROR(ENOMEM
);
1412 vas
= vaDeriveImage(hwctx
->display
, surface_id
,
1414 if (vas
!= VA_STATUS_SUCCESS
) {
1415 av_log(hwfc
, AV_LOG_ERROR
, "Failed to derive image from "
1416 "surface %#x: %d (%s).\n",
1417 surface_id
, vas
, vaErrorStr(vas
));
1422 for (i
= 0; i
< FF_ARRAY_ELEMS(vaapi_drm_format_map
); i
++) {
1423 if (vaapi_drm_format_map
[i
].va_fourcc
==
1424 mapping
->image
.format
.fourcc
)
1427 if (i
>= FF_ARRAY_ELEMS(vaapi_drm_format_map
)) {
1428 av_log(hwfc
, AV_LOG_ERROR
, "No matching DRM format for "
1429 "VAAPI format %#x.\n", mapping
->image
.format
.fourcc
);
1430 err
= AVERROR(EINVAL
);
1434 mapping
->buffer_info
.mem_type
=
1435 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME
;
1437 mapping
->drm_desc
.nb_layers
=
1438 vaapi_drm_format_map
[i
].nb_layer_formats
;
1439 if (mapping
->drm_desc
.nb_layers
> 1) {
1440 if (mapping
->drm_desc
.nb_layers
!= mapping
->image
.num_planes
) {
1441 av_log(hwfc
, AV_LOG_ERROR
, "Image properties do not match "
1442 "expected format: got %d planes, but expected %d.\n",
1443 mapping
->image
.num_planes
, mapping
->drm_desc
.nb_layers
);
1444 err
= AVERROR(EINVAL
);
1448 for(p
= 0; p
< mapping
->drm_desc
.nb_layers
; p
++) {
1449 mapping
->drm_desc
.layers
[p
] = (AVDRMLayerDescriptor
) {
1450 .format
= vaapi_drm_format_map
[i
].layer_formats
[p
],
1454 .offset
= mapping
->image
.offsets
[p
],
1455 .pitch
= mapping
->image
.pitches
[p
],
1460 mapping
->drm_desc
.layers
[0].format
=
1461 vaapi_drm_format_map
[i
].layer_formats
[0];
1462 mapping
->drm_desc
.layers
[0].nb_planes
= mapping
->image
.num_planes
;
1463 for (p
= 0; p
< mapping
->image
.num_planes
; p
++) {
1464 mapping
->drm_desc
.layers
[0].planes
[p
] = (AVDRMPlaneDescriptor
) {
1466 .offset
= mapping
->image
.offsets
[p
],
1467 .pitch
= mapping
->image
.pitches
[p
],
1472 vas
= vaAcquireBufferHandle(hwctx
->display
, mapping
->image
.buf
,
1473 &mapping
->buffer_info
);
1474 if (vas
!= VA_STATUS_SUCCESS
) {
1475 av_log(hwfc
, AV_LOG_ERROR
, "Failed to get buffer "
1476 "handle from image %#x (derived from surface %#x): "
1477 "%d (%s).\n", mapping
->image
.buf
, surface_id
,
1478 vas
, vaErrorStr(vas
));
1483 av_log(hwfc
, AV_LOG_DEBUG
, "DRM PRIME fd is %ld.\n",
1484 mapping
->buffer_info
.handle
);
1486 mapping
->drm_desc
.nb_objects
= 1;
1487 mapping
->drm_desc
.objects
[0] = (AVDRMObjectDescriptor
) {
1488 .fd
= mapping
->buffer_info
.handle
,
1489 .size
= mapping
->image
.data_size
,
1490 // There is no way to get the format modifier with this API.
1491 .format_modifier
= DRM_FORMAT_MOD_INVALID
,
1494 err
= ff_hwframe_map_create(src
->hw_frames_ctx
,
1495 dst
, src
, &vaapi_unmap_to_drm_abh
,
1500 dst
->data
[0] = (uint8_t*)&mapping
->drm_desc
;
1501 dst
->width
= src
->width
;
1502 dst
->height
= src
->height
;
1507 vaReleaseBufferHandle(hwctx
->display
, mapping
->image
.buf
);
1509 vaDestroyImage(hwctx
->display
, mapping
->image
.image_id
);
1516 static int vaapi_map_to_drm(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
1517 const AVFrame
*src
, int flags
)
1519 #if VA_CHECK_VERSION(1, 1, 0)
1521 err
= vaapi_map_to_drm_esh(hwfc
, dst
, src
, flags
);
1522 if (err
!= AVERROR(ENOSYS
))
1525 #if VA_CHECK_VERSION(0, 36, 0)
1526 return vaapi_map_to_drm_abh(hwfc
, dst
, src
, flags
);
1528 return AVERROR(ENOSYS
);
1531 #endif /* CONFIG_LIBDRM */
1533 static int vaapi_map_to(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
1534 const AVFrame
*src
, int flags
)
1536 switch (src
->format
) {
1538 case AV_PIX_FMT_DRM_PRIME
:
1539 return vaapi_map_from_drm(hwfc
, dst
, src
, flags
);
1542 return AVERROR(ENOSYS
);
1546 static int vaapi_map_from(AVHWFramesContext
*hwfc
, AVFrame
*dst
,
1547 const AVFrame
*src
, int flags
)
1549 switch (dst
->format
) {
1551 case AV_PIX_FMT_DRM_PRIME
:
1552 return vaapi_map_to_drm(hwfc
, dst
, src
, flags
);
1555 return vaapi_map_to_memory(hwfc
, dst
, src
, flags
);
1559 static void vaapi_device_free(AVHWDeviceContext
*ctx
)
1561 AVVAAPIDeviceContext
*hwctx
= ctx
->hwctx
;
1562 VAAPIDevicePriv
*priv
= ctx
->user_opaque
;
1565 vaTerminate(hwctx
->display
);
1568 if (priv
->x11_display
)
1569 XCloseDisplay(priv
->x11_display
);
1572 if (priv
->drm_fd
>= 0)
1573 close(priv
->drm_fd
);
1579 static void vaapi_device_log_error(void *context
, const char *message
)
1581 AVHWDeviceContext
*ctx
= context
;
1583 av_log(ctx
, AV_LOG_ERROR
, "libva: %s", message
);
1586 static void vaapi_device_log_info(void *context
, const char *message
)
1588 AVHWDeviceContext
*ctx
= context
;
1590 av_log(ctx
, AV_LOG_VERBOSE
, "libva: %s", message
);
1594 static int vaapi_device_connect(AVHWDeviceContext
*ctx
,
1597 AVVAAPIDeviceContext
*hwctx
= ctx
->hwctx
;
1602 vaSetErrorCallback(display
, &vaapi_device_log_error
, ctx
);
1603 vaSetInfoCallback (display
, &vaapi_device_log_info
, ctx
);
1606 hwctx
->display
= display
;
1608 vas
= vaInitialize(display
, &major
, &minor
);
1609 if (vas
!= VA_STATUS_SUCCESS
) {
1610 av_log(ctx
, AV_LOG_ERROR
, "Failed to initialise VAAPI "
1611 "connection: %d (%s).\n", vas
, vaErrorStr(vas
));
1612 return AVERROR(EIO
);
1614 av_log(ctx
, AV_LOG_VERBOSE
, "Initialised VAAPI connection: "
1615 "version %d.%d\n", major
, minor
);
1620 static int vaapi_device_create(AVHWDeviceContext
*ctx
, const char *device
,
1621 AVDictionary
*opts
, int flags
)
1623 VAAPIDevicePriv
*priv
;
1624 VADisplay display
= NULL
;
1625 const AVDictionaryEntry
*ent
;
1626 int try_drm
, try_x11
, try_all
;
1628 priv
= av_mallocz(sizeof(*priv
));
1630 return AVERROR(ENOMEM
);
1634 ctx
->user_opaque
= priv
;
1635 ctx
->free
= vaapi_device_free
;
1637 ent
= av_dict_get(opts
, "connection_type", NULL
, 0);
1639 try_all
= try_drm
= try_x11
= 0;
1640 if (!strcmp(ent
->value
, "drm")) {
1642 } else if (!strcmp(ent
->value
, "x11")) {
1645 av_log(ctx
, AV_LOG_ERROR
, "Invalid connection type %s.\n",
1647 return AVERROR(EINVAL
);
1651 try_drm
= HAVE_VAAPI_DRM
;
1652 try_x11
= HAVE_VAAPI_X11
;
1656 while (!display
&& try_drm
) {
1657 // If the device is specified, try to open it as a DRM device node.
1658 // If not, look for a usable render node, possibly restricted to those
1659 // using a specified kernel driver.
1660 int loglevel
= try_all
? AV_LOG_VERBOSE
: AV_LOG_ERROR
;
1662 priv
->drm_fd
= open(device
, O_RDWR
);
1663 if (priv
->drm_fd
< 0) {
1664 av_log(ctx
, loglevel
, "Failed to open %s as "
1665 "DRM device node.\n", device
);
1670 int n
, max_devices
= 8;
1672 const AVDictionaryEntry
*kernel_driver
;
1673 kernel_driver
= av_dict_get(opts
, "kernel_driver", NULL
, 0);
1675 for (n
= 0; n
< max_devices
; n
++) {
1676 snprintf(path
, sizeof(path
),
1677 "/dev/dri/renderD%d", 128 + n
);
1678 priv
->drm_fd
= open(path
, O_RDWR
);
1679 if (priv
->drm_fd
< 0) {
1680 av_log(ctx
, AV_LOG_VERBOSE
, "Cannot open "
1681 "DRM render node for device %d.\n", n
);
1685 if (kernel_driver
) {
1687 info
= drmGetVersion(priv
->drm_fd
);
1688 if (strcmp(kernel_driver
->value
, info
->name
)) {
1689 av_log(ctx
, AV_LOG_VERBOSE
, "Ignoring device %d "
1690 "with non-matching kernel driver (%s).\n",
1692 drmFreeVersion(info
);
1693 close(priv
->drm_fd
);
1697 av_log(ctx
, AV_LOG_VERBOSE
, "Trying to use "
1698 "DRM render node for device %d, "
1699 "with matching kernel driver (%s).\n",
1701 drmFreeVersion(info
);
1705 av_log(ctx
, AV_LOG_VERBOSE
, "Trying to use "
1706 "DRM render node for device %d.\n", n
);
1710 if (n
>= max_devices
)
1714 display
= vaGetDisplayDRM(priv
->drm_fd
);
1716 av_log(ctx
, AV_LOG_VERBOSE
, "Cannot open a VA display "
1717 "from DRM device %s.\n", device
);
1718 return AVERROR_EXTERNAL
;
1725 if (!display
&& try_x11
) {
1726 // Try to open the device as an X11 display.
1727 priv
->x11_display
= XOpenDisplay(device
);
1728 if (!priv
->x11_display
) {
1729 av_log(ctx
, AV_LOG_VERBOSE
, "Cannot open X11 display "
1730 "%s.\n", XDisplayName(device
));
1732 display
= vaGetDisplay(priv
->x11_display
);
1734 av_log(ctx
, AV_LOG_ERROR
, "Cannot open a VA display "
1735 "from X11 display %s.\n", XDisplayName(device
));
1736 return AVERROR_UNKNOWN
;
1739 av_log(ctx
, AV_LOG_VERBOSE
, "Opened VA display via "
1740 "X11 display %s.\n", XDisplayName(device
));
1747 av_log(ctx
, AV_LOG_ERROR
, "No VA display found for "
1748 "device %s.\n", device
);
1750 av_log(ctx
, AV_LOG_ERROR
, "No VA display found for "
1751 "any default device.\n");
1752 return AVERROR(EINVAL
);
1755 ent
= av_dict_get(opts
, "driver", NULL
, 0);
1757 #if VA_CHECK_VERSION(0, 38, 0)
1759 vas
= vaSetDriverName(display
, ent
->value
);
1760 if (vas
!= VA_STATUS_SUCCESS
) {
1761 av_log(ctx
, AV_LOG_ERROR
, "Failed to set driver name to "
1762 "%s: %d (%s).\n", ent
->value
, vas
, vaErrorStr(vas
));
1763 vaTerminate(display
);
1764 return AVERROR_EXTERNAL
;
1767 av_log(ctx
, AV_LOG_WARNING
, "Driver name setting is not "
1768 "supported with this VAAPI version.\n");
1772 return vaapi_device_connect(ctx
, display
);
1775 static int vaapi_device_derive(AVHWDeviceContext
*ctx
,
1776 AVHWDeviceContext
*src_ctx
,
1777 AVDictionary
*opts
, int flags
)
1780 if (src_ctx
->type
== AV_HWDEVICE_TYPE_DRM
) {
1781 AVDRMDeviceContext
*src_hwctx
= src_ctx
->hwctx
;
1783 VAAPIDevicePriv
*priv
;
1786 if (src_hwctx
->fd
< 0) {
1787 av_log(ctx
, AV_LOG_ERROR
, "DRM instance requires an associated "
1788 "device to derive a VA display from.\n");
1789 return AVERROR(EINVAL
);
1794 int node_type
= drmGetNodeTypeFromFd(src_hwctx
->fd
);
1796 if (node_type
< 0) {
1797 av_log(ctx
, AV_LOG_ERROR
, "DRM instance fd does not appear "
1798 "to refer to a DRM device.\n");
1799 return AVERROR(EINVAL
);
1801 if (node_type
== DRM_NODE_RENDER
) {
1804 render_node
= drmGetRenderDeviceNameFromFd(src_hwctx
->fd
);
1806 av_log(ctx
, AV_LOG_VERBOSE
, "Using non-render node "
1807 "because the device does not have an "
1808 "associated render node.\n");
1811 fd
= open(render_node
, O_RDWR
);
1813 av_log(ctx
, AV_LOG_VERBOSE
, "Using non-render node "
1814 "because the associated render node "
1815 "could not be opened.\n");
1818 av_log(ctx
, AV_LOG_VERBOSE
, "Using render node %s "
1819 "in place of non-render DRM device.\n",
1830 priv
= av_mallocz(sizeof(*priv
));
1832 if (fd
!= src_hwctx
->fd
) {
1833 // The fd was opened in this function.
1836 return AVERROR(ENOMEM
);
1839 if (fd
== src_hwctx
->fd
) {
1840 // The fd is inherited from the source context and we are holding
1841 // a reference to that, we don't want to close it from here.
1847 ctx
->user_opaque
= priv
;
1848 ctx
->free
= &vaapi_device_free
;
1850 display
= vaGetDisplayDRM(fd
);
1852 av_log(ctx
, AV_LOG_ERROR
, "Failed to open a VA display from "
1854 return AVERROR(EIO
);
1857 return vaapi_device_connect(ctx
, display
);
1860 return AVERROR(ENOSYS
);
1863 const HWContextType ff_hwcontext_type_vaapi
= {
1864 .type
= AV_HWDEVICE_TYPE_VAAPI
,
1867 .device_hwctx_size
= sizeof(AVVAAPIDeviceContext
),
1868 .device_priv_size
= sizeof(VAAPIDeviceContext
),
1869 .device_hwconfig_size
= sizeof(AVVAAPIHWConfig
),
1870 .frames_hwctx_size
= sizeof(AVVAAPIFramesContext
),
1871 .frames_priv_size
= sizeof(VAAPIFramesContext
),
1873 .device_create
= &vaapi_device_create
,
1874 .device_derive
= &vaapi_device_derive
,
1875 .device_init
= &vaapi_device_init
,
1876 .device_uninit
= &vaapi_device_uninit
,
1877 .frames_get_constraints
= &vaapi_frames_get_constraints
,
1878 .frames_init
= &vaapi_frames_init
,
1879 .frames_uninit
= &vaapi_frames_uninit
,
1880 .frames_get_buffer
= &vaapi_get_buffer
,
1881 .transfer_get_formats
= &vaapi_transfer_get_formats
,
1882 .transfer_data_to
= &vaapi_transfer_data_to
,
1883 .transfer_data_from
= &vaapi_transfer_data_from
,
1884 .map_to
= &vaapi_map_to
,
1885 .map_from
= &vaapi_map_from
,
1887 .pix_fmts
= (const enum AVPixelFormat
[]) {