Newer
Older

Karsten Suehring
committed
/* 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

Karsten Suehring
committed
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
* 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 <typeinfo>
#include <vector>
//////////////////////////////////////////////////////////////////////////
// Encoder modes to try out
//////////////////////////////////////////////////////////////////////////
enum EncTestModeType
{

Karsten Suehring
committed
ETM_MERGE_SKIP,
ETM_INTER_ME,
ETM_AFFINE,
ETM_MERGE_TRIANGLE,

Karsten Suehring
committed
ETM_INTRA,
ETM_IPCM,
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

Karsten Suehring
committed
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)
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 ), lossless( false ) {}

Karsten Suehring
committed
EncTestMode( EncTestModeType _type )
: type( _type ), opts( ETO_STANDARD ), qp( -1 ), lossless( false ) {}

Karsten Suehring
committed
EncTestMode( EncTestModeType _type, int _qp, bool _lossless )
: type( _type ), opts( ETO_STANDARD ), qp( _qp ), lossless( _lossless ) {}
EncTestMode( EncTestModeType _type, EncTestModeOpts _opts, int _qp, bool _lossless )
: type( _type ), opts( _opts ), qp( _qp ), lossless( _lossless ) {}

Karsten Suehring
committed
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
EncTestModeType type;
EncTestModeOpts opts;
int qp;
bool lossless;
};
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
|| encTestmode.type == ETM_AFFINE
|| encTestmode.type == ETM_MERGE_TRIANGLE

Karsten Suehring
committed
);
}
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);

Karsten Suehring
committed
}
//////////////////////////////////////////////////////////////////////////
// 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 )

Karsten Suehring
committed
, bestCS ( nullptr )
, bestCU ( nullptr )
, bestTU ( nullptr )
, extraFeatures ( )
, extraFeaturesd( )
, bestInterCost ( MAX_DOUBLE )
, interHad (std::numeric_limits<Distortion>::max())
#if ENABLE_SPLIT_PARALLELISM
, isLevelSplitParallel
( false )
#endif
, bestCostWithoutSplitFlags( MAX_DOUBLE )

Karsten Suehring
committed
{
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 );
}
unsigned minDepth;
unsigned maxDepth;
unsigned cuX, cuY, cuW, cuH, partIdx;
std::vector<EncTestMode> testModes;
EncTestMode lastTestMode;
bool earlySkip;

Karsten Suehring
committed
CodingStructure *bestCS;
CodingUnit *bestCU;
TransformUnit *bestTU;
static_vector<int64_t, 30> extraFeatures;
static_vector<double, 30> extraFeaturesd;
double bestInterCost;
Distortion interHad;
#if ENABLE_SPLIT_PARALLELISM
bool isLevelSplitParallel;
#endif
double bestCostWithoutSplitFlags;

Karsten Suehring
committed
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
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; }
};
//////////////////////////////////////////////////////////////////////////
// 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
bool m_fastDeltaQP;
static_vector<ComprCUCtx, ( MAX_CU_DEPTH << 2 )> m_ComprCUCtxList;
#if ENABLE_SPLIT_PARALLELISM
int m_runNextInParallel;
#endif
public:
virtual ~EncModeCtrl () {}

Karsten Suehring
committed
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
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;
#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; }

Karsten Suehring
committed
virtual void setBest ( CodingStructure& cs );
bool anyMode () const;
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 getBestCostWithoutSplitFlags () const { return m_ComprCUCtxList.back().bestCostWithoutSplitFlags; }
void setBestCostWithoutSplitFlags ( double cost ) { m_ComprCUCtxList.back().bestCostWithoutSplitFlags = cost; }

Karsten Suehring
committed
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 );

Karsten Suehring
committed
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

Karsten Suehring
committed
static const int MAX_STORED_CU_INFO_REFS = 4;
struct CodedCUInfo
{
bool isInter;
bool isIntra;
bool isSkip;
bool isMMVDSkip;

Karsten Suehring
committed
bool validMv[NUM_REF_PIC_LIST_01][MAX_STORED_CU_INFO_REFS];
Mv saveMv [NUM_REF_PIC_LIST_01][MAX_STORED_CU_INFO_REFS];

Karsten Suehring
committed
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
#if ENABLE_SPLIT_PARALLELISM
uint64_t
temporalId;
#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
CodedCUInfo& getBlkInfo( const UnitArea& area );
public:
virtual ~CacheBlkInfoCtrl() {}
bool isSkip ( const UnitArea& area );
bool isMMVDSkip(const UnitArea& area);

Karsten Suehring
committed
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 setGbiIdx( const UnitArea& area, uint8_t gBiIdx );
uint8_t getGbiIdx( const UnitArea& area );

Karsten Suehring
committed
};
#if REUSE_CU_RESULTS
struct BestEncodingInfo
{
CodingUnit cu;
PredictionUnit pu;
#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS
TransformUnit tus[MAX_NUM_TUS];
size_t numTus;
#else

Karsten Suehring
committed
TransformUnit tu;

Karsten Suehring
committed
EncTestMode testMode;
int poc;
#if ENABLE_SPLIT_PARALLELISM
int64_t temporalId;
#endif

Karsten Suehring
committed
};
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;
Pel *m_pPcmBuf;
CodingStructure m_dummyCS;
XUCache m_dummyCache;
#if ENABLE_SPLIT_PARALLELISM
int64_t m_currTemporalId;
#endif

Karsten Suehring
committed
protected:
void create ( const ChromaFormat chFmt );
void destroy ();
bool setFromCs( const CodingStructure& cs, const Partitioner& partitioner );
bool isValid ( const CodingStructure &cs, const Partitioner &partitioner, int qp );

Karsten Suehring
committed
#if ENABLE_SPLIT_PARALLELISM
void touch ( const UnitArea& area );
#endif

Karsten Suehring
committed
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 );

Karsten Suehring
committed
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
//////////////////////////////////////////////////////////////////////////
class EncModeCtrlMTnoRQT : public EncModeCtrl, public CacheBlkInfoCtrl
#if REUSE_CU_RESULTS
, public BestEncInfoCache
#endif
, public SaveLoadEncInfoSbt

Karsten Suehring
committed
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
{
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,
QT_BEFORE_BT,
IS_BEST_NOSPLIT_SKIP,
MAX_QT_SUB_DEPTH,
#if REUSE_CU_RESULTS
IS_REUSING_CU,
#endif
NUM_EXTRA_FEATURES
};
unsigned m_skipThreshold;
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
};
//! \}
#endif // __ENCMODECTRL__