Skip to content

LayZhanger/h265_c_reference

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

写verilog实现H265解码器前为了理解协议实现的一个简化版本的H265解码器C代码,是VS2013的工程,输入文件是test.265,工程里含有一些测试文件,重命令成test.265即可。编译,按F5跑即可,输出out.yuv,以及一些log文件。

主要参考H265标准,ffmpeg和HM,参考的是JCTVC-L1003_v34,
代码尽量和标准写的保持一致,变量名字和标准也保持一致,便于理解,消除看HM和ffmpeg时因为绕弯而带来的困惑,适合初学h265标准的同学们。
举一个cabac decode bin的例子,
HM12.0的代码如下,
Void
TDecBinCABAC::decodeBin( UInt& ruiBin, ContextModel &rcCtxModel )
{
  UInt uiLPS = TComCABACTables::sm_aucLPSTable[ rcCtxModel.getState() ][ ( m_uiRange >> 6 ) - 4 ];
  m_uiRange -= uiLPS;
  UInt scaledRange = m_uiRange << 7;
  
  if( m_uiValue < scaledRange )
  {
    // MPS path
    ruiBin = rcCtxModel.getMps();
    rcCtxModel.updateMPS();
    
    if ( scaledRange >= ( 256 << 7 ) )
    {
      return;
    }
    
    m_uiRange = scaledRange >> 6;
    m_uiValue += m_uiValue;
    
    if ( ++m_bitsNeeded == 0 )
    {
      m_bitsNeeded = -8;
      m_uiValue += m_pcTComBitstream->readByte();      
    }
  }
  else
  {
    // LPS path
    Int numBits = TComCABACTables::sm_aucRenormTable[ uiLPS >> 3 ];
    m_uiValue   = ( m_uiValue - scaledRange ) << numBits;
    m_uiRange   = uiLPS << numBits;
    ruiBin      = 1 - rcCtxModel.getMps();
    rcCtxModel.updateLPS();
    
    m_bitsNeeded += numBits;
    
    if ( m_bitsNeeded >= 0 )
    {
      m_uiValue += m_pcTComBitstream->readByte() << m_bitsNeeded;
      m_bitsNeeded -= 8;
    }
  }
}

FFMPEG的代码,
static av_always_inline int get_cabac_inline(CABACContext *c, uint8_t * const state){
    int s = *state;
    int RangeLPS= ff_h264_lps_range[2*(c->range&0xC0) + s];
    int bit, lps_mask;


    c->range -= RangeLPS;
    lps_mask= ((c->range<<(CABAC_BITS+1)) - c->low)>>31;

    s^=lps_mask;
    *state= (ff_h264_mlps_state+128)[s];
    bit= s&1;


    lps_mask= ff_h264_norm_shift[c->range];
    c->range<<= lps_mask;
    c->low  <<= lps_mask;

    if(!(c->low & CABAC_MASK)) {
        refill2(c);

    }
    return bit;
}
下面是完完全全按照spec两幅图来实现的代码,实践证明代码完全按照spec来写,结果也是对的,而HM和ffpeg都有不同程度的绕弯,让人在理解过程中感到蛋腾。





void decode_bin(unsigned char *rbsp, int *binVal, struct context_model *cm)
{
	//9.3.4.3.2  Arithmetic decoding process for a binary decision
	int ivlLpsRange, qRangeIdx;
	qRangeIdx = (ivlCurrRange >> 6) & 3;
	ivlLpsRange = rangeTabLps[cm->pStateIdx][qRangeIdx];

	ivlCurrRange = ivlCurrRange - ivlLpsRange;
	if (ivlOffset >= ivlCurrRange) {
		//LPS path
		*binVal = 1 - cm->valMps;
		ivlOffset -= ivlCurrRange;
		ivlCurrRange = ivlLpsRange;
	} else {
		//MPS path
		*binVal = cm->valMps;
	}
	//9.3.4.3.2.2  State transition process 
	if(*binVal == cm->valMps){ 
		cm->pStateIdx = transIdxMps[cm->pStateIdx];
	} else {
		if (cm->pStateIdx == 0) 
			cm->valMps = 1 - cm->valMps;

		cm->pStateIdx = transIdxLps[cm->pStateIdx];
	}
	//renorm
	while (ivlCurrRange < 256) {
		ivlCurrRange = ivlCurrRange << 1;
		ivlOffset = ivlOffset << 1;
		ivlOffset = ivlOffset | read_one_bit(rbsp);
	}

}


About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C++ 91.4%
  • C 8.6%