📄 motion_est.c
字号:
const int size=0; const int h=8; int block; int P[10][2]; uint8_t * const mv_penalty= c->current_mv_penalty; int same=1; const int stride= 2*s->linesize; int dmin_sum= 0; const int mot_stride= s->mb_stride; const int xy= s->mb_x + s->mb_y*mot_stride; c->ymin>>=1; c->ymax>>=1; c->stride<<=1; c->uvstride<<=1; init_interlaced_ref(s, ref_index); for(block=0; block<2; block++){ int field_select; int best_dmin= INT_MAX; int best_field= -1; for(field_select=0; field_select<2; field_select++){ int dmin, mx_i, my_i; int16_t (*mv_table)[2]= mv_tables[block][field_select]; if(user_field_select){ assert(field_select==0 || field_select==1); assert(field_select_tables[block][xy]==0 || field_select_tables[block][xy]==1); if(field_select_tables[block][xy] != field_select) continue; } P_LEFT[0] = mv_table[xy - 1][0]; P_LEFT[1] = mv_table[xy - 1][1]; if(P_LEFT[0] > (c->xmax<<1)) P_LEFT[0] = (c->xmax<<1); c->pred_x= P_LEFT[0]; c->pred_y= P_LEFT[1]; if(!s->first_slice_line){ P_TOP[0] = mv_table[xy - mot_stride][0]; P_TOP[1] = mv_table[xy - mot_stride][1]; P_TOPRIGHT[0] = mv_table[xy - mot_stride + 1][0]; P_TOPRIGHT[1] = mv_table[xy - mot_stride + 1][1]; if(P_TOP[1] > (c->ymax<<1)) P_TOP[1] = (c->ymax<<1); if(P_TOPRIGHT[0] < (c->xmin<<1)) P_TOPRIGHT[0]= (c->xmin<<1); if(P_TOPRIGHT[0] > (c->xmax<<1)) P_TOPRIGHT[0]= (c->xmax<<1); if(P_TOPRIGHT[1] > (c->ymax<<1)) P_TOPRIGHT[1]= (c->ymax<<1); P_MEDIAN[0]= mid_pred(P_LEFT[0], P_TOP[0], P_TOPRIGHT[0]); P_MEDIAN[1]= mid_pred(P_LEFT[1], P_TOP[1], P_TOPRIGHT[1]); } P_MV1[0]= mx; //FIXME not correct if block != field_select P_MV1[1]= my / 2; dmin = epzs_motion_search2(s, &mx_i, &my_i, P, block, field_select+ref_index, mv_table, (1<<16)>>1); dmin= c->sub_motion_search(s, &mx_i, &my_i, dmin, block, field_select+ref_index, size, h); mv_table[xy][0]= mx_i; mv_table[xy][1]= my_i; if(s->dsp.me_sub_cmp[0] != s->dsp.mb_cmp[0]){ int dxy; //FIXME chroma ME uint8_t *ref= c->ref[field_select+ref_index][0] + (mx_i>>1) + (my_i>>1)*stride; dxy = ((my_i & 1) << 1) | (mx_i & 1); if(s->no_rounding){ s->dsp.put_no_rnd_pixels_tab[size][dxy](c->scratchpad, ref , stride, h); }else{ s->dsp.put_pixels_tab [size][dxy](c->scratchpad, ref , stride, h); } dmin= s->dsp.mb_cmp[size](s, c->src[block][0], c->scratchpad, stride, h); dmin+= (mv_penalty[mx_i-c->pred_x] + mv_penalty[my_i-c->pred_y] + 1)*c->mb_penalty_factor; }else dmin+= c->mb_penalty_factor; //field_select bits dmin += field_select != block; //slightly prefer same field if(dmin < best_dmin){ best_dmin= dmin; best_field= field_select; } } { int16_t (*mv_table)[2]= mv_tables[block][best_field]; if(mv_table[xy][0] != mx) same=0; //FIXME check if these checks work and are any good at all if(mv_table[xy][1]&1) same=0; if(mv_table[xy][1]*2 != my) same=0; if(best_field != block) same=0; } field_select_tables[block][xy]= best_field; dmin_sum += best_dmin; } c->ymin<<=1; c->ymax<<=1; c->stride>>=1; c->uvstride>>=1; if(same) return INT_MAX; switch(c->avctx->mb_cmp&0xFF){ /*case FF_CMP_SSE: return dmin_sum+ 32*s->qscale*s->qscale;*/ case FF_CMP_RD: return dmin_sum; default: return dmin_sum+ 11*c->mb_penalty_factor; }}static void clip_input_mv(MpegEncContext * s, int16_t *mv, int interlaced){ int ymax= s->me.ymax>>interlaced; int ymin= s->me.ymin>>interlaced; if(mv[0] < s->me.xmin) mv[0] = s->me.xmin; if(mv[0] > s->me.xmax) mv[0] = s->me.xmax; if(mv[1] < ymin) mv[1] = ymin; if(mv[1] > ymax) mv[1] = ymax;}static inline int check_input_motion(MpegEncContext * s, int mb_x, int mb_y, int p_type){ MotionEstContext * const c= &s->me; Picture *p= s->current_picture_ptr; int mb_xy= mb_x + mb_y*s->mb_stride; int xy= 2*mb_x + 2*mb_y*s->b8_stride; int mb_type= s->current_picture.mb_type[mb_xy]; int flags= c->flags; int shift= (flags&FLAG_QPEL) + 1; int mask= (1<<shift)-1; int x, y, i; int d=0; me_cmp_func cmpf= s->dsp.sse[0]; me_cmp_func chroma_cmpf= s->dsp.sse[1]; if(p_type && USES_LIST(mb_type, 1)){ av_log(c->avctx, AV_LOG_ERROR, "backward motion vector in P frame\n"); return INT_MAX/2; } assert(IS_INTRA(mb_type) || USES_LIST(mb_type,0) || USES_LIST(mb_type,1)); for(i=0; i<4; i++){ int xy= s->block_index[i]; clip_input_mv(s, p->motion_val[0][xy], !!IS_INTERLACED(mb_type)); clip_input_mv(s, p->motion_val[1][xy], !!IS_INTERLACED(mb_type)); } if(IS_INTERLACED(mb_type)){ int xy2= xy + s->b8_stride; s->mb_type[mb_xy]=CANDIDATE_MB_TYPE_INTRA; c->stride<<=1; c->uvstride<<=1; if(!(s->flags & CODEC_FLAG_INTERLACED_ME)){ av_log(c->avctx, AV_LOG_ERROR, "Interlaced macroblock selected but interlaced motion estimation disabled\n"); return INT_MAX/2; } if(USES_LIST(mb_type, 0)){ int field_select0= p->ref_index[0][xy ]; int field_select1= p->ref_index[0][xy2]; assert(field_select0==0 ||field_select0==1); assert(field_select1==0 ||field_select1==1); init_interlaced_ref(s, 0); if(p_type){ s->p_field_select_table[0][mb_xy]= field_select0; s->p_field_select_table[1][mb_xy]= field_select1; *(uint32_t*)s->p_field_mv_table[0][field_select0][mb_xy]= *(uint32_t*)p->motion_val[0][xy ]; *(uint32_t*)s->p_field_mv_table[1][field_select1][mb_xy]= *(uint32_t*)p->motion_val[0][xy2]; s->mb_type[mb_xy]=CANDIDATE_MB_TYPE_INTER_I; }else{ s->b_field_select_table[0][0][mb_xy]= field_select0; s->b_field_select_table[0][1][mb_xy]= field_select1; *(uint32_t*)s->b_field_mv_table[0][0][field_select0][mb_xy]= *(uint32_t*)p->motion_val[0][xy ]; *(uint32_t*)s->b_field_mv_table[0][1][field_select1][mb_xy]= *(uint32_t*)p->motion_val[0][xy2]; s->mb_type[mb_xy]= CANDIDATE_MB_TYPE_FORWARD_I; } x= p->motion_val[0][xy ][0]; y= p->motion_val[0][xy ][1]; d = cmp(s, x>>shift, y>>shift, x&mask, y&mask, 0, 8, field_select0, 0, cmpf, chroma_cmpf, flags); x= p->motion_val[0][xy2][0]; y= p->motion_val[0][xy2][1]; d+= cmp(s, x>>shift, y>>shift, x&mask, y&mask, 0, 8, field_select1, 1, cmpf, chroma_cmpf, flags); } if(USES_LIST(mb_type, 1)){ int field_select0= p->ref_index[1][xy ]; int field_select1= p->ref_index[1][xy2]; assert(field_select0==0 ||field_select0==1); assert(field_select1==0 ||field_select1==1); init_interlaced_ref(s, 2); s->b_field_select_table[1][0][mb_xy]= field_select0; s->b_field_select_table[1][1][mb_xy]= field_select1; *(uint32_t*)s->b_field_mv_table[1][0][field_select0][mb_xy]= *(uint32_t*)p->motion_val[1][xy ]; *(uint32_t*)s->b_field_mv_table[1][1][field_select1][mb_xy]= *(uint32_t*)p->motion_val[1][xy2]; if(USES_LIST(mb_type, 0)){ s->mb_type[mb_xy]= CANDIDATE_MB_TYPE_BIDIR_I; }else{ s->mb_type[mb_xy]= CANDIDATE_MB_TYPE_BACKWARD_I; } x= p->motion_val[1][xy ][0]; y= p->motion_val[1][xy ][1]; d = cmp(s, x>>shift, y>>shift, x&mask, y&mask, 0, 8, field_select0+2, 0, cmpf, chroma_cmpf, flags); x= p->motion_val[1][xy2][0]; y= p->motion_val[1][xy2][1]; d+= cmp(s, x>>shift, y>>shift, x&mask, y&mask, 0, 8, field_select1+2, 1, cmpf, chroma_cmpf, flags); //FIXME bidir scores } c->stride>>=1; c->uvstride>>=1; }else if(IS_8X8(mb_type)){ if(!(s->flags & CODEC_FLAG_4MV)){ av_log(c->avctx, AV_LOG_ERROR, "4MV macroblock selected but 4MV encoding disabled\n"); return INT_MAX/2; } cmpf= s->dsp.sse[1]; chroma_cmpf= s->dsp.sse[1]; init_mv4_ref(c); for(i=0; i<4; i++){ xy= s->block_index[i]; x= p->motion_val[0][xy][0]; y= p->motion_val[0][xy][1]; d+= cmp(s, x>>shift, y>>shift, x&mask, y&mask, 1, 8, i, i, cmpf, chroma_cmpf, flags); } s->mb_type[mb_xy]=CANDIDATE_MB_TYPE_INTER4V; }else{ if(USES_LIST(mb_type, 0)){ if(p_type){ *(uint32_t*)s->p_mv_table[mb_xy]= *(uint32_t*)p->motion_val[0][xy]; s->mb_type[mb_xy]=CANDIDATE_MB_TYPE_INTER; }else if(USES_LIST(mb_type, 1)){ *(uint32_t*)s->b_bidir_forw_mv_table[mb_xy]= *(uint32_t*)p->motion_val[0][xy]; *(uint32_t*)s->b_bidir_back_mv_table[mb_xy]= *(uint32_t*)p->motion_val[1][xy]; s->mb_type[mb_xy]=CANDIDATE_MB_TYPE_BIDIR; }else{ *(uint32_t*)s->b_forw_mv_table[mb_xy]= *(uint32_t*)p->motion_val[0][xy]; s->mb_type[mb_xy]=CANDIDATE_MB_TYPE_FORWARD; } x= p->motion_val[0][xy][0]; y= p->motion_val[0][xy][1]; d = cmp(s, x>>shift, y>>shift, x&mask, y&mask, 0, 16, 0, 0, cmpf, chroma_cmpf, flags); }else if(USES_LIST(mb_type, 1)){ *(uint32_t*)s->b_back_mv_table[mb_xy]= *(uint32_t*)p->motion_val[1][xy]; s->mb_type[mb_xy]=CANDIDATE_MB_TYPE_BACKWARD; x= p->motion_val[1][xy][0]; y= p->motion_val[1][xy][1]; d = cmp(s, x>>shift, y>>shift, x&mask, y&mask, 0, 16, 2, 0, cmpf, chroma_cmpf, flags); }else s->mb_type[mb_xy]=CANDIDATE_MB_TYPE_INTRA; } return d;}void ff_estimate_p_frame_motion(MpegEncContext * s, int mb_x, int mb_y){ MotionEstContext * const c= &s->me; uint8_t *pix, *ppix; int sum, mx, my, dmin; int varc; ///< the variance of the block (sum of squared (p[y][x]-average)) int vard; ///< sum of squared differences with the estimated motion vector int P[10][2]; const int shift= 1+s->quarter_sample; int mb_type=0; Picture * const pic= &s->current_picture; init_ref(c, s->new_picture.data, s->last_picture.data, NULL, 16*mb_x, 16*mb_y, 0); assert(s->quarter_sample==0 || s->quarter_sample==1); assert(s->linesize == c->stride); assert(s->uvlinesize == c->uvstride); c->penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_cmp); c->sub_penalty_factor= get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_sub_cmp); c->mb_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->mb_cmp); c->current_mv_penalty= c->mv_penalty[s->f_code] + MAX_MV; get_limits(s, 16*mb_x, 16*mb_y); c->skip=0; /* intra / predictive decision */ pix = c->src[0][0]; sum = s->dsp.pix_sum(pix, s->linesize); varc = s->dsp.pix_norm1(pix, s->linesize) - (((unsigned)(sum*sum))>>8) + 500; pic->mb_mean[s->mb_stride * mb_y + mb_x] = (sum+128)>>8; pic->mb_var [s->mb_stride * mb_y + mb_x] = (varc+128)>>8; c->mb_var_sum_temp += (varc+128)>>8; if(c->avctx->me_threshold){ vard= check_input_motion(s, mb_x, mb_y, 1); if((vard+128)>>8 < c->avctx->me_threshold){ int p_score= FFMIN(vard, varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*100); int i_score= varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*20; pic->mc_mb_var[s->mb_stride * mb_y + mb_x] = (vard+128)>>8; c->mc_mb_var_sum_temp += (vard+128)>>8; c->scene_change_score+= ff_sqrt(p_score) - ff_sqrt(i_score); return; } if((vard+128)>>8 < c->avctx->mb_threshold) mb_type= s->mb_type[mb_x + mb_y*s->mb_stride]; } switch(s->me_method) { case ME_ZERO: default: no_motion_search(s, &mx, &my); mx-= mb_x*16; my-= mb_y*16; dmin = 0; break; case ME_X1: case ME_EPZS: { const int mot_stride = s->b8_stride; const int mot_xy = s->block_index[0]; P_LEFT[0] = s->current_picture.motion_val[0][mot_xy - 1][0]; P_LEFT[1] = s->current_picture.motion_val[0][mot_xy - 1][1]; if(P_LEFT[0] > (c->xmax<<shift)) P_LEFT[0] = (c->xmax<<shift); if(!s->first_slice_line) { P_TOP[0] = s->current_picture.motion_val[0][mot_xy - mot_stride ][0]; P_TOP[1] = s->current_picture.motion_val[0][mot_xy - mot_stride ][1]; P_TOPRIGHT[0] = s->current_picture.motion_val[0][mot_xy - mot_stride + 2][0]; P_TOPRIGHT[1] = s->current_picture.motion_val[0][mot_xy - mot_stride + 2][1]; if(P_TOP[1] > (c->ymax<<shift)) P_TOP[1] = (c->ymax<<shift); if(P_TOPRIGHT[0] < (c->xmin<<shift)) P_TOPRIGHT[0]= (c->xmin<<shift); if(P_TOPRIGHT[1] > (c->ymax<<shift)) P_TOPRIGHT[1]= (c->ymax<<shift); P_MEDIAN[0]= mid_pred(P_LEFT[0], P_TOP[0], P_TOPRIGHT[0]); P_MEDIAN[1]= mid_pred(P_LEFT[1], P_TOP[1], P_TOPRIGHT[1]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -