入口函数: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;
}