lavfi: make filter_frame non-recursive.

A lot of changes happen at the same time:

- Add a framequeue fifo to AVFilterLink.

- split AVFilterLink.status into status_in and status_out: requires
  changes to the few filters and programs that use it directly
  (f_interleave, split, filtfmts).

- Add a field ready to AVFilterContext, marking when the filter is ready
  and its activation priority.

- Add flags to mark blocked links.

- Change ff_filter_frame() to enqueue the frame.

- Change all filtering functions to update the ready field and the
  blocked flags.

- Update ff_filter_graph_run_once() to use the ready field.

- buffersrc: always push the frame immediately.
This commit is contained in:
Nicolas George
2016-01-03 15:44:42 +01:00
parent 62b11db0a0
commit 02aa0701ae
10 changed files with 492 additions and 142 deletions

View File

@@ -32,6 +32,9 @@
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#define FF_INTERNAL_FIELDS 1
#include "framequeue.h"
#include "avfilter.h"
#include "formats.h"
#include "internal.h"
@@ -87,6 +90,7 @@ AVFilterGraph *avfilter_graph_alloc(void)
ret->av_class = &filtergraph_class;
av_opt_set_defaults(ret);
ff_framequeue_global_init(&ret->internal->frame_queues);
return ret;
}
@@ -1377,10 +1381,10 @@ void ff_avfilter_graph_update_heap(AVFilterGraph *graph, AVFilterLink *link)
heap_bubble_down(graph, link, link->age_index);
}
int avfilter_graph_request_oldest(AVFilterGraph *graph)
{
AVFilterLink *oldest = graph->sink_links[0];
int64_t frame_count;
int r;
while (graph->sink_links_count) {
@@ -1400,7 +1404,8 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph)
if (!graph->sink_links_count)
return AVERROR_EOF;
av_assert1(oldest->age_index >= 0);
while (oldest->frame_wanted_out) {
frame_count = oldest->frame_count_out;
while (frame_count == oldest->frame_count_out) {
r = ff_filter_graph_run_once(graph);
if (r < 0)
return r;
@@ -1408,41 +1413,17 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph)
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;
AVFilterContext *filter;
unsigned i;
link = graph_run_once_find_filter(graph);
if (!link) {
av_log(NULL, AV_LOG_WARNING, "Useless run of a filter graph\n");
av_assert0(graph->nb_filters);
filter = graph->filters[0];
for (i = 1; i < graph->nb_filters; i++)
if (graph->filters[i]->ready > filter->ready)
filter = graph->filters[i];
if (!filter->ready)
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;
return ff_filter_activate(filter);
}