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
55- H.264 Decoding on Android via Stagefright55- H.264 Decoding on Android via Stagefright
56- Prores decoder56- Prores decoder
57- BIN/XBIN/ADF/IDF text file decoder57- BIN/XBIN/ADF/IDF text file decoder
58- aconvert audio filter added
58 59
59 60
60version 0.8:61version 0.8:
configure+1−0
@@ -1575,6 +1575,7 @@ udp_protocol_deps="network" · 1574 unmodified lines
1575 1575
1576# filters1576# filters
1577abuffer_filter_deps="strtok_r"1577abuffer_filter_deps="strtok_r"
1578aconvert_filter_deps="strtok_r"
1578aformat_filter_deps="strtok_r"1579aformat_filter_deps="strtok_r"
1579amovie_filter_deps="avcodec avformat"1580amovie_filter_deps="avcodec avformat"
1580blackframe_filter_deps="gpl"1581blackframe_filter_deps="gpl"
doc/filters.texi+36−0
@@ -99,6 +99,42 @@ build. · 98 unmodified lines
99 99
100Below is a description of the currently available audio filters.100Below is a description of the currently available audio filters.
101 101
102@section aconvert
103
104Convert the input audio format to the specified formats.
105
106The 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
110the corresponding numeric value defined in @file{libavutil/samplefmt.h}.
111
112@var{channel_layout} specifies the channel layout, and can be a string
113or 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
116of "planar" or "packed", or the corresponding numeric values "0" or "1".
117
118The special parameter "auto", signifies that the filter will
119automatically select the output format depending on the output filter.
120
121Some examples follow.
122
123@itemize
124@item
125Convert input to unsigned 8-bit, stereo, packed:
126@example
127aconvert=u8:stereo:packed
128@end example
129
130@item
131Convert input to unsigned 8-bit, automatically select out channel layout
132and packing format:
133@example
134aconvert=u8:auto:auto
135@end example
136@end itemize
137
102@section aformat138@section aformat
103 139
104Convert the input audio to one of the specified formats. The framework will140Convert 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
2 2
3NAME = avfilter3NAME = avfilter
4FFLIBS = avutil4FFLIBS = avutil
5
6FFLIBS-$(CONFIG_ACONVERT_FILTER) += avcodec
5FFLIBS-$(CONFIG_AMOVIE_FILTER) += avformat avcodec7FFLIBS-$(CONFIG_AMOVIE_FILTER) += avformat avcodec
6FFLIBS-$(CONFIG_ARESAMPLE_FILTER) += avcodec8FFLIBS-$(CONFIG_ARESAMPLE_FILTER) += avcodec
7FFLIBS-$(CONFIG_MOVIE_FILTER) += avformat avcodec9FFLIBS-$(CONFIG_MOVIE_FILTER) += avformat avcodec
@@ -20,6 +22,7 @@ OBJS = allfilters.o \ · 12 unmodified lines
20 22
21OBJS-$(CONFIG_AVCODEC) += avcodec.o23OBJS-$(CONFIG_AVCODEC) += avcodec.o
22 24
25OBJS-$(CONFIG_ACONVERT_FILTER) += af_aconvert.o
23OBJS-$(CONFIG_AFORMAT_FILTER) += af_aformat.o26OBJS-$(CONFIG_AFORMAT_FILTER) += af_aformat.o
24OBJS-$(CONFIG_ANULL_FILTER) += af_anull.o27OBJS-$(CONFIG_ANULL_FILTER) += af_anull.o
25OBJS-$(CONFIG_ARESAMPLE_FILTER) += af_aresample.o28OBJS-$(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
35typedef 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
82REMATRIX_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
101static 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
117static 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
141end:
142 av_freep(&args);
143 return ret;
144}
145
146static 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
155static 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
195static 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
251static 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
334fail_no_mem:
335 av_log(inlink->dst, AV_LOG_ERROR, "Could not allocate memory.\n");
336 return AVERROR(ENOMEM);
337}
338
339static 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
400AVFilter 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
32REMATRIX_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
50REMATRIX_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
59REMATRIX_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 */
83REMATRIX_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
92REMATRIX_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 */
115REMATRIX_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
129REMATRIX_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/*
1445.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
147Where rear_gain is usually around 0.5-1.0 and
148 center_gain is almost always 0.7 (-3 dB)
149*/
150REMATRIX_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
160REMATRIX_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
34 return;34 return;
35 initialized = 1;35 initialized = 1;
36 36
37 REGISTER_FILTER (ACONVERT, aconvert, af);
37 REGISTER_FILTER (AFORMAT, aformat, af);38 REGISTER_FILTER (AFORMAT, aformat, af);
38 REGISTER_FILTER (ANULL, anull, af);39 REGISTER_FILTER (ANULL, anull, af);
39 REGISTER_FILTER (ARESAMPLE, aresample, af);40 REGISTER_FILTER (ARESAMPLE, aresample, af);
libavfilter/avfilter.h+1−1
@@ -29,7 +29,7 @@ · 28 unmodified lines
29#include "libavutil/rational.h"29#include "libavutil/rational.h"
30 30
31#define LIBAVFILTER_VERSION_MAJOR 231#define LIBAVFILTER_VERSION_MAJOR 2
32#define LIBAVFILTER_VERSION_MINOR 4232#define LIBAVFILTER_VERSION_MINOR 43
33#define LIBAVFILTER_VERSION_MICRO 033#define LIBAVFILTER_VERSION_MICRO 0
34 34
35#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \35#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