diff options
author | Nicolas George <george@nsup.org> | 2015-10-25 16:31:00 +0100 |
---|---|---|
committer | Nicolas George <george@nsup.org> | 2015-11-07 16:02:48 +0100 |
commit | b16e56931271db1ddd7008850bad5c7056d2f7ff (patch) | |
tree | 31217b5ee23434d88e003370f96a4029a5f45a85 /libavfilter | |
parent | 91bc4de2a4fcd68950085b0a6bef99727968ce82 (diff) | |
download | ffmpeg-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')
-rw-r--r-- | libavfilter/Makefile | 1 | ||||
-rw-r--r-- | libavfilter/allfilters.c | 1 | ||||
-rw-r--r-- | libavfilter/vsrc_testsrc.c | 271 |
3 files changed, 273 insertions, 0 deletions
diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 1b2308585c..f771dca0f9 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -264,6 +264,7 @@ OBJS-$(CONFIG_RGBTESTSRC_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_SMPTEBARS_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_SMPTEHDBARS_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_TESTSRC_FILTER) += vsrc_testsrc.o +OBJS-$(CONFIG_TESTSRC2_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_NULLSINK_FILTER) += vsink_nullsink.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index a538b81983..05dfac9182 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -285,6 +285,7 @@ void avfilter_register_all(void) REGISTER_FILTER(SMPTEBARS, smptebars, vsrc); REGISTER_FILTER(SMPTEHDBARS, smptehdbars, vsrc); REGISTER_FILTER(TESTSRC, testsrc, vsrc); + REGISTER_FILTER(TESTSRC2, testsrc2, vsrc); REGISTER_FILTER(NULLSINK, nullsink, vsink); 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 |