HEVC多次进行熵编码的原因

HEVC多次进行熵编码的原因



    在HM中有个让人很疑惑的地方,就是熵编码会被多次调用
    1、compressSlice中有两次
        (1)第一次是compressCU中,使用熵编码来进行RDO优化,用来选择最优的编码参数
        (2)第二次是紧接着compressCU后面调用了encodeCU
    2、encodeSlice中有一次
        (1)调用encodeCU


原因解释


    后来有大神解释了一下:
    1、在compressCU中调用熵编码,是为了进行RDO优化,这个比较好理解
    2、compressCU后面调用encodeCU,是为了保持CABAC的状态,因为熵编码是以slice为单位进行的,在一个slice中要保证这种状态的连续性,RDO的时候,在开始编码第二个CTU的时候的CABAC的状态得保证和第一个CTU熵编码完了以后的CABAC状态是一样的,因此要调用encodeCU
    3、在encodeSlice中调用encodeCU的目的是真正的熵编码
    4、另外需要注意的是,第一、二次调用熵编码操作不会写入比特流中,只有第三次调用才会写入比特流中。





在代码中的实现


Void TEncSlice::compressSlice( TComPic*& rpcPic )
{
	//***省略

	TEncTop* pcEncTop = (TEncTop*) m_pcCfg;


	TEncSbac**** ppppcRDSbacCoders    = pcEncTop->getRDSbacCoders();

	// 比特计数器
	TComBitCounter* pcBitCounters     = pcEncTop->getBitCounters();

	
	// ***省略

	for( uiEncCUOrder = uiStartCUAddr/rpcPic->getNumPartInCU();
		uiEncCUOrder < (uiBoundingCUAddr+(rpcPic->getNumPartInCU()-1))/rpcPic->getNumPartInCU();
		uiCUAddr = rpcPic->getPicSym()->getCUOrderMap(++uiEncCUOrder) )
	{
		// ***省略

		// set go-on entropy coder
		m_pcEntropyCoder->setEntropyCoder ( m_pcRDGoOnSbacCoder, pcSlice );
		// 注意这里,pcBitCounters是比特计数器,它和比特流类有相同的接口,但是只是用于比特计数,不会写数据到比特流中
		m_pcEntropyCoder->setBitstream( &pcBitCounters[uiSubStrm] );

		// 启用比特计数的功能
		((TEncBinCABAC*)m_pcRDGoOnSbacCoder->getEncBinIf())->setBinCountingEnableFlag(true);

		// ***
		
		// 选择最优的编码模式
		m_pcCuEncoder->compressCU( pcCU );

		// restore entropy coder to an initial stage
		m_pcEntropyCoder->setEntropyCoder ( m_pppcRDSbacCoder[0][CI_CURR_BEST], pcSlice );

		// 同样还是比特计数器
		m_pcEntropyCoder->setBitstream( &pcBitCounters[uiSubStrm] );
		m_pcCuEncoder->setBitCounter( &pcBitCounters[uiSubStrm] );

		m_pcBitCounter = &pcBitCounters[uiSubStrm];
		pppcRDSbacCoder->setBinCountingEnableFlag( true );
		m_pcBitCounter->resetBits();
		pppcRDSbacCoder->setBinsCoded( 0 );

		// 为了在一个slice保证CABAC状态的连续性,因为CABAC是以slice为单位的
		m_pcCuEncoder->encodeCU( pcCU );

		
		// *** 省略
	} // for end


	// ***省略
}


Void TEncSlice::encodeSlice   ( TComPic*& rpcPic, TComOutputBitstream* pcSubstreams )
{
	//*** 省略

	// 遍历条带中的每一个CU
	for( uiEncCUOrder = uiStartCUAddr /rpcPic->getNumPartInCU();
		uiEncCUOrder < (uiBoundingCUAddr+rpcPic->getNumPartInCU()-1)/rpcPic->getNumPartInCU();
		uiCUAddr = rpcPic->getPicSym()->getCUOrderMap(++uiEncCUOrder) )
	{
		// ***省略

		// 注意这里,pcSubstreams是比特流,不是比特计数器,因此,熵编码后会将数据写入比特流中
		m_pcEntropyCoder->setBitstream( &pcSubstreams[uiSubStrm] );
		
		// *** 省略
		if ( (m_pcCfg->getSliceMode()!=0 || m_pcCfg->getSliceSegmentMode()!=0) &&
			uiCUAddr == rpcPic->getPicSym()->getCUOrderMap((uiBoundingCUAddr+rpcPic->getNumPartInCU()-1)/rpcPic->getNumPartInCU()-1) )
		{
			// 和compressSlice一样调用了encodeCU函数,但是实现的功能已经不一样了
			// 因为compressSlice主要是进行帧内(帧间)最优模式的选择,还有变换、量化等功能
			// 而在这里,由于前面的几个步骤都已经进行完毕,所以,这里是单纯的进行熵编码
			m_pcCuEncoder->encodeCU( pcCU );
		}
		else
		{
			m_pcCuEncoder->encodeCU( pcCU );
		}

		// ***省略
	}
	// ***省略
}




评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值