Skip to content
Snippets Groups Projects
EncCu.cpp 140 KiB
Newer Older
  • Learn to ignore specific revisions
  • /* 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-2019, 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     EncCu.cpp
        \brief    Coding Unit (CU) encoder class
    */
    
    #include "EncCu.h"
    
    #include "EncLib.h"
    #include "Analyze.h"
    #include "AQp.h"
    
    #include "CommonLib/dtrace_codingstruct.h"
    #include "CommonLib/Picture.h"
    #include "CommonLib/UnitTools.h"
    
    
    #include "CommonLib/dtrace_buffer.h"
    
    #include <stdio.h>
    #include <cmath>
    #include <algorithm>
    #if ENABLE_WPP_PARALLELISM
    #include <mutex>
    extern std::recursive_mutex g_cache_mutex;
    #endif
    
    
    
    //! \ingroup EncoderLib
    //! \{
    
    // ====================================================================================================================
    // Constructor / destructor / create / destroy
    // ====================================================================================================================
    
    #if JVET_M0883_TRIANGLE_SIGNALING
    const TriangleMotionInfo  EncCu::m_triangleModeTest[TRIANGLE_MAX_NUM_CANDS] = 
    {
      TriangleMotionInfo( 0, 1, 0 ), TriangleMotionInfo( 1, 0, 1 ), TriangleMotionInfo( 1, 0, 2 ), TriangleMotionInfo( 0, 0, 1 ), TriangleMotionInfo( 0, 2, 0 ),
      TriangleMotionInfo( 1, 0, 3 ), TriangleMotionInfo( 1, 0, 4 ), TriangleMotionInfo( 1, 1, 0 ), TriangleMotionInfo( 0, 3, 0 ), TriangleMotionInfo( 0, 4, 0 ),
      TriangleMotionInfo( 0, 0, 2 ), TriangleMotionInfo( 0, 1, 2 ), TriangleMotionInfo( 1, 1, 2 ), TriangleMotionInfo( 0, 0, 4 ), TriangleMotionInfo( 0, 0, 3 ),
      TriangleMotionInfo( 0, 1, 3 ), TriangleMotionInfo( 0, 1, 4 ), TriangleMotionInfo( 1, 1, 4 ), TriangleMotionInfo( 1, 1, 3 ), TriangleMotionInfo( 1, 2, 1 ),
      TriangleMotionInfo( 1, 2, 0 ), TriangleMotionInfo( 0, 2, 1 ), TriangleMotionInfo( 0, 4, 3 ), TriangleMotionInfo( 1, 3, 0 ), TriangleMotionInfo( 1, 3, 2 ),
      TriangleMotionInfo( 1, 3, 4 ), TriangleMotionInfo( 1, 4, 0 ), TriangleMotionInfo( 1, 3, 1 ), TriangleMotionInfo( 1, 2, 3 ), TriangleMotionInfo( 1, 4, 1 ),
      TriangleMotionInfo( 0, 4, 1 ), TriangleMotionInfo( 0, 2, 3 ), TriangleMotionInfo( 1, 4, 2 ), TriangleMotionInfo( 0, 3, 2 ), TriangleMotionInfo( 1, 4, 3 ),
      TriangleMotionInfo( 0, 3, 1 ), TriangleMotionInfo( 0, 2, 4 ), TriangleMotionInfo( 1, 2, 4 ), TriangleMotionInfo( 0, 4, 2 ), TriangleMotionInfo( 0, 3, 4 ),
    };
    #endif
    
    
    void EncCu::create( EncCfg* encCfg )
    {
      unsigned      uiMaxWidth    = encCfg->getMaxCUWidth();
      unsigned      uiMaxHeight   = encCfg->getMaxCUHeight();
      ChromaFormat  chromaFormat  = encCfg->getChromaFormatIdc();
    
      unsigned      numWidths     = gp_sizeIdxInfo->numWidths();
      unsigned      numHeights    = gp_sizeIdxInfo->numHeights();
      m_pTempCS = new CodingStructure**  [numWidths];
      m_pBestCS = new CodingStructure**  [numWidths];
    
    
    Li's avatar
    Li committed
      m_pTempMotLUTs = new LutMotionCand**[numWidths];
      m_pBestMotLUTs = new LutMotionCand**[numWidths];
      m_pSplitTempMotLUTs = new LutMotionCand**[numWidths];
    
      for( unsigned w = 0; w < numWidths; w++ )
      {
        m_pTempCS[w] = new CodingStructure*  [numHeights];
        m_pBestCS[w] = new CodingStructure*  [numHeights];
    
    Li's avatar
    Li committed
        m_pTempMotLUTs[w] = new LutMotionCand*[numHeights];
        m_pBestMotLUTs[w] = new LutMotionCand*[numHeights];
        m_pSplitTempMotLUTs[w] = new LutMotionCand*[numHeights];
    
    
        for( unsigned h = 0; h < numHeights; h++ )
        {
          unsigned width  = gp_sizeIdxInfo->sizeFrom( w );
          unsigned height = gp_sizeIdxInfo->sizeFrom( h );
    
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          if( gp_sizeIdxInfo->isCuSize( width ) && gp_sizeIdxInfo->isCuSize( height ) )
    
          {
            m_pTempCS[w][h] = new CodingStructure( m_unitCache.cuCache, m_unitCache.puCache, m_unitCache.tuCache );
            m_pBestCS[w][h] = new CodingStructure( m_unitCache.cuCache, m_unitCache.puCache, m_unitCache.tuCache );
    
            m_pTempCS[w][h]->create( chromaFormat, Area( 0, 0, width, height ), false );
            m_pBestCS[w][h]->create( chromaFormat, Area( 0, 0, width, height ), false );
    
    Li's avatar
    Li committed
            m_pTempMotLUTs[w][h] = new LutMotionCand ;
            m_pBestMotLUTs[w][h] = new LutMotionCand ;
            m_pSplitTempMotLUTs[w][h] = new LutMotionCand;
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC
    
    Yu Han's avatar
    Yu Han committed
            m_pSplitTempMotLUTs[w][h]->currCnt = 0;
            m_pSplitTempMotLUTs[w][h]->currCntIBC = 0;
            m_pSplitTempMotLUTs[w][h]->motionCand = nullptr;
            m_pSplitTempMotLUTs[w][h]->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS * 2];
    
            m_pTempMotLUTs[w][h]->currCnt = 0;
            m_pTempMotLUTs[w][h]->currCntIBC = 0;
            m_pTempMotLUTs[w][h]->motionCand = nullptr;
            m_pTempMotLUTs[w][h]->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS * 2];
    
            m_pBestMotLUTs[w][h]->currCnt = 0;
            m_pBestMotLUTs[w][h]->currCntIBC = 0;
            m_pBestMotLUTs[w][h]->motionCand = nullptr;
            m_pBestMotLUTs[w][h]->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS * 2];
    #else
    
            m_pSplitTempMotLUTs[w][h]->currCnt = 0;
            m_pSplitTempMotLUTs[w][h]->motionCand = nullptr;
            m_pSplitTempMotLUTs[w][h]->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS];
    
            m_pTempMotLUTs[w][h]->currCnt = 0;
            m_pTempMotLUTs[w][h]->motionCand = nullptr;
            m_pTempMotLUTs[w][h]->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS];
    
            m_pBestMotLUTs[w][h]->currCnt = 0;
            m_pBestMotLUTs[w][h]->motionCand = nullptr;
            m_pBestMotLUTs[w][h]->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS];
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
          }
          else
          {
            m_pTempCS[w][h] = nullptr;
            m_pBestCS[w][h] = nullptr;
    
            m_pTempMotLUTs[w][h] = nullptr;
            m_pBestMotLUTs[w][h] = nullptr;
            m_pSplitTempMotLUTs[w][h] = nullptr;
    
          }
        }
      }
    
      // WIA: only the weight==height case is relevant without QTBT
      m_pImvTempCS = nullptr;
    
      m_cuChromaQpOffsetIdxPlus1 = 0;
    
      unsigned maxDepth = numWidths + numHeights;
    
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      m_modeCtrl = new EncModeCtrlMTnoRQT();
    
      for (unsigned ui = 0; ui < MMVD_MRG_MAX_RD_BUF_NUM; ui++)
    
      {
        m_acMergeBuffer[ui].create( chromaFormat, Area( 0, 0, uiMaxWidth, uiMaxHeight ) );
      }
    
      for (unsigned ui = 0; ui < MRG_MAX_NUM_CANDS; ui++)
      {
        m_acRealMergeBuffer[ui].create(chromaFormat, Area(0, 0, uiMaxWidth, uiMaxHeight));
      }
    
    #if JVET_M0883_TRIANGLE_SIGNALING
      for( unsigned ui = 0; ui < TRIANGLE_MAX_NUM_UNI_CANDS; ui++ )
      {
        for( unsigned uj = 0; uj < TRIANGLE_MAX_NUM_UNI_CANDS; uj++ )
        {
          if(ui == uj)
            continue;
          uint8_t idxBits0 = ui + (ui == TRIANGLE_MAX_NUM_UNI_CANDS - 1 ? 0 : 1);
          uint8_t candIdx1Enc = uj - (uj > ui ? 1 : 0);
          uint8_t idxBits1 = candIdx1Enc + (candIdx1Enc == TRIANGLE_MAX_NUM_UNI_CANDS - 2 ? 0 : 1);
          m_triangleIdxBins[1][ui][uj] = m_triangleIdxBins[0][ui][uj] = 1 + idxBits0 + idxBits1;
        }
      }
    #endif
    
      for( unsigned ui = 0; ui < TRIANGLE_MAX_NUM_CANDS; ui++ )
      {
    
    rlliao's avatar
    rlliao committed
        m_acTriangleWeightedBuffer[ui].create( chromaFormat, Area( 0, 0, uiMaxWidth, uiMaxHeight ) );
    
    
      m_CtxBuffer.resize( maxDepth );
      m_CurrCtx = 0;
    }
    
    
    void EncCu::destroy()
    {
      unsigned numWidths  = gp_sizeIdxInfo->numWidths();
      unsigned numHeights = gp_sizeIdxInfo->numHeights();
    
      for( unsigned w = 0; w < numWidths; w++ )
      {
        for( unsigned h = 0; h < numHeights; h++ )
        {
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          if( m_pBestCS[w][h] ) m_pBestCS[w][h]->destroy();
          if( m_pTempCS[w][h] ) m_pTempCS[w][h]->destroy();
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          delete m_pBestCS[w][h];
          delete m_pTempCS[w][h];
          if (m_pTempMotLUTs[w][h])
          {
            delete[] m_pTempMotLUTs[w][h]->motionCand;
            m_pTempMotLUTs[w][h]->motionCand = nullptr;
    
    Xiang Li's avatar
    Xiang Li committed
            delete m_pTempMotLUTs[w][h];
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          }
          if (m_pBestMotLUTs[w][h])
          {
            delete[] m_pBestMotLUTs[w][h]->motionCand;
            m_pBestMotLUTs[w][h]->motionCand = nullptr;
    
    Xiang Li's avatar
    Xiang Li committed
            delete m_pBestMotLUTs[w][h];
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          }
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          if (m_pSplitTempMotLUTs[w][h])
          {
            delete[] m_pSplitTempMotLUTs[w][h]->motionCand;
            m_pSplitTempMotLUTs[w][h]->motionCand = nullptr;
    
    Xiang Li's avatar
    Xiang Li committed
            delete m_pSplitTempMotLUTs[w][h];
    
        delete[] m_pBestMotLUTs[w];
        delete[] m_pTempMotLUTs[w];
        delete[] m_pSplitTempMotLUTs[w];
    
      }
    
      delete[] m_pBestCS; m_pBestCS = nullptr;
      delete[] m_pTempCS; m_pTempCS = nullptr;
    
      delete[] m_pSplitTempMotLUTs; m_pSplitTempMotLUTs = nullptr;
      delete[] m_pBestMotLUTs; m_pBestMotLUTs = nullptr;
      delete[] m_pTempMotLUTs; m_pTempMotLUTs = nullptr;
    
    
    #if REUSE_CU_RESULTS
      m_modeCtrl->destroy();
    
    #endif
      delete m_modeCtrl;
      m_modeCtrl = nullptr;
    
      // WIA: only the weight==height case is relevant without QTBT
      if( m_pImvTempCS )
      {
        for( unsigned w = 0; w < numWidths; w++ )
        {
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          if( m_pImvTempCS[w] )
    
    Karsten Suehring's avatar
    Karsten Suehring committed
            m_pImvTempCS[w]->destroy();
            delete[] m_pImvTempCS[w];
    
      for (unsigned ui = 0; ui < MMVD_MRG_MAX_RD_BUF_NUM; ui++)
    
      for (unsigned ui = 0; ui < MRG_MAX_NUM_CANDS; ui++)
      {
        m_acRealMergeBuffer[ui].destroy();
      }
    
      for( unsigned ui = 0; ui < TRIANGLE_MAX_NUM_CANDS; ui++ )
      {
    
    rlliao's avatar
    rlliao committed
        m_acTriangleWeightedBuffer[ui].destroy();
    
    }
    
    
    
    EncCu::~EncCu()
    {
    }
    
    
    
    /** \param    pcEncLib      pointer of encoder class
     */
    void EncCu::init( EncLib* pcEncLib, const SPS& sps PARL_PARAM( const int tId ) )
    {
      m_pcEncCfg           = pcEncLib;
      m_pcIntraSearch      = pcEncLib->getIntraSearch( PARL_PARAM0( tId ) );
      m_pcInterSearch      = pcEncLib->getInterSearch( PARL_PARAM0( tId ) );
      m_pcTrQuant          = pcEncLib->getTrQuant( PARL_PARAM0( tId ) );
      m_pcRdCost           = pcEncLib->getRdCost ( PARL_PARAM0( tId ) );
      m_CABACEstimator     = pcEncLib->getCABACEncoder( PARL_PARAM0( tId ) )->getCABACEstimator( &sps );
      m_CABACEstimator->setEncCu(this);
      m_CtxCache           = pcEncLib->getCtxCache( PARL_PARAM0( tId ) );
      m_pcRateCtrl         = pcEncLib->getRateCtrl();
      m_pcSliceEncoder     = pcEncLib->getSliceEncoder();
    #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM
      m_pcEncLib           = pcEncLib;
      m_dataId             = tId;
    #endif
    
    #if JVET_M0170_MRG_SHARELIST
      m_shareState = NO_SHARE;
      m_pcInterSearch->setShareState(0);
      setShareStateDec(0);
    #endif
    
    #if JVET_M0170_MRG_SHARELIST
      m_shareBndPosX = -1;
      m_shareBndPosY = -1;
      m_shareBndSizeW = 0;
      m_shareBndSizeH = 0;
    #endif
    
    
    #if REUSE_CU_RESULTS
      DecCu::init( m_pcTrQuant, m_pcIntraSearch, m_pcInterSearch );
    
    #endif
      m_modeCtrl->init( m_pcEncCfg, m_pcRateCtrl, m_pcRdCost );
    
      m_pcInterSearch->setModeCtrl( m_modeCtrl );
      ::memset(m_subMergeBlkSize, 0, sizeof(m_subMergeBlkSize));
      ::memset(m_subMergeBlkNum, 0, sizeof(m_subMergeBlkNum));
      m_prevPOC = MAX_UINT;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    
    
    #if  JVET_M0255_FRACMMVD_SWITCH
    
      if ( ( m_pcEncCfg->getIBCHashSearch() && m_pcEncCfg->getIBCMode() ) || m_pcEncCfg->getAllowDisFracMMVD() )
    
    Yu Han's avatar
    Yu Han committed
      if (m_pcEncCfg->getIBCHashSearch() && m_pcEncCfg->getIBCMode())
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      {
    
    Yu Han's avatar
    Yu Han committed
        m_ibcHashMap.init(m_pcEncCfg->getSourceWidth(), m_pcEncCfg->getSourceHeight());
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      }
    
    }
    
    // ====================================================================================================================
    // Public member functions
    // ====================================================================================================================
    
    void EncCu::compressCtu( CodingStructure& cs, const UnitArea& area, const unsigned ctuRsAddr, const int prevQP[], const int currQP[] )
    {
    
    #if !JVET_M0255_FRACMMVD_SWITCH
    
    Yu Han's avatar
    Yu Han committed
      if (m_pcEncCfg->getIBCHashSearch() && ctuRsAddr == 0 && cs.slice->getSPS()->getSpsNext().getIBCMode())
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      {
    
    Yu Han's avatar
    Yu Han committed
        m_ibcHashMap.rebuildPicHashMap(cs.picture->getOrigBuf());
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      }
    
      m_modeCtrl->initCTUEncoding( *cs.slice );
    
    #if ENABLE_SPLIT_PARALLELISM
      if( m_pcEncCfg->getNumSplitThreads() > 1 )
      {
        for( int jId = 1; jId < NUM_RESERVERD_SPLIT_JOBS; jId++ )
        {
          EncCu*            jobEncCu  = m_pcEncLib->getCuEncoder( cs.picture->scheduler.getSplitDataId( jId ) );
          CacheBlkInfoCtrl* cacheCtrl = dynamic_cast< CacheBlkInfoCtrl* >( jobEncCu->m_modeCtrl );
          if( cacheCtrl )
          {
            cacheCtrl->init( *cs.slice );
          }
        }
      }
    
      if( auto* cacheCtrl = dynamic_cast<CacheBlkInfoCtrl*>( m_modeCtrl ) ) { cacheCtrl->tick(); }
    #endif
      // init the partitioning manager
      Partitioner *partitioner = PartitionerFactory::get( *cs.slice );
      partitioner->initCtu( area, CH_L, *cs.slice );
    
    Yu Han's avatar
    Yu Han committed
      if (m_pcEncCfg->getIBCMode())
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      {
        m_pcInterSearch->resetCtuRecord();
    
    Yu Han's avatar
    Yu Han committed
        m_ctuIbcSearchRangeX = m_pcEncCfg->getIBCLocalSearchRangeX();
        m_ctuIbcSearchRangeY = m_pcEncCfg->getIBCLocalSearchRangeY();
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      }
    
    Yu Han's avatar
    Yu Han committed
      if (m_pcEncCfg->getIBCMode() && m_pcEncCfg->getIBCHashSearch() && (m_pcEncCfg->getIBCFastMethod() & IBC_FAST_METHOD_ADAPTIVE_SEARCHRANGE))
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      {
    
    Yu Han's avatar
    Yu Han committed
        const int hashHitRatio = m_ibcHashMap.getHashHitRatio(area.Y()); // in percent
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        if (hashHitRatio < 5) // 5%
        {
    
    Yu Han's avatar
    Yu Han committed
          m_ctuIbcSearchRangeX >>= 1;
          m_ctuIbcSearchRangeY >>= 1;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        }
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC
    
    Yu Han's avatar
    Yu Han committed
        if (cs.slice->getNumRefIdx(REF_PIC_LIST_0) > 0)
    #else
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        if (cs.slice->getNumRefIdx(REF_PIC_LIST_0) > 1)
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        {
    
    Yu Han's avatar
    Yu Han committed
          m_ctuIbcSearchRangeX >>= 1;
          m_ctuIbcSearchRangeY >>= 1;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        }
      }
    
      // init current context pointer
      m_CurrCtx = m_CtxBuffer.data();
    
      CodingStructure *tempCS = m_pTempCS[gp_sizeIdxInfo->idxFrom( area.lumaSize().width )][gp_sizeIdxInfo->idxFrom( area.lumaSize().height )];
      CodingStructure *bestCS = m_pBestCS[gp_sizeIdxInfo->idxFrom( area.lumaSize().width )][gp_sizeIdxInfo->idxFrom( area.lumaSize().height )];
    
    Li's avatar
    Li committed
      LutMotionCand *tempMotCandLUTs = m_pTempMotLUTs[gp_sizeIdxInfo->idxFrom(area.lumaSize().width)][gp_sizeIdxInfo->idxFrom(area.lumaSize().height)];
      LutMotionCand *bestMotCandLUTs = m_pBestMotLUTs[gp_sizeIdxInfo->idxFrom(area.lumaSize().width)][gp_sizeIdxInfo->idxFrom(area.lumaSize().height)];
    
      cs.slice->copyMotionLUTs(cs.slice->getMotionLUTs(), tempMotCandLUTs);
      cs.slice->copyMotionLUTs(cs.slice->getMotionLUTs(), bestMotCandLUTs);
    
    
      cs.initSubStructure( *tempCS, partitioner->chType, partitioner->currArea(), false );
      cs.initSubStructure( *bestCS, partitioner->chType, partitioner->currArea(), false );
      tempCS->currQP[CH_L] = bestCS->currQP[CH_L] =
      tempCS->baseQP       = bestCS->baseQP       = currQP[CH_L];
      tempCS->prevQP[CH_L] = bestCS->prevQP[CH_L] = prevQP[CH_L];
    
    
      xCompressCU( tempCS, bestCS, *partitioner
        , tempMotCandLUTs
        , bestMotCandLUTs
      );
    
    
      // all signals were already copied during compression if the CTU was split - at this point only the structures are copied to the top level CS
      const bool copyUnsplitCTUSignals = bestCS->cus.size() == 1 && KEEP_PRED_AND_RESI_SIGNALS;
      cs.useSubStructure( *bestCS, partitioner->chType, CS::getArea( *bestCS, area, partitioner->chType ), copyUnsplitCTUSignals, false, false, copyUnsplitCTUSignals );
    
      cs.slice->copyMotionLUTs(bestMotCandLUTs, cs.slice->getMotionLUTs());
    
      if( !cs.pcv->ISingleTree && cs.slice->isIRAP() && cs.pcv->chrFormat != CHROMA_400 )
    
      {
        m_CABACEstimator->getCtx() = m_CurrCtx->start;
    
        partitioner->initCtu( area, CH_C, *cs.slice );
    
        cs.initSubStructure( *tempCS, partitioner->chType, partitioner->currArea(), false );
        cs.initSubStructure( *bestCS, partitioner->chType, partitioner->currArea(), false );
        tempCS->currQP[CH_C] = bestCS->currQP[CH_C] =
        tempCS->baseQP       = bestCS->baseQP       = currQP[CH_C];
        tempCS->prevQP[CH_C] = bestCS->prevQP[CH_C] = prevQP[CH_C];
    
    
        xCompressCU( tempCS, bestCS, *partitioner
          , tempMotCandLUTs
          , bestMotCandLUTs
        );
    
    
        const bool copyUnsplitCTUSignals = bestCS->cus.size() == 1 && KEEP_PRED_AND_RESI_SIGNALS;
        cs.useSubStructure( *bestCS, partitioner->chType, CS::getArea( *bestCS, area, partitioner->chType ), copyUnsplitCTUSignals, false, false, copyUnsplitCTUSignals );
      }
    
    
      if (m_pcEncCfg->getUseRateCtrl())
      {
        (m_pcRateCtrl->getRCPic()->getLCU(ctuRsAddr)).m_actualMSE = (double)bestCS->dist / (double)m_pcRateCtrl->getRCPic()->getLCU(ctuRsAddr).m_numberOfPixel;
      }
    
      // reset context states and uninit context pointer
      m_CABACEstimator->getCtx() = m_CurrCtx->start;
      m_CurrCtx                  = 0;
      delete partitioner;
    
    #if ENABLE_SPLIT_PARALLELISM && ENABLE_WPP_PARALLELISM
      if( m_pcEncCfg->getNumSplitThreads() > 1 && m_pcEncCfg->getNumWppThreads() > 1 )
      {
        cs.picture->finishCtuPart( area );
      }
    #endif
    
      // Ensure that a coding was found
      // Selected mode's RD-cost must be not MAX_DOUBLE.
      CHECK( bestCS->cus.empty()                                   , "No possible encoding found" );
      CHECK( bestCS->cus[0]->predMode == NUMBER_OF_PREDICTION_MODES, "No possible encoding found" );
      CHECK( bestCS->cost             == MAX_DOUBLE                , "No possible encoding found" );
    }
    
    // ====================================================================================================================
    // Protected member functions
    // ====================================================================================================================
    
    static int xCalcHADs8x8_ISlice(const Pel *piOrg, const 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  EncCu::updateCtuDataISlice(const CPelBuf buf)
    {
      int  xBl, yBl;
      const int iBlkSize = 8;
      const Pel* pOrgInit = buf.buf;
      int  iStrideOrig = buf.stride;
    
      int iSumHad = 0;
      for( yBl = 0; ( yBl + iBlkSize ) <= buf.height; yBl += iBlkSize )
      {
        for( xBl = 0; ( xBl + iBlkSize ) <= buf.width; xBl += iBlkSize )
        {
          const Pel* pOrg = pOrgInit + iStrideOrig*yBl + xBl;
          iSumHad += xCalcHADs8x8_ISlice( pOrg, iStrideOrig );
        }
      }
      return( iSumHad );
    }
    
    
    bool EncCu::xCheckBestMode( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
    
      bool bestCSUpdated = false;
    
      if( !tempCS->cus.empty() )
      {
        if( tempCS->cus.size() == 1 )
        {
          const CodingUnit& cu = *tempCS->cus.front();
          CHECK( cu.skip && !cu.firstPU->mergeFlag, "Skip flag without a merge flag is not allowed!" );
        }
    
    #if WCG_EXT
        DTRACE_BEST_MODE( tempCS, bestCS, m_pcRdCost->getLambda( true ) );
    #else
        DTRACE_BEST_MODE( tempCS, bestCS, m_pcRdCost->getLambda() );
    #endif
    
        if( m_modeCtrl->useModeResult( encTestMode, tempCS, partitioner ) )
        {
          if( tempCS->cus.size() == 1 )
          {
            // if tempCS is not a split-mode
            CodingUnit &cu = *tempCS->cus.front();
    
            if( CU::isLosslessCoded( cu ) && !cu.ipcm )
            {
              xFillPCMBuffer( cu );
            }
          }
    
          std::swap( tempCS, bestCS );
          // store temp best CI for next CU coding
          m_CurrCtx->best = m_CABACEstimator->getCtx();
    
          bestCSUpdated = true;
    
        }
      }
    
      // reset context states
      m_CABACEstimator->getCtx() = m_CurrCtx->start;
    
      return bestCSUpdated;
    
    void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner
    
      , LutMotionCand *&tempMotCandLUTs
      , LutMotionCand *&bestMotCandLUTs
    
    #if JVET_M0170_MRG_SHARELIST
      if (m_shareState == NO_SHARE)
      {
        tempCS->sharedBndPos = tempCS->area.Y().lumaPos();
        tempCS->sharedBndSize.width = tempCS->area.lwidth();
        tempCS->sharedBndSize.height = tempCS->area.lheight();
        bestCS->sharedBndPos = bestCS->area.Y().lumaPos();
        bestCS->sharedBndSize.width = bestCS->area.lwidth();
        bestCS->sharedBndSize.height = bestCS->area.lheight();
      }
    #endif
    
    #if ENABLE_SPLIT_PARALLELISM
      CHECK( m_dataId != tempCS->picture->scheduler.getDataId(), "Working in the wrong dataId!" );
    
      if( m_pcEncCfg->getNumSplitThreads() != 1 && tempCS->picture->scheduler.getSplitJobId() == 0 )
      {
        if( m_modeCtrl->isParallelSplit( *tempCS, partitioner ) )
        {
          m_modeCtrl->setParallelSplit( true );
          xCompressCUParallel( tempCS, bestCS, partitioner );
          return;
        }
      }
    
    #endif
    
      Slice&   slice      = *tempCS->slice;
      const PPS &pps      = *tempCS->pps;
      const SPS &sps      = *tempCS->sps;
      const uint32_t uiLPelX  = tempCS->area.Y().lumaPos().x;
      const uint32_t uiTPelY  = tempCS->area.Y().lumaPos().y;
    
      const unsigned wIdx = gp_sizeIdxInfo->idxFrom( partitioner.currArea().lwidth()  );
    
      const UnitArea currCsArea = clipArea( CS::getArea( *bestCS, bestCS->area, partitioner.chType ), *tempCS->picture );
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC 
    
    Yu Han's avatar
    Yu Han committed
      if (m_pImvTempCS && (!slice.isIntra() || slice.getSPS()->getSpsNext().getIBCMode()))
    #else
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        tempCS->initSubStructure( *m_pImvTempCS[wIdx], partitioner.chType, partitioner.currArea(), false );
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      tempCS->chType = partitioner.chType;
      bestCS->chType = partitioner.chType;
    
      m_modeCtrl->initCULevel( partitioner, *tempCS );
    
      m_CurrCtx->start = m_CABACEstimator->getCtx();
    
      m_cuChromaQpOffsetIdxPlus1 = 0;
    
      if( slice.getUseChromaQpAdj() )
      {
        int lgMinCuSize = sps.getLog2MinCodingBlockSize() +
          std::max<int>( 0, sps.getLog2DiffMaxMinCodingBlockSize() - int( pps.getPpsRangeExtension().getDiffCuChromaQpOffsetDepth() ) );
        m_cuChromaQpOffsetIdxPlus1 = ( ( uiLPelX >> lgMinCuSize ) + ( uiTPelY >> lgMinCuSize ) ) % ( pps.getPpsRangeExtension().getChromaQpOffsetListLen() + 1 );
      }
    
      if( !m_modeCtrl->anyMode() )
      {
        m_modeCtrl->finishCULevel( partitioner );
        return;
      }
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC
    
    Yu Han's avatar
    Yu Han committed
      if ((!slice.isIntra() || slice.getSPS()->getSpsNext().getIBCMode())
    #else
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      if (!slice.isIntra()
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        && tempCS->chType == CHANNEL_TYPE_LUMA
        )
    
    Li's avatar
    Li committed
      {
        tempCS->slice->copyMotionLUTs(tempMotCandLUTs, tempCS->slice->getMotionLUTs());
      }
    
    
      DTRACE_UPDATE( g_trace_ctx, std::make_pair( "cux", uiLPelX ) );
      DTRACE_UPDATE( g_trace_ctx, std::make_pair( "cuy", uiTPelY ) );
      DTRACE_UPDATE( g_trace_ctx, std::make_pair( "cuw", tempCS->area.lwidth() ) );
      DTRACE_UPDATE( g_trace_ctx, std::make_pair( "cuh", tempCS->area.lheight() ) );
      DTRACE( g_trace_ctx, D_COMMON, "@(%4d,%4d) [%2dx%2d]\n", tempCS->area.lx(), tempCS->area.ly(), tempCS->area.lwidth(), tempCS->area.lheight() );
    
    
    
    #if JVET_M0170_MRG_SHARELIST
      int startShareThisLevel = 0;
    #endif
    
    #if JVET_M0246_AFFINE_AMVR 
      m_pcInterSearch->resetSavedAffineMotion();
    #endif
    
        EncTestMode currTestMode = m_modeCtrl->currTestMode();
    
    
        if (tempCS->pps->getUseDQP() && CS::isDualITree(*tempCS) && isChroma(partitioner.chType))
    
        {
          const Position chromaCentral(tempCS->area.Cb().chromaPos().offset(tempCS->area.Cb().chromaSize().width >> 1, tempCS->area.Cb().chromaSize().height >> 1));
          const Position lumaRefPos(chromaCentral.x << getComponentScaleX(COMPONENT_Cb, tempCS->area.chromaFormat), chromaCentral.y << getComponentScaleY(COMPONENT_Cb, tempCS->area.chromaFormat));
          const CodingStructure* baseCS = bestCS->picture->cs;
          const CodingUnit* colLumaCu = baseCS->getCU(lumaRefPos, CHANNEL_TYPE_LUMA);
          const TransformUnit*  tu = baseCS->getTU(lumaRefPos, CHANNEL_TYPE_LUMA);
    
    
    
    #if SHARP_LUMA_DELTA_QP
        if( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() && partitioner.currDepth <= pps.getMaxCuDQPDepth() )
        {
    #if ENABLE_SPLIT_PARALLELISM
          CHECK( tempCS->picture->scheduler.getSplitJobId() > 0, "Changing lambda is only allowed in the master thread!" );
    #endif
          if (currTestMode.qp >= 0)
          {
            updateLambda(&slice, currTestMode.qp);
          }
        }
    #endif
    
        if( currTestMode.type == ETM_INTER_ME )
        {
          if( ( currTestMode.opts & ETO_IMV ) != 0 )
          {
    
    #if JVET_M0246_AFFINE_AMVR
            tempCS->bestCS = bestCS;
            xCheckRDCostInterIMV( tempCS, bestCS, partitioner, currTestMode );
            tempCS->bestCS = nullptr;
    #else
    
            xCheckRDCostInterIMV(tempCS, bestCS, partitioner, currTestMode);
    
    #if JVET_M0246_AFFINE_AMVR
            tempCS->bestCS = bestCS;
    
            xCheckRDCostInter( tempCS, bestCS, partitioner, currTestMode );
    
            tempCS->bestCS = nullptr;
    #else
            xCheckRDCostInter( tempCS, bestCS, partitioner, currTestMode );
    #endif
    
          }
    
        }
        else if( currTestMode.type == ETM_AFFINE )
        {
          xCheckRDCostAffineMerge2Nx2N( tempCS, bestCS, partitioner, currTestMode );
        }
    #if REUSE_CU_RESULTS
        else if( currTestMode.type == ETM_RECO_CACHED )
        {
          xReuseCachedResult( tempCS, bestCS, partitioner );
        }
    #endif
        else if( currTestMode.type == ETM_MERGE_SKIP )
        {
          xCheckRDCostMerge2Nx2N( tempCS, bestCS, partitioner, currTestMode );
    
          CodingUnit* cu = bestCS->getCU(partitioner.chType);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          if (cu)
    
          cu->mmvdSkip = cu->skip == false ? false : cu->mmvdSkip;
    
        else if( currTestMode.type == ETM_MERGE_TRIANGLE )
        {
          xCheckRDCostMergeTriangle2Nx2N( tempCS, bestCS, partitioner, currTestMode );
        }
    
        else if( currTestMode.type == ETM_INTRA )
        {
          xCheckRDCostIntra( tempCS, bestCS, partitioner, currTestMode );
        }
        else if( currTestMode.type == ETM_IPCM )
        {
          xCheckIntraPCM( tempCS, bestCS, partitioner, currTestMode );
        }
    
    Yu Han's avatar
    Yu Han committed
        else if (currTestMode.type == ETM_IBC)
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        {
    
    Yu Han's avatar
    Yu Han committed
          xCheckRDCostIBCMode(tempCS, bestCS, partitioner, currTestMode);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        }
    
    Yu Han's avatar
    Yu Han committed
        else if (currTestMode.type == ETM_IBC_MERGE)
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        {
    
    Yu Han's avatar
    Yu Han committed
          xCheckRDCostIBCModeMerge2Nx2N(tempCS, bestCS, partitioner, currTestMode);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        }
    
          xCheckModeSplit( tempCS, bestCS, partitioner, currTestMode
            , tempMotCandLUTs
            , bestMotCandLUTs
            , partitioner.currArea()
          );
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          THROW( "Don't know how to handle mode: type = " << currTestMode.type << ", options = " << currTestMode.opts );
    
        }
      } while( m_modeCtrl->nextMode( *tempCS, partitioner ) );
    
    
    #if JVET_M0170_MRG_SHARELIST
      if(startShareThisLevel == 1)
      {
        m_shareState = NO_SHARE;
        m_pcInterSearch->setShareState(m_shareState);
        setShareStateDec(m_shareState);
      }
    #endif
    
    
      //////////////////////////////////////////////////////////////////////////
      // Finishing CU
    #if ENABLE_SPLIT_PARALLELISM
      if( bestCS->cus.empty() )
      {
        CHECK( bestCS->cost != MAX_DOUBLE, "Cost should be maximal if no encoding found" );
        CHECK( bestCS->picture->scheduler.getSplitJobId() == 0, "Should always get a result in serial case" );
    
        m_modeCtrl->finishCULevel( partitioner );
        return;
      }
    
    #endif
      // set context states
      m_CABACEstimator->getCtx() = m_CurrCtx->best;
    
      // QP from last processed CU for further processing
      bestCS->prevQP[partitioner.chType] = bestCS->cus.back()->qp;
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC
    
    Yu Han's avatar
    Yu Han committed
      if ((!slice.isIntra() || slice.getSPS()->getSpsNext().getIBCMode())
    #else
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      if (!slice.isIntra() 
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        && bestCS->chType == CHANNEL_TYPE_LUMA
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC
    
    Yu Han's avatar
    Yu Han committed
        && bestCS->cus.size() == 1 && (bestCS->cus.back()->predMode == MODE_INTER || bestCS->cus.back()->predMode == MODE_IBC)
    #else
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        && bestCS->cus.size() == 1 && bestCS->cus.back()->predMode == MODE_INTER 
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        && bestCS->area.Y() == (*bestCS->cus.back()).Y()
        )
    
      {
        bestCS->slice->updateMotionLUTs(bestMotCandLUTs, (*bestCS->cus.back()));
      }
    
      bestCS->picture->getRecoBuf( currCsArea ).copyFrom( bestCS->getRecoBuf( currCsArea ) );
      m_modeCtrl->finishCULevel( partitioner );
    
    #if ENABLE_SPLIT_PARALLELISM
      if( tempCS->picture->scheduler.getSplitJobId() == 0 && m_pcEncCfg->getNumSplitThreads() != 1 )
      {
        tempCS->picture->finishParallelPart( currCsArea );
      }
    
    #endif
      // Assert if Best prediction mode is NONE
      // Selected mode's RD-cost must be not MAX_DOUBLE.
      CHECK( bestCS->cus.empty()                                   , "No possible encoding found" );
      CHECK( bestCS->cus[0]->predMode == NUMBER_OF_PREDICTION_MODES, "No possible encoding found" );
      CHECK( bestCS->cost             == MAX_DOUBLE                , "No possible encoding found" );
    }
    
    #if SHARP_LUMA_DELTA_QP
    void EncCu::updateLambda( Slice* slice, double dQP )
    {
    #if WCG_EXT
      int    NumberBFrames = ( m_pcEncCfg->getGOPSize() - 1 );
      int    SHIFT_QP = 12;
      double dLambda_scale = 1.0 - Clip3( 0.0, 0.5, 0.05*(double)(slice->getPic()->fieldPic ? NumberBFrames/2 : NumberBFrames) );
    
      int bitdepth_luma_qp_scale = 6
                                   * (slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA) - 8
                                      - DISTORTION_PRECISION_ADJUSTMENT(slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA)));
      double qp_temp = (double) dQP + bitdepth_luma_qp_scale - SHIFT_QP;
    
      double dQPFactor = m_pcEncCfg->getGOPEntry( m_pcSliceEncoder->getGopId() ).m_QPFactor;
    
      if( slice->getSliceType() == I_SLICE )
      {
        if( m_pcEncCfg->getIntraQpFactor() >= 0.0 /*&& m_pcEncCfg->getGOPEntry( m_pcSliceEncoder->getGopId() ).m_sliceType != I_SLICE*/ )
        {
          dQPFactor = m_pcEncCfg->getIntraQpFactor();
        }
        else
        {
          if( m_pcEncCfg->getLambdaFromQPEnable() )
          {
            dQPFactor = 0.57;
          }
          else
          {
            dQPFactor = 0.57*dLambda_scale;
          }
        }
      }
      else if( m_pcEncCfg->getLambdaFromQPEnable() )
      {
        dQPFactor = 0.57*dQPFactor;
      }
    
      double dLambda = dQPFactor*pow( 2.0, qp_temp/3.0 );
      int depth = slice->getDepth();
    
      if( !m_pcEncCfg->getLambdaFromQPEnable() && depth>0 )
      {
        int qp_temp_slice = slice->getSliceQp() + bitdepth_luma_qp_scale - SHIFT_QP; // avoid lambda  over adjustment,  use slice_qp here
        dLambda *= Clip3( 2.00, 4.00, (qp_temp_slice / 6.0) ); // (j == B_SLICE && p_cur_frm->layer != 0 )
      }
      if( !m_pcEncCfg->getUseHADME() && slice->getSliceType( ) != I_SLICE )
      {
        dLambda *= 0.95;
      }
    
      const int temporalId = m_pcEncCfg->getGOPEntry( m_pcSliceEncoder->getGopId() ).m_temporalId;
      const std::vector<double> &intraLambdaModifiers = m_pcEncCfg->getIntraLambdaModifier();
      double lambdaModifier;
      if( slice->getSliceType( ) != I_SLICE || intraLambdaModifiers.empty())
      {
        lambdaModifier = m_pcEncCfg->getLambdaModifier(temporalId);
      }
      else
      {
        lambdaModifier = intraLambdaModifiers[(temporalId < intraLambdaModifiers.size()) ? temporalId : (intraLambdaModifiers.size() - 1)];
      }
      dLambda *= lambdaModifier;
    
      int qpBDoffset = slice->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA);
    
      int iQP = Clip3(-qpBDoffset, MAX_QP, (int)floor(dQP + 0.5));
    
      m_pcSliceEncoder->setUpLambda(slice, dLambda, iQP);
    
    #else
      int iQP = (int)dQP;
      const double oldQP     = (double)slice->getSliceQpBase();
      const double oldLambda = m_pcSliceEncoder->calculateLambda (slice, m_pcSliceEncoder->getGopId(), slice->getDepth(), oldQP, oldQP, iQP);
      const double newLambda = oldLambda * pow (2.0, (dQP - oldQP) / 3.0);
    #if RDOQ_CHROMA_LAMBDA
      const double chromaLambda = newLambda / m_pcRdCost->getChromaWeight();
      const double lambdaArray[MAX_NUM_COMPONENT] = {newLambda, chromaLambda, chromaLambda};
      m_pcTrQuant->setLambdas (lambdaArray);
    #else
      m_pcTrQuant->setLambda (newLambda);
    #endif
      m_pcRdCost->setLambda( newLambda, slice->getSPS()->getBitDepths() );
    #endif
    }
    #endif
    
    #if ENABLE_SPLIT_PARALLELISM
    //#undef DEBUG_PARALLEL_TIMINGS
    //#define DEBUG_PARALLEL_TIMINGS 1
    void EncCu::xCompressCUParallel( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner )
    {
      const unsigned wIdx = gp_sizeIdxInfo->idxFrom( partitioner.currArea().lwidth() );
      const unsigned hIdx = gp_sizeIdxInfo->idxFrom( partitioner.currArea().lheight() );
    
      Picture* picture = tempCS->picture;
    
      int numJobs = m_modeCtrl->getNumParallelJobs( *bestCS, partitioner );
    
      bool    jobUsed                            [NUM_RESERVERD_SPLIT_JOBS];
      std::fill( jobUsed, jobUsed + NUM_RESERVERD_SPLIT_JOBS, false );
    
      const UnitArea currArea = CS::getArea( *tempCS, partitioner.currArea(), partitioner.chType );
    #if ENABLE_WPP_PARALLELISM
      const int      wppTId   = picture->scheduler.getWppThreadId();