Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
| 11 | 11 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,56 @@ |
| 0 |
+/* |
|
| 1 |
+ * Copyright (C) 2012 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/avassert.h" |
|
| 21 |
+#include "swresample_internal.h" |
|
| 22 |
+ |
|
| 23 |
+void swri_get_dither(void *dst, int len, unsigned seed, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, enum SwrDitherType method) {
|
|
| 24 |
+ double scale = 0; |
|
| 25 |
+ int i; |
|
| 26 |
+ |
|
| 27 |
+ if(in_fmt == AV_SAMPLE_FMT_FLT || in_fmt == AV_SAMPLE_FMT_DBL){
|
|
| 28 |
+ if(out_fmt == AV_SAMPLE_FMT_S32) scale = 1.0/(1L<<31); |
|
| 29 |
+ if(out_fmt == AV_SAMPLE_FMT_S16) scale = 1.0/(1L<<15); |
|
| 30 |
+ if(out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1.0/(1L<< 7); |
|
| 31 |
+ } |
|
| 32 |
+ if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_S16) scale = 1L<<16; |
|
| 33 |
+ if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1L<<24; |
|
| 34 |
+ if(in_fmt == AV_SAMPLE_FMT_S16 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1L<<8; |
|
| 35 |
+ |
|
| 36 |
+ for(i=0; i<len; i++){
|
|
| 37 |
+ double v; |
|
| 38 |
+ seed = seed* 1664525 + 1013904223; |
|
| 39 |
+ |
|
| 40 |
+ switch(method){
|
|
| 41 |
+ case SWR_DITHER_RECTANGULAR: v= ((double)seed) / UINT_MAX - 0.5; break; |
|
| 42 |
+ default: av_assert0(0); |
|
| 43 |
+ } |
|
| 44 |
+ |
|
| 45 |
+ v*= scale; |
|
| 46 |
+ |
|
| 47 |
+ switch(in_fmt){
|
|
| 48 |
+ case AV_SAMPLE_FMT_S16: ((int16_t*)dst)[i] = v; break; |
|
| 49 |
+ case AV_SAMPLE_FMT_S32: ((int32_t*)dst)[i] = v; break; |
|
| 50 |
+ case AV_SAMPLE_FMT_FLT: ((float *)dst)[i] = v; break; |
|
| 51 |
+ case AV_SAMPLE_FMT_DBL: ((double *)dst)[i] = v; break; |
|
| 52 |
+ default: av_assert0(0); |
|
| 53 |
+ } |
|
| 54 |
+ } |
|
| 55 |
+} |
| ... | ... |
@@ -272,6 +272,14 @@ int swri_rematrix_init(SwrContext *s){
|
| 272 | 272 |
return 0; |
| 273 | 273 |
} |
| 274 | 274 |
|
| 275 |
+void swri_sum2(enum AVSampleFormat format, void *dst, const void *src0, const void *src1, float coef0, float coef1, int len){
|
|
| 276 |
+ if(format == AV_SAMPLE_FMT_FLT){
|
|
| 277 |
+ sum2_float((float *)dst, (const float *)src0, (const float *)src1, coef0, coef1, len); |
|
| 278 |
+ }else{
|
|
| 279 |
+ sum2_s16 ((int16_t*)dst, (const int16_t*)src0, (const int16_t*)src1, lrintf(coef0 * 32768), lrintf(coef1 * 32768), len); |
|
| 280 |
+ } |
|
| 281 |
+} |
|
| 282 |
+ |
|
| 275 | 283 |
int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy){
|
| 276 | 284 |
int out_i, in_i, i, j; |
| 277 | 285 |
|
| ... | ... |
@@ -295,15 +303,8 @@ int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mus |
| 295 | 295 |
} |
| 296 | 296 |
break; |
| 297 | 297 |
case 2: |
| 298 |
- if(s->int_sample_fmt == AV_SAMPLE_FMT_FLT){
|
|
| 299 |
- 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] ], |
|
| 300 |
- s->matrix[out_i][ s->matrix_ch[out_i][1] ], s->matrix[out_i][ s->matrix_ch[out_i][2] ], |
|
| 301 |
- len); |
|
| 302 |
- }else{
|
|
| 303 |
- 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] ], |
|
| 304 |
- s->matrix32[out_i][ s->matrix_ch[out_i][1] ], s->matrix32[out_i][ s->matrix_ch[out_i][2] ], |
|
| 305 |
- len); |
|
| 306 |
- } |
|
| 298 |
+ 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] ], |
|
| 299 |
+ s->matrix[out_i][ s->matrix_ch[out_i][1] ], s->matrix[out_i][ s->matrix_ch[out_i][2] ], len); |
|
| 307 | 300 |
break; |
| 308 | 301 |
default: |
| 309 | 302 |
if(s->int_sample_fmt == AV_SAMPLE_FMT_FLT){
|
| ... | ... |
@@ -53,6 +53,7 @@ static const AVOption options[]={
|
| 53 | 53 |
{"rmvol", "rematrix volume" , OFFSET(rematrix_volume), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, -1000, 1000, 0},
|
| 54 | 54 |
{"flags", NULL , OFFSET(flags) , AV_OPT_TYPE_FLAGS, {.dbl=0}, 0, UINT_MAX, 0, "flags"},
|
| 55 | 55 |
{"res", "force resampling", 0, AV_OPT_TYPE_CONST, {.dbl=SWR_FLAG_RESAMPLE}, INT_MIN, INT_MAX, 0, "flags"},
|
| 56 |
+{"dither", "dither method" , OFFSET(dither_method), AV_OPT_TYPE_INT, {.dbl=0}, 0, SWR_DITHER_NB-1, 0},
|
|
| 56 | 57 |
|
| 57 | 58 |
{0}
|
| 58 | 59 |
}; |
| ... | ... |
@@ -139,6 +140,7 @@ void swr_free(SwrContext **ss){
|
| 139 | 139 |
free_temp(&s->midbuf); |
| 140 | 140 |
free_temp(&s->preout); |
| 141 | 141 |
free_temp(&s->in_buffer); |
| 142 |
+ free_temp(&s->dither); |
|
| 142 | 143 |
swri_audio_convert_free(&s-> in_convert); |
| 143 | 144 |
swri_audio_convert_free(&s->out_convert); |
| 144 | 145 |
swri_audio_convert_free(&s->full_convert); |
| ... | ... |
@@ -156,6 +158,7 @@ int swr_init(struct SwrContext *s){
|
| 156 | 156 |
free_temp(&s->midbuf); |
| 157 | 157 |
free_temp(&s->preout); |
| 158 | 158 |
free_temp(&s->in_buffer); |
| 159 |
+ free_temp(&s->dither); |
|
| 159 | 160 |
swri_audio_convert_free(&s-> in_convert); |
| 160 | 161 |
swri_audio_convert_free(&s->out_convert); |
| 161 | 162 |
swri_audio_convert_free(&s->full_convert); |
| ... | ... |
@@ -281,6 +284,8 @@ av_assert0(s->out.ch_count); |
| 281 | 281 |
s->in_buffer.planar = 1; |
| 282 | 282 |
} |
| 283 | 283 |
|
| 284 |
+ s->dither = s->preout; |
|
| 285 |
+ |
|
| 284 | 286 |
if(s->rematrix) |
| 285 | 287 |
return swri_rematrix_init(s); |
| 286 | 288 |
|
| ... | ... |
@@ -505,6 +510,21 @@ static int swr_convert_internal(struct SwrContext *s, AudioData *out, int out_co |
| 505 | 505 |
} |
| 506 | 506 |
|
| 507 | 507 |
if(preout != out && out_count){
|
| 508 |
+ if(s->dither_method){
|
|
| 509 |
+ int ch, i; |
|
| 510 |
+ av_assert0(preout != in); |
|
| 511 |
+ |
|
| 512 |
+ if((ret=realloc_audio(&s->dither, out_count))<0) |
|
| 513 |
+ return ret; |
|
| 514 |
+ if(ret) |
|
| 515 |
+ for(ch=0; ch<s->dither.ch_count; ch++) |
|
| 516 |
+ swri_get_dither(s->dither.ch[ch], s->dither.count, 12345678913579<<ch, s->out_sample_fmt, s->int_sample_fmt, s->dither_method); |
|
| 517 |
+ av_assert0(s->dither.ch_count == preout->ch_count); |
|
| 518 |
+ |
|
| 519 |
+ for(ch=0; ch<preout->ch_count; ch++){
|
|
| 520 |
+ swri_sum2(s->int_sample_fmt, preout->ch[ch], preout->ch[ch], s->dither.ch[ch], 1, 1, out_count); |
|
| 521 |
+ } |
|
| 522 |
+ } |
|
| 508 | 523 |
//FIXME packed doesnt need more than 1 chan here! |
| 509 | 524 |
swri_audio_convert(s->out_convert, out, preout, out_count); |
| 510 | 525 |
} |
| ... | ... |
@@ -30,7 +30,7 @@ |
| 30 | 30 |
#include "libavutil/samplefmt.h" |
| 31 | 31 |
|
| 32 | 32 |
#define LIBSWRESAMPLE_VERSION_MAJOR 0 |
| 33 |
-#define LIBSWRESAMPLE_VERSION_MINOR 10 |
|
| 33 |
+#define LIBSWRESAMPLE_VERSION_MINOR 11 |
|
| 34 | 34 |
#define LIBSWRESAMPLE_VERSION_MICRO 100 |
| 35 | 35 |
|
| 36 | 36 |
#define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \ |
| ... | ... |
@@ -45,6 +45,11 @@ |
| 45 | 45 |
//TODO use int resample ? |
| 46 | 46 |
//long term TODO can we enable this dynamically? |
| 47 | 47 |
|
| 48 |
+enum SwrDitherType {
|
|
| 49 |
+ SWR_DITHER_NONE = 0, |
|
| 50 |
+ SWR_DITHER_RECTANGULAR, |
|
| 51 |
+ SWR_DITHER_NB, ///< not part of API/ABI |
|
| 52 |
+}; |
|
| 48 | 53 |
|
| 49 | 54 |
typedef struct SwrContext SwrContext; |
| 50 | 55 |
|
| ... | ... |
@@ -49,6 +49,7 @@ struct SwrContext {
|
| 49 | 49 |
float rematrix_volume; ///< rematrixing volume coefficient |
| 50 | 50 |
const int *channel_map; ///< channel index (or -1 if muted channel) map |
| 51 | 51 |
int used_ch_count; ///< number of used input channels (mapped channel count if channel_map, otherwise in.ch_count) |
| 52 |
+ enum SwrDitherType dither_method; |
|
| 52 | 53 |
|
| 53 | 54 |
int int_bps; ///< internal bytes per sample |
| 54 | 55 |
int resample_first; ///< 1 if resampling must come first, 0 if rematrixing |
| ... | ... |
@@ -61,6 +62,7 @@ struct SwrContext {
|
| 61 | 61 |
AudioData preout; ///< pre-output audio data: used for rematrix/resample |
| 62 | 62 |
AudioData out; ///< converted output audio data |
| 63 | 63 |
AudioData in_buffer; ///< cached audio data (convert and resample purpose) |
| 64 |
+ AudioData dither; ///< cached audio data (convert and resample purpose) |
|
| 64 | 65 |
int in_buffer_index; ///< cached buffer position |
| 65 | 66 |
int in_buffer_count; ///< cached buffer length |
| 66 | 67 |
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 * |
| 89 | 89 |
|
| 90 | 90 |
int swri_rematrix_init(SwrContext *s); |
| 91 | 91 |
int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy); |
| 92 |
+void swri_sum2(enum AVSampleFormat format, void *dst, const void *src0, const void *src1, float coef0, float coef1, int len); |
|
| 93 |
+ |
|
| 94 |
+void swri_get_dither(void *dst, int len, unsigned seed, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, enum SwrDitherType type); |
|
| 92 | 95 |
|
| 93 | 96 |
#endif |