forked from mirror/libbpg
1649 lines
60 KiB
C++
1649 lines
60 KiB
C++
/* 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 <stdio.h>
|
|
#include "TEncTop.h"
|
|
#include "TEncCu.h"
|
|
#include "TEncAnalyze.h"
|
|
#include "TLibCommon/Debug.h"
|
|
|
|
#include <cmath>
|
|
#include <algorithm>
|
|
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<m_uhTotalDepth-1 ; i++)
|
|
{
|
|
uiNumPartitions = 1<<( ( m_uhTotalDepth - i - 1 )<<1 );
|
|
UInt uiWidth = uiMaxWidth >> 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 ; i<m_uhTotalDepth-1 ; i++)
|
|
{
|
|
if(m_ppcBestCU[i])
|
|
{
|
|
m_ppcBestCU[i]->destroy(); 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<<pcPic->getSlice(0)->getSPS()->getPCMLog2MaxSize())
|
|
&& rpcTempCU->getWidth(0) >= (1<<pcPic->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<TEncPic*>( 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; u<LEVEL_RANGE;u++)
|
|
{
|
|
m_pcTrQuant->getSliceSumC()[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
|
|
//! \}
|