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

來源:互聯網
上載者:User

FFmpeg的H.264解碼器原始碼簡單分析:概述,ffmpegh.264
本文簡單記錄FFmpeg中libavcodec的H.264解碼器(H.264 Decoder)的原始碼。這個H.264解碼器十分重要,可以說FFmpeg項目今天可以幾乎“壟斷”視音頻編解碼技術,很大一部分貢獻就來自於這個H.264解碼器。這個H.264解碼器一方面功能強大,效能穩定;另一方面原始碼也比較複雜,難以深入研究。本文打算梳理一下這個H.264解碼器的原始碼結構,以方便以後深入學習H.264使用。
PS:這部分代碼挺複雜的,還有不少地方還比較模糊,還需要慢慢學習......

函數呼叫歷程圖

H.264解碼器的函數呼叫歷程圖如下所示。


單擊查看更清晰的大圖

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


作為介面的結構體FFmpeg和H.264解碼器之間作為介面的結構體有2個:
ff_h264_parser:用於解析H.264碼流的AVCodecParser結構體。
ff_h264_decoder:用於解碼H.264碼流的AVCodec結構體。

函數背景色函數在圖中以方框的形式表現出來。不同的背景色標誌了該函數不同的作用:
白色背景的函數:普通內建函式。
粉紅色背景函數:解析函數(Parser)。這些函數用於解析SPS、PPS等資訊。
紫色背景的函數:熵解碼函數(Entropy Decoding)。這些函數讀取碼流資料並且進行CABAC或者CAVLC熵解碼。
綠色背景的函數:解碼函數(Decode)。這些函數通過幀內預測、幀間預測、DCT反變換等方法解碼壓縮資料。
黃色背景的函數:環路濾波函數(Loop Filter)。這些函數對解碼後的資料進行濾波,去除方塊效應。
藍色背景函數:彙編函數(Assembly)。這些函數是做過彙編最佳化的函數。圖中主要畫出了這些函數的C語言版本,此外這些函數還包含MMX版本、SSE版本、NEON版本等。

箭頭線箭頭線標誌了函數的調用關係:
黑色箭頭線:不加區別的調用關係。
粉紅色的箭頭線:解析函數(Parser)之間的調用關係。
紫色箭頭線:熵解碼函數(Entropy Decoding)之間的調用關係。
綠色箭頭線:解碼函數(Decode)之間的調用關係。
黃色箭頭線:環路濾波函數(Loop Filter)之間的調用關係。
 
函數所在的檔案

每個函數標識了它所在的檔案路徑。


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



FFmpeg和H.264解碼器之間作為介面的結構體

FFmpeg和H.264解碼器之間作為介面的結構體有2個:ff_h264_parser和ff_h264_decoder。

ff_h264_parser
ff_h264_parser是用於解析H.264碼流的AVCodecParser結構體。AVCodecParser中包含了幾個重要的函數指標:
parser_init():初始化解析器。
parser_parse():解析。
parser_close():關閉解析器。
在ff_h264_parser結構體中,上述幾個函數指標分別指向下面幾個實現函數:
init():初始化H.264解析器。
h264_parse():解析H.264碼流。
close():關閉H.264解析器。
ff_h264_decoder
ff_h264_decoder是用於解碼H.264碼流的AVCodec結構體。AVCodec中包含了幾個重要的函數指標:
init():初始化解碼器。
decode():解碼。
close():關閉解碼器。
在ff_h264_decoder結構體中,上述幾個函數指標分別指向下面幾個實現函數:
ff_h264_decode_init():初始化H.264解碼器。
h264_decode_frame():解碼H.264碼流。
h264_decode_end():關閉H.264解碼器。

普通內建函式普通內建函式指的是H.264解碼器中還沒有進行分類的函數。下面舉幾個例子。
ff_h264_decoder中ff_h264_decode_init()調用的初始化函數:
ff_h264dsp_init():初始化DSP相關的函數。包含了IDCT、環路濾波函數等。
ff_h264qpel_init():初始化四分之一像素運動補償相關的函數。
ff_h264_pred_init():初始化幀內預測相關的函數。
ff_h264_decode_extradata():解析AVCodecContext中的extradata。
ff_h264_decoder中h264_decode_frame()逐層調用的和解碼Slice相關的函數:
decode_nal_units(),ff_h264_execute_decode_slices(),decode_slice()等。
ff_h264_decoder中h264_decode_end()調用的清理函數:
ff_h264_remove_all_refs():移除所有參考幀。
ff_h264_free_context():釋放在初始化H.264解碼器的時候分配的記憶體。
ff_h264_parser中h264_parse()逐層調用的和解析Slice相關的函數:
h264_find_frame_end():尋找NALU的結尾。
parse_nal_units():解析一個NALU。

解析函數(Parser)解析函數(Parser)用於解析H.264碼流中的一些資訊(例如SPS、PPS、Slice Header等)。在parse_nal_units()和decode_nal_units()中都調用這些解析函數完成瞭解析。下面舉幾個解析函數的例子。
ff_h264_decode_nal():解析NALU。這個函數是後幾個解析函數的前提。
ff_h264_decode_slice_header():解析Slice Header。
ff_h264_decode_sei():解析SEI。
ff_h264_decode_seq_parameter_set():解析SPS。
ff_h264_decode_picture_parameter_set():解析PPS。

熵解碼函數(Entropy Decoding)熵解碼函數(Entropy Decoding)讀取碼流資料並且進行CABAC或者CAVLC熵解碼。CABAC解碼函數是ff_h264_decode_mb_cabac(),CAVLC解碼函數是ff_h264_decode_mb_cavlc()。熵解碼函數中包含了很多的讀取指數哥倫布編碼資料的函數,例如get_ue_golomb_long(),get_ue_golomb(),get_se_golomb(),get_ue_golomb_31()等等。
在擷取殘差資料的時候需要進行CAVLC/CABAC解碼。例如解碼CAVLC的時候,會調用decode_residual()函數,而decode_residual()會調用get_vlc2()函數,get_vlc2()會調用OPEN_READER(),UPDATE_CACHE(),GET_VLC(),CLOSE_READER()幾個函數讀取CAVLC格式的資料。
此外,在擷取運動向量的時候,會調用pred_motion()以及類似的幾個函數擷取運動向量相關的資訊。

解碼函數(Decode)解碼函數(Decode)通過幀內預測、幀間預測、DCT反變換等方法解碼壓縮資料。解碼函數是ff_h264_hl_decode_mb()。其中跟宏塊類型的不同,會調用幾個不同的函數,最常見的就是調用hl_decode_mb_simple_8()。
hl_decode_mb_simple_8()的定義是無法在原始碼中直接找到的,這是因為它實際代碼的函數名稱是使用宏的方式寫的(以後再具體分析)。hl_decode_mb_simple_8()的原始碼實際上就是FUNC(hl_decode_mb)()函數的原始碼。
FUNC(hl_decode_mb)()根據宏塊類型的不同作不同的處理:如果宏塊類型是INTRA,就會調用hl_decode_mb_predict_luma()進行幀內預測;如果宏塊類型不是INTRA,就會調用FUNC(hl_motion_422)()或者FUNC(hl_motion_420)()進行四分之一像素運動補償。
隨後FUNC(hl_decode_mb)()會調用hl_decode_mb_idct_luma()等幾個函數對資料進行DCT反變換工作。

環路濾波函數(Loop Filter)環路濾波函數(Loop Filter)對解碼後的資料進行濾波,去除方塊效應。環路濾波函數是loop_filter()。其中調用了ff_h264_filter_mb()和ff_h264_filter_mb_fast()。ff_h264_filter_mb_fast()中又調用了h264_filter_mb_fast_internal()。而h264_filter_mb_fast_internal()中又調用了下面幾個函數進行濾波:
filter_mb_edgeh():亮度水平濾波
filter_mb_edgev():亮度垂直濾波
filter_mb_edgech():色度水平濾波

filter_mb_edgecv():色度垂直濾波


彙編函數(Assembly)彙編函數(Assembly)是做過彙編最佳化的函數。為了提高效率,整個H.264解碼器中(主要在解碼部分和環路濾波部分)包含了大量的彙編函數。實際解碼的過程中,FFmpeg會根據系統的特性調用相應的彙編函數(而不是C語言函數)以提高解碼的效率。如果系統不支援彙編最佳化的話,FFmpeg才會調用C語言版本的函數。例如在幀內預測的時候,對於16x16亮度DC模式,有以下幾個版本的函數:
C語言版本的pred16x16_dc_8_c()
NEON版本的ff_pred16x16_dc_neon()
MMXEXT版本的ff_pred16x16_dc_8_mmxext()
SSE2版本的ff_pred16x16_dc_8_sse2()


附錄

在網上找到一張圖(出處不詳),分析了FFmpeg的H.264解碼器每個函數啟動並執行耗時情況,比較有參考意義,在這裡附上。


單擊查看更清晰的圖片


可以看出,熵解碼、宏塊解碼、環路濾波耗時比例分別為:23.64%、51.85%、22.22%。



至此FFmpeg的H.264解碼器的結構就大致梳理完畢了。




雷霄驊
leixiaohua1020@126.com
http://blog.csdn.net/leixiaohua1020




相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.