comparison motion_est.c @ 327:d359db02fc90 libavcodec

much better ME for b frames (a bit slow though) fixed MC rounding for b frames fixed hq mode with b-frames
author michaelni
date Fri, 19 Apr 2002 03:25:20 +0000
parents 9c6f056f0e41
children ba9c3b8088c0
comparison
equal deleted inserted replaced
326:6ebb8680885d 327:d359db02fc90
27 27
28 #define ABS(a) ((a)>0 ? (a) : -(a)) 28 #define ABS(a) ((a)>0 ? (a) : -(a))
29 #define MAX(a,b) ((a) > (b) ? (a) : (b)) 29 #define MAX(a,b) ((a) > (b) ? (a) : (b))
30 #define INTER_BIAS 257 30 #define INTER_BIAS 257
31 31
32 static void halfpel_motion_search(MpegEncContext * s, 32 static int halfpel_motion_search(MpegEncContext * s,
33 int *mx_ptr, int *my_ptr, int dmin, 33 int *mx_ptr, int *my_ptr, int dmin,
34 int xmin, int ymin, int xmax, int ymax, 34 int xmin, int ymin, int xmax, int ymax,
35 int pred_x, int pred_y, uint8_t *ref_picture); 35 int pred_x, int pred_y, uint8_t *ref_picture);
36 36
37 static int pix_sum(UINT8 * pix, int line_size) 37 static int pix_sum(UINT8 * pix, int line_size)
671 my= my1 + y;\ 671 my= my1 + y;\
672 } 672 }
673 673
674 /* The idea would be to make half pel ME after Inter/Intra decision to 674 /* The idea would be to make half pel ME after Inter/Intra decision to
675 save time. */ 675 save time. */
676 static inline void halfpel_motion_search(MpegEncContext * s, 676 static inline int halfpel_motion_search(MpegEncContext * s,
677 int *mx_ptr, int *my_ptr, int dmin, 677 int *mx_ptr, int *my_ptr, int dmin,
678 int xmin, int ymin, int xmax, int ymax, 678 int xmin, int ymin, int xmax, int ymax,
679 int pred_x, int pred_y, uint8_t *ref_picture) 679 int pred_x, int pred_y, uint8_t *ref_picture)
680 { 680 {
681 UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame 681 UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame
700 mx= mx1= 2*(mx - xx); 700 mx= mx1= 2*(mx - xx);
701 my= my1= 2*(my - yy); 701 my= my1= 2*(my - yy);
702 if(dmin < Z_THRESHOLD && mx==0 && my==0){ 702 if(dmin < Z_THRESHOLD && mx==0 && my==0){
703 *mx_ptr = 0; 703 *mx_ptr = 0;
704 *my_ptr = 0; 704 *my_ptr = 0;
705 return; 705 return dmin;
706 } 706 }
707 707
708 pen_x= pred_x + mx; 708 pen_x= pred_x + mx;
709 pen_y= pred_y + my; 709 pen_y= pred_y + my;
710 710
725 my= 2*(my - yy); 725 my= 2*(my - yy);
726 } 726 }
727 727
728 *mx_ptr = mx; 728 *mx_ptr = mx;
729 *my_ptr = my; 729 *my_ptr = my;
730 return dminh;
730 } 731 }
731 732
732 static inline void halfpel_motion_search4(MpegEncContext * s, 733 static inline void halfpel_motion_search4(MpegEncContext * s,
733 int *mx_ptr, int *my_ptr, int dmin, 734 int *mx_ptr, int *my_ptr, int dmin,
734 int xmin, int ymin, int xmax, int ymax, 735 int xmin, int ymin, int xmax, int ymax,
1042 1043
1043 s->mb_type[mb_y*s->mb_width + mb_x]= mb_type; 1044 s->mb_type[mb_y*s->mb_width + mb_x]= mb_type;
1044 set_p_mv_tables(s, mx, my); 1045 set_p_mv_tables(s, mx, my);
1045 } 1046 }
1046 1047
1047 void ff_estimate_motion_b(MpegEncContext * s, 1048 int ff_estimate_motion_b(MpegEncContext * s,
1048 int mb_x, int mb_y, int16_t (*mv_table)[2], uint8_t *ref_picture, int f_code) 1049 int mb_x, int mb_y, int16_t (*mv_table)[2], uint8_t *ref_picture, int f_code)
1049 { 1050 {
1050 UINT8 *pix, *ppix; 1051 int mx, my, range, dmin;
1051 int sum, varc, vard, mx, my, range, dmin, xx, yy;
1052 int xmin, ymin, xmax, ymax; 1052 int xmin, ymin, xmax, ymax;
1053 int rel_xmin, rel_ymin, rel_xmax, rel_ymax; 1053 int rel_xmin, rel_ymin, rel_xmax, rel_ymax;
1054 int pred_x=0, pred_y=0; 1054 int pred_x=0, pred_y=0;
1055 int P[6][2]; 1055 int P[6][2];
1056 const int shift= 1+s->quarter_sample; 1056 const int shift= 1+s->quarter_sample;
1057 int mb_type=0;
1058 const int mot_stride = s->mb_width + 2; 1057 const int mot_stride = s->mb_width + 2;
1059 const int mot_xy = (mb_y + 1)*mot_stride + mb_x + 1; 1058 const int mot_xy = (mb_y + 1)*mot_stride + mb_x + 1;
1060 1059
1061 get_limits(s, &range, &xmin, &ymin, &xmax, &ymax, f_code); 1060 get_limits(s, &range, &xmin, &ymin, &xmax, &ymax, f_code);
1062 1061
1122 1121
1123 // pix = s->new_picture[0] + (yy * s->linesize) + xx; 1122 // pix = s->new_picture[0] + (yy * s->linesize) + xx;
1124 /* At this point (mx,my) are full-pell and the absolute displacement */ 1123 /* At this point (mx,my) are full-pell and the absolute displacement */
1125 // ppix = ref_picture + (my * s->linesize) + mx; 1124 // ppix = ref_picture + (my * s->linesize) + mx;
1126 1125
1127 halfpel_motion_search(s, &mx, &my, dmin, xmin, ymin, xmax, ymax, pred_x, pred_y, ref_picture); 1126 dmin= halfpel_motion_search(s, &mx, &my, dmin, xmin, ymin, xmax, ymax, pred_x, pred_y, ref_picture);
1128 1127
1129 // s->mb_type[mb_y*s->mb_width + mb_x]= mb_type; 1128 // s->mb_type[mb_y*s->mb_width + mb_x]= mb_type;
1130 mv_table[mot_xy][0]= mx; 1129 mv_table[mot_xy][0]= mx;
1131 mv_table[mot_xy][1]= my; 1130 mv_table[mot_xy][1]= my;
1132 } 1131 return dmin;
1133 1132 }
1134 1133
1135 int ff_decide_type(MpegEncContext * s, 1134
1136 int mb_x, int mb_y) 1135 static inline int check_bidir_mv(MpegEncContext * s,
1137 { 1136 int mb_x, int mb_y,
1138 1137 int motion_fx, int motion_fy,
1138 int motion_bx, int motion_by,
1139 int pred_fx, int pred_fy,
1140 int pred_bx, int pred_by)
1141 {
1142 //FIXME optimize?
1143 UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame
1144 uint8_t *dest_y = s->me_scratchpad;
1145 uint8_t *ptr;
1146 int dxy;
1147 int src_x, src_y;
1148 int fbmin;
1149
1150 fbmin = (mv_penalty[motion_fx-pred_fx] + mv_penalty[motion_fy-pred_fy])*s->qscale;
1151
1152 dxy = ((motion_fy & 1) << 1) | (motion_fx & 1);
1153 src_x = mb_x * 16 + (motion_fx >> 1);
1154 src_y = mb_y * 16 + (motion_fy >> 1);
1155
1156 ptr = s->last_picture[0] + (src_y * s->linesize) + src_x;
1157 put_pixels_tab[dxy](dest_y , ptr , s->linesize, 16);
1158 put_pixels_tab[dxy](dest_y + 8, ptr + 8, s->linesize, 16);
1159
1160 fbmin += (mv_penalty[motion_bx-pred_bx] + mv_penalty[motion_by-pred_by])*s->qscale;
1161
1162 dxy = ((motion_by & 1) << 1) | (motion_bx & 1);
1163 src_x = mb_x * 16 + (motion_bx >> 1);
1164 src_y = mb_y * 16 + (motion_by >> 1);
1165
1166 ptr = s->next_picture[0] + (src_y * s->linesize) + src_x;
1167 avg_pixels_tab[dxy](dest_y , ptr , s->linesize, 16);
1168 avg_pixels_tab[dxy](dest_y + 8, ptr + 8, s->linesize, 16);
1169
1170 fbmin += pix_abs16x16(s->new_picture[0] + mb_x*16 + mb_y*16*s->linesize, dest_y, s->linesize);
1171 return fbmin;
1172 }
1173
1174 /* refine the bidir vectors in hq mode and return the score in both lq & hq mode*/
1175 static inline int bidir_refine(MpegEncContext * s,
1176 int mb_x, int mb_y)
1177 {
1178 const int mot_stride = s->mb_width + 2;
1179 const int xy = (mb_y + 1)*mot_stride + mb_x + 1;
1180 int fbmin;
1181 int pred_fx= s->b_bidir_forw_mv_table[xy-1][0];
1182 int pred_fy= s->b_bidir_forw_mv_table[xy-1][1];
1183 int pred_bx= s->b_bidir_back_mv_table[xy-1][0];
1184 int pred_by= s->b_bidir_back_mv_table[xy-1][1];
1185 int motion_fx= s->b_bidir_forw_mv_table[xy][0]= s->b_forw_mv_table[xy][0];
1186 int motion_fy= s->b_bidir_forw_mv_table[xy][1]= s->b_forw_mv_table[xy][1];
1187 int motion_bx= s->b_bidir_back_mv_table[xy][0]= s->b_back_mv_table[xy][0];
1188 int motion_by= s->b_bidir_back_mv_table[xy][1]= s->b_back_mv_table[xy][1];
1189
1190 //FIXME do refinement and add flag
1191
1192 fbmin= check_bidir_mv(s, mb_x, mb_y,
1193 motion_fx, motion_fy,
1194 motion_bx, motion_by,
1195 pred_fx, pred_fy,
1196 pred_bx, pred_by);
1197
1198 return fbmin;
1199 }
1200
1201 static inline int direct_search(MpegEncContext * s,
1202 int mb_x, int mb_y)
1203 {
1204 int P[6][2];
1205 const int mot_stride = s->mb_width + 2;
1206 const int mot_xy = (mb_y + 1)*mot_stride + mb_x + 1;
1207 int dmin, dmin2;
1208 int motion_fx, motion_fy, motion_bx, motion_by, motion_bx0, motion_by0;
1209 int motion_dx, motion_dy;
1210 const int motion_px= s->p_mv_table[mot_xy][0];
1211 const int motion_py= s->p_mv_table[mot_xy][1];
1212 const int time_pp= s->pp_time;
1213 const int time_bp= s->bp_time;
1214 const int time_pb= time_pp - time_bp;
1215 int bx, by;
1216 int mx, my, mx2, my2;
1217 uint8_t *ref_picture= s->me_scratchpad - (mb_x + 1 + (mb_y + 1)*s->linesize)*16;
1218 int16_t (*mv_table)[2]= s->b_direct_mv_table;
1219 uint16_t *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame
1220
1221 /* thanks to iso-mpeg the rounding is different for the zero vector, so we need to handle that ... */
1222 motion_fx= (motion_px*time_pb)/time_pp;
1223 motion_fy= (motion_py*time_pb)/time_pp;
1224 motion_bx0= (-motion_px*time_bp)/time_pp;
1225 motion_by0= (-motion_py*time_bp)/time_pp;
1226 motion_dx= motion_dy=0;
1227 dmin2= check_bidir_mv(s, mb_x, mb_y,
1228 motion_fx, motion_fy,
1229 motion_bx0, motion_by0,
1230 motion_fx, motion_fy,
1231 motion_bx0, motion_by0) - s->qscale;
1232
1233 motion_bx= motion_fx - motion_px;
1234 motion_by= motion_fy - motion_py;
1235 for(by=-1; by<2; by++){
1236 for(bx=-1; bx<2; bx++){
1237 uint8_t *dest_y = s->me_scratchpad + (by+1)*s->linesize*16 + (bx+1)*16;
1238 uint8_t *ptr;
1239 int dxy;
1240 int src_x, src_y;
1241 const int width= s->width;
1242 const int height= s->height;
1243
1244 dxy = ((motion_fy & 1) << 1) | (motion_fx & 1);
1245 src_x = (mb_x + bx) * 16 + (motion_fx >> 1);
1246 src_y = (mb_y + by) * 16 + (motion_fy >> 1);
1247 src_x = clip(src_x, -16, width);
1248 if (src_x == width) dxy &= ~1;
1249 src_y = clip(src_y, -16, height);
1250 if (src_y == height) dxy &= ~2;
1251
1252 ptr = s->last_picture[0] + (src_y * s->linesize) + src_x;
1253 put_pixels_tab[dxy](dest_y , ptr , s->linesize, 16);
1254 put_pixels_tab[dxy](dest_y + 8, ptr + 8, s->linesize, 16);
1255
1256 dxy = ((motion_by & 1) << 1) | (motion_bx & 1);
1257 src_x = (mb_x + bx) * 16 + (motion_bx >> 1);
1258 src_y = (mb_y + by) * 16 + (motion_by >> 1);
1259 src_x = clip(src_x, -16, width);
1260 if (src_x == width) dxy &= ~1;
1261 src_y = clip(src_y, -16, height);
1262 if (src_y == height) dxy &= ~2;
1263
1264 avg_pixels_tab[dxy](dest_y , ptr , s->linesize, 16);
1265 avg_pixels_tab[dxy](dest_y + 8, ptr + 8, s->linesize, 16);
1266 }
1267 }
1268
1269 P[0][0] = mv_table[mot_xy ][0];
1270 P[0][1] = mv_table[mot_xy ][1];
1271 P[1][0] = mv_table[mot_xy - 1][0];
1272 P[1][1] = mv_table[mot_xy - 1][1];
1273
1274 /* special case for first line */
1275 if ((mb_y == 0 || s->first_slice_line || s->first_gob_line)) {
1276 P[4][0] = P[1][0];
1277 P[4][1] = P[1][1];
1278 } else {
1279 P[2][0] = mv_table[mot_xy - mot_stride ][0];
1280 P[2][1] = mv_table[mot_xy - mot_stride ][1];
1281 P[3][0] = mv_table[mot_xy - mot_stride + 1 ][0];
1282 P[3][1] = mv_table[mot_xy - mot_stride + 1 ][1];
1283
1284 P[4][0]= mid_pred(P[1][0], P[2][0], P[3][0]);
1285 P[4][1]= mid_pred(P[1][1], P[2][1], P[3][1]);
1286 }
1287 dmin = epzs_motion_search(s, &mx, &my, P, 0, 0, -16, -16, 15, 15, ref_picture);
1288 if(mx==0 && my==0) dmin=99999999; // not representable, due to rounding stuff
1289 if(dmin2<dmin){
1290 dmin= dmin2;
1291 mx=0;
1292 my=0;
1293 }
1294 #if 1
1295 mx2= mx= mx*2;
1296 my2= my= my*2;
1297 for(by=-1; by<2; by++){
1298 if(my2+by < -32) continue;
1299 for(bx=-1; bx<2; bx++){
1300 if(bx==0 && by==0) continue;
1301 if(mx2+bx < -32) continue;
1302 dmin2= check_bidir_mv(s, mb_x, mb_y,
1303 mx2+bx+motion_fx, my2+by+motion_fy,
1304 mx2+bx+motion_bx, my2+by+motion_by,
1305 mx2+bx+motion_fx, my2+by+motion_fy,
1306 motion_bx, motion_by) - s->qscale;
1307
1308 if(dmin2<dmin){
1309 dmin=dmin2;
1310 mx= mx2 + bx;
1311 my= my2 + by;
1312 }
1313 }
1314 }
1315 #else
1316 mx*=2; my*=2;
1317 #endif
1318 if(mx==0 && my==0){
1319 motion_bx= motion_bx0;
1320 motion_by= motion_by0;
1321 }
1322
1323 s->b_direct_mv_table[mot_xy][0]= mx;
1324 s->b_direct_mv_table[mot_xy][1]= my;
1325 s->b_direct_forw_mv_table[mot_xy][0]= motion_fx + mx;
1326 s->b_direct_forw_mv_table[mot_xy][1]= motion_fy + my;
1327 s->b_direct_back_mv_table[mot_xy][0]= motion_bx + mx;
1328 s->b_direct_back_mv_table[mot_xy][1]= motion_by + my;
1329 return dmin;
1139 } 1330 }
1140 1331
1141 void ff_estimate_b_frame_motion(MpegEncContext * s, 1332 void ff_estimate_b_frame_motion(MpegEncContext * s,
1142 int mb_x, int mb_y) 1333 int mb_x, int mb_y)
1143 { 1334 {
1144 const int mot_stride = s->mb_width + 2; 1335 const int mot_stride = s->mb_width + 2;
1145 const int xy = (mb_y + 1)*mot_stride + mb_x + 1; 1336 const int xy = (mb_y + 1)*mot_stride + mb_x + 1;
1146 1337 const int quant= s->qscale;
1147 ff_estimate_motion_b(s, mb_x, mb_y, s->b_forw_mv_table, s->last_picture[0], s->f_code); 1338 int fmin, bmin, dmin, fbmin;
1148 ff_estimate_motion_b(s, mb_x, mb_y, s->b_back_mv_table, s->next_picture[0], s->b_code); 1339 int type=0;
1340 int motion_fx, motion_fy, motion_bx, motion_by;
1341
1342 dmin= direct_search(s, mb_x, mb_y);
1343
1344 fmin= ff_estimate_motion_b(s, mb_x, mb_y, s->b_forw_mv_table, s->last_picture[0], s->f_code);
1345 bmin= ff_estimate_motion_b(s, mb_x, mb_y, s->b_back_mv_table, s->next_picture[0], s->b_code) - quant;
1149 //printf(" %d %d ", s->b_forw_mv_table[xy][0], s->b_forw_mv_table[xy][1]); 1346 //printf(" %d %d ", s->b_forw_mv_table[xy][0], s->b_forw_mv_table[xy][1]);
1150 s->b_bidir_forw_mv_table[xy][0]= s->b_forw_mv_table[xy][0]; 1347
1151 s->b_bidir_forw_mv_table[xy][1]= s->b_forw_mv_table[xy][1]; 1348 fbmin= bidir_refine(s, mb_x, mb_y);
1152 s->b_bidir_back_mv_table[xy][0]= s->b_back_mv_table[xy][0]; 1349
1153 s->b_bidir_back_mv_table[xy][1]= s->b_back_mv_table[xy][1]; 1350 if(s->flags&CODEC_FLAG_HQ){
1154 1351 type= MB_TYPE_FORWARD | MB_TYPE_BACKWARD | MB_TYPE_BIDIR | MB_TYPE_DIRECT;
1155 s->mb_type[mb_y*s->mb_width + mb_x]= MB_TYPE_FORWARD; //FIXME 1352 }else{
1353 int score= dmin;
1354 type=MB_TYPE_DIRECT;
1355
1356 if(fmin<score){
1357 score=fmin;
1358 type= MB_TYPE_FORWARD;
1359 }
1360 if(bmin<score){
1361 score=bmin;
1362 type= MB_TYPE_BACKWARD;
1363 }
1364 if(fbmin<score){
1365 score=fbmin;
1366 type= MB_TYPE_BIDIR;
1367 }
1368 s->mc_mb_var += score;
1369 }
1370
1371 s->mb_type[mb_y*s->mb_width + mb_x]= type;
1156 } 1372 }
1157 1373
1158 /* find best f_code for ME which do unlimited searches */ 1374 /* find best f_code for ME which do unlimited searches */
1159 int ff_get_best_fcode(MpegEncContext * s, int16_t (*mv_table)[2], int type) 1375 int ff_get_best_fcode(MpegEncContext * s, int16_t (*mv_table)[2], int type)
1160 { 1376 {
1182 xy++; 1398 xy++;
1183 } 1399 }
1184 } 1400 }
1185 1401
1186 for(i=MAX_FCODE; i>1; i--){ 1402 for(i=MAX_FCODE; i>1; i--){
1403 int threshold;
1187 loose+= mv_num[i]; 1404 loose+= mv_num[i];
1188 if(loose > s->mb_num/20) break; //FIXME this is pretty ineffective 1405
1406 if(s->pict_type==B_TYPE) threshold= 0;
1407 else threshold= s->mb_num/20; //FIXME
1408 if(loose > threshold) break;
1189 } 1409 }
1190 // printf("fcode: %d type: %d\n", i, s->pict_type); 1410 // printf("fcode: %d type: %d\n", i, s->pict_type);
1191 return i; 1411 return i;
1192 /* for(i=0; i<=MAX_FCODE; i++){ 1412 /* for(i=0; i<=MAX_FCODE; i++){
1193 printf("%d ", mv_num[i]); 1413 printf("%d ", mv_num[i]);
1273 if(s->mb_type[i]&type){ 1493 if(s->mb_type[i]&type){
1274 if( fcode_tab[mv_table[xy][0] + MAX_MV] > f_code 1494 if( fcode_tab[mv_table[xy][0] + MAX_MV] > f_code
1275 || fcode_tab[mv_table[xy][0] + MAX_MV] == 0 1495 || fcode_tab[mv_table[xy][0] + MAX_MV] == 0
1276 || fcode_tab[mv_table[xy][1] + MAX_MV] > f_code 1496 || fcode_tab[mv_table[xy][1] + MAX_MV] > f_code
1277 || fcode_tab[mv_table[xy][1] + MAX_MV] == 0 ){ 1497 || fcode_tab[mv_table[xy][1] + MAX_MV] == 0 ){
1278 s->mb_type[i] &= ~type; 1498 if(s->mb_type[i]&(~type)) s->mb_type[i] &= ~type;
1279 if(s->mb_type[i]==0) s->mb_type[i]= MB_TYPE_FORWARD; //FIXME 1499 else{
1280 mv_table[xy][0] = 0; 1500 mv_table[xy][0] = 0;
1281 mv_table[xy][1] = 0; 1501 mv_table[xy][1] = 0;
1282 //this is certainly bad FIXME 1502 //this is certainly bad FIXME
1503 }
1283 } 1504 }
1284 } 1505 }
1285 xy++; 1506 xy++;
1286 i++; 1507 i++;
1287 } 1508 }