summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libswresample/Makefile2
-rw-r--r--libswresample/dither.c56
-rw-r--r--libswresample/rematrix.c19
-rw-r--r--libswresample/swresample.c20
-rw-r--r--libswresample/swresample.h7
-rw-r--r--libswresample/swresample_internal.h5
6 files changed, 98 insertions, 11 deletions
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; i<len; i++){
+ double v;
+ seed = seed* 1664525 + 1013904223;
+
+ switch(method){
+ case SWR_DITHER_RECTANGULAR: v= ((double)seed) / UINT_MAX - 0.5; break;
+ default: av_assert0(0);
+ }
+
+ v*= scale;
+
+ switch(in_fmt){
+ case AV_SAMPLE_FMT_S16: ((int16_t*)dst)[i] = v; break;
+ case AV_SAMPLE_FMT_S32: ((int32_t*)dst)[i] = v; break;
+ case AV_SAMPLE_FMT_FLT: ((float *)dst)[i] = v; break;
+ case AV_SAMPLE_FMT_DBL: ((double *)dst)[i] = v; break;
+ default: av_assert0(0);
+ }
+ }
+}
diff --git a/libswresample/rematrix.c b/libswresample/rematrix.c
index e9f919cf50..1dc8ffbaa4 100644
--- a/libswresample/rematrix.c
+++ b/libswresample/rematrix.c
@@ -272,6 +272,14 @@ int swri_rematrix_init(SwrContext *s){
return 0;
}
+void swri_sum2(enum AVSampleFormat format, void *dst, const void *src0, const void *src1, float coef0, float coef1, int len){
+ if(format == AV_SAMPLE_FMT_FLT){
+ sum2_float((float *)dst, (const float *)src0, (const float *)src1, coef0, coef1, len);
+ }else{
+ sum2_s16 ((int16_t*)dst, (const int16_t*)src0, (const int16_t*)src1, lrintf(coef0 * 32768), lrintf(coef1 * 32768), len);
+ }
+}
+
int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy){
int out_i, in_i, i, j;
@@ -295,15 +303,8 @@ int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mus
}
break;
case 2:
- if(s->int_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; ch<s->dither.ch_count; ch++)
+ swri_get_dither(s->dither.ch[ch], s->dither.count, 12345678913579<<ch, s->out_sample_fmt, s->int_sample_fmt, s->dither_method);
+ av_assert0(s->dither.ch_count == preout->ch_count);
+
+ for(ch=0; ch<preout->ch_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