diff -urpN a/build/Makefile.am b/build/Makefile.am --- a/build/Makefile.am 2010-03-22 21:39:46.000000000 +1100 +++ b/build/Makefile.am 2013-12-16 10:16:32.426878578 +1100 @@ -18,6 +18,7 @@ libmediatomb_a_CXXFLAGS = \ $(ICONV_CXXFLAGS) \ $(LIBMAGIC_CFLAGS) \ $(ID3LIB_CFLAGS) \ + $(FLAC_CFLAGS) \ $(LIBEXIF_CFLAGS) \ $(ZLIB_CFLAGS) \ $(PTHREAD_CFLAGS) \ @@ -44,6 +45,7 @@ mediatomb_CXXFLAGS = -I$(top_srcdir)/src $(ICONV_CXXFLAGS) \ $(LIBMAGIC_CFLAGS) \ $(ID3LIB_CFLAGS) \ + $(FLAC_CFLAGS) \ $(LIBEXIF_CFLAGS) \ $(ZLIB_CFLAGS) \ $(PTHREAD_CFLAGS) \ @@ -78,6 +80,7 @@ mediatomb_LDADD = \ $(JS_LIBS) \ $(LIBMAGIC_LIBS) \ $(ID3LIB_LIBS) \ + $(FLAC_LIBS) \ $(LIBEXIF_LIBS) \ $(ZLIB_LIBS) \ $(RT_LIBS) \ diff -urpN a/build/libmediatomb_src b/build/libmediatomb_src --- a/build/libmediatomb_src 2010-03-23 04:09:53.000000000 +1100 +++ b/build/libmediatomb_src 2013-12-16 10:14:49.730356868 +1100 @@ -98,6 +98,8 @@ libmediatomb_a_SOURCES = \ ../src/metadata/libmp4v2_handler.h \ ../src/metadata/taglib_handler.cc \ ../src/metadata/taglib_handler.h \ +../src/metadata/flac_handler.cc \ +../src/metadata/flac_handler.h \ ../src/mpegdemux/buffer.c \ ../src/mpegdemux/buffer.h \ ../src/mpegdemux/mpegdemux.c \ diff -urpN a/configure.ac b/configure.ac --- a/configure.ac 2010-04-08 08:38:51.000000000 +1000 +++ b/configure.ac 2013-12-16 10:24:16.547793225 +1100 @@ -1314,6 +1314,35 @@ LDFLAGS="$LDFLAGS_SAVE" LIBS="$LIBS_SAVE" CXXFLAGS="$CXXFLAGS_SAVE" CPPFLAGS="$CPPFLAGS_SAVE" + +######### FLAC + +FLAC_STATUS= + +MT_OPTION([FLAC], [enable], + [FLAC metadata extraction with the help of FLAC],[],[]) + +if test "x$FLAC_OPTION_ENABLED" = xyes; then + MT_CHECK_PACKAGE([FLAC], + [FLAC/metadata], + [FLAC], [main]) +else + FLAC_STATUS=disabled +fi + +if test "x$FLAC_STATUS" != xyes; then + if (test "x$FLAC_OPTION_REQUESTED" = xyes) && + (test "x$FLAC_OPTION_ENABLED" = xyes); then + AC_MSG_ERROR([unable to configure FLAC support]) + fi +else + CFLAGS="$CFLAGS $FLAC_CFLAGS" + CXXFLAGS="$CXXFLAGS $FLAC_CFLAGS" + LDFLAGS="$LDFLAGS $FLAC_LDFLAGS $FLAC_LIBS" + AC_LANG_SAVE + AC_LANG_CPLUSPLUS +fi + ######## curl CURL_PROG_FOUND=0 @@ -1914,7 +1943,7 @@ if (test "x$SOPCAST_OPTION_ENABLED" = xy AC_DEFINE([SOPCAST], [1], [Enable support for the SopCast service]) fi -AC_DEFINE_UNQUOTED([COMPILE_INFO], "\thost:\t\t\t$host\n\tsqlite3:\t\t$SQLITE3_STATUS\n\tmysql:\t\t\t$MYSQL_STATUS\n\tlibjs:\t\t\t$JS_OK\n\tlibmagic:\t\t$LIBMAGIC_STATUS\n\tinotify:\t\t$INOTIFY_STATUS\n\tlibexif:\t\t$LIBEXIF_STATUS\n\tid3lib:\t\t\t$ID3LIB_STATUS\n\ttaglib:\t\t\t$TAGLIB_STATUS\n\tffmpeg\t\t\t$FFMPEG_STATUS\n\tlibmp4v2:\t\t$LIBMP4V2_STATUS\n\texternal transcoding:\t$EXTERNAL_TRANSCODING_OPTION_ENABLED\n\tcurl:\t\t\t$CURL_OK\n\tYouTube:\t\t$YOUTUBE_OPTION_ENABLED\n\tlibextractor\t\t$LIBEXTRACTOR_STATUS\n\tdb-autocreate:\t\t$DB_AUTOCREATE_OPTION_ENABLED\n\tdebug log:\t\t$DEBUG_LOG_OPTION_ENABLED\n\tprotocol info extension:$PROTOCOLINFO_EXTENSION_OPTION_ENABLED\n\tffmpegthumbnailer:\t$FFMPEGTHUMBNAILER_STATUS\n\tlastfmlib:\t\t$LASTFMLIB_STATUS\n\tdata directory:\t\t$PACKAGE_DATADIR", [compile option summary]) +AC_DEFINE_UNQUOTED([COMPILE_INFO], "\thost:\t\t\t$host\n\tsqlite3:\t\t$SQLITE3_STATUS\n\tmysql:\t\t\t$MYSQL_STATUS\n\tlibjs:\t\t\t$JS_OK\n\tlibmagic:\t\t$LIBMAGIC_STATUS\n\tinotify:\t\t$INOTIFY_STATUS\n\tlibexif:\t\t$LIBEXIF_STATUS\n\tid3lib:\t\t\t$ID3LIB_STATUS\n\ttaglib:\t\t\t$TAGLIB_STATUS\n\tFLAC:\t\t\t$FLAC_STATUS\n\tffmpeg\t\t\t$FFMPEG_STATUS\n\tlibmp4v2:\t\t$LIBMP4V2_STATUS\n\texternal transcoding:\t$EXTERNAL_TRANSCODING_OPTION_ENABLED\n\tcurl:\t\t\t$CURL_OK\n\tYouTube:\t\t$YOUTUBE_OPTION_ENABLED\n\tlibextractor\t\t$LIBEXTRACTOR_STATUS\n\tdb-autocreate:\t\t$DB_AUTOCREATE_OPTION_ENABLED\n\tdebug log:\t\t$DEBUG_LOG_OPTION_ENABLED\n\tprotocol info extension:$PROTOCOLINFO_EXTENSION_OPTION_ENABLED\n\tffmpegthumbnailer:\t$FFMPEGTHUMBNAILER_STATUS\n\tlastfmlib:\t\t$LASTFMLIB_STATUS\n\tdata directory:\t\t$PACKAGE_DATADIR", [compile option summary]) ############### AC_CONFIG_FILES([ @@ -1946,6 +1975,7 @@ echo "inotify : $INOTIFY_S echo "libexif : $LIBEXIF_STATUS" echo "id3lib : $ID3LIB_STATUS" echo "taglib : $TAGLIB_STATUS" +echo "FLAC : $FLAC_STATUS" echo "libmp4v2 : $LIBMP4V2_STATUS" echo "ffmpeg : $FFMPEG_STATUS" echo "ffmpegthumbnailer : $FFMPEGTHUMBNAILER_STATUS" diff -urpN a/src/cds_resource_manager.cc b/src/cds_resource_manager.cc --- a/src/cds_resource_manager.cc 2010-03-26 01:58:11.000000000 +1100 +++ b/src/cds_resource_manager.cc 2013-12-16 10:25:15.277987292 +1100 @@ -372,6 +372,7 @@ void CdsResourceManager::addResources(Re // only add upnp:AlbumArtURI if we have an AA, skip the resource if ((i > 0) && ((item->getResource(i)->getHandlerType() == CH_ID3) || (item->getResource(i)->getHandlerType() == CH_MP4) || + (item->getResource(i)->getHandlerType() == CH_FLAC) || (item->getResource(i)->getHandlerType() == CH_EXTURL))) { String rct; diff -urpN a/src/config_manager.cc b/src/config_manager.cc --- a/src/config_manager.cc 2010-03-26 01:58:11.000000000 +1100 +++ b/src/config_manager.cc 2013-12-16 10:26:57.220886235 +1100 @@ -624,6 +624,10 @@ String ConfigManager::createDefaultConfi _(CONTENT_TYPE_OGG))); mtcontent->appendElementChild(treat_as(_("audio/x-flac"), _(CONTENT_TYPE_FLAC))); + mtcontent->appendElementChild(treat_as(_("audio/x-ms-wma"), + _(CONTENT_TYPE_WMA))); + mtcontent->appendElementChild(treat_as(_("audio/x-wavpack"), + _(CONTENT_TYPE_WAVPACK))); mtcontent->appendElementChild(treat_as(_("image/jpeg"), _(CONTENT_TYPE_JPG))); mtcontent->appendElementChild(treat_as(_("audio/x-mpegurl"), diff -urpN a/src/metadata/flac_handler.cc b/src/metadata/flac_handler.cc --- a/src/metadata/flac_handler.cc 1970-01-01 10:00:00.000000000 +1000 +++ b/src/metadata/flac_handler.cc 2013-12-16 10:30:19.955604387 +1100 @@ -0,0 +1,204 @@ +/*MT* + + MediaTomb - http://www.mediatomb.cc/ + + flac_handler.cc - this file is part of MediaTomb. + + Copyright (C) 2005 Gena Batyan , + Sergey 'Jin' Bostandzhyan + + Copyright (C) 2006-2009 Gena Batyan , + Sergey 'Jin' Bostandzhyan , + Leonhard Wimmer + + MediaTomb is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + MediaTomb 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 + version 2 along with MediaTomb; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + + $Id: flac_handler.cc 2032 2009-12-21 22:58:57Z lww $ +*/ + +/// \file flac_handler.cc +/// \brief Implementeation of the FlacHandler class. + +#ifdef HAVE_CONFIG_H + #include "autoconfig.h" +#endif + +#ifdef HAVE_FLAC + +#include + +#include "flac_handler.h" +#include "string_converter.h" +#include "config_manager.h" +#include "common.h" +#include "tools.h" +#include "mem_io_handler.h" + +#include "content_manager.h" + +using namespace zmm; + +FlacHandler::FlacHandler() : MetadataHandler() +{ +} + +static void addField(metadata_fields_t field, const FLAC__StreamMetadata* tags, Ref item) +{ + String value; + int i; + + Ref sc = StringConverter::i2i(); // sure is sure + + switch (field) + { + case M_TITLE: + i = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, /*offset=*/0, "TITLE"); + break; + case M_ARTIST: + i = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, /*offset=*/0, "ARTIST"); + break; + case M_ALBUM: + i = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, /*offset=*/0, "ALBUM"); + break; + case M_DATE: + i = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, /*offset=*/0, "DATE"); + break; + case M_GENRE: + i = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, /*offset=*/0, "GENRE"); + break; + case M_DESCRIPTION: + i = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, /*offset=*/0, "DESCRIPTION"); + break; + case M_TRACKNUMBER: + i = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, /*offset=*/0, "TRACKNUMBER"); + break; + default: + return; + } + + if( 0 <= i ) + value = strchr((const char *)tags->data.vorbis_comment.comments[i].entry, '=') + 1; + else + return; + + value = trim_string(value); + + if (string_ok(value)) + { + item->setMetadata(MT_KEYS[field].upnp, sc->convert(value)); + log_debug("Setting metadata on item: %d, %s\n", field, sc->convert(value).c_str()); + } +} + +void FlacHandler::fillMetadata(Ref item) +{ + FLAC__StreamMetadata* tags = NULL; + FLAC__StreamMetadata streaminfo; + Ref sc = StringConverter::i2i(); // sure is sure + + if( !FLAC__metadata_get_tags(item->getLocation().c_str(), &tags) ) + return; + + if( FLAC__METADATA_TYPE_VORBIS_COMMENT == tags->type ) + { + for (int i = 0; i < M_MAX; i++) + addField((metadata_fields_t) i, tags, item); + } + + FLAC__metadata_object_delete(tags); + tags = NULL; + + if( !FLAC__metadata_get_streaminfo(item->getLocation().c_str(), &streaminfo) ) + return; + + if( FLAC__METADATA_TYPE_STREAMINFO == streaminfo.type ) + { + // note: UPnP requires bytes/second + item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_BITRATE), String::from((unsigned)((streaminfo.data.stream_info.bits_per_sample * streaminfo.data.stream_info.sample_rate) / 8))); + // note: UPnP requires HMS + item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_DURATION), secondsToHMS((unsigned)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate))); + item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_SAMPLEFREQUENCY), String::from(streaminfo.data.stream_info.sample_rate)); + item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_NRAUDIOCHANNELS), String::from(streaminfo.data.stream_info.channels)); + } + + if( !FLAC__metadata_get_picture(item->getLocation().c_str(), + &tags, + FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER, + NULL, + NULL, + (unsigned)-1, + (unsigned)-1, + (unsigned)-1, + (unsigned)-1 ) ) + return; + + if( FLAC__METADATA_TYPE_PICTURE == tags->type ) + { + String art_mimetype = tags->data.picture.mime_type; + log_debug("Mime type : %s\n", sc->convert(art_mimetype).c_str()); + + // saw that simply "PNG" was used with some mp3's, so mimetype setting + // was probably invalid + if (!string_ok(art_mimetype) || (art_mimetype.index('/') == -1)) + { +#ifdef HAVE_MAGIC + art_mimetype = ContentManager::getInstance()->getMimeTypeFromBuffer((void *)tags->data.picture.data, tags->data.picture.data_length); + if (!string_ok(art_mimetype)) +#endif + art_mimetype = _(MIMETYPE_DEFAULT); + + log_debug("Mime type via magic: %s\n", sc->convert(art_mimetype).c_str()); + } + + // if we could not determine the mimetype, then there is no + // point to add the resource - it's probably garbage + if (art_mimetype != _(MIMETYPE_DEFAULT)) + { + Ref resource(new CdsResource(CH_FLAC)); + resource->addAttribute(MetadataHandler::getResAttrName(R_PROTOCOLINFO), renderProtocolInfo(art_mimetype)); + resource->addParameter(_(RESOURCE_CONTENT_TYPE), _(ID3_ALBUM_ART)); + item->addResource(resource); + } + } + + FLAC__metadata_object_delete(tags); +} + +Ref FlacHandler::serveContent(Ref item, int resNum, off_t *data_size) +{ + FLAC__StreamMetadata* picture = NULL; + + if( !FLAC__metadata_get_picture(item->getLocation().c_str(), + &picture, + FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER, + NULL, + NULL, + (unsigned)-1, + (unsigned)-1, + (unsigned)-1, + (unsigned)-1 ) ) + throw _Exception(_("FlacHandler: could not exctract cover from: ") + item->getLocation()); + + if( FLAC__METADATA_TYPE_PICTURE != picture->type ) + throw _Exception(_("TagHandler: resource has no album information")); + + Ref h(new MemIOHandler((void *)picture->data.picture.data, picture->data.picture.data_length)); + *data_size = picture->data.picture.data_length; + + FLAC__metadata_object_delete(picture); + + return h; +} + +#endif // HAVE_FLAC diff -urpN a/src/metadata/flac_handler.h b/src/metadata/flac_handler.h --- a/src/metadata/flac_handler.h 1970-01-01 10:00:00.000000000 +1000 +++ b/src/metadata/flac_handler.h 2013-12-16 10:31:24.061822827 +1100 @@ -0,0 +1,47 @@ +/*MT* + + MediaTomb - http://www.mediatomb.cc/ + + flac_handler.h - this file is part of MediaTomb. + + Copyright (C) 2005 Gena Batyan , + Sergey 'Jin' Bostandzhyan + + Copyright (C) 2006-2009 Gena Batyan , + Sergey 'Jin' Bostandzhyan , + Leonhard Wimmer + + MediaTomb is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + MediaTomb 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 + version 2 along with MediaTomb; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + + $Id: flac_handler.h 2010 2009-01-11 19:10:43Z lww $ +*/ + +/// \file flac_handler.h +/// \brief Definition of the FlacHandler class. + +#ifndef __METADATA_FLAC_H__ +#define __METADATA_FLAC_H__ + +#include "metadata_handler.h" + +/// \brief This class is responsible for reading FLAC metadata +class FlacHandler : public MetadataHandler +{ +public: + FlacHandler(); + virtual void fillMetadata(zmm::Ref item); + virtual zmm::Ref serveContent(zmm::Ref item, int resNum, off_t *data_size); +}; + +#endif // __METADATA_FLAC_H__ diff -urpN a/src/metadata_handler.cc b/src/metadata_handler.cc --- a/src/metadata_handler.cc 2010-03-26 01:58:11.000000000 +1100 +++ b/src/metadata_handler.cc 2013-12-16 10:35:48.783540865 +1100 @@ -51,6 +51,10 @@ #endif // HAVE_ID3LIB #endif // HAVE_TAGLIB +#ifdef HAVE_FLAC +#include "metadata/flac_handler.h" +#endif + #ifdef HAVE_LIBMP4V2 #include "metadata/libmp4v2_handler.h" #endif @@ -140,7 +144,8 @@ void MetadataHandler::setMetadata(RefgetFlag(OBJECT_FLAG_OGG_THEORA))) || - (content_type == CONTENT_TYPE_FLAC)) + (content_type == CONTENT_TYPE_WMA) || + (content_type == CONTENT_TYPE_WAVPACK)) { handler = Ref(new TagHandler()); break; @@ -155,7 +160,13 @@ void MetadataHandler::setMetadata(Ref(new FlacHandler()); + break; + } +#endif #ifdef HAVE_EXIV2 /* @@ -277,6 +288,10 @@ Ref MetadataHandler::cr case CH_FFTH: return Ref(new FfmpegHandler()); #endif +#ifdef HAVE_FLAC + case CH_FLAC: + return Ref(new FlacHandler()); +#endif default: throw _Exception(_("unknown content handler ID: ") + handlerType); } diff -urpN a/src/metadata_handler.h b/src/metadata_handler.h --- a/src/metadata_handler.h 2010-03-26 01:58:11.000000000 +1100 +++ b/src/metadata_handler.h 2013-12-16 10:52:23.234353526 +1100 @@ -45,10 +45,13 @@ #define CH_EXTURL 4 #define CH_MP4 5 #define CH_FFTH 6 +#define CH_FLAC 7 #define CONTENT_TYPE_MP3 "mp3" #define CONTENT_TYPE_OGG "ogg" #define CONTENT_TYPE_FLAC "flac" +#define CONTENT_TYPE_WMA "wma" +#define CONTENT_TYPE_WAVPACK "wv" #define CONTENT_TYPE_JPG "jpg" #define CONTENT_TYPE_PLAYLIST "playlist" #define CONTENT_TYPE_MP4 "mp4"