Cleanup
[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 audo, 1 for voice, 2 for audio:\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[2];
75    int frame_size, channels;
76    int bitrate_bps;
77    unsigned char *data[2];
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    int write_samples;
96    int lost, lost_prev = 1;
97    int toggle = 0;
98    int enc_final_range[2];
99
100    if (argc < 7 )
101    {
102       print_usage( argv );
103       return 1;
104    }
105
106    mode = atoi(argv[1]) + OPUS_MODE_AUTO;
107    sampling_rate = atoi(argv[2]);
108    channels = atoi(argv[3]);
109    bitrate_bps = atoi(argv[4]);
110
111    frame_size = sampling_rate/50;
112
113    /* defaults: */
114    use_vbr = 1;
115    bandwidth=-1;
116    internal_sampling_rate_Hz = sampling_rate;
117    max_payload_bytes = MAX_PACKET;
118    complexity = 10;
119    use_inbandfec = 0;
120    use_dtx = 0;
121    packet_loss_perc = 0;
122
123    switch(sampling_rate)
124    {
125    case 8000:
126            bandwidth = BANDWIDTH_NARROWBAND;
127            break;
128    case 12000:
129            bandwidth = BANDWIDTH_MEDIUMBAND;
130            break;
131    case 16000:
132            bandwidth = BANDWIDTH_WIDEBAND;
133            break;
134    case 24000:
135            bandwidth = BANDWIDTH_SUPERWIDEBAND;
136            break;
137    case 48000:
138            bandwidth = BANDWIDTH_FULLBAND;
139            break;
140    }
141    args = 5;
142    while( args < argc - 2 ) {
143        /* process command line options */
144         if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-cbr" ) == 0 ) {
145             use_vbr = 0;
146             args++;
147         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-bandwidth" ) == 0 ) {
148             if (strcmp(argv[ args + 1 ], "NB")==0)
149                 bandwidth = BANDWIDTH_NARROWBAND;
150             else if (strcmp(argv[ args + 1 ], "MB")==0)
151                 bandwidth = BANDWIDTH_MEDIUMBAND;
152             else if (strcmp(argv[ args + 1 ], "WB")==0)
153                 bandwidth = BANDWIDTH_WIDEBAND;
154             else if (strcmp(argv[ args + 1 ], "SWB")==0)
155                 bandwidth = BANDWIDTH_SUPERWIDEBAND;
156             else if (strcmp(argv[ args + 1 ], "FB")==0)
157                 bandwidth = BANDWIDTH_FULLBAND;
158             else {
159                 fprintf(stderr, "Unknown bandwidth %s. Supported are NB, MB, WB, SWB, FB.\n", argv[ args + 1 ]);
160                 return 1;
161             }
162             args += 2;
163         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-framesize" ) == 0 ) {
164             if (strcmp(argv[ args + 1 ], "2.5")==0)
165                 frame_size = sampling_rate/400;
166             else if (strcmp(argv[ args + 1 ], "5")==0)
167                 frame_size = sampling_rate/200;
168             else if (strcmp(argv[ args + 1 ], "10")==0)
169                 frame_size = sampling_rate/100;
170             else if (strcmp(argv[ args + 1 ], "20")==0)
171                 frame_size = sampling_rate/50;
172             else if (strcmp(argv[ args + 1 ], "40")==0)
173                 frame_size = sampling_rate/25;
174             else if (strcmp(argv[ args + 1 ], "60")==0)
175                 frame_size = 3*sampling_rate/50;
176             else {
177                 fprintf(stderr, "Unsupported frame size: %s ms. Supported are 2.5, 5, 10, 20, 40, 60.\n", argv[ args + 1 ]);
178                 return 1;
179             }
180             args += 2;
181         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-max_payload" ) == 0 ) {
182             max_payload_bytes = atoi( argv[ args + 1 ] );
183             args += 2;
184         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-complexity" ) == 0 ) {
185             complexity = atoi( argv[ args + 1 ] );
186             args += 2;
187         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-inbandfec" ) == 0 ) {
188             use_inbandfec = 1;
189             args++;
190         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-dtx") == 0 ) {
191             use_dtx = 1;
192             args++;
193         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-loss" ) == 0 ) {
194             packet_loss_perc = atoi( argv[ args + 1 ] );
195             args += 2;
196         } else {
197             printf( "Error: unrecognized setting: %s\n\n", argv[ args ] );
198             print_usage( argv );
199             return 1;
200         }
201    }
202
203    if( mode < OPUS_MODE_AUTO || mode > OPUS_MODE_AUDIO) {
204       fprintf (stderr, "mode must be: 0, 1 or 2\n");
205       return 1;
206    }
207
208    if (max_payload_bytes < 0 || max_payload_bytes > MAX_PACKET)
209    {
210       fprintf (stderr, "max_payload_bytes must be between 0 and %d\n",
211                         MAX_PACKET);
212       return 1;
213    }
214    if (bitrate_bps < 0 || bitrate_bps*frame_size/sampling_rate > max_payload_bytes*8)
215    {
216       fprintf (stderr, "bytes per packet must be between 0 and %d\n",
217                         max_payload_bytes);
218       return 1;
219    }
220
221    inFile = argv[argc-2];
222    fin = fopen(inFile, "rb");
223    if (!fin)
224    {
225       fprintf (stderr, "Could not open input file %s\n", argv[argc-2]);
226       return 1;
227    }
228    outFile = argv[argc-1];
229    fout = fopen(outFile, "wb+");
230    if (!fout)
231    {
232       fprintf (stderr, "Could not open output file %s\n", argv[argc-1]);
233       return 1;
234    }
235
236    enc = opus_encoder_create(sampling_rate, channels);
237    dec = opus_decoder_create(sampling_rate, channels);
238
239    if (bandwidth == -1)
240    {
241        fprintf (stderr, "Please specify a bandwidth when the sampling rate does not match one exactly\n");
242        return 1;
243    }
244    opus_encoder_ctl(enc, OPUS_SET_MODE(mode));
245    opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
246    opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth));
247    opus_encoder_ctl(enc, OPUS_SET_VBR_FLAG(use_vbr));
248    opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
249    opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC_FLAG(use_inbandfec));
250    opus_encoder_ctl(enc, OPUS_SET_DTX_FLAG(use_dtx));
251    opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc));
252
253    skip = 5*sampling_rate/1000;
254    /* When SILK resamples, add 18 samples delay */
255    /*if (mode != MODE_SILK_ONLY || sampling_rate > 16000)
256            skip += 18;*/
257
258    switch(bandwidth)
259    {
260    case BANDWIDTH_NARROWBAND:
261            bandwidth_string = "narrowband";
262            break;
263    case BANDWIDTH_MEDIUMBAND:
264            bandwidth_string = "mediumband";
265            break;
266    case BANDWIDTH_WIDEBAND:
267            bandwidth_string = "wideband";
268            break;
269    case BANDWIDTH_SUPERWIDEBAND:
270            bandwidth_string = "superwideband";
271            break;
272    case BANDWIDTH_FULLBAND:
273            bandwidth_string = "fullband";
274            break;
275    default:
276            bandwidth_string = "unknown";
277    }
278
279    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);
280
281    in = (short*)malloc(frame_size*channels*sizeof(short));
282    out = (short*)malloc(frame_size*channels*sizeof(short));
283    data[0] = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
284    if( use_inbandfec ) {
285        data[1] = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
286    }
287    while (!stop)
288    {
289
290       err = fread(in, sizeof(short), frame_size*channels, fin);
291       tot_read += err;
292       if (err < frame_size*channels)
293       {
294           int i;
295           for (i=err;i<frame_size*channels;i++)
296               in[i] = 0;
297       }
298
299       len[toggle] = opus_encode(enc, in, frame_size, data[toggle], max_payload_bytes);
300 #if OPUS_TEST_RANGE_CODER_STATE
301       enc_final_range[toggle] = opus_encoder_get_final_range( enc );
302 #endif
303       if (len[toggle] <= 0)
304       {
305          fprintf (stderr, "opus_encode() returned %d\n", len[toggle]);
306          return 1;
307       }
308
309       lost = rand()%100<packet_loss_perc;
310       if( count >= use_inbandfec ) {
311           /* delay by one packet when using in-band FEC */
312           if( use_inbandfec  ) {
313               if( lost_prev ) {
314                   /* attempt to decode with in-band FEC from next packet */
315                   opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, frame_size, 1);
316               } else {
317                   /* regular decode */
318                   opus_decode(dec, data[1-toggle], len[1-toggle], out, frame_size, 0);
319               }
320           } else {
321               opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, frame_size, 0);
322           }
323           write_samples = frame_size-skip;
324           tot_written += write_samples*channels;
325           if (tot_written > tot_read)
326           {
327               write_samples -= (tot_written-tot_read)/channels;
328               stop = 1;
329           }
330           fwrite(out+skip, sizeof(short), write_samples*channels, fout);
331           skip = 0;
332       }
333
334 #if OPUS_TEST_RANGE_CODER_STATE
335       /* compare final range encoder rng values of encoder and decoder */
336       if( !lost && !lost_prev && opus_decoder_get_final_range( dec ) != enc_final_range[toggle^use_inbandfec] ) {
337           fprintf (stderr, "Error: Range coder state mismatch between encoder and decoder.\n");
338           return 0;
339       }
340 #endif
341
342       lost_prev = lost;
343
344       /* count bits */
345       bits += len[toggle]*8;
346       if( count >= use_inbandfec ) {
347           nrg = 0.0;
348           for ( k = 0; k < frame_size * channels; k++ ) {
349               nrg += in[ k ] * (double)in[ k ];
350           }
351           if ( ( nrg / ( frame_size * channels ) ) > 1e5 ) {
352               bits_act += len[toggle]*8;
353               count_act++;
354           }
355               /* Variance */
356               bits2 += len[toggle]*len[toggle]*64;
357       }
358       count++;
359       toggle = (toggle + use_inbandfec) & 1;
360    }
361    fprintf (stderr, "average bitrate:             %7.3f kb/s\n", 1e-3*bits*sampling_rate/(frame_size*(double)count));
362    fprintf (stderr, "active bitrate:              %7.3f kb/s\n", 1e-3*bits_act*sampling_rate/(frame_size*(double)count_act));
363    fprintf (stderr, "bitrate standard deviation:  %7.3f kb/s\n", 1e-3*sqrt(bits2/count - bits*bits/(count*(double)count))*sampling_rate/frame_size);
364    /* Close any files to which intermediate results were stored */
365    DEBUG_STORE_CLOSE_FILES
366    SKP_TimerSave("opus_timing.txt");
367    opus_encoder_destroy(enc);
368    opus_decoder_destroy(dec);
369    fclose(fin);
370    fclose(fout);
371    free(in);
372    free(out);
373    return 0;
374 }