rendered paste bodyIndex: 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;
-}
-