This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 8f1e6edbabf811786f63fa0a69f669d88efb7e39 Author: Julius Bairaktaris <[email protected]> AuthorDate: Sun Sep 13 15:52:13 2026 +0200 Commit: ArazIusubov <[email protected]> CommitDate: Wed Sep 16 22:05:28 2026 +0000 avfilter/amf: hold the wrapped D3D11 and DXVA2 frame until AMF releases it CreateSurfaceFromDX11Native() and CreateSurfaceFromDX9Native() wrap the texture without taking a reference on anything FFmpeg owns. The input AVFrame was freed at the end of the activation that submitted it, which hands its pool entry back to the decoder while the component may still hold the surface, so the decoder could write the next picture into a texture the component has not finished reading. Nothing pinned the frame for the surface's lifetime; the AMF encoder retains a clone of its input for the same reason. Pass an AMFSurfaceObserver that carries a clone of the frame and free both from OnSurfaceDataRelease(), which AMF calls when the wrapped surface is destroyed. The pool entry stays checked out for exactly as long as AMF references the surface. The copy path for D3D11VA decoder textures is unaffected: its copy is queued on the immediate context before the frame is released, so it is ordered ahead of any later write. Tested on Windows 11, RX 9070 XT, driver 32.0.31041.1004 with a probe counting the callbacks: every wrapped frame is released exactly once, for D3D11VA decoder textures into frc_amf, the path that wraps without copying, and for DXVA2 surfaces into all four filters. On this device the release arrives before the next frame is submitted, so the components consume the texture within the submitting activation and the hold changes nothing observable there: framecrc output is identical to the previous revision and decodes of 300 frames over DXVA2 and 600 over D3D11VA complete. Assisted-by: Claude Fable 5.1 Signed-off-by: Julius Bairaktaris <[email protected]> --- libavfilter/vf_amf_common.c | 51 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/libavfilter/vf_amf_common.c b/libavfilter/vf_amf_common.c index 5cd93aef2b..e1d0b42ee3 100644 --- a/libavfilter/vf_amf_common.c +++ b/libavfilter/vf_amf_common.c @@ -739,6 +739,39 @@ static int amf_copy_d3d11_texture(AVFilterContext *avctx, const AVFrame *frame, } #endif +#if CONFIG_D3D11VA || CONFIG_DXVA2 +typedef struct AMFFrameHolder { + AMFSurfaceObserver observer; + AVFrame *frame; +} AMFFrameHolder; + +static void AMF_STD_CALL amf_release_held_frame(AMFSurfaceObserver *observer, AMFSurface *surface) +{ + AMFFrameHolder *holder = (AMFFrameHolder*)observer; + + av_frame_free(&holder->frame); + av_free(holder); +} + +static const AMFSurfaceObserverVtbl amf_frame_holder_vtbl = { amf_release_held_frame }; + +static int amf_hold_frame(const AVFrame *frame, AMFSurfaceObserver **observer) +{ + AMFFrameHolder *holder = av_mallocz(sizeof(*holder)); + + if (!holder) + return AVERROR(ENOMEM); + holder->frame = av_frame_clone(frame); + if (!holder->frame) { + av_free(holder); + return AVERROR(ENOMEM); + } + holder->observer.pVtbl = &amf_frame_holder_vtbl; + *observer = &holder->observer; + return 0; +} +#endif + int amf_avframe_to_amfsurface(AVFilterContext *avctx, const AVFrame *frame, AMFSurface** ppSurface) { AMFVariantStruct var = { 0 }; @@ -747,6 +780,9 @@ int amf_avframe_to_amfsurface(AVFilterContext *avctx, const AVFrame *frame, AMFS AMFSurface *surface; AMF_RESULT res; int hw_surface = 0; +#if CONFIG_D3D11VA || CONFIG_DXVA2 + AMFSurfaceObserver *observer; +#endif switch (frame->format) { #if CONFIG_D3D11VA @@ -769,7 +805,12 @@ int amf_avframe_to_amfsurface(AVFilterContext *avctx, const AVFrame *frame, AMFS texture->lpVtbl->SetPrivateData(texture, &AMFTextureArrayIndexGUID, sizeof(index), &index); - res = ctx->amf_device_ctx->context->pVtbl->CreateSurfaceFromDX11Native(ctx->amf_device_ctx->context, texture, &surface, NULL); // wrap to AMF surface + ret = amf_hold_frame(frame, &observer); + if (ret < 0) + return ret; + res = ctx->amf_device_ctx->context->pVtbl->CreateSurfaceFromDX11Native(ctx->amf_device_ctx->context, texture, &surface, observer); // wrap to AMF surface + if (res != AMF_OK) + amf_release_held_frame(observer, NULL); AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX11Native() failed with error %d\n", res); hw_surface = 1; } @@ -787,8 +828,14 @@ int amf_avframe_to_amfsurface(AVFilterContext *avctx, const AVFrame *frame, AMFS case AV_PIX_FMT_DXVA2_VLD: { IDirect3DSurface9 *texture = (IDirect3DSurface9 *)frame->data[3]; // actual texture + int ret; - res = ctx->amf_device_ctx->context->pVtbl->CreateSurfaceFromDX9Native(ctx->amf_device_ctx->context, texture, &surface, NULL); // wrap to AMF surface + ret = amf_hold_frame(frame, &observer); + if (ret < 0) + return ret; + res = ctx->amf_device_ctx->context->pVtbl->CreateSurfaceFromDX9Native(ctx->amf_device_ctx->context, texture, &surface, observer); // wrap to AMF surface + if (res != AMF_OK) + amf_release_held_frame(observer, NULL); AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX9Native() failed with error %d\n", res); hw_surface = 1; } -- To stop receiving notification emails like this one, please contact [email protected]. _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
