aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2011-09-19 06:13:30 +0200
committerMichael Niedermayer <michaelni@gmx.at>2011-09-19 07:04:17 +0200
commitb5875b91113a0f3de6ad61e9ff8b74b81de94760 (patch)
treeb33f19a81ebe0d3145368f0d6494f4f4aab75aba
parent53e37840bf205a24c3b3ad6d838805dc54a905bf (diff)
downloadffmpeg-b5875b91113a0f3de6ad61e9ff8b74b81de94760.tar.gz
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>
-rw-r--r--Makefile1
-rw-r--r--common.mak2
-rwxr-xr-xconfigure7
-rw-r--r--ffmpeg.c83
-rw-r--r--libswresample/Makefile12
-rw-r--r--libswresample/audioconvert.c113
-rw-r--r--libswresample/audioconvert.h65
-rw-r--r--libswresample/rematrix.c271
-rw-r--r--libswresample/rematrix_template.c38
-rw-r--r--libswresample/resample2.c352
-rw-r--r--libswresample/swresample.c432
-rw-r--r--libswresample/swresample.h79
-rw-r--r--libswresample/swresample_internal.h77
-rw-r--r--libswresample/swresample_test.c149
-rw-r--r--tests/ref/acodec/g7266
-rw-r--r--tests/ref/acodec/pcm6
-rw-r--r--tests/ref/lavf/dv_fmt4
-rw-r--r--tests/ref/lavf/mxf_d104
18 files changed, 1634 insertions, 67 deletions
diff --git a/Makefile b/Makefile
index 27b841f348..167dd3210e 100644
--- a/Makefile
+++ b/Makefile
@@ -33,6 +33,7 @@ FFLIBS-$(CONFIG_AVFILTER) += avfilter
FFLIBS-$(CONFIG_AVFORMAT) += avformat
FFLIBS-$(CONFIG_AVCODEC) += avcodec
FFLIBS-$(CONFIG_POSTPROC) += postproc
+FFLIBS-$(CONFIG_SWRESAMPLE)+= swresample
FFLIBS-$(CONFIG_SWSCALE) += swscale
FFLIBS := avutil
diff --git a/common.mak b/common.mak
index bad86fde3b..8dd24396d2 100644
--- a/common.mak
+++ b/common.mak
@@ -20,7 +20,7 @@ $(foreach VAR,$(SILENT),$(eval override $(VAR) = @$($(VAR))))
$(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL))
endif
-ALLFFLIBS = avcodec avdevice avfilter avformat avutil postproc swscale
+ALLFFLIBS = avcodec avdevice avfilter avformat avutil postproc swscale swresample
# NASM requires -I path terminated with /
IFLAGS := -I. -I$(SRC_PATH)/
diff --git a/configure b/configure
index 4cdb4916ce..dfc8ee3863 100755
--- a/configure
+++ b/configure
@@ -89,6 +89,7 @@ Configuration options:
--disable-avdevice disable libavdevice build
--disable-avcodec disable libavcodec build
--disable-avformat disable libavformat build
+ --disable-swresample disable libswresample build
--disable-swscale disable libswscale build
--disable-postproc disable libpostproc build
--disable-avfilter disable video filter support [no]
@@ -1037,6 +1038,7 @@ CONFIG_LIST="
small
sram
static
+ swresample
swscale
swscale_alpha
thumb
@@ -1603,7 +1605,7 @@ avformat_deps="avcodec"
postproc_deps="gpl"
# programs
-ffmpeg_deps="avcodec avformat swscale"
+ffmpeg_deps="avcodec avformat swscale swresample"
ffmpeg_select="buffer_filter buffersink_filter"
avconv_deps="avcodec avformat swscale"
avconv_select="buffer_filter"
@@ -1766,6 +1768,7 @@ enable postproc
enable protocols
enable static
enable stripping
+enable swresample
enable swscale
enable swscale_alpha
@@ -3143,7 +3146,7 @@ enabled extra_warnings && check_cflags -Winline
# add some linker flags
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
echo "X{};" > $TMPV
diff --git a/ffmpeg.c b/ffmpeg.c
index b887abd7f5..6da97d24ae 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -45,6 +45,7 @@
#include "libavutil/avstring.h"
#include "libavutil/libm.h"
#include "libavformat/os_support.h"
+#include "libswresample/swresample.h"
#include "libavformat/ffm.h" // not public API
@@ -229,15 +230,14 @@ typedef struct OutputStream {
/* audio only */
int audio_resample;
- ReSampleContext *resample; /* for audio resampling */
int resample_sample_fmt;
int resample_channels;
int resample_sample_rate;
- int reformat_pair;
- AVAudioConvert *reformat_ctx;
AVFifoBuffer *fifo; /* for compression: one audio fifo per codec */
FILE *logfile;
+ struct SwrContext *swr;
+
#if CONFIG_AVFILTER
AVFilterContext *output_video_filter;
AVFilterContext *input_video_filter;
@@ -843,14 +843,15 @@ need_realloc:
exit_program(1);
}
- if (enc->channels != dec->channels)
+ if (enc->channels != dec->channels
+ || enc->sample_fmt != dec->sample_fmt)
ost->audio_resample = 1;
resample_changed = ost->resample_sample_fmt != dec->sample_fmt ||
ost->resample_channels != dec->channels ||
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) {
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,
@@ -859,24 +860,29 @@ need_realloc:
ost->resample_sample_fmt = dec->sample_fmt;
ost->resample_channels = dec->channels;
ost->resample_sample_rate = dec->sample_rate;
- if (ost->resample)
- audio_resample_close(ost->resample);
+ swr_free(&ost->swr);
}
/* if audio_sync_method is >1 the resampler is needed for audio drift compensation */
if (audio_sync_method <= 1 &&
ost->resample_sample_fmt == enc->sample_fmt &&
ost->resample_channels == enc->channels &&
ost->resample_sample_rate == enc->sample_rate) {
- ost->resample = NULL;
+ //ost->swr = NULL;
ost->audio_resample = 0;
} else {
- if (dec->sample_fmt != AV_SAMPLE_FMT_S16)
- fprintf(stderr, "Warning, using s16 intermediate sample format for resampling\n");
- ost->resample = av_audio_resample_init(enc->channels, dec->channels,
- enc->sample_rate, dec->sample_rate,
- enc->sample_fmt, dec->sample_fmt,
- 16, 10, 0, 0.8);
- if (!ost->resample) {
+ ost->swr = swr_alloc2(ost->swr,
+ enc->channel_layout, enc->sample_fmt, enc->sample_rate,
+ dec->channel_layout, dec->sample_fmt, dec->sample_rate,
+ 0, NULL);
+ av_set_int(ost->swr, "ich", dec->channels);
+ av_set_int(ost->swr, "och", enc->channels);
+ 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",
dec->channels, dec->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))
- 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);
- }
+ av_assert0(ost->audio_resample || dec->sample_fmt==enc->sample_fmt);
if(audio_sync_method){
double delta = get_sync_ipts(ost) * enc->sample_rate - ost->sync_opts
@@ -941,7 +933,7 @@ need_realloc:
if(verbose > 2)
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));
- av_resample_compensate(*(struct AVResampleContext**)ost->resample, comp, enc->sample_rate);
+ swr_compensate(ost->swr, comp, enc->sample_rate);
}
}
}else
@@ -950,30 +942,15 @@ need_realloc:
if (ost->audio_resample) {
buftmp = audio_buf;
- size_out = audio_resample(ost->resample,
- (short *)buftmp, (short *)buf,
- size / (dec->channels * isize));
+ size_out = swr_convert(ost->swr, ( uint8_t*[]){buftmp}, audio_buf_size / (enc->channels * osize),
+ (const uint8_t*[]){buf }, size / (dec->channels * isize));
size_out = size_out * enc->channels * osize;
} else {
buftmp = buf;
size_out = size;
}
- if (!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;
- }
+ av_assert0(ost->audio_resample || dec->sample_fmt==enc->sample_fmt);
/* now encode as many frames as possible */
if (enc->frame_size > 1) {
@@ -2133,7 +2110,6 @@ static int transcode_init(OutputFile *output_files, int nb_output_files,
if (!ost->fifo) {
return AVERROR(ENOMEM);
}
- ost->reformat_pair = MAKE_SFMT_PAIR(AV_SAMPLE_FMT_NONE,AV_SAMPLE_FMT_NONE);
if (!codec->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)
codec->channel_layout = 0;
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;
ist->decoding_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);
if (ost->video_resample)
sws_freeContext(ost->img_resample_ctx);
- if (ost->resample)
- audio_resample_close(ost->resample);
- if (ost->reformat_ctx)
- av_audio_convert_free(ost->reformat_ctx);
+ swr_free(&ost->swr);
av_dict_free(&ost->opts);
}
}
diff --git a/libswresample/Makefile b/libswresample/Makefile
new file mode 100644
index 0000000000..33b8ea0c58
--- /dev/null
+++ b/libswresample/Makefile
@@ -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
diff --git a/libswresample/audioconvert.c b/libswresample/audioconvert.c
new file mode 100644
index 0000000000..a1fa3eb10c
--- /dev/null
+++ b/libswresample/audioconvert.c
@@ -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;
+}
diff --git a/libswresample/audioconvert.h b/libswresample/audioconvert.h
new file mode 100644
index 0000000000..e5fd4dfd80
--- /dev/null
+++ b/libswresample/audioconvert.h
@@ -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 */
diff --git a/libswresample/rematrix.c b/libswresample/rematrix.c
new file mode 100644
index 0000000000..b8c5d45327
--- /dev/null
+++ b/libswresample/rematrix.c
@@ -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;
+}
diff --git a/libswresample/rematrix_template.c b/libswresample/rematrix_template.c
new file mode 100644
index 0000000000..5d5aef2ca8
--- /dev/null
+++ b/libswresample/rematrix_template.c
@@ -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
+ }
+}
+
diff --git a/libswresample/resample2.c b/libswresample/resample2.c
new file mode 100644
index 0000000000..8623877c7c
--- /dev/null
+++ b/libswresample/resample2.c
@@ -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;
+}
diff --git a/libswresample/swresample.c b/libswresample/swresample.c
new file mode 100644
index 0000000000..db2d1df8f8
--- /dev/null
+++ b/libswresample/swresample.c
@@ -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;
+}
diff --git a/libswresample/swresample.h b/libswresample/swresample.h
new file mode 100644
index 0000000000..05c4f6dc01
--- /dev/null
+++ b/libswresample/swresample.h
@@ -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
diff --git a/libswresample/swresample_internal.h b/libswresample/swresample_internal.h
new file mode 100644
index 0000000000..17a93d8dc9
--- /dev/null
+++ b/libswresample/swresample_internal.h
@@ -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
diff --git a/libswresample/swresample_test.c b/libswresample/swresample_test.c
new file mode 100644
index 0000000000..b6341517ca
--- /dev/null
+++ b/libswresample/swresample_test.c
@@ -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;
+}
diff --git a/tests/ref/acodec/g726 b/tests/ref/acodec/g726
index d2dbe5048c..32e1a48b31 100644
--- a/tests/ref/acodec/g726
+++ b/tests/ref/acodec/g726
@@ -1,4 +1,4 @@
-fd090ddf05cc3401cc75c4a5ace1d05a *./tests/data/acodec/g726.wav
+a76fc937faac62c5de057cd69191732a *./tests/data/acodec/g726.wav
24052 ./tests/data/acodec/g726.wav
-74abea06027375111eeac1b2f8c7d3af *./tests/data/g726.acodec.out.wav
-stddev: 8554.55 PSNR: 17.69 MAXDIFF:29353 bytes: 95984/ 1058400
+124de13e6cb5af64ea8758aa49feb7fc *./tests/data/g726.acodec.out.wav
+stddev: 8554.23 PSNR: 17.69 MAXDIFF:29353 bytes: 95984/ 1058400
diff --git a/tests/ref/acodec/pcm b/tests/ref/acodec/pcm
index fc9dd8f29d..5c828b171b 100644
--- a/tests/ref/acodec/pcm
+++ b/tests/ref/acodec/pcm
@@ -66,7 +66,7 @@ stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
529256 ./tests/data/acodec/pcm_zork.wav
864c8c866ac25642c29a13b122c70709 *./tests/data/pcm.acodec.out.wav
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
-f552afadfdfcd6348a07095da6382de5 *./tests/data/pcm.acodec.out.wav
-stddev: 9416.28 PSNR: 16.85 MAXDIFF:42744 bytes: 6911796/ 1058400
+4708f86529c594e29404603c64bb208c *./tests/data/pcm.acodec.out.wav
+stddev: 8967.92 PSNR: 17.28 MAXDIFF:42548 bytes: 6911796/ 1058400
diff --git a/tests/ref/lavf/dv_fmt b/tests/ref/lavf/dv_fmt
index f39ff39bf0..7450720f1f 100644
--- a/tests/ref/lavf/dv_fmt
+++ b/tests/ref/lavf/dv_fmt
@@ -1,3 +1,3 @@
-188f804bd2d10cd436c8a7b111bdcd2a *./tests/data/lavf/lavf.dv
+6e716216d5f9e3819db8eb8796de9129 *./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
diff --git a/tests/ref/lavf/mxf_d10 b/tests/ref/lavf/mxf_d10
index 2582022d17..1e0ee2ecf8 100644
--- a/tests/ref/lavf/mxf_d10
+++ b/tests/ref/lavf/mxf_d10
@@ -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
-./tests/data/lavf/lavf.mxf_d10 CRC=0xc3f4f92e
+./tests/data/lavf/lavf.mxf_d10 CRC=0x96c02dfd