C语言读取MP3文件id tag计算播放时长

原文:https://blog.csdn.net/hongjiujing/article/details/2148370

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/io.h>

#define SEEK_END 2

void main()
{
	FILE *fp=NULL;
	int bHasID3V2=0;
	char cVer=0;
	char cRevision=0;
	int bHasExtHeader=0;
	int ID3V2_size=0;
	#define ID3V1_size 128
	char cID3V2_head[10]={0}; 
	char cID3v2Frame_head[10]={0};
	char *cID3v2Frame=NULL;
	long iID3v2Frame_length=0;
	
	/*##########################Symbol In Frame###################################*/ 
	long iFrameStart=0,iFrameMove=0,iFrameCount=0;
	unsigned long iFrameSize=0;
	char cFrameHead_bin[33]={0};
	char cFrameHead_bin_temp[9]={0};
	
	/*##########################Symbol In ID3V1###################################*/
	char cID3V1[128]={0};
	
	/*##########################Symbol Above######################################*/
	unsigned char* cBuffer=NULL;
	int SamplingrateTable[3][3]={{44100,22050,11025},{48000,24000,120000},{32000,16000,8000}};
	char* ChannelDescrip[4]={"立体声","混合立体声","双声","单声"};
	int cBuffer_size=1024,Bitrate=0,FrameSize=0,FrameCount=0,mp3Duration=0;
	char LayerDescript=0 ,bRateIndex=0 ,bSampleRate=0,Version=0,bPadding=0,bChannelMode=0;
	long int flength=0;
	int i=0,j=0;
	char argv[]={"music.mp3"};
	
	/*##########################Symbol Above######################################*/ 
	void getBin(int ,char* );
	int GetBitRate(int ,int , int ); //函数宣告
	if((fp=fopen(argv,"rb"))==NULL)
	{
		printf("<%s, %d>ERROR:can't open the file!\n", __FILE__, __LINE__);
		getchar();
		exit(1);
	}
	/*##########################ID3V2 Reading#####################################*/
	fread(cID3V2_head,10,1,fp);
	if( (cID3V2_head[0]=='I'||cID3V2_head[1]=='i')
	&&(cID3V2_head[1]=='D'||cID3V2_head[2]=='d')
	&&cID3V2_head[2]=='3')
	{
		bHasID3V2=1;
		cVer=cID3V2_head[3];
		cRevision=cID3V2_head[4];
		
		if(cID3V2_head[5]&0x64==0x64) bHasExtHeader = 1;
		if(cID3V2_head[5]&0x10==0x10) bHasExtHeader = 1;

		//ID3V2_size = (cID3V2_head[6]&0x7F)*0x200000
		//+ (cID3V2_head[7]&0x7F)*0x400
		//+ (cID3V2_head[8]&0x7F)*0x80
		//+ (cID3V2_head[9]&0x7F);
		ID3V2_size= (cID3V2_head[6]&0x7F) << 21
		| (cID3V2_head[7]&0x7F) << 14
		| (cID3V2_head[8]&0x7F) << 7
		| (cID3V2_head[9]&0x7F) + 10 ; 
		printf("<%s, %d>ID3V2_size:%d bytes\n",__FILE__, __LINE__, ID3V2_size);
		iFrameStart=--ID3V2_size;
	}
	else
	{
		bHasID3V2=0;
		printf("<%s, %d>There is no ID3V2*\n", __FILE__, __LINE__);
	}
	
	rewind(fp); /*改文件指针指向文件头*/
	fseek(fp,10L,1);

	while((ftell(fp)+10)<=ID3V2_size)
	{
		memset(cID3v2Frame_head,0,10); /*内存清空*/
		fread(cID3v2Frame_head,10,1,fp); /*ID3V2帧信息头读取*/

		iID3v2Frame_length =(long)(cID3v2Frame_head[4]*0x100000000
		+cID3v2Frame_head[5]*0x10000
		+cID3v2Frame_head[6]*0x100
		+cID3v2Frame_head[7]); /*计算帧的大小.*/

		if (cID3v2Frame_head[0]=='/0'
			&& cID3v2Frame_head[1]=='/0'
			&& cID3v2Frame_head[2]=='/0'
			&& cID3v2Frame_head[3]=='/0')
		break;

		#if 0
		for (i=0;i<4;i++) putchar(cID3v2Frame_head[i]); /*FrameSign(4)*/
		putchar('-');putchar('>'); /* Print "->"*/

		cID3v2Frame=malloc(iID3v2Frame_length); /* 为 cID3v2Frame 指针分配内存, 功能类似于VB中的动态数组*/
		if (cID3v2Frame!=NULL) // 检测动态内存分配是否已经成功
		{
			fread(cID3v2Frame,iID3v2Frame_length,1,fp);
			i=0;
			while(i<iID3v2Frame_length) 
			{
				putchar(cID3v2Frame[i]);
				i++;
			}
			putchar('/n');
			free(cID3v2Frame);
		}
		else
		{
			if(fp!=NULL) fclose(fp);
			printf("<%s, %d>ERROR:Memory Exhausted!\n", __FILE__, __LINE__);
			exit(1);
		}
		#endif
	}
	putchar('*');
	putchar('\n');

	/*(mp3_FrameHeader) Reading*/
	fseek(fp, 0L, SEEK_END); //移文件指针到文件尾
	flength = ftell(fp); //文件长 
 
	rewind(fp);
	fseek(fp,10+ID3V2_size,1);
	while((ftell(fp)+4)<flength)
	{
		if (ftell(fp)+1024<=flength)
			cBuffer_size=1024; 
		else 
			cBuffer_size=flength-ftell(fp); 
		 
		cBuffer=malloc(cBuffer_size); 
		if (cBuffer==NULL) // 检测动态内存分配是否已经成功 
		{ 
			if (fp!=NULL) fclose(fp); 
			printf("<%s, %d>ERROR:Memory Exhausted!\n", __FILE__, __LINE__); 
			exit(1);
		} 
		memset(cBuffer,0,cBuffer_size); 
		fread(cBuffer,cBuffer_size,1,fp); 
		for(i=0;i<(cBuffer_size-4); i++) 
		{ 
			//Mp3帧头(FRAMEHEADER)格式如下:AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM 
			LayerDescript = (cBuffer[i+1] & 0x6)>>1; //Part CC IN 'AAABBCCD' ,Layer description '00' - reserved 
		 
			//Part EEEE in 'EEEEFFGH', But '1111' is Bad Bitrate index, "bad" means that this is not an allowed value 
			bRateIndex = cBuffer[i+2] /0x10 ; // EEEEXXXX!='1111' 
			bSampleRate = (cBuffer[i+2] & 0xA) >>2 ; //Part FF IN 'EEEEFFGH' ,'11' reserved 
		 
			if (cBuffer[i] ==0xFF 
			&& cBuffer[i+1] > 0xE0 
			&& bRateIndex != 0xF 
			&& LayerDescript != 0x0 
			&& bSampleRate < 0x3 ) 
			{ 
				printf("<%s, %d>Mp3_FrameHeader->\n", __FILE__, __LINE__); 
				memset(cFrameHead_bin,0,32); 
				j=cBuffer[i]; 
				getBin(j,cFrameHead_bin_temp); 
				strcat(cFrameHead_bin,cFrameHead_bin_temp); 
				putchar('-'); 

				j=cBuffer[i+1]; 
				getBin(j,cFrameHead_bin_temp); 
				strcat(cFrameHead_bin,cFrameHead_bin_temp);//strcat的两个传入参数都必需以 '/0' 代表结尾 
				putchar('-'); 

				j=cBuffer[i+2]; 
				getBin(j,cFrameHead_bin_temp); 
				strcat(cFrameHead_bin,cFrameHead_bin_temp); 
				putchar('-'); 

				j=cBuffer[i+3]; 
				getBin(j,cFrameHead_bin_temp); 
				strcat(cFrameHead_bin,cFrameHead_bin_temp); 

				Version = (cBuffer[i+1] & 0x18)>>3; 
				bPadding=(cBuffer[i+1] & 0x2)>>1; 
				Bitrate = GetBitRate(bRateIndex, LayerDescript, Version); 
				bChannelMode=(cBuffer[i+3] & 0xC0)>>6; 
				putchar ('\n'); 

				if (bRateIndex != 0) 
				{ 
					switch (Version) 
					{ 
					case 0: 
					printf("<%s, %d>MPEG 2.5 层 %d, %dHz %s\n",__FILE__, __LINE__, 4-LayerDescript, 
					SamplingrateTable[bSampleRate][2],ChannelDescrip[bChannelMode]); 

					FrameSize = ((72 * Bitrate*1000) / SamplingrateTable[bSampleRate][2]) + 

					bPadding; 
					FrameCount=(int)((flength-(ftell(fp)-cBuffer_size+i)) /FrameSize); 
					mp3Duration=(int)(FrameCount*0.026); //每帧的播放时间:无论帧长是多少,每帧的播放时间都是26ms; 
					printf("<%s, %d>CBR:-> %dKbit %d帧\n",__FILE__, __LINE__, Bitrate,FrameCount); 
					printf("<%s, %d>长度:%d 秒\n", __FILE__, __LINE__, mp3Duration); 
					break;
					
					case 2: 
					printf("<%s, %d>MPEG 2.0 层 %d, %dHz %s\n", __FILE__, __LINE__, 4-LayerDescript, 
					SamplingrateTable[bSampleRate][1],ChannelDescrip[bChannelMode]); 
		 
					FrameSize = ((72 * Bitrate*1000) / SamplingrateTable[bSampleRate][1]) + 
					bPadding;
					FrameCount=(int)((flength-(ftell(fp)-cBuffer_size+i)) /FrameSize);
					mp3Duration=(int)(FrameCount*0.026); //每帧的播放时间:无论帧长是多少,每帧的播放时间都是26ms;
					printf("<%s, %d>CBR:-> %dKbit %d帧\n", __FILE__, __LINE__, Bitrate,FrameCount);
					printf("<%s, %d>长度:%d 秒\n", __FILE__, __LINE__, mp3Duration);
					break;
					
					case 3: 
					printf("<%s, %d>MPEG 1.0 层 %d, %dHz %s\n", __FILE__, __LINE__, 4-LayerDescript,
					SamplingrateTable[bSampleRate][0],ChannelDescrip[bChannelMode]); 
					
					FrameSize = ((144 * Bitrate*1000) / SamplingrateTable[bSampleRate][0]) +
					
					bPadding;
					FrameCount=(int)((flength-(ftell(fp)-cBuffer_size+i)) /FrameSize);
					mp3Duration=(int)(FrameCount*0.026); //每帧的播放时间:无论帧长是多少,每帧的播放时间都是26ms;
					
					printf("<%s, %d>CBR:->%dKbit %dFrame\n", __FILE__, __LINE__, Bitrate,FrameCount);
					printf("<%s, %d>mp3Duration:%ds\n", __FILE__, __LINE__, mp3Duration);
					break;
					}
				}
				else
					printf("<%s, %d>This a Free Rate MP3 File!\n", __FILE__, __LINE__);

				cBuffer_size=-1;
				break;
			}
		}
		free(cBuffer);
		if (cBuffer_size ==(-1) ) break;
	}
	/*ID3V1 Reading*/
	 
	fseek(fp,-128L,SEEK_END);
	fread(cID3V1,ID3V1_size ,1,fp);

	if((cID3V1[0]=='T'||cID3V1[0]=='t')
	&&(cID3V1[1]=='A'||cID3V1[1]=='a')
	&&(cID3V1[2]=='G'||cID3V1[2]=='g'))
	{
		printf("<%s, %d>ID3V1_size:%d bytes\n", __FILE__, __LINE__, ID3V1_size );
		for(i=0;i<128;i++) putchar(cID3V1[i]);
		putchar('\n');
	}
	else
	{
		printf("<%s, %d>There is no ID3V1\n", __FILE__, __LINE__);
	}
	fclose(fp);
}

void getBin( int dec,char* bin)
{
	#if 0
	int i,j,len;
	char temp[8];
	memset(temp,0,8);
	itoa(dec,temp,2); ///把整数i转换成字符串将i转换为字符串放入temp中,最后一个数字表示2进制
	len=strlen(temp);
	memset(bin,0,strlen(bin));
	
	for(i=0,j=0;i<8;i++,j++)
	{ 
		if (temp[j]!='/0')
		bin[i]=temp[j];
		else
		bin[i]='0';
	}
	bin[i]='/0';
	for(i=0,j=0;i<8;i++,j++) putchar(bin[i]);
	#endif
}
	
int GetBitRate(int bRateIndex,int LayerDescript, int Version)
{ 
	int BitrateTable[6][15]= 
	{ 
		{-1,32,64,96,128,160,192,224,256,288,320,352,384,416,448},
		{-1,32,48,56,64,80,96,112,128,160,192,224,256,320,384},
		{-1,32,40,48,56,64,80,96,112,128,160,192,224,256,320},
		{-1,32,64,96,128,160,192,2324,256,288,320,352,384,416,448},
		{-1,32,48,56,64,80,96,112,128,160,192,224,256,320,384},
		{-1,8,16,24,32,64,80,56,64,128,160,112,128,256,320}
	}; //kbps (-1) means :free
	int i,j; 
	if (Version==3 && LayerDescript==3 )j=0; 
	else if (Version==3 && LayerDescript==2 )j=1;
	else if (Version==3 && LayerDescript==1 )j=2; 
	else if (Version==2 && LayerDescript==1 )j=3;
	else if (Version==2 && LayerDescript==2 )j=4;
	else if (Version==2 && LayerDescript==3 )j=5; 
	i=BitrateTable[j][bRateIndex];
	return i;
}

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值