首页 > 代码库 > 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)