您的位置:首页 > 编程语言

如何在JM8.6代码的编码端提取残差(为简便起见,仅以I4x4宏块为例)

2015-05-11 22:32 417 查看
原文转自:http://blog.csdn.net/stpeace/article/details/8205759

要在JM8.6代码中找出某一数据,不能瞎撞,不能用蛮力,而是要根据H.264的流程来找.比如,要在编码端找到像素残差,就可以按照下面的思路来找. (为简便起见,仅以I4x4宏块为例)

提前说一句:有时候对于同一个量,有好几个地方多可以提取,所以思路不要太局限,重要的是知道该量过去从何而来,将来又何去何从. 下面的思路是提取I4x4宏块中残差的思路.(啰嗦一句:如何要提取所有类型宏块的残差,那么仅在下面这个地方提取则是不够的)

前面说过,原始的YUV像素存储在imgY_org中,而编码端要对残差进行变换编码,而encode_one_macroblock就是编码一个宏块的关键函数,所以,如果要在编码端提取残差,就可以尝试在encode_one_macroblock所在的文件搜索imgY_org, 一搜索,还真有,但很多,回想一下,残差是怎么形成的?很显然残差的形成必然涉及到相减,也就是要在代码中找“imgY_org[][] - ...”这样形式的代码. 找找,还真有,但是我们需要的“imgY_org[][] - ...”形式的代码却在Mode_Decision_for_4x4IntraBlocks函数中,没关系的,因为encode_one_macroblock调用了Mode_Decision_for_4x4IntraBlocks函数.

提取残差的代码如下:(其中只有部分代码用于提取残差,以I4x4宏块为例))

[cpp] view
plaincopy





int Mode_Decision_for_4x4IntraBlocks (int b8, int b4, double lambda, int* min_cost)

{

int ipmode, best_ipmode = 0, i, j, k, x, y, cost, dummy;

int c_nz, nonzero = 0, rec4x4[4][4], diff[16];

double rdcost;

int block_x = 8*(b8%2)+4*(b4%2);

int block_y = 8*(b8/2)+4*(b4/2);

int pic_pix_x = img->pix_x+block_x;

int pic_pix_y = img->pix_y+block_y;

int pic_opix_x = img->opix_x+block_x;

int pic_opix_y = img->opix_y+block_y;

int pic_block_x = pic_pix_x/4;

int pic_block_y = pic_pix_y/4;

double min_rdcost = 1e30;

int left_available, up_available, all_available;

int upMode;

int leftMode;

int mostProbableMode;

static int controlFlag = 0;

PixelPos left_block;

PixelPos top_block;

getLuma4x4Neighbour(img->current_mb_nr, block_x/4, block_y/4, -1, 0, &left_block);

getLuma4x4Neighbour(img->current_mb_nr, block_x/4, block_y/4, 0, -1, &top_block);

// constrained intra pred

if (input->UseConstrainedIntraPred)

{

left_block.available = left_block.available ? img->intra_block[left_block.mb_addr] : 0;

top_block.available = top_block.available ? img->intra_block[top_block.mb_addr] : 0;

}

upMode = top_block.available ? img->ipredmode[top_block.pos_x ][top_block.pos_y ] : -1;

leftMode = left_block.available ? img->ipredmode[left_block.pos_x][left_block.pos_y] : -1;

mostProbableMode = (upMode < 0 || leftMode < 0) ? DC_PRED : upMode < leftMode ? upMode : leftMode;

*min_cost = (1<<20);

//===== INTRA PREDICTION FOR 4x4 BLOCK =====

intrapred_luma (pic_pix_x, pic_pix_y, &left_available, &up_available, &all_available);

//===== LOOP OVER ALL 4x4 INTRA PREDICTION MODES =====

for (ipmode=0; ipmode<NO_INTRA_PMODE; ipmode++)

{

int available_mode = (ipmode==DC_PRED) ||

((ipmode==VERT_PRED||ipmode==VERT_LEFT_PRED||ipmode==DIAG_DOWN_LEFT_PRED) && up_available ) ||

((ipmode==HOR_PRED||ipmode==HOR_UP_PRED) && left_available ) ||(all_available);

if( available_mode)

{

if (!input->rdopt)

{

for (k=j=0; j<4; j++)

for (i=0; i<4; i++, k++)

{

diff[k] = imgY_org[pic_opix_y+j][pic_opix_x+i] - img->mprr[ipmode][j][i];

}

cost = (ipmode == mostProbableMode) ? 0 : (int)floor(4 * lambda );

cost += SATD (diff, input->hadamard);

if (cost < *min_cost)

{

best_ipmode = ipmode;

*min_cost = cost;

}

}

else

{

// get prediction and prediction error

for (j=0; j<4; j++)

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

{

img->mpr[block_x+i][block_y+j] = img->mprr[ipmode][j][i];

img->m7[i][j] = imgY_org[pic_opix_y+j][pic_opix_x+i] - img->mprr[ipmode][j][i];

}

//**************************************************************

// 下面是提取残差的代码(原始值,预测值和残差都打印出来)

// controlFlag是static int 类型的变量,用于表示宏块中的小块

// 比如controlFlag为2,则表示第一宏块的第二个4*4小块

controlFlag++;

if(2 == controlFlag)

{

printf("****************************\n");

for (j = 0; j < 4; j++)

{

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

{

printf("%d\t",imgY_org[pic_opix_y+j][pic_opix_x+i]);

}

printf("\n");

}

printf("****************************\n");

for (j = 0; j < 4; j++)

{

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

{

printf("%d\t",img->mprr[ipmode][j][i]);

}

printf("\n");

}

printf("****************************\n");

for (j=0; j<4; j++)

{

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

{

printf("%d\t",img->m7[i][j]);

}

printf("\n");

}

}

//**************************************************************

//===== store the coding state =====

store_coding_state (cs_cm);

// get and check rate-distortion cost

if ((rdcost = RDCost_for_4x4IntraBlocks (&c_nz, b8, b4, ipmode, lambda, min_rdcost, mostProbableMode)) < min_rdcost)

{

//--- set coefficients ---

for (j=0; j<2; j++)

for (i=0; i<18;i++) cofAC4x4[j][i]=img->cofAC[b8][b4][j][i];

//--- set reconstruction ---

for (y=0; y<4; y++)

for (x=0; x<4; x++) rec4x4[y][x] = enc_picture->imgY[pic_pix_y+y][pic_pix_x+x];

//--- flag if dct-coefficients must be coded ---

nonzero = c_nz;

//--- set best mode update minimum cost ---

min_rdcost = rdcost;

best_ipmode = ipmode;

}

reset_coding_state (cs_cm);

}

}

}

//===== set intra mode prediction =====

img->ipredmode[pic_block_x][pic_block_y] = best_ipmode;

img->mb_data[img->current_mb_nr].intra_pred_modes[4*b8+b4] = mostProbableMode == best_ipmode ? -1 : best_ipmode < mostProbableMode ? best_ipmode : best_ipmode-1;

if (!input->rdopt)

{

// get prediction and prediction error

for (j=0; j<4; j++)

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

{

img->mpr[block_x+i][block_y+j] = img->mprr[best_ipmode][j][i];

img->m7[i][j] = imgY_org[pic_opix_y+j][pic_opix_x+i] - img->mprr[best_ipmode][j][i];

}

nonzero = dct_luma (block_x, block_y, &dummy, 1);

}

else

{

//===== restore coefficients =====

for (j=0; j<2; j++)

for (i=0; i<18;i++) img->cofAC[b8][b4][j][i]=cofAC4x4[j][i];

//===== restore reconstruction and prediction (needed if single coeffs are removed) =====

for (y=0; y<4; y++)

for (x=0; x<4; x++)

{

enc_picture->imgY[pic_pix_y+y][pic_pix_x+x] = rec4x4[y][x];

img->mpr[block_x+x][block_y+y] = img->mprr[best_ipmode][y][x];

}

}

return nonzero;

}

结果为:

****************************

251 254 254 253

228 205 213 185

197 173 185 136

177 189 198 160

****************************

238 238 238 238

205 205 205 205

167 167 167 167

160 160 160 160

****************************

13 16 16 15

23 0 8 -20

30 6 18 -31

17 29 38 0

三个矩阵分别对应第一帧第一宏块的第二个4*4块的原始值、预测值和残差,为了验证上述结果的正确性,可以用H.264visa分析一下,结果如下:

原始值为:(注意: H.264visa也可以读取原始的YUV数据)

====================== Y Data ======================

+----------------+----------------+----------------+----------------+

| 43,216,254,249,|251,254,254,253,|251,252,254,254,|254,254,254,253,|

| 49,198,193,211,|228,205,213,185,|211,207,186,248,|198,203,208,183,|

| 48,194,177,171,|197,173,185,136,|191,195,138,179,|142,176,177,135,|

| 46,214,225,169,|177,189,198,160,|203,208,177,165,|173,196,191,156,|

+----------------+----------------+----------------+----------------+

| 41,185,208,180,|203,228,226,200,|214,226,225,227,|228,225,224,210,|

| 31,130,173,178,|215,230,221,212,|220,229,227,228,|229,227,226,226,|

| 29,119,194,216,|211,213,219,222,|225,223,220,219,|218,218,218,218,|

| 25,126,219,224,|217,224,227,227,|227,226,225,224,|220,220,221,222,|

+----------------+----------------+----------------+----------------+

| 26,131,215,223,|226,225,225,225,|225,226,223,219,|221,221,219,220,|

| 30,136,216,226,|223,224,225,225,|224,221,217,221,|222,219,220,226,|

| 30,136,216,227,|224,224,225,223,|221,218,221,216,|211,224,224,211,|

| 29,135,217,225,|222,221,222,222,|221,209,181,155,|186,210,186,164,|

+----------------+----------------+----------------+----------------+

| 29,134,216,224,|226,230,230,227,|206,177,146,113,|149,162,147,150,|

| 29,135,219,231,|225,201,190,185,|163,144,153,140,|127,143,165,184,|

| 30,139,210,192,|165,142,134,133,|143,141,129,138,|150,178,201,207,|

| 30,125,166,145,|144,154,132,111,|118,161,175,180,|204,214,213,209,|

+----------------+----------------+----------------+----------------+

预测值为:(注意:H.264visa相当于一个解码器,解码端的残差和编码端的残差必定相等)

====================== Y Data ======================

+----------------+----------------+----------------+----------------+

|128,128,128,128,|238,238,238,238,|255,255,255,255,|245,228,210,192,|

|128,128,128,128,|205,205,205,205,|180,180,180,180,|210,192,174,170,|

|128,128,128,128,|167,167,167,167,|137,137,137,137,|174,170,166,166,|

|128,128,128,128,|160,160,160,160,|169,169,169,169,|166,166,166,166,|

+----------------+----------------+----------------+----------------+

|161,161,161,161,|179,189,182,169,|201,201,201,201,|219,219,219,219,|

|161,161,161,161,|184,185,175,169,|214,214,214,214,|227,227,227,227,|

|161,161,161,161,|189,182,169,169,|216,216,216,216,|219,219,219,219,|

|161,161,161,161,|185,175,169,169,|229,229,229,229,|227,227,227,227,|

+----------------+----------------+----------------+----------------+

| 28,127,218,229,|224,224,224,224,|227,227,228,227,|224,224,224,224,|

| 28,127,218,229,|224,224,224,224,|224,225,227,227,|214,214,214,214,|

| 28,127,218,229,|224,224,224,224,|224,224,224,225,|212,212,212,212,|

| 28,127,218,229,|224,224,224,224,|224,224,224,224,|165,165,165,165,|

+----------------+----------------+----------------+----------------+

| 33,130,216,224,|231,223,215,194,|204,182,160,142,|127,133,139,147,|

| 33,130,216,224,|215,194,173,162,|160,142,125,120,|139,147,154,165,|

| 33,130,216,224,|173,162,150,150,|125,120,116,116,|154,165,176,176,|

| 33,130,216,224,|150,150,150,150,|116,116,116,116,|176,176,176,176,|

+----------------+----------------+----------------+----------------+

残差为:(注意:H.264visa相当于一个解码器,而解码端的残差与编码端的残差只是近似,并不相等)

====================== Y Data ======================

+------------------------+------------------------+------------------------+------------------------+

| -78, 88, 132, 110,| 24, 14, 24, 19,| -8, 7, -3, -4,| 16, 31, 48, 51,|

| -81, 63, 67, 77,| 30, 1, 11, -25,| 19, 24, 6, 59,| -12, 20, 32, 10,|

| -83, 62, 48, 39,| 25, 6, 16, -30,| 54, 46, 4, 44,| -30, 7, 5, -32,|

| -80, 87, 93, 32,| 14, 24, 34, 9,| 31, 37, 7, -3,| 6, 28, 21, -9,|

+------------------------+------------------------+------------------------+------------------------+

| -117, 22, 51, 22,| 25, 35, 38, 32,| 18, 18, 18, 18,| 5, 5, 5, 5,|

| -135, -22, 22, 19,| 32, 43, 50, 45,| 13, 13, 13, 13,| 3, 3, 3, 3,|

| -131, -38, 38, 55,| 20, 35, 48, 47,| 3, 3, 3, 3,| -2, -2, -2, -2,|

| -133, -34, 57, 68,| 27, 43, 60, 60,| -2, -2, -2, -2,| -5, -5, -5, -5,|

+------------------------+------------------------+------------------------+------------------------+

| 5, 3, -2, -5,| 0, 0, 0, 0,| -4, -4, -3, -3,| -5, -6, -5, -2,|

| 5, 3, -2, -5,| 0, 0, 0, 0,| -3, -5, -10, -13,| -2, 5, 14, 15,|

| 5, 3, -2, -5,| 0, 0, 0, 0,| -3, -5, -10, -13,| 0, 14, 15, 3,|

| 5, 3, -2, -5,| 0, 0, 0, 0,| 2, -13, -44, -59,| 23, 35, 24, 0,|

+------------------------+------------------------+------------------------+------------------------+

| -4, -4, 0, 4,| 1, 5, 18, 26,| 0, 0, -2, -34,| 25, 20, 8, 3,|

| 2, 7, 11, 10,| 13, 3, 9, 25,| 6, 7, 25, 26,| -9, -3, 9, 15,|

| 0, 6, -8, -28,| -5, -11, -17, -17,| 16, 20, 12, 16,| -5, 4, 22, 31,|

| -6, -5, -39, -74,| -9, 3, -10, -34,| 6, 43, 55, 60,| 33, 33, 35, 35,|

+------------------------+------------------------+------------------------+------------------------+

最后,如果上面代码中的if(2 == controlFlag)改为if(1 == controlFlag),那么结果为:

****************************

43 216 254 249

49 198 193 211

48 194 177 171

46 214 225 169

****************************

128 128 128 128

128 128 128 128

128 128 128 128

128 128 128 128

****************************

-85 88 126 121

-79 70 65 83

-80 66 49 43

-82 86 97 41

与上面的H.264visa的结果进行对比,一切都一目了然,便不再赘述了.

P.S. 后来,我发现,上面的过程是有瑕疵的,因为对于一个宏块来说,Mode_Decision_for_4x4IntraBlocks函数不止被调用16次,所以并不对应16个4*4块,为什么会有这种情况呢?跟踪代码后发现,原来对于一个4*4块而言,要选出最终最合理的帧内预测模式,所要进行的DCT变换次数远不止16次. 所以如果要真正在编码端提取像素残差,就应该对这么多次有所选择, 而JM8.6代码必然要作出了这样的选择,找找就可以了.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: