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