/src/ffmpeg/libswresample/dither.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2012-2013 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 "libavutil/mem.h" |
23 | | #include "swresample_internal.h" |
24 | | |
25 | | #include "noise_shaping_data.c" |
26 | | |
27 | 0 | int swri_get_dither(SwrContext *s, void *dst, int len, unsigned seed, enum AVSampleFormat noise_fmt) { |
28 | 0 | double scale = s->dither.noise_scale; |
29 | 0 | #define TMP_EXTRA 2 |
30 | 0 | double *tmp = av_malloc_array(len + TMP_EXTRA, sizeof(double)); |
31 | 0 | int i; |
32 | |
|
33 | 0 | if (!tmp) |
34 | 0 | return AVERROR(ENOMEM); |
35 | | |
36 | 0 | for(i=0; i<len + TMP_EXTRA; i++){ |
37 | 0 | double v; |
38 | 0 | seed = seed* 1664525 + 1013904223; |
39 | |
|
40 | 0 | switch(s->dither.method){ |
41 | 0 | case SWR_DITHER_RECTANGULAR: v= ((double)seed) / UINT_MAX - 0.5; break; |
42 | 0 | default: |
43 | 0 | av_assert0(s->dither.method < SWR_DITHER_NB); |
44 | 0 | v = ((double)seed) / UINT_MAX; |
45 | 0 | seed = seed*1664525 + 1013904223; |
46 | 0 | v-= ((double)seed) / UINT_MAX; |
47 | 0 | break; |
48 | 0 | } |
49 | 0 | tmp[i] = v; |
50 | 0 | } |
51 | | |
52 | 0 | for(i=0; i<len; i++){ |
53 | 0 | double v; |
54 | |
|
55 | 0 | switch(s->dither.method){ |
56 | 0 | default: |
57 | 0 | av_assert0(s->dither.method < SWR_DITHER_NB); |
58 | 0 | v = tmp[i]; |
59 | 0 | break; |
60 | 0 | case SWR_DITHER_TRIANGULAR_HIGHPASS : |
61 | 0 | v = (- tmp[i] + 2*tmp[i+1] - tmp[i+2]) / sqrt(6); |
62 | 0 | break; |
63 | 0 | } |
64 | | |
65 | 0 | v*= scale; |
66 | |
|
67 | 0 | switch(noise_fmt){ |
68 | 0 | case AV_SAMPLE_FMT_S16P: ((int16_t*)dst)[i] = v; break; |
69 | 0 | case AV_SAMPLE_FMT_S32P: ((int32_t*)dst)[i] = v; break; |
70 | 0 | case AV_SAMPLE_FMT_FLTP: ((float *)dst)[i] = v; break; |
71 | 0 | case AV_SAMPLE_FMT_DBLP: ((double *)dst)[i] = v; break; |
72 | 0 | default: av_assert0(0); |
73 | 0 | } |
74 | 0 | } |
75 | | |
76 | 0 | av_free(tmp); |
77 | 0 | return 0; |
78 | 0 | } |
79 | | |
80 | | av_cold int swri_dither_init(SwrContext *s, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt) |
81 | 115k | { |
82 | 115k | int i; |
83 | 115k | double scale = 0; |
84 | | |
85 | 115k | if (s->dither.method > SWR_DITHER_TRIANGULAR_HIGHPASS && s->dither.method <= SWR_DITHER_NS) |
86 | 0 | return AVERROR(EINVAL); |
87 | | |
88 | 115k | out_fmt = av_get_packed_sample_fmt(out_fmt); |
89 | 115k | in_fmt = av_get_packed_sample_fmt( in_fmt); |
90 | | |
91 | 115k | if(in_fmt == AV_SAMPLE_FMT_FLT || in_fmt == AV_SAMPLE_FMT_DBL){ |
92 | 113k | if(out_fmt == AV_SAMPLE_FMT_S32) scale = 1.0/(1LL<<31); |
93 | 113k | if(out_fmt == AV_SAMPLE_FMT_S16) scale = 1.0/(1LL<<15); |
94 | 113k | if(out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1.0/(1LL<< 7); |
95 | 113k | } |
96 | 115k | if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_S32 && (s->dither.output_sample_bits&31)) scale = 1; |
97 | 115k | if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_S16) scale = 1<<16; |
98 | 115k | if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1<<24; |
99 | 115k | if(in_fmt == AV_SAMPLE_FMT_S16 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1<<8; |
100 | | |
101 | 115k | scale *= s->dither.scale; |
102 | | |
103 | 115k | if (out_fmt == AV_SAMPLE_FMT_S32 && s->dither.output_sample_bits) |
104 | 0 | scale *= 1<<(32-s->dither.output_sample_bits); |
105 | | |
106 | 115k | if (scale == 0) { |
107 | 111k | s->dither.method = 0; |
108 | 111k | return 0; |
109 | 111k | } |
110 | | |
111 | 3.08k | s->dither.ns_pos = 0; |
112 | 3.08k | s->dither.noise_scale= scale; |
113 | 3.08k | s->dither.ns_scale = scale; |
114 | 3.08k | s->dither.ns_scale_1 = scale ? 1/scale : 0; |
115 | 3.08k | memset(s->dither.ns_errors, 0, sizeof(s->dither.ns_errors)); |
116 | 49.4k | for (i=0; filters[i].coefs; i++) { |
117 | 46.3k | const filter_t *f = &filters[i]; |
118 | 46.3k | if (llabs(s->out_sample_rate - f->rate)*20 <= f->rate && f->name == s->dither.method) { |
119 | 0 | int j; |
120 | 0 | s->dither.ns_taps = f->len; |
121 | 0 | for (j=0; j<f->len; j++) |
122 | 0 | s->dither.ns_coeffs[j] = f->coefs[j]; |
123 | 0 | s->dither.ns_scale_1 *= 1 - exp(f->gain_cB * M_LN10 * 0.005) * 2 / (1<<(8*av_get_bytes_per_sample(out_fmt))); |
124 | 0 | break; |
125 | 0 | } |
126 | 46.3k | } |
127 | 3.08k | if (!filters[i].coefs && s->dither.method > SWR_DITHER_NS) { |
128 | 0 | av_log(s, AV_LOG_WARNING, "Requested noise shaping dither not available at this sampling rate, using triangular hp dither\n"); |
129 | 0 | s->dither.method = SWR_DITHER_TRIANGULAR_HIGHPASS; |
130 | 0 | } |
131 | | |
132 | 3.08k | return 0; |
133 | 115k | } |
134 | | |
135 | | #define TEMPLATE_DITHER_S16 |
136 | | #include "dither_template.c" |
137 | | #undef TEMPLATE_DITHER_S16 |
138 | | |
139 | | #define TEMPLATE_DITHER_S32 |
140 | | #include "dither_template.c" |
141 | | #undef TEMPLATE_DITHER_S32 |
142 | | |
143 | | #define TEMPLATE_DITHER_FLT |
144 | | #include "dither_template.c" |
145 | | #undef TEMPLATE_DITHER_FLT |
146 | | |
147 | | #define TEMPLATE_DITHER_DBL |
148 | | #include "dither_template.c" |
149 | | #undef TEMPLATE_DITHER_DBL |