Commit 01a472bb authored by Stan Seibert's avatar Stan Seibert

- Speex support for ogg123. Reads comments and all that, but does not

  calculate the total play length of the file.  Chained streams don't
  work yet either.  Just like FLAC, this support is optional and can
  be disabled at build time using --without-speex.

- Fixed some very silly printing bugs that prevented metadata from being
printed at the right verbosity level.

svn path=/trunk/vorbis-tools/; revision=4227
parent 784bfe67
...@@ -91,6 +91,7 @@ AC_ARG_ENABLE(ogginfo,[ --disable-ogginfo Skip building ogginfo], build_ogginf ...@@ -91,6 +91,7 @@ AC_ARG_ENABLE(ogginfo,[ --disable-ogginfo Skip building ogginfo], build_ogginf
AC_ARG_ENABLE(vcut, [ --disable-vcut Skip building vcut], build_vcut="$enableval", build_vcut="yes") AC_ARG_ENABLE(vcut, [ --disable-vcut Skip building vcut], build_vcut="$enableval", build_vcut="yes")
AC_ARG_ENABLE(vorbiscomment, [ --disable-vorbiscomment Skip building vorbiscomment], build_vorbiscomment="$enableval", build_vorbiscomment="yes") AC_ARG_ENABLE(vorbiscomment, [ --disable-vorbiscomment Skip building vorbiscomment], build_vorbiscomment="$enableval", build_vorbiscomment="yes")
AC_ARG_WITH(flac, [ --without-flac Do not compile FLAC support], build_flac="$enableval", build_flac="yes") AC_ARG_WITH(flac, [ --without-flac Do not compile FLAC support], build_flac="$enableval", build_flac="yes")
AC_ARG_WITH(speex, [ --without-speex Do not compile Speex support], build_speex="$enableval", build_speex="yes")
dnl -------------------------------------------------- dnl --------------------------------------------------
dnl Check for generally needed libraries dnl Check for generally needed libraries
...@@ -125,6 +126,8 @@ if test "x$build_ogg123" = xyes; then ...@@ -125,6 +126,8 @@ if test "x$build_ogg123" = xyes; then
fi fi
fi fi
dnl -------------------- FLAC ----------------------
FLAC_LIBS= FLAC_LIBS=
AC_CHECK_LIB(m,log,FLAC_EXTRA_LIBS="-lm") AC_CHECK_LIB(m,log,FLAC_EXTRA_LIBS="-lm")
...@@ -147,6 +150,31 @@ fi ...@@ -147,6 +150,31 @@ fi
AM_CONDITIONAL(HAVE_LIBFLAC, test "x$build_flac" = xyes) AM_CONDITIONAL(HAVE_LIBFLAC, test "x$build_flac" = xyes)
AC_SUBST(FLAC_LIBS) AC_SUBST(FLAC_LIBS)
dnl ------------------- Speex ------------------------
SPEEX_LIBS=
AC_CHECK_LIB(m,log,SPEEX_EXTRA_LIBS="-lm")
AC_CHECK_LIB(speex, speex_decoder_init,have_libspeex=yes,
AC_MSG_WARN(libspeex missing)
have_libspeex=no, $SPEEX_EXTRA_LIBS
)
AC_CHECK_HEADER(speex.h,,
AC_MSG_WARN(libspeex headers missing)
have_libspeex=no,[ ])
if test "x$have_libspeex" = xyes; then
if test "x$build_speex" = xyes; then
AC_DEFINE(HAVE_LIBSPEEX)
SPEEX_LIBS="$SPEEX_EXTRA_LIBS -lspeex"
fi
else
build_speex="no"
fi
AM_CONDITIONAL(HAVE_LIBSPEEX, test "x$build_speex" = xyes)
AC_SUBST(SPEEX_LIBS)
dnl -------------------------------------------------- dnl --------------------------------------------------
dnl Check for library functions dnl Check for library functions
dnl -------------------------------------------------- dnl --------------------------------------------------
......
...@@ -14,18 +14,23 @@ ogg123sources = audio.c buffer.c callbacks.c \ ...@@ -14,18 +14,23 @@ ogg123sources = audio.c buffer.c callbacks.c \
format.h ogg123.h playlist.h status.h \ format.h ogg123.h playlist.h status.h \
transport.h vorbis_comments.h transport.h vorbis_comments.h
flacsources = flac_format.c easyflac.c easyflac.h flacsources = flac_format.c easyflac.c easyflac.h
speexsources = speex_format.c
if HAVE_LIBFLAC if HAVE_LIBFLAC
flaccompile = $(flacsources)
buildsources = $(ogg123sources) $(flacsources)
flaclibs = @FLAC_LIBS@ flaclibs = @FLAC_LIBS@
else else
flaccompile =
buildsources = $(ogg123sources)
flaclibs = flaclibs =
endif
if HAVE_LIBSPEEX
speexcompile = $(speexsources)
speexlibs = @SPEEX_LIBS@
else
speexcompile =
speexlibs =
endif endif
...@@ -45,16 +50,17 @@ INCLUDES = @OGG_CFLAGS@ @VORBIS_CFLAGS@ @AO_CFLAGS@ @CURL_CFLAGS@ \ ...@@ -45,16 +50,17 @@ INCLUDES = @OGG_CFLAGS@ @VORBIS_CFLAGS@ @AO_CFLAGS@ @CURL_CFLAGS@ \
ogg123_LDADD = @SHARE_LIBS@ \ ogg123_LDADD = @SHARE_LIBS@ \
@VORBISFILE_LIBS@ @VORBIS_LIBS@ @OGG_LIBS@ @AO_LIBS@ \ @VORBISFILE_LIBS@ @VORBIS_LIBS@ @OGG_LIBS@ @AO_LIBS@ \
@SOCKET_LIBS@ @LIBICONV@ @CURL_LIBS@ @PTHREAD_CFLAGS@ \ @SOCKET_LIBS@ @LIBICONV@ @CURL_LIBS@ @PTHREAD_CFLAGS@ \
@PTHREAD_LIBS@ @I18N_LIBS@ $(flaclibs) @PTHREAD_LIBS@ @I18N_LIBS@ $(flaclibs) $(speexlibs)
ogg123_DEPENDENCIES = @SHARE_LIBS@ ogg123_DEPENDENCIES = @SHARE_LIBS@
ogg123_SOURCES = $(buildsources) ogg123_SOURCES = $(ogg123sources) $(speexcompile) $(flaccompile)
man_MANS = $(mans) man_MANS = $(mans)
doc_DATA = $(docs) doc_DATA = $(docs)
endif endif
EXTRA_DIST = $(ogg123sources) $(flacsources) $(mans) $(docs) EXTRA_DIST = $(ogg123sources) $(flacsources) $(speexsources) $(mans) $(docs)
debug: debug:
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* * * *
******************************************************************** ********************************************************************
last mod: $Id: callbacks.c,v 1.7 2002/07/06 04:27:19 msmith Exp $ last mod: $Id: callbacks.c,v 1.8 2003/01/12 20:19:22 volsung Exp $
********************************************************************/ ********************************************************************/
...@@ -351,5 +351,6 @@ void decoder_buffered_metadata_callback (void *arg, int verbosity, ...@@ -351,5 +351,6 @@ void decoder_buffered_metadata_callback (void *arg, int verbosity,
} }
} }
sm_arg->verbosity = verbosity;
buffer_append_action_at_end(buf, &status_message_action, sm_arg); buffer_append_action_at_end(buf, &status_message_action, sm_arg);
} }
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* * * *
******************************************************************** ********************************************************************
last mod: $Id: flac_format.c,v 1.1 2003/01/11 22:51:44 volsung Exp $ last mod: $Id: flac_format.c,v 1.2 2003/01/12 20:19:22 volsung Exp $
********************************************************************/ ********************************************************************/
...@@ -205,11 +205,11 @@ int flac_read (decoder_t *decoder, void *ptr, int nbytes, int *eos, ...@@ -205,11 +205,11 @@ int flac_read (decoder_t *decoder, void *ptr, int nbytes, int *eos,
decoder->actual_fmt.channels = priv->channels; decoder->actual_fmt.channels = priv->channels;
decoder->actual_fmt.word_size = ((priv->bits_per_sample + 7) / 8); decoder->actual_fmt.word_size = ((priv->bits_per_sample + 7) / 8);
print_flac_stream_info(decoder);
if (priv->comments != NULL) if (priv->comments != NULL)
print_flac_comments(&priv->comments->data.vorbis_comment, cb, print_flac_comments(&priv->comments->data.vorbis_comment, cb,
decoder->callback_arg); decoder->callback_arg);
print_flac_stream_info(decoder);
priv->bos = 0; priv->bos = 0;
} }
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* * * *
******************************************************************** ********************************************************************
last mod: $Id: format.c,v 1.4 2003/01/11 22:51:44 volsung Exp $ last mod: $Id: format.c,v 1.5 2003/01/12 20:19:22 volsung Exp $
********************************************************************/ ********************************************************************/
...@@ -23,17 +23,24 @@ ...@@ -23,17 +23,24 @@
#include "i18n.h" #include "i18n.h"
extern format_t oggvorbis_format; extern format_t oggvorbis_format;
extern format_t speex_format;
#ifdef HAVE_LIBFLAC #ifdef HAVE_LIBFLAC
extern format_t flac_format; extern format_t flac_format;
extern format_t oggflac_format; extern format_t oggflac_format;
#endif #endif
#ifdef HAVE_LIBSPEEX
extern format_t speex_format;
#endif
format_t *formats[] = { format_t *formats[] = {
#ifdef HAVE_LIBFLAC #ifdef HAVE_LIBFLAC
&flac_format, &flac_format,
&oggflac_format, &oggflac_format,
#endif
#ifdef HAVE_LIBSPEEX
&speex_format,
#endif #endif
&oggvorbis_format, &oggvorbis_format,
NULL }; NULL };
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* * * *
******************************************************************** ********************************************************************
last mod: $Id: ogg123.c,v 1.65 2002/07/06 19:12:18 volsung Exp $ last mod: $Id: ogg123.c,v 1.66 2003/01/12 20:19:22 volsung Exp $
********************************************************************/ ********************************************************************/
...@@ -416,11 +416,11 @@ void play (char *source_string) ...@@ -416,11 +416,11 @@ void play (char *source_string)
/* Select appropriate callbacks */ /* Select appropriate callbacks */
if (audio_buffer != NULL) { if (audio_buffer != NULL) {
decoder_callbacks.printf_error = &decoder_buffered_error_callback; decoder_callbacks.printf_error = &decoder_buffered_error_callback;
decoder_callbacks.printf_metadata = &decoder_buffered_error_callback; decoder_callbacks.printf_metadata = &decoder_buffered_metadata_callback;
decoder_callbacks_arg = audio_buffer; decoder_callbacks_arg = audio_buffer;
} else { } else {
decoder_callbacks.printf_error = &decoder_error_callback; decoder_callbacks.printf_error = &decoder_error_callback;
decoder_callbacks.printf_metadata = &decoder_error_callback; decoder_callbacks.printf_metadata = &decoder_metadata_callback;
decoder_callbacks_arg = NULL; decoder_callbacks_arg = NULL;
} }
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* * * *
******************************************************************** ********************************************************************
last mod: $Id: oggvorbis_format.c,v 1.10 2003/01/11 22:51:44 volsung Exp $ last mod: $Id: oggvorbis_format.c,v 1.11 2003/01/12 20:19:22 volsung Exp $
********************************************************************/ ********************************************************************/
...@@ -124,8 +124,8 @@ int ovf_read (decoder_t *decoder, void *ptr, int nbytes, int *eos, ...@@ -124,8 +124,8 @@ int ovf_read (decoder_t *decoder, void *ptr, int nbytes, int *eos,
decoder->actual_fmt.channels = priv->vi->channels; decoder->actual_fmt.channels = priv->vi->channels;
print_vorbis_comments(priv->vc, cb, decoder->callback_arg);
print_vorbis_stream_info(decoder); print_vorbis_stream_info(decoder);
print_vorbis_comments(priv->vc, cb, decoder->callback_arg);
priv->bos = 0; priv->bos = 0;
} }
......
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
* THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
* PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE Ogg123 SOURCE CODE IS (C) COPYRIGHT 2000-2003 *
* by Stan Seibert <volsung@xiph.org> AND OTHER CONTRIBUTORS *
* http://www.xiph.org/ *
* *
********************************************************************
last mod: $Id: speex_format.c,v 1.1 2003/01/12 20:19:22 volsung Exp $
********************************************************************/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <speex.h>
#include <speex_header.h>
#include <speex_stereo.h>
#include <speex_callbacks.h>
#include <ogg/ogg.h>
#include "transport.h"
#include "format.h"
#include "vorbis_comments.h"
#include "utf8.h"
#include "i18n.h"
/* Note that this file contains gratuitous cut and paste from speexdec.c. */
/* Use speex's audio enhancement feature */
#define ENHANCE_AUDIO 1
typedef struct speex_private_t {
ogg_sync_state oy;
ogg_page og;
ogg_packet op;
ogg_stream_state os;
SpeexBits bits;
SpeexStereoState stereo;
SpeexHeader *header;
void *st;
char *comment_packet;
int comment_packet_len;
float *output; /* Has frame_size * [number of channels] * frames_per_packet
elements */
int output_start;
int output_left;
int frames_per_packet;
int frame_size;
int vbr;
int bos; /* If we are at the beginning (before headers) of a stream */
int eof; /* If we've read the end of the data source (but there still might
be data in the buffers */
/* For calculating bitrate stats */
long samples_decoded;
long samples_decoded_previous;
long bytes_read;
long bytes_read_previous;
long totalsamples;
long currentsample;
decoder_stats_t stats;
} speex_private_t;
/* Forward declarations */
format_t speex_format;
/* Private functions declarations */
void print_speex_info(SpeexHeader *header, decoder_callbacks_t *cb,
void *callback_arg);
void print_speex_comments(char *comments, int length,
decoder_callbacks_t *cb, void *callback_arg);
void *process_header(ogg_packet *op, int *frame_size,
SpeexHeader **header,
SpeexStereoState *stereo, decoder_callbacks_t *cb,
void *callback_arg);
int read_speex_header(decoder_t *decoder);
/* ----------------------------------------------------------- */
int speex_can_decode (data_source_t *source)
{
char buf[36];
int len;
len = source->transport->peek(source, buf, sizeof(char), 36);
if (len >= 32 && memcmp(buf, "OggS", 4) == 0
&& memcmp(buf+28, "Speex ", 8) == 0) /* 3 trailing spaces */
return 1;
else
return 0;
}
decoder_t* speex_init (data_source_t *source, ogg123_options_t *ogg123_opts,
audio_format_t *audio_fmt,
decoder_callbacks_t *callbacks, void *callback_arg)
{
decoder_t *decoder;
speex_private_t *private;
int ret;
/* Allocate data source structures */
decoder = malloc(sizeof(decoder_t));
private = malloc(sizeof(speex_private_t));
if (decoder != NULL && private != NULL) {
decoder->source = source;
decoder->actual_fmt = decoder->request_fmt = *audio_fmt;
decoder->format = &speex_format;
decoder->callbacks = callbacks;
decoder->callback_arg = callback_arg;
decoder->private = private;
private->bos = 1;
private->eof = 0;
private->samples_decoded = private->samples_decoded_previous = 0;
private->bytes_read = private->bytes_read_previous = 0;
private->currentsample = 0;
private->comment_packet = NULL;
private->comment_packet_len = 0;
private->header = NULL;
private->stats.total_time = 0.0;
private->stats.current_time = 0.0;
private->stats.instant_bitrate = 0;
private->stats.avg_bitrate = 0;
} else {
fprintf(stderr, _("Error: Out of memory.\n"));
exit(1);
}
/* Initialize structures */
ogg_sync_init(&private->oy);
speex_bits_init(&private->bits);
ret = 1;
if (ret < 0) {
free(private);
/* free(source); nope. caller frees. */
return NULL;
}
return decoder;
}
int speex_read (decoder_t *decoder, void *ptr, int nbytes, int *eos,
audio_format_t *audio_fmt)
{
speex_private_t *priv = decoder->private;
decoder_callbacks_t *cb = decoder->callbacks;
transport_t *trans = decoder->source->transport;
int bytes_requested = nbytes;
int ret;
short *out = (short *) ptr;
/* Read comments and audio info at the start of a logical bitstream */
if (priv->bos) {
ret = read_speex_header(decoder);
if (!ret) {
*eos = 1;
return 0; /* Bail out! */
}
print_speex_info(priv->header, cb, decoder->callback_arg);
if (priv->comment_packet != NULL)
print_speex_comments(priv->comment_packet, priv->comment_packet_len,
cb, decoder->callback_arg);
priv->bos = 0;
}
*audio_fmt = decoder->actual_fmt;
while (nbytes) {
char *data;
int i, j, nb_read;
/* First see if there is anything left in the output buffer and
empty it out */
if (priv->output_left > 0) {
int to_copy = nbytes / (2 * audio_fmt->channels);
to_copy *= audio_fmt->channels;
to_copy = priv->output_left < to_copy ? priv->output_left : to_copy;
/* Integerify it! */
for (i = 0; i < to_copy; i++)
out[i]=(ogg_int16_t)priv->output[i+priv->output_start];
out += to_copy;
priv->output_start += to_copy;
priv->output_left -= to_copy;
priv->currentsample += to_copy / audio_fmt->channels;
nbytes -= to_copy * 2;
} else if (ogg_stream_packetout(&priv->os, &priv->op) == 1) {
float *temp_output = priv->output;
/* Decode some more samples */
/*Copy Ogg packet to Speex bitstream*/
speex_bits_read_from(&priv->bits, (char*)priv->op.packet,
priv->op.bytes);
for (j = 0;j < priv->frames_per_packet; j++) {
/*Decode frame*/
speex_decode(priv->st, &priv->bits, temp_output);
if (audio_fmt->channels==2)
speex_decode_stereo(temp_output, priv->frame_size, &priv->stereo);
priv->samples_decoded += priv->frame_size;
/*PCM saturation (just in case)*/
for (i=0;i < priv->frame_size * audio_fmt->channels; i++) {
if (temp_output[i]>32000.0)
temp_output[i]=32000.0;
else if (temp_output[i]<-32000.0)
temp_output[i]=-32000.0;
}
temp_output += priv->frame_size * audio_fmt->channels;
}
priv->output_start = 0;
priv->output_left = priv->frame_size * audio_fmt->channels *
priv->frames_per_packet;
} else if (ogg_sync_pageout(&priv->oy, &priv->og) == 1) {
/* Read in another ogg page */
ogg_stream_pagein(&priv->os, &priv->og);
} else if (!priv->eof) {
/* Finally, pull in some more data and try again on the next pass */
/*Get the ogg buffer for writing*/
data = ogg_sync_buffer(&priv->oy, 200);
/*Read bitstream from input file*/
nb_read = trans->read(decoder->source, data, sizeof(char), 200);
if (nb_read == 0)
priv->eof = 1; /* We've read the end of the file */
ogg_sync_wrote(&priv->oy, nb_read);
priv->bytes_read += nb_read;
} else {
*eos = 1;
break;
}
}
return bytes_requested - nbytes;
}
int speex_seek (decoder_t *decoder, double offset, int whence)
{
speex_private_t *priv = decoder->private;
return 0;
}
#define AVG_FACTOR 0.7
decoder_stats_t *speex_statistics (decoder_t *decoder)
{
speex_private_t *priv = decoder->private;
long instant_bitrate;
long avg_bitrate;
priv->stats.total_time = (double) priv->totalsamples /
(double) decoder->actual_fmt.rate;
priv->stats.current_time = (double) priv->currentsample /
(double) decoder->actual_fmt.rate;
/* Need this test to prevent averaging in false zeros. */
if ((priv->bytes_read - priv->bytes_read_previous) != 0 &&
(priv->samples_decoded - priv->samples_decoded_previous) != 0) {
instant_bitrate = 8.0 * (priv->bytes_read - priv->bytes_read_previous)
* decoder->actual_fmt.rate
/ (double) (priv->samples_decoded - priv->samples_decoded_previous);
/* A little exponential averaging to smooth things out */
priv->stats.instant_bitrate = AVG_FACTOR * instant_bitrate
+ (1.0 - AVG_FACTOR) * priv->stats.instant_bitrate;
priv->bytes_read_previous = priv->bytes_read;
priv->samples_decoded_previous = priv->samples_decoded;
}
/* Don't know unless we seek the stream */
priv->stats.avg_bitrate = 0;
return malloc_decoder_stats(&priv->stats);
}
void speex_cleanup (decoder_t *decoder)
{
speex_private_t *priv = decoder->private;
free(priv->comment_packet);
free(priv->output);
free(decoder->private);
free(decoder);
}
format_t speex_format = {
"speex",
&speex_can_decode,
&speex_init,
&speex_read,
&speex_seek,
&speex_statistics,
&speex_cleanup,
};
/* ------------------- Private functions -------------------- */
#define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \
((buf[base+2]<<16)&0xff0000)| \
((buf[base+1]<<8)&0xff00)| \
(buf[base]&0xff))
void print_speex_info(SpeexHeader *header, decoder_callbacks_t *cb,
void *callback_arg)
{