]> git.sesse.net Git - ffmpeg/blob - libavfilter/asrc_abuffer.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libavfilter / asrc_abuffer.c
1 /*
2  * Copyright (c) 2010 S.N. Hemanth Meenakshisundaram
3  * Copyright (c) 2011 Mina Nagy Zaki
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 /**
23  * @file
24  * memory buffer source for audio
25  */
26
27 #include "libavutil/audioconvert.h"
28 #include "libavutil/fifo.h"
29 #include "asrc_abuffer.h"
30 #include "internal.h"
31
32 typedef struct {
33     // Audio format of incoming buffers
34     int sample_rate;
35     unsigned int sample_format;
36     int64_t channel_layout;
37     int packing_format;
38
39     // FIFO buffer of audio buffer ref pointers
40     AVFifoBuffer *fifo;
41
42     // Normalization filters
43     AVFilterContext *aconvert;
44     AVFilterContext *aresample;
45 } ABufferSourceContext;
46
47 #define FIFO_SIZE 8
48
49 static void buf_free(AVFilterBuffer *ptr)
50 {
51     av_free(ptr);
52     return;
53 }
54
55 static void set_link_source(AVFilterContext *src, AVFilterLink *link)
56 {
57     link->src       = src;
58     link->srcpad    = &(src->output_pads[0]);
59     src->outputs[0] = link;
60 }
61
62 static int reconfigure_filter(ABufferSourceContext *abuffer, AVFilterContext *filt_ctx)
63 {
64     int ret;
65     AVFilterLink * const inlink  = filt_ctx->inputs[0];
66     AVFilterLink * const outlink = filt_ctx->outputs[0];
67
68     inlink->format         = abuffer->sample_format;
69     inlink->channel_layout = abuffer->channel_layout;
70     inlink->planar         = abuffer->packing_format;
71     inlink->sample_rate    = abuffer->sample_rate;
72
73     filt_ctx->filter->uninit(filt_ctx);
74     memset(filt_ctx->priv, 0, filt_ctx->filter->priv_size);
75     if ((ret = filt_ctx->filter->init(filt_ctx, NULL , NULL)) < 0)
76         return ret;
77     if ((ret = inlink->srcpad->config_props(inlink)) < 0)
78         return ret;
79     return outlink->srcpad->config_props(outlink);
80 }
81
82 static int insert_filter(ABufferSourceContext *abuffer,
83                          AVFilterLink *link, AVFilterContext **filt_ctx,
84                          const char *filt_name)
85 {
86     int ret;
87
88     if ((ret = avfilter_open(filt_ctx, avfilter_get_by_name(filt_name), NULL)) < 0)
89         return ret;
90
91     link->src->outputs[0] = NULL;
92     if ((ret = avfilter_link(link->src, 0, *filt_ctx, 0)) < 0) {
93         link->src->outputs[0] = link;
94         return ret;
95     }
96
97     set_link_source(*filt_ctx, link);
98
99     if ((ret = reconfigure_filter(abuffer, *filt_ctx)) < 0) {
100         avfilter_free(*filt_ctx);
101         return ret;
102     }
103
104     return 0;
105 }
106
107 static void remove_filter(AVFilterContext **filt_ctx)
108 {
109     AVFilterLink *outlink = (*filt_ctx)->outputs[0];
110     AVFilterContext *src  = (*filt_ctx)->inputs[0]->src;
111
112     (*filt_ctx)->outputs[0] = NULL;
113     avfilter_free(*filt_ctx);
114     *filt_ctx = NULL;
115
116     set_link_source(src, outlink);
117 }
118
119 static inline void log_input_change(void *ctx, AVFilterLink *link, AVFilterBufferRef *ref)
120 {
121     char old_layout_str[16], new_layout_str[16];
122     av_get_channel_layout_string(old_layout_str, sizeof(old_layout_str),
123                                  -1, link->channel_layout);
124     av_get_channel_layout_string(new_layout_str, sizeof(new_layout_str),
125                                  -1, ref->audio->channel_layout);
126     av_log(ctx, AV_LOG_INFO,
127            "Audio input format changed: "
128            "%s:%s:%d -> %s:%s:%d, normalizing\n",
129            av_get_sample_fmt_name(link->format),
130            old_layout_str, (int)link->sample_rate,
131            av_get_sample_fmt_name(ref->format),
132            new_layout_str, ref->audio->sample_rate);
133 }
134
135 int av_asrc_buffer_add_audio_buffer_ref(AVFilterContext *ctx,
136                                         AVFilterBufferRef *samplesref,
137                                         int av_unused flags)
138 {
139     ABufferSourceContext *abuffer = ctx->priv;
140     AVFilterLink *link;
141     int ret, logged = 0;
142
143     if (av_fifo_space(abuffer->fifo) < sizeof(samplesref)) {
144         av_log(ctx, AV_LOG_ERROR,
145                "Buffering limit reached. Please consume some available frames "
146                "before adding new ones.\n");
147         return AVERROR(EINVAL);
148     }
149
150     // Normalize input
151
152     link = ctx->outputs[0];
153     if (samplesref->audio->sample_rate != link->sample_rate) {
154
155         log_input_change(ctx, link, samplesref);
156         logged = 1;
157
158         abuffer->sample_rate = samplesref->audio->sample_rate;
159
160         if (!abuffer->aresample) {
161             ret = insert_filter(abuffer, link, &abuffer->aresample, "aresample");
162             if (ret < 0) return ret;
163         } else {
164             link = abuffer->aresample->outputs[0];
165             if (samplesref->audio->sample_rate == link->sample_rate)
166                 remove_filter(&abuffer->aresample);
167             else
168                 if ((ret = reconfigure_filter(abuffer, abuffer->aresample)) < 0)
169                     return ret;
170         }
171     }
172
173     link = ctx->outputs[0];
174     if (samplesref->format                != link->format         ||
175         samplesref->audio->channel_layout != link->channel_layout ||
176         samplesref->audio->planar         != link->planar) {
177
178         if (!logged) log_input_change(ctx, link, samplesref);
179
180         abuffer->sample_format  = samplesref->format;
181         abuffer->channel_layout = samplesref->audio->channel_layout;
182         abuffer->packing_format = samplesref->audio->planar;
183
184         if (!abuffer->aconvert) {
185             ret = insert_filter(abuffer, link, &abuffer->aconvert, "aconvert");
186             if (ret < 0) return ret;
187         } else {
188             link = abuffer->aconvert->outputs[0];
189             if (samplesref->format                == link->format         &&
190                 samplesref->audio->channel_layout == link->channel_layout &&
191                 samplesref->audio->planar         == link->planar
192                )
193                 remove_filter(&abuffer->aconvert);
194             else
195                 if ((ret = reconfigure_filter(abuffer, abuffer->aconvert)) < 0)
196                     return ret;
197         }
198     }
199
200     if (sizeof(samplesref) != av_fifo_generic_write(abuffer->fifo, &samplesref,
201                                                     sizeof(samplesref), NULL)) {
202         av_log(ctx, AV_LOG_ERROR, "Error while writing to FIFO\n");
203         return AVERROR(EINVAL);
204     }
205
206     return 0;
207 }
208
209 int av_asrc_buffer_add_samples(AVFilterContext *ctx,
210                                uint8_t *data[8], int linesize[8],
211                                int nb_samples, int sample_rate,
212                                int sample_fmt, int64_t channel_layout, int planar,
213                                int64_t pts, int av_unused flags)
214 {
215     AVFilterBufferRef *samplesref;
216
217     samplesref = avfilter_get_audio_buffer_ref_from_arrays(
218                      data, linesize, AV_PERM_WRITE,
219                      nb_samples,
220                      sample_fmt, channel_layout, planar);
221     if (!samplesref)
222         return AVERROR(ENOMEM);
223
224     samplesref->buf->free  = buf_free;
225     samplesref->pts = pts;
226     samplesref->audio->sample_rate = sample_rate;
227
228     return av_asrc_buffer_add_audio_buffer_ref(ctx, samplesref, 0);
229 }
230
231 int av_asrc_buffer_add_buffer(AVFilterContext *ctx,
232                               uint8_t *buf, int buf_size, int sample_rate,
233                               int sample_fmt, int64_t channel_layout, int planar,
234                               int64_t pts, int av_unused flags)
235 {
236     uint8_t *data[8];
237     int linesize[8];
238     int nb_channels = av_get_channel_layout_nb_channels(channel_layout),
239         nb_samples  = buf_size / nb_channels / av_get_bytes_per_sample(sample_fmt);
240
241     av_samples_fill_arrays(data, linesize,
242                            buf, nb_channels, nb_samples,
243                            sample_fmt, planar, 16);
244
245     return av_asrc_buffer_add_samples(ctx,
246                                       data, linesize, nb_samples,
247                                       sample_rate,
248                                       sample_fmt, channel_layout, planar,
249                                       pts, flags);
250 }
251
252 static av_cold int init(AVFilterContext *ctx, const char *args0, void *opaque)
253 {
254     ABufferSourceContext *abuffer = ctx->priv;
255     char *arg = NULL, *ptr, chlayout_str[16];
256     char *args = av_strdup(args0);
257     int ret;
258
259     arg = strtok_r(args, ":", &ptr);
260
261 #define ADD_FORMAT(fmt_name)                                            \
262     if (!arg)                                                           \
263         goto arg_fail;                                                  \
264     if ((ret = ff_parse_##fmt_name(&abuffer->fmt_name, arg, ctx)) < 0) { \
265         av_freep(&args);                                                \
266         return ret;                                                     \
267     }                                                                   \
268     if (*args)                                                          \
269         arg = strtok_r(NULL, ":", &ptr)
270
271     ADD_FORMAT(sample_rate);
272     ADD_FORMAT(sample_format);
273     ADD_FORMAT(channel_layout);
274     ADD_FORMAT(packing_format);
275
276     abuffer->fifo = av_fifo_alloc(FIFO_SIZE*sizeof(AVFilterBufferRef*));
277     if (!abuffer->fifo) {
278         av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo, filter init failed.\n");
279         return AVERROR(ENOMEM);
280     }
281
282     av_get_channel_layout_string(chlayout_str, sizeof(chlayout_str),
283                                  -1, abuffer->channel_layout);
284     av_log(ctx, AV_LOG_INFO, "format:%s layout:%s rate:%d\n",
285            av_get_sample_fmt_name(abuffer->sample_format), chlayout_str,
286            abuffer->sample_rate);
287     av_freep(&args);
288
289     return 0;
290
291 arg_fail:
292     av_log(ctx, AV_LOG_ERROR, "Invalid arguments, must be of the form "
293                               "sample_rate:sample_fmt:channel_layout:packing\n");
294     av_freep(&args);
295     return AVERROR(EINVAL);
296 }
297
298 static av_cold void uninit(AVFilterContext *ctx)
299 {
300     ABufferSourceContext *abuffer = ctx->priv;
301     av_fifo_free(abuffer->fifo);
302 }
303
304 static int query_formats(AVFilterContext *ctx)
305 {
306     ABufferSourceContext *abuffer = ctx->priv;
307     AVFilterFormats *formats;
308
309     formats = NULL;
310     avfilter_add_format(&formats, abuffer->sample_format);
311     avfilter_set_common_sample_formats(ctx, formats);
312
313     formats = NULL;
314     avfilter_add_format(&formats, abuffer->channel_layout);
315     avfilter_set_common_channel_layouts(ctx, formats);
316
317     formats = NULL;
318     avfilter_add_format(&formats, abuffer->packing_format);
319     avfilter_set_common_packing_formats(ctx, formats);
320
321     return 0;
322 }
323
324 static int config_output(AVFilterLink *outlink)
325 {
326     ABufferSourceContext *abuffer = outlink->src->priv;
327     outlink->sample_rate = abuffer->sample_rate;
328     return 0;
329 }
330
331 static int request_frame(AVFilterLink *outlink)
332 {
333     ABufferSourceContext *abuffer = outlink->src->priv;
334     AVFilterBufferRef *samplesref;
335
336     if (!av_fifo_size(abuffer->fifo)) {
337         av_log(outlink->src, AV_LOG_ERROR,
338                "request_frame() called with no available frames!\n");
339         return AVERROR(EINVAL);
340     }
341
342     av_fifo_generic_read(abuffer->fifo, &samplesref, sizeof(samplesref), NULL);
343     avfilter_filter_samples(outlink, avfilter_ref_buffer(samplesref, ~0));
344     avfilter_unref_buffer(samplesref);
345
346     return 0;
347 }
348
349 static int poll_frame(AVFilterLink *outlink)
350 {
351     ABufferSourceContext *abuffer = outlink->src->priv;
352     return av_fifo_size(abuffer->fifo)/sizeof(AVFilterBufferRef*);
353 }
354
355 AVFilter avfilter_asrc_abuffer = {
356     .name        = "abuffer",
357     .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them accessible to the filterchain."),
358     .priv_size   = sizeof(ABufferSourceContext),
359     .query_formats = query_formats,
360
361     .init        = init,
362     .uninit      = uninit,
363
364     .inputs      = (AVFilterPad[]) {{ .name = NULL }},
365     .outputs     = (AVFilterPad[]) {{ .name            = "default",
366                                       .type            = AVMEDIA_TYPE_AUDIO,
367                                       .request_frame   = request_frame,
368                                       .poll_frame      = poll_frame,
369                                       .config_props    = config_output, },
370                                     { .name = NULL}},
371 };