首先呈現(xiàn)分析出來的FFmpeg源代碼結(jié)構(gòu)圖。這張圖的尺寸非常的大,尺寸大約有4000x4000,有點(diǎn)像一張地圖(因此最好選擇“查看更清晰的圖片”之后,右鍵保存圖片到本機(jī)之后再查看)。它表明了FFmpeg在解碼一個(gè)視頻的時(shí)候的函數(shù)調(diào)用流程。為了保證結(jié)構(gòu)清晰,其中僅列出了最關(guān)鍵的函數(shù),剔除了其它不是特別重要的函數(shù)。
下面解釋一下圖中關(guān)鍵標(biāo)記的含義。
函數(shù)在圖中以方框的形式表現(xiàn)出來。不同的背景色標(biāo)志了該函數(shù)不同的作用:
粉紅色背景函數(shù):FFmpeg的API函數(shù)。
白色背景的函數(shù):FFmpeg的內(nèi)部函數(shù)。
黃色背景的函數(shù):URLProtocol結(jié)構(gòu)體中的函數(shù),包含處理協(xié)議(Protocol)的功能。
綠色背景的函數(shù):AVInputFormat結(jié)構(gòu)體中的函數(shù),包含處理封裝格式(Format)的功能。
藍(lán)色背景的函數(shù):AVCodec結(jié)構(gòu)體中的函數(shù),包含了編解碼器(Codec)的功能。
PS:URLProtocol,AVInputFormat,AVCodec在FFmpeg開始運(yùn)行并且注冊(cè)完組件之后,都會(huì)分別被連接成一個(gè)個(gè)的鏈表。因此實(shí)際上是有很多的URLProtocol,AVInputFormat,AVCodec的。圖中畫出了解碼一個(gè)輸入?yún)f(xié)議是“文件”(其實(shí)就是打開一個(gè)文件。“文件”也被當(dāng)做是一種廣義的協(xié)議),封裝格式為FLV,視頻編碼格式是H.264的數(shù)據(jù)的函數(shù)調(diào)用關(guān)系。
整個(gè)架構(gòu)圖可以分為以下幾個(gè)區(qū)域:
左邊區(qū)域——架構(gòu)函數(shù)區(qū)域:這些函數(shù)并不針對(duì)某一特定的視頻格式。
右上方黃色區(qū)域——協(xié)議處理函數(shù)區(qū)域:不同的協(xié)議(RTP,RTMP,F(xiàn)ILE)會(huì)調(diào)用不同的協(xié)議處理函數(shù)。
右邊中間綠色區(qū)域——封裝格式處理函數(shù)區(qū)域:不同的封裝格式(MKV,F(xiàn)LV,MPEGTS,AVI)會(huì)調(diào)用不同的封裝格式處理函數(shù)。
右邊下方藍(lán)色區(qū)域——編解碼函數(shù)區(qū)域:不同的編碼標(biāo)準(zhǔn)(HEVC,H.264,MPEG2)會(huì)調(diào)用不同的編解碼函數(shù)。
為了把調(diào)用關(guān)系表示的更明顯,圖中的箭頭線也使用了不同的顏色:
黑色箭頭線:標(biāo)志了函數(shù)之間的調(diào)用關(guān)系。
紅色的箭頭線:標(biāo)志了解碼的流程。
其他顏色的箭頭線:標(biāo)志了函數(shù)之間的調(diào)用關(guān)系。其中:
調(diào)用URLProtocol結(jié)構(gòu)體中的函數(shù)用黃色箭頭線標(biāo)識(shí);
調(diào)用AVInputFormat結(jié)構(gòu)體中的函數(shù)用綠色箭頭線標(biāo)識(shí);
調(diào)用AVCodec結(jié)構(gòu)體中的函數(shù)用藍(lán)色箭頭線標(biāo)識(shí)。
每個(gè)函數(shù)旁邊標(biāo)識(shí)了它所在的文件的路徑。
此外,還有一點(diǎn)需要注意的是,一些API函數(shù)內(nèi)部也調(diào)用了另一些API函數(shù)。也就是說,API函數(shù)并不一定全部都調(diào)用FFmpeg的內(nèi)部函數(shù),他也有可能調(diào)用其他的API函數(shù)。例如從圖中可以看出來,avformat_close_input()調(diào)用了avformat_free_context()和avio_close()。這些在內(nèi)部代碼中被調(diào)用的API函數(shù)也標(biāo)記為粉紅色。
下面簡單列出幾個(gè)區(qū)域中函數(shù)之間的調(diào)用關(guān)系(函數(shù)之間的調(diào)用關(guān)系使用縮進(jìn)的方式表現(xiàn)出來)。詳細(xì)的函數(shù)分析可以參考相關(guān)的《FFmpeg源代碼分析》系列文章。
左邊區(qū)域(FFmpeg架構(gòu)函數(shù))
1. ?av_register_all()【函數(shù)簡單分析】
1) ?avcodec_register_all()
(a)?REGISTER_HWACCEL()
(b)?REGISTER_ENCODER()
(c)?REGISTER_DECODER()
(d)?REGISTER_PARSER()
(e)?REGISTER_BSF()
2) ?REGISTER_MUXER()
3) ?REGISTER_DEMUXER()
4) ?REGISTER_PROTOCOL()
2. ?avformat_alloc_context()【函數(shù)簡單分析】
1)?av_malloc(sizeof(AVFormatContext))
2)?avformat_get_context_defaults()
(a)?av_opt_set_defaults()
3. ?avformat_open_input()【函數(shù)簡單分析】
1)?init_input()
(a)?avio_open2()【函數(shù)簡單分析】
a)?ffurl_open()
i.?ffurl_alloc()
l?url_find_protocol()
l?url_alloc_for_protocol()
ii. ffurl_connect()
URLProtocol->url_open()
b)?ffio_fdopen()
i.?av_malloc(buffer_size)
ii.avio_alloc_context()
l?av_mallocz(sizeof(AVIOContext))
l?ffio_init_context()
(b)av_probe_input_buffer2()
a)avio_read()
i.AVInputFormat->read_packet()
b)av_probe_input_format2()
c)av_probe_input_format3()
i.av_iformat_next()
ii.av_match_name()
iii.av_match_ext()
iv.AVInputFormat->read_probe()
2)?AVInputFormat->read_header()
4.?avformat_find_stream_info()【函數(shù)簡單分析】
1)?find_decoder()
(a)avcodec_find_decoder()
2)avcodec_open2()
3)?read_frame_internal()
4)?try_decode_frame()
(a)avcodec_decode_video2()
5)avcodec_close()
6)?estimate_timings()
(a)??estimate_timings_from_pts()
(b)??estimate_timings_from_bit_rate()
(c)??update_stream_timings()
5.?avcodec_find_decoder()【函數(shù)簡單分析】
1)?find_encdec()
6.?avcodec_open2()【函數(shù)簡單分析】
1)AVCodec->init()
7.?av_read_frame()【函數(shù)簡單分析】
1)?read_from_packet_buffer()
2)?read_frame_internal()
(a)?ff_read_packet()
a)AVInputFormat->read_packet()
(b)?parse_packet()
a)?av_parser_parse2()
8.?avcodec_decode_video2()【函數(shù)簡單分析】
1)?av_packet_split_side_data()
2)AVCodec->?decode()
3)?av_frame_set_pkt_pos()
4)?av_frame_set_best_effort_timestamp()
9.?avcodec_close()【函數(shù)簡單分析】
1)AVCodec->close()
10.?avformat_close_input()【函數(shù)簡單分析】
1)AVInputFormat->read_close()
2)?avformat_free_context()
(a)?ff_free_stream()
3)?avio_close()
(a)?avio_flush()
a)?flush_buffer()
(b)?ffurl_close()
a)?ffurl_closep()
URLProtocol->url_close()
右上區(qū)域(URLProtocol協(xié)議處理函數(shù))
URLProtocol結(jié)構(gòu)體包含如下協(xié)議處理函數(shù)指針:
url_open():打開
url_read():讀取
url_write():寫入
url_seek():調(diào)整進(jìn)度
url_close():關(guān)閉
【例子】不同的協(xié)議對(duì)應(yīng)著上述接口有不同的實(shí)現(xiàn)函數(shù),舉幾個(gè)例子:
File協(xié)議(即文件)對(duì)應(yīng)的URLProtocol結(jié)構(gòu)體ff_file_protocol:
url_open() -> file_open() -> open()
url_read() -> file_read() -> read()
url_write() -> file_write() -> write()
url_seek() -> file_seek() -> lseek()
url_close() -> file_close() -> close()
RTMP協(xié)議(libRTMP)對(duì)應(yīng)的URLProtocol結(jié)構(gòu)體ff_librtmp_protocol:
url_open() -> rtmp_open() -> RTMP_Init(), RTMP_SetupURL(), RTMP_Connect(), RTMP_ConnectStream()
url_read() -> rtmp_read() -> RTMP_Read()
url_write() -> rtmp_write() -> RTMP_Write()
url_seek() -> rtmp_read_seek() -> RTMP_SendSeek()
url_close() -> rtmp_close() -> RTMP_Close()
UDP協(xié)議對(duì)應(yīng)的URLProtocol結(jié)構(gòu)體ff_udp_protocol:
url_open() -> udp_open()
url_read() -> udp_read()
url_write() -> udp_write()
url_seek() -> udp_close()
url_close() -> udp_close()
右中區(qū)域(AVInputFormat封裝格式處理函數(shù))
AVInputFormat包含如下封裝格式處理函數(shù)指針:
read_probe():檢查格式
read_header():讀取文件頭
read_packet():讀取一幀數(shù)據(jù)
read_seek():調(diào)整進(jìn)度
read_close():關(guān)閉
【例子】不同的封裝格式對(duì)應(yīng)著上述接口有不同的實(shí)現(xiàn)函數(shù),舉幾個(gè)例子:
FLV封裝格式對(duì)應(yīng)的AVInputFormat結(jié)構(gòu)體ff_flv_demuxer:
read_probe() -> flv_probe() –> probe()
read_header() -> flv_read_header() -> create_stream() -> avformat_new_stream()
read_packet() -> flv_read_packet()
read_seek() -> flv_read_seek()
read_close() -> flv_read_close()
MKV封裝格式對(duì)應(yīng)的AVInputFormat結(jié)構(gòu)體ff_matroska_demuxer:
read_probe() -> matroska_probe()
read_header() -> matroska_read_header()
read_packet() -> matroska_read_packet()
read_seek() -> matroska_read_seek()
read_close() -> matroska_read_close()
MPEG2TS封裝格式對(duì)應(yīng)的AVInputFormat結(jié)構(gòu)體ff_mpegts_demuxer:
read_probe() -> mpegts_probe()
read_header() -> mpegts_read_header()
read_packet() -> mpegts_read_packet()
read_close() -> mpegts_read_close()
AVI封裝格式對(duì)應(yīng)的AVInputFormat結(jié)構(gòu)體ff_avi_demuxer:
read_probe() -> avi_probe()
read_header() -> avi_read_header()
read_packet() -> avi_read_packet()
read_seek() -> avi_read_seek()
read_close() -> avi_read_close()
AVCodec包含如下編解碼函數(shù)指針:
init():初始化
decode():解碼一幀數(shù)據(jù)
close():關(guān)閉
【例子】不同的編解碼器對(duì)應(yīng)著上述接口有不同的實(shí)現(xiàn)函數(shù),舉幾個(gè)例子:
HEVC解碼對(duì)應(yīng)的AVCodec結(jié)構(gòu)體ff_hevc_decoder:
init() -> hevc_decode_init()
decode() -> hevc_decode_frame() -> decode_nal_units()
close() -> hevc_decode_free()
H.264解碼對(duì)應(yīng)的AVCodec結(jié)構(gòu)體ff_h264_decoder:
init() -> ff_h264_decode_init()
decode() -> h264_decode_frame() -> decode_nal_units()
close() -> h264_decode_end()
VP8解碼(libVPX)對(duì)應(yīng)的AVCodec結(jié)構(gòu)體ff_libvpx_vp8_decoder:
init() -> vpx_init() -> vpx_codec_dec_init()
decode() -> vp8_decode() -> vpx_codec_decode(), vpx_codec_get_frame()
close() -> vp8_free() -> vpx_codec_destroy()
MPEG2解碼對(duì)應(yīng)的AVCodec結(jié)構(gòu)體ff_mpeg2video_decoder:
init() -> mpeg_decode_init()
decode() -> mpeg_decode_frame()
close() -> mpeg_decode_end()
1、具有1-5工作經(jīng)驗(yàn)的,面對(duì)目前流行的技術(shù)不知從何下手,
需要突破技術(shù)瓶頸的可以加。
2、在公司待久了,過得很安逸,
但跳槽時(shí)面試碰壁。
需要在短時(shí)間內(nèi)進(jìn)修、跳槽拿高薪的可以加。
3、如果沒有工作經(jīng)驗(yàn),但基礎(chǔ)非常扎實(shí),對(duì)java工作機(jī)制,
常用設(shè)計(jì)思想,常用java開發(fā)框架掌握熟練的,可以加。
4、覺得自己很牛B,一般需求都能搞定。
但是所學(xué)的知識(shí)點(diǎn)沒有系統(tǒng)化,很難在技術(shù)領(lǐng)域繼續(xù)突破的可以加。
5. 群號(hào):高級(jí)架構(gòu)群 Java進(jìn)階群:180705916.備注好信息!送架構(gòu)視頻。
6.阿里Java高級(jí)大牛直播講解知識(shí)點(diǎn),分享知識(shí),
多年工作經(jīng)驗(yàn)的梳理和總結(jié),帶著大家全面、
科學(xué)地建立自己的技術(shù)體系和技術(shù)認(rèn)知!