]> git.sesse.net Git - ffmpeg/blobdiff - libavfilter/vsrc_testsrc.c
lavfi: add testsrc2 test source.
[ffmpeg] / libavfilter / vsrc_testsrc.c
index f63c861186db6e92291dbeb3914370d374721ca7..1fca3e71eed804a07f813103ed6691637fe3b186 100644 (file)
@@ -41,6 +41,7 @@
 #include "libavutil/imgutils.h"
 #include "libavutil/intreadwrite.h"
 #include "libavutil/parseutils.h"
+#include "libavutil/xga_font_data.h"
 #include "avfilter.h"
 #include "drawutils.h"
 #include "formats.h"
@@ -679,6 +680,276 @@ AVFilter ff_vsrc_testsrc = {
 
 #endif /* CONFIG_TESTSRC_FILTER */
 
+#if CONFIG_TESTSRC2_FILTER
+
+static const AVOption testsrc2_options[] = {
+    COMMON_OPTIONS
+    { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(testsrc2);
+
+static void set_color(TestSourceContext *s, FFDrawColor *color, uint32_t argb)
+{
+    uint8_t rgba[4] = { (argb >> 16) & 0xFF,
+                        (argb >>  8) & 0xFF,
+                        (argb >>  0) & 0xFF,
+                        (argb >> 24) & 0xFF, };
+    ff_draw_color(&s->draw, color, rgba);
+}
+
+static uint32_t color_gradient(unsigned index)
+{
+    unsigned si = index & 0xFF, sd = 0xFF - si;
+    switch (index >> 8) {
+    case 0: return 0xFF0000 + (si <<  8);
+    case 1: return 0x00FF00 + (sd << 16);
+    case 2: return 0x00FF00 + (si <<  0);
+    case 3: return 0x0000FF + (sd <<  8);
+    case 4: return 0x0000FF + (si << 16);
+    case 5: return 0xFF0000 + (sd <<  0);
+    }
+    av_assert0(0);
+}
+
+static void draw_text(TestSourceContext *s, AVFrame *frame, FFDrawColor *color,
+                      int x0, int y0, const uint8_t *text)
+{
+    int x = x0;
+
+    for (; *text; text++) {
+        if (*text == '\n') {
+            x = x0;
+            y0 += 16;
+            continue;
+        }
+        ff_blend_mask(&s->draw, color, frame->data, frame->linesize,
+                      frame->width, frame->height,
+                      avpriv_vga16_font + *text * 16, 1, 8, 16, 0, 0, x, y0);
+        x += 8;
+    }
+}
+
+static void test2_fill_picture(AVFilterContext *ctx, AVFrame *frame)
+{
+    TestSourceContext *s = ctx->priv;
+    FFDrawColor color;
+
+    /* colored background */
+    {
+        unsigned i, x = 0, x2;
+
+        x = 0;
+        for (i = 1; i < 7; i++) {
+            x2 = av_rescale(i, s->w, 6);
+            x2 = ff_draw_round_to_sub(&s->draw, 0, 0, x2);
+            set_color(s, &color, ((i & 1) ? 0xFF0000 : 0) |
+                                 ((i & 2) ? 0x00FF00 : 0) |
+                                 ((i & 4) ? 0x0000FF : 0));
+            ff_fill_rectangle(&s->draw, &color, frame->data, frame->linesize,
+                              x, 0, x2 - x, frame->height);
+            x = x2;
+        }
+    }
+
+    /* oblique gradient */
+    /* note: too slow if using blending */
+    if (s->h >= 64) {
+        unsigned x, dx, y0, y, g0, g;
+
+        dx = ff_draw_round_to_sub(&s->draw, 0, +1, 1);
+        y0 = av_rescale_q(s->pts, s->time_base, av_make_q(2, s->h - 16));
+        g0 = av_rescale_q(s->pts, s->time_base, av_make_q(1, 128));
+        for (x = 0; x < s->w; x += dx) {
+            g = (av_rescale(x, 6 * 256, s->w) + g0) % (6 * 256);
+            set_color(s, &color, color_gradient(g));
+            y = y0 + av_rescale(x, s->h / 2, s->w);
+            y %= 2 * (s->h - 16);
+            if (y > s->h - 16)
+                y = 2 * (s->h - 16) - y;
+            y = ff_draw_round_to_sub(&s->draw, 1, 0, y);
+            ff_fill_rectangle(&s->draw, &color, frame->data, frame->linesize,
+                              x, y, dx, 16);
+        }
+    }
+
+    /* top right: draw clock hands */
+    if (s->w >= 64 && s->h >= 64) {
+        int l = (FFMIN(s->w, s->h) - 32) >> 1;
+        int steps = FFMAX(4, l >> 5);
+        int xc = (s->w >> 2) + (s->w >> 1);
+        int yc = (s->h >> 2);
+        int cycle = l << 2;
+        int pos, xh, yh;
+        int c, i;
+
+        for (c = 0; c < 3; c++) {
+            set_color(s, &color, 0xBBBBBB ^ (0xFF << (c << 3)));
+            pos = av_rescale_q(s->pts, s->time_base, av_make_q(64 >> (c << 1), cycle)) % cycle;
+            xh = pos < 1 * l ? pos :
+                 pos < 2 * l ? l :
+                 pos < 3 * l ? 3 * l - pos : 0;
+            yh = pos < 1 * l ? 0 :
+                 pos < 2 * l ? pos - l :
+                 pos < 3 * l ? l :
+                               cycle - pos;
+            xh -= l >> 1;
+            yh -= l >> 1;
+            for (i = 1; i <= steps; i++) {
+                int x = av_rescale(xh, i, steps) + xc;
+                int y = av_rescale(yh, i, steps) + yc;
+                x = ff_draw_round_to_sub(&s->draw, 0, -1, x);
+                y = ff_draw_round_to_sub(&s->draw, 1, -1, y);
+                ff_fill_rectangle(&s->draw, &color, frame->data, frame->linesize,
+                                  x, y, 8, 8);
+            }
+        }
+    }
+
+    /* bottom left: beating rectangles */
+    if (s->w >= 64 && s->h >= 64) {
+        int l = (FFMIN(s->w, s->h) - 16) >> 2;
+        int cycle = l << 3;
+        int xc = (s->w >> 2);
+        int yc = (s->h >> 2) + (s->h >> 1);
+        int xm1 = ff_draw_round_to_sub(&s->draw, 0, -1, xc - 8);
+        int xm2 = ff_draw_round_to_sub(&s->draw, 0, +1, xc + 8);
+        int ym1 = ff_draw_round_to_sub(&s->draw, 1, -1, yc - 8);
+        int ym2 = ff_draw_round_to_sub(&s->draw, 1, +1, yc + 8);
+        int size, step, x1, x2, y1, y2;
+
+        size = av_rescale_q(s->pts, s->time_base, av_make_q(4, cycle));
+        step = size / l;
+        size %= l;
+        if (step & 1)
+            size = l - size;
+        step = (step >> 1) & 3;
+        set_color(s, &color, 0xFF808080);
+        x1 = ff_draw_round_to_sub(&s->draw, 0, -1, xc - 4 - size);
+        x2 = ff_draw_round_to_sub(&s->draw, 0, +1, xc + 4 + size);
+        y1 = ff_draw_round_to_sub(&s->draw, 1, -1, yc - 4 - size);
+        y2 = ff_draw_round_to_sub(&s->draw, 1, +1, yc + 4 + size);
+        if (step == 0 || step == 2)
+            ff_fill_rectangle(&s->draw, &color, frame->data, frame->linesize,
+                              x1, ym1, x2 - x1, ym2 - ym1);
+        if (step == 1 || step == 2)
+            ff_fill_rectangle(&s->draw, &color, frame->data, frame->linesize,
+                              xm1, y1, xm2 - xm1, y2 - y1);
+        if (step == 3)
+            ff_fill_rectangle(&s->draw, &color, frame->data, frame->linesize,
+                              x1, y1, x2 - x1, y2 - y1);
+    }
+
+    /* bottom right: checker with random noise */
+    {
+        unsigned xmin = av_rescale(5, s->w, 8);
+        unsigned xmax = av_rescale(7, s->w, 8);
+        unsigned ymin = av_rescale(5, s->h, 8);
+        unsigned ymax = av_rescale(7, s->h, 8);
+        unsigned x, y, i, r;
+        uint8_t alpha[256];
+
+        r = s->pts;
+        for (y = ymin; y < ymax - 15; y += 16) {
+            for (x = xmin; x < xmax - 15; x += 16) {
+                if ((x ^ y) & 16)
+                    continue;
+                for (i = 0; i < 256; i++) {
+                    r = r * 1664525 + 1013904223;
+                    alpha[i] = r >> 24;
+                }
+                set_color(s, &color, 0xFF00FF80);
+                ff_blend_mask(&s->draw, &color, frame->data, frame->linesize,
+                                   frame->width, frame->height,
+                                   alpha, 16, 16, 16, 3, 0, x, y);
+            }
+        }
+    }
+
+    /* bouncing square */
+    if (s->w >= 16 && s->h >= 16) {
+        unsigned w = s->w - 8;
+        unsigned h = s->h - 8;
+        unsigned x = av_rescale_q(s->pts, s->time_base, av_make_q(233, 55 * w)) % (w << 1);
+        unsigned y = av_rescale_q(s->pts, s->time_base, av_make_q(233, 89 * h)) % (h << 1);
+        if (x > w)
+            x = (w << 1) - x;
+        if (y > h)
+            y = (h << 1) - y;
+        x = ff_draw_round_to_sub(&s->draw, 0, -1, x);
+        y = ff_draw_round_to_sub(&s->draw, 1, -1, y);
+        set_color(s, &color, 0xFF8000FF);
+        ff_fill_rectangle(&s->draw, &color, frame->data, frame->linesize,
+                          x, y, 8, 8);
+    }
+
+    /* top right: draw frame time and frame number */
+    {
+        char buf[256];
+        unsigned time;
+
+        time = av_rescale_q(s->pts, s->time_base, av_make_q(1, 1000)) % 86400000;
+        set_color(s, &color, 0xC0000000);
+        ff_blend_rectangle(&s->draw, &color, frame->data, frame->linesize,
+                           frame->width, frame->height,
+                           2, 2, 100, 36);
+        set_color(s, &color, 0xFFFF8000);
+        snprintf(buf, sizeof(buf), "%02d:%02d:%02d.%03d\n%12"PRIi64,
+                 time / 3600000, (time / 60000) % 60, (time / 1000) % 60,
+                 time % 1000, s->pts);
+        draw_text(s, frame, &color, 4, 4, buf);
+    }
+}
+static av_cold int test2_init(AVFilterContext *ctx)
+{
+    TestSourceContext *s = ctx->priv;
+
+    s->fill_picture_fn = test2_fill_picture;
+    return init(ctx);
+}
+
+static int test2_query_formats(AVFilterContext *ctx)
+{
+    return ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
+}
+
+static int test2_config_props(AVFilterLink *inlink)
+{
+    AVFilterContext *ctx = inlink->src;
+    TestSourceContext *s = ctx->priv;
+
+    av_assert0(ff_draw_init(&s->draw, inlink->format, 0) >= 0);
+    s->w = ff_draw_round_to_sub(&s->draw, 0, -1, s->w);
+    s->h = ff_draw_round_to_sub(&s->draw, 1, -1, s->h);
+    if (av_image_check_size(s->w, s->h, 0, ctx) < 0)
+        return AVERROR(EINVAL);
+    return config_props(inlink);
+}
+
+static const AVFilterPad avfilter_vsrc_testsrc2_outputs[] = {
+    {
+        .name          = "default",
+        .type          = AVMEDIA_TYPE_VIDEO,
+        .request_frame = request_frame,
+        .config_props  = test2_config_props,
+    },
+    { NULL }
+};
+
+AVFilter ff_vsrc_testsrc2 = {
+    .name          = "testsrc2",
+    .description   = NULL_IF_CONFIG_SMALL("Generate another test pattern."),
+    .priv_size     = sizeof(TestSourceContext),
+    .priv_class    = &testsrc2_class,
+    .init          = test2_init,
+    .uninit        = uninit,
+    .query_formats = test2_query_formats,
+    .inputs        = NULL,
+    .outputs       = avfilter_vsrc_testsrc2_outputs,
+};
+
+#endif /* CONFIG_TESTSRC2_FILTER */
+
 #if CONFIG_RGBTESTSRC_FILTER
 
 #define rgbtestsrc_options options