/* The copyright in this software is being 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 TEncCu.cpp \brief Coding Unit (CU) encoder class */ #include #include "TEncTop.h" #include "TEncCu.h" #include "TEncAnalyze.h" #include "TLibCommon/Debug.h" #include #include using namespace std; //! \ingroup TLibEncoder //! \{ // ==================================================================================================================== // Constructor / destructor / create / destroy // ==================================================================================================================== /** \param uiTotalDepth total number of allowable depth \param uiMaxWidth largest CU width \param uiMaxHeight largest CU height */ Void TEncCu::create(UChar uhTotalDepth, UInt uiMaxWidth, UInt uiMaxHeight, ChromaFormat chromaFormat) { Int i; m_uhTotalDepth = uhTotalDepth + 1; m_ppcBestCU = new TComDataCU*[m_uhTotalDepth-1]; m_ppcTempCU = new TComDataCU*[m_uhTotalDepth-1]; m_ppcPredYuvBest = new TComYuv*[m_uhTotalDepth-1]; m_ppcResiYuvBest = new TComYuv*[m_uhTotalDepth-1]; m_ppcRecoYuvBest = new TComYuv*[m_uhTotalDepth-1]; m_ppcPredYuvTemp = new TComYuv*[m_uhTotalDepth-1]; m_ppcResiYuvTemp = new TComYuv*[m_uhTotalDepth-1]; m_ppcRecoYuvTemp = new TComYuv*[m_uhTotalDepth-1]; m_ppcOrigYuv = new TComYuv*[m_uhTotalDepth-1]; UInt uiNumPartitions; for( i=0 ; i> i; UInt uiHeight = uiMaxHeight >> i; m_ppcBestCU[i] = new TComDataCU; m_ppcBestCU[i]->create( chromaFormat, uiNumPartitions, uiWidth, uiHeight, false, uiMaxWidth >> (m_uhTotalDepth - 1) ); m_ppcTempCU[i] = new TComDataCU; m_ppcTempCU[i]->create( chromaFormat, uiNumPartitions, uiWidth, uiHeight, false, uiMaxWidth >> (m_uhTotalDepth - 1) ); m_ppcPredYuvBest[i] = new TComYuv; m_ppcPredYuvBest[i]->create(uiWidth, uiHeight, chromaFormat); m_ppcResiYuvBest[i] = new TComYuv; m_ppcResiYuvBest[i]->create(uiWidth, uiHeight, chromaFormat); m_ppcRecoYuvBest[i] = new TComYuv; m_ppcRecoYuvBest[i]->create(uiWidth, uiHeight, chromaFormat); m_ppcPredYuvTemp[i] = new TComYuv; m_ppcPredYuvTemp[i]->create(uiWidth, uiHeight, chromaFormat); m_ppcResiYuvTemp[i] = new TComYuv; m_ppcResiYuvTemp[i]->create(uiWidth, uiHeight, chromaFormat); m_ppcRecoYuvTemp[i] = new TComYuv; m_ppcRecoYuvTemp[i]->create(uiWidth, uiHeight, chromaFormat); m_ppcOrigYuv [i] = new TComYuv; m_ppcOrigYuv [i]->create(uiWidth, uiHeight, chromaFormat); } m_bEncodeDQP = false; m_CodeChromaQpAdjFlag = false; m_ChromaQpAdjIdc = 0; // initialize partition order. UInt* piTmp = &g_auiZscanToRaster[0]; initZscanToRaster( m_uhTotalDepth, 1, 0, piTmp); initRasterToZscan( uiMaxWidth, uiMaxHeight, m_uhTotalDepth ); // initialize conversion matrix from partition index to pel initRasterToPelXY( uiMaxWidth, uiMaxHeight, m_uhTotalDepth ); } Void TEncCu::destroy() { Int i; for( i=0 ; idestroy(); delete m_ppcBestCU[i]; m_ppcBestCU[i] = NULL; } if(m_ppcTempCU[i]) { m_ppcTempCU[i]->destroy(); delete m_ppcTempCU[i]; m_ppcTempCU[i] = NULL; } if(m_ppcPredYuvBest[i]) { m_ppcPredYuvBest[i]->destroy(); delete m_ppcPredYuvBest[i]; m_ppcPredYuvBest[i] = NULL; } if(m_ppcResiYuvBest[i]) { m_ppcResiYuvBest[i]->destroy(); delete m_ppcResiYuvBest[i]; m_ppcResiYuvBest[i] = NULL; } if(m_ppcRecoYuvBest[i]) { m_ppcRecoYuvBest[i]->destroy(); delete m_ppcRecoYuvBest[i]; m_ppcRecoYuvBest[i] = NULL; } if(m_ppcPredYuvTemp[i]) { m_ppcPredYuvTemp[i]->destroy(); delete m_ppcPredYuvTemp[i]; m_ppcPredYuvTemp[i] = NULL; } if(m_ppcResiYuvTemp[i]) { m_ppcResiYuvTemp[i]->destroy(); delete m_ppcResiYuvTemp[i]; m_ppcResiYuvTemp[i] = NULL; } if(m_ppcRecoYuvTemp[i]) { m_ppcRecoYuvTemp[i]->destroy(); delete m_ppcRecoYuvTemp[i]; m_ppcRecoYuvTemp[i] = NULL; } if(m_ppcOrigYuv[i]) { m_ppcOrigYuv[i]->destroy(); delete m_ppcOrigYuv[i]; m_ppcOrigYuv[i] = NULL; } } if(m_ppcBestCU) { delete [] m_ppcBestCU; m_ppcBestCU = NULL; } if(m_ppcTempCU) { delete [] m_ppcTempCU; m_ppcTempCU = NULL; } if(m_ppcPredYuvBest) { delete [] m_ppcPredYuvBest; m_ppcPredYuvBest = NULL; } if(m_ppcResiYuvBest) { delete [] m_ppcResiYuvBest; m_ppcResiYuvBest = NULL; } if(m_ppcRecoYuvBest) { delete [] m_ppcRecoYuvBest; m_ppcRecoYuvBest = NULL; } if(m_ppcPredYuvTemp) { delete [] m_ppcPredYuvTemp; m_ppcPredYuvTemp = NULL; } if(m_ppcResiYuvTemp) { delete [] m_ppcResiYuvTemp; m_ppcResiYuvTemp = NULL; } if(m_ppcRecoYuvTemp) { delete [] m_ppcRecoYuvTemp; m_ppcRecoYuvTemp = NULL; } if(m_ppcOrigYuv) { delete [] m_ppcOrigYuv; m_ppcOrigYuv = NULL; } } /** \param pcEncTop pointer of encoder class */ Void TEncCu::init( TEncTop* pcEncTop ) { m_pcEncCfg = pcEncTop; m_pcPredSearch = pcEncTop->getPredSearch(); m_pcTrQuant = pcEncTop->getTrQuant(); m_pcRdCost = pcEncTop->getRdCost(); m_pcEntropyCoder = pcEncTop->getEntropyCoder(); m_pcBinCABAC = pcEncTop->getBinCABAC(); m_pppcRDSbacCoder = pcEncTop->getRDSbacCoder(); m_pcRDGoOnSbacCoder = pcEncTop->getRDGoOnSbacCoder(); m_pcRateCtrl = pcEncTop->getRateCtrl(); } // ==================================================================================================================== // Public member functions // ==================================================================================================================== /** \param rpcCU pointer of CU data class */ Void TEncCu::compressCtu( TComDataCU* pCtu ) { // initialize CU data m_ppcBestCU[0]->initCtu( pCtu->getPic(), pCtu->getCtuRsAddr() ); m_ppcTempCU[0]->initCtu( pCtu->getPic(), pCtu->getCtuRsAddr() ); // analysis of CU DEBUG_STRING_NEW(sDebug) xCompressCU( m_ppcBestCU[0], m_ppcTempCU[0], 0 DEBUG_STRING_PASS_INTO(sDebug) ); DEBUG_STRING_OUTPUT(std::cout, sDebug) #if ADAPTIVE_QP_SELECTION if( m_pcEncCfg->getUseAdaptQpSelect() ) { if(pCtu->getSlice()->getSliceType()!=I_SLICE) //IIII { xCtuCollectARLStats( pCtu ); } } #endif } /** \param pcCU pointer of CU data class */ Void TEncCu::encodeCtu ( TComDataCU* pCtu ) { if ( pCtu->getSlice()->getPPS()->getUseDQP() ) { setdQPFlag(true); } if ( pCtu->getSlice()->getUseChromaQpAdj() ) { setCodeChromaQpAdjFlag(true); } // Encode CU data xEncodeCU( pCtu, 0, 0 ); } // ==================================================================================================================== // Protected member functions // ==================================================================================================================== /** Derive small set of test modes for AMP encoder speed-up *\param rpcBestCU *\param eParentPartSize *\param bTestAMP_Hor *\param bTestAMP_Ver *\param bTestMergeAMP_Hor *\param bTestMergeAMP_Ver *\returns Void */ #if AMP_ENC_SPEEDUP #if AMP_MRG Void TEncCu::deriveTestModeAMP (TComDataCU *pcBestCU, PartSize eParentPartSize, Bool &bTestAMP_Hor, Bool &bTestAMP_Ver, Bool &bTestMergeAMP_Hor, Bool &bTestMergeAMP_Ver) #else Void TEncCu::deriveTestModeAMP (TComDataCU *pcBestCU, PartSize eParentPartSize, Bool &bTestAMP_Hor, Bool &bTestAMP_Ver) #endif { if ( pcBestCU->getPartitionSize(0) == SIZE_2NxN ) { bTestAMP_Hor = true; } else if ( pcBestCU->getPartitionSize(0) == SIZE_Nx2N ) { bTestAMP_Ver = true; } else if ( pcBestCU->getPartitionSize(0) == SIZE_2Nx2N && pcBestCU->getMergeFlag(0) == false && pcBestCU->isSkipped(0) == false ) { bTestAMP_Hor = true; bTestAMP_Ver = true; } #if AMP_MRG //! Utilizing the partition size of parent PU if ( eParentPartSize >= SIZE_2NxnU && eParentPartSize <= SIZE_nRx2N ) { bTestMergeAMP_Hor = true; bTestMergeAMP_Ver = true; } if ( eParentPartSize == NUMBER_OF_PART_SIZES ) //! if parent is intra { if ( pcBestCU->getPartitionSize(0) == SIZE_2NxN ) { bTestMergeAMP_Hor = true; } else if ( pcBestCU->getPartitionSize(0) == SIZE_Nx2N ) { bTestMergeAMP_Ver = true; } } if ( pcBestCU->getPartitionSize(0) == SIZE_2Nx2N && pcBestCU->isSkipped(0) == false ) { bTestMergeAMP_Hor = true; bTestMergeAMP_Ver = true; } if ( pcBestCU->getWidth(0) == 64 ) { bTestAMP_Hor = false; bTestAMP_Ver = false; } #else //! Utilizing the partition size of parent PU if ( eParentPartSize >= SIZE_2NxnU && eParentPartSize <= SIZE_nRx2N ) { bTestAMP_Hor = true; bTestAMP_Ver = true; } if ( eParentPartSize == SIZE_2Nx2N ) { bTestAMP_Hor = false; bTestAMP_Ver = false; } #endif } #endif // ==================================================================================================================== // Protected member functions // ==================================================================================================================== /** Compress a CU block recursively with enabling sub-CTU-level delta QP *\param rpcBestCU *\param rpcTempCU *\param uiDepth *\returns Void * *- for loop of QP value to compress the current CU with all possible QP */ #if AMP_ENC_SPEEDUP Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, UInt uiDepth DEBUG_STRING_FN_DECLARE(sDebug_), PartSize eParentPartSize ) #else Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, UInt uiDepth ) #endif { TComPic* pcPic = rpcBestCU->getPic(); DEBUG_STRING_NEW(sDebug) // get Original YUV data from picture m_ppcOrigYuv[uiDepth]->copyFromPicYuv( pcPic->getPicYuvOrg(), rpcBestCU->getCtuRsAddr(), rpcBestCU->getZorderIdxInCtu() ); // variable for Early CU determination Bool bSubBranch = true; // variable for Cbf fast mode PU decision Bool doNotBlockPu = true; Bool earlyDetectionSkipMode = false; Bool bBoundary = false; UInt uiLPelX = rpcBestCU->getCUPelX(); UInt uiRPelX = uiLPelX + rpcBestCU->getWidth(0) - 1; UInt uiTPelY = rpcBestCU->getCUPelY(); UInt uiBPelY = uiTPelY + rpcBestCU->getHeight(0) - 1; Int iBaseQP = xComputeQP( rpcBestCU, uiDepth ); Int iMinQP; Int iMaxQP; Bool isAddLowestQP = false; const UInt numberValidComponents = rpcBestCU->getPic()->getNumberValidComponents(); if( (g_uiMaxCUWidth>>uiDepth) >= rpcTempCU->getSlice()->getPPS()->getMinCuDQPSize() ) { Int idQP = m_pcEncCfg->getMaxDeltaQP(); iMinQP = Clip3( -rpcTempCU->getSlice()->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP-idQP ); iMaxQP = Clip3( -rpcTempCU->getSlice()->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP+idQP ); } else { iMinQP = rpcTempCU->getQP(0); iMaxQP = rpcTempCU->getQP(0); } if ( m_pcEncCfg->getUseRateCtrl() ) { iMinQP = m_pcRateCtrl->getRCQP(); iMaxQP = m_pcRateCtrl->getRCQP(); } // transquant-bypass (TQB) processing loop variable initialisation --- const Int lowestQP = iMinQP; // For TQB, use this QP which is the lowest non TQB QP tested (rather than QP'=0) - that way delta QPs are smaller, and TQB can be tested at all CU levels. if ( (rpcTempCU->getSlice()->getPPS()->getTransquantBypassEnableFlag()) ) { isAddLowestQP = true; // mark that the first iteration is to cost TQB mode. iMinQP = iMinQP - 1; // increase loop variable range by 1, to allow testing of TQB mode along with other QPs if ( m_pcEncCfg->getCUTransquantBypassFlagForceValue() ) { iMaxQP = iMinQP; } } TComSlice * pcSlice = rpcTempCU->getPic()->getSlice(rpcTempCU->getPic()->getCurrSliceIdx()); // We need to split, so don't try these modes. if ( ( uiRPelX < rpcBestCU->getSlice()->getSPS()->getPicWidthInLumaSamples() ) && ( uiBPelY < rpcBestCU->getSlice()->getSPS()->getPicHeightInLumaSamples() ) ) { for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++) { const Bool bIsLosslessMode = isAddLowestQP && (iQP == iMinQP); if (bIsLosslessMode) { iQP = lowestQP; } m_ChromaQpAdjIdc = 0; if (pcSlice->getUseChromaQpAdj()) { /* Pre-estimation of chroma QP based on input block activity may be performed * here, using for example m_ppcOrigYuv[uiDepth] */ /* To exercise the current code, the index used for adjustment is based on * block position */ Int lgMinCuSize = pcSlice->getSPS()->getLog2MinCodingBlockSize(); m_ChromaQpAdjIdc = ((uiLPelX >> lgMinCuSize) + (uiTPelY >> lgMinCuSize)) % (pcSlice->getPPS()->getChromaQpAdjTableSize() + 1); } rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); // do inter modes, SKIP and 2Nx2N if( rpcBestCU->getSlice()->getSliceType() != I_SLICE ) { // 2Nx2N if(m_pcEncCfg->getUseEarlySkipDetection()) { xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2Nx2N DEBUG_STRING_PASS_INTO(sDebug) ); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );//by Competition for inter_2Nx2N } // SKIP xCheckRDCostMerge2Nx2N( rpcBestCU, rpcTempCU DEBUG_STRING_PASS_INTO(sDebug), &earlyDetectionSkipMode );//by Merge for inter_2Nx2N rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); if(!m_pcEncCfg->getUseEarlySkipDetection()) { // 2Nx2N, NxN xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2Nx2N DEBUG_STRING_PASS_INTO(sDebug) ); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); if(m_pcEncCfg->getUseCbfFastMode()) { doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0; } } } if (bIsLosslessMode) // Restore loop variable if lossless mode was searched. { iQP = iMinQP; } } if(!earlyDetectionSkipMode) { for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++) { const Bool bIsLosslessMode = isAddLowestQP && (iQP == iMinQP); // If lossless, then iQP is irrelevant for subsequent modules. if (bIsLosslessMode) { iQP = lowestQP; } rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); // do inter modes, NxN, 2NxN, and Nx2N if( rpcBestCU->getSlice()->getSliceType() != I_SLICE ) { // 2Nx2N, NxN if(!( (rpcBestCU->getWidth(0)==8) && (rpcBestCU->getHeight(0)==8) )) { if( uiDepth == g_uiMaxCUDepth - g_uiAddCUDepth && doNotBlockPu) { xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_NxN DEBUG_STRING_PASS_INTO(sDebug) ); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); } } if(doNotBlockPu) { xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_Nx2N DEBUG_STRING_PASS_INTO(sDebug) ); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_Nx2N ) { doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0; } } if(doNotBlockPu) { xCheckRDCostInter ( rpcBestCU, rpcTempCU, SIZE_2NxN DEBUG_STRING_PASS_INTO(sDebug) ); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxN) { doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0; } } //! Try AMP (SIZE_2NxnU, SIZE_2NxnD, SIZE_nLx2N, SIZE_nRx2N) if( pcPic->getSlice(0)->getSPS()->getAMPAcc(uiDepth) ) { #if AMP_ENC_SPEEDUP Bool bTestAMP_Hor = false, bTestAMP_Ver = false; #if AMP_MRG Bool bTestMergeAMP_Hor = false, bTestMergeAMP_Ver = false; deriveTestModeAMP (rpcBestCU, eParentPartSize, bTestAMP_Hor, bTestAMP_Ver, bTestMergeAMP_Hor, bTestMergeAMP_Ver); #else deriveTestModeAMP (rpcBestCU, eParentPartSize, bTestAMP_Hor, bTestAMP_Ver); #endif //! Do horizontal AMP if ( bTestAMP_Hor ) { if(doNotBlockPu) { xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnU DEBUG_STRING_PASS_INTO(sDebug) ); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxnU ) { doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0; } } if(doNotBlockPu) { xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnD DEBUG_STRING_PASS_INTO(sDebug) ); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxnD ) { doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0; } } } #if AMP_MRG else if ( bTestMergeAMP_Hor ) { if(doNotBlockPu) { xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnU DEBUG_STRING_PASS_INTO(sDebug), true ); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxnU ) { doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0; } } if(doNotBlockPu) { xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnD DEBUG_STRING_PASS_INTO(sDebug), true ); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_2NxnD ) { doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0; } } } #endif //! Do horizontal AMP if ( bTestAMP_Ver ) { if(doNotBlockPu) { xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nLx2N DEBUG_STRING_PASS_INTO(sDebug) ); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_nLx2N ) { doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0; } } if(doNotBlockPu) { xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nRx2N DEBUG_STRING_PASS_INTO(sDebug) ); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); } } #if AMP_MRG else if ( bTestMergeAMP_Ver ) { if(doNotBlockPu) { xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nLx2N DEBUG_STRING_PASS_INTO(sDebug), true ); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); if(m_pcEncCfg->getUseCbfFastMode() && rpcBestCU->getPartitionSize(0) == SIZE_nLx2N ) { doNotBlockPu = rpcBestCU->getQtRootCbf( 0 ) != 0; } } if(doNotBlockPu) { xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nRx2N DEBUG_STRING_PASS_INTO(sDebug), true ); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); } } #endif #else xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnU ); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_2NxnD ); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nLx2N ); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); xCheckRDCostInter( rpcBestCU, rpcTempCU, SIZE_nRx2N ); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); #endif } } // do normal intra modes // speedup for inter frames Double intraCost = 0.0; if((rpcBestCU->getSlice()->getSliceType() == I_SLICE) || (rpcBestCU->getCbf( 0, COMPONENT_Y ) != 0) || ((rpcBestCU->getCbf( 0, COMPONENT_Cb ) != 0) && (numberValidComponents > COMPONENT_Cb)) || ((rpcBestCU->getCbf( 0, COMPONENT_Cr ) != 0) && (numberValidComponents > COMPONENT_Cr)) ) // avoid very complex intra if it is unlikely { xCheckRDCostIntra( rpcBestCU, rpcTempCU, intraCost, SIZE_2Nx2N DEBUG_STRING_PASS_INTO(sDebug) ); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); if( uiDepth == g_uiMaxCUDepth - g_uiAddCUDepth ) { if( rpcTempCU->getWidth(0) > ( 1 << rpcTempCU->getSlice()->getSPS()->getQuadtreeTULog2MinSize() ) ) { Double tmpIntraCost; xCheckRDCostIntra( rpcBestCU, rpcTempCU, tmpIntraCost, SIZE_NxN DEBUG_STRING_PASS_INTO(sDebug) ); intraCost = std::min(intraCost, tmpIntraCost); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); } } } // test PCM if(pcPic->getSlice(0)->getSPS()->getUsePCM() && rpcTempCU->getWidth(0) <= (1<getSlice(0)->getSPS()->getPCMLog2MaxSize()) && rpcTempCU->getWidth(0) >= (1<getSlice(0)->getSPS()->getPCMLog2MinSize()) ) { UInt uiRawBits = getTotalBits(rpcBestCU->getWidth(0), rpcBestCU->getHeight(0), rpcBestCU->getPic()->getChromaFormat(), g_bitDepth); UInt uiBestBits = rpcBestCU->getTotalBits(); if((uiBestBits > uiRawBits) || (rpcBestCU->getTotalCost() > m_pcRdCost->calcRdCost(uiRawBits, 0))) { xCheckIntraPCM (rpcBestCU, rpcTempCU); rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); } } if (bIsLosslessMode) // Restore loop variable if lossless mode was searched. { iQP = iMinQP; } } } m_pcEntropyCoder->resetBits(); m_pcEntropyCoder->encodeSplitFlag( rpcBestCU, 0, uiDepth, true ); rpcBestCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // split bits rpcBestCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded(); rpcBestCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcBestCU->getTotalBits(), rpcBestCU->getTotalDistortion() ); // Early CU determination if( m_pcEncCfg->getUseEarlyCU() && rpcBestCU->isSkipped(0) ) { bSubBranch = false; } else { bSubBranch = true; } } else { bBoundary = true; } // copy orginal YUV samples to PCM buffer if( rpcBestCU->isLosslessCoded(0) && (rpcBestCU->getIPCMFlag(0) == false)) { xFillPCMBuffer(rpcBestCU, m_ppcOrigYuv[uiDepth]); } if( (g_uiMaxCUWidth>>uiDepth) == rpcTempCU->getSlice()->getPPS()->getMinCuDQPSize() ) { Int idQP = m_pcEncCfg->getMaxDeltaQP(); iMinQP = Clip3( -rpcTempCU->getSlice()->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP-idQP ); iMaxQP = Clip3( -rpcTempCU->getSlice()->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP+idQP ); } else if( (g_uiMaxCUWidth>>uiDepth) > rpcTempCU->getSlice()->getPPS()->getMinCuDQPSize() ) { iMinQP = iBaseQP; iMaxQP = iBaseQP; } else { const Int iStartQP = rpcTempCU->getQP(0); iMinQP = iStartQP; iMaxQP = iStartQP; } if ( m_pcEncCfg->getUseRateCtrl() ) { iMinQP = m_pcRateCtrl->getRCQP(); iMaxQP = m_pcRateCtrl->getRCQP(); } if ( m_pcEncCfg->getCUTransquantBypassFlagForceValue() ) { iMaxQP = iMinQP; // If all TUs are forced into using transquant bypass, do not loop here. } for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++) { const Bool bIsLosslessMode = false; // False at this level. Next level down may set it to true. rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode ); // further split if( bSubBranch && uiDepth < g_uiMaxCUDepth - g_uiAddCUDepth ) { UChar uhNextDepth = uiDepth+1; TComDataCU* pcSubBestPartCU = m_ppcBestCU[uhNextDepth]; TComDataCU* pcSubTempPartCU = m_ppcTempCU[uhNextDepth]; DEBUG_STRING_NEW(sTempDebug) for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 4; uiPartUnitIdx++ ) { pcSubBestPartCU->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP ); // clear sub partition datas or init. pcSubTempPartCU->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP ); // clear sub partition datas or init. if( ( pcSubBestPartCU->getCUPelX() < pcSlice->getSPS()->getPicWidthInLumaSamples() ) && ( pcSubBestPartCU->getCUPelY() < pcSlice->getSPS()->getPicHeightInLumaSamples() ) ) { if ( 0 == uiPartUnitIdx) //initialize RD with previous depth buffer { m_pppcRDSbacCoder[uhNextDepth][CI_CURR_BEST]->load(m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST]); } else { m_pppcRDSbacCoder[uhNextDepth][CI_CURR_BEST]->load(m_pppcRDSbacCoder[uhNextDepth][CI_NEXT_BEST]); } #if AMP_ENC_SPEEDUP DEBUG_STRING_NEW(sChild) if ( !rpcBestCU->isInter(0) ) { xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth DEBUG_STRING_PASS_INTO(sChild), NUMBER_OF_PART_SIZES ); } else { xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth DEBUG_STRING_PASS_INTO(sChild), rpcBestCU->getPartitionSize(0) ); } DEBUG_STRING_APPEND(sTempDebug, sChild) #else xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth ); #endif rpcTempCU->copyPartFrom( pcSubBestPartCU, uiPartUnitIdx, uhNextDepth ); // Keep best part data to current temporary data. xCopyYuv2Tmp( pcSubBestPartCU->getTotalNumPart()*uiPartUnitIdx, uhNextDepth ); } else { pcSubBestPartCU->copyToPic( uhNextDepth ); rpcTempCU->copyPartFrom( pcSubBestPartCU, uiPartUnitIdx, uhNextDepth ); } } if( !bBoundary ) { m_pcEntropyCoder->resetBits(); m_pcEntropyCoder->encodeSplitFlag( rpcTempCU, 0, uiDepth, true ); rpcTempCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // split bits rpcTempCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded(); } rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() ); if( (g_uiMaxCUWidth>>uiDepth) == rpcTempCU->getSlice()->getPPS()->getMinCuDQPSize() && rpcTempCU->getSlice()->getPPS()->getUseDQP()) { Bool hasResidual = false; for( UInt uiBlkIdx = 0; uiBlkIdx < rpcTempCU->getTotalNumPart(); uiBlkIdx ++) { if( ( rpcTempCU->getCbf(uiBlkIdx, COMPONENT_Y) || (rpcTempCU->getCbf(uiBlkIdx, COMPONENT_Cb) && (numberValidComponents > COMPONENT_Cb)) || (rpcTempCU->getCbf(uiBlkIdx, COMPONENT_Cr) && (numberValidComponents > COMPONENT_Cr)) ) ) { hasResidual = true; break; } } UInt uiTargetPartIdx = 0; if ( hasResidual ) { #if !RDO_WITHOUT_DQP_BITS m_pcEntropyCoder->resetBits(); m_pcEntropyCoder->encodeQP( rpcTempCU, uiTargetPartIdx, false ); rpcTempCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // dQP bits rpcTempCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded(); rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() ); #endif Bool foundNonZeroCbf = false; rpcTempCU->setQPSubCUs( rpcTempCU->getRefQP( uiTargetPartIdx ), 0, uiDepth, foundNonZeroCbf ); assert( foundNonZeroCbf ); } else { rpcTempCU->setQPSubParts( rpcTempCU->getRefQP( uiTargetPartIdx ), 0, uiDepth ); // set QP to default QP } } m_pppcRDSbacCoder[uhNextDepth][CI_NEXT_BEST]->store(m_pppcRDSbacCoder[uiDepth][CI_TEMP_BEST]); // TODO: this does not account for the slice bytes already written. See other instances of FIXED_NUMBER_OF_BYTES Bool isEndOfSlice = rpcBestCU->getSlice()->getSliceMode()==FIXED_NUMBER_OF_BYTES && (rpcBestCU->getTotalBits()>rpcBestCU->getSlice()->getSliceArgument()<<3); Bool isEndOfSliceSegment = rpcBestCU->getSlice()->getSliceSegmentMode()==FIXED_NUMBER_OF_BYTES && (rpcBestCU->getTotalBits()>rpcBestCU->getSlice()->getSliceSegmentArgument()<<3); if(isEndOfSlice||isEndOfSliceSegment) { if (m_pcEncCfg->getCostMode()==COST_MIXED_LOSSLESS_LOSSY_CODING) rpcBestCU->getTotalCost()=rpcTempCU->getTotalCost() + (1.0 / m_pcRdCost->getLambda()); else rpcBestCU->getTotalCost()=rpcTempCU->getTotalCost()+1; } xCheckBestMode( rpcBestCU, rpcTempCU, uiDepth DEBUG_STRING_PASS_INTO(sDebug) DEBUG_STRING_PASS_INTO(sTempDebug) DEBUG_STRING_PASS_INTO(false) ); // RD compare current larger prediction // with sub partitioned prediction. } } DEBUG_STRING_APPEND(sDebug_, sDebug); rpcBestCU->copyToPic(uiDepth); // Copy Best data to Picture for next partition prediction. xCopyYuv2Pic( rpcBestCU->getPic(), rpcBestCU->getCtuRsAddr(), rpcBestCU->getZorderIdxInCtu(), uiDepth, uiDepth, rpcBestCU, uiLPelX, uiTPelY ); // Copy Yuv data to picture Yuv if (bBoundary) { return; } // Assert if Best prediction mode is NONE // Selected mode's RD-cost must be not MAX_DOUBLE. assert( rpcBestCU->getPartitionSize ( 0 ) != NUMBER_OF_PART_SIZES ); assert( rpcBestCU->getPredictionMode( 0 ) != NUMBER_OF_PREDICTION_MODES ); assert( rpcBestCU->getTotalCost ( ) != MAX_DOUBLE ); } /** finish encoding a cu and handle end-of-slice conditions * \param pcCU * \param uiAbsPartIdx * \param uiDepth * \returns Void */ Void TEncCu::finishCU( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) { TComPic* pcPic = pcCU->getPic(); TComSlice * pcSlice = pcCU->getPic()->getSlice(pcCU->getPic()->getCurrSliceIdx()); //Calculate end address const Int currentCTUTsAddr = pcPic->getPicSym()->getCtuRsToTsAddrMap(pcCU->getCtuRsAddr()); const Bool isLastSubCUOfCtu = pcCU->isLastSubCUOfCtu(uiAbsPartIdx); if ( isLastSubCUOfCtu ) { // The 1-terminating bit is added to all streams, so don't add it here when it's 1. // i.e. when the slice segment CurEnd CTU address is the current CTU address+1. if (pcSlice->getSliceSegmentCurEndCtuTsAddr() != currentCTUTsAddr+1) { m_pcEntropyCoder->encodeTerminatingBit( 0 ); } } } /** Compute QP for each CU * \param pcCU Target CU * \param uiDepth CU depth * \returns quantization parameter */ Int TEncCu::xComputeQP( TComDataCU* pcCU, UInt uiDepth ) { Int iBaseQp = pcCU->getSlice()->getSliceQp(); Int iQpOffset = 0; if ( m_pcEncCfg->getUseAdaptiveQP() ) { TEncPic* pcEPic = dynamic_cast( pcCU->getPic() ); UInt uiAQDepth = min( uiDepth, pcEPic->getMaxAQDepth()-1 ); TEncPicQPAdaptationLayer* pcAQLayer = pcEPic->getAQLayer( uiAQDepth ); UInt uiAQUPosX = pcCU->getCUPelX() / pcAQLayer->getAQPartWidth(); UInt uiAQUPosY = pcCU->getCUPelY() / pcAQLayer->getAQPartHeight(); UInt uiAQUStride = pcAQLayer->getAQPartStride(); TEncQPAdaptationUnit* acAQU = pcAQLayer->getQPAdaptationUnit(); Double dMaxQScale = pow(2.0, m_pcEncCfg->getQPAdaptationRange()/6.0); Double dAvgAct = pcAQLayer->getAvgActivity(); Double dCUAct = acAQU[uiAQUPosY * uiAQUStride + uiAQUPosX].getActivity(); Double dNormAct = (dMaxQScale*dCUAct + dAvgAct) / (dCUAct + dMaxQScale*dAvgAct); Double dQpOffset = log(dNormAct) / log(2.0) * 6.0; iQpOffset = Int(floor( dQpOffset + 0.49999 )); } return Clip3(-pcCU->getSlice()->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQp+iQpOffset ); } /** encode a CU block recursively * \param pcCU * \param uiAbsPartIdx * \param uiDepth * \returns Void */ Void TEncCu::xEncodeCU( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) { TComPic* pcPic = pcCU->getPic(); Bool bBoundary = false; UInt uiLPelX = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsPartIdx] ]; UInt uiRPelX = uiLPelX + (g_uiMaxCUWidth>>uiDepth) - 1; UInt uiTPelY = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsPartIdx] ]; UInt uiBPelY = uiTPelY + (g_uiMaxCUHeight>>uiDepth) - 1; TComSlice * pcSlice = pcCU->getPic()->getSlice(pcCU->getPic()->getCurrSliceIdx()); if( ( uiRPelX < pcSlice->getSPS()->getPicWidthInLumaSamples() ) && ( uiBPelY < pcSlice->getSPS()->getPicHeightInLumaSamples() ) ) { m_pcEntropyCoder->encodeSplitFlag( pcCU, uiAbsPartIdx, uiDepth ); } else { bBoundary = true; } if( ( ( uiDepth < pcCU->getDepth( uiAbsPartIdx ) ) && ( uiDepth < (g_uiMaxCUDepth-g_uiAddCUDepth) ) ) || bBoundary ) { UInt uiQNumParts = ( pcPic->getNumPartitionsInCtu() >> (uiDepth<<1) )>>2; if( (g_uiMaxCUWidth>>uiDepth) == pcCU->getSlice()->getPPS()->getMinCuDQPSize() && pcCU->getSlice()->getPPS()->getUseDQP()) { setdQPFlag(true); } if( (g_uiMaxCUWidth>>uiDepth) == pcCU->getSlice()->getPPS()->getMinCuChromaQpAdjSize() && pcCU->getSlice()->getUseChromaQpAdj()) { setCodeChromaQpAdjFlag(true); } for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 4; uiPartUnitIdx++, uiAbsPartIdx+=uiQNumParts ) { uiLPelX = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsPartIdx] ]; uiTPelY = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsPartIdx] ]; if( ( uiLPelX < pcSlice->getSPS()->getPicWidthInLumaSamples() ) && ( uiTPelY < pcSlice->getSPS()->getPicHeightInLumaSamples() ) ) { xEncodeCU( pcCU, uiAbsPartIdx, uiDepth+1 ); } } return; } if( (g_uiMaxCUWidth>>uiDepth) >= pcCU->getSlice()->getPPS()->getMinCuDQPSize() && pcCU->getSlice()->getPPS()->getUseDQP()) { setdQPFlag(true); } if( (g_uiMaxCUWidth>>uiDepth) >= pcCU->getSlice()->getPPS()->getMinCuChromaQpAdjSize() && pcCU->getSlice()->getUseChromaQpAdj()) { setCodeChromaQpAdjFlag(true); } if (pcCU->getSlice()->getPPS()->getTransquantBypassEnableFlag()) { m_pcEntropyCoder->encodeCUTransquantBypassFlag( pcCU, uiAbsPartIdx ); } if( !pcCU->getSlice()->isIntra() ) { m_pcEntropyCoder->encodeSkipFlag( pcCU, uiAbsPartIdx ); } if( pcCU->isSkipped( uiAbsPartIdx ) ) { m_pcEntropyCoder->encodeMergeIndex( pcCU, uiAbsPartIdx ); finishCU(pcCU,uiAbsPartIdx,uiDepth); return; } m_pcEntropyCoder->encodePredMode( pcCU, uiAbsPartIdx ); m_pcEntropyCoder->encodePartSize( pcCU, uiAbsPartIdx, uiDepth ); if (pcCU->isIntra( uiAbsPartIdx ) && pcCU->getPartitionSize( uiAbsPartIdx ) == SIZE_2Nx2N ) { m_pcEntropyCoder->encodeIPCMInfo( pcCU, uiAbsPartIdx ); if(pcCU->getIPCMFlag(uiAbsPartIdx)) { // Encode slice finish finishCU(pcCU,uiAbsPartIdx,uiDepth); return; } } // prediction Info ( Intra : direction mode, Inter : Mv, reference idx ) m_pcEntropyCoder->encodePredInfo( pcCU, uiAbsPartIdx ); // Encode Coefficients Bool bCodeDQP = getdQPFlag(); Bool codeChromaQpAdj = getCodeChromaQpAdjFlag(); m_pcEntropyCoder->encodeCoeff( pcCU, uiAbsPartIdx, uiDepth, bCodeDQP, codeChromaQpAdj ); setCodeChromaQpAdjFlag( codeChromaQpAdj ); setdQPFlag( bCodeDQP ); // --- write terminating bit --- finishCU(pcCU,uiAbsPartIdx,uiDepth); } Int xCalcHADs8x8_ISlice(Pel *piOrg, Int iStrideOrg) { Int k, i, j, jj; Int diff[64], m1[8][8], m2[8][8], m3[8][8], iSumHad = 0; for( k = 0; k < 64; k += 8 ) { diff[k+0] = piOrg[0] ; diff[k+1] = piOrg[1] ; diff[k+2] = piOrg[2] ; diff[k+3] = piOrg[3] ; diff[k+4] = piOrg[4] ; diff[k+5] = piOrg[5] ; diff[k+6] = piOrg[6] ; diff[k+7] = piOrg[7] ; piOrg += iStrideOrg; } //horizontal for (j=0; j < 8; j++) { jj = j << 3; m2[j][0] = diff[jj ] + diff[jj+4]; m2[j][1] = diff[jj+1] + diff[jj+5]; m2[j][2] = diff[jj+2] + diff[jj+6]; m2[j][3] = diff[jj+3] + diff[jj+7]; m2[j][4] = diff[jj ] - diff[jj+4]; m2[j][5] = diff[jj+1] - diff[jj+5]; m2[j][6] = diff[jj+2] - diff[jj+6]; m2[j][7] = diff[jj+3] - diff[jj+7]; m1[j][0] = m2[j][0] + m2[j][2]; m1[j][1] = m2[j][1] + m2[j][3]; m1[j][2] = m2[j][0] - m2[j][2]; m1[j][3] = m2[j][1] - m2[j][3]; m1[j][4] = m2[j][4] + m2[j][6]; m1[j][5] = m2[j][5] + m2[j][7]; m1[j][6] = m2[j][4] - m2[j][6]; m1[j][7] = m2[j][5] - m2[j][7]; m2[j][0] = m1[j][0] + m1[j][1]; m2[j][1] = m1[j][0] - m1[j][1]; m2[j][2] = m1[j][2] + m1[j][3]; m2[j][3] = m1[j][2] - m1[j][3]; m2[j][4] = m1[j][4] + m1[j][5]; m2[j][5] = m1[j][4] - m1[j][5]; m2[j][6] = m1[j][6] + m1[j][7]; m2[j][7] = m1[j][6] - m1[j][7]; } //vertical for (i=0; i < 8; i++) { m3[0][i] = m2[0][i] + m2[4][i]; m3[1][i] = m2[1][i] + m2[5][i]; m3[2][i] = m2[2][i] + m2[6][i]; m3[3][i] = m2[3][i] + m2[7][i]; m3[4][i] = m2[0][i] - m2[4][i]; m3[5][i] = m2[1][i] - m2[5][i]; m3[6][i] = m2[2][i] - m2[6][i]; m3[7][i] = m2[3][i] - m2[7][i]; m1[0][i] = m3[0][i] + m3[2][i]; m1[1][i] = m3[1][i] + m3[3][i]; m1[2][i] = m3[0][i] - m3[2][i]; m1[3][i] = m3[1][i] - m3[3][i]; m1[4][i] = m3[4][i] + m3[6][i]; m1[5][i] = m3[5][i] + m3[7][i]; m1[6][i] = m3[4][i] - m3[6][i]; m1[7][i] = m3[5][i] - m3[7][i]; m2[0][i] = m1[0][i] + m1[1][i]; m2[1][i] = m1[0][i] - m1[1][i]; m2[2][i] = m1[2][i] + m1[3][i]; m2[3][i] = m1[2][i] - m1[3][i]; m2[4][i] = m1[4][i] + m1[5][i]; m2[5][i] = m1[4][i] - m1[5][i]; m2[6][i] = m1[6][i] + m1[7][i]; m2[7][i] = m1[6][i] - m1[7][i]; } for (i = 0; i < 8; i++) { for (j = 0; j < 8; j++) { iSumHad += abs(m2[i][j]); } } iSumHad -= abs(m2[0][0]); iSumHad =(iSumHad+2)>>2; return(iSumHad); } Int TEncCu::updateCtuDataISlice(TComDataCU* pCtu, Int width, Int height) { Int xBl, yBl; const Int iBlkSize = 8; Pel* pOrgInit = pCtu->getPic()->getPicYuvOrg()->getAddr(COMPONENT_Y, pCtu->getCtuRsAddr(), 0); Int iStrideOrig = pCtu->getPic()->getPicYuvOrg()->getStride(COMPONENT_Y); Pel *pOrg; Int iSumHad = 0; for ( yBl=0; (yBl+iBlkSize)<=height; yBl+= iBlkSize) { for ( xBl=0; (xBl+iBlkSize)<=width; xBl+= iBlkSize) { pOrg = pOrgInit + iStrideOrig*yBl + xBl; iSumHad += xCalcHADs8x8_ISlice(pOrg, iStrideOrig); } } return(iSumHad); } /** check RD costs for a CU block encoded with merge * \param rpcBestCU * \param rpcTempCU * \returns Void */ Void TEncCu::xCheckRDCostMerge2Nx2N( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU DEBUG_STRING_FN_DECLARE(sDebug), Bool *earlyDetectionSkipMode ) { assert( rpcTempCU->getSlice()->getSliceType() != I_SLICE ); TComMvField cMvFieldNeighbours[2 * MRG_MAX_NUM_CANDS]; // double length for mv of both lists UChar uhInterDirNeighbours[MRG_MAX_NUM_CANDS]; Int numValidMergeCand = 0; const Bool bTransquantBypassFlag = rpcTempCU->getCUTransquantBypass(0); for( UInt ui = 0; ui < rpcTempCU->getSlice()->getMaxNumMergeCand(); ++ui ) { uhInterDirNeighbours[ui] = 0; } UChar uhDepth = rpcTempCU->getDepth( 0 ); rpcTempCU->setPartSizeSubParts( SIZE_2Nx2N, 0, uhDepth ); // interprets depth relative to CTU level rpcTempCU->getInterMergeCandidates( 0, 0, cMvFieldNeighbours,uhInterDirNeighbours, numValidMergeCand ); Int mergeCandBuffer[MRG_MAX_NUM_CANDS]; for( UInt ui = 0; ui < numValidMergeCand; ++ui ) { mergeCandBuffer[ui] = 0; } Bool bestIsSkip = false; UInt iteration; if ( rpcTempCU->isLosslessCoded(0)) { iteration = 1; } else { iteration = 2; } DEBUG_STRING_NEW(bestStr) for( UInt uiNoResidual = 0; uiNoResidual < iteration; ++uiNoResidual ) { for( UInt uiMergeCand = 0; uiMergeCand < numValidMergeCand; ++uiMergeCand ) { if(!(uiNoResidual==1 && mergeCandBuffer[uiMergeCand]==1)) { if( !(bestIsSkip && uiNoResidual == 0) ) { DEBUG_STRING_NEW(tmpStr) // set MC parameters rpcTempCU->setPredModeSubParts( MODE_INTER, 0, uhDepth ); // interprets depth relative to CTU level rpcTempCU->setCUTransquantBypassSubParts( bTransquantBypassFlag, 0, uhDepth ); rpcTempCU->setChromaQpAdjSubParts( bTransquantBypassFlag ? 0 : m_ChromaQpAdjIdc, 0, uhDepth ); rpcTempCU->setPartSizeSubParts( SIZE_2Nx2N, 0, uhDepth ); // interprets depth relative to CTU level rpcTempCU->setMergeFlagSubParts( true, 0, 0, uhDepth ); // interprets depth relative to CTU level rpcTempCU->setMergeIndexSubParts( uiMergeCand, 0, 0, uhDepth ); // interprets depth relative to CTU level rpcTempCU->setInterDirSubParts( uhInterDirNeighbours[uiMergeCand], 0, 0, uhDepth ); // interprets depth relative to CTU level rpcTempCU->getCUMvField( REF_PIC_LIST_0 )->setAllMvField( cMvFieldNeighbours[0 + 2*uiMergeCand], SIZE_2Nx2N, 0, 0 ); // interprets depth relative to rpcTempCU level rpcTempCU->getCUMvField( REF_PIC_LIST_1 )->setAllMvField( cMvFieldNeighbours[1 + 2*uiMergeCand], SIZE_2Nx2N, 0, 0 ); // interprets depth relative to rpcTempCU level // do MC m_pcPredSearch->motionCompensation ( rpcTempCU, m_ppcPredYuvTemp[uhDepth] ); // estimate residual and encode everything m_pcPredSearch->encodeResAndCalcRdInterCU( rpcTempCU, m_ppcOrigYuv [uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcResiYuvBest[uhDepth], m_ppcRecoYuvTemp[uhDepth], (uiNoResidual != 0) DEBUG_STRING_PASS_INTO(tmpStr) ); #ifdef DEBUG_STRING DebugInterPredResiReco(tmpStr, *(m_ppcPredYuvTemp[uhDepth]), *(m_ppcResiYuvBest[uhDepth]), *(m_ppcRecoYuvTemp[uhDepth]), DebugStringGetPredModeMask(rpcTempCU->getPredictionMode(0))); #endif if ((uiNoResidual == 0) && (rpcTempCU->getQtRootCbf(0) == 0)) { // If no residual when allowing for one, then set mark to not try case where residual is forced to 0 mergeCandBuffer[uiMergeCand] = 1; } rpcTempCU->setSkipFlagSubParts( rpcTempCU->getQtRootCbf(0) == 0, 0, uhDepth ); Int orgQP = rpcTempCU->getQP( 0 ); xCheckDQP( rpcTempCU ); xCheckBestMode(rpcBestCU, rpcTempCU, uhDepth DEBUG_STRING_PASS_INTO(bestStr) DEBUG_STRING_PASS_INTO(tmpStr)); rpcTempCU->initEstData( uhDepth, orgQP, bTransquantBypassFlag ); if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip ) { bestIsSkip = rpcBestCU->getQtRootCbf(0) == 0; } } } } if(uiNoResidual == 0 && m_pcEncCfg->getUseEarlySkipDetection()) { if(rpcBestCU->getQtRootCbf( 0 ) == 0) { if( rpcBestCU->getMergeFlag( 0 )) { *earlyDetectionSkipMode = true; } else if(m_pcEncCfg->getFastSearch() != SELECTIVE) { Int absoulte_MV=0; for ( UInt uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++ ) { if ( rpcBestCU->getSlice()->getNumRefIdx( RefPicList( uiRefListIdx ) ) > 0 ) { TComCUMvField* pcCUMvField = rpcBestCU->getCUMvField(RefPicList( uiRefListIdx )); Int iHor = pcCUMvField->getMvd( 0 ).getAbsHor(); Int iVer = pcCUMvField->getMvd( 0 ).getAbsVer(); absoulte_MV+=iHor+iVer; } } if(absoulte_MV == 0) { *earlyDetectionSkipMode = true; } } } } } DEBUG_STRING_APPEND(sDebug, bestStr) } #if AMP_MRG Void TEncCu::xCheckRDCostInter( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, PartSize ePartSize DEBUG_STRING_FN_DECLARE(sDebug), Bool bUseMRG) #else Void TEncCu::xCheckRDCostInter( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, PartSize ePartSize ) #endif { DEBUG_STRING_NEW(sTest) UChar uhDepth = rpcTempCU->getDepth( 0 ); rpcTempCU->setDepthSubParts( uhDepth, 0 ); rpcTempCU->setSkipFlagSubParts( false, 0, uhDepth ); rpcTempCU->setPartSizeSubParts ( ePartSize, 0, uhDepth ); rpcTempCU->setPredModeSubParts ( MODE_INTER, 0, uhDepth ); rpcTempCU->setChromaQpAdjSubParts( rpcTempCU->getCUTransquantBypass(0) ? 0 : m_ChromaQpAdjIdc, 0, uhDepth ); #if AMP_MRG rpcTempCU->setMergeAMP (true); m_pcPredSearch->predInterSearch ( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcRecoYuvTemp[uhDepth] DEBUG_STRING_PASS_INTO(sTest), false, bUseMRG ); #else m_pcPredSearch->predInterSearch ( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcRecoYuvTemp[uhDepth] ); #endif #if AMP_MRG if ( !rpcTempCU->getMergeAMP() ) { return; } #endif m_pcPredSearch->encodeResAndCalcRdInterCU( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcResiYuvBest[uhDepth], m_ppcRecoYuvTemp[uhDepth], false DEBUG_STRING_PASS_INTO(sTest) ); rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() ); #ifdef DEBUG_STRING DebugInterPredResiReco(sTest, *(m_ppcPredYuvTemp[uhDepth]), *(m_ppcResiYuvBest[uhDepth]), *(m_ppcRecoYuvTemp[uhDepth]), DebugStringGetPredModeMask(rpcTempCU->getPredictionMode(0))); #endif xCheckDQP( rpcTempCU ); xCheckBestMode(rpcBestCU, rpcTempCU, uhDepth DEBUG_STRING_PASS_INTO(sDebug) DEBUG_STRING_PASS_INTO(sTest)); } Void TEncCu::xCheckRDCostIntra( TComDataCU *&rpcBestCU, TComDataCU *&rpcTempCU, Double &cost, PartSize eSize DEBUG_STRING_FN_DECLARE(sDebug) ) { DEBUG_STRING_NEW(sTest) UInt uiDepth = rpcTempCU->getDepth( 0 ); rpcTempCU->setSkipFlagSubParts( false, 0, uiDepth ); rpcTempCU->setPartSizeSubParts( eSize, 0, uiDepth ); rpcTempCU->setPredModeSubParts( MODE_INTRA, 0, uiDepth ); rpcTempCU->setChromaQpAdjSubParts( rpcTempCU->getCUTransquantBypass(0) ? 0 : m_ChromaQpAdjIdc, 0, uiDepth ); Bool bSeparateLumaChroma = true; // choose estimation mode Distortion uiPreCalcDistC = 0; if (rpcBestCU->getPic()->getChromaFormat()==CHROMA_400) { bSeparateLumaChroma=true; } Pel resiLuma[NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE]; if( !bSeparateLumaChroma ) { // after this function, the direction will be PLANAR, DC, HOR or VER // however, if Luma ends up being one of those, the chroma dir must be later changed to DM_CHROMA. m_pcPredSearch->preestChromaPredMode( rpcTempCU, m_ppcOrigYuv[uiDepth], m_ppcPredYuvTemp[uiDepth] ); } m_pcPredSearch->estIntraPredQT( rpcTempCU, m_ppcOrigYuv[uiDepth], m_ppcPredYuvTemp[uiDepth], m_ppcResiYuvTemp[uiDepth], m_ppcRecoYuvTemp[uiDepth], resiLuma, uiPreCalcDistC, bSeparateLumaChroma DEBUG_STRING_PASS_INTO(sTest) ); m_ppcRecoYuvTemp[uiDepth]->copyToPicComponent(COMPONENT_Y, rpcTempCU->getPic()->getPicYuvRec(), rpcTempCU->getCtuRsAddr(), rpcTempCU->getZorderIdxInCtu() ); if (rpcBestCU->getPic()->getChromaFormat()!=CHROMA_400) { m_pcPredSearch->estIntraPredChromaQT( rpcTempCU, m_ppcOrigYuv[uiDepth], m_ppcPredYuvTemp[uiDepth], m_ppcResiYuvTemp[uiDepth], m_ppcRecoYuvTemp[uiDepth], resiLuma, uiPreCalcDistC DEBUG_STRING_PASS_INTO(sTest) ); } m_pcEntropyCoder->resetBits(); if ( rpcTempCU->getSlice()->getPPS()->getTransquantBypassEnableFlag()) { m_pcEntropyCoder->encodeCUTransquantBypassFlag( rpcTempCU, 0, true ); } m_pcEntropyCoder->encodeSkipFlag ( rpcTempCU, 0, true ); m_pcEntropyCoder->encodePredMode( rpcTempCU, 0, true ); m_pcEntropyCoder->encodePartSize( rpcTempCU, 0, uiDepth, true ); m_pcEntropyCoder->encodePredInfo( rpcTempCU, 0 ); m_pcEntropyCoder->encodeIPCMInfo(rpcTempCU, 0, true ); // Encode Coefficients Bool bCodeDQP = getdQPFlag(); Bool codeChromaQpAdjFlag = getCodeChromaQpAdjFlag(); m_pcEntropyCoder->encodeCoeff( rpcTempCU, 0, uiDepth, bCodeDQP, codeChromaQpAdjFlag ); setCodeChromaQpAdjFlag( codeChromaQpAdjFlag ); setdQPFlag( bCodeDQP ); m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[uiDepth][CI_TEMP_BEST]); rpcTempCU->getTotalBits() = m_pcEntropyCoder->getNumberOfWrittenBits(); rpcTempCU->getTotalBins() = ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded(); rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() ); xCheckDQP( rpcTempCU ); cost = rpcTempCU->getTotalCost(); xCheckBestMode(rpcBestCU, rpcTempCU, uiDepth DEBUG_STRING_PASS_INTO(sDebug) DEBUG_STRING_PASS_INTO(sTest)); } /** Check R-D costs for a CU with PCM mode. * \param rpcBestCU pointer to best mode CU data structure * \param rpcTempCU pointer to testing mode CU data structure * \returns Void * * \note Current PCM implementation encodes sample values in a lossless way. The distortion of PCM mode CUs are zero. PCM mode is selected if the best mode yields bits greater than that of PCM mode. */ Void TEncCu::xCheckIntraPCM( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU ) { UInt uiDepth = rpcTempCU->getDepth( 0 ); rpcTempCU->setSkipFlagSubParts( false, 0, uiDepth ); rpcTempCU->setIPCMFlag(0, true); rpcTempCU->setIPCMFlagSubParts (true, 0, rpcTempCU->getDepth(0)); rpcTempCU->setPartSizeSubParts( SIZE_2Nx2N, 0, uiDepth ); rpcTempCU->setPredModeSubParts( MODE_INTRA, 0, uiDepth ); rpcTempCU->setTrIdxSubParts ( 0, 0, uiDepth ); rpcTempCU->setChromaQpAdjSubParts( rpcTempCU->getCUTransquantBypass(0) ? 0 : m_ChromaQpAdjIdc, 0, uiDepth ); m_pcPredSearch->IPCMSearch( rpcTempCU, m_ppcOrigYuv[uiDepth], m_ppcPredYuvTemp[uiDepth], m_ppcResiYuvTemp[uiDepth], m_ppcRecoYuvTemp[uiDepth]); m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST]); m_pcEntropyCoder->resetBits(); if ( rpcTempCU->getSlice()->getPPS()->getTransquantBypassEnableFlag()) { m_pcEntropyCoder->encodeCUTransquantBypassFlag( rpcTempCU, 0, true ); } m_pcEntropyCoder->encodeSkipFlag ( rpcTempCU, 0, true ); m_pcEntropyCoder->encodePredMode ( rpcTempCU, 0, true ); m_pcEntropyCoder->encodePartSize ( rpcTempCU, 0, uiDepth, true ); m_pcEntropyCoder->encodeIPCMInfo ( rpcTempCU, 0, true ); m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[uiDepth][CI_TEMP_BEST]); rpcTempCU->getTotalBits() = m_pcEntropyCoder->getNumberOfWrittenBits(); rpcTempCU->getTotalBins() = ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded(); rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() ); xCheckDQP( rpcTempCU ); DEBUG_STRING_NEW(a) DEBUG_STRING_NEW(b) xCheckBestMode(rpcBestCU, rpcTempCU, uiDepth DEBUG_STRING_PASS_INTO(a) DEBUG_STRING_PASS_INTO(b)); } /** check whether current try is the best with identifying the depth of current try * \param rpcBestCU * \param rpcTempCU * \returns Void */ Void TEncCu::xCheckBestMode( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, UInt uiDepth DEBUG_STRING_FN_DECLARE(sParent) DEBUG_STRING_FN_DECLARE(sTest) DEBUG_STRING_PASS_INTO(Bool bAddSizeInfo) ) { if( rpcTempCU->getTotalCost() < rpcBestCU->getTotalCost() ) { TComYuv* pcYuv; // Change Information data TComDataCU* pcCU = rpcBestCU; rpcBestCU = rpcTempCU; rpcTempCU = pcCU; // Change Prediction data pcYuv = m_ppcPredYuvBest[uiDepth]; m_ppcPredYuvBest[uiDepth] = m_ppcPredYuvTemp[uiDepth]; m_ppcPredYuvTemp[uiDepth] = pcYuv; // Change Reconstruction data pcYuv = m_ppcRecoYuvBest[uiDepth]; m_ppcRecoYuvBest[uiDepth] = m_ppcRecoYuvTemp[uiDepth]; m_ppcRecoYuvTemp[uiDepth] = pcYuv; pcYuv = NULL; pcCU = NULL; // store temp best CI for next CU coding m_pppcRDSbacCoder[uiDepth][CI_TEMP_BEST]->store(m_pppcRDSbacCoder[uiDepth][CI_NEXT_BEST]); #ifdef DEBUG_STRING DEBUG_STRING_SWAP(sParent, sTest) const PredMode predMode=rpcBestCU->getPredictionMode(0); if ((DebugOptionList::DebugString_Structure.getInt()&DebugStringGetPredModeMask(predMode)) && bAddSizeInfo) { std::stringstream ss(stringstream::out); ss <<"###: " << (predMode==MODE_INTRA?"Intra ":"Inter ") << partSizeToString[rpcBestCU->getPartitionSize(0)] << " CU at " << rpcBestCU->getCUPelX() << ", " << rpcBestCU->getCUPelY() << " width=" << UInt(rpcBestCU->getWidth(0)) << std::endl; sParent+=ss.str(); } #endif } } Void TEncCu::xCheckDQP( TComDataCU* pcCU ) { UInt uiDepth = pcCU->getDepth( 0 ); if( pcCU->getSlice()->getPPS()->getUseDQP() && (g_uiMaxCUWidth>>uiDepth) >= pcCU->getSlice()->getPPS()->getMinCuDQPSize() ) { if ( pcCU->getQtRootCbf( 0) ) { #if !RDO_WITHOUT_DQP_BITS m_pcEntropyCoder->resetBits(); m_pcEntropyCoder->encodeQP( pcCU, 0, false ); pcCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // dQP bits pcCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded(); pcCU->getTotalCost() = m_pcRdCost->calcRdCost( pcCU->getTotalBits(), pcCU->getTotalDistortion() ); #endif } else { pcCU->setQPSubParts( pcCU->getRefQP( 0 ), 0, uiDepth ); // set QP to default QP } } } Void TEncCu::xCopyAMVPInfo (AMVPInfo* pSrc, AMVPInfo* pDst) { pDst->iN = pSrc->iN; for (Int i = 0; i < pSrc->iN; i++) { pDst->m_acMvCand[i] = pSrc->m_acMvCand[i]; } } Void TEncCu::xCopyYuv2Pic(TComPic* rpcPic, UInt uiCUAddr, UInt uiAbsPartIdx, UInt uiDepth, UInt uiSrcDepth, TComDataCU* pcCU, UInt uiLPelX, UInt uiTPelY ) { UInt uiAbsPartIdxInRaster = g_auiZscanToRaster[uiAbsPartIdx]; UInt uiSrcBlkWidth = rpcPic->getNumPartInCtuWidth() >> (uiSrcDepth); UInt uiBlkWidth = rpcPic->getNumPartInCtuWidth() >> (uiDepth); UInt uiPartIdxX = ( ( uiAbsPartIdxInRaster % rpcPic->getNumPartInCtuWidth() ) % uiSrcBlkWidth) / uiBlkWidth; UInt uiPartIdxY = ( ( uiAbsPartIdxInRaster / rpcPic->getNumPartInCtuWidth() ) % uiSrcBlkWidth) / uiBlkWidth; UInt uiPartIdx = uiPartIdxY * ( uiSrcBlkWidth / uiBlkWidth ) + uiPartIdxX; m_ppcRecoYuvBest[uiSrcDepth]->copyToPicYuv( rpcPic->getPicYuvRec (), uiCUAddr, uiAbsPartIdx, uiDepth - uiSrcDepth, uiPartIdx); m_ppcPredYuvBest[uiSrcDepth]->copyToPicYuv( rpcPic->getPicYuvPred (), uiCUAddr, uiAbsPartIdx, uiDepth - uiSrcDepth, uiPartIdx); } Void TEncCu::xCopyYuv2Tmp( UInt uiPartUnitIdx, UInt uiNextDepth ) { UInt uiCurrDepth = uiNextDepth - 1; m_ppcRecoYuvBest[uiNextDepth]->copyToPartYuv( m_ppcRecoYuvTemp[uiCurrDepth], uiPartUnitIdx ); m_ppcPredYuvBest[uiNextDepth]->copyToPartYuv( m_ppcPredYuvBest[uiCurrDepth], uiPartUnitIdx); } /** Function for filling the PCM buffer of a CU using its original sample array * \param pcCU pointer to current CU * \param pcOrgYuv pointer to original sample array * \returns Void */ Void TEncCu::xFillPCMBuffer ( TComDataCU* pCU, TComYuv* pOrgYuv ) { const ChromaFormat format = pCU->getPic()->getChromaFormat(); const UInt numberValidComponents = getNumberValidComponents(format); for (UInt componentIndex = 0; componentIndex < numberValidComponents; componentIndex++) { const ComponentID component = ComponentID(componentIndex); const UInt width = pCU->getWidth(0) >> getComponentScaleX(component, format); const UInt height = pCU->getHeight(0) >> getComponentScaleY(component, format); Pel *source = pOrgYuv->getAddr(component, 0, width); Pel *destination = pCU->getPCMSample(component); const UInt sourceStride = pOrgYuv->getStride(component); for (Int line = 0; line < height; line++) { for (Int column = 0; column < width; column++) { destination[column] = source[column]; } source += sourceStride; destination += width; } } } #if ADAPTIVE_QP_SELECTION /** Collect ARL statistics from one block */ Int TEncCu::xTuCollectARLStats(TCoeff* rpcCoeff, TCoeff* rpcArlCoeff, Int NumCoeffInCU, Double* cSum, UInt* numSamples ) { for( Int n = 0; n < NumCoeffInCU; n++ ) { TCoeff u = abs( rpcCoeff[ n ] ); TCoeff absc = rpcArlCoeff[ n ]; if( u != 0 ) { if( u < LEVEL_RANGE ) { cSum[ u ] += ( Double )absc; numSamples[ u ]++; } else { cSum[ LEVEL_RANGE ] += ( Double )absc - ( Double )( u << ARL_C_PRECISION ); numSamples[ LEVEL_RANGE ]++; } } } return 0; } /** Collect ARL statistics from one CTU * \param pcCU */ Void TEncCu::xCtuCollectARLStats(TComDataCU* pCtu ) { Double cSum[ LEVEL_RANGE + 1 ]; //: the sum of DCT coefficients corresponding to datatype and quantization output UInt numSamples[ LEVEL_RANGE + 1 ]; //: the number of coefficients corresponding to datatype and quantization output TCoeff* pCoeffY = pCtu->getCoeff(COMPONENT_Y); TCoeff* pArlCoeffY = pCtu->getArlCoeff(COMPONENT_Y); UInt uiMinCUWidth = g_uiMaxCUWidth >> g_uiMaxCUDepth; UInt uiMinNumCoeffInCU = 1 << uiMinCUWidth; memset( cSum, 0, sizeof( Double )*(LEVEL_RANGE+1) ); memset( numSamples, 0, sizeof( UInt )*(LEVEL_RANGE+1) ); // Collect stats to cSum[][] and numSamples[][] for(Int i = 0; i < pCtu->getTotalNumPart(); i ++ ) { UInt uiTrIdx = pCtu->getTransformIdx(i); if(pCtu->isInter(i) && pCtu->getCbf( i, COMPONENT_Y, uiTrIdx ) ) { xTuCollectARLStats(pCoeffY, pArlCoeffY, uiMinNumCoeffInCU, cSum, numSamples); }//Note that only InterY is processed. QP rounding is based on InterY data only. pCoeffY += uiMinNumCoeffInCU; pArlCoeffY += uiMinNumCoeffInCU; } for(Int u=1; ugetSliceSumC()[u] += cSum[ u ] ; m_pcTrQuant->getSliceNSamples()[u] += numSamples[ u ] ; } m_pcTrQuant->getSliceSumC()[LEVEL_RANGE] += cSum[ LEVEL_RANGE ] ; m_pcTrQuant->getSliceNSamples()[LEVEL_RANGE] += numSamples[ LEVEL_RANGE ] ; } #endif //! \}