FFmpeg
hwcontext_amf.c
Go to the documentation of this file.
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
30 #endif
31 #if CONFIG_D3D12VA
33 #endif
34 #if CONFIG_DXVA2
35 #define COBJMACROS
37 #endif
38 #include "mem.h"
39 #include "pixdesc.h"
40 #include "pixfmt.h"
41 #include "imgutils.h"
42 #include "thread.h"
43 #include "libavutil/avassert.h"
44 #include <AMF/core/Surface.h>
45 #include <AMF/core/Trace.h>
46 #ifdef _WIN32
47 #include "compat/w32dlfcn.h"
48 #else
49 #include <dlfcn.h>
50 #endif
51 #define FFMPEG_AMF_WRITER_ID L"ffmpeg_amf"
52 
53 static void amf_lock_default(void *opaque)
54 {
55  ff_mutex_lock((AVMutex*)opaque);
56 }
57 
58 static void amf_unlock_default(void *opaque)
59 {
60  ff_mutex_unlock((AVMutex*)opaque);
61 }
62 
63 typedef struct AmfTraceWriter {
64  AMFTraceWriterVtbl *vtblp;
65  void *avctx;
66  AMFTraceWriterVtbl vtbl;
68 
69 static void AMF_CDECL_CALL AMFTraceWriter_Write(AMFTraceWriter *pThis,
70  const wchar_t *scope, const wchar_t *message)
71 {
72  AmfTraceWriter *tracer = (AmfTraceWriter*)pThis;
73  av_log(tracer->avctx, AV_LOG_DEBUG, "%ls: %ls", scope, message); // \n is provided from AMF
74 }
75 
76 static void AMF_CDECL_CALL AMFTraceWriter_Flush(AMFTraceWriter *pThis)
77 {
78 }
79 
80 static AmfTraceWriter * amf_writer_alloc(void *avctx)
81 {
82  AmfTraceWriter * writer = av_mallocz(sizeof(AmfTraceWriter));
83  if (!writer)
84  return NULL;
85 
86  writer->vtblp = &writer->vtbl;
87  writer->vtblp->Write = AMFTraceWriter_Write;
88  writer->vtblp->Flush = AMFTraceWriter_Flush;
89  writer->avctx = avctx;
90 
91  return writer;
92 }
93 
94 static void amf_writer_free(void *opaque)
95 {
96  AmfTraceWriter *writer = (AmfTraceWriter *)opaque;
97  av_freep(&writer);
98 }
99 
100 /**
101  * We still need AVHWFramesContext to utilize our hardware memory
102  * otherwise, we will receive the error "HW format requires hw_frames_ctx to be non-NULL".
103  * (libavfilter\buffersrc.c function query_formats)
104 */
105 typedef struct {
106  void *dummy;
108 
109 typedef struct AVAMFFormatMap {
111  enum AMF_SURFACE_FORMAT amf_format;
112 } FormatMap;
113 
114 const FormatMap format_map[] =
115 {
116  { AV_PIX_FMT_NONE, AMF_SURFACE_UNKNOWN },
117  { AV_PIX_FMT_NV12, AMF_SURFACE_NV12 },
118  { AV_PIX_FMT_BGR0, AMF_SURFACE_BGRA },
119  { AV_PIX_FMT_RGB0, AMF_SURFACE_RGBA },
120  { AV_PIX_FMT_BGRA, AMF_SURFACE_BGRA },
121  { AV_PIX_FMT_ARGB, AMF_SURFACE_ARGB },
122  { AV_PIX_FMT_RGBA, AMF_SURFACE_RGBA },
123  { AV_PIX_FMT_GRAY8, AMF_SURFACE_GRAY8 },
124  { AV_PIX_FMT_YUV420P, AMF_SURFACE_YUV420P },
125  { AV_PIX_FMT_YUYV422, AMF_SURFACE_YUY2 },
126  { AV_PIX_FMT_P010, AMF_SURFACE_P010 },
127  { AV_PIX_FMT_X2BGR10, AMF_SURFACE_R10G10B10A2 },
128  { AV_PIX_FMT_RGBAF16, AMF_SURFACE_RGBA_F16},
129 };
130 
131 enum AMF_SURFACE_FORMAT av_av_to_amf_format(enum AVPixelFormat fmt)
132 {
133  int i;
134  for (i = 0; i < amf_countof(format_map); i++) {
135  if (format_map[i].av_format == fmt) {
136  return format_map[i].amf_format;
137  }
138  }
139  return AMF_SURFACE_UNKNOWN;
140 }
141 
142 enum AVPixelFormat av_amf_to_av_format(enum AMF_SURFACE_FORMAT fmt)
143 {
144  int i;
145  for (i = 0; i < amf_countof(format_map); i++) {
146  if (format_map[i].amf_format == fmt) {
147  return format_map[i].av_format;
148  }
149  }
150  return AV_PIX_FMT_NONE;
151 }
152 
153 static const enum AVPixelFormat supported_formats[] = {
160 #if CONFIG_D3D11VA
162 #endif
163 #if CONFIG_D3D12VA
165 #endif
166 #if CONFIG_DXVA2
168 #endif
169 };
170 
178 };
179 
181  const void *hwconfig,
182  AVHWFramesConstraints *constraints)
183 {
184  int i;
185 
187  sizeof(*constraints->valid_sw_formats));
188  if (!constraints->valid_sw_formats)
189  return AVERROR(ENOMEM);
190 
191  for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++)
192  constraints->valid_sw_formats[i] = supported_formats[i];
194 
195  constraints->valid_hw_formats = av_malloc_array(2, sizeof(*constraints->valid_hw_formats));
196  if (!constraints->valid_hw_formats)
197  return AVERROR(ENOMEM);
198 
199  constraints->valid_hw_formats[0] = AV_PIX_FMT_AMF_SURFACE;
200  constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
201 
202  return 0;
203 }
204 
205 static void amf_dummy_free(void *opaque, uint8_t *data)
206 {
207 
208 }
209 
210 static AVBufferRef *amf_pool_alloc(void *opaque, size_t size)
211 {
212  AVHWFramesContext *hwfc = (AVHWFramesContext *)opaque;
213  AVBufferRef *buf;
214 
216  if (!buf) {
217  av_log(hwfc, AV_LOG_ERROR, "Failed to create buffer for AMF context.\n");
218  return NULL;
219  }
220  return buf;
221 }
222 
224 {
225  int i;
226 
227  for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) {
228  if (ctx->sw_format == supported_formats[i])
229  break;
230  }
232  av_log(ctx, AV_LOG_ERROR, "Pixel format '%s' is not supported\n",
233  av_get_pix_fmt_name(ctx->sw_format));
234  return AVERROR(ENOSYS);
235  }
236 
238  av_buffer_pool_init2(sizeof(AMFSurface), ctx,
239  &amf_pool_alloc, NULL);
240 
241  return 0;
242 }
243 
244 
246 {
247  frame->buf[0] = av_buffer_pool_get(ctx->pool);
248  if (!frame->buf[0])
249  return AVERROR(ENOMEM);
250 
251  frame->data[0] = frame->buf[0]->data;
252  frame->format = AV_PIX_FMT_AMF_SURFACE;
253  frame->width = ctx->width;
254  frame->height = ctx->height;
255  return 0;
256 }
257 
260  enum AVPixelFormat **formats)
261 {
262  enum AVPixelFormat *fmts;
263  int i;
264 
266  if (!fmts)
267  return AVERROR(ENOMEM);
269  fmts[i] = supported_transfer_formats[i];
270 
271  *formats = fmts;
272 
273  return 0;
274 }
275 
276 static void amf_free_amfsurface(void *opaque, uint8_t *data)
277 {
278  if(!!data){
279  AMFSurface *surface = (AMFSurface*)(data);
280  surface->pVtbl->Release(surface);
281  }
282 }
283 
285  const AVFrame *src)
286 {
287  AMFSurface* surface = (AMFSurface*)dst->data[0];
288  AMFPlane *plane;
289  uint8_t *dst_data[4];
290  int dst_linesize[4];
291  int planes;
292  int i;
293  int res;
294  int w = FFMIN(dst->width, src->width);
295  int h = FFMIN(dst->height, src->height);
296 
297  if (dst->hw_frames_ctx->data != (uint8_t *)ctx || src->format != ctx->sw_format)
298  return AVERROR(EINVAL);
299 
300  if (!surface) {
301  AVHWDeviceContext *hwdev_ctx = ctx->device_ctx;
302  AVAMFDeviceContext *amf_device_ctx = (AVAMFDeviceContext *)hwdev_ctx->hwctx;
303  AMF_SURFACE_FORMAT format = av_av_to_amf_format(ctx->sw_format);
304  res = amf_device_ctx->context->pVtbl->AllocSurface(amf_device_ctx->context, AMF_MEMORY_HOST, format, dst->width, dst->height, &surface);
305  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "AllocSurface() failed with error %d\n", res);
306  dst->data[0] = (uint8_t *)surface;
307  dst->buf[1] = av_buffer_create((uint8_t *)surface, sizeof(surface),
309  NULL,
311  AMF_RETURN_IF_FALSE(ctx, !!dst->buf[1], AVERROR(ENOMEM), "av_buffer_create for amf surface failed.");
312  }
313 
314  planes = (int)surface->pVtbl->GetPlanesCount(surface);
315  av_assert0(planes < FF_ARRAY_ELEMS(dst_data));
316 
317  for (i = 0; i < planes; i++) {
318  plane = surface->pVtbl->GetPlaneAt(surface, i);
319  dst_data[i] = plane->pVtbl->GetNative(plane);
320  dst_linesize[i] = plane->pVtbl->GetHPitch(plane);
321  }
322  av_image_copy2(dst_data, dst_linesize,
323  src->data, src->linesize, src->format,
324  w, h);
325 
326  return 0;
327 }
328 
330  const AVFrame *src)
331 {
332  AMFSurface* surface = (AMFSurface*)src->data[0];
333  AMFPlane *plane;
334  uint8_t *src_data[4];
335  int src_linesize[4];
336  int planes;
337  int i;
338  int w = FFMIN(dst->width, src->width);
339  int h = FFMIN(dst->height, src->height);
340  int ret;
341 
342  if (src->hw_frames_ctx->data != (uint8_t *)ctx || dst->format != ctx->sw_format)
343  return AVERROR(EINVAL);
344 
345  ret = surface->pVtbl->Convert(surface, AMF_MEMORY_HOST);
346  AMF_RETURN_IF_FALSE(ctx, ret == AMF_OK, AVERROR_UNKNOWN, "Convert(amf::AMF_MEMORY_HOST) failed with error %d\n", AVERROR_UNKNOWN);
347 
348  planes = (int)surface->pVtbl->GetPlanesCount(surface);
349  av_assert0(planes < FF_ARRAY_ELEMS(src_data));
350 
351  for (i = 0; i < planes; i++) {
352  plane = surface->pVtbl->GetPlaneAt(surface, i);
353  src_data[i] = plane->pVtbl->GetNative(plane);
354  src_linesize[i] = plane->pVtbl->GetHPitch(plane);
355  }
356  av_image_copy2(dst->data, dst->linesize,
357  src_data, src_linesize, dst->format,
358  w, h);
359  return 0;
360 }
361 
362 
363 
364 static void amf_device_uninit(AVHWDeviceContext *device_ctx)
365 {
366  AVAMFDeviceContext *amf_ctx = device_ctx->hwctx;
367  AMF_RESULT res = AMF_NOT_INITIALIZED;
368  AMFTrace *trace;
369 
370  if (amf_ctx->context) {
371  amf_ctx->context->pVtbl->Terminate(amf_ctx->context);
372  amf_ctx->context->pVtbl->Release(amf_ctx->context);
373  amf_ctx->context = NULL;
374  }
375 
376  if (amf_ctx->factory)
377  res = amf_ctx->factory->pVtbl->GetTrace(amf_ctx->factory, &trace);
378 
379  if (res == AMF_OK) {
380  trace->pVtbl->UnregisterWriter(trace, FFMPEG_AMF_WRITER_ID);
381  }
382 
383  if(amf_ctx->library) {
384  dlclose(amf_ctx->library);
385  amf_ctx->library = NULL;
386  }
387  if (amf_ctx->trace_writer) {
388  amf_writer_free(amf_ctx->trace_writer);
389  }
390 
391  if (amf_ctx->lock_ctx == amf_lock_default) {
392  ff_mutex_destroy((AVMutex*)amf_ctx->lock_ctx);
393  av_freep(&amf_ctx->lock_ctx);
394  amf_ctx->lock = NULL;
395  amf_ctx->unlock = NULL;
396  }
397 
398  amf_ctx->version = 0;
399 }
400 
402 {
403  AVAMFDeviceContext *amf_ctx = ctx->hwctx;
404  AMFContext1 *context1 = NULL;
405  AMF_RESULT res;
406 
407  if (!amf_ctx->lock) {
408  amf_ctx->lock_ctx = av_mallocz(sizeof(AVMutex));
409  if (!amf_ctx->lock_ctx) {
410  return AVERROR(ENOMEM);
411  }
412  ff_mutex_init((AVMutex*)amf_ctx->lock_ctx, NULL);
413  amf_ctx->lock = amf_lock_default;
414  amf_ctx->unlock = amf_unlock_default;
415  }
416 
417 #ifdef _WIN32
418  res = amf_ctx->context->pVtbl->InitDX11(amf_ctx->context, NULL, AMF_DX11_1);
419  if (res == AMF_OK || res == AMF_ALREADY_INITIALIZED) {
420  av_log(ctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D11.\n");
421  } else {
422  res = amf_ctx->context->pVtbl->InitDX9(amf_ctx->context, NULL);
423  if (res == AMF_OK) {
424  av_log(ctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D9.\n");
425  } else {
426 #endif
427  AMFGuid guid = IID_AMFContext1();
428  res = amf_ctx->context->pVtbl->QueryInterface(amf_ctx->context, &guid, (void**)&context1);
429  AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext1() failed with error %d\n", res);
430 
431  res = context1->pVtbl->InitVulkan(context1, NULL);
432  context1->pVtbl->Release(context1);
433  if (res != AMF_OK && res != AMF_ALREADY_INITIALIZED) {
434  if (res == AMF_NOT_SUPPORTED)
435  av_log(ctx, AV_LOG_ERROR, "AMF via Vulkan is not supported on the given device.\n");
436  else
437  av_log(ctx, AV_LOG_ERROR, "AMF failed to initialise on the given Vulkan device: %d.\n", res);
438  return AVERROR(ENOSYS);
439  }
440  av_log(ctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via Vulkan.\n");
441 #ifdef _WIN32
442  }
443  }
444 #endif
445 
446  return 0;
447 }
448 
449 static int amf_load_library(AVAMFDeviceContext* amf_ctx, void* avcl)
450 {
451  AMFInit_Fn init_fun;
452  AMFQueryVersion_Fn version_fun;
453  AMF_RESULT res;
454 
455  amf_ctx->library = dlopen(AMF_DLL_NAMEA, RTLD_NOW | RTLD_LOCAL);
456  AMF_RETURN_IF_FALSE(avcl, amf_ctx->library != NULL,
457  AVERROR_UNKNOWN, "DLL %s failed to open\n", AMF_DLL_NAMEA);
458 
459  init_fun = (AMFInit_Fn)dlsym(amf_ctx->library, AMF_INIT_FUNCTION_NAME);
460  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);
461 
462  version_fun = (AMFQueryVersion_Fn)dlsym(amf_ctx->library, AMF_QUERY_VERSION_FUNCTION_NAME);
463  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);
464 
465  res = version_fun(&amf_ctx->version);
466  AMF_RETURN_IF_FALSE(avcl, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_QUERY_VERSION_FUNCTION_NAME, res);
467  res = init_fun(AMF_FULL_VERSION, &amf_ctx->factory);
468  AMF_RETURN_IF_FALSE(avcl, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_INIT_FUNCTION_NAME, res);
469  return 0;
470 }
471 
472 static int amf_device_create(AVHWDeviceContext *device_ctx,
473  const char *device,
474  AVDictionary *opts, int flags)
475 {
476  AVAMFDeviceContext *ctx = device_ctx->hwctx;
477  AMFTrace *trace;
478  int ret;
479  if ((ret = amf_load_library(ctx, device_ctx)) == 0) {
480  ret = ctx->factory->pVtbl->GetTrace(ctx->factory, &trace);
481  if (ret == AMF_OK) {
482  int level_ff = av_log_get_level();
483  int level_amf = AMF_TRACE_TRACE;
484  amf_bool enable_log = true;
485  switch(level_ff)
486  {
487  case AV_LOG_QUIET:
488  level_amf = AMF_TRACE_ERROR;
489  enable_log = false;
490  break;
491  case AV_LOG_PANIC:
492  case AV_LOG_FATAL:
493  case AV_LOG_ERROR:
494  level_amf = AMF_TRACE_ERROR;
495  break;
496  case AV_LOG_WARNING:
497  case AV_LOG_INFO:
498  level_amf = AMF_TRACE_WARNING;
499  break;
500  case AV_LOG_VERBOSE:
501  level_amf = AMF_TRACE_INFO;
502  break;
503  case AV_LOG_DEBUG:
504  level_amf = AMF_TRACE_DEBUG;
505  break;
506  case AV_LOG_TRACE:
507  level_amf = AMF_TRACE_TRACE;
508  break;
509  }
510  if(ctx->version == AMF_MAKE_FULL_VERSION(1, 4, 35, 0)){// get around a bug in trace in AMF runtime driver 24.20
511  level_amf = AMF_TRACE_WARNING;
512  }
513 
514  trace->pVtbl->EnableWriter(trace, AMF_TRACE_WRITER_CONSOLE, 0);
515  trace->pVtbl->SetGlobalLevel(trace, level_amf);
516 
517  // connect AMF logger to av_log
518  ctx->trace_writer = amf_writer_alloc(device_ctx);
519  trace->pVtbl->RegisterWriter(trace, FFMPEG_AMF_WRITER_ID, (AMFTraceWriter*)ctx->trace_writer, 1);
520  trace->pVtbl->SetWriterLevel(trace, FFMPEG_AMF_WRITER_ID, level_amf);
521  trace->pVtbl->EnableWriter(trace, FFMPEG_AMF_WRITER_ID, enable_log);
522  trace->pVtbl->SetWriterLevel(trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, level_amf);
523  trace->pVtbl->EnableWriter(trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, enable_log);
524  }
525 
526 
527  ret = ctx->factory->pVtbl->CreateContext(ctx->factory, &ctx->context);
528  if (ret == AMF_OK) {
529  AMF_ASSIGN_PROPERTY_INT64(ret, ctx->context, L"DeviceSurfaceCacheSize", 50 );
530  return 0;
531  }
532  av_log(device_ctx, AV_LOG_ERROR, "CreateContext() failed with error %d.\n", ret);
533  }
534  amf_device_uninit(device_ctx);
535  return ret;
536 }
537 
538 #if CONFIG_DXVA2
539 static int amf_init_from_dxva2_device(AVAMFDeviceContext * amf_ctx, AVHWDeviceContext *child_device_ctx)
540 {
541  AVDXVA2DeviceContext *hwctx = child_device_ctx->hwctx;
542  IDirect3DDevice9 *device;
543  HANDLE device_handle;
544  HRESULT hr;
545  AMF_RESULT res;
546  int ret;
547 
548  hr = IDirect3DDeviceManager9_OpenDeviceHandle(hwctx->devmgr, &device_handle);
549  if (FAILED(hr)) {
550  av_log(child_device_ctx, AV_LOG_ERROR, "Failed to open device handle for Direct3D9 device: %lx.\n", (unsigned long)hr);
551  return AVERROR_EXTERNAL;
552  }
553 
554  hr = IDirect3DDeviceManager9_LockDevice(hwctx->devmgr, device_handle, &device, FALSE);
555  if (SUCCEEDED(hr)) {
556  IDirect3DDeviceManager9_UnlockDevice(hwctx->devmgr, device_handle, FALSE);
557  ret = 0;
558  } else {
559  av_log(child_device_ctx, AV_LOG_ERROR, "Failed to lock device handle for Direct3D9 device: %lx.\n", (unsigned long)hr);
561  }
562 
563 
564  IDirect3DDeviceManager9_CloseDeviceHandle(hwctx->devmgr, device_handle);
565 
566  if (ret < 0)
567  return ret;
568 
569  res = amf_ctx->context->pVtbl->InitDX9(amf_ctx->context, device);
570 
571  IDirect3DDevice9_Release(device);
572 
573  if (res != AMF_OK && res != AMF_ALREADY_INITIALIZED) {
574  if (res == AMF_NOT_SUPPORTED)
575  av_log(child_device_ctx, AV_LOG_ERROR, "AMF via D3D9 is not supported on the given device.\n");
576  else
577  av_log(child_device_ctx, AV_LOG_ERROR, "AMF failed to initialise on given D3D9 device: %d.\n", res);
578  return AVERROR(ENODEV);
579  }
580  av_log(child_device_ctx, AV_LOG_INFO, "AMF via DXVA2.\n");
581  return 0;
582 }
583 #endif
584 
585 #if CONFIG_D3D11VA
586 static int amf_init_from_d3d11_device(AVAMFDeviceContext* amf_ctx, AVHWDeviceContext *child_device_ctx)
587 {
588  AMF_RESULT res;
589  AVD3D11VADeviceContext *hwctx = child_device_ctx->hwctx;
590  res = amf_ctx->context->pVtbl->InitDX11(amf_ctx->context, hwctx->device, AMF_DX11_1);
591  if (res != AMF_OK && res != AMF_ALREADY_INITIALIZED) {
592  if (res == AMF_NOT_SUPPORTED)
593  av_log(child_device_ctx, AV_LOG_ERROR, "AMF via D3D11 is not supported on the given device.\n");
594  else
595  av_log(child_device_ctx, AV_LOG_ERROR, "AMF failed to initialise on the given D3D11 device: %d.\n", res);
596  return AVERROR(ENODEV);
597  }
598  av_log(child_device_ctx, AV_LOG_INFO, "AMF via D3D11.\n");
599  return 0;
600 }
601 #endif
602 
603 #if CONFIG_D3D12VA
604 static int amf_init_from_d3d12_device(AVAMFDeviceContext* amf_ctx, AVHWDeviceContext *child_device_ctx)
605 {
606  AVD3D12VADeviceContext *hwctx = child_device_ctx->hwctx;
607  AMF_RESULT res;
608  AMFContext2 *context2 = NULL;
609  AMFGuid guid = IID_AMFContext2();
610  res = amf_ctx->context->pVtbl->QueryInterface(amf_ctx->context, &guid, (void**)&context2);
611  AMF_RETURN_IF_FALSE(child_device_ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext2() failed with error %d\n", res);
612  res = context2->pVtbl->InitDX12(context2, hwctx->device, AMF_DX12);
613  context2->pVtbl->Release(context2);
614  if (res != AMF_OK && res != AMF_ALREADY_INITIALIZED) {
615  if (res == AMF_NOT_SUPPORTED)
616  av_log(child_device_ctx, AV_LOG_ERROR, "AMF via D3D12 is not supported on the given device.\n");
617  else
618  av_log(child_device_ctx, AV_LOG_ERROR, "AMF failed to initialise on the given D3D12 device: %d.\n", res);
619  return AVERROR(ENODEV);
620  }
621  av_log(child_device_ctx, AV_LOG_INFO, "AMF via D3D12.\n");
622  return 0;
623 }
624 #endif
625 
626 
627 static int amf_device_derive(AVHWDeviceContext *device_ctx,
628  AVHWDeviceContext *child_device_ctx, AVDictionary *opts,
629  int flags)
630 {
631 #if CONFIG_DXVA2 || CONFIG_D3D11VA
632  AVAMFDeviceContext *amf_ctx = device_ctx->hwctx;
633 #endif
634  int ret;
635 
636  ret = amf_device_create(device_ctx, "", opts, flags);
637  if(ret < 0)
638  return ret;
639 
640  switch (child_device_ctx->type) {
641 
642 #if CONFIG_DXVA2
643  case AV_HWDEVICE_TYPE_DXVA2: {
644  return amf_init_from_dxva2_device(amf_ctx, child_device_ctx);
645  }
646  break;
647 #endif
648 
649 #if CONFIG_D3D11VA
651  return amf_init_from_d3d11_device(amf_ctx, child_device_ctx);
652  }
653  break;
654 #endif
655 #if CONFIG_D3D12VA
657  return amf_init_from_d3d12_device(amf_ctx, child_device_ctx);
658  }
659  break;
660 #endif
661  default: {
662  av_log(child_device_ctx, AV_LOG_ERROR, "AMF initialisation from a %s device is not supported.\n",
663  av_hwdevice_get_type_name(child_device_ctx->type));
664  return AVERROR(ENOSYS);
665  }
666  }
667  return 0;
668 }
669 
672  .name = "AMF",
673 
674  .device_hwctx_size = sizeof(AVAMFDeviceContext),
675  .frames_hwctx_size = sizeof(AMFFramesContext),
676 
677  .device_create = amf_device_create,
678  .device_derive = amf_device_derive,
679  .device_init = amf_device_init,
680  .device_uninit = amf_device_uninit,
681  .frames_get_constraints = amf_frames_get_constraints,
682  .frames_init = amf_frames_init,
683  .frames_get_buffer = amf_get_buffer,
684  .transfer_get_formats = amf_transfer_get_formats,
685  .transfer_data_to = amf_transfer_data_to,
686  .transfer_data_from = amf_transfer_data_from,
687 
688  .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_AMF_SURFACE, AV_PIX_FMT_NONE },
689 };
flags
const SwsFlags flags[]
Definition: swscale.c:61
formats
formats
Definition: signature.h:47
AMFFramesContext::dummy
void * dummy
Definition: hwcontext_amf.c:106
AVHWDeviceContext::hwctx
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:88
FFHWFramesContext::pool_internal
AVBufferPool * pool_internal
Definition: hwcontext_internal.h:101
AVD3D12VADeviceContext::device
ID3D12Device * device
Device used for objects creation and access.
Definition: hwcontext_d3d12va.h:54
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:71
ff_mutex_init
static int ff_mutex_init(AVMutex *mutex, const void *attr)
Definition: thread.h:187
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
message
Definition: api-threadmessage-test.c:47
AV_LOG_QUIET
#define AV_LOG_QUIET
Print no output.
Definition: log.h:192
thread.h
AV_LOG_PANIC
#define AV_LOG_PANIC
Something went really wrong and we will crash now.
Definition: log.h:197
amf_writer_alloc
static AmfTraceWriter * amf_writer_alloc(void *avctx)
Definition: hwcontext_amf.c:80
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:427
pixdesc.h
amf_dummy_free
static void amf_dummy_free(void *opaque, uint8_t *data)
Definition: hwcontext_amf.c:205
AVAMFDeviceContext::lock
void(* lock)(void *lock_ctx)
Definition: hwcontext_amf.h:42
data
const char data[16]
Definition: mxf.c:149
amf_device_create
static int amf_device_create(AVHWDeviceContext *device_ctx, const char *device, AVDictionary *opts, int flags)
Definition: hwcontext_amf.c:472
AVDXVA2DeviceContext::devmgr
IDirect3DDeviceManager9 * devmgr
Definition: hwcontext_dxva2.h:40
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:226
AMFTraceWriter_Write
static void AMF_CDECL_CALL AMFTraceWriter_Write(AMFTraceWriter *pThis, const wchar_t *scope, const wchar_t *message)
Definition: hwcontext_amf.c:69
AV_PIX_FMT_BGRA
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:102
AVDictionary
Definition: dict.c:32
AMF_RETURN_IF_FALSE
#define AMF_RETURN_IF_FALSE(avctx, exp, ret_value,...)
Error handling helper.
Definition: amfenc.h:169
AVHWFramesConstraints::valid_hw_formats
enum AVPixelFormat * valid_hw_formats
A list of possible values for format in the hw_frames_ctx, terminated by AV_PIX_FMT_NONE.
Definition: hwcontext.h:449
AVERROR_UNKNOWN
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:73
AVAMFFormatMap
Definition: hwcontext_amf.c:109
AV_PIX_FMT_AMF_SURFACE
@ AV_PIX_FMT_AMF_SURFACE
HW acceleration through AMF.
Definition: pixfmt.h:477
AVHWFramesConstraints
This struct describes the constraints on hardware frames attached to a given device with a hardware-s...
Definition: hwcontext.h:444
ff_mutex_unlock
static int ff_mutex_unlock(AVMutex *mutex)
Definition: thread.h:189
AVAMFDeviceContext::lock_ctx
void * lock_ctx
Definition: hwcontext_amf.h:44
av_amf_to_av_format
enum AVPixelFormat av_amf_to_av_format(enum AMF_SURFACE_FORMAT fmt)
Definition: hwcontext_amf.c:142
AV_HWDEVICE_TYPE_D3D11VA
@ AV_HWDEVICE_TYPE_D3D11VA
Definition: hwcontext.h:35
av_buffer_pool_init2
AVBufferPool * av_buffer_pool_init2(size_t size, void *opaque, AVBufferRef *(*alloc)(void *opaque, size_t size), void(*pool_free)(void *opaque))
Allocate and initialize a buffer pool with a more complex allocator.
Definition: buffer.c:259
av_av_to_amf_format
enum AMF_SURFACE_FORMAT av_av_to_amf_format(enum AVPixelFormat fmt)
Definition: hwcontext_amf.c:131
AVAMFDeviceContext::context
AMFContext * context
Definition: hwcontext_amf.h:39
AVHWDeviceContext
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:63
amf_transfer_get_formats
static int amf_transfer_get_formats(AVHWFramesContext *ctx, enum AVHWFrameTransferDirection dir, enum AVPixelFormat **formats)
Definition: hwcontext_amf.c:258
avassert.h
HWContextType::type
enum AVHWDeviceType type
Definition: hwcontext_internal.h:30
ffhwframesctx
static FFHWFramesContext * ffhwframesctx(AVHWFramesContext *ctx)
Definition: hwcontext_internal.h:115
AV_LOG_TRACE
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:236
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
AVHWFramesConstraints::valid_sw_formats
enum AVPixelFormat * valid_sw_formats
A list of possible values for sw_format in the hw_frames_ctx, terminated by AV_PIX_FMT_NONE.
Definition: hwcontext.h:456
AVMutex
#define AVMutex
Definition: thread.h:184
av_buffer_pool_get
AVBufferRef * av_buffer_pool_get(AVBufferPool *pool)
Allocate a new AVBuffer, reusing an old buffer from the pool when available.
Definition: buffer.c:390
AVAMFFormatMap::av_format
enum AVPixelFormat av_format
Definition: hwcontext_amf.c:110
AV_PIX_FMT_DXVA2_VLD
@ AV_PIX_FMT_DXVA2_VLD
HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer.
Definition: pixfmt.h:134
amf_frames_get_constraints
static int amf_frames_get_constraints(AVHWDeviceContext *ctx, const void *hwconfig, AVHWFramesConstraints *constraints)
Definition: hwcontext_amf.c:180
AVD3D11VADeviceContext::device
ID3D11Device * device
Device used for texture creation and access.
Definition: hwcontext_d3d11va.h:56
AV_BUFFER_FLAG_READONLY
#define AV_BUFFER_FLAG_READONLY
Always treat the buffer as read-only, even when it has only one reference.
Definition: buffer.h:114
AmfTraceWriter::vtblp
AMFTraceWriterVtbl * vtblp
Definition: hwcontext_amf.c:64
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:41
amf_device_init
static int amf_device_init(AVHWDeviceContext *ctx)
Definition: hwcontext_amf.c:401
AV_HWDEVICE_TYPE_AMF
@ AV_HWDEVICE_TYPE_AMF
Definition: hwcontext.h:41
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:231
amf_transfer_data_to
static int amf_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src)
Definition: hwcontext_amf.c:284
ctx
AVFormatContext * ctx
Definition: movenc.c:49
FFMPEG_AMF_WRITER_ID
#define FFMPEG_AMF_WRITER_ID
Definition: hwcontext_amf.c:51
hwcontext_amf.h
AVAMFDeviceContext::version
int64_t version
version of AMF runtime
Definition: hwcontext_amf.h:38
amf_writer_free
static void amf_writer_free(void *opaque)
Definition: hwcontext_amf.c:94
av_hwdevice_get_type_name
const char * av_hwdevice_get_type_name(enum AVHWDeviceType type)
Get the string name of an AVHWDeviceType.
Definition: hwcontext.c:120
AV_PIX_FMT_YUV420P
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:73
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:100
av_log_get_level
int av_log_get_level(void)
Get the current log level.
Definition: log.c:472
opts
AVDictionary * opts
Definition: movenc.c:51
NULL
#define NULL
Definition: coverity.c:32
amf_pool_alloc
static AVBufferRef * amf_pool_alloc(void *opaque, size_t size)
Definition: hwcontext_amf.c:210
format
New swscale design to change SwsGraph is what coordinates multiple passes These can include cascaded scaling error diffusion and so on Or we could have separate passes for the vertical and horizontal scaling In between each SwsPass lies a fully allocated image buffer Graph passes may have different levels of e g we can have a single threaded error diffusion pass following a multi threaded scaling pass SwsGraph is internally recreated whenever the image format
Definition: swscale-v2.txt:14
AV_HWDEVICE_TYPE_DXVA2
@ AV_HWDEVICE_TYPE_DXVA2
Definition: hwcontext.h:32
AV_PIX_FMT_YUYV422
@ AV_PIX_FMT_YUYV422
packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
Definition: pixfmt.h:74
hwcontext_vulkan.h
AV_PIX_FMT_BGR0
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:265
AV_PIX_FMT_D3D12
@ AV_PIX_FMT_D3D12
Hardware surfaces for Direct3D 12.
Definition: pixfmt.h:440
AV_PIX_FMT_GRAY8
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition: pixfmt.h:81
AVAMFDeviceContext::trace_writer
void * trace_writer
Definition: hwcontext_amf.h:36
hwcontext_d3d12va.h
amf_get_buffer
static int amf_get_buffer(AVHWFramesContext *ctx, AVFrame *frame)
Definition: hwcontext_amf.c:245
AVAMFDeviceContext::library
void * library
Definition: hwcontext_amf.h:34
av_buffer_create
AVBufferRef * av_buffer_create(uint8_t *data, size_t size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:55
AmfTraceWriter
Definition: hwcontext_amf.c:63
ff_mutex_destroy
static int ff_mutex_destroy(AVMutex *mutex)
Definition: thread.h:190
AV_PIX_FMT_X2BGR10
#define AV_PIX_FMT_X2BGR10
Definition: pixfmt.h:614
hwcontext_dxva2.h
AV_HWDEVICE_TYPE_D3D12VA
@ AV_HWDEVICE_TYPE_D3D12VA
Definition: hwcontext.h:40
amf_free_amfsurface
static void amf_free_amfsurface(void *opaque, uint8_t *data)
Definition: hwcontext_amf.c:276
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:87
size
int size
Definition: twinvq_data.h:10344
AVAMFDeviceContext
This struct is allocated as AVHWDeviceContext.hwctx.
Definition: hwcontext_amf.h:33
amf_lock_default
static void amf_lock_default(void *opaque)
Definition: hwcontext_amf.c:53
ff_hwcontext_type_amf
const HWContextType ff_hwcontext_type_amf
Definition: hwcontext_amf.c:670
amf_device_uninit
static void amf_device_uninit(AVHWDeviceContext *device_ctx)
Definition: hwcontext_amf.c:364
AMFFramesContext
We still need AVHWFramesContext to utilize our hardware memory otherwise, we will receive the error "...
Definition: hwcontext_amf.c:105
buffer.h
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:59
ff_mutex_lock
static int ff_mutex_lock(AVMutex *mutex)
Definition: thread.h:188
AV_PIX_FMT_RGB0
@ AV_PIX_FMT_RGB0
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition: pixfmt.h:263
AV_PIX_FMT_D3D11
@ AV_PIX_FMT_D3D11
Hardware surfaces for Direct3D11.
Definition: pixfmt.h:336
amf_frames_init
static int amf_frames_init(AVHWFramesContext *ctx)
Definition: hwcontext_amf.c:223
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:221
AV_PIX_FMT_ARGB
@ AV_PIX_FMT_ARGB
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Definition: pixfmt.h:99
AVAMFFormatMap::amf_format
enum AMF_SURFACE_FORMAT amf_format
Definition: hwcontext_amf.c:111
AVD3D12VADeviceContext
This struct is allocated as AVHWDeviceContext.hwctx.
Definition: hwcontext_d3d12va.h:43
AVAMFDeviceContext::factory
AMFFactory * factory
Definition: hwcontext_amf.h:35
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
AVDXVA2DeviceContext
This struct is allocated as AVHWDeviceContext.hwctx.
Definition: hwcontext_dxva2.h:39
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:32
common.h
AVD3D11VADeviceContext
This struct is allocated as AVHWDeviceContext.hwctx.
Definition: hwcontext_d3d11va.h:45
amf_transfer_data_from
static int amf_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src)
Definition: hwcontext_amf.c:329
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
amf_device_derive
static int amf_device_derive(AVHWDeviceContext *device_ctx, AVHWDeviceContext *child_device_ctx, AVDictionary *opts, int flags)
Definition: hwcontext_amf.c:627
AVHWFrameTransferDirection
AVHWFrameTransferDirection
Definition: hwcontext.h:406
AVHWFramesContext
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:118
ret
ret
Definition: filter_design.txt:187
AV_LOG_FATAL
#define AV_LOG_FATAL
Something went wrong and recovery is not possible.
Definition: log.h:204
AVHWDeviceContext::type
enum AVHWDeviceType type
This field identifies the underlying API used for hardware access.
Definition: hwcontext.h:75
pixfmt.h
AV_PIX_FMT_NV12
@ AV_PIX_FMT_NV12
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition: pixfmt.h:96
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:265
supported_formats
static enum AVPixelFormat supported_formats[]
Definition: hwcontext_amf.c:153
hwcontext_amf_internal.h
planes
static const struct @549 planes[]
amf_unlock_default
static void amf_unlock_default(void *opaque)
Definition: hwcontext_amf.c:58
AVAMFDeviceContext::unlock
void(* unlock)(void *lock_ctx)
Definition: hwcontext_amf.h:43
amf_load_library
static int amf_load_library(AVAMFDeviceContext *amf_ctx, void *avcl)
Definition: hwcontext_amf.c:449
av_image_copy2
static void av_image_copy2(uint8_t *const dst_data[4], const int dst_linesizes[4], uint8_t *const src_data[4], const int src_linesizes[4], enum AVPixelFormat pix_fmt, int width, int height)
Wrapper around av_image_copy() to workaround the limitation that the conversion from uint8_t * const ...
Definition: imgutils.h:184
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:72
format_map
const FormatMap format_map[]
Definition: hwcontext_amf.c:114
AmfTraceWriter::avctx
void * avctx
Definition: hwcontext_amf.c:65
L
#define L(x)
Definition: vpx_arith.h:36
AV_PIX_FMT_P010
#define AV_PIX_FMT_P010
Definition: pixfmt.h:602
mem.h
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
AmfTraceWriter::vtbl
AMFTraceWriterVtbl vtbl
Definition: hwcontext_amf.c:66
w
uint8_t w
Definition: llvidencdsp.c:39
hwcontext_internal.h
AMFTraceWriter_Flush
static void AMF_CDECL_CALL AMFTraceWriter_Flush(AMFTraceWriter *pThis)
Definition: hwcontext_amf.c:76
AV_PIX_FMT_RGBAF16
#define AV_PIX_FMT_RGBAF16
Definition: pixfmt.h:624
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
imgutils.h
hwcontext.h
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
HWContextType
Definition: hwcontext_internal.h:29
h
h
Definition: vp9dsp_template.c:2070
hwcontext_d3d11va.h
src
#define src
Definition: vp8dsp.c:248
supported_transfer_formats
static enum AVPixelFormat supported_transfer_formats[]
Definition: hwcontext_amf.c:171
w32dlfcn.h
av_get_pix_fmt_name
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
Definition: pixdesc.c:3376