/* 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-2023, 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 EncModeCtrl.h \brief Encoder controller for trying out specific modes */ #ifndef __ENCMODECTRL__ #define __ENCMODECTRL__ // Include files #include "EncCfg.h" #include "CommonLib/CommonDef.h" #include "CommonLib/CodingStructure.h" #include "InterSearch.h" #include <typeinfo> #include <vector> ////////////////////////////////////////////////////////////////////////// // Encoder modes to try out ////////////////////////////////////////////////////////////////////////// enum EncTestModeType { ETM_HASH_INTER, ETM_MERGE_SKIP, ETM_INTER_ME, #if !MERGE_ENC_OPT ETM_AFFINE, #endif #if AFFINE_MMVD && !MERGE_ENC_OPT ETM_AF_MMVD, #endif #if TM_MRG && !MERGE_ENC_OPT ETM_MERGE_TM, #endif ETM_MERGE_GEO, ETM_INTRA, ETM_PALETTE, ETM_SPLIT_QT, ETM_SPLIT_BT_H, ETM_SPLIT_BT_V, ETM_SPLIT_TT_H, ETM_SPLIT_TT_V, ETM_POST_DONT_SPLIT, // dummy mode to collect the data from the unsplit coding #if REUSE_CU_RESULTS ETM_RECO_CACHED, #endif ETM_TRIGGER_IMV_LIST, ETM_IBC, // ibc mode ETM_IBC_MERGE, // ibc merge mode #if MULTI_HYP_PRED ETM_INTER_MULTIHYP, #endif ETM_INVALID }; enum EncTestModeOpts { ETO_STANDARD = 0, // empty (standard option) ETO_FORCE_MERGE = 1<<0, // bit 0 (indicates forced merge) ETO_IMV_SHIFT = 1, // bits 1-3 (imv parameter starts at bit 1) ETO_IMV = 7<<ETO_IMV_SHIFT, // bits 1-3 (imv parameter uses 3 bits) #if INTER_LIC ETO_LIC = 1 << 4, // bit 4 (local illumination compensation) #endif ETO_DUMMY = 1<<5, // bit 5 (dummy) ETO_INVALID = 0xffffffff // bits 0-31 (invalid option) }; static void getAreaIdx(const Area& area, const PreCalcValues &pcv, unsigned &idx1, unsigned &idx2, unsigned &idx3, unsigned &idx4) { idx1 = (area.x & pcv.maxCUWidthMask) >> MIN_CU_LOG2; idx2 = (area.y & pcv.maxCUHeightMask) >> MIN_CU_LOG2; idx3 = gp_sizeIdxInfo->idxFrom( area.width ); idx4 = gp_sizeIdxInfo->idxFrom( area.height ); } struct EncTestMode { EncTestMode() : type( ETM_INVALID ), opts( ETO_INVALID ), qp( -1 ) {} EncTestMode( EncTestModeType _type ) : type( _type ), opts( ETO_STANDARD ), qp( -1 ) {} EncTestMode( EncTestModeType _type, int _qp ) : type( _type ), opts( ETO_STANDARD ), qp( _qp ) {} EncTestMode( EncTestModeType _type, EncTestModeOpts _opts, int _qp ) : type( _type ), opts( _opts ), qp( _qp ) {} EncTestModeType type; EncTestModeOpts opts; int qp; double maxCostAllowed; }; inline bool isModeSplit( const EncTestMode& encTestmode ) { switch( encTestmode.type ) { case ETM_SPLIT_QT : case ETM_SPLIT_BT_H : case ETM_SPLIT_BT_V : case ETM_SPLIT_TT_H : case ETM_SPLIT_TT_V : return true; default: return false; } } inline bool isModeNoSplit( const EncTestMode& encTestmode ) { return !isModeSplit( encTestmode ) && encTestmode.type != ETM_POST_DONT_SPLIT; } inline bool isModeInter( const EncTestMode& encTestmode ) // perhaps remove { return ( encTestmode.type == ETM_INTER_ME || encTestmode.type == ETM_MERGE_SKIP #if !MERGE_ENC_OPT || encTestmode.type == ETM_AFFINE #endif #if AFFINE_MMVD && !MERGE_ENC_OPT || encTestmode.type == ETM_AF_MMVD #endif #if TM_MRG && !MERGE_ENC_OPT || encTestmode.type == ETM_MERGE_TM #endif || encTestmode.type == ETM_MERGE_GEO || encTestmode.type == ETM_HASH_INTER #if MULTI_HYP_PRED || encTestmode.type == ETM_INTER_MULTIHYP #endif ); } inline PartSplit getPartSplit( const EncTestMode& encTestmode ) { switch( encTestmode.type ) { case ETM_SPLIT_QT : return CU_QUAD_SPLIT; case ETM_SPLIT_BT_H : return CU_HORZ_SPLIT; case ETM_SPLIT_BT_V : return CU_VERT_SPLIT; case ETM_SPLIT_TT_H : return CU_TRIH_SPLIT; case ETM_SPLIT_TT_V : return CU_TRIV_SPLIT; default: return CU_DONT_SPLIT; } } inline EncTestMode getCSEncMode( const CodingStructure& cs ) { return EncTestMode( EncTestModeType( (unsigned)cs.features[ENC_FT_ENC_MODE_TYPE] ), EncTestModeOpts( (unsigned)cs.features[ENC_FT_ENC_MODE_OPTS] ), false); } ////////////////////////////////////////////////////////////////////////// // EncModeCtrl controls if specific modes should be tested ////////////////////////////////////////////////////////////////////////// struct ComprCUCtx { ComprCUCtx() : testModes(), extraFeatures() { } ComprCUCtx( const CodingStructure& cs, const uint32_t _minDepth, const uint32_t _maxDepth, const uint32_t numExtraFeatures ) : minDepth ( _minDepth ) , maxDepth ( _maxDepth ) , testModes ( ) , lastTestMode ( ) , earlySkip ( false ) , isHashPerfectMatch ( false ) , bestCS ( nullptr ) , bestCU ( nullptr ) , bestTU ( nullptr ) , extraFeatures ( ) , extraFeaturesd( ) , bestInterCost ( MAX_DOUBLE ) , bestMtsSize2Nx2N1stPass ( MAX_DOUBLE ) , skipSecondMTSPass ( false ) , interHad (std::numeric_limits<Distortion>::max()) #if ENABLE_SPLIT_PARALLELISM , isLevelSplitParallel ( false ) #endif , bestCostWithoutSplitFlags( MAX_DOUBLE ) , bestCostMtsFirstPassNoIsp( MAX_DOUBLE ) , bestCostIsp ( MAX_DOUBLE ) , ispWasTested ( false ) , bestPredModeDCT2 ( UINT8_MAX ) , relatedCuIsValid ( false ) , ispPredModeVal( 0 ) , bestDCT2NonISPCost ( MAX_DOUBLE ) , bestNonDCT2Cost ( MAX_DOUBLE ) , bestISPIntraMode ( UINT8_MAX ) #if JVET_V0130_INTRA_TMP , tmpFlag (false) #endif , mipFlag ( false ) , ispMode ( NOT_INTRA_SUBPARTITIONS ) , ispLfnstIdx ( 0 ) , stopNonDCT2Transforms ( false ) { getAreaIdx( cs.area.Y(), *cs.pcv, cuX, cuY, cuW, cuH ); partIdx = ( ( cuX << 8 ) | cuY ); extraFeatures.reserve( numExtraFeatures ); extraFeatures.resize ( numExtraFeatures, 0 ); extraFeaturesd.reserve( numExtraFeatures ); extraFeaturesd.resize ( numExtraFeatures, 0.0 ); #if INTRA_TRANS_ENC_OPT bestLfnstCost[0] = bestLfnstCost[1] = MAX_DOUBLE; #endif } unsigned minDepth; unsigned maxDepth; unsigned cuX, cuY, cuW, cuH, partIdx; std::vector<EncTestMode> testModes; EncTestMode lastTestMode; bool earlySkip; bool isHashPerfectMatch; CodingStructure *bestCS; CodingUnit *bestCU; TransformUnit *bestTU; static_vector<int64_t, 30> extraFeatures; static_vector<double, 30> extraFeaturesd; double bestInterCost; double bestMtsSize2Nx2N1stPass; bool skipSecondMTSPass; Distortion interHad; #if ENABLE_SPLIT_PARALLELISM bool isLevelSplitParallel; #endif double bestCostWithoutSplitFlags; double bestCostMtsFirstPassNoIsp; double bestCostIsp; #if INTRA_TRANS_ENC_OPT double bestLfnstCost[2]; #endif bool ispWasTested; uint16_t bestPredModeDCT2; bool relatedCuIsValid; uint16_t ispPredModeVal; double bestDCT2NonISPCost; double bestNonDCT2Cost; uint8_t bestISPIntraMode; #if JVET_V0130_INTRA_TMP bool tmpFlag; #endif bool mipFlag; uint8_t ispMode; uint8_t ispLfnstIdx; bool stopNonDCT2Transforms; template<typename T> T get( int ft ) const { return typeid(T) == typeid(double) ? (T&)extraFeaturesd[ft] : T(extraFeatures[ft]); } template<typename T> void set( int ft, T val ) { extraFeatures [ft] = int64_t( val ); } void set( int ft, double val ) { extraFeaturesd[ft] = val; } #if INTRA_TRANS_ENC_OPT bool isLfnstTested() const { return (bestLfnstCost[0] != MAX_DOUBLE && bestLfnstCost[1] != MAX_DOUBLE); } #endif }; ////////////////////////////////////////////////////////////////////////// // EncModeCtrl - abstract class specifying the general flow of mode control ////////////////////////////////////////////////////////////////////////// class EncModeCtrl { protected: const EncCfg *m_pcEncCfg; const class RateCtrl *m_pcRateCtrl; class RdCost *m_pcRdCost; const Slice *m_slice; #if SHARP_LUMA_DELTA_QP int m_lumaLevelToDeltaQPLUT[LUMA_LEVEL_TO_DQP_LUT_MAXSIZE]; int m_lumaQPOffset; #endif #if JVET_Y0240_BIM std::map<int, int*> *m_bimQPMap; #endif bool m_fastDeltaQP; static_vector<ComprCUCtx, ( MAX_CU_DEPTH << 2 )> m_ComprCUCtxList; #if ENABLE_SPLIT_PARALLELISM int m_runNextInParallel; #endif InterSearch* m_pcInterSearch; bool m_doPlt; #if JVET_AE0057_MTT_ET double m_noSplitIntraRdCost; #endif public: virtual ~EncModeCtrl () {} virtual void create ( const EncCfg& cfg ) = 0; virtual void destroy () = 0; virtual void initCTUEncoding ( const Slice &slice ) = 0; virtual void initCULevel ( Partitioner &partitioner, const CodingStructure& cs ) = 0; virtual void finishCULevel ( Partitioner &partitioner ) = 0; protected: virtual bool tryMode ( const EncTestMode& encTestmode, const CodingStructure &cs, Partitioner& partitioner ) = 0; public: virtual bool useModeResult ( const EncTestMode& encTestmode, CodingStructure*& tempCS, Partitioner& partitioner ) = 0; virtual bool checkSkipOtherLfnst ( const EncTestMode& encTestmode, CodingStructure*& tempCS, Partitioner& partitioner ) = 0; #if ENABLE_SPLIT_PARALLELISM virtual void copyState ( const EncModeCtrl& other, const UnitArea& area ); virtual int getNumParallelJobs ( const CodingStructure &cs, Partitioner& partitioner ) const { return 1; } virtual bool isParallelSplit ( const CodingStructure &cs, Partitioner& partitioner ) const { return false; } virtual bool parallelJobSelector ( const EncTestMode& encTestmode, const CodingStructure &cs, Partitioner& partitioner ) const { return true; } void setParallelSplit ( bool val ) { m_runNextInParallel = val; } #endif void init ( EncCfg *pCfg, RateCtrl *pRateCtrl, RdCost *pRdCost ); bool tryModeMaster ( const EncTestMode& encTestmode, const CodingStructure &cs, Partitioner& partitioner ); bool nextMode ( const CodingStructure &cs, Partitioner &partitioner ); EncTestMode currTestMode () const; EncTestMode lastTestMode () const; void setEarlySkipDetected (); void setIsHashPerfectMatch( bool b ) { m_ComprCUCtxList.back().isHashPerfectMatch = b; } bool getIsHashPerfectMatch() { return m_ComprCUCtxList.back().isHashPerfectMatch; } virtual void setBest ( CodingStructure& cs ); bool anyMode () const; #if JVET_AE0057_MTT_ET void setNoSplitIntraCost (double cost) { m_noSplitIntraRdCost = cost; } #endif const ComprCUCtx& getComprCUCtx () { CHECK( m_ComprCUCtxList.empty(), "Accessing empty list!"); return m_ComprCUCtxList.back(); } #if SHARP_LUMA_DELTA_QP void initLumaDeltaQpLUT(); int calculateLumaDQP ( const CPelBuf& rcOrg ); #endif void setFastDeltaQp ( bool b ) { m_fastDeltaQP = b; } bool getFastDeltaQp () const { return m_fastDeltaQP; } double getBestInterCost () const { return m_ComprCUCtxList.back().bestInterCost; } Distortion getInterHad () const { return m_ComprCUCtxList.back().interHad; } void enforceInterHad ( Distortion had ) { m_ComprCUCtxList.back().interHad = had; } double getMtsSize2Nx2NFirstPassCost () const { return m_ComprCUCtxList.back().bestMtsSize2Nx2N1stPass; } bool getSkipSecondMTSPass () const { return m_ComprCUCtxList.back().skipSecondMTSPass; } void setSkipSecondMTSPass ( bool b ) { m_ComprCUCtxList.back().skipSecondMTSPass = b; } double getBestCostWithoutSplitFlags () const { return m_ComprCUCtxList.back().bestCostWithoutSplitFlags; } void setBestCostWithoutSplitFlags ( double cost ) { m_ComprCUCtxList.back().bestCostWithoutSplitFlags = cost; } double getMtsFirstPassNoIspCost () const { return m_ComprCUCtxList.back().bestCostMtsFirstPassNoIsp; } void setMtsFirstPassNoIspCost ( double cost ) { m_ComprCUCtxList.back().bestCostMtsFirstPassNoIsp = cost; } double getIspCost () const { return m_ComprCUCtxList.back().bestCostIsp; } void setIspCost ( double val ) { m_ComprCUCtxList.back().bestCostIsp = val; } #if INTRA_TRANS_ENC_OPT void resetLfnstCost () { m_ComprCUCtxList.back().bestLfnstCost[0] = m_ComprCUCtxList.back().bestLfnstCost[1] = MAX_DOUBLE; } #endif bool getISPWasTested () const { return m_ComprCUCtxList.back().ispWasTested; } void setISPWasTested ( bool val ) { m_ComprCUCtxList.back().ispWasTested = val; } void setBestPredModeDCT2 ( uint16_t val ) { m_ComprCUCtxList.back().bestPredModeDCT2 = val; } uint16_t getBestPredModeDCT2 () const { return m_ComprCUCtxList.back().bestPredModeDCT2; } bool getRelatedCuIsValid () const { return m_ComprCUCtxList.back().relatedCuIsValid; } void setRelatedCuIsValid ( bool val ) { m_ComprCUCtxList.back().relatedCuIsValid = val; } uint16_t getIspPredModeValRelCU () const { return m_ComprCUCtxList.back().ispPredModeVal; } void setIspPredModeValRelCU ( uint16_t val ) { m_ComprCUCtxList.back().ispPredModeVal = val; } double getBestDCT2NonISPCostRelCU () const { return m_ComprCUCtxList.back().bestDCT2NonISPCost; } void setBestDCT2NonISPCostRelCU ( double val ) { m_ComprCUCtxList.back().bestDCT2NonISPCost = val; } double getBestNonDCT2Cost () const { return m_ComprCUCtxList.back().bestNonDCT2Cost; } void setBestNonDCT2Cost ( double val ) { m_ComprCUCtxList.back().bestNonDCT2Cost = val; } uint8_t getBestISPIntraModeRelCU () const { return m_ComprCUCtxList.back().bestISPIntraMode; } void setBestISPIntraModeRelCU ( uint8_t val ) { m_ComprCUCtxList.back().bestISPIntraMode = val; } #if JVET_V0130_INTRA_TMP void setTPMFlagISPPass (bool val) { m_ComprCUCtxList.back().tmpFlag = val; } #endif void setMIPFlagISPPass ( bool val ) { m_ComprCUCtxList.back().mipFlag = val; } void setISPMode ( uint8_t val ) { m_ComprCUCtxList.back().ispMode = val; } void setISPLfnstIdx ( uint8_t val ) { m_ComprCUCtxList.back().ispLfnstIdx = val; } bool getStopNonDCT2Transforms () const { return m_ComprCUCtxList.back().stopNonDCT2Transforms; } void setStopNonDCT2Transforms ( bool val ) { m_ComprCUCtxList.back().stopNonDCT2Transforms = val; } void setInterSearch (InterSearch* pcInterSearch) { m_pcInterSearch = pcInterSearch; } void setPltEnc ( bool b ) { m_doPlt = b; } bool getPltEnc() const { return m_doPlt; } #if JVET_Y0240_BIM void setBIMQPMap ( std::map<int, int*> *qpMap ) { m_bimQPMap = qpMap; } int getBIMOffset ( int poc, int ctuId ) { auto it = m_bimQPMap->find(poc); return (it == m_bimQPMap->end()) ? 0 : (*m_bimQPMap)[poc][ctuId]; } #endif #if JVET_Z0118_GDR void forceIntraMode() { // remove all inter or split to force make intra int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (isModeInter(etm.type)) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } void forceIntraNoSplit() { // remove all inter or split to force make intra int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (isModeInter(etm.type) || isModeSplit(etm.type)) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } // Note: ForceInterMode void forceInterMode() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_INTRA) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } void removeHashInter() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_HASH_INTER) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } void removeMergeSkip() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_MERGE_SKIP) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } void removeInterME() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_INTER_ME) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } #if !MERGE_ENC_OPT void removeAffine() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_AFFINE) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } #endif void removeMergeGeo() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_MERGE_GEO) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } void removeIntra() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_INTRA) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } void removeBadMode() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_INTER_ME && ((etm.opts & ETO_IMV) >> ETO_IMV_SHIFT) > 2) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; break; } } } bool anyPredModeLeft() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_HASH_INTER || etm.type == ETM_MERGE_SKIP || etm.type == ETM_INTER_ME || #if !MERGE_ENC_OPT etm.type == ETM_AFFINE || #endif etm.type == ETM_MERGE_GEO || etm.type == ETM_INTRA || etm.type == ETM_PALETTE || etm.type == ETM_IBC || etm.type == ETM_IBC_MERGE) { return true; } } return false; } bool anyIntraIBCMode() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_INTRA || etm.type == ETM_IBC) { return true; } } return false; } void forceRemovePredMode() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if ( etm.type == ETM_HASH_INTER || etm.type == ETM_MERGE_SKIP || etm.type == ETM_INTER_ME #if !MERGE_ENC_OPT || etm.type == ETM_AFFINE #endif #if AFFINE_MMVD && !MERGE_ENC_OPT || etm.type == ETM_AF_MMVD #endif #if TM_MRG && !MERGE_ENC_OPT || etm.type == ETM_MERGE_TM #endif || etm.type == ETM_MERGE_GEO || etm.type == ETM_INTRA || etm.type == ETM_PALETTE || etm.type == ETM_IBC || etm.type == ETM_IBC_MERGE #if MULTI_HYP_PRED || etm.type == ETM_INTER_MULTIHYP #endif ) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } void forceRemoveDontSplit() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_POST_DONT_SPLIT) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } void forceVerSplitOnly() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_SPLIT_BT_H || etm.type == ETM_SPLIT_TT_H) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } void forceRemoveTTH() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_SPLIT_TT_H) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } void forceRemoveTTV() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_SPLIT_TT_V) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } void forceRemoveBTH() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_SPLIT_BT_H) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } void forceRemoveBTV() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_SPLIT_BT_V) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } void forceRemoveQT() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_SPLIT_QT) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } void forceRemoveHT() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_SPLIT_BT_H || etm.type == ETM_SPLIT_TT_H) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } void forceRemoveQTHT() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_SPLIT_QT || etm.type == ETM_SPLIT_BT_H || etm.type == ETM_SPLIT_TT_H) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } void forceRemoveAllSplit() { int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type == ETM_SPLIT_QT || etm.type == ETM_SPLIT_BT_H || etm.type == ETM_SPLIT_BT_V || etm.type == ETM_SPLIT_TT_H || etm.type == ETM_SPLIT_TT_V) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } void forceQTonlyMode() { // remove all split except QT int n = (int)m_ComprCUCtxList.back().testModes.size(); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; if (etm.type != ETM_SPLIT_QT) { m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); j--; n--; } } } const char* printType(EncTestModeType type) { char *ret; switch (type) { case ETM_HASH_INTER: ret = strdup("Hash"); break; case ETM_MERGE_SKIP: ret = strdup("Mkip"); break; case ETM_INTER_ME: ret = strdup("InterMe"); break; #if !MERGE_ENC_OPT case ETM_AFFINE: ret = strdup("Affi"); break; #endif #if AFFINE_MMVD && !MERGE_ENC_OPT case ETM_AF_MMVD: ret = strdup("AfMMVD"); break; #endif #if TM_MRG && !MERGE_ENC_OPT case ETM_MERGE_TM: ret = strdup("MergeTM"); break; #endif case ETM_MERGE_GEO: ret = strdup("MergeGeo"); break; case ETM_INTRA: ret = strdup("Intra"); break; case ETM_PALETTE: ret = strdup("Palet"); break; case ETM_SPLIT_QT: ret = strdup("QT"); break; case ETM_SPLIT_BT_H: ret = strdup("BTH"); break; case ETM_SPLIT_BT_V: ret = strdup("BTV"); break; case ETM_SPLIT_TT_H: ret = strdup("TTH"); break; case ETM_SPLIT_TT_V: ret = strdup("TTV"); break; case ETM_POST_DONT_SPLIT: ret = strdup("|"); break; #if REUSE_CU_RESULTS case ETM_RECO_CACHED: ret = strdup("CACHE"); break; #endif case ETM_TRIGGER_IMV_LIST: ret = strdup("TrigIMVList"); break; case ETM_IBC: ret = strdup("IBC"); break; case ETM_IBC_MERGE: ret = strdup("IBCMerge"); break; #if MULTI_HYP_PRED case ETM_INTER_MULTIHYP: ret = strdup("MulHyp"); break; #endif default: ret = strdup("INVALID"); } return ret; } void printMode() { // remove all inter or split to force make intra int n = (int)m_ComprCUCtxList.back().testModes.size(); printf("-:["); for (int j = 0; j < n; j++) { const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; printf(" %s", printType(etm.type)); } printf("]\n"); } #endif protected: void xExtractFeatures ( const EncTestMode encTestmode, CodingStructure& cs ); void xGetMinMaxQP ( int& iMinQP, int& iMaxQP, const CodingStructure& cs, const Partitioner &pm, const int baseQP, const SPS& sps, const PPS& pps, const PartSplit splitMode ); int xComputeDQP ( const CodingStructure &cs, const Partitioner &pm ); }; ////////////////////////////////////////////////////////////////////////// // some utility interfaces that expose some functionality that can be used without concerning about which particular controller is used ////////////////////////////////////////////////////////////////////////// struct SaveLoadStructSbt { uint8_t numPuInfoStored; uint32_t puSse[SBT_NUM_SL]; uint8_t puSbt[SBT_NUM_SL]; uint8_t puTrs[SBT_NUM_SL]; }; class SaveLoadEncInfoSbt { protected: #if ENABLE_SPLIT_PARALLELISM public: #endif void init( const Slice &slice ); #if ENABLE_SPLIT_PARALLELISM protected: #endif void create(); void destroy(); private: SaveLoadStructSbt ****m_saveLoadSbt; Slice const *m_sliceSbt; public: virtual ~SaveLoadEncInfoSbt() { } void resetSaveloadSbt( int maxSbtSize ); uint16_t findBestSbt( const UnitArea& area, const uint32_t curPuSse ); bool saveBestSbt( const UnitArea& area, const uint32_t curPuSse, const uint8_t curPuSbt, const uint8_t curPuTrs ); #if ENABLE_SPLIT_PARALLELISM void copyState(const SaveLoadEncInfoSbt& other); #endif }; static const int MAX_STORED_CU_INFO_REFS = 4; struct CodedCUInfo { bool isInter; bool isIntra; bool isSkip; bool isMMVDSkip; bool isIBC; #if JVET_W0097_GPM_MMVD_TM bool skipGPM; char isGPMTested; int geoDirCandList[GEO_MAX_TRY_WEIGHTED_SATD]; int numGeoDirCand; int geoMrgIdx0List[GEO_MAX_TRY_WEIGHTED_SATD]; int geoMrgIdx1List[GEO_MAX_TRY_WEIGHTED_SATD]; #endif #if JVET_AD0213_LIC_IMP bool skipLIC; #endif #if JVET_AA0070_RRIBC bool isRribcCoded; bool isRribcTested; #endif bool validMv[NUM_REF_PIC_LIST_01][MAX_STORED_CU_INFO_REFS]; Mv saveMv [NUM_REF_PIC_LIST_01][MAX_STORED_CU_INFO_REFS]; #if MULTI_HYP_PRED uint8_t numAddHyp; #endif uint8_t bcwIdx; char selectColorSpaceOption; // 0 - test both two color spaces; 1 - only test the first color spaces; 2 - only test the second color spaces uint16_t ispPredModeVal; double bestDCT2NonISPCost; double bestCost; double bestNonDCT2Cost; bool relatedCuIsValid; uint8_t bestISPIntraMode; #if INTRA_TRANS_ENC_OPT double bestCostForLfnst; bool relatedCuLfnstIsValid; bool skipLfnstTest; #endif #if ENABLE_SPLIT_PARALLELISM uint64_t temporalId; #endif #if JVET_AB0092_GLM_WITH_LUMA bool skipGLM; #endif }; class CacheBlkInfoCtrl { private: unsigned m_numWidths, m_numHeights; Slice const *m_slice_chblk; // x in CTU, y in CTU, width, height CodedCUInfo ***m_codedCUInfo[MAX_CU_SIZE >> MIN_CU_LOG2][MAX_CU_SIZE >> MIN_CU_LOG2]; protected: void create (); void destroy (); #if ENABLE_SPLIT_PARALLELISM public: #endif void init ( const Slice &slice ); #if ENABLE_SPLIT_PARALLELISM private: uint64_t m_currTemporalId; public: void tick () { m_currTemporalId++; CHECK( m_currTemporalId <= 0, "Problem with integer overflow!" ); } // mark the state of the blk as changed within the current temporal id void copyState( const CacheBlkInfoCtrl &other, const UnitArea& area ); protected: void touch ( const UnitArea& area ); #endif #if JVET_W0097_GPM_MMVD_TM || INTRA_TRANS_ENC_OPT public: #endif CodedCUInfo& getBlkInfo( const UnitArea& area ); public: virtual ~CacheBlkInfoCtrl() {} bool isSkip ( const UnitArea& area ); bool isMMVDSkip(const UnitArea& area); bool getMv ( const UnitArea& area, const RefPicList refPicList, const int iRefIdx, Mv& rMv ) const; void setMv ( const UnitArea& area, const RefPicList refPicList, const int iRefIdx, const Mv& rMv ); bool getInter( const UnitArea& area ); void setBcwIdx( const UnitArea& area, uint8_t gBiIdx ); uint8_t getBcwIdx( const UnitArea& area ); char getSelectColorSpaceOption(const UnitArea& area); }; #if REUSE_CU_RESULTS struct BestEncodingInfo { CodingUnit cu; PredictionUnit pu; #if CONVERT_NUM_TU_SPLITS_TO_CFG std::vector<TransformUnit> tus; size_t numTus; #elif REUSE_CU_RESULTS_WITH_MULTIPLE_TUS TransformUnit tus[MAX_NUM_TUS]; size_t numTus; #else TransformUnit tu; #endif EncTestMode testMode; int poc; #if ENABLE_SPLIT_PARALLELISM int64_t temporalId; #endif }; class BestEncInfoCache { private: unsigned m_numWidths, m_numHeights; const Slice *m_slice_bencinf; BestEncodingInfo ***m_bestEncInfo[MAX_CU_SIZE >> MIN_CU_LOG2][MAX_CU_SIZE >> MIN_CU_LOG2]; TCoeff *m_pCoeff; #if SIGN_PREDICTION TCoeff *m_pCoeffSign; #if JVET_Y0141_SIGN_PRED_IMPROVE unsigned *m_pCoeffSignScanIdx; #endif #endif Pel *m_pPcmBuf; bool *m_runType; CodingStructure m_dummyCS; XUCache m_dummyCache; #if ENABLE_SPLIT_PARALLELISM int64_t m_currTemporalId; #endif #if CONVERT_NUM_TU_SPLITS_TO_CFG int m_maxNumTUs; #endif protected: #if CONVERT_NUM_TU_SPLITS_TO_CFG void create ( const ChromaFormat chFmt, const int maxNumTUs ); #else void create ( const ChromaFormat chFmt ); #endif void destroy (); bool setFromCs( const CodingStructure& cs, const Partitioner& partitioner ); bool isValid ( const CodingStructure &cs, const Partitioner &partitioner, int qp ); #if ENABLE_SPLIT_PARALLELISM void touch ( const UnitArea& area ); #endif public: BestEncInfoCache() : m_slice_bencinf( nullptr ), m_dummyCS( m_dummyCache.cuCache, m_dummyCache.puCache, m_dummyCache.tuCache ) {} virtual ~BestEncInfoCache() {} #if ENABLE_SPLIT_PARALLELISM void copyState( const BestEncInfoCache &other, const UnitArea &area ); void tick () { m_currTemporalId++; CHECK( m_currTemporalId <= 0, "Problem with integer overflow!" ); } #endif void init ( const Slice &slice ); bool setCsFrom( CodingStructure& cs, EncTestMode& testMode, const Partitioner& partitioner ) const; }; #endif ////////////////////////////////////////////////////////////////////////// // EncModeCtrlMTnoRQT - allows and controls modes introduced by QTBT (inkl. multi-type-tree) // - only 2Nx2N, no RQT, additional binary/triary CU splits ////////////////////////////////////////////////////////////////////////// #if JVET_W0097_GPM_MMVD_TM enum ExtraFeatures { DID_HORZ_SPLIT = 0, DID_VERT_SPLIT, DID_QUAD_SPLIT, BEST_HORZ_SPLIT_COST, BEST_VERT_SPLIT_COST, BEST_TRIH_SPLIT_COST, BEST_TRIV_SPLIT_COST, DO_TRIH_SPLIT, DO_TRIV_SPLIT, BEST_NON_SPLIT_COST, BEST_NO_IMV_COST, BEST_IMV_COST, BEST_GPM_COST, #if JVET_AD0213_LIC_IMP BEST_LIC_COST, #endif QT_BEFORE_BT, IS_BEST_NOSPLIT_SKIP, MAX_QT_SUB_DEPTH, #if REUSE_CU_RESULTS IS_REUSING_CU, #endif #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS BEST_INTRA_NZ_CNT, #endif NUM_EXTRA_FEATURES }; #endif class EncModeCtrlMTnoRQT : public EncModeCtrl, public CacheBlkInfoCtrl #if REUSE_CU_RESULTS , public BestEncInfoCache #endif , public SaveLoadEncInfoSbt { #if !JVET_W0097_GPM_MMVD_TM enum ExtraFeatures { DID_HORZ_SPLIT = 0, DID_VERT_SPLIT, DID_QUAD_SPLIT, BEST_HORZ_SPLIT_COST, BEST_VERT_SPLIT_COST, BEST_TRIH_SPLIT_COST, BEST_TRIV_SPLIT_COST, DO_TRIH_SPLIT, DO_TRIV_SPLIT, BEST_NON_SPLIT_COST, BEST_NO_IMV_COST, BEST_IMV_COST, #if JVET_AD0213_LIC_IMP BEST_LIC_COST, #endif QT_BEFORE_BT, IS_BEST_NOSPLIT_SKIP, MAX_QT_SUB_DEPTH, #if REUSE_CU_RESULTS IS_REUSING_CU, #endif NUM_EXTRA_FEATURES }; #endif unsigned m_skipThreshold; #if JVET_Z0118_GDR EncCfg m_encCfg; #endif public: virtual void create ( const EncCfg& cfg ); virtual void destroy (); virtual void initCTUEncoding ( const Slice &slice ); virtual void initCULevel ( Partitioner &partitioner, const CodingStructure& cs ); virtual void finishCULevel ( Partitioner &partitioner ); virtual bool tryMode ( const EncTestMode& encTestmode, const CodingStructure &cs, Partitioner& partitioner ); virtual bool useModeResult ( const EncTestMode& encTestmode, CodingStructure*& tempCS, Partitioner& partitioner ); #if ENABLE_SPLIT_PARALLELISM virtual void copyState ( const EncModeCtrl& other, const UnitArea& area ); virtual int getNumParallelJobs ( const CodingStructure &cs, Partitioner& partitioner ) const; virtual bool isParallelSplit ( const CodingStructure &cs, Partitioner& partitioner ) const; virtual bool parallelJobSelector( const EncTestMode& encTestmode, const CodingStructure &cs, Partitioner& partitioner ) const; #endif virtual bool checkSkipOtherLfnst( const EncTestMode& encTestmode, CodingStructure*& tempCS, Partitioner& partitioner ); #if JVET_Y0152_TT_ENC_SPEEDUP bool xSkipTreeCandidate(const PartSplit split, const double* splitRdCostBest, const SliceType& sliceType) const; #endif }; //! \} #endif // __ENCMODECTRL__