History

lavfi: add audio convert filter

Add aconvert filter to perform sample format, channel layout, and packing format conversion. The aconvert code depends on audio conversion code in libavcodec, so this requires a dependency on libavcodec. Based on previous work by S.N. Hemanth Meenakshisundaram and Mina Nagy Zaki, performed for the GSoC 2010 and 2011.

Stefano Sabatini committed 15 years ago

Commit 37cc4431 parent 553c5e98 files · +632 −1Browse files

Unified · Split

8 files
  1. Changelog +1 −0
  2. configure +1 −0
  3. doc/filters.texi +36 −0
  4. libavfilter/Makefile +3 −0
  5. libavfilter/af_aconvert.c +417 −0
  6. libavfilter/af_aconvert_rematrix.c +172 −0
  7. libavfilter/allfilters.c +1 −0
  8. libavfilter/avfilter.h +1 −1
Changelog+1−0
@@ -55,6 +55,7 @@ easier to use. The changes are: · 54 unmodified lines
5555 - H.264 Decoding on Android via Stagefright
5656 - Prores decoder
5757 - BIN/XBIN/ADF/IDF text file decoder
58+- aconvert audio filter added
5859
5960
6061 version 0.8:
configure+1−0
@@ -1575,6 +1575,7 @@ udp_protocol_deps="network" · 1574 unmodified lines
15751575
15761576 # filters
15771577 abuffer_filter_deps="strtok_r"
1578+aconvert_filter_deps="strtok_r"
15781579 aformat_filter_deps="strtok_r"
15791580 amovie_filter_deps="avcodec avformat"
15801581 blackframe_filter_deps="gpl"
doc/filters.texi+36−0
@@ -99,6 +99,42 @@ build. · 98 unmodified lines
9999
100100 Below is a description of the currently available audio filters.
101101
102+@section aconvert
103+
104+Convert the input audio format to the specified formats.
105+
106+The filter accepts a string of the form:
107+"@var{sample_format}:@var{channel_layout}:@var{packing_format}".
108+
109+@var{sample_format} specifies the sample format, and can be a string or
110+the corresponding numeric value defined in @file{libavutil/samplefmt.h}.
111+
112+@var{channel_layout} specifies the channel layout, and can be a string
113+or the corresponding numer value defined in @file{libavutil/chlayout.h}.
114+
115+@var{packing_format} specifies the type of packing in output, can be one
116+of "planar" or "packed", or the corresponding numeric values "0" or "1".
117+
118+The special parameter "auto", signifies that the filter will
119+automatically select the output format depending on the output filter.
120+
121+Some examples follow.
122+
123+@itemize
124+@item
125+Convert input to unsigned 8-bit, stereo, packed:
126+@example
127+aconvert=u8:stereo:packed
128+@end example
129+
130+@item
131+Convert input to unsigned 8-bit, automatically select out channel layout
132+and packing format:
133+@example
134+aconvert=u8:auto:auto
135+@end example
136+@end itemize
137+
102138 @section aformat
103139
104140 Convert the input audio to one of the specified formats. The framework will
libavfilter/Makefile+3−0
@@ -2,6 +2,8 @@ include $(SUBDIR)../config.mak · 1 unmodified line
22
33 NAME = avfilter
44 FFLIBS = avutil
5+
6+FFLIBS-$(CONFIG_ACONVERT_FILTER) += avcodec
57 FFLIBS-$(CONFIG_AMOVIE_FILTER) += avformat avcodec
68 FFLIBS-$(CONFIG_ARESAMPLE_FILTER) += avcodec
79 FFLIBS-$(CONFIG_MOVIE_FILTER) += avformat avcodec
@@ -20,6 +22,7 @@ OBJS = allfilters.o \ · 12 unmodified lines
2022
2123 OBJS-$(CONFIG_AVCODEC) += avcodec.o
2224
25+OBJS-$(CONFIG_ACONVERT_FILTER) += af_aconvert.o
2326 OBJS-$(CONFIG_AFORMAT_FILTER) += af_aformat.o
2427 OBJS-$(CONFIG_ANULL_FILTER) += af_anull.o
2528 OBJS-$(CONFIG_ARESAMPLE_FILTER) += af_aresample.o
libavfilter/af_aconvert.c+417−0
@@ -0,0 +1,417 @@
1+/*
2+ * Copyright (c) 2010 S.N. Hemanth Meenakshisundaram <smeenaks@ucsd.edu>
3+ * Copyright (c) 2011 Stefano Sabatini
4+ * Copyright (c) 2011 Mina Nagy Zaki
5+ *
6+ * This file is part of FFmpeg.
7+ *
8+ * FFmpeg is free software; you can redistribute it and/or
9+ * modify it under the terms of the GNU Lesser General Public
10+ * License as published by the Free Software Foundation; either
11+ * version 2.1 of the License, or (at your option) any later version.
12+ *
13+ * FFmpeg is distributed in the hope that it will be useful,
14+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+ * Lesser General Public License for more details.
17+ *
18+ * You should have received a copy of the GNU Lesser General Public
19+ * License along with FFmpeg; if not, write to the Free Software
20+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21+ */
22+
23+/**
24+ * @file
25+ * sample format and channel layout conversion audio filter
26+ * based on code in libavcodec/resample.c by Fabrice Bellard and
27+ * libavcodec/audioconvert.c by Michael Niedermayer
28+ */
29+
30+#include "libavutil/audioconvert.h"
31+#include "libavcodec/audioconvert.h"
32+#include "avfilter.h"
33+#include "internal.h"
34+
35+typedef struct {
36+ enum AVSampleFormat out_sample_fmt, in_sample_fmt; ///< in/out sample formats
37+ int64_t out_chlayout, in_chlayout; ///< in/out channel layout
38+ int out_nb_channels, in_nb_channels; ///< number of in/output channels
39+ enum AVFilterPacking out_packing_fmt, in_packing_fmt; ///< output packing format
40+
41+ int max_nb_samples; ///< maximum number of buffered samples
42+ AVFilterBufferRef *mix_samplesref; ///< rematrixed buffer
43+ AVFilterBufferRef *out_samplesref; ///< output buffer after required conversions
44+
45+ uint8_t *in_mix[8], *out_mix[8]; ///< input/output for rematrixing functions
46+ uint8_t *packed_data[8]; ///< pointers for packing conversion
47+ int out_strides[8], in_strides[8]; ///< input/output strides for av_audio_convert
48+ uint8_t **in_conv, **out_conv; ///< input/output for av_audio_convert
49+
50+ AVAudioConvert *audioconvert_ctx; ///< context for conversion to output sample format
51+
52+ void (*convert_chlayout)(); ///< function to do the requested rematrixing
53+} AConvertContext;
54+
55+#define REMATRIX_FUNC_SIG(NAME) static void REMATRIX_FUNC_NAME(NAME) \
56+ (FMT_TYPE *outp[], FMT_TYPE *inp[], int nb_samples, AConvertContext *aconvert)
57+
58+#define FMT_TYPE uint8_t
59+#define REMATRIX_FUNC_NAME(NAME) NAME ## _u8
60+#include "af_aconvert_rematrix.c"
61+
62+#define FMT_TYPE int16_t
63+#define REMATRIX_FUNC_NAME(NAME) NAME ## _s16
64+#include "af_aconvert_rematrix.c"
65+
66+#define FMT_TYPE int32_t
67+#define REMATRIX_FUNC_NAME(NAME) NAME ## _s32
68+#include "af_aconvert_rematrix.c"
69+
70+#define FLOATING
71+
72+#define FMT_TYPE float
73+#define REMATRIX_FUNC_NAME(NAME) NAME ## _flt
74+#include "af_aconvert_rematrix.c"
75+
76+#define FMT_TYPE double
77+#define REMATRIX_FUNC_NAME(NAME) NAME ## _dbl
78+#include "af_aconvert_rematrix.c"
79+
80+#define FMT_TYPE uint8_t
81+#define REMATRIX_FUNC_NAME(NAME) NAME
82+REMATRIX_FUNC_SIG(stereo_remix_planar)
83+{
84+ int size = av_get_bytes_per_sample(aconvert->in_sample_fmt) * nb_samples;
85+
86+ memcpy(outp[0], inp[0], size);
87+ memcpy(outp[1], inp[aconvert->in_nb_channels == 1 ? 0 : 1], size);
88+}
89+
90+#define REGISTER_FUNC_PACKING(INCHLAYOUT, OUTCHLAYOUT, FUNC, PACKING) \
91+ {INCHLAYOUT, OUTCHLAYOUT, PACKING, AV_SAMPLE_FMT_U8, FUNC##_u8}, \
92+ {INCHLAYOUT, OUTCHLAYOUT, PACKING, AV_SAMPLE_FMT_S16, FUNC##_s16}, \
93+ {INCHLAYOUT, OUTCHLAYOUT, PACKING, AV_SAMPLE_FMT_S32, FUNC##_s32}, \
94+ {INCHLAYOUT, OUTCHLAYOUT, PACKING, AV_SAMPLE_FMT_FLT, FUNC##_flt}, \
95+ {INCHLAYOUT, OUTCHLAYOUT, PACKING, AV_SAMPLE_FMT_DBL, FUNC##_dbl},
96+
97+#define REGISTER_FUNC(INCHLAYOUT, OUTCHLAYOUT, FUNC) \
98+ REGISTER_FUNC_PACKING(INCHLAYOUT, OUTCHLAYOUT, FUNC##_packed, AVFILTER_PACKED) \
99+ REGISTER_FUNC_PACKING(INCHLAYOUT, OUTCHLAYOUT, FUNC##_planar, AVFILTER_PLANAR)
100+
101+static struct RematrixFunctionInfo {
102+ int64_t in_chlayout, out_chlayout;
103+ int planar, sfmt;
104+ void (*func)();
105+} rematrix_funcs[] = {
106+ REGISTER_FUNC (AV_CH_LAYOUT_STEREO, AV_CH_LAYOUT_5POINT1, stereo_to_surround_5p1)
107+ REGISTER_FUNC (AV_CH_LAYOUT_5POINT1, AV_CH_LAYOUT_STEREO, surround_5p1_to_stereo)
108+ REGISTER_FUNC_PACKING(AV_CH_LAYOUT_STEREO, AV_CH_LAYOUT_MONO, stereo_to_mono_packed, AVFILTER_PACKED)
109+ REGISTER_FUNC_PACKING(AV_CH_LAYOUT_MONO, AV_CH_LAYOUT_STEREO, mono_to_stereo_packed, AVFILTER_PACKED)
110+ REGISTER_FUNC (0, AV_CH_LAYOUT_MONO, mono_downmix)
111+ REGISTER_FUNC_PACKING(0, AV_CH_LAYOUT_STEREO, stereo_downmix_packed, AVFILTER_PACKED)
112+
113+ // This function works for all sample formats
114+ {0, AV_CH_LAYOUT_STEREO, AVFILTER_PLANAR, -1, stereo_remix_planar}
115+};
116+
117+static av_cold int init(AVFilterContext *ctx, const char *args0, void *opaque)
118+{
119+ AConvertContext *aconvert = ctx->priv;
120+ char *arg, *ptr = NULL;
121+ int ret = 0;
122+ char *args = av_strdup(args0);
123+
124+ aconvert->out_sample_fmt = AV_SAMPLE_FMT_NONE;
125+ aconvert->out_chlayout = 0;
126+ aconvert->out_packing_fmt = -1;
127+
128+ if ((arg = strtok_r(args, ":", &ptr)) && strcmp(arg, "auto")) {
129+ if ((ret = ff_parse_sample_format(&aconvert->out_sample_fmt, arg, ctx)) < 0)
130+ goto end;
131+ }
132+ if ((arg = strtok_r(NULL, ":", &ptr)) && strcmp(arg, "auto")) {
133+ if ((ret = ff_parse_channel_layout(&aconvert->out_chlayout, arg, ctx)) < 0)
134+ goto end;
135+ }
136+ if ((arg = strtok_r(NULL, ":", &ptr)) && strcmp(arg, "auto")) {
137+ if ((ret = ff_parse_packing_format((int *)&aconvert->out_packing_fmt, arg, ctx)) < 0)
138+ goto end;
139+ }
140+
141+end:
142+ av_freep(&args);
143+ return ret;
144+}
145+
146+static av_cold void uninit(AVFilterContext *ctx)
147+{
148+ AConvertContext *aconvert = ctx->priv;
149+ avfilter_unref_buffer(aconvert->mix_samplesref);
150+ avfilter_unref_buffer(aconvert->out_samplesref);
151+ if (aconvert->audioconvert_ctx)
152+ av_audio_convert_free(aconvert->audioconvert_ctx);
153+}
154+
155+static int query_formats(AVFilterContext *ctx)
156+{
157+ AVFilterFormats *formats = NULL;
158+ AConvertContext *aconvert = ctx->priv;
159+ AVFilterLink *inlink = ctx->inputs[0];
160+ AVFilterLink *outlink = ctx->outputs[0];
161+
162+ avfilter_formats_ref(avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO),
163+ &inlink->out_formats);
164+ if (aconvert->out_sample_fmt != AV_SAMPLE_FMT_NONE) {
165+ formats = NULL;
166+ avfilter_add_format(&formats, aconvert->out_sample_fmt);
167+ avfilter_formats_ref(formats, &outlink->in_formats);
168+ } else
169+ avfilter_formats_ref(avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO),
170+ &outlink->in_formats);
171+
172+ avfilter_formats_ref(avfilter_make_all_channel_layouts(),
173+ &inlink->out_chlayouts);
174+ if (aconvert->out_chlayout != 0) {
175+ formats = NULL;
176+ avfilter_add_format(&formats, aconvert->out_chlayout);
177+ avfilter_formats_ref(formats, &outlink->in_chlayouts);
178+ } else
179+ avfilter_formats_ref(avfilter_make_all_channel_layouts(),
180+ &outlink->in_chlayouts);
181+
182+ avfilter_formats_ref(avfilter_make_all_packing_formats(),
183+ &inlink->out_packing);
184+ if (aconvert->out_packing_fmt != -1) {
185+ formats = NULL;
186+ avfilter_add_format(&formats, aconvert->out_packing_fmt);
187+ avfilter_formats_ref(formats, &outlink->in_packing);
188+ } else
189+ avfilter_formats_ref(avfilter_make_all_packing_formats(),
190+ &outlink->in_packing);
191+
192+ return 0;
193+}
194+
195+static int config_output(AVFilterLink *outlink)
196+{
197+ AVFilterLink *inlink = outlink->src->inputs[0];
198+ AConvertContext *aconvert = outlink->src->priv;
199+ char buf1[64], buf2[64];
200+
201+ aconvert->in_sample_fmt = inlink->format;
202+ aconvert->in_packing_fmt = inlink->planar;
203+ if (aconvert->out_packing_fmt == -1)
204+ aconvert->out_packing_fmt = outlink->planar;
205+ aconvert->in_chlayout = inlink->channel_layout;
206+ aconvert->in_nb_channels =
207+ av_get_channel_layout_nb_channels(inlink->channel_layout);
208+
209+ /* if not specified in args, use the format and layout of the output */
210+ if (aconvert->out_sample_fmt == AV_SAMPLE_FMT_NONE)
211+ aconvert->out_sample_fmt = outlink->format;
212+ if (aconvert->out_chlayout == 0)
213+ aconvert->out_chlayout = outlink->channel_layout;
214+ aconvert->out_nb_channels =
215+ av_get_channel_layout_nb_channels(outlink->channel_layout);
216+
217+ av_get_channel_layout_string(buf1, sizeof(buf1),
218+ -1, inlink ->channel_layout);
219+ av_get_channel_layout_string(buf2, sizeof(buf2),
220+ -1, outlink->channel_layout);
221+ av_log(outlink->src, AV_LOG_INFO,
222+ "fmt:%s cl:%s planar:%i -> fmt:%s cl:%s planar:%i\n",
223+ av_get_sample_fmt_name(inlink ->format), buf1, inlink ->planar,
224+ av_get_sample_fmt_name(outlink->format), buf2, outlink->planar);
225+
226+ /* compute which channel layout conversion to use */
227+ if (inlink->channel_layout != outlink->channel_layout) {
228+ int i;
229+ for (i = 0; i < sizeof(rematrix_funcs); i++) {
230+ const struct RematrixFunctionInfo *f = &rematrix_funcs[i];
231+ if ((f->in_chlayout == 0 || f->in_chlayout == inlink ->channel_layout) &&
232+ (f->out_chlayout == 0 || f->out_chlayout == outlink->channel_layout) &&
233+ (f->planar == -1 || f->planar == inlink->planar) &&
234+ (f->sfmt == -1 || f->sfmt == inlink->format)
235+ ) {
236+ aconvert->convert_chlayout = f->func;
237+ break;
238+ }
239+ }
240+ if (!aconvert->convert_chlayout) {
241+ av_log(outlink->src, AV_LOG_ERROR,
242+ "Unsupported channel layout conversion '%s -> %s' requested!\n",
243+ buf1, buf2);
244+ return AVERROR(EINVAL);
245+ }
246+ }
247+
248+ return 0;
249+}
250+
251+static int init_buffers(AVFilterLink *inlink, int nb_samples)
252+{
253+ AConvertContext *aconvert = inlink->dst->priv;
254+ AVFilterLink * const outlink = inlink->dst->outputs[0];
255+ int i, packed_stride = 0;
256+ const unsigned
257+ packing_conv = inlink->planar != outlink->planar &&
258+ aconvert->out_nb_channels != 1,
259+ format_conv = inlink->format != outlink->format;
260+ int nb_channels = aconvert->out_nb_channels;
261+
262+ uninit(inlink->dst);
263+ aconvert->max_nb_samples = nb_samples;
264+
265+ if (aconvert->convert_chlayout) {
266+ /* allocate buffer for storing intermediary mixing samplesref */
267+ uint8_t *data[8];
268+ int linesize[8];
269+ int nb_channels = av_get_channel_layout_nb_channels(outlink->channel_layout);
270+
271+ if (av_samples_alloc(data, linesize, nb_channels, nb_samples,
272+ inlink->format, inlink->planar, 16) < 0)
273+ goto fail_no_mem;
274+ aconvert->mix_samplesref =
275+ avfilter_get_audio_buffer_ref_from_arrays(data, linesize, AV_PERM_WRITE,
276+ nb_samples, inlink->format,
277+ outlink->channel_layout,
278+ inlink->planar);
279+ if (!aconvert->mix_samplesref)
280+ goto fail_no_mem;
281+ }
282+
283+ // if there's a format/packing conversion we need an audio_convert context
284+ if (format_conv || packing_conv) {
285+ aconvert->out_samplesref =
286+ avfilter_get_audio_buffer(outlink, AV_PERM_WRITE, nb_samples);
287+ if (!aconvert->out_samplesref)
288+ goto fail_no_mem;
289+
290+ aconvert->in_strides [0] = av_get_bytes_per_sample(inlink ->format);
291+ aconvert->out_strides[0] = av_get_bytes_per_sample(outlink->format);
292+
293+ aconvert->out_conv = aconvert->out_samplesref->data;
294+ if (aconvert->mix_samplesref)
295+ aconvert->in_conv = aconvert->mix_samplesref->data;
296+
297+ if (packing_conv) {
298+ // packed -> planar
299+ if (outlink->planar == AVFILTER_PLANAR) {
300+ if (aconvert->mix_samplesref)
301+ aconvert->packed_data[0] = aconvert->mix_samplesref->data[0];
302+ aconvert->in_conv = aconvert->packed_data;
303+ packed_stride = aconvert->in_strides[0];
304+ aconvert->in_strides[0] *= nb_channels;
305+ // planar -> packed
306+ } else {
307+ aconvert->packed_data[0] = aconvert->out_samplesref->data[0];
308+ aconvert->out_conv = aconvert->packed_data;
309+ packed_stride = aconvert->out_strides[0];
310+ aconvert->out_strides[0] *= nb_channels;
311+ }
312+ } else if (outlink->planar == AVFILTER_PACKED) {
313+ /* If there's no packing conversion, and the stream is packed
314+ * then we treat the entire stream as one big channel
315+ */
316+ nb_channels = 1;
317+ }
318+
319+ for (i = 1; i < nb_channels; i++) {
320+ aconvert->packed_data[i] = aconvert->packed_data[i-1] + packed_stride;
321+ aconvert->in_strides[i] = aconvert->in_strides[0];
322+ aconvert->out_strides[i] = aconvert->out_strides[0];
323+ }
324+
325+ aconvert->audioconvert_ctx =
326+ av_audio_convert_alloc(outlink->format, nb_channels,
327+ inlink->format, nb_channels, NULL, 0);
328+ if (!aconvert->audioconvert_ctx)
329+ goto fail_no_mem;
330+ }
331+
332+ return 0;
333+
334+fail_no_mem:
335+ av_log(inlink->dst, AV_LOG_ERROR, "Could not allocate memory.\n");
336+ return AVERROR(ENOMEM);
337+}
338+
339+static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamplesref)
340+{
341+ AConvertContext *aconvert = inlink->dst->priv;
342+ AVFilterBufferRef *curbuf = insamplesref;
343+ AVFilterLink * const outlink = inlink->dst->outputs[0];
344+ int chan_mult;
345+
346+ /* in/reinint the internal buffers if this is the first buffer
347+ * provided or it is needed to use a bigger one */
348+ if (!aconvert->max_nb_samples ||
349+ (curbuf->audio->nb_samples > aconvert->max_nb_samples))
350+ if (init_buffers(inlink, curbuf->audio->nb_samples) < 0) {
351+ av_log(inlink->dst, AV_LOG_ERROR, "Could not initialize buffers.\n");
352+ return;
353+ }
354+
355+ /* if channel mixing is required */
356+ if (aconvert->mix_samplesref) {
357+ memcpy(aconvert->in_mix, curbuf->data, sizeof(aconvert->in_mix));
358+ memcpy(aconvert->out_mix, aconvert->mix_samplesref->data, sizeof(aconvert->out_mix));
359+ aconvert->convert_chlayout(aconvert->out_mix,
360+ aconvert->in_mix,
361+ curbuf->audio->nb_samples,
362+ aconvert);
363+ curbuf = aconvert->mix_samplesref;
364+ }
365+
366+ if (aconvert->audioconvert_ctx) {
367+ if (!aconvert->mix_samplesref) {
368+ if (aconvert->in_conv == aconvert->packed_data) {
369+ int i, packed_stride = av_get_bytes_per_sample(inlink->format);
370+ aconvert->packed_data[0] = curbuf->data[0];
371+ for (i = 1; i < aconvert->out_nb_channels; i++)
372+ aconvert->packed_data[i] = aconvert->packed_data[i-1] + packed_stride;
373+ } else {
374+ aconvert->in_conv = curbuf->data;
375+ }
376+ }
377+
378+ chan_mult = inlink->planar == outlink->planar && inlink->planar == 0 ?
379+ aconvert->out_nb_channels : 1;
380+
381+ av_audio_convert(aconvert->audioconvert_ctx,
382+ (void * const *) aconvert->out_conv,
383+ aconvert->out_strides,
384+ (const void * const *) aconvert->in_conv,
385+ aconvert->in_strides,
386+ curbuf->audio->nb_samples * chan_mult);
387+
388+ curbuf = aconvert->out_samplesref;
389+ }
390+
391+ avfilter_copy_buffer_ref_props(curbuf, insamplesref);
392+ curbuf->audio->channel_layout = outlink->channel_layout;
393+ curbuf->audio->planar = outlink->planar;
394+
395+ avfilter_filter_samples(inlink->dst->outputs[0],
396+ avfilter_ref_buffer(curbuf, ~0));
397+ avfilter_unref_buffer(insamplesref);
398+}
399+
400+AVFilter avfilter_af_aconvert = {
401+ .name = "aconvert",
402+ .description = NULL_IF_CONFIG_SMALL("Convert the input audio to sample_fmt:channel_layout:packed_fmt."),
403+ .priv_size = sizeof(AConvertContext),
404+ .init = init,
405+ .uninit = uninit,
406+ .query_formats = query_formats,
407+
408+ .inputs = (AVFilterPad[]) {{ .name = "default",
409+ .type = AVMEDIA_TYPE_AUDIO,
410+ .filter_samples = filter_samples,
411+ .min_perms = AV_PERM_READ, },
412+ { .name = NULL}},
413+ .outputs = (AVFilterPad[]) {{ .name = "default",
414+ .type = AVMEDIA_TYPE_AUDIO,
415+ .config_props = config_output, },
416+ { .name = NULL}},
417+};
libavfilter/af_aconvert_rematrix.c+172−0
@@ -0,0 +1,172 @@
1+/*
2+ * Copyright (c) 2011 Mina Nagy Zaki
3+ *
4+ * This file is part of FFmpeg.
5+ *
6+ * FFmpeg is free software; you can redistribute it and/or
7+ * modify it under the terms of the GNU Lesser General Public
8+ * License as published by the Free Software Foundation; either
9+ * version 2.1 of the License, or (at your option) any later version.
10+ *
11+ * FFmpeg is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+ * Lesser General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU Lesser General Public
17+ * License along with FFmpeg; if not, write to the Free Software
18+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19+ */
20+
21+/**
22+ * @file
23+ * audio rematrixing functions, based on functions from libavcodec/resample.c
24+ */
25+
26+#if defined(FLOATING)
27+# define DIV2 /2
28+#else
29+# define DIV2 >>1
30+#endif
31+
32+REMATRIX_FUNC_SIG(stereo_to_mono_packed)
33+{
34+ while (nb_samples >= 4) {
35+ outp[0][0] = (inp[0][0] + inp[0][1]) DIV2;
36+ outp[0][1] = (inp[0][2] + inp[0][3]) DIV2;
37+ outp[0][2] = (inp[0][4] + inp[0][5]) DIV2;
38+ outp[0][3] = (inp[0][6] + inp[0][7]) DIV2;
39+ outp[0] += 4;
40+ inp[0] += 8;
41+ nb_samples -= 4;
42+ }
43+ while (nb_samples--) {
44+ outp[0][0] = (inp[0][0] + inp[0][1]) DIV2;
45+ outp[0]++;
46+ inp[0] += 2;
47+ }
48+}
49+
50+REMATRIX_FUNC_SIG(stereo_downmix_packed)
51+{
52+ while (nb_samples--) {
53+ *outp[0]++ = inp[0][0];
54+ *outp[0]++ = inp[0][1];
55+ inp[0] += aconvert->in_nb_channels;
56+ }
57+}
58+
59+REMATRIX_FUNC_SIG(mono_to_stereo_packed)
60+{
61+ while (nb_samples >= 4) {
62+ outp[0][0] = outp[0][1] = inp[0][0];
63+ outp[0][2] = outp[0][3] = inp[0][1];
64+ outp[0][4] = outp[0][5] = inp[0][2];
65+ outp[0][6] = outp[0][7] = inp[0][3];
66+ outp[0] += 8;
67+ inp[0] += 4;
68+ nb_samples -= 4;
69+ }
70+ while (nb_samples--) {
71+ outp[0][0] = outp[0][1] = inp[0][0];
72+ outp[0] += 2;
73+ inp[0] += 1;
74+ }
75+}
76+
77+/**
78+ * This is for when we have more than 2 input channels, need to downmix to mono
79+ * and do not have a conversion formula available. We just use first two input
80+ * channels - left and right. This is a placeholder until more conversion
81+ * functions are written.
82+ */
83+REMATRIX_FUNC_SIG(mono_downmix_packed)
84+{
85+ while (nb_samples--) {
86+ outp[0][0] = (inp[0][0] + inp[0][1]) DIV2;
87+ inp[0] += aconvert->in_nb_channels;
88+ outp[0]++;
89+ }
90+}
91+
92+REMATRIX_FUNC_SIG(mono_downmix_planar)
93+{
94+ FMT_TYPE *out = outp[0];
95+
96+ while (nb_samples >= 4) {
97+ out[0] = (inp[0][0] + inp[1][0]) DIV2;
98+ out[1] = (inp[0][1] + inp[1][1]) DIV2;
99+ out[2] = (inp[0][2] + inp[1][2]) DIV2;
100+ out[3] = (inp[0][3] + inp[1][3]) DIV2;
101+ out += 4;
102+ inp[0] += 4;
103+ inp[1] += 4;
104+ nb_samples -= 4;
105+ }
106+ while (nb_samples--) {
107+ out[0] = (inp[0][0] + inp[1][0]) DIV2;
108+ out++;
109+ inp[0]++;
110+ inp[1]++;
111+ }
112+}
113+
114+/* Stereo to 5.1 output */
115+REMATRIX_FUNC_SIG(stereo_to_surround_5p1_packed)
116+{
117+ while (nb_samples--) {
118+ outp[0][0] = inp[0][0]; /* left */
119+ outp[0][1] = inp[0][1]; /* right */
120+ outp[0][2] = (inp[0][0] + inp[0][1]) DIV2; /* center */
121+ outp[0][3] = 0; /* low freq */
122+ outp[0][4] = 0; /* FIXME: left surround: -3dB or -6dB or -9dB of stereo left */
123+ outp[0][5] = 0; /* FIXME: right surroud: -3dB or -6dB or -9dB of stereo right */
124+ inp[0] += 2;
125+ outp[0] += 6;
126+ }
127+}
128+
129+REMATRIX_FUNC_SIG(stereo_to_surround_5p1_planar)
130+{
131+ while (nb_samples--) {
132+ *outp[0]++ = *inp[0]; /* left */
133+ *outp[1]++ = *inp[1]; /* right */
134+ *outp[2]++ = (*inp[0] + *inp[1]) DIV2; /* center */
135+ *outp[3]++ = 0; /* low freq */
136+ *outp[4]++ = 0; /* FIXME: left surround: -3dB or -6dB or -9dB of stereo left */
137+ *outp[5]++ = 0; /* FIXME: right surroud: -3dB or -6dB or -9dB of stereo right */
138+ inp[0]++; inp[1]++;
139+ }
140+}
141+
142+
143+/*
144+5.1 to stereo input: [fl, fr, c, lfe, rl, rr]
145+- Left = front_left + rear_gain * rear_left + center_gain * center
146+- Right = front_right + rear_gain * rear_right + center_gain * center
147+Where rear_gain is usually around 0.5-1.0 and
148+ center_gain is almost always 0.7 (-3 dB)
149+*/
150+REMATRIX_FUNC_SIG(surround_5p1_to_stereo_packed)
151+{
152+ while (nb_samples--) {
153+ *outp[0]++ = inp[0][0] + (0.5 * inp[0][4]) + (0.7 * inp[0][2]); //FIXME CLIPPING!
154+ *outp[0]++ = inp[0][1] + (0.5 * inp[0][5]) + (0.7 * inp[0][2]); //FIXME CLIPPING!
155+
156+ inp[0] += 6;
157+ }
158+}
159+
160+REMATRIX_FUNC_SIG(surround_5p1_to_stereo_planar)
161+{
162+ while (nb_samples--) {
163+ *outp[0]++ = *inp[0] + (0.5 * *inp[4]) + (0.7 * *inp[2]); //FIXME CLIPPING!
164+ *outp[1]++ = *inp[1] + (0.5 * *inp[5]) + (0.7 * *inp[2]); //FIXME CLIPPING!
165+
166+ inp[0]++; inp[1]++; inp[2]++; inp[3]++; inp[4]++; inp[5]++;
167+ }
168+}
169+
170+#undef DIV2
171+#undef REMATRIX_FUNC_NAME
172+#undef FMT_TYPE
libavfilter/allfilters.c+1−0
@@ -34,6 +34,7 @@ void avfilter_register_all(void) · 33 unmodified lines
3434 return;
3535 initialized = 1;
3636
37+ REGISTER_FILTER (ACONVERT, aconvert, af);
3738 REGISTER_FILTER (AFORMAT, aformat, af);
3839 REGISTER_FILTER (ANULL, anull, af);
3940 REGISTER_FILTER (ARESAMPLE, aresample, af);
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 42
32+#define LIBAVFILTER_VERSION_MINOR 43
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