Unified · Split
| @@ -5,6 +5,6 @@ FFLIBS = avutil · 4 unmodified lines | |||
| 5 | 5 | ||
| 6 | HEADERS = swresample.h | 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 | TESTPROGS = swresample_test | 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 | return 0; | 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 | int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy){ | 283 | int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy){ |
| 276 | int out_i, in_i, i, j; | 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 | break; | 304 | break; |
| 297 | case 2: | 305 | case 2: |
| 298 | if(s->int_sample_fmt == AV_SAMPLE_FMT_FLT){ | 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] ], |
| 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] ], | 307 | s->matrix[out_i][ s->matrix_ch[out_i][1] ], s->matrix[out_i][ s->matrix_ch[out_i][2] ], len); |
| 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 | } | ||
| 307 | break; | 308 | break; |
| 308 | default: | 309 | default: |
| 309 | if(s->int_sample_fmt == AV_SAMPLE_FMT_FLT){ | 310 | if(s->int_sample_fmt == AV_SAMPLE_FMT_FLT){ |
| @@ -53,6 +53,7 @@ static const AVOption options[]={ · 52 unmodified lines | |||
| 53 | {"rmvol", "rematrix volume" , OFFSET(rematrix_volume), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, -1000, 1000, 0}, | 53 | {"rmvol", "rematrix volume" , OFFSET(rematrix_volume), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, -1000, 1000, 0}, |
| 54 | {"flags", NULL , OFFSET(flags) , AV_OPT_TYPE_FLAGS, {.dbl=0}, 0, UINT_MAX, 0, "flags"}, | 54 | {"flags", NULL , OFFSET(flags) , AV_OPT_TYPE_FLAGS, {.dbl=0}, 0, UINT_MAX, 0, "flags"}, |
| 55 | {"res", "force resampling", 0, AV_OPT_TYPE_CONST, {.dbl=SWR_FLAG_RESAMPLE}, INT_MIN, INT_MAX, 0, "flags"}, | 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 | {0} | 58 | {0} |
| 58 | }; | 59 | }; |
| @@ -139,6 +140,7 @@ void swr_free(SwrContext **ss){ · 80 unmodified lines | |||
| 139 | free_temp(&s->midbuf); | 140 | free_temp(&s->midbuf); |
| 140 | free_temp(&s->preout); | 141 | free_temp(&s->preout); |
| 141 | free_temp(&s->in_buffer); | 142 | free_temp(&s->in_buffer); |
| 143 | free_temp(&s->dither); | ||
| 142 | swri_audio_convert_free(&s-> in_convert); | 144 | swri_audio_convert_free(&s-> in_convert); |
| 143 | swri_audio_convert_free(&s->out_convert); | 145 | swri_audio_convert_free(&s->out_convert); |
| 144 | swri_audio_convert_free(&s->full_convert); | 146 | swri_audio_convert_free(&s->full_convert); |
| @@ -156,6 +158,7 @@ int swr_init(struct SwrContext *s){ · 11 unmodified lines | |||
| 156 | free_temp(&s->midbuf); | 158 | free_temp(&s->midbuf); |
| 157 | free_temp(&s->preout); | 159 | free_temp(&s->preout); |
| 158 | free_temp(&s->in_buffer); | 160 | free_temp(&s->in_buffer); |
| 161 | free_temp(&s->dither); | ||
| 159 | swri_audio_convert_free(&s-> in_convert); | 162 | swri_audio_convert_free(&s-> in_convert); |
| 160 | swri_audio_convert_free(&s->out_convert); | 163 | swri_audio_convert_free(&s->out_convert); |
| 161 | swri_audio_convert_free(&s->full_convert); | 164 | swri_audio_convert_free(&s->full_convert); |
| @@ -281,6 +284,8 @@ av_assert0(s->out.ch_count); · 119 unmodified lines | |||
| 281 | s->in_buffer.planar = 1; | 284 | s->in_buffer.planar = 1; |
| 282 | } | 285 | } |
| 283 | 286 | ||
| 287 | s->dither = s->preout; | ||
| 288 | |||
| 284 | if(s->rematrix) | 289 | if(s->rematrix) |
| 285 | return swri_rematrix_init(s); | 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 | if(preout != out && out_count){ | 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 | //FIXME packed doesnt need more than 1 chan here! | 528 | //FIXME packed doesnt need more than 1 chan here! |
| 509 | swri_audio_convert(s->out_convert, out, preout, out_count); | 529 | swri_audio_convert(s->out_convert, out, preout, out_count); |
| 510 | } | 530 | } |
| @@ -30,7 +30,7 @@ · 29 unmodified lines | |||
| 30 | #include "libavutil/samplefmt.h" | 30 | #include "libavutil/samplefmt.h" |
| 31 | 31 | ||
| 32 | #define LIBSWRESAMPLE_VERSION_MAJOR 0 | 32 | #define LIBSWRESAMPLE_VERSION_MAJOR 0 |
| 33 | #define LIBSWRESAMPLE_VERSION_MINOR 10 | 33 | #define LIBSWRESAMPLE_VERSION_MINOR 11 |
| 34 | #define LIBSWRESAMPLE_VERSION_MICRO 100 | 34 | #define LIBSWRESAMPLE_VERSION_MICRO 100 |
| 35 | 35 | ||
| 36 | #define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \ | 36 | #define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \ |
| @@ -45,6 +45,11 @@ · 8 unmodified lines | |||
| 45 | //TODO use int resample ? | 45 | //TODO use int resample ? |
| 46 | //long term TODO can we enable this dynamically? | 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 | typedef struct SwrContext SwrContext; | 54 | typedef struct SwrContext SwrContext; |
| 50 | 55 | ||
| @@ -49,6 +49,7 @@ struct SwrContext { · 48 unmodified lines | |||
| 49 | float rematrix_volume; ///< rematrixing volume coefficient | 49 | float rematrix_volume; ///< rematrixing volume coefficient |
| 50 | const int *channel_map; ///< channel index (or -1 if muted channel) map | 50 | const int *channel_map; ///< channel index (or -1 if muted channel) map |
| 51 | int used_ch_count; ///< number of used input channels (mapped channel count if channel_map, otherwise in.ch_count) | 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 | int int_bps; ///< internal bytes per sample | 54 | int int_bps; ///< internal bytes per sample |
| 54 | int resample_first; ///< 1 if resampling must come first, 0 if rematrixing | 55 | int resample_first; ///< 1 if resampling must come first, 0 if rematrixing |
| @@ -61,6 +62,7 @@ struct SwrContext { · 6 unmodified lines | |||
| 61 | AudioData preout; ///< pre-output audio data: used for rematrix/resample | 62 | AudioData preout; ///< pre-output audio data: used for rematrix/resample |
| 62 | AudioData out; ///< converted output audio data | 63 | AudioData out; ///< converted output audio data |
| 63 | AudioData in_buffer; ///< cached audio data (convert and resample purpose) | 64 | AudioData in_buffer; ///< cached audio data (convert and resample purpose) |
| 65 | AudioData dither; ///< cached audio data (convert and resample purpose) | ||
| 64 | int in_buffer_index; ///< cached buffer position | 66 | int in_buffer_index; ///< cached buffer position |
| 65 | int in_buffer_count; ///< cached buffer length | 67 | int in_buffer_count; ///< cached buffer length |
| 66 | int resample_in_constraint; ///< 1 if the input end was reach before the output end, 0 otherwise | 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 | int swri_rematrix_init(SwrContext *s); | 92 | int swri_rematrix_init(SwrContext *s); |
| 91 | int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy); | 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 | #endif | 98 | #endif |