General formatting clean-up.
[xiph/unicode.git] / vorbis-tools / ogg123 / oggvorbis_format.c
blob3ffade7de40295c47136c372f0c753da32e336c9
1 /********************************************************************
2 * *
3 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
5 * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
6 * PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE Ogg123 SOURCE CODE IS (C) COPYRIGHT 2000-2003 *
9 * by Stan Seibert <volsung@xiph.org> AND OTHER CONTRIBUTORS *
10 * http://www.xiph.org/ *
11 * *
12 ********************************************************************
14 last mod: $Id: oggvorbis_format.c,v 1.13 2003/06/24 12:34:40 giles Exp $
16 ********************************************************************/
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <ogg/ogg.h>
27 #include <vorbis/codec.h>
28 #include <vorbis/vorbisfile.h>
29 #include "transport.h"
30 #include "format.h"
31 #include "vorbis_comments.h"
32 #include "utf8.h"
33 #include "i18n.h"
36 typedef struct ovf_private_t {
37 OggVorbis_File vf;
38 vorbis_comment *vc;
39 vorbis_info *vi;
40 int current_section;
42 int bos; /* At beginning of logical bitstream */
44 decoder_stats_t stats;
45 } ovf_private_t;
47 /* Forward declarations */
48 format_t oggvorbis_format;
49 ov_callbacks vorbisfile_callbacks;
52 void print_vorbis_stream_info (decoder_t *decoder);
53 void print_vorbis_comments (vorbis_comment *vc, decoder_callbacks_t *cb,
54 void *callback_arg);
57 /* ----------------------------------------------------------- */
60 int ovf_can_decode (data_source_t *source)
62 return 1; /* The file transport is tested last, so always try it */
66 decoder_t* ovf_init (data_source_t *source, ogg123_options_t *ogg123_opts,
67 audio_format_t *audio_fmt,
68 decoder_callbacks_t *callbacks, void *callback_arg)
70 decoder_t *decoder;
71 ovf_private_t *private;
72 int ret;
75 /* Allocate data source structures */
76 decoder = malloc(sizeof(decoder_t));
77 private = malloc(sizeof(ovf_private_t));
79 if (decoder != NULL && private != NULL) {
80 decoder->source = source;
81 decoder->actual_fmt = decoder->request_fmt = *audio_fmt;
82 decoder->format = &oggvorbis_format;
83 decoder->callbacks = callbacks;
84 decoder->callback_arg = callback_arg;
85 decoder->private = private;
87 private->bos = 1;
88 private->current_section = -1;
90 private->stats.total_time = 0.0;
91 private->stats.current_time = 0.0;
92 private->stats.instant_bitrate = 0;
93 private->stats.avg_bitrate = 0;
94 } else {
95 fprintf(stderr, _("Error: Out of memory.\n"));
96 exit(1);
99 /* Initialize vorbisfile decoder */
101 ret = ov_open_callbacks (decoder, &private->vf, NULL, 0,
102 vorbisfile_callbacks);
104 if (ret < 0) {
105 free(private);
106 /* free(source); nope. caller frees. */
107 return NULL;
110 return decoder;
114 int ovf_read (decoder_t *decoder, void *ptr, int nbytes, int *eos,
115 audio_format_t *audio_fmt)
117 ovf_private_t *priv = decoder->private;
118 decoder_callbacks_t *cb = decoder->callbacks;
119 int bytes_read = 0;
120 int ret;
121 int old_section;
123 /* Read comments and audio info at the start of a logical bitstream */
124 if (priv->bos) {
125 priv->vc = ov_comment(&priv->vf, -1);
126 priv->vi = ov_info(&priv->vf, -1);
128 decoder->actual_fmt.rate = priv->vi->rate;
129 decoder->actual_fmt.channels = priv->vi->channels;
132 print_vorbis_stream_info(decoder);
133 print_vorbis_comments(priv->vc, cb, decoder->callback_arg);
134 priv->bos = 0;
137 *audio_fmt = decoder->actual_fmt;
139 /* Attempt to read as much audio as is requested */
140 while (nbytes >= audio_fmt->word_size * audio_fmt->channels) {
142 old_section = priv->current_section;
143 ret = ov_read(&priv->vf, ptr, nbytes, audio_fmt->big_endian,
144 audio_fmt->word_size, audio_fmt->signed_sample,
145 &priv->current_section);
147 if (ret == 0) {
149 /* EOF */
150 *eos = 1;
151 break;
153 } else if (ret == OV_HOLE) {
155 if (cb->printf_error != NULL)
156 cb->printf_error(decoder->callback_arg, INFO,
157 _("--- Hole in the stream; probably harmless\n"));
159 } else if (ret < 0) {
161 if (cb->printf_error != NULL)
162 cb->printf_error(decoder->callback_arg, ERROR,
163 _("=== Vorbis library reported a stream error.\n"));
165 /* EOF */
166 *eos = 1;
167 break;
168 } else {
170 bytes_read += ret;
171 ptr = (void *)((unsigned char *)ptr + ret);
172 nbytes -= ret;
174 /* did we enter a new logical bitstream? */
175 if (old_section != priv->current_section && old_section != -1) {
177 *eos = 1;
178 priv->bos = 1; /* Read new headers next time through */
179 break;
185 return bytes_read;
189 int ovf_seek (decoder_t *decoder, double offset, int whence)
191 ovf_private_t *priv = decoder->private;
192 int ret;
193 double cur;
195 if (whence == DECODER_SEEK_CUR) {
196 cur = ov_time_tell(&priv->vf);
197 if (cur >= 0.0)
198 offset += cur;
199 else
200 return 0;
203 ret = ov_time_seek(&priv->vf, offset);
204 if (ret == 0)
205 return 1;
206 else
207 return 0;
211 decoder_stats_t *ovf_statistics (decoder_t *decoder)
213 ovf_private_t *priv = decoder->private;
214 long instant_bitrate;
215 long avg_bitrate;
217 /* ov_time_tell() doesn't work on non-seekable streams, so we use
218 ov_pcm_tell() */
219 priv->stats.total_time = (double) ov_pcm_total(&priv->vf, -1) /
220 (double) decoder->actual_fmt.rate;
221 priv->stats.current_time = (double) ov_pcm_tell(&priv->vf) /
222 (double) decoder->actual_fmt.rate;
224 /* vorbisfile returns 0 when no bitrate change has occurred */
225 instant_bitrate = ov_bitrate_instant(&priv->vf);
226 if (instant_bitrate > 0)
227 priv->stats.instant_bitrate = instant_bitrate;
229 avg_bitrate = ov_bitrate(&priv->vf, priv->current_section);
230 /* Catch error case caused by non-seekable stream */
231 priv->stats.avg_bitrate = avg_bitrate > 0 ? avg_bitrate : 0;
234 return malloc_decoder_stats(&priv->stats);
238 void ovf_cleanup (decoder_t *decoder)
240 ovf_private_t *priv = decoder->private;
242 ov_clear(&priv->vf);
244 free(decoder->private);
245 free(decoder);
249 format_t oggvorbis_format = {
250 "oggvorbis",
251 &ovf_can_decode,
252 &ovf_init,
253 &ovf_read,
254 &ovf_seek,
255 &ovf_statistics,
256 &ovf_cleanup,
260 /* ------------------- Vorbisfile Callbacks ----------------- */
262 size_t vorbisfile_cb_read (void *ptr, size_t size, size_t nmemb, void *arg)
264 decoder_t *decoder = arg;
266 return decoder->source->transport->read(decoder->source, ptr, size, nmemb);
269 int vorbisfile_cb_seek (void *arg, ogg_int64_t offset, int whence)
271 decoder_t *decoder = arg;
273 return decoder->source->transport->seek(decoder->source, offset, whence);
276 int vorbisfile_cb_close (void *arg)
278 return 1; /* Ignore close request so transport can be closed later */
281 long vorbisfile_cb_tell (void *arg)
283 decoder_t *decoder = arg;
285 return decoder->source->transport->tell(decoder->source);
289 ov_callbacks vorbisfile_callbacks = {
290 &vorbisfile_cb_read,
291 &vorbisfile_cb_seek,
292 &vorbisfile_cb_close,
293 &vorbisfile_cb_tell
297 /* ------------------- Private functions -------------------- */
300 void print_vorbis_stream_info (decoder_t *decoder)
302 ovf_private_t *priv = decoder->private;
303 decoder_callbacks_t *cb = decoder->callbacks;
306 if (cb == NULL || cb->printf_metadata == NULL)
307 return;
309 cb->printf_metadata(decoder->callback_arg, 2,
310 _("Ogg Vorbis stream: %d channel, %ld Hz"),
311 priv->vi->channels,
312 priv->vi->rate);
314 cb->printf_metadata(decoder->callback_arg, 3,
315 _("Vorbis format: Version %d"),
316 priv->vi->version);
318 cb->printf_metadata(decoder->callback_arg, 3,
319 _("Bitrate hints: upper=%ld nominal=%ld lower=%ld "
320 "window=%ld"),
321 priv->vi->bitrate_upper,
322 priv->vi->bitrate_nominal,
323 priv->vi->bitrate_lower,
324 priv->vi->bitrate_window);
326 cb->printf_metadata(decoder->callback_arg, 3,
327 _("Encoded by: %s"), priv->vc->vendor);
330 void print_vorbis_comments (vorbis_comment *vc, decoder_callbacks_t *cb,
331 void *callback_arg)
333 int i;
334 char *temp = NULL;
335 int temp_len = 0;
337 for (i = 0; i < vc->comments; i++) {
339 /* Gotta null terminate these things */
340 if (temp_len < vc->comment_lengths[i] + 1) {
341 temp_len = vc->comment_lengths[i] + 1;
342 temp = realloc(temp, sizeof(char) * temp_len);
345 strncpy(temp, vc->user_comments[i], vc->comment_lengths[i]);
346 temp[vc->comment_lengths[i]] = '\0';
348 print_vorbis_comment(temp, cb, callback_arg);
351 free(temp);