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

Git pushed a commit to branch master
in repository ffmpeg.

commit 2f0c34b10e02df29a707cdc4d16a29044fbbe2bd
Author:     Lynne <[email protected]>
AuthorDate: Sun Sep 20 13:58:46 2026 +0900
Commit:     Lynne <[email protected]>
CommitDate: Sun Sep 20 14:45:52 2026 +0900

    vulkan_h264: only bind reference fields that were decoded into their slot
    
    A Vulkan DPB slot only becomes active once a decode operation sets it up,
    and from then on holds exactly the picture resource that was decoded into
    it. The H.264 decoder however hands us references that never went through
    the hwaccel: the dummies it synthesizes to fill frame_num gaps and to stand
    in for missing references, and fields lost to a seek. Binding those as
    active slots fails validation (VUIDs 07239, 07265, 07266, 07151), and since
    the slot lookup for long-term references only searched the first 16
    pictures and fell back to slot 0, a resource could end up bound twice
    (07238, 07264).
    
    Track, per picture, which fields were actually decoded into its slot, and
    bind only the references, and only the fields of them, that were:
    vk_h264_fill_pict returns 1 when it bound the picture and 0 when it cannot
    be bound, and the reference loops advance by that. Use the picture's index
    in the DPB as its slot directly instead of searching for it, and describe
    the setup slot by the structure of the picture being decoded rather than by
    its reference marking, which does not describe the slot's contents while
    decoding the second field of a pair.
---
 libavcodec/vulkan_h264.c | 96 +++++++++++++++++++++++-------------------------
 1 file changed, 46 insertions(+), 50 deletions(-)

diff --git a/libavcodec/vulkan_h264.c b/libavcodec/vulkan_h264.c
index 0c50de4e84..6be0f957e9 100644
--- a/libavcodec/vulkan_h264.c
+++ b/libavcodec/vulkan_h264.c
@@ -37,6 +37,9 @@ const FFVulkanDecodeDescriptor ff_vk_dec_h264_desc = {
 typedef struct H264VulkanDecodePicture {
     FFVulkanDecodePicture           vp;
 
+    /* PICT_* mask of what was actually decoded into the picture's DPB slot */
+    int                             decoded;
+
     /* Current picture */
     StdVideoDecodeH264ReferenceInfo h264_ref;
     VkVideoDecodeH264DpbSlotInfoKHR vkh264_ref;
@@ -53,22 +56,34 @@ typedef struct H264VulkanDecodePicture {
 
 const static int h264_scaling_list8_order[] = { 0, 3, 1, 4, 2, 5 };
 
+/* Returns 1 if the picture was bound, 0 if it cannot be */
 static int vk_h264_fill_pict(AVCodecContext *avctx, H264Picture **ref_src,
                              VkVideoReferenceSlotInfoKHR *ref_slot,       /* 
Main structure */
                              VkVideoPictureResourceInfoKHR *ref,          /* 
Goes in ^ */
                              VkVideoDecodeH264DpbSlotInfoKHR *vkh264_ref, /* 
Goes in ^ */
                              StdVideoDecodeH264ReferenceInfo *h264_ref,   /* 
Goes in ^ */
                              H264Picture *pic, int is_current,
-                             int is_field, int picture_structure,
-                             int dpb_slot_index)
+                             int is_field, int picture_structure)
 {
+    const H264Context *h = avctx->priv_data;
     FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
     FFVulkanDecodeShared *ctx = dec->shared_ctx;
     H264VulkanDecodePicture *hp = pic->hwaccel_picture_private;
     FFVulkanDecodePicture *vkpic = &hp->vp;
+    const int dpb_slot_index = pic - h->DPB;
+    int err;
+
+    /* A slot only holds what was decoded into it: not the pictures the
+     * decoder synthesizes to fill frame_num gaps or to stand in for missing
+     * references, nor fields lost to a seek. */
+    if (!is_current) {
+        picture_structure &= hp->decoded;
+        if (!picture_structure)
+            return 0;
+    }
 
-    int err = ff_vk_decode_prepare_frame(dec, pic->f, vkpic, is_current,
-                                         dec->dedicated_dpb);
+    err = ff_vk_decode_prepare_frame(dec, pic->f, vkpic, is_current,
+                                     dec->dedicated_dpb);
     if (err < 0)
         return err;
 
@@ -113,7 +128,7 @@ static int vk_h264_fill_pict(AVCodecContext *avctx, 
H264Picture **ref_src,
     if (ref_src)
         *ref_src = pic;
 
-    return 0;
+    return 1;
 }
 
 static StdVideoH264LevelIdc convert_to_vk_level_idc(int level_idc)
@@ -375,7 +390,7 @@ static int vk_h264_start_frame(AVCodecContext          
*avctx,
                                av_unused uint32_t       size)
 {
     int err;
-    int dpb_slot_index = 0;
+    int nb_refs = 0;
     H264Context *h = avctx->priv_data;
 
     H264Picture *pic = h->cur_pic_ptr;
@@ -383,62 +398,36 @@ static int vk_h264_start_frame(AVCodecContext          
*avctx,
     FFVulkanDecodePicture *vp = &hp->vp;
 
     /* Fill in main slot */
-    dpb_slot_index = 0;
-    for (unsigned slot = 0; slot < H264_MAX_PICTURE_COUNT; slot++) {
-        if (pic == &h->DPB[slot]) {
-            dpb_slot_index = slot;
-            break;
-        }
-    }
-
     err = vk_h264_fill_pict(avctx, NULL, &vp->ref_slot, &vp->ref,
                             &hp->vkh264_ref, &hp->h264_ref, pic, 1,
-                            h->DPB[dpb_slot_index].field_picture,
-                            h->DPB[dpb_slot_index].reference,
-                            dpb_slot_index);
+                            FIELD_PICTURE(h), h->picture_structure);
     if (err < 0)
         return err;
 
     /* Fill in short-term references */
     for (int i = 0; i < h->short_ref_count; i++) {
-        dpb_slot_index = 0;
-        for (unsigned slot = 0; slot < H264_MAX_PICTURE_COUNT; slot++) {
-            if (h->short_ref[i] == &h->DPB[slot]) {
-                dpb_slot_index = slot;
-                break;
-            }
-        }
-        err = vk_h264_fill_pict(avctx, &hp->ref_src[i], &vp->ref_slots[i],
-                                &vp->refs[i], &hp->vkh264_refs[i],
-                                &hp->h264_refs[i], h->short_ref[i], 0,
-                                h->DPB[dpb_slot_index].field_picture,
-                                h->DPB[dpb_slot_index].reference,
-                                dpb_slot_index);
+        H264Picture *ref = h->short_ref[i];
+        err = vk_h264_fill_pict(avctx, &hp->ref_src[nb_refs], 
&vp->ref_slots[nb_refs],
+                                &vp->refs[nb_refs], &hp->vkh264_refs[nb_refs],
+                                &hp->h264_refs[nb_refs], ref, 0,
+                                ref->field_picture, ref->reference);
         if (err < 0)
             return err;
+        nb_refs += err;
     }
 
     /* Fill in long-term refs */
-    for (int r = 0, i = h->short_ref_count; r < H264_MAX_DPB_FRAMES &&
-         i < h->short_ref_count + h->long_ref_count; r++) {
-        if (!h->long_ref[r])
+    for (int r = 0, i = 0; r < H264_MAX_DPB_FRAMES && i < h->long_ref_count; 
r++) {
+        H264Picture *ref = h->long_ref[r];
+        if (!ref)
             continue;
-
-        dpb_slot_index = 0;
-        for (unsigned slot = 0; slot < 16; slot++) {
-            if (h->long_ref[r] == &h->DPB[slot]) {
-                dpb_slot_index = slot;
-                break;
-            }
-        }
-        err = vk_h264_fill_pict(avctx, &hp->ref_src[i], &vp->ref_slots[i],
-                                &vp->refs[i], &hp->vkh264_refs[i],
-                                &hp->h264_refs[i], h->long_ref[r], 0,
-                                h->DPB[dpb_slot_index].field_picture,
-                                h->DPB[dpb_slot_index].reference,
-                                dpb_slot_index);
+        err = vk_h264_fill_pict(avctx, &hp->ref_src[nb_refs], 
&vp->ref_slots[nb_refs],
+                                &vp->refs[nb_refs], &hp->vkh264_refs[nb_refs],
+                                &hp->h264_refs[nb_refs], ref, 0,
+                                ref->field_picture, ref->reference);
         if (err < 0)
             return err;
+        nb_refs += err;
         i++;
     }
 
@@ -470,7 +459,7 @@ static int vk_h264_start_frame(AVCodecContext          
*avctx,
         .pNext = &hp->h264_pic_info,
         .flags = 0x0,
         .pSetupReferenceSlot = &vp->ref_slot,
-        .referenceSlotCount = h->short_ref_count + h->long_ref_count,
+        .referenceSlotCount = nb_refs,
         .pReferenceSlots = vp->ref_slots,
         .dstPictureResource = (VkVideoPictureResourceInfoKHR) {
             .sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR,
@@ -520,6 +509,7 @@ static int vk_h264_end_frame(AVCodecContext *avctx)
     FFVulkanDecodePicture *vp = &hp->vp;
     FFVulkanDecodePicture *rvp[H264_MAX_PICTURE_COUNT] = { 0 };
     AVFrame *rav[H264_MAX_PICTURE_COUNT] = { 0 };
+    int err;
 
 #ifdef VK_KHR_video_maintenance2
     StdVideoH264ScalingLists vksps_scaling;
@@ -551,7 +541,7 @@ static int vk_h264_end_frame(AVCodecContext *avctx)
 
     if (!dec->session_params &&
         !(ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2)) {
-        int err = vk_h264_create_params(avctx, &dec->session_params);
+        err = vk_h264_create_params(avctx, &dec->session_params);
         if (err < 0)
             return err;
 
@@ -570,7 +560,13 @@ static int vk_h264_end_frame(AVCodecContext *avctx)
     av_log(avctx, AV_LOG_DEBUG, "Decoding frame, %zu bytes, %i slices\n",
            vp->slices_size, hp->h264_pic_info.sliceCount);
 
-    return ff_vk_decode_frame(avctx, pic->f, vp, rav, rvp);
+    err = ff_vk_decode_frame(avctx, pic->f, vp, rav, rvp);
+    if (err < 0)
+        return err;
+
+    hp->decoded |= h->picture_structure;
+
+    return 0;
 }
 
 static void vk_h264_free_frame_priv(AVRefStructOpaque _hwctx, void *data)

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