1 /* libSoX Opus-in-Ogg sound format handler
2 * Copyright (C) 2013 John Stumpo <stump@jstump.com>
4 * Largely based on vorbis.c:
5 * libSoX Ogg Vorbis sound format handler
6 * Copyright 2001, Stan Seibert <indigo@aztec.asu.edu>
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
12 * May 9, 2001 - Stan Seibert (indigo@aztec.asu.edu)
13 * Ogg Vorbis handler initially written.
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.
31 #define DEF_BUF_LEN 4096
43 size_t end
; /* Unsent data samples in buf[start] through buf[end-1] */
48 /******** Callback functions used in op_open_callbacks ************/
50 static int callback_read(void* ft_data
, unsigned char* ptr
, int nbytes
)
52 sox_format_t
* ft
= (sox_format_t
*)ft_data
;
53 return lsx_readbuf(ft
, ptr
, (size_t)nbytes
);
56 static int callback_seek(void* ft_data
, opus_int64 off
, int whence
)
58 sox_format_t
* ft
= (sox_format_t
*)ft_data
;
59 int ret
= ft
->seekable
? lsx_seeki(ft
, (off_t
)off
, whence
) : -1;
66 static int callback_close(void* ft_data UNUSED
)
68 /* Do nothing so sox can close the file for us */
72 static opus_int64
callback_tell(void* ft_data
)
74 sox_format_t
* ft
= (sox_format_t
*)ft_data
;
78 /********************* End callbacks *****************************/
82 * Do anything required before you start reading samples.
84 * Find out sampling rate,
85 * size and encoding of samples,
88 static int startread(sox_format_t
* ft
)
90 priv_t
* vb
= (priv_t
*) ft
->priv
;
94 OpusFileCallbacks callbacks
= {
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");
108 /* Get info about the Opus stream */
109 ot
= op_tags(vb
->of
, -1);
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);
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.
121 ft
->signal
.length
= op_pcm_total(vb
->of
, -1) * ft
->signal
.channels
;
123 /* Record comments */
124 for (i
= 0; i
< ot
->comments
; i
++)
125 sox_append_comment(&ft
->oob
.comments
, ot
->user_comments
[i
]);
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;
133 /* Fill in other info */
135 vb
->current_section
= -1;
137 return (SOX_SUCCESS
);
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
)
146 priv_t
* vb
= (priv_t
*) ft
->priv
;
149 if (vb
->start
== vb
->end
) /* Samples all played */
150 vb
->start
= vb
->end
= 0;
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
);
158 else if (num_read
== OP_HOLE
)
159 lsx_warn("Warning: hole in stream; probably harmless");
160 else if (num_read
< 0)
163 vb
->end
+= num_read
* sizeof(opus_int16
) * ft
->signal
.channels
;
170 * Read up to len samples from file.
171 * Convert to signed longs.
173 * Return number of samples read.
176 static size_t read_samples(sox_format_t
* ft
, sox_sample_t
* buf
, size_t len
)
178 priv_t
* vb
= (priv_t
*) ft
->priv
;
184 for (i
= 0; i
< len
; i
++) {
185 if (vb
->start
== vb
->end
) {
188 ret
= refill_buffer(ft
);
189 if (ret
== BUF_EOF
|| ret
== BUF_ERROR
) {
196 l
= (vb
->buf
[vb
->start
+ 1] << 24)
197 | (0xffffff & (vb
->buf
[vb
->start
] << 16));
205 * Do anything required when you stop reading samples.
206 * Don't close input file!
208 static int stopread(sox_format_t
* ft
)
210 priv_t
* vb
= (priv_t
*) ft
->priv
;
215 return (SOX_SUCCESS
);
218 static int seek(sox_format_t
* ft
, uint64_t offset
)
220 priv_t
* vb
= (priv_t
*) ft
->priv
;
222 return op_pcm_seek(vb
->of
, (opus_int64
)(offset
/ ft
->signal
.channels
))? SOX_EOF
:SOX_SUCCESS
;
225 LSX_FORMAT_HANDLER(opus
)
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
,
232 seek
, NULL
, NULL
, sizeof(priv_t
)