diff mbox

[FFmpeg-devel] AMF: Vulkan initialization support for encoder.

Message ID 20190619150307.8712-1-ovchinnikov.dmitrii@gmail.com
State New
Headers show

Commit Message

Dmitrii Ovchinnikov June 19, 2019, 3:03 p.m. UTC
Added linux support for amf encoder through vulkan.

To use h.264(AMD VCE) encoder on linux amdgru-pro version 19.20+ and amf-amdgpu-pro package(amdgru-pro contains, but does not install automatically) are required.

Initialization of amf encoder occurs in this order:
1) trying to initialize through dx11
2) trying to initialize through dx9
3) trying to initialize through vulkan

Only Vulkan initialization available on linux.


---
 libavcodec/amfenc.c | 22 ++++++++++++++++++++--
 libavcodec/amfenc.h |  1 +
 2 files changed, 21 insertions(+), 2 deletions(-)

Comments

Mark Thompson July 7, 2019, 1:10 p.m. UTC | #1
On 19/06/2019 16:03, OvchinnikovDmitrii wrote:
> Added linux support for amf encoder through vulkan.
> 
> To use h.264(AMD VCE) encoder on linux amdgru-pro version 19.20+ and amf-amdgpu-pro package(amdgru-pro contains, but does not install automatically) are required.
> 
> Initialization of amf encoder occurs in this order:
> 1) trying to initialize through dx11
> 2) trying to initialize through dx9
> 3) trying to initialize through vulkan
> 
> Only Vulkan initialization available on linux.

Does Vulkan initialisation work on Windows?

Please add a note in the docs to make it clear that on Linux this only works on the weird proprietary graphics stack that is rarely used and won't be installed by default anywhere.  The regular Mesa driver supports encode through OpenMAX and VAAPI.

> ---
>  libavcodec/amfenc.c | 22 ++++++++++++++++++++--
>  libavcodec/amfenc.h |  1 +
>  2 files changed, 21 insertions(+), 2 deletions(-)
> 
> diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c
> index 384d8efc92..5f42c2328a 100644
> --- a/libavcodec/amfenc.c
> +++ b/libavcodec/amfenc.c
> @@ -234,6 +234,7 @@ static int amf_init_context(AVCodecContext *avctx)
>      ctx->trace->pVtbl->SetWriterLevel(ctx->trace, FFMPEG_AMF_WRITER_ID, AMF_TRACE_TRACE);
>  
>      res = ctx->factory->pVtbl->CreateContext(ctx->factory, &ctx->context);
> +    ctx->context1 = NULL;
>      AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext() failed with error %d\n", res);
>  
>      // If a device was passed to the encoder, try to initialise from that.
> @@ -311,8 +312,19 @@ static int amf_init_context(AVCodecContext *avctx)
>              if (res == AMF_OK) {
>                  av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D9.\n");
>              } else {
> -                av_log(avctx, AV_LOG_ERROR, "AMF initialisation failed via D3D9: error %d.\n", res);
> -                return AVERROR(ENOSYS);
> +                AMFGuid guid = IID_AMFContext1();
> +                res = ctx->context->pVtbl->QueryInterface(ctx->context, &guid, (void**)&ctx->context1);
> +                AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext1() failed with error %d\n", res);
> +
> +                res = ctx->context1->pVtbl->InitVulkan(ctx->context1, NULL);
> +                if (res != AMF_OK) {
> +                    if (res == AMF_NOT_SUPPORTED)
> +                        av_log(avctx, AV_LOG_ERROR, "AMF via Vulkan is not supported on the given device.\n");
> +                    else
> +                        av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on the given Vulkan device: %d.\n", res);
> +                    return AVERROR(ENOSYS);
> +                }
> +                av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via Vulkan.\n");
>              }
>          }
>      }
> @@ -373,6 +385,12 @@ int av_cold ff_amf_encode_close(AVCodecContext *avctx)
>          ctx->context->pVtbl->Release(ctx->context);
>          ctx->context = NULL;
>      }
> +
> +    if (ctx->context1) {
> +        ctx->context1->pVtbl->Terminate(ctx->context1);
> +        ctx->context1->pVtbl->Release(ctx->context1);
> +        ctx->context1 = NULL;
> +    }
>      av_buffer_unref(&ctx->hw_device_ctx);
>      av_buffer_unref(&ctx->hw_frames_ctx);
>  
> diff --git a/libavcodec/amfenc.h b/libavcodec/amfenc.h
> index b1361842bd..9c4ea7c071 100644
> --- a/libavcodec/amfenc.h
> +++ b/libavcodec/amfenc.h
> @@ -54,6 +54,7 @@ typedef struct AmfContext {
>      amf_uint64          version; ///< version of AMF runtime
>      AmfTraceWriter      tracer;  ///< AMF writer registered with AMF
>      AMFContext         *context; ///< AMF context
> +    AMFContext1        *context1;///< AMF context1 with vulkan support

AMFContext1 seems to be a superset of AMFContext - do you actually need both variables, or can you just have an AMFContext1?

Relatedly, is there any version requirement on this being present?  Currently the only check is for AMF version 1.4.4.1 or greater.

>      //encoder
>      AMFComponent       *encoder; ///< AMF encoder object
>      amf_bool            eof;     ///< flag indicating EOF happened
> 

- Mark
Dmitrii Ovchinnikov July 16, 2019, 5:11 p.m. UTC | #2
>Does Vulkan initialisation work on Windows?
Yes, but only if dx initialisation failed.

>Please add a note in the docs to make it clear that on Linux this only
works on the weird proprietary graphics stack that is rarely used and won't
be installed by default anywhere.  The regular Mesa driver supports encode
through OpenMAX and VAAPI.
>AMFContext1 seems to be a superset of AMFContext - do you actually need
both variables, or can you just have an AMFContext1?
DAMFContext1 inherits/extends AMFContext. In C++ terms pointer to
AMFContext1 could be passed as pointer to AMFContext.
in ā€˜Cā€™ it is enough to query AMFContext1 just for init Vulkan and release.
So we dont need to store pointer to AMFContext1. I updated the code and
notes in general.texi file and sent a new patch (
https://patchwork.ffmpeg.org/patch/13972/)

>Relatedly, is there any version requirement on this being present?
Currently the only check is for AMF version 1.4.4.1 or greater.
AMFContext1 was added at version 1.4.9.
diff mbox

Patch

diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c
index 384d8efc92..5f42c2328a 100644
--- a/libavcodec/amfenc.c
+++ b/libavcodec/amfenc.c
@@ -234,6 +234,7 @@  static int amf_init_context(AVCodecContext *avctx)
     ctx->trace->pVtbl->SetWriterLevel(ctx->trace, FFMPEG_AMF_WRITER_ID, AMF_TRACE_TRACE);
 
     res = ctx->factory->pVtbl->CreateContext(ctx->factory, &ctx->context);
+    ctx->context1 = NULL;
     AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext() failed with error %d\n", res);
 
     // If a device was passed to the encoder, try to initialise from that.
@@ -311,8 +312,19 @@  static int amf_init_context(AVCodecContext *avctx)
             if (res == AMF_OK) {
                 av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D9.\n");
             } else {
-                av_log(avctx, AV_LOG_ERROR, "AMF initialisation failed via D3D9: error %d.\n", res);
-                return AVERROR(ENOSYS);
+                AMFGuid guid = IID_AMFContext1();
+                res = ctx->context->pVtbl->QueryInterface(ctx->context, &guid, (void**)&ctx->context1);
+                AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext1() failed with error %d\n", res);
+
+                res = ctx->context1->pVtbl->InitVulkan(ctx->context1, NULL);
+                if (res != AMF_OK) {
+                    if (res == AMF_NOT_SUPPORTED)
+                        av_log(avctx, AV_LOG_ERROR, "AMF via Vulkan is not supported on the given device.\n");
+                    else
+                        av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on the given Vulkan device: %d.\n", res);
+                    return AVERROR(ENOSYS);
+                }
+                av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via Vulkan.\n");
             }
         }
     }
@@ -373,6 +385,12 @@  int av_cold ff_amf_encode_close(AVCodecContext *avctx)
         ctx->context->pVtbl->Release(ctx->context);
         ctx->context = NULL;
     }
+
+    if (ctx->context1) {
+        ctx->context1->pVtbl->Terminate(ctx->context1);
+        ctx->context1->pVtbl->Release(ctx->context1);
+        ctx->context1 = NULL;
+    }
     av_buffer_unref(&ctx->hw_device_ctx);
     av_buffer_unref(&ctx->hw_frames_ctx);
 
diff --git a/libavcodec/amfenc.h b/libavcodec/amfenc.h
index b1361842bd..9c4ea7c071 100644
--- a/libavcodec/amfenc.h
+++ b/libavcodec/amfenc.h
@@ -54,6 +54,7 @@  typedef struct AmfContext {
     amf_uint64          version; ///< version of AMF runtime
     AmfTraceWriter      tracer;  ///< AMF writer registered with AMF
     AMFContext         *context; ///< AMF context
+    AMFContext1        *context1;///< AMF context1 with vulkan support
     //encoder
     AMFComponent       *encoder; ///< AMF encoder object
     amf_bool            eof;     ///< flag indicating EOF happened