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)
96 } VAAPIFormatDescriptor;
98 #define MAP(va, rt, av, swap_uv) { \
100 VA_RT_FORMAT_ ## rt, \
107 MAP(NV12, YUV420, NV12, 0),
108 #ifdef VA_FOURCC_I420
109 MAP(I420, YUV420, YUV420P, 0),
111 MAP(YV12, YUV420, YUV420P, 1),
112 MAP(IYUV, YUV420, YUV420P, 0),
113 MAP(422
H, YUV422, YUV422P, 0),
114 #ifdef VA_FOURCC_YV16
115 MAP(YV16, YUV422, YUV422P, 1),
117 MAP(UYVY, YUV422, UYVY422, 0),
118 MAP(YUY2, YUV422, YUYV422, 0),
119 MAP(411
P, YUV411, YUV411P, 0),
120 MAP(422
V, YUV422, YUV440P, 0),
121 MAP(444
P, YUV444, YUV444P, 0),
122 MAP(Y800, YUV400, GRAY8, 0),
123 #ifdef VA_FOURCC_P010
124 MAP(P010, YUV420_10BPP, P010, 0),
126 MAP(BGRA, RGB32, BGRA, 0),
127 MAP(BGRX, RGB32, BGR0, 0),
129 MAP(RGBX, RGB32, RGB0, 0),
130 #ifdef VA_FOURCC_ABGR
131 MAP(ABGR, RGB32, ABGR, 0),
132 MAP(XBGR, RGB32, 0BGR, 0),
134 MAP(ARGB, RGB32, ARGB, 0),
135 MAP(XRGB, RGB32, 0RGB, 0),
139 static const VAAPIFormatDescriptor *
149 static const VAAPIFormatDescriptor *
161 const VAAPIFormatDescriptor *
desc;
164 return desc->pix_fmt;
171 VAImageFormat **image_format)
176 for (
i = 0;
i <
ctx->nb_formats;
i++) {
179 *image_format = &
ctx->formats[
i].image_format;
187 const void *hwconfig,
193 VASurfaceAttrib *attr_list =
NULL;
197 int err,
i, j, attr_count, pix_fmt_count;
204 if (vas != VA_STATUS_SUCCESS) {
206 "%d (%s).\n", vas, vaErrorStr(vas));
211 attr_list =
av_malloc(attr_count *
sizeof(*attr_list));
218 attr_list, &attr_count);
219 if (vas != VA_STATUS_SUCCESS) {
221 "%d (%s).\n", vas, vaErrorStr(vas));
227 for (
i = 0;
i < attr_count;
i++) {
228 switch (attr_list[
i].
type) {
229 case VASurfaceAttribPixelFormat:
230 fourcc = attr_list[
i].value.value.i;
238 case VASurfaceAttribMinWidth:
239 constraints->
min_width = attr_list[
i].value.value.i;
241 case VASurfaceAttribMinHeight:
242 constraints->
min_height = attr_list[
i].value.value.i;
244 case VASurfaceAttribMaxWidth:
245 constraints->
max_width = attr_list[
i].value.value.i;
247 case VASurfaceAttribMaxHeight:
248 constraints->
max_height = attr_list[
i].value.value.i;
252 if (pix_fmt_count == 0) {
264 for (
i = j = 0;
i < attr_count;
i++) {
265 if (attr_list[
i].
type != VASurfaceAttribPixelFormat)
267 fourcc = attr_list[
i].value.value.i;
284 for (
i = 0;
i <
ctx->nb_formats;
i++)
303 static const struct {
308 #if !VA_CHECK_VERSION(1, 0, 0)
311 "Intel i965 (Quick Sync)",
323 "Splitted-Desktop Systems VDPAU backend for VA-API",
332 VAImageFormat *image_list =
NULL;
334 const char *vendor_string;
335 int err,
i, image_count;
339 image_count = vaMaxNumImageFormats(hwctx->
display);
340 if (image_count <= 0) {
344 image_list =
av_malloc(image_count *
sizeof(*image_list));
349 vas = vaQueryImageFormats(hwctx->
display, image_list, &image_count);
350 if (vas != VA_STATUS_SUCCESS) {
361 for (
i = 0;
i < image_count;
i++) {
371 ctx->formats[
ctx->nb_formats].image_format = image_list[
i];
376 vendor_string = vaQueryVendorString(hwctx->
display);
388 if (strstr(vendor_string,
391 "as known nonstandard driver \"%s\", setting "
402 "nonstandard list, using standard behaviour.\n");
406 "assuming standard behaviour.\n");
429 VASurfaceID surface_id;
432 surface_id = (VASurfaceID)(uintptr_t)
data;
434 vas = vaDestroySurfaces(hwctx->
display, &surface_id, 1);
435 if (vas != VA_STATUS_SUCCESS) {
437 "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
447 VASurfaceID surface_id;
455 vas = vaCreateSurfaces(hwctx->
display,
ctx->rt_format,
458 ctx->attributes,
ctx->nb_attributes);
459 if (vas != VA_STATUS_SUCCESS) {
461 "%d (%s).\n", vas, vaErrorStr(vas));
470 vaDestroySurfaces(hwctx->
display, &surface_id, 1);
490 const VAAPIFormatDescriptor *
desc;
491 VAImageFormat *expected_format;
493 VASurfaceID test_surface_id;
508 int need_pixel_format = 1;
510 if (avfc->
attributes[
i].type == VASurfaceAttribMemoryType)
511 need_memory_type = 0;
512 if (avfc->
attributes[
i].type == VASurfaceAttribPixelFormat)
513 need_pixel_format = 0;
519 sizeof(*
ctx->attributes));
520 if (!
ctx->attributes) {
527 if (need_memory_type) {
528 ctx->attributes[
i++] = (VASurfaceAttrib) {
529 .type = VASurfaceAttribMemoryType,
530 .
flags = VA_SURFACE_ATTRIB_SETTABLE,
531 .value.type = VAGenericValueTypeInteger,
532 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
535 if (need_pixel_format) {
536 ctx->attributes[
i++] = (VASurfaceAttrib) {
537 .type = VASurfaceAttribPixelFormat,
538 .
flags = VA_SURFACE_ATTRIB_SETTABLE,
539 .value.type = VAGenericValueTypeInteger,
540 .value.value.i =
desc->fourcc,
546 ctx->nb_attributes = 0;
549 ctx->rt_format =
desc->rt_format;
585 "user-configured buffer pool.\n");
593 "internal buffer pool.\n");
598 test_surface_id = (VASurfaceID)(uintptr_t)test_surface->
data;
600 ctx->derive_works = 0;
605 vas = vaDeriveImage(hwctx->
display, test_surface_id, &test_image);
606 if (vas == VA_STATUS_SUCCESS) {
607 if (expected_format->fourcc == test_image.format.fourcc) {
609 ctx->derive_works = 1;
612 "derived image format %08x does not match "
613 "expected format %08x.\n",
614 expected_format->fourcc, test_image.format.fourcc);
616 vaDestroyImage(hwctx->
display, test_image.image_id);
619 "deriving image does not work: "
620 "%d (%s).\n", vas, vaErrorStr(vas));
624 "image format is not supported.\n");
666 int i, k, sw_format_available;
668 sw_format_available = 0;
669 for (
i = 0;
i <
ctx->nb_formats;
i++) {
671 sw_format_available = 1;
678 if (sw_format_available) {
684 for (
i = 0;
i <
ctx->nb_formats;
i++) {
701 VASurfaceID surface_id;
704 surface_id = (VASurfaceID)(uintptr_t)hwmap->
source->
data[3];
707 vas = vaUnmapBuffer(hwctx->
display,
map->image.buf);
708 if (vas != VA_STATUS_SUCCESS) {
710 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
715 vas = vaPutImage(hwctx->
display, surface_id,
map->image.image_id,
718 if (vas != VA_STATUS_SUCCESS) {
720 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
724 vas = vaDestroyImage(hwctx->
display,
map->image.image_id);
725 if (vas != VA_STATUS_SUCCESS) {
727 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
738 VASurfaceID surface_id;
739 const VAAPIFormatDescriptor *
desc;
740 VAImageFormat *image_format;
743 void *address =
NULL;
746 surface_id = (VASurfaceID)(uintptr_t)
src->data[3];
770 map->image.image_id = VA_INVALID_ID;
772 vas = vaSyncSurface(hwctx->
display, surface_id);
773 if (vas != VA_STATUS_SUCCESS) {
775 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
789 vas = vaDeriveImage(hwctx->
display, surface_id, &
map->image);
790 if (vas != VA_STATUS_SUCCESS) {
792 "surface %#x: %d (%s).\n",
793 surface_id, vas, vaErrorStr(vas));
797 if (
map->image.format.fourcc != image_format->fourcc) {
799 "is in wrong format: expected %#08x, got %#08x.\n",
800 surface_id, image_format->fourcc,
map->image.format.fourcc);
806 vas = vaCreateImage(hwctx->
display, image_format,
808 if (vas != VA_STATUS_SUCCESS) {
810 "surface %#x: %d (%s).\n",
811 surface_id, vas, vaErrorStr(vas));
816 vas = vaGetImage(hwctx->
display, surface_id, 0, 0,
818 if (vas != VA_STATUS_SUCCESS) {
820 "surface %#x: %d (%s).\n",
821 surface_id, vas, vaErrorStr(vas));
828 vas = vaMapBuffer(hwctx->
display,
map->image.buf, &address);
829 if (vas != VA_STATUS_SUCCESS) {
831 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
844 for (
i = 0;
i <
map->image.num_planes;
i++) {
850 if (
desc &&
desc->chroma_planes_swapped) {
860 vaUnmapBuffer(hwctx->
display,
map->image.buf);
861 if (
map->image.image_id != VA_INVALID_ID)
862 vaDestroyImage(hwctx->
display,
map->image.image_id);
911 map->format =
src->format;
918 map->height =
src->height;
954 #define DRM_MAP(va, layers, ...) { \
959 static const struct {
961 int nb_layer_formats;
963 } vaapi_drm_format_map[] = {
965 DRM_MAP(NV12, 2, DRM_FORMAT_R8, DRM_FORMAT_RG88),
967 DRM_MAP(NV12, 1, DRM_FORMAT_NV12),
968 #if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16)
969 DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
971 DRM_MAP(BGRA, 1, DRM_FORMAT_ARGB8888),
972 DRM_MAP(BGRX, 1, DRM_FORMAT_XRGB8888),
973 DRM_MAP(
RGBA, 1, DRM_FORMAT_ABGR8888),
974 DRM_MAP(RGBX, 1, DRM_FORMAT_XBGR8888),
975 #ifdef VA_FOURCC_ABGR
976 DRM_MAP(ABGR, 1, DRM_FORMAT_RGBA8888),
977 DRM_MAP(XBGR, 1, DRM_FORMAT_RGBX8888),
979 DRM_MAP(ARGB, 1, DRM_FORMAT_BGRA8888),
980 DRM_MAP(XRGB, 1, DRM_FORMAT_BGRX8888),
989 VASurfaceID surface_id = (VASurfaceID)(uintptr_t)hwmap->
priv;
993 vaDestroySurfaces(dst_dev->
display, &surface_id, 1);
1003 const VAAPIFormatDescriptor *format_desc;
1004 VASurfaceID surface_id;
1009 unsigned long buffer_handle;
1010 VASurfaceAttribExternalBuffers buffer_desc;
1011 VASurfaceAttrib attrs[2] = {
1013 .type = VASurfaceAttribMemoryType,
1014 .flags = VA_SURFACE_ATTRIB_SETTABLE,
1015 .value.type = VAGenericValueTypeInteger,
1016 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
1019 .type = VASurfaceAttribExternalBufferDescriptor,
1020 .flags = VA_SURFACE_ATTRIB_SETTABLE,
1021 .value.type = VAGenericValueTypePointer,
1022 .value.value.p = &buffer_desc,
1028 if (
desc->nb_objects != 1) {
1030 "made from a single DRM object.\n");
1036 if (
desc->nb_layers != vaapi_drm_format_map[
i].nb_layer_formats)
1038 for (j = 0; j <
desc->nb_layers; j++) {
1039 if (
desc->layers[j].format !=
1040 vaapi_drm_format_map[
i].layer_formats[j])
1043 if (j !=
desc->nb_layers)
1045 va_fourcc = vaapi_drm_format_map[
i].va_fourcc;
1055 "%08x.\n",
desc->objects[0].fd, va_fourcc);
1060 buffer_handle =
desc->objects[0].fd;
1061 buffer_desc.pixel_format = va_fourcc;
1062 buffer_desc.width = src_fc->width;
1063 buffer_desc.height = src_fc->height;
1064 buffer_desc.data_size =
desc->objects[0].size;
1065 buffer_desc.buffers = &buffer_handle;
1066 buffer_desc.num_buffers = 1;
1067 buffer_desc.flags = 0;
1070 for (
i = 0;
i <
desc->nb_layers;
i++) {
1071 for (j = 0; j <
desc->layers[
i].nb_planes; j++) {
1072 buffer_desc.pitches[k] =
desc->layers[
i].planes[j].pitch;
1073 buffer_desc.offsets[k] =
desc->layers[
i].planes[j].offset;
1077 buffer_desc.num_planes = k;
1079 if (format_desc->chroma_planes_swapped &&
1080 buffer_desc.num_planes == 3) {
1081 FFSWAP(uint32_t, buffer_desc.pitches[1], buffer_desc.pitches[2]);
1082 FFSWAP(uint32_t, buffer_desc.offsets[1], buffer_desc.offsets[2]);
1085 vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format,
1089 if (vas != VA_STATUS_SUCCESS) {
1091 "object: %d (%s).\n", vas, vaErrorStr(vas));
1097 &vaapi_unmap_from_drm,
1098 (
void*)(uintptr_t)surface_id);
1102 dst->width =
src->width;
1103 dst->height =
src->height;
1104 dst->data[3] = (
uint8_t*)(uintptr_t)surface_id;
1107 "surface %#x.\n",
desc->objects[0].fd, surface_id);
1112 #if VA_CHECK_VERSION(1, 1, 0)
1129 VASurfaceID surface_id;
1131 VADRMPRIMESurfaceDescriptor va_desc;
1133 uint32_t export_flags;
1136 surface_id = (VASurfaceID)(uintptr_t)
src->data[3];
1138 export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS;
1140 export_flags |= VA_EXPORT_SURFACE_READ_ONLY;
1142 export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY;
1144 vas = vaExportSurfaceHandle(hwctx->
display, surface_id,
1145 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
1146 export_flags, &va_desc);
1147 if (vas != VA_STATUS_SUCCESS) {
1148 if (vas == VA_STATUS_ERROR_UNIMPLEMENTED)
1151 "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
1163 for (
i = 0;
i < va_desc.num_objects;
i++) {
1167 va_desc.objects[
i].drm_format_modifier;
1169 drm_desc->
nb_layers = va_desc.num_layers;
1170 for (
i = 0;
i < va_desc.num_layers;
i++) {
1173 for (j = 0; j < va_desc.layers[
i].num_planes; j++) {
1175 va_desc.layers[
i].object_index[j];
1177 va_desc.layers[
i].offset[j];
1179 va_desc.layers[
i].pitch[j];
1184 &vaapi_unmap_to_drm_esh, drm_desc);
1195 for (
i = 0;
i < va_desc.num_objects;
i++)
1196 close(va_desc.objects[
i].fd);
1202 #if VA_CHECK_VERSION(0, 36, 0)
1203 typedef struct VAAPIDRMImageBufferMapping {
1205 VABufferInfo buffer_info;
1208 } VAAPIDRMImageBufferMapping;
1214 VAAPIDRMImageBufferMapping *mapping = hwmap->
priv;
1215 VASurfaceID surface_id;
1218 surface_id = (VASurfaceID)(uintptr_t)hwmap->
source->
data[3];
1225 vas = vaReleaseBufferHandle(hwctx->
display, mapping->image.buf);
1226 if (vas != VA_STATUS_SUCCESS) {
1228 "handle of image %#x (derived from surface %#x): "
1229 "%d (%s).\n", mapping->image.buf, surface_id,
1230 vas, vaErrorStr(vas));
1233 vas = vaDestroyImage(hwctx->
display, mapping->image.image_id);
1234 if (vas != VA_STATUS_SUCCESS) {
1236 "derived from surface %#x: %d (%s).\n",
1237 surface_id, vas, vaErrorStr(vas));
1247 VAAPIDRMImageBufferMapping *mapping =
NULL;
1248 VASurfaceID surface_id;
1252 surface_id = (VASurfaceID)(uintptr_t)
src->data[3];
1260 vas = vaDeriveImage(hwctx->
display, surface_id,
1262 if (vas != VA_STATUS_SUCCESS) {
1264 "surface %#x: %d (%s).\n",
1265 surface_id, vas, vaErrorStr(vas));
1271 if (vaapi_drm_format_map[
i].va_fourcc ==
1272 mapping->image.format.fourcc)
1277 "VAAPI format %#x.\n", mapping->image.format.fourcc);
1282 mapping->buffer_info.mem_type =
1283 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
1285 mapping->drm_desc.nb_layers =
1286 vaapi_drm_format_map[
i].nb_layer_formats;
1287 if (mapping->drm_desc.nb_layers > 1) {
1288 if (mapping->drm_desc.nb_layers != mapping->image.num_planes) {
1290 "expected format: got %d planes, but expected %d.\n",
1291 mapping->image.num_planes, mapping->drm_desc.nb_layers);
1296 for(p = 0; p < mapping->drm_desc.nb_layers; p++) {
1298 .format = vaapi_drm_format_map[
i].layer_formats[p],
1302 .offset = mapping->image.offsets[p],
1303 .pitch = mapping->image.pitches[p],
1308 mapping->drm_desc.layers[0].format =
1309 vaapi_drm_format_map[
i].layer_formats[0];
1310 mapping->drm_desc.layers[0].nb_planes = mapping->image.num_planes;
1311 for (p = 0; p < mapping->image.num_planes; p++) {
1314 .offset = mapping->image.offsets[p],
1315 .pitch = mapping->image.pitches[p],
1320 vas = vaAcquireBufferHandle(hwctx->
display, mapping->image.buf,
1321 &mapping->buffer_info);
1322 if (vas != VA_STATUS_SUCCESS) {
1324 "handle from image %#x (derived from surface %#x): "
1325 "%d (%s).\n", mapping->image.buf, surface_id,
1326 vas, vaErrorStr(vas));
1332 mapping->buffer_info.handle);
1334 mapping->drm_desc.nb_objects = 1;
1336 .fd = mapping->buffer_info.handle,
1337 .size = mapping->image.data_size,
1339 .format_modifier = DRM_FORMAT_MOD_INVALID,
1343 dst,
src, &vaapi_unmap_to_drm_abh,
1355 vaReleaseBufferHandle(hwctx->
display, mapping->image.buf);
1357 vaDestroyImage(hwctx->
display, mapping->image.image_id);
1367 #if VA_CHECK_VERSION(1, 1, 0)
1369 err = vaapi_map_to_drm_esh(hwfc, dst,
src,
flags);
1373 #if VA_CHECK_VERSION(0, 36, 0)
1374 return vaapi_map_to_drm_abh(hwfc, dst,
src,
flags);
1384 switch (
src->format) {
1387 return vaapi_map_from_drm(hwfc, dst,
src,
flags);
1400 return vaapi_map_to_drm(hwfc, dst,
src,
flags);
1416 if (priv->x11_display)
1417 XCloseDisplay(priv->x11_display);
1427 static void vaapi_device_log_error(
void *
context,
const char *
message)
1434 static void vaapi_device_log_info(
void *
context,
const char *
message)
1450 vaSetErrorCallback(display, &vaapi_device_log_error,
ctx);
1451 vaSetInfoCallback (display, &vaapi_device_log_info,
ctx);
1456 vas = vaInitialize(display, &major, &minor);
1457 if (vas != VA_STATUS_SUCCESS) {
1459 "connection: %d (%s).\n", vas, vaErrorStr(vas));
1463 "version %d.%d\n", major, minor);
1472 VADisplay display =
NULL;
1474 int try_drm, try_x11, try_all;
1482 ctx->user_opaque = priv;
1487 try_all = try_drm = try_x11 = 0;
1488 if (!strcmp(ent->
value,
"drm")) {
1490 }
else if (!strcmp(ent->
value,
"x11")) {
1499 try_drm = HAVE_VAAPI_DRM;
1500 try_x11 = HAVE_VAAPI_X11;
1504 while (!display && try_drm) {
1510 priv->
drm_fd = open(device, O_RDWR);
1512 av_log(
ctx, loglevel,
"Failed to open %s as "
1513 "DRM device node.\n", device);
1518 int n, max_devices = 8;
1523 for (
n = 0;
n < max_devices;
n++) {
1525 "/dev/dri/renderD%d", 128 +
n);
1526 priv->
drm_fd = open(path, O_RDWR);
1529 "DRM render node for device %d.\n",
n);
1533 if (kernel_driver) {
1536 if (strcmp(kernel_driver->
value,
info->name)) {
1538 "with non-matching kernel driver (%s).\n",
1540 drmFreeVersion(
info);
1546 "DRM render node for device %d, "
1547 "with matching kernel driver (%s).\n",
1549 drmFreeVersion(
info);
1554 "DRM render node for device %d.\n",
n);
1558 if (
n >= max_devices)
1562 display = vaGetDisplayDRM(priv->
drm_fd);
1565 "from DRM device %s.\n", device);
1573 if (!display && try_x11) {
1575 priv->x11_display = XOpenDisplay(device);
1576 if (!priv->x11_display) {
1578 "%s.\n", XDisplayName(device));
1580 display = vaGetDisplay(priv->x11_display);
1583 "from X11 display %s.\n", XDisplayName(device));
1588 "X11 display %s.\n", XDisplayName(device));
1596 "device %s.\n", device);
1599 "any default device.\n");
1605 #if VA_CHECK_VERSION(0, 38, 0)
1607 vas = vaSetDriverName(display, ent->
value);
1608 if (vas != VA_STATUS_SUCCESS) {
1610 "%s: %d (%s).\n", ent->
value, vas, vaErrorStr(vas));
1611 vaTerminate(display);
1616 "supported with this VAAPI version.\n");
1632 if (src_hwctx->
fd < 0) {
1634 "device to derive a VA display from.\n");
1645 ctx->user_opaque = priv;
1648 display = vaGetDisplayDRM(src_hwctx->
fd);