openh264--熵编码

依次介绍CAVLC,CABAC

CAVLC

1 获取coeff_token

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

例: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<<suffixLength);level_suffix = levelCode % (1<<suffixLength);

    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的预测方式。

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
OpenH264 是思科公司发布的一个开源的 H.264 编码和解码器。编码器特性Constrained Baseline Profile up to Level 5.2 (4096x2304)Arbitrary resolution, not constrained to multiples of 16x16Rate control with adaptive quantization, or constant quantizationSlice options: 1 slice per frame, N slices per frame, N macroblocks per slice, or N bytes per sliceMultiple threads automatically used for multiple slicesTemporal scalability up to 4 layers in a dyadic hierarchySpatial simulcast up to 4 resolutions from a single inputLong Term Reference (LTR) framesMemory Management Control Operation (MMCO)Reference picture list modificationSingle reference frame for inter predictionMultiple reference frames when using LTR and/or 3-4 temporal layersPeriodic and on-demand Instantaneous Decoder Refresh (IDR) frame insertionDynamic changes to bit rate, frame rate, and resolutionAnnex B byte stream outputYUV 4:2:0 planar input解码器特性Constrained Baseline Profile up to Level 5.2 (4096x2304)Arbitrary resolution, not constrained to multiples of 16x16Single thread for all slicesLong Term Reference (LTR) framesMemory Management Control Operation (MMCO)Reference picture list modificationMultiple reference frames when specified in Sequence Parameter Set (SPS)Annex B byte stream inputYUV 4:2:0 planar output支持的操作系统Windows 64-bit and 32-bit (initial release is only 32-bit, 64-bit will follow soon)Mac OS X 64-bit (initial release does not include this target, will follow soon)Linux 64-bit and 32-bit (initial release is only 32-bit, 64-bit will follow soon)Android 32-bit (initial release does not include this target, will follow soon)iOS 64-bit and 32-bit (not supported yet, may be added in the future)支持的处理器Intel x86 optionally with MMX/SSE (no AVX yet, help is welcome)ARMv7 optionally with NEON (initial release does not include this target, will follow later)Any architecture using C/C fallback functions 标签:OpenH264
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山西茄子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值