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