從今天開始,正式轉入到幀間預測方向。由於幀間預測涉及到的方面廣且復雜,所以我的理解出現錯誤的情況可能會更多,請大家以辯證的眼光來看待我的帖子,有問題歡迎大家批評指正。 大家都知道xCompressCU是實際進行預測編碼的函數,故很容易就能鎖定幀間預測的一個大致范圍,在研究了幀內預測的基礎上,相信很快就能在該函數中找到與幀間預測相關的函數:xCheckRDCostInter,xCheckRDCostMerge2Nx2N。前者進行除了merge模式以外的所有幀間預測,後者則是針對merge模式的。由於merge模式相對於H.264來說是個新事物,我們考慮先從研究它入手。 進入到xCheckRDCostMerge2Nx2N函數後,開頭有一個比較重要的函數getInterMergeCandidates,它的功能是創建一個merge list,在該模式中是個很重要的函數,故我們先討論它。下面按照慣例,給出我對這個函數的注釋: [cpp] Void TComDataCU::getInterMergeCandidates( UInt uiAbsPartIdx, UInt uiPUIdx, TComMvField* pcMvFieldNeighbours, UChar* puhInterDirNeighbours, Int& numValidMergeCand, Int mrgCandIdx ) { UInt uiAbsPartAddr = m_uiAbsIdxInLCU + uiAbsPartIdx; //!< 當前CU的ZScan地址 UInt uiIdx = 1; Bool abCandIsInter[ MRG_MAX_NUM_CANDS ]; for( UInt ui = 0; ui < getSlice()->getMaxNumMergeCand(); ++ui ) //!< m_maxNumMergeCand = 5 { abCandIsInter[ui] = false; } numValidMergeCand = getSlice()->getMaxNumMergeCand(); //!< 5 // compute the location of the current PU Int xP, yP, nPSW, nPSH; this->getPartPosition(uiPUIdx, xP, yP, nPSW, nPSH); //!< 獲得當前PU的地址和大小 Int iCount = 0; //!< 統計Merge candidate的個數 UInt uiPartIdxLT, uiPartIdxRT, uiPartIdxLB; PartSize cCurPS = getPartitionSize( uiAbsPartIdx ); //!< CU的分割模式 deriveLeftRightTopIdxGeneral( uiAbsPartIdx, uiPUIdx, uiPartIdxLT, uiPartIdxRT ); //!< 左上部,右上部 deriveLeftBottomIdxGeneral ( uiAbsPartIdx, uiPUIdx, uiPartIdxLB ); //!< 左下部 //left UInt uiLeftPartIdx = 0; TComDataCU* pcCULeft = 0; pcCULeft = getPULeft( uiLeftPartIdx, uiPartIdxLB, true, false ); #if MERGE_CLEANUP_AND_K0197 //!< 在有多個PU在一個CU中的時候,去除第二個PU對A1和B1的依賴性 Bool isAvailableA1 = pcCULeft && pcCULeft->isDiffMER(xP -1, yP+nPSH-1, xP, yP) && //!< 當前PU和它的相鄰PU不在同一個ME區域 !( uiPUIdx == 1 && (cCurPS == SIZE_Nx2N || cCurPS == SIZE_nLx2N || cCurPS == SIZE_nRx2N) ) && !pcCULeft->isIntra( uiLeftPartIdx ) ; if ( isAvailableA1 ) #else if (pcCULeft) { if (!pcCULeft->isDiffMER(xP -1, yP+nPSH-1, xP, yP)) { pcCULeft = NULL; } } PartSize partSize = getPartitionSize( uiAbsPartIdx ); if (!(uiPUIdx == 1 && (partSize == SIZE_Nx2N || partSize == SIZE_nLx2N || partSize == SIZE_nRx2N))) { if ( pcCULeft && !pcCULeft->isIntra( uiLeftPartIdx ) ) #endif { abCandIsInter[iCount] = true; // get Inter Dir puhInterDirNeighbours[iCount] = pcCULeft->getInterDir( uiLeftPartIdx ); //!< inter dir分L0,L1,Bi // get Mv from Left,將pcCULeft的MV存放到pcMvFieldNeighbours中 pcCULeft->getMvField( pcCULeft, uiLeftPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] ); if ( getSlice()->isInterB() ) { pcCULeft->getMvField( pcCULeft, uiLeftPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] ); } if ( mrgCandIdx == iCount ) { return; } iCount ++; } #if !MERGE_CLEANUP_AND_K0197 } #endif // early termination if (iCount == getSlice()->getMaxNumMergeCand()) { return; } // above UInt uiAbovePartIdx = 0; TComDataCU* pcCUAbove = 0; #if LINEBUF_CLEANUP pcCUAbove = getPUAbove( uiAbovePartIdx, uiPartIdxRT, true, false ); #else pcCUAbove = getPUAbove( uiAbovePartIdx, uiPartIdxRT, true, false, true ); #endif #if MERGE_CLEANUP_AND_K0197 //!< Bool isAvailableB1 = pcCUAbove && pcCUAbove->isDiffMER(xP+nPSW-1, yP-1, xP, yP) && !( uiPUIdx == 1 && (cCurPS == SIZE_2NxN || cCurPS == SIZE_2NxnU || cCurPS == SIZE_2NxnD) ) && !pcCUAbove->isIntra( uiAbovePartIdx ); if ( isAvailableB1 && (!isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCUAbove, uiAbovePartIdx ) ) ) #else//!< 如果A1可用,則檢查A1和B1的MV是否相同,否則不需要檢查 if (pcCUAbove) { if (!pcCUAbove->isDiffMER(xP+nPSW-1, yP-1, xP, yP)) { pcCUAbove = NULL; } } if ( pcCUAbove && !pcCUAbove->isIntra( uiAbovePartIdx ) && !(uiPUIdx == 1 && (cCurPS == SIZE_2NxN || cCurPS == SIZE_2NxnU || cCurPS == SIZE_2NxnD)) && ( !pcCULeft || pcCULeft->isIntra( uiLeftPartIdx ) || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCUAbove, uiAbovePartIdx ) ) ) #endif { abCandIsInter[iCount] = true; // get Inter Dir puhInterDirNeighbours[iCount] = pcCUAbove->getInterDir( uiAbovePartIdx ); // get Mv from Above pcCUAbove->getMvField( pcCUAbove, uiAbovePartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] ); if ( getSlice()->isInterB() ) { pcCUAbove->getMvField( pcCUAbove, uiAbovePartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] ); } if ( mrgCandIdx == iCount ) { return; } iCount ++; } // early termination if (iCount == getSlice()->getMaxNumMergeCand()) { return; } // above right UInt uiAboveRightPartIdx = 0; TComDataCU* pcCUAboveRight = 0; #if LINEBUF_CLEANUP pcCUAboveRight = getPUAboveRight( uiAboveRightPartIdx, uiPartIdxRT, true, false ); #else pcCUAboveRight = getPUAboveRight( uiAboveRightPartIdx, uiPartIdxRT, true, false, true ); #endif #if MERGE_CLEANUP_AND_K0197 Bool isAvailableB0 = pcCUAboveRight && pcCUAboveRight->isDiffMER(xP+nPSW, yP-1, xP, yP) && !pcCUAboveRight->isIntra( uiAboveRightPartIdx ); if ( isAvailableB0 && ( !isAvailableB1 || !pcCUAbove->hasEqualMotion( uiAbovePartIdx, pcCUAboveRight, uiAboveRightPartIdx ) ) ) #else//!< 如果B1可用,則檢查B1和B0的MV是否相同,否則不需要檢查 if (pcCUAboveRight) { if (!pcCUAboveRight->isDiffMER(xP+nPSW, yP-1, xP, yP)) { pcCUAboveRight = NULL; } } if ( pcCUAboveRight && !pcCUAboveRight->isIntra( uiAboveRightPartIdx ) && ( !pcCUAbove || pcCUAbove->isIntra( uiAbovePartIdx ) || !pcCUAbove->hasEqualMotion( uiAbovePartIdx, pcCUAboveRight, uiAboveRightPartIdx ) ) ) #endif { abCandIsInter[iCount] = true; // get Inter Dir puhInterDirNeighbours[iCount] = pcCUAboveRight->getInterDir( uiAboveRightPartIdx ); // get Mv from AboveRight pcCUAboveRight->getMvField( pcCUAboveRight, uiAboveRightPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] ); if ( getSlice()->isInterB() ) { pcCUAboveRight->getMvField( pcCUAboveRight, uiAboveRightPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] ); } if ( mrgCandIdx == iCount ) { return; } iCount ++; } // early termination if (iCount == getSlice()->getMaxNumMergeCand()) { return; } //left bottom UInt uiLeftBottomPartIdx = 0; TComDataCU* pcCULeftBottom = 0; pcCULeftBottom = this->getPUBelowLeft( uiLeftBottomPartIdx, uiPartIdxLB, true, false ); #if MERGE_CLEANUP_AND_K0197 Bool isAvailableA0 = pcCULeftBottom && pcCULeftBottom->isDiffMER(xP-1, yP+nPSH, xP, yP) && !pcCULeftBottom->isIntra( uiLeftBottomPartIdx ) ; if ( isAvailableA0 && ( !isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCULeftBottom, uiLeftBottomPartIdx ) ) ) #else//!< 如果A1可用,則檢查A1和A0的MV是否相同,否則不需要檢查 if (pcCULeftBottom) { if (!pcCULeftBottom->isDiffMER(xP-1, yP+nPSH, xP, yP)) { pcCULeftBottom = NULL; } } if ( pcCULeftBottom && !pcCULeftBottom->isIntra( uiLeftBottomPartIdx ) && ( !pcCULeft || pcCULeft->isIntra( uiLeftPartIdx ) || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCULeftBottom, uiLeftBottomPartIdx ) ) ) #endif { abCandIsInter[iCount] = true; // get Inter Dir puhInterDirNeighbours[iCount] = pcCULeftBottom->getInterDir( uiLeftBottomPartIdx ); // get Mv from LeftBottom pcCULeftBottom->getMvField( pcCULeftBottom, uiLeftBottomPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] ); if ( getSlice()->isInterB() ) { pcCULeftBottom->getMvField( pcCULeftBottom, uiLeftBottomPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] ); } if ( mrgCandIdx == iCount ) { return; } iCount ++; } // early termination if (iCount == getSlice()->getMaxNumMergeCand()) { return; } // above left if( iCount < 4 ) { UInt uiAboveLeftPartIdx = 0; TComDataCU* pcCUAboveLeft = 0; #if LINEBUF_CLEANUP pcCUAboveLeft = getPUAboveLeft( uiAboveLeftPartIdx, uiAbsPartAddr, true, false ); #else pcCUAboveLeft = getPUAboveLeft( uiAboveLeftPartIdx, uiAbsPartAddr, true, false, true ); #endif #if MERGE_CLEANUP_AND_K0197 Bool isAvailableB2 = pcCUAboveLeft && pcCUAboveLeft->isDiffMER(xP-1, yP-1, xP, yP) && !pcCUAboveLeft->isIntra( uiAboveLeftPartIdx ); if ( isAvailableB2 && ( !isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCUAboveLeft, uiAboveLeftPartIdx ) ) && ( !isAvailableB1 || !pcCUAbove->hasEqualMotion( uiAbovePartIdx, pcCUAboveLeft, uiAboveLeftPartIdx ) ) ) #else//!< 分別將B2與A1、B1的mv進行比較 if (pcCUAboveLeft) { if (!pcCUAboveLeft->isDiffMER(xP-1, yP-1, xP, yP)) { pcCUAboveLeft = NULL; } } if( pcCUAboveLeft && !pcCUAboveLeft->isIntra( uiAboveLeftPartIdx ) && ( !pcCULeft || pcCULeft->isIntra( uiLeftPartIdx ) || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCUAboveLeft, uiAboveLeftPartIdx ) ) && ( !pcCUAbove || pcCUAbove->isIntra( uiAbovePartIdx ) || !pcCUAbove->hasEqualMotion( uiAbovePartIdx, pcCUAboveLeft, uiAboveLeftPartIdx ) ) ) #endif { abCandIsInter[iCount] = true; // get Inter Dir puhInterDirNeighbours[iCount] = pcCUAboveLeft->getInterDir( uiAboveLeftPartIdx ); // get Mv from AboveLeft pcCUAboveLeft->getMvField( pcCUAboveLeft, uiAboveLeftPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] ); if ( getSlice()->isInterB() ) { pcCUAboveLeft->getMvField( pcCUAboveLeft, uiAboveLeftPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] ); } if ( mrgCandIdx == iCount ) { return; } iCount ++; } } // early termination if (iCount == getSlice()->getMaxNumMergeCand()) //!< 如果可用的merge candidates達到預設的最大值(5),則提前退出 { return; } if ( getSlice()->getEnableTMVPFlag()) //!< default is 1 { //>> MTK colocated-RightBottom UInt uiPartIdxRB; Int uiLCUIdx = getAddr(); deriveRightBottomIdx( uiPUIdx, uiPartIdxRB ); //!< 當前PU的右下部的地址 UInt uiAbsPartIdxTmp = g_auiZscanToRaster[uiPartIdxRB]; UInt uiNumPartInCUWidth = m_pcPic->getNumPartInWidth(); //!< CU以partition為單位的寬度 TComMv cColMv; Int iRefIdx; if ( ( m_pcPic->getCU(m_uiCUAddr)->getCUPelX() + g_auiRasterToPelX[uiAbsPartIdxTmp] + m_pcPic->getMinCUWidth() ) >= m_pcSlice->getSPS()->getPicWidthInLumaSamples() ) // image boundary check { uiLCUIdx = -1; }//!< 橫坐標超出圖像邊界 else if ( ( m_pcPic->getCU(m_uiCUAddr)->getCUPelY() + g_auiRasterToPelY[uiAbsPartIdxTmp] + m_pcPic->getMinCUHeight() ) >= m_pcSlice->getSPS()->getPicHeightInLumaSamples() ) { uiLCUIdx = -1; }//!< 縱坐標超出圖像邊界 else { if ( ( uiAbsPartIdxTmp % uiNumPartInCUWidth < uiNumPartInCUWidth - 1 ) && // is not at the last column of LCU ( uiAbsPartIdxTmp / uiNumPartInCUWidth < m_pcPic->getNumPartInHeight() - 1 ) ) // is not at the last row of LCU {//!< 不在LCU的最後一列且不在LCU的最後一行,SIZE_NxN的第1個PU uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdxTmp + uiNumPartInCUWidth + 1 ]; //!< 下一行+1 uiLCUIdx = getAddr(); //!< 與當前PU屬於相同的CU } else if ( uiAbsPartIdxTmp % uiNumPartInCUWidth < uiNumPartInCUWidth - 1 ) // is not at the last column of LCU But is last row of LCU {//!< 不在LCU的最後一列但在LCU的最後一行,SIZE_Nx2N的第1個PU,SIZE_NxN的第3個PU,SIZE_nLx2N的第1個PU,SIZE_nRx2N的第1個PU uiAbsPartAddr = g_auiRasterToZscan[ (uiAbsPartIdxTmp + uiNumPartInCUWidth + 1) % m_pcPic->getNumPartInCU() ]; uiLCUIdx = -1 ; } else if ( uiAbsPartIdxTmp / uiNumPartInCUWidth < m_pcPic->getNumPartInHeight() - 1 ) // is not at the last row of LCU But is last column of LCU {//!< 不在LCU的最後一行但在LCU的最後一列,SIZE_2NxN的第1個PU,SIZE_NxN的第2個PU,SIZE_2NxnU的第1個PU,SIZE_2NxnD的第1個PU uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdxTmp + 1 ]; uiLCUIdx = getAddr() + 1; } else //is the right bottom corner of LCU,SIZE_2Nx2N { uiAbsPartAddr = 0; uiLCUIdx = -1 ; } } iRefIdx = 0; Bool bExistMV = false; UInt uiPartIdxCenter; UInt uiCurLCUIdx = getAddr(); xDeriveCenterIdx( uiPUIdx, uiPartIdxCenter ); //!< 根據uiPUIdx計算PU的中心地址uiPartIdxCenter //! 獲取colocated CU的mv,並經scaled過的。 bExistMV = uiLCUIdx >= 0 && xGetColMVP( REF_PIC_LIST_0, uiLCUIdx, uiAbsPartAddr, cColMv, iRefIdx ); if( bExistMV == false ) { bExistMV = xGetColMVP( REF_PIC_LIST_0, uiCurLCUIdx, uiPartIdxCenter, cColMv, iRefIdx ); } if( bExistMV ) { UInt uiArrayAddr = iCount; abCandIsInter[uiArrayAddr] = true; pcMvFieldNeighbours[uiArrayAddr << 1].setMvField( cColMv, iRefIdx ); if ( getSlice()->isInterB() ) { iRefIdx = 0; bExistMV = uiLCUIdx >= 0 && xGetColMVP( REF_PIC_LIST_1, uiLCUIdx, uiAbsPartAddr, cColMv, iRefIdx); if( bExistMV == false ) { bExistMV = xGetColMVP( REF_PIC_LIST_1, uiCurLCUIdx, uiPartIdxCenter, cColMv, iRefIdx ); } if( bExistMV ) { pcMvFieldNeighbours[ ( uiArrayAddr << 1 ) + 1 ].setMvField( cColMv, iRefIdx ); puhInterDirNeighbours[uiArrayAddr] = 3; //!< Bi } else { puhInterDirNeighbours[uiArrayAddr] = 1; //!< L0 } } else { puhInterDirNeighbours[uiArrayAddr] = 1; //!< L0 } if ( mrgCandIdx == iCount ) { return; } iCount++; } uiIdx++; } // early termination if (iCount == getSlice()->getMaxNumMergeCand()) { return; } UInt uiArrayAddr = iCount; UInt uiCutoff = uiArrayAddr; if ( getSlice()->isInterB()) {//! 參考draft Table 8-6 ---- Specification of l0CandIdx and l1CandIdx UInt uiPriorityList0[12] = {0 , 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3}; UInt uiPriorityList1[12] = {1 , 0, 2, 0, 2, 1, 3, 0, 3, 1, 3, 2}; for (Int idx=0; idx<uiCutoff*(uiCutoff-1) && uiArrayAddr!= getSlice()->getMaxNumMergeCand(); idx++) { Int i = uiPriorityList0[idx]; Int j = uiPriorityList1[idx]; if (abCandIsInter[i] && abCandIsInter[j]&& (puhInterDirNeighbours[i]&0x1)&&(puhInterDirNeighbours[j]&0x2)) { abCandIsInter[uiArrayAddr] = true; puhInterDirNeighbours[uiArrayAddr] = 3; // get Mv from cand[i] and cand[j] pcMvFieldNeighbours[uiArrayAddr << 1].setMvField(pcMvFieldNeighbours[i<<1].getMv(), pcMvFieldNeighbours[i<<1].getRefIdx()); pcMvFieldNeighbours[( uiArrayAddr << 1 ) + 1].setMvField(pcMvFieldNeighbours[(j<<1)+1].getMv(), pcMvFieldNeighbours[(j<<1)+1].getRefIdx()); Int iRefPOCL0 = m_pcSlice->getRefPOC( REF_PIC_LIST_0, pcMvFieldNeighbours[(uiArrayAddr<<1)].getRefIdx() ); Int iRefPOCL1 = m_pcSlice->getRefPOC( REF_PIC_LIST_1, pcMvFieldNeighbours[(uiArrayAddr<<1)+1].getRefIdx() ); if (iRefPOCL0 == iRefPOCL1 && pcMvFieldNeighbours[(uiArrayAddr<<1)].getMv() == pcMvFieldNeighbours[(uiArrayAddr<<1)+1].getMv()) { abCandIsInter[uiArrayAddr] = false; } else { uiArrayAddr++; } } } } // early termination if (uiArrayAddr == getSlice()->getMaxNumMergeCand()) { return; } //! 當可用的merge candidates數目仍小於預設值時,將余量均設置為零運動矢量 Int iNumRefIdx = (getSlice()->isInterB()) ? min(m_pcSlice->getNumRefIdx(REF_PIC_LIST_0), m_pcSlice->getNumRefIdx(REF_PIC_LIST_1)) : m_pcSlice->getNumRefIdx(REF_PIC_LIST_0); Int r = 0; Int refcnt = 0; while (uiArrayAddr < getSlice()->getMaxNumMergeCand()) { abCandIsInter[uiArrayAddr] = true; puhInterDirNeighbours[uiArrayAddr] = 1; pcMvFieldNeighbours[uiArrayAddr << 1].setMvField( TComMv(0, 0), r); //!< 設置為零運動矢量 if ( getSlice()->isInterB() ) { puhInterDirNeighbours[uiArrayAddr] = 3; pcMvFieldNeighbours[(uiArrayAddr << 1) + 1].setMvField(TComMv(0, 0), r); } www.2cto.com uiArrayAddr++; if ( refcnt == iNumRefIdx - 1 ) //!< 達到參考幀列表的參考幀數 { r = 0; } else { ++r; ++refcnt; } } numValidMergeCand = uiArrayAddr; }