X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Famfenc.c;h=384d8efc92cf894014b4314cf5998abcfcb5f7bf;hb=6cc8cfe30c09b1776b935988fcdedf0333602f8e;hp=65a8e0a85323eae54dbe8fbab7533b4555acc8f9;hpb=73ed6fa9d77da8cd4f34742dd0f56e64aa714786;p=ffmpeg diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c index 65a8e0a8532..384d8efc92c 100644 --- a/libavcodec/amfenc.c +++ b/libavcodec/amfenc.c @@ -24,6 +24,10 @@ #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" @@ -50,6 +54,9 @@ const enum AVPixelFormat ff_amf_pix_fmts[] = { AV_PIX_FMT_YUV420P, #if CONFIG_D3D11VA AV_PIX_FMT_D3D11, +#endif +#if CONFIG_DXVA2 + AV_PIX_FMT_DXVA2_VLD, #endif AV_PIX_FMT_NONE }; @@ -68,7 +75,6 @@ static const FormatMap format_map[] = { 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 enum AMF_SURFACE_FORMAT amf_av_to_amf_format(enum AVPixelFormat fmt) @@ -101,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); @@ -163,6 +164,52 @@ static int amf_init_from_d3d11_device(AVCodecContext *avctx, AVD3D11VADeviceCont } #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; @@ -206,6 +253,13 @@ static int amf_init_context(AVCodecContext *avctx) 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", @@ -230,6 +284,13 @@ static int amf_init_context(AVCodecContext *avctx) 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", @@ -260,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: @@ -276,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); @@ -287,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; } @@ -329,11 +397,11 @@ int av_cold ff_amf_encode_close(AVCodecContext *avctx) static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame, AMFSurface* surface) { - AMFPlane *plane = NULL; - uint8_t *dst_data[4]; - int dst_linesize[4]; - int planes; - int i; + 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)); @@ -364,11 +432,11 @@ static inline int timestamp_queue_enqueue(AVCodecContext *avctx, int64_t timesta 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); + 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; @@ -424,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) { @@ -514,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); @@ -574,6 +629,18 @@ int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame) 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: {