lavfi: loop on request_frame if necessary.
authorNicolas George <nicolas.george@normalesup.org>
Sun, 31 Mar 2013 17:17:57 +0000 (19:17 +0200)
committerNicolas George <nicolas.george@normalesup.org>
Wed, 3 Apr 2013 15:33:27 +0000 (17:33 +0200)
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.

libavfilter/avfilter.c
libavfilter/avfilter.h
libavfilter/internal.h

index 8a907dc..f621941 100644 (file)
@@ -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) {
index 455161f..7583dcc 100644 (file)
@@ -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;
 };
 
 /**
index 9a42ae0..0b28422 100644 (file)
@@ -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 */