Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
Michael Niedermayer authored on 2011/09/19 13:13:30... | ... |
@@ -33,6 +33,7 @@ FFLIBS-$(CONFIG_AVFILTER) += avfilter |
33 | 33 |
FFLIBS-$(CONFIG_AVFORMAT) += avformat |
34 | 34 |
FFLIBS-$(CONFIG_AVCODEC) += avcodec |
35 | 35 |
FFLIBS-$(CONFIG_POSTPROC) += postproc |
36 |
+FFLIBS-$(CONFIG_SWRESAMPLE)+= swresample |
|
36 | 37 |
FFLIBS-$(CONFIG_SWSCALE) += swscale |
37 | 38 |
|
38 | 39 |
FFLIBS := avutil |
... | ... |
@@ -20,7 +20,7 @@ $(foreach VAR,$(SILENT),$(eval override $(VAR) = @$($(VAR)))) |
20 | 20 |
$(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL)) |
21 | 21 |
endif |
22 | 22 |
|
23 |
-ALLFFLIBS = avcodec avdevice avfilter avformat avutil postproc swscale |
|
23 |
+ALLFFLIBS = avcodec avdevice avfilter avformat avutil postproc swscale swresample |
|
24 | 24 |
|
25 | 25 |
# NASM requires -I path terminated with / |
26 | 26 |
IFLAGS := -I. -I$(SRC_PATH)/ |
... | ... |
@@ -89,6 +89,7 @@ Configuration options: |
89 | 89 |
--disable-avdevice disable libavdevice build |
90 | 90 |
--disable-avcodec disable libavcodec build |
91 | 91 |
--disable-avformat disable libavformat build |
92 |
+ --disable-swresample disable libswresample build |
|
92 | 93 |
--disable-swscale disable libswscale build |
93 | 94 |
--disable-postproc disable libpostproc build |
94 | 95 |
--disable-avfilter disable video filter support [no] |
... | ... |
@@ -1037,6 +1038,7 @@ CONFIG_LIST=" |
1037 | 1037 |
small |
1038 | 1038 |
sram |
1039 | 1039 |
static |
1040 |
+ swresample |
|
1040 | 1041 |
swscale |
1041 | 1042 |
swscale_alpha |
1042 | 1043 |
thumb |
... | ... |
@@ -1603,7 +1605,7 @@ avformat_deps="avcodec" |
1603 | 1603 |
postproc_deps="gpl" |
1604 | 1604 |
|
1605 | 1605 |
# programs |
1606 |
-ffmpeg_deps="avcodec avformat swscale" |
|
1606 |
+ffmpeg_deps="avcodec avformat swscale swresample" |
|
1607 | 1607 |
ffmpeg_select="buffer_filter buffersink_filter" |
1608 | 1608 |
avconv_deps="avcodec avformat swscale" |
1609 | 1609 |
avconv_select="buffer_filter" |
... | ... |
@@ -1766,6 +1768,7 @@ enable postproc |
1766 | 1766 |
enable protocols |
1767 | 1767 |
enable static |
1768 | 1768 |
enable stripping |
1769 |
+enable swresample |
|
1769 | 1770 |
enable swscale |
1770 | 1771 |
enable swscale_alpha |
1771 | 1772 |
|
... | ... |
@@ -3143,7 +3146,7 @@ enabled extra_warnings && check_cflags -Winline |
3143 | 3143 |
|
3144 | 3144 |
# add some linker flags |
3145 | 3145 |
check_ldflags -Wl,--warn-common |
3146 |
-check_ldflags -Wl,-rpath-link=libpostproc:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil |
|
3146 |
+check_ldflags -Wl,-rpath-link=libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil |
|
3147 | 3147 |
test_ldflags -Wl,-Bsymbolic && append SHFLAGS -Wl,-Bsymbolic |
3148 | 3148 |
|
3149 | 3149 |
echo "X{};" > $TMPV |
... | ... |
@@ -45,6 +45,7 @@ |
45 | 45 |
#include "libavutil/avstring.h" |
46 | 46 |
#include "libavutil/libm.h" |
47 | 47 |
#include "libavformat/os_support.h" |
48 |
+#include "libswresample/swresample.h" |
|
48 | 49 |
|
49 | 50 |
#include "libavformat/ffm.h" // not public API |
50 | 51 |
|
... | ... |
@@ -229,15 +230,14 @@ typedef struct OutputStream { |
229 | 229 |
|
230 | 230 |
/* audio only */ |
231 | 231 |
int audio_resample; |
232 |
- ReSampleContext *resample; /* for audio resampling */ |
|
233 | 232 |
int resample_sample_fmt; |
234 | 233 |
int resample_channels; |
235 | 234 |
int resample_sample_rate; |
236 |
- int reformat_pair; |
|
237 |
- AVAudioConvert *reformat_ctx; |
|
238 | 235 |
AVFifoBuffer *fifo; /* for compression: one audio fifo per codec */ |
239 | 236 |
FILE *logfile; |
240 | 237 |
|
238 |
+ struct SwrContext *swr; |
|
239 |
+ |
|
241 | 240 |
#if CONFIG_AVFILTER |
242 | 241 |
AVFilterContext *output_video_filter; |
243 | 242 |
AVFilterContext *input_video_filter; |
... | ... |
@@ -843,14 +843,15 @@ need_realloc: |
843 | 843 |
exit_program(1); |
844 | 844 |
} |
845 | 845 |
|
846 |
- if (enc->channels != dec->channels) |
|
846 |
+ if (enc->channels != dec->channels |
|
847 |
+ || enc->sample_fmt != dec->sample_fmt) |
|
847 | 848 |
ost->audio_resample = 1; |
848 | 849 |
|
849 | 850 |
resample_changed = ost->resample_sample_fmt != dec->sample_fmt || |
850 | 851 |
ost->resample_channels != dec->channels || |
851 | 852 |
ost->resample_sample_rate != dec->sample_rate; |
852 | 853 |
|
853 |
- if ((ost->audio_resample && !ost->resample) || resample_changed) { |
|
854 |
+ if ((ost->audio_resample && !ost->swr) || resample_changed) { |
|
854 | 855 |
if (resample_changed) { |
855 | 856 |
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", |
856 | 857 |
ist->file_index, ist->st->index, |
... | ... |
@@ -859,24 +860,29 @@ need_realloc: |
859 | 859 |
ost->resample_sample_fmt = dec->sample_fmt; |
860 | 860 |
ost->resample_channels = dec->channels; |
861 | 861 |
ost->resample_sample_rate = dec->sample_rate; |
862 |
- if (ost->resample) |
|
863 |
- audio_resample_close(ost->resample); |
|
862 |
+ swr_free(&ost->swr); |
|
864 | 863 |
} |
865 | 864 |
/* if audio_sync_method is >1 the resampler is needed for audio drift compensation */ |
866 | 865 |
if (audio_sync_method <= 1 && |
867 | 866 |
ost->resample_sample_fmt == enc->sample_fmt && |
868 | 867 |
ost->resample_channels == enc->channels && |
869 | 868 |
ost->resample_sample_rate == enc->sample_rate) { |
870 |
- ost->resample = NULL; |
|
869 |
+ //ost->swr = NULL; |
|
871 | 870 |
ost->audio_resample = 0; |
872 | 871 |
} else { |
873 |
- if (dec->sample_fmt != AV_SAMPLE_FMT_S16) |
|
874 |
- fprintf(stderr, "Warning, using s16 intermediate sample format for resampling\n"); |
|
875 |
- ost->resample = av_audio_resample_init(enc->channels, dec->channels, |
|
876 |
- enc->sample_rate, dec->sample_rate, |
|
877 |
- enc->sample_fmt, dec->sample_fmt, |
|
878 |
- 16, 10, 0, 0.8); |
|
879 |
- if (!ost->resample) { |
|
872 |
+ ost->swr = swr_alloc2(ost->swr, |
|
873 |
+ enc->channel_layout, enc->sample_fmt, enc->sample_rate, |
|
874 |
+ dec->channel_layout, dec->sample_fmt, dec->sample_rate, |
|
875 |
+ 0, NULL); |
|
876 |
+ av_set_int(ost->swr, "ich", dec->channels); |
|
877 |
+ av_set_int(ost->swr, "och", enc->channels); |
|
878 |
+ if(audio_sync_method>1) av_set_int(ost->swr, "flags", SWR_FLAG_RESAMPLE); |
|
879 |
+ if(ost->swr && swr_init(ost->swr) < 0){ |
|
880 |
+ fprintf(stderr, "swr_init() failed\n"); |
|
881 |
+ swr_free(&ost->swr); |
|
882 |
+ } |
|
883 |
+ |
|
884 |
+ if (!ost->swr) { |
|
880 | 885 |
fprintf(stderr, "Can not resample %d channels @ %d Hz to %d channels @ %d Hz\n", |
881 | 886 |
dec->channels, dec->sample_rate, |
882 | 887 |
enc->channels, enc->sample_rate); |
... | ... |
@@ -885,21 +891,7 @@ need_realloc: |
885 | 885 |
} |
886 | 886 |
} |
887 | 887 |
|
888 |
-#define MAKE_SFMT_PAIR(a,b) ((a)+AV_SAMPLE_FMT_NB*(b)) |
|
889 |
- if (!ost->audio_resample && dec->sample_fmt!=enc->sample_fmt && |
|
890 |
- MAKE_SFMT_PAIR(enc->sample_fmt,dec->sample_fmt)!=ost->reformat_pair) { |
|
891 |
- if (ost->reformat_ctx) |
|
892 |
- av_audio_convert_free(ost->reformat_ctx); |
|
893 |
- ost->reformat_ctx = av_audio_convert_alloc(enc->sample_fmt, 1, |
|
894 |
- dec->sample_fmt, 1, NULL, 0); |
|
895 |
- if (!ost->reformat_ctx) { |
|
896 |
- fprintf(stderr, "Cannot convert %s sample format to %s sample format\n", |
|
897 |
- av_get_sample_fmt_name(dec->sample_fmt), |
|
898 |
- av_get_sample_fmt_name(enc->sample_fmt)); |
|
899 |
- exit_program(1); |
|
900 |
- } |
|
901 |
- ost->reformat_pair=MAKE_SFMT_PAIR(enc->sample_fmt,dec->sample_fmt); |
|
902 |
- } |
|
888 |
+ av_assert0(ost->audio_resample || dec->sample_fmt==enc->sample_fmt); |
|
903 | 889 |
|
904 | 890 |
if(audio_sync_method){ |
905 | 891 |
double delta = get_sync_ipts(ost) * enc->sample_rate - ost->sync_opts |
... | ... |
@@ -941,7 +933,7 @@ need_realloc: |
941 | 941 |
if(verbose > 2) |
942 | 942 |
fprintf(stderr, "compensating audio timestamp drift:%f compensation:%d in:%d\n", delta, comp, enc->sample_rate); |
943 | 943 |
// 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)); |
944 |
- av_resample_compensate(*(struct AVResampleContext**)ost->resample, comp, enc->sample_rate); |
|
944 |
+ swr_compensate(ost->swr, comp, enc->sample_rate); |
|
945 | 945 |
} |
946 | 946 |
} |
947 | 947 |
}else |
... | ... |
@@ -950,30 +942,15 @@ need_realloc: |
950 | 950 |
|
951 | 951 |
if (ost->audio_resample) { |
952 | 952 |
buftmp = audio_buf; |
953 |
- size_out = audio_resample(ost->resample, |
|
954 |
- (short *)buftmp, (short *)buf, |
|
955 |
- size / (dec->channels * isize)); |
|
953 |
+ size_out = swr_convert(ost->swr, ( uint8_t*[]){buftmp}, audio_buf_size / (enc->channels * osize), |
|
954 |
+ (const uint8_t*[]){buf }, size / (dec->channels * isize)); |
|
956 | 955 |
size_out = size_out * enc->channels * osize; |
957 | 956 |
} else { |
958 | 957 |
buftmp = buf; |
959 | 958 |
size_out = size; |
960 | 959 |
} |
961 | 960 |
|
962 |
- if (!ost->audio_resample && dec->sample_fmt!=enc->sample_fmt) { |
|
963 |
- const void *ibuf[6]= {buftmp}; |
|
964 |
- void *obuf[6]= {audio_buf}; |
|
965 |
- int istride[6]= {isize}; |
|
966 |
- int ostride[6]= {osize}; |
|
967 |
- int len= size_out/istride[0]; |
|
968 |
- if (av_audio_convert(ost->reformat_ctx, obuf, ostride, ibuf, istride, len)<0) { |
|
969 |
- printf("av_audio_convert() failed\n"); |
|
970 |
- if (exit_on_error) |
|
971 |
- exit_program(1); |
|
972 |
- return; |
|
973 |
- } |
|
974 |
- buftmp = audio_buf; |
|
975 |
- size_out = len*osize; |
|
976 |
- } |
|
961 |
+ av_assert0(ost->audio_resample || dec->sample_fmt==enc->sample_fmt); |
|
977 | 962 |
|
978 | 963 |
/* now encode as many frames as possible */ |
979 | 964 |
if (enc->frame_size > 1) { |
... | ... |
@@ -2133,7 +2110,6 @@ static int transcode_init(OutputFile *output_files, int nb_output_files, |
2133 | 2133 |
if (!ost->fifo) { |
2134 | 2134 |
return AVERROR(ENOMEM); |
2135 | 2135 |
} |
2136 |
- ost->reformat_pair = MAKE_SFMT_PAIR(AV_SAMPLE_FMT_NONE,AV_SAMPLE_FMT_NONE); |
|
2137 | 2136 |
if (!codec->sample_rate) { |
2138 | 2137 |
codec->sample_rate = icodec->sample_rate; |
2139 | 2138 |
} |
... | ... |
@@ -2149,6 +2125,8 @@ static int transcode_init(OutputFile *output_files, int nb_output_files, |
2149 | 2149 |
if (av_get_channel_layout_nb_channels(codec->channel_layout) != codec->channels) |
2150 | 2150 |
codec->channel_layout = 0; |
2151 | 2151 |
ost->audio_resample = codec->sample_rate != icodec->sample_rate || audio_sync_method > 1; |
2152 |
+ ost->audio_resample |= codec->sample_fmt != icodec->sample_fmt |
|
2153 |
+ || codec->channel_layout != icodec->channel_layout; |
|
2152 | 2154 |
icodec->request_channels = codec->channels; |
2153 | 2155 |
ist->decoding_needed = 1; |
2154 | 2156 |
ost->encoding_needed = 1; |
... | ... |
@@ -2679,10 +2657,7 @@ static int transcode(OutputFile *output_files, int nb_output_files, |
2679 | 2679 |
av_free(ost->forced_kf_pts); |
2680 | 2680 |
if (ost->video_resample) |
2681 | 2681 |
sws_freeContext(ost->img_resample_ctx); |
2682 |
- if (ost->resample) |
|
2683 |
- audio_resample_close(ost->resample); |
|
2684 |
- if (ost->reformat_ctx) |
|
2685 |
- av_audio_convert_free(ost->reformat_ctx); |
|
2682 |
+ swr_free(&ost->swr); |
|
2686 | 2683 |
av_dict_free(&ost->opts); |
2687 | 2684 |
} |
2688 | 2685 |
} |
2689 | 2686 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,12 @@ |
0 |
+include $(SUBDIR)../config.mak |
|
1 |
+ |
|
2 |
+NAME = swresample |
|
3 |
+FFLIBS = avutil |
|
4 |
+ |
|
5 |
+HEADERS = swresample.h |
|
6 |
+ |
|
7 |
+OBJS = swresample.o audioconvert.o resample2.o rematrix.o |
|
8 |
+ |
|
9 |
+TESTPROGS = swresample_test |
|
10 |
+ |
|
11 |
+include $(SUBDIR)../subdir.mak |
0 | 12 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,113 @@ |
0 |
+/* |
|
1 |
+ * audio conversion |
|
2 |
+ * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> |
|
3 |
+ * |
|
4 |
+ * This file is part of FFmpeg. |
|
5 |
+ * |
|
6 |
+ * FFmpeg is free software; you can redistribute it and/or |
|
7 |
+ * modify it under the terms of the GNU Lesser General Public |
|
8 |
+ * License as published by the Free Software Foundation; either |
|
9 |
+ * version 2.1 of the License, or (at your option) any later version. |
|
10 |
+ * |
|
11 |
+ * FFmpeg is distributed in the hope that it will be useful, |
|
12 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
14 |
+ * Lesser General Public License for more details. |
|
15 |
+ * |
|
16 |
+ * You should have received a copy of the GNU Lesser General Public |
|
17 |
+ * License along with FFmpeg; if not, write to the Free Software |
|
18 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
19 |
+ */ |
|
20 |
+ |
|
21 |
+/** |
|
22 |
+ * @file |
|
23 |
+ * audio conversion |
|
24 |
+ * @author Michael Niedermayer <michaelni@gmx.at> |
|
25 |
+ */ |
|
26 |
+ |
|
27 |
+#include "libavutil/avstring.h" |
|
28 |
+#include "libavutil/avassert.h" |
|
29 |
+#include "libavutil/libm.h" |
|
30 |
+#include "libavutil/samplefmt.h" |
|
31 |
+#include "audioconvert.h" |
|
32 |
+ |
|
33 |
+ |
|
34 |
+struct AVAudioConvert { |
|
35 |
+ int channels; |
|
36 |
+ int fmt_pair; |
|
37 |
+}; |
|
38 |
+ |
|
39 |
+AVAudioConvert *swr_audio_convert_alloc(enum AVSampleFormat out_fmt, |
|
40 |
+ enum AVSampleFormat in_fmt, |
|
41 |
+ int channels, int flags) |
|
42 |
+{ |
|
43 |
+ AVAudioConvert *ctx; |
|
44 |
+ ctx = av_malloc(sizeof(AVAudioConvert)); |
|
45 |
+ if (!ctx) |
|
46 |
+ return NULL; |
|
47 |
+ ctx->channels = channels; |
|
48 |
+ ctx->fmt_pair = out_fmt + AV_SAMPLE_FMT_NB*in_fmt; |
|
49 |
+ return ctx; |
|
50 |
+} |
|
51 |
+ |
|
52 |
+void swr_audio_convert_free(AVAudioConvert **ctx) |
|
53 |
+{ |
|
54 |
+ av_freep(ctx); |
|
55 |
+} |
|
56 |
+ |
|
57 |
+int swr_audio_convert(AVAudioConvert *ctx, AudioData *out, AudioData*in, int len) |
|
58 |
+{ |
|
59 |
+ int ch; |
|
60 |
+ |
|
61 |
+ av_assert0(ctx->channels == out->ch_count); |
|
62 |
+ |
|
63 |
+ //FIXME optimize common cases |
|
64 |
+ |
|
65 |
+ for(ch=0; ch<ctx->channels; ch++){ |
|
66 |
+ const int is= (in ->planar ? 1 : in->ch_count) * in->bps; |
|
67 |
+ const int os= (out->planar ? 1 :out->ch_count) *out->bps; |
|
68 |
+ const uint8_t *pi= in ->ch[ch]; |
|
69 |
+ uint8_t *po= out->ch[ch]; |
|
70 |
+ uint8_t *end= po + os*len; |
|
71 |
+ if(!po) |
|
72 |
+ continue; |
|
73 |
+ |
|
74 |
+#define CONV(ofmt, otype, ifmt, expr)\ |
|
75 |
+if(ctx->fmt_pair == ofmt + AV_SAMPLE_FMT_NB*ifmt){\ |
|
76 |
+ do{\ |
|
77 |
+ *(otype*)po = expr; pi += is; po += os;\ |
|
78 |
+ }while(po < end);\ |
|
79 |
+} |
|
80 |
+ |
|
81 |
+//FIXME put things below under ifdefs so we do not waste space for cases no codec will need |
|
82 |
+//FIXME rounding ? |
|
83 |
+ |
|
84 |
+ CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_U8 , *(const uint8_t*)pi) |
|
85 |
+ else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)<<8) |
|
86 |
+ else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)<<24) |
|
87 |
+ else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0 / (1<<7))) |
|
88 |
+ else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0 / (1<<7))) |
|
89 |
+ else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S16, (*(const int16_t*)pi>>8) + 0x80) |
|
90 |
+ else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi) |
|
91 |
+ else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi<<16) |
|
92 |
+ else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0 / (1<<15))) |
|
93 |
+ else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0 / (1<<15))) |
|
94 |
+ else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S32, (*(const int32_t*)pi>>24) + 0x80) |
|
95 |
+ else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi>>16) |
|
96 |
+ else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi) |
|
97 |
+ else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0 / (1U<<31))) |
|
98 |
+ else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0 / (1U<<31))) |
|
99 |
+ else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_FLT, av_clip_uint8( lrintf(*(const float*)pi * (1<<7)) + 0x80)) |
|
100 |
+ else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, av_clip_int16( lrintf(*(const float*)pi * (1<<15)))) |
|
101 |
+ else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, av_clipl_int32(llrintf(*(const float*)pi * (1U<<31)))) |
|
102 |
+ else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_FLT, *(const float*)pi) |
|
103 |
+ else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_FLT, *(const float*)pi) |
|
104 |
+ else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_DBL, av_clip_uint8( lrint(*(const double*)pi * (1<<7)) + 0x80)) |
|
105 |
+ else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, av_clip_int16( lrint(*(const double*)pi * (1<<15)))) |
|
106 |
+ else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, av_clipl_int32(llrint(*(const double*)pi * (1U<<31)))) |
|
107 |
+ else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_DBL, *(const double*)pi) |
|
108 |
+ else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_DBL, *(const double*)pi) |
|
109 |
+ else return -1; |
|
110 |
+ } |
|
111 |
+ return 0; |
|
112 |
+} |
0 | 113 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,65 @@ |
0 |
+/* |
|
1 |
+ * audio conversion |
|
2 |
+ * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> |
|
3 |
+ * Copyright (c) 2008 Peter Ross |
|
4 |
+ * |
|
5 |
+ * This file is part of FFmpeg. |
|
6 |
+ * |
|
7 |
+ * FFmpeg is free software; you can redistribute it and/or |
|
8 |
+ * modify it under the terms of the GNU Lesser General Public |
|
9 |
+ * License as published by the Free Software Foundation; either |
|
10 |
+ * version 2.1 of the License, or (at your option) any later version. |
|
11 |
+ * |
|
12 |
+ * FFmpeg is distributed in the hope that it will be useful, |
|
13 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
14 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
15 |
+ * Lesser General Public License for more details. |
|
16 |
+ * |
|
17 |
+ * You should have received a copy of the GNU Lesser General Public |
|
18 |
+ * License along with FFmpeg; if not, write to the Free Software |
|
19 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
20 |
+ */ |
|
21 |
+ |
|
22 |
+#ifndef SWR_AUDIOCONVERT_H |
|
23 |
+#define SWR_AUDIOCONVERT_H |
|
24 |
+ |
|
25 |
+/** |
|
26 |
+ * @file |
|
27 |
+ * Audio format conversion routines |
|
28 |
+ */ |
|
29 |
+ |
|
30 |
+ |
|
31 |
+#include "swresample_internal.h" |
|
32 |
+#include "libavutil/cpu.h" |
|
33 |
+#include "libavutil/audioconvert.h" |
|
34 |
+ |
|
35 |
+struct AVAudioConvert; |
|
36 |
+typedef struct AVAudioConvert AVAudioConvert; |
|
37 |
+ |
|
38 |
+/** |
|
39 |
+ * Create an audio sample format converter context |
|
40 |
+ * @param out_fmt Output sample format |
|
41 |
+ * @param in_fmt Input sample format |
|
42 |
+ * @param channels Number of channels |
|
43 |
+ * @param flags See AV_CPU_FLAG_xx |
|
44 |
+ * @return NULL on error |
|
45 |
+ */ |
|
46 |
+AVAudioConvert *swr_audio_convert_alloc(enum AVSampleFormat out_fmt, |
|
47 |
+ enum AVSampleFormat in_fmt, |
|
48 |
+ int channels, int flags); |
|
49 |
+ |
|
50 |
+/** |
|
51 |
+ * Free audio sample format converter context. |
|
52 |
+ * and set the pointer to NULL |
|
53 |
+ */ |
|
54 |
+void swr_audio_convert_free(AVAudioConvert **ctx); |
|
55 |
+ |
|
56 |
+/** |
|
57 |
+ * Convert between audio sample formats |
|
58 |
+ * @param[in] out array of output buffers for each channel. set to NULL to ignore processing of the given channel. |
|
59 |
+ * @param[in] in array of input buffers for each channel |
|
60 |
+ * @param len length of audio frame size (measured in samples) |
|
61 |
+ */ |
|
62 |
+int swr_audio_convert(AVAudioConvert *ctx, AudioData *out, AudioData *in, int len); |
|
63 |
+ |
|
64 |
+#endif /* AVCODEC_AUDIOCONVERT_H */ |
0 | 65 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,271 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2011 Michael Niedermayer (michaelni@gmx.at) |
|
2 |
+ * |
|
3 |
+ * This file is part of libswresample |
|
4 |
+ * |
|
5 |
+ * libswresample is free software; you can redistribute it and/or |
|
6 |
+ * modify it under the terms of the GNU Lesser General Public |
|
7 |
+ * License as published by the Free Software Foundation; either |
|
8 |
+ * version 2.1 of the License, or (at your option) any later version. |
|
9 |
+ * |
|
10 |
+ * libswresample is distributed in the hope that it will be useful, |
|
11 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 |
+ * Lesser General Public License for more details. |
|
14 |
+ * |
|
15 |
+ * You should have received a copy of the GNU Lesser General Public |
|
16 |
+ * License along with libswresample; if not, write to the Free Software |
|
17 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+#include "swresample_internal.h" |
|
21 |
+#include "libavutil/audioconvert.h" |
|
22 |
+#include "libavutil/avassert.h" |
|
23 |
+ |
|
24 |
+#define SAMPLE float |
|
25 |
+#define RENAME(x) x ## _float |
|
26 |
+#include "rematrix_template.c" |
|
27 |
+#undef SAMPLE |
|
28 |
+#undef RENAME |
|
29 |
+ |
|
30 |
+#define SAMPLE int16_t |
|
31 |
+#define RENAME(x) x ## _s16 |
|
32 |
+#include "rematrix_template.c" |
|
33 |
+ |
|
34 |
+ |
|
35 |
+#define FRONT_LEFT 0 |
|
36 |
+#define FRONT_RIGHT 1 |
|
37 |
+#define FRONT_CENTER 2 |
|
38 |
+#define LOW_FREQUENCY 3 |
|
39 |
+#define BACK_LEFT 4 |
|
40 |
+#define BACK_RIGHT 5 |
|
41 |
+#define FRONT_LEFT_OF_CENTER 6 |
|
42 |
+#define FRONT_RIGHT_OF_CENTER 7 |
|
43 |
+#define BACK_CENTER 8 |
|
44 |
+#define SIDE_LEFT 9 |
|
45 |
+#define SIDE_RIGHT 10 |
|
46 |
+#define TOP_CENTER 11 |
|
47 |
+#define TOP_FRONT_LEFT 12 |
|
48 |
+#define TOP_FRONT_CENTER 13 |
|
49 |
+#define TOP_FRONT_RIGHT 14 |
|
50 |
+#define TOP_BACK_LEFT 15 |
|
51 |
+#define TOP_BACK_CENTER 16 |
|
52 |
+#define TOP_BACK_RIGHT 17 |
|
53 |
+ |
|
54 |
+static int even(int64_t layout){ |
|
55 |
+ if(!layout) return 1; |
|
56 |
+ if(layout&(layout-1)) return 1; |
|
57 |
+ return 0; |
|
58 |
+} |
|
59 |
+ |
|
60 |
+static int sane_layout(int64_t layout){ |
|
61 |
+ if(!(layout & AV_CH_LAYOUT_SURROUND)) // at least 1 front speaker |
|
62 |
+ return 0; |
|
63 |
+ if(!even(layout & (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT))) // no asymetric front |
|
64 |
+ return 0; |
|
65 |
+ if(!even(layout & (AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT))) // no asymetric side |
|
66 |
+ return 0; |
|
67 |
+ if(!even(layout & (AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT))) |
|
68 |
+ return 0; |
|
69 |
+ if(!even(layout & (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER))) |
|
70 |
+ return 0; |
|
71 |
+ if(av_get_channel_layout_nb_channels(layout) >= SWR_CH_MAX) |
|
72 |
+ return 0; |
|
73 |
+ |
|
74 |
+ return 1; |
|
75 |
+} |
|
76 |
+ |
|
77 |
+int swr_rematrix_init(SwrContext *s){ |
|
78 |
+ int i, j, in_i, out_i; |
|
79 |
+ float matrix[64][64]={0}; |
|
80 |
+ int64_t unaccounted= s->in_ch_layout & ~s->out_ch_layout; |
|
81 |
+ float maxcoef=0; |
|
82 |
+ |
|
83 |
+ for(i=0; i<64; i++){ |
|
84 |
+ if(s->in_ch_layout & s->out_ch_layout & (1LL<<i)) |
|
85 |
+ matrix[i][i]= 1.0; |
|
86 |
+ } |
|
87 |
+ |
|
88 |
+ if(!sane_layout(s->in_ch_layout)){ |
|
89 |
+ av_log(s, AV_LOG_ERROR, "Input channel layout isnt supported\n"); |
|
90 |
+ return AVERROR(EINVAL); |
|
91 |
+ } |
|
92 |
+ if(!sane_layout(s->out_ch_layout)){ |
|
93 |
+ av_log(s, AV_LOG_ERROR, "Output channel layout isnt supported\n"); |
|
94 |
+ return AVERROR(EINVAL); |
|
95 |
+ } |
|
96 |
+ |
|
97 |
+//FIXME implement dolby surround |
|
98 |
+//FIXME implement full ac3 |
|
99 |
+ |
|
100 |
+ |
|
101 |
+ if(unaccounted & AV_CH_FRONT_CENTER){ |
|
102 |
+ if((s->out_ch_layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO){ |
|
103 |
+ matrix[ FRONT_LEFT][FRONT_CENTER]+= sqrt(0.5); |
|
104 |
+ matrix[FRONT_RIGHT][FRONT_CENTER]+= sqrt(0.5); |
|
105 |
+ }else |
|
106 |
+ av_assert0(0); |
|
107 |
+ } |
|
108 |
+ if(unaccounted & AV_CH_LAYOUT_STEREO){ |
|
109 |
+ if(s->out_ch_layout & AV_CH_FRONT_CENTER){ |
|
110 |
+ matrix[FRONT_CENTER][ FRONT_LEFT]+= sqrt(0.5); |
|
111 |
+ matrix[FRONT_CENTER][FRONT_RIGHT]+= sqrt(0.5); |
|
112 |
+ if(s->in_ch_layout & AV_CH_FRONT_CENTER) |
|
113 |
+ matrix[FRONT_CENTER][ FRONT_CENTER] = s->clev*sqrt(2); |
|
114 |
+ }else |
|
115 |
+ av_assert0(0); |
|
116 |
+ } |
|
117 |
+ |
|
118 |
+ if(unaccounted & AV_CH_BACK_CENTER){ |
|
119 |
+ if(s->out_ch_layout & AV_CH_BACK_LEFT){ |
|
120 |
+ matrix[ BACK_LEFT][BACK_CENTER]+= sqrt(0.5); |
|
121 |
+ matrix[BACK_RIGHT][BACK_CENTER]+= sqrt(0.5); |
|
122 |
+ }else if(s->out_ch_layout & AV_CH_SIDE_LEFT){ |
|
123 |
+ matrix[ SIDE_LEFT][BACK_CENTER]+= sqrt(0.5); |
|
124 |
+ matrix[SIDE_RIGHT][BACK_CENTER]+= sqrt(0.5); |
|
125 |
+ }else if(s->out_ch_layout & AV_CH_FRONT_LEFT){ |
|
126 |
+ matrix[ FRONT_LEFT][BACK_CENTER]+= s->slev*sqrt(0.5); |
|
127 |
+ matrix[FRONT_RIGHT][BACK_CENTER]+= s->slev*sqrt(0.5); |
|
128 |
+ }else if(s->out_ch_layout & AV_CH_FRONT_CENTER){ |
|
129 |
+ matrix[ FRONT_CENTER][BACK_CENTER]+= s->slev*sqrt(0.5); |
|
130 |
+ }else |
|
131 |
+ av_assert0(0); |
|
132 |
+ } |
|
133 |
+ if(unaccounted & AV_CH_BACK_LEFT){ |
|
134 |
+ if(s->out_ch_layout & AV_CH_BACK_CENTER){ |
|
135 |
+ matrix[BACK_CENTER][ BACK_LEFT]+= sqrt(0.5); |
|
136 |
+ matrix[BACK_CENTER][BACK_RIGHT]+= sqrt(0.5); |
|
137 |
+ }else if(s->out_ch_layout & AV_CH_SIDE_LEFT){ |
|
138 |
+ if(s->in_ch_layout & AV_CH_SIDE_LEFT){ |
|
139 |
+ matrix[ SIDE_LEFT][ BACK_LEFT]+= sqrt(0.5); |
|
140 |
+ matrix[SIDE_RIGHT][BACK_RIGHT]+= sqrt(0.5); |
|
141 |
+ }else{ |
|
142 |
+ matrix[ SIDE_LEFT][ BACK_LEFT]+= 1.0; |
|
143 |
+ matrix[SIDE_RIGHT][BACK_RIGHT]+= 1.0; |
|
144 |
+ } |
|
145 |
+ }else if(s->out_ch_layout & AV_CH_FRONT_LEFT){ |
|
146 |
+ matrix[ FRONT_LEFT][ BACK_LEFT]+= s->slev; |
|
147 |
+ matrix[FRONT_RIGHT][BACK_RIGHT]+= s->slev; |
|
148 |
+ }else if(s->out_ch_layout & AV_CH_FRONT_CENTER){ |
|
149 |
+ matrix[ FRONT_CENTER][BACK_LEFT ]+= s->slev*sqrt(0.5); |
|
150 |
+ matrix[ FRONT_CENTER][BACK_RIGHT]+= s->slev*sqrt(0.5); |
|
151 |
+ }else |
|
152 |
+ av_assert0(0); |
|
153 |
+ } |
|
154 |
+ |
|
155 |
+ if(unaccounted & AV_CH_SIDE_LEFT){ |
|
156 |
+ if(s->out_ch_layout & AV_CH_BACK_LEFT){ |
|
157 |
+ matrix[ BACK_LEFT][ SIDE_LEFT]+= 1.0; |
|
158 |
+ matrix[BACK_RIGHT][SIDE_RIGHT]+= 1.0; |
|
159 |
+ }else if(s->out_ch_layout & AV_CH_BACK_CENTER){ |
|
160 |
+ matrix[BACK_CENTER][ SIDE_LEFT]+= sqrt(0.5); |
|
161 |
+ matrix[BACK_CENTER][SIDE_RIGHT]+= sqrt(0.5); |
|
162 |
+ }else if(s->out_ch_layout & AV_CH_FRONT_LEFT){ |
|
163 |
+ matrix[ FRONT_LEFT][ SIDE_LEFT]+= s->slev; |
|
164 |
+ matrix[FRONT_RIGHT][SIDE_RIGHT]+= s->slev; |
|
165 |
+ }else if(s->out_ch_layout & AV_CH_FRONT_CENTER){ |
|
166 |
+ matrix[ FRONT_CENTER][SIDE_LEFT ]+= s->slev*sqrt(0.5); |
|
167 |
+ matrix[ FRONT_CENTER][SIDE_RIGHT]+= s->slev*sqrt(0.5); |
|
168 |
+ }else |
|
169 |
+ av_assert0(0); |
|
170 |
+ } |
|
171 |
+ |
|
172 |
+ if(unaccounted & AV_CH_FRONT_LEFT_OF_CENTER){ |
|
173 |
+ if(s->out_ch_layout & AV_CH_FRONT_LEFT){ |
|
174 |
+ matrix[ FRONT_LEFT][ FRONT_LEFT_OF_CENTER]+= 1.0; |
|
175 |
+ matrix[FRONT_RIGHT][FRONT_RIGHT_OF_CENTER]+= 1.0; |
|
176 |
+ }else if(s->out_ch_layout & AV_CH_FRONT_CENTER){ |
|
177 |
+ matrix[ FRONT_CENTER][ FRONT_LEFT_OF_CENTER]+= sqrt(0.5); |
|
178 |
+ matrix[ FRONT_CENTER][FRONT_RIGHT_OF_CENTER]+= sqrt(0.5); |
|
179 |
+ }else |
|
180 |
+ av_assert0(0); |
|
181 |
+ } |
|
182 |
+ |
|
183 |
+ //FIXME quantize for integeres |
|
184 |
+ for(out_i=i=0; i<64; i++){ |
|
185 |
+ double sum=0; |
|
186 |
+ int in_i=0; |
|
187 |
+ int ch_in=0; |
|
188 |
+ for(j=0; j<64; j++){ |
|
189 |
+ s->matrix[out_i][in_i]= matrix[i][j]; |
|
190 |
+ if(matrix[i][j]){ |
|
191 |
+ s->matrix_ch[out_i][++ch_in]= in_i; |
|
192 |
+ sum += fabs(matrix[i][j]); |
|
193 |
+ } |
|
194 |
+ if(s->in_ch_layout & (1ULL<<j)) |
|
195 |
+ in_i++; |
|
196 |
+ } |
|
197 |
+ s->matrix_ch[out_i][0]= ch_in; |
|
198 |
+ maxcoef= FFMAX(maxcoef, sum); |
|
199 |
+ if(s->out_ch_layout & (1ULL<<i)) |
|
200 |
+ out_i++; |
|
201 |
+ } |
|
202 |
+ if(( s->out_sample_fmt < AV_SAMPLE_FMT_FLT |
|
203 |
+ || s->int_sample_fmt < AV_SAMPLE_FMT_FLT) && maxcoef > 1.0){ |
|
204 |
+ for(i=0; i<SWR_CH_MAX; i++) |
|
205 |
+ for(j=0; j<SWR_CH_MAX; j++) |
|
206 |
+ s->matrix[i][j] /= maxcoef; |
|
207 |
+ } |
|
208 |
+ for(i=0; i<av_get_channel_layout_nb_channels(s->out_ch_layout); i++){ |
|
209 |
+ for(j=0; j<av_get_channel_layout_nb_channels(s->in_ch_layout); j++){ |
|
210 |
+ av_log(NULL, AV_LOG_ERROR, "%f ", s->matrix[i][j]); |
|
211 |
+ } |
|
212 |
+ av_log(NULL, AV_LOG_ERROR, "\n"); |
|
213 |
+ } |
|
214 |
+ return 0; |
|
215 |
+} |
|
216 |
+ |
|
217 |
+int swr_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy){ |
|
218 |
+ int out_i, in_i, i, j; |
|
219 |
+ |
|
220 |
+av_assert0(out->ch_count == av_get_channel_layout_nb_channels(s->out_ch_layout)); |
|
221 |
+av_assert0(in ->ch_count == av_get_channel_layout_nb_channels(s-> in_ch_layout)); |
|
222 |
+ |
|
223 |
+ for(out_i=0; out_i<out->ch_count; out_i++){ |
|
224 |
+ switch(s->matrix_ch[out_i][0]){ |
|
225 |
+ case 1: |
|
226 |
+ in_i= s->matrix_ch[out_i][1]; |
|
227 |
+ if(mustcopy || s->matrix[out_i][in_i]!=1.0){ |
|
228 |
+ if(s->int_sample_fmt == AV_SAMPLE_FMT_FLT){ |
|
229 |
+ copy_float(out->ch[out_i], in->ch[in_i], s->matrix[out_i][in_i], len); |
|
230 |
+ }else |
|
231 |
+ copy_s16 (out->ch[out_i], in->ch[in_i], s->matrix[out_i][in_i], len); |
|
232 |
+ }else{ |
|
233 |
+ out->ch[out_i]= in->ch[in_i]; |
|
234 |
+ } |
|
235 |
+ break; |
|
236 |
+ case 2: |
|
237 |
+ if(s->int_sample_fmt == AV_SAMPLE_FMT_FLT){ |
|
238 |
+ sum2_float(out->ch[out_i], in->ch[ s->matrix_ch[out_i][1] ], in->ch[ s->matrix_ch[out_i][2] ], |
|
239 |
+ s->matrix[out_i][ s->matrix_ch[out_i][1] ], s->matrix[out_i][ s->matrix_ch[out_i][2] ], |
|
240 |
+ len); |
|
241 |
+ }else{ |
|
242 |
+ sum2_s16 (out->ch[out_i], in->ch[ s->matrix_ch[out_i][1] ], in->ch[ s->matrix_ch[out_i][2] ], |
|
243 |
+ s->matrix[out_i][ s->matrix_ch[out_i][1] ], s->matrix[out_i][ s->matrix_ch[out_i][2] ], |
|
244 |
+ len); |
|
245 |
+ } |
|
246 |
+ break; |
|
247 |
+ default: |
|
248 |
+ if(s->int_sample_fmt == AV_SAMPLE_FMT_FLT){ |
|
249 |
+ for(i=0; i<len; i++){ |
|
250 |
+ float v=0; |
|
251 |
+ for(j=0; j<s->matrix_ch[out_i][0]; j++){ |
|
252 |
+ in_i= s->matrix_ch[out_i][1+j]; |
|
253 |
+ v+= ((float*)in->ch[in_i])[i] * s->matrix[out_i][in_i]; |
|
254 |
+ } |
|
255 |
+ ((float*)out->ch[out_i])[i]= v; |
|
256 |
+ } |
|
257 |
+ }else{ |
|
258 |
+ for(i=0; i<len; i++){ |
|
259 |
+ int v=0; |
|
260 |
+ for(j=0; j<s->matrix_ch[out_i][0]; j++){ |
|
261 |
+ in_i= s->matrix_ch[out_i][1+j]; |
|
262 |
+ v+= ((int16_t*)in->ch[in_i])[i] * s->matrix[out_i][in_i]; //FIXME use int16 coeffs |
|
263 |
+ } |
|
264 |
+ ((int16_t*)out->ch[out_i])[i]= v; |
|
265 |
+ } |
|
266 |
+ } |
|
267 |
+ } |
|
268 |
+ } |
|
269 |
+ return 0; |
|
270 |
+} |
0 | 271 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,38 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2011 Michael Niedermayer (michaelni@gmx.at) |
|
2 |
+ * |
|
3 |
+ * This file is part of libswresample |
|
4 |
+ * |
|
5 |
+ * libswresample is free software; you can redistribute it and/or |
|
6 |
+ * modify it under the terms of the GNU Lesser General Public |
|
7 |
+ * License as published by the Free Software Foundation; either |
|
8 |
+ * version 2.1 of the License, or (at your option) any later version. |
|
9 |
+ * |
|
10 |
+ * libswresample is distributed in the hope that it will be useful, |
|
11 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 |
+ * Lesser General Public License for more details. |
|
14 |
+ * |
|
15 |
+ * You should have received a copy of the GNU Lesser General Public |
|
16 |
+ * License along with libswresample; if not, write to the Free Software |
|
17 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+ |
|
21 |
+static void RENAME(sum2)(SAMPLE *out, const SAMPLE *in1, const SAMPLE *in2, float coeff1, float coeff2, int len){ |
|
22 |
+ int i; |
|
23 |
+ |
|
24 |
+ for(i=0; i<len; i++) |
|
25 |
+ out[i] = coeff1*in1[i] + coeff2*in2[i]; //FIXME better int16 |
|
26 |
+} |
|
27 |
+ |
|
28 |
+static void RENAME(copy)(SAMPLE *out, const SAMPLE *in, float coeff, int len){ |
|
29 |
+ if(coeff == 1.0){ |
|
30 |
+ memcpy(out, in, sizeof(SAMPLE)*len); |
|
31 |
+ }else{ |
|
32 |
+ int i; |
|
33 |
+ for(i=0; i<len; i++) |
|
34 |
+ out[i] = coeff*in[i]; //FIXME better int16 |
|
35 |
+ } |
|
36 |
+} |
|
37 |
+ |
0 | 38 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,352 @@ |
0 |
+/* |
|
1 |
+ * audio resampling |
|
2 |
+ * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> |
|
3 |
+ * |
|
4 |
+ * This file is part of FFmpeg. |
|
5 |
+ * |
|
6 |
+ * FFmpeg is free software; you can redistribute it and/or |
|
7 |
+ * modify it under the terms of the GNU Lesser General Public |
|
8 |
+ * License as published by the Free Software Foundation; either |
|
9 |
+ * version 2.1 of the License, or (at your option) any later version. |
|
10 |
+ * |
|
11 |
+ * FFmpeg is distributed in the hope that it will be useful, |
|
12 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
14 |
+ * Lesser General Public License for more details. |
|
15 |
+ * |
|
16 |
+ * You should have received a copy of the GNU Lesser General Public |
|
17 |
+ * License along with FFmpeg; if not, write to the Free Software |
|
18 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
19 |
+ */ |
|
20 |
+ |
|
21 |
+/** |
|
22 |
+ * @file |
|
23 |
+ * audio resampling |
|
24 |
+ * @author Michael Niedermayer <michaelni@gmx.at> |
|
25 |
+ */ |
|
26 |
+ |
|
27 |
+#include "libavutil/log.h" |
|
28 |
+#include "swresample_internal.h" |
|
29 |
+ |
|
30 |
+#ifndef CONFIG_RESAMPLE_HP |
|
31 |
+#define FILTER_SHIFT 15 |
|
32 |
+ |
|
33 |
+#define FELEM int16_t |
|
34 |
+#define FELEM2 int32_t |
|
35 |
+#define FELEML int64_t |
|
36 |
+#define FELEM_MAX INT16_MAX |
|
37 |
+#define FELEM_MIN INT16_MIN |
|
38 |
+#define WINDOW_TYPE 9 |
|
39 |
+#elif !defined(CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE) |
|
40 |
+#define FILTER_SHIFT 30 |
|
41 |
+ |
|
42 |
+#define FELEM int32_t |
|
43 |
+#define FELEM2 int64_t |
|
44 |
+#define FELEML int64_t |
|
45 |
+#define FELEM_MAX INT32_MAX |
|
46 |
+#define FELEM_MIN INT32_MIN |
|
47 |
+#define WINDOW_TYPE 12 |
|
48 |
+#else |
|
49 |
+#define FILTER_SHIFT 0 |
|
50 |
+ |
|
51 |
+#define FELEM double |
|
52 |
+#define FELEM2 double |
|
53 |
+#define FELEML double |
|
54 |
+#define WINDOW_TYPE 24 |
|
55 |
+#endif |
|
56 |
+ |
|
57 |
+ |
|
58 |
+typedef struct AVResampleContext{ |
|
59 |
+ const AVClass *av_class; |
|
60 |
+ FELEM *filter_bank; |
|
61 |
+ int filter_length; |
|
62 |
+ int ideal_dst_incr; |
|
63 |
+ int dst_incr; |
|
64 |
+ int index; |
|
65 |
+ int frac; |
|
66 |
+ int src_incr; |
|
67 |
+ int compensation_distance; |
|
68 |
+ int phase_shift; |
|
69 |
+ int phase_mask; |
|
70 |
+ int linear; |
|
71 |
+ double factor; |
|
72 |
+}AVResampleContext; |
|
73 |
+ |
|
74 |
+/** |
|
75 |
+ * 0th order modified bessel function of the first kind. |
|
76 |
+ */ |
|
77 |
+static double bessel(double x){ |
|
78 |
+ double v=1; |
|
79 |
+ double lastv=0; |
|
80 |
+ double t=1; |
|
81 |
+ int i; |
|
82 |
+ static const double inv[100]={ |
|
83 |
+ 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), |
|
84 |
+ 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), |
|
85 |
+ 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), |
|
86 |
+ 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), |
|
87 |
+ 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), |
|
88 |
+ 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), |
|
89 |
+ 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), |
|
90 |
+ 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), |
|
91 |
+ 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), |
|
92 |
+ 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) |
|
93 |
+ }; |
|
94 |
+ |
|
95 |
+ x= x*x/4; |
|
96 |
+ for(i=0; v != lastv; i++){ |
|
97 |
+ lastv=v; |
|
98 |
+ t *= x*inv[i]; |
|
99 |
+ v += t; |
|
100 |
+ } |
|
101 |
+ return v; |
|
102 |
+} |
|
103 |
+ |
|
104 |
+/** |
|
105 |
+ * builds a polyphase filterbank. |
|
106 |
+ * @param factor resampling factor |
|
107 |
+ * @param scale wanted sum of coefficients for each filter |
|
108 |
+ * @param type 0->cubic, 1->blackman nuttall windowed sinc, 2..16->kaiser windowed sinc beta=2..16 |
|
109 |
+ * @return 0 on success, negative on error |
|
110 |
+ */ |
|
111 |
+static int build_filter(FELEM *filter, double factor, int tap_count, int phase_count, int scale, int type){ |
|
112 |
+ int ph, i; |
|
113 |
+ double x, y, w; |
|
114 |
+ double *tab = av_malloc(tap_count * sizeof(*tab)); |
|
115 |
+ const int center= (tap_count-1)/2; |
|
116 |
+ |
|
117 |
+ if (!tab) |
|
118 |
+ return AVERROR(ENOMEM); |
|
119 |
+ |
|
120 |
+ /* if upsampling, only need to interpolate, no filter */ |
|
121 |
+ if (factor > 1.0) |
|
122 |
+ factor = 1.0; |
|
123 |
+ |
|
124 |
+ for(ph=0;ph<phase_count;ph++) { |
|
125 |
+ double norm = 0; |
|
126 |
+ for(i=0;i<tap_count;i++) { |
|
127 |
+ x = M_PI * ((double)(i - center) - (double)ph / phase_count) * factor; |
|
128 |
+ if (x == 0) y = 1.0; |
|
129 |
+ else y = sin(x) / x; |
|
130 |
+ switch(type){ |
|
131 |
+ case 0:{ |
|
132 |
+ const float d= -0.5; //first order derivative = -0.5 |
|
133 |
+ x = fabs(((double)(i - center) - (double)ph / phase_count) * factor); |
|
134 |
+ if(x<1.0) y= 1 - 3*x*x + 2*x*x*x + d*( -x*x + x*x*x); |
|
135 |
+ else y= d*(-4 + 8*x - 5*x*x + x*x*x); |
|
136 |
+ break;} |
|
137 |
+ case 1: |
|
138 |
+ w = 2.0*x / (factor*tap_count) + M_PI; |
|
139 |
+ y *= 0.3635819 - 0.4891775 * cos(w) + 0.1365995 * cos(2*w) - 0.0106411 * cos(3*w); |
|
140 |
+ break; |
|
141 |
+ default: |
|
142 |
+ w = 2.0*x / (factor*tap_count*M_PI); |
|
143 |
+ y *= bessel(type*sqrt(FFMAX(1-w*w, 0))); |
|
144 |
+ break; |
|
145 |
+ } |
|
146 |
+ |
|
147 |
+ tab[i] = y; |
|
148 |
+ norm += y; |
|
149 |
+ } |
|
150 |
+ |
|
151 |
+ /* normalize so that an uniform color remains the same */ |
|
152 |
+ for(i=0;i<tap_count;i++) { |
|
153 |
+#ifdef CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE |
|
154 |
+ filter[ph * tap_count + i] = tab[i] / norm; |
|
155 |
+#else |
|
156 |
+ filter[ph * tap_count + i] = av_clip(lrintf(tab[i] * scale / norm), FELEM_MIN, FELEM_MAX); |
|
157 |
+#endif |
|
158 |
+ } |
|
159 |
+ } |
|
160 |
+#if 0 |
|
161 |
+ { |
|
162 |
+#define LEN 1024 |
|
163 |
+ int j,k; |
|
164 |
+ double sine[LEN + tap_count]; |
|
165 |
+ double filtered[LEN]; |
|
166 |
+ double maxff=-2, minff=2, maxsf=-2, minsf=2; |
|
167 |
+ for(i=0; i<LEN; i++){ |
|
168 |
+ double ss=0, sf=0, ff=0; |
|
169 |
+ for(j=0; j<LEN+tap_count; j++) |
|
170 |
+ sine[j]= cos(i*j*M_PI/LEN); |
|
171 |
+ for(j=0; j<LEN; j++){ |
|
172 |
+ double sum=0; |
|
173 |
+ ph=0; |
|
174 |
+ for(k=0; k<tap_count; k++) |
|
175 |
+ sum += filter[ph * tap_count + k] * sine[k+j]; |
|
176 |
+ filtered[j]= sum / (1<<FILTER_SHIFT); |
|
177 |
+ ss+= sine[j + center] * sine[j + center]; |
|
178 |
+ ff+= filtered[j] * filtered[j]; |
|
179 |
+ sf+= sine[j + center] * filtered[j]; |
|
180 |
+ } |
|
181 |
+ ss= sqrt(2*ss/LEN); |
|
182 |
+ ff= sqrt(2*ff/LEN); |
|
183 |
+ sf= 2*sf/LEN; |
|
184 |
+ maxff= FFMAX(maxff, ff); |
|
185 |
+ minff= FFMIN(minff, ff); |
|
186 |
+ maxsf= FFMAX(maxsf, sf); |
|
187 |
+ minsf= FFMIN(minsf, sf); |
|
188 |
+ if(i%11==0){ |
|
189 |
+ 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); |
|
190 |
+ minff=minsf= 2; |
|
191 |
+ maxff=maxsf= -2; |
|
192 |
+ } |
|
193 |
+ } |
|
194 |
+ } |
|
195 |
+#endif |
|
196 |
+ |
|
197 |
+ av_free(tab); |
|
198 |
+ return 0; |
|
199 |
+} |
|
200 |
+ |
|
201 |
+AVResampleContext *swr_resample_init(AVResampleContext *c, int out_rate, int in_rate, int filter_size, int phase_shift, int linear, double cutoff){ |
|
202 |
+ double factor= FFMIN(out_rate * cutoff / in_rate, 1.0); |
|
203 |
+ int phase_count= 1<<phase_shift; |
|
204 |
+ |
|
205 |
+ if(!c || c->phase_shift!=phase_shift || c->linear!=linear || c->factor != factor |
|
206 |
+ || c->filter_length!=FFMAX((int)ceil(filter_size/factor), 1)){ |
|
207 |
+ c= av_mallocz(sizeof(AVResampleContext)); |
|
208 |
+ if (!c) |
|
209 |
+ return NULL; |
|
210 |
+ |
|
211 |
+ c->phase_shift= phase_shift; |
|
212 |
+ c->phase_mask= phase_count-1; |
|
213 |
+ c->linear= linear; |
|
214 |
+ c->factor= factor; |
|
215 |
+ |
|
216 |
+ c->filter_length= FFMAX((int)ceil(filter_size/factor), 1); |
|
217 |
+ c->filter_bank= av_mallocz(c->filter_length*(phase_count+1)*sizeof(FELEM)); |
|
218 |
+ if (!c->filter_bank) |
|
219 |
+ goto error; |
|
220 |
+ if (build_filter(c->filter_bank, factor, c->filter_length, phase_count, 1<<FILTER_SHIFT, WINDOW_TYPE)) |
|
221 |
+ goto error; |
|
222 |
+ memcpy(&c->filter_bank[c->filter_length*phase_count+1], c->filter_bank, (c->filter_length-1)*sizeof(FELEM)); |
|
223 |
+ c->filter_bank[c->filter_length*phase_count]= c->filter_bank[c->filter_length - 1]; |
|
224 |
+ } |
|
225 |
+ |
|
226 |
+ c->compensation_distance= 0; |
|
227 |
+ c->src_incr= out_rate; |
|
228 |
+ c->ideal_dst_incr= c->dst_incr= in_rate * phase_count; |
|
229 |
+ c->index= -phase_count*((c->filter_length-1)/2); |
|
230 |
+ c->frac= 0; |
|
231 |
+ |
|
232 |
+ return c; |
|
233 |
+error: |
|
234 |
+ av_free(c->filter_bank); |
|
235 |
+ av_free(c); |
|
236 |
+ return NULL; |
|
237 |
+} |
|
238 |
+ |
|
239 |
+void swr_resample_free(AVResampleContext **c){ |
|
240 |
+ if(!*c) |
|
241 |
+ return; |
|
242 |
+ av_freep(&(*c)->filter_bank); |
|
243 |
+ av_freep(c); |
|
244 |
+} |
|
245 |
+ |
|
246 |
+void swr_compensate(struct SwrContext *s, int sample_delta, int compensation_distance){ |
|
247 |
+ AVResampleContext *c= s->resample; |
|
248 |
+// sample_delta += (c->ideal_dst_incr - c->dst_incr)*(int64_t)c->compensation_distance / c->ideal_dst_incr; |
|
249 |
+ c->compensation_distance= compensation_distance; |
|
250 |
+ c->dst_incr = c->ideal_dst_incr - c->ideal_dst_incr * (int64_t)sample_delta / compensation_distance; |
|
251 |
+} |
|
252 |
+ |
|
253 |
+int swr_resample(AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx){ |
|
254 |
+ int dst_index, i; |
|
255 |
+ int index= c->index; |
|
256 |
+ int frac= c->frac; |
|
257 |
+ int dst_incr_frac= c->dst_incr % c->src_incr; |
|
258 |
+ int dst_incr= c->dst_incr / c->src_incr; |
|
259 |
+ int compensation_distance= c->compensation_distance; |
|
260 |
+ |
|
261 |
+ if(compensation_distance == 0 && c->filter_length == 1 && c->phase_shift==0){ |
|
262 |
+ int64_t index2= ((int64_t)index)<<32; |
|
263 |
+ int64_t incr= (1LL<<32) * c->dst_incr / c->src_incr; |
|
264 |
+ dst_size= FFMIN(dst_size, (src_size-1-index) * (int64_t)c->src_incr / c->dst_incr); |
|
265 |
+ |
|
266 |
+ for(dst_index=0; dst_index < dst_size; dst_index++){ |
|
267 |
+ dst[dst_index] = src[index2>>32]; |
|
268 |
+ index2 += incr; |
|
269 |
+ } |
|
270 |
+ frac += dst_index * dst_incr_frac; |
|
271 |
+ index += dst_index * dst_incr; |
|
272 |
+ index += frac / c->src_incr; |
|
273 |
+ frac %= c->src_incr; |
|
274 |
+ }else{ |
|
275 |
+ for(dst_index=0; dst_index < dst_size; dst_index++){ |
|
276 |
+ FELEM *filter= c->filter_bank + c->filter_length*(index & c->phase_mask); |
|
277 |
+ int sample_index= index >> c->phase_shift; |
|
278 |
+ FELEM2 val=0; |
|
279 |
+ |
|
280 |
+ if(sample_index < 0){ |
|
281 |
+ for(i=0; i<c->filter_length; i++) |
|
282 |
+ val += src[FFABS(sample_index + i) % src_size] * filter[i]; |
|
283 |
+ }else if(sample_index + c->filter_length > src_size){ |
|
284 |
+ break; |
|
285 |
+ }else if(c->linear){ |
|
286 |
+ FELEM2 v2=0; |
|
287 |
+ for(i=0; i<c->filter_length; i++){ |
|
288 |
+ val += src[sample_index + i] * (FELEM2)filter[i]; |
|
289 |
+ v2 += src[sample_index + i] * (FELEM2)filter[i + c->filter_length]; |
|
290 |
+ } |
|
291 |
+ val+=(v2-val)*(FELEML)frac / c->src_incr; |
|
292 |
+ }else{ |
|
293 |
+ for(i=0; i<c->filter_length; i++){ |
|
294 |
+ val += src[sample_index + i] * (FELEM2)filter[i]; |
|
295 |
+ } |
|
296 |
+ } |
|
297 |
+ |
|
298 |
+#ifdef CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE |
|
299 |
+ dst[dst_index] = av_clip_int16(lrintf(val)); |
|
300 |
+#else |
|
301 |
+ val = (val + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT; |
|
302 |
+ dst[dst_index] = (unsigned)(val + 32768) > 65535 ? (val>>31) ^ 32767 : val; |
|
303 |
+#endif |
|
304 |
+ |
|
305 |
+ frac += dst_incr_frac; |
|
306 |
+ index += dst_incr; |
|
307 |
+ if(frac >= c->src_incr){ |
|
308 |
+ frac -= c->src_incr; |
|
309 |
+ index++; |
|
310 |
+ } |
|
311 |
+ |
|
312 |
+ if(dst_index + 1 == compensation_distance){ |
|
313 |
+ compensation_distance= 0; |
|
314 |
+ dst_incr_frac= c->ideal_dst_incr % c->src_incr; |
|
315 |
+ dst_incr= c->ideal_dst_incr / c->src_incr; |
|
316 |
+ } |
|
317 |
+ } |
|
318 |
+ } |
|
319 |
+ *consumed= FFMAX(index, 0) >> c->phase_shift; |
|
320 |
+ if(index>=0) index &= c->phase_mask; |
|
321 |
+ |
|
322 |
+ if(compensation_distance){ |
|
323 |
+ compensation_distance -= dst_index; |
|
324 |
+ assert(compensation_distance > 0); |
|
325 |
+ } |
|
326 |
+ if(update_ctx){ |
|
327 |
+ c->frac= frac; |
|
328 |
+ c->index= index; |
|
329 |
+ c->dst_incr= dst_incr_frac + c->src_incr*dst_incr; |
|
330 |
+ c->compensation_distance= compensation_distance; |
|
331 |
+ } |
|
332 |
+#if 0 |
|
333 |
+ if(update_ctx && !c->compensation_distance){ |
|
334 |
+#undef rand |
|
335 |
+ av_resample_compensate(c, rand() % (8000*2) - 8000, 8000*2); |
|
336 |
+av_log(NULL, AV_LOG_DEBUG, "%d %d %d\n", c->dst_incr, c->ideal_dst_incr, c->compensation_distance); |
|
337 |
+ } |
|
338 |
+#endif |
|
339 |
+ |
|
340 |
+ return dst_index; |
|
341 |
+} |
|
342 |
+ |
|
343 |
+int swr_multiple_resample(AVResampleContext *c, AudioData *dst, int dst_size, AudioData *src, int src_size, int *consumed){ |
|
344 |
+ int i, ret= -1; |
|
345 |
+ |
|
346 |
+ for(i=0; i<dst->ch_count; i++){ |
|
347 |
+ ret= swr_resample(c, dst->ch[i], src->ch[i], consumed, src_size, dst_size, i+1==dst->ch_count); |
|
348 |
+ } |
|
349 |
+ |
|
350 |
+ return ret; |
|
351 |
+} |
0 | 352 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,432 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2011 Michael Niedermayer (michaelni@gmx.at) |
|
2 |
+ * |
|
3 |
+ * This file is part of libswresample |
|
4 |
+ * |
|
5 |
+ * libswresample is free software; you can redistribute it and/or |
|
6 |
+ * modify it under the terms of the GNU Lesser General Public |
|
7 |
+ * License as published by the Free Software Foundation; either |
|
8 |
+ * version 2.1 of the License, or (at your option) any later version. |
|
9 |
+ * |
|
10 |
+ * libswresample is distributed in the hope that it will be useful, |
|
11 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 |
+ * Lesser General Public License for more details. |
|
14 |
+ * |
|
15 |
+ * You should have received a copy of the GNU Lesser General Public |
|
16 |
+ * License along with libswresample; if not, write to the Free Software |
|
17 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+#include "libavutil/opt.h" |
|
21 |
+#include "swresample_internal.h" |
|
22 |
+#include "audioconvert.h" |
|
23 |
+#include "libavutil/avassert.h" |
|
24 |
+ |
|
25 |
+#define C30DB M_SQRT2 |
|
26 |
+#define C15DB 1.189207115 |
|
27 |
+#define C__0DB 1.0 |
|
28 |
+#define C_15DB 0.840896415 |
|
29 |
+#define C_30DB M_SQRT1_2 |
|
30 |
+#define C_45DB 0.594603558 |
|
31 |
+#define C_60DB 0.5 |
|
32 |
+ |
|
33 |
+ |
|
34 |
+//TODO split options array out? |
|
35 |
+#define OFFSET(x) offsetof(SwrContext,x) |
|
36 |
+static const AVOption options[]={ |
|
37 |
+{"ich", "input channel count", OFFSET( in.ch_count ), FF_OPT_TYPE_INT, {.dbl=2}, 1, SWR_CH_MAX, 0}, |
|
38 |
+{"och", "output channel count", OFFSET(out.ch_count ), FF_OPT_TYPE_INT, {.dbl=2}, 1, SWR_CH_MAX, 0}, |
|
39 |
+{"isr", "input sample rate" , OFFSET( in_sample_rate), FF_OPT_TYPE_INT, {.dbl=48000}, 1, INT_MAX, 0}, |
|
40 |
+{"osr", "output sample rate" , OFFSET(out_sample_rate), FF_OPT_TYPE_INT, {.dbl=48000}, 1, INT_MAX, 0}, |
|
41 |
+{"ip" , "input planar" , OFFSET( in.planar ), FF_OPT_TYPE_INT, {.dbl=0}, 0, 1, 0}, |
|
42 |
+{"op" , "output planar" , OFFSET(out.planar ), FF_OPT_TYPE_INT, {.dbl=0}, 0, 1, 0}, |
|
43 |
+{"isf", "input sample format", OFFSET( in_sample_fmt ), FF_OPT_TYPE_INT, {.dbl=AV_SAMPLE_FMT_S16}, 0, AV_SAMPLE_FMT_NB-1, 0}, |
|
44 |
+{"osf", "output sample format", OFFSET(out_sample_fmt ), FF_OPT_TYPE_INT, {.dbl=AV_SAMPLE_FMT_S16}, 0, AV_SAMPLE_FMT_NB-1, 0}, |
|
45 |
+{"tsf", "internal sample format", OFFSET(int_sample_fmt ), FF_OPT_TYPE_INT, {.dbl=AV_SAMPLE_FMT_NONE}, -1, AV_SAMPLE_FMT_FLT, 0}, |
|
46 |
+{"icl", "input channel layout" , OFFSET( in_ch_layout), FF_OPT_TYPE_INT64, {.dbl=0}, 0, INT64_MAX, 0, "channel_layout"}, |
|
47 |
+{"ocl", "output channel layout", OFFSET(out_ch_layout), FF_OPT_TYPE_INT64, {.dbl=0}, 0, INT64_MAX, 0, "channel_layout"}, |
|
48 |
+{"clev", "center mix level" , OFFSET(clev) , FF_OPT_TYPE_FLOAT, {.dbl=C_30DB}, 0, 4, 0}, |
|
49 |
+{"slev", "sourround mix level" , OFFSET(slev) , FF_OPT_TYPE_FLOAT, {.dbl=C_30DB}, 0, 4, 0}, |
|
50 |
+{"flags", NULL , OFFSET(flags) , FF_OPT_TYPE_FLAGS, {.dbl=0}, 0, UINT_MAX, 0, "flags"}, |
|
51 |
+{"res", "force resampling", 0, FF_OPT_TYPE_CONST, {.dbl=SWR_FLAG_RESAMPLE}, INT_MIN, INT_MAX, 0, "flags"}, |
|
52 |
+ |
|
53 |
+{0} |
|
54 |
+}; |
|
55 |
+ |
|
56 |
+static const char* context_to_name(void* ptr) { |
|
57 |
+ return "SWR"; |
|
58 |
+} |
|
59 |
+ |
|
60 |
+static const AVClass av_class = { "SwrContext", context_to_name, options, LIBAVUTIL_VERSION_INT, OFFSET(log_level_offset), OFFSET(log_ctx) }; |
|
61 |
+ |
|
62 |
+static int resample(SwrContext *s, AudioData *out_param, int out_count, |
|
63 |
+ const AudioData * in_param, int in_count); |
|
64 |
+ |
|
65 |
+SwrContext *swr_alloc(void){ |
|
66 |
+ SwrContext *s= av_mallocz(sizeof(SwrContext)); |
|
67 |
+ if(s){ |
|
68 |
+ s->av_class= &av_class; |
|
69 |
+ av_opt_set_defaults2(s, 0, 0); |
|
70 |
+ } |
|
71 |
+ return s; |
|
72 |
+} |
|
73 |
+ |
|
74 |
+SwrContext *swr_alloc2(struct SwrContext *s, int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate, |
|
75 |
+ int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate, |
|
76 |
+ int log_offset, void *log_ctx){ |
|
77 |
+ if(!s) s= swr_alloc(); |
|
78 |
+ if(!s) return NULL; |
|
79 |
+ |
|
80 |
+ s->log_level_offset= log_offset; |
|
81 |
+ s->log_ctx= log_ctx; |
|
82 |
+ |
|
83 |
+ av_set_int(s, "ocl", out_ch_layout); |
|
84 |
+ av_set_int(s, "osf", out_sample_fmt); |
|
85 |
+ av_set_int(s, "osr", out_sample_rate); |
|
86 |
+ av_set_int(s, "icl", in_ch_layout); |
|
87 |
+ av_set_int(s, "isf", in_sample_fmt); |
|
88 |
+ av_set_int(s, "isr", in_sample_rate); |
|
89 |
+ |
|
90 |
+ s-> in.ch_count= av_get_channel_layout_nb_channels(s-> in_ch_layout); |
|
91 |
+ s->out.ch_count= av_get_channel_layout_nb_channels(s->out_ch_layout); |
|
92 |
+ s->int_sample_fmt = AV_SAMPLE_FMT_S16; |
|
93 |
+ |
|
94 |
+ return s; |
|
95 |
+} |
|
96 |
+ |
|
97 |
+ |
|
98 |
+static void free_temp(AudioData *a){ |
|
99 |
+ av_free(a->data); |
|
100 |
+ memset(a, 0, sizeof(*a)); |
|
101 |
+} |
|
102 |
+ |
|
103 |
+void swr_free(SwrContext **ss){ |
|
104 |
+ SwrContext *s= *ss; |
|
105 |
+ if(s){ |
|
106 |
+ free_temp(&s->postin); |
|
107 |
+ free_temp(&s->midbuf); |
|
108 |
+ free_temp(&s->preout); |
|
109 |
+ free_temp(&s->in_buffer); |
|
110 |
+ swr_audio_convert_free(&s-> in_convert); |
|
111 |
+ swr_audio_convert_free(&s->out_convert); |
|
112 |
+ swr_resample_free(&s->resample); |
|
113 |
+ } |
|
114 |
+ |
|
115 |
+ av_freep(ss); |
|
116 |
+} |
|
117 |
+ |
|
118 |
+static int64_t guess_layout(int ch){ |
|
119 |
+ switch(ch){ |
|
120 |
+ case 1: return AV_CH_LAYOUT_MONO; |
|
121 |
+ case 2: return AV_CH_LAYOUT_STEREO; |
|
122 |
+ case 5: return AV_CH_LAYOUT_5POINT0; |
|
123 |
+ case 6: return AV_CH_LAYOUT_5POINT1; |
|
124 |
+ case 7: return AV_CH_LAYOUT_7POINT0; |
|
125 |
+ case 8: return AV_CH_LAYOUT_7POINT1; |
|
126 |
+ default: return 0; |
|
127 |
+ } |
|
128 |
+} |
|
129 |
+ |
|
130 |
+int swr_init(SwrContext *s){ |
|
131 |
+ s->in_buffer_index= 0; |
|
132 |
+ s->in_buffer_count= 0; |
|
133 |
+ s->resample_in_constraint= 0; |
|
134 |
+ free_temp(&s->postin); |
|
135 |
+ free_temp(&s->midbuf); |
|
136 |
+ free_temp(&s->preout); |
|
137 |
+ free_temp(&s->in_buffer); |
|
138 |
+ swr_audio_convert_free(&s-> in_convert); |
|
139 |
+ swr_audio_convert_free(&s->out_convert); |
|
140 |
+ |
|
141 |
+ //We assume AVOptions checked the various values and the defaults where allowed |
|
142 |
+ if( s->int_sample_fmt != AV_SAMPLE_FMT_S16 |
|
143 |
+ &&s->int_sample_fmt != AV_SAMPLE_FMT_FLT){ |
|
144 |
+ 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)); |
|
145 |
+ return AVERROR(EINVAL); |
|
146 |
+ } |
|
147 |
+ |
|
148 |
+ //FIXME should we allow/support using FLT on material that doesnt need it ? |
|
149 |
+ if(s->in_sample_fmt <= AV_SAMPLE_FMT_S16 || s->int_sample_fmt==AV_SAMPLE_FMT_S16){ |
|
150 |
+ s->int_sample_fmt= AV_SAMPLE_FMT_S16; |
|
151 |
+ }else |
|
152 |
+ s->int_sample_fmt= AV_SAMPLE_FMT_FLT; |
|
153 |
+ |
|
154 |
+ |
|
155 |
+ if (s->out_sample_rate!=s->in_sample_rate || (s->flags & SWR_FLAG_RESAMPLE)){ |
|
156 |
+ s->resample = swr_resample_init(s->resample, s->out_sample_rate, s->in_sample_rate, 16, 10, 0, 0.8); |
|
157 |
+ }else |
|
158 |
+ swr_resample_free(&s->resample); |
|
159 |
+ if(s->int_sample_fmt != AV_SAMPLE_FMT_S16 && s->resample){ |
|
160 |
+ av_log(s, AV_LOG_ERROR, "Resampling only supported with internal s16 currently\n"); //FIXME |
|
161 |
+ return -1; |
|
162 |
+ } |
|
163 |
+ |
|
164 |
+ if(!s-> in_ch_layout) |
|
165 |
+ s-> in_ch_layout= guess_layout(s->in.ch_count); |
|
166 |
+ if(!s->out_ch_layout) |
|
167 |
+ s->out_ch_layout= guess_layout(s->out.ch_count); |
|
168 |
+ |
|
169 |
+ s->rematrix= s->out_ch_layout !=s->in_ch_layout; |
|
170 |
+ |
|
171 |
+#define RSC 1 //FIXME finetune |
|
172 |
+ if(!s-> in.ch_count) |
|
173 |
+ s-> in.ch_count= av_get_channel_layout_nb_channels(s-> in_ch_layout); |
|
174 |
+ if(!s->out.ch_count) |
|
175 |
+ s->out.ch_count= av_get_channel_layout_nb_channels(s->out_ch_layout); |
|
176 |
+ |
|
177 |
+av_assert0(s-> in.ch_count); |
|
178 |
+av_assert0(s->out.ch_count); |
|
179 |
+ s->resample_first= RSC*s->out.ch_count/s->in.ch_count - RSC < s->out_sample_rate/(float)s-> in_sample_rate - 1.0; |
|
180 |
+ |
|
181 |
+ s-> in.bps= av_get_bits_per_sample_fmt(s-> in_sample_fmt)/8; |
|
182 |
+ s->int_bps= av_get_bits_per_sample_fmt(s->int_sample_fmt)/8; |
|
183 |
+ s->out.bps= av_get_bits_per_sample_fmt(s->out_sample_fmt)/8; |
|
184 |
+ |
|
185 |
+ s->in_convert = swr_audio_convert_alloc(s->int_sample_fmt, |
|
186 |
+ s-> in_sample_fmt, s-> in.ch_count, 0); |
|
187 |
+ s->out_convert= swr_audio_convert_alloc(s->out_sample_fmt, |
|
188 |
+ s->int_sample_fmt, s->out.ch_count, 0); |
|
189 |
+ |
|
190 |
+ |
|
191 |
+ s->postin= s->in; |
|
192 |
+ s->preout= s->out; |
|
193 |
+ s->midbuf= s->in; |
|
194 |
+ s->in_buffer= s->in; |
|
195 |
+ if(!s->resample_first){ |
|
196 |
+ s->midbuf.ch_count= s->out.ch_count; |
|
197 |
+ s->in_buffer.ch_count = s->out.ch_count; |
|
198 |
+ } |
|
199 |
+ |
|
200 |
+ s->in_buffer.bps = s->postin.bps = s->midbuf.bps = s->preout.bps = s->int_bps; |
|
201 |
+ s->in_buffer.planar = s->postin.planar = s->midbuf.planar = s->preout.planar = 1; |
|
202 |
+ |
|
203 |
+ |
|
204 |
+ if(s->rematrix && swr_rematrix_init(s)<0) |
|
205 |
+ return -1; |
|
206 |
+ |
|
207 |
+ return 0; |
|
208 |
+} |
|
209 |
+ |
|
210 |
+static int realloc_audio(AudioData *a, int count){ |
|
211 |
+ int i, countb; |
|
212 |
+ AudioData old; |
|
213 |
+ |
|
214 |
+ if(a->count >= count) |
|
215 |
+ return 0; |
|
216 |
+ |
|
217 |
+ count*=2; |
|
218 |
+ |
|
219 |
+ countb= FFALIGN(count*a->bps, 32); |
|
220 |
+ old= *a; |
|
221 |
+ |
|
222 |
+ av_assert0(a->planar); |
|
223 |
+ av_assert0(a->bps); |
|
224 |
+ av_assert0(a->ch_count); |
|
225 |
+ |
|
226 |
+ a->data= av_malloc(countb*a->ch_count); |
|
227 |
+ if(!a->data) |
|
228 |
+ return AVERROR(ENOMEM); |
|
229 |
+ for(i=0; i<a->ch_count; i++){ |
|
230 |
+ a->ch[i]= a->data + i*(a->planar ? countb : a->bps); |
|
231 |
+ if(a->planar) memcpy(a->ch[i], old.ch[i], a->count*a->bps); |
|
232 |
+ } |
|
233 |
+ av_free(old.data); |
|
234 |
+ a->count= count; |
|
235 |
+ |
|
236 |
+ return 1; |
|
237 |
+} |
|
238 |
+ |
|
239 |
+static void copy(AudioData *out, AudioData *in, |
|
240 |
+ int count){ |
|
241 |
+ av_assert0(out->planar == in->planar); |
|
242 |
+ av_assert0(out->bps == in->bps); |
|
243 |
+ av_assert0(out->ch_count == in->ch_count); |
|
244 |
+ if(out->planar){ |
|
245 |
+ int ch; |
|
246 |
+ for(ch=0; ch<out->ch_count; ch++) |
|
247 |
+ memcpy(out->ch[ch], in->ch[ch], count*out->bps); |
|
248 |
+ }else |
|
249 |
+ memcpy(out->ch[0], in->ch[0], count*out->ch_count*out->bps); |
|
250 |
+} |
|
251 |
+ |
|
252 |
+int swr_convert(struct SwrContext *s, uint8_t *out_arg[SWR_CH_MAX], int out_count, |
|
253 |
+ const uint8_t *in_arg [SWR_CH_MAX], int in_count){ |
|
254 |
+ AudioData *postin, *midbuf, *preout; |
|
255 |
+ int ret, i/*, in_max*/; |
|
256 |
+ AudioData * in= &s->in; |
|
257 |
+ AudioData *out= &s->out; |
|
258 |
+ AudioData preout_tmp, midbuf_tmp; |
|
259 |
+ |
|
260 |
+ if(!s->resample){ |
|
261 |
+ if(in_count > out_count) |
|
262 |
+ return -1; |
|
263 |
+ out_count = in_count; |
|
264 |
+ } |
|
265 |
+ |
|
266 |
+ av_assert0(in ->planar == 0); |
|
267 |
+ av_assert0(out->planar == 0); |
|
268 |
+ for(i=0; i<s-> in.ch_count; i++) |
|
269 |
+ in ->ch[i]= in_arg[0] + i* in->bps; |
|
270 |
+ for(i=0; i<s->out.ch_count; i++) |
|
271 |
+ out->ch[i]= out_arg[0] + i*out->bps; |
|
272 |
+ |
|
273 |
+// in_max= out_count*(int64_t)s->in_sample_rate / s->out_sample_rate + resample_filter_taps; |
|
274 |
+// in_count= FFMIN(in_count, in_in + 2 - s->hist_buffer_count); |
|
275 |
+ |
|
276 |
+ if((ret=realloc_audio(&s->postin, in_count))<0) |
|
277 |
+ return ret; |
|
278 |
+ if(s->resample_first){ |
|
279 |
+ av_assert0(s->midbuf.ch_count == s-> in.ch_count); |
|
280 |
+ if((ret=realloc_audio(&s->midbuf, out_count))<0) |
|
281 |
+ return ret; |
|
282 |
+ }else{ |
|
283 |
+ av_assert0(s->midbuf.ch_count == s->out.ch_count); |
|
284 |
+ if((ret=realloc_audio(&s->midbuf, in_count))<0) |
|
285 |
+ return ret; |
|
286 |
+ } |
|
287 |
+ if((ret=realloc_audio(&s->preout, out_count))<0) |
|
288 |
+ return ret; |
|
289 |
+ |
|
290 |
+ postin= &s->postin; |
|
291 |
+ |
|
292 |
+ midbuf_tmp= s->midbuf; |
|
293 |
+ midbuf= &midbuf_tmp; |
|
294 |
+ preout_tmp= s->preout; |
|
295 |
+ preout= &preout_tmp; |
|
296 |
+ |
|
297 |
+ if(s->int_sample_fmt == s-> in_sample_fmt && s->in.planar) |
|
298 |
+ postin= in; |
|
299 |
+ |
|
300 |
+ if(s->resample_first ? !s->resample : !s->rematrix) |
|
301 |
+ midbuf= postin; |
|
302 |
+ |
|
303 |
+ if(s->resample_first ? !s->rematrix : !s->resample) |
|
304 |
+ preout= midbuf; |
|
305 |
+ |
|
306 |
+ if(s->int_sample_fmt == s->out_sample_fmt && s->out.planar){ |
|
307 |
+ if(preout==in){ |
|
308 |
+ out_count= FFMIN(out_count, in_count); //TODO check at teh end if this is needed or redundant |
|
309 |
+ av_assert0(s->in.planar); //we only support planar internally so it has to be, we support copying non planar though |
|
310 |
+ copy(out, in, out_count); |
|
311 |
+ return out_count; |
|
312 |
+ } |
|
313 |
+ else if(preout==postin) preout= midbuf= postin= out; |
|
314 |
+ else if(preout==midbuf) preout= midbuf= out; |
|
315 |
+ else preout= out; |
|
316 |
+ } |
|
317 |
+ |
|
318 |
+ if(in != postin){ |
|
319 |
+ swr_audio_convert(s->in_convert, postin, in, in_count); |
|
320 |
+ } |
|
321 |
+ |
|
322 |
+ if(s->resample_first){ |
|
323 |
+ if(postin != midbuf) |
|
324 |
+ out_count= resample(s, midbuf, out_count, postin, in_count); |
|
325 |
+ if(midbuf != preout) |
|
326 |
+ swr_rematrix(s, preout, midbuf, out_count, preout==out); |
|
327 |
+ }else{ |
|
328 |
+ if(postin != midbuf) |
|
329 |
+ swr_rematrix(s, midbuf, postin, in_count, midbuf==out); |
|
330 |
+ if(midbuf != preout) |
|
331 |
+ out_count= resample(s, preout, out_count, midbuf, in_count); |
|
332 |
+ } |
|
333 |
+ |
|
334 |
+ if(preout != out){ |
|
335 |
+//FIXME packed doesnt need more than 1 chan here! |
|
336 |
+ swr_audio_convert(s->out_convert, out, preout, out_count); |
|
337 |
+ } |
|
338 |
+ return out_count; |
|
339 |
+} |
|
340 |
+ |
|
341 |
+/** |
|
342 |
+ * |
|
343 |
+ * out may be equal in. |
|
344 |
+ */ |
|
345 |
+static void buf_set(AudioData *out, AudioData *in, int count){ |
|
346 |
+ if(in->planar){ |
|
347 |
+ int ch; |
|
348 |
+ for(ch=0; ch<out->ch_count; ch++) |
|
349 |
+ out->ch[ch]= in->ch[ch] + count*out->bps; |
|
350 |
+ }else |
|
351 |
+ out->ch[0]= in->ch[0] + count*out->ch_count*out->bps; |
|
352 |
+} |
|
353 |
+ |
|
354 |
+/** |
|
355 |
+ * |
|
356 |
+ * @return number of samples output per channel |
|
357 |
+ */ |
|
358 |
+static int resample(SwrContext *s, AudioData *out_param, int out_count, |
|
359 |
+ const AudioData * in_param, int in_count){ |
|
360 |
+ AudioData in, out, tmp; |
|
361 |
+ int ret_sum=0; |
|
362 |
+ int border=0; |
|
363 |
+ int ch_count= s->resample_first ? s->in.ch_count : s->out.ch_count; |
|
364 |
+ |
|
365 |
+ tmp=out=*out_param; |
|
366 |
+ in = *in_param; |
|
367 |
+ |
|
368 |
+ do{ |
|
369 |
+ int ret, size, consumed; |
|
370 |
+ if(!s->resample_in_constraint && s->in_buffer_count){ |
|
371 |
+ buf_set(&tmp, &s->in_buffer, s->in_buffer_index); |
|
372 |
+ ret= swr_multiple_resample(s->resample, &out, out_count, &tmp, s->in_buffer_count, &consumed); |
|
373 |
+ out_count -= ret; |
|
374 |
+ ret_sum += ret; |
|
375 |
+ buf_set(&out, &out, ret); |
|
376 |
+ s->in_buffer_count -= consumed; |
|
377 |
+ s->in_buffer_index += consumed; |
|
378 |
+ |
|
379 |
+ if(!in_count) |
|
380 |
+ break; |
|
381 |
+ if(s->in_buffer_count <= border){ |
|
382 |
+ buf_set(&in, &in, -s->in_buffer_count); |
|
383 |
+ in_count += s->in_buffer_count; |
|
384 |
+ s->in_buffer_count=0; |
|
385 |
+ s->in_buffer_index=0; |
|
386 |
+ border = 0; |
|
387 |
+ } |
|
388 |
+ } |
|
389 |
+ |
|
390 |
+ if(in_count && !s->in_buffer_count){ |
|
391 |
+ s->in_buffer_index=0; |
|
392 |
+ ret= swr_multiple_resample(s->resample, &out, out_count, &in, in_count, &consumed); |
|
393 |
+ out_count -= ret; |
|
394 |
+ ret_sum += ret; |
|
395 |
+ buf_set(&out, &out, ret); |
|
396 |
+ in_count -= consumed; |
|
397 |
+ buf_set(&in, &in, consumed); |
|
398 |
+ } |
|
399 |
+ |
|
400 |
+ //TODO is this check sane considering the advanced copy avoidance below |
|
401 |
+ size= s->in_buffer_index + s->in_buffer_count + in_count; |
|
402 |
+ if( size > s->in_buffer.count |
|
403 |
+ && s->in_buffer_count + in_count <= s->in_buffer_index){ |
|
404 |
+ buf_set(&tmp, &s->in_buffer, s->in_buffer_index); |
|
405 |
+ copy(&s->in_buffer, &tmp, s->in_buffer_count); |
|
406 |
+ s->in_buffer_index=0; |
|
407 |
+ }else |
|
408 |
+ if((ret=realloc_audio(&s->in_buffer, size)) < 0) |
|
409 |
+ return ret; |
|
410 |
+ |
|
411 |
+ if(in_count){ |
|
412 |
+ int count= in_count; |
|
413 |
+ if(s->in_buffer_count && s->in_buffer_count+2 < count && out_count) count= s->in_buffer_count+2; |
|
414 |
+ |
|
415 |
+ buf_set(&tmp, &s->in_buffer, s->in_buffer_index + s->in_buffer_count); |
|
416 |
+ copy(&tmp, &in, /*in_*/count); |
|
417 |
+ s->in_buffer_count += count; |
|
418 |
+ in_count -= count; |
|
419 |
+ border += count; |
|
420 |
+ buf_set(&in, &in, count); |
|
421 |
+ s->resample_in_constraint= 0; |
|
422 |
+ if(s->in_buffer_count != count || in_count) |
|
423 |
+ continue; |
|
424 |
+ } |
|
425 |
+ break; |
|
426 |
+ }while(1); |
|
427 |
+ |
|
428 |
+ s->resample_in_constraint= !!out_count; |
|
429 |
+ |
|
430 |
+ return ret_sum; |
|
431 |
+} |
0 | 432 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,79 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2011 Michael Niedermayer (michaelni@gmx.at) |
|
2 |
+ * |
|
3 |
+ * This file is part of libswresample |
|
4 |
+ * |
|
5 |
+ * libswresample is free software; you can redistribute it and/or |
|
6 |
+ * modify it under the terms of the GNU Lesser General Public |
|
7 |
+ * License as published by the Free Software Foundation; either |
|
8 |
+ * version 2.1 of the License, or (at your option) any later version. |
|
9 |
+ * |
|
10 |
+ * libswresample is distributed in the hope that it will be useful, |
|
11 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 |
+ * Lesser General Public License for more details. |
|
14 |
+ * |
|
15 |
+ * You should have received a copy of the GNU Lesser General Public |
|
16 |
+ * License along with libswresample; if not, write to the Free Software |
|
17 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+#ifndef SWR_H |
|
21 |
+#define SWR_H |
|
22 |
+ |
|
23 |
+#include <inttypes.h> |
|
24 |
+#include "libavutil/samplefmt.h" |
|
25 |
+ |
|
26 |
+#define LIBSWRESAMPLE_VERSION_MAJOR 0 |
|
27 |
+#define LIBSWRESAMPLE_VERSION_MINOR 0 |
|
28 |
+#define LIBSWRESAMPLE_VERSION_MICRO 0 |
|
29 |
+ |
|
30 |
+#define SWR_CH_MAX 16 |
|
31 |
+ |
|
32 |
+#define SWR_FLAG_RESAMPLE 1///< Force resampling even if equal sample rate |
|
33 |
+//TODO use int resample ? |
|
34 |
+//long term TODO can we enable this dynamically? |
|
35 |
+ |
|
36 |
+ |
|
37 |
+struct SwrContext; |
|
38 |
+ |
|
39 |
+/** |
|
40 |
+ * Allocate SwrContext. |
|
41 |
+ * @see swr_init(),swr_free() |
|
42 |
+ * @return NULL on error |
|
43 |
+ */ |
|
44 |
+struct SwrContext *swr_alloc(void); |
|
45 |
+ |
|
46 |
+/** |
|
47 |
+ * Initialize context after user parameters have been set. |
|
48 |
+ * @return negativo n error |
|
49 |
+ */ |
|
50 |
+int swr_init(struct SwrContext *s); |
|
51 |
+ |
|
52 |
+/** |
|
53 |
+ * Allocate SwrContext. |
|
54 |
+ * @see swr_init(),swr_free() |
|
55 |
+ * @return NULL on error |
|
56 |
+ */ |
|
57 |
+struct SwrContext *swr_alloc2(struct SwrContext *s, int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate, |
|
58 |
+ int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate, |
|
59 |
+ int log_offset, void *log_ctx); |
|
60 |
+ |
|
61 |
+/** |
|
62 |
+ * Free the given SwrContext. |
|
63 |
+ * And set the pointer to NULL |
|
64 |
+ */ |
|
65 |
+void swr_free(struct SwrContext **s); |
|
66 |
+ |
|
67 |
+/** |
|
68 |
+ * Convert audio. |
|
69 |
+ * @param in_count Number of input samples available in one channel. |
|
70 |
+ * @param out_count Amount of space available for output in samples per channel. |
|
71 |
+ * @return number of samples output per channel |
|
72 |
+ */ |
|
73 |
+int swr_convert(struct SwrContext *s, uint8_t *out[SWR_CH_MAX], int out_count, |
|
74 |
+ const uint8_t *in [SWR_CH_MAX], int in_count); |
|
75 |
+ |
|
76 |
+void swr_compensate(struct SwrContext *s, int sample_delta, int compensation_distance); |
|
77 |
+ |
|
78 |
+#endif |
0 | 79 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,77 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2011 Michael Niedermayer (michaelni@gmx.at) |
|
2 |
+ * |
|
3 |
+ * This file is part of libswresample |
|
4 |
+ * |
|
5 |
+ * libswresample is free software; you can redistribute it and/or |
|
6 |
+ * modify it under the terms of the GNU Lesser General Public |
|
7 |
+ * License as published by the Free Software Foundation; either |
|
8 |
+ * version 2.1 of the License, or (at your option) any later version. |
|
9 |
+ * |
|
10 |
+ * libswresample is distributed in the hope that it will be useful, |
|
11 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 |
+ * Lesser General Public License for more details. |
|
14 |
+ * |
|
15 |
+ * You should have received a copy of the GNU Lesser General Public |
|
16 |
+ * License along with libswresample; if not, write to the Free Software |
|
17 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+#ifndef SWR_INTERNAL_H |
|
21 |
+#define SWR_INTERNAL_H |
|
22 |
+ |
|
23 |
+#include "swresample.h" |
|
24 |
+ |
|
25 |
+typedef struct AudioData{ |
|
26 |
+ uint8_t *ch[SWR_CH_MAX]; |
|
27 |
+ uint8_t *data; |
|
28 |
+ int ch_count; |
|
29 |
+ int bps; |
|
30 |
+ int count; |
|
31 |
+ int planar; |
|
32 |
+} AudioData; |
|
33 |
+ |
|
34 |
+typedef struct SwrContext { //FIXME find unused fields |
|
35 |
+ AVClass *av_class; |
|
36 |
+ int log_level_offset; |
|
37 |
+ void *log_ctx; |
|
38 |
+ enum AVSampleFormat in_sample_fmt; |
|
39 |
+ enum AVSampleFormat int_sample_fmt; ///<AV_SAMPLE_FMT_FLT OR AV_SAMPLE_FMT_S16 |
|
40 |
+ enum AVSampleFormat out_sample_fmt; |
|
41 |
+ int64_t in_ch_layout; |
|
42 |
+ int64_t out_ch_layout; |
|
43 |
+ int in_sample_rate; |
|
44 |
+ int out_sample_rate; |
|
45 |
+ int flags; |
|
46 |
+ float slev, clev; |
|
47 |
+ |
|
48 |
+ //below are private |
|
49 |
+ int int_bps; |
|
50 |
+ int resample_first; |
|
51 |
+ int rematrix; ///< flag to indicate if rematrixing is used |
|
52 |
+ |
|
53 |
+ AudioData in, postin, midbuf, preout, out, in_buffer; |
|
54 |
+ int in_buffer_index; |
|
55 |
+ int in_buffer_count; |
|
56 |
+ int resample_in_constraint; |
|
57 |
+ |
|
58 |
+ struct AVAudioConvert *in_convert; |
|
59 |
+ struct AVAudioConvert *out_convert; |
|
60 |
+ struct AVResampleContext *resample; |
|
61 |
+ |
|
62 |
+ float matrix[SWR_CH_MAX][SWR_CH_MAX]; |
|
63 |
+ uint8_t matrix_ch[SWR_CH_MAX][SWR_CH_MAX+1]; |
|
64 |
+ |
|
65 |
+ //TODO callbacks for asm optims |
|
66 |
+}SwrContext; |
|
67 |
+ |
|
68 |
+struct AVResampleContext *swr_resample_init(struct AVResampleContext *, int out_rate, int in_rate, int filter_size, int phase_shift, int linear, double cutoff); |
|
69 |
+void swr_resample_free(struct AVResampleContext **c); |
|
70 |
+int swr_multiple_resample(struct AVResampleContext *c, AudioData *dst, int dst_size, AudioData *src, int src_size, int *consumed); |
|
71 |
+void swr_resample_compensate(struct AVResampleContext *c, int sample_delta, int compensation_distance); |
|
72 |
+int swr_resample(struct AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx); |
|
73 |
+ |
|
74 |
+int swr_rematrix_init(SwrContext *s); |
|
75 |
+int swr_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy); |
|
76 |
+#endif |
0 | 77 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,149 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2011 Michael Niedermayer (michaelni@gmx.at) |
|
2 |
+ * |
|
3 |
+ * This file is part of libswresample |
|
4 |
+ * |
|
5 |
+ * libswresample is free software; you can redistribute it and/or modify |
|
6 |
+ * it under the terms of the GNU General Public License as published by |
|
7 |
+ * the Free Software Foundation; either version 2 of the License, or |
|
8 |
+ * (at your option) any later version. |
|
9 |
+ * |
|
10 |
+ * libswresample is distributed in the hope that it will be useful, |
|
11 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 |
+ * GNU General Public License for more details. |
|
14 |
+ * |
|
15 |
+ * You should have received a copy of the GNU General Public License |
|
16 |
+ * along with libswresample; if not, write to the Free Software |
|
17 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+#include "libavutil/avassert.h" |
|
21 |
+#include "libavutil/common.h" |
|
22 |
+#include "libavutil/audioconvert.h" |
|
23 |
+#include "swresample.h" |
|
24 |
+#undef fprintf |
|
25 |
+ |
|
26 |
+#define SAMPLES 1000 |
|
27 |
+ |
|
28 |
+#define ASSERT_LEVEL 2 |
|
29 |
+ |
|
30 |
+static double get(const void *p, int index, enum AVSampleFormat f){ |
|
31 |
+ switch(f){ |
|
32 |
+ case AV_SAMPLE_FMT_U8 : return ((const uint8_t*)p)[index]/255.0*2-1.0; |
|
33 |
+ case AV_SAMPLE_FMT_S16: return ((const int16_t*)p)[index]/32767.0; |
|
34 |
+ case AV_SAMPLE_FMT_S32: return ((const int32_t*)p)[index]/2147483647.0; |
|
35 |
+ case AV_SAMPLE_FMT_FLT: return ((const float *)p)[index]; |
|
36 |
+ case AV_SAMPLE_FMT_DBL: return ((const double *)p)[index]; |
|
37 |
+ default: av_assert2(0); |
|
38 |
+ } |
|
39 |
+} |
|
40 |
+ |
|
41 |
+static void set(void *p, int index, enum AVSampleFormat f, double v){ |
|
42 |
+ switch(f){ |
|
43 |
+ case AV_SAMPLE_FMT_U8 : ((uint8_t*)p)[index]= (v+1.0)*255.0/2; break; |
|
44 |
+ case AV_SAMPLE_FMT_S16: ((int16_t*)p)[index]= v*32767; break; |
|
45 |
+ case AV_SAMPLE_FMT_S32: ((int32_t*)p)[index]= v*2147483647; break; |
|
46 |
+ case AV_SAMPLE_FMT_FLT: ((float *)p)[index]= v; break; |
|
47 |
+ case AV_SAMPLE_FMT_DBL: ((double *)p)[index]= v; break; |
|
48 |
+ default: av_assert2(0); |
|
49 |
+ } |
|
50 |
+} |
|
51 |
+ |
|
52 |
+uint64_t layouts[]={ |
|
53 |
+AV_CH_LAYOUT_MONO , |
|
54 |
+AV_CH_LAYOUT_STEREO , |
|
55 |
+AV_CH_LAYOUT_2_1 , |
|
56 |
+AV_CH_LAYOUT_SURROUND , |
|
57 |
+AV_CH_LAYOUT_4POINT0 , |
|
58 |
+AV_CH_LAYOUT_2_2 , |
|
59 |
+AV_CH_LAYOUT_QUAD , |
|
60 |
+AV_CH_LAYOUT_5POINT0 , |
|
61 |
+AV_CH_LAYOUT_5POINT1 , |
|
62 |
+AV_CH_LAYOUT_5POINT0_BACK , |
|
63 |
+AV_CH_LAYOUT_5POINT1_BACK , |
|
64 |
+AV_CH_LAYOUT_7POINT0 , |
|
65 |
+AV_CH_LAYOUT_7POINT1 , |
|
66 |
+AV_CH_LAYOUT_7POINT1_WIDE , |
|
67 |
+0 |
|
68 |
+}; |
|
69 |
+ |
|
70 |
+int main(int argc, char **argv){ |
|
71 |
+ int in_sample_rate, out_sample_rate, ch ,i, in_ch_layout_index, out_ch_layout_index, osr; |
|
72 |
+ uint64_t in_ch_layout, out_ch_layout; |
|
73 |
+ enum AVSampleFormat in_sample_fmt, out_sample_fmt; |
|
74 |
+ int sample_rates[]={8000,11025,16000,22050,32000}; |
|
75 |
+ uint8_t array_in[SAMPLES*8*8]; |
|
76 |
+ uint8_t array_mid[SAMPLES*8*8*3]; |
|
77 |
+ uint8_t array_out[SAMPLES*8*8+100]; |
|
78 |
+ struct SwrContext * forw_ctx= NULL; |
|
79 |
+ struct SwrContext *backw_ctx= NULL; |
|
80 |
+ |
|
81 |
+ in_sample_rate=16000; |
|
82 |
+ for(osr=0; osr<5; osr++){ |
|
83 |
+ out_sample_rate= sample_rates[osr]; |
|
84 |
+ for(in_sample_fmt= AV_SAMPLE_FMT_U8; in_sample_fmt<=AV_SAMPLE_FMT_DBL; in_sample_fmt++){ |
|
85 |
+ for(out_sample_fmt= AV_SAMPLE_FMT_U8; out_sample_fmt<=AV_SAMPLE_FMT_DBL; out_sample_fmt++){ |
|
86 |
+ for(in_ch_layout_index=0; layouts[in_ch_layout_index]; in_ch_layout_index++){ |
|
87 |
+ in_ch_layout= layouts[in_ch_layout_index]; |
|
88 |
+ int in_ch_count= av_get_channel_layout_nb_channels(in_ch_layout); |
|
89 |
+ for(out_ch_layout_index=0; layouts[out_ch_layout_index]; out_ch_layout_index++){ |
|
90 |
+ int out_count, mid_count; |
|
91 |
+ out_ch_layout= layouts[out_ch_layout_index]; |
|
92 |
+ int out_ch_count= av_get_channel_layout_nb_channels(out_ch_layout); |
|
93 |
+ fprintf(stderr, "ch %d->%d, rate:%5d->%5d, fmt:%s->%s", |
|
94 |
+ in_ch_count, out_ch_count, |
|
95 |
+ in_sample_rate, out_sample_rate, |
|
96 |
+ av_get_sample_fmt_name(in_sample_fmt), av_get_sample_fmt_name(out_sample_fmt)); |
|
97 |
+ forw_ctx = swr_alloc2(forw_ctx, out_ch_layout, out_sample_fmt, out_sample_rate, |
|
98 |
+ in_ch_layout, in_sample_fmt, in_sample_rate, 0, 0); |
|
99 |
+ backw_ctx = swr_alloc2(backw_ctx,in_ch_layout, in_sample_fmt, in_sample_rate, |
|
100 |
+ out_ch_layout, out_sample_fmt, out_sample_rate, 0, 0); |
|
101 |
+ if(swr_init( forw_ctx) < 0) |
|
102 |
+ fprintf(stderr, "swr_init(->) failed\n"); |
|
103 |
+ if(swr_init(backw_ctx) < 0) |
|
104 |
+ fprintf(stderr, "swr_init(<-) failed\n"); |
|
105 |
+ if(!forw_ctx) |
|
106 |
+ fprintf(stderr, "Failed to init forw_cts\n"); |
|
107 |
+ if(!backw_ctx) |
|
108 |
+ fprintf(stderr, "Failed to init backw_ctx\n"); |
|
109 |
+ //FIXME test planar |
|
110 |
+ for(ch=0; ch<in_ch_count; ch++){ |
|
111 |
+ for(i=0; i<SAMPLES; i++) |
|
112 |
+ set(array_in, ch + i*in_ch_count, in_sample_fmt, sin(i*i*3/SAMPLES)); |
|
113 |
+ } |
|
114 |
+ mid_count= swr_convert(forw_ctx, ( uint8_t*[]){array_mid}, 3*SAMPLES, |
|
115 |
+ (const uint8_t*[]){array_in }, SAMPLES); |
|
116 |
+ out_count= swr_convert(backw_ctx,( uint8_t*[]){array_out}, 3*SAMPLES, |
|
117 |
+ (const uint8_t*[]){array_mid}, mid_count); |
|
118 |
+ for(ch=0; ch<in_ch_count; ch++){ |
|
119 |
+ double sse, x, maxdiff=0; |
|
120 |
+ double sum_a= 0; |
|
121 |
+ double sum_b= 0; |
|
122 |
+ double sum_aa= 0; |
|
123 |
+ double sum_bb= 0; |
|
124 |
+ double sum_ab= 0; |
|
125 |
+ for(i=0; i<SAMPLES; i++){ |
|
126 |
+ double a= get(array_in , ch + i*in_ch_count, in_sample_fmt); |
|
127 |
+ double b= get(array_out, ch + i*in_ch_count, in_sample_fmt); |
|
128 |
+ sum_a += a; |
|
129 |
+ sum_b += b; |
|
130 |
+ sum_aa+= a*a; |
|
131 |
+ sum_bb+= b*b; |
|
132 |
+ sum_ab+= a*b; |
|
133 |
+ maxdiff= FFMAX(maxdiff, FFABS(a-b)); |
|
134 |
+ } |
|
135 |
+ x = sum_ab/sum_bb; |
|
136 |
+ sse= sum_aa + sum_bb*x*x - 2*x*sum_ab; |
|
137 |
+ |
|
138 |
+ fprintf(stderr, "[%f %f %f] len:%5d\n", sqrt(sse/SAMPLES), x, maxdiff, out_count); |
|
139 |
+ } |
|
140 |
+ fprintf(stderr, "\n"); |
|
141 |
+ } |
|
142 |
+ } |
|
143 |
+ } |
|
144 |
+ } |
|
145 |
+ } |
|
146 |
+ |
|
147 |
+ return 0; |
|
148 |
+} |
... | ... |
@@ -1,4 +1,4 @@ |
1 |
-fd090ddf05cc3401cc75c4a5ace1d05a *./tests/data/acodec/g726.wav |
|
1 |
+a76fc937faac62c5de057cd69191732a *./tests/data/acodec/g726.wav |
|
2 | 2 |
24052 ./tests/data/acodec/g726.wav |
3 |
-74abea06027375111eeac1b2f8c7d3af *./tests/data/g726.acodec.out.wav |
|
4 |
-stddev: 8554.55 PSNR: 17.69 MAXDIFF:29353 bytes: 95984/ 1058400 |
|
3 |
+124de13e6cb5af64ea8758aa49feb7fc *./tests/data/g726.acodec.out.wav |
|
4 |
+stddev: 8554.23 PSNR: 17.69 MAXDIFF:29353 bytes: 95984/ 1058400 |
... | ... |
@@ -66,7 +66,7 @@ stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400 |
66 | 66 |
529256 ./tests/data/acodec/pcm_zork.wav |
67 | 67 |
864c8c866ac25642c29a13b122c70709 *./tests/data/pcm.acodec.out.wav |
68 | 68 |
stddev: 633.11 PSNR: 40.30 MAXDIFF:32768 bytes: 1058400/ 1058400 |
69 |
-8168a5c1343553ef027541830f2cb879 *./tests/data/acodec/pcm_s24daud.302 |
|
69 |
+1b75d5198ae789ab3c48f7024e08f4a9 *./tests/data/acodec/pcm_s24daud.302 |
|
70 | 70 |
10368730 ./tests/data/acodec/pcm_s24daud.302 |
71 |
-f552afadfdfcd6348a07095da6382de5 *./tests/data/pcm.acodec.out.wav |
|
72 |
-stddev: 9416.28 PSNR: 16.85 MAXDIFF:42744 bytes: 6911796/ 1058400 |
|
71 |
+4708f86529c594e29404603c64bb208c *./tests/data/pcm.acodec.out.wav |
|
72 |
+stddev: 8967.92 PSNR: 17.28 MAXDIFF:42548 bytes: 6911796/ 1058400 |
... | ... |
@@ -1,3 +1,3 @@ |
1 |
-b3174e2db508564c1cce0b5e3c1bc1bd *./tests/data/lavf/lavf.mxf_d10 |
|
1 |
+8eb67301f72f2b5860fafab422b920ad *./tests/data/lavf/lavf.mxf_d10 |
|
2 | 2 |
5330989 ./tests/data/lavf/lavf.mxf_d10 |
3 |
-./tests/data/lavf/lavf.mxf_d10 CRC=0xc3f4f92e |
|
3 |
+./tests/data/lavf/lavf.mxf_d10 CRC=0x96c02dfd |