總所周知,QP是整數。然而HM/JEM均支持浮點QP(floating point QP),而且HM中從HM-1.0就開始支持了,這是爲什麼呢?先來看配置文件的參數說明:
從上圖可以看出,配置文件中的QP被程序讀進來的時候是一個浮點數Double TAppEncCfg::m_fQP。讀進來之後在函數TAppEncCfg::parseCfg中對這個浮點QP進行如下處理:
// allocate slice-based dQP values
m_aidQP = new Int[ m_framesToBeEncoded + m_iGOPSize + 1 ];
::memset( m_aidQP, 0, sizeof(Int)*( m_framesToBeEncoded + m_iGOPSize + 1 ) );
// handling of floating-point QP values
// if QP is not integer, sequence is split into two sections having QP and QP+1
m_iQP = (Int)( m_fQP );
if ( m_iQP < m_fQP )
{
Int iSwitchPOC = (Int)( m_framesToBeEncoded - (m_fQP - m_iQP)*m_framesToBeEncoded + 0.5 );
// iSwitchPOC須是key幀,所以需要取整
iSwitchPOC = (Int)( (Double)iSwitchPOC / m_iGOPSize + 0.5 )*m_iGOPSize;
for ( Int i=iSwitchPOC; i<m_framesToBeEncoded + m_iGOPSize + 1; i++ )
{
m_aidQP[i] = 1;
}
}
上面的代碼中,將poc小於iSwitchPOC的幀級QP偏置置爲0,poc大於iSwitchPOC的幀級QP偏置置爲1。其中,TEncCfg::m_aidQP
就是delta QP(QP偏置);如果m_fQP更接近m_iQP,iSwitchPOC更偏向0,如果m_fQP更接近m_iQP+1,iSwitchPOC更偏向m_framesToBeEncoded+m_iGOPSize。
再在TEncSlice::initEncSlice中用TEncCfg::m_aidQP修改slice級QP:
// modify QP
Int* pdQPs = m_pcCfg->getdQPs();
if ( pdQPs )
{
dQP += pdQPs[ rpcSlice->getPOC() ];
}
簡言之,浮點QP是所有base QP的均值,且前面部分幀的base QP爲[m_fQP],後面部分幀的base QP爲[m_fQP]+1。
下面是一個例子,在不開率控的情況下設置QP爲32.5,FramesToBeEncoded爲9。從圖中可以看出,前二個GOP的QP的base QP爲32,第三個GOP的QP的base QP爲33: