2 * Copyright 2004-2005 Timo Hirvonen
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * 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
22 #include "read_wrapper.h"
24 #include "config/tremor.h"
27 #include <tremor/ivorbisfile.h>
29 #include <vorbis/vorbisfile.h>
34 #include <sys/types.h>
37 struct vorbis_private
{
42 /* http://www.xiph.org/vorbis/doc/vorbisfile/callbacks.html */
44 static size_t read_func(void *ptr
, size_t size
, size_t nmemb
, void *datasource
)
46 struct input_plugin_data
*ip_data
= datasource
;
49 rc
= read_wrapper(ip_data
, ptr
, size
* nmemb
);
51 d_print("error: %s\n", strerror(errno
));
61 static int seek_func(void *datasource
, ogg_int64_t offset
, int whence
)
63 struct input_plugin_data
*ip_data
= datasource
;
66 rc
= lseek(ip_data
->fd
, offset
, whence
);
72 static int close_func(void *datasource
)
74 struct input_plugin_data
*ip_data
= datasource
;
77 rc
= close(ip_data
->fd
);
82 static long tell_func(void *datasource
)
84 struct input_plugin_data
*ip_data
= datasource
;
87 rc
= lseek(ip_data
->fd
, 0, SEEK_CUR
);
93 * size_t (*read_func) (void *ptr, size_t size, size_t nmemb, void *datasource);
94 * int (*seek_func) (void *datasource, ogg_int64_t offset, int whence);
95 * int (*close_func) (void *datasource);
96 * long (*tell_func) (void *datasource);
99 static ov_callbacks callbacks
= {
100 .read_func
= read_func
,
101 .seek_func
= seek_func
,
102 .close_func
= close_func
,
103 .tell_func
= tell_func
106 static int vorbis_open(struct input_plugin_data
*ip_data
)
108 struct vorbis_private
*priv
;
112 priv
= xnew(struct vorbis_private
, 1);
113 priv
->current_section
= 0;
114 memset(&priv
->vf
, 0, sizeof(priv
->vf
));
116 rc
= ov_open_callbacks(ip_data
, &priv
->vf
, NULL
, 0, callbacks
);
118 d_print("ov_open failed: %d\n", rc
);
120 return -IP_ERROR_FILE_FORMAT
;
122 ip_data
->private = priv
;
124 vi
= ov_info(&priv
->vf
, -1);
125 ip_data
->sf
= sf_rate(vi
->rate
) | sf_channels(vi
->channels
) | sf_bits(16) | sf_signed(1);
129 static int vorbis_close(struct input_plugin_data
*ip_data
)
131 struct vorbis_private
*priv
;
134 priv
= ip_data
->private;
135 /* this closes ip_data->fd! */
136 rc
= ov_clear(&priv
->vf
);
139 d_print("ov_clear returned %d\n", rc
);
141 ip_data
->private = NULL
;
147 * indicates there was an interruption in the data.
148 * (one of: garbage between pages, loss of sync followed by recapture,
151 * indicates that an invalid stream section was supplied to libvorbisfile,
152 * or the requested link is corrupt.
156 * indicates actual number of bytes read. ov_read() will decode at most
157 * one vorbis packet per invocation, so the value returned will generally
158 * be less than length.
160 static int vorbis_read(struct input_plugin_data
*ip_data
, char *buffer
, int count
)
162 struct vorbis_private
*priv
;
165 priv
= ip_data
->private;
167 /* Tremor can only handle signed 16 bit data */
168 rc
= ov_read(&priv
->vf
, buffer
, count
, &priv
->current_section
);
170 rc
= ov_read(&priv
->vf
, buffer
, count
, 0, 2, 1, &priv
->current_section
);
184 d_print("error: %s\n", strerror(errno
));
186 /* return -IP_ERROR_INTERNAL; */
192 d_print("error: %d\n", rc
);
193 rc
= -IP_ERROR_FILE_FORMAT
;
199 static int vorbis_seek(struct input_plugin_data
*ip_data
, double offset
)
201 struct vorbis_private
*priv
;
204 priv
= ip_data
->private;
207 rc
= ov_time_seek(&priv
->vf
, offset
* 1000);
209 rc
= ov_time_seek(&priv
->vf
, offset
);
213 return -IP_ERROR_FUNCTION_NOT_SUPPORTED
;
215 return -IP_ERROR_INTERNAL
;
217 return -IP_ERROR_INTERNAL
;
219 return -IP_ERROR_INTERNAL
;
221 return -IP_ERROR_INTERNAL
;
226 static int vorbis_read_comments(struct input_plugin_data
*ip_data
,
227 struct keyval
**comments
)
230 struct vorbis_private
*priv
;
234 priv
= ip_data
->private;
235 vc
= ov_comment(&priv
->vf
, -1);
237 d_print("vc == NULL\n");
238 *comments
= xnew0(struct keyval
, 1);
241 for (i
= 0; i
< vc
->comments
; i
++) {
242 const char *str
= vc
->user_comments
[i
];
243 const char *eq
= strchr(str
, '=');
247 d_print("invalid comment: '%s' ('=' expected)\n", str
);
251 key
= xstrndup(str
, eq
- str
);
252 comments_add_const(&c
, key
, eq
+ 1);
255 keyvals_terminate(&c
);
256 *comments
= c
.keyvals
;
260 static int vorbis_duration(struct input_plugin_data
*ip_data
)
262 struct vorbis_private
*priv
;
265 priv
= ip_data
->private;
266 duration
= ov_time_total(&priv
->vf
, -1);
267 if (duration
== OV_EINVAL
)
268 return -IP_ERROR_FUNCTION_NOT_SUPPORTED
;
270 duration
= (duration
+ 500) / 1000;
275 const struct input_plugin_ops ip_ops
= {
277 .close
= vorbis_close
,
280 .read_comments
= vorbis_read_comments
,
281 .duration
= vorbis_duration
284 const char * const ip_extensions
[] = { "ogg", NULL
};
285 const char * const ip_mime_types
[] = { "application/ogg", "audio/x-ogg", NULL
};