FFmpeg的H.264解碼器原始碼簡單分析:概述
=====================================================
H.264原始碼分析文章列表:
【編碼 - x264】
【解碼 - libavcodec H.264 解碼器】
=====================================================
本文簡單記錄FFmpeg中libavcodec的H.264解碼器(H.264 Decoder)的原始碼。這個H.264解碼器十分重要,可以說FFmpeg專案今天可以幾乎“壟斷”視音訊編解碼技術,很大一部分貢獻就來自於這個H.264解碼器。這個H.264解碼器一方面功能強大,效能穩定;另一方面原始碼也比較複雜,難以深入研究。本文打算梳理一下這個H.264解碼器的原始碼結構,以方便以後深入學習H.264使用。
函式呼叫關係圖
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_parserff_h264_parser是用於解析H.264碼流的AVCodecParser結構體。AVCodecParser中包含了幾個重要的函式指標:
parser_init():初始化解析器。在ff_h264_parser結構體中,上述幾個函式指標分別指向下面幾個實現函式:
parser_parse():解析。
parser_close():關閉解析器。
init():初始化H.264解析器。ff_h264_decoder
h264_parse():解析H.264碼流。
close():關閉H.264解析器。
ff_h264_decoder是用於解碼H.264碼流的AVCodec結構體。AVCodec中包含了幾個重要的函式指標:
init():初始化解碼器。在ff_h264_decoder結構體中,上述幾個函式指標分別指向下面幾個實現函式:
decode():解碼。
close():關閉解碼器。
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_h264_decoder中h264_decode_frame()逐層呼叫的和解碼Slice相關的函式:
ff_h264qpel_init():初始化四分之一畫素運動補償相關的函式。
ff_h264_pred_init():初始化幀內預測相關的函式。
ff_h264_decode_extradata():解析AVCodecContext中的extradata。
decode_nal_units(),ff_h264_execute_decode_slices(),decode_slice()等。ff_h264_decoder中h264_decode_end()呼叫的清理函式:
ff_h264_remove_all_refs():移除所有參考幀。ff_h264_parser中h264_parse()逐層呼叫的和解析Slice相關的函式:
ff_h264_free_context():釋放在初始化H.264解碼器的時候分配的記憶體。
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%。
雷霄驊
[email protected]
http://blog.csdn.net/leixiaohua1020
相關推薦
FFmpeg的H.264解碼器原始碼簡單分析:概述
=====================================================H.264原始碼分析文章列表:【編碼 - x264】【解碼 - libavcodec H.264 解碼器】================================
FFmpeg的H.264解碼器原始碼簡單分析:解碼器主幹部分
=====================================================H.264原始碼分析文章列表:【編碼 - x264】【解碼 - libavcodec H.264 解碼器】================================
FFmpeg的H.264解碼器原始碼簡單分析:熵解碼(Entropy Decoding)部分
=====================================================H.264原始碼分析文章列表:【編碼 - x264】【解碼 - libavcodec H.264 解碼器】================================
FFmpeg的HEVC解碼器原始碼簡單分析:CTU解碼(CTU Decode)部分-TU
=====================================================HEVC原始碼分析文章列表:【解碼 -libavcodec HEVC 解碼器】==============================================
H264編碼器4( x264原始碼簡單分析:概述)
來自:https://blog.csdn.net/leixiaohua1020/article/details/45536607 ===================================================== H.264原始碼分析文章列表:
H264編碼器5( x264原始碼簡單分析:x264_slice_write() 與H264 編碼簡介)
x264原始碼簡單分析:x264_slice_write() 來自:https://blog.csdn.net/leixiaohua1020/article/details/45536607 H264 編碼簡介 https://blo
Netty中LineBasedFrameDecoder解碼器使用與分析:解決TCP粘包問題
ring public xpl cep ctx new 綁定端口 註意 相關 [toc] Netty中LineBasedFrameDecoder解碼器使用與分析:解決TCP粘包問題 上一篇文章《Netty中TCP粘包問題代碼示例與分析》演示了使用了時間服務器的例子演示了T
ffmpeg 原始碼簡單分析 : av_read_frame()
此前寫了好幾篇ffmpeg原始碼分析文章,列表如下: ============================ ffmpeg中的av_read_frame()的作用是讀取碼流中的音訊若干幀或者視訊一幀。例如,解碼視訊的時
ffmpeg 原始碼簡單分析 : av_register_all()
此前寫了好幾篇ffmpeg原始碼分析文章,列表如下: ============================ 前一陣子看了一下ffmpeg的原始碼,並且做了一些註釋,在此貼出來以作備忘。 本文分析一下ffmpeg註冊
FFmpeg原始碼簡單分析:makefile
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】================================
FFmpeg原始碼簡單分析:結構體成員管理系統-AVClass
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】================================
FFmpeg原始碼簡單分析:avcodec_open2()
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】================================
FFmpeg原始碼簡單分析:avformat_close_input()
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】================================
FFmpeg原始碼簡單分析:av_write_frame()
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】================================
FFmpeg原始碼簡單分析:常見結構體的初始化和銷燬(AVFormatContext,AVFrame等)
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】================================
FFmpeg原始碼簡單分析:記憶體的分配和釋放(av_malloc()、av_free()等)
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】================================
FFmpeg原始碼簡單分析:avcodec_encode_video()
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】================================
FFmpeg原始碼簡單分析:configure
=====================================================FFmpeg的庫函式原始碼分析文章列表:【架構圖】【通用】【解碼】【編碼】【其它】【指令碼】【H.264】================================
live555 原始碼簡單分析1:主程式
live555是使用十分廣泛的開源流媒體伺服器,之前也看過其他人寫的live555的學習筆記,在這裡自己簡單總結下。 live555原始碼有以下幾個明顯的特點: 1.標頭檔案是.hh字尾的,但沒覺得和.h字尾的有什麼不同 2.採用了面向物件的程式設計思路,裡面各種物件 好
FFmpeg源代碼簡單分析:常見結構體的初始化和銷毀(AVFormatContext,AVFrame等)
new init _array border 代碼 alloc ecc .com VC 結構體 初始化 銷毀 AVFormatContext avformat_alloc_context() avfo