`
确实比较男
  • 浏览: 112040 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

解析mp3文件,获得mp3中的专辑图片

阅读更多

与上一篇写的一样,参考的都是一样的资料

参考的资料:

http://duyouhua1214.iteye.com/blog/1326238

 

 

这仍然也是操作的是字节,所以其他语言都是适用的。

mp3文件的首尾都存有文件的信息,存在尾部的称为ID3V1,在首部的称为 ID3V2。专辑图片是存放在部的ID3V2。所以这里解析ID3v2

 

 

主要的知识点,都是资料中的:

ID3V2 到现在一共有 4 个版本,但流行的播放软件一般只支持第 3 版,既 ID3v2.3。由于 ID3V1 记录
在 MP3 文件的末尾,ID3V2 就只好记录在 MP3 文件的首部了(如果有一天发布 ID3V3,真不知道该记录在哪
里)。也正是由于这个原因,对 ID3V2 的操作比 ID3V1 要慢。而且 ID3V2 结构比 ID3V1 的结构要复杂得多,
但比前者全面且可以伸缩和扩展。
 下面就介绍一下 ID3V2.3。
 每个 ID3V2.3 的标签都一个标签头和若干个标签帧或一个扩展标签头组成。关于曲目的信息如标题、作者
等都存放在不同的标签帧中,扩展标签头和标签帧并不是必要的,但每个标签至少要有一个标签帧。标签
头和标签帧一起顺序存放在 MP3 文件的首部。
1、标签头
在文件的首部顺序记录 10 个字节的 ID3V2.3 的头部。数据结构如下:
 char Header[3];     /*必须为"ID3"否则认为标签不存在*/
 char Ver;     /*版本号 ID3V2.3 就记录 3*/
 char Revision;     /*副版本号此版本记录为 0*/
 char Flag;     /*存放标志的字节,这个版本只定义了三位,稍后详细解说*/
 char Size[4];     /*标签大小,包括标签头的 10 个字节和所有的标签帧的大小*/
 1).标志字节
 标志字节一般为 0,定义如下:
 abc00000
 a -- 表示是否使用 Unsynchronisation(这个单词不知道是什么意思,字典里也没有找到,一般不设置)
 b -- 表示是否有扩展头部,一般没有(至少 Winamp 没有记录),所以一般也不设置
 c -- 表示是否为测试标签(99.99%的标签都不是测试用的啦,所以一般也不设置)
 2).标签大小
 一共四个字节,但每个字节只用 7 位,最高位不使用恒为 0。所以格式如下
 0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx
 计算大小时要将 0 去掉,得到一个 28 位的二进制数,就是标签大小(不懂为什么要这样做),计算公式如
下:
 int total_size;
 total_size =    (Size[0]&0x7F)*0x200000
   +(Size[1]&0x7F)*0x400
   +(Size[2]&0x7F)*0x80
   +(Size[3]&0x7F)
2、标签帧
每个标签帧都有一个 10 个字节的帧头和至少一个字节的不固定长度的内容组成。                    它们也是顺序存放在文件
中,和标签头和其他的标签帧也没有特殊的字符分隔。得到一个完整的帧的内容只有从帧头中的到内容大
小后才能读出,读取时要注意大小,不要将其他帧的内容或帧头读入。
帧头的定义如下:
 char FrameID[4];   /*用四个字符标识一个帧,说明其内容,稍后有常用的标识对照表*/
 char Size[4];    /*帧内容的大小,不包括帧头,不得小于 1*/
 char Flags[2];    /*存放标志,只定义了 6 位,稍后详细解说*/
 1).帧标识
 用四个字符标识一个帧,说明一个帧的内容含义,常用的对照如下:
 TIT2=标题 表示内容为这首歌的标题,下同
 TPE1=作者
 TALB=专集
 TRCK=音轨 格式:N/M        其中 N 为专集中的第 N 首,M 为专集中共 M 首,N 和 M 为 ASCII 码表示的数字
 TYER=年代 是用 ASCII 码表示的数字
 TCON=类型 直接用字符串表示
 COMM=备注 格式:"eng\0 备注内容",其中 eng 表示备注所使用的自然语言
 2).大小
 这个可没有标签头的算法那么麻烦,每个字节的 8 位全用,格式如下
 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
 算法如下:
 int FSize;
 FSize = Size[0]*0x100000000
 +Size[1]*0x10000
 +Size[2]*0x100
 +Size[3];
 3).标志
 只定义了 6 位,另外的 10 位为 0,但大部分的情况下 16 位都为 0 就可以了。格式如下:
 abc00000 ijk00000
 a -- 标签保护标志,设置时认为此帧作废
 b -- 文件保护标志,设置时认为此帧作废
 c -- 只读标志,设置时认为此帧不能修改(但我没有找到一个软件理会这个标志)
 i -- 压缩标志,设置时一个字节存放两个 BCD 码表示数字
 j -- 加密标志(没有见过哪个 MP3 文件的标签用了加密)
 k -- 组标志,设置时说明此帧和其他的某帧是一组
 值得一提的是 winamp 在保存和读取帧内容的时候会在内容前面加个'\0',并把这个字节计算在帧内容的
大小中。
 
    这个文件SoundPlayer是在播放音乐的时候得到专辑
 
 
package service
{
	//import省略

	public class SoundPlayer
	{	private var channel:SoundChannel;//声音通道
		private var sound:Sound;//声音
		private var fileUrl:String;
		private var loader:Loader = new Loader  ;
		private var bitmap:Bitmap;
		public function SoundPlayer(){}

		//播放音乐的方法
		public function play(url:String):void
		{
			this.fileUrl = url;
			sound = new Sound  ;
			sound.load(new URLRequest(url));
			channel = sound.play();

			sound.addEventListener(Event.COMPLETE,soundLoaderComplete);
		}
		//soundLoaderComplete 歌曲加载成功 得到专辑图片
		private function soundLoaderComplete(event:Event):void
		{
			(event.target as Sound).removeEventListener(Event.COMPLETE,soundLoaderComplete);
			var fileStream:FileStream = new FileStream  ;
			fileStream.open(new File(this.fileUrl),FileMode.READ);
			//设置文件读取的位置;
			var buffer:ByteArray = new ByteArray  ;
			fileStream.readBytes(buffer,0,10);
			var id3Header:ID3V2Header = new ID3V2Header(buffer);
			//去除标签头
			while (true)
			{	//读取帧头
				var frameHeaderBuffer:ByteArray = new ByteArray  ;
				fileStream.readBytes(frameHeaderBuffer,0,10);
				var id3FrameHeader:ID3V2Frameheader = new ID3V2Frameheader(frameHeaderBuffer);
				if (id3FrameHeader.getFrameSize() <= 0)
				{
					//没有专辑图片
					//删除原来的图片
					loader.unload();
					loader.load(new URLRequest("../images/app.png"));
					loader.contentLoaderInfo.addEventListener(Event.COMPLETE,imageLoaderComplete);
					break;
				}

				//读取帧体
				var frameBodyBuffer:ByteArray = new ByteArray  ;
				fileStream.readBytes(frameBodyBuffer,0,id3FrameHeader.getFrameSize());

				//符标识;
				var key:String = id3FrameHeader.getFrameId();
				//专辑图片的符标识是“APIC”
				if (key == "APIC")
				{
					//专辑图片
					var imageBytes:ByteArray = new ByteArray  ;
					//前14个字节无用   去除掉
					frameBodyBuffer.position = 14;
					frameBodyBuffer.readBytes(imageBytes,0,frameBodyBuffer.length - 14);
					//删除原来的图片;
					loader.unload();
					loader.loadBytes(imageBytes);
					loader.contentLoaderInfo.addEventListener(Event.COMPLETE,imageLoaderComplete);

					break;
				}
			}
			fileStream.close();
		}

		//专辑图片加载完成
		private function imageLoaderComplete(event:Event):void
		{
			loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,imageLoaderComplete);                                                                                     
			this.bitmap = loader.content as Bitmap;
		}


	}

}
 
 
 
 标签头
ID3V2Header.as
 
package service
{
	import flash.utils.ByteArray;

	public class ID3V2Header
	{

		private var identi:ByteArray = new ByteArray;// ID3标示 3
		private var major:ByteArray = new ByteArray;// 版本号 3 1
		private var revsion:ByteArray = new ByteArray;// 0 1
		private var flags:ByteArray = new ByteArray;// 1
		private var total_size:int;// 标签体大小 4


		public function ID3V2Header(data:ByteArray)
		{
			// constructor code
			data.readBytes(identi,0,3);
			data.readBytes(major,0,1);
			data.readBytes(revsion,0,1);
			data.readBytes(flags,0,1);

			total_size = (data.readByte() & 0x7F) * 0x200000 + (data.readByte() & 0x7F) * 0x400
						+ (data.readByte() & 0x7F) * 0x80 + (data.readByte() & 0x7F);
			
		}
		
		
		//返回整个标签体的大小
		public function getTotal_size():int{
			return total_size;
		}

	}

}
 
帧头   ID3V2Frameheader.as
 
package service
{
	import flash.utils.ByteArray;

	public class ID3V2Frameheader
	{

		private var frameId:ByteArray = new ByteArray;//数据帧标示       4
		private var frameSize:int;//数据帧体大小   4
		private var flags:ByteArray =  new ByteArray;//0        2
		
		public function ID3V2Frameheader(data:ByteArray)
		{
			// constructor code
			data.readBytes(frameId,0,4);
			frameSize = data.readByte()*0x1000000
			 +data.readByte()*0x10000
			 +data.readByte()*0x100
			 +data.readByte();
			data.readBytes(flags,0,2);
			
		}
		
		//返回数据帧表示
		public function getFrameId():String{
			return this.frameId.toString();
		}
		
		//返回这一帧的总共数据大小
		public function getFrameSize():int{
			return this.frameSize;
		}
		

	}

}
 
 
 

 

在这里简单说下mp3文件的首部,

1.首先是一个标签头(10个字节), 里面有一个重要的信息是可以通过计算得出标签体的大小

2.然后就是标签体,其中是出若干的帧组成,帧又是由帧头(10个字节),帧体组成(大小不定)

3.帧头中主要有帧标识(APIC,TIT2等等),帧体的大小(可计算大小)

 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
分享到:
评论

相关推荐

    mp3 id3tag 解析源码

    mp3 id3 tag解析 可获得文件内封面图片,演唱者,歌曲名称等信息

    360云网盘直连解析 v1.0

    功能: 1、把360云网盘下载链接转化为直连。 2、如果资源是多媒体,可直接...5、点击播放复制,如果是 .mp3或者.mp4或者.flv后缀的话,会直接显示播放测试,如果不是这几个后缀的话,会直接复制解析地址倒剪贴板。

    威盘音乐外链 1.8

    增加 bd.php 百度网盘MP3外链解析文件,只支持解析MP3外链,如需要全能解析请联系! 程序目前支持mp3、wma格式上传,其他格式上传不了,如需修改,请在ok.php内修改: if(($Type!="mp3")&&($Type!="wma")) 这个要...

    C#开发实例大全(基础卷).软件开发技术联盟(带详细书签) PDF 下载

    实例043 从字符串中分离文件路径、文件名及 扩展名 55 实例044 获取字符串中汉字的个数 57 实例045 批量替换某一类字符串 58 实例046 对字符串进行加密与解密 59 3.3 常用数字处理技术 61 实例047 判断输入的货币值...

    PHP文件下载实例代码浅析

    .mp4,MP3,图片等会被直接解析 核心代码 使用php代码控制文件的下载合适很简单的。我们住需要很少的代码便可以完成如此复杂的工作。 类型 // 使用basename函数可以获得文件的名称而不是路径信息,保护了服务器的...

    C#编程经验技巧宝典

    73 &lt;br&gt;0106 如何获得一个字符串中数字的长度 74 &lt;br&gt;0107 如何获得字符串中数字或字母的长度 74 &lt;br&gt;0108 如何获得字符串中某个数字的位置 75 &lt;br&gt;0109 获得字符串中汉字的个数 76 &lt;br&gt;0110...

    java源码包2

     这是个J2ME控制台程序,它能剔除PNG文件中的非关键数据段,减少文件大小从而达到压缩图片的目的。而图片的质量并不会受到损失。使用时候只需在控制台窗口执行jar就可以了。 Java 3DMenu 界面源码 5个目标文件 ...

    手机 pdf 阅读器

    由于在JAVA中无法获得当前的屏幕亮度,因此,当设置的屏幕亮度后,退出后无法恢复原来的设置 [以下问题求助] 在三星手机上,时间会走得比较快,由于没有真机,实在找不到问题所在 [2008.1.1] Ver:3.2.1 修正了阅读...

    JAVA上百实例源码以及开源项目

     这是个J2ME控制台程序,它能剔除PNG文件中的非关键数据段,减少文件大小从而达到压缩图片的目的。而图片的质量并不会受到损失。使用时候只需在控制台窗口执行jar就可以了。 Java 3DMenu 界面源码 5个目标文件 ...

    java源码包---java 源码 大量 实例

     这是个J2ME控制台程序,它能剔除PNG文件中的非关键数据段,减少文件大小从而达到压缩图片的目的。而图片的质量并不会受到损失。使用时候只需在控制台窗口执行jar就可以了。 Java 3DMenu 界面源码 5个目标文件 ...

    Visual C++程序开发范例宝典(光盘) 第四部分

    实例109 管理计算机内图片文件的程序 实例110 提取并保存应用程序图标 3.10 图片动画 实例111 利用图片制作屏幕保护程序 实例112 图片动画 3.11 简单游戏设计 实例113 拼图游戏 实例114 网络五子棋 实例115...

    Visual C++程序开发范例宝典(光盘) 第八部分

    实例109 管理计算机内图片文件的程序 实例110 提取并保存应用程序图标 3.10 图片动画 实例111 利用图片制作屏幕保护程序 实例112 图片动画 3.11 简单游戏设计 实例113 拼图游戏 实例114 网络五子棋 实例115...

    java源码包3

     这是个J2ME控制台程序,它能剔除PNG文件中的非关键数据段,减少文件大小从而达到压缩图片的目的。而图片的质量并不会受到损失。使用时候只需在控制台窗口执行jar就可以了。 Java 3DMenu 界面源码 5个目标文件 ...

    自己动手写搜索引擎(罗刚著).doc

    第3章 获得海量数据 22 3.1 自己的网络蜘蛛 22 3.1.1 BerkeleyDB介绍 27 3.1.2 抓取网页 28 3.1.3 MP3 抓取 29 3.1.4 RSS 抓取 30 3.1.5 图片抓取 33 3.1.6 垂直行业抓取 34 3.2 抓取数据库中的内容 36 3.2.1 建立...

    java源码包4

     这是个J2ME控制台程序,它能剔除PNG文件中的非关键数据段,减少文件大小从而达到压缩图片的目的。而图片的质量并不会受到损失。使用时候只需在控制台窗口执行jar就可以了。 Java 3DMenu 界面源码 5个目标文件 ...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    J2ME优化压缩PNG文件 4个目标文件 内容索引:JAVA源码,综合应用,J2me游戏,PNG,图形处理 这是个J2ME控制台程序,它能剔除PNG文件中的非关键数据段,减少文件大小从而达到压缩图片的目的。而图片的质量并不会受到损失...

    JAVA上百实例源码以及开源项目源代码

     这是个J2ME控制台程序,它能剔除PNG文件中的非关键数据段,减少文件大小从而达到压缩图片的目的。而图片的质量并不会受到损失。使用时候只需在控制台窗口执行jar就可以了。 Java 3DMenu 界面源码 5个目标文件 ...

Global site tag (gtag.js) - Google Analytics