ref: 5be25490b689959d4c9fc62074e8be2f8eb666ab
parent: 9cdde2e9f347629ab8c90ec38311d9318217ada6
author: Gregory Maxwell <greg@xiph.org>
date: Sat Nov 19 23:33:28 EST 2011
Incremental work rewriting opusenc.
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,5 +1,5 @@
CC=gcc
-CFLAGS=-DHAVE_SYS_SOUNDCARD_H -O2 -g -fstack-protector-all -c -Wall -DHAVE_GETOPT_H -DEXPORT= -DRANDOM_PREFIX=opustools -DOUTSIDE_SPEEX -DFLOATING_POINT
+CFLAGS=-DHAVE_SYS_SOUNDCARD_H -O2 -g -fstack-protector-all -c -Wall -Wextra -DHAVE_GETOPT_H -DEXPORT= -DRANDOM_PREFIX=opustools -DOUTSIDE_SPEEX -DFLOATING_POINT
INCLUDES=-I../../opus/include
all: opusenc opusdec
--- a/src/opusdec.c
+++ b/src/opusdec.c
@@ -410,12 +410,17 @@
*channels = header.channels;
- if (!*rate)
- *rate = header.input_sample_rate;
+ if(!*rate)*rate=header.input_sample_rate;
+ /*If the rate is unspecified we decode to 48000*/
+ if(*rate==0)*rate=48000;
+ if(*rate<8000||*rate>192000){
+ fprintf(stderr,"Warning: Crazy input_rate %d, decoding to 48000 instead.\n",*rate);
+ *rate=48000;
+ }
+
*preskip = header.preskip;
st = opus_multistream_decoder_create(48000, header.channels, 1, header.channels==2 ? 1 : 0, mapping, &err);
- if (err != OPUS_OK)
- {
+ if(err != OPUS_OK){
fprintf(stderr, "Cannot create encoder: %s\n", opus_strerror(err));
return NULL;
}
@@ -814,6 +819,9 @@
if (strlen(outFile)==0)
WIN_Audio_close ();
#endif
+
+ if(shapemem.a_buf)free(shapemem.a_buf);
+ if(shapemem.b_buf)free(shapemem.b_buf);
if (close_in)
fclose(fin);
--- a/src/opusenc.c
+++ b/src/opusenc.c
@@ -1,19 +1,19 @@
-/* Copyright (c) 2002-2011 Jean-Marc Valin
- Copyright (c) 2007-2011 Xiph.Org Foundation
- Copyright (c) 2008-2010 Gregory Maxwell
+/* Copyright (C)2002-2011 Jean-Marc Valin
+ Copyright (C)2007-2012 Xiph.Org Foundation
+ Copyright (C)2008-2012 Gregory Maxwell
File: opusenc.c
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
@@ -36,7 +36,8 @@
#include <stdlib.h>
#include <string.h>
-#include <time.h>
+#include <sys/time.h>
+#include <math.h>
#include "opus_header.h"
#include "speex_resampler.h"
@@ -60,14 +61,12 @@
void comment_init(char **comments, int* length, char *vendor_string);
void comment_add(char **comments, int* length, char *tag, char *val);
-
/*Write an Ogg page to a file pointer*/
int oe_write_page(ogg_page *page, FILE *fp)
{
int written;
- written = fwrite(page->header,1,page->header_len, fp);
- written += fwrite(page->body,1,page->body_len, fp);
-
+ written=fwrite(page->header,1,page->header_len, fp);
+ written+=fwrite(page->body,1,page->body_len, fp);
return written;
}
@@ -81,80 +80,58 @@
int lsb, float * input, char *buff, opus_int32 *size,
int *extra_samples)
{
- short s[MAX_FRAME_SIZE*2];
- unsigned char *in = (unsigned char*)s;
- int i;
- int nb_read;
- int extra=0;
+ short s[MAX_FRAME_SIZE*2];
+ unsigned char *in=(unsigned char*)s;
+ int i;
+ int nb_read;
+ int extra=0;
- /*Read input audio*/
- if (buff)
- {
- for (i=0;i<12;i++)
- in[i]=buff[i];
- nb_read = fread(in+12, 1, bits/8*channels*frame_size-12, fin) + 12;
- if (size)
- *size += 12;
- } else {
- int tmp = frame_size;
- if (size && tmp > *size)
- tmp = *size;
- nb_read = fread(in, 1, bits/8*channels* tmp, fin);
- }
- nb_read /= bits/8*channels;
+ /*Read input audio*/
+ if(buff){
+ for(i=0;i<12;i++)in[i]=buff[i];
+ nb_read=fread(in+12, 1, bits/8*channels*frame_size-12, fin) + 12;
+ if(size)*size+=12;
+ }else{
+ int tmp=frame_size;
+ if(size&&tmp>*size)tmp=*size;
+ nb_read=fread(in, 1, bits/8*channels* tmp, fin);
+ }
+ nb_read/=bits/8*channels;
- /* Make sure to return *extra_samples zeros at the end */
- if (nb_read<frame_size)
- {
- extra = frame_size-nb_read;
- if (extra > *extra_samples)
- extra = *extra_samples;
- *extra_samples -= extra;
- }
- /*fprintf (stderr, "%d\n", nb_read);*/
- if (nb_read==0 && extra==0)
- return 0;
+ /* Make sure to return *extra_samples zeros at the end */
+ if(nb_read<frame_size){
+ extra=frame_size-nb_read;
+ if(extra > *extra_samples)
+ extra=*extra_samples;
+ *extra_samples-=extra;
+ }
+ /*fprintf(stderr, "%d\n", nb_read);*/
+ if(nb_read==0 && extra==0)return 0;
- if(bits==8)
- {
- /* Convert 8->16 bits */
- for(i=frame_size*channels-1;i>=0;i--)
- {
- s[i]=(in[i]<<8)^0x8000;
- }
- } else
- {
- /* convert to our endian format */
- for(i=0;i<frame_size*channels;i++)
- {
- if(lsb)
- s[i]=le_short(s[i]);
- else
- s[i]=be_short(s[i]);
- }
- }
+ if(bits==8){
+ /* Convert 8->16 bits */
+ for(i=frame_size*channels-1;i>=0;i--){
+ s[i]=(in[i]<<8)^0x8000;
+ }
+ }else{
+ /* convert to our endian format */
+ for(i=0;i<frame_size*channels;i++){
+ if(lsb)s[i]=le_short(s[i]);
+ else s[i]=be_short(s[i]);
+ }
+ }
- /* copy to float input buffer */
- for (i=0;i<frame_size*channels;i++)
- {
- input[i]=s[i]*(1/32768.f);
- }
+ /* copy to float input buffer */
+ for(i=0;i<frame_size*channels;i++)input[i]=s[i]*(1/32768.f);
+ for(i=nb_read*channels;i<frame_size*channels;i++)input[i]=0;
- for (i=nb_read*channels;i<frame_size*channels;i++)
- {
- input[i]=0;
- }
-
- nb_read += extra;
- if (size)
- {
- int tmp = bits/8*channels*nb_read;
- if (tmp > *size)
- *size = 0;
- else
- *size -= tmp;
- }
- return nb_read;
+ nb_read+=extra;
+ if(size){
+ int tmp=bits/8*channels*nb_read;
+ if(tmp>*size)*size=0;
+ else *size-=tmp;
+ }
+ return nb_read;
}
static int read_samples(FILE *fin,int frame_size, int bits, int channels,
@@ -161,589 +138,738 @@
int lsb, float * input, char *buff, opus_int32 *size,
SpeexResamplerState *resampler, int *extra_samples)
{
- if (resampler)
- {
- /* FIXME: This is a hack, get rid of these static variables */
- static float pcmbuf[2048];
- static int inbuf=0;
- int out_samples=0;
- while (out_samples<frame_size)
- {
- int i;
- int reading, ret;
- unsigned in_len, out_len;
- reading = 1024-inbuf;
- ret = read_samples_pcm(fin, reading, bits, channels, lsb, pcmbuf+inbuf*channels, buff, size, extra_samples);
- inbuf += ret;
- in_len = inbuf;
- out_len = frame_size-out_samples;
- speex_resampler_process_interleaved_float(resampler, pcmbuf, &in_len, input+out_samples*channels, &out_len);
- if (ret==0 && in_len==0)
- {
- for (i=out_samples*channels;i<frame_size*channels;i++)
- input[i] = 0;
- return out_samples;
- }
- out_samples += out_len;
- for (i=0;i<channels*(inbuf-in_len);i++)
- pcmbuf[i] = pcmbuf[i+channels*in_len];
- inbuf -= in_len;
+ if(resampler){
+ /* FIXME: This is a hack, get rid of these static variables */
+ static float pcmbuf[2048];
+ static int inbuf=0;
+ int out_samples=0;
+ while(out_samples<frame_size){
+ int i;
+ int reading, ret;
+ unsigned in_len, out_len;
+ reading=1024-inbuf;
+ ret=read_samples_pcm(fin, reading, bits, channels, lsb, pcmbuf+inbuf*channels, buff, size, extra_samples);
+ inbuf+=ret;
+ in_len=inbuf;
+ out_len=frame_size-out_samples;
+ speex_resampler_process_interleaved_float(resampler, pcmbuf, &in_len, input+out_samples*channels, &out_len);
+ if(ret==0&&in_len==0){
+ for(i=out_samples*channels;i<frame_size*channels;i++)input[i]=0;
+ return out_samples;
}
- return out_samples;
- } else {
- return read_samples_pcm(fin, frame_size, bits, channels, lsb, input, buff, size, extra_samples);
- }
+ out_samples+=out_len;
+ for(i=0;i<channels*(inbuf-in_len);i++)pcmbuf[i]=pcmbuf[i+channels*in_len];
+ inbuf-=in_len;
+ }
+ return out_samples;
+ }else{
+ return read_samples_pcm(fin, frame_size, bits, channels, lsb, input, buff, size, extra_samples);
+ }
}
void version(const char *version)
{
- printf ("opusenc (based on %s)\n",version);
- printf ("Copyright (C) 2008-2011 Xiph.Org Foundation (written by Jean-Marc Valin)\n");
+ printf("opusenc (using %s)\n",version);
+ printf("Copyright (C) 2008-2012 Xiph.Org Foundation\n");
}
void version_short(const char *version)
{
- printf ("opusenc (based on %s)\n",version);
- printf ("Copyright (C) 2008-2011 Xiph.Org Foundation (written by Jean-Marc Valin)\n");
+ printf("opusenc (using %s)\n",version);
+ printf("Copyright (C) 2008-2012 Xiph.Org Foundation\n");
}
void usage(void)
{
- printf ("Usage: opusenc [options] input_file output_file.oga\n");
- printf ("\n");
- printf ("Encodes input_file using Opus. It can read the WAV or raw files.\n");
- printf ("\n");
- printf ("input_file can be:\n");
- printf (" filename.wav wav file\n");
- printf (" filename.* Raw PCM file (any extension other than .wav)\n");
- printf (" - stdin\n");
- printf ("\n");
- printf ("output_file can be:\n");
- printf (" filename.oga compressed file\n");
- printf (" - stdout\n");
- printf ("\n");
- printf ("Options:\n");
- printf (" --speech Optimize for speech\n");
- printf (" --music Optimize for music\n");
- printf (" --bitrate n Encoding bit-rate in kbit/sec\n");
- printf (" --cbr Use constant bitrate encoding\n");
- printf (" --comp n Encoding complexity (0-10)\n");
- printf (" --framesize n Frame size (Default: 960)\n");
- printf (" --nopf Do not use the prefilter/postfilter\n");
- printf (" --independent Encode frames independently (implies nopf)\n");
- printf (" --comment Add the given string as an extra comment. This may be\n");
- printf (" used multiple times\n");
- printf (" --author Author of this track\n");
- printf (" --title Title for this track\n");
- printf (" -h, --help This help\n");
- printf (" -v, --version Version information\n");
- printf (" -V Verbose mode (show bit-rate)\n");
- printf ("Raw input options:\n");
- printf (" --rate n Sampling rate for raw input\n");
- printf (" --mono Consider raw input as mono\n");
- printf (" --stereo Consider raw input as stereo\n");
- printf (" --le Raw input is little-endian\n");
- printf (" --be Raw input is big-endian\n");
- printf (" --8bit Raw input is 8-bit unsigned\n");
- printf (" --16bit Raw input is 16-bit signed\n");
- printf ("Default raw PCM input is 48kHz, 16-bit, little-endian, stereo\n");
+ printf("Usage: opusenc [options] input_file output_file.oga\n");
+ printf("\n");
+ printf("Encodes input_file using Opus. It can read the WAV or raw files.\n");
+ printf("\nGeneral options:\n");
+ printf(" -h, --help This help\n");
+ printf(" -v, --version Version information\n");
+ printf(" --quiet Quiet mode\n");
+ printf("\n");
+ printf("input_file can be:\n");
+ printf(" filename.wav wav file\n");
+ printf(" filename.* Raw PCM file (any extension other than .wav)\n");
+ printf(" - stdin\n");
+ printf("\n");
+ printf("output_file can be:\n");
+ printf(" filename.oga compressed file\n");
+ printf(" - stdout\n");
+ printf("\nEncoding options:\n");
+ printf(" --speech Optimize for speech\n");
+ printf(" --music Optimize for music\n");
+ printf(" --bitrate n.nnn Encoding bit-rate in kbit/sec (6-256 per-channel)\n");
+ printf(" --vbr Use variable bitrate encoding (default)\n");
+ printf(" --cvbr Use constrained variable bitrate encoding\n");
+ printf(" --hard-cbr Use hard constant bitrate encoding\n");
+ printf(" --comp n Encoding complexity (0-10, default: 10)\n");
+ printf(" --framesize n Maximum frame size in milliseconds\n");
+ printf(" (2.5, 5, 10, 20, 40, 60, default: 20)\n");
+ printf(" --expect-loss Percentage packet loss to expect (default: 0)\n");
+ printf(" --force-mono Force mono output\n");
+ printf(" --max-ogg-delay n Maximum container delay in milliseconds\n");
+ printf(" (0-1000, default: 1000)\n");
+ printf("\nDiagnostic options:\n");
+ printf(" --save-range file Saves check values for every frame to a file\n");
+ printf(" --set-ctl-int x=y Pass the encoder control x with value y (advanced)\n");
+ printf(" This may be used multiple times\n");
+ printf("\nMetadata options:\n");
+ printf(" --comment Add the given string as an extra comment\n");
+ printf(" This may be used multiple times\n");
+ printf(" --author Author of this track\n");
+ printf(" --title Title for this track\n");
+ printf("\nRaw input options:\n");
+ printf(" --rate n Sampling rate for raw input\n");
+ printf(" --mono Consider raw input as mono\n");
+ printf(" --stereo Consider raw input as stereo\n");
+ printf(" --le Raw input is little-endian\n");
+ printf(" --be Raw input is big-endian\n");
+ printf(" --8bit Raw input is 8-bit unsigned\n");
+ printf(" --16bit Raw input is 16-bit signed\n");
+ printf("Default raw PCM input is 48kHz, 16-bit, little-endian, stereo\n");
}
+static inline void print_time(double seconds)
+{
+ long long hours, minutes;
+ hours=seconds/3600;
+ seconds-=hours*3600.;
+ minutes=seconds/60;
+ seconds-=minutes*60.;
+ if(hours)fprintf(stderr," %lld hour%s%s",hours,hours>1?"s":"",
+ minutes&&!(seconds>0)?" and":"");
+ if(minutes)fprintf(stderr,"%s%lld minute%s%s",hours?", ":" ",minutes,
+ minutes>1?"s":"",!hours&&seconds>0?" and":seconds>0?", and":"");
+ if(seconds>0)fprintf(stderr," %0.4g second%s",seconds,seconds!=1?"s":"");
+}
int main(int argc, char **argv)
{
- int nb_samples, total_samples=0, nb_encoded;
- int c;
- int option_index = 0;
- char *inFile, *outFile;
- FILE *fin, *fout;
- float input[MAX_FRAME_SIZE*2];
- opus_int32 frame_size = 960;
- int quiet=0;
- int nbBytes;
- OpusMSEncoder *st;
- unsigned char bits[MAX_FRAME_BYTES];
- int with_cbr = 0;
- int with_cvbr = 0;
- int total_bytes = 0;
- int peak_bytes = 0;
- struct option long_options[] =
- {
- {"bitrate", required_argument, NULL, 0},
- {"cbr",no_argument,NULL, 0},
- {"cvbr",no_argument,NULL, 0},
- {"comp", required_argument, NULL, 0},
- {"nopf", no_argument, NULL, 0},
- {"independent", no_argument, NULL, 0},
- {"framesize", required_argument, NULL, 0},
- {"help", no_argument, NULL, 0},
- {"quiet", no_argument, NULL, 0},
- {"le", no_argument, NULL, 0},
- {"be", no_argument, NULL, 0},
- {"8bit", no_argument, NULL, 0},
- {"16bit", no_argument, NULL, 0},
- {"mono", no_argument, NULL, 0},
- {"stereo", no_argument, NULL, 0},
- {"rate", required_argument, NULL, 0},
- {"music", no_argument, NULL, 0},
- {"speech", no_argument, NULL, 0},
- {"version", no_argument, NULL, 0},
- {"version-short", no_argument, NULL, 0},
- {"comment", required_argument, NULL, 0},
- {"author", required_argument, NULL, 0},
- {"title", required_argument, NULL, 0},
- {0, 0, 0, 0}
- };
- int print_bitrate=0;
- opus_int32 rate=48000;
- opus_int32 size;
- int chan=1;
- int fmt=16;
- int lsb=1;
- ogg_stream_state os;
- ogg_page og;
- ogg_packet op;
- ogg_int64_t last_granulepos = 0;
- int bytes_written=0, ret, result;
- int id=-1;
- OpusHeader header;
- char vendor_string[64];
- char *comments;
- int comments_length;
- int close_in=0, close_out=0;
- int eos=0;
- float bitrate=-1;
- char first_bytes[12];
- int wave_input=0;
- opus_int32 lookahead = 0;
- int bytes_per_packet=-1;
- int complexity=-127;
- const char *opus_version;
- SpeexResamplerState *resampler=NULL;
- int extra_samples;
- int signal = OPUS_AUTO;
- unsigned char mapping[256] = {0, 1};
- int err;
+ int i, c, nb_samples;
+ int option_index=0;
+ char *inFile, *outFile;
+ FILE *fin, *fout, *frange;
+ char *range_file;
+ float input[MAX_FRAME_SIZE*2];
+ opus_int32 frame_size=960;
+ opus_int64 nb_encoded, bytes_written=0, pages_out=0, total_bytes=0, total_samples=0;
+ struct timeval start_time, stop_time;
+ int last_spin_len=0;
+ time_t last_spin=0;
+ int quiet=0;
+ int nbBytes;
+ OpusMSEncoder *st;
+ unsigned char *packet;
+ int with_hard_cbr=0;
+ int with_cvbr=0;
+ opus_int32 peak_bytes=0;
+ opus_int32 min_bytes=MAX_FRAME_BYTES;
+ int expect_loss=0;
+ int force_mono=0;
+ int *opt_ctls_ctlval;
+ int opt_ctls=0;
+ int max_ogg_delay=48000;
+ struct option long_options[] =
+ {
+ {"bitrate", required_argument, NULL, 0},
+ {"hard-cbr",no_argument,NULL, 0},
+ {"vbr",no_argument,NULL, 0},
+ {"cvbr",no_argument,NULL, 0},
+ {"comp", required_argument, NULL, 0},
+ {"framesize", required_argument, NULL, 0},
+ {"expect-loss", required_argument, NULL, 0},
+ {"force-mono",no_argument,NULL, 0},
+ {"max-ogg-delay", required_argument, NULL, 0},
+ {"save-range", required_argument, NULL, 0},
+ {"set-ctl-int", required_argument, NULL, 0},
+ {"help", no_argument, NULL, 0},
+ {"quiet", no_argument, NULL, 0},
+ {"le", no_argument, NULL, 0},
+ {"be", no_argument, NULL, 0},
+ {"8bit", no_argument, NULL, 0},
+ {"16bit", no_argument, NULL, 0},
+ {"mono", no_argument, NULL, 0},
+ {"stereo", no_argument, NULL, 0},
+ {"rate", required_argument, NULL, 0},
+ {"music", no_argument, NULL, 0},
+ {"speech", no_argument, NULL, 0},
+ {"version", no_argument, NULL, 0},
+ {"version-short", no_argument, NULL, 0},
+ {"comment", required_argument, NULL, 0},
+ {"author", required_argument, NULL, 0},
+ {"title", required_argument, NULL, 0},
+ {0, 0, 0, 0}
+ };
+ opus_int32 rate=48000;
+ opus_int32 coding_rate=48000;
+ opus_int32 size;
+ int chan=1;
+ int fmt=16;
+ int lsb=1;
+ ogg_stream_state os;
+ ogg_page og;
+ ogg_packet op;
+ ogg_int64_t last_granulepos=0;
+ int ret, result;
+ int id=-1;
+ OpusHeader header;
+ char vendor_string[64];
+ char *comments;
+ int comments_length;
+ int close_in=0, close_out=0;
+ int eos=0;
+ opus_int32 bitrate=-1;
+ char first_bytes[12];
+ int wave_input=0;
+ opus_int32 lookahead=0;
+ int bytes_per_packet=-1;
+ int complexity=10;
+ const char *opus_version;
+ SpeexResamplerState *resampler=NULL;
+ int extra_samples;
+ int signal=OPUS_AUTO;
+ unsigned char mapping[256]={0, 1};
+ int err;
+
+ opt_ctls_ctlval=NULL;
+ frange=NULL;
+ range_file=NULL;
+ opus_version=opus_get_version_string();
+ snprintf(vendor_string, sizeof(vendor_string), "%s\n",opus_version);
+ comment_init(&comments, &comments_length, vendor_string);
- opus_version = opus_get_version_string();
- snprintf(vendor_string, sizeof(vendor_string), "%s\n",opus_version);
- comment_init(&comments, &comments_length, vendor_string);
+ packet=malloc(sizeof(unsigned char)*MAX_FRAME_BYTES);
+ if(packet==NULL){
+ fprintf(stderr,"Error allocating packet buffer.\n");
+ exit(1);
+ }
- /*Process command-line options*/
- while(1)
- {
- c = getopt_long (argc, argv, "hvV",
- long_options, &option_index);
- if (c==-1)
- break;
+ /*Process command-line options*/
+ while(1){
+ c=getopt_long(argc, argv, "hv",
+ long_options, &option_index);
+ if(c==-1)
+ break;
- switch(c)
- {
+ switch(c){
case 0:
- if (strcmp(long_options[option_index].name,"bitrate")==0)
- {
- bitrate = atof (optarg);
- } else if (strcmp(long_options[option_index].name,"cbr")==0)
- {
- with_cbr=1;
- } else if (strcmp(long_options[option_index].name,"cvbr")==0)
- {
- with_cvbr=1;
- } else if (strcmp(long_options[option_index].name,"help")==0)
- {
- usage();
- exit(0);
- } else if (strcmp(long_options[option_index].name,"quiet")==0)
- {
- quiet = 1;
- } else if (strcmp(long_options[option_index].name,"version")==0)
- {
- version(opus_version);
- exit(0);
- } else if (strcmp(long_options[option_index].name,"version-short")==0)
- {
- version_short(opus_version);
- exit(0);
- } else if (strcmp(long_options[option_index].name,"le")==0)
- {
- lsb=1;
- } else if (strcmp(long_options[option_index].name,"be")==0)
- {
- lsb=0;
- } else if (strcmp(long_options[option_index].name,"8bit")==0)
- {
- fmt=8;
- } else if (strcmp(long_options[option_index].name,"16bit")==0)
- {
- fmt=16;
- } else if (strcmp(long_options[option_index].name,"stereo")==0)
- {
- chan=2;
- } else if (strcmp(long_options[option_index].name,"mono")==0)
- {
- chan=1;
- } else if (strcmp(long_options[option_index].name,"rate")==0)
- {
- rate=atoi (optarg);
- } else if (strcmp(long_options[option_index].name,"music")==0)
- {
- signal = OPUS_SIGNAL_MUSIC;
- } else if (strcmp(long_options[option_index].name,"speech")==0)
- {
- signal = OPUS_SIGNAL_VOICE;
- } else if (strcmp(long_options[option_index].name,"comp")==0)
- {
- complexity=atoi (optarg);
- } else if (strcmp(long_options[option_index].name,"framesize")==0)
- {
- frame_size=IMIN(atoi(optarg),MAX_FRAME_SIZE);
- } else if (strcmp(long_options[option_index].name,"comment")==0)
- {
- if (!strchr(optarg, '='))
- {
- fprintf (stderr, "Invalid comment: %s\n", optarg);
- fprintf (stderr, "Comments must be of the form name=value\n");
- exit(1);
- }
- comment_add(&comments, &comments_length, NULL, optarg);
- } else if (strcmp(long_options[option_index].name,"author")==0)
- {
- comment_add(&comments, &comments_length, "author=", optarg);
- } else if (strcmp(long_options[option_index].name,"title")==0)
- {
- comment_add(&comments, &comments_length, "title=", optarg);
- }
-
- break;
+ if(strcmp(long_options[option_index].name,"bitrate")==0){
+ bitrate=atof(optarg)*1000.;
+ }else if(strcmp(long_options[option_index].name,"hard-cbr")==0){
+ with_hard_cbr=1;
+ with_cvbr=0;
+ }else if(strcmp(long_options[option_index].name,"cvbr")==0){
+ with_cvbr=1;
+ with_hard_cbr=0;
+ }else if(strcmp(long_options[option_index].name,"vbr")==0){
+ with_cvbr=0;
+ with_hard_cbr=0;
+ }else if(strcmp(long_options[option_index].name,"help")==0){
+ usage();
+ exit(0);
+ }else if(strcmp(long_options[option_index].name,"quiet")==0){
+ quiet=1;
+ }else if(strcmp(long_options[option_index].name,"version")==0){
+ version(opus_version);
+ exit(0);
+ }else if(strcmp(long_options[option_index].name,"version-short")==0){
+ version_short(opus_version);
+ exit(0);
+ }else if(strcmp(long_options[option_index].name,"le")==0){
+ lsb=1;
+ }else if(strcmp(long_options[option_index].name,"be")==0){
+ lsb=0;
+ }else if(strcmp(long_options[option_index].name,"8bit")==0){
+ fmt=8;
+ }else if(strcmp(long_options[option_index].name,"16bit")==0){
+ fmt=16;
+ }else if(strcmp(long_options[option_index].name,"stereo")==0){
+ chan=2;
+ }else if(strcmp(long_options[option_index].name,"mono")==0){
+ chan=1;
+ } else if(strcmp(long_options[option_index].name,"rate")==0){
+ rate=atoi(optarg);
+ }else if(strcmp(long_options[option_index].name,"music")==0){
+ signal=OPUS_SIGNAL_MUSIC;
+ }else if(strcmp(long_options[option_index].name,"speech")==0){
+ signal=OPUS_SIGNAL_VOICE;
+ }else if(strcmp(long_options[option_index].name,"force-mono")==0){
+ force_mono=1;
+ }else if(strcmp(long_options[option_index].name,"expect-loss")==0){
+ expect_loss=atoi(optarg);
+ if(expect_loss>100||expect_loss<0){
+ fprintf(stderr,"Invalid expect-loss: %s\n",optarg);
+ fprintf(stderr,"Expected loss is a percent and must be 0-100.\n");
+ exit(1);
+ }
+ }else if(strcmp(long_options[option_index].name,"comp")==0){
+ complexity=atoi(optarg);
+ if(complexity>10||complexity<0){
+ fprintf(stderr,"Invalid complexity: %s\n",optarg);
+ fprintf(stderr,"Complexity must be 0-10.\n");
+ exit(1);
+ }
+ }else if(strcmp(long_options[option_index].name,"framesize")==0){
+ if(strcmp(optarg,"2.5")==0)frame_size=120;
+ else if(strcmp(optarg,"5")==0)frame_size=240;
+ else if(strcmp(optarg,"10")==0)frame_size=480;
+ else if(strcmp(optarg,"20")==0)frame_size=960;
+ else if(strcmp(optarg,"40")==0)frame_size=1920;
+ else if(strcmp(optarg,"60")==0)frame_size=2880;
+ else{
+ fprintf(stderr,"Invalid framesize: %s\n",optarg);
+ fprintf(stderr,"Framesize must be 2.5, 5, 10, 20, 40, or 60.\n");
+ exit(1);
+ }
+ }else if(strcmp(long_options[option_index].name,"max-ogg-delay")==0){
+ max_ogg_delay=floor(atof(optarg)*48.);
+ if(max_ogg_delay<0||max_ogg_delay>48000){
+ fprintf(stderr,"Invalid max-ogg-delay: %s\n",optarg);
+ fprintf(stderr,"max-ogg-delay 0-1000 ms.\n");
+ exit(1);
+ }
+ }else if(strcmp(long_options[option_index].name,"set-ctl-int")==0){
+ int len=strlen(optarg);
+ char *spos;
+ spos=strchr(optarg,'=');
+ if(len<3||spos==NULL||(spos-optarg)<1||(spos-optarg)>=len){
+ fprintf(stderr, "Invalid set-ctl-int: %s\n", optarg);
+ fprintf(stderr, "Syntax is --set-ctl-int intX=intY\n");
+ exit(1);
+ }
+ if((atoi(optarg)&1)!=0){
+ fprintf(stderr, "Invalid set-ctl-int: %s\n", optarg);
+ fprintf(stderr, "libopus set CTL values are even.\n");
+ exit(1);
+ }
+ if(opt_ctls==0)opt_ctls_ctlval=malloc(sizeof(int)*2);
+ else opt_ctls_ctlval=realloc(opt_ctls_ctlval,sizeof(int)*(opt_ctls+1)*2);
+ opt_ctls_ctlval[opt_ctls<<1]=atoi(optarg);
+ opt_ctls_ctlval[(opt_ctls<<1)+1]=atoi(spos+1);
+ opt_ctls++;
+ }else if(strcmp(long_options[option_index].name,"save-range")==0){
+ frange=fopen(optarg,"w");
+ if(frange==NULL){
+ perror(optarg);
+ fprintf(stderr,"Could not open save-range file: %s\n",optarg);
+ fprintf(stderr,"Must provide a writable file name.\n");
+ exit(1);
+ }
+ range_file=optarg;
+ }else if(strcmp(long_options[option_index].name,"comment")==0){
+ if(!strchr(optarg,'=')){
+ fprintf(stderr, "Invalid comment: %s\n", optarg);
+ fprintf(stderr, "Comments must be of the form name=value\n");
+ exit(1);
+ }
+ comment_add(&comments, &comments_length, NULL, optarg);
+ }else if(strcmp(long_options[option_index].name,"author")==0){
+ comment_add(&comments, &comments_length, "author=", optarg);
+ } else if(strcmp(long_options[option_index].name,"title")==0){
+ comment_add(&comments, &comments_length, "title=", optarg);
+ }
+ break;
case 'h':
- usage();
- exit(0);
- break;
+ usage();
+ exit(0);
+ break;
case 'v':
- version(opus_version);
- exit(0);
- break;
- case 'V':
- print_bitrate=1;
- break;
+ version(opus_version);
+ exit(0);
+ break;
case '?':
- usage();
- exit(1);
- break;
- }
- }
- if (argc-optind!=2)
- {
- usage();
- exit(1);
- }
- inFile=argv[optind];
- outFile=argv[optind+1];
+ usage();
+ exit(1);
+ break;
+ }
+ }
+ if(argc-optind!=2){
+ usage();
+ exit(1);
+ }
+ inFile=argv[optind];
+ outFile=argv[optind+1];
- /*Initialize Ogg stream struct*/
- srand(time(NULL));
- if (ogg_stream_init(&os, rand())==-1)
- {
- fprintf(stderr,"Error: stream init failed\n");
- exit(1);
- }
+ /*Initialize Ogg stream struct*/
+ gettimeofday(&start_time,NULL);
+ srand(start_time.tv_sec^start_time.tv_usec);
+ if(ogg_stream_init(&os, rand())==-1){
+ fprintf(stderr,"Error: stream init failed\n");
+ exit(1);
+ }
- if (strcmp(inFile, "-")==0)
- {
+ if(strcmp(inFile, "-")==0){
#if defined WIN32 || defined _WIN32
- _setmode(_fileno(stdin), _O_BINARY);
+ _setmode(_fileno(stdin), _O_BINARY);
#elif defined OS2
- _fsetmode(stdin,"b");
+ _fsetmode(stdin,"b");
#endif
- fin=stdin;
- }
- else
- {
- fin = fopen(inFile, "rb");
- if (!fin)
- {
- perror(inFile);
- exit(1);
- }
- close_in=1;
- }
+ fin=stdin;
+ }else{
+ fin=fopen(inFile, "rb");
+ if(!fin){
+ perror(inFile);
+ exit(1);
+ }
+ close_in=1;
+ }
- {
- int ret;
- ret = fread(first_bytes, 1, 12, fin);
- if (strncmp(first_bytes,"RIFF",4)==0 && strncmp(first_bytes,"RIFF",4)==0)
- {
- if (read_wav_header(fin, &rate, &chan, &fmt, &size)==-1)
- exit(1);
- wave_input=1;
- lsb=1; /* CHECK: exists big-endian .wav ?? */
- }
- }
+ err=fread(first_bytes, 1, 12, fin);
+ if(strncmp(first_bytes,"RIFF",4)==0 && strncmp(first_bytes,"RIFF",4)==0){
+ if(read_wav_header(fin, &rate, &chan, &fmt, &size)==-1)exit(1);
+ wave_input=1;
+ lsb=1; /* CHECK: exists big-endian .wav ?? */
+ }
- if (rate != 48000)
- {
- fprintf(stderr, "Resampling from %d Hz to %d Hz before encoding\n", rate, 48000);
- resampler = speex_resampler_init(chan, rate, 48000, 5, &err);
- if (err!=0)
- fprintf(stderr, "resampler error: %s\n", speex_resampler_strerror(err));
- /* Using pre-skip to skip the zeros */
- /*speex_resampler_skip_zeros(resampler);*/
- }
- if (bitrate<=0.005)
- {
- if (chan==1)
- bitrate=64.0;
- else
- bitrate=128.0;
- }
- bytes_per_packet = MAX_FRAME_BYTES;
+ if(rate>24000)coding_rate=48000;
+ else if(rate>16000)coding_rate=24000;
+ else if(rate>12000)coding_rate=12000;
+ else coding_rate=8000;
- /*Initialize OPUS encoder*/
- st = opus_multistream_encoder_create(48000, chan, 1, chan==2, mapping, OPUS_APPLICATION_AUDIO, &err);
- if (err != OPUS_OK)
- {
- fprintf(stderr, "Cannot create encoder: %s\n", opus_strerror(err));
- return 1;
- }
- opus_multistream_encoder_ctl(st, OPUS_SET_SIGNAL(signal));
- header.channels = chan;
- opus_multistream_encoder_ctl(st, OPUS_GET_LOOKAHEAD(&lookahead));
- header.preskip = lookahead;
- if (resampler)
- header.preskip += speex_resampler_get_output_latency(resampler);
- header.channel_mapping = 0;
- header.nb_streams = 1;
- header.nb_coupled = 1;
- /* 0 dB gain is the recommended unless you know what you're doing */
- header.gain = 0;
- header.input_sample_rate = rate;
+ frame_size=frame_size/(48000/coding_rate);
- /* Extra samples that need to be read to compensate for the pre-skip */
- extra_samples = (int)header.preskip * (rate/48000.);
- {
- char *st_string="mono";
- if (chan==2)
- st_string="stereo";
- if (!quiet)
- {
- if (with_cbr)
- fprintf (stderr, "Encoding %.0f kHz %s audio in %.0fms packets at %0.3fkbit/sec (%d bytes per packet, CBR)\n",
- header.input_sample_rate/1000., st_string, frame_size/48., bitrate, bytes_per_packet);
- else
- fprintf (stderr, "Encoding %.0f kHz %s audio in %.0fms packets at %0.3fkbit/sec\n",
- header.input_sample_rate/1000., st_string, frame_size/48., bitrate);
- }
- }
+ bitrate=bitrate>0?bitrate:32000*(force_mono?1:chan)+32000;
+ bytes_per_packet=MAX_FRAME_BYTES;
- {
- int tmp = (bitrate*1000);
- if (opus_multistream_encoder_ctl(st, OPUS_SET_BITRATE(tmp)) != OPUS_OK)
- {
- fprintf (stderr, "bitrate request failed\n");
- return 1;
- }
- }
- if (!with_cbr)
- {
- if (opus_multistream_encoder_ctl(st, OPUS_SET_VBR(1)) != OPUS_OK)
- {
- fprintf (stderr, "VBR request failed\n");
- return 1;
- }
- if (!with_cvbr)
- {
- if (opus_multistream_encoder_ctl(st, OPUS_SET_VBR_CONSTRAINT(0)) != OPUS_OK)
- {
- fprintf (stderr, "VBR constraint failed\n");
- return 1;
- }
- }
- }
+ if(bitrate>2048000||bitrate<500){
+ fprintf(stderr,"Error: Bitrate %d bits/sec is insane.\nDid you mistake bits for kilobits?\n",bitrate);
+ fprintf(stderr,"--bitrate values from 6-256 kbit/sec per channel are meaningful.\n");
+ exit(1);
+ }
+ bitrate=IMIN((force_mono?1:chan)*256000,bitrate);
- if (complexity!=-127) {
- if (opus_multistream_encoder_ctl(st, OPUS_SET_COMPLEXITY(complexity)) != OPUS_OK)
- {
- fprintf (stderr, "Only complexity 0 through 10 is supported\n");
- return 1;
- }
- }
+ if(rate!=coding_rate){
+ /*if(!quiet)fprintf(stderr, "Resampling from %dHz to %dHz before encoding\n", rate, coding_rate);*/
+ resampler=speex_resampler_init(chan, rate, coding_rate, 5, &err);
+ if(err!=0)fprintf(stderr, "resampler error: %s\n", speex_resampler_strerror(err));
+ /* Using pre-skip to skip the zeros */
+ /*speex_resampler_skip_zeros(resampler);*/
+ }
- if (strcmp(outFile,"-")==0)
- {
+
+ /*Initialize OPUS encoder*/
+ st=opus_multistream_encoder_create(coding_rate, chan, 1, chan==2, mapping, OPUS_APPLICATION_AUDIO, &err);
+ if(err!=OPUS_OK){
+ fprintf(stderr, "Cannot create encoder: %s\n", opus_strerror(err));
+ exit(1);
+ }
+
+ err=opus_multistream_encoder_ctl(st, OPUS_SET_SIGNAL(signal));
+ if(err!=OPUS_OK){
+ fprintf(stderr,"OPUS_SET_SIGNAL returned: %s\n",opus_strerror(err));
+ exit(1);
+ }
+ header.channels=force_mono?1:chan;
+ header.channel_mapping=0;
+ header.nb_streams=1;
+ header.nb_coupled=1;
+ /* 0 dB gain is the recommended unless you know what you're doing */
+ header.gain=0;
+ header.input_sample_rate=rate;
+
+ if(force_mono){
+ OpusEncoder *oe;
+ opus_multistream_encoder_ctl(st,OPUS_MULTISTREAM_GET_ENCODER_STATE(0,&oe));
+ err=opus_encoder_ctl(oe, OPUS_SET_FORCE_CHANNELS(1));
+ if(err!=OPUS_OK){
+ fprintf(stderr,"OPUS_SET_FORCE_CHANNELS returned: %s\n",opus_strerror(err));
+ exit(1);
+ }
+ }
+
+ err=opus_multistream_encoder_ctl(st, OPUS_SET_BITRATE(bitrate));
+ if(err!=OPUS_OK){
+ fprintf(stderr,"OPUS_SET_BITRATE returned: %s\n",opus_strerror(err));
+ exit(1);
+ }
+
+ err=opus_multistream_encoder_ctl(st, OPUS_SET_VBR(!with_hard_cbr));
+ if(err!=OPUS_OK){
+ fprintf(stderr,"OPUS_SET_VBR returned: %s\n",opus_strerror(err));
+ exit(1);
+ }
+
+ if(!with_hard_cbr){
+ err=opus_multistream_encoder_ctl(st, OPUS_SET_VBR_CONSTRAINT(with_cvbr));
+ if(err!=OPUS_OK){
+ fprintf(stderr,"OPUS_SET_VBR_CONSTRAINT returned: %s\n",opus_strerror(err));
+ exit(1);
+ }
+ }
+
+ err=opus_multistream_encoder_ctl(st, OPUS_SET_COMPLEXITY(complexity));
+ if(err!=OPUS_OK){
+ fprintf(stderr,"OPUS_SET_COMPLEXITY returned: %s\n",opus_strerror(err));
+ exit(1);
+ }
+
+ err=opus_multistream_encoder_ctl(st, OPUS_SET_PACKET_LOSS_PERC(expect_loss));
+ if(err!=OPUS_OK){
+ fprintf(stderr,"OPUS_SET_PACKET_LOSS_PERC returned: %s\n",opus_strerror(err));
+ exit(1);
+ }
+
+ for(i=0;i<opt_ctls;i++){
+ err=opus_multistream_encoder_ctl(st,opt_ctls_ctlval[i<<1],opt_ctls_ctlval[(i<<1)+1]);
+ if(err!=OPUS_OK){
+ fprintf(stderr,"opus_multistream_encoder_ctl(st,%d,%d) returned: %s\n",opt_ctls_ctlval[i<<1],opt_ctls_ctlval[(i<<1)+1],opus_strerror(err));
+ exit(1);
+ }
+ }
+
+ /*We do the lookahead check late so user CTLs can change it*/
+ err=opus_multistream_encoder_ctl(st, OPUS_GET_LOOKAHEAD(&lookahead));
+ if(err!=OPUS_OK){
+ fprintf(stderr,"OPUS_GET_LOOKAHEAD returned: %s\n",opus_strerror(err));
+ exit(1);
+ }
+ header.preskip=lookahead*(48000/coding_rate);
+ if(resampler)header.preskip+=speex_resampler_get_output_latency(resampler)*(48000/coding_rate);
+ /* Extra samples that need to be read to compensate for the pre-skip */
+ extra_samples=(int)header.preskip*(rate/48000.);
+
+ if(!quiet){
+ int opus_app;
+ fprintf(stderr,"Encoding using %s",opus_version);
+ opus_multistream_encoder_ctl(st,OPUS_GET_APPLICATION(&opus_app));
+ if(opus_app==OPUS_APPLICATION_VOIP)fprintf(stderr," (VoIP)\n");
+ else if(opus_app==OPUS_APPLICATION_AUDIO)fprintf(stderr," (audio)\n");
+ else if(opus_app==OPUS_APPLICATION_RESTRICTED_LOWDELAY)fprintf(stderr," (low-delay)\n");
+ else fprintf(stderr," (unknown)\n");
+ fprintf(stderr,"-----------------------------------------------------\n");
+ fprintf(stderr," Input: %0.6gkHz %d channel%s\n",
+ header.input_sample_rate/1000.,chan,chan<2?"":"s");
+ fprintf(stderr," Output: %d channel%s, %0.2gms packets, %0.6gkbit/sec%s\n",
+ force_mono?1:chan,(force_mono?1:chan)<2?"":"s",
+ frame_size/(coding_rate/1000.), bitrate/1000.,
+ with_hard_cbr?" CBR":with_cvbr?" CVBR":" VBR");
+ fprintf(stderr," Pregap: %d\n",header.preskip);
+
+ if(frange!=NULL)fprintf(stderr," Writing final range file %s\n",range_file);
+ fprintf(stderr,"\n");
+ }
+
+ if(strcmp(outFile,"-")==0){
#if defined WIN32 || defined _WIN32
- _setmode(_fileno(stdout), _O_BINARY);
+ _setmode(_fileno(stdout), _O_BINARY);
#endif
- fout=stdout;
- }
- else
- {
- fout = fopen(outFile, "wb");
- if (!fout)
- {
- perror(outFile);
- exit(1);
- }
- close_out=1;
- }
+ fout=stdout;
+ }else{
+ fout=fopen(outFile, "wb");
+ if(!fout){
+ perror(outFile);
+ exit(1);
+ }
+ close_out=1;
+ }
- /*Write header*/
- {
- unsigned char header_data[100];
- int packet_size = opus_header_to_packet(&header, header_data, 100);
- op.packet = header_data;
- op.bytes = packet_size;
- op.b_o_s = 1;
- op.e_o_s = 0;
- op.granulepos = 0;
- op.packetno = 0;
- ogg_stream_packetin(&os, &op);
+ /*Write header*/
+ {
+ unsigned char header_data[100];
+ int packet_size=opus_header_to_packet(&header, header_data, 100);
+ op.packet=header_data;
+ op.bytes=packet_size;
+ op.b_o_s=1;
+ op.e_o_s=0;
+ op.granulepos=0;
+ op.packetno=0;
+ ogg_stream_packetin(&os, &op);
- while((result = ogg_stream_flush(&os, &og)))
- {
- if(!result) break;
- ret = oe_write_page(&og, fout);
- if(ret != og.header_len + og.body_len)
- {
- fprintf (stderr,"Error: failed writing header to output stream\n");
- exit(1);
- }
- else
- bytes_written += ret;
+ while((result=ogg_stream_flush(&os, &og))){
+ if(!result)break;
+ ret=oe_write_page(&og, fout);
+ if(ret!=og.header_len+og.body_len){
+ fprintf(stderr,"Error: failed writing header to output stream\n");
+ exit(1);
}
+ bytes_written+=ret;
+ pages_out++;
+ }
- op.packet = (unsigned char *)comments;
- op.bytes = comments_length;
- op.b_o_s = 0;
- op.e_o_s = 0;
- op.granulepos = 0;
- op.packetno = 1;
- ogg_stream_packetin(&os, &op);
- }
+ op.packet=(unsigned char *)comments;
+ op.bytes=comments_length;
+ op.b_o_s=0;
+ op.e_o_s=0;
+ op.granulepos=0;
+ op.packetno=1;
+ ogg_stream_packetin(&os, &op);
+ }
- /* writing the rest of the opus header packets */
- while((result = ogg_stream_flush(&os, &og)))
- {
- if(!result) break;
- ret = oe_write_page(&og, fout);
- if(ret != og.header_len + og.body_len)
- {
- fprintf (stderr,"Error: failed writing header to output stream\n");
- exit(1);
- }
- else
- bytes_written += ret;
- }
+ /* writing the rest of the opus header packets */
+ while((result=ogg_stream_flush(&os, &og))){
+ if(!result)break;
+ ret=oe_write_page(&og, fout);
+ if(ret!=og.header_len + og.body_len){
+ fprintf(stderr,"Error: failed writing header to output stream\n");
+ exit(1);
+ }
+ bytes_written+=ret;
+ pages_out++;
+ }
- free(comments);
+ free(comments);
- if (!wave_input)
- {
- nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, first_bytes, NULL, resampler, &extra_samples);
- } else {
- nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size, resampler, &extra_samples);
- }
- if (nb_samples==0)
- eos=1;
- total_samples += nb_samples;
- nb_encoded = -header.preskip;
- /*Main encoding loop (one frame per iteration)*/
- while (!eos)
- {
- id++;
- /*Encode current frame*/
+ if(!wave_input)nb_samples=read_samples(fin,frame_size,fmt,chan,lsb,input, first_bytes, NULL, resampler, &extra_samples);
+ else nb_samples=read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size, resampler, &extra_samples);
- nbBytes = opus_multistream_encode_float(st, input, frame_size, bits, bytes_per_packet);
- if (nbBytes<0)
- {
- fprintf(stderr, "Encoding failed: %s. Aborting.\n", opus_strerror(nbBytes));
- break;
- }
- nb_encoded += frame_size;
- total_bytes += nbBytes;
- peak_bytes=IMAX(nbBytes,peak_bytes);
+ if(nb_samples==0)eos=1;
+ total_samples+=nb_samples;
+ nb_encoded=-header.preskip;
+ /*Main encoding loop (one frame per iteration)*/
+ while(!eos){
+ id++;
+ /*Encode current frame*/
- if (wave_input)
- {
- nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size, resampler, &extra_samples);
- } else {
- nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, NULL, resampler, &extra_samples);
+ nbBytes=opus_multistream_encode_float(st, input, frame_size, packet, bytes_per_packet);
+ if(nbBytes<0){
+ fprintf(stderr, "Encoding failed: %s. Aborting.\n", opus_strerror(nbBytes));
+ break;
+ }
+ nb_encoded+=frame_size;
+ total_bytes+=nbBytes;
+ peak_bytes=IMAX(nbBytes,peak_bytes);
+ min_bytes=IMIN(nbBytes,min_bytes);
+
+ if(frange!=NULL){
+ static const char *bw_strings[5]={"NB","MB","WB","SWB","FB"};
+ static const char *mode_strings[3]={"LP","HYB","MDCT"};
+ int streams=1; /*FIXME, mode data should be per stream too*/
+ OpusEncoder *oe;
+ opus_uint32 rng;
+ fprintf(frange,"%d %d ",frame_size*(48000/coding_rate),nbBytes);
+ fprintf(frange,"%s %s %c %d ",mode_strings[((((packet[0]>>3)+48)&92)+4)>>5],
+ bw_strings[opus_packet_get_bandwidth(packet)-OPUS_BANDWIDTH_NARROWBAND],
+ packet[0]&4?'S':'M',opus_packet_get_samples_per_frame(packet,48000));
+ for(i=0;i<streams;i++){
+ err=opus_multistream_encoder_ctl(st,OPUS_MULTISTREAM_GET_ENCODER_STATE(i,&oe));
+ err=opus_encoder_ctl(oe,OPUS_GET_FINAL_RANGE(&rng));
+ fprintf(frange,"%llu%c",(unsigned long long)rng,i+1==streams?'\n':' ');
}
- if (nb_samples==0)
- {
- eos=1;
- }
- if (eos && total_samples<=nb_encoded)
- op.e_o_s = 1;
- else
- op.e_o_s = 0;
- total_samples += nb_samples;
+ }
- op.packet = (unsigned char *)bits;
- op.bytes = nbBytes;
- op.b_o_s = 0;
- /*Is this redundent?*/
- if (eos && total_samples<=nb_encoded)
- op.e_o_s = 1;
- else
- op.e_o_s = 0;
- op.granulepos = (id+1)*frame_size;
- if (op.granulepos>total_samples)
- op.granulepos = total_samples;
- op.packetno = 2+id;
- /*printf ("granulepos: %d %d %d\n", (int)op.granulepos, op.packetno, op.bytes);*/
- ogg_stream_packetin(&os, &op);
+ if(wave_input)nb_samples=read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size, resampler, &extra_samples);
+ else nb_samples=read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, NULL, resampler, &extra_samples);
+ if(nb_samples==0)eos=1;
+ if(eos && total_samples<=nb_encoded)op.e_o_s=1;
+ else op.e_o_s=0;
- /*Write all new pages (most likely 0 or 1)
- Flush if we've buffered 1 second to avoid excessive framing delay. */
- while (eos||(op.granulepos-last_granulepos+frame_size>48000)?
+ total_samples+=nb_samples;
+
+ op.packet=(unsigned char *)packet;
+ op.bytes=nbBytes;
+ op.b_o_s=0;
+ /*Is this redundent?*/
+ if(eos && total_samples<=nb_encoded)op.e_o_s=1;
+ else op.e_o_s=0;
+ op.granulepos=(id+1)*frame_size*(48000/coding_rate);
+ if(op.granulepos>total_samples)op.granulepos=total_samples*(48000/coding_rate);
+ op.packetno=2+id;
+ /*printf("granulepos: %d %d %d\n", (int)op.granulepos, op.packetno, op.bytes);*/
+ ogg_stream_packetin(&os, &op);
+
+ /*Write all new pages (most likely 0 or 1)
+ Flush if we've buffered >max_ogg_delay second to avoid excessive framing delay. */
+ while(eos||(op.granulepos-last_granulepos+(frame_size*(48000/coding_rate))>max_ogg_delay)?
#if 0
- /*Libogg > 1.2.2 allows us to achieve lower overhead by
- producing larger pages. For 20ms frames this is only relevant
- above ~32kbit/sec. We still target somewhat smaller than the
- maximum size in order to avoid continued pages.*/
- ogg_stream_flush_fill(&os, &og,255*255-7*1276):
- ogg_stream_pageout_fill(&os, &og,255*255-7*1276))
+ /*Libogg > 1.2.2 allows us to achieve lower overhead by
+ producing larger pages. For 20ms frames this is only relevant
+ above ~32kbit/sec. We still target somewhat smaller than the
+ maximum size in order to avoid continued pages.*/
+ ogg_stream_flush_fill(&os, &og,255*255-7*1276):
+ ogg_stream_pageout_fill(&os, &og,255*255-7*1276))
#else
- ogg_stream_flush(&os, &og):
- ogg_stream_pageout(&os, &og))
+#define OLD_LIBOGG
+ ogg_stream_flush(&os, &og):
+ ogg_stream_pageout(&os, &og))
#endif
- {
- if (ogg_page_packets(&og)!=0)
- last_granulepos = ogg_page_granulepos(&og);
- ret = oe_write_page(&og, fout);
- if(ret != og.header_len + og.body_len)
- {
- fprintf (stderr,"Error: failed writing header to output stream\n");
- exit(1);
- }
- else
- bytes_written += ret;
- }
- }
- /*Flush all pages left to be written*/
- while (ogg_stream_flush(&os, &og))
- {
- ret = oe_write_page(&og, fout);
- if(ret != og.header_len + og.body_len)
- {
- fprintf (stderr,"Error: failed writing header to output stream\n");
+ {
+ if(ogg_page_packets(&og)!=0)last_granulepos=ogg_page_granulepos(&og);
+ ret=oe_write_page(&og, fout);
+ if(ret!=og.header_len+og.body_len){
+ fprintf(stderr,"Error: failed writing header to output stream\n");
exit(1);
}
- else
- bytes_written += ret;
- }
+ bytes_written+=ret;
+ pages_out++;
+ }
- if (!with_cbr && !quiet)
- fprintf (stderr, "Average rate %0.3fkbit/sec, %d peak bytes per packet\n", (total_bytes*8.0/((float)nb_encoded/header.input_sample_rate))/1000.0, peak_bytes);
+ if(!quiet){
+ gettimeofday(&stop_time,NULL);
+ if(stop_time.tv_sec>last_spin){
+ double estbitrate;
+ double coded_seconds=nb_encoded/(double)coding_rate;
+ double wall_time=(stop_time.tv_sec-start_time.tv_sec)+
+ (stop_time.tv_usec-start_time.tv_usec)*1e-06;
+ char sbuf[55];
+ static const char spinner[]="|/-\\";
+ if(!with_hard_cbr){
+ double tweight=1./(1+exp(-((coded_seconds/10.)-3.)));
+ estbitrate=(total_bytes*8.0/coded_seconds)*tweight+
+ bitrate*(1.-tweight);
+ }else estbitrate=nbBytes*8*((double)coding_rate/frame_size);
+ for(i=0;i<last_spin_len;i++)fprintf(stderr," ");
+ snprintf(sbuf,54,"\r[%c] %02d:%02d:%02d.%02d %4.3gx realtime, %5.4gkbit/s\r",
+ spinner[last_spin&3],
+ (int)(coded_seconds/3600),(int)(coded_seconds/60)%60,
+ (int)(coded_seconds)%60,(int)(coded_seconds*100)%100,
+ coded_seconds/wall_time,
+ estbitrate/1000.);
+ fprintf(stderr,"%s",sbuf);
+ last_spin_len=strlen(sbuf);
+ last_spin=stop_time.tv_sec;
+ }
+ }
+ }
+ gettimeofday(&stop_time,NULL);
- opus_multistream_encoder_destroy(st);
- ogg_stream_clear(&os);
+ for(i=0;i<last_spin_len;i++)fprintf(stderr," ");
+ if(last_spin_len)fprintf(stderr,"\r");
- if (close_in)
- fclose(fin);
- if (close_out)
- fclose(fout);
- return 0;
+ /*Flush all pages left to be written*/
+ while(ogg_stream_flush(&os, &og)){
+ ret=oe_write_page(&og, fout);
+ if(ret!=og.header_len+og.body_len){
+ fprintf(stderr,"Error: failed writing header to output stream\n");
+ exit(1);
+ }
+ bytes_written+=ret;
+ pages_out++;
+ }
+
+ if(!quiet){
+ double coded_seconds=nb_encoded/(double)coding_rate;
+ double wall_time=(stop_time.tv_sec-start_time.tv_sec)+
+ (stop_time.tv_usec-start_time.tv_usec)*1e-06;
+ fprintf(stderr,"Encoding complete\n");
+ fprintf(stderr,"-----------------------------------------------------\n");
+ fprintf(stderr," Encoded:");
+ print_time(coded_seconds);
+ fprintf(stderr,"\n Runtime:");
+ print_time(wall_time);
+ fprintf(stderr,"\n (%0.4gx realtime)\n",coded_seconds/wall_time);
+ fprintf(stderr," Wrote: %lld bytes, %d packets, %lld pages\n",total_bytes,id,pages_out);
+ fprintf(stderr," Bitrate: %0.6gkbit/s (without overhead)\n",
+ total_bytes*8.0/(coded_seconds)/1000.0);
+ fprintf(stderr," Rate range: %0.6gkbit/s to %0.6gkbit/s\n (%d to %d bytes per packet)\n",
+ min_bytes*8*((double)coding_rate/frame_size/1000.),
+ peak_bytes*8*((double)coding_rate/frame_size/1000.),min_bytes,peak_bytes);
+ fprintf(stderr," Overhead: %0.3g%% (container+metadata)\n",(bytes_written-total_bytes)/(double)total_bytes*100.);
+#ifdef OLD_LIBOGG
+ if(max_ogg_delay>(frame_size*(48000/coding_rate)*4))fprintf(stderr," (use libogg 1.2.2 or later for lower overhead)\n");
+#endif
+ }
+
+ opus_multistream_encoder_destroy(st);
+ ogg_stream_clear(&os);
+ free(packet);
+ if(opt_ctls)free(opt_ctls_ctlval);
+ if(rate!=coding_rate)speex_resampler_destroy(resampler);
+ if(close_in)fclose(fin);
+ if(close_out)fclose(fout);
+ if(frange)fclose(frange);
+ return 0;
}
/*
@@ -751,6 +877,8 @@
It is describled in the "Structure" section of
http://www.xiph.org/ogg/vorbis/doc/v-comment.html
+ However, Opus and other non-vorbis formats omit the "framing_bit".
+
The comment header is decoded as follows:
1) [vendor_length] = read an unsigned integer of 32 bits
2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
@@ -759,17 +887,13 @@
5) [length] = read an unsigned integer of 32 bits
6) this iteration's user comment = read a UTF-8 vector as [length] octets
}
- 7) [framing_bit] = read a single bit as boolean
- 8) if ( [framing_bit] unset or end of packet ) then ERROR
- 9) done.
+ 7) done.
+*/
- If you have troubles, please write to ymnk@jcraft.com.
- */
-
#define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \
((buf[base+2]<<16)&0xff0000)| \
((buf[base+1]<<8)&0xff00)| \
- (buf[base]&0xff))
+ (buf[base]&0xff))
#define writeint(buf, base, val) do{ buf[base+3]=((val)>>24)&0xff; \
buf[base+2]=((val)>>16)&0xff; \
buf[base+1]=((val)>>8)&0xff; \
@@ -783,8 +907,8 @@
int len=8+4+vendor_length+4;
char *p=(char*)malloc(len);
if(p==NULL){
- fprintf (stderr, "malloc failed in comment_init()\n");
- exit(1);
+ fprintf(stderr, "malloc failed in comment_init()\n");
+ exit(1);
}
memcpy(p, "OpusTags", 8);
writeint(p, 8, vendor_length);
@@ -793,6 +917,7 @@
*length=len;
*comments=p;
}
+
void comment_add(char **comments, int* length, char *tag, char *val)
{
char* p=*comments;
@@ -804,8 +929,8 @@
p=(char*)realloc(p, len);
if(p==NULL){
- fprintf (stderr, "realloc failed in comment_add()\n");
- exit(1);
+ fprintf(stderr, "realloc failed in comment_add()\n");
+ exit(1);
}
writeint(p, *length, tag_len+val_len); /* length of comment */
@@ -812,7 +937,6 @@
if(tag) memcpy(p+*length+4, tag, tag_len); /* comment */
memcpy(p+*length+4+tag_len, val, val_len); /* comment */
writeint(p, 8+4+vendor_length, user_comment_list_length+1);
-
*comments=p;
*length=len;
}