Commit 7a060867 authored by Paul B Mahol's avatar Paul B Mahol

avfilter/vf_tile: add overlap option

Signed-off-by: 's avatarPaul B Mahol <onemda@gmail.com>
parent a7e7abf8
...@@ -14441,6 +14441,10 @@ refer to the pad video filter. ...@@ -14441,6 +14441,10 @@ refer to the pad video filter.
Specify the color of the unused area. For the syntax of this option, check the Specify the color of the unused area. For the syntax of this option, check the
"Color" section in the ffmpeg-utils manual. The default value of @var{color} "Color" section in the ffmpeg-utils manual. The default value of @var{color}
is "black". is "black".
@item overlap
Set the number of frames to overlap when tiling several successive frames together.
The value must be between @code{0} and @var{nb_frames - 1}.
@end table @end table
@subsection Examples @subsection Examples
......
...@@ -37,11 +37,13 @@ typedef struct TileContext { ...@@ -37,11 +37,13 @@ typedef struct TileContext {
unsigned w, h; unsigned w, h;
unsigned margin; unsigned margin;
unsigned padding; unsigned padding;
unsigned overlap;
unsigned current; unsigned current;
unsigned nb_frames; unsigned nb_frames;
FFDrawContext draw; FFDrawContext draw;
FFDrawColor blank; FFDrawColor blank;
AVFrame *out_ref; AVFrame *out_ref;
AVFrame *prev_out_ref;
uint8_t rgba_color[4]; uint8_t rgba_color[4];
} TileContext; } TileContext;
...@@ -58,6 +60,8 @@ static const AVOption tile_options[] = { ...@@ -58,6 +60,8 @@ static const AVOption tile_options[] = {
{ "padding", "set inner border thickness in pixels", OFFSET(padding), { "padding", "set inner border thickness in pixels", OFFSET(padding),
AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1024, FLAGS }, AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1024, FLAGS },
{ "color", "set the color of the unused area", OFFSET(rgba_color), AV_OPT_TYPE_COLOR, {.str = "black"}, .flags = FLAGS }, { "color", "set the color of the unused area", OFFSET(rgba_color), AV_OPT_TYPE_COLOR, {.str = "black"}, .flags = FLAGS },
{ "overlap", "set how many frames to overlap for each render", OFFSET(overlap),
AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS },
{ NULL } { NULL }
}; };
...@@ -90,6 +94,11 @@ static av_cold int init(AVFilterContext *ctx) ...@@ -90,6 +94,11 @@ static av_cold int init(AVFilterContext *ctx)
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
if (tile->overlap >= tile->nb_frames) {
av_log(ctx, AV_LOG_WARNING, "overlap must be less than %d\n", tile->nb_frames);
tile->overlap = tile->nb_frames - 1;
}
return 0; return 0;
} }
...@@ -120,19 +129,19 @@ static int config_props(AVFilterLink *outlink) ...@@ -120,19 +129,19 @@ static int config_props(AVFilterLink *outlink)
outlink->h = tile->h * inlink->h + total_margin_h; outlink->h = tile->h * inlink->h + total_margin_h;
outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
outlink->frame_rate = av_mul_q(inlink->frame_rate, outlink->frame_rate = av_mul_q(inlink->frame_rate,
av_make_q(1, tile->nb_frames)); av_make_q(1, tile->nb_frames - tile->overlap));
ff_draw_init(&tile->draw, inlink->format, 0); ff_draw_init(&tile->draw, inlink->format, 0);
ff_draw_color(&tile->draw, &tile->blank, tile->rgba_color); ff_draw_color(&tile->draw, &tile->blank, tile->rgba_color);
return 0; return 0;
} }
static void get_current_tile_pos(AVFilterContext *ctx, unsigned *x, unsigned *y) static void get_tile_pos(AVFilterContext *ctx, unsigned *x, unsigned *y, unsigned current)
{ {
TileContext *tile = ctx->priv; TileContext *tile = ctx->priv;
AVFilterLink *inlink = ctx->inputs[0]; AVFilterLink *inlink = ctx->inputs[0];
const unsigned tx = tile->current % tile->w; const unsigned tx = current % tile->w;
const unsigned ty = tile->current / tile->w; const unsigned ty = current / tile->w;
*x = tile->margin + (inlink->w + tile->padding) * tx; *x = tile->margin + (inlink->w + tile->padding) * tx;
*y = tile->margin + (inlink->h + tile->padding) * ty; *y = tile->margin + (inlink->h + tile->padding) * ty;
...@@ -144,7 +153,7 @@ static void draw_blank_frame(AVFilterContext *ctx, AVFrame *out_buf) ...@@ -144,7 +153,7 @@ static void draw_blank_frame(AVFilterContext *ctx, AVFrame *out_buf)
AVFilterLink *inlink = ctx->inputs[0]; AVFilterLink *inlink = ctx->inputs[0];
unsigned x0, y0; unsigned x0, y0;
get_current_tile_pos(ctx, &x0, &y0); get_tile_pos(ctx, &x0, &y0, tile->current);
ff_fill_rectangle(&tile->draw, &tile->blank, ff_fill_rectangle(&tile->draw, &tile->blank,
out_buf->data, out_buf->linesize, out_buf->data, out_buf->linesize,
x0, y0, inlink->w, inlink->h); x0, y0, inlink->w, inlink->h);
...@@ -160,8 +169,13 @@ static int end_last_frame(AVFilterContext *ctx) ...@@ -160,8 +169,13 @@ static int end_last_frame(AVFilterContext *ctx)
while (tile->current < tile->nb_frames) while (tile->current < tile->nb_frames)
draw_blank_frame(ctx, out_buf); draw_blank_frame(ctx, out_buf);
tile->current = tile->overlap;
if (tile->current) {
av_frame_free(&tile->prev_out_ref);
tile->prev_out_ref = av_frame_clone(out_buf);
}
ret = ff_filter_frame(outlink, out_buf); ret = ff_filter_frame(outlink, out_buf);
tile->current = 0; tile->out_ref = NULL;
return ret; return ret;
} }
...@@ -176,7 +190,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref) ...@@ -176,7 +190,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
AVFilterLink *outlink = ctx->outputs[0]; AVFilterLink *outlink = ctx->outputs[0];
unsigned x0, y0; unsigned x0, y0;
if (!tile->current) { if (!tile->out_ref) {
tile->out_ref = ff_get_video_buffer(outlink, outlink->w, outlink->h); tile->out_ref = ff_get_video_buffer(outlink, outlink->w, outlink->h);
if (!tile->out_ref) { if (!tile->out_ref) {
av_frame_free(&picref); av_frame_free(&picref);
...@@ -194,7 +208,21 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref) ...@@ -194,7 +208,21 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
0, 0, outlink->w, outlink->h); 0, 0, outlink->w, outlink->h);
} }
get_current_tile_pos(ctx, &x0, &y0); if (tile->prev_out_ref) {
unsigned x1, y1, i;
for (i = tile->nb_frames - tile->overlap; i < tile->nb_frames; i++) {
get_tile_pos(ctx, &x1, &y1, i);
get_tile_pos(ctx, &x0, &y0, i - (tile->nb_frames - tile->overlap));
ff_copy_rectangle2(&tile->draw,
tile->out_ref->data, tile->out_ref->linesize,
tile->prev_out_ref->data, tile->prev_out_ref->linesize,
x0, y0, x1, y1, inlink->w, inlink->h);
}
}
get_tile_pos(ctx, &x0, &y0, tile->current);
ff_copy_rectangle2(&tile->draw, ff_copy_rectangle2(&tile->draw,
tile->out_ref->data, tile->out_ref->linesize, tile->out_ref->data, tile->out_ref->linesize,
picref->data, picref->linesize, picref->data, picref->linesize,
...@@ -215,11 +243,18 @@ static int request_frame(AVFilterLink *outlink) ...@@ -215,11 +243,18 @@ static int request_frame(AVFilterLink *outlink)
int r; int r;
r = ff_request_frame(inlink); r = ff_request_frame(inlink);
if (r == AVERROR_EOF && tile->current) if (r == AVERROR_EOF && tile->current && tile->out_ref)
r = end_last_frame(ctx); r = end_last_frame(ctx);
return r; return r;
} }
static av_cold void uninit(AVFilterContext *ctx)
{
TileContext *tile = ctx->priv;
av_frame_free(&tile->prev_out_ref);
}
static const AVFilterPad tile_inputs[] = { static const AVFilterPad tile_inputs[] = {
{ {
.name = "default", .name = "default",
...@@ -243,6 +278,7 @@ AVFilter ff_vf_tile = { ...@@ -243,6 +278,7 @@ AVFilter ff_vf_tile = {
.name = "tile", .name = "tile",
.description = NULL_IF_CONFIG_SMALL("Tile several successive frames together."), .description = NULL_IF_CONFIG_SMALL("Tile several successive frames together."),
.init = init, .init = init,
.uninit = uninit,
.query_formats = query_formats, .query_formats = query_formats,
.priv_size = sizeof(TileContext), .priv_size = sizeof(TileContext),
.inputs = tile_inputs, .inputs = tile_inputs,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment