[原创]桓泽学音频编解码(10):AAC 无损解码模块算法分析

前面的博客索引

[原创]桓泽学音频编解码(1):MPEG1 MP3 系统算法分析

[原创]桓泽学音频编解码(2):AC3/Dolby Digital 系统算法分析

[原创]桓泽学音频编解码(3):AAC 系统算法分析

[原创]桓泽学音频编解码(4):MP3 和 AAC 中反量化原理,优化设计与参考代码中实现

[原创]桓泽学音频编解码(5):MP3 和 AAC 中IMDCT算法的原理,优化设计与参考代码中实现

[原创]桓泽学音频编解码(6):MP3 无损解码模块算法分析

[原创]桓泽学音频编解码(7):MP3 和 AAC 中huffman解码原理,优化设计与参考代码中实现

[原创]桓泽学音频编解码(8):关于MP3和AAC量化器设计的研究

[原创]桓泽学音频编解码(9):MP3 多相滤波器组算法分析

标题指引

1. 无损解码概述

2.解码过程

  2.1 解码scalefactor

2.2 解码量化谱线数据

2.2.1 对小于16的量化谱线系数的解码方法

2.2.2 对等于16的量化谱线系数的解码方法

  2.3 解码脉冲数据

  2.4 recoder处理

3 C参考代码

 

1. 无损解码概述

在AAC编码器内部,无损编码用于进一步减少scalefactor和量化谱线系数的冗余。

在AAC解码器内部,从individual_channel_stream层提取码流进行解码无损解码。码流信息包括以下解码量化谱线数据部分(global_gain,section_data(),section_scalefactor(),spectra_data())和解码脉冲数据部分(pulse_data_present, pulse_data())。

2.解码过程

  2.1 解码scalefactor

  Scalefactor压缩数据来自码流中scale_factor_data()。

AAC首次提出对差分scalefactor数据使用huffman编码。并且有1个huffman表。

码流格式如下

 

scale_factor_data()

{

      for (g = 0; g < num_window_groups; g++) {

            for (sfb = 0; sfb < max_sfb; sfb++) {

                  if (sfb_cb[g][sfb] != ZERO_HCB) {

                        if (is_intensity(g,sfb))

                              hcod_sf[dpcm_is_position[g][sfb]];

                        else

                              hcod_sf[dpcm_sf[g][sfb]];

                  }

            }

      }

}

  

注1:sfb_cb[g][sfb] != ZERO_HCB表示窗组g的sfb子带的谱线码本不是0。若sfb_cb[g][sfb] == ZERO_HCB表示在窗组g的sfb子带内的谱线数据全部为0。谱线数据全部为0也就没有什么Scalefactor,所以码流中存在Scalefactor的前提条件是sfb_cb[g][sfb] != ZERO_HCB。

注2:is_intensity(g,sfb)表示在窗组g的sfb子带内是否使用强度立体声编码。因为在使用了强度立体声编码的通道内传送的是dpcm_is_position数据不是差分scalefactor数据。

在获取了差分scalefactor数据dpcm_sf[g][sfb]以后,按照如下公式解码。

Scalefactor[g][sfb]=dpcm_sf[g][sfb]+ Scalefactor [g][sfb-1];

1≤Sfb≤max_scalefactor

Scalefactor [g][0]=global_gain

2.2 解码量化谱线数据

量化谱线数据来自码流中spectral_data()。AAC的huffman编码算法对量化谱线有两步分组处理.如上所述,第一步分组是分出scalefactor band中的谱线个数是4的倍数.目的是进行4个谱线一起编码.第二步分割是标准中把1个或几个scalefactor band合并成一个section.同一个section内的所有scalefactor band的谱线使用同一个huffman码表.所以,如果要进行huffman解码,section的宽度信息和码本号作为side information附加在section data中传输.解码端要先解出这些信息才能进行huffman解码.而section的长度小于scalefactor band的个数而大于scalefactor windows band的个数. 为了最大限度的匹配量化谱线的统计特性,Huffman为了使量化谱线的统计特性最大化的匹配huffman码本,section的数量允许和scalefactor band的数量一样大. Section个数的最大值是max_sfb.但注意section的边界要与scalefactor band的边界重合. 用huffman编码的4个一组的量化系数和2个一组的4个一组的量化系数的传送顺序是从低频系数到高频系数. 对于每个frame有多个windows的情况,要注意有分组和交织情况,系数的集合需要解交织,系数存储在数组x_quant[g][win][sfb][bin]。

AAC的huffman解码一共有15个码本,除了一个码本专用于scalefactor解码.11个码本用于谱线系数的解码.1个码本表示传输的系数全位零,是0码本,不需解码.2个码本是intensity码本,也是0码本.在为谱线系数解码的11个码本中,每个码本有自己可以编码的最大量化谱线系数的绝对值,用LAV表示.如表2, 用于谱线系数的解码的11个码本中最后一个码本可以解码出谱线系数的最大值是16.但当解码出谱线系数的值大于0小于16的时候.解码出的值就是实际的谱线系数的绝对值,当解码锄地谱线系数是16时,表示退出huffman解码,使用其他方式解码(稍后说明).所以在该码本中解码出的值16被定义成ESC_FLAG.表2中的unsigned_cb[i]标志位表示该码本是有符号码本还是无符号码本,unsigned_cb[i]=0时表示该码本是有符号码本, unsigned_cb[i]=1时表示该码本是无符号码本.解码有符号数时,先按照无符号解码再从输入的解码比特流中提取符号位,若解码出的谱线系数非零,则其符号位紧跟在被该谱线系数的码字的后面。

量化谱线 Huffman码本参数

Codebook Number, i

unsigned_cb[i]

Dimension of Codebook

LAV for codebook

Codebook listed in

0

-

-

0

-

1

0

4

1

 

2

0

4

1

 

3

1

4

2

 

4

1

4

2

 

5

0

2

4

 

6

0

2

4

 

7

1

2

7

 

8

1

2

7

 

9

1

2

12

 

10

1

2

12

 

11

1

2

(16) ESC

 

12

-

-

(reserved)

-

13

-

-

(reserved)

-

14

-

-

intensity out-of-phase

-

15

-

-

intensity in-phase

-

Codebook Number,i:码本的索引,即码流中sect_cb值。

unsigned_cb[i]:表示码本i是有符号码本还是无符号码本。

Dimension of Codebook:码本的维数。

2.2.1 对小于16的量化谱线系数的解码方法

 

首先解码huffman表中的index值。再完成从index到谱线数据的映射。流程图如下

 

之所以采取分组的整体huffman编码的方法是为了进一步压缩帧内的相关性节省码字.但由index映射到谱线数据一步实在多此一举(当然也有好处就是节省码本空间),实际上完全可以直接选用(w,x,y,z)制表,查表。

 2.2.2 对等于16的量化谱线系数的解码方法

 若sect_cb等于11且解码出的谱线系数有y,z值有一个等于ESC_FLAG(ESC_FLAG等于16)的情况要进行跳出huffman表的处理,使用其他方式编码。跳出huffman表

表示码流中有一个escape_sequence值表示跳出huffman表的谱线的值。这个escape_flag是变长的。由3部分组成escape_prefix,escape_separator和escape_word组成。

escape_prefix是N个1,escape_separator是1个0。escape_word是一个N+4位的值。

escape_sequence=2^(N+4)+ escape_word;

注意,escape_sequence也是有符号的,在解码escape_sequence之前,有几个符号位就有几个escape_sequence。(实际上有几个escape_sequence前面一定有相应多的符号位)。

解码流程图如下

 

 2.3 解码脉冲数据

  若码流中的标志位pulse_data_present为1则表示编码器使用了脉冲退出处理。表示在编码器端有一个或多个量化谱线用更小的幅值的系数替代number_pulse表示有多少个量化系数被替代,在重建谱线数据时要在相应的谱线中加上或减去pulse_amp值。注意:在8短窗序列中是不能使用脉冲数据编码的。

   算法流程图

 

2.4 recoder处理

由于在其他的解码器中都是使用不分组的谱线数据,所以对已经分组的量化谱线数据要重新排序。伪代码如下

quant_to_spec() {

   k = 0;

   for (g = 0; g < num_window_groups; g++) {

     j = 0;

     for (sfb = 0; sfb < num_swb; sfb ++) {

        width = swb_offset[sfb+1] - swb_offset[sfb];

        for (win = 0; win < window_group_length[g]; win++) {

           for (bin = 0; bin < width; bin++) {

             spec[win+k][bin+j] = x_quant[g][win][sfb][bin] ;

           }

        }

        j += width;

     }

     k += window_group_length[g];

   }

}

3 C参考代码

13818 -7 ISO官方参考代码中解码一个huffman码字的函数的流程图与注释:

 

int decode_huff_cw(Huffman *h)函数的流程图与注释

 

posted @ 2012-05-15 07:00  杭州桓泽  阅读(2780)  评论(1编辑  收藏  举报