[FFmpeg-cvslog] lavfi/framesync2: implement "activate" design.
Nicolas George
git at videolan.org
Sun Jul 30 13:35:36 EEST 2017
ffmpeg | branch: master | Nicolas George <george at nsup.org> | Mon Jul 17 14:36:42 2017 +0200| [4e0e9ce2dc67a94c98d40a46e91fe5aa53ad0376] | committer: Nicolas George
lavfi/framesync2: implement "activate" design.
With this helper API, filters that used the first framesync
helper API can easily be changed to use the new and more
extensible design for filters with a single activate() callback.
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=4e0e9ce2dc67a94c98d40a46e91fe5aa53ad0376
---
libavfilter/framesync2.c | 166 +++++++++++++++++++----------------------------
libavfilter/framesync2.h | 77 ++++------------------
2 files changed, 82 insertions(+), 161 deletions(-)
diff --git a/libavfilter/framesync2.c b/libavfilter/framesync2.c
index 8d81bb5c48..0e9f6f210c 100644
--- a/libavfilter/framesync2.c
+++ b/libavfilter/framesync2.c
@@ -18,12 +18,9 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#define FF_INTERNAL_FIELDS 1
-#include "framequeue.h"
-
#include "libavutil/avassert.h"
#include "avfilter.h"
-#include "bufferqueue.h"
+#include "filters.h"
#include "framesync2.h"
#include "internal.h"
@@ -49,8 +46,13 @@ enum {
STATE_EOF,
};
-int ff_framesync2_init(FFFrameSync *fs, void *parent, unsigned nb_in)
+int ff_framesync2_init(FFFrameSync *fs, AVFilterContext *parent, unsigned nb_in)
{
+ /* For filters with several outputs, we will not be able to assume which
+ output is relevant for ff_outlink_frame_wanted() and
+ ff_outlink_set_status(). To be designed when needed. */
+ av_assert0(parent->nb_outputs == 1);
+
fs->class = &framesync_class;
fs->parent = parent;
fs->nb_in = nb_in;
@@ -61,6 +63,13 @@ int ff_framesync2_init(FFFrameSync *fs, void *parent, unsigned nb_in)
return 0;
}
+static void framesync_eof(FFFrameSync *fs)
+{
+ fs->eof = 1;
+ fs->frame_ready = 0;
+ ff_outlink_set_status(fs->parent->outputs[0], AVERROR_EOF, AV_NOPTS_VALUE);
+}
+
static void framesync_sync_level_update(FFFrameSync *fs)
{
unsigned i, level = 0;
@@ -74,7 +83,7 @@ static void framesync_sync_level_update(FFFrameSync *fs)
if (level)
fs->sync_level = level;
else
- fs->eof = 1;
+ framesync_eof(fs);
}
int ff_framesync2_configure(FFFrameSync *fs)
@@ -144,7 +153,7 @@ static void framesync_advance(FFFrameSync *fs)
if (fs->in[i].pts_next < pts)
pts = fs->in[i].pts_next;
if (pts == INT64_MAX) {
- fs->eof = 1;
+ framesync_eof(fs);
break;
}
for (i = 0; i < fs->nb_in; i++) {
@@ -162,11 +171,9 @@ static void framesync_advance(FFFrameSync *fs)
fs->frame_ready = 1;
if (fs->in[i].state == STATE_EOF &&
fs->in[i].after == EXT_STOP)
- fs->eof = 1;
+ framesync_eof(fs);
}
}
- if (fs->eof)
- fs->frame_ready = 0;
if (fs->frame_ready)
for (i = 0; i < fs->nb_in; i++)
if ((fs->in[i].state == STATE_BOF &&
@@ -188,45 +195,24 @@ static void framesync_inject_frame(FFFrameSync *fs, unsigned in, AVFrame *frame)
int64_t pts;
av_assert0(!fs->in[in].have_next);
- if (frame) {
- pts = av_rescale_q(frame->pts, fs->in[in].time_base, fs->time_base);
- frame->pts = pts;
- } else {
- pts = fs->in[in].state != STATE_RUN || fs->in[in].after == EXT_INFINITY
- ? INT64_MAX : framesync_pts_extrapolate(fs, in, fs->in[in].pts);
- fs->in[in].sync = 0;
- framesync_sync_level_update(fs);
- }
+ av_assert0(frame);
+ pts = av_rescale_q(frame->pts, fs->in[in].time_base, fs->time_base);
+ frame->pts = pts;
fs->in[in].frame_next = frame;
fs->in[in].pts_next = pts;
fs->in[in].have_next = 1;
}
-int ff_framesync2_add_frame(FFFrameSync *fs, unsigned in, AVFrame *frame)
-{
- av_assert1(in < fs->nb_in);
- if (!fs->in[in].have_next)
- framesync_inject_frame(fs, in, frame);
- else
- ff_bufqueue_add(fs, &fs->in[in].queue, frame);
- return 0;
-}
-
-void ff_framesync2_next(FFFrameSync *fs)
-{
- unsigned i;
-
- av_assert0(!fs->frame_ready);
- for (i = 0; i < fs->nb_in; i++)
- if (!fs->in[i].have_next && fs->in[i].queue.available)
- framesync_inject_frame(fs, i, ff_bufqueue_get(&fs->in[i].queue));
- fs->frame_ready = 0;
- framesync_advance(fs);
-}
-
-void ff_framesync2_drop(FFFrameSync *fs)
+static void framesync_inject_status(FFFrameSync *fs, unsigned in, int status, int64_t pts)
{
- fs->frame_ready = 0;
+ av_assert0(!fs->in[in].have_next);
+ pts = fs->in[in].state != STATE_RUN || fs->in[in].after == EXT_INFINITY
+ ? INT64_MAX : framesync_pts_extrapolate(fs, in, fs->in[in].pts);
+ fs->in[in].sync = 0;
+ framesync_sync_level_update(fs);
+ fs->in[in].frame_next = NULL;
+ fs->in[in].pts_next = pts;
+ fs->in[in].have_next = 1;
}
int ff_framesync2_get_frame(FFFrameSync *fs, unsigned in, AVFrame **rframe,
@@ -273,71 +259,55 @@ void ff_framesync2_uninit(FFFrameSync *fs)
for (i = 0; i < fs->nb_in; i++) {
av_frame_free(&fs->in[i].frame);
av_frame_free(&fs->in[i].frame_next);
- ff_bufqueue_discard_all(&fs->in[i].queue);
}
av_freep(&fs->in);
}
-int ff_framesync2_process_frame(FFFrameSync *fs, unsigned all)
+int ff_framesync2_activate(FFFrameSync *fs)
{
- int ret, count = 0;
+ AVFilterContext *ctx = fs->parent;
+ AVFrame *frame = NULL;
+ int64_t pts;
+ unsigned i, nb_active, nb_miss;
+ int ret, status;
- av_assert0(fs->on_event);
- while (1) {
- ff_framesync2_next(fs);
- if (fs->eof || !fs->frame_ready)
- break;
- if ((ret = fs->on_event(fs)) < 0)
+ nb_active = nb_miss = 0;
+ for (i = 0; i < fs->nb_in; i++) {
+ if (fs->in[i].have_next || fs->in[i].state == STATE_EOF)
+ continue;
+ nb_active++;
+ ret = ff_inlink_consume_frame(ctx->inputs[i], &frame);
+ if (ret < 0)
return ret;
- ff_framesync2_drop(fs);
- count++;
- if (!all)
- break;
+ if (ret) {
+ av_assert0(frame);
+ framesync_inject_frame(fs, i, frame);
+ } else {
+ ret = ff_inlink_acknowledge_status(ctx->inputs[i], &status, &pts);
+ if (ret > 0) {
+ framesync_inject_status(fs, i, status, pts);
+ } else if (!ret) {
+ nb_miss++;
+ }
+ }
+ }
+ if (nb_miss) {
+ if (nb_miss == nb_active && !ff_outlink_frame_wanted(ctx->outputs[0]))
+ return FFERROR_NOT_READY;
+ for (i = 0; i < fs->nb_in; i++)
+ if (!fs->in[i].have_next && fs->in[i].state != STATE_EOF)
+ ff_inlink_request_frame(ctx->inputs[i]);
+ return 0;
}
- if (!count && fs->eof)
- return AVERROR_EOF;
- return count;
-}
-
-int ff_framesync2_filter_frame(FFFrameSync *fs, AVFilterLink *inlink,
- AVFrame *in)
-{
- int ret;
- if ((ret = ff_framesync2_process_frame(fs, 1)) < 0)
- return ret;
- if ((ret = ff_framesync2_add_frame(fs, FF_INLINK_IDX(inlink), in)) < 0)
- return ret;
- if ((ret = ff_framesync2_process_frame(fs, 0)) < 0)
+ framesync_advance(fs);
+ if (fs->eof || !fs->frame_ready)
+ return 0;
+ ret = fs->on_event(fs);
+ if (ret < 0)
return ret;
- return 0;
-}
-
-int ff_framesync2_request_frame(FFFrameSync *fs, AVFilterLink *outlink)
-{
- AVFilterContext *ctx = outlink->src;
- int input, ret, i;
+ fs->frame_ready = 0;
- if ((ret = ff_framesync2_process_frame(fs, 0)) < 0)
- return ret;
- if (ret > 0)
- return 0;
- if (fs->eof)
- return AVERROR_EOF;
- input = fs->in_request;
- /* Detect status change early */
- for (i = 0; i < fs->nb_in; i++)
- if (!ff_framequeue_queued_frames(&ctx->inputs[i]->fifo) &&
- ctx->inputs[i]->status_in && !ctx->inputs[i]->status_out)
- input = i;
- ret = ff_request_frame(ctx->inputs[input]);
- if (ret == AVERROR_EOF) {
- if ((ret = ff_framesync2_add_frame(fs, input, NULL)) < 0)
- return ret;
- if ((ret = ff_framesync2_process_frame(fs, 0)) < 0)
- return ret;
- ret = 0;
- }
- return ret;
+ return 0;
}
diff --git a/libavfilter/framesync2.h b/libavfilter/framesync2.h
index e19d0f37e8..2b37636ebb 100644
--- a/libavfilter/framesync2.h
+++ b/libavfilter/framesync2.h
@@ -25,7 +25,6 @@
/*
* TODO
- * Callback-based API similar to dualinput.
* Export convenient options.
*/
@@ -41,16 +40,9 @@
* situations where some stream extend beyond the beginning or the end of
* others can be configured.
*
- * The basic working of this API is the following:
- *
- * - When a frame is available on any input, add it using
- * ff_framesync2_add_frame().
- *
- * - When a frame event is ready to be processed (i.e. after adding a frame
- * or when requested on input):
- * - call ff_framesync2_next();
- * - if fs->frame_ready is true, process the frames;
- * - call ff_framesync2_drop().
+ * The basic working of this API is the following: set the on_event
+ * callback, then call ff_framesync2_activate() from the filter's activate
+ * callback.
*/
/**
@@ -83,11 +75,6 @@ enum FFFrameSyncExtMode {
typedef struct FFFrameSyncIn {
/**
- * Queue of incoming AVFrame, and NULL to mark EOF
- */
- struct FFBufQueue queue;
-
- /**
* Extrapolation mode for timestamps before the first frame
*/
enum FFFrameSyncExtMode before;
@@ -152,7 +139,11 @@ typedef struct FFFrameSyncIn {
*/
typedef struct FFFrameSync {
const AVClass *class;
- void *parent;
+
+ /**
+ * Parent filter context.
+ */
+ AVFilterContext *parent;
/**
* Number of input streams
@@ -213,11 +204,11 @@ typedef struct FFFrameSync {
* The entire structure is expected to be already set to 0.
*
* @param fs frame sync structure to initialize
- * @param parent parent object, used for logging
+ * @param parent parent AVFilterContext object
* @param nb_in number of inputs
* @return >= 0 for success or a negative error code
*/
-int ff_framesync2_init(FFFrameSync *fs, void *parent, unsigned nb_in);
+int ff_framesync2_init(FFFrameSync *fs, AVFilterContext *parent, unsigned nb_in);
/**
* Configure a frame sync structure.
@@ -234,29 +225,6 @@ int ff_framesync2_configure(FFFrameSync *fs);
void ff_framesync2_uninit(FFFrameSync *fs);
/**
- * Add a frame to an input
- *
- * Typically called from the filter_frame() method.
- *
- * @param fs frame sync structure
- * @param in index of the input
- * @param frame input frame, or NULL for EOF
- */
-int ff_framesync2_add_frame(FFFrameSync *fs, unsigned in, AVFrame *frame);
-
-/**
- * Prepare the next frame event.
- *
- * The status of the operation can be found in fs->frame_ready and fs->eof.
- */
-void ff_framesync2_next(FFFrameSync *fs);
-
-/**
- * Drop the current frame event.
- */
-void ff_framesync2_drop(FFFrameSync *fs);
-
-/**
* Get the current frame in an input.
*
* @param fs frame sync structure
@@ -270,28 +238,11 @@ int ff_framesync2_get_frame(FFFrameSync *fs, unsigned in, AVFrame **rframe,
unsigned get);
/**
- * Process one or several frame using the on_event callback.
- *
- * @return number of frames processed or negative error code
- */
-int ff_framesync2_process_frame(FFFrameSync *fs, unsigned all);
-
-
-/**
- * Accept a frame on a filter input.
- *
- * This function can be the complete implementation of all filter_frame
- * methods of a filter using framesync.
- */
-int ff_framesync2_filter_frame(FFFrameSync *fs, AVFilterLink *inlink,
- AVFrame *in);
-
-/**
- * Request a frame on the filter output.
+ * Examine the frames in the filter's input and try to produce output.
*
- * This function can be the complete implementation of all filter_frame
- * methods of a filter using framesync if it has only one output.
+ * This function can be the complete implementation of the activate
+ * method of a filter using framesync2.
*/
-int ff_framesync2_request_frame(FFFrameSync *fs, AVFilterLink *outlink);
+int ff_framesync2_activate(FFFrameSync *fs);
#endif /* AVFILTER_FRAMESYNC2_H */
More information about the ffmpeg-cvslog
mailing list