Better options for test_opus
[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    - Neither the name of the Xiph.org Foundation nor the names of its
17    contributors may be used to endorse or promote products derived from
18    this software without specific prior written permission.
19
20    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
24    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <math.h>
40 #include <string.h>
41 #include "opus.h"
42 #include "SKP_debug.h"
43
44
45 #define MAX_PACKET 1024
46
47 void print_usage( char* argv[] ) 
48 {
49     fprintf(stderr, "Usage: %s <mode (0/1/2)> <sampling rate (Hz)> <channels> <frame size (samples)> "
50         "<bits per second>  [options] <input> <output>\n\n", argv[0]);
51     fprintf(stderr, "mode: 0 for SILK, 1 for hybrid, 2 for CELT:\n" );
52     fprintf(stderr, "options:\n" );
53     fprintf(stderr, "-vbr                 : enable variable bitrate (recommended for SILK)\n" );
54     fprintf(stderr, "-internal_rate <Hz>  : internal sampling rate in Hz, default: input smplng rate\n" );
55     fprintf(stderr, "-max_payload <bytes> : maximum payload size in bytes, default: 1024\n" );
56     fprintf(stderr, "-complexity <comp>   : SILK complexity, 0: low, 1: medium, 2: high; default: 2\n" );
57     fprintf(stderr, "-inbandfec           : enable SILK inband FEC\n" );
58     fprintf(stderr, "-dtx                 : enable SILK DTX\n" );
59     fprintf(stderr, "-loss <perc>         : simulate packet loss, in percent (0-100); default: 0\n" );
60 }
61
62 #ifdef _WIN32
63 #       define STR_CASEINSENSITIVE_COMPARE(x, y) _stricmp(x, y)
64 #else
65 #       define STR_CASEINSENSITIVE_COMPARE(x, y) strcasecmp(x, y)
66 #endif 
67
68
69 int main(int argc, char *argv[])
70 {
71    int err;
72    char *inFile, *outFile;
73    FILE *fin, *fout;
74    OpusEncoder *enc;
75    OpusDecoder *dec;
76    int args;
77    int len;
78    int frame_size, channels;
79    int bitrate_bps;
80    unsigned char *data;
81    int sampling_rate;
82    int use_vbr;
83    int internal_sampling_rate_Hz;
84    int max_payload_bytes;
85    int complexity;
86    int use_inbandfec;
87    int use_dtx;
88    int packet_loss_perc;
89    int count=0, count_act=0, k;
90    int skip;
91    int stop=0;
92    int tot_read=0, tot_written=0;
93    short *in, *out;
94    int mode;
95    double bits=0.0, bits_act=0.0, bits2=0.0, nrg;
96
97    if (argc < 8 )
98    {
99       print_usage( argv );
100       return 1;
101    }
102
103    mode = atoi(argv[1]) + MODE_SILK_ONLY;
104    sampling_rate = atoi(argv[2]);
105    channels = atoi(argv[3]);
106    frame_size = atoi(argv[4]);
107    bitrate_bps = atoi(argv[5]);
108
109    /* defaults: */
110    use_vbr = 0;
111    internal_sampling_rate_Hz = sampling_rate;
112    max_payload_bytes = MAX_PACKET;
113    complexity = 2;
114    use_inbandfec = 0;
115    use_dtx = 0;
116    packet_loss_perc = 0;
117
118    args = 6;
119    while( args < argc - 2 ) {
120        /* process command line options */
121         if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-vbr" ) == 0 ) {
122             use_vbr = 1;
123             args++;
124         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-internal_rate" ) == 0 ) {
125             internal_sampling_rate_Hz = atoi( argv[ args + 1 ] );
126             args += 2;
127         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-max_payload" ) == 0 ) {
128             max_payload_bytes = atoi( argv[ args + 1 ] );
129             args += 2;
130         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-complexity" ) == 0 ) {
131             complexity = atoi( argv[ args + 1 ] );
132             args += 2;
133         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-inbandfec" ) == 0 ) {
134             use_inbandfec = 1;
135             args++;
136         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-fec") == 0 ) {
137             use_dtx = 1;
138             args++;
139         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-loss" ) == 0 ) {
140             packet_loss_perc = atoi( argv[ args + 1 ] );
141             args += 2;
142         } else {
143             printf( "Error: unrecognized setting: %s\n\n", argv[ args ] );
144             print_usage( argv );
145             return 1;
146         }
147    }
148
149    if( mode < MODE_SILK_ONLY || mode > MODE_CELT_ONLY ) {
150       fprintf (stderr, "mode must be: 0, 1 or 2\n");
151       return 1;
152    }
153
154    if (max_payload_bytes < 0 || max_payload_bytes > MAX_PACKET)
155    {
156       fprintf (stderr, "max_payload_bytes must be between 0 and %d\n",
157                         MAX_PACKET);
158       return 1;
159    }
160    if (bitrate_bps < 0 || bitrate_bps*frame_size/sampling_rate > max_payload_bytes*8)
161    {
162       fprintf (stderr, "bytes per packet must be between 0 and %d\n",
163                         max_payload_bytes);
164       return 1;
165    }
166
167    inFile = argv[argc-2];
168    fin = fopen(inFile, "rb");
169    if (!fin)
170    {
171       fprintf (stderr, "Could not open input file %s\n", argv[argc-2]);
172       return 1;
173    }
174    outFile = argv[argc-1];
175    fout = fopen(outFile, "wb+");
176    if (!fout)
177    {
178       fprintf (stderr, "Could not open output file %s\n", argv[argc-1]);
179       return 1;
180    }
181
182    enc = opus_encoder_create(sampling_rate, channels);
183    dec = opus_decoder_create(sampling_rate, channels);
184
185    opus_encoder_ctl(enc, OPUS_SET_MODE(mode));
186    opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
187
188    if( internal_sampling_rate_Hz == 48000 ) {
189        opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(BANDWIDTH_FULLBAND));
190    } else if( internal_sampling_rate_Hz == 32000 ) {
191        opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(BANDWIDTH_SUPERWIDEBAND));
192    //} else if( internal_sampling_rate_Hz == 24000 ) {
193    //    opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(BANDWIDTH_EXTRAWIDEBAND));
194    } else if( internal_sampling_rate_Hz == 16000 ) {
195        opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(BANDWIDTH_WIDEBAND));
196    } else if( internal_sampling_rate_Hz == 12000 ) {
197        opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(BANDWIDTH_MEDIUMBAND));
198    } else if( internal_sampling_rate_Hz == 8000 ) {
199        opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(BANDWIDTH_NARROWBAND));
200    } else {
201       fprintf (stderr, "Unsupported internal sampling rate %d\n", internal_sampling_rate_Hz);
202       return 1;
203    }
204
205    opus_encoder_ctl(enc, OPUS_SET_VBR_FLAG(use_vbr));
206    opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
207    opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC_FLAG(use_inbandfec));
208    opus_encoder_ctl(enc, OPUS_SET_DTX_FLAG(use_dtx));
209
210    //skip = 5*sampling_rate/1000 + 18;      // 18 is when SILK resamples
211    skip = 5*sampling_rate/1000;
212
213    in = (short*)malloc(frame_size*channels*sizeof(short));
214    out = (short*)malloc(frame_size*channels*sizeof(short));
215    data = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
216    while (!stop)
217    {
218       int write_samples;
219       err = fread(in, sizeof(short), frame_size*channels, fin);
220       tot_read += err;
221       if (err < frame_size*channels)
222       {
223           int i;
224           for (i=err;i<frame_size*channels;i++)
225               in[i] = 0;
226       }
227       len = opus_encode(enc, in, frame_size, data, max_payload_bytes);
228       if (len <= 0)
229       {
230          fprintf (stderr, "opus_encode() returned %d\n", len);
231          return 1;
232       }
233
234       opus_decode(dec, rand()%100<packet_loss_perc ? NULL : data, len, out, frame_size);
235       count++;
236       tot_written += (frame_size-skip)*channels;
237       write_samples = frame_size;
238       if (tot_written > tot_read && skip==0)
239       {
240           write_samples -= (tot_written-tot_read)/channels;
241           stop = 1;
242       }
243       fwrite(out+skip, sizeof(short), (write_samples-skip)*channels, fout);
244       skip = 0;
245
246       /* count bits */
247       bits += len*8;
248       nrg = 0.0;
249       for ( k = 0; k < frame_size * channels; k++ ) {
250           nrg += out[ k ] * (double)out[ k ];
251       }
252       if ( ( nrg / ( frame_size * channels ) ) > 1e5 ) {
253           bits_act += len*8;
254           count_act++;
255       }
256           /* Variance */
257           bits2 += len*len*64;
258    }
259    fprintf (stderr, "average bitrate:             %7.3f kb/s\n", 1e-3*bits*sampling_rate/(frame_size*(double)count));
260    fprintf (stderr, "active bitrate:              %7.3f kb/s\n", 1e-3*bits_act*sampling_rate/(frame_size*(double)count_act));
261    fprintf (stderr, "bitrate standard deviation:  %7.3f kb/s\n", 1e-3*sqrt(bits2/count - bits*bits/(count*(double)count))*sampling_rate/frame_size);
262    DEBUG_STORE_CLOSE_FILES              /* Close any files to which intermediate results were stored */
263    opus_encoder_destroy(enc);
264    opus_decoder_destroy(dec);
265    fclose(fin);
266    fclose(fout);
267    free(in);
268    free(out);
269    return 0;
270 }