diff mbox series

[FFmpeg-devel] lavfi: add noise_vulkan filter

Message ID NWcvhd3--F-9@lynne.ee
State New
Headers show
Series [FFmpeg-devel] lavfi: add noise_vulkan filter | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Lynne May 29, 2023, 7:14 p.m. UTC
Patch attached
diff mbox series

Patch

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(-)

diff --git a/configure b/configure
index 495493aa0e..a4cc214e76 100755
--- a/configure
+++ b/configure
@@ -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"
diff --git a/doc/filters.texi b/doc/filters.texi
index c47e88e5d4..1f2828e450 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -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.
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 18935b1616..ff059cfab4 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -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
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index f1f781101b..22f59e3ecf 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -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;
diff --git a/libavfilter/vsrc_testsrc_vulkan.c b/libavfilter/vsrc_testsrc_vulkan.c
index 7eacb57c80..12ac556fff 100644
--- a/libavfilter/vsrc_testsrc_vulkan.c
+++ b/libavfilter/vsrc_testsrc_vulkan.c
@@ -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