PR #25149 opened by JuliusBairaktaris URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25149 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25149.patch
The AMF filters output AMF surfaces. A D3D11 consumer gets them only through hwdownload and a new upload, although on a D3D11VA-derived AMF device they already are textures on that device. - `avutil/hwcontext_amf: do not map to system memory for a hardware target`: hwmap to a hardware format now fails instead of passing a system memory frame on. - `avutil/hwcontext_amf: map AMF surfaces to D3D11 frames`: exports the texture and array slice; lavu 61.14.101 and an APIchanges entry. Usage: `-vf vqe_amf,hwmap=derive_device=d3d11va,format=d3d11` Not covered: DXVA2 and D3D12 targets, Linux. framemd5 over 300 frames matches the hwdownload path for vqe_amf, sr_amf, vpp_amf (scale and bgra) and 10-bit vqe_amf. 1200 frames, median of 3: utime 0.594 s → 0.219 s, stime 0.625 s → 0.266 s, rtime 1.306 s → 1.209 s. Tested on Windows 11, RX 9070 XT, driver 32.0.31041.1004. Written with Claude Opus 5.5 in Claude Code; `Assisted-by` trailers on the commits. From df7524ee55326acfd638128d9d309b5de408f2cf Mon Sep 17 00:00:00 2001 From: Julius Bairaktaris <[email protected]> Date: Mon, 28 Sep 2026 11:22:38 +0200 Subject: [PATCH 1/2] avutil/hwcontext_amf: do not map to system memory for a hardware target amf_map_frame() ignores dst->format and always maps to system memory. hwmap to a hardware format therefore passes a system memory frame down a hardware link, and the next filter fails. Return AVERROR(ENOSYS) for a hardware destination format. Mapping to system memory is unchanged. Assisted-by: Claude Opus 5.5 Signed-off-by: Julius Bairaktaris <[email protected]> --- libavutil/hwcontext_amf.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libavutil/hwcontext_amf.c b/libavutil/hwcontext_amf.c index 7f47df5b59..de785db68a 100644 --- a/libavutil/hwcontext_amf.c +++ b/libavutil/hwcontext_amf.c @@ -931,6 +931,10 @@ static int amf_map_frame(AVHWFramesContext *device_ctx, AVFrame *dst, const AVFr size_t plane_count = 0; int ret = -1; + if (dst->format != AV_PIX_FMT_NONE && + av_pix_fmt_desc_get(dst->format)->flags & AV_PIX_FMT_FLAG_HWACCEL) + return AVERROR(ENOSYS); + AMF_RETURN_IF_FALSE(device_ctx, surface != NULL, AVERROR(EINVAL) , "Source surface is null"); res = AMF_IFACE_CALL(surface, QueryInterface, &guid, (void**)&surface1); -- 2.54.0 From bdb29eff08a91db943e17be20655c2fda7385eb3 Mon Sep 17 00:00:00 2001 From: Julius Bairaktaris <[email protected]> Date: Mon, 28 Sep 2026 11:23:11 +0200 Subject: [PATCH 2/2] avutil/hwcontext_amf: map AMF surfaces to D3D11 frames AMF surfaces reach a D3D11 consumer only through hwdownload and a new upload, although on an AMF device derived from D3D11VA they already are textures on that device. Export the surface's texture and array slice as a D3D11 frame, converting the surface to AMF_MEMORY_DX11 first if needed. The mapping requires the AMF context to run on the target's D3D11 device and keeps a reference to the source frame, so it needs no unmap callback. hwmap does not restrict its output to the derived device, so format=d3d11 must follow it. Assisted-by: Claude Opus 5.5 Signed-off-by: Julius Bairaktaris <[email protected]> --- doc/APIchanges | 3 +++ libavutil/hwcontext_amf.c | 49 +++++++++++++++++++++++++++++++++++++++ libavutil/version.h | 2 +- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/doc/APIchanges b/doc/APIchanges index f7f9f5d9e1..cd93194770 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2026-06-23. API changes, most recent first: +2026-10-xx - xxxxxxxxxx - lavu 61.14.101 - hwcontext_amf.h + AMF frames can be mapped to D3D11 frames with av_hwframe_map(). + 2026-10-xx - xxxxxxxxxx - lavu 61.14.100 - gain_map.h Add av_gain_map_params_from_iso21496() and av_gain_map_params_to_iso21496(). Add AV_GAIN_MAP_MAX_PAYLOAD_SIZE. diff --git a/libavutil/hwcontext_amf.c b/libavutil/hwcontext_amf.c index de785db68a..6c30775d8f 100644 --- a/libavutil/hwcontext_amf.c +++ b/libavutil/hwcontext_amf.c @@ -919,6 +919,51 @@ static void amf_unmap_frame(av_unused AVHWFramesContext *unused, HWMapDescriptor AMF_IFACE_CALL(surface1, Release); } +#if CONFIG_D3D11VA +static int amf_map_to_d3d11(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src) +{ + AVAMFDeviceContext *amf_ctx = ctx->device_ctx->hwctx; + AVHWFramesContext *dst_fc; + AVD3D11VADeviceContext *d3d11_ctx; + static const GUID AMFTextureArrayIndexGUID = { 0x28115527, 0xe7c3, 0x4b66, { 0x99, 0xd3, 0x4f, 0x2a, 0xe6, 0xb4, 0x7f, 0xaf } }; + AMFSurface *surface = (AMFSurface *)src->data[0]; + ID3D11Texture2D *texture; + AMFPlane *plane; + UINT size = sizeof(int); + AMF_RESULT res; + int index = 0; + int ret; + + AMF_RETURN_IF_FALSE(ctx, surface, AVERROR(EINVAL), "Source surface is null\n"); + if (!dst->hw_frames_ctx) + return AVERROR(EINVAL); + dst_fc = (AVHWFramesContext *)dst->hw_frames_ctx->data; + d3d11_ctx = dst_fc->device_ctx->hwctx; + if (AMF_IFACE_CALL(amf_ctx->context, GetDX11Device, AMF_DX11_0) != d3d11_ctx->device) { + av_log(ctx, AV_LOG_ERROR, "The AMF context does not use the D3D11 device of the target frames.\n"); + return AVERROR(EINVAL); + } + res = AMF_IFACE_CALL(surface, Convert, AMF_MEMORY_DX11); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(EINVAL), "Convert(AMF_MEMORY_DX11) failed with error %d\n", res); + + plane = AMF_IFACE_CALL(surface, GetPlaneAt, 0); + texture = plane->pVtbl->GetNative(plane); + if (FAILED(texture->lpVtbl->GetPrivateData(texture, &AMFTextureArrayIndexGUID, &size, &index)) || + size != sizeof(index)) + index = 0; + + ret = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src, NULL, NULL); + if (ret < 0) + return ret; + + dst->data[0] = (uint8_t *)texture; + dst->data[1] = (uint8_t *)(intptr_t)index; + dst->width = src->width; + dst->height = src->height; + return 0; +} +#endif + static int amf_map_frame(AVHWFramesContext *device_ctx, AVFrame *dst, const AVFrame *src, int flags) { AMFSurface *surface = (AMFSurface *)src->data[0]; @@ -931,6 +976,10 @@ static int amf_map_frame(AVHWFramesContext *device_ctx, AVFrame *dst, const AVFr size_t plane_count = 0; int ret = -1; +#if CONFIG_D3D11VA + if (dst->format == AV_PIX_FMT_D3D11) + return amf_map_to_d3d11(device_ctx, dst, src); +#endif if (dst->format != AV_PIX_FMT_NONE && av_pix_fmt_desc_get(dst->format)->flags & AV_PIX_FMT_FLAG_HWACCEL) return AVERROR(ENOSYS); diff --git a/libavutil/version.h b/libavutil/version.h index ed6abeab78..0ae09719ae 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -80,7 +80,7 @@ #define LIBAVUTIL_VERSION_MAJOR 61 #define LIBAVUTIL_VERSION_MINOR 14 -#define LIBAVUTIL_VERSION_MICRO 100 +#define LIBAVUTIL_VERSION_MICRO 101 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ LIBAVUTIL_VERSION_MINOR, \ -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
