---
 doc/APIchanges             |    3 +++
 libavresample/audio_mix.c  |   40 +++++++++++++++++++++++++++++++++-------
 libavresample/avresample.h |   33 ++++++++++++++++++++++++++++++++-
 libavresample/internal.h   |    2 ++
 libavresample/utils.c      |   41 ++++++++++++++++++++++++++++++++++++++++-
 libavresample/version.h    |    2 +-
 6 files changed, 111 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..38d4568 100644
--- a/libavresample/audio_mix.c
+++ b/libavresample/audio_mix.c
@@ -350,6 +350,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 +393,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 +417,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 +427,7 @@ AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr)
     return am;
 
 error:
+    av_free(am->channel_map);
     av_free(am);
     return NULL;
 }
@@ -428,6 +448,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 +545,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

Reply via email to