diff options
Diffstat (limited to 'libavcodec/amfenc.c')
-rw-r--r-- | libavcodec/amfenc.c | 449 |
1 files changed, 263 insertions, 186 deletions
diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c index 9a60050..384d8ef 100644 --- a/libavcodec/amfenc.c +++ b/libavcodec/amfenc.c @@ -1,52 +1,51 @@ /* - * AMD AMF support - * Copyright (C) 2017 Luca Barbato - * Copyright (C) 2017 Mikhail Mironov <mikhail.mironov@amd.com> + * This file is part of FFmpeg. * - * This file is part of Libav. - * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" + #include "libavutil/avassert.h" #include "libavutil/imgutils.h" #include "libavutil/hwcontext.h" -#include "internal.h" #if CONFIG_D3D11VA #include "libavutil/hwcontext_d3d11va.h" #endif +#if CONFIG_DXVA2 +#define COBJMACROS +#include "libavutil/hwcontext_dxva2.h" +#endif #include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/time.h" #include "amfenc.h" +#include "internal.h" #if CONFIG_D3D11VA #include <d3d11.h> #endif -#if HAVE_WINDOWS_H -#include <windows.h> -#define dlopen(filename, flags) LoadLibrary((filename)) -#define dlsym(handle, symbol) GetProcAddress(handle, symbol) -#define dlclose(handle) FreeLibrary(handle) +#ifdef _WIN32 +#include "compat/w32dlfcn.h" #else #include <dlfcn.h> #endif -#define LIBAV_AMF_WRITER_ID L"libav_log" +#define FFMPEG_AMF_WRITER_ID L"ffmpeg_amf" #define PTS_PROP L"PtsProp" @@ -56,6 +55,9 @@ const enum AVPixelFormat ff_amf_pix_fmts[] = { #if CONFIG_D3D11VA AV_PIX_FMT_D3D11, #endif +#if CONFIG_DXVA2 + AV_PIX_FMT_DXVA2_VLD, +#endif AV_PIX_FMT_NONE }; @@ -68,22 +70,13 @@ static const FormatMap format_map[] = { { AV_PIX_FMT_NONE, AMF_SURFACE_UNKNOWN }, { AV_PIX_FMT_NV12, AMF_SURFACE_NV12 }, -// { AV_PIX_FMT_BGR0, AMF_SURFACE_BGRA }, -// { AV_PIX_FMT_RGB0, AMF_SURFACE_RGBA }, + { 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 }, - { AV_PIX_FMT_D3D11, AMF_SURFACE_NV12 }, }; - -static int is_hwaccel_pix_fmt(enum AVPixelFormat pix_fmt) -{ - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); - return desc->flags & AV_PIX_FMT_FLAG_HWACCEL; -} - - static enum AMF_SURFACE_FORMAT amf_av_to_amf_format(enum AVPixelFormat fmt) { int i; @@ -114,16 +107,11 @@ static AMFTraceWriterVtbl tracer_vtbl = static int amf_load_library(AVCodecContext *avctx) { - AmfContext *ctx = avctx->priv_data; - AMFInit_Fn init_fun = NULL; - AMFQueryVersion_Fn version_fun = NULL; - AMF_RESULT res = AMF_OK; + AmfContext *ctx = avctx->priv_data; + AMFInit_Fn init_fun; + AMFQueryVersion_Fn version_fun; + AMF_RESULT res; - ctx->eof = 0; - ctx->delayed_drain = 0; - ctx->hw_frames_ctx = NULL; - ctx->hw_device_ctx = NULL; - ctx->delayed_surface = NULL; ctx->delayed_frame = av_frame_alloc(); if (!ctx->delayed_frame) { return AVERROR(ENOMEM); @@ -157,10 +145,76 @@ static int amf_load_library(AVCodecContext *avctx) 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; - AMF_RESULT res = AMF_OK; + AmfContext *ctx = avctx->priv_data; + AMF_RESULT res; + av_unused int ret; ctx->hwsurfaces_in_queue = 0; ctx->hwsurfaces_in_queue_max = 16; @@ -176,64 +230,90 @@ static int amf_init_context(AVCodecContext *avctx) // connect AMF logger to av_log ctx->tracer.vtbl = &tracer_vtbl; ctx->tracer.avctx = avctx; - ctx->trace->pVtbl->RegisterWriter(ctx->trace, LIBAV_AMF_WRITER_ID,(AMFTraceWriter *)&ctx->tracer, 1); - ctx->trace->pVtbl->SetWriterLevel(ctx->trace, LIBAV_AMF_WRITER_ID, AMF_TRACE_TRACE); + 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); - // try to reuse existing DX device -#if CONFIG_D3D11VA + + // If a device was passed to the encoder, try to initialise from that. if (avctx->hw_frames_ctx) { - AVHWFramesContext *device_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - if (device_ctx->device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) { - if (amf_av_to_amf_format(device_ctx->sw_format) != AMF_SURFACE_UNKNOWN) { - if (device_ctx->device_ctx->hwctx) { - AVD3D11VADeviceContext *device_d3d11 = (AVD3D11VADeviceContext *)device_ctx->device_ctx->hwctx; - res = ctx->context->pVtbl->InitDX11(ctx->context, device_d3d11->device, AMF_DX11_1); - if (res == AMF_OK) { - ctx->hw_frames_ctx = av_buffer_ref(avctx->hw_frames_ctx); - if (!ctx->hw_frames_ctx) { - return AVERROR(ENOMEM); - } - if (device_ctx->initial_pool_size > 0) - ctx->hwsurfaces_in_queue_max = device_ctx->initial_pool_size - 1; - } else { - if(res == AMF_NOT_SUPPORTED) - av_log(avctx, AV_LOG_INFO, "avctx->hw_frames_ctx has D3D11 device which doesn't have D3D11VA interface, switching to default\n"); - else - av_log(avctx, AV_LOG_INFO, "avctx->hw_frames_ctx has non-AMD device, switching to default\n"); - } - } - } else { - av_log(avctx, AV_LOG_INFO, "avctx->hw_frames_ctx has format not uspported by AMF, switching to default\n"); - } + 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); } - } else if (avctx->hw_device_ctx) { - AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)(avctx->hw_device_ctx->data); - if (device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) { - if (device_ctx->hwctx) { - AVD3D11VADeviceContext *device_d3d11 = (AVD3D11VADeviceContext *)device_ctx->hwctx; - res = ctx->context->pVtbl->InitDX11(ctx->context, device_d3d11->device, AMF_DX11_1); - if (res == AMF_OK) { - ctx->hw_device_ctx = av_buffer_ref(avctx->hw_device_ctx); - if (!ctx->hw_device_ctx) { - return AVERROR(ENOMEM); - } - } else { - if (res == AMF_NOT_SUPPORTED) - av_log(avctx, AV_LOG_INFO, "avctx->hw_device_ctx has D3D11 device which doesn't have D3D11VA interface, switching to default\n"); - else - av_log(avctx, AV_LOG_INFO, "avctx->hw_device_ctx has non-AMD device, switching to default\n"); - } - } + + 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 (!ctx->hw_frames_ctx && !ctx->hw_device_ctx) { +#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) { + 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); - AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "InitDX9() failed with error %d\n", res); + if (res == AMF_OK) { + av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D9.\n"); + } else { + av_log(avctx, AV_LOG_ERROR, "AMF initialisation failed via D3D9: error %d.\n", res); + return AVERROR(ENOSYS); + } } } return 0; @@ -241,9 +321,10 @@ static int amf_init_context(AVCodecContext *avctx) static int amf_init_encoder(AVCodecContext *avctx) { - AmfContext *ctx = avctx->priv_data; - const wchar_t *codec_id = NULL; - AMF_RESULT res = AMF_OK; + AmfContext *ctx = avctx->priv_data; + const wchar_t *codec_id = NULL; + AMF_RESULT res; + enum AVPixelFormat pix_fmt; switch (avctx->codec->id) { case AV_CODEC_ID_H264: @@ -257,8 +338,14 @@ 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); - ctx->format = amf_av_to_amf_format(avctx->pix_fmt); - AMF_RETURN_IF_FALSE(ctx, ctx->format != AMF_SURFACE_UNKNOWN, AVERROR(EINVAL), "Format %d is not supported\n", avctx->pix_fmt); + if (ctx->hw_frames_ctx) + pix_fmt = ((AVHWFramesContext*)ctx->hw_frames_ctx->data)->sw_format; + else + pix_fmt = avctx->pix_fmt; + + ctx->format = amf_av_to_amf_format(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)); res = ctx->factory->pVtbl->CreateComponent(ctx->factory, ctx->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); @@ -268,9 +355,9 @@ static int amf_init_encoder(AVCodecContext *avctx) int av_cold ff_amf_encode_close(AVCodecContext *avctx) { - AmfContext *ctx = avctx->priv_data; - if (ctx->delayed_surface) - { + AmfContext *ctx = avctx->priv_data; + + if (ctx->delayed_surface) { ctx->delayed_surface->pVtbl->Release(ctx->delayed_surface); ctx->delayed_surface = NULL; } @@ -290,7 +377,7 @@ int av_cold ff_amf_encode_close(AVCodecContext *avctx) av_buffer_unref(&ctx->hw_frames_ctx); if (ctx->trace) { - ctx->trace->pVtbl->UnregisterWriter(ctx->trace, LIBAV_AMF_WRITER_ID); + ctx->trace->pVtbl->UnregisterWriter(ctx->trace, FFMPEG_AMF_WRITER_ID); } if (ctx->library) { dlclose(ctx->library); @@ -302,9 +389,7 @@ int av_cold ff_amf_encode_close(AVCodecContext *avctx) ctx->version = 0; ctx->delayed_drain = 0; av_frame_free(&ctx->delayed_frame); - av_fifo_free(ctx->timestamp_list); - ctx->timestamp_list = NULL; - ctx->timestamp_last = 0; + av_fifo_freep(&ctx->timestamp_list); return 0; } @@ -312,32 +397,14 @@ int av_cold ff_amf_encode_close(AVCodecContext *avctx) static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame, AMFSurface* surface) { - AVFrame *sw_frame = NULL; - AMFPlane *plane = NULL; - uint8_t *dst_data[4]; - int dst_linesize[4]; - int ret = 0; - int planes; - int i; - - if (frame->hw_frames_ctx && is_hwaccel_pix_fmt(frame->format)) { - if (!(sw_frame = av_frame_alloc())) { - av_log(avctx, AV_LOG_ERROR, "Can not alloc frame\n"); - ret = AVERROR(ENOMEM); - goto fail; - } - if ((ret = av_hwframe_transfer_data(sw_frame, frame, 0)) < 0) { - av_log(avctx, AV_LOG_ERROR, "Error transferring the data to system memory\n"); - goto fail; - } - frame = sw_frame; - } - planes = (int)surface->pVtbl->GetPlanesCount(surface); - if (planes > amf_countof(dst_data)) { - av_log(avctx, AV_LOG_ERROR, "Invalid number of planes %d in surface\n", planes); - ret = AVERROR(EINVAL); - goto fail; - } + AMFPlane *plane; + uint8_t *dst_data[4]; + int dst_linesize[4]; + int planes; + int i; + + planes = surface->pVtbl->GetPlanesCount(surface); + av_assert0(planes < FF_ARRAY_ELEMS(dst_data)); for (i = 0; i < planes; i++) { plane = surface->pVtbl->GetPlaneAt(surface, i); @@ -348,37 +415,30 @@ static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame, (const uint8_t**)frame->data, frame->linesize, frame->format, avctx->width, avctx->height); -fail: - if (sw_frame) { - av_frame_free(&sw_frame); - } - return ret; + return 0; } static inline int timestamp_queue_enqueue(AVCodecContext *avctx, int64_t timestamp) { AmfContext *ctx = avctx->priv_data; if (av_fifo_space(ctx->timestamp_list) < sizeof(timestamp)) { - int size = av_fifo_size(ctx->timestamp_list); - if (INT_MAX / 2 - size < sizeof(timestamp)) - return AVERROR(EINVAL); - av_fifo_realloc2(ctx->timestamp_list, (size + sizeof(timestamp)) * 2); + if (av_fifo_grow(ctx->timestamp_list, sizeof(timestamp)) < 0) { + return AVERROR(ENOMEM); + } } av_fifo_generic_write(ctx->timestamp_list, ×tamp, sizeof(timestamp), NULL); - ctx->timestamp_last = timestamp; return 0; } static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buffer) { - AmfContext *ctx = avctx->priv_data; - int ret; - AMFVariantStruct var = {0}; - int64_t timestamp = AV_NOPTS_VALUE; - int64_t size = buffer->pVtbl->GetSize(buffer); - - //if ((ret = ff_alloc_packet2(avctx, pkt, size, 0)) < 0) { - if (ret = ff_alloc_packet(pkt, size)) { + AmfContext *ctx = avctx->priv_data; + int ret; + AMFVariantStruct var = {0}; + int64_t timestamp = AV_NOPTS_VALUE; + int64_t size = buffer->pVtbl->GetSize(buffer); + + if ((ret = ff_alloc_packet2(avctx, pkt, size, 0)) < 0) { return ret; } memcpy(pkt->data, buffer->pVtbl->GetNative(buffer), size); @@ -411,13 +471,19 @@ static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buff // calc dts shift if max_b_frames > 0 if (avctx->max_b_frames > 0 && ctx->dts_delay == 0) { + int64_t timestamp_last = AV_NOPTS_VALUE; AMF_RETURN_IF_FALSE(ctx, av_fifo_size(ctx->timestamp_list) > 0, AVERROR_UNKNOWN, "timestamp_list is empty while max_b_frames = %d\n", avctx->max_b_frames); - - if (timestamp < 0 || ctx->timestamp_last < AV_NOPTS_VALUE) { + av_fifo_generic_peek_at( + ctx->timestamp_list, + ×tamp_last, + (av_fifo_size(ctx->timestamp_list) / sizeof(timestamp) - 1) * sizeof(timestamp_last), + sizeof(timestamp_last), + NULL); + if (timestamp < 0 || timestamp_last < AV_NOPTS_VALUE) { return AVERROR(ERANGE); } - ctx->dts_delay = ctx->timestamp_last - timestamp; + ctx->dts_delay = timestamp_last - timestamp; } pkt->dts = timestamp - ctx->dts_delay; return 0; @@ -426,20 +492,7 @@ static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buff // amfenc API implementation int ff_amf_encode_init(AVCodecContext *avctx) { - AmfContext *ctx = avctx->priv_data; - int ret; - - ctx->factory = NULL; - ctx->debug = NULL; - ctx->trace = NULL; - ctx->context = NULL; - ctx->encoder = NULL; - ctx->library = NULL; - ctx->version = 0; - ctx->eof = 0; - ctx->format = 0; - ctx->tracer.vtbl = NULL; - ctx->tracer.avctx = NULL; + int ret; if ((ret = amf_load_library(avctx)) == 0) { if ((ret = amf_init_context(avctx)) == 0) { @@ -516,18 +569,18 @@ static AMFBuffer *amf_create_buffer_with_frame_ref(const AVFrame *frame, AMFCont static void amf_release_buffer_with_frame_ref(AMFBuffer *frame_ref_storage_buffer) { - AVFrame *av_frame_ref; - memcpy(&av_frame_ref, frame_ref_storage_buffer->pVtbl->GetNative(frame_ref_storage_buffer), sizeof(av_frame_ref)); - av_frame_free(&av_frame_ref); + AVFrame *frame_ref; + memcpy(&frame_ref, frame_ref_storage_buffer->pVtbl->GetNative(frame_ref_storage_buffer), sizeof(frame_ref)); + av_frame_free(&frame_ref); frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer); } int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame) { - AMF_RESULT res = AMF_OK; - AmfContext *ctx = avctx->priv_data; - AMFSurface *surface = NULL; - int ret; + AmfContext *ctx = avctx->priv_data; + AMFSurface *surface; + AMF_RESULT res; + int ret; if (!ctx->encoder) return AVERROR(EINVAL); @@ -551,31 +604,58 @@ int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame) return AVERROR_EOF; } } else { // submit frame + int hw_surface = 0; + if (ctx->delayed_surface != NULL) { return AVERROR(EAGAIN); // should not happen when called from ffmpeg, other clients may resubmit } // prepare surface from frame - if (frame->hw_frames_ctx && ( // HW frame detected - // check if the same hw_frames_ctx as used in initialization - (ctx->hw_frames_ctx && frame->hw_frames_ctx->data == ctx->hw_frames_ctx->data) || - // check if the same hw_device_ctx as used in initialization - (ctx->hw_device_ctx && ((AVHWFramesContext*)frame->hw_frames_ctx->data)->device_ctx == - (AVHWDeviceContext*)ctx->hw_device_ctx->data) - )) { - AMFBuffer *frame_ref_storage_buffer; - + switch (frame->format) { #if CONFIG_D3D11VA - static const GUID AMFTextureArrayIndexGUID = { 0x28115527, 0xe7c3, 0x4b66, { 0x99, 0xd3, 0x4f, 0x2a, 0xe6, 0xb4, 0x7f, 0xaf } }; - ID3D11Texture2D *texture = (ID3D11Texture2D*)frame->data[0]; // actual texture - int index = (int)(size_t)frame->data[1]; // index is a slice in texture array is - set to tell AMF which slice to use - texture->lpVtbl->SetPrivateData(texture, &AMFTextureArrayIndexGUID, sizeof(index), &index); + case AV_PIX_FMT_D3D11: + { + static const GUID AMFTextureArrayIndexGUID = { 0x28115527, 0xe7c3, 0x4b66, { 0x99, 0xd3, 0x4f, 0x2a, 0xe6, 0xb4, 0x7f, 0xaf } }; + 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); + + texture->lpVtbl->SetPrivateData(texture, &AMFTextureArrayIndexGUID, sizeof(index), &index); + + res = ctx->context->pVtbl->CreateSurfaceFromDX11Native(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); - res = ctx->context->pVtbl->CreateSurfaceFromDX11Native(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; + } + break; +#endif +#if CONFIG_DXVA2 + case AV_PIX_FMT_DXVA2_VLD: + { + IDirect3DSurface9 *texture = (IDirect3DSurface9 *)frame->data[3]; // actual texture + + res = ctx->context->pVtbl->CreateSurfaceFromDX9Native(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 + default: + { + res = ctx->context->pVtbl->AllocSurface(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); + } + break; + } + + if (hw_surface) { + AMFBuffer *frame_ref_storage_buffer; // input HW surfaces can be vertically aligned by 16; tell AMF the real size surface->pVtbl->SetCrop(surface, 0, 0, frame->width, frame->height); -#endif frame_ref_storage_buffer = amf_create_buffer_with_frame_ref(frame, ctx->context); AMF_RETURN_IF_FALSE(ctx, frame_ref_storage_buffer != NULL, AVERROR(ENOMEM), "create_buffer_with_frame_ref() returned NULL\n"); @@ -584,11 +664,8 @@ int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame) AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SetProperty failed for \"av_frame_ref\" with error %d\n", res); ctx->hwsurfaces_in_queue++; frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer); - } else { - res = ctx->context->pVtbl->AllocSurface(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); } + surface->pVtbl->SetPts(surface, frame->pts); AMF_ASSIGN_PROPERTY_INT64(res, surface, PTS_PROP, frame->pts); |