首页 > 代码库 > HEVC熵解码代码分析—类结构(1)

HEVC熵解码代码分析—类结构(1)

最近开始做HEVC了,其中熵解码作为最底层的部分,因为和h264差不多,难度系数不是很大,主要是一些查表的操作

具体的实现原理就不细说了,主要从代码来进行解释

首先分析HM工程当中的熵解码的部分作为引导,因为最终要在DSP上进行运行,之后会重写为C代码,流程性更强


代码分析

首先介绍熵解码中比较重要的几个结构体和设计到的函数

一进入main函数,最主要的就是对应的解码类TAppDecTop

int main(int argc, char* argv[])
{
  TAppDecTop  cTAppDecTop;

TAppDecTop类中主要是create和destroy相关的成员函数,真正重要的解码类还在TDecTop当中,打开TDecTop类,会看到一些比较重要的模块的类

  TComPrediction          m_cPrediction;
  TComTrQuant             m_cTrQuant;
  TDecGop                 m_cGopDecoder;
  TDecSlice               m_cSliceDecoder;
  TDecCu                  m_cCuDecoder;
  TDecEntropy             m_cEntropyDecoder;
  TDecCavlc               m_cCavlcDecoder;
  TDecSbac                m_cSbacDecoder;
  TDecBinCABAC            m_cBinCABAC;
  SEIReader               m_seiReader;
  TComLoopFilter          m_cLoopFilter;
  TComSampleAdaptiveOffset m_cSAO;

很明显有几个和熵解码有关系:

TDecEntropy             m_cEntropyDecoder;看一下成员函数

  Void init (TComPrediction* p) {m_pcPrediction = p;}
  Void decodePUWise       ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, TComDataCU* pcSubCU );
  Void decodeInterDirPU   ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, UInt uiPartIdx );
  Void decodeRefFrmIdxPU  ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, UInt uiPartIdx, RefPicList eRefList );
  Void decodeMvdPU        ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, UInt uiPartIdx, RefPicList eRefList );
  Void decodeMVPIdxPU     ( TComDataCU* pcSubCU, UInt uiPartAddr, UInt uiDepth, UInt uiPartIdx, RefPicList eRefList );

  Void    setEntropyDecoder           ( TDecEntropyIf* p );
  Void    setBitstream                ( TComInputBitstream* p ) { m_pcEntropyDecoderIf->setBitstream(p);                    }
  Void    resetEntropy                ( TComSlice* p)           { m_pcEntropyDecoderIf->resetEntropy(p);                    }

  Void    decodeVPS                   ( TComVPS* pcVPS ) { m_pcEntropyDecoderIf->parseVPS(pcVPS); }
  Void    decodeSPS                   ( TComSPS* pcSPS ) { m_pcEntropyDecoderIf->parseSPS(pcSPS); }
  Void    decodePPS                   ( TComPPS* pcPPS ) { m_pcEntropyDecoderIf->parsePPS(pcPPS); }
可以看出来,就是一些解码模块对应的功能函数

但是这里有一个比较需要注意的地方就是这个函数里面对应的解码,不仅会用到熵解码的相关方法,还会有CAVLC的解码方法,那么怎么区分呢

这里一个C++相关的知识就有了,C++类的多态的实现

TDecEntropyIf*  m_pcEntropyDecoderIf;

class TDecEntropyIf
{
public:
  //  Virtual list for SBAC/CAVLC
  virtual Void  resetEntropy          ( TComSlice* pcSlice )     = 0;
  virtual Void  setBitstream          ( TComInputBitstream* p )  = 0;

  virtual Void  parseVPS                  ( TComVPS* pcVPS )     = 0;
  virtual Void  parseSPS                  ( TComSPS* pcSPS )     = 0;
  virtual Void  parsePPS                  ( TComPPS* pcPPS )     = 0;

  virtual Void parseSliceHeader          ( TComSlice* pcSlice, ParameterSetManagerDecoder *parameterSetManager)       = 0;

  virtual Void parseTerminatingBit       ( UInt& ruilsLast )                                     = 0;
  virtual Void parseRemainingBytes( Bool noTrailingBytesExpected ) = 0;

  virtual Void parseMVPIdx        ( Int& riMVPIdx ) = 0;

public:
  virtual Void parseSkipFlag      ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) = 0;
  virtual Void parseCUTransquantBypassFlag( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) = 0;
  virtual Void parseSplitFlag     ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) = 0;
  virtual Void parsePLTModeFlag          ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) = 0;
  virtual Void parsePLTModeSyntax        ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, UInt uiNumComp) = 0;
  virtual Void parsePLTSharingModeFlag   ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) = 0;
  virtual Void parseScanRotationModeFlag ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) = 0;
  virtual Void parseMergeFlag     ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, UInt uiPUIdx ) = 0;
  virtual Void parseMergeIndex    ( TComDataCU* pcCU, UInt& ruiMergeIndex ) = 0;
  virtual Void parsePartSize      ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) = 0;
  virtual Void parsePartSizeIntraBC( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) = 0;
  virtual Void parsePredMode      ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) = 0;

  virtual Void parseIntraDirLumaAng( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) = 0;

  virtual Void parseIntraDirChroma( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) = 0;

  virtual Void parseIntraBCFlag   ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth ) = 0;
  virtual Void parseIntraBC       ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth ) = 0;
  virtual Void parseIntraBCBvd    ( TComDataCU* pcCU, UInt uiAbsPartAddr, UInt uiPartIdx, UInt uiDepth, RefPicList eRefList ) = 0;
  virtual Void parseInterDir      ( TComDataCU* pcCU, UInt& ruiInterDir, UInt uiAbsPartIdx ) = 0;
  virtual Void parseRefFrmIdx     ( TComDataCU* pcCU, Int& riRefFrmIdx, RefPicList eRefList ) = 0;
  virtual Void parseMvd           ( TComDataCU* pcCU, UInt uiAbsPartAddr, UInt uiPartIdx, UInt uiDepth, RefPicList eRefList ) = 0;

  virtual Void parseCrossComponentPrediction ( class TComTU &rTu, ComponentID compID ) = 0;

  virtual Void parseTransformSubdivFlag( UInt& ruiSubdivFlag, UInt uiLog2TransformBlockSize ) = 0;
  virtual Void parseQtCbf         ( TComTU &rTu, const ComponentID compID, const Bool lowestLevel ) = 0;
  virtual Void parseColourTransformFlag( UInt uiAbsPartIdx, Bool& uiFlag ) = 0;

  virtual Void parseQtRootCbf     ( UInt uiAbsPartIdx, UInt& uiQtRootCbf ) = 0;

  virtual Void parseDeltaQP       ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) = 0;
  virtual Void parseChromaQpAdjustment( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth ) = 0;

  virtual Void parseIPCMInfo     ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth) = 0;

  virtual Void parseCoeffNxN( class TComTU &rTu, ComponentID compID  ) = 0;

  virtual Void parseTransformSkipFlags ( class TComTU &rTu, ComponentID component ) = 0;

  virtual Void parseExplicitRdpcmMode ( TComTU &rTu, ComponentID compID ) = 0;

  virtual ~TDecEntropyIf() {}
};

这个类里面都是虚成员函数,是通过具体传入这个类的继承类的情况选择相应的解码方法。

Void    setEntropyDecoder           ( TDecEntropyIf* p );

比如

class TDecSbac : public TDecEntropyIf

class TDecCavlc : public SyntaxElementParser, public TDecEntropyIf

这样上层的类就基本上差不多了

和熵解码最相关的两个类:

  TDecSbac                m_cSbacDecoder;
  TDecBinCABAC            m_cBinCABAC;

其中TDecSbac                m_cSbacDecoder 是包含了一个slice当中解模块的所有功能函数,其中包括

  Void load                       ( const TDecSbac* pSrc );
  Void loadContexts               ( const TDecSbac* pSrc );
  Void xCopyFrom                  ( const TDecSbac* pSrc );
  Void xCopyContextsFrom          ( const TDecSbac* pSrc );

  Void  resetEntropy (TComSlice* pSlice );
  Void  setBitstream              ( TComInputBitstream* p  ) { m_pcBitstream = p; m_pcTDecBinIf->init( p ); }
  Void  parseVPS                  ( TComVPS* /*pcVPS*/ ) {}
  Void  parseSPS                  ( TComSPS* /*pcSPS*/ ) {}
  Void  parsePPS                  ( TComPPS* /*pcPPS*/ ) {}

  Void  parseSliceHeader          ( TComSlice* /*pcSlice*/, ParameterSetManagerDecoder* /*parameterSetManager*/) {}
  Void  parseTerminatingBit       ( UInt& ruiBit );
  Void  parseRemainingBytes       ( Bool noTrailingBytesExpected);
  Void  parseMVPIdx               ( Int& riMVPIdx          );
  Void  parseSaoMaxUvlc           ( UInt& val, UInt maxSymbol );
  Void  parseSaoMerge             ( UInt&  ruiVal   );
  Void  parseSaoTypeIdx           ( UInt&  ruiVal  );
  Void  parseSaoUflc              ( UInt uiLength, UInt& ruiVal     );
  Void parseSAOBlkParam           (SAOBlkParam& saoBlkParam, Bool* sliceEnabled, Bool leftMergeAvail, Bool aboveMergeAvail);
  Void parseSaoSign               (UInt& val);

码流的获取,底层熵解码一个bit,根据bit数据反二值化等操作,最终解出语法元素相应的值


TDecBinCABAC类就是熵解码中最底层,从码流中解码出相应的1个bit数据的函数

也就是最底层的算术解码

  Void  decodeBin         ( UInt& ruiBin, ContextModel& rcCtxModel );
  Void  decodeBinEP       ( UInt& ruiBin                           );
  Void  decodeBinsEP      ( UInt& ruiBin, Int numBins              );
  Void  decodeAlignedBinsEP( UInt& ruiBins, Int numBins             );
#endif

  Void  align             ();

  Void  decodeBinTrm      ( UInt& ruiBin                           );

  Void  xReadPCMCode      ( UInt uiLength, UInt& ruiCode );

  Void  copyState         ( const TDecBinIf* pcTDecBinIf );
  TDecBinCABAC* getTDecBinCABAC()             { return this; }
  const TDecBinCABAC* getTDecBinCABAC() const { return this; }

private:
  TComInputBitstream* m_pcTComBitstream;
  UInt                m_uiRange;
  UInt                m_uiValue;
  Int                 m_bitsNeeded;
};

总结一下:

在HM中和熵解码有关的类结构基本上罗列出来就是:

TAppDecTop

       TDecTop

                TDecEntropy

                TDecSbac

                TDecBinCABAC


HEVC熵解码代码分析—类结构(1)