唐昆鵬,陳慶奎
(上海理工大學(xué) 光電信息與計(jì)算機(jī)學(xué)院,上?!?00093)
?
基于CUDA的多路高清視頻流解碼器設(shè)計(jì)與實(shí)現(xiàn)
唐昆鵬,陳慶奎
(上海理工大學(xué) 光電信息與計(jì)算機(jī)學(xué)院,上海200093)
摘要針對多視頻流解碼和顯示時(shí)CPU占用率過高等問題。設(shè)計(jì)了基于統(tǒng)一計(jì)算設(shè)備架構(gòu)(CUDA)平臺(tái)上的GPU多視頻流并行化處理方案,定義了表示GPU顯卡設(shè)備和解碼器的數(shù)據(jù)結(jié)構(gòu),通過解碼函數(shù)接口的調(diào)用可適用于多種視頻播放器中去。實(shí)驗(yàn)結(jié)果表明,所設(shè)計(jì)的解碼器大幅降低了多視頻解碼顯示中CPU的占用率,同時(shí)與JM實(shí)現(xiàn)的軟件解碼方案相比,解碼單路720 p的高清視頻CPU占用率同比降低約30%,所以此硬件解碼方案表現(xiàn)出更加高效的多視頻流解碼處理能力。提高了系統(tǒng)性能和資源復(fù)用率,并能保持較低的能量消耗。
關(guān)鍵詞多視頻流解碼;CUDA;并行化;占用率;能量消耗
H.264[1]作為目前視頻壓縮領(lǐng)域編碼效率較高的編碼標(biāo)準(zhǔn),具有低帶寬高畫質(zhì)的壓縮能力,比H.263和MPEG-4編碼效率提高約50%[2]。但其實(shí)現(xiàn)算法復(fù)雜度和計(jì)算量較高、目前CPU的計(jì)算能力在解碼720 p和1 080 p等高清視頻時(shí)性能不足。
于是,GPU被設(shè)計(jì)用于為并行計(jì)算提供支持,并分擔(dān)部分視頻解碼的任務(wù)[3-4],利用GPU內(nèi)部具有眾多并行計(jì)算核心來編寫GPU上運(yùn)行的代碼,結(jié)合NVIDIA的CUDA[5-6]平臺(tái),將高密度計(jì)算量和耗時(shí)的任務(wù)移植到GPU上。與基于平臺(tái)實(shí)現(xiàn)GPU加速的DXVA技術(shù)相比,CUDA平臺(tái)上的解碼方案具有更好的解碼速度、效率和跨平臺(tái)性。本文將GPU加速解碼的方案與H.264學(xué)術(shù)研究使用的JM18.4軟件解碼方案進(jìn)行比較,在解碼速度和幀率上表現(xiàn)出較高的優(yōu)勢。同時(shí),為滿足多路視頻會(huì)議和監(jiān)控設(shè)備等應(yīng)用需求,提出了基于CUDA的多視頻流解碼方案,實(shí)驗(yàn)表明,該設(shè)計(jì)大幅降低了解碼多路高清視頻時(shí)CPU的占用率,有效提高系統(tǒng)多視頻流并行解碼能力[7]。
1關(guān)鍵技術(shù)
NVIDIA公司開發(fā)的統(tǒng)一計(jì)算設(shè)備架構(gòu)(Compute Unified Device Architecture,CUDA)[8-9]為GPU增加一個(gè)易用的編程接口。CPU負(fù)責(zé)派生出運(yùn)行在GPU設(shè)備處理器上的多線程任務(wù)(CUDA稱為內(nèi)核函數(shù))。GPU設(shè)有內(nèi)部調(diào)度器將這些內(nèi)核程序分配到相應(yīng)的GPU硬件上。NVIDIA C編譯器NVCC作為CUDA架構(gòu)核心用來編譯分離出GPU和CPU代碼,GPU代碼被編譯成GPU計(jì)算匯編代碼PTX并經(jīng)CUDA Driver支持運(yùn)行在GPU。H.264采用多模式運(yùn)動(dòng)估計(jì)[10]、幀內(nèi)預(yù)測、多幀預(yù)測等先進(jìn)實(shí)用技術(shù),以更低的碼率和壓縮畫質(zhì)成為行業(yè)標(biāo)準(zhǔn)。其解碼框架圖如圖1所示。
圖1 H.264解碼流程
2CUDA解碼器設(shè)計(jì)與實(shí)現(xiàn)
GPU硬件加速將一部分解碼任務(wù)從CPU端轉(zhuǎn)移到GPU端來完成,將解碼后的數(shù)據(jù)保存在顯存中,在GPU內(nèi)部完成解碼后視頻數(shù)據(jù)的后期處理工作(顏色空間轉(zhuǎn)換、縮放、與OpenGL交互處理等)。CUDA硬件解碼的處理架構(gòu)為:將解碼的MC(Motion Compensation)、IDCT、VLD(Variable-Length Decoding)、Deblocking轉(zhuǎn)移到GPU中處理。
2.1CUDA解碼器緩沖區(qū)
解碼器需要使用硬件解碼單元,然后向硬件單元傳送一些配置參數(shù),CUDA中每個(gè)參數(shù)均以對應(yīng)的緩沖區(qū)來傳送,需要先申請緩沖區(qū)然后填充對應(yīng)類型的緩沖區(qū)。解碼器需要傳入代表不同緩沖區(qū)的4個(gè)參數(shù):圖片參數(shù)緩沖區(qū)、碼流緩沖區(qū)、條帶控制命令緩沖區(qū)和量化矩陣緩沖區(qū)。
(1)圖片參數(shù)緩沖區(qū)。在CUDA解碼器解碼當(dāng)前幀時(shí)需要一個(gè)對當(dāng)前幀描述的參數(shù),對于多個(gè)編碼標(biāo)準(zhǔn)可使用CUVIDPICPARMS結(jié)構(gòu)體來描述。圖片級別中圖片的信息會(huì)不一樣,所以每解碼一幀圖片之前,此結(jié)構(gòu)體都要被傳送。以下是CUVIDPICPARMS結(jié)構(gòu)體的定義:
typedef struct_CUVIDPICPARAMS
{
int PicWidthInMbs;
int FrameHeightInMbs;
unsigned int nBitstreamDataLen;
const unsigned char *pBitstreamData;
……
union {
CUVIDH264PICPARAMS h264;
…
} CodecSpecific;
} CUVIDPICPARAMS;
該結(jié)構(gòu)體詳細(xì)定義了圖片層數(shù)據(jù),例如,比特流緩存區(qū)中的字節(jié)數(shù)nBitstreamDataLen,pBitstreamData指針指向當(dāng)前幀,union部分表示的不同視頻流編碼標(biāo)準(zhǔn);
(2)條帶參數(shù)。條帶控制參數(shù)用來描述當(dāng)前碼流,用_CUDA_Slice結(jié)構(gòu)體進(jìn)行描述和定義:
typedef struct_CUDA_Slice {
UINT DataLocation;
UINT SliceDataInBuffer;
USHORT isBadSliceChopping;
} CUDA_Slice;
DataLocation表示傳輸碼流中nalu單元包含的編碼數(shù)據(jù)起始字節(jié)數(shù),SliceDataInBuffer表示總的碼流傳輸字節(jié)數(shù),isBadSliceChopping表示傳輸?shù)拇a流是否含有起始碼;
(3)碼流和量化參數(shù)緩沖區(qū)。解碼器進(jìn)行反量化時(shí)的量化參數(shù)將會(huì)保存在量化矩陣緩沖區(qū)中,結(jié)構(gòu)體定義為:
typedef struct_CUDA_Qmatrix {
unsigned char WeightScale4×4[6][16];
unsigned char WeightScale8×8[2][64];
} CUDA_Qmatrix;
該數(shù)據(jù)結(jié)構(gòu)體中包含兩種不同類型的反量化參數(shù)矩陣,分別為4×4和8×8大小。同時(shí)將顯存中的一塊地址分配給碼流緩沖區(qū),再通過這塊碼流緩沖區(qū)向GPU傳送解碼的碼流。
2.2CUDA解碼流程
CUDA提供加速解碼的接口函數(shù)API,本文基于該API實(shí)現(xiàn)并行化的視頻解碼,圖2顯示了該解碼器的解碼流程。
圖2 解碼基本流程圖
步驟1讀取視頻文件,使用cuvidparseVideoData()函數(shù)解析視頻幀信息;
步驟2初始化CUDA解碼器設(shè)備并設(shè)置相關(guān)參數(shù),例如:顯卡序號、顯存分配大小等;
步驟3將步驟1獲得的視頻幀信息,如:文件頭標(biāo)記、文件大小(payload)、時(shí)間戳等讀入視頻幀結(jié)構(gòu)體。再將該結(jié)構(gòu)體數(shù)據(jù)傳入解碼函數(shù)cuvidDecodePicture(),然后執(zhí)行解碼任務(wù);
步驟4完成步驟3后,獲得原始YUV數(shù)據(jù),因?yàn)樵贕PU中完成解碼,這些數(shù)據(jù)仍保留在設(shè)備顯存中,用于視頻的播放顯示,也可以拷貝到主機(jī)內(nèi)存做其他操作;
步驟5解碼完成一幀數(shù)據(jù)后,進(jìn)行文件結(jié)束標(biāo)記檢查,讀取完成則銷毀CUDA解碼器、否則使用read_frame_data()讀取下一幀數(shù)據(jù)。
CUDA視頻解碼庫使用兩種不同的GPU加速引擎,即顯卡硬件和視頻處理器VP。本文通過使用多線程技術(shù),不同線程分配不同的顯示任務(wù)并執(zhí)行,cuvidMapVideoFrame線程使用映射技術(shù),從VP解碼幀得到映射后的CUDA設(shè)備指針信息;cuD3D9ResourceGetMappedPointer線程從D3D紋理中獲取設(shè)備指針信息;cudaPostProcessFrame線程連續(xù)調(diào)用幀數(shù)據(jù)后處理函數(shù),并把結(jié)果返回給映射D3D紋理;cuD3DUnmapResources線程讓驅(qū)動(dòng)釋放指針給D3D9,表示已經(jīng)完成修改,可以在D3D9中安全使用;cuvidUnmapVideoFrame線程釋放VP解碼幀。
2.3多視頻流解碼架構(gòu)設(shè)計(jì)與實(shí)現(xiàn)
單視頻流解碼時(shí)通過充分利用CUDA平臺(tái)實(shí)現(xiàn)的解碼器完成GPU硬件加速解碼,為解決多路視頻解碼問題,本文重新定義代表顯卡設(shè)備的數(shù)據(jù)結(jié)構(gòu)和代表解碼器的數(shù)據(jù)結(jié)構(gòu),便于多碼流的數(shù)據(jù)管理和調(diào)度。驅(qū)動(dòng)程序可實(shí)現(xiàn)多個(gè)對象共用一個(gè)硬件設(shè)備,則在視頻解碼中解碼器便可關(guān)聯(lián)到同一個(gè)顯卡設(shè)備。
2.3.1顯卡和解碼器數(shù)據(jù)結(jié)構(gòu)定義
顯卡數(shù)據(jù)結(jié)構(gòu)定義:
typedef struct DeviceManager {
HWND Hwnd;
IDirect3D9 *pD3D9;
IDirect3DDevice9 *pD3DD9;
IDirect3DDeviceManager9 *pD3DManager;
Unsigned PCI_Vendor;
Unsigned DecoderNum;
} DeviceManager;
其中,Hwnd是程序創(chuàng)建的一個(gè)用來顯示的窗口句柄,pD3D9和pD3DD9分別表示顯卡對象和顯卡設(shè)備,pD3Dmanager代表顯卡設(shè)備的管理器,主要是用來管理多個(gè)解碼器共享顯卡設(shè)備的,PCI_Vendor表示顯卡制造廠商,DecoderNum是表示與顯卡關(guān)聯(lián)的解碼器個(gè)數(shù),解碼器定義的數(shù)據(jù)結(jié)構(gòu)如下:
typedef struct_CUDADecoder {
DeviceManager *pD3DManager;
IDirectXVideoDecoder *pCUDADecoder;
IDirect3DSurface9 **pD3D9Surface;
CUVIDPICPARAMS cudaPicParams;
CUDA_Slice cudaSliceData;
CUDA_Qmatrix cudaQmatrix;
Seq_parameter_rasp_t sps;
Pic_parameter_rasp_t pps;
} CUDADecoder;
pD3Dmanager是解碼器關(guān)聯(lián)的顯卡設(shè)備,pCUDADecoder是創(chuàng)建的解碼器,pD3D9 surface是解碼后的數(shù)據(jù)存放的表面,CUVIDPICPARAMS,CUDA_Slice和CUDAQmatrix是硬件解碼單元使用的數(shù)據(jù)緩沖區(qū)結(jié)構(gòu)體,sps和pps是H.264標(biāo)準(zhǔn)中所標(biāo)示的條帶控制參數(shù)和圖像控制參數(shù)。這里基于CUDA提供的接口函數(shù)API做了一次封裝,便于應(yīng)用程序調(diào)用。同時(shí)定義設(shè)備的創(chuàng)建和解碼接口,幾個(gè)主要接口函數(shù)為:
(1)CUresult。InitDeviceManager(DeviceManager *pManager),該函數(shù)主要功能是顯卡初始化、顯卡設(shè)備的創(chuàng)建和類型檢測等;
(2)CUresult。CreateCUDADecoder(CUDADecoder *pDecoder),該函數(shù)依據(jù)所關(guān)聯(lián)的DeviceManager創(chuàng)建一個(gè)相應(yīng)的硬件解碼器對象,并將所關(guān)聯(lián)的DeviceManager數(shù)據(jù)結(jié)構(gòu)中的解碼器計(jì)數(shù)器加1;
(3)CUresult。CUDADecodeFrame(CUDADecoder *pDecoder,NALU_t *pNalu,RECT *pRect),該函數(shù)作為解碼器的接口,含有3個(gè)主要參數(shù),第一個(gè)參數(shù)代表解碼器,pNalu代表碼流的一個(gè)NALU單元,pRect代表解碼器解碼產(chǎn)生的數(shù)據(jù)將會(huì)在顯示窗口中呈現(xiàn)的顯示區(qū)域;
(4)CUresult。DestroyCUDADecoder(CUDADecoder *pDecoder),該函數(shù)的功能是釋放解碼器設(shè)備,同時(shí)將相關(guān)聯(lián)的數(shù)據(jù)結(jié)構(gòu)DeviceManager中的解碼器計(jì)數(shù)量減去1;
(5)CUresult。DestroyDeviceManager(DeviceManager *pManager),該函數(shù)的功能是釋放顯卡設(shè)備,銷毀創(chuàng)建的數(shù)據(jù)顯示窗口。函數(shù)會(huì)在銷毀之前檢查所關(guān)聯(lián)的解碼器個(gè)數(shù)是否為0,若<0,就不執(zhí)行任何操作并返回,以保證安全的調(diào)用。
2.3.2多視頻流解碼調(diào)度
系統(tǒng)的整體執(zhí)行流程如圖3所示,具體到解碼一幀數(shù)據(jù)時(shí)解碼器的內(nèi)部執(zhí)行流程如圖4所示。其中解碼器內(nèi)部添加阻塞鎖以避免多個(gè)解碼器同時(shí)競爭使用一個(gè)硬件解碼單元,這樣便可開啟多個(gè)解碼線程進(jìn)行多路視頻流的解碼。
圖3 多碼流解碼算法流程圖
設(shè)計(jì)思想為:同時(shí)輸入幾個(gè)視頻流,這幾個(gè)碼流輪流解碼直至全部解碼完成,共用解碼器的主體部分,達(dá)到資源復(fù)用的目的。其中,Eos_num代表已解碼完成的視頻流個(gè)數(shù),MaxVsNum最大解碼視頻流個(gè)數(shù),CurVsNum當(dāng)前解碼的視頻流序號,Is_eos[CurVsNum]判斷序號為CurVsNum的視頻流是否解碼完成。
多碼流的解碼,必須保持各碼流之間的獨(dú)立性,解碼器主體函數(shù)中,需要做一些修改。比如碼流緩沖區(qū)、存放解碼圖像的緩沖區(qū)、存儲(chǔ)碼流的SPS和存儲(chǔ)碼流的PPS等結(jié)構(gòu)體分別為不同的碼流分配不同的存放空間。解碼每一幀時(shí)的幀級和宏塊級變量均會(huì)被重新賦值,對各幀之間的解碼沒有影響,因此不用修改。多碼流級別的全局變量為所有碼流可見,生命周期是整個(gè)解碼的過程,所以需要增加一維,深度設(shè)置為最大解碼視頻流的個(gè)數(shù),每個(gè)碼流占用其中一維,這樣多個(gè)碼流的解碼操作互不干涉。
3實(shí)驗(yàn)結(jié)果與性能分析
測試平臺(tái)環(huán)境相關(guān)參數(shù)為:雙核Intel Core 2 Duo E8400 CPU,主頻3.00 GHz,內(nèi)存4 GB,GPU為NVIDIA GeForce GTX 280,顯存容量為1 GB,流處理器(SP)個(gè)數(shù)240個(gè),操作系統(tǒng)為Windows7,CUDA 5.5,并在Visual Studio 2010環(huán)境下調(diào)試編譯,計(jì)時(shí)函數(shù)采用Win32 API中的GetTickCount()函數(shù),精確到ms。
3.1JM18.4軟件解碼與CUDA解碼對比
針對不同視頻流文件進(jìn)行測試,JM18.4軟件解碼器與CUDA解碼器在解碼時(shí)間、幀率上做對比,分別如圖5和圖6所示。
圖4 解碼時(shí)間對比
圖5 幀率對比
以同時(shí)解碼視頻流文件Sample為例,從幀率上比較,CUDA是JM18.4的近115倍,解碼時(shí)間上也只有后者的0.6%,實(shí)驗(yàn)結(jié)果表明,基于CUDA優(yōu)化的GPU并行加速解碼方案比JM18.4軟解碼具有更好的性能和效率,因此使用GPU并行化加速視頻流解碼具有較大的優(yōu)勢。
3.2基于CUDA的多視頻流解碼器性能評測
通過CPU解碼與基于CUDA的GPU解碼器進(jìn)行了多視頻解碼的對比測試,測試視頻文件為720 p的高清視頻,碼率平均為14.8 Mbit·s-1,衡量標(biāo)準(zhǔn)為每解碼30幀圖像的時(shí)間。開啟6個(gè)解碼線程同時(shí)解碼,本文主要測試解碼器的解碼速度和CPU的占用率這兩個(gè)標(biāo)準(zhǔn),測試結(jié)果如圖7和表1所示。
圖6 6路視頻解碼時(shí)間
幀率最低為24幀/s,畫面才會(huì)保持流暢,這里編碼器采用30幀/s,同時(shí)解碼6路720 p的高清視頻,平均時(shí)間0.74 s,可計(jì)算得幀率為40.43。所以可保證流暢的播放視頻畫面。
基于GPU的硬件解碼方案,負(fù)擔(dān)高計(jì)算量的解碼任務(wù)同時(shí),同時(shí)降低了CPU的占用率,取1路720 p高清視頻解碼,對比試驗(yàn)如表1所示。
表1 CPU占用率
由表1實(shí)驗(yàn)數(shù)據(jù)可看出,基于CUDA的解碼器播放高清視頻時(shí)可大幅降低CPU占用率,提高多視頻流的解碼能力,圖7中6路視頻解碼保持幀率40.43時(shí),CPU占用率不到100%。若將線程的分配和設(shè)備的初始化設(shè)計(jì)進(jìn)一步優(yōu)化,則可降低CPU的占有率。
4結(jié)束語
本文研究了基于CUDA的GPU視頻解碼技術(shù),實(shí)現(xiàn)了并行化的多視頻流解碼方案,實(shí)驗(yàn)結(jié)果證明,與軟件解碼方案JM18.4比較,GPU等硬件并行化加速處理方案對視頻解碼的具有更高的處理效能,降低CPU的占用率近30%,提高了多路視頻解碼的能力,具有較好的研究與應(yīng)用價(jià)值。使解碼器同時(shí)解碼更多數(shù)量和更高分辨率的高清視頻流是今后需要繼續(xù)研究的內(nèi)容。
參考文獻(xiàn)
[1]畢厚杰.新一代視頻壓縮編碼標(biāo)準(zhǔn)[M].北京:人民郵電出版社,2005.
[2]李超,柴文磊,劉勁松.高清視頻會(huì)議系統(tǒng)技術(shù)淺析[J].信息安全與技術(shù),2010(10):50-51.
[3]侯興松,劉大齊,盛凱,等.H.264并行編碼中負(fù)載平衡方法[J].中國圖象圖形學(xué)報(bào),2012,17(8):911-918.
[4]張舒,楮艷利.GPU高性能運(yùn)算之CUDA[M].北京:中國水利水電出版社,2009.
[5]Shane Cook.CUDA并行程序設(shè)計(jì):GPU編程指南[M].北京:機(jī)械工業(yè)出版社,2014.
[6]董亞清.基于GPU的線性調(diào)頻信號脈沖壓縮算法實(shí)現(xiàn)[J].電子科技,2013,26(12):12-16.
[7]Youngsub K O,Youngmin Y I,Soonhoi H A.An efficient parallel motion estimation algorithm and X264 parallelization in CUDA[C].Tampere,Finland:2011 Conference on Design and Architectures for Signal and Image Processing(DASIP),2011:4521-4536.
[8]Jae-Jin Lee,Kyungjin Byun.Multi-core architecture for video decoding[J].SoC Design Conference(ISOCC),2012,3(12):4-7.
[9]Juurlink B,Alvarez-Mesa M,Chi C C,et al.Scalable parallel programming applied to H.264/AVC decoding[M].New York,USA:Springer-Verlag,2012.
[10]Kovács P T,Nagy Z,Barsi A,et al.Overview of the applicability of H.264/MVC for real-time light-field applications[C].Budapest,Hungary:Proceeding of 3D TV Conference,2014.
歡 迎 刊 登 廣 告
請?jiān)L問:www.dianzikeji.orgE-mail:dzkj@mail.xidian.edu.cn
聯(lián)系電話:029-88202440傳真:029-88202440
Design and Implementation of Multi-stream Hd-decoder Based on Cuda
TANG Kunpeng,CHEN Qingkui
(School of Optical-Electrical and Computer Engineering,University of Shanghai for Science and Technology,Shanghai 200093,China)
AbstractA GPU multi-stream parallel decoding implementation based on compute unified device architecture (CUDA) platform is designed to solve the high CPU load problem in multi-video decoding and display.The data structure of the graphics processing unit (GPU) device and video decoder are defined.By calling the decoding function interface,the decoder can be used in variety of video players efficiently.The experimental results show that this decoder can greatly reduce the CPU utilization.Also,compared with the JM reference software decoder,CPU utilization is remarkably reduced by 30% when decoding the single road 720 p high definition video synchronously.So the decoder based on hardware enjoys higher efficiencyin video parallel decoding.Besides,the system performance and resource reuse rate are improved together with lower energy consumption.
Keywordsmulti-video decoding;CUDA;parallelization;occupancy;energy consumption
中圖分類號TN919.8;TP338
文獻(xiàn)標(biāo)識碼A
文章編號1007-7820(2016)04-071-05
doi:10.16180/j.cnki.issn1007-7820.2016.04.019
作者簡介:唐昆鵬(1989—),男,碩士研究生。研究方向:并行計(jì)算。陳慶奎(1966—),男,博士,教授。研究方向:并行計(jì)算等。
基金項(xiàng)目:國家自然科學(xué)基金資助項(xiàng)目(60970012);高等學(xué)校博士學(xué)科點(diǎn)專項(xiàng)科研博導(dǎo)基金資助項(xiàng)目(20113120110008);上海重點(diǎn)科技攻關(guān)基金資助項(xiàng)目(14511107902)
收稿日期:2015- 08- 21