Simple mode selection logic
[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    /*if (mode==MODE_SILK_ONLY)
237    {
238        if (bandwidth == BANDWIDTH_SUPERWIDEBAND || bandwidth == BANDWIDTH_FULLBAND)
239        {
240            fprintf (stderr, "Predictive mode only supports up to wideband\n");
241            return 1;
242        }
243    }
244    if (mode==MODE_HYBRID)
245    {
246        if (bandwidth != BANDWIDTH_SUPERWIDEBAND && bandwidth != BANDWIDTH_FULLBAND)
247        {
248            fprintf (stderr, "Hybrid mode only supports superwideband and fullband\n");
249            return 1;
250        }
251    }
252    if (mode==MODE_CELT_ONLY)
253    {
254        if (bandwidth == BANDWIDTH_MEDIUMBAND)
255        {
256            fprintf (stderr, "Transform mode does not support mediumband\n");
257            return 1;
258        }
259    }*/
260
261    enc = opus_encoder_create(sampling_rate, channels);
262    dec = opus_decoder_create(sampling_rate, channels);
263
264    if (bandwidth == -1)
265    {
266        fprintf (stderr, "Please specify a bandwidth when the sampling rate does not match one exactly\n");
267        return 1;
268    }
269    opus_encoder_ctl(enc, OPUS_SET_MODE(mode));
270    opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
271    opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth));
272    opus_encoder_ctl(enc, OPUS_SET_VBR_FLAG(use_vbr));
273    opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
274    opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC_FLAG(use_inbandfec));
275    opus_encoder_ctl(enc, OPUS_SET_DTX_FLAG(use_dtx));
276    opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc));
277
278    skip = 5*sampling_rate/1000;
279    /* When SILK resamples, add 18 samples delay */
280    /*if (mode != MODE_SILK_ONLY || sampling_rate > 16000)
281            skip += 18;*/
282
283    switch(bandwidth)
284    {
285    case BANDWIDTH_NARROWBAND:
286            bandwidth_string = "narrowband";
287            break;
288    case BANDWIDTH_MEDIUMBAND:
289            bandwidth_string = "mediumband";
290            break;
291    case BANDWIDTH_WIDEBAND:
292            bandwidth_string = "wideband";
293            break;
294    case BANDWIDTH_SUPERWIDEBAND:
295            bandwidth_string = "superwideband";
296            break;
297    case BANDWIDTH_FULLBAND:
298            bandwidth_string = "fullband";
299            break;
300    default:
301            bandwidth_string = "unknown";
302    }
303
304    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);
305
306    in = (short*)malloc(frame_size*channels*sizeof(short));
307    out = (short*)malloc(frame_size*channels*sizeof(short));
308    data[0] = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
309    if( use_inbandfec ) {
310        data[1] = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
311    }
312    while (!stop)
313    {
314
315       err = fread(in, sizeof(short), frame_size*channels, fin);
316       tot_read += err;
317       if (err < frame_size*channels)
318       {
319           int i;
320           for (i=err;i<frame_size*channels;i++)
321               in[i] = 0;
322       }
323
324       len[toggle] = opus_encode(enc, in, frame_size, data[toggle], max_payload_bytes);
325 #if OPUS_TEST_RANGE_CODER_STATE
326       enc_final_range[toggle] = opus_encoder_get_final_range( enc );
327 #endif
328       if (len[toggle] <= 0)
329       {
330          fprintf (stderr, "opus_encode() returned %d\n", len[toggle]);
331          return 1;
332       }
333
334       lost = rand()%100<packet_loss_perc;
335       if( count >= use_inbandfec ) {
336           /* delay by one packet when using in-band FEC */
337           if( use_inbandfec  ) {
338               if( lost_prev ) {
339                   /* attempt to decode with in-band FEC from next packet */
340                   opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, frame_size, 1);
341               } else {
342                   /* regular decode */
343                   opus_decode(dec, data[1-toggle], len[1-toggle], out, frame_size, 0);
344               }
345           } else {
346               opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, frame_size, 0);
347           }
348           write_samples = frame_size-skip;
349           tot_written += write_samples*channels;
350           if (tot_written > tot_read)
351           {
352               write_samples -= (tot_written-tot_read)/channels;
353               stop = 1;
354           }
355           fwrite(out+skip, sizeof(short), write_samples*channels, fout);
356           skip = 0;
357       }
358
359 #if OPUS_TEST_RANGE_CODER_STATE
360       /* compare final range encoder rng values of encoder and decoder */
361       if( !lost && !lost_prev && opus_decoder_get_final_range( dec ) != enc_final_range[toggle^use_inbandfec] ) {
362           fprintf (stderr, "Error: Range coder state mismatch between encoder and decoder.\n");
363           return 0;
364       }
365 #endif
366
367       lost_prev = lost;
368
369       /* count bits */
370       bits += len[toggle]*8;
371       if( count >= use_inbandfec ) {
372           nrg = 0.0;
373           for ( k = 0; k < frame_size * channels; k++ ) {
374               nrg += in[ k ] * (double)in[ k ];
375           }
376           if ( ( nrg / ( frame_size * channels ) ) > 1e5 ) {
377               bits_act += len[toggle]*8;
378               count_act++;
379           }
380               /* Variance */
381               bits2 += len[toggle]*len[toggle]*64;
382       }
383       count++;
384       toggle = (toggle + use_inbandfec) & 1;
385    }
386    fprintf (stderr, "average bitrate:             %7.3f kb/s\n", 1e-3*bits*sampling_rate/(frame_size*(double)count));
387    fprintf (stderr, "active bitrate:              %7.3f kb/s\n", 1e-3*bits_act*sampling_rate/(frame_size*(double)count_act));
388    fprintf (stderr, "bitrate standard deviation:  %7.3f kb/s\n", 1e-3*sqrt(bits2/count - bits*bits/(count*(double)count))*sampling_rate/frame_size);
389    /* Close any files to which intermediate results were stored */
390    DEBUG_STORE_CLOSE_FILES
391    SKP_TimerSave("opus_timing.txt");
392    opus_encoder_destroy(enc);
393    opus_decoder_destroy(dec);
394    fclose(fin);
395    fclose(fout);
396    free(in);
397    free(out);
398    return 0;
399 }