解码一帧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=====================================================
【本程序下载地址】http://jmp123.sourceforge.net/
相关推荐
这个压缩包文件的标题揭示了它的核心内容——一个使用jmp123解码器的MP3播放器项目。jmp123是一个开源的、用C语言编写的MP3解码库,它能够解析并解码MP3音频文件,将压缩的数字音频数据转化为可以播放的格式。这个...
综上所述,"jmpg123.tar.gz_jmpg1_jmpg123_mp1_mp2_mp3 解码"涉及到的是用Java编写的MP1、MP2和MP3音频解码器的源代码,其在多媒体处理领域有广泛应用前景,同时也展示了Java在实现跨平台音频处理上的能力。...
用JAVA编写了一个小工具,用于检测当前显示器也就是显卡的显示模式,比如分辨率,色彩以及刷新频率等。 Java波浪文字制作方法及源代码 1个目标文件 摘要:Java源码,初学实例,波浪文字 Java波浪文字,一个利用...
【Java课程设计——电子音乐盒】是一个以Java技术为基础,利用Java Media Framework(JMF)开发的音乐播放软件。这个项目旨在让学生掌握Java编程语言在多媒体应用中的实践,特别是音频处理和用户界面设计方面的能力...
本篇将深入探讨如何使用Java进行逐行读取TXT文件,并提供相关示例代码。 首先,我们需要了解Java中的几个关键类,它们在文件读取过程中扮演着重要角色: 1. `File` 类:代表文件或目录的路径名。可以创建、重命名...
【音乐播放器——湘潭大学JAVA课程设计题目】是湘潭大学一门JAVA课程的期末项目,旨在让学生运用所学的JAVA编程知识开发一个功能丰富的音乐播放器。这个播放器不仅包含了基本的音乐播放功能,还增加了多项高级特性,...
该项目用Java编写,但通过Java绑定,也可以在其他编程语言,如MATLAB中使用。 MATLAB是一个强大的数学计算和数据分析环境,但其原生功能并不包括二维码的处理。在MATLAB中调用ZXing解码二维码,需要进行一些额外的...
今天我们将聚焦于一个名为"jmp123_400_utf8_mini"的JAVA开源项目,它包含了MP3解码器库和播放器,对于那些想要深入理解音频处理和JAVA编程的朋友们来说,这是一个宝贵的资源。 首先,我们来解析一下这个项目的名称...
用JAVA编写了一个小工具,用于检测当前显示器也就是显卡的显示模式,比如分辨率,色彩以及刷新频率等。 Java波浪文字制作方法及源代码 1个目标文件 摘要:Java源码,初学实例,波浪文字 Java波浪文字,一个利用...
用JAVA编写了一个小工具,用于检测当前显示器也就是显卡的显示模式,比如分辨率,色彩以及刷新频率等。 Java波浪文字制作方法及源代码 1个目标文件 摘要:Java源码,初学实例,波浪文字 Java波浪文字,一个利用...
本话题聚焦于一个特定的应用——"用Java语言写的JPEG图象生成器程序",这是一个适用于课程设计和学习管理系统开发的宝贵资源。 首先,我们要理解JPEG(Joint Photographic Experts Group)是一种广泛使用的有损图像...
- 考虑到性能和内存消耗,合理选择FFmpeg的编译选项,如是否包含所有解码器和编码器。 - 处理好异步操作,避免在主线程中执行耗时的原生代码,以免引起UI卡顿。 这个"Android 使用 FFmpeg (一)——编译.so文件...
FFmpeg的JNI接口会被用来在Java层调用C/C++编写的解码器,这样可以充分利用CPU的性能并降低内存消耗。 4. **Android多媒体框架**: Android系统本身提供了一个多媒体框架,包括MediaPlayer类,它可以播放本地和网络...
3. **FFmpeg**:FFmpeg是一个开源的跨平台多媒体处理工具,它包含了各种音频和视频编解码器,可以进行音视频的编码、解码、转换、封装等操作。在直播系统中,FFmpeg用于处理视频源,将其转化为适合网络传输的格式,...
Java编写的显示器显示模式检测程序 2个目标文件 内容索引:JAVA源码,系统相关,系统信息检测 用JAVA编写了一个小工具,用于检测当前显示器也就是显卡的显示模式,比如分辨率,色彩以及刷新频率等。 Java波浪文字制作...
有时,Android内置的编解码器可能无法满足特殊需求,这时可以考虑编写自定义编解码器。这需要深入理解编码算法,如MPEG-4 AAC编码、H.264编码等,并实现MediaCodec接口。 六、实战应用 1. 视频直播:通过推流和拉流...
Java二维码(JAVA二维码)是一种广泛应用于移动设备和网络服务中的数据编码技术,它将大量信息如网址、文本、名片等编码成一个二维图形——二维码,然后通过扫描来快速读取和解析这些信息。在Java中处理二维码,通常...
用JAVA编写了一个小工具,用于检测当前显示器也就是显卡的显示模式,比如分辨率,色彩以及刷新频率等。 Java波浪文字制作方法及源代码 1个目标文件 摘要:Java源码,初学实例,波浪文字 Java波浪文字,一个利用...
此时,解码器可以尝试反转出现错误的那一位,以恢复原始数据。 3. **源代码实现**:JAVA作为面向对象的编程语言,可以利用类和方法来组织EVENODD码的编码和解码逻辑。一个简单的实现可能包括两个类:`...