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
35static 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)                                     \
41static 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
53PUT_FUNC(u8,  AV_SAMPLE_FMT_U8,  uint8_t, av_clip_uint8 ( lrint(v_dbl * (1  <<  7)) + 128))
54PUT_FUNC(s16, AV_SAMPLE_FMT_S16, int16_t, av_clip_int16 ( lrint(v_dbl * (1  << 15))))
55PUT_FUNC(s32, AV_SAMPLE_FMT_S32, int32_t, av_clipl_int32(llrint(v_dbl * (1U << 31))))
56PUT_FUNC(flt, AV_SAMPLE_FMT_FLT, float,   v_dbl)
57PUT_FUNC(dbl, AV_SAMPLE_FMT_DBL, double,  v_dbl)
58
59static 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
81static 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
162static 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
175static const int rates[] = {
176    48000,
177    44100,
178    16000
179};
180
181static 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
188int 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
336end:
337    av_freep(&in_buf);
338    av_freep(&out_buf);
339    avresample_free(&s);
340    return ret;
341}
342