1 |
/************************************************************************** |
/***************************************************************************** |
2 |
* |
* |
3 |
* XVID MPEG-4 VIDEO CODEC |
* XVID MPEG-4 VIDEO CODEC |
4 |
* motion estimation |
* - Motion Estimation module - |
5 |
* |
* |
6 |
* This program is an implementation of a part of one or more MPEG-4 |
* Copyright(C) 2002 Christoph Lampert <gruel@web.de> |
7 |
* Video tools as specified in ISO/IEC 14496-2 standard. Those intending |
* 2002 Michael Militzer <michael@xvid.org> |
|
* to use this software module in hardware or software products are |
|
|
* advised that its use may infringe existing patents or copyrights, and |
|
|
* any such use would be at such party's own risk. The original |
|
|
* developer of this software module and his/her company, and subsequent |
|
|
* editors and their companies, will have no liability for use of this |
|
|
* software or modifications or derivatives thereof. |
|
8 |
* |
* |
9 |
* This program is free software; you can redistribute it and/or modify |
* This file is part of XviD, a free MPEG-4 video encoder/decoder |
10 |
* it under the terms of the GNU General Public License as published by |
* |
11 |
|
* XviD is free software; you can redistribute it and/or modify it |
12 |
|
* under the terms of the GNU General Public License as published by |
13 |
* the Free Software Foundation; either version 2 of the License, or |
* the Free Software Foundation; either version 2 of the License, or |
14 |
* (at your option) any later version. |
* (at your option) any later version. |
15 |
* |
* |
20 |
* |
* |
21 |
* You should have received a copy of the GNU General Public License |
* You should have received a copy of the GNU General Public License |
22 |
* along with this program; if not, write to the Free Software |
* along with this program; if not, write to the Free Software |
23 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
24 |
* |
* |
25 |
*************************************************************************/ |
* Under section 8 of the GNU General Public License, the copyright |
26 |
|
* holders of XVID explicitly forbid distribution in the following |
27 |
/************************************************************************** |
* countries: |
28 |
|
* |
29 |
|
* - Japan |
30 |
|
* - United States of America |
31 |
* |
* |
32 |
* Modifications: |
* Linking XviD statically or dynamically with other modules is making a |
33 |
|
* combined work based on XviD. Thus, the terms and conditions of the |
34 |
|
* GNU General Public License cover the whole combination. |
35 |
* |
* |
36 |
* 01.05.2002 updated MotionEstimationBVOP |
* As a special exception, the copyright holders of XviD give you |
37 |
* 25.04.2002 partial prevMB conversion |
* permission to link XviD with independent modules that communicate with |
38 |
* 22.04.2002 remove some compile warning by chenm001 <chenm001@163.com> |
* XviD solely through the VFW1.1 and DShow interfaces, regardless of the |
39 |
* 14.04.2002 added MotionEstimationBVOP() |
* license terms of these independent modules, and to copy and distribute |
40 |
* 02.04.2002 add EPZS(^2) as ME algorithm, use PMV_USESQUARES to choose between |
* the resulting combined work under terms of your choice, provided that |
41 |
* EPZS and EPZS^2 |
* every copy of the combined work is accompanied by a complete copy of |
42 |
* 08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop |
* the source code of XviD (the version of XviD used to produce the |
43 |
* PMVFast_Refine to support multiple searches with different start points |
* combined work), being distributed under the terms of the GNU General |
44 |
* 07.01.2002 uv-block-based interpolation |
* Public License plus this exception. An independent module is a module |
45 |
* 06.01.2002 INTER/INTRA-decision is now done before any SEARCH8 (speedup) |
* which is not derived from or based on XviD. |
|
* changed INTER_BIAS to 150 (as suggested by suxen_drol) |
|
|
* removed halfpel refinement step in PMVfastSearch8 + quality=5 |
|
|
* added new quality mode = 6 which performs halfpel refinement |
|
|
* filesize difference between quality 5 and 6 is smaller than 1% |
|
|
* (Isibaar) |
|
|
* 31.12.2001 PMVfastSearch16 and PMVfastSearch8 (gruel) |
|
|
* 30.12.2001 get_range/MotionSearchX simplified; blue/green bug fix |
|
|
* 22.12.2001 commented best_point==99 check |
|
|
* 19.12.2001 modified get_range (purple bug fix) |
|
|
* 15.12.2001 moved pmv displacement from mbprediction |
|
|
* 02.12.2001 motion estimation/compensation split (Isibaar) |
|
|
* 16.11.2001 rewrote/tweaked search algorithms; pross@cs.rmit.edu.au |
|
|
* 10.11.2001 support for sad16/sad8 functions |
|
|
* 28.08.2001 reactivated MODE_INTER4V for EXT_MODE |
|
|
* 24.08.2001 removed MODE_INTER4V_Q, disabled MODE_INTER4V for EXT_MODE |
|
|
* 22.08.2001 added MODE_INTER4V_Q |
|
|
* 20.08.2001 added pragma to get rid of internal compiler error with VC6 |
|
|
* idea by Cyril. Thanks. |
|
46 |
* |
* |
47 |
* Michael Militzer <isibaar@videocoding.de> |
* Note that people who make modified versions of XviD are not obligated |
48 |
|
* to grant this special exception for their modified versions; it is |
49 |
|
* their choice whether to do so. The GNU General Public License gives |
50 |
|
* permission to release a modified version without this exception; this |
51 |
|
* exception also makes it possible to release a modified version which |
52 |
|
* carries forward this exception. |
53 |
* |
* |
54 |
**************************************************************************/ |
* $Id: motion_est.c,v 1.53 2002-11-17 00:32:06 edgomez Exp $ |
55 |
|
* |
56 |
|
*************************************************************************/ |
57 |
|
|
58 |
#include <assert.h> |
#include <assert.h> |
59 |
#include <stdio.h> |
#include <stdio.h> |
164 |
static const VECTOR zeroMV = { 0, 0 }; |
static const VECTOR zeroMV = { 0, 0 }; |
165 |
VECTOR predMV; |
VECTOR predMV; |
166 |
|
|
167 |
int32_t x, y; |
uint32_t x, y; |
168 |
int32_t iIntra = 0; |
uint32_t iIntra = 0; |
169 |
VECTOR pmv; |
VECTOR pmv; |
170 |
|
|
171 |
if (sadInit) |
if (sadInit) |
379 |
{ iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \ |
{ iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \ |
380 |
} |
} |
381 |
|
|
382 |
|
#if 0 |
383 |
/* too slow and not fully functional at the moment */ |
/* too slow and not fully functional at the moment */ |
|
/* |
|
384 |
int32_t ZeroSearch16( |
int32_t ZeroSearch16( |
385 |
const uint8_t * const pRef, |
const uint8_t * const pRef, |
386 |
const uint8_t * const pRefH, |
const uint8_t * const pRefH, |
419 |
return iSAD; |
return iSAD; |
420 |
|
|
421 |
} |
} |
422 |
*/ |
#endif /* 0 */ |
423 |
|
|
424 |
int32_t |
int32_t |
425 |
Diamond16_MainSearch(const uint8_t * const pRef, |
Diamond16_MainSearch(const uint8_t * const pRef, |
448 |
/* Do a diamond search around given starting point, return SAD of best */ |
/* Do a diamond search around given starting point, return SAD of best */ |
449 |
|
|
450 |
int32_t iDirection = 0; |
int32_t iDirection = 0; |
451 |
|
int32_t iDirectionBackup; |
452 |
int32_t iSAD; |
int32_t iSAD; |
453 |
VECTOR backupMV; |
VECTOR backupMV; |
454 |
|
|
462 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3); |
CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3); |
463 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4); |
CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4); |
464 |
|
|
465 |
if (iDirection) |
if (iDirection) { |
466 |
while (!iFound) { |
while (!iFound) { |
467 |
iFound = 1; |
iFound = 1; |
468 |
backupMV = *currMV; |
backupMV = *currMV; |
469 |
|
iDirectionBackup = iDirection; |
470 |
|
|
471 |
if (iDirection != 2) |
if (iDirectionBackup != 2) |
472 |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
473 |
backupMV.y, 1); |
backupMV.y, 1); |
474 |
if (iDirection != 1) |
if (iDirectionBackup != 1) |
475 |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
476 |
backupMV.y, 2); |
backupMV.y, 2); |
477 |
if (iDirection != 4) |
if (iDirectionBackup != 4) |
478 |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x, |
479 |
backupMV.y - iDiamondSize, 3); |
backupMV.y - iDiamondSize, 3); |
480 |
if (iDirection != 3) |
if (iDirectionBackup != 3) |
481 |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x, |
482 |
backupMV.y + iDiamondSize, 4); |
backupMV.y + iDiamondSize, 4); |
483 |
|
} |
484 |
} else { |
} else { |
485 |
currMV->x = start_x; |
currMV->x = start_x; |
486 |
currMV->y = start_y; |
currMV->y = start_y; |
544 |
backupMV.y + iDiamondSize, 8); |
backupMV.y + iDiamondSize, 8); |
545 |
|
|
546 |
|
|
547 |
if (iDirection) |
if (iDirection) { |
548 |
while (!iFound) { |
while (!iFound) { |
549 |
iFound = 1; |
iFound = 1; |
550 |
backupMV = *currMV; |
backupMV = *currMV; |
553 |
case 1: |
case 1: |
554 |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
555 |
backupMV.y, 1); |
backupMV.y, 1); |
556 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
557 |
backupMV.y - iDiamondSize, 5); |
backupMV.y - iDiamondSize, 5); |
558 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
559 |
backupMV.y - iDiamondSize, 7); |
backupMV.y - iDiamondSize, 7); |
560 |
break; |
break; |
561 |
case 2: |
case 2: |
562 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y, |
563 |
2); |
2); |
564 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
565 |
backupMV.y + iDiamondSize, 6); |
backupMV.y + iDiamondSize, 6); |
566 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
567 |
backupMV.y + iDiamondSize, 8); |
backupMV.y + iDiamondSize, 8); |
568 |
break; |
break; |
569 |
|
|
570 |
case 3: |
case 3: |
571 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize, |
572 |
4); |
4); |
573 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
574 |
backupMV.y - iDiamondSize, 7); |
backupMV.y - iDiamondSize, 7); |
575 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
576 |
backupMV.y + iDiamondSize, 8); |
backupMV.y + iDiamondSize, 8); |
577 |
break; |
break; |
578 |
|
|
579 |
case 4: |
case 4: |
580 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize, |
581 |
3); |
3); |
582 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
583 |
backupMV.y - iDiamondSize, 5); |
backupMV.y - iDiamondSize, 5); |
584 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
585 |
backupMV.y + iDiamondSize, 6); |
backupMV.y + iDiamondSize, 6); |
586 |
break; |
break; |
587 |
|
|
588 |
case 5: |
case 5: |
589 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y, |
590 |
1); |
1); |
591 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize, |
592 |
3); |
3); |
593 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
594 |
backupMV.y - iDiamondSize, 5); |
backupMV.y - iDiamondSize, 5); |
595 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
596 |
backupMV.y + iDiamondSize, 6); |
backupMV.y + iDiamondSize, 6); |
597 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
598 |
backupMV.y - iDiamondSize, 7); |
backupMV.y - iDiamondSize, 7); |
599 |
break; |
break; |
600 |
|
|
601 |
case 6: |
case 6: |
602 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y, |
603 |
2); |
2); |
604 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize, |
605 |
3); |
3); |
606 |
|
|
607 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
608 |
backupMV.y - iDiamondSize, 5); |
backupMV.y - iDiamondSize, 5); |
609 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
610 |
backupMV.y + iDiamondSize, 6); |
backupMV.y + iDiamondSize, 6); |
611 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
612 |
backupMV.y + iDiamondSize, 8); |
backupMV.y + iDiamondSize, 8); |
613 |
|
|
614 |
break; |
break; |
616 |
case 7: |
case 7: |
617 |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
618 |
backupMV.y, 1); |
backupMV.y, 1); |
619 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize, |
620 |
4); |
4); |
621 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
622 |
backupMV.y - iDiamondSize, 5); |
backupMV.y - iDiamondSize, 5); |
623 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
624 |
backupMV.y - iDiamondSize, 7); |
backupMV.y - iDiamondSize, 7); |
625 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
626 |
backupMV.y + iDiamondSize, 8); |
backupMV.y + iDiamondSize, 8); |
627 |
break; |
break; |
628 |
|
|
629 |
case 8: |
case 8: |
630 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y, |
631 |
2); |
2); |
632 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize, |
633 |
4); |
4); |
634 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
635 |
backupMV.y + iDiamondSize, 6); |
backupMV.y + iDiamondSize, 6); |
636 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
637 |
backupMV.y - iDiamondSize, 7); |
backupMV.y - iDiamondSize, 7); |
638 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
639 |
backupMV.y + iDiamondSize, 8); |
backupMV.y + iDiamondSize, 8); |
640 |
break; |
break; |
641 |
default: |
default: |
642 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y, |
643 |
1); |
1); |
644 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y, |
645 |
2); |
2); |
646 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize, |
647 |
3); |
3); |
648 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize, |
649 |
4); |
4); |
650 |
|
|
651 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
652 |
backupMV.y - iDiamondSize, 5); |
backupMV.y - iDiamondSize, 5); |
653 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
654 |
backupMV.y + iDiamondSize, 6); |
backupMV.y + iDiamondSize, 6); |
655 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
656 |
backupMV.y - iDiamondSize, 7); |
backupMV.y - iDiamondSize, 7); |
657 |
CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, |
CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
658 |
backupMV.y + iDiamondSize, 8); |
backupMV.y + iDiamondSize, 8); |
659 |
break; |
break; |
660 |
} |
} |
661 |
|
} |
662 |
} else { |
} else { |
663 |
currMV->x = start_x; |
currMV->x = start_x; |
664 |
currMV->y = start_y; |
currMV->y = start_y; |
713 |
const uint8_t * const cur, |
const uint8_t * const cur, |
714 |
const int x, |
const int x, |
715 |
const int y, |
const int y, |
716 |
int start_x, |
const int start_xi, |
717 |
int start_y, |
const int start_yi, |
718 |
int iMinSAD, |
int iMinSAD, |
719 |
VECTOR * const currMV, |
VECTOR * const currMV, |
720 |
const int center_x, |
const int center_x, |
731 |
{ |
{ |
732 |
|
|
733 |
int32_t iSAD; |
int32_t iSAD; |
734 |
|
int start_x = start_xi, start_y = start_yi; |
735 |
|
|
736 |
/* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */ |
/* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */ |
737 |
|
|
862 |
} |
} |
863 |
while (1); //forever |
while (1); //forever |
864 |
} |
} |
|
return iMinSAD; |
|
|
} |
|
|
|
|
|
|
|
|
#define CHECK_MV16_F_INTERPOL(X,Y,BX,BY) { \ |
|
|
if ( ((X) <= max_dx) && ((X) >= min_dx) \ |
|
|
&& ((Y) <= max_dy) && ((Y) >= min_dy) ) \ |
|
|
{ \ |
|
|
iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \ |
|
|
iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\ |
|
|
if (iSAD < iMinSAD) \ |
|
|
{ iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \ |
|
|
} |
|
|
|
|
|
#define CHECK_MV16_F_INTERPOL_DIR(X,Y,BX,BY,D) { \ |
|
|
if ( ((X) <= max_dx) && ((X) >= min_dx) \ |
|
|
&& ((Y) <= max_dy) && ((Y) >= min_dy) ) \ |
|
|
{ \ |
|
|
iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \ |
|
|
iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\ |
|
|
if (iSAD < iMinSAD) \ |
|
|
{ iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \ |
|
|
} |
|
|
|
|
|
#define CHECK_MV16_F_INTERPOL_FOUND(X,Y,BX,BY,D) { \ |
|
|
if ( ((X) <= max_dx) && ((X) >= min_dx) \ |
|
|
&& ((Y) <= max_dy) && ((Y) >= min_dy) ) \ |
|
|
{ \ |
|
|
iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \ |
|
|
iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\ |
|
|
if (iSAD < iMinSAD) \ |
|
|
{ iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \ |
|
|
} |
|
|
|
|
|
|
|
|
#define CHECK_MV16_B_INTERPOL(FX,FY,X,Y) { \ |
|
|
if ( ((X) <= max_dx) && ((X) >= min_dx) \ |
|
|
&& ((Y) <= max_dy) && ((Y) >= min_dy) ) \ |
|
|
{ \ |
|
|
iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \ |
|
|
iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\ |
|
|
if (iSAD < iMinSAD) \ |
|
|
{ iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \ |
|
|
} |
|
|
|
|
|
|
|
|
#define CHECK_MV16_B_INTERPOL_DIR(FX,FY,X,Y,D) { \ |
|
|
if ( ((X) <= max_dx) && ((X) >= min_dx) \ |
|
|
&& ((Y) <= max_dy) && ((Y) >= min_dy) ) \ |
|
|
{ \ |
|
|
iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \ |
|
|
iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\ |
|
|
if (iSAD < iMinSAD) \ |
|
|
{ iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \ |
|
|
} |
|
|
|
|
|
|
|
|
#define CHECK_MV16_B_INTERPOL_FOUND(FX,FY,X,Y,D) { \ |
|
|
if ( ((X) <= max_dx) && ((X) >= min_dx) \ |
|
|
&& ((Y) <= max_dy) && ((Y) >= min_dy) ) \ |
|
|
{ \ |
|
|
iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \ |
|
|
iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\ |
|
|
if (iSAD < iMinSAD) \ |
|
|
{ iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \ |
|
|
} |
|
|
|
|
|
|
|
|
#if (0==1) |
|
|
int32_t |
|
|
Diamond16_InterpolMainSearch( |
|
|
const uint8_t * const f_pRef, |
|
|
const uint8_t * const f_pRefH, |
|
|
const uint8_t * const f_pRefV, |
|
|
const uint8_t * const f_pRefHV, |
|
|
const uint8_t * const cur, |
|
|
|
|
|
const uint8_t * const b_pRef, |
|
|
const uint8_t * const b_pRefH, |
|
|
const uint8_t * const b_pRefV, |
|
|
const uint8_t * const b_pRefHV, |
|
|
|
|
|
const int x, |
|
|
const int y, |
|
865 |
|
|
|
const int f_start_x, |
|
|
const int f_start_y, |
|
|
const int b_start_x, |
|
|
const int b_start_y, |
|
|
|
|
|
int iMinSAD, |
|
|
VECTOR * const f_currMV, |
|
|
VECTOR * const b_currMV, |
|
|
|
|
|
const int f_center_x, |
|
|
const int f_center_y, |
|
|
const int b_center_x, |
|
|
const int b_center_y, |
|
|
|
|
|
const int32_t min_dx, |
|
|
const int32_t max_dx, |
|
|
const int32_t min_dy, |
|
|
const int32_t max_dy, |
|
|
const int32_t iEdgedWidth, |
|
|
const int32_t iDiamondSize, |
|
|
|
|
|
const int32_t f_iFcode, |
|
|
const int32_t b_iFcode, |
|
|
|
|
|
const int32_t iQuant, |
|
|
int iFound) |
|
|
{ |
|
|
/* Do a diamond search around given starting point, return SAD of best */ |
|
|
|
|
|
int32_t f_iDirection = 0; |
|
|
int32_t b_iDirection = 0; |
|
|
int32_t iSAD; |
|
|
|
|
|
VECTOR f_backupMV; |
|
|
VECTOR b_backupMV; |
|
|
|
|
|
f_backupMV.x = start_x; |
|
|
f_backupMV.y = start_y; |
|
|
b_backupMV.x = start_x; |
|
|
b_backupMV.y = start_y; |
|
|
|
|
|
/* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */ |
|
|
|
|
|
CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1); |
|
|
CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2); |
|
|
CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3); |
|
|
CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4); |
|
|
|
|
|
if (iDirection) |
|
|
while (!iFound) { |
|
|
iFound = 1; |
|
|
backupMV = *currMV; |
|
|
|
|
|
if (iDirection != 2) |
|
|
CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
|
|
backupMV.y, 1); |
|
|
if (iDirection != 1) |
|
|
CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
|
|
backupMV.y, 2); |
|
|
if (iDirection != 4) |
|
|
CHECK_MV16_CANDIDATE_FOUND(backupMV.x, |
|
|
backupMV.y - iDiamondSize, 3); |
|
|
if (iDirection != 3) |
|
|
CHECK_MV16_CANDIDATE_FOUND(backupMV.x, |
|
|
backupMV.y + iDiamondSize, 4); |
|
|
} else { |
|
|
currMV->x = start_x; |
|
|
currMV->y = start_y; |
|
|
} |
|
866 |
return iMinSAD; |
return iMinSAD; |
867 |
} |
} |
|
#endif |
|
|
|
|
868 |
|
|
869 |
int32_t |
int32_t |
870 |
AdvDiamond8_MainSearch(const uint8_t * const pRef, |
AdvDiamond8_MainSearch(const uint8_t * const pRef, |
874 |
const uint8_t * const cur, |
const uint8_t * const cur, |
875 |
const int x, |
const int x, |
876 |
const int y, |
const int y, |
877 |
int start_x, |
const int start_xi, |
878 |
int start_y, |
const int start_yi, |
879 |
int iMinSAD, |
int iMinSAD, |
880 |
VECTOR * const currMV, |
VECTOR * const currMV, |
881 |
const int center_x, |
const int center_x, |
892 |
{ |
{ |
893 |
|
|
894 |
int32_t iSAD; |
int32_t iSAD; |
895 |
|
int start_x = start_xi, start_y = start_yi; |
896 |
|
|
897 |
/* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */ |
/* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */ |
898 |
|
|
1115 |
const IMAGE * const pCur, |
const IMAGE * const pCur, |
1116 |
const int x, |
const int x, |
1117 |
const int y, |
const int y, |
1118 |
const int start_x, |
const int start_x, /* start is searched first, so it should contain the most */ |
1119 |
const int start_y, |
const int start_y, /* likely motion vector for this block */ |
1120 |
const int center_x, |
const int center_x, /* center is from where length of MVs is measured */ |
1121 |
const int center_y, |
const int center_y, |
1122 |
const uint32_t MotionFlags, |
const uint32_t MotionFlags, |
1123 |
const uint32_t iQuant, |
const uint32_t iQuant, |
1172 |
} |
} |
1173 |
|
|
1174 |
/* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */ |
/* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */ |
|
//bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad); |
|
1175 |
bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad); |
bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad); |
1176 |
|
|
1177 |
if ((x == 0) && (y == 0)) { |
if ((x == 0) && (y == 0)) { |
1229 |
if ((iMinSAD < 256) || |
if ((iMinSAD < 256) || |
1230 |
((MVequal(*currMV, prevMB->mvs[0])) && |
((MVequal(*currMV, prevMB->mvs[0])) && |
1231 |
((int32_t) iMinSAD < prevMB->sad16))) { |
((int32_t) iMinSAD < prevMB->sad16))) { |
1232 |
if (iMinSAD < 2 * iQuant) // high chances for SKIP-mode |
if (iMinSAD < (int)(2 * iQuant)) // high chances for SKIP-mode |
1233 |
{ |
{ |
1234 |
if (!MVzero(*currMV)) { |
if (!MVzero(*currMV)) { |
1235 |
iMinSAD += MV16_00_BIAS; |
iMinSAD += MV16_00_BIAS; |
1434 |
const uint8_t * const cur, |
const uint8_t * const cur, |
1435 |
const int x, |
const int x, |
1436 |
const int y, |
const int y, |
1437 |
int32_t start_x, |
const int32_t start_x, |
1438 |
int32_t start_y, |
const int32_t start_y, |
1439 |
int32_t iMinSAD, |
int32_t iMinSAD, |
1440 |
VECTOR * const currMV, |
VECTOR * const currMV, |
1441 |
const int center_x, |
const int center_x, |
1453 |
/* Do a diamond search around given starting point, return SAD of best */ |
/* Do a diamond search around given starting point, return SAD of best */ |
1454 |
|
|
1455 |
int32_t iDirection = 0; |
int32_t iDirection = 0; |
1456 |
|
int32_t iDirectionBackup; |
1457 |
int32_t iSAD; |
int32_t iSAD; |
1458 |
VECTOR backupMV; |
VECTOR backupMV; |
1459 |
|
|
1467 |
CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3); |
CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3); |
1468 |
CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4); |
CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4); |
1469 |
|
|
1470 |
if (iDirection) |
if (iDirection) { |
1471 |
while (!iFound) { |
while (!iFound) { |
1472 |
iFound = 1; |
iFound = 1; |
1473 |
backupMV = *currMV; // since iDirection!=0, this is well defined! |
backupMV = *currMV; // since iDirection!=0, this is well defined! |
1474 |
|
iDirectionBackup = iDirection; |
1475 |
|
|
1476 |
if (iDirection != 2) |
if (iDirectionBackup != 2) |
1477 |
CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
1478 |
backupMV.y, 1); |
backupMV.y, 1); |
1479 |
if (iDirection != 1) |
if (iDirectionBackup != 1) |
1480 |
CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
1481 |
backupMV.y, 2); |
backupMV.y, 2); |
1482 |
if (iDirection != 4) |
if (iDirectionBackup != 4) |
1483 |
CHECK_MV8_CANDIDATE_FOUND(backupMV.x, |
CHECK_MV8_CANDIDATE_FOUND(backupMV.x, |
1484 |
backupMV.y - iDiamondSize, 3); |
backupMV.y - iDiamondSize, 3); |
1485 |
if (iDirection != 3) |
if (iDirectionBackup != 3) |
1486 |
CHECK_MV8_CANDIDATE_FOUND(backupMV.x, |
CHECK_MV8_CANDIDATE_FOUND(backupMV.x, |
1487 |
backupMV.y + iDiamondSize, 4); |
backupMV.y + iDiamondSize, 4); |
1488 |
|
} |
1489 |
} else { |
} else { |
1490 |
currMV->x = start_x; |
currMV->x = start_x; |
1491 |
currMV->y = start_y; |
currMV->y = start_y; |
1493 |
return iMinSAD; |
return iMinSAD; |
1494 |
} |
} |
1495 |
|
|
1496 |
|
|
1497 |
|
|
1498 |
|
|
1499 |
int32_t |
int32_t |
1500 |
Halfpel8_Refine_c(const uint8_t * const pRef, |
Square8_MainSearch(const uint8_t * const pRef, |
1501 |
const uint8_t * const pRefH, |
const uint8_t * const pRefH, |
1502 |
const uint8_t * const pRefV, |
const uint8_t * const pRefV, |
1503 |
const uint8_t * const pRefHV, |
const uint8_t * const pRefHV, |
1504 |
const uint8_t * const cur, |
const uint8_t * const cur, |
1505 |
const int x, |
const int x, |
1506 |
const int y, |
const int y, |
1507 |
VECTOR * const currMV, |
const int32_t start_x, |
1508 |
|
const int32_t start_y, |
1509 |
int32_t iMinSAD, |
int32_t iMinSAD, |
1510 |
|
VECTOR * const currMV, |
1511 |
const int center_x, |
const int center_x, |
1512 |
const int center_y, |
const int center_y, |
1513 |
const int32_t min_dx, |
const int32_t min_dx, |
1514 |
const int32_t max_dx, |
const int32_t max_dx, |
1515 |
const int32_t min_dy, |
const int32_t min_dy, |
1516 |
const int32_t max_dy, |
const int32_t max_dy, |
1517 |
|
const int32_t iEdgedWidth, |
1518 |
|
const int32_t iDiamondSize, |
1519 |
const int32_t iFcode, |
const int32_t iFcode, |
1520 |
const int32_t iQuant, |
const int32_t iQuant, |
1521 |
const int32_t iEdgedWidth) |
int iFound) |
1522 |
{ |
{ |
1523 |
/* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */ |
/* Do a square search around given starting point, return SAD of best */ |
1524 |
|
|
1525 |
|
int32_t iDirection = 0; |
1526 |
int32_t iSAD; |
int32_t iSAD; |
1527 |
VECTOR backupMV = *currMV; |
VECTOR backupMV; |
|
|
|
|
CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y - 1); |
|
|
CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y - 1); |
|
|
CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y - 1); |
|
|
CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y); |
|
|
CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y); |
|
|
CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y + 1); |
|
|
CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y + 1); |
|
|
CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y + 1); |
|
1528 |
|
|
1529 |
return iMinSAD; |
backupMV.x = start_x; |
1530 |
} |
backupMV.y = start_y; |
1531 |
|
|
1532 |
|
/* It's one search with full square pattern, and new parts for all following diamonds */ |
1533 |
|
|
1534 |
#define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8) |
/* new direction are extra, so 1-4 is normal diamond |
1535 |
|
537 |
1536 |
|
1*2 |
1537 |
|
648 |
1538 |
|
*/ |
1539 |
|
|
1540 |
int32_t |
CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1); |
1541 |
PMVfastSearch8(const uint8_t * const pRef, |
CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2); |
1542 |
const uint8_t * const pRefH, |
CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3); |
1543 |
const uint8_t * const pRefV, |
CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4); |
|
const uint8_t * const pRefHV, |
|
|
const IMAGE * const pCur, |
|
|
const int x, |
|
|
const int y, |
|
|
const int start_x, |
|
|
const int start_y, |
|
|
const int center_x, |
|
|
const int center_y, |
|
|
const uint32_t MotionFlags, |
|
|
const uint32_t iQuant, |
|
|
const uint32_t iFcode, |
|
|
const MBParam * const pParam, |
|
|
const MACROBLOCK * const pMBs, |
|
|
const MACROBLOCK * const prevMBs, |
|
|
VECTOR * const currMV, |
|
|
VECTOR * const currPMV) |
|
|
{ |
|
|
const uint32_t iWcount = pParam->mb_width; |
|
|
const int32_t iWidth = pParam->width; |
|
|
const int32_t iHeight = pParam->height; |
|
|
const int32_t iEdgedWidth = pParam->edged_width; |
|
1544 |
|
|
1545 |
const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth; |
CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, |
1546 |
|
backupMV.y - iDiamondSize, 5); |
1547 |
|
CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, |
1548 |
|
backupMV.y + iDiamondSize, 6); |
1549 |
|
CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, |
1550 |
|
backupMV.y - iDiamondSize, 7); |
1551 |
|
CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, |
1552 |
|
backupMV.y + iDiamondSize, 8); |
1553 |
|
|
|
int32_t iDiamondSize; |
|
1554 |
|
|
1555 |
int32_t min_dx; |
if (iDirection) { |
1556 |
int32_t max_dx; |
while (!iFound) { |
1557 |
int32_t min_dy; |
iFound = 1; |
1558 |
int32_t max_dy; |
backupMV = *currMV; |
1559 |
|
|
1560 |
|
switch (iDirection) { |
1561 |
|
case 1: |
1562 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
1563 |
|
backupMV.y, 1); |
1564 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
1565 |
|
backupMV.y - iDiamondSize, 5); |
1566 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
1567 |
|
backupMV.y - iDiamondSize, 7); |
1568 |
|
break; |
1569 |
|
case 2: |
1570 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y, |
1571 |
|
2); |
1572 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
1573 |
|
backupMV.y + iDiamondSize, 6); |
1574 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
1575 |
|
backupMV.y + iDiamondSize, 8); |
1576 |
|
break; |
1577 |
|
|
1578 |
|
case 3: |
1579 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize, |
1580 |
|
4); |
1581 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
1582 |
|
backupMV.y - iDiamondSize, 7); |
1583 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
1584 |
|
backupMV.y + iDiamondSize, 8); |
1585 |
|
break; |
1586 |
|
|
1587 |
|
case 4: |
1588 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize, |
1589 |
|
3); |
1590 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
1591 |
|
backupMV.y - iDiamondSize, 5); |
1592 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
1593 |
|
backupMV.y + iDiamondSize, 6); |
1594 |
|
break; |
1595 |
|
|
1596 |
|
case 5: |
1597 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y, |
1598 |
|
1); |
1599 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize, |
1600 |
|
3); |
1601 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
1602 |
|
backupMV.y - iDiamondSize, 5); |
1603 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
1604 |
|
backupMV.y + iDiamondSize, 6); |
1605 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
1606 |
|
backupMV.y - iDiamondSize, 7); |
1607 |
|
break; |
1608 |
|
|
1609 |
|
case 6: |
1610 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y, |
1611 |
|
2); |
1612 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize, |
1613 |
|
3); |
1614 |
|
|
1615 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
1616 |
|
backupMV.y - iDiamondSize, 5); |
1617 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
1618 |
|
backupMV.y + iDiamondSize, 6); |
1619 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
1620 |
|
backupMV.y + iDiamondSize, 8); |
1621 |
|
|
1622 |
|
break; |
1623 |
|
|
1624 |
|
case 7: |
1625 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
1626 |
|
backupMV.y, 1); |
1627 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize, |
1628 |
|
4); |
1629 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
1630 |
|
backupMV.y - iDiamondSize, 5); |
1631 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
1632 |
|
backupMV.y - iDiamondSize, 7); |
1633 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
1634 |
|
backupMV.y + iDiamondSize, 8); |
1635 |
|
break; |
1636 |
|
|
1637 |
|
case 8: |
1638 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y, |
1639 |
|
2); |
1640 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize, |
1641 |
|
4); |
1642 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
1643 |
|
backupMV.y + iDiamondSize, 6); |
1644 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
1645 |
|
backupMV.y - iDiamondSize, 7); |
1646 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
1647 |
|
backupMV.y + iDiamondSize, 8); |
1648 |
|
break; |
1649 |
|
default: |
1650 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y, |
1651 |
|
1); |
1652 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y, |
1653 |
|
2); |
1654 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize, |
1655 |
|
3); |
1656 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize, |
1657 |
|
4); |
1658 |
|
|
1659 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
1660 |
|
backupMV.y - iDiamondSize, 5); |
1661 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, |
1662 |
|
backupMV.y + iDiamondSize, 6); |
1663 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
1664 |
|
backupMV.y - iDiamondSize, 7); |
1665 |
|
CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, |
1666 |
|
backupMV.y + iDiamondSize, 8); |
1667 |
|
break; |
1668 |
|
} |
1669 |
|
} |
1670 |
|
} else { |
1671 |
|
currMV->x = start_x; |
1672 |
|
currMV->y = start_y; |
1673 |
|
} |
1674 |
|
return iMinSAD; |
1675 |
|
} |
1676 |
|
|
1677 |
|
|
1678 |
|
|
1679 |
|
|
1680 |
|
|
1681 |
|
int32_t |
1682 |
|
Halfpel8_Refine_c(const uint8_t * const pRef, |
1683 |
|
const uint8_t * const pRefH, |
1684 |
|
const uint8_t * const pRefV, |
1685 |
|
const uint8_t * const pRefHV, |
1686 |
|
const uint8_t * const cur, |
1687 |
|
const int x, |
1688 |
|
const int y, |
1689 |
|
VECTOR * const currMV, |
1690 |
|
int32_t iMinSAD, |
1691 |
|
const int center_x, |
1692 |
|
const int center_y, |
1693 |
|
const int32_t min_dx, |
1694 |
|
const int32_t max_dx, |
1695 |
|
const int32_t min_dy, |
1696 |
|
const int32_t max_dy, |
1697 |
|
const int32_t iFcode, |
1698 |
|
const int32_t iQuant, |
1699 |
|
const int32_t iEdgedWidth) |
1700 |
|
{ |
1701 |
|
/* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */ |
1702 |
|
|
1703 |
|
int32_t iSAD; |
1704 |
|
VECTOR backupMV = *currMV; |
1705 |
|
|
1706 |
|
CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y - 1); |
1707 |
|
CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y - 1); |
1708 |
|
CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y - 1); |
1709 |
|
CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y); |
1710 |
|
CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y); |
1711 |
|
CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y + 1); |
1712 |
|
CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y + 1); |
1713 |
|
CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y + 1); |
1714 |
|
|
1715 |
|
return iMinSAD; |
1716 |
|
} |
1717 |
|
|
1718 |
|
|
1719 |
|
#define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8) |
1720 |
|
|
1721 |
|
int32_t |
1722 |
|
PMVfastSearch8(const uint8_t * const pRef, |
1723 |
|
const uint8_t * const pRefH, |
1724 |
|
const uint8_t * const pRefV, |
1725 |
|
const uint8_t * const pRefHV, |
1726 |
|
const IMAGE * const pCur, |
1727 |
|
const int x, |
1728 |
|
const int y, |
1729 |
|
const int start_x, |
1730 |
|
const int start_y, |
1731 |
|
const int center_x, |
1732 |
|
const int center_y, |
1733 |
|
const uint32_t MotionFlags, |
1734 |
|
const uint32_t iQuant, |
1735 |
|
const uint32_t iFcode, |
1736 |
|
const MBParam * const pParam, |
1737 |
|
const MACROBLOCK * const pMBs, |
1738 |
|
const MACROBLOCK * const prevMBs, |
1739 |
|
VECTOR * const currMV, |
1740 |
|
VECTOR * const currPMV) |
1741 |
|
{ |
1742 |
|
const uint32_t iWcount = pParam->mb_width; |
1743 |
|
const int32_t iWidth = pParam->width; |
1744 |
|
const int32_t iHeight = pParam->height; |
1745 |
|
const int32_t iEdgedWidth = pParam->edged_width; |
1746 |
|
|
1747 |
|
const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth; |
1748 |
|
|
1749 |
|
int32_t iDiamondSize; |
1750 |
|
|
1751 |
|
int32_t min_dx; |
1752 |
|
int32_t max_dx; |
1753 |
|
int32_t min_dy; |
1754 |
|
int32_t max_dy; |
1755 |
|
|
1756 |
VECTOR pmv[4]; |
VECTOR pmv[4]; |
1757 |
int32_t psad[4]; |
int32_t psad[4]; |
1786 |
} |
} |
1787 |
|
|
1788 |
/* because we might use IF (dx>max_dx) THEN dx=max_dx; */ |
/* because we might use IF (dx>max_dx) THEN dx=max_dx; */ |
|
//bPredEq = get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad); |
|
1789 |
bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad); |
bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad); |
1790 |
|
|
1791 |
if ((x == 0) && (y == 0)) { |
if ((x == 0) && (y == 0)) { |
1815 |
|
|
1816 |
// Prepare for main loop |
// Prepare for main loop |
1817 |
|
|
1818 |
// if (MotionFlags & PMV_USESQUARES8) |
if (MotionFlags & PMV_USESQUARES8) |
1819 |
// MainSearchPtr = Square8_MainSearch; |
MainSearchPtr = Square8_MainSearch; |
1820 |
// else |
else |
1821 |
|
|
1822 |
if (MotionFlags & PMV_ADVANCEDDIAMOND8) |
if (MotionFlags & PMV_ADVANCEDDIAMOND8) |
1823 |
MainSearchPtr = AdvDiamond8_MainSearch; |
MainSearchPtr = AdvDiamond8_MainSearch; |
2100 |
max_dy = EVEN(max_dy); |
max_dy = EVEN(max_dy); |
2101 |
} |
} |
2102 |
/* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */ |
/* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */ |
|
//bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad); |
|
2103 |
bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad); |
bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad); |
2104 |
|
|
2105 |
/* Step 4: Calculate SAD around the Median prediction. |
/* Step 4: Calculate SAD around the Median prediction. |
2382 |
max_dy = EVEN(max_dy); |
max_dy = EVEN(max_dy); |
2383 |
} |
} |
2384 |
/* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */ |
/* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */ |
|
//bPredEq = get_pmvdata(pMBs, x >> 1, y >> 1, iWcount, iSubBlock, pmv[0].x, pmv[0].y, psad); |
|
2385 |
bPredEq = get_pmvdata2(pMBs, iWcount, 0, x >> 1, y >> 1, iSubBlock, pmv, psad); |
bPredEq = get_pmvdata2(pMBs, iWcount, 0, x >> 1, y >> 1, iSubBlock, pmv, psad); |
2386 |
|
|
2387 |
|
|
2493 |
|
|
2494 |
// there is no EPZS^2 for inter4v at the moment |
// there is no EPZS^2 for inter4v at the moment |
2495 |
|
|
2496 |
// if (MotionFlags & PMV_USESQUARES8) |
if (MotionFlags & PMV_USESQUARES8) |
2497 |
// MainSearchPtr = Square8_MainSearch; |
MainSearchPtr = Square8_MainSearch; |
2498 |
// else |
else |
2499 |
|
|
2500 |
if (MotionFlags & PMV_ADVANCEDDIAMOND8) |
if (MotionFlags & PMV_ADVANCEDDIAMOND8) |
2501 |
MainSearchPtr = AdvDiamond8_MainSearch; |
MainSearchPtr = AdvDiamond8_MainSearch; |
2559 |
currPMV->y = currMV->y - center_y; |
currPMV->y = currMV->y - center_y; |
2560 |
return iMinSAD; |
return iMinSAD; |
2561 |
} |
} |
|
|
|
|
|
|
|
|
|
|
int32_t |
|
|
PMVfastIntSearch16(const uint8_t * const pRef, |
|
|
const uint8_t * const pRefH, |
|
|
const uint8_t * const pRefV, |
|
|
const uint8_t * const pRefHV, |
|
|
const IMAGE * const pCur, |
|
|
const int x, |
|
|
const int y, |
|
|
const int start_x, |
|
|
const int start_y, |
|
|
const int center_x, |
|
|
const int center_y, |
|
|
const uint32_t MotionFlags, |
|
|
const uint32_t iQuant, |
|
|
const uint32_t iFcode, |
|
|
const MBParam * const pParam, |
|
|
const MACROBLOCK * const pMBs, |
|
|
const MACROBLOCK * const prevMBs, |
|
|
VECTOR * const currMV, |
|
|
VECTOR * const currPMV) |
|
|
{ |
|
|
const uint32_t iWcount = pParam->mb_width; |
|
|
const int32_t iWidth = pParam->width; |
|
|
const int32_t iHeight = pParam->height; |
|
|
const int32_t iEdgedWidth = pParam->edged_width; |
|
|
|
|
|
const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth; |
|
|
const VECTOR zeroMV = { 0, 0 }; |
|
|
|
|
|
int32_t iDiamondSize; |
|
|
|
|
|
int32_t min_dx; |
|
|
int32_t max_dx; |
|
|
int32_t min_dy; |
|
|
int32_t max_dy; |
|
|
|
|
|
int32_t iFound; |
|
|
|
|
|
VECTOR newMV; |
|
|
VECTOR backupMV; /* just for PMVFAST */ |
|
|
|
|
|
VECTOR pmv[4]; |
|
|
int32_t psad[4]; |
|
|
|
|
|
MainSearch16FuncPtr MainSearchPtr; |
|
|
|
|
|
const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount; |
|
|
MACROBLOCK *const pMB = pMBs + x + y * iWcount; |
|
|
|
|
|
int32_t threshA, threshB; |
|
|
int32_t bPredEq; |
|
|
int32_t iMinSAD, iSAD; |
|
|
|
|
|
|
|
|
/* Get maximum range */ |
|
|
get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight, |
|
|
iFcode); |
|
|
|
|
|
/* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */ |
|
|
|
|
|
if ((x == 0) && (y == 0)) { |
|
|
threshA = 512; |
|
|
threshB = 1024; |
|
|
|
|
|
bPredEq = 0; |
|
|
psad[0] = psad[1] = psad[2] = psad[3] = 0; |
|
|
*currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV; |
|
|
|
|
|
} else { |
|
|
threshA = psad[0]; |
|
|
threshB = threshA + 256; |
|
|
if (threshA < 512) |
|
|
threshA = 512; |
|
|
if (threshA > 1024) |
|
|
threshA = 1024; |
|
|
if (threshB > 1792) |
|
|
threshB = 1792; |
|
|
|
|
|
bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad); |
|
|
*currMV = pmv[0]; /* current best := prediction */ |
|
|
} |
|
|
|
|
|
iFound = 0; |
|
|
|
|
|
/* Step 4: Calculate SAD around the Median prediction. |
|
|
MinSAD=SAD |
|
|
If Motion Vector equal to Previous frame motion vector |
|
|
and MinSAD<PrevFrmSAD goto Step 10. |
|
|
If SAD<=256 goto Step 10. |
|
|
*/ |
|
|
|
|
|
if (currMV->x > max_dx) { |
|
|
currMV->x = EVEN(max_dx); |
|
|
} |
|
|
if (currMV->x < min_dx) { |
|
|
currMV->x = EVEN(min_dx); |
|
|
} |
|
|
if (currMV->y > max_dy) { |
|
|
currMV->y = EVEN(max_dy); |
|
|
} |
|
|
if (currMV->y < min_dy) { |
|
|
currMV->y = EVEN(min_dy); |
|
|
} |
|
|
|
|
|
iMinSAD = |
|
|
sad16(cur, |
|
|
get_iref_mv(pRef, x, y, 16, currMV, |
|
|
iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); |
|
|
iMinSAD += |
|
|
calc_delta_16(currMV->x - center_x, currMV->y - center_y, |
|
|
(uint8_t) iFcode, iQuant); |
|
|
|
|
|
if ((iMinSAD < 256) || |
|
|
((MVequal(*currMV, prevMB->i_mvs[0])) && |
|
|
((int32_t) iMinSAD < prevMB->i_sad16))) { |
|
|
if (iMinSAD < 2 * iQuant) // high chances for SKIP-mode |
|
|
{ |
|
|
if (!MVzero(*currMV)) { |
|
|
iMinSAD += MV16_00_BIAS; |
|
|
CHECK_MV16_ZERO; // (0,0) saves space for letterboxed pictures |
|
|
iMinSAD -= MV16_00_BIAS; |
|
|
} |
|
|
} |
|
|
|
|
|
if (MotionFlags & PMV_EARLYSTOP16) |
|
|
goto PMVfastInt16_Terminate_with_Refine; |
|
|
} |
|
|
|
|
|
|
|
|
/* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion |
|
|
vector of the median. |
|
|
If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2 |
|
|
*/ |
|
|
|
|
|
if ((bPredEq) && (MVequal(pmv[0], prevMB->i_mvs[0]))) |
|
|
iFound = 2; |
|
|
|
|
|
/* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search. |
|
|
Otherwise select large Diamond Search. |
|
|
*/ |
|
|
|
|
|
if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq)) |
|
|
iDiamondSize = 2; // halfpel units! |
|
|
else |
|
|
iDiamondSize = 4; // halfpel units! |
|
|
|
|
|
/* |
|
|
Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block. |
|
|
Also calculate (0,0) but do not subtract offset. |
|
|
Let MinSAD be the smallest SAD up to this point. |
|
|
If MV is (0,0) subtract offset. |
|
|
*/ |
|
|
|
|
|
// (0,0) is often a good choice |
|
|
|
|
|
if (!MVzero(pmv[0])) |
|
|
CHECK_MV16_ZERO; |
|
|
|
|
|
// previous frame MV is always possible |
|
|
|
|
|
if (!MVzero(prevMB->i_mvs[0])) |
|
|
if (!MVequal(prevMB->i_mvs[0], pmv[0])) |
|
|
CHECK_MV16_CANDIDATE(prevMB->i_mvs[0].x, prevMB->i_mvs[0].y); |
|
|
|
|
|
// left neighbour, if allowed |
|
|
|
|
|
if (!MVzero(pmv[1])) |
|
|
if (!MVequal(pmv[1], prevMB->i_mvs[0])) |
|
|
if (!MVequal(pmv[1], pmv[0])) |
|
|
CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y); |
|
|
|
|
|
// top neighbour, if allowed |
|
|
if (!MVzero(pmv[2])) |
|
|
if (!MVequal(pmv[2], prevMB->i_mvs[0])) |
|
|
if (!MVequal(pmv[2], pmv[0])) |
|
|
if (!MVequal(pmv[2], pmv[1])) |
|
|
CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y); |
|
|
|
|
|
// top right neighbour, if allowed |
|
|
if (!MVzero(pmv[3])) |
|
|
if (!MVequal(pmv[3], prevMB->i_mvs[0])) |
|
|
if (!MVequal(pmv[3], pmv[0])) |
|
|
if (!MVequal(pmv[3], pmv[1])) |
|
|
if (!MVequal(pmv[3], pmv[2])) |
|
|
CHECK_MV16_CANDIDATE(pmv[3].x, |
|
|
pmv[3].y); |
|
|
|
|
|
if ((MVzero(*currMV)) && |
|
|
(!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ ) |
|
|
iMinSAD -= MV16_00_BIAS; |
|
|
|
|
|
|
|
|
/* Step 6: If MinSAD <= thresa goto Step 10. |
|
|
If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10. |
|
|
*/ |
|
|
|
|
|
if ((iMinSAD <= threshA) || |
|
|
(MVequal(*currMV, prevMB->i_mvs[0]) && |
|
|
((int32_t) iMinSAD < prevMB->i_sad16))) { |
|
|
|
|
|
if (MotionFlags & PMV_EARLYSTOP16) |
|
|
goto PMVfastInt16_Terminate_with_Refine; |
|
|
} |
|
|
|
|
|
|
|
|
/************ (Diamond Search) **************/ |
|
|
/* |
|
|
Step 7: Perform Diamond search, with either the small or large diamond. |
|
|
If Found=2 only examine one Diamond pattern, and afterwards goto step 10 |
|
|
Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond. |
|
|
If center then goto step 10. |
|
|
Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center. |
|
|
Refine by using small diamond and goto step 10. |
|
|
*/ |
|
|
|
|
|
if (MotionFlags & PMV_USESQUARES16) |
|
|
MainSearchPtr = Square16_MainSearch; |
|
|
else if (MotionFlags & PMV_ADVANCEDDIAMOND16) |
|
|
MainSearchPtr = AdvDiamond16_MainSearch; |
|
|
else |
|
|
MainSearchPtr = Diamond16_MainSearch; |
|
|
|
|
|
backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */ |
|
|
|
|
|
|
|
|
/* default: use best prediction as starting point for one call of PMVfast_MainSearch */ |
|
|
iSAD = |
|
|
(*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x, |
|
|
currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, |
|
|
min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, |
|
|
iQuant, iFound); |
|
|
|
|
|
if (iSAD < iMinSAD) { |
|
|
*currMV = newMV; |
|
|
iMinSAD = iSAD; |
|
|
} |
|
|
|
|
|
if (MotionFlags & PMV_EXTSEARCH16) { |
|
|
/* extended: search (up to) two more times: orignal prediction and (0,0) */ |
|
|
|
|
|
if (!(MVequal(pmv[0], backupMV))) { |
|
|
iSAD = |
|
|
(*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, |
|
|
pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y, |
|
|
min_dx, max_dx, min_dy, max_dy, iEdgedWidth, |
|
|
iDiamondSize, iFcode, iQuant, iFound); |
|
|
|
|
|
if (iSAD < iMinSAD) { |
|
|
*currMV = newMV; |
|
|
iMinSAD = iSAD; |
|
|
} |
|
|
} |
|
|
|
|
|
if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) { |
|
|
iSAD = |
|
|
(*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0, |
|
|
iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy, |
|
|
max_dy, iEdgedWidth, iDiamondSize, iFcode, |
|
|
iQuant, iFound); |
|
|
|
|
|
if (iSAD < iMinSAD) { |
|
|
*currMV = newMV; |
|
|
iMinSAD = iSAD; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
/* |
|
|
Step 10: The motion vector is chosen according to the block corresponding to MinSAD. |
|
|
*/ |
|
|
|
|
|
PMVfastInt16_Terminate_with_Refine: |
|
|
|
|
|
pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV; |
|
|
pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD; |
|
|
|
|
|
if (MotionFlags & PMV_HALFPELREFINE16) // perform final half-pel step |
|
|
iMinSAD = |
|
|
Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV, |
|
|
iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy, |
|
|
iFcode, iQuant, iEdgedWidth); |
|
|
|
|
|
pmv[0] = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); // get _REAL_ prediction (halfpel possible) |
|
|
|
|
|
PMVfastInt16_Terminate_without_Refine: |
|
|
currPMV->x = currMV->x - center_x; |
|
|
currPMV->y = currMV->y - center_y; |
|
|
return iMinSAD; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* *********************************************************** |
|
|
bvop motion estimation |
|
|
// TODO: need to incorporate prediction here (eg. sad += calc_delta_16) |
|
|
***************************************************************/ |
|
|
|
|
|
|
|
|
#define DIRECT_PENALTY 0 |
|
|
#define DIRECT_UPPERLIMIT 256 // never use direct mode if SAD is larger than this |
|
|
|
|
|
void |
|
|
MotionEstimationBVOP(MBParam * const pParam, |
|
|
FRAMEINFO * const frame, |
|
|
const int32_t time_bp, |
|
|
const int32_t time_pp, |
|
|
// forward (past) reference |
|
|
const MACROBLOCK * const f_mbs, |
|
|
const IMAGE * const f_ref, |
|
|
const IMAGE * const f_refH, |
|
|
const IMAGE * const f_refV, |
|
|
const IMAGE * const f_refHV, |
|
|
// backward (future) reference |
|
|
const MACROBLOCK * const b_mbs, |
|
|
const IMAGE * const b_ref, |
|
|
const IMAGE * const b_refH, |
|
|
const IMAGE * const b_refV, |
|
|
const IMAGE * const b_refHV) |
|
|
{ |
|
|
const int mb_width = pParam->mb_width; |
|
|
const int mb_height = pParam->mb_height; |
|
|
const int edged_width = pParam->edged_width; |
|
|
|
|
|
int i, j, k; |
|
|
|
|
|
static const VECTOR zeroMV={0,0}; |
|
|
|
|
|
int f_sad16; /* forward (as usual) search */ |
|
|
int b_sad16; /* backward (only in b-frames) search */ |
|
|
int i_sad16; /* interpolated (both direction, b-frames only) */ |
|
|
int d_sad16; /* direct mode (assume linear motion) */ |
|
|
|
|
|
int best_sad; |
|
|
|
|
|
VECTOR f_predMV, b_predMV; /* there is no prediction for direct mode*/ |
|
|
VECTOR pmv_dontcare; |
|
|
|
|
|
int f_count=0; |
|
|
int b_count=0; |
|
|
int i_count=0; |
|
|
int d_count=0; |
|
|
int s_count=0; |
|
|
|
|
|
const int64_t TRB = (int32_t)time_pp - (int32_t)time_bp; |
|
|
const int64_t TRD = (int32_t)time_pp; |
|
|
|
|
|
// fprintf(stderr,"TRB = %lld TRD = %lld time_bp =%d time_pp =%d\n\n",TRB,TRD,time_bp,time_pp); |
|
|
// note: i==horizontal, j==vertical |
|
|
for (j = 0; j < mb_height; j++) { |
|
|
|
|
|
f_predMV = zeroMV; /* prediction is reset at left boundary */ |
|
|
b_predMV = zeroMV; |
|
|
|
|
|
for (i = 0; i < mb_width; i++) { |
|
|
MACROBLOCK *mb = &frame->mbs[i + j * mb_width]; |
|
|
const MACROBLOCK *f_mb = &f_mbs[i + j * mb_width]; |
|
|
const MACROBLOCK *b_mb = &b_mbs[i + j * mb_width]; |
|
|
|
|
|
mb->deltamv=zeroMV; |
|
|
|
|
|
/* special case, if collocated block is SKIPed: encoding is forward(0,0) */ |
|
|
|
|
|
#ifndef _DISABLE_SKIP |
|
|
if (b_mb->mode == MODE_INTER && b_mb->cbp == 0 && |
|
|
b_mb->mvs[0].x == 0 && b_mb->mvs[0].y == 0) { |
|
|
mb->mode = MODE_NOT_CODED; |
|
|
mb->mvs[0].x = 0; |
|
|
mb->mvs[0].y = 0; |
|
|
mb->b_mvs[0].x = 0; |
|
|
mb->b_mvs[0].y = 0; |
|
|
continue; |
|
|
} |
|
|
#endif |
|
|
|
|
|
d_sad16 = DIRECT_PENALTY; |
|
|
|
|
|
if (b_mb->mode == MODE_INTER4V) |
|
|
{ |
|
|
|
|
|
/* same method of scaling as in decoder.c, so we copy from there */ |
|
|
for (k = 0; k < 4; k++) { |
|
|
|
|
|
mb->directmv[k] = b_mb->mvs[k]; |
|
|
|
|
|
mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x); |
|
|
mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0) |
|
|
? ((TRB - TRD) * mb->directmv[k].x) / TRD |
|
|
: mb->mvs[k].x - mb->directmv[k].x); |
|
|
|
|
|
mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y); |
|
|
mb->b_mvs[k].y = (int32_t) ((mb->directmv[k].y == 0) |
|
|
? ((TRB - TRD) * mb->directmv[k].y) / TRD |
|
|
: mb->mvs[k].y - mb->directmv[k].y); |
|
|
|
|
|
d_sad16 += |
|
|
sad8bi(frame->image.y + 2*(i+(k&1))*8 + 2*(j+(k>>1))*8*edged_width, |
|
|
get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y, |
|
|
2*(i+(k&1)), 2*(j+(k>>1)), 8, &mb->mvs[k], edged_width), |
|
|
get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y, |
|
|
2*(i+(k&1)), 2*(j+(k>>1)), 8, &mb->b_mvs[k], edged_width), |
|
|
edged_width); |
|
|
} |
|
|
} |
|
|
else |
|
|
{ |
|
|
mb->directmv[3] = mb->directmv[2] = mb->directmv[1] = |
|
|
mb->directmv[0] = b_mb->mvs[0]; |
|
|
|
|
|
mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x); |
|
|
mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0) |
|
|
? ((TRB - TRD) * mb->directmv[0].x) / TRD |
|
|
: mb->mvs[0].x - mb->directmv[0].x); |
|
|
|
|
|
mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y); |
|
|
mb->b_mvs[0].y = (int32_t) ((mb->directmv[0].y == 0) |
|
|
? ((TRB - TRD) * mb->directmv[0].y) / TRD |
|
|
: mb->mvs[0].y - mb->directmv[0].y); |
|
|
|
|
|
d_sad16 += sad16bi(frame->image.y + i * 16 + j * 16 * edged_width, |
|
|
get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y, |
|
|
i, j, 16, &mb->mvs[0], edged_width), |
|
|
get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y, |
|
|
i, j, 16, &mb->b_mvs[0], edged_width), |
|
|
edged_width); |
|
|
|
|
|
} |
|
|
d_sad16 += calc_delta_16(mb->deltamv.x, mb->deltamv.y, 1, frame->quant); |
|
|
|
|
|
// forward search |
|
|
f_sad16 = SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y, |
|
|
&frame->image, i, j, |
|
|
mb->mvs[0].x, mb->mvs[0].y, /* start point f_directMV */ |
|
|
f_predMV.x, f_predMV.y, /* center is f-prediction */ |
|
|
frame->motion_flags, |
|
|
frame->quant, frame->fcode, pParam, |
|
|
f_mbs, f_mbs, |
|
|
&mb->mvs[0], &pmv_dontcare); |
|
|
|
|
|
|
|
|
// backward search |
|
|
b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y, |
|
|
&frame->image, i, j, |
|
|
mb->b_mvs[0].x, mb->b_mvs[0].y, /* start point b_directMV */ |
|
|
b_predMV.x, b_predMV.y, /* center is b-prediction */ |
|
|
frame->motion_flags, |
|
|
frame->quant, frame->bcode, pParam, |
|
|
b_mbs, b_mbs, |
|
|
&mb->b_mvs[0], &pmv_dontcare); |
|
|
|
|
|
i_sad16 = |
|
|
sad16bi(frame->image.y + i * 16 + j * 16 * edged_width, |
|
|
get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y, |
|
|
i, j, 16, &mb->mvs[0], edged_width), |
|
|
get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y, |
|
|
i, j, 16, &mb->b_mvs[0], edged_width), |
|
|
edged_width); |
|
|
i_sad16 += calc_delta_16(mb->mvs[0].x-f_predMV.x, mb->mvs[0].y-f_predMV.y, |
|
|
frame->fcode, frame->quant); |
|
|
i_sad16 += calc_delta_16(mb->b_mvs[0].x-b_predMV.x, mb->b_mvs[0].y-b_predMV.y, |
|
|
frame->bcode, frame->quant); |
|
|
|
|
|
// TODO: direct search |
|
|
// predictor + delta vector in range [-32,32] (fcode=1) |
|
|
|
|
|
i_sad16 = 65535; |
|
|
f_sad16 = 65535; |
|
|
b_sad16 = 65535; |
|
|
// d_sad16 = 65535; |
|
|
|
|
|
if (f_sad16 < b_sad16) { |
|
|
best_sad = f_sad16; |
|
|
mb->mode = MODE_FORWARD; |
|
|
} else { |
|
|
best_sad = b_sad16; |
|
|
mb->mode = MODE_BACKWARD; |
|
|
} |
|
|
|
|
|
if (i_sad16 < best_sad) { |
|
|
best_sad = i_sad16; |
|
|
mb->mode = MODE_INTERPOLATE; |
|
|
} |
|
|
|
|
|
if (d_sad16 < best_sad) { |
|
|
|
|
|
if (b_mb->mode == MODE_INTER4V) |
|
|
{ |
|
|
|
|
|
/* same method of scaling as in decoder.c, so we copy from there */ |
|
|
for (k = 0; k < 4; k++) { |
|
|
|
|
|
mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x); |
|
|
mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0) |
|
|
? ((TRB - TRD) * mb->directmv[k].x) / TRD |
|
|
: mb->mvs[k].x - mb->directmv[k].x); |
|
|
|
|
|
mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y); |
|
|
mb->b_mvs[k].y = (int32_t) ((mb->directmv[k].y == 0) |
|
|
? ((TRB - TRD) * mb->directmv[k].y) / TRD |
|
|
: mb->mvs[k].y - mb->directmv[k].y); |
|
|
} |
|
|
} |
|
|
else |
|
|
{ |
|
|
mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x); |
|
|
|
|
|
mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0) |
|
|
? ((TRB - TRD) * mb->directmv[0].x) / TRD |
|
|
: mb->mvs[0].x - mb->directmv[0].x); |
|
|
|
|
|
mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y); |
|
|
|
|
|
mb->b_mvs[0].y = (int32_t) ((mb->directmv[0].y == 0) |
|
|
? ((TRB - TRD) * mb->directmv[0].y) / TRD |
|
|
: mb->mvs[0].y - mb->directmv[0].y); |
|
|
|
|
|
mb->mvs[3] = mb->mvs[2] = mb->mvs[1] = mb->mvs[0]; |
|
|
mb->b_mvs[3] = mb->b_mvs[2] = mb->b_mvs[1] = mb->b_mvs[0]; |
|
|
} |
|
|
|
|
|
best_sad = d_sad16; |
|
|
mb->mode = MODE_DIRECT; |
|
|
mb->mode = MODE_INTERPOLATE; // direct mode still broken :-( |
|
|
} |
|
|
|
|
|
switch (mb->mode) |
|
|
{ |
|
|
case MODE_FORWARD: |
|
|
f_count++; |
|
|
f_predMV = mb->mvs[0]; |
|
|
break; |
|
|
case MODE_BACKWARD: |
|
|
b_count++; |
|
|
b_predMV = mb->b_mvs[0]; |
|
|
|
|
|
break; |
|
|
case MODE_INTERPOLATE: |
|
|
i_count++; |
|
|
f_predMV = mb->mvs[0]; |
|
|
b_predMV = mb->b_mvs[0]; |
|
|
break; |
|
|
case MODE_DIRECT: |
|
|
d_count++; |
|
|
break; |
|
|
default: |
|
|
s_count++; // ??? |
|
|
break; |
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
#ifdef _DEBUG_BFRAME_STAT |
|
|
fprintf(stderr,"B-Stat: F: %04d B: %04d I: %04d D: %04d S: %04d\n", |
|
|
f_count,b_count,i_count,d_count,s_count); |
|
|
#endif |
|
|
|
|
|
} |
|