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
1322012-03-26 - a67d9cf - lavfi 2.66.1001322012-03-26 - a67d9cf - lavfi 2.66.100
133 Add avfilter_fill_frame_from_{audio_,}buffer_ref() functions.133 Add avfilter_fill_frame_from_{audio_,}buffer_ref() functions.
134 134
1352013-xx-xx - xxxxxxx - lavr 1.1.0
136 Add avresample_set_channel_mapping() for input channel reordering,
137 duplication, and silencing.
138
1352012-xx-xx - xxxxxxx - lavu 52.2.1 - avstring.h1392012-xx-xx - xxxxxxx - lavu 52.2.1 - avstring.h
136 Add av_basename() and av_dirname().140 Add av_basename() and av_dirname().
137 141
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
228 You can commit unfinished stuff (for testing etc), but it must be disabled228 You can commit unfinished stuff (for testing etc), but it must be disabled
229 (#ifdef etc) by default so it does not interfere with other developers'229 (#ifdef etc) by default so it does not interfere with other developers'
230 work.230 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.
231@item238@item
232 You do not have to over-test things. If it works for you, and you think it239 You do not have to over-test things. If it works for you, and you think it
233 should work for others, then commit. If your code has problems240 should work for others, then commit. If your code has problems
libavresample/audio_convert.c+46−4
@@ -30,7 +30,6 @@ · 29 unmodified lines
30#include "audio_convert.h"30#include "audio_convert.h"
31#include "audio_data.h"31#include "audio_data.h"
32#include "dither.h"32#include "dither.h"
33#include "internal.h"
34 33
35enum ConvFuncType {34enum ConvFuncType {
36 CONV_FUNC_TYPE_FLAT,35 CONV_FUNC_TYPE_FLAT,
@@ -51,6 +50,7 @@ struct AudioConvert { · 14 unmodified lines
51 DitherContext *dc;50 DitherContext *dc;
52 enum AVSampleFormat in_fmt;51 enum AVSampleFormat in_fmt;
53 enum AVSampleFormat out_fmt;52 enum AVSampleFormat out_fmt;
53 int apply_map;
54 int channels;54 int channels;
55 int planes;55 int planes;
56 int ptr_align;56 int ptr_align;
@@ -260,7 +260,8 @@ void ff_audio_convert_free(AudioConvert **ac) · 203 unmodified lines
260AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,260AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
261 enum AVSampleFormat out_fmt,261 enum AVSampleFormat out_fmt,
262 enum AVSampleFormat in_fmt,262 enum AVSampleFormat in_fmt,
263 int channels, int sample_rate)263 int channels, int sample_rate,
264 int apply_map)
264{265{
265 AudioConvert *ac;266 AudioConvert *ac;
266 int in_planar, out_planar;267 int in_planar, out_planar;
@@ -273,11 +274,13 @@ AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, · 6 unmodified lines
273 ac->out_fmt = out_fmt;274 ac->out_fmt = out_fmt;
274 ac->in_fmt = in_fmt;275 ac->in_fmt = in_fmt;
275 ac->channels = channels;276 ac->channels = channels;
277 ac->apply_map = apply_map;
276 278
277 if (avr->dither_method != AV_RESAMPLE_DITHER_NONE &&279 if (avr->dither_method != AV_RESAMPLE_DITHER_NONE &&
278 av_get_packed_sample_fmt(out_fmt) == AV_SAMPLE_FMT_S16 &&280 av_get_packed_sample_fmt(out_fmt) == AV_SAMPLE_FMT_S16 &&
279 av_get_bytes_per_sample(in_fmt) > 2) {281 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);
281 if (!ac->dc) {284 if (!ac->dc) {
282 av_free(ac);285 av_free(ac);
283 return NULL;286 return NULL;
@@ -310,6 +313,7 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) · 26 unmodified lines
310{313{
311 int use_generic = 1;314 int use_generic = 1;
312 int len = in->nb_samples;315 int len = in->nb_samples;
316 int p;
313 317
314 if (ac->dc) {318 if (ac->dc) {
315 /* dithered conversion */319 /* dithered conversion */
@@ -336,9 +340,46 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) · 20 unmodified lines
336 av_get_sample_fmt_name(ac->out_fmt),340 av_get_sample_fmt_name(ac->out_fmt),
337 use_generic ? ac->func_descr_generic : ac->func_descr);341 use_generic ? ac->func_descr_generic : ac->func_descr);
338 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 {
339 switch (ac->func_type) {381 switch (ac->func_type) {
340 case CONV_FUNC_TYPE_FLAT: {382 case CONV_FUNC_TYPE_FLAT: {
341 int p;
342 if (!in->is_planar)383 if (!in->is_planar)
343 len *= in->channels;384 len *= in->channels;
344 if (use_generic) {385 if (use_generic) {
@@ -363,6 +404,7 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) · 18 unmodified lines
363 ac->conv_deinterleave(out->data, in->data[0], len, ac->channels);404 ac->conv_deinterleave(out->data, in->data[0], len, ac->channels);
364 break;405 break;
365 }406 }
407 }
366 408
367 out->nb_samples = in->nb_samples;409 out->nb_samples = in->nb_samples;
368 return 0;410 return 0;
libavresample/audio_convert.h+4−3
@@ -23,10 +23,9 @@ · 22 unmodified lines
23 23
24#include "libavutil/samplefmt.h"24#include "libavutil/samplefmt.h"
25#include "avresample.h"25#include "avresample.h"
26#include "internal.h"
26#include "audio_data.h"27#include "audio_data.h"
27 28
28typedef struct AudioConvert AudioConvert;
29
30/**29/**
31 * Set conversion function if the parameters match.30 * Set conversion function if the parameters match.
32 *31 *
@@ -59,12 +58,14 @@ void ff_audio_convert_set_func(AudioConvert *ac, enum AVSampleFormat out_fmt, · 26 unmodified lines
59 * @param in_fmt input sample format58 * @param in_fmt input sample format
60 * @param channels number of channels59 * @param channels number of channels
61 * @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
62 * @return newly-allocated AudioConvert context62 * @return newly-allocated AudioConvert context
63 */63 */
64AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,64AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
65 enum AVSampleFormat out_fmt,65 enum AVSampleFormat out_fmt,
66 enum AVSampleFormat in_fmt,66 enum AVSampleFormat in_fmt,
67 int channels, int sample_rate);67 int channels, int sample_rate,
68 int apply_map);
68 69
69/**70/**
70 * 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+5−3
@@ -27,11 +27,12 @@ · 26 unmodified lines
27#include "libavutil/log.h"27#include "libavutil/log.h"
28#include "libavutil/samplefmt.h"28#include "libavutil/samplefmt.h"
29#include "avresample.h"29#include "avresample.h"
30#include "internal.h"
30 31
31/**32/**
32 * Audio buffer used for intermediate storage between conversion phases.33 * Audio buffer used for intermediate storage between conversion phases.
33 */34 */
34typedef struct AudioData {35struct AudioData {
35 const AVClass *class; /**< AVClass for logging */36 const AVClass *class; /**< AVClass for logging */
36 uint8_t *data[AVRESAMPLE_MAX_CHANNELS]; /**< data plane pointers */37 uint8_t *data[AVRESAMPLE_MAX_CHANNELS]; /**< data plane pointers */
37 uint8_t *buffer; /**< data buffer */38 uint8_t *buffer; /**< data buffer */
@@ -50,7 +51,7 @@ typedef struct AudioData { · 12 unmodified lines
50 int ptr_align; /**< minimum data pointer alignment */51 int ptr_align; /**< minimum data pointer alignment */
51 int samples_align; /**< allocated samples alignment */52 int samples_align; /**< allocated samples alignment */
52 const char *name; /**< name for debug logging */53 const char *name; /**< name for debug logging */
53} AudioData;54};
54 55
55int ff_audio_data_set_channels(AudioData *a, int channels);56int ff_audio_data_set_channels(AudioData *a, int channels);
56 57
@@ -117,9 +118,10 @@ void ff_audio_data_free(AudioData **a); · 60 unmodified lines
117 *118 *
118 * @param out output AudioData119 * @param out output AudioData
119 * @param in input AudioData120 * @param in input AudioData
121 * @param map channel map, NULL if not remapping
120 * @return 0 on success, negative AVERROR value on error122 * @return 0 on success, negative AVERROR value on error
121 */123 */
122int ff_audio_data_copy(AudioData *out, AudioData *in);124int ff_audio_data_copy(AudioData *out, AudioData *in, ChannelMapInfo *map);
123 125
124/**126/**
125 * Append data from one AudioData to the end of another.127 * Append data from one AudioData to the end of another.
libavresample/audio_mix.h+1−2
@@ -25,13 +25,12 @@ · 24 unmodified lines
25 25
26#include "libavutil/samplefmt.h"26#include "libavutil/samplefmt.h"
27#include "avresample.h"27#include "avresample.h"
28#include "internal.h"
28#include "audio_data.h"29#include "audio_data.h"
29 30
30typedef void (mix_func)(uint8_t **src, void **matrix, int len, int out_ch,31typedef void (mix_func)(uint8_t **src, void **matrix, int len, int out_ch,
31 int in_ch);32 int in_ch);
32 33
33typedef struct AudioMix AudioMix;
34
35/**34/**
36 * Set mixing function if the parameters match.35 * Set mixing function if the parameters match.
37 *36 *
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+28−4
@@ -26,10 +26,29 @@ · 25 unmodified lines
26#include "libavutil/opt.h"26#include "libavutil/opt.h"
27#include "libavutil/samplefmt.h"27#include "libavutil/samplefmt.h"
28#include "avresample.h"28#include "avresample.h"
29#include "audio_convert.h"29
30#include "audio_data.h"30typedef struct AudioData AudioData;
31#include "audio_mix.h"31typedef struct AudioConvert AudioConvert;
32#include "resample.h"32typedef struct AudioMix AudioMix;
33typedef struct ResampleContext ResampleContext;
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;
33 52
34struct AVAudioResampleContext {53struct AVAudioResampleContext {
35 const AVClass *av_class; /**< AVClass for logging and AVOptions */54 const AVClass *av_class; /**< AVClass for logging and AVOptions */
@@ -64,6 +83,7 @@ struct AVAudioResampleContext { · 28 unmodified lines
64 int resample_needed; /**< resampling is needed */83 int resample_needed; /**< resampling is needed */
65 int in_convert_needed; /**< input sample format conversion is needed */84 int in_convert_needed; /**< input sample format conversion is needed */
66 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 */
67 87
68 AudioData *in_buffer; /**< buffer for converted input */88 AudioData *in_buffer; /**< buffer for converted input */
69 AudioData *resample_out_buffer; /**< buffer for output from resampler */89 AudioData *resample_out_buffer; /**< buffer for output from resampler */
@@ -81,6 +101,10 @@ struct AVAudioResampleContext { · 11 unmodified lines
81 * only used if avresample_set_matrix() is called before avresample_open()101 * only used if avresample_set_matrix() is called before avresample_open()
82 */102 */
83 double *mix_matrix;103 double *mix_matrix;
104
105 int use_channel_map;
106 enum RemapPoint remap_point;
107 ChannelMapInfo ch_map_info;
84};108};
85 109
86#endif /* AVRESAMPLE_INTERNAL_H */110#endif /* AVRESAMPLE_INTERNAL_H */
libavresample/resample.c+1−0
@@ -23,6 +23,7 @@ · 22 unmodified lines
23#include "libavutil/libm.h"23#include "libavutil/libm.h"
24#include "libavutil/log.h"24#include "libavutil/log.h"
25#include "internal.h"25#include "internal.h"
26#include "resample.h"
26#include "audio_data.h"27#include "audio_data.h"
27 28
28struct ResampleContext {29struct ResampleContext {
libavresample/resample.h+1−2
@@ -22,10 +22,9 @@ · 21 unmodified lines
22#define AVRESAMPLE_RESAMPLE_H22#define AVRESAMPLE_RESAMPLE_H
23 23
24#include "avresample.h"24#include "avresample.h"
25#include "internal.h"
25#include "audio_data.h"26#include "audio_data.h"
26 27
27typedef struct ResampleContext ResampleContext;
28
29/**28/**
30 * Allocate and initialize a ResampleContext.29 * Allocate and initialize a ResampleContext.
31 *30 *
libavresample/utils.c+150−11
@@ -26,8 +26,11 @@ · 25 unmodified lines
26#include "libavutil/opt.h"26#include "libavutil/opt.h"
27 27
28#include "avresample.h"28#include "avresample.h"
29#include "audio_data.h"
30#include "internal.h"29#include "internal.h"
30#include "audio_data.h"
31#include "audio_convert.h"
32#include "audio_mix.h"
33#include "resample.h"
31 34
32int avresample_open(AVAudioResampleContext *avr)35int avresample_open(AVAudioResampleContext *avr)
33{36{
@@ -93,20 +96,84 @@ int avresample_open(AVAudioResampleContext *avr) · 59 unmodified lines
93 av_get_sample_fmt_name(avr->internal_sample_fmt));96 av_get_sample_fmt_name(avr->internal_sample_fmt));
94 }97 }
95 98
96 /* set sample format conversion parameters */99 /* treat all mono as planar for easier comparison */
97 if (avr->in_channels == 1)100 if (avr->in_channels == 1)
98 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);
99 if (avr->out_channels == 1)102 if (avr->out_channels == 1)
100 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);
101 avr->in_convert_needed = (avr->resample_needed || avr->mixing_needed) &&104
102 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 */
103 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)
104 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;
105 else121 else
106 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;
107 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
108 /* allocate buffers */175 /* allocate buffers */
109 if (avr->mixing_needed || avr->in_convert_needed) {176 if (avr->in_copy_needed || avr->in_convert_needed) {
110 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),
111 0, avr->internal_sample_fmt,178 0, avr->internal_sample_fmt,
112 "in_buffer");179 "in_buffer");
@@ -143,7 +210,8 @@ int avresample_open(AVAudioResampleContext *avr) · 30 unmodified lines
143 if (avr->in_convert_needed) {210 if (avr->in_convert_needed) {
144 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,
145 avr->in_sample_fmt, avr->in_channels,212 avr->in_sample_fmt, avr->in_channels,
146 avr->in_sample_rate);213 avr->in_sample_rate,
214 avr->remap_point == REMAP_IN_CONVERT);
147 if (!avr->ac_in) {215 if (!avr->ac_in) {
148 ret = AVERROR(ENOMEM);216 ret = AVERROR(ENOMEM);
149 goto error;217 goto error;
@@ -157,7 +225,8 @@ int avresample_open(AVAudioResampleContext *avr) · 7 unmodified lines
157 src_fmt = avr->in_sample_fmt;225 src_fmt = avr->in_sample_fmt;
158 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,
159 avr->out_channels,227 avr->out_channels,
160 avr->out_sample_rate);228 avr->out_sample_rate,
229 avr->remap_point == REMAP_OUT_CONVERT);
161 if (!avr->ac_out) {230 if (!avr->ac_out) {
162 ret = AVERROR(ENOMEM);231 ret = AVERROR(ENOMEM);
163 goto error;232 goto error;
@@ -197,6 +266,8 @@ void avresample_close(AVAudioResampleContext *avr) · 33 unmodified lines
197 ff_audio_resample_free(&avr->resample);266 ff_audio_resample_free(&avr->resample);
198 ff_audio_mix_free(&avr->am);267 ff_audio_mix_free(&avr->am);
199 av_freep(&avr->mix_matrix);268 av_freep(&avr->mix_matrix);
269
270 avr->use_channel_map = 0;
200}271}
201 272
202void avresample_free(AVAudioResampleContext **avr)273void avresample_free(AVAudioResampleContext **avr)
@@ -239,7 +310,9 @@ static int handle_buffered_output(AVAudioResampleContext *avr, · 36 unmodified lines
239 data in the output FIFO */310 data in the output FIFO */
240 av_dlog(avr, "[copy] %s to output\n", converted->name);311 av_dlog(avr, "[copy] %s to output\n", converted->name);
241 output->nb_samples = 0;312 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);
243 if (ret < 0)316 if (ret < 0)
244 return ret;317 return ret;
245 av_dlog(avr, "[end conversion]\n");318 av_dlog(avr, "[end conversion]\n");
@@ -303,11 +376,24 @@ int attribute_align_arg avresample_convert(AVAudioResampleContext *avr, · 57 unmodified lines
303 /* in some rare cases we can copy input to output and upmix376 /* in some rare cases we can copy input to output and upmix
304 directly in the output buffer */377 directly in the output buffer */
305 av_dlog(avr, "[copy] %s to output\n", current_buffer->name);378 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);
307 if (ret < 0)382 if (ret < 0)
308 return ret;383 return ret;
309 current_buffer = &output_buffer;384 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) {
311 /* if needed, copy or convert input to in_buffer, and downmix if397 /* if needed, copy or convert input to in_buffer, and downmix if
312 applicable */398 applicable */
313 if (avr->in_convert_needed) {399 if (avr->in_convert_needed) {
@@ -322,7 +408,9 @@ int attribute_align_arg avresample_convert(AVAudioResampleContext *avr, · 8 unmodified lines
322 return ret;408 return ret;
323 } else {409 } else {
324 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);
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);
326 if (ret < 0)414 if (ret < 0)
327 return ret;415 return ret;
328 }416 }
@@ -467,6 +555,57 @@ int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix, · 138 unmodified lines
467 return 0;555 return 0;
468}556}
469 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
470int avresample_available(AVAudioResampleContext *avr)609int avresample_available(AVAudioResampleContext *avr)
471{610{
472 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