Add Russian translation provided by Валерий Крувялис <valkru@mail.ru>
[xiph-mirror.git] / vorbis-tools / ogg123 / oggvorbis_format.c
blob5406a3e45aec40f2c48bd4fe31ddc8a78351b8dc
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$
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"
35 #ifdef HAVE_OV_READ_FILTER
36 #include "vgfilter.h"
37 #endif
39 typedef struct ovf_private_t {
40 OggVorbis_File vf;
41 vorbis_comment *vc;
42 vorbis_info *vi;
43 int current_section;
45 int bos; /* At beginning of logical bitstream */
47 decoder_stats_t stats;
48 #ifdef HAVE_OV_READ_FILTER
49 vgain_state vg;
50 #endif
51 } ovf_private_t;
53 /* Forward declarations */
54 format_t oggvorbis_format;
55 ov_callbacks vorbisfile_callbacks;
58 void print_vorbis_stream_info (decoder_t *decoder);
59 void print_vorbis_comments (vorbis_comment *vc, decoder_callbacks_t *cb,
60 void *callback_arg);
63 /* ----------------------------------------------------------- */
66 int ovf_can_decode (data_source_t *source)
68 return 1; /* The file transport is tested last, so always try it */
72 decoder_t* ovf_init (data_source_t *source, ogg123_options_t *ogg123_opts,
73 audio_format_t *audio_fmt,
74 decoder_callbacks_t *callbacks, void *callback_arg)
76 decoder_t *decoder;
77 ovf_private_t *private;
78 int ret;
81 /* Allocate data source structures */
82 decoder = malloc(sizeof(decoder_t));
83 private = malloc(sizeof(ovf_private_t));
85 if (decoder != NULL && private != NULL) {
86 decoder->source = source;
87 decoder->actual_fmt = decoder->request_fmt = *audio_fmt;
88 decoder->format = &oggvorbis_format;
89 decoder->callbacks = callbacks;
90 decoder->callback_arg = callback_arg;
91 decoder->private = private;
93 private->bos = 1;
94 private->current_section = -1;
96 private->stats.total_time = 0.0;
97 private->stats.current_time = 0.0;
98 private->stats.instant_bitrate = 0;
99 private->stats.avg_bitrate = 0;
101 #ifdef HAVE_OV_READ_FILTER
102 private->vg.scale_factor = 1.0;
103 private->vg.max_scale = 1.0;
104 #endif
105 } else {
106 fprintf(stderr, _("ERROR: Out of memory.\n"));
107 exit(1);
110 /* Initialize vorbisfile decoder */
112 ret = ov_open_callbacks (decoder, &private->vf, NULL, 0,
113 vorbisfile_callbacks);
115 if (ret < 0) {
116 free(private);
117 /* free(source); nope. caller frees. */
118 return NULL;
121 return decoder;
125 int ovf_read (decoder_t *decoder, void *ptr, int nbytes, int *eos,
126 audio_format_t *audio_fmt)
128 ovf_private_t *priv = decoder->private;
129 decoder_callbacks_t *cb = decoder->callbacks;
130 int bytes_read = 0;
131 int ret;
132 int old_section;
134 /* Read comments and audio info at the start of a logical bitstream */
135 if (priv->bos) {
136 priv->vc = ov_comment(&priv->vf, -1);
137 priv->vi = ov_info(&priv->vf, -1);
139 decoder->actual_fmt.rate = priv->vi->rate;
140 decoder->actual_fmt.channels = priv->vi->channels;
142 switch(decoder->actual_fmt.channels){
143 case 1:
144 decoder->actual_fmt.matrix="M";
145 break;
146 case 2:
147 decoder->actual_fmt.matrix="L,R";
148 break;
149 case 3:
150 decoder->actual_fmt.matrix="L,C,R";
151 break;
152 case 4:
153 decoder->actual_fmt.matrix="L,R,BL,BR";
154 break;
155 case 5:
156 decoder->actual_fmt.matrix="L,C,R,BL,BR";
157 break;
158 case 6:
159 decoder->actual_fmt.matrix="L,C,R,BL,BR,LFE";
160 break;
161 case 7:
162 decoder->actual_fmt.matrix="L,C,R,SL,SR,BC,LFE";
163 break;
164 case 8:
165 decoder->actual_fmt.matrix="L,C,R,SL,SR,BL,BR,LFE";
166 break;
167 default:
168 decoder->actual_fmt.matrix=NULL;
169 break;
172 #ifdef HAVE_OV_READ_FILTER
173 vg_init(&priv->vg, priv->vc);
174 #endif
176 print_vorbis_stream_info(decoder);
177 print_vorbis_comments(priv->vc, cb, decoder->callback_arg);
178 priv->bos = 0;
181 *audio_fmt = decoder->actual_fmt;
183 /* Attempt to read as much audio as is requested */
184 while (nbytes >= audio_fmt->word_size * audio_fmt->channels) {
186 old_section = priv->current_section;
187 #ifdef HAVE_OV_READ_FILTER
188 ret = ov_read_filter(&priv->vf, ptr, nbytes, audio_fmt->big_endian,
189 audio_fmt->word_size, audio_fmt->signed_sample,
190 &priv->current_section,
191 vg_filter, &priv->vg);
192 #else
193 ret = ov_read(&priv->vf, ptr, nbytes, audio_fmt->big_endian,
194 audio_fmt->word_size, audio_fmt->signed_sample,
195 &priv->current_section);
196 #endif
198 if (ret == 0) {
200 /* EOF */
201 *eos = 1;
202 break;
204 } else if (ret == OV_HOLE) {
206 if (cb->printf_error != NULL)
207 cb->printf_error(decoder->callback_arg, INFO,
208 _("--- Hole in the stream; probably harmless\n"));
210 } else if (ret < 0) {
212 if (cb->printf_error != NULL)
213 cb->printf_error(decoder->callback_arg, ERROR,
214 _("=== Vorbis library reported a stream error.\n"));
216 /* EOF */
217 *eos = 1;
218 break;
219 } else {
221 bytes_read += ret;
222 ptr = (void *)((unsigned char *)ptr + ret);
223 nbytes -= ret;
225 /* did we enter a new logical bitstream? */
226 if (old_section != priv->current_section && old_section != -1) {
228 *eos = 1;
229 priv->bos = 1; /* Read new headers next time through */
230 break;
236 return bytes_read;
240 int ovf_seek (decoder_t *decoder, double offset, int whence)
242 ovf_private_t *priv = decoder->private;
243 int ret;
244 double cur;
246 if (whence == DECODER_SEEK_CUR) {
247 cur = ov_time_tell(&priv->vf);
248 if (cur >= 0.0)
249 offset += cur;
250 else
251 return 0;
254 ret = ov_time_seek(&priv->vf, offset);
255 if (ret == 0)
256 return 1;
257 else
258 return 0;
262 decoder_stats_t *ovf_statistics (decoder_t *decoder)
264 ovf_private_t *priv = decoder->private;
265 long instant_bitrate;
266 long avg_bitrate;
268 /* ov_time_tell() doesn't work on non-seekable streams, so we use
269 ov_pcm_tell() */
270 priv->stats.total_time = (double) ov_pcm_total(&priv->vf, -1) /
271 (double) decoder->actual_fmt.rate;
272 priv->stats.current_time = (double) ov_pcm_tell(&priv->vf) /
273 (double) decoder->actual_fmt.rate;
275 /* vorbisfile returns 0 when no bitrate change has occurred */
276 instant_bitrate = ov_bitrate_instant(&priv->vf);
277 if (instant_bitrate > 0)
278 priv->stats.instant_bitrate = instant_bitrate;
280 avg_bitrate = ov_bitrate(&priv->vf, priv->current_section);
281 /* Catch error case caused by non-seekable stream */
282 priv->stats.avg_bitrate = avg_bitrate > 0 ? avg_bitrate : 0;
285 return malloc_decoder_stats(&priv->stats);
289 void ovf_cleanup (decoder_t *decoder)
291 ovf_private_t *priv = decoder->private;
293 ov_clear(&priv->vf);
295 free(decoder->private);
296 free(decoder);
300 format_t oggvorbis_format = {
301 "oggvorbis",
302 &ovf_can_decode,
303 &ovf_init,
304 &ovf_read,
305 &ovf_seek,
306 &ovf_statistics,
307 &ovf_cleanup,
311 /* ------------------- Vorbisfile Callbacks ----------------- */
313 size_t vorbisfile_cb_read (void *ptr, size_t size, size_t nmemb, void *arg)
315 decoder_t *decoder = arg;
317 return decoder->source->transport->read(decoder->source, ptr, size, nmemb);
320 int vorbisfile_cb_seek (void *arg, ogg_int64_t offset, int whence)
322 decoder_t *decoder = arg;
324 return decoder->source->transport->seek(decoder->source, offset, whence);
327 int vorbisfile_cb_close (void *arg)
329 return 1; /* Ignore close request so transport can be closed later */
332 long vorbisfile_cb_tell (void *arg)
334 decoder_t *decoder = arg;
336 return decoder->source->transport->tell(decoder->source);
340 ov_callbacks vorbisfile_callbacks = {
341 &vorbisfile_cb_read,
342 &vorbisfile_cb_seek,
343 &vorbisfile_cb_close,
344 &vorbisfile_cb_tell
348 /* ------------------- Private functions -------------------- */
351 void print_vorbis_stream_info (decoder_t *decoder)
353 ovf_private_t *priv = decoder->private;
354 decoder_callbacks_t *cb = decoder->callbacks;
357 if (cb == NULL || cb->printf_metadata == NULL)
358 return;
360 cb->printf_metadata(decoder->callback_arg, 2,
361 _("Ogg Vorbis stream: %d channel, %ld Hz"),
362 priv->vi->channels,
363 priv->vi->rate);
365 cb->printf_metadata(decoder->callback_arg, 3,
366 _("Vorbis format: Version %d"),
367 priv->vi->version);
369 cb->printf_metadata(decoder->callback_arg, 3,
370 _("Bitrate hints: upper=%ld nominal=%ld lower=%ld "
371 "window=%ld"),
372 priv->vi->bitrate_upper,
373 priv->vi->bitrate_nominal,
374 priv->vi->bitrate_lower,
375 priv->vi->bitrate_window);
377 cb->printf_metadata(decoder->callback_arg, 3,
378 _("Encoded by: %s"), priv->vc->vendor);
381 void print_vorbis_comments (vorbis_comment *vc, decoder_callbacks_t *cb,
382 void *callback_arg)
384 int i;
385 char *temp = NULL;
386 int temp_len = 0;
388 for (i = 0; i < vc->comments; i++) {
390 /* Gotta null terminate these things */
391 if (temp_len < vc->comment_lengths[i] + 1) {
392 temp_len = vc->comment_lengths[i] + 1;
393 temp = realloc(temp, sizeof(char) * temp_len);
396 strncpy(temp, vc->user_comments[i], vc->comment_lengths[i]);
397 temp[vc->comment_lengths[i]] = '\0';
399 print_vorbis_comment(temp, cb, callback_arg);
402 free(temp);