hwcontext_amf.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  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. #include "buffer.h"
  19. #include "common.h"
  20. #include "hwcontext.h"
  21. #include "hwcontext_amf.h"
  22. #include "hwcontext_internal.h"
  23. #include "hwcontext_amf_internal.h"
  24. #if CONFIG_VULKAN
  25. #include "hwcontext_vulkan.h"
  26. #endif
  27. #if CONFIG_D3D11VA
  28. #include "libavutil/hwcontext_d3d11va.h"
  29. #endif
  30. #if CONFIG_D3D12VA
  31. #include "libavutil/hwcontext_d3d12va.h"
  32. #endif
  33. #if CONFIG_DXVA2
  34. #define COBJMACROS
  35. #include "libavutil/hwcontext_dxva2.h"
  36. #endif
  37. #include "mem.h"
  38. #include "pixdesc.h"
  39. #include "pixfmt.h"
  40. #include "imgutils.h"
  41. #include "libavutil/avassert.h"
  42. #include <AMF/core/Surface.h>
  43. #include <AMF/core/Trace.h>
  44. #ifdef _WIN32
  45. #include "compat/w32dlfcn.h"
  46. #else
  47. #include <dlfcn.h>
  48. #endif
  49. #define FFMPEG_AMF_WRITER_ID L"ffmpeg_amf"
  50. typedef struct AmfTraceWriter {
  51. AMFTraceWriterVtbl *vtblp;
  52. void *avctx;
  53. AMFTraceWriterVtbl vtbl;
  54. } AmfTraceWriter;
  55. static void AMF_CDECL_CALL AMFTraceWriter_Write(AMFTraceWriter *pThis,
  56. const wchar_t *scope, const wchar_t *message)
  57. {
  58. AmfTraceWriter *tracer = (AmfTraceWriter*)pThis;
  59. av_log(tracer->avctx, AV_LOG_DEBUG, "%ls: %ls", scope, message); // \n is provided from AMF
  60. }
  61. static void AMF_CDECL_CALL AMFTraceWriter_Flush(AMFTraceWriter *pThis)
  62. {
  63. }
  64. static AmfTraceWriter * amf_writer_alloc(void *avctx)
  65. {
  66. AmfTraceWriter * writer = av_mallocz(sizeof(AmfTraceWriter));
  67. if (!writer)
  68. return NULL;
  69. writer->vtblp = &writer->vtbl;
  70. writer->vtblp->Write = AMFTraceWriter_Write;
  71. writer->vtblp->Flush = AMFTraceWriter_Flush;
  72. writer->avctx = avctx;
  73. return writer;
  74. }
  75. static void amf_writer_free(void *opaque)
  76. {
  77. AmfTraceWriter *writer = (AmfTraceWriter *)opaque;
  78. av_freep(&writer);
  79. }
  80. /**
  81. * We still need AVHWFramesContext to utilize our hardware memory
  82. * otherwise, we will receive the error "HW format requires hw_frames_ctx to be non-NULL".
  83. * (libavfilter\buffersrc.c function query_formats)
  84. */
  85. typedef struct {
  86. void *dummy;
  87. } AMFFramesContext;
  88. typedef struct AVAMFFormatMap {
  89. enum AVPixelFormat av_format;
  90. enum AMF_SURFACE_FORMAT amf_format;
  91. } FormatMap;
  92. const FormatMap format_map[] =
  93. {
  94. { AV_PIX_FMT_NONE, AMF_SURFACE_UNKNOWN },
  95. { AV_PIX_FMT_NV12, AMF_SURFACE_NV12 },
  96. { AV_PIX_FMT_BGR0, AMF_SURFACE_BGRA },
  97. { AV_PIX_FMT_RGB0, AMF_SURFACE_RGBA },
  98. { AV_PIX_FMT_BGRA, AMF_SURFACE_BGRA },
  99. { AV_PIX_FMT_ARGB, AMF_SURFACE_ARGB },
  100. { AV_PIX_FMT_RGBA, AMF_SURFACE_RGBA },
  101. { AV_PIX_FMT_GRAY8, AMF_SURFACE_GRAY8 },
  102. { AV_PIX_FMT_YUV420P, AMF_SURFACE_YUV420P },
  103. { AV_PIX_FMT_YUYV422, AMF_SURFACE_YUY2 },
  104. { AV_PIX_FMT_P010, AMF_SURFACE_P010 },
  105. { AV_PIX_FMT_X2BGR10, AMF_SURFACE_R10G10B10A2 },
  106. { AV_PIX_FMT_RGBAF16, AMF_SURFACE_RGBA_F16},
  107. };
  108. enum AMF_SURFACE_FORMAT av_av_to_amf_format(enum AVPixelFormat fmt)
  109. {
  110. int i;
  111. for (i = 0; i < amf_countof(format_map); i++) {
  112. if (format_map[i].av_format == fmt) {
  113. return format_map[i].amf_format;
  114. }
  115. }
  116. return AMF_SURFACE_UNKNOWN;
  117. }
  118. enum AVPixelFormat av_amf_to_av_format(enum AMF_SURFACE_FORMAT fmt)
  119. {
  120. int i;
  121. for (i = 0; i < amf_countof(format_map); i++) {
  122. if (format_map[i].amf_format == fmt) {
  123. return format_map[i].av_format;
  124. }
  125. }
  126. return AV_PIX_FMT_NONE;
  127. }
  128. static const enum AVPixelFormat supported_formats[] = {
  129. AV_PIX_FMT_NV12,
  130. AV_PIX_FMT_YUV420P,
  131. AV_PIX_FMT_BGRA,
  132. AV_PIX_FMT_RGBA,
  133. AV_PIX_FMT_P010,
  134. #if CONFIG_D3D11VA
  135. AV_PIX_FMT_D3D11,
  136. #endif
  137. #if CONFIG_D3D12VA
  138. AV_PIX_FMT_D3D12,
  139. #endif
  140. #if CONFIG_DXVA2
  141. AV_PIX_FMT_DXVA2_VLD,
  142. #endif
  143. };
  144. static const enum AVPixelFormat supported_transfer_formats[] = {
  145. AV_PIX_FMT_NV12,
  146. AV_PIX_FMT_YUV420P,
  147. AV_PIX_FMT_BGRA,
  148. AV_PIX_FMT_RGBA,
  149. AV_PIX_FMT_P010,
  150. AV_PIX_FMT_NONE,
  151. };
  152. static int amf_frames_get_constraints(AVHWDeviceContext *ctx,
  153. const void *hwconfig,
  154. AVHWFramesConstraints *constraints)
  155. {
  156. int i;
  157. constraints->valid_sw_formats = av_malloc_array(FF_ARRAY_ELEMS(supported_formats) + 1,
  158. sizeof(*constraints->valid_sw_formats));
  159. if (!constraints->valid_sw_formats)
  160. return AVERROR(ENOMEM);
  161. for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++)
  162. constraints->valid_sw_formats[i] = supported_formats[i];
  163. constraints->valid_sw_formats[FF_ARRAY_ELEMS(supported_formats)] = AV_PIX_FMT_NONE;
  164. constraints->valid_hw_formats = av_malloc_array(2, sizeof(*constraints->valid_hw_formats));
  165. if (!constraints->valid_hw_formats)
  166. return AVERROR(ENOMEM);
  167. constraints->valid_hw_formats[0] = AV_PIX_FMT_AMF_SURFACE;
  168. constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
  169. return 0;
  170. }
  171. static void amf_dummy_free(void *opaque, uint8_t *data)
  172. {
  173. }
  174. static AVBufferRef *amf_pool_alloc(void *opaque, size_t size)
  175. {
  176. AVHWFramesContext *hwfc = (AVHWFramesContext *)opaque;
  177. AVBufferRef *buf;
  178. buf = av_buffer_create(NULL, 0, amf_dummy_free, hwfc, AV_BUFFER_FLAG_READONLY);
  179. if (!buf) {
  180. av_log(hwfc, AV_LOG_ERROR, "Failed to create buffer for AMF context.\n");
  181. return NULL;
  182. }
  183. return buf;
  184. }
  185. static int amf_frames_init(AVHWFramesContext *ctx)
  186. {
  187. int i;
  188. for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) {
  189. if (ctx->sw_format == supported_formats[i])
  190. break;
  191. }
  192. if (i == FF_ARRAY_ELEMS(supported_formats)) {
  193. av_log(ctx, AV_LOG_ERROR, "Pixel format '%s' is not supported\n",
  194. av_get_pix_fmt_name(ctx->sw_format));
  195. return AVERROR(ENOSYS);
  196. }
  197. ffhwframesctx(ctx)->pool_internal =
  198. av_buffer_pool_init2(sizeof(AMFSurface), ctx,
  199. &amf_pool_alloc, NULL);
  200. return 0;
  201. }
  202. static int amf_get_buffer(AVHWFramesContext *ctx, AVFrame *frame)
  203. {
  204. frame->buf[0] = av_buffer_pool_get(ctx->pool);
  205. if (!frame->buf[0])
  206. return AVERROR(ENOMEM);
  207. frame->data[0] = frame->buf[0]->data;
  208. frame->format = AV_PIX_FMT_AMF_SURFACE;
  209. frame->width = ctx->width;
  210. frame->height = ctx->height;
  211. return 0;
  212. }
  213. static int amf_transfer_get_formats(AVHWFramesContext *ctx,
  214. enum AVHWFrameTransferDirection dir,
  215. enum AVPixelFormat **formats)
  216. {
  217. enum AVPixelFormat *fmts;
  218. int i;
  219. fmts = av_malloc_array(FF_ARRAY_ELEMS(supported_transfer_formats), sizeof(*fmts));
  220. if (!fmts)
  221. return AVERROR(ENOMEM);
  222. for (i = 0; i < FF_ARRAY_ELEMS(supported_transfer_formats); i++)
  223. fmts[i] = supported_transfer_formats[i];
  224. *formats = fmts;
  225. return 0;
  226. }
  227. static void amf_free_amfsurface(void *opaque, uint8_t *data)
  228. {
  229. if(!!data){
  230. AMFSurface *surface = (AMFSurface*)(data);
  231. surface->pVtbl->Release(surface);
  232. }
  233. }
  234. static int amf_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst,
  235. const AVFrame *src)
  236. {
  237. AMFSurface* surface = (AMFSurface*)dst->data[0];
  238. AMFPlane *plane;
  239. uint8_t *dst_data[4];
  240. int dst_linesize[4];
  241. int planes;
  242. int i;
  243. int res;
  244. int w = FFMIN(dst->width, src->width);
  245. int h = FFMIN(dst->height, src->height);
  246. if (dst->hw_frames_ctx->data != (uint8_t *)ctx || src->format != ctx->sw_format)
  247. return AVERROR(EINVAL);
  248. if (!surface) {
  249. AVHWDeviceContext *hwdev_ctx = ctx->device_ctx;
  250. AVAMFDeviceContext *amf_device_ctx = (AVAMFDeviceContext *)hwdev_ctx->hwctx;
  251. AMF_SURFACE_FORMAT format = av_av_to_amf_format(ctx->sw_format);
  252. res = amf_device_ctx->context->pVtbl->AllocSurface(amf_device_ctx->context, AMF_MEMORY_HOST, format, dst->width, dst->height, &surface);
  253. AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "AllocSurface() failed with error %d\n", res);
  254. dst->data[0] = (uint8_t *)surface;
  255. dst->buf[1] = av_buffer_create((uint8_t *)surface, sizeof(surface),
  256. amf_free_amfsurface,
  257. NULL,
  258. AV_BUFFER_FLAG_READONLY);
  259. AMF_RETURN_IF_FALSE(ctx, !!dst->buf[1], AVERROR(ENOMEM), "av_buffer_create for amf surface failed.");
  260. }
  261. planes = (int)surface->pVtbl->GetPlanesCount(surface);
  262. av_assert0(planes < FF_ARRAY_ELEMS(dst_data));
  263. for (i = 0; i < planes; i++) {
  264. plane = surface->pVtbl->GetPlaneAt(surface, i);
  265. dst_data[i] = plane->pVtbl->GetNative(plane);
  266. dst_linesize[i] = plane->pVtbl->GetHPitch(plane);
  267. }
  268. av_image_copy2(dst_data, dst_linesize,
  269. src->data, src->linesize, src->format,
  270. w, h);
  271. return 0;
  272. }
  273. static int amf_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst,
  274. const AVFrame *src)
  275. {
  276. AMFSurface* surface = (AMFSurface*)src->data[0];
  277. AMFPlane *plane;
  278. uint8_t *src_data[4];
  279. int src_linesize[4];
  280. int planes;
  281. int i;
  282. int w = FFMIN(dst->width, src->width);
  283. int h = FFMIN(dst->height, src->height);
  284. int ret;
  285. if (src->hw_frames_ctx->data != (uint8_t *)ctx || dst->format != ctx->sw_format)
  286. return AVERROR(EINVAL);
  287. ret = surface->pVtbl->Convert(surface, AMF_MEMORY_HOST);
  288. AMF_RETURN_IF_FALSE(ctx, ret == AMF_OK, AVERROR_UNKNOWN, "Convert(amf::AMF_MEMORY_HOST) failed with error %d\n", AVERROR_UNKNOWN);
  289. planes = (int)surface->pVtbl->GetPlanesCount(surface);
  290. av_assert0(planes < FF_ARRAY_ELEMS(src_data));
  291. for (i = 0; i < planes; i++) {
  292. plane = surface->pVtbl->GetPlaneAt(surface, i);
  293. src_data[i] = plane->pVtbl->GetNative(plane);
  294. src_linesize[i] = plane->pVtbl->GetHPitch(plane);
  295. }
  296. av_image_copy2(dst->data, dst->linesize,
  297. src_data, src_linesize, dst->format,
  298. w, h);
  299. return 0;
  300. }
  301. static void amf_device_uninit(AVHWDeviceContext *device_ctx)
  302. {
  303. AVAMFDeviceContext *amf_ctx = device_ctx->hwctx;
  304. AMF_RESULT res = AMF_NOT_INITIALIZED;
  305. AMFTrace *trace;
  306. if (amf_ctx->context) {
  307. amf_ctx->context->pVtbl->Terminate(amf_ctx->context);
  308. amf_ctx->context->pVtbl->Release(amf_ctx->context);
  309. amf_ctx->context = NULL;
  310. }
  311. if (amf_ctx->factory)
  312. res = amf_ctx->factory->pVtbl->GetTrace(amf_ctx->factory, &trace);
  313. if (res == AMF_OK) {
  314. trace->pVtbl->UnregisterWriter(trace, FFMPEG_AMF_WRITER_ID);
  315. }
  316. if(amf_ctx->library) {
  317. dlclose(amf_ctx->library);
  318. amf_ctx->library = NULL;
  319. }
  320. if (amf_ctx->trace_writer) {
  321. amf_writer_free(amf_ctx->trace_writer);
  322. }
  323. amf_ctx->version = 0;
  324. ff_mutex_destroy(&amf_ctx->mutex);
  325. }
  326. static int amf_device_init(AVHWDeviceContext *ctx)
  327. {
  328. AVAMFDeviceContext *amf_ctx = ctx->hwctx;
  329. AMFContext1 *context1 = NULL;
  330. AMF_RESULT res;
  331. #ifdef _WIN32
  332. res = amf_ctx->context->pVtbl->InitDX11(amf_ctx->context, NULL, AMF_DX11_1);
  333. if (res == AMF_OK || res == AMF_ALREADY_INITIALIZED) {
  334. av_log(ctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D11.\n");
  335. } else {
  336. res = amf_ctx->context->pVtbl->InitDX9(amf_ctx->context, NULL);
  337. if (res == AMF_OK) {
  338. av_log(ctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D9.\n");
  339. } else {
  340. #endif
  341. AMFGuid guid = IID_AMFContext1();
  342. res = amf_ctx->context->pVtbl->QueryInterface(amf_ctx->context, &guid, (void**)&context1);
  343. AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext1() failed with error %d\n", res);
  344. res = context1->pVtbl->InitVulkan(context1, NULL);
  345. context1->pVtbl->Release(context1);
  346. if (res != AMF_OK && res != AMF_ALREADY_INITIALIZED) {
  347. if (res == AMF_NOT_SUPPORTED)
  348. av_log(ctx, AV_LOG_ERROR, "AMF via Vulkan is not supported on the given device.\n");
  349. else
  350. av_log(ctx, AV_LOG_ERROR, "AMF failed to initialise on the given Vulkan device: %d.\n", res);
  351. return AVERROR(ENOSYS);
  352. }
  353. av_log(ctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via Vulkan.\n");
  354. #ifdef _WIN32
  355. }
  356. }
  357. #endif
  358. ff_mutex_init(&amf_ctx->mutex, NULL);
  359. return 0;
  360. }
  361. static int amf_load_library(AVAMFDeviceContext* amf_ctx, void* avcl)
  362. {
  363. AMFInit_Fn init_fun;
  364. AMFQueryVersion_Fn version_fun;
  365. AMF_RESULT res;
  366. amf_ctx->library = dlopen(AMF_DLL_NAMEA, RTLD_NOW | RTLD_LOCAL);
  367. AMF_RETURN_IF_FALSE(avcl, amf_ctx->library != NULL,
  368. AVERROR_UNKNOWN, "DLL %s failed to open\n", AMF_DLL_NAMEA);
  369. init_fun = (AMFInit_Fn)dlsym(amf_ctx->library, AMF_INIT_FUNCTION_NAME);
  370. 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);
  371. version_fun = (AMFQueryVersion_Fn)dlsym(amf_ctx->library, AMF_QUERY_VERSION_FUNCTION_NAME);
  372. 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);
  373. res = version_fun(&amf_ctx->version);
  374. AMF_RETURN_IF_FALSE(avcl, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_QUERY_VERSION_FUNCTION_NAME, res);
  375. res = init_fun(AMF_FULL_VERSION, &amf_ctx->factory);
  376. AMF_RETURN_IF_FALSE(avcl, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_INIT_FUNCTION_NAME, res);
  377. return 0;
  378. }
  379. static int amf_device_create(AVHWDeviceContext *device_ctx,
  380. const char *device,
  381. AVDictionary *opts, int flags)
  382. {
  383. AVAMFDeviceContext *ctx = device_ctx->hwctx;
  384. AMFTrace *trace;
  385. int ret;
  386. if ((ret = amf_load_library(ctx, device_ctx)) == 0) {
  387. ret = ctx->factory->pVtbl->GetTrace(ctx->factory, &trace);
  388. if (ret == AMF_OK) {
  389. int level_ff = av_log_get_level();
  390. int level_amf = AMF_TRACE_TRACE;
  391. amf_bool enable_log = true;
  392. switch(level_ff)
  393. {
  394. case AV_LOG_QUIET:
  395. level_amf = AMF_TRACE_ERROR;
  396. enable_log = false;
  397. break;
  398. case AV_LOG_PANIC:
  399. case AV_LOG_FATAL:
  400. case AV_LOG_ERROR:
  401. level_amf = AMF_TRACE_ERROR;
  402. break;
  403. case AV_LOG_WARNING:
  404. case AV_LOG_INFO:
  405. level_amf = AMF_TRACE_WARNING;
  406. break;
  407. case AV_LOG_VERBOSE:
  408. level_amf = AMF_TRACE_INFO;
  409. break;
  410. case AV_LOG_DEBUG:
  411. level_amf = AMF_TRACE_DEBUG;
  412. break;
  413. case AV_LOG_TRACE:
  414. level_amf = AMF_TRACE_TRACE;
  415. break;
  416. }
  417. if(ctx->version == AMF_MAKE_FULL_VERSION(1, 4, 35, 0)){// get around a bug in trace in AMF runtime driver 24.20
  418. level_amf = AMF_TRACE_WARNING;
  419. }
  420. trace->pVtbl->EnableWriter(trace, AMF_TRACE_WRITER_CONSOLE, 0);
  421. trace->pVtbl->SetGlobalLevel(trace, level_amf);
  422. // connect AMF logger to av_log
  423. ctx->trace_writer = amf_writer_alloc(device_ctx);
  424. trace->pVtbl->RegisterWriter(trace, FFMPEG_AMF_WRITER_ID, (AMFTraceWriter*)ctx->trace_writer, 1);
  425. trace->pVtbl->SetWriterLevel(trace, FFMPEG_AMF_WRITER_ID, level_amf);
  426. trace->pVtbl->EnableWriter(trace, FFMPEG_AMF_WRITER_ID, enable_log);
  427. trace->pVtbl->SetWriterLevel(trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, level_amf);
  428. trace->pVtbl->EnableWriter(trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, enable_log);
  429. }
  430. ret = ctx->factory->pVtbl->CreateContext(ctx->factory, &ctx->context);
  431. if (ret == AMF_OK) {
  432. AMF_ASSIGN_PROPERTY_INT64(ret, ctx->context, L"DeviceSurfaceCacheSize", 50 );
  433. return 0;
  434. }
  435. av_log(device_ctx, AV_LOG_ERROR, "CreateContext() failed with error %d.\n", ret);
  436. }
  437. amf_device_uninit(device_ctx);
  438. return ret;
  439. }
  440. #if CONFIG_DXVA2
  441. static int amf_init_from_dxva2_device(AVAMFDeviceContext * amf_ctx, AVHWDeviceContext *child_device_ctx)
  442. {
  443. AVDXVA2DeviceContext *hwctx = child_device_ctx->hwctx;
  444. IDirect3DDevice9 *device;
  445. HANDLE device_handle;
  446. HRESULT hr;
  447. AMF_RESULT res;
  448. int ret;
  449. hr = IDirect3DDeviceManager9_OpenDeviceHandle(hwctx->devmgr, &device_handle);
  450. if (FAILED(hr)) {
  451. av_log(child_device_ctx, AV_LOG_ERROR, "Failed to open device handle for Direct3D9 device: %lx.\n", (unsigned long)hr);
  452. return AVERROR_EXTERNAL;
  453. }
  454. hr = IDirect3DDeviceManager9_LockDevice(hwctx->devmgr, device_handle, &device, FALSE);
  455. if (SUCCEEDED(hr)) {
  456. IDirect3DDeviceManager9_UnlockDevice(hwctx->devmgr, device_handle, FALSE);
  457. ret = 0;
  458. } else {
  459. av_log(child_device_ctx, AV_LOG_ERROR, "Failed to lock device handle for Direct3D9 device: %lx.\n", (unsigned long)hr);
  460. ret = AVERROR_EXTERNAL;
  461. }
  462. IDirect3DDeviceManager9_CloseDeviceHandle(hwctx->devmgr, device_handle);
  463. if (ret < 0)
  464. return ret;
  465. res = amf_ctx->context->pVtbl->InitDX9(amf_ctx->context, device);
  466. IDirect3DDevice9_Release(device);
  467. if (res != AMF_OK && res != AMF_ALREADY_INITIALIZED) {
  468. if (res == AMF_NOT_SUPPORTED)
  469. av_log(child_device_ctx, AV_LOG_ERROR, "AMF via D3D9 is not supported on the given device.\n");
  470. else
  471. av_log(child_device_ctx, AV_LOG_ERROR, "AMF failed to initialise on given D3D9 device: %d.\n", res);
  472. return AVERROR(ENODEV);
  473. }
  474. av_log(child_device_ctx, AV_LOG_INFO, "AMF via DXVA2.\n");
  475. return 0;
  476. }
  477. #endif
  478. #if CONFIG_D3D11VA
  479. static int amf_init_from_d3d11_device(AVAMFDeviceContext* amf_ctx, AVHWDeviceContext *child_device_ctx)
  480. {
  481. AMF_RESULT res;
  482. AVD3D11VADeviceContext *hwctx = child_device_ctx->hwctx;
  483. res = amf_ctx->context->pVtbl->InitDX11(amf_ctx->context, hwctx->device, AMF_DX11_1);
  484. if (res != AMF_OK && res != AMF_ALREADY_INITIALIZED) {
  485. if (res == AMF_NOT_SUPPORTED)
  486. av_log(child_device_ctx, AV_LOG_ERROR, "AMF via D3D11 is not supported on the given device.\n");
  487. else
  488. av_log(child_device_ctx, AV_LOG_ERROR, "AMF failed to initialise on the given D3D11 device: %d.\n", res);
  489. return AVERROR(ENODEV);
  490. }
  491. av_log(child_device_ctx, AV_LOG_INFO, "AMF via D3D11.\n");
  492. return 0;
  493. }
  494. #endif
  495. #if CONFIG_D3D12VA
  496. static int amf_init_from_d3d12_device(AVAMFDeviceContext* amf_ctx, AVHWDeviceContext *child_device_ctx)
  497. {
  498. AVD3D12VADeviceContext *hwctx = child_device_ctx->hwctx;
  499. AMF_RESULT res;
  500. AMFContext2 *context2 = NULL;
  501. AMFGuid guid = IID_AMFContext2();
  502. res = amf_ctx->context->pVtbl->QueryInterface(amf_ctx->context, &guid, (void**)&context2);
  503. AMF_RETURN_IF_FALSE(child_device_ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext2() failed with error %d\n", res);
  504. res = context2->pVtbl->InitDX12(context2, hwctx->device, AMF_DX12);
  505. context2->pVtbl->Release(context2);
  506. if (res != AMF_OK && res != AMF_ALREADY_INITIALIZED) {
  507. if (res == AMF_NOT_SUPPORTED)
  508. av_log(child_device_ctx, AV_LOG_ERROR, "AMF via D3D12 is not supported on the given device.\n");
  509. else
  510. av_log(child_device_ctx, AV_LOG_ERROR, "AMF failed to initialise on the given D3D12 device: %d.\n", res);
  511. return AVERROR(ENODEV);
  512. }
  513. av_log(child_device_ctx, AV_LOG_INFO, "AMF via D3D12.\n");
  514. return 0;
  515. }
  516. #endif
  517. static int amf_device_derive(AVHWDeviceContext *device_ctx,
  518. AVHWDeviceContext *child_device_ctx, AVDictionary *opts,
  519. int flags)
  520. {
  521. #if CONFIG_DXVA2 || CONFIG_D3D11VA
  522. AVAMFDeviceContext *amf_ctx = device_ctx->hwctx;
  523. #endif
  524. int ret;
  525. ret = amf_device_create(device_ctx, "", opts, flags);
  526. if(ret < 0)
  527. return ret;
  528. switch (child_device_ctx->type) {
  529. #if CONFIG_DXVA2
  530. case AV_HWDEVICE_TYPE_DXVA2: {
  531. return amf_init_from_dxva2_device(amf_ctx, child_device_ctx);
  532. }
  533. break;
  534. #endif
  535. #if CONFIG_D3D11VA
  536. case AV_HWDEVICE_TYPE_D3D11VA: {
  537. return amf_init_from_d3d11_device(amf_ctx, child_device_ctx);
  538. }
  539. break;
  540. #endif
  541. #if CONFIG_D3D12VA
  542. case AV_HWDEVICE_TYPE_D3D12VA: {
  543. return amf_init_from_d3d12_device(amf_ctx, child_device_ctx);
  544. }
  545. break;
  546. #endif
  547. default: {
  548. av_log(child_device_ctx, AV_LOG_ERROR, "AMF initialisation from a %s device is not supported.\n",
  549. av_hwdevice_get_type_name(child_device_ctx->type));
  550. return AVERROR(ENOSYS);
  551. }
  552. }
  553. return 0;
  554. }
  555. const HWContextType ff_hwcontext_type_amf = {
  556. .type = AV_HWDEVICE_TYPE_AMF,
  557. .name = "AMF",
  558. .device_hwctx_size = sizeof(AVAMFDeviceContext),
  559. .frames_hwctx_size = sizeof(AMFFramesContext),
  560. .device_create = amf_device_create,
  561. .device_derive = amf_device_derive,
  562. .device_init = amf_device_init,
  563. .device_uninit = amf_device_uninit,
  564. .frames_get_constraints = amf_frames_get_constraints,
  565. .frames_init = amf_frames_init,
  566. .frames_get_buffer = amf_get_buffer,
  567. .transfer_get_formats = amf_transfer_get_formats,
  568. .transfer_data_to = amf_transfer_data_to,
  569. .transfer_data_from = amf_transfer_data_from,
  570. .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_AMF_SURFACE, AV_PIX_FMT_NONE },
  571. };