History

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

Michael Niedermayer committed 13 years ago

Commit 249fca32 parents 3a0bac2 074a00d15 files · +328 −41Browse files

Unified · Split

15 files
  1. doc/APIchanges +4 −0
  2. doc/developer.texi +7 −0
  3. libavresample/audio_convert.c +46 −4
  4. libavresample/audio_convert.h +4 −3
  5. libavresample/audio_data.c +29 −3
  6. libavresample/audio_data.h +5 −3
  7. libavresample/audio_mix.h +1 −2
  8. libavresample/avresample.h +30 −0
  9. libavresample/dither.c +19 −6
  10. libavresample/dither.h +1 −1
  11. libavresample/internal.h +28 −4
  12. libavresample/resample.c +1 −0
  13. libavresample/resample.h +1 −2
  14. libavresample/utils.c +150 −11
  15. libavresample/version.h +2 −2
doc/APIchanges+4−0
@@ -132,6 +132,10 @@ API changes, most recent first: · 131 unmodified lines
132132 2012-03-26 - a67d9cf - lavfi 2.66.100
133133 Add avfilter_fill_frame_from_{audio_,}buffer_ref() functions.
134134
135+2013-xx-xx - xxxxxxx - lavr 1.1.0
136+ Add avresample_set_channel_mapping() for input channel reordering,
137+ duplication, and silencing.
138+
135139 2012-xx-xx - xxxxxxx - lavu 52.2.1 - avstring.h
136140 Add av_basename() and av_dirname().
137141
doc/developer.texi+7−0
@@ -228,6 +228,13 @@ For Emacs, add these roughly equivalent lines to your @file{.emacs.d/init.el}: · 227 unmodified lines
228228 You can commit unfinished stuff (for testing etc), but it must be disabled
229229 (#ifdef etc) by default so it does not interfere with other developers'
230230 work.
231+@item
232+ The commit message should have a short first line in the form of
233+ a @samp{topic: short description} as a header, separated by a newline
234+ from the body consisting of an explanation of why the change is necessary.
235+ If the commit fixes a known bug on the bug tracker, the commit message
236+ should include its bug ID. Referring to the issue on the bug tracker does
237+ not exempt you from writing an excerpt of the bug in the commit message.
231238 @item
232239 You do not have to over-test things. If it works for you, and you think it
233240 should work for others, then commit. If your code has problems
libavresample/audio_convert.c+46−4
@@ -30,7 +30,6 @@ · 29 unmodified lines
3030 #include "audio_convert.h"
3131 #include "audio_data.h"
3232 #include "dither.h"
33−#include "internal.h"
3433
3534 enum ConvFuncType {
3635 CONV_FUNC_TYPE_FLAT,
@@ -51,6 +50,7 @@ struct AudioConvert { · 14 unmodified lines
5150 DitherContext *dc;
5251 enum AVSampleFormat in_fmt;
5352 enum AVSampleFormat out_fmt;
53+ int apply_map;
5454 int channels;
5555 int planes;
5656 int ptr_align;
@@ -260,7 +260,8 @@ void ff_audio_convert_free(AudioConvert **ac) · 203 unmodified lines
260260 AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
261261 enum AVSampleFormat out_fmt,
262262 enum AVSampleFormat in_fmt,
263− int channels, int sample_rate)
263+ int channels, int sample_rate,
264+ int apply_map)
264265 {
265266 AudioConvert *ac;
266267 int in_planar, out_planar;
@@ -273,11 +274,13 @@ AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, · 6 unmodified lines
273274 ac->out_fmt = out_fmt;
274275 ac->in_fmt = in_fmt;
275276 ac->channels = channels;
277+ ac->apply_map = apply_map;
276278
277279 if (avr->dither_method != AV_RESAMPLE_DITHER_NONE &&
278280 av_get_packed_sample_fmt(out_fmt) == AV_SAMPLE_FMT_S16 &&
279281 av_get_bytes_per_sample(in_fmt) > 2) {
280− ac->dc = ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate);
282+ ac->dc = ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate,
283+ apply_map);
281284 if (!ac->dc) {
282285 av_free(ac);
283286 return NULL;
@@ -310,6 +313,7 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) · 26 unmodified lines
310313 {
311314 int use_generic = 1;
312315 int len = in->nb_samples;
316+ int p;
313317
314318 if (ac->dc) {
315319 /* dithered conversion */
@@ -336,9 +340,46 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) · 20 unmodified lines
336340 av_get_sample_fmt_name(ac->out_fmt),
337341 use_generic ? ac->func_descr_generic : ac->func_descr);
338342
343+ if (ac->apply_map) {
344+ ChannelMapInfo *map = &ac->avr->ch_map_info;
345+
346+ if (!av_sample_fmt_is_planar(ac->out_fmt)) {
347+ av_log(ac->avr, AV_LOG_ERROR, "cannot remap packed format during conversion\n");
348+ return AVERROR(EINVAL);
349+ }
350+
351+ if (map->do_remap) {
352+ if (av_sample_fmt_is_planar(ac->in_fmt)) {
353+ conv_func_flat *convert = use_generic ? ac->conv_flat_generic :
354+ ac->conv_flat;
355+
356+ for (p = 0; p < ac->planes; p++)
357+ if (map->channel_map[p] >= 0)
358+ convert(out->data[p], in->data[map->channel_map[p]], len);
359+ } else {
360+ uint8_t *data[AVRESAMPLE_MAX_CHANNELS];
361+ conv_func_deinterleave *convert = use_generic ?
362+ ac->conv_deinterleave_generic :
363+ ac->conv_deinterleave;
364+
365+ for (p = 0; p < ac->channels; p++)
366+ data[map->input_map[p]] = out->data[p];
367+
368+ convert(data, in->data[0], len, ac->channels);
369+ }
370+ }
371+ if (map->do_copy || map->do_zero) {
372+ for (p = 0; p < ac->planes; p++) {
373+ if (map->channel_copy[p])
374+ memcpy(out->data[p], out->data[map->channel_copy[p]],
375+ len * out->stride);
376+ else if (map->channel_zero[p])
377+ av_samples_set_silence(&out->data[p], 0, len, 1, ac->out_fmt);
378+ }
379+ }
380+ } else {
339381 switch (ac->func_type) {
340382 case CONV_FUNC_TYPE_FLAT: {
341− int p;
342383 if (!in->is_planar)
343384 len *= in->channels;
344385 if (use_generic) {
@@ -363,6 +404,7 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) · 18 unmodified lines
363404 ac->conv_deinterleave(out->data, in->data[0], len, ac->channels);
364405 break;
365406 }
407+ }
366408
367409 out->nb_samples = in->nb_samples;
368410 return 0;
libavresample/audio_convert.h+4−3
@@ -23,10 +23,9 @@ · 22 unmodified lines
2323
2424 #include "libavutil/samplefmt.h"
2525 #include "avresample.h"
26+#include "internal.h"
2627 #include "audio_data.h"
2728
28−typedef struct AudioConvert AudioConvert;
29−
3029 /**
3130 * Set conversion function if the parameters match.
3231 *
@@ -59,12 +58,14 @@ void ff_audio_convert_set_func(AudioConvert *ac, enum AVSampleFormat out_fmt, · 26 unmodified lines
5958 * @param in_fmt input sample format
6059 * @param channels number of channels
6160 * @param sample_rate sample rate (used for dithering)
61+ * @param apply_map apply channel map during conversion
6262 * @return newly-allocated AudioConvert context
6363 */
6464 AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
6565 enum AVSampleFormat out_fmt,
6666 enum AVSampleFormat in_fmt,
67− int channels, int sample_rate);
67+ int channels, int sample_rate,
68+ int apply_map);
6869
6970 /**
7071 * Free AudioConvert.
libavresample/audio_data.c+29−3
@@ -213,7 +213,7 @@ void ff_audio_data_free(AudioData **a) · 212 unmodified lines
213213 av_freep(a);
214214 }
215215
216−int ff_audio_data_copy(AudioData *dst, AudioData *src)
216+int ff_audio_data_copy(AudioData *dst, AudioData *src, ChannelMapInfo *map)
217217 {
218218 int ret, p;
219219
@@ -221,6 +221,11 @@ int ff_audio_data_copy(AudioData *dst, AudioData *src) · 1 unmodified line
221221 if (dst->sample_fmt != src->sample_fmt || dst->channels < src->channels)
222222 return AVERROR(EINVAL);
223223
224+ if (map && !src->is_planar) {
225+ av_log(src, AV_LOG_ERROR, "cannot remap packed format during copy\n");
226+ return AVERROR(EINVAL);
227+ }
228+
224229 /* if the input is empty, just empty the output */
225230 if (!src->nb_samples) {
226231 dst->nb_samples = 0;
@@ -233,8 +238,29 @@ int ff_audio_data_copy(AudioData *dst, AudioData *src) · 6 unmodified lines
233238 return ret;
234239
235240 /* copy data */
236− for (p = 0; p < src->planes; p++)
237− memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride);
241+ if (map) {
242+ if (map->do_remap) {
243+ for (p = 0; p < src->planes; p++) {
244+ if (map->channel_map[p] >= 0)
245+ memcpy(dst->data[p], src->data[map->channel_map[p]],
246+ src->nb_samples * src->stride);
247+ }
248+ }
249+ if (map->do_copy || map->do_zero) {
250+ for (p = 0; p < src->planes; p++) {
251+ if (map->channel_copy[p])
252+ memcpy(dst->data[p], dst->data[map->channel_copy[p]],
253+ src->nb_samples * src->stride);
254+ else if (map->channel_zero[p])
255+ av_samples_set_silence(&dst->data[p], 0, src->nb_samples,
256+ 1, dst->sample_fmt);
257+ }
258+ }
259+ } else {
260+ for (p = 0; p < src->planes; p++)
261+ memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride);
262+ }
263+
238264 dst->nb_samples = src->nb_samples;
239265
240266 return 0;
libavresample/audio_data.h+5−3
@@ -27,11 +27,12 @@ · 26 unmodified lines
2727 #include "libavutil/log.h"
2828 #include "libavutil/samplefmt.h"
2929 #include "avresample.h"
30+#include "internal.h"
3031
3132 /**
3233 * Audio buffer used for intermediate storage between conversion phases.
3334 */
34−typedef struct AudioData {
35+struct AudioData {
3536 const AVClass *class; /**< AVClass for logging */
3637 uint8_t *data[AVRESAMPLE_MAX_CHANNELS]; /**< data plane pointers */
3738 uint8_t *buffer; /**< data buffer */
@@ -50,7 +51,7 @@ typedef struct AudioData { · 12 unmodified lines
5051 int ptr_align; /**< minimum data pointer alignment */
5152 int samples_align; /**< allocated samples alignment */
5253 const char *name; /**< name for debug logging */
53−} AudioData;
54+};
5455
5556 int ff_audio_data_set_channels(AudioData *a, int channels);
5657
@@ -117,9 +118,10 @@ void ff_audio_data_free(AudioData **a); · 60 unmodified lines
117118 *
118119 * @param out output AudioData
119120 * @param in input AudioData
121+ * @param map channel map, NULL if not remapping
120122 * @return 0 on success, negative AVERROR value on error
121123 */
122−int ff_audio_data_copy(AudioData *out, AudioData *in);
124+int ff_audio_data_copy(AudioData *out, AudioData *in, ChannelMapInfo *map);
123125
124126 /**
125127 * Append data from one AudioData to the end of another.
libavresample/audio_mix.h+1−2
@@ -25,13 +25,12 @@ · 24 unmodified lines
2525
2626 #include "libavutil/samplefmt.h"
2727 #include "avresample.h"
28+#include "internal.h"
2829 #include "audio_data.h"
2930
3031 typedef void (mix_func)(uint8_t **src, void **matrix, int len, int out_ch,
3132 int in_ch);
3233
33−typedef struct AudioMix AudioMix;
34−
3534 /**
3635 * Set mixing function if the parameters match.
3736 *
libavresample/avresample.h+30−0
@@ -258,6 +258,36 @@ int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix, · 257 unmodified lines
258258 int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
259259 int stride);
260260
261+/**
262+ * Set a customized input channel mapping.
263+ *
264+ * This function can only be called when the allocated context is not open.
265+ * Also, the input channel layout must have already been set.
266+ *
267+ * Calling avresample_close() on the context will clear the channel mapping.
268+ *
269+ * The map for each input channel specifies the channel index in the source to
270+ * use for that particular channel, or -1 to mute the channel. Source channels
271+ * can be duplicated by using the same index for multiple input channels.
272+ *
273+ * Examples:
274+ *
275+ * Reordering 5.1 AAC order (C,L,R,Ls,Rs,LFE) to Libav order (L,R,C,LFE,Ls,Rs):
276+ * { 1, 2, 0, 5, 3, 4 }
277+ *
278+ * Muting the 3rd channel in 4-channel input:
279+ * { 0, 1, -1, 3 }
280+ *
281+ * Duplicating the left channel of stereo input:
282+ * { 0, 0 }
283+ *
284+ * @param avr audio resample context
285+ * @param channel_map customized input channel mapping
286+ * @return 0 on success, negative AVERROR code on failure
287+ */
288+int avresample_set_channel_mapping(AVAudioResampleContext *avr,
289+ const int *channel_map);
290+
261291 /**
262292 * Set compensation for resampling.
263293 *
libavresample/dither.c+19−6
@@ -53,6 +53,8 @@ typedef struct DitherState { · 52 unmodified lines
5353 struct DitherContext {
5454 DitherDSPContext ddsp;
5555 enum AVResampleDitherMethod method;
56+ int apply_map;
57+ ChannelMapInfo *ch_map_info;
5658
5759 int mute_dither_threshold; // threshold for disabling dither
5860 int mute_reset_threshold; // threshold for resetting noise shaping
@@ -251,17 +253,23 @@ int ff_convert_dither(DitherContext *c, AudioData *dst, AudioData *src) · 192 unmodified lines
251253 return ret;
252254 }
253255
254− if (src->sample_fmt != AV_SAMPLE_FMT_FLTP) {
256+ if (src->sample_fmt != AV_SAMPLE_FMT_FLTP || c->apply_map) {
255257 /* make sure flt_data is large enough for the input */
256258 ret = ff_audio_data_realloc(c->flt_data, src->nb_samples);
257259 if (ret < 0)
258260 return ret;
259261 flt_data = c->flt_data;
262+ }
260263
264+ if (src->sample_fmt != AV_SAMPLE_FMT_FLTP) {
261265 /* convert input samples to fltp and scale to s16 range */
262266 ret = ff_audio_convert(c->ac_in, flt_data, src);
263267 if (ret < 0)
264268 return ret;
269+ } else if (c->apply_map) {
270+ ret = ff_audio_data_copy(flt_data, src, c->ch_map_info);
271+ if (ret < 0)
272+ return ret;
265273 } else {
266274 flt_data = src;
267275 }
@@ -333,7 +341,7 @@ static void dither_init(DitherDSPContext *ddsp, · 65 unmodified lines
333341 DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,
334342 enum AVSampleFormat out_fmt,
335343 enum AVSampleFormat in_fmt,
336− int channels, int sample_rate)
344+ int channels, int sample_rate, int apply_map)
337345 {
338346 AVLFG seed_gen;
339347 DitherContext *c;
@@ -350,6 +358,10 @@ DitherContext *ff_dither_alloc(AVAudioResampleContext *avr, · 10 unmodified lines
350358 if (!c)
351359 return NULL;
352360
361+ c->apply_map = apply_map;
362+ if (apply_map)
363+ c->ch_map_info = &avr->ch_map_info;
364+
353365 if (avr->dither_method == AV_RESAMPLE_DITHER_TRIANGULAR_NS &&
354366 sample_rate != 48000 && sample_rate != 44100) {
355367 av_log(avr, AV_LOG_WARNING, "sample rate must be 48000 or 44100 Hz "
@@ -379,19 +391,20 @@ DitherContext *ff_dither_alloc(AVAudioResampleContext *avr, · 23 unmodified lines
379391 goto fail;
380392
381393 c->ac_out = ff_audio_convert_alloc(avr, out_fmt, AV_SAMPLE_FMT_S16P,
382− channels, sample_rate);
394+ channels, sample_rate, 0);
383395 if (!c->ac_out)
384396 goto fail;
385397 }
386398
387− if (in_fmt != AV_SAMPLE_FMT_FLTP) {
399+ if (in_fmt != AV_SAMPLE_FMT_FLTP || c->apply_map) {
388400 c->flt_data = ff_audio_data_alloc(channels, 1024, AV_SAMPLE_FMT_FLTP,
389401 "dither flt buffer");
390402 if (!c->flt_data)
391403 goto fail;
392−
404+ }
405+ if (in_fmt != AV_SAMPLE_FMT_FLTP) {
393406 c->ac_in = ff_audio_convert_alloc(avr, AV_SAMPLE_FMT_FLTP, in_fmt,
394− channels, sample_rate);
407+ channels, sample_rate, c->apply_map);
395408 if (!c->ac_in)
396409 goto fail;
397410 }
libavresample/dither.h+1−1
@@ -66,7 +66,7 @@ typedef struct DitherDSPContext { · 65 unmodified lines
6666 DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,
6767 enum AVSampleFormat out_fmt,
6868 enum AVSampleFormat in_fmt,
69− int channels, int sample_rate);
69+ int channels, int sample_rate, int apply_map);
7070
7171 /**
7272 * Free a DitherContext.
libavresample/internal.h+28−4
@@ -26,10 +26,29 @@ · 25 unmodified lines
2626 #include "libavutil/opt.h"
2727 #include "libavutil/samplefmt.h"
2828 #include "avresample.h"
29−#include "audio_convert.h"
30−#include "audio_data.h"
31−#include "audio_mix.h"
32−#include "resample.h"
29+
30+typedef struct AudioData AudioData;
31+typedef struct AudioConvert AudioConvert;
32+typedef struct AudioMix AudioMix;
33+typedef struct ResampleContext ResampleContext;
34+
35+enum RemapPoint {
36+ REMAP_NONE,
37+ REMAP_IN_COPY,
38+ REMAP_IN_CONVERT,
39+ REMAP_OUT_COPY,
40+ REMAP_OUT_CONVERT,
41+};
42+
43+typedef struct ChannelMapInfo {
44+ int channel_map[AVRESAMPLE_MAX_CHANNELS]; /**< source index of each output channel, -1 if not remapped */
45+ int do_remap; /**< remap needed */
46+ int channel_copy[AVRESAMPLE_MAX_CHANNELS]; /**< dest index to copy from */
47+ int do_copy; /**< copy needed */
48+ int channel_zero[AVRESAMPLE_MAX_CHANNELS]; /**< dest index to zero */
49+ int do_zero; /**< zeroing needed */
50+ int input_map[AVRESAMPLE_MAX_CHANNELS]; /**< dest index of each input channel */
51+} ChannelMapInfo;
3352
3453 struct AVAudioResampleContext {
3554 const AVClass *av_class; /**< AVClass for logging and AVOptions */
@@ -64,6 +83,7 @@ struct AVAudioResampleContext { · 28 unmodified lines
6483 int resample_needed; /**< resampling is needed */
6584 int in_convert_needed; /**< input sample format conversion is needed */
6685 int out_convert_needed; /**< output sample format conversion is needed */
86+ int in_copy_needed; /**< input data copy is needed */
6787
6888 AudioData *in_buffer; /**< buffer for converted input */
6989 AudioData *resample_out_buffer; /**< buffer for output from resampler */
@@ -81,6 +101,10 @@ struct AVAudioResampleContext { · 11 unmodified lines
81101 * only used if avresample_set_matrix() is called before avresample_open()
82102 */
83103 double *mix_matrix;
104+
105+ int use_channel_map;
106+ enum RemapPoint remap_point;
107+ ChannelMapInfo ch_map_info;
84108 };
85109
86110 #endif /* AVRESAMPLE_INTERNAL_H */
libavresample/resample.c+1−0
@@ -23,6 +23,7 @@ · 22 unmodified lines
2323 #include "libavutil/libm.h"
2424 #include "libavutil/log.h"
2525 #include "internal.h"
26+#include "resample.h"
2627 #include "audio_data.h"
2728
2829 struct ResampleContext {
libavresample/resample.h+1−2
@@ -22,10 +22,9 @@ · 21 unmodified lines
2222 #define AVRESAMPLE_RESAMPLE_H
2323
2424 #include "avresample.h"
25+#include "internal.h"
2526 #include "audio_data.h"
2627
27−typedef struct ResampleContext ResampleContext;
28−
2928 /**
3029 * Allocate and initialize a ResampleContext.
3130 *
libavresample/utils.c+150−11
@@ -26,8 +26,11 @@ · 25 unmodified lines
2626 #include "libavutil/opt.h"
2727
2828 #include "avresample.h"
29−#include "audio_data.h"
3029 #include "internal.h"
30+#include "audio_data.h"
31+#include "audio_convert.h"
32+#include "audio_mix.h"
33+#include "resample.h"
3134
3235 int avresample_open(AVAudioResampleContext *avr)
3336 {
@@ -93,20 +96,84 @@ int avresample_open(AVAudioResampleContext *avr) · 59 unmodified lines
9396 av_get_sample_fmt_name(avr->internal_sample_fmt));
9497 }
9598
96− /* set sample format conversion parameters */
99+ /* treat all mono as planar for easier comparison */
97100 if (avr->in_channels == 1)
98101 avr->in_sample_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt);
99102 if (avr->out_channels == 1)
100103 avr->out_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt);
101− avr->in_convert_needed = (avr->resample_needed || avr->mixing_needed) &&
102− avr->in_sample_fmt != avr->internal_sample_fmt;
104+
105+ /* we may need to add an extra conversion in order to remap channels if
106+ the output format is not planar */
107+ if (avr->use_channel_map && !avr->mixing_needed && !avr->resample_needed &&
108+ !av_sample_fmt_is_planar(avr->out_sample_fmt)) {
109+ avr->internal_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt);
110+ }
111+
112+ /* set sample format conversion parameters */
103113 if (avr->resample_needed || avr->mixing_needed)
114+ avr->in_convert_needed = avr->in_sample_fmt != avr->internal_sample_fmt;
115+ else
116+ avr->in_convert_needed = avr->use_channel_map &&
117+ !av_sample_fmt_is_planar(avr->out_sample_fmt);
118+
119+ if (avr->resample_needed || avr->mixing_needed || avr->in_convert_needed)
104120 avr->out_convert_needed = avr->internal_sample_fmt != avr->out_sample_fmt;
105121 else
106122 avr->out_convert_needed = avr->in_sample_fmt != avr->out_sample_fmt;
107123
124+ avr->in_copy_needed = !avr->in_convert_needed && (avr->mixing_needed ||
125+ (avr->use_channel_map && avr->resample_needed));
126+
127+ if (avr->use_channel_map) {
128+ if (avr->in_copy_needed) {
129+ avr->remap_point = REMAP_IN_COPY;
130+ av_dlog(avr, "remap channels during in_copy\n");
131+ } else if (avr->in_convert_needed) {
132+ avr->remap_point = REMAP_IN_CONVERT;
133+ av_dlog(avr, "remap channels during in_convert\n");
134+ } else if (avr->out_convert_needed) {
135+ avr->remap_point = REMAP_OUT_CONVERT;
136+ av_dlog(avr, "remap channels during out_convert\n");
137+ } else {
138+ avr->remap_point = REMAP_OUT_COPY;
139+ av_dlog(avr, "remap channels during out_copy\n");
140+ }
141+
142+#ifdef DEBUG
143+ {
144+ int ch;
145+ av_dlog(avr, "output map: ");
146+ if (avr->ch_map_info.do_remap)
147+ for (ch = 0; ch < avr->in_channels; ch++)
148+ av_dlog(avr, " % 2d", avr->ch_map_info.channel_map[ch]);
149+ else
150+ av_dlog(avr, "n/a");
151+ av_dlog(avr, "\n");
152+ av_dlog(avr, "copy map: ");
153+ if (avr->ch_map_info.do_copy)
154+ for (ch = 0; ch < avr->in_channels; ch++)
155+ av_dlog(avr, " % 2d", avr->ch_map_info.channel_copy[ch]);
156+ else
157+ av_dlog(avr, "n/a");
158+ av_dlog(avr, "\n");
159+ av_dlog(avr, "zero map: ");
160+ if (avr->ch_map_info.do_zero)
161+ for (ch = 0; ch < avr->in_channels; ch++)
162+ av_dlog(avr, " % 2d", avr->ch_map_info.channel_zero[ch]);
163+ else
164+ av_dlog(avr, "n/a");
165+ av_dlog(avr, "\n");
166+ av_dlog(avr, "input map: ");
167+ for (ch = 0; ch < avr->in_channels; ch++)
168+ av_dlog(avr, " % 2d", avr->ch_map_info.input_map[ch]);
169+ av_dlog(avr, "\n");
170+ }
171+#endif
172+ } else
173+ avr->remap_point = REMAP_NONE;
174+
108175 /* allocate buffers */
109− if (avr->mixing_needed || avr->in_convert_needed) {
176+ if (avr->in_copy_needed || avr->in_convert_needed) {
110177 avr->in_buffer = ff_audio_data_alloc(FFMAX(avr->in_channels, avr->out_channels),
111178 0, avr->internal_sample_fmt,
112179 "in_buffer");
@@ -143,7 +210,8 @@ int avresample_open(AVAudioResampleContext *avr) · 30 unmodified lines
143210 if (avr->in_convert_needed) {
144211 avr->ac_in = ff_audio_convert_alloc(avr, avr->internal_sample_fmt,
145212 avr->in_sample_fmt, avr->in_channels,
146− avr->in_sample_rate);
213+ avr->in_sample_rate,
214+ avr->remap_point == REMAP_IN_CONVERT);
147215 if (!avr->ac_in) {
148216 ret = AVERROR(ENOMEM);
149217 goto error;
@@ -157,7 +225,8 @@ int avresample_open(AVAudioResampleContext *avr) · 7 unmodified lines
157225 src_fmt = avr->in_sample_fmt;
158226 avr->ac_out = ff_audio_convert_alloc(avr, avr->out_sample_fmt, src_fmt,
159227 avr->out_channels,
160− avr->out_sample_rate);
228+ avr->out_sample_rate,
229+ avr->remap_point == REMAP_OUT_CONVERT);
161230 if (!avr->ac_out) {
162231 ret = AVERROR(ENOMEM);
163232 goto error;
@@ -197,6 +266,8 @@ void avresample_close(AVAudioResampleContext *avr) · 33 unmodified lines
197266 ff_audio_resample_free(&avr->resample);
198267 ff_audio_mix_free(&avr->am);
199268 av_freep(&avr->mix_matrix);
269+
270+ avr->use_channel_map = 0;
200271 }
201272
202273 void avresample_free(AVAudioResampleContext **avr)
@@ -239,7 +310,9 @@ static int handle_buffered_output(AVAudioResampleContext *avr, · 36 unmodified lines
239310 data in the output FIFO */
240311 av_dlog(avr, "[copy] %s to output\n", converted->name);
241312 output->nb_samples = 0;
242− ret = ff_audio_data_copy(output, converted);
313+ ret = ff_audio_data_copy(output, converted,
314+ avr->remap_point == REMAP_OUT_COPY ?
315+ &avr->ch_map_info : NULL);
243316 if (ret < 0)
244317 return ret;
245318 av_dlog(avr, "[end conversion]\n");
@@ -303,11 +376,24 @@ int attribute_align_arg avresample_convert(AVAudioResampleContext *avr, · 57 unmodified lines
303376 /* in some rare cases we can copy input to output and upmix
304377 directly in the output buffer */
305378 av_dlog(avr, "[copy] %s to output\n", current_buffer->name);
306− ret = ff_audio_data_copy(&output_buffer, current_buffer);
379+ ret = ff_audio_data_copy(&output_buffer, current_buffer,
380+ avr->remap_point == REMAP_OUT_COPY ?
381+ &avr->ch_map_info : NULL);
307382 if (ret < 0)
308383 return ret;
309384 current_buffer = &output_buffer;
310− } else if (avr->mixing_needed || avr->in_convert_needed) {
385+ } else if (avr->remap_point == REMAP_OUT_COPY &&
386+ (!direct_output || out_samples < in_samples)) {
387+ /* if remapping channels during output copy, we may need to
388+ * use an intermediate buffer in order to remap before adding
389+ * samples to the output fifo */
390+ av_dlog(avr, "[copy] %s to out_buffer\n", current_buffer->name);
391+ ret = ff_audio_data_copy(avr->out_buffer, current_buffer,
392+ &avr->ch_map_info);
393+ if (ret < 0)
394+ return ret;
395+ current_buffer = avr->out_buffer;
396+ } else if (avr->in_copy_needed || avr->in_convert_needed) {
311397 /* if needed, copy or convert input to in_buffer, and downmix if
312398 applicable */
313399 if (avr->in_convert_needed) {
@@ -322,7 +408,9 @@ int attribute_align_arg avresample_convert(AVAudioResampleContext *avr, · 8 unmodified lines
322408 return ret;
323409 } else {
324410 av_dlog(avr, "[copy] %s to in_buffer\n", current_buffer->name);
325− ret = ff_audio_data_copy(avr->in_buffer, current_buffer);
411+ ret = ff_audio_data_copy(avr->in_buffer, current_buffer,
412+ avr->remap_point == REMAP_IN_COPY ?
413+ &avr->ch_map_info : NULL);
326414 if (ret < 0)
327415 return ret;
328416 }
@@ -467,6 +555,57 @@ int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix, · 138 unmodified lines
467555 return 0;
468556 }
469557
558+int avresample_set_channel_mapping(AVAudioResampleContext *avr,
559+ const int *channel_map)
560+{
561+ ChannelMapInfo *info = &avr->ch_map_info;
562+ int in_channels, ch, i;
563+
564+ in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout);
565+ if (in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS) {
566+ av_log(avr, AV_LOG_ERROR, "Invalid input channel layout\n");
567+ return AVERROR(EINVAL);
568+ }
569+
570+ memset(info, 0, sizeof(*info));
571+ memset(info->input_map, -1, sizeof(info->input_map));
572+
573+ for (ch = 0; ch < in_channels; ch++) {
574+ if (channel_map[ch] >= in_channels) {
575+ av_log(avr, AV_LOG_ERROR, "Invalid channel map\n");
576+ return AVERROR(EINVAL);
577+ }
578+ if (channel_map[ch] < 0) {
579+ info->channel_zero[ch] = 1;
580+ info->channel_map[ch] = -1;
581+ info->do_zero = 1;
582+ } else if (info->input_map[channel_map[ch]] >= 0) {
583+ info->channel_copy[ch] = info->input_map[channel_map[ch]];
584+ info->channel_map[ch] = -1;
585+ info->do_copy = 1;
586+ } else {
587+ info->channel_map[ch] = channel_map[ch];
588+ info->input_map[channel_map[ch]] = ch;
589+ info->do_remap = 1;
590+ }
591+ }
592+ /* Fill-in unmapped input channels with unmapped output channels.
593+ This is used when remapping during conversion from interleaved to
594+ planar format. */
595+ for (ch = 0, i = 0; ch < in_channels && i < in_channels; ch++, i++) {
596+ while (ch < in_channels && info->input_map[ch] >= 0)
597+ ch++;
598+ while (i < in_channels && info->channel_map[i] >= 0)
599+ i++;
600+ if (ch >= in_channels || i >= in_channels)
601+ break;
602+ info->input_map[ch] = i;
603+ }
604+
605+ avr->use_channel_map = 1;
606+ return 0;
607+}
608+
470609 int avresample_available(AVAudioResampleContext *avr)
471610 {
472611 return av_audio_fifo_size(avr->out_fifo);
libavresample/version.h+2−2
@@ -20,8 +20,8 @@ · 19 unmodified lines
2020 #define AVRESAMPLE_VERSION_H
2121
2222 #define LIBAVRESAMPLE_VERSION_MAJOR 1
23−#define LIBAVRESAMPLE_VERSION_MINOR 0
24−#define LIBAVRESAMPLE_VERSION_MICRO 1
23+#define LIBAVRESAMPLE_VERSION_MINOR 1
24+#define LIBAVRESAMPLE_VERSION_MICRO 0
2525
2626 #define LIBAVRESAMPLE_VERSION_INT AV_VERSION_INT(LIBAVRESAMPLE_VERSION_MAJOR, \
2727 LIBAVRESAMPLE_VERSION_MINOR, \

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t