📄 motion_est.c
字号:
/* * Motion estimation * Copyright (c) 2000,2001 Fabrice Bellard. * Copyright (c) 2002-2004 Michael Niedermayer * * * This library 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. * * This library 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 <michaelni@gmx.at> */ /** * @file motion_est.c * Motion estimation. */ #include <stdlib.h>#include <stdio.h>#include <limits.h>#include "avcodec.h"#include "dsputil.h"#include "mpegvideo.h"#undef NDEBUG#include <assert.h>#define SQ(a) ((a)*(a))#define P_LEFT P[1]#define P_TOP P[2]#define P_TOPRIGHT P[3]#define P_MEDIAN P[4]#define P_MV1 P[9]static inline int sad_hpel_motion_search(MpegEncContext * s, int *mx_ptr, int *my_ptr, int dmin, int src_index, int ref_index, int size, int h);static inline int update_map_generation(MotionEstContext *c){ c->map_generation+= 1<<(ME_MAP_MV_BITS*2); if(c->map_generation==0){ c->map_generation= 1<<(ME_MAP_MV_BITS*2); memset(c->map, 0, sizeof(uint32_t)*ME_MAP_SIZE); } return c->map_generation;}/* shape adaptive search stuff */typedef struct Minima{ int height; int x, y; int checked;}Minima;static int minima_cmp(const void *a, const void *b){ const Minima *da = (const Minima *) a; const Minima *db = (const Minima *) b; return da->height - db->height;}#define FLAG_QPEL 1 //must be 1#define FLAG_CHROMA 2#define FLAG_DIRECT 4static inline void init_ref(MotionEstContext *c, uint8_t *src[3], uint8_t *ref[3], uint8_t *ref2[3], int x, int y, int ref_index){ const int offset[3]= { y*c-> stride + x, ((y*c->uvstride + x)>>1), ((y*c->uvstride + x)>>1), }; int i; for(i=0; i<3; i++){ c->src[0][i]= src [i] + offset[i]; c->ref[0][i]= ref [i] + offset[i]; } if(ref_index){ for(i=0; i<3; i++){ c->ref[ref_index][i]= ref2[i] + offset[i]; } }}static int get_flags(MotionEstContext *c, int direct, int chroma){ return ((c->avctx->flags&CODEC_FLAG_QPEL) ? FLAG_QPEL : 0) + (direct ? FLAG_DIRECT : 0) + (chroma ? FLAG_CHROMA : 0);}static 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; const int stride= c->stride; const int uvstride= c->uvstride; const int qpel= flags&FLAG_QPEL; const int chroma= flags&FLAG_CHROMA; const int dxy= subx + (suby<<(1+qpel)); //FIXME log2_subpel? const int hx= subx + (x<<(1+qpel)); const int hy= suby + (y<<(1+qpel)); uint8_t * const * const ref= c->ref[ref_index]; uint8_t * const * const src= c->src[src_index]; int d; //FIXME check chroma 4mv, (no crashes ...) if(flags&FLAG_DIRECT){ 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; const int mask= 2*qpel+1; if(s->mv_type==MV_TYPE_8X8){ int i; for(i=0; i<4; i++){ int fx = c->direct_basis_mv[i][0] + hx; int fy = c->direct_basis_mv[i][1] + hy; int bx = hx ? fx - c->co_located_mv[i][0] : c->co_located_mv[i][0]*(time_pb - time_pp)/time_pp + ((i &1)<<(qpel+4)); int by = hy ? fy - c->co_located_mv[i][1] : c->co_located_mv[i][1]*(time_pb - time_pp)/time_pp + ((i>>1)<<(qpel+4)); int fxy= (fx&mask) + ((fy&mask)<<(qpel+1)); int bxy= (bx&mask) + ((by&mask)<<(qpel+1)); uint8_t *dst= c->temp + 8*(i&1) + 8*stride*(i>>1); if(qpel){ c->qpel_put[1][fxy](dst, ref[0] + (fx>>2) + (fy>>2)*stride, stride); c->qpel_avg[1][bxy](dst, ref[8] + (bx>>2) + (by>>2)*stride, stride); }else{ c->hpel_put[1][fxy](dst, ref[0] + (fx>>1) + (fy>>1)*stride, stride, 8); c->hpel_avg[1][bxy](dst, ref[8] + (bx>>1) + (by>>1)*stride, stride, 8); } } }else{ int fx = c->direct_basis_mv[0][0] + hx; int fy = c->direct_basis_mv[0][1] + hy; int bx = hx ? fx - c->co_located_mv[0][0] : (c->co_located_mv[0][0]*(time_pb - time_pp)/time_pp); int by = hy ? fy - c->co_located_mv[0][1] : (c->co_located_mv[0][1]*(time_pb - time_pp)/time_pp); int fxy= (fx&mask) + ((fy&mask)<<(qpel+1)); int bxy= (bx&mask) + ((by&mask)<<(qpel+1)); if(qpel){ c->qpel_put[1][fxy](c->temp , ref[0] + (fx>>2) + (fy>>2)*stride , stride); c->qpel_put[1][fxy](c->temp + 8 , ref[0] + (fx>>2) + (fy>>2)*stride + 8 , stride); c->qpel_put[1][fxy](c->temp + 8*stride, ref[0] + (fx>>2) + (fy>>2)*stride + 8*stride, stride); c->qpel_put[1][fxy](c->temp + 8 + 8*stride, ref[0] + (fx>>2) + (fy>>2)*stride + 8 + 8*stride, stride); c->qpel_avg[1][bxy](c->temp , ref[8] + (bx>>2) + (by>>2)*stride , stride); c->qpel_avg[1][bxy](c->temp + 8 , ref[8] + (bx>>2) + (by>>2)*stride + 8 , stride); c->qpel_avg[1][bxy](c->temp + 8*stride, ref[8] + (bx>>2) + (by>>2)*stride + 8*stride, stride); c->qpel_avg[1][bxy](c->temp + 8 + 8*stride, ref[8] + (bx>>2) + (by>>2)*stride + 8 + 8*stride, stride); }else{ assert((fx>>1) + 16*s->mb_x >= -16); assert((fy>>1) + 16*s->mb_y >= -16); assert((fx>>1) + 16*s->mb_x <= s->width); assert((fy>>1) + 16*s->mb_y <= s->height); assert((bx>>1) + 16*s->mb_x >= -16); assert((by>>1) + 16*s->mb_y >= -16); assert((bx>>1) + 16*s->mb_x <= s->width); assert((by>>1) + 16*s->mb_y <= s->height); c->hpel_put[0][fxy](c->temp, ref[0] + (fx>>1) + (fy>>1)*stride, stride, 16); c->hpel_avg[0][bxy](c->temp, ref[8] + (bx>>1) + (by>>1)*stride, stride, 16); } } d = cmp_func(s, c->temp, src[0], stride, 16); }else d= 256*256*256*32; }else{ int uvdxy; /* no, it might not be used uninitialized */ if(dxy){ if(qpel){ c->qpel_put[size][dxy](c->temp, ref[0] + x + y*stride, stride); //FIXME prototype (add h) if(chroma){ int cx= hx/2; int cy= hy/2; cx= (cx>>1)|(cx&1); cy= (cy>>1)|(cy&1); uvdxy= (cx&1) + 2*(cy&1); //FIXME x/y wrong, but mpeg4 qpel is sick anyway, we should drop as much of it as possible in favor for h264 } }else{ c->hpel_put[size][dxy](c->temp, ref[0] + x + y*stride, stride, h); if(chroma) uvdxy= dxy | (x&1) | (2*(y&1)); } d = cmp_func(s, c->temp, src[0], stride, h); }else{ d = cmp_func(s, src[0], ref[0] + x + y*stride, stride, h); if(chroma) uvdxy= (x&1) + 2*(y&1); } if(chroma){ uint8_t * const uvtemp= c->temp + 16*stride; c->hpel_put[size+1][uvdxy](uvtemp , ref[1] + (x>>1) + (y>>1)*uvstride, uvstride, h>>1); c->hpel_put[size+1][uvdxy](uvtemp+8, ref[2] + (x>>1) + (y>>1)*uvstride, uvstride, h>>1); d += chroma_cmp_func(s, uvtemp , src[1], uvstride, h>>1); d += chroma_cmp_func(s, uvtemp+8, src[2], uvstride, h>>1); } }#if 0 if(full_pel){ const int index= (((y)<<ME_MAP_SHIFT) + (x))&(ME_MAP_SIZE-1); score_map[index]= d; } d += (c->mv_penalty[hx - c->pred_x] + c->mv_penalty[hy - c->pred_y])*c->penalty_factor;#endif return d;}#include "motion_est_template.c"static int zero_cmp(void *s, uint8_t *a, uint8_t *b, int stride, int h){ return 0;}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; c->avctx= s->avctx; 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); ff_set_cmp(&s->dsp, s->dsp.mb_cmp, c->avctx->mb_cmp); c->flags = get_flags(c, 0, c->avctx->me_cmp &FF_CMP_CHROMA); c->sub_flags= get_flags(c, 0, c->avctx->me_sub_cmp&FF_CMP_CHROMA); c->mb_flags = get_flags(c, 0, c->avctx->mb_cmp &FF_CMP_CHROMA);/*FIXME s->no_rounding b_type*/ if(s->flags&CODEC_FLAG_QPEL){ c->sub_motion_search= qpel_motion_search; c->qpel_avg= s->dsp.avg_qpel_pixels_tab; if(s->no_rounding) c->qpel_put= s->dsp.put_no_rnd_qpel_pixels_tab; else c->qpel_put= s->dsp.put_qpel_pixels_tab; }else{ if(c->avctx->me_sub_cmp&FF_CMP_CHROMA) c->sub_motion_search= hpel_motion_search; else if( c->avctx->me_sub_cmp == FF_CMP_SAD && c->avctx-> me_cmp == FF_CMP_SAD && c->avctx-> mb_cmp == FF_CMP_SAD) c->sub_motion_search= sad_hpel_motion_search; // 2050 vs. 2450 cycles else c->sub_motion_search= hpel_motion_search; } c->hpel_avg= s->dsp.avg_pixels_tab; if(s->no_rounding) c->hpel_put= s->dsp.put_no_rnd_pixels_tab; else c->hpel_put= s->dsp.put_pixels_tab; if(s->linesize){ c->stride = s->linesize; c->uvstride= s->uvlinesize; }else{ c->stride = 16*s->mb_width + 32; 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 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; } if((c->avctx->me_sub_cmp&FF_CMP_CHROMA) && !s->dsp.me_sub_cmp[2]){ s->dsp.me_sub_cmp[2]= zero_cmp; } c->hpel_put[2][0]= c->hpel_put[2][1]= c->hpel_put[2][2]= c->hpel_put[2][3]= zero_hpel; } if(s->codec_id == CODEC_ID_H261){ c->sub_motion_search= no_sub_motion_search; } c->temp= c->scratchpad;} #if 0static int pix_dev(uint8_t * 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;}#endifstatic inline void no_motion_search(MpegEncContext * s, int *mx_ptr, int *my_ptr){ *mx_ptr = 16 * s->mb_x; *my_ptr = 16 * s->mb_y;}#if 0 /* the use of these functions is inside #if 0 */static int full_motion_search(MpegEncContext * s, int *mx_ptr, int *my_ptr, int range, int xmin, int ymin, int xmax, int ymax, uint8_t *ref_picture){ int x1, y1, x2, y2, xx, yy, x, y; int mx, my, dmin, d; uint8_t *pix; xx = 16 * s->mb_x; yy = 16 * s->mb_y; x1 = xx - range + 1; /* we loose one pixel to avoid boundary pb with half pixel pred */ if (x1 < xmin) x1 = xmin; x2 = xx + range - 1; if (x2 > xmax) x2 = xmax; y1 = yy - range + 1; if (y1 < ymin) y1 = ymin; y2 = yy + range - 1; if (y2 > ymax) y2 = ymax; pix = s->new_picture.data[0] + (yy * s->linesize) + xx; dmin = 0x7fffffff; mx = 0; my = 0; for (y = y1; y <= y2; y++) { for (x = x1; x <= x2; x++) { d = s->dsp.pix_abs[0][0](NULL, pix, ref_picture + (y * s->linesize) + x, s->linesize, 16); if (d < dmin || (d == dmin && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) { dmin = d; mx = x; my = y; } } } *mx_ptr = mx; *my_ptr = my;#if 0 if (*mx_ptr < -(2 * range) || *mx_ptr >= (2 * range) ||
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -