Commit cd41c05e authored by Stan Seibert's avatar Stan Seibert

ogg123 now plays FLAC files!

-  Added stuff into configure.in to detect FLAC libraries and headers
   (should autodetect correctly, but you can also force it off with
   --without-flac) as well as setup conditional building.
- FLAC is not required to build ogg123 (unlike curl).
- Reads both FLAC and Ogg FLAC
- Refactored vorbis comment pretty printing into separate file since it
  is shared by both FLAC and Vorbis readers (and future Speex reader will
  need it too)
- Fixed bug caused by assuming Vorbis comments were null terminated.

svn path=/trunk/vorbis-tools/; revision=4222
parent fd0af034
......@@ -90,7 +90,7 @@ AC_ARG_ENABLE(oggenc, [ --disable-oggenc Skip building oggenc], build_oggenc=
AC_ARG_ENABLE(ogginfo,[ --disable-ogginfo Skip building ogginfo], build_ogginfo="$enableval", build_ogginfo="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_WITH(flac, [ --without-flac Do not compile FLAC support], build_flac="$enableval", build_flac="yes")
dnl --------------------------------------------------
dnl Check for generally needed libraries
......@@ -110,7 +110,7 @@ AC_CHECK_LIB(socket, socket, SOCKET_LIBS="-lsocket")
AC_CHECK_LIB(nsl, gethostbyname, SOCKET_LIBS="-lnsl $SOCKET_LIBS")
dnl --------------------------------------------------
dnl Check for ogg123 critical libraries
dnl Check for ogg123 critical libraries and other optional libraries
dnl --------------------------------------------------
if test "x$build_ogg123" = xyes; then
......@@ -124,7 +124,29 @@ if test "x$build_ogg123" = xyes; then
AC_MSG_WARN([Prerequisites for ogg123 not met, ogg123 will not be built])
fi
fi
FLAC_LIBS=
AC_CHECK_LIB(m,log,FLAC_EXTRA_LIBS="-lm")
AC_CHECK_LIB(FLAC, FLAC__stream_decoder_process_single,have_libFLAC=yes,
AC_MSG_WARN(libFLAC missing)
have_libFLAC=no, $FLAC_EXTRA_LIBS
)
AC_CHECK_HEADER(FLAC/stream_decoder.h,,
AC_MSG_WARN(libFLAC headers missing)
have_libFLAC=no,[ ])
if test "x$have_libFLAC" = xyes; then
if test "x$build_flac" = xyes; then
AC_DEFINE(HAVE_LIBFLAC)
FLAC_LIBS="$FLAC_EXTRA_LIBS -lFLAC -lOggFLAC"
fi
else
build_flac="no"
fi
AM_CONDITIONAL(HAVE_LIBFLAC, test "x$build_flac" = xyes)
AC_SUBST(FLAC_LIBS)
dnl --------------------------------------------------
dnl Check for library functions
dnl --------------------------------------------------
......
......@@ -8,11 +8,25 @@ ogg123sources = audio.c buffer.c callbacks.c \
cfgfile_options.c cmdline_options.c \
file_transport.c format.c http_transport.c \
ogg123.c oggvorbis_format.c playlist.c \
status.c transport.c \
status.c transport.c vorbis_comments.c \
audio.h buffer.h callbacks.h compat.h \
cfgfile_options.h cmdline_options.h \
format.h ogg123.h playlist.h status.h \
transport.h
transport.h vorbis_comments.h
flacsources = flac_format.c easyflac.c easyflac.h
if HAVE_LIBFLAC
buildsources = $(ogg123sources) $(flacsources)
flaclibs = @FLAC_LIBS@
else
buildsources = $(ogg123sources)
flaclibs =
endif
if BUILD_OGG123
......@@ -31,16 +45,16 @@ INCLUDES = @OGG_CFLAGS@ @VORBIS_CFLAGS@ @AO_CFLAGS@ @CURL_CFLAGS@ \
ogg123_LDADD = @SHARE_LIBS@ \
@VORBISFILE_LIBS@ @VORBIS_LIBS@ @OGG_LIBS@ @AO_LIBS@ \
@SOCKET_LIBS@ @LIBICONV@ @CURL_LIBS@ @PTHREAD_CFLAGS@ \
@PTHREAD_LIBS@ @I18N_LIBS@
@PTHREAD_LIBS@ @I18N_LIBS@ $(flaclibs)
ogg123_DEPENDENCIES = @SHARE_LIBS@
ogg123_SOURCES = $(ogg123sources)
ogg123_SOURCES = $(buildsources)
man_MANS = $(mans)
doc_DATA = $(docs)
endif
EXTRA_DIST = $(ogg123sources) $(mans) $(docs)
EXTRA_DIST = $(ogg123sources) $(flacsources) $(mans) $(docs)
debug:
......
This diff is collapsed.
/* EasyFLAC - A thin decoding wrapper around libFLAC and libOggFLAC to
* make your code less ugly.
*
* Copyright 2003 - Stan Seibert <volsung@xiph.org>
* This code is licensed under a BSD style license:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Xiph.org Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
************************************************************************
*
* The motivation for this wrapper is to avoid issues where you need to
* decode both FLAC and Ogg FLAC but don't want to enclose all of your code
* in enormous if blocks where the body of the two branches is essentially
* the same. For example, you don't want to do something like this:
*
* if (is_ogg_flac)
* {
* OggFLAC__blah_blah();
* OggFLAC__more_stuff();
* }
* else
* {
* FLAC__blah_blah();
* FLAC__more_stuff();
* }
*
* when you really just want this:
*
* EasyFLAC__blah_blah();
* EasyFLAC__more_stuff();
*
* This is even more cumbersome when you have to deal with constants.
*
* EasyFLAC uses essentially the same API as
* FLAC__stream_decoder with two additions:
*
* - EasyFLAC__is_oggflac() for those rare occassions when you might
* need to distiguish the difference cases.
*
* - EasyFLAC__stream_decoder_new() takes a parameter to select when
* you are reading FLAC or Ogg FLAC.
*
* The constants are all FLAC__stream_decoder_*.
*
* WARNING: Always call EasyFLAC__set_client_data() even if all you
* want to do is set the client data to NULL.
*/
#ifndef __EASYFLAC_H
#define __EASYFLAC_H
#include <FLAC/stream_decoder.h>
#include <OggFLAC/stream_decoder.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct EasyFLAC__StreamDecoder EasyFLAC__StreamDecoder;
typedef FLAC__StreamDecoderReadStatus (*EasyFLAC__StreamDecoderReadCallback)(const EasyFLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data);
typedef FLAC__StreamDecoderWriteStatus (*EasyFLAC__StreamDecoderWriteCallback)(const EasyFLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
typedef void (*EasyFLAC__StreamDecoderMetadataCallback)(const EasyFLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
typedef void (*EasyFLAC__StreamDecoderErrorCallback)(const EasyFLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
struct EasyFLAC__StreamDecoder {
FLAC__bool is_oggflac;
FLAC__StreamDecoder *flac;
OggFLAC__StreamDecoder *oggflac;
struct {
EasyFLAC__StreamDecoderReadCallback read;
EasyFLAC__StreamDecoderWriteCallback write;
EasyFLAC__StreamDecoderMetadataCallback metadata;
EasyFLAC__StreamDecoderErrorCallback error;
void *client_data;
} callbacks;
};
FLAC__bool EasyFLAC__is_oggflac(EasyFLAC__StreamDecoder *decoder);
EasyFLAC__StreamDecoder *EasyFLAC__stream_decoder_new(FLAC__bool is_oggflac);
void EasyFLAC__stream_decoder_delete(EasyFLAC__StreamDecoder *decoder);
FLAC__bool EasyFLAC__set_read_callback(EasyFLAC__StreamDecoder *decoder, EasyFLAC__StreamDecoderReadCallback value);
FLAC__bool EasyFLAC__set_write_callback(EasyFLAC__StreamDecoder *decoder, EasyFLAC__StreamDecoderWriteCallback value);
FLAC__bool EasyFLAC__set_metadata_callback(EasyFLAC__StreamDecoder *decoder, EasyFLAC__StreamDecoderMetadataCallback value);
FLAC__bool EasyFLAC__set_error_callback(EasyFLAC__StreamDecoder *decoder, EasyFLAC__StreamDecoderErrorCallback value);
FLAC__bool EasyFLAC__set_client_data(EasyFLAC__StreamDecoder *decoder, void *value);
FLAC__bool EasyFLAC__set_metadata_respond(EasyFLAC__StreamDecoder *decoder, FLAC__MetadataType type);
FLAC__bool EasyFLAC__set_metadata_respond_application(EasyFLAC__StreamDecoder *decoder, const FLAC__byte id[4]);
FLAC__bool EasyFLAC__set_metadata_respond_all(EasyFLAC__StreamDecoder *decoder);
FLAC__bool EasyFLAC__set_metadata_ignore(EasyFLAC__StreamDecoder *decoder, FLAC__MetadataType type);
FLAC__bool EasyFLAC__set_metadata_ignore_application(EasyFLAC__StreamDecoder *decoder, const FLAC__byte id[4]);
FLAC__bool EasyFLAC__set_metadata_ignore_all(EasyFLAC__StreamDecoder *decoder);
FLAC__StreamDecoderState EasyFLAC__get_state(const EasyFLAC__StreamDecoder *decoder);
unsigned EasyFLAC__get_channels(const EasyFLAC__StreamDecoder *decoder);
FLAC__ChannelAssignment EasyFLAC__get_channel_assignment(const EasyFLAC__StreamDecoder *decoder);
unsigned EasyFLAC__get_bits_per_sample(const EasyFLAC__StreamDecoder *decoder);
unsigned EasyFLAC__get_sample_rate(const EasyFLAC__StreamDecoder *decoder);
unsigned EasyFLAC__get_blocksize(const EasyFLAC__StreamDecoder *decoder);
FLAC__StreamDecoderState EasyFLAC__init(EasyFLAC__StreamDecoder *decoder);
void EasyFLAC__finish(EasyFLAC__StreamDecoder *decoder);
FLAC__bool EasyFLAC__flush(EasyFLAC__StreamDecoder *decoder);
FLAC__bool EasyFLAC__reset(EasyFLAC__StreamDecoder *decoder);
FLAC__bool EasyFLAC__process_single(EasyFLAC__StreamDecoder *decoder);
FLAC__bool EasyFLAC__process_until_end_of_metadata(EasyFLAC__StreamDecoder *decoder);
FLAC__bool EasyFLAC__process_until_end_of_stream(EasyFLAC__StreamDecoder *decoder);
#ifdef __cplusplus
}
#endif
#endif
This diff is collapsed.
......@@ -11,7 +11,7 @@
* *
********************************************************************
last mod: $Id: format.c,v 1.3 2002/01/26 11:06:37 segher Exp $
last mod: $Id: format.c,v 1.4 2003/01/11 22:51:44 volsung Exp $
********************************************************************/
......@@ -24,7 +24,19 @@
extern format_t oggvorbis_format;
format_t *formats[] = { &oggvorbis_format, NULL };
#ifdef HAVE_LIBFLAC
extern format_t flac_format;
extern format_t oggflac_format;
#endif
format_t *formats[] = {
#ifdef HAVE_LIBFLAC
&flac_format,
&oggflac_format,
#endif
&oggvorbis_format,
NULL };
format_t *get_format_by_name (char *name)
......
......@@ -11,7 +11,7 @@
* *
********************************************************************
last mod: $Id: oggvorbis_format.c,v 1.9 2002/07/19 10:31:53 msmith Exp $
last mod: $Id: oggvorbis_format.c,v 1.10 2003/01/11 22:51:44 volsung Exp $
********************************************************************/
......@@ -23,6 +23,7 @@
#include <vorbis/vorbisfile.h>
#include "transport.h"
#include "format.h"
#include "vorbis_comments.h"
#include "utf8.h"
#include "i18n.h"
......@@ -43,26 +44,9 @@ format_t oggvorbis_format;
ov_callbacks vorbisfile_callbacks;
/* Vorbis comment keys that need special formatting. */
struct {
char *key; /* includes the '=' for programming convenience */
char *formatstr; /* formatted output */
} vorbis_comment_keys[] = {
{"TRACKNUMBER=", N_("Track number:")},
{"REPLAYGAIN_TRACK_GAIN=", N_("ReplayGain (Track):")},
{"REPLAYGAIN_ALBUM_GAIN=", N_("ReplayGain (Album):")},
{"REPLAYGAIN_TRACK_PEAK=", N_("ReplayGain (Track) Peak:")},
{"REPLAYGAIN_ALBUM_PEAK=", N_("ReplayGain (Album) Peak:")},
{"COPYRIGHT=", N_("Copyright")},
{"=", N_("Comment:")},
{NULL, N_("Comment:")}
};
/* Private functions declarations */
char *lookup_comment_prettyprint (char *comment, int *offset);
void print_stream_comments (decoder_t *decoder);
void print_stream_info (decoder_t *decoder);
void print_vorbis_stream_info (decoder_t *decoder);
void print_vorbis_comments (vorbis_comment *vc, decoder_callbacks_t *cb,
void *callback_arg);
/* ----------------------------------------------------------- */
......@@ -139,8 +123,9 @@ int ovf_read (decoder_t *decoder, void *ptr, int nbytes, int *eos,
decoder->actual_fmt.rate = priv->vi->rate;
decoder->actual_fmt.channels = priv->vi->channels;
print_stream_comments(decoder);
print_stream_info(decoder);
print_vorbis_comments(priv->vc, cb, decoder->callback_arg);
print_vorbis_stream_info(decoder);
priv->bos = 0;
}
......@@ -304,91 +289,7 @@ ov_callbacks vorbisfile_callbacks = {
/* ------------------- Private functions -------------------- */
char *lookup_comment_prettyprint (char *comment, int *offset)
{
int i, j;
char *s;
/* Search for special-case formatting */
for (i = 0; vorbis_comment_keys[i].key != NULL; i++) {
if ( !strncasecmp (vorbis_comment_keys[i].key, comment,
strlen(vorbis_comment_keys[i].key)) ) {
*offset = strlen(vorbis_comment_keys[i].key);
s = malloc(strlen(vorbis_comment_keys[i].formatstr) + 1);
if (s == NULL) {
fprintf(stderr, _("Error: Out of memory.\n"));
exit(1);
};
strcpy(s, vorbis_comment_keys[i].formatstr);
return s;
}
}
/* Use default formatting */
j = strcspn(comment, "=");
if (j) {
*offset = j + 1;
s = malloc(j + 2);
if (s == NULL) {
fprintf(stderr, _("Error: Out of memory.\n"));
exit(1);
};
strncpy(s, comment, j);
strcpy(s + j, ":");
/* Capitalize */
s[0] = toupper(s[0]);
for (i = 1; i < j; i++) {
s[i] = tolower(s[i]);
};
return s;
}
/* Unrecognized comment, use last format string */
*offset = 0;
s = malloc(strlen(vorbis_comment_keys[i].formatstr) + 1);
if (s == NULL) {
fprintf(stderr, _("Error: Out of memory.\n"));
exit(1);
};
strcpy(s, vorbis_comment_keys[i].formatstr);
return s;
}
void print_stream_comments (decoder_t *decoder)
{
ovf_private_t *priv = decoder->private;
decoder_callbacks_t *cb = decoder->callbacks;
char *comment, *comment_prettyprint;
int offset;
int i;
if (cb == NULL || cb->printf_metadata == NULL)
return;
for (i = 0; i < priv->vc->comments; i++) {
char *decoded_value;
comment = priv->vc->user_comments[i];
comment_prettyprint = lookup_comment_prettyprint(comment, &offset);
if (utf8_decode(comment + offset, &decoded_value) >= 0) {
cb->printf_metadata(decoder->callback_arg, 1,
"%s %s", comment_prettyprint, decoded_value);
free(decoded_value);
} else
cb->printf_metadata(decoder->callback_arg, 1,
"%s %s", comment_prettyprint, comment + offset);
free(comment_prettyprint);
}
}
void print_stream_info (decoder_t *decoder)
void print_vorbis_stream_info (decoder_t *decoder)
{
ovf_private_t *priv = decoder->private;
decoder_callbacks_t *cb = decoder->callbacks;
......@@ -419,3 +320,26 @@ void print_stream_info (decoder_t *decoder)
_("Encoded by: %s"), priv->vc->vendor);
}
void print_vorbis_comments (vorbis_comment *vc, decoder_callbacks_t *cb,
void *callback_arg)
{
int i;
char *temp = NULL;
int temp_len = 0;
for (i = 0; i < vc->comments; i++) {
/* Gotta null terminate these things */
if (temp_len < vc->comment_lengths[i] + 1) {
temp_len = vc->comment_lengths[i] + 1;
temp = realloc(temp, sizeof(char) * temp_len);
}
strncpy(temp, vc->user_comments[i], vc->comment_lengths[i]);
temp[vc->comment_lengths[i]] = '\0';
print_vorbis_comment(temp, cb, callback_arg);
}
free(temp);
}
/********************************************************************
* *
* 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-2001 *
* by Stan Seibert <volsung@xiph.org> AND OTHER CONTRIBUTORS *
* http://www.xiph.org/ *
* *
********************************************************************
last mod: $Id: vorbis_comments.c,v 1.1 2003/01/11 22:51:44 volsung Exp $
********************************************************************/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <ogg/ogg.h>
#include <vorbis/codec.h>
#include <vorbis/vorbisfile.h>
#include "format.h"
#include "utf8.h"
#include "i18n.h"
/* Vorbis comment keys that need special formatting. */
struct {
char *key; /* includes the '=' for programming convenience */
char *formatstr; /* formatted output */
} vorbis_comment_keys[] = {
{"TRACKNUMBER=", N_("Track number:")},
{"REPLAYGAIN_TRACK_GAIN=", N_("ReplayGain (Track):")},
{"REPLAYGAIN_ALBUM_GAIN=", N_("ReplayGain (Album):")},
{"REPLAYGAIN_TRACK_PEAK=", N_("ReplayGain (Track) Peak:")},
{"REPLAYGAIN_ALBUM_PEAK=", N_("ReplayGain (Album) Peak:")},
{"COPYRIGHT=", N_("Copyright")},
{"=", N_("Comment:")},
{NULL, N_("Comment:")}
};
char *lookup_comment_prettyprint (char *comment, int *offset)
{
int i, j;
char *s;
/* Search for special-case formatting */
for (i = 0; vorbis_comment_keys[i].key != NULL; i++) {
if ( !strncasecmp (vorbis_comment_keys[i].key, comment,
strlen(vorbis_comment_keys[i].key)) ) {
*offset = strlen(vorbis_comment_keys[i].key);
s = malloc(strlen(vorbis_comment_keys[i].formatstr) + 1);
if (s == NULL) {
fprintf(stderr, _("Error: Out of memory.\n"));
exit(1);
};
strcpy(s, vorbis_comment_keys[i].formatstr);
return s;
}
}
/* Use default formatting */
j = strcspn(comment, "=");
if (j) {
*offset = j + 1;
s = malloc(j + 2);
if (s == NULL) {
fprintf(stderr, _("Error: Out of memory.\n"));
exit(1);
};
strncpy(s, comment, j);
strcpy(s + j, ":");
/* Capitalize */
s[0] = toupper(s[0]);
for (i = 1; i < j; i++) {
s[i] = tolower(s[i]);
};
return s;
}
/* Unrecognized comment, use last format string */
*offset = 0;
s = malloc(strlen(vorbis_comment_keys[i].formatstr) + 1);
if (s == NULL) {
fprintf(stderr, _("Error: Out of memory.\n"));
exit(1);
};
strcpy(s, vorbis_comment_keys[i].formatstr);
return s;
}
void print_vorbis_comment (char *comment, decoder_callbacks_t *cb,
void *callback_arg)
{
char *comment_prettyprint;
char *decoded_value;
int offset;
if (cb == NULL || cb->printf_metadata == NULL)
return;
comment_prettyprint = lookup_comment_prettyprint(comment, &offset);
if (utf8_decode(comment + offset, &decoded_value) >= 0) {
cb->printf_metadata(callback_arg, 1, "%s %s", comment_prettyprint,
decoded_value);
free(decoded_value);
} else
cb->printf_metadata(callback_arg, 1, "%s %s", comment_prettyprint,
comment + offset);
free(comment_prettyprint);
}
/********************************************************************
* *
* 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: vorbis_comments.h,v 1.1 2003/01/11 22:51:44 volsung Exp $
********************************************************************/
#ifndef __VORBIS_COMMENTS_H__
#define __VORBIS_COMMENTS_H__
#include "format.h"
void print_vorbis_comment (char *comment, decoder_callbacks_t *cb,
void *callback_arg);
#endif /* __VORBIS_COMMENTS_H__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment