標籤:hevc 熵解碼 類結構
最近開始做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)