../../../ffmpeg/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
0 / 673
0.0%
Branches:
0 / 373
0.0%
Functions:
0 / 21
0.0%

libavcodec/vulkan_decode.c
Line Branch Exec Source
1 /*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include "libavutil/attributes.h"
20 #include "libavutil/refstruct.h"
21 #include "vulkan_video.h"
22 #include "vulkan_decode.h"
23 #include "config_components.h"
24 #include "libavutil/avassert.h"
25 #include "libavutil/mem.h"
26 #include "libavutil/vulkan_loader.h"
27 #include "h264dec.h"
28
29 #define DECODER_IS_SDR(codec_id) \
30 (((codec_id) == AV_CODEC_ID_FFV1) || \
31 ((codec_id) == AV_CODEC_ID_DPX) || \
32 ((codec_id) == AV_CODEC_ID_APV) || \
33 ((codec_id) == AV_CODEC_ID_PRORES_RAW) || \
34 ((codec_id) == AV_CODEC_ID_PRORES))
35
36 #if CONFIG_H264_VULKAN_HWACCEL
37 extern const FFVulkanDecodeDescriptor ff_vk_dec_h264_desc;
38 #endif
39 #if CONFIG_HEVC_VULKAN_HWACCEL
40 extern const FFVulkanDecodeDescriptor ff_vk_dec_hevc_desc;
41 #endif
42 #if CONFIG_VP9_VULKAN_HWACCEL
43 extern const FFVulkanDecodeDescriptor ff_vk_dec_vp9_desc;
44 #endif
45 #if CONFIG_AV1_VULKAN_HWACCEL
46 extern const FFVulkanDecodeDescriptor ff_vk_dec_av1_desc;
47 #endif
48 #if CONFIG_FFV1_VULKAN_HWACCEL
49 extern const FFVulkanDecodeDescriptor ff_vk_dec_ffv1_desc;
50 #endif
51 #if CONFIG_PRORES_RAW_VULKAN_HWACCEL
52 extern const FFVulkanDecodeDescriptor ff_vk_dec_prores_raw_desc;
53 #endif
54 #if CONFIG_PRORES_VULKAN_HWACCEL
55 extern const FFVulkanDecodeDescriptor ff_vk_dec_prores_desc;
56 #endif
57 #if CONFIG_DPX_VULKAN_HWACCEL
58 extern const FFVulkanDecodeDescriptor ff_vk_dec_dpx_desc;
59 #endif
60 #if CONFIG_APV_VULKAN_HWACCEL
61 extern const FFVulkanDecodeDescriptor ff_vk_dec_apv_desc;
62 #endif
63
64 static const FFVulkanDecodeDescriptor *dec_descs[] = {
65 #if CONFIG_H264_VULKAN_HWACCEL
66 &ff_vk_dec_h264_desc,
67 #endif
68 #if CONFIG_HEVC_VULKAN_HWACCEL
69 &ff_vk_dec_hevc_desc,
70 #endif
71 #if CONFIG_VP9_VULKAN_HWACCEL
72 &ff_vk_dec_vp9_desc,
73 #endif
74 #if CONFIG_AV1_VULKAN_HWACCEL
75 &ff_vk_dec_av1_desc,
76 #endif
77 #if CONFIG_FFV1_VULKAN_HWACCEL
78 &ff_vk_dec_ffv1_desc,
79 #endif
80 #if CONFIG_PRORES_RAW_VULKAN_HWACCEL
81 &ff_vk_dec_prores_raw_desc,
82 #endif
83 #if CONFIG_PRORES_VULKAN_HWACCEL
84 &ff_vk_dec_prores_desc,
85 #endif
86 #if CONFIG_DPX_VULKAN_HWACCEL
87 &ff_vk_dec_dpx_desc,
88 #endif
89 #if CONFIG_APV_VULKAN_HWACCEL
90 &ff_vk_dec_apv_desc,
91 #endif
92 };
93
94 typedef struct FFVulkanDecodeProfileData {
95 VkVideoDecodeH264ProfileInfoKHR h264_profile;
96 VkVideoDecodeH265ProfileInfoKHR h265_profile;
97 #if CONFIG_VP9_VULKAN_HWACCEL
98 VkVideoDecodeVP9ProfileInfoKHR vp9_profile;
99 #endif
100 VkVideoDecodeAV1ProfileInfoKHR av1_profile;
101
102 VkVideoDecodeUsageInfoKHR usage;
103 VkVideoProfileInfoKHR profile;
104 VkVideoProfileListInfoKHR profile_list;
105 } FFVulkanDecodeProfileData;
106
107 ✗ static const FFVulkanDecodeDescriptor *get_codecdesc(enum AVCodecID codec_id)
108 {
109
0/2
✗ Branch 6 → 3 not taken.
✗ Branch 6 → 7 not taken.
✗ for (size_t i = 0; i < FF_ARRAY_ELEMS(dec_descs); i++)
110
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
✗ if (dec_descs[i]->codec_id == codec_id)
111 ✗ return dec_descs[i];
112 av_assert1(!"no codec descriptor");
113 ✗ return NULL;
114 }
115
116 ✗ static const VkVideoProfileInfoKHR *get_video_profile(FFVulkanDecodeShared *ctx, enum AVCodecID codec_id)
117 {
118 const VkVideoProfileListInfoKHR *profile_list;
119
120 ✗ VkStructureType profile_struct_type =
121
0/8
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 10 not taken.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 9 not taken.
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 8 not taken.
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
✗ codec_id == AV_CODEC_ID_H264 ? VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_INFO_KHR :
122 codec_id == AV_CODEC_ID_HEVC ? VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_INFO_KHR :
123 #if CONFIG_VP9_VULKAN_HWACCEL
124 codec_id == AV_CODEC_ID_VP9 ? VK_STRUCTURE_TYPE_VIDEO_DECODE_VP9_PROFILE_INFO_KHR :
125 #endif
126 codec_id == AV_CODEC_ID_AV1 ? VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_PROFILE_INFO_KHR :
127 VK_STRUCTURE_TYPE_MAX_ENUM;
128
0/2
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 13 not taken.
✗ if (profile_struct_type == VK_STRUCTURE_TYPE_MAX_ENUM)
129 ✗ return NULL;
130
131 ✗ profile_list = ff_vk_find_struct(ctx->s.hwfc->create_pnext,
132 VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR);
133
0/2
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 16 not taken.
✗ if (!profile_list)
134 ✗ return NULL;
135
136
0/2
✗ Branch 21 → 17 not taken.
✗ Branch 21 → 22 not taken.
✗ for (int i = 0; i < profile_list->profileCount; i++)
137
0/2
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 20 not taken.
✗ if (ff_vk_find_struct(profile_list->pProfiles[i].pNext, profile_struct_type))
138 ✗ return &profile_list->pProfiles[i];
139
140 ✗ return NULL;
141 }
142
143 ✗ int ff_vk_update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
144 {
145 ✗ FFVulkanDecodeContext *src_ctx = src->internal->hwaccel_priv_data;
146 ✗ FFVulkanDecodeContext *dst_ctx = dst->internal->hwaccel_priv_data;
147
148 ✗ av_refstruct_replace(&dst_ctx->shared_ctx, src_ctx->shared_ctx);
149
150 ✗ av_refstruct_replace(&dst_ctx->session_params, src_ctx->session_params);
151
152 ✗ dst_ctx->dedicated_dpb = src_ctx->dedicated_dpb;
153 ✗ dst_ctx->external_fg = src_ctx->external_fg;
154
155 ✗ return 0;
156 }
157
158 ✗ int ff_vk_params_invalidate(AVCodecContext *avctx, int t, const uint8_t *b, uint32_t s)
159 {
160 ✗ FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
161 ✗ av_refstruct_unref(&dec->session_params);
162 ✗ return 0;
163 }
164
165 ✗ static void init_frame(FFVulkanDecodeContext *dec, FFVulkanDecodePicture *vkpic)
166 {
167 ✗ FFVulkanDecodeShared *ctx = dec->shared_ctx;
168 ✗ FFVulkanFunctions *vk = &ctx->s.vkfn;
169
170 ✗ vkpic->dpb_frame = NULL;
171 ✗ vkpic->dpb_img = NULL;
172 ✗ vkpic->out_views = NULL;
173 ✗ vkpic->view.ref = VK_NULL_HANDLE;
174 ✗ vkpic->view.out = VK_NULL_HANDLE;
175
176 ✗ vkpic->invalidate_memory_ranges = vk->InvalidateMappedMemoryRanges;
177 ✗ }
178
179 ✗ int ff_vk_decode_prepare_frame(FFVulkanDecodeContext *dec, AVFrame *pic,
180 FFVulkanDecodePicture *vkpic, int is_current,
181 int alloc_dpb)
182 {
183 int err;
184 ✗ FFVulkanDecodeShared *ctx = dec->shared_ctx;
185
186 ✗ vkpic->slices_size = 0;
187
188 /* If the decoder made a blank frame to make up for a missing ref, or the
189 * frame is the current frame so it's missing one, create a re-representation */
190
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
✗ if (vkpic->view.ref)
191 ✗ return 0;
192
193 ✗ init_frame(dec, vkpic);
194
195 /* Refcounted, so executions keep it alive past the picture */
196 ✗ vkpic->out_views = ff_vk_imageviews_alloc(&ctx->s, 1);
197
0/2
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✗ if (!vkpic->out_views)
198 ✗ return AVERROR(ENOMEM);
199
200
0/4
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 11 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 11 not taken.
✗ if (ctx->common.layered_dpb && alloc_dpb) {
201 ✗ vkpic->view.ref = ctx->common.layered_view;
202 ✗ vkpic->view.aspect_ref = ctx->common.layered_aspect;
203
0/2
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 16 not taken.
✗ } else if (alloc_dpb) {
204 ✗ vkpic->dpb_img = av_refstruct_pool_get(ctx->common.dpb->img_pool);
205
0/2
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 15 not taken.
✗ if (!vkpic->dpb_img)
206 ✗ return AVERROR(ENOMEM);
207
208 /* The view is owned by the pool entry */
209 ✗ vkpic->view.ref = vkpic->dpb_img->view;
210 ✗ vkpic->view.aspect_ref = vkpic->dpb_img->aspect;
211 }
212
213
0/4
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 18 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 23 not taken.
✗ if (!alloc_dpb || is_current) {
214 ✗ AVHWFramesContext *frames = (AVHWFramesContext *)pic->hw_frames_ctx->data;
215 ✗ AVVulkanFramesContext *hwfc = frames->hwctx;
216
217 ✗ err = ff_vk_create_view(&ctx->s,
218 ✗ &vkpic->out_views->views[0], &vkpic->view.aspect,
219 ✗ ((AVVkFrame *)pic->data[0])->img[0],
220 hwfc->format[0],
221 ✗ VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR |
222 ✗ (hwfc->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR),
223 0);
224 // the above fixes VUID-VkVideoBeginCodingInfoKHR-slotIndex-07245
225
0/2
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 21 not taken.
✗ if (err < 0)
226 ✗ return err;
227 ✗ vkpic->view.out = vkpic->out_views->views[0];
228
229
0/2
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 23 not taken.
✗ if (!alloc_dpb) {
230 ✗ vkpic->view.ref = vkpic->view.out;
231 ✗ vkpic->view.aspect_ref = vkpic->view.aspect;
232 }
233 }
234
235 ✗ return 0;
236 }
237
238 ✗ int ff_vk_decode_add_slice(AVCodecContext *avctx, FFVulkanDecodePicture *vp,
239 const uint8_t *data, size_t size, int add_startcode,
240 uint32_t *nb_slices, const uint32_t **offsets)
241 {
242 ✗ FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
243 ✗ FFVulkanDecodeShared *ctx = dec->shared_ctx;
244
245 static const uint8_t startcode_prefix[3] = { 0x0, 0x0, 0x1 };
246
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
✗ const size_t startcode_len = add_startcode ? sizeof(startcode_prefix) : 0;
247
0/2
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
✗ const int nb = nb_slices ? *nb_slices : 0;
248 uint8_t *slices;
249 uint32_t *slice_off;
250 FFVkBuffer *vkbuf;
251
252 ✗ size_t new_size = vp->slices_size + startcode_len + size +
253 ✗ ctx->caps.minBitstreamBufferSizeAlignment;
254 ✗ new_size = FFALIGN(new_size, ctx->caps.minBitstreamBufferSizeAlignment);
255
256
0/2
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 13 not taken.
✗ if (offsets) {
257 ✗ slice_off = av_fast_realloc(dec->slice_off, &dec->slice_off_max,
258 ✗ (nb + 1)*sizeof(*slice_off));
259
0/2
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
✗ if (!slice_off)
260 ✗ return AVERROR(ENOMEM);
261
262 ✗ *offsets = dec->slice_off = slice_off;
263
264 ✗ slice_off[nb] = vp->slices_size;
265 }
266
267 ✗ vkbuf = vp->slices_buf;
268
0/4
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 15 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 32 not taken.
✗ if (!vkbuf || vkbuf->size < new_size) {
269 int err;
270 FFVkBuffer *new_buf;
271
272 /* No point in requesting anything smaller. */
273 ✗ size_t buf_size = FFMAX(new_size, 1024*1024);
274
275 /* Align buffer to nearest power of two. Makes fragmentation management
276 * easier, and gives us ample headroom. */
277 ✗ buf_size = 2 << av_log2(buf_size);
278
279 /* When the frames context uses DRM modifier tiling,
280 * hwctx->create_pnext contains VkImageDrmFormatModifierListCreateInfoEXT,
281 * which per spec does not extend VkBufferCreateInfo, so we need to find
282 * the VkVideoProfileListInfoKHR structure within it. */
283 ✗ void *buf_pnext = ctx->s.hwfc->create_pnext;
284
0/2
✗ Branch 15 → 16 not taken.
✗ Branch 15 → 17 not taken.
✗ if (ctx->s.hwfc->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)
285 ✗ buf_pnext = (void *)ff_vk_find_struct(ctx->s.hwfc->create_pnext,
286 VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR);
287
288
0/8
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 22 not taken.
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 22 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 20 → 22 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 23 not taken.
✗ VkBufferUsageFlags buf_usage = DECODER_IS_SDR(avctx->codec_id) ?
289 (VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
290
0/2
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 22 not taken.
✗ VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) :
291 VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR;
292
293 ✗ err = ff_vk_get_pooled_buffer(&ctx->s, &ctx->buf_pool, &new_buf,
294 buf_usage, buf_pnext, buf_size,
295 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
296 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
297
0/2
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 27 not taken.
✗ if (err < 0)
298 ✗ err = ff_vk_get_pooled_buffer(&ctx->s, &ctx->buf_pool, &new_buf,
299 buf_usage, buf_pnext, buf_size,
300 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
301
0/2
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 29 not taken.
✗ if (err < 0)
302 ✗ return err;
303
304 /* Copy data from the old buffer */
305
0/2
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 31 not taken.
✗ if (vkbuf) {
306 ✗ memcpy(new_buf->mapped_mem, vkbuf->mapped_mem, vp->slices_size);
307 ✗ av_refstruct_unref(&vp->slices_buf);
308 }
309
310 ✗ vp->slices_buf = new_buf;
311 ✗ vkbuf = new_buf;
312 }
313 ✗ slices = vkbuf->mapped_mem;
314
315 /* Startcode */
316 ✗ memcpy(slices + vp->slices_size, startcode_prefix, startcode_len);
317
318 /* Slice data */
319 ✗ memcpy(slices + vp->slices_size + startcode_len, data, size);
320
321
0/2
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 34 not taken.
✗ if (nb_slices)
322 ✗ *nb_slices = nb + 1;
323
324 ✗ vp->slices_size += startcode_len + size;
325
326 ✗ return 0;
327 }
328
329 ✗ static int create_empty_session_parameters(AVCodecContext *avctx,
330 FFVulkanDecodeShared *ctx,
331 VkVideoSessionParametersKHR *empty_session_params)
332 {
333
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
✗ if (avctx->codec_id == AV_CODEC_ID_VP9)
334 ✗ return 0;
335
336 ✗ VkVideoDecodeH264SessionParametersCreateInfoKHR h264_params = {
337 .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR,
338 };
339 ✗ VkVideoDecodeH265SessionParametersCreateInfoKHR h265_params = {
340 .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR,
341 };
342 ✗ StdVideoAV1SequenceHeader av1_empty_seq = { 0 };
343 ✗ VkVideoDecodeAV1SessionParametersCreateInfoKHR av1_params = {
344 .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_SESSION_PARAMETERS_CREATE_INFO_KHR,
345 .pStdSequenceHeader = &av1_empty_seq,
346 };
347 ✗ VkVideoSessionParametersCreateInfoKHR session_params_create = {
348 .sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR,
349
0/2
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 10 not taken.
✗ .pNext = avctx->codec_id == AV_CODEC_ID_H264 ? (void *)&h264_params :
350
0/2
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 9 not taken.
✗ avctx->codec_id == AV_CODEC_ID_HEVC ? (void *)&h265_params :
351
0/2
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✗ avctx->codec_id == AV_CODEC_ID_AV1 ? (void *)&av1_params :
352 NULL,
353 ✗ .videoSession = ctx->common.session,
354 };
355
356 VkResult ret;
357 ✗ FFVulkanContext *s = &ctx->s;
358 ✗ FFVulkanFunctions *vk = &s->vkfn;
359 ✗ ret = vk->CreateVideoSessionParametersKHR(s->hwctx->act_dev, &session_params_create,
360 ✗ s->hwctx->alloc, empty_session_params);
361
0/2
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 16 not taken.
✗ if (ret != VK_SUCCESS) {
362 ✗ av_log(avctx, AV_LOG_ERROR, "Unable to create empty Vulkan video session parameters: %s!\n",
363 ff_vk_ret2str(ret));
364 ✗ return AVERROR_EXTERNAL;
365 }
366
367 ✗ return 0;
368 }
369
370 ✗ static int decode_reset(AVCodecContext *avctx, FFVulkanDecodeShared *ctx)
371 {
372 int err;
373 ✗ FFVulkanContext *s = &ctx->s;
374 ✗ FFVulkanFunctions *vk = &s->vkfn;
375
376 ✗ VkVideoBeginCodingInfoKHR decode_start = {
377 .sType = VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR,
378 ✗ .videoSession = ctx->common.session,
379 };
380
381
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 6 not taken.
✗ if (!(ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2)) {
382 ✗ err = create_empty_session_parameters(avctx, ctx,
383 &decode_start.videoSessionParameters);
384
0/2
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
✗ if (err < 0)
385 ✗ return err;
386 }
387
388 ✗ VkVideoCodingControlInfoKHR decode_ctrl = {
389 .sType = VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR,
390 .flags = VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR,
391 };
392 ✗ VkVideoEndCodingInfoKHR decode_end = {
393 .sType = VK_STRUCTURE_TYPE_VIDEO_END_CODING_INFO_KHR,
394 };
395
396 ✗ FFVkExecContext *exec = ff_vk_exec_get(&ctx->s, &ctx->exec_pool);
397 ✗ err = ff_vk_exec_start(&ctx->s, exec);
398
0/2
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 10 not taken.
✗ if (err < 0)
399 ✗ return err;
400
401 ✗ vk->CmdBeginVideoCodingKHR(exec->buf, &decode_start);
402 ✗ vk->CmdControlVideoCodingKHR(exec->buf, &decode_ctrl);
403 ✗ vk->CmdEndVideoCodingKHR(exec->buf, &decode_end);
404
405 ✗ err = ff_vk_exec_submit(&ctx->s, exec);
406
407
0/2
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 18 not taken.
✗ if (decode_start.videoSessionParameters) {
408 /* Wait to complete to delete the temporary session parameters */
409
0/2
✗ Branch 15 → 16 not taken.
✗ Branch 15 → 17 not taken.
✗ if (err >= 0)
410 ✗ ff_vk_exec_wait(&ctx->s, exec);
411
412 ✗ vk->DestroyVideoSessionParametersKHR(s->hwctx->act_dev,
413 decode_start.videoSessionParameters,
414 ✗ s->hwctx->alloc);
415 }
416
417
0/2
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 21 not taken.
✗ if (err < 0)
418 ✗ av_log(avctx, AV_LOG_ERROR, "Unable to reset decoder: %s",
419 ff_vk_ret2str(err));
420
421 ✗ return err;
422 }
423
424 ✗ int ff_vk_decode_frame(AVCodecContext *avctx,
425 AVFrame *pic, FFVulkanDecodePicture *vp,
426 AVFrame *rpic[], FFVulkanDecodePicture *rvkp[])
427 {
428 int err;
429 VkResult ret;
430 VkCommandBuffer cmd_buf;
431 FFVkBuffer *sd_buf;
432
433 ✗ FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
434 ✗ FFVulkanDecodeShared *ctx = dec->shared_ctx;
435 ✗ FFVulkanFunctions *vk = &ctx->s.vkfn;
436
437 /* Output */
438 ✗ AVVkFrame *vkf = (AVVkFrame *)pic->buf[0]->data;
439
440 /* Quirks */
441 ✗ const int layered_dpb = ctx->common.layered_dpb;
442
443 ✗ VkVideoBeginCodingInfoKHR decode_start = {
444 .sType = VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR,
445 ✗ .videoSession = ctx->common.session,
446 ✗ .videoSessionParameters = dec->session_params ?
447
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
✗ *dec->session_params : VK_NULL_HANDLE,
448 ✗ .referenceSlotCount = vp->decode_info.referenceSlotCount,
449 ✗ .pReferenceSlots = vp->decode_info.pReferenceSlots,
450 };
451 ✗ VkVideoEndCodingInfoKHR decode_end = {
452 .sType = VK_STRUCTURE_TYPE_VIDEO_END_CODING_INFO_KHR,
453 };
454
455 VkImageMemoryBarrier2 img_bar[38];
456 ✗ int nb_img_bar = 0;
457
458 ✗ size_t data_size = FFALIGN(vp->slices_size,
459 ctx->caps.minBitstreamBufferSizeAlignment);
460
461 ✗ FFVkExecContext *exec = ff_vk_exec_get(&ctx->s, &ctx->exec_pool);
462
463 /* The current picture's resource has to be bound as an inactive
464 * reference, unless its slot is already bound as an active one, as when
465 * decoding the second field of a pair. */
466 ✗ int cur_bound = 0;
467
0/2
✗ Branch 8 → 7 not taken.
✗ Branch 8 → 9 not taken.
✗ for (int i = 0; i < decode_start.referenceSlotCount; i++)
468 ✗ cur_bound |= decode_start.pReferenceSlots[i].slotIndex == vp->ref_slot.slotIndex;
469
0/2
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 11 not taken.
✗ if (!cur_bound) {
470 VkVideoReferenceSlotInfoKHR *cur_vk_ref;
471 ✗ cur_vk_ref = (void *)&decode_start.pReferenceSlots[decode_start.referenceSlotCount];
472 ✗ cur_vk_ref[0] = vp->ref_slot;
473 ✗ cur_vk_ref[0].slotIndex = -1;
474 ✗ decode_start.referenceSlotCount++;
475 }
476
477 ✗ sd_buf = vp->slices_buf;
478
479 /* Flush if needed */
480
0/2
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 18 not taken.
✗ if (!(sd_buf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
481 ✗ VkMappedMemoryRange flush_buf = {
482 .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
483 ✗ .memory = sd_buf->mem,
484 .offset = 0,
485 ✗ .size = FFALIGN(vp->slices_size,
486 ctx->s.props.properties.limits.nonCoherentAtomSize),
487 };
488
489 ✗ ret = vk->FlushMappedMemoryRanges(ctx->s.hwctx->act_dev, 1, &flush_buf);
490
0/2
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 17 not taken.
✗ if (ret != VK_SUCCESS) {
491 ✗ av_log(avctx, AV_LOG_ERROR, "Failed to flush memory: %s\n",
492 ff_vk_ret2str(ret));
493 ✗ return AVERROR_EXTERNAL;
494 }
495 }
496
497 ✗ vp->decode_info.srcBuffer = sd_buf->buf;
498 ✗ vp->decode_info.srcBufferOffset = 0;
499 ✗ vp->decode_info.srcBufferRange = data_size;
500
501 /* Start command buffer recording */
502 ✗ err = ff_vk_exec_start(&ctx->s, exec);
503
0/2
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 21 not taken.
✗ if (err < 0)
504 ✗ return err;
505 ✗ cmd_buf = exec->buf;
506
507 /* Slices; owned by the execution from now on */
508 ✗ ff_vk_exec_move_dep_refstruct(&ctx->s, exec, &vp->slices_buf);
509
510 /* Parameters; unset when inline session parameters are used */
511
0/2
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 24 not taken.
✗ if (dec->session_params)
512 ✗ ff_vk_exec_add_dep_refstruct(&ctx->s, exec, dec->session_params);
513
514 ✗ err = ff_vk_exec_add_dep_frame(&ctx->s, exec, pic,
515 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
516 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR);
517
0/2
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 28 not taken.
✗ if (err < 0) {
518 ✗ ff_vk_exec_discard(&ctx->s, exec);
519 ✗ return err;
520 }
521
522 /* The output view is kept alive by the execution context; freeing the
523 * picture then needs no host wait. */
524 ✗ ff_vk_exec_add_dep_refstruct(&ctx->s, exec, vp->out_views);
525
526 /* Output image - change layout, as it comes from a pool */
527 ✗ img_bar[nb_img_bar] = (VkImageMemoryBarrier2) {
528 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
529 .pNext = NULL,
530 .srcStageMask = VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
531 .dstStageMask = VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
532 .srcAccessMask = VK_ACCESS_2_NONE,
533 .dstAccessMask = VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR,
534 ✗ .oldLayout = vkf->layout[0],
535
0/2
✗ Branch 30 → 31 not taken.
✗ Branch 30 → 32 not taken.
✗ .newLayout = (layered_dpb || vp->dpb_img) ?
536
0/2
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 31 not taken.
✗ VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR :
537 VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR, /* Spec, 07252 utter madness */
538 ✗ .srcQueueFamilyIndex = vkf->queue_family[0],
539 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
540 ✗ .image = vkf->img[0],
541 .subresourceRange = (VkImageSubresourceRange) {
542 ✗ .aspectMask = vp->view.aspect,
543 .layerCount = 1,
544 .levelCount = 1,
545 },
546 };
547 ✗ ff_vk_exec_update_frame(&ctx->s, exec, pic,
548 ✗ &img_bar[nb_img_bar], &nb_img_bar);
549
550 /* Current picture's DISTINCT-mode DPB image: transition on first use */
551
0/2
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 37 not taken.
✗ if (vp->dpb_img) {
552 ✗ FFVkVideoDPBImage *di = vp->dpb_img;
553
554
0/2
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 37 not taken.
✗ if (di->layout != VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR) {
555 ✗ img_bar[nb_img_bar] = (VkImageMemoryBarrier2) {
556 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
557 .srcStageMask = VK_PIPELINE_STAGE_2_NONE,
558 .dstStageMask = VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
559 .srcAccessMask = VK_ACCESS_2_NONE,
560 ✗ .dstAccessMask = VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR |
561 VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR,
562 ✗ .oldLayout = di->layout,
563 .newLayout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR,
564 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
565 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
566 ✗ .image = di->img,
567 .subresourceRange = (VkImageSubresourceRange) {
568 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
569 .layerCount = 1,
570 .levelCount = 1,
571 },
572 };
573 ✗ nb_img_bar++;
574 ✗ di->layout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR;
575 }
576 }
577
578 /* COINCIDE-mode references only: DISTINCT-mode references are covered
579 * by the memory barrier, with pool-owned views */
580
0/2
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 49 not taken.
✗ if (!dec->dedicated_dpb) {
581
0/2
✗ Branch 48 → 39 not taken.
✗ Branch 48 → 49 not taken.
✗ for (int i = 0; i < vp->decode_info.referenceSlotCount; i++) {
582 ✗ AVFrame *ref_frame = rpic[i];
583 ✗ FFVulkanDecodePicture *rvp = rvkp[i];
584
585 ✗ err = ff_vk_exec_add_dep_frame(&ctx->s, exec, ref_frame,
586 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
587 VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR);
588
0/2
✗ Branch 40 → 41 not taken.
✗ Branch 40 → 43 not taken.
✗ if (err < 0) {
589 ✗ ff_vk_exec_discard(&ctx->s, exec);
590 ✗ return err;
591 }
592
593 /* The reference's image views are kept alive by the execution,
594 * so freeing the picture needs no host wait. */
595
0/4
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 46 not taken.
✗ Branch 44 → 45 not taken.
✗ Branch 44 → 46 not taken.
✗ if (err == 0 && rvp->out_views)
596 ✗ ff_vk_exec_add_dep_refstruct(&ctx->s, exec, rvp->out_views);
597
598 {
599 ✗ AVVkFrame *rvkf = (AVVkFrame *)ref_frame->data[0];
600
601 ✗ img_bar[nb_img_bar] = (VkImageMemoryBarrier2) {
602 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
603 .pNext = NULL,
604 .srcStageMask = VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
605 .dstStageMask = VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
606 .srcAccessMask = VK_ACCESS_2_NONE,
607 ✗ .dstAccessMask = VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR |
608 VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR,
609 ✗ .oldLayout = rvkf->layout[0],
610 .newLayout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR,
611 ✗ .srcQueueFamilyIndex = rvkf->queue_family[0],
612 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
613 ✗ .image = rvkf->img[0],
614 .subresourceRange = (VkImageSubresourceRange) {
615 ✗ .aspectMask = rvp->view.aspect_ref,
616 .layerCount = 1,
617 .levelCount = 1,
618 },
619 };
620 ✗ ff_vk_exec_update_frame(&ctx->s, exec, ref_frame,
621 ✗ &img_bar[nb_img_bar], &nb_img_bar);
622 }
623 }
624 }
625
626 /* Internal DPB images are queue-exclusive: one decode-stage memory
627 * barrier per submission orders all prior work, references included, so
628 * they need no semaphores or dependencies, and image barriers only for
629 * initial layout transitions. */
630 ✗ VkMemoryBarrier2 mem_bar = {
631 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
632 .srcStageMask = VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
633 .srcAccessMask = VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR,
634 .dstStageMask = VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
635 ✗ .dstAccessMask = VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR |
636 VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR,
637 };
638
639 /* Change image layouts, and synchronize the internal DPB if in use */
640 ✗ vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) {
641 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
642 .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT,
643 .pMemoryBarriers = &mem_bar,
644 ✗ .memoryBarrierCount = ctx->common.dpb ? 1 : 0,
645 .pImageMemoryBarriers = img_bar,
646 .imageMemoryBarrierCount = nb_img_bar,
647 });
648
649 /* Start, use parameters, decode and end decoding */
650 ✗ vk->CmdBeginVideoCodingKHR(cmd_buf, &decode_start);
651 ✗ vk->CmdDecodeVideoKHR(cmd_buf, &vp->decode_info);
652 ✗ vk->CmdEndVideoCodingKHR(cmd_buf, &decode_end);
653
654 /* End recording and submit for execution */
655 ✗ return ff_vk_exec_submit(&ctx->s, exec);
656 }
657
658 ✗ void ff_vk_decode_free_frame(AVHWDeviceContext *dev_ctx, FFVulkanDecodePicture *vp)
659 {
660 /* Free slices data */
661 ✗ av_refstruct_unref(&vp->slices_buf);
662
663 /* The views are kept alive by every execution referencing them, so no
664 * host wait is needed. */
665 ✗ av_refstruct_unref(&vp->out_views);
666
667 ✗ av_frame_free(&vp->dpb_frame);
668 /* No wait: pool reuse is ordered by the DPB barrier */
669 ✗ av_refstruct_unref(&vp->dpb_img);
670 ✗ }
671
672 ✗ static void free_common(AVRefStructOpaque unused, void *obj)
673 {
674 ✗ FFVulkanDecodeShared *ctx = obj;
675 ✗ FFVulkanContext *s = &ctx->s;
676
677 /* Wait on and free execution pool */
678 ✗ ff_vk_exec_pool_free(&ctx->s, &ctx->exec_pool);
679
680 ✗ av_refstruct_pool_uninit(&ctx->buf_pool);
681
682 ✗ ff_vk_video_common_uninit(s, &ctx->common);
683
684
0/2
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
✗ if (ctx->sd_ctx_free)
685 ✗ ctx->sd_ctx_free(ctx);
686
687 ✗ ff_vk_uninit(s);
688 ✗ }
689
690 ✗ static int vulkan_decode_bootstrap(AVCodecContext *avctx, AVBufferRef *frames_ref)
691 {
692 int err;
693 ✗ FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
694 ✗ const FFVulkanDecodeDescriptor *vk_desc = get_codecdesc(avctx->codec_id);
695 ✗ AVHWFramesContext *frames = (AVHWFramesContext *)frames_ref->data;
696 ✗ AVHWDeviceContext *device = (AVHWDeviceContext *)frames->device_ref->data;
697 ✗ AVVulkanDeviceContext *hwctx = device->hwctx;
698 FFVulkanDecodeShared *ctx;
699
700
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
✗ if (dec->shared_ctx)
701 ✗ return 0;
702
703 ✗ dec->shared_ctx = av_refstruct_alloc_ext(sizeof(*ctx), 0, NULL,
704 free_common);
705
0/2
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✗ if (!dec->shared_ctx)
706 ✗ return AVERROR(ENOMEM);
707
708 ✗ ctx = dec->shared_ctx;
709
710 ✗ ctx->s.extensions = ff_vk_extensions_to_mask(hwctx->enabled_dev_extensions,
711 hwctx->nb_enabled_dev_extensions);
712
713
0/2
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 14 not taken.
✗ if (vk_desc->queue_flags & VK_QUEUE_VIDEO_DECODE_BIT_KHR) {
714
0/2
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 14 not taken.
✗ if (!(ctx->s.extensions & FF_VK_EXT_VIDEO_DECODE_QUEUE)) {
715 ✗ av_log(avctx, AV_LOG_ERROR, "Device does not support the %s extension!\n",
716 VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME);
717 ✗ av_refstruct_unref(&dec->shared_ctx);
718 ✗ return AVERROR(ENOSYS);
719 }
720 }
721
722 ✗ err = ff_vk_load_functions(device, &ctx->s.vkfn, ctx->s.extensions, 1, 1);
723
0/2
✗ Branch 15 → 16 not taken.
✗ Branch 15 → 18 not taken.
✗ if (err < 0) {
724 ✗ av_refstruct_unref(&dec->shared_ctx);
725 ✗ return err;
726 }
727
728 ✗ return 0;
729 }
730
731 ✗ static VkResult vulkan_setup_profile(AVCodecContext *avctx,
732 FFVulkanDecodeProfileData *prof,
733 AVVulkanDeviceContext *hwctx,
734 FFVulkanFunctions *vk,
735 const FFVulkanDecodeDescriptor *vk_desc,
736 VkVideoDecodeH264CapabilitiesKHR *h264_caps,
737 VkVideoDecodeH265CapabilitiesKHR *h265_caps,
738 #if CONFIG_VP9_VULKAN_HWACCEL
739 VkVideoDecodeVP9CapabilitiesKHR *vp9_caps,
740 #endif
741 VkVideoDecodeAV1CapabilitiesKHR *av1_caps,
742 VkVideoCapabilitiesKHR *caps,
743 VkVideoDecodeCapabilitiesKHR *dec_caps,
744 int cur_profile)
745 {
746 ✗ VkVideoDecodeUsageInfoKHR *usage = &prof->usage;
747 ✗ VkVideoProfileInfoKHR *profile = &prof->profile;
748 ✗ VkVideoProfileListInfoKHR *profile_list = &prof->profile_list;
749
750 ✗ VkVideoDecodeH264ProfileInfoKHR *h264_profile = &prof->h264_profile;
751 ✗ VkVideoDecodeH265ProfileInfoKHR *h265_profile = &prof->h265_profile;
752 #if CONFIG_VP9_VULKAN_HWACCEL
753 ✗ VkVideoDecodeVP9ProfileInfoKHR *vp9_profile = &prof->vp9_profile;
754 #endif
755 ✗ VkVideoDecodeAV1ProfileInfoKHR *av1_profile = &prof->av1_profile;
756
757 ✗ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt);
758
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
✗ if (!desc)
759 ✗ return AVERROR(EINVAL);
760
761
0/2
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 10 not taken.
✗ if (avctx->codec_id == AV_CODEC_ID_H264) {
762 ✗ dec_caps->pNext = h264_caps;
763 ✗ usage->pNext = h264_profile;
764 ✗ h264_profile->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_INFO_KHR;
765
766 /* Vulkan transmits all the constrant_set flags, rather than wanting them
767 * merged in the profile IDC */
768 ✗ h264_profile->stdProfileIdc = cur_profile & ~(AV_PROFILE_H264_CONSTRAINED |
769 AV_PROFILE_H264_INTRA);
770
771 ✗ h264_profile->pictureLayout =
772 VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_PROGRESSIVE_KHR;
773 ✗ const H264Context *h = avctx->priv_data;
774
0/6
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 16 not taken.
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 16 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 16 not taken.
✗ if (h && h->ps.sps && !h->ps.sps->frame_mbs_only_flag)
775 ✗ h264_profile->pictureLayout =
776 VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_INTERLACED_INTERLEAVED_LINES_BIT_KHR;
777
0/2
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
✗ } else if (avctx->codec_id == AV_CODEC_ID_H265) {
778 ✗ dec_caps->pNext = h265_caps;
779 ✗ usage->pNext = h265_profile;
780 ✗ h265_profile->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_INFO_KHR;
781 ✗ h265_profile->stdProfileIdc = cur_profile;
782 #if CONFIG_VP9_VULKAN_HWACCEL
783
0/2
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 14 not taken.
✗ } else if (avctx->codec_id == AV_CODEC_ID_VP9) {
784 ✗ dec_caps->pNext = vp9_caps;
785 ✗ usage->pNext = vp9_profile;
786 ✗ vp9_profile->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_VP9_PROFILE_INFO_KHR;
787 ✗ vp9_profile->stdProfile = cur_profile;
788 #endif
789
0/2
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 16 not taken.
✗ } else if (avctx->codec_id == AV_CODEC_ID_AV1) {
790 ✗ dec_caps->pNext = av1_caps;
791 ✗ usage->pNext = av1_profile;
792 ✗ av1_profile->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_PROFILE_INFO_KHR;
793 ✗ av1_profile->stdProfile = cur_profile;
794 ✗ av1_profile->filmGrainSupport = !(avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN);
795 }
796
797 ✗ usage->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_USAGE_INFO_KHR;
798 ✗ usage->videoUsageHints = VK_VIDEO_DECODE_USAGE_DEFAULT_KHR;
799
800 ✗ profile->sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR;
801 ✗ profile->pNext = usage;
802 ✗ profile->videoCodecOperation = vk_desc->decode_op;
803 ✗ profile->chromaSubsampling = ff_vk_subsampling_from_av_desc(desc);
804 ✗ profile->lumaBitDepth = ff_vk_depth_from_av_depth(desc->comp[0].depth);
805 ✗ profile->chromaBitDepth = profile->lumaBitDepth;
806
807 /* A pixel format without a video profile representation is not a valid
808 * profile to query the capabilities for */
809
0/2
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 20 not taken.
✗ if (profile->chromaSubsampling == VK_VIDEO_CHROMA_SUBSAMPLING_INVALID_KHR ||
810
0/2
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 21 not taken.
✗ profile->lumaBitDepth == VK_VIDEO_COMPONENT_BIT_DEPTH_INVALID_KHR)
811 ✗ return VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR;
812
813 ✗ profile_list->sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR;
814 ✗ profile_list->profileCount = 1;
815 ✗ profile_list->pProfiles = profile;
816
817 /* Get the capabilities of the decoder for the given profile */
818 ✗ caps->sType = VK_STRUCTURE_TYPE_VIDEO_CAPABILITIES_KHR;
819 ✗ caps->pNext = dec_caps;
820 ✗ dec_caps->sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_CAPABILITIES_KHR;
821 /* dec_caps->pNext already filled in */
822
823 ✗ return vk->GetPhysicalDeviceVideoCapabilitiesKHR(hwctx->phys_dev, profile,
824 caps);
825 }
826
827 ✗ static int vulkan_decode_get_profile(AVCodecContext *avctx, AVBufferRef *frames_ref,
828 enum AVPixelFormat *pix_fmt, VkFormat *vk_fmt,
829 FFVulkanDecodeProfileData *prof,
830 int *dpb_dedicate)
831 {
832 VkResult ret;
833 int max_level, base_profile, cur_profile;
834 ✗ const FFVulkanDecodeDescriptor *vk_desc = get_codecdesc(avctx->codec_id);
835 ✗ AVHWFramesContext *frames = (AVHWFramesContext *)frames_ref->data;
836 ✗ AVHWDeviceContext *device = (AVHWDeviceContext *)frames->device_ref->data;
837 ✗ AVVulkanDeviceContext *hwctx = device->hwctx;
838 enum AVPixelFormat source_format;
839 enum AVPixelFormat best_format;
840 VkFormat best_vkfmt;
841
842 ✗ FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
843 ✗ FFVulkanDecodeShared *ctx = dec->shared_ctx;
844 ✗ FFVulkanFunctions *vk = &ctx->s.vkfn;
845
846 ✗ VkVideoCapabilitiesKHR *caps = &ctx->caps;
847 ✗ VkVideoDecodeCapabilitiesKHR *dec_caps = &ctx->dec_caps;
848
849 ✗ VkVideoDecodeH264CapabilitiesKHR h264_caps = {
850 .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_CAPABILITIES_KHR,
851 };
852 ✗ VkVideoDecodeH265CapabilitiesKHR h265_caps = {
853 .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_CAPABILITIES_KHR,
854 };
855 #if CONFIG_VP9_VULKAN_HWACCEL
856 ✗ VkVideoDecodeVP9CapabilitiesKHR vp9_caps = {
857 .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_VP9_CAPABILITIES_KHR,
858 };
859 #endif
860 ✗ VkVideoDecodeAV1CapabilitiesKHR av1_caps = {
861 .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_AV1_CAPABILITIES_KHR,
862 };
863
864 ✗ VkPhysicalDeviceVideoFormatInfoKHR fmt_info = {
865 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_FORMAT_INFO_KHR,
866 ✗ .pNext = &prof->profile_list,
867 };
868 VkVideoFormatPropertiesKHR *ret_info;
869 ✗ uint32_t nb_out_fmts = 0;
870
871
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 7 not taken.
✗ if (!(vk_desc->decode_extension & ctx->s.extensions)) {
872 ✗ av_log(avctx, AV_LOG_ERROR, "Device does not support decoding %s!\n",
873 avcodec_get_name(avctx->codec_id));
874 ✗ return AVERROR(ENOSYS);
875 }
876
877 ✗ cur_profile = avctx->profile;
878
0/2
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 9 not taken.
✗ base_profile = avctx->codec_id == AV_CODEC_ID_H264 ? AV_PROFILE_H264_CONSTRAINED_BASELINE :
879 ✗ avctx->codec_id == AV_CODEC_ID_H265 ? AV_PROFILE_HEVC_MAIN :
880 #if CONFIG_VP9_VULKAN_HWACCEL
881 avctx->codec_id == AV_CODEC_ID_VP9 ? STD_VIDEO_VP9_PROFILE_0 :
882 #endif
883 avctx->codec_id == AV_CODEC_ID_AV1 ? STD_VIDEO_AV1_PROFILE_MAIN :
884 0;
885
886 ✗ ret = vulkan_setup_profile(avctx, prof, hwctx, vk, vk_desc,
887 &h264_caps,
888 &h265_caps,
889 #if CONFIG_VP9_VULKAN_HWACCEL
890 &vp9_caps,
891 #endif
892 &av1_caps,
893 caps,
894 dec_caps,
895 cur_profile);
896
0/2
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 19 not taken.
✗ if (ret == VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR &&
897
0/2
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 19 not taken.
✗ avctx->flags & AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH &&
898
0/2
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 19 not taken.
✗ avctx->profile != base_profile) {
899 ✗ av_log(avctx, AV_LOG_VERBOSE, "%s profile %s not supported, attempting "
900 "again with profile %s\n",
901 avcodec_get_name(avctx->codec_id),
902 avcodec_profile_name(avctx->codec_id, cur_profile),
903 avcodec_profile_name(avctx->codec_id, base_profile));
904 ✗ cur_profile = base_profile;
905 ✗ ret = vulkan_setup_profile(avctx, prof, hwctx, vk, vk_desc,
906 &h264_caps,
907 &h265_caps,
908 #if CONFIG_VP9_VULKAN_HWACCEL
909 &vp9_caps,
910 #endif
911 &av1_caps,
912 caps,
913 dec_caps,
914 cur_profile);
915 }
916
917
0/4
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 21 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 20 → 25 not taken.
✗ if (ret == VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR ||
918 ret == VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR) {
919 ✗ av_log(avctx, AV_LOG_VERBOSE, "Unable to initialize video session: "
920 "%s profile \"%s\" not supported!\n",
921 avcodec_get_name(avctx->codec_id),
922 avcodec_profile_name(avctx->codec_id, cur_profile));
923 ✗ return AVERROR(EINVAL);
924
0/2
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 30 not taken.
✗ } else if (ret == VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR) {
925
0/2
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 28 not taken.
✗ if (avctx->codec_id == AV_CODEC_ID_H264)
926 ✗ av_log(avctx, AV_LOG_VERBOSE, "Unable to initialize video session: "
927 "pictureLayout %#x not supported!\n",
928 ✗ (unsigned)prof->h264_profile.pictureLayout);
929 else
930 ✗ av_log(avctx, AV_LOG_VERBOSE, "Unable to initialize video session: "
931 "pictureLayout not supported!\n");
932 ✗ return AVERROR(EINVAL);
933
0/2
✗ Branch 30 → 31 not taken.
✗ Branch 30 → 34 not taken.
✗ } else if (ret == VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR) {
934 ✗ av_log(avctx, AV_LOG_VERBOSE, "Unable to initialize video session: "
935 "format (%s) not supported!\n",
936 av_get_pix_fmt_name(avctx->sw_pix_fmt));
937 ✗ return AVERROR(EINVAL);
938
0/4
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 36 not taken.
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 37 not taken.
✗ } else if (ret == VK_ERROR_FEATURE_NOT_PRESENT ||
939 ret == VK_ERROR_FORMAT_NOT_SUPPORTED) {
940 ✗ return AVERROR(EINVAL);
941
0/2
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 39 not taken.
✗ } else if (ret != VK_SUCCESS) {
942 ✗ return AVERROR_EXTERNAL;
943 }
944
945
0/2
✗ Branch 39 → 40 not taken.
✗ Branch 39 → 41 not taken.
✗ max_level = avctx->codec_id == AV_CODEC_ID_H264 ? ff_vk_h264_level_to_av(h264_caps.maxLevelIdc) :
946
0/2
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 43 not taken.
✗ avctx->codec_id == AV_CODEC_ID_H265 ? ff_vk_h265_level_to_av(h265_caps.maxLevelIdc) :
947 #if CONFIG_VP9_VULKAN_HWACCEL
948
0/2
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 45 not taken.
✗ avctx->codec_id == AV_CODEC_ID_VP9 ? vp9_caps.maxLevel :
949 #endif
950
0/2
✗ Branch 45 → 46 not taken.
✗ Branch 45 → 47 not taken.
✗ avctx->codec_id == AV_CODEC_ID_AV1 ? av1_caps.maxLevel :
951 0;
952
953 ✗ av_log(avctx, AV_LOG_VERBOSE, "Decoder capabilities for %s profile \"%s\":\n",
954 avcodec_get_name(avctx->codec_id),
955 avcodec_profile_name(avctx->codec_id, cur_profile));
956 ✗ av_log(avctx, AV_LOG_VERBOSE, " Maximum level: %i (stream %i)\n",
957 max_level, avctx->level);
958 ✗ av_log(avctx, AV_LOG_VERBOSE, " Width: from %i to %i\n",
959 caps->minCodedExtent.width, caps->maxCodedExtent.width);
960 ✗ av_log(avctx, AV_LOG_VERBOSE, " Height: from %i to %i\n",
961 caps->minCodedExtent.height, caps->maxCodedExtent.height);
962 ✗ av_log(avctx, AV_LOG_VERBOSE, " Width alignment: %i\n",
963 caps->pictureAccessGranularity.width);
964 ✗ av_log(avctx, AV_LOG_VERBOSE, " Height alignment: %i\n",
965 caps->pictureAccessGranularity.height);
966 ✗ av_log(avctx, AV_LOG_VERBOSE, " Bitstream offset alignment: %"PRIu64"\n",
967 caps->minBitstreamBufferOffsetAlignment);
968 ✗ av_log(avctx, AV_LOG_VERBOSE, " Bitstream size alignment: %"PRIu64"\n",
969 caps->minBitstreamBufferSizeAlignment);
970 ✗ av_log(avctx, AV_LOG_VERBOSE, " Maximum references: %u\n",
971 caps->maxDpbSlots);
972 ✗ av_log(avctx, AV_LOG_VERBOSE, " Maximum active references: %u\n",
973 caps->maxActiveReferencePictures);
974 ✗ av_log(avctx, AV_LOG_VERBOSE, " Codec header name: '%s' (driver), '%s' (compiled)\n",
975 ✗ caps->stdHeaderVersion.extensionName,
976 ✗ vk_desc->ext_props.extensionName);
977 ✗ av_log(avctx, AV_LOG_VERBOSE, " Codec header version: %i.%i.%i (driver), %i.%i.%i (compiled)\n",
978 ✗ CODEC_VER(caps->stdHeaderVersion.specVersion),
979 ✗ CODEC_VER(vk_desc->ext_props.specVersion));
980 ✗ av_log(avctx, AV_LOG_VERBOSE, " Decode modes:%s%s%s\n",
981
0/2
✗ Branch 68 → 69 not taken.
✗ Branch 68 → 70 not taken.
✗ dec_caps->flags ? "" :
982 " invalid",
983
0/2
✗ Branch 65 → 66 not taken.
✗ Branch 65 → 67 not taken.
✗ dec_caps->flags & VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR ?
984 " reuse_dst_dpb" : "",
985
0/2
✗ Branch 62 → 63 not taken.
✗ Branch 62 → 64 not taken.
✗ dec_caps->flags & VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR ?
986 " dedicated_dpb" : "");
987 ✗ av_log(avctx, AV_LOG_VERBOSE, " Capability flags:%s%s%s\n",
988
0/2
✗ Branch 78 → 79 not taken.
✗ Branch 78 → 80 not taken.
✗ caps->flags ? "" :
989 " none",
990
0/2
✗ Branch 75 → 76 not taken.
✗ Branch 75 → 77 not taken.
✗ caps->flags & VK_VIDEO_CAPABILITY_PROTECTED_CONTENT_BIT_KHR ?
991 " protected" : "",
992
0/2
✗ Branch 72 → 73 not taken.
✗ Branch 72 → 74 not taken.
✗ caps->flags & VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR ?
993 " separate_references" : "");
994
995 /* Check if decoding is possible with the given parameters */
996
0/2
✗ Branch 82 → 83 not taken.
✗ Branch 82 → 86 not taken.
✗ if (avctx->coded_width < caps->minCodedExtent.width ||
997
0/2
✗ Branch 83 → 84 not taken.
✗ Branch 83 → 86 not taken.
✗ avctx->coded_height < caps->minCodedExtent.height ||
998
0/2
✗ Branch 84 → 85 not taken.
✗ Branch 84 → 86 not taken.
✗ avctx->coded_width > caps->maxCodedExtent.width ||
999
0/2
✗ Branch 85 → 86 not taken.
✗ Branch 85 → 87 not taken.
✗ avctx->coded_height > caps->maxCodedExtent.height)
1000 ✗ return AVERROR(EINVAL);
1001
1002
0/2
✗ Branch 87 → 88 not taken.
✗ Branch 87 → 90 not taken.
✗ if (!(avctx->hwaccel_flags & AV_HWACCEL_FLAG_IGNORE_LEVEL) &&
1003
0/2
✗ Branch 88 → 89 not taken.
✗ Branch 88 → 90 not taken.
✗ avctx->level > max_level)
1004 ✗ return AVERROR(EINVAL);
1005
1006 /* Some basic sanity checking */
1007
0/2
✗ Branch 90 → 91 not taken.
✗ Branch 90 → 93 not taken.
✗ if (!(dec_caps->flags & (VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR |
1008 VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR))) {
1009 ✗ av_log(avctx, AV_LOG_ERROR, "Buggy driver signals invalid decoding mode: neither "
1010 "VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR nor "
1011 "VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR are set!\n");
1012 ✗ return AVERROR_EXTERNAL;
1013
0/2
✗ Branch 93 → 94 not taken.
✗ Branch 93 → 96 not taken.
✗ } else if ((dec_caps->flags & (VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR |
1014 VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR)) ==
1015 ✗ VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR &&
1016
0/2
✗ Branch 94 → 95 not taken.
✗ Branch 94 → 96 not taken.
✗ !(caps->flags & VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR)) {
1017 ✗ av_log(avctx, AV_LOG_VERBOSE,
1018 "COINCIDE-only decode without SEPARATE_REFERENCE_IMAGES "
1019 "(layered DPB capability); continuing\n");
1020 }
1021
1022 ✗ dec->dedicated_dpb = !!(dec_caps->flags & VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR);
1023
0/2
✗ Branch 96 → 97 not taken.
✗ Branch 96 → 99 not taken.
✗ ctx->common.layered_dpb = !dec->dedicated_dpb ? 0 :
1024
0/2
✗ Branch 97 → 98 not taken.
✗ Branch 97 → 99 not taken.
✗ !(caps->flags & VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR);
1025
1026
0/2
✗ Branch 100 → 101 not taken.
✗ Branch 100 → 102 not taken.
✗ if (dec->dedicated_dpb) {
1027 ✗ fmt_info.imageUsage = VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR;
1028 } else {
1029 ✗ fmt_info.imageUsage = VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR |
1030 VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR |
1031 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
1032 VK_IMAGE_USAGE_SAMPLED_BIT;
1033
1034
0/2
✗ Branch 102 → 103 not taken.
✗ Branch 102 → 105 not taken.
✗ if ((ctx->s.extensions & FF_VK_EXT_VIDEO_ENCODE_QUEUE) &&
1035
0/2
✗ Branch 103 → 104 not taken.
✗ Branch 103 → 105 not taken.
✗ (ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_1))
1036 ✗ fmt_info.imageUsage |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR;
1037 }
1038
1039 /* Get the format of the images necessary */
1040 ✗ ret = vk->GetPhysicalDeviceVideoFormatPropertiesKHR(hwctx->phys_dev,
1041 &fmt_info,
1042 &nb_out_fmts, NULL);
1043
0/2
✗ Branch 106 → 107 not taken.
✗ Branch 106 → 109 not taken.
✗ if (ret == VK_ERROR_FORMAT_NOT_SUPPORTED ||
1044
0/4
✗ Branch 107 → 108 not taken.
✗ Branch 107 → 110 not taken.
✗ Branch 108 → 109 not taken.
✗ Branch 108 → 110 not taken.
✗ (!nb_out_fmts && ret == VK_SUCCESS)) {
1045 ✗ return AVERROR(EINVAL);
1046
0/2
✗ Branch 110 → 111 not taken.
✗ Branch 110 → 114 not taken.
✗ } else if (ret != VK_SUCCESS) {
1047 ✗ av_log(avctx, AV_LOG_ERROR, "Unable to get Vulkan format properties: %s!\n",
1048 ff_vk_ret2str(ret));
1049 ✗ return AVERROR_EXTERNAL;
1050 }
1051
1052 ✗ ret_info = av_mallocz(sizeof(*ret_info)*nb_out_fmts);
1053
0/2
✗ Branch 115 → 116 not taken.
✗ Branch 115 → 117 not taken.
✗ if (!ret_info)
1054 ✗ return AVERROR(ENOMEM);
1055
1056
0/2
✗ Branch 119 → 118 not taken.
✗ Branch 119 → 120 not taken.
✗ for (int i = 0; i < nb_out_fmts; i++)
1057 ✗ ret_info[i].sType = VK_STRUCTURE_TYPE_VIDEO_FORMAT_PROPERTIES_KHR;
1058
1059 ✗ ret = vk->GetPhysicalDeviceVideoFormatPropertiesKHR(hwctx->phys_dev,
1060 &fmt_info,
1061 &nb_out_fmts, ret_info);
1062
0/2
✗ Branch 121 → 122 not taken.
✗ Branch 121 → 124 not taken.
✗ if (ret == VK_ERROR_FORMAT_NOT_SUPPORTED ||
1063
0/4
✗ Branch 122 → 123 not taken.
✗ Branch 122 → 126 not taken.
✗ Branch 123 → 124 not taken.
✗ Branch 123 → 126 not taken.
✗ (!nb_out_fmts && ret == VK_SUCCESS)) {
1064 ✗ av_free(ret_info);
1065 ✗ return AVERROR(EINVAL);
1066
0/2
✗ Branch 126 → 127 not taken.
✗ Branch 126 → 131 not taken.
✗ } else if (ret != VK_SUCCESS) {
1067 ✗ av_log(avctx, AV_LOG_ERROR, "Unable to get Vulkan format properties: %s!\n",
1068 ff_vk_ret2str(ret));
1069 ✗ av_free(ret_info);
1070 ✗ return AVERROR_EXTERNAL;
1071 }
1072
1073 /* Find a format to use */
1074 ✗ *pix_fmt = best_format = AV_PIX_FMT_NONE;
1075 ✗ *vk_fmt = best_vkfmt = VK_FORMAT_UNDEFINED;
1076 ✗ source_format = avctx->sw_pix_fmt;
1077
1078 ✗ av_log(avctx, AV_LOG_DEBUG, "Choosing best pixel format for decoding from %i:\n", nb_out_fmts);
1079
0/2
✗ Branch 146 → 133 not taken.
✗ Branch 146 → 147 not taken.
✗ for (int i = 0; i < nb_out_fmts; i++) {
1080 ✗ enum AVPixelFormat tmp = ff_vk_pix_fmt_from_vkfmt(ret_info[i].format);
1081
0/2
✗ Branch 134 → 135 not taken.
✗ Branch 134 → 137 not taken.
✗ if (tmp == AV_PIX_FMT_NONE) {
1082 ✗ av_log(avctx, AV_LOG_WARNING, "Invalid/unknown Vulkan format %i!\n", ret_info[i].format);
1083 ✗ continue;
1084 }
1085
1086 ✗ best_format = av_find_best_pix_fmt_of_2(tmp, best_format, source_format, 0, NULL);
1087
0/2
✗ Branch 138 → 139 not taken.
✗ Branch 138 → 140 not taken.
✗ if (tmp == best_format)
1088 ✗ best_vkfmt = ret_info[i].format;
1089
1090 ✗ av_log(avctx, AV_LOG_DEBUG, " %s%s (Vulkan ID: %i)\n",
1091 av_get_pix_fmt_name(tmp), tmp == best_format ? "*" : "",
1092
0/2
✗ Branch 140 → 141 not taken.
✗ Branch 140 → 142 not taken.
✗ ret_info[i].format);
1093 }
1094
1095 ✗ av_free(ret_info);
1096
1097
0/2
✗ Branch 148 → 149 not taken.
✗ Branch 148 → 151 not taken.
✗ if (best_format == AV_PIX_FMT_NONE) {
1098 ✗ av_log(avctx, AV_LOG_ERROR, "No valid/compatible pixel format found for decoding!\n");
1099 ✗ return AVERROR(EINVAL);
1100 } else {
1101 ✗ av_log(avctx, AV_LOG_VERBOSE, "Chosen frame pixfmt: %s (Vulkan ID: %i)\n",
1102 av_get_pix_fmt_name(best_format), best_vkfmt);
1103 }
1104
1105 ✗ *pix_fmt = best_format;
1106 ✗ *vk_fmt = best_vkfmt;
1107
1108 ✗ *dpb_dedicate = dec->dedicated_dpb;
1109
1110 ✗ return 0;
1111 }
1112
1113 ✗ static void free_profile_data(AVHWFramesContext *hwfc)
1114 {
1115 ✗ av_free(hwfc->user_opaque);
1116 ✗ }
1117
1118 ✗ int ff_vk_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx)
1119 {
1120 int err, dedicated_dpb;
1121 ✗ AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ctx->data;
1122 ✗ AVVulkanFramesContext *hwfc = frames_ctx->hwctx;
1123 ✗ FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
1124 ✗ FFVulkanDecodeProfileData *prof = NULL;
1125
1126 ✗ err = vulkan_decode_bootstrap(avctx, hw_frames_ctx);
1127
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
✗ if (err < 0)
1128 ✗ return err;
1129
1130 ✗ frames_ctx->format = AV_PIX_FMT_VULKAN;
1131 ✗ frames_ctx->sw_format = avctx->sw_pix_fmt;
1132 ✗ frames_ctx->width = avctx->coded_width;
1133 ✗ frames_ctx->height = avctx->coded_height;
1134
1135
0/10
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 19 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 19 not taken.
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 19 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 19 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 19 not taken.
✗ if (!DECODER_IS_SDR(avctx->codec_id)) {
1136 ✗ prof = av_mallocz(sizeof(FFVulkanDecodeProfileData));
1137
0/2
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 13 not taken.
✗ if (!prof)
1138 ✗ return AVERROR(ENOMEM);
1139
1140 ✗ err = vulkan_decode_get_profile(avctx, hw_frames_ctx,
1141 &frames_ctx->sw_format,
1142 &hwfc->format[0],
1143 prof, &dedicated_dpb);
1144
0/2
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 17 not taken.
✗ if (err < 0) {
1145 ✗ av_free(prof);
1146 ✗ return err;
1147 }
1148
1149 ✗ const AVPixFmtDescriptor *pdesc = av_pix_fmt_desc_get(frames_ctx->sw_format);
1150 ✗ frames_ctx->width = FFALIGN(frames_ctx->width, 1 << pdesc->log2_chroma_w);
1151 ✗ frames_ctx->height = FFALIGN(frames_ctx->height, 1 << pdesc->log2_chroma_h);
1152 ✗ frames_ctx->user_opaque = prof;
1153 ✗ frames_ctx->free = free_profile_data;
1154
1155 ✗ hwfc->create_pnext = &prof->profile_list;
1156 } else {
1157 ✗ hwfc->format[0] = VK_FORMAT_UNDEFINED;
1158
0/9
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 21 not taken.
✗ Branch 19 → 22 not taken.
✗ Branch 19 → 23 not taken.
✗ Branch 19 → 24 not taken.
✗ Branch 19 → 25 not taken.
✗ Branch 19 → 26 not taken.
✗ Branch 19 → 27 not taken.
✗ Branch 19 → 28 not taken.
✗ switch (frames_ctx->sw_format) {
1159 ✗ case AV_PIX_FMT_GBRAP16:
1160 /* This should be more efficient for downloading and using */
1161 ✗ frames_ctx->sw_format = AV_PIX_FMT_RGBA64;
1162 ✗ break;
1163 ✗ case AV_PIX_FMT_GBRP10:
1164 /* This saves memory bandwidth when downloading */
1165 ✗ frames_ctx->sw_format = AV_PIX_FMT_X2BGR10;
1166 ✗ break;
1167 ✗ case AV_PIX_FMT_RGB24:
1168 case AV_PIX_FMT_BGR0:
1169 /* mpv has issues with bgr0 mapping, so just remap it */
1170 ✗ frames_ctx->sw_format = AV_PIX_FMT_RGB0;
1171 ✗ break;
1172 /* DPX endian mismatch remappings */
1173 ✗ case AV_PIX_FMT_RGB48LE:
1174 ✗ case AV_PIX_FMT_RGB48BE: frames_ctx->sw_format = AV_PIX_FMT_GBRP16; break;
1175 ✗ case AV_PIX_FMT_RGBA64BE: frames_ctx->sw_format = AV_PIX_FMT_RGBA64; break;
1176 ✗ case AV_PIX_FMT_GRAY16BE: frames_ctx->sw_format = AV_PIX_FMT_GRAY16; break;
1177 /* ProRes needs to clear the input image, which is not possible on YUV formats */
1178 ✗ case AV_PIX_FMT_YUVA422P10:
1179 case AV_PIX_FMT_YUVA444P10:
1180 case AV_PIX_FMT_YUVA422P12:
1181 case AV_PIX_FMT_YUVA444P12:
1182 ✗ hwfc->format[3] = VK_FORMAT_R16_UNORM;
1183 av_fallthrough;
1184 ✗ case AV_PIX_FMT_YUV422P10:
1185 case AV_PIX_FMT_YUV444P10:
1186 case AV_PIX_FMT_YUV422P12:
1187 case AV_PIX_FMT_YUV444P12:
1188 ✗ hwfc->format[0] = VK_FORMAT_R16_UNORM;
1189 ✗ hwfc->format[1] = VK_FORMAT_R16_UNORM;
1190 ✗ hwfc->format[2] = VK_FORMAT_R16_UNORM;
1191 ✗ break;
1192 ✗ default:
1193 ✗ break;
1194 }
1195 }
1196
1197
0/2
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 31 not taken.
✗ if (hwfc->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)
1198 ✗ hwfc->tiling = VK_IMAGE_TILING_OPTIMAL;
1199
1200 ✗ hwfc->usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
1201 VK_IMAGE_USAGE_STORAGE_BIT |
1202 VK_IMAGE_USAGE_SAMPLED_BIT;
1203
1204
0/2
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 37 not taken.
✗ if (prof) {
1205 FFVulkanDecodeShared *ctx;
1206
1207 ✗ hwfc->usage |= VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR;
1208
0/2
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 34 not taken.
✗ if (!dec->dedicated_dpb)
1209 ✗ hwfc->usage |= VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR;
1210
1211 ✗ ctx = dec->shared_ctx;
1212
0/2
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 37 not taken.
✗ if ((ctx->s.extensions & FF_VK_EXT_VIDEO_ENCODE_QUEUE) &&
1213
0/2
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 37 not taken.
✗ (ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_1))
1214 ✗ hwfc->usage |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR;
1215 }
1216
1217 ✗ return err;
1218 }
1219
1220 ✗ static void vk_decode_free_params(AVRefStructOpaque opaque, void *obj)
1221 {
1222 ✗ FFVulkanDecodeShared *ctx = opaque.nc;
1223 ✗ FFVulkanFunctions *vk = &ctx->s.vkfn;
1224 ✗ VkVideoSessionParametersKHR *par = obj;
1225 ✗ vk->DestroyVideoSessionParametersKHR(ctx->s.hwctx->act_dev, *par,
1226 ✗ ctx->s.hwctx->alloc);
1227 ✗ }
1228
1229 ✗ int ff_vk_decode_create_params(VkVideoSessionParametersKHR **par_ref, void *logctx, FFVulkanDecodeShared *ctx,
1230 const VkVideoSessionParametersCreateInfoKHR *session_params_create)
1231 {
1232 VkVideoSessionParametersKHR *par;
1233 ✗ const FFVulkanFunctions *vk = &ctx->s.vkfn;
1234 VkResult ret;
1235
1236 ✗ par = av_refstruct_alloc_ext(sizeof(*par), 0, ctx, vk_decode_free_params);
1237
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
✗ if (!par)
1238 ✗ return AVERROR(ENOMEM);
1239
1240 /* Create session parameters */
1241 ✗ ret = vk->CreateVideoSessionParametersKHR(ctx->s.hwctx->act_dev, session_params_create,
1242 ✗ ctx->s.hwctx->alloc, par);
1243
0/2
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 11 not taken.
✗ if (ret != VK_SUCCESS) {
1244 ✗ av_log(logctx, AV_LOG_ERROR, "Unable to create Vulkan video session parameters: %s!\n",
1245 ff_vk_ret2str(ret));
1246 ✗ *par = VK_NULL_HANDLE;
1247 ✗ av_refstruct_unref(&par);
1248 ✗ return AVERROR_EXTERNAL;
1249 }
1250 ✗ *par_ref = par;
1251
1252 ✗ return 0;
1253 }
1254
1255 ✗ int ff_vk_decode_uninit(AVCodecContext *avctx)
1256 {
1257 ✗ FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
1258
1259 ✗ av_freep(&dec->hevc_headers);
1260 ✗ av_refstruct_unref(&dec->session_params);
1261 ✗ av_refstruct_unref(&dec->shared_ctx);
1262 ✗ av_freep(&dec->slice_off);
1263 ✗ return 0;
1264 }
1265
1266 ✗ int ff_vk_decode_init(AVCodecContext *avctx)
1267 {
1268 int err;
1269 ✗ FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
1270 FFVulkanDecodeShared *ctx;
1271 FFVulkanContext *s;
1272 int async_depth;
1273 const VkVideoProfileInfoKHR *profile;
1274 const FFVulkanDecodeDescriptor *vk_desc;
1275
1276 ✗ VkVideoSessionCreateInfoKHR session_create = {
1277 .sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_CREATE_INFO_KHR,
1278 };
1279
1280 ✗ err = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_VULKAN);
1281
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
✗ if (err < 0)
1282 ✗ return err;
1283
1284 /* Initialize contexts */
1285 ✗ ctx = dec->shared_ctx;
1286 ✗ s = &ctx->s;
1287
1288 ✗ err = ff_vk_init(s, avctx, NULL, avctx->hw_frames_ctx);
1289
0/2
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✗ if (err < 0)
1290 ✗ return err;
1291
1292 ✗ vk_desc = get_codecdesc(avctx->codec_id);
1293
1294 ✗ profile = get_video_profile(ctx, avctx->codec_id);
1295
0/4
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 14 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 14 not taken.
✗ if ((vk_desc->queue_flags & VK_QUEUE_VIDEO_DECODE_BIT_KHR) && !profile) {
1296 ✗ av_log(avctx, AV_LOG_ERROR, "Video profile missing from frames context!");
1297 ✗ return AVERROR(EINVAL);
1298 }
1299
1300 /* Create queue context */
1301 ✗ vk_desc = get_codecdesc(avctx->codec_id);
1302 ✗ ctx->qf = ff_vk_qf_find(s, vk_desc->queue_flags, vk_desc->decode_op);
1303
0/2
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 20 not taken.
✗ if (!ctx->qf) {
1304 ✗ av_log(avctx, AV_LOG_ERROR, "Decoding of %s is not supported by this device\n",
1305 avcodec_get_name(avctx->codec_id));
1306 ✗ return err;
1307 }
1308
1309 ✗ session_create.queueFamilyIndex = ctx->qf->idx;
1310 ✗ session_create.maxCodedExtent = ctx->caps.maxCodedExtent;
1311 ✗ session_create.maxDpbSlots = ctx->caps.maxDpbSlots;
1312 ✗ session_create.maxActiveReferencePictures = ctx->caps.maxActiveReferencePictures;
1313 ✗ session_create.pictureFormat = s->hwfc->format[0];
1314 ✗ session_create.referencePictureFormat = session_create.pictureFormat;
1315 ✗ session_create.pStdHeaderVersion = &vk_desc->ext_props;
1316 ✗ session_create.pVideoProfile = profile;
1317 #ifdef VK_KHR_video_maintenance2
1318
0/2
✗ Branch 20 → 21 not taken.
✗ Branch 20 → 22 not taken.
✗ if (ctx->s.extensions & FF_VK_EXT_VIDEO_MAINTENANCE_2)
1319 ✗ session_create.flags = VK_VIDEO_SESSION_CREATE_INLINE_SESSION_PARAMETERS_BIT_KHR;
1320 #endif
1321
1322 /* Create the decode exec context.
1323 * A small fixed depth is enough to keep the GPU fed, as submissions are
1324 * serialized for hardware decoding; thread-safe hwaccels submit from
1325 * every frame thread concurrently, and need a context per thread. */
1326 ✗ async_depth = FF_VK_DEFAULT_EXEC_CONTEXTS;
1327
0/2
✗ Branch 23 → 24 not taken.
✗ Branch 23 → 25 not taken.
✗ if (ffhwaccel(avctx->hwaccel)->caps_internal & HWACCEL_CAP_THREAD_SAFE)
1328 ✗ async_depth = FFMAX(async_depth, avctx->thread_count);
1329
1330 ✗ err = ff_vk_exec_pool_init(s, ctx->qf, &ctx->exec_pool,
1331 async_depth, 0, 0, 0, profile);
1332
0/2
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 28 not taken.
✗ if (err < 0)
1333 ✗ goto fail;
1334
1335
0/10
✗ Branch 28 → 29 not taken.
✗ Branch 28 → 36 not taken.
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 36 not taken.
✗ Branch 30 → 31 not taken.
✗ Branch 30 → 36 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 36 not taken.
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 36 not taken.
✗ if (!DECODER_IS_SDR(avctx->codec_id)) {
1336 ✗ err = ff_vk_video_common_init(avctx, s, &ctx->common, &session_create);
1337
0/2
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 36 not taken.
✗ if (err < 0)
1338 ✗ goto fail;
1339 }
1340
1341 /* Out-of-place decoding: create the internal, queue-exclusive DPB pool */
1342
0/4
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 38 not taken.
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 63 not taken.
✗ if (dec->dedicated_dpb || avctx->codec_id == AV_CODEC_ID_AV1) {
1343 ✗ VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
1344 ✗ void *create_pnext = (void *)ff_vk_find_struct(ctx->s.hwfc->create_pnext,
1345 VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR);
1346 /* With DPB_AND_OUTPUT_DISTINCT, DPB images never leave the decoder,
1347 * so they don't need the output's DRM modifiers. */
1348 ✗ void *drm_create_pnext = (void *)ff_vk_find_struct(ctx->s.hwfc->create_pnext,
1349 VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
1350
0/2
✗ Branch 40 → 41 not taken.
✗ Branch 40 → 43 not taken.
✗ if (drm_create_pnext &&
1351
0/2
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 43 not taken.
✗ !(ctx->dec_caps.flags & VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR)) {
1352 ✗ create_pnext = drm_create_pnext;
1353 ✗ tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
1354 av_assert2(ff_vk_find_struct(drm_create_pnext, VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR));
1355 }
1356
1357 ✗ err = ff_vk_video_dpb_init(s, &ctx->common, s->hwfc->format[0],
1358 VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR,
1359 tiling, create_pnext,
1360 ✗ s->frames->width, s->frames->height,
1361
0/2
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 45 not taken.
✗ ctx->common.layered_dpb ?
1362 ✗ ctx->caps.maxDpbSlots : 1);
1363
0/2
✗ Branch 47 → 48 not taken.
✗ Branch 47 → 49 not taken.
✗ if (err < 0)
1364 ✗ goto fail;
1365
1366
0/2
✗ Branch 49 → 50 not taken.
✗ Branch 49 → 63 not taken.
✗ if (ctx->common.layered_dpb) {
1367 ✗ FFVulkanFunctions *vk = &ctx->s.vkfn;
1368 FFVkExecContext *exec;
1369 VkImageMemoryBarrier2 img_bar;
1370
1371 ✗ ctx->common.layered_img = av_refstruct_pool_get(ctx->common.dpb->img_pool);
1372
0/2
✗ Branch 51 → 52 not taken.
✗ Branch 51 → 53 not taken.
✗ if (!ctx->common.layered_img) {
1373 ✗ err = AVERROR(ENOMEM);
1374 ✗ goto fail;
1375 }
1376
1377 ✗ ctx->common.layered_view = ctx->common.layered_img->view;
1378 ✗ ctx->common.layered_aspect = ctx->common.layered_img->aspect;
1379
1380 /* Created eagerly, so transitioned eagerly; per-picture images
1381 * transition on first use instead */
1382 ✗ exec = ff_vk_exec_get(&ctx->s, &ctx->exec_pool);
1383 ✗ err = ff_vk_exec_start(&ctx->s, exec);
1384
0/2
✗ Branch 55 → 56 not taken.
✗ Branch 55 → 57 not taken.
✗ if (err < 0)
1385 ✗ goto fail;
1386
1387 ✗ img_bar = (VkImageMemoryBarrier2) {
1388 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
1389 .srcStageMask = VK_PIPELINE_STAGE_2_NONE,
1390 .dstStageMask = VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR,
1391 .srcAccessMask = VK_ACCESS_2_NONE,
1392 ✗ .dstAccessMask = VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR |
1393 VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR,
1394 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
1395 .newLayout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR,
1396 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
1397 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
1398 ✗ .image = ctx->common.layered_img->img,
1399 .subresourceRange = (VkImageSubresourceRange) {
1400 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
1401 .layerCount = VK_REMAINING_ARRAY_LAYERS,
1402 .levelCount = 1,
1403 },
1404 };
1405 ✗ vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) {
1406 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
1407 .pImageMemoryBarriers = &img_bar,
1408 .imageMemoryBarrierCount = 1,
1409 });
1410
1411 ✗ err = ff_vk_exec_submit(&ctx->s, exec);
1412
0/2
✗ Branch 59 → 60 not taken.
✗ Branch 59 → 61 not taken.
✗ if (err < 0)
1413 ✗ goto fail;
1414
1415 ✗ ctx->common.layered_img->layout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR;
1416 }
1417 }
1418
1419
0/10
✗ Branch 63 → 64 not taken.
✗ Branch 63 → 72 not taken.
✗ Branch 64 → 65 not taken.
✗ Branch 64 → 72 not taken.
✗ Branch 65 → 66 not taken.
✗ Branch 65 → 72 not taken.
✗ Branch 66 → 67 not taken.
✗ Branch 66 → 72 not taken.
✗ Branch 67 → 68 not taken.
✗ Branch 67 → 72 not taken.
✗ if (!DECODER_IS_SDR(avctx->codec_id)) {
1420 ✗ err = decode_reset(avctx, ctx);
1421
0/2
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 71 not taken.
✗ if (err < 0)
1422 ✗ return err;
1423 } else {
1424 /* For SDR decoders, this alignment value will be 0. Since this will make
1425 * add_slice() malfunction, set it to a sane default value. */
1426 ✗ ctx->caps.minBitstreamBufferSizeAlignment = AV_INPUT_BUFFER_PADDING_SIZE;
1427 }
1428
1429 const VkPhysicalDeviceDriverProperties *driver_props;
1430 ✗ driver_props = &dec->shared_ctx->s.driver_props;
1431
0/2
✗ Branch 73 → 74 not taken.
✗ Branch 73 → 79 not taken.
✗ if (driver_props->driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY &&
1432
0/2
✗ Branch 74 → 75 not taken.
✗ Branch 74 → 79 not taken.
✗ driver_props->conformanceVersion.major == 1 &&
1433
0/2
✗ Branch 75 → 76 not taken.
✗ Branch 75 → 79 not taken.
✗ driver_props->conformanceVersion.minor == 3 &&
1434
0/2
✗ Branch 76 → 77 not taken.
✗ Branch 76 → 79 not taken.
✗ driver_props->conformanceVersion.subminor == 8 &&
1435
0/2
✗ Branch 77 → 78 not taken.
✗ Branch 77 → 79 not taken.
✗ driver_props->conformanceVersion.patch < 3)
1436 ✗ dec->quirk_av1_offset = 1;
1437
1438 ✗ av_log(avctx, AV_LOG_VERBOSE, "Vulkan decoder initialization successful\n");
1439
1440 ✗ return 0;
1441
1442 ✗ fail:
1443 ✗ ff_vk_decode_uninit(avctx);
1444
1445 ✗ return err;
1446 }
1447