简单记录了最重要函数的调用关系:
encode()--->encode()--->compressGOP()--->compressSlice()
--->compressctu()--->xcompressCU()--->xCheckRDCostIntra()等等;
主要是对这几个函数的调用关系有些疑问,先记录下来,慢慢学习。
1.int main(int argc, char* argv[])
{
cTAppEncTop.encode();
}
2. cTAppEncTop.encode()
{
while ( !bEos )//由bEOS控制,循环调用encode对视频帧进行编码,好像是一帧循环一次???;
{
bEos = (m_isField && (m_iFrameRcvd == (m_framesToBeEncoded >> 1) )) || ( !m_isField && (m_iFrameRcvd == m_framesToBeEncoded) );
m_cTEncTop.encode();
}
}
3. TEncTop::encode()
{
m_cGOPEncoder.compressGOP();//以GOP为单位进行compress,所以跟上面矛盾了???;
}
4. TEncGOP::compressGOP()
{
for ( Int iGOPid=0; iGOPid < m_iGopSize; iGOPid++ )//循环次数是GOP中图像的数量,一帧就是一个slice;
{
for(UInt nextCtuTsAddr = 0; nextCtuTsAddr < numberOfCtusInFrame; )//循环系数是一帧中CTU的数量;
{
m_pcSliceEncoder->compressSlice ();//以slice为单位进行compress,所以与numberOfCtusInFrame矛盾?
nextCtuTsAddr =bSliceSegmentEnd;
}
m_pcSliceEncoder->encodeSlice();
}
}
5. TEncSlice::compressSlice()
{
//循环次数是一个slice中CTU的数量;
for( UInt ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ++ctuTsAddr )
{
m_pcCuEncoder->compressCtu( pCtu );//以CTU为单位进行compress;
m_pcCuEncoder->encodeCtu( pCtu );
}
}
6. TEncCu::compressCtu( TComDataCU* pCtu )
{
xCompressCU();
if (pCtu->getSlice()->isIntra())
{
xCompressCU();
}
}
7. TEncCu::xCompressCU()
{
1) if (bTestHorSplit) //如果要进行二叉树水平划分;
{
for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++)
{
for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 2; uiPartUnitIdx++ )//等于2是因为进行了二叉树划分;
{
xCompressCU();
}
xCheckBestMode ();
}
}
2) if (bTestVerSplit) //如果要进行二叉树垂直划分;
{
for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++)
{
for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 2; uiPartUnitIdx++ )//等于2是因为进行了二叉树划分;
{
xCompressCU();
}
xCheckBestMode ();
}
}
3)if( bQTSplit)//进行四叉树划分;
{
for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++)
{
for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 4; uiPartUnitIdx++ )//等于4是因为进行了四叉树划分;
{
xCompressCU();
}
xCheckBestMode ();
}
}
}
8. xCheckRDCostIntra()
{
estIntraPredLumaQT();
estIntraPredChromaQT();
xCheckBestMode();
}
9. estIntraPredLumaQT()(???有很多疑问)
{
getIntraDirPredictor();//得到6个MPMs;
for( Int modeIdx = 0; modeIdx < numModesAvailable; modeIdx++ )//循环结束,从原始35种原始模式中选取5个SADT最小的模式;
{
predIntraAng();
xModeBitsIntra();
updateCandList();
}
for( Int modeIdx = 0; modeIdx < numModesForFullRD; modeIdx++ )//对N中候选列表里的前3种模式用邻近角度模式进行更新;
{
for( Int subModeIdx = -1; subModeIdx <= 1; subModeIdx+=2 )
{
predIntraAng();
xModeBitsIntra();
updateCandList();
}
}
再将3种候选模式和2个MPMs合并;
for( UInt uiMode = 0; uiMode < numModesForFullRD; uiMode++ )//遍历uiRdModeList里的预测模式,根据RDcost选取一种最好的预测模式;
{
xRecurIntraCodingLumaQT();
if( dPUCost < dBestPUCost )
{
uiBestPUMode = uiOrgMode;
uiBestPUDistY = uiPUDistY;
dBestPUCost = dPUCost;
xSetIntraResultLumaQT();
}
}
}
10. estIntraPredChromaQT()
{
getAllowedChromaDir( uiPartOffset, uiModeList );//获得可用的色度预测模式,uiModeList里有11种候选模式;
for (UInt uiMode = LM_CHROMA_F1_IDX; uiMode < LM_CHROMA_F1_IDX + LM_FILTER_NUM; uiMode++)//遍历69,70,71,72 4种模式,计算每种模式的代价;
{
predLMIntraChroma();//用亮度分量预测Cb分量;
predLMIntraChroma();//用亮度分量预测Cr分量;
}
for( UInt uiMode = uiMinMode; uiMode < uiMaxMode; uiMode++ )//遍历11种帧内预测模式,选出一种最优的预测模式;
{
xRecurIntraChromaCodingQT ();
m_pcRdCost->calcRdCost();
if( dCost < dBestCost )//如果该模式的代价小于当前的最优代价,则将最优模式等相关数据更新;
{
dBestCost = dCost;
uiBestDist = uiDist;
uiBestMode = uiModeList[uiMode];
xSetIntraResultChromaQT( pcRecoYuv, tuRecurseWithPU );//保存最优模式的数据;
}
}
}