summaryrefslogtreecommitdiff
path: root/libavfilter
diff options
context:
space:
mode:
authorPaul B Mahol <onemda@gmail.com>2023-05-06 22:52:47 +0200
committerPaul B Mahol <onemda@gmail.com>2023-05-09 08:48:44 +0200
commit3475c8342c850bddff7c5bd43f608b87f7a4ded9 (patch)
treeeee2bef284ad21f7bd79651fef5f03038bbb021c /libavfilter
parent086a0f3e5edee4d5f97c5759fbf5c893f58fb6e5 (diff)
downloadffmpeg-3475c8342c850bddff7c5bd43f608b87f7a4ded9.tar.gz
avfilter: add zoneplate video test source
Diffstat (limited to 'libavfilter')
-rw-r--r--libavfilter/Makefile1
-rw-r--r--libavfilter/allfilters.c1
-rw-r--r--libavfilter/version.h4
-rw-r--r--libavfilter/vsrc_testsrc.c197
4 files changed, 201 insertions, 2 deletions
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 */