📄 motion_est.c
字号:
/* * Motion estimation * Copyright (c) 2000,2001 Fabrice Bellard. * Copyright (c) 2002 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> */#include <stdlib.h>#include <stdio.h>#include "avcodec.h"#include "dsputil.h"#include "mpegvideo.h"#define SQ(a) ((a)*(a))#define INTER_BIAS 257#define P_LAST P[0]#define P_LEFT P[1]#define P_TOP P[2]#define P_TOPRIGHT P[3]#define P_MEDIAN P[4]#define P_LAST_LEFT P[5]#define P_LAST_RIGHT P[6]#define P_LAST_TOP P[7]#define P_LAST_BOTTOM P[8]#define P_MV1 P[9]static int pix_dev(UINT8 * 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;}static int pix_norm(UINT8 * pix1, UINT8 * pix2, int line_size){ int s, i, j; UINT32 *sq = squareTbl + 256; s = 0; for (i = 0; i < 16; i++) { for (j = 0; j < 16; j += 8) { s += sq[pix1[0] - pix2[0]]; s += sq[pix1[1] - pix2[1]]; s += sq[pix1[2] - pix2[2]]; s += sq[pix1[3] - pix2[3]]; s += sq[pix1[4] - pix2[4]]; s += sq[pix1[5] - pix2[5]]; s += sq[pix1[6] - pix2[6]]; s += sq[pix1[7] - pix2[7]]; pix1 += 8; pix2 += 8; } pix1 += line_size - 16; pix2 += line_size - 16; } return s;}static 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;}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 *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[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_abs16x16(pix, ref_picture + (y * s->linesize) + x, s->linesize); 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) || *my_ptr < -(2 * range) || *my_ptr >= (2 * range)) { fprintf(stderr, "error %d %d\n", *mx_ptr, *my_ptr); }#endif return dmin;}static int log_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 *pix; xx = s->mb_x << 4; yy = s->mb_y << 4; /* Left limit */ x1 = xx - range; if (x1 < xmin) x1 = xmin; /* Right limit */ x2 = xx + range; if (x2 > xmax) x2 = xmax; /* Upper limit */ y1 = yy - range; if (y1 < ymin) y1 = ymin; /* Lower limit */ y2 = yy + range; if (y2 > ymax) y2 = ymax; pix = s->new_picture[0] + (yy * s->linesize) + xx; dmin = 0x7fffffff; mx = 0; my = 0; do { for (y = y1; y <= y2; y += range) { for (x = x1; x <= x2; x += range) { d = s->dsp.pix_abs16x16(pix, ref_picture + (y * s->linesize) + x, s->linesize); if (d < dmin || (d == dmin && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) { dmin = d; mx = x; my = y; } } } range = range >> 1; x1 = mx - range; if (x1 < xmin) x1 = xmin; x2 = mx + range; if (x2 > xmax) x2 = xmax; y1 = my - range; if (y1 < ymin) y1 = ymin; y2 = my + range; if (y2 > ymax) y2 = ymax; } while (range >= 1);#ifdef DEBUG fprintf(stderr, "log - MX: %d\tMY: %d\n", mx, my);#endif *mx_ptr = mx; *my_ptr = my; return dmin;}static int phods_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, lastx, d; int mx, my, dminx, dminy; UINT8 *pix; xx = s->mb_x << 4; yy = s->mb_y << 4; /* Left limit */ x1 = xx - range; if (x1 < xmin) x1 = xmin; /* Right limit */ x2 = xx + range; if (x2 > xmax) x2 = xmax; /* Upper limit */ y1 = yy - range; if (y1 < ymin) y1 = ymin; /* Lower limit */ y2 = yy + range; if (y2 > ymax) y2 = ymax; pix = s->new_picture[0] + (yy * s->linesize) + xx; mx = 0; my = 0; x = xx; y = yy; do { dminx = 0x7fffffff; dminy = 0x7fffffff; lastx = x; for (x = x1; x <= x2; x += range) { d = s->dsp.pix_abs16x16(pix, ref_picture + (y * s->linesize) + x, s->linesize); if (d < dminx || (d == dminx && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) { dminx = d; mx = x; } } x = lastx; for (y = y1; y <= y2; y += range) { d = s->dsp.pix_abs16x16(pix, ref_picture + (y * s->linesize) + x, s->linesize); if (d < dminy || (d == dminy && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) { dminy = d; my = y; } } range = range >> 1; x = mx; y = my; x1 = mx - range; if (x1 < xmin) x1 = xmin; x2 = mx + range; if (x2 > xmax) x2 = xmax; y1 = my - range; if (y1 < ymin) y1 = ymin; y2 = my + range; if (y2 > ymax) y2 = ymax; } while (range >= 1);#ifdef DEBUG fprintf(stderr, "phods - MX: %d\tMY: %d\n", mx, my);#endif /* half pixel search */ *mx_ptr = mx; *my_ptr = my; return dminy;}#define Z_THRESHOLD 256#define CHECK_MV(x,y)\{\ const int key= ((y)<<ME_MAP_MV_BITS) + (x) + map_generation;\ const int index= (((y)<<ME_MAP_SHIFT) + (x))&(ME_MAP_SIZE-1);\ if(map[index]!=key){\ d = s->dsp.pix_abs16x16(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride);\ d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant;\ COPY3_IF_LT(dmin, d, best[0], x, best[1], y)\ map[index]= key;\ score_map[index]= d;\ }\}#define CHECK_MV_DIR(x,y,new_dir)\{\ const int key= ((y)<<ME_MAP_MV_BITS) + (x) + map_generation;\ const int index= (((y)<<ME_MAP_SHIFT) + (x))&(ME_MAP_SIZE-1);\ if(map[index]!=key){\ d = pix_abs(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride);\ d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant;\ if(d<dmin){\ best[0]=x;\ best[1]=y;\ dmin=d;\ next_dir= new_dir;\ }\ map[index]= key;\ score_map[index]= d;\ }\}#define CHECK_MV4(x,y)\{\ const int key= ((y)<<ME_MAP_MV_BITS) + (x) + map_generation;\ const int index= (((y)<<ME_MAP_SHIFT) + (x))&(ME_MAP_SIZE-1);\ if(map[index]!=key){\ d = s->dsp.pix_abs8x8(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride);\ d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant;\ COPY3_IF_LT(dmin, d, best[0], x, best[1], y)\ map[index]= key;\ score_map[index]= d;\ }\}#define check(x,y,S,v)\if( (x)<(xmin<<(S)) ) printf("%d %d %d %d %d xmin" #v, xmin, (x), (y), s->mb_x, s->mb_y);\if( (x)>(xmax<<(S)) ) printf("%d %d %d %d %d xmax" #v, xmax, (x), (y), s->mb_x, s->mb_y);\if( (y)<(ymin<<(S)) ) printf("%d %d %d %d %d ymin" #v, ymin, (x), (y), s->mb_x, s->mb_y);\if( (y)>(ymax<<(S)) ) printf("%d %d %d %d %d ymax" #v, ymax, (x), (y), s->mb_x, s->mb_y);\static inline int small_diamond_search(MpegEncContext * s, int *best, int dmin, UINT8 *new_pic, UINT8 *old_pic, int pic_stride, int pred_x, int pred_y, UINT16 *mv_penalty, int quant, int xmin, int ymin, int xmax, int ymax, int shift, uint32_t *map, uint16_t *score_map, int map_generation, op_pixels_abs_func pix_abs){ int next_dir=-1; for(;;){ int d; const int dir= next_dir; const int x= best[0]; const int y= best[1]; next_dir=-1;//printf("%d", dir); if(dir!=2 && x>xmin) CHECK_MV_DIR(x-1, y , 0) if(dir!=3 && y>ymin) CHECK_MV_DIR(x , y-1, 1) if(dir!=0 && x<xmax) CHECK_MV_DIR(x+1, y , 2) if(dir!=1 && y<ymax) CHECK_MV_DIR(x , y+1, 3) if(next_dir==-1){ return dmin; } }/* for(;;){ int d; const int x= best[0]; const int y= best[1]; const int last_min=dmin; if(x>xmin) CHECK_MV(x-1, y ) if(y>xmin) CHECK_MV(x , y-1) if(x<xmax) CHECK_MV(x+1, y ) if(y<xmax) CHECK_MV(x , y+1) if(x>xmin && y>ymin) CHECK_MV(x-1, y-1) if(x>xmin && y<ymax) CHECK_MV(x-1, y+1) if(x<xmax && y>ymin) CHECK_MV(x+1, y-1) if(x<xmax && y<ymax) CHECK_MV(x+1, y+1) if(x-1>xmin) CHECK_MV(x-2, y ) if(y-1>xmin) CHECK_MV(x , y-2) if(x+1<xmax) CHECK_MV(x+2, y ) if(y+1<xmax) CHECK_MV(x , y+2) if(x-1>xmin && y-1>ymin) CHECK_MV(x-2, y-2) if(x-1>xmin && y+1<ymax) CHECK_MV(x-2, y+2) if(x+1<xmax && y-1>ymin) CHECK_MV(x+2, y-2) if(x+1<xmax && y+1<ymax) CHECK_MV(x+2, y+2) if(dmin==last_min) return dmin; } */}#if 1#define SNAKE_1 3#define SNAKE_2 2#else#define SNAKE_1 7#define SNAKE_2 3#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -