2 * Copyright (C) 2011-2012 Michael Niedermayer (michaelni@gmx.at)
3 * Copyright (c) 2002 Fabrice Bellard
5 * This file is part of libswresample
7 * libswresample is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * libswresample 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
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with libswresample; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "libavutil/avassert.h"
23 #include "libavutil/channel_layout.h"
24 #include "libavutil/common.h"
25 #include "libavutil/opt.h"
26 #include "swresample.h"
36 #define ASSERT_LEVEL 2
38 static double get(uint8_t *a
[], int ch
, int index
, int ch_count
, enum AVSampleFormat f
){
40 if(av_sample_fmt_is_planar(f
)){
41 f
= av_get_alt_sample_fmt(f
, 0);
45 index
= ch
+ index
*ch_count
;
49 case AV_SAMPLE_FMT_U8
: return ((const uint8_t*)p
)[index
]/127.0-1.0;
50 case AV_SAMPLE_FMT_S16
: return ((const int16_t*)p
)[index
]/32767.0;
51 case AV_SAMPLE_FMT_S32
: return ((const int32_t*)p
)[index
]/2147483647.0;
52 case AV_SAMPLE_FMT_FLT
: return ((const float *)p
)[index
];
53 case AV_SAMPLE_FMT_DBL
: return ((const double *)p
)[index
];
54 default: av_assert0(0);
58 static void set(uint8_t *a
[], int ch
, int index
, int ch_count
, enum AVSampleFormat f
, double v
){
60 if(av_sample_fmt_is_planar(f
)){
61 f
= av_get_alt_sample_fmt(f
, 0);
65 index
= ch
+ index
*ch_count
;
68 case AV_SAMPLE_FMT_U8
: ((uint8_t*)p
)[index
]= av_clip_uint8 (lrint((v
+1.0)*127)); break;
69 case AV_SAMPLE_FMT_S16
: ((int16_t*)p
)[index
]= av_clip_int16 (lrint(v
*32767)); break;
70 case AV_SAMPLE_FMT_S32
: ((int32_t*)p
)[index
]= av_clipl_int32(llrint(v
*2147483647)); break;
71 case AV_SAMPLE_FMT_FLT
: ((float *)p
)[index
]= v
; break;
72 case AV_SAMPLE_FMT_DBL
: ((double *)p
)[index
]= v
; break;
73 default: av_assert2(0);
77 static void shift(uint8_t *a
[], int index
, int ch_count
, enum AVSampleFormat f
){
80 if(av_sample_fmt_is_planar(f
)){
81 f
= av_get_alt_sample_fmt(f
, 0);
82 for(ch
= 0; ch
<ch_count
; ch
++)
83 a
[ch
] += index
*av_get_bytes_per_sample(f
);
85 a
[0] += index
*ch_count
*av_get_bytes_per_sample(f
);
89 static const enum AVSampleFormat formats
[] = {
102 static const int rates
[] = {
113 AV_CH_LAYOUT_STEREO
,
115 AV_CH_LAYOUT_SURROUND
,
116 AV_CH_LAYOUT_4POINT0
,
119 AV_CH_LAYOUT_5POINT0
,
120 AV_CH_LAYOUT_5POINT1
,
121 AV_CH_LAYOUT_5POINT0_BACK
,
122 AV_CH_LAYOUT_5POINT1_BACK
,
123 AV_CH_LAYOUT_7POINT0
,
124 AV_CH_LAYOUT_7POINT1
,
125 AV_CH_LAYOUT_7POINT1_WIDE
,
128 static void setup_array(uint8_t *out
[SWR_CH_MAX
], uint8_t *in
, enum AVSampleFormat format
, int samples
){
129 if(av_sample_fmt_is_planar(format
)){
131 int plane_size
= av_get_bytes_per_sample(format
&0xFF)*samples
;
133 for(i
=0; i
<SWR_CH_MAX
; i
++){
134 out
[i
]= in
+ i
*plane_size
;
141 static int cmp(const int *a
, const int *b
){
145 static void audiogen(void *data
, enum AVSampleFormat sample_fmt
,
146 int channels
, int sample_rate
, int nb_samples
)
149 double v
, f
, a
, ampa
;
150 double tabf1
[SWR_CH_MAX
];
151 double tabf2
[SWR_CH_MAX
];
152 double taba
[SWR_CH_MAX
];
155 #define PUT_SAMPLE set(data, ch, k, channels, sample_fmt, v);
156 #define uint_rand(x) (x = x * 1664525 + 1013904223)
157 #define dbl_rand(x) (uint_rand(x)*2.0 / (double)UINT_MAX - 1)
160 /* 1 second of single freq sinus at 1000 Hz */
162 for (i
= 0; i
< 1 * sample_rate
&& k
< nb_samples
; i
++, k
++) {
164 for (ch
= 0; ch
< channels
; ch
++)
166 a
+= M_PI
* 1000.0 * 2.0 / sample_rate
;
169 /* 1 second of varying frequency between 100 and 10000 Hz */
171 for (i
= 0; i
< 1 * sample_rate
&& k
< nb_samples
; i
++, k
++) {
173 for (ch
= 0; ch
< channels
; ch
++)
175 f
= 100.0 + (((10000.0 - 100.0) * i
) / sample_rate
);
176 a
+= M_PI
* f
* 2.0 / sample_rate
;
179 /* 0.5 second of low amplitude white noise */
180 for (i
= 0; i
< sample_rate
/ 2 && k
< nb_samples
; i
++, k
++) {
181 v
= dbl_rand(rnd
) * 0.30;
182 for (ch
= 0; ch
< channels
; ch
++)
186 /* 0.5 second of high amplitude white noise */
187 for (i
= 0; i
< sample_rate
/ 2 && k
< nb_samples
; i
++, k
++) {
189 for (ch
= 0; ch
< channels
; ch
++)
193 /* 1 second of unrelated ramps for each channel */
194 for (ch
= 0; ch
< channels
; ch
++) {
196 tabf1
[ch
] = 100 + uint_rand(rnd
) % 5000;
197 tabf2
[ch
] = 100 + uint_rand(rnd
) % 5000;
199 for (i
= 0; i
< 1 * sample_rate
&& k
< nb_samples
; i
++, k
++) {
200 for (ch
= 0; ch
< channels
; ch
++) {
201 v
= sin(taba
[ch
]) * 0.30;
203 f
= tabf1
[ch
] + (((tabf2
[ch
] - tabf1
[ch
]) * i
) / sample_rate
);
204 taba
[ch
] += M_PI
* f
* 2.0 / sample_rate
;
208 /* 2 seconds of 500 Hz with varying volume */
211 for (i
= 0; i
< 2 * sample_rate
&& k
< nb_samples
; i
++, k
++) {
212 for (ch
= 0; ch
< channels
; ch
++) {
213 double amp
= (1.0 + sin(ampa
)) * 0.15;
218 a
+= M_PI
* 500.0 * 2.0 / sample_rate
;
219 ampa
+= M_PI
* 2.0 / sample_rate
;
224 int main(int argc
, char **argv
){
225 int in_sample_rate
, out_sample_rate
, ch
,i
, flush_count
;
226 uint64_t in_ch_layout
, out_ch_layout
;
227 enum AVSampleFormat in_sample_fmt
, out_sample_fmt
;
228 uint8_t array_in
[SAMPLES
*8*8];
229 uint8_t array_mid
[SAMPLES
*8*8*3];
230 uint8_t array_out
[SAMPLES
*8*8+100];
231 uint8_t *ain
[SWR_CH_MAX
];
232 uint8_t *aout
[SWR_CH_MAX
];
233 uint8_t *amid
[SWR_CH_MAX
];
236 int num_tests
= 10000;
238 uint32_t rand_seed
= 0;
239 int remaining_tests
[FF_ARRAY_ELEMS(rates
) * FF_ARRAY_ELEMS(layouts
) * FF_ARRAY_ELEMS(formats
) * FF_ARRAY_ELEMS(layouts
) * FF_ARRAY_ELEMS(formats
)];
240 int max_tests
= FF_ARRAY_ELEMS(remaining_tests
);
242 int specific_test
= -1;
244 struct SwrContext
* forw_ctx
= NULL
;
245 struct SwrContext
*backw_ctx
= NULL
;
248 if (!strcmp(argv
[1], "-h") || !strcmp(argv
[1], "--help")) {
249 av_log(NULL
, AV_LOG_INFO
, "Usage: swresample-test [<num_tests>[ <test>]] \n"
250 "num_tests Default is %d\n", num_tests
);
253 num_tests
= strtol(argv
[1], NULL
, 0);
255 num_tests
= -num_tests
;
258 if(num_tests
<= 0 || num_tests
>max_tests
)
259 num_tests
= max_tests
;
261 specific_test
= strtol(argv
[1], NULL
, 0);
265 for(i
=0; i
<max_tests
; i
++)
266 remaining_tests
[i
] = i
;
268 for(test
=0; test
<num_tests
; test
++){
271 r
= (seed
* (uint64_t)(max_tests
- test
)) >>32;
272 FFSWAP(int, remaining_tests
[r
], remaining_tests
[max_tests
- test
- 1]);
274 qsort(remaining_tests
+ max_tests
- num_tests
, num_tests
, sizeof(remaining_tests
[0]), (void*)cmp
);
275 in_sample_rate
=16000;
276 for(test
=0; test
<num_tests
; test
++){
277 char in_layout_string
[256];
278 char out_layout_string
[256];
279 unsigned vector
= remaining_tests
[max_tests
- test
- 1];
281 int out_count
, mid_count
, out_ch_count
;
283 in_ch_layout
= layouts
[vector
% FF_ARRAY_ELEMS(layouts
)]; vector
/= FF_ARRAY_ELEMS(layouts
);
284 out_ch_layout
= layouts
[vector
% FF_ARRAY_ELEMS(layouts
)]; vector
/= FF_ARRAY_ELEMS(layouts
);
285 in_sample_fmt
= formats
[vector
% FF_ARRAY_ELEMS(formats
)]; vector
/= FF_ARRAY_ELEMS(formats
);
286 out_sample_fmt
= formats
[vector
% FF_ARRAY_ELEMS(formats
)]; vector
/= FF_ARRAY_ELEMS(formats
);
287 out_sample_rate
= rates
[vector
% FF_ARRAY_ELEMS(rates
)]; vector
/= FF_ARRAY_ELEMS(rates
);
290 if(specific_test
== 0){
291 if(out_sample_rate
!= in_sample_rate
|| in_ch_layout
!= out_ch_layout
)
295 in_ch_count
= av_get_channel_layout_nb_channels(in_ch_layout
);
296 out_ch_count
= av_get_channel_layout_nb_channels(out_ch_layout
);
297 av_get_channel_layout_string( in_layout_string
, sizeof( in_layout_string
), in_ch_count
, in_ch_layout
);
298 av_get_channel_layout_string(out_layout_string
, sizeof(out_layout_string
), out_ch_count
, out_ch_layout
);
299 fprintf(stderr
, "TEST: %s->%s, rate:%5d->%5d, fmt:%s->%s\n",
300 in_layout_string
, out_layout_string
,
301 in_sample_rate
, out_sample_rate
,
302 av_get_sample_fmt_name(in_sample_fmt
), av_get_sample_fmt_name(out_sample_fmt
));
303 forw_ctx
= swr_alloc_set_opts(forw_ctx
, out_ch_layout
, out_sample_fmt
, out_sample_rate
,
304 in_ch_layout
, in_sample_fmt
, in_sample_rate
,
306 backw_ctx
= swr_alloc_set_opts(backw_ctx
, in_ch_layout
, in_sample_fmt
, in_sample_rate
,
307 out_ch_layout
, out_sample_fmt
, out_sample_rate
,
310 fprintf(stderr
, "Failed to init forw_cts\n");
314 fprintf(stderr
, "Failed to init backw_ctx\n");
317 if(swr_init( forw_ctx
) < 0)
318 fprintf(stderr
, "swr_init(->) failed\n");
319 if(swr_init(backw_ctx
) < 0)
320 fprintf(stderr
, "swr_init(<-) failed\n");
322 setup_array(ain
, array_in
, in_sample_fmt
, SAMPLES
);
323 setup_array(amid
, array_mid
, out_sample_fmt
, 3*SAMPLES
);
324 setup_array(aout
, array_out
, in_sample_fmt
, SAMPLES
);
326 for(ch
=0; ch
<in_ch_count
; ch
++){
327 for(i
=0; i
<SAMPLES
; i
++)
328 set(ain
, ch
, i
, in_ch_count
, in_sample_fmt
, sin(i
*i
*3/SAMPLES
));
331 audiogen(ain
, in_sample_fmt
, in_ch_count
, SAMPLES
/6+1, SAMPLES
);
333 mode
= uint_rand(rand_seed
) % 3;
334 if(mode
==0 /*|| out_sample_rate == in_sample_rate*/) {
335 mid_count
= swr_convert(forw_ctx
, amid
, 3*SAMPLES
, (const uint8_t **)ain
, SAMPLES
);
337 mid_count
= swr_convert(forw_ctx
, amid
, 0, (const uint8_t **)ain
, SAMPLES
);
338 mid_count
+=swr_convert(forw_ctx
, amid
, 3*SAMPLES
, (const uint8_t **)ain
, 0);
341 mid_count
= swr_convert(forw_ctx
, amid
, 0, (const uint8_t **)ain
, 1);
342 av_assert0(mid_count
==0);
343 shift(ain
, 1, in_ch_count
, in_sample_fmt
);
344 mid_count
+=swr_convert(forw_ctx
, amid
, 3*SAMPLES
, (const uint8_t **)ain
, 0);
345 shift(amid
, mid_count
, out_ch_count
, out_sample_fmt
); tmp_count
= mid_count
;
346 mid_count
+=swr_convert(forw_ctx
, amid
, 2, (const uint8_t **)ain
, 2);
347 shift(amid
, mid_count
-tmp_count
, out_ch_count
, out_sample_fmt
); tmp_count
= mid_count
;
348 shift(ain
, 2, in_ch_count
, in_sample_fmt
);
349 mid_count
+=swr_convert(forw_ctx
, amid
, 1, (const uint8_t **)ain
, SAMPLES
-3);
350 shift(amid
, mid_count
-tmp_count
, out_ch_count
, out_sample_fmt
); tmp_count
= mid_count
;
351 shift(ain
, -3, in_ch_count
, in_sample_fmt
);
352 mid_count
+=swr_convert(forw_ctx
, amid
, 3*SAMPLES
, (const uint8_t **)ain
, 0);
353 shift(amid
, -tmp_count
, out_ch_count
, out_sample_fmt
);
355 out_count
= swr_convert(backw_ctx
,aout
, SAMPLES
, (const uint8_t **)amid
, mid_count
);
357 for(ch
=0; ch
<in_ch_count
; ch
++){
358 double sse
, maxdiff
=0;
364 for(i
=0; i
<out_count
; i
++){
365 double a
= get(ain
, ch
, i
, in_ch_count
, in_sample_fmt
);
366 double b
= get(aout
, ch
, i
, in_ch_count
, in_sample_fmt
);
372 maxdiff
= FFMAX(maxdiff
, FFABS(a
-b
));
374 sse
= sum_aa
+ sum_bb
- 2*sum_ab
;
375 if(sse
< 0 && sse
> -0.00001) sse
=0; //fix rounding error
377 fprintf(stderr
, "[e:%f c:%f max:%f] len:%5d\n", out_count
? sqrt(sse
/out_count
) : 0, sum_ab
/(sqrt(sum_aa
*sum_bb
)), maxdiff
, out_count
);
382 flush_count
= swr_convert(backw_ctx
,aout
, flush_i
, 0, 0);
383 shift(aout
, flush_i
, in_ch_count
, in_sample_fmt
);
384 flush_count
+= swr_convert(backw_ctx
,aout
, SAMPLES
-flush_i
, 0, 0);
385 shift(aout
, -flush_i
, in_ch_count
, in_sample_fmt
);
387 for(ch
=0; ch
<in_ch_count
; ch
++){
388 double sse
, maxdiff
=0;
394 for(i
=0; i
<flush_count
; i
++){
395 double a
= get(ain
, ch
, i
+out_count
, in_ch_count
, in_sample_fmt
);
396 double b
= get(aout
, ch
, i
, in_ch_count
, in_sample_fmt
);
402 maxdiff
= FFMAX(maxdiff
, FFABS(a
-b
));
404 sse
= sum_aa
+ sum_bb
- 2*sum_ab
;
405 if(sse
< 0 && sse
> -0.00001) sse
=0; //fix rounding error
407 fprintf(stderr
, "[e:%f c:%f max:%f] len:%5d F:%3d\n", sqrt(sse
/flush_count
), sum_ab
/(sqrt(sum_aa
*sum_bb
)), maxdiff
, flush_count
, flush_i
);
412 fprintf(stderr
, "\n");