diff --git a/doc/filters.texi b/doc/filters.texi index e46839bfec..28066d5e62 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -21120,7 +21120,7 @@ __kernel void sierpinski_carpet(__write_only image2d_t dst, @section sierpinski -Generate a Sierpinksi carpet fractal, and randomly pan around. +Generate a Sierpinksi carpet/triangle fractal, and randomly pan around. This source accepts the following options: @@ -21138,6 +21138,9 @@ Set seed which is used for random panning. @item jump Set max jump for single pan destination. Allowed range is from 1 to 10000. + +@item type +Set fractal type, can be default @code{carpet} or @code{triangle}. @end table @c man end VIDEO SOURCES diff --git a/libavfilter/vsrc_sierpinski.c b/libavfilter/vsrc_sierpinski.c index 49867d7470..93567ac189 100644 --- a/libavfilter/vsrc_sierpinski.c +++ b/libavfilter/vsrc_sierpinski.c @@ -39,6 +39,7 @@ typedef struct SierpinskiContext { const AVClass *class; int w, h; + int type; AVRational frame_rate; uint64_t pts; @@ -49,6 +50,7 @@ typedef struct SierpinskiContext { int dest_x, dest_y; AVLFG lfg; + int (*draw_slice)(AVFilterContext *ctx, void *arg, int job, int nb_jobs); } SierpinskiContext; #define OFFSET(x) offsetof(SierpinskiContext, x) @@ -61,6 +63,9 @@ static const AVOption sierpinski_options[] = { {"r", "set frame rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, 0, FLAGS }, {"seed", "set the seed", OFFSET(seed), AV_OPT_TYPE_INT, {.i64=-1}, -1, UINT32_MAX, FLAGS }, {"jump", "set the jump", OFFSET(jump), AV_OPT_TYPE_INT, {.i64=100}, 1, 10000, FLAGS }, + {"type","set fractal type",OFFSET(type), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "type" }, + {"carpet", "sierpinksi carpet", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "type" }, + {"triangle", "sierpinksi triangle", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "type" }, {NULL}, }; @@ -79,25 +84,6 @@ static int query_formats(AVFilterContext *ctx) return ff_set_common_formats(ctx, fmts_list); } -static int config_output(AVFilterLink *inlink) -{ - AVFilterContext *ctx = inlink->src; - SierpinskiContext *s = ctx->priv; - - if (av_image_check_size(s->w, s->h, 0, ctx) < 0) - return AVERROR(EINVAL); - - inlink->w = s->w; - inlink->h = s->h; - inlink->time_base = av_inv_q(s->frame_rate); - inlink->sample_aspect_ratio = (AVRational) {1, 1}; - if (s->seed == -1) - s->seed = av_get_random_seed(); - av_lfg_init(&s->lfg, s->seed); - - return 0; -} - static int fill_sierpinski(SierpinskiContext *s, int x, int y) { int pos_x = x + s->pos_x; @@ -114,7 +100,32 @@ static int fill_sierpinski(SierpinskiContext *s, int x, int y) return 0; } -static int draw_slice(AVFilterContext *ctx, void *arg, int job, int nb_jobs) +static int draw_triangle_slice(AVFilterContext *ctx, void *arg, int job, int nb_jobs) +{ + SierpinskiContext *s = ctx->priv; + AVFrame *frame = arg; + const int width = frame->width; + const int height = frame->height; + const int start = (height * job ) / nb_jobs; + const int end = (height * (job+1)) / nb_jobs; + uint8_t *dst = frame->data[0] + start * frame->linesize[0]; + + for (int y = start; y < end; y++) { + for (int x = 0; x < width; x++) { + if ((s->pos_x + x) & (s->pos_y + y)) { + AV_WL32(&dst[x*4], 0x00000000); + } else { + AV_WL32(&dst[x*4], 0xFFFFFFFF); + } + } + + dst += frame->linesize[0]; + } + + return 0; +} + +static int draw_carpet_slice(AVFilterContext *ctx, void *arg, int job, int nb_jobs) { SierpinskiContext *s = ctx->priv; AVFrame *frame = arg; @@ -139,6 +150,27 @@ static int draw_slice(AVFilterContext *ctx, void *arg, int job, int nb_jobs) return 0; } +static int config_output(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->src; + SierpinskiContext *s = ctx->priv; + + if (av_image_check_size(s->w, s->h, 0, ctx) < 0) + return AVERROR(EINVAL); + + inlink->w = s->w; + inlink->h = s->h; + inlink->time_base = av_inv_q(s->frame_rate); + inlink->sample_aspect_ratio = (AVRational) {1, 1}; + if (s->seed == -1) + s->seed = av_get_random_seed(); + av_lfg_init(&s->lfg, s->seed); + + s->draw_slice = s->type ? draw_triangle_slice : draw_carpet_slice; + + return 0; +} + static void draw_sierpinski(AVFilterContext *ctx, AVFrame *frame) { SierpinskiContext *s = ctx->priv; @@ -162,7 +194,7 @@ static void draw_sierpinski(AVFilterContext *ctx, AVFrame *frame) s->pos_y--; } - ctx->internal->execute(ctx, draw_slice, frame, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx))); + ctx->internal->execute(ctx, s->draw_slice, frame, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx))); } static int sierpinski_request_frame(AVFilterLink *link) @@ -193,7 +225,7 @@ static const AVFilterPad sierpinski_outputs[] = { AVFilter ff_vsrc_sierpinski = { .name = "sierpinski", - .description = NULL_IF_CONFIG_SMALL("Render a Sierpinski carpet fractal."), + .description = NULL_IF_CONFIG_SMALL("Render a Sierpinski fractal."), .priv_size = sizeof(SierpinskiContext), .priv_class = &sierpinski_class, .query_formats = query_formats,