HM编码器代码阅读(9)——片编码器的初始化

入口函数:TEncSlice::initEncSlice。
在处理图像组的时候,遍历图像组的每一帧,对每一帧调用 TEncSlice::initEncSlice。主要是设置和计算一些参数,为片的编码做准备。
主要功能包括:
(1)取出当前帧的第一片(HM15中每一帧只被划分成一片)
(2)设置片的SPS(序列参数集)和PPS(图像参数集)
(3)设置片所属的帧;片初始化(TComSlice::initSlice);设置片的poc
(4)设置片的类型。
(5)根据片的类型和poc等参数,设置当前片是否允许被别人参考
(6)设置量化步长(QP), λ参数数组
(7)设置片的参考帧数组中可用(或者活跃)的图像的个数
(8)去方块滤波相关标志的设置
(9)设置片的深度,帧和片所属的时域层
(10)设置预测图像缓存和残差图像缓存
// 片编码器的初始化
Void TEncSlice::initEncSlice( TComPic* pcPic, Int pocLast, Int pocCurr, Int iNumPicRcvd, Int iGOPid, TComSlice*& rpcSlice, TComSPS* pSPS, TComPPS *pPPS, bool isField )
{
	Double dQP;
	Double dLambda;

	// 将rpcSlice设置为图像的第一个条带
	rpcSlice = pcPic->getSlice(0);
	rpcSlice->setSPS( pSPS );
	rpcSlice->setPPS( pPPS );

	// 设置条带的bit数量
	rpcSlice->setSliceBits(0);

	// 设置条带所属的图像
	rpcSlice->setPic( pcPic );

	// 条带初始化
	rpcSlice->initSlice();
    // 图像输出标志
	rpcSlice->setPicOutputFlag( true );

	// 设置条带的poc(picture of counter)
	rpcSlice->setPOC( pocCurr );

	// depth computation based on GOP size
    // 计算深度
	Int depth;
	{
#if FIX_FIELD_DEPTH    
		Int poc = rpcSlice->getPOC();
		if(isField)
		{
			poc = (poc/2)%(m_pcCfg->getGOPSize()/2);
		}
		else
		{
			LOG_DEBUG("m_pcCfg->getGOPSize()=%d",m_pcCfg->getGOPSize());
			poc = poc%m_pcCfg->getGOPSize();   
		}
#else
		Int poc = rpcSlice->getPOC()%m_pcCfg->getGOPSize();
#endif
        // 对于GOP中的第一帧
		if ( poc == 0 )
		{
			depth = 0;
		}
		else
		{
            // 一般说一个GOP的大小都是固定的(即一个GOP通常包含固定数量的帧)
			Int step = m_pcCfg->getGOPSize();
			depth    = 0;
			for( Int i=step>>1; i>=1; i>>=1 )
			{
				for ( Int j=i; j<m_pcCfg->getGOPSize(); j+=step )
				{
					if ( j == poc )
					{
						i=0;
						break;
					}
				}
				step >>= 1;
				depth++;
			}
		}
#if FIX_FIELD_DEPTH  
#if HARMONIZE_GOP_FIRST_FIELD_COUPLE
		if(poc != 0)
		{
#endif
			if(isField && rpcSlice->getPOC()%2 == 1)
			{
				depth ++;
			}
#if HARMONIZE_GOP_FIRST_FIELD_COUPLE
		}
#endif
#endif
	}

	// slice type
	// 条带类型
	//	B_SLICE,B类型
	// P_SLICE,P类型
	// I_SLICE,I类型
	SliceType eSliceType;

    // 初始的帧的类型是B
	eSliceType=B_SLICE;
#if EFFICIENT_FIELD_IRAP
	if(!(isField && pocLast == 1))
	{
		// 总是会进入这里,因为isField是false
#endif // EFFICIENT_FIELD_IRAP
#if ALLOW_RECOVERY_POINT_AS_RAP

        // 解码刷新类型
		if(m_pcCfg->getDecodingRefreshType() == 3)
		{
            eSliceType = (pocLast == 0 // 如果是GOP的第一帧
                          || pocCurr % m_pcCfg->getIntraPeriod() == 0   // 如果刚好是I帧
                          || m_pcGOPEncoder->getGOPSize() == 0) // 如果GOP的尺寸是0,满足这三种情况之一者的片的类型都是I片
                    ? I_SLICE : eSliceType;
		}
		else
		{
            // 判断和上面的类似
            eSliceType = (pocLast == 0
                          || (pocCurr - isField) % m_pcCfg->getIntraPeriod() == 0
                          || m_pcGOPEncoder->getGOPSize() == 0)
                    ? I_SLICE : eSliceType;
		}
#else
		eSliceType = (pocLast == 0 || (pocCurr - isField) % m_pcCfg->getIntraPeriod() == 0 || m_pcGOPEncoder->getGOPSize() == 0) ? I_SLICE : eSliceType;
#endif
#if EFFICIENT_FIELD_IRAP
	}
#endif

	rpcSlice->setSliceType    ( eSliceType );

	// ------------------------------------------------------------------------------------------------------------------
	// Non-referenced frame marking
	// ------------------------------------------------------------------------------------------------------------------

    // 如果是GOP的第一帧,那么它应该可以被别人参考,所以设置被参考的标志(时域层的)
	if(pocLast == 0)
	{
		rpcSlice->setTemporalLayerNonReferenceFlag(false);
	}
	else
	{
		rpcSlice->setTemporalLayerNonReferenceFlag(!m_pcCfg->getGOPEntry(iGOPid).m_refPic);
	}

	// 该条带可以被参考
	rpcSlice->setReferenced(true);

	// ------------------------------------------------------------------------------------------------------------------
	// QP setting 量化设置
	// ------------------------------------------------------------------------------------------------------------------

    // 量化步长
	dQP = m_pcCfg->getQP();
    // 如果不是I片
	if(eSliceType!=I_SLICE)
	{
        if (!(( m_pcCfg->getMaxDeltaQP() == 0 )
              && (dQP == -rpcSlice->getSPS()->getQpBDOffsetY() )
              && (rpcSlice->getPPS()->getTransquantBypassEnableFlag())))
		{
            // 加上对应的偏移
			dQP += m_pcCfg->getGOPEntry(iGOPid).m_QPOffset;
		}
	}

	// modify QP
    // 每一帧在数组中都有对应的一个位置存放QP
	Int* pdQPs = m_pcCfg->getdQPs();

	if ( pdQPs )
	{
        // 计算QP
		dQP += pdQPs[ rpcSlice->getPOC() ];
	}
	// ------------------------------------------------------------------------------------------------------------------
	// Lambda computation
	// ------------------------------------------------------------------------------------------------------------------

	Int iQP;

	// 32
	Double dOrigQP = dQP;

	// pre-compute lambda and QP values for all possible QP candidates
    // 计算所有可能的候选QP的值和入的值
	for ( Int iDQpIdx = 0; iDQpIdx < 2 * m_pcCfg->getDeltaQpRD() + 1; iDQpIdx++ )
	{
		// compute QP value
		dQP = dOrigQP + ((iDQpIdx+1)>>1)*(iDQpIdx%2 ? -1 : 1);

		// compute lambda value
        // B帧的数量
		Int    NumberBFrames = ( m_pcCfg->getGOPSize() - 1 ); // 0
        // QP偏移
		Int    SHIFT_QP = 12;

		// dLambda_scale == 1
		Double dLambda_scale = 1.0 - Clip3( 0.0, 0.5, 0.05*(Double)(isField ? NumberBFrames/2 : NumberBFrames) );

#if FULL_NBIT
		Int    bitdepth_luma_qp_scale = 6 * (g_bitDepth - 8);
#else
		Int    bitdepth_luma_qp_scale = 0;
#endif
		Double qp_temp = (Double) dQP + bitdepth_luma_qp_scale - SHIFT_QP; // 20
#if FULL_NBIT
		Double qp_temp_orig = (Double) dQP - SHIFT_QP;
#endif
		// Case #1: I or P-slices (key-frame)

        // QP因子
		Double dQPFactor = m_pcCfg->getGOPEntry(iGOPid).m_QPFactor; // 1
		if ( eSliceType==I_SLICE )
		{

			dQPFactor=0.57*dLambda_scale;
		}

		dLambda = dQPFactor*pow( 2.0, qp_temp/3.0 );

		if ( depth>0 )
		{
#if FULL_NBIT
			dLambda *= Clip3( 2.00, 4.00, (qp_temp_orig / 6.0) ); // (j == B_SLICE && p_cur_frm->layer != 0 )
#else
			dLambda *= Clip3( 2.00, 4.00, (qp_temp / 6.0) ); // (j == B_SLICE && p_cur_frm->layer != 0 )
#endif
		}

		// if hadamard is used in ME process
		if ( !m_pcCfg->getUseHADME() && rpcSlice->getSliceType( ) != I_SLICE )
		{
			dLambda *= 0.95;
		}

		// iQP = 32
		iQP = max( -pSPS->getQpBDOffsetY(), min( MAX_QP, (Int) floor( dQP + 0.5 ) ) );

		// 设置相应的量化步长
		m_pdRdPicLambda[iDQpIdx] = dLambda;//57.908....
		m_pdRdPicQp    [iDQpIdx] = dQP;
		m_piRdPicQp    [iDQpIdx] = iQP;
	}

	// obtain dQP = 0 case
	dLambda = m_pdRdPicLambda[0];
	dQP     = m_pdRdPicQp    [0];
	iQP     = m_piRdPicQp    [0];

	if( rpcSlice->getSliceType( ) != I_SLICE )
	{
		dLambda *= m_pcCfg->getLambdaModifier( m_pcCfg->getGOPEntry(iGOPid).m_temporalId );
	}

	// store lambda
	m_pcRdCost ->setLambda( dLambda );
	// for RDO
	// in RdCost there is only one lambda because the luma and chroma bits are not separated, instead we weight the distortion of chroma.
    // 两边的权重
	Double weight[2] = { 1.0, 1.0 };
	Int qpc;
	Int chromaQPOffset;


	chromaQPOffset = rpcSlice->getPPS()->getChromaCbQpOffset() + rpcSlice->getSliceQpDeltaCb();

	qpc = Clip3( 0, 57, iQP + chromaQPOffset);
	weight[0] = pow( 2.0, (iQP-g_aucChromaScale[qpc])/3.0 );  // takes into account of the chroma qp mapping and chroma qp Offset

	// 设置失真权重
	m_pcRdCost->setCbDistortionWeight(weight[0]);

	// chromaQPOffset == 0
	chromaQPOffset = rpcSlice->getPPS()->getChromaCrQpOffset() + rpcSlice->getSliceQpDeltaCr();
	qpc = Clip3( 0, 57, iQP + chromaQPOffset);
	weight[1] = pow( 2.0, (iQP-g_aucChromaScale[qpc])/3.0 );  // takes into account of the chroma qp mapping and chroma qp Offset

	m_pcRdCost->setCrDistortionWeight(weight[1]);


	const Double lambdaArray[3] = {dLambda, (dLambda / weight[0]), (dLambda / weight[1])};

#if RDOQ_CHROMA_LAMBDA 
	// for RDOQ
	// 设置量化步长
	// RDOQ 率失真优化的量化
	m_pcTrQuant->setLambdas( lambdaArray );
#else
	m_pcTrQuant->setLambda( dLambda );
#endif

	// For SAO
	rpcSlice->setLambdas( lambdaArray );

#if HB_LAMBDA_FOR_LDC
	// restore original slice type

#if EFFICIENT_FIELD_IRAP
	if(!(isField && pocLast == 1))
	{
#endif // EFFICIENT_FIELD_IRAP
#if ALLOW_RECOVERY_POINT_AS_RAP

        // 再次设置片的类型(为什么)
		if(m_pcCfg->getDecodingRefreshType() == 3)
		{
			eSliceType = (pocLast == 0 || (pocCurr)           % m_pcCfg->getIntraPeriod() == 0 || m_pcGOPEncoder->getGOPSize() == 0) ? I_SLICE : eSliceType;

		}
		else
		{

			eSliceType = (pocLast == 0 || (pocCurr - isField) % m_pcCfg->getIntraPeriod() == 0 || m_pcGOPEncoder->getGOPSize() == 0) ? I_SLICE : eSliceType;
		}
#else
		eSliceType = (pocLast == 0 || (pocCurr - isField) % m_pcCfg->getIntraPeriod() == 0 || m_pcGOPEncoder->getGOPSize() == 0) ? I_SLICE : eSliceType;
#endif
#if EFFICIENT_FIELD_IRAP
	}
#endif // EFFICIENT_FIELD_IRAP

	rpcSlice->setSliceType        ( eSliceType );
#endif


	if (m_pcCfg->getUseRecalculateQPAccordingToLambda())
	{
		dQP = xGetQPValueAccordingToLambda( dLambda );
		iQP = max( -pSPS->getQpBDOffsetY(), min( MAX_QP, (Int) floor( dQP + 0.5 ) ) );
	}

    // 设置量化步长
	rpcSlice->setSliceQp          ( iQP ); // iQP = 32
#if ADAPTIVE_QP_SELECTION
	rpcSlice->setSliceQpBase      ( iQP );
#endif
    // 分别设置了亮度、色度的QP
	rpcSlice->setSliceQpDelta     ( 0 );
	rpcSlice->setSliceQpDeltaCb   ( 0 );
	rpcSlice->setSliceQpDeltaCr   ( 0 );

    // 设置条带的参考数组中可用图像的个数
	rpcSlice->setNumRefIdx(REF_PIC_LIST_0,m_pcCfg->getGOPEntry(iGOPid).m_numRefPicsActive);
	rpcSlice->setNumRefIdx(REF_PIC_LIST_1,m_pcCfg->getGOPEntry(iGOPid).m_numRefPicsActive);

    // 是否使用了去方块滤波
	if ( m_pcCfg->getDeblockingFilterMetric() )
	{
		rpcSlice->setDeblockingFilterOverrideFlag(true);
		rpcSlice->setDeblockingFilterDisable(false);
		rpcSlice->setDeblockingFilterBetaOffsetDiv2( 0 );
		rpcSlice->setDeblockingFilterTcOffsetDiv2( 0 );
	} 
    // 如果没有使用去方块滤波,但是PPS中出现了去方块滤波标志
	else if (rpcSlice->getPPS()->getDeblockingFilterControlPresentFlag())
	{
		rpcSlice->getPPS()->setDeblockingFilterOverrideEnabledFlag( !m_pcCfg->getLoopFilterOffsetInPPS() );
		rpcSlice->setDeblockingFilterOverrideFlag( !m_pcCfg->getLoopFilterOffsetInPPS() );
		rpcSlice->getPPS()->setPicDisableDeblockingFilterFlag( m_pcCfg->getLoopFilterDisable() );
		rpcSlice->setDeblockingFilterDisable( m_pcCfg->getLoopFilterDisable() );
		if ( !rpcSlice->getDeblockingFilterDisable())
		{
			if ( !m_pcCfg->getLoopFilterOffsetInPPS() && eSliceType!=I_SLICE)
			{
				rpcSlice->getPPS()->setDeblockingFilterBetaOffsetDiv2( m_pcCfg->getGOPEntry(iGOPid).m_betaOffsetDiv2 + m_pcCfg->getLoopFilterBetaOffset() );
				rpcSlice->getPPS()->setDeblockingFilterTcOffsetDiv2( m_pcCfg->getGOPEntry(iGOPid).m_tcOffsetDiv2 + m_pcCfg->getLoopFilterTcOffset() );
				rpcSlice->setDeblockingFilterBetaOffsetDiv2( m_pcCfg->getGOPEntry(iGOPid).m_betaOffsetDiv2 + m_pcCfg->getLoopFilterBetaOffset()  );
				rpcSlice->setDeblockingFilterTcOffsetDiv2( m_pcCfg->getGOPEntry(iGOPid).m_tcOffsetDiv2 + m_pcCfg->getLoopFilterTcOffset() );
			}
			else
			{
				rpcSlice->getPPS()->setDeblockingFilterBetaOffsetDiv2( m_pcCfg->getLoopFilterBetaOffset() );
				rpcSlice->getPPS()->setDeblockingFilterTcOffsetDiv2( m_pcCfg->getLoopFilterTcOffset() );
				rpcSlice->setDeblockingFilterBetaOffsetDiv2( m_pcCfg->getLoopFilterBetaOffset() );
				rpcSlice->setDeblockingFilterTcOffsetDiv2( m_pcCfg->getLoopFilterTcOffset() );
			}
		}
	}
	else
	{
		// 进入这里
		rpcSlice->setDeblockingFilterOverrideFlag( false );
		rpcSlice->setDeblockingFilterDisable( false );
		rpcSlice->setDeblockingFilterBetaOffsetDiv2( 0 );
		rpcSlice->setDeblockingFilterTcOffsetDiv2( 0 );
	}

    // 条带的深度
	rpcSlice->setDepth            ( depth );

    // 设置图像所属的层
	pcPic->setTLayer( m_pcCfg->getGOPEntry(iGOPid).m_temporalId );

    // 如果是I帧那么它所属的层是0层
	if(eSliceType==I_SLICE)
	{
		pcPic->setTLayer(0);
	}

	// 设置条带所属的层
	rpcSlice->setTLayer( pcPic->getTLayer() );

	assert( m_apcPicYuvPred );
	assert( m_apcPicYuvResi );

    // 设置图像的预测图像缓存
	pcPic->setPicYuvPred( m_apcPicYuvPred );
    // 设置图像的残差图像缓存
	pcPic->setPicYuvResi( m_apcPicYuvResi );

	rpcSlice->setSliceMode            ( m_pcCfg->getSliceMode()            );
	rpcSlice->setSliceArgument        ( m_pcCfg->getSliceArgument()        );
	rpcSlice->setSliceSegmentMode     ( m_pcCfg->getSliceSegmentMode()     );
	rpcSlice->setSliceSegmentArgument ( m_pcCfg->getSliceSegmentArgument() );
	rpcSlice->setMaxNumMergeCand        ( m_pcCfg->getMaxNumMergeCand()        );


    // 存储WPP参数
	xStoreWPparam( pPPS->getUseWP(), pPPS->getWPBiPred() );
}
// 片初始化
Void TComSlice::initSlice()
{
    // 参考的索引
	m_aiNumRefIdx[0]      = 0;
	m_aiNumRefIdx[1]      = 0;

    // 参考帧是否都是从list0中来
	m_colFromL0Flag = 1;

	m_colRefIdx = 0;
	initEqualRef();
	m_bCheckLDC = false;
	m_iSliceQpDeltaCb = 0;
	m_iSliceQpDeltaCr = 0;

    // merge模式的候选数量5
	m_maxNumMergeCand = MRG_MAX_NUM_CANDS;

	m_bFinalized=false;

	m_tileByteLocation.clear();
    // CABAC熵编码是否已经初始化
	m_cabacInitFlag        = false;
    // 入口点的数量
	m_numEntryPointOffsets = 0;
    // 启用MVP
	m_enableTMVPFlag = true;
}



你可能感兴趣的:(C++,编码,h.265,HEVC)