linux系统获取MP3的专辑封面图片
背景
我们播放的MP3格式的音乐的时候,有的显示专辑封面图片,有的不显示,这是为什么呢?是这样的,我们看到的MP3文件不仅仅包含听到的那些声音,其实作为一个MP3文件它还包含描述这首歌的一些文字信息(标题名、作者、专集名、年代、风格等等)和歌词信息,还有内嵌的专辑封面图片等信息。但是并不是所有的MP3文件制作的时候都内嵌了图片,所以有的MP3文件播放的时候,可以显示专辑封面图片,有的不能显示专辑封面图片。一些音乐播放器有修改歌曲封面图片的功能,这里我们来讲一讲怎么自己编写代码(C语言实现)来提取歌曲封面图片。
MP3文件构成
MP3文件(二进制文件)分为三个部分:ID3V2标签、音频数据和ID3V1标签,其中ID3V2标签位于MP3文件的开头,中间为音频数据,ID3V1标签位于MP3文件的结尾。ID3V1只是包含歌曲名、作者、专集名、日期和歌曲风格等基本信息,而ID3V2标签不但包含ID3V1标签的所有信息,还包含专辑封面图片信息,MP3文件的构成如下图所示。
注:封面图片一般是JPEG格式的图片,也有PNG、BMP格式的文件,本文以JPEG格式的图片来讲解,其他格式的原理也是一样的。
实现原理
对MP3二进制文件进行解析,主要是对ID3V2标签进行解析,取得其中的专辑封面图片的数据,然后将图片数据保存为指定类型的图片(通过指定文件扩展名实现),存储到指定路径,需要使用图片的时候,到该路径取得就可以。ID3V2标签的解析下文会详细讲解。
实现方法/步骤
1、打开MP3二进制文件(fopen)
2、取MP3文件前3个字符进行判断,如果为“ID3”,则说明该MP3文件包含ID3V2标签。
3、计算MP3文件数据总的大小,MP3文件的第7~10字节(4个字节)保存MP3文件数据总的大小。
4、取得ID3V2标签帧的帧头
.解析出当前的帧标识,根据这个可以确定MP3数据信息的类别
.计算当前的帧内容的长度,即获得类别信息的大小
5、判断MP3二进制文件中是否有专辑封面图片
如果帧标识为“APIC”,说明MP3中含有专辑封面图片。
6、图片文件格式判断
.jpeg文件标志的前两个字节为FF、D8
.png文件标志的前两个字节为89、50
注:当步骤5判断为有图片的时候,从帧标识为“APIC”的帧头位置开始,如果连续的两个字节为FF和D8,说明这个图片为jpeg文件,即FF、D8是jpeg文件的开始标志。
7、将MP3二进制文件中的图片数据读取出来,保存为jpeg文件
得到了jpeg文件的开始位置(FF、D8),也知道jpeg文件数据的大小,就可将这部分二进制数据取出,保存成扩展名为“XXX.jpeg”的文件。
知识点讲解
以下内容为扩展信息,作为对以上内容的补充说明。
ID3V2标签简介
每个ID3V2的标签都有唯一一个标签头和若干个标签帧组成(每个标签至少要有一个标签帧),标签头和标签帧一起顺序存放在MP3文件的开始位置。MP3的信息如标题、作者、专辑封面图片等都存放在不同的标签帧中。
ID3V2标签头
ID3V2标签头信息位于MP3文件的开始处,长度为10个字节。数据结构如下:
char Header[3]; /*必须为"ID3"否则认为标签不存在*/
char Ver; /*版本号;ID3V2.3就记录03,ID3V2.4就记录04*/
char Revision; /*副版本号;此版本记录为00*/
char Flag; /*存放标志的字节,这个版本只定义了三位,其它位为0*/
char Size[4]; /*标签大小,包括标签帧和标签头。(不包括扩展标签头的10个字节)*/
如下图利用UltraEdit打开一个mp3文件(文件名为“阿福(邓福如)-天使.mp3”):
说明:
1、前3个字节为49,44,33对应的ascii码就是ID3,因此判断存在ID3V2标签
2、第4个字节为03,说明这个音乐文件的标签是ID3V2.3格式
3、第5个字节为00,说明副版本号为0,即版本为ID3V2的3.0版本
4、第6个字节为00,标志字节一般为0,定义如下(abc000000B)
a:表示是否使用Unsynchronisation
b:表示是否有扩展头部,一般没有,所以一般也不设置,默认值为0
c:表示是否为测试标签,99.99%的标签都不是测试标签,不设置,默认值为0
5、第7~10个字节为00,03,48,60,记录的是整个标签的大小(字节数),但每个字节只用7位,最高位不使用恒为0,计算公式如下:
nTagSize = ((size[0] & 0xff) << 21)
|((size[1] & 0xff) << 14)
|((size[2] & 0xff) << 7)
|(size[3] & 0xff);
ID3V2标签帧
每个标签帧都有10个字节的帧头(和ID3V2标签头不是一个东西,虽然他们刚好都是10字节,每个ID3V2标签只有一个标签头,而每个标签帧都有一个帧头,一个ID3V2标签有几个标签帧就会有几个帧头)和至少一个字节的帧内容构成,标签头与标签帧(帧头和帧内容构成)之间无特殊字节分割,只能通过帧头信息来确定帧内容的大小,ID3V2标签帧的构成如下图所示。
帧头
每一个ID3V2标签帧都有一个帧头。
帧头结构
帧头长度10字节,由3部分构成,数据结构如下:
char ID[4]; /*标识帧,说明其内容,例如作者/标题等*/
char Size[4]; /*帧内容的大小,不包括帧头,不得小于1*/
char Flags[2]; /*标志帧,只定义了6 位*/
帧头详细说明
标识帧,常见的内容如下:
TIT2 = 标题 表示内容为这首歌的标题
TPE1 = 作者 表示内容为这首歌的作者
TALB = 专集 表示内容为这首歌的专集
TRCK = 音轨 格式:N/M 其中N为专集中的第N首,M为专集中共M首,N和M为ASCII码表示的数字
TYER = 年代 是用ASCII码表示的数字
TCON = 类型 直接用字符串表示
COMM = 备注 格式:"eng\0备注内容",其中eng表示备注所使用的自然语言
APIC = 专辑图片
帧内容
帧头长度为10字节,从帧头标识帧开始位置,向后加10个字节,为该帧内容的开始位置,大小在帧头中已经指定。