Ticket #11947: flac_embedded_art.patch

File flac_embedded_art.patch, 12.2 KB (added by Karl Newman <SiliconFiend@…>, 6 years ago)

Add embedded art support for FLAC files

  • mythtv/libs/libmythmetadata

    diff -Naur mythtv/libs/libmythmetadata.orig/metaio.cpp mythtv/libs/libmythmetadata/metaio.cpp
    old new  
    4141        return new MetaIOOggVorbis;
    4242    else if (extension == "flac")
    4343    {
    44         MetaIOID3 *tagger = new MetaIOID3;
     44        MetaIOFLACVorbis *tagger = new MetaIOFLACVorbis;
    4545        if (tagger->TagExists(filename))
    4646            return tagger;
    4747        else
    4848        {
    4949            delete tagger;
    50             return new MetaIOFLACVorbis;
     50            return new MetaIOID3;
    5151        }
    5252    }
    5353    else if (extension == "m4a")
  • mythtv/libs/libmythmetadata

    diff -Naur mythtv/libs/libmythmetadata.orig/metaioflacvorbis.cpp mythtv/libs/libmythmetadata/metaioflacvorbis.cpp
    old new  
    22// Libmyth
    33#include <mythcontext.h>
    44
     5// qt
     6#include <QBuffer>
     7
    58// Taglib
    69#include <xiphcomment.h>
    710
     
    145148    return metadata;
    146149}
    147150
     151/*!
     152 * \brief Read the albumart image from the file
     153 *
     154 * \param filename The filename for which we want to find the albumart.
     155 * \param type The type of image we want - front/back etc
     156 * \returns A pointer to a QImage owned by the caller or NULL if not found.
     157 */
     158QImage* MetaIOFLACVorbis::getAlbumArt(const QString &filename, ImageType type)
     159{
     160    QImage *picture = new QImage();
     161    TagLib::FLAC::File * flacfile = OpenFile(filename);
     162
     163    if(flacfile) {
     164        TagLib::FLAC::Picture* pic = getPictureFromFile(flacfile, type);
     165        if(pic) {
     166            picture->loadFromData((const uchar *)pic->data().data(),
     167                                            pic->data().size());
     168        } else {
     169            delete picture;
     170            return NULL;
     171        }
     172        delete flacfile;
     173    }
     174    return picture;
     175}
     176
     177TagLib::FLAC::Picture *MetaIOFLACVorbis::getPictureFromFile(
     178                                        TagLib::FLAC::File *flacfile,
     179                                        ImageType type) {
     180    using TagLib::FLAC::Picture;
     181
     182    Picture *pic = NULL;
     183
     184    if (flacfile) {
     185        Picture::Type artType = PictureTypeFromImageType(type);
     186
     187        // From what I can tell, FLAC::File maintains ownership of the Picture pointers, so no need to delete
     188        const TagLib::List<Picture *>& picList = flacfile->pictureList();
     189
     190        for(TagLib::List<Picture *>::ConstIterator it = picList.begin();
     191                it != picList.end(); it++) {
     192            pic = *it;
     193            if(pic->type() == artType) { //found the type we were looking for
     194                break;
     195            }
     196        }
     197    }
     198
     199    return pic;
     200}
     201
     202TagLib::FLAC::Picture::Type MetaIOFLACVorbis::PictureTypeFromImageType(
     203                                                ImageType itype) {
     204    using TagLib::FLAC::Picture;
     205    Picture::Type artType = Picture::Other;
     206    switch (itype)
     207    {
     208        case IT_UNKNOWN :
     209            artType = Picture::Other;
     210            break;
     211        case IT_FRONTCOVER :
     212            artType = Picture::FrontCover;
     213            break;
     214        case IT_BACKCOVER :
     215            artType = Picture::BackCover;
     216            break;
     217        case IT_CD :
     218            artType = Picture::Media;
     219            break;
     220        case IT_INLAY :
     221            artType = Picture::LeafletPage;
     222            break;
     223        case IT_ARTIST :
     224            artType = Picture::Artist;
     225            break;
     226        default:
     227            return Picture::Other;
     228    }
     229    return artType;
     230}
     231
     232/*!
     233 * \brief Read the albumart images from the file
     234 *
     235 * \param filename The filename for which we want to find the images.
     236 */
     237AlbumArtList MetaIOFLACVorbis::getAlbumArtList(const QString &filename)
     238{
     239    using TagLib::FLAC::Picture;
     240    AlbumArtList artlist;
     241    TagLib::FLAC::File * flacfile = OpenFile(filename);
     242
     243    if (flacfile) {
     244        const TagLib::List<Picture *>& picList = flacfile->pictureList();
     245
     246        for(TagLib::List<Picture *>::ConstIterator it = picList.begin();
     247                it != picList.end(); it++) {
     248            Picture* pic = *it;
     249            // Assume a valid image would have at least
     250            // 100 bytes of data (1x1 indexed gif is 35 bytes)
     251            if (pic->data().size() < 100)
     252            {
     253                LOG(VB_GENERAL, LOG_NOTICE,
     254                    "Music Scanner - Discarding picture "
     255                    "with size less than 100 bytes");
     256                continue;
     257            }
     258
     259            AlbumArtImage *art = new AlbumArtImage();
     260
     261            if (pic->description().isEmpty())
     262                art->description.clear();
     263            else
     264                art->description = TStringToQString(pic->description());
     265
     266            art->embedded = true;
     267
     268            QString ext = getExtFromMimeType(
     269                                TStringToQString(pic->mimeType()).toLower());
     270
     271            switch (pic->type())
     272            {
     273                case Picture::FrontCover :
     274                    art->imageType = IT_FRONTCOVER;
     275                    art->filename = QString("front") + ext;
     276                    break;
     277                case Picture::BackCover :
     278                    art->imageType = IT_BACKCOVER;
     279                    art->filename = QString("back") + ext;
     280                    break;
     281                case Picture::Media :
     282                    art->imageType = IT_CD;
     283                    art->filename = QString("cd") + ext;
     284                    break;
     285                case Picture::LeafletPage :
     286                    art->imageType = IT_INLAY;
     287                    art->filename = QString("inlay") + ext;
     288                    break;
     289                case Picture::Artist :
     290                    art->imageType = IT_ARTIST;
     291                    art->filename = QString("artist") + ext;
     292                    break;
     293                case Picture::Other :
     294                    art->imageType = IT_UNKNOWN;
     295                    art->filename = QString("unknown") + ext;
     296                    break;
     297                default:
     298                    LOG(VB_GENERAL, LOG_ERR, "Music Scanner - picture found "
     299                                             "with unsupported type");
     300                    delete art;
     301                    continue;
     302            }
     303
     304            artlist.append(art);
     305        }
     306    }
     307
     308    delete flacfile;
     309    return artlist;
     310}
     311
     312/*!
     313 * \brief Write the albumart image to the file
     314 *
     315 * \param filename The music file to add the albumart
     316 * \param albumart The Album Art image to write
     317 * \returns True if successful
     318 *
     319 * \Note We always save the image in JPEG format
     320 */
     321bool MetaIOFLACVorbis::writeAlbumArt(const QString &filename,
     322                              const AlbumArtImage *albumart)
     323{
     324    using TagLib::FLAC::Picture;
     325    if (filename.isEmpty() || !albumart)
     326        return false;
     327
     328    bool retval = false;
     329   
     330    // load the image into a QByteArray
     331    QImage image(albumart->filename);
     332    QByteArray imageData;
     333    QBuffer buffer(&imageData);
     334    buffer.open(QIODevice::WriteOnly);
     335    // Write the image data to a file
     336    image.save(&buffer, "JPEG");
     337
     338    TagLib::FLAC::File * flacfile = OpenFile(filename);
     339
     340    // This presumes that there is only one art item of each type
     341    if (flacfile) {
     342        // Now see if the art is in the FLAC file
     343        Picture *pic = getPictureFromFile(flacfile, albumart->imageType);
     344
     345        if (pic)
     346        {
     347            // Remove the embedded image of the matching type
     348            flacfile->removePicture(pic, false);
     349        } else
     350        {
     351            // Create a new image of the correct type
     352            pic = new Picture();
     353            pic->setType(PictureTypeFromImageType(albumart->imageType));
     354        }
     355
     356        TagLib::ByteVector bytevector;
     357        bytevector.setData(imageData.data(), imageData.size());
     358
     359        pic->setData(bytevector);
     360        QString mimetype = "image/jpeg";
     361
     362        pic->setMimeType(QStringToTString(mimetype));
     363        pic->setDescription(QStringToTString(albumart->description));
     364
     365        flacfile->addPicture(pic);
     366       
     367        retval = flacfile->save();
     368
     369        delete flacfile;
     370    } else
     371    {
     372        retval = false;
     373    }
     374
     375    return retval;
     376}
     377
     378/*!
     379 * \brief Remove the albumart image from the file
     380 *
     381 * \param filename The music file to remove the albumart
     382 * \param albumart The Album Art image to remove
     383 * \returns True if successful
     384 */
     385bool MetaIOFLACVorbis::removeAlbumArt(const QString &filename,
     386                               const AlbumArtImage *albumart)
     387{
     388    if (filename.isEmpty() || !albumart)
     389        return false;
     390
     391    bool retval = false;
     392   
     393    TagLib::FLAC::File * flacfile = OpenFile(filename);
     394
     395    // This presumes that there is only one art item of each type
     396    if (flacfile) {
     397        // Now see if the art is in the FLAC file
     398        TagLib::FLAC::Picture *pic = getPictureFromFile(flacfile, albumart->imageType);
     399
     400        if (pic)
     401        {
     402            // Remove the embedded image of the matching type
     403            flacfile->removePicture(pic, false);
     404            flacfile->save();
     405            retval = true;
     406        } else
     407        {
     408            retval = false;
     409        }
     410        delete flacfile;
     411    } else
     412    {
     413        retval = false;
     414    }
     415
     416    return retval;
     417}
     418
     419bool MetaIOFLACVorbis::changeImageType(const QString &filename,
     420                                const AlbumArtImage* albumart,
     421                                ImageType newType)
     422{
     423    if (filename.isEmpty() || !albumart)
     424        return false;
     425
     426    if (albumart->imageType == newType)
     427        return true;
     428
     429    bool retval = false;
     430
     431    TagLib::FLAC::File * flacfile = OpenFile(filename);
     432
     433    // This presumes that there is only one art item of each type
     434    if (flacfile) {
     435        // Now see if the art is in the FLAC file
     436        TagLib::FLAC::Picture *pic = getPictureFromFile(flacfile, albumart->imageType);
     437
     438        if (pic)
     439        {
     440            pic->setType(PictureTypeFromImageType(newType));
     441            flacfile->save();
     442            retval = true;
     443        } else
     444        {
     445            retval = false;
     446        }
     447        delete flacfile;
     448    } else
     449    {
     450        retval = false;
     451    }
     452
     453    return retval;
     454}
     455
    148456bool MetaIOFLACVorbis::TagExists(const QString &filename)
    149457{
    150458    TagLib::FLAC::File *flacfile = OpenFile(filename);
     
    162470
    163471    return retval;
    164472}
     473
     474QString MetaIOFLACVorbis::getExtFromMimeType(const QString &mimeType)
     475{
     476    if (mimeType == "image/png")
     477        return QString(".png");
     478    else if (mimeType == "image/jpeg" || mimeType == "image/jpg")
     479        return QString(".jpg");
     480    else if (mimeType == "image/gif")
     481        return QString(".gif");
     482    else if (mimeType == "image/bmp")
     483        return QString(".bmp");
     484
     485    LOG(VB_GENERAL, LOG_ERR,
     486        "Music Scanner - Unknown image mimetype found - " + mimeType);
     487
     488    return QString();
     489}
  • mythtv/libs/libmythmetadata

    diff -Naur mythtv/libs/libmythmetadata.orig/metaioflacvorbis.h mythtv/libs/libmythmetadata/metaioflacvorbis.h
    old new  
    2525    virtual ~MetaIOFLACVorbis(void);
    2626
    2727    bool write(const MusicMetadata* mdata);
     28    bool writeAlbumArt(const QString &filename, const AlbumArtImage *albumart);
     29    bool removeAlbumArt(const QString &filename, const AlbumArtImage *albumart);
     30
    2831    MusicMetadata* read(const QString &filename);
     32    AlbumArtList getAlbumArtList(const QString &filename);
     33    QImage *getAlbumArt(const QString &filename, ImageType type);
     34
     35    bool supportsEmbeddedImages(void) { return true; }
     36
     37    bool changeImageType(const QString &filename, const AlbumArtImage *albumart,
     38                         ImageType newType);
    2939
    3040    virtual bool TagExists(const QString &filename);
    3141
    3242private:
    3343    TagLib::FLAC::File *OpenFile(const QString &filename);
     44    TagLib::FLAC::Picture *getPictureFromFile(TagLib::FLAC::File *flacfile,
     45                                            ImageType type);
     46    TagLib::FLAC::Picture::Type PictureTypeFromImageType(ImageType itype);
     47    QString getExtFromMimeType(const QString &mimeType);
    3448};
    3549
    3650#endif