0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-08-24

概要

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

NanoPi-NEOとMPDとOLEDで音楽再生サーバ
では、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などに渡せば、デコードできる。

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>();
}

サンプル

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

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`

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

0
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?