Browse code

lavfi: support automatically inserting the fifo filter when needed.

This breaks libavfilter ABI.

Anton Khirnov authored on 2012/05/16 16:19:46
Showing 6 changed files
... ...
@@ -4,7 +4,7 @@ since the last major version increase.
4 4
 The last version increases were:
5 5
 libavcodec:    2012-01-27
6 6
 libavdevice:   2011-04-18
7
-libavfilter:   2011-04-18
7
+libavfilter:   2012-06-22
8 8
 libavformat:   2012-01-27
9 9
 libavresample: 2012-04-24
10 10
 libswscale:    2011-06-20
... ...
@@ -363,6 +363,14 @@ struct AVFilterPad {
363 363
      * and another value on error.
364 364
      */
365 365
     int (*config_props)(AVFilterLink *link);
366
+
367
+    /**
368
+     * The filter expects a fifo to be inserted on its input link,
369
+     * typically because it has a delay.
370
+     *
371
+     * input pads only.
372
+     */
373
+    int needs_fifo;
366 374
 };
367 375
 #endif
368 376
 
... ...
@@ -591,12 +591,52 @@ static int graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx)
591 591
     return 0;
592 592
 }
593 593
 
594
+static int graph_insert_fifos(AVFilterGraph *graph, AVClass *log_ctx)
595
+{
596
+    AVFilterContext *f;
597
+    int i, j, ret;
598
+    int fifo_count = 0;
599
+
600
+    for (i = 0; i < graph->filter_count; i++) {
601
+        f = graph->filters[i];
602
+
603
+        for (j = 0; j < f->nb_inputs; j++) {
604
+            AVFilterLink *link = f->inputs[j];
605
+            AVFilterContext *fifo_ctx;
606
+            AVFilter *fifo;
607
+            char name[32];
608
+
609
+            if (!link->dstpad->needs_fifo)
610
+                continue;
611
+
612
+            fifo = f->inputs[j]->type == AVMEDIA_TYPE_VIDEO ?
613
+                   avfilter_get_by_name("fifo") :
614
+                   avfilter_get_by_name("afifo");
615
+
616
+            snprintf(name, sizeof(name), "auto-inserted fifo %d", fifo_count++);
617
+
618
+            ret = avfilter_graph_create_filter(&fifo_ctx, fifo, name, NULL,
619
+                                               NULL, graph);
620
+            if (ret < 0)
621
+                return ret;
622
+
623
+            ret = avfilter_insert_filter(link, fifo_ctx, 0, 0);
624
+            if (ret < 0)
625
+                return ret;
626
+        }
627
+    }
628
+
629
+    return 0;
630
+}
631
+
594 632
 int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx)
595 633
 {
596 634
     int ret;
597 635
 
598 636
     if ((ret = graph_check_validity(graphctx, log_ctx)))
599 637
         return ret;
638
+    if ((ret = graph_insert_fifos(graphctx, log_ctx)) < 0)
639
+        return ret;
600 640
     if ((ret = graph_config_formats(graphctx, log_ctx)))
601 641
         return ret;
602 642
     if ((ret = graph_config_links(graphctx, log_ctx)))
... ...
@@ -25,7 +25,7 @@
25 25
 
26 26
 #include "libavutil/audio_fifo.h"
27 27
 #include "libavutil/audioconvert.h"
28
-#include "libavutil/fifo.h"
28
+#include "libavutil/avassert.h"
29 29
 #include "libavutil/mathematics.h"
30 30
 
31 31
 #include "audio.h"
... ...
@@ -34,86 +34,45 @@
34 34
 #include "internal.h"
35 35
 
36 36
 typedef struct {
37
-    AVFifoBuffer *fifo;          ///< FIFO buffer of frame references
38
-
37
+    AVFilterBufferRef *cur_buf;  ///< last buffer delivered on the sink
39 38
     AVAudioFifo  *audio_fifo;    ///< FIFO for audio samples
40 39
     int64_t next_pts;            ///< interpolating audio pts
41 40
 } BufferSinkContext;
42 41
 
43
-#define FIFO_INIT_SIZE 8
44
-
45 42
 static av_cold void uninit(AVFilterContext *ctx)
46 43
 {
47 44
     BufferSinkContext *sink = ctx->priv;
48 45
 
49
-    while (sink->fifo && av_fifo_size(sink->fifo)) {
50
-        AVFilterBufferRef *buf;
51
-        av_fifo_generic_read(sink->fifo, &buf, sizeof(buf), NULL);
52
-        avfilter_unref_buffer(buf);
53
-    }
54
-    av_fifo_free(sink->fifo);
55
-
56 46
     if (sink->audio_fifo)
57 47
         av_audio_fifo_free(sink->audio_fifo);
58 48
 }
59 49
 
60
-static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
61
-{
62
-    BufferSinkContext *sink = ctx->priv;
63
-
64
-    if (!(sink->fifo = av_fifo_alloc(FIFO_INIT_SIZE*sizeof(AVFilterBufferRef*)))) {
65
-        av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo\n");
66
-        return AVERROR(ENOMEM);
67
-    }
68
-
69
-    return 0;
70
-}
71
-
72
-static void write_buf(AVFilterContext *ctx, AVFilterBufferRef *buf)
50
+static void start_frame(AVFilterLink *link, AVFilterBufferRef *buf)
73 51
 {
74
-    BufferSinkContext *sink = ctx->priv;
75
-
76
-    if (av_fifo_space(sink->fifo) < sizeof(AVFilterBufferRef *) &&
77
-        (av_fifo_realloc2(sink->fifo, av_fifo_size(sink->fifo) * 2) < 0)) {
78
-            av_log(ctx, AV_LOG_ERROR, "Error reallocating the FIFO.\n");
79
-            return;
80
-    }
52
+    BufferSinkContext *s = link->dst->priv;
81 53
 
82
-    av_fifo_generic_write(sink->fifo, &buf, sizeof(buf), NULL);
83
-}
84
-
85
-static void end_frame(AVFilterLink *link)
86
-{
87
-    write_buf(link->dst, link->cur_buf);
54
+    av_assert0(!s->cur_buf);
55
+    s->cur_buf    = buf;
88 56
     link->cur_buf = NULL;
89
-}
90
-
91
-static void filter_samples(AVFilterLink *link, AVFilterBufferRef *buf)
92
-{
93
-    write_buf(link->dst, buf);
94
-}
57
+};
95 58
 
96 59
 int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf)
97 60
 {
98
-    BufferSinkContext *sink = ctx->priv;
61
+    BufferSinkContext *s    = ctx->priv;
99 62
     AVFilterLink      *link = ctx->inputs[0];
100 63
     int ret;
101 64
 
102
-    if (!buf) {
103
-        if (av_fifo_size(sink->fifo))
104
-            return av_fifo_size(sink->fifo)/sizeof(*buf);
105
-        else
106
-            return ff_poll_frame(ctx->inputs[0]);
107
-    }
65
+    if (!buf)
66
+        return ff_poll_frame(ctx->inputs[0]);
108 67
 
109
-    if (!av_fifo_size(sink->fifo) &&
110
-        (ret = ff_request_frame(link)) < 0)
68
+    if ((ret = ff_request_frame(link)) < 0)
111 69
         return ret;
112 70
 
113
-    if (!av_fifo_size(sink->fifo))
71
+    if (!s->cur_buf)
114 72
         return AVERROR(EINVAL);
115 73
 
116
-    av_fifo_generic_read(sink->fifo, buf, sizeof(*buf), NULL);
74
+    *buf       = s->cur_buf;
75
+    s->cur_buf = NULL;
117 76
 
118 77
     return 0;
119 78
 }
... ...
@@ -182,13 +141,13 @@ AVFilter avfilter_vsink_buffer = {
182 182
     .name      = "buffersink",
183 183
     .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
184 184
     .priv_size = sizeof(BufferSinkContext),
185
-    .init      = init,
186 185
     .uninit    = uninit,
187 186
 
188 187
     .inputs    = (AVFilterPad[]) {{ .name          = "default",
189 188
                                     .type          = AVMEDIA_TYPE_VIDEO,
190
-                                    .end_frame     = end_frame,
191
-                                    .min_perms     = AV_PERM_READ, },
189
+                                    .start_frame   = start_frame,
190
+                                    .min_perms     = AV_PERM_READ,
191
+                                    .needs_fifo    = 1 },
192 192
                                   { .name = NULL }},
193 193
     .outputs   = (AVFilterPad[]) {{ .name = NULL }},
194 194
 };
... ...
@@ -197,13 +156,13 @@ AVFilter avfilter_asink_abuffer = {
197 197
     .name      = "abuffersink",
198 198
     .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
199 199
     .priv_size = sizeof(BufferSinkContext),
200
-    .init      = init,
201 200
     .uninit    = uninit,
202 201
 
203 202
     .inputs    = (AVFilterPad[]) {{ .name           = "default",
204 203
                                     .type           = AVMEDIA_TYPE_AUDIO,
205
-                                    .filter_samples = filter_samples,
206
-                                    .min_perms      = AV_PERM_READ, },
204
+                                    .filter_samples = start_frame,
205
+                                    .min_perms      = AV_PERM_READ,
206
+                                    .needs_fifo     = 1 },
207 207
                                   { .name = NULL }},
208 208
     .outputs   = (AVFilterPad[]) {{ .name = NULL }},
209 209
 };
... ...
@@ -149,6 +149,14 @@ struct AVFilterPad {
149 149
      * and another value on error.
150 150
      */
151 151
     int (*config_props)(AVFilterLink *link);
152
+
153
+    /**
154
+     * The filter expects a fifo to be inserted on its input link,
155
+     * typically because it has a delay.
156
+     *
157
+     * input pads only.
158
+     */
159
+    int needs_fifo;
152 160
 };
153 161
 #endif
154 162
 
... ...
@@ -28,8 +28,8 @@
28 28
 
29 29
 #include "libavutil/avutil.h"
30 30
 
31
-#define LIBAVFILTER_VERSION_MAJOR  2
32
-#define LIBAVFILTER_VERSION_MINOR  23
31
+#define LIBAVFILTER_VERSION_MAJOR  3
32
+#define LIBAVFILTER_VERSION_MINOR  0
33 33
 #define LIBAVFILTER_VERSION_MICRO  0
34 34
 
35 35
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \