裴 航,王 磊,王 威,張書欽
(1.中原工學(xué)院 計(jì)算機(jī)學(xué)院,河南 鄭州 451191; 2.中原工學(xué)院 前沿信息技術(shù)研究院,河南 鄭州 451191)
隨著互聯(lián)網(wǎng)的高速發(fā)展以及第五代移動(dòng)通信技術(shù)的到來,人們對(duì)多媒體品質(zhì)的需求日益提升,高清視頻的高效編解碼成為研究熱點(diǎn)。很多處理器平臺(tái)都研發(fā)出相應(yīng)的擴(kuò)展部件來增強(qiáng)計(jì)算機(jī)多媒體數(shù)據(jù)處理能力。單指令流多數(shù)據(jù)流(SIMD)[1]結(jié)構(gòu)可以高效地對(duì)大規(guī)模數(shù)據(jù)進(jìn)行并行處理,有效實(shí)現(xiàn)應(yīng)用程序中規(guī)整的數(shù)據(jù)級(jí)并行(data level parallelism,DLP),從而提升了處理器的吞吐率,在一定程度上滿足了多媒體計(jì)算能力需求[2]。Intel公司在Pentium處理器中最早采用了支持MMX[3]的SIMD技術(shù),一直不斷升級(jí)至現(xiàn)在的AVX2技術(shù)。ARM公司推出的Cortex-A系列處理器采用了NEON技術(shù)[4]。如今越來越多的廠商都在處理器內(nèi)集成、升級(jí)SIMD擴(kuò)展部件,很多應(yīng)用程序都在尋求SIMD并行,以增強(qiáng)移動(dòng)終端的多媒體處理能力。
申威[5]是國內(nèi)自主研發(fā)的通用處理器,提供256位向量寄存器且包括支持256位向量訪存及運(yùn)算的SIMD擴(kuò)展指令。對(duì)于某些處理器體系結(jié)構(gòu),SIMD擴(kuò)展指令允許將原來需要多次裝載的內(nèi)存中地址連續(xù)的數(shù)據(jù)一次性裝載到向量寄存器中。使用一條SIMD擴(kuò)展指令實(shí)現(xiàn)對(duì)SIMD向量寄存器中所有數(shù)據(jù)元素的并行處理,這種執(zhí)行方式非常適合于處理計(jì)算密集、數(shù)據(jù)相關(guān)性少的多媒體程序,如音視頻編解碼[6]。
H.264[7]視頻編碼格式是目前發(fā)展比較成熟的編碼格式。常用的開源解碼器有JM[8]、T264[9]和FFmpeg[10],目前很多國產(chǎn)平臺(tái)都對(duì)FFmpeg視頻解碼器針對(duì)各個(gè)平臺(tái)特點(diǎn)做了相應(yīng)的優(yōu)化。文獻(xiàn)[11]針對(duì)視頻解碼時(shí)CPU占用率高,專用硬件解碼耗時(shí)長等問題,研究了飛騰平臺(tái)上GPU硬件加速視頻解碼技術(shù),設(shè)計(jì)了基于VDPAU硬件解碼接口的GPU硬件視頻解碼方案。文獻(xiàn)[12]在實(shí)現(xiàn)FFmpeg解碼器到國產(chǎn)龍芯3B平臺(tái)的移植的基礎(chǔ)上,并通過龍芯3B所支持的向量擴(kuò)展指令,對(duì)FFmpeg解碼器的各個(gè)關(guān)鍵模塊代碼進(jìn)行了向量優(yōu)化。文獻(xiàn)[13]結(jié)合飛騰多核DSP同構(gòu)多核架構(gòu)以及共享存儲(chǔ)的特點(diǎn),采用面向共享存儲(chǔ)系統(tǒng)結(jié)構(gòu)的工業(yè)標(biāo)準(zhǔn)Open MP,通過設(shè)立并行域以及設(shè)置私有變量對(duì)解碼程序有針對(duì)性地進(jìn)行了并行優(yōu)化。
文中基于國產(chǎn)自主可控平臺(tái)申威421,在對(duì)H.264解碼器的開源程序FFmpeg移植后,H.264視頻解碼效率低,高分辨率的視頻播放不流暢甚至卡頓,嚴(yán)重影響國產(chǎn)平臺(tái)桌面用戶體驗(yàn),阻礙了申威處理器的市場(chǎng)化進(jìn)度。針對(duì)此現(xiàn)象,文中充分利用了申威SIMD擴(kuò)展部件對(duì)多媒體程序進(jìn)行向量化并行。H.264解碼器性能顯著提升,解決了視頻播放不流暢問題,推動(dòng)了國產(chǎn)申威處理器市場(chǎng)化的發(fā)展。
H.264是國際標(biāo)準(zhǔn)化組織(ISO)和國際電信聯(lián)盟(ITU)共同提出的繼MPEG4之后的新一代數(shù)字視頻編解碼標(biāo)準(zhǔn)。最大的優(yōu)勢(shì)是具有比較高的數(shù)據(jù)壓縮比率,在相同圖像質(zhì)量的條件下,H.264的壓縮比是MPEG-2的2倍以上,是MPEG-4的1.5~2倍。H.264視頻編解碼標(biāo)準(zhǔn)沒有明確規(guī)定如何實(shí)現(xiàn)編解碼器,但規(guī)定了編碼視頻比特流的語法和比特流的解碼步驟方法[14]。
本研究主要基于FFmpeg的H.264解碼器進(jìn)行優(yōu)化。FFmpeg是一套基于Linux操作系統(tǒng)的開源編解碼解決方案,它集成了音視頻錄制、格式轉(zhuǎn)換和編解碼器,也可在大多數(shù)操作系統(tǒng)中編譯和使用[15]。它不僅包含各種音頻和視頻編解碼庫,還支持基于流媒體的實(shí)時(shí)流傳輸。
FFmpeg中H.264解碼器的解碼流程如圖1所示。首先通過函數(shù)h264_decode_frame解碼一幀圖像數(shù)據(jù),其中decode_nal_units是用于解碼NALU的函數(shù)。decode_nal_units首先調(diào)用ff_h264_decode_nal判斷NALU的類型,然后根據(jù)NALU類型的不同調(diào)用不同的解析函數(shù)和解碼函數(shù),解析函數(shù)包括解析SPS/PPS/SEI以及slice_head。ff_h264_execute_decode_slices用于解碼獲取圖像信息,ff_h264_execute_decode_slices調(diào)用了decode_slice函數(shù),在decode_slice函數(shù)中完成了熵解碼、變換與量化、宏塊解碼、環(huán)路濾波等解碼的細(xì)節(jié)工作。
圖1 H.264解碼器解碼流程
熵解碼部分的功能是讀取數(shù)據(jù)(宏塊類型、參考幀、運(yùn)動(dòng)矢量、殘差等),并按照H.264的語法和語義規(guī)則將其分配到H.264解碼器中相應(yīng)的變量中。其中熵解碼方面的函數(shù)有ff_h264_decode_mb_cabac和ff_h264_decode_mb_cavlc。分別用于解碼CABAC編碼方式的H.264數(shù)據(jù)和CAVLC編碼方式的H.264數(shù)據(jù)。
根據(jù)熵解碼后各宏塊的信息,函數(shù)hl_decode_mb會(huì)根據(jù)宏塊類型的不同做處理,主要針對(duì)幀間或者幀內(nèi)宏塊。如果是幀間預(yù)測(cè)宏塊,調(diào)用函數(shù)hl_motion_422或者函數(shù)hl_motion_420進(jìn)行四分之一像素運(yùn)動(dòng)補(bǔ)償;如果是幀內(nèi)預(yù)測(cè)宏塊,就會(huì)調(diào)用hl_decode_mb_predict_luma進(jìn)行幀內(nèi)預(yù)測(cè)。經(jīng)過幀內(nèi)預(yù)測(cè)或者幀間預(yù)測(cè)步驟之后,就得到了預(yù)測(cè)數(shù)據(jù)。最后hl_decode_mb會(huì)調(diào)用hl_decode_mb_idct_luma等幾個(gè)函數(shù)對(duì)殘差數(shù)據(jù)進(jìn)行DCT反變換,并將變換后的數(shù)據(jù)疊加到預(yù)測(cè)數(shù)據(jù)上,形成解碼后的圖像數(shù)據(jù)。
Decode_slice在完成宏塊解碼后,調(diào)用loop_filter函數(shù)進(jìn)行環(huán)路濾波工作。環(huán)路濾波主要是為了去除圖像變換量化后產(chǎn)生的塊狀視覺效應(yīng)。loop_filter函數(shù)遍歷該行宏塊中的每個(gè)宏塊,并且針對(duì)每一個(gè)宏塊調(diào)用ff_h264_filter_mb_fast。函數(shù)ff_h264_filter_mb_fast中h264_filter_mb_fast_internal完成一個(gè)宏塊的環(huán)路濾波工作。該函數(shù)分別調(diào)用filter_mb_edgev或filter_mb_edgeh對(duì)亮度垂直或邊界進(jìn)行濾波,和調(diào)用filter_mb_edgecv或filter_mb_edgech對(duì)色度的垂直或水平邊界進(jìn)行濾波。
文中在對(duì)H.264解碼器關(guān)鍵模塊進(jìn)行向量化并行時(shí)首先對(duì)熱點(diǎn)函數(shù)中的循環(huán)進(jìn)行向量化分析,分析循環(huán)內(nèi)是否具有數(shù)據(jù)相關(guān)性、對(duì)齊、連續(xù)等條件。如果滿足向量化分析,使用SIMD指令進(jìn)行替換。如果不滿足,分析是否可以通過循環(huán)變換數(shù)組重組等方法來滿足向量化分析,然后通過內(nèi)嵌匯編進(jìn)行向量指令替換。最后對(duì)向量化后的程序性能進(jìn)行測(cè)試,如果沒有性能提升,繼續(xù)對(duì)下一個(gè)循環(huán)進(jìn)行分析。
perf是內(nèi)置于Linux內(nèi)核源碼中的性能剖析工具?;谑录蓸雍托阅苁录脑瓌t,它支持處理器和操作系統(tǒng)相關(guān)性能指標(biāo)的性能配置文件,并可用于查找瓶頸和定位熱點(diǎn)代碼。本研究針對(duì)視頻序列foreman,使用perf工具列出了H.264解碼器在在整個(gè)視頻解碼過程中所占比重較大的熱點(diǎn)函數(shù),如表1所示。
表1 H.264解碼器熱點(diǎn)函數(shù)
熱點(diǎn)函數(shù)為應(yīng)用程序中耗時(shí)較多,執(zhí)行次數(shù)較多的函數(shù),對(duì)熱點(diǎn)函數(shù)進(jìn)行優(yōu)化相對(duì)來講性能提升比較明顯。通過性能分析工具可以發(fā)現(xiàn)熱點(diǎn)函數(shù)主要集中在宏塊解碼的幀內(nèi)預(yù)測(cè)、運(yùn)動(dòng)補(bǔ)償、環(huán)路濾波等模塊。上述函數(shù)幾乎占據(jù)整個(gè)解碼過程的55%,因此對(duì)上述函數(shù)中的循環(huán)做向量化,解碼器性能理論上可以得到顯著提升。
熱點(diǎn)函數(shù)中h264_qpel系列函數(shù)用于對(duì)1/4像素內(nèi)插做運(yùn)動(dòng)補(bǔ)償,其中h264_qpel_lowpass類函數(shù)完成了半像素內(nèi)插函數(shù)的初始化工作,主要對(duì)2×2、4×4、8×8大小的圖像方塊通過水平或垂直方向?yàn)V波計(jì)算半像素。H.264標(biāo)準(zhǔn)采用了一個(gè)6抽頭的有限脈沖響應(yīng)濾波器(finite impu1se response,F(xiàn)IR)進(jìn)行計(jì)算,濾波器系數(shù)為(1/32,-5/32,5/8,5/8,-5/32,1/32),雖然6抽頭濾波器比較復(fù)雜,但可以明顯改善運(yùn)動(dòng)補(bǔ)償性能[16]。半像素插值計(jì)算如圖2所示,半像素點(diǎn)(如b,h,m)通過對(duì)相應(yīng)整像素點(diǎn)(圖中灰色方塊)進(jìn)行6抽頭濾波得出。半像素b的計(jì)算可由同一行中的整像素E、F、G、H、I、J得出。計(jì)算公式見式(1),其中CLIP用于將取值限幅在0~255。
b=CLIP[(E-5F+20G-20H+5I+J+16)>>5]
(1)
圖2 1/2像素插值
對(duì)于1/2像素插值計(jì)算,由于計(jì)算需要像素每行的存儲(chǔ)規(guī)則,且像素間不存在數(shù)據(jù)相關(guān)性,這種計(jì)算密集,復(fù)雜度較高的運(yùn)算十分適合利用SIMD擴(kuò)展部件對(duì)其進(jìn)行向量計(jì)算,使用申威SIMD擴(kuò)展指令集可以一次性裝入一行整像素點(diǎn)。通過向量計(jì)算得到每行的1/2像素點(diǎn),循環(huán)8次就可以計(jì)算出8×8塊的64個(gè)1/2像素點(diǎn)。8×8圖像塊的每行的1/2像素點(diǎn)的SIMD計(jì)算如圖3所示。
圖3 1/2像素插值SIMD計(jì)算
申威擴(kuò)展指令集提供VLDW_U/VSTW_U非對(duì)齊裝入/存儲(chǔ)指令,可以從存儲(chǔ)器中取出8個(gè)32 bit或32個(gè)8 bit元素到256位向量寄存器,并支持不同長度的加/減移位等運(yùn)算。8 bit的像素可以一次裝入32個(gè)元素到256位向量寄存器/存儲(chǔ)器中,但對(duì)于8×8的圖像塊的1/2像素點(diǎn)的計(jì)算,只需使用向量寄存器的64位,每次進(jìn)行8個(gè)元素的運(yùn)算。函數(shù)put_h264_qpel8_h_lowpass優(yōu)化前和優(yōu)化后的代碼如下所示:
優(yōu)化前:
for(i=0; i { dst[0]=CLIP((((src[0]+src[1])*20-(src[-1]+src[2])*5+(src[-2]+src[3]))+16)>>5); dst[1]=CLIP((((src[1]+src[2])*20-(src[0]+src[3])*5+(src[-1]+src[4]))+16)>>5); ...... } 優(yōu)化后: for(i=0; i { vldw_u $f1,0(a0) vldw_u $f2,0(a1) vldw_u $f3,1(a1) vldw_u $f4,-1(a1) vldw_u $f5,2(a1) vldw_u $f6,-2(a1) vldw_u $f7,3(a1) ldwe $f10,0,(a2) vaddw $f2,$f3,$f2 vsllw $f2,4,$f8; vsllw $f2,2,$f9 vaddw $f8,$f9,$f8 vaddw $f4,$f5,$f4 vsllw $f4,2,$f9 vaddw $f9,$f4,$f9 vsubw $f8,$f9,$f8 vaddw $f6,$f7,$f6 vaddw $f8,$f6,$f8 vaddw $f8,$10,$f8 vsrlw $f8,5,$f8 vstw_u $f8,0(a0) } 首先從存儲(chǔ)器中取出以原像素點(diǎn)src[0]為起始的8個(gè)整像素點(diǎn)放置向量寄存器中,然后分別與依次擴(kuò)展1位的連續(xù)8個(gè)整像素點(diǎn)進(jìn)行向量運(yùn)算。其中乘法直接用加法和移位來代替,最后將計(jì)算的8個(gè)結(jié)果分別放置8個(gè)目標(biāo)分像素點(diǎn),完成一行的分像素點(diǎn)計(jì)算。接著增加步長進(jìn)行下一行的分像素點(diǎn)計(jì)算,循環(huán)8次完成8×8塊的分像素計(jì)算。使用申威SIMD指令進(jìn)行替換,一條SIMD指令可以同時(shí)進(jìn)行8次相同運(yùn)算,計(jì)算出每行的分像素點(diǎn),有效提升了分像素插值的效率。 對(duì)于4×4、2×2塊的水平或垂直方向的1/2像素插值計(jì)算向量化并行同8×8塊計(jì)算方法相似,只是4×4塊對(duì)于每行1/2像素點(diǎn)的計(jì)算只能一次進(jìn)行4個(gè)像素點(diǎn)計(jì)算。而對(duì)于雙向預(yù)測(cè)的1/2像素點(diǎn)的計(jì)算更加復(fù)雜一些,同樣適合使用SIMD指令來進(jìn)行向量化并行計(jì)算1/2插值點(diǎn)。 在H.264關(guān)鍵模塊算法中都存在滿足向量化分析的循環(huán),對(duì)此可以直接進(jìn)行向量指令替換。經(jīng)過1/4像素運(yùn)動(dòng)補(bǔ)償?shù)膸g或者幀內(nèi)預(yù)測(cè)后,就需要將殘差數(shù)據(jù)進(jìn)行DCT反變換,DCT系列函數(shù)中ff_h264_idct8_dc_add_8c對(duì)只有DC系數(shù)的8×8矩陣進(jìn)行整數(shù)DCT反變換。最內(nèi)層循環(huán)通過一條向量指令vaddw就可以實(shí)現(xiàn)對(duì)8×8像素每行與dc系數(shù)的累加來代替最內(nèi)層的8次循環(huán),降低了循環(huán)開銷。相對(duì)比較復(fù)雜的4×4整數(shù)DCT反變換函數(shù)ff_h264_idct_add_8_c,先對(duì)每列進(jìn)行一維整數(shù)變換,然后對(duì)經(jīng)過列變換塊的每行進(jìn)行一維整數(shù)變換,最后將變換后的殘差數(shù)據(jù)疊加來實(shí)現(xiàn)傳統(tǒng)整數(shù)變換的矩陣乘法。由于數(shù)據(jù)是以行來存儲(chǔ)的,所以使用SIMD擴(kuò)展指令可以先實(shí)現(xiàn)一行元素的整數(shù)變換,經(jīng)過四次向量計(jì)算完成整個(gè)塊的縱向一維整數(shù)變換。再對(duì)經(jīng)過縱向一維整數(shù)變換的塊進(jìn)行另一維的向量整數(shù)變換,最后通過向量指令進(jìn)行殘差數(shù)據(jù)疊加。而對(duì)于環(huán)路濾波中h264_loop_filter類函數(shù)由于循環(huán)內(nèi)數(shù)組訪問不連續(xù)以及存在控制流,不能直接向量化,需要對(duì)數(shù)組進(jìn)行重組,然后進(jìn)行向量化。 本次實(shí)驗(yàn)平臺(tái)基于國產(chǎn)自主可控平臺(tái)申威421,操作系統(tǒng)為deepin15.5,編譯器為申威自主研發(fā)編譯器swgcc-5.3.0。實(shí)驗(yàn)環(huán)境如表2所示,為使測(cè)試結(jié)果具有代表性,實(shí)驗(yàn)分別選取了3組不同分辨率720×486、1 600×960、2 048×1 024的視頻序列,視頻播放采用FFmpeg組件ffplay。 表2 實(shí)驗(yàn)環(huán)境 基于移植到申威平臺(tái)的H.264解碼器有很大性能提升。表3表示對(duì)各個(gè)熱點(diǎn)函數(shù)向量化與向量化后的性能對(duì)比,表4表示3個(gè)視頻序列在對(duì)解碼器中關(guān)鍵模塊向量化后的性能對(duì)比。 表3 各函數(shù)向量化前后性能對(duì)比 表4 測(cè)試視頻向量化前后性能對(duì)比 通過實(shí)驗(yàn)對(duì)比,對(duì)熱點(diǎn)函數(shù)中滿足向量化分析的循環(huán)進(jìn)行向量指令替換,增加了指令吞吐率,在保證原視頻清晰度的基礎(chǔ)上,視頻解碼性能有大幅度提升。其中函數(shù)put_h264_qpel8_h_lowpass向量化后加速比達(dá)到3.4,而函數(shù)put_h264_chroma_mcXY_8_c中由于對(duì)未知變量的乘法,需要對(duì)系數(shù)進(jìn)行判斷再執(zhí)行移位運(yùn)算來代替乘法繼續(xù)向量運(yùn)算,向量化指令更加復(fù)雜,加速比只有1.1。測(cè)試的3個(gè)視頻序列中football的解碼性能最高有35.3%的提升。并且CPU占用率明顯降低,釋放了CPU資源,2 048×1 024分辨率高的視頻播放流暢度更高,提高了國產(chǎn)申威平臺(tái)用戶的多媒體視覺體驗(yàn)。 本次研究針對(duì)H.264解碼器中的熱點(diǎn)函數(shù)使用SIMD擴(kuò)展部件來進(jìn)行向量化計(jì)算,提升解碼器性能。但是由于并沒有充分利用到256位向量寄存器,向量重組等技術(shù)存在一定開銷,向量化效果并沒有達(dá)到理想的提升。接下來將會(huì)針對(duì)熱點(diǎn)函數(shù)中由于數(shù)組非對(duì)齊及存在數(shù)據(jù)依賴等程序進(jìn)行重點(diǎn)分析,充分利用256位向量寄存器,更深層次地挖掘數(shù)據(jù)的并行性。隨著高性能計(jì)算的發(fā)展,SIMD擴(kuò)展部件仍然是程序加速的重要手段,SIMD擴(kuò)展部件結(jié)構(gòu)簡單、功耗低、加速效果明顯,不需要增加通信以及cache和內(nèi)存的開銷,在多媒體領(lǐng)域,數(shù)字信號(hào)處理中都起著關(guān)鍵作用。而如何充分利用SIMD擴(kuò)展部件更深層次地挖掘數(shù)據(jù)并行性,提升程序性能,是長久的工作重心。3 實(shí) 驗(yàn)
3.1 實(shí)驗(yàn)環(huán)境
3.2 實(shí)驗(yàn)結(jié)果分析
4 結(jié)束語