Skip to content

Commit

Permalink
MythMusic: add some virtual functions to the MetaIO base class.
Browse files Browse the repository at this point in the history
This adds some virtual functions to the base MetaIO class that derived classes
can override for accessing any embedded album art supported by the tag format.

Update the Id3 tagger to support reading, writing and removing any album art.
  • Loading branch information
Paul Harrison committed May 31, 2011
1 parent 7b9a3a1 commit a52601a
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 40 deletions.
2 changes: 2 additions & 0 deletions mythplugins/mythmusic/mythmusic/metadata.h
Expand Up @@ -41,6 +41,8 @@ typedef struct AlbumArtImage
bool embedded;
} AlbumArtImage;

typedef QList<AlbumArtImage*> AlbumArtList;

typedef QHash<QString,QString> MetadataMap;

class Metadata
Expand Down
41 changes: 38 additions & 3 deletions mythplugins/mythmusic/mythmusic/metaio.h
Expand Up @@ -4,10 +4,10 @@
// QT
#include <QString>

#define MYTH_MUSICBRAINZ_ALBUMARTIST_UUID "89ad4ac3-39f7-470e-963a-56509c546377"
// MythMusic
#include "metadata.h"

// No need to include all the Metadata stuff just for the abstract pointer....
class Metadata;
#define MYTH_MUSICBRAINZ_ALBUMARTIST_UUID "89ad4ac3-39f7-470e-963a-56509c546377"

class MetaIO
{
Expand Down Expand Up @@ -44,6 +44,41 @@ class MetaIO
*/
virtual Metadata* read(QString filename) = 0;

/*!
* \brief Does the tag support embedded cover art.
*
* \returns true if reading/writing embedded images are supported
*/
virtual bool supportsEmbeddedImages(void)
{
return false;
}

/*!
* \brief Reads the list of embedded images in the tag
*
* \returns the list of embedded images
*/
virtual AlbumArtList getAlbumArtList(const QString &filename)
{
(void)filename;
return AlbumArtList();
}

virtual bool writeAlbumArt(const QString &filename, const AlbumArtImage *albumart)
{
(void)filename;
(void)albumart;
return false;
}

virtual bool removeAlbumArt(const QString &filename, const AlbumArtImage *albumart)
{
(void)filename;
(void)albumart;
return false;
}

void readFromFilename(QString filename, QString &artist, QString &album,
QString &title, QString &genre, int &tracknum);

Expand Down
208 changes: 178 additions & 30 deletions mythplugins/mythmusic/mythmusic/metaioid3.cpp
Expand Up @@ -218,14 +218,6 @@ Metadata *MetaIOID3::read(QString filename)
// e.g. Lame under certain circumstances will always write a length of
// 27 hours

// Album Art
if (!tag->frameListMap()["APIC"].isEmpty())
{
QList<struct AlbumArtImage> albumart;
albumart = readAlbumArt(tag);
metadata->setEmbeddedAlbumArt(albumart);
}

metadata->setCompilation(compilation);

TagLib::FileRef *fileref = new TagLib::FileRef(mpegfile);
Expand Down Expand Up @@ -304,6 +296,36 @@ QImage MetaIOID3::getAlbumArt(QString filename, ImageType type)
return picture;
}


/*!
* \brief Read the albumart images from the file
*
* \param filename The filename for which we want to find the images.
*/
AlbumArtList MetaIOID3::getAlbumArtList(const QString &filename)
{
AlbumArtList imageList;
QByteArray fname = filename.toLocal8Bit();
TagLib::MPEG::File *mpegfile = new TagLib::MPEG::File(fname.constData());

if (mpegfile)
{
TagLib::ID3v2::Tag *tag = mpegfile->ID3v2Tag();

if (!tag)
{
delete mpegfile;
return imageList;
}

imageList = readAlbumArt(tag);

delete mpegfile;
}

return imageList;
}

/*!
* \brief Read the albumart image from the file
*
Expand All @@ -313,7 +335,7 @@ QImage MetaIOID3::getAlbumArt(QString filename, ImageType type)
*/
AlbumArtList MetaIOID3::readAlbumArt(TagLib::ID3v2::Tag *tag)
{
QList<struct AlbumArtImage> artlist;
AlbumArtList artlist;

if (!tag->frameListMap()["APIC"].isEmpty())
{
Expand All @@ -335,34 +357,38 @@ AlbumArtList MetaIOID3::readAlbumArt(TagLib::ID3v2::Tag *tag)
continue;
}

AlbumArtImage art;
AlbumArtImage *art = new AlbumArtImage();

if (frame->description().isEmpty())
{
art.description.clear();
}
else {
art.description = TStringToQString(frame->description());
}
art->description.clear();
else
art->description = TStringToQString(frame->description());

art.embedded = true;
art->embedded = true;

QString ext = getExtFromMimeType(TStringToQString(frame->mimeType()).toLower());

switch (frame->type())
{
case AttachedPictureFrame::FrontCover :
art.imageType = IT_FRONTCOVER;
art->imageType = IT_FRONTCOVER;
art->filename = QString("front") + ext;
break;
case AttachedPictureFrame::BackCover :
art.imageType = IT_BACKCOVER;
art->imageType = IT_BACKCOVER;
art->filename = QString("back") + ext;
break;
case AttachedPictureFrame::Media :
art.imageType = IT_CD;
art->imageType = IT_CD;
art->filename = QString("cd") + ext;
break;
case AttachedPictureFrame::LeafletPage :
art.imageType = IT_INLAY;
art->imageType = IT_INLAY;
art->filename = QString("inlay") + ext;
break;
case AttachedPictureFrame::Other :
art.imageType = IT_UNKNOWN;
art->imageType = IT_UNKNOWN;
art->filename = QString("unknown") + ext;
break;
default:
VERBOSE(VB_GENERAL, "Music Scanner - APIC tag found "
Expand All @@ -377,6 +403,22 @@ AlbumArtList MetaIOID3::readAlbumArt(TagLib::ID3v2::Tag *tag)
return artlist;
}

QString MetaIOID3::getExtFromMimeType(const QString &mimeType)
{
if (mimeType == "image/png")
return QString(".png");
else if (mimeType == "image/jpeg" || mimeType == "image/jpg")
return QString(".jpg");
else if (mimeType == "image/gif")
return QString(".gif");
else if (mimeType == "image/bmp")
return QString(".bmp");

VERBOSE(VB_GENERAL, QString("Music Scanner - Unknow image mimetype found - %1").arg(mimeType));

return QString();
}

/*!
* \brief Find an APIC tag by type and optionally description
*
Expand All @@ -403,17 +445,58 @@ AttachedPictureFrame* MetaIOID3::findAPIC(TagLib::ID3v2::Tag *tag,
/*!
* \brief Write the albumart image to the file
*
* \param tag The ID3v2 tag object in which to look for Album Art
* \param filename The music file to add the albumart
* \param albumart The Album Art image to write
* \returns True if successful
*
* \Note We always save the image in JPEG format
*/
bool MetaIOID3::writeAlbumArt(TagLib::ID3v2::Tag *tag, QByteArray *image,
const AttachedPictureFrame::Type &type,
const QString &mimetype)
bool MetaIOID3::writeAlbumArt(const QString &filename, const AlbumArtImage *albumart)
{
if (!tag || !image)
if (filename.isEmpty() || !albumart)
return false;

// load the image into a QByteArray
QImage image(albumart->filename);
QByteArray imageData;
QBuffer buffer(&imageData);
buffer.open(QIODevice::WriteOnly);
image.save(&buffer, "JPEG");

AttachedPictureFrame::Type type = AttachedPictureFrame::Other;
switch (albumart->imageType)
{
case IT_FRONTCOVER:
type = AttachedPictureFrame::FrontCover;
break;
case IT_BACKCOVER:
type = AttachedPictureFrame::BackCover;
break;
case IT_CD:
type = AttachedPictureFrame::Media;
break;
case IT_INLAY:
type = AttachedPictureFrame::LeafletPage;
break;
default:
type = AttachedPictureFrame::Other;
break;
}

TagLib::MPEG::File *mpegfile = OpenFile(filename);

if (!mpegfile)
return false;

AttachedPictureFrame *apic = findAPIC(tag, type);
TagLib::ID3v2::Tag *tag = mpegfile->ID3v2Tag();

if (!tag)
{
delete mpegfile;
return false;
}

AttachedPictureFrame *apic = findAPIC(tag, type, QStringToTString(albumart->description));

if (!apic)
{
Expand All @@ -422,12 +505,77 @@ bool MetaIOID3::writeAlbumArt(TagLib::ID3v2::Tag *tag, QByteArray *image,
apic->setType(type);
}

QString mimetype = "image/jpeg";

TagLib::ByteVector bytevector;
bytevector.setData(image->data(), image->size());
delete image;
bytevector.setData(imageData.data(), imageData.size());

apic->setMimeType(QStringToTString(mimetype));
apic->setPicture(bytevector);
apic->setDescription(QStringToTString(albumart->description));

mpegfile->save();
delete mpegfile;

return true;
}

/*!
* \brief Remove the albumart image from the file
*
* \param filename The music file to remove the albumart
* \param albumart The Album Art image to remove
* \returns True if successful
*/
bool MetaIOID3::removeAlbumArt(const QString &filename, const AlbumArtImage *albumart)
{
if (filename.isEmpty() || !albumart)
return false;

AttachedPictureFrame::Type type = AttachedPictureFrame::Other;
switch (albumart->imageType)
{
case IT_FRONTCOVER:
type = AttachedPictureFrame::FrontCover;
break;
case IT_BACKCOVER:
type = AttachedPictureFrame::BackCover;
break;
case IT_CD:
type = AttachedPictureFrame::Media;
break;
case IT_INLAY:
type = AttachedPictureFrame::LeafletPage;
break;
default:
type = AttachedPictureFrame::Other;
break;
}

TagLib::MPEG::File *mpegfile = OpenFile(filename);

if (!mpegfile)
return false;

TagLib::ID3v2::Tag *tag = mpegfile->ID3v2Tag();

if (!tag)
{
delete mpegfile;
return false;
}

AttachedPictureFrame *apic = findAPIC(tag, type, QStringToTString(albumart->description));
if (!apic)
{
delete mpegfile;
return false;
}

tag->removeFrame(apic);

mpegfile->save();
delete mpegfile;

return true;
}
Expand Down
16 changes: 9 additions & 7 deletions mythplugins/mythmusic/mythmusic/metaioid3.h
Expand Up @@ -24,8 +24,6 @@ using TagLib::ID3v2::PopularimeterFrame;
using TagLib::ID3v2::AttachedPictureFrame;
using TagLib::MPEG::Properties;

typedef QList<struct AlbumArtImage> AlbumArtList;

/*!
* \class MetaIOID3
*
Expand All @@ -44,23 +42,27 @@ class MetaIOID3 : public MetaIOTagLib
bool write(Metadata* mdata);
bool writeVolatileMetadata(const Metadata* mdata);

bool writePlayCount(TagLib::ID3v2::Tag *tag, int playcount);
bool writeRating(TagLib::ID3v2::Tag *tag, int rating);
bool writeAlbumArt(TagLib::ID3v2::Tag *tag, QByteArray *image,
const AttachedPictureFrame::Type &type,
const QString &mimetype);
bool writeAlbumArt(const QString &filename, const AlbumArtImage *albumart);
bool removeAlbumArt(const QString &filename, const AlbumArtImage *albumart);

Metadata* read(QString filename);
AlbumArtList getAlbumArtList(const QString &filename);
static QImage getAlbumArt(QString filename, ImageType type);

bool supportsEmbeddedImages(void) { return true; }

private:
TagLib::MPEG::File *OpenFile(const QString &filename);

bool writePlayCount(TagLib::ID3v2::Tag *tag, int playcount);
bool writeRating(TagLib::ID3v2::Tag *tag, int rating);

AlbumArtList readAlbumArt(TagLib::ID3v2::Tag *tag);
UserTextIdentificationFrame* find(TagLib::ID3v2::Tag *tag, const String &description);
PopularimeterFrame* findPOPM(TagLib::ID3v2::Tag *tag, const String &email);
AttachedPictureFrame* findAPIC(TagLib::ID3v2::Tag *tag, const AttachedPictureFrame::Type &type,
const String &description = String::null);
QString getExtFromMimeType(const QString &mimeType);
};

#endif

0 comments on commit a52601a

Please sign in to comment.