• [原创]桓泽学音频编解码(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)函数的流程图与注释

  • 相关阅读:
    vs2008 服务器控件库
    dropdoenlist 设置默认值
    .NET用HttpFileCollection实现多文件上传
    dropdownlist 绑定
    简单的webservice调用(天气预报)
    统计在线人数
    多文件上传
    dropdownlist1 绑定 value值
    WMI 脚本入门:第一部分 (MSDN)
    WMI 脚本入门:第三部分 (MSDN)
  • 原文地址:https://www.cnblogs.com/gaozehua/p/2500864.html
Copyright © 2020-2023  润新知