diff mbox

[FFmpeg-devel,1/2] libavcodec/qsvdec: Fix the QSV decoder can't work when using system memory

Message ID 0c89be32-7d85-2249-14e3-75024241e6dc@gmail.com
State Superseded
Headers show

Commit Message

Huang, Zhengxu Jan. 9, 2017, 2:05 a.m. UTC
From 37629f14294125c7396e5e12970d75e895b1caba Mon Sep 17 00:00:00 2001
From: Zhengxu <zhengxu.maxwell@gmail.com>
Date: Mon, 19 Dec 2016 01:27:06 -0500
Subject: [PATCH 1/2] libavcodec/qsvdec: Fix the QSV decoder can't work when
 using system memory

Description: ./ffmpeg -c:v h264_qsv -i in -c:v h264 output.h264 does not
work because the qsv decode will failed.

Root cuase: when using the system rather than the hwaccel,ff_qsv_init_internal_session
does not set the vaDisplay handle for the session. The qsv decode will failed.

Solution: when creating the internal session , call the HwContext API to get session and
release all resource when close the decoder.

Signed-off-by: ChaoX A Liu <chaox.a.liu@gmail.com>
Signed-off-by: Huang, Zhengxu <zhengxu.maxwell@gmail.com>
Signed-off-by: Andrew, Zhang <huazh407@gmail.com>
---
 libavcodec/qsv.c          |  6 ++---
 libavcodec/qsv_internal.h |  5 ++++
 libavcodec/qsvdec.c       | 59 ++++++++++++++++++++++++++++++++++++++++++++---
 libavcodec/qsvdec.h       |  1 +
 4 files changed, 65 insertions(+), 6 deletions(-)

Comments

Mark Thompson Jan. 11, 2017, 9 p.m. UTC | #1
On 09/01/17 02:05, Huang, Zhengxu wrote:
> From 37629f14294125c7396e5e12970d75e895b1caba Mon Sep 17 00:00:00 2001
> From: Zhengxu <zhengxu.maxwell@gmail.com>
> Date: Mon, 19 Dec 2016 01:27:06 -0500
> Subject: [PATCH 1/2] libavcodec/qsvdec: Fix the QSV decoder can't work when
>  using system memory
> 
> Description: ./ffmpeg -c:v h264_qsv -i in -c:v h264 output.h264 does not
> work because the qsv decode will failed.

Yes it does!  (Or at least, it works for me?)  In the absence of a provided device handle the dispatcher finds a device to use.

Now I can see that it is likely to run into exactly the same device-selection issues as were being fixed in other patch, but I don't see how this is fixing it.  You are not passing anything to av_hwdevice_ctx_create(), so it will be going through exactly the same set of possible device nodes as ffmpeg did and will therefore fail to find the device in exactly the same way.

So, to properly fix the problem I think you are having (but correct me if this is wrong), you really want the -qsv_device option added to ffmpeg to apply to this case in libavcodec as well?  That is, we get the qsv_device in ffmpeg into libavcodec somehow and then use it with the code below.  (Patch itself implementing that looks mostly fine, but I would prefer to get the methodology resolved first.  Similarly for the matching patch to the encoder.)

- Mark


> Root cuase: when using the system rather than the hwaccel,ff_qsv_init_internal_session
> does not set the vaDisplay handle for the session. The qsv decode will failed.
> 
> Solution: when creating the internal session , call the HwContext API to get session and
> release all resource when close the decoder.
> 
> Signed-off-by: ChaoX A Liu <chaox.a.liu@gmail.com>
> Signed-off-by: Huang, Zhengxu <zhengxu.maxwell@gmail.com>
> Signed-off-by: Andrew, Zhang <huazh407@gmail.com>
> ---
>  libavcodec/qsv.c          |  6 ++---
>  libavcodec/qsv_internal.h |  5 ++++
>  libavcodec/qsvdec.c       | 59 ++++++++++++++++++++++++++++++++++++++++++++---
>  libavcodec/qsvdec.h       |  1 +
>  4 files changed, 65 insertions(+), 6 deletions(-)
> 
> diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
> index aac6ce6..a932fc3 100644
> --- a/libavcodec/qsv.c
> +++ b/libavcodec/qsv.c
> @@ -120,7 +120,7 @@ int ff_qsv_map_pixfmt(enum AVPixelFormat format, uint32_t *fourcc)
>      }
>  }
>  
> -static int qsv_load_plugins(mfxSession session, const char *load_plugins,
> +int ff_qsv_load_plugins(mfxSession session, const char *load_plugins,
>                              void *logctx)
>  {
>      if (!load_plugins || !*load_plugins)
> @@ -185,7 +185,7 @@ int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session,
>          return ff_qsv_error(ret);
>      }
>  
> -    ret = qsv_load_plugins(*session, load_plugins, avctx);
> +    ret = ff_qsv_load_plugins(*session, load_plugins, avctx);
>      if (ret < 0) {
>          av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n");
>          return ret;
> @@ -329,7 +329,7 @@ int ff_qsv_init_session_hwcontext(AVCodecContext *avctx, mfxSession *psession,
>          }
>      }
>  
> -    ret = qsv_load_plugins(session, load_plugins, avctx);
> +    ret = ff_qsv_load_plugins(session, load_plugins, avctx);
>      if (ret < 0) {
>          av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n");
>          return ret;
> diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h
> index 5d2a216..13f23ef 100644
> --- a/libavcodec/qsv_internal.h
> +++ b/libavcodec/qsv_internal.h
> @@ -50,6 +50,10 @@ typedef struct QSVFrame {
>      struct QSVFrame *next;
>  } QSVFrame;
>  
> +typedef struct QSVDeviceContext {
> +    AVBufferRef *hw_device_ctx;
> +} QSVDeviceContext;
> +
>  typedef struct QSVFramesContext {
>      AVBufferRef *hw_frames_ctx;
>      mfxFrameInfo info;
> @@ -73,5 +77,6 @@ int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session,
>  int ff_qsv_init_session_hwcontext(AVCodecContext *avctx, mfxSession *session,
>                                    QSVFramesContext *qsv_frames_ctx,
>                                    const char *load_plugins, int opaque);
> +int ff_qsv_load_plugins(mfxSession session, const char *load_plugins, void *logctx);
>  
>  #endif /* AVCODEC_QSV_INTERNAL_H */
> diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
> index 258042d..ccd5e26 100644
> --- a/libavcodec/qsvdec.c
> +++ b/libavcodec/qsvdec.c
> @@ -41,6 +41,58 @@
>  #include "qsv_internal.h"
>  #include "qsvdec.h"
>  
> +static int qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session,
> +                                 QSVContext *q, const char *load_plugins)
> +{
> +    mfxIMPL impl   = MFX_IMPL_AUTO_ANY;
> +    mfxVersion ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR } };
> +
> +    const char *desc;
> +    int ret;
> +    AVHWDeviceContext *device_hw;
> +    AVQSVDeviceContext *hwctx;
> +    AVBufferRef *hw_device_ctx;
> +
> +    ret = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_QSV, NULL, NULL, 0);
> +    if (ret < 0) {
> +        av_log(NULL, AV_LOG_ERROR, "Failed to create a QSV device\n");
> +        return ret;
> +    }
> +    device_hw = (AVHWDeviceContext*)hw_device_ctx->data;
> +    hwctx = device_hw->hwctx;
> +
> +    *session = hwctx->session;
> +
> +    q->device_ctx.hw_device_ctx = hw_device_ctx;
> +
> +    ret = ff_qsv_load_plugins(*session, load_plugins, avctx);
> +    if (ret < 0) {
> +        av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n");
> +        return ret;
> +    }
> +    MFXQueryIMPL(*session, &impl);
> +
> +    switch (MFX_IMPL_BASETYPE(impl)) {
> +    case MFX_IMPL_SOFTWARE:
> +        desc = "software";
> +        break;
> +    case MFX_IMPL_HARDWARE:
> +    case MFX_IMPL_HARDWARE2:
> +    case MFX_IMPL_HARDWARE3:
> +    case MFX_IMPL_HARDWARE4:
> +        desc = "hardware accelerated";
> +        break;
> +    default:
> +        desc = "unknown";
> +    }
> +
> +    av_log(avctx, AV_LOG_VERBOSE,
> +           "Initialized an internal MFX session using %s implementation\n",
> +           desc);
> +
> +    return 0;
> +}
> +
>  static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession session,
>                              AVBufferRef *hw_frames_ref)
>  {
> @@ -70,13 +122,13 @@ static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession ses
>          q->session = q->internal_session;
>      } else {
>          if (!q->internal_session) {
> -            ret = ff_qsv_init_internal_session(avctx, &q->internal_session,
> +            ret = qsv_init_internal_session(avctx, &q->session, q,
>                                                 q->load_plugins);
>              if (ret < 0)
>                  return ret;
>          }
> -
> -        q->session = q->internal_session;
> +        /* the session will close when unref the hw_device_ctx */
> +       // q->session = q->internal_session;
>      }
>  
>      /* make sure the decoder is uninitialized */
> @@ -428,6 +480,7 @@ int ff_qsv_decode_close(QSVContext *q)
>          MFXClose(q->internal_session);
>  
>      av_buffer_unref(&q->frames_ctx.hw_frames_ctx);
> +    av_buffer_unref(&q->device_ctx.hw_device_ctx);
>      av_freep(&q->frames_ctx.mids);
>      q->frames_ctx.nb_mids = 0;
>  
> diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h
> index 41fb716..ae810bc 100644
> --- a/libavcodec/qsvdec.h
> +++ b/libavcodec/qsvdec.h
> @@ -44,6 +44,7 @@ typedef struct QSVContext {
>      mfxSession internal_session;
>  
>      QSVFramesContext frames_ctx;
> +    QSVDeviceContext device_ctx;
>  
>      /**
>       * a linked list of frames currently being used by QSV
> -- 
> 1.8.3.1
>
diff mbox

Patch

diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
index aac6ce6..a932fc3 100644
--- a/libavcodec/qsv.c
+++ b/libavcodec/qsv.c
@@ -120,7 +120,7 @@  int ff_qsv_map_pixfmt(enum AVPixelFormat format, uint32_t *fourcc)
     }
 }
 
-static int qsv_load_plugins(mfxSession session, const char *load_plugins,
+int ff_qsv_load_plugins(mfxSession session, const char *load_plugins,
                             void *logctx)
 {
     if (!load_plugins || !*load_plugins)
@@ -185,7 +185,7 @@  int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session,
         return ff_qsv_error(ret);
     }
 
-    ret = qsv_load_plugins(*session, load_plugins, avctx);
+    ret = ff_qsv_load_plugins(*session, load_plugins, avctx);
     if (ret < 0) {
         av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n");
         return ret;
@@ -329,7 +329,7 @@  int ff_qsv_init_session_hwcontext(AVCodecContext *avctx, mfxSession *psession,
         }
     }
 
-    ret = qsv_load_plugins(session, load_plugins, avctx);
+    ret = ff_qsv_load_plugins(session, load_plugins, avctx);
     if (ret < 0) {
         av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n");
         return ret;
diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h
index 5d2a216..13f23ef 100644
--- a/libavcodec/qsv_internal.h
+++ b/libavcodec/qsv_internal.h
@@ -50,6 +50,10 @@  typedef struct QSVFrame {
     struct QSVFrame *next;
 } QSVFrame;
 
+typedef struct QSVDeviceContext {
+    AVBufferRef *hw_device_ctx;
+} QSVDeviceContext;
+
 typedef struct QSVFramesContext {
     AVBufferRef *hw_frames_ctx;
     mfxFrameInfo info;
@@ -73,5 +77,6 @@  int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session,
 int ff_qsv_init_session_hwcontext(AVCodecContext *avctx, mfxSession *session,
                                   QSVFramesContext *qsv_frames_ctx,
                                   const char *load_plugins, int opaque);
+int ff_qsv_load_plugins(mfxSession session, const char *load_plugins, void *logctx);
 
 #endif /* AVCODEC_QSV_INTERNAL_H */
diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
index 258042d..ccd5e26 100644
--- a/libavcodec/qsvdec.c
+++ b/libavcodec/qsvdec.c
@@ -41,6 +41,58 @@ 
 #include "qsv_internal.h"
 #include "qsvdec.h"
 
+static int qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session,
+                                 QSVContext *q, const char *load_plugins)
+{
+    mfxIMPL impl   = MFX_IMPL_AUTO_ANY;
+    mfxVersion ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR } };
+
+    const char *desc;
+    int ret;
+    AVHWDeviceContext *device_hw;
+    AVQSVDeviceContext *hwctx;
+    AVBufferRef *hw_device_ctx;
+
+    ret = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_QSV, NULL, NULL, 0);
+    if (ret < 0) {
+        av_log(NULL, AV_LOG_ERROR, "Failed to create a QSV device\n");
+        return ret;
+    }
+    device_hw = (AVHWDeviceContext*)hw_device_ctx->data;
+    hwctx = device_hw->hwctx;
+
+    *session = hwctx->session;
+
+    q->device_ctx.hw_device_ctx = hw_device_ctx;
+
+    ret = ff_qsv_load_plugins(*session, load_plugins, avctx);
+    if (ret < 0) {
+        av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n");
+        return ret;
+    }
+    MFXQueryIMPL(*session, &impl);
+
+    switch (MFX_IMPL_BASETYPE(impl)) {
+    case MFX_IMPL_SOFTWARE:
+        desc = "software";
+        break;
+    case MFX_IMPL_HARDWARE:
+    case MFX_IMPL_HARDWARE2:
+    case MFX_IMPL_HARDWARE3:
+    case MFX_IMPL_HARDWARE4:
+        desc = "hardware accelerated";
+        break;
+    default:
+        desc = "unknown";
+    }
+
+    av_log(avctx, AV_LOG_VERBOSE,
+           "Initialized an internal MFX session using %s implementation\n",
+           desc);
+
+    return 0;
+}
+
 static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession session,
                             AVBufferRef *hw_frames_ref)
 {
@@ -70,13 +122,13 @@  static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession ses
         q->session = q->internal_session;
     } else {
         if (!q->internal_session) {
-            ret = ff_qsv_init_internal_session(avctx, &q->internal_session,
+            ret = qsv_init_internal_session(avctx, &q->session, q,
                                                q->load_plugins);
             if (ret < 0)
                 return ret;
         }
-
-        q->session = q->internal_session;
+        /* the session will close when unref the hw_device_ctx */
+       // q->session = q->internal_session;
     }
 
     /* make sure the decoder is uninitialized */
@@ -428,6 +480,7 @@  int ff_qsv_decode_close(QSVContext *q)
         MFXClose(q->internal_session);
 
     av_buffer_unref(&q->frames_ctx.hw_frames_ctx);
+    av_buffer_unref(&q->device_ctx.hw_device_ctx);
     av_freep(&q->frames_ctx.mids);
     q->frames_ctx.nb_mids = 0;
 
diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h
index 41fb716..ae810bc 100644
--- a/libavcodec/qsvdec.h
+++ b/libavcodec/qsvdec.h
@@ -44,6 +44,7 @@  typedef struct QSVContext {
     mfxSession internal_session;
 
     QSVFramesContext frames_ctx;
+    QSVDeviceContext device_ctx;
 
     /**
      * a linked list of frames currently being used by QSV