diff options
Diffstat (limited to 'src/libffmpeg/libavcodec/motion_est.c')
-rw-r--r-- | src/libffmpeg/libavcodec/motion_est.c | 703 |
1 files changed, 627 insertions, 76 deletions
diff --git a/src/libffmpeg/libavcodec/motion_est.c b/src/libffmpeg/libavcodec/motion_est.c index 084eb6038..92724ac87 100644 --- a/src/libffmpeg/libavcodec/motion_est.c +++ b/src/libffmpeg/libavcodec/motion_est.c @@ -16,6 +16,8 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * new Motion Estimation (X1/EPZS) by Michael Niedermayer <michaelni@gmx.at> */ #include "config.h" #include "xine-utils/xineutils.h" @@ -25,9 +27,14 @@ #include "dsputil.h" #include "mpegvideo.h" +#define ABS(a) ((a)>0 ? (a) : -(a)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define INTER_BIAS 257 + static void halfpel_motion_search(MpegEncContext * s, int *mx_ptr, int *my_ptr, int dmin, - int xmin, int ymin, int xmax, int ymax); + int xmin, int ymin, int xmax, int ymax, + int pred_x, int pred_y); /* config it to test motion vector encoding (send random vectors) */ //#define CONFIG_TEST_MV_ENCODE @@ -54,6 +61,28 @@ static int pix_sum(UINT8 * pix, int line_size) return s; } +static int pix_dev(UINT8 * pix, int line_size, int mean) +{ + int s, i, j; + + s = 0; + for (i = 0; i < 16; i++) { + for (j = 0; j < 16; j += 8) { + s += ABS(pix[0]-mean); + s += ABS(pix[1]-mean); + s += ABS(pix[2]-mean); + s += ABS(pix[3]-mean); + s += ABS(pix[4]-mean); + s += ABS(pix[5]-mean); + s += ABS(pix[6]-mean); + s += ABS(pix[7]-mean); + pix += 8; + } + pix += line_size - 16; + } + return s; +} + static int pix_norm1(UINT8 * pix, int line_size) { int s, i, j; @@ -138,7 +167,7 @@ static int full_motion_search(MpegEncContext * s, for (y = y1; y <= y2; y++) { for (x = x1; x <= x2; x++) { d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, - s->linesize, 16); + s->linesize); if (d < dmin || (d == dmin && (abs(x - xx) + abs(y - yy)) < @@ -202,7 +231,7 @@ static int log_motion_search(MpegEncContext * s, do { for (y = y1; y <= y2; y += range) { for (x = x1; x <= x2; x += range) { - d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize, 16); + d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize); if (d < dmin || (d == dmin && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) { dmin = d; mx = x; @@ -282,7 +311,7 @@ static int phods_motion_search(MpegEncContext * s, lastx = x; for (x = x1; x <= x2; x += range) { - d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize, 16); + d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize); if (d < dminx || (d == dminx && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) { dminx = d; mx = x; @@ -291,7 +320,7 @@ static int phods_motion_search(MpegEncContext * s, x = lastx; for (y = y1; y <= y2; y += range) { - d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize, 16); + d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize); if (d < dminy || (d == dminy && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) { dminy = d; my = y; @@ -330,78 +359,474 @@ static int phods_motion_search(MpegEncContext * s, return dminy; } + +#define Z_THRESHOLD 256 + +#define CHECK_MV(x,y)\ +{\ + d = pix_abs16x16(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride);\ + d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant;\ + if(d<dmin){\ + best[0]=x;\ + best[1]=y;\ + dmin=d;\ + }\ +} + +#define CHECK_MV_DIR(x,y,new_dir)\ +{\ + d = pix_abs16x16(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride);\ + d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant;\ + if(d<dmin){\ + best[0]=x;\ + best[1]=y;\ + dmin=d;\ + next_dir= new_dir;\ + }\ +} + +#define CHECK_MV4(x,y)\ +{\ + d = pix_abs8x8(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride);\ + d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant;\ + if(d<dmin){\ + best[0]=x;\ + best[1]=y;\ + dmin=d;\ + }\ +} + +#define CHECK_MV4_DIR(x,y,new_dir)\ +{\ + d = pix_abs8x8(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride);\ + d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant;\ + if(d<dmin){\ + best[0]=x;\ + best[1]=y;\ + dmin=d;\ + next_dir= new_dir;\ + }\ +} + + +#define check(x,y,S,v)\ +if( (x)<(xmin<<(S)) ) printf("%d %d %d %d xmin" #v, (x), (y), s->mb_x, s->mb_y);\ +if( (x)>(xmax<<(S)) ) printf("%d %d %d %d xmax" #v, (x), (y), s->mb_x, s->mb_y);\ +if( (y)<(ymin<<(S)) ) printf("%d %d %d %d ymin" #v, (x), (y), s->mb_x, s->mb_y);\ +if( (y)>(ymax<<(S)) ) printf("%d %d %d %d ymax" #v, (x), (y), s->mb_x, s->mb_y);\ + + +static inline int small_diamond_search(MpegEncContext * s, int *best, int dmin, + UINT8 *new_pic, UINT8 *old_pic, int pic_stride, + int pred_x, int pred_y, UINT16 *mv_penalty, int quant, + int xmin, int ymin, int xmax, int ymax, int shift) +{ + int next_dir=-1; + + for(;;){ + int d; + const int dir= next_dir; + const int x= best[0]; + const int y= best[1]; + next_dir=-1; + +//printf("%d", dir); + if(dir!=2 && x>xmin) CHECK_MV_DIR(x-1, y , 0) + if(dir!=3 && y>ymin) CHECK_MV_DIR(x , y-1, 1) + if(dir!=0 && x<xmax) CHECK_MV_DIR(x+1, y , 2) + if(dir!=1 && y<ymax) CHECK_MV_DIR(x , y+1, 3) + + if(next_dir==-1){ + return dmin; + } + } + +/* for(;;){ + int d; + const int x= best[0]; + const int y= best[1]; + const int last_min=dmin; + if(x>xmin) CHECK_MV(x-1, y ) + if(y>xmin) CHECK_MV(x , y-1) + if(x<xmax) CHECK_MV(x+1, y ) + if(y<xmax) CHECK_MV(x , y+1) + if(x>xmin && y>ymin) CHECK_MV(x-1, y-1) + if(x>xmin && y<ymax) CHECK_MV(x-1, y+1) + if(x<xmax && y>ymin) CHECK_MV(x+1, y-1) + if(x<xmax && y<ymax) CHECK_MV(x+1, y+1) + if(x-1>xmin) CHECK_MV(x-2, y ) + if(y-1>xmin) CHECK_MV(x , y-2) + if(x+1<xmax) CHECK_MV(x+2, y ) + if(y+1<xmax) CHECK_MV(x , y+2) + if(x-1>xmin && y-1>ymin) CHECK_MV(x-2, y-2) + if(x-1>xmin && y+1<ymax) CHECK_MV(x-2, y+2) + if(x+1<xmax && y-1>ymin) CHECK_MV(x+2, y-2) + if(x+1<xmax && y+1<ymax) CHECK_MV(x+2, y+2) + if(dmin==last_min) return dmin; + } + */ +} + +static inline int small_diamond_search4MV(MpegEncContext * s, int *best, int dmin, + UINT8 *new_pic, UINT8 *old_pic, int pic_stride, + int pred_x, int pred_y, UINT16 *mv_penalty, int quant, + int xmin, int ymin, int xmax, int ymax, int shift) +{ + int next_dir=-1; + + for(;;){ + int d; + const int dir= next_dir; + const int x= best[0]; + const int y= best[1]; + next_dir=-1; + +//printf("%d", dir); + if(dir!=2 && x>xmin) CHECK_MV4_DIR(x-1, y , 0) + if(dir!=3 && y>ymin) CHECK_MV4_DIR(x , y-1, 1) + if(dir!=0 && x<xmax) CHECK_MV4_DIR(x+1, y , 2) + if(dir!=1 && y<ymax) CHECK_MV4_DIR(x , y+1, 3) + + if(next_dir==-1){ + return dmin; + } + } +} + +static inline int snake_search(MpegEncContext * s, int *best, int dmin, + UINT8 *new_pic, UINT8 *old_pic, int pic_stride, + int pred_x, int pred_y, UINT16 *mv_penalty, int quant, + int xmin, int ymin, int xmax, int ymax, int shift) +{ + int dir=0; + int c=1; + static int x_dir[8]= {1,1,0,-1,-1,-1, 0, 1}; + static int y_dir[8]= {0,1,1, 1, 0,-1,-1,-1}; + int fails=0; + int last_d[2]={dmin, dmin}; + +/*static int good=0; +static int bad=0; +static int point=0; + +point++; +if(256*256*256*64%point==0) +{ + printf("%d %d %d\n", good, bad, point); +}*/ + + for(;;){ + int x= best[0]; + int y= best[1]; + int d; + x+=x_dir[dir]; + y+=y_dir[dir]; + if(x>=xmin && x<=xmax && y>=ymin && y<=ymax){ + d = pix_abs16x16(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride); + d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant; + }else{ + d = dmin + 10000; //FIXME smarter boundary handling + } + if(d<dmin){ + best[0]=x; + best[1]=y; + dmin=d; + + if(last_d[1] - last_d[0] > last_d[0] - d) c= -c; + dir+=c; + + fails=0; +//good++; + last_d[1]=last_d[0]; + last_d[0]=d; + }else{ +//bad++; + if(fails){ + if(fails>=3) return dmin; + }else{ + c= -c; + } + dir+=c*2; + fails++; + } + dir&=7; + } +} + +static int epzs_motion_search(MpegEncContext * s, + int *mx_ptr, int *my_ptr, + int P[5][2], int pred_x, int pred_y, + int xmin, int ymin, int xmax, int ymax) +{ + int best[2]={0, 0}; + int d, dmin; + UINT8 *new_pic, *old_pic; + const int pic_stride= s->linesize; + const int pic_xy= (s->mb_y*pic_stride + s->mb_x)*16; + UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame + int quant= s->qscale; // qscale of the prev frame + const int shift= 1+s->quarter_sample; + + new_pic = s->new_picture[0] + pic_xy; + old_pic = s->last_picture[0] + pic_xy; + + dmin = pix_abs16x16(new_pic, old_pic, pic_stride); + if(dmin<Z_THRESHOLD){ + *mx_ptr= 0; + *my_ptr= 0; +//printf("Z"); + return dmin; + } + + /* first line */ + if ((s->mb_y == 0 || s->first_slice_line || s->first_gob_line)) { + CHECK_MV(P[1][0]>>shift, P[1][1]>>shift) + }else{ + CHECK_MV(P[4][0]>>shift, P[4][1]>>shift) + if(dmin<Z_THRESHOLD){ + *mx_ptr= P[4][0]>>shift; + *my_ptr= P[4][1]>>shift; +//printf("M\n"); + return dmin; + } + CHECK_MV(P[1][0]>>shift, P[1][1]>>shift) + CHECK_MV(P[2][0]>>shift, P[2][1]>>shift) + CHECK_MV(P[3][0]>>shift, P[3][1]>>shift) + } + CHECK_MV(P[0][0]>>shift, P[0][1]>>shift) + +//check(best[0],best[1],0, b0) + if(s->full_search==ME_EPZS) + dmin= small_diamond_search(s, best, dmin, new_pic, old_pic, pic_stride, + pred_x, pred_y, mv_penalty, quant, xmin, ymin, xmax, ymax, shift); + else + dmin= snake_search(s, best, dmin, new_pic, old_pic, pic_stride, + pred_x, pred_y, mv_penalty, quant, xmin, ymin, xmax, ymax, shift); +//check(best[0],best[1],0, b1) + *mx_ptr= best[0]; + *my_ptr= best[1]; + +// printf("%d %d %d \n", best[0], best[1], dmin); + return dmin; +} + +static int epzs_motion_search4(MpegEncContext * s, int block, + int *mx_ptr, int *my_ptr, + int P[6][2], int pred_x, int pred_y, + int xmin, int ymin, int xmax, int ymax) +{ + int best[2]={0, 0}; + int d, dmin; + UINT8 *new_pic, *old_pic; + const int pic_stride= s->linesize; + const int pic_xy= ((s->mb_y*2 + (block>>1))*pic_stride + s->mb_x*2 + (block&1))*8; + UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame + int quant= s->qscale; // qscale of the prev frame + const int shift= 1+s->quarter_sample; + + new_pic = s->new_picture[0] + pic_xy; + old_pic = s->last_picture[0] + pic_xy; + + dmin = pix_abs8x8(new_pic, old_pic, pic_stride); + + /* first line */ + if ((s->mb_y == 0 || s->first_slice_line || s->first_gob_line) && block<2) { + CHECK_MV4(P[1][0]>>shift, P[1][1]>>shift) + }else{ + CHECK_MV4(P[4][0]>>shift, P[4][1]>>shift) + if(dmin<Z_THRESHOLD){ + *mx_ptr= P[4][0]>>shift; + *my_ptr= P[4][1]>>shift; +//printf("M\n"); + return dmin; + } + CHECK_MV4(P[1][0]>>shift, P[1][1]>>shift) + CHECK_MV4(P[2][0]>>shift, P[2][1]>>shift) + CHECK_MV4(P[3][0]>>shift, P[3][1]>>shift) + } + CHECK_MV4(P[0][0]>>shift, P[0][1]>>shift) + CHECK_MV4(P[5][0]>>shift, P[5][1]>>shift) + +//check(best[0],best[1],0, b0) + dmin= small_diamond_search4MV(s, best, dmin, new_pic, old_pic, pic_stride, + pred_x, pred_y, mv_penalty, quant, xmin, ymin, xmax, ymax, shift); +//check(best[0],best[1],0, b1) + *mx_ptr= best[0]; + *my_ptr= best[1]; + +// printf("%d %d %d \n", best[0], best[1], dmin); + return dmin; +} + +#define CHECK_HALF_MV(suffix, x, y) \ + d= pix_abs16x16_ ## suffix(pix, ptr+((x)>>1), s->linesize);\ + d += (mv_penalty[pen_x + x] + mv_penalty[pen_y + y])*quant;\ + if(d<dminh){\ + dminh= d;\ + mx= mx1 + x;\ + my= my1 + y;\ + } + +#define CHECK_HALF_MV4(suffix, x, y) \ + d= pix_abs8x8_ ## suffix(pix, ptr+((x)>>1), s->linesize);\ + d += (mv_penalty[pen_x + x] + mv_penalty[pen_y + y])*quant;\ + if(d<dminh){\ + dminh= d;\ + mx= mx1 + x;\ + my= my1 + y;\ + } + /* The idea would be to make half pel ME after Inter/Intra decision to save time. */ -static void halfpel_motion_search(MpegEncContext * s, +static inline void halfpel_motion_search(MpegEncContext * s, int *mx_ptr, int *my_ptr, int dmin, - int xmin, int ymin, int xmax, int ymax) + int xmin, int ymin, int xmax, int ymax, + int pred_x, int pred_y) { + UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame + const int quant= s->qscale; + int pen_x, pen_y; int mx, my, mx1, my1, d, xx, yy, dminh; - UINT8 *pix; + UINT8 *pix, *ptr; - mx = *mx_ptr << 1; - my = *my_ptr << 1; + mx = *mx_ptr; + my = *my_ptr; + ptr = s->last_picture[0] + (my * s->linesize) + mx; xx = 16 * s->mb_x; yy = 16 * s->mb_y; - + pix = s->new_picture[0] + (yy * s->linesize) + xx; + dminh = dmin; - /* Half pixel search */ - mx1 = mx; - my1 = my; + if (mx > xmin && mx < xmax && + my > ymin && my < ymax) { - pix = s->new_picture[0] + (yy * s->linesize) + xx; + mx= mx1= 2*(mx - xx); + my= my1= 2*(my - yy); + if(dmin < Z_THRESHOLD && mx==0 && my==0){ + *mx_ptr = 0; + *my_ptr = 0; + return; + } + + pen_x= pred_x + mx; + pen_y= pred_y + my; + + ptr-= s->linesize; + CHECK_HALF_MV(xy2, -1, -1) + CHECK_HALF_MV(y2 , 0, -1) + CHECK_HALF_MV(xy2, +1, -1) + + ptr+= s->linesize; + CHECK_HALF_MV(x2 , -1, 0) + CHECK_HALF_MV(x2 , +1, 0) + CHECK_HALF_MV(xy2, -1, +1) + CHECK_HALF_MV(y2 , 0, +1) + CHECK_HALF_MV(xy2, +1, +1) + + }else{ + mx= 2*(mx - xx); + my= 2*(my - yy); + } - if ((mx > (xmin << 1)) && mx < (xmax << 1) && - (my > (ymin << 1)) && my < (ymax << 1)) { - int dx, dy, px, py; - UINT8 *ptr; - for (dy = -1; dy <= 1; dy++) { - for (dx = -1; dx <= 1; dx++) { - if (dx != 0 || dy != 0) { - px = mx1 + dx; - py = my1 + dy; - ptr = s->last_picture[0] + ((py >> 1) * s->linesize) + (px >> 1); - switch (((py & 1) << 1) | (px & 1)) { - default: - case 0: - d = pix_abs16x16(pix, ptr, s->linesize, 16); - break; - case 1: - d = pix_abs16x16_x2(pix, ptr, s->linesize, 16); - break; - case 2: - d = pix_abs16x16_y2(pix, ptr, s->linesize, 16); - break; - case 3: - d = pix_abs16x16_xy2(pix, ptr, s->linesize, 16); - break; - } - if (d < dminh) { - dminh = d; - mx = px; - my = py; - } - } - } + *mx_ptr = mx; + *my_ptr = my; +} + +static inline void halfpel_motion_search4(MpegEncContext * s, + int *mx_ptr, int *my_ptr, int dmin, + int xmin, int ymin, int xmax, int ymax, + int pred_x, int pred_y, int block_x, int block_y) +{ + UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame + const int quant= s->qscale; + int pen_x, pen_y; + int mx, my, mx1, my1, d, xx, yy, dminh; + UINT8 *pix, *ptr; + + xx = 8 * block_x; + yy = 8 * block_y; + pix = s->new_picture[0] + (yy * s->linesize) + xx; + + mx = *mx_ptr; + my = *my_ptr; + ptr = s->last_picture[0] + ((yy+my) * s->linesize) + xx + mx; + + dminh = dmin; + + if (mx > xmin && mx < xmax && + my > ymin && my < ymax) { + + mx= mx1= 2*mx; + my= my1= 2*my; + if(dmin < Z_THRESHOLD && mx==0 && my==0){ + *mx_ptr = 0; + *my_ptr = 0; + return; } + + pen_x= pred_x + mx; + pen_y= pred_y + my; + + ptr-= s->linesize; + CHECK_HALF_MV4(xy2, -1, -1) + CHECK_HALF_MV4(y2 , 0, -1) + CHECK_HALF_MV4(xy2, +1, -1) + + ptr+= s->linesize; + CHECK_HALF_MV4(x2 , -1, 0) + CHECK_HALF_MV4(x2 , +1, 0) + CHECK_HALF_MV4(xy2, -1, +1) + CHECK_HALF_MV4(y2 , 0, +1) + CHECK_HALF_MV4(xy2, +1, +1) + + }else{ + mx*=2; + my*=2; } - *mx_ptr = mx - (xx << 1); - *my_ptr = my - (yy << 1); - //fprintf(stderr,"half - MX: %d\tMY: %d\n",*mx_ptr ,*my_ptr); + *mx_ptr = mx; + *my_ptr = my; +} + +static inline void set_mv_tables(MpegEncContext * s, int mx, int my) +{ + const int xy= s->mb_x + s->mb_y*s->mb_width; + + s->mv_table[0][xy] = mx; + s->mv_table[1][xy] = my; + + /* has allready been set to the 4 MV if 4MV is done */ + if(!(s->flags&CODEC_FLAG_4MV)){ + int mot_xy= s->block_index[0]; + + s->motion_val[mot_xy ][0]= mx; + s->motion_val[mot_xy ][1]= my; + s->motion_val[mot_xy+1][0]= mx; + s->motion_val[mot_xy+1][1]= my; + + mot_xy += s->block_wrap[0]; + s->motion_val[mot_xy ][0]= mx; + s->motion_val[mot_xy ][1]= my; + s->motion_val[mot_xy+1][0]= mx; + s->motion_val[mot_xy+1][1]= my; + } } #ifndef CONFIG_TEST_MV_ENCODE -int estimate_motion(MpegEncContext * s, - int mb_x, int mb_y, - int *mx_ptr, int *my_ptr) +void estimate_motion(MpegEncContext * s, + int mb_x, int mb_y) { UINT8 *pix, *ppix; int sum, varc, vard, mx, my, range, dmin, xx, yy; int xmin, ymin, xmax, ymax; + int rel_xmin, rel_ymin, rel_xmax, rel_ymax; + int pred_x=0, pred_y=0; + int P[6][2]; + const int shift= 1+s->quarter_sample; + int mb_type=0; range = 8 * (1 << (s->f_code - 1)); /* XXX: temporary kludge to avoid overflow for msmpeg4 */ @@ -411,6 +836,8 @@ int estimate_motion(MpegEncContext * s, if (s->unrestricted_mv) { xmin = -16; ymin = -16; + if (s->h263_plus) + range *= 2; if(s->avctx==NULL || s->avctx->codec->id!=CODEC_ID_MPEG4){ xmax = s->mb_width*16; ymax = s->mb_height*16; @@ -426,7 +853,6 @@ int estimate_motion(MpegEncContext * s, xmax = s->mb_width*16 - 16; ymax = s->mb_height*16 - 16; } - switch(s->full_search) { case ME_ZERO: default: @@ -442,8 +868,116 @@ int estimate_motion(MpegEncContext * s, case ME_PHODS: dmin = phods_motion_search(s, &mx, &my, range / 2, xmin, ymin, xmax, ymax); break; + case ME_X1: + case ME_EPZS: + { + const int mot_stride = s->block_wrap[0]; + const int mot_xy = s->block_index[0]; + + rel_xmin= xmin - mb_x*16; + rel_xmax= xmax - mb_x*16; + rel_ymin= ymin - mb_y*16; + rel_ymax= ymax - mb_y*16; + + P[0][0] = s->motion_val[mot_xy ][0]; + P[0][1] = s->motion_val[mot_xy ][1]; + P[1][0] = s->motion_val[mot_xy - 1][0]; + P[1][1] = s->motion_val[mot_xy - 1][1]; + if(P[1][0] > (rel_xmax<<shift)) P[1][0]= (rel_xmax<<shift); + + /* special case for first line */ + if ((mb_y == 0 || s->first_slice_line || s->first_gob_line)) { + P[4][0] = P[1][0]; + P[4][1] = P[1][1]; + } else { + P[2][0] = s->motion_val[mot_xy - mot_stride ][0]; + P[2][1] = s->motion_val[mot_xy - mot_stride ][1]; + P[3][0] = s->motion_val[mot_xy - mot_stride + 2 ][0]; + P[3][1] = s->motion_val[mot_xy - mot_stride + 2 ][1]; + if(P[2][1] > (rel_ymax<<shift)) P[2][1]= (rel_ymax<<shift); + if(P[3][0] < (rel_xmin<<shift)) P[3][0]= (rel_xmin<<shift); + if(P[3][1] > (rel_ymax<<shift)) P[3][1]= (rel_ymax<<shift); + + P[4][0]= mid_pred(P[1][0], P[2][0], P[3][0]); + P[4][1]= mid_pred(P[1][1], P[2][1], P[3][1]); + } + if(s->out_format == FMT_H263){ + pred_x = P[4][0]; + pred_y = P[4][1]; + }else { /* mpeg1 at least */ + pred_x= P[1][0]; + pred_y= P[1][1]; + } + } + dmin = epzs_motion_search(s, &mx, &my, P, pred_x, pred_y, rel_xmin, rel_ymin, rel_xmax, rel_ymax); + + mx+= mb_x*16; + my+= mb_y*16; + break; + } + + if(s->flags&CODEC_FLAG_4MV){ + int block; + + mb_type|= MB_TYPE_INTER4V; + + for(block=0; block<4; block++){ + int mx4, my4; + int pred_x4, pred_y4; + int dmin4; + static const int off[4]= {2, 1, 1, -1}; + const int mot_stride = s->block_wrap[0]; + const int mot_xy = s->block_index[block]; + const int block_x= mb_x*2 + (block&1); + const int block_y= mb_y*2 + (block>>1); + + const int rel_xmin4= xmin - block_x*8; + const int rel_xmax4= xmax - block_x*8 + 8; + const int rel_ymin4= ymin - block_y*8; + const int rel_ymax4= ymax - block_y*8 + 8; + + P[0][0] = s->motion_val[mot_xy ][0]; + P[0][1] = s->motion_val[mot_xy ][1]; + P[1][0] = s->motion_val[mot_xy - 1][0]; + P[1][1] = s->motion_val[mot_xy - 1][1]; + if(P[1][0] > (rel_xmax4<<shift)) P[1][0]= (rel_xmax4<<shift); + + /* special case for first line */ + if ((mb_y == 0 || s->first_slice_line || s->first_gob_line) && block<2) { + P[4][0] = P[1][0]; + P[4][1] = P[1][1]; + } else { + P[2][0] = s->motion_val[mot_xy - mot_stride ][0]; + P[2][1] = s->motion_val[mot_xy - mot_stride ][1]; + P[3][0] = s->motion_val[mot_xy - mot_stride + off[block]][0]; + P[3][1] = s->motion_val[mot_xy - mot_stride + off[block]][1]; + if(P[2][1] > (rel_ymax4<<shift)) P[2][1]= (rel_ymax4<<shift); + if(P[3][0] < (rel_xmin4<<shift)) P[3][0]= (rel_xmin4<<shift); + if(P[3][0] > (rel_xmax4<<shift)) P[3][0]= (rel_xmax4<<shift); + if(P[3][1] > (rel_ymax4<<shift)) P[3][1]= (rel_ymax4<<shift); + + P[4][0]= mid_pred(P[1][0], P[2][0], P[3][0]); + P[4][1]= mid_pred(P[1][1], P[2][1], P[3][1]); + } + if(s->out_format == FMT_H263){ + pred_x4 = P[4][0]; + pred_y4 = P[4][1]; + }else { /* mpeg1 at least */ + pred_x4= P[1][0]; + pred_y4= P[1][1]; + } + P[5][0]= mx - mb_x*16; + P[5][1]= my - mb_y*16; + + dmin4 = epzs_motion_search4(s, block, &mx4, &my4, P, pred_x4, pred_y4, rel_xmin4, rel_ymin4, rel_xmax4, rel_ymax4); + + halfpel_motion_search4(s, &mx4, &my4, dmin4, rel_xmin4, rel_ymin4, rel_xmax4, rel_ymax4, + pred_x4, pred_y4, block_x, block_y); + + s->motion_val[ s->block_index[block] ][0]= mx4; + s->motion_val[ s->block_index[block] ][1]= my4; + } } - emms_c(); /* intra / predictive decision */ xx = mb_x * 16; @@ -452,36 +986,53 @@ int estimate_motion(MpegEncContext * s, pix = s->new_picture[0] + (yy * s->linesize) + xx; /* At this point (mx,my) are full-pell and the absolute displacement */ ppix = s->last_picture[0] + (my * s->linesize) + mx; - + sum = pix_sum(pix, s->linesize); - varc = pix_norm1(pix, s->linesize); - vard = pix_norm(pix, ppix, s->linesize); +#if 0 + varc = pix_dev(pix, s->linesize, (sum+128)>>8) + INTER_BIAS; + vard = pix_abs16x16(pix, ppix, s->linesize); +#else + sum= (sum+8)>>4; + varc = ((pix_norm1(pix, s->linesize) - sum*sum + 128 + 500)>>8); + vard = (pix_norm(pix, ppix, s->linesize)+128)>>8; +#endif - vard = vard >> 8; - sum = sum >> 8; - varc = (varc >> 8) - (sum * sum); s->mb_var[s->mb_width * mb_y + mb_x] = varc; - s->avg_mb_var += varc; - + s->avg_mb_var+= varc; + s->mc_mb_var += vard; + #if 0 printf("varc=%4d avg_var=%4d (sum=%4d) vard=%4d mx=%2d my=%2d\n", varc, s->avg_mb_var, sum, vard, mx - xx, my - yy); #endif - if (vard <= 64 || vard < varc) { - if (s->full_search != ME_ZERO) { - halfpel_motion_search(s, &mx, &my, dmin, xmin, ymin, xmax, ymax); - } else { - mx -= 16 * s->mb_x; - my -= 16 * s->mb_y; + if(s->flags&CODEC_FLAG_HQ){ + if (vard*2 + 200 > varc) + mb_type|= MB_TYPE_INTRA; + if (varc*2 + 200 > vard){ + mb_type|= MB_TYPE_INTER; + halfpel_motion_search(s, &mx, &my, dmin, xmin, ymin, xmax, ymax, pred_x, pred_y); + }else{ + mx = mx*2 - mb_x*32; + my = my*2 - mb_y*32; + } + }else{ + if (vard <= 64 || vard < varc) { + mb_type|= MB_TYPE_INTER; + if (s->full_search != ME_ZERO) { + halfpel_motion_search(s, &mx, &my, dmin, xmin, ymin, xmax, ymax, pred_x, pred_y); + } else { + mx -= 16 * mb_x; + my -= 16 * mb_y; + } + }else{ + mb_type|= MB_TYPE_INTRA; + mx = 0;//mx*2 - 32 * mb_x; + my = 0;//my*2 - 32 * mb_y; } - *mx_ptr = mx; - *my_ptr = my; - return 0; - } else { - *mx_ptr = 0; - *my_ptr = 0; - return 1; } + + s->mb_type[mb_y*s->mb_width + mb_x]= mb_type; + set_mv_tables(s, mx, my); } #else |