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