幀間預測主要包括運動估計(運動搜索方法、運動估計准則、亞像素插值和運動矢量估計)和運動補償。
對於H.264,是對16x16的亮度塊和8x8的色度塊進行幀間預測編碼。
A、樹狀結構分塊
H.264的宏塊,對於16x16的亮度宏塊,可以分成16x16、16x8、8x16和8x8的子塊進行幀間預測。對於8x8的塊(亞宏塊,亮度和色度),往下又可以分成8x8、8x4、4x8、4x4的子塊。在運動估計中,每一種分割都需要嘗試,並計算出運動搜索結果的代價,選擇最小代價的分割方式進行預測編碼。
B、運動估計准則
運動估計就是在搜索范圍內尋找最佳估計塊,使得預測塊與當前塊的殘差數據盡量小,這樣就保證編碼的代價盡量小。對於MxN的像素快,s(x,y)表示當前像素值,z(x,y)表示備選預測像素值,x=1……M,y=1……N。則有下面的運動估計准則:
1、SAD(sum of absolute difference):絕對誤差。MAE:平均絕對差值
SAD = sum(|s(x,y)-z(x,y)|) MAE = (1/MN)*SAD
2、SATD
3、SSD(sum of squared difference):差值的平方和。MSE:平均平方誤差
SSD = sum((s(x,y)-z(x,y)^2)) MSE = (1/MN)*SSD
可以選擇上面的估計標准,計算出的值越小,說明編碼代價越小。
C、運動搜索方法
運動搜索就是在允許的搜索范圍(一般是上下左右各一個子塊大小)內查找最佳匹配塊的過程,主要有全局搜索和快速搜索。
1、全局搜索:最簡單的將所有可能進行搜索比較,總是能找到搜索范圍內的最佳匹配塊,但是效率太低。
2、快搜索算法:每種算法的過程各不相同,主要通過盡量避開不太可能是最佳匹配塊的位置,從而提升搜索效率。過程就是:
》1、確定搜索起始點;
》2、判斷該點有沒有達到最佳匹配塊的要求和能不能進一步繼續搜索。
》3、按照搜索規則,以起始點周圍點為新的起始點進行遞歸搜索。
常見的快速搜索算法有:三步法、二維對數法、交叉法、菱形法等,具體每種搜索方法可以參考書籍或者百度。
D、樹狀分級搜索和亞像素估計
在運動估計時,為了提高估計精度,通常會采用1/2、1/4和1/8的像素精度進行估計,但是全部估計都這樣操作會產生很大的性能開銷,所以一般采用樹狀分級搜索。
樹狀分級搜索就是在進行在進行運動估計時,先以整像素精度進行搜索,找到最佳匹配塊之后,再在該位置周圍進行1/2像素精度的搜索找到最佳匹配點。如果有需要的話,可以繼續在1/2像素精度的最佳匹配點周圍進行1/4像素精度的搜索,尋找最佳匹配點。
在H.264中,對亮度和色度塊的估計,分別支持1/4和1/8像素精度的運動估計。
1、亮度的1/2和1/4像素插值:亮度亞像素差值如圖一
圖一:亮度塊的亞像素插值 圖二:色度塊的亞像素插值
如圖:圖中的灰色點是整數像素點,aa,bb,cc,dd,ee,ff,gg,hh和b,h,s,m,j是1/2像素,其他都是1/4像素。計算過程是先用(1,-5,20,20,-5,1)的六抽頭濾波器進行1/2像素插值,然后再通過臨近像素插值的方法計算1/4像素的插值。具體如下:
水平半像素:如 b = ( E - 5F + 20G + 20H - 5I + J), b = Clip1((b+16) >> 5);Clip1的作用是限制結果在0~255,右移5相當於除以32,加16是為了結果的四舍五入。
垂直半像素:如 h = (A - 5C + 20G + 20M - 5R + T), h = Clip1((h+16) >> 5);
對角半像素:如 j = (cc - 5dd + 20h + 20m - 5ee + ff) = (aa - 5bb + 20b + 20q - 5gg + hh) ,j = Clip1((j+16) >> 5); 即:水平和垂直方向計算結果相同(可以自行展開計算驗證)。
水平1/4像素:如 a = (G + b +1) >> 1; i = (h + j + 1) >> 1;
垂直1/4像素:如 d = (G + h +1) >> 1; f = (b + j + 1) >> 1;
對角1/4像素:如 e = (h + b +1) >> 1; g = (b + m + 1) >> 1; p = ( h + s + 1) >>1; r = (s + m + 1) >>1;
2、色度的1/8像素插值:色度塊是采用二次線型的1/8像素插值,如圖二
如圖:就是利用待查亞像素G周圍的整數像素(A、B、C、D)來加權計算G的像素值。整像素點距離G越近,其權值越大。計算如下:
G = ( (8-dx)*(8-dy)*A + (dx)*(8-dy)*B + (8-dx)*(dy)*C + (dx)*(dy)*D + 32) >> 6; 其中dx、dy分別為G相對A的水平和垂直距離(以1/8像素為單位1距離),取值范圍是1~7。
E、B幀的預測
B幀是雙向預測,分別參考List0和List1兩個參考幀列表進行前向和后向預測,這里的前和后是針對播放順序而不是編碼順序。H.264編碼是以GOP分組處理,每個GOP的編碼結構有III……、IPP……、IBB……P和分層B幀結構。其中第一種一般不使用,編碼效率太低;第二種是屬於H.264的基本檔次。第三、四種屬於主要檔次和擴展檔次。其中第三種(普通B幀)會產生較大的編碼延時。
B宏塊預測有4種模式:直接模式(Direct)、雙向模式(Bipred)、List0和List1。其中16x8和8x16大小的塊只能使用Direct、List0和List1,其他子塊大小可以使用所有的模式。
雙向預測:
從List0和List1兩個參考幀列表中選擇最佳匹配塊進行預測。過程如下:
》在List0和List1中查找最佳匹配塊,得到運動矢量MV(MV1,MV2)。
》利用臨近塊的同方向MV,估計當前塊的兩個方向的MV預測值MVp(MVp1,MVp2,方法見后面:MV的編碼)。PS:該步驟可以和上一步對換,即:先估計得到MVp1和MVp2,然后以MVp1和MVp2為起點進行搜索得到運動矢量MV1和MV2。
》得到MV和MVp,就可以計算兩個MVD(MVD1和MVD2),然后對MVD進行編碼。
》得到兩個預測參考塊和運動矢量后,就可以計算像素塊的像素預測值。
pred(i,j) = (P1 * pred_L0(i,j) + P2 * (pred_L1(i,j))) / (P1 + P2); // 其中P1和P2是兩個方向的參考幀的權重。
List0和List1模式:這兩種模式和雙向模式類似,只不過只進行一個方向的預測 。
直接模式:直接模式應用於16x16、8x8以及8x8塊中的所有子塊。直接模式只編碼預測殘差,而不編碼運動矢量(或MVD)和參考幀序列號,運動矢量和參考幀序列號在解碼端通過計算前、后向MV,利用前后向MV得到像素預測值。
有兩種計算MV的方法:時間模式和空間模式。
時間模式:基於假設“被預測的塊在前后兩個參考塊間是均勻運動的”,所以場景切換和非均勻運動的塊,預測效果不好。
運動估計時,假設當前B塊在List0和List1中參考幀分別為F0和F1,對應的最佳匹配塊(預測塊)分別為B0和B1。如果在之前對B1塊進行幀間預測時,B0是B1的前向最佳匹配塊,即:存在當前塊在List0中的參考塊B0相對於當前塊在List中的參考塊B1的運動矢量MV,那么就可以根據這個運動矢量和當前幀與F0、F1之間的幀間隔(記為d0,d1)算出前向和后向的運動矢量MV0和MV1。
如:MV=(2.5,5),當前幀與F0和F1分別間隔2幀和1幀,即:d0=3,d1=2;於是MV0 = d0/(d0+d1) * MV = (1.5,3),MV1 = -d1 / (d0+d1) * MV =(-1,-2)。
空間模式:利用當前幀的相鄰塊的運動信息估計當前塊的MV和參考幀序號,主要過程包括“參考幀選擇”和“運動矢量選擇”。
》參考幀選擇:利用當前塊的鄰近塊A、B、C(位置見后面MV的編碼)的參考幀中非負幀號最小的幀作為當前塊的參考幀,這是為了選擇離當前塊最近的幀作為參考幀。如果有一個方向上A、B、C都沒有參考幀,那么就采用單項幀間預測。如果A、B、C在兩個方向都沒有參考幀(即A、B、C都是幀內預測),那么當前塊分別選擇兩個方向離當前幀最近的參考幀為當前塊的參考幀。
》運動矢量選擇:若List1中第一幀(當前幀的播放順序后一幀)對應位置塊的運動適量MV1和MV2小於1/4像素(即:當前塊到下一幀運動的比較少),且該幀為短期參考幀,且當前塊的某個方向的參考幀幀號為0,則該方向的MV為0。如果不滿足,則按照后面MV的編碼中描述的方法計算兩個方向(A、B、C的運動適量的中值,不是均值)的MVP作為當前塊的MV
F、MV的編碼
通過上面的樹狀分塊結構,針對各種分塊大小都進行一次幀間預測。每種分塊的幀間預測,通過樹狀像素精度分級搜索,先按照整像素精度找到最佳匹配塊,然后在進一步按照1/2、1/4像素精度尋找更加准確的最佳匹配塊。尋找最佳匹配塊主要是通過快速搜索算法,按照某種搜索准則判斷最佳匹配塊。上述操作完成后,找到各種分塊結構代價最小的最佳匹配塊,從而根據最佳匹配塊和當前塊的位置,得到運動矢量(MV)。通過運動矢量和運動殘差(參考塊和當前塊的像素差值)就可以在解碼端還原圖像數據。但是如果之間編碼MV會產生很大的碼流代價(16x16MB分成多個子塊產生多個MV、采用亞像素、MV包含row和col兩個參數),因為實際操作中往往是根據周圍的塊,對MV進行預測得到MVp,然后編碼運動矢量的實際值與預測值的差值MVD=MV-MVp。
如上圖:當前塊(任意子塊大小)的運動適量預測值有當前塊的左、上、右上的塊A、B、C(任意字塊大小)進行預測。預測規則如下:
》對於非16x8和8x16的子塊,運動矢量的預測值MVp 為A、B、C的運動矢量的中值。MVp = mid(MVA, MVB, MVC)。
》對於16x8的子塊(即圖中的E為上下兩個16x8的子塊),上面子塊的MV預測值是塊B的MVB,下面子塊的MV預測值設計塊A的MVA。
》對於8x16的子塊(即圖中的E為左右兩個16x8的子塊),左邊子塊的MV預測值是塊A的MVA,右邊子塊的MV預測值設計塊C的MVC。
》在進行上面的MV計算時,還要滿足下面的限制條件:
1、只有當當前塊E的參考幀和臨近塊(A、B、C)的參考幀為同一幀,那么才可以使用MVA、MVB、和MVC進行預測;
2、如果MVC不可用,則用當前塊的左上邊塊的運動矢量MVD代替MVC;
3、如果MVA、MVB和MVC中沒有可用的,那么不進行運動矢量預測,直接編碼當前塊的運動矢量MV;
4、如果MVA、MVB和MVC中只有一個可用的,那么MVP就是該可用的臨近塊運動矢量;
5、如果MVA、MVB和MVC中有兩個可用的,那么將另一個不可用的當作0,然后按照3個都可用的策略計算MVP。
Skip模式:H.264中為了降低碼率采用的特殊編碼模式,是針對宏塊(16x16)編碼時,“既不傳輸運動矢量殘差(MVD)、也不傳輸像素塊殘差”的編碼方式。包括P_Skip和B_Skip。
P_Skip:
編碼時:如果參考幀是List0中的第一幀,運動矢量和運動矢量的預測值相同(MVD為0),且殘差系數通過變換量化后成為0或者通過某種策略(率失真優化等)舍棄。那么則只需要標記為P_Skip和傳輸運動矢量預測值MVP。解碼時,就可以的MV=MVP,然后用預測像素值作為解碼像素值。
B_Skip:是B塊直接編碼的一種特殊形式。
編碼時:如果殘差系數通過變化量化后成為0或者通過某種策略舍棄,那么則只需標記為B_Skip模式,也不需要傳輸MVP。解碼時則按照B塊的直接模式計算出參考幀號和相應的運動矢量,然后參考像素值作為當前像素的值。