Commit 02aa0701 authored by Nicolas George's avatar Nicolas George

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.
parent 62b11db0
This diff is collapsed.
...@@ -368,6 +368,13 @@ struct AVFilterContext { ...@@ -368,6 +368,13 @@ struct AVFilterContext {
* Overrides global number of threads set per filter graph. * Overrides global number of threads set per filter graph.
*/ */
int nb_threads; int nb_threads;
/**
* Ready status of the filter.
* A non-0 value means that the filter needs activating;
* a higher value suggests a more urgent activation.
*/
unsigned ready;
}; };
/** /**
...@@ -508,18 +515,6 @@ struct AVFilterLink { ...@@ -508,18 +515,6 @@ struct AVFilterLink {
*/ */
int max_samples; int max_samples;
/**
* Link status.
* If not zero, all attempts of filter_frame or request_frame
* will fail with the corresponding code, and if necessary the reference
* will be destroyed.
* If request_frame returns an error, the status is set on the
* corresponding link.
* It can be set also be set by either the source or the destination
* filter.
*/
int status;
/** /**
* Number of channels. * Number of channels.
*/ */
...@@ -540,13 +535,6 @@ struct AVFilterLink { ...@@ -540,13 +535,6 @@ struct AVFilterLink {
*/ */
void *video_frame_pool; 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. * True if a frame is currently wanted on the output of this filter.
* Set when ff_request_frame() is called by the output, * Set when ff_request_frame() is called by the output,
...@@ -559,6 +547,51 @@ struct AVFilterLink { ...@@ -559,6 +547,51 @@ struct AVFilterLink {
* AVHWFramesContext describing the frames. * AVHWFramesContext describing the frames.
*/ */
AVBufferRef *hw_frames_ctx; AVBufferRef *hw_frames_ctx;
#ifndef FF_INTERNAL_FIELDS
/**
* Internal structure members.
* The fields below this limit are internal for libavfilter's use
* and must in no way be accessed by applications.
*/
char reserved[0xF000];
#else /* FF_INTERNAL_FIELDS */
/**
* Queue of frames waiting to be filtered.
*/
FFFrameQueue fifo;
/**
* If set, the source filter can not generate a frame as is.
* The goal is to avoid repeatedly calling the request_frame() method on
* the same link.
*/
int frame_blocked_in;
/**
* Link input status.
* If not zero, all attempts of filter_frame will fail with the
* corresponding code.
*/
int status_in;
/**
* Timestamp of the input status change.
*/
int64_t status_in_pts;
/**
* Link output status.
* If not zero, all attempts of request_frame will fail with the
* corresponding code.
*/
int status_out;
#endif /* FF_INTERNAL_FIELDS */
}; };
/** /**
......
...@@ -32,6 +32,9 @@ ...@@ -32,6 +32,9 @@
#include "libavutil/opt.h" #include "libavutil/opt.h"
#include "libavutil/pixdesc.h" #include "libavutil/pixdesc.h"
#define FF_INTERNAL_FIELDS 1
#include "framequeue.h"
#include "avfilter.h" #include "avfilter.h"
#include "formats.h" #include "formats.h"
#include "internal.h" #include "internal.h"
...@@ -87,6 +90,7 @@ AVFilterGraph *avfilter_graph_alloc(void) ...@@ -87,6 +90,7 @@ AVFilterGraph *avfilter_graph_alloc(void)
ret->av_class = &filtergraph_class; ret->av_class = &filtergraph_class;
av_opt_set_defaults(ret); av_opt_set_defaults(ret);
ff_framequeue_global_init(&ret->internal->frame_queues);
return ret; return ret;
} }
...@@ -1377,10 +1381,10 @@ void ff_avfilter_graph_update_heap(AVFilterGraph *graph, AVFilterLink *link) ...@@ -1377,10 +1381,10 @@ void ff_avfilter_graph_update_heap(AVFilterGraph *graph, AVFilterLink *link)
heap_bubble_down(graph, link, link->age_index); heap_bubble_down(graph, link, link->age_index);
} }
int avfilter_graph_request_oldest(AVFilterGraph *graph) int avfilter_graph_request_oldest(AVFilterGraph *graph)
{ {
AVFilterLink *oldest = graph->sink_links[0]; AVFilterLink *oldest = graph->sink_links[0];
int64_t frame_count;
int r; int r;
while (graph->sink_links_count) { while (graph->sink_links_count) {
...@@ -1400,7 +1404,8 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph) ...@@ -1400,7 +1404,8 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph)
if (!graph->sink_links_count) if (!graph->sink_links_count)
return AVERROR_EOF; return AVERROR_EOF;
av_assert1(oldest->age_index >= 0); 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); r = ff_filter_graph_run_once(graph);
if (r < 0) if (r < 0)
return r; return r;
...@@ -1408,41 +1413,17 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph) ...@@ -1408,41 +1413,17 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph)
return 0; 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) int ff_filter_graph_run_once(AVFilterGraph *graph)
{ {
AVFilterLink *link; AVFilterContext *filter;
int ret; unsigned i;
link = graph_run_once_find_filter(graph); av_assert0(graph->nb_filters);
if (!link) { filter = graph->filters[0];
av_log(NULL, AV_LOG_WARNING, "Useless run of a filter graph\n"); 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); return AVERROR(EAGAIN);
} return ff_filter_activate(filter);
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;
} }
...@@ -31,6 +31,9 @@ ...@@ -31,6 +31,9 @@
#include "libavutil/mathematics.h" #include "libavutil/mathematics.h"
#include "libavutil/opt.h" #include "libavutil/opt.h"
#define FF_INTERNAL_FIELDS 1
#include "framequeue.h"
#include "audio.h" #include "audio.h"
#include "avfilter.h" #include "avfilter.h"
#include "buffersink.h" #include "buffersink.h"
...@@ -129,18 +132,26 @@ int attribute_align_arg av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFr ...@@ -129,18 +132,26 @@ int attribute_align_arg av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFr
{ {
BufferSinkContext *buf = ctx->priv; BufferSinkContext *buf = ctx->priv;
AVFilterLink *inlink = ctx->inputs[0]; AVFilterLink *inlink = ctx->inputs[0];
int ret; int peek_in_framequeue = 0, ret;
int64_t frame_count;
AVFrame *cur_frame; AVFrame *cur_frame;
/* no picref available, fetch it from the filterchain */ /* no picref available, fetch it from the filterchain */
while (!av_fifo_size(buf->fifo)) { while (!av_fifo_size(buf->fifo)) {
if (inlink->status) /* if peek_in_framequeue is true later, then ff_request_frame() and
return inlink->status; the ff_filter_graph_run_once() loop will take a frame from it and
if (flags & AV_BUFFERSINK_FLAG_NO_REQUEST) move it to the internal fifo, ending the global loop */
av_assert0(!peek_in_framequeue);
if (inlink->status_out)
return inlink->status_out;
peek_in_framequeue = ff_framequeue_queued_frames(&inlink->fifo) &&
ff_framequeue_queued_samples(&inlink->fifo) >= inlink->min_samples;
if ((flags & AV_BUFFERSINK_FLAG_NO_REQUEST) && !peek_in_framequeue)
return AVERROR(EAGAIN); return AVERROR(EAGAIN);
if ((ret = ff_request_frame(inlink)) < 0) if ((ret = ff_request_frame(inlink)) < 0)
return ret; return ret;
while (inlink->frame_wanted_out) { frame_count = inlink->frame_count_out;
while (frame_count == inlink->frame_count_out) {
ret = ff_filter_graph_run_once(ctx->graph); ret = ff_filter_graph_run_once(ctx->graph);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -184,6 +184,7 @@ static int av_buffersrc_add_frame_internal(AVFilterContext *ctx, ...@@ -184,6 +184,7 @@ static int av_buffersrc_add_frame_internal(AVFilterContext *ctx,
if (!frame) { if (!frame) {
s->eof = 1; s->eof = 1;
ff_avfilter_link_set_in_status(ctx->outputs[0], AVERROR_EOF, AV_NOPTS_VALUE);
return 0; return 0;
} else if (s->eof) } else if (s->eof)
return AVERROR(EINVAL); return AVERROR(EINVAL);
...@@ -235,9 +236,8 @@ static int av_buffersrc_add_frame_internal(AVFilterContext *ctx, ...@@ -235,9 +236,8 @@ static int av_buffersrc_add_frame_internal(AVFilterContext *ctx,
return ret; return ret;
} }
if ((flags & AV_BUFFERSRC_FLAG_PUSH)) if ((ret = ctx->output_pads[0].request_frame(ctx->outputs[0])) < 0)
if ((ret = ctx->output_pads[0].request_frame(ctx->outputs[0])) < 0) return ret;
return ret;
return 0; return 0;
} }
......
...@@ -26,6 +26,10 @@ ...@@ -26,6 +26,10 @@
#include "libavutil/avassert.h" #include "libavutil/avassert.h"
#include "libavutil/avstring.h" #include "libavutil/avstring.h"
#include "libavutil/opt.h" #include "libavutil/opt.h"
#define FF_INTERNAL_FIELDS 1
#include "framequeue.h"
#include "avfilter.h" #include "avfilter.h"
#include "bufferqueue.h" #include "bufferqueue.h"
#include "formats.h" #include "formats.h"
...@@ -59,7 +63,7 @@ inline static int push_frame(AVFilterContext *ctx) ...@@ -59,7 +63,7 @@ inline static int push_frame(AVFilterContext *ctx)
for (i = 0; i < ctx->nb_inputs; i++) { for (i = 0; i < ctx->nb_inputs; i++) {
struct FFBufQueue *q = &s->queues[i]; struct FFBufQueue *q = &s->queues[i];
if (!q->available && !ctx->inputs[i]->status) if (!q->available && !ctx->inputs[i]->status_out)
return 0; return 0;
if (q->available) { if (q->available) {
frame = ff_bufqueue_peek(q, 0); frame = ff_bufqueue_peek(q, 0);
...@@ -190,7 +194,7 @@ static int request_frame(AVFilterLink *outlink) ...@@ -190,7 +194,7 @@ static int request_frame(AVFilterLink *outlink)
int i, ret; int i, ret;
for (i = 0; i < ctx->nb_inputs; i++) { for (i = 0; i < ctx->nb_inputs; i++) {
if (!s->queues[i].available && !ctx->inputs[i]->status) { if (!s->queues[i].available && !ctx->inputs[i]->status_out) {
ret = ff_request_frame(ctx->inputs[i]); ret = ff_request_frame(ctx->inputs[i]);
if (ret != AVERROR_EOF) if (ret != AVERROR_EOF)
return ret; return ret;
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "avfiltergraph.h" #include "avfiltergraph.h"
#include "formats.h" #include "formats.h"
#include "framepool.h" #include "framepool.h"
#include "framequeue.h"
#include "thread.h" #include "thread.h"
#include "version.h" #include "version.h"
#include "video.h" #include "video.h"
...@@ -147,6 +148,7 @@ struct AVFilterPad { ...@@ -147,6 +148,7 @@ struct AVFilterPad {
struct AVFilterGraphInternal { struct AVFilterGraphInternal {
void *thread; void *thread;
avfilter_execute_func *thread_execute; avfilter_execute_func *thread_execute;
FFFrameQueueGlobal frame_queues;
}; };
struct AVFilterInternal { struct AVFilterInternal {
...@@ -336,6 +338,8 @@ int ff_request_frame(AVFilterLink *link); ...@@ -336,6 +338,8 @@ int ff_request_frame(AVFilterLink *link);
int ff_request_frame_to_filter(AVFilterLink *link); int ff_request_frame_to_filter(AVFilterLink *link);
int ff_filter_frame_to_filter(AVFilterLink *link);
#define AVFILTER_DEFINE_CLASS(fname) \ #define AVFILTER_DEFINE_CLASS(fname) \
static const AVClass fname##_class = { \ static const AVClass fname##_class = { \
.class_name = #fname, \ .class_name = #fname, \
...@@ -376,6 +380,8 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame); ...@@ -376,6 +380,8 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame);
*/ */
AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name); AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name);
int ff_filter_activate(AVFilterContext *filter);
/** /**
* Remove a filter from a graph; * Remove a filter from a graph;
*/ */
......
...@@ -30,6 +30,9 @@ ...@@ -30,6 +30,9 @@
#include "libavutil/mem.h" #include "libavutil/mem.h"
#include "libavutil/opt.h" #include "libavutil/opt.h"
#define FF_INTERNAL_FIELDS 1
#include "framequeue.h"
#include "avfilter.h" #include "avfilter.h"
#include "audio.h" #include "audio.h"
#include "formats.h" #include "formats.h"
...@@ -78,7 +81,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) ...@@ -78,7 +81,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
for (i = 0; i < ctx->nb_outputs; i++) { for (i = 0; i < ctx->nb_outputs; i++) {
AVFrame *buf_out; AVFrame *buf_out;
if (ctx->outputs[i]->status) if (ctx->outputs[i]->status_in)
continue; continue;
buf_out = av_frame_clone(frame); buf_out = av_frame_clone(frame);
if (!buf_out) { if (!buf_out) {
......
...@@ -25,6 +25,9 @@ ...@@ -25,6 +25,9 @@
#include "libavutil/pixdesc.h" #include "libavutil/pixdesc.h"
#include "libavutil/samplefmt.h" #include "libavutil/samplefmt.h"
#define FF_INTERNAL_FIELDS 1
#include "libavfilter/framequeue.h"
#include "libavfilter/avfilter.h" #include "libavfilter/avfilter.h"
#include "libavfilter/formats.h" #include "libavfilter/formats.h"
......
...@@ -22,6 +22,10 @@ ...@@ -22,6 +22,10 @@
#include "libavutil/imgutils.h" #include "libavutil/imgutils.h"
#include "libavutil/opt.h" #include "libavutil/opt.h"
#include "libavutil/pixdesc.h" #include "libavutil/pixdesc.h"
#define FF_INTERNAL_FIELDS 1
#include "libavfilter/framequeue.h"
#include "avfilter.h" #include "avfilter.h"
#include "drawutils.h" #include "drawutils.h"
#include "internal.h" #include "internal.h"
...@@ -283,7 +287,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) ...@@ -283,7 +287,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
const int idx = s->map[i]; const int idx = s->map[i];
AVFrame *out; AVFrame *out;
if (outlink->status) if (outlink->status_in)
continue; continue;
out = ff_get_video_buffer(outlink, outlink->w, outlink->h); out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment