精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-08-17
最后修改:2010-10-07
文件以字节为单位读取,MP3解码器输入的数据是位流,即每次需要读取几比特,这就需要将字节流转换为比特流。解码器将文件按每次读取几比特将一个文件处理完,所以读取位流的方法以很高的频度被调用。也就是说,MP3文件是通过本类的方法每次将几比特送入解码器,从机而把一个文件解码完的。解码器的功能就是将送入的位流解码成PCM数据,然后由音频处理模块将PCM数据送入音频硬件播放。
设置缓冲区(位流蓄水池)bitReservoir,解码器的其它模块在需要的时候通过调用append(int len)方法 从文件读取len字节 放进bitReservoir,仅当文件读完时append方法返回值为-1。暂存缓冲区中已经读取的比特、字节位置、剩下的字节数等。MP3解码过程中每次最少读入1位,最多读入17位,为了提高读取位流的效率,本类中共提供了3个读取位流的方法:get1Bit()、getBits9(int n)、getBits17(int n),读取的比特数n越小,方法体内执行的操作也就越少,根据每次要读取的比特数分别调用相应的方法。当然,如果要从位流缓冲区读取2位,调用getBits17(2)也是可以返回正确的值的,但getBits17(int n)方法体内要执行的操作要多一些,导致程序效率要低一些。
JAVA没有象C语言的unsigned int那样的无符号整数类型,所以本类的方法中多处出现类似于iret &= 0xffff这样的语句来取32位int类型整数中的低位,确保每次从位流缓冲区读入的一字节是一个0~255的正整数,因为位流缓冲区bitReservoir是byte数组,byte类型的取值范围是-128~+127。例如int iret=bitReservoir[bytePos],假如bitReservoir[bytePos]值为10进制-9,用2进制表示的这个byte类型的值为11110111,赋给int类型的iret将byte转换为int类型,32位长iret的10进制值仍为-9,但用2进制表示为11111111111111111111111111110111,高24位全为1;若将该语句写成int iret=bitReservoir[bytePos] & 0xFF,则iret的值用2进制表示为00000000000000000000000011110111,这才是正确的结果。还需要特别指出的是本类中的get1Byte()方法不是用来读取8比特用的,除非缓冲区bitReservoir已经是字节对齐的,即intBitPos=0才行,也就是说读8bit不等同于读1byte。get1Byte()方法的使用见哈夫曼解码模块,相对于解码帧边信息、解码增益因子而言,哈夫曼解码需要读取的比特数多,故采用了更为高效的字节对齐的、用一个32位的int变量来“2级缓冲”的方法。
后 续的解码模块共实例化了2个BitStream对象,一个是供解码帧边信息用,每次调用append(int len)方法向bitReservoir添加不超过32字节;另一个供解码主信息(主信息又可细分为增益因子、用哈夫曼编码的主数据两部分),每次向bitReservoir添加的字节数不超过1732。
BitStream的成员变量iraInput为IRandomAcces类型,既可用于读取本地磁盘文件,也可用于读取网络文件;申明为static类型,使2个BitStream实例由同一文件向缓冲区bitReservoir填充数据。
位流读取比较简单,效率是关键。BitStream.java源码: /* * BitStream.java -- 读取位流 * Copyright (C) 2010 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * If you would like to negotiate alternate licensing terms, you may do * so by contacting the author: <http://jmp123.sourceforge.net/> */ package jmp123.decoder; import jmp123.instream.IRandomAccess; public final class BitStream { private static final int RESELEN = 4096; private static IRandomAccess iraInput; private byte[] bitReservoir; private int bitPos; private int bytePos; private int endPos; //bitReservoir已填入的字节数 public BitStream(IRandomAccess iraIn) { iraInput = iraIn; bitReservoir = new byte[RESELEN + 4]; // 长度不小于512+1732(最大帧长) } public BitStream(int len) { bitReservoir = new byte[len]; // 任意长度,用于帧边信息解码 } /** * 向bitReservoir添加len字节,RESELEN后尾部要空出4字节用于32bit的"2级缓冲". */ public int append(int len) { if (len + endPos > RESELEN) { //将缓冲区bytePos及之后的字节移动到缓冲区首 System.arraycopy(bitReservoir, bytePos, bitReservoir, 0, endPos - bytePos); endPos -= bytePos; bitPos = bytePos = 0; } try { if(iraInput.read(bitReservoir, endPos, len) < len) return -1; } catch (Exception e) { return -1; } endPos += len; return len; } public void resetIndex() { bytePos = bitPos = endPos = 0; } /** * 从缓冲区bitReservoir读取1 bit */ public int get1Bit() { int bit = bitReservoir[bytePos] << bitPos; bit >>= 7; bit &= 0x1; bitPos++; bytePos += bitPos >> 3; bitPos &= 0x7; return bit; } /* * 2 <= n <= 17 */ public int getBits17(int n) { int iret = bitReservoir[bytePos]; iret <<= 8; iret |= bitReservoir[bytePos + 1] & 0xff; iret <<= 8; iret |= bitReservoir[bytePos + 2] & 0xff; iret <<= bitPos; iret &= 0xffffff; // 高8位置0; iret >>= 24 - n; bitPos += n; bytePos += bitPos >> 3; bitPos &= 0x7; return iret; } /** * 2<= n <= 9 */ public int getBits9(int n) { int iret = bitReservoir[bytePos]; iret <<= 8; iret |= bitReservoir[bytePos + 1] & 0xff; iret <<= bitPos; iret &= 0xffff; // 高16位置0; iret >>= 16 - n; bitPos += n; bytePos += bitPos >> 3; bitPos &= 0x7; return iret; } public int getBytePos() { return bytePos; } public int getBuffBytes() { return endPos; } public int getBitPos() { return bitPos; } /** * 返回值是0-255的无符号整数 */ public int get1Byte() { return bitReservoir[bytePos++] & 0xff; } public void backBits(int n) { bitPos -= n; bytePos += bitPos >> 3; bitPos &= 0x7; } public void skipBytes(int nbytes) { bytePos += nbytes; bitPos = 0; } }
【本程序下载地址】http://jmp123.sourceforge.net/ 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
浏览 6361 次