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

(七)用JAVA编写MP3解码器——解码帧边信息

阅读更多

解码一帧Layer3第1步:帧边信息解码 -- getSideInfo()方法

 

      帧边信息用于描述一帧内的主信息(增益因子和主数据)特征,而后文讲到的解码的增益因子、主数据是描述一个声道的,换一种说法,帧边信息每帧连续存储在一处,增益因子和主数据(可能多达各4个)分散存储在每帧数据中的2处(MPEG 1.0的单声道/MPEG 2.0/2.5的2声道)或4处(MPEG 1.0的2个声道)。弄明白了这一点区别,就很容易弄明白后文中讲到的Layer3的decodeFrame方法的流程。

 

  解码帧边信息先实例化一个BitStream对象bsSI,bsSI已经在Layer3的构造方法中初始化。从上一讲的帧数据结构示意图可以看出,对某一帧的帧头、帧边信息解码后,这些位流数据在后续过程中就不再被使用,而当前帧的主信息有可能是下一帧的,即解码下一帧才用到到,所以需要暂存起来。要将帧边信息读入到36字节长度的缓冲区内;主信息暂存在长度不低于1732+512字节的另一缓冲区内,这里的512是何来历?请看源代码中的objSI.main_data_begin = bsSI.getBits9(9)这一行就明白了,main_data_begin值的单位为字节

 

      帧边信息的解码结果暂存到SideInfo类型变量objSI中,供后续步骤使用。在前面的帧子中,先后有好几人说到我的代码中变量命名不合JAVA规范,代码中(比如class SideInfo的成员)变量名基本上采用了手册描述MP3解码规范里的名称或简写,尽量做到“见名知义”,比如part2_3_length就是指一个声道内增益因子(part2)和主数据(part3)的比特数;part1在哪?你说呢~~

 

      class SideInfo内定义的成员变量表示的具体含义在手册中查得到,不再赘述,解码帧边信息的流程特简单,从源码很容易看懂帧边信息的结构。要把这些成员变量的含义、作用阐述清楚并非易事,没几千字下不来,其中个别变量在后续的过程中使用到这些变量的值时会讲解到。从这儿的源代码也可以看出MPEG 1.0版和2.0/2.5版帧数据的不同之处:

  • 标准立体声编码的MPEG 1.0的粒度组为2,解码得到的PCM样本值个数为2304;而MPEG 2.0/2.5的粒度组为1,解码得到的PCM样本值个数为1157。这将导致解码一帧不同版的MPEG Audio向音频硬件写入的PCM数据长度不同。
  • MPEG 1.0的两个粒度组(每个粒度组内1或2个声道)的增益因子可能共用,如果两个粒度组的增益因子值是相同的,就不用分别存储两份,这样可以提高帧数据的存储效率。是否共用由帧边信息的第6..9比特(2个声道)或4..7比特(单声道)每一比特的值是否为1给出,这个值暂存在SideInfo的scfsi变量中;MPEG 2.0/2.5只有一个粒度组,就不存在共用的问题了。“共用”导致解码增益因子的代码比较复杂。
  • 正是由于MPEG1.0和2.0/2.5粒度组的不同,为SideInfo中与增益因子相关的变量(取名为scalefacxxx)赋值时从位流中取得的比特数不同。
  • 为class SideInfo内其它变量赋值时从位流中取得的比特数MPEG 1.0/2.0/2.5都是相同的。

      class Layer3内的getSideInfo()方法的源码如下:

	//1.
	//>>>>SIDE INFORMATION=====================================================
	private static SideInfo objSI;
	private BitStream bsSI;	// 读帧边信息位流

	private boolean getSideInfo()  throws Exception {
		int ch, gr, i;
		bsSI.resetIndex();
		i = objHeader.getSideInfoSize();
		if(bsSI.append(i) < i)
			return false;
		Layer3.GRInfo gri;

		if (isMPEG1) {
			objSI.main_data_begin = bsSI.getBits9(9);
			if (intChannels == 1)
				bsSI.getBits9(5);	//private_bits
			else
				bsSI.getBits9(3);	//private_bits

			int[] scfsi;
			for (ch = 0; ch < intChannels; ch++) {
				scfsi = objSI.ch[ch].scfsi;
				scfsi[0] = bsSI.get1Bit();
				scfsi[1] = bsSI.get1Bit();
				scfsi[2] = bsSI.get1Bit();
				scfsi[3] = bsSI.get1Bit();
			}

			for (gr = 0; gr < 2; gr++) {
				for (ch = 0; ch < intChannels; ch++) {
					gri = objSI.ch[ch].gr[gr];
					gri.part2_3_length = bsSI.getBits17(12);
					gri.big_values = bsSI.getBits9(9);
					gri.global_gain = bsSI.getBits9(8);
					gri.scalefac_compress = bsSI.getBits9(4);
					gri.window_switching_flag = bsSI.get1Bit();
					if ((gri.window_switching_flag) != 0) {
						gri.block_type = bsSI.getBits9(2);
						gri.mixed_block_flag = bsSI.get1Bit();
						gri.table_select[0] = bsSI.getBits9(5);
						gri.table_select[1] = bsSI.getBits9(5);
						gri.subblock_gain[0] = bsSI.getBits9(3);
						gri.subblock_gain[1] = bsSI.getBits9(3);
						gri.subblock_gain[2] = bsSI.getBits9(3);
						if (gri.block_type == 0)
							return false;
						else if (gri.block_type == 2 && gri.mixed_block_flag == 0)
							gri.region0_count = 8;
						else
							gri.region0_count = 7;
						gri.region1_count = 20 - gri.region0_count;
					} else {
						gri.table_select[0] = bsSI.getBits9(5);
						gri.table_select[1] = bsSI.getBits9(5);
						gri.table_select[2] = bsSI.getBits9(5);
						gri.region0_count = bsSI.getBits9(4);
						gri.region1_count = bsSI.getBits9(3);
						gri.block_type = 0;
					}
					gri.preflag = bsSI.get1Bit();
					gri.scalefac_scale = bsSI.get1Bit();
					gri.count1table_select = bsSI.get1Bit();
				}
			}
		} else {
			// MPEG 2.0/2.5
			objSI.main_data_begin = bsSI.getBits9(8);
			if (intChannels == 1)
				bsSI.get1Bit();
			else
				bsSI.getBits9(2);
			for (ch = 0; ch < intChannels; ch++) {
				gri = objSI.ch[ch].gr[0];
				gri.part2_3_length = bsSI.getBits17(12);
				gri.big_values = bsSI.getBits9(9);
				gri.global_gain = bsSI.getBits9(8);
				gri.scalefac_compress = bsSI.getBits9(9);
				gri.window_switching_flag = bsSI.get1Bit();
				if ((gri.window_switching_flag) != 0) {
					gri.block_type = bsSI.getBits9(2);
					gri.mixed_block_flag = bsSI.get1Bit();
					gri.table_select[0] = bsSI.getBits9(5);
					gri.table_select[1] = bsSI.getBits9(5);
					gri.subblock_gain[0] = bsSI.getBits9(3);
					gri.subblock_gain[1] = bsSI.getBits9(3);
					gri.subblock_gain[2] = bsSI.getBits9(3);
					if (gri.block_type == 0)
						return false;
					else if (gri.block_type == 2 && gri.mixed_block_flag == 0)
						gri.region0_count = 8;
					else {
						gri.region0_count = 7;
						gri.region1_count = 20 - gri.region0_count;
					}
				} else {
					gri.table_select[0] = bsSI.getBits9(5);
					gri.table_select[1] = bsSI.getBits9(5);
					gri.table_select[2] = bsSI.getBits9(5);
					gri.region0_count = bsSI.getBits9(4);
					gri.region1_count = bsSI.getBits9(3);
					gri.block_type = 0;
					gri.mixed_block_flag = 0;
				}
				gri.scalefac_scale = bsSI.get1Bit();
				gri.count1table_select = bsSI.get1Bit();
			}
		}

		return true;
	}
	//<<<<SIDE INFORMATION=====================================================

 

 

上一篇:(六)用JAVA编写MP3解码器——帧数据结构

下一篇:(八)用JAVA编写MP3解码器——解码增益因子

 

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

分享到:
评论

相关推荐

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

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

    java源码包4

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

    java源码包2

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

    java源码包3

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

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

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

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

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

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

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

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

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

    java实现收发邮件源码-awesome-go:令人惊叹的Go库、资源和闪亮事物的精选列表

    java实现邮件邮件源码真棒去 一个非常棒的 Go 库、资源和闪亮事物的精选列表。 贡献 如果您在此处看到不再维护或不适合的包或项目,请提交拉取请求以改进此文件。 谢谢! 内容 音频和音乐 用于处理音频的库。 名称 ...

    java实现收发邮件源码-awesome-go:avelino/awesome-go的每日克隆,包含来自go-search的信息

    java实现邮件邮件源码扩展真棒围棋 每日克隆与来自 . :down_arrow: - 导入此包的包数 :star: - 星星数 真棒去 精选的 Go 框架、库和软件的精选列表。 灵感来自 . 贡献 请先快速看一下。 谢谢大家 ; 你摇滚! 如果您...

    百度翻译源码java-my-awesome-starred:我的真棒明星

    解码器和编码器 - 树莓派的Buildroot开发环境 - 操作系统项目 4 - 支持多种 GSS 方法的 nfs-utils - 操作系统项目 4 - 公共 libevent 存储库。 官方存储库位于 - ØMQ的高级C绑定 C# —— C++ - 使用数据流图进行可...

    ringo-evented:基于 Java Netty 项目的 RingoJS 事件库

    它建立在优秀的项目之上,该项目提供了可靠的 NIO 客户端/服务器 Java 框架和用于处理网络协议的一系列令人印象深刻的编解码器。 此时ringo-evented处于非常 pre-alpha 的状态,API 应该被认为是高度不稳定的。 我...

    Android程序设计基础

    Android内置了最常用的行业标准音频和视频格式的编解码器,这些格式包括H.264 (AVC)、MP3和AAC。  当前及未来各类硬件间的可移植性。所有程序都是用Java语言编写的,并且将由Android的Dalvik虚拟机执行,所以代码...

    android系统原理及开发要点详解

     第2章“Android系统开发综述”,介绍Android系统开发的综述性内容,包括工具使用、获得代码、编译系统、仿真器运行、SDK使用等。  第3章“Android的Linux内核与驱动程序”,介绍Android内核的特点、Android中使用...

Global site tag (gtag.js) - Google Analytics