ref: a638dfa37bd857e14b088e0ccade701dc6aafc79
parent: e9bbfacf0a1bbade70005fa730cc50e838baaa32
author: Jean-Marc Valin <jmvalin@jmvalin.ca>
date: Wed May 10 18:30:32 EDT 2017
opusenc: Convert to use libopusenc This adds a dependency, but gets rid of a lot of code. The main benefit is that libopusenc supports delayed decision. Signed-off-by: Mark Harris <mark.hsj@gmail.com>
--- a/Makefile.am
+++ b/Makefile.am
@@ -15,8 +15,7 @@
src/diag_range.h \
src/flac.h \
src/info_opus.h \
- src/lpc.h \
- src/opusenc.h \
+ src/encoder.h \
src/opus_header.h \
src/opusinfo.h \
src/os_support.h \
@@ -53,10 +52,10 @@
resampler_CPPFLAGS = -DSPX_RESAMPLE_EXPORT= -DRANDOM_PREFIX=opustools -DOUTSIDE_SPEEX -DFLOATING_POINT
-opusenc_SOURCES = src/opus_header.c src/opusenc.c src/picture.c src/resample.c src/audio-in.c src/diag_range.c src/flac.c src/lpc.c win32/unicode_support.c
-opusenc_CPPFLAGS = $(AM_CPPFLAGS) $(resampler_CPPFLAGS)
-opusenc_CFLAGS = $(AM_CFLAGS) $(FLAC_CFLAGS)
-opusenc_LDADD = $(OPUS_LIBS) $(FLAC_LIBS) $(OGG_LIBS) $(LIBM)
+opusenc_SOURCES = src/opus_header.c src/opusenc.c src/picture.c src/audio-in.c src/diag_range.c src/flac.c win32/unicode_support.c
+opusenc_CPPFLAGS = $(AM_CPPFLAGS)
+opusenc_CFLAGS = $(AM_CFLAGS) $(LIBOPUSENC_CFLAGS) $(FLAC_CFLAGS)
+opusenc_LDADD = $(LIBOPUSENC_LIBS) $(OPUS_LIBS) $(FLAC_LIBS) $(OGG_LIBS) $(LIBM)
opusenc_MANS = man/opusenc.1
opusdec_SOURCES = src/opus_header.c src/wav_io.c src/wave_out.c src/opusdec.c src/resample.c src/diag_range.c win32/unicode_support.c
--- a/configure.ac
+++ b/configure.ac
@@ -159,6 +159,17 @@
OPUSURL_LIBS="$OPUSFILE_LIBS -lopusurl"
])
+dnl check for libopusenc
+AS_IF([test "$HAVE_PKG_CONFIG" = "yes"],
+ [PKG_CHECK_MODULES([LIBOPUSENC],[libopusenc >= 0.1.1])],
+ [
+ dnl fall back to the old school test
+ XIPH_PATH_LIBOPUSENC(, AC_MSG_ERROR([
+ libopusenc is required to build this package!
+ Please see https://opus-codec.org/ for how to obtain a copy.
+ ]))
+ ])
+
dnl check for OSS
HAVE_OSS=no
AC_CHECK_HEADERS([sys/soundcard.h soundcard.h machine/soundcard.h],[
--- /dev/null
+++ b/m4/libopusenc.m4
@@ -1,0 +1,117 @@
+# Configure paths for libopusenc
+# Jean-Marc Valin <jmvalin@jmvalin.ca> 11-12-2017
+# Jack Moffitt <jack@icecast.org> 10-21-2000
+# Shamelessly stolen from Owen Taylor and Manish Singh
+
+dnl XIPH_PATH_LIBOPUSENC([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for libopusenc, and define LIBOPUSENC_CFLAGS and LIBOPUSENC_LIBS
+dnl
+AC_DEFUN([XIPH_PATH_LIBOPUSENC],
+[dnl
+dnl Get the cflags and libraries
+dnl
+AC_ARG_WITH(libopusenc,AC_HELP_STRING([--with-libopusenc=PFX],[Prefix where libopusenc is installed (optional)]), libopusenc_prefix="$withval", libopusenc_prefix="")
+AC_ARG_WITH(libopusenc-libraries,AC_HELP_STRING([--with-libopusenc-libraries=DIR],[Directory where libopusenc library is installed (optional)]), libopusenc_libraries="$withval", libopusenc_libraries="")
+AC_ARG_WITH(libopusenc-includes,AC_HELP_STRING([--with-libopusenc-includes=DIR],[Directory where libopusenc header files are installed (optional)]), libopusenc_includes="$withval", libopusenc_includes="")
+AC_ARG_ENABLE(libopusenctest,AC_HELP_STRING([--disable-libopusenctest],[Do not try to compile and run a test libopusenc program]),, enable_libopusenctest=yes)
+
+ if test "x$libopusenc_libraries" != "x" ; then
+ LIBOPUSENC_LIBS="-L$libopusenc_libraries"
+ elif test "x$libopusenc_prefix" = "xno" || test "x$libopusenc_prefix" = "xyes" ; then
+ LIBOPUSENC_LIBS=""
+ elif test "x$libopusenc_prefix" != "x" ; then
+ LIBOPUSENC_LIBS="-L$libopusenc_prefix/lib"
+ elif test "x$prefix" != "xNONE" ; then
+ LIBOPUSENC_LIBS="-L$prefix/lib"
+ fi
+
+ if test "x$libopusenc_prefix" != "xno" ; then
+ LIBOPUSENC_LIBS="$LIBOPUSENC_LIBS -lopusenc"
+ fi
+
+ if test "x$libopusenc_includes" != "x" ; then
+ LIBOPUSENC_CFLAGS="-I$libopusenc_includes"
+ elif test "x$libopusenc_prefix" = "xno" || test "x$libopusenc_prefix" = "xyes" ; then
+ LIBOPUSENC_CFLAGS=""
+ elif test "x$libopusenc_prefix" != "x" ; then
+ LIBOPUSENC_CFLAGS="-I$libopusenc_prefix/include/opus"
+ elif test "x$prefix" != "xNONE"; then
+ LIBOPUSENC_CFLAGS="-I$prefix/include/opus"
+ fi
+
+ AC_MSG_CHECKING(for libopusenc)
+ if test "x$libopusenc_prefix" = "xno" ; then
+ no_libopusenc="disabled"
+ enable_libopusenctest="no"
+ else
+ no_libopusenc=""
+ fi
+
+
+ if test "x$enable_libopusenctest" = "xyes" ; then
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $LIBOPUSENC_CFLAGS $OPUS_CFLAGS"
+ LIBS="$LIBS $LIBOPUSENC_LIBS $OPUS_LIBS"
+dnl
+dnl Now check if the installed libopusenc is sufficiently new.
+dnl
+ rm -f conf.libopusenctest
+ AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <opusenc.h>
+
+int main ()
+{
+ system("touch conf.libopusenctest");
+ return 0;
+}
+
+],, no_libopusenc=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+
+ if test "x$no_libopusenc" = "xdisabled" ; then
+ AC_MSG_RESULT(no)
+ ifelse([$2], , :, [$2])
+ elif test "x$no_libopusenc" = "x" ; then
+ AC_MSG_RESULT(yes)
+ ifelse([$1], , :, [$1])
+ else
+ AC_MSG_RESULT(no)
+ if test -f conf.libopusenctest ; then
+ :
+ else
+ echo "*** Could not run libopusenc test program, checking why..."
+ CFLAGS="$CFLAGS $LIBOPUSENC_CFLAGS"
+ LIBS="$LIBS $LIBOPUSENC_LIBS"
+ AC_TRY_LINK([
+#include <stdio.h>
+#include <opusenc.h>
+], [ return 0; ],
+ [ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding libopusenc or finding the wrong"
+ echo "*** version of libopusenc. If it is not finding libopusenc, you'll need to set your"
+ echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+ echo "*** to the installed location Also, make sure you have run ldconfig if that"
+ echo "*** is required on your system"
+ echo "***"
+ echo "*** If you have an old version installed, it is best to remove it, although"
+ echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+ [ echo "*** The test program failed to compile or link. See the file config.log for the"
+ echo "*** exact error that occured. This usually means libopusenc was incorrectly installed"
+ echo "*** or that you have moved libopusenc since it was installed." ])
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ LIBOPUSENC_CFLAGS=""
+ LIBOPUSENC_LIBS=""
+ ifelse([$2], , :, [$2])
+ fi
+ AC_SUBST(LIBOPUSENC_CFLAGS)
+ AC_SUBST(LIBOPUSENC_LIBS)
+ rm -f conf.libopusenctest
+])
--- a/man/opusenc.1
+++ b/man/opusenc.1
@@ -267,33 +267,17 @@
There may only be one picture each of type 1 and 2 in a file.
.I media-type
-is optional. If left blank, it will be detected from the file. For
-best compatibility with players, use pictures with a
-.I media-type
-of image/jpeg or image/png. The
-.I media-type
-can also be "-->" to mean that
-.I filename
-is actually a URL to an image, though this use is discouraged.
-The file at the URL will not be fetched.
-The URL itself is stored in the metadata.
+is optional and is now ignored.
.I description
is optional. The default is an empty string.
-The next part specifies the resolution and color information. If the
-.I media-type
-is image/jpeg, image/png, or image/gif, this can usually be left empty
-and the information will be read from the file.
-Otherwise, you must specify the width in
-pixels, height in pixels, and color depth in bits-per-pixel. If the image has
-indexed colors you should also specify the number of colors used. If possible,
-these are checked against the file for accuracy.
+The next part specifies the resolution and color information, but
+is now ignored.
.I filename
-is the path to the picture file to be imported, or the URL if the
-.I media-type
-is "-->".
+is the path to the picture file to be imported.
+
.IP "--padding n"
Reserve
.I n
--- a/src/audio-in.c
+++ b/src/audio-in.c
@@ -71,9 +71,7 @@
#endif
#include <ogg/ogg.h>
-#include "opusenc.h"
-#include "speex_resampler.h"
-#include "lpc.h"
+#include "encoder.h"
#include "opus_header.h"
#include "flac.h"
@@ -886,157 +884,6 @@
opt->readdata = d;
d->channels = opt->channels;
d->scale_factor = scale;
-}
-
-typedef struct {
- audio_read_func real_reader;
- void *real_readdata;
- ogg_int64_t *original_samples;
- int channels;
- int lpc_ptr;
- int *extra_samples;
- float *lpc_out;
-} padder;
-
-/* Read audio data, appending padding to make up any gap
- * between the available and requested number of samples
- * with LPC-predicted data to minimize the pertubation of
- * the valid data that falls in the same frame.
- */
-static long read_padder(void *data, float *buffer, int samples) {
- padder *d = data;
- long in_samples = d->real_reader(d->real_readdata, buffer, samples);
- int i, extra=0;
- const int lpc_order=32;
-
- if(d->original_samples)*d->original_samples+=in_samples;
-
- if(in_samples<samples){
- if(d->lpc_ptr<0){
- d->lpc_out=calloc(d->channels * *d->extra_samples, sizeof(*d->lpc_out));
- if(in_samples>lpc_order*2){
- float *lpc=alloca(lpc_order*sizeof(*lpc));
- for(i=0;i<d->channels;i++){
- vorbis_lpc_from_data(buffer+i,lpc,in_samples,lpc_order,d->channels);
- vorbis_lpc_predict(lpc,buffer+i+(in_samples-lpc_order)*d->channels,
- lpc_order,d->lpc_out+i,*d->extra_samples,d->channels);
- }
- }
- d->lpc_ptr=0;
- }
- extra=samples-in_samples;
- if(extra>*d->extra_samples)extra=*d->extra_samples;
- *d->extra_samples-=extra;
- }
- memcpy(buffer+in_samples*d->channels,d->lpc_out+d->lpc_ptr*d->channels,extra*d->channels*sizeof(*buffer));
- d->lpc_ptr+=extra;
- return in_samples+extra;
-}
-
-void setup_padder(oe_enc_opt *opt,ogg_int64_t *original_samples) {
- padder *d = calloc(1, sizeof(padder));
-
- d->real_reader = opt->read_samples;
- d->real_readdata = opt->readdata;
-
- opt->read_samples = read_padder;
- opt->readdata = d;
- d->channels = opt->channels;
- d->extra_samples = &opt->extraout;
- d->original_samples=original_samples;
- d->lpc_ptr = -1;
- d->lpc_out = NULL;
-}
-
-void clear_padder(oe_enc_opt *opt) {
- padder *d = opt->readdata;
-
- opt->read_samples = d->real_reader;
- opt->readdata = d->real_readdata;
-
- if(d->lpc_out)free(d->lpc_out);
- free(d);
-}
-
-typedef struct {
- SpeexResamplerState *resampler;
- audio_read_func real_reader;
- void *real_readdata;
- float *bufs;
- int channels;
- int bufpos;
- int bufsize;
- int done;
-} resampler;
-
-static long read_resampled(void *d, float *buffer, int samples)
-{
- resampler *rs = d;
- int out_samples=0;
- float *pcmbuf;
- int *inbuf;
- pcmbuf=rs->bufs;
- inbuf=&rs->bufpos;
- while(out_samples<samples){
- int i;
- int reading, ret;
- unsigned in_len, out_len;
- out_len=samples-out_samples;
- reading=rs->bufsize-*inbuf;
- if(reading>1024)reading=1024;
- ret=rs->real_reader(rs->real_readdata, pcmbuf+*inbuf*rs->channels, reading);
- *inbuf+=ret;
- in_len=*inbuf;
- speex_resampler_process_interleaved_float(rs->resampler, pcmbuf, &in_len, buffer+out_samples*rs->channels, &out_len);
- out_samples+=out_len;
- if(ret==0&&in_len==0){
- for(i=out_samples*rs->channels;i<samples*rs->channels;i++)buffer[i]=0;
- return out_samples;
- }
- for(i=0;i<rs->channels*(*inbuf-(long int)in_len);i++)pcmbuf[i]=pcmbuf[i+rs->channels*in_len];
- *inbuf-=in_len;
- }
- return out_samples;
-}
-
-int setup_resample(oe_enc_opt *opt, int complexity, long outfreq) {
- resampler *rs = calloc(1, sizeof(resampler));
- int err;
-
- rs->bufsize = 5760*2; /* Have at least two output frames worth, just in case of ugly ratios */
- rs->bufpos = 0;
-
- rs->real_reader = opt->read_samples;
- rs->real_readdata = opt->readdata;
- rs->channels = opt->channels;
- rs->done = 0;
- rs->resampler = speex_resampler_init(rs->channels, opt->rate, outfreq, complexity, &err);
- if(err!=0)fprintf(stderr, _("resampler error: %s\n"), speex_resampler_strerror(err));
-
- speex_resampler_skip_zeros(rs->resampler);
-
- rs->bufs = malloc(sizeof(float) * rs->bufsize * opt->channels);
-
- opt->read_samples = read_resampled;
- opt->readdata = rs;
- if(opt->total_samples_per_channel)
- opt->total_samples_per_channel = (opus_int64)
- ((double)opt->total_samples_per_channel * ((double)outfreq/(double)opt->rate));
- opt->rate = outfreq;
-
- return 0;
-}
-
-void clear_resample(oe_enc_opt *opt) {
- resampler *rs = opt->readdata;
-
- opt->read_samples = rs->real_reader;
- opt->readdata = rs->real_readdata;
- speex_resampler_destroy(rs->resampler);
-
- free(rs->bufs);
-
- free(rs);
}
typedef struct {
--- a/src/diag_range.c
+++ b/src/diag_range.c
@@ -216,7 +216,7 @@
return count;
}
-void save_range(FILE *frange, int frame_size, unsigned char *packet, int nbBytes, opus_uint32 *rngs, int nb_streams){
+void save_range(FILE *frange, int frame_size, const unsigned char *packet, int nbBytes, opus_uint32 *rngs, int nb_streams){
int i, parsed_size;
const unsigned char *subpkt;
static const char *bw_strings[5]={"NB","MB","WB","SWB","FB"};
--- a/src/diag_range.h
+++ b/src/diag_range.h
@@ -25,4 +25,4 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-void save_range(FILE *frange, int frame_size, unsigned char *packet, int nbBytes, opus_uint32 *rngs, int nb_streams);
+void save_range(FILE *frange, int frame_size, const unsigned char *packet, int nbBytes, opus_uint32 *rngs, int nb_streams);
--- /dev/null
+++ b/src/encoder.h
@@ -1,0 +1,103 @@
+#ifndef __OPUSENC_H
+#define __OPUSENC_H
+
+#include <opus_types.h>
+#include <opusenc.h>
+
+#ifdef ENABLE_NLS
+#include <libintl.h>
+#define _(X) gettext(X)
+#else
+#define _(X) (X)
+#define textdomain(X)
+#define bindtextdomain(X, Y)
+#endif
+#ifdef gettext_noop
+#define N_(X) gettext_noop(X)
+#else
+#define N_(X) (X)
+#endif
+
+typedef long (*audio_read_func)(void *src, float *buffer, int samples);
+
+typedef struct
+{
+ audio_read_func read_samples;
+ void *readdata;
+ opus_int64 total_samples_per_channel;
+ int rawmode;
+ int channels;
+ long rate;
+ int gain;
+ int samplesize;
+ int endianness;
+ char *infilename;
+ int ignorelength;
+ int skip;
+ int extraout;
+ OggOpusComments *comments;
+ int copy_comments;
+ int copy_pictures;
+} oe_enc_opt;
+
+void setup_scaler(oe_enc_opt *opt, float scale);
+void clear_scaler(oe_enc_opt *opt);
+int setup_downmix(oe_enc_opt *opt, int out_channels);
+void clear_downmix(oe_enc_opt *opt);
+
+typedef struct
+{
+ int (*id_func)(unsigned char *buf, int len); /* Returns true if can load file */
+ int id_data_len; /* Amount of data needed to id whether this can load the file */
+ int (*open_func)(FILE *in, oe_enc_opt *opt, unsigned char *buf, int buflen);
+ void (*close_func)(void *);
+ char *format;
+ char *description;
+} input_format;
+
+typedef struct {
+ unsigned short format;
+ unsigned short channels;
+ unsigned int samplerate;
+ unsigned int bytespersec;
+ unsigned short align;
+ unsigned short samplesize;
+ unsigned int mask;
+} wav_fmt;
+
+typedef struct {
+ unsigned short channels;
+ short samplesize;
+ opus_int64 totalsamples;
+ opus_int64 samplesread;
+ FILE *f;
+ short bigendian;
+ short unsigned8bit;
+ int *channel_permute;
+} wavfile;
+
+typedef struct {
+ short channels;
+ unsigned int totalframes;
+ short samplesize;
+ double rate;
+ unsigned int offset;
+ unsigned int blocksize;
+} aiff_fmt;
+
+typedef wavfile aifffile; /* They're the same */
+
+input_format *open_audio_file(FILE *in, oe_enc_opt *opt);
+
+int raw_open(FILE *in, oe_enc_opt *opt, unsigned char *buf, int buflen);
+int wav_open(FILE *in, oe_enc_opt *opt, unsigned char *buf, int buflen);
+int aiff_open(FILE *in, oe_enc_opt *opt, unsigned char *buf, int buflen);
+int wav_id(unsigned char *buf, int len);
+int aiff_id(unsigned char *buf, int len);
+void wav_close(void *);
+void raw_close(void *);
+
+long wav_read(void *, float *buffer, int samples);
+long wav_ieee_read(void *, float *buffer, int samples);
+
+#endif /* __OPUSENC_H */
--- a/src/flac.c
+++ b/src/flac.c
@@ -168,7 +168,7 @@
_("Discarding comment not in the form name=value\n"));
continue;
}
- comment_add(&inopt->comments,&inopt->comments_length,NULL,entry);
+ ope_comments_add_string(inopt->comments,entry);
}
setlocale(LC_NUMERIC,saved_locale);
/*Set the header gain to the album gain after converting to the R128
@@ -184,8 +184,7 @@
gain=256*(track_gain-album_gain)+0.5;
track_gain_val=gain<-32768?-32768:gain<32767?(int)floor(gain):32767;
sprintf(track_gain_buf,"%i",track_gain_val);
- comment_add(&inopt->comments,&inopt->comments_length,
- "R128_TRACK_GAIN",track_gain_buf);
+ ope_comments_add(inopt->comments, "R128_TRACK_GAIN",track_gain_buf);
}
}
break;
@@ -231,8 +230,7 @@
b64=(char *)malloc(b64_sz);
base64_encode(b64,buf,buf_sz);
free(buf);
- comment_add(&inopt->comments,&inopt->comments_length,
- "METADATA_BLOCK_PICTURE",b64);
+ ope_comments_add(inopt->comments, "METADATA_BLOCK_PICTURE", b64);
free(b64);
}
break;
--- a/src/flac.h
+++ b/src/flac.h
@@ -26,7 +26,7 @@
# define __FLAC_H
# include <stdio.h>
# include "os_support.h"
-# include "opusenc.h"
+# include "encoder.h"
# if defined(HAVE_LIBFLAC)
# include <FLAC/stream_decoder.h>
# include <FLAC/metadata.h>
--- a/src/lpc.c
+++ /dev/null
@@ -1,166 +1,0 @@
-/********************************************************************
- * *
- * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
- * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
- * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
- * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
- * *
- * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
- * *
- ********************************************************************
-
- function: LPC low level routines
- last mod: $Id: lpc.c 16227 2009-07-08 06:58:46Z xiphmont $
-
- ********************************************************************/
-
-/* Some of these routines (autocorrelator, LPC coefficient estimator)
- are derived from code written by Jutta Degener and Carsten Bormann;
- thus we include their copyright below. The entirety of this file
- is freely redistributable on the condition that both of these
- copyright notices are preserved without modification. */
-
-/* Preserved Copyright: *********************************************/
-
-/* Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann,
-Technische Universita"t Berlin
-
-Any use of this software is permitted provided that this notice is not
-removed and that neither the authors nor the Technische Universita"t
-Berlin are deemed to have made any representations as to the
-suitability of this software for any purpose nor are held responsible
-for any defects of this software. THERE IS ABSOLUTELY NO WARRANTY FOR
-THIS SOFTWARE.
-
-As a matter of courtesy, the authors request to be informed about uses
-this software has found, about bugs in this software, and about any
-improvements that may be of general interest.
-
-Berlin, 28.11.1994
-Jutta Degener
-Carsten Bormann
-
-*********************************************************************/
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include "lpc.h"
-
-/* Autocorrelation LPC coeff generation algorithm invented by
- N. Levinson in 1947, modified by J. Durbin in 1959. */
-
-/* Input : n elements of time doamin data
- Output: m lpc coefficients, excitation energy */
-
-float vorbis_lpc_from_data(float *data,float *lpci,int n,int m,int stride){
- double *aut=malloc(sizeof(*aut)*(m+1));
- double *lpc=malloc(sizeof(*lpc)*(m));
- double error;
- double epsilon;
- int i,j;
-
- if(!aut || !lpc)return 0;
-
- /* autocorrelation, p+1 lag coefficients */
- j=m+1;
- while(j--){
- double d=0; /* double needed for accumulator depth */
- for(i=j;i<n;i++)d+=(double)data[i*stride]*data[(i-j)*stride];
- aut[j]=d;
- }
-
- /* Generate lpc coefficients from autocorr values */
-
- /* set our noise floor to about -100dB */
- error=aut[0] * (1. + 1e-10);
- epsilon=1e-9*aut[0]+1e-10;
-
- for(i=0;i<m;i++){
- double r= -aut[i+1];
-
- if(error<epsilon){
- memset(lpc+i,0,(m-i)*sizeof(*lpc));
- goto done;
- }
-
- /* Sum up this iteration's reflection coefficient; note that in
- Vorbis we don't save it. If anyone wants to recycle this code
- and needs reflection coefficients, save the results of 'r' from
- each iteration. */
-
- for(j=0;j<i;j++)r-=lpc[j]*aut[i-j];
- r/=error;
-
- /* Update LPC coefficients and total error */
-
- lpc[i]=r;
- for(j=0;j<i/2;j++){
- double tmp=lpc[j];
-
- lpc[j]+=r*lpc[i-1-j];
- lpc[i-1-j]+=r*tmp;
- }
- if(i&1)lpc[j]+=lpc[j]*r;
-
- error*=1.-r*r;
-
- }
-
- done:
-
- /* slightly damp the filter */
- {
- double g = .99;
- double damp = g;
- for(j=0;j<m;j++){
- lpc[j]*=damp;
- damp*=g;
- }
- }
-
- for(j=0;j<m;j++)lpci[j]=(float)lpc[j];
-
- /* we need the error value to know how big an impulse to hit the
- filter with later */
- free(aut);
- free(lpc);
- return error;
-}
-
-void vorbis_lpc_predict(float *coeff,float *prime,int m,
- float *data,long n,int stride){
-
- /* in: coeff[0...m-1] LPC coefficients
- prime[0...m-1] initial values (allocated size of n+m-1)
- out: data[0...n-1] data samples */
-
- long i,j,o,p;
- float y;
- float *work=malloc(sizeof(*work)*(m+n));
-
- if(!work)return;
-
- if(!prime)
- for(i=0;i<m;i++)
- work[i]=0.f;
- else
- for(i=0;i<m;i++)
- work[i]=prime[i*stride];
-
- for(i=0;i<n;i++){
- y=0;
- o=i;
- p=m;
- for(j=0;j<m;j++)
- y-=work[o++]*coeff[--p];
-
- data[i*stride]=work[o]=y;
- }
- free(work);
-}
--- a/src/lpc.h
+++ /dev/null
@@ -1,27 +1,0 @@
-/********************************************************************
- * *
- * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
- * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
- * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
- * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
- * *
- * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
- * *
- ********************************************************************
-
- function: LPC low level routines
- last mod: $Id: lpc.h 16037 2009-05-26 21:10:58Z xiphmont $
-
- ********************************************************************/
-
-#ifndef _V_LPC_H_
-#define _V_LPC_H_
-
-/* simple linear scale LPC code */
-extern float vorbis_lpc_from_data(float *data,float *lpc,int n,int m,int stride);
-
-extern void vorbis_lpc_predict(float *coeff,float *prime,int m,
- float *data,long n,int stride);
-
-#endif
--- a/src/opus_header.c
+++ b/src/opus_header.c
@@ -58,49 +58,11 @@
*/
typedef struct {
- unsigned char *data;
- int maxlen;
- int pos;
-} Packet;
-
-typedef struct {
const unsigned char *data;
int maxlen;
int pos;
} ROPacket;
-static int write_uint32(Packet *p, ogg_uint32_t val)
-{
- if (p->pos>p->maxlen-4)
- return 0;
- p->data[p->pos ] = (val ) & 0xFF;
- p->data[p->pos+1] = (val>> 8) & 0xFF;
- p->data[p->pos+2] = (val>>16) & 0xFF;
- p->data[p->pos+3] = (val>>24) & 0xFF;
- p->pos += 4;
- return 1;
-}
-
-static int write_uint16(Packet *p, ogg_uint16_t val)
-{
- if (p->pos>p->maxlen-2)
- return 0;
- p->data[p->pos ] = (val ) & 0xFF;
- p->data[p->pos+1] = (val>> 8) & 0xFF;
- p->pos += 2;
- return 1;
-}
-
-static int write_chars(Packet *p, const unsigned char *str, int nb_chars)
-{
- int i;
- if (p->pos>p->maxlen-nb_chars)
- return 0;
- for (i=0;i<nb_chars;i++)
- p->data[p->pos++] = str[i];
- return 1;
-}
-
static int read_uint32(ROPacket *p, ogg_uint32_t *val)
{
if (p->pos>p->maxlen-4)
@@ -214,61 +176,6 @@
if ((h->version==0 || h->version==1) && p.pos != len)
return 0;
return 1;
-}
-
-int opus_header_to_packet(const OpusHeader *h, unsigned char *packet, int len)
-{
- int i;
- Packet p;
- unsigned char ch;
-
- p.data = packet;
- p.maxlen = len;
- p.pos = 0;
- if (len<19)return 0;
- if (!write_chars(&p, (const unsigned char*)"OpusHead", 8))
- return 0;
- /* Version is 1 */
- ch = 1;
- if (!write_chars(&p, &ch, 1))
- return 0;
-
- ch = h->channels;
- if (!write_chars(&p, &ch, 1))
- return 0;
-
- if (!write_uint16(&p, h->preskip))
- return 0;
-
- if (!write_uint32(&p, h->input_sample_rate))
- return 0;
-
- if (!write_uint16(&p, h->gain))
- return 0;
-
- ch = h->channel_mapping;
- if (!write_chars(&p, &ch, 1))
- return 0;
-
- if (h->channel_mapping != 0)
- {
- ch = h->nb_streams;
- if (!write_chars(&p, &ch, 1))
- return 0;
-
- ch = h->nb_coupled;
- if (!write_chars(&p, &ch, 1))
- return 0;
-
- /* Multi-stream support */
- for (i=0;i<h->channels;i++)
- {
- if (!write_chars(&p, &h->stream_map[i], 1))
- return 0;
- }
- }
-
- return p.pos;
}
/* This is just here because it's a convenient file linked by both opusenc and
--- a/src/opus_header.h
+++ b/src/opus_header.h
@@ -44,7 +44,6 @@
} OpusHeader;
int opus_header_parse(const unsigned char *header, int len, OpusHeader *h);
-int opus_header_to_packet(const OpusHeader *h, unsigned char *packet, int len);
extern const int wav_permute_matrix[8][8];
--- a/src/opusenc.c
+++ b/src/opusenc.c
@@ -61,14 +61,13 @@
#include <opus.h>
#include <opus_multistream.h>
-#include <ogg/ogg.h>
#include "wav_io.h"
-#include "picture.h"
#include "opus_header.h"
-#include "opusenc.h"
+#include "encoder.h"
#include "diag_range.h"
#include "cpusupport.h"
+#include <opusenc.h>
#ifdef VALGRIND
#include <valgrind/memcheck.h>
@@ -79,19 +78,6 @@
#define VG_CHECK(x,y)
#endif
-static void comment_init(char **comments, int* length, const char *vendor_string);
-static void comment_pad(char **comments, int* length, int amount);
-
-/*Write an Ogg page to a file pointer*/
-static inline 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);
- return written;
-}
-
-#define MAX_FRAME_BYTES 61295
#define IMIN(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum int value. */
#define IMAX(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum int value. */
@@ -206,25 +192,14 @@
printf(" be specified to attach multiple pictures. There may only be one\n");
printf(" picture each of type 1 and 2 in a file.\n");
printf("\n");
- printf(" MEDIA-TYPE is optional. If left blank, it will be detected from the\n");
- printf(" file. For best compatibility with players, use pictures with a\n");
- printf(" MEDIA-TYPE of image/jpeg or image/png. The MEDIA-TYPE can also be\n");
- printf(" \"-->\" to mean that FILENAME is actually a URL to an image, though\n");
- printf(" this use is discouraged. The file at the URL will not be fetched.\n");
- printf(" The URL itself is stored in the metadata.\n");
+ printf(" MEDIA-TYPE is optional and is now ignored.\n");
printf("\n");
printf(" DESCRIPTION is optional. The default is an empty string.\n");
printf("\n");
- printf(" The next part specifies the resolution and color information. If\n");
- printf(" the MEDIA-TYPE is image/jpeg, image/png, or image/gif, this can\n");
- printf(" usually be left empty and the information will be read from the\n");
- printf(" file. Otherwise, you must specify the width in pixels, height in\n");
- printf(" pixels, and color depth in bits-per-pixel. If the image has indexed\n");
- printf(" colors you should also specify the number of colors used. If possible,\n");
- printf(" these are checked against the file for accuracy.\n");
+ printf(" The next part specifies the resolution and color information, but\n");
+ printf(" is now ignored.\n");
printf("\n");
- printf(" FILENAME is the path to the picture file to be imported, or the URL\n");
- printf(" if the MEDIA-TYPE is \"-->\".\n");
+ printf(" FILENAME is the path to the picture file to be imported.\n");
}
static inline void print_time(double seconds)
@@ -241,6 +216,62 @@
if(seconds>0)fprintf(stderr," %0.4g second%s",seconds,seconds!=1?"s":"");
}
+typedef struct {
+ OggOpusEnc *enc;
+ FILE *fout;
+ opus_int64 total_bytes;
+ opus_int64 bytes_written;
+ opus_int64 nb_encoded;
+ opus_int64 pages_out;
+ opus_int64 packets_out;
+ int peak_bytes;
+ int min_bytes;
+ int last_length;
+ FILE *frange;
+} EncData;
+
+int write_callback(void *user_data, const unsigned char *ptr, opus_int32 len) {
+ EncData *data = (EncData*)user_data;
+ data->bytes_written += len;
+ data->pages_out++;
+ return fwrite(ptr, 1, len, data->fout) != (size_t)len;
+}
+
+int close_callback(void *user_data) {
+ EncData *obj = (EncData*)user_data;
+ int ret = 0;
+ if (obj->fout) ret = fclose(obj->fout);
+ return ret;
+}
+
+int packet_callback(void *user_data, const unsigned char *packet_ptr, opus_int32 packet_len, opus_uint32 flags) {
+ int frame_size;
+ EncData *data = (EncData*)user_data;
+ if (packet_ptr[0] == 'O' && packet_ptr[1] == 'p') return 0;
+ data->total_bytes+=packet_len;
+ data->peak_bytes=IMAX(packet_len,data->peak_bytes);
+ data->min_bytes=IMIN(packet_len,data->min_bytes);
+ frame_size = opus_packet_get_samples_per_frame(packet_ptr, 48000);
+ data->nb_encoded += frame_size;
+ data->packets_out++;
+ data->last_length = packet_len;
+ if(data->frange!=NULL){
+ int ret;
+ opus_uint32 rngs[256];
+ OpusEncoder *oe;
+ int nb_streams;
+ for(nb_streams=0;;nb_streams++){
+ ret=ope_encoder_ctl(data->enc,OPUS_MULTISTREAM_GET_ENCODER_STATE(nb_streams,&oe));
+ if (ret != 0 || oe == NULL) break;
+ ret=opus_encoder_ctl(oe,OPUS_GET_FINAL_RANGE(&rngs[nb_streams]));
+ }
+ save_range(data->frange,frame_size,packet_ptr,packet_len,
+ rngs,nb_streams);
+ }
+ (void)flags;
+ return 0;
+}
+
int main(int argc, char **argv)
{
static const input_format raw_format = {NULL, 0, raw_open, wav_close, "raw",N_("RAW file reader")};
@@ -288,9 +319,10 @@
};
int i, ret;
int cline_size;
- OpusMSEncoder *st;
+ OpusEncCallbacks callbacks = {write_callback, close_callback};
+ OggOpusEnc *enc;
+ EncData data;
const char *opus_version;
- unsigned char *packet;
float *input;
/*I/O*/
oe_enc_opt inopt;
@@ -299,28 +331,11 @@
char *outFile;
char *range_file;
FILE *fin;
- FILE *fout;
- FILE *frange;
- ogg_stream_state os;
- ogg_page og;
- ogg_packet op;
- ogg_int64_t last_granulepos=0;
- ogg_int64_t enc_granulepos=0;
- ogg_int64_t original_samples=0;
- ogg_int32_t id=-1;
- int last_segments=0;
- OpusHeader header;
+ int eos;
char ENCODER_string[1024];
/*Counters*/
- opus_int64 nb_encoded=0;
- opus_int64 bytes_written=0;
- opus_int64 pages_out=0;
- opus_int64 total_bytes=0;
opus_int64 total_samples=0;
- opus_int32 nbBytes;
opus_int32 nb_samples;
- opus_int32 peak_bytes=0;
- opus_int32 min_bytes;
time_t start_time;
time_t stop_time;
time_t last_spin=0;
@@ -327,11 +342,10 @@
int last_spin_len=0;
/*Settings*/
int quiet=0;
- int max_frame_bytes;
opus_int32 bitrate=-1;
opus_int32 rate=48000;
- opus_int32 coding_rate=48000;
opus_int32 frame_size=960;
+ opus_int32 opus_frame_param = OPUS_FRAMESIZE_20_MS;
int chan=2;
int with_hard_cbr=0;
int with_cvbr=0;
@@ -345,6 +359,8 @@
int comment_padding=512;
int serialno;
opus_int32 lookahead=0;
+ int nb_streams;
+ int nb_coupled;
#ifdef WIN_UNICODE
int argc_utf8;
char **argv_utf8;
@@ -363,11 +379,10 @@
#endif
opt_ctls_ctlval=NULL;
- frange=NULL;
range_file=NULL;
in_format=NULL;
inopt.channels=chan;
- inopt.rate=coding_rate=rate;
+ inopt.rate=rate;
/* 0 dB gain is recommended unless you know what you're doing */
inopt.gain=0;
inopt.samplesize=16;
@@ -381,15 +396,16 @@
srand(((getpid()&65535)<<15)^start_time);
serialno=rand();
+ inopt.comments = ope_comments_create();
opus_version=opus_get_version_string();
/*Vendor string should just be the encoder library,
the ENCODER comment specifies the tool used.*/
- comment_init(&inopt.comments, &inopt.comments_length, opus_version);
snprintf(ENCODER_string, sizeof(ENCODER_string), "opusenc from %s %s",PACKAGE_NAME,PACKAGE_VERSION);
- comment_add(&inopt.comments, &inopt.comments_length, "ENCODER", ENCODER_string);
+ ope_comments_add(inopt.comments, "ENCODER", ENCODER_string);
/*Process command-line options*/
cline_size=0;
+ data.frange = NULL;
while(1){
int c;
int save_cmd=1;
@@ -473,6 +489,18 @@
exit(1);
}
}else if(strcmp(long_options[option_index].name,"framesize")==0){
+ if(strcmp(optarg,"2.5")==0)opus_frame_param=OPUS_FRAMESIZE_2_5_MS;
+ else if(strcmp(optarg,"5")==0)opus_frame_param=OPUS_FRAMESIZE_5_MS;
+ else if(strcmp(optarg,"10")==0)opus_frame_param=OPUS_FRAMESIZE_10_MS;
+ else if(strcmp(optarg,"20")==0)opus_frame_param=OPUS_FRAMESIZE_20_MS;
+ else if(strcmp(optarg,"40")==0)opus_frame_param=OPUS_FRAMESIZE_40_MS;
+ else if(strcmp(optarg,"60")==0)opus_frame_param=OPUS_FRAMESIZE_60_MS;
+ else{
+ fprintf(stderr,"Invalid framesize: %s\n",optarg);
+ fprintf(stderr,"Framesize must be 2.5, 5, 10, 20, 40, or 60.\n");
+ exit(1);
+ }
+
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;
@@ -525,9 +553,9 @@
opt_ctls_ctlval[opt_ctls*3+2]=atoi(spos+1);
opt_ctls++;
}else if(strcmp(long_options[option_index].name,"save-range")==0){
- frange=fopen_utf8(optarg,"w");
+ data.frange=fopen_utf8(optarg,"w");
save_cmd=0;
- if(frange==NULL){
+ if(data.frange==NULL){
perror(optarg);
fprintf(stderr,"Could not open save-range file: %s\n",optarg);
fprintf(stderr,"Must provide a writable file name.\n");
@@ -541,35 +569,93 @@
fprintf(stderr, "Comments must be of the form name=value\n");
exit(1);
}
- comment_add(&inopt.comments, &inopt.comments_length, NULL, optarg);
+ ope_comments_add_string(inopt.comments, optarg);
}else if(strcmp(long_options[option_index].name,"artist")==0){
save_cmd=0;
- comment_add(&inopt.comments, &inopt.comments_length, "artist", optarg);
+ ope_comments_add(inopt.comments, "artist", optarg);
} else if(strcmp(long_options[option_index].name,"title")==0){
save_cmd=0;
- comment_add(&inopt.comments, &inopt.comments_length, "title", optarg);
+ ope_comments_add(inopt.comments, "title", optarg);
} else if(strcmp(long_options[option_index].name,"album")==0){
save_cmd=0;
- comment_add(&inopt.comments, &inopt.comments_length, "album", optarg);
+ ope_comments_add(inopt.comments, "album", optarg);
} else if(strcmp(long_options[option_index].name,"date")==0){
save_cmd=0;
- comment_add(&inopt.comments, &inopt.comments_length, "date", optarg);
+ ope_comments_add(inopt.comments, "date", optarg);
} else if(strcmp(long_options[option_index].name,"genre")==0){
save_cmd=0;
- comment_add(&inopt.comments, &inopt.comments_length, "genre", optarg);
+ ope_comments_add(inopt.comments, "genre", optarg);
} else if(strcmp(long_options[option_index].name,"picture")==0){
- const char *error_message;
- char *picture_data;
- save_cmd=0;
- picture_data=parse_picture_specification(optarg,&error_message,
- &seen_file_icons);
- if(picture_data==NULL){
- fprintf(stderr,"Error parsing picture option: %s\n",error_message);
+ const char *media_type;
+ const char *media_type_end;
+ const char *description;
+ const char *description_end;
+ const char *filename;
+ const char *spec;
+ char *description_copy;
+ FILE *picture_file;
+ int picture_type;
+ spec = optarg;
+ picture_type=3;
+ media_type=media_type_end=description=description_end=filename=spec;
+ picture_file=fopen_utf8(filename,"rb");
+ description_copy=NULL;
+ if(picture_file==NULL&&strchr(spec,'|')){
+ const char *p;
+ char *q;
+ unsigned long val;
+ /*We don't have a plain file, and there is a pipe character: assume it's
+ the full form of the specification.*/
+ val=strtoul(spec,&q,10);
+ if(*q!='|'||val>20){
+ fprintf(stderr, "Invalid picture type: %.*s\n",
+ (int)strcspn(spec,"|"), spec);
+ exit(1);
+ }
+ /*An empty field implies a default of 'Cover (front)'.*/
+ if(spec!=q)picture_type=val;
+ media_type=q+1;
+ media_type_end=media_type+strcspn(media_type,"|");
+ if(*media_type_end=='|'){
+ description=media_type_end+1;
+ description_end=description+strcspn(description,"|");
+ if(*description_end=='|'){
+ p=description_end+1;
+ /*Ignore WIDTHxHEIGHTxDEPTH/COLORS.*/
+ p+=strcspn(p,"|");
+ if(*p=='|'){
+ filename=p+1;
+ }
+ }
+ }
+ if (filename==spec) {
+ fprintf(stderr, "Not enough fields in picture specification: %s\n", spec);
+ exit(1);
+ }
+ if (media_type_end-media_type==3 && strncmp("-->",media_type,3)==0) {
+ fprintf(stderr, "Picture URLs are no longer supported.\n");
+ exit(1);
+ }
+ if (picture_type>=1&&picture_type<=2&&(seen_file_icons&picture_type)) {
+ fprintf(stderr, "Only one picture of type %d (%s) is allowed.\n",
+ picture_type, picture_type==1 ? "32x32 icon" : "icon");
+ exit(1);
+ }
+ }
+ if (picture_file) fclose(picture_file);
+ if (description_end-description != 0) {
+ size_t len = description_end-description;
+ description_copy = malloc(len+1);
+ memcpy(description_copy, description, len);
+ description_copy[len]=0;
+ }
+ ret = ope_comments_add_picture(inopt.comments, filename, picture_type, description_copy);
+ if (ret != OPE_OK) {
+ fprintf(stderr, "Error: %s: %s\n", ope_strerror(ret), filename);
exit(1);
}
- comment_add(&inopt.comments,&inopt.comments_length,
- "METADATA_BLOCK_PICTURE",picture_data);
- free(picture_data);
+ if (description_copy) free(description_copy);
+ if (picture_type>=1&&picture_type<=2) seen_file_icons|=picture_type;
} else if(strcmp(long_options[option_index].name,"padding")==0){
comment_padding=atoi(optarg);
} else if(strcmp(long_options[option_index].name,"discard-comments")==0){
@@ -619,7 +705,7 @@
inFile=argv_utf8[optind];
outFile=argv_utf8[optind+1];
- if(cline_size>0)comment_add(&inopt.comments, &inopt.comments_length, "ENCODER_OPTIONS", ENCODER_string);
+ if(cline_size>0)ope_comments_add(inopt.comments, "ENCODER_OPTIONS", ENCODER_string);
if(strcmp(inFile, "-")==0){
#if defined WIN32 || defined _WIN32
@@ -669,52 +755,23 @@
chan=inopt.channels;
inopt.skip=0;
- /*In order to code the complete length we'll need to do a little padding*/
- setup_padder(&inopt,&original_samples);
-
- if(rate>24000)coding_rate=48000;
- else if(rate>16000)coding_rate=24000;
- else if(rate>12000)coding_rate=16000;
- else if(rate>8000)coding_rate=12000;
- else coding_rate=8000;
-
- frame_size=frame_size/(48000/coding_rate);
-
- /*Scale the resampler complexity, but only for 48000 output because
- the near-cutoff behavior matters a lot more at lower rates.*/
- if(rate!=coding_rate)setup_resample(&inopt,coding_rate==48000?(complexity+1)/2:5,coding_rate);
-
- if(rate!=coding_rate&&complexity!=10&&!quiet){
- fprintf(stderr,"Notice: Using resampling with complexity<10.\n");
- fprintf(stderr,"Opusenc is fastest with 48, 24, 16, 12, or 8kHz input.\n\n");
- }
-
- /*OggOpus headers*/ /*FIXME: broke forcemono*/
- header.channels=chan;
- header.channel_mapping=header.channels>8?255:chan>2;
- header.input_sample_rate=rate;
- header.gain=inopt.gain;
-
/*Initialize Opus encoder*/
- /*Frame sizes <10ms can only use the MDCT modes, so we switch on RESTRICTED_LOWDELAY
- to save the extra 4ms of codec lookahead when we'll be using only small frames.*/
- st=opus_multistream_surround_encoder_create(coding_rate, chan, header.channel_mapping, &header.nb_streams, &header.nb_coupled,
- header.stream_map, frame_size<480/(48000/coding_rate)?OPUS_APPLICATION_RESTRICTED_LOWDELAY:OPUS_APPLICATION_AUDIO, &ret);
- if(ret!=OPUS_OK){
- fprintf(stderr, "Error cannot create encoder: %s\n", opus_strerror(ret));
- exit(1);
+ enc = ope_encoder_create_callbacks(&callbacks, &data, inopt.comments, rate, chan, chan>8?255:chan>2, NULL);
+ ope_encoder_ctl(enc, OPE_SET_MUXING_DELAY(max_ogg_delay));
+ ope_encoder_ctl(enc, OPE_SET_SERIALNO(serialno));
+ ope_encoder_ctl(enc, OPE_SET_PACKET_CALLBACK(packet_callback, &data));
+ ope_encoder_ctl(enc, OPUS_SET_EXPERT_FRAME_DURATION(opus_frame_param));
+ ope_encoder_ctl(enc, OPE_SET_COMMENT_PADDING(comment_padding));
+ for(nb_streams=0;;nb_streams++){
+ OpusEncoder *oe;
+ ret=ope_encoder_ctl(enc,OPUS_MULTISTREAM_GET_ENCODER_STATE(nb_streams,&oe));
+ if (ret != 0 || oe == NULL) break;
}
+ nb_coupled = chan - nb_streams;
- min_bytes=max_frame_bytes=(1275*3+7)*header.nb_streams;
- packet=malloc(sizeof(unsigned char)*max_frame_bytes);
- if(packet==NULL){
- fprintf(stderr,"Error allocating packet buffer.\n");
- exit(1);
- }
-
if(bitrate<0){
/*Lower default rate for sampling rates [8000-44100) by a factor of (rate+16k)/(64k)*/
- bitrate=((64000*header.nb_streams+32000*header.nb_coupled)*
+ bitrate=((64000*nb_streams+32000*nb_coupled)*
(IMIN(48,IMAX(8,((rate<44100?rate:48000)+1000)/1000))+16)+32)>>6;
}
@@ -725,13 +782,13 @@
}
bitrate=IMIN(chan*256000,bitrate);
- ret=opus_multistream_encoder_ctl(st, OPUS_SET_BITRATE(bitrate));
+ ret = ope_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate));
if(ret!=OPUS_OK){
fprintf(stderr,"Error OPUS_SET_BITRATE returned: %s\n",opus_strerror(ret));
exit(1);
}
- ret=opus_multistream_encoder_ctl(st, OPUS_SET_VBR(!with_hard_cbr));
+ ret = ope_encoder_ctl(enc, OPUS_SET_VBR(!with_hard_cbr));
if(ret!=OPUS_OK){
fprintf(stderr,"Error OPUS_SET_VBR returned: %s\n",opus_strerror(ret));
exit(1);
@@ -738,7 +795,7 @@
}
if(!with_hard_cbr){
- ret=opus_multistream_encoder_ctl(st, OPUS_SET_VBR_CONSTRAINT(with_cvbr));
+ ret = ope_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(with_cvbr));
if(ret!=OPUS_OK){
fprintf(stderr,"Error OPUS_SET_VBR_CONSTRAINT returned: %s\n",opus_strerror(ret));
exit(1);
@@ -745,13 +802,13 @@
}
}
- ret=opus_multistream_encoder_ctl(st, OPUS_SET_COMPLEXITY(complexity));
+ ret = ope_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
if(ret!=OPUS_OK){
fprintf(stderr,"Error OPUS_SET_COMPLEXITY returned: %s\n",opus_strerror(ret));
exit(1);
}
- ret=opus_multistream_encoder_ctl(st, OPUS_SET_PACKET_LOSS_PERC(expect_loss));
+ ret = ope_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(expect_loss));
if(ret!=OPUS_OK){
fprintf(stderr,"Error OPUS_SET_PACKET_LOSS_PERC returned: %s\n",opus_strerror(ret));
exit(1);
@@ -758,7 +815,7 @@
}
#ifdef OPUS_SET_LSB_DEPTH
- ret=opus_multistream_encoder_ctl(st, OPUS_SET_LSB_DEPTH(IMAX(8,IMIN(24,inopt.samplesize))));
+ ret = ope_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(IMAX(8,IMIN(24,inopt.samplesize))));
if(ret!=OPUS_OK){
fprintf(stderr,"Warning OPUS_SET_LSB_DEPTH returned: %s\n",opus_strerror(ret));
}
@@ -768,14 +825,14 @@
for(i=0;i<opt_ctls;i++){
int target=opt_ctls_ctlval[i*3];
if(target==-1){
- ret=opus_multistream_encoder_ctl(st,opt_ctls_ctlval[i*3+1],opt_ctls_ctlval[i*3+2]);
+ ret = ope_encoder_ctl(enc, opt_ctls_ctlval[i*3+1],opt_ctls_ctlval[i*3+2]);
if(ret!=OPUS_OK){
fprintf(stderr,"Error opus_multistream_encoder_ctl(st,%d,%d) returned: %s\n",opt_ctls_ctlval[i*3+1],opt_ctls_ctlval[i*3+2],opus_strerror(ret));
exit(1);
}
- }else if(target<header.nb_streams){
+ }else if(target<nb_streams){
OpusEncoder *oe;
- opus_multistream_encoder_ctl(st,OPUS_MULTISTREAM_GET_ENCODER_STATE(target,&oe));
+ ope_encoder_ctl(enc, OPUS_MULTISTREAM_GET_ENCODER_STATE(target,&oe));
ret=opus_encoder_ctl(oe, opt_ctls_ctlval[i*3+1],opt_ctls_ctlval[i*3+2]);
if(ret!=OPUS_OK){
fprintf(stderr,"Error opus_encoder_ctl(st[%d],%d,%d) returned: %s\n",target,opt_ctls_ctlval[i*3+1],opt_ctls_ctlval[i*3+2],opus_strerror(ret));
@@ -782,28 +839,25 @@
exit(1);
}
}else{
- fprintf(stderr,"Error --set-ctl-int target stream %d is higher than the maximum stream number %d.\n",target,header.nb_streams-1);
+ fprintf(stderr,"Error --set-ctl-int target stream %d is higher than the maximum stream number %d.\n",target,nb_streams-1);
exit(1);
}
}
/*We do the lookahead check late so user CTLs can change it*/
- ret=opus_multistream_encoder_ctl(st, OPUS_GET_LOOKAHEAD(&lookahead));
+ ret = ope_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&lookahead));
if(ret!=OPUS_OK){
fprintf(stderr,"Error OPUS_GET_LOOKAHEAD returned: %s\n",opus_strerror(ret));
exit(1);
}
inopt.skip+=lookahead;
- /*Regardless of the rate we're coding at the ogg timestamping/skip is
- always timed at 48000.*/
- header.preskip=inopt.skip*(48000./coding_rate);
/* Extra samples that need to be read to compensate for the pre-skip */
- inopt.extraout=(int)header.preskip*(rate/48000.);
+ inopt.extraout=(int)lookahead*(rate/48000.);
if(!quiet){
int opus_app;
fprintf(stderr,"Encoding using %s",opus_version);
- opus_multistream_encoder_ctl(st,OPUS_GET_APPLICATION(&opus_app));
+ ope_encoder_ctl(enc, 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");
@@ -810,18 +864,18 @@
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 (",header.channels,header.channels<2?"":"s");
- if(header.nb_coupled>0)fprintf(stderr,"%d coupled",header.nb_coupled*2);
- if(header.nb_streams-header.nb_coupled>0)fprintf(stderr,
- "%s%d uncoupled",header.nb_coupled>0?", ":"",
- header.nb_streams-header.nb_coupled);
+ rate/1000.,chan,chan<2?"":"s");
+ fprintf(stderr," Output: %d channel%s (",chan,chan<2?"":"s");
+ if(nb_coupled>0)fprintf(stderr,"%d coupled",nb_coupled*2);
+ if(nb_streams-nb_coupled>0)fprintf(stderr,
+ "%s%d uncoupled",nb_coupled>0?", ":"",
+ nb_streams-nb_coupled);
fprintf(stderr,")\n %0.2gms packets, %0.6gkbit/sec%s\n",
- frame_size/(coding_rate/1000.), bitrate/1000.,
+ frame_size/(48000/1000.), bitrate/1000.,
with_hard_cbr?" CBR":with_cvbr?" CVBR":" VBR");
- fprintf(stderr," Preskip: %d\n",header.preskip);
+ fprintf(stderr," Preskip: %d\n",lookahead);
- if(frange!=NULL)fprintf(stderr," Writing final range file %s\n",range_file);
+ if(data.frange!=NULL)fprintf(stderr," Writing final range file %s\n",range_file);
fprintf(stderr,"\n");
}
@@ -829,72 +883,24 @@
#if defined WIN32 || defined _WIN32
_setmode(_fileno(stdout), _O_BINARY);
#endif
- fout=stdout;
+ data.fout=stdout;
}else{
- fout=fopen_utf8(outFile, "wb");
- if(!fout){
+ data.fout=fopen_utf8(outFile, "wb");
+ if(!data.fout){
perror(outFile);
exit(1);
}
}
+ data.enc = enc;
+ data.total_bytes = 0;
+ data.bytes_written = 0;
+ data.nb_encoded = 0;
+ data.packets_out = 0;
+ data.peak_bytes = 0;
+ data.min_bytes = 256*1275*6;
+ data.pages_out = 0;
+ data.last_length = 0;
- /*Initialize Ogg stream struct*/
- if(ogg_stream_init(&os, serialno)==-1){
- fprintf(stderr,"Error: stream init failed\n");
- exit(1);
- }
-
- /*Write header*/
- {
- /*The Identification Header is 19 bytes, plus a Channel Mapping Table for
- mapping families other than 0. The Channel Mapping Table is 2 bytes +
- 1 byte per channel. Because the maximum number of channels is 255, the
- maximum size of this header is 19 + 2 + 255 = 276 bytes.*/
- unsigned char header_data[276];
- int packet_size=opus_header_to_packet(&header, header_data, sizeof(header_data));
- 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((ret=ogg_stream_flush(&os, &og))){
- if(!ret)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++;
- }
-
- comment_pad(&inopt.comments, &inopt.comments_length, comment_padding);
- op.packet=(unsigned char *)inopt.comments;
- op.bytes=inopt.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((ret=ogg_stream_flush(&os, &og))){
- if(!ret)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(inopt.comments);
-
input=malloc(sizeof(float)*frame_size*chan);
if(input==NULL){
fprintf(stderr,"Error: couldn't allocate sample buffer.\n");
@@ -901,149 +907,37 @@
exit(1);
}
+ eos = 0;
/*Main encoding loop (one frame per iteration)*/
- nb_samples=-1;
- while(!op.e_o_s){
- int size_segments,cur_frame_size;
- id++;
+ while(!eos){
+ nb_samples = inopt.read_samples(inopt.readdata,input,frame_size);
+ total_samples+=nb_samples;
- if(nb_samples<0){
- nb_samples = inopt.read_samples(inopt.readdata,input,frame_size);
- total_samples+=nb_samples;
- }
-
+ ope_encoder_write_float(enc, input, nb_samples);
if(start_time==0){
start_time = time(NULL);
}
- cur_frame_size=frame_size;
+ if (nb_samples < frame_size) eos = 1;
- if(nb_samples<cur_frame_size){
- op.e_o_s=1;
- /*Avoid making the final packet 20ms or more longer than needed.*/
- cur_frame_size-=((cur_frame_size-(nb_samples>0?nb_samples:1))
- /(coding_rate/50))*(coding_rate/50);
- /*No fancy end padding, just fill with zeros for now.*/
- for(i=nb_samples*chan;i<cur_frame_size*chan;i++)input[i]=0;
- }
-
- /*Encode current frame*/
- VG_UNDEF(packet,max_frame_bytes);
- VG_CHECK(input,sizeof(float)*chan*cur_frame_size);
- nbBytes=opus_multistream_encode_float(st, input, cur_frame_size, packet, max_frame_bytes);
- if(nbBytes<0){
- fprintf(stderr, "Encoding failed: %s. Aborting.\n", opus_strerror(nbBytes));
- break;
- }
- VG_CHECK(packet,nbBytes);
- VG_UNDEF(input,sizeof(float)*chan*cur_frame_size);
- nb_encoded+=cur_frame_size;
- enc_granulepos+=cur_frame_size*48000/coding_rate;
- total_bytes+=nbBytes;
- size_segments=(nbBytes+255)/255;
- peak_bytes=IMAX(nbBytes,peak_bytes);
- min_bytes=IMIN(nbBytes,min_bytes);
-
- if(frange!=NULL){
- opus_uint32 rngs[256];
- OpusEncoder *oe;
- for(i=0;i<header.nb_streams;i++){
- ret=opus_multistream_encoder_ctl(st,OPUS_MULTISTREAM_GET_ENCODER_STATE(i,&oe));
- ret=opus_encoder_ctl(oe,OPUS_GET_FINAL_RANGE(&rngs[i]));
- }
- save_range(frange,cur_frame_size*(48000/coding_rate),packet,nbBytes,
- rngs,header.nb_streams);
- }
-
- /*Flush early if adding this packet would make us end up with a
- continued page which we wouldn't have otherwise.*/
- while((((size_segments<=255)&&(last_segments+size_segments>255))||
- (enc_granulepos-last_granulepos>max_ogg_delay))&&
-#ifdef OLD_LIBOGG
- ogg_stream_flush(&os, &og)){
-#else
- ogg_stream_flush_fill(&os, &og,255*255)){
-#endif
- if(ogg_page_packets(&og)!=0)last_granulepos=ogg_page_granulepos(&og);
- last_segments-=og.header[26];
- ret=oe_write_page(&og, fout);
- if(ret!=og.header_len+og.body_len){
- fprintf(stderr,"Error: failed writing data to output stream\n");
- exit(1);
- }
- bytes_written+=ret;
- pages_out++;
- }
-
- /*The downside of early reading is if the input is an exact
- multiple of the frame_size you'll get an extra frame that needs
- to get cropped off. The downside of late reading is added delay.
- If your ogg_delay is 120ms or less we'll assume you want the
- low delay behavior.*/
- if((!op.e_o_s)&&max_ogg_delay>5760){
- nb_samples = inopt.read_samples(inopt.readdata,input,frame_size);
- total_samples+=nb_samples;
- if(nb_samples==0)op.e_o_s=1;
- } else nb_samples=-1;
-
- op.packet=(unsigned char *)packet;
- op.bytes=nbBytes;
- op.b_o_s=0;
- op.granulepos=enc_granulepos;
- if(op.e_o_s){
- /*We compute the final GP as ceil(len*48k/input_rate)+preskip. When a
- resampling decoder does the matching floor((len-preskip)*input_rate/48k)
- conversion, the resulting output length will exactly equal the original
- input length when 0<input_rate<=48000.*/
- op.granulepos=((original_samples*48000+rate-1)/rate)+header.preskip;
- }
- op.packetno=2+id;
- ogg_stream_packetin(&os, &op);
- last_segments+=size_segments;
-
- /*If the stream is over or we're sure that the delayed flush will fire,
- go ahead and flush now to avoid adding delay.*/
- while((op.e_o_s||(enc_granulepos+(frame_size*48000/coding_rate)-last_granulepos>max_ogg_delay)||
- (last_segments>=255))?
-#ifdef OLD_LIBOGG
- /*Libogg > 1.2.2 allows us to achieve lower overhead by
- producing larger pages. For 20ms frames this is only relevant
- above ~32kbit/sec.*/
- ogg_stream_flush(&os, &og):
- ogg_stream_pageout(&os, &og)){
-#else
- ogg_stream_flush_fill(&os, &og,255*255):
- ogg_stream_pageout_fill(&os, &og,255*255)){
-#endif
- if(ogg_page_packets(&og)!=0)last_granulepos=ogg_page_granulepos(&og);
- last_segments-=og.header[26];
- ret=oe_write_page(&og, fout);
- if(ret!=og.header_len+og.body_len){
- fprintf(stderr,"Error: failed writing data to output stream\n");
- exit(1);
- }
- bytes_written+=ret;
- pages_out++;
- }
-
if(!quiet){
stop_time = time(NULL);
if(stop_time>last_spin){
double estbitrate;
- double coded_seconds=nb_encoded/(double)coding_rate;
+ double coded_seconds=data.nb_encoded/48000.;
double wall_time=(stop_time-start_time)+1e-6;
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+
+ estbitrate=(data.total_bytes*8.0/coded_seconds)*tweight+
bitrate*(1.-tweight);
- }else estbitrate=nbBytes*8*((double)coding_rate/frame_size);
+ }else estbitrate=data.last_length*8*(48000./frame_size);
fprintf(stderr,"\r");
for(i=0;i<last_spin_len;i++)fprintf(stderr," ");
- if(inopt.total_samples_per_channel>0 && nb_encoded<inopt.total_samples_per_channel){
+ if(inopt.total_samples_per_channel>0 && data.nb_encoded<inopt.total_samples_per_channel){
snprintf(sbuf,54,"\r[%c] %2d%% ",spinner[last_spin&3],
- (int)floor(nb_encoded/(double)(inopt.total_samples_per_channel+inopt.skip)*100.));
+ (int)floor(data.nb_encoded/(double)(inopt.total_samples_per_channel+lookahead)*100.));
}else{
snprintf(sbuf,54,"\r[%c] ",spinner[last_spin&3]);
}
@@ -1067,8 +961,10 @@
for(i=0;i<last_spin_len;i++)fprintf(stderr," ");
if(last_spin_len)fprintf(stderr,"\r");
+ ope_encoder_drain(enc);
+
if(!quiet){
- double coded_seconds=nb_encoded/(double)coding_rate;
+ double coded_seconds=data.nb_encoded/48000.;
double wall_time=(stop_time-start_time)+1e-6;
fprintf(stderr,"Encoding complete\n");
fprintf(stderr,"-----------------------------------------------------\n");
@@ -1077,129 +973,27 @@
fprintf(stderr,"\n Runtime:");
print_time(wall_time);
fprintf(stderr,"\n (%0.4gx realtime)\n",coded_seconds/wall_time);
- fprintf(stderr," Wrote: %" I64FORMAT " bytes, %d packets, %" I64FORMAT " pages\n",bytes_written,id+1,pages_out);
+ fprintf(stderr," Wrote: %" I64FORMAT " bytes, %" I64FORMAT " packets, %" I64FORMAT " pages\n",data.bytes_written,data.packets_out-1,data.pages_out);
fprintf(stderr," Bitrate: %0.6gkbit/s (without overhead)\n",
- total_bytes*8.0/(coded_seconds)/1000.0);
+ data.total_bytes*8.0/(coded_seconds)/1000.0);
fprintf(stderr," Instant rates: %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)bytes_written*100.);
-#ifdef OLD_LIBOGG
- if(max_ogg_delay>(frame_size*(48000/coding_rate)*4))fprintf(stderr," (use libogg 1.3 or later for lower overhead)\n");
-#endif
+ data.min_bytes*8*(48000./frame_size/1000.),
+ data.peak_bytes*8*(48000./frame_size/1000.),data.min_bytes,data.peak_bytes);
+ fprintf(stderr," Overhead: %0.3g%% (container+metadata)\n",(data.bytes_written-data.total_bytes)/(double)data.bytes_written*100.);
fprintf(stderr,"\n");
}
- opus_multistream_encoder_destroy(st);
- ogg_stream_clear(&os);
- free(packet);
+ ope_encoder_destroy(enc);
+ ope_comments_destroy(inopt.comments);
free(input);
if(opt_ctls)free(opt_ctls_ctlval);
- if(rate!=coding_rate)clear_resample(&inopt);
- clear_padder(&inopt);
if(downmix)clear_downmix(&inopt);
in_format->close_func(inopt.readdata);
if(fin)fclose(fin);
- if(fout)fclose(fout);
- if(frange)fclose(frange);
+ if(data.frange)fclose(data.frange);
#ifdef WIN_UNICODE
free_commandline_arguments_utf8(&argc_utf8, &argv_utf8);
#endif
return 0;
}
-
-/*
- Comments will be stored in the Vorbis style.
- It is described 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
- 3) [user_comment_list_length] = read an unsigned integer of 32 bits
- 4) iterate [user_comment_list_length] times {
- 5) [length] = read an unsigned integer of 32 bits
- 6) this iteration's user comment = read a UTF-8 vector as [length] octets
- }
- 7) done.
-*/
-
-#define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \
- ((buf[base+2]<<16)&0xff0000)| \
- ((buf[base+1]<<8)&0xff00)| \
- (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; \
- buf[base]=(val)&0xff; \
- }while(0)
-
-static void comment_init(char **comments, int* length, const char *vendor_string)
-{
- /*The 'vendor' field should be the actual encoding library used.*/
- int vendor_length=strlen(vendor_string);
- int user_comment_list_length=0;
- 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);
- }
- memcpy(p, "OpusTags", 8);
- writeint(p, 8, vendor_length);
- memcpy(p+12, vendor_string, vendor_length);
- writeint(p, 12+vendor_length, user_comment_list_length);
- *length=len;
- *comments=p;
-}
-
-void comment_add(char **comments, int* length, char *tag, char *val)
-{
- char* p=*comments;
- int vendor_length=readint(p, 8);
- int user_comment_list_length=readint(p, 8+4+vendor_length);
- int tag_len=(tag?strlen(tag)+1:0);
- int val_len=strlen(val);
- int len=(*length)+4+tag_len+val_len;
-
- p=(char*)realloc(p, len);
- if(p==NULL){
- fprintf(stderr, "realloc failed in comment_add()\n");
- exit(1);
- }
-
- writeint(p, *length, tag_len+val_len); /* length of comment */
- if(tag){
- memcpy(p+*length+4, tag, tag_len); /* comment tag */
- (p+*length+4)[tag_len-1] = '='; /* separator */
- }
- 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;
-}
-
-static void comment_pad(char **comments, int* length, int amount)
-{
- if(amount>0){
- int i;
- int newlen;
- char* p=*comments;
- /*Make sure there is at least amount worth of padding free, and
- round up to the maximum that fits in the current ogg segments.*/
- newlen=(*length+amount+255)/255*255-1;
- p=realloc(p,newlen);
- if(p==NULL){
- fprintf(stderr,"realloc failed in comment_pad()\n");
- exit(1);
- }
- for(i=*length;i<newlen;i++)p[i]=0;
- *comments=p;
- *length=newlen;
- }
-}
-#undef readint
-#undef writeint
--- a/src/opusenc.h
+++ /dev/null
@@ -1,109 +1,0 @@
-#ifndef __OPUSENC_H
-#define __OPUSENC_H
-
-#include <opus_types.h>
-#include <ogg/ogg.h>
-
-#ifdef ENABLE_NLS
-#include <libintl.h>
-#define _(X) gettext(X)
-#else
-#define _(X) (X)
-#define textdomain(X)
-#define bindtextdomain(X, Y)
-#endif
-#ifdef gettext_noop
-#define N_(X) gettext_noop(X)
-#else
-#define N_(X) (X)
-#endif
-
-typedef long (*audio_read_func)(void *src, float *buffer, int samples);
-
-typedef struct
-{
- audio_read_func read_samples;
- void *readdata;
- opus_int64 total_samples_per_channel;
- int rawmode;
- int channels;
- long rate;
- int gain;
- int samplesize;
- int endianness;
- char *infilename;
- int ignorelength;
- int skip;
- int extraout;
- char *comments;
- int comments_length;
- int copy_comments;
- int copy_pictures;
-} oe_enc_opt;
-
-void setup_scaler(oe_enc_opt *opt, float scale);
-void clear_scaler(oe_enc_opt *opt);
-void setup_padder(oe_enc_opt *opt, ogg_int64_t *original_samples);
-void clear_padder(oe_enc_opt *opt);
-int setup_downmix(oe_enc_opt *opt, int out_channels);
-void clear_downmix(oe_enc_opt *opt);
-void comment_add(char **comments, int* length, char *tag, char *val);
-
-typedef struct
-{
- int (*id_func)(unsigned char *buf, int len); /* Returns true if can load file */
- int id_data_len; /* Amount of data needed to id whether this can load the file */
- int (*open_func)(FILE *in, oe_enc_opt *opt, unsigned char *buf, int buflen);
- void (*close_func)(void *);
- char *format;
- char *description;
-} input_format;
-
-typedef struct {
- unsigned short format;
- unsigned short channels;
- unsigned int samplerate;
- unsigned int bytespersec;
- unsigned short align;
- unsigned short samplesize;
- unsigned int mask;
-} wav_fmt;
-
-typedef struct {
- unsigned short channels;
- short samplesize;
- opus_int64 totalsamples;
- opus_int64 samplesread;
- FILE *f;
- short bigendian;
- short unsigned8bit;
- int *channel_permute;
-} wavfile;
-
-typedef struct {
- short channels;
- unsigned int totalframes;
- short samplesize;
- double rate;
- unsigned int offset;
- unsigned int blocksize;
-} aiff_fmt;
-
-typedef wavfile aifffile; /* They're the same */
-
-input_format *open_audio_file(FILE *in, oe_enc_opt *opt);
-
-int raw_open(FILE *in, oe_enc_opt *opt, unsigned char *buf, int buflen);
-int wav_open(FILE *in, oe_enc_opt *opt, unsigned char *buf, int buflen);
-int aiff_open(FILE *in, oe_enc_opt *opt, unsigned char *buf, int buflen);
-int wav_id(unsigned char *buf, int len);
-int aiff_id(unsigned char *buf, int len);
-void wav_close(void *);
-void raw_close(void *);
-int setup_resample(oe_enc_opt *opt, int complexity, long outfreq);
-void clear_resample(oe_enc_opt *opt);
-
-long wav_read(void *, float *buffer, int samples);
-long wav_ieee_read(void *, float *buffer, int samples);
-
-#endif /* __OPUSENC_H */
--- a/src/picture.c
+++ b/src/picture.c
@@ -225,275 +225,3 @@
}
}
}
-
-#define IMAX(a,b) ((a) > (b) ? (a) : (b))
-
-/*Parse a picture SPECIFICATION as given on the command-line.
- spec: The specification.
- error_message: Returns an error message on error.
- seen_file_icons: Bit flags used to track if any pictures of type 1 or type 2
- have already been added, to ensure only one is allowed.
- Return: A Base64-encoded string suitable for use in a METADATA_BLOCK_PICTURE
- tag.*/
-char *parse_picture_specification(const char *spec,
- const char **error_message,
- int *seen_file_icons){
- FILE *picture_file;
- unsigned long picture_type;
- unsigned long width;
- unsigned long height;
- unsigned long depth;
- unsigned long colors;
- const char *mime_type;
- const char *mime_type_end;
- const char *description;
- const char *description_end;
- const char *filename;
- unsigned char *buf;
- char *out;
- size_t cbuf;
- size_t nbuf;
- size_t data_offset;
- size_t data_length;
- size_t b64_length;
- int is_url;
- /*If a filename has a '|' in it, there's no way we can distinguish it from a
- full specification just from the spec string.
- Instead, try to open the file.
- If it exists, the user probably meant the file.*/
- picture_type=3;
- width=height=depth=colors=0;
- mime_type=mime_type_end=description=description_end=filename=spec;
- is_url=0;
- picture_file=fopen(filename,"rb");
- if(picture_file==NULL&&strchr(spec,'|')){
- const char *p;
- char *q;
- /*We don't have a plain file, and there is a pipe character: assume it's
- the full form of the specification.*/
- picture_type=strtoul(spec,&q,10);
- if(*q!='|'||picture_type>20){
- *error_message="invalid picture type";
- return NULL;
- }
- if(picture_type>=1&&picture_type<=2&&(*seen_file_icons&picture_type)){
- *error_message=picture_type==1?
- "only one picture of type 1 (32x32 icon) allowed":
- "only one picture of type 2 (icon) allowed";
- return NULL;
- }
- /*An empty field implies a default of 'Cover (front)'.*/
- if(spec==q)picture_type=3;
- mime_type=q+1;
- mime_type_end=mime_type+strcspn(mime_type,"|");
- if(*mime_type_end!='|'){
- *error_message="invalid picture specification: not enough fields";
- return NULL;
- }
- /*The media type must be composed of ASCII printable characters 0x20-0x7E.*/
- for(p=mime_type;p<mime_type_end;p++)if(*p<0x20||*p>0x7E){
- *error_message="invalid characters in media type";
- return NULL;
- }
- is_url=mime_type_end-mime_type==3
- &&strncmp("-->",mime_type,mime_type_end-mime_type)==0;
- description=mime_type_end+1;
- description_end=description+strcspn(description,"|");
- if(*description_end!='|'){
- *error_message="invalid picture specification: not enough fields";
- return NULL;
- }
- p=description_end+1;
- if(*p!='|'){
- width=strtoul(p,&q,10);
- if(*q!='x'){
- *error_message=
- "invalid picture specification: can't parse resolution/color field";
- return NULL;
- }
- p=q+1;
- height=strtoul(p,&q,10);
- if(*q!='x'){
- *error_message=
- "invalid picture specification: can't parse resolution/color field";
- return NULL;
- }
- p=q+1;
- depth=strtoul(p,&q,10);
- if(*q=='/'){
- p=q+1;
- colors=strtoul(p,&q,10);
- }
- if(*q!='|'){
- *error_message=
- "invalid picture specification: can't parse resolution/color field";
- return NULL;
- }
- p=q;
- }
- filename=p+1;
- if(!is_url)picture_file=fopen(filename,"rb");
- }
- /*Buffer size: 8 static 4-byte fields plus 2 dynamic fields, plus the
- file/URL data.
- We reserve at least 10 bytes for the media type, in case we still need to
- extract it from the file.*/
- data_offset=32+(description_end-description)+IMAX(mime_type_end-mime_type,10);
- buf=NULL;
- if(is_url){
- /*Easy case: just stick the URL at the end.
- We don't do anything to verify it's a valid URL.*/
- data_length=strlen(filename);
- cbuf=nbuf=data_offset+data_length;
- buf=(unsigned char *)malloc(cbuf);
- memcpy(buf+data_offset,filename,data_length);
- }
- else{
- ogg_uint32_t file_width;
- ogg_uint32_t file_height;
- ogg_uint32_t file_depth;
- ogg_uint32_t file_colors;
- int has_palette;
- /*Complicated case: we have a real file.
- Read it in, attempt to parse the media type and image dimensions if
- necessary, and validate what the user passed in.*/
- if(picture_file==NULL){
- *error_message="error opening picture file";
- return NULL;
- }
- nbuf=data_offset;
- /*Add a reasonable starting image file size.*/
- cbuf=data_offset+65536;
- for(;;){
- unsigned char *new_buf;
- size_t nread;
- new_buf=realloc(buf,cbuf);
- if(new_buf==NULL){
- fclose(picture_file);
- free(buf);
- *error_message="insufficient memory";
- return NULL;
- }
- buf=new_buf;
- nread=fread(buf+nbuf,1,cbuf-nbuf,picture_file);
- nbuf+=nread;
- if(nbuf<cbuf){
- int error;
- error=ferror(picture_file);
- fclose(picture_file);
- if(error){
- free(buf);
- *error_message="error reading picture file";
- return NULL;
- }
- break;
- }
- if(cbuf==0xFFFFFFFF){
- fclose(picture_file);
- free(buf);
- *error_message="file too large";
- return NULL;
- }
- else if(cbuf>0x7FFFFFFFU)cbuf=0xFFFFFFFFU;
- else cbuf=cbuf<<1|1;
- }
- data_length=nbuf-data_offset;
- /*If there was no media type, try to extract it from the file data.*/
- if(mime_type_end==mime_type){
- if(is_jpeg(buf+data_offset,data_length)){
- mime_type="image/jpeg";
- mime_type_end=mime_type+10;
- }
- else if(is_png(buf+data_offset,data_length)){
- mime_type="image/png";
- mime_type_end=mime_type+9;
- }
- else if(is_gif(buf+data_offset,data_length)){
- mime_type="image/gif";
- mime_type_end=mime_type+9;
- }
- else{
- free(buf);
- *error_message="unable to guess media type from file, "
- "must set it explicitly";
- return NULL;
- }
- }
- /*Try to extract the image dimensions/color information from the file.*/
- file_width=file_height=file_depth=file_colors=0;
- has_palette=-1;
- if(mime_type_end-mime_type==9
- &&oi_strncasecmp("image/png",mime_type,mime_type_end-mime_type)==0){
- extract_png_params(buf+data_offset,data_length,
- &file_width,&file_height,&file_depth,&file_colors,&has_palette);
- }
- else if(mime_type_end-mime_type==9
- &&oi_strncasecmp("image/gif",mime_type,mime_type_end-mime_type)==0){
- extract_gif_params(buf+data_offset,data_length,
- &file_width,&file_height,&file_depth,&file_colors,&has_palette);
- }
- else if(mime_type_end-mime_type==10
- &&oi_strncasecmp("image/jpeg",mime_type,mime_type_end-mime_type)==0){
- extract_jpeg_params(buf+data_offset,data_length,
- &file_width,&file_height,&file_depth,&file_colors,&has_palette);
- }
- if(!width)width=file_width;
- if(!height)height=file_height;
- if(!depth)depth=file_depth;
- if(!colors)colors=file_colors;
- if((file_width&&width!=file_width)
- ||(file_height&&height!=file_height)
- ||(file_depth&&depth!=file_depth)
- /*We use has_palette to ensure we also reject non-0 user color counts for
- images we've positively identified as non-paletted.*/
- ||(has_palette>=0&&colors!=file_colors)){
- free(buf);
- *error_message="invalid picture specification: "
- "resolution/color field does not match file";
- return NULL;
- }
- }
- /*These fields MUST be set correctly OR all set to zero.
- So if any of them (except colors, for which 0 is a valid value) are still
- zero, clear the rest to zero.*/
- if(width==0||height==0||depth==0)width=height=depth=colors=0;
- if(picture_type==1&&(width!=32||height!=32
- ||mime_type_end-mime_type!=9
- ||oi_strncasecmp("image/png",mime_type,mime_type_end-mime_type)!=0)){
- free(buf);
- *error_message="pictures of type 1 MUST be 32x32 PNGs";
- return NULL;
- }
- /*Build the METADATA_BLOCK_PICTURE buffer.
- We do this backwards from data_offset, because we didn't necessarily know
- how big the media type string was before we read the data in.*/
- data_offset-=4;
- WRITE_U32_BE(buf+data_offset,(unsigned long)data_length);
- data_offset-=4;
- WRITE_U32_BE(buf+data_offset,colors);
- data_offset-=4;
- WRITE_U32_BE(buf+data_offset,depth);
- data_offset-=4;
- WRITE_U32_BE(buf+data_offset,height);
- data_offset-=4;
- WRITE_U32_BE(buf+data_offset,width);
- data_offset-=description_end-description;
- memcpy(buf+data_offset,description,description_end-description);
- data_offset-=4;
- WRITE_U32_BE(buf+data_offset,(unsigned long)(description_end-description));
- data_offset-=mime_type_end-mime_type;
- memcpy(buf+data_offset,mime_type,mime_type_end-mime_type);
- data_offset-=4;
- WRITE_U32_BE(buf+data_offset,(unsigned long)(mime_type_end-mime_type));
- data_offset-=4;
- WRITE_U32_BE(buf+data_offset,picture_type);
- data_length=nbuf-data_offset;
- b64_length=BASE64_LENGTH(data_length);
- out=(char *)malloc(b64_length+1);
- if(out!=NULL){
- base64_encode(out,(char *)buf+data_offset,data_length);
- if(picture_type>=1&&picture_type<=2)*seen_file_icons|=picture_type;
- }
- free(buf);
- return out;
-}
--- a/src/picture.h
+++ b/src/picture.h
@@ -34,10 +34,6 @@
ogg_uint32_t *depth, ogg_uint32_t *colors,
int *has_palette);
-char *parse_picture_specification(const char *spec,
- const char **error_message,
- int *seen_file_icons);
-
#define WRITE_U32_BE(buf, val) \
do{ \
(buf)[0]=(unsigned char)((val)>>24); \