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
47 hwcontext_d3d12va.h \47 hwcontext_d3d12va.h \
48 hwcontext_drm.h \48 hwcontext_drm.h \
49 hwcontext_dxva2.h \49 hwcontext_dxva2.h \
50 hwcontext_amf.h \
50 hwcontext_qsv.h \51 hwcontext_qsv.h \
51 hwcontext_mediacodec.h \52 hwcontext_mediacodec.h \
52 hwcontext_opencl.h \53 hwcontext_opencl.h \
@@ -200,6 +201,7 @@ OBJS-$(CONFIG_CUDA) += hwcontext_cuda.o · 147 unmodified lines
200OBJS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.o201OBJS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.o
201OBJS-$(CONFIG_D3D12VA) += hwcontext_d3d12va.o202OBJS-$(CONFIG_D3D12VA) += hwcontext_d3d12va.o
202OBJS-$(CONFIG_DXVA2) += hwcontext_dxva2.o203OBJS-$(CONFIG_DXVA2) += hwcontext_dxva2.o
204OBJS-$(CONFIG_AMF) += hwcontext_amf.o
203OBJS-$(CONFIG_LIBDRM) += hwcontext_drm.o205OBJS-$(CONFIG_LIBDRM) += hwcontext_drm.o
204OBJS-$(CONFIG_MACOS_KPERF) += macos_kperf.o206OBJS-$(CONFIG_MACOS_KPERF) += macos_kperf.o
205OBJS-$(CONFIG_MEDIACODEC) += hwcontext_mediacodec.o207OBJS-$(CONFIG_MEDIACODEC) += hwcontext_mediacodec.o
@@ -224,6 +226,8 @@ SKIPHEADERS-$(CONFIG_CUDA) += hwcontext_cuda_internal.h \ · 18 unmodified lines
224SKIPHEADERS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.h226SKIPHEADERS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.h
225SKIPHEADERS-$(CONFIG_D3D12VA) += hwcontext_d3d12va.h227SKIPHEADERS-$(CONFIG_D3D12VA) += hwcontext_d3d12va.h
226SKIPHEADERS-$(CONFIG_DXVA2) += hwcontext_dxva2.h228SKIPHEADERS-$(CONFIG_DXVA2) += hwcontext_dxva2.h
229SKIPHEADERS-$(CONFIG_AMF) += hwcontext_amf.h \
230 hwcontext_amf_internal
227SKIPHEADERS-$(CONFIG_QSV) += hwcontext_qsv.h231SKIPHEADERS-$(CONFIG_QSV) += hwcontext_qsv.h
228SKIPHEADERS-$(CONFIG_OPENCL) += hwcontext_opencl.h232SKIPHEADERS-$(CONFIG_OPENCL) += hwcontext_opencl.h
229SKIPHEADERS-$(CONFIG_VAAPI) += hwcontext_vaapi.h233SKIPHEADERS-$(CONFIG_VAAPI) += hwcontext_vaapi.h
libavutil/hwcontext.c+4−0
@@ -65,6 +65,9 @@ static const HWContextType * const hw_table[] = { · 64 unmodified lines
65#endif65#endif
66#if CONFIG_VULKAN66#if CONFIG_VULKAN
67 &ff_hwcontext_type_vulkan,67 &ff_hwcontext_type_vulkan,
68#endif
69#if CONFIG_AMF
70 &ff_hwcontext_type_amf,
68#endif71#endif
69 NULL,72 NULL,
70};73};
@@ -82,6 +85,7 @@ static const char *const hw_type_names[] = { · 11 unmodified lines
82 [AV_HWDEVICE_TYPE_VIDEOTOOLBOX] = "videotoolbox",85 [AV_HWDEVICE_TYPE_VIDEOTOOLBOX] = "videotoolbox",
83 [AV_HWDEVICE_TYPE_MEDIACODEC] = "mediacodec",86 [AV_HWDEVICE_TYPE_MEDIACODEC] = "mediacodec",
84 [AV_HWDEVICE_TYPE_VULKAN] = "vulkan",87 [AV_HWDEVICE_TYPE_VULKAN] = "vulkan",
88 [AV_HWDEVICE_TYPE_AMF] = "amf",
85};89};
86 90
87typedef struct FFHWDeviceContext {91typedef struct FFHWDeviceContext {
libavutil/hwcontext.h+1−0
@@ -38,6 +38,7 @@ enum AVHWDeviceType { · 37 unmodified lines
38 AV_HWDEVICE_TYPE_MEDIACODEC,38 AV_HWDEVICE_TYPE_MEDIACODEC,
39 AV_HWDEVICE_TYPE_VULKAN,39 AV_HWDEVICE_TYPE_VULKAN,
40 AV_HWDEVICE_TYPE_D3D12VA,40 AV_HWDEVICE_TYPE_D3D12VA,
41 AV_HWDEVICE_TYPE_AMF,
41};42};
42 43
43/**44/**
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
50typedef struct AmfTraceWriter {
51 AMFTraceWriterVtbl *vtblp;
52 void *avctx;
53 AMFTraceWriterVtbl vtbl;
54} AmfTraceWriter;
55
56static 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
63static void AMF_CDECL_CALL AMFTraceWriter_Flush(AMFTraceWriter *pThis)
64{
65}
66
67static 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
81static 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*/
92typedef struct {
93 void *dummy;
94} AMFFramesContext;
95
96typedef struct AVAMFFormatMap {
97 enum AVPixelFormat av_format;
98 enum AMF_SURFACE_FORMAT amf_format;
99} FormatMap;
100
101const 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
116enum 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
127enum 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
138static 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
152static 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
161static 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
186static void amf_dummy_free(void *opaque, uint8_t *data)
187{
188
189}
190
191static 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
204static 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
226static 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
239static 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
257static 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
265static 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
307static 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
339static 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
367static 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
404static 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
427static 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
492static 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
537static 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
552static 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
591const 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 */
33typedef 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
42enum AMF_SURFACE_FORMAT av_av_to_amf_format(enum AVPixelFormat fmt);
43enum 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
163extern const HWContextType ff_hwcontext_type_videotoolbox;163extern const HWContextType ff_hwcontext_type_videotoolbox;
164extern const HWContextType ff_hwcontext_type_mediacodec;164extern const HWContextType ff_hwcontext_type_mediacodec;
165extern const HWContextType ff_hwcontext_type_vulkan;165extern const HWContextType ff_hwcontext_type_vulkan;
166extern const HWContextType ff_hwcontext_type_amf;
166 167
167#endif /* AVUTIL_HWCONTEXT_INTERNAL_H */168#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
2133 .name = "cuda",2133 .name = "cuda",
2134 .flags = AV_PIX_FMT_FLAG_HWACCEL,2134 .flags = AV_PIX_FMT_FLAG_HWACCEL,
2135 },2135 },
2136 [AV_PIX_FMT_AMF_SURFACE] = {
2137 .name = "amf",
2138 .flags = AV_PIX_FMT_FLAG_HWACCEL,
2139 },
2136 [AV_PIX_FMT_VYU444] = {2140 [AV_PIX_FMT_VYU444] = {
2137 .name = "vyu444",2141 .name = "vyu444",
2138 .nb_components = 3,2142 .nb_components = 3,
libavutil/pixfmt.h+5−0
@@ -471,6 +471,11 @@ enum AVPixelFormat { · 470 unmodified lines
471 AV_PIX_FMT_GRAYF16BE, ///< IEEE-754 half precision Y, 16bpp, big-endian471 AV_PIX_FMT_GRAYF16BE, ///< IEEE-754 half precision Y, 16bpp, big-endian
472 AV_PIX_FMT_GRAYF16LE, ///< IEEE-754 half precision Y, 16bpp, little-endian472 AV_PIX_FMT_GRAYF16LE, ///< IEEE-754 half precision Y, 16bpp, little-endian
473 473
474 /**
475 * HW acceleration through AMF. data[0] contain AMFSurface pointer
476 */
477 AV_PIX_FMT_AMF_SURFACE,
478
474 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 versions479 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
475};480};
476 481

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