X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fmotion_est.c;h=54bc93da38a5daf0b7ce2c42ffc44fb31799c6ca;hb=454064ad1eb39ffbea4906dbe2e246e18a5d5d67;hp=b645ffef0376142dffb7250b9097e09a4489ea42;hpb=316a2ec84ce19909e2732a1dc10be20bd38304c5;p=ffmpeg diff --git a/libavcodec/motion_est.c b/libavcodec/motion_est.c index b645ffef037..54bc93da38a 100644 --- a/libavcodec/motion_est.c +++ b/libavcodec/motion_est.c @@ -3,22 +3,23 @@ * Copyright (c) 2000,2001 Fabrice Bellard. * Copyright (c) 2002-2004 Michael Niedermayer * + * new motion estimation (X1/EPZS) by Michael Niedermayer * - * This library is free software; you can redistribute it and/or + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * - * This library is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * new Motion Estimation (X1/EPZS) by Michael Niedermayer + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** @@ -101,7 +102,10 @@ static int get_flags(MotionEstContext *c, int direct, int chroma){ + (chroma ? FLAG_CHROMA : 0); } -static always_inline int cmp(MpegEncContext *s, const int x, const int y, const int subx, const int suby, +/*! \brief compares a block (either a full macroblock or a partition thereof) + against a proposed motion-compensated prediction of that block + */ +static av_always_inline int cmp(MpegEncContext *s, const int x, const int y, const int subx, const int suby, const int size, const int h, int ref_index, int src_index, me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, const int flags){ MotionEstContext * const c= &s->me; @@ -117,6 +121,7 @@ static always_inline int cmp(MpegEncContext *s, const int x, const int y, const int d; //FIXME check chroma 4mv, (no crashes ...) if(flags&FLAG_DIRECT){ + assert(x >= c->xmin && hx <= c->xmax<<(qpel+1) && y >= c->ymin && hy <= c->ymax<<(qpel+1)); if(x >= c->xmin && hx <= c->xmax<<(qpel+1) && y >= c->ymin && hy <= c->ymax<<(qpel+1)){ const int time_pp= s->pp_time; const int time_pb= s->pb_time; @@ -228,8 +233,14 @@ static void zero_hpel(uint8_t *a, const uint8_t *b, int stride, int h){ void ff_init_me(MpegEncContext *s){ MotionEstContext * const c= &s->me; + int cache_size= FFMIN(ME_MAP_SIZE>>ME_MAP_SHIFT, 1<avctx->dia_size)&255, FFABS(s->avctx->pre_dia_size)&255); c->avctx= s->avctx; + if(cache_size < 2*dia_size && !c->stride){ + av_log(s->avctx, AV_LOG_INFO, "ME_MAP size may be a little small for the selected diamond size\n"); + } + ff_set_cmp(&s->dsp, s->dsp.me_pre_cmp, c->avctx->me_pre_cmp); ff_set_cmp(&s->dsp, s->dsp.me_cmp, c->avctx->me_cmp); ff_set_cmp(&s->dsp, s->dsp.me_sub_cmp, c->avctx->me_sub_cmp); @@ -267,7 +278,9 @@ void ff_init_me(MpegEncContext *s){ c->uvstride= 8*s->mb_width + 16; } - // 8x8 fullpel search would need a 4x4 chroma compare, which we dont have yet, and even if we had the motion estimation code doesnt expect it + /* 8x8 fullpel search would need a 4x4 chroma compare, which we do + * not have yet, and even if we had, the motion estimation code + * does not expect it. */ if(s->codec_id != CODEC_ID_SNOW){ if((c->avctx->me_cmp&FF_CMP_CHROMA)/* && !s->dsp.me_cmp[2]*/){ s->dsp.me_cmp[2]= zero_cmp; @@ -294,14 +307,14 @@ static int pix_dev(uint8_t * pix, int line_size, int mean) 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); + s += FFABS(pix[0]-mean); + s += FFABS(pix[1]-mean); + s += FFABS(pix[2]-mean); + s += FFABS(pix[3]-mean); + s += FFABS(pix[4]-mean); + s += FFABS(pix[5]-mean); + s += FFABS(pix[6]-mean); + s += FFABS(pix[7]-mean); pix += 8; } pix += line_size - 16; @@ -365,7 +378,7 @@ static int full_motion_search(MpegEncContext * s, #if 0 if (*mx_ptr < -(2 * range) || *mx_ptr >= (2 * range) || *my_ptr < -(2 * range) || *my_ptr >= (2 * range)) { - fprintf(stderr, "error %d %d\n", *mx_ptr, *my_ptr); + av_log(NULL, AV_LOG_ERROR, "error %d %d\n", *mx_ptr, *my_ptr); } #endif return dmin; @@ -687,6 +700,7 @@ static inline void set_p_mv_tables(MpegEncContext * s, int mx, int my, int mv4) static inline void get_limits(MpegEncContext *s, int x, int y) { MotionEstContext * const c= &s->me; + int range= c->avctx->me_range >> (1 + !!(c->flags&FLAG_QPEL)); /* if(c->avctx->me_range) c->range= c->avctx->me_range >> 1; else c->range= 16; @@ -708,6 +722,12 @@ static inline void get_limits(MpegEncContext *s, int x, int y) c->xmax = - x + s->mb_width *16 - 16; c->ymax = - y + s->mb_height*16 - 16; } + if(range){ + c->xmin = FFMAX(c->xmin,-range); + c->xmax = FFMIN(c->xmax, range); + c->ymin = FFMAX(c->ymin,-range); + c->ymax = FFMIN(c->ymax, range); + } } static inline void init_mv4_ref(MotionEstContext *c){ @@ -901,6 +921,8 @@ static int interlaced_search(MpegEncContext *s, int ref_index, 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; } @@ -1141,7 +1163,9 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, { MotionEstContext * const c= &s->me; uint8_t *pix, *ppix; - int sum, varc, vard, mx, my, dmin; + 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; @@ -1164,26 +1188,24 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, /* 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 + 128)>>8; + 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; - c->mb_var_sum_temp += varc; + 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)+128)>>8; - - if(vardavctx->me_threshold){ - pic->mc_mb_var[s->mb_stride * mb_y + mb_x] = vard; - c->mc_mb_var_sum_temp += vard; - if (vard <= 64 || vard < varc) { //FIXME - c->scene_change_score+= ff_sqrt(vard) - ff_sqrt(varc); - }else{ - c->scene_change_score+= s->qscale; - } + 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(vardavctx->mb_threshold) + if((vard+128)>>8 < c->avctx->mb_threshold) mb_type= s->mb_type[mb_x + mb_y*s->mb_stride]; } @@ -1256,21 +1278,20 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, /* At this point (mx,my) are full-pell and the relative displacement */ ppix = c->ref[0][0] + (my * s->linesize) + mx; - vard = (s->dsp.sse[0](NULL, pix, ppix, s->linesize, 16)+128)>>8; + vard = s->dsp.sse[0](NULL, pix, ppix, s->linesize, 16); - pic->mc_mb_var[s->mb_stride * mb_y + mb_x] = vard; + pic->mc_mb_var[s->mb_stride * mb_y + mb_x] = (vard+128)>>8; // pic->mb_cmp_score[s->mb_stride * mb_y + mb_x] = dmin; - c->mc_mb_var_sum_temp += vard; + c->mc_mb_var_sum_temp += (vard+128)>>8; #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(mb_type){ - if (vard <= 64 || vard < varc) - c->scene_change_score+= ff_sqrt(vard) - ff_sqrt(varc); - else - c->scene_change_score+= s->qscale; + int p_score= FFMIN(vard, varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*100); + int i_score= varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*20; + c->scene_change_score+= ff_sqrt(p_score) - ff_sqrt(i_score); if(mb_type == CANDIDATE_MB_TYPE_INTER){ c->sub_motion_search(s, &mx, &my, dmin, 0, 0, 0, 16); @@ -1288,14 +1309,14 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, interlaced_search(s, 0, s->p_field_mv_table, s->p_field_select_table, mx, my, 1); } }else if(c->avctx->mb_decision > FF_MB_DECISION_SIMPLE){ - if (vard <= 64 || vard < varc) - c->scene_change_score+= ff_sqrt(vard) - ff_sqrt(varc); - else - c->scene_change_score+= s->qscale; + int p_score= FFMIN(vard, varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*100); + int i_score= varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*20; + c->scene_change_score+= ff_sqrt(p_score) - ff_sqrt(i_score); - if (vard*2 + 200 > varc) + if (vard*2 + 200*256 > varc) mb_type|= CANDIDATE_MB_TYPE_INTRA; - if (varc*2 + 200 > vard){ + if (varc*2 + 200*256 > vard || s->qscale > 24){ +// if (varc*2 + 200*256 + 50*(s->lambda2>>FF_LAMBDA_SHIFT) > vard){ mb_type|= CANDIDATE_MB_TYPE_INTER; c->sub_motion_search(s, &mx, &my, dmin, 0, 0, 0, 16); if(s->flags&CODEC_FLAG_MV0) @@ -1306,7 +1327,7 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, my <<=shift; } if((s->flags&CODEC_FLAG_4MV) - && !c->skip && varc>50 && vard>10){ + && !c->skip && varc>50<<8 && vard>10<<8){ if(h263_mv4_search(s, mx, my, shift) < INT_MAX) mb_type|=CANDIDATE_MB_TYPE_INTER4V; @@ -1327,7 +1348,7 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, dmin= ff_get_mb_score(s, mx, my, 0, 0, 0, 16, 1); if((s->flags&CODEC_FLAG_4MV) - && !c->skip && varc>50 && vard>10){ + && !c->skip && varc>50<<8 && vard>10<<8){ int dmin4= h263_mv4_search(s, mx, my, shift); if(dmin4 < dmin){ mb_type= CANDIDATE_MB_TYPE_INTER4V; @@ -1348,7 +1369,7 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, /* get intra luma score */ if((c->avctx->mb_cmp&0xFF)==FF_CMP_SSE){ - intra_score= (varc<<8) - 500; //FIXME dont scale it down so we dont have to fix it + intra_score= varc - 500; }else{ int mean= (sum+128)>>8; mean*= 0x01010101; @@ -1394,10 +1415,10 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, }else s->current_picture.mb_type[mb_y*s->mb_stride + mb_x]= 0; - if (vard <= 64 || vard < varc) { //FIXME - c->scene_change_score+= ff_sqrt(vard) - ff_sqrt(varc); - }else{ - c->scene_change_score+= s->qscale; + { + int p_score= FFMIN(vard, varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*100); + int i_score= varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*20; + c->scene_change_score+= ff_sqrt(p_score) - ff_sqrt(i_score); } } @@ -1636,6 +1657,12 @@ static inline int bidir_refine(MpegEncContext * s, int mb_x, int mb_y) const int ymin= c->ymin<xmax<ymax<avctx->bidir_refine){ int score, end; #define CHECK_BIDIR(fx,fy,bx,by)\ - score= check_bidir_mv(s, motion_fx+fx, motion_fy+fy, motion_bx+bx, motion_by+by, pred_fx, pred_fy, pred_bx, pred_by, 0, 16);\ - if(score < fbmin){\ - fbmin= score;\ - motion_fx+=fx;\ - motion_fy+=fy;\ - motion_bx+=bx;\ - motion_by+=by;\ - end=0;\ + if( !BIDIR_MAP(fx,fy,bx,by)\ + &&(fx<=0 || motion_fx+fx<=xmax) && (fy<=0 || motion_fy+fy<=ymax) && (bx<=0 || motion_bx+bx<=xmax) && (by<=0 || motion_by+by<=ymax)\ + &&(fx>=0 || motion_fx+fx>=xmin) && (fy>=0 || motion_fy+fy>=ymin) && (bx>=0 || motion_bx+bx>=xmin) && (by>=0 || motion_by+by>=ymin)){\ + BIDIR_MAP(fx,fy,bx,by) = 1;\ + score= check_bidir_mv(s, motion_fx+fx, motion_fy+fy, motion_bx+bx, motion_by+by, pred_fx, pred_fy, pred_bx, pred_by, 0, 16);\ + if(score < fbmin){\ + fbmin= score;\ + motion_fx+=fx;\ + motion_fy+=fy;\ + motion_bx+=bx;\ + motion_by+=by;\ + end=0;\ + }\ } #define CHECK_BIDIR2(a,b,c,d)\ CHECK_BIDIR(a,b,c,d)\ -CHECK_BIDIR(-a,-b,-c,-d) +CHECK_BIDIR(-(a),-(b),-(c),-(d)) #define CHECK_BIDIRR(a,b,c,d)\ CHECK_BIDIR2(a,b,c,d)\ @@ -1668,10 +1700,6 @@ CHECK_BIDIR2(d,a,b,c) do{ end=1; - if( motion_fx >= xmax || motion_bx >= xmax || motion_fx <= xmin || motion_bx <= xmin - || motion_fy >= ymax || motion_by >= ymax || motion_fy <= ymin || motion_by <= ymin) - break; - CHECK_BIDIRR( 0, 0, 0, 1) if(s->avctx->bidir_refine > 1){ CHECK_BIDIRR( 0, 0, 1, 1) @@ -1697,6 +1725,11 @@ CHECK_BIDIR2(d,a,b,c) }while(!end); } + s->b_bidir_forw_mv_table[xy][0]= motion_fx; + s->b_bidir_forw_mv_table[xy][1]= motion_fy; + s->b_bidir_back_mv_table[xy][0]= motion_bx; + s->b_bidir_back_mv_table[xy][1]= motion_by; + return fbmin; } @@ -1769,15 +1802,15 @@ static inline int direct_search(MpegEncContext * s, int mb_x, int mb_y) c->pred_x=0; c->pred_y=0; - P_LEFT[0] = clip(mv_table[mot_xy - 1][0], xmin<first_slice_line) { //FIXME maybe allow this over thread boundary as its cliped - P_TOP[0] = clip(mv_table[mot_xy - mot_stride ][0], xmin<first_slice_line) { //FIXME maybe allow this over thread boundary as it is clipped + P_TOP[0] = av_clip(mv_table[mot_xy - mot_stride ][0], xmin<?min/max, maybe not needed - s->b_direct_mv_table[mot_xy][0]= mx; - s->b_direct_mv_table[mot_xy][1]= my; + mv_table[mot_xy][0]= mx; + mv_table[mot_xy][1]= my; c->flags &= ~FLAG_DIRECT; c->sub_flags &= ~FLAG_DIRECT; @@ -1815,27 +1848,39 @@ void ff_estimate_b_frame_motion(MpegEncContext * s, get_limits(s, 16*mb_x, 16*mb_y); c->skip=0; + + if(s->codec_id == CODEC_ID_MPEG4 && s->next_picture.mbskip_table[xy]){ + int score= direct_search(s, mb_x, mb_y); //FIXME just check 0,0 + + score= ((unsigned)(score*score + 128*256))>>16; + c->mc_mb_var_sum_temp += score; + s->current_picture.mc_mb_var[mb_y*s->mb_stride + mb_x] = score; //FIXME use SSE + s->mb_type[mb_y*s->mb_stride + mb_x]= CANDIDATE_MB_TYPE_DIRECT0; + + return; + } + if(c->avctx->me_threshold){ - int vard= (check_input_motion(s, mb_x, mb_y, 0)+128)>>8; + int vard= check_input_motion(s, mb_x, mb_y, 0); - if(vardavctx->me_threshold){ + if((vard+128)>>8 < c->avctx->me_threshold){ // 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 + 128)>>8; +// varc = s->dsp.pix_norm1(pix, s->linesize) - (((unsigned)(sum*sum))>>8) + 500; -// pic->mb_var [s->mb_stride * mb_y + mb_x] = varc; - s->current_picture.mc_mb_var[s->mb_stride * mb_y + mb_x] = vard; +// pic->mb_var [s->mb_stride * mb_y + mb_x] = (varc+128)>>8; + s->current_picture.mc_mb_var[s->mb_stride * mb_y + mb_x] = (vard+128)>>8; /* pic->mb_mean [s->mb_stride * mb_y + mb_x] = (sum+128)>>8; - c->mb_var_sum_temp += varc;*/ - c->mc_mb_var_sum_temp += vard; -/* if (vard <= 64 || vard < varc) { + c->mb_var_sum_temp += (varc+128)>>8;*/ + c->mc_mb_var_sum_temp += (vard+128)>>8; +/* if (vard <= 64<<8 || vard < varc) { c->scene_change_score+= ff_sqrt(vard) - ff_sqrt(varc); }else{ - c->scene_change_score+= s->qscale; + c->scene_change_score+= s->qscale * s->avctx->scenechange_factor; }*/ return; } - if(vardavctx->mb_threshold){ + if((vard+128)>>8 < c->avctx->mb_threshold){ type= s->mb_type[mb_y*s->mb_stride + mb_x]; if(type == CANDIDATE_MB_TYPE_DIRECT){ direct_search(s, mb_x, mb_y); @@ -1936,7 +1981,9 @@ void ff_estimate_b_frame_motion(MpegEncContext * s, type |= CANDIDATE_MB_TYPE_BIDIR_I; } //FIXME something smarter - if(dmin>256*256*16) type&= ~CANDIDATE_MB_TYPE_DIRECT; //dont try direct mode if its invalid for this MB + if(dmin>256*256*16) type&= ~CANDIDATE_MB_TYPE_DIRECT; //do not try direct mode if it is invalid for this MB + if(s->codec_id == CODEC_ID_MPEG4 && type&CANDIDATE_MB_TYPE_DIRECT && s->flags&CODEC_FLAG_MV0 && *(uint32_t*)s->b_direct_mv_table[xy]) + type |= CANDIDATE_MB_TYPE_DIRECT0; #if 0 if(s->out_format == FMT_MPEG1) type |= CANDIDATE_MB_TYPE_INTRA; @@ -1979,7 +2026,7 @@ int ff_get_best_fcode(MpegEncContext * s, int16_t (*mv_table)[2], int type) continue; for(j=0; jpict_type==B_TYPE || s->current_picture.mc_mb_var[xy] < s->current_picture.mb_var[xy]) + if(s->pict_type==FF_B_TYPE || s->current_picture.mc_mb_var[xy] < s->current_picture.mb_var[xy]) score[j]-= 170; } } @@ -2011,7 +2058,7 @@ void ff_fix_long_p_mvs(MpegEncContext * s) MotionEstContext * const c= &s->me; const int f_code= s->f_code; int y, range; - assert(s->pict_type==P_TYPE); + assert(s->pict_type==FF_P_TYPE); range = (((s->out_format == FMT_MPEG1 || s->msmpeg4_version) ? 8 : 16) << f_code);