PR #24224 opened by t-boiko
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24224
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24224.patch

Set VkVideoDecodeH264ProfileInfoKHR::pictureLayout from SPS 
frame_mbs_only_flag: 
- progressive when frame_mbs_only_flag == 1 / no SPS;
- interlaced when frame_mbs_only_flag == 0 (field/MBAFF allowed per ITU-T 
H.264).
Do not use avctx->field_order: MBAFF may still report progressive.

The commit fixes a decoding of the ITU-T H.264.1 MBAFF samples:

CAMA1_Sony_C
CAMA3_Sand_E
CAMACI3_Sony_C
CAMANL3_Sand_E
CAMASL3_Sony_B
CANLMA2_Sony_C
CANLMA3_Sony_C
CVCANLMA2_Sony_C
CVMA1_Sony_D
CVMAQP2_Sony_G
CVMAQP3_Sony_D


>From 4e0b062770e10d5d245a962caffb2b43f6e8a2f8 Mon Sep 17 00:00:00 2001
From: Tymur Boiko <[email protected]>
Date: Thu, 20 Aug 2026 22:40:18 +0200
Subject: [PATCH] avcodec/vulkan_decode: set H.264 pictureLayout from SPS
 frame_mbs_only_flag

VkVideoDecodeH264ProfileInfoKHR::pictureLayout must match the sequence.
ITU-T H.264 frame_mbs_only_flag==1 means frames only; ==0 allows field
pictures and MBAFF. Vulkan PROGRESSIVE sessions are progressive-only;
non-PROGRESSIVE enables interlaced field DPB (h264_decode / videocoding).

pictureLayout values are mutually exclusive video profiles (vk.xml).
Map with !frame_mbs_only_flag, then validate with
vkGetPhysicalDeviceVideoCapabilitiesKHR:

- frame_mbs_only_flag == 1, or no SPS -> PROGRESSIVE (one query)
- frame_mbs_only_flag == 0 -> prefer INTERLEAVED_LINES, then SEPARATE_PLANES
  only on VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR

Do not use avctx->field_order: MBAFF may still report progressive.

Signed-off-by: Tymur Boiko <[email protected]>
---
 libavcodec/vulkan_decode.c | 42 ++++++++++++++++++++++++++++++++------
 1 file changed, 36 insertions(+), 6 deletions(-)

diff --git a/libavcodec/vulkan_decode.c b/libavcodec/vulkan_decode.c
index b954c78250..635fdeeeea 100644
--- a/libavcodec/vulkan_decode.c
+++ b/libavcodec/vulkan_decode.c
@@ -24,6 +24,9 @@
 #include "libavutil/avassert.h"
 #include "libavutil/mem.h"
 #include "libavutil/vulkan_loader.h"
+#if CONFIG_H264_VULKAN_HWACCEL
+#include "h264dec.h"
+#endif
 
 #define DECODER_IS_SDR(codec_id) \
     (((codec_id) == AV_CODEC_ID_FFV1) || \
@@ -745,6 +748,7 @@ static VkResult vulkan_setup_profile(AVCodecContext *avctx,
     VkVideoDecodeVP9ProfileInfoKHR *vp9_profile  = &prof->vp9_profile;
 #endif
     VkVideoDecodeAV1ProfileInfoKHR *av1_profile  = &prof->av1_profile;
+    int h264_interlaced = 0;
 
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt);
     if (!desc)
@@ -760,10 +764,15 @@ static VkResult vulkan_setup_profile(AVCodecContext 
*avctx,
         h264_profile->stdProfileIdc = cur_profile & 
~(AV_PROFILE_H264_CONSTRAINED |
                                                       AV_PROFILE_H264_INTRA);
 
-        h264_profile->pictureLayout = avctx->field_order == AV_FIELD_UNKNOWN ||
-                                      avctx->field_order == 
AV_FIELD_PROGRESSIVE ?
-                                      
VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_PROGRESSIVE_KHR :
-                                      
VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_INTERLACED_INTERLEAVED_LINES_BIT_KHR;
+        h264_profile->pictureLayout =
+            VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_PROGRESSIVE_KHR;
+#if CONFIG_H264_VULKAN_HWACCEL
+        {
+            const H264Context *h = avctx->priv_data;
+            if (h && h->ps.sps && !h->ps.sps->frame_mbs_only_flag)
+                h264_interlaced = 1;
+        }
+#endif
     } else if (avctx->codec_id == AV_CODEC_ID_H265) {
         dec_caps->pNext = h265_caps;
         usage->pNext = h265_profile;
@@ -804,8 +813,25 @@ static VkResult vulkan_setup_profile(AVCodecContext *avctx,
     dec_caps->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_CAPABILITIES_KHR;
     /* dec_caps->pNext already filled in */
 
-    return vk->GetPhysicalDeviceVideoCapabilitiesKHR(hwctx->phys_dev, profile,
-                                                     caps);
+    if (h264_interlaced) {
+        static const VkVideoDecodeH264PictureLayoutFlagBitsKHR layouts[] = {
+            
VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_INTERLACED_INTERLEAVED_LINES_BIT_KHR,
+            
VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_INTERLACED_SEPARATE_PLANES_BIT_KHR,
+        };
+        VkResult result = VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR;
+
+        for (int i = 0; i < FF_ARRAY_ELEMS(layouts); i++) {
+            h264_profile->pictureLayout = layouts[i];
+            result = vk->GetPhysicalDeviceVideoCapabilitiesKHR(hwctx->phys_dev,
+                                                               profile, caps);
+            if (result != VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR)
+                return result;
+        }
+        return result;
+    } else {
+        return vk->GetPhysicalDeviceVideoCapabilitiesKHR(hwctx->phys_dev, 
profile,
+                                                         caps);
+    }
 }
 
 static int vulkan_decode_get_profile(AVCodecContext *avctx, AVBufferRef 
*frames_ref,
@@ -904,6 +930,10 @@ static int vulkan_decode_get_profile(AVCodecContext 
*avctx, AVBufferRef *frames_
                avcodec_get_name(avctx->codec_id),
                avcodec_profile_name(avctx->codec_id, cur_profile));
         return AVERROR(EINVAL);
+    } else if (ret == VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR) {
+        av_log(avctx, AV_LOG_VERBOSE, "Unable to initialize video session: "
+               "H.264 pictureLayout not supported!\n");
+        return AVERROR(EINVAL);
     } else if (ret == VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR) {
         av_log(avctx, AV_LOG_VERBOSE, "Unable to initialize video session: "
                "format (%s) not supported!\n",
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to