History

lavr: add a public function for setting a custom channel map

This allows reordering, duplication, and silencing of input channels.

Justin Ruggles committed 13 years ago

Commit 074a00d1 parent 4d6826911 files · +305 −27Browse files

Unified · Split

11 files
  1. doc/APIchanges +4 −0
  2. libavresample/audio_convert.c +46 −3
  3. libavresample/audio_convert.h +3 −1
  4. libavresample/audio_data.c +29 −3
  5. libavresample/audio_data.h +2 −1
  6. libavresample/avresample.h +30 −0
  7. libavresample/dither.c +19 −6
  8. libavresample/dither.h +1 −1
  9. libavresample/internal.h +23 −0
  10. libavresample/utils.c +146 −10
  11. libavresample/version.h +2 −2
doc/APIchanges+4−0
@@ -13,6 +13,10 @@ libavutil: 2012-10-22 · 12 unmodified lines
1313
1414 API changes, most recent first:
1515
16+2013-xx-xx - xxxxxxx - lavr 1.1.0
17+ Add avresample_set_channel_mapping() for input channel reordering,
18+ duplication, and silencing.
19+
1620 2012-xx-xx - xxxxxxx - lavu 52.2.1 - avstring.h
1721 Add av_basename() and av_dirname().
1822
libavresample/audio_convert.c+46−3
@@ -50,6 +50,7 @@ struct AudioConvert { · 49 unmodified lines
5050 DitherContext *dc;
5151 enum AVSampleFormat in_fmt;
5252 enum AVSampleFormat out_fmt;
53+ int apply_map;
5354 int channels;
5455 int planes;
5556 int ptr_align;
@@ -259,7 +260,8 @@ void ff_audio_convert_free(AudioConvert **ac) · 203 unmodified lines
259260 AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
260261 enum AVSampleFormat out_fmt,
261262 enum AVSampleFormat in_fmt,
262− int channels, int sample_rate)
263+ int channels, int sample_rate,
264+ int apply_map)
263265 {
264266 AudioConvert *ac;
265267 int in_planar, out_planar;
@@ -272,11 +274,13 @@ AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, · 6 unmodified lines
272274 ac->out_fmt = out_fmt;
273275 ac->in_fmt = in_fmt;
274276 ac->channels = channels;
277+ ac->apply_map = apply_map;
275278
276279 if (avr->dither_method != AV_RESAMPLE_DITHER_NONE &&
277280 av_get_packed_sample_fmt(out_fmt) == AV_SAMPLE_FMT_S16 &&
278281 av_get_bytes_per_sample(in_fmt) > 2) {
279− 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);
280284 if (!ac->dc) {
281285 av_free(ac);
282286 return NULL;
@@ -309,6 +313,7 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) · 26 unmodified lines
309313 {
310314 int use_generic = 1;
311315 int len = in->nb_samples;
316+ int p;
312317
313318 if (ac->dc) {
314319 /* dithered conversion */
@@ -335,9 +340,46 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) · 20 unmodified lines
335340 av_get_sample_fmt_name(ac->out_fmt),
336341 use_generic ? ac->func_descr_generic : ac->func_descr);
337342
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 {
338381 switch (ac->func_type) {
339382 case CONV_FUNC_TYPE_FLAT: {
340− int p;
341383 if (!in->is_planar)
342384 len *= in->channels;
343385 if (use_generic) {
@@ -362,6 +404,7 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) · 18 unmodified lines
362404 ac->conv_deinterleave(out->data, in->data[0], len, ac->channels);
363405 break;
364406 }
407+ }
365408
366409 out->nb_samples = in->nb_samples;
367410 return 0;
libavresample/audio_convert.h+3−1
@@ -58,12 +58,14 @@ void ff_audio_convert_set_func(AudioConvert *ac, enum AVSampleFormat out_fmt, · 57 unmodified lines
5858 * @param in_fmt input sample format
5959 * @param channels number of channels
6060 * @param sample_rate sample rate (used for dithering)
61+ * @param apply_map apply channel map during conversion
6162 * @return newly-allocated AudioConvert context
6263 */
6364 AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
6465 enum AVSampleFormat out_fmt,
6566 enum AVSampleFormat in_fmt,
66− int channels, int sample_rate);
67+ int channels, int sample_rate,
68+ int apply_map);
6769
6870 /**
6971 * 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+2−1
@@ -118,9 +118,10 @@ void ff_audio_data_free(AudioData **a); · 117 unmodified lines
118118 *
119119 * @param out output AudioData
120120 * @param in input AudioData
121+ * @param map channel map, NULL if not remapping
121122 * @return 0 on success, negative AVERROR value on error
122123 */
123−int ff_audio_data_copy(AudioData *out, AudioData *in);
124+int ff_audio_data_copy(AudioData *out, AudioData *in, ChannelMapInfo *map);
124125
125126 /**
126127 * Append data from one AudioData to the end of another.
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+23−0
@@ -32,6 +32,24 @@ typedef struct AudioConvert AudioConvert; · 31 unmodified lines
3232 typedef struct AudioMix AudioMix;
3333 typedef struct ResampleContext ResampleContext;
3434
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;
52+
3553 struct AVAudioResampleContext {
3654 const AVClass *av_class; /**< AVClass for logging and AVOptions */
3755
@@ -65,6 +83,7 @@ struct AVAudioResampleContext { · 27 unmodified lines
6583 int resample_needed; /**< resampling is needed */
6684 int in_convert_needed; /**< input sample format conversion is needed */
6785 int out_convert_needed; /**< output sample format conversion is needed */
86+ int in_copy_needed; /**< input data copy is needed */
6887
6988 AudioData *in_buffer; /**< buffer for converted input */
7089 AudioData *resample_out_buffer; /**< buffer for output from resampler */
@@ -82,6 +101,10 @@ struct AVAudioResampleContext { · 11 unmodified lines
82101 * only used if avresample_set_matrix() is called before avresample_open()
83102 */
84103 double *mix_matrix;
104+
105+ int use_channel_map;
106+ enum RemapPoint remap_point;
107+ ChannelMapInfo ch_map_info;
85108 };
86109
87110 #endif /* AVRESAMPLE_INTERNAL_H */
libavresample/utils.c+146−10
@@ -96,20 +96,84 @@ int avresample_open(AVAudioResampleContext *avr) · 95 unmodified lines
9696 av_get_sample_fmt_name(avr->internal_sample_fmt));
9797 }
9898
99− /* set sample format conversion parameters */
99+ /* treat all mono as planar for easier comparison */
100100 if (avr->in_channels == 1)
101101 avr->in_sample_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt);
102102 if (avr->out_channels == 1)
103103 avr->out_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt);
104− avr->in_convert_needed = (avr->resample_needed || avr->mixing_needed) &&
105− 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 */
106113 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)
107120 avr->out_convert_needed = avr->internal_sample_fmt != avr->out_sample_fmt;
108121 else
109122 avr->out_convert_needed = avr->in_sample_fmt != avr->out_sample_fmt;
110123
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+
111175 /* allocate buffers */
112− if (avr->mixing_needed || avr->in_convert_needed) {
176+ if (avr->in_copy_needed || avr->in_convert_needed) {
113177 avr->in_buffer = ff_audio_data_alloc(FFMAX(avr->in_channels, avr->out_channels),
114178 0, avr->internal_sample_fmt,
115179 "in_buffer");
@@ -146,7 +210,8 @@ int avresample_open(AVAudioResampleContext *avr) · 30 unmodified lines
146210 if (avr->in_convert_needed) {
147211 avr->ac_in = ff_audio_convert_alloc(avr, avr->internal_sample_fmt,
148212 avr->in_sample_fmt, avr->in_channels,
149− avr->in_sample_rate);
213+ avr->in_sample_rate,
214+ avr->remap_point == REMAP_IN_CONVERT);
150215 if (!avr->ac_in) {
151216 ret = AVERROR(ENOMEM);
152217 goto error;
@@ -160,7 +225,8 @@ int avresample_open(AVAudioResampleContext *avr) · 7 unmodified lines
160225 src_fmt = avr->in_sample_fmt;
161226 avr->ac_out = ff_audio_convert_alloc(avr, avr->out_sample_fmt, src_fmt,
162227 avr->out_channels,
163− avr->out_sample_rate);
228+ avr->out_sample_rate,
229+ avr->remap_point == REMAP_OUT_CONVERT);
164230 if (!avr->ac_out) {
165231 ret = AVERROR(ENOMEM);
166232 goto error;
@@ -200,6 +266,8 @@ void avresample_close(AVAudioResampleContext *avr) · 33 unmodified lines
200266 ff_audio_resample_free(&avr->resample);
201267 ff_audio_mix_free(&avr->am);
202268 av_freep(&avr->mix_matrix);
269+
270+ avr->use_channel_map = 0;
203271 }
204272
205273 void avresample_free(AVAudioResampleContext **avr)
@@ -242,7 +310,9 @@ static int handle_buffered_output(AVAudioResampleContext *avr, · 36 unmodified lines
242310 data in the output FIFO */
243311 av_dlog(avr, "[copy] %s to output\n", converted->name);
244312 output->nb_samples = 0;
245− 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);
246316 if (ret < 0)
247317 return ret;
248318 av_dlog(avr, "[end conversion]\n");
@@ -306,11 +376,24 @@ int attribute_align_arg avresample_convert(AVAudioResampleContext *avr, · 57 unmodified lines
306376 /* in some rare cases we can copy input to output and upmix
307377 directly in the output buffer */
308378 av_dlog(avr, "[copy] %s to output\n", current_buffer->name);
309− 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);
310382 if (ret < 0)
311383 return ret;
312384 current_buffer = &output_buffer;
313− } 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) {
314397 /* if needed, copy or convert input to in_buffer, and downmix if
315398 applicable */
316399 if (avr->in_convert_needed) {
@@ -325,7 +408,9 @@ int attribute_align_arg avresample_convert(AVAudioResampleContext *avr, · 8 unmodified lines
325408 return ret;
326409 } else {
327410 av_dlog(avr, "[copy] %s to in_buffer\n", current_buffer->name);
328− 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);
329414 if (ret < 0)
330415 return ret;
331416 }
@@ -470,6 +555,57 @@ int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix, · 138 unmodified lines
470555 return 0;
471556 }
472557
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+
473609 int avresample_available(AVAudioResampleContext *avr)
474610 {
475611 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