📄 motion_est.c
字号:
/* * Motion estimation * Copyright (c) 2000,2001 Fabrice Bellard. * Copyright (c) 2002-2003 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 xmin, int ymin, int xmax, int ymax, int pred_x, int pred_y, Picture *picture, int n, int size, uint8_t * const mv_penalty);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;}/* 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;} /* SIMPLE */#define RENAME(a) simple_ ## a#define CMP(d, x, y, size)\d = cmp(s, src_y, (ref_y) + (x) + (y)*(stride), stride);#define CMP_HPEL(d, dx, dy, x, y, size)\{\ const int dxy= (dx) + 2*(dy);\ hpel_put[0][dxy](s->me.scratchpad, (ref_y) + (x) + (y)*(stride), stride, (16>>size));\ d = cmp_sub(s, s->me.scratchpad, src_y, stride);\}#define CMP_QPEL(d, dx, dy, x, y, size)\{\ const int dxy= (dx) + 4*(dy);\ qpel_put[0][dxy](s->me.scratchpad, (ref_y) + (x) + (y)*(stride), stride);\ d = cmp_sub(s, s->me.scratchpad, src_y, stride);\}#include "motion_est_template.c"#undef RENAME#undef CMP#undef CMP_HPEL#undef CMP_QPEL#undef INIT/* SIMPLE CHROMA */#define RENAME(a) simple_chroma_ ## a#define CMP(d, x, y, size)\d = cmp(s, src_y, (ref_y) + (x) + (y)*(stride), stride);\if(chroma_cmp){\ int dxy= ((x)&1) + 2*((y)&1);\ int c= ((x)>>1) + ((y)>>1)*uvstride;\\ chroma_hpel_put[0][dxy](s->me.scratchpad, ref_u + c, uvstride, 8);\ d += chroma_cmp(s, s->me.scratchpad, src_u, uvstride);\ chroma_hpel_put[0][dxy](s->me.scratchpad, ref_v + c, uvstride, 8);\ d += chroma_cmp(s, s->me.scratchpad, src_v, uvstride);\}#define CMP_HPEL(d, dx, dy, x, y, size)\{\ const int dxy= (dx) + 2*(dy);\ hpel_put[0][dxy](s->me.scratchpad, (ref_y) + (x) + (y)*(stride), stride, (16>>size));\ d = cmp_sub(s, s->me.scratchpad, src_y, stride);\ if(chroma_cmp_sub){\ int cxy= (dxy) | ((x)&1) | (2*((y)&1));\ int c= ((x)>>1) + ((y)>>1)*uvstride;\ chroma_hpel_put[0][cxy](s->me.scratchpad, ref_u + c, uvstride, 8);\ d += chroma_cmp_sub(s, s->me.scratchpad, src_u, uvstride);\ chroma_hpel_put[0][cxy](s->me.scratchpad, ref_v + c, uvstride, 8);\ d += chroma_cmp_sub(s, s->me.scratchpad, src_v, uvstride);\ }\}#define CMP_QPEL(d, dx, dy, x, y, size)\{\ const int dxy= (dx) + 4*(dy);\ qpel_put[0][dxy](s->me.scratchpad, (ref_y) + (x) + (y)*(stride), stride);\ d = cmp_sub(s, s->me.scratchpad, src_y, stride);\ if(chroma_cmp_sub){\ int cxy, c;\ int cx= (4*(x) + (dx))/2;\ int cy= (4*(y) + (dy))/2;\ cx= (cx>>1)|(cx&1);\ cy= (cy>>1)|(cy&1);\ cxy= (cx&1) + 2*(cy&1);\ c= ((cx)>>1) + ((cy)>>1)*uvstride;\ chroma_hpel_put[0][cxy](s->me.scratchpad, ref_u + c, uvstride, 8);\ d += chroma_cmp_sub(s, s->me.scratchpad, src_u, uvstride);\ chroma_hpel_put[0][cxy](s->me.scratchpad, ref_v + c, uvstride, 8);\ d += chroma_cmp_sub(s, s->me.scratchpad, src_v, uvstride);\ }\}#include "motion_est_template.c"#undef RENAME#undef CMP#undef CMP_HPEL#undef CMP_QPEL#undef INIT/* SIMPLE DIRECT HPEL */#define RENAME(a) simple_direct_hpel_ ## a//FIXME precalc divisions stuff#define CMP_DIRECT(d, dx, dy, x, y, size, cmp_func)\if((x) >= xmin && 2*(x) + (dx) <= 2*xmax && (y) >= ymin && 2*(y) + (dy) <= 2*ymax){\ const int hx= 2*(x) + (dx);\ const int hy= 2*(y) + (dy);\ if(s->mv_type==MV_TYPE_8X8){\ int i;\ for(i=0; i<4; i++){\ int fx = s->me.direct_basis_mv[i][0] + hx;\ int fy = s->me.direct_basis_mv[i][1] + hy;\ int bx = hx ? fx - s->me.co_located_mv[i][0] : s->me.co_located_mv[i][0]*(time_pb - time_pp)/time_pp + (i &1)*16;\ int by = hy ? fy - s->me.co_located_mv[i][1] : s->me.co_located_mv[i][1]*(time_pb - time_pp)/time_pp + (i>>1)*16;\ int fxy= (fx&1) + 2*(fy&1);\ int bxy= (bx&1) + 2*(by&1);\\ uint8_t *dst= s->me.scratchpad + 8*(i&1) + 8*stride*(i>>1);\ hpel_put[1][fxy](dst, (ref_y ) + (fx>>1) + (fy>>1)*(stride), stride, 8);\ hpel_avg[1][bxy](dst, (ref2_y) + (bx>>1) + (by>>1)*(stride), stride, 8);\ }\ }else{\ int fx = s->me.direct_basis_mv[0][0] + hx;\ int fy = s->me.direct_basis_mv[0][1] + hy;\ int bx = hx ? fx - s->me.co_located_mv[0][0] : (s->me.co_located_mv[0][0]*(time_pb - time_pp)/time_pp);\ int by = hy ? fy - s->me.co_located_mv[0][1] : (s->me.co_located_mv[0][1]*(time_pb - time_pp)/time_pp);\ int fxy= (fx&1) + 2*(fy&1);\ int bxy= (bx&1) + 2*(by&1);\ \ 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);\\ hpel_put[0][fxy](s->me.scratchpad, (ref_y ) + (fx>>1) + (fy>>1)*(stride), stride, 16);\ hpel_avg[0][bxy](s->me.scratchpad, (ref2_y) + (bx>>1) + (by>>1)*(stride), stride, 16);\ }\ d = cmp_func(s, s->me.scratchpad, src_y, stride);\}else\ d= 256*256*256*32;#define CMP_HPEL(d, dx, dy, x, y, size)\ CMP_DIRECT(d, dx, dy, x, y, size, cmp_sub)#define CMP(d, x, y, size)\ CMP_DIRECT(d, 0, 0, x, y, size, cmp) #include "motion_est_template.c"#undef RENAME#undef CMP#undef CMP_HPEL#undef CMP_QPEL#undef INIT#undef CMP_DIRECT/* SIMPLE DIRECT QPEL */#define RENAME(a) simple_direct_qpel_ ## a#define CMP_DIRECT(d, dx, dy, x, y, size, cmp_func)\if((x) >= xmin && 4*(x) + (dx) <= 4*xmax && (y) >= ymin && 4*(y) + (dy) <= 4*ymax){\ const int qx= 4*(x) + (dx);\ const int qy= 4*(y) + (dy);\ if(s->mv_type==MV_TYPE_8X8){\ int i;\ for(i=0; i<4; i++){\ int fx = s->me.direct_basis_mv[i][0] + qx;\ int fy = s->me.direct_basis_mv[i][1] + qy;\ int bx = qx ? fx - s->me.co_located_mv[i][0] : s->me.co_located_mv[i][0]*(time_pb - time_pp)/time_pp + (i &1)*16;\ int by = qy ? fy - s->me.co_located_mv[i][1] : s->me.co_located_mv[i][1]*(time_pb - time_pp)/time_pp + (i>>1)*16;\ int fxy= (fx&3) + 4*(fy&3);\ int bxy= (bx&3) + 4*(by&3);\\ uint8_t *dst= s->me.scratchpad + 8*(i&1) + 8*stride*(i>>1);\ qpel_put[1][fxy](dst, (ref_y ) + (fx>>2) + (fy>>2)*(stride), stride);\ qpel_avg[1][bxy](dst, (ref2_y) + (bx>>2) + (by>>2)*(stride), stride);\ }\ }else{\ int fx = s->me.direct_basis_mv[0][0] + qx;\ int fy = s->me.direct_basis_mv[0][1] + qy;\ int bx = qx ? fx - s->me.co_located_mv[0][0] : s->me.co_located_mv[0][0]*(time_pb - time_pp)/time_pp;\ int by = qy ? fy - s->me.co_located_mv[0][1] : s->me.co_located_mv[0][1]*(time_pb - time_pp)/time_pp;\ int fxy= (fx&3) + 4*(fy&3);\ int bxy= (bx&3) + 4*(by&3);\\ qpel_put[1][fxy](s->me.scratchpad , (ref_y ) + (fx>>2) + (fy>>2)*(stride) , stride);\ qpel_put[1][fxy](s->me.scratchpad + 8 , (ref_y ) + (fx>>2) + (fy>>2)*(stride) + 8 , stride);\ qpel_put[1][fxy](s->me.scratchpad + 8*stride, (ref_y ) + (fx>>2) + (fy>>2)*(stride) + 8*stride, stride);\ qpel_put[1][fxy](s->me.scratchpad + 8 + 8*stride, (ref_y ) + (fx>>2) + (fy>>2)*(stride) + 8 + 8*stride, stride);\ qpel_avg[1][bxy](s->me.scratchpad , (ref2_y) + (bx>>2) + (by>>2)*(stride) , stride);\ qpel_avg[1][bxy](s->me.scratchpad + 8 , (ref2_y) + (bx>>2) + (by>>2)*(stride) + 8 , stride);\ qpel_avg[1][bxy](s->me.scratchpad + 8*stride, (ref2_y) + (bx>>2) + (by>>2)*(stride) + 8*stride, stride);\ qpel_avg[1][bxy](s->me.scratchpad + 8 + 8*stride, (ref2_y) + (bx>>2) + (by>>2)*(stride) + 8 + 8*stride, stride);\ }\ d = cmp_func(s, s->me.scratchpad, src_y, stride);\}else\ d= 256*256*256*32;#define CMP_QPEL(d, dx, dy, x, y, size)\ CMP_DIRECT(d, dx, dy, x, y, size, cmp_sub)#define CMP(d, x, y, size)\ CMP_DIRECT(d, 0, 0, x, y, size, cmp)#include "motion_est_template.c"#undef RENAME#undef CMP#undef CMP_HPEL#undef CMP_QPEL#undef INIT#undef CMP__DIRECTstatic int zero_cmp(void *s, uint8_t *a, uint8_t *b, int stride){ return 0;}static void set_cmp(MpegEncContext *s, me_cmp_func *cmp, int type){ DSPContext* c= &s->dsp; int i; memset(cmp, 0, sizeof(void*)*11); switch(type&0xFF){ case FF_CMP_SAD: cmp[0]= c->sad[0]; cmp[1]= c->sad[1]; break; case FF_CMP_SATD: cmp[0]= c->hadamard8_diff[0]; cmp[1]= c->hadamard8_diff[1]; break; case FF_CMP_SSE: cmp[0]= c->sse[0]; cmp[1]= c->sse[1]; break; case FF_CMP_DCT: cmp[0]= c->dct_sad[0]; cmp[1]= c->dct_sad[1]; break; case FF_CMP_PSNR: cmp[0]= c->quant_psnr[0]; cmp[1]= c->quant_psnr[1]; break; case FF_CMP_BIT: cmp[0]= c->bit[0]; cmp[1]= c->bit[1]; break; case FF_CMP_RD: cmp[0]= c->rd[0]; cmp[1]= c->rd[1]; break; case FF_CMP_ZERO: for(i=0; i<7; i++){ cmp[i]= zero_cmp; } break; default: av_log(s->avctx, AV_LOG_ERROR,"internal error in cmp function selection\n"); }}static inline int get_penalty_factor(MpegEncContext *s, int type){ switch(type&0xFF){ default: case FF_CMP_SAD: return s->qscale*2; case FF_CMP_DCT: return s->qscale*3; case FF_CMP_SATD: return s->qscale*6; case FF_CMP_SSE: return s->qscale*s->qscale*2; case FF_CMP_BIT: return 1; case FF_CMP_RD: case FF_CMP_PSNR: return (s->qscale*s->qscale*185 + 64)>>7; }}void ff_init_me(MpegEncContext *s){ set_cmp(s, s->dsp.me_pre_cmp, s->avctx->me_pre_cmp); set_cmp(s, s->dsp.me_cmp, s->avctx->me_cmp); set_cmp(s, s->dsp.me_sub_cmp, s->avctx->me_sub_cmp); set_cmp(s, s->dsp.mb_cmp, s->avctx->mb_cmp); if(s->flags&CODEC_FLAG_QPEL){ if(s->avctx->me_sub_cmp&FF_CMP_CHROMA) s->me.sub_motion_search= simple_chroma_qpel_motion_search; else s->me.sub_motion_search= simple_qpel_motion_search; }else{ if(s->avctx->me_sub_cmp&FF_CMP_CHROMA) s->me.sub_motion_search= simple_chroma_hpel_motion_search; else if( s->avctx->me_sub_cmp == FF_CMP_SAD && s->avctx-> me_cmp == FF_CMP_SAD && s->avctx-> mb_cmp == FF_CMP_SAD) s->me.sub_motion_search= sad_hpel_motion_search; else s->me.sub_motion_search= simple_hpel_motion_search; } if(s->avctx->me_cmp&FF_CMP_CHROMA){ s->me.motion_search[0]= simple_chroma_epzs_motion_search; s->me.motion_search[1]= simple_chroma_epzs_motion_search4; }else{ s->me.motion_search[0]= simple_epzs_motion_search; s->me.motion_search[1]= simple_epzs_motion_search4; } if(s->avctx->me_pre_cmp&FF_CMP_CHROMA){ s->me.pre_motion_search= simple_chroma_epzs_motion_search; }else{ s->me.pre_motion_search= simple_epzs_motion_search; } if(s->flags&CODEC_FLAG_QPEL){ if(s->avctx->mb_cmp&FF_CMP_CHROMA) s->me.get_mb_score= simple_chroma_qpel_get_mb_score; else s->me.get_mb_score= simple_qpel_get_mb_score; }else{ if(s->avctx->mb_cmp&FF_CMP_CHROMA) s->me.get_mb_score= simple_chroma_hpel_get_mb_score; else s->me.get_mb_score= simple_hpel_get_mb_score; }} #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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -