Mercurial > libavcodec.hg
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 } |