Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use TagLib to read/write coverart in different audio formats?

Tags:

c++

taglib

cover

I would like to use TagLib to read/write coverart especially for mp3 AND ogg files, but I couldn't find any examples. Could someone point me to some examples? Where should I look to find more information about this?

like image 355
Bernd Avatar asked Jan 20 '11 20:01

Bernd


3 Answers

Here is a version for mp3 and m4a.

#include <mpegfile.h>
#include <attachedpictureframe.h>
#include <id3v2tag.h>
#include <mp4file.h>
#include <mp4tag.h>
#include <mp4coverart.h>

#include <iostream>

class ImageFile : public TagLib::File
{
public:
ImageFile(const char *file) : TagLib::File(file)
{

}

TagLib::ByteVector data()
{
    return readBlock(length());
}


private:
virtual TagLib::Tag *tag() const { return 0; }
virtual TagLib::AudioProperties *audioProperties() const { return 0; }
virtual bool save() { return false; }
};

int main(int argc, char *argv[])
{
if (argc != 3) 
{
    std::cout << "Usage: setcover <mp3|m4a> cover.jpg" << std::endl;
    return 1;
}

TagLib::String fileName = argv[1];
TagLib::String fileType = fileName.substr(fileName.size() - 3).upper();

ImageFile imageFile(argv[2]);

if (fileType == "M4A")
{
  // read the image file
  TagLib::MP4::CoverArt coverArt((TagLib::MP4::CoverArt::Format) 0x0D,   imageFile.data());

  // read the mp4 file
  TagLib::MP4::File audioFile(argv[1]);

  // get the tag ptr
  TagLib::MP4::Tag *tag = audioFile.tag();

  // get the items map
  TagLib::MP4::ItemListMap itemsListMap = tag->itemListMap();

  // create cover art list
  TagLib::MP4::CoverArtList coverArtList;

  // append instance
  coverArtList.append(coverArt);

  // convert to item
  TagLib::MP4::Item coverItem(coverArtList);

  // add item to map
  itemsListMap.insert("covr", coverItem);

  tag->save();
  //audioFile.save();      
}
else if (fileType == "MP3")
{
  TagLib::MPEG::File audioFile(argv[1]);

  TagLib::ID3v2::Tag *tag = audioFile.ID3v2Tag(true);
  TagLib::ID3v2::AttachedPictureFrame *frame = new TagLib::ID3v2::AttachedPictureFrame;

  frame->setMimeType("image/jpeg");
  frame->setPicture(imageFile.data());

  tag->addFrame(frame);
  audioFile.save();      
}
else
{
   std::cout << fileType << " is unsupported." << std::endl;
}
}
like image 58
guymac Avatar answered Nov 19 '22 15:11

guymac


I got it to work for mp3 files. See if you can adapt it for ogg

Good luck.
PS::This tagging stuff is way harder than it should be. We need to find another lib.

/*********************************************************************************************************************************
 *Description: A simple program using taglib to extract pictures attached to mp3 id3v2 tags
 *Author: Dr Deo [at] stackoverflow *dot* com
 *AOB: I hope you will find this useful and are free to use it for anything, but there is no waranty and use at your own risk :)
 *********************************************************************************************************************************
*/
#include<iostream>
#include<stdio.h>

/*taglib specific includes*/
#include<tbytevector.h>//ByteVector
#include<mpegfile.h>//mp3 file
#include<id3v2tag.h>//tag
#include<id3v2frame.h>//frame
#include <attachedPictureFrame.h>//attachedPictureFrame

using namespace std ;
using namespace TagLib::ID3v2 ;

int main(int argc, char * argv[])
{
    if(argc !=2)
    {
        cout<<"usage: drag an mp3 file on to the program and it will extract the attached image"<<endl<<endl;
        system("pause");//on linux you can replace this with cin.get()
        exit(1);
    }

    TagLib::MPEG::File mp3File(argv[1]);
    Tag * mp3Tag;
    FrameList listOfMp3Frames;
    AttachedPictureFrame * pictureFrame;

    mp3Tag= mp3File.ID3v2Tag();
    if(mp3Tag)
    {
        listOfMp3Frames = mp3Tag->frameListMap()["APIC"];//look for picture frames only
        if(!listOfMp3Frames.isEmpty())
        {
            FrameList::ConstIterator it= listOfMp3Frames.begin();
            for(; it != listOfMp3Frames.end() ; it++)
            {
                pictureFrame = static_cast<AttachedPictureFrame *> (*it);//cast Frame * to AttachedPictureFrame*

                //Warning. format of picture assumed to be jpg. This may be false, for example it may be png.
                FILE * fout;
                fopen_s(&fout, "outputFile.jpg", "wb");
                cout<<"processing the file "<< argv[1] <<endl<<endl;
                fwrite(pictureFrame->picture().data(), pictureFrame->picture().size(), 1, fout);
                fclose(fout);
                cout<<" The picture has been written to \t outputFile.jpg  \nRemember that the file type .jpg is just assumed for simplicity"<<endl<<endl;
            }
        }
        else cerr<<"there seem to be no picture frames (APIC) frames in this file"<<endl<<endl;
    }
    else cerr<<"the file "<<argv[1]<<"does not appear to have any mp3 tags"<<endl<<endl;

    system("pause");//on linux you can replace this with cin.get()
    return 0;
}
like image 44
Dr Deo Avatar answered Nov 19 '22 15:11

Dr Deo


Ogg Vorbis tags are text-only (and as such don't support cover art). For MP3s, this is somewhat cleaner than the other solution suggested:

using namespace TagLib;

struct Image
{
    Image(const String &m = String(), const ByteVector &d = ByteVector()) :
      mimeType(m), data(d) {}
    String mimeType;
    ByteVector data;
};

static Image getImage(const ID3v2::Tag *tag)
{
    ID3v2::FrameList frames = tag->frameList("APIC");

    if(frames.isEmpty())
    {
        return Image();
    }

    ID3v2::AttachedPictureFrame *frame =
        static_cast<ID3v2::AttachedPictureFrame *>(frames.front());

    return Image(frame->mimeType(), frame->picture());
}

static void setImage(ID3v2::Tag *tag, const Image &image)
{
    ID3v2::FrameList frames = tag->frameList("APIC");
    ID3v2::AttachedPictureFrame *frame = 0;

    if(frames.isEmpty())
    {
        frame = new TagLib::ID3v2::AttachedPictureFrame;
        tag->addFrame(frame);
    }
    else
    {
        frame = static_cast<ID3v2::AttachedPictureFrame *>(frames.front());
    }

    frame->setPicture(image.data);
    frame->setMimeType(image.mimeType);
}
like image 3
scotchi Avatar answered Nov 19 '22 13:11

scotchi