文档章节

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

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

解码一帧Layer3第2步:解码增益因子  -- getScaleFactors_1()和getScaleFactors_2()方法

 

      增益因子(Scale Factor)数据存储在帧内的主信息中。主信息包含增益因子和用哈夫曼编码的主数据(main_data)。增益因子简单讲就是逆量化公式的指数中的一个因子。手册中解码主数据的伪码算法如下,其中MPEG 1.0由ISO/IEC 11172-3给出,MPEG 2.0由ISO/IEC 13818-3给出。官方并没有MPEG2.5这个版本,这个版本是民间版本。

解码主数据的伪码算法

 

      解码MPEG 1.0的增益因子时用到的输入值:

  • slen0[]、slen1[]:从上图中看出增益因子的值为位流中读取0..5位的值,当前究竟应该取几位,由这两个常量表给出。
  • 粒度组信息gri:用于判断块的类型的成员变量block_type、mixed_block_flag值已经在上一步中初始化。
  • scfsi:其值已在上一步初始化,若scfsi[0..3]=1表示增益因子共用。

 

解码MPEG 2.0的增益因子时用到的输入值

  • i_slen2[]:强度立体声(intensity stereo)的增益因子(scalefactor)比特数,变量名中的2表示是MPEG 2.0版。从伪码算法看出解码时需要从位流中读入0..4位,这个常量表的值给出当前应该读多少位
  • n_slen2[]:正常(normal)编码的增益因子(scalefactor,简称sf)比特数,这个常量表的值给出当前应该读多少位
  • 常量表i_slen2[]和n_slen2[]的取值见ISO/IEC 13818-3 subclause 2.4.3.2 slenx x=1..4,这两个常量表已经在Layer3的构造方法内被初始化。
  • nr_of_sfb[3][6][4]:MPEG 2.0的增益因子被分割为4部分,故nr_of_sfb的第3维长度为4;根据块的类型和scalefac_compress值增益因子频带(简称sfb)每部分的个数(number)分为6种情况,6种情况下其个数各不相同,故nr_of_sfb的第2维长度为6;根据帧边信息中block_type和mixed_block_flag这两个成员的值,共分为3种不同的块类型,故nr_of_sfb的第1维长度为3。我把nr_of_sfb设计为这样的结构,是考虑到和逆量化取得增益因子的值顺序一致。

 

解码增益因子得到的值:

 

  • 增益因子用去的比特数保存在part2_bits中,供后续的哈夫曼解码时计算主数据的比特数。
  • 解码得到的增益因子的值,长块的放入scfL[2][23];
  • 得到的增益因子的值,短块(包括纯短块和混合块中的短块)的值保存在scfS[2][3][13]中,得到的这些值供后续的逆量化使用,这些值在数组中的存放顺序要和逆量化时读取的顺序一致,这样效率更高一些。

 

 

  解码MPEG 1.0和MPEG 2.0/2.5增益因子的方法差别很大,这里定义了两个版本的方法。这里涉及到的“纯短块”、“长块”、“混合块”、“窗”概念,在逆量化中再作说明。根据上面对常量及变量值的描述中提及的“共用”、“块的类型”、“窗”就很容易看懂getScaleFactors_x()方法中的if语句和for语句的作用;短块内每个子带分3窗,所以有2重循环。

 

      class Layer3内定义的getScaleFactors_x()方法源码:

//2.
	//>>>>SCALE FACTORS========================================================
	private static int[][] scfL;		// [2][23];
	private static int[][][] scfS;		// [2][3][13];
	private static int[] i_slen2;		// MPEG 2.0 slen for intensity stereo
	private static int[] n_slen2;		// MPEG 2.0 slen for 'normal' mode
										// slen: 增益因子(scalefactor)比特数
	private static byte[][][] nr_of_sfb;//[3][6][4]

	/*
	 * MPEG 2.0/2.5
	 */
	private void getScaleFactors_2(final int ch, final int gr) {
		byte[] nr;
		int i, bandIdx, win, slen, num, n = 0, scf = 0;
		boolean i_stereo = objHeader.isIStereo();
		GRInfo gri = objSI.ch[ch].gr[gr];
		int[] l = scfL[ch];
		int[][] s = scfS[ch];

		rzero_bandL = 0;
		if ((ch > 0) && i_stereo)
			slen = i_slen2[gri.scalefac_compress >> 1];
		else
			slen = n_slen2[gri.scalefac_compress];

		gri.preflag = (slen >> 15) & 0x1;
		gri.part2_bits = 0;
		if (gri.block_type == 2) {
			n++;
			if ((gri.mixed_block_flag) != 0)
				n++;
			nr = nr_of_sfb[n][(slen >> 12) & 0x7];

			for (i = 0; i < 4; i++) {
				num = slen & 0x7;
				slen >>= 3;
				if (num != 0) {
					for (bandIdx = 0; bandIdx < nr[i]; bandIdx += 3) {
						for (win = 0; win < 3; win++)
							s[win][scf] = bsMainInfo.getBits17(num);
						scf++;
					}
					gri.part2_bits += nr[i] * num;
				} else {
					for (bandIdx = 0; bandIdx < nr[i]; bandIdx += 3) {
						for (win = 0; win < 3; win++)
							s[win][scf] = 0;
						scf++;
					}
				}
			}

			n = (n << 1) + 1;
			for (i = 0; i < n; i += 3) {
				for (win = 0; win < 3; win++)
					s[win][scf] = 0;
				scf++;
			}
		} else {
			nr = nr_of_sfb[n][(slen >> 12) & 0x7];
			for (i = 0; i < 4; i++) {
				num = slen & 0x7;
				slen >>= 3;
				if (num != 0) {
					for (bandIdx = 0; bandIdx < nr[i]; bandIdx++)
						l[scf++] = bsMainInfo.getBits17(num);
					gri.part2_bits += nr[i] * num;
				} else {
					for (bandIdx = 0; bandIdx < nr[i]; bandIdx++)
						l[scf++] = 0;
				}
			}

			n = (n << 1) + 1;
			for (i = 0; i < n; i++)
				l[scf++] = 0;
		}
	}

	/*
	 * MPEG 1.0
	 */
	private static final int slen0[] = { 0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4 };
	private static final int slen1[] = { 0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3 };

	private void getScaleFactors_1(final int ch, final int gr) {
		GRInfo gri = objSI.ch[ch].gr[gr];
		int scale_comp = gri.scalefac_compress;
		int length0 = slen0[scale_comp];
		int length1 = slen1[scale_comp];
		int sfb, win;
		int[] l = scfL[ch];
		int[][] s = scfS[ch];

		gri.part2_bits = 0;

		if (gri.window_switching_flag != 0 && gri.block_type == 2) {
			if (gri.mixed_block_flag != 0) {
				// MIXED block
				gri.part2_bits = 17 * length0 + 18 * length1;
				for (sfb = 0; sfb < 8; sfb++)
					l[sfb] = bsMainInfo.getBits9(length0);

				for (sfb = 3; sfb < 6; sfb++)
					for (win = 0; win < 3; win++)
						s[win][sfb] = bsMainInfo.getBits9(length0);

				for (sfb = 6; sfb < 12; sfb++)
					for (win = 0; win < 3; win++)
						s[win][sfb] = bsMainInfo.getBits9(length1);
			} else {
				// pure SHORT block
				gri.part2_bits = 18 * (length0 + length1);
				for (sfb = 0; sfb < 6; sfb++)
					for (win = 0; win < 3; win++)
						s[win][sfb] = bsMainInfo.getBits9(length0);
				for (sfb = 6; sfb < 12; sfb++)
					for (win = 0; win < 3; win++)
						s[win][sfb] = bsMainInfo.getBits9(length1);
			}
		} else {
			// LONG types 0,1,3
			int[] scfsi = objSI.ch[ch].scfsi;
			if (gr == 0) {
				gri.part2_bits = 10 * (length0 + length1) + length0;
				for (sfb = 0; sfb < 11; sfb++)
					l[sfb] = bsMainInfo.getBits9(length0);
				for (sfb = 11; sfb < 21; sfb++)
					l[sfb] = bsMainInfo.getBits9(length1);
			} else {
				gri.part2_bits = 0;
				if (scfsi[0] == 0) {
					for (sfb = 0; sfb < 6; sfb++)
						l[sfb] = bsMainInfo.getBits9(length0);
					gri.part2_bits += 6 * length0;
				}
				if (scfsi[1] == 0) {
					for (sfb = 6; sfb < 11; sfb++)
						l[sfb] = bsMainInfo.getBits9(length0);
					gri.part2_bits += 5 * length0;
				}
				if (scfsi[2] == 0) {
					for (sfb = 11; sfb < 16; sfb++)
						l[sfb] = bsMainInfo.getBits9(length1);
					gri.part2_bits += 5 * length1;
				}
				if (scfsi[3] == 0) {
					for (sfb = 16; sfb < 21; sfb++)
						l[sfb] = bsMainInfo.getBits9(length1);
					gri.part2_bits += 5 * length1;
				}
			}
		}
	}
	//<<<<SCALE FACTORS========================================================

 

 

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

下一篇:(九)用JAVA编写MP3解码器——哈夫曼解码

 

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

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

暗之幻影
粉丝 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
运用函数式思维:探索函数编程和控制

本文中,我们将讨论函数式思维的概念,讲解一级函数、优化和闭包。但本期的内在主题是控制:什么时候想要控制、什么时候需要控制、什么时候应该放弃控制。 一级(First-class)函数和控制 我...

IBMdW
2011/08/08
565
0
Spring Cloud OpenFeign集成Protocol Buffer

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

aoho
2018/10/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

为什么Netty的FastThreadLocal速度快

前言 最近在看netty源码的时候发现了一个叫FastThreadLocal的类,jdk本身自带了ThreadLocal类,所以可以大致想到此类比jdk自带的类速度更快,主要快在什么地方,以及为什么速度更快,下面做一...

ksfzhaohui
3分钟前
1
0
资治通鉴解析:无论什么条件,要挟权力做出承诺,都会被清算

电影《满城尽带黄金甲》里有句经典的名言“朕赐给你的,才是你的。朕不给你的,你不能抢。”之所以这段话有名,核心的就是,它揭示了这样一个权力心思:无论什么情况,权力的行使,都不愿意受...

太空堡垒185
7分钟前
1
0
CSS技巧之向下箭头

本文转载于:专业的前端网站➫CSS技巧之向下箭头 思路: 使用◇符号(可在输入法的软键盘找到该符号),使用定位选择位置,并隐藏溢出的上半部分 细点: 1.使用i标签的楷体属性把◇变大 2.给i...

前端老手
24分钟前
1
0
SpringCloud alibaba微服务之NACOS多环境配置整合

前言 伴随着spring cloud alibaba 登上主板以后,我就去了解下感觉还是蛮不错的。说实话第一次看见Nacos好长一段时间连读法都不知道...(/nɑ:kəʊs/)。按照官方的话说Nacos是:一个更易于...

攻城狮-飞牛
26分钟前
2
0
tcpdump

tcpdump -A -s0 port 21011 -i any (1)tcp: ip icmp arp rarp 和 tcp、udp、icmp这些选项等都要放到第一个参数的位置,用来过滤数据报的类型 (2)-i eth1 : 只抓经过接口eth1的包 (3)-t : 不显...

mskk
31分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部