3 * Copyright (c) 2000,2001 Gerard Lantau.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "mpegvideo.h"
26 static void halfpel_motion_search(MpegEncContext * s,
27 int *mx_ptr, int *my_ptr, int dmin,
28 int xmin, int ymin, int xmax, int ymax);
30 /* config it to test motion vector encoding (send random vectors) */
31 //#define CONFIG_TEST_MV_ENCODE
33 static int pix_sum(UINT8 * pix, int line_size)
38 for (i = 0; i < 16; i++) {
39 for (j = 0; j < 16; j += 8) {
50 pix += line_size - 16;
55 static int pix_norm1(UINT8 * pix, int line_size)
58 UINT32 *sq = squareTbl + 256;
61 for (i = 0; i < 16; i++) {
62 for (j = 0; j < 16; j += 8) {
73 pix += line_size - 16;
78 static int pix_norm(UINT8 * pix1, UINT8 * pix2, int line_size)
81 UINT32 *sq = squareTbl + 256;
84 for (i = 0; i < 16; i++) {
85 for (j = 0; j < 16; j += 8) {
86 s += sq[pix1[0] - pix2[0]];
87 s += sq[pix1[1] - pix2[1]];
88 s += sq[pix1[2] - pix2[2]];
89 s += sq[pix1[3] - pix2[3]];
90 s += sq[pix1[4] - pix2[4]];
91 s += sq[pix1[5] - pix2[5]];
92 s += sq[pix1[6] - pix2[6]];
93 s += sq[pix1[7] - pix2[7]];
97 pix1 += line_size - 16;
98 pix2 += line_size - 16;
103 static void no_motion_search(MpegEncContext * s,
104 int *mx_ptr, int *my_ptr)
106 *mx_ptr = 16 * s->mb_x;
107 *my_ptr = 16 * s->mb_y;
110 static int full_motion_search(MpegEncContext * s,
111 int *mx_ptr, int *my_ptr, int range,
112 int xmin, int ymin, int xmax, int ymax)
114 int x1, y1, x2, y2, xx, yy, x, y;
120 x1 = xx - range + 1; /* we loose one pixel to avoid boundary pb with half pixel pred */
132 pix = s->new_picture[0] + (yy * s->linesize) + xx;
136 for (y = y1; y <= y2; y++) {
137 for (x = x1; x <= x2; x++) {
138 d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x,
142 (abs(x - xx) + abs(y - yy)) <
143 (abs(mx - xx) + abs(my - yy)))) {
155 if (*mx_ptr < -(2 * range) || *mx_ptr >= (2 * range) ||
156 *my_ptr < -(2 * range) || *my_ptr >= (2 * range)) {
157 fprintf(stderr, "error %d %d\n", *mx_ptr, *my_ptr);
164 static int log_motion_search(MpegEncContext * s,
165 int *mx_ptr, int *my_ptr, int range,
166 int xmin, int ymin, int xmax, int ymax)
168 int x1, y1, x2, y2, xx, yy, x, y;
195 pix = s->new_picture[0] + (yy * s->linesize) + xx;
201 for (y = y1; y <= y2; y += range) {
202 for (x = x1; x <= x2; x += range) {
203 d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize, 16);
204 if (d < dmin || (d == dmin && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
230 } while (range >= 1);
233 fprintf(stderr, "log - MX: %d\tMY: %d\n", mx, my);
240 static int phods_motion_search(MpegEncContext * s,
241 int *mx_ptr, int *my_ptr, int range,
242 int xmin, int ymin, int xmax, int ymax)
244 int x1, y1, x2, y2, xx, yy, x, y, lastx, d;
245 int mx, my, dminx, dminy;
271 pix = s->new_picture[0] + (yy * s->linesize) + xx;
282 for (x = x1; x <= x2; x += range) {
283 d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize, 16);
284 if (d < dminx || (d == dminx && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
291 for (y = y1; y <= y2; y += range) {
292 d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize, 16);
293 if (d < dminy || (d == dminy && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
319 } while (range >= 1);
322 fprintf(stderr, "phods - MX: %d\tMY: %d\n", mx, my);
325 /* half pixel search */
331 /* The idea would be to make half pel ME after Inter/Intra decision to
333 static void halfpel_motion_search(MpegEncContext * s,
334 int *mx_ptr, int *my_ptr, int dmin,
335 int xmin, int ymin, int xmax, int ymax)
337 int mx, my, mx1, my1, d, xx, yy, dminh;
348 /* Half pixel search */
352 pix = s->new_picture[0] + (yy * s->linesize) + xx;
354 if ((mx > (xmin << 1)) && mx < (xmax << 1) &&
355 (my > (ymin << 1)) && my < (ymax << 1)) {
358 for (dy = -1; dy <= 1; dy++) {
359 for (dx = -1; dx <= 1; dx++) {
360 if (dx != 0 || dy != 0) {
363 ptr = s->last_picture[0] + ((py >> 1) * s->linesize) + (px >> 1);
364 switch (((py & 1) << 1) | (px & 1)) {
367 d = pix_abs16x16(pix, ptr, s->linesize, 16);
370 d = pix_abs16x16_x2(pix, ptr, s->linesize, 16);
373 d = pix_abs16x16_y2(pix, ptr, s->linesize, 16);
376 d = pix_abs16x16_xy2(pix, ptr, s->linesize, 16);
389 *mx_ptr = mx - (xx << 1);
390 *my_ptr = my - (yy << 1);
391 //fprintf(stderr,"half - MX: %d\tMY: %d\n",*mx_ptr ,*my_ptr);
394 #ifndef CONFIG_TEST_MV_ENCODE
396 int estimate_motion(MpegEncContext * s,
398 int *mx_ptr, int *my_ptr)
401 int sum, varc, vard, mx, my, range, dmin, xx, yy;
402 int xmin, ymin, xmax, ymax;
404 range = 8 * (1 << (s->f_code - 1));
405 /* XXX: temporary kludge to avoid overflow for msmpeg4 */
406 if (s->out_format == FMT_H263 && !s->h263_msmpeg4)
409 if (s->unrestricted_mv) {
412 if(s->avctx==NULL || s->avctx->codec->id!=CODEC_ID_MPEG4){
413 xmax = s->mb_width*16;
414 ymax = s->mb_height*16;
416 /* XXX: dunno if this is correct but ffmpeg4 decoder wont like it otherwise
417 (cuz the drawn edge isnt large enough))*/
424 xmax = s->mb_width*16 - 16;
425 ymax = s->mb_height*16 - 16;
428 switch(s->full_search) {
431 no_motion_search(s, &mx, &my);
435 dmin = full_motion_search(s, &mx, &my, range, xmin, ymin, xmax, ymax);
438 dmin = log_motion_search(s, &mx, &my, range / 2, xmin, ymin, xmax, ymax);
441 dmin = phods_motion_search(s, &mx, &my, range / 2, xmin, ymin, xmax, ymax);
446 /* intra / predictive decision */
450 pix = s->new_picture[0] + (yy * s->linesize) + xx;
451 /* At this point (mx,my) are full-pell and the absolute displacement */
452 ppix = s->last_picture[0] + (my * s->linesize) + mx;
454 sum = pix_sum(pix, s->linesize);
455 varc = pix_norm1(pix, s->linesize);
456 vard = pix_norm(pix, ppix, s->linesize);
460 varc = (varc >> 8) - (sum * sum);
461 s->mb_var[s->mb_width * mb_y + mb_x] = varc;
462 s->avg_mb_var += varc;
465 printf("varc=%4d avg_var=%4d (sum=%4d) vard=%4d mx=%2d my=%2d\n",
466 varc, s->avg_mb_var, sum, vard, mx - xx, my - yy);
468 if (vard <= 64 || vard < varc) {
469 if (s->full_search != ME_ZERO) {
470 halfpel_motion_search(s, &mx, &my, dmin, xmin, ymin, xmax, ymax);
487 /* test version which generates valid random vectors */
488 int estimate_motion(MpegEncContext * s,
490 int *mx_ptr, int *my_ptr)
492 int xx, yy, x1, y1, x2, y2, range;
494 if ((random() % 10) >= 5) {
495 range = 8 * (1 << (s->f_code - 1));
496 if (s->out_format == FMT_H263 && !s->h263_msmpeg4)
505 if (x2 > (s->width - 16))
511 if (y2 > (s->height - 16))
514 *mx_ptr = (random() % (2 * (x2 - x1 + 1))) + 2 * (x1 - xx);
515 *my_ptr = (random() % (2 * (y2 - y1 + 1))) + 2 * (y1 - yy);