[FFmpeg-cvslog] avfilter: add zoneplate video test source

Paul B Mahol git at videolan.org
Tue May 9 09:50:26 EEST 2023


ffmpeg | branch: master | Paul B Mahol <onemda at gmail.com> | Sat May  6 22:52:47 2023 +0200| [3475c8342c850bddff7c5bd43f608b87f7a4ded9] | committer: Paul B Mahol

avfilter: add zoneplate video test source

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=3475c8342c850bddff7c5bd43f608b87f7a4ded9
---

 Changelog                  |   1 +
 doc/filters.texi           |  98 ++++++++++++++++++++++
 libavfilter/Makefile       |   1 +
 libavfilter/allfilters.c   |   1 +
 libavfilter/version.h      |   4 +-
 libavfilter/vsrc_testsrc.c | 197 +++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 300 insertions(+), 2 deletions(-)

diff --git a/Changelog b/Changelog
index 2061aaf462..b7ffeeff0d 100644
--- a/Changelog
+++ b/Changelog
@@ -8,6 +8,7 @@ version <next>:
 - afireqsrc audio source filter
 - arls filter
 - ffmpeg CLI new option: -readrate_initial_burst
+- zoneplate video source filter
 
 version 6.0:
 - Radiance HDR image support
diff --git a/doc/filters.texi b/doc/filters.texi
index b965f05e60..d2f0eab619 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -28083,6 +28083,104 @@ Set max jump for single pan destination. Allowed range is from 1 to 10000.
 Set fractal type, can be default @code{carpet} or @code{triangle}.
 @end table
 
+ at section zoneplate
+Generate a zoneplate test video pattern.
+
+This source accepts the following options:
+
+ at table @option
+ at item size, s
+Set frame size. For the syntax of this option, check the @ref{video size syntax,,"Video
+size" section in the ffmpeg-utils manual,ffmpeg-utils}. Default value is "320x240".
+
+ at item rate, r
+Set frame rate, expressed as number of frames per second. Default
+value is "25".
+
+ at item duration, d
+Set the duration of the sourced video. See
+ at ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils}
+for the accepted syntax.
+
+If not specified, or the expressed duration is negative, the video is
+supposed to be generated forever.
+
+ at item sar
+Set the sample aspect ratio of the sourced video.
+
+ at item precision
+Set precision in bits for look-up table for sine calculations. Default value is 10.
+Allowed range is from 4 to 16.
+
+ at item xo
+Set horizontal axis offset for output signal. Default value is 0.
+
+ at item yo
+Set vertical axis offset for output signal. Default value is 0.
+
+ at item to
+Set time axis offset for output signal. Default value is 0.
+
+ at item k0
+Set 0-order, constant added to signal phase. Default value is 0.
+
+ at item kx
+Set 1-order, phase factor multiplier for horizontal axis. Default value is 0.
+
+ at item ky
+Set 1-order, phase factor multiplier for vertical axis. Default value is 0.
+
+ at item kt
+Set 1-order, phase factor multiplier for time axis. Default value is 0.
+
+ at item kxt, kyt, kxy
+Set phase factor multipliers for combination of spatial and temporal axis.
+Default value is 0.
+
+ at item kx2
+Set 2-order, phase factor multiplier for horizontal axis. Default value is 0.
+
+ at item ky2
+Set 2-order, phase factor multiplier for vertical axis. Default value is 0.
+
+ at item kt2
+Set 2-order, phase factor multiplier for time axis. Default value is 0.
+
+ at item ku
+Set the constant added to final phase to produce chroma-blue component of signal.
+Default value is 0.
+
+ at item kv
+Set the constant added to final phase to produce chroma-red component of signal.
+Default value is 0.
+ at end table
+
+ at subsection Commands
+
+This source supports the some above options as @ref{commands}.
+
+ at subsection Examples
+
+ at itemize
+ at item
+Generate horizontal color sine sweep:
+ at example
+zoneplate=ku=512:kv=0:kt2=0:kx2=256:s=wvga:xo=-426:kt=11
+ at end example
+
+ at item
+Generate vertical color sine sweep:
+ at example
+zoneplate=ku=512:kv=0:kt2=0:ky2=156:s=wvga:yo=-240:kt=11
+ at end example
+
+ at item
+Generate circular zone-plate:
+ at example
+zoneplate=ku=512:kv=100:kt2=0:ky2=256:kx2=556:s=wvga:yo=0:kt=11
+ at end example
+ at end itemize
+
 @c man end VIDEO SOURCES
 
 @chapter Video Sinks
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 482aeaff4b..01f1cdfe0c 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -592,6 +592,7 @@ OBJS-$(CONFIG_SMPTEHDBARS_FILTER)            += vsrc_testsrc.o
 OBJS-$(CONFIG_TESTSRC_FILTER)                += vsrc_testsrc.o
 OBJS-$(CONFIG_TESTSRC2_FILTER)               += vsrc_testsrc.o
 OBJS-$(CONFIG_YUVTESTSRC_FILTER)             += vsrc_testsrc.o
+OBJS-$(CONFIG_ZONEPLATE_FILTER)              += vsrc_testsrc.o
 
 OBJS-$(CONFIG_NULLSINK_FILTER)               += vsink_nullsink.o
 
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 6994124ce8..4083296bb2 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -557,6 +557,7 @@ extern const AVFilter ff_vsrc_smptehdbars;
 extern const AVFilter ff_vsrc_testsrc;
 extern const AVFilter ff_vsrc_testsrc2;
 extern const AVFilter ff_vsrc_yuvtestsrc;
+extern const AVFilter ff_vsrc_zoneplate;
 
 extern const AVFilter ff_vsink_nullsink;
 
diff --git a/libavfilter/version.h b/libavfilter/version.h
index c303f96b15..ba8a6fdab2 100644
--- a/libavfilter/version.h
+++ b/libavfilter/version.h
@@ -31,8 +31,8 @@
 
 #include "version_major.h"
 
-#define LIBAVFILTER_VERSION_MINOR   7
-#define LIBAVFILTER_VERSION_MICRO 102
+#define LIBAVFILTER_VERSION_MINOR   8
+#define LIBAVFILTER_VERSION_MICRO 100
 
 
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c
index f391ac02e0..0138e14fb9 100644
--- a/libavfilter/vsrc_testsrc.c
+++ b/libavfilter/vsrc_testsrc.c
@@ -88,6 +88,15 @@ typedef struct TestSourceContext {
 
     /* only used by haldclut */
     int level;
+
+    /* only used by zoneplate */
+    int k0, kx, ky, kt;
+    int kxt, kyt, kxy;
+    int kx2, ky2, kt2;
+    int xo, yo, to, kU, kV;
+    int lut_precision;
+    uint8_t *lut;
+    int (*fill_slice_fn)(AVFilterContext *ctx, void *arg, int job, int nb_jobs);
 } TestSourceContext;
 
 #define OFFSET(x) offsetof(TestSourceContext, x)
@@ -135,6 +144,7 @@ static av_cold void uninit(AVFilterContext *ctx)
     TestSourceContext *test = ctx->priv;
 
     av_frame_free(&test->picref);
+    av_freep(&test->lut);
 }
 
 static int config_props(AVFilterLink *outlink)
@@ -2049,3 +2059,190 @@ const AVFilter ff_vsrc_colorchart = {
 };
 
 #endif /* CONFIG_COLORCHART_FILTER */
+
+#if CONFIG_ZONEPLATE_FILTER
+
+static const AVOption zoneplate_options[] = {
+    COMMON_OPTIONS
+    { "precision", "set LUT precision", OFFSET(lut_precision), AV_OPT_TYPE_INT, {.i64=10}, 4, 16, FLAGS },
+    { "xo", "set X-axis offset", OFFSET(xo), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGSR },
+    { "yo", "set Y-axis offset", OFFSET(yo), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGSR },
+    { "to", "set T-axis offset", OFFSET(to), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGSR },
+    { "k0", "set 0-order phase", OFFSET(k0), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGSR },
+    { "kx", "set 1-order X-axis phase", OFFSET(kx), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGSR },
+    { "ky", "set 1-order Y-axis phase", OFFSET(ky), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGSR },
+    { "kt", "set 1-order T-axis phase", OFFSET(kt), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGSR },
+    { "kxt", "set X-axis*T-axis product phase", OFFSET(kxt), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGSR },
+    { "kyt", "set Y-axis*T-axis product phase", OFFSET(kyt), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGSR },
+    { "kxy", "set X-axis*Y-axis product phase", OFFSET(kxy), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGSR },
+    { "kx2", "set 2-order X-axis phase", OFFSET(kx2), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGSR },
+    { "ky2", "set 2-order Y-axis phase", OFFSET(ky2), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGSR },
+    { "kt2", "set 2-order T-axis phase", OFFSET(kt2), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGSR },
+    { "ku", "set 0-order U-color phase", OFFSET(kU), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGSR },
+    { "kv", "set 0-order V-color phase", OFFSET(kV), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGSR },
+    { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(zoneplate);
+
+#define ZONEPLATE_SLICE(name, type)                                \
+static int zoneplate_fill_slice_##name(AVFilterContext *ctx,       \
+                                       void *arg, int job,         \
+                                       int nb_jobs)                \
+{                                                                  \
+    TestSourceContext *test = ctx->priv;                           \
+    AVFrame *frame = arg;                                          \
+    const int w = frame->width;                                    \
+    const int h = frame->height;                                   \
+    const int kxt = test->kxt, kyt = test->kyt, kx2 = test->kx2;   \
+    const int t = test->pts + test->to, k0 = test->k0;             \
+    const int kt = test->kt, kt2 = test->kt2, ky2 = test->ky2;     \
+    const int ky = test->ky, kx = test->kx, kxy = test->kxy;       \
+    const int lut_mask = (1 << test->lut_precision) - 1;           \
+    const int nkt2t = kt2 * t * t, nktt = kt * t;                  \
+    const int start = (h *  job   ) / nb_jobs;                     \
+    const int end   = (h * (job+1)) / nb_jobs;                     \
+    const int ylinesize = frame->linesize[0] / sizeof(type);       \
+    const int ulinesize = frame->linesize[1] / sizeof(type);       \
+    const int vlinesize = frame->linesize[2] / sizeof(type);       \
+    const int xreset = -(w / 2) - test->xo;                        \
+    const int yreset = -(h / 2) - test->yo + start;                \
+    const int kU = test->kU, kV = test->kV;                        \
+    const int skxy = 0xffff / (w / 2);                             \
+    const int skx2 = 0xffff / w;                                   \
+    const int dkxt = kxt * t;                                      \
+    type *ydst = ((type *)frame->data[0]) + start * ylinesize;     \
+    type *udst = ((type *)frame->data[1]) + start * ulinesize;     \
+    type *vdst = ((type *)frame->data[2]) + start * vlinesize;     \
+    const type *lut = (const type *)test->lut;                     \
+    int akx, akxt, aky, akyt;                                      \
+                                                                   \
+    aky = start * ky;                                              \
+    akyt = start * kyt * t;                                        \
+                                                                   \
+    for (int j = start, y = yreset; j < end; j++, y++) {           \
+        const int dkxy = kxy * y * skxy;                           \
+        const int nky2kt2 = (ky2 * y * y) / h + (nkt2t >> 1);      \
+        int akxy = dkxy * xreset;                                  \
+                                                                   \
+        akx = 0;                                                   \
+        akxt = 0;                                                  \
+        aky += ky;                                                 \
+        akyt += kyt * t;                                           \
+                                                                   \
+        for (int i = 0, x = xreset; i < w; i++, x++) {             \
+            int phase = k0, uphase = kU, vphase = kV;              \
+                                                                   \
+            akx += kx;                                             \
+            phase += akx + aky + nktt;                             \
+                                                                   \
+            akxt += dkxt;                                          \
+            akxy += dkxy;                                          \
+            phase += akxt + akyt;                                  \
+            phase += akxy >> 16;                                   \
+            phase += ((kx2 * x * x * skx2) >> 16) + nky2kt2;       \
+            uphase += phase;                                       \
+            vphase += phase;                                       \
+                                                                   \
+            ydst[i] = lut[phase  & lut_mask];                      \
+            udst[i] = lut[uphase & lut_mask];                      \
+            vdst[i] = lut[vphase & lut_mask];                      \
+        }                                                          \
+                                                                   \
+        ydst += ylinesize;                                         \
+        udst += ulinesize;                                         \
+        vdst += vlinesize;                                         \
+    }                                                              \
+                                                                   \
+    return 0;                                                      \
+}
+
+ZONEPLATE_SLICE( 8, uint8_t)
+ZONEPLATE_SLICE( 9, uint16_t)
+ZONEPLATE_SLICE(10, uint16_t)
+ZONEPLATE_SLICE(12, uint16_t)
+ZONEPLATE_SLICE(14, uint16_t)
+ZONEPLATE_SLICE(16, uint16_t)
+
+static void zoneplate_fill_picture(AVFilterContext *ctx, AVFrame *frame)
+{
+    TestSourceContext *test = ctx->priv;
+    ff_filter_execute(ctx, test->fill_slice_fn, frame, NULL,
+                      FFMIN(frame->height, ff_filter_get_nb_threads(ctx)));
+}
+
+static int zoneplate_config_props(AVFilterLink *outlink)
+{
+    AVFilterContext *ctx = outlink->src;
+    TestSourceContext *test = ctx->priv;
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
+    const int lut_size = 1 << test->lut_precision;
+    const int depth = desc->comp[0].depth;
+    uint16_t *lut16;
+    uint8_t *lut8;
+
+    if (av_image_check_size(test->w, test->h, 0, ctx) < 0)
+        return AVERROR(EINVAL);
+
+    test->lut = av_calloc(lut_size, sizeof(*test->lut) * ((depth + 7) / 8));
+    if (!test->lut)
+        return AVERROR(ENOMEM);
+
+    lut8 = test->lut;
+    lut16 = (uint16_t *)test->lut;
+    switch (depth) {
+    case 8:
+        for (int i = 0; i < lut_size; i++)
+            lut8[i] = lrintf(255.f * (0.5f + 0.5f * sinf((2.f * M_PI * i) / lut_size)));
+        break;
+    default:
+        for (int i = 0; i < lut_size; i++)
+            lut16[i] = lrintf(((1 << depth) - 1) * (0.5f + 0.5f * sinf((2.f * M_PI * i) / lut_size)));
+        break;
+    }
+
+    test->draw_once = 0;
+    test->fill_picture_fn = zoneplate_fill_picture;
+
+    switch (depth) {
+    case  8: test->fill_slice_fn = zoneplate_fill_slice_8;  break;
+    case  9: test->fill_slice_fn = zoneplate_fill_slice_9;  break;
+    case 10: test->fill_slice_fn = zoneplate_fill_slice_10; break;
+    case 12: test->fill_slice_fn = zoneplate_fill_slice_12; break;
+    case 14: test->fill_slice_fn = zoneplate_fill_slice_14; break;
+    case 16: test->fill_slice_fn = zoneplate_fill_slice_16; break;
+    }
+    return config_props(outlink);
+}
+
+static const enum AVPixelFormat zoneplate_pix_fmts[] = {
+    AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P9,
+    AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV444P12,
+    AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV444P16,
+    AV_PIX_FMT_NONE,
+};
+
+static const AVFilterPad avfilter_vsrc_zoneplate_outputs[] = {
+    {
+        .name          = "default",
+        .type          = AVMEDIA_TYPE_VIDEO,
+        .config_props  = zoneplate_config_props,
+    },
+};
+
+const AVFilter ff_vsrc_zoneplate = {
+    .name          = "zoneplate",
+    .description   = NULL_IF_CONFIG_SMALL("Generate zone-plate."),
+    .priv_size     = sizeof(TestSourceContext),
+    .priv_class    = &zoneplate_class,
+    .init          = init,
+    .uninit        = uninit,
+    .activate      = activate,
+    .inputs        = NULL,
+    FILTER_OUTPUTS(avfilter_vsrc_zoneplate_outputs),
+    FILTER_PIXFMTS_ARRAY(zoneplate_pix_fmts),
+    .flags         = AVFILTER_FLAG_SLICE_THREADS,
+    .process_command = ff_filter_process_command,
+};
+
+#endif /* CONFIG_ZONEPLATE_FILTER */



More information about the ffmpeg-cvslog mailing list