From 63dd4b45983babdf1703b320526aed48a87ca45e Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Mon, 4 Dec 2006 04:45:50 +0000 Subject: [PATCH] Add OggFLAC support when using the new 1.1.3 FLAC library This means that when using libFLAC as a shared object, OggFLAC support is dependent on the compile-time options of the libFLAC library loaded. git-svn-id: https://svn.musicpd.org/mpd/trunk@5112 09075e82-0dd4-0310-85a5-a0d7c8717e4f --- src/inputPlugins/_flac_common.h | 18 +++-- src/inputPlugins/flac_plugin.c | 123 +++++++++++++++++++++++++++----- 2 files changed, 119 insertions(+), 22 deletions(-) diff --git a/src/inputPlugins/_flac_common.h b/src/inputPlugins/_flac_common.h index eab7971e5..2dd5517e5 100644 --- a/src/inputPlugins/_flac_common.h +++ b/src/inputPlugins/_flac_common.h @@ -36,6 +36,8 @@ # define flac_decoder FLAC__SeekableStreamDecoder # define flac_new(x) FLAC__seekable_stream_decoder_new(x) +# define flac_ogg_init(a,b,c,d,e,f,g,h,i,j) (0) + # define flac_get_decode_position(x,y) \ FLAC__seekable_stream_decoder_get_decode_position(x,y) # define flac_get_state(x) FLAC__seekable_stream_decoder_get_state(x) @@ -78,18 +80,26 @@ # include # endif #else /* FLAC_API_VERSION_CURRENT >= 7 */ - /* OggFLAC support is handled by our flac_plugin already */ -# ifdef HAVE_OGGFLAC -# undef HAVE_OGGFLAC + + /* OggFLAC support is handled by our flac_plugin already, and + * thus we *can* always have it if libFLAC was compiled with it */ +# ifndef HAVE_OGGFLAC +# define HAVE_OGGFLAC 1 # endif -# include # include "_ogg_common.h" +# undef HAVE_OGGFLAC /* we don't need this defined anymore */ + +# include # define flac_decoder FLAC__StreamDecoder # define flac_new(x) FLAC__stream_decoder_new(x) # define flac_init(a,b,c,d,e,f,g,h,i,j) \ (FLAC__stream_decoder_init_stream(a,b,c,d,e,f,g,h,i,j) \ == FLAC__STREAM_DECODER_INIT_STATUS_OK) +# define flac_ogg_init(a,b,c,d,e,f,g,h,i,j) \ + (FLAC__stream_decoder_init_ogg_stream(a,b,c,d,e,f,g,h,i,j) \ + == FLAC__STREAM_DECODER_INIT_STATUS_OK) + # define flac_get_decode_position(x,y) \ FLAC__stream_decoder_get_decode_position(x,y) # define flac_get_state(x) FLAC__stream_decoder_get_state(x) diff --git a/src/inputPlugins/flac_plugin.c b/src/inputPlugins/flac_plugin.c index 0b0625417..ee8e61be6 100644 --- a/src/inputPlugins/flac_plugin.c +++ b/src/inputPlugins/flac_plugin.c @@ -31,6 +31,7 @@ #include #include #include +#include /* this code was based on flac123, from flac-tools */ @@ -339,30 +340,34 @@ static MpdTag *flacTagDup(char *file) return ret; } -static int flac_decode(OutputBuffer * cb, DecoderControl * dc, - InputStream * inStream) +static int flac_decode_internal(OutputBuffer * cb, DecoderControl * dc, + InputStream * inStream, int is_ogg) { flac_decoder *flacDec; FlacData data; - int ret = 0; + const char *err = NULL; if (!(flacDec = flac_new())) return -1; init_FlacData(&data, cb, dc, inStream); - if (!flac_init(flacDec, flacRead, flacSeek, flacTell, flacLength, - flacEOF, flacWrite, flacMetadata, flacError, - (void *)&data)) { - ERROR("flac problem doing init()\n"); - flacPrintErroredState(flac_get_state(flacDec)); - ret = -1; - goto fail; - } - - if (!flac_process_metadata(flacDec)) { - ERROR("flac problem reading metadata\n"); - flacPrintErroredState(flac_get_state(flacDec)); - ret = -1; - goto fail; + if (is_ogg) { + if (!flac_ogg_init(flacDec, flacRead, flacSeek, flacTell, + flacLength, flacEOF, flacWrite, flacMetadata, + flacError, (void *)&data)) { + err = "doing Ogg init()"; + goto fail; + } + } else { + if (!flac_init(flacDec, flacRead, flacSeek, flacTell, + flacLength, flacEOF, flacWrite, flacMetadata, + flacError, (void *)&data)) { + err = "doing init()"; + goto fail; + } + if (!flac_process_metadata(flacDec)) { + err = "problem reading metadata"; + goto fail; + } } dc->state = DECODE_STATE_DECODE; @@ -412,15 +417,97 @@ fail: closeInputStream(inStream); + if (err) { + ERROR("flac %s\n", err); + return -1; + } + return 0; +} + +static int flac_decode(OutputBuffer * cb, DecoderControl * dc, + InputStream * inStream) +{ + return flac_decode_internal(cb, dc, inStream, 0); +} + +#if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT <= 7 +# define flac_plugin_init NULL +#else /* FLAC_API_VERSION_CURRENT >= 7 */ +/* some of this stuff is duplicated from oggflac_plugin.c */ +extern InputPlugin oggflacPlugin; + +static MpdTag *oggflac_tag_dup(char *file) +{ + MpdTag *ret = NULL; + FLAC__Metadata_Iterator *it; + FLAC__StreamMetadata *block; + FLAC__Metadata_Chain *chain = FLAC__metadata_chain_new(); + + if (!(FLAC__metadata_chain_read_ogg(chain, file))) + goto out; + it = FLAC__metadata_iterator_new(); + FLAC__metadata_iterator_init(it, chain); + do { + if (!(block = FLAC__metadata_iterator_get_block(it))) + break; + if (block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { + ret = copyVorbisCommentBlockToMpdTag(block, ret); + } else if (block->type == FLAC__METADATA_TYPE_STREAMINFO) { + if (!ret) + ret = newMpdTag(); + ret->time = ((float)block->data.stream_info. + total_samples) / + block->data.stream_info.sample_rate + 0.5; + } + } while (FLAC__metadata_iterator_next(it)); + FLAC__metadata_iterator_delete(it); +out: + FLAC__metadata_chain_delete(chain); return ret; } +static int oggflac_decode(OutputBuffer * cb, DecoderControl * dc, + InputStream * inStream) +{ + return flac_decode_internal(cb, dc, inStream, 1); +} + +static unsigned int oggflac_try_decode(InputStream * inStream) +{ + return (ogg_stream_type_detect(inStream) == FLAC) ? 1 : 0; +} + +static char *oggflac_suffixes[] = { "ogg", NULL }; +static char *oggflac_mime_types[] = { "application/ogg", NULL }; + +static int flac_plugin_init(void) +{ + if (!FLAC_API_SUPPORTS_OGG_FLAC) { + DEBUG("libFLAC does not support OggFLAC\n"); + return 1; + } + DEBUG("libFLAC supports OggFLAC, initializing OggFLAC support\n"); + assert(oggflacPlugin.name == NULL); + oggflacPlugin.name = "oggflac"; + oggflacPlugin.tryDecodeFunc = oggflac_try_decode; + oggflacPlugin.streamDecodeFunc = oggflac_decode; + oggflacPlugin.tagDupFunc = oggflac_tag_dup; + oggflacPlugin.streamTypes = INPUT_PLUGIN_STREAM_URL | + INPUT_PLUGIN_STREAM_FILE; + oggflacPlugin.suffixes = oggflac_suffixes; + oggflacPlugin.mimeTypes = oggflac_mime_types; + loadInputPlugin(&oggflacPlugin); + return 1; +} + +#endif /* FLAC_API_VERSION_CURRENT >= 7 */ + static char *flacSuffixes[] = { "flac", NULL }; static char *flac_mime_types[] = { "application/x-flac", NULL }; InputPlugin flacPlugin = { "flac", - NULL, + flac_plugin_init, NULL, NULL, flac_decode,