Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | |
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 | #include <stdint.h> | |
22 | ||
23 | #include "libavutil/common.h" | |
24 | #include "libavutil/libm.h" | |
25 | #include "libavutil/samplefmt.h" | |
26 | #include "avresample.h" | |
27 | #include "internal.h" | |
28 | #include "audio_data.h" | |
29 | #include "audio_mix.h" | |
30 | ||
31 | static const char * const coeff_type_names[] = { "q8", "q15", "flt" }; | |
32 | ||
33 | struct AudioMix { | |
34 | AVAudioResampleContext *avr; | |
35 | enum AVSampleFormat fmt; | |
36 | enum AVMixCoeffType coeff_type; | |
37 | uint64_t in_layout; | |
38 | uint64_t out_layout; | |
39 | int in_channels; | |
40 | int out_channels; | |
41 | ||
42 | int ptr_align; | |
43 | int samples_align; | |
44 | int has_optimized_func; | |
45 | const char *func_descr; | |
46 | const char *func_descr_generic; | |
47 | mix_func *mix; | |
48 | mix_func *mix_generic; | |
49 | ||
50 | int in_matrix_channels; | |
51 | int out_matrix_channels; | |
52 | int output_zero[AVRESAMPLE_MAX_CHANNELS]; | |
53 | int input_skip[AVRESAMPLE_MAX_CHANNELS]; | |
54 | int output_skip[AVRESAMPLE_MAX_CHANNELS]; | |
55 | int16_t *matrix_q8[AVRESAMPLE_MAX_CHANNELS]; | |
56 | int32_t *matrix_q15[AVRESAMPLE_MAX_CHANNELS]; | |
57 | float *matrix_flt[AVRESAMPLE_MAX_CHANNELS]; | |
58 | void **matrix; | |
59 | }; | |
60 | ||
61 | void ff_audio_mix_set_func(AudioMix *am, enum AVSampleFormat fmt, | |
62 | enum AVMixCoeffType coeff_type, int in_channels, | |
63 | int out_channels, int ptr_align, int samples_align, | |
64 | const char *descr, void *mix_func) | |
65 | { | |
66 | if (fmt == am->fmt && coeff_type == am->coeff_type && | |
67 | ( in_channels == am->in_matrix_channels || in_channels == 0) && | |
68 | (out_channels == am->out_matrix_channels || out_channels == 0)) { | |
69 | char chan_str[16]; | |
70 | am->mix = mix_func; | |
71 | am->func_descr = descr; | |
72 | am->ptr_align = ptr_align; | |
73 | am->samples_align = samples_align; | |
74 | if (ptr_align == 1 && samples_align == 1) { | |
75 | am->mix_generic = mix_func; | |
76 | am->func_descr_generic = descr; | |
77 | } else { | |
78 | am->has_optimized_func = 1; | |
79 | } | |
80 | if (in_channels) { | |
81 | if (out_channels) | |
82 | snprintf(chan_str, sizeof(chan_str), "[%d to %d] ", | |
83 | in_channels, out_channels); | |
84 | else | |
85 | snprintf(chan_str, sizeof(chan_str), "[%d to any] ", | |
86 | in_channels); | |
87 | } else if (out_channels) { | |
88 | snprintf(chan_str, sizeof(chan_str), "[any to %d] ", | |
89 | out_channels); | |
90 | } else { | |
91 | snprintf(chan_str, sizeof(chan_str), "[any to any] "); | |
92 | } | |
93 | av_log(am->avr, AV_LOG_DEBUG, "audio_mix: found function: [fmt=%s] " | |
94 | "[c=%s] %s(%s)\n", av_get_sample_fmt_name(fmt), | |
95 | coeff_type_names[coeff_type], chan_str, descr); | |
96 | } | |
97 | } | |
98 | ||
99 | #define MIX_FUNC_NAME(fmt, cfmt) mix_any_ ## fmt ##_## cfmt ##_c | |
100 | ||
101 | #define MIX_FUNC_GENERIC(fmt, cfmt, stype, ctype, sumtype, expr) \ | |
102 | static void MIX_FUNC_NAME(fmt, cfmt)(stype **samples, ctype **matrix, \ | |
103 | int len, int out_ch, int in_ch) \ | |
104 | { \ | |
105 | int i, in, out; \ | |
106 | stype temp[AVRESAMPLE_MAX_CHANNELS]; \ | |
107 | for (i = 0; i < len; i++) { \ | |
108 | for (out = 0; out < out_ch; out++) { \ | |
109 | sumtype sum = 0; \ | |
110 | for (in = 0; in < in_ch; in++) \ | |
111 | sum += samples[in][i] * matrix[out][in]; \ | |
112 | temp[out] = expr; \ | |
113 | } \ | |
114 | for (out = 0; out < out_ch; out++) \ | |
115 | samples[out][i] = temp[out]; \ | |
116 | } \ | |
117 | } | |
118 | ||
119 | MIX_FUNC_GENERIC(FLTP, FLT, float, float, float, sum) | |
120 | MIX_FUNC_GENERIC(S16P, FLT, int16_t, float, float, av_clip_int16(lrintf(sum))) | |
121 | MIX_FUNC_GENERIC(S16P, Q15, int16_t, int32_t, int64_t, av_clip_int16(sum >> 15)) | |
122 | MIX_FUNC_GENERIC(S16P, Q8, int16_t, int16_t, int32_t, av_clip_int16(sum >> 8)) | |
123 | ||
124 | /* TODO: templatize the channel-specific C functions */ | |
125 | ||
126 | static void mix_2_to_1_fltp_flt_c(float **samples, float **matrix, int len, | |
127 | int out_ch, int in_ch) | |
128 | { | |
129 | float *src0 = samples[0]; | |
130 | float *src1 = samples[1]; | |
131 | float *dst = src0; | |
132 | float m0 = matrix[0][0]; | |
133 | float m1 = matrix[0][1]; | |
134 | ||
135 | while (len > 4) { | |
136 | *dst++ = *src0++ * m0 + *src1++ * m1; | |
137 | *dst++ = *src0++ * m0 + *src1++ * m1; | |
138 | *dst++ = *src0++ * m0 + *src1++ * m1; | |
139 | *dst++ = *src0++ * m0 + *src1++ * m1; | |
140 | len -= 4; | |
141 | } | |
142 | while (len > 0) { | |
143 | *dst++ = *src0++ * m0 + *src1++ * m1; | |
144 | len--; | |
145 | } | |
146 | } | |
147 | ||
148 | static void mix_2_to_1_s16p_flt_c(int16_t **samples, float **matrix, int len, | |
149 | int out_ch, int in_ch) | |
150 | { | |
151 | int16_t *src0 = samples[0]; | |
152 | int16_t *src1 = samples[1]; | |
153 | int16_t *dst = src0; | |
154 | float m0 = matrix[0][0]; | |
155 | float m1 = matrix[0][1]; | |
156 | ||
157 | while (len > 4) { | |
158 | *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1)); | |
159 | *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1)); | |
160 | *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1)); | |
161 | *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1)); | |
162 | len -= 4; | |
163 | } | |
164 | while (len > 0) { | |
165 | *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1)); | |
166 | len--; | |
167 | } | |
168 | } | |
169 | ||
170 | static void mix_2_to_1_s16p_q8_c(int16_t **samples, int16_t **matrix, int len, | |
171 | int out_ch, int in_ch) | |
172 | { | |
173 | int16_t *src0 = samples[0]; | |
174 | int16_t *src1 = samples[1]; | |
175 | int16_t *dst = src0; | |
176 | int16_t m0 = matrix[0][0]; | |
177 | int16_t m1 = matrix[0][1]; | |
178 | ||
179 | while (len > 4) { | |
180 | *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8; | |
181 | *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8; | |
182 | *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8; | |
183 | *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8; | |
184 | len -= 4; | |
185 | } | |
186 | while (len > 0) { | |
187 | *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8; | |
188 | len--; | |
189 | } | |
190 | } | |
191 | ||
192 | static void mix_1_to_2_fltp_flt_c(float **samples, float **matrix, int len, | |
193 | int out_ch, int in_ch) | |
194 | { | |
195 | float v; | |
196 | float *dst0 = samples[0]; | |
197 | float *dst1 = samples[1]; | |
198 | float *src = dst0; | |
199 | float m0 = matrix[0][0]; | |
200 | float m1 = matrix[1][0]; | |
201 | ||
202 | while (len > 4) { | |
203 | v = *src++; | |
204 | *dst0++ = v * m0; | |
205 | *dst1++ = v * m1; | |
206 | v = *src++; | |
207 | *dst0++ = v * m0; | |
208 | *dst1++ = v * m1; | |
209 | v = *src++; | |
210 | *dst0++ = v * m0; | |
211 | *dst1++ = v * m1; | |
212 | v = *src++; | |
213 | *dst0++ = v * m0; | |
214 | *dst1++ = v * m1; | |
215 | len -= 4; | |
216 | } | |
217 | while (len > 0) { | |
218 | v = *src++; | |
219 | *dst0++ = v * m0; | |
220 | *dst1++ = v * m1; | |
221 | len--; | |
222 | } | |
223 | } | |
224 | ||
225 | static void mix_6_to_2_fltp_flt_c(float **samples, float **matrix, int len, | |
226 | int out_ch, int in_ch) | |
227 | { | |
228 | float v0, v1; | |
229 | float *src0 = samples[0]; | |
230 | float *src1 = samples[1]; | |
231 | float *src2 = samples[2]; | |
232 | float *src3 = samples[3]; | |
233 | float *src4 = samples[4]; | |
234 | float *src5 = samples[5]; | |
235 | float *dst0 = src0; | |
236 | float *dst1 = src1; | |
237 | float *m0 = matrix[0]; | |
238 | float *m1 = matrix[1]; | |
239 | ||
240 | while (len > 0) { | |
241 | v0 = *src0++; | |
242 | v1 = *src1++; | |
243 | *dst0++ = v0 * m0[0] + | |
244 | v1 * m0[1] + | |
245 | *src2 * m0[2] + | |
246 | *src3 * m0[3] + | |
247 | *src4 * m0[4] + | |
248 | *src5 * m0[5]; | |
249 | *dst1++ = v0 * m1[0] + | |
250 | v1 * m1[1] + | |
251 | *src2++ * m1[2] + | |
252 | *src3++ * m1[3] + | |
253 | *src4++ * m1[4] + | |
254 | *src5++ * m1[5]; | |
255 | len--; | |
256 | } | |
257 | } | |
258 | ||
259 | static void mix_2_to_6_fltp_flt_c(float **samples, float **matrix, int len, | |
260 | int out_ch, int in_ch) | |
261 | { | |
262 | float v0, v1; | |
263 | float *dst0 = samples[0]; | |
264 | float *dst1 = samples[1]; | |
265 | float *dst2 = samples[2]; | |
266 | float *dst3 = samples[3]; | |
267 | float *dst4 = samples[4]; | |
268 | float *dst5 = samples[5]; | |
269 | float *src0 = dst0; | |
270 | float *src1 = dst1; | |
271 | ||
272 | while (len > 0) { | |
273 | v0 = *src0++; | |
274 | v1 = *src1++; | |
275 | *dst0++ = v0 * matrix[0][0] + v1 * matrix[0][1]; | |
276 | *dst1++ = v0 * matrix[1][0] + v1 * matrix[1][1]; | |
277 | *dst2++ = v0 * matrix[2][0] + v1 * matrix[2][1]; | |
278 | *dst3++ = v0 * matrix[3][0] + v1 * matrix[3][1]; | |
279 | *dst4++ = v0 * matrix[4][0] + v1 * matrix[4][1]; | |
280 | *dst5++ = v0 * matrix[5][0] + v1 * matrix[5][1]; | |
281 | len--; | |
282 | } | |
283 | } | |
284 | ||
285 | static av_cold int mix_function_init(AudioMix *am) | |
286 | { | |
287 | am->func_descr = am->func_descr_generic = "n/a"; | |
288 | am->mix = am->mix_generic = NULL; | |
289 | ||
290 | /* no need to set a mix function when we're skipping mixing */ | |
291 | if (!am->in_matrix_channels || !am->out_matrix_channels) | |
292 | return 0; | |
293 | ||
294 | /* any-to-any C versions */ | |
295 | ||
296 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | |
297 | 0, 0, 1, 1, "C", MIX_FUNC_NAME(FLTP, FLT)); | |
298 | ||
299 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT, | |
300 | 0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, FLT)); | |
301 | ||
302 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q15, | |
303 | 0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, Q15)); | |
304 | ||
305 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q8, | |
306 | 0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, Q8)); | |
307 | ||
308 | /* channel-specific C versions */ | |
309 | ||
310 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | |
311 | 2, 1, 1, 1, "C", mix_2_to_1_fltp_flt_c); | |
312 | ||
313 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT, | |
314 | 2, 1, 1, 1, "C", mix_2_to_1_s16p_flt_c); | |
315 | ||
316 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q8, | |
317 | 2, 1, 1, 1, "C", mix_2_to_1_s16p_q8_c); | |
318 | ||
319 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | |
320 | 1, 2, 1, 1, "C", mix_1_to_2_fltp_flt_c); | |
321 | ||
322 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | |
323 | 6, 2, 1, 1, "C", mix_6_to_2_fltp_flt_c); | |
324 | ||
325 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | |
326 | 2, 6, 1, 1, "C", mix_2_to_6_fltp_flt_c); | |
327 | ||
328 | if (ARCH_X86) | |
329 | ff_audio_mix_init_x86(am); | |
330 | ||
331 | if (!am->mix) { | |
332 | av_log(am->avr, AV_LOG_ERROR, "audio_mix: NO FUNCTION FOUND: [fmt=%s] " | |
333 | "[c=%s] [%d to %d]\n", av_get_sample_fmt_name(am->fmt), | |
334 | coeff_type_names[am->coeff_type], am->in_channels, | |
335 | am->out_channels); | |
336 | return AVERROR_PATCHWELCOME; | |
337 | } | |
338 | return 0; | |
339 | } | |
340 | ||
341 | AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr) | |
342 | { | |
343 | AudioMix *am; | |
344 | int ret; | |
345 | ||
346 | am = av_mallocz(sizeof(*am)); | |
347 | if (!am) | |
348 | return NULL; | |
349 | am->avr = avr; | |
350 | ||
351 | if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P && | |
352 | avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP) { | |
353 | av_log(avr, AV_LOG_ERROR, "Unsupported internal format for " | |
354 | "mixing: %s\n", | |
355 | av_get_sample_fmt_name(avr->internal_sample_fmt)); | |
356 | goto error; | |
357 | } | |
358 | ||
359 | am->fmt = avr->internal_sample_fmt; | |
360 | am->coeff_type = avr->mix_coeff_type; | |
361 | am->in_layout = avr->in_channel_layout; | |
362 | am->out_layout = avr->out_channel_layout; | |
363 | am->in_channels = avr->in_channels; | |
364 | am->out_channels = avr->out_channels; | |
365 | ||
366 | /* build matrix if the user did not already set one */ | |
367 | if (avr->mix_matrix) { | |
368 | ret = ff_audio_mix_set_matrix(am, avr->mix_matrix, avr->in_channels); | |
369 | if (ret < 0) | |
370 | goto error; | |
371 | av_freep(&avr->mix_matrix); | |
372 | } else { | |
373 | double *matrix_dbl = av_mallocz(avr->out_channels * avr->in_channels * | |
374 | sizeof(*matrix_dbl)); | |
375 | if (!matrix_dbl) | |
376 | goto error; | |
377 | ||
378 | ret = avresample_build_matrix(avr->in_channel_layout, | |
379 | avr->out_channel_layout, | |
380 | avr->center_mix_level, | |
381 | avr->surround_mix_level, | |
382 | avr->lfe_mix_level, | |
383 | avr->normalize_mix_level, | |
384 | matrix_dbl, | |
385 | avr->in_channels, | |
386 | avr->matrix_encoding); | |
387 | if (ret < 0) { | |
388 | av_free(matrix_dbl); | |
389 | goto error; | |
390 | } | |
391 | ||
392 | ret = ff_audio_mix_set_matrix(am, matrix_dbl, avr->in_channels); | |
393 | if (ret < 0) { | |
394 | av_log(avr, AV_LOG_ERROR, "error setting mix matrix\n"); | |
395 | av_free(matrix_dbl); | |
396 | goto error; | |
397 | } | |
398 | ||
399 | av_free(matrix_dbl); | |
400 | } | |
401 | ||
402 | return am; | |
403 | ||
404 | error: | |
405 | av_free(am); | |
406 | return NULL; | |
407 | } | |
408 | ||
409 | void ff_audio_mix_free(AudioMix **am_p) | |
410 | { | |
411 | AudioMix *am; | |
412 | ||
413 | if (!*am_p) | |
414 | return; | |
415 | am = *am_p; | |
416 | ||
417 | if (am->matrix) { | |
418 | av_free(am->matrix[0]); | |
419 | am->matrix = NULL; | |
420 | } | |
421 | memset(am->matrix_q8, 0, sizeof(am->matrix_q8 )); | |
422 | memset(am->matrix_q15, 0, sizeof(am->matrix_q15)); | |
423 | memset(am->matrix_flt, 0, sizeof(am->matrix_flt)); | |
424 | ||
425 | av_freep(am_p); | |
426 | } | |
427 | ||
428 | int ff_audio_mix(AudioMix *am, AudioData *src) | |
429 | { | |
430 | int use_generic = 1; | |
431 | int len = src->nb_samples; | |
432 | int i, j; | |
433 | ||
434 | /* determine whether to use the optimized function based on pointer and | |
435 | samples alignment in both the input and output */ | |
436 | if (am->has_optimized_func) { | |
437 | int aligned_len = FFALIGN(len, am->samples_align); | |
438 | if (!(src->ptr_align % am->ptr_align) && | |
439 | src->samples_align >= aligned_len) { | |
440 | len = aligned_len; | |
441 | use_generic = 0; | |
442 | } | |
443 | } | |
444 | av_dlog(am->avr, "audio_mix: %d samples - %d to %d channels (%s)\n", | |
445 | src->nb_samples, am->in_channels, am->out_channels, | |
446 | use_generic ? am->func_descr_generic : am->func_descr); | |
447 | ||
448 | if (am->in_matrix_channels && am->out_matrix_channels) { | |
449 | uint8_t **data; | |
450 | uint8_t *data0[AVRESAMPLE_MAX_CHANNELS] = { NULL }; | |
451 | ||
452 | if (am->out_matrix_channels < am->out_channels || | |
453 | am->in_matrix_channels < am->in_channels) { | |
454 | for (i = 0, j = 0; i < FFMAX(am->in_channels, am->out_channels); i++) { | |
455 | if (am->input_skip[i] || am->output_skip[i] || am->output_zero[i]) | |
456 | continue; | |
457 | data0[j++] = src->data[i]; | |
458 | } | |
459 | data = data0; | |
460 | } else { | |
461 | data = src->data; | |
462 | } | |
463 | ||
464 | if (use_generic) | |
465 | am->mix_generic(data, am->matrix, len, am->out_matrix_channels, | |
466 | am->in_matrix_channels); | |
467 | else | |
468 | am->mix(data, am->matrix, len, am->out_matrix_channels, | |
469 | am->in_matrix_channels); | |
470 | } | |
471 | ||
472 | if (am->out_matrix_channels < am->out_channels) { | |
473 | for (i = 0; i < am->out_channels; i++) | |
474 | if (am->output_zero[i]) | |
475 | av_samples_set_silence(&src->data[i], 0, len, 1, am->fmt); | |
476 | } | |
477 | ||
478 | ff_audio_data_set_channels(src, am->out_channels); | |
479 | ||
480 | return 0; | |
481 | } | |
482 | ||
483 | int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride) | |
484 | { | |
485 | int i, o, i0, o0; | |
486 | ||
487 | if ( am->in_channels <= 0 || am->in_channels > AVRESAMPLE_MAX_CHANNELS || | |
488 | am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) { | |
489 | av_log(am->avr, AV_LOG_ERROR, "Invalid channel counts\n"); | |
490 | return AVERROR(EINVAL); | |
491 | } | |
492 | ||
493 | #define GET_MATRIX_CONVERT(suffix, scale) \ | |
494 | if (!am->matrix_ ## suffix[0]) { \ | |
495 | av_log(am->avr, AV_LOG_ERROR, "matrix is not set\n"); \ | |
496 | return AVERROR(EINVAL); \ | |
497 | } \ | |
498 | for (o = 0, o0 = 0; o < am->out_channels; o++) { \ | |
499 | for (i = 0, i0 = 0; i < am->in_channels; i++) { \ | |
500 | if (am->input_skip[i] || am->output_zero[o]) \ | |
501 | matrix[o * stride + i] = 0.0; \ | |
502 | else \ | |
503 | matrix[o * stride + i] = am->matrix_ ## suffix[o0][i0] * \ | |
504 | (scale); \ | |
505 | if (!am->input_skip[i]) \ | |
506 | i0++; \ | |
507 | } \ | |
508 | if (!am->output_zero[o]) \ | |
509 | o0++; \ | |
510 | } | |
511 | ||
512 | switch (am->coeff_type) { | |
513 | case AV_MIX_COEFF_TYPE_Q8: | |
514 | GET_MATRIX_CONVERT(q8, 1.0 / 256.0); | |
515 | break; | |
516 | case AV_MIX_COEFF_TYPE_Q15: | |
517 | GET_MATRIX_CONVERT(q15, 1.0 / 32768.0); | |
518 | break; | |
519 | case AV_MIX_COEFF_TYPE_FLT: | |
520 | GET_MATRIX_CONVERT(flt, 1.0); | |
521 | break; | |
522 | default: | |
523 | av_log(am->avr, AV_LOG_ERROR, "Invalid mix coeff type\n"); | |
524 | return AVERROR(EINVAL); | |
525 | } | |
526 | ||
527 | return 0; | |
528 | } | |
529 | ||
530 | static void reduce_matrix(AudioMix *am, const double *matrix, int stride) | |
531 | { | |
532 | int i, o; | |
533 | ||
534 | memset(am->output_zero, 0, sizeof(am->output_zero)); | |
535 | memset(am->input_skip, 0, sizeof(am->input_skip)); | |
536 | memset(am->output_skip, 0, sizeof(am->output_skip)); | |
537 | ||
538 | /* exclude output channels if they can be zeroed instead of mixed */ | |
539 | for (o = 0; o < am->out_channels; o++) { | |
540 | int zero = 1; | |
541 | ||
542 | /* check if the output is always silent */ | |
543 | for (i = 0; i < am->in_channels; i++) { | |
544 | if (matrix[o * stride + i] != 0.0) { | |
545 | zero = 0; | |
546 | break; | |
547 | } | |
548 | } | |
549 | /* check if the corresponding input channel makes a contribution to | |
550 | any output channel */ | |
551 | if (o < am->in_channels) { | |
552 | for (i = 0; i < am->out_channels; i++) { | |
553 | if (matrix[i * stride + o] != 0.0) { | |
554 | zero = 0; | |
555 | break; | |
556 | } | |
557 | } | |
558 | } | |
559 | if (zero) { | |
560 | am->output_zero[o] = 1; | |
561 | am->out_matrix_channels--; | |
562 | if (o < am->in_channels) | |
563 | am->in_matrix_channels--; | |
564 | } | |
565 | } | |
566 | if (am->out_matrix_channels == 0 || am->in_matrix_channels == 0) { | |
567 | am->out_matrix_channels = 0; | |
568 | am->in_matrix_channels = 0; | |
569 | return; | |
570 | } | |
571 | ||
572 | /* skip input channels that contribute fully only to the corresponding | |
573 | output channel */ | |
574 | for (i = 0; i < FFMIN(am->in_channels, am->out_channels); i++) { | |
575 | int skip = 1; | |
576 | ||
577 | for (o = 0; o < am->out_channels; o++) { | |
578 | int i0; | |
579 | if ((o != i && matrix[o * stride + i] != 0.0) || | |
580 | (o == i && matrix[o * stride + i] != 1.0)) { | |
581 | skip = 0; | |
582 | break; | |
583 | } | |
584 | /* if the input contributes fully to the output, also check that no | |
585 | other inputs contribute to this output */ | |
586 | if (o == i) { | |
587 | for (i0 = 0; i0 < am->in_channels; i0++) { | |
588 | if (i0 != i && matrix[o * stride + i0] != 0.0) { | |
589 | skip = 0; | |
590 | break; | |
591 | } | |
592 | } | |
593 | } | |
594 | } | |
595 | if (skip) { | |
596 | am->input_skip[i] = 1; | |
597 | am->in_matrix_channels--; | |
598 | } | |
599 | } | |
600 | /* skip input channels that do not contribute to any output channel */ | |
601 | for (; i < am->in_channels; i++) { | |
602 | int contrib = 0; | |
603 | ||
604 | for (o = 0; o < am->out_channels; o++) { | |
605 | if (matrix[o * stride + i] != 0.0) { | |
606 | contrib = 1; | |
607 | break; | |
608 | } | |
609 | } | |
610 | if (!contrib) { | |
611 | am->input_skip[i] = 1; | |
612 | am->in_matrix_channels--; | |
613 | } | |
614 | } | |
615 | if (am->in_matrix_channels == 0) { | |
616 | am->out_matrix_channels = 0; | |
617 | return; | |
618 | } | |
619 | ||
620 | /* skip output channels that only get full contribution from the | |
621 | corresponding input channel */ | |
622 | for (o = 0; o < FFMIN(am->in_channels, am->out_channels); o++) { | |
623 | int skip = 1; | |
624 | int o0; | |
625 | ||
626 | for (i = 0; i < am->in_channels; i++) { | |
627 | if ((o != i && matrix[o * stride + i] != 0.0) || | |
628 | (o == i && matrix[o * stride + i] != 1.0)) { | |
629 | skip = 0; | |
630 | break; | |
631 | } | |
632 | } | |
633 | /* check if the corresponding input channel makes a contribution to | |
634 | any other output channel */ | |
635 | i = o; | |
636 | for (o0 = 0; o0 < am->out_channels; o0++) { | |
637 | if (o0 != i && matrix[o0 * stride + i] != 0.0) { | |
638 | skip = 0; | |
639 | break; | |
640 | } | |
641 | } | |
642 | if (skip) { | |
643 | am->output_skip[o] = 1; | |
644 | am->out_matrix_channels--; | |
645 | } | |
646 | } | |
647 | if (am->out_matrix_channels == 0) { | |
648 | am->in_matrix_channels = 0; | |
649 | return; | |
650 | } | |
651 | } | |
652 | ||
653 | int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride) | |
654 | { | |
655 | int i, o, i0, o0, ret; | |
656 | char in_layout_name[128]; | |
657 | char out_layout_name[128]; | |
658 | ||
659 | if ( am->in_channels <= 0 || am->in_channels > AVRESAMPLE_MAX_CHANNELS || | |
660 | am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) { | |
661 | av_log(am->avr, AV_LOG_ERROR, "Invalid channel counts\n"); | |
662 | return AVERROR(EINVAL); | |
663 | } | |
664 | ||
665 | if (am->matrix) { | |
666 | av_free(am->matrix[0]); | |
667 | am->matrix = NULL; | |
668 | } | |
669 | ||
670 | am->in_matrix_channels = am->in_channels; | |
671 | am->out_matrix_channels = am->out_channels; | |
672 | ||
673 | reduce_matrix(am, matrix, stride); | |
674 | ||
675 | #define CONVERT_MATRIX(type, expr) \ | |
676 | am->matrix_## type[0] = av_mallocz(am->out_matrix_channels * \ | |
677 | am->in_matrix_channels * \ | |
678 | sizeof(*am->matrix_## type[0])); \ | |
679 | if (!am->matrix_## type[0]) \ | |
680 | return AVERROR(ENOMEM); \ | |
681 | for (o = 0, o0 = 0; o < am->out_channels; o++) { \ | |
682 | if (am->output_zero[o] || am->output_skip[o]) \ | |
683 | continue; \ | |
684 | if (o0 > 0) \ | |
685 | am->matrix_## type[o0] = am->matrix_## type[o0 - 1] + \ | |
686 | am->in_matrix_channels; \ | |
687 | for (i = 0, i0 = 0; i < am->in_channels; i++) { \ | |
688 | double v; \ | |
689 | if (am->input_skip[i] || am->output_zero[i]) \ | |
690 | continue; \ | |
691 | v = matrix[o * stride + i]; \ | |
692 | am->matrix_## type[o0][i0] = expr; \ | |
693 | i0++; \ | |
694 | } \ | |
695 | o0++; \ | |
696 | } \ | |
697 | am->matrix = (void **)am->matrix_## type; | |
698 | ||
699 | if (am->in_matrix_channels && am->out_matrix_channels) { | |
700 | switch (am->coeff_type) { | |
701 | case AV_MIX_COEFF_TYPE_Q8: | |
702 | CONVERT_MATRIX(q8, av_clip_int16(lrint(256.0 * v))) | |
703 | break; | |
704 | case AV_MIX_COEFF_TYPE_Q15: | |
705 | CONVERT_MATRIX(q15, av_clipl_int32(llrint(32768.0 * v))) | |
706 | break; | |
707 | case AV_MIX_COEFF_TYPE_FLT: | |
708 | CONVERT_MATRIX(flt, v) | |
709 | break; | |
710 | default: | |
711 | av_log(am->avr, AV_LOG_ERROR, "Invalid mix coeff type\n"); | |
712 | return AVERROR(EINVAL); | |
713 | } | |
714 | } | |
715 | ||
716 | ret = mix_function_init(am); | |
717 | if (ret < 0) | |
718 | return ret; | |
719 | ||
720 | av_get_channel_layout_string(in_layout_name, sizeof(in_layout_name), | |
721 | am->in_channels, am->in_layout); | |
722 | av_get_channel_layout_string(out_layout_name, sizeof(out_layout_name), | |
723 | am->out_channels, am->out_layout); | |
724 | av_log(am->avr, AV_LOG_DEBUG, "audio_mix: %s to %s\n", | |
725 | in_layout_name, out_layout_name); | |
726 | av_log(am->avr, AV_LOG_DEBUG, "matrix size: %d x %d\n", | |
727 | am->in_matrix_channels, am->out_matrix_channels); | |
728 | for (o = 0; o < am->out_channels; o++) { | |
729 | for (i = 0; i < am->in_channels; i++) { | |
730 | if (am->output_zero[o]) | |
731 | av_log(am->avr, AV_LOG_DEBUG, " (ZERO)"); | |
732 | else if (am->input_skip[i] || am->output_zero[i] || am->output_skip[o]) | |
733 | av_log(am->avr, AV_LOG_DEBUG, " (SKIP)"); | |
734 | else | |
735 | av_log(am->avr, AV_LOG_DEBUG, " %0.3f ", | |
736 | matrix[o * am->in_channels + i]); | |
737 | } | |
738 | av_log(am->avr, AV_LOG_DEBUG, "\n"); | |
739 | } | |
740 | ||
741 | return 0; | |
742 | } |