寫(xiě)參數集x264_sps_write()和x264_pps_write()以及其中基本的bs_write()的過(guò)程。
挺有意思,挺巧妙的。他們就是負責碼流寫(xiě)入的過(guò)程,這個(gè)不同于寫(xiě)字節,直接COPY內存,用C語(yǔ)言實(shí)現對位的操作真的顯得比較笨拙,但是這里代碼還是很巧妙的。
說(shuō)基本的,static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits )這個(gè)函數的作用就是,向s里寫(xiě)入i_bits流的前i_count位,s當然是以字節為單位了,所以夠8個(gè)位就寫(xiě)下個(gè),哎呀太麻煩了,引別人寫(xiě)的把,不知道他這個(gè)是什么時(shí)候版本,但是大概意思差不多。酬和看。
| 地址 | 碼流值 | 十進(jìn)制值 | ASCII碼值 | i_bits | i_left |
| 0x00890058 | 11001101 | 205 | 8 | ||
| 0x00890058 | 01001101 | 77 | M | 0 | 7 |
| 0x00890058 | 00001101 | 13 | □ | 0 | 6 |
| 0x00890058 | 00101101 | 45 | - | 1 | 5 |
| Bit string form | Range of codeNum |
| 1 | 0 |
| 0 1 x0 | 1-2 |
| 0 0 1 x1 x0 | 3-6 |
| 0 0 0 1 x2 x1 x0 | 7-14 |
| 0 0 0 0 1 x3 x2 x1 x0 | 15-30 |
| 0 0 0 0 0 1 x4 x3 x2 x1 x0 | 31-62 |
| … | … |
static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits )
{
}
函數功能:
i_count是循環(huán)的次數即要寫(xiě)入的位數,i_bits是要編碼的數,i_left是當前空閑碼流的位數即記錄當前字節的空余位數。將i_bits編為i_count位的碼流,每次循環(huán),i_count和i_left都會(huì )減1,i_count和i_left并不一定相等。當i_left==0時(shí),s->p指針指向下一個(gè)碼流單元,i_left更新為8。
函數流程:
首先判斷i_count是否大于0,如果是,則判斷s->p是否大于s->p_end,若是則終止,否則,可以寫(xiě)入碼流。這個(gè)條件是在判斷是否有空閑的存儲空間供新的碼流寫(xiě)入。
若可以寫(xiě)碼流,則i_count--,表明可以進(jìn)行寫(xiě)一位的操作。注意,寫(xiě)i_bits是逐位寫(xiě)入的。
if( ( i_bits >> i_count )&0x01 )是用來(lái)判斷當前要寫(xiě)入的i_bits位是0還是1,從而選擇不同的算法來(lái)寫(xiě)入這個(gè)碼流。如果當前要寫(xiě)入的是0,則選擇*s->p &= ~( 1 << ( s->i_left - 1 ) )來(lái)把這個(gè)0寫(xiě)入碼流;如果當前要寫(xiě)入的是1,則選擇*s->p |= 1 << ( s->i_left - 1 )來(lái)把這個(gè)1寫(xiě)入碼流。
寫(xiě)完一位碼流后,初始的i_left被新寫(xiě)入的bit占了一位,所以i_left的值-1.
在進(jìn)入下一循環(huán)的時(shí)候,先判斷i_count的值,如果非零,程序繼續;如果為0,表示碼流已經(jīng)全部寫(xiě)入,程序終止。
注:該函數是采用一個(gè)while循環(huán),一次寫(xiě)入一個(gè)位,循環(huán)i_count次將i_bits的前i_count位寫(xiě)入s中。
2)static inline void bs_write1( bs_t *s, uint32_t i_bits )
該函數的作用是:將i_bits流的后1位寫(xiě)入s。
static inline void bs_write1( bs_t *s, uint32_t i_bits )
{
}
bs_write1()相當于bs_write(bs_t *s,1, uint32_t i_bits) 就是只寫(xiě)入1 bit碼流。
函數流程:
首先判斷s->p是否大于s->p_end,若是則終止,否則,可以寫(xiě)入碼流。
if(
寫(xiě)完一位碼流后,初始的i_left被新寫(xiě)入的bit占了一位,所以i_left的值-1.
這時(shí)判斷I_left是否等于0,如果i_left==0時(shí),表示當前存儲單元已被寫(xiě)滿(mǎn),所以s->p指針指向下一個(gè)存儲單元,i_left更新為8。這時(shí)再進(jìn)入下一循環(huán)。
注:上面兩個(gè)write函數是從網(wǎng)上找的,一次寫(xiě)入一個(gè)位數,先判斷要寫(xiě)入的位是0或1,再直接寫(xiě)入0或1,比較繁瑣但是便于理解,故此附上以供參考。
以下介紹的都是來(lái)自x264中的源碼。
3)static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits )
該函數的作用是:向s里寫(xiě)入i_bits流的后i_count位。
static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits )
{
}
流程簡(jiǎn)介:
首先判斷是否有空閑的存儲空間供新的碼流寫(xiě)入,若剩余不足4個(gè)字節的空間,則認為空間不夠,直接返回(uint32_t是32位,要4個(gè)字節的存儲空間); i_count是否大于0,如果是,則可以寫(xiě)入碼流。這個(gè)條件是在判斷是否該開(kāi)始或繼續寫(xiě)入碼流。
若可以寫(xiě)碼流,若i_count<32,則i_bits &= (1<<i_count)-1,將不需要寫(xiě)入的位置0。
注意,該函數寫(xiě)i_bits不是逐位寫(xiě)入的。
如果要寫(xiě)入的位數i_count < 本字節空余的位數s->i_left,則一次性將i_count位寫(xiě)入:
否則,則先寫(xiě)入i_left位:*s->p = (*s->p << s->i_left) | (i_bits >> (i_count - s->i_left)),i_count -= s->i_left(要寫(xiě)入的數減少),s->p++(進(jìn)入s的下一個(gè)字節),i_left重新置位為8。
while循環(huán)直至寫(xiě)入i_count位。
注:該函數同1)小節中介紹的函數作用一樣,不過(guò)效率要高。后面函數流程就不再詳細介紹了,只說(shuō)明大概思路。
4)static inline void bs_write1( bs_t *s, uint32_t i_bit )
該函數的作用是:將i_bits流的后1位寫(xiě)入s。
static inline void bs_write1( bs_t *s, uint32_t i_bit )
{
}
思路:直接寫(xiě)入*s->p <<= 1;
2 讀出碼流函數bs_read
1)static inline uint32_t bs_read( bs_t *s, int i_count )
該函數的作用是:從s中讀出i_count位,并將其做為uint32_t類(lèi)型返回。
static inline uint32_t bs_read( bs_t *s, int i_count )
{