[FFmpeg-devel] [PATCH 5/5] lavfi: make request_frame() non-recursive.

Hendrik Leppkes h.leppkes at gmail.com
Mon Nov 30 23:28:02 CET 2015


On Sun, Nov 29, 2015 at 5:21 PM, Nicolas George <george at nsup.org> wrote:
> Instead of calling the input filter request_frame() method,
> ff_request_frame() now marks the link and returns immediately.
> bufferskin is changed to activate the marked filters until
> a frame is obtained.
>
> Signed-off-by: Nicolas George <george at nsup.org>
> ---
>  libavfilter/avfilter.c      | 20 +++++++++++++++-
>  libavfilter/avfilter.h      | 14 +++++++++++
>  libavfilter/avfiltergraph.c | 58 +++++++++++++++++++++++++++++++++++++++++----
>  libavfilter/buffersink.c    |  5 ++++
>  libavfilter/internal.h      |  7 ++++++
>  5 files changed, 99 insertions(+), 5 deletions(-)
>
> diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
> index 9c7b462..e413546 100644
> --- a/libavfilter/avfilter.c
> +++ b/libavfilter/avfilter.c
> @@ -185,6 +185,7 @@ void ff_avfilter_link_set_in_status(AVFilterLink *link, int status, int64_t pts)
>  void ff_avfilter_link_set_out_status(AVFilterLink *link, int status, int64_t pts)
>  {
>      link->status = status;
> +    link->frame_wanted_in = link->frame_wanted_out = 0;
>      ff_update_link_current_pts(link, pts);
>  }
>
> @@ -353,11 +354,21 @@ void ff_tlog_link(void *ctx, AVFilterLink *link, int end)
>
>  int ff_request_frame(AVFilterLink *link)
>  {
> -    int ret = -1;
>      FF_TPRINTF_START(NULL, request_frame); ff_tlog_link(NULL, link, 1);
>
>      if (link->status)
>          return link->status;
> +    link->frame_wanted_in = 1;
> +    link->frame_wanted_out = 1;
> +    return 0;
> +}
> +
> +int ff_request_frame_to_filter(AVFilterLink *link)
> +{
> +    int ret = -1;
> +
> +    FF_TPRINTF_START(NULL, request_frame_to_filter); ff_tlog_link(NULL, link, 1);
> +    link->frame_wanted_in = 0;
>      if (link->srcpad->request_frame)
>          ret = link->srcpad->request_frame(link);
>      else if (link->src->inputs[0])
> @@ -366,6 +377,9 @@ int ff_request_frame(AVFilterLink *link)
>          AVFrame *pbuf = link->partial_buf;
>          link->partial_buf = NULL;
>          ret = ff_filter_frame_framed(link, pbuf);
> +        ff_avfilter_link_set_in_status(link, AVERROR_EOF, AV_NOPTS_VALUE);
> +        link->frame_wanted_out = 0;
> +        return ret;
>      }
>      if (ret < 0) {
>          if (ret != AVERROR(EAGAIN) && ret != link->status)
> @@ -1135,6 +1149,9 @@ static int ff_filter_frame_needs_framing(AVFilterLink *link, AVFrame *frame)
>          if (pbuf->nb_samples >= link->min_samples) {
>              ret = ff_filter_frame_framed(link, pbuf);
>              pbuf = NULL;
> +        } else {
> +            if (link->frame_wanted_out)
> +                link->frame_wanted_in = 1;
>          }
>      }
>      av_frame_free(&frame);
> @@ -1176,6 +1193,7 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
>          }
>      }
>
> +    link->frame_wanted_out = 0;
>      /* Go directly to actual filtering if possible */
>      if (link->type == AVMEDIA_TYPE_AUDIO &&
>          link->min_samples &&
> diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
> index f3a0f2d..801f29d 100644
> --- a/libavfilter/avfilter.h
> +++ b/libavfilter/avfilter.h
> @@ -515,6 +515,20 @@ struct AVFilterLink {
>       * Number of past frames sent through the link.
>       */
>      int64_t frame_count;
> +
> +    /**
> +     * True if a frame is currently wanted on the input of this filter.
> +     * Set when ff_request_frame() is called by the output,
> +     * cleared when the request is handled or forwarded.
> +     */
> +    unsigned frame_wanted_in;
> +
> +    /**
> +     * True if a frame is currently wanted on the output of this filter.
> +     * Set when ff_request_frame() is called by the output,
> +     * cleared when a frame is filtered.
> +     */
> +    unsigned frame_wanted_out;

We generally just use ints for boolean properties, any particular
reason this uses unsigned instead?

>  };
>
>  /**
> diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
> index ec2245f..9f50b41 100644
> --- a/libavfilter/avfiltergraph.c
> +++ b/libavfilter/avfiltergraph.c
> @@ -1367,11 +1367,14 @@ void ff_avfilter_graph_update_heap(AVFilterGraph *graph, AVFilterLink *link)
>
>  int avfilter_graph_request_oldest(AVFilterGraph *graph)
>  {
> +    AVFilterLink *oldest = graph->sink_links[0];
> +    int r;
> +
>      while (graph->sink_links_count) {
> -        AVFilterLink *oldest = graph->sink_links[0];
> -        int r = ff_request_frame(oldest);
> +        oldest = graph->sink_links[0];
> +        r = ff_request_frame(oldest);
>          if (r != AVERROR_EOF)
> -            return r;
> +            break;
>          av_log(oldest->dst, AV_LOG_DEBUG, "EOF on sink link %s:%s.\n",
>                 oldest->dst ? oldest->dst->name : "unknown",
>                 oldest->dstpad ? oldest->dstpad->name : "unknown");
> @@ -1381,5 +1384,52 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph)
>                               oldest->age_index);
>          oldest->age_index = -1;
>      }
> -    return AVERROR_EOF;
> +    if (!graph->sink_links_count)
> +        return AVERROR_EOF;
> +    av_assert1(oldest->age_index >= 0);
> +    while (oldest->frame_wanted_out) {
> +        r = ff_filter_graph_run_once(graph);
> +        if (r < 0)
> +            return r;
> +    }
> +    return 0;
> +}
> +
> +static AVFilterLink *graph_run_once_find_filter(AVFilterGraph *graph)
> +{
> +    unsigned i, j;
> +    AVFilterContext *f;
> +
> +    /* TODO: replace scanning the graph with a priority list */
> +    for (i = 0; i < graph->nb_filters; i++) {
> +        f = graph->filters[i];
> +        for (j = 0; j < f->nb_outputs; j++)
> +            if (f->outputs[j]->frame_wanted_in)
> +                return f->outputs[j];
> +    }
> +    for (i = 0; i < graph->nb_filters; i++) {
> +        f = graph->filters[i];
> +        for (j = 0; j < f->nb_outputs; j++)
> +            if (f->outputs[j]->frame_wanted_out)
> +                return f->outputs[j];
> +    }
> +    return NULL;
> +}
> +
> +int ff_filter_graph_run_once(AVFilterGraph *graph)
> +{
> +    AVFilterLink *link;
> +    int ret;
> +
> +    link = graph_run_once_find_filter(graph);
> +    if (!link) {
> +        av_log(NULL, AV_LOG_WARNING, "Useless run of a filter graph\n");
> +        return AVERROR(EAGAIN);
> +    }
> +    ret = ff_request_frame_to_filter(link);
> +    if (ret == AVERROR_EOF)
> +        /* local EOF will be forwarded through request_frame() /
> +           set_status() until it reaches the sink */
> +        ret = 0;
> +    return ret < 0 ? ret : 1;
>  }
> diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
> index 7a19df2..2feb56d 100644
> --- a/libavfilter/buffersink.c
> +++ b/libavfilter/buffersink.c
> @@ -140,6 +140,11 @@ int attribute_align_arg av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFr
>              return AVERROR(EAGAIN);
>          if ((ret = ff_request_frame(inlink)) < 0)
>              return ret;
> +        while (inlink->frame_wanted_out) {
> +            ret = ff_filter_graph_run_once(ctx->graph);
> +            if (ret < 0)
> +                return ret;
> +        }
>      }
>
>      if (flags & AV_BUFFERSINK_FLAG_PEEK) {
> diff --git a/libavfilter/internal.h b/libavfilter/internal.h
> index e55ae9d..afc8488 100644
> --- a/libavfilter/internal.h
> +++ b/libavfilter/internal.h
> @@ -330,6 +330,8 @@ int ff_poll_frame(AVFilterLink *link);
>   */
>  int ff_request_frame(AVFilterLink *link);
>
> +int ff_request_frame_to_filter(AVFilterLink *link);
> +
>  #define AVFILTER_DEFINE_CLASS(fname)            \
>      static const AVClass fname##_class = {      \
>          .class_name = #fname,                   \
> @@ -376,6 +378,11 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name);
>  void ff_filter_graph_remove_filter(AVFilterGraph *graph, AVFilterContext *filter);
>
>  /**
> + * Run one round of processing on a filter graph.
> + */
> +int ff_filter_graph_run_once(AVFilterGraph *graph);
> +
> +/**
>   * Normalize the qscale factor
>   * FIXME the H264 qscale is a log based scale, mpeg1/2 is not, the code below
>   *       cannot be optimal
> --
> 2.6.2
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


More information about the ffmpeg-devel mailing list