fa52d899932cfc768dc8d0fa150552896aa38537
[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 "celt_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(celt_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 celt_uint32 char_to_int(unsigned char ch[4])
78 {
79     return ((celt_uint32)ch[0]<<24) | ((celt_uint32)ch[1]<<16)
80          | ((celt_uint32)ch[2]<< 8) |  (celt_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 internal_sampling_rate_Hz;
98    int max_payload_bytes;
99    int complexity;
100    int use_inbandfec;
101    int use_dtx;
102    int forcemono;
103    int cvbr = 0;
104    int packet_loss_perc;
105    int count=0, count_act=0, k;
106    int skip;
107    int stop=0;
108    int tot_read=0, tot_written=0;
109    short *in, *out;
110    int application;
111    double bits=0.0, bits_act=0.0, bits2=0.0, nrg;
112    int bandwidth=-1;
113    const char *bandwidth_string;
114    int write_samples;
115    int lost, lost_prev = 1;
116    int toggle = 0;
117    int enc_final_range[2];
118    int encode_only=0, decode_only=0;
119
120    if (argc < 7 )
121    {
122       print_usage( argv );
123       return 1;
124    }
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    internal_sampling_rate_Hz = sampling_rate;
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
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    if (bitrate_bps < 0 || bitrate_bps*frame_size/sampling_rate > max_payload_bytes*8)
242    {
243       fprintf (stderr, "bytes per packet must be between 0 and %d\n",
244                         max_payload_bytes);
245       return 1;
246    }
247
248    inFile = argv[argc-2];
249    fin = fopen(inFile, "rb");
250    if (!fin)
251    {
252       fprintf (stderr, "Could not open input file %s\n", argv[argc-2]);
253       return 1;
254    }
255    outFile = argv[argc-1];
256    fout = fopen(outFile, "wb+");
257    if (!fout)
258    {
259       fprintf (stderr, "Could not open output file %s\n", argv[argc-1]);
260       return 1;
261    }
262
263    enc = opus_encoder_create(sampling_rate, channels, application);
264    dec = opus_decoder_create(sampling_rate, channels);
265
266    if (enc==NULL)
267    {
268       fprintf(stderr, "Failed to create an encoder\n");
269       exit(1);
270    }
271    if (dec==NULL)
272    {
273       fprintf(stderr, "Failed to create a decoder\n");
274       exit(1);
275    }
276
277    opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
278    opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth));
279    opus_encoder_ctl(enc, OPUS_SET_VBR_FLAG(use_vbr));
280    opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(cvbr));
281    opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
282    opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC_FLAG(use_inbandfec));
283    opus_encoder_ctl(enc, OPUS_SET_FORCE_MONO(forcemono));
284    opus_encoder_ctl(enc, OPUS_SET_DTX_FLAG(use_dtx));
285    opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc));
286
287    skip = 5*sampling_rate/1000;
288    /* When SILK resamples, add 18 samples delay */
289    /*if (mode != MODE_SILK_ONLY || sampling_rate > 16000)
290            skip += 18;*/
291
292    switch(bandwidth)
293    {
294    case OPUS_BANDWIDTH_NARROWBAND:
295            bandwidth_string = "narrowband";
296            break;
297    case OPUS_BANDWIDTH_MEDIUMBAND:
298            bandwidth_string = "mediumband";
299            break;
300    case OPUS_BANDWIDTH_WIDEBAND:
301            bandwidth_string = "wideband";
302            break;
303    case OPUS_BANDWIDTH_SUPERWIDEBAND:
304            bandwidth_string = "superwideband";
305            break;
306    case OPUS_BANDWIDTH_FULLBAND:
307            bandwidth_string = "fullband";
308            break;
309    case OPUS_BANDWIDTH_AUTO:
310            bandwidth_string = "auto";
311            break;
312    default:
313            bandwidth_string = "unknown";
314    }
315
316    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);
317
318    in = (short*)malloc(frame_size*channels*sizeof(short));
319    out = (short*)malloc(frame_size*channels*sizeof(short));
320    data[0] = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
321    if( use_inbandfec ) {
322        data[1] = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
323    }
324    while (!stop)
325    {
326       if (decode_only)
327       {
328           unsigned char ch[4];
329           err = fread(ch, 1, 4, fin);
330           len[toggle] = char_to_int(ch);
331           err = fread(ch, 1, 4, fin);
332           enc_final_range[toggle] = char_to_int(ch);
333           err = fread(data[toggle], 1, len[toggle], fin);
334           if (feof(fin))
335               break;
336           tot_read += frame_size*channels;
337       } else {
338           err = fread(in, sizeof(short), frame_size*channels, fin);
339           tot_read += err;
340           if (err < frame_size*channels)
341           {
342               int i;
343               for (i=err;i<frame_size*channels;i++)
344                   in[i] = 0;
345               stop = 1;
346           }
347
348           len[toggle] = opus_encode(enc, in, frame_size, data[toggle], max_payload_bytes);
349 #if OPUS_TEST_RANGE_CODER_STATE
350           enc_final_range[toggle] = opus_encoder_get_final_range( enc );
351 #endif
352           if (len[toggle] < 0)
353           {
354               fprintf (stderr, "opus_encode() returned %d\n", len[toggle]);
355               return 1;
356           }
357       }
358
359       if (encode_only)
360       {
361           unsigned char int_field[4];
362           int_to_char(len[toggle], int_field);
363           fwrite(int_field, 1, 4, fout);
364           int_to_char(enc_final_range[toggle], int_field);
365           fwrite(int_field, 1, 4, fout);
366           fwrite(data[toggle], 1, len[toggle], fout);
367       } else {
368           lost = rand()%100 < packet_loss_perc || len[toggle]==0;
369           if( count >= use_inbandfec ) {
370               /* delay by one packet when using in-band FEC */
371               if( use_inbandfec  ) {
372                   if( lost_prev ) {
373                       /* attempt to decode with in-band FEC from next packet */
374                       opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, frame_size, 1);
375                   } else {
376                       /* regular decode */
377                       opus_decode(dec, data[1-toggle], len[1-toggle], out, frame_size, 0);
378                   }
379               } else {
380                   opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, frame_size, 0);
381               }
382               write_samples = frame_size-skip;
383               tot_written += write_samples*channels;
384               if (tot_written > tot_read)
385               {
386                   write_samples -= (tot_written-tot_read)/channels;
387               }
388               fwrite(out+skip, sizeof(short), write_samples*channels, fout);
389               skip = 0;
390           }
391       }
392
393 #if OPUS_TEST_RANGE_CODER_STATE
394       /* compare final range encoder rng values of encoder and decoder */
395       if( !encode_only && !lost && !lost_prev
396          && opus_decoder_get_final_range( dec ) != enc_final_range[toggle^use_inbandfec] ) {
397           fprintf (stderr, "Error: Range coder state mismatch between encoder and decoder in frame %d.\n", count);
398           return 0;
399       }
400 #endif
401
402       lost_prev = lost;
403
404       /* count bits */
405       bits += len[toggle]*8;
406       if( count >= use_inbandfec ) {
407           nrg = 0.0;
408           for ( k = 0; k < frame_size * channels; k++ ) {
409               nrg += in[ k ] * (double)in[ k ];
410           }
411           if ( ( nrg / ( frame_size * channels ) ) > 1e5 ) {
412               bits_act += len[toggle]*8;
413               count_act++;
414           }
415               /* Variance */
416               bits2 += len[toggle]*len[toggle]*64;
417       }
418       count++;
419       toggle = (toggle + use_inbandfec) & 1;
420    }
421    fprintf (stderr, "average bitrate:             %7.3f kb/s\n", 1e-3*bits*sampling_rate/(frame_size*(double)count));
422    fprintf (stderr, "active bitrate:              %7.3f kb/s\n", 1e-3*bits_act*sampling_rate/(frame_size*(double)count_act));
423    fprintf (stderr, "bitrate standard deviation:  %7.3f kb/s\n", 1e-3*sqrt(bits2/count - bits*bits/(count*(double)count))*sampling_rate/frame_size);
424    /* Close any files to which intermediate results were stored */
425    SILK_DEBUG_STORE_CLOSE_FILES
426    silk_TimerSave("opus_timing.txt");
427    opus_encoder_destroy(enc);
428    opus_decoder_destroy(dec);
429    free(data[0]);
430    if (use_inbandfec)
431            free(data[1]);
432    fclose(fin);
433    fclose(fout);
434    free(in);
435    free(out);
436    return 0;
437 }