經過大約一個月左右的業余時間,終于初步完成一個H.265/HEVC碼流分析工具。時間包括平時的周末、晚上,以及調休的集中時間。當然,中秋回家過節不寫代碼。截至今天,經過多種H.265序列測試,也有各種工具對比,基本上無大問題,v2.0版本終于釋放出來。v1.x版本是去年年初做的,彈指間一年多的今天又繼續做。但后面也不知道有沒有時間和心情完善,隨緣吧。
一、背景
按慣例,每年年中的時候,公司都要講新平臺預研,但不等預研結束,公司高層就開會舉手敲定一個新平臺,而使得“預研”結束。今年主題之一是上H.265。第一個H.265標準在2013年1月出來,至今不夠3年時間,有很多公司盯上了這領域,勢頭很好,但畢竟只是開始的幾年,還是有待發展。
這種宣傳性的東西,估計產品經理、行業總監們要關注,咱們這些寫代碼的其實不用關心太多。但對于技術的研究、探索,還是很有必要的。網上已經有很多商用的工具開發出來了,在文章《初識HEVC/H.265》中提到一些。鑒于以前也寫了H264碼流分析工具,從這方面入手會好一些,一來練練手,保持代碼熟悉度,二來在寫的過程對照標準手冊學習,效果比單看手冊好很多。于是就在原來工具基礎上,繼續做H265的分析。
二、思路
在文章《完成一個分析H264碼流的工具》中大概寫了一些思路,但不是很系統。這里再寫一下。核心代碼為h264bitstream開源庫,它提供了一個很好的H.264碼流讀、寫的方案,而且開源。它提供了基本的讀寫碼流的接口。比如查找NAL,指數哥倫布編碼等。因此,使用該開源庫,只需根據標準手冊里的語法規定去一一解析即可。關于這個庫,不在此處詳細展開描述。
0、根據標準手冊語法,建立全局結構體,每個字段都單獨存儲。所有結構體歸屬于h264_stream_t和h265_stream_t結構體。對于數量不確定的字段,統一使用vector存儲。
1、用戶打開文件時,先判斷文件類型,目前只支持H.264和H.265兩種格式,如有后綴名,優先使用后綴名判定,否則讀取文件開始處的NAL頭,查看手冊,兩種碼流的NAL頭有差異,故可以使用該種方法。
2、按字節讀取文件,根據start code解析NAL,得到NAL偏移量、長度、類型(如果是slice,還會解析出slice的類型,如I幀、P幀、B幀),存儲于vector中,同時,為了得到如視頻分辨率,幀率、YUV空間等信息,在解析NAL時,一并進行。做這些工作,是為了在界面的列表中列出各個NAL信息以及視頻的概要信息。詳見下文的界面截圖。
3、鼠標雙擊某一個NAL時,根據前面得到NAL索引、偏移,讀取文件并解析,從而得到該NAL詳細信息,這里使用的方法,就是根據手冊,逐一讀取碼流。
三、實現
此處講述一下在編碼、學習過程的經驗。
未動手寫代碼時,去下載商業工具玩玩,但只有幾天的試用期,就把幾個關鍵的NAL截圖保存起來,方便日后對比。后面過期了,就拿HM的工程做對比,該工程打開幾個宏就可以把運行過程的信息打印出來,包括解析碼流的各個字段。
然后按手冊的語法,參考h264bitstream代碼,建立H.265的對應結構體,基本上語法大的方面保持一致,但H.265多了一個VPS結構體,還有ptl(profile tier level)。添加這些語法,耗時很多,一來語法字段本來就多,二來要對著手冊看——即使這樣,后面還是發現有個別錯誤、疏漏的。H.264/H.265有很多字段是屬于數組類型,根據某一數值來確定范圍。起初參考h264bitstream,數組統一使用255,但后來想想還是用Vector好一些,就改了。
讀取碼流完成了,打印字段也完成了,再從宏觀上看整個工程,發現寫有亂。這次是在去年寫的工具上進行的,其實改善空間很大,只是自己懶,不去做。于是趁機會把代碼重構了,重構后條理性好了很多。
之后就進行調試。在這個過程,還是有不少問題。
有些是細節問題,比如有個地方判斷B幀,結果把“==”寫成“=”,查了半天才發現。還有一個地方是pred_weight_table的判斷,判斷P和B幀的條件不同,但代碼復制時不注意,沒搞對,又花了很久排查。還有一個是讀取slice頭部的num_ref_idx_l1_active_minus1字段,同樣是代碼復制,沒有注意是ue(),在和HM代碼運行結果對比時,花了很多時間才確定問題。
打印NAL字段函數里,有些不按語法上寫,導致個別字段和其它工具的不一致,于是又對著手冊改——開始時就應該如此,又是懶沒用心寫。
下面說說其它的問題。
解析NAL,是要將碼流轉換成RBSP,代碼工程統一使用h264bitstream提供的nal_to_rbsp函數,但該函數只針對只有一個字節的H.264碼流的,而H.265的NAL頭有2個字節。在轉換時是不包括NAL頭的,于是就手動修改該函數的參數。
關于SEI,h264bitstream庫并沒有做過多解析。或許是SEI信息重要程度不高吧。還有一個問題。在PPS中,more_rbsp_data的判斷不正確。導致后面的字段不再解析。幾經搜索,最終使用FFMPEG代碼的判斷方法,似乎是正常的了,就不再深究。
而至于其它的修改、完善,我在另一篇文章《關于h264bitstream的bug修正及完善》里寫了,這里不再寫出了。
四、界面
無論怎樣,還是完成了。此事務算告一段落。界面如下:
源代碼倉庫地址為:https://github.com/latelee/H264BSAnalyzer。后續不確定是否要繼續維護、更新,以倉庫代碼為準。
后記:調休期間,有傳言說大大boss拍板停止調研某國產的支持H.265的芯片平臺,但我沒有在正式場合得到信息,不懂是否真實。在不確定是否上H.265時,我決定搞這個工具,在不確定是否停止H.265時,完成這個工具。有始有終。
2015.11.21的更新:
發布v2.1版本。使用樹形控件顯示碼流語法元素。增加界面的縮放功能。離上個版本有差不多2個月了,理論上搞這么個小功能不用花那么久的,主要還是因為自己懶,一到周末就完全不想寫代碼了。新版本界面如下(一眼看上去,頓時覺得高端好多):
