📄 motion_est.c
字号:
c->xmax = - x + s->mb_width *16;
c->ymax = - y + s->mb_height*16;
} else if (s->out_format == FMT_H261){
// Search range of H261 is different from other codec standards
c->xmin = (x > 15) ? - 15 : 0;
c->ymin = (y > 15) ? - 15 : 0;
c->xmax = (x < s->mb_width * 16 - 16) ? 15 : 0;
c->ymax = (y < s->mb_height * 16 - 16) ? 15 : 0;
} else {
c->xmin = - x;
c->ymin = - 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){
const int stride= c->stride;
c->ref[1][0] = c->ref[0][0] + 8;
c->ref[2][0] = c->ref[0][0] + 8*stride;
c->ref[3][0] = c->ref[2][0] + 8;
c->src[1][0] = c->src[0][0] + 8;
c->src[2][0] = c->src[0][0] + 8*stride;
c->src[3][0] = c->src[2][0] + 8;
}
static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift)
{
MotionEstContext * const c= &s->me;
const int size= 1;
const int h=8;
int block;
int P[10][2];
int dmin_sum=0, mx4_sum=0, my4_sum=0;
int same=1;
const int stride= c->stride;
uint8_t *mv_penalty= c->current_mv_penalty;
init_mv4_ref(c);
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->b8_stride;
const int mot_xy = s->block_index[block];
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);
/* special case for first line */
if (s->first_slice_line && block<2) {
c->pred_x= pred_x4= P_LEFT[0];
c->pred_y= pred_y4= P_LEFT[1];
} else {
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 + off[block]][0];
P_TOPRIGHT[1] = s->current_picture.motion_val[0][mot_xy - mot_stride + off[block]][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[0] > (c->xmax<<shift)) P_TOPRIGHT[0]= (c->xmax<<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]);
c->pred_x= pred_x4 = P_MEDIAN[0];
c->pred_y= pred_y4 = P_MEDIAN[1];
}
P_MV1[0]= mx;
P_MV1[1]= my;
dmin4 = epzs_motion_search4(s, &mx4, &my4, P, block, block, s->p_mv_table, (1<<16)>>shift);
dmin4= c->sub_motion_search(s, &mx4, &my4, dmin4, block, block, size, h);
if(s->dsp.me_sub_cmp[0] != s->dsp.mb_cmp[0]){
int dxy;
const int offset= ((block&1) + (block>>1)*stride)*8;
uint8_t *dest_y = c->scratchpad + offset;
if(s->quarter_sample){
uint8_t *ref= c->ref[block][0] + (mx4>>2) + (my4>>2)*stride;
dxy = ((my4 & 3) << 2) | (mx4 & 3);
if(s->no_rounding)
s->dsp.put_no_rnd_qpel_pixels_tab[1][dxy](dest_y , ref , stride);
else
s->dsp.put_qpel_pixels_tab [1][dxy](dest_y , ref , stride);
}else{
uint8_t *ref= c->ref[block][0] + (mx4>>1) + (my4>>1)*stride;
dxy = ((my4 & 1) << 1) | (mx4 & 1);
if(s->no_rounding)
s->dsp.put_no_rnd_pixels_tab[1][dxy](dest_y , ref , stride, h);
else
s->dsp.put_pixels_tab [1][dxy](dest_y , ref , stride, h);
}
dmin_sum+= (mv_penalty[mx4-pred_x4] + mv_penalty[my4-pred_y4])*c->mb_penalty_factor;
}else
dmin_sum+= dmin4;
if(s->quarter_sample){
mx4_sum+= mx4/2;
my4_sum+= my4/2;
}else{
mx4_sum+= mx4;
my4_sum+= my4;
}
s->current_picture.motion_val[0][ s->block_index[block] ][0]= mx4;
s->current_picture.motion_val[0][ s->block_index[block] ][1]= my4;
if(mx4 != mx || my4 != my) same=0;
}
if(same)
return INT_MAX;
if(s->dsp.me_sub_cmp[0] != s->dsp.mb_cmp[0]){
dmin_sum += s->dsp.mb_cmp[0](s, s->new_picture.data[0] + s->mb_x*16 + s->mb_y*16*stride, c->scratchpad, stride, 16);
}
if(c->avctx->mb_cmp&FF_CMP_CHROMA){
int dxy;
int mx, my;
int offset;
mx= ff_h263_round_chroma(mx4_sum);
my= ff_h263_round_chroma(my4_sum);
dxy = ((my & 1) << 1) | (mx & 1);
offset= (s->mb_x*8 + (mx>>1)) + (s->mb_y*8 + (my>>1))*s->uvlinesize;
if(s->no_rounding){
s->dsp.put_no_rnd_pixels_tab[1][dxy](c->scratchpad , s->last_picture.data[1] + offset, s->uvlinesize, 8);
s->dsp.put_no_rnd_pixels_tab[1][dxy](c->scratchpad+8 , s->last_picture.data[2] + offset, s->uvlinesize, 8);
}else{
s->dsp.put_pixels_tab [1][dxy](c->scratchpad , s->last_picture.data[1] + offset, s->uvlinesize, 8);
s->dsp.put_pixels_tab [1][dxy](c->scratchpad+8 , s->last_picture.data[2] + offset, s->uvlinesize, 8);
}
dmin_sum += s->dsp.mb_cmp[1](s, s->new_picture.data[1] + s->mb_x*8 + s->mb_y*8*s->uvlinesize, c->scratchpad , s->uvlinesize, 8);
dmin_sum += s->dsp.mb_cmp[1](s, s->new_picture.data[2] + s->mb_x*8 + s->mb_y*8*s->uvlinesize, c->scratchpad+8, s->uvlinesize, 8);
}
c->pred_x= mx;
c->pred_y= my;
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 inline void init_interlaced_ref(MpegEncContext *s, int ref_index){
MotionEstContext * const c= &s->me;
c->ref[1+ref_index][0] = c->ref[0+ref_index][0] + s->linesize;
c->src[1][0] = c->src[0][0] + s->linesize;
if(c->flags & FLAG_CHROMA){
c->ref[1+ref_index][1] = c->ref[0+ref_index][1] + s->uvlinesize;
c->ref[1+ref_index][2] = c->ref[0+ref_index][2] + s->uvlinesize;
c->src[1][1] = c->src[0][1] + s->uvlinesize;
c->src[1][2] = c->src[0][2] + s->uvlinesize;
}
}
static int interlaced_search(MpegEncContext *s, int ref_index,
int16_t (*mv_tables[2][2])[2], uint8_t *field_select_tables[2], int mx, int my, int user_field_select)
{
MotionEstContext * const c= &s->me;
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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -