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