/* The copyright in this software is beinOMg made available under the BSD * License, included below. This software may be subject to other third party * and contributor rights, including patent rights, and no such rights are * granted under this license. * * Copyright (c) 2010-2014, ITU/ISO/IEC * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /** \file TComPrediction.cpp \brief prediction class */ #include #include "TComPrediction.h" #include "TComTU.h" //! \ingroup TLibCommon //! \{ // ==================================================================================================================== // Tables // ==================================================================================================================== const UChar TComPrediction::m_aucIntraFilter[MAX_NUM_CHANNEL_TYPE][MAX_INTRA_FILTER_DEPTHS] = { { // Luma 10, //4x4 7, //8x8 1, //16x16 0, //32x32 10, //64x64 }, { // Chroma 10, //4xn 7, //8xn 1, //16xn 0, //32xn 10, //64xn } }; // ==================================================================================================================== // Constructor / destructor / initialize // ==================================================================================================================== TComPrediction::TComPrediction() : m_pLumaRecBuffer(0) , m_iLumaRecStride(0) { for(UInt ch=0; ch>1) + 1) { m_iLumaRecStride = (MAX_CU_SIZE>>1) + 1; if (!m_pLumaRecBuffer) { m_pLumaRecBuffer = new Pel[ m_iLumaRecStride * m_iLumaRecStride ]; } } } // ==================================================================================================================== // Public member functions // ==================================================================================================================== // Function for calculating DC value of the reference samples used in Intra prediction //NOTE: Bit-Limit - 25-bit source Pel TComPrediction::predIntraGetPredValDC( const Pel* pSrc, Int iSrcStride, UInt iWidth, UInt iHeight, ChannelType channelType, ChromaFormat format, Bool bAbove, Bool bLeft ) { assert(iWidth > 0 && iHeight > 0); Int iInd, iSum = 0; Pel pDcVal; if (bAbove) { for (iInd = 0;iInd < iWidth;iInd++) { iSum += pSrc[iInd-iSrcStride]; } } if (bLeft) { for (iInd = 0;iInd < iHeight;iInd++) { iSum += pSrc[iInd*iSrcStride-1]; } } if (bAbove && bLeft) { pDcVal = (iSum + iWidth) / (iWidth + iHeight); } else if (bAbove) { pDcVal = (iSum + iWidth/2) / iWidth; } else if (bLeft) { pDcVal = (iSum + iHeight/2) / iHeight; } else { pDcVal = pSrc[-1]; // Default DC value already calculated and placed in the prediction array if no neighbors are available } return pDcVal; } // Function for deriving the angular Intra predictions /** Function for deriving the simplified angular intra predictions. * \param pSrc pointer to reconstructed sample array * \param srcStride the stride of the reconstructed sample array * \param rpDst reference to pointer for the prediction sample array * \param dstStride the stride of the prediction sample array * \param width the width of the block * \param height the height of the block * \param dirMode the intra prediction mode index * \param blkAboveAvailable boolean indication if the block above is available * \param blkLeftAvailable boolean indication if the block to the left is available * * This function derives the prediction samples for the angular mode based on the prediction direction indicated by * the prediction mode index. The prediction direction is given by the displacement of the bottom row of the block and * the reference row above the block in the case of vertical prediction or displacement of the rightmost column * of the block and reference column left from the block in the case of the horizontal prediction. The displacement * is signalled at 1/32 pixel accuracy. When projection of the predicted pixel falls inbetween reference samples, * the predicted value for the pixel is linearly interpolated from the reference samples. All reference samples are taken * from the extended main reference. */ //NOTE: Bit-Limit - 25-bit source Void TComPrediction::xPredIntraAng( Int bitDepth, const Pel* pSrc, Int srcStride, Pel* pTrueDst, Int dstStrideTrue, UInt uiWidth, UInt uiHeight, ChannelType channelType, ChromaFormat format, UInt dirMode, Bool blkAboveAvailable, Bool blkLeftAvailable , const Bool bEnableEdgeFilters ) { Int width=Int(uiWidth); Int height=Int(uiHeight); // Map the mode index to main prediction direction and angle assert( dirMode != PLANAR_IDX ); //no planar const Bool modeDC = dirMode==DC_IDX; // Do the DC prediction if (modeDC) { const Pel dcval = predIntraGetPredValDC(pSrc, srcStride, width, height, channelType, format, blkAboveAvailable, blkLeftAvailable); for (Int y=height;y>0;y--, pTrueDst+=dstStrideTrue) { for (Int x=0; x= 18); const Int intraPredAngleMode = (bIsModeVer) ? (Int)dirMode - VER_IDX : -((Int)dirMode - HOR_IDX); const Int absAngMode = abs(intraPredAngleMode); const Int signAng = intraPredAngleMode < 0 ? -1 : 1; const Bool edgeFilter = bEnableEdgeFilters && isLuma(channelType) && (width <= MAXIMUM_INTRA_FILTERED_WIDTH) && (height <= MAXIMUM_INTRA_FILTERED_HEIGHT); // Set bitshifts and scale the angle parameter to block size static const Int angTable[9] = {0, 2, 5, 9, 13, 17, 21, 26, 32}; static const Int invAngTable[9] = {0, 4096, 1638, 910, 630, 482, 390, 315, 256}; // (256 * 32) / Angle Int invAngle = invAngTable[absAngMode]; Int absAng = angTable[absAngMode]; Int intraPredAngle = signAng * absAng; Pel* refMain; Pel* refSide; Pel refAbove[2*MAX_CU_SIZE+1]; Pel refLeft[2*MAX_CU_SIZE+1]; // Initialise the Main and Left reference array. if (intraPredAngle < 0) { const Int refMainOffsetPreScale = (bIsModeVer ? height : width ) - 1; const Int refMainOffset = height - 1; for (Int x=0;x(refMainOffsetPreScale+1)*intraPredAngle>>5; k--) { invAngleSum += invAngle; refMain[k] = refSide[invAngleSum>>8]; } } else { for (Int x=0;x<2*width+1;x++) { refAbove[x] = pSrc[x-srcStride-1]; } for (Int y=0;y<2*height+1;y++) { refLeft[y] = pSrc[(y-1)*srcStride-1]; } refMain = bIsModeVer ? refAbove : refLeft ; refSide = bIsModeVer ? refLeft : refAbove; } // swap width/height if we are doing a horizontal mode: Pel tempArray[MAX_CU_SIZE*MAX_CU_SIZE]; const Int dstStride = bIsModeVer ? dstStrideTrue : MAX_CU_SIZE; Pel *pDst = bIsModeVer ? pTrueDst : tempArray; if (!bIsModeVer) { std::swap(width, height); } if (intraPredAngle == 0) // pure vertical or pure horizontal { for (Int y=0;y> 1) ); } } } else { Pel *pDsty=pDst; for (Int y=0, deltaPos=intraPredAngle; y> 5; const Int deltaFract = deltaPos & (32 - 1); if (deltaFract) { // Do linear filtering const Pel *pRM=refMain+deltaInt+1; Int lastRefMainPel=*pRM++; for (Int x=0;x> 5 ); lastRefMainPel=thisRefMainPel; } } else { // Just copy the integer samples for (Int x=0;x= 0 ); // 4x 4 assert( g_aucConvertToBit[ iWidth ] <= 5 ); // 128x128 //assert( iWidth == iHeight ); Pel *pDst = piPred; // get starting pixel in block const Int sw = (2 * iWidth + 1); if ( bUseLosslessDPCM ) { const Pel *ptrSrc = getPredictorPtr( compID, false ); // Sample Adaptive intra-Prediction (SAP) if (uiDirMode==HOR_IDX) { // left column filled with reference samples // remaining columns filled with piOrg data (if available). for(Int y=0; yisRDPCMEnabled(uiAbsPartIdx) && pcCU->getCUTransquantBypass(uiAbsPartIdx)); #if O0043_BEST_EFFORT_DECODING xPredIntraAng( g_bitDepthInStream[channelType], ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight, channelType, format, uiDirMode, bAbove, bLeft, enableEdgeFilters ); #else xPredIntraAng( g_bitDepth[channelType], ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight, channelType, format, uiDirMode, bAbove, bLeft, enableEdgeFilters ); #endif if(( uiDirMode == DC_IDX ) && bAbove && bLeft ) { xDCPredFiltering( ptrSrc+sw+1, sw, pDst, uiStride, iWidth, iHeight, channelType ); } } } } /** Function for checking identical motion. * \param TComDataCU* pcCU * \param UInt PartAddr */ Bool TComPrediction::xCheckIdenticalMotion ( TComDataCU* pcCU, UInt PartAddr ) { if( pcCU->getSlice()->isInterB() && !pcCU->getSlice()->getPPS()->getWPBiPred() ) { if( pcCU->getCUMvField(REF_PIC_LIST_0)->getRefIdx(PartAddr) >= 0 && pcCU->getCUMvField(REF_PIC_LIST_1)->getRefIdx(PartAddr) >= 0) { Int RefPOCL0 = pcCU->getSlice()->getRefPic(REF_PIC_LIST_0, pcCU->getCUMvField(REF_PIC_LIST_0)->getRefIdx(PartAddr))->getPOC(); Int RefPOCL1 = pcCU->getSlice()->getRefPic(REF_PIC_LIST_1, pcCU->getCUMvField(REF_PIC_LIST_1)->getRefIdx(PartAddr))->getPOC(); if(RefPOCL0 == RefPOCL1 && pcCU->getCUMvField(REF_PIC_LIST_0)->getMv(PartAddr) == pcCU->getCUMvField(REF_PIC_LIST_1)->getMv(PartAddr)) { return true; } } } return false; } Void TComPrediction::motionCompensation ( TComDataCU* pcCU, TComYuv* pcYuvPred, RefPicList eRefPicList, Int iPartIdx ) { Int iWidth; Int iHeight; UInt uiPartAddr; if ( iPartIdx >= 0 ) { pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iWidth, iHeight ); if ( eRefPicList != REF_PIC_LIST_X ) { if( pcCU->getSlice()->getPPS()->getUseWP()) { xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred, true ); } else { xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred ); } if ( pcCU->getSlice()->getPPS()->getUseWP() ) { xWeightedPredictionUni( pcCU, pcYuvPred, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred ); } } else { if ( xCheckIdenticalMotion( pcCU, uiPartAddr ) ) { xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, REF_PIC_LIST_0, pcYuvPred ); } else { xPredInterBi (pcCU, uiPartAddr, iWidth, iHeight, pcYuvPred ); } } return; } for ( iPartIdx = 0; iPartIdx < pcCU->getNumPartitions(); iPartIdx++ ) { pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iWidth, iHeight ); if ( eRefPicList != REF_PIC_LIST_X ) { if( pcCU->getSlice()->getPPS()->getUseWP()) { xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred, true ); } else { xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred ); } if ( pcCU->getSlice()->getPPS()->getUseWP() ) { xWeightedPredictionUni( pcCU, pcYuvPred, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred ); } } else { if ( xCheckIdenticalMotion( pcCU, uiPartAddr ) ) { xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, REF_PIC_LIST_0, pcYuvPred ); } else { xPredInterBi (pcCU, uiPartAddr, iWidth, iHeight, pcYuvPred ); } } } return; } Void TComPrediction::xPredInterUni ( TComDataCU* pcCU, UInt uiPartAddr, Int iWidth, Int iHeight, RefPicList eRefPicList, TComYuv* pcYuvPred, Bool bi ) { Int iRefIdx = pcCU->getCUMvField( eRefPicList )->getRefIdx( uiPartAddr ); assert (iRefIdx >= 0); TComMv cMv = pcCU->getCUMvField( eRefPicList )->getMv( uiPartAddr ); pcCU->clipMv(cMv); for (UInt ch=COMPONENT_Y; chgetNumberValidComponents(); ch++) xPredInterBlk (ComponentID(ch), pcCU, pcCU->getSlice()->getRefPic( eRefPicList, iRefIdx )->getPicYuvRec(), uiPartAddr, &cMv, iWidth, iHeight, pcYuvPred, bi ); } Void TComPrediction::xPredInterBi ( TComDataCU* pcCU, UInt uiPartAddr, Int iWidth, Int iHeight, TComYuv* pcYuvPred ) { TComYuv* pcMbYuv; Int iRefIdx[NUM_REF_PIC_LIST_01] = {-1, -1}; for ( UInt refList = 0; refList < NUM_REF_PIC_LIST_01; refList++ ) { RefPicList eRefPicList = (refList ? REF_PIC_LIST_1 : REF_PIC_LIST_0); iRefIdx[refList] = pcCU->getCUMvField( eRefPicList )->getRefIdx( uiPartAddr ); if ( iRefIdx[refList] < 0 ) { continue; } assert( iRefIdx[refList] < pcCU->getSlice()->getNumRefIdx(eRefPicList) ); pcMbYuv = &m_acYuvPred[refList]; if( pcCU->getCUMvField( REF_PIC_LIST_0 )->getRefIdx( uiPartAddr ) >= 0 && pcCU->getCUMvField( REF_PIC_LIST_1 )->getRefIdx( uiPartAddr ) >= 0 ) { xPredInterUni ( pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcMbYuv, true ); } else { if ( ( pcCU->getSlice()->getPPS()->getUseWP() && pcCU->getSlice()->getSliceType() == P_SLICE ) || ( pcCU->getSlice()->getPPS()->getWPBiPred() && pcCU->getSlice()->getSliceType() == B_SLICE ) ) { xPredInterUni ( pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcMbYuv, true ); } else { xPredInterUni ( pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcMbYuv ); } } } if ( pcCU->getSlice()->getPPS()->getWPBiPred() && pcCU->getSlice()->getSliceType() == B_SLICE ) { xWeightedPredictionBi( pcCU, &m_acYuvPred[REF_PIC_LIST_0], &m_acYuvPred[REF_PIC_LIST_1], iRefIdx[REF_PIC_LIST_0], iRefIdx[REF_PIC_LIST_1], uiPartAddr, iWidth, iHeight, pcYuvPred ); } else if ( pcCU->getSlice()->getPPS()->getUseWP() && pcCU->getSlice()->getSliceType() == P_SLICE ) { xWeightedPredictionUni( pcCU, &m_acYuvPred[REF_PIC_LIST_0], uiPartAddr, iWidth, iHeight, REF_PIC_LIST_0, pcYuvPred ); } else { xWeightedAverage( &m_acYuvPred[REF_PIC_LIST_0], &m_acYuvPred[REF_PIC_LIST_1], iRefIdx[REF_PIC_LIST_0], iRefIdx[REF_PIC_LIST_1], uiPartAddr, iWidth, iHeight, pcYuvPred ); } } /** * \brief Generate motion-compensated block * * \param cu Pointer to current CU * \param refPic Pointer to reference picture * \param partAddr Address of block within CU * \param mv Motion vector * \param width Width of block * \param height Height of block * \param dstPic Pointer to destination picture * \param bi Flag indicating whether bipred is used */ Void TComPrediction::xPredInterBlk(const ComponentID compID, TComDataCU *cu, TComPicYuv *refPic, UInt partAddr, TComMv *mv, Int width, Int height, TComYuv *dstPic, Bool bi ) { Int refStride = refPic->getStride(compID); Int dstStride = dstPic->getStride(compID); Int shiftHor=(2+refPic->getComponentScaleX(compID)); Int shiftVer=(2+refPic->getComponentScaleY(compID)); Int refOffset = (mv->getHor() >> shiftHor) + (mv->getVer() >> shiftVer) * refStride; Pel* ref = refPic->getAddr(compID, cu->getCtuRsAddr(), cu->getZorderIdxInCtu() + partAddr ) + refOffset; Pel* dst = dstPic->getAddr( compID, partAddr ); Int xFrac = mv->getHor() & ((1<getVer() & ((1<> refPic->getComponentScaleX(compID); UInt cxHeight = height >> refPic->getComponentScaleY(compID); const ChromaFormat chFmt = cu->getPic()->getChromaFormat(); if ( yFrac == 0 ) { m_if.filterHor(compID, ref, refStride, dst, dstStride, cxWidth, cxHeight, xFrac, !bi, chFmt); } else if ( xFrac == 0 ) { m_if.filterVer(compID, ref, refStride, dst, dstStride, cxWidth, cxHeight, yFrac, true, !bi, chFmt); } else { Int tmpStride = m_filteredBlockTmp[0].getStride(compID); Pel* tmp = m_filteredBlockTmp[0].getAddr(compID); const Int vFilterSize = isLuma(compID) ? NTAPS_LUMA : NTAPS_CHROMA; m_if.filterHor(compID, ref - ((vFilterSize>>1) -1)*refStride, refStride, tmp, tmpStride, cxWidth, cxHeight+vFilterSize-1, xFrac, false, chFmt); m_if.filterVer(compID, tmp + ((vFilterSize>>1) -1)*tmpStride, tmpStride, dst, dstStride, cxWidth, cxHeight, yFrac, false, !bi, chFmt); } } Void TComPrediction::xWeightedAverage( TComYuv* pcYuvSrc0, TComYuv* pcYuvSrc1, Int iRefIdx0, Int iRefIdx1, UInt uiPartIdx, Int iWidth, Int iHeight, TComYuv* pcYuvDst ) { if( iRefIdx0 >= 0 && iRefIdx1 >= 0 ) { pcYuvDst->addAvg( pcYuvSrc0, pcYuvSrc1, uiPartIdx, iWidth, iHeight ); } else if ( iRefIdx0 >= 0 && iRefIdx1 < 0 ) { pcYuvSrc0->copyPartToPartYuv( pcYuvDst, uiPartIdx, iWidth, iHeight ); } else if ( iRefIdx0 < 0 && iRefIdx1 >= 0 ) { pcYuvSrc1->copyPartToPartYuv( pcYuvDst, uiPartIdx, iWidth, iHeight ); } } // AMVP Void TComPrediction::getMvPredAMVP( TComDataCU* pcCU, UInt uiPartIdx, UInt uiPartAddr, RefPicList eRefPicList, TComMv& rcMvPred ) { AMVPInfo* pcAMVPInfo = pcCU->getCUMvField(eRefPicList)->getAMVPInfo(); if( pcAMVPInfo->iN <= 1 ) { rcMvPred = pcAMVPInfo->m_acMvCand[0]; pcCU->setMVPIdxSubParts( 0, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr)); pcCU->setMVPNumSubParts( pcAMVPInfo->iN, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr)); return; } assert(pcCU->getMVPIdx(eRefPicList,uiPartAddr) >= 0); rcMvPred = pcAMVPInfo->m_acMvCand[pcCU->getMVPIdx(eRefPicList,uiPartAddr)]; return; } /** Function for deriving planar intra prediction. * \param pSrc pointer to reconstructed sample array * \param srcStride the stride of the reconstructed sample array * \param rpDst reference to pointer for the prediction sample array * \param dstStride the stride of the prediction sample array * \param width the width of the block * \param height the height of the block * * This function derives the prediction samples for planar mode (intra coding). */ //NOTE: Bit-Limit - 24-bit source Void TComPrediction::xPredIntraPlanar( const Pel* pSrc, Int srcStride, Pel* rpDst, Int dstStride, UInt width, UInt height, ChannelType channelType, ChromaFormat format ) { assert(width <= height); Int leftColumn[MAX_CU_SIZE+1], topRow[MAX_CU_SIZE+1], bottomRow[MAX_CU_SIZE], rightColumn[MAX_CU_SIZE]; UInt shift1Dhor = g_aucConvertToBit[ width ] + 2; UInt shift1Dver = g_aucConvertToBit[ height ] + 2; // Get left and above reference column and row for(Int k=0;k>topRowShift); rpDst[y*dstStride+x] = ( horPred + vertPred ) >> (shift1Dhor+1); } } } /** Function for filtering intra DC predictor. * \param pSrc pointer to reconstructed sample array * \param iSrcStride the stride of the reconstructed sample array * \param rpDst reference to pointer for the prediction sample array * \param iDstStride the stride of the prediction sample array * \param iWidth the width of the block * \param iHeight the height of the block * * This function performs filtering left and top edges of the prediction samples for DC mode (intra coding). */ Void TComPrediction::xDCPredFiltering( const Pel* pSrc, Int iSrcStride, Pel* pDst, Int iDstStride, Int iWidth, Int iHeight, ChannelType channelType ) { Int x, y, iDstStride2, iSrcStride2; if (isLuma(channelType) && (iWidth <= MAXIMUM_INTRA_FILTERED_WIDTH) && (iHeight <= MAXIMUM_INTRA_FILTERED_HEIGHT)) { //top-left pDst[0] = (Pel)((pSrc[-iSrcStride] + pSrc[-1] + 2 * pDst[0] + 2) >> 2); //top row (vertical filter) for ( x = 1; x < iWidth; x++ ) { pDst[x] = (Pel)((pSrc[x - iSrcStride] + 3 * pDst[x] + 2) >> 2); } //left column (horizontal filter) for ( y = 1, iDstStride2 = iDstStride, iSrcStride2 = iSrcStride-1; y < iHeight; y++, iDstStride2+=iDstStride, iSrcStride2+=iSrcStride ) { pDst[iDstStride2] = (Pel)((pSrc[iSrcStride2] + 3 * pDst[iDstStride2] + 2) >> 2); } } return; } /* Static member function */ Bool TComPrediction::UseDPCMForFirstPassIntraEstimation(TComTU &rTu, const UInt uiDirMode) { return (rTu.getCU()->isRDPCMEnabled(rTu.GetAbsPartIdxTU()) ) && rTu.getCU()->getCUTransquantBypass(rTu.GetAbsPartIdxTU()) && (uiDirMode==HOR_IDX || uiDirMode==VER_IDX); } //! \}