openh264--熵编码

依次介绍CAVLC,CABAC

CAVLC

1 获取coeff_token

g_kuiVlcCoeffToken是CoeffToken,TotalCoff,TrailingOnes的映射关系,是个标准表,

openh264--熵编码_第1张图片

例:If (TotalCoeffs == 5 && TrailingOnes == 3 && 0 <= NC < 2),可得 coeff_token = 0000 100;  ,如下图高亮的部分,4表示值,7表示bit数。

//g_kuiVlcCoeffToken[nc][total-coeff][trailing-ones][0--value, 1--bit count]
const uint8_t g_kuiVlcCoeffToken[5][17][4][2] = {
  {
    //0<=nc<2
    { { 1,  1}, { 0,  0}, { 0,  0}, { 0,  0} },//0
    { { 5,  6}, { 1,  2}, { 0,  0}, { 0,  0} },//1
    { { 7,  8}, { 4,  6}, { 1,  3}, { 0,  0} },//2
    { { 7,  9}, { 6,  8}, { 5,  7}, { 3,  5} },//3
    { { 7, 10}, { 6,  9}, { 5,  8}, { 3,  6} },//4
    { { 7, 11}, { 6, 10}, { 5,  9}, { 4,  7} },//5
    { {15, 13}, { 6, 11}, { 5, 10}, { 4,  8} },//6
  },

.........

一个完整的例子:

1 计算非零系数(TotalCoeffs)和拖尾系数(TrailingOnes)的数目。
2 计算nC(numberCurrent,当前块值)。
3 查表获得coff_token的编码。
4 编码每个拖尾系数的符号,按zig-zag的逆序进行编码。
5 编码除拖尾系数之外非零系数的level(Levels)。
6 编码最后一个非零系数之前0的个数(totalZeos)。
7 编码每个系数前面0的数目(run_before)。

假设有一个4*4数据块NC=1,
{
   0,   3,   -1,   0,
   0,   -1,   1,   0,
   1,   0,   0,   0,
   0,   0,    0,   0
}
数据重排列:0,3,0,1,-1,-1,0,1,0……,
即:
第一步:TotalCoeffs = 5, TrailingOnes = 3, Total_zeros = 3.
第二步: 如果不是色度直流,NC=(NA+NB)/2=1,如果是色度直流,NC=-1.
查表得:
If (TotalCoeffs == 5 && TrailingOnes == 3 && 0 <= NC < 2)
      coeff_token = 0000 100;
      Code = 0000 100;
第三步:逆序编码,三个拖尾系数的符号依次是+(0),-(1),-(1);
即:
TrailingOne sign[i--] = 0;
TrailingOne sign[i--] = 1;
TrailingOne sign[i--] = 1;
Code = 0000 1000 11;
第四步:编码除了拖尾系数以外非零系数幅值Levels:
这步需要再分析下。
结果:
 Code = 0000 1000 1110 010;
第五步:编码最后一个非零系数前零的数目(TotalZeros)。
   查表,当TotalCoeffs = 5,total_zero = 3时,bit string = 111;

  Code = 0000 1000 1110 0101 11;
第六步:对每个非零系数前零的个数(RunBefore)进行编码:
i = TotalCoeffs = 5;ZerosLeft = Total_zeros = 3;查表:
依然按照逆序编码
ZerosLeft =3, run_before = 1         run_before[4]=10;
ZerosLeft =2, run_before = 0         run_before[3]=1;
ZerosLeft =2, run_before = 0         run_before[2]=1;
ZerosLeft =2, run_before = 1         run_before[1]=01;
ZerosLeft =1, run_before = 1         run_before[0]//最后一个系数不需要编码。
Code = 0000 1000 1110 0101 1110 1101;
 

WriteBlockResidualCavlc

int32_t  WriteBlockResidualCavlc (SWelsFuncPtrList* pFuncList, int16_t* pCoffLevel, int32_t iEndIdx,
                                  int32_t iCalRunLevelFlag,
                                  int32_t iResidualProperty, int8_t iNC, SBitStringAux* pBs) {
  ENFORCE_STACK_ALIGN_1D (int16_t, iLevel, 16, 16)
  ENFORCE_STACK_ALIGN_1D (uint8_t, uiRun, 16, 16)

  int32_t iTotalCoeffs = 0;
  int32_t iTrailingOnes = 0;
  int32_t iTotalZeros = 0, iZerosLeft = 0;
  uint32_t uiSign = 0;
  int32_t iLevelCode = 0, iLevelPrefix = 0, iLevelSuffix = 0, uiSuffixLength = 0, iLevelSuffixSize = 0;
  int32_t iValue = 0, iThreshold, iZeroLeft;
  int32_t n = 0;
  int32_t i = 0;


  CAVLC_BS_INIT (pBs);

  /*Step 1: calculate iLevel and iRun and total */

  if (iCalRunLevelFlag) {
    int32_t iCount = 0;
    iTotalZeros = pFuncList->pfCavlcParamCal (pCoffLevel, uiRun, iLevel, &iTotalCoeffs, iEndIdx);
    iCount = (iTotalCoeffs > 3) ? 3 : iTotalCoeffs;
    for (i = 0; i < iCount ; i++) {
      if (WELS_ABS (iLevel[i]) == 1) {
        iTrailingOnes ++;
        uiSign <<= 1;
        if (iLevel[i] < 0)
          uiSign |= 1;
      } else {
        break;

      }
    }
  }
  /*Step 3: coeff token */
  const uint8_t* upCoeffToken = &g_kuiVlcCoeffToken[g_kuiEncNcMapTable[iNC]][iTotalCoeffs][iTrailingOnes][0];
  iValue = upCoeffToken[0];
  n = upCoeffToken[1];

  if (iTotalCoeffs == 0) {
    CAVLC_BS_WRITE (n, iValue);

    CAVLC_BS_UNINIT (pBs);
    return ENC_RETURN_SUCCESS;
  }

  /* Step 4: trailing */
  n += iTrailingOnes;
  iValue = (iValue << iTrailingOnes) + uiSign;
  CAVLC_BS_WRITE (n, iValue);

  /*  levels */
  uiSuffixLength = (iTotalCoeffs > 10 && iTrailingOnes < 3) ? 1 : 0;     //初始化值为0,或者1

  for (i = iTrailingOnes; i < iTotalCoeffs; i++) {
    int32_t iVal = iLevel[i];

    iLevelCode = (iVal - 1) * (1 << 1);
    uiSign = (iLevelCode >> 31);
    iLevelCode = (iLevelCode ^ uiSign) + (uiSign << 1);
    iLevelCode -= ((i == iTrailingOnes) && (iTrailingOnes < 3)) << 1;

    iLevelPrefix = iLevelCode >> uiSuffixLength;
    iLevelSuffixSize = uiSuffixLength;
    iLevelSuffix = iLevelCode - (iLevelPrefix << uiSuffixLength);

    //level_prefix = levelCode / (1<

    if (iLevelPrefix >= 14 && iLevelPrefix < 30 && uiSuffixLength == 0) {
      iLevelPrefix = 14;
      iLevelSuffix = iLevelCode - iLevelPrefix;
      iLevelSuffixSize = 4;
    } else if (iLevelPrefix >= 15) {
      iLevelPrefix = 15;
      iLevelSuffix = iLevelCode - (iLevelPrefix << uiSuffixLength);
      //for baseline profile,overflow when the length of iLevelSuffix is larger than 11.
      if (iLevelSuffix >> 11)
        return ENC_RETURN_VLCOVERFLOWFOUND;
      if (uiSuffixLength == 0) {
        iLevelSuffix -= 15;
      }
      iLevelSuffixSize = 12;
    }

/*   计算levelSuffixSize: (后缀是长度为levelSuffixSize的无符号整数),除了以下两种情况levelSuffixSize等于suffixLength:

1、  level_prefix == 14 && suffixLength == 0 时, levelSuffixSize = 4;

2、  level_prefix >= 15 时,levelSuffixSize = level_prefix – 3;      */

    n = iLevelPrefix + 1 + iLevelSuffixSize;
    iValue = ((1 << iLevelSuffixSize) | iLevelSuffix);
    CAVLC_BS_WRITE (n, iValue);

    uiSuffixLength += !uiSuffixLength;
    iThreshold = 3 << (uiSuffixLength - 1);
    uiSuffixLength += ((iVal > iThreshold) || (iVal < -iThreshold)) && (uiSuffixLength < 6);

  }

  /* Step 5: total zeros,参见标准文档的表9.7*/

  if (iTotalCoeffs < iEndIdx + 1) {
    if (CHROMA_DC != iResidualProperty) {
      const uint8_t* upTotalZeros = &g_kuiVlcTotalZeros[iTotalCoeffs][iTotalZeros][0];
      n = upTotalZeros[1];
      iValue = upTotalZeros[0];
      CAVLC_BS_WRITE (n, iValue);
    } else {
      const uint8_t* upTotalZeros = &g_kuiVlcTotalZerosChromaDc[iTotalCoeffs][iTotalZeros][0];
      n = upTotalZeros[1];
      iValue = upTotalZeros[0];
      CAVLC_BS_WRITE (n, iValue);
    }
  }

  /* Step 6: pRun before,参见标准文档的表9.10*/
  iZerosLeft = iTotalZeros;
  for (i = 0; i + 1 < iTotalCoeffs && iZerosLeft > 0; ++ i) {
    const uint8_t uirun = uiRun[i];
    iZeroLeft = g_kuiZeroLeftMap[iZerosLeft];
    n = g_kuiVlcRunBefore[iZeroLeft][uirun][1];
    iValue = g_kuiVlcRunBefore[iZeroLeft][uirun][0];
    CAVLC_BS_WRITE (n, iValue);
    iZerosLeft -= uirun;
  }

  CAVLC_BS_UNINIT (pBs);
  return ENC_RETURN_SUCCESS;
}

 

 

CABAC

I宏块类型的二值化

I宏块类型包含类型名称,预测方式,色度CBP,亮度CBP,帧内16X16的预测模式,I宏块类型的二值化最多生成7个BIT,各BIT位的意义如下:

第一位: 0表示I_4X4,1表示非I_4X4,可以是I_16X16,I_PCM。

第二位:0表示I_16X16,1表示I_PCM。

接下来是色度CBP,色度CBP最多需要两个BIT,0表示所有残差都不被传送,解码器把所有残差系统赋为0,1表示只有DC系数被传送,解码器把所有AC系数赋为0,2表示所有残差系数(包括DC,AC)都被传送,解码器用接收到的残差系数重建图像。

当色度CBP小于2时,

第三位:值为0时,表示所有残差都不被传送;值为1时,表示只有DC系数被传送。

第四位:该位表示亮度CBP,由于非I_16X16的宏块不单独编码DC系数,所有这个变量只指明两种编码方案:该位等于0表示对应子宏块残差全部不被传送,该位等于1表示对应子宏块残差系数被传送,0表示残差全部不编码,1表示残差全部编码。

第五,六位为帧内16X16的预测方式,共四种,占两位。

当色度CBP等于2时,

第四,五位合起来表示所有残差系数都被传送。

第六,七位为帧内16X16的预测方式。

 

 

 

你可能感兴趣的:(openh264--熵编码)