int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride) { int i, o; 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; } #define CONVERT_MATRIX(type, expr) \ am->matrix_## type[0] = av_mallocz(am->out_channels * am->in_channels * \ sizeof(*am->matrix_## type[0])); \ if (!am->matrix_## type[0]) \ return AVERROR(ENOMEM); \ for (o = 0; o < am->out_channels; o++) { \ if (o > 0) \ am->matrix_## type[o] = am->matrix_## type[o - 1] + \ am->in_channels; \ for (i = 0; i < am->in_channels; i++) { \ double v = matrix[o * stride + i]; \ am->matrix_## type[o][i] = expr; \ } \ } \ 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); } return mix_function_init(am); }
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 * \ sizeof(*am->matrix_## type[0])); \ if (!am->matrix_## type[0]) \ return AVERROR(ENOMEM); \ for (o = 0, o0 = 0; o < am->out_channels; o++) { \ if (am->output_zero[o] || am->output_skip[o]) \ continue; \ if (o0 > 0) \ am->matrix_## type[o0] = am->matrix_## type[o0 - 1] + \ am->in_matrix_channels; \ for (i = 0, i0 = 0; i < am->in_channels; i++) { \ double v; \ if (am->input_skip[i]) \ continue; \ v = matrix[o * stride + i]; \ am->matrix_## type[o0][i0] = expr; \ i0++; \ } \ o0++; \ } \ am->matrix = (void **)am->matrix_## type; 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); if (ret < 0) return ret; av_get_channel_layout_string(in_layout_name, sizeof(in_layout_name), am->in_channels, am->in_layout); av_get_channel_layout_string(out_layout_name, sizeof(out_layout_name), am->out_channels, am->out_layout); av_log(am->avr, AV_LOG_DEBUG, "audio_mix: %s to %s\n", in_layout_name, out_layout_name); av_log(am->avr, AV_LOG_DEBUG, "matrix size: %d x %d\n", am->in_matrix_channels, am->out_matrix_channels); for (o = 0; o < am->out_channels; o++) { for (i = 0; i < am->in_channels; i++) { if (am->output_zero[o]) av_log(am->avr, AV_LOG_DEBUG, " (ZERO)"); else if (am->input_skip[i] || am->output_skip[o]) av_log(am->avr, AV_LOG_DEBUG, " (SKIP)"); else av_log(am->avr, AV_LOG_DEBUG, " %0.3f ", matrix[o * am->in_channels + i]); } av_log(am->avr, AV_LOG_DEBUG, "\n"); } return 0; }
int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride) { int i, o, i0, o0; 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; } 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; /* exclude output channels if they can be zeroed instead of mixed */ for (o = 0; o < am->out_channels; o++) { int zero = 1; /* check if the output is always silent */ for (i = 0; i < am->in_channels; i++) { if (matrix[o * stride + i] != 0.0) { zero = 0; break; } } /* check if the corresponding input channel makes a contribution to any output channel */ if (o < am->in_channels) { for (i = 0; i < am->out_channels; i++) { if (matrix[i * stride + o] != 0.0) { zero = 0; break; } } } if (zero) { am->output_zero[o] = 1; am->out_matrix_channels--; } } if (am->out_matrix_channels == 0) { am->in_matrix_channels = 0; return 0; } /* skip input channels that contribute fully only to the corresponding output channel */ for (i = 0; i < FFMIN(am->in_channels, am->out_channels); i++) { int skip = 1; for (o = 0; o < am->out_channels; o++) { if ((o != i && matrix[o * stride + i] != 0.0) || (o == i && matrix[o * stride + i] != 1.0)) { skip = 0; break; } } if (skip) { am->input_skip[i] = 1; am->in_matrix_channels--; } } /* skip input channels that do not contribute to any output channel */ for (; i < am->in_channels; i++) { int contrib = 0; for (o = 0; o < am->out_channels; o++) { if (matrix[o * stride + i] != 0.0) { contrib = 1; break; } } if (!contrib) { am->input_skip[i] = 1; am->in_matrix_channels--; } } if (am->in_matrix_channels == 0) { am->out_matrix_channels = 0; return 0; } /* 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; for (i = 0; i < am->in_channels; i++) { if ((o != i && matrix[o * stride + i] != 0.0) || (o == i && matrix[o * stride + i] != 1.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; } #define CONVERT_MATRIX(type, expr) \ am->matrix_## type[0] = av_mallocz(am->out_matrix_channels * \ am->in_matrix_channels * \ sizeof(*am->matrix_## type[0])); \ if (!am->matrix_## type[0]) \ return AVERROR(ENOMEM); \ for (o = 0, o0 = 0; o < am->out_channels; o++) { \ if (am->output_zero[o] || am->output_skip[o]) \ continue; \ if (o0 > 0) \ am->matrix_## type[o0] = am->matrix_## type[o0 - 1] + \ am->in_matrix_channels; \ for (i = 0, i0 = 0; i < am->in_channels; i++) { \ double v; \ if (am->input_skip[i]) \ continue; \ v = matrix[o * stride + i]; \ am->matrix_## type[o0][i0] = expr; \ i0++; \ } \ o0++; \ } \ 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); } return mix_function_init(am); }