]> git.sesse.net Git - ffmpeg/blobdiff - libavutil/hwcontext_vaapi.c
swscale: Fix AltiVec/VSX build with recent GCC
[ffmpeg] / libavutil / hwcontext_vaapi.c
index 8624369bb9f14b61fe49b1b9fd4ea5d2e3bbb053..cf117640f283d5c857672051327afb5e180304f8 100644 (file)
@@ -27,6 +27,7 @@
 
 #if CONFIG_LIBDRM
 #   include <va/va_drmcommon.h>
+#   include <xf86drm.h>
 #   include <drm_fourcc.h>
 #   ifndef DRM_FORMAT_MOD_INVALID
 #       define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
@@ -1469,6 +1470,8 @@ static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
 {
     VAAPIDevicePriv *priv;
     VADisplay display = NULL;
+    const AVDictionaryEntry *ent;
+    int try_drm, try_x11, try_all;
 
     priv = av_mallocz(sizeof(*priv));
     if (!priv)
@@ -1479,8 +1482,95 @@ static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
     ctx->user_opaque = priv;
     ctx->free        = vaapi_device_free;
 
+    ent = av_dict_get(opts, "connection_type", NULL, 0);
+    if (ent) {
+        try_all = try_drm = try_x11 = 0;
+        if (!strcmp(ent->value, "drm")) {
+            try_drm = 1;
+        } else if (!strcmp(ent->value, "x11")) {
+            try_x11 = 1;
+        } else {
+            av_log(ctx, AV_LOG_ERROR, "Invalid connection type %s.\n",
+                   ent->value);
+            return AVERROR(EINVAL);
+        }
+    } else {
+        try_all = 1;
+        try_drm = HAVE_VAAPI_DRM;
+        try_x11 = HAVE_VAAPI_X11;
+    }
+
+#if HAVE_VAAPI_DRM
+    while (!display && try_drm) {
+        // If the device is specified, try to open it as a DRM device node.
+        // If not, look for a usable render node, possibly restricted to those
+        // using a specified kernel driver.
+        int loglevel = try_all ? AV_LOG_VERBOSE : AV_LOG_ERROR;
+        if (device) {
+            priv->drm_fd = open(device, O_RDWR);
+            if (priv->drm_fd < 0) {
+                av_log(ctx, loglevel, "Failed to open %s as "
+                       "DRM device node.\n", device);
+                break;
+            }
+        } else {
+            char path[64];
+            int n, max_devices = 8;
+#if CONFIG_LIBDRM
+            const AVDictionaryEntry *kernel_driver;
+            kernel_driver = av_dict_get(opts, "kernel_driver", NULL, 0);
+#endif
+            for (n = 0; n < max_devices; n++) {
+                snprintf(path, sizeof(path),
+                         "/dev/dri/renderD%d", 128 + n);
+                priv->drm_fd = open(path, O_RDWR);
+                if (priv->drm_fd < 0) {
+                    av_log(ctx, AV_LOG_VERBOSE, "Cannot open "
+                           "DRM render node for device %d.\n", n);
+                    break;
+                }
+#if CONFIG_LIBDRM
+                if (kernel_driver) {
+                    drmVersion *info;
+                    info = drmGetVersion(priv->drm_fd);
+                    if (strcmp(kernel_driver->value, info->name)) {
+                        av_log(ctx, AV_LOG_VERBOSE, "Ignoring device %d "
+                               "with non-matching kernel driver (%s).\n",
+                               n, info->name);
+                        drmFreeVersion(info);
+                        close(priv->drm_fd);
+                        priv->drm_fd = -1;
+                        continue;
+                    }
+                    av_log(ctx, AV_LOG_VERBOSE, "Trying to use "
+                           "DRM render node for device %d, "
+                           "with matching kernel driver (%s).\n",
+                           n, info->name);
+                    drmFreeVersion(info);
+                } else
+#endif
+                {
+                    av_log(ctx, AV_LOG_VERBOSE, "Trying to use "
+                           "DRM render node for device %d.\n", n);
+                }
+                break;
+            }
+            if (n >= max_devices)
+                break;
+        }
+
+        display = vaGetDisplayDRM(priv->drm_fd);
+        if (!display) {
+            av_log(ctx, AV_LOG_VERBOSE, "Cannot open a VA display "
+                   "from DRM device %s.\n", device);
+            return AVERROR_EXTERNAL;
+        }
+        break;
+    }
+#endif
+
 #if HAVE_VAAPI_X11
-    if (!display && !(device && device[0] == '/')) {
+    if (!display && try_x11) {
         // Try to open the device as an X11 display.
         priv->x11_display = XOpenDisplay(device);
         if (!priv->x11_display) {
@@ -1500,34 +1590,31 @@ static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
     }
 #endif
 
-#if HAVE_VAAPI_DRM
     if (!display) {
-        // Try to open the device as a DRM path.
-        // Default to using the first render node if the user did not
-        // supply a path.
-        const char *path = device ? device : "/dev/dri/renderD128";
-        priv->drm_fd = open(path, O_RDWR);
-        if (priv->drm_fd < 0) {
-            av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n",
-                   path);
-        } else {
-            display = vaGetDisplayDRM(priv->drm_fd);
-            if (!display) {
-                av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
-                       "from DRM device %s.\n", path);
-                return AVERROR_UNKNOWN;
-            }
+        if (device)
+            av_log(ctx, AV_LOG_ERROR, "No VA display found for "
+                   "device %s.\n", device);
+        else
+            av_log(ctx, AV_LOG_ERROR, "No VA display found for "
+                   "any default device.\n");
+        return AVERROR(EINVAL);
+    }
 
-            av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
-                   "DRM device %s.\n", path);
+    ent = av_dict_get(opts, "driver", NULL, 0);
+    if (ent) {
+#if VA_CHECK_VERSION(0, 38, 0)
+        VAStatus vas;
+        vas = vaSetDriverName(display, ent->value);
+        if (vas != VA_STATUS_SUCCESS) {
+            av_log(ctx, AV_LOG_ERROR, "Failed to set driver name to "
+                   "%s: %d (%s).\n", ent->value, vas, vaErrorStr(vas));
+            vaTerminate(display);
+            return AVERROR_EXTERNAL;
         }
-    }
+#else
+        av_log(ctx, AV_LOG_WARNING, "Driver name setting is not "
+               "supported with this VAAPI version.\n");
 #endif
-
-    if (!display) {
-        av_log(ctx, AV_LOG_ERROR, "No VA display found for "
-               "device: %s.\n", device ? device : "");
-        return AVERROR(EINVAL);
     }
 
     return vaapi_device_connect(ctx, display);