summaryrefslogtreecommitdiff
path: root/libavfilter/vsrc_testsrc.c
diff options
context:
space:
mode:
authorNicolas George <george@nsup.org>2015-10-25 16:31:00 +0100
committerNicolas George <george@nsup.org>2015-11-07 16:02:48 +0100
commitb16e56931271db1ddd7008850bad5c7056d2f7ff (patch)
tree31217b5ee23434d88e003370f96a4029a5f45a85 /libavfilter/vsrc_testsrc.c
parent91bc4de2a4fcd68950085b0a6bef99727968ce82 (diff)
downloadffmpeg-b16e56931271db1ddd7008850bad5c7056d2f7ff.tar.gz
lavfi: add testsrc2 test source.
Similar to testsrc, but using drawutils and therefore supporting a lot of pixel formats instead of just rgb24. This allows using it as input for other tests without requiring a format conversion. It is also slightly faster than testsrc for some reason.
Diffstat (limited to 'libavfilter/vsrc_testsrc.c')
-rw-r--r--libavfilter/vsrc_testsrc.c271
1 files changed, 271 insertions, 0 deletions
diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c
index f63c861186..1fca3e71ee 100644
--- a/libavfilter/vsrc_testsrc.c
+++ b/libavfilter/vsrc_testsrc.c
@@ -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