---
Oops. Rebasing mistake in the last patch. This is the correct one.
doc/APIchanges | 3 +++
libavresample/audio_mix.c | 42 +++++++++++++++++++++++++++++++++++-------
libavresample/avresample.h | 33 ++++++++++++++++++++++++++++++++-
libavresample/internal.h | 2 ++
libavresample/utils.c | 41 ++++++++++++++++++++++++++++++++++++++++-
libavresample/version.h | 2 +-
6 files changed, 113 insertions(+), 10 deletions(-)
diff --git a/doc/APIchanges b/doc/APIchanges
index 1c6247e..096f222 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -13,6 +13,9 @@ libavutil: 2012-10-22
API changes, most recent first:
+2012-xx-xx - xxxxxxx - lavr 1.1.0
+ Add avresample_set_channel_mapping()
+
2012-xx-xx - xxxxxxx - lavu 52.2.0 - audioconvert.h
Rename audioconvert.h to channel_layout.h. audioconvert.h is now deprecated.
diff --git a/libavresample/audio_mix.c b/libavresample/audio_mix.c
index 62f8bd6..988ab7e 100644
--- a/libavresample/audio_mix.c
+++ b/libavresample/audio_mix.c
@@ -51,6 +51,8 @@ struct AudioMix {
int32_t *matrix_q15[AVRESAMPLE_MAX_CHANNELS];
float *matrix_flt[AVRESAMPLE_MAX_CHANNELS];
void **matrix;
+
+ int *channel_map;
};
void ff_audio_mix_set_func(AudioMix *am, enum AVSampleFormat fmt,
@@ -350,6 +352,20 @@ AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr)
am->in_channels = avr->in_channels;
am->out_channels = avr->out_channels;
+ if (avr->channel_map) {
+ am->channel_map = avr->channel_map;
+ avr->channel_map = NULL;
+ } else {
+ int i;
+
+ am->channel_map = av_malloc(am->in_channels *
sizeof(*am->channel_map));
+ if (!am->channel_map)
+ goto error;
+
+ for (i = 0; i < am->in_channels; i++)
+ am->channel_map[i] = i;
+ }
+
/* build matrix if the user did not already set one */
if (avr->mix_matrix) {
ret = ff_audio_mix_set_matrix(am, avr->mix_matrix, avr->in_channels);
@@ -379,6 +395,16 @@ AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr)
goto error;
}
+ ret = ff_audio_mix_set_matrix(am, matrix_dbl, avr->in_channels);
+ if (ret < 0) {
+ av_free(matrix_dbl);
+ goto error;
+ }
+ ret = ff_audio_mix_get_matrix(am, matrix_dbl, avr->in_channels);
+ if (ret < 0) {
+ av_free(matrix_dbl);
+ goto error;
+ }
av_get_channel_layout_string(in_layout_name, sizeof(in_layout_name),
avr->in_channels, avr->in_channel_layout);
av_get_channel_layout_string(out_layout_name, sizeof(out_layout_name),
@@ -393,11 +419,6 @@ AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr)
av_log(avr, AV_LOG_DEBUG, "\n");
}
- ret = ff_audio_mix_set_matrix(am, matrix_dbl, avr->in_channels);
- if (ret < 0) {
- av_free(matrix_dbl);
- goto error;
- }
av_free(matrix_dbl);
}
@@ -408,6 +429,7 @@ AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr)
return am;
error:
+ av_free(am->channel_map);
av_free(am);
return NULL;
}
@@ -428,6 +450,8 @@ void ff_audio_mix_free(AudioMix **am_p)
memset(am->matrix_q15, 0, sizeof(am->matrix_q15));
memset(am->matrix_flt, 0, sizeof(am->matrix_flt));
+ av_freep(&am->channel_map);
+
av_freep(am_p);
}
@@ -523,8 +547,12 @@ int ff_audio_mix_set_matrix(AudioMix *am, const double
*matrix, int stride)
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; \
+ if (am->channel_map[i] < 0) { \
+ am->matrix_## type[o][am->channel_map[i]] = 0; \
+ } else { \
+ double v = matrix[o * stride + i]; \
+ am->matrix_## type[o][am->channel_map[i]] = expr; \
+ } \
} \
} \
am->matrix = (void **)am->matrix_## type;
diff --git a/libavresample/avresample.h b/libavresample/avresample.h
index a73d686..8c27bfc 100644
--- a/libavresample/avresample.h
+++ b/libavresample/avresample.h
@@ -168,7 +168,8 @@ int avresample_open(AVAudioResampleContext *avr);
* This closes the context, but it does not change the parameters. The context
* can be reopened with avresample_open(). It does, however, clear the output
* FIFO and any remaining leftover samples in the resampling delay buffer. If
- * there was a custom matrix being used, that is also cleared.
+ * there was a custom matrix or channel mapping being used, those are also
+ * cleared.
*
* @see avresample_convert()
* @see avresample_set_matrix()
@@ -219,6 +220,10 @@ int avresample_build_matrix(uint64_t in_layout, uint64_t
out_layout,
* If no custom matrix has been previously set or the AVAudioResampleContext is
* not open, an error is returned.
*
+ * If a custom channel mapping is being used, the returned matrix will take the
+ * channel mapping into account if this function is called while the context
+ * is open.
+ *
* @param avr audio resample context
* @param matrix mixing coefficients; matrix[i + stride * o] is the weight of
* input channel i in output channel o.
@@ -238,6 +243,10 @@ int avresample_get_matrix(AVAudioResampleContext *avr,
double *matrix,
* avresample_convert() always uses the current matrix.
* Calling avresample_close() on the context will clear the current matrix.
*
+ * If a custom channel mapping is being used, it is applied to the current
+ * matrix when the context is opened or when calling avresample_set_matrix()
+ * on an already open context.
+ *
* @see avresample_close()
*
* @param avr audio resample context
@@ -250,6 +259,28 @@ int avresample_set_matrix(AVAudioResampleContext *avr,
const double *matrix,
int stride);
/**
+ * Set a customized input channel mapping.
+ *
+ * This function can only be called when the allocated context is not open.
+ * Also, the input channel layout must have already been set.
+ *
+ * If a custom channel mapping is being used, it is applied to the current
+ * matrix when the context is opened or when calling avresample_set_matrix()
+ * on an already open context. If the default matrix is being used, the mapping
+ * will be applied to the default matrix. If channel mixing is otherwise not
+ * needed, setting a custom channel mapping will force mixing.
+ *
+ * Calling avresample_close() on the context will clear the channel mapping.
+ *
+ * @param avr audio resample context
+ * @param channel_map customized input channel mapping (array of channel
+ * indexes, -1 for a muted channel)
+ * @return 0 on success, negative AVERROR code on failure
+ */
+int avresample_set_channel_mapping(AVAudioResampleContext *avr,
+ const int *channel_map);
+
+/**
* Set compensation for resampling.
*
* This can be called anytime after avresample_open(). If resampling was not
diff --git a/libavresample/internal.h b/libavresample/internal.h
index 3fd33fe..13505cb 100644
--- a/libavresample/internal.h
+++ b/libavresample/internal.h
@@ -80,6 +80,8 @@ struct AVAudioResampleContext {
* only used if avresample_set_matrix() is called before avresample_open()
*/
double *mix_matrix;
+ int force_mixing;
+ int *channel_map; /**< input channel map */
};
#endif /* AVRESAMPLE_INTERNAL_H */
diff --git a/libavresample/utils.c b/libavresample/utils.c
index fe2e1c2..d0d18dc 100644
--- a/libavresample/utils.c
+++ b/libavresample/utils.c
@@ -49,7 +49,7 @@ int avresample_open(AVAudioResampleContext *avr)
avr->resample_channels = FFMIN(avr->in_channels, avr->out_channels);
avr->downmix_needed = avr->in_channels > avr->out_channels;
avr->upmix_needed = avr->out_channels > avr->in_channels ||
- (!avr->downmix_needed && (avr->mix_matrix ||
+ (!avr->downmix_needed && (avr->force_mixing ||
avr->in_channel_layout !=
avr->out_channel_layout));
avr->mixing_needed = avr->downmix_needed || avr->upmix_needed;
@@ -195,6 +195,7 @@ void avresample_close(AVAudioResampleContext *avr)
ff_audio_resample_free(&avr->resample);
ff_audio_mix_free(&avr->am);
av_freep(&avr->mix_matrix);
+ av_freep(&avr->channel_map);
}
void avresample_free(AVAudioResampleContext **avr)
@@ -462,6 +463,44 @@ int avresample_set_matrix(AVAudioResampleContext *avr,
const double *matrix,
for (i = 0; i < in_channels; i++)
avr->mix_matrix[o * in_channels + i] = matrix[o * stride + i];
+ avr->force_mixing = 1;
+ return 0;
+}
+
+int avresample_set_channel_mapping(AVAudioResampleContext *avr,
+ const int *channel_map)
+{
+ int in_channels, i;
+
+ /* avr cannot already be open */
+ if (avr->in_channels) {
+ av_log(avr, AV_LOG_ERROR, "AVAudioResampleContext is already open\n");
+ return AVERROR(EINVAL);
+ }
+
+ in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout);
+ if (in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS) {
+ av_log(avr, AV_LOG_ERROR, "Invalid input channel layout\n");
+ return AVERROR(EINVAL);
+ }
+
+ for (i = 0; i < in_channels; i++) {
+ if (channel_map[i] < -1 || channel_map[i] >= in_channels) {
+ av_log(avr, AV_LOG_ERROR, "Invalid channel map\n");
+ return AVERROR(EINVAL);
+ }
+ }
+
+ if (avr->channel_map)
+ av_freep(&avr->channel_map);
+ avr->channel_map = av_malloc(in_channels * sizeof(*avr->channel_map));
+ if (!avr->channel_map)
+ return AVERROR(ENOMEM);
+
+ memcpy(avr->channel_map, channel_map,
+ in_channels * sizeof(*avr->channel_map));
+
+ avr->force_mixing = 1;
return 0;
}
diff --git a/libavresample/version.h b/libavresample/version.h
index 53ba802..2e57c22 100644
--- a/libavresample/version.h
+++ b/libavresample/version.h
@@ -20,7 +20,7 @@
#define AVRESAMPLE_VERSION_H
#define LIBAVRESAMPLE_VERSION_MAJOR 1
-#define LIBAVRESAMPLE_VERSION_MINOR 0
+#define LIBAVRESAMPLE_VERSION_MINOR 1
#define LIBAVRESAMPLE_VERSION_MICRO 0
#define LIBAVRESAMPLE_VERSION_INT AV_VERSION_INT(LIBAVRESAMPLE_VERSION_MAJOR,
\
--
1.7.1
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel