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
23 #include <read_wrapper.h>
27 #include <tremor/ivorbisfile.h>
29 #include <vorbis/vorbisfile.h>
35 #include <sys/types.h>
38 struct vorbis_private
{
43 /* http://www.xiph.org/vorbis/doc/vorbisfile/callbacks.html */
45 static size_t read_func(void *ptr
, size_t size
, size_t nmemb
, void *datasource
)
47 struct input_plugin_data
*ip_data
= datasource
;
50 rc
= read_wrapper(ip_data
, ptr
, size
* nmemb
);
52 d_print("error: %s\n", strerror(errno
));
62 static int seek_func(void *datasource
, ogg_int64_t offset
, int whence
)
64 struct input_plugin_data
*ip_data
= datasource
;
67 rc
= lseek(ip_data
->fd
, offset
, whence
);
73 static int close_func(void *datasource
)
75 struct input_plugin_data
*ip_data
= datasource
;
78 rc
= close(ip_data
->fd
);
83 static long tell_func(void *datasource
)
85 struct input_plugin_data
*ip_data
= datasource
;
88 rc
= lseek(ip_data
->fd
, 0, SEEK_CUR
);
94 * size_t (*read_func) (void *ptr, size_t size, size_t nmemb, void *datasource);
95 * int (*seek_func) (void *datasource, ogg_int64_t offset, int whence);
96 * int (*close_func) (void *datasource);
97 * long (*tell_func) (void *datasource);
100 static ov_callbacks callbacks
= {
101 .read_func
= read_func
,
102 .seek_func
= seek_func
,
103 .close_func
= close_func
,
104 .tell_func
= tell_func
107 static int vorbis_open(struct input_plugin_data
*ip_data
)
109 struct vorbis_private
*priv
;
113 priv
= xnew(struct vorbis_private
, 1);
114 priv
->current_section
= 0;
115 memset(&priv
->vf
, 0, sizeof(priv
->vf
));
117 rc
= ov_open_callbacks(ip_data
, &priv
->vf
, NULL
, 0, callbacks
);
119 d_print("ov_open failed: %d\n", rc
);
121 return -IP_ERROR_FILE_FORMAT
;
123 ip_data
->private = priv
;
125 vi
= ov_info(&priv
->vf
, -1);
126 ip_data
->sf
= sf_rate(vi
->rate
) | sf_channels(vi
->channels
) | sf_bits(16) | sf_signed(1);
130 static int vorbis_close(struct input_plugin_data
*ip_data
)
132 struct vorbis_private
*priv
;
135 priv
= ip_data
->private;
136 /* this closes ip_data->fd! */
137 rc
= ov_clear(&priv
->vf
);
140 d_print("ov_clear returned %d\n", rc
);
142 ip_data
->private = NULL
;
148 * indicates there was an interruption in the data.
149 * (one of: garbage between pages, loss of sync followed by recapture,
152 * indicates that an invalid stream section was supplied to libvorbisfile,
153 * or the requested link is corrupt.
157 * indicates actual number of bytes read. ov_read() will decode at most
158 * one vorbis packet per invocation, so the value returned will generally
159 * be less than length.
161 static int vorbis_read(struct input_plugin_data
*ip_data
, char *buffer
, int count
)
163 struct vorbis_private
*priv
;
166 priv
= ip_data
->private;
168 /* Tremor can only handle signed 16 bit data */
169 rc
= ov_read(&priv
->vf
, buffer
, count
, &priv
->current_section
);
171 rc
= ov_read(&priv
->vf
, buffer
, count
, 0, 2, 1, &priv
->current_section
);
185 d_print("error: %s\n", strerror(errno
));
187 /* return -IP_ERROR_INTERNAL; */
193 d_print("error: %d\n", rc
);
194 rc
= -IP_ERROR_FILE_FORMAT
;
200 static int vorbis_seek(struct input_plugin_data
*ip_data
, double offset
)
202 struct vorbis_private
*priv
;
205 priv
= ip_data
->private;
208 rc
= ov_time_seek(&priv
->vf
, offset
* 1000);
210 rc
= ov_time_seek(&priv
->vf
, offset
);
214 return -IP_ERROR_FUNCTION_NOT_SUPPORTED
;
216 return -IP_ERROR_INTERNAL
;
218 return -IP_ERROR_INTERNAL
;
220 return -IP_ERROR_INTERNAL
;
222 return -IP_ERROR_INTERNAL
;
227 static int vorbis_read_comments(struct input_plugin_data
*ip_data
,
228 struct keyval
**comments
)
231 struct vorbis_private
*priv
;
235 priv
= ip_data
->private;
236 vc
= ov_comment(&priv
->vf
, -1);
238 d_print("vc == NULL\n");
239 *comments
= xnew0(struct keyval
, 1);
242 c
= xnew0(struct keyval
, vc
->comments
+ 1);
243 for (s
= 0, d
= 0; s
< vc
->comments
; s
++) {
244 const char *str
= vc
->user_comments
[s
];
247 for (i
= 0; str
[i
]; i
++) {
252 d_print("invalid comment: '%s' ('=' expected)\n", str
);
255 key
= xstrndup(str
, i
);
256 if (!is_interesting_key(key
)) {
261 val
= xstrdup(str
+ i
+ 1);
262 if (!strcasecmp(key
, "tracknumber") || !strcasecmp(key
, "discnumber"))
263 fix_track_or_disc(val
);
272 static int vorbis_duration(struct input_plugin_data
*ip_data
)
274 struct vorbis_private
*priv
;
277 priv
= ip_data
->private;
278 duration
= ov_time_total(&priv
->vf
, -1);
279 if (duration
== OV_EINVAL
)
280 return -IP_ERROR_FUNCTION_NOT_SUPPORTED
;
282 duration
= (duration
+ 500) / 1000;
287 const struct input_plugin_ops ip_ops
= {
289 .close
= vorbis_close
,
292 .read_comments
= vorbis_read_comments
,
293 .duration
= vorbis_duration
296 const char * const ip_extensions
[] = { "ogg", NULL
};
297 const char * const ip_mime_types
[] = { "application/ogg", "audio/x-ogg", NULL
};