}
}
-static int mix_function_init(AudioMix *am)
+static av_cold int mix_function_init(AudioMix *am)
{
am->func_descr = am->func_descr_generic = "n/a";
am->mix = am->mix_generic = NULL;
return 0;
}
-int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride)
+static void reduce_matrix(AudioMix *am, const double *matrix, int stride)
{
- int i, o, i0, o0, ret;
- char in_layout_name[128];
- char out_layout_name[128];
-
- if ( am->in_channels <= 0 || am->in_channels > AVRESAMPLE_MAX_CHANNELS ||
- am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) {
- av_log(am->avr, AV_LOG_ERROR, "Invalid channel counts\n");
- return AVERROR(EINVAL);
- }
-
- if (am->matrix) {
- av_free(am->matrix[0]);
- am->matrix = NULL;
- }
+ int i, o;
memset(am->output_zero, 0, sizeof(am->output_zero));
memset(am->input_skip, 0, sizeof(am->input_skip));
- memset(am->output_skip, 0, sizeof(am->output_zero));
- am->in_matrix_channels = am->in_channels;
- am->out_matrix_channels = am->out_channels;
+ memset(am->output_skip, 0, sizeof(am->output_skip));
/* exclude output channels if they can be zeroed instead of mixed */
for (o = 0; o < am->out_channels; o++) {
}
if (am->out_matrix_channels == 0) {
am->in_matrix_channels = 0;
- return 0;
+ return;
}
/* skip input channels that contribute fully only to the corresponding
int skip = 1;
for (o = 0; o < am->out_channels; o++) {
+ int i0;
if ((o != i && matrix[o * stride + i] != 0.0) ||
(o == i && matrix[o * stride + i] != 1.0)) {
skip = 0;
break;
}
+ /* if the input contributes fully to the output, also check that no
+ other inputs contribute to this output */
+ if (o == i) {
+ for (i0 = 0; i0 < am->in_channels; i0++) {
+ if (i0 != i && matrix[o * stride + i0] != 0.0) {
+ skip = 0;
+ break;
+ }
+ }
+ }
}
if (skip) {
am->input_skip[i] = 1;
}
if (am->in_matrix_channels == 0) {
am->out_matrix_channels = 0;
- return 0;
+ return;
}
/* skip output channels that only get full contribution from the
corresponding input channel */
for (o = 0; o < FFMIN(am->in_channels, am->out_channels); o++) {
int skip = 1;
+ int o0;
for (i = 0; i < am->in_channels; i++) {
if ((o != i && matrix[o * stride + i] != 0.0) ||
break;
}
}
+ /* check if the corresponding input channel makes a contribution to
+ any other output channel */
+ i = o;
+ for (o0 = 0; o0 < am->out_channels; o0++) {
+ if (o0 != i && matrix[o0 * stride + i] != 0.0) {
+ skip = 0;
+ break;
+ }
+ }
if (skip) {
am->output_skip[o] = 1;
am->out_matrix_channels--;
}
if (am->out_matrix_channels == 0) {
am->in_matrix_channels = 0;
- return 0;
+ return;
+ }
+}
+
+int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride)
+{
+ int i, o, i0, o0, ret;
+ char in_layout_name[128];
+ char out_layout_name[128];
+
+ if ( am->in_channels <= 0 || am->in_channels > AVRESAMPLE_MAX_CHANNELS ||
+ am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) {
+ av_log(am->avr, AV_LOG_ERROR, "Invalid channel counts\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (am->matrix) {
+ av_free(am->matrix[0]);
+ am->matrix = NULL;
}
+ am->in_matrix_channels = am->in_channels;
+ am->out_matrix_channels = am->out_channels;
+
+ reduce_matrix(am, matrix, stride);
+
#define CONVERT_MATRIX(type, expr) \
am->matrix_## type[0] = av_mallocz(am->out_matrix_channels * \
am->in_matrix_channels * \
} \
am->matrix = (void **)am->matrix_## type;
- switch (am->coeff_type) {
- case AV_MIX_COEFF_TYPE_Q8:
- CONVERT_MATRIX(q8, av_clip_int16(lrint(256.0 * v)))
- break;
- case AV_MIX_COEFF_TYPE_Q15:
- CONVERT_MATRIX(q15, av_clipl_int32(llrint(32768.0 * v)))
- break;
- case AV_MIX_COEFF_TYPE_FLT:
- CONVERT_MATRIX(flt, v)
- break;
- default:
- av_log(am->avr, AV_LOG_ERROR, "Invalid mix coeff type\n");
- return AVERROR(EINVAL);
+ if (am->in_matrix_channels && am->out_matrix_channels) {
+ switch (am->coeff_type) {
+ case AV_MIX_COEFF_TYPE_Q8:
+ CONVERT_MATRIX(q8, av_clip_int16(lrint(256.0 * v)))
+ break;
+ case AV_MIX_COEFF_TYPE_Q15:
+ CONVERT_MATRIX(q15, av_clipl_int32(llrint(32768.0 * v)))
+ break;
+ case AV_MIX_COEFF_TYPE_FLT:
+ CONVERT_MATRIX(flt, v)
+ break;
+ default:
+ av_log(am->avr, AV_LOG_ERROR, "Invalid mix coeff type\n");
+ return AVERROR(EINVAL);
+ }
}
ret = mix_function_init(am);