依次介绍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<
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的预测方式。