理解视频编码中的熵编码

  首先理解算术编码的原理: 假设比特0、1概率分别为0.8和0.2。信源流为00100,对此信源进行算术编码,过程如下:

理解视频编码中的熵编码_第1张图片

  每输入一个新比特,都会缩小概率区间,当输入00100后,得到的概率区间为(0.512, 0.59392),解码过程与编码过程相反,给定最终概率区间可以解码出原始比特流:

(1)、初始概率区间为(0, 1.0)。

(2)、(0.512, 0.59392)落在(0, 0.8)之间,第一个比特为0,概率区间为(0, 0.8)。

(3)、(0.512, 0.59392)落在(0, 0.64)之间,第二个比特为0,概率区间为(0, 0.64)。

(4)、(0.512, 0.59392)落在(0.512, 0.64)之间,第三个比特为1,概率区间为(0.512, 0.64)。

(5)、(0.512, 0.59392)落在(0.512, 0.6144)之间,第四个比特为0,概率区间为(0.512,  0.6144)。

(6)、(0.512, 0.59392)落在(0.512, 0.59392)之间,第五个比特为0,概率区间为(0.512, 0.59392)。

(7)、再往后就无法确定信源比特了。

  如果知道信源的比特数,那么利用最终概率区间中的任意值都可以解出信源比特流。

  如何将此概率区间表示为最终压缩后的比特流呢?

  用一个有限位的二进制小数来表示此区间,首先需要明确要用多少个比特来表示此区间。给定一个有限位的二进制小数0.xxxN, 小数点后第N位大小为2^(-N),第N位后的所有小数不管怎么变化,小数的波动区间都限定在(0, 2^(-N))内(最小为0.xxxN0000,最大为0.xxxN111...... 约等于0.xxxN + 0.xxx1)。上述概率区间为0.8 * 0.8 * 0.2 * 0.8 * 0.8 = 0.08192,熵为-log2(0.08192) = 3.61。当小数确定4个比特之后,小数的波动区间为(0, 0.0625),因此需要4个比特来表示这个概率区间。最终输出码流为0.1001 (= 0.5625)


  真实的算术编码,都是一边编码一边输出码流的。那么何时输出bit呢?

(1)、确定第一个输出bit,假设为0,则输出为0.0xxxx,处于(0, 0.5)之间。假设为1,则输出为0.1xxxx,处于(0.5, 1.0)之间。所以当概率区间长度小于0.5时,才可以确定第一个输出比特。当信源输入到001时,概率区间缩为(0.512, 0.64), 区间0.128长度小于0.5,输出bit 1

(2)、确定第二个输出bit,假设为0,输出为0.10xxx,处于(0.5, 0.75)之间。假设为1,输出为0.11xxx,处于(0.75, 1.0)之间。所以当概率区间长度小于0.25时,可以确定第二个输出比特。当信源输入到001时,概率区间缩为(0.512, 0.64), 区间长度0.128小于0.25,输出bit 0。

(3)、确定第三个输出bit,假设为0,输出为0.100xxx,处于(0.5, 0.625)之间。假设为1,输出为0.101xxx,处于(0.625, 0.75)之间。所以当概率区间长度小于0.125时,可以确定第三个输出比特。当信源输入到0010时,概率区间缩为(0.512,  0.6144), 区间长度0.1024小于0.125,输出bit 0。

(4)、确定第四个输出bit,假设为0,输出为0.1000xxx,处于(0.5, 0.5625)之间。假设为1,输出为0.1001xxx,处于(0.5625, 0.625)之间。所以当概率区间长度小于0.0625时,可以确定第四个输出比特。当信源输入到00100时,概率区间缩为(0.512,  0.59392), 区间长度0.08192大于0.0625,不输出。但是此时已经到了信源最后一个bit,所以也可以选择输出了。

上述的第(2)步开始可以做归一化处理:第一个bit确定后,可以去除第一个bit的影响:将概率区间*2,同时将区间起始值进行偏移。(2)中,(0.5, 1.0) * 2 - 1.0 = (0.0, 1.0), (0.512, 0.64) * 2 - 1.0 = (0.024, 0.28)。此时继续重复(1)的步骤。进行归一化处理后,如果当前概率区间小于0.5,则可以输出一个比特。

在真实的视频编码器设计中,为了避免浮点数运算,概率空间(0,1)被划分成离散的512等分。输入一个bit后,概率区间的计算通过查表得到:表格需要两个索引:当前LPS的概率,当前的概率区间。这里LPS的概率是用索引pStateIdx(0~64)来表示的。

理解视频编码中的熵编码_第2张图片

每编1个比特后,如果概率区间小于256,则循环以下步骤:输出一个比特,然后概率区间乘以2。直至概率区间大于256。所以在每次编码1比特之前,概率区间必然大于256,二进制表示为 1 xxxx xxxx

给定概率区间ivlCurrRange(如上所述,>256,二进制为1 xxxx xxxx),和当前LP(low probability)的概率索引 pStateIdx,查询得到ivlLPRange(本来需要用乘法计算得到: ivlCurrRange * p_LP), ivlLpsRange = rangeTabLps[pStateIdx][ (ivlCurrRange >> 6) & 3]。 在HM中,概率区间查询表格rangeTabLps规定如下:

const UChar TComCABACTables::sm_aucLPSTable[1 << CONTEXT_STATE_BITS][4] =
{
  { 128, 176, 208, 240}, // 约等于 {0.50 * 1 0000 0000b, 0.50 * 1 0110 0000b, 0.50 * 1 1010 0000b, 0.50 * 1 1110 0000b}
  { 128, 167, 197, 227}, // 约等于 {0.48 * 1 0000 0000b, 0.48 * 1 0100 0000b, 0.48 * 1 1010 0000b, 0.48 * 1 1110 0000b}
  { 128, 158, 187, 216},
  { 123, 150, 178, 205},
  { 116, 142, 169, 195},
  { 111, 135, 160, 185},
  { 105, 128, 152, 175},
  { 100, 122, 144, 166},
  {  95, 116, 137, 158},
  {  90, 110, 130, 150},
  {  85, 104, 123, 142},
  {  81,  99, 117, 135},
  {  77,  94, 111, 128},
  {  73,  89, 105, 122},
  {  69,  85, 100, 116},
  {  66,  80,  95, 110},
  {  62,  76,  90, 104},
  {  59,  72,  86,  99},
  {  56,  69,  81,  94},
  {  53,  65,  77,  89},
  {  51,  62,  73,  85},
  {  48,  59,  69,  80},
  {  46,  56,  66,  76},
  {  43,  53,  63,  72},
  {  41,  50,  59,  69},
  {  39,  48,  56,  65},
  {  37,  45,  54,  62},
  {  35,  43,  51,  59},
  {  33,  41,  48,  56},
  {  32,  39,  46,  53},
  {  30,  37,  43,  50},
  {  29,  35,  41,  48},
  {  27,  33,  39,  45},
  {  26,  31,  37,  43},
  {  24,  30,  35,  41},
  {  23,  28,  33,  39},
  {  22,  27,  32,  37},
  {  21,  26,  30,  35},
  {  20,  24,  29,  33},
  {  19,  23,  27,  31},
  {  18,  22,  26,  30},
  {  17,  21,  25,  28},
  {  16,  20,  23,  27},
  {  15,  19,  22,  25},
  {  14,  18,  21,  24},
  {  14,  17,  20,  23},
  {  13,  16,  19,  22},
  {  12,  15,  18,  21},
  {  12,  14,  17,  20},
  {  11,  14,  16,  19},
  {  11,  13,  15,  18},
  {  10,  12,  15,  17},
  {  10,  12,  14,  16},
  {   9,  11,  13,  15},
  {   9,  11,  12,  14},
  {   8,  10,  12,  14},
  {   8,   9,  11,  13},
  {   7,   9,  11,  12},
  {   7,   9,  10,  12},
  {   7,   8,  10,  11},
  {   6,   8,   9,  11},
  {   6,   7,   9,  10},
  {   6,   7,   8,   9},
  {   2,   2,   2,   2}
};

编码一个Bit的流程图如下:

理解视频编码中的熵编码_第3张图片


  编码器在RDO过程中,需要计算编码后的比特数,但不需要输出真正的码流,所以在x264和x265的RDO中,采用简化方法估算编码比特数的。直观的说,如果输入的bit概率小于0.5,那么需要超过1个比特来表示,概率越小,需要的比特数越多:

  假设输入比特流为a1a2a3a4a5......,概率分别为p1,p2,p3,p4,p5,那么算术编码这些信息需要的比特数等于信息熵,即log2(p1 * p2 * p3 * p4 * p5 *...)。编码器中,概率p用索引pStateIdx来表示,为了换算成整数运算,上述熵也可以表示为 (32768 * log2(p1) + 32768 * log2(p2) + 32768 * log2(p3) + 32768 * log2(p4) + 32768 * log2(p5) + ...) >> 15,将所有的pStateIdx对应的概率制作成表,后面就可以通过查表获得比特数了。x265中的表格如下

const uint32_t g_entropyBits[128] =
{
    // Corrected table, most notably for last state
    0x07b23, 0x085f9, 0x074a0, 0x08cbc, 0x06ee4, 0x09354, 0x067f4, 0x09c1b, 0x060b0, 0x0a62a, 0x05a9c, 0x0af5b, 0x0548d, 0x0b955, 0x04f56, 0x0c2a9,
    0x04a87, 0x0cbf7, 0x045d6, 0x0d5c3, 0x04144, 0x0e01b, 0x03d88, 0x0e937, 0x039e0, 0x0f2cd, 0x03663, 0x0fc9e, 0x03347, 0x10600, 0x03050, 0x10f95,
    0x02d4d, 0x11a02, 0x02ad3, 0x12333, 0x0286e, 0x12cad, 0x02604, 0x136df, 0x02425, 0x13f48, 0x021f4, 0x149c4, 0x0203e, 0x1527b, 0x01e4d, 0x15d00,
    0x01c99, 0x166de, 0x01b18, 0x17017, 0x019a5, 0x17988, 0x01841, 0x18327, 0x016df, 0x18d50, 0x015d9, 0x19547, 0x0147c, 0x1a083, 0x0138e, 0x1a8a3,
    0x01251, 0x1b418, 0x01166, 0x1bd27, 0x01068, 0x1c77b, 0x00f7f, 0x1d18e, 0x00eda, 0x1d91a, 0x00e19, 0x1e254, 0x00d4f, 0x1ec9a, 0x00c90, 0x1f6e0,
    0x00c01, 0x1fef8, 0x00b5f, 0x208b1, 0x00ab6, 0x21362, 0x00a15, 0x21e46, 0x00988, 0x2285d, 0x00934, 0x22ea8, 0x008a8, 0x239b2, 0x0081d, 0x24577,
    0x007c9, 0x24ce6, 0x00763, 0x25663, 0x00710, 0x25e8f, 0x006a0, 0x26a26, 0x00672, 0x26f23, 0x005e8, 0x27ef8, 0x005ba, 0x284b5, 0x0055e, 0x29057,
    0x0050c, 0x29bab, 0x004c1, 0x2a674, 0x004a7, 0x2aa5e, 0x0046f, 0x2b32f, 0x0041f, 0x2c0ad, 0x003e7, 0x2ca8d, 0x003ba, 0x2d323, 0x0010c, 0x3bfbb
};
待续......



你可能感兴趣的