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
159endif (NOT HAVE_SYS_SOUNDCARD_H)159endif (NOT HAVE_SYS_SOUNDCARD_H)
160optional(HAVE_WAVEAUDIO mmsystem.h winmm waveInGetDevCapsA waveaudio)160optional(HAVE_WAVEAUDIO mmsystem.h winmm waveInGetDevCapsA waveaudio)
161optional4(HAVE_OGG_VORBIS vorbis/codec.h ogg ogg_stream_flush vorbis vorbis_analysis_headerout vorbisfile ov_clear vorbisenc vorbis_encode_init_vbr vorbis)161optional4(HAVE_OGG_VORBIS vorbis/codec.h ogg ogg_stream_flush vorbis vorbis_analysis_headerout vorbisfile ov_clear vorbisenc vorbis_encode_init_vbr vorbis)
162optional3(HAVE_OPUS opusfile.h ogg ogg_stream_flush opus opus_encoder_create opusfile op_open_callbacks opus)
162optional(HAVE_WAVPACK wavpack/wavpack.h wavpack WavpackGetSampleRate wavpack)163optional(HAVE_WAVPACK wavpack/wavpack.h wavpack WavpackGetSampleRate wavpack)
163 164
164if (HAVE_LAME_LAME_H OR HAVE_MAD_H)165if (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
427 AC_CHECK_LIB(vorbisenc, vorbis_encode_init_vbr, OGG_VORBIS_LIBS="-lvorbisenc $OGG_VORBIS_LIBS", using_oggvorbis=no, $OGG_VORBIS_LIBS)],427 AC_CHECK_LIB(vorbisenc, vorbis_encode_init_vbr, OGG_VORBIS_LIBS="-lvorbisenc $OGG_VORBIS_LIBS", using_oggvorbis=no, $OGG_VORBIS_LIBS)],
428 using_oggvorbis=no)])428 using_oggvorbis=no)])
429 429
430# Check for Opus
431AC_OPTIONAL_FORMAT(opus, OPUS,
432 [PKG_CHECK_MODULES(OPUS, [opusfile], [], using_opus=no)],
433 using_opus=no)
434
430 435
431 436
432# Check for FLAC libraries437# Check for FLAC libraries
@@ -673,6 +678,7 @@ if test "x$using_twolame" = "xyes"; then · 240 unmodified lines
673echo " dlopen twolame............$enable_dl_twolame"678echo " dlopen twolame............$enable_dl_twolame"
674fi679fi
675echo "oggvorbis..................$using_oggvorbis"680echo "oggvorbis..................$using_oggvorbis"
681echo "opus.......................$using_opus"
676echo "sndfile....................$using_sndfile"682echo "sndfile....................$using_sndfile"
677if test "x$using_sndfile" = "xyes"; then683if test "x$using_sndfile" = "xyes"; then
678echo " dlopen sndfile............$enable_dl_sndfile"684echo " 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
57 CHECK(txw , 0, 0, "" , 0, 6, "LM8953")57 CHECK(txw , 0, 0, "" , 0, 6, "LM8953")
58 CHECK(sndt , 0, 0, "" , 0, 6, "SOUND\x1a")58 CHECK(sndt , 0, 0, "" , 0, 6, "SOUND\x1a")
59 CHECK(vorbis, 0, 4, "OggS" , 29, 6, "vorbis")59 CHECK(vorbis, 0, 4, "OggS" , 29, 6, "vorbis")
60 CHECK(opus , 0, 4, "OggS" , 28, 8, "OpusHead")
60 CHECK(speex , 0, 4, "OggS" , 28, 6, "Speex")61 CHECK(speex , 0, 4, "OggS" , 28, 6, "Speex")
61 CHECK(hcom ,65, 4, "FSSD" , 128,4, "HCOM")62 CHECK(hcom ,65, 4, "FSSD" , 128,4, "HCOM")
62 CHECK(wav , 0, 4, "RIFF" , 8, 4, "WAVE")63 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
142 {sox_encodings_lossy2, "AMR-NB" , "AMR-NB"},143 {sox_encodings_lossy2, "AMR-NB" , "AMR-NB"},
143 {sox_encodings_lossy2, "CVSD" , "CVSD"},144 {sox_encodings_lossy2, "CVSD" , "CVSD"},
144 {sox_encodings_lossy2, "LPC10" , "LPC10"},145 {sox_encodings_lossy2, "LPC10" , "LPC10"},
146 {sox_encodings_lossy2, "Opus" , "Opus"},
145};147};
146 148
147assert_static(array_length(s_sox_encodings_info) == SOX_ENCODINGS,149assert_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
182 184
183 case SOX_ENCODING_GSM:185 case SOX_ENCODING_GSM:
184 case SOX_ENCODING_VORBIS:186 case SOX_ENCODING_VORBIS:
187 case SOX_ENCODING_OPUS:
185 case SOX_ENCODING_AMR_WB:188 case SOX_ENCODING_AMR_WB:
186 case SOX_ENCODING_AMR_NB:189 case SOX_ENCODING_AMR_NB:
187 case SOX_ENCODING_LPC10: return !bits_per_sample? 16: 0;190 case SOX_ENCODING_LPC10: return !bits_per_sample? 16: 0;
src/formats.h+3−0
@@ -92,6 +92,9 @@ · 91 unmodified lines
92#if defined HAVE_MP3 && (defined STATIC_MP3 || !defined HAVE_LIBLTDL)92#if defined HAVE_MP3 && (defined STATIC_MP3 || !defined HAVE_LIBLTDL)
93 FORMAT(mp3)93 FORMAT(mp3)
94#endif94#endif
95#if defined HAVE_OPUS && (defined STATIC_OPUS || !defined HAVE_LIBLTDL)
96 FORMAT(opus)
97#endif
95#if defined HAVE_OSS && (defined STATIC_OSS || !defined HAVE_LIBLTDL)98#if defined HAVE_OSS && (defined STATIC_OSS || !defined HAVE_LIBLTDL)
96 FORMAT(oss)99 FORMAT(oss)
97#endif100#endif
src/optional-fmts.am+17−0
@@ -135,6 +135,23 @@ else · 134 unmodified lines
135endif135endif
136endif136endif
137 137
138if HAVE_OPUS
139if STATIC_OPUS
140 libsox_la_SOURCES += opus.c
141 libsox_la_CFLAGS += @OPUS_CFLAGS@ -Wno-long-long
142if STATIC_LIBSOX_ONLY
143 sox_LDADD += @OPUS_LIBS@
144else
145 libsox_la_LIBADD += @OPUS_LIBS@
146endif
147else
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
152endif
153endif
154
138if HAVE_OSS155if HAVE_OSS
139if STATIC_OSS156if STATIC_OSS
140 libsox_la_SOURCES += oss.c157 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
37typedef 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
50static 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
56static 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
66static int callback_close(void* ft_data UNUSED)
67{
68 /* Do nothing so sox can close the file for us */
69 return 0;
70}
71
72static 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 */
88static 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 */
144static 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
176static 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 */
208static 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
218static 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
225LSX_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
593 SOX_ENCODING_AMR_NB , /**< AMR-NB compression */593 SOX_ENCODING_AMR_NB , /**< AMR-NB compression */
594 SOX_ENCODING_CVSD , /**< Continuously Variable Slope Delta modulation */594 SOX_ENCODING_CVSD , /**< Continuously Variable Slope Delta modulation */
595 SOX_ENCODING_LPC10 , /**< Linear Predictive Coding */595 SOX_ENCODING_LPC10 , /**< Linear Predictive Coding */
596 SOX_ENCODING_OPUS , /**< Opus compression */
596 597
597 SOX_ENCODINGS /**< End of list marker */598 SOX_ENCODINGS /**< End of list marker */
598} sox_encoding_t;599} 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