[FFmpeg-devel] [PATCH 2/6] lavfi: loop on request_frame if necessary.

Nicolas George nicolas.george at normalesup.org
Sun Mar 31 19:43:45 CEST 2013


Some filters need several input frames before producing output.
For these filter, it becomes simpler to return 0 in
request_frame() and let the framework call it again until
output has been produced.

Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
---
 libavfilter/avfilter.c |   17 +++++++++++++++--
 libavfilter/avfilter.h |   11 +++++++++++
 libavfilter/internal.h |   14 ++++++++++++++
 3 files changed, 40 insertions(+), 2 deletions(-)


Note: the flag on the link is not strictly necessary, looping could be
unconditional, but it may hide bugs, so I would rather enable it only
if requested.


diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 8a907dc..f621941 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -323,6 +323,10 @@ int ff_request_frame(AVFilterLink *link)
 
     if (link->closed)
         return AVERROR_EOF;
+    av_assert0(!link->frame_requested);
+    link->frame_requested = 1;
+    while (link->frame_requested) {
+        /* TODO reindent */
     if (link->srcpad->request_frame)
         ret = link->srcpad->request_frame(link);
     else if (link->src->inputs[0])
@@ -332,8 +336,15 @@ int ff_request_frame(AVFilterLink *link)
         link->partial_buf = NULL;
         ret = ff_filter_frame_framed(link, pbuf);
     }
-    if (ret == AVERROR_EOF)
-        link->closed = 1;
+        if (ret < 0) {
+            link->frame_requested = 0;
+            if (ret == AVERROR_EOF)
+                link->closed = 1;
+        } else {
+            av_assert0(!link->frame_requested ||
+                       link->flags & FF_LINK_FLAG_REQUEST_LOOP);
+        }
+    }
     return ret;
 }
 
@@ -702,6 +713,7 @@ static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame)
 
     pts = out->pts;
     ret = filter_frame(link, out);
+    link->frame_requested = 0;
     ff_update_link_current_pts(link, pts);
     return ret;
 }
@@ -713,6 +725,7 @@ static int ff_filter_frame_needs_framing(AVFilterLink *link, AVFrame *frame)
     int nb_channels = av_frame_get_channels(frame);
     int ret = 0;
 
+    link->flags |= FF_LINK_FLAG_REQUEST_LOOP;
     /* Handle framing (min_samples, max_samples) */
     while (insamples) {
         if (!pbuf) {
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 455161f..7583dcc 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -682,6 +682,17 @@ struct AVFilterLink {
      * Number of channels.
      */
     int channels;
+
+    /**
+     * True if a frame is being requested on the link.
+     * Used internally by the framework.
+     */
+    unsigned frame_requested;
+
+    /**
+     * Link processing flags.
+     */
+    unsigned flags;
 };
 
 /**
diff --git a/libavfilter/internal.h b/libavfilter/internal.h
index 9a42ae0..0b28422 100644
--- a/libavfilter/internal.h
+++ b/libavfilter/internal.h
@@ -325,4 +325,18 @@ int ff_buffersink_read_samples_compat(AVFilterContext *ctx, AVFilterBufferRef **
  */
 int ff_filter_frame(AVFilterLink *link, AVFrame *frame);
 
+/**
+ * Flags for AVFilterLink.flags.
+ */
+enum {
+
+    /**
+     * Frame requests may need to loop in order to be fulfilled.
+     * A filter must set this flags on an output link if it may return 0 in
+     * request_frame() without filtering a frame.
+     */
+    FF_LINK_FLAG_REQUEST_LOOP = 1,
+
+};
+
 #endif /* AVFILTER_INTERNAL_H */
-- 
1.7.10.4



More information about the ffmpeg-devel mailing list