diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2012-12-12 10:31:49 +0100 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2012-12-12 10:31:56 +0100 |
commit | 82c0211213430a9aef0d6ef5b29de35043f5bcba (patch) | |
tree | c6b102b3756f9be53f28f6a0e078ed9d12861ac0 /libavresample/audio_mix.c | |
parent | 8dbc384f1527446b07eb6a673101f765e67f3eca (diff) | |
parent | 14758e3211d34a97c42b07acae117ce5627d7f57 (diff) | |
download | ffmpeg-82c0211213430a9aef0d6ef5b29de35043f5bcba.tar.gz |
Merge commit '14758e3211d34a97c42b07acae117ce5627d7f57'
* commit '14758e3211d34a97c42b07acae117ce5627d7f57':
lavr: temporarily store custom matrix in AVAudioResampleContext
lavr: clarify documentation for avresample_get/set_matrix()
Merged-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavresample/audio_mix.c')
-rw-r--r-- | libavresample/audio_mix.c | 154 |
1 files changed, 128 insertions, 26 deletions
diff --git a/libavresample/audio_mix.c b/libavresample/audio_mix.c index dd2f33d27f..3b39ceeca5 100644 --- a/libavresample/audio_mix.c +++ b/libavresample/audio_mix.c @@ -302,27 +302,37 @@ static int mix_function_init(AudioMix *am) return 0; } -int ff_audio_mix_init(AVAudioResampleContext *avr) +AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr) { + AudioMix *am; int ret; + am = av_mallocz(sizeof(*am)); + if (!am) + return NULL; + am->avr = avr; + if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P && avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP) { av_log(avr, AV_LOG_ERROR, "Unsupported internal format for " "mixing: %s\n", av_get_sample_fmt_name(avr->internal_sample_fmt)); - return AVERROR(EINVAL); + goto error; } + am->fmt = avr->internal_sample_fmt; + am->coeff_type = avr->mix_coeff_type; + am->in_layout = avr->in_channel_layout; + am->out_layout = avr->out_channel_layout; + am->in_channels = avr->in_channels; + am->out_channels = avr->out_channels; + /* build matrix if the user did not already set one */ - if (avr->am->matrix) { - if (avr->am->coeff_type != avr->mix_coeff_type || - avr->am->in_layout != avr->in_channel_layout || - avr->am->out_layout != avr->out_channel_layout) { - av_log(avr, AV_LOG_ERROR, - "Custom matrix does not match current parameters\n"); - return AVERROR(EINVAL); - } + if (avr->mix_matrix) { + ret = ff_audio_mix_set_matrix(am, avr->mix_matrix, avr->in_channels); + if (ret < 0) + goto error; + av_freep(&avr->mix_matrix); } else { int i, j; char in_layout_name[128]; @@ -330,7 +340,7 @@ int ff_audio_mix_init(AVAudioResampleContext *avr) double *matrix_dbl = av_mallocz(avr->out_channels * avr->in_channels * sizeof(*matrix_dbl)); if (!matrix_dbl) - return AVERROR(ENOMEM); + goto error; ret = avresample_build_matrix(avr->in_channel_layout, avr->out_channel_layout, @@ -343,7 +353,7 @@ int ff_audio_mix_init(AVAudioResampleContext *avr) avr->matrix_encoding); if (ret < 0) { av_free(matrix_dbl); - return ret; + goto error; } av_get_channel_layout_string(in_layout_name, sizeof(in_layout_name), @@ -360,32 +370,33 @@ int ff_audio_mix_init(AVAudioResampleContext *avr) av_log(avr, AV_LOG_DEBUG, "\n"); } - ret = avresample_set_matrix(avr, matrix_dbl, avr->in_channels); + ret = ff_audio_mix_set_matrix(am, matrix_dbl, avr->in_channels); if (ret < 0) { av_free(matrix_dbl); - return ret; + goto error; } av_free(matrix_dbl); } - avr->am->fmt = avr->internal_sample_fmt; - avr->am->coeff_type = avr->mix_coeff_type; - avr->am->in_layout = avr->in_channel_layout; - avr->am->out_layout = avr->out_channel_layout; - avr->am->in_channels = avr->in_channels; - avr->am->out_channels = avr->out_channels; - - ret = mix_function_init(avr->am); + ret = mix_function_init(am); if (ret < 0) - return ret; + goto error; - return 0; + return am; + +error: + av_free(am); + return NULL; } -void ff_audio_mix_close(AudioMix *am) +void ff_audio_mix_free(AudioMix **am_p) { - if (!am) + AudioMix *am; + + if (!*am_p) return; + am = *am_p; + if (am->matrix) { av_free(am->matrix[0]); am->matrix = NULL; @@ -393,6 +404,8 @@ void ff_audio_mix_close(AudioMix *am) memset(am->matrix_q8, 0, sizeof(am->matrix_q8 )); memset(am->matrix_q15, 0, sizeof(am->matrix_q15)); memset(am->matrix_flt, 0, sizeof(am->matrix_flt)); + + av_freep(am_p); } int ff_audio_mix(AudioMix *am, AudioData *src) @@ -424,3 +437,92 @@ int ff_audio_mix(AudioMix *am, AudioData *src) return 0; } + +int ff_audio_mix_get_matrix(AudioMix *am, 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, AV_LOG_ERROR, "Invalid channel counts\n"); + return AVERROR(EINVAL); + } + +#define GET_MATRIX_CONVERT(suffix, scale) \ + if (!am->matrix_ ## suffix[0]) { \ + av_log(am, AV_LOG_ERROR, "matrix is not set\n"); \ + return AVERROR(EINVAL); \ + } \ + for (o = 0; o < am->out_channels; o++) \ + for (i = 0; i < am->in_channels; i++) \ + matrix[o * stride + i] = am->matrix_ ## suffix[o][i] * (scale); + + switch (am->coeff_type) { + case AV_MIX_COEFF_TYPE_Q8: + GET_MATRIX_CONVERT(q8, 1.0 / 256.0); + break; + case AV_MIX_COEFF_TYPE_Q15: + GET_MATRIX_CONVERT(q15, 1.0 / 32768.0); + break; + case AV_MIX_COEFF_TYPE_FLT: + GET_MATRIX_CONVERT(flt, 1.0); + break; + default: + av_log(am, AV_LOG_ERROR, "Invalid mix coeff type\n"); + return AVERROR(EINVAL); + } + + return 0; +} + +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, 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, AV_LOG_ERROR, "Invalid mix coeff type\n"); + return AVERROR(EINVAL); + } + + /* TODO: detect situations where we can just swap around pointers + instead of doing matrix multiplications with 0.0 and 1.0 */ + + return 0; +} |