Add libswresample.
authorMichael Niedermayer <michaelni@gmx.at>
Mon, 19 Sep 2011 04:13:30 +0000 (06:13 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Mon, 19 Sep 2011 05:04:17 +0000 (07:04 +0200)
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>
18 files changed:
Makefile
common.mak
configure
ffmpeg.c
libswresample/Makefile [new file with mode: 0644]
libswresample/audioconvert.c [new file with mode: 0644]
libswresample/audioconvert.h [new file with mode: 0644]
libswresample/rematrix.c [new file with mode: 0644]
libswresample/rematrix_template.c [new file with mode: 0644]
libswresample/resample2.c [new file with mode: 0644]
libswresample/swresample.c [new file with mode: 0644]
libswresample/swresample.h [new file with mode: 0644]
libswresample/swresample_internal.h [new file with mode: 0644]
libswresample/swresample_test.c [new file with mode: 0644]
tests/ref/acodec/g726
tests/ref/acodec/pcm
tests/ref/lavf/dv_fmt
tests/ref/lavf/mxf_d10

index 27b841f..167dd32 100644 (file)
--- 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
index bad86fd..8dd2439 100644 (file)
@@ -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)/
index 4cdb491..dfc8ee3 100755 (executable)
--- 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
index b887abd..6da97d2 100644 (file)
--- 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 (file)
index 0000000..33b8ea0
--- /dev/null
@@ -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 (file)
index 0000000..a1fa3eb
--- /dev/null
@@ -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 (file)
index 0000000..e5fd4df
--- /dev/null
@@ -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 (file)
index 0000000..b8c5d45
--- /dev/null
@@ -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 (file)
index 0000000..5d5aef2
--- /dev/null
@@ -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 (file)
index 0000000..8623877
--- /dev/null
@@ -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 (file)
index 0000000..db2d1df
--- /dev/null
@@ -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 (file)
index 0000000..05c4f6d
--- /dev/null
@@ -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 (file)
index 0000000..17a93d8
--- /dev/null
@@ -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 (file)
index 0000000..b634151
--- /dev/null
@@ -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;
+}
index d2dbe50..32e1a48 100644 (file)
@@ -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
index fc9dd8f..5c828b1 100644 (file)
@@ -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
index f39ff39..7450720 100644 (file)
@@ -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
index 2582022..1e0ee2e 100644 (file)
@@ -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