ffplayer分析
在《Ffplay視頻播放流程》文章中我給出了一個(gè)ffplay的函數調用關(guān)系圖,在分析代碼上會(huì )有不小的幫助。那么本文就詳細的描述如何從源碼中一步步的得到我們想要的函數調用關(guān)系圖。
下載ffmpeg源碼
安裝graphviz:sudo>http://www.gson.org/egypt/
我采用的是默認配置+直接編譯的方式,即./configure &&>ffmpeg$ makeCC ffplay.oLD ffplay_gCP ffplaySTRIP ffplay
我們從上述輸出中可以看到,編譯ffplay主要有四步:編譯(CC),鏈接(LD),重命名(CP),去除符號表操作(STRIP),其中編譯階段是我們重點(diǎn)要分析的,因為編譯是對源碼的直接分析和處理。
確定了需要在編譯ffplay的步驟后,我們在makefile中找到具體的編譯函數:
define COMPILE
$(call $(1)DEP,$(1))
$($(1)) $($(1)FLAGS) $($(1)_DEPFLAGS) $($(1)_C) $($(1)_O) $<
endef
CFLAGS += $(ECFLAGS) -fdump-rtl-expand并且在COMPILE函數中將$($(1)FLAGS)的值打印出來(lái),那么再次修改ffplay.c并編譯后的輸出如下:
-I. -I./ -D_ISOC99_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -std=c99 -fomit-frame-pointer -pthread -D_GNU_SOURCE=1 -D_REENTRANT -I/usr/include/SDL -g -Wdeclaration-after-statement -Wall -Wno-parentheses -Wno-switch -Wno-format-zero-length -Wdisabled-optimization -Wpointer-arith -Wredundant-decls -Wno-pointer-sign -Wwrite-strings -Wtype-limits -Wundef -Wmissing-prototypes -Wno-pointer-to-int-cast -Wstrict-prototypes -O3 -fno-math-errno -fno-signed-zeros -fno-tree-vectorize -Werror=implicit-function-declaration -Werror=missing-prototypes -Werror=return-type -Werror=vla -fdump-rtl-expand -D_GNU_SOURCE=1 -D_REENTRANT -I/usr/include/SDL CC ffplay.o LD ffplay_g CP ffplay STRIP ffplay
生成完RTL文件后,我們可以使用現成的一個(gè)工具來(lái)分析它:egypt,具體命令如下:
egypt ffplay.c.144r.expand > ffplay.dot
有了dot文件,使用graphviz提供的工具就可以直接生成圖形了:
dot ffplay.dot -Tpng -o ffplay.png其中ffplay.dot是輸入文件,-Tpng表示生成png格式的文件,-o>
文件有點(diǎn)大,請自行保存下來(lái)進(jìn)行查看。
這個(gè)圖看上去有些奇怪,比如在main函數中非常顯眼的event_loop函數,哪里去了呢?
神奇之處就在于CFLAYGS中的-O3參數,gcc的man手冊中如是說(shuō):
因此,為了保持生成的RTL文件和源代碼保持一致性,我們去除所有的編譯優(yōu)化選項,即在config.mak文件中,從CFLAGS定義中刪除-O3字符串:

哇塞,通過(guò)這兩個(gè)圖形對比,我們發(fā)現編譯優(yōu)化選項做了多大的工作啊,或者說(shuō)原始代碼為了可閱讀行,是多么的爛??!
未優(yōu)化的函數調用關(guān)系圖太復雜了,在分析問(wèn)題時(shí),感覺(jué)有些老虎吃刺猬無(wú)處下嘴??!
那么我們就可以手動(dòng)打開(kāi)剛才處理RTL后生成的dot文件,比如去除一些孤立的點(diǎn),去除一些細節處理等等。最后,我們得到一個(gè)比較概要的函數調用關(guān)系圖。

PS:和上述圖片對應的dot文件如下:
聯(lián)系客服