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
13 13
14API changes, most recent first:14API changes, most recent first:
15 15
162013-xx-xx - xxxxxxx - lavr 1.1.0
17 Add avresample_set_channel_mapping() for input channel reordering,
18 duplication, and silencing.
19
162012-xx-xx - xxxxxxx - lavu 52.2.1 - avstring.h202012-xx-xx - xxxxxxx - lavu 52.2.1 - avstring.h
17 Add av_basename() and av_dirname().21 Add av_basename() and av_dirname().
18 22
libavresample/audio_convert.c+46−3
@@ -50,6 +50,7 @@ struct AudioConvert { · 49 unmodified lines
50 DitherContext *dc;50 DitherContext *dc;
51 enum AVSampleFormat in_fmt;51 enum AVSampleFormat in_fmt;
52 enum AVSampleFormat out_fmt;52 enum AVSampleFormat out_fmt;
53 int apply_map;
53 int channels;54 int channels;
54 int planes;55 int planes;
55 int ptr_align;56 int ptr_align;
@@ -259,7 +260,8 @@ void ff_audio_convert_free(AudioConvert **ac) · 203 unmodified lines
259AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,260AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
260 enum AVSampleFormat out_fmt,261 enum AVSampleFormat out_fmt,
261 enum AVSampleFormat in_fmt,262 enum AVSampleFormat in_fmt,
262 int channels, int sample_rate)263 int channels, int sample_rate,
264 int apply_map)
263{265{
264 AudioConvert *ac;266 AudioConvert *ac;
265 int in_planar, out_planar;267 int in_planar, out_planar;
@@ -272,11 +274,13 @@ AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, · 6 unmodified lines
272 ac->out_fmt = out_fmt;274 ac->out_fmt = out_fmt;
273 ac->in_fmt = in_fmt;275 ac->in_fmt = in_fmt;
274 ac->channels = channels;276 ac->channels = channels;
277 ac->apply_map = apply_map;
275 278
276 if (avr->dither_method != AV_RESAMPLE_DITHER_NONE &&279 if (avr->dither_method != AV_RESAMPLE_DITHER_NONE &&
277 av_get_packed_sample_fmt(out_fmt) == AV_SAMPLE_FMT_S16 &&280 av_get_packed_sample_fmt(out_fmt) == AV_SAMPLE_FMT_S16 &&
278 av_get_bytes_per_sample(in_fmt) > 2) {281 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);
280 if (!ac->dc) {284 if (!ac->dc) {
281 av_free(ac);285 av_free(ac);
282 return NULL;286 return NULL;
@@ -309,6 +313,7 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) · 26 unmodified lines
309{313{
310 int use_generic = 1;314 int use_generic = 1;
311 int len = in->nb_samples;315 int len = in->nb_samples;
316 int p;
312 317
313 if (ac->dc) {318 if (ac->dc) {
314 /* dithered conversion */319 /* dithered conversion */
@@ -335,9 +340,46 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) · 20 unmodified lines
335 av_get_sample_fmt_name(ac->out_fmt),340 av_get_sample_fmt_name(ac->out_fmt),
336 use_generic ? ac->func_descr_generic : ac->func_descr);341 use_generic ? ac->func_descr_generic : ac->func_descr);
337 342
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 {
338 switch (ac->func_type) {381 switch (ac->func_type) {
339 case CONV_FUNC_TYPE_FLAT: {382 case CONV_FUNC_TYPE_FLAT: {
340 int p;
341 if (!in->is_planar)383 if (!in->is_planar)
342 len *= in->channels;384 len *= in->channels;
343 if (use_generic) {385 if (use_generic) {
@@ -362,6 +404,7 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) · 18 unmodified lines
362 ac->conv_deinterleave(out->data, in->data[0], len, ac->channels);404 ac->conv_deinterleave(out->data, in->data[0], len, ac->channels);
363 break;405 break;
364 }406 }
407 }
365 408
366 out->nb_samples = in->nb_samples;409 out->nb_samples = in->nb_samples;
367 return 0;410 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
58 * @param in_fmt input sample format58 * @param in_fmt input sample format
59 * @param channels number of channels59 * @param channels number of channels
60 * @param sample_rate sample rate (used for dithering)60 * @param sample_rate sample rate (used for dithering)
61 * @param apply_map apply channel map during conversion
61 * @return newly-allocated AudioConvert context62 * @return newly-allocated AudioConvert context
62 */63 */
63AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,64AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
64 enum AVSampleFormat out_fmt,65 enum AVSampleFormat out_fmt,
65 enum AVSampleFormat in_fmt,66 enum AVSampleFormat in_fmt,
66 int channels, int sample_rate);67 int channels, int sample_rate,
68 int apply_map);
67 69
68/**70/**
69 * Free AudioConvert.71 * Free AudioConvert.
libavresample/audio_data.c+29−3
@@ -213,7 +213,7 @@ void ff_audio_data_free(AudioData **a) · 212 unmodified lines
213 av_freep(a);213 av_freep(a);
214}214}
215 215
216int ff_audio_data_copy(AudioData *dst, AudioData *src)216int ff_audio_data_copy(AudioData *dst, AudioData *src, ChannelMapInfo *map)
217{217{
218 int ret, p;218 int ret, p;
219 219
@@ -221,6 +221,11 @@ int ff_audio_data_copy(AudioData *dst, AudioData *src) · 1 unmodified line
221 if (dst->sample_fmt != src->sample_fmt || dst->channels < src->channels)221 if (dst->sample_fmt != src->sample_fmt || dst->channels < src->channels)
222 return AVERROR(EINVAL);222 return AVERROR(EINVAL);
223 223
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
224 /* if the input is empty, just empty the output */229 /* if the input is empty, just empty the output */
225 if (!src->nb_samples) {230 if (!src->nb_samples) {
226 dst->nb_samples = 0;231 dst->nb_samples = 0;
@@ -233,8 +238,29 @@ int ff_audio_data_copy(AudioData *dst, AudioData *src) · 6 unmodified lines
233 return ret;238 return ret;
234 239
235 /* copy data */240 /* copy data */
236 for (p = 0; p < src->planes; p++)241 if (map) {
237 memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride);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
238 dst->nb_samples = src->nb_samples;264 dst->nb_samples = src->nb_samples;
239 265
240 return 0;266 return 0;
libavresample/audio_data.h+2−1
@@ -118,9 +118,10 @@ void ff_audio_data_free(AudioData **a); · 117 unmodified lines
118 *118 *
119 * @param out output AudioData119 * @param out output AudioData
120 * @param in input AudioData120 * @param in input AudioData
121 * @param map channel map, NULL if not remapping
121 * @return 0 on success, negative AVERROR value on error122 * @return 0 on success, negative AVERROR value on error
122 */123 */
123int ff_audio_data_copy(AudioData *out, AudioData *in);124int ff_audio_data_copy(AudioData *out, AudioData *in, ChannelMapInfo *map);
124 125
125/**126/**
126 * Append data from one AudioData to the end of another.127 * 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
258int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,258int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
259 int stride);259 int stride);
260 260
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 */
288int avresample_set_channel_mapping(AVAudioResampleContext *avr,
289 const int *channel_map);
290
261/**291/**
262 * Set compensation for resampling.292 * Set compensation for resampling.
263 *293 *
libavresample/dither.c+19−6
@@ -53,6 +53,8 @@ typedef struct DitherState { · 52 unmodified lines
53struct DitherContext {53struct DitherContext {
54 DitherDSPContext ddsp;54 DitherDSPContext ddsp;
55 enum AVResampleDitherMethod method;55 enum AVResampleDitherMethod method;
56 int apply_map;
57 ChannelMapInfo *ch_map_info;
56 58
57 int mute_dither_threshold; // threshold for disabling dither59 int mute_dither_threshold; // threshold for disabling dither
58 int mute_reset_threshold; // threshold for resetting noise shaping60 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
251 return ret;253 return ret;
252 }254 }
253 255
254 if (src->sample_fmt != AV_SAMPLE_FMT_FLTP) {256 if (src->sample_fmt != AV_SAMPLE_FMT_FLTP || c->apply_map) {
255 /* make sure flt_data is large enough for the input */257 /* make sure flt_data is large enough for the input */
256 ret = ff_audio_data_realloc(c->flt_data, src->nb_samples);258 ret = ff_audio_data_realloc(c->flt_data, src->nb_samples);
257 if (ret < 0)259 if (ret < 0)
258 return ret;260 return ret;
259 flt_data = c->flt_data;261 flt_data = c->flt_data;
262 }
260 263
264 if (src->sample_fmt != AV_SAMPLE_FMT_FLTP) {
261 /* convert input samples to fltp and scale to s16 range */265 /* convert input samples to fltp and scale to s16 range */
262 ret = ff_audio_convert(c->ac_in, flt_data, src);266 ret = ff_audio_convert(c->ac_in, flt_data, src);
263 if (ret < 0)267 if (ret < 0)
264 return ret;268 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;
265 } else {273 } else {
266 flt_data = src;274 flt_data = src;
267 }275 }
@@ -333,7 +341,7 @@ static void dither_init(DitherDSPContext *ddsp, · 65 unmodified lines
333DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,341DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,
334 enum AVSampleFormat out_fmt,342 enum AVSampleFormat out_fmt,
335 enum AVSampleFormat in_fmt,343 enum AVSampleFormat in_fmt,
336 int channels, int sample_rate)344 int channels, int sample_rate, int apply_map)
337{345{
338 AVLFG seed_gen;346 AVLFG seed_gen;
339 DitherContext *c;347 DitherContext *c;
@@ -350,6 +358,10 @@ DitherContext *ff_dither_alloc(AVAudioResampleContext *avr, · 10 unmodified lines
350 if (!c)358 if (!c)
351 return NULL;359 return NULL;
352 360
361 c->apply_map = apply_map;
362 if (apply_map)
363 c->ch_map_info = &avr->ch_map_info;
364
353 if (avr->dither_method == AV_RESAMPLE_DITHER_TRIANGULAR_NS &&365 if (avr->dither_method == AV_RESAMPLE_DITHER_TRIANGULAR_NS &&
354 sample_rate != 48000 && sample_rate != 44100) {366 sample_rate != 48000 && sample_rate != 44100) {
355 av_log(avr, AV_LOG_WARNING, "sample rate must be 48000 or 44100 Hz "367 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
379 goto fail;391 goto fail;
380 392
381 c->ac_out = ff_audio_convert_alloc(avr, out_fmt, AV_SAMPLE_FMT_S16P,393 c->ac_out = ff_audio_convert_alloc(avr, out_fmt, AV_SAMPLE_FMT_S16P,
382 channels, sample_rate);394 channels, sample_rate, 0);
383 if (!c->ac_out)395 if (!c->ac_out)
384 goto fail;396 goto fail;
385 }397 }
386 398
387 if (in_fmt != AV_SAMPLE_FMT_FLTP) {399 if (in_fmt != AV_SAMPLE_FMT_FLTP || c->apply_map) {
388 c->flt_data = ff_audio_data_alloc(channels, 1024, AV_SAMPLE_FMT_FLTP,400 c->flt_data = ff_audio_data_alloc(channels, 1024, AV_SAMPLE_FMT_FLTP,
389 "dither flt buffer");401 "dither flt buffer");
390 if (!c->flt_data)402 if (!c->flt_data)
391 goto fail;403 goto fail;
392 404 }
405 if (in_fmt != AV_SAMPLE_FMT_FLTP) {
393 c->ac_in = ff_audio_convert_alloc(avr, AV_SAMPLE_FMT_FLTP, in_fmt,406 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);
395 if (!c->ac_in)408 if (!c->ac_in)
396 goto fail;409 goto fail;
397 }410 }
libavresample/dither.h+1−1
@@ -66,7 +66,7 @@ typedef struct DitherDSPContext { · 65 unmodified lines
66DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,66DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,
67 enum AVSampleFormat out_fmt,67 enum AVSampleFormat out_fmt,
68 enum AVSampleFormat in_fmt,68 enum AVSampleFormat in_fmt,
69 int channels, int sample_rate);69 int channels, int sample_rate, int apply_map);
70 70
71/**71/**
72 * Free a DitherContext.72 * Free a DitherContext.
libavresample/internal.h+23−0
@@ -32,6 +32,24 @@ typedef struct AudioConvert AudioConvert; · 31 unmodified lines
32typedef struct AudioMix AudioMix;32typedef struct AudioMix AudioMix;
33typedef struct ResampleContext ResampleContext;33typedef struct ResampleContext ResampleContext;
34 34
35enum RemapPoint {
36 REMAP_NONE,
37 REMAP_IN_COPY,
38 REMAP_IN_CONVERT,
39 REMAP_OUT_COPY,
40 REMAP_OUT_CONVERT,
41};
42
43typedef 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
35struct AVAudioResampleContext {53struct AVAudioResampleContext {
36 const AVClass *av_class; /**< AVClass for logging and AVOptions */54 const AVClass *av_class; /**< AVClass for logging and AVOptions */
37 55
@@ -65,6 +83,7 @@ struct AVAudioResampleContext { · 27 unmodified lines
65 int resample_needed; /**< resampling is needed */83 int resample_needed; /**< resampling is needed */
66 int in_convert_needed; /**< input sample format conversion is needed */84 int in_convert_needed; /**< input sample format conversion is needed */
67 int out_convert_needed; /**< output sample format conversion is needed */85 int out_convert_needed; /**< output sample format conversion is needed */
86 int in_copy_needed; /**< input data copy is needed */
68 87
69 AudioData *in_buffer; /**< buffer for converted input */88 AudioData *in_buffer; /**< buffer for converted input */
70 AudioData *resample_out_buffer; /**< buffer for output from resampler */89 AudioData *resample_out_buffer; /**< buffer for output from resampler */
@@ -82,6 +101,10 @@ struct AVAudioResampleContext { · 11 unmodified lines
82 * only used if avresample_set_matrix() is called before avresample_open()101 * only used if avresample_set_matrix() is called before avresample_open()
83 */102 */
84 double *mix_matrix;103 double *mix_matrix;
104
105 int use_channel_map;
106 enum RemapPoint remap_point;
107 ChannelMapInfo ch_map_info;
85};108};
86 109
87#endif /* AVRESAMPLE_INTERNAL_H */110#endif /* AVRESAMPLE_INTERNAL_H */
libavresample/utils.c+146−10
@@ -96,20 +96,84 @@ int avresample_open(AVAudioResampleContext *avr) · 95 unmodified lines
96 av_get_sample_fmt_name(avr->internal_sample_fmt));96 av_get_sample_fmt_name(avr->internal_sample_fmt));
97 }97 }
98 98
99 /* set sample format conversion parameters */99 /* treat all mono as planar for easier comparison */
100 if (avr->in_channels == 1)100 if (avr->in_channels == 1)
101 avr->in_sample_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt);101 avr->in_sample_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt);
102 if (avr->out_channels == 1)102 if (avr->out_channels == 1)
103 avr->out_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt);103 avr->out_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt);
104 avr->in_convert_needed = (avr->resample_needed || avr->mixing_needed) &&104
105 avr->in_sample_fmt != avr->internal_sample_fmt;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 */
106 if (avr->resample_needed || avr->mixing_needed)113 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)
107 avr->out_convert_needed = avr->internal_sample_fmt != avr->out_sample_fmt;120 avr->out_convert_needed = avr->internal_sample_fmt != avr->out_sample_fmt;
108 else121 else
109 avr->out_convert_needed = avr->in_sample_fmt != avr->out_sample_fmt;122 avr->out_convert_needed = avr->in_sample_fmt != avr->out_sample_fmt;
110 123
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
111 /* allocate buffers */175 /* allocate buffers */
112 if (avr->mixing_needed || avr->in_convert_needed) {176 if (avr->in_copy_needed || avr->in_convert_needed) {
113 avr->in_buffer = ff_audio_data_alloc(FFMAX(avr->in_channels, avr->out_channels),177 avr->in_buffer = ff_audio_data_alloc(FFMAX(avr->in_channels, avr->out_channels),
114 0, avr->internal_sample_fmt,178 0, avr->internal_sample_fmt,
115 "in_buffer");179 "in_buffer");
@@ -146,7 +210,8 @@ int avresample_open(AVAudioResampleContext *avr) · 30 unmodified lines
146 if (avr->in_convert_needed) {210 if (avr->in_convert_needed) {
147 avr->ac_in = ff_audio_convert_alloc(avr, avr->internal_sample_fmt,211 avr->ac_in = ff_audio_convert_alloc(avr, avr->internal_sample_fmt,
148 avr->in_sample_fmt, avr->in_channels,212 avr->in_sample_fmt, avr->in_channels,
149 avr->in_sample_rate);213 avr->in_sample_rate,
214 avr->remap_point == REMAP_IN_CONVERT);
150 if (!avr->ac_in) {215 if (!avr->ac_in) {
151 ret = AVERROR(ENOMEM);216 ret = AVERROR(ENOMEM);
152 goto error;217 goto error;
@@ -160,7 +225,8 @@ int avresample_open(AVAudioResampleContext *avr) · 7 unmodified lines
160 src_fmt = avr->in_sample_fmt;225 src_fmt = avr->in_sample_fmt;
161 avr->ac_out = ff_audio_convert_alloc(avr, avr->out_sample_fmt, src_fmt,226 avr->ac_out = ff_audio_convert_alloc(avr, avr->out_sample_fmt, src_fmt,
162 avr->out_channels,227 avr->out_channels,
163 avr->out_sample_rate);228 avr->out_sample_rate,
229 avr->remap_point == REMAP_OUT_CONVERT);
164 if (!avr->ac_out) {230 if (!avr->ac_out) {
165 ret = AVERROR(ENOMEM);231 ret = AVERROR(ENOMEM);
166 goto error;232 goto error;
@@ -200,6 +266,8 @@ void avresample_close(AVAudioResampleContext *avr) · 33 unmodified lines
200 ff_audio_resample_free(&avr->resample);266 ff_audio_resample_free(&avr->resample);
201 ff_audio_mix_free(&avr->am);267 ff_audio_mix_free(&avr->am);
202 av_freep(&avr->mix_matrix);268 av_freep(&avr->mix_matrix);
269
270 avr->use_channel_map = 0;
203}271}
204 272
205void avresample_free(AVAudioResampleContext **avr)273void avresample_free(AVAudioResampleContext **avr)
@@ -242,7 +310,9 @@ static int handle_buffered_output(AVAudioResampleContext *avr, · 36 unmodified lines
242 data in the output FIFO */310 data in the output FIFO */
243 av_dlog(avr, "[copy] %s to output\n", converted->name);311 av_dlog(avr, "[copy] %s to output\n", converted->name);
244 output->nb_samples = 0;312 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);
246 if (ret < 0)316 if (ret < 0)
247 return ret;317 return ret;
248 av_dlog(avr, "[end conversion]\n");318 av_dlog(avr, "[end conversion]\n");
@@ -306,11 +376,24 @@ int attribute_align_arg avresample_convert(AVAudioResampleContext *avr, · 57 unmodified lines
306 /* in some rare cases we can copy input to output and upmix376 /* in some rare cases we can copy input to output and upmix
307 directly in the output buffer */377 directly in the output buffer */
308 av_dlog(avr, "[copy] %s to output\n", current_buffer->name);378 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);
310 if (ret < 0)382 if (ret < 0)
311 return ret;383 return ret;
312 current_buffer = &output_buffer;384 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) {
314 /* if needed, copy or convert input to in_buffer, and downmix if397 /* if needed, copy or convert input to in_buffer, and downmix if
315 applicable */398 applicable */
316 if (avr->in_convert_needed) {399 if (avr->in_convert_needed) {
@@ -325,7 +408,9 @@ int attribute_align_arg avresample_convert(AVAudioResampleContext *avr, · 8 unmodified lines
325 return ret;408 return ret;
326 } else {409 } else {
327 av_dlog(avr, "[copy] %s to in_buffer\n", current_buffer->name);410 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);
329 if (ret < 0)414 if (ret < 0)
330 return ret;415 return ret;
331 }416 }
@@ -470,6 +555,57 @@ int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix, · 138 unmodified lines
470 return 0;555 return 0;
471}556}
472 557
558int 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
473int avresample_available(AVAudioResampleContext *avr)609int avresample_available(AVAudioResampleContext *avr)
474{610{
475 return av_audio_fifo_size(avr->out_fifo);611 return av_audio_fifo_size(avr->out_fifo);
libavresample/version.h+2−2
@@ -20,8 +20,8 @@ · 19 unmodified lines
20#define AVRESAMPLE_VERSION_H20#define AVRESAMPLE_VERSION_H
21 21
22#define LIBAVRESAMPLE_VERSION_MAJOR 122#define LIBAVRESAMPLE_VERSION_MAJOR 1
23#define LIBAVRESAMPLE_VERSION_MINOR 023#define LIBAVRESAMPLE_VERSION_MINOR 1
24#define LIBAVRESAMPLE_VERSION_MICRO 124#define LIBAVRESAMPLE_VERSION_MICRO 0
25 25
26#define LIBAVRESAMPLE_VERSION_INT AV_VERSION_INT(LIBAVRESAMPLE_VERSION_MAJOR, \26#define LIBAVRESAMPLE_VERSION_INT AV_VERSION_INT(LIBAVRESAMPLE_VERSION_MAJOR, \
27 LIBAVRESAMPLE_VERSION_MINOR, \27 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