Added vorbis-tools.
[vorbis-lancer-gcc.git] / vorbis-tools-1.2.0 / ogg123 / speex_format.c
blobfd6ec420dfc0a980887413556d98fedc4cffd9bc
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: speex_format.c,v 1.3 2003/06/24 02:22:33 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 <speex/speex.h>
28 #include <speex/speex_header.h>
29 #include <speex/speex_stereo.h>
30 #include <speex/speex_callbacks.h>
31 #include "transport.h"
32 #include "format.h"
33 #include "vorbis_comments.h"
34 #include "utf8.h"
35 #include "i18n.h"
37 /* Note that this file contains gratuitous cut and paste from speexdec.c. */
40 /* Use speex's audio enhancement feature */
41 #define ENHANCE_AUDIO 1
44 typedef struct speex_private_t {
45 ogg_sync_state oy;
46 ogg_page og;
47 ogg_packet op;
48 ogg_stream_state os;
49 SpeexBits bits;
50 SpeexStereoState stereo;
51 SpeexHeader *header;
52 void *st;
54 char *comment_packet;
55 int comment_packet_len;
57 float *output; /* Has frame_size * [number of channels] * frames_per_packet
58 elements */
59 int output_start;
60 int output_left;
62 int frames_per_packet;
63 int frame_size;
64 int vbr;
66 int bos; /* If we are at the beginning (before headers) of a stream */
67 int eof; /* If we've read the end of the data source (but there still might
68 be data in the buffers */
69 /* For calculating bitrate stats */
70 long samples_decoded;
71 long samples_decoded_previous;
72 long bytes_read;
73 long bytes_read_previous;
75 long totalsamples;
76 long currentsample;
78 decoder_stats_t stats;
79 } speex_private_t;
81 /* Forward declarations */
82 format_t speex_format;
86 /* Private functions declarations */
87 void print_speex_info(SpeexHeader *header, decoder_callbacks_t *cb,
88 void *callback_arg);
89 void print_speex_comments(char *comments, int length,
90 decoder_callbacks_t *cb, void *callback_arg);
91 void *process_header(ogg_packet *op, int *frame_size,
92 SpeexHeader **header,
93 SpeexStereoState *stereo, decoder_callbacks_t *cb,
94 void *callback_arg);
95 int read_speex_header(decoder_t *decoder);
97 /* ----------------------------------------------------------- */
100 int speex_can_decode (data_source_t *source)
102 char buf[36];
103 int len;
105 len = source->transport->peek(source, buf, sizeof(char), 36);
107 if (len >= 32 && memcmp(buf, "OggS", 4) == 0
108 && memcmp(buf+28, "Speex ", 8) == 0) /* 3 trailing spaces */
109 return 1;
110 else
111 return 0;
115 decoder_t* speex_init (data_source_t *source, ogg123_options_t *ogg123_opts,
116 audio_format_t *audio_fmt,
117 decoder_callbacks_t *callbacks, void *callback_arg)
119 decoder_t *decoder;
120 speex_private_t *private;
121 int ret;
124 /* Allocate data source structures */
125 decoder = malloc(sizeof(decoder_t));
126 private = malloc(sizeof(speex_private_t));
128 if (decoder != NULL && private != NULL) {
129 decoder->source = source;
130 decoder->actual_fmt = decoder->request_fmt = *audio_fmt;
131 decoder->format = &speex_format;
132 decoder->callbacks = callbacks;
133 decoder->callback_arg = callback_arg;
134 decoder->private = private;
137 private->bos = 1;
138 private->eof = 0;
139 private->samples_decoded = private->samples_decoded_previous = 0;
140 private->bytes_read = private->bytes_read_previous = 0;
141 private->currentsample = 0;
142 private->comment_packet = NULL;
143 private->comment_packet_len = 0;
144 private->header = NULL;
146 private->stats.total_time = 0.0;
147 private->stats.current_time = 0.0;
148 private->stats.instant_bitrate = 0;
149 private->stats.avg_bitrate = 0;
150 } else {
151 fprintf(stderr, _("Error: Out of memory.\n"));
152 exit(1);
155 /* Initialize structures */
156 ogg_sync_init(&private->oy);
157 speex_bits_init(&private->bits);
158 ret = 1;
160 if (ret < 0) {
161 free(private);
162 /* free(source); nope. caller frees. */
163 return NULL;
166 return decoder;
170 int speex_read (decoder_t *decoder, void *ptr, int nbytes, int *eos,
171 audio_format_t *audio_fmt)
173 speex_private_t *priv = decoder->private;
174 decoder_callbacks_t *cb = decoder->callbacks;
175 transport_t *trans = decoder->source->transport;
176 int bytes_requested = nbytes;
177 int ret;
178 short *out = (short *) ptr;
180 /* Read comments and audio info at the start of a logical bitstream */
181 if (priv->bos) {
183 ret = read_speex_header(decoder);
185 if (!ret) {
186 *eos = 1;
187 return 0; /* Bail out! */
190 print_speex_info(priv->header, cb, decoder->callback_arg);
191 if (priv->comment_packet != NULL)
192 print_speex_comments(priv->comment_packet, priv->comment_packet_len,
193 cb, decoder->callback_arg);
195 priv->bos = 0;
198 *audio_fmt = decoder->actual_fmt;
200 while (nbytes) {
201 char *data;
202 int i, j, nb_read;
204 /* First see if there is anything left in the output buffer and
205 empty it out */
206 if (priv->output_left > 0) {
207 int to_copy = nbytes / (2 * audio_fmt->channels);
209 to_copy *= audio_fmt->channels;
211 to_copy = priv->output_left < to_copy ? priv->output_left : to_copy;
213 /* Integerify it! */
214 for (i = 0; i < to_copy; i++)
215 out[i]=(ogg_int16_t)priv->output[i+priv->output_start];
217 out += to_copy;
218 priv->output_start += to_copy;
219 priv->output_left -= to_copy;
221 priv->currentsample += to_copy / audio_fmt->channels;
223 nbytes -= to_copy * 2;
224 } else if (ogg_stream_packetout(&priv->os, &priv->op) == 1) {
225 float *temp_output = priv->output;
226 /* Decode some more samples */
228 /*Copy Ogg packet to Speex bitstream*/
229 speex_bits_read_from(&priv->bits, (char*)priv->op.packet,
230 priv->op.bytes);
232 for (j = 0;j < priv->frames_per_packet; j++) {
233 /*Decode frame*/
234 speex_decode(priv->st, &priv->bits, temp_output);
236 if (audio_fmt->channels==2)
237 speex_decode_stereo(temp_output, priv->frame_size, &priv->stereo);
239 priv->samples_decoded += priv->frame_size;
241 /*PCM saturation (just in case)*/
242 for (i=0;i < priv->frame_size * audio_fmt->channels; i++) {
243 if (temp_output[i]>32000.0)
244 temp_output[i]=32000.0;
245 else if (temp_output[i]<-32000.0)
246 temp_output[i]=-32000.0;
249 temp_output += priv->frame_size * audio_fmt->channels;
252 priv->output_start = 0;
253 priv->output_left = priv->frame_size * audio_fmt->channels *
254 priv->frames_per_packet;
255 } else if (ogg_sync_pageout(&priv->oy, &priv->og) == 1) {
256 /* Read in another ogg page */
257 ogg_stream_pagein(&priv->os, &priv->og);
258 } else if (!priv->eof) {
259 /* Finally, pull in some more data and try again on the next pass */
261 /*Get the ogg buffer for writing*/
262 data = ogg_sync_buffer(&priv->oy, 200);
263 /*Read bitstream from input file*/
264 nb_read = trans->read(decoder->source, data, sizeof(char), 200);
266 if (nb_read == 0)
267 priv->eof = 1; /* We've read the end of the file */
269 ogg_sync_wrote(&priv->oy, nb_read);
271 priv->bytes_read += nb_read;
272 } else {
273 *eos = 1;
274 break;
278 return bytes_requested - nbytes;
282 int speex_seek (decoder_t *decoder, double offset, int whence)
284 speex_private_t *priv = decoder->private;
286 return 0;
290 #define AVG_FACTOR 0.7
292 decoder_stats_t *speex_statistics (decoder_t *decoder)
294 speex_private_t *priv = decoder->private;
295 long instant_bitrate;
296 long avg_bitrate;
298 priv->stats.total_time = (double) priv->totalsamples /
299 (double) decoder->actual_fmt.rate;
300 priv->stats.current_time = (double) priv->currentsample /
301 (double) decoder->actual_fmt.rate;
303 /* Need this test to prevent averaging in false zeros. */
304 if ((priv->bytes_read - priv->bytes_read_previous) != 0 &&
305 (priv->samples_decoded - priv->samples_decoded_previous) != 0) {
307 instant_bitrate = 8.0 * (priv->bytes_read - priv->bytes_read_previous)
308 * decoder->actual_fmt.rate
309 / (double) (priv->samples_decoded - priv->samples_decoded_previous);
311 /* A little exponential averaging to smooth things out */
312 priv->stats.instant_bitrate = AVG_FACTOR * instant_bitrate
313 + (1.0 - AVG_FACTOR) * priv->stats.instant_bitrate;
315 priv->bytes_read_previous = priv->bytes_read;
316 priv->samples_decoded_previous = priv->samples_decoded;
319 /* Don't know unless we seek the stream */
320 priv->stats.avg_bitrate = 0;
323 return malloc_decoder_stats(&priv->stats);
327 void speex_cleanup (decoder_t *decoder)
329 speex_private_t *priv = decoder->private;
331 free(priv->comment_packet);
332 free(priv->output);
333 free(decoder->private);
334 free(decoder);
338 format_t speex_format = {
339 "speex",
340 &speex_can_decode,
341 &speex_init,
342 &speex_read,
343 &speex_seek,
344 &speex_statistics,
345 &speex_cleanup,
349 /* ------------------- Private functions -------------------- */
351 #define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \
352 ((buf[base+2]<<16)&0xff0000)| \
353 ((buf[base+1]<<8)&0xff00)| \
354 (buf[base]&0xff))
356 void print_speex_info(SpeexHeader *header, decoder_callbacks_t *cb,
357 void *callback_arg)
359 int modeID = header->mode;
361 if (header->vbr)
362 cb->printf_metadata(callback_arg, 2,
363 _("Ogg Speex stream: %d channel, %d Hz, %s mode (VBR)"),
364 header->nb_channels,
365 header->rate,
366 speex_mode_list[modeID]->modeName);
367 else
368 cb->printf_metadata(callback_arg, 2,
369 _("Ogg Speex stream: %d channel, %d Hz, %s mode"),
370 header->nb_channels,
371 header->rate,
372 speex_mode_list[modeID]->modeName);
374 cb->printf_metadata(callback_arg, 3,
375 _("Speex version: %s"),
376 header->speex_version);
381 void print_speex_comments(char *comments, int length,
382 decoder_callbacks_t *cb, void *callback_arg)
384 char *c = comments;
385 int len, i, nb_fields;
386 char *end;
387 char *temp = NULL;
388 int temp_len = 0;
390 if (length<8) {
391 cb->printf_error(callback_arg, WARNING, _("Invalid/corrupted comments"));
392 return;
395 /* Parse out vendor string */
397 end = c + length;
398 len = readint(c, 0);
399 c += 4;
401 if (c+len>end) {
402 cb->printf_error(callback_arg, WARNING, _("Invalid/corrupted comments"));
403 return;
407 temp_len = len + 1;
408 temp = malloc(sizeof(char) * temp_len);
410 strncpy(temp, c, len);
411 temp[len] = '\0';
413 cb->printf_metadata(callback_arg, 3, _("Encoded by: %s"), temp);
416 /* Parse out user comments */
418 c += len;
420 if (c + 4>end) {
421 cb->printf_error(callback_arg, WARNING, _("Invalid/corrupted comments"));
422 free(temp);
423 return;
426 nb_fields = readint(c, 0);
427 c += 4;
429 for (i = 0; i < nb_fields; i++) {
430 if (c + 4 > end) {
431 cb->printf_error(callback_arg, WARNING, _("Invalid/corrupted comments"));
432 free(temp);
433 return;
435 len = readint(c, 0);
436 c += 4;
437 if (c + len > end) {
438 cb->printf_error(callback_arg, WARNING, _("Invalid/corrupted comments"));
440 free(temp);
441 return;
444 if (temp_len < len + 1) {
445 temp_len = len + 1;
446 temp = realloc(temp, sizeof(char) * temp_len);
450 strncpy(temp, c, len);
451 temp[len] = '\0';
453 print_vorbis_comment(temp, cb, callback_arg);
455 c += len;
458 free(temp);
462 void *process_header(ogg_packet *op, int *frame_size,
463 SpeexHeader **header,
464 SpeexStereoState *stereo, decoder_callbacks_t *cb,
465 void *callback_arg)
467 void *st;
468 SpeexMode *mode;
469 int modeID;
470 SpeexCallback callback;
471 int enhance = ENHANCE_AUDIO;
473 *header = speex_packet_to_header((char*)op->packet, op->bytes);
474 if (!*header) {
475 cb->printf_error(callback_arg, ERROR, _("Cannot read header"));
476 return NULL;
478 if ((*header)->mode >= SPEEX_NB_MODES) {
479 cb->printf_error(callback_arg, ERROR,
480 _("Mode number %d does not (any longer) exist in this version"),
481 (*header)->mode);
482 return NULL;
485 modeID = (*header)->mode;
486 mode = speex_mode_list[modeID];
488 if (mode->bitstream_version < (*header)->mode_bitstream_version) {
489 cb->printf_error(callback_arg, ERROR, _("The file was encoded with a newer version of Speex.\n You need to upgrade in order to play it.\n"));
490 return NULL;
492 if (mode->bitstream_version > (*header)->mode_bitstream_version) {
493 cb->printf_error(callback_arg, ERROR, _("The file was encoded with an older version of Speex.\nYou would need to downgrade the version in order to play it."));
494 return NULL;
497 st = speex_decoder_init(mode);
498 speex_decoder_ctl(st, SPEEX_SET_ENH, &enhance);
499 speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size);
501 callback.callback_id = SPEEX_INBAND_STEREO;
502 callback.func = speex_std_stereo_request_handler;
503 callback.data = stereo;
504 speex_decoder_ctl(st, SPEEX_SET_HANDLER, &callback);
506 speex_decoder_ctl(st, SPEEX_SET_SAMPLING_RATE, &(*header)->rate);
508 return st;
512 int read_speex_header (decoder_t *decoder)
514 speex_private_t *priv = decoder->private;
515 transport_t *trans = decoder->source->transport;
516 int packet_count = 0;
517 int stream_init = 0;
518 char *data;
519 int nb_read;
521 while (packet_count < 2) {
522 /*Get the ogg buffer for writing*/
523 data = ogg_sync_buffer(&priv->oy, 200);
525 /*Read bitstream from input file*/
526 nb_read = trans->read(decoder->source, data, sizeof(char), 200);
527 ogg_sync_wrote(&priv->oy, nb_read);
529 /*Loop for all complete pages we got (most likely only one)*/
530 while (ogg_sync_pageout(&priv->oy, &priv->og)==1) {
532 if (stream_init == 0) {
533 ogg_stream_init(&priv->os, ogg_page_serialno(&priv->og));
534 stream_init = 1;
537 /*Add page to the bitstream*/
538 ogg_stream_pagein(&priv->os, &priv->og);
540 /*Extract all available packets FIXME: EOS!*/
541 while (ogg_stream_packetout(&priv->os, &priv->op)==1) {
542 /*If first packet, process as Speex header*/
543 if (packet_count==0) {
544 priv->st = process_header(&priv->op,
545 &priv->frame_size,
546 &priv->header,
547 &priv->stereo,
548 decoder->callbacks,
549 decoder->callback_arg);
551 if (!priv->st)
552 return 0;
554 decoder->actual_fmt.rate = priv->header->rate;
555 priv->frames_per_packet = priv->header->frames_per_packet;
556 decoder->actual_fmt.channels = priv->header->nb_channels;
557 priv->vbr = priv->header->vbr;
559 if (!priv->frames_per_packet)
560 priv->frames_per_packet=1;
563 priv->output = calloc(priv->frame_size *
564 decoder->actual_fmt.channels *
565 priv->frames_per_packet, sizeof(float));
566 priv->output_start = 0;
567 priv->output_left = 0;
569 } else if (packet_count==1){
570 priv->comment_packet_len = priv->op.bytes;
571 priv->comment_packet = malloc(sizeof(char) *
572 priv->comment_packet_len);
573 memcpy(priv->comment_packet, priv->op.packet,
574 priv->comment_packet_len);
577 packet_count++;
582 return 1;