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