ID3V2是目前主流的mp3标签格式,特别是做为车载音乐播放器等一些无法连接到互联网的应用场景上,我们无法通过网络获得歌曲的信息,因此,读取ID3V2或者ID3V1标签就是一个很好的解决方案,这里主要记录的是在qt上通过代码实现这些信息的读取,借鉴了网上主流的方案,这里只是简单的介绍了下代码会用到的地方
一、ID3V2标签格式说明
1.1 标签头
在文件的首部顺序记录10个字节的ID3V2.3的头部。数据结构如下:
char Header[3]; /*必须为"ID3"否则认为标签不存在*/
char Ver; /*版本号;ID3V2.3就记录03,ID3V2.4就记录04*/
char Revision; /*副版本号;此版本记录为00*/
char Flag; /*存放标志的字节,这个版本只定义了三位,稍后详细解说*/
char Size[4]; /*标签大小,包括标签帧和标签头。(不包括扩展标签头的10个字节)*/
我们可以利用Binary Viewer打开任意一个mp3文件:
观察前10个字节:
其中,49,44,33 对应的ascii码就是ID3,03代表ID3V2.3,说明这个音乐文件的标签是ID3V2.3格式;
后4个字节00,17,2B,1A记录的是整个标签的大小(字节),但每个字节只用7位,最高位不使用恒为0。所以格式如下:
0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx
计算时要做适当的转换,通过移位操作实现:
mp3_TagSize = ((Header_size[0] & 0xff) << 21) |
((Header_size[1] & 0xff) << 14) |
((Header_size[2] & 0xff) << 7) |
(Header_size[3] & 0xff);
其中Header_size[0]对应的是00字节,Header_size[3]对应的是最后一个字节(1A),以此类推;
1.2标签帧
每个标签帧都有一个10个字节的帧头和至少一个字节的不固定长度的内容组成,如图所示:
灰色框为帧头,蓝色框为帧内容
帧头的定义如下:
char FrameID[4]; /*用四个字符标识一个帧,说明其内容,稍后有常用的标识对照表*/
char Size[4]; /*帧内容的大小,不包括帧头,不得小于1*/
char Flags[2]; /*存放标志,只定义了6位,稍后详细解说*/
帧内容每个字节的8位全用,格式如下:
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
framecount = frameSize[0]*0x1000000+frameSize[1]*0x10000+frameSize[2]*0x100+frameSize[3];
1.3 帧标识
用四个字符标识一个帧,说明一个帧的内容含义,常用的对照如下:
TIT2=标题 表示内容为这首歌的标题,下同
TPE1=作者
TALB=专集
TRCK=音轨 格式:N/M 其中N为专集中的第N首,M为专集中共M首,N和M为ASCII码表示的数字
TYER=年代 是用ASCII码表示的数字
TCON=类型 直接用字符串表示
COMM=备注 格式:"eng\0备注内容",其中eng表示备注所使用的自然语言
APIC = 专辑图片
二、图片读取
在网易云音乐和qq音乐下载的歌曲,一般都是以png和jfif(jpeg的一种衍生格式)储存在歌曲文件中的,我们要把图片提取并且存放,就必须知道图片的存储格式,这样才能生成指定的图片文件格式
jpeg格式解析可以参考博文:
https://blog.csdn.net/u012819339/article/details/46544061
png格式解析可以参考博文:
https://blog.csdn.net/bisword/article/details/2777121
我这里只做简单的判断:
png文件标志的前两个字节为89 50;
jpeg文件标志的前两个字节为FF,D8;
根据这两个特点可以判断出图片的类型
图中红色部分的14个字节是固定的,我们在读取图片的数据帧时直接跳过,接着到绿色部分,判断绿色部分的数据,根据数据可以得出图片类型,图中显然是jpeg格式图片,接着就可以读取图片内容了(绿色部分也要包含在图片内容的读取部分,红色不用)
总结:在代码中,只要在标签头的10个字节中判断文件开头是否为ID3V2,读取标签的总大小;
然后依次读取每个标签帧;
每个标签帧中又分为:读取标签头,获得标签类型,获得帧内容大小,读取帧内容;
下一篇将通过代码实现读取
QT 读取mp3ID3V2 获取mp3专辑图片、专辑名称、标题、作者(二)