splitting encoder config in terms of application and signal type
[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 "silk_debug.h"
39
40
41 #define MAX_PACKET 1500
42
43 void print_usage( char* argv[] ) 
44 {
45     fprintf(stderr, "Usage: %s <application (0/1)> <sampling rate (Hz)> <channels (1/2)> "
46         "<bits per second>  [options] <input> <output>\n\n", argv[0]);
47     fprintf(stderr, "mode: 0 for VoIP, 1 for audio:\n" );
48     fprintf(stderr, "options:\n" );
49     fprintf(stderr, "-cbr                 : enable constant bitrate; default: variable bitrate\n" );
50     fprintf(stderr, "-cvbr                : enable constraint variable bitrate; default: unconstraint\n" );
51     fprintf(stderr, "-bandwidth <NB|MB|WB|SWB|FB>  : audio bandwidth (from narrowband to fullband); default: sampling rate\n" );
52     fprintf(stderr, "-framesize <2.5|5|10|20|40|60>  : frame size in ms; default: 20 \n" );
53     fprintf(stderr, "-max_payload <bytes> : maximum payload size in bytes, default: 1024\n" );
54     fprintf(stderr, "-complexity <comp>   : complexity, 0 (lowest) ... 10 (highest); default: 10\n" );
55     fprintf(stderr, "-inbandfec           : enable SILK inband FEC\n" );
56     fprintf(stderr, "-forcemono           : force mono encoding, even for stereo input\n" );
57     fprintf(stderr, "-dtx                 : enable SILK DTX\n" );
58     fprintf(stderr, "-loss <perc>         : simulate packet loss, in percent (0-100); default: 0\n" );
59 }
60
61 #ifdef _WIN32
62 #       define STR_CASEINSENSITIVE_COMPARE(x, y) _stricmp(x, y)
63 #else
64 #       define STR_CASEINSENSITIVE_COMPARE(x, y) strcasecmp(x, y)
65 #endif 
66
67
68 int main(int argc, char *argv[])
69 {
70    int err;
71    char *inFile, *outFile;
72    FILE *fin, *fout;
73    OpusEncoder *enc;
74    OpusDecoder *dec;
75    int args;
76    int len[2];
77    int frame_size, channels;
78    int bitrate_bps;
79    unsigned char *data[2];
80    int sampling_rate;
81    int use_vbr;
82    int internal_sampling_rate_Hz;
83    int max_payload_bytes;
84    int complexity;
85    int use_inbandfec;
86    int use_dtx;
87    int forcemono;
88    int cvbr = 0;
89    int packet_loss_perc;
90    int count=0, count_act=0, k;
91    int skip;
92    int stop=0;
93    int tot_read=0, tot_written=0;
94    short *in, *out;
95    int application;
96    double bits=0.0, bits_act=0.0, bits2=0.0, nrg;
97    int bandwidth=-1;
98    const char *bandwidth_string;
99    int write_samples;
100    int lost, lost_prev = 1;
101    int toggle = 0;
102    int enc_final_range[2];
103
104    if (argc < 7 )
105    {
106       print_usage( argv );
107       return 1;
108    }
109
110    application = atoi(argv[1]) + OPUS_APPLICATION_VOIP;
111    sampling_rate = atoi(argv[2]);
112    channels = atoi(argv[3]);
113    bitrate_bps = atoi(argv[4]);
114
115    if (sampling_rate != 8000 && sampling_rate != 12000 && sampling_rate != 16000
116            && sampling_rate != 24000 && sampling_rate != 48000)
117    {
118        fprintf(stderr, "Supported sampling rates are 8000, 12000, 16000, "
119                "24000 and 48000.\n");
120        return 1;
121    }
122    frame_size = sampling_rate/50;
123
124    /* defaults: */
125    use_vbr = 1;
126    bandwidth=OPUS_BANDWIDTH_AUTO;
127    internal_sampling_rate_Hz = sampling_rate;
128    max_payload_bytes = MAX_PACKET;
129    complexity = 10;
130    use_inbandfec = 0;
131    forcemono = 0;
132    use_dtx = 0;
133    packet_loss_perc = 0;
134
135    args = 5;
136    while( args < argc - 2 ) {
137        /* process command line options */
138         if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-cbr" ) == 0 ) {
139             use_vbr = 0;
140             args++;
141         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-bandwidth" ) == 0 ) {
142             if (strcmp(argv[ args + 1 ], "NB")==0)
143                 bandwidth = OPUS_BANDWIDTH_NARROWBAND;
144             else if (strcmp(argv[ args + 1 ], "MB")==0)
145                 bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
146             else if (strcmp(argv[ args + 1 ], "WB")==0)
147                 bandwidth = OPUS_BANDWIDTH_WIDEBAND;
148             else if (strcmp(argv[ args + 1 ], "SWB")==0)
149                 bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND;
150             else if (strcmp(argv[ args + 1 ], "FB")==0)
151                 bandwidth = OPUS_BANDWIDTH_FULLBAND;
152             else {
153                 fprintf(stderr, "Unknown bandwidth %s. Supported are NB, MB, WB, SWB, FB.\n", argv[ args + 1 ]);
154                 return 1;
155             }
156             args += 2;
157         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-framesize" ) == 0 ) {
158             if (strcmp(argv[ args + 1 ], "2.5")==0)
159                 frame_size = sampling_rate/400;
160             else if (strcmp(argv[ args + 1 ], "5")==0)
161                 frame_size = sampling_rate/200;
162             else if (strcmp(argv[ args + 1 ], "10")==0)
163                 frame_size = sampling_rate/100;
164             else if (strcmp(argv[ args + 1 ], "20")==0)
165                 frame_size = sampling_rate/50;
166             else if (strcmp(argv[ args + 1 ], "40")==0)
167                 frame_size = sampling_rate/25;
168             else if (strcmp(argv[ args + 1 ], "60")==0)
169                 frame_size = 3*sampling_rate/50;
170             else {
171                 fprintf(stderr, "Unsupported frame size: %s ms. Supported are 2.5, 5, 10, 20, 40, 60.\n", argv[ args + 1 ]);
172                 return 1;
173             }
174             args += 2;
175         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-max_payload" ) == 0 ) {
176             max_payload_bytes = atoi( argv[ args + 1 ] );
177             args += 2;
178         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-complexity" ) == 0 ) {
179             complexity = atoi( argv[ args + 1 ] );
180             args += 2;
181         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-inbandfec" ) == 0 ) {
182             use_inbandfec = 1;
183             args++;
184         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-forcemono" ) == 0 ) {
185             forcemono = 1;
186             args++;
187         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-cvbr" ) == 0 ) {
188             cvbr = 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( application < OPUS_APPLICATION_VOIP || application > OPUS_APPLICATION_AUDIO) {
204       fprintf (stderr, "mode must be: 0 or 1\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, application);
237    dec = opus_decoder_create(sampling_rate, channels);
238
239    if (enc==NULL)
240    {
241       fprintf(stderr, "Failed to create an encoder\n");
242       exit(1);
243    }
244    if (dec==NULL)
245    {
246       fprintf(stderr, "Failed to create a decoder\n");
247       exit(1);
248    }
249
250    opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
251    opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth));
252    opus_encoder_ctl(enc, OPUS_SET_VBR_FLAG(use_vbr));
253    opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(cvbr));
254    opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
255    opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC_FLAG(use_inbandfec));
256    opus_encoder_ctl(enc, OPUS_SET_FORCE_MONO(forcemono));
257    opus_encoder_ctl(enc, OPUS_SET_DTX_FLAG(use_dtx));
258    opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc));
259
260    skip = 5*sampling_rate/1000;
261    /* When SILK resamples, add 18 samples delay */
262    /*if (mode != MODE_SILK_ONLY || sampling_rate > 16000)
263            skip += 18;*/
264
265    switch(bandwidth)
266    {
267    case OPUS_BANDWIDTH_NARROWBAND:
268            bandwidth_string = "narrowband";
269            break;
270    case OPUS_BANDWIDTH_MEDIUMBAND:
271            bandwidth_string = "mediumband";
272            break;
273    case OPUS_BANDWIDTH_WIDEBAND:
274            bandwidth_string = "wideband";
275            break;
276    case OPUS_BANDWIDTH_SUPERWIDEBAND:
277            bandwidth_string = "superwideband";
278            break;
279    case OPUS_BANDWIDTH_FULLBAND:
280            bandwidth_string = "fullband";
281            break;
282    case OPUS_BANDWIDTH_AUTO:
283            bandwidth_string = "auto";
284            break;
285    default:
286            bandwidth_string = "unknown";
287    }
288
289    fprintf(stderr, "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);
290
291    in = (short*)malloc(frame_size*channels*sizeof(short));
292    out = (short*)malloc(frame_size*channels*sizeof(short));
293    data[0] = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
294    if( use_inbandfec ) {
295        data[1] = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
296    }
297    while (!stop)
298    {
299
300       err = fread(in, sizeof(short), frame_size*channels, fin);
301       tot_read += err;
302       if (err < frame_size*channels)
303       {
304           int i;
305           for (i=err;i<frame_size*channels;i++)
306               in[i] = 0;
307       }
308
309       len[toggle] = opus_encode(enc, in, frame_size, data[toggle], max_payload_bytes);
310 #if OPUS_TEST_RANGE_CODER_STATE
311       enc_final_range[toggle] = opus_encoder_get_final_range( enc );
312 #endif
313       if (len[toggle] < 0)
314       {
315          fprintf (stderr, "opus_encode() returned %d\n", len[toggle]);
316          return 1;
317       }
318
319       lost = rand()%100 < packet_loss_perc || len[toggle]==0;
320       if( count >= use_inbandfec ) {
321           /* delay by one packet when using in-band FEC */
322           if( use_inbandfec  ) {
323               if( lost_prev ) {
324                   /* attempt to decode with in-band FEC from next packet */
325                   opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, frame_size, 1);
326               } else {
327                   /* regular decode */
328                   opus_decode(dec, data[1-toggle], len[1-toggle], out, frame_size, 0);
329               }
330           } else {
331               opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, frame_size, 0);
332           }
333           write_samples = frame_size-skip;
334           tot_written += write_samples*channels;
335           if (tot_written > tot_read)
336           {
337               write_samples -= (tot_written-tot_read)/channels;
338               stop = 1;
339           }
340           fwrite(out+skip, sizeof(short), write_samples*channels, fout);
341           skip = 0;
342       }
343
344 #if OPUS_TEST_RANGE_CODER_STATE
345       /* compare final range encoder rng values of encoder and decoder */
346       if( !lost && !lost_prev && opus_decoder_get_final_range( dec ) != enc_final_range[toggle^use_inbandfec] ) {
347           fprintf (stderr, "Error: Range coder state mismatch between encoder and decoder in frame %d.\n", count);
348           return 0;
349       }
350 #endif
351
352       lost_prev = lost;
353
354       /* count bits */
355       bits += len[toggle]*8;
356       if( count >= use_inbandfec ) {
357           nrg = 0.0;
358           for ( k = 0; k < frame_size * channels; k++ ) {
359               nrg += in[ k ] * (double)in[ k ];
360           }
361           if ( ( nrg / ( frame_size * channels ) ) > 1e5 ) {
362               bits_act += len[toggle]*8;
363               count_act++;
364           }
365               /* Variance */
366               bits2 += len[toggle]*len[toggle]*64;
367       }
368       count++;
369       toggle = (toggle + use_inbandfec) & 1;
370    }
371    fprintf (stderr, "average bitrate:             %7.3f kb/s\n", 1e-3*bits*sampling_rate/(frame_size*(double)count));
372    fprintf (stderr, "active bitrate:              %7.3f kb/s\n", 1e-3*bits_act*sampling_rate/(frame_size*(double)count_act));
373    fprintf (stderr, "bitrate standard deviation:  %7.3f kb/s\n", 1e-3*sqrt(bits2/count - bits*bits/(count*(double)count))*sampling_rate/frame_size);
374    /* Close any files to which intermediate results were stored */
375    SILK_DEBUG_STORE_CLOSE_FILES
376    silk_TimerSave("opus_timing.txt");
377    opus_encoder_destroy(enc);
378    opus_decoder_destroy(dec);
379    free(data[0]);
380    if (use_inbandfec)
381            free(data[1]);
382    fclose(fin);
383    fclose(fout);
384    free(in);
385    free(out);
386    return 0;
387 }