Ticket #2942: mythmusic_apic.diff

File mythmusic_apic.diff, 20.8 KB (added by stuartm, 14 years ago)

Added image size sanity check

  • mythmusic/mythmusic/visualize.cpp

     
    389389    return false;
    390390}
    391391
    392 QString AlbumArt::getImageFilename()
    393 {
    394     return m_pParent->metadata()->getAlbumArt(m_currImageType);
    395 }
    396 
    397392bool AlbumArt::draw(QPainter *p, const QColor &back)
    398393{
    399394    if (!m_pParent->decoder())
     
    402397    // If the directory has changed (new album) or the size, reload
    403398    if (needsUpdate())
    404399    {
    405         QImage art(getImageFilename());
     400        QImage art(m_pParent->metadata()->getAlbumArt(m_currImageType));
    406401        if (art.isNull())
    407402        {
    408403            m_cursize = m_size;
  • mythmusic/mythmusic/metadata.cpp

     
    381381
    382382    if (m_id < 1 && query.isActive() && 1 == query.numRowsAffected())
    383383        m_id = query.lastInsertId().toInt();
     384
     385    if (! m_albumart.empty())
     386    {
     387        QValueList<struct AlbumArtImage>::iterator it;
     388        for ( it = m_albumart.begin(); it != m_albumart.end(); ++it )
     389        {
     390            query.prepare("SELECT albumart_id FROM music_albumart WHERE "
     391                          "song_id=:SONGID AND imagetype=:TYPE;");
     392            query.bindValue(":TYPE", (*it).imageType);
     393            query.bindValue(":SONGID", m_id);
     394            query.exec();
     395
     396            if (query.next())
     397            {
     398                int artid = query.value(0).toInt();
     399
     400                query.prepare("UPDATE music_albumart SET "
     401                            "filename=:FILENAME, imagetype=:TYPE, "
     402                            "song_id=:SONGID, embedded=:EMBED "
     403                            "WHERE albumart_id=:ARTID");
     404
     405                query.bindValue(":ARTID", artid);
     406            }
     407            else
     408            {
     409                query.prepare("INSERT INTO music_albumart ( filename, "
     410                            "imagetype, song_id, embedded ) VALUES ( "
     411                            ":FILENAME, :TYPE, :SONGID, :EMBED );");
     412            }
     413
     414            query.bindValue(":FILENAME", (*it).description);
     415            query.bindValue(":TYPE", (*it).imageType);
     416            query.bindValue(":SONGID", m_id);
     417            query.bindValue(":EMBED", 1);
     418
     419            query.exec();
     420        }
     421    }
    384422}
    385423
    386424// Default values for formats
     
    616654    m_changed = true;
    617655}
    618656
     657void Metadata::setEmbeddedAlbumArt(QValueList<struct AlbumArtImage> albumart)
     658{
     659    m_albumart = albumart;
     660}
     661
    619662QStringList Metadata::fillFieldList(QString field)
    620663{
    621664    QStringList searchList;
     
    658701    return searchList;
    659702}
    660703
    661 QStringList Metadata::AlbumArtInDir(QString directory)
     704QImage Metadata::getAlbumArt(ImageType type)
    662705{
    663     QStringList paths;
     706    AlbumArtImages albumArt(this);
    664707
    665     directory.remove(0, m_startdir.length());
     708    QImage image;
    666709
    667     MSqlQuery query(MSqlQuery::InitCon());
    668     query.prepare("SELECT CONCAT_WS('/', music_directories.path, "
    669                   "music_albumart.filename) FROM music_albumart "
    670                   "LEFT JOIN music_directories ON "
    671                   "music_directories.directory_id=music_albumart.directory_id "
    672                   "WHERE music_directories.path = :DIR;");
    673     query.bindValue(":DIR", directory.utf8());
    674     if (query.exec())
     710    if (albumArt.isImageAvailable(type))
    675711    {
    676         while (query.next())
    677         {
    678             paths += m_startdir + "/" +
    679                 QString::fromUtf8(query.value(0).toString());
    680         }
     712        AlbumArtImage albumart_image = albumArt.getImage(type);
     713
     714        if (albumart_image.embedded)
     715            image = QImage(MetaIOTagLib::getAlbumArt(m_filename, type));
     716        else
     717            image = QImage(albumart_image.filename);
    681718    }
    682     return paths;
    683 }
    684719
    685 QString Metadata::getAlbumArt(ImageType type)
    686 {
    687     QString res = "";
    688     AlbumArtImages albumArt(this);
    689 
    690     res = albumArt.getImageFilename(type);
    691 
    692     return res;
     720    return image;
    693721}
    694722
    695723MetadataLoadingThread::MetadataLoadingThread(AllMusic *parent_ptr)
     
    13891417    if (m_parent == NULL)
    13901418        return;
    13911419
     1420    int trackid = m_parent->ID();
     1421
    13921422    QFileInfo fi(m_parent->Filename());
    13931423    QString dir = fi.dirPath(true);
    13941424    dir.remove(0, Metadata::GetStartdir().length());
    13951425
    13961426    MSqlQuery query(MSqlQuery::InitCon());
    13971427    query.prepare("SELECT albumart_id, CONCAT_WS('/', music_directories.path, "
    1398             "music_albumart.filename), music_albumart.imagetype "
     1428            "music_albumart.filename), music_albumart.imagetype, "
     1429            "music_albumart.embedded "
    13991430            "FROM music_albumart "
    14001431            "LEFT JOIN music_directories ON "
    14011432            "music_directories.directory_id=music_albumart.directory_id "
    14021433            "WHERE music_directories.path = :DIR "
     1434            "OR song_id = :SONGID "
    14031435            "ORDER BY music_albumart.imagetype;");
    14041436    query.bindValue(":DIR", dir.utf8());
     1437    query.bindValue(":SONGID", trackid);
    14051438    if (query.exec())
    14061439    {
    14071440        while (query.next())
     
    14121445                    QString::fromUtf8(query.value(1).toString());
    14131446            image->imageType = (ImageType) query.value(2).toInt();
    14141447            image->typeName = getTypeName(image->imageType);
     1448            if (query.value(3).toInt() == 1)
     1449            {
     1450                image->description = query.value(1).toString();
     1451                image->embedded = true;
     1452            }
     1453            else {
     1454                image->embedded = false;
     1455            }
    14151456            m_imageList.append(image);
    14161457        }
    14171458    }
    14181459}
    14191460
    1420 QString AlbumArtImages::getImageFilename(ImageType type)
     1461AlbumArtImage AlbumArtImages::getImage(ImageType type)
    14211462{
    14221463    // try to find a matching image
    14231464    AlbumArtImage *image;
     
    14251466    for (image = m_imageList.first(); image; image = m_imageList.next())
    14261467    {
    14271468        if (image->imageType == type)
    1428             return image->filename;
     1469            return *image;
    14291470    }
    14301471
    1431     return "";
     1472    return *image;
    14321473}
    14331474
    14341475QStringList AlbumArtImages::getImageFilenames()
     
    14451486    return paths;
    14461487}
    14471488
     1489AlbumArtImage AlbumArtImages::getImageAt(uint index)
     1490{
     1491    return *(m_imageList.at(index));
     1492}
     1493
    14481494bool AlbumArtImages::isImageAvailable(ImageType type)
    14491495{
    14501496    // try to find a matching image
     
    14591505    return false;
    14601506}
    14611507
    1462 bool AlbumArtImages::saveImageType(const QString &filename, ImageType type)
     1508bool AlbumArtImages::saveImageType(const int id, ImageType type)
    14631509{
    1464     // try to find a matching filename
    1465     AlbumArtImage *image;
    1466 
    1467     for (image = m_imageList.first(); image; image = m_imageList.next())
    1468     {
    1469         if (image->filename == filename)
    1470         {
    1471             image->imageType = type;
    1472 
    1473             MSqlQuery query(MSqlQuery::InitCon());
    1474             query.prepare("UPDATE music_albumart SET imagetype = :TYPE "
    1475                           "WHERE albumart_id = :ID");
    1476             query.bindValue(":TYPE", type);
    1477             query.bindValue(":ID", image->id);
    1478             return (query.exec());
    1479         }
    1480     }
    1481 
    1482     return false;
     1510    MSqlQuery query(MSqlQuery::InitCon());
     1511    query.prepare("UPDATE music_albumart SET imagetype = :TYPE "
     1512                    "WHERE albumart_id = :ID");
     1513    query.bindValue(":TYPE", type);
     1514    query.bindValue(":ID", id);
     1515    return (query.exec());
    14831516}
    14841517
    14851518QString AlbumArtImages::getTypeName(ImageType type)
  • mythmusic/mythmusic/dbcheck.cpp

     
    99#include "mythtv/mythcontext.h"
    1010#include "mythtv/mythdbcon.h"
    1111
    12 const QString currentDatabaseVersion = "1011";
     12const QString currentDatabaseVersion = "1012";
    1313
    1414static bool UpdateDBVersionNumber(const QString &newnumber)
    1515{   
     
    587587            return false;
    588588
    589589    }
     590
     591    if (dbver == "1011")
     592    {
     593        const QString updates[] = {
     594"ALTER TABLE music_albumart ADD COLUMN song_id int(11) NOT NULL DEFAULT '0', ADD COLUMN embedded TINYINT(1) NOT NULL DEFAULT '0';",
     595        ""
     596};
     597
     598        if (!performActualUpdate(updates, "1012", dbver))
     599            return false;
     600
     601    }
    590602/* in 0.21 */
    591603//"DROP TABLE musicmetadata;",
    592604//"DROP TABLE musicplaylist;",
  • mythmusic/mythmusic/metadata.h

     
    44#include <qstring.h>
    55#include <qstringlist.h>
    66#include <qptrlist.h>
     7#include <qvaluelist.h>
    78#include <qmap.h>
    89#include <qthread.h>
    910
    1011#include "treecheckitem.h"
    1112#include <mythtv/uitypes.h>
    1213
     14
    1315class AllMusic;
    1416class CoverArt;
    1517
     
    2325    IT_LAST
    2426};
    2527
     28#include "metaiotaglib.h"
     29
    2630typedef struct AlbumArtImage
    2731{
    2832    int       id;
    2933    QString   filename;
    3034    ImageType imageType;
    3135    QString   typeName;
     36    QString   description;
     37    bool      embedded;
    3238} AlbumArtImage;
    3339
     40//typedef QValueList<struct AlbumArtImage> AlbumArtList;
     41
    3442class Metadata
    3543{
    3644  public:
     
    5967                   m_lastplay(llastplay),
    6068                   m_playcount(lplaycount),
    6169                   m_compilation(lcompilation),
     70                   m_albumart(),
    6271                   m_id(lid),
    6372                   m_filename(lfilename),
    6473                   m_changed(false),
     
    159168    }
    160169    bool determineIfCompilation(bool cd = false);
    161170
     171    void setEmbeddedAlbumArt(QValueList<struct AlbumArtImage> art);
     172
    162173    bool isInDatabase(void);
    163174    void dumpToDatabase(void);
    164175    void setField(const QString &field, const QString &data);
     
    173184
    174185    static QStringList fillFieldList(QString field);
    175186
    176     QStringList AlbumArtInDir(QString directory);
    177     QString getAlbumArt(ImageType type);
     187    QImage getAlbumArt(ImageType type);
    178188
    179189  private:
    180190    void setCompilationFormatting(bool cd = false);
     
    201211    QString m_lastplay;
    202212    int m_playcount;
    203213    bool m_compilation;
     214    QValueList<struct AlbumArtImage> m_albumart;
    204215
    205216    unsigned int m_id;
    206217    QString m_filename;
     
    389400    AlbumArtImages(Metadata *metadata);
    390401
    391402    uint                     getImageCount() { return m_imageList.count(); }
    392     QString                  getImageFilename(ImageType type);
     403    AlbumArtImage            getImage(ImageType type);
    393404    QString                  getTypeName(ImageType type);
    394405    QStringList              getImageFilenames();
    395406    QPtrList<AlbumArtImage> *getImageList() { return &m_imageList; }
     
    397408
    398409    bool isImageAvailable(ImageType type);
    399410
    400     bool saveImageType(const QString &filename, ImageType type);
     411    bool saveImageType(const int id, ImageType type);
    401412
    402413    static ImageType guessImageType(const QString &filename);
    403414
  • mythmusic/mythmusic/editmetadata.cpp

     
    148148
    149149    for (uint x = 0; x < albumArtList->count(); x++)
    150150    {
     151        if (albumArtList->at(x)->embedded)
     152            continue;
     153
    151154        QPixmap *pixmap = createScaledPixmap(albumArtList->at(x)->filename,
    152155                                             size.width(), size.height(),
    153156                                             QImage::ScaleMin);
     
    738741                image->typeName = item->text;
    739742
    740743                // save the image type to the DB
    741                 albumArt->saveImageType(image->filename, image->imageType);
     744                albumArt->saveImageType(image->id, image->imageType);
    742745
    743746                gridItemChanged(item);
    744747            }
  • mythmusic/mythmusic/metaiotaglib.h

     
    22#define METAIOTAGLIB_H_
    33
    44#include "metaio.h"
     5#include "metadata.h"
    56#include <id3v2tag.h>
    67#include <textidentificationframe.h>
     8#include <attachedpictureframe.h>
    79#include <mpegfile.h>
     10#include <mpegproperties.h>
    811
    912using TagLib::MPEG::File;
    1013using TagLib::Tag;
    1114using TagLib::ID3v2::UserTextIdentificationFrame;
     15using TagLib::ID3v2::AttachedPictureFrame;
    1216using TagLib::String;
     17using TagLib::MPEG::Properties;
    1318
    1419class MetaIOTagLib : public MetaIO
    1520{
     
    2025    bool write(Metadata* mdata, bool exclusive = false);
    2126    Metadata* read(QString filename);
    2227
     28    static QImage getAlbumArt(QString filename, ImageType type);
     29
    2330private:
    2431
    25      int getTrackLength(QString filename);
     32    int getTrackLength(QString filename);
    2633
    27      UserTextIdentificationFrame* find(TagLib::ID3v2::Tag *tag, const String &description);
     34    QValueList<struct AlbumArtImage> readAlbumArt(TagLib::ID3v2::Tag *tag);
     35    UserTextIdentificationFrame* find(TagLib::ID3v2::Tag *tag, const String &description);
    2836};
    2937
    3038#endif
  • mythmusic/mythmusic/metaiotaglib.cpp

     
    102102            genre = "";
    103103    int year = 0, tracknum = 0, length = 0, playcount = 0, rating = 0, id = 0;
    104104    bool compilation = false;
     105    QValueList<struct AlbumArtImage> albumart;
    105106
    106107    QString extension = filename.section( '.', -1 ) ;
    107108
     
    151152        // Length
    152153        if(!taglib->ID3v2Tag()->frameListMap()["TLEN"].isEmpty())
    153154            length = taglib->ID3v2Tag()->frameListMap()["TLEN"].front()->toString().toInt();
     155
     156        // Album Art
     157        if(!taglib->ID3v2Tag()->frameListMap()["APIC"].isEmpty())
     158        {
     159            albumart = readAlbumArt(taglib->ID3v2Tag());
     160        }
    154161    }
    155162
    156163    // Fallback to filename reading
     
    183190                                     id, rating, playcount);
    184191
    185192    retdata->setCompilation(compilation);
     193    retdata->setEmbeddedAlbumArt(albumart);
    186194
    187195    return retdata;
    188196}
     
    203211}
    204212
    205213/*!
     214 * \brief Read the albumart image from the file
     215 *
     216 * \param filename The filename for which we want to find the length.
     217 * \param type The type of image we want - front/back etc
     218 * \returns A QByteArray that can contains the image data.
     219 */
     220QImage MetaIOTagLib::getAlbumArt(QString filename, ImageType type)
     221{
     222    QImage picture;
     223
     224    AttachedPictureFrame::Type apicType
     225        = AttachedPictureFrame::FrontCover;
     226
     227    switch (type)
     228    {
     229        case IT_UNKNOWN :
     230            apicType = AttachedPictureFrame::Other;
     231            break;
     232        case IT_FRONTCOVER :
     233            apicType = AttachedPictureFrame::FrontCover;
     234            break;
     235        case IT_BACKCOVER :
     236            apicType = AttachedPictureFrame::BackCover;
     237            break;
     238        case IT_CD :
     239            apicType = AttachedPictureFrame::Media;
     240            break;
     241        case IT_INLAY :
     242            apicType = AttachedPictureFrame::LeafletPage;
     243            break;
     244        default:
     245            return picture;
     246    }
     247
     248    File *taglib = new TagLib::MPEG::File(filename.local8Bit());
     249
     250    if (taglib->isOpen() && !taglib->ID3v2Tag()->frameListMap()["APIC"].isEmpty())
     251    {
     252        TagLib::ID3v2::FrameList apicframes = taglib->ID3v2Tag()->frameListMap()["APIC"];
     253
     254        for(TagLib::ID3v2::FrameList::Iterator it = apicframes.begin(); it != apicframes.end(); ++it) {
     255            AttachedPictureFrame *frame = static_cast<AttachedPictureFrame *>(*it);
     256            if(frame && frame->type() == apicType)
     257            {
     258                QImage picture;
     259                picture.loadFromData((const uchar *)frame->picture().data(), frame->picture().size());
     260                return picture;
     261            }
     262        }
     263    }
     264
     265    return picture;
     266}
     267
     268/*!
     269 * \brief Read the albumart image from the file
     270 *
     271 * \param tag The ID3v2 tag object in which to look for Album Art
     272 * \returns A QValueList containing a list of AlbumArtImage structs
     273 *          with the type and description of the APIC tag.
     274 */
     275QValueList<struct AlbumArtImage> MetaIOTagLib::readAlbumArt(TagLib::ID3v2::Tag *tag)
     276{
     277
     278    QValueList<struct AlbumArtImage> artlist;
     279
     280    if (!tag->frameListMap()["APIC"].isEmpty())
     281    {
     282        TagLib::ID3v2::FrameList apicframes = tag->frameListMap()["APIC"];
     283
     284        for(TagLib::ID3v2::FrameList::Iterator it = apicframes.begin();
     285            it != apicframes.end(); ++it)
     286        {
     287
     288            AttachedPictureFrame *frame =
     289                static_cast<AttachedPictureFrame *>(*it);
     290
     291            // Assume a valid image would have at least
     292            // 100 bytes of data (1x1 indexed gif is 35 bytes)
     293            if (frame->picture().size() < 100)
     294            {
     295                VERBOSE(VB_GENERAL, "Music Scanner - Discarding APIC frame "
     296                                    "with size less than 100 bytes");
     297                continue;
     298            }
     299
     300            AlbumArtImage art;
     301
     302            if (frame->description().isEmpty())
     303            {
     304                art.description = "";
     305            }
     306            else {
     307                art.description = TStringToQString(frame->description());
     308            }
     309
     310            art.embedded = true;
     311
     312            switch (frame->type())
     313            {
     314                case AttachedPictureFrame::FrontCover :
     315                    art.imageType = IT_FRONTCOVER;
     316                    break;
     317                case AttachedPictureFrame::BackCover :
     318                    art.imageType = IT_BACKCOVER;
     319                    break;
     320                case AttachedPictureFrame::Media :
     321                    art.imageType = IT_CD;
     322                    break;
     323                case AttachedPictureFrame::LeafletPage :
     324                    art.imageType = IT_INLAY;
     325                    break;
     326                case AttachedPictureFrame::Other :
     327                    art.imageType = IT_UNKNOWN;
     328                    break;
     329                default:
     330                    VERBOSE(VB_GENERAL, "Music Scanner - APIC tag found "
     331                                        "with unsupported type");
     332                    continue;
     333            }
     334
     335            artlist.append(art);
     336        }
     337    }
     338
     339    return artlist;
     340}
     341
     342/*!
    206343 * \brief Find the a custom comment tag by description.
    207344 *        This is a copy of the same function in the
    208345 *        TagLib::ID3v2::UserTextIdentificationFrame Class with a static
  • mythmusic/mythmusic/mainvisual.cpp

     
    353353        return;
    354354
    355355    QString  text = "\"" + mdata->Title() + "\"\n" +  mdata->Artist() + "\n" + mdata->Album();
    356     QString albumArt = mdata->getAlbumArt(IT_FRONTCOVER);
     356    QImage albumArt = mdata->getAlbumArt(IT_FRONTCOVER);
    357357
    358358    if (text == info)
    359359        return;
     
    373373    }
    374374
    375375    // ...and only then when we have an album art image to show
    376     if (visMode != 2 && fullScreen && albumArt == "")
     376    if (visMode != 2 && fullScreen && albumArt.isNull())
    377377    {
    378378        hide();
    379379        return;
    380380    }
    381381
    382     if (fullScreen && albumArt != "")
     382    if (fullScreen && ! albumArt.isNull())
    383383    {
    384384        resize(parentWidget()->width(), parentWidget()->height());
    385385        move(0, 0);
     
    403403    int x = indent;
    404404    int y = indent;
    405405
    406     if (fullScreen && albumArt != "")
     406    if (fullScreen && ! albumArt.isNull())
    407407    {
    408408        p.fillRect(0, 0, info_pixmap.width(), info_pixmap.height(), QColor ("black"));
    409409
     
    422422    {
    423423        p.fillRect(0, 0, info_pixmap.width(), info_pixmap.height(), QColor ("darkblue"));
    424424
    425         if (albumArt != "")
     425        if (! albumArt.isNull())
    426426        {
    427427            // draw the albumArt image
    428428
  • mythmusic/mythmusic/visualize.h

     
    9191
    9292  private:
    9393    bool needsUpdate(void);
    94     QString getImageFilename(void);
    9594    void findFrontCover(void);
    9695
    9796    QSize m_size, m_cursize;
  • mythmusic/mythmusic/filescanner.cpp

     
    469469    MSqlQuery query(MSqlQuery::InitCon());
    470470    query.exec("SELECT CONCAT_WS('/', path, filename) "
    471471               "FROM music_albumart LEFT JOIN music_directories "
    472                "ON music_albumart.directory_id=music_directories.directory_id ");
     472               "ON music_albumart.directory_id=music_directories.directory_id "
     473               "WHERE music_albumart.embedded=0");
    473474
    474475    int counter = 0;
    475476