You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

799 lines
28KB

  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 "config.h"
  19. #include "libavutil/avassert.h"
  20. #include "libavutil/imgutils.h"
  21. #include "libavutil/hwcontext.h"
  22. #if CONFIG_D3D11VA
  23. #include "libavutil/hwcontext_d3d11va.h"
  24. #endif
  25. #if CONFIG_DXVA2
  26. #define COBJMACROS
  27. #include "libavutil/hwcontext_dxva2.h"
  28. #endif
  29. #include "libavutil/mem.h"
  30. #include "libavutil/pixdesc.h"
  31. #include "libavutil/time.h"
  32. #include "amfenc.h"
  33. #include "internal.h"
  34. #if CONFIG_D3D11VA
  35. #include <d3d11.h>
  36. #endif
  37. #ifdef _WIN32
  38. #include "compat/w32dlfcn.h"
  39. #else
  40. #include <dlfcn.h>
  41. #endif
  42. #define FFMPEG_AMF_WRITER_ID L"ffmpeg_amf"
  43. #define PTS_PROP L"PtsProp"
  44. const enum AVPixelFormat ff_amf_pix_fmts[] = {
  45. AV_PIX_FMT_NV12,
  46. AV_PIX_FMT_YUV420P,
  47. #if CONFIG_D3D11VA
  48. AV_PIX_FMT_D3D11,
  49. #endif
  50. #if CONFIG_DXVA2
  51. AV_PIX_FMT_DXVA2_VLD,
  52. #endif
  53. AV_PIX_FMT_NONE
  54. };
  55. typedef struct FormatMap {
  56. enum AVPixelFormat av_format;
  57. enum AMF_SURFACE_FORMAT amf_format;
  58. } FormatMap;
  59. static const FormatMap format_map[] =
  60. {
  61. { AV_PIX_FMT_NONE, AMF_SURFACE_UNKNOWN },
  62. { AV_PIX_FMT_NV12, AMF_SURFACE_NV12 },
  63. { AV_PIX_FMT_BGR0, AMF_SURFACE_BGRA },
  64. { AV_PIX_FMT_RGB0, AMF_SURFACE_RGBA },
  65. { AV_PIX_FMT_GRAY8, AMF_SURFACE_GRAY8 },
  66. { AV_PIX_FMT_YUV420P, AMF_SURFACE_YUV420P },
  67. { AV_PIX_FMT_YUYV422, AMF_SURFACE_YUY2 },
  68. };
  69. static enum AMF_SURFACE_FORMAT amf_av_to_amf_format(enum AVPixelFormat fmt)
  70. {
  71. int i;
  72. for (i = 0; i < amf_countof(format_map); i++) {
  73. if (format_map[i].av_format == fmt) {
  74. return format_map[i].amf_format;
  75. }
  76. }
  77. return AMF_SURFACE_UNKNOWN;
  78. }
  79. static void AMF_CDECL_CALL AMFTraceWriter_Write(AMFTraceWriter *pThis,
  80. const wchar_t *scope, const wchar_t *message)
  81. {
  82. AmfTraceWriter *tracer = (AmfTraceWriter*)pThis;
  83. av_log(tracer->avctx, AV_LOG_DEBUG, "%ls: %ls", scope, message); // \n is provided from AMF
  84. }
  85. static void AMF_CDECL_CALL AMFTraceWriter_Flush(AMFTraceWriter *pThis)
  86. {
  87. }
  88. static AMFTraceWriterVtbl tracer_vtbl =
  89. {
  90. .Write = AMFTraceWriter_Write,
  91. .Flush = AMFTraceWriter_Flush,
  92. };
  93. static int amf_load_library(AVCodecContext *avctx)
  94. {
  95. AmfContext *ctx = avctx->priv_data;
  96. AMFInit_Fn init_fun = NULL;
  97. AMFQueryVersion_Fn version_fun = NULL;
  98. AMF_RESULT res = AMF_OK;
  99. ctx->eof = 0;
  100. ctx->delayed_drain = 0;
  101. ctx->hw_frames_ctx = NULL;
  102. ctx->hw_device_ctx = NULL;
  103. ctx->delayed_surface = NULL;
  104. ctx->delayed_frame = av_frame_alloc();
  105. if (!ctx->delayed_frame) {
  106. return AVERROR(ENOMEM);
  107. }
  108. // hardcoded to current HW queue size - will realloc in timestamp_queue_enqueue() if too small
  109. ctx->timestamp_list = av_fifo_alloc((avctx->max_b_frames + 16) * sizeof(int64_t));
  110. if (!ctx->timestamp_list) {
  111. return AVERROR(ENOMEM);
  112. }
  113. ctx->dts_delay = 0;
  114. ctx->library = dlopen(AMF_DLL_NAMEA, RTLD_NOW | RTLD_LOCAL);
  115. AMF_RETURN_IF_FALSE(ctx, ctx->library != NULL,
  116. AVERROR_UNKNOWN, "DLL %s failed to open\n", AMF_DLL_NAMEA);
  117. init_fun = (AMFInit_Fn)dlsym(ctx->library, AMF_INIT_FUNCTION_NAME);
  118. AMF_RETURN_IF_FALSE(ctx, init_fun != NULL, AVERROR_UNKNOWN, "DLL %s failed to find function %s\n", AMF_DLL_NAMEA, AMF_INIT_FUNCTION_NAME);
  119. version_fun = (AMFQueryVersion_Fn)dlsym(ctx->library, AMF_QUERY_VERSION_FUNCTION_NAME);
  120. AMF_RETURN_IF_FALSE(ctx, version_fun != NULL, AVERROR_UNKNOWN, "DLL %s failed to find function %s\n", AMF_DLL_NAMEA, AMF_QUERY_VERSION_FUNCTION_NAME);
  121. res = version_fun(&ctx->version);
  122. AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_QUERY_VERSION_FUNCTION_NAME, res);
  123. res = init_fun(AMF_FULL_VERSION, &ctx->factory);
  124. AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_INIT_FUNCTION_NAME, res);
  125. res = ctx->factory->pVtbl->GetTrace(ctx->factory, &ctx->trace);
  126. AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetTrace() failed with error %d\n", res);
  127. res = ctx->factory->pVtbl->GetDebug(ctx->factory, &ctx->debug);
  128. AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetDebug() failed with error %d\n", res);
  129. return 0;
  130. }
  131. #if CONFIG_D3D11VA
  132. static int amf_init_from_d3d11_device(AVCodecContext *avctx, AVD3D11VADeviceContext *hwctx)
  133. {
  134. AmfContext *ctx = avctx->priv_data;
  135. AMF_RESULT res;
  136. res = ctx->context->pVtbl->InitDX11(ctx->context, hwctx->device, AMF_DX11_1);
  137. if (res != AMF_OK) {
  138. if (res == AMF_NOT_SUPPORTED)
  139. av_log(avctx, AV_LOG_ERROR, "AMF via D3D11 is not supported on the given device.\n");
  140. else
  141. av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on the given D3D11 device: %d.\n", res);
  142. return AVERROR(ENODEV);
  143. }
  144. return 0;
  145. }
  146. #endif
  147. #if CONFIG_DXVA2
  148. static int amf_init_from_dxva2_device(AVCodecContext *avctx, AVDXVA2DeviceContext *hwctx)
  149. {
  150. AmfContext *ctx = avctx->priv_data;
  151. HANDLE device_handle;
  152. IDirect3DDevice9 *device;
  153. HRESULT hr;
  154. AMF_RESULT res;
  155. int ret;
  156. hr = IDirect3DDeviceManager9_OpenDeviceHandle(hwctx->devmgr, &device_handle);
  157. if (FAILED(hr)) {
  158. av_log(avctx, AV_LOG_ERROR, "Failed to open device handle for Direct3D9 device: %lx.\n", (unsigned long)hr);
  159. return AVERROR_EXTERNAL;
  160. }
  161. hr = IDirect3DDeviceManager9_LockDevice(hwctx->devmgr, device_handle, &device, FALSE);
  162. if (SUCCEEDED(hr)) {
  163. IDirect3DDeviceManager9_UnlockDevice(hwctx->devmgr, device_handle, FALSE);
  164. ret = 0;
  165. } else {
  166. av_log(avctx, AV_LOG_ERROR, "Failed to lock device handle for Direct3D9 device: %lx.\n", (unsigned long)hr);
  167. ret = AVERROR_EXTERNAL;
  168. }
  169. IDirect3DDeviceManager9_CloseDeviceHandle(hwctx->devmgr, device_handle);
  170. if (ret < 0)
  171. return ret;
  172. res = ctx->context->pVtbl->InitDX9(ctx->context, device);
  173. IDirect3DDevice9_Release(device);
  174. if (res != AMF_OK) {
  175. if (res == AMF_NOT_SUPPORTED)
  176. av_log(avctx, AV_LOG_ERROR, "AMF via D3D9 is not supported on the given device.\n");
  177. else
  178. av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on given D3D9 device: %d.\n", res);
  179. return AVERROR(ENODEV);
  180. }
  181. return 0;
  182. }
  183. #endif
  184. static int amf_init_context(AVCodecContext *avctx)
  185. {
  186. AmfContext *ctx = avctx->priv_data;
  187. AMF_RESULT res;
  188. av_unused int ret;
  189. ctx->hwsurfaces_in_queue = 0;
  190. ctx->hwsurfaces_in_queue_max = 16;
  191. // configure AMF logger
  192. // the return of these functions indicates old state and do not affect behaviour
  193. ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, ctx->log_to_dbg != 0 );
  194. if (ctx->log_to_dbg)
  195. ctx->trace->pVtbl->SetWriterLevel(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, AMF_TRACE_TRACE);
  196. ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_CONSOLE, 0);
  197. ctx->trace->pVtbl->SetGlobalLevel(ctx->trace, AMF_TRACE_TRACE);
  198. // connect AMF logger to av_log
  199. ctx->tracer.vtbl = &tracer_vtbl;
  200. ctx->tracer.avctx = avctx;
  201. ctx->trace->pVtbl->RegisterWriter(ctx->trace, FFMPEG_AMF_WRITER_ID,(AMFTraceWriter*)&ctx->tracer, 1);
  202. ctx->trace->pVtbl->SetWriterLevel(ctx->trace, FFMPEG_AMF_WRITER_ID, AMF_TRACE_TRACE);
  203. res = ctx->factory->pVtbl->CreateContext(ctx->factory, &ctx->context);
  204. AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext() failed with error %d\n", res);
  205. // If a device was passed to the encoder, try to initialise from that.
  206. if (avctx->hw_frames_ctx) {
  207. AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
  208. if (amf_av_to_amf_format(frames_ctx->sw_format) == AMF_SURFACE_UNKNOWN) {
  209. av_log(avctx, AV_LOG_ERROR, "Format of input frames context (%s) is not supported by AMF.\n",
  210. av_get_pix_fmt_name(frames_ctx->sw_format));
  211. return AVERROR(EINVAL);
  212. }
  213. switch (frames_ctx->device_ctx->type) {
  214. #if CONFIG_D3D11VA
  215. case AV_HWDEVICE_TYPE_D3D11VA:
  216. ret = amf_init_from_d3d11_device(avctx, frames_ctx->device_ctx->hwctx);
  217. if (ret < 0)
  218. return ret;
  219. break;
  220. #endif
  221. #if CONFIG_DXVA2
  222. case AV_HWDEVICE_TYPE_DXVA2:
  223. ret = amf_init_from_dxva2_device(avctx, frames_ctx->device_ctx->hwctx);
  224. if (ret < 0)
  225. return ret;
  226. break;
  227. #endif
  228. default:
  229. av_log(avctx, AV_LOG_ERROR, "AMF initialisation from a %s frames context is not supported.\n",
  230. av_hwdevice_get_type_name(frames_ctx->device_ctx->type));
  231. return AVERROR(ENOSYS);
  232. }
  233. ctx->hw_frames_ctx = av_buffer_ref(avctx->hw_frames_ctx);
  234. if (!ctx->hw_frames_ctx)
  235. return AVERROR(ENOMEM);
  236. if (frames_ctx->initial_pool_size > 0)
  237. ctx->hwsurfaces_in_queue_max = frames_ctx->initial_pool_size - 1;
  238. } else if (avctx->hw_device_ctx) {
  239. AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)avctx->hw_device_ctx->data;
  240. switch (device_ctx->type) {
  241. #if CONFIG_D3D11VA
  242. case AV_HWDEVICE_TYPE_D3D11VA:
  243. ret = amf_init_from_d3d11_device(avctx, device_ctx->hwctx);
  244. if (ret < 0)
  245. return ret;
  246. break;
  247. #endif
  248. #if CONFIG_DXVA2
  249. case AV_HWDEVICE_TYPE_DXVA2:
  250. ret = amf_init_from_dxva2_device(avctx, device_ctx->hwctx);
  251. if (ret < 0)
  252. return ret;
  253. break;
  254. #endif
  255. default:
  256. av_log(avctx, AV_LOG_ERROR, "AMF initialisation from a %s device is not supported.\n",
  257. av_hwdevice_get_type_name(device_ctx->type));
  258. return AVERROR(ENOSYS);
  259. }
  260. ctx->hw_device_ctx = av_buffer_ref(avctx->hw_device_ctx);
  261. if (!ctx->hw_device_ctx)
  262. return AVERROR(ENOMEM);
  263. } else {
  264. res = ctx->context->pVtbl->InitDX11(ctx->context, NULL, AMF_DX11_1);
  265. if (res == AMF_OK) {
  266. av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D11.\n");
  267. } else {
  268. res = ctx->context->pVtbl->InitDX9(ctx->context, NULL);
  269. if (res == AMF_OK) {
  270. av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D9.\n");
  271. } else {
  272. av_log(avctx, AV_LOG_ERROR, "AMF initialisation failed via D3D9: error %d.\n", res);
  273. return AVERROR(ENOSYS);
  274. }
  275. }
  276. }
  277. return 0;
  278. }
  279. static int amf_init_encoder(AVCodecContext *avctx)
  280. {
  281. AmfContext *ctx = avctx->priv_data;
  282. const wchar_t *codec_id = NULL;
  283. AMF_RESULT res = AMF_OK;
  284. enum AVPixelFormat pix_fmt;
  285. switch (avctx->codec->id) {
  286. case AV_CODEC_ID_H264:
  287. codec_id = AMFVideoEncoderVCE_AVC;
  288. break;
  289. case AV_CODEC_ID_HEVC:
  290. codec_id = AMFVideoEncoder_HEVC;
  291. break;
  292. default:
  293. break;
  294. }
  295. AMF_RETURN_IF_FALSE(ctx, codec_id != NULL, AVERROR(EINVAL), "Codec %d is not supported\n", avctx->codec->id);
  296. if (ctx->hw_frames_ctx)
  297. pix_fmt = ((AVHWFramesContext*)ctx->hw_frames_ctx->data)->sw_format;
  298. else
  299. pix_fmt = avctx->pix_fmt;
  300. ctx->format = amf_av_to_amf_format(pix_fmt);
  301. AMF_RETURN_IF_FALSE(ctx, ctx->format != AMF_SURFACE_UNKNOWN, AVERROR(EINVAL),
  302. "Format %s is not supported\n", av_get_pix_fmt_name(pix_fmt));
  303. res = ctx->factory->pVtbl->CreateComponent(ctx->factory, ctx->context, codec_id, &ctx->encoder);
  304. AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_ENCODER_NOT_FOUND, "CreateComponent(%ls) failed with error %d\n", codec_id, res);
  305. return 0;
  306. }
  307. int av_cold ff_amf_encode_close(AVCodecContext *avctx)
  308. {
  309. AmfContext *ctx = avctx->priv_data;
  310. if (ctx->delayed_surface)
  311. {
  312. ctx->delayed_surface->pVtbl->Release(ctx->delayed_surface);
  313. ctx->delayed_surface = NULL;
  314. }
  315. if (ctx->encoder) {
  316. ctx->encoder->pVtbl->Terminate(ctx->encoder);
  317. ctx->encoder->pVtbl->Release(ctx->encoder);
  318. ctx->encoder = NULL;
  319. }
  320. if (ctx->context) {
  321. ctx->context->pVtbl->Terminate(ctx->context);
  322. ctx->context->pVtbl->Release(ctx->context);
  323. ctx->context = NULL;
  324. }
  325. av_buffer_unref(&ctx->hw_device_ctx);
  326. av_buffer_unref(&ctx->hw_frames_ctx);
  327. if (ctx->trace) {
  328. ctx->trace->pVtbl->UnregisterWriter(ctx->trace, FFMPEG_AMF_WRITER_ID);
  329. }
  330. if (ctx->library) {
  331. dlclose(ctx->library);
  332. ctx->library = NULL;
  333. }
  334. ctx->trace = NULL;
  335. ctx->debug = NULL;
  336. ctx->factory = NULL;
  337. ctx->version = 0;
  338. ctx->delayed_drain = 0;
  339. av_frame_free(&ctx->delayed_frame);
  340. av_fifo_freep(&ctx->timestamp_list);
  341. return 0;
  342. }
  343. static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame,
  344. AMFSurface* surface)
  345. {
  346. AMFPlane *plane = NULL;
  347. uint8_t *dst_data[4];
  348. int dst_linesize[4];
  349. int planes;
  350. int i;
  351. planes = surface->pVtbl->GetPlanesCount(surface);
  352. av_assert0(planes < FF_ARRAY_ELEMS(dst_data));
  353. for (i = 0; i < planes; i++) {
  354. plane = surface->pVtbl->GetPlaneAt(surface, i);
  355. dst_data[i] = plane->pVtbl->GetNative(plane);
  356. dst_linesize[i] = plane->pVtbl->GetHPitch(plane);
  357. }
  358. av_image_copy(dst_data, dst_linesize,
  359. (const uint8_t**)frame->data, frame->linesize, frame->format,
  360. avctx->width, avctx->height);
  361. return 0;
  362. }
  363. static inline int timestamp_queue_enqueue(AVCodecContext *avctx, int64_t timestamp)
  364. {
  365. AmfContext *ctx = avctx->priv_data;
  366. if (av_fifo_space(ctx->timestamp_list) < sizeof(timestamp)) {
  367. if (av_fifo_grow(ctx->timestamp_list, sizeof(timestamp)) < 0) {
  368. return AVERROR(ENOMEM);
  369. }
  370. }
  371. av_fifo_generic_write(ctx->timestamp_list, &timestamp, sizeof(timestamp), NULL);
  372. return 0;
  373. }
  374. static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buffer)
  375. {
  376. AmfContext *ctx = avctx->priv_data;
  377. int ret;
  378. AMFVariantStruct var = {0};
  379. int64_t timestamp = AV_NOPTS_VALUE;
  380. int64_t size = buffer->pVtbl->GetSize(buffer);
  381. if ((ret = ff_alloc_packet2(avctx, pkt, size, 0)) < 0) {
  382. return ret;
  383. }
  384. memcpy(pkt->data, buffer->pVtbl->GetNative(buffer), size);
  385. switch (avctx->codec->id) {
  386. case AV_CODEC_ID_H264:
  387. buffer->pVtbl->GetProperty(buffer, AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE, &var);
  388. if(var.int64Value == AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_IDR) {
  389. pkt->flags = AV_PKT_FLAG_KEY;
  390. }
  391. break;
  392. case AV_CODEC_ID_HEVC:
  393. buffer->pVtbl->GetProperty(buffer, AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE, &var);
  394. if (var.int64Value == AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE_IDR) {
  395. pkt->flags = AV_PKT_FLAG_KEY;
  396. }
  397. break;
  398. default:
  399. break;
  400. }
  401. buffer->pVtbl->GetProperty(buffer, PTS_PROP, &var);
  402. pkt->pts = var.int64Value; // original pts
  403. AMF_RETURN_IF_FALSE(ctx, av_fifo_size(ctx->timestamp_list) > 0, AVERROR_UNKNOWN, "timestamp_list is empty\n");
  404. av_fifo_generic_read(ctx->timestamp_list, &timestamp, sizeof(timestamp), NULL);
  405. // calc dts shift if max_b_frames > 0
  406. if (avctx->max_b_frames > 0 && ctx->dts_delay == 0) {
  407. int64_t timestamp_last = AV_NOPTS_VALUE;
  408. AMF_RETURN_IF_FALSE(ctx, av_fifo_size(ctx->timestamp_list) > 0, AVERROR_UNKNOWN,
  409. "timestamp_list is empty while max_b_frames = %d\n", avctx->max_b_frames);
  410. av_fifo_generic_peek_at(
  411. ctx->timestamp_list,
  412. &timestamp_last,
  413. (av_fifo_size(ctx->timestamp_list) / sizeof(timestamp) - 1) * sizeof(timestamp_last),
  414. sizeof(timestamp_last),
  415. NULL);
  416. if (timestamp < 0 || timestamp_last < AV_NOPTS_VALUE) {
  417. return AVERROR(ERANGE);
  418. }
  419. ctx->dts_delay = timestamp_last - timestamp;
  420. }
  421. pkt->dts = timestamp - ctx->dts_delay;
  422. return 0;
  423. }
  424. // amfenc API implementation
  425. int ff_amf_encode_init(AVCodecContext *avctx)
  426. {
  427. AmfContext *ctx = avctx->priv_data;
  428. int ret;
  429. ctx->factory = NULL;
  430. ctx->debug = NULL;
  431. ctx->trace = NULL;
  432. ctx->context = NULL;
  433. ctx->encoder = NULL;
  434. ctx->library = NULL;
  435. ctx->version = 0;
  436. ctx->eof = 0;
  437. ctx->format = 0;
  438. ctx->tracer.vtbl = NULL;
  439. ctx->tracer.avctx = NULL;
  440. if ((ret = amf_load_library(avctx)) == 0) {
  441. if ((ret = amf_init_context(avctx)) == 0) {
  442. if ((ret = amf_init_encoder(avctx)) == 0) {
  443. return 0;
  444. }
  445. }
  446. }
  447. ff_amf_encode_close(avctx);
  448. return ret;
  449. }
  450. static AMF_RESULT amf_set_property_buffer(AMFSurface *object, const wchar_t *name, AMFBuffer *val)
  451. {
  452. AMF_RESULT res;
  453. AMFVariantStruct var;
  454. res = AMFVariantInit(&var);
  455. if (res == AMF_OK) {
  456. AMFGuid guid_AMFInterface = IID_AMFInterface();
  457. AMFInterface *amf_interface;
  458. res = val->pVtbl->QueryInterface(val, &guid_AMFInterface, (void**)&amf_interface);
  459. if (res == AMF_OK) {
  460. res = AMFVariantAssignInterface(&var, amf_interface);
  461. amf_interface->pVtbl->Release(amf_interface);
  462. }
  463. if (res == AMF_OK) {
  464. res = object->pVtbl->SetProperty(object, name, var);
  465. }
  466. AMFVariantClear(&var);
  467. }
  468. return res;
  469. }
  470. static AMF_RESULT amf_get_property_buffer(AMFData *object, const wchar_t *name, AMFBuffer **val)
  471. {
  472. AMF_RESULT res;
  473. AMFVariantStruct var;
  474. res = AMFVariantInit(&var);
  475. if (res == AMF_OK) {
  476. res = object->pVtbl->GetProperty(object, name, &var);
  477. if (res == AMF_OK) {
  478. if (var.type == AMF_VARIANT_INTERFACE) {
  479. AMFGuid guid_AMFBuffer = IID_AMFBuffer();
  480. AMFInterface *amf_interface = AMFVariantInterface(&var);
  481. res = amf_interface->pVtbl->QueryInterface(amf_interface, &guid_AMFBuffer, (void**)val);
  482. } else {
  483. res = AMF_INVALID_DATA_TYPE;
  484. }
  485. }
  486. AMFVariantClear(&var);
  487. }
  488. return res;
  489. }
  490. static AMFBuffer *amf_create_buffer_with_frame_ref(const AVFrame *frame, AMFContext *context)
  491. {
  492. AVFrame *frame_ref;
  493. AMFBuffer *frame_ref_storage_buffer = NULL;
  494. AMF_RESULT res;
  495. res = context->pVtbl->AllocBuffer(context, AMF_MEMORY_HOST, sizeof(frame_ref), &frame_ref_storage_buffer);
  496. if (res == AMF_OK) {
  497. frame_ref = av_frame_clone(frame);
  498. if (frame_ref) {
  499. memcpy(frame_ref_storage_buffer->pVtbl->GetNative(frame_ref_storage_buffer), &frame_ref, sizeof(frame_ref));
  500. } else {
  501. frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer);
  502. frame_ref_storage_buffer = NULL;
  503. }
  504. }
  505. return frame_ref_storage_buffer;
  506. }
  507. static void amf_release_buffer_with_frame_ref(AMFBuffer *frame_ref_storage_buffer)
  508. {
  509. AVFrame *av_frame_ref;
  510. memcpy(&av_frame_ref, frame_ref_storage_buffer->pVtbl->GetNative(frame_ref_storage_buffer), sizeof(av_frame_ref));
  511. av_frame_free(&av_frame_ref);
  512. frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer);
  513. }
  514. int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame)
  515. {
  516. AMF_RESULT res = AMF_OK;
  517. AmfContext *ctx = avctx->priv_data;
  518. AMFSurface *surface = NULL;
  519. int ret;
  520. if (!ctx->encoder)
  521. return AVERROR(EINVAL);
  522. if (!frame) { // submit drain
  523. if (!ctx->eof) { // submit drain one time only
  524. if (ctx->delayed_surface != NULL) {
  525. ctx->delayed_drain = 1; // input queue is full: resubmit Drain() in ff_amf_receive_packet
  526. } else if(!ctx->delayed_drain) {
  527. res = ctx->encoder->pVtbl->Drain(ctx->encoder);
  528. if (res == AMF_INPUT_FULL) {
  529. ctx->delayed_drain = 1; // input queue is full: resubmit Drain() in ff_amf_receive_packet
  530. } else {
  531. if (res == AMF_OK) {
  532. ctx->eof = 1; // drain started
  533. }
  534. AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Drain() failed with error %d\n", res);
  535. }
  536. }
  537. } else{
  538. return AVERROR_EOF;
  539. }
  540. } else { // submit frame
  541. int hw_surface = 0;
  542. if (ctx->delayed_surface != NULL) {
  543. return AVERROR(EAGAIN); // should not happen when called from ffmpeg, other clients may resubmit
  544. }
  545. // prepare surface from frame
  546. switch (frame->format) {
  547. #if CONFIG_D3D11VA
  548. case AV_PIX_FMT_D3D11:
  549. {
  550. static const GUID AMFTextureArrayIndexGUID = { 0x28115527, 0xe7c3, 0x4b66, { 0x99, 0xd3, 0x4f, 0x2a, 0xe6, 0xb4, 0x7f, 0xaf } };
  551. ID3D11Texture2D *texture = (ID3D11Texture2D*)frame->data[0]; // actual texture
  552. int index = (intptr_t)frame->data[1]; // index is a slice in texture array is - set to tell AMF which slice to use
  553. av_assert0(frame->hw_frames_ctx && ctx->hw_frames_ctx &&
  554. frame->hw_frames_ctx->data == ctx->hw_frames_ctx->data);
  555. texture->lpVtbl->SetPrivateData(texture, &AMFTextureArrayIndexGUID, sizeof(index), &index);
  556. res = ctx->context->pVtbl->CreateSurfaceFromDX11Native(ctx->context, texture, &surface, NULL); // wrap to AMF surface
  557. AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX11Native() failed with error %d\n", res);
  558. hw_surface = 1;
  559. }
  560. break;
  561. #endif
  562. #if CONFIG_DXVA2
  563. case AV_PIX_FMT_DXVA2_VLD:
  564. {
  565. IDirect3DSurface9 *texture = (IDirect3DSurface9 *)frame->data[3]; // actual texture
  566. res = ctx->context->pVtbl->CreateSurfaceFromDX9Native(ctx->context, texture, &surface, NULL); // wrap to AMF surface
  567. AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX9Native() failed with error %d\n", res);
  568. hw_surface = 1;
  569. }
  570. break;
  571. #endif
  572. default:
  573. {
  574. res = ctx->context->pVtbl->AllocSurface(ctx->context, AMF_MEMORY_HOST, ctx->format, avctx->width, avctx->height, &surface);
  575. AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "AllocSurface() failed with error %d\n", res);
  576. amf_copy_surface(avctx, frame, surface);
  577. }
  578. break;
  579. }
  580. if (hw_surface) {
  581. AMFBuffer *frame_ref_storage_buffer;
  582. // input HW surfaces can be vertically aligned by 16; tell AMF the real size
  583. surface->pVtbl->SetCrop(surface, 0, 0, frame->width, frame->height);
  584. frame_ref_storage_buffer = amf_create_buffer_with_frame_ref(frame, ctx->context);
  585. AMF_RETURN_IF_FALSE(ctx, frame_ref_storage_buffer != NULL, AVERROR(ENOMEM), "create_buffer_with_frame_ref() returned NULL\n");
  586. res = amf_set_property_buffer(surface, L"av_frame_ref", frame_ref_storage_buffer);
  587. AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SetProperty failed for \"av_frame_ref\" with error %d\n", res);
  588. ctx->hwsurfaces_in_queue++;
  589. frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer);
  590. }
  591. surface->pVtbl->SetPts(surface, frame->pts);
  592. AMF_ASSIGN_PROPERTY_INT64(res, surface, PTS_PROP, frame->pts);
  593. switch (avctx->codec->id) {
  594. case AV_CODEC_ID_H264:
  595. AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_AUD, !!ctx->aud);
  596. break;
  597. case AV_CODEC_ID_HEVC:
  598. AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_INSERT_AUD, !!ctx->aud);
  599. break;
  600. default:
  601. break;
  602. }
  603. // submit surface
  604. res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)surface);
  605. if (res == AMF_INPUT_FULL) { // handle full queue
  606. //store surface for later submission
  607. ctx->delayed_surface = surface;
  608. if (surface->pVtbl->GetMemoryType(surface) == AMF_MEMORY_DX11) {
  609. av_frame_ref(ctx->delayed_frame, frame);
  610. }
  611. } else {
  612. surface->pVtbl->Release(surface);
  613. AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SubmitInput() failed with error %d\n", res);
  614. if ((ret = timestamp_queue_enqueue(avctx, frame->pts)) < 0) {
  615. return ret;
  616. }
  617. }
  618. }
  619. return 0;
  620. }
  621. int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
  622. {
  623. int ret;
  624. AMF_RESULT res;
  625. AMF_RESULT res_query;
  626. AmfContext *ctx = avctx->priv_data;
  627. AMFData *data = NULL;
  628. int block_and_wait;
  629. if (!ctx->encoder)
  630. return AVERROR(EINVAL);
  631. do {
  632. block_and_wait = 0;
  633. // poll data
  634. res_query = ctx->encoder->pVtbl->QueryOutput(ctx->encoder, &data);
  635. if (data) {
  636. // copy data to packet
  637. AMFBuffer* buffer;
  638. AMFGuid guid = IID_AMFBuffer();
  639. data->pVtbl->QueryInterface(data, &guid, (void**)&buffer); // query for buffer interface
  640. ret = amf_copy_buffer(avctx, avpkt, buffer);
  641. buffer->pVtbl->Release(buffer);
  642. if (data->pVtbl->HasProperty(data, L"av_frame_ref")) {
  643. AMFBuffer *frame_ref_storage_buffer;
  644. res = amf_get_property_buffer(data, L"av_frame_ref", &frame_ref_storage_buffer);
  645. AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetProperty failed for \"av_frame_ref\" with error %d\n", res);
  646. amf_release_buffer_with_frame_ref(frame_ref_storage_buffer);
  647. ctx->hwsurfaces_in_queue--;
  648. }
  649. data->pVtbl->Release(data);
  650. AMF_RETURN_IF_FALSE(ctx, ret >= 0, ret, "amf_copy_buffer() failed with error %d\n", ret);
  651. if (ctx->delayed_surface != NULL) { // try to resubmit frame
  652. res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)ctx->delayed_surface);
  653. if (res != AMF_INPUT_FULL) {
  654. int64_t pts = ctx->delayed_surface->pVtbl->GetPts(ctx->delayed_surface);
  655. ctx->delayed_surface->pVtbl->Release(ctx->delayed_surface);
  656. ctx->delayed_surface = NULL;
  657. av_frame_unref(ctx->delayed_frame);
  658. AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Repeated SubmitInput() failed with error %d\n", res);
  659. if ((ret = timestamp_queue_enqueue(avctx, pts)) < 0) {
  660. return ret;
  661. }
  662. } else {
  663. av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed frame submission got AMF_INPUT_FULL- should not happen\n");
  664. }
  665. } else if (ctx->delayed_drain) { // try to resubmit drain
  666. res = ctx->encoder->pVtbl->Drain(ctx->encoder);
  667. if (res != AMF_INPUT_FULL) {
  668. ctx->delayed_drain = 0;
  669. ctx->eof = 1; // drain started
  670. AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Repeated Drain() failed with error %d\n", res);
  671. } else {
  672. av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed drain submission got AMF_INPUT_FULL- should not happen\n");
  673. }
  674. }
  675. } else if (ctx->delayed_surface != NULL || ctx->delayed_drain || (ctx->eof && res_query != AMF_EOF) || (ctx->hwsurfaces_in_queue >= ctx->hwsurfaces_in_queue_max)) {
  676. block_and_wait = 1;
  677. av_usleep(1000); // wait and poll again
  678. }
  679. } while (block_and_wait);
  680. if (res_query == AMF_EOF) {
  681. ret = AVERROR_EOF;
  682. } else if (data == NULL) {
  683. ret = AVERROR(EAGAIN);
  684. } else {
  685. ret = 0;
  686. }
  687. return ret;
  688. }