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 -} - -// 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 @@ -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 +#include +#include + +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 +#include +#include +#include +#include +#include +using namespace std; + +#include "metaiotaglib.h" +#include "metadata.h" + +#include + +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 -#include -#include -#include -#include -using namespace std; - -#include - -#include "metaioid3v2.h" -#include "metadata.h" - -#include "metaio_libid3hack.h" - -#include - -//========================================================================== -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; jfields[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 -#include #include "maddecoder.h" #include "metadata.h" #include "constants.h" #include -#include "metaioid3v2.h" +#include "metaiotaglib.h" #include #include @@ -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 - -#include -#include -#include -#include -#include - -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; -} -