H 264碼流結構及JM8 6中碼流的產生步驟

2021-06-26 16:30:51 字數 3177 閱讀 9742

整理自:

h.264碼流結構示意圖:

nalu第一位元組包括3個語法結構:

forbidden_zero_bit(1) // 1bit禁止位,一般為0;
nal_ref_idc(2) // 2bit 表示該nal單元的重要性,
nal_unit_type(5) // 5bit 表示nalu型別
加起來正好乙個位元組, 如下圖所示:

對sodb的最後填充rbsp_trailing_bits就得到rbsp,而這個rbsp_trailing_bits是第乙個位元為1,接下來是0,直到位元組對齊。比如sodb的最後幾個位元是1001,這時rbsp_trailing_bits即為:1000

sodb 到rbsp到轉換**如下:

void sodbtorbsp(bitstream*currstream)

前4句就是要得到rbsp_trailing_bits,bits_to_go用來記錄要添0的個數。bits_to_go這個量在進行u_v等函式呼叫的函式writeuvlc2buffer中是對其不斷進行改變的。

這個函式是將rbsp轉為ebsp,需要進行填充防止競爭的0x03,需要對以下幾種進行變化:

0x000000----->0x00000300

0x000001----->0x00000301

0x000002----->0x00000302

0x000003------>0x00000303

在具體的**中, 是利用下面的**進行實現的:

if(count == zerobytes_shortstartcode && !(nal_payload_buffer[i] & 0xfc))

注意:在上面的if語句中,count用於統計0x00位元組的個數,當count==2時,我們需要檢測接下來的乙個位元組是否為(00,01,02或03),此處用的方法比較巧妙:0xfc=11111100b,也就是說遮蔽了最後兩位位元,這樣要求nal_payload_buffer[i] 必須為0。如果滿足這個說明就是我們要找的那4個。

在jm8.6的main函式中,先呼叫start_sequence();函式來開始序列:start_sequence()函式中進行了寫序列引數集和影象引數集的操作。

(1) generateseq_parameter_set_nalu產生序列引數集,writenalu函式寫nalu,即:

nalu = generateseq_parameter_set_nalu ();

len += writenalu (nalu);

(2) generatepic_parameter_set_nalu產生影象引數集,writenalu函式寫nalu,即:

nalu = generatepic_parameter_set_nalu ();

len += writenalu (nalu);

(該文最下面有對writenalu的介紹)

在函式generateseq_parameter_set_nalu和函式generatepic_parameter_set_nalu中都是先將引數集資料寫入到資料結構bitstream->streambuffer中,然後利用sodbtorbsp函式對原始資料進行處理得到rbsp,然後再函式rbsptonalu函式中將rbsp轉為ebsp 最後呼叫writenalu (nalu)函式將所寫好的nalu寫入到檔案中去。

在for迴圈中呼叫encode_one_frame函式編碼每一幀,並且包括將編碼完每一幀得到熵編碼得到的碼流 寫入到乙個nalu中去,所以說乙個nalu就是一幀影象編碼過程中的編碼結果是儲存在currstream->streambuffer資料結構中的,然後在函式writeunit中將currstream->streambuffer中的資料複製到了nalu結構中。其實是在writeunit函式中先生成了乙個nalu資料結構,然後填充nalu的相關資料,最後呼叫writenalu函式將nalu寫入到檔案中。

幀影象:encode_one_frame()

->(1) frame_picture()->code_a_picture()->(while迴圈)encode_one_slice->encode_one_mb

(2) writeout_picture()->(for迴圈)writeunit()->writenalu()[準確來說是寫乙個slice]

場影象:encode_one_frame()

->(1)field_picture (top_pic, bottom_pic);->code_a_picture(分別對頂場和底場編碼)

(2)writeout_picture (top_pic);

writeout_picture (bottom_pic);分別寫頂場和底場

通過分析可以知道編碼時是將乙個slice作為乙個小組(區域單位)進行編碼的,一幀影象可以包括多個slice。在jm8.6中資料結構的層次是:

picture

}}

從這個我們可以看到一幅影象可以包括多個slice,乙個slice可以對應1個bitstream,而在函式writeunit中是以slice為單位進行寫的,所以我們可以得到乙個nalu中包含乙個slice,一般情況下乙個slice對應一幅影象,所以,此時乙個nalu也就對應乙個slice。

最後釋放空間。

在start_sequence()函式中將writenalu函式指標賦值,

int start_sequence()    

}

先寫3個位元組的起始碼0x000001

即:putc (0, f);

putc (0, f);

putc (1, f);

bitswritten += 24;

然後再將nalu寫入到檔案中,即:

if (n->len != fwrite (n->buf, 1, n->len, f))

H 264碼流結構

a 對照 h.263 的碼流結構 h.263 定義的碼流結構是分級結構,共四層。自上而下分別為 影象層 picture layer 塊組層 gob layer 巨集塊層 macroblock layer 和塊層 block layer psctr ptype pquant cpmpsbi trbdb...

H 264碼流結構

a 對照 h.263的碼流結構 h.263定義的碼流結構是分級結構,共四層。自上而下分別為 影象層 picture layer 塊組層 gob layer 巨集塊層 macroblock layer 和塊層 block layer psc tr ptype pquant cpmpsbi trbdbq...

H 264碼流結構

什麼是封裝格式 重新整理影象概念 在我們的印象中,一張就是一張影象,而在h264中影象是個集合的概念。逐行掃瞄與隔行掃瞄.png 幀與場.png h264原始碼流 h264碼流.png 乙個原始的h.264 nalu 單元常由 startcode nalu header nalu payload 三...