2011年4月22日19:49:49
題目: JM8.6中幀內幀間模式的選擇
在JM8.6中幀內與幀間模式的選擇是其中非常重要的一部分, 模式選擇的過程其實涵蓋了H.264編碼中的大部分內容. 從代碼看來, 這一部分其實和碼率控制中的代價函數計算是重疊在一起的, 在進行代價函數的計算過程中也就實現了模式的選擇, 代價計算完畢, 最優模式也就選擇完畢.
1. 下面, 我們先回顧一下H.264中的幀內預測算法:
2. H.264中的幀間模式選擇算法:
在幀間模式選中, 要進行的一個重要的過程就是運動估計(運動搜索)
3. 代價函數
在上面我們也提到過, 幀內幀間模式的選擇其實和代價的計算是重疊的. 在具體的JM中實現時, 其實對於代價的計算是分為兩種情況的, 在幀內模式選擇的過程中也提到過, 主要分為RDO模式和非RDO模式. RDO指率失真優化.
H.264在運動搜索,參考幀擇優, 模式決策三個方面運用了不同的RDO代價函數, 同時也將非RDO代價函數列為可選模式, 以滿足不同的需要.
4. 具體代碼實現
具體的代價函數如下:
代價函數主要包括MV_COST, REF_COST和MODE_COST, 而前兩者在幀間模式選擇時才存在, 換句話說, 幀內模式選擇時主要是計算MODE_COST.
4.1 運動矢量代價MV_ COST
運動矢量代價主要運用於運動搜索模塊中, 為搜索點的擇優提供了代價依據。H.264 直接運用了RDO 運動搜索代價函數,其主要構成如下:
其中, S AD 是當前塊和參考幀搜索位置塊的差值, 如果用了哈達馬變換則 SA D 轉化為 S A TD; MV bi t s 是編碼運動矢量MV 的比特數,由 MV bit s 列表給出。
具體在JM8.6中的代碼實現:
對比公式可以發現, 代碼中MV_COST不包含SAD.只是計算的后面一部分
通過查看代碼可以發現, MV_COST計算所使用的地方都是在運動搜索的函數中, 這也是可以理解的: 通過比較MV_COST來得到最佳的預測塊.
其實仔細看代碼我們可以發現, 在運動搜索時為了尋找最優塊其實就是使用了上面的公式, 在代碼中有計算SAD:
byte_abs與img->quad是類似,img->quad存儲的是-255到255的平方,用於計算SSD,而byte_abs則是絕對值,用於計算SAD
在代碼中都有類似的計算SAD的代碼(有的地方使用SATD)
所以其實在運動搜索的函數中其實將計算得到的運動搜索儲存在了mcost(或mv_cost)中,並且其中是包括SAD的.
在非RDO模式下搜索: 看下面的代碼:
其中motion_cost是一個全局變量,記錄着每種模式下在每一個參考幀下的每一個8x8塊的運動搜索代價
接着看:
在encode_one_macroblock函數中的幀間模式選擇中:
經過函數Partition...后motion_cost有每一個參考幀對應的運動搜索代價
在RDO模式下:
在RDO模式下比較特殊, 因為在這種情況下實際上是完成了編碼, 直接生成了碼流, 可以得到對應的碼率(rate)
所以在RDO模式下沒有計算運動搜索代價
對於MV_COST, 它搜索后的最優代價結果是保存在motion_cost中的
4.2 參考幀代價REF_ COST
參考幀代價用於多參考幀的擇優, 采用RDO 或非RDO 代價函數時,其定義有所差別。
(1) 非RDO 方式時:
其中,參考幀號為參考幀的編號,其他各變量的定義與MV_ COST 中一致。
(2) RDO 方式時:
其中, REF bit s 是編碼參考幀號的比特數,由REF bit s 列表給出,其他變量與上述定義一致。\
具體在JM8.6中的實現:
同樣也是沒有考慮SAD先,
可以看到, 這兒是分開RDO和非RDO的.與上面的 公式相符的.
同時, 我搜索了代碼, 可以發現, 只有這一個地方計算REF_COST, 所以這個地方我們可以聯系上面的運動搜索代價MV_COST, 可以發現其實兩者最后都加到mcost變量中去了,用於參考幀的選擇.
REF_ COST用於參考幀的選擇, RDO和非RDO模式下選出的參考幀不一樣
對於MV_COST, 在RDO模式和非RDO模式下是一樣的, 也就是說MV_COST的計算不分RDO模式或非RDO模式.
可以看出, 下面的這個循環根據MV_COST和REF_COST選擇出了最佳參考幀:
准確來說上面REF_COST和MV_COST都是對應模式(16x16,16x8….)下針對某一塊(8x8)的. 最后對於每一種模式都是要將所有的塊累加起來比較大小的.
對於REF_COST, 它搜索后的最優代價(前向參考, 對於B幀還要考慮后向和雙向)保存在fw_mcost中
總結一下, 上面的REF_COST和MV_COST都是兩方面用處, 首先用於參考幀和運動矢量的搜索, 其次最優的參考幀代價和最優的運動矢量代價累加到模式代價中, 進行模式選擇
4.3 模式代價MODE_ COST
模式代價用於塊模式的擇優中, 在幀內預測塊和幀間預測塊的各模式選擇過程中定義有所不同。
1. 幀內模式選擇:
對於幀內, 主要是在I4MB和I16MB之間進行選擇.
對於亮度分量擇優,非RDO 方式:
其中, SA D 為當前塊與預測塊的差值,同樣,如果用了哈達馬變換則轉化為S AT D 。
RDO 方式:
其中, SS D 為當前塊與重構塊的差值; BL OCK bi t s 為某種預測模式下的殘差塊編碼比特數,由熵編碼結果給出。
對於色度分量幀內預測模式擇優(色度分量只有幀內預測) , 因為對於幀間模式[色度塊采用和亮度塊同樣的分割模式, 只是尺寸減半(水平和垂直方向都減半)], 並且只是在RDO方式下, 非RDO方式下沒有考慮色度
SAD 為當前塊與預測塊的差值, 用了哈達馬變換則轉化為SATD。
我們來看代碼方面的實現:
-
對於I4MB的模式代價計算:
代價的計算主要是在函數中,最后的代價保存在cost中. 具體的計算時,
-
將宏塊16x16, 分為4個8x8塊,利用
計算得到每一個8x8塊的代價,然后累加起來得到整個宏塊的代價.
-
對於8x8塊是分為4個4x4塊,利用
計算得到每一個4x4塊的代價,然后累加起來得到一個8x8塊的代價.即
-
對於一個4x4塊, 在函數 Mode_Decision_for_4x4IntraBlocks中,利用函數intrapred_luma計算出了9中預測模式下的預測值保存在img->mprr中.
接下來, 對於9種模式分別計算其代價,然后選擇最優的模式,此時是要分RDO還是非RDO的:
-
非RDO方式下,
利用上面給出的公式計算代價, 代碼如下:
計算中利用SATD函數,在這個函數中會根據配置文件中的設置來選擇是否使用SAD還是SATD
最優的代價保存在min_cost中, 這樣就可以得到整個宏塊16個4x4塊的代價之和, 也就是一個宏塊在I4MB模式下的的代價.並且最優的I4MB中的模式保存在了best_ipmode中
-
RDO方式下,
先計算了一下, 殘差, 保存在img->m7中,然后調用函數RDCost_for_4x4IntraBlocks,
(1) 在這個函數中,調用函數dct_luma對img->m7進行DCT,量化, 反DCT,反量化,將重建后的結果保存在enc_picture->imgY中.
(2) 計算出SSD,即distortion,
(3) 對該4x4塊進行編碼, 從而得到碼流大小rate
(4) 最后利用公公式得到代價:
最后利用RDCost_for_4x4IntraBlocks返回的代價rdcost,在9種模式中比較得到最優的代價保存在min_rdcost中,同時最優模式保存在best_ipmode中.
在函數Mode_Decision_for_4x4IntraBlocks返回前還保存了最優模式在img->ipredmode中
最后根據在Mode_Decision_for_4x4IntraBlocks中求得的代價可以比較I4MB代價是不是比較小,如下:
-
對於I16MB模式代價計算:
-
首先是非RDO方式:
-
(1)調用intrapred_luma_16x16函數,計算I16MB的4種模式下的預測值,保存在img->mprr_2中
(2) 調用函數find_sad_16x16, 計算SAD,將SAD作為最終的代價,根據SAD比較得到最優的I16MB模式
其實這兒與下面的敘述結合起來看,可以發現,如果代碼運動到上面的部分,那么非RDO方式下的幀內與幀間最佳模式已經選擇出來了.非RDO下的幀內幀間預測選擇是隨着代碼的從上而下的運行不斷進行比較選擇的.
-
RDO方式:
在RDCost_for_macroblocks函數中調用
查看Intra16x16_Mode_Decision可以看到與非RDO方式是一樣的
但是RDO方式下, 還是要計算的
2. 幀間模式選擇:
對於亮度分量擇優,非RDO 方式:
其中, MV _ COST、 RE F _ COST 分別為運動搜索、 參考幀擇優后的最佳代價; MODE bit s 為編碼模式號的比特數,由列表給出。
RDO 方式:
其中, SSD 為當前塊與重構塊的差值; BL OCK bit s 為某種塊模式下的塊編碼比特數, 由熵編碼結果給出, 包括殘差塊、 運動矢量和參考幀編碼比特數。
下面看看具體JM8.6中的代碼實現:
對於幀間模式需要在(16x16,16x8, 8x16,8x8,8x4,4x8和4x4)7種模式中選擇一種, 對於RDO和非RDO差別比較大.
-
在非RDO方式下:
由於幀間的模式選擇牽扯到運動搜索和參考幀搜索, 所以在計算模式代價的時候要考慮到這兩方面. 在前面對MV_COST和REF_COST進行分析中,我們也提到過了, MV_COST和REF_COST是要作為幀間模式選擇時代價函數的一個重要部分的.
-
首先是宏塊級的選擇: 16x16,16x8, 8x16
看代碼我們可以發現, 其實MV_COST和REF_COST的選擇是在模式選擇的過程中完成的.
在計算一個宏塊(16x16)在16x16,16x8, 8x16三種模式下的代價的時候, mode16x16是一個塊直接計算完, mode16x8是分兩個塊的和, mode8x16也是2個8x16塊的和. 其中代碼中的cost就是一整個宏塊的總的代價和.
下面的代碼很清晰的顯示了在宏塊級進行模式選擇的過程.
-
然后是亞宏塊級的選擇: 8x8,8x4,4x8和4x4
亞宏塊的選擇與宏塊級的步驟是類似的.
當前宏塊的在亞宏塊模式下的代價cost8x8與之前宏塊級模式下的最優代價min_cost進行比較, 再選擇最優
-
在RDO方式下:
在JM8.6中RDO方式下的模式選擇包括幀內和幀間都是在一起進行選擇的, 通過在函數RDCost_for_macroblocks中計算對應模式的RDO代價,進行比較得到最優的模式.從下面的代碼中可以看出來:
下面我們深入到RDCost_for_macroblock函數中進行, 分析這些模式的比較, 由於對於幀內I4MB和I16MB兩種模式已經進行過分析, 所以這兒我們主要專注於幀間模式的選擇:
首先, 調用函數設置當前宏塊的模式和參考幀信息(其實是設置currMB->b8mode[4])
上面針對不同的模式進行不同的計算.
-
我們先看對於亞宏塊級(P8x8):
亞宏塊級的RDO計算的代碼不在這個地方, 是和非RDO方式混合在一起的, 可以結合上面的對非RDO方式下對亞宏塊級的分析來看>對於一個宏塊的4個8x8塊都要進行進行4種亞宏塊級模式的選擇:
調用了RDCost_for_8x8blocks函數, 對於RDCost_for_8x8blocks
由於在函數Partition...進行運動搜索時已經計算出了運動矢量mv保存在了img->all_mv中,所以這兒就可以根據mv直接找到預測值,進而在函數LumaPrediction4x4中完成預測值計算,保存在img->mpr中,然后在函數LumaResidualCoding8x8中計算得到殘差,保存在img->m7中
接着再dct_luma函數中完成DCT變換,量化, 反DCT,反量化,然后將得到的重建值存在enc_picture->imgY中,同時也計算出了coef_cost, 這個coef_cost作為RDCost_for_8x8blocks函數中的cnt_nonz,表征殘差中是否存在不為零的數. 經過這些操作后, 我們現在可以總結一下到底在RDO模式下的代價怎么計算的?
上面是RDCost_for_8x8blocks的返回值,我們可以發現, RDO模式下代價的計算是嚴格遵守了公式
失真distortion的計算是
是原始值與重建值的差
rate是對很多項進行編碼后所占用的碼流大小
RDCost_for_8x8blocks函數計算得到的代價保存在rdcost中,然后利用rdcost和min_rdcost比較
進而得到一個8x8塊的最優P8x8中一種
這樣我們就在RDO方式下, 得到了一個宏塊中的4個8x8塊的最優幀間模式.
同時我們要在這兒鄭重說明一下: RDCost_for_8x8blocks函數與RDCost_for_macroblocks的不同在於, RDCost_for_8x8blocks只是在RDO方式下為一個8x8塊在4種亞宏塊模式中一種計算其代價,進行選擇最佳模式,並且不考慮色度塊,而RDCost_for_macroblocks是為一整個宏塊(16x16)在(0,1-3,P8x8,I4MB,I16MB)計算其RDO代價,然后選擇一個最優模式,並且是考慮色度塊的.
所以下RDCost_for_macroblocks中, 要對選擇P8x8模式下的整個宏塊重新計算其代價的.並且在本函數中只是調用函數設置一下參數
包括AC系數img->cofAC和重建值enc_picture->imgY及模式currMB->intra_pred_modes
-
宏塊級(LumaResidualCoding):
對於幀間的模式(1-3)調用了函數LumaResidualCoding,在函數LumaResidualCoding中對宏塊殘差進行編碼, 是將一個宏塊分為4個8x8塊分別進行編碼, 在這個函數中調用了LumaResidualCoding8x8,與RDCost_for_8x8blocks函數類似,
在函數LumaResidualCoding8x8中, 對8x8塊的4個4x4塊分別進行預測,dct變換等,得到coef_cost
利用函數LumaPrediction4x4根據已經得到的mv來計算每一塊的預測值,保存在img->mpr中,進而計算殘差保存在img->m7中,然后利用這個殘差調用函數dct_luma進行DCT, 量化,反DCT, 反量化, 之后得到重建值保存在enc_picture->imgY中.
其實到現在為止上面的分析都是在模式的選擇都是在I4MB的9種中選擇最佳,在I16MB的4種中選擇最佳, 在P8x8中的4種中選擇最佳. 下面我們要在幀內和幀間所有7種模式(0,16x16,16x8,8x16,P8x8,I4MB和I16MB)中選擇最優.
先調用函數ChromaResidualCoding, 在這個函數中主要是計算色度的預測值, 保存在enc_picuture->imgUV中
(1) 計算失真distortion(包括亮度和色度)
(2)計算碼率rate
最后計算代價
這樣就得到了最優的代價及最優的模式.
4.5 JM8.6中模式選擇
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
經過上面的分析, 下面我們對JM8.6中的模式選擇做一個總結:
總起來說, 模式選擇是這么一個過程:
分為RDO和非RDO兩種情況, (我們假設幀內和幀間模式都允許)
1. 非RDO方式
(1) 在宏塊級模式16x16, 16x8, 8x16中選擇最佳模式,min_cost初始化為一個很大數,cost是一種宏塊級模式的代價
最終,從上面的3種模式中選擇到最佳模式:best_mode保存最佳模式,min_cost保存最佳代價
(2) 對整個宏塊中的4個8x8塊分別,在亞宏塊級模式8x8,8x4,4x8,4x4中選擇最佳模式,每一個8x8塊的最佳模式保存在best8x8mode[4]中,最佳代價保存在min_cost8x8中, 最后4個8x8塊的代價累加得到整個宏塊的代價cost8x8中,
這樣就可以將宏塊的P8x8模式與宏塊級模式進行比較了:
由於min_cost保存的是宏塊級3種模式中的最佳代價所以和cost8x8比較,得到16x16,16x8,8x16和P8x8中的最優模式
同樣best_mode保存最佳模式,min_cost保存最佳代價.
至此我們就得到了幀間預測模式中的最佳模式和對應的最佳代價
(3) 計算Direct的代價,與幀間最佳模式進行比較,得到最有模式:
(4)進行幀內I4MB的9種模式的選擇,利用函數Mode_Decision_for_Intra4x4Macroblock,同時得到最優代價cost和整個宏塊中16個4x4塊對應的最優模式 img->ipredmode[pic_block_x][pic_block_y] = best_ipmode;
然后與Direct和幀間的最佳模式進行比較,得到三者中的最優模式
(5) 進行幀內I16MB的4種模式的選擇,先利用函數intrapred_luma_16x16計算得到4種模式下的預測值,保存在img->mprr_2中,然后利用 find_sad_16x16選擇得到最佳模式i16mode和對應代價cost,
然后cost與前面所有幀內幀間的最佳代價進行比較,從而得到最終的幀內和幀間的模式中的最佳模式:best_mode
最終利用函數SetModesAndRefframeForBlocks將best_mode 保存到當前宏塊的mb_type
2. RDO方式
前提,所需要的運動矢量代價和對應的參考幀代價都計算出來了.
(1)在亞宏塊級的4種模式中選擇最優的模式,利用的是函數RDCost_for_8x8blocks計算一個8x8塊的代價,這樣最佳模式保存在了best8x8mode[4]中,這樣就可以得到一個宏塊的4個8x8塊對應的最佳模式,
(2) 接下來在7種模式(0,16x16,16x8,8x16,P8x8,I4MB和I16MB)中選擇選擇一種最優模式
其中I4MB是利用Mode_Decision_for_Intra4x4Macroblock得到9種I4MB幀內模式中得到最優模式后,作為I4MB
同樣I16MB是利用函數Intra16x16_Mode_Decision得到4種I16MB幀內模式中的最優模式后作為I4MB
在函數RDCost_for_macroblocks計算每種模式對應的代價,然后比較得到最優的模式.
由於RDO方式是要先對每種模式進行具體編碼一次,得到對應的碼率和失真后利用公式來計算得到的, 所以對於上面的7種模式都必須計算失真distortion(包括亮度和色度)和碼率rate
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
另外對於P 幀亮度分量的特殊模式SKIP 模式和B 幀亮度分量的特殊模式SKIP、 DIRECT 模式,其非RDO
代價:
SA D 為當前塊與參考幀相應位置塊的差值, 同樣,如果用了哈達馬變換則轉化為SA T D。
在代碼中具體如下:
這個應該是對應B幀的Direct模式
但是我現在沒有在代碼中發現P幀skip模式下代價的計算
xkfz007
2011年4月23日20:52:43