aboutsummaryrefslogtreecommitdiffstats
path: root/libavfilter
diff options
context:
space:
mode:
authorNicolas George <george@nsup.org>2015-09-30 16:11:57 +0200
committerNicolas George <george@nsup.org>2015-12-22 16:04:30 +0100
commit16557887127256fb1e491702375e7ea7b3940924 (patch)
treee6218ca8a613ccf7c54a95047d618de3d7e66724 /libavfilter
parent108b4de5529a75b06da72b974b26625a8067001f (diff)
downloadffmpeg-16557887127256fb1e491702375e7ea7b3940924.tar.gz
lavfi: make request_frame() non-recursive.
Instead of calling the input filter request_frame() method, ff_request_frame() now marks the link and returns immediately. buffersink is changed to activate the marked filters until a frame is obtained.
Diffstat (limited to 'libavfilter')
-rw-r--r--libavfilter/avfilter.c20
-rw-r--r--libavfilter/avfilter.h14
-rw-r--r--libavfilter/avfiltergraph.c58
-rw-r--r--libavfilter/buffersink.c5
-rw-r--r--libavfilter/internal.h7
5 files changed, 99 insertions, 5 deletions
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index cdb47f7f3e..2f4d59f316 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -186,6 +186,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);
}
@@ -354,11 +355,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])
@@ -367,6 +378,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)
@@ -1136,6 +1150,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);
@@ -1177,6 +1194,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 c52175b4c9..599369dcb0 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -520,6 +520,20 @@ struct AVFilterLink {
* A pointer to a FFVideoFramePool struct.
*/
void *video_frame_pool;
+
+ /**
+ * 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.
+ */
+ int 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.
+ */
+ int frame_wanted_out;
};
/**
diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index ec2245f15b..9f50b4120d 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 7a19df2c3a..2feb56dee9 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 836733ff76..766debeb71 100644
--- a/libavfilter/internal.h
+++ b/libavfilter/internal.h
@@ -334,6 +334,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, \
@@ -380,6 +382,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