diff options
-rw-r--r-- | audio/filter/af_lavrresample.c | 13 | ||||
-rw-r--r-- | audio/reorder_ch.c | 53 | ||||
-rw-r--r-- | audio/reorder_ch.h | 3 | ||||
-rwxr-xr-x | configure | 18 |
4 files changed, 86 insertions, 1 deletions
diff --git a/audio/filter/af_lavrresample.c b/audio/filter/af_lavrresample.c index 4372100ea0..162f196477 100644 --- a/audio/filter/af_lavrresample.c +++ b/audio/filter/af_lavrresample.c @@ -34,6 +34,7 @@ #if defined(CONFIG_LIBAVRESAMPLE) #include <libavresample/avresample.h> +#define USE_SET_CHANNEL_MAPPING HAVE_AVRESAMPLE_SET_CHANNEL_MAPPING #elif defined(CONFIG_LIBSWRESAMPLE) #include <libswresample/swresample.h> #define AVAudioResampleContext SwrContext @@ -44,6 +45,7 @@ #define avresample_convert(ctx, out, out_planesize, out_samples, in, in_planesize, in_samples) \ swr_convert(ctx, out, out_samples, (const uint8_t**)(in), in_samples) #define avresample_set_channel_mapping swr_set_channel_mapping +#define USE_SET_CHANNEL_MAPPING 1 #else #error "config.h broken" #endif @@ -52,6 +54,7 @@ #include "core/subopt-helper.h" #include "audio/filter/af.h" #include "audio/fmt-conversion.h" +#include "audio/reorder_ch.h" struct af_resample_opts { int filter_size; @@ -217,11 +220,13 @@ static int control(struct af_instance *af, int cmd, void *arg) av_opt_set_int(s->avrctx_out, "in_sample_rate", s->ctx.out_rate, 0); av_opt_set_int(s->avrctx_out, "out_sample_rate", s->ctx.out_rate, 0); +#if USE_SET_CHANNEL_MAPPING // API has weird requirements, quoting avresample.h: // * This function can only be called when the allocated context is not open. // * Also, the input channel layout must have already been set. avresample_set_channel_mapping(s->avrctx, s->reorder_in); avresample_set_channel_mapping(s->avrctx_out, s->reorder_out); +#endif if (avresample_open(s->avrctx) < 0 || avresample_open(s->avrctx_out) < 0) @@ -322,12 +327,17 @@ static struct mp_audio *play(struct af_instance *af, struct mp_audio *data) s->ctx.out_rate, s->ctx.in_rate, AV_ROUND_UP); +#if USE_SET_CHANNEL_MAPPING + reorder_channels(data->audio, s->reorder_in, data->bps, data->nch, in_samples); +#endif + out_samples = avresample_convert(s->avrctx, (uint8_t **) &out->audio, out_size, out_samples, (uint8_t **) &in->audio, in_size, in_samples); *data = *out; +#if USE_SET_CHANNEL_MAPPING if (needs_reorder(s->reorder_out, out->nch)) { if (talloc_get_size(s->reorder_buffer) < out_size) s->reorder_buffer = talloc_realloc_size(s, s->reorder_buffer, out_size); @@ -336,6 +346,9 @@ static struct mp_audio *play(struct af_instance *af, struct mp_audio *data) (uint8_t **) &data->audio, out_size, out_samples, (uint8_t **) &out->audio, out_size, out_samples); } +#else + reorder_channels(data->audio, s->reorder_out, out->bps, out->nch, out_samples); +#endif data->len = out->bps * out_samples * out->nch; return data; diff --git a/audio/reorder_ch.c b/audio/reorder_ch.c index 3a2b747668..57cb664a6f 100644 --- a/audio/reorder_ch.c +++ b/audio/reorder_ch.c @@ -22,8 +22,10 @@ #include <inttypes.h> #include <string.h> +#include <assert.h> -#include "audio/reorder_ch.h" +#include "chmap.h" +#include "reorder_ch.h" static inline void reorder_to_planar_(void *restrict out, const void *restrict in, size_t size, size_t nchan, size_t nmemb) @@ -92,3 +94,52 @@ void reorder_to_packed(uint8_t *out, uint8_t **in, else reorder_to_packed_(out, in, size, nchan, nmemb); } + +#define MAX_SAMPLESIZE 8 + +static void reorder_channels_(uint8_t *restrict data, int *restrict ch_order, + size_t sample_size, size_t num_ch, + size_t num_frames) +{ + char buffer[MP_NUM_CHANNELS * MAX_SAMPLESIZE]; + for (size_t f = 0; f < num_frames; f++) { + for (uint8_t c = 0; c < num_ch; c++) { + memcpy(buffer + sample_size * c, data + sample_size * ch_order[c], + sample_size); + } + memcpy(data, buffer, sample_size * num_ch); + data += num_ch * sample_size; + } +} + +// Reorders for each channel: +// out[ch] = in[ch_order[ch]] (but in-place) +// num_ch is the number of channels +// sample_size is e.g. 2 for s16le +// full byte size of in/out = num_ch * sample_size * num_frames +// Do not use this function in new code; use libavresample instead. +void reorder_channels(void *restrict data, int *restrict ch_order, + size_t sample_size, size_t num_ch, size_t num_frames) +{ + // Check 1:1 mapping + bool need_reorder = false; + for (int n = 0; n < num_ch; n++) + need_reorder |= ch_order[n] != n; + if (!need_reorder) + return; + assert(sample_size <= MAX_SAMPLESIZE); + assert(num_ch <= MP_NUM_CHANNELS); + // See reorder_to_planar() why this is done this way + // s16 and float are the most common sample sizes, and 6 channels is the + // most common case where reordering is required. + if (sample_size == 2 && num_ch == 6) + reorder_channels_(data, ch_order, 2, 6, num_frames); + else if (sample_size == 2) + reorder_channels_(data, ch_order, 2, num_ch, num_frames); + else if (sample_size == 4 && num_ch == 6) + reorder_channels_(data, ch_order, 4, 6, num_frames); + else if (sample_size == 4) + reorder_channels_(data, ch_order, 4, num_ch, num_frames); + else + reorder_channels_(data, ch_order, sample_size, num_ch, num_frames); +} diff --git a/audio/reorder_ch.h b/audio/reorder_ch.h index c9c101e719..6b5902c1b6 100644 --- a/audio/reorder_ch.h +++ b/audio/reorder_ch.h @@ -30,4 +30,7 @@ void reorder_to_planar(void *restrict out, const void *restrict in, void reorder_to_packed(uint8_t *out, uint8_t **in, size_t size, size_t nchan, size_t nmemb); +void reorder_channels(void *restrict data, int *restrict ch_order, + size_t sample_size, size_t num_ch, size_t num_frames); + #endif /* MPLAYER_REORDER_CH_H */ @@ -2639,15 +2639,25 @@ echores "yes" _resampler=no +_avresample=no +_avresample_has_set_channel_mapping=no + echocheck "libavresample >= 1.0.0" if test "$_disable_avresample" = no ; then if pkg_config_add "libavresample >= 1.0.0" ; then _resampler=yes + _avresample=yes def_resampler='#define CONFIG_LIBAVRESAMPLE' fi fi echores "$_resampler" +if test "$_avresample" = yes ; then + echocheck "libavresample avresample_set_channel_mapping() API" + statement_check libavresample/avresample.h 'avresample_set_channel_mapping(NULL, NULL)' && _avresample_has_set_channel_mapping=yes + echores "$_avresample_has_set_channel_mapping" +fi + if test "$_resampler" = no ; then echocheck "libswresample >= 0.15.100" @@ -2658,10 +2668,17 @@ if test "$_resampler" = no ; then echores "$_resampler" fi + if test "$_resampler" = no ; then die "No resampler found. Install libavresample or libswresample (FFmpeg)." fi +if test "$_avresample_has_set_channel_mapping" = yes ; then + def_avresample_has_set_channel_mapping='#define HAVE_AVRESAMPLE_SET_CHANNEL_MAPPING 1' +else + def_avresample_has_set_channel_mapping='#define HAVE_AVRESAMPLE_SET_CHANNEL_MAPPING 0' +fi + echocheck "libavutil QP API" _avutil_has_qp_api=no @@ -3307,6 +3324,7 @@ $def_xv /* FFmpeg */ $def_encoding $def_resampler +$def_avresample_has_set_channel_mapping $def_fast_64bit $def_pthreads |