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:
		@@ -132,6 +132,10 @@ API changes, most recent first:
 | 
				
			|||||||
2012-03-26 - a67d9cf - lavfi 2.66.100
 | 
					2012-03-26 - a67d9cf - lavfi 2.66.100
 | 
				
			||||||
  Add avfilter_fill_frame_from_{audio_,}buffer_ref() functions.
 | 
					  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
 | 
					2012-xx-xx - xxxxxxx - lavu 52.2.1 - avstring.h
 | 
				
			||||||
  Add av_basename() and av_dirname().
 | 
					  Add av_basename() and av_dirname().
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
					   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'
 | 
					   (#ifdef etc) by default so it does not interfere with other developers'
 | 
				
			||||||
   work.
 | 
					   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
 | 
					@item
 | 
				
			||||||
   You do not have to over-test things. If it works for you, and you think it
 | 
					   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
 | 
					   should work for others, then commit. If your code has problems
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,7 +30,6 @@
 | 
				
			|||||||
#include "audio_convert.h"
 | 
					#include "audio_convert.h"
 | 
				
			||||||
#include "audio_data.h"
 | 
					#include "audio_data.h"
 | 
				
			||||||
#include "dither.h"
 | 
					#include "dither.h"
 | 
				
			||||||
#include "internal.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum ConvFuncType {
 | 
					enum ConvFuncType {
 | 
				
			||||||
    CONV_FUNC_TYPE_FLAT,
 | 
					    CONV_FUNC_TYPE_FLAT,
 | 
				
			||||||
@@ -51,6 +50,7 @@ struct AudioConvert {
 | 
				
			|||||||
    DitherContext *dc;
 | 
					    DitherContext *dc;
 | 
				
			||||||
    enum AVSampleFormat in_fmt;
 | 
					    enum AVSampleFormat in_fmt;
 | 
				
			||||||
    enum AVSampleFormat out_fmt;
 | 
					    enum AVSampleFormat out_fmt;
 | 
				
			||||||
 | 
					    int apply_map;
 | 
				
			||||||
    int channels;
 | 
					    int channels;
 | 
				
			||||||
    int planes;
 | 
					    int planes;
 | 
				
			||||||
    int ptr_align;
 | 
					    int ptr_align;
 | 
				
			||||||
@@ -260,7 +260,8 @@ void ff_audio_convert_free(AudioConvert **ac)
 | 
				
			|||||||
AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
 | 
					AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
 | 
				
			||||||
                                     enum AVSampleFormat out_fmt,
 | 
					                                     enum AVSampleFormat out_fmt,
 | 
				
			||||||
                                     enum AVSampleFormat in_fmt,
 | 
					                                     enum AVSampleFormat in_fmt,
 | 
				
			||||||
                                     int channels, int sample_rate)
 | 
					                                     int channels, int sample_rate,
 | 
				
			||||||
 | 
					                                     int apply_map)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    AudioConvert *ac;
 | 
					    AudioConvert *ac;
 | 
				
			||||||
    int in_planar, out_planar;
 | 
					    int in_planar, out_planar;
 | 
				
			||||||
@@ -273,11 +274,13 @@ AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
 | 
				
			|||||||
    ac->out_fmt  = out_fmt;
 | 
					    ac->out_fmt  = out_fmt;
 | 
				
			||||||
    ac->in_fmt   = in_fmt;
 | 
					    ac->in_fmt   = in_fmt;
 | 
				
			||||||
    ac->channels = channels;
 | 
					    ac->channels = channels;
 | 
				
			||||||
 | 
					    ac->apply_map = apply_map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (avr->dither_method != AV_RESAMPLE_DITHER_NONE          &&
 | 
					    if (avr->dither_method != AV_RESAMPLE_DITHER_NONE          &&
 | 
				
			||||||
        av_get_packed_sample_fmt(out_fmt) == AV_SAMPLE_FMT_S16 &&
 | 
					        av_get_packed_sample_fmt(out_fmt) == AV_SAMPLE_FMT_S16 &&
 | 
				
			||||||
        av_get_bytes_per_sample(in_fmt) > 2) {
 | 
					        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) {
 | 
					        if (!ac->dc) {
 | 
				
			||||||
            av_free(ac);
 | 
					            av_free(ac);
 | 
				
			||||||
            return NULL;
 | 
					            return NULL;
 | 
				
			||||||
@@ -310,6 +313,7 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    int use_generic = 1;
 | 
					    int use_generic = 1;
 | 
				
			||||||
    int len         = in->nb_samples;
 | 
					    int len         = in->nb_samples;
 | 
				
			||||||
 | 
					    int p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (ac->dc) {
 | 
					    if (ac->dc) {
 | 
				
			||||||
        /* dithered conversion */
 | 
					        /* dithered conversion */
 | 
				
			||||||
@@ -336,9 +340,46 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in)
 | 
				
			|||||||
            av_get_sample_fmt_name(ac->out_fmt),
 | 
					            av_get_sample_fmt_name(ac->out_fmt),
 | 
				
			||||||
            use_generic ? ac->func_descr_generic : ac->func_descr);
 | 
					            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) {
 | 
					    switch (ac->func_type) {
 | 
				
			||||||
    case CONV_FUNC_TYPE_FLAT: {
 | 
					    case CONV_FUNC_TYPE_FLAT: {
 | 
				
			||||||
        int p;
 | 
					 | 
				
			||||||
        if (!in->is_planar)
 | 
					        if (!in->is_planar)
 | 
				
			||||||
            len *= in->channels;
 | 
					            len *= in->channels;
 | 
				
			||||||
        if (use_generic) {
 | 
					        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);
 | 
					            ac->conv_deinterleave(out->data, in->data[0], len, ac->channels);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    out->nb_samples = in->nb_samples;
 | 
					    out->nb_samples = in->nb_samples;
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,10 +23,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "libavutil/samplefmt.h"
 | 
					#include "libavutil/samplefmt.h"
 | 
				
			||||||
#include "avresample.h"
 | 
					#include "avresample.h"
 | 
				
			||||||
 | 
					#include "internal.h"
 | 
				
			||||||
#include "audio_data.h"
 | 
					#include "audio_data.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct AudioConvert AudioConvert;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Set conversion function if the parameters match.
 | 
					 * 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 in_fmt      input sample format
 | 
				
			||||||
 * @param channels    number of channels
 | 
					 * @param channels    number of channels
 | 
				
			||||||
 * @param sample_rate sample rate (used for dithering)
 | 
					 * @param sample_rate sample rate (used for dithering)
 | 
				
			||||||
 | 
					 * @param apply_map   apply channel map during conversion
 | 
				
			||||||
 * @return            newly-allocated AudioConvert context
 | 
					 * @return            newly-allocated AudioConvert context
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
 | 
					AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
 | 
				
			||||||
                                     enum AVSampleFormat out_fmt,
 | 
					                                     enum AVSampleFormat out_fmt,
 | 
				
			||||||
                                     enum AVSampleFormat in_fmt,
 | 
					                                     enum AVSampleFormat in_fmt,
 | 
				
			||||||
                                     int channels, int sample_rate);
 | 
					                                     int channels, int sample_rate,
 | 
				
			||||||
 | 
					                                     int apply_map);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Free AudioConvert.
 | 
					 * Free AudioConvert.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -213,7 +213,7 @@ void ff_audio_data_free(AudioData **a)
 | 
				
			|||||||
    av_freep(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;
 | 
					    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)
 | 
					    if (dst->sample_fmt != src->sample_fmt || dst->channels < src->channels)
 | 
				
			||||||
        return AVERROR(EINVAL);
 | 
					        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 the input is empty, just empty the output */
 | 
				
			||||||
    if (!src->nb_samples) {
 | 
					    if (!src->nb_samples) {
 | 
				
			||||||
        dst->nb_samples = 0;
 | 
					        dst->nb_samples = 0;
 | 
				
			||||||
@@ -233,8 +238,29 @@ int ff_audio_data_copy(AudioData *dst, AudioData *src)
 | 
				
			|||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* copy data */
 | 
					    /* copy data */
 | 
				
			||||||
    for (p = 0; p < src->planes; p++)
 | 
					    if (map) {
 | 
				
			||||||
        memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride);
 | 
					        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;
 | 
					    dst->nb_samples = src->nb_samples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,11 +27,12 @@
 | 
				
			|||||||
#include "libavutil/log.h"
 | 
					#include "libavutil/log.h"
 | 
				
			||||||
#include "libavutil/samplefmt.h"
 | 
					#include "libavutil/samplefmt.h"
 | 
				
			||||||
#include "avresample.h"
 | 
					#include "avresample.h"
 | 
				
			||||||
 | 
					#include "internal.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Audio buffer used for intermediate storage between conversion phases.
 | 
					 * Audio buffer used for intermediate storage between conversion phases.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
typedef struct AudioData {
 | 
					struct AudioData {
 | 
				
			||||||
    const AVClass *class;               /**< AVClass for logging            */
 | 
					    const AVClass *class;               /**< AVClass for logging            */
 | 
				
			||||||
    uint8_t *data[AVRESAMPLE_MAX_CHANNELS]; /**< data plane pointers        */
 | 
					    uint8_t *data[AVRESAMPLE_MAX_CHANNELS]; /**< data plane pointers        */
 | 
				
			||||||
    uint8_t *buffer;                    /**< data buffer                    */
 | 
					    uint8_t *buffer;                    /**< data buffer                    */
 | 
				
			||||||
@@ -50,7 +51,7 @@ typedef struct AudioData {
 | 
				
			|||||||
    int ptr_align;                      /**< minimum data pointer alignment */
 | 
					    int ptr_align;                      /**< minimum data pointer alignment */
 | 
				
			||||||
    int samples_align;                  /**< allocated samples alignment    */
 | 
					    int samples_align;                  /**< allocated samples alignment    */
 | 
				
			||||||
    const char *name;                   /**< name for debug logging         */
 | 
					    const char *name;                   /**< name for debug logging         */
 | 
				
			||||||
} AudioData;
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int ff_audio_data_set_channels(AudioData *a, int channels);
 | 
					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 out  output AudioData
 | 
				
			||||||
 * @param in   input AudioData
 | 
					 * @param in   input AudioData
 | 
				
			||||||
 | 
					 * @param map  channel map, NULL if not remapping
 | 
				
			||||||
 * @return     0 on success, negative AVERROR value on error
 | 
					 * @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.
 | 
					 * Append data from one AudioData to the end of another.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,13 +25,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "libavutil/samplefmt.h"
 | 
					#include "libavutil/samplefmt.h"
 | 
				
			||||||
#include "avresample.h"
 | 
					#include "avresample.h"
 | 
				
			||||||
 | 
					#include "internal.h"
 | 
				
			||||||
#include "audio_data.h"
 | 
					#include "audio_data.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef void (mix_func)(uint8_t **src, void **matrix, int len, int out_ch,
 | 
					typedef void (mix_func)(uint8_t **src, void **matrix, int len, int out_ch,
 | 
				
			||||||
                        int in_ch);
 | 
					                        int in_ch);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct AudioMix AudioMix;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Set mixing function if the parameters match.
 | 
					 * Set mixing function if the parameters match.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -258,6 +258,36 @@ int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix,
 | 
				
			|||||||
int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
 | 
					int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
 | 
				
			||||||
                          int stride);
 | 
					                          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.
 | 
					 * Set compensation for resampling.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,6 +53,8 @@ typedef struct DitherState {
 | 
				
			|||||||
struct DitherContext {
 | 
					struct DitherContext {
 | 
				
			||||||
    DitherDSPContext  ddsp;
 | 
					    DitherDSPContext  ddsp;
 | 
				
			||||||
    enum AVResampleDitherMethod method;
 | 
					    enum AVResampleDitherMethod method;
 | 
				
			||||||
 | 
					    int apply_map;
 | 
				
			||||||
 | 
					    ChannelMapInfo *ch_map_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int mute_dither_threshold;  // threshold for disabling dither
 | 
					    int mute_dither_threshold;  // threshold for disabling dither
 | 
				
			||||||
    int mute_reset_threshold;   // threshold for resetting noise shaping
 | 
					    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;
 | 
					            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 */
 | 
					        /* make sure flt_data is large enough for the input */
 | 
				
			||||||
        ret = ff_audio_data_realloc(c->flt_data, src->nb_samples);
 | 
					        ret = ff_audio_data_realloc(c->flt_data, src->nb_samples);
 | 
				
			||||||
        if (ret < 0)
 | 
					        if (ret < 0)
 | 
				
			||||||
            return ret;
 | 
					            return ret;
 | 
				
			||||||
        flt_data = c->flt_data;
 | 
					        flt_data = c->flt_data;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (src->sample_fmt != AV_SAMPLE_FMT_FLTP) {
 | 
				
			||||||
        /* convert input samples to fltp and scale to s16 range */
 | 
					        /* convert input samples to fltp and scale to s16 range */
 | 
				
			||||||
        ret = ff_audio_convert(c->ac_in, flt_data, src);
 | 
					        ret = ff_audio_convert(c->ac_in, flt_data, src);
 | 
				
			||||||
        if (ret < 0)
 | 
					        if (ret < 0)
 | 
				
			||||||
            return ret;
 | 
					            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 {
 | 
					    } else {
 | 
				
			||||||
        flt_data = src;
 | 
					        flt_data = src;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -333,7 +341,7 @@ static void dither_init(DitherDSPContext *ddsp,
 | 
				
			|||||||
DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,
 | 
					DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,
 | 
				
			||||||
                               enum AVSampleFormat out_fmt,
 | 
					                               enum AVSampleFormat out_fmt,
 | 
				
			||||||
                               enum AVSampleFormat in_fmt,
 | 
					                               enum AVSampleFormat in_fmt,
 | 
				
			||||||
                               int channels, int sample_rate)
 | 
					                               int channels, int sample_rate, int apply_map)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    AVLFG seed_gen;
 | 
					    AVLFG seed_gen;
 | 
				
			||||||
    DitherContext *c;
 | 
					    DitherContext *c;
 | 
				
			||||||
@@ -350,6 +358,10 @@ DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,
 | 
				
			|||||||
    if (!c)
 | 
					    if (!c)
 | 
				
			||||||
        return NULL;
 | 
					        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 &&
 | 
					    if (avr->dither_method == AV_RESAMPLE_DITHER_TRIANGULAR_NS &&
 | 
				
			||||||
        sample_rate != 48000 && sample_rate != 44100) {
 | 
					        sample_rate != 48000 && sample_rate != 44100) {
 | 
				
			||||||
        av_log(avr, AV_LOG_WARNING, "sample rate must be 48000 or 44100 Hz "
 | 
					        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;
 | 
					            goto fail;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        c->ac_out = ff_audio_convert_alloc(avr, out_fmt, AV_SAMPLE_FMT_S16P,
 | 
					        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)
 | 
					        if (!c->ac_out)
 | 
				
			||||||
            goto fail;
 | 
					            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,
 | 
					        c->flt_data = ff_audio_data_alloc(channels, 1024, AV_SAMPLE_FMT_FLTP,
 | 
				
			||||||
                                          "dither flt buffer");
 | 
					                                          "dither flt buffer");
 | 
				
			||||||
        if (!c->flt_data)
 | 
					        if (!c->flt_data)
 | 
				
			||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (in_fmt != AV_SAMPLE_FMT_FLTP) {
 | 
				
			||||||
        c->ac_in = ff_audio_convert_alloc(avr, AV_SAMPLE_FMT_FLTP, in_fmt,
 | 
					        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)
 | 
					        if (!c->ac_in)
 | 
				
			||||||
            goto fail;
 | 
					            goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66,7 +66,7 @@ typedef struct DitherDSPContext {
 | 
				
			|||||||
DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,
 | 
					DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,
 | 
				
			||||||
                               enum AVSampleFormat out_fmt,
 | 
					                               enum AVSampleFormat out_fmt,
 | 
				
			||||||
                               enum AVSampleFormat in_fmt,
 | 
					                               enum AVSampleFormat in_fmt,
 | 
				
			||||||
                               int channels, int sample_rate);
 | 
					                               int channels, int sample_rate, int apply_map);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Free a DitherContext.
 | 
					 * Free a DitherContext.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,10 +26,29 @@
 | 
				
			|||||||
#include "libavutil/opt.h"
 | 
					#include "libavutil/opt.h"
 | 
				
			||||||
#include "libavutil/samplefmt.h"
 | 
					#include "libavutil/samplefmt.h"
 | 
				
			||||||
#include "avresample.h"
 | 
					#include "avresample.h"
 | 
				
			||||||
#include "audio_convert.h"
 | 
					
 | 
				
			||||||
#include "audio_data.h"
 | 
					typedef struct AudioData AudioData;
 | 
				
			||||||
#include "audio_mix.h"
 | 
					typedef struct AudioConvert AudioConvert;
 | 
				
			||||||
#include "resample.h"
 | 
					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 {
 | 
					struct AVAudioResampleContext {
 | 
				
			||||||
    const AVClass *av_class;        /**< AVClass for logging and AVOptions  */
 | 
					    const AVClass *av_class;        /**< AVClass for logging and AVOptions  */
 | 
				
			||||||
@@ -64,6 +83,7 @@ struct AVAudioResampleContext {
 | 
				
			|||||||
    int resample_needed;    /**< resampling is needed                       */
 | 
					    int resample_needed;    /**< resampling is needed                       */
 | 
				
			||||||
    int in_convert_needed;  /**< input sample format conversion is needed   */
 | 
					    int in_convert_needed;  /**< input sample format conversion is needed   */
 | 
				
			||||||
    int out_convert_needed; /**< output 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 *in_buffer;           /**< buffer for converted input         */
 | 
				
			||||||
    AudioData *resample_out_buffer; /**< buffer for output from resampler   */
 | 
					    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()
 | 
					     * only used if avresample_set_matrix() is called before avresample_open()
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    double *mix_matrix;
 | 
					    double *mix_matrix;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int use_channel_map;
 | 
				
			||||||
 | 
					    enum RemapPoint remap_point;
 | 
				
			||||||
 | 
					    ChannelMapInfo ch_map_info;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* AVRESAMPLE_INTERNAL_H */
 | 
					#endif /* AVRESAMPLE_INTERNAL_H */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@
 | 
				
			|||||||
#include "libavutil/libm.h"
 | 
					#include "libavutil/libm.h"
 | 
				
			||||||
#include "libavutil/log.h"
 | 
					#include "libavutil/log.h"
 | 
				
			||||||
#include "internal.h"
 | 
					#include "internal.h"
 | 
				
			||||||
 | 
					#include "resample.h"
 | 
				
			||||||
#include "audio_data.h"
 | 
					#include "audio_data.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ResampleContext {
 | 
					struct ResampleContext {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,10 +22,9 @@
 | 
				
			|||||||
#define AVRESAMPLE_RESAMPLE_H
 | 
					#define AVRESAMPLE_RESAMPLE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "avresample.h"
 | 
					#include "avresample.h"
 | 
				
			||||||
 | 
					#include "internal.h"
 | 
				
			||||||
#include "audio_data.h"
 | 
					#include "audio_data.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct ResampleContext ResampleContext;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Allocate and initialize a ResampleContext.
 | 
					 * Allocate and initialize a ResampleContext.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,8 +26,11 @@
 | 
				
			|||||||
#include "libavutil/opt.h"
 | 
					#include "libavutil/opt.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "avresample.h"
 | 
					#include "avresample.h"
 | 
				
			||||||
#include "audio_data.h"
 | 
					 | 
				
			||||||
#include "internal.h"
 | 
					#include "internal.h"
 | 
				
			||||||
 | 
					#include "audio_data.h"
 | 
				
			||||||
 | 
					#include "audio_convert.h"
 | 
				
			||||||
 | 
					#include "audio_mix.h"
 | 
				
			||||||
 | 
					#include "resample.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int avresample_open(AVAudioResampleContext *avr)
 | 
					int avresample_open(AVAudioResampleContext *avr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -93,20 +96,84 @@ int avresample_open(AVAudioResampleContext *avr)
 | 
				
			|||||||
               av_get_sample_fmt_name(avr->internal_sample_fmt));
 | 
					               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)
 | 
					    if (avr->in_channels == 1)
 | 
				
			||||||
        avr->in_sample_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt);
 | 
					        avr->in_sample_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt);
 | 
				
			||||||
    if (avr->out_channels == 1)
 | 
					    if (avr->out_channels == 1)
 | 
				
			||||||
        avr->out_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt);
 | 
					        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)
 | 
					    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;
 | 
					        avr->out_convert_needed = avr->internal_sample_fmt != avr->out_sample_fmt;
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
        avr->out_convert_needed = avr->in_sample_fmt != avr->out_sample_fmt;
 | 
					        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 */
 | 
					    /* 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),
 | 
					        avr->in_buffer = ff_audio_data_alloc(FFMAX(avr->in_channels, avr->out_channels),
 | 
				
			||||||
                                             0, avr->internal_sample_fmt,
 | 
					                                             0, avr->internal_sample_fmt,
 | 
				
			||||||
                                             "in_buffer");
 | 
					                                             "in_buffer");
 | 
				
			||||||
@@ -143,7 +210,8 @@ int avresample_open(AVAudioResampleContext *avr)
 | 
				
			|||||||
    if (avr->in_convert_needed) {
 | 
					    if (avr->in_convert_needed) {
 | 
				
			||||||
        avr->ac_in = ff_audio_convert_alloc(avr, avr->internal_sample_fmt,
 | 
					        avr->ac_in = ff_audio_convert_alloc(avr, avr->internal_sample_fmt,
 | 
				
			||||||
                                            avr->in_sample_fmt, avr->in_channels,
 | 
					                                            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) {
 | 
					        if (!avr->ac_in) {
 | 
				
			||||||
            ret = AVERROR(ENOMEM);
 | 
					            ret = AVERROR(ENOMEM);
 | 
				
			||||||
            goto error;
 | 
					            goto error;
 | 
				
			||||||
@@ -157,7 +225,8 @@ int avresample_open(AVAudioResampleContext *avr)
 | 
				
			|||||||
            src_fmt = avr->in_sample_fmt;
 | 
					            src_fmt = avr->in_sample_fmt;
 | 
				
			||||||
        avr->ac_out = ff_audio_convert_alloc(avr, avr->out_sample_fmt, src_fmt,
 | 
					        avr->ac_out = ff_audio_convert_alloc(avr, avr->out_sample_fmt, src_fmt,
 | 
				
			||||||
                                             avr->out_channels,
 | 
					                                             avr->out_channels,
 | 
				
			||||||
                                             avr->out_sample_rate);
 | 
					                                             avr->out_sample_rate,
 | 
				
			||||||
 | 
					                                             avr->remap_point == REMAP_OUT_CONVERT);
 | 
				
			||||||
        if (!avr->ac_out) {
 | 
					        if (!avr->ac_out) {
 | 
				
			||||||
            ret = AVERROR(ENOMEM);
 | 
					            ret = AVERROR(ENOMEM);
 | 
				
			||||||
            goto error;
 | 
					            goto error;
 | 
				
			||||||
@@ -197,6 +266,8 @@ void avresample_close(AVAudioResampleContext *avr)
 | 
				
			|||||||
    ff_audio_resample_free(&avr->resample);
 | 
					    ff_audio_resample_free(&avr->resample);
 | 
				
			||||||
    ff_audio_mix_free(&avr->am);
 | 
					    ff_audio_mix_free(&avr->am);
 | 
				
			||||||
    av_freep(&avr->mix_matrix);
 | 
					    av_freep(&avr->mix_matrix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    avr->use_channel_map = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void avresample_free(AVAudioResampleContext **avr)
 | 
					void avresample_free(AVAudioResampleContext **avr)
 | 
				
			||||||
@@ -239,7 +310,9 @@ static int handle_buffered_output(AVAudioResampleContext *avr,
 | 
				
			|||||||
           data in the output FIFO */
 | 
					           data in the output FIFO */
 | 
				
			||||||
        av_dlog(avr, "[copy] %s to output\n", converted->name);
 | 
					        av_dlog(avr, "[copy] %s to output\n", converted->name);
 | 
				
			||||||
        output->nb_samples = 0;
 | 
					        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)
 | 
					        if (ret < 0)
 | 
				
			||||||
            return ret;
 | 
					            return ret;
 | 
				
			||||||
        av_dlog(avr, "[end conversion]\n");
 | 
					        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
 | 
					            /* in some rare cases we can copy input to output and upmix
 | 
				
			||||||
               directly in the output buffer */
 | 
					               directly in the output buffer */
 | 
				
			||||||
            av_dlog(avr, "[copy] %s to output\n", current_buffer->name);
 | 
					            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)
 | 
					            if (ret < 0)
 | 
				
			||||||
                return ret;
 | 
					                return ret;
 | 
				
			||||||
            current_buffer = &output_buffer;
 | 
					            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
 | 
					            /* if needed, copy or convert input to in_buffer, and downmix if
 | 
				
			||||||
               applicable */
 | 
					               applicable */
 | 
				
			||||||
            if (avr->in_convert_needed) {
 | 
					            if (avr->in_convert_needed) {
 | 
				
			||||||
@@ -322,7 +408,9 @@ int attribute_align_arg avresample_convert(AVAudioResampleContext *avr,
 | 
				
			|||||||
                    return ret;
 | 
					                    return ret;
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                av_dlog(avr, "[copy] %s to in_buffer\n", current_buffer->name);
 | 
					                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)
 | 
					                if (ret < 0)
 | 
				
			||||||
                    return ret;
 | 
					                    return ret;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -467,6 +555,57 @@ int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
 | 
				
			|||||||
    return 0;
 | 
					    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)
 | 
					int avresample_available(AVAudioResampleContext *avr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return av_audio_fifo_size(avr->out_fifo);
 | 
					    return av_audio_fifo_size(avr->out_fifo);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,8 +20,8 @@
 | 
				
			|||||||
#define AVRESAMPLE_VERSION_H
 | 
					#define AVRESAMPLE_VERSION_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LIBAVRESAMPLE_VERSION_MAJOR  1
 | 
					#define LIBAVRESAMPLE_VERSION_MAJOR  1
 | 
				
			||||||
#define LIBAVRESAMPLE_VERSION_MINOR  0
 | 
					#define LIBAVRESAMPLE_VERSION_MINOR  1
 | 
				
			||||||
#define LIBAVRESAMPLE_VERSION_MICRO  1
 | 
					#define LIBAVRESAMPLE_VERSION_MICRO  0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LIBAVRESAMPLE_VERSION_INT  AV_VERSION_INT(LIBAVRESAMPLE_VERSION_MAJOR, \
 | 
					#define LIBAVRESAMPLE_VERSION_INT  AV_VERSION_INT(LIBAVRESAMPLE_VERSION_MAJOR, \
 | 
				
			||||||
                                                  LIBAVRESAMPLE_VERSION_MINOR, \
 | 
					                                                  LIBAVRESAMPLE_VERSION_MINOR, \
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user