文档章节

(十六)用JAVA编写MP3解码器——解码Layer2

暗之幻影
 暗之幻影
发布于 2015/01/04 15:29
字数 1753
阅读 7
收藏 0

      MPEG 1.0/2.0/2.5 对声音的压缩分三层:Layer I、Layer II和Layer III。相比于Layer3,Layer2的解码就简单得多了。

      1.变量初始化  申明的成员变量在构造方法内初始化,这些常量值是从解码规范的文档里直接COPY过来的。

      2.帧的数据结构  以Layer2编码的文件按帧存放,解码时也是逐帧解码。每一帧内依次存放位分配信息、增益因子选择信息、增益因子、主数据。采用标准立体声编码的Layer2一帧内的主数据有12个粒度组(granule),一个粒度组内最多可有32个子带(subband),每个子带两个声道。每个声道内3组样本值连续存放,每一组32个值。

      3.解码过程  Layer2编码不采用心理声学模型,解码端不用IMDCT;Layer2编码端没有哈夫曼编码。逆量化没有采用解码Layer3那样的查表法而是直接运算,Layer2的逆量化公式也比Layer3的简单得多。解码一帧Layer2只需6步,这6个步骤在decodeFrame方法内注解出来,每一步的细节一看就懂,不再赘述。解码Layer2的源码如下:

/*
* Layer2.java -- MPEG 1.0/2.0/2.5 Audio Layer II Decoder
* 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.sf.net/>
*/
package decoder;

public final class Layer2 implements ILayer123 {
	private static Header header;
	private static BitStream bs;
	private static Synthesis filter;
	private static int nch, aidx, sblimit;
	private static byte[][] allocation;		//[2][32]
	private static byte[][] nbal;			//[5][]
	private static byte[][] sbquant_offset;	//[5][]
	private static byte[][] scfsi;			//[2][32]
	private static byte[][][] scalefactor;	//[2][32][3]
	private static int[] cq_steps;			//[17]
	private static float[] cq_C;			//[17]
	private static float[] cq_D;			//[17]
	private static byte[] cq_bits;			//[17]
	private static byte[] bitalloc_offset;	//[8]
	private static byte[][] offset_table;	//[6][15]
	private static byte[] group;			//[17]
	private static int[] samplecode;		//[3]
	private static float[][][] syin;		//[2][3][32]

	// Layer1也用到factor[]
	public static float[] factor;			//[63]

	public Layer2(BitStream bitstream,Header h, Synthesis filter, int wch) {
		header = h;
		bs = bitstream;
		this.filter = filter;

		nbal = new byte[5][];
		// ISO/IEC 11172-3 Table 3-B.2a
		nbal[0] = new byte[] { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3,
				3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2 };

		// ISO/IEC 11172-3 Table 3-B.2b
		nbal[1] = new byte[] { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3,
				3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2 };

		// ISO/IEC 11172-3 Table 3-B.2c
		nbal[2] = new byte[] { 4, 4, 3, 3, 3, 3, 3, 3 };

		// ISO/IEC 11172-3 Table 3-B.2d
		nbal[3] = new byte[] { 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 };

		// ISO/IEC 13818-3 Table B.1
		nbal[4] = new byte[] { 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2,
				2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };

		// ISO/IEC 11172-3 Table 3-B.1
		factor = new float[] {2.00000000000000f, 1.58740105196820f,
			1.25992104989487f, 1.00000000000000f, 0.79370052598410f,
			0.62996052494744f, 0.50000000000000f, 0.39685026299205f,
			0.31498026247372f, 0.25000000000000f, 0.19842513149602f,
			0.15749013123686f, 0.12500000000000f, 0.09921256574801f,
			0.07874506561843f, 0.06250000000000f, 0.04960628287401f,
			0.03937253280921f, 0.03125000000000f, 0.02480314143700f,
			0.01968626640461f, 0.01562500000000f, 0.01240157071850f,
			0.00984313320230f, 0.00781250000000f, 0.00620078535925f,
			0.00492156660115f, 0.00390625000000f, 0.00310039267963f,
			0.00246078330058f, 0.00195312500000f, 0.00155019633981f,
			0.00123039165029f, 0.00097656250000f, 0.00077509816991f,
			0.00061519582514f, 0.00048828125000f, 0.00038754908495f,
			0.00030759791257f, 0.00024414062500f, 0.00019377454248f,
			0.00015379895629f, 0.00012207031250f, 0.00009688727124f,
			0.00007689947814f, 0.00006103515625f, 0.00004844363562f,
			0.00003844973907f, 0.00003051757813f, 0.00002422181781f,
			0.00001922486954f, 0.00001525878906f, 0.00001211090890f,
			0.00000961243477f, 0.00000762939453f, 0.00000605545445f,
			0.00000480621738f, 0.00000381469727f, 0.00000302772723f,
			0.00000240310869f, 0.00000190734863f, 0.00000151386361f,
			0.00000120155435f };

		// cq_xxx: Layer II classes of quantization, ISO/IEC 11172-3 Table 3-B.4
		cq_steps = new int[] { 3, 5, 7, 9, 15, 31, 63, 127, 255, 511, 1023,
				2047, 4095, 8191, 16383, 32767, 65535 };
		cq_C = new float[] { 1.3333333f, 1.6f, 1.1428571f, 1.77777778f,
				1.0666667f, 1.0322581f, 1.015873f, 1.007874f, 1.0039216f,
				1.0019569f, 1.0009775f, 1.0004885f, 1.0002442f, 1.000122f,
				1.000061f, 1.0000305f, 1.00001525902f };
		cq_D = new float[] { 0.5f, 0.5f, 0.25f, 0.5f, 0.125f, 0.0625f,
				0.03125f, 0.015625f, 0.0078125f, 0.00390625f, 0.001953125f,
				0.0009765625f, 0.00048828125f, 0.00024414063f, 0.00012207031f,
				0.00006103516f, 0.00003051758f };
		cq_bits = new byte[] {5,7,3,10,4,5,6,7,8,9,10,11,12,13,14,15,16};

		sbquant_offset = new byte[][] {
			// ISO/IEC 11172-3 Table 3-B.2a
			{7,7,7,6,6,6,6,6,6,6,6,3,3,3,3,3,3,3,3,3,	3,3,3,0,0,0,0},

			// ISO/IEC 11172-3 Table 3-B.2b
			{7,7,7,6,6,6,6,6,6,6,6,3,3,3,3,3,3,3,3,3,	3,3,3,0,0,0,0,0,0,0},

			// ISO/IEC 11172-3 Table 3-B.2c
			{5,5,2,2,2,2,2,2},

			// ISO/IEC 11172-3 Table 3-B.2d
			{5,5,2,2,2,2,2,2,2,2,2,2},

			// ISO/IEC 13818-3 Table B.1
			{4,4,4,4,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,	1,1,1,1,1,1,1,1,1,1} };

		bitalloc_offset = new byte[] { 0, 3, 3, 1, 2, 3, 4, 5 };
		offset_table = new byte[][] { { 0, 1, 16 }, { 0, 1, 2, 3, 4, 5, 16 },
				{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 },
				{ 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
				{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 },
				{ 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 } };
		group = new byte[] { 2, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

		allocation = new byte[2][32];
		scfsi = new byte[2][32];
		scalefactor = new byte[2][32][3];
		samplecode = new int[3];
		syin = new float[2][3][32];

		//nch,aidx,sblimit...
		nch = header.getChannels();
		int bitrate = header.getBitrate() / nch;
		if(header.getVersion() == Header.MPEG1)
			if(bitrate <= 48)
				aidx = (bitrate == 32) ? 3 : 2;
			else if(bitrate <= 80)
				aidx = 0;
			else
				aidx = (bitrate == 48) ? 0 : 1;
		else //mpeg 2.0/2.5
			aidx = 4;
		byte[] limit = {27, 30, 8, 12, 30};
		sblimit = limit[aidx];
	}

	private void requantization(int index, int gr, int ch, int sb) {
		int nb, s, c;
		int nlevels = cq_steps[index];
		if ((nb = group[index]) != 0) {		// degrouping
			c = bs.getBits17(cq_bits[index]);
			for (s = 0; s < 3; s++) {
				samplecode[s] = c % nlevels;
				c /= nlevels;
			}
			nlevels = (1 << nb) - 1;	//用于计算fractional
		}
		else {
			nb = cq_bits[index];
			for (s = 0; s < 3; s++)
				samplecode[s] = bs.getBits17(nb);
		}

		for (s = 0; s < 3; s++) {
			float fractional = 2.0f * samplecode[s] / (nlevels + 1) - 1.0f;
			// s'' = C * (s''' + D)
			syin[ch][s][sb] = cq_C[index] * (fractional + cq_D[index]);
			// s' = factor * s''
			syin[ch][s][sb] *= factor[scalefactor[ch][sb][gr >> 2]];
		}
	}

	private void stereo(int index, int gr, int sb) {
		int nb, s, c;
		int nlevels = cq_steps[index];
		if ((nb = group[index]) != 0) {
			c = bs.getBits17(cq_bits[index]);
			for (s = 0; s < 3; s++) {
				samplecode[s] = c % nlevels;
				c /= nlevels;
			}
			nlevels = (1 << nb) - 1;
		}
		else {
			nb = cq_bits[index];
			for (s = 0; s < 3; s++)
				samplecode[s] = bs.getBits17(nb);
		}

		for (s = 0; s < 3; s++) {
			float fractional = 2.0f * samplecode[s] / (nlevels + 1) - 1.0f;
			// s'' = C * (s''' + D)
			syin[0][s][sb] = syin[1][s][sb] = cq_C[index] * (fractional + cq_D[index]);
			// s' = factor * s''
			syin[0][s][sb] *= factor[scalefactor[0][sb][gr >> 2]];
			syin[1][s][sb] *= factor[scalefactor[1][sb][gr >> 2]];
		}
	}

	public void decodeFrame() throws Exception {
		int maindata_begin ,bound, sb, ch;
		int slots = header.getMainDataSlots();
		bs.append(slots);
		maindata_begin = bs.getBytePos();
		bound = (header.getMode() == 1) ? ((header.getModeExtension() + 1) * 4) : 32;
		if(bound > sblimit)
			bound = sblimit;

		/*
		 * 1. Bit allocation decoding
		 */
		for (sb = 0; sb < bound; sb++)
			for (ch = 0; ch < nch; ch++)
				allocation[ch][sb] = (byte)bs.getBits9(nbal[aidx][sb]); // 2..4 bits
		for (sb = bound; sb < sblimit; sb++)
			allocation[1][sb] = allocation[0][sb] = (byte)bs.getBits9(nbal[aidx][sb]);

		/*
		 * 2. Scalefactor selection information decoding
		 */
		for (sb = 0; sb < sblimit; sb++)
			for (ch = 0; ch < nch; ch++)
				if (allocation[ch][sb] != 0)
					scfsi[ch][sb] = (byte)bs.getBits9(2);
				else
					scfsi[ch][sb] = 0;

		/*
		 * 3. Scalefactor decoding
		 */
		for (sb = 0; sb < sblimit; ++sb)
			for (ch = 0; ch < nch; ++ch)
				if (allocation[ch][sb] != 0) {
					scalefactor[ch][sb][0] = (byte)bs.getBits9(6);
					switch (scfsi[ch][sb]) {
					case 2:
						scalefactor[ch][sb][2] = scalefactor[ch][sb][1] = scalefactor[ch][sb][0];
						break;
					case 0:
						scalefactor[ch][sb][1] = (byte)bs.getBits9(6);
					case 1:
					case 3:
						scalefactor[ch][sb][2] = (byte)bs.getBits9(6);
					}
					if ((scfsi[ch][sb] & 1) == 1)
						scalefactor[ch][sb][1] = scalefactor[ch][sb][scfsi[ch][sb] - 1];
				}

		int gr, index, s;
		for (gr = 0; gr < 12; gr++) {
			/*
			 * 4. Requantization of subband samples
			 */
			for (sb = 0; sb < bound; sb++)
				for (ch = 0; ch < nch; ch++)
					if ((index = allocation[ch][sb]) != 0) {
						index = offset_table[bitalloc_offset[sbquant_offset[aidx][sb]]][index - 1];
						requantization(index, gr, ch, sb);
					} else
						syin[ch][0][sb] = syin[ch][1][sb] = syin[ch][2][sb] = 0;

			//mode=1(Joint Stereo)
			for (sb = bound; sb < sblimit; sb++)
				if ((index = allocation[0][sb]) != 0) {
					index = offset_table[bitalloc_offset[sbquant_offset[aidx][sb]]][index - 1];
					stereo(index, gr, sb);
				} else
					for (ch = 0; ch < nch; ch++)
						syin[ch][0][sb] = syin[ch][1][sb] = syin[ch][2][sb] = 0;
			
			for (ch = 0; ch < nch; ch++)
				for (s = 0; s < 3; s++)
					for (sb = sblimit; sb < 32; sb++)
						syin[ch][s][sb] = 0;

			/*
			 * 5. Synthesis subband filter
			 */
			for (ch = 0; ch < nch; ch++)
				for (s = 0; s < 3; s++)
					filter.synthesisSubBand(syin[ch][s], ch);
		} // for gr=0 to 12

		/*
		 * 6. Ancillary bits
		 */
		int discard = slots + maindata_begin - bs.getBytePos();
		bs.skipBytes(discard);
	}
}

 

 

上一篇:(十五)用JAVA编写MP3解码器——音频输出

下一篇:(十七)用JAVA编写MP3解码器——解码Layer1

 

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

本文转载自:http://lfp001.iteye.com/blog/750070

暗之幻影
粉丝 20
博文 377
码字总数 71245
作品 0
南京
高级程序员
私信 提问
(五)用JAVA编写MP3解码器——解析文件信息

前文提到解析MP3标签,程序源码中也已经出现了调用解析MP3标签、打印MP3文件信息的功能,这儿先说说MP3文件信息的解析。 解析MP3的文件信息对MP3解码器来说只是一个附加功能,如果不加入这部...

暗之幻影
2015/01/04
61
0
疯狂Spring Cloud连载(11)——Feign的编码器与解码器

本文节选自《疯狂Spring Cloud微服务架构实战》 京东购买地址:https://item.jd.com/12256011.html 当当网购买地址:http://product.dangdang.com/25201393.html Spring Cloud教学视频:htt...

杨大仙的程序空间
2017/10/23
3.1K
5
Java8 BASE64编解码

Java8 BASE64编解码 Base64是一种用64个字符来表示任意二进制数据的方法。 Base64是一种最常见的二进制编码方法。 Java一直缺少BASE64编码 API,以至于通常在项目开发中会选用第三方的API...

秋风醉了
2015/04/02
1K
0
Spring Cloud OpenFeign集成Protocol Buffer

本文作者张天,著有《Spring Cloud 微服务架构进阶》一书。 背景  在之前的文章中,我们介绍过基于Spring Cloud微服务架构,其中,微服务实例之间的交互方式一般为RESTful HTTP请求或RPC调用...

aoho
2018/10/07
0
0
Mina多次协议解析缓冲对象IoBuffer

为什么要定义成员变量IoBuffer呢? 因为数据接收并不是一次完成的;比如客户端发送一个请求有400个字节,先发送了200个字节,这时暂停某段时间,然后又发送了剩余200字节;在解码时,Decode的...

boonya
2013/05/02
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

爬虫可以采集哪些数据?爬虫借用什么代理可以提高效率

学习爬虫的门槛非常低,特别是通过Python学习爬虫,即使是网上也能找到许多学习爬虫的方法,而且爬虫在数据采集方面效果比较好,比如可以采集几万、上百万网页数据进行分析,带来极有价值的数...

xiaotaomi
23分钟前
4
0
redis自建笔记

自建redis笔记 最近在linux安装了一下redis,特做一些笔记! 本文先单节点启动redis,然后再进行持久化配置,在次基础上,再分享搭建主从模式的配置以及Sentinel 哨兵模式及集群的搭建 单节点...

北极之北
24分钟前
4
0
没想到Spring Boot居然这么耗内存,有点惊讶

Spring Boot总体来说,搭建还是比较容易的,特别是Spring Cloud全家桶,简称亲民微服务,但在发展趋势中,容器化技术已经成熟,面对巨耗内存的Spring Boot,小公司表示用不起。如今,很多刚诞...

程序员修BUG
28分钟前
4
0
Spring Security 实战干货:Spring Boot 中的 Spring Security 自动配置初探

1. 前言 我们在前几篇对 Spring Security 的用户信息管理机制,密码机制进行了探讨。我们发现 Spring Security Starter相关的 Servlet 自动配置都在spring-boot-autoconfigure-2.1.9.RELEASE...

码农小胖哥
30分钟前
4
0
Docker 容器时区时间不一致 问题解决

解决方案: 1,最傻瓜也最方便的处理方式,运行新的容器前设置本机时区和时间文件与容器的映射 docker run -v /etc/timezone:/etc/timezone -v /etc/localtime:/etc/localtime ...1 -v /etc/...

突突突酱
31分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部