diff --git a/libswresample/Makefile b/libswresample/Makefile index 6393598ab7..6e4e468495 100644 --- a/libswresample/Makefile +++ b/libswresample/Makefile @@ -5,6 +5,6 @@ FFLIBS = avutil HEADERS = swresample.h -OBJS = swresample.o audioconvert.o resample.o rematrix.o +OBJS = swresample.o audioconvert.o resample.o rematrix.o dither.o TESTPROGS = swresample_test diff --git a/libswresample/dither.c b/libswresample/dither.c new file mode 100644 index 0000000000..4e39cceb0d --- /dev/null +++ b/libswresample/dither.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2012 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/avassert.h" +#include "swresample_internal.h" + +void swri_get_dither(void *dst, int len, unsigned seed, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, enum SwrDitherType method) { + double scale = 0; + int i; + + if(in_fmt == AV_SAMPLE_FMT_FLT || in_fmt == AV_SAMPLE_FMT_DBL){ + if(out_fmt == AV_SAMPLE_FMT_S32) scale = 1.0/(1L<<31); + if(out_fmt == AV_SAMPLE_FMT_S16) scale = 1.0/(1L<<15); + if(out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1.0/(1L<< 7); + } + if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_S16) scale = 1L<<16; + if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1L<<24; + if(in_fmt == AV_SAMPLE_FMT_S16 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1L<<8; + + for(i=0; iint_sample_fmt == AV_SAMPLE_FMT_FLT){ - sum2_float((float *)out->ch[out_i], (const float *)in->ch[ s->matrix_ch[out_i][1] ], (const float *)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 ((int16_t*)out->ch[out_i], (const int16_t*)in->ch[ s->matrix_ch[out_i][1] ], (const int16_t*)in->ch[ s->matrix_ch[out_i][2] ], - s->matrix32[out_i][ s->matrix_ch[out_i][1] ], s->matrix32[out_i][ s->matrix_ch[out_i][2] ], - len); - } + swri_sum2(s->int_sample_fmt, 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){ diff --git a/libswresample/swresample.c b/libswresample/swresample.c index 73e88f08dc..23b7449930 100644 --- a/libswresample/swresample.c +++ b/libswresample/swresample.c @@ -53,6 +53,7 @@ static const AVOption options[]={ {"rmvol", "rematrix volume" , OFFSET(rematrix_volume), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, -1000, 1000, 0}, {"flags", NULL , OFFSET(flags) , AV_OPT_TYPE_FLAGS, {.dbl=0}, 0, UINT_MAX, 0, "flags"}, {"res", "force resampling", 0, AV_OPT_TYPE_CONST, {.dbl=SWR_FLAG_RESAMPLE}, INT_MIN, INT_MAX, 0, "flags"}, +{"dither", "dither method" , OFFSET(dither_method), AV_OPT_TYPE_INT, {.dbl=0}, 0, SWR_DITHER_NB-1, 0}, {0} }; @@ -139,6 +140,7 @@ void swr_free(SwrContext **ss){ free_temp(&s->midbuf); free_temp(&s->preout); free_temp(&s->in_buffer); + free_temp(&s->dither); swri_audio_convert_free(&s-> in_convert); swri_audio_convert_free(&s->out_convert); swri_audio_convert_free(&s->full_convert); @@ -156,6 +158,7 @@ int swr_init(struct SwrContext *s){ free_temp(&s->midbuf); free_temp(&s->preout); free_temp(&s->in_buffer); + free_temp(&s->dither); swri_audio_convert_free(&s-> in_convert); swri_audio_convert_free(&s->out_convert); swri_audio_convert_free(&s->full_convert); @@ -281,6 +284,8 @@ av_assert0(s->out.ch_count); s->in_buffer.planar = 1; } + s->dither = s->preout; + if(s->rematrix) return swri_rematrix_init(s); @@ -505,6 +510,21 @@ static int swr_convert_internal(struct SwrContext *s, AudioData *out, int out_co } if(preout != out && out_count){ + if(s->dither_method){ + int ch, i; + av_assert0(preout != in); + + if((ret=realloc_audio(&s->dither, out_count))<0) + return ret; + if(ret) + for(ch=0; chdither.ch_count; ch++) + swri_get_dither(s->dither.ch[ch], s->dither.count, 12345678913579<out_sample_fmt, s->int_sample_fmt, s->dither_method); + av_assert0(s->dither.ch_count == preout->ch_count); + + for(ch=0; chch_count; ch++){ + swri_sum2(s->int_sample_fmt, preout->ch[ch], preout->ch[ch], s->dither.ch[ch], 1, 1, out_count); + } + } //FIXME packed doesnt need more than 1 chan here! swri_audio_convert(s->out_convert, out, preout, out_count); } diff --git a/libswresample/swresample.h b/libswresample/swresample.h index f912bac042..1f87617d9d 100644 --- a/libswresample/swresample.h +++ b/libswresample/swresample.h @@ -30,7 +30,7 @@ #include "libavutil/samplefmt.h" #define LIBSWRESAMPLE_VERSION_MAJOR 0 -#define LIBSWRESAMPLE_VERSION_MINOR 10 +#define LIBSWRESAMPLE_VERSION_MINOR 11 #define LIBSWRESAMPLE_VERSION_MICRO 100 #define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \ @@ -45,6 +45,11 @@ //TODO use int resample ? //long term TODO can we enable this dynamically? +enum SwrDitherType { + SWR_DITHER_NONE = 0, + SWR_DITHER_RECTANGULAR, + SWR_DITHER_NB, ///< not part of API/ABI +}; typedef struct SwrContext SwrContext; diff --git a/libswresample/swresample_internal.h b/libswresample/swresample_internal.h index 618afc11ff..ebc275913d 100644 --- a/libswresample/swresample_internal.h +++ b/libswresample/swresample_internal.h @@ -49,6 +49,7 @@ struct SwrContext { float rematrix_volume; ///< rematrixing volume coefficient const int *channel_map; ///< channel index (or -1 if muted channel) map int used_ch_count; ///< number of used input channels (mapped channel count if channel_map, otherwise in.ch_count) + enum SwrDitherType dither_method; int int_bps; ///< internal bytes per sample int resample_first; ///< 1 if resampling must come first, 0 if rematrixing @@ -61,6 +62,7 @@ struct SwrContext { AudioData preout; ///< pre-output audio data: used for rematrix/resample AudioData out; ///< converted output audio data AudioData in_buffer; ///< cached audio data (convert and resample purpose) + AudioData dither; ///< cached audio data (convert and resample purpose) int in_buffer_index; ///< cached buffer position int in_buffer_count; ///< cached buffer length int resample_in_constraint; ///< 1 if the input end was reach before the output end, 0 otherwise @@ -89,5 +91,8 @@ int swri_resample_double(struct ResampleContext *c,double *dst, const double * int swri_rematrix_init(SwrContext *s); int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy); +void swri_sum2(enum AVSampleFormat format, void *dst, const void *src0, const void *src1, float coef0, float coef1, int len); + +void swri_get_dither(void *dst, int len, unsigned seed, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, enum SwrDitherType type); #endif