summaryrefslogtreecommitdiff
path: root/src/libffmpeg/libavcodec/motion_est.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libffmpeg/libavcodec/motion_est.c')
-rw-r--r--src/libffmpeg/libavcodec/motion_est.c703
1 files changed, 627 insertions, 76 deletions
diff --git a/src/libffmpeg/libavcodec/motion_est.c b/src/libffmpeg/libavcodec/motion_est.c
index 084eb6038..92724ac87 100644
--- a/src/libffmpeg/libavcodec/motion_est.c
+++ b/src/libffmpeg/libavcodec/motion_est.c
@@ -16,6 +16,8 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * new Motion Estimation (X1/EPZS) by Michael Niedermayer <michaelni@gmx.at>
*/
#include "config.h"
#include "xine-utils/xineutils.h"
@@ -25,9 +27,14 @@
#include "dsputil.h"
#include "mpegvideo.h"
+#define ABS(a) ((a)>0 ? (a) : -(a))
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#define INTER_BIAS 257
+
static void halfpel_motion_search(MpegEncContext * s,
int *mx_ptr, int *my_ptr, int dmin,
- int xmin, int ymin, int xmax, int ymax);
+ int xmin, int ymin, int xmax, int ymax,
+ int pred_x, int pred_y);
/* config it to test motion vector encoding (send random vectors) */
//#define CONFIG_TEST_MV_ENCODE
@@ -54,6 +61,28 @@ static int pix_sum(UINT8 * pix, int line_size)
return s;
}
+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_norm1(UINT8 * pix, int line_size)
{
int s, i, j;
@@ -138,7 +167,7 @@ static int full_motion_search(MpegEncContext * s,
for (y = y1; y <= y2; y++) {
for (x = x1; x <= x2; x++) {
d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x,
- s->linesize, 16);
+ s->linesize);
if (d < dmin ||
(d == dmin &&
(abs(x - xx) + abs(y - yy)) <
@@ -202,7 +231,7 @@ static int log_motion_search(MpegEncContext * s,
do {
for (y = y1; y <= y2; y += range) {
for (x = x1; x <= x2; x += range) {
- d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize, 16);
+ d = pix_abs16x16(pix, s->last_picture[0] + (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;
@@ -282,7 +311,7 @@ static int phods_motion_search(MpegEncContext * s,
lastx = x;
for (x = x1; x <= x2; x += range) {
- d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize, 16);
+ d = pix_abs16x16(pix, s->last_picture[0] + (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;
@@ -291,7 +320,7 @@ static int phods_motion_search(MpegEncContext * s,
x = lastx;
for (y = y1; y <= y2; y += range) {
- d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize, 16);
+ d = pix_abs16x16(pix, s->last_picture[0] + (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;
@@ -330,78 +359,474 @@ static int phods_motion_search(MpegEncContext * s,
return dminy;
}
+
+#define Z_THRESHOLD 256
+
+#define CHECK_MV(x,y)\
+{\
+ d = 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;\
+ if(d<dmin){\
+ best[0]=x;\
+ best[1]=y;\
+ dmin=d;\
+ }\
+}
+
+#define CHECK_MV_DIR(x,y,new_dir)\
+{\
+ d = 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;\
+ if(d<dmin){\
+ best[0]=x;\
+ best[1]=y;\
+ dmin=d;\
+ next_dir= new_dir;\
+ }\
+}
+
+#define CHECK_MV4(x,y)\
+{\
+ d = 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;\
+ if(d<dmin){\
+ best[0]=x;\
+ best[1]=y;\
+ dmin=d;\
+ }\
+}
+
+#define CHECK_MV4_DIR(x,y,new_dir)\
+{\
+ d = 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;\
+ if(d<dmin){\
+ best[0]=x;\
+ best[1]=y;\
+ dmin=d;\
+ next_dir= new_dir;\
+ }\
+}
+
+
+#define check(x,y,S,v)\
+if( (x)<(xmin<<(S)) ) printf("%d %d %d %d xmin" #v, (x), (y), s->mb_x, s->mb_y);\
+if( (x)>(xmax<<(S)) ) printf("%d %d %d %d xmax" #v, (x), (y), s->mb_x, s->mb_y);\
+if( (y)<(ymin<<(S)) ) printf("%d %d %d %d ymin" #v, (x), (y), s->mb_x, s->mb_y);\
+if( (y)>(ymax<<(S)) ) printf("%d %d %d %d ymax" #v, (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)
+{
+ 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;
+ }
+ */
+}
+
+static inline int small_diamond_search4MV(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)
+{
+ 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_MV4_DIR(x-1, y , 0)
+ if(dir!=3 && y>ymin) CHECK_MV4_DIR(x , y-1, 1)
+ if(dir!=0 && x<xmax) CHECK_MV4_DIR(x+1, y , 2)
+ if(dir!=1 && y<ymax) CHECK_MV4_DIR(x , y+1, 3)
+
+ if(next_dir==-1){
+ return dmin;
+ }
+ }
+}
+
+static inline int snake_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)
+{
+ int dir=0;
+ int c=1;
+ static int x_dir[8]= {1,1,0,-1,-1,-1, 0, 1};
+ static int y_dir[8]= {0,1,1, 1, 0,-1,-1,-1};
+ int fails=0;
+ int last_d[2]={dmin, dmin};
+
+/*static int good=0;
+static int bad=0;
+static int point=0;
+
+point++;
+if(256*256*256*64%point==0)
+{
+ printf("%d %d %d\n", good, bad, point);
+}*/
+
+ for(;;){
+ int x= best[0];
+ int y= best[1];
+ int d;
+ x+=x_dir[dir];
+ y+=y_dir[dir];
+ if(x>=xmin && x<=xmax && y>=ymin && y<=ymax){
+ d = 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;
+ }else{
+ d = dmin + 10000; //FIXME smarter boundary handling
+ }
+ if(d<dmin){
+ best[0]=x;
+ best[1]=y;
+ dmin=d;
+
+ if(last_d[1] - last_d[0] > last_d[0] - d) c= -c;
+ dir+=c;
+
+ fails=0;
+//good++;
+ last_d[1]=last_d[0];
+ last_d[0]=d;
+ }else{
+//bad++;
+ if(fails){
+ if(fails>=3) return dmin;
+ }else{
+ c= -c;
+ }
+ dir+=c*2;
+ fails++;
+ }
+ dir&=7;
+ }
+}
+
+static int epzs_motion_search(MpegEncContext * s,
+ int *mx_ptr, int *my_ptr,
+ int P[5][2], int pred_x, int pred_y,
+ int xmin, int ymin, int xmax, int ymax)
+{
+ int best[2]={0, 0};
+ int d, dmin;
+ UINT8 *new_pic, *old_pic;
+ const int pic_stride= s->linesize;
+ const int pic_xy= (s->mb_y*pic_stride + s->mb_x)*16;
+ UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame
+ int quant= s->qscale; // qscale of the prev frame
+ const int shift= 1+s->quarter_sample;
+
+ new_pic = s->new_picture[0] + pic_xy;
+ old_pic = s->last_picture[0] + pic_xy;
+
+ dmin = pix_abs16x16(new_pic, old_pic, pic_stride);
+ if(dmin<Z_THRESHOLD){
+ *mx_ptr= 0;
+ *my_ptr= 0;
+//printf("Z");
+ return dmin;
+ }
+
+ /* first line */
+ if ((s->mb_y == 0 || s->first_slice_line || s->first_gob_line)) {
+ CHECK_MV(P[1][0]>>shift, P[1][1]>>shift)
+ }else{
+ CHECK_MV(P[4][0]>>shift, P[4][1]>>shift)
+ if(dmin<Z_THRESHOLD){
+ *mx_ptr= P[4][0]>>shift;
+ *my_ptr= P[4][1]>>shift;
+//printf("M\n");
+ return dmin;
+ }
+ CHECK_MV(P[1][0]>>shift, P[1][1]>>shift)
+ CHECK_MV(P[2][0]>>shift, P[2][1]>>shift)
+ CHECK_MV(P[3][0]>>shift, P[3][1]>>shift)
+ }
+ CHECK_MV(P[0][0]>>shift, P[0][1]>>shift)
+
+//check(best[0],best[1],0, b0)
+ if(s->full_search==ME_EPZS)
+ dmin= small_diamond_search(s, best, dmin, new_pic, old_pic, pic_stride,
+ pred_x, pred_y, mv_penalty, quant, xmin, ymin, xmax, ymax, shift);
+ else
+ dmin= snake_search(s, best, dmin, new_pic, old_pic, pic_stride,
+ pred_x, pred_y, mv_penalty, quant, xmin, ymin, xmax, ymax, shift);
+//check(best[0],best[1],0, b1)
+ *mx_ptr= best[0];
+ *my_ptr= best[1];
+
+// printf("%d %d %d \n", best[0], best[1], dmin);
+ return dmin;
+}
+
+static int epzs_motion_search4(MpegEncContext * s, int block,
+ int *mx_ptr, int *my_ptr,
+ int P[6][2], int pred_x, int pred_y,
+ int xmin, int ymin, int xmax, int ymax)
+{
+ int best[2]={0, 0};
+ int d, dmin;
+ UINT8 *new_pic, *old_pic;
+ const int pic_stride= s->linesize;
+ const int pic_xy= ((s->mb_y*2 + (block>>1))*pic_stride + s->mb_x*2 + (block&1))*8;
+ UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame
+ int quant= s->qscale; // qscale of the prev frame
+ const int shift= 1+s->quarter_sample;
+
+ new_pic = s->new_picture[0] + pic_xy;
+ old_pic = s->last_picture[0] + pic_xy;
+
+ dmin = pix_abs8x8(new_pic, old_pic, pic_stride);
+
+ /* first line */
+ if ((s->mb_y == 0 || s->first_slice_line || s->first_gob_line) && block<2) {
+ CHECK_MV4(P[1][0]>>shift, P[1][1]>>shift)
+ }else{
+ CHECK_MV4(P[4][0]>>shift, P[4][1]>>shift)
+ if(dmin<Z_THRESHOLD){
+ *mx_ptr= P[4][0]>>shift;
+ *my_ptr= P[4][1]>>shift;
+//printf("M\n");
+ return dmin;
+ }
+ CHECK_MV4(P[1][0]>>shift, P[1][1]>>shift)
+ CHECK_MV4(P[2][0]>>shift, P[2][1]>>shift)
+ CHECK_MV4(P[3][0]>>shift, P[3][1]>>shift)
+ }
+ CHECK_MV4(P[0][0]>>shift, P[0][1]>>shift)
+ CHECK_MV4(P[5][0]>>shift, P[5][1]>>shift)
+
+//check(best[0],best[1],0, b0)
+ dmin= small_diamond_search4MV(s, best, dmin, new_pic, old_pic, pic_stride,
+ pred_x, pred_y, mv_penalty, quant, xmin, ymin, xmax, ymax, shift);
+//check(best[0],best[1],0, b1)
+ *mx_ptr= best[0];
+ *my_ptr= best[1];
+
+// printf("%d %d %d \n", best[0], best[1], dmin);
+ return dmin;
+}
+
+#define CHECK_HALF_MV(suffix, x, y) \
+ d= pix_abs16x16_ ## suffix(pix, ptr+((x)>>1), s->linesize);\
+ d += (mv_penalty[pen_x + x] + mv_penalty[pen_y + y])*quant;\
+ if(d<dminh){\
+ dminh= d;\
+ mx= mx1 + x;\
+ my= my1 + y;\
+ }
+
+#define CHECK_HALF_MV4(suffix, x, y) \
+ d= pix_abs8x8_ ## suffix(pix, ptr+((x)>>1), s->linesize);\
+ d += (mv_penalty[pen_x + x] + mv_penalty[pen_y + y])*quant;\
+ if(d<dminh){\
+ dminh= d;\
+ mx= mx1 + x;\
+ my= my1 + y;\
+ }
+
/* The idea would be to make half pel ME after Inter/Intra decision to
save time. */
-static void halfpel_motion_search(MpegEncContext * s,
+static inline void halfpel_motion_search(MpegEncContext * s,
int *mx_ptr, int *my_ptr, int dmin,
- int xmin, int ymin, int xmax, int ymax)
+ int xmin, int ymin, int xmax, int ymax,
+ int pred_x, int pred_y)
{
+ UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame
+ const int quant= s->qscale;
+ int pen_x, pen_y;
int mx, my, mx1, my1, d, xx, yy, dminh;
- UINT8 *pix;
+ UINT8 *pix, *ptr;
- mx = *mx_ptr << 1;
- my = *my_ptr << 1;
+ mx = *mx_ptr;
+ my = *my_ptr;
+ ptr = s->last_picture[0] + (my * s->linesize) + mx;
xx = 16 * s->mb_x;
yy = 16 * s->mb_y;
-
+ pix = s->new_picture[0] + (yy * s->linesize) + xx;
+
dminh = dmin;
- /* Half pixel search */
- mx1 = mx;
- my1 = my;
+ if (mx > xmin && mx < xmax &&
+ my > ymin && my < ymax) {
- pix = s->new_picture[0] + (yy * s->linesize) + xx;
+ mx= mx1= 2*(mx - xx);
+ my= my1= 2*(my - yy);
+ if(dmin < Z_THRESHOLD && mx==0 && my==0){
+ *mx_ptr = 0;
+ *my_ptr = 0;
+ return;
+ }
+
+ pen_x= pred_x + mx;
+ pen_y= pred_y + my;
+
+ ptr-= s->linesize;
+ CHECK_HALF_MV(xy2, -1, -1)
+ CHECK_HALF_MV(y2 , 0, -1)
+ CHECK_HALF_MV(xy2, +1, -1)
+
+ ptr+= s->linesize;
+ CHECK_HALF_MV(x2 , -1, 0)
+ CHECK_HALF_MV(x2 , +1, 0)
+ CHECK_HALF_MV(xy2, -1, +1)
+ CHECK_HALF_MV(y2 , 0, +1)
+ CHECK_HALF_MV(xy2, +1, +1)
+
+ }else{
+ mx= 2*(mx - xx);
+ my= 2*(my - yy);
+ }
- if ((mx > (xmin << 1)) && mx < (xmax << 1) &&
- (my > (ymin << 1)) && my < (ymax << 1)) {
- int dx, dy, px, py;
- UINT8 *ptr;
- for (dy = -1; dy <= 1; dy++) {
- for (dx = -1; dx <= 1; dx++) {
- if (dx != 0 || dy != 0) {
- px = mx1 + dx;
- py = my1 + dy;
- ptr = s->last_picture[0] + ((py >> 1) * s->linesize) + (px >> 1);
- switch (((py & 1) << 1) | (px & 1)) {
- default:
- case 0:
- d = pix_abs16x16(pix, ptr, s->linesize, 16);
- break;
- case 1:
- d = pix_abs16x16_x2(pix, ptr, s->linesize, 16);
- break;
- case 2:
- d = pix_abs16x16_y2(pix, ptr, s->linesize, 16);
- break;
- case 3:
- d = pix_abs16x16_xy2(pix, ptr, s->linesize, 16);
- break;
- }
- if (d < dminh) {
- dminh = d;
- mx = px;
- my = py;
- }
- }
- }
+ *mx_ptr = mx;
+ *my_ptr = my;
+}
+
+static inline void halfpel_motion_search4(MpegEncContext * s,
+ int *mx_ptr, int *my_ptr, int dmin,
+ int xmin, int ymin, int xmax, int ymax,
+ int pred_x, int pred_y, int block_x, int block_y)
+{
+ UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame
+ const int quant= s->qscale;
+ int pen_x, pen_y;
+ int mx, my, mx1, my1, d, xx, yy, dminh;
+ UINT8 *pix, *ptr;
+
+ xx = 8 * block_x;
+ yy = 8 * block_y;
+ pix = s->new_picture[0] + (yy * s->linesize) + xx;
+
+ mx = *mx_ptr;
+ my = *my_ptr;
+ ptr = s->last_picture[0] + ((yy+my) * s->linesize) + xx + mx;
+
+ dminh = dmin;
+
+ if (mx > xmin && mx < xmax &&
+ my > ymin && my < ymax) {
+
+ mx= mx1= 2*mx;
+ my= my1= 2*my;
+ if(dmin < Z_THRESHOLD && mx==0 && my==0){
+ *mx_ptr = 0;
+ *my_ptr = 0;
+ return;
}
+
+ pen_x= pred_x + mx;
+ pen_y= pred_y + my;
+
+ ptr-= s->linesize;
+ CHECK_HALF_MV4(xy2, -1, -1)
+ CHECK_HALF_MV4(y2 , 0, -1)
+ CHECK_HALF_MV4(xy2, +1, -1)
+
+ ptr+= s->linesize;
+ CHECK_HALF_MV4(x2 , -1, 0)
+ CHECK_HALF_MV4(x2 , +1, 0)
+ CHECK_HALF_MV4(xy2, -1, +1)
+ CHECK_HALF_MV4(y2 , 0, +1)
+ CHECK_HALF_MV4(xy2, +1, +1)
+
+ }else{
+ mx*=2;
+ my*=2;
}
- *mx_ptr = mx - (xx << 1);
- *my_ptr = my - (yy << 1);
- //fprintf(stderr,"half - MX: %d\tMY: %d\n",*mx_ptr ,*my_ptr);
+ *mx_ptr = mx;
+ *my_ptr = my;
+}
+
+static inline void set_mv_tables(MpegEncContext * s, int mx, int my)
+{
+ const int xy= s->mb_x + s->mb_y*s->mb_width;
+
+ s->mv_table[0][xy] = mx;
+ s->mv_table[1][xy] = my;
+
+ /* has allready been set to the 4 MV if 4MV is done */
+ if(!(s->flags&CODEC_FLAG_4MV)){
+ int mot_xy= s->block_index[0];
+
+ s->motion_val[mot_xy ][0]= mx;
+ s->motion_val[mot_xy ][1]= my;
+ s->motion_val[mot_xy+1][0]= mx;
+ s->motion_val[mot_xy+1][1]= my;
+
+ mot_xy += s->block_wrap[0];
+ s->motion_val[mot_xy ][0]= mx;
+ s->motion_val[mot_xy ][1]= my;
+ s->motion_val[mot_xy+1][0]= mx;
+ s->motion_val[mot_xy+1][1]= my;
+ }
}
#ifndef CONFIG_TEST_MV_ENCODE
-int estimate_motion(MpegEncContext * s,
- int mb_x, int mb_y,
- int *mx_ptr, int *my_ptr)
+void estimate_motion(MpegEncContext * s,
+ int mb_x, int mb_y)
{
UINT8 *pix, *ppix;
int sum, varc, vard, mx, my, range, dmin, xx, yy;
int xmin, ymin, xmax, ymax;
+ int rel_xmin, rel_ymin, rel_xmax, rel_ymax;
+ int pred_x=0, pred_y=0;
+ int P[6][2];
+ const int shift= 1+s->quarter_sample;
+ int mb_type=0;
range = 8 * (1 << (s->f_code - 1));
/* XXX: temporary kludge to avoid overflow for msmpeg4 */
@@ -411,6 +836,8 @@ int estimate_motion(MpegEncContext * s,
if (s->unrestricted_mv) {
xmin = -16;
ymin = -16;
+ if (s->h263_plus)
+ range *= 2;
if(s->avctx==NULL || s->avctx->codec->id!=CODEC_ID_MPEG4){
xmax = s->mb_width*16;
ymax = s->mb_height*16;
@@ -426,7 +853,6 @@ int estimate_motion(MpegEncContext * s,
xmax = s->mb_width*16 - 16;
ymax = s->mb_height*16 - 16;
}
-
switch(s->full_search) {
case ME_ZERO:
default:
@@ -442,8 +868,116 @@ int estimate_motion(MpegEncContext * s,
case ME_PHODS:
dmin = phods_motion_search(s, &mx, &my, range / 2, xmin, ymin, xmax, ymax);
break;
+ case ME_X1:
+ case ME_EPZS:
+ {
+ const int mot_stride = s->block_wrap[0];
+ const int mot_xy = s->block_index[0];
+
+ rel_xmin= xmin - mb_x*16;
+ rel_xmax= xmax - mb_x*16;
+ rel_ymin= ymin - mb_y*16;
+ rel_ymax= ymax - mb_y*16;
+
+ P[0][0] = s->motion_val[mot_xy ][0];
+ P[0][1] = s->motion_val[mot_xy ][1];
+ P[1][0] = s->motion_val[mot_xy - 1][0];
+ P[1][1] = s->motion_val[mot_xy - 1][1];
+ if(P[1][0] > (rel_xmax<<shift)) P[1][0]= (rel_xmax<<shift);
+
+ /* special case for first line */
+ if ((mb_y == 0 || s->first_slice_line || s->first_gob_line)) {
+ P[4][0] = P[1][0];
+ P[4][1] = P[1][1];
+ } else {
+ P[2][0] = s->motion_val[mot_xy - mot_stride ][0];
+ P[2][1] = s->motion_val[mot_xy - mot_stride ][1];
+ P[3][0] = s->motion_val[mot_xy - mot_stride + 2 ][0];
+ P[3][1] = s->motion_val[mot_xy - mot_stride + 2 ][1];
+ if(P[2][1] > (rel_ymax<<shift)) P[2][1]= (rel_ymax<<shift);
+ if(P[3][0] < (rel_xmin<<shift)) P[3][0]= (rel_xmin<<shift);
+ if(P[3][1] > (rel_ymax<<shift)) P[3][1]= (rel_ymax<<shift);
+
+ P[4][0]= mid_pred(P[1][0], P[2][0], P[3][0]);
+ P[4][1]= mid_pred(P[1][1], P[2][1], P[3][1]);
+ }
+ if(s->out_format == FMT_H263){
+ pred_x = P[4][0];
+ pred_y = P[4][1];
+ }else { /* mpeg1 at least */
+ pred_x= P[1][0];
+ pred_y= P[1][1];
+ }
+ }
+ dmin = epzs_motion_search(s, &mx, &my, P, pred_x, pred_y, rel_xmin, rel_ymin, rel_xmax, rel_ymax);
+
+ mx+= mb_x*16;
+ my+= mb_y*16;
+ break;
+ }
+
+ if(s->flags&CODEC_FLAG_4MV){
+ int block;
+
+ mb_type|= MB_TYPE_INTER4V;
+
+ 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->block_wrap[0];
+ const int mot_xy = s->block_index[block];
+ const int block_x= mb_x*2 + (block&1);
+ const int block_y= mb_y*2 + (block>>1);
+
+ const int rel_xmin4= xmin - block_x*8;
+ const int rel_xmax4= xmax - block_x*8 + 8;
+ const int rel_ymin4= ymin - block_y*8;
+ const int rel_ymax4= ymax - block_y*8 + 8;
+
+ P[0][0] = s->motion_val[mot_xy ][0];
+ P[0][1] = s->motion_val[mot_xy ][1];
+ P[1][0] = s->motion_val[mot_xy - 1][0];
+ P[1][1] = s->motion_val[mot_xy - 1][1];
+ if(P[1][0] > (rel_xmax4<<shift)) P[1][0]= (rel_xmax4<<shift);
+
+ /* special case for first line */
+ if ((mb_y == 0 || s->first_slice_line || s->first_gob_line) && block<2) {
+ P[4][0] = P[1][0];
+ P[4][1] = P[1][1];
+ } else {
+ P[2][0] = s->motion_val[mot_xy - mot_stride ][0];
+ P[2][1] = s->motion_val[mot_xy - mot_stride ][1];
+ P[3][0] = s->motion_val[mot_xy - mot_stride + off[block]][0];
+ P[3][1] = s->motion_val[mot_xy - mot_stride + off[block]][1];
+ if(P[2][1] > (rel_ymax4<<shift)) P[2][1]= (rel_ymax4<<shift);
+ if(P[3][0] < (rel_xmin4<<shift)) P[3][0]= (rel_xmin4<<shift);
+ if(P[3][0] > (rel_xmax4<<shift)) P[3][0]= (rel_xmax4<<shift);
+ if(P[3][1] > (rel_ymax4<<shift)) P[3][1]= (rel_ymax4<<shift);
+
+ P[4][0]= mid_pred(P[1][0], P[2][0], P[3][0]);
+ P[4][1]= mid_pred(P[1][1], P[2][1], P[3][1]);
+ }
+ if(s->out_format == FMT_H263){
+ pred_x4 = P[4][0];
+ pred_y4 = P[4][1];
+ }else { /* mpeg1 at least */
+ pred_x4= P[1][0];
+ pred_y4= P[1][1];
+ }
+ P[5][0]= mx - mb_x*16;
+ P[5][1]= my - mb_y*16;
+
+ dmin4 = epzs_motion_search4(s, block, &mx4, &my4, P, pred_x4, pred_y4, rel_xmin4, rel_ymin4, rel_xmax4, rel_ymax4);
+
+ halfpel_motion_search4(s, &mx4, &my4, dmin4, rel_xmin4, rel_ymin4, rel_xmax4, rel_ymax4,
+ pred_x4, pred_y4, block_x, block_y);
+
+ s->motion_val[ s->block_index[block] ][0]= mx4;
+ s->motion_val[ s->block_index[block] ][1]= my4;
+ }
}
- emms_c();
/* intra / predictive decision */
xx = mb_x * 16;
@@ -452,36 +986,53 @@ int estimate_motion(MpegEncContext * s,
pix = s->new_picture[0] + (yy * s->linesize) + xx;
/* At this point (mx,my) are full-pell and the absolute displacement */
ppix = s->last_picture[0] + (my * s->linesize) + mx;
-
+
sum = pix_sum(pix, s->linesize);
- varc = pix_norm1(pix, s->linesize);
- vard = pix_norm(pix, ppix, s->linesize);
+#if 0
+ varc = pix_dev(pix, s->linesize, (sum+128)>>8) + INTER_BIAS;
+ vard = pix_abs16x16(pix, ppix, s->linesize);
+#else
+ sum= (sum+8)>>4;
+ varc = ((pix_norm1(pix, s->linesize) - sum*sum + 128 + 500)>>8);
+ vard = (pix_norm(pix, ppix, s->linesize)+128)>>8;
+#endif
- vard = vard >> 8;
- sum = sum >> 8;
- varc = (varc >> 8) - (sum * sum);
s->mb_var[s->mb_width * mb_y + mb_x] = varc;
- s->avg_mb_var += varc;
-
+ s->avg_mb_var+= varc;
+ s->mc_mb_var += vard;
+
#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 (vard <= 64 || vard < varc) {
- if (s->full_search != ME_ZERO) {
- halfpel_motion_search(s, &mx, &my, dmin, xmin, ymin, xmax, ymax);
- } else {
- mx -= 16 * s->mb_x;
- my -= 16 * s->mb_y;
+ if(s->flags&CODEC_FLAG_HQ){
+ if (vard*2 + 200 > varc)
+ mb_type|= MB_TYPE_INTRA;
+ if (varc*2 + 200 > vard){
+ mb_type|= MB_TYPE_INTER;
+ halfpel_motion_search(s, &mx, &my, dmin, xmin, ymin, xmax, ymax, pred_x, pred_y);
+ }else{
+ mx = mx*2 - mb_x*32;
+ my = my*2 - mb_y*32;
+ }
+ }else{
+ if (vard <= 64 || vard < varc) {
+ mb_type|= MB_TYPE_INTER;
+ if (s->full_search != ME_ZERO) {
+ halfpel_motion_search(s, &mx, &my, dmin, xmin, ymin, xmax, ymax, pred_x, pred_y);
+ } else {
+ mx -= 16 * mb_x;
+ my -= 16 * mb_y;
+ }
+ }else{
+ mb_type|= MB_TYPE_INTRA;
+ mx = 0;//mx*2 - 32 * mb_x;
+ my = 0;//my*2 - 32 * mb_y;
}
- *mx_ptr = mx;
- *my_ptr = my;
- return 0;
- } else {
- *mx_ptr = 0;
- *my_ptr = 0;
- return 1;
}
+
+ s->mb_type[mb_y*s->mb_width + mb_x]= mb_type;
+ set_mv_tables(s, mx, my);
}
#else