[FFmpeg-devel] [PATCH] lavu, lavc/amf: hwcontext_amf phase 1. move AMF library and AMF device management from amfenc to hwcontext_amf
Alexander Kravchenko
akravchenko188 at gmail.com
Thu Apr 26 22:01:10 EEST 2018
This patch moves AMF library and AMF device management from amfenc to hwcontext_amf.
Now av_hwdevice_ctx API is used for AMF library/context creation/destroying
Phase 2 probably will include frame interop/map functions using hwframe_ctx API
---
libavcodec/amfenc.c | 250 ++++---------------------------
libavcodec/amfenc.h | 27 +---
libavutil/Makefile | 2 +
libavutil/hwcontext.c | 4 +
libavutil/hwcontext.h | 1 +
libavutil/hwcontext_amf.c | 329 +++++++++++++++++++++++++++++++++++++++++
libavutil/hwcontext_amf.h | 43 ++++++
libavutil/hwcontext_internal.h | 1 +
8 files changed, 418 insertions(+), 239 deletions(-)
create mode 100644 libavutil/hwcontext_amf.c
create mode 100644 libavutil/hwcontext_amf.h
diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c
index 384d8efc92..a8186c7b86 100644
--- a/libavcodec/amfenc.c
+++ b/libavcodec/amfenc.c
@@ -21,13 +21,7 @@
#include "libavutil/avassert.h"
#include "libavutil/imgutils.h"
#include "libavutil/hwcontext.h"
-#if CONFIG_D3D11VA
-#include "libavutil/hwcontext_d3d11va.h"
-#endif
-#if CONFIG_DXVA2
-#define COBJMACROS
-#include "libavutil/hwcontext_dxva2.h"
-#endif
+
#include "libavutil/mem.h"
#include "libavutil/pixdesc.h"
#include "libavutil/time.h"
@@ -35,14 +29,12 @@
#include "amfenc.h"
#include "internal.h"
-#if CONFIG_D3D11VA
-#include <d3d11.h>
+#if CONFIG_DXVA2
+#include <d3d9.h>
#endif
-#ifdef _WIN32
-#include "compat/w32dlfcn.h"
-#else
-#include <dlfcn.h>
+#if CONFIG_D3D11VA
+#include <d3d11.h>
#endif
#define FFMPEG_AMF_WRITER_ID L"ffmpeg_amf"
@@ -88,34 +80,17 @@ static enum AMF_SURFACE_FORMAT amf_av_to_amf_format(enum AVPixelFormat fmt)
return AMF_SURFACE_UNKNOWN;
}
-static void AMF_CDECL_CALL AMFTraceWriter_Write(AMFTraceWriter *pThis,
- const wchar_t *scope, const wchar_t *message)
-{
- AmfTraceWriter *tracer = (AmfTraceWriter*)pThis;
- av_log(tracer->avctx, AV_LOG_DEBUG, "%ls: %ls", scope, message); // \n is provided from AMF
-}
-static void AMF_CDECL_CALL AMFTraceWriter_Flush(AMFTraceWriter *pThis)
-{
-}
-
-static AMFTraceWriterVtbl tracer_vtbl =
-{
- .Write = AMFTraceWriter_Write,
- .Flush = AMFTraceWriter_Flush,
-};
-
-static int amf_load_library(AVCodecContext *avctx)
+static int amf_init_context(AVCodecContext *avctx)
{
- AmfContext *ctx = avctx->priv_data;
- AMFInit_Fn init_fun;
- AMFQueryVersion_Fn version_fun;
- AMF_RESULT res;
+ AmfContext *ctx = avctx->priv_data;
+ av_unused int ret;
ctx->delayed_frame = av_frame_alloc();
if (!ctx->delayed_frame) {
return AVERROR(ENOMEM);
}
+
// hardcoded to current HW queue size - will realloc in timestamp_queue_enqueue() if too small
ctx->timestamp_list = av_fifo_alloc((avctx->max_b_frames + 16) * sizeof(int64_t));
if (!ctx->timestamp_list) {
@@ -123,119 +98,9 @@ static int amf_load_library(AVCodecContext *avctx)
}
ctx->dts_delay = 0;
-
- ctx->library = dlopen(AMF_DLL_NAMEA, RTLD_NOW | RTLD_LOCAL);
- AMF_RETURN_IF_FALSE(ctx, ctx->library != NULL,
- AVERROR_UNKNOWN, "DLL %s failed to open\n", AMF_DLL_NAMEA);
-
- init_fun = (AMFInit_Fn)dlsym(ctx->library, AMF_INIT_FUNCTION_NAME);
- AMF_RETURN_IF_FALSE(ctx, init_fun != NULL, AVERROR_UNKNOWN, "DLL %s failed to find function %s\n", AMF_DLL_NAMEA, AMF_INIT_FUNCTION_NAME);
-
- version_fun = (AMFQueryVersion_Fn)dlsym(ctx->library, AMF_QUERY_VERSION_FUNCTION_NAME);
- AMF_RETURN_IF_FALSE(ctx, version_fun != NULL, AVERROR_UNKNOWN, "DLL %s failed to find function %s\n", AMF_DLL_NAMEA, AMF_QUERY_VERSION_FUNCTION_NAME);
-
- res = version_fun(&ctx->version);
- AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_QUERY_VERSION_FUNCTION_NAME, res);
- res = init_fun(AMF_FULL_VERSION, &ctx->factory);
- AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_INIT_FUNCTION_NAME, res);
- res = ctx->factory->pVtbl->GetTrace(ctx->factory, &ctx->trace);
- AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetTrace() failed with error %d\n", res);
- res = ctx->factory->pVtbl->GetDebug(ctx->factory, &ctx->debug);
- AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetDebug() failed with error %d\n", res);
- return 0;
-}
-
-#if CONFIG_D3D11VA
-static int amf_init_from_d3d11_device(AVCodecContext *avctx, AVD3D11VADeviceContext *hwctx)
-{
- AmfContext *ctx = avctx->priv_data;
- AMF_RESULT res;
-
- res = ctx->context->pVtbl->InitDX11(ctx->context, hwctx->device, AMF_DX11_1);
- if (res != AMF_OK) {
- if (res == AMF_NOT_SUPPORTED)
- av_log(avctx, AV_LOG_ERROR, "AMF via D3D11 is not supported on the given device.\n");
- else
- av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on the given D3D11 device: %d.\n", res);
- return AVERROR(ENODEV);
- }
-
- return 0;
-}
-#endif
-
-#if CONFIG_DXVA2
-static int amf_init_from_dxva2_device(AVCodecContext *avctx, AVDXVA2DeviceContext *hwctx)
-{
- AmfContext *ctx = avctx->priv_data;
- HANDLE device_handle;
- IDirect3DDevice9 *device;
- HRESULT hr;
- AMF_RESULT res;
- int ret;
-
- hr = IDirect3DDeviceManager9_OpenDeviceHandle(hwctx->devmgr, &device_handle);
- if (FAILED(hr)) {
- av_log(avctx, AV_LOG_ERROR, "Failed to open device handle for Direct3D9 device: %lx.\n", (unsigned long)hr);
- return AVERROR_EXTERNAL;
- }
-
- hr = IDirect3DDeviceManager9_LockDevice(hwctx->devmgr, device_handle, &device, FALSE);
- if (SUCCEEDED(hr)) {
- IDirect3DDeviceManager9_UnlockDevice(hwctx->devmgr, device_handle, FALSE);
- ret = 0;
- } else {
- av_log(avctx, AV_LOG_ERROR, "Failed to lock device handle for Direct3D9 device: %lx.\n", (unsigned long)hr);
- ret = AVERROR_EXTERNAL;
- }
-
- IDirect3DDeviceManager9_CloseDeviceHandle(hwctx->devmgr, device_handle);
-
- if (ret < 0)
- return ret;
-
- res = ctx->context->pVtbl->InitDX9(ctx->context, device);
-
- IDirect3DDevice9_Release(device);
-
- if (res != AMF_OK) {
- if (res == AMF_NOT_SUPPORTED)
- av_log(avctx, AV_LOG_ERROR, "AMF via D3D9 is not supported on the given device.\n");
- else
- av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on given D3D9 device: %d.\n", res);
- return AVERROR(ENODEV);
- }
-
- return 0;
-}
-#endif
-
-static int amf_init_context(AVCodecContext *avctx)
-{
- AmfContext *ctx = avctx->priv_data;
- AMF_RESULT res;
- av_unused int ret;
-
ctx->hwsurfaces_in_queue = 0;
ctx->hwsurfaces_in_queue_max = 16;
- // configure AMF logger
- // the return of these functions indicates old state and do not affect behaviour
- ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, ctx->log_to_dbg != 0 );
- if (ctx->log_to_dbg)
- ctx->trace->pVtbl->SetWriterLevel(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, AMF_TRACE_TRACE);
- ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_CONSOLE, 0);
- ctx->trace->pVtbl->SetGlobalLevel(ctx->trace, AMF_TRACE_TRACE);
-
- // connect AMF logger to av_log
- ctx->tracer.vtbl = &tracer_vtbl;
- ctx->tracer.avctx = avctx;
- ctx->trace->pVtbl->RegisterWriter(ctx->trace, FFMPEG_AMF_WRITER_ID,(AMFTraceWriter*)&ctx->tracer, 1);
- ctx->trace->pVtbl->SetWriterLevel(ctx->trace, FFMPEG_AMF_WRITER_ID, AMF_TRACE_TRACE);
-
- res = ctx->factory->pVtbl->CreateContext(ctx->factory, &ctx->context);
- 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.
if (avctx->hw_frames_ctx) {
AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
@@ -246,26 +111,9 @@ static int amf_init_context(AVCodecContext *avctx)
return AVERROR(EINVAL);
}
- switch (frames_ctx->device_ctx->type) {
-#if CONFIG_D3D11VA
- case AV_HWDEVICE_TYPE_D3D11VA:
- ret = amf_init_from_d3d11_device(avctx, frames_ctx->device_ctx->hwctx);
- if (ret < 0)
- return ret;
- break;
-#endif
-#if CONFIG_DXVA2
- case AV_HWDEVICE_TYPE_DXVA2:
- ret = amf_init_from_dxva2_device(avctx, frames_ctx->device_ctx->hwctx);
- if (ret < 0)
- return ret;
- break;
-#endif
- default:
- av_log(avctx, AV_LOG_ERROR, "AMF initialisation from a %s frames context is not supported.\n",
- av_hwdevice_get_type_name(frames_ctx->device_ctx->type));
- return AVERROR(ENOSYS);
- }
+ ret = av_hwdevice_ctx_create_derived(&ctx->amf_device_ctx, AV_HWDEVICE_TYPE_AMF, frames_ctx->device_ref, 0);
+ if (ret < 0)
+ return ret;
ctx->hw_frames_ctx = av_buffer_ref(avctx->hw_frames_ctx);
if (!ctx->hw_frames_ctx)
@@ -275,46 +123,26 @@ static int amf_init_context(AVCodecContext *avctx)
ctx->hwsurfaces_in_queue_max = frames_ctx->initial_pool_size - 1;
} else if (avctx->hw_device_ctx) {
- AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)avctx->hw_device_ctx->data;
-
- switch (device_ctx->type) {
-#if CONFIG_D3D11VA
- case AV_HWDEVICE_TYPE_D3D11VA:
- ret = amf_init_from_d3d11_device(avctx, device_ctx->hwctx);
- if (ret < 0)
- return ret;
- break;
-#endif
-#if CONFIG_DXVA2
- case AV_HWDEVICE_TYPE_DXVA2:
- ret = amf_init_from_dxva2_device(avctx, device_ctx->hwctx);
- if (ret < 0)
- return ret;
- break;
-#endif
- default:
- av_log(avctx, AV_LOG_ERROR, "AMF initialisation from a %s device is not supported.\n",
- av_hwdevice_get_type_name(device_ctx->type));
- return AVERROR(ENOSYS);
- }
+ ret = av_hwdevice_ctx_create_derived(&ctx->amf_device_ctx, AV_HWDEVICE_TYPE_AMF, avctx->hw_device_ctx, 0);
+ if (ret < 0)
+ return ret;
ctx->hw_device_ctx = av_buffer_ref(avctx->hw_device_ctx);
if (!ctx->hw_device_ctx)
return AVERROR(ENOMEM);
} else {
- res = ctx->context->pVtbl->InitDX11(ctx->context, NULL, AMF_DX11_1);
- if (res == AMF_OK) {
- av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D11.\n");
- } else {
- res = ctx->context->pVtbl->InitDX9(ctx->context, NULL);
- 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);
- }
- }
+ ret = av_hwdevice_ctx_create(&ctx->amf_device_ctx, AV_HWDEVICE_TYPE_AMF, NULL, NULL, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ if(ctx->amf_device_ctx)
+ {
+ AVHWDeviceContext *avhwctx = (AVHWDeviceContext*)ctx->amf_device_ctx->data;
+ AVAMFDeviceContext *amf_ctx = avhwctx->hwctx;
+ ctx->context = amf_ctx->context;
+ ctx->factory = amf_ctx->factory;
}
return 0;
}
@@ -368,29 +196,17 @@ int av_cold ff_amf_encode_close(AVCodecContext *avctx)
ctx->encoder = NULL;
}
- if (ctx->context) {
- ctx->context->pVtbl->Terminate(ctx->context);
- ctx->context->pVtbl->Release(ctx->context);
- ctx->context = NULL;
- }
av_buffer_unref(&ctx->hw_device_ctx);
av_buffer_unref(&ctx->hw_frames_ctx);
- if (ctx->trace) {
- ctx->trace->pVtbl->UnregisterWriter(ctx->trace, FFMPEG_AMF_WRITER_ID);
- }
- if (ctx->library) {
- dlclose(ctx->library);
- ctx->library = NULL;
- }
- ctx->trace = NULL;
- ctx->debug = NULL;
ctx->factory = NULL;
- ctx->version = 0;
+ ctx->context = NULL;
ctx->delayed_drain = 0;
av_frame_free(&ctx->delayed_frame);
av_fifo_freep(&ctx->timestamp_list);
+ av_buffer_unref(&ctx->amf_device_ctx);
+
return 0;
}
@@ -494,11 +310,9 @@ int ff_amf_encode_init(AVCodecContext *avctx)
{
int ret;
- if ((ret = amf_load_library(avctx)) == 0) {
- if ((ret = amf_init_context(avctx)) == 0) {
- if ((ret = amf_init_encoder(avctx)) == 0) {
- return 0;
- }
+ if ((ret = amf_init_context(avctx)) == 0) {
+ if ((ret = amf_init_encoder(avctx)) == 0) {
+ return 0;
}
}
ff_amf_encode_close(avctx);
diff --git a/libavcodec/amfenc.h b/libavcodec/amfenc.h
index b1361842bd..9ce577fa8f 100644
--- a/libavcodec/amfenc.h
+++ b/libavcodec/amfenc.h
@@ -19,41 +19,26 @@
#ifndef AVCODEC_AMFENC_H
#define AVCODEC_AMFENC_H
-#include <AMF/core/Factory.h>
-
#include <AMF/components/VideoEncoderVCE.h>
#include <AMF/components/VideoEncoderHEVC.h>
#include "libavutil/fifo.h"
+#include "libavutil/hwcontext_amf.h"
#include "avcodec.h"
-/**
-* AMF trace writer callback class
-* Used to capture all AMF logging
-*/
-
-typedef struct AmfTraceWriter {
- AMFTraceWriterVtbl *vtbl;
- AVCodecContext *avctx;
-} AmfTraceWriter;
-
/**
* AMF encoder context
*/
typedef struct AmfContext {
AVClass *avclass;
- // access to AMF runtime
- amf_handle library; ///< handle to DLL library
- AMFFactory *factory; ///< pointer to AMF factory
- AMFDebug *debug; ///< pointer to AMF debug interface
- AMFTrace *trace; ///< pointer to AMF trace interface
-
- amf_uint64 version; ///< version of AMF runtime
- AmfTraceWriter tracer; ///< AMF writer registered with AMF
- AMFContext *context; ///< AMF context
+
+ AMFContext *context;
+ AMFFactory *factory;
+ AVBufferRef *amf_device_ctx;
+
//encoder
AMFComponent *encoder; ///< AMF encoder object
amf_bool eof; ///< flag indicating EOF happened
diff --git a/libavutil/Makefile b/libavutil/Makefile
index a63ba523c9..34b858c606 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -168,6 +168,7 @@ OBJS-$(CONFIG_VAAPI) += hwcontext_vaapi.o
OBJS-$(CONFIG_VIDEOTOOLBOX) += hwcontext_videotoolbox.o
OBJS-$(CONFIG_VDPAU) += hwcontext_vdpau.o
OBJS-$(CONFIG_MEDIACODEC) += hwcontext_mediacodec.o
+OBJS-$(CONFIG_AMF) += hwcontext_amf.o
OBJS += $(COMPAT_OBJS:%=../compat/%)
@@ -183,6 +184,7 @@ SKIPHEADERS-$(CONFIG_OPENCL) += hwcontext_opencl.h
SKIPHEADERS-$(CONFIG_VAAPI) += hwcontext_vaapi.h
SKIPHEADERS-$(CONFIG_VIDEOTOOLBOX) += hwcontext_videotoolbox.h
SKIPHEADERS-$(CONFIG_VDPAU) += hwcontext_vdpau.h
+SKIPHEADERS-$(CONFIG_AMF) += hwcontext_amf.h
TESTPROGS = adler32 \
aes \
diff --git a/libavutil/hwcontext.c b/libavutil/hwcontext.c
index 70c556ecac..decf2d3566 100644
--- a/libavutil/hwcontext.c
+++ b/libavutil/hwcontext.c
@@ -58,6 +58,9 @@ static const HWContextType * const hw_table[] = {
#endif
#if CONFIG_MEDIACODEC
&ff_hwcontext_type_mediacodec,
+#endif
+#if CONFIG_AMF
+ &ff_hwcontext_type_amf,
#endif
NULL,
};
@@ -73,6 +76,7 @@ static const char *const hw_type_names[] = {
[AV_HWDEVICE_TYPE_VDPAU] = "vdpau",
[AV_HWDEVICE_TYPE_VIDEOTOOLBOX] = "videotoolbox",
[AV_HWDEVICE_TYPE_MEDIACODEC] = "mediacodec",
+ [AV_HWDEVICE_TYPE_AMF] = "amf",
};
enum AVHWDeviceType av_hwdevice_find_type_by_name(const char *name)
diff --git a/libavutil/hwcontext.h b/libavutil/hwcontext.h
index f5a4b62387..b18591205a 100644
--- a/libavutil/hwcontext.h
+++ b/libavutil/hwcontext.h
@@ -36,6 +36,7 @@ enum AVHWDeviceType {
AV_HWDEVICE_TYPE_DRM,
AV_HWDEVICE_TYPE_OPENCL,
AV_HWDEVICE_TYPE_MEDIACODEC,
+ AV_HWDEVICE_TYPE_AMF,
};
typedef struct AVHWDeviceInternal AVHWDeviceInternal;
diff --git a/libavutil/hwcontext_amf.c b/libavutil/hwcontext_amf.c
new file mode 100644
index 0000000000..2c32f0e224
--- /dev/null
+++ b/libavutil/hwcontext_amf.c
@@ -0,0 +1,329 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string.h>
+
+#include "config.h"
+
+#include "avassert.h"
+#include "avstring.h"
+#include "common.h"
+#include "hwcontext.h"
+#include "hwcontext_internal.h"
+#include "hwcontext_amf.h"
+
+#if CONFIG_D3D11VA
+#include "libavutil/hwcontext_d3d11va.h"
+#endif
+
+#if CONFIG_DXVA2
+#define COBJMACROS
+#include "libavutil/hwcontext_dxva2.h"
+#endif
+
+#ifdef _WIN32
+#include "compat/w32dlfcn.h"
+#else
+#include <dlfcn.h>
+#endif
+
+/**
+* Error handling helper
+*/
+#define AMFAV_RETURN_IF_FALSE(avctx, exp, ret_value, /*message,*/ ...) \
+ if (!(exp)) { \
+ av_log(avctx, AV_LOG_ERROR, __VA_ARGS__); \
+ return ret_value; \
+ }
+
+typedef struct AmfTraceWriter {
+ AMFTraceWriterVtbl *vtbl;
+ void *avcl;
+} AmfTraceWriter;
+
+static void AMF_CDECL_CALL AMFTraceWriter_Write(AMFTraceWriter *pThis,
+ const wchar_t *scope, const wchar_t *message)
+{
+ AmfTraceWriter *tracer = (AmfTraceWriter*)pThis;
+ av_log(tracer->avcl, AV_LOG_DEBUG, "%ls: %ls", scope, message);
+}
+
+static void AMF_CDECL_CALL AMFTraceWriter_Flush(AMFTraceWriter *pThis)
+{
+}
+
+static AMFTraceWriterVtbl tracer_vtbl =
+{
+ .Write = AMFTraceWriter_Write,
+ .Flush = AMFTraceWriter_Flush,
+};
+
+#define AMFAV_WRITER_ID L"avlog"
+
+static const AVClass amflib_class = {
+ .class_name = "amf",
+ .item_name = av_default_item_name,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+typedef struct AMFLibrary {
+ const AVClass *avclass;
+ amf_handle library;
+ AMFFactory *factory;
+ AMFDebug *debug;
+ AMFTrace *trace;
+
+ amf_uint64 version;
+ AmfTraceWriter tracer;
+
+} AMFLibrary;
+
+static void amf_library_ctx_free(void *opaque, uint8_t *data)
+{
+ AMFLibrary *ctx = (AMFLibrary*)data;
+
+ if (ctx->trace) {
+ ctx->trace->pVtbl->UnregisterWriter(ctx->trace, AMFAV_WRITER_ID);
+ }
+ if (ctx->library) {
+ dlclose(ctx->library);
+ }
+
+ av_freep(&ctx);
+}
+
+static AVBufferRef *amf_library_ctx_alloc(void)
+{
+ AVBufferRef *buf;
+ AMFLibrary *ctx;
+
+ ctx = av_mallocz(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+
+ buf = av_buffer_create((uint8_t*)ctx, sizeof(*ctx), amf_library_ctx_free, NULL, AV_BUFFER_FLAG_READONLY);
+ return buf;
+}
+
+static int amf_init_library(AMFLibrary *ctx)
+{
+ AMFInit_Fn init_fun = NULL;
+ AMFQueryVersion_Fn version_fun = NULL;
+ AMF_RESULT res = AMF_OK;
+
+ ctx->avclass = &amflib_class;
+ ctx->library = dlopen(AMF_DLL_NAMEA, RTLD_NOW | RTLD_LOCAL);
+ AMFAV_RETURN_IF_FALSE(ctx, ctx->library != NULL, AVERROR_UNKNOWN, "DLL %s failed to open\n", AMF_DLL_NAMEA);
+
+ init_fun = (AMFInit_Fn)dlsym(ctx->library, AMF_INIT_FUNCTION_NAME);
+ AMFAV_RETURN_IF_FALSE(ctx, init_fun != NULL, AVERROR_UNKNOWN, "DLL %s failed to find function %s\n", AMF_DLL_NAMEA, AMF_INIT_FUNCTION_NAME);
+
+ version_fun = (AMFQueryVersion_Fn)dlsym(ctx->library, AMF_QUERY_VERSION_FUNCTION_NAME);
+ AMFAV_RETURN_IF_FALSE(ctx, version_fun != NULL, AVERROR_UNKNOWN, "DLL %s failed to find function %s\n", AMF_DLL_NAMEA, AMF_QUERY_VERSION_FUNCTION_NAME);
+
+ res = version_fun(&ctx->version);
+ AMFAV_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_QUERY_VERSION_FUNCTION_NAME, res);
+ res = init_fun(AMF_FULL_VERSION, &ctx->factory);
+ AMFAV_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_INIT_FUNCTION_NAME, res);
+ res = ctx->factory->pVtbl->GetTrace(ctx->factory, &ctx->trace);
+ AMFAV_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetTrace() failed with error %d\n", res);
+ res = ctx->factory->pVtbl->GetDebug(ctx->factory, &ctx->debug);
+ AMFAV_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetDebug() failed with error %d\n", res);
+
+ ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_CONSOLE, 0);
+ ctx->trace->pVtbl->SetGlobalLevel(ctx->trace, AMF_TRACE_TRACE);
+
+ // connect AMF logger to av_log
+ ctx->tracer.vtbl = &tracer_vtbl;
+ ctx->tracer.avcl = ctx;
+ ctx->trace->pVtbl->RegisterWriter(ctx->trace, AMFAV_WRITER_ID, (AMFTraceWriter*)&ctx->tracer, 1);
+ ctx->trace->pVtbl->SetWriterLevel(ctx->trace, AMFAV_WRITER_ID, AMF_TRACE_TRACE);
+ return 0;
+}
+
+static AVBufferRef *amf_library_ctx = NULL;
+static AVBufferRef *aquire_amf_library_ctx(void)
+{
+ AVBufferRef *ret = NULL;
+ if (amf_library_ctx == NULL)
+ {
+ ret = amf_library_ctx_alloc();
+ if(amf_init_library((AMFLibrary *)ret->data) < 0)
+ {
+ av_buffer_unref(&amf_library_ctx);
+ ret = NULL;
+ } else {
+ amf_library_ctx = ret;
+ }
+ } else {
+ ret = av_buffer_ref(amf_library_ctx);
+ }
+ return ret;
+}
+
+typedef struct AVAMFDeviceContextPrivate {
+ AMFLibrary *lib;
+ AVBufferRef *lib_ref;
+} AVAMFDeviceContextPrivate;
+
+static int amf_init_device_ctx_object(AVHWDeviceContext *ctx)
+{
+ AVAMFDeviceContext *hwctx = ctx->hwctx;
+ AVAMFDeviceContextPrivate *priv = ctx->internal->priv;
+ AMF_RESULT res;
+
+ priv->lib_ref = aquire_amf_library_ctx();
+ priv->lib = (AMFLibrary*)priv->lib_ref->data;
+
+ res = priv->lib->factory->pVtbl->CreateContext(priv->lib->factory, &hwctx->context);
+ hwctx->factory = priv->lib->factory;
+ AMFAV_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext() failed with error %d\n", res);
+ return 0;
+}
+
+static int amf_device_create(AVHWDeviceContext *ctx, const char *device,
+ AVDictionary *opts, int flags)
+{
+ AVAMFDeviceContext *amf_ctx = ctx->hwctx;
+ AMF_RESULT res;
+ int err;
+
+ err = amf_init_device_ctx_object(ctx);
+ if(err < 0)
+ return err;
+
+ res = amf_ctx->context->pVtbl->InitDX11(amf_ctx->context, NULL, AMF_DX11_1);
+ if (res == AMF_OK) {
+ av_log(ctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D11.\n");
+ } else {
+ res = amf_ctx->context->pVtbl->InitDX9(amf_ctx->context, NULL);
+ if (res == AMF_OK) {
+ av_log(ctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D9.\n");
+ } else {
+ av_log(ctx, AV_LOG_ERROR, "AMF initialisation failed via D3D9: error %d.\n", res);
+ return AVERROR(ENOSYS);
+ }
+ }
+ return 0;
+}
+
+static int amf_device_derive(AVHWDeviceContext *dst_ctx,
+ AVHWDeviceContext *src_ctx,
+ int flags)
+{
+ AVAMFDeviceContext *amf_ctx = dst_ctx->hwctx;
+ AMF_RESULT res;
+ int err;
+
+ err = amf_init_device_ctx_object(dst_ctx);
+ if(err < 0)
+ return err;
+
+ switch (src_ctx->type) {
+
+#if CONFIG_D3D11VA
+ case AV_HWDEVICE_TYPE_DXVA2:
+ {
+ AVDXVA2DeviceContext *dxva2_ctx = src_ctx->hwctx;
+ HANDLE device_handle;
+ IDirect3DDevice9 *device;
+ HRESULT hr;
+ AMF_RESULT res;
+ int ret;
+
+ hr = IDirect3DDeviceManager9_OpenDeviceHandle(dxva2_ctx->devmgr, &device_handle);
+ if (FAILED(hr)) {
+ av_log(dst_ctx, AV_LOG_ERROR, "Failed to open device handle for Direct3D9 device: %lx.\n", (unsigned long)hr);
+ return AVERROR_EXTERNAL;
+ }
+
+ hr = IDirect3DDeviceManager9_LockDevice(dxva2_ctx->devmgr, device_handle, &device, FALSE);
+ if (SUCCEEDED(hr)) {
+ IDirect3DDeviceManager9_UnlockDevice(dxva2_ctx->devmgr, device_handle, FALSE);
+ ret = 0;
+ } else {
+ av_log(dst_ctx, AV_LOG_ERROR, "Failed to lock device handle for Direct3D9 device: %lx.\n", (unsigned long)hr);
+ ret = AVERROR_EXTERNAL;
+ }
+
+ IDirect3DDeviceManager9_CloseDeviceHandle(dxva2_ctx->devmgr, device_handle);
+
+ if (ret < 0)
+ return ret;
+
+ res = amf_ctx->context->pVtbl->InitDX9(amf_ctx->context, device);
+
+ IDirect3DDevice9_Release(device);
+
+ if (res != AMF_OK) {
+ if (res == AMF_NOT_SUPPORTED)
+ av_log(dst_ctx, AV_LOG_ERROR, "AMF via D3D9 is not supported on the given device.\n");
+ else
+ av_log(dst_ctx, AV_LOG_ERROR, "AMF failed to initialise on given D3D9 device: %d.\n", res);
+ return AVERROR(ENODEV);
+ }
+ }
+ break;
+#endif
+
+#if CONFIG_D3D11VA
+ case AV_HWDEVICE_TYPE_D3D11VA:
+ {
+ AVD3D11VADeviceContext *d3d11_ctx = src_ctx->hwctx;
+ res = amf_ctx->context->pVtbl->InitDX11(amf_ctx->context, d3d11_ctx->device, AMF_DX11_1);
+ if (res != AMF_OK) {
+ if (res == AMF_NOT_SUPPORTED)
+ av_log(dst_ctx, AV_LOG_ERROR, "AMF via D3D11 is not supported on the given device.\n");
+ else
+ av_log(dst_ctx, AV_LOG_ERROR, "AMF failed to initialise on the given D3D11 device: %d.\n", res);
+ return AVERROR(ENODEV);
+ }
+ }
+ break;
+#endif
+ default:
+ av_log(dst_ctx, AV_LOG_ERROR, "AMF initialisation from a %s device is not supported.\n",
+ av_hwdevice_get_type_name(src_ctx->type));
+ return AVERROR(ENOSYS);
+ }
+ return 0;
+}
+
+static void amf_device_uninit(AVHWDeviceContext *ctx)
+{
+ AVAMFDeviceContext *amf_ctx = ctx->hwctx;
+ AVAMFDeviceContextPrivate *priv = ctx->internal->priv;
+ if (amf_ctx->context) {
+ amf_ctx->context->pVtbl->Terminate(amf_ctx->context);
+ amf_ctx->context->pVtbl->Release(amf_ctx->context);
+ amf_ctx->context = NULL;
+ }
+ av_buffer_unref(&priv->lib_ref);
+}
+
+const HWContextType ff_hwcontext_type_amf = {
+ .type = AV_HWDEVICE_TYPE_AMF,
+ .name = "AMF",
+
+ .device_hwctx_size = sizeof(AVAMFDeviceContext),
+ .device_priv_size = sizeof(AVAMFDeviceContextPrivate),
+
+ .device_create = &amf_device_create,
+ .device_derive = &amf_device_derive,
+ .device_uninit = &amf_device_uninit,
+};
diff --git a/libavutil/hwcontext_amf.h b/libavutil/hwcontext_amf.h
new file mode 100644
index 0000000000..1b19fd2ce8
--- /dev/null
+++ b/libavutil/hwcontext_amf.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#ifndef AVUTIL_HWCONTEXT_AMF_H
+#define AVUTIL_HWCONTEXT_AMF_H
+
+/**
+ * @file
+ * API-specific header for AV_HWDEVICE_TYPE_AMF.
+ *
+ */
+
+#include "frame.h"
+#include "AMF/core/Context.h"
+#include "AMF/core/Factory.h"
+
+
+/**
+ * This struct is allocated as AVHWDeviceContext.hwctx
+ */
+typedef struct AVAMFDeviceContext {
+ AMFContext *context;
+ AMFFactory *factory;
+} AVAMFDeviceContext;
+
+
+#endif /* AVUTIL_HWCONTEXT_AMF_H */
diff --git a/libavutil/hwcontext_internal.h b/libavutil/hwcontext_internal.h
index 332062ddaa..179797a936 100644
--- a/libavutil/hwcontext_internal.h
+++ b/libavutil/hwcontext_internal.h
@@ -167,5 +167,6 @@ extern const HWContextType ff_hwcontext_type_vaapi;
extern const HWContextType ff_hwcontext_type_vdpau;
extern const HWContextType ff_hwcontext_type_videotoolbox;
extern const HWContextType ff_hwcontext_type_mediacodec;
+extern const HWContextType ff_hwcontext_type_amf;
#endif /* AVUTIL_HWCONTEXT_INTERNAL_H */
--
2.16.2.windows.1
More information about the ffmpeg-devel
mailing list