x264閱讀記錄-3

 

14. x264_macroblock_encode函數-1 算法

這個函數主要根據已經選定的模式來對宏塊殘差進行編碼。 數組

1)若是是P_SKIP模式,那麼調用x264_macroblock_encode_pskip函數 less

x264_macroblock_encode_pskip中先對亮度和色度進行運動補償,調用的函數函數h->mc.mc_luma h->mc.mc_chroma。這兩個是函數指針,根據須要對其進行初始化。通常經常使用的是函數mc_luma, mc.c文件中。mc_luma中若是存在MVxy均不爲0),那麼調用pixel_avg;不然,調用mc_copypixel_avg位於mc.c文件中,是1/4搜索時須要臨時插值函數。  函數

dst[x] = ( src1[x] + src2[x] + 1 ) >> 1;   //利用相鄰半像素和兩個像素取平均插值 編碼

mc_copy位於mc.c文件。 spa

最後還要調用x264_macroblock_encode_skip函數,在這個函數中主要設置CBP值。 指針

(2)若是是B_SKIP模式,先是調用x264_mb_mc函數完成運動補償,而後調用x264_macroblock_encode_skip來進行CBP設置。 code

3)接下來是幀內模式的編碼,包括幀內I_16x16,幀內I_8x8和幀內I_4x4。在作每種模式的編碼以前都要先計算預測幀。分別調用相應的預測函數 predict_16x16predict_8x84個塊)和predict_4x416個塊)。 orm

A. 對於I_16x16,調用x264_mb_encode_i16x16進行編碼,若是是無損編碼h->mb.b_lossless被置上,則以4x4爲單位,進行無損壓縮的量化和掃描。如果有損壓縮方式,先調用 h-> dctf. sub16x16_dct計算宏塊殘差(p_src-p_dst)並進行4x4大小的DCT變換。 仍然,h-> dctf. sub16x16_dct是一個函數指針,其最常設置的值是sub16x16_dct,位於dct.c文件中。 blog

sub16x16_dct函數中,是對48x8塊進行調用分別調用sub8x8_dct來完成殘差計算和DCT變換的。而sub8x8_dct則是調用4sub4x4_dct分別對44x4塊進行殘差DCT變換計算的。具體到sub4x4_dct,是調用pixel_sub_wxh來計算獲得殘差,而後再進行DCT變換,採用264中經典的4x4DCT變換的算法。

DCT變換完成以後,對164x4塊在for循環中進行處理:先拿出每一個4x4塊的DC係數(存放在一個數組dct4x4[0]中),而後對每一個4x4塊進行量化、掃描和反量化。分別由函數:x264_quant_4x4_trellisquant_4x4scan_zigzag_4x4h->quantf.dequant_4x4完成。

接下來,對全部4x4塊的在數組dct4x4 [0]DCT係數進行:DCT變換、量化和掃描。分別由函數: h->dctf.dct4x4dcquant_4x4_dcscan_zigzag_4x4full完成。

而後,爲了重建幀的須要,對DC係數進行反DCT變換、反量化(爲何不是先反量化後反變換,待解決)。分別由函數h->dctf.idct4x4dcx264_mb_dequant_4x4_dc完成。對於直流係數,對每一個4x4子塊進行反DCT、反量化並加到預測宏塊上獲得重建的幀。由函數 h->dctf.add16x16_idct完成。

B. 對於I_8x8模式,將宏塊分紅48x8來分別進行。先調用predict_8x8函數來計算預測值,而後調用函數x264_mb_encode_i8x8進行編碼。在該函數中,8x8DCT變換——h->dctf.sub8x8_dct8函數,量化—— x264_quant_8x8_trellisquant_8x8函數、掃描——h->zigzagf.scan_8x8函數、反量化—— h->quantf.dequant_8x8函數和反DCT變換並加到預測宏塊上——h->dctf.add8x8_idct8函數。

 

C.164x4塊分別進行。先h->predict_4x4[i_mode]進行幀內預測,獲得預測幀。而後x264_mb_encode_i4x4編碼。在x264_mb_encode_i4x4中,若是是無損壓縮h->mb.b_lossless置位。調用sub_zigzag_4x4full計算殘差,並掃描,返回。如果非無損編碼,進行DCT、量化、Z字掃描、反量化、反IDCT並加到預測幀上。分別由函數:h->dctf.sub4x4_dct x264_quant_4x4_trellisquant_4x4scan_zigzag_4x4full h->quantf.dequant_4x4h->dctf.add4x4_idct完成。

4)若是是幀間模式編碼,

A. 先調用x264_mb_mc進行運動補償。根據宏塊類型進行相應的運動補償:使用列表0h->mb.i_type == P_L0)的16x16預測模式,根據h->mb.i_partition的類型(D_16x16D_16x8D_8x16),分別調用 x264_mb_mc_0xywh函數進行前向宏塊運動補償。x264_mb_mc_0xywh分別對亮度和色度進行運動補償: h->mc.mc_lumah->mc.mc_chroma函數。若是宏塊類型(h->mb.i_type)爲P_8x8B_8x8。對48x8塊,分別調用x264_mb_mc_8x8進行運動補償。 其根據字塊類型(h->mb.i_sub_partition[i8])分別進行運動補償。D_L0_8x8D_L0_8x4D_L0_4x8 D_L0_4x4類型,調用x264_mb_mc_0xywh進行前向宏塊運動補償。D_L1_8x8D_L1_8x4D_L1_4x8 D_L1_4x4類型,調用x264_mb_mc_1xywh進行後向宏塊運動補償。D_BI_8x8D_BI_8x4D_BI_4x8 D_BI_4x4類型,分別調用x264_mb_mc_01xywh進行宏塊雙向運動補償。D_DIRECT_8x8類型,調用x264_mb_mc_direct8x8 進行直接模式8*8塊運動補償。x264_mb_mc_direct8x8函數根據不一樣的條件調用x264_mb_mc_0xywhx264_mb_mc_1xywhx264_mb_mc_01xywh函數。若是宏塊類型(h->mb.i_type)爲B_SKIPB_DIRECT。調用直接模式8*8塊運動補償函數x264_mb_mc_direct8x8。若是宏塊類型(h->mb.i_type)爲其它B幀模式。先初始化參考列表。根據子塊類型(h->mb.i_partition 爲,D_16x16D_16x8D_8x16和前向、後項、雙向參考類型,分別調用x264_mb_mc_0xywh x264_mb_mc_1xywhx264_mb_mc_01xywh函數。

B. 運動補償以後,進行編碼。若是是無損編碼(h->mb.b_lossless ==1),對164x4塊,分別進行殘差計算和z字掃描,由函數sub_zigzag_4x4full完成。若是要進行8x8子塊編碼( h->mb.b_transform_8x8),調用h->dctf.sub16x16_dct8對每一個8x8塊先計算殘差,再DCT變換。而後對48x8塊,分別調用x264_denoise_dct去噪、x264_quant_8x8_trellisquant_8x8量化、字掃描。而後是反量化、將殘差加到參考宏塊上。由h->quantf.dequant_8x8h->dctf.add8x8_idct8完成。而後對48x8塊,分別調用x264_denoise_dct去噪、x264_quant_8x8_trellisquant_8x8量化、scan_zigzag_8x8full Z字掃描。而後是反量化、將殘差加到參考宏塊上。由h->quantf.dequant_8x8h->dctf.add8x8_idct8完成。

C. 若是不進行8x8子塊編碼。先用h->dctf.sub16x16_dct先算p_src-p_dst宏塊殘差,再對每一個4x4模塊進行 dct變換。而後對164x4塊進行去噪——x264_denoise_dct、量化x264_quant_4x4_trellis quant_4x4Z字掃描——scan_zigzag_4x4full。而後是反量化——h->quantf.dequant_4x4 DCT並加到參考幀上——h->dctf.add8x8_idct

D. 亮度編碼完成後,進行色度編碼。x264_mb_encode_8x8_chroma函數。對CbCr份量分別進行。

若是時無損編碼,對44x4塊進行殘差計算、Z字掃描和DC係數計算。

非無損編碼,用h->dctf.sub8x8_dct對每一個4x4塊進行殘差計算和DCT轉換。以後對每一個4x4塊,先取2x2DC係數,量 ——quant_4x4_chromaZ字掃描——h->zigzagf.scan_4x4ac。對2x2DC係數進行DCT變換、量化和Z 掃描,分別由函數h->dctf.dct2x2dcquant_2x2_dcscan_zigzag_2x2_dc。接着是反DCT變換和反量 化,h->dctf.idct2x2dcx264_mb_dequant_2x2_dc函數。h->quantf.dequant_4x4 4x4塊反量化,h->dctf.add8x8_idct對每一個4x4塊反DCT變換而且加到色度預測幀上。

E. 亮度和色度編碼完成後。計算亮度和色度模式和非零的個數,肯定h->mb.i_cbp_chromah->mb.cbp的值。

 

 

15. x264_macroblock_encode函數-2

下面是該函數的調用狀況,在上面對這個函數的分析中,已經對其中的大部分的函數都有了一個相對比較詳細的介紹,

 

16. x264_macroblock_write_cabac函數

在宏塊編碼結束後,就要將編碼生成的內容寫到碼流中。若是支持CABAC編碼,就調用x264_macroblock_write_cabac。若是是CAVLC編碼,就調用x264_macroblock_write_cavlc

先調用函數x264_cabac_mb_type來將宏塊類型寫入碼流,而後根據宏塊的類型進行碼流的寫入操做:

A. 若是是I_PCM類型,那麼直接對亮度和色度調用函數bs_write來將數據寫入碼流,而後返回。

B. 若是是幀內類型,若是採用了8x8DCT變換而且不是I_16x16,那麼就調用x264_cabac_mb_transform_size來將變換的尺寸寫入碼流,若是是I_8x8I_4x4,須要將預測模式寫入碼流,而後是將色度預測模式寫入碼流。

C. 若是是幀間16x16, 16x8 8x16 ,則根據相應的類型,調用x264_cabac_mb_ref將參考幀寫入碼流,調用x264_cabac_mb_mvd將運動矢量差寫入碼流

D. 若是是幀間P_8x8模式,首先將每個子塊的模式寫入碼流x264_cabac_mb_sub_p_partition,而後將每個塊用到的參考幀寫入碼流x264_cabac_mb_ref,最後在函數x264_cabac_mb8x8_mvd中將每個8x8塊的mvd寫入碼流。

E. 若是是B_8x8模式,一樣寫入子塊模式x264_cabac_mb_sub_b_partition,而後先後參考幀寫入碼流x264_cabac_mb_ref,最後調用x264_cabac_mb8x8_mvdL0L1上的參考幀寫入碼流。

F. 若是是除B_DIRECT以外全部其餘模式,將參考幀和mvd寫入碼流。

 

接下來將亮度和色度CBP寫入碼流:x264_cabac_mb_cbp_lumax264_cabac_mb_cbp_chroma

而後將qp_delta寫入碼流x264_cabac_mb_qp_delta 同時根據宏塊類型將殘差係數寫入碼流block_residual_write_cabac

 

 

17.x264_macroblock_write_cavlc函數


首先,根據幀類型計算i_mb_i_offset的值。依據宏塊類型(i_mb_type)寫相應的數據到流中:

A. 若是宏塊類型是I_PCM,就把16x16個亮度值、2x8x8個色度值直接寫到碼流中。

B. 若是宏塊類型是I_4x4I_8x8,先寫入是不是8x8模式。而後對164x4塊和48x8塊,先調用 x264_mb_predict_intra4x4_mode獲取最可能的預測模式,而後比較當前的預測模式和最可能的預測模式,將判斷結果寫入碼流中, 最後寫入當前的預測模式值。

C. 若是宏塊類型是I_16x16,將當前的預測模式寫入碼流。

D. 若是宏塊類型是P_L0, 宏塊子分區分別爲D_16x16D_16x8D_8x16時,處理步驟類似,先將分區類型寫入碼流,而後預測運動向量(x264_mb_predict_mv)獲得mvp,最後寫入當前運動向量與mvp的差值(MVD)。

E. 若是宏塊類型是P_8x8B_8x8時,過程相似。先寫入類型,接着寫入4個子宏塊類型,參考幀信息,調用cavlc_mb8x8_mvd計算 mvdcavlc_mb8x8_mvd函數中根據不一樣的子分區類型(D_L0_8x8/D_L1_8x8/D_BI_8x8...)調用 cavlc_mb_mvd函數計算MVD並寫入碼流。cavlc_mb_mvd函數中也是計算mvpx264_mb_predict_mv),算mvd 並寫入碼流中。

F. 若是宏塊類型是非B_DIRECT——B幀的非直接模式,可能會雙向參考。以後根據兩個參考幀列表結合子分區類型(D_16x16D_16x8D_8x16),寫入參考幀信息,計算mvpx264_mb_predict_mv),計算mvd並寫入碼流中。

G. 若是宏塊類型是B_DIRECT,就寫個類型。

 

這樣,在運動向量差寫入完成後。寫編碼的塊模式。寫殘差數據,分亮度殘差數據和色度殘差數據。

A. 若是類型是I_16x16,先計算qp-delta並寫入碼流,寫亮度DCAC係數(block_residual_write_cavlc)。

B. 若是不是I_16x16,且亮度和色度有一個不是零(h->mb.i_cbp_luma != 0 || h->mb.i_cbp_chroma != 0)。先計算qp-delta並寫入碼流,而後調用x264_macroblock_luma_write_cavlc進行亮度宏塊編碼。

 

對於色度殘差數據的cavlc編碼,先寫入Cb,CrDC係數(block_residual_write_cavlc),後寫入AC係數(block_residual_write_cavlc)。

這樣就完成了熵編碼。

相關文章
相關標籤/搜索