自己動手寫 H.264 解碼器---指數(shù)哥倫布熵編碼代碼實現(xiàn)

引言

更多系列文章請訪問自己動手寫 H.264 解碼器

上一小節(jié),我們闡述了無符號指數(shù)哥倫布熵編碼 ue(v),有符號指數(shù)哥倫布熵編碼 se(v),映射指數(shù)哥倫布熵編碼 me(v),截斷指數(shù)哥倫布熵編碼 te(v)四種指數(shù)哥倫布熵編碼的理論知識。本小節(jié),就來看看怎么用代碼來解碼指數(shù)哥倫布編碼的數(shù)據(jù)。

本小節(jié)主要介紹無符號指數(shù)哥倫布熵編碼和有符號指數(shù)哥倫布熵編碼的解碼,對于映射指數(shù)哥倫布熵編碼和截斷指數(shù)哥倫布熵編碼,因為涉及到一些前置知識還沒有講到,本節(jié)先不做實現(xiàn),后續(xù)遇到的時候會實現(xiàn)。

BitStream

我們之前就說過,在 H.264 碼流中的操作單位是 bit,所以,用普通的指針是無法達到這樣的操作顆粒度。

我們現(xiàn)在需要一個以 bit 為操作單位的流對象,我們把他叫做 BitStream。

1566f2152fff2b58ac3d34d9822e46ea.png

接口設(shè)計

類的結(jié)構(gòu)

class BitStream {
public:
    /**
      * 構(gòu)造函數(shù)可以傳入一個 buffer,這里可以直接把 nalu 的 buffer 傳入
      */
    BitStream(unsigned char * buf, int size);
    ~BitStream();

private:
    // 指向 buffer 開始的位置
    unsigned char * start = nullptr;

    // buffer 的長度(單位 Byte)
    int size = 0;

    // 當(dāng)前讀取到了哪個字節(jié)
    unsigned char * p = nullptr;

    // 當(dāng)前讀取到了字節(jié)中的第幾位
    int bits_left = 8;
};

各個屬性的說明圖

2786f5f8c9a2cca4643ba61005a821f9.png

函數(shù)的設(shè)計

  • 從 Bitstream 中讀取 1 bit 的接口

    在編寫從數(shù)據(jù)流里讀取指數(shù)哥倫布編碼的數(shù)據(jù)之前,我們先來完成一個最基本的函數(shù)的封裝:先讀取 1 bit 的數(shù)據(jù)。

    int ReadU1();
    

    我們先定義一個 ReadU1 的成員函數(shù),這個函數(shù)的作用是從 bitstram 讀取一個 bit 的數(shù)據(jù),并把這一個 bit 的數(shù)據(jù)轉(zhuǎn)換成一個 int 類型,然后把數(shù)據(jù)指針向后移動一個 bit(通過 bits_left 減 1 實現(xiàn),如果 bits_left 被減到了 0,那么 unsigned char * p 將向后移動一個字節(jié))。雖然 1 bit 的數(shù)據(jù)只會有 0 或者 1 兩種情況,但是我們?yōu)榱朔奖氵€是直接用一個 int 來裝。如果你覺得有些浪費空間,可以自己修改一下。

    這個函數(shù)的實現(xiàn)如下:

    int ReadU1()
    {
        int r = 0;
        bits_left--;
        r = ((*(p)) >> bits_left) & 0x01;
        if (bits_left == 0) {
            p++;
            bits_left = 8;
        }
        return r;
    }
    
  • 從 Bitstream 中讀取 n bit 的接口

    接下來,我們再寫一個函數(shù),這個函數(shù)是 ReadU1 的擴增,我們可以一下從 Bitstream 中讀取 n bit 的數(shù)據(jù)。

    int ReadU(int n)
    {
        int r = 0;
        int i;
        for (i = 0; i < n; i++) {
            r |= ( ReadU1() << ( n - i - 1 ) );
        }
        return r;
    }
    
  • 從 Bitstream 中讀取一個無符號指數(shù)哥倫布熵編碼的數(shù)據(jù)

    這個應(yīng)該是不需要做過多的解釋了。我們在前一小結(jié)已經(jīng)專門講解了。

    int ReadUE()
    {
        int r = 0;
        int i = 0;
        while((ReadU1() == 0) && (i < 32)){
            i++;
        }
        r = ReadU(i);
        r += (1 << i) - 1;
        return r;
    }
    
  • 從 Bitstream 中讀取一個有符號指數(shù)哥倫布熵編碼的數(shù)據(jù)

    我們在讀取有符號的指數(shù)哥倫布熵編碼的時候,實際上是先按照無符號的方式去讀,然后讀出來之后再解析符號。

    int ReadSE()
    {
        int r = ReadUE();
        if (r & 0x01) {
            r = (r+1)/2;
        }
        else {
            r = -(r/2);
        }
        return r;
    }
    

完整代碼

BitStream.hpp

#ifndef EYERLIB_BITSTREAM_HPP
#define EYERLIB_BITSTREAM_HPP

class BitStream {
public:
    BitStream(unsigned char * buf, int size);
    ~BitStream();

    int ReadU1();
    int ReadU(int n);

    int ReadUE();
    int ReadSE();

private:
    unsigned char * start = nullptr;
    int size = 0;
    unsigned char * p = nullptr;
    int bits_left;
};


#endif //EYERLIB_BITSTREAM_HPP

BitStream.cpp

#include "BitStream.hpp"


BitStream::BitStream(unsigned char * _buf, int _size)
{
    start = _buf;
    p = _buf;
    size = _size;
    bits_left = 8;
}

BitStream::~BitStream()
{

}

int BitStream::ReadU1()
{
    int r = 0;
    bits_left--;
    r = ((*(p)) >> bits_left) & 0x01;
    if (bits_left == 0) {
        p++;
        bits_left = 8;
    }
    return r;
}

int BitStream::ReadU(int n)
{
    int r = 0;
    int i;
    for (i = 0; i < n; i++) {
        r |= ( ReadU1() << ( n - i - 1 ) );
    }
    return r;
}

int BitStream::ReadUE()
{
    int r = 0;
    int i = 0;
    while((ReadU1() == 0) && (i < 32)){
        i++;
    }
    r = ReadU(i);
    r += (1 << i) - 1;
    return r;
}

int BitStream::ReadSE()
{
    int r = ReadUE();
    if (r & 0x01) {
        r = (r+1)/2;
    }
    else {
        r = -(r/2);
    }
    return r;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容