/* File: sv_h263_motion.c */ /***************************************************************************** ** Copyright (c) Digital Equipment Corporation, 1995, 1997 ** ** ** ** All Rights Reserved. Unpublished rights reserved under the copyright ** ** laws of the United States. ** ** ** ** The software contained on this media is proprietary to and embodies ** ** the confidential technology of Digital Equipment Corporation. ** ** Possession, use, duplication or dissemination of the software and ** ** media is authorized only pursuant to a valid written license from ** ** Digital Equipment Corporation. ** ** ** ** RESTRICTED RIGHTS LEGEND Use, duplication, or disclosure by the U.S. ** ** Government is subject to restrictions as set forth in Subparagraph ** ** (c)(1)(ii) of DFARS 252.227-7013, or in FAR 52.227-19, as applicable. ** ******************************************************************************/ #include "sv_h263.h" #include "proto.h" /* #define USE_C */ #ifndef USE_C #include "perr.h" #endif static unsigned char *sv_H263LoadArea(unsigned char *im, int x, int y, int x_size, int y_size, int lx); /********************************************************************** * * Name: MotionEstimation * Description: Estimate all motionvectors for one MB * * Input: pointers to current an previous image, * pointers to current slice and current MB * Returns: * Side effects: motion vector imformation in MB changed * ***********************************************************************/ void sv_H263MotionEstimation(SvH263CompressInfo_t *H263Info, unsigned char *curr, unsigned char *prev, int x_curr, int y_curr, int xoff, int yoff, int seek_dist, H263_MotionVector *MV[6][H263_MBR+1][H263_MBC+2], int *SAD_0) { int Min_FRAME[5]; H263_MotionVector MVframe[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 = H263Info->pels; ymax = H263Info->lines; sxy = seek_dist; if (!H263Info->long_vectors) { /* Maximum normal search range centered around _zero-vector_ */ sxy = mmin(15, sxy); } else { /* Maximum extended search range centered around _predictor_ */ sxy = mmin(15 - (2*H263_DEF_8X8_WIN+1), sxy); /* NB! */ /* It is only possible to transmit motion vectors within a 15x15 window around the motion vector predictor for any 8x8 or 16x16 block */ /* The reason for the search window's reduction above with 2*DEF_8X8_WIN+1 is that the 8x8 search may change the MV predictor for some of the blocks within the macroblock. When we impose the limitation above, we are sure that any 8x8 vector we might find is possible to transmit */ /* We have found that with OBMC, DEF_8X8_WIN should be quite small for two reasons: (i) a good filtering effect, and (ii) not too many bits used for transferring the vectors. As can be seen above this is also useful to avoid a large limitation on the MV search range */ /* It is possible to make sure the motion vectors found are legal in other less limiting ways than above, but this would be more complicated as well as time-consuming. Any good suggestions for improvement is welcome, though */ #ifdef USE_C xoff = mmin(16,mmax(-16,xoff)); yoff = mmin(16,mmax(-16,yoff)); #else xoff = sv_H263lim_S(xoff,-16,16); yoff = sv_H263lim_S(yoff,-16,16); #endif /* There is no need to check if (xoff + x_curr) points outside the picture, since the Extended Motion Vector Range is always used together with the Unrestricted MV mode */ } lx = (H263Info->mv_outside_frame ? H263Info->pels + (H263Info->long_vectors?64:32) : H263Info->pels); ilow = x_curr + xoff - sxy; ihigh = x_curr + xoff + sxy; jlow = y_curr + yoff - sxy; jhigh = y_curr + yoff + sxy; if (!H263Info->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; #if 1 act_block = curr + x_curr + y_curr * H263Info->pels; search_area = prev + ilow + jlow * lx; #else act_block = sv_H263LoadArea(curr, x_curr, y_curr, 16, 16, H263Info->pels); search_area = sv_H263LoadArea(prev, ilow, jlow, h_length, v_length, lx); #endif for (k = 0; k < 5; k++) { Min_FRAME[k] = INT_MAX; MVframe[k].x = 0; MVframe[k].y = 0; MVframe[k].x_half = 0; MVframe[k].y_half = 0; } /* Zero vector search*/ if (x_curr-ilow < 0 || y_curr-jlow < 0 || x_curr-ilow+H263_MB_SIZE > h_length || y_curr-jlow+H263_MB_SIZE > v_length) { /* in case the zero vector is outside the loaded area in search_area */ #ifndef USE_C zero_area = prev + x_curr + y_curr * lx; *SAD_0 = sv_H263PError16x16_S(zero_area, act_block, lx, H263Info->pels, INT_MAX) - H263_PREF_NULL_VEC; #else zero_area = prev + x_curr + y_curr * lx; *SAD_0 = sv_H263SADMacroblock(zero_area, act_block, lx, H263Info->pels, INT_MAX) - H263_PREF_NULL_VEC; #endif } else { /* the zero vector is within search_area */ #ifndef USE_C ii = search_area + (x_curr-ilow) + (y_curr-jlow)*lx; *SAD_0 = sv_H263PError16x16_S(ii, act_block, lx, H263Info->pels, INT_MAX) - H263_PREF_NULL_VEC; #else ii = search_area + (x_curr-ilow) + (y_curr-jlow)*lx; *SAD_0 = sv_H263SADMacroblock(ii, act_block, lx, H263Info->pels, INT_MAX) - H263_PREF_NULL_VEC; #endif } if (xoff == 0 && yoff == 0) { Min_FRAME[0] = *SAD_0; MVframe[0].x = 0; MVframe[0].y = 0; } else { #ifndef USE_C ii = search_area + (x_curr+xoff-ilow) + (y_curr+yoff-jlow)*lx; sad = sv_H263PError16x16_S(ii, act_block, lx, H263Info->pels, Min_FRAME[0]); #else ii = search_area + (x_curr+xoff-ilow) + (y_curr+yoff-jlow)*lx; sad = sv_H263SADMacroblock(ii, act_block, lx, H263Info->pels, Min_FRAME[0]); #endif MVframe[0].x = (short)xoff; MVframe[0].y = (short)yoff; } /* NB: if xoff or yoff != 0, the Extended MV Range is used. If we allow the zero vector to be chosen prior to the half pel search in this case, the half pel search might lead to a non-transmittable vector (on the wrong side of zero). If SAD_0 turns out to be the best SAD, the zero-vector will be chosen after half pel search instead. The zero-vector can be transmitted in all modes, no matter what the MV predictor is */ /* Spiral search */ 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 integer pel MV */ #ifndef USE_C ii = search_area + (i-ilow) + (j-jlow)*lx; sad = sv_H263PError16x16_S(ii, act_block, lx, H263Info->pels, Min_FRAME[0]); #else ii = search_area + (i-ilow) + (j-jlow)*lx; sad = sv_H263SADMacroblock(ii, act_block, lx, H263Info->pels, Min_FRAME[0]); #endif if (sad < Min_FRAME[0]) { MVframe[0].x = i - x_curr; MVframe[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 (H263Info->advanced) { /* Center the 8x8 search around the 16x16 vector. This is different than in TMN5 where the 8x8 search is also a full search. The reasons for this is: (i) it is faster, and (ii) it generally gives better results because of a better OBMC filtering effect and less bits spent for vectors, and (iii) if the Extended MV Range is used, the search range around the motion vector predictor will be less limited */ xvec = MVframe[0].x; yvec = MVframe[0].y; if (!H263Info->long_vectors) { if (xvec > 15 - H263_DEF_8X8_WIN) { xvec = 15 - H263_DEF_8X8_WIN ;} if (yvec > 15 - H263_DEF_8X8_WIN) { yvec = 15 - H263_DEF_8X8_WIN ;} if (xvec < -15 + H263_DEF_8X8_WIN) { xvec = -15 + H263_DEF_8X8_WIN ;} if (yvec < -15 + H263_DEF_8X8_WIN) { yvec = -15 + H263_DEF_8X8_WIN ;} } adv_x_curr = x_curr + xvec; adv_y_curr = y_curr + yvec; sxy = H263_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 = sv_H263LoadArea(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; #ifndef USE_C aa = act_block + ((block&1)<<3) + ((block&2)<<2)*H263Info->pels; Min_FRAME[block+1] = sv_H263PError8x8_S(ii,aa,adv_h_length,H263Info->pels,Min_FRAME[block+1]); #else aa = act_block + ((block&1)<<3) + ((block&2)<<2)*H263Info->pels; Min_FRAME[block+1] = sv_H263MySADBlock(ii,aa,adv_h_length,H263Info->pels,Min_FRAME[block+1]); #endif MVframe[block+1].x = MVframe[0].x; MVframe[block+1].y = MVframe[0].y; } /* Spiral search */ 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 integer pel MVs */ 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; #ifndef USE_C aa = act_block + ((block&1)<<3) + ((block&2)<<2)*H263Info->pels; sad = sv_H263PError8x8_S(ii, aa, adv_h_length, H263Info->pels, Min_FRAME[block+1]); #else aa = act_block + ((block&1)<<3) + ((block&2)<<2)*H263Info->pels; sad = sv_H263MySADBlock(ii, aa, adv_h_length, H263Info->pels, Min_FRAME[block+1]); #endif if (sad < Min_FRAME[block+1]) { MVframe[block+1].x = i - x_curr; MVframe[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/H263_MB_SIZE+1; j = y_curr/H263_MB_SIZE+1; if (!H263Info->advanced) { MV[0][j][i]->x = MVframe[0].x; MV[0][j][i]->y = MVframe[0].y; MV[0][j][i]->min_error = (short)Min_FRAME[0]; } else { for (k = 0; k < 5; k++) { MV[k][j][i]->x = MVframe[k].x; MV[k][j][i]->y = MVframe[k].y; MV[k][j][i]->min_error = (short)Min_FRAME[k]; } } #if 0 ScFree(act_block); ScFree(search_area); #endif if (H263Info->advanced) ScFree(adv_search_area); return; } /********************************************************************** * * Name: LoadArea * Description: fills array with a square of image-data * * Input: pointer to image and position, x and y size * Returns: pointer to area * Side effects: memory allocated to array * ***********************************************************************/ #if 1 static unsigned char *sv_H263LoadArea(unsigned char *im, int x, int y, int x_size, int y_size, int lx) { unsigned char *res = (unsigned char *)ScAlloc(sizeof(char)*x_size*y_size); register unsigned char *in, *out; in = im + (y*lx) + x; out = res; while (y_size--) { memcpy(out,in,x_size) ; in += lx ; out += x_size; }; return res; } #else static unsigned char *svH263LoadArea(unsigned char *im, int x, int y, int x_size, int y_size, int lx) { unsigned char *res = (unsigned char *)ScAlloc(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; } #endif /********************************************************************** * * Name: SAD_Macroblock * Description: fast way to find the SAD of one vector * * Input: pointers to search_area and current block, * Min_F1/F2/FR * Returns: sad_f1/f2 * Side effects: * ***********************************************************************/ #ifdef USE_C /* replaced by sv_H263PError16x16_S */ int sv_H263SADMacroblock(unsigned char *ii, unsigned char *act_block, int h_length, int lx2, int Min_FRAME) { unsigned char *kk; int i; int sad = 0; 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 += lx2; if (sad > Min_FRAME) return INT_MAX; } return sad; } #endif #ifdef USE_C /* replaced by sv_H263PError8x8_S */ int svH263SAD_Block(unsigned char *ii, unsigned char *act_block, int h_length, int min_sofar) { unsigned char *kk; int i; int sad = 0; 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; } #endif int sv_H263BError16x16_C(unsigned char *ii, unsigned char *aa, unsigned char *bb, int width, int min_sofar) { unsigned char *ll, *kk; int i, sad = 0; 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; } /********************************************************************** * * Name: FindMB * Description: Picks out one MB from picture * * Input: position of MB to pick out, * pointer to frame data, empty 16x16 array * Returns: * Side effects: fills array with MB data * ***********************************************************************/ void sv_H263FindMB(SvH263CompressInfo_t *H263Info, int x, int y, unsigned char *image, short MB[16][16]) { #ifndef USE_C sv_H263CtoI16_S((image + y*H263Info->pels + x), &(MB[0][0]), H263Info->pels); #else register int m, n; int xdiff = H263Info->pels - H263_MB_SIZE; unsigned char *in; short *out; in = image + y*H263Info->pels + x; out = &(MB[0][0]); m = H263_MB_SIZE; while (m--) { n = H263_MB_SIZE; while (n--) *out++ = *in++; in += xdiff ; }; #endif } /********************************************************************** * * Name: MotionEstimation * Description: Estimate all motionvectors for one MB * * Input: pointers to current an previous image, * pointers to current slice and current MB * Returns: * Side effects: motion vector information in MB changed * ***********************************************************************/ void sv_H263FastME(SvH263CompressInfo_t *H263Info, unsigned char *curr, unsigned char *prev, int x_curr, int y_curr, int xoff, int yoff, int seek_dist, short *MVx, short *MVy, short *MVer, int *SAD_0) { int Min_FRAME; H263_MotionVector MVframe; int sxy,i,k,j; int ihigh,ilow,jhigh,jlow,h_length,v_length; unsigned char *act_block,*ii,*search_area, *zero_area = NULL; int h_lenby2,v_lenby2; unsigned char *act_block_subs2, *search_area_subs2; int xmax,ymax,sad; int xlevel1,ylevel1; int level1_x_curr,level1_y_curr; int level0_x_curr,level0_y_curr; xmax = H263Info->pels; ymax = H263Info->lines; sxy = seek_dist; sxy = mmin(15, sxy); ilow = x_curr + xoff - sxy; ihigh = x_curr + xoff + sxy; jlow = y_curr + yoff - sxy; jhigh = y_curr + yoff + sxy; 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 = curr + x_curr + y_curr * H263Info->pels; search_area = prev + ilow + jlow * H263Info->pels; /* subsampled version for ME level 1 */ h_lenby2 = (h_length-1)>>1; v_lenby2 = (v_length-1)>>1; act_block_subs2 = H263Info->block_subs2; search_area_subs2 = H263Info->srch_area_subs2; sv_H263LdSubs2Area(curr, x_curr, y_curr, 8, 8, H263Info->pels, act_block_subs2, 8); sv_H263LdSubs2Area(prev, ilow, jlow, h_lenby2, v_lenby2, H263Info->pels, search_area_subs2, H263_SRCH_RANGE); Min_FRAME = INT_MAX; MVframe.x = 0; MVframe.y = 0; MVframe.x_half = 0; MVframe.y_half = 0; /* match for zero (or [xoff,yoff]) motion vector on subsampled images */ ii = search_area_subs2 + ((x_curr+xoff-ilow)>>1) + ((y_curr+yoff-jlow)>>1)*H263_SRCH_RANGE; #ifndef USE_C Min_FRAME = sv_H263PEr8_init_S(ii,act_block_subs2,H263_SRCH_RANGE,8); #else Min_FRAME = sv_H263MySADBlock(ii,act_block_subs2,H263_SRCH_RANGE,8,INT_MAX); #endif MVframe.x = (short)xoff; MVframe.y = (short)yoff; /*** +-7 search on subsampled images: *** *** three-step +-4, +-2, +-1 ***/ /* first step: +- 4 */ /* sxylevel1 = 4; */ i = x_curr + xoff - 8; j = y_curr + yoff - 8; for (k = 0; k < 32; k++) { if (i>=ilow && i<=ihigh && j>=jlow && j<=jhigh) { /* 8x8 integer pel MV */ ii = search_area_subs2+((i-ilow)>>1) + ((j-jlow)>>1)*H263_SRCH_RANGE; #ifndef USE_C sad = sv_H263PError8x8_S(ii,act_block_subs2,H263_SRCH_RANGE,8,Min_FRAME); #else sad = sv_H263MySADBlock(ii,act_block_subs2,H263_SRCH_RANGE,8,Min_FRAME); #endif if (sad < Min_FRAME) { MVframe.x = i - x_curr; MVframe.y = j - y_curr; Min_FRAME = sad; } } if (k<8) i+=2; else if (k<16) j+=2; else if (k<24) i-=2; else j-=2; } /* second step: +- 2 */ /* sxylevel1 = 2; */ level1_x_curr = x_curr + MVframe.x; level1_y_curr = y_curr + MVframe.y; i = level1_x_curr - 4; j = level1_y_curr - 4; for (k = 0; k < 16; k++) { if (i>=ilow && i<=ihigh && j>=jlow && j<=jhigh) { /* 8x8 integer pel MV */ ii = search_area_subs2+((i-ilow)>>1) + ((j-jlow)>>1) * H263_SRCH_RANGE; #ifndef USE_C sad = sv_H263PError8x8_S(ii,act_block_subs2,H263_SRCH_RANGE,8,Min_FRAME); #else sad = sv_H263MySADBlock(ii,act_block_subs2,H263_SRCH_RANGE,8,Min_FRAME); #endif if (sad < Min_FRAME) { MVframe.x = i - x_curr; MVframe.y = j - y_curr; Min_FRAME = sad; } } if (k<4) i+=2; else if (k<8) j+=2; else if (k<12) i-=2; else j-=2; } /* third step: +- 1 */ /* sxylevel1 = 1; */ level1_x_curr = x_curr + MVframe.x; level1_y_curr = y_curr + MVframe.y; i = level1_x_curr - 2; j = level1_y_curr - 2; for (k = 0; k < 8; k++) { if (i>=ilow && i<=ihigh && j>=jlow && j<=jhigh) { /* 8x8 integer pel MV */ ii = search_area_subs2+((i-ilow)>>1) + ((j-jlow)>>1) * H263_SRCH_RANGE; #ifndef USE_C sad = sv_H263PError8x8_S(ii,act_block_subs2,H263_SRCH_RANGE,8,Min_FRAME); #else sad = sv_H263MySADBlock(ii,act_block_subs2,H263_SRCH_RANGE,8,Min_FRAME); #endif if (sad < Min_FRAME) { MVframe.x = i - x_curr; MVframe.y = j - y_curr; Min_FRAME = sad; } } if (k<2) i+=2; else if (k<4) j+=2; else if (k<6) i-=2; else j-=2; } /* motion vectors after step3 - level1 */ xlevel1=MVframe.x; ylevel1=MVframe.y; /* reset */ Min_FRAME = INT_MAX; MVframe.x = 0; MVframe.y = 0; /* Zero vector search*/ if (x_curr-ilow < 0 || y_curr-jlow < 0 || x_curr-ilow+H263_MB_SIZE > h_length || y_curr-jlow+H263_MB_SIZE > v_length) { /* in case the zero vector is outside the loaded area in search_area */ zero_area = sv_H263LoadArea(prev, x_curr, y_curr, 16, 16, H263Info->pels); #ifndef USE_C *SAD_0 = sv_H263PError16x16_S(zero_area, act_block, 16, H263Info->pels, INT_MAX) - H263_PREF_NULL_VEC; #else *SAD_0 = sv_H263SADMacroblock(zero_area, act_block, 16, H263Info->pels, INT_MAX) - H263_PREF_NULL_VEC; #endif ScFree(zero_area); } else { /* the zero vector is within search_area */ ii = search_area + (x_curr-ilow) + (y_curr-jlow)*H263Info->pels; #ifndef USE_C *SAD_0 = sv_H263PError16x16_S(ii, act_block, H263Info->pels, H263Info->pels, INT_MAX) - H263_PREF_NULL_VEC; #else *SAD_0 = sv_H263SADMacroblock(ii, act_block, H263Info->pels, H263Info->pels, INT_MAX) - H263_PREF_NULL_VEC; #endif } if (xoff == 0 && yoff == 0) { Min_FRAME = *SAD_0; MVframe.x = 0; MVframe.y = 0; } if (xlevel1 == 0 && ylevel1 == 0) { Min_FRAME = *SAD_0; MVframe.x = 0; MVframe.y = 0; } else { ii = search_area + (x_curr+xlevel1-ilow) + (y_curr+ylevel1-jlow)*H263Info->pels; #ifndef USE_C sad = sv_H263PError16x16_S(ii, act_block, H263Info->pels, H263Info->pels, Min_FRAME) ; #else sad = sv_H263SADMacroblock(ii, act_block, H263Info->pels, H263Info->pels, Min_FRAME) ; #endif if (sad < Min_FRAME) { MVframe.x = (short)xlevel1; MVframe.y = (short)ylevel1; Min_FRAME = sad; } } /* NB: if xoff or yoff != 0, the Extended MV Range is used. If we allow the zero vector to be chosen prior to the half pel search in this case, the half pel search might lead to a non-transmittable vector (on the wrong side of zero). If SAD_0 turns out to be the best SAD, the zero-vector will be chosen after half pel search instead. The zero-vector can be transmitted in all modes, no matter what the MV predictor is */ /*** +-1 search on full-resolution images ***/ level0_x_curr = x_curr + xlevel1; level0_y_curr = y_curr + ylevel1; /* sxylevel0=1; */ i = level0_x_curr - 1; j = level0_y_curr - 1; for (k = 0; k < 8; k++) { if (i>=ilow && i<=ihigh && j>=jlow && j<=jhigh) { /* 16x16 integer pel MV */ ii = search_area + (i-ilow) + (j-jlow)*H263Info->pels; #ifndef USE_C sad = sv_H263PError16x16_S(ii, act_block, H263Info->pels, H263Info->pels, Min_FRAME) ; #else sad = sv_H263SADMacroblock(ii, act_block, H263Info->pels, H263Info->pels, Min_FRAME) ; #endif if (sad < Min_FRAME) { MVframe.x = i - x_curr; MVframe.y = j - y_curr; Min_FRAME = sad; } } if (k<2) i++; else if (k<4) j++; else if (k<6) i--; else j--; } i = x_curr/H263_MB_SIZE+1; j = y_curr/H263_MB_SIZE+1; *MVx = MVframe.x; *MVy = MVframe.y; *MVer = (short)Min_FRAME; return; } #ifdef USE_C int sv_H263MySADBlock(unsigned char *ii, unsigned char *act_block, int h_length, int lx2, int min_sofar) { /* return sv_H263PError8x8_S(ii,act_block,h_length,8,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 += lx2; if (sad > min_sofar) return INT_MAX; } return sad; } #endif /********************************************************************** * * Name: LoadArea * Description: fills array with a square of image-data * * Input: pointer to image and position, x and y size * Returns: pointer to area * Side effects: memory allocated to array * * ***********************************************************************/ void sv_H263LdSubs2Area(unsigned char *im, int x, int y, int x_size, int y_size, int lx, unsigned char *srch_area, int area_length) { register unsigned char *in, *out; register int incrs1, incrs2, i; x = ((x+1)>>1) << 1; /* subsampled images always correspond to pixels*/ y = ((y+1)>>1) << 1; /* of even coordinates in the original image */ in = im + (y*lx) + x; out = srch_area; #ifdef USE_C incrs1 = (lx - x_size) << 1; incrs2 = area_length - x_size; while (y_size--) { i = x_size; while (i--) { *out++ = *in; in+=2; } in += incrs1; out += incrs2; }; #else if(area_length == 8){ sv_H263Subsamp8_S(in, out, y_size, (lx << 1)) ; } else { incrs1 = (lx - x_size) << 1; incrs2 = area_length - x_size; while (y_size--) { i = x_size; while (i--) { *out++ = *in; in+=2; } in += incrs1; out += incrs2; }; } #endif return ; }