音楽ファイル(mp3,m4a,flac,etc...)から、taglibでCoverArtを抽出する

# 概要

音楽ファイル(mp3,m4a,flac,etc...)から、taglibでCoverArtを抽出してみる。
これ！っていうコードが無かったので、Ubuntu, gcc 環境で作成した。

[NanoPi-NEOとMPDとOLEDで音楽再生サーバ](http://qiita.com/blue-7/items/e58bcfa5ecf93cc8838b)
では、Python & mutagen で取得していたが、今回は、C++ & taglib になる。

残念ながら　taglibは、まだDSDには対応していない。
今後に期待しましょう。

# taglib のインストール

apt install libtag1-dev

# コード

管理はgitで
https://github.com/blue777/NanoPi-NEO/blob/master/CoverArtExtractor.h

音楽ファイルを指定すると、CoverArtの画像ファイルのバイナリが返る。
それを、OpenCVのcv::imencodeなどに渡せば、デコードできる。


```C++:CoverArtExtractor.h
#include <stdio.h>
#include <string.h>

#include <taglib/tag.h>
#include <taglib/fileref.h>
#include <taglib/tstring.h>

#include <taglib/apetag.h>
#include <taglib/asftag.h>
#include <taglib/id3v1tag.h>
#include <taglib/id3v2tag.h>
#include <taglib/mp4tag.h>
#include <taglib/xiphcomment.h>
#include <taglib/modtag.h>
#include <taglib/infotag.h>
#include <taglib/apefile.h>
#include <taglib/asffile.h>
#include <taglib/flacfile.h>
#include <taglib/modfilebase.h>
#include <taglib/mp4file.h>
#include <taglib/mpcfile.h>
#include <taglib/mpegfile.h>
#include <taglib/oggfile.h>
#include <taglib/rifffile.h>
#include <taglib/trueaudiofile.h>
#include <taglib/wavpackfile.h>

std::vector<unsigned char>	ExtractCoverArt( const char * pszFilePath )
{
	printf( "----------------------------------------\n");
	printf( "file    : %s\n", pszFilePath );

	TagLib::FileRef	file( pszFilePath );
	TagLib::Tag*	piTag	= file.tag();

	if( NULL != piTag )
	{
		TagLib::File*				piFile		= file.file();
		TagLib::APE::File*			piFileAPE	= dynamic_cast<TagLib::APE::File*>(piFile);
		TagLib::ASF::File *			piFileASF	= dynamic_cast<TagLib::ASF::File*>(piFile);
		TagLib::FLAC::File *		piFileFLAC	= dynamic_cast<TagLib::FLAC::File*>(piFile);
		TagLib::Mod::FileBase  *	piFileMod	= dynamic_cast<TagLib::Mod::FileBase*>(piFile);
		TagLib::MP4::File *			piFileMP4	= dynamic_cast<TagLib::MP4::File*>(piFile);
		TagLib::MPC::File *			piFileMPC	= dynamic_cast<TagLib::MPC::File*>(piFile);
		TagLib::MPEG::File  *		piFileMPEG	= dynamic_cast<TagLib::MPEG::File*>(piFile);
		TagLib::Ogg::File *			piFileOgg	= dynamic_cast<TagLib::Ogg::File*>(piFile);
		TagLib::RIFF::File *		piFileRIFF	= dynamic_cast<TagLib::RIFF::File*>(piFile);
		TagLib::TrueAudio::File *	piFileTA	= dynamic_cast<TagLib::TrueAudio::File*>(piFile);
		TagLib::WavPack::File *		piFileWav	= dynamic_cast<TagLib::WavPack::File*>(piFile);
		
		TagLib::ID3v2::Tag*			piTagID3v2	= NULL;

		printf(
			"FileType: "
			"APE:%p, "	"ASP:%p, "	"FLAC:%p, "	"Mod:%p, "	"MP4:%p, "	"MPC:%p, "	"MPEG:%p, "	"Ogg:%p, "	"RIFF:%p, "	"TrueAudio:%p, "	"WavPack:%p, "	"\n",
			piFileAPE,	piFileASF,	piFileFLAC,	piFileMod,	piFileMP4,	piFileMPC,	piFileMPEG,	piFileOgg,	piFileRIFF,	piFileTA,			piFileWav );

		printf( "title   : %s\n", piTag->title().toCString(true) );
		printf( "artist  : %s\n", piTag->artist().toCString(true) );
		printf( "album   : %s\n", piTag->album().toCString(true) );
		printf( "year    : %d\n", piTag->year());
		printf( "comment : %s\n", piTag->comment().toCString(true) );

		if( NULL != piFileFLAC )
		{
			if( 0 < piFileFLAC->pictureList().size() )
			{
				TagLib::FLAC::Picture* pic = piFileFLAC->pictureList()[0];

			    std::vector<unsigned char>	data( pic->data().size());
			    memcpy( data.data(), pic->data().data(), data.size() );

				printf("CoverArt: %zu [bytes] FLAC\n", data.size() );
				return	data;
			}

			piTagID3v2	= piFileFLAC->ID3v2Tag(false);
		}
		else if( NULL != piFileMP4 )
		{
			TagLib::MP4::Tag* tag	= piFileMP4->tag();
			TagLib::MP4::ItemListMap itemsListMap = tag->itemListMap();
			TagLib::MP4::Item coverItem = itemsListMap["covr"];
			TagLib::MP4::CoverArtList coverArtList = coverItem.toCoverArtList();

			if (!coverArtList.isEmpty())
			{
			    TagLib::MP4::CoverArt	coverArt = coverArtList.front();

			    std::vector<unsigned char>	data( coverArt.data().size());
			    memcpy( data.data(), coverArt.data().data(), data.size() );

				printf("CoverArt: %zu [bytes] MP4\n", data.size() );
				return	data;
			}
		}
		else if( NULL != piFileASF )
		{
			const TagLib::ASF::AttributeListMap&	attrListMap = piFileASF->tag()->attributeListMap();
			const TagLib::ASF::AttributeList&		attrList	= attrListMap["WM/Picture"];
			TagLib::ASF::Picture					pic			= attrList[0].toPicture();

		    std::vector<unsigned char>	data( pic.picture().size());
		    memcpy( data.data(), pic.picture().data(), data.size() );

			printf("CoverArt: %zu [bytes] ASF\n", data.size() );
			return	data;
		}
		else if( NULL != piFileMPEG )
		{
			piTagID3v2	= piFileMPEG->ID3v2Tag(false);
		}

		if( NULL != piTagID3v2 )
		{
			TagLib::ID3v2::FrameList	frameList = piTagID3v2->frameList("APIC");
			if( !frameList.isEmpty() )
			{
				TagLib::ID3v2::AttachedPictureFrame*	coverImg = static_cast<TagLib::ID3v2::AttachedPictureFrame *>(frameList.front());

			    std::vector<unsigned char>	data( coverImg->picture().size());
			    memcpy( data.data(), coverImg->picture().data(), data.size() );

				printf("CoverArt: %zu [bytes] ID3v2\n", data.size() );
				return	data;
			}
		}
	}

	return	std::vector<unsigned char>();
}
```

# サンプル

こんな感じでしょうか？
サンプルはコンパイルは通していないので、悪しからず。

```C:SAMPLE
#include "CoverArtExtractor.h"

int main()
{
  ・
  ・
  ・
std::vector<unsigned char> coverArt = ExtractCoverArt( "SomeMusicFile.mp3" );
  ・
  ・
  ・
fwrite( coverArt.data(), coverArt.size(), 1, fp );
  ・
  ・
  ・
cv::Mat image = cv::imdecode( coverArt, cv::IMREAD_COLOR );
  ・
  ・
  ・
}
```

コンパイル時は、

```:gccに追加するオプション
`taglib-config --cflags` `taglib-config --libs`
```

のフラグ指定追加で、必要なオプションを展開してくれます。