Unified · Split
| @@ -5,6 +5,6 @@ FFLIBS = avutil · 4 unmodified lines | ||
| 5 | 5 | |
| 6 | 6 | HEADERS = swresample.h |
| 7 | 7 | |
| 8 | −OBJS = swresample.o audioconvert.o resample.o rematrix.o | |
| 8 | +OBJS = swresample.o audioconvert.o resample.o rematrix.o dither.o | |
| 9 | 9 | |
| 10 | 10 | TESTPROGS = swresample_test |
| @@ -0,0 +1,56 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (C) 2012 Michael Niedermayer (michaelni@gmx.at) | |
| 3 | + * | |
| 4 | + * This file is part of libswresample | |
| 5 | + * | |
| 6 | + * libswresample is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU Lesser General Public | |
| 8 | + * License as published by the Free Software Foundation; either | |
| 9 | + * version 2.1 of the License, or (at your option) any later version. | |
| 10 | + * | |
| 11 | + * libswresample is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | + * Lesser General Public License for more details. | |
| 15 | + * | |
| 16 | + * You should have received a copy of the GNU Lesser General Public | |
| 17 | + * License along with libswresample; if not, write to the Free Software | |
| 18 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 19 | + */ | |
| 20 | + | |
| 21 | +#include "libavutil/avassert.h" | |
| 22 | +#include "swresample_internal.h" | |
| 23 | + | |
| 24 | +void swri_get_dither(void *dst, int len, unsigned seed, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, enum SwrDitherType method) { | |
| 25 | + double scale = 0; | |
| 26 | + int i; | |
| 27 | + | |
| 28 | + if(in_fmt == AV_SAMPLE_FMT_FLT || in_fmt == AV_SAMPLE_FMT_DBL){ | |
| 29 | + if(out_fmt == AV_SAMPLE_FMT_S32) scale = 1.0/(1L<<31); | |
| 30 | + if(out_fmt == AV_SAMPLE_FMT_S16) scale = 1.0/(1L<<15); | |
| 31 | + if(out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1.0/(1L<< 7); | |
| 32 | + } | |
| 33 | + if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_S16) scale = 1L<<16; | |
| 34 | + if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1L<<24; | |
| 35 | + if(in_fmt == AV_SAMPLE_FMT_S16 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1L<<8; | |
| 36 | + | |
| 37 | + for(i=0; i<len; i++){ | |
| 38 | + double v; | |
| 39 | + seed = seed* 1664525 + 1013904223; | |
| 40 | + | |
| 41 | + switch(method){ | |
| 42 | + case SWR_DITHER_RECTANGULAR: v= ((double)seed) / UINT_MAX - 0.5; break; | |
| 43 | + default: av_assert0(0); | |
| 44 | + } | |
| 45 | + | |
| 46 | + v*= scale; | |
| 47 | + | |
| 48 | + switch(in_fmt){ | |
| 49 | + case AV_SAMPLE_FMT_S16: ((int16_t*)dst)[i] = v; break; | |
| 50 | + case AV_SAMPLE_FMT_S32: ((int32_t*)dst)[i] = v; break; | |
| 51 | + case AV_SAMPLE_FMT_FLT: ((float *)dst)[i] = v; break; | |
| 52 | + case AV_SAMPLE_FMT_DBL: ((double *)dst)[i] = v; break; | |
| 53 | + default: av_assert0(0); | |
| 54 | + } | |
| 55 | + } | |
| 56 | +} | |
| @@ -272,6 +272,14 @@ int swri_rematrix_init(SwrContext *s){ · 271 unmodified lines | ||
| 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 · 17 unmodified lines | ||
| 295 | 303 | } |
| 296 | 304 | break; |
| 297 | 305 | 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 | − } | |
| 306 | + 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] ], | |
| 307 | + s->matrix[out_i][ s->matrix_ch[out_i][1] ], s->matrix[out_i][ s->matrix_ch[out_i][2] ], len); | |
| 307 | 308 | break; |
| 308 | 309 | default: |
| 309 | 310 | if(s->int_sample_fmt == AV_SAMPLE_FMT_FLT){ |
| @@ -53,6 +53,7 @@ static const AVOption options[]={ · 52 unmodified lines | ||
| 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){ · 80 unmodified lines | ||
| 139 | 140 | free_temp(&s->midbuf); |
| 140 | 141 | free_temp(&s->preout); |
| 141 | 142 | free_temp(&s->in_buffer); |
| 143 | + free_temp(&s->dither); | |
| 142 | 144 | swri_audio_convert_free(&s-> in_convert); |
| 143 | 145 | swri_audio_convert_free(&s->out_convert); |
| 144 | 146 | swri_audio_convert_free(&s->full_convert); |
| @@ -156,6 +158,7 @@ int swr_init(struct SwrContext *s){ · 11 unmodified lines | ||
| 156 | 158 | free_temp(&s->midbuf); |
| 157 | 159 | free_temp(&s->preout); |
| 158 | 160 | free_temp(&s->in_buffer); |
| 161 | + free_temp(&s->dither); | |
| 159 | 162 | swri_audio_convert_free(&s-> in_convert); |
| 160 | 163 | swri_audio_convert_free(&s->out_convert); |
| 161 | 164 | swri_audio_convert_free(&s->full_convert); |
| @@ -281,6 +284,8 @@ av_assert0(s->out.ch_count); · 119 unmodified lines | ||
| 281 | 284 | s->in_buffer.planar = 1; |
| 282 | 285 | } |
| 283 | 286 | |
| 287 | + s->dither = s->preout; | |
| 288 | + | |
| 284 | 289 | if(s->rematrix) |
| 285 | 290 | return swri_rematrix_init(s); |
| 286 | 291 | |
| @@ -505,6 +510,21 @@ static int swr_convert_internal(struct SwrContext *s, AudioData *out, int out_co · 218 unmodified lines | ||
| 505 | 510 | } |
| 506 | 511 | |
| 507 | 512 | if(preout != out && out_count){ |
| 513 | + if(s->dither_method){ | |
| 514 | + int ch, i; | |
| 515 | + av_assert0(preout != in); | |
| 516 | + | |
| 517 | + if((ret=realloc_audio(&s->dither, out_count))<0) | |
| 518 | + return ret; | |
| 519 | + if(ret) | |
| 520 | + for(ch=0; ch<s->dither.ch_count; ch++) | |
| 521 | + swri_get_dither(s->dither.ch[ch], s->dither.count, 12345678913579<<ch, s->out_sample_fmt, s->int_sample_fmt, s->dither_method); | |
| 522 | + av_assert0(s->dither.ch_count == preout->ch_count); | |
| 523 | + | |
| 524 | + for(ch=0; ch<preout->ch_count; ch++){ | |
| 525 | + swri_sum2(s->int_sample_fmt, preout->ch[ch], preout->ch[ch], s->dither.ch[ch], 1, 1, out_count); | |
| 526 | + } | |
| 527 | + } | |
| 508 | 528 | //FIXME packed doesnt need more than 1 chan here! |
| 509 | 529 | swri_audio_convert(s->out_convert, out, preout, out_count); |
| 510 | 530 | } |
| @@ -30,7 +30,7 @@ · 29 unmodified lines | ||
| 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 @@ · 8 unmodified lines | ||
| 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 { · 48 unmodified lines | ||
| 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 { · 6 unmodified lines | ||
| 61 | 62 | AudioData preout; ///< pre-output audio data: used for rematrix/resample |
| 62 | 63 | AudioData out; ///< converted output audio data |
| 63 | 64 | AudioData in_buffer; ///< cached audio data (convert and resample purpose) |
| 65 | + AudioData dither; ///< cached audio data (convert and resample purpose) | |
| 64 | 66 | int in_buffer_index; ///< cached buffer position |
| 65 | 67 | int in_buffer_count; ///< cached buffer length |
| 66 | 68 | 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 * · 22 unmodified lines | ||
| 89 | 91 | |
| 90 | 92 | int swri_rematrix_init(SwrContext *s); |
| 91 | 93 | int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy); |
| 94 | +void swri_sum2(enum AVSampleFormat format, void *dst, const void *src0, const void *src1, float coef0, float coef1, int len); | |
| 95 | + | |
| 96 | +void swri_get_dither(void *dst, int len, unsigned seed, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, enum SwrDitherType type); | |
| 92 | 97 | |
| 93 | 98 | #endif |