From patchwork Thu Nov 1 22:03:41 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Kravchenko X-Patchwork-Id: 10883 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 8F22B44D90A for ; Fri, 2 Nov 2018 00:10:44 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id F377968A937; Fri, 2 Nov 2018 00:10:15 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lf1-f68.google.com (mail-lf1-f68.google.com [209.85.167.68]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 3FF6D68A930 for ; Fri, 2 Nov 2018 00:10:10 +0200 (EET) Received: by mail-lf1-f68.google.com with SMTP id p86so12834lfg.5 for ; Thu, 01 Nov 2018 15:10:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=sL088i69PI/go8JqBuVxRL3mfLJdUyMkDhATRyUKKkA=; b=kPnrfoIahnMmsPPTXz0OEes0mFKy6+qqW0hM6ENRT/wmqf8rA5mTri5mQwbISZm+Ta NMV3KUISi41DjT9tAR1wrrPBqg5qWQTpK7eS4/9/s2ij4gIP7d//P2jjdh4n9wa6VJbh y4cNauxpS6EjBm/p4WMPlXFswpnj14nO3SKI4LQa0mKcbdTXPRAsSfFgvJtiglHIFpAJ y3IzYSOzmTxVMLvKQRyLP1Qa/KY7ooHPW1vVW/llvMSHBxJRxpvlv6GJtne+qBbdVUMQ 3yhQiGBYgCDsWE4ek7H8rrKIjmXpL+w81w27ASXY3taAmUXA04vmh1fSYxIMleVhhFcN dHoQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=sL088i69PI/go8JqBuVxRL3mfLJdUyMkDhATRyUKKkA=; b=kFnyMfrXUEpr+12bsUXmO3aR1Rj8Pg4i8RlUfP6RQdoG2GVyPwt0shgoLzeocwtAzk HrkYRwhPPJ1rojA5zIEsQbIO4DX9O2HG8dIIVrBnOE+swWAzu1QtYMExW1cwcKAa+Evg xqYlSG3t7gTV4oUl3OFfjKkPazPzSNMt+ne6tu7Py3itqy3iTlvEiCyWb2+/qIirhlYV jABny8Jtn7jhQjfbf/6TuYgGDEpoYHUq0SuRPCEI4ibZxcqp7vOTVcXieT+s5SIOyfOI sXiaWTAIQUXtnehyK2d3SVdfFmAwyRnDtuYbIW411E6YmvuH3muG1yw7j1iZUwhBaJTo 2DAQ== X-Gm-Message-State: AGRZ1gKFO55BbFZWz2F5vCkpfW5a9yAJ4D1siXRrXU/swrD6S9QReHNb oYeLIUGBfDgZHjQiiNaB0MaUSTzZ X-Google-Smtp-Source: AJdET5dkq/2OWKscphxP4fO2a4hpJnBLUxsLdwWr0+NKIJFISLCzCqUpUixiEyUXrFxsN26+A5rR1g== X-Received: by 2002:a19:9508:: with SMTP id x8mr5575680lfd.112.1541109831843; Thu, 01 Nov 2018 15:03:51 -0700 (PDT) Received: from localhost.localdomain ([188.227.65.188]) by smtp.gmail.com with ESMTPSA id 26-v6sm3607634lje.18.2018.11.01.15.03.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 01 Nov 2018 15:03:51 -0700 (PDT) From: akravchenko188@gmail.com To: ffmpeg-devel@ffmpeg.org Date: Fri, 2 Nov 2018 01:03:41 +0300 Message-Id: <20181101220341.11644-1-akravchenko188@gmail.com> X-Mailer: git-send-email 2.19.0.windows.1 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 1/2] lavu/hwcontext_amf: HWContext for AMF based components X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Alexander Kravchenko Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" From: Alexander Kravchenko --- 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 + +#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 +#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;