On Sun, Nov 29, 2015 at 5:21 PM, Nicolas George <geo...@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 <geo...@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@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel