[FFmpeg-devel,3/6] qsvdec: Allow creation of the internal session from a device context

Submitted by Mark Thompson on Jan. 17, 2017, 10:30 p.m.

Details

Message ID 81c67c62-d7e7-badd-1c52-02317b858ad7@jkqxz.net
State New
Headers show

Commit Message

Mark Thompson Jan. 17, 2017, 10:30 p.m.
---
 libavcodec/qsvdec.c | 25 +++++++++++++++++++++++--
 libavcodec/qsvdec.h |  2 ++
 2 files changed, 25 insertions(+), 2 deletions(-)

Comments

wm4 Jan. 18, 2017, 7:57 a.m.
On Tue, 17 Jan 2017 22:30:44 +0000
Mark Thompson <sw@jkqxz.net> wrote:

> ---
>  libavcodec/qsvdec.c | 25 +++++++++++++++++++++++--
>  libavcodec/qsvdec.h |  2 ++
>  2 files changed, 25 insertions(+), 2 deletions(-)
> 
> diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
> index 258042d..5a42fd7 100644
> --- a/libavcodec/qsvdec.c
> +++ b/libavcodec/qsvdec.c
> @@ -42,7 +42,7 @@
>  #include "qsvdec.h"
>  
>  static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession session,
> -                            AVBufferRef *hw_frames_ref)
> +                            AVBufferRef *hw_frames_ref, AVBufferRef *hw_device_ref)
>  {
>      int ret;
>  
> @@ -68,6 +68,25 @@ static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession ses
>          }
>  
>          q->session = q->internal_session;
> +    } else if (hw_device_ref) {
> +        if (q->internal_session) {
> +            MFXClose(q->internal_session);
> +            q->internal_session = NULL;
> +        }
> +        av_buffer_unref(&q->hw_device_ctx);
> +
> +        q->hw_device_ctx = av_buffer_ref(hw_device_ref);
> +        if (!q->hw_device_ctx)
> +            return AVERROR(ENOMEM);
> +
> +        ret = ff_qsv_init_session_device(avctx, &q->internal_session,
> +                                         q->hw_device_ctx, q->load_plugins);
> +        if (ret < 0) {
> +            av_buffer_unref(&q->hw_device_ctx);
> +            return ret;
> +        }
> +
> +        q->session = q->internal_session;
>      } else {
>          if (!q->internal_session) {
>              ret = ff_qsv_init_internal_session(avctx, &q->internal_session,
> @@ -133,7 +152,7 @@ static int qsv_decode_init(AVCodecContext *avctx, QSVContext *q)
>          iopattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
>      q->iopattern = iopattern;
>  
> -    ret = qsv_init_session(avctx, q, session, avctx->hw_frames_ctx);
> +    ret = qsv_init_session(avctx, q, session, avctx->hw_frames_ctx, avctx->hw_device_ctx);
>      if (ret < 0) {
>          av_log(avctx, AV_LOG_ERROR, "Error initializing an MFX session\n");
>          return ret;
> @@ -431,6 +450,8 @@ int ff_qsv_decode_close(QSVContext *q)
>      av_freep(&q->frames_ctx.mids);
>      q->frames_ctx.nb_mids = 0;
>  
> +    av_buffer_unref(&q->hw_device_ctx);
> +
>      return 0;
>  }
>  
> diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h
> index 41fb716..5fb02aa 100644
> --- a/libavcodec/qsvdec.h
> +++ b/libavcodec/qsvdec.h
> @@ -43,6 +43,8 @@ typedef struct QSVContext {
>      // one
>      mfxSession internal_session;
>  
> +    AVBufferRef *hw_device_ctx;
> +
>      QSVFramesContext frames_ctx;
>  
>      /**

Seems fine.

Looks like with this decoder, attempting to change the device in
get_format (by using a frames context with another device) is undefined
behavior.
Mark Thompson Jan. 21, 2017, 10:20 p.m.
On 18/01/17 07:57, wm4 wrote:
> On Tue, 17 Jan 2017 22:30:44 +0000
> Mark Thompson <sw@jkqxz.net> wrote:
> 
>> ---
>>  libavcodec/qsvdec.c | 25 +++++++++++++++++++++++--
>>  libavcodec/qsvdec.h |  2 ++
>>  2 files changed, 25 insertions(+), 2 deletions(-)
>>
>> diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
>> index 258042d..5a42fd7 100644
>> --- a/libavcodec/qsvdec.c
>> +++ b/libavcodec/qsvdec.c
>> @@ -42,7 +42,7 @@
>>  #include "qsvdec.h"
>>  
>>  static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession session,
>> -                            AVBufferRef *hw_frames_ref)
>> +                            AVBufferRef *hw_frames_ref, AVBufferRef *hw_device_ref)
>>  {
>>      int ret;
>>  
>> @@ -68,6 +68,25 @@ static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession ses
>>          }
>>  
>>          q->session = q->internal_session;
>> +    } else if (hw_device_ref) {
>> +        if (q->internal_session) {
>> +            MFXClose(q->internal_session);
>> +            q->internal_session = NULL;
>> +        }
>> +        av_buffer_unref(&q->hw_device_ctx);
>> +
>> +        q->hw_device_ctx = av_buffer_ref(hw_device_ref);
>> +        if (!q->hw_device_ctx)
>> +            return AVERROR(ENOMEM);
>> +
>> +        ret = ff_qsv_init_session_device(avctx, &q->internal_session,
>> +                                         q->hw_device_ctx, q->load_plugins);
>> +        if (ret < 0) {
>> +            av_buffer_unref(&q->hw_device_ctx);
>> +            return ret;
>> +        }
>> +
>> +        q->session = q->internal_session;
>>      } else {
>>          if (!q->internal_session) {
>>              ret = ff_qsv_init_internal_session(avctx, &q->internal_session,
>> @@ -133,7 +152,7 @@ static int qsv_decode_init(AVCodecContext *avctx, QSVContext *q)
>>          iopattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
>>      q->iopattern = iopattern;
>>  
>> -    ret = qsv_init_session(avctx, q, session, avctx->hw_frames_ctx);
>> +    ret = qsv_init_session(avctx, q, session, avctx->hw_frames_ctx, avctx->hw_device_ctx);
>>      if (ret < 0) {
>>          av_log(avctx, AV_LOG_ERROR, "Error initializing an MFX session\n");
>>          return ret;
>> @@ -431,6 +450,8 @@ int ff_qsv_decode_close(QSVContext *q)
>>      av_freep(&q->frames_ctx.mids);
>>      q->frames_ctx.nb_mids = 0;
>>  
>> +    av_buffer_unref(&q->hw_device_ctx);
>> +
>>      return 0;
>>  }
>>  
>> diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h
>> index 41fb716..5fb02aa 100644
>> --- a/libavcodec/qsvdec.h
>> +++ b/libavcodec/qsvdec.h
>> @@ -43,6 +43,8 @@ typedef struct QSVContext {
>>      // one
>>      mfxSession internal_session;
>>  
>> +    AVBufferRef *hw_device_ctx;
>> +
>>      QSVFramesContext frames_ctx;
>>  
>>      /**
> 
> Seems fine.
> 
> Looks like with this decoder, attempting to change the device in
> get_format (by using a frames context with another device) is undefined
> behavior.

Yes.  I'm deliberately supporting only the first operation mode of AVCodecContext.hw_device_ctx (see the device thread) because it's simpler and there can only be one device with Intel.

Patch hide | download patch | download mbox

diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
index 258042d..5a42fd7 100644
--- a/libavcodec/qsvdec.c
+++ b/libavcodec/qsvdec.c
@@ -42,7 +42,7 @@ 
 #include "qsvdec.h"
 
 static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession session,
-                            AVBufferRef *hw_frames_ref)
+                            AVBufferRef *hw_frames_ref, AVBufferRef *hw_device_ref)
 {
     int ret;
 
@@ -68,6 +68,25 @@  static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession ses
         }
 
         q->session = q->internal_session;
+    } else if (hw_device_ref) {
+        if (q->internal_session) {
+            MFXClose(q->internal_session);
+            q->internal_session = NULL;
+        }
+        av_buffer_unref(&q->hw_device_ctx);
+
+        q->hw_device_ctx = av_buffer_ref(hw_device_ref);
+        if (!q->hw_device_ctx)
+            return AVERROR(ENOMEM);
+
+        ret = ff_qsv_init_session_device(avctx, &q->internal_session,
+                                         q->hw_device_ctx, q->load_plugins);
+        if (ret < 0) {
+            av_buffer_unref(&q->hw_device_ctx);
+            return ret;
+        }
+
+        q->session = q->internal_session;
     } else {
         if (!q->internal_session) {
             ret = ff_qsv_init_internal_session(avctx, &q->internal_session,
@@ -133,7 +152,7 @@  static int qsv_decode_init(AVCodecContext *avctx, QSVContext *q)
         iopattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
     q->iopattern = iopattern;
 
-    ret = qsv_init_session(avctx, q, session, avctx->hw_frames_ctx);
+    ret = qsv_init_session(avctx, q, session, avctx->hw_frames_ctx, avctx->hw_device_ctx);
     if (ret < 0) {
         av_log(avctx, AV_LOG_ERROR, "Error initializing an MFX session\n");
         return ret;
@@ -431,6 +450,8 @@  int ff_qsv_decode_close(QSVContext *q)
     av_freep(&q->frames_ctx.mids);
     q->frames_ctx.nb_mids = 0;
 
+    av_buffer_unref(&q->hw_device_ctx);
+
     return 0;
 }
 
diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h
index 41fb716..5fb02aa 100644
--- a/libavcodec/qsvdec.h
+++ b/libavcodec/qsvdec.h
@@ -43,6 +43,8 @@  typedef struct QSVContext {
     // one
     mfxSession internal_session;
 
+    AVBufferRef *hw_device_ctx;
+
     QSVFramesContext frames_ctx;
 
     /**