⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mot_est.c

📁 encoder 视频会议 视频编码算法 源程序
💻 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 + -