From 06985c12d8280f1d953a60b6e56b40d85debd849 Mon Sep 17 00:00:00 2001
From: Lynne <dev@lynne.ee>
Date: Mon, 29 May 2023 20:47:46 +0200
Subject: [PATCH] lavfi: add noise_vulkan filter
---
configure | 1 +
doc/filters.texi | 43 ++++++++++++++++
libavfilter/Makefile | 1 +
libavfilter/allfilters.c | 1 +
libavfilter/vsrc_testsrc_vulkan.c | 85 +++++++++++++++++++++++++++++--
5 files changed, 126 insertions(+), 5 deletions(-)
@@ -3707,6 +3707,7 @@ negate_filter_deps="lut_filter"
nlmeans_opencl_filter_deps="opencl"
nlmeans_vulkan_filter_deps="vulkan spirv_compiler"
nnedi_filter_deps="gpl"
+noise_vulkan_filter_deps="vulkan spirv_compiler"
ocr_filter_deps="libtesseract"
ocv_filter_deps="libopencv"
openclsrc_filter_deps="opencl"
@@ -27469,6 +27469,49 @@ Must be odd number in range [0, 99].
@end table
+@section noise_vulkan
+
+Video source that creates a Vulkan frame containing TV static/white noise.
+Useful for benchmarking, or overlaying.
+
+It accepts the following parameters:
+
+@table @option
+@item size
+The size of the output frame. Default value is @code{1920x1080}.
+
+@item rate
+The framerate to output at. Default value is @code{60} frames per second.
+
+@item duration
+The video duration. Default value is @code{-0.000001}.
+
+@item sar
+The video signal aspect ratio. Default value is @code{1/1}.
+
+@item format
+The pixel format of the output Vulkan frames. Default value is @code{yuv444p}.
+
+@item out_range
+Set the output YCbCr sample range.
+
+This allows the autodetected value to be overridden as well as allows forcing
+a specific value used for the output and encoder. If not specified, the
+range depends on the pixel format. Possible values:
+
+@table @samp
+@item auto/unknown
+Choose automatically.
+
+@item jpeg/full/pc
+Set full range (0-255 in case of 8-bit luma).
+
+@item mpeg/limited/tv
+Set "MPEG" range (16-235 in case of 8-bit luma).
+@end table
+
+@end table
+
@section overlay_vulkan
Overlay one video on top of another.
@@ -395,6 +395,7 @@ OBJS-$(CONFIG_NLMEANS_VULKAN_FILTER) += vf_nlmeans_vulkan.o vulkan.o vul
OBJS-$(CONFIG_NNEDI_FILTER) += vf_nnedi.o
OBJS-$(CONFIG_NOFORMAT_FILTER) += vf_format.o
OBJS-$(CONFIG_NOISE_FILTER) += vf_noise.o
+OBJS-$(CONFIG_NOISE_VULKAN_FILTER) += vsrc_testsrc_vulkan.o vulkan.o vulkan_filter.o
OBJS-$(CONFIG_NORMALIZE_FILTER) += vf_normalize.o
OBJS-$(CONFIG_NULL_FILTER) += vf_null.o
OBJS-$(CONFIG_OCR_FILTER) += vf_ocr.o
@@ -550,6 +550,7 @@ extern const AVFilter ff_vsrc_haldclutsrc;
extern const AVFilter ff_vsrc_life;
extern const AVFilter ff_vsrc_mandelbrot;
extern const AVFilter ff_vsrc_mptestsrc;
+extern const AVFilter ff_vsrc_noise_vulkan;
extern const AVFilter ff_vsrc_nullsrc;
extern const AVFilter ff_vsrc_openclsrc;
extern const AVFilter ff_vsrc_pal75bars;
@@ -29,10 +29,12 @@
enum TestSrcVulkanMode {
TESTSRC_COLOR,
+ TESTSRC_NOISE,
};
typedef struct TestSrcVulkanPushData {
float color_comp[4];
+ uint32_t frame_nb;
} TestSrcVulkanPushData;
typedef struct TestSrcVulkanContext {
@@ -63,6 +65,23 @@ typedef struct TestSrcVulkanContext {
AVFrame *picref; ///< cached reference containing the painted picture
} TestSrcVulkanContext;
+static const char noise_fn[] = {
+ C(0, vec4 noise_fn(inout uvec4 s) )
+ C(0, { )
+ C(1, s = 1664525u * s + uvec4(1013904223u); )
+ C(1, s.x += s.y * s.w; )
+ C(1, s.y += s.z * s.x; )
+ C(1, s.z += s.x * s.y; )
+ C(1, s.w += s.y * s.z; )
+ C(1, s ^= s >> 16u; )
+ C(1, s.x += s.y * s.w; )
+ C(1, s.y += s.z * s.x; )
+ C(1, s.z += s.x * s.y; )
+ C(1, s.w += s.y * s.z; )
+ C(1, return vec4(s) * 1.0/float(0xFFFFFFFFu); )
+ C(0, } )
+};
+
static av_cold int init_filter(AVFilterContext *ctx, enum TestSrcVulkanMode mode)
{
int err;
@@ -92,6 +111,7 @@ static av_cold int init_filter(AVFilterContext *ctx, enum TestSrcVulkanMode mode
GLSLC(0, layout(push_constant, std430) uniform pushConstants { );
GLSLC(1, vec4 color_comp; );
+ GLSLC(1, uvec4 frame_nb; );
GLSLC(0, }; );
GLSLC(0, );
@@ -112,9 +132,6 @@ static av_cold int init_filter(AVFilterContext *ctx, enum TestSrcVulkanMode mode
RET(ff_vk_pipeline_descriptor_set_add(vkctx, &s->pl, shd, desc_set, 1, 0, 0));
- GLSLC(0, void main() );
- GLSLC(0, { );
- GLSLC(1, ivec2 pos = ivec2(gl_GlobalInvocationID.xy); );
if (mode == TESTSRC_COLOR) {
double rgb2yuv[3][3];
double rgbad[4];
@@ -164,6 +181,9 @@ static av_cold int init_filter(AVFilterContext *ctx, enum TestSrcVulkanMode mode
for (int i = 0; i < 4; i++)
s->opts.color_comp[i] = yuvad[i];
+ GLSLC(0, void main() );
+ GLSLC(0, { );
+ GLSLC(1, ivec2 pos = ivec2(gl_GlobalInvocationID.xy); );
GLSLC(1, vec4 r; );
GLSLC(0, );
for (int i = 0, c_off = 0; i < planes; i++) {
@@ -176,8 +196,27 @@ static av_cold int init_filter(AVFilterContext *ctx, enum TestSrcVulkanMode mode
GLSLF(1, imageStore(output_img[%i], pos, r); ,i);
GLSLC(0, );
}
+ } else if (mode == TESTSRC_NOISE) {
+ GLSLD( noise_fn );
+ GLSLC(0, void main() );
+ GLSLC(0, { );
+ GLSLC(1, ivec2 pos = ivec2(gl_GlobalInvocationID.xy); );
+ GLSLC(1, uvec4 s = uvec4(pos.x, pos.y, pos.x ^ pos.y, pos.x + pos.y) + uvec4(frame_nb); );
+ GLSLC(1, vec4 r; );
+ GLSLC(0, );
+ for (int i = 0; i < planes; i++) {
+ GLSLC(1, r = noise_fn(s); );
+ if (!(desc->flags & AV_PIX_FMT_FLAG_RGB)) {
+ int chroma = (i > 0) && (i != 3);
+ if (s->out_range == AVCOL_RANGE_MPEG) {
+ GLSLF(1, r *= (%i) / 255.0; ,chroma ? 224 : 219);
+ GLSLF(1, r += (%i) / 255.0; ,chroma ? 16 : 18);
+ }
+ }
+ GLSLF(1, imageStore(output_img[%i], pos, r); ,i);
+ }
}
- GLSLC(0, } );
+ GLSLC(0, } );
RET(spv->compile_shader(spv, ctx, shd, &spv_data, &spv_len, "main",
&spv_opaque));
@@ -207,12 +246,19 @@ static int testsrc_vulkan_activate(AVFilterContext *ctx)
AVFrame *frame;
if (!s->initialized) {
- enum TestSrcVulkanMode mode = TESTSRC_COLOR;
+ enum TestSrcVulkanMode mode;
+ if (!strcmp(ctx->filter->name, "color_vulkan"))
+ mode = TESTSRC_COLOR;
+ else if (!strcmp(ctx->filter->name, "noise_vulkan"))
+ mode = TESTSRC_NOISE;
+
err = init_filter(ctx, mode);
if (err < 0)
return err;
}
+ s->opts.frame_nb = s->nb_frame;
+
if (!ff_outlink_frame_wanted(outlink))
return FFERROR_NOT_READY;
if (s->duration >= 0 &&
@@ -375,3 +421,32 @@ const AVFilter ff_vsrc_color_vulkan = {
.priv_class = &color_vulkan_class,
.flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
};
+
+static const AVOption noise_vulkan_options[] = {
+ COMMON_OPTS
+ { "out_range", "Output colour range (from 0 to 2) (default 0)", OFFSET(out_range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_UNSPECIFIED}, AVCOL_RANGE_UNSPECIFIED, AVCOL_RANGE_JPEG, .flags = FLAGS, "range" },
+ { "full", "Full range", 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_JPEG }, 0, 0, FLAGS, "range" },
+ { "limited", "Limited range", 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_MPEG }, 0, 0, FLAGS, "range" },
+ { "jpeg", "Full range", 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_JPEG }, 0, 0, FLAGS, "range" },
+ { "mpeg", "Limited range", 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_MPEG }, 0, 0, FLAGS, "range" },
+ { "tv", "Limited range", 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_MPEG }, 0, 0, FLAGS, "range" },
+ { "pc", "Full range", 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_JPEG }, 0, 0, FLAGS, "range" },
+ { NULL },
+};
+
+AVFILTER_DEFINE_CLASS(noise_vulkan);
+
+const AVFilter ff_vsrc_noise_vulkan = {
+ .name = "noise_vulkan",
+ .description = NULL_IF_CONFIG_SMALL("Generate video noise (Vulkan)"),
+ .priv_size = sizeof(TestSrcVulkanContext),
+ .init = &ff_vk_filter_init,
+ .uninit = &testsrc_vulkan_uninit,
+ .inputs = NULL,
+ .flags = AVFILTER_FLAG_HWDEVICE,
+ .activate = testsrc_vulkan_activate,
+ FILTER_OUTPUTS(testsrc_vulkan_outputs),
+ FILTER_SINGLE_PIXFMT(AV_PIX_FMT_VULKAN),
+ .priv_class = &noise_vulkan_class,
+ .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
+};
--
2.40.1