History

Add read-only Opus support using libopusfile.

John Stumpo committed 13 years ago

Commit 9fd6eee1 parent e597e807 files · +266 −0Browse files

Unified · Split

7 files
  1. CMakeLists.txt +1 −0
  2. configure.ac +6 −0
  3. src/formats.c +3 −0
  4. src/formats.h +3 −0
  5. src/optional-fmts.am +17 −0
  6. src/opus.c +235 −0
  7. src/sox.h +1 −0
CMakeLists.txt+1−0
@@ -159,6 +159,7 @@ if (NOT HAVE_SYS_SOUNDCARD_H) · 158 unmodified lines
159159 endif (NOT HAVE_SYS_SOUNDCARD_H)
160160 optional(HAVE_WAVEAUDIO mmsystem.h winmm waveInGetDevCapsA waveaudio)
161161 optional4(HAVE_OGG_VORBIS vorbis/codec.h ogg ogg_stream_flush vorbis vorbis_analysis_headerout vorbisfile ov_clear vorbisenc vorbis_encode_init_vbr vorbis)
162+optional3(HAVE_OPUS opusfile.h ogg ogg_stream_flush opus opus_encoder_create opusfile op_open_callbacks opus)
162163 optional(HAVE_WAVPACK wavpack/wavpack.h wavpack WavpackGetSampleRate wavpack)
163164
164165 if (HAVE_LAME_LAME_H OR HAVE_MAD_H)
configure.ac+6−0
@@ -427,6 +427,11 @@ AC_OPTIONAL_FORMAT(oggvorbis, OGG_VORBIS, [AC_CHECK_HEADER(vorbis/codec.h, · 426 unmodified lines
427427 AC_CHECK_LIB(vorbisenc, vorbis_encode_init_vbr, OGG_VORBIS_LIBS="-lvorbisenc $OGG_VORBIS_LIBS", using_oggvorbis=no, $OGG_VORBIS_LIBS)],
428428 using_oggvorbis=no)])
429429
430+# Check for Opus
431+AC_OPTIONAL_FORMAT(opus, OPUS,
432+ [PKG_CHECK_MODULES(OPUS, [opusfile], [], using_opus=no)],
433+ using_opus=no)
434+
430435
431436
432437 # Check for FLAC libraries
@@ -673,6 +678,7 @@ if test "x$using_twolame" = "xyes"; then · 240 unmodified lines
673678 echo " dlopen twolame............$enable_dl_twolame"
674679 fi
675680 echo "oggvorbis..................$using_oggvorbis"
681+echo "opus.......................$using_opus"
676682 echo "sndfile....................$using_sndfile"
677683 if test "x$using_sndfile" = "xyes"; then
678684 echo " dlopen sndfile............$enable_dl_sndfile"
src/formats.c+3−0
@@ -57,6 +57,7 @@ static char const * auto_detect_format(sox_format_t * ft, char const * ext) · 56 unmodified lines
5757 CHECK(txw , 0, 0, "" , 0, 6, "LM8953")
5858 CHECK(sndt , 0, 0, "" , 0, 6, "SOUND\x1a")
5959 CHECK(vorbis, 0, 4, "OggS" , 29, 6, "vorbis")
60+ CHECK(opus , 0, 4, "OggS" , 28, 8, "OpusHead")
6061 CHECK(speex , 0, 4, "OggS" , 28, 6, "Speex")
6162 CHECK(hcom ,65, 4, "FSSD" , 128,4, "HCOM")
6263 CHECK(wav , 0, 4, "RIFF" , 8, 4, "WAVE")
@@ -142,6 +143,7 @@ static sox_encodings_info_t const s_sox_encodings_info[] = { · 79 unmodified lines
142143 {sox_encodings_lossy2, "AMR-NB" , "AMR-NB"},
143144 {sox_encodings_lossy2, "CVSD" , "CVSD"},
144145 {sox_encodings_lossy2, "LPC10" , "LPC10"},
146+ {sox_encodings_lossy2, "Opus" , "Opus"},
145147 };
146148
147149 assert_static(array_length(s_sox_encodings_info) == SOX_ENCODINGS,
@@ -182,6 +184,7 @@ unsigned sox_precision(sox_encoding_t encoding, unsigned bits_per_sample) · 34 unmodified lines
182184
183185 case SOX_ENCODING_GSM:
184186 case SOX_ENCODING_VORBIS:
187+ case SOX_ENCODING_OPUS:
185188 case SOX_ENCODING_AMR_WB:
186189 case SOX_ENCODING_AMR_NB:
187190 case SOX_ENCODING_LPC10: return !bits_per_sample? 16: 0;
src/formats.h+3−0
@@ -92,6 +92,9 @@ · 91 unmodified lines
9292 #if defined HAVE_MP3 && (defined STATIC_MP3 || !defined HAVE_LIBLTDL)
9393 FORMAT(mp3)
9494 #endif
95+#if defined HAVE_OPUS && (defined STATIC_OPUS || !defined HAVE_LIBLTDL)
96+ FORMAT(opus)
97+#endif
9598 #if defined HAVE_OSS && (defined STATIC_OSS || !defined HAVE_LIBLTDL)
9699 FORMAT(oss)
97100 #endif
src/optional-fmts.am+17−0
@@ -135,6 +135,23 @@ else · 134 unmodified lines
135135 endif
136136 endif
137137
138+if HAVE_OPUS
139+if STATIC_OPUS
140+ libsox_la_SOURCES += opus.c
141+ libsox_la_CFLAGS += @OPUS_CFLAGS@ -Wno-long-long
142+if STATIC_LIBSOX_ONLY
143+ sox_LDADD += @OPUS_LIBS@
144+else
145+ libsox_la_LIBADD += @OPUS_LIBS@
146+endif
147+else
148+ libsox_fmt_opus_la_SOURCES = opus.c
149+ libsox_fmt_opus_la_CFLAGS = @OPUS_CFLAGS@ -Wno-long-long
150+ libsox_fmt_opus_la_LIBADD = libsox.la @OPUS_LIBS@
151+ pkglib_LTLIBRARIES += libsox_fmt_opus.la
152+endif
153+endif
154+
138155 if HAVE_OSS
139156 if STATIC_OSS
140157 libsox_la_SOURCES += oss.c
src/opus.c+235−0
@@ -0,0 +1,235 @@
1+/* libSoX Opus-in-Ogg sound format handler
2+ * Copyright (C) 2013 John Stumpo <stump@jstump.com>
3+ *
4+ * Largely based on vorbis.c:
5+ * libSoX Ogg Vorbis sound format handler
6+ * Copyright 2001, Stan Seibert <indigo@aztec.asu.edu>
7+ *
8+ * Portions from oggenc, (c) Michael Smith <msmith@labyrinth.net.au>,
9+ * ogg123, (c) Kenneth Arnold <kcarnold@yahoo.com>, and
10+ * libvorbisfile (c) Xiphophorus Company
11+ *
12+ * May 9, 2001 - Stan Seibert (indigo@aztec.asu.edu)
13+ * Ogg Vorbis handler initially written.
14+ *
15+ * July 5, 1991 - Skeleton file
16+ * Copyright 1991 Lance Norskog And Sundry Contributors
17+ * This source code is freely redistributable and may be used for
18+ * any purpose. This copyright notice must be maintained.
19+ * Lance Norskog And Sundry Contributors are not responsible for
20+ * the consequences of using this software.
21+ */
22+
23+#include "sox_i.h"
24+
25+#include <stdio.h>
26+#include <string.h>
27+#include <errno.h>
28+
29+#include <opusfile.h>
30+
31+#define DEF_BUF_LEN 4096
32+
33+#define BUF_ERROR -1
34+#define BUF_EOF 0
35+#define BUF_DATA 1
36+
37+typedef struct {
38+ /* Decoding data */
39+ OggOpusFile *of;
40+ char *buf;
41+ size_t buf_len;
42+ size_t start;
43+ size_t end; /* Unsent data samples in buf[start] through buf[end-1] */
44+ int current_section;
45+ int eof;
46+} priv_t;
47+
48+/******** Callback functions used in op_open_callbacks ************/
49+
50+static int callback_read(void* ft_data, unsigned char* ptr, int nbytes)
51+{
52+ sox_format_t* ft = (sox_format_t*)ft_data;
53+ return lsx_readbuf(ft, ptr, (size_t)nbytes);
54+}
55+
56+static int callback_seek(void* ft_data, opus_int64 off, int whence)
57+{
58+ sox_format_t* ft = (sox_format_t*)ft_data;
59+ int ret = ft->seekable ? lsx_seeki(ft, (off_t)off, whence) : -1;
60+
61+ if (ret == EBADF)
62+ ret = -1;
63+ return ret;
64+}
65+
66+static int callback_close(void* ft_data UNUSED)
67+{
68+ /* Do nothing so sox can close the file for us */
69+ return 0;
70+}
71+
72+static opus_int64 callback_tell(void* ft_data)
73+{
74+ sox_format_t* ft = (sox_format_t*)ft_data;
75+ return lsx_tell(ft);
76+}
77+
78+/********************* End callbacks *****************************/
79+
80+
81+/*
82+ * Do anything required before you start reading samples.
83+ * Read file header.
84+ * Find out sampling rate,
85+ * size and encoding of samples,
86+ * mono/stereo/quad.
87+ */
88+static int startread(sox_format_t * ft)
89+{
90+ priv_t * vb = (priv_t *) ft->priv;
91+ const OpusTags *ot;
92+ int i;
93+
94+ OpusFileCallbacks callbacks = {
95+ callback_read,
96+ callback_seek,
97+ callback_tell,
98+ callback_close
99+ };
100+
101+ /* Init the decoder */
102+ vb->of = op_open_callbacks(ft, &callbacks, NULL, (size_t) 0, NULL);
103+ if (vb->of == NULL) {
104+ lsx_fail_errno(ft, SOX_EHDR, "Input not an Ogg Opus audio stream");
105+ return (SOX_EOF);
106+ }
107+
108+ /* Get info about the Opus stream */
109+ ot = op_tags(vb->of, -1);
110+
111+ /* Record audio info */
112+ ft->signal.rate = 48000; /* libopusfile always uses 48 kHz */
113+ ft->encoding.encoding = SOX_ENCODING_OPUS;
114+ ft->signal.channels = op_channel_count(vb->of, -1);
115+
116+ /* op_pcm_total doesn't work on non-seekable files so
117+ * skip that step in that case. Also, it reports
118+ * "frame"-ish results so we must * channels.
119+ */
120+ if (ft->seekable)
121+ ft->signal.length = op_pcm_total(vb->of, -1) * ft->signal.channels;
122+
123+ /* Record comments */
124+ for (i = 0; i < ot->comments; i++)
125+ sox_append_comment(&ft->oob.comments, ot->user_comments[i]);
126+
127+ /* Setup buffer */
128+ vb->buf_len = DEF_BUF_LEN;
129+ vb->buf_len -= vb->buf_len % (ft->signal.channels*2); /* 2 bytes per sample */
130+ vb->buf = lsx_calloc(vb->buf_len, sizeof(char));
131+ vb->start = vb->end = 0;
132+
133+ /* Fill in other info */
134+ vb->eof = 0;
135+ vb->current_section = -1;
136+
137+ return (SOX_SUCCESS);
138+}
139+
140+
141+/* Refill the buffer with samples. Returns BUF_EOF if the end of the
142+ * Opus data was reached while the buffer was being filled,
143+ * BUF_ERROR is something bad happens, and BUF_DATA otherwise */
144+static int refill_buffer(sox_format_t * ft)
145+{
146+ priv_t * vb = (priv_t *) ft->priv;
147+ int num_read;
148+
149+ if (vb->start == vb->end) /* Samples all played */
150+ vb->start = vb->end = 0;
151+
152+ while (vb->end < vb->buf_len) {
153+ num_read = op_read(vb->of, (opus_int16*) (vb->buf + vb->end),
154+ (int) ((vb->buf_len - vb->end) / sizeof(opus_int16)),
155+ &vb->current_section);
156+ if (num_read == 0)
157+ return (BUF_EOF);
158+ else if (num_read == OP_HOLE)
159+ lsx_warn("Warning: hole in stream; probably harmless");
160+ else if (num_read < 0)
161+ return (BUF_ERROR);
162+ else
163+ vb->end += num_read * sizeof(opus_int16) * ft->signal.channels;
164+ }
165+ return (BUF_DATA);
166+}
167+
168+
169+/*
170+ * Read up to len samples from file.
171+ * Convert to signed longs.
172+ * Place in buf[].
173+ * Return number of samples read.
174+ */
175+
176+static size_t read_samples(sox_format_t * ft, sox_sample_t * buf, size_t len)
177+{
178+ priv_t * vb = (priv_t *) ft->priv;
179+ size_t i;
180+ int ret;
181+ sox_sample_t l;
182+
183+
184+ for (i = 0; i < len; i++) {
185+ if (vb->start == vb->end) {
186+ if (vb->eof)
187+ break;
188+ ret = refill_buffer(ft);
189+ if (ret == BUF_EOF || ret == BUF_ERROR) {
190+ vb->eof = 1;
191+ if (vb->end == 0)
192+ break;
193+ }
194+ }
195+
196+ l = (vb->buf[vb->start + 1] << 24)
197+ | (0xffffff & (vb->buf[vb->start] << 16));
198+ *(buf + i) = l;
199+ vb->start += 2;
200+ }
201+ return i;
202+}
203+
204+/*
205+ * Do anything required when you stop reading samples.
206+ * Don't close input file!
207+ */
208+static int stopread(sox_format_t * ft)
209+{
210+ priv_t * vb = (priv_t *) ft->priv;
211+
212+ free(vb->buf);
213+ op_free(vb->of);
214+
215+ return (SOX_SUCCESS);
216+}
217+
218+static int seek(sox_format_t * ft, uint64_t offset)
219+{
220+ priv_t * vb = (priv_t *) ft->priv;
221+
222+ return op_pcm_seek(vb->of, (opus_int64)(offset / ft->signal.channels))? SOX_EOF:SOX_SUCCESS;
223+}
224+
225+LSX_FORMAT_HANDLER(opus)
226+{
227+ static const char *const names[] = {"opus", NULL};
228+ static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE,
229+ "Xiph.org's Opus lossy compression", names, 0,
230+ startread, read_samples, stopread,
231+ NULL, NULL, NULL,
232+ seek, NULL, NULL, sizeof(priv_t)
233+ };
234+ return &handler;
235+}
src/sox.h+1−0
@@ -593,6 +593,7 @@ typedef enum sox_encoding_t { · 592 unmodified lines
593593 SOX_ENCODING_AMR_NB , /**< AMR-NB compression */
594594 SOX_ENCODING_CVSD , /**< Continuously Variable Slope Delta modulation */
595595 SOX_ENCODING_LPC10 , /**< Linear Predictive Coding */
596+ SOX_ENCODING_OPUS , /**< Opus compression */
596597
597598 SOX_ENCODINGS /**< End of list marker */
598599 } sox_encoding_t;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t