[FFmpeg-devel] [PATCH] avfilter: add tpad filter

Gyan gyandoshi at gmail.com
Tue Oct 30 12:56:05 EET 2018


On Tue, Oct 30, 2018 at 3:27 PM Paul B Mahol <onemda at gmail.com> wrote:

> Signed-off-by: Paul B Mahol <onemda at gmail.com>
> ---
>  doc/filters.texi         |  22 ++++++
>  libavfilter/Makefile     |   1 +
>  libavfilter/allfilters.c |   1 +
>  libavfilter/vf_tpad.c    | 166 +++++++++++++++++++++++++++++++++++++++
>  4 files changed, 190 insertions(+)
>  create mode 100644 libavfilter/vf_tpad.c
>
> diff --git a/doc/filters.texi b/doc/filters.texi
> index 9b84b1145b..6dda780aa0 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -16676,6 +16676,28 @@ embedded peak information in display metadata is
> not reliable or when tone
>  mapping from a lower range to a higher range.
>  @end table
>
> + at section tpad
> +
> +Temporarily pad video frames.
> +
> +The filter accepts the following options:
> +
> + at table @option
> + at item start
> +Specify number of delay frames before input video stream.
> +
> + at item stop
> +Specify number of padding frames after input video stream.
> +Set to -1 to pad indefinitely.
> +
> + at item color
> +Specify the color of the padded area. For the syntax of this option,
> +check the @ref{color syntax,,"Color" section in the ffmpeg-utils
> +manual,ffmpeg-utils}.
> +
> +The default value of @var{color} is "black".
> + at end table
> +
>  @anchor{transpose}
>  @section transpose
>
> diff --git a/libavfilter/Makefile b/libavfilter/Makefile
> index c35cd8f422..51e48efc2e 100644
> --- a/libavfilter/Makefile
> +++ b/libavfilter/Makefile
> @@ -383,6 +383,7 @@ OBJS-$(CONFIG_TMIX_FILTER)                   +=
> vf_mix.o framesync.o
>  OBJS-$(CONFIG_TONEMAP_FILTER)                += vf_tonemap.o colorspace.o
>  OBJS-$(CONFIG_TONEMAP_OPENCL_FILTER)         += vf_tonemap_opencl.o
> colorspace.o opencl.o \
>                                                  opencl/tonemap.o
> opencl/colorspace_common.o
> +OBJS-$(CONFIG_TPAD_FILTER)                   += vf_tpad.o
>  OBJS-$(CONFIG_TRANSPOSE_FILTER)              += vf_transpose.o
>  OBJS-$(CONFIG_TRANSPOSE_NPP_FILTER)          += vf_transpose_npp.o
>  OBJS-$(CONFIG_TRIM_FILTER)                   += trim.o
> diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
> index d5a211bda5..6052cb8c3c 100644
> --- a/libavfilter/allfilters.c
> +++ b/libavfilter/allfilters.c
> @@ -365,6 +365,7 @@ extern AVFilter ff_vf_tlut2;
>  extern AVFilter ff_vf_tmix;
>  extern AVFilter ff_vf_tonemap;
>  extern AVFilter ff_vf_tonemap_opencl;
> +extern AVFilter ff_vf_tpad;
>  extern AVFilter ff_vf_transpose;
>  extern AVFilter ff_vf_transpose_npp;
>  extern AVFilter ff_vf_trim;
> diff --git a/libavfilter/vf_tpad.c b/libavfilter/vf_tpad.c
> new file mode 100644
> index 0000000000..e59037ca56
> --- /dev/null
> +++ b/libavfilter/vf_tpad.c
> @@ -0,0 +1,166 @@
> +/*
> + * Copyright (c) 2018 Paul B Mahol
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA
> + */
> +
> +#include "libavutil/avassert.h"
> +#include "libavutil/channel_layout.h"
> +#include "libavutil/opt.h"
> +#include "avfilter.h"
> +#include "audio.h"
> +#include "filters.h"
> +#include "internal.h"
> +#include "formats.h"
> +#include "drawutils.h"
> +
> +typedef struct TPadContext {
> +    const AVClass *class;
> +    int pad_start;
> +    int pad_stop;
> +    uint8_t rgba_color[4];  ///< color for the padding area
> +
> +    FFDrawContext draw;
> +    FFDrawColor color;
> +    int64_t pts;
> +    int eof;
> +} TPadContext;
> +
> +#define OFFSET(x) offsetof(TPadContext, x)
> +#define VF AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
> +
> +static const AVOption tpad_options[] = {
> +    { "start", "set the number of frames to delay input",
> OFFSET(pad_start),  AV_OPT_TYPE_INT,   {.i64=0},        0, INT_MAX, VF },
> +    { "stop",  "set the number of frames to add after input finished",
> OFFSET(pad_stop),   AV_OPT_TYPE_INT,   {.i64=0},       -1, INT_MAX, VF },
> +    { "color", "set the color of the added frames",
> OFFSET(rgba_color), AV_OPT_TYPE_COLOR, {.str="black"},  0,       0, VF },
> +    { NULL }
> +};
> +
> +AVFILTER_DEFINE_CLASS(tpad);
> +
> +static int query_formats(AVFilterContext *ctx)
> +{
> +    return ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
> +}
> +
> +static int activate(AVFilterContext *ctx)
> +{
> +    AVFilterLink *inlink = ctx->inputs[0];
> +    AVFilterLink *outlink = ctx->outputs[0];
> +    TPadContext *s = ctx->priv;
> +    AVFrame *frame = NULL;
> +    int ret, status;
> +    int64_t pts;
> +
> +    FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
> +
> +    if (s->pad_start > 0 && ff_outlink_frame_wanted(outlink)) {
> +        frame = ff_get_video_buffer(outlink, outlink->w, outlink->h);
> +        if (!frame)
> +            return AVERROR(ENOMEM);
> +        ff_fill_rectangle(&s->draw, &s->color,
> +                          frame->data, frame->linesize,
> +                          0, 0, frame->width, frame->height);
> +        frame->pts = s->pts;
> +        s->pts += av_rescale_q(1, av_inv_q(outlink->frame_rate),
> outlink->time_base);
> +        s->pad_start--;
> +        return ff_filter_frame(outlink, frame);
> +    }
> +
> +    if (!s->eof && !s->pad_start) {
> +        ret = ff_inlink_consume_frame(inlink, &frame);
> +        if (ret < 0)
> +            return ret;
> +        if (ret > 0) {
> +            frame->pts += s->pts;
> +            return ff_filter_frame(outlink, frame);
> +        }
> +    }
> +
> +    if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) {
> +        if (status == AVERROR_EOF) {
> +            if (!s->pad_stop) {
> +                ff_outlink_set_status(outlink, status, pts);
> +                return 0;
> +            }
> +            s->eof = 1;
> +            s->pts += pts;
> +        }
> +    }
> +
> +    if (s->eof) {
> +        if (!s->pad_stop) {
> +            ff_outlink_set_status(outlink, AVERROR_EOF, s->pts);
> +            return 0;
> +        }
> +        frame = ff_get_video_buffer(outlink, outlink->w, outlink->h);
> +        if (!frame)
> +            return AVERROR(ENOMEM);
> +        ff_fill_rectangle(&s->draw, &s->color,
> +                          frame->data, frame->linesize,
> +                          0, 0, frame->width, frame->height);
> +        frame->pts = s->pts;
> +        s->pts += av_rescale_q(1, av_inv_q(outlink->frame_rate),
> outlink->time_base);
> +        if (s->pad_stop > 0)
> +            s->pad_stop--;
> +        return ff_filter_frame(outlink, frame);
> +    }
> +
> +    if (!s->pad_start)
> +        FF_FILTER_FORWARD_WANTED(outlink, inlink);
> +
> +    return FFERROR_NOT_READY;
> +}
> +
> +static int config_input(AVFilterLink *inlink)
> +{
> +    AVFilterContext *ctx = inlink->dst;
> +    TPadContext *s = ctx->priv;
> +
> +    ff_draw_init(&s->draw, inlink->format, 0);
> +    ff_draw_color(&s->draw, &s->color, s->rgba_color);
> +
> +    return 0;
> +}
> +
> +static const AVFilterPad tpad_inputs[] = {
> +    {
> +        .name         = "default",
> +        .type         = AVMEDIA_TYPE_VIDEO,
> +        .config_props = config_input,
> +    },
> +    { NULL }
> +};
> +
> +static const AVFilterPad tpad_outputs[] = {
> +    {
> +        .name = "default",
> +        .type = AVMEDIA_TYPE_VIDEO,
> +    },
> +    { NULL }
> +};
> +
> +AVFilter ff_vf_tpad = {
> +    .name          = "tpad",
> +    .description   = NULL_IF_CONFIG_SMALL("Temporarily pad video
> frames."),
> +    .priv_size     = sizeof(TPadContext),
> +    .priv_class    = &tpad_class,
> +    .query_formats = query_formats,
> +    .inputs        = tpad_inputs,
> +    .outputs       = tpad_outputs,
> +    .activate      = activate,
> +};
>

Nice. Thanks.

A couple of suggestions:

1) allow the user to supply duration as well.

2) allow cloning the nearest frame. First frame for start delay and last
frame for end padding.

Gyan


More information about the ffmpeg-devel mailing list