Add Russian translation provided by Валерий Крувялис <valkru@mail.ru>
[xiph-mirror.git] / vorbis-tools / ogg123 / speex_format.c
blob30efde456c8062f4229f3fe5db9b56911826b3a6
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 <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;
145 private->stereo = speex_stereo_state_init();
147 private->stats.total_time = 0.0;
148 private->stats.current_time = 0.0;
149 private->stats.instant_bitrate = 0;
150 private->stats.avg_bitrate = 0;
151 } else {
152 fprintf(stderr, _("ERROR: Out of memory.\n"));
153 exit(1);
156 /* Initialize structures */
157 ogg_sync_init(&private->oy);
158 speex_bits_init(&private->bits);
159 ret = 1;
161 if (ret < 0) {
162 free(private);
163 /* free(source); nope. caller frees. */
164 return NULL;
167 return decoder;
171 int speex_read (decoder_t *decoder, void *ptr, int nbytes, int *eos,
172 audio_format_t *audio_fmt)
174 speex_private_t *priv = decoder->private;
175 decoder_callbacks_t *cb = decoder->callbacks;
176 transport_t *trans = decoder->source->transport;
177 int bytes_requested = nbytes;
178 int ret;
179 short *out = (short *) ptr;
181 /* Read comments and audio info at the start of a logical bitstream */
182 if (priv->bos) {
184 ret = read_speex_header(decoder);
186 if (!ret) {
187 *eos = 1;
188 return 0; /* Bail out! */
191 print_speex_info(priv->header, cb, decoder->callback_arg);
192 if (priv->comment_packet != NULL)
193 print_speex_comments(priv->comment_packet, priv->comment_packet_len,
194 cb, decoder->callback_arg);
196 priv->bos = 0;
199 *audio_fmt = decoder->actual_fmt;
201 while (nbytes) {
202 char *data;
203 int i, j, nb_read;
205 /* First see if there is anything left in the output buffer and
206 empty it out */
207 if (priv->output_left > 0) {
208 int to_copy = nbytes / (2 * audio_fmt->channels);
210 to_copy *= audio_fmt->channels;
212 to_copy = priv->output_left < to_copy ? priv->output_left : to_copy;
214 /* Integerify it! */
215 for (i = 0; i < to_copy; i++)
216 out[i]=(ogg_int16_t)priv->output[i+priv->output_start];
218 out += to_copy;
219 priv->output_start += to_copy;
220 priv->output_left -= to_copy;
222 priv->currentsample += to_copy / audio_fmt->channels;
224 nbytes -= to_copy * 2;
225 } else if (ogg_stream_packetout(&priv->os, &priv->op) == 1) {
226 float *temp_output = priv->output;
227 /* Decode some more samples */
229 /*Copy Ogg packet to Speex bitstream*/
230 speex_bits_read_from(&priv->bits, (char*)priv->op.packet,
231 priv->op.bytes);
233 for (j = 0;j < priv->frames_per_packet; j++) {
234 /*Decode frame*/
235 speex_decode(priv->st, &priv->bits, temp_output);
237 if (audio_fmt->channels==2)
238 speex_decode_stereo(temp_output, priv->frame_size, priv->stereo);
240 priv->samples_decoded += priv->frame_size;
242 /*PCM saturation (just in case)*/
243 for (i=0;i < priv->frame_size * audio_fmt->channels; i++) {
244 if (temp_output[i]>32000.0)
245 temp_output[i]=32000.0;
246 else if (temp_output[i]<-32000.0)
247 temp_output[i]=-32000.0;
250 temp_output += priv->frame_size * audio_fmt->channels;
253 priv->output_start = 0;
254 priv->output_left = priv->frame_size * audio_fmt->channels *
255 priv->frames_per_packet;
256 } else if (ogg_sync_pageout(&priv->oy, &priv->og) == 1) {
257 /* Read in another ogg page */
258 ogg_stream_pagein(&priv->os, &priv->og);
259 } else if (!priv->eof) {
260 /* Finally, pull in some more data and try again on the next pass */
262 /*Get the ogg buffer for writing*/
263 data = ogg_sync_buffer(&priv->oy, 200);
264 /*Read bitstream from input file*/
265 nb_read = trans->read(decoder->source, data, sizeof(char), 200);
267 if (nb_read == 0)
268 priv->eof = 1; /* We've read the end of the file */
270 ogg_sync_wrote(&priv->oy, nb_read);
272 priv->bytes_read += nb_read;
273 } else {
274 *eos = 1;
275 break;
279 return bytes_requested - nbytes;
283 int speex_seek (decoder_t *decoder, double offset, int whence)
285 speex_private_t *priv = decoder->private;
287 return 0;
291 #define AVG_FACTOR 0.7
293 decoder_stats_t *speex_statistics (decoder_t *decoder)
295 speex_private_t *priv = decoder->private;
296 long instant_bitrate;
297 long avg_bitrate;
299 priv->stats.total_time = (double) priv->totalsamples /
300 (double) decoder->actual_fmt.rate;
301 priv->stats.current_time = (double) priv->currentsample /
302 (double) decoder->actual_fmt.rate;
304 /* Need this test to prevent averaging in false zeros. */
305 if ((priv->bytes_read - priv->bytes_read_previous) != 0 &&
306 (priv->samples_decoded - priv->samples_decoded_previous) != 0) {
308 instant_bitrate = 8.0 * (priv->bytes_read - priv->bytes_read_previous)
309 * decoder->actual_fmt.rate
310 / (double) (priv->samples_decoded - priv->samples_decoded_previous);
312 /* A little exponential averaging to smooth things out */
313 priv->stats.instant_bitrate = AVG_FACTOR * instant_bitrate
314 + (1.0 - AVG_FACTOR) * priv->stats.instant_bitrate;
316 priv->bytes_read_previous = priv->bytes_read;
317 priv->samples_decoded_previous = priv->samples_decoded;
320 /* Don't know unless we seek the stream */
321 priv->stats.avg_bitrate = 0;
324 return malloc_decoder_stats(&priv->stats);
328 void speex_cleanup (decoder_t *decoder)
330 speex_private_t *priv = decoder->private;
332 speex_stereo_state_destroy(priv->stereo);
333 free(priv->comment_packet);
334 free(priv->output);
335 free(decoder->private);
336 free(decoder);
340 format_t speex_format = {
341 "speex",
342 &speex_can_decode,
343 &speex_init,
344 &speex_read,
345 &speex_seek,
346 &speex_statistics,
347 &speex_cleanup,
351 /* ------------------- Private functions -------------------- */
353 #define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \
354 ((buf[base+2]<<16)&0xff0000)| \
355 ((buf[base+1]<<8)&0xff00)| \
356 (buf[base]&0xff))
358 void print_speex_info(SpeexHeader *header, decoder_callbacks_t *cb,
359 void *callback_arg)
361 int modeID = header->mode;
363 if (header->vbr)
364 cb->printf_metadata(callback_arg, 2,
365 _("Ogg Speex stream: %d channel, %d Hz, %s mode (VBR)"),
366 header->nb_channels,
367 header->rate,
368 speex_mode_list[modeID]->modeName);
369 else
370 cb->printf_metadata(callback_arg, 2,
371 _("Ogg Speex stream: %d channel, %d Hz, %s mode"),
372 header->nb_channels,
373 header->rate,
374 speex_mode_list[modeID]->modeName);
376 cb->printf_metadata(callback_arg, 3,
377 _("Speex version: %s"),
378 header->speex_version);
383 void print_speex_comments(char *comments, int length,
384 decoder_callbacks_t *cb, void *callback_arg)
386 char *c = comments;
387 int len, i, nb_fields;
388 char *end;
389 char *temp = NULL;
390 int temp_len = 0;
392 if (length<8) {
393 cb->printf_error(callback_arg, WARNING, _("Invalid/corrupted comments"));
394 return;
397 /* Parse out vendor string */
399 end = c + length;
400 len = readint(c, 0);
401 c += 4;
403 if (c+len>end) {
404 cb->printf_error(callback_arg, WARNING, _("Invalid/corrupted comments"));
405 return;
409 temp_len = len + 1;
410 temp = malloc(sizeof(char) * temp_len);
412 strncpy(temp, c, len);
413 temp[len] = '\0';
415 cb->printf_metadata(callback_arg, 3, _("Encoded by: %s"), temp);
418 /* Parse out user comments */
420 c += len;
422 if (c + 4>end) {
423 cb->printf_error(callback_arg, WARNING, _("Invalid/corrupted comments"));
424 free(temp);
425 return;
428 nb_fields = readint(c, 0);
429 c += 4;
431 for (i = 0; i < nb_fields; i++) {
432 if (c + 4 > end) {
433 cb->printf_error(callback_arg, WARNING, _("Invalid/corrupted comments"));
434 free(temp);
435 return;
437 len = readint(c, 0);
438 c += 4;
439 if (c + len > end) {
440 cb->printf_error(callback_arg, WARNING, _("Invalid/corrupted comments"));
442 free(temp);
443 return;
446 if (temp_len < len + 1) {
447 temp_len = len + 1;
448 temp = realloc(temp, sizeof(char) * temp_len);
452 strncpy(temp, c, len);
453 temp[len] = '\0';
455 print_vorbis_comment(temp, cb, callback_arg);
457 c += len;
460 free(temp);
464 void *process_header(ogg_packet *op, int *frame_size,
465 SpeexHeader **header,
466 SpeexStereoState *stereo, decoder_callbacks_t *cb,
467 void *callback_arg)
469 void *st;
470 SpeexMode *mode;
471 int modeID;
472 SpeexCallback callback;
473 int enhance = ENHANCE_AUDIO;
475 *header = speex_packet_to_header((char*)op->packet, op->bytes);
476 if (!*header) {
477 cb->printf_error(callback_arg, ERROR, _("Cannot read header"));
478 return NULL;
480 if ((*header)->mode >= SPEEX_NB_MODES || (*header)->mode < 0) {
481 cb->printf_error(callback_arg, ERROR,
482 _("Mode number %d does not (any longer) exist in this version"),
483 (*header)->mode);
484 return NULL;
487 modeID = (*header)->mode;
488 mode = speex_mode_list[modeID];
490 if (mode->bitstream_version < (*header)->mode_bitstream_version) {
491 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"));
492 return NULL;
494 if (mode->bitstream_version > (*header)->mode_bitstream_version) {
495 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."));
496 return NULL;
499 st = speex_decoder_init(mode);
500 speex_decoder_ctl(st, SPEEX_SET_ENH, &enhance);
501 speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size);
503 callback.callback_id = SPEEX_INBAND_STEREO;
504 callback.func = speex_std_stereo_request_handler;
505 callback.data = stereo;
506 speex_decoder_ctl(st, SPEEX_SET_HANDLER, &callback);
508 speex_decoder_ctl(st, SPEEX_SET_SAMPLING_RATE, &(*header)->rate);
510 return st;
514 int read_speex_header (decoder_t *decoder)
516 speex_private_t *priv = decoder->private;
517 transport_t *trans = decoder->source->transport;
518 int packet_count = 0;
519 int stream_init = 0;
520 char *data;
521 int nb_read;
523 while (packet_count < 2) {
524 /*Get the ogg buffer for writing*/
525 data = ogg_sync_buffer(&priv->oy, 200);
527 /*Read bitstream from input file*/
528 nb_read = trans->read(decoder->source, data, sizeof(char), 200);
529 ogg_sync_wrote(&priv->oy, nb_read);
531 /*Loop for all complete pages we got (most likely only one)*/
532 while (ogg_sync_pageout(&priv->oy, &priv->og)==1) {
534 if (stream_init == 0) {
535 ogg_stream_init(&priv->os, ogg_page_serialno(&priv->og));
536 stream_init = 1;
539 /*Add page to the bitstream*/
540 ogg_stream_pagein(&priv->os, &priv->og);
542 /*Extract all available packets FIXME: EOS!*/
543 while (ogg_stream_packetout(&priv->os, &priv->op)==1) {
544 /*If first packet, process as Speex header*/
545 if (packet_count==0) {
546 priv->st = process_header(&priv->op,
547 &priv->frame_size,
548 &priv->header,
549 priv->stereo,
550 decoder->callbacks,
551 decoder->callback_arg);
553 if (!priv->st)
554 return 0;
556 decoder->actual_fmt.rate = priv->header->rate;
557 priv->frames_per_packet = priv->header->frames_per_packet;
558 decoder->actual_fmt.channels = priv->header->nb_channels;
559 priv->vbr = priv->header->vbr;
561 if (!priv->frames_per_packet)
562 priv->frames_per_packet=1;
565 priv->output = calloc(priv->frame_size *
566 decoder->actual_fmt.channels *
567 priv->frames_per_packet, sizeof(float));
568 priv->output_start = 0;
569 priv->output_left = 0;
571 } else if (packet_count==1){
572 priv->comment_packet_len = priv->op.bytes;
573 priv->comment_packet = malloc(sizeof(char) *
574 priv->comment_packet_len);
575 memcpy(priv->comment_packet, priv->op.packet,
576 priv->comment_packet_len);
579 packet_count++;
584 return 1;