mp3文件解码- 哈夫曼码区

哈夫曼码区

花了很多时间才完全摸透了这个部分,参考很多代码和博文,学士论文,在这个过程中,尝试发邮件和各个技术论坛的消息向大神请教,还遇到过文章主人不知道自己的内容被盗用的情况,作为敲门砖向其提供了被盗链接之后,就没有回音了,我的问题也被忽略了。

期间下载了N份完整的mp3解码代码,大部分是

/**********************************************************************
Copyright (c) 1991 MPEG/audio software simulation group, All Rights Reserved
**********************************************************************/

以及在这个基础上改写的C++版本,当时完全看不懂,而大多技术博客文章和论文也只是简单的提及了大值区(bigvlues)一对值共同编码,cout1区两对值共同编码,以及区域边界。

作为一个非科班的学渣,一次一次的重复着搁置又重拾的过程,都被哈夫曼编码给打败了。
直到换了个思路,看了这篇文章,尽管早早的了解过哈夫曼树,知道哈夫曼树是一种带权的二叉树,值保存在叶子节点,然后根据左子树编0,右子树编1,这样就获得了变长的编码。

看完这篇博文,我终于知道了用哈夫曼编码进行压缩的时候,首先要对文件流进行统计,计算所有值的出现次数,按照出现次数最少的一步步往上构建出一棵哈夫曼树,然后遍历这棵树,把编码和值成对写到表中。
第二次按照表对文件流进行编码,但是逆过程不但需要知道哈夫曼编码,还需要知道更多的信息,比如编码长度,补0情况等信息。这些信息都会一并写入到编码后的文件中。

通常来说,需要将哈夫曼表也写到文件中,想jpg图片用到的哈夫曼码表,就写在jpg文件中一个特定的位置,而mp3解码用到的哈夫曼码表则独立出来,在ISO_11172-3_ANNEX_AB 的Table 3-B.7. Huffman codes for Layer III 提供了大值区解码所需的32张表,和小值区解码所需的2张表。

大值区的32张表是这样的
哈夫曼码表
x 和 y 取值范围是0到15,它们代表着从哈夫曼编码区解码出来的两个值的一部分,因为它们的取值范围是0-15,所以它们只需要用4bits就能表示,>15的部分需要从哈夫曼编码中读取N个bits来与x和y相加,得到2个值,指示了需要读N个值的是linbits,但不是linbits不为0的表,就需要读取,而是解码出来的x或者y 等于15,且linbits不为0的时候,需要从编码中再读linbits个bits与x或者y相加。

到这步还没把两个值都解码出来,因为如果x或者y不为0,还需要从编码中读1bit来确定x或者y的符号。

所以bigvalue区编码信息包含的内容是这个样子的

内容hcodx>15的部分y > 15的部分x的符号y的符号
长度hlen个bitslinbits 个 bitslinbits 个 bits1bit1bit
存在条件采用除table0以外的表x == 15 且 linbits !=0y == 15 且 linbits !=0x!=0y!=0

count1区的所用到的两张表
count1哈夫曼码表
value代码解码出来的四个值 x,y,v,w,编码前他们的取值范围值-1、0、1。
count1区每一个单元包含的信息是这样的:

内容hcodx的符号y的符号v的符号w的符号
长度hlen个bits1bit1bit1bit1bit
存在条件x!=0y!=0v!=0w!=0

在解码哈夫曼编码前,需要将哈夫曼码表存储到内存中,解码的方式决定了存储的方式,官方给出的代码是一次从位流中读取1bit,ycb1698大佬则是一次从位流中读取2bits,官方的代码需要将哈夫曼码表还原成一棵二叉树,ycb1698大佬的代码则是还原成一棵四叉树,具体流程传送门
以下介绍官方2叉树的还原,因为哈夫曼树只有叶子节点才存放值,所以哈夫曼码表记录的都是叶子节点,但解码的时候需要完整的哈夫曼树。
用table1来说
官方给出的table1
因为x和y都可以用4bits来表示,所以用1byte来表示这个值,高4位存放x,低4位存放y,合并后的四个值,就用abcd表示,它们所在哈夫曼树是这样的
2叉树
官方用一个值指示该节点是否为叶子节点,另一个值存放合并值,然后从根节点按照NRL的顺序遍历二叉树
存储值
框起来的两个数字前一个指示是否为叶子节点,0表示该节点是叶子节点,非0则是它的左子树顺延的步长,让人怒摔的是,这对值采用的16进制值,最后一个0 11,代表的是d所在节点,d的值是0x11.

对比大值区,小值区的解码就容易多了,用到的两张表 table A,和tableB,tableB4个bits,解码出来4个值,tableA则是变长的,解码方法跟大值区差不多。只是不需要读取linbits。解码出来的4个值x,y,v,w,顺序是翻过来的。

	while ((hsstell() < part2_start + (*si).ch[ch].gr[gr].part2_3_length ) &&
     ( i < SSLIMIT*SBLIMIT ))
	{
		huffman_decoder(h, &x, &y, &v, &w);
		is[i/SSLIMIT][i%SSLIMIT]			= v;
		is[(i+1)/SSLIMIT][(i+1)%SSLIMIT]	= w;
		is[(i+2)/SSLIMIT][(i+2)%SSLIMIT]	= x;
		is[(i+3)/SSLIMIT][(i+3)%SSLIMIT]	= y;
		i += 4;
	}

最后,特别鸣谢ycb1698大佬,反复阅读了他的用JAVA编写MP3解码器——哈夫曼解码MP3解码之哈夫曼解码快速算法终于把这一块搞懂了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值