您的位置:首页 > 编程语言

HM编码器代码阅读(44)——样点自适应补偿SAO(三)选取最优的SAO模式并确定补偿值

2017-02-22 20:01 411 查看

选取最优的SAO模式并确定补偿值

对像素值进行统计之后,需要确定应该SAO的哪一种模式,具体的方法是利用率失真优化的方式来确定最优的模式。同时还要得到该模式下的补偿值,后面就可以利用这个补偿值对像素块进行补偿(所谓补偿就是对像素值进行修正)。

选取最优模式和确定补偿值的主函数

选取最优模式和确定补偿值的主函数是decideBlkParams,流程如下:

1、对图像的每一个CTU进行处理

2、CTU尝试每一种SAO模式,选出最优的SAO模式

3、利用选取出来的SAO模式对重建块进行补偿

/*
** 选取最优模式
** 对图像的每一个CTU进行处理,对CTU尝试每一种SAO模式,选出最优的SAO模式
** 用选出来的最优SAO模式,对重建块进行处理
*/
Void TEncSampleAdaptiveOffset::decideBlkParams(TComPic* pic, Bool* sliceEnabled, SAOStatData*** blkStats, TComPicYuv* srcYuv, TComPicYuv* resYuv, SAOBlkParam* reconParams, SAOBlkParam* codedParams)
{
Bool isAllBlksDisabled = false;
if(!sliceEnabled[SAO_Y] && !sliceEnabled[SAO_Cb] && !sliceEnabled[SAO_Cr])
{
isAllBlksDisabled = true;
}

m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[ SAO_CABACSTATE_PIC_INIT ]);

SAOBlkParam modeParam;
Double minCost, modeCost;

// 遍历图像的所有CTU,对每一个CTU进行SAO处理
for(Int ctu=0; ctu< m_numCTUsPic; ctu++)
{
if(isAllBlksDisabled)
{
codedParams[ctu].reset();
continue;
}

m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[ SAO_CABACSTATE_BLK_CUR ]);

//get merge list
std::vector<SAOBlkParam*> mergeList;

// 获取merge列表
getMergeList(pic, ctu, reconParams, mergeList);

minCost = MAX_DOUBLE;
// 遍历所有的SAO模式
for(Int mode=0; mode < NUM_SAO_MODES; mode++)
{
switch(mode)
{
case SAO_MODE_OFF:
{
continue; //not necessary, since all-off case will be tested in SAO_MODE_NEW case.
}
break;
case SAO_MODE_NEW: // EO或者BO
{
deriveModeNewRDO(ctu, mergeList, sliceEnabled, blkStats, modeParam, modeCost, m_pppcRDSbacCoder, SAO_CABACSTATE_BLK_CUR);

}
break;
case SAO_MODE_MERGE: // merge模式
{
deriveModeMergeRDO(ctu, mergeList, sliceEnabled, blkStats , modeParam, modeCost, m_pppcRDSbacCoder, SAO_CABACSTATE_BLK_CUR);
}
break;
default:
{
printf("Not a supported SAO mode\n");
assert(0);
exit(-1);
}
}

// 选取最优的模式
if(modeCost < minCost)
{
minCost = modeCost;
codedParams[ctu] = modeParam;
m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[ SAO_CABACSTATE_BLK_NEXT ]);

}
} //mode
m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[ SAO_CABACSTATE_BLK_NEXT ]);

//apply reconstructed offsets
reconParams[ctu] = codedParams[ctu];
// 对重建像素块进行像素值补偿
reconstructBlkSAOParam(reconParams[ctu], mergeList);
offsetCTU(ctu, srcYuv, resYuv, reconParams[ctu], pic);
} //ctu

#if SAO_ENCODING_CHOICE
Int picTempLayer = pic->getSlice(0)->getDepth();
Int numLcusForSAOOff[NUM_SAO_COMPONENTS];
numLcusForSAOOff[SAO_Y ] = numLcusForSAOOff[SAO_Cb]= numLcusForSAOOff[SAO_Cr]= 0;

for (Int compIdx=0; compIdx<NUM_SAO_COMPONENTS; compIdx++)
{
for(Int ctu=0; ctu< m_numCTUsPic; ctu++)
{
if( reconParams[ctu][compIdx].modeIdc == SAO_MODE_OFF)
{
numLcusForSAOOff[compIdx]++;
}
}
}
#if SAO_ENCODING_CHOICE_CHROMA
for (Int compIdx=0; compIdx<NUM_SAO_COMPONENTS; compIdx++)
{
m_saoDisabledRate[compIdx][picTempLayer] = (Double)numLcusForSAOOff[compIdx]/(Double)m_numCTUsPic;
}
#else
if (picTempLayer == 0)
{
m_saoDisabledRate[SAO_Y][0] = (Double)(numLcusForSAOOff[SAO_Y]+numLcusForSAOOff[SAO_Cb]+numLcusForSAOOff[SAO_Cr])/(Double)(m_numCTUsPic*3);
}
#endif
#endif
}


选取EO和BO类别的最优模式

首先要明确,色度分量的SAO模式可以和亮度分量的SAO模式不同,但是两个色度分量的SAO模式是一样的

选取EO、BO类别的最优模式的流程如下:

1、对亮度分量进行操作

(1)尝试SAO_OFF模式,并计算代价

(2)尝试其余的SAO模式(EO、BO),选取出最优的模式

2、对色度分量

(1)尝试SAO_OFF模式,并计算代价

(2)对两个色度分量尝试其他的SAO模式(EO、BO),选取出最优的模式

3、通过步骤1和2得到了亮度和色度分量的最优SAO模式

选取EO和BO类别最优模式的函数

流程如下:

1、先确定亮度分量的最优模式

2、再确定色度分量的最优模式

/*
** 利用率失真优化,确定SAO的EO/BO类别的最优模式
*/
Void TEncSampleAdaptiveOffset::deriveModeNewRDO(Int ctu, std::vector<SAOBlkParam*>& mergeList, Bool* sliceEnabled, SAOStatData*** blkStats, SAOBlkParam& modeParam, Double& modeNormCost, TEncSbac** cabacCoderRDO, Int inCabacLabel)
{
Double minCost, cost;
Int rate;
UInt previousWrittenBits;

Int64 dist[NUM_SAO_COMPONENTS], modeDist[NUM_SAO_COMPONENTS];
SAOOffset testOffset[NUM_SAO_COMPONENTS];

Int compIdx;
Int invQuantOffset[MAX_NUM_SAO_CLASSES];

// 初始化模式的失真
modeDist[SAO_Y]= modeDist[SAO_Cb] = modeDist[SAO_Cr] = 0;

//pre-encode merge flags
// 预处理merge模式
modeParam[SAO_Y ].modeIdc = SAO_MODE_OFF;
m_pcRDGoOnSbacCoder->load(cabacCoderRDO[inCabacLabel]);
m_pcRDGoOnSbacCoder->codeSAOBlkParam(modeParam, sliceEnabled, (mergeList[SAO_MERGE_LEFT]!= NULL), (mergeList[SAO_MERGE_ABOVE]!= NULL), true);
m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_MID]);

// 【=========对亮度分量进行操作,目的是选出亮度分量的最优SAO模式-begin============】
//------ luma --------//
compIdx = SAO_Y;
//"off" case as initial cost
// 先尝试SAO-OFF(即关闭SAO)模式
modeParam[compIdx].modeIdc = SAO_MODE_OFF;
m_pcRDGoOnSbacCoder->resetBits();
m_pcRDGoOnSbacCoder->codeSAOOffsetParam(compIdx, modeParam[compIdx], sliceEnabled[compIdx]);
modeDist[compIdx] = 0;
// 计算代价
minCost= m_lambda[compIdx]*((Double)m_pcRDGoOnSbacCoder->getNumberOfWrittenBits());
m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]);

// 对SAO的EO、BO模式进行操作,选出最优的模式
if(sliceEnabled[compIdx])
{
for(Int typeIdc=0; typeIdc< NUM_SAO_NEW_TYPES; typeIdc++)
{
testOffset[compIdx].modeIdc = SAO_MODE_NEW;
testOffset[compIdx].typeIdc = typeIdc;

//derive coded offset
deriveOffsets(ctu, compIdx, typeIdc, blkStats[ctu][compIdx][typeIdc], testOffset[compIdx].offset, testOffset[compIdx].typeAuxInfo);

//inversed quantized offsets
invertQuantOffsets(compIdx, typeIdc, testOffset[compIdx].typeAuxInfo, invQuantOffset, testOffset[compIdx].offset);

//get distortion
dist[compIdx] = getDistortion(ctu, compIdx, testOffset[compIdx].typeIdc, testOffset[compIdx].typeAuxInfo, invQuantOffset, blkStats[ctu][compIdx][typeIdc]);

//get rate
m_pcRDGoOnSbacCoder->load(cabacCoderRDO[SAO_CABACSTATE_BLK_MID]);
m_pcRDGoOnSbacCoder->resetBits();
m_pcRDGoOnSbacCoder->codeSAOOffsetParam(compIdx, testOffset[compIdx], sliceEnabled[compIdx]);
rate = m_pcRDGoOnSbacCoder->getNumberOfWrittenBits();
cost = (Double)dist[compIdx] + m_lambda[compIdx]*((Double)rate);
if(cost < minCost)
{
minCost = cost;
modeDist[compIdx] = dist[compIdx];
modeParam[compIdx]= testOffset[compIdx];
m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]);
}
}
}
// 【=========对亮度分量进行操作,目的是选出亮度分量的最优SAO模式-end============】

m_pcRDGoOnSbacCoder->load(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]);
m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_MID]);

// 【=========对色度分量进行操作,目的是选出色度分量的最优模式-begin============】
/*
** 注意:色度分量的SAO模式可以和亮度分量的SAO模式不同
** 但是两个色度分量的SAO模式是一样的
*/
//------ chroma --------//
//"off" case as initial cost
cost = 0;
previousWrittenBits = 0;
m_pcRDGoOnSbacCoder->resetBits();
// 对两个色度分量,尝试SAO-OFF模式
for (Int component = SAO_Cb; component < NUM_SAO_COMPONENTS; component++)
{
modeParam[component].modeIdc = SAO_MODE_OFF;
modeDist [component] = 0;

m_pcRDGoOnSbacCoder->codeSAOOffsetParam(component, modeParam[component], sliceEnabled[component]);

const UInt currentWrittenBits = m_pcRDGoOnSbacCoder->getNumberOfWrittenBits();
cost += m_lambda[component] * (currentWrittenBits - previousWrittenBits);
previousWrittenBits = currentWrittenBits;
}

minCost = cost;

//doesn't need to store cabac status here since the whole CTU parameters will be re-encoded at the end of this function

// 对两个色度分量尝试其他的SAO模式(EO、BO)
for(Int typeIdc=0; typeIdc< NUM_SAO_NEW_TYPES; typeIdc++)
{
m_pcRDGoOnSbacCoder->load(cabacCoderRDO[SAO_CABACSTATE_BLK_MID]);
m_pcRDGoOnSbacCoder->resetBits();
previousWrittenBits = 0;
cost = 0;

for(compIdx= SAO_Cb; compIdx< NUM_SAO_COMPONENTS; compIdx++)
{
if(!sliceEnabled[compIdx])
{
testOffset[compIdx].modeIdc = SAO_MODE_OFF;
dist[compIdx]= 0;
continue;
}
testOffset[compIdx].modeIdc = SAO_MODE_NEW;
testOffset[compIdx].typeIdc = typeIdc;

//derive offset & get distortion
deriveOffsets(ctu, compIdx, typeIdc, blkStats[ctu][compIdx][typeIdc], testOffset[compIdx].offset, testOffset[compIdx].typeAuxInfo);
invertQuantOffsets(compIdx, typeIdc, testOffset[compIdx].typeAuxInfo, invQuantOffset, testOffset[compIdx].offset);
dist[compIdx]= getDistortion(ctu, compIdx, typeIdc, testOffset[compIdx].typeAuxInfo, invQuantOffset, blkStats[ctu][compIdx][typeIdc]);

m_pcRDGoOnSbacCoder->codeSAOOffsetParam(compIdx, testOffset[compIdx], sliceEnabled[compIdx]);

const UInt currentWrittenBits = m_pcRDGoOnSbacCoder->getNumberOfWrittenBits();
cost += dist[compIdx] + (m_lambda[compIdx] * (currentWrittenBits - previousWrittenBits));
previousWrittenBits = currentWrittenBits;
}

// 选出最优的模式
if(cost < minCost)
{
minCost = cost;
for(compIdx= SAO_Cb; compIdx< NUM_SAO_COMPONENTS; compIdx++)
{
modeDist [compIdx] = dist      [compIdx];
modeParam[compIdx] = testOffset[compIdx];
}
}
}
// 【=========对色度分量进行操作,目的是选出色度分量的最优模式-end============】

// 到了这里已经选出了亮度和色度分量的最优SAO模式了

//----- re-gen rate & normalized cost----//

modeNormCost = 0;
for(UInt component = SAO_Y; component < NUM_SAO_COMPONENTS; component++)
{
modeNormCost += (Double)modeDist[component] / m_lambda[component];
}
m_pcRDGoOnSbacCoder->load(cabacCoderRDO[inCabacLabel]);
m_pcRDGoOnSbacCoder->resetBits();
m_pcRDGoOnSbacCoder->codeSAOBlkParam(modeParam, sliceEnabled, (mergeList[SAO_MERGE_LEFT]!= NULL), (mergeList[SAO_MERGE_ABOVE]!= NULL), false);
modeNormCost += (Double)m_pcRDGoOnSbacCoder->getNumberOfWrittenBits();

}


确定补偿值

确定补偿值的流程如下:

1、确定初始的补偿值

2、调整补偿值,得到最优的补偿值

/*
** 得到最优的补偿值
** 该函数EO和BO共用
*/
Void TEncSampleAdaptiveOffset::deriveOffsets(Int ctu, Int compIdx, Int typeIdc, SAOStatData& statData, Int* quantOffsets, Int& typeAuxInfo)
{
Int bitDepth = (compIdx== SAO_Y) ? g_bitDepthY : g_bitDepthC;
Int shift = 2 * DISTORTION_PRECISION_ADJUSTMENT(bitDepth-8);
Int offsetTh = g_saoMaxOffsetQVal[compIdx];  //inclusive

::memset(quantOffsets, 0, sizeof(Int)*MAX_NUM_SAO_CLASSES);

//derive initial offsets
Int numClasses = (typeIdc == SAO_TYPE_BO)?((Int)NUM_SAO_BO_CLASSES):((Int)NUM_SAO_EO_CLASSES);
// 遍历EO或者BO下的所有类型,确定初始的补偿值
for(Int classIdx=0; classIdx< numClasses; classIdx++)
{
if( (typeIdc != SAO_TYPE_BO) && (classIdx==SAO_CLASS_EO_PLAIN)  )
{
continue; //offset will be zero
}

if(statData.count[classIdx] == 0)
{
continue; //offset will be zero
}

quantOffsets[classIdx] = (Int) xRoundIbdi(bitDepth, (Double)( statData.diff[classIdx]<<(bitDepth-8))
/
(Double)( statData.count[classIdx]<< m_offsetStepLog2[compIdx])
);
quantOffsets[classIdx] = Clip3(-offsetTh, offsetTh, quantOffsets[classIdx]);
}

// adjust offsets
// 调整补偿值
switch(typeIdc)
{
case SAO_TYPE_EO_0:
case SAO_TYPE_EO_90:
case SAO_TYPE_EO_135:
case SAO_TYPE_EO_45:
{
Int64 classDist;
Double classCost;
for(Int classIdx=0; classIdx<NUM_SAO_EO_CLASSES; classIdx++)
{
if(classIdx==SAO_CLASS_EO_FULL_VALLEY && quantOffsets[classIdx] < 0) quantOffsets[classIdx] =0;
if(classIdx==SAO_CLASS_EO_HALF_VALLEY && quantOffsets[classIdx] < 0) quantOffsets[classIdx] =0;
if(classIdx==SAO_CLASS_EO_HALF_PEAK   && quantOffsets[classIdx] > 0) quantOffsets[classIdx] =0;
if(classIdx==SAO_CLASS_EO_FULL_PEAK   && quantOffsets[classIdx] > 0) quantOffsets[classIdx] =0;

// 如果补偿值不为0,那么进行调整,以得到最优的补偿值
if( quantOffsets[classIdx] != 0 ) //iterative adjustment only when derived offset is not zero
{
quantOffsets[classIdx] = estIterOffset( typeIdc, classIdx, m_lambda[compIdx], quantOffsets[classIdx], statData.count[classIdx], statData.diff[classIdx], shift, m_offsetStepLog2[compIdx], classDist , classCost , offsetTh );
}
}

typeAuxInfo =0;
}
break;
case SAO_TYPE_BO:
{
Int64  distBOClasses[NUM_SAO_BO_CLASSES];
Double costBOClasses[NUM_SAO_BO_CLASSES];
::memset(distBOClasses, 0, sizeof(Int64)*NUM_SAO_BO_CLASSES);
for(Int classIdx=0; classIdx< NUM_SAO_BO_CLASSES; classIdx++)
{
costBOClasses[classIdx]= m_lambda[compIdx];
// 如果补偿值不为0,那么进行调整,以得到最优的补偿值
if( quantOffsets[classIdx] != 0 ) //iterative adjustment only when derived offset is not zero
{
quantOffsets[classIdx] = estIterOffset( typeIdc, classIdx, m_lambda[compIdx], quantOffsets[classIdx], statData.count[classIdx], statData.diff[classIdx], shift, m_offsetStepLog2[compIdx], distBOClasses[classIdx], costBOClasses[classIdx], offsetTh );
}
}

//decide the starting band index
Double minCost = MAX_DOUBLE, cost;
for(Int band=0; band< NUM_SAO_BO_CLASSES- 4+ 1; band++)
{
cost  = costBOClasses[band  ];
cost += costBOClasses[band+1];
cost += costBOClasses[band+2];
cost += costBOClasses[band+3];

if(cost < minCost)
{
minCost = cost;
typeAuxInfo = band;
}
}
//clear those unused classes
Int clearQuantOffset[NUM_SAO_BO_CLASSES];
::memset(clearQuantOffset, 0, sizeof(Int)*NUM_SAO_BO_CLASSES);
for(Int i=0; i< 4; i++)
{
Int band = (typeAuxInfo+i)%NUM_SAO_BO_CLASSES;
clearQuantOffset[band] = quantOffsets[band];
}
::memcpy(quantOffsets, clearQuantOffset, sizeof(Int)*NUM_SAO_BO_CLASSES);
}
break;
default:
{
printf("Not a supported type");
assert(0);
exit(-1);
}

}
}


对补偿值进行调整

对补偿值调整的目的是得到最优的补偿值

inline Int TEncSampleAdaptiveOffset::estIterOffset(Int typeIdx, Int classIdx, Double lambda, Int offsetInput, Int64 count, Int64 diffSum, Int shift, Int bitIncrease, Int64& bestDist, Double& bestCost, Int offsetTh )
{
Int iterOffset, tempOffset;
Int64 tempDist, tempRate;
Double tempCost, tempMinCost;
Int offsetOutput = 0;
iterOffset = offsetInput;
// Assuming sending quantized value 0 results in zero offset and sending the value zero needs 1 bit. entropy coder can be used to measure the exact rate here.
tempMinCost = lambda;
while (iterOffset != 0)
{
// Calculate the bits required for signaling the offset
tempRate = (typeIdx == SAO_TYPE_BO) ? (abs((Int)iterOffset)+2) : (abs((Int)iterOffset)+1);
if (abs((Int)iterOffset)==offsetTh) //inclusive
{
tempRate --;
}
// Do the dequantization before distortion calculation
tempOffset  = iterOffset << bitIncrease;
tempDist    = estSaoDist( count, tempOffset, diffSum, shift);
tempCost    = ((Double)tempDist + lambda * (Double) tempRate);
if(tempCost < tempMinCost)
{
tempMinCost = tempCost;
offsetOutput = iterOffset;
bestDist = tempDist;
bestCost = tempCost;
}
iterOffset = (iterOffset > 0) ? (iterOffset-1):(iterOffset+1);
}
return offsetOutput;
}


选取merge类别的最优模式

在SAO的merge模式中,merge是一个大类,它包含两种方式:

1、与左边的CTU的SAO参数进行合并

2、与上面的CTU的SAO参数进行合并

因此,首先应该获取候选的merge模式列表,然后遍历候选列表,选取最优的合并方式。另外,因为merge模式是和相邻CTU贡献SAO参数,因此不需要计算补偿值。

获取merge模式的候选列表

/*
** 获取SAO的merge模式的候选列表
*/
Int TComSampleAdaptiveOffset::getMergeList(TComPic* pic, Int ctu, SAOBlkParam* blkParams, std::vector<SAOBlkParam*>& mergeList)
{
Int ctuX = ctu % m_numCTUInWidth;
Int ctuY = ctu / m_numCTUInWidth;
Int mergedCTUPos;
Int numValidMergeCandidates = 0;

// 遍历所有的merge模式
for(Int mergeType=0; mergeType< NUM_SAO_MERGE_TYPES; mergeType++)
{
SAOBlkParam* mergeCandidate = NULL;

switch(mergeType)
{
case SAO_MERGE_ABOVE: // 和上面的CTU合并
{
if(ctuY > 0)
{
mergedCTUPos = ctu- m_numCTUInWidth;
if( pic->getSAOMergeAvailability(ctu, mergedCTUPos) )
{
mergeCandidate = &(blkParams[mergedCTUPos]);
}
}
}
break;
case SAO_MERGE_LEFT: // 和左边的CTU合并
{
if(ctuX > 0)
{
mergedCTUPos = ctu- 1;
if( pic->getSAOMergeAvailability(ctu, mergedCTUPos) )
{
mergeCandidate = &(blkParams[mergedCTUPos]);
}
}
}
break;
default:
{
printf("not a supported merge type");
assert(0);
exit(-1);
}
}

// 把候选模式压入列表中
mergeList.push_back(mergeCandidate);
if (mergeCandidate != NULL)
{
numValidMergeCandidates++;
}
}

return numValidMergeCandidates;
}


计算merge模式的最优合并方式

遍历候选列表,通过率失真优化的方式选取最优的模式

/*
** 利用率失真优化,确定SAO的merge模式的最优合并方式
*/
Void TEncSampleAdaptiveOffset::deriveModeMergeRDO(Int ctu, std::vector<SAOBlkParam*>& mergeList, Bool* sliceEnabled, SAOStatData*** blkStats, SAOBlkParam& modeParam, Double& modeNormCost, TEncSbac** cabacCoderRDO, Int inCabacLabel)
{
Int mergeListSize = (Int)mergeList.size();
modeNormCost = MAX_DOUBLE;

Double cost;
SAOBlkParam testBlkParam;

// 遍历merge模式的候选列表
for(Int mergeType=0; mergeType< mergeListSize; mergeType++)
{
if(mergeList[mergeType] == NULL)
{
continue;
}

testBlkParam = *(mergeList[mergeType]);
//normalized distortion
Double normDist=0;

// 依次处理三个分量
for(Int compIdx=0; compIdx< NUM_SAO_COMPONENTS; compIdx++)
{
testBlkParam[compIdx].modeIdc = SAO_MODE_MERGE;
testBlkParam[compIdx].typeIdc = mergeType;

SAOOffset& mergedOffsetParam = (*(mergeList[mergeType]))[compIdx];

if( mergedOffsetParam.modeIdc != SAO_MODE_OFF)
{
//offsets have been reconstructed. Don't call inversed quantization function.
// 计算失真
normDist += (((Double)getDistortion(ctu, compIdx, mergedOffsetParam.typeIdc, mergedOffsetParam.typeAuxInfo, mergedOffsetParam.offset, blkStats[ctu][compIdx][mergedOffsetParam.typeIdc]))
/m_lambda[compIdx]
);
}

}

//rate
m_pcRDGoOnSbacCoder->load(cabacCoderRDO[inCabacLabel]);
m_pcRDGoOnSbacCoder->resetBits();
m_pcRDGoOnSbacCoder->codeSAOBlkParam(testBlkParam, sliceEnabled, (mergeList[SAO_MERGE_LEFT]!= NULL), (mergeList[SAO_MERGE_ABOVE]!= NULL), false);
Int rate = m_pcRDGoOnSbacCoder->getNumberOfWrittenBits();

cost = normDist+(Double)rate;

// 选取最优模式
if(cost < modeNormCost)
{
modeNormCost = cost;
modeParam    = testBlkParam;
m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]);
}
}

m_pcRDGoOnSbacCoder->load(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]);

}


通过比较得到所有模式中最优的模式

在decideBlkParams函数中,得到了EO、BO的最优模式以及merge的最优模式之后,要对他们的率失真代价进行比较,来得到它们之中最优的一个。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: