mp3 file format


MP3文件大体分为三部分:

TAG_V2(ID3V2)

音频数据,

TAG_V1(ID3V1)

其中ID3V2ID3V1的补充,并不是所有的MP3都有ID3V2补充,即是不是所有的MP3文件都有ID3V2


如果MP3文件存在ID3V2,则一定在文件的头部,ID3V2结构分为头部(header)和若干标签帧,其中头部长度为10字节,10个字节的结构如表1

0

1

2

3

4

5

6

7

8

9

内容为”ID3”

版本号

副版本号

存放标志的字节

ID3V2总大小(帧头和之后的若干标签帧总和)


判断MP3文件是否存在ID3V2,只需要判断文件前三个字节是否是”ID3”.


读取MP3文件ID3V2信息的函数可如下:

//定义头部和标签帧

typedefstruct ID3v2Header{

   char Identify[3];         // ID3v2固定标志:ID3

   char Ver;              //主版本号,ID3v2就是3

   char Rever;            //副版本号,一般都为0

   char Flag;             //标志位,一般为0,字义为abc00000

   char Size[4];             //标签大小,一共四个字节,但每个字节只使用7位,最高位不使用恒为0,所以格式: 0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx

}ID3v2Header;

 

shell.albert@yantai:~/temporary/build-ZAudioTest-Desktop_Qt_5_3_GCC_64bit-Debug> hexdump  -C test.mp3 | head -n 2
00000000  49 44 33 03 00 00 00 00  1f 76 54 50 45 31 00 00  |ID3......vTPE1..|
00000010  00 1d 00 00 01 ff fe 53  00 65 00 63 00 72 00 65  |.......S.e.c.r.e|


typedefstruct ID3v2Frame//标签帧,10个字节

{

   char FrameID[4];          //标志对照符,如TEXTTOPETDAT....

   char Size[4];             //帧体的大小,按照正常的8位存储的,FSize = Size[0]*0x100000000 + Size[1]*0x10000 + Size[2]*0x100 + Size[3];

   char Flag[2];             //存放标志

}ID3v2Frame;

 

//输出信息并返回ID3V2大小

int ReadID3v2(FILE *pf)

{

   ID3v2Headermp3header;

   ID3v2Frame mp3Frame;

   int FSize      = 0;

   char str[4096] = {0};

   char str2[5]   = {0};

   int ID3size;

   inthead_size = 0;

   inti;

   if(!pf)

       return -1;

   fseek(pf,0,SEEK_SET);

 读取mp3的头部分信息

   fread(&mp3header,sizeof(mp3header),1,pf);

   if (mp3header.Identify[0]!='I' || mp3header.Identify[1]!='D' || mp3header.Identify[2]!='3' ){

       printf("此歌曲不支持ID3v2标准!\n");

       //文件复位

       rewind(pf);

       return -2;

   }

   printf("ID3v2标志:%.3s\n",mp3header.Identify);

   printf("ID3v2版本:%d\n",  mp3header.Ver);

   ID3size= (mp3header.Size[0]& 0x7F)<< 21|(mp3header.Size[1]& 0x7F)<< 14|(mp3header.Size[2] & 0x7F) << 7|(mp3header.Size[3] & 0x7F);

   printf("标签大小:%d\n***********\n",ID3size);

   for (i=0;i<ID3size;i=i+11+FSize){

       memset(&mp3Frame,0,sizeof(mp3Frame));

       memset(&str,0,sizeof(str));

       fseek(pf,10+i,SEEK_SET);               //移动到标签帧头

       fread(&mp3Frame,sizeof(mp3Frame),1,pf);

       //原则上是不用-1的,但是实际发现,总有一个字节的差距,为了计算方便-1,所以出现-1时标明此区块无内容

       FSize  = (int)(mp3Frame.Size[0]*0x100000000 + mp3Frame.Size[1]*0x10000+ mp3Frame.Size[2]*0x100 + mp3Frame.Size[3]-1);

       if (FSize>0)   {

           fseek(pf,10+11+i,SEEK_SET);//移动到内容区           

           fread(str,FSize,1,pf);

           GetStr(mp3Frame.FrameID,str2);

           printf("%s-%s:\t%s\n",str2,mp3Frame.FrameID,str);

           head_size+=11;

       }else{

           return ID3size+10;

       }

   }

   return ID3size+10;

}

 

//通过FrameID获取对应的中文名

void GetStr(char* oldstr,char* str)

{

   if (0==memcmp((LPCTSTR)"TIT2",oldstr,4))

   {

       memcpy(str,"标题",4);

   }elseif(0==memcmp((LPCTSTR)"TPE1",oldstr,4)){

       memcpy(str,"作者",4);

   }elseif(0==memcmp((LPCTSTR)"TALB",oldstr,4)){

       memcpy(str,"专辑",4);

   }elseif(0==memcmp((LPCTSTR)"TRCK",oldstr,4)){

       memcpy(str,"音轨",4);

   }elseif(0==memcmp((LPCTSTR)"TYER",oldstr,4)){

       memcpy(str,"年代",4);

   }elseif(0==memcmp((LPCTSTR)"COMM",oldstr,4)){

       memcpy(str,"备注",4);

   }elseif(0==memcmp((LPCTSTR)"TCON",oldstr,4)){

       memcpy(str,"类型",4);

   }else{

       memcpy(str,"未知",4);  //其他的不是很重要,所以省略了

   }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值