锁定老帖子 主题:MP3解码之哈夫曼解码快速算法
精华帖 (9) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-08-15
最后修改:2010-09-06
哈夫曼(huffman)解码用查表法,数据组织采用树形结构,若采用二叉树,一次处理一位(bit),效率是比较低的。从一些杂志上看到关于哈夫曼(huffman)解码的快速算法介绍,直接用位流索引一次处理N(4<N<=32)位,这种方法实际上是不可行的,原因是构造出的码表很长,如果一次处理8位,可以编写程序构造出码表,不过可以肯定的是码表的长度会超过我们事先的想象,以至于没有多大的实用价值。一次处理多位(一位以上)码表中冗余度很大导致码表很长。 MP3解码处理主数据(main_data)的第一步就是对主数据进行哈夫曼解码。MP3编解码用到的哈夫曼表由ISO/IEC 11172-3 的附录B中给出,大值区用到31张码表(其中第0、4、14号码表未使用),小值区用到两张码表。从ISO/IEC 11172-3复制出两张原始的码表来分析,解码大值区的码表: Huffman code table 7
解码小值区的码表: Huffman code table 17
所有码表中取值范围是:x=0..15,y=0..15,码长hlen=1..19。
一次处理多位应该如何实现呢?首先构造出码表,如果每次处理2比特,构造码表暂存数据时用4叉树;如果一次处理3比特,则用8叉树,以此类推。编程从一个文本文件中读入如上所示的原始的哈夫曼表数据,将其插入到N叉树中相应的位置。假如一次处理2位而码字(hcod)是5位(hlen=5),那么在hcod最后分别补上0和1凑足2的整数倍位数,这就导致了构造出的哈夫曼表冗余度,即一个码字对应多个码表中元素。一次处理的位数越多,构造出的码表的冗余度越大。
根据自己解码设计构造出码表比较费事,解码过程挺简单。
实际编程中,可以用数组来存储N叉树,只需要将指针域的值改为元素在数组中的下标值。以大值区解码一次处理2比特为例,x和y取值范围为0..15,只需占用4比特;码长hlen取值范围为1..19,存储hlen只需5比特。存储一个码值只需要13比特,可以将一个码值存储在16位整数中,低4位是y,接下来的4位是x,再接下来的5位是hlen。高3位全为零表示该数组元素存储的是一个码值,最高位为1(表示负数)则其绝对什表示该数组元素存储的是数组的下标值。经过这样处理后解码大值区的码表“Huffman code table 7”一次处理2位,是4叉树: static short htbv7[72] = { -4, -68, 256, 256, -8, -48, -64,1041, -12, -28, -40, -44, -16, -20, -24,2069, 2645,2629,2644,2643,2357,2357,2372,2372,2341,2341,2386,2386,2129, -32,2128, -36, 2309,2309,2356,2356,2371,2371,2355,2355,2084,2114,1812,1812,1857,1857,1856,1856, -52, -56, -60,1554,2052,2083,2098,2051,1811,1811,1841,1841,1840,1840,1826,1826, 1313,1313,1538,1568, 769, 769, 784, 784};
解码小值区的码表“Huffman code table 17”一次处理4位,是16叉树: static short htc0[80] = { -16, -32, -48, -64,1026,1025,1028,1032, 256, 256, 256, 256, 256, 256, 256, 256, 1547,1547,1547,1547,1551,1551,1551,1551,1549,1549,1549,1549,1550,1550,1550,1550, 1543,1543,1543,1543,1541,1541,1541,1541,1289,1289,1289,1289,1289,1289,1289,1289, 1286,1286,1286,1286,1286,1286,1286,1286,1283,1283,1283,1283,1283,1283,1283,1283, 1290,1290,1290,1290,1290,1290,1290,1290,1292,1292,1292,1292,1292,1292,1292,1292};
码表构造好了,如何解码呢?由位流索引查表,从码流中读入4字节暂存到unsigned int umask,解码大值区得到x和y: y = ptab[umask >> 30]; // 一次处理2比特,ptab指向码表(如ptab=htbv7) while (y < 0) { umask <<= 2; y = ptab[(umask >> 30) - y]; } x = y >> 8; // hlen num -= x; // num为umask中剩余的比特数 umask <<= x; x = (y >> 4) & 0xf; // 得到x值 y &= 0xf; // 得到y值 1--5行为查表过程,一次处理的位数越多,执行循环的次数越少。9--10行得到原始码表中的x、y值,对x、y进一步处理就解得哈夫曼码值。
解码小值区得到y值的代码: y = ptab[umask >> 28]; // 一次处理4比特 while (y < 0) { umask <<= 4; y = ptab[(umask >> 28) - y]; } x = y >> 8; // hlen num -= x; umask <<= x; y &= 0xf; // 得到y值
每解码完一个码字,重新刷新umask和num。以上解码方法正确与否可以用“Huffman code table 7”或“Huffman code table 17”内的一行数据根据源码去检查。 以Huffman code table 7的一行“2 2 7 0001101”为例:这一行表示的意思是x=2,y=2,码长hlen=7,码字hcod=0001101;
一次处理N比特肯定比一次处理1比特效率高。兼顾效率和存储空间开销,解码大值区采用一次处理2位到4位,解码小值区一次处理4位,这样比较好。
本文的“哈夫曼解码快速算法”的JAVA代码是jmp123开源项目的一部分。 【jmp123下载地址】http://jmp123.sourceforge.net/ 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-08-24
|
|
返回顶楼 | |
发表时间:2010-08-27
硬是没有看明白, 好像现在有不少的快速算法, 正在研究~
|
|
返回顶楼 | |
发表时间:2010-08-31
最后修改:2010-08-31
sdh5724 写道 硬是没有看明白, 好像现在有不少的快速算法, 正在研究~
写的有点简略,新补充了一个解码过程例子,看清解码过程容易点了。 解码过程比较简单,构造码表比较复杂一点。 |
|
返回顶楼 | |
浏览 7267 次