static int scanPosLast_c(const uint16_t *scan, const coeff_t *coeff, uint16_t *coeffSign, uint16_t *coeffFlag, uint8_t *coeffNum, int numSig, const uint16_t* /*scanCG4x4*/, const int /*trSize*/)
{
memset(coeffNum, 0, MLS_GRP_NUM * sizeof(*coeffNum));
memset(coeffFlag, 0, MLS_GRP_NUM * sizeof(*coeffFlag));
memset(coeffSign, 0, MLS_GRP_NUM * sizeof(*coeffSign));
int scanPosLast = 0;
do
{
const uint32_t cgIdx = (uint32_t)scanPosLast >> MLS_CG_SIZE;
const uint32_t posLast = scan[scanPosLast++];
const int curCoeff = coeff[posLast];
const uint32_t isNZCoeff = (curCoeff != 0); //是否为非零系数
// get L1 sig map
// NOTE: the new algorithm is complicated, so I keep reference code here
//uint32_t posy = posLast >> log2TrSize;
//uint32_t posx = posLast - (posy << log2TrSize);
//uint32_t blkIdx0 = ((posy >> MLS_CG_LOG2_SIZE) << codingParameters.log2TrSizeCG) + (posx >> MLS_CG_LOG2_SIZE);
//const uint32_t blkIdx = ((posLast >> (2 * MLS_CG_LOG2_SIZE)) & ~maskPosXY) + ((posLast >> MLS_CG_LOG2_SIZE) & maskPosXY);
//sigCoeffGroupFlag64 |= ((uint64_t)isNZCoeff << blkIdx);
numSig -= isNZCoeff; //非零系数减1
// TODO: optimize by instruction BTS
coeffSign[cgIdx] += (uint16_t)(((uint32_t)curCoeff >> 31) << coeffNum[cgIdx]); //
coeffFlag[cgIdx] = (coeffFlag[cgIdx] << 1) + (uint16_t)isNZCoeff;//
coeffNum[cgIdx] += (uint8_t)isNZCoeff; //非零系数个数
}
while (numSig > 0);
return scanPosLast - 1;
}
前三个语句初始化了三个数组,
该函数遍历CG系数组从第一个非零系数到最后一个非零系数,同时统计了TB块中的sig_coeff_flag语法元素(表示当前位置上的系数是否为0),coeff_sign_flag语法元素(用于表示非零系数是正值还是负值)和非零系数的数目,分别记录在coeffFlag, coeffSign, coeffNum数组中。
通过这个函数可以推断出x265对系数位置的表示,以对角扫描威力,首先因为它是从CG系数组中的最后一恶搞系数开始统计的,所以scanPosLast = 0表示的位置就是左上角的位置。
在看之前提到的scan参量,该数组所存储的对于8x8对焦萨摩顺序的数据为。
{ 0, 8, 1, 16, 9, 2, 24, 17, 10, 3, 25, 18, 11, 26, 19, 27, 32, 40, 33, 48, 41, 34, 56, 49, 42, 35, 57, 50, 43, 58, 51, 59, 4, 12, 5, 20, 13, 6, 28, 21, 14, 7, 29, 22, 15, 30, 23, 31, 36, 44, 37, 52, 45, 38, 60, 53, 46, 39, 61, 54, 47, 62, 55, 63 }
因此,未扫描钱, TB中的变换系数是从左上角开始,向右,逐行向下进行标序的。scanPosLast也是对CG中系数位置的特殊表述。
回到函数中,do循环就是遍历的过程,scanPosLast >> MLS_CG_SIZE 4,除16,表示当前系数所在的CG块,
根据前面所述,posLast变量就表示扫描当前系数在TB中的位置,curCoeff就存储该系数的值,
isNZCoeff = (curCoeff != 0) 判断该系数是否为非零系数,numSig 存储的是剩余非零系数个数。
coeffSign[cgIdx] += (uint16_t)((uint32_t)curCoeff >> 31) << coeffNum[cgIdx];
先将curCoeff右移31位,取出符号位,再左移当前所记录的非零系数数目,添加进数组中,可见数组中的一个数表示一个CG,其中有16位数,分别表示cg中16个数的coeff_sign_flag值,TB中位置靠前的再低位。
coeffFlag[cgIdx] = (coeffFlag[cgIdx] << 1) + (uint16_t)isNZCoeff;
采用同样的存储方法,但是在该数组中,TB中位置靠前的在高位,coeffNum就不用说了,最后scanPosLast - 1对应循环中的scanPosLast++, 返回正确值。