lavfi/buffersrc: implement flags.
authorNicolas George <nicolas.george@normalesup.org>
Sun, 10 Mar 2013 12:33:18 +0000 (13:33 +0100)
committerNicolas George <nicolas.george@normalesup.org>
Sun, 10 Mar 2013 12:56:17 +0000 (13:56 +0100)
The PUSH flags is necessary for efficient scheduling;
otherwise there is no feedback when adding frames to
closed paths.

The NO_CHECK_FORMAT is a small optimization that does
not cost much to implement.

The KEEP_REF flag maps to the add/write distinction in
the fork's API.

libavfilter/buffersrc.c
libavfilter/buffersrc.h

index 6c6689b..185018d 100644 (file)
@@ -75,14 +75,23 @@ typedef struct {
         return AVERROR(EINVAL);\
     }
 
-int av_buffersrc_add_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags)
+int av_buffersrc_write_frame(AVFilterContext *ctx, const AVFrame *frame)
 {
-    return av_buffersrc_add_frame(ctx, frame);
+    return av_buffersrc_add_frame_flags(ctx, (AVFrame *)frame,
+                                        AV_BUFFERSRC_FLAG_KEEP_REF);
 }
 
-int av_buffersrc_write_frame(AVFilterContext *ctx, const AVFrame *frame)
+int av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame)
 {
-    AVFrame *copy;
+    return av_buffersrc_add_frame_flags(ctx, frame, 0);
+}
+
+static int av_buffersrc_add_frame_internal(AVFilterContext *ctx,
+                                           AVFrame *frame, int flags);
+
+int av_buffersrc_add_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags)
+{
+    AVFrame *copy = NULL;
     int ret = 0;
     int64_t layout = frame->channel_layout;
 
@@ -91,22 +100,25 @@ int av_buffersrc_write_frame(AVFilterContext *ctx, const AVFrame *frame)
         return AVERROR(EINVAL);
     }
 
+    if (!(flags & AV_BUFFERSRC_FLAG_KEEP_REF) || !frame)
+        return av_buffersrc_add_frame_internal(ctx, frame, flags);
+
     if (!(copy = av_frame_alloc()))
         return AVERROR(ENOMEM);
     ret = av_frame_ref(copy, frame);
     if (ret >= 0)
-        ret = av_buffersrc_add_frame(ctx, copy);
+        ret = av_buffersrc_add_frame_internal(ctx, copy, flags);
 
     av_frame_free(&copy);
     return ret;
 }
 
-int av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame)
+static int av_buffersrc_add_frame_internal(AVFilterContext *ctx,
+                                           AVFrame *frame, int flags)
 {
     BufferSourceContext *s = ctx->priv;
     AVFrame *copy;
     int ret;
-    int64_t layout;
 
     if (!frame) {
         s->eof = 1;
@@ -114,6 +126,8 @@ int av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame)
     } else if (s->eof)
         return AVERROR(EINVAL);
 
+    if (!(flags & AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT)) {
+
     switch (ctx->outputs[0]->type) {
     case AVMEDIA_TYPE_VIDEO:
         CHECK_VIDEO_PARAM_CHANGE(ctx, s, frame->width, frame->height,
@@ -122,17 +136,13 @@ int av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame)
     case AVMEDIA_TYPE_AUDIO:
         CHECK_AUDIO_PARAM_CHANGE(ctx, s, frame->sample_rate, frame->channel_layout,
                                  frame->format);
-
-        layout = frame->channel_layout;
-        if (layout && av_get_channel_layout_nb_channels(layout) != av_frame_get_channels(frame)) {
-            av_log(0, AV_LOG_ERROR, "Layout indicates a different number of channels than actually present\n");
-            return AVERROR(EINVAL);
-        }
         break;
     default:
         return AVERROR(EINVAL);
     }
 
+    }
+
     if (!av_fifo_space(s->fifo) &&
         (ret = av_fifo_realloc2(s->fifo, av_fifo_size(s->fifo) +
                                          sizeof(copy))) < 0)
@@ -148,6 +158,10 @@ int av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame)
         return ret;
     }
 
+    if ((flags & AV_BUFFERSRC_FLAG_PUSH))
+        if ((ret = ctx->output_pads[0].request_frame(ctx->outputs[0])) < 0)
+            return ret;
+
     return 0;
 }
 
index 3b9fd52..66361b3 100644 (file)
@@ -35,16 +35,25 @@ enum {
      */
     AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT = 1,
 
+#if FF_API_AVFILTERBUFFER
     /**
-     * Do not copy buffer data.
+     * Ignored
      */
     AV_BUFFERSRC_FLAG_NO_COPY = 2,
+#endif
 
     /**
      * Immediately push the frame to the output.
      */
     AV_BUFFERSRC_FLAG_PUSH = 4,
 
+    /**
+     * Keep a reference to the frame.
+     * If the frame if reference-counted, create a new reference; otherwise
+     * copy the frame data.
+     */
+    AV_BUFFERSRC_FLAG_KEEP_REF = 8,
+
 };
 
 /**
@@ -91,6 +100,9 @@ int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf);
  * copied.
  *
  * @return 0 on success, a negative AVERROR on error
+ *
+ * This function is equivalent to av_buffersrc_add_frame_flags() with the
+ * AV_BUFFERSRC_FLAG_KEEP_REF flag.
  */
 int av_buffersrc_write_frame(AVFilterContext *s, const AVFrame *frame);
 
@@ -108,11 +120,20 @@ int av_buffersrc_write_frame(AVFilterContext *s, const AVFrame *frame);
  * @note the difference between this function and av_buffersrc_write_frame() is
  * that av_buffersrc_write_frame() creates a new reference to the input frame,
  * while this function takes ownership of the reference passed to it.
+ *
+ * This function is equivalent to av_buffersrc_add_frame_flags() without the
+ * AV_BUFFERSRC_FLAG_KEEP_REF flag.
  */
 int av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame);
 
 /**
- * Add frame data to buffer_src. XXX
+ * Add a frame to the buffer source.
+ *
+ * By default, if the frame is reference-counted, this function will take
+ * ownership of the reference(s) and reset the frame. This can be controled
+ * using the flags.
+ *
+ * If this function returns an error, the input frame is not touched.
  *
  * @param buffer_src  pointer to a buffer source context
  * @param frame       a frame, or NULL to mark EOF