History

lavfi: add asrc_abuffer - audio buffer source

Originally based on code by Stefano Sabatini and S. N. Hemanth.

Mina Nagy Zaki committed 15 years ago

Commit 587c8ab1 parent f138c7f7 files · +495 −1Browse files

Unified · Split

7 files
  1. configure +1 −0
  2. doc/filters.texi +45 −0
  3. libavfilter/Makefile +1 −0
  4. libavfilter/allfilters.c +1 −0
  5. libavfilter/asrc_abuffer.c +366 −0
  6. libavfilter/asrc_abuffer.h +80 −0
  7. libavfilter/avfilter.h +1 −1
configure+1−0
@@ -1501,6 +1501,7 @@ tcp_protocol_deps="network" · 1500 unmodified lines
15011501 udp_protocol_deps="network"
15021502
15031503 # filters
1504+abuffer="strtok_r"
15041505 aformat_filter_deps="strtok_r"
15051506 blackframe_filter_deps="gpl"
15061507 boxblur_filter_deps="gpl"
doc/filters.texi+45−0
@@ -194,6 +194,51 @@ Adler-32 checksum for each input frame plane, expressed in the form · 193 unmodified lines
194194
195195 Below is a description of the currently available audio sources.
196196
197+@section abuffer
198+
199+Buffer audio frames, and make them available to the filter chain.
200+
201+This source is mainly intended for a programmatic use, in particular
202+through the interface defined in @file{libavfilter/asrc_abuffer.h}.
203+
204+It accepts the following mandatory parameters:
205+@var{sample_rate}:@var{sample_fmt}:@var{channel_layout}:@var{packing}
206+
207+@table @option
208+
209+@item sample_rate
210+The sample rate of the incoming audio buffers.
211+
212+@item sample_fmt
213+The sample format of the incoming audio buffers.
214+Either a sample format name or its corresponging integer representation from
215+the enum AVSampleFormat in @file{libavutil/samplefmt.h}
216+
217+@item channel_layout
218+The channel layout of the incoming audio buffers.
219+Either a channel layout name from channel_layout_map in
220+@file{libavutil/audioconvert.c} or its corresponding integer representation
221+from the AV_CH_LAYOUT_* macros in @file{libavutil/audioconvert.h}
222+
223+@item packing
224+Either "packed" or "planar", or their integer representation: 0 or 1
225+respectively.
226+
227+@end table
228+
229+For example:
230+@example
231+abuffer=44100:s16:stereo:planar
232+@end example
233+
234+will instruct the source to accept planar 16bit signed stereo at 44100Hz.
235+Since the sample format with name "s16" corresponds to the number
236+1 and the "stereo" channel layout corresponds to the value 3, this is
237+equivalent to:
238+@example
239+abuffer=44100:1:3:1
240+@end example
241+
197242 @section anullsrc
198243
199244 Null audio source, never return audio frames. It is mainly useful as a
libavfilter/Makefile+1−0
@@ -24,6 +24,7 @@ OBJS-$(CONFIG_ANULL_FILTER) += af_anull.o · 23 unmodified lines
2424 OBJS-$(CONFIG_ARESAMPLE_FILTER) += af_aresample.o
2525 OBJS-$(CONFIG_ASHOWINFO_FILTER) += af_ashowinfo.o
2626
27+OBJS-$(CONFIG_ABUFFER_FILTER) += asrc_abuffer.o
2728 OBJS-$(CONFIG_ANULLSRC_FILTER) += asrc_anullsrc.o
2829
2930 OBJS-$(CONFIG_ABUFFERSINK_FILTER) += asink_abuffer.o
libavfilter/allfilters.c+1−0
@@ -39,6 +39,7 @@ void avfilter_register_all(void) · 38 unmodified lines
3939 REGISTER_FILTER (ARESAMPLE, aresample, af);
4040 REGISTER_FILTER (ASHOWINFO, ashowinfo, af);
4141
42+ REGISTER_FILTER (ABUFFER, abuffer, asrc);
4243 REGISTER_FILTER (ANULLSRC, anullsrc, asrc);
4344
4445 REGISTER_FILTER (ABUFFERSINK, abuffersink, asink);
libavfilter/asrc_abuffer.c+366−0
@@ -0,0 +1,366 @@
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:%"PRId64" -> %s:%s:%u, normalizing\n",
129+ av_get_sample_fmt_name(link->format),
130+ old_layout_str, 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 *args, void *opaque)
253+{
254+ ABufferSourceContext *abuffer = ctx->priv;
255+ char *arg = NULL, *ptr, chlayout_str[16];
256+ int ret;
257+
258+ arg = strtok_r(args, ":", &ptr);
259+
260+#define ADD_FORMAT(fmt_name) \
261+ if (!arg) \
262+ goto arg_fail; \
263+ if ((ret = ff_parse_##fmt_name(&abuffer->fmt_name, arg, ctx)) < 0) \
264+ return ret; \
265+ if (*args) \
266+ arg = strtok_r(NULL, ":", &ptr)
267+
268+ ADD_FORMAT(sample_rate);
269+ ADD_FORMAT(sample_format);
270+ ADD_FORMAT(channel_layout);
271+ ADD_FORMAT(packing_format);
272+
273+ abuffer->fifo = av_fifo_alloc(FIFO_SIZE*sizeof(AVFilterBufferRef*));
274+ if (!abuffer->fifo) {
275+ av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo, filter init failed.\n");
276+ return AVERROR(ENOMEM);
277+ }
278+
279+ av_get_channel_layout_string(chlayout_str, sizeof(chlayout_str),
280+ -1, abuffer->channel_layout);
281+ av_log(ctx, AV_LOG_INFO, "format:%s layout:%s rate:%d\n",
282+ av_get_sample_fmt_name(abuffer->sample_format), chlayout_str,
283+ abuffer->sample_rate);
284+
285+ return 0;
286+
287+arg_fail:
288+ av_log(ctx, AV_LOG_ERROR, "Invalid arguments, must be of the form "
289+ "sample_rate:sample_fmt:channel_layout:packing\n");
290+ return AVERROR(EINVAL);
291+}
292+
293+static av_cold void uninit(AVFilterContext *ctx)
294+{
295+ ABufferSourceContext *abuffer = ctx->priv;
296+ av_fifo_free(abuffer->fifo);
297+}
298+
299+static int query_formats(AVFilterContext *ctx)
300+{
301+ ABufferSourceContext *abuffer = ctx->priv;
302+ AVFilterFormats *formats;
303+
304+ formats = NULL;
305+ avfilter_add_format(&formats, abuffer->sample_format);
306+ avfilter_set_common_sample_formats(ctx, formats);
307+
308+ formats = NULL;
309+ avfilter_add_format(&formats, abuffer->channel_layout);
310+ avfilter_set_common_channel_layouts(ctx, formats);
311+
312+ formats = NULL;
313+ avfilter_add_format(&formats, abuffer->packing_format);
314+ avfilter_set_common_packing_formats(ctx, formats);
315+
316+ return 0;
317+}
318+
319+static int config_output(AVFilterLink *outlink)
320+{
321+ ABufferSourceContext *abuffer = outlink->src->priv;
322+ outlink->sample_rate = abuffer->sample_rate;
323+ return 0;
324+}
325+
326+static int request_frame(AVFilterLink *outlink)
327+{
328+ ABufferSourceContext *abuffer = outlink->src->priv;
329+ AVFilterBufferRef *samplesref;
330+
331+ if (!av_fifo_size(abuffer->fifo)) {
332+ av_log(outlink->src, AV_LOG_ERROR,
333+ "request_frame() called with no available frames!\n");
334+ return AVERROR(EINVAL);
335+ }
336+
337+ av_fifo_generic_read(abuffer->fifo, &samplesref, sizeof(samplesref), NULL);
338+ avfilter_filter_samples(outlink, avfilter_ref_buffer(samplesref, ~0));
339+ avfilter_unref_buffer(samplesref);
340+
341+ return 0;
342+}
343+
344+static int poll_frame(AVFilterLink *outlink)
345+{
346+ ABufferSourceContext *abuffer = outlink->src->priv;
347+ return av_fifo_size(abuffer->fifo)/sizeof(AVFilterBufferRef*);
348+}
349+
350+AVFilter avfilter_asrc_abuffer = {
351+ .name = "abuffer",
352+ .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them accessible to the filterchain."),
353+ .priv_size = sizeof(ABufferSourceContext),
354+ .query_formats = query_formats,
355+
356+ .init = init,
357+ .uninit = uninit,
358+
359+ .inputs = (AVFilterPad[]) {{ .name = NULL }},
360+ .outputs = (AVFilterPad[]) {{ .name = "default",
361+ .type = AVMEDIA_TYPE_AUDIO,
362+ .request_frame = request_frame,
363+ .poll_frame = poll_frame,
364+ .config_props = config_output, },
365+ { .name = NULL}},
366+};
libavfilter/asrc_abuffer.h+80−0
@@ -0,0 +1,80 @@
1+/*
2+ * This file is part of FFmpeg.
3+ *
4+ * FFmpeg is free software; you can redistribute it and/or
5+ * modify it under the terms of the GNU Lesser General Public
6+ * License as published by the Free Software Foundation; either
7+ * version 2.1 of the License, or (at your option) any later version.
8+ *
9+ * FFmpeg is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+ * Lesser General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU Lesser General Public
15+ * License along with FFmpeg; if not, write to the Free Software
16+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17+ */
18+
19+#ifndef AVFILTER_ASRC_ABUFFER_H
20+#define AVFILTER_ASRC_ABUFFER_H
21+
22+#include "avfilter.h"
23+
24+/**
25+ * @file
26+ * memory buffer source for audio
27+ */
28+
29+/**
30+ * Queue an audio buffer to the audio buffer source.
31+ *
32+ * @param abuffersrc audio source buffer context
33+ * @param data pointers to the samples planes
34+ * @param linesize linesizes of each audio buffer plane
35+ * @param nb_samples number of samples per channel
36+ * @param sample_fmt sample format of the audio data
37+ * @param ch_layout channel layout of the audio data
38+ * @param planar flag to indicate if audio data is planar or packed
39+ * @param pts presentation timestamp of the audio buffer
40+ * @param flags unused
41+ */
42+int av_asrc_buffer_add_samples(AVFilterContext *abuffersrc,
43+ uint8_t *data[8], int linesize[8],
44+ int nb_samples, int sample_rate,
45+ int sample_fmt, int64_t ch_layout, int planar,
46+ int64_t pts, int av_unused flags);
47+
48+/**
49+ * Queue an audio buffer to the audio buffer source.
50+ *
51+ * This is similar to av_asrc_buffer_add_samples(), but the samples
52+ * are stored in a buffer with known size.
53+ *
54+ * @param abuffersrc audio source buffer context
55+ * @param buf pointer to the samples data, packed is assumed
56+ * @param size the size in bytes of the buffer, it must contain an
57+ * integer number of samples
58+ * @param sample_fmt sample format of the audio data
59+ * @param ch_layout channel layout of the audio data
60+ * @param pts presentation timestamp of the audio buffer
61+ * @param flags unused
62+ */
63+int av_asrc_buffer_add_buffer(AVFilterContext *abuffersrc,
64+ uint8_t *buf, int buf_size,
65+ int sample_rate,
66+ int sample_fmt, int64_t ch_layout, int planar,
67+ int64_t pts, int av_unused flags);
68+
69+/**
70+ * Queue an audio buffer to the audio buffer source.
71+ *
72+ * @param abuffersrc audio source buffer context
73+ * @param samplesref buffer ref to queue
74+ * @param flags unused
75+ */
76+int av_asrc_buffer_add_audio_buffer_ref(AVFilterContext *abuffersrc,
77+ AVFilterBufferRef *samplesref,
78+ int av_unused flags);
79+
80+#endif /* AVFILTER_ASRC_ABUFFER_H */
libavfilter/avfilter.h+1−1
@@ -29,7 +29,7 @@ · 28 unmodified lines
2929 #include "libavutil/rational.h"
3030
3131 #define LIBAVFILTER_VERSION_MAJOR 2
32−#define LIBAVFILTER_VERSION_MINOR 33
32+#define LIBAVFILTER_VERSION_MINOR 34
3333 #define LIBAVFILTER_VERSION_MICRO 0
3434
3535 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t