JM模型I幀幀內預測流程
I幀只存在幀內編碼,沒(méi)有幀間運動(dòng)估計,不用參考其他的幀,所以I幀具有同步作用,.付出的代價(jià)就是效率稍差,不過(guò)也十分必要的。
I幀幀內編碼分為亮度編碼和色度編碼,需要完成預測,計算RD代價(jià),來(lái)判別宏塊分塊模式.
I幀亮度度分塊模式分為16X16,8X8,4X4三種模式,色度分塊模式只有一種8X8模式,每種分塊模式,又有不同的
預測方式,在JM模型中,需要對這些模式進(jìn)行RD代價(jià)計算,選擇其中最小值作為最優(yōu)模式。
下面對涉及分塊模式的數據進(jìn)行說(shuō)明:
const int mb_mode_table[9] = {0, 1, 2, 3, P8x8, I16MB, I4MB, I8MB, IPCM}; // DO NOT CHANGE ORDER !!!
0:16X16 Direct模式,在B幀中有效
1:Inter16X16,在幀間有效
2:Inter16X8,在幀間有效
3:Inter8X16,在幀間有效
P8X8:幀間有效
I16MB:Intra16X16幀內有效
I4MB:Intra有效
I8MB:Intra有效
IPCM:Intra有效,不要預測,直接對RAW數據編碼.
其中P8X8模式和下面的數據又有關(guān)系:
const int b8_mode_table[6] = {0, 4, 5, 6, 7}; // DO NOT CHANGE ORDER !!!
上面的5種模式都歸入P8X8模式,叫做亞宏塊級,在碼流TRACE文件有一個(gè)語(yǔ)法元素叫做b8mode,說(shuō)的就是這個(gè)。
0:8X8 Direct模式,在B幀中有效。
4:Inter8X8,在幀間有效
5:Inter8X4,在幀間有效
6:Inter4X8,在幀間有效
7:Inter4X4,在幀間有效
下面舉個(gè)例子,TRACE文件里面:
@45800 mb_type (B_SLICE) ( 7, 4) = 8 0000 ( 22)
@45804 8x8 mode/pdir( 0) = 4/0 000 ( 1)
@45807 8x8 mode/pdir( 1) = 6/1 0000 ( 7)
@45811 8x8 mode/pdir( 2) = 4/0 00 ( 1)
@45813 8x8 mode/pdir( 3) = 5/1 0000000 ( 6)
意思就是位置(7,4)宏塊是P8X8分塊,
其中第一個(gè)8X8塊是8X8,list0預測,第二個(gè)8X8塊,是兩個(gè)4X8塊,list1方向預測,第3個(gè)是8X8,list0預測,第四個(gè)是兩個(gè)8X4,list1預測,
這個(gè)好象有點(diǎn)跑題了,因為b8mode不是I幀分塊模式,是P,B幀中分塊模式。
以上基本包括了264幀內,幀間要用到的所有分塊模式.
下面開(kāi)始分析幀內預測流程:
色度預測(計算所有可能的預測模式的預測值)---->亮度預測(所有的分塊模式,要對3種分塊)---->計算每種模式的RD值(包括各種預測方式)--->獲得最優(yōu)。
下面可是一步一步進(jìn)行說(shuō)明:
1:色度預測
色度預測基于8X8塊預測,8X8預測有4種預測模式,包括水平,垂直,DC預測,平坦預測。
對色度幀內預測,必須要提到幾個(gè)表格:
一個(gè)表格是:
static int block_pos[3][4][4]= //[yuv][b8][b4]
{
{ {0, 1, 2, 3},{0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0}},
{ {0, 1, 2, 3},{2, 3, 2, 3},{0, 0, 0, 0},{0, 0, 0, 0}},
{ {0, 1, 2, 3},{1, 1, 3, 3},{2, 3, 2, 3},{3, 3, 3, 3}}
};
其中yuv就是YUV采樣比例,yuv = YUV format -1,因此YUV420,yuv值等于0,b8為宏塊色度8X8塊序號,YUV420,8X8塊只有一個(gè),b8為0,
b4有0,1,2,3,因此,很容易看明白上面的表格.
第二個(gè)表格是
const unsigned char subblk_offset_x[3][8][4] = //[yuv][b8][b4]
{
{ {0, 4, 0, 4},
{0, 4, 0, 4},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0}, },
{ {0, 4, 0, 4},
{0, 4, 0, 4},
{0, 4, 0, 4},
{0, 4, 0, 4},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0}, },
{ {0, 4, 0, 4},
{8,12, 8,12},
{0, 4, 0, 4},
{8,12, 8,12},
{0, 4, 0, 4},
{8,12, 8,12},
{0, 4, 0, 4},
{8,12, 8,12} }
};
const unsigned char subblk_offset_y[3][8][4] =//[yuv][b8][b4]
{ { {0, 0, 4, 4},
{0, 0, 4, 4},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0}, },
{ {0, 0, 4, 4},
{8, 8,12,12},
{0, 0, 4, 4},
{8, 8,12,12},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0} },
{ {0, 0, 4, 4},
{0, 0, 4, 4},
{8, 8,12,12},
{8, 8,12,12},
{0, 0, 4, 4},
{0, 0, 4, 4},
{8, 8,12,12},
{8, 8,12,12} }
};
這兩個(gè)表格和上面的那個(gè)block_pos含義差不多,但是對U,V兩個(gè)分量都包括進(jìn)去了,這個(gè)含義是幀內坐標偏移,不是上面序號的意思
色度幀內預測要用到臨塊A,B,C宏塊情況做出判斷,色度塊預測.
由于寫(xiě)這篇文章的時(shí)候,是邊對照代碼,邊寫(xiě)的,所以是思路有些不對,有點(diǎn)寫(xiě)文章中倒敘的方式
ImageParameters結構里面有一個(gè)成員mprr_c[2][4][16][16];//[uv][DC_PRED_8/HOR_PRED_8/VERT_PRED_8/PLANE_8][16][16]這個(gè)成員,
放置了各種模式下的預測值,問(wèn)為什么要16X16呢,而不是8X8,當YUV444模式時(shí),當然是16X16了,這個(gè)是預留得
1:DC預測,DC預測又是以4X4塊為基本單位,對A,B,C塊的象素取平均值,假如沒(méi)有A,B,C塊的時(shí)候,取128了
2:垂直預測,假如B宏塊存在,直接把B宏塊最下邊的象素Copy
3:水平預測,假如A宏塊存在,直接把A宏塊最右邊的象素Copy
4:平坦模式,需要A,B,C同時(shí)存在,平坦模式的預測象素值算法比較復雜,這里不講了.
預測完了色度值,暫時(shí)保存在mprr_c數組里面,等待后面使用,
2:對亮度的預測和代價(jià)值的計算都在函數compute_mode_RD_cost中,該函數又用RDCost_for_macroblocks來(lái)完成主要計算
該函數說(shuō)明如下:
int RDCost_for_macroblocks (double lambda, // <-- lagrange multiplier,拉格朗日因子
int mode, // <-- modus (0-COPY/DIRECT, 1-16x16, 2-16x8, 3-8x16, 4-8x8(+), 5-Intra4x4, 6-Intra16x16)
// mode 9種分塊模式.
double* min_rdcost, // <-> minimum rate-distortion cost
double* min_rate, // --> bitrate of mode which has minimum rate-distortion cost.
int i16mode ) //16X16預測模式,僅對幀間16X16有效。
該函數對mode取不同值選擇不同的模式?jīng)Q策函數
I4MB-------------Mode_Decision_for_Intra4x4Macroblock
I16MB------------Intra16x16_Mode_Decision
I8MB-------------Mode_Decision_for_new_Intra8x8Macroblock
下面對I4MB進(jìn)行分析
I4MB又調用Mode_Decision_for_8x8IntraBlocks函數,故名思義,該函數對8X8塊進(jìn)行模式選擇,
該函數又調用Mode_Decision_for_4x4IntraBlocks,該函數完成4X4幀內預測,殘差計算,參差DCT,Zig排序,量化,RL編碼,IDCT,反量化,
存儲重建象素,便于以后使用.
二。264編一個(gè)I幀多麻煩---JM 9.7中I幀編碼分析
編碼一幀,首先當然得知道從哪兒開(kāi)始編,自打有了容錯這種東西之后,FMO(Flexible macroblock ordering)就成了選擇編碼塊的
第一步了.當然,最平常的編碼方法中,一幀就是一個(gè)slice,一個(gè)slice從一幀的第一個(gè)宏塊開(kāi)始算,所以得到一幀的最左上角的宏塊
地址,I幀編碼開(kāi)始.
在初始化編碼參數的時(shí)候,大都都是在configure文件中設置好的編碼參數,比如說(shuō)在Intra中4x4的某個(gè)方向的預測是不是被禁止的
,8x8是可選的,還是說(shuō)壓根兒就不用等等.這些都被初始化到enc_mb->valid[]這個(gè)詭異的小東西里面了,所以說(shuō)如果要做單個(gè)block
mode的時(shí)候,對里面的數據一定是要非常小心的.
對于一個(gè)I幀來(lái)說(shuō),編碼總是先把一幀的U,V部分先進(jìn)行Intra prediction,然后才考慮在Chroma最優(yōu)之后,Luma的最優(yōu)解.之后通過(guò)計
算編碼這一幀來(lái)說(shuō)最小的RD cost的mode來(lái)得到當前l(fā)uma分量的編碼方法.
核心函數:rdopt.c: int RDCost_for_macroblocks(.....)
在該函數中,對于不同種的分塊模式以及當前的編碼status來(lái)分析,涉及到Intra coding的有I4MB,I8MB,I16MB以及IPCM(IPCM是個(gè)
| 關(guān)于H.264中DCT變換問(wèn)題 |
以前寫(xiě)的一篇文章,現在放上來(lái)。解碼器現在作到Huffman解碼了。 窗外的煙花聲音漸漸沉寂,開(kāi)始工作了. H.264標準DCT8X8變換問(wèn)題,據流媒體MPEG4/H264版面斑竹,X264/MPEG4開(kāi)發(fā)小組成員的chenm001講已經(jīng)廢棄,所有 ABT(自適應塊尺寸變換)部分,都從標準中拿掉.但是我從JM97測試模型中依然開(kāi)始看到,這一部分還在工作,碼流依然輸出 了相關(guān)的DCT8X8 flag信息,所謂ABT(adaptive block transform),就是講在DCT變換的時(shí)候,選擇4X4,8X8,16X16是可以自適應 的,自動(dòng)選擇其最合理的方式,聽(tīng)起來(lái)的挺好的事情,任何好的東西都是要付出代價(jià)的,天下沒(méi)有掉下的餡餅。自適應是要 付出計算代價(jià)的。H.264 80%以上(對不起,沒(méi)有數據參考,純屬個(gè)人估計)的DCT變換是基于4X4的,對I16MB模式下用16X16 變換.其實(shí)DCT8X8變換是很多壓縮標準使用的變換方式,比如JPEG. DCT8X8模式是JM的一個(gè)可選項.哪些項可以啟用8X8DCT呢? 我們看JM對此決策: if ((mode >= 1 && mode <= 3) && currMB->luma_transform_size_8x8_flag == 0) { //try with 8x8 transform size } //=========== try DIRECT-MODE with 8x8 transform =========== else if (mode == 0 && bslice && active_sps->direct_8x8_inference_flag && currMB->luma_transform_size_8x8_flag == 0) { //try with 8x8 transform size continue; } //=========== try mb_type P8x8 for mode 4 with 4x4/8x8 transform =========== else if ((mode == P8x8) && (enc_mb.valid[4]) && (currMB->luma_transform_size_8x8_flag == 0)) { //check 8x8 partition for transform size 8x8 } 可以看得出來(lái)當我們幀間預測的時(shí)候,模式為16X8,8X16,16X16,P8X8,I8MB時(shí)候,我們都要需要測試計算DCT8X8的RD大小. 為何其他的尺寸不做DCT8X8,比如I4MB,這是理所當然的,我們作DCT是為了塊數據的去相關(guān)性,我們對I4MB是做4X4預測的 我們卻對四個(gè)4X4的block合并一起作DCT8X8,數據之間的相關(guān)性不大,可以想象效果不會(huì )好.這里要指出,對宏塊作I8MB子塊預測 也是新加入標準的,據我對JM的了解,I8MB也和I4MB一樣,有9種預測模式.值的注意的是,I8MB和其它的幀內子塊有所不同,由于 DCT8X8變換尺寸比較大,大尺寸變換雖然去相關(guān)效果不錯,但是會(huì )尺寸比較嚴重的塊效應,尤其兩塊之間的邊緣會(huì )形成比較大的梯度 所以在預測之前,I8MB子預測要做低通濾波,人工去除兩塊之間變換后引入的高頻噪聲,這樣塊邊界看起來(lái)比較平滑。 |
詭異的東西,回頭再說(shuō))
對于I16MB來(lái)說(shuō):
首先進(jìn)行16x16塊的Intra prediction.當然這是整個(gè)塊的預測了,所以不涉及到ABT的問(wèn)題,直接用DC,水平,垂直,Plane四種mode進(jìn)
行編碼,就可以得到四個(gè)mode的預測結果.
得到預測結果之后,我們用orignal的數據減去我們預測的數據,得到的就是residual,不同的mode得到的residual的值是不同的,結
果就是他們所含的能量是不同的,它的結果是編碼所消耗的碼字是不同的,于是乎結果就是不同的.多少年來(lái),做編碼的人們?yōu)榱诉@么
幾個(gè)bits費勁腦力,為了省bits,對比結果的這么些個(gè)功還是得做的.比較的內容就是他們各自的sad(sum of absolute difference)
,SAD最小的那個(gè)mode被稱(chēng)為I16MB分塊方式中最佳的編碼模式.
預測結束之后,我們就使用這個(gè)編碼模式,對residual進(jìn)行DCT與Quantization,結果直接送給熵編碼器進(jìn)行處理,這樣一個(gè)I16MB編碼
完畢.
對于I4MB來(lái)說(shuō):
將16x16的宏塊先分成4個(gè)8x8的子塊,再把各個(gè)子塊各分成4個(gè)4x4的子塊,對每一個(gè)4x4的塊進(jìn)行intra prediction,當然4x4的塊進(jìn)行
預測有9個(gè)mode,是根據它們可能的紋理走向進(jìn)行預測的,最符合紋理方向的mode得到的residual比較小,才會(huì )被選為是最佳編碼的
mode.用最佳的mode得到的最佳intra prediction的值求得相應的residual,計算各自的RD.方法大同小異,計算DCT,送給Quantization,
結果送給熵編碼器,編碼收工.
這樣一直等到16個(gè)4x4的塊編碼完成算是完事.
對于I8MB來(lái)說(shuō):
把一個(gè)16x16的宏塊分成4個(gè)8x8的子塊,對于每一個(gè)子塊都進(jìn)行8x8的prediction.計算的結果,算得residual,將每一個(gè)residual利用
Hadamard變換求得SATD,比較大小,小的那個(gè)為最佳的預測mode.保留最佳residual,進(jìn)行8x8的dct變換,將變換系數保留,編碼結束.
這樣一直進(jìn)行操作,使得整個(gè)幀都被編碼,這時(shí)I幀編碼結束.寫(xiě)出MB Layer數據,寫(xiě)出Macroblock編碼數據,I幀編碼結束.
可以看到對于I幀編碼很容易想到更復雜的算法,比如說(shuō)在一個(gè)宏塊里面使用多種子塊方法等,但是這樣的做法可能會(huì )使得cbp的bits
數過(guò)多,使得bitrate與PSNR的比值不劃算,所以編碼的一個(gè)中心的思想還是很重要的,就是復雜的不見(jiàn)得最優(yōu),數學(xué)理論與實(shí)驗科學(xué)還
是有一些區別的.這也為繼續的研究給出來(lái)一個(gè)啟示,多想想簡(jiǎn)單而出新的想法,不要把一切都歸給數學(xué),警示.
聯(lián)系客服