与上一篇写的一样,参考的都是一样的资料
参考的资料:
http://duyouhua1214.iteye.com/blog/1326238
这仍然也是操作的是字节,所以其他语言都是适用的。
mp3文件的首尾都存有文件的信息,存在尾部的称为ID3V1,在首部的称为 ID3V2。专辑图片是存放在部的ID3V2。所以这里解析ID3v2
主要的知识点,都是资料中的:
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; } } }
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; } } }
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等等),帧体的大小(可计算大小)