274fbcb74067bf9b5c010e2eb6f6fc9d23349f7f
[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 "silk_debug.h"
39 #include "opus_types.h"
40
41 #define MAX_PACKET 1500
42
43 void print_usage( char* argv[] )
44 {
45     fprintf(stderr, "Usage: %s [-e | -d] <application (0/1)> <sampling rate (Hz)> <channels (1/2)> "
46         "<bits per second>  [options] <input> <output>\n\n", argv[0]);
47     fprintf(stderr, "mode: 0 for VoIP, 1 for audio:\n" );
48     fprintf(stderr, "options:\n" );
49     fprintf(stderr, "-e                   : only runs the encoder (output the bit-stream)\n" );
50     fprintf(stderr, "-d                   : only runs the decoder (reads the bit-stream as input)\n" );
51     fprintf(stderr, "-cbr                 : enable constant bitrate; default: variable bitrate\n" );
52     fprintf(stderr, "-cvbr                : enable constrained variable bitrate; default: unconstrained\n" );
53     fprintf(stderr, "-bandwidth <NB|MB|WB|SWB|FB> : audio bandwidth (from narrowband to fullband); default: sampling rate\n" );
54     fprintf(stderr, "-framesize <2.5|5|10|20|40|60> : frame size in ms; default: 20 \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, "-forcemono           : force mono encoding, even for stereo input\n" );
59     fprintf(stderr, "-dtx                 : enable SILK DTX\n" );
60     fprintf(stderr, "-loss <perc>         : simulate packet loss, in percent (0-100); default: 0\n" );
61 }
62
63 #ifdef _WIN32
64 #   define STR_CASEINSENSITIVE_COMPARE(x, y) _stricmp(x, y)
65 #else
66 #   define STR_CASEINSENSITIVE_COMPARE(x, y) strcasecmp(x, y)
67 #endif
68
69 static void int_to_char(opus_uint32 i, unsigned char ch[4])
70 {
71     ch[0] = i>>24;
72     ch[1] = (i>>16)&0xFF;
73     ch[2] = (i>>8)&0xFF;
74     ch[3] = i&0xFF;
75 }
76
77 static opus_uint32 char_to_int(unsigned char ch[4])
78 {
79     return ((opus_uint32)ch[0]<<24) | ((opus_uint32)ch[1]<<16)
80          | ((opus_uint32)ch[2]<< 8) |  (opus_uint32)ch[3];
81 }
82
83 int main(int argc, char *argv[])
84 {
85     int err;
86     char *inFile, *outFile;
87     FILE *fin, *fout;
88     OpusEncoder *enc;
89     OpusDecoder *dec;
90     int args;
91     int len[2];
92     int frame_size, channels;
93     int bitrate_bps;
94     unsigned char *data[2];
95     int sampling_rate;
96     int use_vbr;
97     int max_payload_bytes;
98     int complexity;
99     int use_inbandfec;
100     int use_dtx;
101     int forcemono;
102     int cvbr = 0;
103     int packet_loss_perc;
104     int count=0, count_act=0, k;
105     int skip;
106     int stop=0;
107     short *in, *out;
108     int application;
109     double bits=0.0, bits_act=0.0, bits2=0.0, nrg;
110     int bandwidth=-1;
111     const char *bandwidth_string;
112     int lost = 0, lost_prev = 1;
113     int toggle = 0;
114     int enc_final_range[2];
115     int encode_only=0, decode_only=0;
116
117     if (argc < 7 )
118     {
119        print_usage( argv );
120        return 1;
121     }
122
123     fprintf(stderr, "%s\n", opus_get_version_string());
124
125     if (strcmp(argv[1], "-e")==0)
126     {
127         encode_only = 1;
128         argv++;
129         argc--;
130     } else if (strcmp(argv[1], "-d")==0)
131     {
132         decode_only = 1;
133         argv++;
134         argc--;
135     }
136     application = atoi(argv[1]) + OPUS_APPLICATION_VOIP;
137     sampling_rate = atoi(argv[2]);
138     channels = atoi(argv[3]);
139     bitrate_bps = atoi(argv[4]);
140
141     if (sampling_rate != 8000 && sampling_rate != 12000 && sampling_rate != 16000
142      && sampling_rate != 24000 && sampling_rate != 48000)
143     {
144         fprintf(stderr, "Supported sampling rates are 8000, 12000, 16000, "
145                 "24000 and 48000.\n");
146         return 1;
147     }
148     frame_size = sampling_rate/50;
149
150     /* defaults: */
151     use_vbr = 1;
152     bandwidth = OPUS_BANDWIDTH_AUTO;
153     max_payload_bytes = MAX_PACKET;
154     complexity = 10;
155     use_inbandfec = 0;
156     forcemono = 0;
157     use_dtx = 0;
158     packet_loss_perc = 0;
159     int max_frame_size = 960*6;
160     int curr_read=0;
161
162     args = 5;
163     while( args < argc - 2 ) {
164         /* process command line options */
165         if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-cbr" ) == 0 ) {
166             use_vbr = 0;
167             args++;
168         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-bandwidth" ) == 0 ) {
169             if (strcmp(argv[ args + 1 ], "NB")==0)
170                 bandwidth = OPUS_BANDWIDTH_NARROWBAND;
171             else if (strcmp(argv[ args + 1 ], "MB")==0)
172                 bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
173             else if (strcmp(argv[ args + 1 ], "WB")==0)
174                 bandwidth = OPUS_BANDWIDTH_WIDEBAND;
175             else if (strcmp(argv[ args + 1 ], "SWB")==0)
176                 bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND;
177             else if (strcmp(argv[ args + 1 ], "FB")==0)
178                 bandwidth = OPUS_BANDWIDTH_FULLBAND;
179             else {
180                 fprintf(stderr, "Unknown bandwidth %s. Supported are NB, MB, WB, SWB, FB.\n", argv[ args + 1 ]);
181                 return 1;
182             }
183             args += 2;
184         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-framesize" ) == 0 ) {
185             if (strcmp(argv[ args + 1 ], "2.5")==0)
186                 frame_size = sampling_rate/400;
187             else if (strcmp(argv[ args + 1 ], "5")==0)
188                 frame_size = sampling_rate/200;
189             else if (strcmp(argv[ args + 1 ], "10")==0)
190                 frame_size = sampling_rate/100;
191             else if (strcmp(argv[ args + 1 ], "20")==0)
192                 frame_size = sampling_rate/50;
193             else if (strcmp(argv[ args + 1 ], "40")==0)
194                 frame_size = sampling_rate/25;
195             else if (strcmp(argv[ args + 1 ], "60")==0)
196                 frame_size = 3*sampling_rate/50;
197             else {
198                 fprintf(stderr, "Unsupported frame size: %s ms. Supported are 2.5, 5, 10, 20, 40, 60.\n", argv[ args + 1 ]);
199                 return 1;
200             }
201             args += 2;
202         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-max_payload" ) == 0 ) {
203             max_payload_bytes = atoi( argv[ args + 1 ] );
204             args += 2;
205         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-complexity" ) == 0 ) {
206             complexity = atoi( argv[ args + 1 ] );
207             args += 2;
208         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-inbandfec" ) == 0 ) {
209             use_inbandfec = 1;
210             args++;
211         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-forcemono" ) == 0 ) {
212             forcemono = 1;
213             args++;
214         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-cvbr" ) == 0 ) {
215             cvbr = 1;
216             args++;
217         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-dtx") == 0 ) {
218             use_dtx = 1;
219             args++;
220         } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-loss" ) == 0 ) {
221             packet_loss_perc = atoi( argv[ args + 1 ] );
222             args += 2;
223         } else {
224             printf( "Error: unrecognized setting: %s\n\n", argv[ args ] );
225             print_usage( argv );
226             return 1;
227         }
228     }
229
230     if( application < OPUS_APPLICATION_VOIP || application > OPUS_APPLICATION_AUDIO) {
231         fprintf (stderr, "mode must be: 0 or 1\n");
232         return 1;
233     }
234
235     if (max_payload_bytes < 0 || max_payload_bytes > MAX_PACKET)
236     {
237         fprintf (stderr, "max_payload_bytes must be between 0 and %d\n",
238                           MAX_PACKET);
239         return 1;
240     }
241
242     inFile = argv[argc-2];
243     fin = fopen(inFile, "rb");
244     if (!fin)
245     {
246         fprintf (stderr, "Could not open input file %s\n", argv[argc-2]);
247         return 1;
248     }
249     outFile = argv[argc-1];
250     fout = fopen(outFile, "wb+");
251     if (!fout)
252     {
253         fprintf (stderr, "Could not open output file %s\n", argv[argc-1]);
254         return 1;
255     }
256
257     enc = opus_encoder_create(sampling_rate, channels, application);
258     dec = opus_decoder_create(sampling_rate, channels);
259
260     if (enc==NULL)
261     {
262         fprintf(stderr, "Failed to create an encoder\n");
263         exit(1);
264     }
265     if (dec==NULL)
266     {
267         fprintf(stderr, "Failed to create a decoder\n");
268         exit(1);
269     }
270
271     opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
272     opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth));
273     opus_encoder_ctl(enc, OPUS_SET_VBR_FLAG(use_vbr));
274     opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(cvbr));
275     opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
276     opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC_FLAG(use_inbandfec));
277     opus_encoder_ctl(enc, OPUS_SET_FORCE_MONO(forcemono));
278     opus_encoder_ctl(enc, OPUS_SET_DTX_FLAG(use_dtx));
279     opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc));
280
281     skip = 5*sampling_rate/1000;
282     /* When SILK resamples, add 18 samples delay */
283     /*if (mode != MODE_SILK_ONLY || sampling_rate > 16000)
284         skip += 18;*/
285
286     switch(bandwidth)
287     {
288     case OPUS_BANDWIDTH_NARROWBAND:
289          bandwidth_string = "narrowband";
290          break;
291     case OPUS_BANDWIDTH_MEDIUMBAND:
292          bandwidth_string = "mediumband";
293          break;
294     case OPUS_BANDWIDTH_WIDEBAND:
295          bandwidth_string = "wideband";
296          break;
297     case OPUS_BANDWIDTH_SUPERWIDEBAND:
298          bandwidth_string = "superwideband";
299          break;
300     case OPUS_BANDWIDTH_FULLBAND:
301          bandwidth_string = "fullband";
302          break;
303     case OPUS_BANDWIDTH_AUTO:
304          bandwidth_string = "auto";
305          break;
306     default:
307          bandwidth_string = "unknown";
308     }
309
310     fprintf(stderr, "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);
311
312     in = (short*)malloc(frame_size*channels*sizeof(short));
313     out = (short*)malloc(max_frame_size*channels*sizeof(short));
314     data[0] = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
315     if ( use_inbandfec ) {
316         data[1] = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
317     }
318     while (!stop)
319     {
320         if (decode_only)
321         {
322             unsigned char ch[4];
323             err = fread(ch, 1, 4, fin);
324             len[toggle] = char_to_int(ch);
325             if (len[toggle]>max_payload_bytes || len[toggle]<0)
326             {
327                 fprintf(stderr, "Invalid payload length\n");
328                 break;
329             }
330             err = fread(ch, 1, 4, fin);
331             enc_final_range[toggle] = char_to_int(ch);
332             err = fread(data[toggle], 1, len[toggle], fin);
333             if (feof(fin))
334                 break;
335         } else {
336             err = fread(in, sizeof(short)*channels, frame_size, fin);
337             curr_read = err;
338             if (curr_read < frame_size)
339             {
340                 int i;
341                 for (i=curr_read*channels;i<frame_size*channels;i++)
342                    in[i] = 0;
343                 stop = 1;
344             }
345
346             len[toggle] = opus_encode(enc, in, frame_size, data[toggle], max_payload_bytes);
347             enc_final_range[toggle] = opus_encoder_get_final_range( enc );
348             if (len[toggle] < 0)
349             {
350                 fprintf (stderr, "opus_encode() returned %d\n", len[toggle]);
351                 return 1;
352             }
353         }
354
355         if (encode_only)
356         {
357             unsigned char int_field[4];
358             int_to_char(len[toggle], int_field);
359             fwrite(int_field, 1, 4, fout);
360             int_to_char(enc_final_range[toggle], int_field);
361             fwrite(int_field, 1, 4, fout);
362             fwrite(data[toggle], 1, len[toggle], fout);
363         } else {
364             int output_samples;
365             lost = rand()%100 < packet_loss_perc || len[toggle]==0;
366             if( count >= use_inbandfec ) {
367                 /* delay by one packet when using in-band FEC */
368                 if( use_inbandfec  ) {
369                     if( lost_prev ) {
370                         /* attempt to decode with in-band FEC from next packet */
371                         output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, max_frame_size, 1);
372                     } else {
373                         /* regular decode */
374                         output_samples = opus_decode(dec, data[1-toggle], len[1-toggle], out, max_frame_size, 0);
375                     }
376                 } else {
377                     output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, max_frame_size, 0);
378                 }
379                 if (output_samples>0)
380                 {
381                     fwrite(out+skip, sizeof(short)*channels, output_samples-skip, fout);
382                     skip = 0;
383                 }
384             }
385         }
386
387         /* compare final range encoder rng values of encoder and decoder */
388         if( enc_final_range[toggle^use_inbandfec]!=0  && !encode_only && !lost && !lost_prev &&
389              opus_decoder_get_final_range( dec ) != enc_final_range[toggle^use_inbandfec] ) {
390             fprintf (stderr, "Error: Range coder state mismatch between encoder and decoder in frame %d: 0x%8x vs 0x%8x\n", count,  enc_final_range[toggle^use_inbandfec], opus_decoder_get_final_range( dec ));
391             return 0;
392         }
393
394         lost_prev = lost;
395
396         /* count bits */
397         bits += len[toggle]*8;
398         if( count >= use_inbandfec ) {
399             nrg = 0.0;
400             if (!decode_only)
401             {
402                 for ( k = 0; k < frame_size * channels; k++ ) {
403                     nrg += in[ k ] * (double)in[ k ];
404                 }
405             }
406             if ( ( nrg / ( frame_size * channels ) ) > 1e5 ) {
407                 bits_act += len[toggle]*8;
408                 count_act++;
409             }
410             /* Variance */
411             bits2 += len[toggle]*len[toggle]*64;
412         }
413         count++;
414         toggle = (toggle + use_inbandfec) & 1;
415     }
416     fprintf (stderr, "average bitrate:             %7.3f kb/s\n", 1e-3*bits*sampling_rate/(frame_size*(double)count));
417     fprintf (stderr, "active bitrate:              %7.3f kb/s\n", 1e-3*bits_act*sampling_rate/(frame_size*(double)count_act));
418     fprintf (stderr, "bitrate standard deviation:  %7.3f kb/s\n", 1e-3*sqrt(bits2/count - bits*bits/(count*(double)count))*sampling_rate/frame_size);
419     /* Close any files to which intermediate results were stored */
420     SILK_DEBUG_STORE_CLOSE_FILES
421     silk_TimerSave("opus_timing.txt");
422     opus_encoder_destroy(enc);
423     opus_decoder_destroy(dec);
424     free(data[0]);
425     if (use_inbandfec)
426         free(data[1]);
427     fclose(fin);
428     fclose(fout);
429     free(in);
430     free(out);
431     return 0;
432 }