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

Merged-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
Michael Niedermayer 2013-01-08 12:56:41 +01:00
commit 249fca3df9
15 changed files with 328 additions and 41 deletions

View File

@ -132,6 +132,10 @@ API changes, most recent first:
2012-03-26 - a67d9cf - lavfi 2.66.100
Add avfilter_fill_frame_from_{audio_,}buffer_ref() functions.
2013-xx-xx - xxxxxxx - lavr 1.1.0
Add avresample_set_channel_mapping() for input channel reordering,
duplication, and silencing.
2012-xx-xx - xxxxxxx - lavu 52.2.1 - avstring.h
Add av_basename() and av_dirname().

View File

@ -228,6 +228,13 @@ For Emacs, add these roughly equivalent lines to your @file{.emacs.d/init.el}:
You can commit unfinished stuff (for testing etc), but it must be disabled
(#ifdef etc) by default so it does not interfere with other developers'
work.
@item
The commit message should have a short first line in the form of
a @samp{topic: short description} as a header, separated by a newline
from the body consisting of an explanation of why the change is necessary.
If the commit fixes a known bug on the bug tracker, the commit message
should include its bug ID. Referring to the issue on the bug tracker does
not exempt you from writing an excerpt of the bug in the commit message.
@item
You do not have to over-test things. If it works for you, and you think it
should work for others, then commit. If your code has problems

View File

@ -30,7 +30,6 @@
#include "audio_convert.h"
#include "audio_data.h"
#include "dither.h"
#include "internal.h"
enum ConvFuncType {
CONV_FUNC_TYPE_FLAT,
@ -51,6 +50,7 @@ struct AudioConvert {
DitherContext *dc;
enum AVSampleFormat in_fmt;
enum AVSampleFormat out_fmt;
int apply_map;
int channels;
int planes;
int ptr_align;
@ -260,7 +260,8 @@ void ff_audio_convert_free(AudioConvert **ac)
AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
enum AVSampleFormat out_fmt,
enum AVSampleFormat in_fmt,
int channels, int sample_rate)
int channels, int sample_rate,
int apply_map)
{
AudioConvert *ac;
int in_planar, out_planar;
@ -273,11 +274,13 @@ AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
ac->out_fmt = out_fmt;
ac->in_fmt = in_fmt;
ac->channels = channels;
ac->apply_map = apply_map;
if (avr->dither_method != AV_RESAMPLE_DITHER_NONE &&
av_get_packed_sample_fmt(out_fmt) == AV_SAMPLE_FMT_S16 &&
av_get_bytes_per_sample(in_fmt) > 2) {
ac->dc = ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate);
ac->dc = ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate,
apply_map);
if (!ac->dc) {
av_free(ac);
return NULL;
@ -310,6 +313,7 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in)
{
int use_generic = 1;
int len = in->nb_samples;
int p;
if (ac->dc) {
/* dithered conversion */
@ -336,9 +340,46 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in)
av_get_sample_fmt_name(ac->out_fmt),
use_generic ? ac->func_descr_generic : ac->func_descr);
if (ac->apply_map) {
ChannelMapInfo *map = &ac->avr->ch_map_info;
if (!av_sample_fmt_is_planar(ac->out_fmt)) {
av_log(ac->avr, AV_LOG_ERROR, "cannot remap packed format during conversion\n");
return AVERROR(EINVAL);
}
if (map->do_remap) {
if (av_sample_fmt_is_planar(ac->in_fmt)) {
conv_func_flat *convert = use_generic ? ac->conv_flat_generic :
ac->conv_flat;
for (p = 0; p < ac->planes; p++)
if (map->channel_map[p] >= 0)
convert(out->data[p], in->data[map->channel_map[p]], len);
} else {
uint8_t *data[AVRESAMPLE_MAX_CHANNELS];
conv_func_deinterleave *convert = use_generic ?
ac->conv_deinterleave_generic :
ac->conv_deinterleave;
for (p = 0; p < ac->channels; p++)
data[map->input_map[p]] = out->data[p];
convert(data, in->data[0], len, ac->channels);
}
}
if (map->do_copy || map->do_zero) {
for (p = 0; p < ac->planes; p++) {
if (map->channel_copy[p])
memcpy(out->data[p], out->data[map->channel_copy[p]],
len * out->stride);
else if (map->channel_zero[p])
av_samples_set_silence(&out->data[p], 0, len, 1, ac->out_fmt);
}
}
} else {
switch (ac->func_type) {
case CONV_FUNC_TYPE_FLAT: {
int p;
if (!in->is_planar)
len *= in->channels;
if (use_generic) {
@ -363,6 +404,7 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in)
ac->conv_deinterleave(out->data, in->data[0], len, ac->channels);
break;
}
}
out->nb_samples = in->nb_samples;
return 0;

View File

@ -23,10 +23,9 @@
#include "libavutil/samplefmt.h"
#include "avresample.h"
#include "internal.h"
#include "audio_data.h"
typedef struct AudioConvert AudioConvert;
/**
* Set conversion function if the parameters match.
*
@ -59,12 +58,14 @@ void ff_audio_convert_set_func(AudioConvert *ac, enum AVSampleFormat out_fmt,
* @param in_fmt input sample format
* @param channels number of channels
* @param sample_rate sample rate (used for dithering)
* @param apply_map apply channel map during conversion
* @return newly-allocated AudioConvert context
*/
AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
enum AVSampleFormat out_fmt,
enum AVSampleFormat in_fmt,
int channels, int sample_rate);
int channels, int sample_rate,
int apply_map);
/**
* Free AudioConvert.

View File

@ -213,7 +213,7 @@ void ff_audio_data_free(AudioData **a)
av_freep(a);
}
int ff_audio_data_copy(AudioData *dst, AudioData *src)
int ff_audio_data_copy(AudioData *dst, AudioData *src, ChannelMapInfo *map)
{
int ret, p;
@ -221,6 +221,11 @@ int ff_audio_data_copy(AudioData *dst, AudioData *src)
if (dst->sample_fmt != src->sample_fmt || dst->channels < src->channels)
return AVERROR(EINVAL);
if (map && !src->is_planar) {
av_log(src, AV_LOG_ERROR, "cannot remap packed format during copy\n");
return AVERROR(EINVAL);
}
/* if the input is empty, just empty the output */
if (!src->nb_samples) {
dst->nb_samples = 0;
@ -233,8 +238,29 @@ int ff_audio_data_copy(AudioData *dst, AudioData *src)
return ret;
/* copy data */
for (p = 0; p < src->planes; p++)
memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride);
if (map) {
if (map->do_remap) {
for (p = 0; p < src->planes; p++) {
if (map->channel_map[p] >= 0)
memcpy(dst->data[p], src->data[map->channel_map[p]],
src->nb_samples * src->stride);
}
}
if (map->do_copy || map->do_zero) {
for (p = 0; p < src->planes; p++) {
if (map->channel_copy[p])
memcpy(dst->data[p], dst->data[map->channel_copy[p]],
src->nb_samples * src->stride);
else if (map->channel_zero[p])
av_samples_set_silence(&dst->data[p], 0, src->nb_samples,
1, dst->sample_fmt);
}
}
} else {
for (p = 0; p < src->planes; p++)
memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride);
}
dst->nb_samples = src->nb_samples;
return 0;

View File

@ -27,11 +27,12 @@
#include "libavutil/log.h"
#include "libavutil/samplefmt.h"
#include "avresample.h"
#include "internal.h"
/**
* Audio buffer used for intermediate storage between conversion phases.
*/
typedef struct AudioData {
struct AudioData {
const AVClass *class; /**< AVClass for logging */
uint8_t *data[AVRESAMPLE_MAX_CHANNELS]; /**< data plane pointers */
uint8_t *buffer; /**< data buffer */
@ -50,7 +51,7 @@ typedef struct AudioData {
int ptr_align; /**< minimum data pointer alignment */
int samples_align; /**< allocated samples alignment */
const char *name; /**< name for debug logging */
} AudioData;
};
int ff_audio_data_set_channels(AudioData *a, int channels);
@ -117,9 +118,10 @@ void ff_audio_data_free(AudioData **a);
*
* @param out output AudioData
* @param in input AudioData
* @param map channel map, NULL if not remapping
* @return 0 on success, negative AVERROR value on error
*/
int ff_audio_data_copy(AudioData *out, AudioData *in);
int ff_audio_data_copy(AudioData *out, AudioData *in, ChannelMapInfo *map);
/**
* Append data from one AudioData to the end of another.

View File

@ -25,13 +25,12 @@
#include "libavutil/samplefmt.h"
#include "avresample.h"
#include "internal.h"
#include "audio_data.h"
typedef void (mix_func)(uint8_t **src, void **matrix, int len, int out_ch,
int in_ch);
typedef struct AudioMix AudioMix;
/**
* Set mixing function if the parameters match.
*

View File

@ -258,6 +258,36 @@ int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix,
int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
int stride);
/**
* Set a customized input channel mapping.
*
* This function can only be called when the allocated context is not open.
* Also, the input channel layout must have already been set.
*
* Calling avresample_close() on the context will clear the channel mapping.
*
* The map for each input channel specifies the channel index in the source to
* use for that particular channel, or -1 to mute the channel. Source channels
* can be duplicated by using the same index for multiple input channels.
*
* Examples:
*
* Reordering 5.1 AAC order (C,L,R,Ls,Rs,LFE) to Libav order (L,R,C,LFE,Ls,Rs):
* { 1, 2, 0, 5, 3, 4 }
*
* Muting the 3rd channel in 4-channel input:
* { 0, 1, -1, 3 }
*
* Duplicating the left channel of stereo input:
* { 0, 0 }
*
* @param avr audio resample context
* @param channel_map customized input channel mapping
* @return 0 on success, negative AVERROR code on failure
*/
int avresample_set_channel_mapping(AVAudioResampleContext *avr,
const int *channel_map);
/**
* Set compensation for resampling.
*

View File

@ -53,6 +53,8 @@ typedef struct DitherState {
struct DitherContext {
DitherDSPContext ddsp;
enum AVResampleDitherMethod method;
int apply_map;
ChannelMapInfo *ch_map_info;
int mute_dither_threshold; // threshold for disabling dither
int mute_reset_threshold; // threshold for resetting noise shaping
@ -251,17 +253,23 @@ int ff_convert_dither(DitherContext *c, AudioData *dst, AudioData *src)
return ret;
}
if (src->sample_fmt != AV_SAMPLE_FMT_FLTP) {
if (src->sample_fmt != AV_SAMPLE_FMT_FLTP || c->apply_map) {
/* make sure flt_data is large enough for the input */
ret = ff_audio_data_realloc(c->flt_data, src->nb_samples);
if (ret < 0)
return ret;
flt_data = c->flt_data;
}
if (src->sample_fmt != AV_SAMPLE_FMT_FLTP) {
/* convert input samples to fltp and scale to s16 range */
ret = ff_audio_convert(c->ac_in, flt_data, src);
if (ret < 0)
return ret;
} else if (c->apply_map) {
ret = ff_audio_data_copy(flt_data, src, c->ch_map_info);
if (ret < 0)
return ret;
} else {
flt_data = src;
}
@ -333,7 +341,7 @@ static void dither_init(DitherDSPContext *ddsp,
DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,
enum AVSampleFormat out_fmt,
enum AVSampleFormat in_fmt,
int channels, int sample_rate)
int channels, int sample_rate, int apply_map)
{
AVLFG seed_gen;
DitherContext *c;
@ -350,6 +358,10 @@ DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,
if (!c)
return NULL;
c->apply_map = apply_map;
if (apply_map)
c->ch_map_info = &avr->ch_map_info;
if (avr->dither_method == AV_RESAMPLE_DITHER_TRIANGULAR_NS &&
sample_rate != 48000 && sample_rate != 44100) {
av_log(avr, AV_LOG_WARNING, "sample rate must be 48000 or 44100 Hz "
@ -379,19 +391,20 @@ DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,
goto fail;
c->ac_out = ff_audio_convert_alloc(avr, out_fmt, AV_SAMPLE_FMT_S16P,
channels, sample_rate);
channels, sample_rate, 0);
if (!c->ac_out)
goto fail;
}
if (in_fmt != AV_SAMPLE_FMT_FLTP) {
if (in_fmt != AV_SAMPLE_FMT_FLTP || c->apply_map) {
c->flt_data = ff_audio_data_alloc(channels, 1024, AV_SAMPLE_FMT_FLTP,
"dither flt buffer");
if (!c->flt_data)
goto fail;
}
if (in_fmt != AV_SAMPLE_FMT_FLTP) {
c->ac_in = ff_audio_convert_alloc(avr, AV_SAMPLE_FMT_FLTP, in_fmt,
channels, sample_rate);
channels, sample_rate, c->apply_map);
if (!c->ac_in)
goto fail;
}

View File

@ -66,7 +66,7 @@ typedef struct DitherDSPContext {
DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,
enum AVSampleFormat out_fmt,
enum AVSampleFormat in_fmt,
int channels, int sample_rate);
int channels, int sample_rate, int apply_map);
/**
* Free a DitherContext.

View File

@ -26,10 +26,29 @@
#include "libavutil/opt.h"
#include "libavutil/samplefmt.h"
#include "avresample.h"
#include "audio_convert.h"
#include "audio_data.h"
#include "audio_mix.h"
#include "resample.h"
typedef struct AudioData AudioData;
typedef struct AudioConvert AudioConvert;
typedef struct AudioMix AudioMix;
typedef struct ResampleContext ResampleContext;
enum RemapPoint {
REMAP_NONE,
REMAP_IN_COPY,
REMAP_IN_CONVERT,
REMAP_OUT_COPY,
REMAP_OUT_CONVERT,
};
typedef struct ChannelMapInfo {
int channel_map[AVRESAMPLE_MAX_CHANNELS]; /**< source index of each output channel, -1 if not remapped */
int do_remap; /**< remap needed */
int channel_copy[AVRESAMPLE_MAX_CHANNELS]; /**< dest index to copy from */
int do_copy; /**< copy needed */
int channel_zero[AVRESAMPLE_MAX_CHANNELS]; /**< dest index to zero */
int do_zero; /**< zeroing needed */
int input_map[AVRESAMPLE_MAX_CHANNELS]; /**< dest index of each input channel */
} ChannelMapInfo;
struct AVAudioResampleContext {
const AVClass *av_class; /**< AVClass for logging and AVOptions */
@ -64,6 +83,7 @@ struct AVAudioResampleContext {
int resample_needed; /**< resampling is needed */
int in_convert_needed; /**< input sample format conversion is needed */
int out_convert_needed; /**< output sample format conversion is needed */
int in_copy_needed; /**< input data copy is needed */
AudioData *in_buffer; /**< buffer for converted input */
AudioData *resample_out_buffer; /**< buffer for output from resampler */
@ -81,6 +101,10 @@ struct AVAudioResampleContext {
* only used if avresample_set_matrix() is called before avresample_open()
*/
double *mix_matrix;
int use_channel_map;
enum RemapPoint remap_point;
ChannelMapInfo ch_map_info;
};
#endif /* AVRESAMPLE_INTERNAL_H */

View File

@ -23,6 +23,7 @@
#include "libavutil/libm.h"
#include "libavutil/log.h"
#include "internal.h"
#include "resample.h"
#include "audio_data.h"
struct ResampleContext {

View File

@ -22,10 +22,9 @@
#define AVRESAMPLE_RESAMPLE_H
#include "avresample.h"
#include "internal.h"
#include "audio_data.h"
typedef struct ResampleContext ResampleContext;
/**
* Allocate and initialize a ResampleContext.
*

View File

@ -26,8 +26,11 @@
#include "libavutil/opt.h"
#include "avresample.h"
#include "audio_data.h"
#include "internal.h"
#include "audio_data.h"
#include "audio_convert.h"
#include "audio_mix.h"
#include "resample.h"
int avresample_open(AVAudioResampleContext *avr)
{
@ -93,20 +96,84 @@ int avresample_open(AVAudioResampleContext *avr)
av_get_sample_fmt_name(avr->internal_sample_fmt));
}
/* set sample format conversion parameters */
/* treat all mono as planar for easier comparison */
if (avr->in_channels == 1)
avr->in_sample_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt);
if (avr->out_channels == 1)
avr->out_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt);
avr->in_convert_needed = (avr->resample_needed || avr->mixing_needed) &&
avr->in_sample_fmt != avr->internal_sample_fmt;
/* we may need to add an extra conversion in order to remap channels if
the output format is not planar */
if (avr->use_channel_map && !avr->mixing_needed && !avr->resample_needed &&
!av_sample_fmt_is_planar(avr->out_sample_fmt)) {
avr->internal_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt);
}
/* set sample format conversion parameters */
if (avr->resample_needed || avr->mixing_needed)
avr->in_convert_needed = avr->in_sample_fmt != avr->internal_sample_fmt;
else
avr->in_convert_needed = avr->use_channel_map &&
!av_sample_fmt_is_planar(avr->out_sample_fmt);
if (avr->resample_needed || avr->mixing_needed || avr->in_convert_needed)
avr->out_convert_needed = avr->internal_sample_fmt != avr->out_sample_fmt;
else
avr->out_convert_needed = avr->in_sample_fmt != avr->out_sample_fmt;
avr->in_copy_needed = !avr->in_convert_needed && (avr->mixing_needed ||
(avr->use_channel_map && avr->resample_needed));
if (avr->use_channel_map) {
if (avr->in_copy_needed) {
avr->remap_point = REMAP_IN_COPY;
av_dlog(avr, "remap channels during in_copy\n");
} else if (avr->in_convert_needed) {
avr->remap_point = REMAP_IN_CONVERT;
av_dlog(avr, "remap channels during in_convert\n");
} else if (avr->out_convert_needed) {
avr->remap_point = REMAP_OUT_CONVERT;
av_dlog(avr, "remap channels during out_convert\n");
} else {
avr->remap_point = REMAP_OUT_COPY;
av_dlog(avr, "remap channels during out_copy\n");
}
#ifdef DEBUG
{
int ch;
av_dlog(avr, "output map: ");
if (avr->ch_map_info.do_remap)
for (ch = 0; ch < avr->in_channels; ch++)
av_dlog(avr, " % 2d", avr->ch_map_info.channel_map[ch]);
else
av_dlog(avr, "n/a");
av_dlog(avr, "\n");
av_dlog(avr, "copy map: ");
if (avr->ch_map_info.do_copy)
for (ch = 0; ch < avr->in_channels; ch++)
av_dlog(avr, " % 2d", avr->ch_map_info.channel_copy[ch]);
else
av_dlog(avr, "n/a");
av_dlog(avr, "\n");
av_dlog(avr, "zero map: ");
if (avr->ch_map_info.do_zero)
for (ch = 0; ch < avr->in_channels; ch++)
av_dlog(avr, " % 2d", avr->ch_map_info.channel_zero[ch]);
else
av_dlog(avr, "n/a");
av_dlog(avr, "\n");
av_dlog(avr, "input map: ");
for (ch = 0; ch < avr->in_channels; ch++)
av_dlog(avr, " % 2d", avr->ch_map_info.input_map[ch]);
av_dlog(avr, "\n");
}
#endif
} else
avr->remap_point = REMAP_NONE;
/* allocate buffers */
if (avr->mixing_needed || avr->in_convert_needed) {
if (avr->in_copy_needed || avr->in_convert_needed) {
avr->in_buffer = ff_audio_data_alloc(FFMAX(avr->in_channels, avr->out_channels),
0, avr->internal_sample_fmt,
"in_buffer");
@ -143,7 +210,8 @@ int avresample_open(AVAudioResampleContext *avr)
if (avr->in_convert_needed) {
avr->ac_in = ff_audio_convert_alloc(avr, avr->internal_sample_fmt,
avr->in_sample_fmt, avr->in_channels,
avr->in_sample_rate);
avr->in_sample_rate,
avr->remap_point == REMAP_IN_CONVERT);
if (!avr->ac_in) {
ret = AVERROR(ENOMEM);
goto error;
@ -157,7 +225,8 @@ int avresample_open(AVAudioResampleContext *avr)
src_fmt = avr->in_sample_fmt;
avr->ac_out = ff_audio_convert_alloc(avr, avr->out_sample_fmt, src_fmt,
avr->out_channels,
avr->out_sample_rate);
avr->out_sample_rate,
avr->remap_point == REMAP_OUT_CONVERT);
if (!avr->ac_out) {
ret = AVERROR(ENOMEM);
goto error;
@ -197,6 +266,8 @@ void avresample_close(AVAudioResampleContext *avr)
ff_audio_resample_free(&avr->resample);
ff_audio_mix_free(&avr->am);
av_freep(&avr->mix_matrix);
avr->use_channel_map = 0;
}
void avresample_free(AVAudioResampleContext **avr)
@ -239,7 +310,9 @@ static int handle_buffered_output(AVAudioResampleContext *avr,
data in the output FIFO */
av_dlog(avr, "[copy] %s to output\n", converted->name);
output->nb_samples = 0;
ret = ff_audio_data_copy(output, converted);
ret = ff_audio_data_copy(output, converted,
avr->remap_point == REMAP_OUT_COPY ?
&avr->ch_map_info : NULL);
if (ret < 0)
return ret;
av_dlog(avr, "[end conversion]\n");
@ -303,11 +376,24 @@ int attribute_align_arg avresample_convert(AVAudioResampleContext *avr,
/* in some rare cases we can copy input to output and upmix
directly in the output buffer */
av_dlog(avr, "[copy] %s to output\n", current_buffer->name);
ret = ff_audio_data_copy(&output_buffer, current_buffer);
ret = ff_audio_data_copy(&output_buffer, current_buffer,
avr->remap_point == REMAP_OUT_COPY ?
&avr->ch_map_info : NULL);
if (ret < 0)
return ret;
current_buffer = &output_buffer;
} else if (avr->mixing_needed || avr->in_convert_needed) {
} else if (avr->remap_point == REMAP_OUT_COPY &&
(!direct_output || out_samples < in_samples)) {
/* if remapping channels during output copy, we may need to
* use an intermediate buffer in order to remap before adding
* samples to the output fifo */
av_dlog(avr, "[copy] %s to out_buffer\n", current_buffer->name);
ret = ff_audio_data_copy(avr->out_buffer, current_buffer,
&avr->ch_map_info);
if (ret < 0)
return ret;
current_buffer = avr->out_buffer;
} else if (avr->in_copy_needed || avr->in_convert_needed) {
/* if needed, copy or convert input to in_buffer, and downmix if
applicable */
if (avr->in_convert_needed) {
@ -322,7 +408,9 @@ int attribute_align_arg avresample_convert(AVAudioResampleContext *avr,
return ret;
} else {
av_dlog(avr, "[copy] %s to in_buffer\n", current_buffer->name);
ret = ff_audio_data_copy(avr->in_buffer, current_buffer);
ret = ff_audio_data_copy(avr->in_buffer, current_buffer,
avr->remap_point == REMAP_IN_COPY ?
&avr->ch_map_info : NULL);
if (ret < 0)
return ret;
}
@ -467,6 +555,57 @@ int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
return 0;
}
int avresample_set_channel_mapping(AVAudioResampleContext *avr,
const int *channel_map)
{
ChannelMapInfo *info = &avr->ch_map_info;
int in_channels, ch, i;
in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout);
if (in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS) {
av_log(avr, AV_LOG_ERROR, "Invalid input channel layout\n");
return AVERROR(EINVAL);
}
memset(info, 0, sizeof(*info));
memset(info->input_map, -1, sizeof(info->input_map));
for (ch = 0; ch < in_channels; ch++) {
if (channel_map[ch] >= in_channels) {
av_log(avr, AV_LOG_ERROR, "Invalid channel map\n");
return AVERROR(EINVAL);
}
if (channel_map[ch] < 0) {
info->channel_zero[ch] = 1;
info->channel_map[ch] = -1;
info->do_zero = 1;
} else if (info->input_map[channel_map[ch]] >= 0) {
info->channel_copy[ch] = info->input_map[channel_map[ch]];
info->channel_map[ch] = -1;
info->do_copy = 1;
} else {
info->channel_map[ch] = channel_map[ch];
info->input_map[channel_map[ch]] = ch;
info->do_remap = 1;
}
}
/* Fill-in unmapped input channels with unmapped output channels.
This is used when remapping during conversion from interleaved to
planar format. */
for (ch = 0, i = 0; ch < in_channels && i < in_channels; ch++, i++) {
while (ch < in_channels && info->input_map[ch] >= 0)
ch++;
while (i < in_channels && info->channel_map[i] >= 0)
i++;
if (ch >= in_channels || i >= in_channels)
break;
info->input_map[ch] = i;
}
avr->use_channel_map = 1;
return 0;
}
int avresample_available(AVAudioResampleContext *avr)
{
return av_audio_fifo_size(avr->out_fifo);

View File

@ -20,8 +20,8 @@
#define AVRESAMPLE_VERSION_H
#define LIBAVRESAMPLE_VERSION_MAJOR 1
#define LIBAVRESAMPLE_VERSION_MINOR 0
#define LIBAVRESAMPLE_VERSION_MICRO 1
#define LIBAVRESAMPLE_VERSION_MINOR 1
#define LIBAVRESAMPLE_VERSION_MICRO 0
#define LIBAVRESAMPLE_VERSION_INT AV_VERSION_INT(LIBAVRESAMPLE_VERSION_MAJOR, \
LIBAVRESAMPLE_VERSION_MINOR, \