【HEVC學習與研究】26、HEVC的算數編碼實現
阿新 • • 發佈:2019-02-14
關於HEVC的前25篇博文全文發表在新浪部落格,地址為:http://blog.sina.com.cn/s/articlelist_1376260467_0_1.html。從第26篇開始部落格全文發在CSDN,新浪同步更新摘要和連結地址。
在第13篇博文中貼出了我們在除錯程式碼時所採用的二進位制碼流的開頭一部分資料,並根據這些資料進行了NAL Header解析、引數集合解析和條帶頭解析等資訊的分析。今後的博文中如無特殊情況依然會採用這些資料作為學習材料。
通過對這段碼流進行分析,我們可以看出,在對於一個slice進行解碼的過程中,對slice header和slice data採取了不同的熵解碼方法:slice header的語法元素採用了變長碼(主要是指數哥倫布編碼),而slice data的語法元素採用的是算術編碼CABAC。由於對CABAC的基本概念不是非常熟悉,之前一段時間一直在回顧H.264中CABAC相關的知識,現在來看HEVC重的算術編碼相對於H.264做了什麼樣的改變。TDecBinCABAC::decodeBin( UInt& ruiBin, ContextModel &rcCtxModel )
{
//實現匯出ivlLpsRange值的過程:通過選定的上下文模型獲取當前狀態,通過計算ivlCurrRange的值計算得到qRangeIdx(qRangeIdx =( ivlCurrRange >> 6 ) & 3);
UInt uiLPS = TComCABACTables::sm_aucLPSTable[ rcCtxModel.getState() ][ ( m_uiRange >> 6 ) - 4 ];
m_uiRange -= uiLPS; //m_uiRange(標準文件中描述為ivlCurrRange)初始化為510,並變更為ivlCurrRange − ivlLpsRange
UInt scaledRange = m_uiRange << 7;//計算更新的ivlOffset,這個值是表示算數解碼器引擎狀態的變數之一,在解碼引擎初始化的時候進行賦值
if( m_uiValue < scaledRange )//根據ivlOffset與ivlCurrRange的對比判斷當前屬於MPS還是LPS
{
// MPS path
ruiBin = rcCtxModel.getMps();//直接將valMps返回給輸出值binVal
rcCtxModel.updateMPS();//更新MPS的上下文索引,通過查詢表m_aucNextStateMPS[]獲得
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();//輸出值valMps設為1-valMps
rcCtxModel.updateLPS();//更新LPS的上下文模型索引,通過查詢表m_aucNextStateLPS[]獲得。
m_bitsNeeded += numBits;
if ( m_bitsNeeded >= 0 )
{
m_uiValue += m_pcTComBitstream->readByte() << m_bitsNeeded;
m_bitsNeeded -= 8;
}
}
}