id3: fix COMM frame handling
[sox.git] / src / opus.c
blob49fa74be95a3900867d5d2cb61ddaf2b8754e4ea
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.
23 #include "sox_i.h"
25 #include <stdio.h>
26 #include <string.h>
27 #include <errno.h>
29 #include <opusfile.h>
31 #define DEF_BUF_LEN 4096
33 #define BUF_ERROR -1
34 #define BUF_EOF 0
35 #define BUF_DATA 1
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;
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;
61 if (ret == EBADF)
62 ret = -1;
63 return ret;
66 static int callback_close(void* ft_data UNUSED)
68 /* Do nothing so sox can close the file for us */
69 return 0;
72 static opus_int64 callback_tell(void* ft_data)
74 sox_format_t* ft = (sox_format_t*)ft_data;
75 return lsx_tell(ft);
78 /********************* End callbacks *****************************/
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.
88 static int startread(sox_format_t * ft)
90 priv_t * vb = (priv_t *) ft->priv;
91 const OpusTags *ot;
92 int i;
94 OpusFileCallbacks callbacks = {
95 callback_read,
96 callback_seek,
97 callback_tell,
98 callback_close
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);
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.
120 if (ft->seekable)
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]);
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;
133 /* Fill in other info */
134 vb->eof = 0;
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;
147 int num_read;
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);
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;
165 return (BUF_DATA);
170 * Read up to len samples from file.
171 * Convert to signed longs.
172 * Place in buf[].
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;
179 size_t i;
180 int ret;
181 sox_sample_t l;
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;
196 l = (vb->buf[vb->start + 1] << 24)
197 | (0xffffff & (vb->buf[vb->start] << 16));
198 *(buf + i) = l;
199 vb->start += 2;
201 return i;
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;
212 free(vb->buf);
213 op_free(vb->of);
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,
231 NULL, NULL, NULL,
232 seek, NULL, NULL, sizeof(priv_t)
234 return &handler;