[FFmpeg-devel] [PATCH 1/5] lavfi: add filter metaframes infrastructure.

Nicolas George george at nsup.org
Sun Aug 3 15:15:36 CEST 2014


Metaframes are frames without data, identified by a negative
format code, used to carry special conditions.
They are sent only to filter that declare supporting them.

The only metaframe for now is EOF; this mechanism augments
the current mechanism based on request_frame() returning
AVERROR_EOF, with the advantage that the EOF metaframe carries
a timestamp.
The API has also the advantage to work in push-only mode if
all the filters in the chain support metaframes.

The metaframes are a purely internal API and do not leak to
the application.

Signed-off-by: Nicolas George <george at nsup.org>
---
 libavfilter/avfilter.c | 73 +++++++++++++++++++++++++++++++++++++++++++++-----
 libavfilter/internal.h | 34 +++++++++++++++++++++++
 2 files changed, 100 insertions(+), 7 deletions(-)


TODO: find a way of forwarding the EOF, and hopefully the timestamp for
filters that do not support metaframes. Possibly triggering a request_frame
on filters that have exactly one output would help.


diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 7b11467..d3fbe56 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -346,15 +346,16 @@ int ff_request_frame(AVFilterLink *link)
             ret = link->srcpad->request_frame(link);
         else if (link->src->inputs[0])
             ret = ff_request_frame(link->src->inputs[0]);
-        if (ret == AVERROR_EOF && link->partial_buf) {
-            AVFrame *pbuf = link->partial_buf;
-            link->partial_buf = NULL;
-            ret = ff_filter_frame_framed(link, pbuf);
-        }
         if (ret < 0) {
+            if (!link->frame_requested) {
+                av_assert0(ret == AVERROR_EOF);
+                ret = 0;
+            }
             link->frame_requested = 0;
-            if (ret == AVERROR_EOF)
-                link->closed = 1;
+            if (ret == AVERROR_EOF) {
+                ret = ff_filter_link_close(link, AV_NOPTS_VALUE);
+                return ret < 0 ? ret : AVERROR_EOF;
+            }
         } else {
             av_assert0(!link->frame_requested ||
                        link->flags & FF_LINK_FLAG_REQUEST_LOOP);
@@ -1132,10 +1133,52 @@ static int ff_filter_frame_needs_framing(AVFilterLink *link, AVFrame *frame)
     return ret;
 }
 
+static int ff_filter_metaframe(AVFilterLink *link, AVFrame *frame)
+{
+    AVFrame *pbuf = link->partial_buf;
+    int ret = 0;
+
+    if (pbuf) {
+        link->partial_buf = NULL;
+        if ((ret = ff_filter_frame_framed(link, pbuf)) < 0)
+            return ret;
+    }
+
+    if ((link->dst->filter->flags & FF_FILTER_FLAG_SUPPORT_METAFRAMES)) {
+        ret = link->dstpad->filter_frame ?
+              link->dstpad->filter_frame(link, frame) :
+              default_filter_frame(link, frame);
+        if (ret < 0)
+            return ret;
+    }
+
+    switch (frame->format) {
+
+    case FF_METAFRAME_EOF:
+        link->closed = 1;
+        break;
+
+    case 0:
+    case FF_METAFRAME_NOP:
+        /* Not implemented yet because not used either for now.
+           Caveat: if the same metaframe is forwarded to the next filter
+           and the next filter changes the type, the type change must not be
+           taken into account for the first link. */
+
+    default:
+        av_assert0(!"reached");
+    }
+
+    return ret;
+}
+
 int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
 {
     FF_TPRINTF_START(NULL, filter_frame); ff_tlog_link(NULL, link, 1); ff_tlog(NULL, " "); ff_tlog_ref(NULL, frame, 1);
 
+    if (frame->format < -1)
+        return ff_filter_metaframe(link, frame);
+
     /* Consistency checks */
     if (link->type == AVMEDIA_TYPE_VIDEO) {
         if (strcmp(link->dst->filter->name, "scale")) {
@@ -1162,6 +1205,22 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
     }
 }
 
+int ff_filter_link_close(AVFilterLink *link, int64_t pts)
+{
+    AVFrame *frame;
+    int ret;
+
+    if (link->closed)
+        return 0;
+    if (!(frame = av_frame_alloc()))
+        return AVERROR(ENOMEM);
+    frame->format = FF_METAFRAME_EOF;
+    frame->pts = pts;
+    ret = ff_filter_frame(link, frame);
+    av_frame_free(&frame);
+    return ret;
+}
+
 const AVClass *avfilter_get_class(void)
 {
     return &avfilter_class;
diff --git a/libavfilter/internal.h b/libavfilter/internal.h
index 308b115..fbe603a 100644
--- a/libavfilter/internal.h
+++ b/libavfilter/internal.h
@@ -374,4 +374,38 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name);
  */
 void ff_filter_graph_remove_filter(AVFilterGraph *graph, AVFilterContext *filter);
 
+/**
+ * The filter can accept metaframes.
+ * Metaframes are AVFrame structures with a negative format field.
+ * The framework will take default actions based on the metaframe type.
+ * The destination filter is allowed to reset the type to inhibit the
+ * default actions.
+ */
+#define FF_FILTER_FLAG_SUPPORT_METAFRAMES (1 << 24)
+
+/**
+ * Types of metaframes that can be passer to a filter.
+ */
+enum {
+    /**
+     * Do not do anything.
+     * Can be used by the destination filter to inhibit default handling.
+     */
+    FF_METAFRAME_NOP = -1,
+
+    /**
+     * The input has reached EOF.
+     * The pts field holds the timestamp of the end of the stream,
+     * therefore allowing to compute the duration of the last frame.
+     * The frame structure still belongs to the framework and must not be
+     * stored by the destination filter; it also may be incomplete.
+     */
+    FF_METAFRAME_EOF = AVERROR_EOF,
+};
+
+/**
+ * Close the link by sending the EOF metaframes to the destination filter.
+ */
+int ff_filter_link_close(AVFilterLink *link, int64_t pts);
+
 #endif /* AVFILTER_INTERNAL_H */
-- 
2.0.1



More information about the ffmpeg-devel mailing list