1 /* libSoX Ogg Vorbis sound format handler
2 * Copyright 2001, Stan Seibert <indigo@aztec.asu.edu>
3 *
4 * Portions from oggenc, (c) Michael Smith <msmith@labyrinth.net.au>,
5 * ogg123, (c) Kenneth Arnold <kcarnold@yahoo.com>, and
6 * libvorbisfile (c) Xiphophorus Company
7 *
8 * May 9, 2001 - Stan Seibert (indigo@aztec.asu.edu)
9 * Ogg Vorbis handler initially written.
10 *
11 * July 5, 1991 - Skeleton file
12 * Copyright 1991 Lance Norskog And Sundry Contributors
13 * This source code is freely redistributable and may be used for
14 * any purpose. This copyright notice must be maintained.
15 * Lance Norskog And Sundry Contributors are not responsible for
16 * the consequences of using this software.
17 */
18
19 #include "sox_i.h"
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <errno.h>
24
25 #include <ogg/ogg.h>
26 #include <vorbis/codec.h>
27 #include <vorbis/vorbisfile.h>
28 #include <vorbis/vorbisenc.h>
29
30 #define DEF_BUF_LEN 4096
31
32 #define BUF_ERROR -1
33 #define BUF_EOF 0
34 #define BUF_DATA 1
35
36 #define HEADER_ERROR 0
37 #define HEADER_OK 1
38
39 /* Private data for Ogg Vorbis file */
40 typedef struct {
41 ogg_stream_state os;
42 ogg_page og;
43 ogg_packet op;
44
45 vorbis_dsp_state vd;
46 vorbis_block vb;
47 vorbis_info vi;
48 } vorbis_enc_t;
49
50 typedef struct {
51 /* Decoding data */
52 OggVorbis_File *vf;
53 char *buf;
54 size_t buf_len;
55 size_t start;
56 size_t end; /* Unsent data samples in buf[start] through buf[end-1] */
57 int current_section;
58 int eof;
59
60 vorbis_enc_t *vorbis_enc_data;
61 } priv_t;
62
63 /******** Callback functions used in ov_open_callbacks ************/
64
callback_read(void * ptr,size_t size,size_t nmemb,void * ft_data)65 static size_t callback_read(void* ptr, size_t size, size_t nmemb, void* ft_data)
66 {
67 sox_format_t* ft = (sox_format_t*)ft_data;
68 size_t ret = lsx_readbuf(ft, ptr, size * nmemb);
69 return ret / size;
70 }
71
callback_seek(void * ft_data,ogg_int64_t off,int whence)72 static int callback_seek(void* ft_data, ogg_int64_t off, int whence)
73 {
74 sox_format_t* ft = (sox_format_t*)ft_data;
75 int ret = ft->seekable ? lsx_seeki(ft, (off_t)off, whence) : -1;
76
77 if (ret == EBADF)
78 ret = -1;
79 return ret;
80 }
81
callback_close(void * ft_data UNUSED)82 static int callback_close(void* ft_data UNUSED)
83 {
84 /* Do nothing so sox can close the file for us */
85 return 0;
86 }
87
callback_tell(void * ft_data)88 static long callback_tell(void* ft_data)
89 {
90 sox_format_t* ft = (sox_format_t*)ft_data;
91 return lsx_tell(ft);
92 }
93
94 /********************* End callbacks *****************************/
95
96
97 /*
98 * Do anything required before you start reading samples.
99 * Read file header.
100 * Find out sampling rate,
101 * size and encoding of samples,
102 * mono/stereo/quad.
103 */
startread(sox_format_t * ft)104 static int startread(sox_format_t * ft)
105 {
106 priv_t * vb = (priv_t *) ft->priv;
107 vorbis_info *vi;
108 vorbis_comment *vc;
109 int i;
110
111 ov_callbacks callbacks = {
112 callback_read,
113 callback_seek,
114 callback_close,
115 callback_tell
116 };
117
118 /* Allocate space for decoding structure */
119 vb->vf = lsx_malloc(sizeof(OggVorbis_File));
120
121 /* Init the decoder */
122 if (ov_open_callbacks(ft, vb->vf, NULL, (size_t) 0, callbacks) < 0) {
123 lsx_fail_errno(ft, SOX_EHDR, "Input not an Ogg Vorbis audio stream");
124 return (SOX_EOF);
125 }
126
127 /* Get info about the Ogg Vorbis stream */
128 vi = ov_info(vb->vf, -1);
129 vc = ov_comment(vb->vf, -1);
130
131 /* Record audio info */
132 ft->signal.rate = vi->rate;
133 ft->encoding.encoding = SOX_ENCODING_VORBIS;
134 ft->signal.channels = vi->channels;
135
136 /* ov_pcm_total doesn't work on non-seekable files so
137 * skip that step in that case. Also, it reports
138 * "frame"-ish results so we must * channels.
139 */
140 if (ft->seekable)
141 ft->signal.length = ov_pcm_total(vb->vf, -1) * ft->signal.channels;
142
143 /* Record comments */
144 for (i = 0; i < vc->comments; i++)
145 sox_append_comment(&ft->oob.comments, vc->user_comments[i]);
146
147 /* Setup buffer */
148 vb->buf_len = DEF_BUF_LEN;
149 vb->buf_len -= vb->buf_len % (vi->channels*2); /* 2 bytes per sample */
150 vb->buf = lsx_calloc(vb->buf_len, sizeof(char));
151 vb->start = vb->end = 0;
152
153 /* Fill in other info */
154 vb->eof = 0;
155 vb->current_section = -1;
156
157 return (SOX_SUCCESS);
158 }
159
160
161 /* Refill the buffer with samples. Returns BUF_EOF if the end of the
162 * vorbis data was reached while the buffer was being filled,
163 * BUF_ERROR is something bad happens, and BUF_DATA otherwise */
refill_buffer(priv_t * vb)164 static int refill_buffer(priv_t * vb)
165 {
166 int num_read;
167
168 if (vb->start == vb->end) /* Samples all played */
169 vb->start = vb->end = 0;
170
171 while (vb->end < vb->buf_len) {
172 num_read = ov_read(vb->vf, vb->buf + vb->end,
173 (int) (vb->buf_len - vb->end), 0, 2, 1, &vb->current_section);
174 if (num_read == 0)
175 return (BUF_EOF);
176 else if (num_read == OV_HOLE)
177 lsx_warn("Warning: hole in stream; probably harmless");
178 else if (num_read < 0)
179 return (BUF_ERROR);
180 else
181 vb->end += num_read;
182 }
183 return (BUF_DATA);
184 }
185
186
187 /*
188 * Read up to len samples from file.
189 * Convert to signed longs.
190 * Place in buf[].
191 * Return number of samples read.
192 */
193
read_samples(sox_format_t * ft,sox_sample_t * buf,size_t len)194 static size_t read_samples(sox_format_t * ft, sox_sample_t * buf, size_t len)
195 {
196 priv_t * vb = (priv_t *) ft->priv;
197 size_t i;
198 int ret;
199 sox_sample_t l;
200
201
202 for (i = 0; i < len; i++) {
203 if (vb->start == vb->end) {
204 if (vb->eof)
205 break;
206 ret = refill_buffer(vb);
207 if (ret == BUF_EOF || ret == BUF_ERROR) {
208 vb->eof = 1;
209 if (vb->end == 0)
210 break;
211 }
212 }
213
214 l = (vb->buf[vb->start + 1] << 24)
215 | (0xffffff & (vb->buf[vb->start] << 16));
216 *(buf + i) = l;
217 vb->start += 2;
218 }
219 return i;
220 }
221
222 /*
223 * Do anything required when you stop reading samples.
224 * Don't close input file!
225 */
stopread(sox_format_t * ft)226 static int stopread(sox_format_t * ft)
227 {
228 priv_t * vb = (priv_t *) ft->priv;
229
230 free(vb->buf);
231 ov_clear(vb->vf);
232
233 return (SOX_SUCCESS);
234 }
235
236 /* Write a page of ogg data to a file. Taken directly from encode.c in
237 * oggenc. Returns the number of bytes written. */
oe_write_page(ogg_page * page,sox_format_t * ft)238 static int oe_write_page(ogg_page * page, sox_format_t * ft)
239 {
240 int written;
241
242 written = lsx_writebuf(ft, page->header, (size_t) page->header_len);
243 written += lsx_writebuf(ft, page->body, (size_t) page->body_len);
244
245 return written;
246 }
247
248 /* Write out the header packets. Derived mostly from encode.c in oggenc.
249 * Returns HEADER_OK if the header can be written, HEADER_ERROR otherwise. */
write_vorbis_header(sox_format_t * ft,vorbis_enc_t * ve)250 static int write_vorbis_header(sox_format_t * ft, vorbis_enc_t * ve)
251 {
252 ogg_packet header_main;
253 ogg_packet header_comments;
254 ogg_packet header_codebooks;
255 vorbis_comment vc;
256 int i, ret = HEADER_OK;
257
258 memset(&vc, 0, sizeof(vc));
259 vc.comments = sox_num_comments(ft->oob.comments);
260 if (vc.comments) { /* Make the comment structure */
261 vc.comment_lengths = lsx_calloc((size_t)vc.comments, sizeof(*vc.comment_lengths));
262 vc.user_comments = lsx_calloc((size_t)vc.comments, sizeof(*vc.user_comments));
263 for (i = 0; i < vc.comments; ++i) {
264 static const char prepend[] = "Comment=";
265 char * text = lsx_calloc(strlen(prepend) + strlen(ft->oob.comments[i]) + 1, sizeof(*text));
266 /* Prepend `Comment=' if no field-name already in the comment */
267 if (!strchr(ft->oob.comments[i], '='))
268 strcpy(text, prepend);
269 vc.user_comments[i] = strcat(text, ft->oob.comments[i]);
270 vc.comment_lengths[i] = strlen(text);
271 }
272 }
273 if (vorbis_analysis_headerout( /* Build the packets */
274 &ve->vd, &vc, &header_main, &header_comments, &header_codebooks) < 0) {
275 ret = HEADER_ERROR;
276 goto cleanup;
277 }
278
279 ogg_stream_packetin(&ve->os, &header_main); /* And stream them out */
280 ogg_stream_packetin(&ve->os, &header_comments);
281 ogg_stream_packetin(&ve->os, &header_codebooks);
282
283 while (ogg_stream_flush(&ve->os, &ve->og) && ret == HEADER_OK)
284 if (!oe_write_page(&ve->og, ft))
285 ret = HEADER_ERROR;
286 cleanup:
287 for (i = 0; i < vc.comments; ++i)
288 free(vc.user_comments[i]);
289 free(vc.user_comments);
290 free(vc.comment_lengths);
291 return ret;
292 }
293
startwrite(sox_format_t * ft)294 static int startwrite(sox_format_t * ft)
295 {
296 priv_t * vb = (priv_t *) ft->priv;
297 vorbis_enc_t *ve;
298 long rate;
299 double quality = 3; /* Default compression quality gives ~112kbps */
300
301 ft->encoding.encoding = SOX_ENCODING_VORBIS;
302
303 /* Allocate memory for all of the structures */
304 ve = vb->vorbis_enc_data = lsx_malloc(sizeof(vorbis_enc_t));
305
306 vorbis_info_init(&ve->vi);
307
308 /* TODO */
309 rate = ft->signal.rate;
310 if (rate)
311 lsx_fail_errno(ft, SOX_EHDR,
312 "Error setting-up Ogg Vorbis encoder; check sample-rate & # of channels");
313
314 /* Use encoding to average bit rate of VBR as specified by the -C option */
315 if (ft->encoding.compression != HUGE_VAL) {
316 if (ft->encoding.compression < -1 || ft->encoding.compression > 10) {
317 lsx_fail_errno(ft, SOX_EINVAL,
318 "Vorbis compression quality nust be between -1 and 10");
319 return SOX_EOF;
320 }
321 quality = ft->encoding.compression;
322 }
323
324 if (vorbis_encode_init_vbr(&ve->vi, ft->signal.channels, ft->signal.rate + .5, quality / 10))
325 {
326 lsx_fail_errno(ft, SOX_EFMT, "libVorbis cannot encode this sample-rate or # of channels");
327 return SOX_EOF;
328 }
329
330 vorbis_analysis_init(&ve->vd, &ve->vi);
331 vorbis_block_init(&ve->vd, &ve->vb);
332
333 ogg_stream_init(&ve->os, INT_MAX & (int)RANQD1); /* Random serial number */
334
335 if (write_vorbis_header(ft, ve) == HEADER_ERROR) {
336 lsx_fail_errno(ft, SOX_EHDR,
337 "Error writing header for Ogg Vorbis audio stream");
338 return (SOX_EOF);
339 }
340
341 return (SOX_SUCCESS);
342 }
343
write_samples(sox_format_t * ft,const sox_sample_t * buf,size_t len)344 static size_t write_samples(sox_format_t * ft, const sox_sample_t * buf,
345 size_t len)
346 {
347 priv_t * vb = (priv_t *) ft->priv;
348 vorbis_enc_t *ve = vb->vorbis_enc_data;
349 size_t samples = len / ft->signal.channels;
350 float **buffer = vorbis_analysis_buffer(&ve->vd, (int) samples);
351 size_t i, j;
352 int ret;
353 int eos = 0;
354
355 /* Copy samples into vorbis buffer */
356 for (i = 0; i < samples; i++)
357 for (j = 0; j < ft->signal.channels; j++)
358 buffer[j][i] = buf[i * ft->signal.channels + j]
359 / ((float) SOX_SAMPLE_MAX);
360
361 vorbis_analysis_wrote(&ve->vd, (int) samples);
362
363 while (vorbis_analysis_blockout(&ve->vd, &ve->vb) == 1) {
364 /* Do the main analysis, creating a packet */
365 vorbis_analysis(&ve->vb, &ve->op);
366 vorbis_bitrate_addblock(&ve->vb);
367
368 /* Add packet to bitstream */
369 while (vorbis_bitrate_flushpacket(&ve->vd, &ve->op)) {
370 ogg_stream_packetin(&ve->os, &ve->op);
371
372 /* If we've gone over a page boundary, we can do actual
373 * output, so do so (for however many pages are available)
374 */
375
376 while (!eos) {
377 int result = ogg_stream_pageout(&ve->os, &ve->og);
378
379 if (!result)
380 break;
381
382 ret = oe_write_page(&ve->og, ft);
383 if (!ret)
384 return 0;
385
386 if (ogg_page_eos(&ve->og))
387 eos = 1;
388 }
389 }
390 }
391
392 return (len);
393 }
394
stopwrite(sox_format_t * ft)395 static int stopwrite(sox_format_t * ft)
396 {
397 priv_t * vb = (priv_t *) ft->priv;
398 vorbis_enc_t *ve = vb->vorbis_enc_data;
399
400 /* Close out the remaining data */
401 write_samples(ft, NULL, (size_t) 0);
402
403 ogg_stream_clear(&ve->os);
404 vorbis_block_clear(&ve->vb);
405 vorbis_dsp_clear(&ve->vd);
406 vorbis_info_clear(&ve->vi);
407
408 return (SOX_SUCCESS);
409 }
410
seek(sox_format_t * ft,uint64_t offset)411 static int seek(sox_format_t * ft, uint64_t offset)
412 {
413 priv_t * vb = (priv_t *) ft->priv;
414
415 return ov_pcm_seek(vb->vf, (ogg_int64_t)(offset / ft->signal.channels))? SOX_EOF:SOX_SUCCESS;
416 }
417
LSX_FORMAT_HANDLER(vorbis)418 LSX_FORMAT_HANDLER(vorbis)
419 {
420 static const char *names[] = {"vorbis", "ogg", NULL};
421 static const unsigned encodings[] = {SOX_ENCODING_VORBIS, 0, 0};
422 static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE,
423 "Xiph.org's ogg-vorbis lossy compression", names, 0,
424 startread, read_samples, stopread,
425 startwrite, write_samples, stopwrite,
426 seek, encodings, NULL, sizeof(priv_t)
427 };
428 return &handler;
429 }
430