(九)用JAVA编写MP3解码器——哈夫曼解码

本文详细介绍了如何使用JAVA编写MP3解码器的哈夫曼解码部分,包括码表解析、哈夫曼树构造、2叉树和N叉树的优缺点以及解码过程,探讨了如何提高解码效率。
摘要由CSDN通过智能技术生成

解码一帧Layer3第3步:哈夫曼解码 -- huffmanDecoder方法

 

  1.哈夫曼码表 共有33张码表,从ISO/IEC 11172-3复制一张码表出来,看看码表的庐山真面目,下面说到的哈夫曼树的构造及解码过程都以这一张表为例。码表如下所示:

Huffman code table 6
x y hlen hcod No.
0 0 3 111 0
0 1 3 011 1
0 2 5 00101 2
0 3 7 0000001 3
1 0 3 110 4
1 1 2 10 5
1 2 4 0011 6
1 3 5 00010 7
2 0 4 0101 8
2 1 4 0100 9
2 2 5 00100 10
2 3 6 000001 11
3 0 6 000011 12
3 1 5 00011 13
3 2 6 000010 14
3 3 7 0000000 15

  码表的每一行由4个元素x、y、hlen、hcod组成,其最后一列是为了后文描述问题方便,我加上去的。解码大值区,一个码字(hcod)解码得到x、y两个值,hlen是码字的长度。33张码表中这几个值的取值范围是:x=0..15,y=0..15,hlen=0..19。其实33张码表只有象“Huffman code table 6”这样的表15张,码表有“共用”的情况,但是“共用”码表的linbits不同,看一看HuffmanBits的构造方法就明白这一点了。

 

  2.哈夫曼树 哈夫曼解码用位流索引查表法,无论你采用何种数据结构存储码表,码表在逻辑是仍然是树形结构。

  (1).2叉树 可以构造一棵2叉树装入这张码表,从位流中读入一位,根据是0还是1确定指向左子树还是右子树,直至到达叶结点,叶结点保存x、y,这样就可以由位流解得一个码字的2个码值的x和y了。

  (2).N叉树 采用2叉树这种数据结构一次只能从位流处理1位,效率比较低。如果一次处理位流中的n位,采用N(N=2^n)叉树这种数据结构。以一次处理2位的4叉树为例,上面的码表“Huffman code table 6”构造出的4叉树如下:

4叉树Huffman code table 6

  • 图中每一个2行4列的表格表示4叉树的的一个结点;
  • 每个结点的第一行中的数字0..15表示码表“Huffman code table 6”中的序号,例如15表示NO.15这一行,存储4叉树的时候,编号0..15的域(图中的1格)存储码表的x、y、hlen,根据其取值范围,存储x和y各需4比特,存储hlen需5比特,所以这3个值可以存储在一个short类型的整数内;
  • 每个结点第1行的p1..p7表示该结点不是叶结点,该结点的这个域存储的是指向下一个结点的“指针”,JAVA没有指针类型,这个4叉树采用数组来存储,用p1..p7存储数组下标,这个下标值同样用 一个 short类型的整数值表示
  • 存储4叉树用short类型的数组,其数组元素既有“指针”也有叶结点中某个域的值,用正、负号来区分它们。
  • 每个结点第2行的00、01、10、11表示一个结点内“子树”的编号。2叉树用左子树、右子树描述其子孙;4叉树用00子树、01子树...去描述。
  • 如果hlen为奇数,需要在末尾分别补上0和1凑成偶数。例如No.4这一行,hlen=3,hcod=110,要补成1100和1101,这两个二进制串都表示No.4这一行。这就是说,采用N叉树会使存储表冗余,n越大冗余度越大。
  • 4叉树示意图举例:No.3这一行hcod=0000001,按长度2将hcod分为00、00、00、10(或11)共4部分,分别对应图中4个结点的p1、p4、p7、3这4个域。No.3这一行的hlen=7,为奇数,同样要补成偶数,所以图中有一个结点的两个域都是“3”。
  • 遍历如图所示的4叉将结点的各个域存储到一个short类型的数组内,就存储好这张码表了。可以用任意一种方式遍历,先根次序、后根次序、层次遍历都可以。上图“Huffman code table 6”的4叉树存储在数组中为:
private final static short htbv6[] = {	//32
	-4, -24, 529, -28,  -8, -16, -20,1042, -12,1571,1586,1584,1843,1843,1795,1795,
	1299,1299,1329,1329,1314,1314,1282,1282,1057,1056, 769, 769, 784, 784, 768, 768};

htbv6被初始化到解码用的码表htBV[6],见下文给出的源代码 HuffmanBits.java的第52行,这一行中的0表示该码表的linbits=

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值