[FFmpeg-devel] [PATCH] life: add slow_death, life_color and death_color options.
Clément Bœsch
ubitux at gmail.com
Mon Dec 5 00:48:47 CET 2011
---
Additionally to the example, here is a more organic one:
ffplay -f lavfi life=f=CREDITS:s=400x400:slow_death=1:r=120:death_color=#113366:life_color=#ff0000,boxblur=2:2
---
doc/filters.texi | 17 ++++++++++
libavfilter/vsrc_life.c | 82 +++++++++++++++++++++++++++++++---------------
2 files changed, 72 insertions(+), 27 deletions(-)
diff --git a/doc/filters.texi b/doc/filters.texi
index eb1a4df..5e38b08 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -2863,6 +2863,17 @@ If a filename is not specified, the size value defaults to "320x240"
@item stitch
If set to 1, stitch the left and right grid edges together, and the
top and bottom edges also. Defaults to 1.
+
+ at item slow_death
+If set to 1, the progressive death effect will be effective: the dead cells
+will slightly go from @option{death_color} to black.
+
+ at item life_color
+Color of a living cell.
+
+ at item death_color
+Color of a dead cell. If @option{slow_death} is set, this is the first color
+used to represent a dead cell.
@end table
@subsection Examples
@@ -2887,6 +2898,12 @@ Specify a custom rule for evolving a randomly generated grid:
life=rule=S14/B34
@end example
+ at item
+Full example with slow death effect using ffplay:
+ at example
+ffplay -f lavfi life=s=300x200:slow_death=1:r=60:ratio=0.1:death_color=#C83232:life_color=#00ff00,scale=1200:800:flags=16
+ at end example
+
@end itemize
@section nullsrc, rgbtestsrc, testsrc
diff --git a/libavfilter/vsrc_life.c b/libavfilter/vsrc_life.c
index 79e064a..e3b5561 100644
--- a/libavfilter/vsrc_life.c
+++ b/libavfilter/vsrc_life.c
@@ -50,6 +50,11 @@ typedef struct {
double random_fill_ratio;
uint32_t random_seed;
int stitch;
+ int slow_death;
+ char *life_color_str;
+ char *death_color_str;
+ uint8_t life_color[4];
+ uint8_t death_color[4];
AVLFG lfg;
} LifeContext;
@@ -68,6 +73,9 @@ static const AVOption life_options[] = {
{ "random_seed", "set the seed for filling the initial grid randomly", OFFSET(random_seed), AV_OPT_TYPE_INT, {.dbl=-1}, -1, UINT32_MAX },
{ "seed", "set the seed for filling the initial grid randomly", OFFSET(random_seed), AV_OPT_TYPE_INT, {.dbl=-1}, -1, UINT32_MAX },
{ "stitch", "stitch boundaries", OFFSET(stitch), AV_OPT_TYPE_INT, {.dbl=1}, 0, 1 },
+ { "slow_death", "progressive death effect", OFFSET(slow_death), AV_OPT_TYPE_INT, {.dbl=0}, 0, 1 },
+ { "life_color", "set life color", OFFSET( life_color_str), AV_OPT_TYPE_STRING, {.str="white"}, CHAR_MIN, CHAR_MAX },
+ { "death_color", "set death color", OFFSET(death_color_str), AV_OPT_TYPE_STRING, {.str="black"}, CHAR_MIN, CHAR_MAX },
{ NULL },
};
@@ -135,7 +143,7 @@ static void show_life_grid(AVFilterContext *ctx)
return;
for (i = 0; i < life->h; i++) {
for (j = 0; j < life->w; j++)
- line[j] = life->buf[life->buf_idx][i*life->w + j] ? '@' : ' ';
+ line[j] = life->buf[life->buf_idx][i*life->w + j] ? ' ' : '@';
line[j] = 0;
av_log(ctx, AV_LOG_DEBUG, "%3d: %s\n", i, line);
}
@@ -184,18 +192,17 @@ static int init_pattern_from_file(AVFilterContext *ctx)
return AVERROR(ENOMEM);
}
- /* fill buf[0] */
p = life->file_buf;
+ memset(life->buf[0], 0xff, life->w * life->h);
for (i0 = 0, i = (life->h - h)/2; i0 < h; i0++, i++) {
for (j = (life->w - max_w)/2;; j++) {
av_log(ctx, AV_LOG_DEBUG, "%d:%d %c\n", i, j, *p == '\n' ? 'N' : *p);
if (*p == '\n') {
p++; break;
} else
- life->buf[0][i*life->w + j] = !!isgraph(*(p++));
+ life->buf[0][i*life->w + j] = !isgraph(*(p++)) * 0xff;
}
}
- life->buf_idx = 0;
return 0;
}
@@ -231,6 +238,16 @@ static int init(AVFilterContext *ctx, const char *args, void *opaque)
if ((ret = parse_rule(&life->born_rule, &life->stay_rule, life->rule_str, ctx)) < 0)
return ret;
+ if ((ret = av_parse_color(life->life_color, life->life_color_str, -1, ctx))) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid life color '%s'\n", life->life_color_str);
+ return ret;
+ }
+
+ if ((ret = av_parse_color(life->death_color, life->death_color_str, -1, ctx))) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid death color '%s'\n", life->death_color_str);
+ return ret;
+ }
+
life->time_base.num = frame_rate.den;
life->time_base.den = frame_rate.num;
@@ -251,14 +268,15 @@ static int init(AVFilterContext *ctx, const char *args, void *opaque)
for (i = 0; i < life->w * life->h; i++) {
double r = (double)av_lfg_get(&life->lfg) / UINT32_MAX;
- if (r <= life->random_fill_ratio)
- life->buf[0][i] = 1;
+ if (r > life->random_fill_ratio)
+ life->buf[0][i] = 0xff; // dead
}
- life->buf_idx = 0;
} else {
if ((ret = init_pattern_from_file(ctx)) < 0)
return ret;
}
+ memcpy(life->buf[1], life->buf[0], life->w * life->h);
+ life->buf_idx = 0;
av_log(ctx, AV_LOG_INFO,
"s:%dx%d r:%d/%d rule:%s stay_rule:%d born_rule:%d stitch:%d\n",
@@ -322,17 +340,18 @@ static void evolve(AVFilterContext *ctx)
}
/* compute the number of live neighbor cells */
- n = (pos[NW][0] == -1 || pos[NW][1] == -1 ? 0 : oldbuf[pos[NW][0]*life->w + pos[NW][1]]) +
- (pos[N ][0] == -1 || pos[N ][1] == -1 ? 0 : oldbuf[pos[N ][0]*life->w + pos[N ][1]]) +
- (pos[NE][0] == -1 || pos[NE][1] == -1 ? 0 : oldbuf[pos[NE][0]*life->w + pos[NE][1]]) +
- (pos[W ][0] == -1 || pos[W ][1] == -1 ? 0 : oldbuf[pos[W ][0]*life->w + pos[W ][1]]) +
- (pos[E ][0] == -1 || pos[E ][1] == -1 ? 0 : oldbuf[pos[E ][0]*life->w + pos[E ][1]]) +
- (pos[SW][0] == -1 || pos[SW][1] == -1 ? 0 : oldbuf[pos[SW][0]*life->w + pos[SW][1]]) +
- (pos[S ][0] == -1 || pos[S ][1] == -1 ? 0 : oldbuf[pos[S ][0]*life->w + pos[S ][1]]) +
- (pos[SE][0] == -1 || pos[SE][1] == -1 ? 0 : oldbuf[pos[SE][0]*life->w + pos[SE][1]]);
- v = !!(1<<n & (oldbuf[i*life->w + j] ? life->stay_rule : life->born_rule));
- av_dlog(ctx, "i:%d j:%d live_neighbors:%d cell:%d -> cell:%d\n", i, j, n, oldbuf[i*life->w + j], v);
- newbuf[i*life->w+j] = v;
+ n = (pos[NW][0] == -1 || pos[NW][1] == -1 ? 0 : !oldbuf[pos[NW][0]*life->w + pos[NW][1]]) +
+ (pos[N ][0] == -1 || pos[N ][1] == -1 ? 0 : !oldbuf[pos[N ][0]*life->w + pos[N ][1]]) +
+ (pos[NE][0] == -1 || pos[NE][1] == -1 ? 0 : !oldbuf[pos[NE][0]*life->w + pos[NE][1]]) +
+ (pos[W ][0] == -1 || pos[W ][1] == -1 ? 0 : !oldbuf[pos[W ][0]*life->w + pos[W ][1]]) +
+ (pos[E ][0] == -1 || pos[E ][1] == -1 ? 0 : !oldbuf[pos[E ][0]*life->w + pos[E ][1]]) +
+ (pos[SW][0] == -1 || pos[SW][1] == -1 ? 0 : !oldbuf[pos[SW][0]*life->w + pos[SW][1]]) +
+ (pos[S ][0] == -1 || pos[S ][1] == -1 ? 0 : !oldbuf[pos[S ][0]*life->w + pos[S ][1]]) +
+ (pos[SE][0] == -1 || pos[SE][1] == -1 ? 0 : !oldbuf[pos[SE][0]*life->w + pos[SE][1]]);
+ v = 1<<n & (!oldbuf[i*life->w + j] ? life->stay_rule : life->born_rule);
+ *newbuf = v ? 0 : *newbuf + (*newbuf < 0xff);
+ av_dlog(ctx, "i:%d j:%d live_neighbors:%d cell:%d -> cell:%d\n", i, j, n, oldbuf[i*life->w + j], *newbuf);
+ newbuf++;
}
}
@@ -343,18 +362,27 @@ static void fill_picture(AVFilterContext *ctx, AVFilterBufferRef *picref)
{
LifeContext *life = ctx->priv;
uint8_t *buf = life->buf[life->buf_idx];
- int i, j, k;
+ int i, j;
/* fill the output picture with the old grid buffer */
for (i = 0; i < life->h; i++) {
- uint8_t byte = 0;
uint8_t *p = picref->data[0] + i * picref->linesize[0];
- for (k = 0, j = 0; j < life->w; j++) {
- byte |= buf[i*life->w+j]<<(7-k++);
- if (k==8 || j == life->w-1) {
- k = 0;
- *p++ = byte;
- byte = 0;
+ for (j = 0; j < life->w; j++) {
+ uint8_t death_age = buf[i*life->w + j];
+ if (death_age == 0) {
+ *p++ = life->life_color[0];
+ *p++ = life->life_color[1];
+ *p++ = life->life_color[2];
+ } else {
+ if (life->slow_death) {
+ *p++ = FFMAX((int)life->death_color[0] - death_age, 0);
+ *p++ = FFMAX((int)life->death_color[1] - death_age, 0);
+ *p++ = FFMAX((int)life->death_color[2] - death_age, 0);
+ } else {
+ *p++ = life->death_color[0];
+ *p++ = life->death_color[1];
+ *p++ = life->death_color[2];
+ }
}
}
}
@@ -384,7 +412,7 @@ static int request_frame(AVFilterLink *outlink)
static int query_formats(AVFilterContext *ctx)
{
- static const enum PixelFormat pix_fmts[] = { PIX_FMT_MONOBLACK, PIX_FMT_NONE };
+ static const enum PixelFormat pix_fmts[] = { PIX_FMT_RGB24, PIX_FMT_NONE };
avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
return 0;
}
--
1.7.7.4
More information about the ffmpeg-devel
mailing list