李 紅,李 旸,張文將,王 力
H.264是由ITU-T的VCEG(視頻編碼專家組)和ISO/IEC的 MPEG(活動(dòng)圖像編碼專家組)聯(lián)合開(kāi)發(fā)的新一代視頻編解碼標(biāo)準(zhǔn)[1-3],它在獲得更好壓縮性能的同時(shí)增加了算法的時(shí)間復(fù)雜度。JM是JVT公開(kāi)發(fā)布的H.264官方測(cè)試模型,與官方標(biāo)準(zhǔn)相對(duì)應(yīng),理解H.264的編解碼模型是學(xué)習(xí)H.264的基礎(chǔ)。盡管H.264的每個(gè)JM版本都盡可能的實(shí)現(xiàn)了H.264當(dāng)時(shí)的所有特性,但是JM忽視了編碼的復(fù)雜度,使代碼閱讀的難度加大。JM8.6是JM 的一個(gè)經(jīng)典開(kāi)源模型[4-5],沒(méi)有更高版本針對(duì)高分辨率和高清晰度有特別要求的FRExt分支,也沒(méi)有引進(jìn)最新的運(yùn)動(dòng)搜索以及快速模式選擇算法,它的研究對(duì)于更快的掌握H.264的核心內(nèi)容具有重要的意義。
JM8.6模型可以在 http://iphome.hhi.de/suehring/tml/網(wǎng)站上進(jìn)行免費(fèi)下載,用C語(yǔ)言編寫而成,下面介紹在VC++6.0上運(yùn)行JM8.6的步驟[6]。
(1)下載解壓JM8.6源代碼文件,檢查源代碼根目錄下的bin文件,在確保存在配置文件encoder_*.cfg、待編碼視頻序列文件foreman_part_qcif.yuv和解碼配置文件decoder.cfg之后,打開(kāi)源代碼根目錄下的工作區(qū)tml.dsw。
(2)編碼:鼠標(biāo)選中“l(fā)encod工程”,打開(kāi)“工程——設(shè)置——調(diào)試”,在“工作目錄”下填寫./bin,“程序變量”中填寫-dencoder_baseline.cfg,點(diǎn)擊“確定”,將“l(fā)encod工程”選中右擊鼠標(biāo),選中“設(shè)為活動(dòng)工程”并編譯運(yùn)行,成功完成編碼之后檢查源代碼根目錄下的bin文件夾,其中test.264即為壓縮碼流文件。
(3)解碼:鼠標(biāo)選中“l(fā)decod工程”,進(jìn)行同樣設(shè)置之后在“程序變量”中填寫decoder.cfg。解碼編譯成功后,檢查源代碼根目錄下的bin文件夾,test_dec.yuv即為解碼文件。
H.264之所以比以往的視頻編碼算法優(yōu)越是因?yàn)槠湟M(jìn)了很多先進(jìn)的技術(shù),包括4×4整數(shù)變換、空域內(nèi)的幀內(nèi)預(yù)測(cè)、1/4像素精度的運(yùn)動(dòng)估計(jì)、多參考幀與多種大小的塊的幀間預(yù)測(cè)技術(shù)、率失真優(yōu)化技術(shù)等[7]。新技術(shù)帶來(lái)了較高的壓縮比,同時(shí)也大大提高了算法的復(fù)雜度。圖1為H.264編碼的總體過(guò)程[8],可以看出整個(gè)過(guò)程關(guān)鍵處就是循環(huán)編碼每個(gè)宏塊。
代價(jià)函數(shù)是一種編碼策略,即采用幀內(nèi)編碼與采用幀間編碼的最優(yōu)選擇,其實(shí)質(zhì)是使當(dāng)前資源達(dá)到最佳結(jié)果的分配問(wèn)題。理解代價(jià)函數(shù)是理解程序代碼工作方式的關(guān)鍵。H.264中用到的代價(jià)共有三種:運(yùn)動(dòng)矢量代價(jià)MV_COST,參考幀代價(jià)REF_COST,模式代價(jià)MODE_COST。這三種代價(jià)共同作用選擇出合適的運(yùn)動(dòng)矢量、參考幀和宏塊的最佳分割方式。除了運(yùn)動(dòng)矢量代價(jià)MV_COST在RDO模式和非RDO模式下有相同的過(guò)程,其余兩種都是可以依據(jù)不同情況的需要選擇RDO模式和非RDO模式。
圖1 H.264編碼的總體過(guò)程
運(yùn)動(dòng)矢量代價(jià)主要用于運(yùn)動(dòng)搜索模塊中,通過(guò)比較MV_COST來(lái)得到最佳預(yù)測(cè)塊,公式如下:
式中SAD表示原始圖像塊與參考幀搜索位置塊的絕對(duì)差值和。如果使用了Hadamard變換,則SAD就表示成SATD[9],表示對(duì)原始圖像和預(yù)測(cè)圖像之間的差值矩陣進(jìn)行Hadamard變換之后的矩陣求絕對(duì)值。MVbits是編碼運(yùn)動(dòng)矢量MV的比特?cái)?shù),查詢mvbits[]列表可得。具體計(jì)算是在PartitionMotionSearch()函數(shù)中,該函數(shù)的主要功能是對(duì)每個(gè)分塊進(jìn)行運(yùn)動(dòng)搜索并計(jì)算得出代價(jià)。在JM8.6中的代碼如下:
調(diào)用BlockMotionSearch()函數(shù)進(jìn)行每個(gè)分塊的運(yùn)動(dòng)搜索,可以得到運(yùn)動(dòng)向量并將對(duì)應(yīng)的代價(jià)作為函數(shù)的返回值,更新motion_cost,為接下來(lái)的參考幀選擇提供依據(jù)。motion_cost是一個(gè)全局變量,該數(shù)組存儲(chǔ)了一個(gè)宏塊的分塊在不同幀間模式和參考幀下的運(yùn)動(dòng)估計(jì)的開(kāi)銷值。
參考幀代價(jià)是用來(lái)選擇最優(yōu)參考幀,其在RDO方式下和非RDO方式下,定義有所不同。
非RDO方式時(shí):
RDO方式時(shí):
參考幀號(hào)是參考幀的編號(hào),REFbits在JM同樣用查詢r(jià)efbits[]列表可得。在以下的JM8.6的代碼中,可以看出是分為RDO方式和非RDO方式計(jì)算的。
觀察代碼 mcost+=motion_cost[mode][LIST_0][ref][block]了解到運(yùn)動(dòng)矢量代價(jià) motion_cost和REF_COST代價(jià)都加到了中間變量mcost中,共同用于最佳模式的選擇。
幀內(nèi)與幀間模式的選擇過(guò)程是H.264中非常重要的一部分,涵蓋了H.264編碼中的大部分內(nèi)容,是在其核心函數(shù)encode_one_macroblock()中結(jié)合代價(jià)函數(shù)的計(jì)算實(shí)現(xiàn)的[10]。
為了簡(jiǎn)明起見(jiàn),本文直接考慮待編碼的宏塊屬于P Slice(I Slice模式包括在此之中且不考慮P Skip模式),通過(guò)對(duì)JM8.6模型的代碼分析,得出在幀間宏塊級(jí)(16×16,16×8,8×16)、亞宏塊級(jí)P8×8(8×8,8×4,4×8,4×4)以及幀內(nèi)的兩種大模式I16MB、I4MB中選出最優(yōu)的分割模式流程圖,如圖2。
圖2 最優(yōu)的分割模式選擇過(guò)程
因?yàn)镠.264編碼器為了得到最佳的模式通常采用RDO技術(shù)[10-11],對(duì)每一種模式計(jì)算出率失真代價(jià)RDCost,所以這里主要分析RDO方式下的模式選擇過(guò)程。根據(jù)配置文件中的RDOptimization的取值決定是否使用拉格朗日率失真優(yōu)化模型進(jìn)行模式選擇,0為關(guān)閉,1為打開(kāi),2為考慮丟包等情況下的率失真。
RDO方式下的模式開(kāi)銷公式為:
SSD為當(dāng)前塊和重構(gòu)塊的差值,BLOCKbits表示編碼所需要的比特?cái)?shù),調(diào)用熵編碼函數(shù)確定。RDO方式下,幀間和幀內(nèi)的模式選擇是一起進(jìn)行的,通過(guò)在 RDCost_for_macroblocks()中計(jì)算幀間宏塊級(jí)(16×16,16×8,8×16)、亞宏塊級(jí)P8×8(8×8,8×4,4×8,4×4)和幀內(nèi)的I16MB、I4MB對(duì)應(yīng)模式的RDO代價(jià),進(jìn)行比較得到最優(yōu)的模式。
(1)對(duì)于幀間的宏塊級(jí)模式調(diào)用函數(shù)Luma-ResidualCoding()對(duì)宏塊的殘差進(jìn)行編碼,具體是將一個(gè)宏塊分為4個(gè)8×8塊分別進(jìn)行編碼,調(diào)用LumaResidualCoding8x8()函數(shù)對(duì)8×8塊的4個(gè)4×4塊分別進(jìn)行預(yù)測(cè)、dct變換等。LumaResidualCoding8x8()的主要工作分為三步:
第一步:因?yàn)镻artitionMotionSearch()函數(shù)在進(jìn)行運(yùn)動(dòng)搜索的時(shí)候已經(jīng)計(jì)算出了運(yùn)動(dòng)矢量mv保存在了img->all_mv中,所以在Luma-Prediction4x4()函數(shù)中直接進(jìn)行預(yù)測(cè)值的計(jì)算,保存在img->all_mv中。
第二步:在LumaResidualCoding8x8()中計(jì)算得到殘差,保存在img->m7中。
第三步:調(diào)用dct_luma()函數(shù)對(duì)殘差數(shù)據(jù)完成DCT變換,量化,反量化,反DCT變換,將重建值存儲(chǔ)在enc_picture->imgY中。
(2)因幀間的亞宏塊模式的RDO代價(jià)計(jì)算和非RDO模式相結(jié)合,所以在 RDCost_for_macroblocks()函數(shù)中只是調(diào)用函數(shù)SetCoeffAndReconstruction8x8()設(shè)置參數(shù)。跟蹤代碼進(jìn)入亞宏塊模式的非RDO計(jì)算,發(fā)現(xiàn)調(diào)用 RDCost_for_8x8blocks()函數(shù)進(jìn)行了RDO代價(jià)計(jì)算。繼續(xù)跟蹤RDCost_for_8x8blocks()函數(shù),最終也是調(diào)用了LumaResidualCoding8x8()函數(shù)對(duì)8×8塊進(jìn)行亮度值的預(yù)測(cè)、殘差數(shù)據(jù)的變換量化、反變化反量化以及重建圖像的計(jì)算和保存。此函數(shù)還調(diào)用熵編碼函數(shù)進(jìn)行計(jì)算比特值,包括模式,運(yùn)動(dòng)矢量和亮度殘差數(shù)據(jù)的比特計(jì)算。
(3)進(jìn)行幀內(nèi)I4MB的9種模式選擇時(shí),調(diào)用Mode_Decision_for_8x8IntraBlocks()函數(shù)計(jì)算每一個(gè)8×8塊的代價(jià)。每個(gè)8×8塊又細(xì)分為4×4塊的代價(jià),調(diào)用 Mode_Decision_for_4x4IntraBlocks()函數(shù)實(shí)現(xiàn),累加起來(lái)得到一個(gè)8×8塊的代價(jià),具體過(guò)程分為兩步:
第一步:利用intrapred_luma()函數(shù)計(jì)算出9種預(yù)測(cè)模式下的預(yù)測(cè)值保存在img->mprr中。
第二步:調(diào)用 RDCost_for_4x4IntraBlocks()函數(shù),計(jì)算返回的rdcost即是9種模式中比較得出的最優(yōu)代價(jià),保存在min_rdcost中,同時(shí)最優(yōu)模式保存在best_ipmode中。
(4)對(duì)于幀內(nèi)I16MB模式的代價(jià)計(jì)算,RDO模式與非RDO模式相同,但在RDO模式下要進(jìn)行rdcost的計(jì)算。具體過(guò)程分為三步:
第一步:調(diào)用intrapred_luma_16x16()函數(shù)計(jì)算I16MB模式下的預(yù)測(cè)值,保存在img->mprr_2中。
第二步:調(diào)用find_sad_16x16(i16mode),依據(jù)SAD比較得到最優(yōu)的I6MB模式。
第三步:調(diào)用dct_luma_16x16()函數(shù)進(jìn)行亮度的DCT變換等。
(5)以上的分析都是分別在幀間宏塊級(jí)、亞宏塊級(jí)和幀內(nèi)的I4MB,I16MB中選擇最佳模式。函數(shù)的最后計(jì)算失真distortion(包括亮度和色度)和碼率,按照公式(5)計(jì)算出最優(yōu)的代價(jià)以及最優(yōu)模式。
rdcost= (double)distortion+lambda *(double)rate (5)
以上所得,得出 RDCost_for_macroblocks()函數(shù)調(diào)用框圖如圖3所示。
圖3 RDCost_for_macroblocks()函數(shù)調(diào)用框圖
JM8.6作為經(jīng)典測(cè)試模型,雖壓縮性能提高,但算法復(fù)雜不便理解?,F(xiàn)對(duì)其內(nèi)部結(jié)構(gòu)的研究有助于H.264算法的學(xué)習(xí)。本文先介紹了JM8.6的安裝方法,后以待編碼宏塊P Slice為例,通過(guò)追蹤RDO方式下代價(jià)函數(shù)的代碼,得出encode_one_macroblock()函數(shù)的幀內(nèi)與幀間選擇流程圖,也明確了RDCost_for_macroblocks()函數(shù)內(nèi)部各個(gè)子函數(shù)的調(diào)用結(jié)構(gòu)框圖以及作用。在此基礎(chǔ)上,研究的下一步將是對(duì)JM8.6模型中復(fù)雜的算法進(jìn)行優(yōu)化,以縮短編碼時(shí)間和提高編碼效率。例如在encode_one_macroblock()函數(shù)中進(jìn)行幀內(nèi)與幀間選擇模式的算法優(yōu)化,在BlockMotionSearch()函數(shù)中定義更加快速更加精確的運(yùn)動(dòng)搜索算法。
[1]JVT of ITU-T VCEG and ISO/IEC MPEG.Final draft international standard of joint video specification.JVT-G050.2003.
[2]畢厚杰,王 健.新一代視頻壓縮編碼標(biāo)準(zhǔn)——H.264/AVC[M].北京:人民郵電出版社,2009.
[3]Iain E.G.Richardson.H.264and MPEG-4Video Compression[M].England:John Wiley & Sons Ltd,2003.
[4]陳 舉,趙 琦,董金明.H.264編解碼軟件JM8.6的核心編碼函數(shù)研究[J].計(jì)算機(jī)工程與設(shè)計(jì),2008,29(17):4498-4506.
[5]ITU-T Recommendation H.264,Advanced video coding for generic audiovisual services[S].
[6]在 VC中編譯運(yùn)行JM 視頻教程[EB/OL].http://www.chinavideo.org/forum.php?mod=view thread &tid=997,2006-9-27/2013-7-10.
[7]鄧中亮,段大高,崔巖松,等.基于 H.264的視頻編/解碼與控制技術(shù)[M].北京:北京郵電大學(xué)出版社,2011.
[8]陳 靖,劉 京,曹喜信.深入理解視頻編解碼技術(shù)——基于H.264標(biāo)準(zhǔn)及參考模型[M].北京:北京航空航天大學(xué)出版社,2012.
[9]JM8.6中幀內(nèi)幀間模式的選擇[EB/OL].http://www.chinavideo.org/forum.php? mod = view thread&tid =11403&extra=page%3D5,2011-4-23/2013-08-01.
[10]謝翠蘭,鄭藝玲.基于SAD和SATD的 H.264快速幀內(nèi)預(yù)測(cè)算法[J].計(jì)算機(jī)工程,2008,34(10):215-217.
[11]王維哲,周 兵,張行進(jìn).H.264編碼中的幀內(nèi)預(yù)測(cè)模式選擇算法[J].計(jì)算機(jī)工程,2008,34(2):226-228.