H.265/HEVC解码器 C 参考代码

五年前,为了在fpga上实现h.265, 花了一段时间来看懂h.265的spec,现在分享出来有点晚了,h.266也出来了。

代码分享在github,https://github.com/tishi43/h265_c_reference

   也欢迎到我的github主页https://github.com/tishi43看看,定期上传一些代码,

    这是一个简化版本的h.265代码,中间没有任何优化,为了和协议保持完全一致,变量名字和协议里保持一致,流程和协议一致,适合初学者拿来理解协议。

参考了HM和ffmpeg,参考的时候,发现代码和spec不完全对得起来,其中有绕弯。还有做了一些优化,优化的地方跟spec有些偏离了,有些地方看好一会才理解过来。

下面是cabac decode bin的例子,

举一个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两幅图来实现的代码

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);
	}

}

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值