Message ID | 20190619150307.8712-1-ovchinnikov.dmitrii@gmail.com |
---|---|
State | New |
Headers | show |
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
>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 --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