H.266/VCコード学習6:VTM 4.0のlambdaとQPの関係
32364 ワード
Lambdaはレート歪み最適化における重要なパラメータであり、その値は量子化パラメータQPと比較的固定的な関数関係を有する.次にVTM 4に深く入り込む.0コードでlambdaとQPの関係を探究する.
まずcfgでQP値を得ることができ、本書では輝度QPとしてQP(Y)と記す.cfgにおいて、CbQpOffsetおよびCrQpOffsetも得られ、その後、色度QPを計算し、QP(C)として記載することができる.輝度lambdaと色度lambdaは、以上の2つのQPから算出され、lambda(Y)とlambda(C)と表記される.
一、明るさlambda(Y)を設定する
輝度lambdaの計算式は次のとおりです.
lambda(Y) = 0.57 * 2^(x/3)
内
x = QP(Y)+ (bitdepth - 8) * 6 – 12
すなわち、ビット深度が10の場合、xはQP(Y)値に等しい.MEプロセスでhadamard変換を使用する場合は、lambda(Y)の最終値として元のベースに0.95を乗じます.
lambda(Y)= 0.57 * 2^(x/3) * 0.95
コード内の輝度部分の対応する関数はcalculateLambdaである.
二、色度lambda(C)の設定
cfgでCbQpOffsetとCrQpOffsetを読み出し、QP(Y)値と演算して、1つの色度QP一時値QP(t)を得る
QP(t)=QP(Y)+CbQpOffset
または
QP(t)=QP(Y)+CrQpOffset
QP(t)の値に基づいて、後続の計算のための色度QPの真値QPをROMにおいて求める©,下表のとおりです.
色度QP一時値QP(t)
色度QP真実値QP(C)
30≤QP(t)≤33
QP( C) = QP(t) - 1
35≤QP(t)≤36
QP( C) = QP(t) - 2
37≤QP(t)≤38
QP( C) = QP(t) - 3
39≤QP(t)≤40
QP( C) = QP(t) - 4
41≤QP(t)≤42
QP( C) = QP(t) – 5
43≤QP(t)≤69
QP( C)= QP(t) – 6
一時歪み重みwをGOPに関連付ける.
w = 2 ^ [(QP(Y)- QP( C)+ 0.1)/3.0] GOPsize<8
w = 2 ^ [(QP(Y)- QP( C)+ 0.2)/3.0] GOPsize≥8
最終的な優位性lambda値:
lambda ( C)=lambda(Y)/w
色度部分のコードにおける対応関数はsetUpLambdaである.
三、QPとlambdaの関係
以上の関係から、QPとlambdaの関係整理がわかります.
lambda(Y)≈ 0.54 * 2^(QP(Y)/3)
lambda( C)≈ 0.53 * 2^(QP( C)/3)
一般的に決定された場合、lambdaはQPのみに関連すると初歩的に結論した.
まずcfgでQP値を得ることができ、本書では輝度QPとしてQP(Y)と記す.cfgにおいて、CbQpOffsetおよびCrQpOffsetも得られ、その後、色度QPを計算し、QP(C)として記載することができる.輝度lambdaと色度lambdaは、以上の2つのQPから算出され、lambda(Y)とlambda(C)と表記される.
一、明るさlambda(Y)を設定する
輝度lambdaの計算式は次のとおりです.
lambda(Y) = 0.57 * 2^(x/3)
内
x = QP(Y)+ (bitdepth - 8) * 6 – 12
すなわち、ビット深度が10の場合、xはQP(Y)値に等しい.MEプロセスでhadamard変換を使用する場合は、lambda(Y)の最終値として元のベースに0.95を乗じます.
lambda(Y)= 0.57 * 2^(x/3) * 0.95
コード内の輝度部分の対応する関数はcalculateLambdaである.
#if SHARP_LUMA_DELTA_QP
double EncSlice::calculateLambda( const Slice* slice,
const int GOPid, // entry in the GOP table
const int depth, // slice GOP hierarchical depth.
const double refQP, // initial slice-level QP slice QP
const double dQP, // initial double-precision QP QP
int &iQP ) // returned integer QP.
{
enum SliceType eSliceType = slice->getSliceType();
const bool isField = slice->getPic()->fieldPic;
const int NumberBFrames = ( m_pcCfg->getGOPSize() - 1 );
const int SHIFT_QP = 12;
#if X0038_LAMBDA_FROM_QP_CAPABILITY
const int temporalId=m_pcCfg->getGOPEntry(GOPid).m_temporalId;//CFG
const std::vector<double> &intraLambdaModifiers=m_pcCfg->getIntraLambdaModifier();//CFG
#endif
int bitdepth_luma_qp_scale = 6
* (slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA) - 8
- DISTORTION_PRECISION_ADJUSTMENT(slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)));//
double qp_temp = dQP + bitdepth_luma_qp_scale - SHIFT_QP;// t, QP = QP+ QP-QP (12)
// Case #1: I or P-slices (key-frame)
double dQPFactor = m_pcCfg->getGOPEntry(GOPid).m_QPFactor;//CFG
/******** I *********/
if /*true*/( eSliceType==I_SLICE )
{
if /*false*/(m_pcCfg->getIntraQpFactor()>=0.0 && m_pcCfg->getGOPEntry(GOPid).m_sliceType != I_SLICE)
{
dQPFactor=m_pcCfg->getIntraQpFactor();
}
else/*true*/
{
#if X0038_LAMBDA_FROM_QP_CAPABILITY
if/*false*/ (m_pcCfg->getLambdaFromQPEnable())
{
dQPFactor=0.57;
}
else/*true*/
{
#endif
double dLambda_scale = 1.0 - Clip3( 0.0, 0.5, 0.05*(double)(isField ? NumberBFrames/2 : NumberBFrames) );// a
dQPFactor=0.57*dLambda_scale;// b,b=0.57*a
#if X0038_LAMBDA_FROM_QP_CAPABILITY
}
#endif
}
}
#if X0038_LAMBDA_FROM_QP_CAPABILITY/**************** CFG “ QP Lambda”***********/
else if/*false*/( m_pcCfg->getLambdaFromQPEnable() )
{
dQPFactor=0.57;
}
#endif
double dLambda = dQPFactor*pow( 2.0, qp_temp/3.0 );// x, x = b * 2^(t/3) = 0.57*a * 2^(t/3)
#if X0038_LAMBDA_FROM_QP_CAPABILITY /************ CFG “ QP Lambda”***********/
if/*false*/( !(m_pcCfg->getLambdaFromQPEnable()) && depth>0 )// 0
#else
if ( depth>0 )
#endif
{
double qp_temp_ref = refQP + bitdepth_luma_qp_scale - SHIFT_QP;
dLambda *= Clip3(2.00, 4.00, (qp_temp_ref / 6.0)); // (j == B_SLICE && p_cur_frm->layer != 0 )
}
// if hadamard is used in ME process ME hadamard
if/*true*/ ( !m_pcCfg->getUseHADME() && slice->getSliceType( ) != I_SLICE )
{
dLambda *= 0.95;//x = 0.57*a * 2^(t/3) *0.95
}
#if X0038_LAMBDA_FROM_QP_CAPABILITY
double lambdaModifier;// m
if/*true*/( eSliceType != I_SLICE || intraLambdaModifiers.empty())
{
lambdaModifier = m_pcCfg->getLambdaModifier( temporalId );
}
else/*false*/
{
lambdaModifier = intraLambdaModifiers[ (temporalId < intraLambdaModifiers.size()) ? temporalId : (intraLambdaModifiers.size()-1) ];
}
dLambda *= lambdaModifier;//x = 0.57*a * 2^(t/3) * 0.95 * m
#endif
iQP = Clip3( -slice->getSPS()->getQpBDOffset( CHANNEL_TYPE_LUMA ), MAX_QP, (int) floor( dQP + 0.5 ) );
if/*true*/( m_pcCfg->getDepQuantEnabledFlag() )
{// lambda ( ) x = 0.57*a * 2^(t/3) * 0.95 * m * 2^(0.25/3)
dLambda *= pow( 2.0, 0.25/3.0 ); // slight lambda adjustment for dependent quantization (due to different slope of quantizer)
}
// NOTE: the lambda modifiers that are sometimes applied later might be best always applied in here.
return dLambda;//x = 0.57*a * 2^(t/3) * 0.95 * m * 2^(0.25/3)
}
#endif
二、色度lambda(C)の設定
cfgでCbQpOffsetとCrQpOffsetを読み出し、QP(Y)値と演算して、1つの色度QP一時値QP(t)を得る
QP(t)=QP(Y)+CbQpOffset
または
QP(t)=QP(Y)+CrQpOffset
QP(t)の値に基づいて、後続の計算のための色度QPの真値QPをROMにおいて求める©,下表のとおりです.
色度QP一時値QP(t)
色度QP真実値QP(C)
30≤QP(t)≤33
QP( C) = QP(t) - 1
35≤QP(t)≤36
QP( C) = QP(t) - 2
37≤QP(t)≤38
QP( C) = QP(t) - 3
39≤QP(t)≤40
QP( C) = QP(t) - 4
41≤QP(t)≤42
QP( C) = QP(t) – 5
43≤QP(t)≤69
QP( C)= QP(t) – 6
一時歪み重みwをGOPに関連付ける.
w = 2 ^ [(QP(Y)- QP( C)+ 0.1)/3.0] GOPsize<8
w = 2 ^ [(QP(Y)- QP( C)+ 0.2)/3.0] GOPsize≥8
最終的な優位性lambda値:
lambda ( C)=lambda(Y)/w
色度部分のコードにおける対応関数はsetUpLambdaである.
void
EncSlice::setUpLambda( Slice* slice, const double dLambda, int iQP)
{
// store lambda lambda
m_pcRdCost ->setLambda( dLambda, slice->getSPS()->getBitDepths() );
// 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 dLambdas[MAX_NUM_COMPONENT] = { dLambda };
for( uint32_t compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++ )// 2 lambda, lambda ( lambda/ )
{
const ComponentID compID = ComponentID( compIdx );
int chromaQPOffset = slice->getPPS()->getQpOffset( compID ) + slice->getSliceChromaQpDelta( compID );
int qpc = ( iQP + chromaQPOffset < 0 ) ? iQP : getScaledChromaQP( iQP + chromaQPOffset, m_pcCfg->getChromaFormatIdc() );
double tmpWeight = pow( 2.0, ( iQP - qpc ) / 3.0 ); // takes into account of the chroma qp mapping and chroma qp Offset qp qp
if( m_pcCfg->getDepQuantEnabledFlag() )
{
tmpWeight *= ( m_pcCfg->getGOPSize() >= 8 ? pow( 2.0, 0.1/3.0 ) : pow( 2.0, 0.2/3.0 ) ); // increase chroma weight for dependent quantization (in order to reduce bit rate shift from chroma to luma) ( )
}
m_pcRdCost->setDistortionWeight( compID, tmpWeight );
#if ENABLE_WPP_PARALLELISM
for( int jId = 1; jId < ( m_pcLib->getNumWppThreads() + m_pcLib->getNumWppExtraLines() ); jId++ )
{
m_pcLib->getRdCost( slice->getPic()->scheduler.getWppDataId( jId ) )->setDistortionWeight( compID, tmpWeight );
}
#endif
dLambdas[compIdx] = dLambda / tmpWeight;// lambda
}
#if RDOQ_CHROMA_LAMBDA
// for RDOQ
m_pcTrQuant->setLambdas( dLambdas );// lambda
#else
m_pcTrQuant->setLambda( dLambda );
#endif
// for SAO
slice->setLambdas( dLambdas );// lambda
}
三、QPとlambdaの関係
以上の関係から、QPとlambdaの関係整理がわかります.
lambda(Y)≈ 0.54 * 2^(QP(Y)/3)
lambda( C)≈ 0.53 * 2^(QP( C)/3)
一般的に決定された場合、lambdaはQPのみに関連すると初歩的に結論した.