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 }
236