ref: 703bedf7d34bf5dfeda0b81be73d155e1c8772a5
parent: e597e802903cc5f7c72e2efef1cbb166ea79b194
parent: f5b1ce0d612ba55c208fa9841d54f7cffc6fa314
author: Ulrich Klauer <ulrich@chirlu.de>
date: Thu Mar 7 22:14:18 EST 2013
Merge branch 'opus' Ogg Opus read support.
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -159,6 +159,7 @@
endif (NOT HAVE_SYS_SOUNDCARD_H)
optional(HAVE_WAVEAUDIO mmsystem.h winmm waveInGetDevCapsA waveaudio)
optional4(HAVE_OGG_VORBIS vorbis/codec.h ogg ogg_stream_flush vorbis vorbis_analysis_headerout vorbisfile ov_clear vorbisenc vorbis_encode_init_vbr vorbis)
+optional3(HAVE_OPUS opusfile.h ogg ogg_stream_flush opus opus_encoder_create opusfile op_open_callbacks opus)
optional(HAVE_WAVPACK wavpack/wavpack.h wavpack WavpackGetSampleRate wavpack)
if (HAVE_LAME_LAME_H OR HAVE_MAD_H)
--- a/ChangeLog
+++ b/ChangeLog
@@ -20,6 +20,10 @@
14.4.1 OpenMP < 3.0 OpenMP >= 3.0
14.4.1 F ffmpeg ffmpeg/avconv via pipe
+File formats:
+
+ o Add optional support for reading Ogg Opus files. (John Stumpo)
+
Effects:
o 'Deemph' can now also be used at 48kHz sample rate. (robs)
--- a/FEATURES.in
+++ b/FEATURES.in
@@ -21,6 +21,7 @@
* Amiga MAUD files
* AMR-WB & AMR-NB (with optional libamrwb & libamrnb libraries)
* MP2/MP3 (with optional libmad, libtwolame and libmp3lame libraries)
+* Opus files (read only; with optional Opus libraries)
(:cell:)
* Ogg Vorbis files (with optional Ogg Vorbis libraries)
* FLAC files (with optional libFLAC)
--- a/INSTALL
+++ b/INSTALL
@@ -30,6 +30,7 @@
MP3 ID3 tags http://www.underbit.com/products/mad GPL
Magic http://www.darwinsys.com/file BSD
Ogg Vorbis http://www.vorbis.com BSD
+Opus http://www.opus-codec.org/ BSD
PNG http://www.libpng.org/pub/png zlib (BSD-like)
Sndfile http://www.mega-nerd.com/libsndfile LGPL
WavPack http://www.wavpack.com BSD
--- a/configure.ac
+++ b/configure.ac
@@ -427,6 +427,13 @@
AC_CHECK_LIB(vorbisenc, vorbis_encode_init_vbr, OGG_VORBIS_LIBS="-lvorbisenc $OGG_VORBIS_LIBS", using_oggvorbis=no, $OGG_VORBIS_LIBS)],
using_oggvorbis=no)])
+# Check for Opus
+AC_OPTIONAL_FORMAT(opus, OPUS,
+ [PKG_CHECK_MODULES(OPUS, [opusfile], [], using_opus=no)],
+ using_opus=no)
+if test "$GCC" = "yes"; then
+ OPUS_CFLAGS="$OPUS_CFLAGS -Wno-long-long"
+fi
# Check for FLAC libraries
@@ -673,6 +680,7 @@
echo " dlopen twolame............$enable_dl_twolame"
fi
echo "oggvorbis..................$using_oggvorbis"
+echo "opus.......................$using_opus"
echo "sndfile....................$using_sndfile"
if test "x$using_sndfile" = "xyes"; then
echo " dlopen sndfile............$enable_dl_sndfile"
--- a/soxformat.7
+++ b/soxformat.7
@@ -478,6 +478,12 @@
.B .mp3
for a similar format.
.TP
+\&\fB.opus\fR (optional)
+Xiph.org's Opus compressed audio; an open, lossy, low-latency codec
+offering a wide range of compression rates. It uses the Ogg container.
+.SP
+SoX can only read Opus files, not write them.
+.TP
\fBoss\fR (optional)
Open Sound System /dev/dsp device driver; supports both playing and
recording audio. OSS support is available in Unix-like operating systems,
--- a/src/formats.c
+++ b/src/formats.c
@@ -57,6 +57,7 @@
CHECK(txw , 0, 0, "" , 0, 6, "LM8953")
CHECK(sndt , 0, 0, "" , 0, 6, "SOUND\x1a")
CHECK(vorbis, 0, 4, "OggS" , 29, 6, "vorbis")
+ CHECK(opus , 0, 4, "OggS" , 28, 8, "OpusHead")
CHECK(speex , 0, 4, "OggS" , 28, 6, "Speex")
CHECK(hcom ,65, 4, "FSSD" , 128,4, "HCOM")
CHECK(wav , 0, 4, "RIFF" , 8, 4, "WAVE")
@@ -142,6 +143,7 @@
{sox_encodings_lossy2, "AMR-NB" , "AMR-NB"},
{sox_encodings_lossy2, "CVSD" , "CVSD"},
{sox_encodings_lossy2, "LPC10" , "LPC10"},
+ {sox_encodings_lossy2, "Opus" , "Opus"},
};
assert_static(array_length(s_sox_encodings_info) == SOX_ENCODINGS,
@@ -182,6 +184,7 @@
case SOX_ENCODING_GSM:
case SOX_ENCODING_VORBIS:
+ case SOX_ENCODING_OPUS:
case SOX_ENCODING_AMR_WB:
case SOX_ENCODING_AMR_NB:
case SOX_ENCODING_LPC10: return !bits_per_sample? 16: 0;
--- a/src/formats.h
+++ b/src/formats.h
@@ -92,6 +92,9 @@
#if defined HAVE_MP3 && (defined STATIC_MP3 || !defined HAVE_LIBLTDL)
FORMAT(mp3)
#endif
+#if defined HAVE_OPUS && (defined STATIC_OPUS || !defined HAVE_LIBLTDL)
+ FORMAT(opus)
+#endif
#if defined HAVE_OSS && (defined STATIC_OSS || !defined HAVE_LIBLTDL)
FORMAT(oss)
#endif
--- a/src/optional-fmts.am
+++ b/src/optional-fmts.am
@@ -135,6 +135,23 @@
endif
endif
+if HAVE_OPUS
+if STATIC_OPUS
+ libsox_la_SOURCES += opus.c
+ libsox_la_CFLAGS += @OPUS_CFLAGS@
+if STATIC_LIBSOX_ONLY
+ sox_LDADD += @OPUS_LIBS@
+else
+ libsox_la_LIBADD += @OPUS_LIBS@
+endif
+else
+ libsox_fmt_opus_la_SOURCES = opus.c
+ libsox_fmt_opus_la_CFLAGS = @OPUS_CFLAGS@
+ libsox_fmt_opus_la_LIBADD = libsox.la @OPUS_LIBS@
+ pkglib_LTLIBRARIES += libsox_fmt_opus.la
+endif
+endif
+
if HAVE_OSS
if STATIC_OSS
libsox_la_SOURCES += oss.c
--- /dev/null
+++ b/src/opus.c
@@ -1,0 +1,235 @@
+/* libSoX Opus-in-Ogg sound format handler
+ * Copyright (C) 2013 John Stumpo <stump@jstump.com>
+ *
+ * Largely based on vorbis.c:
+ * libSoX Ogg Vorbis sound format handler
+ * Copyright 2001, Stan Seibert <indigo@aztec.asu.edu>
+ *
+ * Portions from oggenc, (c) Michael Smith <msmith@labyrinth.net.au>,
+ * ogg123, (c) Kenneth Arnold <kcarnold@yahoo.com>, and
+ * libvorbisfile (c) Xiphophorus Company
+ *
+ * May 9, 2001 - Stan Seibert (indigo@aztec.asu.edu)
+ * Ogg Vorbis handler initially written.
+ *
+ * July 5, 1991 - Skeleton file
+ * Copyright 1991 Lance Norskog And Sundry Contributors
+ * This source code is freely redistributable and may be used for
+ * any purpose. This copyright notice must be maintained.
+ * Lance Norskog And Sundry Contributors are not responsible for
+ * the consequences of using this software.
+ */
+
+#include "sox_i.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <opusfile.h>
+
+#define DEF_BUF_LEN 4096
+
+#define BUF_ERROR -1
+#define BUF_EOF 0
+#define BUF_DATA 1
+
+typedef struct {
+ /* Decoding data */
+ OggOpusFile *of;
+ char *buf;
+ size_t buf_len;
+ size_t start;
+ size_t end; /* Unsent data samples in buf[start] through buf[end-1] */
+ int current_section;
+ int eof;
+} priv_t;
+
+/******** Callback functions used in op_open_callbacks ************/
+
+static int callback_read(void* ft_data, unsigned char* ptr, int nbytes)
+{
+ sox_format_t* ft = (sox_format_t*)ft_data;
+ return lsx_readbuf(ft, ptr, (size_t)nbytes);
+}
+
+static int callback_seek(void* ft_data, opus_int64 off, int whence)
+{
+ sox_format_t* ft = (sox_format_t*)ft_data;
+ int ret = ft->seekable ? lsx_seeki(ft, (off_t)off, whence) : -1;
+
+ if (ret == EBADF)
+ ret = -1;
+ return ret;
+}
+
+static int callback_close(void* ft_data UNUSED)
+{
+ /* Do nothing so sox can close the file for us */
+ return 0;
+}
+
+static opus_int64 callback_tell(void* ft_data)
+{
+ sox_format_t* ft = (sox_format_t*)ft_data;
+ return lsx_tell(ft);
+}
+
+/********************* End callbacks *****************************/
+
+
+/*
+ * Do anything required before you start reading samples.
+ * Read file header.
+ * Find out sampling rate,
+ * size and encoding of samples,
+ * mono/stereo/quad.
+ */
+static int startread(sox_format_t * ft)
+{
+ priv_t * vb = (priv_t *) ft->priv;
+ const OpusTags *ot;
+ int i;
+
+ OpusFileCallbacks callbacks = {
+ callback_read,
+ callback_seek,
+ callback_tell,
+ callback_close
+ };
+
+ /* Init the decoder */
+ vb->of = op_open_callbacks(ft, &callbacks, NULL, (size_t) 0, NULL);
+ if (vb->of == NULL) {
+ lsx_fail_errno(ft, SOX_EHDR, "Input not an Ogg Opus audio stream");
+ return (SOX_EOF);
+ }
+
+ /* Get info about the Opus stream */
+ ot = op_tags(vb->of, -1);
+
+ /* Record audio info */
+ ft->signal.rate = 48000; /* libopusfile always uses 48 kHz */
+ ft->encoding.encoding = SOX_ENCODING_OPUS;
+ ft->signal.channels = op_channel_count(vb->of, -1);
+
+ /* op_pcm_total doesn't work on non-seekable files so
+ * skip that step in that case. Also, it reports
+ * "frame"-ish results so we must * channels.
+ */
+ if (ft->seekable)
+ ft->signal.length = op_pcm_total(vb->of, -1) * ft->signal.channels;
+
+ /* Record comments */
+ for (i = 0; i < ot->comments; i++)
+ sox_append_comment(&ft->oob.comments, ot->user_comments[i]);
+
+ /* Setup buffer */
+ vb->buf_len = DEF_BUF_LEN;
+ vb->buf_len -= vb->buf_len % (ft->signal.channels*2); /* 2 bytes per sample */
+ vb->buf = lsx_calloc(vb->buf_len, sizeof(char));
+ vb->start = vb->end = 0;
+
+ /* Fill in other info */
+ vb->eof = 0;
+ vb->current_section = -1;
+
+ return (SOX_SUCCESS);
+}
+
+
+/* Refill the buffer with samples. Returns BUF_EOF if the end of the
+ * Opus data was reached while the buffer was being filled,
+ * BUF_ERROR is something bad happens, and BUF_DATA otherwise */
+static int refill_buffer(sox_format_t * ft)
+{
+ priv_t * vb = (priv_t *) ft->priv;
+ int num_read;
+
+ if (vb->start == vb->end) /* Samples all played */
+ vb->start = vb->end = 0;
+
+ while (vb->end < vb->buf_len) {
+ num_read = op_read(vb->of, (opus_int16*) (vb->buf + vb->end),
+ (int) ((vb->buf_len - vb->end) / sizeof(opus_int16)),
+ &vb->current_section);
+ if (num_read == 0)
+ return (BUF_EOF);
+ else if (num_read == OP_HOLE)
+ lsx_warn("Warning: hole in stream; probably harmless");
+ else if (num_read < 0)
+ return (BUF_ERROR);
+ else
+ vb->end += num_read * sizeof(opus_int16) * ft->signal.channels;
+ }
+ return (BUF_DATA);
+}
+
+
+/*
+ * Read up to len samples from file.
+ * Convert to signed longs.
+ * Place in buf[].
+ * Return number of samples read.
+ */
+
+static size_t read_samples(sox_format_t * ft, sox_sample_t * buf, size_t len)
+{
+ priv_t * vb = (priv_t *) ft->priv;
+ size_t i;
+ int ret;
+ sox_sample_t l;
+
+
+ for (i = 0; i < len; i++) {
+ if (vb->start == vb->end) {
+ if (vb->eof)
+ break;
+ ret = refill_buffer(ft);
+ if (ret == BUF_EOF || ret == BUF_ERROR) {
+ vb->eof = 1;
+ if (vb->end == 0)
+ break;
+ }
+ }
+
+ l = (vb->buf[vb->start + 1] << 24)
+ | (0xffffff & (vb->buf[vb->start] << 16));
+ *(buf + i) = l;
+ vb->start += 2;
+ }
+ return i;
+}
+
+/*
+ * Do anything required when you stop reading samples.
+ * Don't close input file!
+ */
+static int stopread(sox_format_t * ft)
+{
+ priv_t * vb = (priv_t *) ft->priv;
+
+ free(vb->buf);
+ op_free(vb->of);
+
+ return (SOX_SUCCESS);
+}
+
+static int seek(sox_format_t * ft, uint64_t offset)
+{
+ priv_t * vb = (priv_t *) ft->priv;
+
+ return op_pcm_seek(vb->of, (opus_int64)(offset / ft->signal.channels))? SOX_EOF:SOX_SUCCESS;
+}
+
+LSX_FORMAT_HANDLER(opus)
+{
+ static const char *const names[] = {"opus", NULL};
+ static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE,
+ "Xiph.org's Opus lossy compression", names, 0,
+ startread, read_samples, stopread,
+ NULL, NULL, NULL,
+ seek, NULL, NULL, sizeof(priv_t)
+ };
+ return &handler;
+}
--- a/src/sox.h
+++ b/src/sox.h
@@ -593,6 +593,7 @@
SOX_ENCODING_AMR_NB , /**< AMR-NB compression */
SOX_ENCODING_CVSD , /**< Continuously Variable Slope Delta modulation */
SOX_ENCODING_LPC10 , /**< Linear Predictive Coding */
+ SOX_ENCODING_OPUS , /**< Opus compression */
SOX_ENCODINGS /**< End of list marker */
} sox_encoding_t;