FFmpeg源代碼結構圖 - 解碼
版權聲明:本文為博主原創文章,未經博主允許不得轉載。
目錄(?)[+]
=====================================================
FFmpeg的庫函數源代碼分析文章列表:
【架構圖】
FFmpeg源代碼結構圖 - 解碼
FFmpeg源代碼結構圖 - 編碼
【通用】
FFmpeg 源代碼簡單分析:av_register_all()
FFmpeg 源代碼簡單分析:avcodec_register_all()
FFmpeg 源代碼簡單分析:內存的分配和釋放(av_malloc()、av_free()等)
FFmpeg 源代碼簡單分析:常見結構體的初始化和銷毀(AVFormatContext,AVFrame等)
FFmpeg 源代碼簡單分析:avio_open2()
FFmpeg 源代碼簡單分析:av_find_decoder()和av_find_encoder()
FFmpeg 源代碼簡單分析:avcodec_open2()
FFmpeg 源代碼簡單分析:avcodec_close()
【解碼】
圖解FFMPEG打開媒體的函數avformat_open_input
FFmpeg 源代碼簡單分析:avformat_open_input()
FFmpeg 源代碼簡單分析:avformat_find_stream_info()
FFmpeg 源代碼簡單分析:av_read_frame()
FFmpeg 源代碼簡單分析:avcodec_decode_video2()
FFmpeg 源代碼簡單分析:avformat_close_input()
【編碼】
FFmpeg 源代碼簡單分析:avformat_alloc_output_context2()
FFmpeg 源代碼簡單分析:avformat_write_header()
FFmpeg 源代碼簡單分析:avcodec_encode_video()
FFmpeg 源代碼簡單分析:av_write_frame()
FFmpeg 源代碼簡單分析:av_write_trailer()
【其它】
FFmpeg源代碼簡單分析:日誌輸出系統(av_log()等)
FFmpeg源代碼簡單分析:結構體成員管理系統-AVClass
FFmpeg源代碼簡單分析:結構體成員管理系統-AVOption
FFmpeg源代碼簡單分析:libswscale的sws_getContext()
FFmpeg源代碼簡單分析:libswscale的sws_scale()
FFmpeg源代碼簡單分析:libavdevice的avdevice_register_all()
FFmpeg源代碼簡單分析:libavdevice的gdigrab
【腳本】
FFmpeg源代碼簡單分析:makefile
FFmpeg源代碼簡單分析:configure
【H.264】
FFmpeg的H.264解碼器源代碼簡單分析:概述
=====================================================
近期研究了一下FFmpeg的內部的源代碼。之前對於FFmpeg的研究主要在它的應用層面上,因此制作的很多示例程序都是調用的FFmpeg的API。但是一直感覺這樣對FFmpeg的理解還是比較淺,所以打算剖析一下它的源代碼,理一下它內部結構的“脈絡”。但是有一個很難辦的問題:FFmpeg自帶的三個工程:ffplay, ffmpeg, ffprobe的代碼量非常的大,其中包含了成百上千的API;而這些API背後又包含了大量的FFmpeg內部函數。如此一來,幾乎是不可能理清他們之間的關系的。經過一番思考之後,打算選擇FFmpeg編碼和解碼過程中的最核心的API進行分析。在編碼或者解碼的過程中,核心的API數量不多,一共大約10個左右,這樣一來就可以剖析其內部的源代碼了。
- FFmpeg解碼過程核心的API可以參考:《最簡單的基於FFmpeg+SDL的視頻播放器》
- 編碼過程核心的API可以參考:《最簡單的基於FFmpeg的視頻編碼器》
FFmpeg源代碼結構圖-解碼
首先呈現分析出來的FFmpeg源代碼結構圖。這張圖的尺寸非常的大,尺寸大約有4000x4000,有點像一張地圖(因此最好選擇“查看更清晰的圖片”之後,右鍵保存圖片到本機之後再查看)。它表明了FFmpeg在解碼一個視頻的時候的函數調用流程。為了保證結構清晰,其中僅列出了最關鍵的函數,剔除了其它不是特別重要的函數。
單擊查看更清晰的圖片
下面解釋一下圖中關鍵標記的含義。
函數背景色
函數在圖中以方框的形式表現出來。不同的背景色標誌了該函數不同的作用:
- 粉紅色背景函數:FFmpeg的API函數。
- 白色背景的函數:FFmpeg的內部函數。
- 黃色背景的函數:URLProtocol結構體中的函數,包含處理協議(Protocol)的功能。
- 綠色背景的函數:AVInputFormat結構體中的函數,包含處理封裝格式(Format)的功能。
- 藍色背景的函數:AVCodec結構體中的函數,包含了編解碼器(Codec)的功能。
PS:URLProtocol,AVInputFormat,AVCodec在FFmpeg開始運行並且註冊完組件之後,都會分別被連接成一個個的鏈表。因此實際上是有很多的URLProtocol,AVInputFormat,AVCodec的。圖中畫出了解碼一個輸入協議是“文件”(其實就是打開一個文件。“文件”也被當做是一種廣義的協議),封裝格式為FLV,視頻編碼格式是H.264的數據的函數調用關系。
區域
整個架構圖可以分為以下幾個區域:
- 左邊區域——架構函數區域:這些函數並不針對某一特定的視頻格式。
- 右上方黃色區域——協議處理函數區域:不同的協議(RTP,RTMP,FILE)會調用不同的協議處理函數。
- 右邊中間綠色區域——封裝格式處理函數區域:不同的封裝格式(MKV,FLV,MPEGTS,AVI)會調用不同的封裝格式處理函數。
- 右邊下方藍色區域——編解碼函數區域:不同的編碼標準(HEVC,H.264,MPEG2)會調用不同的編解碼函數。
箭頭線
為了把調用關系表示的更明顯,圖中的箭頭線也使用了不同的顏色:
黑色箭頭線:標誌了函數之間的調用關系。
紅色的箭頭線:標誌了解碼的流程。
其他顏色的箭頭線:標誌了函數之間的調用關系。其中:
調用URLProtocol結構體中的函數用黃色箭頭線標識;
調用AVInputFormat結構體中的函數用綠色箭頭線標識;
調用AVCodec結構體中的函數用藍色箭頭線標識。
函數所在的文件
每個函數旁邊標識了它所在的文件的路徑。
此外,還有一點需要註意的是,一些API函數內部也調用了另一些API函數。也就是說,API函數並不一定全部都調用FFmpeg的內部函數,他也有可能調用其他的API函數。例如從圖中可以看出來,avformat_close_input()調用了avformat_free_context()和avio_close()。這些在內部代碼中被調用的API函數也標記為粉紅色。
函數調用關系
下面簡單列出幾個區域中函數之間的調用關系(函數之間的調用關系使用縮進的方式表現出來)。詳細的函數分析可以參考相關的《FFmpeg源代碼分析》系列文章。
左邊區域(FFmpeg架構函數)
1. av_register_all()【函數簡單分析】
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()【函數簡單分析】
1) av_malloc(sizeof(AVFormatContext))
2) avformat_get_context_defaults()
(a) av_opt_set_defaults()
3. avformat_open_input()【函數簡單分析】
1) init_input()
(a) avio_open2()【函數簡單分析】
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()【函數簡單分析】
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()【函數簡單分析】
1) find_encdec()
6. avcodec_open2()【函數簡單分析】
1) AVCodec->init()
7. av_read_frame()【函數簡單分析】
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()【函數簡單分析】
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()【函數簡單分析】
1) AVCodec->close()
10. avformat_close_input()【函數簡單分析】
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()
右上區域(URLProtocol協議處理函數)
URLProtocol結構體包含如下協議處理函數指針:
url_open():打開
url_read():讀取
url_write():寫入
url_seek():調整進度
url_close():關閉
【例子】不同的協議對應著上述接口有不同的實現函數,舉幾個例子:
File協議(即文件)對應的URLProtocol結構體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協議(libRTMP)對應的URLProtocol結構體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協議對應的URLProtocol結構體ff_udp_protocol:
url_open() -> udp_open()
url_read() -> udp_read()
url_write() -> udp_write()
url_seek() -> udp_close()url_close() -> udp_close()
右中區域(AVInputFormat封裝格式處理函數)
AVInputFormat包含如下封裝格式處理函數指針:
read_probe():檢查格式
read_header():讀取文件頭
read_packet():讀取一幀數據
read_seek():調整進度
read_close():關閉
【例子】不同的封裝格式對應著上述接口有不同的實現函數,舉幾個例子:
FLV封裝格式對應的AVInputFormat結構體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封裝格式對應的AVInputFormat結構體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封裝格式對應的AVInputFormat結構體ff_mpegts_demuxer:
read_probe() -> mpegts_probe()
read_header() -> mpegts_read_header()
read_packet() -> mpegts_read_packet()
read_close() -> mpegts_read_close()
AVI封裝格式對應的AVInputFormat結構體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編解碼函數)
AVCodec包含如下編解碼函數指針:
init():初始化
decode():解碼一幀數據
close():關閉
【例子】不同的編解碼器對應著上述接口有不同的實現函數,舉幾個例子:
HEVC解碼對應的AVCodec結構體ff_hevc_decoder:
init() -> hevc_decode_init()
decode() -> hevc_decode_frame() -> decode_nal_units()
close() -> hevc_decode_free()
H.264解碼對應的AVCodec結構體ff_h264_decoder:
init() -> ff_h264_decode_init()
decode() -> h264_decode_frame() -> decode_nal_units()
close() -> h264_decode_end()
VP8解碼(libVPX)對應的AVCodec結構體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解碼對應的AVCodec結構體ff_mpeg2video_decoder:
init() -> mpeg_decode_init()
decode() -> mpeg_decode_frame()
close() -> mpeg_decode_end()
轉:
雷霄驊 (Lei Xiaohua)
[email protected]
http://blog.csdn.NET/leixiaohua1020
FFmpeg源代碼結構圖 - 解碼