Commit 67d2f0820b for ffmpeg

commit 67d2f0820b060f23de6a96be1b00db492da3869c
Author: Marcos Ashton Iglesias <marcosashiglesias@gmail.com>
Date:   Fri Oct 16 16:08:45 2026 +0100

    avcodec/vulkan_decode: retry the AV1 profile query without filmGrainSupport

    Drivers without it, like ANV, rejected every AV1 stream by default;
    sequences with film grain still fail there unless it is exported.

diff --git a/libavcodec/vulkan_av1.c b/libavcodec/vulkan_av1.c
index 99bdac46e5..d02e892d66 100644
--- a/libavcodec/vulkan_av1.c
+++ b/libavcodec/vulkan_av1.c
@@ -271,6 +271,12 @@ static int vk_av1_start_frame(AVCodecContext          *avctx,
                                                          STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_WIENER,
                                                          STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_SGRPROJ };

+    if (apply_grain && dec->external_fg) {
+        av_log(avctx, AV_LOG_ERROR, "The decode session has no filmGrainSupport, "
+               "but this frame needs film grain\n");
+        return AVERROR(ENOTSUP);
+    }
+
     /* Use the current frame_ids in ref[] to decide occupied frame_ids */
     for (int i = 0; i < STD_VIDEO_AV1_NUM_REF_FRAMES; i++) {
         const AV1VulkanDecodePicture* rp = s->ref[i].hwaccel_picture_private;
diff --git a/libavcodec/vulkan_decode.c b/libavcodec/vulkan_decode.c
index f3c93492f7..55c34d92f9 100644
--- a/libavcodec/vulkan_decode.c
+++ b/libavcodec/vulkan_decode.c
@@ -24,6 +24,7 @@
 #include "libavutil/avassert.h"
 #include "libavutil/mem.h"
 #include "libavutil/vulkan_loader.h"
+#include "av1dec.h"
 #include "h264dec.h"

 #define DECODER_IS_SDR(codec_id) \
@@ -781,7 +782,6 @@ static VkResult vulkan_setup_profile(AVCodecContext *avctx,
         usage->pNext = av1_profile;
         av1_profile->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_PROFILE_INFO_KHR;
         av1_profile->stdProfile = cur_profile;
-        av1_profile->filmGrainSupport = !(avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN);
     }

     usage->sType           = VK_STRUCTURE_TYPE_VIDEO_DECODE_USAGE_INFO_KHR;
@@ -895,8 +895,35 @@ static int vulkan_decode_get_profile(AVCodecContext *avctx, AVBufferRef *frames_
     else if (avctx->codec_id == AV_CODEC_ID_AV1)
         dec_caps->pNext = &av1_caps;

+    if (avctx->codec_id == AV_CODEC_ID_AV1)
+        prof->av1_profile.filmGrainSupport =
+            !(avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN);
+
     ret = vulkan_setup_profile(avctx, prof, hwctx, vk, vk_desc, caps, dec_caps,
                                cur_profile);
+
+    /* ANV returns OPERATION_NOT_SUPPORTED when it lacks filmGrainSupport */
+    if (profile_unsupported(ret) && prof->av1_profile.filmGrainSupport) {
+        const AV1DecContext *s = avctx->priv_data;
+
+        av_log(avctx, AV_LOG_VERBOSE, "%s profile %s not supported, "
+               "attempting again without filmGrainSupport\n",
+               avcodec_get_name(avctx->codec_id),
+               profile_name(avctx->codec_id, cur_profile));
+        prof->av1_profile.filmGrainSupport = 0;
+        if (vulkan_setup_profile(avctx, prof, hwctx, vk, vk_desc, caps,
+                                 dec_caps, cur_profile) != VK_SUCCESS) {
+            prof->av1_profile.filmGrainSupport = 1;
+        } else if (s->raw_seq->film_grain_params_present) {
+            av_log(avctx, AV_LOG_ERROR, "The device does not support film "
+                   "grain; set export_side_data to film_grain to export it as "
+                   "side data instead\n");
+            return AVERROR(ENOTSUP);
+        } else {
+            ret = VK_SUCCESS;
+        }
+    }
+
     if (profile_unsupported(ret) &&
         avctx->hwaccel_flags & AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH &&
         avctx->profile != base_profile) {
@@ -1292,6 +1319,13 @@ int ff_vk_decode_init(AVCodecContext *avctx)
         return AVERROR(EINVAL);
     }

+    if (avctx->codec_id == AV_CODEC_ID_AV1) {
+        const VkVideoDecodeAV1ProfileInfoKHR *av1_profile =
+            ff_vk_find_struct(profile->pNext,
+                              VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_PROFILE_INFO_KHR);
+        dec->external_fg = !av1_profile->filmGrainSupport;
+    }
+
     /* Create queue context */
     vk_desc = get_codecdesc(avctx->codec_id);
     ctx->qf = ff_vk_qf_find(s, vk_desc->queue_flags, vk_desc->decode_op);
diff --git a/libavcodec/vulkan_decode.h b/libavcodec/vulkan_decode.h
index eb334ea1ae..2f8a2b714c 100644
--- a/libavcodec/vulkan_decode.h
+++ b/libavcodec/vulkan_decode.h
@@ -56,7 +56,7 @@ typedef struct FFVulkanDecodeContext {
     VkVideoSessionParametersKHR *session_params;

     int dedicated_dpb; /* Oddity  #1 - separate DPB images */
-    int external_fg;   /* Oddity  #2 - hardware can't apply film grain */
+    int external_fg;   /* Oddity  #2 - the session can't apply film grain */

     /* Workaround for NVIDIA drivers tested with CTS version 1.3.8 for AV1.
      * The tests were incorrect as the OrderHints were offset by 1. */