Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * Copyright (c) 2002 Fabrice Bellard | |
3 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | |
4 | * | |
5 | * This file is part of FFmpeg. | |
6 | * | |
7 | * FFmpeg is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * FFmpeg is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with FFmpeg; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | */ | |
21 | ||
22 | #include <stdint.h> | |
23 | #include <stdio.h> | |
24 | ||
25 | #include "libavutil/avstring.h" | |
26 | #include "libavutil/common.h" | |
27 | #include "libavutil/lfg.h" | |
28 | #include "libavutil/libm.h" | |
29 | #include "libavutil/log.h" | |
30 | #include "libavutil/mem.h" | |
31 | #include "libavutil/opt.h" | |
32 | #include "libavutil/samplefmt.h" | |
33 | #include "avresample.h" | |
34 | ||
35 | static double dbl_rand(AVLFG *lfg) | |
36 | { | |
37 | return 2.0 * (av_lfg_get(lfg) / (double)UINT_MAX) - 1.0; | |
38 | } | |
39 | ||
40 | #define PUT_FUNC(name, fmt, type, expr) \ | |
41 | static void put_sample_ ## name(void **data, enum AVSampleFormat sample_fmt,\ | |
42 | int channels, int sample, int ch, \ | |
43 | double v_dbl) \ | |
44 | { \ | |
45 | type v = expr; \ | |
46 | type **out = (type **)data; \ | |
47 | if (av_sample_fmt_is_planar(sample_fmt)) \ | |
48 | out[ch][sample] = v; \ | |
49 | else \ | |
50 | out[0][sample * channels + ch] = v; \ | |
51 | } | |
52 | ||
53 | PUT_FUNC(u8, AV_SAMPLE_FMT_U8, uint8_t, av_clip_uint8 ( lrint(v_dbl * (1 << 7)) + 128)) | |
54 | PUT_FUNC(s16, AV_SAMPLE_FMT_S16, int16_t, av_clip_int16 ( lrint(v_dbl * (1 << 15)))) | |
55 | PUT_FUNC(s32, AV_SAMPLE_FMT_S32, int32_t, av_clipl_int32(llrint(v_dbl * (1U << 31)))) | |
56 | PUT_FUNC(flt, AV_SAMPLE_FMT_FLT, float, v_dbl) | |
57 | PUT_FUNC(dbl, AV_SAMPLE_FMT_DBL, double, v_dbl) | |
58 | ||
59 | static void put_sample(void **data, enum AVSampleFormat sample_fmt, | |
60 | int channels, int sample, int ch, double v_dbl) | |
61 | { | |
62 | switch (av_get_packed_sample_fmt(sample_fmt)) { | |
63 | case AV_SAMPLE_FMT_U8: | |
64 | put_sample_u8(data, sample_fmt, channels, sample, ch, v_dbl); | |
65 | break; | |
66 | case AV_SAMPLE_FMT_S16: | |
67 | put_sample_s16(data, sample_fmt, channels, sample, ch, v_dbl); | |
68 | break; | |
69 | case AV_SAMPLE_FMT_S32: | |
70 | put_sample_s32(data, sample_fmt, channels, sample, ch, v_dbl); | |
71 | break; | |
72 | case AV_SAMPLE_FMT_FLT: | |
73 | put_sample_flt(data, sample_fmt, channels, sample, ch, v_dbl); | |
74 | break; | |
75 | case AV_SAMPLE_FMT_DBL: | |
76 | put_sample_dbl(data, sample_fmt, channels, sample, ch, v_dbl); | |
77 | break; | |
78 | } | |
79 | } | |
80 | ||
81 | static void audiogen(AVLFG *rnd, void **data, enum AVSampleFormat sample_fmt, | |
82 | int channels, int sample_rate, int nb_samples) | |
83 | { | |
84 | int i, ch, k; | |
85 | double v, f, a, ampa; | |
86 | double tabf1[AVRESAMPLE_MAX_CHANNELS]; | |
87 | double tabf2[AVRESAMPLE_MAX_CHANNELS]; | |
88 | double taba[AVRESAMPLE_MAX_CHANNELS]; | |
89 | ||
90 | #define PUT_SAMPLE put_sample(data, sample_fmt, channels, k, ch, v); | |
91 | ||
92 | k = 0; | |
93 | ||
94 | /* 1 second of single freq sine at 1000 Hz */ | |
95 | a = 0; | |
96 | for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) { | |
97 | v = sin(a) * 0.30; | |
98 | for (ch = 0; ch < channels; ch++) | |
99 | PUT_SAMPLE | |
100 | a += M_PI * 1000.0 * 2.0 / sample_rate; | |
101 | } | |
102 | ||
103 | /* 1 second of varying frequency between 100 and 10000 Hz */ | |
104 | a = 0; | |
105 | for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) { | |
106 | v = sin(a) * 0.30; | |
107 | for (ch = 0; ch < channels; ch++) | |
108 | PUT_SAMPLE | |
109 | f = 100.0 + (((10000.0 - 100.0) * i) / sample_rate); | |
110 | a += M_PI * f * 2.0 / sample_rate; | |
111 | } | |
112 | ||
113 | /* 0.5 second of low amplitude white noise */ | |
114 | for (i = 0; i < sample_rate / 2 && k < nb_samples; i++, k++) { | |
115 | v = dbl_rand(rnd) * 0.30; | |
116 | for (ch = 0; ch < channels; ch++) | |
117 | PUT_SAMPLE | |
118 | } | |
119 | ||
120 | /* 0.5 second of high amplitude white noise */ | |
121 | for (i = 0; i < sample_rate / 2 && k < nb_samples; i++, k++) { | |
122 | v = dbl_rand(rnd); | |
123 | for (ch = 0; ch < channels; ch++) | |
124 | PUT_SAMPLE | |
125 | } | |
126 | ||
127 | /* 1 second of unrelated ramps for each channel */ | |
128 | for (ch = 0; ch < channels; ch++) { | |
129 | taba[ch] = 0; | |
130 | tabf1[ch] = 100 + av_lfg_get(rnd) % 5000; | |
131 | tabf2[ch] = 100 + av_lfg_get(rnd) % 5000; | |
132 | } | |
133 | for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) { | |
134 | for (ch = 0; ch < channels; ch++) { | |
135 | v = sin(taba[ch]) * 0.30; | |
136 | PUT_SAMPLE | |
137 | f = tabf1[ch] + (((tabf2[ch] - tabf1[ch]) * i) / sample_rate); | |
138 | taba[ch] += M_PI * f * 2.0 / sample_rate; | |
139 | } | |
140 | } | |
141 | ||
142 | /* 2 seconds of 500 Hz with varying volume */ | |
143 | a = 0; | |
144 | ampa = 0; | |
145 | for (i = 0; i < 2 * sample_rate && k < nb_samples; i++, k++) { | |
146 | for (ch = 0; ch < channels; ch++) { | |
147 | double amp = (1.0 + sin(ampa)) * 0.15; | |
148 | if (ch & 1) | |
149 | amp = 0.30 - amp; | |
150 | v = sin(a) * amp; | |
151 | PUT_SAMPLE | |
152 | a += M_PI * 500.0 * 2.0 / sample_rate; | |
153 | ampa += M_PI * 2.0 / sample_rate; | |
154 | } | |
155 | } | |
156 | } | |
157 | ||
158 | /* formats, rates, and layouts are ordered for priority in testing. | |
159 | e.g. 'avresample-test 4 2 2' will test all input/output combinations of | |
160 | S16/FLTP/S16P/FLT, 48000/44100, and stereo/mono */ | |
161 | ||
162 | static const enum AVSampleFormat formats[] = { | |
163 | AV_SAMPLE_FMT_S16, | |
164 | AV_SAMPLE_FMT_FLTP, | |
165 | AV_SAMPLE_FMT_S16P, | |
166 | AV_SAMPLE_FMT_FLT, | |
167 | AV_SAMPLE_FMT_S32P, | |
168 | AV_SAMPLE_FMT_S32, | |
169 | AV_SAMPLE_FMT_U8P, | |
170 | AV_SAMPLE_FMT_U8, | |
171 | AV_SAMPLE_FMT_DBLP, | |
172 | AV_SAMPLE_FMT_DBL, | |
173 | }; | |
174 | ||
175 | static const int rates[] = { | |
176 | 48000, | |
177 | 44100, | |
178 | 16000 | |
179 | }; | |
180 | ||
181 | static const uint64_t layouts[] = { | |
182 | AV_CH_LAYOUT_STEREO, | |
183 | AV_CH_LAYOUT_MONO, | |
184 | AV_CH_LAYOUT_5POINT1, | |
185 | AV_CH_LAYOUT_7POINT1, | |
186 | }; | |
187 | ||
188 | int main(int argc, char **argv) | |
189 | { | |
190 | AVAudioResampleContext *s; | |
191 | AVLFG rnd; | |
192 | int ret = 0; | |
193 | uint8_t *in_buf = NULL; | |
194 | uint8_t *out_buf = NULL; | |
195 | unsigned int in_buf_size; | |
196 | unsigned int out_buf_size; | |
197 | uint8_t *in_data[AVRESAMPLE_MAX_CHANNELS] = { 0 }; | |
198 | uint8_t *out_data[AVRESAMPLE_MAX_CHANNELS] = { 0 }; | |
199 | int in_linesize; | |
200 | int out_linesize; | |
201 | uint64_t in_ch_layout; | |
202 | int in_channels; | |
203 | enum AVSampleFormat in_fmt; | |
204 | int in_rate; | |
205 | uint64_t out_ch_layout; | |
206 | int out_channels; | |
207 | enum AVSampleFormat out_fmt; | |
208 | int out_rate; | |
209 | int num_formats, num_rates, num_layouts; | |
210 | int i, j, k, l, m, n; | |
211 | ||
212 | num_formats = 2; | |
213 | num_rates = 2; | |
214 | num_layouts = 2; | |
215 | if (argc > 1) { | |
216 | if (!av_strncasecmp(argv[1], "-h", 3)) { | |
217 | av_log(NULL, AV_LOG_INFO, "Usage: avresample-test [<num formats> " | |
218 | "[<num sample rates> [<num channel layouts>]]]\n" | |
219 | "Default is 2 2 2\n"); | |
220 | return 0; | |
221 | } | |
222 | num_formats = strtol(argv[1], NULL, 0); | |
223 | num_formats = av_clip(num_formats, 1, FF_ARRAY_ELEMS(formats)); | |
224 | } | |
225 | if (argc > 2) { | |
226 | num_rates = strtol(argv[2], NULL, 0); | |
227 | num_rates = av_clip(num_rates, 1, FF_ARRAY_ELEMS(rates)); | |
228 | } | |
229 | if (argc > 3) { | |
230 | num_layouts = strtol(argv[3], NULL, 0); | |
231 | num_layouts = av_clip(num_layouts, 1, FF_ARRAY_ELEMS(layouts)); | |
232 | } | |
233 | ||
234 | av_log_set_level(AV_LOG_DEBUG); | |
235 | ||
236 | av_lfg_init(&rnd, 0xC0FFEE); | |
237 | ||
238 | in_buf_size = av_samples_get_buffer_size(&in_linesize, 8, 48000 * 6, | |
239 | AV_SAMPLE_FMT_DBLP, 0); | |
240 | out_buf_size = in_buf_size; | |
241 | ||
242 | in_buf = av_malloc(in_buf_size); | |
243 | if (!in_buf) | |
244 | goto end; | |
245 | out_buf = av_malloc(out_buf_size); | |
246 | if (!out_buf) | |
247 | goto end; | |
248 | ||
249 | s = avresample_alloc_context(); | |
250 | if (!s) { | |
251 | av_log(NULL, AV_LOG_ERROR, "Error allocating AVAudioResampleContext\n"); | |
252 | ret = 1; | |
253 | goto end; | |
254 | } | |
255 | ||
256 | for (i = 0; i < num_formats; i++) { | |
257 | in_fmt = formats[i]; | |
258 | for (k = 0; k < num_layouts; k++) { | |
259 | in_ch_layout = layouts[k]; | |
260 | in_channels = av_get_channel_layout_nb_channels(in_ch_layout); | |
261 | for (m = 0; m < num_rates; m++) { | |
262 | in_rate = rates[m]; | |
263 | ||
264 | ret = av_samples_fill_arrays(in_data, &in_linesize, in_buf, | |
265 | in_channels, in_rate * 6, | |
266 | in_fmt, 0); | |
267 | if (ret < 0) { | |
268 | av_log(s, AV_LOG_ERROR, "failed in_data fill arrays\n"); | |
269 | goto end; | |
270 | } | |
271 | audiogen(&rnd, (void **)in_data, in_fmt, in_channels, in_rate, in_rate * 6); | |
272 | ||
273 | for (j = 0; j < num_formats; j++) { | |
274 | out_fmt = formats[j]; | |
275 | for (l = 0; l < num_layouts; l++) { | |
276 | out_ch_layout = layouts[l]; | |
277 | out_channels = av_get_channel_layout_nb_channels(out_ch_layout); | |
278 | for (n = 0; n < num_rates; n++) { | |
279 | out_rate = rates[n]; | |
280 | ||
281 | av_log(NULL, AV_LOG_INFO, "%s to %s, %d to %d channels, %d Hz to %d Hz\n", | |
282 | av_get_sample_fmt_name(in_fmt), av_get_sample_fmt_name(out_fmt), | |
283 | in_channels, out_channels, in_rate, out_rate); | |
284 | ||
285 | ret = av_samples_fill_arrays(out_data, &out_linesize, | |
286 | out_buf, out_channels, | |
287 | out_rate * 6, out_fmt, 0); | |
288 | if (ret < 0) { | |
289 | av_log(s, AV_LOG_ERROR, "failed out_data fill arrays\n"); | |
290 | goto end; | |
291 | } | |
292 | ||
293 | av_opt_set_int(s, "in_channel_layout", in_ch_layout, 0); | |
294 | av_opt_set_int(s, "in_sample_fmt", in_fmt, 0); | |
295 | av_opt_set_int(s, "in_sample_rate", in_rate, 0); | |
296 | av_opt_set_int(s, "out_channel_layout", out_ch_layout, 0); | |
297 | av_opt_set_int(s, "out_sample_fmt", out_fmt, 0); | |
298 | av_opt_set_int(s, "out_sample_rate", out_rate, 0); | |
299 | ||
300 | av_opt_set_int(s, "internal_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); | |
301 | ||
302 | ret = avresample_open(s); | |
303 | if (ret < 0) { | |
304 | av_log(s, AV_LOG_ERROR, "Error opening context\n"); | |
305 | goto end; | |
306 | } | |
307 | ||
308 | ret = avresample_convert(s, out_data, out_linesize, out_rate * 6, | |
309 | in_data, in_linesize, in_rate * 6); | |
310 | if (ret < 0) { | |
311 | char errbuf[256]; | |
312 | av_strerror(ret, errbuf, sizeof(errbuf)); | |
313 | av_log(NULL, AV_LOG_ERROR, "%s\n", errbuf); | |
314 | goto end; | |
315 | } | |
316 | av_log(NULL, AV_LOG_INFO, "Converted %d samples to %d samples\n", | |
317 | in_rate * 6, ret); | |
318 | if (avresample_get_delay(s) > 0) | |
319 | av_log(NULL, AV_LOG_INFO, "%d delay samples not converted\n", | |
320 | avresample_get_delay(s)); | |
321 | if (avresample_available(s) > 0) | |
322 | av_log(NULL, AV_LOG_INFO, "%d samples available for output\n", | |
323 | avresample_available(s)); | |
324 | av_log(NULL, AV_LOG_INFO, "\n"); | |
325 | ||
326 | avresample_close(s); | |
327 | } | |
328 | } | |
329 | } | |
330 | } | |
331 | } | |
332 | } | |
333 | ||
334 | ret = 0; | |
335 | ||
336 | end: | |
337 | av_freep(&in_buf); | |
338 | av_freep(&out_buf); | |
339 | avresample_free(&s); | |
340 | return ret; | |
341 | } |