Add libswresample.

Similar to libswscale this does resampling and format convertion, just for audio
instead of video.
changing sampling rate, sample formats, channel layouts and sample packing all
in one with a very simple public interface.

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
pull/2/head
Michael Niedermayer 13 years ago
parent 53e37840bf
commit b5875b9111
  1. 1
      Makefile
  2. 2
      common.mak
  3. 7
      configure
  4. 83
      ffmpeg.c
  5. 12
      libswresample/Makefile
  6. 113
      libswresample/audioconvert.c
  7. 65
      libswresample/audioconvert.h
  8. 271
      libswresample/rematrix.c
  9. 38
      libswresample/rematrix_template.c
  10. 352
      libswresample/resample2.c
  11. 432
      libswresample/swresample.c
  12. 79
      libswresample/swresample.h
  13. 77
      libswresample/swresample_internal.h
  14. 149
      libswresample/swresample_test.c
  15. 6
      tests/ref/acodec/g726
  16. 6
      tests/ref/acodec/pcm
  17. 4
      tests/ref/lavf/dv_fmt
  18. 4
      tests/ref/lavf/mxf_d10

@ -33,6 +33,7 @@ FFLIBS-$(CONFIG_AVFILTER) += avfilter
FFLIBS-$(CONFIG_AVFORMAT) += avformat FFLIBS-$(CONFIG_AVFORMAT) += avformat
FFLIBS-$(CONFIG_AVCODEC) += avcodec FFLIBS-$(CONFIG_AVCODEC) += avcodec
FFLIBS-$(CONFIG_POSTPROC) += postproc FFLIBS-$(CONFIG_POSTPROC) += postproc
FFLIBS-$(CONFIG_SWRESAMPLE)+= swresample
FFLIBS-$(CONFIG_SWSCALE) += swscale FFLIBS-$(CONFIG_SWSCALE) += swscale
FFLIBS := avutil FFLIBS := avutil

@ -20,7 +20,7 @@ $(foreach VAR,$(SILENT),$(eval override $(VAR) = @$($(VAR))))
$(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL)) $(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL))
endif endif
ALLFFLIBS = avcodec avdevice avfilter avformat avutil postproc swscale ALLFFLIBS = avcodec avdevice avfilter avformat avutil postproc swscale swresample
# NASM requires -I path terminated with / # NASM requires -I path terminated with /
IFLAGS := -I. -I$(SRC_PATH)/ IFLAGS := -I. -I$(SRC_PATH)/

7
configure vendored

@ -89,6 +89,7 @@ Configuration options:
--disable-avdevice disable libavdevice build --disable-avdevice disable libavdevice build
--disable-avcodec disable libavcodec build --disable-avcodec disable libavcodec build
--disable-avformat disable libavformat build --disable-avformat disable libavformat build
--disable-swresample disable libswresample build
--disable-swscale disable libswscale build --disable-swscale disable libswscale build
--disable-postproc disable libpostproc build --disable-postproc disable libpostproc build
--disable-avfilter disable video filter support [no] --disable-avfilter disable video filter support [no]
@ -1037,6 +1038,7 @@ CONFIG_LIST="
small small
sram sram
static static
swresample
swscale swscale
swscale_alpha swscale_alpha
thumb thumb
@ -1603,7 +1605,7 @@ avformat_deps="avcodec"
postproc_deps="gpl" postproc_deps="gpl"
# programs # programs
ffmpeg_deps="avcodec avformat swscale" ffmpeg_deps="avcodec avformat swscale swresample"
ffmpeg_select="buffer_filter buffersink_filter" ffmpeg_select="buffer_filter buffersink_filter"
avconv_deps="avcodec avformat swscale" avconv_deps="avcodec avformat swscale"
avconv_select="buffer_filter" avconv_select="buffer_filter"
@ -1766,6 +1768,7 @@ enable postproc
enable protocols enable protocols
enable static enable static
enable stripping enable stripping
enable swresample
enable swscale enable swscale
enable swscale_alpha enable swscale_alpha
@ -3143,7 +3146,7 @@ enabled extra_warnings && check_cflags -Winline
# add some linker flags # add some linker flags
check_ldflags -Wl,--warn-common check_ldflags -Wl,--warn-common
check_ldflags -Wl,-rpath-link=libpostproc:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil check_ldflags -Wl,-rpath-link=libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil
test_ldflags -Wl,-Bsymbolic && append SHFLAGS -Wl,-Bsymbolic test_ldflags -Wl,-Bsymbolic && append SHFLAGS -Wl,-Bsymbolic
echo "X{};" > $TMPV echo "X{};" > $TMPV

@ -45,6 +45,7 @@
#include "libavutil/avstring.h" #include "libavutil/avstring.h"
#include "libavutil/libm.h" #include "libavutil/libm.h"
#include "libavformat/os_support.h" #include "libavformat/os_support.h"
#include "libswresample/swresample.h"
#include "libavformat/ffm.h" // not public API #include "libavformat/ffm.h" // not public API
@ -229,15 +230,14 @@ typedef struct OutputStream {
/* audio only */ /* audio only */
int audio_resample; int audio_resample;
ReSampleContext *resample; /* for audio resampling */
int resample_sample_fmt; int resample_sample_fmt;
int resample_channels; int resample_channels;
int resample_sample_rate; int resample_sample_rate;
int reformat_pair;
AVAudioConvert *reformat_ctx;
AVFifoBuffer *fifo; /* for compression: one audio fifo per codec */ AVFifoBuffer *fifo; /* for compression: one audio fifo per codec */
FILE *logfile; FILE *logfile;
struct SwrContext *swr;
#if CONFIG_AVFILTER #if CONFIG_AVFILTER
AVFilterContext *output_video_filter; AVFilterContext *output_video_filter;
AVFilterContext *input_video_filter; AVFilterContext *input_video_filter;
@ -843,14 +843,15 @@ need_realloc:
exit_program(1); exit_program(1);
} }
if (enc->channels != dec->channels) if (enc->channels != dec->channels
|| enc->sample_fmt != dec->sample_fmt)
ost->audio_resample = 1; ost->audio_resample = 1;
resample_changed = ost->resample_sample_fmt != dec->sample_fmt || resample_changed = ost->resample_sample_fmt != dec->sample_fmt ||
ost->resample_channels != dec->channels || ost->resample_channels != dec->channels ||
ost->resample_sample_rate != dec->sample_rate; ost->resample_sample_rate != dec->sample_rate;
if ((ost->audio_resample && !ost->resample) || resample_changed) { if ((ost->audio_resample && !ost->swr) || resample_changed) {
if (resample_changed) { if (resample_changed) {
av_log(NULL, AV_LOG_INFO, "Input stream #%d.%d frame changed from rate:%d fmt:%s ch:%d to rate:%d fmt:%s ch:%d\n", av_log(NULL, AV_LOG_INFO, "Input stream #%d.%d frame changed from rate:%d fmt:%s ch:%d to rate:%d fmt:%s ch:%d\n",
ist->file_index, ist->st->index, ist->file_index, ist->st->index,
@ -859,24 +860,29 @@ need_realloc:
ost->resample_sample_fmt = dec->sample_fmt; ost->resample_sample_fmt = dec->sample_fmt;
ost->resample_channels = dec->channels; ost->resample_channels = dec->channels;
ost->resample_sample_rate = dec->sample_rate; ost->resample_sample_rate = dec->sample_rate;
if (ost->resample) swr_free(&ost->swr);
audio_resample_close(ost->resample);
} }
/* if audio_sync_method is >1 the resampler is needed for audio drift compensation */ /* if audio_sync_method is >1 the resampler is needed for audio drift compensation */
if (audio_sync_method <= 1 && if (audio_sync_method <= 1 &&
ost->resample_sample_fmt == enc->sample_fmt && ost->resample_sample_fmt == enc->sample_fmt &&
ost->resample_channels == enc->channels && ost->resample_channels == enc->channels &&
ost->resample_sample_rate == enc->sample_rate) { ost->resample_sample_rate == enc->sample_rate) {
ost->resample = NULL; //ost->swr = NULL;
ost->audio_resample = 0; ost->audio_resample = 0;
} else { } else {
if (dec->sample_fmt != AV_SAMPLE_FMT_S16) ost->swr = swr_alloc2(ost->swr,
fprintf(stderr, "Warning, using s16 intermediate sample format for resampling\n"); enc->channel_layout, enc->sample_fmt, enc->sample_rate,
ost->resample = av_audio_resample_init(enc->channels, dec->channels, dec->channel_layout, dec->sample_fmt, dec->sample_rate,
enc->sample_rate, dec->sample_rate, 0, NULL);
enc->sample_fmt, dec->sample_fmt, av_set_int(ost->swr, "ich", dec->channels);
16, 10, 0, 0.8); av_set_int(ost->swr, "och", enc->channels);
if (!ost->resample) { if(audio_sync_method>1) av_set_int(ost->swr, "flags", SWR_FLAG_RESAMPLE);
if(ost->swr && swr_init(ost->swr) < 0){
fprintf(stderr, "swr_init() failed\n");
swr_free(&ost->swr);
}
if (!ost->swr) {
fprintf(stderr, "Can not resample %d channels @ %d Hz to %d channels @ %d Hz\n", fprintf(stderr, "Can not resample %d channels @ %d Hz to %d channels @ %d Hz\n",
dec->channels, dec->sample_rate, dec->channels, dec->sample_rate,
enc->channels, enc->sample_rate); enc->channels, enc->sample_rate);
@ -885,21 +891,7 @@ need_realloc:
} }
} }
#define MAKE_SFMT_PAIR(a,b) ((a)+AV_SAMPLE_FMT_NB*(b)) av_assert0(ost->audio_resample || dec->sample_fmt==enc->sample_fmt);
if (!ost->audio_resample && dec->sample_fmt!=enc->sample_fmt &&
MAKE_SFMT_PAIR(enc->sample_fmt,dec->sample_fmt)!=ost->reformat_pair) {
if (ost->reformat_ctx)
av_audio_convert_free(ost->reformat_ctx);
ost->reformat_ctx = av_audio_convert_alloc(enc->sample_fmt, 1,
dec->sample_fmt, 1, NULL, 0);
if (!ost->reformat_ctx) {
fprintf(stderr, "Cannot convert %s sample format to %s sample format\n",
av_get_sample_fmt_name(dec->sample_fmt),
av_get_sample_fmt_name(enc->sample_fmt));
exit_program(1);
}
ost->reformat_pair=MAKE_SFMT_PAIR(enc->sample_fmt,dec->sample_fmt);
}
if(audio_sync_method){ if(audio_sync_method){
double delta = get_sync_ipts(ost) * enc->sample_rate - ost->sync_opts double delta = get_sync_ipts(ost) * enc->sample_rate - ost->sync_opts
@ -941,7 +933,7 @@ need_realloc:
if(verbose > 2) if(verbose > 2)
fprintf(stderr, "compensating audio timestamp drift:%f compensation:%d in:%d\n", delta, comp, enc->sample_rate); fprintf(stderr, "compensating audio timestamp drift:%f compensation:%d in:%d\n", delta, comp, enc->sample_rate);
// fprintf(stderr, "drift:%f len:%d opts:%"PRId64" ipts:%"PRId64" fifo:%d\n", delta, -1, ost->sync_opts, (int64_t)(get_sync_ipts(ost) * enc->sample_rate), av_fifo_size(ost->fifo)/(ost->st->codec->channels * 2)); // fprintf(stderr, "drift:%f len:%d opts:%"PRId64" ipts:%"PRId64" fifo:%d\n", delta, -1, ost->sync_opts, (int64_t)(get_sync_ipts(ost) * enc->sample_rate), av_fifo_size(ost->fifo)/(ost->st->codec->channels * 2));
av_resample_compensate(*(struct AVResampleContext**)ost->resample, comp, enc->sample_rate); swr_compensate(ost->swr, comp, enc->sample_rate);
} }
} }
}else }else
@ -950,30 +942,15 @@ need_realloc:
if (ost->audio_resample) { if (ost->audio_resample) {
buftmp = audio_buf; buftmp = audio_buf;
size_out = audio_resample(ost->resample, size_out = swr_convert(ost->swr, ( uint8_t*[]){buftmp}, audio_buf_size / (enc->channels * osize),
(short *)buftmp, (short *)buf, (const uint8_t*[]){buf }, size / (dec->channels * isize));
size / (dec->channels * isize));
size_out = size_out * enc->channels * osize; size_out = size_out * enc->channels * osize;
} else { } else {
buftmp = buf; buftmp = buf;
size_out = size; size_out = size;
} }
if (!ost->audio_resample && dec->sample_fmt!=enc->sample_fmt) { av_assert0(ost->audio_resample || dec->sample_fmt==enc->sample_fmt);
const void *ibuf[6]= {buftmp};
void *obuf[6]= {audio_buf};
int istride[6]= {isize};
int ostride[6]= {osize};
int len= size_out/istride[0];
if (av_audio_convert(ost->reformat_ctx, obuf, ostride, ibuf, istride, len)<0) {
printf("av_audio_convert() failed\n");
if (exit_on_error)
exit_program(1);
return;
}
buftmp = audio_buf;
size_out = len*osize;
}
/* now encode as many frames as possible */ /* now encode as many frames as possible */
if (enc->frame_size > 1) { if (enc->frame_size > 1) {
@ -2133,7 +2110,6 @@ static int transcode_init(OutputFile *output_files, int nb_output_files,
if (!ost->fifo) { if (!ost->fifo) {
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
} }
ost->reformat_pair = MAKE_SFMT_PAIR(AV_SAMPLE_FMT_NONE,AV_SAMPLE_FMT_NONE);
if (!codec->sample_rate) { if (!codec->sample_rate) {
codec->sample_rate = icodec->sample_rate; codec->sample_rate = icodec->sample_rate;
} }
@ -2149,6 +2125,8 @@ static int transcode_init(OutputFile *output_files, int nb_output_files,
if (av_get_channel_layout_nb_channels(codec->channel_layout) != codec->channels) if (av_get_channel_layout_nb_channels(codec->channel_layout) != codec->channels)
codec->channel_layout = 0; codec->channel_layout = 0;
ost->audio_resample = codec->sample_rate != icodec->sample_rate || audio_sync_method > 1; ost->audio_resample = codec->sample_rate != icodec->sample_rate || audio_sync_method > 1;
ost->audio_resample |= codec->sample_fmt != icodec->sample_fmt
|| codec->channel_layout != icodec->channel_layout;
icodec->request_channels = codec->channels; icodec->request_channels = codec->channels;
ist->decoding_needed = 1; ist->decoding_needed = 1;
ost->encoding_needed = 1; ost->encoding_needed = 1;
@ -2679,10 +2657,7 @@ static int transcode(OutputFile *output_files, int nb_output_files,
av_free(ost->forced_kf_pts); av_free(ost->forced_kf_pts);
if (ost->video_resample) if (ost->video_resample)
sws_freeContext(ost->img_resample_ctx); sws_freeContext(ost->img_resample_ctx);
if (ost->resample) swr_free(&ost->swr);
audio_resample_close(ost->resample);
if (ost->reformat_ctx)
av_audio_convert_free(ost->reformat_ctx);
av_dict_free(&ost->opts); av_dict_free(&ost->opts);
} }
} }

@ -0,0 +1,12 @@
include $(SUBDIR)../config.mak
NAME = swresample
FFLIBS = avutil
HEADERS = swresample.h
OBJS = swresample.o audioconvert.o resample2.o rematrix.o
TESTPROGS = swresample_test
include $(SUBDIR)../subdir.mak

@ -0,0 +1,113 @@
/*
* audio conversion
* Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* audio conversion
* @author Michael Niedermayer <michaelni@gmx.at>
*/
#include "libavutil/avstring.h"
#include "libavutil/avassert.h"
#include "libavutil/libm.h"
#include "libavutil/samplefmt.h"
#include "audioconvert.h"
struct AVAudioConvert {
int channels;
int fmt_pair;
};
AVAudioConvert *swr_audio_convert_alloc(enum AVSampleFormat out_fmt,
enum AVSampleFormat in_fmt,
int channels, int flags)
{
AVAudioConvert *ctx;
ctx = av_malloc(sizeof(AVAudioConvert));
if (!ctx)
return NULL;
ctx->channels = channels;
ctx->fmt_pair = out_fmt + AV_SAMPLE_FMT_NB*in_fmt;
return ctx;
}
void swr_audio_convert_free(AVAudioConvert **ctx)
{
av_freep(ctx);
}
int swr_audio_convert(AVAudioConvert *ctx, AudioData *out, AudioData*in, int len)
{
int ch;
av_assert0(ctx->channels == out->ch_count);
//FIXME optimize common cases
for(ch=0; ch<ctx->channels; ch++){
const int is= (in ->planar ? 1 : in->ch_count) * in->bps;
const int os= (out->planar ? 1 :out->ch_count) *out->bps;
const uint8_t *pi= in ->ch[ch];
uint8_t *po= out->ch[ch];
uint8_t *end= po + os*len;
if(!po)
continue;
#define CONV(ofmt, otype, ifmt, expr)\
if(ctx->fmt_pair == ofmt + AV_SAMPLE_FMT_NB*ifmt){\
do{\
*(otype*)po = expr; pi += is; po += os;\
}while(po < end);\
}
//FIXME put things below under ifdefs so we do not waste space for cases no codec will need
//FIXME rounding ?
CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_U8 , *(const uint8_t*)pi)
else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)<<8)
else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)<<24)
else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0 / (1<<7)))
else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0 / (1<<7)))
else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S16, (*(const int16_t*)pi>>8) + 0x80)
else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi)
else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi<<16)
else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0 / (1<<15)))
else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0 / (1<<15)))
else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S32, (*(const int32_t*)pi>>24) + 0x80)
else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi>>16)
else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi)
else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0 / (1U<<31)))
else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0 / (1U<<31)))
else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_FLT, av_clip_uint8( lrintf(*(const float*)pi * (1<<7)) + 0x80))
else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, av_clip_int16( lrintf(*(const float*)pi * (1<<15))))
else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, av_clipl_int32(llrintf(*(const float*)pi * (1U<<31))))
else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_FLT, *(const float*)pi)
else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_FLT, *(const float*)pi)
else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_DBL, av_clip_uint8( lrint(*(const double*)pi * (1<<7)) + 0x80))
else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, av_clip_int16( lrint(*(const double*)pi * (1<<15))))
else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, av_clipl_int32(llrint(*(const double*)pi * (1U<<31))))
else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_DBL, *(const double*)pi)
else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_DBL, *(const double*)pi)
else return -1;
}
return 0;
}

@ -0,0 +1,65 @@
/*
* audio conversion
* Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2008 Peter Ross
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef SWR_AUDIOCONVERT_H
#define SWR_AUDIOCONVERT_H
/**
* @file
* Audio format conversion routines
*/
#include "swresample_internal.h"
#include "libavutil/cpu.h"
#include "libavutil/audioconvert.h"
struct AVAudioConvert;
typedef struct AVAudioConvert AVAudioConvert;
/**
* Create an audio sample format converter context
* @param out_fmt Output sample format
* @param in_fmt Input sample format
* @param channels Number of channels
* @param flags See AV_CPU_FLAG_xx
* @return NULL on error
*/
AVAudioConvert *swr_audio_convert_alloc(enum AVSampleFormat out_fmt,
enum AVSampleFormat in_fmt,
int channels, int flags);
/**
* Free audio sample format converter context.
* and set the pointer to NULL
*/
void swr_audio_convert_free(AVAudioConvert **ctx);
/**
* Convert between audio sample formats
* @param[in] out array of output buffers for each channel. set to NULL to ignore processing of the given channel.
* @param[in] in array of input buffers for each channel
* @param len length of audio frame size (measured in samples)
*/
int swr_audio_convert(AVAudioConvert *ctx, AudioData *out, AudioData *in, int len);
#endif /* AVCODEC_AUDIOCONVERT_H */

@ -0,0 +1,271 @@
/*
* Copyright (C) 2011 Michael Niedermayer (michaelni@gmx.at)
*
* This file is part of libswresample
*
* libswresample is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libswresample is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libswresample; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "swresample_internal.h"
#include "libavutil/audioconvert.h"
#include "libavutil/avassert.h"
#define SAMPLE float
#define RENAME(x) x ## _float
#include "rematrix_template.c"
#undef SAMPLE
#undef RENAME
#define SAMPLE int16_t
#define RENAME(x) x ## _s16
#include "rematrix_template.c"
#define FRONT_LEFT 0
#define FRONT_RIGHT 1
#define FRONT_CENTER 2
#define LOW_FREQUENCY 3
#define BACK_LEFT 4
#define BACK_RIGHT 5
#define FRONT_LEFT_OF_CENTER 6
#define FRONT_RIGHT_OF_CENTER 7
#define BACK_CENTER 8
#define SIDE_LEFT 9
#define SIDE_RIGHT 10
#define TOP_CENTER 11
#define TOP_FRONT_LEFT 12
#define TOP_FRONT_CENTER 13
#define TOP_FRONT_RIGHT 14
#define TOP_BACK_LEFT 15
#define TOP_BACK_CENTER 16
#define TOP_BACK_RIGHT 17
static int even(int64_t layout){
if(!layout) return 1;
if(layout&(layout-1)) return 1;
return 0;
}
static int sane_layout(int64_t layout){
if(!(layout & AV_CH_LAYOUT_SURROUND)) // at least 1 front speaker
return 0;
if(!even(layout & (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT))) // no asymetric front
return 0;
if(!even(layout & (AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT))) // no asymetric side
return 0;
if(!even(layout & (AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT)))
return 0;
if(!even(layout & (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER)))
return 0;
if(av_get_channel_layout_nb_channels(layout) >= SWR_CH_MAX)
return 0;
return 1;
}
int swr_rematrix_init(SwrContext *s){
int i, j, in_i, out_i;
float matrix[64][64]={0};
int64_t unaccounted= s->in_ch_layout & ~s->out_ch_layout;
float maxcoef=0;
for(i=0; i<64; i++){
if(s->in_ch_layout & s->out_ch_layout & (1LL<<i))
matrix[i][i]= 1.0;
}
if(!sane_layout(s->in_ch_layout)){
av_log(s, AV_LOG_ERROR, "Input channel layout isnt supported\n");
return AVERROR(EINVAL);
}
if(!sane_layout(s->out_ch_layout)){
av_log(s, AV_LOG_ERROR, "Output channel layout isnt supported\n");
return AVERROR(EINVAL);
}
//FIXME implement dolby surround
//FIXME implement full ac3
if(unaccounted & AV_CH_FRONT_CENTER){
if((s->out_ch_layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO){
matrix[ FRONT_LEFT][FRONT_CENTER]+= sqrt(0.5);
matrix[FRONT_RIGHT][FRONT_CENTER]+= sqrt(0.5);
}else
av_assert0(0);
}
if(unaccounted & AV_CH_LAYOUT_STEREO){
if(s->out_ch_layout & AV_CH_FRONT_CENTER){
matrix[FRONT_CENTER][ FRONT_LEFT]+= sqrt(0.5);
matrix[FRONT_CENTER][FRONT_RIGHT]+= sqrt(0.5);
if(s->in_ch_layout & AV_CH_FRONT_CENTER)
matrix[FRONT_CENTER][ FRONT_CENTER] = s->clev*sqrt(2);
}else
av_assert0(0);
}
if(unaccounted & AV_CH_BACK_CENTER){
if(s->out_ch_layout & AV_CH_BACK_LEFT){
matrix[ BACK_LEFT][BACK_CENTER]+= sqrt(0.5);
matrix[BACK_RIGHT][BACK_CENTER]+= sqrt(0.5);
}else if(s->out_ch_layout & AV_CH_SIDE_LEFT){
matrix[ SIDE_LEFT][BACK_CENTER]+= sqrt(0.5);
matrix[SIDE_RIGHT][BACK_CENTER]+= sqrt(0.5);
}else if(s->out_ch_layout & AV_CH_FRONT_LEFT){
matrix[ FRONT_LEFT][BACK_CENTER]+= s->slev*sqrt(0.5);
matrix[FRONT_RIGHT][BACK_CENTER]+= s->slev*sqrt(0.5);
}else if(s->out_ch_layout & AV_CH_FRONT_CENTER){
matrix[ FRONT_CENTER][BACK_CENTER]+= s->slev*sqrt(0.5);
}else
av_assert0(0);
}
if(unaccounted & AV_CH_BACK_LEFT){
if(s->out_ch_layout & AV_CH_BACK_CENTER){
matrix[BACK_CENTER][ BACK_LEFT]+= sqrt(0.5);
matrix[BACK_CENTER][BACK_RIGHT]+= sqrt(0.5);
}else if(s->out_ch_layout & AV_CH_SIDE_LEFT){
if(s->in_ch_layout & AV_CH_SIDE_LEFT){
matrix[ SIDE_LEFT][ BACK_LEFT]+= sqrt(0.5);
matrix[SIDE_RIGHT][BACK_RIGHT]+= sqrt(0.5);
}else{
matrix[ SIDE_LEFT][ BACK_LEFT]+= 1.0;
matrix[SIDE_RIGHT][BACK_RIGHT]+= 1.0;
}
}else if(s->out_ch_layout & AV_CH_FRONT_LEFT){
matrix[ FRONT_LEFT][ BACK_LEFT]+= s->slev;
matrix[FRONT_RIGHT][BACK_RIGHT]+= s->slev;
}else if(s->out_ch_layout & AV_CH_FRONT_CENTER){
matrix[ FRONT_CENTER][BACK_LEFT ]+= s->slev*sqrt(0.5);
matrix[ FRONT_CENTER][BACK_RIGHT]+= s->slev*sqrt(0.5);
}else
av_assert0(0);
}
if(unaccounted & AV_CH_SIDE_LEFT){
if(s->out_ch_layout & AV_CH_BACK_LEFT){
matrix[ BACK_LEFT][ SIDE_LEFT]+= 1.0;
matrix[BACK_RIGHT][SIDE_RIGHT]+= 1.0;
}else if(s->out_ch_layout & AV_CH_BACK_CENTER){
matrix[BACK_CENTER][ SIDE_LEFT]+= sqrt(0.5);
matrix[BACK_CENTER][SIDE_RIGHT]+= sqrt(0.5);
}else if(s->out_ch_layout & AV_CH_FRONT_LEFT){
matrix[ FRONT_LEFT][ SIDE_LEFT]+= s->slev;
matrix[FRONT_RIGHT][SIDE_RIGHT]+= s->slev;
}else if(s->out_ch_layout & AV_CH_FRONT_CENTER){
matrix[ FRONT_CENTER][SIDE_LEFT ]+= s->slev*sqrt(0.5);
matrix[ FRONT_CENTER][SIDE_RIGHT]+= s->slev*sqrt(0.5);
}else
av_assert0(0);
}
if(unaccounted & AV_CH_FRONT_LEFT_OF_CENTER){
if(s->out_ch_layout & AV_CH_FRONT_LEFT){
matrix[ FRONT_LEFT][ FRONT_LEFT_OF_CENTER]+= 1.0;
matrix[FRONT_RIGHT][FRONT_RIGHT_OF_CENTER]+= 1.0;
}else if(s->out_ch_layout & AV_CH_FRONT_CENTER){
matrix[ FRONT_CENTER][ FRONT_LEFT_OF_CENTER]+= sqrt(0.5);
matrix[ FRONT_CENTER][FRONT_RIGHT_OF_CENTER]+= sqrt(0.5);
}else
av_assert0(0);
}
//FIXME quantize for integeres
for(out_i=i=0; i<64; i++){
double sum=0;
int in_i=0;
int ch_in=0;
for(j=0; j<64; j++){
s->matrix[out_i][in_i]= matrix[i][j];
if(matrix[i][j]){
s->matrix_ch[out_i][++ch_in]= in_i;
sum += fabs(matrix[i][j]);
}
if(s->in_ch_layout & (1ULL<<j))
in_i++;
}
s->matrix_ch[out_i][0]= ch_in;
maxcoef= FFMAX(maxcoef, sum);
if(s->out_ch_layout & (1ULL<<i))
out_i++;
}
if(( s->out_sample_fmt < AV_SAMPLE_FMT_FLT
|| s->int_sample_fmt < AV_SAMPLE_FMT_FLT) && maxcoef > 1.0){
for(i=0; i<SWR_CH_MAX; i++)
for(j=0; j<SWR_CH_MAX; j++)
s->matrix[i][j] /= maxcoef;
}
for(i=0; i<av_get_channel_layout_nb_channels(s->out_ch_layout); i++){
for(j=0; j<av_get_channel_layout_nb_channels(s->in_ch_layout); j++){
av_log(NULL, AV_LOG_ERROR, "%f ", s->matrix[i][j]);
}
av_log(NULL, AV_LOG_ERROR, "\n");
}
return 0;
}
int swr_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy){
int out_i, in_i, i, j;
av_assert0(out->ch_count == av_get_channel_layout_nb_channels(s->out_ch_layout));
av_assert0(in ->ch_count == av_get_channel_layout_nb_channels(s-> in_ch_layout));
for(out_i=0; out_i<out->ch_count; out_i++){
switch(s->matrix_ch[out_i][0]){
case 1:
in_i= s->matrix_ch[out_i][1];
if(mustcopy || s->matrix[out_i][in_i]!=1.0){
if(s->int_sample_fmt == AV_SAMPLE_FMT_FLT){
copy_float(out->ch[out_i], in->ch[in_i], s->matrix[out_i][in_i], len);
}else
copy_s16 (out->ch[out_i], in->ch[in_i], s->matrix[out_i][in_i], len);
}else{
out->ch[out_i]= in->ch[in_i];
}
break;
case 2:
if(s->int_sample_fmt == AV_SAMPLE_FMT_FLT){
sum2_float(out->ch[out_i], in->ch[ s->matrix_ch[out_i][1] ], in->ch[ s->matrix_ch[out_i][2] ],
s->matrix[out_i][ s->matrix_ch[out_i][1] ], s->matrix[out_i][ s->matrix_ch[out_i][2] ],
len);
}else{
sum2_s16 (out->ch[out_i], in->ch[ s->matrix_ch[out_i][1] ], in->ch[ s->matrix_ch[out_i][2] ],
s->matrix[out_i][ s->matrix_ch[out_i][1] ], s->matrix[out_i][ s->matrix_ch[out_i][2] ],
len);
}
break;
default:
if(s->int_sample_fmt == AV_SAMPLE_FMT_FLT){
for(i=0; i<len; i++){
float v=0;
for(j=0; j<s->matrix_ch[out_i][0]; j++){
in_i= s->matrix_ch[out_i][1+j];
v+= ((float*)in->ch[in_i])[i] * s->matrix[out_i][in_i];
}
((float*)out->ch[out_i])[i]= v;
}
}else{
for(i=0; i<len; i++){
int v=0;
for(j=0; j<s->matrix_ch[out_i][0]; j++){
in_i= s->matrix_ch[out_i][1+j];
v+= ((int16_t*)in->ch[in_i])[i] * s->matrix[out_i][in_i]; //FIXME use int16 coeffs
}
((int16_t*)out->ch[out_i])[i]= v;
}
}
}
}
return 0;
}

@ -0,0 +1,38 @@
/*
* Copyright (C) 2011 Michael Niedermayer (michaelni@gmx.at)
*
* This file is part of libswresample
*
* libswresample is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libswresample is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libswresample; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
static void RENAME(sum2)(SAMPLE *out, const SAMPLE *in1, const SAMPLE *in2, float coeff1, float coeff2, int len){
int i;
for(i=0; i<len; i++)
out[i] = coeff1*in1[i] + coeff2*in2[i]; //FIXME better int16
}
static void RENAME(copy)(SAMPLE *out, const SAMPLE *in, float coeff, int len){
if(coeff == 1.0){
memcpy(out, in, sizeof(SAMPLE)*len);
}else{
int i;
for(i=0; i<len; i++)
out[i] = coeff*in[i]; //FIXME better int16
}
}

@ -0,0 +1,352 @@
/*
* audio resampling
* Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* audio resampling
* @author Michael Niedermayer <michaelni@gmx.at>
*/
#include "libavutil/log.h"
#include "swresample_internal.h"
#ifndef CONFIG_RESAMPLE_HP
#define FILTER_SHIFT 15
#define FELEM int16_t
#define FELEM2 int32_t
#define FELEML int64_t
#define FELEM_MAX INT16_MAX
#define FELEM_MIN INT16_MIN
#define WINDOW_TYPE 9
#elif !defined(CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE)
#define FILTER_SHIFT 30
#define FELEM int32_t
#define FELEM2 int64_t
#define FELEML int64_t
#define FELEM_MAX INT32_MAX
#define FELEM_MIN INT32_MIN
#define WINDOW_TYPE 12
#else
#define FILTER_SHIFT 0
#define FELEM double
#define FELEM2 double
#define FELEML double
#define WINDOW_TYPE 24
#endif
typedef struct AVResampleContext{
const AVClass *av_class;
FELEM *filter_bank;
int filter_length;
int ideal_dst_incr;
int dst_incr;
int index;
int frac;
int src_incr;
int compensation_distance;
int phase_shift;
int phase_mask;
int linear;
double factor;
}AVResampleContext;
/**
* 0th order modified bessel function of the first kind.
*/
static double bessel(double x){
double v=1;
double lastv=0;
double t=1;
int i;
static const double inv[100]={
1.0/( 1* 1), 1.0/( 2* 2), 1.0/( 3* 3), 1.0/( 4* 4), 1.0/( 5* 5), 1.0/( 6* 6), 1.0/( 7* 7), 1.0/( 8* 8), 1.0/( 9* 9), 1.0/(10*10),
1.0/(11*11), 1.0/(12*12), 1.0/(13*13), 1.0/(14*14), 1.0/(15*15), 1.0/(16*16), 1.0/(17*17), 1.0/(18*18), 1.0/(19*19), 1.0/(20*20),
1.0/(21*21), 1.0/(22*22), 1.0/(23*23), 1.0/(24*24), 1.0/(25*25), 1.0/(26*26), 1.0/(27*27), 1.0/(28*28), 1.0/(29*29), 1.0/(30*30),
1.0/(31*31), 1.0/(32*32), 1.0/(33*33), 1.0/(34*34), 1.0/(35*35), 1.0/(36*36), 1.0/(37*37), 1.0/(38*38), 1.0/(39*39), 1.0/(40*40),
1.0/(41*41), 1.0/(42*42), 1.0/(43*43), 1.0/(44*44), 1.0/(45*45), 1.0/(46*46), 1.0/(47*47), 1.0/(48*48), 1.0/(49*49), 1.0/(50*50),
1.0/(51*51), 1.0/(52*52), 1.0/(53*53), 1.0/(54*54), 1.0/(55*55), 1.0/(56*56), 1.0/(57*57), 1.0/(58*58), 1.0/(59*59), 1.0/(60*60),
1.0/(61*61), 1.0/(62*62), 1.0/(63*63), 1.0/(64*64), 1.0/(65*65), 1.0/(66*66), 1.0/(67*67), 1.0/(68*68), 1.0/(69*69), 1.0/(70*70),
1.0/(71*71), 1.0/(72*72), 1.0/(73*73), 1.0/(74*74), 1.0/(75*75), 1.0/(76*76), 1.0/(77*77), 1.0/(78*78), 1.0/(79*79), 1.0/(80*80),
1.0/(81*81), 1.0/(82*82), 1.0/(83*83), 1.0/(84*84), 1.0/(85*85), 1.0/(86*86), 1.0/(87*87), 1.0/(88*88), 1.0/(89*89), 1.0/(90*90),
1.0/(91*91), 1.0/(92*92), 1.0/(93*93), 1.0/(94*94), 1.0/(95*95), 1.0/(96*96), 1.0/(97*97), 1.0/(98*98), 1.0/(99*99), 1.0/(10000)
};
x= x*x/4;
for(i=0; v != lastv; i++){
lastv=v;
t *= x*inv[i];
v += t;
}
return v;
}
/**
* builds a polyphase filterbank.
* @param factor resampling factor
* @param scale wanted sum of coefficients for each filter
* @param type 0->cubic, 1->blackman nuttall windowed sinc, 2..16->kaiser windowed sinc beta=2..16
* @return 0 on success, negative on error
*/
static int build_filter(FELEM *filter, double factor, int tap_count, int phase_count, int scale, int type){
int ph, i;
double x, y, w;
double *tab = av_malloc(tap_count * sizeof(*tab));
const int center= (tap_count-1)/2;
if (!tab)
return AVERROR(ENOMEM);
/* if upsampling, only need to interpolate, no filter */
if (factor > 1.0)
factor = 1.0;
for(ph=0;ph<phase_count;ph++) {
double norm = 0;
for(i=0;i<tap_count;i++) {
x = M_PI * ((double)(i - center) - (double)ph / phase_count) * factor;
if (x == 0) y = 1.0;
else y = sin(x) / x;
switch(type){
case 0:{
const float d= -0.5; //first order derivative = -0.5
x = fabs(((double)(i - center) - (double)ph / phase_count) * factor);
if(x<1.0) y= 1 - 3*x*x + 2*x*x*x + d*( -x*x + x*x*x);
else y= d*(-4 + 8*x - 5*x*x + x*x*x);
break;}
case 1:
w = 2.0*x / (factor*tap_count) + M_PI;
y *= 0.3635819 - 0.4891775 * cos(w) + 0.1365995 * cos(2*w) - 0.0106411 * cos(3*w);
break;
default:
w = 2.0*x / (factor*tap_count*M_PI);
y *= bessel(type*sqrt(FFMAX(1-w*w, 0)));
break;
}
tab[i] = y;
norm += y;
}
/* normalize so that an uniform color remains the same */
for(i=0;i<tap_count;i++) {
#ifdef CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE
filter[ph * tap_count + i] = tab[i] / norm;
#else
filter[ph * tap_count + i] = av_clip(lrintf(tab[i] * scale / norm), FELEM_MIN, FELEM_MAX);
#endif
}
}
#if 0
{
#define LEN 1024
int j,k;
double sine[LEN + tap_count];
double filtered[LEN];
double maxff=-2, minff=2, maxsf=-2, minsf=2;
for(i=0; i<LEN; i++){
double ss=0, sf=0, ff=0;
for(j=0; j<LEN+tap_count; j++)
sine[j]= cos(i*j*M_PI/LEN);
for(j=0; j<LEN; j++){
double sum=0;
ph=0;
for(k=0; k<tap_count; k++)
sum += filter[ph * tap_count + k] * sine[k+j];
filtered[j]= sum / (1<<FILTER_SHIFT);
ss+= sine[j + center] * sine[j + center];
ff+= filtered[j] * filtered[j];
sf+= sine[j + center] * filtered[j];
}
ss= sqrt(2*ss/LEN);
ff= sqrt(2*ff/LEN);
sf= 2*sf/LEN;
maxff= FFMAX(maxff, ff);
minff= FFMIN(minff, ff);
maxsf= FFMAX(maxsf, sf);
minsf= FFMIN(minsf, sf);
if(i%11==0){
av_log(NULL, AV_LOG_ERROR, "i:%4d ss:%f ff:%13.6e-%13.6e sf:%13.6e-%13.6e\n", i, ss, maxff, minff, maxsf, minsf);
minff=minsf= 2;
maxff=maxsf= -2;
}
}
}
#endif
av_free(tab);
return 0;
}
AVResampleContext *swr_resample_init(AVResampleContext *c, int out_rate, int in_rate, int filter_size, int phase_shift, int linear, double cutoff){
double factor= FFMIN(out_rate * cutoff / in_rate, 1.0);
int phase_count= 1<<phase_shift;
if(!c || c->phase_shift!=phase_shift || c->linear!=linear || c->factor != factor
|| c->filter_length!=FFMAX((int)ceil(filter_size/factor), 1)){
c= av_mallocz(sizeof(AVResampleContext));
if (!c)
return NULL;
c->phase_shift= phase_shift;
c->phase_mask= phase_count-1;
c->linear= linear;
c->factor= factor;
c->filter_length= FFMAX((int)ceil(filter_size/factor), 1);
c->filter_bank= av_mallocz(c->filter_length*(phase_count+1)*sizeof(FELEM));
if (!c->filter_bank)
goto error;
if (build_filter(c->filter_bank, factor, c->filter_length, phase_count, 1<<FILTER_SHIFT, WINDOW_TYPE))
goto error;
memcpy(&c->filter_bank[c->filter_length*phase_count+1], c->filter_bank, (c->filter_length-1)*sizeof(FELEM));
c->filter_bank[c->filter_length*phase_count]= c->filter_bank[c->filter_length - 1];
}
c->compensation_distance= 0;
c->src_incr= out_rate;
c->ideal_dst_incr= c->dst_incr= in_rate * phase_count;
c->index= -phase_count*((c->filter_length-1)/2);
c->frac= 0;
return c;
error:
av_free(c->filter_bank);
av_free(c);
return NULL;
}
void swr_resample_free(AVResampleContext **c){
if(!*c)
return;
av_freep(&(*c)->filter_bank);
av_freep(c);
}
void swr_compensate(struct SwrContext *s, int sample_delta, int compensation_distance){
AVResampleContext *c= s->resample;
// sample_delta += (c->ideal_dst_incr - c->dst_incr)*(int64_t)c->compensation_distance / c->ideal_dst_incr;
c->compensation_distance= compensation_distance;
c->dst_incr = c->ideal_dst_incr - c->ideal_dst_incr * (int64_t)sample_delta / compensation_distance;
}
int swr_resample(AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx){
int dst_index, i;
int index= c->index;
int frac= c->frac;
int dst_incr_frac= c->dst_incr % c->src_incr;
int dst_incr= c->dst_incr / c->src_incr;
int compensation_distance= c->compensation_distance;
if(compensation_distance == 0 && c->filter_length == 1 && c->phase_shift==0){
int64_t index2= ((int64_t)index)<<32;
int64_t incr= (1LL<<32) * c->dst_incr / c->src_incr;
dst_size= FFMIN(dst_size, (src_size-1-index) * (int64_t)c->src_incr / c->dst_incr);
for(dst_index=0; dst_index < dst_size; dst_index++){
dst[dst_index] = src[index2>>32];
index2 += incr;
}
frac += dst_index * dst_incr_frac;
index += dst_index * dst_incr;
index += frac / c->src_incr;
frac %= c->src_incr;
}else{
for(dst_index=0; dst_index < dst_size; dst_index++){
FELEM *filter= c->filter_bank + c->filter_length*(index & c->phase_mask);
int sample_index= index >> c->phase_shift;
FELEM2 val=0;
if(sample_index < 0){
for(i=0; i<c->filter_length; i++)
val += src[FFABS(sample_index + i) % src_size] * filter[i];
}else if(sample_index + c->filter_length > src_size){
break;
}else if(c->linear){
FELEM2 v2=0;
for(i=0; i<c->filter_length; i++){
val += src[sample_index + i] * (FELEM2)filter[i];
v2 += src[sample_index + i] * (FELEM2)filter[i + c->filter_length];
}
val+=(v2-val)*(FELEML)frac / c->src_incr;
}else{
for(i=0; i<c->filter_length; i++){
val += src[sample_index + i] * (FELEM2)filter[i];
}
}
#ifdef CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE
dst[dst_index] = av_clip_int16(lrintf(val));
#else
val = (val + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT;
dst[dst_index] = (unsigned)(val + 32768) > 65535 ? (val>>31) ^ 32767 : val;
#endif
frac += dst_incr_frac;
index += dst_incr;
if(frac >= c->src_incr){
frac -= c->src_incr;
index++;
}
if(dst_index + 1 == compensation_distance){
compensation_distance= 0;
dst_incr_frac= c->ideal_dst_incr % c->src_incr;
dst_incr= c->ideal_dst_incr / c->src_incr;
}
}
}
*consumed= FFMAX(index, 0) >> c->phase_shift;
if(index>=0) index &= c->phase_mask;
if(compensation_distance){
compensation_distance -= dst_index;
assert(compensation_distance > 0);
}
if(update_ctx){
c->frac= frac;
c->index= index;
c->dst_incr= dst_incr_frac + c->src_incr*dst_incr;
c->compensation_distance= compensation_distance;
}
#if 0
if(update_ctx && !c->compensation_distance){
#undef rand
av_resample_compensate(c, rand() % (8000*2) - 8000, 8000*2);
av_log(NULL, AV_LOG_DEBUG, "%d %d %d\n", c->dst_incr, c->ideal_dst_incr, c->compensation_distance);
}
#endif
return dst_index;
}
int swr_multiple_resample(AVResampleContext *c, AudioData *dst, int dst_size, AudioData *src, int src_size, int *consumed){
int i, ret= -1;
for(i=0; i<dst->ch_count; i++){
ret= swr_resample(c, dst->ch[i], src->ch[i], consumed, src_size, dst_size, i+1==dst->ch_count);
}
return ret;
}

@ -0,0 +1,432 @@
/*
* Copyright (C) 2011 Michael Niedermayer (michaelni@gmx.at)
*
* This file is part of libswresample
*
* libswresample is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libswresample is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libswresample; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/opt.h"
#include "swresample_internal.h"
#include "audioconvert.h"
#include "libavutil/avassert.h"
#define C30DB M_SQRT2
#define C15DB 1.189207115
#define C__0DB 1.0
#define C_15DB 0.840896415
#define C_30DB M_SQRT1_2
#define C_45DB 0.594603558
#define C_60DB 0.5
//TODO split options array out?
#define OFFSET(x) offsetof(SwrContext,x)
static const AVOption options[]={
{"ich", "input channel count", OFFSET( in.ch_count ), FF_OPT_TYPE_INT, {.dbl=2}, 1, SWR_CH_MAX, 0},
{"och", "output channel count", OFFSET(out.ch_count ), FF_OPT_TYPE_INT, {.dbl=2}, 1, SWR_CH_MAX, 0},
{"isr", "input sample rate" , OFFSET( in_sample_rate), FF_OPT_TYPE_INT, {.dbl=48000}, 1, INT_MAX, 0},
{"osr", "output sample rate" , OFFSET(out_sample_rate), FF_OPT_TYPE_INT, {.dbl=48000}, 1, INT_MAX, 0},
{"ip" , "input planar" , OFFSET( in.planar ), FF_OPT_TYPE_INT, {.dbl=0}, 0, 1, 0},
{"op" , "output planar" , OFFSET(out.planar ), FF_OPT_TYPE_INT, {.dbl=0}, 0, 1, 0},
{"isf", "input sample format", OFFSET( in_sample_fmt ), FF_OPT_TYPE_INT, {.dbl=AV_SAMPLE_FMT_S16}, 0, AV_SAMPLE_FMT_NB-1, 0},
{"osf", "output sample format", OFFSET(out_sample_fmt ), FF_OPT_TYPE_INT, {.dbl=AV_SAMPLE_FMT_S16}, 0, AV_SAMPLE_FMT_NB-1, 0},
{"tsf", "internal sample format", OFFSET(int_sample_fmt ), FF_OPT_TYPE_INT, {.dbl=AV_SAMPLE_FMT_NONE}, -1, AV_SAMPLE_FMT_FLT, 0},
{"icl", "input channel layout" , OFFSET( in_ch_layout), FF_OPT_TYPE_INT64, {.dbl=0}, 0, INT64_MAX, 0, "channel_layout"},
{"ocl", "output channel layout", OFFSET(out_ch_layout), FF_OPT_TYPE_INT64, {.dbl=0}, 0, INT64_MAX, 0, "channel_layout"},
{"clev", "center mix level" , OFFSET(clev) , FF_OPT_TYPE_FLOAT, {.dbl=C_30DB}, 0, 4, 0},
{"slev", "sourround mix level" , OFFSET(slev) , FF_OPT_TYPE_FLOAT, {.dbl=C_30DB}, 0, 4, 0},
{"flags", NULL , OFFSET(flags) , FF_OPT_TYPE_FLAGS, {.dbl=0}, 0, UINT_MAX, 0, "flags"},
{"res", "force resampling", 0, FF_OPT_TYPE_CONST, {.dbl=SWR_FLAG_RESAMPLE}, INT_MIN, INT_MAX, 0, "flags"},
{0}
};
static const char* context_to_name(void* ptr) {
return "SWR";
}
static const AVClass av_class = { "SwrContext", context_to_name, options, LIBAVUTIL_VERSION_INT, OFFSET(log_level_offset), OFFSET(log_ctx) };
static int resample(SwrContext *s, AudioData *out_param, int out_count,
const AudioData * in_param, int in_count);
SwrContext *swr_alloc(void){
SwrContext *s= av_mallocz(sizeof(SwrContext));
if(s){
s->av_class= &av_class;
av_opt_set_defaults2(s, 0, 0);
}
return s;
}
SwrContext *swr_alloc2(struct SwrContext *s, int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate,
int log_offset, void *log_ctx){
if(!s) s= swr_alloc();
if(!s) return NULL;
s->log_level_offset= log_offset;
s->log_ctx= log_ctx;
av_set_int(s, "ocl", out_ch_layout);
av_set_int(s, "osf", out_sample_fmt);
av_set_int(s, "osr", out_sample_rate);
av_set_int(s, "icl", in_ch_layout);
av_set_int(s, "isf", in_sample_fmt);
av_set_int(s, "isr", in_sample_rate);
s-> in.ch_count= av_get_channel_layout_nb_channels(s-> in_ch_layout);
s->out.ch_count= av_get_channel_layout_nb_channels(s->out_ch_layout);
s->int_sample_fmt = AV_SAMPLE_FMT_S16;
return s;
}
static void free_temp(AudioData *a){
av_free(a->data);
memset(a, 0, sizeof(*a));
}
void swr_free(SwrContext **ss){
SwrContext *s= *ss;
if(s){
free_temp(&s->postin);
free_temp(&s->midbuf);
free_temp(&s->preout);
free_temp(&s->in_buffer);
swr_audio_convert_free(&s-> in_convert);
swr_audio_convert_free(&s->out_convert);
swr_resample_free(&s->resample);
}
av_freep(ss);
}
static int64_t guess_layout(int ch){
switch(ch){
case 1: return AV_CH_LAYOUT_MONO;
case 2: return AV_CH_LAYOUT_STEREO;
case 5: return AV_CH_LAYOUT_5POINT0;
case 6: return AV_CH_LAYOUT_5POINT1;
case 7: return AV_CH_LAYOUT_7POINT0;
case 8: return AV_CH_LAYOUT_7POINT1;
default: return 0;
}
}
int swr_init(SwrContext *s){
s->in_buffer_index= 0;
s->in_buffer_count= 0;
s->resample_in_constraint= 0;
free_temp(&s->postin);
free_temp(&s->midbuf);
free_temp(&s->preout);
free_temp(&s->in_buffer);
swr_audio_convert_free(&s-> in_convert);
swr_audio_convert_free(&s->out_convert);
//We assume AVOptions checked the various values and the defaults where allowed
if( s->int_sample_fmt != AV_SAMPLE_FMT_S16
&&s->int_sample_fmt != AV_SAMPLE_FMT_FLT){
av_log(s, AV_LOG_ERROR, "Requested sample format %s is not supported internally, only float & S16 is supported\n", av_get_sample_fmt_name(s->int_sample_fmt));
return AVERROR(EINVAL);
}
//FIXME should we allow/support using FLT on material that doesnt need it ?
if(s->in_sample_fmt <= AV_SAMPLE_FMT_S16 || s->int_sample_fmt==AV_SAMPLE_FMT_S16){
s->int_sample_fmt= AV_SAMPLE_FMT_S16;
}else
s->int_sample_fmt= AV_SAMPLE_FMT_FLT;
if (s->out_sample_rate!=s->in_sample_rate || (s->flags & SWR_FLAG_RESAMPLE)){
s->resample = swr_resample_init(s->resample, s->out_sample_rate, s->in_sample_rate, 16, 10, 0, 0.8);
}else
swr_resample_free(&s->resample);
if(s->int_sample_fmt != AV_SAMPLE_FMT_S16 && s->resample){
av_log(s, AV_LOG_ERROR, "Resampling only supported with internal s16 currently\n"); //FIXME
return -1;
}
if(!s-> in_ch_layout)
s-> in_ch_layout= guess_layout(s->in.ch_count);
if(!s->out_ch_layout)
s->out_ch_layout= guess_layout(s->out.ch_count);
s->rematrix= s->out_ch_layout !=s->in_ch_layout;
#define RSC 1 //FIXME finetune
if(!s-> in.ch_count)
s-> in.ch_count= av_get_channel_layout_nb_channels(s-> in_ch_layout);
if(!s->out.ch_count)
s->out.ch_count= av_get_channel_layout_nb_channels(s->out_ch_layout);
av_assert0(s-> in.ch_count);
av_assert0(s->out.ch_count);
s->resample_first= RSC*s->out.ch_count/s->in.ch_count - RSC < s->out_sample_rate/(float)s-> in_sample_rate - 1.0;
s-> in.bps= av_get_bits_per_sample_fmt(s-> in_sample_fmt)/8;
s->int_bps= av_get_bits_per_sample_fmt(s->int_sample_fmt)/8;
s->out.bps= av_get_bits_per_sample_fmt(s->out_sample_fmt)/8;
s->in_convert = swr_audio_convert_alloc(s->int_sample_fmt,
s-> in_sample_fmt, s-> in.ch_count, 0);
s->out_convert= swr_audio_convert_alloc(s->out_sample_fmt,
s->int_sample_fmt, s->out.ch_count, 0);
s->postin= s->in;
s->preout= s->out;
s->midbuf= s->in;
s->in_buffer= s->in;
if(!s->resample_first){
s->midbuf.ch_count= s->out.ch_count;
s->in_buffer.ch_count = s->out.ch_count;
}
s->in_buffer.bps = s->postin.bps = s->midbuf.bps = s->preout.bps = s->int_bps;
s->in_buffer.planar = s->postin.planar = s->midbuf.planar = s->preout.planar = 1;
if(s->rematrix && swr_rematrix_init(s)<0)
return -1;
return 0;
}
static int realloc_audio(AudioData *a, int count){
int i, countb;
AudioData old;
if(a->count >= count)
return 0;
count*=2;
countb= FFALIGN(count*a->bps, 32);
old= *a;
av_assert0(a->planar);
av_assert0(a->bps);
av_assert0(a->ch_count);
a->data= av_malloc(countb*a->ch_count);
if(!a->data)
return AVERROR(ENOMEM);
for(i=0; i<a->ch_count; i++){
a->ch[i]= a->data + i*(a->planar ? countb : a->bps);
if(a->planar) memcpy(a->ch[i], old.ch[i], a->count*a->bps);
}
av_free(old.data);
a->count= count;
return 1;
}
static void copy(AudioData *out, AudioData *in,
int count){
av_assert0(out->planar == in->planar);
av_assert0(out->bps == in->bps);
av_assert0(out->ch_count == in->ch_count);
if(out->planar){
int ch;
for(ch=0; ch<out->ch_count; ch++)
memcpy(out->ch[ch], in->ch[ch], count*out->bps);
}else
memcpy(out->ch[0], in->ch[0], count*out->ch_count*out->bps);
}
int swr_convert(struct SwrContext *s, uint8_t *out_arg[SWR_CH_MAX], int out_count,
const uint8_t *in_arg [SWR_CH_MAX], int in_count){
AudioData *postin, *midbuf, *preout;
int ret, i/*, in_max*/;
AudioData * in= &s->in;
AudioData *out= &s->out;
AudioData preout_tmp, midbuf_tmp;
if(!s->resample){
if(in_count > out_count)
return -1;
out_count = in_count;
}
av_assert0(in ->planar == 0);
av_assert0(out->planar == 0);
for(i=0; i<s-> in.ch_count; i++)
in ->ch[i]= in_arg[0] + i* in->bps;
for(i=0; i<s->out.ch_count; i++)
out->ch[i]= out_arg[0] + i*out->bps;
// in_max= out_count*(int64_t)s->in_sample_rate / s->out_sample_rate + resample_filter_taps;
// in_count= FFMIN(in_count, in_in + 2 - s->hist_buffer_count);
if((ret=realloc_audio(&s->postin, in_count))<0)
return ret;
if(s->resample_first){
av_assert0(s->midbuf.ch_count == s-> in.ch_count);
if((ret=realloc_audio(&s->midbuf, out_count))<0)
return ret;
}else{
av_assert0(s->midbuf.ch_count == s->out.ch_count);
if((ret=realloc_audio(&s->midbuf, in_count))<0)
return ret;
}
if((ret=realloc_audio(&s->preout, out_count))<0)
return ret;
postin= &s->postin;
midbuf_tmp= s->midbuf;
midbuf= &midbuf_tmp;
preout_tmp= s->preout;
preout= &preout_tmp;
if(s->int_sample_fmt == s-> in_sample_fmt && s->in.planar)
postin= in;
if(s->resample_first ? !s->resample : !s->rematrix)
midbuf= postin;
if(s->resample_first ? !s->rematrix : !s->resample)
preout= midbuf;
if(s->int_sample_fmt == s->out_sample_fmt && s->out.planar){
if(preout==in){
out_count= FFMIN(out_count, in_count); //TODO check at teh end if this is needed or redundant
av_assert0(s->in.planar); //we only support planar internally so it has to be, we support copying non planar though
copy(out, in, out_count);
return out_count;
}
else if(preout==postin) preout= midbuf= postin= out;
else if(preout==midbuf) preout= midbuf= out;
else preout= out;
}
if(in != postin){
swr_audio_convert(s->in_convert, postin, in, in_count);
}
if(s->resample_first){
if(postin != midbuf)
out_count= resample(s, midbuf, out_count, postin, in_count);
if(midbuf != preout)
swr_rematrix(s, preout, midbuf, out_count, preout==out);
}else{
if(postin != midbuf)
swr_rematrix(s, midbuf, postin, in_count, midbuf==out);
if(midbuf != preout)
out_count= resample(s, preout, out_count, midbuf, in_count);
}
if(preout != out){
//FIXME packed doesnt need more than 1 chan here!
swr_audio_convert(s->out_convert, out, preout, out_count);
}
return out_count;
}
/**
*
* out may be equal in.
*/
static void buf_set(AudioData *out, AudioData *in, int count){
if(in->planar){
int ch;
for(ch=0; ch<out->ch_count; ch++)
out->ch[ch]= in->ch[ch] + count*out->bps;
}else
out->ch[0]= in->ch[0] + count*out->ch_count*out->bps;
}
/**
*
* @return number of samples output per channel
*/
static int resample(SwrContext *s, AudioData *out_param, int out_count,
const AudioData * in_param, int in_count){
AudioData in, out, tmp;
int ret_sum=0;
int border=0;
int ch_count= s->resample_first ? s->in.ch_count : s->out.ch_count;
tmp=out=*out_param;
in = *in_param;
do{
int ret, size, consumed;
if(!s->resample_in_constraint && s->in_buffer_count){
buf_set(&tmp, &s->in_buffer, s->in_buffer_index);
ret= swr_multiple_resample(s->resample, &out, out_count, &tmp, s->in_buffer_count, &consumed);
out_count -= ret;
ret_sum += ret;
buf_set(&out, &out, ret);
s->in_buffer_count -= consumed;
s->in_buffer_index += consumed;
if(!in_count)
break;
if(s->in_buffer_count <= border){
buf_set(&in, &in, -s->in_buffer_count);
in_count += s->in_buffer_count;
s->in_buffer_count=0;
s->in_buffer_index=0;
border = 0;
}
}
if(in_count && !s->in_buffer_count){
s->in_buffer_index=0;
ret= swr_multiple_resample(s->resample, &out, out_count, &in, in_count, &consumed);
out_count -= ret;
ret_sum += ret;
buf_set(&out, &out, ret);
in_count -= consumed;
buf_set(&in, &in, consumed);
}
//TODO is this check sane considering the advanced copy avoidance below
size= s->in_buffer_index + s->in_buffer_count + in_count;
if( size > s->in_buffer.count
&& s->in_buffer_count + in_count <= s->in_buffer_index){
buf_set(&tmp, &s->in_buffer, s->in_buffer_index);
copy(&s->in_buffer, &tmp, s->in_buffer_count);
s->in_buffer_index=0;
}else
if((ret=realloc_audio(&s->in_buffer, size)) < 0)
return ret;
if(in_count){
int count= in_count;
if(s->in_buffer_count && s->in_buffer_count+2 < count && out_count) count= s->in_buffer_count+2;
buf_set(&tmp, &s->in_buffer, s->in_buffer_index + s->in_buffer_count);
copy(&tmp, &in, /*in_*/count);
s->in_buffer_count += count;
in_count -= count;
border += count;
buf_set(&in, &in, count);
s->resample_in_constraint= 0;
if(s->in_buffer_count != count || in_count)
continue;
}
break;
}while(1);
s->resample_in_constraint= !!out_count;
return ret_sum;
}

@ -0,0 +1,79 @@
/*
* Copyright (C) 2011 Michael Niedermayer (michaelni@gmx.at)
*
* This file is part of libswresample
*
* libswresample is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libswresample is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libswresample; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef SWR_H
#define SWR_H
#include <inttypes.h>
#include "libavutil/samplefmt.h"
#define LIBSWRESAMPLE_VERSION_MAJOR 0
#define LIBSWRESAMPLE_VERSION_MINOR 0
#define LIBSWRESAMPLE_VERSION_MICRO 0
#define SWR_CH_MAX 16
#define SWR_FLAG_RESAMPLE 1///< Force resampling even if equal sample rate
//TODO use int resample ?
//long term TODO can we enable this dynamically?
struct SwrContext;
/**
* Allocate SwrContext.
* @see swr_init(),swr_free()
* @return NULL on error
*/
struct SwrContext *swr_alloc(void);
/**
* Initialize context after user parameters have been set.
* @return negativo n error
*/
int swr_init(struct SwrContext *s);
/**
* Allocate SwrContext.
* @see swr_init(),swr_free()
* @return NULL on error
*/
struct SwrContext *swr_alloc2(struct SwrContext *s, int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate,
int log_offset, void *log_ctx);
/**
* Free the given SwrContext.
* And set the pointer to NULL
*/
void swr_free(struct SwrContext **s);
/**
* Convert audio.
* @param in_count Number of input samples available in one channel.
* @param out_count Amount of space available for output in samples per channel.
* @return number of samples output per channel
*/
int swr_convert(struct SwrContext *s, uint8_t *out[SWR_CH_MAX], int out_count,
const uint8_t *in [SWR_CH_MAX], int in_count);
void swr_compensate(struct SwrContext *s, int sample_delta, int compensation_distance);
#endif

@ -0,0 +1,77 @@
/*
* Copyright (C) 2011 Michael Niedermayer (michaelni@gmx.at)
*
* This file is part of libswresample
*
* libswresample is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libswresample is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libswresample; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef SWR_INTERNAL_H
#define SWR_INTERNAL_H
#include "swresample.h"
typedef struct AudioData{
uint8_t *ch[SWR_CH_MAX];
uint8_t *data;
int ch_count;
int bps;
int count;
int planar;
} AudioData;
typedef struct SwrContext { //FIXME find unused fields
AVClass *av_class;
int log_level_offset;
void *log_ctx;
enum AVSampleFormat in_sample_fmt;
enum AVSampleFormat int_sample_fmt; ///<AV_SAMPLE_FMT_FLT OR AV_SAMPLE_FMT_S16
enum AVSampleFormat out_sample_fmt;
int64_t in_ch_layout;
int64_t out_ch_layout;
int in_sample_rate;
int out_sample_rate;
int flags;
float slev, clev;
//below are private
int int_bps;
int resample_first;
int rematrix; ///< flag to indicate if rematrixing is used
AudioData in, postin, midbuf, preout, out, in_buffer;
int in_buffer_index;
int in_buffer_count;
int resample_in_constraint;
struct AVAudioConvert *in_convert;
struct AVAudioConvert *out_convert;
struct AVResampleContext *resample;
float matrix[SWR_CH_MAX][SWR_CH_MAX];
uint8_t matrix_ch[SWR_CH_MAX][SWR_CH_MAX+1];
//TODO callbacks for asm optims
}SwrContext;
struct AVResampleContext *swr_resample_init(struct AVResampleContext *, int out_rate, int in_rate, int filter_size, int phase_shift, int linear, double cutoff);
void swr_resample_free(struct AVResampleContext **c);
int swr_multiple_resample(struct AVResampleContext *c, AudioData *dst, int dst_size, AudioData *src, int src_size, int *consumed);
void swr_resample_compensate(struct AVResampleContext *c, int sample_delta, int compensation_distance);
int swr_resample(struct AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx);
int swr_rematrix_init(SwrContext *s);
int swr_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy);
#endif

@ -0,0 +1,149 @@
/*
* Copyright (C) 2011 Michael Niedermayer (michaelni@gmx.at)
*
* This file is part of libswresample
*
* libswresample is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* libswresample is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libswresample; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/avassert.h"
#include "libavutil/common.h"
#include "libavutil/audioconvert.h"
#include "swresample.h"
#undef fprintf
#define SAMPLES 1000
#define ASSERT_LEVEL 2
static double get(const void *p, int index, enum AVSampleFormat f){
switch(f){
case AV_SAMPLE_FMT_U8 : return ((const uint8_t*)p)[index]/255.0*2-1.0;
case AV_SAMPLE_FMT_S16: return ((const int16_t*)p)[index]/32767.0;
case AV_SAMPLE_FMT_S32: return ((const int32_t*)p)[index]/2147483647.0;
case AV_SAMPLE_FMT_FLT: return ((const float *)p)[index];
case AV_SAMPLE_FMT_DBL: return ((const double *)p)[index];
default: av_assert2(0);
}
}
static void set(void *p, int index, enum AVSampleFormat f, double v){
switch(f){
case AV_SAMPLE_FMT_U8 : ((uint8_t*)p)[index]= (v+1.0)*255.0/2; break;
case AV_SAMPLE_FMT_S16: ((int16_t*)p)[index]= v*32767; break;
case AV_SAMPLE_FMT_S32: ((int32_t*)p)[index]= v*2147483647; break;
case AV_SAMPLE_FMT_FLT: ((float *)p)[index]= v; break;
case AV_SAMPLE_FMT_DBL: ((double *)p)[index]= v; break;
default: av_assert2(0);
}
}
uint64_t layouts[]={
AV_CH_LAYOUT_MONO ,
AV_CH_LAYOUT_STEREO ,
AV_CH_LAYOUT_2_1 ,
AV_CH_LAYOUT_SURROUND ,
AV_CH_LAYOUT_4POINT0 ,
AV_CH_LAYOUT_2_2 ,
AV_CH_LAYOUT_QUAD ,
AV_CH_LAYOUT_5POINT0 ,
AV_CH_LAYOUT_5POINT1 ,
AV_CH_LAYOUT_5POINT0_BACK ,
AV_CH_LAYOUT_5POINT1_BACK ,
AV_CH_LAYOUT_7POINT0 ,
AV_CH_LAYOUT_7POINT1 ,
AV_CH_LAYOUT_7POINT1_WIDE ,
0
};
int main(int argc, char **argv){
int in_sample_rate, out_sample_rate, ch ,i, in_ch_layout_index, out_ch_layout_index, osr;
uint64_t in_ch_layout, out_ch_layout;
enum AVSampleFormat in_sample_fmt, out_sample_fmt;
int sample_rates[]={8000,11025,16000,22050,32000};
uint8_t array_in[SAMPLES*8*8];
uint8_t array_mid[SAMPLES*8*8*3];
uint8_t array_out[SAMPLES*8*8+100];
struct SwrContext * forw_ctx= NULL;
struct SwrContext *backw_ctx= NULL;
in_sample_rate=16000;
for(osr=0; osr<5; osr++){
out_sample_rate= sample_rates[osr];
for(in_sample_fmt= AV_SAMPLE_FMT_U8; in_sample_fmt<=AV_SAMPLE_FMT_DBL; in_sample_fmt++){
for(out_sample_fmt= AV_SAMPLE_FMT_U8; out_sample_fmt<=AV_SAMPLE_FMT_DBL; out_sample_fmt++){
for(in_ch_layout_index=0; layouts[in_ch_layout_index]; in_ch_layout_index++){
in_ch_layout= layouts[in_ch_layout_index];
int in_ch_count= av_get_channel_layout_nb_channels(in_ch_layout);
for(out_ch_layout_index=0; layouts[out_ch_layout_index]; out_ch_layout_index++){
int out_count, mid_count;
out_ch_layout= layouts[out_ch_layout_index];
int out_ch_count= av_get_channel_layout_nb_channels(out_ch_layout);
fprintf(stderr, "ch %d->%d, rate:%5d->%5d, fmt:%s->%s",
in_ch_count, out_ch_count,
in_sample_rate, out_sample_rate,
av_get_sample_fmt_name(in_sample_fmt), av_get_sample_fmt_name(out_sample_fmt));
forw_ctx = swr_alloc2(forw_ctx, out_ch_layout, out_sample_fmt, out_sample_rate,
in_ch_layout, in_sample_fmt, in_sample_rate, 0, 0);
backw_ctx = swr_alloc2(backw_ctx,in_ch_layout, in_sample_fmt, in_sample_rate,
out_ch_layout, out_sample_fmt, out_sample_rate, 0, 0);
if(swr_init( forw_ctx) < 0)
fprintf(stderr, "swr_init(->) failed\n");
if(swr_init(backw_ctx) < 0)
fprintf(stderr, "swr_init(<-) failed\n");
if(!forw_ctx)
fprintf(stderr, "Failed to init forw_cts\n");
if(!backw_ctx)
fprintf(stderr, "Failed to init backw_ctx\n");
//FIXME test planar
for(ch=0; ch<in_ch_count; ch++){
for(i=0; i<SAMPLES; i++)
set(array_in, ch + i*in_ch_count, in_sample_fmt, sin(i*i*3/SAMPLES));
}
mid_count= swr_convert(forw_ctx, ( uint8_t*[]){array_mid}, 3*SAMPLES,
(const uint8_t*[]){array_in }, SAMPLES);
out_count= swr_convert(backw_ctx,( uint8_t*[]){array_out}, 3*SAMPLES,
(const uint8_t*[]){array_mid}, mid_count);
for(ch=0; ch<in_ch_count; ch++){
double sse, x, maxdiff=0;
double sum_a= 0;
double sum_b= 0;
double sum_aa= 0;
double sum_bb= 0;
double sum_ab= 0;
for(i=0; i<SAMPLES; i++){
double a= get(array_in , ch + i*in_ch_count, in_sample_fmt);
double b= get(array_out, ch + i*in_ch_count, in_sample_fmt);
sum_a += a;
sum_b += b;
sum_aa+= a*a;
sum_bb+= b*b;
sum_ab+= a*b;
maxdiff= FFMAX(maxdiff, FFABS(a-b));
}
x = sum_ab/sum_bb;
sse= sum_aa + sum_bb*x*x - 2*x*sum_ab;
fprintf(stderr, "[%f %f %f] len:%5d\n", sqrt(sse/SAMPLES), x, maxdiff, out_count);
}
fprintf(stderr, "\n");
}
}
}
}
}
return 0;
}

@ -1,4 +1,4 @@
fd090ddf05cc3401cc75c4a5ace1d05a *./tests/data/acodec/g726.wav a76fc937faac62c5de057cd69191732a *./tests/data/acodec/g726.wav
24052 ./tests/data/acodec/g726.wav 24052 ./tests/data/acodec/g726.wav
74abea06027375111eeac1b2f8c7d3af *./tests/data/g726.acodec.out.wav 124de13e6cb5af64ea8758aa49feb7fc *./tests/data/g726.acodec.out.wav
stddev: 8554.55 PSNR: 17.69 MAXDIFF:29353 bytes: 95984/ 1058400 stddev: 8554.23 PSNR: 17.69 MAXDIFF:29353 bytes: 95984/ 1058400

@ -66,7 +66,7 @@ stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
529256 ./tests/data/acodec/pcm_zork.wav 529256 ./tests/data/acodec/pcm_zork.wav
864c8c866ac25642c29a13b122c70709 *./tests/data/pcm.acodec.out.wav 864c8c866ac25642c29a13b122c70709 *./tests/data/pcm.acodec.out.wav
stddev: 633.11 PSNR: 40.30 MAXDIFF:32768 bytes: 1058400/ 1058400 stddev: 633.11 PSNR: 40.30 MAXDIFF:32768 bytes: 1058400/ 1058400
8168a5c1343553ef027541830f2cb879 *./tests/data/acodec/pcm_s24daud.302 1b75d5198ae789ab3c48f7024e08f4a9 *./tests/data/acodec/pcm_s24daud.302
10368730 ./tests/data/acodec/pcm_s24daud.302 10368730 ./tests/data/acodec/pcm_s24daud.302
f552afadfdfcd6348a07095da6382de5 *./tests/data/pcm.acodec.out.wav 4708f86529c594e29404603c64bb208c *./tests/data/pcm.acodec.out.wav
stddev: 9416.28 PSNR: 16.85 MAXDIFF:42744 bytes: 6911796/ 1058400 stddev: 8967.92 PSNR: 17.28 MAXDIFF:42548 bytes: 6911796/ 1058400

@ -1,3 +1,3 @@
188f804bd2d10cd436c8a7b111bdcd2a *./tests/data/lavf/lavf.dv 6e716216d5f9e3819db8eb8796de9129 *./tests/data/lavf/lavf.dv
3600000 ./tests/data/lavf/lavf.dv 3600000 ./tests/data/lavf/lavf.dv
./tests/data/lavf/lavf.dv CRC=0x02c0af30 ./tests/data/lavf/lavf.dv CRC=0x92d1e3f0

@ -1,3 +1,3 @@
b3174e2db508564c1cce0b5e3c1bc1bd *./tests/data/lavf/lavf.mxf_d10 8eb67301f72f2b5860fafab422b920ad *./tests/data/lavf/lavf.mxf_d10
5330989 ./tests/data/lavf/lavf.mxf_d10 5330989 ./tests/data/lavf/lavf.mxf_d10
./tests/data/lavf/lavf.mxf_d10 CRC=0xc3f4f92e ./tests/data/lavf/lavf.mxf_d10 CRC=0x96c02dfd

Loading…
Cancel
Save