2 * Copyright (c) 2010 S.N. Hemanth Meenakshisundaram <smeenaks@ucsd.edu>
3 * Copyright (c) 2011 Stefano Sabatini
4 * Copyright (c) 2011 Mina Nagy Zaki
6 * This file is part of FFmpeg.
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.
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.
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
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
30 #include "libavutil/audioconvert.h"
31 #include "libavcodec/audioconvert.h"
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
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
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
50 AVAudioConvert *audioconvert_ctx; ///< context for conversion to output sample format
52 void (*convert_chlayout)(); ///< function to do the requested rematrixing
55 #define REMATRIX_FUNC_SIG(NAME) static void REMATRIX_FUNC_NAME(NAME) \
56 (FMT_TYPE *outp[], FMT_TYPE *inp[], int nb_samples, AConvertContext *aconvert)
58 #define FMT_TYPE uint8_t
59 #define REMATRIX_FUNC_NAME(NAME) NAME ## _u8
60 #include "af_aconvert_rematrix.c"
62 #define FMT_TYPE int16_t
63 #define REMATRIX_FUNC_NAME(NAME) NAME ## _s16
64 #include "af_aconvert_rematrix.c"
66 #define FMT_TYPE int32_t
67 #define REMATRIX_FUNC_NAME(NAME) NAME ## _s32
68 #include "af_aconvert_rematrix.c"
72 #define FMT_TYPE float
73 #define REMATRIX_FUNC_NAME(NAME) NAME ## _flt
74 #include "af_aconvert_rematrix.c"
76 #define FMT_TYPE double
77 #define REMATRIX_FUNC_NAME(NAME) NAME ## _dbl
78 #include "af_aconvert_rematrix.c"
80 #define FMT_TYPE uint8_t
81 #define REMATRIX_FUNC_NAME(NAME) NAME
82 REMATRIX_FUNC_SIG(stereo_remix_planar)
84 int size = av_get_bytes_per_sample(aconvert->in_sample_fmt) * nb_samples;
86 memcpy(outp[0], inp[0], size);
87 memcpy(outp[1], inp[aconvert->in_nb_channels == 1 ? 0 : 1], size);
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},
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)
101 static struct RematrixFunctionInfo {
102 int64_t in_chlayout, out_chlayout;
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)
113 // This function works for all sample formats
114 {0, AV_CH_LAYOUT_STEREO, AVFILTER_PLANAR, -1, stereo_remix_planar}
117 static av_cold int init(AVFilterContext *ctx, const char *args0, void *opaque)
119 AConvertContext *aconvert = ctx->priv;
120 char *arg, *ptr = NULL;
122 char *args = av_strdup(args0);
124 aconvert->out_sample_fmt = AV_SAMPLE_FMT_NONE;
125 aconvert->out_chlayout = 0;
126 aconvert->out_packing_fmt = -1;
128 if ((arg = strtok_r(args, ":", &ptr)) && strcmp(arg, "auto")) {
129 if ((ret = ff_parse_sample_format(&aconvert->out_sample_fmt, arg, ctx)) < 0)
132 if ((arg = strtok_r(NULL, ":", &ptr)) && strcmp(arg, "auto")) {
133 if ((ret = ff_parse_channel_layout(&aconvert->out_chlayout, arg, ctx)) < 0)
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)
146 static av_cold void uninit(AVFilterContext *ctx)
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);
155 static int query_formats(AVFilterContext *ctx)
157 AVFilterFormats *formats = NULL;
158 AConvertContext *aconvert = ctx->priv;
159 AVFilterLink *inlink = ctx->inputs[0];
160 AVFilterLink *outlink = ctx->outputs[0];
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) {
166 avfilter_add_format(&formats, aconvert->out_sample_fmt);
167 avfilter_formats_ref(formats, &outlink->in_formats);
169 avfilter_formats_ref(avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO),
170 &outlink->in_formats);
172 avfilter_formats_ref(avfilter_make_all_channel_layouts(),
173 &inlink->out_chlayouts);
174 if (aconvert->out_chlayout != 0) {
176 avfilter_add_format(&formats, aconvert->out_chlayout);
177 avfilter_formats_ref(formats, &outlink->in_chlayouts);
179 avfilter_formats_ref(avfilter_make_all_channel_layouts(),
180 &outlink->in_chlayouts);
182 avfilter_formats_ref(avfilter_make_all_packing_formats(),
183 &inlink->out_packing);
184 if (aconvert->out_packing_fmt != -1) {
186 avfilter_add_format(&formats, aconvert->out_packing_fmt);
187 avfilter_formats_ref(formats, &outlink->in_packing);
189 avfilter_formats_ref(avfilter_make_all_packing_formats(),
190 &outlink->in_packing);
195 static int config_output(AVFilterLink *outlink)
197 AVFilterLink *inlink = outlink->src->inputs[0];
198 AConvertContext *aconvert = outlink->src->priv;
199 char buf1[64], buf2[64];
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);
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);
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);
226 /* compute which channel layout conversion to use */
227 if (inlink->channel_layout != outlink->channel_layout) {
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)
236 aconvert->convert_chlayout = f->func;
240 if (!aconvert->convert_chlayout) {
241 av_log(outlink->src, AV_LOG_ERROR,
242 "Unsupported channel layout conversion '%s -> %s' requested!\n",
244 return AVERROR(EINVAL);
251 static int init_buffers(AVFilterLink *inlink, int nb_samples)
253 AConvertContext *aconvert = inlink->dst->priv;
254 AVFilterLink * const outlink = inlink->dst->outputs[0];
255 int i, packed_stride = 0;
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;
263 aconvert->max_nb_samples = nb_samples;
265 if (aconvert->convert_chlayout) {
266 /* allocate buffer for storing intermediary mixing samplesref */
269 int nb_channels = av_get_channel_layout_nb_channels(outlink->channel_layout);
271 if (av_samples_alloc(data, linesize, nb_channels, nb_samples,
272 inlink->format, inlink->planar, 16) < 0)
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,
279 if (!aconvert->mix_samplesref)
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)
290 aconvert->in_strides [0] = av_get_bytes_per_sample(inlink ->format);
291 aconvert->out_strides[0] = av_get_bytes_per_sample(outlink->format);
293 aconvert->out_conv = aconvert->out_samplesref->data;
294 if (aconvert->mix_samplesref)
295 aconvert->in_conv = aconvert->mix_samplesref->data;
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;
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;
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
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];
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)
335 av_log(inlink->dst, AV_LOG_ERROR, "Could not allocate memory.\n");
336 return AVERROR(ENOMEM);
339 static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamplesref)
341 AConvertContext *aconvert = inlink->dst->priv;
342 AVFilterBufferRef *curbuf = insamplesref;
343 AVFilterLink * const outlink = inlink->dst->outputs[0];
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");
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,
361 curbuf->audio->nb_samples,
363 curbuf = aconvert->mix_samplesref;
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;
374 aconvert->in_conv = curbuf->data;
378 chan_mult = inlink->planar == outlink->planar && inlink->planar == 0 ?
379 aconvert->out_nb_channels : 1;
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);
388 curbuf = aconvert->out_samplesref;
391 avfilter_copy_buffer_ref_props(curbuf, insamplesref);
392 curbuf->audio->channel_layout = outlink->channel_layout;
393 curbuf->audio->planar = outlink->planar;
395 avfilter_filter_samples(inlink->dst->outputs[0],
396 avfilter_ref_buffer(curbuf, ~0));
397 avfilter_unref_buffer(insamplesref);
400 AVFilter avfilter_af_aconvert = {
402 .description = NULL_IF_CONFIG_SMALL("Convert the input audio to sample_fmt:channel_layout:packed_fmt."),
403 .priv_size = sizeof(AConvertContext),
406 .query_formats = query_formats,
408 .inputs = (AVFilterPad[]) {{ .name = "default",
409 .type = AVMEDIA_TYPE_AUDIO,
410 .filter_samples = filter_samples,
411 .min_perms = AV_PERM_READ, },
413 .outputs = (AVFilterPad[]) {{ .name = "default",
414 .type = AVMEDIA_TYPE_AUDIO,
415 .config_props = config_output, },