1. 程式人生 > >H264編碼器4( x264原始碼簡單分析:概述)

H264編碼器4( x264原始碼簡單分析:概述)

來自:https://blog.csdn.net/leixiaohua1020/article/details/45536607

 

=====================================================

H.264原始碼分析文章列表:

【編碼 - x264】

x264原始碼簡單分析:概述

x264原始碼簡單分析:x264命令列工具(x264.exe)

x264原始碼簡單分析:編碼器主幹部分-1

x264原始碼簡單分析:編碼器主幹部分-2

x264原始碼簡單分析:x264_slice_write()

x264原始碼簡單分析:濾波(Filter)部分

x264原始碼簡單分析:巨集塊分析(Analysis)部分-幀內巨集塊(Intra)

x264原始碼簡單分析:巨集塊分析(Analysis)部分-幀間巨集塊(Inter)

x264原始碼簡單分析:巨集塊編碼(Encode)部分

x264原始碼簡單分析:熵編碼(Entropy Encoding)部分

FFmpeg與libx264介面原始碼簡單分析

【解碼 - libavcodec H.264 解碼器】

FFmpeg的H.264解碼器原始碼簡單分析:概述

FFmpeg的H.264解碼器原始碼簡單分析:解析器(Parser)部分

FFmpeg的H.264解碼器原始碼簡單分析:解碼器主幹部分

FFmpeg的H.264解碼器原始碼簡單分析:熵解碼(EntropyDecoding)部分

FFmpeg的H.264解碼器原始碼簡單分析:巨集塊解碼(Decode)部分-幀內巨集塊(Intra)

FFmpeg的H.264解碼器原始碼簡單分析:巨集塊解碼(Decode)部分-幀間巨集塊(Inter)

FFmpeg的H.264解碼器原始碼簡單分析:環路濾波(Loop Filter)部分

=====================================================


最近正在研究H.264和HEVC的編碼方式,因此分析了一下最常見的H.264編碼器——x264的原始碼。本文簡單梳理一下它的結構。X264的原始碼量比較大而且涉及到很多的演算法,目前還有很多不懂的地方,因此也不能保證分析的完全正確。目前打算先把已經理解的部分整理出來以作備忘。

函式呼叫關係圖
X264的函式呼叫關係圖如下所示。

單擊檢視更清晰的大圖

下面解釋一下圖中關鍵標記的含義。

函式背景色
函式在圖中以方框的形式表現出來。不同的背景色標誌了該函式不同的作用:
白色背景的函式:不加區分的普通內部函式。
淺紅背景的函式:libx264類庫的介面函式(API)。
粉紅色背景函式:濾波函式(Filter)。用於環路濾波,半畫素插值,SSIM/PSNR的計算。
黃色背景函式:分析函式(Analysis)。用於幀內預測模式的判斷,或者幀間預測模式的判斷。
綠色背景的函式:巨集塊編碼函式(Encode)。通過對殘差的DCT變換、量化等方式對巨集塊進行編碼。
紫色背景的函式:熵編碼函式(Entropy Coding)。對巨集塊編碼後的資料進行CABAC或者CAVLC熵編碼。
藍色背景函式:彙編函式(Assembly)。做過彙編優化的函式。圖中主要畫出了這些函式的C語言版本,此外這些函式還包含MMX版本、SSE版本、NEON版本等。
淺藍色背景函式:位元速率控制函式(Rate Control)。對位元速率進行控制的函式。具體的方法包括了ABR、CBR、CRF等。

區域
整個關係圖可以分為以下幾個區域:
最左邊區域——x264命令列程式函式區域。
左邊中間區域——libx264內部函式區域。
右上方粉紅色區域——濾波模組。其中包括了環路濾波,半畫素插值,SSIM/PSNR計算。
右上方黃色區域——分析模組。其中包含了幀內預測模式分析以及幀間運動估計等。
右中間綠色區域——巨集塊編碼模組。其中包含了針對編碼幀的DCT變換,量化,Hadamard變換等;以及針對重建幀的DCT反變換,反量化,Hadamard反變換等。
右下方紫色區域——熵編碼模組。其中包含了CABAC或者CAVLC熵編碼。

箭頭線
箭頭線標誌了函式的呼叫關係:

黑色箭頭線:不加區別的呼叫關係。
粉紅色的箭頭線:濾波函式(Filter)之間的呼叫關係。
黃色箭頭線:分析函式(Analysis)之間的呼叫關係。
綠色箭頭線:巨集塊編碼函式(Encode)之間的呼叫關係。
紫色箭頭線:熵編碼函式(Entropy Coding)之間的呼叫關係。
 
函式所在的檔案
每個函式標識了它所在的檔案路徑。


幾個關鍵的部分
下文簡單記錄圖中幾個關鍵的部分。

x264命令列程式
x264命令列程式指的是x264專案提供的控制檯程式。通過這個程式可以呼叫libx264編碼YUV為H.264碼流。該程式的入口函式為main()。main()函式首先呼叫parse()解析輸入的引數,然後呼叫encode()編碼YUV資料。
parse()首先呼叫x264_param_default()為儲存引數的x264_param_t結構體賦預設值;然後在一個大迴圈中通過getopt_long()解析通過命令列傳遞來的儲存在argv[]中的引數,並作相應的設定工作;最後呼叫select_input()和select_output()完成輸入檔案格式(yuv,y4m等)和輸出檔案格式(裸流,mp4,mkv,FLV等)的設定。
encode()首先呼叫x264_encoder_open()開啟編碼器;接著在一個迴圈中反覆呼叫encode_frame()一幀一幀地進行編碼;最後在編碼完成後呼叫x264_encoder_close()關閉編碼器。
encode_frame()則呼叫x264_encoder_encode()將儲存YUV資料的x264_picture_t編碼為儲存H.264資料的x264_nal_t。

libx264類庫的介面
在一個x264編碼流程中,至少需要呼叫如下API函式(參考文章《最簡單的視訊編碼器:基於libx264(編碼YUV為H.264)》):
x264_param_default():設定引數集結構體x264_param_t的預設值。
x264_picture_alloc():為影象結構體x264_picture_t分配記憶體。
x264_encoder_open():開啟編碼器。
x264_encoder_encode():編碼一幀影象。
x264_encoder_close():關閉編碼器。
x264_picture_clean():釋放x264_picture_alloc()申請的資源。

libx264主幹函式
libx264主幹函式指的是編碼API之後,x264_slice_write()之前的函式。這一部分函式較多,暫時不詳細分析,僅僅舉幾個例子列一下它們的功能。
x264_encoder_open()呼叫了下面的函式:
x264_validate_parameters():檢查輸入引數(例如輸入影象的寬高是否為正數)。
x264_predict_16x16_init():初始化Intra16x16幀內預測彙編函式。
x264_predict_4x4_init():初始化Intra4x4幀內預測彙編函式。
x264_pixel_init():初始化畫素值計算相關的彙編函式(包括SAD、SATD、SSD等)。
x264_dct_init():初始化DCT變換和DCT反變換相關的彙編函式。
x264_mc_init():初始化運動補償相關的彙編函式。
x264_quant_init():初始化量化和反量化相關的彙編函式。
x264_deblock_init():初始化去塊效應濾波器相關的彙編函式。
x264_lookahead_init():初始化Lookahead相關的變數。
x264_ratecontrol_new():初始化位元速率控制模組。

x264_encoder_headers()呼叫了下面的函式:
x264_sps_write():輸出SPS
x264_pps_write():輸出PPS
x264_sei_version_write():輸出SEI

x264_encoder_encode()呼叫了下面的函式:
x264_frame_pop_unused():獲取1個x264_frame_t型別結構體fenc。如果frames.unused[]佇列不為空,就呼叫x264_frame_pop()從unused[]佇列取1個現成的;否則就呼叫x264_frame_new()建立一個新的。
x264_frame_copy_picture():將輸入的影象資料拷貝至fenc。
x264_lookahead_put_frame():將fenc放入lookahead.next.list[]佇列,等待確定幀型別。
x264_lookahead_get_frames():通過lookahead分析幀型別。該函式呼叫了x264_slicetype_decide(),x264_slicetype_analyse()和x264_slicetype_frame_cost()等函式。經過一些列分析之後,最終確定了幀型別資訊,並且將幀放入frames.current[]佇列。
x264_frame_shift():從frames.current[]佇列取出一幀用於編碼。
x264_reference_update():更新參考幀列表。
x264_reference_reset():如果為IDR幀,呼叫該函式清空參考幀列表。
x264_reference_hierarchy_reset():如果是I(非IDR幀)、P幀、B幀(可做為參考幀),呼叫該函式(還沒研究)。
x264_reference_build_list():建立參考幀列表list0和list1。
x264_ratecontrol_start():開啟位元速率控制。
x264_slice_init():建立 Slice Header。
x264_slices_write():編碼資料(最關鍵的步驟)。其中呼叫了x264_slice_write()完成了編碼的工作(注意“x264_slices_write()”和“x264_slice_write()”名字差了一個“s”)。
x264_encoder_frame_end():編碼結束後做一些後續處理,例如釋放一些中間變數以及列印輸出一些統計資訊。其中呼叫了x264_frame_push_unused()將fenc重新放回frames.unused[]佇列,並且呼叫x264_ratecontrol_end()關閉位元速率控制。

x264_slice_write()
x264_slice_write()用於編碼Slice。該函式中包含了一個很長的for()迴圈。該迴圈每執行一遍編碼一個巨集塊。x264_slice_write()中以下幾個函式比較重要:
x264_nal_start():開始寫一個NALU。
x264_macroblock_thread_init():初始化儲存巨集塊的重建資料快取fdec_buf[]和編碼資料快取fenc_buf[]。
x264_slice_header_write():輸出 Slice Header。
x264_fdec_filter_row():濾波模組。該模組包含了環路濾波,半畫素插值,SSIM/PSNR的計算。
x264_macroblock_cache_load():將要編碼的巨集塊的周圍的巨集塊的資訊讀進來。
x264_macroblock_analyse():分析模組。該模組包含了幀內預測模式分析以及幀間運動估計等。
x264_macroblock_encode():巨集塊編碼模組。該模組通過對殘差的DCT變換、量化等方式對巨集塊進行編碼。
x264_macroblock_write_cabac():CABAC熵編碼模組。
x264_macroblock_write_cavlc():CAVLC熵編碼模組。
x264_macroblock_cache_save():儲存當前巨集塊的資訊。
x264_ratecontrol_mb():位元速率控制。
x264_nal_end():結束寫一個NALU。

濾波模組
濾波模組對應的函式是x264_fdec_filter_row()。該函式完成了環路濾波,半畫素插值,SSIM/PSNR的計算的功能。該函式呼叫了以下及個比較重要的函式:
x264_frame_deblock_row():去塊效應濾波器。
x264_frame_filter():半畫素插值。
x264_pixel_ssd_wxh():PSNR計算。
x264_pixel_ssim_wxh():SSIM計算。

分析模組
分析模組對應的函式是x264_macroblock_analyse()。該函式包含了幀內預測模式分析以及幀間運動估計等。該函式呼叫了以下比較重要的函式(只列舉了幾個有代表性的函式):
x264_mb_analyse_init():Analysis模組初始化。
x264_mb_analyse_intra():I巨集塊幀內預測模式分析。
x264_macroblock_probe_pskip():分析是否是skip模式。
x264_mb_analyse_inter_p16x16():P16x16巨集塊幀間預測模式分析。
x264_mb_analyse_inter_p8x8():P8x8巨集塊幀間預測模式分析。
x264_mb_analyse_inter_p16x8():P16x8巨集塊幀間預測模式分析。
x264_mb_analyse_inter_b16x16():B16x16巨集塊幀間預測模式分析。
x264_mb_analyse_inter_b8x8():B8x8巨集塊幀間預測模式分析。
x264_mb_analyse_inter_b16x8():B16x8巨集塊幀間預測模式分析。

巨集塊編碼模組
巨集塊編碼模組對應的函式是x264_macroblock_encode()。該模組通過對殘差的DCT變換、量化等方式對巨集塊進行編碼。對於Intra16x16巨集塊,呼叫x264_mb_encode_i16x16()進行編碼,對於Intra4x4,呼叫x264_mb_encode_i4x4()進行編碼。對於Inter型別的巨集塊則直接在函式體裡面編碼。

熵編碼模組
CABAC熵編碼對應的函式是x264_macroblock_write_cabac()。CAVLC熵編碼對應的函式是x264_macroblock_write_cavlc()。x264_macroblock_write_cavlc()呼叫了以下幾個比較重要的函式:
x264_cavlc_mb_header_i():寫入I巨集塊MB Header資料。包含幀內預測模式等。
x264_cavlc_mb_header_p():寫入P巨集塊MB Header資料。包含MVD、參考幀序號等。
x264_cavlc_mb_header_b():寫入B巨集塊MB Header資料。包含MVD、參考幀序號等。
x264_cavlc_qp_delta():寫入QP。
x264_cavlc_block_residual():寫入殘差資料。

位元速率控制模組
位元速率控制模組函式分佈在x264原始碼不同的地方,包含了以下幾個比較重要的函式:
x264_encoder_open()中的x264_ratecontrol_new():建立位元速率控制。
x264_encoder_encode()中的x264_ratecontrol_start():開始位元速率控制。
x264_slice_write()中的x264_ratecontrol_mb():位元速率控制演算法。
x264_encoder_encode()中的x264_ratecontrol_end():結束位元速率控制。
x264_encoder_close()中的x264_ratecontrol_summary():位元速率控制資訊。
x264_encoder_close()中的x264_ratecontrol_delete():釋放位元速率控制。


至此x264的原始碼概述就基本完成了,後續幾篇文章詳細記錄其內部的原始碼。

雷霄驊
[email protected]
http://blog.csdn.net/leixiaohua1020
--------------------- 
作者:雷霄驊 
來源:CSDN 
原文:https://blog.csdn.net/leixiaohua1020/article/details/45536607 
版權宣告:本文為博主原創文章,轉載請附上博文連結!