hevc所使用的熵編碼方法為cabac(基於上下文的自適應二進位制算術編碼),大致分為三個步驟:
1、二值化
2、上下文建模(模型初始化、更新)
3、二進位制算術編碼
對該語法元素的編碼是在codedeltaqp函式中完成的。
void entropy::codedeltaqp(const cudata& cu, uint32_t abspartidx)
}
一、二值化
根據hevc的標準,cu_qp_delta_abs語法元素的字首部分的值為:prefixval=min(cu_qp_delta_abs,5)。並且對prefixval的編碼使用截斷萊斯二進位製化方法(tr),tr方法的兩個引數cmax=5、criceparam = 0。x265中將cu_dqp_tu_cmax(cmax)和tuvalue(prefixval)兩個引數傳遞給writeunarymaxsymbol函式並在其中完成二值化,該函式也同時對其進行編碼,這之後會講。
void entropy::writeunarymaxsymbol(uint32_t symbol, uint8_t* scmmodel, int offset, uint32_t maxsymbol)
該函式中symbol為語法元素值,maxsymbol為門限值cmax,萊斯引數r(criceparam)=0,其他引數先不管。tr分為字首碼和字尾碼,兩者分開求取。
字首值p=v>>r,所以p=symbol,第一種情況:若p小於值(cmax>>r)=maxsymbol,則字首碼由p個『1』和乙個『0』組成,當symbol為0時,p等於0,所以字首就只有乙個0,而p不等於0時,字首碼的第乙個值就為1,所以對第一位進行編碼的encodebin函式的第乙個引數就可以確定,剩餘的『1』在while迴圈中編碼完成,因為迴圈條件為(--symbol)所以會編碼symbol-1個『1』。到此也就完成了p個『1』的編碼,且symbol第二種情況:p大於等於值(cmax>>r)時,字首碼由maxsymbol個『1』組成,由第乙個編碼函式加上while中的編碼函式完成。
字尾值s=v-(p二、上下文模型
1、初始化
codedeltaqp傳遞給writeunarymaxsymbol的兩個引數:
&entropy->m_contextstate[off_delta_qp_ctx](最大概率符號mps、概率狀態索引)和1(初始化型別)
確定了對該語法元素編碼的上下文模型。下面講解對上下文的初始化:
首先先給出標準中對該步驟的描述
inittype01
2initvariable
0..1
2..3
4..5
initvariable
initvalue
我們最終所要的就是initvalue,初始化的函式為:
initbuffer(&m_contextstate[off_delta_qp_ctx], slicetype, qp, (uint8_t*)init_dqp, num_delta_qp_ctx);
static void initbuffer(uint8_t* contextmodel, slicetype slicetype, int qp, uint8_t* ctxmodel, int size)
先看initbuffer函式的引數列表,size=num_delta_qp_ctx=3,表示上下文模型個數,根據上面的**可知,實際上該語法元素需要6個上下模型,但因為initvalue的值都相同,初始化出來的模型也都相同,也就不需要initvariable的中轉,可以直接與inittype對應。slicetype就代表inittype
typedef enum slicetype
slicetype;
init_dqp=ctxmodel儲存initvaluestatic const uint8_t init_dqp[3][num_delta_qp_ctx] =
, ,,};
contextmodel就是儲存位址,qp為片層亮度量化引數,初始化演算法中會使用。將initvalue和qp傳給sbacinit實現初始化。
uint8_t sbacinit(int qp, int initvalue)
初始變數計算方法(標準中已給出),mpstate?(initstate-64):(63-initstate)得到概率狀態索引,mpstate為最大概率符號,最後將概率狀態索引左移一位,末尾賦值最大概率符號,state同時儲存兩個引數。
contextmodel=m_contextstate陣列內儲存的就是state,也就是上下文模型。
2、更新
writeunarymaxsymbol函式中的encodebin函式就是實現對二進位制值得編碼,第乙個引數就是二進位制值,第二個引數就是所使用的上下文模型,其引數offset表示在確定inittype中的偏移量,第乙個二進位制位比較特殊需要與後幾位想區分,使用第乙個上下文模型,而後幾位就使用offset所確定的上下文模型。
void entropy::encodebin(uint32_t binvalue, uint8_t &ctxmodel)
uint32_t range = m_range;
uint32_t state = sbacgetstate(mstate);
uint32_t lps = g_lpstable[state][((uint8_t)range >> 6)];
range -= lps;
x265_check(lps >= 2, "lps is too small\n");
int numbits = (uint32_t)(range - 256) >> 31;
uint32_t low = m_low;
// note: mps must be lowest bit in mstate
x265_check((uint32_t)((binvalue ^ mstate) & 1) == (uint32_t)(binvalue != sbacgetmps(mstate)), "binvalue failure\n");
if ((binvalue ^ mstate) & 1)
m_low = (low << numbits);
m_range = (range << numbits);
m_bitsleft += numbits;
if (m_bitsleft >= 0)
writeout();
}
函式中是使用sbacnext通過查表的方法對模型進行更新的。實際上就是標準中所給的概率更新表,只是根據x265中的實際情況進行改寫,就是考慮到mstate最後一位為mps。const uint8_t g_nextstate[128][2] =
, , , , , , , ,
, , , , , , , ,
, , , , , , , ,
, , , , , , , ,
, , , , , , , ,
, , , , , , , ,
, , , , , , , ,
, , , , , , , ,
, , , , , , , ,
, , , , , , , ,
, , , , , , , ,
, , , , , , , ,
, , , , , , , ,
, , , , , , , ,
, , , , , , , ,
, , , , , , ,
};
三、二進位制算術編碼
encodebin後續完成的就是算術編碼,取出當前的編碼區間m_range和區間下限m_low,sbacgetstate函式將mstate右移一位得到state概率狀態索引,通過取出m_range的後8位(unit8)&3得到計算索引值,與state仍通過查編碼區間索引表的方法確定出當前的最小概率符號區間lps,x265中直接計算range=range-lps得到最大概率區間。
變數numbits表示的是重歸一化過程中輸出的碼元數。重歸一化流程圖如圖所示
numbits第一次被賦的值為(range - 256) >> 31,range為32位,取出符號位,也就得到range是否大於256,。該numbits是在當前二進位制值等於mps的情況下使用的,而其取值為什麼只能為『0』和『1』,是因為在
編碼區間索引表中相鄰概率狀態索引值所對應的lps取值相近,表明當前m_range減去lps若小於256,只要左移一位就可以使其值大於256。
函式的最後根據所得的numbits,實現部分的歸一化操作,並將numbits存入全域性變數中。
if語句中實現的是二進位制值等於(最小概率符號)lps的情況,if中的條件就是binvalue和mstate最後一位的值不相同時執行。
clz函式得到lps二進位制串最高位『1』的位置。
int clz(unsigned int a)
}m_numbufferedbytes = 1;
m_bufferedbyte = (uint8_t)leadbyte;}}
該函式實現流程圖中根據不同情況對l進行調整的步驟,並根據l的值決定輸出的是『0』還是『1』。但這裡使用的是相當複雜的演算法,最終以位元組為單位將編碼下限m_low中的高位作為碼流輸出。到此就完成了熵編碼一條支線上的全過程。
感謝閱讀!!上述都是個人的理解,如果有什麼原則性的錯誤還請提出!!
x265探索與研究(二) x265使用基本方法
參考 第一步 進入 x265 1.8 build vc10 x86 雙擊 build all.bat 則進行編譯。資料夾中的內容變化如下兩圖所示。第二步 用vs開啟上一步中生成的 x265.sln 其具體位置在 x265 1.8 build vc10 x86 如下圖,根據平台選擇 開啟後,vs出現如...
x265各個preset對比
x265編碼器中設定了一系列的preset,包括ultrafast,supe st,veryfast,faster,fast,medium,slow,slower,veryslow和placebo。現在對這幾種preset的引數值進行乙個簡單的對比。其中藍色區域是default的值,medium就是...
x265多執行緒 鎖
對互斥量的一層包裝 class lock 銷毀互斥量 lock 對互斥量加鎖 void acquire 釋放互斥量 void release protected pthread mutex t handle 互斥量 模擬lock guard,建立時自動加鎖 超出scopedlock的作用域,被析構 ...