幀內解碼時,在解碼端,首先通過當前宏塊左邊、上邊已經解碼完成的宏塊使用當前宏塊的預測模式(預測模式計算過程請參見我的論文《H.264數字視頻差錯控制技術的研究》,在群FTP“本群原創資料”目錄中)得到當前宏塊的像素預測值。然后通過對碼流進行解碼得到當前宏塊的像素殘差。最后將殘差和預測值加在一起就得到重構的像素值。如果當前宏塊的左邊或者右邊的宏塊不存在(即當前宏塊為圖像邊界上的宏塊),那么其預測值全部為128。
幀間解碼時,在解碼端,首先對碼流進行解碼得到當前宏塊的參考幀,然后通過當前宏塊周圍宏塊計算運動矢量預測值(具體方法見畢厚杰書99頁,標準中也有,但我一時不知道在什么地方了)。然后通過對碼流進行解碼得到當前宏塊的運動矢量殘差。將運動矢量殘差與運動矢量預測值相加得到實際的運動矢量。然后通過對碼流進行解碼得到當前宏塊的像素殘差(如果當前宏塊有像素殘差的話)。然后通過參考幀與上面計算得到的MV計算出當前宏塊的像素預測值。再將像素預測值與像素殘差相加就得到當前宏塊的重構。
說明:
1、以上過程為 JM86 的解碼過程。并不一定所有代碼都按照這個流程;????
2、上面說的運動矢量預測值的計算過程實際是以4*4塊為單位,參考幀也是針對4*4塊做的。這里寫成宏塊主要是方便大家理解。
RDO
Rate-Distortion Optimization 是視頻編碼中最優選擇mode的一種方法。比如h.264里好多mode 8x8 16x16 I4x4 I16 在給定的條件下,哪個是最好的?
Distortion 是指選用candidate mode產生的失真,rate是用這個mode需要的rate.他們換算成RDCost = Distortion + lamda * rate. 兩個mode誰的rdcost 低就選誰,其中的數學原理是條件極值轉非條件極值。
JM 里用的RDO是比較經典的方法。最早是Gary J.Sullivan做的 參見 IEEE Signal Processing Magazine 1998 Nov.? "Rate-Distortion Optimization for video compression" rdo的經典。 h264里的rdo還可參考CSVT H.264 special issue.
在H.264里面當前幀屬于哪個slice的決定形式是多種多樣的,對于JM中的碼流中,一般一幀圖象就認為是一個slice,那么如果當前幀是一個I幀,那么它就屬于一個I slice.這時整個frame的為一個slice.但是具體我們用什么樣的方式來進行slice type的決策呢,這也是一個問題。我們看一下T264里面是如何處理這個問題的。
在T264中,如果我們設定了,USE_SCENEDETECT的話,當前的slice種類是由當前幀的幀號與設定的idrframe,iframe跟bframe相關的,如果frame_no%idrframe==0的話,那么說明當前幀是屬于一個IDR slice的,如果frame_no%iframe==0的話,該幀屬于一個I slice.如果上面的情況不滿足那么是屬于P slice或B slice.由于碼流中只有如下幾種類型:0) I P P P ..... I P P P? 1) I B P B P.....B P B P?? 2) I B B P B B P.....B B P I B B P,所以如果frame_no%(bframe+1)==0的話,就屬于P slice,如果不是的話屬于B slice.
如果沒有使用USE_SCENEDETECT的話,是用MeAnalysis來決定當前屬于什么slice的。這種形式是動態式地決定是不是要加入一個I slice。決定流程如下:如果我們達到了我們在config里面設定的iframe interval的話,當前幀就是一個I slice.我們設定一個INTRA_THRESHOLD,對幀中的每一個宏塊進行預測,來計算sad.這個過程因為計算量比較大,所以使用了簡化算法,首先用前一幀的mv做預測值,計算sad,如果這個值大于我們設定的SEARCH_THRESHOLD的話,說明上一幀的mv已不適合做當前幀的預測,我們會使用一個簡化的diamond search來簡單地找一下當前宏塊的mv,進行sad計算。整個幀的sad計算結束之后,我們與INTRA_THRESHOLD進行比較,如果sad大的話,這一幀為I slice中的一幀,如果小的話,我們認為它是一個P或B幀。對于當前幀是P還是B幀還是用上面的方法進行。