标题指引
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)函数的流程图与注释