📄 motion_est.c
字号:
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, uint32_t *map, uint16_t *score_map,int map_generation, op_pixels_abs_func pix_abs){ 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){ const int key= ((y)<<ME_MAP_MV_BITS) + (x) + map_generation; const int index= (((y)<<ME_MAP_SHIFT) + (x))&(ME_MAP_SIZE-1); if(map[index]!=key){ d = pix_abs(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride); d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant; map[index]=key; score_map[index]=d; }else d= dmin+1; }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>=SNAKE_1+1) return dmin; }else{ if(dir&1) dir-= c*3; else c= -c;// c= -c; } dir+=c*SNAKE_2; fails++; } dir&=7; }}static inline int cross_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, uint32_t *map, uint16_t *score_map,int map_generation, op_pixels_abs_func pix_abs){ static int x_dir[4]= {-1, 0, 1, 0}; static int y_dir[4]= { 0,-1, 0, 1}; int improvement[2]={100000, 100000}; int dirs[2]={2, 3}; int dir; int last_dir= -1; for(;;){ dir= dirs[ improvement[0] > improvement[1] ? 0 : 1 ]; if(improvement[dir&1]==-1) return dmin; { const int x= best[0] + x_dir[dir]; const int y= best[1] + y_dir[dir]; const int key= (y<<ME_MAP_MV_BITS) + x + map_generation; const int index= ((y<<ME_MAP_SHIFT) + x)&(ME_MAP_SIZE-1); int d; if(x>=xmin && x<=xmax && y>=ymin && y<=ymax){ if(map[index]!=key){ d = pix_abs(new_pic, old_pic + x + y*pic_stride, pic_stride); d += (mv_penalty[(x<<shift)-pred_x] + mv_penalty[(y<<shift)-pred_y])*quant; map[index]=key; score_map[index]=d; if(d<dmin){ improvement[dir&1]= dmin-d; improvement[(dir&1)^1]++; dmin=d; best[0]= x; best[1]= y; last_dir=dir; continue; } }else{ d= score_map[index]; } }else{ d= dmin + 1000; //FIXME is this a good idea? } /* evaluated point was cached or checked and worse */ if(last_dir==dir){ improvement[dir&1]= -1; }else{ improvement[dir&1]= d-dmin; last_dir= dirs[dir&1]= dir^2; } } }}static inline int update_map_generation(MpegEncContext * s){ s->me_map_generation+= 1<<(ME_MAP_MV_BITS*2); if(s->me_map_generation==0){ s->me_map_generation= 1<<(ME_MAP_MV_BITS*2); memset(s->me_map, 0, sizeof(uint32_t)*ME_MAP_SIZE); } return s->me_map_generation;}static int epzs_motion_search(MpegEncContext * s, int *mx_ptr, int *my_ptr, int P[10][2], int pred_x, int pred_y, int xmin, int ymin, int xmax, int ymax, uint8_t * ref_picture){ 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; uint32_t *map= s->me_map; uint16_t *score_map= s->me_score_map; int map_generation; new_pic = s->new_picture[0] + pic_xy; old_pic = ref_picture + pic_xy; map_generation= update_map_generation(s); dmin = s->dsp.pix_abs16x16(new_pic, old_pic, pic_stride); map[0]= map_generation; score_map[0]= dmin; /* first line */ if ((s->mb_y == 0 || s->first_slice_line)) { CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift) CHECK_MV(P_LAST[0]>>shift, P_LAST[1]>>shift) }else{ if(dmin<256 && ( P_LEFT[0] |P_LEFT[1] |P_TOP[0] |P_TOP[1] |P_TOPRIGHT[0]|P_TOPRIGHT[1])==0){ *mx_ptr= 0; *my_ptr= 0; s->skip_me=1; return dmin; } CHECK_MV(P_MEDIAN[0]>>shift, P_MEDIAN[1]>>shift) if(dmin>256*2){ CHECK_MV(P_LAST[0] >>shift, P_LAST[1] >>shift) CHECK_MV(P_LEFT[0] >>shift, P_LEFT[1] >>shift) CHECK_MV(P_TOP[0] >>shift, P_TOP[1] >>shift) CHECK_MV(P_TOPRIGHT[0]>>shift, P_TOPRIGHT[1]>>shift) } } if(dmin>256*4){ CHECK_MV(P_LAST_RIGHT[0] >>shift, P_LAST_RIGHT[1] >>shift) CHECK_MV(P_LAST_BOTTOM[0]>>shift, P_LAST_BOTTOM[1]>>shift) }#if 0 //doest only slow things down if(dmin>512*3){ int step; dmin= score_map[0]; best[0]= best[1]=0; for(step=128; step>0; step>>=1){ const int step2= step; int y; for(y=-step2+best[1]; y<=step2+best[1]; y+=step){ int x; if(y<ymin || y>ymax) continue; for(x=-step2+best[0]; x<=step2+best[0]; x+=step){ if(x<xmin || x>xmax) continue; if(x==best[0] && y==best[1]) continue; CHECK_MV(x,y) } } } }#endif//check(best[0],best[1],0, b0) if(s->me_method==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, map, score_map, map_generation, s->dsp.pix_abs16x16); else dmin= cross_search(s, best, dmin, new_pic, old_pic, pic_stride, pred_x, pred_y, mv_penalty, quant, xmin, ymin, xmax, ymax, shift, map, score_map, map_generation, s->dsp.pix_abs16x16);//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[10][2], int pred_x, int pred_y, int xmin, int ymin, int xmax, int ymax, uint8_t *ref_picture){ 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; uint32_t *map= s->me_map; uint16_t *score_map= s->me_score_map; int map_generation; new_pic = s->new_picture[0] + pic_xy; old_pic = ref_picture + pic_xy; map_generation= update_map_generation(s); dmin = 1000000;//printf("%d %d %d %d //",xmin, ymin, xmax, ymax); /* first line */ if ((s->mb_y == 0 || s->first_slice_line) && block<2) { CHECK_MV4(P_LEFT[0]>>shift, P_LEFT[1]>>shift) CHECK_MV4(P_LAST[0]>>shift, P_LAST[1]>>shift) CHECK_MV4(P_MV1[0]>>shift, P_MV1[1]>>shift) }else{ CHECK_MV4(P_MV1[0]>>shift, P_MV1[1]>>shift) //FIXME try some early stop if(dmin>64*2){ CHECK_MV4(P_MEDIAN[0]>>shift, P_MEDIAN[1]>>shift) CHECK_MV4(P_LEFT[0]>>shift, P_LEFT[1]>>shift) CHECK_MV4(P_TOP[0]>>shift, P_TOP[1]>>shift) CHECK_MV4(P_TOPRIGHT[0]>>shift, P_TOPRIGHT[1]>>shift) CHECK_MV4(P_LAST[0]>>shift, P_LAST[1]>>shift) } } if(dmin>64*4){ CHECK_MV4(P_LAST_RIGHT[0]>>shift, P_LAST_RIGHT[1]>>shift) CHECK_MV4(P_LAST_BOTTOM[0]>>shift, P_LAST_BOTTOM[1]>>shift) } if(s->me_method==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, map, score_map, map_generation, s->dsp.pix_abs8x8); else dmin= cross_search(s, best, dmin, new_pic, old_pic, pic_stride, pred_x, pred_y, mv_penalty, quant, xmin, ymin, xmax, ymax, shift, map, score_map, map_generation, s->dsp.pix_abs8x8); *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_abs_ ## suffix(pix, ptr+((x)>>1), s->linesize);\ d += (mv_penalty[pen_x + x] + mv_penalty[pen_y + y])*quant;\ COPY3_IF_LT(dminh, d, dx, x, dy, y)\} /* The idea would be to make half pel ME after Inter/Intra decision to save time. */static inline int halfpel_motion_search(MpegEncContext * s, int *mx_ptr, int *my_ptr, int dmin, int xmin, int ymin, int xmax, int ymax, int pred_x, int pred_y, uint8_t *ref_picture, op_pixels_abs_func pix_abs_x2, op_pixels_abs_func pix_abs_y2, op_pixels_abs_func pix_abs_xy2, int n){ UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame const int quant= s->qscale; int mx, my, xx, yy, dminh; UINT8 *pix, *ptr; if(s->skip_me){ *mx_ptr = 0; *my_ptr = 0; return dmin; } xx = 16 * s->mb_x + 8*(n&1); yy = 16 * s->mb_y + 8*(n>>1); pix = s->new_picture[0] + (yy * s->linesize) + xx; mx = *mx_ptr; my = *my_ptr; ptr = ref_picture + ((yy + my) * s->linesize) + (xx + mx); dminh = dmin; if (mx > xmin && mx < xmax && my > ymin && my < ymax) { int dx=0, dy=0; int d, pen_x, pen_y; mx<<=1; my<<=1; 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) mx+=dx; my+=dy; }else{ mx<<=1; my<<=1; } *mx_ptr = mx; *my_ptr = my; return dminh;}static inline int fast_halfpel_motion_search(MpegEncContext * s, int *mx_ptr, int *my_ptr, int dmin, int xmin, int ymin, int xmax, int ymax, int pred_x, int pred_y, uint8_t *ref_picture, op_pixels_abs_func pix_abs_x2, op_pixels_abs_func pix_abs_y2, op_pixels_abs_func pix_abs_xy2, int n){ UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame uint16_t *score_map= s->me_score_map; const int quant= s->qscale; int mx, my, xx, yy, dminh; UINT8 *pix, *ptr; if(s->skip_me){// printf("S"); *mx_ptr = 0; *my_ptr = 0; return dmin; }// printf("N"); xx = 16 * s->mb_x + 8*(n&1); yy = 16 * s->mb_y + 8*(n>>1); pix = s->new_picture[0] + (yy * s->linesize) + xx; mx = *mx_ptr; my = *my_ptr; ptr = ref_picture + ((yy + my) * s->linesize) + (xx + mx); dminh = dmin; if (mx > xmin && mx < xmax && my > ymin && my < ymax) { int dx=0, dy=0; int d, pen_x, pen_y; const int index= (my<<ME_MAP_SHIFT) + mx; const int t= score_map[(index-(1<<ME_MAP_SHIFT))&(ME_MAP_SIZE-1)]; const int l= score_map[(index- 1 )&(ME_MAP_SIZE-1)]; const int r= score_map[(index+ 1 )&(ME_MAP_SIZE-1)]; const int b= score_map[(index+(1<<ME_MAP_SHIFT))&(ME_MAP_SIZE-1)]; mx<<=1; my<<=1; pen_x= pred_x + mx; pen_y= pred_y + my; ptr-= s->linesize; if(t<=b){ CHECK_HALF_MV(y2 , 0, -1) if(l<=r){ CHECK_HALF_MV(xy2, -1, -1) if(t+r<=b+l){ CHECK_HALF_MV(xy2, +1, -1) ptr+= s->linesize; }else{ ptr+= s->linesize; CHECK_HALF_MV(xy2, -1, +1) } CHECK_HALF_MV(x2 , -1, 0) }else{ CHECK_HALF_MV(xy2, +1, -1) if(t+l<=b+r){ CHECK_HALF_MV(xy2, -1, -1) ptr+= s->linesize; }else{ ptr+= s->linesize; CHECK_HALF_MV(xy2, +1, +1) } CHECK_HALF_MV(x2 , +1, 0) }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -