[FFmpeg-devel] [PATCH 1/2] lavu/hwcontext_amf: HWContext for AMF based components
akravchenko188 at gmail.com
akravchenko188 at gmail.com
Fri Nov 2 00:03:41 EET 2018
From: Alexander Kravchenko <akravchenko188 at gmail.com>
---
libavutil/Makefile | 2 +
libavutil/hwcontext.c | 4 +
libavutil/hwcontext.h | 1 +
libavutil/hwcontext_amf.c | 290 +++++++++++++++++++++++++++++++++
libavutil/hwcontext_amf.h | 53 ++++++
libavutil/hwcontext_internal.h | 1 +
6 files changed, 351 insertions(+)
create mode 100644 libavutil/hwcontext_amf.c
create mode 100644 libavutil/hwcontext_amf.h
diff --git a/libavutil/Makefile b/libavutil/Makefile
index 9ed24cfc82..d8b9f03d43 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -157,6 +157,7 @@ OBJS = adler32.o \
xtea.o \
tea.o \
+OBJS-$(CONFIG_AMF) += hwcontext_amf.o
OBJS-$(CONFIG_CUDA) += hwcontext_cuda.o
OBJS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.o
OBJS-$(CONFIG_DXVA2) += hwcontext_dxva2.o
@@ -174,6 +175,7 @@ OBJS += $(COMPAT_OBJS:%=../compat/%)
# Windows resource file
SLIBOBJS-$(HAVE_GNU_WINDRES) += avutilres.o
+SKIPHEADERS-$(CONFIG_AMF) += hwcontext_amf.h
SKIPHEADERS-$(HAVE_CUDA_H) += hwcontext_cuda.h
SKIPHEADERS-$(CONFIG_CUDA) += hwcontext_cuda_internal.h
SKIPHEADERS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.h
diff --git a/libavutil/hwcontext.c b/libavutil/hwcontext.c
index f1e404ab20..642f3ca5d0 100644
--- a/libavutil/hwcontext.c
+++ b/libavutil/hwcontext.c
@@ -29,6 +29,9 @@
#include "pixfmt.h"
static const HWContextType * const hw_table[] = {
+#if CONFIG_AMF
+ &ff_hwcontext_type_amf,
+#endif
#if CONFIG_CUDA
&ff_hwcontext_type_cuda,
#endif
@@ -63,6 +66,7 @@ static const HWContextType * const hw_table[] = {
};
static const char *const hw_type_names[] = {
+ [AV_HWDEVICE_TYPE_AMF] = "amf",
[AV_HWDEVICE_TYPE_CUDA] = "cuda",
[AV_HWDEVICE_TYPE_DRM] = "drm",
[AV_HWDEVICE_TYPE_DXVA2] = "dxva2",
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..b993c76a7e
--- /dev/null
+++ b/libavutil/hwcontext_amf.c
@@ -0,0 +1,290 @@
+/*
+ * 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 "hwcontext_d3d11va.h"
+#endif
+
+#if CONFIG_DXVA2
+#define COBJMACROS
+#include "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; \
+ }
+
+/**
+* AMF library context: amflib_class, amflib_context, amf_trace_writer
+* AMF library has global tracer settings. It is set global library context
+* to path AMF logs to av_log with library class
+*
+*/
+static const AVClass amflib_class = {
+ .class_name = "amf",
+ .item_name = av_default_item_name,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+typedef struct AMFLibraryContext {
+ const AVClass *avclass;
+} AMFLibraryContext;
+
+static AMFLibraryContext amflib_context =
+{
+ .avclass = &amflib_class,
+};
+
+typedef struct AmfTraceWriter {
+ const 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 const AMFTraceWriterVtbl tracer_vtbl =
+{
+ .Write = AMFTraceWriter_Write,
+ .Flush = AMFTraceWriter_Flush,
+};
+
+static const AmfTraceWriter amf_trace_writer =
+{
+ .vtbl = &tracer_vtbl,
+ .avcl = &amflib_context,
+};
+#define AMFAV_WRITER_ID L"avlog"
+
+typedef struct AMFDeviceContextPrivate {
+ amf_handle library;
+ AMFDebug *debug;
+ AMFTrace *trace;
+} AMFDeviceContextPrivate;
+
+static void amf_device_free(AVHWDeviceContext *ctx)
+{
+ AVAMFDeviceContext *amf_ctx = ctx->hwctx;
+ AMFDeviceContextPrivate *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;
+ }
+ if (priv->library) {
+ dlclose(priv->library);
+ }
+}
+
+static int amf_init_device_ctx_object(AVHWDeviceContext *ctx)
+{
+ AVAMFDeviceContext *hwctx = ctx->hwctx;
+ AMFDeviceContextPrivate *priv = ctx->internal->priv;
+ AMF_RESULT res;
+ AMFInit_Fn init_fun;
+
+ ctx->free = amf_device_free;
+
+ priv->library = dlopen(AMF_DLL_NAMEA, RTLD_NOW | RTLD_LOCAL);
+ AMFAV_RETURN_IF_FALSE(ctx, priv->library != NULL, AVERROR_UNKNOWN, "DLL %s failed to open\n", AMF_DLL_NAMEA);
+
+ init_fun = (AMFInit_Fn)dlsym(priv->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);
+
+ res = init_fun(AMF_FULL_VERSION, &hwctx->factory);
+ AMFAV_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_INIT_FUNCTION_NAME, res);
+
+ res = hwctx->factory->pVtbl->GetTrace(hwctx->factory, &priv->trace);
+ AMFAV_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetTrace() failed with error %d\n", res);
+ res = hwctx->factory->pVtbl->GetDebug(hwctx->factory, &priv->debug);
+ AMFAV_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetDebug() failed with error %d\n", res);
+
+ priv->trace->pVtbl->EnableWriter(priv->trace, AMF_TRACE_WRITER_CONSOLE, 0);
+ priv->trace->pVtbl->SetGlobalLevel(priv->trace, AMF_TRACE_TRACE);
+
+ // connect AMF logger to av_log
+ priv->trace->pVtbl->RegisterWriter(priv->trace, AMFAV_WRITER_ID, (AMFTraceWriter*)&amf_trace_writer, 1);
+ priv->trace->pVtbl->SetWriterLevel(priv->trace, AMFAV_WRITER_ID, AMF_TRACE_TRACE);
+
+ res = hwctx->factory->pVtbl->CreateContext(hwctx->factory, &hwctx->context);
+ 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;
+}
+
+#if CONFIG_DXVA2
+static int amf_device_derive_dxva2(AVHWDeviceContext *dst_ctx, AVHWDeviceContext *src_ctx)
+{
+ AVAMFDeviceContext *amf_ctx = dst_ctx->hwctx;
+ 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);
+ }
+ return 0;
+}
+#endif
+
+#if CONFIG_D3D11VA
+static int amf_device_derive_d3d11(AVHWDeviceContext *dst_ctx, AVHWDeviceContext *src_ctx)
+{
+ AVAMFDeviceContext *amf_ctx = dst_ctx->hwctx;
+ AVD3D11VADeviceContext *d3d11_ctx = src_ctx->hwctx;
+ AMF_RESULT res;
+ 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);
+ }
+ return 0;
+}
+#endif
+
+static int amf_device_derive(AVHWDeviceContext *dst_ctx,
+ AVHWDeviceContext *src_ctx,
+ int flags)
+{
+ int err;
+
+ err = amf_init_device_ctx_object(dst_ctx);
+ if (err < 0)
+ return err;
+
+ switch (src_ctx->type) {
+
+#if CONFIG_DXVA2
+ case AV_HWDEVICE_TYPE_DXVA2:
+ return amf_device_derive_dxva2(dst_ctx, src_ctx);
+#endif
+
+#if CONFIG_D3D11VA
+ case AV_HWDEVICE_TYPE_D3D11VA:
+ return amf_device_derive_d3d11(dst_ctx, src_ctx);
+#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;
+}
+
+const HWContextType ff_hwcontext_type_amf = {
+ .type = AV_HWDEVICE_TYPE_AMF,
+ .name = "AMF",
+
+ .device_hwctx_size = sizeof(AVAMFDeviceContext),
+ .device_priv_size = sizeof(AMFDeviceContextPrivate),
+
+ .device_create = &amf_device_create,
+ .device_derive = &amf_device_derive,
+};
diff --git a/libavutil/hwcontext_amf.h b/libavutil/hwcontext_amf.h
new file mode 100644
index 0000000000..691a217c2e
--- /dev/null
+++ b/libavutil/hwcontext_amf.h
@@ -0,0 +1,53 @@
+/*
+ * 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 "AMF/core/Context.h"
+#include "AMF/core/Factory.h"
+
+
+/**
+ * This struct is allocated as AVHWDeviceContext.hwctx
+ */
+typedef struct AVAMFDeviceContext {
+ /**
+ * Context used for:
+ * texture and buffers allocation.
+ * Access to device objects (DX9, DX11, OpenCL, OpenGL) which are being used in the context
+ */
+ AMFContext *context;
+
+ /**
+ * Factory used for:
+ * AMF component creation such as encoder, decoder, converter...
+ * Access AMF Library settings such as trace/debug/cache
+ */
+ AMFFactory *factory;
+} AVAMFDeviceContext;
+
+
+#endif /* AVUTIL_HWCONTEXT_AMF_H */
diff --git a/libavutil/hwcontext_internal.h b/libavutil/hwcontext_internal.h
index 77dc47ddd6..cb76e04866 100644
--- a/libavutil/hwcontext_internal.h
+++ b/libavutil/hwcontext_internal.h
@@ -162,6 +162,7 @@ int ff_hwframe_map_create(AVBufferRef *hwframe_ref,
*/
int ff_hwframe_map_replace(AVFrame *dst, const AVFrame *src);
+extern const HWContextType ff_hwcontext_type_amf;
extern const HWContextType ff_hwcontext_type_cuda;
extern const HWContextType ff_hwcontext_type_d3d11va;
extern const HWContextType ff_hwcontext_type_drm;
--
2.19.1.windows.1
More information about the ffmpeg-devel
mailing list