`
lfp001
  • 浏览: 100707 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

(三)用JAVA编写MP3解码器——读取位流

阅读更多

  文件以字节为单位读取,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;
	}
}

 

上一篇:(二)用JAVA编写MP3解码器——帧头信息解码

下一篇:(四)用JAVA编写MP3解码器——读取文件

 

【本程序下载地址】http://jmp123.sourceforge.net/

分享到:
评论

相关推荐

    JAVA读取文件——以行为单位读取

    本篇将深入探讨如何使用Java进行逐行读取TXT文件,并提供相关示例代码。 首先,我们需要了解Java中的几个关键类,它们在文件读取过程中扮演着重要角色: 1. `File` 类:代表文件或目录的路径名。可以创建、重命名...

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

     用JAVA编写了一个小工具,用于检测当前显示器也就是显卡的显示模式,比如分辨率,色彩以及刷新频率等。 Java波浪文字制作方法及源代码 1个目标文件 摘要:Java源码,初学实例,波浪文字  Java波浪文字,一个利用...

    基于jmp123解码器的mp3播放器.zip

    这个压缩包文件的标题揭示了它的核心内容——一个使用jmp123解码器的MP3播放器项目。jmp123是一个开源的、用C语言编写的MP3解码库,它能够解析并解码MP3音频文件,将压缩的数字音频数据转化为可以播放的格式。这个...

    Java课程设计——电子音乐盒

    【Java课程设计——电子音乐盒】是一个以Java技术为基础,利用Java Media Framework(JMF)开发的音乐播放软件。这个项目旨在让学生掌握Java编程语言在多媒体应用中的实践,特别是音频处理和用户界面设计方面的能力...

    音乐播放器——湘潭大学JAVA课程设计题目

    开发者需要了解如何加载音频文件,如MP3或WAV,然后使用AudioInputStream和Clip类来解码和播放音频流。 3. **进度条显示**:进度条用于显示当前音乐的播放进度。这涉及到监听音乐播放状态,通过获取音乐总时长和...

    java IO流学习笔记——(3)字节缓冲流&字符缓冲流&转换流&数据流

    Java IO流是Java平台中处理输入输出操作的重要组成部分,它提供了丰富的类库来高效地读写数据。在Java中,IO流分为字节流和字符流两大类,每类又...理解并熟练掌握这些流的使用,对于编写高效的Java I/O程序至关重要。

    java源码包3

     用JAVA编写了一个小工具,用于检测当前显示器也就是显卡的显示模式,比如分辨率,色彩以及刷新频率等。 Java波浪文字制作方法及源代码 1个目标文件 摘要:Java源码,初学实例,波浪文字  Java波浪文字,一个利用...

    java源码包2

     用JAVA编写了一个小工具,用于检测当前显示器也就是显卡的显示模式,比如分辨率,色彩以及刷新频率等。 Java波浪文字制作方法及源代码 1个目标文件 摘要:Java源码,初学实例,波浪文字  Java波浪文字,一个利用...

    jmp123_400_utf8_mini:JAVA开源程序,包含MP3解码器库和播放器

    学习这个开源项目,我们可以了解到JAVA如何处理音频数据,包括如何读取MP3文件、如何解码音频流、如何使用JAVA Sound API进行播放等技术。同时,通过阅读源代码,我们可以看到如何组织和优化音频处理的算法,以及...

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

    Java编写的显示器显示模式检测程序 2个目标文件 内容索引:JAVA源码,系统相关,系统信息检测 用JAVA编写了一个小工具,用于检测当前显示器也就是显卡的显示模式,比如分辨率,色彩以及刷新频率等。 Java波浪文字制作...

    java源码包4

     用JAVA编写了一个小工具,用于检测当前显示器也就是显卡的显示模式,比如分辨率,色彩以及刷新频率等。 Java波浪文字制作方法及源代码 1个目标文件 摘要:Java源码,初学实例,波浪文字  Java波浪文字,一个利用...

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

    Java编写的显示器显示模式检测程序 2个目标文件 内容索引:JAVA源码,系统相关,系统信息检测 用JAVA编写了一个小工具,用于检测当前显示器也就是显卡的显示模式,比如分辨率,色彩以及刷新频率等。 Java波浪文字制作...

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

    Java编写的显示器显示模式检测程序 2个目标文件 内容索引:JAVA源码,系统相关,系统信息检测 用JAVA编写了一个小工具,用于检测当前显示器也就是显卡的显示模式,比如分辨率,色彩以及刷新频率等。 Java波浪文字制作...

    安卓Android源码——基于SDL、FFmpeg的播放器源码.zip

    FFmpeg的JNI接口会被用来在Java层调用C/C++编写的解码器,这样可以充分利用CPU的性能并降低内存消耗。 4. **Android多媒体框架**: Android系统本身提供了一个多媒体框架,包括MediaPlayer类,它可以播放本地和网络...

    安卓Android源码——FFMpeg.rar

    使用硬件加速可以提升解码速度,但需要检查设备是否支持相应的编码器或解码器。 这个压缩包中的源码示例可能涵盖了如何在 Android 上构建 FFmpeg,如何初始化和使用 FFmpeg API,以及如何处理 Android 中特有的问题...

    一个基于matlab的简单二维码解码程序Decoder.rar

    该项目用Java编写,但通过Java绑定,也可以在其他编程语言,如MATLAB中使用。 MATLAB是一个强大的数学计算和数据分析环境,但其原生功能并不包括二维码的处理。在MATLAB中调用ZXing解码二维码,需要进行一些额外的...

    JAVA二维码jar包与例子

    Java二维码(JAVA二维码)是一种广泛应用于移动设备和网络服务中的数据编码技术,它将大量信息如网址、文本、名片等编码成一个二维图形——二维码,然后通过扫描来快速读取和解析这些信息。在Java中处理二维码,通常...

    JAVA的相关

    它以其“一次编写,到处运行”(Write Once, Run Anywhere, WORA)的特性而闻名,因为Java程序可以在支持Java虚拟机(JVM)的任何平台上运行。在本文中,我们将关注基于Java的音乐播放器——JMPlayer的开发。 1. **...

    java_ttplayer_src.rar_java 酒店管理系统_java 播放_界面_音乐播放器

    首先,我们要了解Java在GUI(图形用户界面)设计中使用的核心库——Java Swing或JavaFX。在这个音乐播放器项目中,Swing很可能被用来创建界面元素,如按钮、播放/暂停控件、音量调节滑块等。Swing提供了丰富的组件库...

    2010-2014java上机真题 北大计算机应用专业(自考

    8. 格式化输出与输入:在文本编辑器的实现中,需要支持格式化文档的保存和读取,可能涉及到不同文件格式(如txt、bin)的编码和解码。 9. UI设计原则:设计简单易用的资源浏览器和文本编辑器时,需要遵循良好的用户...

Global site tag (gtag.js) - Google Analytics