天天看點

ffmpeg的HEVC解碼源代碼分析(一)整體架構

通過調試ffmpeg對HEVC碼流(格式為es流,就是rawvideo)的解碼過程,分析ffmpeg的HEVC解碼過程和實作方法。

首先要說的是調試所用的工程的config為:./configure –disable-asm –disable-pthreads –enable-debug –disable-optimizations進行configure。

禁用了pthread,是以涉及到pthread的函數都不采用。

配置和編譯的詳細過程見文章《Linux環境下,用eclipse對ffmpeg源代碼進行調試》。

輸入為HEVC的純碼流,輸出為YUV檔案。

開始調試,進入main函數後的函數調用關系如圖fig.A所示:

ffmpeg的HEVC解碼源代碼分析(一)整體架構

fig.A中大多數的步驟都是ffmpeg中各種codec通用的,不針對HEVC。

1.注冊變量和函數,通過一系列的函數順序實作,包括:avcodec_register_all(),avfilter_register_all,av_register_all等等。

2.ffmpeg_parse_options():深入分析輸入參數。對輸入輸出檔案做分析。

為什麼說深入呢?因為這個函數做了很多工作:将使用者的指令行分解,打開輸入的碼流檔案,并對碼流檔案進行試解碼(調用函數try_decode_frame)以分析輸入碼流的特征。是以運作完這個函數,ffmpeg已經可以确定輸入檔案的檔案類型,codec等等資訊了。

3.transcode():字面意思是轉碼,就是将輸入檔案轉成輸出檔案的格式,對視訊來說就是一個解碼到YUV圖像,再進行編碼的過程,在本文中,輸出為YUV,就不用再進行編碼了。

3.1:transcode_init():初始化,輸入輸出檔案的各種配置,比如色彩空間,檔案格式等等。

3.2:transcode_step()到process_init(): 開始轉碼,對本文來說就是解碼。

3.2.1:get_input_packet(),av_read_frame(),read_from_packet_buffer()函數,完成的任務就是從輸入碼流中讀入一個packet,将資訊存放到結構體AVPacket(AVPacket的分析見《ffmpeg重要結構體之AVPacket》)。packet的含義我個人了解就是能解出一幀圖像的碼流單元。

舉個例子,對于HEVC,在某碼流開始時,前6個nal的類型依次為:VPS,SPS,PPS,SEI,slice,slice.兩個slice的nal組成一幀,則第一個packet就由這6個nal組成。

3.2.2 :從process_input_packet()一直到avctx->codec->decode(),avctx->codec->decode()指向hevc_decode_frame(),正式進入到HEVC解碼部分。

ffmpeg的HEVC解碼源代碼分析(一)整體架構

fig.B從函數hevc_decode_frame()開始的函數調用關系。hevc_decode_frame()調用decode_nal_units(),逐個解析nalu。

1.ff_hevc_split_packet():這個函數将AVPacket分解為一個個的nalu,并将每個nalu的資訊存放的結構體HEVCContext的成員HEVCPacket pkt(見《ffmpeg重要結構體之HEVCContext和HEVCFrame》)中,舉個例子,一個packet中有10個nalu,ff_hevc_split_packet()會将這10個nalu的類型和長度都解析出來,并存好。

2.decode_nal_unit():此函數解碼一個nalu的碼流,根據nalu的類型調用不同的函數進行處理。

2.1:碼流解析:當nalu的類型為VPS,PPS,SPS,或者SEI時,decode_nal_unit()調用相對應的解析函數進行處理。

這個步驟相對簡單,解析函數比如ff_hevc_decode_nal_sps(),基本上就是按照HEVC的标準,将碼流元素逐個讀入,并存放的過程。

2.2slice解碼:當nalu的類型為slice的時候,會先調用hls_slice_header()函數,将slice header 的資訊讀入,然後便是HEVC的slice解碼。

hevc_frame_start()和函數ff_hevc_slice_rpl()涉及到DPB(decoded picture buffer)管理和rpl(reference picture list)解析即應用,以後會展開讨論。

而hls_decode_entry()就是逐個解碼slice中的CTU(coding tree unit)了,在其他文章裡會繼續讨論。