2 * Copyright (C) 2005-2006 Andre Noll <maan@systemlinux.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
19 /** \file oggdec.c paraslash's ogg vorbis decoder */
23 #include "oggdec_filter.cmdline.h"
30 #include <vorbis/vorbisfile.h>
32 /** \cond some internal constants */
38 /** data specific to the oggdec filter */
39 struct private_oggdec_data
{
40 /** describes an ogg vorbis file */
42 /** the input buffer */
44 /** the length of \a inbuf */
46 /** the number of bytes consumed from the input buffer */
50 static size_t cb_read(void *buf
, size_t size
, size_t nmemb
, void *datasource
)
52 struct filter_node
*fn
= datasource
;
53 struct private_oggdec_data
*pod
= fn
->private_data
;
54 size_t ret
, have
= pod
->inbuf_len
- pod
->converted
;
55 char *p
= pod
->inbuf
+ pod
->converted
;
57 // PARA_DEBUG_LOG("pod = %p\n", pod);
58 // PARA_DEBUG_LOG("vorbis requests %d bytes, have %d\n", size * nmemb, have);
59 if (pod
->inbuf_len
< size
) {
60 if (*fn
->fc
->reader_eof
)
65 ret
= PARA_MIN(nmemb
, have
/ size
) * size
;
67 pod
->converted
+= ret
;
72 * cb_seek -- custom data seeking function
73 * Since we want the data source to be treated as unseekable at all
74 * times, the provided seek callback always returns -1 (failure).
76 static int cb_seek(__a_unused
void *datasource
, __a_unused ogg_int64_t offset
,
77 __a_unused
int whence
)
82 static int cb_close(__a_unused
void *datasource
)
87 static const ov_callbacks ovc
= {
90 .close_func
= cb_close
,
92 * The tell function need not be provided if
93 * the data IO abstraction is not seekable
98 static void ogg_open(struct filter_node
*fn
)
100 struct private_oggdec_data
*pod
= para_calloc(
101 sizeof(struct private_oggdec_data
));
102 struct oggdec_filter_args_info
*conf
= fn
->conf
;
104 fn
->private_data
= pod
;
105 fn
->bufsize
= conf
->bufsize_arg
* 1024;
106 fn
->buf
= para_malloc(fn
->bufsize
);
109 static void ogg_close(struct filter_node
*fn
)
111 struct private_oggdec_data
*pod
= fn
->private_data
;
113 PARA_DEBUG_LOG("ov_clearing %p, pod = %p\n", pod
->vf
, pod
);
118 PARA_DEBUG_LOG("nothing to close in fc %p, pod = %p\n", pod
->vf
, pod
);
121 free(fn
->private_data
);
122 fn
->private_data
= NULL
;
125 static ssize_t
ogg_convert(char *inbuffer
, size_t len
, struct filter_node
*fn
)
128 struct private_oggdec_data
*pod
= fn
->private_data
;
129 struct oggdec_filter_args_info
*conf
= fn
->conf
;
130 /* make the buffer known to the read callback cb_read() */
131 pod
->inbuf
= inbuffer
;
132 pod
->inbuf_len
= len
;
136 int ib
= 1024 * conf
->initial_buffer_arg
; /* initial buffer */
137 if (len
<ib
&& !*fn
->fc
->reader_eof
) {
138 PARA_INFO_LOG("initial input buffer %zd/%d, waiting for more data\n",
142 pod
->vf
= para_malloc(sizeof(struct OggVorbis_File
));
143 PARA_NOTICE_LOG("input buffer: %zd, opening ov callbacks\n", len
);
144 ret
= ov_open_callbacks(fn
, pod
->vf
,
145 NULL
, /* no initial buffer */
146 0, /* no initial bytes */
147 ovc
); /* the ov_open_callbacks */
149 return -E_OGGDEC_READ
;
150 if (ret
== OV_ENOTVORBIS
)
151 return -E_OGGDEC_NOTVORBIS
;
152 if (ret
== OV_EVERSION
)
153 return -E_OGGDEC_VERSION
;
154 if (ret
== OV_EBADHEADER
)
155 return -E_OGGDEC_BADHEADER
;
157 return -E_OGGDEC_FAULT
;
158 fn
->fc
->channels
= ov_info(pod
->vf
, 0)->channels
;
159 fn
->fc
->samplerate
= ov_info(pod
->vf
, 0)->rate
;
160 PARA_NOTICE_LOG("%d channels, %d Hz\n", fn
->fc
->channels
, fn
->fc
->samplerate
);
163 ret
= ov_read(pod
->vf
, fn
->buf
+ fn
->loaded
, fn
->bufsize
- fn
->loaded
,
164 ENDIAN
, BITS
/ 8, SIGN
, NULL
);
165 if (ret
== OV_HOLE
|| !ret
) {
166 return pod
->converted
;
169 return -E_OGGDEC_BADLINK
;
171 if (!*fn
->fc
->reader_eof
&& fn
->loaded
< fn
->bufsize
)
173 return pod
->converted
;
176 static void *oggdec_parse_config(int argc
, char **argv
)
178 struct oggdec_filter_args_info
*ret
= para_calloc(sizeof(struct oggdec_filter_args_info
));
179 if (!oggdec_cmdline_parser(argc
, argv
, ret
))
185 /** the init function of the ogg vorbis decoder */
186 void oggdec_init(struct filter
*f
)
189 f
->close
= ogg_close
;
190 f
->convert
= ogg_convert
;
191 f
->print_help
= oggdec_cmdline_parser_print_help
;
192 f
->parse_config
= oggdec_parse_config
;