This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch release/7.1
in repository ffmpeg.

The following commit(s) were added to refs/heads/release/7.1 by this push:
     new 9cf577a607 avcodec/dxva2: fix frame->buf[] data race with frame 
threading
9cf577a607 is described below

commit 9cf577a6075277610797b9eb3c0e6c64f670191b
Author:     Diego de Souza <[email protected]>
AuthorDate: Thu Oct 8 15:23:51 2026 +0200
Commit:     Timo Rothenpieler <[email protected]>
CommitDate: Thu Oct 8 21:29:08 2026 +0200

    avcodec/dxva2: fix frame->buf[] data race with frame threading
    
    ff_dxva2_common_end_frame() adds a reference to the decoder to
    frame->buf[], so that the decoder outlives the frames decoded with it.
    It is called from the hwaccel end_frame() callback, which with frame
    threading may run after ff_thread_finish_setup(). From that point on,
    other threads may copy the frame: the H.264 decoder keeps a separate
    AVFrame per picture in each thread and synchronizes them in
    update_thread_context() with av_frame_replace(), which reads
    frame->buf[] while the decoding thread may be writing to it. As noted
    in fa77cb258b ("avcodec/h264dec: Fix data race when updating
    decode_error_flags"), a decoding thread must not modify any field that
    av_frame_ref() copies after ff_thread_finish_setup().
    
    This has been observed as an intermittent access violation in
    av_buffer_replace() when decoding H.264 with D3D11VA and frame
    threading on Windows on Arm: the copying thread read a non-NULL
    frame->buf[1] entry, but saw the fields of the AVBufferRef it points
    to as zero, and dereferenced the NULL buffer pointer when incrementing
    the reference count.
    
    Store the decoder reference in FrameDecodeData.hwaccel_priv instead,
    as nvdec does for its per-frame state. The decode data is attached to
    frame->private_ref when the buffer is allocated, before
    ff_thread_finish_setup(), and all references to the frame share it, so
    update_thread_context() only takes a new reference to it. The decoder
    reference is added to frame->buf[] by hwaccel_priv_post_process(),
    which runs in the caller's thread when the frame is returned, so
    returned frames keep the decoder alive. Since the decode data
    is shared, the second field of a field pair no longer adds a second
    decoder reference to the frame.
    
    Signed-off-by: Diego de Souza <[email protected]>
    (cherry picked from commit 538d10d1878fb546c3a2645efa56119848f9ccfc)
---
 libavcodec/dxva2.c | 35 ++++++++++++++++++++++++++++++++---
 1 file changed, 32 insertions(+), 3 deletions(-)

diff --git a/libavcodec/dxva2.c b/libavcodec/dxva2.c
index 22ecd5acaf..e0dfe551d9 100644
--- a/libavcodec/dxva2.c
+++ b/libavcodec/dxva2.c
@@ -889,6 +889,20 @@ static int frame_add_buf(AVFrame *frame, AVBufferRef *ref)
     return AVERROR(EINVAL);
 }
 
+static void dxva2_frame_priv_free(void *priv)
+{
+    AVBufferRef *decoder_ref = priv;
+
+    av_buffer_unref(&decoder_ref);
+}
+
+static int dxva2_frame_post_process(void *logctx, AVFrame *frame)
+{
+    const FrameDecodeData *fdd = (const FrameDecodeData 
*)frame->private_ref->data;
+
+    return frame_add_buf(frame, fdd->hwaccel_priv);
+}
+
 int ff_dxva2_common_end_frame(AVCodecContext *avctx, AVFrame *frame,
                               const void *pp, unsigned pp_size,
                               const void *qm, unsigned qm_size,
@@ -911,9 +925,24 @@ int ff_dxva2_common_end_frame(AVCodecContext *avctx, 
AVFrame *frame,
     FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx);
 
     if (sctx->decoder_ref) {
-        result = frame_add_buf(frame, sctx->decoder_ref);
-        if (result < 0)
-            return result;
+        FrameDecodeData *fdd = (FrameDecodeData *)frame->private_ref->data;
+
+        /* With frame threading, this may run after ff_thread_finish_setup(),
+         * when other threads may already be copying this AVFrame, so its
+         * buf[] array must not be modified here. Store the decoder
+         * reference in the per-frame decode data, which all references to
+         * the frame share, and add it to frame->buf[] once the frame is
+         * output. The second field of a field pair reuses the reference
+         * stored for the first. */
+        if (!fdd->hwaccel_priv) {
+            AVBufferRef *decoder_ref = av_buffer_ref(sctx->decoder_ref);
+            if (!decoder_ref)
+                return AVERROR(ENOMEM);
+
+            fdd->hwaccel_priv      = decoder_ref;
+            fdd->hwaccel_priv_free = dxva2_frame_priv_free;
+            fdd->post_process      = dxva2_frame_post_process;
+        }
     }
 
     do {

-- 
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]

Reply via email to