HM编码器代码阅读(11)——CU的初始化

入口函数TComDataCU::initCU
主要流程:
(1)计算当前LCU在图像中的像素地址
(2)计算LCU可以被分成多少个4x4的CU
(3)把片的起始CU的地址存储起来
(4)设置每一个4x4子CU的参数信息
(5)设置当前LCU的左边、上方、右上角、左上角的相邻的LCU

(6)设置参考帧的数组

// 编码单元初始化
Void TComDataCU::initCU( TComPic* pcPic, UInt iCUAddr )
{
	// 当前CU所属的图像
	m_pcPic              = pcPic;
	// 当前CU所属的slice
	m_pcSlice            = pcPic->getSlice(pcPic->getCurrSliceIdx());
	// CU的地址
	m_uiCUAddr           = iCUAddr;
	// LCU在图像中的实际像素地址
	m_uiCUPelX           = ( iCUAddr % pcPic->getFrameWidthInCU() ) * g_uiMaxCUWidth;
	m_uiCUPelY           = ( iCUAddr / pcPic->getFrameWidthInCU() ) * g_uiMaxCUHeight;
	m_uiAbsIdxInLCU      = 0;
	// 总的RD消耗
	m_dTotalCost         = MAX_DOUBLE;
	// 总的失真
	m_uiTotalDistortion  = 0;
	// 总的比特数
	m_uiTotalBits        = 0;
	// 总的二进制数
	m_uiTotalBins        = 0;

	// 一帧图像最多可以分成256个CU(即深度是4,2^4 * 2^4 = 256)
	m_uiNumPartition     = pcPic->getNumPartInCU();

	// m_sliceStartCU初始化之后全都是0
	for(Int i=0; i<pcPic->getNumPartInCU(); i++)
	{
		if(pcPic->getPicSym()->getInverseCUOrderMap(iCUAddr)*pcPic->getNumPartInCU()+i>=getSlice()->getSliceCurStartCUAddr())
		{
			// 设置条带开始的CU的地址放到一个数组中
			m_sliceStartCU[i]=getSlice()->getSliceCurStartCUAddr();
		}
		else
		{
			// 获取slice中的所有CU,存放到一个数组中
			m_sliceStartCU[i]=pcPic->getCU(getAddr())->m_sliceStartCU[i];
		}
	}

	for(Int i=0; i<pcPic->getNumPartInCU(); i++)
	{
		if(pcPic->getPicSym()->getInverseCUOrderMap(iCUAddr)*pcPic->getNumPartInCU()+i>=getSlice()->getSliceSegmentCurStartCUAddr())
		{
			m_sliceSegmentStartCU[i]=getSlice()->getSliceSegmentCurStartCUAddr();
		}
		else
		{
			// 获取所有的条带片段中的CU,存放到数组中
			m_sliceSegmentStartCU[i]=pcPic->getCU(getAddr())->m_sliceSegmentStartCU[i];
		}
	}

	// getInverseCUOrderMap 这个函数是根据CU的地址获取CU的顺序索引
	Int partStartIdx = getSlice()->getSliceSegmentCurStartCUAddr() - pcPic->getPicSym()->getInverseCUOrderMap(iCUAddr) * pcPic->getNumPartInCU();

	// 元素的个数
	Int numElements = min<Int>( partStartIdx, m_uiNumPartition );
	for ( Int ui = 0; ui < numElements; ui++ )
	{
		TComDataCU * pcFrom = pcPic->getCU(getAddr());
		m_skipFlag[ui]   = pcFrom->getSkipFlag(ui);
		m_pePartSize[ui] = pcFrom->getPartitionSize(ui);
		m_pePredMode[ui] = pcFrom->getPredictionMode(ui);
		m_CUTransquantBypass[ui] = pcFrom->getCUTransquantBypass(ui);
		m_puhDepth[ui] = pcFrom->getDepth(ui);
		m_puhWidth  [ui] = pcFrom->getWidth(ui);
		m_puhHeight [ui] = pcFrom->getHeight(ui);
		m_puhTrIdx  [ui] = pcFrom->getTransformIdx(ui);
		m_puhTransformSkip[0][ui] = pcFrom->getTransformSkip(ui,TEXT_LUMA);
		m_puhTransformSkip[1][ui] = pcFrom->getTransformSkip(ui,TEXT_CHROMA_U);
		m_puhTransformSkip[2][ui] = pcFrom->getTransformSkip(ui,TEXT_CHROMA_V);
		m_apiMVPIdx[0][ui] = pcFrom->m_apiMVPIdx[0][ui];;
		m_apiMVPIdx[1][ui] = pcFrom->m_apiMVPIdx[1][ui];
		m_apiMVPNum[0][ui] = pcFrom->m_apiMVPNum[0][ui];
		m_apiMVPNum[1][ui] = pcFrom->m_apiMVPNum[1][ui];
		m_phQP[ui]=pcFrom->m_phQP[ui];
		m_pbMergeFlag[ui]=pcFrom->m_pbMergeFlag[ui];
		m_puhMergeIndex[ui]=pcFrom->m_puhMergeIndex[ui];
		m_puhLumaIntraDir[ui]=pcFrom->m_puhLumaIntraDir[ui];
		m_puhChromaIntraDir[ui]=pcFrom->m_puhChromaIntraDir[ui];
		m_puhInterDir[ui]=pcFrom->m_puhInterDir[ui];
		m_puhCbf[0][ui]=pcFrom->m_puhCbf[0][ui];
		m_puhCbf[1][ui]=pcFrom->m_puhCbf[1][ui];
		m_puhCbf[2][ui]=pcFrom->m_puhCbf[2][ui];
		m_pbIPCMFlag[ui] = pcFrom->m_pbIPCMFlag[ui];
	}

	// 第一个元素
	Int firstElement = max<Int>( partStartIdx, 0 );

	// 元素的个数
	numElements = m_uiNumPartition - firstElement;

	if ( numElements > 0 )
	{
		memset( m_skipFlag          + firstElement, false,                    numElements * sizeof( *m_skipFlag ) );

		memset( m_pePartSize        + firstElement, SIZE_NONE,                numElements * sizeof( *m_pePartSize ) );
		memset( m_pePredMode        + firstElement, MODE_NONE,                numElements * sizeof( *m_pePredMode ) );
		memset( m_CUTransquantBypass+ firstElement, false,                    numElements * sizeof( *m_CUTransquantBypass) );
		memset( m_puhDepth          + firstElement, 0,                        numElements * sizeof( *m_puhDepth ) );
		memset( m_puhTrIdx          + firstElement, 0,                        numElements * sizeof( *m_puhTrIdx ) );
		memset( m_puhTransformSkip[0] + firstElement, 0,                      numElements * sizeof( *m_puhTransformSkip[0]) );
		memset( m_puhTransformSkip[1] + firstElement, 0,                      numElements * sizeof( *m_puhTransformSkip[1]) );
		memset( m_puhTransformSkip[2] + firstElement, 0,                      numElements * sizeof( *m_puhTransformSkip[2]) );
		memset( m_puhWidth          + firstElement, g_uiMaxCUWidth,           numElements * sizeof( *m_puhWidth ) );
		memset( m_puhHeight         + firstElement, g_uiMaxCUHeight,          numElements * sizeof( *m_puhHeight ) );
		memset( m_apiMVPIdx[0]      + firstElement, -1,                       numElements * sizeof( *m_apiMVPIdx[0] ) );
		memset( m_apiMVPIdx[1]      + firstElement, -1,                       numElements * sizeof( *m_apiMVPIdx[1] ) );
		memset( m_apiMVPNum[0]      + firstElement, -1,                       numElements * sizeof( *m_apiMVPNum[0] ) );
		memset( m_apiMVPNum[1]      + firstElement, -1,                       numElements * sizeof( *m_apiMVPNum[1] ) );
		memset( m_phQP              + firstElement, getSlice()->getSliceQp(), numElements * sizeof( *m_phQP ) );
		memset( m_pbMergeFlag       + firstElement, false,                    numElements * sizeof( *m_pbMergeFlag ) );
		memset( m_puhMergeIndex     + firstElement, 0,                        numElements * sizeof( *m_puhMergeIndex ) );
		memset( m_puhLumaIntraDir   + firstElement, DC_IDX,                   numElements * sizeof( *m_puhLumaIntraDir ) );
		memset( m_puhChromaIntraDir + firstElement, 0,                        numElements * sizeof( *m_puhChromaIntraDir ) );
		memset( m_puhInterDir       + firstElement, 0,                        numElements * sizeof( *m_puhInterDir ) );
		memset( m_puhCbf[0]         + firstElement, 0,                        numElements * sizeof( *m_puhCbf[0] ) );
		memset( m_puhCbf[1]         + firstElement, 0,                        numElements * sizeof( *m_puhCbf[1] ) );
		memset( m_puhCbf[2]         + firstElement, 0,                        numElements * sizeof( *m_puhCbf[2] ) );
		memset( m_pbIPCMFlag        + firstElement, false,                    numElements * sizeof( *m_pbIPCMFlag ) );
	}

	UInt uiTmp = g_uiMaxCUWidth*g_uiMaxCUHeight;
	if ( 0 >= partStartIdx ) 
	{
		m_acCUMvField[0].clearMvField();
		m_acCUMvField[1].clearMvField();
		memset( m_pcTrCoeffY , 0, sizeof( TCoeff ) * uiTmp );
#if ADAPTIVE_QP_SELECTION
		memset( m_pcArlCoeffY , 0, sizeof( Int ) * uiTmp );  
#endif
		memset( m_pcIPCMSampleY , 0, sizeof( Pel ) * uiTmp );
		uiTmp  >>= 2;
		memset( m_pcTrCoeffCb, 0, sizeof( TCoeff ) * uiTmp );
		memset( m_pcTrCoeffCr, 0, sizeof( TCoeff ) * uiTmp );
#if ADAPTIVE_QP_SELECTION  
		memset( m_pcArlCoeffCb, 0, sizeof( Int ) * uiTmp );
		memset( m_pcArlCoeffCr, 0, sizeof( Int ) * uiTmp );
#endif
		memset( m_pcIPCMSampleCb , 0, sizeof( Pel ) * uiTmp );
		memset( m_pcIPCMSampleCr , 0, sizeof( Pel ) * uiTmp );
	}
	else 
	{
		TComDataCU * pcFrom = pcPic->getCU(getAddr());
		m_acCUMvField[0].copyFrom(&pcFrom->m_acCUMvField[0],m_uiNumPartition,0);
		m_acCUMvField[1].copyFrom(&pcFrom->m_acCUMvField[1],m_uiNumPartition,0);
		for(Int i=0; i<uiTmp; i++)
		{
			m_pcTrCoeffY[i]=pcFrom->m_pcTrCoeffY[i];
#if ADAPTIVE_QP_SELECTION
			m_pcArlCoeffY[i]=pcFrom->m_pcArlCoeffY[i];
#endif
			m_pcIPCMSampleY[i]=pcFrom->m_pcIPCMSampleY[i];
		}
		for(Int i=0; i<(uiTmp>>2); i++)
		{
			m_pcTrCoeffCb[i]=pcFrom->m_pcTrCoeffCb[i];
			m_pcTrCoeffCr[i]=pcFrom->m_pcTrCoeffCr[i];
#if ADAPTIVE_QP_SELECTION
			m_pcArlCoeffCb[i]=pcFrom->m_pcArlCoeffCb[i];
			m_pcArlCoeffCr[i]=pcFrom->m_pcArlCoeffCr[i];
#endif
			m_pcIPCMSampleCb[i]=pcFrom->m_pcIPCMSampleCb[i];
			m_pcIPCMSampleCr[i]=pcFrom->m_pcIPCMSampleCr[i];
		}
	}

	// Setting neighbor CU
	// 设置相邻CU
	m_pcCULeft        = NULL;			// 左边的CU
	m_pcCUAbove       = NULL;			// 上面的CU
	m_pcCUAboveLeft   = NULL;		// 左上方的CU
	m_pcCUAboveRight  = NULL;		// 右上方的CU

	// 位置数组,有两个元素
	m_apcCUColocated[0] = NULL;
	m_apcCUColocated[1] = NULL;

	// 获取一帧图片中,横向上CU的个数
	UInt uiWidthInCU = pcPic->getFrameWidthInCU();

	// 分别获取当前CU各个方向上相邻的CU

	// 如果CU地址不为图片上横向上CU个数的整数倍,那么它的左边有CU
	if ( m_uiCUAddr % uiWidthInCU )
	{
		m_pcCULeft = pcPic->getCU( m_uiCUAddr - 1 );
	}

	// 如果CU地址不为图像纵向上CU个数的整数倍,那么它的上方存在CU
	if ( m_uiCUAddr / uiWidthInCU )
	{
		m_pcCUAbove = pcPic->getCU( m_uiCUAddr - uiWidthInCU );
	}

	// 如果左边有CU,上方有CU,那么当前CU的上面有CU
	if ( m_pcCULeft && m_pcCUAbove )
	{
		m_pcCUAboveLeft = pcPic->getCU( m_uiCUAddr - uiWidthInCU - 1 );
	}

	// 如果上边有CU,而且当前CU不是当前行最后一个CU,那么它的右上角有CU
	if ( m_pcCUAbove && ( (m_uiCUAddr%uiWidthInCU) < (uiWidthInCU-1) )  )
	{
		m_pcCUAboveRight = pcPic->getCU( m_uiCUAddr - uiWidthInCU + 1 );
	}

	// getNumRefIdx从参考图片数组(数组0或1)获取参考图片的数量
	if ( getSlice()->getNumRefIdx( REF_PIC_LIST_0 ) > 0 )
	{
		m_apcCUColocated[0] = getSlice()->getRefPic( REF_PIC_LIST_0, 0)->getCU( m_uiCUAddr );
	}

	if ( getSlice()->getNumRefIdx( REF_PIC_LIST_1 ) > 0 )
	{
		m_apcCUColocated[1] = getSlice()->getRefPic( REF_PIC_LIST_1, 0)->getCU( m_uiCUAddr );
	}
}


  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值