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