Browse Source

Merge commit '074a00d192c0e749d677b008b337da42597e780f'

* commit '074a00d192c0e749d677b008b337da42597e780f':
  lavr: add a public function for setting a custom channel map
  lavr: typedef internal structs in internal.h
  doc: Extend commit message section

Conflicts:
	doc/APIchanges
	doc/developer.texi

Merged-by: Michael Niedermayer <michaelni@gmx.at>
Michael Niedermayer 12 years ago
parent
commit
249fca3df9

+ 4 - 0
doc/APIchanges

@@ -132,6 +132,10 @@ API changes, most recent first:
 2012-03-26 - a67d9cf - lavfi 2.66.100
   Add avfilter_fill_frame_from_{audio_,}buffer_ref() functions.
 
+2013-xx-xx - xxxxxxx - lavr 1.1.0
+  Add avresample_set_channel_mapping() for input channel reordering,
+  duplication, and silencing.
+
 2012-xx-xx - xxxxxxx - lavu 52.2.1 - avstring.h
   Add av_basename() and av_dirname().
 

+ 7 - 0
doc/developer.texi

@@ -228,6 +228,13 @@ For Emacs, add these roughly equivalent lines to your @file{.emacs.d/init.el}:
    You can commit unfinished stuff (for testing etc), but it must be disabled
    (#ifdef etc) by default so it does not interfere with other developers'
    work.
+@item
+   The commit message should have a short first line in the form of
+   a @samp{topic: short description} as a header, separated by a newline
+   from the body consisting of an explanation of why the change is necessary.
+   If the commit fixes a known bug on the bug tracker, the commit message
+   should include its bug ID. Referring to the issue on the bug tracker does
+   not exempt you from writing an excerpt of the bug in the commit message.
 @item
    You do not have to over-test things. If it works for you, and you think it
    should work for others, then commit. If your code has problems

+ 46 - 4
libavresample/audio_convert.c

@@ -30,7 +30,6 @@
 #include "audio_convert.h"
 #include "audio_data.h"
 #include "dither.h"
-#include "internal.h"
 
 enum ConvFuncType {
     CONV_FUNC_TYPE_FLAT,
@@ -51,6 +50,7 @@ struct AudioConvert {
     DitherContext *dc;
     enum AVSampleFormat in_fmt;
     enum AVSampleFormat out_fmt;
+    int apply_map;
     int channels;
     int planes;
     int ptr_align;
@@ -260,7 +260,8 @@ void ff_audio_convert_free(AudioConvert **ac)
 AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
                                      enum AVSampleFormat out_fmt,
                                      enum AVSampleFormat in_fmt,
-                                     int channels, int sample_rate)
+                                     int channels, int sample_rate,
+                                     int apply_map)
 {
     AudioConvert *ac;
     int in_planar, out_planar;
@@ -273,11 +274,13 @@ AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
     ac->out_fmt  = out_fmt;
     ac->in_fmt   = in_fmt;
     ac->channels = channels;
+    ac->apply_map = apply_map;
 
     if (avr->dither_method != AV_RESAMPLE_DITHER_NONE          &&
         av_get_packed_sample_fmt(out_fmt) == AV_SAMPLE_FMT_S16 &&
         av_get_bytes_per_sample(in_fmt) > 2) {
-        ac->dc = ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate);
+        ac->dc = ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate,
+                                 apply_map);
         if (!ac->dc) {
             av_free(ac);
             return NULL;
@@ -310,6 +313,7 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in)
 {
     int use_generic = 1;
     int len         = in->nb_samples;
+    int p;
 
     if (ac->dc) {
         /* dithered conversion */
@@ -336,9 +340,46 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in)
             av_get_sample_fmt_name(ac->out_fmt),
             use_generic ? ac->func_descr_generic : ac->func_descr);
 
+    if (ac->apply_map) {
+        ChannelMapInfo *map = &ac->avr->ch_map_info;
+
+        if (!av_sample_fmt_is_planar(ac->out_fmt)) {
+            av_log(ac->avr, AV_LOG_ERROR, "cannot remap packed format during conversion\n");
+            return AVERROR(EINVAL);
+        }
+
+        if (map->do_remap) {
+            if (av_sample_fmt_is_planar(ac->in_fmt)) {
+                conv_func_flat *convert = use_generic ? ac->conv_flat_generic :
+                                                        ac->conv_flat;
+
+                for (p = 0; p < ac->planes; p++)
+                    if (map->channel_map[p] >= 0)
+                        convert(out->data[p], in->data[map->channel_map[p]], len);
+            } else {
+                uint8_t *data[AVRESAMPLE_MAX_CHANNELS];
+                conv_func_deinterleave *convert = use_generic ?
+                                                  ac->conv_deinterleave_generic :
+                                                  ac->conv_deinterleave;
+
+                for (p = 0; p < ac->channels; p++)
+                    data[map->input_map[p]] = out->data[p];
+
+                convert(data, in->data[0], len, ac->channels);
+            }
+        }
+        if (map->do_copy || map->do_zero) {
+            for (p = 0; p < ac->planes; p++) {
+                if (map->channel_copy[p])
+                    memcpy(out->data[p], out->data[map->channel_copy[p]],
+                           len * out->stride);
+                else if (map->channel_zero[p])
+                    av_samples_set_silence(&out->data[p], 0, len, 1, ac->out_fmt);
+            }
+        }
+    } else {
     switch (ac->func_type) {
     case CONV_FUNC_TYPE_FLAT: {
-        int p;
         if (!in->is_planar)
             len *= in->channels;
         if (use_generic) {
@@ -363,6 +404,7 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in)
             ac->conv_deinterleave(out->data, in->data[0], len, ac->channels);
         break;
     }
+    }
 
     out->nb_samples = in->nb_samples;
     return 0;

+ 4 - 3
libavresample/audio_convert.h

@@ -23,10 +23,9 @@
 
 #include "libavutil/samplefmt.h"
 #include "avresample.h"
+#include "internal.h"
 #include "audio_data.h"
 
-typedef struct AudioConvert AudioConvert;
-
 /**
  * Set conversion function if the parameters match.
  *
@@ -59,12 +58,14 @@ void ff_audio_convert_set_func(AudioConvert *ac, enum AVSampleFormat out_fmt,
  * @param in_fmt      input sample format
  * @param channels    number of channels
  * @param sample_rate sample rate (used for dithering)
+ * @param apply_map   apply channel map during conversion
  * @return            newly-allocated AudioConvert context
  */
 AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
                                      enum AVSampleFormat out_fmt,
                                      enum AVSampleFormat in_fmt,
-                                     int channels, int sample_rate);
+                                     int channels, int sample_rate,
+                                     int apply_map);
 
 /**
  * Free AudioConvert.

+ 29 - 3
libavresample/audio_data.c

@@ -213,7 +213,7 @@ void ff_audio_data_free(AudioData **a)
     av_freep(a);
 }
 
-int ff_audio_data_copy(AudioData *dst, AudioData *src)
+int ff_audio_data_copy(AudioData *dst, AudioData *src, ChannelMapInfo *map)
 {
     int ret, p;
 
@@ -221,6 +221,11 @@ int ff_audio_data_copy(AudioData *dst, AudioData *src)
     if (dst->sample_fmt != src->sample_fmt || dst->channels < src->channels)
         return AVERROR(EINVAL);
 
+    if (map && !src->is_planar) {
+        av_log(src, AV_LOG_ERROR, "cannot remap packed format during copy\n");
+        return AVERROR(EINVAL);
+    }
+
     /* if the input is empty, just empty the output */
     if (!src->nb_samples) {
         dst->nb_samples = 0;
@@ -233,8 +238,29 @@ int ff_audio_data_copy(AudioData *dst, AudioData *src)
         return ret;
 
     /* copy data */
-    for (p = 0; p < src->planes; p++)
-        memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride);
+    if (map) {
+        if (map->do_remap) {
+            for (p = 0; p < src->planes; p++) {
+                if (map->channel_map[p] >= 0)
+                    memcpy(dst->data[p], src->data[map->channel_map[p]],
+                           src->nb_samples * src->stride);
+            }
+        }
+        if (map->do_copy || map->do_zero) {
+            for (p = 0; p < src->planes; p++) {
+                if (map->channel_copy[p])
+                    memcpy(dst->data[p], dst->data[map->channel_copy[p]],
+                           src->nb_samples * src->stride);
+                else if (map->channel_zero[p])
+                    av_samples_set_silence(&dst->data[p], 0, src->nb_samples,
+                                           1, dst->sample_fmt);
+            }
+        }
+    } else {
+        for (p = 0; p < src->planes; p++)
+            memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride);
+    }
+
     dst->nb_samples = src->nb_samples;
 
     return 0;

+ 5 - 3
libavresample/audio_data.h

@@ -27,11 +27,12 @@
 #include "libavutil/log.h"
 #include "libavutil/samplefmt.h"
 #include "avresample.h"
+#include "internal.h"
 
 /**
  * Audio buffer used for intermediate storage between conversion phases.
  */
-typedef struct AudioData {
+struct AudioData {
     const AVClass *class;               /**< AVClass for logging            */
     uint8_t *data[AVRESAMPLE_MAX_CHANNELS]; /**< data plane pointers        */
     uint8_t *buffer;                    /**< data buffer                    */
@@ -50,7 +51,7 @@ typedef struct AudioData {
     int ptr_align;                      /**< minimum data pointer alignment */
     int samples_align;                  /**< allocated samples alignment    */
     const char *name;                   /**< name for debug logging         */
-} AudioData;
+};
 
 int ff_audio_data_set_channels(AudioData *a, int channels);
 
@@ -117,9 +118,10 @@ void ff_audio_data_free(AudioData **a);
  *
  * @param out  output AudioData
  * @param in   input AudioData
+ * @param map  channel map, NULL if not remapping
  * @return     0 on success, negative AVERROR value on error
  */
-int ff_audio_data_copy(AudioData *out, AudioData *in);
+int ff_audio_data_copy(AudioData *out, AudioData *in, ChannelMapInfo *map);
 
 /**
  * Append data from one AudioData to the end of another.

+ 1 - 2
libavresample/audio_mix.h

@@ -25,13 +25,12 @@
 
 #include "libavutil/samplefmt.h"
 #include "avresample.h"
+#include "internal.h"
 #include "audio_data.h"
 
 typedef void (mix_func)(uint8_t **src, void **matrix, int len, int out_ch,
                         int in_ch);
 
-typedef struct AudioMix AudioMix;
-
 /**
  * Set mixing function if the parameters match.
  *

+ 30 - 0
libavresample/avresample.h

@@ -258,6 +258,36 @@ int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix,
 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.
+ *
+ * Calling avresample_close() on the context will clear the channel mapping.
+ *
+ * The map for each input channel specifies the channel index in the source to
+ * use for that particular channel, or -1 to mute the channel. Source channels
+ * can be duplicated by using the same index for multiple input channels.
+ *
+ * Examples:
+ *
+ * Reordering 5.1 AAC order (C,L,R,Ls,Rs,LFE) to Libav order (L,R,C,LFE,Ls,Rs):
+ * { 1, 2, 0, 5, 3, 4 }
+ *
+ * Muting the 3rd channel in 4-channel input:
+ * { 0, 1, -1, 3 }
+ *
+ * Duplicating the left channel of stereo input:
+ * { 0, 0 }
+ *
+ * @param avr         audio resample context
+ * @param channel_map customized input channel mapping
+ * @return            0 on success, negative AVERROR code on failure
+ */
+int avresample_set_channel_mapping(AVAudioResampleContext *avr,
+                                   const int *channel_map);
+
 /**
  * Set compensation for resampling.
  *

+ 19 - 6
libavresample/dither.c

@@ -53,6 +53,8 @@ typedef struct DitherState {
 struct DitherContext {
     DitherDSPContext  ddsp;
     enum AVResampleDitherMethod method;
+    int apply_map;
+    ChannelMapInfo *ch_map_info;
 
     int mute_dither_threshold;  // threshold for disabling dither
     int mute_reset_threshold;   // threshold for resetting noise shaping
@@ -251,17 +253,23 @@ int ff_convert_dither(DitherContext *c, AudioData *dst, AudioData *src)
             return ret;
     }
 
-    if (src->sample_fmt != AV_SAMPLE_FMT_FLTP) {
+    if (src->sample_fmt != AV_SAMPLE_FMT_FLTP || c->apply_map) {
         /* make sure flt_data is large enough for the input */
         ret = ff_audio_data_realloc(c->flt_data, src->nb_samples);
         if (ret < 0)
             return ret;
         flt_data = c->flt_data;
+    }
 
+    if (src->sample_fmt != AV_SAMPLE_FMT_FLTP) {
         /* convert input samples to fltp and scale to s16 range */
         ret = ff_audio_convert(c->ac_in, flt_data, src);
         if (ret < 0)
             return ret;
+    } else if (c->apply_map) {
+        ret = ff_audio_data_copy(flt_data, src, c->ch_map_info);
+        if (ret < 0)
+            return ret;
     } else {
         flt_data = src;
     }
@@ -333,7 +341,7 @@ static void dither_init(DitherDSPContext *ddsp,
 DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,
                                enum AVSampleFormat out_fmt,
                                enum AVSampleFormat in_fmt,
-                               int channels, int sample_rate)
+                               int channels, int sample_rate, int apply_map)
 {
     AVLFG seed_gen;
     DitherContext *c;
@@ -350,6 +358,10 @@ DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,
     if (!c)
         return NULL;
 
+    c->apply_map = apply_map;
+    if (apply_map)
+        c->ch_map_info = &avr->ch_map_info;
+
     if (avr->dither_method == AV_RESAMPLE_DITHER_TRIANGULAR_NS &&
         sample_rate != 48000 && sample_rate != 44100) {
         av_log(avr, AV_LOG_WARNING, "sample rate must be 48000 or 44100 Hz "
@@ -379,19 +391,20 @@ DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,
             goto fail;
 
         c->ac_out = ff_audio_convert_alloc(avr, out_fmt, AV_SAMPLE_FMT_S16P,
-                                           channels, sample_rate);
+                                           channels, sample_rate, 0);
         if (!c->ac_out)
             goto fail;
     }
 
-    if (in_fmt != AV_SAMPLE_FMT_FLTP) {
+    if (in_fmt != AV_SAMPLE_FMT_FLTP || c->apply_map) {
         c->flt_data = ff_audio_data_alloc(channels, 1024, AV_SAMPLE_FMT_FLTP,
                                           "dither flt buffer");
         if (!c->flt_data)
             goto fail;
-
+    }
+    if (in_fmt != AV_SAMPLE_FMT_FLTP) {
         c->ac_in = ff_audio_convert_alloc(avr, AV_SAMPLE_FMT_FLTP, in_fmt,
-                                          channels, sample_rate);
+                                          channels, sample_rate, c->apply_map);
         if (!c->ac_in)
             goto fail;
     }

+ 1 - 1
libavresample/dither.h

@@ -66,7 +66,7 @@ typedef struct DitherDSPContext {
 DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,
                                enum AVSampleFormat out_fmt,
                                enum AVSampleFormat in_fmt,
-                               int channels, int sample_rate);
+                               int channels, int sample_rate, int apply_map);
 
 /**
  * Free a DitherContext.

Some files were not shown because too many files changed in this diff