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