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