FFmpeg
Loading...
Searching...
No Matches
vf_interlace_vulkan.c
Go to the documentation of this file.
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
21#include "libavutil/opt.h"
22#include "vulkan_filter.h"
23
24#include "tinterlace.h"
25#include "filters.h"
26#include "video.h"
27
28extern const unsigned char ff_interlace_comp_spv_data[];
29extern const unsigned int ff_interlace_comp_spv_len;
30
45
47{
48 int err;
50 FFVulkanContext *vkctx = &s->vkctx;
51 const int planes = av_pix_fmt_count_planes(s->vkctx.output_format);
52
53 s->qf = ff_vk_qf_find(vkctx, VK_QUEUE_COMPUTE_BIT, 0);
54 if (!s->qf) {
55 av_log(ctx, AV_LOG_ERROR, "Device has no compute queues\n");
56 err = AVERROR(ENOTSUP);
57 goto fail;
58 }
59
60 RET(ff_vk_exec_pool_init(vkctx, s->qf, &s->e, FF_VK_DEFAULT_EXEC_CONTEXTS, 0, 0, 0, NULL));
61 RET(ff_vk_init_sampler(vkctx, &s->sampler, 1,
62 s->lowpass == VLPF_OFF ? VK_FILTER_NEAREST
63 : VK_FILTER_LINEAR));
64
65 SPEC_LIST_CREATE(sl, 2, 2*sizeof(int))
66 SPEC_LIST_ADD(sl, 0, 32, s->lowpass);
67 SPEC_LIST_ADD(sl, 1, 32, planes);
68
69 ff_vk_shader_load(&s->shd, VK_SHADER_STAGE_COMPUTE_BIT,
70 sl, (uint32_t []) { 32, 1, planes }, 0);
71
73 { /* top_field */
74 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
75 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
76 .samplers = DUP_SAMPLER(s->sampler),
77 .elems = planes,
78 },
79 { /* bot_field */
80 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
81 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
82 .samplers = DUP_SAMPLER(s->sampler),
83 .elems = planes,
84 },
85 { /* output_img */
86 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
87 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
88 .elems = planes,
89 },
90 };
91 ff_vk_shader_add_descriptor_set(vkctx, &s->shd, desc, 3, 0);
92
93 RET(ff_vk_shader_link(vkctx, &s->shd,
96
97 RET(ff_vk_shader_register_exec(vkctx, &s->e, &s->shd));
98
99 s->initialized = 1;
100
101fail:
102 return err;
103}
104
106{
107 int err;
108 AVFrame *out = NULL, *input_top, *input_bot;
109 AVFilterContext *ctx = link->dst;
111 const AVFilterLink *inlink = ctx->inputs[0];
112 AVFilterLink *outlink = ctx->outputs[0];
113 FilterLink *l = ff_filter_link(outlink);
114
115 if (!s->initialized)
117
118 /* Need both frames to filter */
119 if (!s->cur) {
120 s->cur = in;
121 return 0;
122 }
123
124 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
125 if (!out) {
126 err = AVERROR(ENOMEM);
127 goto fail;
128 }
129
130 if (s->mode == MODE_TFF) {
131 input_top = s->cur;
132 input_bot = in;
133 } else {
134 input_top = in;
135 input_bot = s->cur;
136 }
137
138 RET(ff_vk_filter_process_Nin(&s->vkctx, &s->e, &s->shd,
139 out, (AVFrame *[]){ input_top, input_bot }, 2,
140 s->sampler, 1, NULL, 0));
141
142 err = av_frame_copy_props(out, s->cur);
143 if (err < 0)
144 goto fail;
145
147 if (s->mode == MODE_TFF)
149
150 out->pts = av_rescale_q(out->pts, inlink->time_base, outlink->time_base);
151 out->duration = av_rescale_q(1, av_inv_q(l->frame_rate), outlink->time_base);
152
153 av_frame_free(&s->cur);
154 av_frame_free(&in);
155
156 return ff_filter_frame(outlink, out);
157
158fail:
159 av_frame_free(&s->cur);
160 av_frame_free(&in);
162 return err;
163}
164
166{
167 InterlaceVulkanContext *s = avctx->priv;
168 FFVulkanContext *vkctx = &s->vkctx;
169 FFVulkanFunctions *vk = &vkctx->vkfn;
170
171 av_frame_free(&s->cur);
172
173 ff_vk_exec_pool_free(vkctx, &s->e);
174 ff_vk_shader_free(vkctx, &s->shd);
175
176 if (s->sampler)
177 vk->DestroySampler(vkctx->hwctx->act_dev, s->sampler,
178 vkctx->hwctx->alloc);
179
180 ff_vk_uninit(&s->vkctx);
181
182 s->initialized = 0;
183}
184
185static int config_out_props(AVFilterLink *outlink)
186{
187 AVFilterLink *inlink = outlink->src->inputs[0];
188 const FilterLink *il = ff_filter_link(inlink);
189 FilterLink *ol = ff_filter_link(outlink);
190
191 ol->frame_rate = av_mul_q(il->frame_rate, av_make_q(1, 2));
192 outlink->time_base = av_mul_q(inlink->time_base, av_make_q(2, 1));
193 return ff_vk_filter_config_output(outlink);
194}
195
196#define OFFSET(x) offsetof(InterlaceVulkanContext, x)
197#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
199 { "scan", "scanning mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64 = MODE_TFF}, 0, 1, FLAGS, .unit = "mode"},
200 { "tff", "top field first", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_TFF}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"},
201 { "bff", "bottom field first", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_BFF}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"},
202 { "lowpass", "set vertical low-pass filter", OFFSET(lowpass), AV_OPT_TYPE_INT, {.i64 = VLPF_LIN}, 0, 2, FLAGS, .unit = "lowpass" },
203 { "off", "disable vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = VLPF_OFF}, INT_MIN, INT_MAX, FLAGS, .unit = "lowpass" },
204 { "linear", "linear vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = VLPF_LIN}, INT_MIN, INT_MAX, FLAGS, .unit = "lowpass" },
205 { "complex", "complex vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = VLPF_CMP}, INT_MIN, INT_MAX, FLAGS, .unit = "lowpass" },
206 { NULL },
207};
208
209AVFILTER_DEFINE_CLASS(interlace_vulkan);
210
212 {
213 .name = "default",
214 .type = AVMEDIA_TYPE_VIDEO,
215 .filter_frame = &interlace_vulkan_filter_frame,
216 .config_props = &ff_vk_filter_config_input,
217 },
218};
219
221 {
222 .name = "default",
223 .type = AVMEDIA_TYPE_VIDEO,
224 .config_props = &config_out_props,
225 },
226};
227
229 .p.name = "interlace_vulkan",
230 .p.description = NULL_IF_CONFIG_SMALL("Convert progressive video into interlaced."),
231 .p.priv_class = &interlace_vulkan_class,
232 .p.flags = AVFILTER_FLAG_HWDEVICE,
233 .priv_size = sizeof(InterlaceVulkanContext),
239 .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
240};
@ lowpass
Definition af_biquads.c:87
const FFFilter ff_vf_interlace_vulkan
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
#define s(width, name)
Definition cbs_vp9.c:198
#define FLAGS
Definition cmdutils.c:598
#define NULL
Definition coverity.c:32
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
#define fail
Definition test.h:479
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
#define AVFILTER_FLAG_HWDEVICE
The filter can create hardware frames using AVFilterContext.hw_device_ctx.
Definition avfilter.h:187
#define AVERROR(e)
Definition error.h:45
#define AV_FRAME_FLAG_INTERLACED
A flag to mark frames whose content is interlaced.
Definition frame.h:695
#define AV_FRAME_FLAG_TOP_FIELD_FIRST
A flag to mark frames where the top field is displayed first if the content is interlaced.
Definition frame.h:700
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition frame.c:599
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
AVRational av_mul_q(AVRational b, AVRational c)
Multiply two rationals.
Definition rational.c:80
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition rational.h:71
static av_always_inline AVRational av_inv_q(AVRational q)
Invert a rational.
Definition rational.h:159
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
static av_cold void uninit(AVBitStreamFilterContext *ctx)
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
#define FF_FILTER_FLAG_HWFRAME_AWARE
The filter is aware of hardware frames, and any hardware frame context should not be automatically pr...
Definition filters.h:208
static FilterLink * ff_filter_link(AVFilterLink *link)
Definition filters.h:199
#define FILTER_SINGLE_PIXFMT(pix_fmt_)
Definition filters.h:254
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
#define av_cold
Definition attributes.h:117
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
int ff_vk_shader_load(FFVulkanShader *shd, VkPipelineStageFlags stage, VkSpecializationInfo *spec, uint32_t wg_size[3], uint32_t required_subgroup_size)
Initialize a shader object.
Definition vulkan.c:2070
void ff_vk_shader_add_descriptor_set(FFVulkanContext *s, FFVulkanShader *shd, const FFVulkanDescriptorSetBinding *desc, int nb, int singular)
Add descriptor to a shader.
Definition vulkan.c:2373
void ff_vk_exec_pool_free(FFVulkanContext *s, FFVkExecPool *pool)
Definition vulkan.c:310
int ff_vk_exec_pool_init(FFVulkanContext *s, AVVulkanDeviceQueueFamily *qf, FFVkExecPool *pool, int nb_contexts, int nb_queries, VkQueryType query_type, int query_64bit, const void *query_create_pnext)
Allocates/frees an execution pool.
Definition vulkan.c:357
void ff_vk_uninit(FFVulkanContext *s)
Frees main context.
Definition vulkan.c:2638
void ff_vk_shader_free(FFVulkanContext *s, FFVulkanShader *shd)
Free a shader.
Definition vulkan.c:2614
int ff_vk_shader_register_exec(FFVulkanContext *s, FFVkExecPool *pool, FFVulkanShader *shd)
Register a shader with an exec pool.
Definition vulkan.c:2407
int ff_vk_init_sampler(FFVulkanContext *s, VkSampler *sampler, int unnorm_coords, VkFilter filt)
Create a sampler.
Definition vulkan.c:1454
AVVulkanDeviceQueueFamily * ff_vk_qf_find(FFVulkanContext *s, VkQueueFlagBits dev_family, VkVideoCodecOperationFlagBitsKHR vid_ops)
Chooses an appropriate QF.
Definition vulkan.c:297
int ff_vk_shader_link(FFVulkanContext *s, FFVulkanShader *shd, const char *spirv, size_t spirv_len, const char *entrypoint)
Link a shader into an executable.
Definition vulkan.c:2267
const char * desc
Definition libsvtav1.c:83
static const struct @257111027162314367033347246032313251342043035002 planes[]
AVOptions.
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3500
@ AV_PIX_FMT_VULKAN
Vulkan hardware images.
Definition pixfmt.h:379
An instance of a filter.
Definition avfilter.h:273
AVFilterLink ** inputs
array of pointers to input links
Definition avfilter.h:281
void * priv
private data for use by the filter
Definition avfilter.h:288
A filter pad used for either input or output.
Definition filters.h:40
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
AVOption.
Definition opt.h:428
const VkAllocationCallbacks * alloc
Custom memory allocator, else NULL.
VkDevice act_dev
Active device.
AVVulkanDeviceContext * hwctx
Definition vulkan.h:329
FFVulkanFunctions vkfn
Definition vulkan.h:294
AVVulkanDeviceQueueFamily * qf
Definition swscale.c:71
#define av_log(a,...)
static FILE * out
Definition movenc.c:55
static AVFormatContext * ctx
Definition movenc.c:49
temporal field interlace filter, ported from MPlayer/libmpcodecs
@ VLPF_OFF
Definition tinterlace.h:43
@ VLPF_LIN
Definition tinterlace.h:44
@ VLPF_CMP
Definition tinterlace.h:45
@ MODE_BFF
Definition tinterlace.h:62
@ MODE_TFF
Definition tinterlace.h:61
static int config_out_props(AVFilterLink *outlink)
Definition vf_dejudder.c:79
static void interlace_vulkan_uninit(AVFilterContext *avctx)
static const AVOption interlace_vulkan_options[]
static const AVFilterPad interlace_vulkan_inputs[]
static av_cold int init_filter(AVFilterContext *ctx)
static const AVFilterPad interlace_vulkan_outputs[]
const unsigned int ff_interlace_comp_spv_len
const unsigned char ff_interlace_comp_spv_data[]
#define OFFSET(x)
static int config_out_props(AVFilterLink *outlink)
static int interlace_vulkan_filter_frame(AVFilterLink *link, AVFrame *in)
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition video.c:89
#define FF_VK_DEFAULT_EXEC_CONTEXTS
Definition vulkan.h:121
#define RET(x)
Definition vulkan.h:37
#define SPEC_LIST_ADD(name, idx, val_bits, val)
Definition vulkan.h:55
#define SPEC_LIST_CREATE(name, max_length, max_size)
Definition vulkan.h:45
#define DUP_SAMPLER(x)
Definition vulkan.h:73
int ff_vk_filter_config_input(AVFilterLink *inlink)
int ff_vk_filter_config_output(AVFilterLink *outlink)
int ff_vk_filter_process_Nin(FFVulkanContext *vkctx, FFVkExecPool *e, FFVulkanShader *shd, AVFrame *out, AVFrame *in[], int nb_in, VkSampler sampler, uint32_t wgc_z, void *push_src, size_t push_size)
Up to 16 inputs, one output.
int ff_vk_filter_init(AVFilterContext *avctx)
General lavfi IO functions.