]> git.sesse.net Git - ffmpeg/blob - libavresample/audio_mix.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libavresample / audio_mix.c
1 /*
2  * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
3  *
4  * This file is part of Libav.
5  *
6  * Libav 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  * Libav 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 Libav; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20
21 #include <stdint.h>
22
23 #include "libavutil/libm.h"
24 #include "libavutil/samplefmt.h"
25 #include "avresample.h"
26 #include "internal.h"
27 #include "audio_data.h"
28 #include "audio_mix.h"
29
30 static const char *coeff_type_names[] = { "q8", "q15", "flt" };
31
32 void ff_audio_mix_set_func(AudioMix *am, enum AVSampleFormat fmt,
33                            enum AVMixCoeffType coeff_type, int in_channels,
34                            int out_channels, int ptr_align, int samples_align,
35                            const char *descr, void *mix_func)
36 {
37     if (fmt == am->fmt && coeff_type == am->coeff_type &&
38         ( in_channels ==  am->in_channels ||  in_channels == 0) &&
39         (out_channels == am->out_channels || out_channels == 0)) {
40         char chan_str[16];
41         am->mix           = mix_func;
42         am->func_descr    = descr;
43         am->ptr_align     = ptr_align;
44         am->samples_align = samples_align;
45         if (ptr_align == 1 && samples_align == 1) {
46             am->mix_generic        = mix_func;
47             am->func_descr_generic = descr;
48         } else {
49             am->has_optimized_func = 1;
50         }
51         if (in_channels) {
52             if (out_channels)
53                 snprintf(chan_str, sizeof(chan_str), "[%d to %d] ",
54                          in_channels, out_channels);
55             else
56                 snprintf(chan_str, sizeof(chan_str), "[%d to any] ",
57                          in_channels);
58         } else if (out_channels) {
59                 snprintf(chan_str, sizeof(chan_str), "[any to %d] ",
60                          out_channels);
61         }
62         av_log(am->avr, AV_LOG_DEBUG, "audio_mix: found function: [fmt=%s] "
63                "[c=%s] %s(%s)\n", av_get_sample_fmt_name(fmt),
64                coeff_type_names[coeff_type],
65                (in_channels || out_channels) ? chan_str : "", descr);
66     }
67 }
68
69 #define MIX_FUNC_NAME(fmt, cfmt) mix_any_ ## fmt ##_## cfmt ##_c
70
71 #define MIX_FUNC_GENERIC(fmt, cfmt, stype, ctype, sumtype, expr)            \
72 static void MIX_FUNC_NAME(fmt, cfmt)(stype **samples, ctype **matrix,       \
73                                      int len, int out_ch, int in_ch)        \
74 {                                                                           \
75     int i, in, out;                                                         \
76     stype temp[AVRESAMPLE_MAX_CHANNELS];                                    \
77     for (i = 0; i < len; i++) {                                             \
78         for (out = 0; out < out_ch; out++) {                                \
79             sumtype sum = 0;                                                \
80             for (in = 0; in < in_ch; in++)                                  \
81                 sum += samples[in][i] * matrix[out][in];                    \
82             temp[out] = expr;                                               \
83         }                                                                   \
84         for (out = 0; out < out_ch; out++)                                  \
85             samples[out][i] = temp[out];                                    \
86     }                                                                       \
87 }
88
89 MIX_FUNC_GENERIC(FLTP, FLT, float,   float,   float,   sum)
90 MIX_FUNC_GENERIC(S16P, FLT, int16_t, float,   float,   av_clip_int16(lrintf(sum)))
91 MIX_FUNC_GENERIC(S16P, Q15, int16_t, int32_t, int64_t, av_clip_int16(sum >> 15))
92 MIX_FUNC_GENERIC(S16P, Q8,  int16_t, int16_t, int32_t, av_clip_int16(sum >>  8))
93
94 /* TODO: templatize the channel-specific C functions */
95
96 static void mix_2_to_1_fltp_flt_c(float **samples, float **matrix, int len,
97                                   int out_ch, int in_ch)
98 {
99     float *src0 = samples[0];
100     float *src1 = samples[1];
101     float *dst  = src0;
102     float m0    = matrix[0][0];
103     float m1    = matrix[0][1];
104
105     while (len > 4) {
106         *dst++ = *src0++ * m0 + *src1++ * m1;
107         *dst++ = *src0++ * m0 + *src1++ * m1;
108         *dst++ = *src0++ * m0 + *src1++ * m1;
109         *dst++ = *src0++ * m0 + *src1++ * m1;
110         len -= 4;
111     }
112     while (len > 0) {
113         *dst++ = *src0++ * m0 + *src1++ * m1;
114         len--;
115     }
116 }
117
118 static void mix_2_to_1_s16p_flt_c(int16_t **samples, float **matrix, int len,
119                                   int out_ch, int in_ch)
120 {
121     int16_t *src0 = samples[0];
122     int16_t *src1 = samples[1];
123     int16_t *dst  = src0;
124     float m0      = matrix[0][0];
125     float m1      = matrix[0][1];
126
127     while (len > 4) {
128         *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1));
129         *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1));
130         *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1));
131         *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1));
132         len -= 4;
133     }
134     while (len > 0) {
135         *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1));
136         len--;
137     }
138 }
139
140 static void mix_2_to_1_s16p_q8_c(int16_t **samples, int16_t **matrix, int len,
141                                  int out_ch, int in_ch)
142 {
143     int16_t *src0 = samples[0];
144     int16_t *src1 = samples[1];
145     int16_t *dst  = src0;
146     int16_t m0    = matrix[0][0];
147     int16_t m1    = matrix[0][1];
148
149     while (len > 4) {
150         *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8;
151         *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8;
152         *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8;
153         *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8;
154         len -= 4;
155     }
156     while (len > 0) {
157         *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8;
158         len--;
159     }
160 }
161
162 static void mix_1_to_2_fltp_flt_c(float **samples, float **matrix, int len,
163                                   int out_ch, int in_ch)
164 {
165     float v;
166     float *dst0 = samples[0];
167     float *dst1 = samples[1];
168     float *src  = dst0;
169     float m0    = matrix[0][0];
170     float m1    = matrix[1][0];
171
172     while (len > 4) {
173         v = *src++;
174         *dst0++ = v * m1;
175         *dst1++ = v * m0;
176         v = *src++;
177         *dst0++ = v * m1;
178         *dst1++ = v * m0;
179         v = *src++;
180         *dst0++ = v * m1;
181         *dst1++ = v * m0;
182         v = *src++;
183         *dst0++ = v * m1;
184         *dst1++ = v * m0;
185         len -= 4;
186     }
187     while (len > 0) {
188         v = *src++;
189         *dst0++ = v * m1;
190         *dst1++ = v * m0;
191         len--;
192     }
193 }
194
195 static void mix_6_to_2_fltp_flt_c(float **samples, float **matrix, int len,
196                                   int out_ch, int in_ch)
197 {
198     float v0, v1;
199     float *src0 = samples[0];
200     float *src1 = samples[1];
201     float *src2 = samples[2];
202     float *src3 = samples[3];
203     float *src4 = samples[4];
204     float *src5 = samples[5];
205     float *dst0 = src0;
206     float *dst1 = src1;
207     float *m0   = matrix[0];
208     float *m1   = matrix[1];
209
210     while (len > 0) {
211         v0 = *src0++;
212         v1 = *src1++;
213         *dst0++ = v0      * m0[0] +
214                   v1      * m0[1] +
215                   *src2   * m0[2] +
216                   *src3   * m0[3] +
217                   *src4   * m0[4] +
218                   *src5   * m0[5];
219         *dst1++ = v0      * m1[0] +
220                   v1      * m1[1] +
221                   *src2++ * m1[2] +
222                   *src3++ * m1[3] +
223                   *src4++ * m1[4] +
224                   *src5++ * m1[5];
225         len--;
226     }
227 }
228
229 static void mix_2_to_6_fltp_flt_c(float **samples, float **matrix, int len,
230                                   int out_ch, int in_ch)
231 {
232     float v0, v1;
233     float *dst0 = samples[0];
234     float *dst1 = samples[1];
235     float *dst2 = samples[2];
236     float *dst3 = samples[3];
237     float *dst4 = samples[4];
238     float *dst5 = samples[5];
239     float *src0 = dst0;
240     float *src1 = dst1;
241
242     while (len > 0) {
243         v0 = *src0++;
244         v1 = *src1++;
245         *dst0++ = v0 * matrix[0][0] + v1 * matrix[0][1];
246         *dst1++ = v0 * matrix[1][0] + v1 * matrix[1][1];
247         *dst2++ = v0 * matrix[2][0] + v1 * matrix[2][1];
248         *dst3++ = v0 * matrix[3][0] + v1 * matrix[3][1];
249         *dst4++ = v0 * matrix[4][0] + v1 * matrix[4][1];
250         *dst5++ = v0 * matrix[5][0] + v1 * matrix[5][1];
251         len--;
252     }
253 }
254
255 static int mix_function_init(AudioMix *am)
256 {
257     /* any-to-any C versions */
258
259     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,
260                           0, 0, 1, 1, "C", MIX_FUNC_NAME(FLTP, FLT));
261
262     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,
263                           0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, FLT));
264
265     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q15,
266                           0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, Q15));
267
268     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q8,
269                           0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, Q8));
270
271     /* channel-specific C versions */
272
273     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,
274                           2, 1, 1, 1, "C", mix_2_to_1_fltp_flt_c);
275
276     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,
277                           2, 1, 1, 1, "C", mix_2_to_1_s16p_flt_c);
278
279     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q8,
280                           2, 1, 1, 1, "C", mix_2_to_1_s16p_q8_c);
281
282     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,
283                           1, 2, 1, 1, "C", mix_1_to_2_fltp_flt_c);
284
285     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,
286                           6, 2, 1, 1, "C", mix_6_to_2_fltp_flt_c);
287
288     ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,
289                           2, 6, 1, 1, "C", mix_2_to_6_fltp_flt_c);
290
291     if (ARCH_X86)
292         ff_audio_mix_init_x86(am);
293
294     if (!am->mix) {
295         av_log(am->avr, AV_LOG_ERROR, "audio_mix: NO FUNCTION FOUND: [fmt=%s] "
296                "[c=%s] [%d to %d]\n", av_get_sample_fmt_name(am->fmt),
297                coeff_type_names[am->coeff_type], am->in_channels,
298                am->out_channels);
299         return AVERROR_PATCHWELCOME;
300     }
301     return 0;
302 }
303
304 int ff_audio_mix_init(AVAudioResampleContext *avr)
305 {
306     int ret;
307
308     if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P &&
309         avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP) {
310         av_log(avr, AV_LOG_ERROR, "Unsupported internal format for "
311                "mixing: %s\n",
312                av_get_sample_fmt_name(avr->internal_sample_fmt));
313         return AVERROR(EINVAL);
314     }
315
316     /* build matrix if the user did not already set one */
317     if (avr->am->matrix) {
318         if (avr->am->coeff_type != avr->mix_coeff_type      ||
319             avr->am->in_layout  != avr->in_channel_layout   ||
320             avr->am->out_layout != avr->out_channel_layout) {
321             av_log(avr, AV_LOG_ERROR,
322                    "Custom matrix does not match current parameters\n");
323             return AVERROR(EINVAL);
324         }
325     } else {
326         int i, j;
327         char in_layout_name[128];
328         char out_layout_name[128];
329         double *matrix_dbl = av_mallocz(avr->out_channels * avr->in_channels *
330                                         sizeof(*matrix_dbl));
331         if (!matrix_dbl)
332             return AVERROR(ENOMEM);
333
334         ret = avresample_build_matrix(avr->in_channel_layout,
335                                       avr->out_channel_layout,
336                                       avr->center_mix_level,
337                                       avr->surround_mix_level,
338                                       avr->lfe_mix_level, 1, matrix_dbl,
339                                       avr->in_channels,
340                                       avr->matrix_encoding);
341         if (ret < 0) {
342             av_free(matrix_dbl);
343             return ret;
344         }
345
346         av_get_channel_layout_string(in_layout_name, sizeof(in_layout_name),
347                                      avr->in_channels, avr->in_channel_layout);
348         av_get_channel_layout_string(out_layout_name, sizeof(out_layout_name),
349                                      avr->out_channels, avr->out_channel_layout);
350         av_log(avr, AV_LOG_DEBUG, "audio_mix: %s to %s\n",
351                in_layout_name, out_layout_name);
352         for (i = 0; i < avr->out_channels; i++) {
353             for (j = 0; j < avr->in_channels; j++) {
354                 av_log(avr, AV_LOG_DEBUG, "  %0.3f ",
355                        matrix_dbl[i * avr->in_channels + j]);
356             }
357             av_log(avr, AV_LOG_DEBUG, "\n");
358         }
359
360         ret = avresample_set_matrix(avr, matrix_dbl, avr->in_channels);
361         if (ret < 0) {
362             av_free(matrix_dbl);
363             return ret;
364         }
365         av_free(matrix_dbl);
366     }
367
368     avr->am->fmt          = avr->internal_sample_fmt;
369     avr->am->coeff_type   = avr->mix_coeff_type;
370     avr->am->in_layout    = avr->in_channel_layout;
371     avr->am->out_layout   = avr->out_channel_layout;
372     avr->am->in_channels  = avr->in_channels;
373     avr->am->out_channels = avr->out_channels;
374
375     ret = mix_function_init(avr->am);
376     if (ret < 0)
377         return ret;
378
379     return 0;
380 }
381
382 void ff_audio_mix_close(AudioMix *am)
383 {
384     if (!am)
385         return;
386     if (am->matrix) {
387         av_free(am->matrix[0]);
388         am->matrix = NULL;
389     }
390     memset(am->matrix_q8,  0, sizeof(am->matrix_q8 ));
391     memset(am->matrix_q15, 0, sizeof(am->matrix_q15));
392     memset(am->matrix_flt, 0, sizeof(am->matrix_flt));
393 }
394
395 int ff_audio_mix(AudioMix *am, AudioData *src)
396 {
397     int use_generic = 1;
398     int len = src->nb_samples;
399
400     /* determine whether to use the optimized function based on pointer and
401        samples alignment in both the input and output */
402     if (am->has_optimized_func) {
403         int aligned_len = FFALIGN(len, am->samples_align);
404         if (!(src->ptr_align % am->ptr_align) &&
405             src->samples_align >= aligned_len) {
406             len = aligned_len;
407             use_generic = 0;
408         }
409     }
410     av_dlog(am->avr, "audio_mix: %d samples - %d to %d channels (%s)\n",
411             src->nb_samples, am->in_channels, am->out_channels,
412             use_generic ? am->func_descr_generic : am->func_descr);
413
414     if (use_generic)
415         am->mix_generic(src->data, am->matrix, len, am->out_channels,
416                         am->in_channels);
417     else
418         am->mix(src->data, am->matrix, len, am->out_channels, am->in_channels);
419
420     ff_audio_data_set_channels(src, am->out_channels);
421
422     return 0;
423 }