Signed-off-by: Michael Niedermayer <michaelni@gmx.at>tags/n0.11
@@ -5,6 +5,6 @@ FFLIBS = avutil | |||||
HEADERS = swresample.h | 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 | TESTPROGS = swresample_test |
@@ -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); | |||||
} | |||||
} | |||||
} |
@@ -272,6 +272,14 @@ int swri_rematrix_init(SwrContext *s){ | |||||
return 0; | 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 swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy){ | ||||
int out_i, in_i, i, j; | 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; | break; | ||||
case 2: | 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; | break; | ||||
default: | default: | ||||
if(s->int_sample_fmt == AV_SAMPLE_FMT_FLT){ | if(s->int_sample_fmt == AV_SAMPLE_FMT_FLT){ | ||||
@@ -53,6 +53,7 @@ static const AVOption options[]={ | |||||
{"rmvol", "rematrix volume" , OFFSET(rematrix_volume), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, -1000, 1000, 0}, | {"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"}, | {"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"}, | {"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} | {0} | ||||
}; | }; | ||||
@@ -139,6 +140,7 @@ void swr_free(SwrContext **ss){ | |||||
free_temp(&s->midbuf); | free_temp(&s->midbuf); | ||||
free_temp(&s->preout); | free_temp(&s->preout); | ||||
free_temp(&s->in_buffer); | free_temp(&s->in_buffer); | ||||
free_temp(&s->dither); | |||||
swri_audio_convert_free(&s-> in_convert); | swri_audio_convert_free(&s-> in_convert); | ||||
swri_audio_convert_free(&s->out_convert); | swri_audio_convert_free(&s->out_convert); | ||||
swri_audio_convert_free(&s->full_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->midbuf); | ||||
free_temp(&s->preout); | free_temp(&s->preout); | ||||
free_temp(&s->in_buffer); | free_temp(&s->in_buffer); | ||||
free_temp(&s->dither); | |||||
swri_audio_convert_free(&s-> in_convert); | swri_audio_convert_free(&s-> in_convert); | ||||
swri_audio_convert_free(&s->out_convert); | swri_audio_convert_free(&s->out_convert); | ||||
swri_audio_convert_free(&s->full_convert); | swri_audio_convert_free(&s->full_convert); | ||||
@@ -281,6 +284,8 @@ av_assert0(s->out.ch_count); | |||||
s->in_buffer.planar = 1; | s->in_buffer.planar = 1; | ||||
} | } | ||||
s->dither = s->preout; | |||||
if(s->rematrix) | if(s->rematrix) | ||||
return swri_rematrix_init(s); | 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(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! | //FIXME packed doesnt need more than 1 chan here! | ||||
swri_audio_convert(s->out_convert, out, preout, out_count); | swri_audio_convert(s->out_convert, out, preout, out_count); | ||||
} | } | ||||
@@ -30,7 +30,7 @@ | |||||
#include "libavutil/samplefmt.h" | #include "libavutil/samplefmt.h" | ||||
#define LIBSWRESAMPLE_VERSION_MAJOR 0 | #define LIBSWRESAMPLE_VERSION_MAJOR 0 | ||||
#define LIBSWRESAMPLE_VERSION_MINOR 10 | |||||
#define LIBSWRESAMPLE_VERSION_MINOR 11 | |||||
#define LIBSWRESAMPLE_VERSION_MICRO 100 | #define LIBSWRESAMPLE_VERSION_MICRO 100 | ||||
#define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \ | #define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \ | ||||
@@ -45,6 +45,11 @@ | |||||
//TODO use int resample ? | //TODO use int resample ? | ||||
//long term TODO can we enable this dynamically? | //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; | typedef struct SwrContext SwrContext; | ||||
@@ -49,6 +49,7 @@ struct SwrContext { | |||||
float rematrix_volume; ///< rematrixing volume coefficient | float rematrix_volume; ///< rematrixing volume coefficient | ||||
const int *channel_map; ///< channel index (or -1 if muted channel) map | 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) | 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 int_bps; ///< internal bytes per sample | ||||
int resample_first; ///< 1 if resampling must come first, 0 if rematrixing | 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 preout; ///< pre-output audio data: used for rematrix/resample | ||||
AudioData out; ///< converted output audio data | AudioData out; ///< converted output audio data | ||||
AudioData in_buffer; ///< cached audio data (convert and resample purpose) | 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_index; ///< cached buffer position | ||||
int in_buffer_count; ///< cached buffer length | int in_buffer_count; ///< cached buffer length | ||||
int resample_in_constraint; ///< 1 if the input end was reach before the output end, 0 otherwise | 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_init(SwrContext *s); | ||||
int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy); | 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 | #endif |