Some more hybrid tuning (mostly for CBR)
[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, "-bandwidth <NB|MB|WB|SWB|FB>  : audio bandwidth (from narrowband to fullband)\n" );
55     fprintf(stderr, "-max_payload <bytes> : maximum payload size in bytes, default: 1024\n" );
56     fprintf(stderr, "-complexity <comp>   : complexity, 0 (lowest) ... 10 (highest); default: 10\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    int bandwidth=-1;
97
98    if (argc < 8 )
99    {
100       print_usage( argv );
101       return 1;
102    }
103
104    mode = atoi(argv[1]) + MODE_SILK_ONLY;
105    sampling_rate = atoi(argv[2]);
106    channels = atoi(argv[3]);
107    frame_size = atoi(argv[4]);
108    bitrate_bps = atoi(argv[5]);
109
110    /* defaults: */
111    use_vbr = 0;
112    bandwidth=-1;
113    internal_sampling_rate_Hz = sampling_rate;
114    max_payload_bytes = MAX_PACKET;
115    complexity = 10;
116    use_inbandfec = 0;
117    use_dtx = 0;
118    packet_loss_perc = 0;
119
120    args = 6;
121    while( args < argc - 2 ) {
122        /* process command line options */
123         if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-vbr" ) == 0 ) {
124             use_vbr = 1;
125             args++;
126         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-bandwidth" ) == 0 ) {
127             if (strcmp(argv[ args + 1 ], "NB")==0)
128                 bandwidth = BANDWIDTH_NARROWBAND;
129             else if (strcmp(argv[ args + 1 ], "MB")==0)
130                 bandwidth = BANDWIDTH_MEDIUMBAND;
131             else if (strcmp(argv[ args + 1 ], "WB")==0)
132                 bandwidth = BANDWIDTH_WIDEBAND;
133             else if (strcmp(argv[ args + 1 ], "SWB")==0)
134                 bandwidth = BANDWIDTH_SUPERWIDEBAND;
135             else if (strcmp(argv[ args + 1 ], "FB")==0)
136                 bandwidth = BANDWIDTH_FULLBAND;
137             else {
138                 fprintf(stderr, "Unknown bandwidth %s. Supported are NB, MB, WB, SWB, FB.\n", argv[ args + 1 ]);
139                 return 1;
140             }
141             args += 2;
142         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-max_payload" ) == 0 ) {
143             max_payload_bytes = atoi( argv[ args + 1 ] );
144             args += 2;
145         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-complexity" ) == 0 ) {
146             complexity = atoi( argv[ args + 1 ] );
147             args += 2;
148         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-inbandfec" ) == 0 ) {
149             use_inbandfec = 1;
150             args++;
151         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-dtx") == 0 ) {
152             use_dtx = 1;
153             args++;
154         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-loss" ) == 0 ) {
155             packet_loss_perc = atoi( argv[ args + 1 ] );
156             args += 2;
157         } else {
158             printf( "Error: unrecognized setting: %s\n\n", argv[ args ] );
159             print_usage( argv );
160             return 1;
161         }
162    }
163
164    if( mode < MODE_SILK_ONLY || mode > MODE_CELT_ONLY ) {
165       fprintf (stderr, "mode must be: 0, 1 or 2\n");
166       return 1;
167    }
168
169    if (max_payload_bytes < 0 || max_payload_bytes > MAX_PACKET)
170    {
171       fprintf (stderr, "max_payload_bytes must be between 0 and %d\n",
172                         MAX_PACKET);
173       return 1;
174    }
175    if (bitrate_bps < 0 || bitrate_bps*frame_size/sampling_rate > max_payload_bytes*8)
176    {
177       fprintf (stderr, "bytes per packet must be between 0 and %d\n",
178                         max_payload_bytes);
179       return 1;
180    }
181
182    inFile = argv[argc-2];
183    fin = fopen(inFile, "rb");
184    if (!fin)
185    {
186       fprintf (stderr, "Could not open input file %s\n", argv[argc-2]);
187       return 1;
188    }
189    outFile = argv[argc-1];
190    fout = fopen(outFile, "wb+");
191    if (!fout)
192    {
193       fprintf (stderr, "Could not open output file %s\n", argv[argc-1]);
194       return 1;
195    }
196
197    if (mode==MODE_SILK_ONLY)
198    {
199        if (bandwidth == BANDWIDTH_SUPERWIDEBAND || bandwidth == BANDWIDTH_FULLBAND)
200        {
201            fprintf (stderr, "Predictive mode only supports up to wideband\n");
202            return 1;
203        }
204    }
205    if (mode==MODE_HYBRID)
206    {
207        if (bandwidth != BANDWIDTH_SUPERWIDEBAND && bandwidth != BANDWIDTH_FULLBAND)
208        {
209            fprintf (stderr, "Hybrid mode only supports superwideband and fullband\n");
210            return 1;
211        }
212    }
213    if (mode==MODE_CELT_ONLY)
214    {
215        if (bandwidth == BANDWIDTH_MEDIUMBAND)
216        {
217            fprintf (stderr, "Transform mode does not support mediumband\n");
218            return 1;
219        }
220    }
221
222    enc = opus_encoder_create(sampling_rate, channels);
223    dec = opus_decoder_create(sampling_rate, channels);
224
225    opus_encoder_ctl(enc, OPUS_SET_MODE(mode));
226    opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
227
228    if (bandwidth != -1)
229        opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth));
230
231    opus_encoder_ctl(enc, OPUS_SET_VBR_FLAG(use_vbr));
232    opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
233    opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC_FLAG(use_inbandfec));
234    opus_encoder_ctl(enc, OPUS_SET_DTX_FLAG(use_dtx));
235
236    //skip = 5*sampling_rate/1000 + 18;      // 18 is when SILK resamples
237    skip = 5*sampling_rate/1000;
238
239    in = (short*)malloc(frame_size*channels*sizeof(short));
240    out = (short*)malloc(frame_size*channels*sizeof(short));
241    data = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
242    while (!stop)
243    {
244       int write_samples;
245       err = fread(in, sizeof(short), frame_size*channels, fin);
246       tot_read += err;
247       if (err < frame_size*channels)
248       {
249           int i;
250           for (i=err;i<frame_size*channels;i++)
251               in[i] = 0;
252       }
253       len = opus_encode(enc, in, frame_size, data, max_payload_bytes);
254       if (len <= 0)
255       {
256          fprintf (stderr, "opus_encode() returned %d\n", len);
257          return 1;
258       }
259
260       opus_decode(dec, rand()%100<packet_loss_perc ? NULL : data, len, out, frame_size);
261       count++;
262       tot_written += (frame_size-skip)*channels;
263       write_samples = frame_size;
264       if (tot_written > tot_read && skip==0)
265       {
266           write_samples -= (tot_written-tot_read)/channels;
267           stop = 1;
268       }
269       fwrite(out+skip, sizeof(short), (write_samples-skip)*channels, fout);
270       skip = 0;
271
272 #if OPUS_TEST_RANGE_CODER_STATE
273       /* compare final range encoder rng values of encoder and decoder */
274       if( opus_decoder_get_final_range( dec ) != opus_encoder_get_final_range( enc ) ) {
275           fprintf (stderr, "Error: Range coder state mismatch between encoder and decoder.\n");
276           return 0;
277       }
278 #endif
279
280       /* count bits */
281       bits += len*8;
282       nrg = 0.0;
283       for ( k = 0; k < frame_size * channels; k++ ) {
284           nrg += out[ k ] * (double)out[ k ];
285       }
286       if ( ( nrg / ( frame_size * channels ) ) > 1e5 ) {
287           bits_act += len*8;
288           count_act++;
289       }
290           /* Variance */
291           bits2 += len*len*64;
292    }
293    fprintf (stderr, "average bitrate:             %7.3f kb/s\n", 1e-3*bits*sampling_rate/(frame_size*(double)count));
294    fprintf (stderr, "active bitrate:              %7.3f kb/s\n", 1e-3*bits_act*sampling_rate/(frame_size*(double)count_act));
295    fprintf (stderr, "bitrate standard deviation:  %7.3f kb/s\n", 1e-3*sqrt(bits2/count - bits*bits/(count*(double)count))*sampling_rate/frame_size);
296    DEBUG_STORE_CLOSE_FILES              /* Close any files to which intermediate results were stored */
297    opus_encoder_destroy(enc);
298    opus_decoder_destroy(dec);
299    fclose(fin);
300    fclose(fout);
301    free(in);
302    free(out);
303    return 0;
304 }