diff --git a/INSTALL b/INSTALL index 22a06fa62..5970e6e58 100644 --- a/INSTALL +++ b/INSTALL @@ -69,6 +69,9 @@ MAD - http://www.underbit.com/products/mad/ For MP3 support. You will need libmad, and optionally libid3tag if you want ID3 tag support. +libmpg123 - http://www.mpg123.de/ +Alternative for MP3 support. + Ogg Vorbis - http://www.xiph.org/ogg/vorbis/ For Ogg Vorbis support. You will need libogg and libvorbis. diff --git a/Makefile.am b/Makefile.am index 8e1341f0f..b017d970a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -348,6 +348,7 @@ DECODER_CFLAGS = \ $(WILDMIDI_CFLAGS) \ $(WAVPACK_CFLAGS) \ $(MAD_CFLAGS) \ + $(MPG123_CFLAGS) \ $(FFMPEG_CFLAGS) \ $(CUE_CFLAGS) @@ -362,6 +363,7 @@ DECODER_LIBS = \ $(WILDMIDI_LIBS) \ $(WAVPACK_LIBS) \ $(MAD_LIBS) \ + $(MPG123_LIBS) \ $(MP4FF_LIBS) \ $(FFMPEG_LIBS) \ $(CUE_LIBS) @@ -374,6 +376,10 @@ if HAVE_MAD DECODER_SRC += src/decoder/mad_plugin.c endif +if HAVE_MPG123 +DECODER_SRC += src/decoder/mpg123_decoder_plugin.c +endif + if HAVE_MPCDEC DECODER_SRC += src/decoder/mpcdec_plugin.c endif diff --git a/NEWS b/NEWS index ec9b27496..ae53f52c5 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,7 @@ ver 0.16 (20??/??/??) - ffmpeg: convert metadata to generic format - sndfile: new decoder plugin based on libsndfile - flac: load external cue sheet when no internal one + - mpg123: new decoder plugin based on libmpg123 * encoders: - twolame: new encoder plugin based on libtwolame * output: diff --git a/configure.ac b/configure.ac index efa638caa..681feae6c 100644 --- a/configure.ac +++ b/configure.ac @@ -427,6 +427,18 @@ if test x$enable_mad = xyes; then fi AM_CONDITIONAL(HAVE_MAD, test x$enable_mad = xyes) +AC_ARG_ENABLE(mpg123, + AS_HELP_STRING([--enable-mpg123], + [enable libmpg123 decoder plugin]),, + enable_mpg123=auto) + +MPD_AUTO_PKG(mpg123, MPG123, [libmpg123], + [libmpg123 decoder plugin], [libmpg123 not found]) +if test x$enable_mpg123 = xyes; then + AC_DEFINE(HAVE_MPG123, 1, [Define to use libmpg123]) +fi +AM_CONDITIONAL(HAVE_MPG123, test x$enable_mpg123 = xyes) + AC_ARG_ENABLE(mikmod, AS_HELP_STRING([--enable-mikmod], [enable the mikmod decoder (default: disable)]),, @@ -1411,6 +1423,12 @@ else echo " MAD mp3 decoder support .......disabled" fi +if test x$enable_mpg123 = xyes; then + echo " libmpg123 decoder support .....enabled" +else + echo " libmpg123 decoder support .....disabled" +fi + if test x$enable_mp4 = xyes; then echo " MP4 support ...................enabled" else @@ -1474,6 +1492,7 @@ fi if test x$enable_mad = xno && + test x$enable_mpg123 = xno && test x$enable_vorbis = xno && test x$enable_flac = xno && test x$enable_oggflac = xno && diff --git a/src/decoder/mpg123_decoder_plugin.c b/src/decoder/mpg123_decoder_plugin.c new file mode 100644 index 000000000..7ffeb1155 --- /dev/null +++ b/src/decoder/mpg123_decoder_plugin.c @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2003-2009 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "decoder_api.h" + +#include + +#include + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "mpg123" + +static bool +mpd_mpg123_init(G_GNUC_UNUSED const struct config_param *param) +{ + mpg123_init(); + + return true; +} + +static void +mpd_mpg123_finish(void) +{ + mpg123_exit(); +} + +/** + * Opens a file with an existing #mpg123_handle. + * + * @param handle a handle which was created before; on error, this + * function will not free it + * @param audio_format this parameter is filled after successful + * return + * @return true on success + */ +static bool +mpd_mpg123_open(mpg123_handle *handle, const char *path_fs, + struct audio_format *audio_format) +{ + char *path_dup; + int error; + int channels, encoding; + long rate; + + /* mpg123_open() wants a writable string :-( */ + path_dup = g_strdup(path_fs); + + error = mpg123_open(handle, path_dup); + g_free(path_dup); + if (error != MPG123_OK) { + g_warning("libmpg123 failed to open %s: %s", + path_fs, mpg123_plain_strerror(error)); + return false; + } + + /* obtain the audio format */ + + error = mpg123_getformat(handle, &rate, &channels, &encoding); + if (error != MPG123_OK) { + g_warning("mpg123_getformat() failed: %s", + mpg123_plain_strerror(error)); + return false; + } + + if (encoding != MPG123_ENC_SIGNED_16) { + /* other formats not yet implemented */ + g_warning("expected MPG123_ENC_SIGNED_16, got %d", encoding); + return false; + } + + audio_format_init(audio_format, rate, 16, channels); + if (!audio_format_valid(audio_format)) { + g_warning("invalid audio format"); + return false; + } + + return true; +} + +static void +mpd_mpg123_file_decode(struct decoder *decoder, const char *path_fs) +{ + struct audio_format audio_format; + mpg123_handle *handle; + int error; + off_t num_samples, position; + enum decoder_command cmd; + + /* open the file */ + + handle = mpg123_new(NULL, &error); + if (handle == NULL) { + g_warning("mpg123_new() failed: %s", + mpg123_plain_strerror(error)); + return; + } + + if (!mpd_mpg123_open(handle, path_fs, &audio_format)) { + mpg123_delete(handle); + return; + } + + num_samples = mpg123_length(handle); + + /* tell MPD core we're ready */ + + decoder_initialized(decoder, &audio_format, false, + (float)num_samples / + (float)audio_format.sample_rate); + + /* the decoder main loop */ + + do { + unsigned char buffer[8192]; + size_t nbytes; + + position = mpg123_tell(handle); + + /* decode */ + + error = mpg123_read(handle, buffer, sizeof(buffer), &nbytes); + if (error != MPG123_OK) { + if (error != MPG123_DONE) + g_warning("mpg123_read() failed: %s", + mpg123_plain_strerror(error)); + break; + } + + /* send to MPD */ + + cmd = decoder_data(decoder, NULL, buffer, nbytes, + (float)position / + (float)audio_format.sample_rate, + 0, NULL); + + /* seeking not yet implemented */ + } while (cmd == DECODE_COMMAND_NONE); + + /* cleanup */ + + mpg123_delete(handle); +} + +static struct tag * +mpd_mpg123_tag_dup(const char *path_fs) +{ + struct audio_format audio_format; + mpg123_handle *handle; + int error; + off_t num_samples; + struct tag *tag; + + handle = mpg123_new(NULL, &error); + if (handle == NULL) { + g_warning("mpg123_new() failed: %s", + mpg123_plain_strerror(error)); + return NULL; + } + + if (!mpd_mpg123_open(handle, path_fs, &audio_format)) { + mpg123_delete(handle); + return NULL; + } + + num_samples = mpg123_length(handle); + if (num_samples <= 0) { + mpg123_delete(handle); + return NULL; + } + + tag = tag_new(); + + tag->time = num_samples / audio_format.sample_rate; + + /* ID3 tag support not yet implemented */ + + mpg123_delete(handle); + return tag; +} + +static const char *const mpg123_suffixes[] = { + "mp3", + NULL +}; + +const struct decoder_plugin mpg123_decoder_plugin = { + .name = "mpg123", + .init = mpd_mpg123_init, + .finish = mpd_mpg123_finish, + .file_decode = mpd_mpg123_file_decode, + /* streaming not yet implemented */ + .tag_dup = mpd_mpg123_tag_dup, + .suffixes = mpg123_suffixes, +}; diff --git a/src/decoder_list.c b/src/decoder_list.c index 177ac46e4..d30611e1b 100644 --- a/src/decoder_list.c +++ b/src/decoder_list.c @@ -28,6 +28,7 @@ #include extern const struct decoder_plugin mad_decoder_plugin; +extern const struct decoder_plugin mpg123_decoder_plugin; extern const struct decoder_plugin vorbis_decoder_plugin; extern const struct decoder_plugin flac_decoder_plugin; extern const struct decoder_plugin oggflac_decoder_plugin; @@ -48,6 +49,9 @@ static const struct decoder_plugin *const decoder_plugins[] = { #ifdef HAVE_MAD &mad_decoder_plugin, #endif +#ifdef HAVE_MPG123 + &mpg123_decoder_plugin, +#endif #ifdef ENABLE_VORBIS_DECODER &vorbis_decoder_plugin, #endif