1. 程式人生 > >0階 無符號指數哥倫布編碼

0階 無符號指數哥倫布編碼

%d 表示 syntax ber 相關性 variable aps 官方 pla

指數哥倫布編碼與哈夫曼編碼一樣都屬於變長編碼

但二者也有顯著的區別:

1>信源相關性: 哈夫曼編碼依賴於信源的概率分布,而指數哥倫布編碼與信源無關

2>額外信息: 哈夫曼編碼必須攜帶與該信源匹配的碼表,指數哥倫布編碼無需攜帶額外信息

h264官方協議文檔中定義了4類指數哥倫布編碼分為:

ue(v)無符號指數哥倫布編碼 、se(v)有符號指數哥倫布編碼、 te(v)截斷指數哥倫布編碼 和 me(v)映射指數哥倫布編碼

下面我們截取了協議文檔中 ue(v)無符號指數哥倫布編碼的部分作為例子來分析,其他幾種模式均是在此基礎上 進行變換得來。

9 Parsing process

Inputs to this process are bits from the RBSP.

Outputs of this process are syntax element values.

This process is invoked when the descriptor of a syntax element in the syntax tables in subclause 7.3 is equal to ue(v), me(v), se(v), te(v) (see subclause 9.1), ce(v) (see subclause 9.2), or ae(v) (see subclause 9.3).

9.1 Parsing process for Exp-Golomb codes

This process is invoked when the descriptor of a syntax element in the syntax tables in subclause 7.3 is equal to ue(v), me(v), se(v), or te(v). For syntax elements in subclauses 7.3.4 and 7.3.5, this process is invoked only when entropy_coding_mode_flag is equal to 0.

Inputs to this process are bits from the RBSP.

Outputs of this process are syntax element values.

Syntax elements coded as ue(v), me(v), or se(v) are Exp-Golomb-coded. Syntax elements coded as te(v) are truncated Exp-Golomb-coded. The parsing process for these syntax elements begins with reading the bits starting at the current location in the bitstream up to and including the first non-zero bit, and counting the number of leading bits that are equal to 0. This process is specified as follows:

leadingZeroBits = ?1

for( b = 0; !b; leadingZeroBits++ )

b = read_bits( 1 )

The variable codeNum is then assigned as follows:

(9-1)

codeNum = 2leadingZeroBits ? 1 + read_bits( leadingZeroBits )

(9-2)

where the value returned from read_bits( leadingZeroBits ) is interpreted as a binary representation of an unsigned integer with most significant bit written first.

Table 9-1 illustrates the structure of the Exp-Golomb code by separating the bit string into "prefix" and "suffix" bits. The "prefix" bits are those bits that are parsed in the above pseudo-code for the computation of leadingZeroBits, and are shown as either 0 or 1 in the bit string column of Table 9-1. The "suffix" bits are those bits that are parsed in the computation of codeNum and are shown as xi in Table 9-1, with i being in the range 0 to leadingZeroBits ? 1, inclusive.

Each xi can take on values 0 or 1.

Table 9-1 – Bit strings with "prefix" and "suffix" bits and assignment to codeNum ranges (informative)

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

從上述表中我們可以看到 一個編碼片段 分為3個部分 前綴0 、標誌位bit1、後綴二進制數與前綴的位數相同。

計算公式為 codeNum = 2leadingZeroBits ? 1 + read_bits( leadingZeroBits )

如 0 0 0 1 0 1 1
前綴prefix 為 2^(leadingZeroBits = 3) -1 = 7
後綴surfix 0 1 1 = 0*2^2 + 1*2^1 +1*2^0 = 3
codeNum = prefix + surfix = 10

具體實現如下

技術分享圖片
// ExpColomb.cpp : 定義控制臺應用程序的入口點。
//

#include "stdafx.h"
#include <assert.h>

typedef unsigned char UINT8;
/*
buf 為字節數組
bytePosition 為字節位置
bitPosition 為當前字節中 從左往右 的 bit位 的 位置 範圍(0~7)
如 buf:                   0 0 0 0 1 0 0 0, 1 1 0 0 0 1 0 0, 0
bytePosition:         [         0         ]  [         1         ]
bitPosition:           0 1 2 3 4 5 6 7  0 1 2 3 4 5 6 7  0 
*/
static int get_bit_at_position(UINT8 *buf, UINT8 &bytePosition, UINT8 &bitPosition)
{
    UINT8 mask = 0, val = 0;

    mask = 1 << (7 - bitPosition);
    val = ((buf[bytePosition] & mask) != 0);//獲取當前bit位的值
    if (++bitPosition > 7)//若大於7則進入下一個字節
    {
        bytePosition++;
        bitPosition = 0;
    }

    return val;
}

static int get_uev_code_num(UINT8 *buf, UINT8 &bytePosition, UINT8 &bitPosition)
{
    assert(bitPosition < 8);
    UINT8 bitVal = 0;
    int codeNum = 0,prefix = 0, surfix = 0,leadingZeroBits = 0;
    //獲取前導0的個數
    while (true)
    {
        bitVal = get_bit_at_position(buf, bytePosition, bitPosition);
        if (0 == bitVal)
        {
            leadingZeroBits++;
        }
        else
        {
            break;
        }
    }
    /*如 0 0 0     1     0 1 1   
    前綴prefix 為  2^(leadingZeroBits = 3) -1 = 7
    後綴surfix  0 1 1  = 0*2^2 + 1*2^1 +1*2^0 = 3
    codeNum = prefix + surfix = 10
    */
    prefix = (1 << leadingZeroBits) - 1;
    for (int bit_pos = leadingZeroBits-1; bit_pos >-1; bit_pos--)
    {
        bitVal = get_bit_at_position(buf, bytePosition, bitPosition);
        surfix += (1 << bit_pos)*bitVal;
    }
    codeNum = prefix + surfix;
    return codeNum;
}

int main()
{
    UINT8 strArray[6] = { 0xA6, 0x42, 0x98, 0xE2, 0x04, 0x8A };
    UINT8 bytePosition = 0, bitPosition = 0;
    UINT8 dataBitLength = sizeof(strArray) * 8; //數組的總bit數

    int codeNum = 0;
    while ((bytePosition * 8 + bitPosition) < dataBitLength)
    {
        codeNum = get_uev_code_num(strArray, bytePosition, bitPosition);
        printf("ExpColomb codeNum = %d\n", codeNum);
    }

    getchar();
    return 0;
}
View Code

技術分享圖片

從運行結果可以看到 這裏用6個字節 表示了從0到9的10個十進制數

標準協議文檔中se(v) 有符號指數哥倫布編碼如下

Table 9-3 – Assignment of syntax element to codeNum for signed Exp-Golomb coded syntax elements se(v)

codeNum

syntax element value

0

0

1

1

2

?1

3

2

4

?2

5

3

6

?3

k

(?1)k+1 Ceil( k÷2 )

我們可以看出 se(v) 是由 我們上面計算的codeNum通過公式 (?1)codeNum+1 Ceil(codeNum÷2 ) 變換得來,

其中 ceil 為向上取整 ceil(1.5) = 2

映射指數哥倫布也是在得出codeNum的基礎上,再通過查表得出具體數值 如:

(a) ChromaArrayType is equal to 0 or 3

codeNum

coded_block_pattern

Intra_4x4, Intra_8x8

Inter

0

15

0

1

0

1

2

7

2

3

11

4

4

13

8

5

14

3

6

3

5

7

5

10

8

10

12

一個codeNum通過查表可以得到2個參數

0階 無符號指數哥倫布編碼