Relicensing to simplified (2-clause) BSD license
[opus.git] / src / test_opus.c
1 /* Copyright (c) 2007-2008 CSIRO
2    Copyright (c) 2007-2009 Xiph.Org Foundation
3    Written by Jean-Marc Valin */
4 /*
5    Redistribution and use in source and binary forms, with or without
6    modification, are permitted provided that the following conditions
7    are met:
8
9    - Redistributions of source code must retain the above copyright
10    notice, this list of conditions and the following disclaimer.
11
12    - Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in the
14    documentation and/or other materials provided with the distribution.
15
16    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
20    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <math.h>
36 #include <string.h>
37 #include "opus.h"
38 #include "SKP_debug.h"
39
40
41 #define MAX_PACKET 1024
42
43 void print_usage( char* argv[] ) 
44 {
45     fprintf(stderr, "Usage: %s <mode (0/1/2)> <sampling rate (Hz)> <channels> "
46         "<bits per second>  [options] <input> <output>\n\n", argv[0]);
47     fprintf(stderr, "mode: 0 for SILK, 1 for hybrid, 2 for CELT:\n" );
48     fprintf(stderr, "options:\n" );
49     fprintf(stderr, "-cbr                 : enable constant bitrate; default: VBR\n" );
50     fprintf(stderr, "-bandwidth <NB|MB|WB|SWB|FB>  : audio bandwidth (from narrowband to fullband); default: sampling rate\n" );
51     fprintf(stderr, "-framesize <2.5|5|10|20|40|60>  : frame size in ms; default: 20 \n" );
52     fprintf(stderr, "-max_payload <bytes> : maximum payload size in bytes, default: 1024\n" );
53     fprintf(stderr, "-complexity <comp>   : complexity, 0 (lowest) ... 10 (highest); default: 10\n" );
54     fprintf(stderr, "-inbandfec           : enable SILK inband FEC\n" );
55     fprintf(stderr, "-dtx                 : enable SILK DTX\n" );
56     fprintf(stderr, "-loss <perc>         : simulate packet loss, in percent (0-100); default: 0\n" );
57 }
58
59 #ifdef _WIN32
60 #       define STR_CASEINSENSITIVE_COMPARE(x, y) _stricmp(x, y)
61 #else
62 #       define STR_CASEINSENSITIVE_COMPARE(x, y) strcasecmp(x, y)
63 #endif 
64
65
66 int main(int argc, char *argv[])
67 {
68    int err;
69    char *inFile, *outFile;
70    FILE *fin, *fout;
71    OpusEncoder *enc;
72    OpusDecoder *dec;
73    int args;
74    int len;
75    int frame_size, channels;
76    int bitrate_bps;
77    unsigned char *data;
78    int sampling_rate;
79    int use_vbr;
80    int internal_sampling_rate_Hz;
81    int max_payload_bytes;
82    int complexity;
83    int use_inbandfec;
84    int use_dtx;
85    int packet_loss_perc;
86    int count=0, count_act=0, k;
87    int skip;
88    int stop=0;
89    int tot_read=0, tot_written=0;
90    short *in, *out;
91    int mode;
92    double bits=0.0, bits_act=0.0, bits2=0.0, nrg;
93    int bandwidth=-1;
94    const char *bandwidth_string;
95
96    if (argc < 7 )
97    {
98       print_usage( argv );
99       return 1;
100    }
101
102    mode = atoi(argv[1]) + MODE_SILK_ONLY;
103    sampling_rate = atoi(argv[2]);
104    channels = atoi(argv[3]);
105    bitrate_bps = atoi(argv[4]);
106
107    frame_size = sampling_rate/50;
108
109    /* defaults: */
110    use_vbr = 1;
111    bandwidth=-1;
112    internal_sampling_rate_Hz = sampling_rate;
113    max_payload_bytes = MAX_PACKET;
114    complexity = 10;
115    use_inbandfec = 0;
116    use_dtx = 0;
117    packet_loss_perc = 0;
118
119    switch(sampling_rate)
120    {
121    case 8000:
122            bandwidth = BANDWIDTH_NARROWBAND;
123            break;
124    case 12000:
125            bandwidth = BANDWIDTH_MEDIUMBAND;
126            break;
127    case 16000:
128            bandwidth = BANDWIDTH_WIDEBAND;
129            break;
130    case 24000:
131            bandwidth = BANDWIDTH_SUPERWIDEBAND;
132            break;
133    case 48000:
134            bandwidth = BANDWIDTH_FULLBAND;
135            break;
136    }
137    args = 5;
138    while( args < argc - 2 ) {
139        /* process command line options */
140         if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-cbr" ) == 0 ) {
141             use_vbr = 0;
142             args++;
143         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-bandwidth" ) == 0 ) {
144             if (strcmp(argv[ args + 1 ], "NB")==0)
145                 bandwidth = BANDWIDTH_NARROWBAND;
146             else if (strcmp(argv[ args + 1 ], "MB")==0)
147                 bandwidth = BANDWIDTH_MEDIUMBAND;
148             else if (strcmp(argv[ args + 1 ], "WB")==0)
149                 bandwidth = BANDWIDTH_WIDEBAND;
150             else if (strcmp(argv[ args + 1 ], "SWB")==0)
151                 bandwidth = BANDWIDTH_SUPERWIDEBAND;
152             else if (strcmp(argv[ args + 1 ], "FB")==0)
153                 bandwidth = BANDWIDTH_FULLBAND;
154             else {
155                 fprintf(stderr, "Unknown bandwidth %s. Supported are NB, MB, WB, SWB, FB.\n", argv[ args + 1 ]);
156                 return 1;
157             }
158             args += 2;
159         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-framesize" ) == 0 ) {
160             if (strcmp(argv[ args + 1 ], "2.5")==0)
161                 frame_size = sampling_rate/400;
162             else if (strcmp(argv[ args + 1 ], "5")==0)
163                 frame_size = sampling_rate/200;
164             else if (strcmp(argv[ args + 1 ], "10")==0)
165                 frame_size = sampling_rate/100;
166             else if (strcmp(argv[ args + 1 ], "20")==0)
167                 frame_size = sampling_rate/50;
168             else if (strcmp(argv[ args + 1 ], "40")==0)
169                 frame_size = sampling_rate/25;
170             else if (strcmp(argv[ args + 1 ], "60")==0)
171                 frame_size = 3*sampling_rate/50;
172             else {
173                 fprintf(stderr, "Unsupported frame size: %s ms. Supported are 2.5, 5, 10, 20, 40, 60.\n", argv[ args + 1 ]);
174                 return 1;
175             }
176             args += 2;
177         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-max_payload" ) == 0 ) {
178             max_payload_bytes = atoi( argv[ args + 1 ] );
179             args += 2;
180         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-complexity" ) == 0 ) {
181             complexity = atoi( argv[ args + 1 ] );
182             args += 2;
183         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-inbandfec" ) == 0 ) {
184             use_inbandfec = 1;
185             args++;
186         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-dtx") == 0 ) {
187             use_dtx = 1;
188             args++;
189         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-loss" ) == 0 ) {
190             packet_loss_perc = atoi( argv[ args + 1 ] );
191             args += 2;
192         } else {
193             printf( "Error: unrecognized setting: %s\n\n", argv[ args ] );
194             print_usage( argv );
195             return 1;
196         }
197    }
198
199    if( mode < MODE_SILK_ONLY || mode > MODE_CELT_ONLY ) {
200       fprintf (stderr, "mode must be: 0, 1 or 2\n");
201       return 1;
202    }
203
204    if (max_payload_bytes < 0 || max_payload_bytes > MAX_PACKET)
205    {
206       fprintf (stderr, "max_payload_bytes must be between 0 and %d\n",
207                         MAX_PACKET);
208       return 1;
209    }
210    if (bitrate_bps < 0 || bitrate_bps*frame_size/sampling_rate > max_payload_bytes*8)
211    {
212       fprintf (stderr, "bytes per packet must be between 0 and %d\n",
213                         max_payload_bytes);
214       return 1;
215    }
216
217    inFile = argv[argc-2];
218    fin = fopen(inFile, "rb");
219    if (!fin)
220    {
221       fprintf (stderr, "Could not open input file %s\n", argv[argc-2]);
222       return 1;
223    }
224    outFile = argv[argc-1];
225    fout = fopen(outFile, "wb+");
226    if (!fout)
227    {
228       fprintf (stderr, "Could not open output file %s\n", argv[argc-1]);
229       return 1;
230    }
231
232    if (mode==MODE_SILK_ONLY)
233    {
234        if (bandwidth == BANDWIDTH_SUPERWIDEBAND || bandwidth == BANDWIDTH_FULLBAND)
235        {
236            fprintf (stderr, "Predictive mode only supports up to wideband\n");
237            return 1;
238        }
239    }
240    if (mode==MODE_HYBRID)
241    {
242        if (bandwidth != BANDWIDTH_SUPERWIDEBAND && bandwidth != BANDWIDTH_FULLBAND)
243        {
244            fprintf (stderr, "Hybrid mode only supports superwideband and fullband\n");
245            return 1;
246        }
247    }
248    if (mode==MODE_CELT_ONLY)
249    {
250        if (bandwidth == BANDWIDTH_MEDIUMBAND)
251        {
252            fprintf (stderr, "Transform mode does not support mediumband\n");
253            return 1;
254        }
255    }
256
257    enc = opus_encoder_create(sampling_rate, channels);
258    dec = opus_decoder_create(sampling_rate, channels);
259
260    opus_encoder_ctl(enc, OPUS_SET_MODE(mode));
261    opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
262
263    if (bandwidth == -1)
264    {
265        fprintf (stderr, "Please specify a bandwidth when the sampling rate does not match one exactly\n");
266        return 1;
267    }
268    opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth));
269
270    opus_encoder_ctl(enc, OPUS_SET_VBR_FLAG(use_vbr));
271    opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
272    opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC_FLAG(use_inbandfec));
273    opus_encoder_ctl(enc, OPUS_SET_DTX_FLAG(use_dtx));
274
275    skip = 5*sampling_rate/1000;
276    /* When SILK resamples, add 18 samples delay */
277    if (mode != MODE_SILK_ONLY || sampling_rate > 16000)
278            skip += 18;
279
280    switch(bandwidth)
281    {
282    case BANDWIDTH_NARROWBAND:
283            bandwidth_string = "narrowband";
284            break;
285    case BANDWIDTH_MEDIUMBAND:
286            bandwidth_string = "mediumband";
287            break;
288    case BANDWIDTH_WIDEBAND:
289            bandwidth_string = "wideband";
290            break;
291    case BANDWIDTH_SUPERWIDEBAND:
292            bandwidth_string = "superwideband";
293            break;
294    case BANDWIDTH_FULLBAND:
295            bandwidth_string = "fullband";
296            break;
297    default:
298            bandwidth_string = "unknown";
299    }
300
301    printf("Encoding %d Hz input at %.3f kb/s in %s mode with %d-sample frames.\n", sampling_rate, bitrate_bps*0.001, bandwidth_string, frame_size);
302
303    in = (short*)malloc(frame_size*channels*sizeof(short));
304    out = (short*)malloc(frame_size*channels*sizeof(short));
305    data = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
306    while (!stop)
307    {
308       int write_samples;
309       int lost;
310       err = fread(in, sizeof(short), frame_size*channels, fin);
311       tot_read += err;
312       if (err < frame_size*channels)
313       {
314           int i;
315           for (i=err;i<frame_size*channels;i++)
316               in[i] = 0;
317       }
318       len = opus_encode(enc, in, frame_size, data, max_payload_bytes);
319       if (len <= 0)
320       {
321          fprintf (stderr, "opus_encode() returned %d\n", len);
322          return 1;
323       }
324
325       lost = rand()%100<packet_loss_perc;
326       opus_decode(dec, lost ? NULL : data, len, out, frame_size);
327       count++;
328       tot_written += (frame_size-skip)*channels;
329       write_samples = frame_size;
330       if (tot_written > tot_read && skip==0)
331       {
332           write_samples -= (tot_written-tot_read)/channels;
333           stop = 1;
334       }
335       fwrite(out+skip, sizeof(short), (write_samples-skip)*channels, fout);
336       skip = 0;
337
338 #if OPUS_TEST_RANGE_CODER_STATE
339       /* compare final range encoder rng values of encoder and decoder */
340       if( !lost && opus_decoder_get_final_range( dec ) != opus_encoder_get_final_range( enc ) ) {
341           fprintf (stderr, "Error: Range coder state mismatch between encoder and decoder.\n");
342           return 0;
343       }
344 #endif
345
346       /* count bits */
347       bits += len*8;
348       nrg = 0.0;
349       for ( k = 0; k < frame_size * channels; k++ ) {
350           nrg += out[ k ] * (double)out[ k ];
351       }
352       if ( ( nrg / ( frame_size * channels ) ) > 1e5 ) {
353           bits_act += len*8;
354           count_act++;
355       }
356           /* Variance */
357           bits2 += len*len*64;
358    }
359    fprintf (stderr, "average bitrate:             %7.3f kb/s\n", 1e-3*bits*sampling_rate/(frame_size*(double)count));
360    fprintf (stderr, "active bitrate:              %7.3f kb/s\n", 1e-3*bits_act*sampling_rate/(frame_size*(double)count_act));
361    fprintf (stderr, "bitrate standard deviation:  %7.3f kb/s\n", 1e-3*sqrt(bits2/count - bits*bits/(count*(double)count))*sampling_rate/frame_size);
362    DEBUG_STORE_CLOSE_FILES              /* Close any files to which intermediate results were stored */
363    opus_encoder_destroy(enc);
364    opus_decoder_destroy(dec);
365    fclose(fin);
366    fclose(fout);
367    free(in);
368    free(out);
369    return 0;
370 }