?? mot_est.c
字號:
#include"sim.h"/********************************************************************** * * 函數名:MotionEstimation * 函數功能:估計編碼塊的所有運動向量 * 函數輸入:curr:當前幀圖像數據的指針
* prev:上一幀圖像數據的指針
* x_curr:當前幀圖像分片的位置(水平方向)
* y_curr:當前幀圖像分片的位置(豎直方向)
* xoff:編碼宏塊的水平位置
* yoff:編碼宏塊的豎直位置
* seek_dist:運動估計的搜索區域
* MV:運動向量
* SAD_0:宏塊的SAD值 * 函數返回值:編碼宏塊中運動向量信息 ***********************************************************************/void MotionEstimation(unsigned char *curr, unsigned char *prev, int x_curr, int y_curr, int xoff, int yoff, int seek_dist, MotionVector *MV[6][MBR+1][MBC+2], int *SAD_0){ int Min_FRAME[5]; MotionVector MV_FRAME[5]; unsigned char *act_block,*aa,*ii; unsigned char *search_area, *adv_search_area = NULL, *zero_area = NULL; int sxy,i,k,j,l; int ihigh,ilow,jhigh,jlow,h_length,v_length; int adv_ihigh,adv_ilow,adv_jhigh,adv_jlow,adv_h_length,adv_v_length; int xmax,ymax,block,sad,lx; int adv_x_curr, adv_y_curr,xvec,yvec; xmax = pels; ymax = lines; sxy = seek_dist; if (!long_vectors) { /* 以零向量為中心的最大搜索區域 */ sxy = mmin(15, sxy); } else { /* 以預測為中心的最大擴展搜索范圍*/ sxy = mmin(15 - (2*DEF_8X8_WIN+1), sxy); /* 對任意8x8和16x16的編碼塊,只有那些處在運動向量預測
周圍15x15的窗口區域的運動向量才能被傳送出來。 */ xoff = mmin(16,mmax(-16,xoff)); yoff = mmin(16,mmax(-16,yoff)); } /* 通常不需要檢查(xoff + x_curr)的點是否在圖像幀之外,這是因為
擴展運動區域總是同非限制性的MV模式同時使用 */ lx = (mv_outside_frame ? pels + (long_vectors?64:32) : pels); ilow = x_curr + xoff - sxy; ihigh = x_curr + xoff + sxy; jlow = y_curr + yoff - sxy; jhigh = y_curr + yoff + sxy; if (!mv_outside_frame) { if (ilow<0) ilow = 0; if (ihigh>xmax-16) ihigh = xmax-16; if (jlow<0) jlow = 0; if (jhigh>ymax-16) jhigh = ymax-16; }
/* 編碼塊和運動估計搜索區域 */ h_length = ihigh - ilow + 16; v_length = jhigh - jlow + 16; act_block = LoadArea(curr, x_curr, y_curr, 16, 16, pels); search_area = LoadArea(prev, ilow, jlow, h_length, v_length, lx); for (k = 0; k < 5; k++) { Min_FRAME[k] = INT_MAX; MV_FRAME[k].x = 0; MV_FRAME[k].y = 0; MV_FRAME[k].x_half = 0; MV_FRAME[k].y_half = 0; } /* 零向量搜索 */ if (x_curr-ilow < 0 || y_curr-jlow < 0 || x_curr-ilow+MB_SIZE > h_length || y_curr-jlow+MB_SIZE > v_length) { /* 防止零向量跳出搜索區域的有效面積 */ zero_area = LoadArea(prev, x_curr, y_curr, 16, 16, lx); *SAD_0 = SAD_Macroblock(zero_area, act_block, 16, Min_FRAME[0]) - PREF_NULL_VEC; free(zero_area); } else { /* 零向量位于搜索區域內 */ ii = search_area + (x_curr-ilow) + (y_curr-jlow)*h_length; *SAD_0 = SAD_Macroblock(ii, act_block, h_length, Min_FRAME[0]) - PREF_NULL_VEC; } /* 如果xoff和yoff等于0,即SAD_0成為最佳的編碼塊SAD值,那么零向量
在所有模式下都可傳送,而不需要考慮MV預測值是怎么樣的。*/ if (xoff == 0 && yoff == 0) { Min_FRAME[0] = *SAD_0; MV_FRAME[0].x = 0; MV_FRAME[0].y = 0; }
/* 如果xoff或yoff不等于0,那么系統使用擴展的MV搜索范圍。*/ else { ii = search_area + (x_curr+xoff-ilow) + (y_curr+yoff-jlow)*h_length; Min_FRAME[0] = SAD_Macroblock(ii, act_block, h_length, Min_FRAME[0]); MV_FRAME[0].x = xoff; MV_FRAME[0].y = yoff; } /* 盤旋搜索 */ for (l = 1; l <= sxy; l++) { i = x_curr + xoff - l; j = y_curr + yoff - l; for (k = 0; k < 8*l; k++) { if (i>=ilow && i<=ihigh && j>=jlow && j<=jhigh) { /* 16x16整數個像素MV */ ii = search_area + (i-ilow) + (j-jlow)*h_length; sad = SAD_Macroblock(ii, act_block, h_length, Min_FRAME[0]); if (sad < Min_FRAME[0]) { MV_FRAME[0].x = i - x_curr; MV_FRAME[0].y = j - y_curr; Min_FRAME[0] = sad; } } if (k<2*l) i++; else if (k<4*l) j++; else if (k<6*l) i--; else j--; } } if (advanced) { /* 以8x8的區域為中心尋找16x16的運動向量,這里仍然采用全局搜索的方法。
這樣做的原因:1)這種方法更快;2)這種方法能得到更好的結果;3)如
果運用了擴展的MV搜索范圍,那么在運動向量預測周圍的搜索范圍將會降低
限制。*/ xvec = MV_FRAME[0].x; yvec = MV_FRAME[0].y; if (!long_vectors) { if (xvec > 15 - DEF_8X8_WIN) { xvec = 15 - DEF_8X8_WIN ;} if (yvec > 15 - DEF_8X8_WIN) { yvec = 15 - DEF_8X8_WIN ;} if (xvec < -15 + DEF_8X8_WIN) { xvec = -15 + DEF_8X8_WIN ;} if (yvec < -15 + DEF_8X8_WIN) { yvec = -15 + DEF_8X8_WIN ;} } adv_x_curr = x_curr + xvec; adv_y_curr = y_curr + yvec; sxy = DEF_8X8_WIN; adv_ilow = adv_x_curr - sxy; adv_ihigh = adv_x_curr + sxy; adv_jlow = adv_y_curr - sxy; adv_jhigh = adv_y_curr + sxy; adv_h_length = adv_ihigh - adv_ilow + 16; adv_v_length = adv_jhigh - adv_jlow + 16; adv_search_area = LoadArea(prev, adv_ilow, adv_jlow, adv_h_length, adv_v_length, lx); for (block = 0; block < 4; block++) { ii = adv_search_area + (adv_x_curr-adv_ilow) + ((block&1)<<3) + (adv_y_curr-adv_jlow + ((block&2)<<2) )*adv_h_length; aa = act_block + ((block&1)<<3) + ((block&2)<<2)*16; Min_FRAME[block+1] = SAD_Block(ii,aa,adv_h_length,Min_FRAME[block+1]); MV_FRAME[block+1].x = MV_FRAME[0].x; MV_FRAME[block+1].y = MV_FRAME[0].y; } /* 盤旋搜索 */ for (l = 1; l <= sxy; l++) { i = adv_x_curr - l; j = adv_y_curr - l; for (k = 0; k < 8*l; k++) { if (i>=adv_ilow && i<=adv_ihigh && j>=adv_jlow && j<=adv_jhigh) { /* 8x8整數個像素MV */ for (block = 0; block < 4; block++) { ii = adv_search_area + (i-adv_ilow) + ((block&1)<<3) + (j-adv_jlow + ((block&2)<<2) )*adv_h_length; aa = act_block + ((block&1)<<3) + ((block&2)<<2)*16; sad = SAD_Block(ii, aa, adv_h_length, Min_FRAME[block+1]); if (sad < Min_FRAME[block+1]) { MV_FRAME[block+1].x = i - x_curr; MV_FRAME[block+1].y = j - y_curr; Min_FRAME[block+1] = sad; } } } if (k<2*l) i++; else if (k<4*l) j++; else if (k<6*l) i--; else j--; } } } i = x_curr/MB_SIZE+1; j = y_curr/MB_SIZE+1; if (!advanced) { MV[0][j][i]->x = MV_FRAME[0].x; MV[0][j][i]->y = MV_FRAME[0].y; MV[0][j][i]->min_error = Min_FRAME[0]; } else { for (k = 0; k < 5; k++) { MV[k][j][i]->x = MV_FRAME[k].x; MV[k][j][i]->y = MV_FRAME[k].y; MV[k][j][i]->min_error = Min_FRAME[k]; } } free(act_block); free(search_area); if (advanced) free(adv_search_area); return;}/********************************************************************** * * 函數名:LoadArea * 函數功能:利用一個方塊區域的圖像數據填充矩陣 * 函數輸入:im:圖像塊數據指針
* x:圖像塊的水平位置
* y:圖像塊的豎直位置
* x_size:矩陣的水平尺寸
* y_size:矩陣的豎直尺寸
* lx:輔助變量,將矩陣和圖像的訪問形式轉換為一維數組形式 * 函數返回值:圖像區域數據指針 ***********************************************************************/unsigned char *LoadArea(unsigned char *im, int x, int y, int x_size, int y_size, int lx){ unsigned char *res = (unsigned char *)malloc(sizeof(char)*x_size*y_size); unsigned char *in; unsigned char *out; int i = x_size; int j = y_size; in = im + (y*lx) + x; out = res; while (j--) { while (i--) *out++ = *in++; i = x_size; in += lx - x_size; }; return res;}/********************************************************************** * * 函數名:SAD_Macroblock * 函數功能:計算一個運動向量的SAD值 * 函數輸入值:ii:當前搜索區域的數據指針
* act_block:當前的編碼塊
* h_length:編碼塊高度值
* Min_FRAME:當前幀最小的SAD值
* 函數返回值:宏塊運動向量的SAD值 ***********************************************************************/int SAD_Macroblock(unsigned char *ii, unsigned char *act_block, int h_length, int Min_FRAME){ int i; int sad = 0; unsigned char *kk; kk = act_block; i = 16; while (i--) { sad += (abs(*ii - *kk ) +abs(*(ii+1 ) - *(kk+1) ) +abs(*(ii+2) - *(kk+2) ) +abs(*(ii+3 ) - *(kk+3) ) +abs(*(ii+4) - *(kk+4) ) +abs(*(ii+5 ) - *(kk+5) ) +abs(*(ii+6) - *(kk+6) ) +abs(*(ii+7 ) - *(kk+7) ) +abs(*(ii+8) - *(kk+8) ) +abs(*(ii+9 ) - *(kk+9) ) +abs(*(ii+10)- *(kk+10)) +abs(*(ii+11) - *(kk+11)) +abs(*(ii+12)- *(kk+12)) +abs(*(ii+13) - *(kk+13)) +abs(*(ii+14)- *(kk+14)) +abs(*(ii+15) - *(kk+15)) ); ii += h_length; kk += 16; if (sad > Min_FRAME) return INT_MAX; } return sad;}int SAD_Block(unsigned char *ii, unsigned char *act_block, int h_length, int min_sofar){ int i; int sad = 0; unsigned char *kk; kk = act_block; i = 8; while (i--) { sad += (abs(*ii - *kk ) +abs(*(ii+1 ) - *(kk+1) ) +abs(*(ii+2) - *(kk+2) ) +abs(*(ii+3 ) - *(kk+3) ) +abs(*(ii+4) - *(kk+4) ) +abs(*(ii+5 ) - *(kk+5) ) +abs(*(ii+6) - *(kk+6) ) +abs(*(ii+7 ) - *(kk+7) )); ii += h_length; kk += 16; if (sad > min_sofar) return INT_MAX; } return sad;}int SAD_MB_Bidir(unsigned char *ii, unsigned char *aa, unsigned char *bb, int width, int min_sofar){ int i, sad = 0; unsigned char *ll, *kk; kk = aa; ll = bb; i = 16; while (i--) { sad += (abs(*ii - ((*kk + *ll )>>1)) + abs(*(ii+1) - ((*(kk+1)+ *(ll+1))>>1)) + abs(*(ii+2) - ((*(kk+2)+ *(ll+2))>>1)) + abs(*(ii+3) - ((*(kk+3)+ *(ll+3))>>1)) + abs(*(ii+4) - ((*(kk+4)+ *(ll+4))>>1)) + abs(*(ii+5) - ((*(kk+5)+ *(ll+5))>>1)) + abs(*(ii+6) - ((*(kk+6)+ *(ll+6))>>1)) + abs(*(ii+7) - ((*(kk+7)+ *(ll+7))>>1)) + abs(*(ii+8) - ((*(kk+8)+ *(ll+8))>>1)) + abs(*(ii+9) - ((*(kk+9)+ *(ll+9))>>1)) + abs(*(ii+10) - ((*(kk+10)+ *(ll+10))>>1)) + abs(*(ii+11) - ((*(kk+11)+ *(ll+11))>>1)) + abs(*(ii+12) - ((*(kk+12)+ *(ll+12))>>1)) + abs(*(ii+13) - ((*(kk+13)+ *(ll+13))>>1)) + abs(*(ii+14) - ((*(kk+14)+ *(ll+14))>>1)) + abs(*(ii+15) - ((*(kk+15)+ *(ll+15))>>1))); ii += width; kk += width; ll += width; if (sad > min_sofar) return INT_MAX; } return sad;}int SAD_MB_integer(int *ii, int *act_block, int h_length, int min_sofar){ int i, sad = 0, *kk; kk = act_block; i = 16; while (i--) { sad += (abs(*ii - *kk ) +abs(*(ii+1 ) - *(kk+1) ) +abs(*(ii+2) - *(kk+2) ) +abs(*(ii+3 ) - *(kk+3) ) +abs(*(ii+4) - *(kk+4) ) +abs(*(ii+5 ) - *(kk+5) ) +abs(*(ii+6) - *(kk+6) ) +abs(*(ii+7 ) - *(kk+7) ) +abs(*(ii+8) - *(kk+8) ) +abs(*(ii+9 ) - *(kk+9) ) +abs(*(ii+10)- *(kk+10)) +abs(*(ii+11) - *(kk+11)) +abs(*(ii+12)- *(kk+12)) +abs(*(ii+13) - *(kk+13)) +abs(*(ii+14)- *(kk+14)) +abs(*(ii+15) - *(kk+15)) ); ii += h_length; kk += 16; if (sad > min_sofar) return INT_MAX; } return sad;}/********************************************************************** * * 函數名:FindMB
* 函數功能:從當前視頻幀中找出一個編碼宏塊
* 函數輸入:x:所要尋找的宏塊的水平位置
* y:所要尋找的宏塊的豎直位置
* image:視頻幀的數據指針
* MB:一個空的16x16大小的二維數組,存放宏塊的數據 ***********************************************************************/void FindMB(int x, int y, unsigned char *image, int MB[16][16]){ int n; register int m; for (n = 0; n < MB_SIZE; n++) for (m = 0; m < MB_SIZE; m++) MB[n][m] = *(image + x+m + (y+n)*pels);}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -