From aa319aac75ed30441ed53fac56ddfc347d2d454c Mon Sep 17 00:00:00 2001
From: Ivan Uskov <ivan.uskov@nablet.com>
Date: Tue, 30 Jun 2015 16:59:26 +0300
Subject: [PATCH] Adding QSV/MFX session initialization for linux platform,
 where a display handle is required. Now ff_qsv_init_internal_session() is
 able to find appropriate display handle under linux using VAAPI.

---
 libavcodec/qsv.c          | 84 +++++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/qsv_internal.h | 17 +++++++++-
 2 files changed, 100 insertions(+), 1 deletion(-)
 mode change 100644 => 100755 libavcodec/qsv.c
 mode change 100644 => 100755 libavcodec/qsv_internal.h

diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
old mode 100644
new mode 100755
index 31be9d1..ba81815
--- a/libavcodec/qsv.c
+++ b/libavcodec/qsv.c
@@ -18,6 +18,11 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+/**
+ * @file
+ * Intel QSV H.264 codec general functions.
+ */
+
 #include <mfx/mfxvideo.h>
 
 #include "libavutil/error.h"
@@ -25,6 +30,9 @@
 #include "avcodec.h"
 #include "qsv_internal.h"
 
+/**
+ * @brief translate ffmpeg codec IDs to MSDK
+ */
 int ff_qsv_codec_id_to_mfx(enum AVCodecID codec_id)
 {
     switch (codec_id) {
@@ -42,6 +50,10 @@ int ff_qsv_codec_id_to_mfx(enum AVCodecID codec_id)
     return AVERROR(ENOSYS);
 }
 
+
+/**
+ * @brief translate MSDK error codes to ffmpeg error codes
+ */
 int ff_qsv_error(int mfx_err)
 {
     switch (mfx_err) {
@@ -77,6 +89,22 @@ int ff_qsv_error(int mfx_err)
     }
 }
 
+
+/**
+ * @brief Initialize a MSDK session
+ *
+ * Media SDK is based on sessions, so this is the prerequisite 
+ * initialization for HW acceleration.  For Windows the session is
+ * complete and ready to use, for Linux a display handle is
+ * required.  For releases of Media Server Studio >= 2015 R4 the 
+ * render nodes interface is preferred (/dev/dri/renderD). 
+ * Using Media Server Studio 2015 R4 or newer is recommended
+ * but the older /dev/dri/card interface is also searched
+ * for broader compatibility.
+ * 
+ * @param avctx    ffmpeg metadata for this codec context
+ * @param session  the MSDK session used
+ */
 int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session)
 {
     mfxIMPL impl   = MFX_IMPL_AUTO_ANY;
@@ -91,6 +119,62 @@ int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session)
         return ff_qsv_error(ret);
     }
 
+
+    // this code is only required for Linux.  It searches for a valid
+    // display handle.  First in /dev/dri/renderD then in /dev/dri/card
+#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
+    // VAAPI display handle
+    VADisplay va_dpy=NULL;
+    VAStatus va_res = VA_STATUS_SUCCESS;
+    int major_version = 0, minor_version = 0;
+    int fd=-1;
+      
+    //search for valid graphics device
+    char adapterpath[256];
+    for (int adapter_num=0;adapter_num<6;adapter_num++) {
+
+        if (adapter_num<3) {
+            snprintf(adapterpath,sizeof(adapterpath),
+                "/dev/dri/renderD%d", adapter_num+128);
+        } else {
+            snprintf(adapterpath,sizeof(adapterpath),
+                "/dev/dri/card%d", adapter_num-3);
+        }
+
+        fd = open(adapterpath, O_RDWR);
+        if (fd < 0) {
+            av_log(avctx, AV_LOG_ERROR, 
+                "mfx init: %s fd open failed\n", adapterpath);
+            continue;
+        }
+
+        va_dpy = vaGetDisplayDRM(fd);
+        if (!va_dpy) {
+            av_log(avctx, AV_LOG_ERROR, 
+                "mfx init: %s vaGetDisplayDRM failed\n", adapterpath);
+            close(fd);
+            continue;
+        }
+
+        va_res = vaInitialize(va_dpy, &major_version, &minor_version);
+        if (VA_STATUS_SUCCESS != va_res) {
+            av_log(avctx, AV_LOG_ERROR, 
+                "mfx init: %s vaInitialize failed\n", adapterpath);
+            close(fd);
+            fd = -1;
+            continue;
+        }
+        else
+        {
+            av_log(avctx, AV_LOG_VERBOSE, 
+            "mfx initialization: %s vaInitialize successful\n",adapterpath);
+            break;
+        }
+    }
+    MFXVideoCORE_SetHandle((*session), (mfxHandleType)MFX_HANDLE_VA_DISPLAY, (mfxHDL)va_dpy);
+
+#endif //AVCODEC_QSV_LINUX_SESSION_HANDLE
+
     MFXQueryIMPL(*session, &impl);
 
     switch (MFX_IMPL_BASETYPE(impl)) {
diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h
old mode 100644
new mode 100755
index 86fca5f..de8ee47
--- a/libavcodec/qsv_internal.h
+++ b/libavcodec/qsv_internal.h
@@ -21,12 +21,27 @@
 #ifndef AVCODEC_QSV_INTERNAL_H
 #define AVCODEC_QSV_INTERNAL_H
 
+#ifdef CONFIG_VAAPI
+#define AVCODEC_QSV_LINUX_SESSION_HANDLE
+#endif //CONFIG_VAAPI
+
+#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <va/va.h>
+#include <va/va_drm.h>
+#endif
+
 #include <mfx/mfxvideo.h>
 
 #include "libavutil/frame.h"
 
 #define QSV_VERSION_MAJOR 1
-#define QSV_VERSION_MINOR 1
+#define QSV_VERSION_MINOR 9 
 
 #define ASYNC_DEPTH_DEFAULT 4       // internal parallelism
 
-- 
1.8.3.1

