馬希超,魏志強,葛 珊
(中國電子科技集團公司第三研究所,北京 100015)
隨著無人機在偵察監視、安防保衛、森林消防及航拍攝影等眾多領域的推廣應用,作為其核心載荷的光電吊艙得到了人們越來越多的關注[1-2]。在執行飛行任務時,光電吊艙作為無人機的“眼睛”,通過有線或無線傳輸鏈路將采集的可見光視頻和紅外視頻實時傳輸至地面,由地面操控臺上運行的顯控軟件接收并顯示。目前,主流的光電吊艙采集的可見光視頻分辨率基本都可達到1 920×1 080 像素,幀率為25 f/s 或30 f/s。通過計算可知,如果直接傳輸原始視頻數據,數據量會達到Gb/s 的量級,對于遠距離無線傳輸來說極難實現。因此,通常對視頻進行編碼,如采用H.264 或H.265 格式,將數據量壓縮至Mb/s 的量級,再經無線鏈路傳輸后由地面顯控軟件解碼后顯示[3-4]。
視頻編解碼的引入對顯控軟件提出了更高的要求[5],主要體現在實時性和平穩性兩個方面。一方面,顯控軟件從接收視頻流到解碼再到顯示需經過多個環節,若簡單地順序執行,必然會導致較大的滯后,對操控設備和觀察視頻造成明顯的影響。為保證較好的實時性,需要設計合理的多線程架構,盡量減小視頻顯示的延遲滯后。另一方面,在H.264或H.265 格式的視頻碼流中,視頻幀分為關鍵幀(I幀)、前向參考幀(P幀)和雙向參考幀(B幀)3類[6]。其中,I 幀每隔一定時間出現一次,包含一幀圖像的完整信息,因此數據量較大;其余的P 幀和B 幀只包含幀差信息,數據量小。因此,傳輸、接收及解碼I 幀時所需的時間較長,導致視頻在顯示時出現周期性卡頓現象。此時,需要采取適當的方法來保證視頻顯示的平穩性。
本文描述一種針對機載光電吊艙的視頻流實時解碼顯示技術。通過設計合理的多線程架構,采用動態圖像緩存技術,實現了視頻解碼顯示的低延遲和無卡頓,提高了顯控軟件的實時性和平穩性。
整個流程分為3 個線程,即接收線程、解碼線程及顯示線程。3 個線程并行運行,通過視頻流緩存和圖像緩存兩個存儲區進行數據交換。處理流程和線程結構如圖1 所示。

圖1 流程圖
在接收線程中,程序以循環的方式不斷接收視頻流數據并存入視頻流緩存;解碼線程同樣以循環的方式不斷檢查視頻流緩存中的數據量,當數據量超過一定的閾值,提取數據進行解碼,并將解碼后的圖像存入圖像緩存;顯示線程以定時器方式周期性地從圖像緩存中提取圖像進行顯示。3 個線程在各自獨立運行的同時緊密配合,以保證數據的快速傳遞,最大限度降低延遲,同時數據流向清晰,避免產生線程沖突。
接收線程用于完成光電吊艙下傳視頻流的接收。光電吊艙通常采用UDP 通信協議,通過網絡下傳視頻流,可能帶有加密幀頭。接收線程通過循環的方式不斷讀取網絡數據,根據通信協議從加密數據包中提取有效的視頻流數據,并立即將數據存入視頻流緩存。視頻流緩存為全局存儲區,需具備大量數據快速寫入寫出的能力。同時,它對內存空間的控制十分重要,一旦發生接收線程和解碼線程配合失常的情況,如接收線程正常運行而解碼線程由于初始化問題未能運行時,視頻流緩存將出現只存入不取出的情況,最終導致內存溢出,程序崩潰。為避免這種情況的發生,采用環形存儲器作為視頻流緩存。環形存儲器采用先進先出原則,當存儲空間用盡后會從尾部回到頭部,用新的數據覆蓋最早的數據。這樣既可以免去不斷申請新內存空間的開銷,又可避免出現內存溢出的情況。在程序運行過程中,接收線程控制存儲器的寫入指針不斷存入視頻流數據,到達末端后便回到起點繼續寫入;解碼線程控制存儲器的讀取指針以追趕的方式不斷取出數據,使存儲器內的數據量始終保持在一定長度之內,實現動態平衡。
解碼線程同樣采用循環方式不斷獲取視頻流緩存中的數據量。當數據量大于設定的閾值N(如1 024 Bytes)時,則提取N個字節的數據移交至解碼器處理。解碼器調用FFmpeg 程序庫對H.264 或H.265 碼流解碼,并轉換為RGB 格式圖像存入圖像緩存。
在H.264 或H.265 碼流中,大部分幀都是只包含幀差信息的參考幀(P 幀和B 幀),數據量較小。每隔固定時間(如1 s)會有一個關鍵幀I 幀,包含完整的圖像信息,數據量大,使得傳輸和解碼都較為耗時。因此,解碼得到各幀圖像的時間間隔是不均勻的。若不加處理地將每一幀解碼圖像立即顯示,則會每隔一段時間出現一次卡頓現象,影響視頻顯示的連貫性和平穩性。
為解決這一問題,本文引入了圖像緩存。圖像緩存的總體思路是將解碼圖像依次存入緩存,由顯示線程定時提取圖像進行顯示,使顯示的周期與解碼的周期隔離開來并保持均勻。圖像緩存采用隊列形式,以先入先出原則進行存取。采用圖像緩存需要解決的一個重要問題是保證輸入輸出的平衡。雖然根據相機的幀率可以計算各幀的平均間隔,但并不十分精確。此外,為定時器設定的響應周期也無法做到與真實的幀間隔完全一致,會導致輸入輸出的不平衡。若輸出快于輸入,則會耗盡緩存內的圖像,存入一幀則立即顯示一幀,導致緩存失去作用,視頻依然發生卡頓;若輸出慢于輸入,則緩存數量不斷增加,若不加限制會導致內存溢出,程序崩潰,若設置限幅則會丟失圖像。
本文采用動態圖像緩存的方法實現輸入輸出的平衡,流程如圖2 所示。每隔一段時間判斷一次緩存內的圖像數量,若數量較多,則減小定時器的間隔,加快顯示;若數量較少,則增大定時器的間隔,減慢顯示;若數量適中,則保持初始間隔。以30 f/s的可見光視頻為例,設初始顯示間隔T=33 ms。每解碼30 幀判斷一次緩存數量N,若N>5,則令T=30 ms,加速顯示,消耗緩存數量,減小視頻滯后;若N<3,則令T=34 ms,稍稍減慢顯示,積累緩存數量,避免出現卡頓;若3 ≤N≤5,則令T=33 ms,保持穩定顯示。
經過對提取頻率的動態調整,可以使圖像緩存長期維持在數量較少的狀態,保持輸入與輸出的平衡和穩定。
測試所用的光電吊艙顯控軟件采用C++語言和Qt 框架編寫,實現了本文所述的多線程架構和動態圖像緩存技術。在解碼線程和顯示線程中分別記錄每幀圖像解碼和顯示的時間戳,計算解碼時間間隔和經動態調整后的顯示時間間隔,最后繪制如圖3 所示的曲線圖。
從圖3 可知,解碼間隔極不穩定,約30 幀(大概1 s)會出現一次120 ms 以上的長間隔,即處理I幀所需的時間。而經動態調整后,顯示間隔平穩程度顯著提高,絕大多數數據穩定在33 ms 左右,其中一小段在30 ms 左右,這是緩存數量較多、加快顯示的結果。這一結果表明,采用動態圖像緩存技術可以有效提高視頻顯示的平穩性,避免出現卡頓現象。

圖2 動態圖像緩存流程

圖3 幀間隔統計
此外,合理的多線程架構設計也使顯控軟件具有較好的實時性。本文用簡易方法測試了從相機成像到視頻編碼、傳輸再到接收、解碼及顯示全過程的總延遲時間約為0.4 s,如圖4 所示。在這一較低的延遲下,控制光電吊艙和觀察視頻時基本不會產生明顯的滯后現象。

圖4 延遲時間測試
本文介紹了一種針對機載光電吊艙的視頻流實時解碼技術,通過設計合理的多線程架構和數據交換方式,采用動態圖像緩存技術,實現了低延遲和無卡頓的視頻解碼顯示效果,對于充分發揮光電吊艙的性能和提高地面顯控軟件的運行效率與使用體驗具有重要意義。