X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavfilter%2Fvf_tile.c;h=439689a14d4663468e24aa0b2aca9f3515e42f03;hb=061337a073236cb0bc6c56036f50f883d2887681;hp=e9d246fc73b0bd47a465a96d4638f9887e78d220;hpb=27aa69896bd6a816026f0fd57b12ad1fc147ab65;p=ffmpeg diff --git a/libavfilter/vf_tile.c b/libavfilter/vf_tile.c index e9d246fc73b..439689a14d4 100644 --- a/libavfilter/vf_tile.c +++ b/libavfilter/vf_tile.c @@ -37,11 +37,14 @@ typedef struct TileContext { unsigned w, h; unsigned margin; unsigned padding; + unsigned overlap; + unsigned init_padding; unsigned current; unsigned nb_frames; FFDrawContext draw; FFDrawColor blank; AVFrame *out_ref; + AVFrame *prev_out_ref; uint8_t rgba_color[4]; } TileContext; @@ -58,6 +61,10 @@ static const AVOption tile_options[] = { { "padding", "set inner border thickness in pixels", OFFSET(padding), 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 }, + { "overlap", "set how many frames to overlap for each render", OFFSET(overlap), + AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS }, + { "init_padding", " set how many frames to initially pad", OFFSET(init_padding), + AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS }, { NULL } }; @@ -90,6 +97,17 @@ static av_cold int init(AVFilterContext *ctx) 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; + } + + if (tile->init_padding >= tile->nb_frames) { + av_log(ctx, AV_LOG_WARNING, "init_padding must be less than %d\n", tile->nb_frames); + } else { + tile->current = tile->init_padding; + } + return 0; } @@ -120,19 +138,19 @@ static int config_props(AVFilterLink *outlink) outlink->h = tile->h * inlink->h + total_margin_h; outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; 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_color(&tile->draw, &tile->blank, tile->rgba_color); 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; AVFilterLink *inlink = ctx->inputs[0]; - const unsigned tx = tile->current % tile->w; - const unsigned ty = tile->current / tile->w; + const unsigned tx = current % tile->w; + const unsigned ty = current / tile->w; *x = tile->margin + (inlink->w + tile->padding) * tx; *y = tile->margin + (inlink->h + tile->padding) * ty; @@ -144,7 +162,7 @@ static void draw_blank_frame(AVFilterContext *ctx, AVFrame *out_buf) AVFilterLink *inlink = ctx->inputs[0]; 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, out_buf->data, out_buf->linesize, x0, y0, inlink->w, inlink->h); @@ -160,8 +178,13 @@ static int end_last_frame(AVFilterContext *ctx) while (tile->current < tile->nb_frames) 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); - tile->current = 0; + tile->out_ref = NULL; return ret; } @@ -176,7 +199,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref) AVFilterLink *outlink = ctx->outputs[0]; unsigned x0, y0; - if (!tile->current) { + if (!tile->out_ref) { tile->out_ref = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!tile->out_ref) { av_frame_free(&picref); @@ -187,14 +210,29 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref) tile->out_ref->height = outlink->h; /* fill surface once for margin/padding */ - if (tile->margin || tile->padding) + if (tile->margin || tile->padding || tile->init_padding) ff_fill_rectangle(&tile->draw, &tile->blank, tile->out_ref->data, tile->out_ref->linesize, 0, 0, outlink->w, outlink->h); + tile->init_padding = 0; } - 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, tile->out_ref->data, tile->out_ref->linesize, picref->data, picref->linesize, @@ -215,11 +253,18 @@ static int request_frame(AVFilterLink *outlink) int r; 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); 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[] = { { .name = "default", @@ -243,6 +288,7 @@ AVFilter ff_vf_tile = { .name = "tile", .description = NULL_IF_CONFIG_SMALL("Tile several successive frames together."), .init = init, + .uninit = uninit, .query_formats = query_formats, .priv_size = sizeof(TileContext), .inputs = tile_inputs,