History

avutil: add hwcontext_amf.

Adds hwcontext_amf, enabling a shared AMF context for encoders, decoders, and AMF-based filters, without copy to the host memory. Code also was tested in HandBrake. Benefits: - Optimizations for direct video memory access from CPU - Significant performance boost in full AMF pipelines with filters - Integration of GPU filters like VPP, Super Resolution, and Compression Artefact Removal(in future plans) - VCN power management control for decoders. - Ability to specify which VCN instance to use for decoding (like for encoder) - AMD will soon introduce full AMF API for multimedia accelerator MA35D - With AMF API, integration will be much easier: GPU and the accelerator will have the same API - including encoder, decoder, scaler, color converter, Windows and Linux. Learn more: https://www.amd.com/en/products/accelerators/alveo/ma35d.html Changes by versions: v2: Header file cleanup. v3: Removed an unnecessary class. v4: code cleanup and improved error handling v5: Fixes related to HandBrake integration. v6: Sequential filters error and memory leak have been fixed.

Dmitrii Ovchinnikov committed 2 years ago

Commit 9e724251 parent 1c5961e9 files · +718 −0Browse files

Showing the changes to libavutil (9 of 9 files). Show all

Unified · Split

9 files
  1. libavutil/Makefile +4 −0
  2. libavutil/hwcontext.c +4 −0
  3. libavutil/hwcontext.h +1 −0
  4. libavutil/hwcontext_amf.c +610 −0
  5. libavutil/hwcontext_amf.h +45 −0
  6. libavutil/hwcontext_amf_internal.h +44 −0
  7. libavutil/hwcontext_internal.h +1 −0
  8. libavutil/pixdesc.c +4 −0
  9. libavutil/pixfmt.h +5 −0
libavutil/Makefile+4−0
@@ -47,6 +47,7 @@ HEADERS = adler32.h \ · 46 unmodified lines
4747 hwcontext_d3d12va.h \
4848 hwcontext_drm.h \
4949 hwcontext_dxva2.h \
50+ hwcontext_amf.h \
5051 hwcontext_qsv.h \
5152 hwcontext_mediacodec.h \
5253 hwcontext_opencl.h \
@@ -200,6 +201,7 @@ OBJS-$(CONFIG_CUDA) += hwcontext_cuda.o · 147 unmodified lines
200201 OBJS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.o
201202 OBJS-$(CONFIG_D3D12VA) += hwcontext_d3d12va.o
202203 OBJS-$(CONFIG_DXVA2) += hwcontext_dxva2.o
204+OBJS-$(CONFIG_AMF) += hwcontext_amf.o
203205 OBJS-$(CONFIG_LIBDRM) += hwcontext_drm.o
204206 OBJS-$(CONFIG_MACOS_KPERF) += macos_kperf.o
205207 OBJS-$(CONFIG_MEDIACODEC) += hwcontext_mediacodec.o
@@ -224,6 +226,8 @@ SKIPHEADERS-$(CONFIG_CUDA) += hwcontext_cuda_internal.h \ · 18 unmodified lines
224226 SKIPHEADERS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.h
225227 SKIPHEADERS-$(CONFIG_D3D12VA) += hwcontext_d3d12va.h
226228 SKIPHEADERS-$(CONFIG_DXVA2) += hwcontext_dxva2.h
229+SKIPHEADERS-$(CONFIG_AMF) += hwcontext_amf.h \
230+ hwcontext_amf_internal
227231 SKIPHEADERS-$(CONFIG_QSV) += hwcontext_qsv.h
228232 SKIPHEADERS-$(CONFIG_OPENCL) += hwcontext_opencl.h
229233 SKIPHEADERS-$(CONFIG_VAAPI) += hwcontext_vaapi.h
libavutil/hwcontext.c+4−0
@@ -65,6 +65,9 @@ static const HWContextType * const hw_table[] = { · 64 unmodified lines
6565 #endif
6666 #if CONFIG_VULKAN
6767 &ff_hwcontext_type_vulkan,
68+#endif
69+#if CONFIG_AMF
70+ &ff_hwcontext_type_amf,
6871 #endif
6972 NULL,
7073 };
@@ -82,6 +85,7 @@ static const char *const hw_type_names[] = { · 11 unmodified lines
8285 [AV_HWDEVICE_TYPE_VIDEOTOOLBOX] = "videotoolbox",
8386 [AV_HWDEVICE_TYPE_MEDIACODEC] = "mediacodec",
8487 [AV_HWDEVICE_TYPE_VULKAN] = "vulkan",
88+ [AV_HWDEVICE_TYPE_AMF] = "amf",
8589 };
8690
8791 typedef struct FFHWDeviceContext {
libavutil/hwcontext.h+1−0
@@ -38,6 +38,7 @@ enum AVHWDeviceType { · 37 unmodified lines
3838 AV_HWDEVICE_TYPE_MEDIACODEC,
3939 AV_HWDEVICE_TYPE_VULKAN,
4040 AV_HWDEVICE_TYPE_D3D12VA,
41+ AV_HWDEVICE_TYPE_AMF,
4142 };
4243
4344 /**
libavutil/hwcontext_amf.c+610−0
@@ -0,0 +1,610 @@
1+/*
2+ * This file is part of FFmpeg.
3+ *
4+ * FFmpeg is free software; you can redistribute it and/or
5+ * modify it under the terms of the GNU Lesser General Public
6+ * License as published by the Free Software Foundation; either
7+ * version 2.1 of the License, or (at your option) any later version.
8+ *
9+ * FFmpeg is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+ * Lesser General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU Lesser General Public
15+ * License along with FFmpeg; if not, write to the Free Software
16+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17+ */
18+
19+#include "buffer.h"
20+#include "common.h"
21+#include "hwcontext.h"
22+#include "hwcontext_amf.h"
23+#include "hwcontext_internal.h"
24+#include "hwcontext_amf_internal.h"
25+#if CONFIG_VULKAN
26+#include "hwcontext_vulkan.h"
27+#endif
28+#if CONFIG_D3D11VA
29+#include "libavutil/hwcontext_d3d11va.h"
30+#endif
31+#if CONFIG_DXVA2
32+#define COBJMACROS
33+#include "libavutil/hwcontext_dxva2.h"
34+#endif
35+#include "mem.h"
36+#include "pixdesc.h"
37+#include "pixfmt.h"
38+#include "imgutils.h"
39+#include "libavutil/avassert.h"
40+#include <AMF/core/Surface.h>
41+#include <AMF/core/Trace.h>
42+#ifdef _WIN32
43+#include "compat/w32dlfcn.h"
44+#else
45+#include <dlfcn.h>
46+#endif
47+#define FFMPEG_AMF_WRITER_ID L"ffmpeg_amf"
48+
49+
50+typedef struct AmfTraceWriter {
51+ AMFTraceWriterVtbl *vtblp;
52+ void *avctx;
53+ AMFTraceWriterVtbl vtbl;
54+} AmfTraceWriter;
55+
56+static void AMF_CDECL_CALL AMFTraceWriter_Write(AMFTraceWriter *pThis,
57+ const wchar_t *scope, const wchar_t *message)
58+{
59+ AmfTraceWriter *tracer = (AmfTraceWriter*)pThis;
60+ av_log(tracer->avctx, AV_LOG_DEBUG, "%ls: %ls", scope, message); // \n is provided from AMF
61+}
62+
63+static void AMF_CDECL_CALL AMFTraceWriter_Flush(AMFTraceWriter *pThis)
64+{
65+}
66+
67+static AmfTraceWriter * amf_writer_alloc(void *avctx)
68+{
69+ AmfTraceWriter * writer = av_mallocz(sizeof(AmfTraceWriter));
70+ if (!writer)
71+ return NULL;
72+
73+ writer->vtblp = &writer->vtbl;
74+ writer->vtblp->Write = AMFTraceWriter_Write;
75+ writer->vtblp->Flush = AMFTraceWriter_Flush;
76+ writer->avctx = avctx;
77+
78+ return writer;
79+}
80+
81+static void amf_writer_free(void *opaque)
82+{
83+ AmfTraceWriter *writer = (AmfTraceWriter *)opaque;
84+ av_freep(&writer);
85+}
86+
87+/**
88+ * We still need AVHWFramesContext to utilize our hardware memory
89+ * otherwise, we will receive the error "HW format requires hw_frames_ctx to be non-NULL".
90+ * (libavfilter\buffersrc.c function query_formats)
91+*/
92+typedef struct {
93+ void *dummy;
94+} AMFFramesContext;
95+
96+typedef struct AVAMFFormatMap {
97+ enum AVPixelFormat av_format;
98+ enum AMF_SURFACE_FORMAT amf_format;
99+} FormatMap;
100+
101+const FormatMap format_map[] =
102+{
103+ { AV_PIX_FMT_NONE, AMF_SURFACE_UNKNOWN },
104+ { AV_PIX_FMT_NV12, AMF_SURFACE_NV12 },
105+ { AV_PIX_FMT_BGR0, AMF_SURFACE_BGRA },
106+ { AV_PIX_FMT_RGB0, AMF_SURFACE_RGBA },
107+ { AV_PIX_FMT_BGRA, AMF_SURFACE_BGRA },
108+ { AV_PIX_FMT_ARGB, AMF_SURFACE_ARGB },
109+ { AV_PIX_FMT_RGBA, AMF_SURFACE_RGBA },
110+ { AV_PIX_FMT_GRAY8, AMF_SURFACE_GRAY8 },
111+ { AV_PIX_FMT_YUV420P, AMF_SURFACE_YUV420P },
112+ { AV_PIX_FMT_YUYV422, AMF_SURFACE_YUY2 },
113+ { AV_PIX_FMT_P010, AMF_SURFACE_P010 },
114+};
115+
116+enum AMF_SURFACE_FORMAT av_av_to_amf_format(enum AVPixelFormat fmt)
117+{
118+ int i;
119+ for (i = 0; i < amf_countof(format_map); i++) {
120+ if (format_map[i].av_format == fmt) {
121+ return format_map[i].amf_format;
122+ }
123+ }
124+ return AMF_SURFACE_UNKNOWN;
125+}
126+
127+enum AVPixelFormat av_amf_to_av_format(enum AMF_SURFACE_FORMAT fmt)
128+{
129+ int i;
130+ for (i = 0; i < amf_countof(format_map); i++) {
131+ if (format_map[i].amf_format == fmt) {
132+ return format_map[i].av_format;
133+ }
134+ }
135+ return AMF_SURFACE_UNKNOWN;
136+}
137+
138+static const enum AVPixelFormat supported_formats[] = {
139+ AV_PIX_FMT_NV12,
140+ AV_PIX_FMT_YUV420P,
141+ AV_PIX_FMT_BGRA,
142+ AV_PIX_FMT_RGBA,
143+ AV_PIX_FMT_P010,
144+#if CONFIG_D3D11VA
145+ AV_PIX_FMT_D3D11,
146+#endif
147+#if CONFIG_DXVA2
148+ AV_PIX_FMT_DXVA2_VLD,
149+#endif
150+};
151+
152+static const enum AVPixelFormat supported_transfer_formats[] = {
153+ AV_PIX_FMT_NV12,
154+ AV_PIX_FMT_YUV420P,
155+ AV_PIX_FMT_BGRA,
156+ AV_PIX_FMT_RGBA,
157+ AV_PIX_FMT_P010,
158+ AV_PIX_FMT_NONE,
159+};
160+
161+static int amf_frames_get_constraints(AVHWDeviceContext *ctx,
162+ const void *hwconfig,
163+ AVHWFramesConstraints *constraints)
164+{
165+ int i;
166+
167+ constraints->valid_sw_formats = av_malloc_array(FF_ARRAY_ELEMS(supported_formats) + 1,
168+ sizeof(*constraints->valid_sw_formats));
169+ if (!constraints->valid_sw_formats)
170+ return AVERROR(ENOMEM);
171+
172+ for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++)
173+ constraints->valid_sw_formats[i] = supported_formats[i];
174+ constraints->valid_sw_formats[FF_ARRAY_ELEMS(supported_formats)] = AV_PIX_FMT_NONE;
175+
176+ constraints->valid_hw_formats = av_malloc_array(2, sizeof(*constraints->valid_hw_formats));
177+ if (!constraints->valid_hw_formats)
178+ return AVERROR(ENOMEM);
179+
180+ constraints->valid_hw_formats[0] = AV_PIX_FMT_AMF_SURFACE;
181+ constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
182+
183+ return 0;
184+}
185+
186+static void amf_dummy_free(void *opaque, uint8_t *data)
187+{
188+
189+}
190+
191+static AVBufferRef *amf_pool_alloc(void *opaque, size_t size)
192+{
193+ AVHWFramesContext *hwfc = (AVHWFramesContext *)opaque;
194+ AVBufferRef *buf;
195+
196+ buf = av_buffer_create(NULL, 0, amf_dummy_free, hwfc, AV_BUFFER_FLAG_READONLY);
197+ if (!buf) {
198+ av_log(hwfc, AV_LOG_ERROR, "Failed to create buffer for AMF context.\n");
199+ return NULL;
200+ }
201+ return buf;
202+}
203+
204+static int amf_frames_init(AVHWFramesContext *ctx)
205+{
206+ int i;
207+
208+ for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) {
209+ if (ctx->sw_format == supported_formats[i])
210+ break;
211+ }
212+ if (i == FF_ARRAY_ELEMS(supported_formats)) {
213+ av_log(ctx, AV_LOG_ERROR, "Pixel format '%s' is not supported\n",
214+ av_get_pix_fmt_name(ctx->sw_format));
215+ return AVERROR(ENOSYS);
216+ }
217+
218+ ffhwframesctx(ctx)->pool_internal =
219+ av_buffer_pool_init2(sizeof(AMFSurface), ctx,
220+ &amf_pool_alloc, NULL);
221+
222+ return 0;
223+}
224+
225+
226+static int amf_get_buffer(AVHWFramesContext *ctx, AVFrame *frame)
227+{
228+ frame->buf[0] = av_buffer_pool_get(ctx->pool);
229+ if (!frame->buf[0])
230+ return AVERROR(ENOMEM);
231+
232+ frame->data[0] = frame->buf[0]->data;
233+ frame->format = AV_PIX_FMT_AMF_SURFACE;
234+ frame->width = ctx->width;
235+ frame->height = ctx->height;
236+ return 0;
237+}
238+
239+static int amf_transfer_get_formats(AVHWFramesContext *ctx,
240+ enum AVHWFrameTransferDirection dir,
241+ enum AVPixelFormat **formats)
242+{
243+ enum AVPixelFormat *fmts;
244+ int i;
245+
246+ fmts = av_malloc_array(FF_ARRAY_ELEMS(supported_transfer_formats), sizeof(*fmts));
247+ if (!fmts)
248+ return AVERROR(ENOMEM);
249+ for (i = 0; i < FF_ARRAY_ELEMS(supported_transfer_formats); i++)
250+ fmts[i] = supported_transfer_formats[i];
251+
252+ *formats = fmts;
253+
254+ return 0;
255+}
256+
257+static void amf_free_amfsurface(void *opaque, uint8_t *data)
258+{
259+ if(!!data){
260+ AMFSurface *surface = (AMFSurface*)(data);
261+ surface->pVtbl->Release(surface);
262+ }
263+}
264+
265+static int amf_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst,
266+ const AVFrame *src)
267+{
268+ AMFSurface* surface = (AMFSurface*)dst->data[0];
269+ AMFPlane *plane;
270+ uint8_t *dst_data[4];
271+ int dst_linesize[4];
272+ int planes;
273+ int i;
274+ int res;
275+ int w = FFMIN(dst->width, src->width);
276+ int h = FFMIN(dst->height, src->height);
277+
278+ if (!surface) {
279+ AVHWDeviceContext *hwdev_ctx = ctx->device_ctx;
280+ AVAMFDeviceContext *amf_device_ctx = (AVAMFDeviceContext *)hwdev_ctx->hwctx;
281+ AMF_SURFACE_FORMAT format = av_av_to_amf_format(ctx->sw_format);
282+ res = amf_device_ctx->context->pVtbl->AllocSurface(amf_device_ctx->context, AMF_MEMORY_HOST, format, dst->width, dst->height, &surface);
283+ AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "AllocSurface() failed with error %d\n", res);
284+ dst->data[0] = (uint8_t *)surface;
285+ dst->buf[1] = av_buffer_create((uint8_t *)surface, sizeof(surface),
286+ amf_free_amfsurface,
287+ NULL,
288+ AV_BUFFER_FLAG_READONLY);
289+ AMF_RETURN_IF_FALSE(ctx, !!dst->buf[1], AVERROR(ENOMEM), "av_buffer_create for amf surface failed.");
290+ }
291+
292+ planes = (int)surface->pVtbl->GetPlanesCount(surface);
293+ av_assert0(planes < FF_ARRAY_ELEMS(dst_data));
294+
295+ for (i = 0; i < planes; i++) {
296+ plane = surface->pVtbl->GetPlaneAt(surface, i);
297+ dst_data[i] = plane->pVtbl->GetNative(plane);
298+ dst_linesize[i] = plane->pVtbl->GetHPitch(plane);
299+ }
300+ av_image_copy2(dst_data, dst_linesize,
301+ src->data, src->linesize, src->format,
302+ w, h);
303+
304+ return 0;
305+}
306+
307+static int amf_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst,
308+ const AVFrame *src)
309+{
310+ AMFSurface* surface = (AMFSurface*)src->data[0];
311+ AMFPlane *plane;
312+ uint8_t *src_data[4];
313+ int src_linesize[4];
314+ int planes;
315+ int i;
316+ int w = FFMIN(dst->width, src->width);
317+ int h = FFMIN(dst->height, src->height);
318+ int ret;
319+
320+ ret = surface->pVtbl->Convert(surface, AMF_MEMORY_HOST);
321+ AMF_RETURN_IF_FALSE(ctx, ret == AMF_OK, AVERROR_UNKNOWN, "Convert(amf::AMF_MEMORY_HOST) failed with error %d\n", AVERROR_UNKNOWN);
322+
323+ planes = (int)surface->pVtbl->GetPlanesCount(surface);
324+ av_assert0(planes < FF_ARRAY_ELEMS(src_data));
325+
326+ for (i = 0; i < planes; i++) {
327+ plane = surface->pVtbl->GetPlaneAt(surface, i);
328+ src_data[i] = plane->pVtbl->GetNative(plane);
329+ src_linesize[i] = plane->pVtbl->GetHPitch(plane);
330+ }
331+ av_image_copy2(dst->data, dst->linesize,
332+ src_data, src_linesize, dst->format,
333+ w, h);
334+ return 0;
335+}
336+
337+
338+
339+static void amf_device_uninit(AVHWDeviceContext *device_ctx)
340+{
341+ AVAMFDeviceContext *amf_ctx = device_ctx->hwctx;
342+ AMF_RESULT res;
343+ AMFTrace *trace;
344+
345+ if (amf_ctx->context) {
346+ amf_ctx->context->pVtbl->Terminate(amf_ctx->context);
347+ amf_ctx->context->pVtbl->Release(amf_ctx->context);
348+ amf_ctx->context = NULL;
349+ }
350+
351+ res = amf_ctx->factory->pVtbl->GetTrace(amf_ctx->factory, &trace);
352+ if (res == AMF_OK) {
353+ trace->pVtbl->UnregisterWriter(trace, FFMPEG_AMF_WRITER_ID);
354+ }
355+
356+ if(amf_ctx->library) {
357+ dlclose(amf_ctx->library);
358+ amf_ctx->library = NULL;
359+ }
360+ if (amf_ctx->trace_writer) {
361+ amf_writer_free(amf_ctx->trace_writer);
362+ }
363+
364+ amf_ctx->version = 0;
365+}
366+
367+static int amf_device_init(AVHWDeviceContext *ctx)
368+{
369+ AVAMFDeviceContext *amf_ctx = ctx->hwctx;
370+ AMFContext1 *context1 = NULL;
371+ AMF_RESULT res;
372+
373+#ifdef _WIN32
374+ res = amf_ctx->context->pVtbl->InitDX11(amf_ctx->context, NULL, AMF_DX11_1);
375+ if (res == AMF_OK || res == AMF_ALREADY_INITIALIZED) {
376+ av_log(ctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D11.\n");
377+ } else {
378+ res = amf_ctx->context->pVtbl->InitDX9(amf_ctx->context, NULL);
379+ if (res == AMF_OK) {
380+ av_log(ctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D9.\n");
381+ } else {
382+#endif
383+ AMFGuid guid = IID_AMFContext1();
384+ res = amf_ctx->context->pVtbl->QueryInterface(amf_ctx->context, &guid, (void**)&context1);
385+ AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext1() failed with error %d\n", res);
386+
387+ res = context1->pVtbl->InitVulkan(context1, NULL);
388+ context1->pVtbl->Release(context1);
389+ if (res != AMF_OK && res != AMF_ALREADY_INITIALIZED) {
390+ if (res == AMF_NOT_SUPPORTED)
391+ av_log(ctx, AV_LOG_ERROR, "AMF via Vulkan is not supported on the given device.\n");
392+ else
393+ av_log(ctx, AV_LOG_ERROR, "AMF failed to initialise on the given Vulkan device: %d.\n", res);
394+ return AVERROR(ENOSYS);
395+ }
396+ av_log(ctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via Vulkan.\n");
397+#ifdef _WIN32
398+ }
399+ }
400+#endif
401+ return 0;
402+}
403+
404+static int amf_load_library(AVAMFDeviceContext* amf_ctx, void* avcl)
405+{
406+ AMFInit_Fn init_fun;
407+ AMFQueryVersion_Fn version_fun;
408+ AMF_RESULT res;
409+
410+ amf_ctx->library = dlopen(AMF_DLL_NAMEA, RTLD_NOW | RTLD_LOCAL);
411+ AMF_RETURN_IF_FALSE(avcl, amf_ctx->library != NULL,
412+ AVERROR_UNKNOWN, "DLL %s failed to open\n", AMF_DLL_NAMEA);
413+
414+ init_fun = (AMFInit_Fn)dlsym(amf_ctx->library, AMF_INIT_FUNCTION_NAME);
415+ AMF_RETURN_IF_FALSE(avcl, init_fun != NULL, AVERROR_UNKNOWN, "DLL %s failed to find function %s\n", AMF_DLL_NAMEA, AMF_INIT_FUNCTION_NAME);
416+
417+ version_fun = (AMFQueryVersion_Fn)dlsym(amf_ctx->library, AMF_QUERY_VERSION_FUNCTION_NAME);
418+ AMF_RETURN_IF_FALSE(avcl, version_fun != NULL, AVERROR_UNKNOWN, "DLL %s failed to find function %s\n", AMF_DLL_NAMEA, AMF_QUERY_VERSION_FUNCTION_NAME);
419+
420+ res = version_fun(&amf_ctx->version);
421+ AMF_RETURN_IF_FALSE(avcl, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_QUERY_VERSION_FUNCTION_NAME, res);
422+ res = init_fun(AMF_FULL_VERSION, &amf_ctx->factory);
423+ AMF_RETURN_IF_FALSE(avcl, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_INIT_FUNCTION_NAME, res);
424+ return 0;
425+}
426+
427+static int amf_device_create(AVHWDeviceContext *device_ctx,
428+ const char *device,
429+ AVDictionary *opts, int flags)
430+{
431+ AVAMFDeviceContext *ctx = device_ctx->hwctx;
432+ AMFTrace *trace;
433+ int ret;
434+ if ((ret = amf_load_library(ctx, device_ctx)) == 0) {
435+ ret = ctx->factory->pVtbl->GetTrace(ctx->factory, &trace);
436+ if (ret == AMF_OK) {
437+ int level_ff = av_log_get_level();
438+ int level_amf = AMF_TRACE_TRACE;
439+ amf_bool enable_log = true;
440+ switch(level_ff)
441+ {
442+ case AV_LOG_QUIET:
443+ level_amf = AMF_TRACE_ERROR;
444+ enable_log = false;
445+ break;
446+ case AV_LOG_PANIC:
447+ case AV_LOG_FATAL:
448+ case AV_LOG_ERROR:
449+ level_amf = AMF_TRACE_ERROR;
450+ break;
451+ case AV_LOG_WARNING:
452+ case AV_LOG_INFO:
453+ level_amf = AMF_TRACE_WARNING;
454+ break;
455+ case AV_LOG_VERBOSE:
456+ level_amf = AMF_TRACE_INFO;
457+ break;
458+ case AV_LOG_DEBUG:
459+ level_amf = AMF_TRACE_DEBUG;
460+ break;
461+ case AV_LOG_TRACE:
462+ level_amf = AMF_TRACE_TRACE;
463+ break;
464+ }
465+ if(ctx->version == AMF_MAKE_FULL_VERSION(1, 4, 35, 0)){// get around a bug in trace in AMF runtime driver 24.20
466+ level_amf = AMF_TRACE_WARNING;
467+ }
468+
469+ trace->pVtbl->EnableWriter(trace, AMF_TRACE_WRITER_CONSOLE, 0);
470+ trace->pVtbl->SetGlobalLevel(trace, level_amf);
471+
472+ // connect AMF logger to av_log
473+ ctx->trace_writer = amf_writer_alloc(device_ctx);
474+ trace->pVtbl->RegisterWriter(trace, FFMPEG_AMF_WRITER_ID, (AMFTraceWriter*)ctx->trace_writer, 1);
475+ trace->pVtbl->SetWriterLevel(trace, FFMPEG_AMF_WRITER_ID, level_amf);
476+ trace->pVtbl->EnableWriter(trace, FFMPEG_AMF_WRITER_ID, enable_log);
477+ trace->pVtbl->SetWriterLevel(trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, level_amf);
478+ trace->pVtbl->EnableWriter(trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, enable_log);
479+ }
480+
481+
482+ ret = ctx->factory->pVtbl->CreateContext(ctx->factory, &ctx->context);
483+ if (ret == AMF_OK)
484+ return 0;
485+ av_log(device_ctx, AV_LOG_ERROR, "CreateContext() failed with error %d.\n", ret);
486+ }
487+ amf_device_uninit(device_ctx);
488+ return ret;
489+}
490+
491+#if CONFIG_DXVA2
492+static int amf_init_from_dxva2_device(AVAMFDeviceContext * amf_ctx, AVDXVA2DeviceContext *hwctx)
493+{
494+ IDirect3DDevice9 *device;
495+ HANDLE device_handle;
496+ HRESULT hr;
497+ AMF_RESULT res;
498+ int ret;
499+
500+ hr = IDirect3DDeviceManager9_OpenDeviceHandle(hwctx->devmgr, &device_handle);
501+ if (FAILED(hr)) {
502+ av_log(hwctx, AV_LOG_ERROR, "Failed to open device handle for Direct3D9 device: %lx.\n", (unsigned long)hr);
503+ return AVERROR_EXTERNAL;
504+ }
505+
506+ hr = IDirect3DDeviceManager9_LockDevice(hwctx->devmgr, device_handle, &device, FALSE);
507+ if (SUCCEEDED(hr)) {
508+ IDirect3DDeviceManager9_UnlockDevice(hwctx->devmgr, device_handle, FALSE);
509+ ret = 0;
510+ } else {
511+ av_log(hwctx, AV_LOG_ERROR, "Failed to lock device handle for Direct3D9 device: %lx.\n", (unsigned long)hr);
512+ ret = AVERROR_EXTERNAL;
513+ }
514+
515+
516+ IDirect3DDeviceManager9_CloseDeviceHandle(hwctx->devmgr, device_handle);
517+
518+ if (ret < 0)
519+ return ret;
520+
521+ res = amf_ctx->context->pVtbl->InitDX9(amf_ctx->context, device);
522+
523+ IDirect3DDevice9_Release(device);
524+
525+ if (res != AMF_OK && res != AMF_ALREADY_INITIALIZED) {
526+ if (res == AMF_NOT_SUPPORTED)
527+ av_log(hwctx, AV_LOG_ERROR, "AMF via D3D9 is not supported on the given device.\n");
528+ else
529+ av_log(hwctx, AV_LOG_ERROR, "AMF failed to initialise on given D3D9 device: %d.\n", res);
530+ return AVERROR(ENODEV);
531+ }
532+ return 0;
533+}
534+#endif
535+
536+#if CONFIG_D3D11VA
537+static int amf_init_from_d3d11_device(AVAMFDeviceContext* amf_ctx, AVD3D11VADeviceContext *hwctx)
538+{
539+ AMF_RESULT res;
540+ res = amf_ctx->context->pVtbl->InitDX11(amf_ctx->context, hwctx->device, AMF_DX11_1);
541+ if (res != AMF_OK && res != AMF_ALREADY_INITIALIZED) {
542+ if (res == AMF_NOT_SUPPORTED)
543+ av_log(hwctx, AV_LOG_ERROR, "AMF via D3D11 is not supported on the given device.\n");
544+ else
545+ av_log(hwctx, AV_LOG_ERROR, "AMF failed to initialise on the given D3D11 device: %d.\n", res);
546+ return AVERROR(ENODEV);
547+ }
548+ return 0;
549+}
550+#endif
551+
552+static int amf_device_derive(AVHWDeviceContext *device_ctx,
553+ AVHWDeviceContext *child_device_ctx, AVDictionary *opts,
554+ int flags)
555+{
556+#if CONFIG_DXVA2 || CONFIG_D3D11VA
557+ AVAMFDeviceContext *amf_ctx = device_ctx->hwctx;
558+#endif
559+ int ret;
560+
561+ ret = amf_device_create(device_ctx, "", opts, flags);
562+ if(ret < 0)
563+ return ret;
564+
565+ switch (child_device_ctx->type) {
566+
567+#if CONFIG_DXVA2
568+ case AV_HWDEVICE_TYPE_DXVA2: {
569+ AVDXVA2DeviceContext *child_device_hwctx = child_device_ctx->hwctx;
570+ return amf_init_from_dxva2_device(amf_ctx, child_device_hwctx);
571+ }
572+ break;
573+#endif
574+
575+#if CONFIG_D3D11VA
576+ case AV_HWDEVICE_TYPE_D3D11VA: {
577+ AVD3D11VADeviceContext *child_device_hwctx = child_device_ctx->hwctx;
578+ return amf_init_from_d3d11_device(amf_ctx, child_device_hwctx);
579+ }
580+ break;
581+#endif
582+ default: {
583+ av_log(child_device_ctx, AV_LOG_ERROR, "AMF initialisation from a %s device is not supported.\n",
584+ av_hwdevice_get_type_name(child_device_ctx->type));
585+ return AVERROR(ENOSYS);
586+ }
587+ }
588+ return 0;
589+}
590+
591+const HWContextType ff_hwcontext_type_amf = {
592+ .type = AV_HWDEVICE_TYPE_AMF,
593+ .name = "AMF",
594+
595+ .device_hwctx_size = sizeof(AVAMFDeviceContext),
596+ .frames_hwctx_size = sizeof(AMFFramesContext),
597+
598+ .device_create = amf_device_create,
599+ .device_derive = amf_device_derive,
600+ .device_init = amf_device_init,
601+ .device_uninit = amf_device_uninit,
602+ .frames_get_constraints = amf_frames_get_constraints,
603+ .frames_init = amf_frames_init,
604+ .frames_get_buffer = amf_get_buffer,
605+ .transfer_get_formats = amf_transfer_get_formats,
606+ .transfer_data_to = amf_transfer_data_to,
607+ .transfer_data_from = amf_transfer_data_from,
608+
609+ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_AMF_SURFACE, AV_PIX_FMT_NONE },
610+};
libavutil/hwcontext_amf.h+45−0
@@ -0,0 +1,45 @@
1+/*
2+ * This file is part of FFmpeg.
3+ *
4+ * FFmpeg is free software; you can redistribute it and/or
5+ * modify it under the terms of the GNU Lesser General Public
6+ * License as published by the Free Software Foundation; either
7+ * version 2.1 of the License, or (at your option) any later version.
8+ *
9+ * FFmpeg is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+ * Lesser General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU Lesser General Public
15+ * License along with FFmpeg; if not, write to the Free Software
16+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17+ */
18+
19+
20+#ifndef AVUTIL_HWCONTEXT_AMF_H
21+#define AVUTIL_HWCONTEXT_AMF_H
22+
23+#include "pixfmt.h"
24+#include "hwcontext.h"
25+#include <AMF/core/Factory.h>
26+#include <AMF/core/Context.h>
27+#include <AMF/core/Trace.h>
28+#include <AMF/core/Debug.h>
29+
30+/**
31+ * This struct is allocated as AVHWDeviceContext.hwctx
32+ */
33+typedef struct AVAMFDeviceContext {
34+ void * library;
35+ AMFFactory *factory;
36+ void *trace_writer;
37+
38+ int64_t version; ///< version of AMF runtime
39+ AMFContext *context;
40+} AVAMFDeviceContext;
41+
42+enum AMF_SURFACE_FORMAT av_av_to_amf_format(enum AVPixelFormat fmt);
43+enum AVPixelFormat av_amf_to_av_format(enum AMF_SURFACE_FORMAT fmt);
44+
45+#endif /* AVUTIL_HWCONTEXT_AMF_H */
libavutil/hwcontext_amf_internal.h+44−0
@@ -0,0 +1,44 @@
1+/*
2+ * This file is part of FFmpeg.
3+ *
4+ * FFmpeg is free software; you can redistribute it and/or
5+ * modify it under the terms of the GNU Lesser General Public
6+ * License as published by the Free Software Foundation; either
7+ * version 2.1 of the License, or (at your option) any later version.
8+ *
9+ * FFmpeg is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+ * Lesser General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU Lesser General Public
15+ * License along with FFmpeg; if not, write to the Free Software
16+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17+ */
18+
19+
20+#ifndef AVUTIL_HWCONTEXT_AMF_INTERNAL_H
21+#define AVUTIL_HWCONTEXT_AMF_INTERNAL_H
22+#include <AMF/core/Factory.h>
23+#include <AMF/core/Context.h>
24+
25+/**
26+* Error handling helper
27+*/
28+#define AMF_RETURN_IF_FALSE(avctx, exp, ret_value, /*message,*/ ...) \
29+ if (!(exp)) { \
30+ av_log(avctx, AV_LOG_ERROR, __VA_ARGS__); \
31+ return ret_value; \
32+ }
33+
34+#define AMF_GOTO_FAIL_IF_FALSE(avctx, exp, ret_value, /*message,*/ ...) \
35+ if (!(exp)) { \
36+ av_log(avctx, AV_LOG_ERROR, __VA_ARGS__); \
37+ ret = ret_value; \
38+ goto fail; \
39+ }
40+
41+#define AMF_TIME_BASE_Q (AVRational){1, AMF_SECOND}
42+
43+
44+#endif /* AVUTIL_HWCONTEXT_AMF_INTERNAL_H */
libavutil/hwcontext_internal.h+1−0
@@ -163,5 +163,6 @@ extern const HWContextType ff_hwcontext_type_vdpau; · 162 unmodified lines
163163 extern const HWContextType ff_hwcontext_type_videotoolbox;
164164 extern const HWContextType ff_hwcontext_type_mediacodec;
165165 extern const HWContextType ff_hwcontext_type_vulkan;
166+extern const HWContextType ff_hwcontext_type_amf;
166167
167168 #endif /* AVUTIL_HWCONTEXT_INTERNAL_H */
libavutil/pixdesc.c+4−0
@@ -2133,6 +2133,10 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { · 2132 unmodified lines
21332133 .name = "cuda",
21342134 .flags = AV_PIX_FMT_FLAG_HWACCEL,
21352135 },
2136+ [AV_PIX_FMT_AMF_SURFACE] = {
2137+ .name = "amf",
2138+ .flags = AV_PIX_FMT_FLAG_HWACCEL,
2139+ },
21362140 [AV_PIX_FMT_VYU444] = {
21372141 .name = "vyu444",
21382142 .nb_components = 3,
libavutil/pixfmt.h+5−0
@@ -471,6 +471,11 @@ enum AVPixelFormat { · 470 unmodified lines
471471 AV_PIX_FMT_GRAYF16BE, ///< IEEE-754 half precision Y, 16bpp, big-endian
472472 AV_PIX_FMT_GRAYF16LE, ///< IEEE-754 half precision Y, 16bpp, little-endian
473473
474+ /**
475+ * HW acceleration through AMF. data[0] contain AMFSurface pointer
476+ */
477+ AV_PIX_FMT_AMF_SURFACE,
478+
474479 AV_PIX_FMT_NB ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions
475480 };
476481

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t