1 /*
2 * Copyright 2025 (c) Niklas Haas
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
26
28
31
37
40
46
51
53 {
54 int err;
55 uint8_t *spv_data;
56 size_t spv_len;
57 void *spv_opaque =
NULL;
63
68
69 spv = ff_vk_spirv_init();
70 if (!spv) {
73 }
74
80 }
81
84 VK_SHADER_STAGE_COMPUTE_BIT,
85 (const char *[]) { "GL_KHR_shader_subgroup_arithmetic" }, 1,
86 32, 32, 1,
87 0));
89
91 {
92 .name = "prev_img",
93 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
95 .mem_quali = "readonly",
96 .dimensions = 2,
98 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
99 }, {
100 .name = "cur_img",
101 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
103 .mem_quali = "readonly",
104 .dimensions = 2,
106 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
107 }, {
108 .name = "sad_buffer",
109 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
110 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
111 .buf_content = "uint frame_sad[];",
112 }
113 };
114
116
117 GLSLC(0, shared uint wg_sum; );
120 GLSLF(1,
const uint slice = gl_WorkGroupID.x %% %
u; ,
SLICES);
121 GLSLC(1,
const ivec2
pos = ivec2(gl_GlobalInvocationID.xy); );
122 GLSLC(1, wg_sum = 0; );
123 GLSLC(1, barrier(); );
124 for (
int i = 0;
i <
s->nb_planes;
i++) {
125 GLSLF(1,
if (IS_WITHIN(
pos, imageSize(cur_img[%d]))) { ,
i);
126 GLSLF(2, uvec4 prev = imageLoad(prev_img[%d],
pos); ,
i);
127 GLSLF(2, uvec4 cur = imageLoad(cur_img[%d],
pos); ,
i);
128 GLSLC(2, uvec4 sad =
abs(ivec4(cur) - ivec4(prev)); );
129 GLSLC(2, uint sum = subgroupAdd(sad.x + sad.y + sad.z); );
130 GLSLC(2,
if (subgroupElect()) );
133 }
134 GLSLC(1, barrier(); );
135 GLSLC(1,
if (gl_LocalInvocationIndex == 0) );
138
140 &spv_opaque));
142
144
146
148 if (spv_opaque)
150 if (spv)
152
153 return err;
154 }
155
157 {
161 uint64_t count;
163
164 uint64_t sad = 0;
167
170 mafd = (
double) sad * 100.0 / count / (1ULL <<
desc->comp[0].depth);
173
175 }
176
178 {
179 int err;
183
186 VkImageMemoryBarrier2 img_bar[8];
187 int nb_img_bar = 0;
188
194
196 double score = 0.0;
197 char str[64];
198
201
206 goto done;
207
209 VK_BUFFER_USAGE_TRANSFER_DST_BIT |
210 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
213 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
214 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
215 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT));
218
221
223 VK_PIPELINE_STAGE_2_NONE,
224 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
226
228 VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE);
229
231 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
232 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
233 VK_ACCESS_SHADER_READ_BIT,
234 VK_IMAGE_LAYOUT_GENERAL,
235 VK_QUEUE_FAMILY_IGNORED);
236
238 VK_PIPELINE_STAGE_2_NONE,
239 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
241
243 VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE);
244
246 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
247 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
248 VK_ACCESS_SHADER_READ_BIT,
249 VK_IMAGE_LAYOUT_GENERAL,
250 VK_QUEUE_FAMILY_IGNORED);
251
252 /* zero buffer */
253 vk->CmdPipelineBarrier2(exec->
buf, &(VkDependencyInfo) {
254 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
255 .pBufferMemoryBarriers = &(VkBufferMemoryBarrier2) {
256 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2,
257 .srcStageMask = VK_PIPELINE_STAGE_2_NONE,
258 .dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
259 .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
260 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
261 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
262 .buffer = buf_vk->buf,
263 .size = buf_vk->size,
264 .offset = 0,
265 },
266 .bufferMemoryBarrierCount = 1,
267 });
268
269 vk->CmdFillBuffer(exec->buf, buf_vk->buf, 0, buf_vk->size, 0x0);
270
271 vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) {
272 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
273 .pImageMemoryBarriers = img_bar,
274 .imageMemoryBarrierCount = nb_img_bar,
275 .pBufferMemoryBarriers = &(VkBufferMemoryBarrier2) {
276 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2,
277 .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
278 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
279 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
280 .dstAccessMask = VK_ACCESS_2_SHADER_STORAGE_READ_BIT |
281 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT,
282 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
283 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
284 .buffer = buf_vk->buf,
285 .size = buf_vk->size,
286 .offset = 0,
287 },
288 .bufferMemoryBarrierCount = 1,
289 });
290
292 buf_vk, 0, buf_vk->size,
293 VK_FORMAT_UNDEFINED));
294
296
297 vk->CmdDispatch(exec->buf,
298 FFALIGN(in->width,
s->shd.lg_size[0]) /
s->shd.lg_size[0],
299 FFALIGN(in->height,
s->shd.lg_size[1]) /
s->shd.lg_size[1],
301
302 vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) {
303 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
304 .pBufferMemoryBarriers = &(VkBufferMemoryBarrier2) {
305 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2,
306 .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
307 .dstStageMask = VK_PIPELINE_STAGE_2_HOST_BIT,
308 .srcAccessMask = VK_ACCESS_2_SHADER_STORAGE_READ_BIT |
309 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT,
310 .dstAccessMask = VK_ACCESS_HOST_READ_BIT,
311 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
312 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
313 .buffer = buf_vk->buf,
314 .size = buf_vk->size,
315 .offset = 0,
316 },
317 .bufferMemoryBarrierCount = 1,
318 });
319
323
324 done:
325 snprintf(str,
sizeof(str),
"%0.3f",
s->prev_mafd);
326 av_dict_set(&in->metadata,
"lavfi.scd.mafd", str, 0);
327 snprintf(str,
sizeof(str),
"%0.3f", score);
328 av_dict_set(&in->metadata,
"lavfi.scd.score", str, 0);
329
330 if (score >=
s->threshold) {
335 }
336
338 if (!
s->sc_pass || score >=
s->threshold)
340 else {
342 return 0;
343 }
344
346 if (exec)
350 return err;
351 }
352
354 {
357
360
363
365
367
369 }
370
371 #define OFFSET(x) offsetof(SceneDetectVulkanContext, x)
372 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
379 };
380
382
384 {
389 },
390 };
391
393 {
397 },
398 };
399
401 .
p.
name =
"scdet_vulkan",
403 .p.priv_class = &scdet_vulkan_class,
412 };