xref: /third_party/ffmpeg/libavcodec/amfenc.c (revision cabdff1a)
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, &timestamp, 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, &timestamp_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