這篇文章大部分內容轉載於http://blog.csdn.net/yangxiao_xiang/article/details/8872173,作者根據自己的理解,加入了一些自己理解的代碼部分。如有不正確的地方還請大家給與指正。
對於幀間預測而言,一定會涉及到參考圖像的問題,但是搞清楚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); <span style="font-family: Arial, Helvetica, sans-serif;">//==list0參考圖像數目==//
- </span>
- 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(參考列表聯合)一起留到後續再討論!