H.264算法的優化策略

文章來源: http://www.tichinese.com/Article/Video/200909/2150.html 編輯:小乙哥

1 代碼優化的主要方法

通過代碼移植能夠獲得在DSP上初步運行的代碼,但是它由于沒有考慮到DSP自身的硬件特點,不適合DSP強大的并行處理能力,因此執行效率低下,不能滿足我們的實時要求,需要對其進行進一步優化。

對DSP代碼進行優化的手段有以下三個層次,分別是:項目級(Project)優化,算法級(algorithm)優化,指令級(instruction)優化。下面對這三種優化手段分別進行介紹。

1)項目級優化

項目級優化,是對項目的整體優化,主要手段有以下幾點:
首先是在對整個項目進行編譯鏈接生成DSP代碼時,合理選擇配置編譯器選項,并針對這些參數選擇,對程序進行調整和修正。其中進行的工作有:

  • 項目編譯時,通過-o3選項來調用最高級別的軟件流水線優化,通過-mw選項來調用軟件流水線循環反饋,從而增大軟件編譯成DSP代碼的并行性。
  • 項目編譯時,用-pm,-o3和-mt選項來改善循環,多重循環,龐大循環體循環的性能。
  • 只讀變量聲明成const型,循環計數器定義為int型,從而加大DSP代碼的并行性。

其次對程序結構進行調整,對不適合DSP執行的語句進行改寫,以提高代碼的并行性。例如,DSP處理器并行性很高,能夠對代碼進行流水線處理,但是原始代碼存在大量條件判斷語句,會對流水線造成中斷,不利于代碼的并行處理,因此,可以采用判斷提前,去除不必要的判斷等方式減少判斷語句對流水線的中斷。

2)算法級優化

算法級優化,就是利用H.264的自身特點,采用一些快速算法,在不影響編碼質量的前提下,提高編碼器速度,從而在速度和質量上達到一個較好的平衡。

3)指令級優化

上述方法無法達到要求時,就要進行指令級優化。C64x系列DSP有豐富的具有高度并行性處理能力的指令。下面介紹一些C64x系列DSP媒體處理相關指令。

  • ADD4:加法指令,一次執行4對8位數的加法。一個寄存器有32位,可以存放4個8位數據。計算中,兩個源寄存器中的四組對應8位數據 分別相加,結果存放在目標寄存器中。
  • AVGU4:一次執行4對8位無符號數據求平均運算。計算中,兩個源寄存器中的4組8位無符號型緊縮字求平均,結果以4個8位緊縮字的 形式存放在目標寄存器中。
  • DOTPU4:一次執行4對8位無符號數據點乘運算。計算中,兩個源寄存器中的4組8位無符號型緊縮字對應相乘,乘積相加,所得結果存放 在32位寄存器中
  • SUBABS4:一次執行4對8位無符號數據求差絕對值運算。計算中,兩個源寄存器中的4組8位無符號型緊縮字對應相減,差值求絕對值,所得結果以4個8位緊縮字的形式存放在目標寄存器中。
  • LDB/LDH/LDW/LDDW:將8位,16位,32位或64位數據讀入目標寄存器中,所讀取的數據在內存中是地址align(32位對齊)的數據。
  • LDNW/LDNDW:將一個32位或64位的非對齊數據讀入目標寄存器中。
  • STB/STH/STW/STDW:將8位,16位,32位或64位數據寫入內存中,所寫入的數據在內村中是地址align(32位對齊)的數據。
  • STNW/STNDW:將一個32位或64位的非對齊數據寫入內存中。

除了這些高并行度的指令,TI還提供了豐富的算法庫[37],如Image/Video Processing Library圖像/視頻處理庫(IMGLib),Digital signal processor Library數字信號處理庫(DSPLib)等。這些算法庫中的函數都是已經充分優化過的算法模塊,而且大都提供對應的C、線性匯編和匯編源代碼,并有文檔進行API介紹。所以要充分利用。

2 算法關鍵模塊的優化

對模塊的優化分三步進行。先認真分析代碼,并進行相應的調整,例如盡量減少有判斷跳轉的代碼,特別是在for循環中,因為判斷跳轉會打斷軟件流水。可以用查表或者用_cmpgtu4、_cmpeq4等intrinsic來代替比較判斷指令,從而巧妙地替代判斷跳轉語句。同時還可以采用TI的CCS中所提供的#pragma,為編譯器提供盡量多的信息。這些信息包括for循環的次數信息、數據對齊信息等。如果經過這部分優化后還無法滿足系統要求,則對這部分模塊使用線性匯編來實現。

2.1 整數變換和量化

整數變換和反變換的運算步驟見下表:

H.264算法的優化策略1

圖1 DCT與IDCT的運算步驟

整數運算和反變換的次數極多,比如,在D1格式下,4?4DCT等要做21600次,如果算上其他大小宏塊的這些變換,時間消耗還是很多的,所以仍然有優化的必要。下面以整數變換為例介紹如何用線性匯編對C語言代碼進行優化:

1)預測殘差的輸入

DCT和IDCT優化的關鍵是在數據的讀和寫上。讀寫指令是和存儲器操作相關的,所以要盡量減少其操作的次數。優化時可以用LDNW(無邊界調整字(四字節)讀取)和STNW(無邊界調整字(四字節)存儲)來代替單字節讀取和存儲,然后在寄存器內部再對數據進行打包處理,這樣可以大大提高速度。讀入方法如下:

LDNDW *A4, a1:a0 ;第一行數據

LDNDW *+A4(8), a3:a2 ;第二行數據

LDNDW *+A4(16), b3:b2;第三行數據

LDNDW *+A4(24), b1:b0;第四行數據

寄存器A4是系統指定用來保存函數返回值的。8字節的數據的讀入要保存到寄存器對中。

2)行變換的實現

C64x里面有多種加法指令,寄存器內容可作為32位數據相加,也可作為兩個16位數據相加,也可以作為四個8位數據相加。對應于上面的數據輸入方法,我們采用16位相加,并使用.S功能單元。實現方法如下:

加法指令

ADD2 a0, b0: r_00 ;a + d

ADD2 a1, b1: r_01 ;

ADD2 a2, b2: r_10 ;b + c

ADD2 a3, b3: r_11 ;

減法指令

SUB2 a2, b2: r _20 ; b - c

SUB2 a3, b3: r_21 ;

SUB2 a0, b0: r_30 ; a - d

SUB2 a1, b1: r_31 ;

另外,因為在C64x指令中沒有對兩個16位數據同時左移的指令,同時DM642的乘法指令可 以在一個周期內完成,所以在表1中求B, D時要使用MPY2指令實現向左的移位運算。由于乘法運算后數據的位數要進行擴展,因此MPY2的結果需要放入一個寄存器對,但實際有效數據不會超過16 位,因此完成乘法后我們又把數據兩兩打包在一個寄存器里,以方便在下面的列變換中進行數據的并行處理。實現方法如下:

MPY2 r_30, r _t,r_tl:r_ t0 ;2*(a-d) r_ t=0x00020002

MPY2 r-31, r_t,r_t3:r_t2

PACK2 r_t 1, r_t0, r_t0

PACK2 r_t3, r_t2, r_t2

3)列變換的實現

行變換后數據以行優先方式存放在4個寄存器對內。所以在進行列變換前要對寄存器內的數據進行轉置調整,以方便我們使用上述的數據并行處理指令。

第一列

PACK2 .S1 a2, a0, r_ m00

PACK2 .S2 b0, b2, r_ m01

第二列

PACKH2 .Ll a2, a0, r_ m10

PACKH2 .L2 b0, b2, r ml l

第三列

PACK2 .S1 a3,a1,r -m20

PACK2 .S2 b1,b3,r_ m21

第四列

PACKH2 .Ll a3,a1,r -m30

PACKH2 .L2 b1,b3,r_ m31

經過寄存器中數據的轉置處理后,我們就可以使用與行變換類似的程序進行列變換的實現。

4)輸出變換結果

列變換的結果即為整數變換的結果,但是輸出之前必須進行第二次轉置處理,使得輸出數據仍然為行優先方式存儲。

STNDW r_mOut0l:r mOut00, *A4

STNDW r_mOut1l:r mOut10, *A4(8)

STNDW r_mOut2l:r mOut20, *A4(16)

STNDW r_mOut3l:r mOut30, *A4(24)

5)檢查生成的匯編代碼并對線性匯編代碼進行相應的調整,以提高效率。如,避免使用A16~A31和B16~B31寄存器,因為這兩組寄存器需要被保護,如果被使用,編譯器會花額外的時間對這些寄存器進行保護操作,這會打斷流水,降低效率。

線性匯編代碼中用“.cproc” 和“.endproc”命令限定了需要優化器優化的代碼段,“.reg”命令允許使用將要存入寄存器的數值描述名字,也就是為寄存器設定了一個標識符。寄存器A4是系統指定用來保存函數返回值的。

量化(DCT)和反量化(IDCT)與整數變換相比多了if判斷,如下所示:

for(i = 0 ; i < 16 ; i ++)

{

if (data[i] > 0)

{

data[i] = (data[i] * quant[mf_index][i] ) >> qbits;

}

else

{

data[i] = -(-(data[i] * quant[mf_index][i]) >> qbits);

}

}

而判斷指令會打斷軟件流水,所以應該避免使用。觀察代碼可知,進行移位操作的都是正數,所以優化時可以對絕對值進行操作,而把符號放在另外的存儲器中,移位計算后再將符號加上去。

比較線性匯編優化前后的性能,我們可以發現效果相當明顯。

H.264算法的優化策略1

圖2 優化前后比較

DCT和量化實際上是兩個相關聯的部分,總是成對出現,我們可以把DCT和量化一起完成,這樣數據可以在寄存器中完成運算,節省了數據存儲和讀取時間。

2.2 熵編碼和解碼

2.2.1 查表方法的改進

CAVLC編碼按如下步驟進行:

1.編碼非零系數的個數(TotalCoeffs)和TrailingOnes的個數(Coeff_token)

通過查表進行,表有5個,定義在結構h264_coeff_token[5][17*4]中,選擇碼表的依據是當前塊上面和左面塊的非零系數個數(N0和N1)。由這兩個值計算一個參數N來查表。這就是所謂的基于上下文自適應(context adaptive)。

2.對每個TrailingOnes的符號進行編碼

對于每個TrailingOnes都要用一個比特來表示它的符號 (0代表正,1代表負)。符號的編碼是逆序進行的,即從最高頻的TrailingOnes開始編碼。

3.對除TrailingOnes之外的非零系數的level值進行編碼

當前塊中每個余下的非零系數的level值 (符號和絕對值) 都將按照逆序進行編碼,即從最高頻的系數開始到DC系數結束。編碼每個level所用的查找表是依據先前己編碼系數的level的絕對值來決定的(上下文自適應)。按原來的做法,此處將查7個表Level_VLC0到Level_VLC6。Level_VLC0適合編碼較小的絕對值;Level_VLC1 適合編碼稍大的絕對值,依此類推。現在采用一種新的查表方式,將非零系數的幅值(Levels)分成兩部分:前綴(level_prefix)和后綴(leve_suffix)。前綴和后綴的求法和一個變量suffixLength有關,如下公式:

H.264算法的優化策略1

變量suffixLength是基于上下文模式自適應更新的,它的更新與當前的 suffixLength的值以及已經解碼好的非零系數的值(Level)有關。這樣可通過更新suffixLength的值將各種非零系數的前綴都控制在一個較小的范圍內,這樣既有利于碼表的構建又有利于提高查表的速度,更新后的算法僅需要一個level_prefix的碼表,碼表如下。

H.264算法的優化策略1

圖3 level_prefix碼表

文章來源: http://www.tichinese.com/Article/Video/200909/2150.html 編輯:小乙哥
level_suffix的編碼只需先按照公式4.1計算出數值,然后根據suffixLength的值來確定后綴的長度即可,無需另外建立碼表。

總體來說,更新的查表方法有以下兩個特點:

1) 大的碼表分解成若干小碼表,縮小了搜索范圍。

2) 利用小碼表中碼字的規律快速確定參數在碼表中的位置。

4.對TotalZero進行編碼

TotalZero代表DC系數與最高頻的非零系數之間零系數的個數。之所以要單獨對TotalZero進行編碼是因為在系數序列的低頻部分往往會含有多個非零系數,而如果編碼TotalZero就可以避免去編碼系數序列低頻部分的一些零游程。

5.對每個run-before進行編碼

run-before表示當前非零系數與下一個非零系數之間零系數的個數。 run-before需要按照逆序編碼。從高頻系數開始,每個非零系數的run-before都要進行編碼,但有兩個例外:

(1)如果沒有余下的零系數需要編碼,則沒必要再編碼任何zero-run( 即之前編碼的run-before之和等于TotalZero)。

(2)沒有必要對最后一個 (最低頻) 非零系數的run-zero進行編碼。

至此,完成了CAVLC編碼。

在熵解碼時,TotalCoeff、TrailingOnes、TotalZeros和 Run_before的值都是直接查表求的,過程比較簡單,此處不進行介紹。在解碼除拖尾系數之外的非零系數幅值時先從當前解碼位置起逐個比特進行檢測,直到找到第一個比特“1”為止。此比特之前,經檢測為“0”的比特的個數就是前綴值。通過前綴值找到對應的碼表,并決定后綴的長度。最后讀入后綴值。利用上面公式反向計算就可得到非零系數的幅值。

2.2.2 函數的優化

CAVLC編碼前要將4×4的殘差塊轉換成zig-zag排列,如圖4所示。

H.264算法的優化策略2

圖4 4×4亮度的zig-zag掃描

Zig-zag掃描后,按步驟是先對掃描后數據的進行逆序遍歷,求出非零系數和拖尾系數的數目之后再開始編碼寫碼流。

函數調用時,要將PC和一些寄存器壓棧保存,函數返回時,則要將這些寄存器出棧返回,增加了一些不必要的操作,因此要對這部分函數進行修改。

C代碼中,zig-zag掃描是由一組賦值語句完成的,將順序排列的16個數的數組轉換成 zig-zag順序排列的數組。編譯器將這段代碼轉化為匯編代碼是將16個數讀入寄存器后再進行排列后寫回的,這時要讀寫一次寄存器,之后遍歷數組求非零系數和拖尾系數時又要讀寫一次寄存器。我們可以將zig-zag掃描的函數改寫成線性匯編代碼,將數據讀入到寄存器后就進行遍歷,另外用寄存器作計數器,記下非零系數和拖尾系數的數目,然后將zig-zag排列的數據和求得的系數一次寫回,這樣就省掉了一次寄存器的讀寫,多次累計起來省掉的時間開銷還是相當可觀的。

CAVLC編碼和解碼中多次調用寫碼流函數和讀碼流函數,由于調用次數很多,可以將這些函數表示成內聯函數,優化效果也相當明顯。比如,完成100次C代碼的寫碼流函數BitstreamPutBits花費4075個cycle,而表示成內聯函數后僅需要2600個cycle。

2.3 幀內預測

2.3.1 幀內4×4 預測模式判別方法的改進

計算4×4 預測模式的過程就是對4×4 塊的9 種預測模式進行計算的過程,分別求出各個模式的SAD值,選取SAD 值最小的預測模式為最優預測模式,因此編碼器的計算復雜度很高。

參考相關文獻可以對判別方法進行如下改進:由于在H.264 中,殘差矩陣量化前后的變換系數都是整數,只要4×4 變換前的殘差矩陣滿足如下條件,其殘差系數量化后的值就是全零。

H.264算法的優化策略2

公式1

其中 為殘差矩陣對應位置的值,H.264算法的優化策略2H.264算法的優化策略2QE是量化參數矩陣,對于給定的H.264算法的優化策略2H.264算法的優化策略2中的最小值。根據相鄰塊的預測模式預測當前4×4 塊的最可能預測模式為predmode。根據此預測模式取其殘差矩陣,對其殘差做H.264算法的優化策略2,并判斷是否H.264算法的優化策略2。如果不等式成立,則當前最可能的預測模式predmode 就是最優預測模式bestmode,結束此4×4 塊的預測模式判斷。否則,對此4×4 塊的其他預測模式進行判斷。對其中的一種預測模式計算它的預測殘差矩陣,判斷不等式H.264算法的優化策略2是否成立,如果成立,則此預測模式為此前4×4 塊的最優預測模式bestmode,結束此4×4 塊的預測模式判斷。否則對此4×4 塊的其他預測模式進行同樣處理,直至9 種預測模式都進行了判斷,獲得一個最優的預測模式。

同時,在改進算法中,對于那些判斷殘差進行變換量化后結果為全零的4×4 塊進行了特別處理。由于這些4×4 塊的殘差經過變換量化后結果為全零,對它們的殘差再進行變換、量化、反量化和反變換就失去了意義,因此可以對這些處理過程進行簡化。具體操作為:對這些 4×4塊的殘差矩陣直接全賦值為零,并對Z 掃描的結果也同樣賦值為零,從而省去了變換、量化、反變換和反量化,并且對編碼結果和圖像的重構結果都不會有影響,能夠進一步減少計算復雜度。

2.3.2 亮度預測的并行實現和線性匯編優化

4×4子塊亮度預測除在匯編指令級采用超長指令字VLIW并行執行8條指令外,主要采用數據并行、線性匯編優化和使用軟件流水進行優化處理。

4×4子塊亮度預測時的數據都是0~255,即unsigned char,在DSP中占一個字節:采用寄存器組A、B并行處理4×4子塊前兩行與后兩行兩塊數據,采用寄存器高低位并行處理兩行數據,如圖5所示。這樣并行處理得到近似為4的加速比。

H.264算法的優化策略2

圖5 4×4亮度塊預測數據并行

觀察4×4子塊亮度預測的九種預測模式,我們會發現后6種預測模式16個像素點的預測有很強的相關性,使用軟件流水線可以得到較好的效果。以模式3 (左下對角線模式)為例,16個像素點分別由公式2得出。

H.264算法的優化策略2

公式2

線性匯編的編寫過程如下:

1.用四字節的讀寫指令代替單字節的讀寫指令

利用LDNW指令用兩次將ABCD和EFGH讀入到兩個寄存器中,利用STNW指令分四次將數據存儲。

2.重新組裝寄存器里的數據

ABCD和EFGH并不是分開的,總是四個一組進行計算。公式4.2中1、2式的操作數是 ABCD,3、4式是CDEF,5、6、7式是EFGH。因而我們不需要將ABCD與EFGH完全拆開存儲,只需要將ABCD中的高半字和EFGH中的低半字拆出來存到一個獨立的寄存器中。這條指令是PACKHL2。

3.分析運算式規律,選擇最簡單的運算指令

所有的運算中,都存在一個計算式X+2Y+Z,同時有三個unsigned char型數據參加運算,下面一條C6400系列的匯編指令正好可以用于此處。

DOTPU4 (.M) src1, src2, dst

這條指令求src1和src2中的兩個無符號數的4個字節對應的積,再相加,和數送入dst 中。在這里我們可以用src2 = 0x0121分別與ABCD、CDEF和EFGH做DOTPU4運算,可直接得出B+2C+D、D+2E+F和F+2G+H,用src2 = 0x1210分別與ABCD、CDEF和EFGH做DOTPU4運算,可直接得出A+2B+C、C+2D+E和E+2F+G。運算后的結果加2后右移2位即可。

對4×4子塊亮度預測的后6種預測模式進行優化后,性能有明顯提高,如下表所示(-o3,no –mu允許軟件流水的條件下)。

font>

H.264算法的優化策略2

圖6 優化性能比較

16×16宏塊亮度預測基本上與4×4塊亮度預測一致,但對早期終止策略進行了優化處理。

16×16宏塊亮度預測按照模式0(垂直預測)→模式1(水平預測) →模式2 (直流預測) →模式3 (平面預測) 編碼順序進行,并在每種預測模式中采用早期終止策略后,流程為[34]:16×16宏塊第i列數據預測、第i列數據求殘差、計算第i列數據SAD值、判別是否進行下一模式預測 (當SAD值大于16個4×4子塊的最優模式下的SAD之和min_cost時)。這樣最多會增加了15次判斷,有測試中表明83%的宏塊在計算了12列數據SAD值才滿足判決條件,15%的宏塊在計算了16列數據SAD值才滿足判決條件,2%的宏塊在計算了8列數據SAD值就滿足判決條件。故實際編程中僅在計算了12列數據SAD值后增加判決,僅增加一次判決,16×16宏塊編碼效率提高20.04%。流程見圖7所示。

H.264算法的優化策略2

圖7 16×16宏塊亮度預測流程

2.4 運動估計

在視頻編碼中,運動估計和補償起著最為關鍵的作用,通常占一個壓縮編碼方案總計算量的60%~ 80%。塊匹配法是目前最為廣泛應用的運動估計方法。在H. 264 中,運動補償部分與之前的標準有很大的不同。它支持更大范圍的運動補償塊,以達到高精度匹配,充分消除時域冗余度,最大程度減小預測誤差。而這是以極高的運算量和復雜度為代價的,僅以整像素搜索為例,H. 264 共允許多種大小的補償塊 (最小可到4×4),對一個16×16 的宏塊采用某一種分塊方式進行全搜索,搜索范圍為16,則求匹配差值的計算次數為:

(2 × 16 + 1) × (2 × 16 + 1) × 16 × 16= 2. 79×105

這樣大的計算量顯然會給實時視頻處理帶來巨大困難,所以要尋找快速的搜索算法和判決策略。

H. 264 標準規定對16×16 的宏塊可以采用16×16、16×8、8×16、8×8 的分塊方式,而對8×8 的分塊又可進一步分成8×8、8×4、4×8、4×4 的小塊。每個獨立的分塊分別進行運動搜索,這樣的處理固然可以達到最好的匹配效果,但要求巨大的運算量。16×8 和8×16 分塊方式的運算量各自與16×16 分塊方式的運算量大致相當,而8×8 分塊方式由于其每一個小塊都要獨立作4 種方式的搜索,其總的運算量大致相當于16×16 的4倍。而通過對H.264標準測試序列測試的結果來看,對Foreman 這類運動劇烈的序列,8×8 分塊方式為最優模式的宏塊數只占總宏塊數的不到10% ,對Akiyo這類平緩的序列,8×8 方式的宏塊百分比更是在2%,因此在優化中可以放棄8×8這種分塊模式。

運動估計的實現采用分步計算加提前終止的方法。其步驟如下:

1.搜索的上下文信息都存放在一個結構體H264_search_context_t 中,context里存儲有推薦的運動矢量(通常有5個:標準預測值、上、右上三個塊運動向量和0向量),首先嘗試context->vec[0] 標準向量,計算RD_cost(這里算得sad),若RD_cost < th0=256,則設置最優vec_best為vec[0],并返回sad值。

2.然后嘗試運動向量的其他預測值,找到最小的SAD,若該SAD小于剛才找到的sad,則設置context->vec_best = context->vec[best],如果該SAD < th0,則返回SAD。

3.若上面都沒有找到小于閾值的SAD,則調用small_diamond_search,進行小菱形搜索,實際就是搜索上下左右四個點,直到當前點為5個點中SAD的最小點。如下圖所示。

H.264算法的優化策略2

圖8 小菱形搜索



H.264解碼器中CAVLC碼表查找算法的分析與優化

0 引言
??? 近年來,隨著信息技術飛速發展和互聯網的日益普及,尤其是以視頻為信息主要來源的多媒體領域越來越受到人們的關注。H.264是ITU-T的視頻編碼專家組(VCEG)和ISO/IEC的活動圖像編碼專家組(MPEG)的聯合視頻組(Joint Video Tearn,JVT)開發的一個新的數字視頻編碼標準,它既是ITU-T的H.264,又是ISO/IEC的MPEG-4的一部分。H.264和以前的標準一樣,也是DPCM加變換編碼的混合編碼模式。H.264標準可分為三檔:基本檔次(其簡單版本,應用面廣);主要檔次(采用了多項提高圖像質量和增加壓縮比的技術措施,可用于SDTV、HDTV和DVD等);擴展檔次(可用于各種網絡的視頻流傳輸)。
??? H.264/AVC的編解碼框架的基本結構與早期的編碼標準(H.263、MPEG4等)相似,都是由運動估計、變換、量化、熵編碼、環路去塊效應濾波器等功能單元組成的。H.264視頻編碼框架的主要變化包括:引入了環內去塊效應濾波器,去塊效應處理后的宏塊被保存在內存中用于對后續宏塊的預側;采用了多參考幀運動估計,需要在內存中保留多個參考視頻幀;引入了幀內預測機制,可以通過同一幀內的宏塊進行預測;采用了新的整型變換方式,取代了以前的離散余弦變換(DCT);H.264與以前視頻標準在運動估計的模式上也有了較大的變化,H.264支持7種模式的可變塊運動估計。此外,在熵編碼中還引入了上下文自適應的變長編碼(CAVLC)和二進制算術編碼(CABAC)。
??? 在熵編碼方面,H.264使用了CABAC和CAVLC兩種不同的編碼方式。CABAC熵編碼是一種基于區間劃分的算術編碼方式。這種編碼方式的效率很高,接近信息熵值,但算法相對復雜,編解碼速度較慢。CAVLC是一種可變長編碼,它根據已編碼語法元素的情況動態調整編碼中使用的碼表,在編碼過程中有些語法元素是組合編碼的,當對這些元素進行查找時就會耗費很長的時間。因此對CAVLC的優化顯得格外重要。

1 原碼表查找算法
??? 原碼表的存儲結構為二維表結構。存儲的內容為碼字,二維坐標分別代表解碼后的兩個語法元素。對于二維表結構。若通過坐標查找內容是很容易的;而通過內容查找坐標,就需要對整個表進行遍歷。JM中的碼表查找算法就是通過遍歷整個碼表實現的,步驟如下:
??? (1)取碼表的中的一個碼字;
??? (2)根據碼字長度從碼流中取出相應長度的bit;
??? (3)比較此碼字和bit串,若相同則查找成功,否則若碼表中還有碼字,回步驟(1),否則查找失敗。

2 算法的優化分析
2.1 基于前綴零分組子表搜索算法
???
基于上下文自適應的變長編碼的解碼算法需要不斷的讀取碼流,判斷,直到在碼表中找到該碼字,如此反復,直至解碼整個塊。由此可見該過程的時間空間復雜度都是相當高的。由于變長碼為霍夫曼前綴碼,所以可以根據碼表的特性,按照碼字長度將原來的一個碼表,按照碼字長度對原碼表進行分割,以Coeff_token碼表為例,原碼表如表1所示,表中NC=-1。

H.264解碼器中CAVLC碼表查找算法的分析與優化

??? 在參考模型中,搜索碼表算法過程如下:
??? (1)從最短碼長開始,讀出該長度二進制數據流對應的碼字;
??? (2)遍歷碼表,如找到該碼字進行步驟(4),否則進入(3);
??? (3)碼字長度加1,重定位指針位置,重復步驟(2);
??? (4)讀取該碼字對應值,更新指針位置。
??? 從上面過程中不難發現,碼字長度的不確定性使得在讀取字節流時只能一次次的試探,導致了效率的下降。如果可以將變長碼的讀取采取固定的策略,一次讀取固定的長度,之后再做判斷,再讀取一定長度,這樣將判斷的次數也固定,從理論上可以降低不斷搜索和重定位指針帶來的時間和空間復雜性。利用可以利用碼表中碼字前綴零數目的不同,將表1拆分為兩個子表,如表2,表3所示NC為-1。

H.264解碼器中CAVLC碼表查找算法的分析與優化

??? 改進后的碼表搜索算法如下:
??? (1)讀取最大碼字長度的二進制流;
??? (2)根據不同的前綴零位數、右移位、判零以確定碼字所在子表;
??? (3)直接根據碼值讀取對應值,更新指針位置。
??? 新的搜索過程不但避免了不確定性,而且無需遍歷碼表,這樣可以在一定程度上提高變長解碼的效率。

H.264解碼器中CAVLC碼表查找算法的分析與優化

??? 按照改進的算法步驟,解碼時,首先從字節流中讀取8位碼字,由于前綴零個數分為大于3和小于3的兩種情形,所以右移5位,若為零,則查找表2,否則查找表 1,根據碼值直接解碼出±1個數,非零系數數目。此外在設計代碼時,還可利用二叉搜索樹的特性,設計搜索過程,提高解碼效率.

2.2 二叉樹一子表混合法
??? 拆分成子表后建立的數組中存在冗余現象。如當0≤N<2且Pre-Zeros<6時,一共有13個碼字。為了保留原先的查表方式以TC和 Tls為矩陣下標的特點,必須要用4×7矩陣,多余位置零。由于實際搜索的對象是矩陣,怎么確定Pre-Zeros值,以保證在分塊數一定的情況下,使用的矩陣較小,成為提高搜索效率的關鍵。從表中可以看到,對不同的N值對應的列,子表之間的Pre-zeros的分界點選取了不同的閾值。按照表2中的分塊方法,矩陣的平均大小為4×6.5。相比JM中使用一個4×17矩陣,搜索效率理論上可以提高(17-6.5)/6.5=1.615倍(假設每張子表的使用概率相同)。以0≤N<2的一張VLC表為例,共分成4張子表。從查找一個碼字的比較次數來看。

H.264解碼器中CAVLC碼表查找算法的分析與優化
??? 可知,子表法查找比較次數的理論最小值為H.264解碼器中CAVLC碼表查找算法的分析與優化此時要求n=s2。如果在第一個步驟(確定子表)中改為采用二分法,則H.264解碼器中CAVLC碼表查找算法的分析與優化這種情況下就可以對以上碼表中前綴連零再細化,將相同連零個數的碼字放在一起,增加子表數而減少子表中的碼字結點數,可以進一步提高查找效率。
??? 從以上分析可見,二叉樹的查找效率是最高的。因此可以將二叉樹應用到子表法中,對每一張子表分別建樹。對于二叉樹來說,查找時間與樹的深度有關。觀察子表中的碼字,發現它們都有不同長度的連零作為前綴,如果直接建樹將導致樹的不平衡并增加了樹的深度。為了解決這個問題,可以考慮在同一張子表中為每個碼字去除相同個數的連零前綴,然后建立二叉樹。在解碼時,先忽略這些連零個數,再進行樹的查找。在最理想情況下,這種查找方法的一次查找的平均比較次數為:

??? H.264解碼器中CAVLC碼表查找算法的分析與優化
??? 對第一張VLC表采用二叉樹一子表法的最大比較次數:

??? H.264解碼器中CAVLC碼表查找算法的分析與優化
??? 幾種算法的對比與復雜度分析如表4所示。

H.264解碼器中CAVLC碼表查找算法的分析與優化

??? 空間復雜度也是需要考慮的問題。JM參考實現中為Tls和TC的聯合碼表建立了2個3×4×17的三維數組共需要408 B的存儲空間。二叉樹法經過統計,一棵樹共有124個結點,其中葉結點62個,其余62個結點為根結點或枝結點。建3棵二叉樹所需要的空間為 (62×4+62×2)×3=1 116 B。子表法將碼表分成12張子表,每張子表用2個二維數組表示,而數組的平均大小為4×6.5,則共要4×6.5×12×2=624 B。

3 結 語
??? H.264是現在視頻編解碼領域研究的熱點也是未來發展的方向,它將代替MPEG2成為主流的信源壓縮標準。H.264應用領域非常廣泛。將H.264的編解碼速度盡可能的提高,可以使其在更多的領域中應用,如數字電視,消費電子類產品,網絡通信,可視電話等現在熱門領域。在此專門對于CAVLC碼表查找給出了改進方案,通過這三種改進方案,避免了對整個碼表的查找,對碼表的查找在效率上有了很大提高。具有明顯的實用意義.


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/454961.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/454961.shtml
英文地址,請注明出處:http://en.pswp.cn/news/454961.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

吃飯、睡覺、打星星之“打星星”!

大家見過這樣的星星么&#xff1f; 你想要多少就可以多少的星星&#xff01;&#xff01;&#xff01; 下面我們就來用奇妙的JavaScript來實現 首先我們要引入一個輸入包 let readline require("readline-sync");然后再讓客戶輸入數字&#xff0c;并將其存放起來con…

mysql 自動分表_Mysql Event 自動分表

create table TempComments Like dycomments;上述 SQL語句創建的新表帶有原表的所有屬性&#xff0c;主鍵&#xff0c;索引等。自動分表怎么做呢&#xff1f;使用上述語句自動創建分表。那么ID怎么設置呢&#xff1f;更改表格自增主鍵的起始值 例如 表格為 xxx_201604 那么將起…

《大道至簡》周愛民讀后感

作為一個準大二的軟件工程系的學生&#xff0c;初讀此書&#xff0c;很多部分是不太容易理解的&#xff0c;自己又沒有經歷過&#xff0c;感覺差了一個高度似的。自己讀的挺蒙&#xff0c;于是就去百度了一下這本書的讀后感&#xff0c;看看別人讀懂了什么&#xff0c;許多的評…

使用iconv-lite解決node當中不支持GBK編碼的問題

1、Node環境當中不支持GBK編碼 node.js當中的Buffer對象支持的編碼格式的種類有限&#xff0c;大概有ascii、utf8、utf16le、ucs2、base64、binary、hex。不支持GBK的編碼形式。對于windows系統來說&#xff0c;由于歷史原因&#xff0c;許多文件默認的編碼格式均為GBK。 比如我…

c1

dmg和package是安裝文件&#xff0c;dmg直接拖進應用程序中&#xff0c;pkg要進行安裝。 playfround是swift項目。--ios -----oc&#xff08;面向對象的C&#xff09; -----swift(oc的封裝)1963年劍橋大學退出cpl,1967年對cpl簡化推出bcpl&#xff0c;1970貝爾實驗室對bcpl簡化…

mysql必_MySQL必知必會(一)

摘自《MySQL必知必會》1.1.1 什么是數據庫數據庫&#xff1a;保存有組織的數據的容器(通常是一個文件或一組文件)人們通常用數據庫這個術語來代表他們使用的數據庫軟件。這是不正確的&#xff0c;它是引起混淆的根源。確切地說&#xff0c;數據庫軟件應稱為DBMS(數據庫管理系統…

python之工作舉例:通過復制NC文件來造數據

1 # 通過對NC文件復制來造數據2 import os, shutil3 4 # 遍歷的根目錄5 root_dir "D:\\test_data\\DISASTER\\"6 # 獲取NC文件的時間7 time_source 201612280800008 # 生成NC文件的時間9 time_new 2018122808000010 11 12 def get_dir_path(dir_name, time_str):1…

Python 3.5.2 TypeError: a bytes-like object is required, not 'str’問題解決方案

運行環境Mac Python 3.5.2 Q: http_response """\ HTTP/1.1 200 OK Hello, World! """ client_connection.sendall(http_response) TypeError: a bytes-like object is required, not str 類型錯誤&#xff0c;需要的是一個byte類型&#xff0…

mysql 集群架構_mysql企業常用集群架構

轉自 https://blog.csdn.net/kingice1014/article/details/760200611、mysql企業常用集群架構在中小型互聯網的企業中。mysql的集群一般就是上圖的架構。WEB節點讀取數據庫的時候讀取dbproxy服務器。dbproxy服務器通過對SQL語句的判斷來進行數據庫的讀寫分離。讀請求負載到從庫…

h.264視頻文件封裝

所謂封裝格式就是將已經編碼壓縮好的視頻軌和音頻軌按照一定的格式放到一個文件中&#xff0c;也就是說僅僅是一個外殼&#xff0c;或者大家把它當成一個放視頻軌和音頻軌的文件夾也可以。說得通俗點&#xff0c;視頻軌相當于飯&#xff0c;而音頻軌相當于菜&#xff0c;封裝格…

python cookbook 筆記三

分組&#xff1a; rows [{address: 5412 N CLARK, date: 07/01/2012},{address: 5148 N CLARK, date: 07/04/2012},{address: 5800 E 58TH, date: 07/02/2012},{address: 2122 N CLARK, date: 07/03/2012},{address: 5645 N RAVENSWOOD, date: 07/02/2012},{address: 1060 W A…

關于Vue2.0,Express實現的簡單跨域

npm install express -g 通過npm全局安裝express&#xff0c;之后可以通過 express --version 來查看express版本 express server 通過express server生成server項目文件 npm install 安裝server的項目依賴 可以通過執行server下的bin\www文件可以開啟服務 在www文件我們可以默…

mysql datetime類型按天查詢_mysql 時間相關sql , 按天、月、季度、年等條件進行查詢...

-- mysql查詢本季度-- 今天select * from ticket_order_detail where to_days(use_time) to_days(now());-- 7天SELECT *FROM ticket_order_detail where DATE_SUB(CURDATE(), INTERVAL 7 DAY) < date( use_time)-- 近30天SELECT *FROM ticket_order_detail where DATE_SUB…

ffmpeg分析系列

hello&#xff0c;各位好&#xff0c;本人是一名嵌入式軟件工程師&#xff0c;目前正使用ffmpeg開發一款嵌入式多媒體播放器&#xff0c;《ffmpeg分析》系列博文是本人在閱讀ffmpeg源代碼時所做的筆記&#xff0c;希望對各位有點幫助。分析過程結合下面的例程&#xff1a;http:…

Linux kernel的中斷子系統之(二):IRQ Domain介紹

返回目錄&#xff1a;《ARM-Linux中斷系統》。 總結&#xff1a;一、二概述了軟硬件不同角度的IRQ Number和HW Interrupt ID&#xff0c;這就需要他們之間架個橋梁。 三介紹了架設這種橋梁的幾種方式&#xff1a;Linear、Radix Tree和no map。 四介紹了兩種基礎數據結構描述中斷…

mysql返回yyyy mm dd_怎么把取出mysql數據庫中的yyyy-MM-dd日期轉成yyyy年MM月dd日格式...

您好&#xff0c;通過兩個個步驟可以完成轉換&#xff1a;第一步&#xff1a;日期處理可以在模板數據集中通過sql語句轉換&#xff0c;轉換方式方式如下&#xff1a;SELECT DATE_FORMAT(NOW(),%Y) YEAR輸出結果&#xff1a;2018SELECT DATE_F…

關于JS的時間控制

關于JS的時間控制實現動態效果及實例操作 <script>BOM //Bowers Object Model 瀏覽器對象模型setTimeout() // 延遲執行一次setInterval() // 間隔執行var a 300;window.setTimeout(abc(a),3000); // 自定義函數賦值function abc(i){alert(i);}//setInterv…

感動一生的幾句話

為什么80%的碼農都做不了架構師&#xff1f;>>> 很多東西就掌握在我們手中&#xff1a; 比如快樂&#xff0c;你不快樂&#xff0c;誰會同情你的悲傷&#xff1b; 比如堅強&#xff0c;你不堅強&#xff0c;誰會憐憫你的懦弱&#xff1b; 比如努力&#xff0c;你不…

mysql5.6 memcached_MySQL 5.6 安裝配置InnoDB memcached Plugin

準備工作, 安裝libmemached包&#xff0c;提供一些memcat/cp/dump命令&#xff0c;方便測試。# yum install libmemcached.x86_64 -y1. Setup required tables.mysql> source MYSQL_HOME/share/innodb_memcached_config.sqlQuery OK, 1 row affected (0.00 sec)Database cha…

Java 監聽器,國際化

1. 監聽器 1.1 概述 監聽器&#xff1a; 主要是用來監聽特定對象的創建或銷毀、屬性的變化的&#xff01; 是一個實現特定接口的普通java類&#xff01; 對象&#xff1a; 自己創建自己用 (不用監聽) 別人創建自己用 &#xff08;需要監聽&#xff09; Servlet中哪些對象需要監…