Co-authored-by: Evgeny Pavlov <lucenti...@gmail.com> v3: cleanup code --- libavcodec/amfenc.c | 573 +++++++++++---------------------------- libavcodec/amfenc.h | 32 +-- libavcodec/amfenc_av1.c | 8 +- libavcodec/amfenc_h264.c | 8 +- libavcodec/amfenc_hevc.c | 14 +- 5 files changed, 176 insertions(+), 459 deletions(-)
diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c index 510050e282..c57fa1b980 100644 --- a/libavcodec/amfenc.c +++ b/libavcodec/amfenc.c @@ -29,6 +29,8 @@ #define COBJMACROS #include "libavutil/hwcontext_dxva2.h" #endif +#include "libavutil/hwcontext_amf.h" +#include "libavutil/hwcontext_amf_internal.h" #include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/time.h" @@ -38,6 +40,18 @@ #include "internal.h" #include "libavutil/mastering_display_metadata.h" +#if CONFIG_D3D11VA +#include <d3d11.h> +#endif + +#ifdef _WIN32 +#include "compat/w32dlfcn.h" +#else +#include <dlfcn.h> +#endif + +#define PTS_PROP L"PtsProp" + static int amf_save_hdr_metadata(AVCodecContext *avctx, const AVFrame *frame, AMFHDRMetadata *hdrmeta) { AVFrameSideData *sd_display; @@ -88,20 +102,6 @@ static int amf_save_hdr_metadata(AVCodecContext *avctx, const AVFrame *frame, AM return 1; } -#if CONFIG_D3D11VA -#include <d3d11.h> -#endif - -#ifdef _WIN32 -#include "compat/w32dlfcn.h" -#else -#include <dlfcn.h> -#endif - -#define FFMPEG_AMF_WRITER_ID L"ffmpeg_amf" - -#define PTS_PROP L"PtsProp" - const enum AVPixelFormat ff_amf_pix_fmts[] = { AV_PIX_FMT_NV12, AV_PIX_FMT_YUV420P, @@ -111,289 +111,18 @@ const enum AVPixelFormat ff_amf_pix_fmts[] = { #if CONFIG_DXVA2 AV_PIX_FMT_DXVA2_VLD, #endif + AV_PIX_FMT_AMF_SURFACE, AV_PIX_FMT_P010, AV_PIX_FMT_NONE }; -typedef struct FormatMap { - enum AVPixelFormat av_format; - enum AMF_SURFACE_FORMAT amf_format; -} FormatMap; - -static const FormatMap format_map[] = -{ - { AV_PIX_FMT_NONE, AMF_SURFACE_UNKNOWN }, - { AV_PIX_FMT_NV12, AMF_SURFACE_NV12 }, - { AV_PIX_FMT_P010, AMF_SURFACE_P010 }, - { AV_PIX_FMT_BGR0, AMF_SURFACE_BGRA }, - { AV_PIX_FMT_RGB0, AMF_SURFACE_RGBA }, - { AV_PIX_FMT_GRAY8, AMF_SURFACE_GRAY8 }, - { AV_PIX_FMT_YUV420P, AMF_SURFACE_YUV420P }, - { AV_PIX_FMT_YUYV422, AMF_SURFACE_YUY2 }, -}; - -static enum AMF_SURFACE_FORMAT amf_av_to_amf_format(enum AVPixelFormat fmt) -{ - int i; - for (i = 0; i < amf_countof(format_map); i++) { - if (format_map[i].av_format == fmt) { - return format_map[i].amf_format; - } - } - return AMF_SURFACE_UNKNOWN; -} - -static void AMF_CDECL_CALL AMFTraceWriter_Write(AMFTraceWriter *pThis, - const wchar_t *scope, const wchar_t *message) -{ - AmfTraceWriter *tracer = (AmfTraceWriter*)pThis; - av_log(tracer->avctx, AV_LOG_DEBUG, "%ls: %ls", scope, message); // \n is provided from AMF -} - -static void AMF_CDECL_CALL AMFTraceWriter_Flush(AMFTraceWriter *pThis) -{ -} - -static AMFTraceWriterVtbl tracer_vtbl = -{ - .Write = AMFTraceWriter_Write, - .Flush = AMFTraceWriter_Flush, -}; - -static int amf_load_library(AVCodecContext *avctx) -{ - AmfContext *ctx = avctx->priv_data; - AMFInit_Fn init_fun; - AMFQueryVersion_Fn version_fun; - AMF_RESULT res; - - ctx->delayed_frame = av_frame_alloc(); - if (!ctx->delayed_frame) { - return AVERROR(ENOMEM); - } - // hardcoded to current HW queue size - will auto-realloc if too small - ctx->timestamp_list = av_fifo_alloc2(avctx->max_b_frames + 16, sizeof(int64_t), - AV_FIFO_FLAG_AUTO_GROW); - if (!ctx->timestamp_list) { - return AVERROR(ENOMEM); - } - ctx->dts_delay = 0; - - - ctx->library = dlopen(AMF_DLL_NAMEA, RTLD_NOW | RTLD_LOCAL); - AMF_RETURN_IF_FALSE(ctx, ctx->library != NULL, - AVERROR_UNKNOWN, "DLL %s failed to open\n", AMF_DLL_NAMEA); - - init_fun = (AMFInit_Fn)dlsym(ctx->library, AMF_INIT_FUNCTION_NAME); - 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); - - version_fun = (AMFQueryVersion_Fn)dlsym(ctx->library, AMF_QUERY_VERSION_FUNCTION_NAME); - 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); - - res = version_fun(&ctx->version); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_QUERY_VERSION_FUNCTION_NAME, res); - res = init_fun(AMF_FULL_VERSION, &ctx->factory); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_INIT_FUNCTION_NAME, res); - res = ctx->factory->pVtbl->GetTrace(ctx->factory, &ctx->trace); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetTrace() failed with error %d\n", res); - res = ctx->factory->pVtbl->GetDebug(ctx->factory, &ctx->debug); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetDebug() failed with error %d\n", res); - return 0; -} - -#if CONFIG_D3D11VA -static int amf_init_from_d3d11_device(AVCodecContext *avctx, AVD3D11VADeviceContext *hwctx) -{ - AmfContext *ctx = avctx->priv_data; - AMF_RESULT res; - - res = ctx->context->pVtbl->InitDX11(ctx->context, hwctx->device, AMF_DX11_1); - if (res != AMF_OK) { - if (res == AMF_NOT_SUPPORTED) - av_log(avctx, AV_LOG_ERROR, "AMF via D3D11 is not supported on the given device.\n"); - else - av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on the given D3D11 device: %d.\n", res); - return AVERROR(ENODEV); - } - - return 0; -} -#endif - -#if CONFIG_DXVA2 -static int amf_init_from_dxva2_device(AVCodecContext *avctx, AVDXVA2DeviceContext *hwctx) -{ - AmfContext *ctx = avctx->priv_data; - HANDLE device_handle; - IDirect3DDevice9 *device; - HRESULT hr; - AMF_RESULT res; - int ret; - - hr = IDirect3DDeviceManager9_OpenDeviceHandle(hwctx->devmgr, &device_handle); - if (FAILED(hr)) { - av_log(avctx, AV_LOG_ERROR, "Failed to open device handle for Direct3D9 device: %lx.\n", (unsigned long)hr); - return AVERROR_EXTERNAL; - } - - hr = IDirect3DDeviceManager9_LockDevice(hwctx->devmgr, device_handle, &device, FALSE); - if (SUCCEEDED(hr)) { - IDirect3DDeviceManager9_UnlockDevice(hwctx->devmgr, device_handle, FALSE); - ret = 0; - } else { - av_log(avctx, AV_LOG_ERROR, "Failed to lock device handle for Direct3D9 device: %lx.\n", (unsigned long)hr); - ret = AVERROR_EXTERNAL; - } - - IDirect3DDeviceManager9_CloseDeviceHandle(hwctx->devmgr, device_handle); - - if (ret < 0) - return ret; - - res = ctx->context->pVtbl->InitDX9(ctx->context, device); - - IDirect3DDevice9_Release(device); - - if (res != AMF_OK) { - if (res == AMF_NOT_SUPPORTED) - av_log(avctx, AV_LOG_ERROR, "AMF via D3D9 is not supported on the given device.\n"); - else - av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on given D3D9 device: %d.\n", res); - return AVERROR(ENODEV); - } - - return 0; -} -#endif - -static int amf_init_context(AVCodecContext *avctx) -{ - AmfContext *ctx = avctx->priv_data; - AMFContext1 *context1 = NULL; - AMF_RESULT res; - av_unused int ret; - - ctx->hwsurfaces_in_queue = 0; - ctx->hwsurfaces_in_queue_max = 16; - - // configure AMF logger - // the return of these functions indicates old state and do not affect behaviour - ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, ctx->log_to_dbg != 0 ); - if (ctx->log_to_dbg) - ctx->trace->pVtbl->SetWriterLevel(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, AMF_TRACE_TRACE); - ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_CONSOLE, 0); - ctx->trace->pVtbl->SetGlobalLevel(ctx->trace, AMF_TRACE_TRACE); - - // connect AMF logger to av_log - ctx->tracer.vtbl = &tracer_vtbl; - ctx->tracer.avctx = avctx; - ctx->trace->pVtbl->RegisterWriter(ctx->trace, FFMPEG_AMF_WRITER_ID,(AMFTraceWriter*)&ctx->tracer, 1); - ctx->trace->pVtbl->SetWriterLevel(ctx->trace, FFMPEG_AMF_WRITER_ID, AMF_TRACE_TRACE); - - res = ctx->factory->pVtbl->CreateContext(ctx->factory, &ctx->context); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext() failed with error %d\n", res); - - // If a device was passed to the encoder, try to initialise from that. - if (avctx->hw_frames_ctx) { - AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - - if (amf_av_to_amf_format(frames_ctx->sw_format) == AMF_SURFACE_UNKNOWN) { - av_log(avctx, AV_LOG_ERROR, "Format of input frames context (%s) is not supported by AMF.\n", - av_get_pix_fmt_name(frames_ctx->sw_format)); - return AVERROR(EINVAL); - } - - switch (frames_ctx->device_ctx->type) { -#if CONFIG_D3D11VA - case AV_HWDEVICE_TYPE_D3D11VA: - ret = amf_init_from_d3d11_device(avctx, frames_ctx->device_ctx->hwctx); - if (ret < 0) - return ret; - break; -#endif -#if CONFIG_DXVA2 - case AV_HWDEVICE_TYPE_DXVA2: - ret = amf_init_from_dxva2_device(avctx, frames_ctx->device_ctx->hwctx); - if (ret < 0) - return ret; - break; -#endif - default: - av_log(avctx, AV_LOG_ERROR, "AMF initialisation from a %s frames context is not supported.\n", - av_hwdevice_get_type_name(frames_ctx->device_ctx->type)); - return AVERROR(ENOSYS); - } - - ctx->hw_frames_ctx = av_buffer_ref(avctx->hw_frames_ctx); - if (!ctx->hw_frames_ctx) - return AVERROR(ENOMEM); - - if (frames_ctx->initial_pool_size > 0) - ctx->hwsurfaces_in_queue_max = frames_ctx->initial_pool_size - 1; - - } else if (avctx->hw_device_ctx) { - AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)avctx->hw_device_ctx->data; - - switch (device_ctx->type) { -#if CONFIG_D3D11VA - case AV_HWDEVICE_TYPE_D3D11VA: - ret = amf_init_from_d3d11_device(avctx, device_ctx->hwctx); - if (ret < 0) - return ret; - break; -#endif -#if CONFIG_DXVA2 - case AV_HWDEVICE_TYPE_DXVA2: - ret = amf_init_from_dxva2_device(avctx, device_ctx->hwctx); - if (ret < 0) - return ret; - break; -#endif - default: - av_log(avctx, AV_LOG_ERROR, "AMF initialisation from a %s device is not supported.\n", - av_hwdevice_get_type_name(device_ctx->type)); - return AVERROR(ENOSYS); - } - - ctx->hw_device_ctx = av_buffer_ref(avctx->hw_device_ctx); - if (!ctx->hw_device_ctx) - return AVERROR(ENOMEM); - - } else { - res = ctx->context->pVtbl->InitDX11(ctx->context, NULL, AMF_DX11_1); - if (res == AMF_OK) { - av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D11.\n"); - } else { - res = ctx->context->pVtbl->InitDX9(ctx->context, NULL); - if (res == AMF_OK) { - av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D9.\n"); - } else { - AMFGuid guid = IID_AMFContext1(); - res = ctx->context->pVtbl->QueryInterface(ctx->context, &guid, (void**)&context1); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext1() failed with error %d\n", res); - - res = context1->pVtbl->InitVulkan(context1, NULL); - context1->pVtbl->Release(context1); - if (res != AMF_OK) { - if (res == AMF_NOT_SUPPORTED) - av_log(avctx, AV_LOG_ERROR, "AMF via Vulkan is not supported on the given device.\n"); - else - av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on the given Vulkan device: %d.\n", res); - return AVERROR(ENOSYS); - } - av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via Vulkan.\n"); - } - } - } - return 0; -} - static int amf_init_encoder(AVCodecContext *avctx) { - AmfContext *ctx = avctx->priv_data; + AMFEncoderContext *ctx = avctx->priv_data; const wchar_t *codec_id = NULL; AMF_RESULT res; enum AVPixelFormat pix_fmt; + AVAMFDeviceContext* internal = ctx->amf_device_ctx; switch (avctx->codec->id) { case AV_CODEC_ID_H264: @@ -410,29 +139,27 @@ static int amf_init_encoder(AVCodecContext *avctx) } AMF_RETURN_IF_FALSE(ctx, codec_id != NULL, AVERROR(EINVAL), "Codec %d is not supported\n", avctx->codec->id); - if (ctx->hw_frames_ctx) - pix_fmt = ((AVHWFramesContext*)ctx->hw_frames_ctx->data)->sw_format; + if (avctx->hw_frames_ctx) + pix_fmt = ((AVHWFramesContext*)avctx->hw_frames_ctx->data)->sw_format; else pix_fmt = avctx->pix_fmt; - ctx->format = amf_av_to_amf_format(pix_fmt); + if (avctx->pix_fmt != AV_PIX_FMT_AMF_SURFACE) + ctx->format = av_amf_av_to_amf_format(pix_fmt); + else + ctx->format = av_amf_av_to_amf_format(avctx->sw_pix_fmt); + AMF_RETURN_IF_FALSE(ctx, ctx->format != AMF_SURFACE_UNKNOWN, AVERROR(EINVAL), - "Format %s is not supported\n", av_get_pix_fmt_name(pix_fmt)); + "Format %s is not supported\n", av_get_pix_fmt_name(pix_fmt)); - res = ctx->factory->pVtbl->CreateComponent(ctx->factory, ctx->context, codec_id, &ctx->encoder); + res = ctx->amf_device_ctx->factory->pVtbl->CreateComponent(ctx->amf_device_ctx->factory, internal->context, codec_id, &ctx->encoder); AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_ENCODER_NOT_FOUND, "CreateComponent(%ls) failed with error %d\n", codec_id, res); - return 0; } int av_cold ff_amf_encode_close(AVCodecContext *avctx) { - AmfContext *ctx = avctx->priv_data; - - if (ctx->delayed_surface) { - ctx->delayed_surface->pVtbl->Release(ctx->delayed_surface); - ctx->delayed_surface = NULL; - } + AMFEncoderContext *ctx = avctx->priv_data; if (ctx->encoder) { ctx->encoder->pVtbl->Terminate(ctx->encoder); @@ -440,38 +167,50 @@ int av_cold ff_amf_encode_close(AVCodecContext *avctx) ctx->encoder = NULL; } - if (ctx->context) { - ctx->context->pVtbl->Terminate(ctx->context); - ctx->context->pVtbl->Release(ctx->context); - ctx->context = NULL; + if (ctx->amf_device_ctx && ctx->local_context) { + av_amf_context_free(0, (uint8_t *)ctx->amf_device_ctx); + av_freep(&ctx->amf_device_ctx); } - av_buffer_unref(&ctx->hw_device_ctx); - av_buffer_unref(&ctx->hw_frames_ctx); + av_fifo_freep2(&ctx->timestamp_list); + + return 0; +} - if (ctx->trace) { - ctx->trace->pVtbl->UnregisterWriter(ctx->trace, FFMPEG_AMF_WRITER_ID); +static int amf_init_encoder_context(AVCodecContext *avctx) +{ + AMFEncoderContext *ctx = avctx->priv_data; + AMFContext1 *context1 = NULL; + int ret; + + if (avctx->hw_frames_ctx) { + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + ret = av_amf_context_derive(ctx->amf_device_ctx, frames_ctx->device_ctx, NULL, 0); + if (ret < 0) + return ret; } - if (ctx->library) { - dlclose(ctx->library); - ctx->library = NULL; + else if (avctx->hw_device_ctx) { + AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)avctx->hw_device_ctx->data; + ret = av_amf_context_derive(ctx->amf_device_ctx, device_ctx, NULL, 0); + if (ret < 0) + return ret; + + } else { + ret = av_amf_context_init(ctx->amf_device_ctx, avctx); + if (ret != 0) { + return ret; + } } - ctx->trace = NULL; - ctx->debug = NULL; - ctx->factory = NULL; - ctx->version = 0; - ctx->delayed_drain = 0; - av_frame_free(&ctx->delayed_frame); - av_fifo_freep2(&ctx->timestamp_list); - return 0; + + return ret; } static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame, AMFSurface* surface) { AMFPlane *plane; - uint8_t *dst_data[4]; - int dst_linesize[4]; + uint8_t *dst_data[4] = {0}; + int dst_linesize[4] = {0}; int planes; int i; @@ -492,7 +231,7 @@ static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame, static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buffer) { - AmfContext *ctx = avctx->priv_data; + AMFEncoderContext *ctx = avctx->priv_data; int ret; AMFVariantStruct var = {0}; int64_t timestamp = AV_NOPTS_VALUE; @@ -555,17 +294,47 @@ int ff_amf_encode_init(AVCodecContext *avctx) { int ret; - if ((ret = amf_load_library(avctx)) == 0) { - if ((ret = amf_init_context(avctx)) == 0) { - if ((ret = amf_init_encoder(avctx)) == 0) { - if (avctx->pix_fmt == AV_PIX_FMT_P010) { - AmfContext *ctx = avctx->priv_data; - AMF_RETURN_IF_FALSE(ctx, ctx->version >= AMF_MAKE_FULL_VERSION(1, 4, 32, 0), AVERROR_UNKNOWN, "10-bit encoder is not supported by AMD GPU drivers versions lower than 23.30.\n"); - } - return 0; - } + AMFEncoderContext *ctx = avctx->priv_data; + AVHWDeviceContext *hwdev_ctx = NULL; + if (avctx->hw_device_ctx) { + hwdev_ctx = (AVHWDeviceContext*)avctx->hw_device_ctx->data; + } else if (avctx->hw_frames_ctx) { + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + hwdev_ctx = (AVHWDeviceContext*)frames_ctx->device_ctx; + } + // hardcoded to current HW queue size - will auto-realloc if too small + ctx->timestamp_list = av_fifo_alloc2(avctx->max_b_frames + 16, sizeof(int64_t), + AV_FIFO_FLAG_AUTO_GROW); + if (!ctx->timestamp_list) { + return AVERROR(ENOMEM); + } + ctx->dts_delay = 0; + + ctx->hwsurfaces_in_queue = 0; + ctx->hwsurfaces_in_queue_max = 16; + ctx->local_context = 0; + if (avctx->hw_frames_ctx && hwdev_ctx && hwdev_ctx->type == AV_HWDEVICE_TYPE_AMF) { + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + ctx->amf_device_ctx = hwdev_ctx->hwctx; + } + else if (avctx->hw_device_ctx && hwdev_ctx && hwdev_ctx->type == AV_HWDEVICE_TYPE_AMF) { + ctx->amf_device_ctx = hwdev_ctx->hwctx; + } else { + ctx->amf_device_ctx = av_mallocz(sizeof(AVAMFDeviceContext)); + ctx->local_context = 1; + if ((ret = av_amf_context_create(ctx->amf_device_ctx, avctx, "", NULL, 0)) != 0) { + ff_amf_encode_close(avctx); + return ret; + } + if ((ret = amf_init_encoder_context(avctx)) != 0) { + ff_amf_encode_close(avctx); + return ret; } } + if ((ret = amf_init_encoder(avctx)) == 0) { + return 0; + } + ff_amf_encode_close(avctx); return ret; } @@ -642,31 +411,27 @@ static void amf_release_buffer_with_frame_ref(AMFBuffer *frame_ref_storage_buffe int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) { - AmfContext *ctx = avctx->priv_data; + AMFEncoderContext *ctx = avctx->priv_data; AMFSurface *surface; AMF_RESULT res; int ret; AMF_RESULT res_query; AMFData *data = NULL; - AVFrame *frame = ctx->delayed_frame; + AVFrame *frame = av_frame_alloc(); int block_and_wait; int query_output_data_flag = 0; - AMF_RESULT res_resubmit; + int count = 0; if (!ctx->encoder) return AVERROR(EINVAL); - if (!frame->buf[0]) { - ret = ff_encode_get_frame(avctx, frame); - if (ret < 0 && ret != AVERROR_EOF) - return ret; - } + ret = ff_encode_get_frame(avctx, frame); + if (ret < 0 && ret != AVERROR_EOF) + return ret; if (!frame->buf[0]) { // submit drain if (!ctx->eof) { // submit drain one time only - if (ctx->delayed_surface != NULL) { - ctx->delayed_drain = 1; // input queue is full: resubmit Drain() in ff_amf_receive_packet - } else if(!ctx->delayed_drain) { + if(!ctx->delayed_drain) { res = ctx->encoder->pVtbl->Drain(ctx->encoder); if (res == AMF_INPUT_FULL) { ctx->delayed_drain = 1; // input queue is full: resubmit Drain() in ff_amf_receive_packet @@ -678,7 +443,7 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) } } } - } else if (!ctx->delayed_surface) { // submit frame + } else { // submit frame int hw_surface = 0; // prepare surface from frame @@ -690,12 +455,12 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) ID3D11Texture2D *texture = (ID3D11Texture2D*)frame->data[0]; // actual texture int index = (intptr_t)frame->data[1]; // index is a slice in texture array is - set to tell AMF which slice to use - av_assert0(frame->hw_frames_ctx && ctx->hw_frames_ctx && - frame->hw_frames_ctx->data == ctx->hw_frames_ctx->data); + av_assert0(frame->hw_frames_ctx && avctx->hw_frames_ctx && + frame->hw_frames_ctx->data == avctx->hw_frames_ctx->data); texture->lpVtbl->SetPrivateData(texture, &AMFTextureArrayIndexGUID, sizeof(index), &index); - res = ctx->context->pVtbl->CreateSurfaceFromDX11Native(ctx->context, texture, &surface, NULL); // wrap to AMF surface + res = ctx->amf_device_ctx->context->pVtbl->CreateSurfaceFromDX11Native(ctx->amf_device_ctx->context, texture, &surface, NULL); // wrap to AMF surface AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX11Native() failed with error %d\n", res); hw_surface = 1; @@ -707,16 +472,23 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) { IDirect3DSurface9 *texture = (IDirect3DSurface9 *)frame->data[3]; // actual texture - res = ctx->context->pVtbl->CreateSurfaceFromDX9Native(ctx->context, texture, &surface, NULL); // wrap to AMF surface + res = ctx->amf_device_ctx->context->pVtbl->CreateSurfaceFromDX9Native(ctx->amf_device_ctx->context, texture, &surface, NULL); // wrap to AMF surface AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX9Native() failed with error %d\n", res); hw_surface = 1; } break; #endif + case AV_PIX_FMT_AMF_SURFACE: + { + surface = (AMFSurface*)frame->data[0]; + surface->pVtbl->Acquire(surface); + hw_surface = 1; + } + break; default: { - res = ctx->context->pVtbl->AllocSurface(ctx->context, AMF_MEMORY_HOST, ctx->format, avctx->width, avctx->height, &surface); + res = ctx->amf_device_ctx->context->pVtbl->AllocSurface(ctx->amf_device_ctx->context, AMF_MEMORY_HOST, ctx->format, avctx->width, avctx->height, &surface); AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "AllocSurface() failed with error %d\n", res); amf_copy_surface(avctx, frame, surface); } @@ -729,7 +501,7 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) // input HW surfaces can be vertically aligned by 16; tell AMF the real size surface->pVtbl->SetCrop(surface, 0, 0, frame->width, frame->height); - frame_ref_storage_buffer = amf_create_buffer_with_frame_ref(frame, ctx->context); + frame_ref_storage_buffer = amf_create_buffer_with_frame_ref(frame, ctx->amf_device_ctx->context); AMF_RETURN_IF_FALSE(ctx, frame_ref_storage_buffer != NULL, AVERROR(ENOMEM), "create_buffer_with_frame_ref() returned NULL\n"); res = amf_set_property_buffer(surface, L"av_frame_ref", frame_ref_storage_buffer); @@ -741,7 +513,7 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) // HDR10 metadata if (frame->color_trc == AVCOL_TRC_SMPTE2084) { AMFBuffer * hdrmeta_buffer = NULL; - res = ctx->context->pVtbl->AllocBuffer(ctx->context, AMF_MEMORY_HOST, sizeof(AMFHDRMetadata), &hdrmeta_buffer); + res = ctx->amf_device_ctx->context->pVtbl->AllocBuffer(ctx->amf_device_ctx->context, AMF_MEMORY_HOST, sizeof(AMFHDRMetadata), &hdrmeta_buffer); if (res == AMF_OK) { AMFHDRMetadata * hdrmeta = (AMFHDRMetadata*)hdrmeta_buffer->pVtbl->GetNative(hdrmeta_buffer); if (amf_save_hdr_metadata(avctx, frame, hdrmeta) == 0) { @@ -750,8 +522,6 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->encoder, AMF_VIDEO_ENCODER_INPUT_HDR_METADATA, hdrmeta_buffer); break; case AV_CODEC_ID_HEVC: AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_INPUT_HDR_METADATA, hdrmeta_buffer); break; - case AV_CODEC_ID_AV1: - AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_INPUT_HDR_METADATA, hdrmeta_buffer); break; } res = amf_set_property_buffer(surface, L"av_frame_hdrmeta", hdrmeta_buffer); AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, "SetProperty failed for \"av_frame_hdrmeta\" with error %d\n", res); @@ -778,13 +548,11 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) // submit surface res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)surface); if (res == AMF_INPUT_FULL) { // handle full queue - //store surface for later submission - ctx->delayed_surface = surface; + av_usleep(1000); // wait and poll again } else { int64_t pts = frame->pts; surface->pVtbl->Release(surface); AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SubmitInput() failed with error %d\n", res); - av_frame_unref(frame); ret = av_fifo_write(ctx->timestamp_list, &pts, 1); if (ret < 0) @@ -796,73 +564,40 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) do { block_and_wait = 0; // poll data - if (!avpkt->data && !avpkt->buf) { - res_query = ctx->encoder->pVtbl->QueryOutput(ctx->encoder, &data); - if (data) { - // copy data to packet - AMFBuffer *buffer; - AMFGuid guid = IID_AMFBuffer(); - query_output_data_flag = 1; - data->pVtbl->QueryInterface(data, &guid, (void**)&buffer); // query for buffer interface - ret = amf_copy_buffer(avctx, avpkt, buffer); - - buffer->pVtbl->Release(buffer); - - if (data->pVtbl->HasProperty(data, L"av_frame_ref")) { - AMFBuffer* frame_ref_storage_buffer; - res = amf_get_property_buffer(data, L"av_frame_ref", &frame_ref_storage_buffer); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetProperty failed for \"av_frame_ref\" with error %d\n", res); - amf_release_buffer_with_frame_ref(frame_ref_storage_buffer); - ctx->hwsurfaces_in_queue--; - } + res_query = ctx->encoder->pVtbl->QueryOutput(ctx->encoder, &data); + if (data) { + // copy data to packet + AMFBuffer* buffer; + AMFGuid guid = IID_AMFBuffer(); + data->pVtbl->QueryInterface(data, &guid, (void**)&buffer); // query for buffer interface + ret = amf_copy_buffer(avctx, avpkt, buffer); + + buffer->pVtbl->Release(buffer); + + if (data->pVtbl->HasProperty(data, L"av_frame_ref")) { + AMFBuffer *frame_ref_storage_buffer; + res = amf_get_property_buffer(data, L"av_frame_ref", &frame_ref_storage_buffer); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetProperty failed for \"av_frame_ref\" with error %d\n", res); + amf_release_buffer_with_frame_ref(frame_ref_storage_buffer); + ctx->hwsurfaces_in_queue--; + } + data->pVtbl->Release(data); - data->pVtbl->Release(data); + AMF_RETURN_IF_FALSE(ctx, ret >= 0, ret, "amf_copy_buffer() failed with error %d\n", ret); - AMF_RETURN_IF_FALSE(ctx, ret >= 0, ret, "amf_copy_buffer() failed with error %d\n", ret); - } - } - res_resubmit = AMF_OK; - if (ctx->delayed_surface != NULL) { // try to resubmit frame - if (ctx->delayed_surface->pVtbl->HasProperty(ctx->delayed_surface, L"av_frame_hdrmeta")) { - AMFBuffer * hdrmeta_buffer = NULL; - res = amf_get_property_buffer((AMFData *)ctx->delayed_surface, L"av_frame_hdrmeta", &hdrmeta_buffer); - AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, "GetProperty failed for \"av_frame_hdrmeta\" with error %d\n", res); - switch (avctx->codec->id) { - case AV_CODEC_ID_H264: - AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->encoder, AMF_VIDEO_ENCODER_INPUT_HDR_METADATA, hdrmeta_buffer); break; - case AV_CODEC_ID_HEVC: - AMF_ASSIGN_PROPERTY_INTERFACE(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_INPUT_HDR_METADATA, hdrmeta_buffer); break; + if (ctx->delayed_drain) { // try to resubmit drain + res = ctx->encoder->pVtbl->Drain(ctx->encoder); + if (res != AMF_INPUT_FULL) { + ctx->delayed_drain = 0; + ctx->eof = 1; // drain started + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Repeated Drain() failed with error %d\n", res); + } else { + av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed drain submission got AMF_INPUT_FULL- should not happen\n"); } - hdrmeta_buffer->pVtbl->Release(hdrmeta_buffer); - } - res_resubmit = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)ctx->delayed_surface); - if (res_resubmit != AMF_INPUT_FULL) { - int64_t pts = ctx->delayed_surface->pVtbl->GetPts(ctx->delayed_surface); - ctx->delayed_surface->pVtbl->Release(ctx->delayed_surface); - ctx->delayed_surface = NULL; - av_frame_unref(ctx->delayed_frame); - AMF_RETURN_IF_FALSE(ctx, res_resubmit == AMF_OK, AVERROR_UNKNOWN, "Repeated SubmitInput() failed with error %d\n", res_resubmit); - - ret = av_fifo_write(ctx->timestamp_list, &pts, 1); - if (ret < 0) - return ret; - } - } else if (ctx->delayed_drain) { // try to resubmit drain - res = ctx->encoder->pVtbl->Drain(ctx->encoder); - if (res != AMF_INPUT_FULL) { - ctx->delayed_drain = 0; - ctx->eof = 1; // drain started - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Repeated Drain() failed with error %d\n", res); - } else { - av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed drain submission got AMF_INPUT_FULL- should not happen\n"); - } - } - - if (query_output_data_flag == 0) { - if (res_resubmit == AMF_INPUT_FULL || ctx->delayed_drain || (ctx->eof && res_query != AMF_EOF) || (ctx->hwsurfaces_in_queue >= ctx->hwsurfaces_in_queue_max)) { - block_and_wait = 1; - av_usleep(1000); } + } else if (ctx->delayed_drain || (ctx->eof && res_query != AMF_EOF) || (ctx->hwsurfaces_in_queue >= ctx->hwsurfaces_in_queue_max)) { + block_and_wait = 1; + av_usleep(1000); // wait and poll again } } while (block_and_wait); @@ -920,5 +655,7 @@ const AVCodecHWConfigInternal *const ff_amfenc_hw_configs[] = { HW_CONFIG_ENCODER_FRAMES(DXVA2_VLD, DXVA2), HW_CONFIG_ENCODER_DEVICE(NONE, DXVA2), #endif + HW_CONFIG_ENCODER_FRAMES(AMF_SURFACE, AMF), + HW_CONFIG_ENCODER_DEVICE(NONE, AMF), NULL, }; diff --git a/libavcodec/amfenc.h b/libavcodec/amfenc.h index 1bda0136bd..8fc411d44d 100644 --- a/libavcodec/amfenc.h +++ b/libavcodec/amfenc.h @@ -25,54 +25,34 @@ #include <AMF/components/VideoEncoderVCE.h> #include <AMF/components/VideoEncoderHEVC.h> #include <AMF/components/VideoEncoderAV1.h> - +#include "libavutil/hwcontext_amf.h" #include "libavutil/fifo.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "hwconfig.h" #define MAX_LOOKAHEAD_DEPTH 41 -/** -* AMF trace writer callback class -* Used to capture all AMF logging -*/ - -typedef struct AmfTraceWriter { - AMFTraceWriterVtbl *vtbl; - AVCodecContext *avctx; -} AmfTraceWriter; - /** * AMF encoder context */ -typedef struct AmfContext { +typedef struct AMFEncoderContext { AVClass *avclass; // access to AMF runtime - amf_handle library; ///< handle to DLL library - AMFFactory *factory; ///< pointer to AMF factory - AMFDebug *debug; ///< pointer to AMF debug interface - AMFTrace *trace; ///< pointer to AMF trace interface - - amf_uint64 version; ///< version of AMF runtime - AmfTraceWriter tracer; ///< AMF writer registered with AMF - AMFContext *context; ///< AMF context + AVAMFDeviceContext *amf_device_ctx; + int *local_context; //encoder AMFComponent *encoder; ///< AMF encoder object amf_bool eof; ///< flag indicating EOF happened AMF_SURFACE_FORMAT format; ///< AMF surface format - AVBufferRef *hw_device_ctx; ///< pointer to HW accelerator (decoder) - AVBufferRef *hw_frames_ctx; ///< pointer to HW accelerator (frame allocator) - int hwsurfaces_in_queue; int hwsurfaces_in_queue_max; // helpers to handle async calls int delayed_drain; - AMFSurface *delayed_surface; - AVFrame *delayed_frame; // shift dts back by max_b_frames in timing AVFifo *timestamp_list; @@ -149,7 +129,7 @@ typedef struct AmfContext { int pa_adaptive_mini_gop; -} AmfContext; +} AMFEncoderContext; extern const AVCodecHWConfigInternal *const ff_amfenc_hw_configs[]; diff --git a/libavcodec/amfenc_av1.c b/libavcodec/amfenc_av1.c index 7d37a242fc..8edde12950 100644 --- a/libavcodec/amfenc_av1.c +++ b/libavcodec/amfenc_av1.c @@ -17,12 +17,12 @@ */ #include "libavutil/internal.h" -#include "libavutil/mem.h" #include "libavutil/opt.h" #include "amfenc.h" #include "codec_internal.h" +#include "internal.h" -#define OFFSET(x) offsetof(AmfContext, x) +#define OFFSET(x) offsetof(AMFEncoderContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { { "usage", "Set the encoding usage", OFFSET(usage), AV_OPT_TYPE_INT, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_TRANSCODING }, AMF_VIDEO_ENCODER_AV1_USAGE_TRANSCODING, AMF_VIDEO_ENCODER_AV1_USAGE_LOW_LATENCY, VE, .unit = "usage" }, @@ -159,7 +159,7 @@ static av_cold int amf_encode_init_av1(AVCodecContext* avctx) { int ret = 0; AMF_RESULT res = AMF_OK; - AmfContext* ctx = avctx->priv_data; + AMFEncoderContext* ctx = avctx->priv_data; AMFVariantStruct var = { 0 }; amf_int64 profile = 0; amf_int64 profile_level = 0; @@ -518,7 +518,7 @@ const FFCodec ff_av1_amf_encoder = { .init = amf_encode_init_av1, FF_CODEC_RECEIVE_PACKET_CB(ff_amf_receive_packet), .close = ff_amf_encode_close, - .priv_data_size = sizeof(AmfContext), + .priv_data_size = sizeof(AMFEncoderContext), .p.priv_class = &av1_amf_class, .defaults = defaults, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE | diff --git a/libavcodec/amfenc_h264.c b/libavcodec/amfenc_h264.c index a26a6dbef8..09f1ebf9d4 100644 --- a/libavcodec/amfenc_h264.c +++ b/libavcodec/amfenc_h264.c @@ -18,13 +18,13 @@ #include "libavutil/internal.h" -#include "libavutil/mem.h" #include "libavutil/opt.h" #include "amfenc.h" #include "codec_internal.h" +#include "internal.h" #include <AMF/components/PreAnalysis.h> -#define OFFSET(x) offsetof(AmfContext, x) +#define OFFSET(x) offsetof(AMFEncoderContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { @@ -192,7 +192,7 @@ static av_cold int amf_encode_init_h264(AVCodecContext *avctx) { int ret = 0; AMF_RESULT res = AMF_OK; - AmfContext *ctx = avctx->priv_data; + AMFEncoderContext *ctx = avctx->priv_data; AMFVariantStruct var = { 0 }; amf_int64 profile = 0; amf_int64 profile_level = 0; @@ -565,7 +565,7 @@ const FFCodec ff_h264_amf_encoder = { .init = amf_encode_init_h264, FF_CODEC_RECEIVE_PACKET_CB(ff_amf_receive_packet), .close = ff_amf_encode_close, - .priv_data_size = sizeof(AmfContext), + .priv_data_size = sizeof(AMFEncoderContext), .p.priv_class = &h264_amf_class, .defaults = defaults, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE | diff --git a/libavcodec/amfenc_hevc.c b/libavcodec/amfenc_hevc.c index 8c26956513..35698c26c8 100644 --- a/libavcodec/amfenc_hevc.c +++ b/libavcodec/amfenc_hevc.c @@ -17,13 +17,13 @@ */ #include "libavutil/internal.h" -#include "libavutil/mem.h" #include "libavutil/opt.h" #include "amfenc.h" #include "codec_internal.h" +#include "internal.h" #include <AMF/components/PreAnalysis.h> -#define OFFSET(x) offsetof(AmfContext, x) +#define OFFSET(x) offsetof(AMFEncoderContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { { "usage", "Set the encoding usage", OFFSET(usage), AV_OPT_TYPE_INT, {.i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_TRANSCODING }, AMF_VIDEO_ENCODER_HEVC_USAGE_TRANSCODING, AMF_VIDEO_ENCODER_HEVC_USAGE_LOW_LATENCY_HIGH_QUALITY, VE, .unit = "usage" }, @@ -34,9 +34,9 @@ static const AVOption options[] = { { "high_quality", "high quality trancoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_HIGH_QUALITY }, 0, 0, VE, .unit = "usage" }, { "lowlatency_high_quality","low latency yet high quality trancoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_LOW_LATENCY_HIGH_QUALITY }, 0, 0, VE, .unit = "usage" }, - { "profile", "Set the profile (default main)", OFFSET(profile), AV_OPT_TYPE_INT,{ .i64 = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN }, AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN, AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN_10, VE, .unit = "profile" }, - { "main", "", 0, AV_OPT_TYPE_CONST,{ .i64 = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN }, 0, 0, VE, .unit = "profile" }, - { "main10", "", 0, AV_OPT_TYPE_CONST,{ .i64 = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN_10 }, 0, 0, VE, .unit = "profile" }, + { "profile", "Set the profile (default main)", OFFSET(profile), AV_OPT_TYPE_INT,{ .i64 = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN }, AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN, AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN_10, VE, "profile" }, + { "main", "", 0, AV_OPT_TYPE_CONST,{ .i64 = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN }, 0, 0, VE, "profile" }, + { "main10", "", 0, AV_OPT_TYPE_CONST,{ .i64 = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN_10 }, 0, 0, VE, "profile" }, { "profile_tier", "Set the profile tier (default main)", OFFSET(tier), AV_OPT_TYPE_INT,{ .i64 = AMF_VIDEO_ENCODER_HEVC_TIER_MAIN }, AMF_VIDEO_ENCODER_HEVC_TIER_MAIN, AMF_VIDEO_ENCODER_HEVC_TIER_HIGH, VE, .unit = "tier" }, { "main", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_TIER_MAIN }, 0, 0, VE, .unit = "tier" }, @@ -154,7 +154,7 @@ static av_cold int amf_encode_init_hevc(AVCodecContext *avctx) { int ret = 0; AMF_RESULT res = AMF_OK; - AmfContext *ctx = avctx->priv_data; + AMFEncoderContext *ctx = avctx->priv_data; AMFVariantStruct var = {0}; amf_int64 profile = 0; amf_int64 profile_level = 0; @@ -488,7 +488,7 @@ const FFCodec ff_hevc_amf_encoder = { .init = amf_encode_init_hevc, FF_CODEC_RECEIVE_PACKET_CB(ff_amf_receive_packet), .close = ff_amf_encode_close, - .priv_data_size = sizeof(AmfContext), + .priv_data_size = sizeof(AMFEncoderContext), .p.priv_class = &hevc_amf_class, .defaults = defaults, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE | -- 2.39.3 (Apple Git-146) _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".