1 /* Copyright (C) 2005 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
3 /** \file oggdec_filter.c Paraslash's ogg vorbis decoder. */
6 #include <vorbis/vorbisfile.h>
11 #include "buffer_tree.h"
16 /** Determine byte sex. */
17 #ifdef WORDS_BIGENDIAN
23 /** Data specific to the oggdec filter. */
24 struct private_oggdec_data {
25 /** Describes an ogg vorbis file. */
27 /** The number of bytes consumed from the input buffer. */
29 /** The number of channels of the current stream. */
30 unsigned int channels;
31 /** Current sample rate in Hz. */
32 unsigned int sample_rate;
33 /** Whether everything was decoded during the previous iteration. */
37 static size_t cb_read(void *buf, size_t size, size_t nmemb, void *datasource)
39 struct filter_node *fn = datasource;
40 struct private_oggdec_data *pod = fn->private_data;
41 struct btr_node *btrn = fn->btrn;
43 size_t nbytes = btr_next_buffer(btrn, &btr_buf), tmp;
46 * oggvorbis always uses size == 1. Other sizes would complicate the code
47 * for no real gain. So we simply don't support size != 1.
50 assert(pod->converted <= nbytes);
51 tmp = nbytes - pod->converted;
52 PARA_DEBUG_LOG("vorbis requests %zu bytes have %zu\n", nmemb, tmp);
53 tmp = PARA_MIN(tmp, nmemb);
56 memcpy(buf, btr_buf + pod->converted, tmp);
57 pod->converted += tmp;
62 * Custom data seeking function.
64 * Since we want the data source to be treated as unseekable at all
65 * times, the provided seek callback always returns -1 (failure).
67 static int cb_seek(__a_unused void *datasource, __a_unused ogg_int64_t offset,
68 __a_unused int whence)
73 static int cb_close(__a_unused void *datasource)
78 static const ov_callbacks ovc = {
81 .close_func = cb_close,
83 * The tell function need not be provided if the data IO abstraction is
89 static void ogg_open(struct filter_node *fn)
91 fn->private_data = zalloc(sizeof(struct private_oggdec_data));
95 static void ogg_close(struct filter_node *fn)
97 struct private_oggdec_data *pod = fn->private_data;
100 PARA_DEBUG_LOG("ov_clearing %p, pod = %p\n", pod->vf, pod);
105 PARA_DEBUG_LOG("nothing to close\n");
107 fn->private_data = NULL;
110 static int oggdec_execute(struct btr_node *btrn, const char *cmd, char **result)
112 struct filter_node *fn = btr_context(btrn);
113 struct private_oggdec_data *pod = fn->private_data;
115 return decoder_execute(cmd, pod->sample_rate, pod->channels, result);
118 static int ogg_init(struct filter_node *fn)
120 struct private_oggdec_data *pod = fn->private_data;
121 struct btr_node *btrn = fn->btrn;
124 struct OggVorbis_File *vf = alloc(sizeof(*vf));
126 PARA_NOTICE_LOG("iqs: %zu, min_iqs: %zu, opening ov callbacks\n",
127 btr_get_input_queue_size(btrn), fn->min_iqs);
129 oret = ov_open_callbacks(fn, vf,
130 NULL, /* no initial buffer */
131 0, /* no initial bytes */
132 ovc); /* the ov_open_callbacks */
133 if (oret == OV_ENOTVORBIS || oret == OV_EBADHEADER) {
134 /* maybe the input buffer is too small */
135 if (!btr_no_parent(btrn)) {
137 iqs = btr_get_input_queue_size(btrn);
139 if (iqs < fn->min_iqs)
141 btr_merge(btrn, fn->min_iqs);
145 ret = (oret == OV_ENOTVORBIS)?
146 -E_OGGDEC_NOTVORBIS : -E_OGGDEC_BADHEADER;
149 ret = -E_OGGDEC_READ;
150 if (oret == OV_EREAD)
152 ret = -E_OGGDEC_VERSION;
153 if (oret == OV_EVERSION)
155 ret = -E_OGGDEC_FAULT;
158 pod->channels = ov_info(vf, 0)->channels;
159 pod->sample_rate = ov_info(vf, 0)->rate;
160 PARA_NOTICE_LOG("%u channels, %u Hz\n", pod->channels,
167 btr_consume(btrn, pod->converted);
171 pod->have_more = true;
176 /** Suspend decoding if output queue size is larger than that. */
177 #define OGGDEC_MAX_OUTPUT_SIZE (96 * 1024)
180 * Allocate chunks of this size and produce at most one chunk of output per
181 * ->post_monitor() invocation. If the buffer could only be filled partially
182 * due to insufficient input being available, it is shrunk to the real output
183 * size and the resized buffer is fed into the output queue.
185 #define OGGDEC_OUTPUT_CHUNK_SIZE (32 * 1024)
187 static void ogg_pre_monitor(struct sched *s, void *context)
189 struct filter_node *fn = context;
190 struct private_oggdec_data *pod = fn->private_data;
191 struct btr_node *btrn = fn->btrn;
194 ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
196 return sched_min_delay(s);
199 if (btr_get_output_queue_size(btrn) > OGGDEC_MAX_OUTPUT_SIZE)
204 static int ogg_post_monitor(__a_unused struct sched *s, void *context)
206 struct filter_node *fn = context;
207 struct private_oggdec_data *pod = fn->private_data;
208 struct btr_node *btrn = fn->btrn;
212 ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
214 if (ret != -E_EOF) /* fatal error */
216 if (fn->min_iqs == 0 && !pod->have_more) /* EOF */
218 /* last ov_read() returned OV_HOLE */
219 } else if (ret == 0 && !pod->have_more) /* nothing to do */
221 if (btr_get_output_queue_size(btrn) > OGGDEC_MAX_OUTPUT_SIZE)
226 btr_merge(btrn, fn->min_iqs);
231 buf = alloc(OGGDEC_OUTPUT_CHUNK_SIZE);
233 ret = ov_read(pod->vf, buf + have, OGGDEC_OUTPUT_CHUNK_SIZE - have,
234 ENDIAN, 2 /* 16 bit */, 1 /* signed */, NULL);
235 btr_consume(btrn, pod->converted);
241 if (have >= OGGDEC_OUTPUT_CHUNK_SIZE)
244 pod->have_more = (ret > 0);
246 if (have < OGGDEC_OUTPUT_CHUNK_SIZE)
247 buf = para_realloc(buf, have);
248 btr_add_output(buf, have, btrn);
251 if (ret == OV_HOLE) /* avoid buffer underruns */
253 if (ret >= 0 || ret == OV_HOLE)
255 ret = -E_OGGDEC_BADLINK;
258 btr_remove_node(&fn->btrn);
262 const struct filter lsg_filter_cmd_com_oggdec_user_data = {
265 .pre_monitor = ogg_pre_monitor,
266 .post_monitor = ogg_post_monitor,
267 .execute = oggdec_execute