美文网首页
音频WMA格式中ID3、专辑图的解析,Java实现

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

作者: QHR168 | 来源:发表于2017-04-11 16:31 被阅读0次

    需要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;

    }

    }

    相关文章

      网友评论

          本文标题:音频WMA格式中ID3、专辑图的解析,Java实现

          本文链接:https://www.haomeiwen.com/subject/bebyattx.html