All pastes #418118 Raw Edit

Something

public text v1 · immutable
#418118 ·published 2007-03-31 12:32 UTC
rendered paste body
Index: configure
===================================================================
--- configure	(revision 13144)
+++ configure	(working copy)
@@ -405,10 +405,10 @@
 
 if test "$music" != "no" ; then
     mad="no"
-    if has_library libmad && has_header mad.h && has_library libid3tag && has_header id3tag.h ; then
+    if has_library libmad && has_header mad.h ; then
         mad="yes"
     else
-        echo "MythMusic requires libmad and libid3tag."
+        echo "MythMusic requires libmad."
     fi 
 
     vorbis="no"
@@ -453,7 +453,14 @@
         echo "MythMusic requires the LAME mp3 encoder."
     fi
 
-    if test "$mad" = "no" -o "$vorbis" = "no" -o "$flac" = "no" -o "$cdaudio" = "no" -o "$paranoia" = "no" -o "$mp3lame" = "no" ; then
+    taglib="no"
+    if has_library libtag && has_header taglib/fileref.h ; then
+        taglib="yes"
+    else
+        echo "MythMusic requires taglib."
+    fi 
+
+    if test "$mad" = "no" -o "$vorbis" = "no" -o "$flac" = "no" -o "$cdaudio" = "no" -o "$paranoia" = "no" -o "$mp3lame" = "no" -o "$taglib" = "no" ; then
         echo "Disabling MythMusic due to missing dependencies."
         music="no"
     fi 
Index: mythmusic/mythmusic/metaio_libid3hack.h
===================================================================
--- mythmusic/mythmusic/metaio_libid3hack.h	(revision 13144)
+++ mythmusic/mythmusic/metaio_libid3hack.h	(working copy)
@@ -1,10 +0,0 @@
-#ifndef METAIO_LIBID3HACK_H_
-#define METAIO_LIBID3HACK_H_
-
-extern "C"
-{
-#define ID3_FILE_UPDATE myth_id3_file_update
-
-int myth_id3_file_update(struct id3_file *file);
-}
-#endif
Index: mythmusic/mythmusic/mythmusic.pro
===================================================================
--- mythmusic/mythmusic/mythmusic.pro	(revision 13144)
+++ mythmusic/mythmusic/mythmusic.pro	(working copy)
@@ -6,7 +6,7 @@
    error(Missing config.pro: please run the configure script)
 }
 
-INCLUDEPATH *= /usr/include/cdda
+INCLUDEPATH *= /usr/include/cdda /usr/include/taglib
 TEMPLATE = lib
 CONFIG += plugin thread
 TARGET = mythmusic
@@ -20,7 +20,7 @@
 
 INSTALLS += installfiles uifiles
 
-LIBS += -lmad -lid3tag -logg -lvorbisfile -lvorbis -lvorbisenc -lcdaudio -lFLAC
+LIBS += -lmad -ltag -logg -lvorbisfile -lvorbis -lvorbisenc -lcdaudio -lFLAC
 LIBS += -lmp3lame -lcdda_paranoia -lcdda_interface
 
 # Input
@@ -30,8 +30,8 @@
 HEADERS += streaminput.h synaesthesia.h encoder.h visualize.h avfdecoder.h
 HEADERS += treecheckitem.h vorbisdecoder.h vorbisencoder.h polygon.h
 HEADERS += bumpscope.h globalsettings.h lameencoder.h dbcheck.h
-HEADERS += metaio.h metaioid3v2.h vcedit.h metaiooggvorbiscomment.h
-HEADERS += metaioflacvorbiscomment.h metaioavfcomment.h metaio_libid3hack.h
+HEADERS += metaio.h metaiotaglib.h vcedit.h metaiooggvorbiscomment.h
+HEADERS += metaioflacvorbiscomment.h metaioavfcomment.h
 HEADERS += goom/filters.h goom/goomconfig.h goom/goom_core.h goom/graphic.h
 HEADERS += goom/ifs.h goom/lines.h goom/mythgoom.h goom/drawmethods.h
 HEADERS += goom/mmx.h goom/mathtools.h goom/tentacle3d.h goom/v3d.h
@@ -46,8 +46,8 @@
 SOURCES += synaesthesia.cpp treecheckitem.cpp vorbisdecoder.cpp lameencoder.cpp
 SOURCES += vorbisencoder.cpp visualize.cpp bumpscope.cpp globalsettings.cpp
 SOURCES += databasebox.cpp genres.cpp
-SOURCES += metaio.cpp metaioid3v2.cpp vcedit.c metaiooggvorbiscomment.cpp 
-SOURCES += metaioflacvorbiscomment.cpp metaioavfcomment.cpp metaio_libid3hack.c
+SOURCES += metaio.cpp metaiotaglib.cpp vcedit.c metaiooggvorbiscomment.cpp 
+SOURCES += metaioflacvorbiscomment.cpp metaioavfcomment.cpp
 SOURCES += goom/filters.c goom/goom_core.c goom/graphic.c goom/tentacle3d.c
 SOURCES += goom/ifs.c goom/ifs_display.c goom/lines.c goom/surf3d.c 
 SOURCES += goom/zoom_filter_mmx.c goom/zoom_filter_xmmx.c goom/mythgoom.cpp
Index: mythmusic/mythmusic/metaioid3v2.h
===================================================================
--- mythmusic/mythmusic/metaioid3v2.h	(revision 13144)
+++ mythmusic/mythmusic/metaioid3v2.h	(working copy)
@@ -1,56 +0,0 @@
-#ifndef metaioID3V2_H_
-#define metaioID3V2_H_
-
-#include "metaio.h"
-
-extern "C" {
-#include <id3tag.h>
-}
-
-// Similar to the ones define in id3tag.h
-#define MYTH_ID3_FRAME_COMPILATIONARTIST "TPE4"
-#define MYTH_ID3_FRAME_COMMENT "TXXX"
-#define MYTH_ID3_FRAME_MUSICBRAINZ_ALBUMARTISTDESC "MusicBrainz Album Artist Id"
-
-#define XING_MAGIC     (('X' << 24) | ('i' << 16) | ('n' << 8) | 'g')
-
-typedef struct {
-    int flags;
-    unsigned long frames;
-    unsigned long bytes;
-    unsigned char toc[100];
-    long scale;
-} xing;
-
-class MetaIOID3v2 : public MetaIO
-{
-public:
-    MetaIOID3v2(void);
-    virtual ~MetaIOID3v2(void);
-
-    bool write(Metadata* mdata, bool exclusive = false);
-    Metadata* read(QString filename);
-
-private:
-    enum {
-        XING_FRAMES = 0x0001,
-        XING_BYTES  = 0x0002,
-        XING_TOC    = 0x0004,
-        XING_SCALE  = 0x0008
-    };
-
-    int getTrackLength(QString filename);
-
-    QString getRawID3String(union id3_field *pField);
-    void removeComment(id3_tag *pTag, const char* pLabel, const QString desc = "");
-    QString getComment(id3_tag *pTag, const char* pLabel,
-                       const QString desc = "");
-
-    bool setComment(id3_tag *pTag, const char* pLabel, const QString value,
-                    const QString desc = "");
-
-    bool findXingHeader(xing *xing, struct mad_bitptr ptr, unsigned int bitlen);
-};
-
-#endif
-
Index: mythmusic/mythmusic/lameencoder.cpp
===================================================================
--- mythmusic/mythmusic/lameencoder.cpp	(revision 13144)
+++ mythmusic/mythmusic/lameencoder.cpp	(working copy)
@@ -30,7 +30,7 @@
 
 #include "metadata.h"
 #include "lameencoder.h"
-#include "metaioid3v2.h"
+#include "metaiotaglib.h"
 
 #include <iostream>
 
@@ -146,7 +146,7 @@
     // Now write the Metadata
     if (metadata)
     {
-        MetaIOID3v2* p_tagger = new MetaIOID3v2;
+        MetaIOTagLib* p_tagger = new MetaIOTagLib;
         QString filename = metadata->Filename();
         QString tmp = *outfile;
         metadata->setFilename(tmp);
Index: mythmusic/mythmusic/metaiotaglib.h
===================================================================
--- mythmusic/mythmusic/metaiotaglib.h	(revision 0)
+++ mythmusic/mythmusic/metaiotaglib.h	(revision 0)
@@ -0,0 +1,30 @@
+#ifndef metaioTAGLIB_H_
+#define metaioTAGLIB_H_
+
+#include "metaio.h"
+#include <id3v2tag.h>
+#include <textidentificationframe.h>
+#include <mpegfile.h>
+
+using TagLib::MPEG::File;
+using TagLib::Tag;
+using TagLib::ID3v2::UserTextIdentificationFrame;
+
+class MetaIOTagLib : public MetaIO
+{
+public:
+    MetaIOTagLib(void);
+    virtual ~MetaIOTagLib(void);
+
+    bool write(Metadata* mdata, bool exclusive = false);
+    Metadata* read(QString filename);
+
+private:
+
+     int getTrackLength(QString filename);
+
+//     bool setPopularimeter(id3_tag *pTag, const QString email, const int rating,
+//                     const QString playcount);
+};
+
+#endif

Property changes on: mythmusic/mythmusic/metaiotaglib.h
___________________________________________________________________
Name: svn:eol-style
   + native

Index: mythmusic/mythmusic/metaiotaglib.cpp
===================================================================
--- mythmusic/mythmusic/metaiotaglib.cpp	(revision 0)
+++ mythmusic/mythmusic/metaiotaglib.cpp	(revision 0)
@@ -0,0 +1,187 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <iostream>
+#include <fstream>
+#include <sys/stat.h>
+using namespace std;
+
+#include "metaiotaglib.h"
+#include "metadata.h"
+
+#include <mythtv/mythcontext.h>
+
+MetaIOTagLib::MetaIOTagLib(void)
+    : MetaIO(".mp3")
+{
+}
+
+MetaIOTagLib::~MetaIOTagLib(void)
+{
+}
+
+/*!
+ * \brief Writes metadata back to a file
+ *
+ * \param mdata A pointer to a Metadata object
+ * \param exclusive Flag to indicate if only the data in mdata should be
+ *                  in the file. If false, any unrecognised tags already
+ *                  in the file will be maintained.
+ * \returns Boolean to indicate success/failure.
+ */
+bool MetaIOTagLib::write(Metadata* mdata, bool exclusive)
+{
+
+    if (!mdata)
+        return false;
+
+    File *taglib = new TagLib::MPEG::File(mdata->Filename().local8Bit());
+
+    Tag *tag = taglib->tag();
+
+    if (!tag)
+        return false;
+
+    if (!mdata->Artist().isEmpty())
+        tag->setArtist(QStringToTString(mdata->Artist()));
+
+    if (mdata->Compilation())
+    {
+
+        UserTextIdentificationFrame *musicbrainz =
+            new TagLib::ID3v2::UserTextIdentificationFrame(TagLib::String::UTF8);
+        taglib->ID3v2Tag()->addFrame(musicbrainz);
+        musicbrainz->setDescription("MusicBrainz Album Artist Id");
+        musicbrainz->setText(MYTH_MUSICBRAINZ_ALBUMARTIST_UUID);
+
+        if (!mdata->CompilationArtist().isEmpty())
+        {
+            // Compilation Artist (TPE4)
+            taglib->ID3v2Tag()->frameListMap()["TPE4"].front()->setText(
+                QStringToTString(mdata->CompilationArtist()));
+        }
+    }
+
+    if (!mdata->Title().isEmpty())
+        tag->setTitle(QStringToTString(mdata->Title()));
+
+    if (!mdata->Album().isEmpty())
+        tag->setAlbum(QStringToTString(mdata->Album()));
+
+    if (mdata->Year() > 999 && mdata->Year() < 10000) // 4 digit year.
+        tag->setYear(mdata->Year());
+
+    if (mdata->Rating() > 0 || mdata->PlayCount() > 0)
+    {
+//         removeComment(tag, MYTH_ID3_FRAME_POPULARIMETER, "devnull@mythtv.org");
+//         int rating = (int) floor(((float)mdata->Rating() / 10 * 255) + 0.5);
+//         setPopularimeter(tag, "devnull@mythtv.org", rating, QString("%1").arg(mdata->PlayCount()));
+    }
+
+    if (!mdata->Genre().isEmpty())
+        tag->setGenre(QStringToTString(mdata->Genre()));
+
+    if (0 != mdata->Track())
+        tag->setTrack(mdata->Track());
+
+    bool result = taglib->save();
+
+    return (result);
+}
+
+
+//==========================================================================
+/*!
+ * \brief Reads Metadata from a file.
+ *
+ * \param filename The filename to read metadata from.
+ * \returns Metadata pointer or NULL on error
+ */
+Metadata* MetaIOTagLib::read(QString filename)
+{
+    QString artist = "", compilation_artist = "", album = "", title = "",
+            genre = "";
+    int year = 0, tracknum = 0, length = 0, playcount = 0, rating = 0, id = 0;
+    bool compilation = false;
+
+    QString extension = filename.section( '.', -1 ) ;
+
+    File *taglib = new TagLib::MPEG::File(filename.local8Bit());
+
+    Tag *tag = taglib->tag();
+
+    if (!tag)
+        return NULL;
+
+    if (! tag->isEmpty())
+    {
+
+        title = TStringToQString(tag->title());
+        artist = TStringToQString(tag->artist());
+        album = TStringToQString(tag->album());
+
+        // Compilation Artist (TPE4)
+        if(!taglib->ID3v2Tag()->frameListMap()["TPE4"].isEmpty())
+            compilation_artist = TStringToQString(
+            taglib->ID3v2Tag()->frameListMap()["TPE4"].front()->toString());
+
+        // Look for MusicBrainz Album+Artist ID in TXXX Frame
+        UserTextIdentificationFrame *musicbrainz =
+            UserTextIdentificationFrame::find(taglib->ID3v2Tag(),
+                "MusicBrainz Album Artist Id");
+
+        // If the MusicBrainz ID is the special "Various Artists" ID
+        // then compilation is TRUE
+        compilation = (MYTH_MUSICBRAINZ_ALBUMARTIST_UUID
+            == TStringToQString(musicbrainz->toString()));
+
+        // Get Track Num dealing with 1/16, 2/16 etc. format
+        tracknum = tag->track();
+        //tracknum.replace(QRegExp("^([0-9]*).*"), QString("\\1")).toInt();
+
+        year = tag->year();
+
+        // Genre.
+        genre = TStringToQString(tag->genre());
+    }
+
+    // Fallback to filename reading
+    if (title.isEmpty())
+    {
+        readFromFilename(filename, artist, album, title, genre, tracknum);
+    }
+
+    if (length <= 0)
+        length = taglib->audioProperties()->length() * 1000;
+
+    // If we don't have title and artist or don't have the length return NULL
+    if ((title.isEmpty() && artist.isEmpty()) || length<=0)
+    {
+        VERBOSE(VB_IMPORTANT, QString("MetaIOTagLib: Failed to read metadata from '%1'")
+                .arg(filename));
+        return NULL;
+    }
+
+    Metadata *retdata = new Metadata(filename, artist, compilation_artist, album,
+                                     title, genre, year, tracknum, length,
+                                     id, rating, playcount);
+
+    //retdata->setCompilation(compilation);
+
+    return retdata;
+}
+
+/*!
+ * \brief Find the length of the track (in seconds)
+ *
+ * \param filename The filename for which we want to find the length.
+ * \returns An integer (signed!) to represent the length in seconds.
+ */
+int MetaIOTagLib::getTrackLength(QString filename)
+{
+    File *taglib = new TagLib::MPEG::File(filename.local8Bit());
+
+    int seconds = taglib->audioProperties()->length();
+
+    return seconds;
+}

Property changes on: mythmusic/mythmusic/metaiotaglib.cpp
___________________________________________________________________
Name: svn:eol-style
   + native

Index: mythmusic/mythmusic/metaioid3v2.cpp
===================================================================
--- mythmusic/mythmusic/metaioid3v2.cpp	(revision 13144)
+++ mythmusic/mythmusic/metaioid3v2.cpp	(working copy)
@@ -1,704 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <iostream>
-#include <fstream>
-#include <sys/stat.h>
-using namespace std;
-
-#include <mad.h>
-
-#include "metaioid3v2.h"
-#include "metadata.h"
-
-#include "metaio_libid3hack.h"
-
-#include <mythtv/mythcontext.h>
-
-//==========================================================================
-MetaIOID3v2::MetaIOID3v2(void)
-    : MetaIO(".mp3")
-{
-}
-
-//==========================================================================
-MetaIOID3v2::~MetaIOID3v2(void)
-{
-}
-
-
-//==========================================================================
-/*!
- * \brief Writes metadata back to a file
- *
- * \param mdata A pointer to a Metadata object
- * \param exclusive Flag to indicate if only the data in mdata should be
- *                  in the file. If false, any unrecognised tags already
- *                  in the file will be maintained.
- * \returns Boolean to indicate success/failure.
- */
-bool MetaIOID3v2::write(Metadata* mdata, bool exclusive)
-{
-    // Sanity check.
-    if (!mdata)
-        return false;
-
-    id3_file* p_input = NULL;
-    
-    p_input = id3_file_open(mdata->Filename().local8Bit(), ID3_FILE_MODE_READWRITE);
-    if (!p_input)
-        p_input = id3_file_open(mdata->Filename().ascii(), ID3_FILE_MODE_READWRITE);
-  
-    if (!p_input)
-      return false;
-
-    // We don't like id3v1 tags... too limiting.
-    // We don't write them on encoding, so we delete them if one exists.
-    id3_tag *tag = id3_file_tag(p_input);
-    if (!tag)
-    {
-        id3_file_close(p_input);
-        return false;
-    }
-
-    if (exclusive)
-    {
-       id3_tag_clearframes(tag);
-    }
-
-    if (!mdata->Artist().isEmpty())
-    {
-        if (!exclusive) removeComment(tag, ID3_FRAME_ARTIST);
-        setComment(tag, ID3_FRAME_ARTIST, mdata->Artist());
-    }
-    
-    if (mdata->Compilation())
-    {
-        if (!exclusive)
-            removeComment(tag, 
-                          MYTH_ID3_FRAME_COMMENT,
-                          MYTH_ID3_FRAME_MUSICBRAINZ_ALBUMARTISTDESC);
-                          
-        setComment(tag, MYTH_ID3_FRAME_COMMENT,
-                   MYTH_MUSICBRAINZ_ALBUMARTIST_UUID, 
-                   MYTH_ID3_FRAME_MUSICBRAINZ_ALBUMARTISTDESC);
-        
-        if (!mdata->CompilationArtist().isEmpty())
-        {
-            if (!exclusive) 
-                removeComment(tag, MYTH_ID3_FRAME_COMPILATIONARTIST);
-                
-            setComment(tag, MYTH_ID3_FRAME_COMPILATIONARTIST,
-                       mdata->CompilationArtist());        
-        }
-    }
-    else if (!exclusive) 
-    {
-        removeComment(tag, 
-                      MYTH_ID3_FRAME_COMMENT,
-                      MYTH_ID3_FRAME_MUSICBRAINZ_ALBUMARTISTDESC);
-                      
-        removeComment(tag, MYTH_ID3_FRAME_COMPILATIONARTIST);
-      
-    }
-
-    if (!mdata->Title().isEmpty())
-    {
-        if (!exclusive) removeComment(tag, ID3_FRAME_TITLE);
-        setComment(tag, ID3_FRAME_TITLE, mdata->Title());
-    }
-    
-    if (!mdata->Album().isEmpty())
-    {
-        if (!exclusive) removeComment(tag, ID3_FRAME_ALBUM);
-        setComment(tag, ID3_FRAME_ALBUM, mdata->Album());
-    }
-    
-    if (mdata->Year() > 999
-        && mdata->Year() < 10000) // 4 digit year.
-    {
-        if (!exclusive) removeComment(tag, ID3_FRAME_YEAR);
-        setComment(tag, ID3_FRAME_YEAR, QString("%1").arg(mdata->Year()));
-    }
-
-    // Write Genre maintaining the ID3v1 genre number if applicable
-    QString data = mdata->Genre();
-    if (!data.isEmpty())
-    {
-        if (!exclusive) removeComment(tag, ID3_FRAME_GENRE);
-
-        id3_ucs4_t* p_ucs4 = 
-          id3_utf8_ucs4duplicate((const id3_utf8_t*)(const char*)data.utf8());
-
-        int genrenum = id3_genre_number(p_ucs4);
-
-        free(p_ucs4);
-
-        // Use the number if it's standard, otherwise just write it (valid in ID3v2)
-        if (genrenum >= 0)
-            setComment(tag, ID3_FRAME_GENRE, 
-                       QString("%1").arg(genrenum));
-        else
-            setComment(tag, ID3_FRAME_GENRE, data);
-    }    
-    
-    if (0 != mdata->Track())
-    {
-        if (!exclusive) removeComment(tag, ID3_FRAME_TRACK);
-        setComment(tag, ID3_FRAME_TRACK, QString("%1").arg(mdata->Track()));
-    }
-
-
-    
-    id3_tag_options(tag, ID3_TAG_OPTION_COMPRESSION, 0);
-    id3_tag_options(tag, ID3_TAG_OPTION_CRC, 0);
-    id3_tag_options(tag, ID3_TAG_OPTION_UNSYNCHRONISATION, 0);
-    id3_tag_options(tag, ID3_TAG_OPTION_ID3V1, 0);
-    
-    // The id3_file_update function has a feature deficit.
-    // See the files: metaio_libid3hack.c/h
-    bool rv = (0 == ID3_FILE_UPDATE(p_input));
-
-    return (0 == id3_file_close(p_input)) && rv;
-}
-
-
-//==========================================================================
-/*!
- * \brief Reads Metadata from a file.
- *
- * \param filename The filename to read metadata from.
- * \returns Metadata pointer or NULL on error
- */
-Metadata* MetaIOID3v2::read(QString filename)
-{
-    QString artist = "", compilation_artist = "", album = "", title = "", 
-            genre = "";
-    int year = 0, tracknum = 0, length = 0;
-    bool compilation = false;
-    id3_file *p_input = NULL;
-    
-    p_input = id3_file_open(filename.local8Bit(), ID3_FILE_MODE_READONLY);
-    if (!p_input)
-        p_input = id3_file_open(filename.ascii(), ID3_FILE_MODE_READONLY);
-
-    if (p_input)
-    {
-        id3_tag *tag = id3_file_tag(p_input);
-        
-        if (!tag)
-        {
-            id3_file_close(p_input);
-            return NULL;
-        }
-        
-        title = getComment(tag, ID3_FRAME_TITLE);
-        artist = getComment(tag, ID3_FRAME_ARTIST);
-        compilation_artist = getComment(tag, MYTH_ID3_FRAME_COMPILATIONARTIST);
-        album = getComment(tag, ID3_FRAME_ALBUM);
-        compilation = (MYTH_MUSICBRAINZ_ALBUMARTIST_UUID 
-                       == getComment(tag,
-                                     MYTH_ID3_FRAME_COMMENT,
-                                     MYTH_ID3_FRAME_MUSICBRAINZ_ALBUMARTISTDESC));
-                                          
-        // Get Track Num dealing with 1/16, 2/16 etc. format
-        tracknum = getComment(tag, ID3_FRAME_TRACK)
-            .replace(QRegExp("^([0-9]*).*"), QString("\\1")).toInt();
-        
-        // NB Year could be TDRC or TYER depending on version....
-        // From: http://www.id3.org/id3v2.4.0-structure.txt
-        // Time stamps can be: yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddTHH,
-        //                     yyyy-MM-ddTHH:mm and yyyy-MM-ddTHH:mm:ss
-        // Basically all starting yyyy.
-        
-        // Depending on the version of libid3tag, it will reassign a #define,
-        // but we want to look for both.
-        year = getComment(tag, ID3_FRAME_YEAR)
-            .replace(QRegExp("^([0-9]{4}).*"), QString("\\1")).toInt();
-        if (0 == year)
-            year = getComment(tag, "TYER").toInt();
-        
-        // Genre.
-        genre = getComment(tag, ID3_FRAME_GENRE);
-        
-        // Genre in ID3v2 = "genrenum|Genre Name"
-        QString genrenumtest = genre;
-        genrenumtest.replace(QRegExp("^[0-9]*$"), QString(""));
-        
-        if (genrenumtest.isEmpty())
-        {
-            // This means the genre is 100% numeric
-            // Try and decode genre number        
-            id3_ucs4_t *p_tmp = 
-                id3_utf8_ucs4duplicate((const id3_utf8_t*)(const char*)genre.utf8());
-            
-            id3_ucs4_t const *p_ucs4 = id3_genre_name(p_tmp);
-            free(p_tmp);
-    
-            id3_utf8_t *p_utf8 = id3_ucs4_utf8duplicate(p_ucs4);  
-            genre = QString::fromUtf8((const char*)p_utf8);
-            
-            free(p_utf8);
-        }
-
-        // If the ID3v2 tag contains the length, then use it
-        length = getComment(tag, "TLEN").toInt();
-
-        id3_file_close(p_input);
-    }
-
-    // Fallback to filename reading
-    if (title.isEmpty())
-    {
-        readFromFilename(filename, artist, album, title, genre, tracknum);
-    }
-
-    if (length <= 0)
-        length = getTrackLength(filename);
-
-    // If we don't have title and artist or don't have the length return NULL
-    if ((title.isEmpty() && artist.isEmpty()) || length<=0)
-    {
-        VERBOSE(VB_IMPORTANT, QString("MetaIOID3v2: Failed to read metadata from '%1'")
-                .arg(filename));
-        return NULL;
-    }
-
-    Metadata *retdata = new Metadata(filename, artist, compilation_artist, album,
-                                     title, genre, year, tracknum, length);
-
-    retdata->setCompilation(compilation);
-
-    return retdata;
-}
-
-
-//==========================================================================
-/*!
- * \brief Find the length of the track (in milliseconds)
- *
- * \param filename The filename for which we want to find the length.
- * \returns An integer (signed!) to represent the length in milliseconds.
- */
-int MetaIOID3v2::getTrackLength(QString filename)
-{
-    struct mad_stream stream;
-    struct mad_header header;
-    struct mad_frame frame;
-    mad_timer_t timer;
-
-    unsigned char buffer[8192];
-    unsigned int buflen = 0;
-
-    mad_stream_init(&stream);
-    mad_header_init(&header);
-    mad_frame_init(&frame);
-
-    timer = mad_timer_zero;
-
-    FILE *input = fopen(filename.local8Bit(), "r");
-    if (!input)
-        input = fopen(filename.ascii(), "r");
-
-    if (!input)
-        return 0;
-
-    struct stat s;
-    fstat(fileno(input), &s);
-    unsigned long old_bitrate = 0;
-    bool vbr = false;
-    int amount_checked = 0;
-    int alt_length = 0;
-    bool loop_de_doo = true;
-    
-    while (loop_de_doo) 
-    {
-        if (buflen < sizeof(buffer)) 
-        {
-            int bytes;
-            bytes = fread(buffer + buflen, 1, sizeof(buffer) - buflen, input);
-            if (bytes <= 0)
-                break;
-            buflen += bytes;
-        }
-
-        mad_stream_buffer(&stream, buffer, buflen);
-
-        while (1)
-        {
-            if (mad_header_decode(&header, &stream) == -1)
-            {
-                if (!MAD_RECOVERABLE(stream.error))
-                {
-                    break;
-                }
-                if (stream.error == MAD_ERROR_LOSTSYNC)
-                {
-                    int tagsize = id3_tag_query(stream.this_frame,
-                                                stream.bufend - 
-                                                stream.this_frame);
-                    if (tagsize > 0)
-                    {
-                        mad_stream_skip(&stream, tagsize);
-                        s.st_size -= tagsize;
-                    }
-                }
-            }
-            else
-            {
-
-                if (amount_checked == 0)
-                {
-                    frame.header = header;
-                    if (mad_frame_decode(&frame, &stream) == -1)
-                    {
-                            if (!MAD_RECOVERABLE(stream.error))
-                            {
-                                    VERBOSE(VB_IMPORTANT, "Unrecoverable "
-                                        "libmad stream error.");
-                                    break;
-                            }
-                    }
-
-                    xing xing;
-                    xing.frames = 0;
-                    xing.bytes = 0;
-
-                    // If we find a xing header we can save time
-                    // by multiplying the frame count by the
-                    // duration of the first frame
-                    if (findXingHeader(&xing, stream.anc_ptr,
-                        stream.anc_bitlen))
-                    {
-                        unsigned long frames = xing.frames;
-                        mad_timer_t duration = header.duration;
-                        mad_timer_multiply(&duration, frames);
-                        alt_length = mad_timer_count(duration,
-                                            MAD_UNITS_MILLISECONDS);
-                        loop_de_doo = false;
-                        break;
-                    }
-                }
-
-                if(amount_checked == 0)
-                {
-                    old_bitrate = header.bitrate;
-                }
-                else if(header.bitrate != old_bitrate)
-                {
-                    vbr = true;
-                }
-                if(amount_checked == 32 && !vbr)
-                {
-                    alt_length = (s.st_size * 8) / (old_bitrate / 1000);
-                    loop_de_doo = false;
-                    break;
-                }
-                amount_checked++;
-                mad_timer_add(&timer, header.duration);
-            }
-
-        }
-
-        if (stream.error != MAD_ERROR_BUFLEN)
-            break;
-
-        memmove(buffer, stream.next_frame, &buffer[buflen] - stream.next_frame);
-        buflen -= stream.next_frame - &buffer[0];
-    }
-
-    mad_header_finish(&header);
-    mad_stream_finish(&stream);
-    mad_frame_finish(&frame);
-
-    fclose(input);
-
-    if (vbr)
-        return mad_timer_count(timer, MAD_UNITS_MILLISECONDS);
-
-    return alt_length;
-}
-
-bool MetaIOID3v2::findXingHeader(xing *xing, struct mad_bitptr ptr,
-unsigned int bitlen)
-{
-    if (bitlen < 64 || mad_bit_read(&ptr, 32) != XING_MAGIC)
-        goto fail;
-
-    xing->flags = mad_bit_read(&ptr, 32);
-    bitlen -= 64;
-
-    if (xing->flags & XING_FRAMES) {
-        if (bitlen < 32)
-            goto fail;
-
-        xing->frames = mad_bit_read(&ptr, 32);
-        bitlen -= 32;
-    }
-
-    if (xing->flags & XING_BYTES) {
-        if (bitlen < 32)
-            goto fail;
-
-        xing->bytes = mad_bit_read(&ptr, 32);
-        bitlen -= 32;
-    }
-
-    if (xing->flags & XING_TOC) {
-        int i;
-
-        if (bitlen < 800)
-            goto fail;
-
-        for (i = 0; i < 100; ++i)
-            xing->toc[i] = mad_bit_read(&ptr, 8);
-
-        bitlen -= 800;
-    }
-
-    if (xing->flags & XING_SCALE) {
-        if (bitlen < 32)
-            goto fail;
-
-        xing->scale = mad_bit_read(&ptr, 32);
-        bitlen -= 32;
-    }
-
-    return true;
-
- fail:
-    xing->flags = 0;
-    xing->frames = 0;
-    xing->bytes = 0;
-    xing->scale = 0;
-    return false;
-}
-
-inline QString MetaIOID3v2::getRawID3String(union id3_field *pField)
-{
-    QString tmp = "";
-        
-    id3_ucs4_t const *p_ucs4 = (id3_ucs4_t *) id3_field_getstring(pField);
-    
-    if (p_ucs4)
-    {
-        id3_utf8_t *p_utf8 = id3_ucs4_utf8duplicate(p_ucs4);
-        
-        if (!p_utf8)
-             return "";
-
-        tmp = QString::fromUtf8((const char*)p_utf8);
-
-        free(p_utf8);
-    }
-    else
-    {
-        unsigned int nstrings = id3_field_getnstrings(pField);
-    
-        for (unsigned int j=0; j<nstrings; ++j)
-        {
-            p_ucs4 = id3_field_getstrings(pField, j);
-
-            if (!p_ucs4)
-                break;
-
-           id3_utf8_t *p_utf8 = id3_ucs4_utf8duplicate(p_ucs4);
-
-           if (!p_utf8)
-               break;
-
-           tmp += QString::fromUtf8((const char*)p_utf8);
-
-           free(p_utf8);
-       }
-    }
-    
-    return tmp;
-  
-}
-
-//==========================================================================
-/*!
- * \brief Function to remove an individual comment in an ID3v2 Tag
- *
- * \param pTag Pointer to a id3_file object
- * \param pLabel The label of the comment you want to delete
- * \param desc Optional descripton to delete (frame type pLabel must support this)
- * \returns Nothing
- */
-void MetaIOID3v2::removeComment(id3_tag *pTag,
-                                const char* pLabel,
-                                const QString desc)
-{
-    if (!pLabel)
-        return;
-    
-    struct id3_frame* p_frame = NULL;
-    
-    bool just_delete = desc.isEmpty();
-    
-    for (int i=0; NULL != (p_frame = id3_tag_findframe(pTag, pLabel, i)); ++i)
-    {
-        if (just_delete)
-        {
-            // Let's delete it!!
-            if (0 == id3_tag_detachframe(pTag, p_frame))
-                id3_frame_delete(p_frame);
-        }
-        else
-        {
-            // Get the description to compare
-            QString tmp = getRawID3String(&p_frame->fields[1]);
-
-            // Let's compare the descriptions.
-            if (tmp == desc)
-            {
-                // Now we know the descriptions match so we delete the frame.
-                if (0 == id3_tag_detachframe(pTag, p_frame))
-                    id3_frame_delete(p_frame);
-                
-                // We're done
-                break;
-            }
-        }
-    }
-}
-
-
-//==========================================================================
-/*!
- * \brief Function to return an individual comment from an ID3v2 comment
- *
- * \param pTag Pointer to a id3_file object
- * \param pLabel The label of the comment you want
- * \param desc An optional description (frame type pLabel must support this)
- * \returns QString containing the contents of the comment you want
- */
-QString MetaIOID3v2::getComment(id3_tag *pTag, const char* pLabel, 
-                                const QString desc)
-{
-    if (!pLabel)
-        return "";
-
-    struct id3_frame *p_frame = NULL;
-    
-    for (int i=0; NULL != (p_frame = id3_tag_findframe(pTag, pLabel, i)); ++i ) 
-    {
-        int field_num = 1;
-        
-        QString tmp = "";
-        
-        // Compare the first field with the description if supplied
-        if (!desc.isEmpty())
-        {
-            tmp = getRawID3String(&p_frame->fields[field_num++]);
-
-            // Now compare tmp to desc
-            if (tmp != desc)
-            {
-                // No match - move on.
-                continue;
-            }      
-        }
-          
-        // Get the value and return it.
-        tmp = getRawID3String(&p_frame->fields[field_num]);
-
-        return tmp;
-    }
-    
-    // Not found.
-    return "";
-}
-
-//==========================================================================
-/*!
- * \brief Function to set an individual comment in an ID3v2 Tag
- *
- * \param pTag Pointer to a id3_file object
- * \param pLabel The label of the comment you want
- * \param value A reference to the data you want to write
- * \param desc An optional description (frame type pLabel must support this)
- * \returns Nothing
- */
-bool MetaIOID3v2::setComment(id3_tag *pTag,
-                             const char* pLabel, 
-                             const QString value,
-                             const QString desc)
-{
-    if (!pLabel || "" == value)
-      return false;
-
-    struct id3_frame* p_frame = NULL;
-    id3_ucs4_t* p_ucs4 = NULL;
-
-    p_frame = id3_frame_new(pLabel);
-
-    if (NULL == p_frame)
-      return false;
-
-    QString prefencoding = gContext->GetSetting("MusicTagEncoding");
-    enum id3_field_textencoding encoding = ID3_FIELD_TEXTENCODING_UTF_16;
-
-    if (prefencoding == "ascii")
-    {
-        encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;
-    }
-    else if (prefencoding == "utf8")
-    {
-        encoding = ID3_FIELD_TEXTENCODING_UTF_8;
-    }
-
-    if (id3_field_settextencoding(&p_frame->fields[0],
-                                  encoding) != 0)
-    {
-        id3_frame_delete(p_frame);
-        return false;
-    }
-
-    // Write a description in field 1 if needs be.
-    if (!desc.isEmpty())
-    {
-        p_ucs4 = id3_utf8_ucs4duplicate((const id3_utf8_t*)(const char*)desc.utf8());
-    
-        if (!p_ucs4)
-        {
-            id3_frame_delete(p_frame);
-            return false;      
-        }
-    
-        if (0 != id3_field_setstring(&p_frame->fields[1], p_ucs4))
-        {
-            free(p_ucs4);
-            id3_frame_delete(p_frame);
-            return false;      
-        }
-          
-        free(p_ucs4);
-    }
-
-    p_ucs4 = id3_utf8_ucs4duplicate((const id3_utf8_t*)(const char*)value.utf8());
-
-    if (!p_ucs4)
-    {
-        id3_frame_delete(p_frame);
-        return false;      
-    }
-
-    if ((desc.isEmpty() && id3_field_setstrings(&p_frame->fields[1], 1, &p_ucs4))
-        || (!desc.isEmpty() && id3_field_setstring(&p_frame->fields[2], p_ucs4)))
-    {
-        free(p_ucs4);
-        id3_frame_delete(p_frame);
-        return false;      
-    }
-
-    free(p_ucs4);
-
-    if (0 != id3_tag_attachframe(pTag, p_frame))
-    {
-        id3_frame_delete(p_frame);
-        return false;      
-    }
-
-    return true;
-}
Index: mythmusic/mythmusic/maddecoder.cpp
===================================================================
--- mythmusic/mythmusic/maddecoder.cpp	(revision 13144)
+++ mythmusic/mythmusic/maddecoder.cpp	(working copy)
@@ -8,13 +8,12 @@
 using namespace std;
 
 #include <mad.h>
-#include <id3tag.h>
 
 #include "maddecoder.h"
 #include "metadata.h"
 #include "constants.h"
 #include <mythtv/audiooutput.h>
-#include "metaioid3v2.h"
+#include "metaiotaglib.h"
 
 #include <mythtv/mythconfig.h>
 #include <mythtv/mythcontext.h>
@@ -530,7 +529,7 @@
 
 MetaIO *MadDecoder::doCreateTagger(void)
 {
-    return new MetaIOID3v2();
+    return new MetaIOTagLib();
 }
 
 bool MadDecoderFactory::supports(const QString &source) const
Index: mythmusic/mythmusic/metaio_libid3hack.c
===================================================================
--- mythmusic/mythmusic/metaio_libid3hack.c	(revision 13144)
+++ mythmusic/mythmusic/metaio_libid3hack.c	(working copy)
@@ -1,283 +0,0 @@
-/** \file metaio_libid3hack.c
-    \brief Full featured id3_file_update implementation.
-
-    libid3tag (0.15.1b) id3_file_update doesn't handle ID3V2 tags that
-    are longer than then existing tag, this includes adding ID3v2
-    tags. Hence this file which is a cut'n'paste job of libid3tags
-    file.c, with the extra feaures and some tweaks like always
-    removing id3v1 tags.
-   
- */
-#include <id3tag.h>
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-enum {
-  ID3_FILE_FLAG_ID3V1 = 0x0001
-};
-
-struct id3_file {
-  FILE *iofile;
-  enum id3_file_mode mode;
-  char *path;
-
-  int flags;
-
-  struct id3_tag *primary;
-
-  unsigned int ntags;
-  struct filetag *tags;
-};
-
-struct filetag {
-  struct id3_tag *tag;
-  unsigned long location;
-  id3_length_t length;
-};
-
-
-/*
- * NAME: v2_write()
- * DESCRIPTION:  write ID3v2 tag modifications to a file
- */
-static
-int myth_v2_write(struct id3_file *file,
-                  id3_byte_t const *data, id3_length_t length)
-{
-  int result = 0;
-  int file_size, overlap;
-  size_t location, data_start;
-  char *buffer = NULL;
-  int buffersize;
-  
-  int bytesread1, bytesread2, bytesread_tmp;
-  char *ring1 = NULL, *ring2 = NULL, *ring_tmp = NULL;
-
-  assert(!data || length > 0);
-
-  if ((file->ntags == 1 && !(file->flags & ID3_FILE_FLAG_ID3V1)) || file->ntags >= 2) {
-      overlap = length - file->tags[0].length;
-      location = file->tags[0].location;
-      data_start = file->tags[0].location + file->tags[0].length;
-  } else {
-      overlap = length;
-      location = 0;
-      data_start = 0;
-  }
-
-  if (overlap == 0) {
-    /* easy special case: rewrite existing tag in-place */
-
-    if (fseek(file->iofile, location, SEEK_SET) == -1 ||
-        fwrite(data, length, 1, file->iofile) != 1 ||
-        fflush(file->iofile) == EOF)
-      return -1;
-
-    goto done;
-    
-  }
-  
-  /* the new tag has a different size */
-  
-  /* calculate the difference in tag sizes.
-   * we'll need at least double this difference to write the file again using 
-   * optimal memory allocation, but avoiding a temporary file.
-   */  
-  
-  if (overlap > 0) {
-    buffersize = overlap*2;
-    buffer = (char*)malloc(buffersize);
-    if (!buffer)
-      return -1;
-      
-    ring1 = buffer;
-    ring2 = &buffer[overlap];
-  } else {
-    /* let's use a 100kB buffer */
-    buffersize = 100*1024;
-    buffer = (char*)malloc(buffersize);
-  }
-  
-  /* find out the filesize */
-  fseek(file->iofile, 0, SEEK_END);
-  file_size = ftell(file->iofile);
-  
-  /* Seek to start of data */
-  if (-1 == fseek(file->iofile, data_start, SEEK_SET))
-    goto fail;
-  
-  /* fill our buffer, if needed */
-  if (overlap > 0) {
-    if (1 != fread(buffer, buffersize, 1, file->iofile))
-      goto fail;
-  }
-  
-  /* write the tag where the old one was */
-  if (-1 == fseek(file->iofile, location, SEEK_SET)
-      || 1 != fwrite(data, length, 1, file->iofile))
-    goto fail;
-  
-  /* loop through reading and writing the data */
-  if (overlap > 0) {
-   
-    /* File is getting larger */
-    bytesread1 = bytesread2 = overlap;
-    while (0 != bytesread1 || 0 != bytesread2) {
-  
-      /* Write the contents of ring1 */
-      if (1 != fwrite(ring1, bytesread1, 1, file->iofile))
-        goto fail;
-      
-      /* Read the next "overlap" bytes into ring1 */
-      bytesread1 = fread(ring1, 1, overlap, file->iofile);
-      
-      if (bytesread1 > 0) {
-        /* Seek back that many bytes */
-        if (-1 == fseek(file->iofile, -1*bytesread1, SEEK_CUR))
-          goto fail;
-      }
-      
-      /* swap rings */
-      ring_tmp = ring1;
-      ring1 = ring2;
-      ring2 = ring_tmp;
-      
-      bytesread_tmp = bytesread1;
-      bytesread1 = bytesread2;
-      bytesread2 = bytesread_tmp;
-    }
-  } else {
-     
-    /* File is getting smaller */
-    
-    /* remember "overlap" is negative so let's absolute it */
-    overlap *= -1;
-    
-    while (0 == feof(file->iofile)) {
-      
-      /* seek ahead "overlap" bytes */
-      if (-1 == fseek(file->iofile, overlap, SEEK_CUR))
-        goto fail;
-      
-      /* read buffer */
-      bytesread1 = fread(buffer, 1, buffersize, file->iofile);
-      
-      if (bytesread1 > 0) {
-        /* seek back that many bytes */
-        if (-1 == fseek(file->iofile, -1*(bytesread1+overlap), SEEK_CUR))
-          goto fail;
-      
-        /* write the buffer contents */
-        if (1 != fwrite(buffer, bytesread1, 1, file->iofile))
-          goto fail;
-      } else {
-        /* just seek back to the point we should be at for truncation */
-        if (-1 == fseek(file->iofile, -1*overlap, SEEK_CUR))
-          goto fail;
-      }
-      
-      /* Check to see if we've reached the end of the file */
-      if (bytesread1 != buffersize)
-        break;
-    }
-  }
-  
-  if (buffer)
-  {
-    free(buffer);
-    buffer = NULL;
-  }
-  
-  /* flush the FILE */
-  if (fflush(file->iofile) == EOF)
-    goto fail;
-  
-  /* truncate if required */
-  if (ftell(file->iofile) < file_size)
-    ftruncate(fileno(file->iofile), ftell(file->iofile));
-
-  if (0) {
-  fail:
-    if (buffer) free(buffer);
-    result = -1;
-  }
-
- done:
-  return result;
-}
-
-/*
- * NAME: file->update()
- * DESCRIPTION:  rewrite tag(s) to a file
- */
-int myth_id3_file_update(struct id3_file *file)
-{
-  int options, result = 0;
-  id3_length_t v2size = 0;
-  id3_byte_t *id3v2 = 0;
-
-  assert(file);
-
-  if (file->mode != ID3_FILE_MODE_READWRITE)
-    return -1;  
-
-  options = id3_tag_options(file->primary, 0, 0);
-
-  /* render ID3v2 */
-
-  id3_tag_options(file->primary, ID3_TAG_OPTION_ID3V1, 0);
-
-  v2size = id3_tag_render(file->primary, 0);
-  if (v2size) {
-      id3v2 = (id3_byte_t*)malloc(v2size);
-    if (id3v2 == 0)
-      goto fail;
-
-    v2size = id3_tag_render(file->primary, id3v2);
-    if (v2size == 0) {
-      free(id3v2);
-      id3v2 = 0;
-    }
-  }
-
-  /* write tags */
-
-  if (myth_v2_write(file, id3v2, v2size) == -1)
-    goto fail;
-
-  /* If ID3v1 tag present (flag set and 'TAG' at size-128 bytes),
-   * remove it by truncating.
-   */
-  if (file->flags & ID3_FILE_FLAG_ID3V1) {
-      char tag[3];
-      if (fseek (file->iofile, -128, SEEK_END) != 0 ||
-          fread (tag, sizeof(tag), 1, file->iofile) != 1)
-          goto fail;
-      if (memcmp (tag, "TAG", sizeof (tag)) == 0)
-          ftruncate (fileno (file->iofile), ftell (file->iofile) - 3);
-      file->flags ^= ID3_FILE_FLAG_ID3V1;
-  }
-
-  rewind(file->iofile);
-
-  /* update file tags array? ... */
-
-  if (0) {
-  fail:
-    result = -1;
-  }
-
-  /* clean up; restore tag options */
-
-  if (id3v2)
-    free(id3v2);
-
-  id3_tag_options(file->primary, ~0, options);
-
-  return result;
-}
-