Browse code

lavfi: add an audio buffer source.

Anton Khirnov authored on 2012/05/05 01:57:04
Showing 3 changed files
... ...
@@ -151,6 +151,33 @@ anullsrc=48000:4
151 151
 anullsrc=48000:mono
152 152
 @end example
153 153
 
154
+@section abuffer
155
+Buffer audio frames, and make them available to the filter chain.
156
+
157
+This source is not intended to be part of user-supplied graph descriptions but
158
+for insertion by calling programs through the interface defined in
159
+@file{libavfilter/buffersrc.h}.
160
+
161
+It accepts the following named parameters:
162
+@table @option
163
+
164
+@item time_base
165
+Timebase which will be used for timestamps of submitted frames. It must be
166
+either a floating-point number or in @var{numerator}/@var{denominator} form.
167
+
168
+@item sample_rate
169
+Audio sample rate.
170
+
171
+@item sample_fmt
172
+Name of the sample format, as returned by @code{av_get_sample_fmt_name()}.
173
+
174
+@item channel_layout
175
+Channel layout of the audio data, in the form that can be accepted by
176
+@code{av_get_channel_layout()}.
177
+@end table
178
+
179
+All the parameters need to be explicitly defined.
180
+
154 181
 @c man end AUDIO SOURCES
155 182
 
156 183
 @chapter Audio Sinks
... ...
@@ -96,6 +96,10 @@ void avfilter_register_all(void)
96 96
         avfilter_register(&avfilter_vsrc_buffer);
97 97
     }
98 98
     {
99
+        extern AVFilter avfilter_asrc_abuffer;
100
+        avfilter_register(&avfilter_asrc_abuffer);
101
+    }
102
+    {
99 103
         extern AVFilter avfilter_vsink_buffer;
100 104
         avfilter_register(&avfilter_vsink_buffer);
101 105
     }
... ...
@@ -23,27 +23,51 @@
23 23
  * memory buffer source filter
24 24
  */
25 25
 
26
+#include "audio.h"
26 27
 #include "avfilter.h"
27 28
 #include "buffersrc.h"
29
+#include "formats.h"
28 30
 #include "vsrc_buffer.h"
31
+
32
+#include "libavutil/audioconvert.h"
29 33
 #include "libavutil/fifo.h"
30 34
 #include "libavutil/imgutils.h"
35
+#include "libavutil/opt.h"
36
+#include "libavutil/samplefmt.h"
31 37
 
32 38
 typedef struct {
39
+    const AVClass    *class;
33 40
     AVFifoBuffer     *fifo;
41
+    AVRational        time_base;     ///< time_base to set in the output link
42
+
43
+    /* video only */
34 44
     int               h, w;
35 45
     enum PixelFormat  pix_fmt;
36
-    AVRational        time_base;     ///< time_base to set in the output link
37 46
     AVRational        pixel_aspect;
47
+
48
+    /* audio only */
49
+    int sample_rate;
50
+    enum AVSampleFormat sample_fmt;
51
+    char               *sample_fmt_str;
52
+    uint64_t channel_layout;
53
+    char    *channel_layout_str;
54
+
38 55
     int eof;
39 56
 } BufferSourceContext;
40 57
 
41
-#define CHECK_PARAM_CHANGE(s, c, width, height, format)\
58
+#define CHECK_VIDEO_PARAM_CHANGE(s, c, width, height, format)\
42 59
     if (c->w != width || c->h != height || c->pix_fmt != format) {\
43 60
         av_log(s, AV_LOG_ERROR, "Changing frame properties on the fly is not supported.\n");\
44 61
         return AVERROR(EINVAL);\
45 62
     }
46 63
 
64
+#define CHECK_AUDIO_PARAM_CHANGE(s, c, srate, ch_layout, format)\
65
+    if (c->sample_fmt != format || c->sample_rate != srate ||\
66
+        c->channel_layout != ch_layout) {\
67
+        av_log(s, AV_LOG_ERROR, "Changing frame properties on the fly is not supported.\n");\
68
+        return AVERROR(EINVAL);\
69
+    }
70
+
47 71
 #if FF_API_VSRC_BUFFER_ADD_FRAME
48 72
 int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame,
49 73
                              int64_t pts, AVRational pixel_aspect)
... ...
@@ -80,12 +104,28 @@ int av_buffersrc_write_frame(AVFilterContext *buffer_filter, AVFrame *frame)
80 80
                                          sizeof(buf))) < 0)
81 81
         return ret;
82 82
 
83
-    CHECK_PARAM_CHANGE(buffer_filter, c, frame->width, frame->height, frame->format);
84
-
85
-    buf = avfilter_get_video_buffer(buffer_filter->outputs[0], AV_PERM_WRITE,
86
-                                    c->w, c->h);
87
-    av_image_copy(buf->data, buf->linesize, frame->data, frame->linesize,
88
-                  c->pix_fmt, c->w, c->h);
83
+    switch (buffer_filter->outputs[0]->type) {
84
+    case AVMEDIA_TYPE_VIDEO:
85
+        CHECK_VIDEO_PARAM_CHANGE(buffer_filter, c, frame->width, frame->height,
86
+                                 frame->format);
87
+        buf = avfilter_get_video_buffer(buffer_filter->outputs[0], AV_PERM_WRITE,
88
+                                        c->w, c->h);
89
+        av_image_copy(buf->data, buf->linesize, frame->data, frame->linesize,
90
+                      c->pix_fmt, c->w, c->h);
91
+        break;
92
+    case AVMEDIA_TYPE_AUDIO:
93
+        CHECK_AUDIO_PARAM_CHANGE(buffer_filter, c, frame->sample_rate, frame->channel_layout,
94
+                                 frame->format);
95
+        buf = ff_get_audio_buffer(buffer_filter->outputs[0], AV_PERM_WRITE,
96
+                                  frame->nb_samples);
97
+        av_samples_copy(buf->extended_data, frame->extended_data,
98
+                        0, 0, frame->nb_samples,
99
+                        av_get_channel_layout_nb_channels(frame->channel_layout),
100
+                        frame->format);
101
+        break;
102
+    default:
103
+        return AVERROR(EINVAL);
104
+    }
89 105
 
90 106
     avfilter_copy_frame_props(buf, frame);
91 107
 
... ...
@@ -113,7 +153,17 @@ int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf)
113 113
                                          sizeof(buf))) < 0)
114 114
         return ret;
115 115
 
116
-    CHECK_PARAM_CHANGE(s, c, buf->video->w, buf->video->h, buf->format);
116
+    switch (s->outputs[0]->type) {
117
+    case AVMEDIA_TYPE_VIDEO:
118
+        CHECK_VIDEO_PARAM_CHANGE(s, c, buf->video->w, buf->video->h, buf->format);
119
+        break;
120
+    case AVMEDIA_TYPE_AUDIO:
121
+        CHECK_AUDIO_PARAM_CHANGE(s, c, buf->audio->sample_rate, buf->audio->channel_layout,
122
+                                 buf->format);
123
+        break;
124
+    default:
125
+        return AVERROR(EINVAL);
126
+    }
117 127
 
118 128
     if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0)
119 129
         return ret;
... ...
@@ -121,7 +171,7 @@ int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf)
121 121
     return 0;
122 122
 }
123 123
 
124
-static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
124
+static av_cold int init_video(AVFilterContext *ctx, const char *args, void *opaque)
125 125
 {
126 126
     BufferSourceContext *c = ctx->priv;
127 127
     char pix_fmt_str[128];
... ...
@@ -150,6 +200,69 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
150 150
     return 0;
151 151
 }
152 152
 
153
+#define OFFSET(x) offsetof(BufferSourceContext, x)
154
+#define A AV_OPT_FLAG_AUDIO_PARAM
155
+static const AVOption audio_options[] = {
156
+    { "time_base",      NULL, OFFSET(time_base),           AV_OPT_TYPE_RATIONAL, { 0 }, 0, INT_MAX, A },
157
+    { "sample_rate",    NULL, OFFSET(sample_rate),         AV_OPT_TYPE_INT,      { 0 }, 0, INT_MAX, A },
158
+    { "sample_fmt",     NULL, OFFSET(sample_fmt_str),      AV_OPT_TYPE_STRING,             .flags = A },
159
+    { "channel_layout", NULL, OFFSET(channel_layout_str),  AV_OPT_TYPE_STRING,             .flags = A },
160
+    { NULL },
161
+};
162
+
163
+static const AVClass abuffer_class = {
164
+    .class_name = "abuffer source",
165
+    .item_name  = av_default_item_name,
166
+    .option     = audio_options,
167
+    .version    = LIBAVUTIL_VERSION_INT,
168
+};
169
+
170
+static av_cold int init_audio(AVFilterContext *ctx, const char *args, void *opaque)
171
+{
172
+    BufferSourceContext *s = ctx->priv;
173
+    int ret = 0;
174
+
175
+    s->class = &abuffer_class;
176
+    av_opt_set_defaults(s);
177
+
178
+    if ((ret = av_set_options_string(s, args, "=", ":")) < 0) {
179
+        av_log(ctx, AV_LOG_ERROR, "Error parsing options string: %s.\n", args);
180
+        goto fail;
181
+    }
182
+
183
+    s->sample_fmt = av_get_sample_fmt(s->sample_fmt_str);
184
+    if (s->sample_fmt == AV_SAMPLE_FMT_NONE) {
185
+        av_log(ctx, AV_LOG_ERROR, "Invalid sample format %s.\n",
186
+               s->sample_fmt_str);
187
+        ret = AVERROR(EINVAL);
188
+        goto fail;
189
+    }
190
+
191
+    s->channel_layout = av_get_channel_layout(s->channel_layout_str);
192
+    if (!s->channel_layout) {
193
+        av_log(ctx, AV_LOG_ERROR, "Invalid channel layout %s.\n",
194
+               s->channel_layout_str);
195
+        ret = AVERROR(EINVAL);
196
+        goto fail;
197
+    }
198
+
199
+    if (!(s->fifo = av_fifo_alloc(sizeof(AVFilterBufferRef*)))) {
200
+        ret = AVERROR(ENOMEM);
201
+        goto fail;
202
+    }
203
+
204
+    if (!s->time_base.num)
205
+        s->time_base = (AVRational){1, s->sample_rate};
206
+
207
+    av_log(ctx, AV_LOG_VERBOSE, "tb:%d/%d samplefmt:%s samplerate: %d "
208
+           "ch layout:%s\n", s->time_base.num, s->time_base.den, s->sample_fmt_str,
209
+           s->sample_rate, s->channel_layout_str);
210
+
211
+fail:
212
+    av_opt_free(s);
213
+    return ret;
214
+}
215
+
153 216
 static av_cold void uninit(AVFilterContext *ctx)
154 217
 {
155 218
     BufferSourceContext *s = ctx->priv;
... ...
@@ -165,9 +278,29 @@ static av_cold void uninit(AVFilterContext *ctx)
165 165
 static int query_formats(AVFilterContext *ctx)
166 166
 {
167 167
     BufferSourceContext *c = ctx->priv;
168
-    enum PixelFormat pix_fmts[] = { c->pix_fmt, PIX_FMT_NONE };
168
+    AVFilterChannelLayouts *channel_layouts = NULL;
169
+    AVFilterFormats *formats = NULL;
170
+    AVFilterFormats *samplerates = NULL;
171
+
172
+    switch (ctx->outputs[0]->type) {
173
+    case AVMEDIA_TYPE_VIDEO:
174
+        avfilter_add_format(&formats, c->pix_fmt);
175
+        avfilter_set_common_formats(ctx, formats);
176
+        break;
177
+    case AVMEDIA_TYPE_AUDIO:
178
+        avfilter_add_format(&formats,           c->sample_fmt);
179
+        avfilter_set_common_formats(ctx, formats);
180
+
181
+        avfilter_add_format(&samplerates,       c->sample_rate);
182
+        ff_set_common_samplerates(ctx, samplerates);
183
+
184
+        ff_add_channel_layout(&channel_layouts, c->channel_layout);
185
+        ff_set_common_channel_layouts(ctx, channel_layouts);
186
+        break;
187
+    default:
188
+        return AVERROR(EINVAL);
189
+    }
169 190
 
170
-    avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts));
171 191
     return 0;
172 192
 }
173 193
 
... ...
@@ -175,11 +308,21 @@ static int config_props(AVFilterLink *link)
175 175
 {
176 176
     BufferSourceContext *c = link->src->priv;
177 177
 
178
-    link->w = c->w;
179
-    link->h = c->h;
180
-    link->sample_aspect_ratio = c->pixel_aspect;
181
-    link->time_base = c->time_base;
178
+    switch (link->type) {
179
+    case AVMEDIA_TYPE_VIDEO:
180
+        link->w = c->w;
181
+        link->h = c->h;
182
+        link->sample_aspect_ratio = c->pixel_aspect;
183
+        break;
184
+    case AVMEDIA_TYPE_AUDIO:
185
+        link->channel_layout = c->channel_layout;
186
+        link->sample_rate    = c->sample_rate;
187
+        break;
188
+    default:
189
+        return AVERROR(EINVAL);
190
+    }
182 191
 
192
+    link->time_base = c->time_base;
183 193
     return 0;
184 194
 }
185 195
 
... ...
@@ -195,9 +338,19 @@ static int request_frame(AVFilterLink *link)
195 195
     }
196 196
     av_fifo_generic_read(c->fifo, &buf, sizeof(buf), NULL);
197 197
 
198
-    avfilter_start_frame(link, avfilter_ref_buffer(buf, ~0));
199
-    avfilter_draw_slice(link, 0, link->h, 1);
200
-    avfilter_end_frame(link);
198
+    switch (link->type) {
199
+    case AVMEDIA_TYPE_VIDEO:
200
+        avfilter_start_frame(link, avfilter_ref_buffer(buf, ~0));
201
+        avfilter_draw_slice(link, 0, link->h, 1);
202
+        avfilter_end_frame(link);
203
+        break;
204
+    case AVMEDIA_TYPE_AUDIO:
205
+        ff_filter_samples(link, avfilter_ref_buffer(buf, ~0));
206
+        break;
207
+    default:
208
+        return AVERROR(EINVAL);
209
+    }
210
+
201 211
     avfilter_unref_buffer(buf);
202 212
 
203 213
     return 0;
... ...
@@ -218,7 +371,7 @@ AVFilter avfilter_vsrc_buffer = {
218 218
     .priv_size = sizeof(BufferSourceContext),
219 219
     .query_formats = query_formats,
220 220
 
221
-    .init      = init,
221
+    .init      = init_video,
222 222
     .uninit    = uninit,
223 223
 
224 224
     .inputs    = (AVFilterPad[]) {{ .name = NULL }},
... ...
@@ -229,3 +382,21 @@ AVFilter avfilter_vsrc_buffer = {
229 229
                                     .config_props    = config_props, },
230 230
                                   { .name = NULL}},
231 231
 };
232
+
233
+AVFilter avfilter_asrc_abuffer = {
234
+    .name          = "abuffer",
235
+    .description   = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them accessible to the filterchain."),
236
+    .priv_size     = sizeof(BufferSourceContext),
237
+    .query_formats = query_formats,
238
+
239
+    .init      = init_audio,
240
+    .uninit    = uninit,
241
+
242
+    .inputs    = (AVFilterPad[]) {{ .name = NULL }},
243
+    .outputs   = (AVFilterPad[]) {{ .name            = "default",
244
+                                    .type            = AVMEDIA_TYPE_AUDIO,
245
+                                    .request_frame   = request_frame,
246
+                                    .poll_frame      = poll_frame,
247
+                                    .config_props    = config_props, },
248
+                                  { .name = NULL}},
249
+};