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 {
* Overrides global number of threads set per filter graph.
*/
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 {
*/
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.
*/
......@@ -540,13 +535,6 @@ struct AVFilterLink {
*/
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,
......@@ -559,6 +547,51 @@ struct AVFilterLink {
* AVHWFramesContext describing the frames.
*/
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 @@
#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;
link = graph_run_once_find_filter(graph);
if (!link) {
av_log(NULL, AV_LOG_WARNING, "Useless run of a filter graph\n");
AVFilterContext *filter;
unsigned i;
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);
}
......@@ -31,6 +31,9 @@
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#define FF_INTERNAL_FIELDS 1
#include "framequeue.h"
#include "audio.h"
#include "avfilter.h"
#include "buffersink.h"
......@@ -129,18 +132,26 @@ int attribute_align_arg av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFr
{
BufferSinkContext *buf = ctx->priv;
AVFilterLink *inlink = ctx->inputs[0];
int ret;
int peek_in_framequeue = 0, ret;
int64_t frame_count;
AVFrame *cur_frame;
/* no picref available, fetch it from the filterchain */
while (!av_fifo_size(buf->fifo)) {
if (inlink->status)
return inlink->status;
if (flags & AV_BUFFERSINK_FLAG_NO_REQUEST)
/* if peek_in_framequeue is true later, then ff_request_frame() and
the ff_filter_graph_run_once() loop will take a frame from it and
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);
if ((ret = ff_request_frame(inlink)) < 0)
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);
if (ret < 0)
return ret;
......
......@@ -184,6 +184,7 @@ static int av_buffersrc_add_frame_internal(AVFilterContext *ctx,
if (!frame) {
s->eof = 1;
ff_avfilter_link_set_in_status(ctx->outputs[0], AVERROR_EOF, AV_NOPTS_VALUE);
return 0;
} else if (s->eof)
return AVERROR(EINVAL);
......@@ -235,7 +236,6 @@ static int av_buffersrc_add_frame_internal(AVFilterContext *ctx,
return ret;
}
if ((flags & AV_BUFFERSRC_FLAG_PUSH))
if ((ret = ctx->output_pads[0].request_frame(ctx->outputs[0])) < 0)
return ret;
......
......@@ -26,6 +26,10 @@
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/opt.h"
#define FF_INTERNAL_FIELDS 1
#include "framequeue.h"
#include "avfilter.h"
#include "bufferqueue.h"
#include "formats.h"
......@@ -59,7 +63,7 @@ inline static int push_frame(AVFilterContext *ctx)
for (i = 0; i < ctx->nb_inputs; i++) {
struct FFBufQueue *q = &s->queues[i];
if (!q->available && !ctx->inputs[i]->status)
if (!q->available && !ctx->inputs[i]->status_out)
return 0;
if (q->available) {
frame = ff_bufqueue_peek(q, 0);
......@@ -190,7 +194,7 @@ static int request_frame(AVFilterLink *outlink)
int i, ret;
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]);
if (ret != AVERROR_EOF)
return ret;
......
......@@ -29,6 +29,7 @@
#include "avfiltergraph.h"
#include "formats.h"
#include "framepool.h"
#include "framequeue.h"
#include "thread.h"
#include "version.h"
#include "video.h"
......@@ -147,6 +148,7 @@ struct AVFilterPad {
struct AVFilterGraphInternal {
void *thread;
avfilter_execute_func *thread_execute;
FFFrameQueueGlobal frame_queues;
};
struct AVFilterInternal {
......@@ -336,6 +338,8 @@ int ff_request_frame(AVFilterLink *link);
int ff_request_frame_to_filter(AVFilterLink *link);
int ff_filter_frame_to_filter(AVFilterLink *link);
#define AVFILTER_DEFINE_CLASS(fname) \
static const AVClass fname##_class = { \
.class_name = #fname, \
......@@ -376,6 +380,8 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame);
*/
AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name);
int ff_filter_activate(AVFilterContext *filter);
/**
* Remove a filter from a graph;
*/
......
......@@ -30,6 +30,9 @@
#include "libavutil/mem.h"
#include "libavutil/opt.h"
#define FF_INTERNAL_FIELDS 1
#include "framequeue.h"
#include "avfilter.h"
#include "audio.h"
#include "formats.h"
......@@ -78,7 +81,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
for (i = 0; i < ctx->nb_outputs; i++) {
AVFrame *buf_out;
if (ctx->outputs[i]->status)
if (ctx->outputs[i]->status_in)
continue;
buf_out = av_frame_clone(frame);
if (!buf_out) {
......
......@@ -25,6 +25,9 @@
#include "libavutil/pixdesc.h"
#include "libavutil/samplefmt.h"
#define FF_INTERNAL_FIELDS 1
#include "libavfilter/framequeue.h"
#include "libavfilter/avfilter.h"
#include "libavfilter/formats.h"
......
......@@ -22,6 +22,10 @@
#include "libavutil/imgutils.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#define FF_INTERNAL_FIELDS 1
#include "libavfilter/framequeue.h"
#include "avfilter.h"
#include "drawutils.h"
#include "internal.h"
......@@ -283,7 +287,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
const int idx = s->map[i];
AVFrame *out;
if (outlink->status)
if (outlink->status_in)
continue;
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