對於幀間預測而言,一定會涉及到參考圖像的問題,但是搞清楚HM中參考圖像是如何配置,對理解其編碼結構尤爲關鍵。顧名思義,參考圖像應該是屬於picture級別的,因此可以在compressGOP函數中找到相應的函數。主要包括以下三個函數:
1、arrangeLongtermPicturesInRPS(pcSlice, rcListPic);
2、pcSlice->setRefPicList ( rcListPic );
3、pcSlice->setRefPOCList();
首先說第一個函數,主要是在RPS(Reference Picture Set)句法中設置LongTermPicture,那麼什麼是LT呢?參考圖像主要有以下三種:long-term,short-term before curr和short-term after curr。第一個函數就是用來提供long-term 參考圖像的,具體實現可以查看函數,這裏不做重點敘述。
重點是第二個函數setRefPicList,上面我們瞭解到參考圖像主要有三種,但是最後參考圖像列表中的參考圖像是通過下面的方式確定的。那些在參考列表中用到的參考圖像,其標誌爲1,相反,則爲0;故setRefPicList函數的實現過程是先通過標誌位判斷(if(m_pcRPS->getUsed(i)))確定三種參考圖像的實際參考幀(如下面第一部分),然後再通過ref_pic_list_init過程,再組成list0和list1列表,實現過程詳見程序。
Void TComSlice::setRefPicList( TComList<TComPic*>& rcListPic )
{
if (m_eSliceType == I_SLICE)
{//==對於I幀而言,直接返回==//
::memset( m_apcRefPicList, 0, sizeof (m_apcRefPicList));
::memset( m_aiNumRefIdx, 0, sizeof ( m_aiNumRefIdx ));
return;
}
m_aiNumRefIdx[0] = getNumRefIdx(REF_PIC_LIST_0); //==list0參考圖像數目==//
m_aiNumRefIdx[1] = getNumRefIdx(REF_PIC_LIST_1); //==list0參考圖像數目==//
TComPic* pcRefPic= NULL;
TComPic* RefPicSetStCurr0[16];
TComPic* RefPicSetStCurr1[16];
TComPic* RefPicSetLtCurr[16];
UInt NumPocStCurr0 = 0;
UInt NumPocStCurr1 = 0;
UInt NumPocLtCurr = 0;
Int i;
for(i=0; i < m_pcRPS->getNumberOfNegativePictures(); i++)
{// 設置short term negative(即前向參考圖像)
if(m_pcRPS->getUsed(i))
{
pcRefPic = xGetRefPic(rcListPic, getPOC()+m_pcRPS->getDeltaPOC(i));
pcRefPic->setIsLongTerm(0);
pcRefPic->setIsUsedAsLongTerm(0);
pcRefPic->getPicYuvRec()->extendPicBorder();
RefPicSetStCurr0[NumPocStCurr0 ] = pcRefPic;
NumPocStCurr0++;
pcRefPic->setCheckLTMSBPresent(false);
}
}
for(; i < m_pcRPS->getNumberOfNegativePictures()+m_pcRPS->getNumberOfPositivePictures(); i++)
{// 設置short term positive(即後向參考圖像)
if(m_pcRPS->getUsed(i))
{
pcRefPic = xGetRefPic(rcListPic, getPOC()+m_pcRPS->getDeltaPOC(i));
pcRefPic->setIsLongTerm(0);
pcRefPic->setIsUsedAsLongTerm(0);
pcRefPic->getPicYuvRec()->extendPicBorder();
RefPicSetStCurr1[NumPocStCurr1] = pcRefPic;
NumPocStCurr1++;
pcRefPic->setCheckLTMSBPresent(false);
}
}
for(i = m_pcRPS->getNumberOfNegativePictures()+m_pcRPS->getNumberOfPositivePictures()+m_pcRPS->getNumberOfLongtermPictures()-1; i > m_pcRPS->getNumberOfNegativePictures()+m_pcRPS->getNumberOfPositivePictures()-1 ; i--)
{//==設置long term參考圖像==//
if(m_pcRPS->getUsed(i))
{
pcRefPic = xGetLongTermRefPic(rcListPic, m_pcRPS->getPOC(i));
pcRefPic->setIsLongTerm(1);
pcRefPic->setIsUsedAsLongTerm(1);
pcRefPic->getPicYuvRec()->extendPicBorder();
RefPicSetLtCurr[NumPocLtCurr] = pcRefPic;
NumPocLtCurr++;
}
if(pcRefPic==NULL)
{
pcRefPic = xGetLongTermRefPic(rcListPic, m_pcRPS->getPOC(i));
}
pcRefPic->setCheckLTMSBPresent(m_pcRPS->getCheckLTMSBPresent(i));
}
// ref_pic_list_init
#if RPL_INIT_FIX
TComPic* rpsCurrList0[MAX_NUM_REF+1];
TComPic* rpsCurrList1[MAX_NUM_REF+1];
Int numPocTotalCurr = NumPocStCurr0 + NumPocStCurr1 + NumPocLtCurr;
{
Int cIdx = 0;
for ( i=0; i<NumPocStCurr0; i++, cIdx++)
{//==(0<=cIdx<NumPocStCurr0)==//
rpsCurrList0[cIdx] = RefPicSetStCurr0[i];
}
for ( i=0; i<NumPocStCurr1; i++, cIdx++)
{//==(NumPocStCurr0<=cIdx<NumPocStCurr1+NumPocStCurr0)==//
rpsCurrList0[cIdx] = RefPicSetStCurr1[i];
}
for ( i=0; i<NumPocLtCurr; i++, cIdx++)
{//==(NumPocStCurr1<=cIdx<numPocTotalCurr)==//
rpsCurrList0[cIdx] = RefPicSetLtCurr[i];
}
}
if (m_eSliceType==B_SLICE)
{
Int cIdx = 0;
for ( i=0; i<NumPocStCurr1; i++, cIdx++)
{//==(0<=cIdx<NumPocStCurr0)==//
rpsCurrList1[cIdx] = RefPicSetStCurr1[i];
}
for ( i=0; i<NumPocStCurr0; i++, cIdx++)
{//==(NumPocStCurr0<=cIdx<NumPocStCurr1+NumPocStCurr0)==//
rpsCurrList1[cIdx] = RefPicSetStCurr0[i];
}
for ( i=0; i<NumPocLtCurr; i++, cIdx++)
{//==(NumPocStCurr1+NumPocStCurr0<=cIdx<numPocTotalCurr)==//
rpsCurrList1[cIdx] = RefPicSetLtCurr[i];
}
}
///=====Unification of reference picture list modification processes(參考JCTVC-H0138)=====///
for (Int rIdx = 0; rIdx <= (m_aiNumRefIdx[0]-1); rIdx ++)
{//===修正list0列表===//
m_apcRefPicList[0][rIdx] = m_RefPicListModification.getRefPicListModificationFlagL0() ? rpsCurrList0[ m_RefPicListModification.getRefPicSetIdxL0(rIdx) ] : rpsCurrList0[rIdx % numPocTotalCurr];
}
if ( m_eSliceType == P_SLICE )
{//////////////////==若爲P幀,則list1爲零==/////////////////////////////
m_aiNumRefIdx[1] = 0;
::memset( m_apcRefPicList[1], 0, sizeof(m_apcRefPicList[1]));
}
else
{//===修正list1列表===//
for (Int rIdx = 0; rIdx <= (m_aiNumRefIdx[1]-1); rIdx ++)
{
m_apcRefPicList[1][rIdx] = m_RefPicListModification.getRefPicListModificationFlagL1() ? rpsCurrList1[ m_RefPicListModification.getRefPicSetIdxL1(rIdx) ] : rpsCurrList1[rIdx % numPocTotalCurr];
}
}
而最後一個函數setRefPOCList就是實現將參考圖像轉化成其相應的POC列表。
Void TComSlice::setRefPOCList ()
{//===將參考圖像列表轉化成相應的POC===//
for (Int iDir = 0; iDir < 2; iDir++)
{
for (Int iNumRefIdx = 0; iNumRefIdx < m_aiNumRefIdx[iDir]; iNumRefIdx++)
{
m_aiRefPOCList[iDir][iNumRefIdx] = m_apcRefPicList[iDir][iNumRefIdx]->getPOC();
}
}
}
另外在第二個函數中有涉及到ListModification(列表修正)的問題,由於篇幅有限,將和 List Combination(參考列表聯合)一起留到後續再討論!