Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.xiph.org/xiph/opus.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Maxwell <greg@xiph.org>2011-10-27 03:56:00 +0400
committerGregory Maxwell <greg@xiph.org>2011-10-27 03:59:49 +0400
commita5ff49ecdcf8db706b9d163e64b65c5eae1020de (patch)
treed79f106aa4945057817fe25a26370df8ba8eb9f7 /src/opus_demo.c
parentd481798ad1f3fc6a51630acae10eff032b681142 (diff)
Renames test_opus to opus_demo and adds the test_opus_api, test_opus_encode, test_opus_decode test programs.
Diffstat (limited to 'src/opus_demo.c')
-rw-r--r--src/opus_demo.c486
1 files changed, 486 insertions, 0 deletions
diff --git a/src/opus_demo.c b/src/opus_demo.c
new file mode 100644
index 00000000..c1ef4f92
--- /dev/null
+++ b/src/opus_demo.c
@@ -0,0 +1,486 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include "opus.h"
+#include "debug.h"
+#include "opus_types.h"
+
+#define MAX_PACKET 1500
+
+void print_usage( char* argv[] )
+{
+ fprintf(stderr, "Usage: %s [-e] <application> <sampling rate (Hz)> <channels (1/2)> "
+ "<bits per second> [options] <input> <output>\n", argv[0]);
+ fprintf(stderr, " %s -d <sampling rate (Hz)> <channels (1/2)> "
+ "[options] <input> <output>\n\n", argv[0]);
+ fprintf(stderr, "mode: voip | audio | restricted-lowdelay\n" );
+ fprintf(stderr, "options:\n" );
+ fprintf(stderr, "-e : only runs the encoder (output the bit-stream)\n" );
+ fprintf(stderr, "-d : only runs the decoder (reads the bit-stream as input)\n" );
+ fprintf(stderr, "-cbr : enable constant bitrate; default: variable bitrate\n" );
+ fprintf(stderr, "-cvbr : enable constrained variable bitrate; default: unconstrained\n" );
+ fprintf(stderr, "-bandwidth <NB|MB|WB|SWB|FB> : audio bandwidth (from narrowband to fullband); default: sampling rate\n" );
+ fprintf(stderr, "-framesize <2.5|5|10|20|40|60> : frame size in ms; default: 20 \n" );
+ fprintf(stderr, "-max_payload <bytes> : maximum payload size in bytes, default: 1024\n" );
+ fprintf(stderr, "-complexity <comp> : complexity, 0 (lowest) ... 10 (highest); default: 10\n" );
+ fprintf(stderr, "-inbandfec : enable SILK inband FEC\n" );
+ fprintf(stderr, "-forcemono : force mono encoding, even for stereo input\n" );
+ fprintf(stderr, "-dtx : enable SILK DTX\n" );
+ fprintf(stderr, "-loss <perc> : simulate packet loss, in percent (0-100); default: 0\n" );
+}
+
+#ifdef _WIN32
+# define STR_CASEINSENSITIVE_COMPARE(x, y) _stricmp(x, y)
+#else
+# include <strings.h>
+# define STR_CASEINSENSITIVE_COMPARE(x, y) strcasecmp(x, y)
+#endif
+
+static void int_to_char(opus_uint32 i, unsigned char ch[4])
+{
+ ch[0] = i>>24;
+ ch[1] = (i>>16)&0xFF;
+ ch[2] = (i>>8)&0xFF;
+ ch[3] = i&0xFF;
+}
+
+static opus_uint32 char_to_int(unsigned char ch[4])
+{
+ return ((opus_uint32)ch[0]<<24) | ((opus_uint32)ch[1]<<16)
+ | ((opus_uint32)ch[2]<< 8) | (opus_uint32)ch[3];
+}
+
+int main(int argc, char *argv[])
+{
+ int err;
+ char *inFile, *outFile;
+ FILE *fin, *fout;
+ OpusEncoder *enc=NULL;
+ OpusDecoder *dec=NULL;
+ int args;
+ int len[2];
+ int frame_size, channels;
+ opus_int32 bitrate_bps=0;
+ unsigned char *data[2];
+ opus_int32 sampling_rate;
+ int use_vbr;
+ int max_payload_bytes;
+ int complexity;
+ int use_inbandfec;
+ int use_dtx;
+ int forcechannels;
+ int cvbr = 0;
+ int packet_loss_perc;
+ opus_int32 count=0, count_act=0;
+ int k;
+ int skip=0;
+ int stop=0;
+ short *in, *out;
+ int application=OPUS_APPLICATION_AUDIO;
+ double bits=0.0, bits_max=0.0, bits_act=0.0, bits2=0.0, nrg;
+ int bandwidth=-1;
+ const char *bandwidth_string;
+ int lost = 0, lost_prev = 1;
+ int toggle = 0;
+ opus_uint32 enc_final_range[2];
+ opus_uint32 dec_final_range;
+ int encode_only=0, decode_only=0;
+ int max_frame_size = 960*6;
+ int curr_read=0;
+ int sweep_bps = 0;
+
+ if (argc < 5 )
+ {
+ print_usage( argv );
+ return 1;
+ }
+
+ fprintf(stderr, "%s\n", opus_get_version_string());
+
+ args = 1;
+ if (strcmp(argv[args], "-e")==0)
+ {
+ encode_only = 1;
+ args++;
+ } else if (strcmp(argv[args], "-d")==0)
+ {
+ decode_only = 1;
+ args++;
+ }
+ if (!decode_only && argc < 7 )
+ {
+ print_usage( argv );
+ return 1;
+ }
+
+ if (!decode_only)
+ {
+ if (strcmp(argv[args], "voip")==0)
+ application = OPUS_APPLICATION_VOIP;
+ else if (strcmp(argv[args], "restricted-lowdelay")==0)
+ application = OPUS_APPLICATION_RESTRICTED_LOWDELAY;
+ else if (strcmp(argv[args], "audio")!=0) {
+ fprintf(stderr, "unknown application: %s\n", argv[args]);
+ print_usage(argv);
+ return 1;
+ }
+ args++;
+ }
+ sampling_rate = (opus_int32)atol(argv[args]);
+ args++;
+ channels = atoi(argv[args]);
+ args++;
+ if (!decode_only)
+ {
+ bitrate_bps = (opus_int32)atol(argv[args]);
+ args++;
+ }
+
+ if (sampling_rate != 8000 && sampling_rate != 12000 && sampling_rate != 16000
+ && sampling_rate != 24000 && sampling_rate != 48000)
+ {
+ fprintf(stderr, "Supported sampling rates are 8000, 12000, 16000, "
+ "24000 and 48000.\n");
+ return 1;
+ }
+ frame_size = sampling_rate/50;
+
+ /* defaults: */
+ use_vbr = 1;
+ bandwidth = OPUS_AUTO;
+ max_payload_bytes = MAX_PACKET;
+ complexity = 10;
+ use_inbandfec = 0;
+ forcechannels = OPUS_AUTO;
+ use_dtx = 0;
+ packet_loss_perc = 0;
+ max_frame_size = 960*6;
+ curr_read=0;
+
+ while( args < argc - 2 ) {
+ /* process command line options */
+ if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-cbr" ) == 0 ) {
+ use_vbr = 0;
+ args++;
+ } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-bandwidth" ) == 0 ) {
+ if (strcmp(argv[ args + 1 ], "NB")==0)
+ bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+ else if (strcmp(argv[ args + 1 ], "MB")==0)
+ bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
+ else if (strcmp(argv[ args + 1 ], "WB")==0)
+ bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ else if (strcmp(argv[ args + 1 ], "SWB")==0)
+ bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND;
+ else if (strcmp(argv[ args + 1 ], "FB")==0)
+ bandwidth = OPUS_BANDWIDTH_FULLBAND;
+ else {
+ fprintf(stderr, "Unknown bandwidth %s. Supported are NB, MB, WB, SWB, FB.\n", argv[ args + 1 ]);
+ return 1;
+ }
+ args += 2;
+ } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-framesize" ) == 0 ) {
+ if (strcmp(argv[ args + 1 ], "2.5")==0)
+ frame_size = sampling_rate/400;
+ else if (strcmp(argv[ args + 1 ], "5")==0)
+ frame_size = sampling_rate/200;
+ else if (strcmp(argv[ args + 1 ], "10")==0)
+ frame_size = sampling_rate/100;
+ else if (strcmp(argv[ args + 1 ], "20")==0)
+ frame_size = sampling_rate/50;
+ else if (strcmp(argv[ args + 1 ], "40")==0)
+ frame_size = sampling_rate/25;
+ else if (strcmp(argv[ args + 1 ], "60")==0)
+ frame_size = 3*sampling_rate/50;
+ else {
+ fprintf(stderr, "Unsupported frame size: %s ms. Supported are 2.5, 5, 10, 20, 40, 60.\n", argv[ args + 1 ]);
+ return 1;
+ }
+ args += 2;
+ } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-max_payload" ) == 0 ) {
+ max_payload_bytes = atoi( argv[ args + 1 ] );
+ args += 2;
+ } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-complexity" ) == 0 ) {
+ complexity = atoi( argv[ args + 1 ] );
+ args += 2;
+ } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-inbandfec" ) == 0 ) {
+ use_inbandfec = 1;
+ args++;
+ } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-forcemono" ) == 0 ) {
+ forcechannels = 1;
+ args++;
+ } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-cvbr" ) == 0 ) {
+ cvbr = 1;
+ args++;
+ } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-dtx") == 0 ) {
+ use_dtx = 1;
+ args++;
+ } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-loss" ) == 0 ) {
+ packet_loss_perc = atoi( argv[ args + 1 ] );
+ args += 2;
+ } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-sweep" ) == 0 ) {
+ sweep_bps = atoi( argv[ args + 1 ] );
+ args += 2;
+ } else {
+ printf( "Error: unrecognized setting: %s\n\n", argv[ args ] );
+ print_usage( argv );
+ return 1;
+ }
+ }
+
+ if (max_payload_bytes < 0 || max_payload_bytes > MAX_PACKET)
+ {
+ fprintf (stderr, "max_payload_bytes must be between 0 and %d\n",
+ MAX_PACKET);
+ return 1;
+ }
+
+ inFile = argv[argc-2];
+ fin = fopen(inFile, "rb");
+ if (!fin)
+ {
+ fprintf (stderr, "Could not open input file %s\n", argv[argc-2]);
+ return 1;
+ }
+ outFile = argv[argc-1];
+ fout = fopen(outFile, "wb+");
+ if (!fout)
+ {
+ fprintf (stderr, "Could not open output file %s\n", argv[argc-1]);
+ return 1;
+ }
+
+ if (!decode_only)
+ {
+ enc = opus_encoder_create(sampling_rate, channels, application, &err);
+ if (err != OPUS_OK)
+ {
+ fprintf(stderr, "Cannot create encoder: %s\n", opus_strerror(err));
+ return 1;
+ }
+ opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
+ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth));
+ opus_encoder_ctl(enc, OPUS_SET_VBR(use_vbr));
+ opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(cvbr));
+ opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
+ opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(use_inbandfec));
+ opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(forcechannels));
+ opus_encoder_ctl(enc, OPUS_SET_DTX(use_dtx));
+ opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc));
+
+ opus_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&skip));
+ }
+ if (!encode_only)
+ {
+ dec = opus_decoder_create(sampling_rate, channels, &err);
+ if (err != OPUS_OK)
+ {
+ fprintf(stderr, "Cannot create decoder: %s\n", opus_strerror(err));
+ return 1;
+ }
+ }
+
+
+ switch(bandwidth)
+ {
+ case OPUS_BANDWIDTH_NARROWBAND:
+ bandwidth_string = "narrowband";
+ break;
+ case OPUS_BANDWIDTH_MEDIUMBAND:
+ bandwidth_string = "mediumband";
+ break;
+ case OPUS_BANDWIDTH_WIDEBAND:
+ bandwidth_string = "wideband";
+ break;
+ case OPUS_BANDWIDTH_SUPERWIDEBAND:
+ bandwidth_string = "superwideband";
+ break;
+ case OPUS_BANDWIDTH_FULLBAND:
+ bandwidth_string = "fullband";
+ break;
+ case OPUS_AUTO:
+ bandwidth_string = "auto";
+ break;
+ default:
+ bandwidth_string = "unknown";
+ break;
+ }
+
+ if (decode_only)
+ fprintf(stderr, "Decoding with %ld Hz output (%d channels)\n", (long)sampling_rate, channels);
+ else
+ fprintf(stderr, "Encoding %ld Hz input at %.3f kb/s in %s mode with %d-sample frames.\n", (long)sampling_rate, bitrate_bps*0.001, bandwidth_string, frame_size);
+
+ in = (short*)malloc(frame_size*channels*sizeof(short));
+ out = (short*)malloc(max_frame_size*channels*sizeof(short));
+ data[0] = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
+ if ( use_inbandfec ) {
+ data[1] = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
+ }
+ while (!stop)
+ {
+ if (decode_only)
+ {
+ unsigned char ch[4];
+ err = fread(ch, 1, 4, fin);
+ if (feof(fin))
+ break;
+ len[toggle] = char_to_int(ch);
+ if (len[toggle]>max_payload_bytes || len[toggle]<0)
+ {
+ fprintf(stderr, "Invalid payload length: %d\n",len[toggle]);
+ break;
+ }
+ err = fread(ch, 1, 4, fin);
+ enc_final_range[toggle] = char_to_int(ch);
+ err = fread(data[toggle], 1, len[toggle], fin);
+ if (err<len[toggle])
+ {
+ fprintf(stderr, "Ran out of input, expecting %d bytes got %d\n",len[toggle],err);
+ break;
+ }
+ } else {
+ err = fread(in, sizeof(short)*channels, frame_size, fin);
+ curr_read = err;
+ if (curr_read < frame_size)
+ {
+ int i;
+ for (i=curr_read*channels;i<frame_size*channels;i++)
+ in[i] = 0;
+ stop = 1;
+ }
+
+ len[toggle] = opus_encode(enc, in, frame_size, data[toggle], max_payload_bytes);
+ if (sweep_bps!=0)
+ {
+ bitrate_bps += sweep_bps;
+ /* safety */
+ if (bitrate_bps<1000)
+ bitrate_bps = 1000;
+ opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
+ }
+ opus_encoder_ctl(enc, OPUS_GET_FINAL_RANGE(&enc_final_range[toggle]));
+ if (len[toggle] < 0)
+ {
+ fprintf (stderr, "opus_encode() returned %d\n", len[toggle]);
+ return 1;
+ }
+ }
+
+ if (encode_only)
+ {
+ unsigned char int_field[4];
+ int_to_char(len[toggle], int_field);
+ fwrite(int_field, 1, 4, fout);
+ int_to_char(enc_final_range[toggle], int_field);
+ fwrite(int_field, 1, 4, fout);
+ fwrite(data[toggle], 1, len[toggle], fout);
+ } else {
+ int output_samples;
+ lost = len[toggle]==0 || (packet_loss_perc>0 && rand()%100 < packet_loss_perc);
+ if( count >= use_inbandfec ) {
+ /* delay by one packet when using in-band FEC */
+ if( use_inbandfec ) {
+ if( lost_prev ) {
+ /* attempt to decode with in-band FEC from next packet */
+ output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, max_frame_size, 1);
+ } else {
+ /* regular decode */
+ output_samples = opus_decode(dec, data[1-toggle], len[1-toggle], out, max_frame_size, 0);
+ }
+ } else {
+ output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, max_frame_size, 0);
+ }
+ if (output_samples>0)
+ {
+ fwrite(out+skip*channels, sizeof(short)*channels, output_samples-skip, fout);
+ skip = 0;
+ } else {
+ fprintf(stderr, "error decoding frame: %s\n", opus_strerror(output_samples));
+ }
+ }
+ }
+
+ if (!encode_only)
+ opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range));
+ /* compare final range encoder rng values of encoder and decoder */
+ if( enc_final_range[toggle^use_inbandfec]!=0 && !encode_only && !lost && !lost_prev &&
+ dec_final_range != enc_final_range[toggle^use_inbandfec] ) {
+ fprintf (stderr, "Error: Range coder state mismatch between encoder and decoder in frame %ld: 0x%8lx vs 0x%8lx\n", (long)count, (unsigned long)enc_final_range[toggle^use_inbandfec], (unsigned long)dec_final_range);
+ return 0;
+ }
+
+ lost_prev = lost;
+
+ /* count bits */
+ bits += len[toggle]*8;
+ bits_max = ( len[toggle]*8 > bits_max ) ? len[toggle]*8 : bits_max;
+ if( count >= use_inbandfec ) {
+ nrg = 0.0;
+ if (!decode_only)
+ {
+ for ( k = 0; k < frame_size * channels; k++ ) {
+ nrg += in[ k ] * (double)in[ k ];
+ }
+ }
+ if ( ( nrg / ( frame_size * channels ) ) > 1e5 ) {
+ bits_act += len[toggle]*8;
+ count_act++;
+ }
+ /* Variance */
+ bits2 += len[toggle]*len[toggle]*64;
+ }
+ count++;
+ toggle = (toggle + use_inbandfec) & 1;
+ }
+ fprintf (stderr, "average bitrate: %7.3f kb/s\n", 1e-3*bits*sampling_rate/(frame_size*(double)count));
+ fprintf (stderr, "maximum bitrate: %7.3f bkp/s\n", 1e-3*bits_max*sampling_rate/frame_size);
+ if (!decode_only)
+ fprintf (stderr, "active bitrate: %7.3f kb/s\n", 1e-3*bits_act*sampling_rate/(frame_size*(double)count_act));
+ fprintf (stderr, "bitrate standard deviation: %7.3f kb/s\n", 1e-3*sqrt(bits2/count - bits*bits/(count*(double)count))*sampling_rate/frame_size);
+ /* Close any files to which intermediate results were stored */
+ SILK_DEBUG_STORE_CLOSE_FILES
+ silk_TimerSave("opus_timing.txt");
+ opus_encoder_destroy(enc);
+ opus_decoder_destroy(dec);
+ free(data[0]);
+ if (use_inbandfec)
+ free(data[1]);
+ fclose(fin);
+ fclose(fout);
+ free(in);
+ free(out);
+ return 0;
+}