diff --git a/libswresample/dither.c b/libswresample/dither.c index 663e2007ba52c4d25c43b929744ecf4bfad4586a..88f788066e7d8b126e929d1090da64e1bdeecb1c 100644 --- a/libswresample/dither.c +++ b/libswresample/dither.c @@ -23,6 +23,8 @@ void swri_get_dither(void *dst, int len, unsigned seed, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, enum SwrDitherType method) { double scale = 0; +#define TMP_EXTRA 2 + double *tmp = av_malloc((len + TMP_EXTRA) * sizeof(double)); int i; if(in_fmt == AV_SAMPLE_FMT_FLT || in_fmt == AV_SAMPLE_FMT_DBL){ @@ -34,19 +36,36 @@ void swri_get_dither(void *dst, int len, unsigned seed, enum AVSampleFormat out_ 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++){ + for(i=0; i<len + TMP_EXTRA; i++){ double v; seed = seed* 1664525 + 1013904223; switch(method){ case SWR_DITHER_RECTANGULAR: v= ((double)seed) / UINT_MAX - 0.5; break; case SWR_DITHER_TRIANGULAR : + case SWR_DITHER_TRIANGULAR_HIGHPASS : v = ((double)seed) / UINT_MAX; seed = seed*1664525 + 1013904223; v-= ((double)seed) / UINT_MAX; break; default: av_assert0(0); } + tmp[i] = v; + } + + for(i=0; i<len; i++){ + double v; + + switch(method){ + case SWR_DITHER_RECTANGULAR: + case SWR_DITHER_TRIANGULAR : + v = tmp[i]; + break; + case SWR_DITHER_TRIANGULAR_HIGHPASS : + v = (- tmp[i] + 2*tmp[i+1] - tmp[i+2]) / sqrt(6); + break; + default: av_assert0(0); + } v*= scale; @@ -58,4 +77,6 @@ void swri_get_dither(void *dst, int len, unsigned seed, enum AVSampleFormat out_ default: av_assert0(0); } } + + av_free(tmp); } diff --git a/libswresample/swresample.c b/libswresample/swresample.c index 715a446456cedeb7e197d30bcf8fda4b4dbf847c..78b0355c4f08956a8c6bd6090e6ef45d0ba39053 100644 --- a/libswresample/swresample.c +++ b/libswresample/swresample.c @@ -56,6 +56,7 @@ static const AVOption options[]={ {"dither", "dither method" , OFFSET(dither_method), AV_OPT_TYPE_INT, {.dbl=0}, 0, SWR_DITHER_NB-1, 0, "dither_method"}, {"rectangular", "rectangular dither", 0, AV_OPT_TYPE_CONST, {.dbl=SWR_DITHER_RECTANGULAR}, INT_MIN, INT_MAX, 0, "dither_method"}, {"triangular" , "triangular dither" , 0, AV_OPT_TYPE_CONST, {.dbl=SWR_DITHER_TRIANGULAR }, INT_MIN, INT_MAX, 0, "dither_method"}, +{"triangular_hp" , "triangular dither with high pass" , 0, AV_OPT_TYPE_CONST, {.dbl=SWR_DITHER_TRIANGULAR_HIGHPASS }, INT_MIN, INT_MAX, 0, "dither_method"}, {0} }; diff --git a/libswresample/swresample.h b/libswresample/swresample.h index 3a54c8eed97200cc83c5fce637f9d9558f012d94..137517d6d2935b19154fe65ac95388d7fcfec727 100644 --- a/libswresample/swresample.h +++ b/libswresample/swresample.h @@ -49,6 +49,7 @@ enum SwrDitherType { SWR_DITHER_NONE = 0, SWR_DITHER_RECTANGULAR, SWR_DITHER_TRIANGULAR, + SWR_DITHER_TRIANGULAR_HIGHPASS, SWR_DITHER_NB, ///< not part of API/ABI };