summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libavresample/audio_mix.c154
-rw-r--r--libavresample/audio_mix.h24
-rw-r--r--libavresample/audio_mix_matrix.c112
-rw-r--r--libavresample/internal.h6
-rw-r--r--libavresample/options.c7
-rw-r--r--libavresample/utils.c71
6 files changed, 216 insertions, 158 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;
+}
diff --git a/libavresample/audio_mix.h b/libavresample/audio_mix.h
index 2199fffe0e..22faea7c1b 100644
--- a/libavresample/audio_mix.h
+++ b/libavresample/audio_mix.h
@@ -79,28 +79,36 @@ void ff_audio_mix_set_func(AudioMix *am, enum AVSampleFormat fmt,
const char *descr, void *mix_func);
/**
- * Initialize the AudioMix context in the AVAudioResampleContext.
+ * Allocate and initialize an AudioMix context.
*
* The parameters in the AVAudioResampleContext are used to initialize the
- * AudioMix context and set the mixing matrix.
+ * AudioMix context.
*
* @param avr AVAudioResampleContext
- * @return 0 on success, negative AVERROR code on failure
+ * @return newly-allocated AudioMix context.
*/
-int ff_audio_mix_init(AVAudioResampleContext *avr);
+AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr);
/**
- * Close an AudioMix context.
- *
- * This clears and frees the mixing matrix arrays.
+ * Free an AudioMix context.
*/
-void ff_audio_mix_close(AudioMix *am);
+void ff_audio_mix_free(AudioMix **am);
/**
* Apply channel mixing to audio data using the current mixing matrix.
*/
int ff_audio_mix(AudioMix *am, AudioData *src);
+/**
+ * Get the current mixing matrix.
+ */
+int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride);
+
+/**
+ * Set the current mixing matrix.
+ */
+int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride);
+
/* arch-specific initialization functions */
void ff_audio_mix_init_x86(AudioMix *am);
diff --git a/libavresample/audio_mix_matrix.c b/libavresample/audio_mix_matrix.c
index 01a93367ef..8da1b487a4 100644
--- a/libavresample/audio_mix_matrix.c
+++ b/libavresample/audio_mix_matrix.c
@@ -287,115 +287,3 @@ int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout,
return 0;
}
-
-int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix,
- int stride)
-{
- int in_channels, out_channels, i, o;
-
- in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout);
- out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
-
- if ( in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS ||
- out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
- av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
- return AVERROR(EINVAL);
- }
-
- switch (avr->mix_coeff_type) {
- case AV_MIX_COEFF_TYPE_Q8:
- if (!avr->am->matrix_q8[0]) {
- av_log(avr, AV_LOG_ERROR, "matrix is not set\n");
- return AVERROR(EINVAL);
- }
- for (o = 0; o < out_channels; o++)
- for (i = 0; i < in_channels; i++)
- matrix[o * stride + i] = avr->am->matrix_q8[o][i] / 256.0;
- break;
- case AV_MIX_COEFF_TYPE_Q15:
- if (!avr->am->matrix_q15[0]) {
- av_log(avr, AV_LOG_ERROR, "matrix is not set\n");
- return AVERROR(EINVAL);
- }
- for (o = 0; o < out_channels; o++)
- for (i = 0; i < in_channels; i++)
- matrix[o * stride + i] = avr->am->matrix_q15[o][i] / 32768.0;
- break;
- case AV_MIX_COEFF_TYPE_FLT:
- if (!avr->am->matrix_flt[0]) {
- av_log(avr, AV_LOG_ERROR, "matrix is not set\n");
- return AVERROR(EINVAL);
- }
- for (o = 0; o < out_channels; o++)
- for (i = 0; i < in_channels; i++)
- matrix[o * stride + i] = avr->am->matrix_flt[o][i];
- break;
- default:
- av_log(avr, AV_LOG_ERROR, "Invalid mix coeff type\n");
- return AVERROR(EINVAL);
- }
-
- return 0;
-}
-
-int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
- int stride)
-{
- int in_channels, out_channels, i, o;
-
- in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout);
- out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
-
- if ( in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS ||
- out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
- av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
- return AVERROR(EINVAL);
- }
-
- if (avr->am->matrix) {
- av_free(avr->am->matrix[0]);
- avr->am->matrix = NULL;
- }
-
-#define CONVERT_MATRIX(type, expr) \
- avr->am->matrix_## type[0] = av_mallocz(out_channels * in_channels * \
- sizeof(*avr->am->matrix_## type[0])); \
- if (!avr->am->matrix_## type[0]) \
- return AVERROR(ENOMEM); \
- for (o = 0; o < out_channels; o++) { \
- if (o > 0) \
- avr->am->matrix_## type[o] = avr->am->matrix_## type[o - 1] + \
- in_channels; \
- for (i = 0; i < in_channels; i++) { \
- double v = matrix[o * stride + i]; \
- avr->am->matrix_## type[o][i] = expr; \
- } \
- } \
- avr->am->matrix = (void **)avr->am->matrix_## type;
-
- switch (avr->mix_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(avr, 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 */
-
- /* set AudioMix params */
- avr->am->in_layout = avr->in_channel_layout;
- avr->am->out_layout = avr->out_channel_layout;
- avr->am->in_channels = in_channels;
- avr->am->out_channels = out_channels;
-
- return 0;
-}
diff --git a/libavresample/internal.h b/libavresample/internal.h
index 006b6fd14a..3fd33fed6a 100644
--- a/libavresample/internal.h
+++ b/libavresample/internal.h
@@ -74,6 +74,12 @@ struct AVAudioResampleContext {
ResampleContext *resample; /**< resampling context */
AudioMix *am; /**< channel mixing context */
enum AVMatrixEncoding matrix_encoding; /**< matrixed stereo encoding */
+
+ /**
+ * mix matrix
+ * only used if avresample_set_matrix() is called before avresample_open()
+ */
+ double *mix_matrix;
};
#endif /* AVRESAMPLE_INTERNAL_H */
diff --git a/libavresample/options.c b/libavresample/options.c
index 8f643700cb..824f5e3bc3 100644
--- a/libavresample/options.c
+++ b/libavresample/options.c
@@ -84,13 +84,6 @@ AVAudioResampleContext *avresample_alloc_context(void)
avr->av_class = &av_resample_context_class;
av_opt_set_defaults(avr);
- avr->am = av_mallocz(sizeof(*avr->am));
- if (!avr->am) {
- av_free(avr);
- return NULL;
- }
- avr->am->avr = avr;
-
return avr;
}
diff --git a/libavresample/utils.c b/libavresample/utils.c
index 3fdeeb8cc0..8245e6a345 100644
--- a/libavresample/utils.c
+++ b/libavresample/utils.c
@@ -169,9 +169,11 @@ int avresample_open(AVAudioResampleContext *avr)
}
}
if (avr->mixing_needed) {
- ret = ff_audio_mix_init(avr);
- if (ret < 0)
+ avr->am = ff_audio_mix_alloc(avr);
+ if (!avr->am) {
+ ret = AVERROR(ENOMEM);
goto error;
+ }
}
return 0;
@@ -191,8 +193,8 @@ void avresample_close(AVAudioResampleContext *avr)
av_freep(&avr->ac_in);
av_freep(&avr->ac_out);
ff_audio_resample_free(&avr->resample);
- ff_audio_mix_close(avr->am);
- return;
+ ff_audio_mix_free(&avr->am);
+ av_freep(&avr->mix_matrix);
}
void avresample_free(AVAudioResampleContext **avr)
@@ -200,7 +202,6 @@ void avresample_free(AVAudioResampleContext **avr)
if (!*avr)
return;
avresample_close(*avr);
- av_freep(&(*avr)->am);
av_opt_free(*avr);
av_freep(avr);
}
@@ -404,6 +405,66 @@ int attribute_align_arg avresample_convert(AVAudioResampleContext *avr,
current_buffer);
}
+int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix,
+ int stride)
+{
+ int in_channels, out_channels, i, o;
+
+ if (avr->am)
+ return ff_audio_mix_get_matrix(avr->am, matrix, stride);
+
+ in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout);
+ out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
+
+ if ( in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS ||
+ out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
+ av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (!avr->mix_matrix) {
+ av_log(avr, AV_LOG_ERROR, "matrix is not set\n");
+ return AVERROR(EINVAL);
+ }
+
+ for (o = 0; o < out_channels; o++)
+ for (i = 0; i < in_channels; i++)
+ matrix[o * stride + i] = avr->mix_matrix[o * in_channels + i];
+
+ return 0;
+}
+
+int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
+ int stride)
+{
+ int in_channels, out_channels, i, o;
+
+ if (avr->am)
+ return ff_audio_mix_set_matrix(avr->am, matrix, stride);
+
+ in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout);
+ out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
+
+ if ( in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS ||
+ out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
+ av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (avr->mix_matrix)
+ av_freep(&avr->mix_matrix);
+ avr->mix_matrix = av_malloc(in_channels * out_channels *
+ sizeof(*avr->mix_matrix));
+ if (!avr->mix_matrix)
+ return AVERROR(ENOMEM);
+
+ for (o = 0; o < out_channels; o++)
+ for (i = 0; i < in_channels; i++)
+ avr->mix_matrix[o * in_channels + i] = matrix[o * stride + i];
+
+ return 0;
+}
+
int avresample_available(AVAudioResampleContext *avr)
{
return av_audio_fifo_size(avr->out_fifo);