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
) {
417 xmax
= s
->width
- 16;
418 ymax
= s
->height
- 16;
421 switch(s
->full_search
) {
424 no_motion_search(s
, &mx
, &my
);
428 dmin
= full_motion_search(s
, &mx
, &my
, range
, xmin
, ymin
, xmax
, ymax
);
431 dmin
= log_motion_search(s
, &mx
, &my
, range
/ 2, xmin
, ymin
, xmax
, ymax
);
434 dmin
= phods_motion_search(s
, &mx
, &my
, range
/ 2, xmin
, ymin
, xmax
, ymax
);
438 if (mm_flags
& MM_MMX
)
442 /* intra / predictive decision */
446 pix
= s
->new_picture
[0] + (yy
* s
->linesize
) + xx
;
447 /* At this point (mx,my) are full-pell and the absolute displacement */
448 ppix
= s
->last_picture
[0] + (my
* s
->linesize
) + mx
;
450 sum
= pix_sum(pix
, s
->linesize
);
451 varc
= pix_norm1(pix
, s
->linesize
);
452 vard
= pix_norm(pix
, ppix
, s
->linesize
);
456 varc
= (varc
>> 8) - (sum
* sum
);
458 printf("varc=%d (sum=%d) vard=%d mx=%d my=%d\n",
459 varc
, sum
, vard
, mx
- xx
, my
- yy
);
461 if (vard
<= 64 || vard
< varc
) {
462 if (s
->full_search
!= ME_ZERO
) {
463 halfpel_motion_search(s
, &mx
, &my
, dmin
, xmin
, ymin
, xmax
, ymax
);
480 /* test version which generates valid random vectors */
481 int estimate_motion(MpegEncContext
* s
,
483 int *mx_ptr
, int *my_ptr
)
485 int xx
, yy
, x1
, y1
, x2
, y2
, range
;
487 if ((random() % 10) >= 5) {
488 range
= 8 * (1 << (s
->f_code
- 1));
489 if (s
->out_format
== FMT_H263
&& !s
->h263_msmpeg4
)
498 if (x2
> (s
->width
- 16))
504 if (y2
> (s
->height
- 16))
507 *mx_ptr
= (random() % (2 * (x2
- x1
+ 1))) + 2 * (x1
- xx
);
508 *my_ptr
= (random() % (2 * (y2
- y1
+ 1))) + 2 * (y1
- yy
);