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 #ifdef VA_FOURCC_Y210
120 MAP(Y210, YUV422_10, Y210, 0),
122 MAP(411
P, YUV411, YUV411P, 0),
123 MAP(422
V, YUV422, YUV440P, 0),
124 MAP(444
P, YUV444, YUV444P, 0),
125 MAP(Y800, YUV400, GRAY8, 0),
126 #ifdef VA_FOURCC_P010
127 MAP(P010, YUV420_10BPP, P010, 0),
129 MAP(BGRA, RGB32, BGRA, 0),
130 MAP(BGRX, RGB32, BGR0, 0),
132 MAP(RGBX, RGB32, RGB0, 0),
133 #ifdef VA_FOURCC_ABGR
134 MAP(ABGR, RGB32, ABGR, 0),
135 MAP(XBGR, RGB32, 0BGR, 0),
137 MAP(ARGB, RGB32, ARGB, 0),
138 MAP(XRGB, RGB32, 0RGB, 0),
142 static const VAAPIFormatDescriptor *
152 static const VAAPIFormatDescriptor *
164 const VAAPIFormatDescriptor *
desc;
167 return desc->pix_fmt;
174 VAImageFormat **image_format)
179 for (
i = 0;
i <
ctx->nb_formats;
i++) {
182 *image_format = &
ctx->formats[
i].image_format;
190 const void *hwconfig,
196 VASurfaceAttrib *attr_list =
NULL;
200 int err,
i, j, attr_count, pix_fmt_count;
207 if (vas != VA_STATUS_SUCCESS) {
209 "%d (%s).\n", vas, vaErrorStr(vas));
214 attr_list =
av_malloc(attr_count *
sizeof(*attr_list));
221 attr_list, &attr_count);
222 if (vas != VA_STATUS_SUCCESS) {
224 "%d (%s).\n", vas, vaErrorStr(vas));
230 for (
i = 0;
i < attr_count;
i++) {
231 switch (attr_list[
i].
type) {
232 case VASurfaceAttribPixelFormat:
233 fourcc = attr_list[
i].value.value.i;
241 case VASurfaceAttribMinWidth:
242 constraints->
min_width = attr_list[
i].value.value.i;
244 case VASurfaceAttribMinHeight:
245 constraints->
min_height = attr_list[
i].value.value.i;
247 case VASurfaceAttribMaxWidth:
248 constraints->
max_width = attr_list[
i].value.value.i;
250 case VASurfaceAttribMaxHeight:
251 constraints->
max_height = attr_list[
i].value.value.i;
255 if (pix_fmt_count == 0) {
267 for (
i = j = 0;
i < attr_count;
i++) {
268 if (attr_list[
i].
type != VASurfaceAttribPixelFormat)
270 fourcc = attr_list[
i].value.value.i;
287 for (
i = 0;
i <
ctx->nb_formats;
i++)
306 static const struct {
311 #if !VA_CHECK_VERSION(1, 0, 0)
314 "Intel i965 (Quick Sync)",
326 "Splitted-Desktop Systems VDPAU backend for VA-API",
335 VAImageFormat *image_list =
NULL;
337 const char *vendor_string;
338 int err,
i, image_count;
342 image_count = vaMaxNumImageFormats(hwctx->
display);
343 if (image_count <= 0) {
347 image_list =
av_malloc(image_count *
sizeof(*image_list));
352 vas = vaQueryImageFormats(hwctx->
display, image_list, &image_count);
353 if (vas != VA_STATUS_SUCCESS) {
364 for (
i = 0;
i < image_count;
i++) {
374 ctx->formats[
ctx->nb_formats].image_format = image_list[
i];
379 vendor_string = vaQueryVendorString(hwctx->
display);
391 if (strstr(vendor_string,
394 "as known nonstandard driver \"%s\", setting "
405 "nonstandard list, using standard behaviour.\n");
409 "assuming standard behaviour.\n");
432 VASurfaceID surface_id;
435 surface_id = (VASurfaceID)(uintptr_t)
data;
437 vas = vaDestroySurfaces(hwctx->
display, &surface_id, 1);
438 if (vas != VA_STATUS_SUCCESS) {
440 "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
450 VASurfaceID surface_id;
458 vas = vaCreateSurfaces(hwctx->
display,
ctx->rt_format,
461 ctx->attributes,
ctx->nb_attributes);
462 if (vas != VA_STATUS_SUCCESS) {
464 "%d (%s).\n", vas, vaErrorStr(vas));
473 vaDestroySurfaces(hwctx->
display, &surface_id, 1);
493 const VAAPIFormatDescriptor *
desc;
494 VAImageFormat *expected_format;
496 VASurfaceID test_surface_id;
511 int need_pixel_format = 1;
513 if (avfc->
attributes[
i].type == VASurfaceAttribMemoryType)
514 need_memory_type = 0;
515 if (avfc->
attributes[
i].type == VASurfaceAttribPixelFormat)
516 need_pixel_format = 0;
522 sizeof(*
ctx->attributes));
523 if (!
ctx->attributes) {
530 if (need_memory_type) {
531 ctx->attributes[
i++] = (VASurfaceAttrib) {
532 .type = VASurfaceAttribMemoryType,
533 .
flags = VA_SURFACE_ATTRIB_SETTABLE,
534 .value.type = VAGenericValueTypeInteger,
535 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
538 if (need_pixel_format) {
539 ctx->attributes[
i++] = (VASurfaceAttrib) {
540 .type = VASurfaceAttribPixelFormat,
541 .
flags = VA_SURFACE_ATTRIB_SETTABLE,
542 .value.type = VAGenericValueTypeInteger,
543 .value.value.i =
desc->fourcc,
549 ctx->nb_attributes = 0;
552 ctx->rt_format =
desc->rt_format;
588 "user-configured buffer pool.\n");
596 "internal buffer pool.\n");
601 test_surface_id = (VASurfaceID)(uintptr_t)test_surface->
data;
603 ctx->derive_works = 0;
608 vas = vaDeriveImage(hwctx->
display, test_surface_id, &test_image);
609 if (vas == VA_STATUS_SUCCESS) {
610 if (expected_format->fourcc == test_image.format.fourcc) {
612 ctx->derive_works = 1;
615 "derived image format %08x does not match "
616 "expected format %08x.\n",
617 expected_format->fourcc, test_image.format.fourcc);
619 vaDestroyImage(hwctx->
display, test_image.image_id);
622 "deriving image does not work: "
623 "%d (%s).\n", vas, vaErrorStr(vas));
627 "image format is not supported.\n");
669 int i, k, sw_format_available;
671 sw_format_available = 0;
672 for (
i = 0;
i <
ctx->nb_formats;
i++) {
674 sw_format_available = 1;
681 if (sw_format_available) {
687 for (
i = 0;
i <
ctx->nb_formats;
i++) {
704 VASurfaceID surface_id;
707 surface_id = (VASurfaceID)(uintptr_t)hwmap->
source->
data[3];
710 vas = vaUnmapBuffer(hwctx->
display,
map->image.buf);
711 if (vas != VA_STATUS_SUCCESS) {
713 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
718 vas = vaPutImage(hwctx->
display, surface_id,
map->image.image_id,
721 if (vas != VA_STATUS_SUCCESS) {
723 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
727 vas = vaDestroyImage(hwctx->
display,
map->image.image_id);
728 if (vas != VA_STATUS_SUCCESS) {
730 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
741 VASurfaceID surface_id;
742 const VAAPIFormatDescriptor *
desc;
743 VAImageFormat *image_format;
746 void *address =
NULL;
749 surface_id = (VASurfaceID)(uintptr_t)
src->data[3];
773 map->image.image_id = VA_INVALID_ID;
775 vas = vaSyncSurface(hwctx->
display, surface_id);
776 if (vas != VA_STATUS_SUCCESS) {
778 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
792 vas = vaDeriveImage(hwctx->
display, surface_id, &
map->image);
793 if (vas != VA_STATUS_SUCCESS) {
795 "surface %#x: %d (%s).\n",
796 surface_id, vas, vaErrorStr(vas));
800 if (
map->image.format.fourcc != image_format->fourcc) {
802 "is in wrong format: expected %#08x, got %#08x.\n",
803 surface_id, image_format->fourcc,
map->image.format.fourcc);
809 vas = vaCreateImage(hwctx->
display, image_format,
811 if (vas != VA_STATUS_SUCCESS) {
813 "surface %#x: %d (%s).\n",
814 surface_id, vas, vaErrorStr(vas));
819 vas = vaGetImage(hwctx->
display, surface_id, 0, 0,
821 if (vas != VA_STATUS_SUCCESS) {
823 "surface %#x: %d (%s).\n",
824 surface_id, vas, vaErrorStr(vas));
831 vas = vaMapBuffer(hwctx->
display,
map->image.buf, &address);
832 if (vas != VA_STATUS_SUCCESS) {
834 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
847 for (
i = 0;
i <
map->image.num_planes;
i++) {
853 if (
desc &&
desc->chroma_planes_swapped) {
863 vaUnmapBuffer(hwctx->
display,
map->image.buf);
864 if (
map->image.image_id != VA_INVALID_ID)
865 vaDestroyImage(hwctx->
display,
map->image.image_id);
914 map->format =
src->format;
921 map->height =
src->height;
957 #define DRM_MAP(va, layers, ...) { \
962 static const struct {
964 int nb_layer_formats;
966 } vaapi_drm_format_map[] = {
968 DRM_MAP(NV12, 2, DRM_FORMAT_R8, DRM_FORMAT_RG88),
970 DRM_MAP(NV12, 1, DRM_FORMAT_NV12),
971 #if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16)
972 DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
974 DRM_MAP(BGRA, 1, DRM_FORMAT_ARGB8888),
975 DRM_MAP(BGRX, 1, DRM_FORMAT_XRGB8888),
976 DRM_MAP(
RGBA, 1, DRM_FORMAT_ABGR8888),
977 DRM_MAP(RGBX, 1, DRM_FORMAT_XBGR8888),
978 #ifdef VA_FOURCC_ABGR
979 DRM_MAP(ABGR, 1, DRM_FORMAT_RGBA8888),
980 DRM_MAP(XBGR, 1, DRM_FORMAT_RGBX8888),
982 DRM_MAP(ARGB, 1, DRM_FORMAT_BGRA8888),
983 DRM_MAP(XRGB, 1, DRM_FORMAT_BGRX8888),
992 VASurfaceID surface_id = (VASurfaceID)(uintptr_t)hwmap->
priv;
996 vaDestroySurfaces(dst_dev->
display, &surface_id, 1);
1006 const VAAPIFormatDescriptor *format_desc;
1007 VASurfaceID surface_id;
1012 unsigned long buffer_handle;
1013 VASurfaceAttribExternalBuffers buffer_desc;
1014 VASurfaceAttrib attrs[2] = {
1016 .type = VASurfaceAttribMemoryType,
1017 .flags = VA_SURFACE_ATTRIB_SETTABLE,
1018 .value.type = VAGenericValueTypeInteger,
1019 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
1022 .type = VASurfaceAttribExternalBufferDescriptor,
1023 .flags = VA_SURFACE_ATTRIB_SETTABLE,
1024 .value.type = VAGenericValueTypePointer,
1025 .value.value.p = &buffer_desc,
1031 if (
desc->nb_objects != 1) {
1033 "made from a single DRM object.\n");
1039 if (
desc->nb_layers != vaapi_drm_format_map[
i].nb_layer_formats)
1041 for (j = 0; j <
desc->nb_layers; j++) {
1042 if (
desc->layers[j].format !=
1043 vaapi_drm_format_map[
i].layer_formats[j])
1046 if (j !=
desc->nb_layers)
1048 va_fourcc = vaapi_drm_format_map[
i].va_fourcc;
1058 "%08x.\n",
desc->objects[0].fd, va_fourcc);
1063 buffer_handle =
desc->objects[0].fd;
1064 buffer_desc.pixel_format = va_fourcc;
1065 buffer_desc.width = src_fc->width;
1066 buffer_desc.height = src_fc->height;
1067 buffer_desc.data_size =
desc->objects[0].size;
1068 buffer_desc.buffers = &buffer_handle;
1069 buffer_desc.num_buffers = 1;
1070 buffer_desc.flags = 0;
1073 for (
i = 0;
i <
desc->nb_layers;
i++) {
1074 for (j = 0; j <
desc->layers[
i].nb_planes; j++) {
1075 buffer_desc.pitches[k] =
desc->layers[
i].planes[j].pitch;
1076 buffer_desc.offsets[k] =
desc->layers[
i].planes[j].offset;
1080 buffer_desc.num_planes = k;
1082 if (format_desc->chroma_planes_swapped &&
1083 buffer_desc.num_planes == 3) {
1084 FFSWAP(uint32_t, buffer_desc.pitches[1], buffer_desc.pitches[2]);
1085 FFSWAP(uint32_t, buffer_desc.offsets[1], buffer_desc.offsets[2]);
1088 vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format,
1092 if (vas != VA_STATUS_SUCCESS) {
1094 "object: %d (%s).\n", vas, vaErrorStr(vas));
1100 &vaapi_unmap_from_drm,
1101 (
void*)(uintptr_t)surface_id);
1105 dst->width =
src->width;
1106 dst->height =
src->height;
1107 dst->data[3] = (
uint8_t*)(uintptr_t)surface_id;
1110 "surface %#x.\n",
desc->objects[0].fd, surface_id);
1115 #if VA_CHECK_VERSION(1, 1, 0)
1132 VASurfaceID surface_id;
1134 VADRMPRIMESurfaceDescriptor va_desc;
1136 uint32_t export_flags;
1139 surface_id = (VASurfaceID)(uintptr_t)
src->data[3];
1141 export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS;
1143 export_flags |= VA_EXPORT_SURFACE_READ_ONLY;
1145 export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY;
1147 vas = vaExportSurfaceHandle(hwctx->
display, surface_id,
1148 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
1149 export_flags, &va_desc);
1150 if (vas != VA_STATUS_SUCCESS) {
1151 if (vas == VA_STATUS_ERROR_UNIMPLEMENTED)
1154 "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
1166 for (
i = 0;
i < va_desc.num_objects;
i++) {
1170 va_desc.objects[
i].drm_format_modifier;
1172 drm_desc->
nb_layers = va_desc.num_layers;
1173 for (
i = 0;
i < va_desc.num_layers;
i++) {
1176 for (j = 0; j < va_desc.layers[
i].num_planes; j++) {
1178 va_desc.layers[
i].object_index[j];
1180 va_desc.layers[
i].offset[j];
1182 va_desc.layers[
i].pitch[j];
1187 &vaapi_unmap_to_drm_esh, drm_desc);
1198 for (
i = 0;
i < va_desc.num_objects;
i++)
1199 close(va_desc.objects[
i].fd);
1205 #if VA_CHECK_VERSION(0, 36, 0)
1206 typedef struct VAAPIDRMImageBufferMapping {
1208 VABufferInfo buffer_info;
1211 } VAAPIDRMImageBufferMapping;
1217 VAAPIDRMImageBufferMapping *mapping = hwmap->
priv;
1218 VASurfaceID surface_id;
1221 surface_id = (VASurfaceID)(uintptr_t)hwmap->
source->
data[3];
1228 vas = vaReleaseBufferHandle(hwctx->
display, mapping->image.buf);
1229 if (vas != VA_STATUS_SUCCESS) {
1231 "handle of image %#x (derived from surface %#x): "
1232 "%d (%s).\n", mapping->image.buf, surface_id,
1233 vas, vaErrorStr(vas));
1236 vas = vaDestroyImage(hwctx->
display, mapping->image.image_id);
1237 if (vas != VA_STATUS_SUCCESS) {
1239 "derived from surface %#x: %d (%s).\n",
1240 surface_id, vas, vaErrorStr(vas));
1250 VAAPIDRMImageBufferMapping *mapping =
NULL;
1251 VASurfaceID surface_id;
1255 surface_id = (VASurfaceID)(uintptr_t)
src->data[3];
1263 vas = vaDeriveImage(hwctx->
display, surface_id,
1265 if (vas != VA_STATUS_SUCCESS) {
1267 "surface %#x: %d (%s).\n",
1268 surface_id, vas, vaErrorStr(vas));
1274 if (vaapi_drm_format_map[
i].va_fourcc ==
1275 mapping->image.format.fourcc)
1280 "VAAPI format %#x.\n", mapping->image.format.fourcc);
1285 mapping->buffer_info.mem_type =
1286 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
1288 mapping->drm_desc.nb_layers =
1289 vaapi_drm_format_map[
i].nb_layer_formats;
1290 if (mapping->drm_desc.nb_layers > 1) {
1291 if (mapping->drm_desc.nb_layers != mapping->image.num_planes) {
1293 "expected format: got %d planes, but expected %d.\n",
1294 mapping->image.num_planes, mapping->drm_desc.nb_layers);
1299 for(p = 0; p < mapping->drm_desc.nb_layers; p++) {
1301 .format = vaapi_drm_format_map[
i].layer_formats[p],
1305 .offset = mapping->image.offsets[p],
1306 .pitch = mapping->image.pitches[p],
1311 mapping->drm_desc.layers[0].format =
1312 vaapi_drm_format_map[
i].layer_formats[0];
1313 mapping->drm_desc.layers[0].nb_planes = mapping->image.num_planes;
1314 for (p = 0; p < mapping->image.num_planes; p++) {
1317 .offset = mapping->image.offsets[p],
1318 .pitch = mapping->image.pitches[p],
1323 vas = vaAcquireBufferHandle(hwctx->
display, mapping->image.buf,
1324 &mapping->buffer_info);
1325 if (vas != VA_STATUS_SUCCESS) {
1327 "handle from image %#x (derived from surface %#x): "
1328 "%d (%s).\n", mapping->image.buf, surface_id,
1329 vas, vaErrorStr(vas));
1335 mapping->buffer_info.handle);
1337 mapping->drm_desc.nb_objects = 1;
1339 .fd = mapping->buffer_info.handle,
1340 .size = mapping->image.data_size,
1342 .format_modifier = DRM_FORMAT_MOD_INVALID,
1346 dst,
src, &vaapi_unmap_to_drm_abh,
1358 vaReleaseBufferHandle(hwctx->
display, mapping->image.buf);
1360 vaDestroyImage(hwctx->
display, mapping->image.image_id);
1370 #if VA_CHECK_VERSION(1, 1, 0)
1372 err = vaapi_map_to_drm_esh(hwfc, dst,
src,
flags);
1376 #if VA_CHECK_VERSION(0, 36, 0)
1377 return vaapi_map_to_drm_abh(hwfc, dst,
src,
flags);
1387 switch (
src->format) {
1390 return vaapi_map_from_drm(hwfc, dst,
src,
flags);
1403 return vaapi_map_to_drm(hwfc, dst,
src,
flags);
1419 if (priv->x11_display)
1420 XCloseDisplay(priv->x11_display);
1430 static void vaapi_device_log_error(
void *
context,
const char *
message)
1437 static void vaapi_device_log_info(
void *
context,
const char *
message)
1453 vaSetErrorCallback(display, &vaapi_device_log_error,
ctx);
1454 vaSetInfoCallback (display, &vaapi_device_log_info,
ctx);
1460 if (vas != VA_STATUS_SUCCESS) {
1462 "connection: %d (%s).\n", vas, vaErrorStr(vas));
1475 VADisplay display =
NULL;
1477 int try_drm, try_x11, try_all;
1485 ctx->user_opaque = priv;
1490 try_all = try_drm = try_x11 = 0;
1491 if (!strcmp(ent->
value,
"drm")) {
1493 }
else if (!strcmp(ent->
value,
"x11")) {
1502 try_drm = HAVE_VAAPI_DRM;
1503 try_x11 = HAVE_VAAPI_X11;
1507 while (!display && try_drm) {
1513 priv->
drm_fd = open(device, O_RDWR);
1515 av_log(
ctx, loglevel,
"Failed to open %s as "
1516 "DRM device node.\n", device);
1521 int n, max_devices = 8;
1526 for (n = 0; n < max_devices; n++) {
1528 "/dev/dri/renderD%d", 128 + n);
1529 priv->
drm_fd = open(path, O_RDWR);
1532 "DRM render node for device %d.\n", n);
1536 if (kernel_driver) {
1539 if (strcmp(kernel_driver->
value,
info->name)) {
1541 "with non-matching kernel driver (%s).\n",
1543 drmFreeVersion(
info);
1549 "DRM render node for device %d, "
1550 "with matching kernel driver (%s).\n",
1552 drmFreeVersion(
info);
1557 "DRM render node for device %d.\n", n);
1561 if (n >= max_devices)
1565 display = vaGetDisplayDRM(priv->
drm_fd);
1568 "from DRM device %s.\n", device);
1576 if (!display && try_x11) {
1578 priv->x11_display = XOpenDisplay(device);
1579 if (!priv->x11_display) {
1581 "%s.\n", XDisplayName(device));
1583 display = vaGetDisplay(priv->x11_display);
1586 "from X11 display %s.\n", XDisplayName(device));
1591 "X11 display %s.\n", XDisplayName(device));
1599 "device %s.\n", device);
1602 "any default device.\n");
1608 #if VA_CHECK_VERSION(0, 38, 0)
1610 vas = vaSetDriverName(display, ent->
value);
1611 if (vas != VA_STATUS_SUCCESS) {
1613 "%s: %d (%s).\n", ent->
value, vas, vaErrorStr(vas));
1614 vaTerminate(display);
1619 "supported with this VAAPI version.\n");
1637 if (src_hwctx->
fd < 0) {
1639 "device to derive a VA display from.\n");
1645 int node_type = drmGetNodeTypeFromFd(src_hwctx->
fd);
1647 if (node_type < 0) {
1649 "to refer to a DRM device.\n");
1652 if (node_type == DRM_NODE_RENDER) {
1655 render_node = drmGetRenderDeviceNameFromFd(src_hwctx->
fd);
1658 "matching the DRM device.\n");
1661 fd = open(render_node, O_RDWR);
1664 "matching the DRM device.\n", render_node);
1669 "of non-render DRM device.\n", render_node);
1681 if (fd == src_hwctx->
fd) {
1689 ctx->user_opaque = priv;
1692 display = vaGetDisplayDRM(fd);