音频WMA格式中ID3、专辑图的解析,Java实现

2017-04-11  本文已影响0人  QHR168

需要WMA格式的TAG信息,整理了一下,在这里与大家分享一下。参考转自:http://blog.csdn.net/werocpp/article/details/5594067。

首先介绍下WMA文件头的结构,如下图

/*************************************************************************

// 分为文件头和各个帧数据(文件头前16个字节WMA格式是固定的,8个字节的大小是高位存在后面,以后遇到大小都是高位存在后面)

+--------------------------------------------------------------+

|      Header (30 bytes)   HeadFlag:16; HeadSize:8; Unknow:6   |

+--------------------------------------------------------------+

|      Frames (1....n)                                         |

+--------------------------------------------------------------+

// 所有的TAG信息存放在标准帧和扩展帧中,其他帧可以不予考虑,标准帧以及扩展帧的16个字节标识头都是固定的

// 所有的信息都是UNICODE编码

// 标准帧结构

+--------------------------------------------------------------+

|      Header (24 bytes)   HeadFlag:16; HeadSize:8;            |

+--------------------------------------------------------------+

|      标题信息大小(2 bytes)                                  |

+--------------------------------------------------------------+

|      艺术家信息大小(2 bytes)                                |

+--------------------------------------------------------------+

|      版权信息大小(2 bytes)                                  |

+--------------------------------------------------------------+

|      备注信息大小(2 bytes)                                  |

+--------------------------------------------------------------+

|      未知信息大小(2 bytes)                                  |

+--------------------------------------------------------------+

|      标题信息内容(0x00 0x00结束)                              |

+--------------------------------------------------------------+

|      艺术家信息内容(0x00 0x00结束)                            |

+--------------------------------------------------------------+

|      版权信息内容(0x00 0x00结束)                              |

+--------------------------------------------------------------+

|      备注信息内容(0x00 0x00结束)                              |

+--------------------------------------------------------------+

|      未知信息内容(0x00 0x00结束)                              |

+--------------------------------------------------------------+

// 扩展帧结构

+--------------------------------------------------------------+

|      Header (24 bytes)   HeadFlag:16; HeadSize:8;            |

+--------------------------------------------------------------+

|      扩展信息个数EXNO(2 bytes)                              |

+--------------------------------------------------------------+

|      EXINFO (1....EXNO)                                      |

+--------------------------------------------------------------+

// 每个扩展信息EXINFO结构

+--------------------------------------------------------------+

|      EXINFO NAME Size (2 bytes)   扩展信息名字大小            |

+--------------------------------------------------------------+

|      扩展信息名称                                             |

+--------------------------------------------------------------+

|      标志FLAG   (2 bytes)                                    |

+--------------------------------------------------------------+

|      值的大小   (2 bytes)                                     |

+--------------------------------------------------------------+

|      实际的值   (若是图片格式参考ID3V2.3)                         |

+--------------------------------------------------------------+

当扩展信息名字为WMFSDKVersion时,这个值表示的是这个WMA文件的版本;

当扩展信息名字为WM/AlbumTitle时,这个值代表的就是专辑名;

当扩展信息名字为WM/Genre时,这个值代表的就是流派;

下面再来看看那个标志Flag,这个基本上是为没什么用的(通常值为0),

对WM/TrackNumber和WM/Track这两个扩展信息名字有用,

当Flag为3的时候后面的值(也就是曲目信息)是以4个字节的整数的形式表示,

当Flag为0的时候,曲目信息是以普通的字符串形式表示的。

// 查看http://msdn.microsoft.com/en-us/library/ms867702.aspx

Java代码:

public classWmaReadId3 {

private static finalStringTAG="id3";

private int[]header= {0x30,0x26,0xB2,0x75,0x8e,0x66,0xCF,0x11,0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,

0x6C};

private int[]WMA_STANDTAG= {0x33,0x26,0xB2,0x75,0x8E,0x66,0xCF,0x11,0xA6,0xD9,0x00,0xAA,0x00,0x62,

0xCE,0x6C};// 标准帧

private int[]WMA_EXTAG= {0x40,0xA4,0xD0,0xD2,0x07,0xE3,0xD2,0x11,0x97,0xF0,0x00,0xA0,0xC9,0x5E,

0xA8,0x50};// 扩展帧

private int[]ALBUM= {0x57,0x00,0x4d,0x00,0x41,0x00,0x6c,0x00,0x62,0x00,0x75,0x00,0x6d,0x00,0x54,

0x00,0x69,0x00,0x74,0x00,0x6c,0x00,0x65,0x00};

private int[]YEAR= {0x57,0x00,0x4d,0x00,0x59,0x00,0x65,0x00,0x61,0x00,0x72,0x00};

private int[]APIC_TAG= {0x69,0x00,0x6D,0x00,0x61,0x00,0x67,0x00,0x65,0x00,0x2F,0x00,0x6A,0x00,0x70,

0x00,0x65,0x00,0x67,0x00,0x00,0x00,0x00,0x00};

privateInputStreammp3ips;

publicStringcharset="UTF-8";// 预设编码为GBK

privateId3v2Infoinfo;

publicWmaReadId3(InputStream inputStream) {

this.mp3ips= inputStream;

info=newId3v2Info();

}

publicId3v2InforeadId3() {

if(mp3ips!=null) {

try{

intreslen =mp3ips.available();// 获取字节总长

mp3ips.skip(0);

byte[] wmadata =new byte[16];

mp3ips.read(wmadata);

booleanisWmaFile = compareArrays(wmadata,header);

if(!isWmaFile) {

returninfo;

}

byte[] hDataSize =new byte[8];

mp3ips.read(hDataSize);

intheadSize =0;

for(inti =0;i < hDataSize.length;i++) {

headSize |= (((int) hDataSize[i] &0xff) << (8* i));

}

mp3ips.skip(6);

intoffset =30;// 偏移量

while(offset < headSize) {

byte[] tagHead =new byte[16];// 帧头

mp3ips.read(tagHead);

offset += tagHead.length;

byte[] tagSize =new byte[8];// 帧长度

mp3ips.read(tagSize);

offset += tagSize.length;

intframeSize =0;

for(inti =0;i < tagSize.length;i++) {

frameSize |= (((int) tagSize[i] &0xff) << (8* i));

}

if(compareArrays(tagHead,WMA_STANDTAG)) {// 是标准帧头

byte[] tmpbuf =new byte[10];

mp3ips.read(tmpbuf);

int[] Tagsize =new int[5];

for(inti =0;i <5;i++) {

Tagsize[i] = (((int) tmpbuf[i *2] &0xff) | ((int) tmpbuf[i *2+1] &0xff) <<8);

}

// read 5 tag.

for(inti =0;i <5;i++) {

if(Tagsize[i] >0) {

byte[] tempData =new byte[Tagsize[i]];

mp3ips.read(tempData);

offset += tempData.length;

switch(i) {

case0:// Title

String title = Byte2Unicode(tempData);

info.setTit2(title);

break;

case1:// Artist

String artist = Byte2Unicode(tempData);

info.setTpe1(artist);

break;

}

}

}

}else if(compareArrays(tagHead,WMA_EXTAG)) {// 是扩展帧头

byte[] extSize =new byte[2];

mp3ips.read(extSize);

offset += extSize.length;

intexTagNum =0;

for(inti =0;i < extSize.length;i++) {

exTagNum |= (((int) extSize[i] &0xff) << (8* i));

}

for(inti =0;i < exTagNum;i++) {

byte[] size1Date =new byte[2];

mp3ips.read(size1Date);

offset += size1Date.length;

intsize1 =0;

for(intj =0;j < size1Date.length;j++) {

size1 |= (((int) size1Date[j] &0xff) << (8* j));

}

byte[] extTagName =new byte[size1];// 扩展信息名

mp3ips.read(extTagName);

offset += extTagName.length;

String name =newString(removeZero(extTagName));//Byte2Unicode(extTagName);

byte[] flagData =new byte[2];

mp3ips.read(flagData);

offset += flagData.length;

intflag =0;

for(intj =0;j < flagData.length;j++) {

flag |= (((int) flagData[j] &0xff) << (8* j));

}

byte[] exValueSizeData =new byte[2];

mp3ips.read(exValueSizeData);

offset += exValueSizeData.length;

intexValueSize =0;

for(intj =0;j < exValueSizeData.length;j++) {

exValueSize |= (((int) exValueSizeData[j] &0xff) << (8* j));

}

if(flag !=3) {

byte[] exValueData =new byte[exValueSize];

mp3ips.read(exValueData);

offset += exValueData.length;

if("WM/AlbumTitle".equals(name)) {

String album = Byte2Unicode(exValueData);

info.setTalb(album);

}else if("WM/AlbumArtist".equals(name)) {

String artist = Byte2Unicode(exValueData);

info.setTpe1(artist);

}else if("WM/Picture".equals(name)) {// 专辑图

LogUtils.d(TAG,"----专辑图----");

byte[] apicTag =new byte[APIC_TAG.length];

System.arraycopy(exValueData,5,apicTag,0,apicTag.length);

if(compareArrays(apicTag,APIC_TAG)) {

byte[] imgData =new byte[exValueData.length-5- apicTag.length];

System.arraycopy(exValueData,5+ apicTag.length,imgData,0,imgData.length);

info.setApic(imgData);

}

}

}else{

mp3ips.skip(4);

offset +=4;

}

}

}else{

mp3ips.skip(frameSize -16-8);

offset += (frameSize -16-8);

}

}

}catch(IOException e) {

e.printStackTrace();

}

}

returninfo;

}

// for (int j = 0; j < extTagName.length; j++) {

// String temp = Integer.toHexString(extTagName[j] &

// 0xff);

// if (temp.length() == 1) {

// temp = "0" + temp;

// }

// LogUtils.d(TAG, "扩展信息名 extTagName[" + j + "]:" +

// temp);

// }

public voidsetInfo(Id3v2Info info) {

this.info= info;

}

publicId3v2InfogetInfo() {

returninfo;

}

publicStringgetName() {

returngetInfo().getTit2();

}

publicStringgetAuthor() {

returngetInfo().getTpe1();

}

publicStringgetSpecial() {

returngetInfo().getTalb();

}

public byte[]getImg() {

returngetInfo().getApic();

}

public booleancompareArrays(byte[] data1, int[] data2) {

if(data1.length== data2.length) {

for(inti =0;i < data2.length;i++) {

if((data1[i] &0xff) != (data2[i] &0xff)) {

return false;

}

}

return true;

}else{

return false;

}

}

public byte[]removeZero(byte[] a) {

intj =0;

// 这个for循环计算出你传入的这个数组去掉0后的长度

for(inti =0;i < a.length;i++) {

if(a[i] !=0) {

j++;

}

}

// 定义数组的长度

byte[] newarr =new byte[j];

j =0;

// 将不为零的copy到新数组中去

for(inti =0;i < a.length;i++) {

if(a[i] !=0) {

newarr[j] = a[i];

j++;

}

}

returnnewarr;

}

publicStringByte2Unicode(byteabyte[], intst, intbEnd)// 不包含bEnd

{

StringBuffer sb =newStringBuffer("");

for(intj = st;j < bEnd;) {

intlw = abyte[j++];

if(lw <0)

lw +=256;

inthi = abyte[j++];

if(hi <0)

hi +=256;

charc = (char) (lw + (hi <<8));

sb.append(c);

}

returnsb.toString();

}

publicStringByte2Unicode(byteabyte[], intlen) {

returnByte2Unicode(abyte,0,len);

}

publicStringByte2Unicode(byteabyte[]) {

returnByte2Unicode(abyte,0,abyte.length);

}

public byte[]Unicode2Byte(String s) {

intlen = s.length();

byteabyte[] =new byte[len <<1];

intj =0;

for(inti =0;i < len;i++) {

charc = s.charAt(i);

abyte[j++] = (byte) (c &0xff);

abyte[j++] = (byte) (c >>8);

}

returnabyte;

}

}

上一篇下一篇

猜你喜欢

热点阅读