d383c8164e97e25d314d9a6072b1ed6f8e452590
[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     opus_uint32 enc_final_range[2];
115     opus_uint32 dec_final_range;
116     int encode_only=0, decode_only=0;
117
118     if (argc < 7 )
119     {
120        print_usage( argv );
121        return 1;
122     }
123
124     fprintf(stderr, "%s\n", opus_get_version_string());
125
126     if (strcmp(argv[1], "-e")==0)
127     {
128         encode_only = 1;
129         argv++;
130         argc--;
131     } else if (strcmp(argv[1], "-d")==0)
132     {
133         decode_only = 1;
134         argv++;
135         argc--;
136     }
137     application = atoi(argv[1]) + OPUS_APPLICATION_VOIP;
138     sampling_rate = atoi(argv[2]);
139     channels = atoi(argv[3]);
140     bitrate_bps = atoi(argv[4]);
141
142     if (sampling_rate != 8000 && sampling_rate != 12000 && sampling_rate != 16000
143      && sampling_rate != 24000 && sampling_rate != 48000)
144     {
145         fprintf(stderr, "Supported sampling rates are 8000, 12000, 16000, "
146                 "24000 and 48000.\n");
147         return 1;
148     }
149     frame_size = sampling_rate/50;
150
151     /* defaults: */
152     use_vbr = 1;
153     bandwidth = OPUS_BANDWIDTH_AUTO;
154     max_payload_bytes = MAX_PACKET;
155     complexity = 10;
156     use_inbandfec = 0;
157     forcemono = 0;
158     use_dtx = 0;
159     packet_loss_perc = 0;
160     int max_frame_size = 960*6;
161     int curr_read=0;
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
243     inFile = argv[argc-2];
244     fin = fopen(inFile, "rb");
245     if (!fin)
246     {
247         fprintf (stderr, "Could not open input file %s\n", argv[argc-2]);
248         return 1;
249     }
250     outFile = argv[argc-1];
251     fout = fopen(outFile, "wb+");
252     if (!fout)
253     {
254         fprintf (stderr, "Could not open output file %s\n", argv[argc-1]);
255         return 1;
256     }
257
258     enc = opus_encoder_create(sampling_rate, channels, application);
259     dec = opus_decoder_create(sampling_rate, channels);
260
261     if (enc==NULL)
262     {
263         fprintf(stderr, "Failed to create an encoder\n");
264         exit(1);
265     }
266     if (dec==NULL)
267     {
268         fprintf(stderr, "Failed to create a decoder\n");
269         exit(1);
270     }
271
272     opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
273     opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth));
274     opus_encoder_ctl(enc, OPUS_SET_VBR(use_vbr));
275     opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(cvbr));
276     opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
277     opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC_FLAG(use_inbandfec));
278     opus_encoder_ctl(enc, OPUS_SET_FORCE_MONO(forcemono));
279     opus_encoder_ctl(enc, OPUS_SET_DTX(use_dtx));
280     opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc));
281
282     skip = 5*sampling_rate/1000;
283     /* When SILK resamples, add 18 samples delay */
284     /*if (mode != MODE_SILK_ONLY || sampling_rate > 16000)
285         skip += 18;*/
286
287     switch(bandwidth)
288     {
289     case OPUS_BANDWIDTH_NARROWBAND:
290          bandwidth_string = "narrowband";
291          break;
292     case OPUS_BANDWIDTH_MEDIUMBAND:
293          bandwidth_string = "mediumband";
294          break;
295     case OPUS_BANDWIDTH_WIDEBAND:
296          bandwidth_string = "wideband";
297          break;
298     case OPUS_BANDWIDTH_SUPERWIDEBAND:
299          bandwidth_string = "superwideband";
300          break;
301     case OPUS_BANDWIDTH_FULLBAND:
302          bandwidth_string = "fullband";
303          break;
304     case OPUS_BANDWIDTH_AUTO:
305          bandwidth_string = "auto";
306          break;
307     default:
308          bandwidth_string = "unknown";
309     }
310
311     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);
312
313     in = (short*)malloc(frame_size*channels*sizeof(short));
314     out = (short*)malloc(max_frame_size*channels*sizeof(short));
315     data[0] = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
316     if ( use_inbandfec ) {
317         data[1] = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
318     }
319     while (!stop)
320     {
321         if (decode_only)
322         {
323             unsigned char ch[4];
324             err = fread(ch, 1, 4, fin);
325             if (feof(fin))
326                 break;
327             len[toggle] = char_to_int(ch);
328             if (len[toggle]>max_payload_bytes || len[toggle]<0)
329             {
330                 fprintf(stderr, "Invalid payload length: %d\n",len[toggle]);
331                 break;
332             }
333             err = fread(ch, 1, 4, fin);
334             enc_final_range[toggle] = char_to_int(ch);
335             err = fread(data[toggle], 1, len[toggle], fin);
336             if (err<len[toggle])
337             {
338                 fprintf(stderr, "Ran out of input, expecting %d bytes got %d\n",len[toggle],err);
339                 break;
340             }
341         } else {
342             err = fread(in, sizeof(short)*channels, frame_size, fin);
343             curr_read = err;
344             if (curr_read < frame_size)
345             {
346                 int i;
347                 for (i=curr_read*channels;i<frame_size*channels;i++)
348                    in[i] = 0;
349                 stop = 1;
350             }
351
352             len[toggle] = opus_encode(enc, in, frame_size, data[toggle], max_payload_bytes);
353             opus_encoder_ctl(enc, OPUS_GET_FINAL_RANGE(&enc_final_range[toggle]));
354             if (len[toggle] < 0)
355             {
356                 fprintf (stderr, "opus_encode() returned %d\n", len[toggle]);
357                 return 1;
358             }
359         }
360
361         if (encode_only)
362         {
363             unsigned char int_field[4];
364             int_to_char(len[toggle], int_field);
365             fwrite(int_field, 1, 4, fout);
366             int_to_char(enc_final_range[toggle], int_field);
367             fwrite(int_field, 1, 4, fout);
368             fwrite(data[toggle], 1, len[toggle], fout);
369         } else {
370             int output_samples;
371             lost = len[toggle]==0 || (packet_loss_perc>0 && rand()%100 < packet_loss_perc);
372             if( count >= use_inbandfec ) {
373                 /* delay by one packet when using in-band FEC */
374                 if( use_inbandfec  ) {
375                     if( lost_prev ) {
376                         /* attempt to decode with in-band FEC from next packet */
377                         output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, max_frame_size, 1);
378                     } else {
379                         /* regular decode */
380                         output_samples = opus_decode(dec, data[1-toggle], len[1-toggle], out, max_frame_size, 0);
381                     }
382                 } else {
383                     output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, max_frame_size, 0);
384                 }
385                 if (output_samples>0)
386                 {
387                     fwrite(out+skip, sizeof(short)*channels, output_samples-skip, fout);
388                     skip = 0;
389                 } else {
390                    fprintf(stderr, "error decoding frame: %s\n", opus_strerror(output_samples));
391                 }
392             }
393         }
394
395         opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range));
396         /* compare final range encoder rng values of encoder and decoder */
397         if( enc_final_range[toggle^use_inbandfec]!=0  && !encode_only && !lost && !lost_prev &&
398                         dec_final_range != enc_final_range[toggle^use_inbandfec] ) {
399             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], dec_final_range);
400             return 0;
401         }
402
403         lost_prev = lost;
404
405         /* count bits */
406         bits += len[toggle]*8;
407         if( count >= use_inbandfec ) {
408             nrg = 0.0;
409             if (!decode_only)
410             {
411                 for ( k = 0; k < frame_size * channels; k++ ) {
412                     nrg += in[ k ] * (double)in[ k ];
413                 }
414             }
415             if ( ( nrg / ( frame_size * channels ) ) > 1e5 ) {
416                 bits_act += len[toggle]*8;
417                 count_act++;
418             }
419             /* Variance */
420             bits2 += len[toggle]*len[toggle]*64;
421         }
422         count++;
423         toggle = (toggle + use_inbandfec) & 1;
424     }
425     fprintf (stderr, "average bitrate:             %7.3f kb/s\n", 1e-3*bits*sampling_rate/(frame_size*(double)count));
426     fprintf (stderr, "active bitrate:              %7.3f kb/s\n", 1e-3*bits_act*sampling_rate/(frame_size*(double)count_act));
427     fprintf (stderr, "bitrate standard deviation:  %7.3f kb/s\n", 1e-3*sqrt(bits2/count - bits*bits/(count*(double)count))*sampling_rate/frame_size);
428     /* Close any files to which intermediate results were stored */
429     SILK_DEBUG_STORE_CLOSE_FILES
430     silk_TimerSave("opus_timing.txt");
431     opus_encoder_destroy(enc);
432     opus_decoder_destroy(dec);
433     free(data[0]);
434     if (use_inbandfec)
435         free(data[1]);
436     fclose(fin);
437     fclose(fout);
438     free(in);
439     free(out);
440     return 0;
441 }