home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 9
/
CD_ASCQ_09_1193.iso
/
news
/
4441
/
mpegcode
/
src
/
bsearch.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-09-27
|
29KB
|
1,093 lines
/*===========================================================================*
* bsearch.c *
* *
* Procedures concerned with the B-frame motion search *
* *
* EXPORTED PROCEDURES: *
* SetBSearchAlg *
* BMotionSearch *
* BSearchName *
* *
*===========================================================================*/
/*
* Copyright (c) 1993 The Regents of the University of California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose, without fee, and without written agreement is
* hereby granted, provided that the above copyright notice and the following
* two paragraphs appear in all copies of this software.
*
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
* CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
/*
* $Header: /n/picasso/users/keving/encode/src/RCS/bsearch.c,v 1.3 1993/07/22 22:23:43 keving Exp keving $
* $Log: bsearch.c,v $
* Revision 1.3 1993/07/22 22:23:43 keving
* nothing
*
* Revision 1.2 1993/06/30 20:06:09 keving
* nothing
*
* Revision 1.1 1993/06/03 21:08:08 keving
* nothing
*
* Revision 1.1 1993/03/02 18:27:05 keving
* nothing
*
*/
/*==============*
* HEADER FILES *
*==============*/
#include "all.h"
#include "mtypes.h"
#include "frames.h"
#include "search.h"
#include "fsize.h"
/*==================*
* STATIC VARIABLES *
*==================*/
static int bsearchAlg;
/*===============================*
* INTERNAL PROCEDURE prototypes *
*===============================*/
static int32 FindBestMatch _ANSI_ARGS_((LumBlock block, LumBlock currentBlock, MpegFrame *prev,
int by, int bx, int *motionY, int *motionX, int32 bestSoFar));
static int BMotionSearchSimple _ANSI_ARGS_((LumBlock currentBlock, MpegFrame *prev,
MpegFrame *next, int by, int bx, int *fmy, int *fmx,
int *bmy, int *bmx, int oldMode));
static int BMotionSearchCross2 _ANSI_ARGS_((LumBlock currentBlock, MpegFrame *prev,
MpegFrame *next, int by, int bx, int *fmy, int *fmx,
int *bmy, int *bmx, int oldMode));
static int BMotionSearchExhaust _ANSI_ARGS_((LumBlock currentBlock, MpegFrame *prev,
MpegFrame *next, int by, int bx, int *fmy, int *fmx,
int *bmy, int *bmx, int oldMode));
static void BMotionSearchNoInterp _ANSI_ARGS_((LumBlock currentBlock, MpegFrame *prev,
MpegFrame *next, int by, int bx,
int *fmy, int *fmx, int *forwardErr,
int *bmy, int *bmx, int *backErr,
boolean backNeeded));
static int32 FindBestMatchExhaust _ANSI_ARGS_((LumBlock block, LumBlock currentBlock, MpegFrame *prev,
int by, int bx, int *motionY, int *motionX,
int32 bestSoFar));
static int32 FindBestMatchTwoLevel _ANSI_ARGS_((LumBlock block, LumBlock currentBlock, MpegFrame *prev,
int by, int bx, int *motionY, int *motionX,
int32 bestSoFar));
static int32 FindBestMatchLogarithmic _ANSI_ARGS_((LumBlock block, LumBlock currentBlock, MpegFrame *prev,
int by, int bx, int *motionY, int *motionX,
int32 bestSoFar));
static int32 FindBestMatchSubSample _ANSI_ARGS_((LumBlock block, LumBlock currentBlock, MpegFrame *prev,
int by, int bx, int *motionY, int *motionX,
int32 bestSoFar));
/*=====================*
* EXPORTED PROCEDURES *
*=====================*/
/*===========================*
* INITIALIZATION PROCEDURES *
*===========================*/
/*===========================================================================*
*
* SetBSearchAlg
*
* set the B-search algorithm
*
* RETURNS: nothing
*
* SIDE EFFECTS: bsearchAlg modified
*
*===========================================================================*/
void
SetBSearchAlg(alg)
char *alg;
{
if ( strcmp(alg, "SIMPLE") == 0 ) {
bsearchAlg = BSEARCH_SIMPLE;
} else if ( strcmp(alg, "CROSS2") == 0 ) {
bsearchAlg = BSEARCH_CROSS2;
} else if ( strcmp(alg, "EXHAUSTIVE") == 0 ) {
bsearchAlg = BSEARCH_EXHAUSTIVE;
} else {
fprintf(stderr, "ERROR: Illegal bsearch alg: %s\n", alg);
exit(1);
}
}
/*===========================================================================*
*
* BSearchName
*
* return the text of the B-search algorithm
*
* RETURNS: a pointer to the string
*
* SIDE EFFECTS: none
*
*===========================================================================*/
char *
BSearchName()
{
switch(bsearchAlg) {
case BSEARCH_SIMPLE:
return "SIMPLE";
case BSEARCH_CROSS2:
return "CROSS2";
case BSEARCH_EXHAUSTIVE:
return "EXHAUSTIVE";
default:
exit(1);
break;
}
}
/*===========================================================================*
*
* BMotionSearch
*
* search for the best B-frame motion vectors
*
* RETURNS: MOTION_FORWARD forward motion should be used
* MOTION_BACKWARD backward motion should be used
* MOTION_INTERPOLATE both should be used and interpolated
*
* OUTPUTS: *fmx, *fmy = TWICE the forward motion vector
* *bmx, *bmy = TWICE the backward motion vector
*
* SIDE EFFECTS: none
*
* PRECONDITIONS: The relevant block in 'current' is valid (it has not
* been dct'd). Thus, the data in 'current' can be
* accesed through y_blocks, cr_blocks, and cb_blocks.
* This is not the case for the blocks in 'prev' and
* 'next.' Therefore, references into 'prev' and 'next'
* should be done
* through the struct items ref_y, ref_cr, ref_cb
*
* POSTCONDITIONS: current, prev, next should be unchanged.
* Some computation could be saved by requiring
* the dct'd difference to be put into current's block
* elements here, depending on the search technique.
* However, it was decided that it mucks up the code
* organization a little, and the saving in computation
* would be relatively little (if any).
*
* NOTES: the search procedure MAY return (0,0) motion vectors
*
*===========================================================================*/
int
BMotionSearch(currentBlock, prev, next, by, bx, fmy, fmx, bmy, bmx, oldMode)
LumBlock currentBlock;
MpegFrame *prev;
MpegFrame *next;
int by;
int bx;
int *fmy;
int *fmx;
int *bmy;
int *bmx;
int oldMode;
{
/* simply call the appropriate algorithm, based on user preference */
switch(bsearchAlg) {
case BSEARCH_SIMPLE:
return BMotionSearchSimple(currentBlock, prev, next, by, bx, fmy,
fmx, bmy, bmx, oldMode);
break;
case BSEARCH_CROSS2:
return BMotionSearchCross2(currentBlock, prev, next, by, bx, fmy,
fmx, bmy, bmx, oldMode);
break;
case BSEARCH_EXHAUSTIVE:
return BMotionSearchExhaust(currentBlock, prev, next, by, bx, fmy,
fmx, bmy, bmx, oldMode);
break;
default:
fprintf(stderr, "Illegal B-frame motion search algorithm: %d\n",
bsearchAlg);
exit(1);
}
}
/*===========================================================================*
*
* BMotionSearchSimple
*
* does a simple search for B-frame motion vectors
* see BMotionSearch for generic description
*
* DESCRIPTION:
* 1) find best backward and forward vectors
* 2) compute interpolated error using those two vectors
* 3) return the best of the three choices
*
*===========================================================================*/
static int
BMotionSearchSimple(currentBlock, prev, next, by, bx, fmy, fmx, bmy, bmx,
oldMode)
LumBlock currentBlock;
MpegFrame *prev;
MpegFrame *next;
int by;
int bx;
int *fmy;
int *fmx;
int *bmy;
int *bmx;
int oldMode;
{
int32 forwardErr, backErr, interpErr;
LumBlock interpBlock;
int32 bestSoFar;
/* STEP 1 */
BMotionSearchNoInterp(currentBlock, prev, next, by, bx, fmy, fmx,
&forwardErr, bmy, bmx, &backErr, TRUE);
/* STEP 2 */
ComputeBMotionLumBlock(prev, next, by, bx, MOTION_INTERPOLATE,
*fmy, *fmx, *bmy, *bmx, interpBlock);
bestSoFar = min(backErr, forwardErr);
interpErr = LumBlockMAD(currentBlock, interpBlock, bestSoFar);
/* STEP 3 */
if ( interpErr <= forwardErr ) {
if ( interpErr <= backErr ) {
return MOTION_INTERPOLATE;
}
else
return MOTION_BACKWARD;
} else if ( forwardErr <= backErr ) {
return MOTION_FORWARD;
} else {
return MOTION_BACKWARD;
}
}
/*===========================================================================*
*
* BMotionSearchCross2
*
* does a cross-2 search for B-frame motion vectors
* see BMotionSearch for generic description
*
* DESCRIPTION:
* 1) find best backward and forward vectors
* 2) find best matching interpolating vectors
* 3) return the best of the 4 choices
*
*===========================================================================*/
static int
BMotionSearchCross2(currentBlock, prev, next, by, bx, fmy, fmx, bmy, bmx,
oldMode)
LumBlock currentBlock;
MpegFrame *prev;
MpegFrame *next;
int by;
int bx;
int *fmy;
int *fmx;
int *bmy;
int *bmx;
int oldMode;
{
LumBlock forwardBlock, backBlock;
int32 forwardErr, backErr, interpErr;
int newfmy, newfmx, newbmy, newbmx;
int32 interpErr2;
int32 bestErr;
/* STEP 1 */
BMotionSearchNoInterp(currentBlock, prev, next, by, bx, fmy, fmx,
&forwardErr, bmy, bmx, &backErr, TRUE);
bestErr = min(forwardErr, backErr);
/* STEP 2 */
ComputeBMotionLumBlock(prev, next, by, bx, MOTION_FORWARD,
*fmy, *fmx, 0, 0, forwardBlock);
ComputeBMotionLumBlock(prev, next, by, bx, MOTION_BACKWARD,
0, 0, *bmy, *bmx, backBlock);
/* try a cross-search; total of 4 local searches */
newbmy = *bmy; newbmx = *bmx;
newfmy = *fmy; newfmx = *fmx;
interpErr = FindBestMatch(forwardBlock, currentBlock, next, by, bx,
&newbmy, &newbmx, bestErr);
bestErr = min(bestErr, interpErr);
interpErr2 = FindBestMatch(backBlock, currentBlock, prev, by, bx,
&newfmy, &newfmx, bestErr);
/* STEP 3 */
if ( interpErr <= interpErr2 ) {
newfmy = *fmy;
newfmx = *fmx;
}
else
{
newbmy = *bmy;
newbmx = *bmx;
interpErr = interpErr2;
}
if ( interpErr <= forwardErr ) {
if ( interpErr <= backErr ) {
*fmy = newfmy;
*fmx = newfmx;
*bmy = newbmy;
*bmx = newbmx;
return MOTION_INTERPOLATE;
}
else
return MOTION_BACKWARD;
} else if ( forwardErr <= backErr ) {
return MOTION_FORWARD;
} else {
return MOTION_BACKWARD;
}
}
/*===========================================================================*
*
* BMotionSearchExhaust
*
* does an exhaustive search for B-frame motion vectors
* see BMotionSearch for generic description
*
* DESCRIPTION:
* 1) find best backward and forward vectors
* 2) use exhaustive search to find best interpolating vectors
* 3) return the best of the 3 choices
*
*===========================================================================*/
static int
BMotionSearchExhaust(currentBlock, prev, next, by, bx, fmy, fmx, bmy, bmx,
oldMode)
LumBlock currentBlock;
MpegFrame *prev;
MpegFrame *next;
int by;
int bx;
int *fmy;
int *fmx;
int *bmy;
int *bmx;
int oldMode;
{
register int mx, my;
int32 diff, bestDiff;
int stepSize;
LumBlock forwardBlock;
int32 forwardErr, backErr;
int newbmy, newbmx;
int leftMY, leftMX;
int rightMY, rightMX;
boolean result;
/* STEP 1 */
BMotionSearchNoInterp(currentBlock, prev, next, by, bx, fmy, fmx,
&forwardErr, bmy, bmx, &backErr, FALSE);
if ( forwardErr <= backErr ) {
bestDiff = forwardErr;
result = MOTION_FORWARD;
}
else
{
bestDiff = backErr;
result = MOTION_BACKWARD;
}
/* STEP 2 */
stepSize = (pixelFullSearch ? 2 : 1);
COMPUTE_MOTION_BOUNDARY(by,bx,stepSize,leftMY,leftMX,rightMY,rightMX);
if ( searchRange < rightMY ) {
rightMY = searchRange;
}
if ( searchRange < rightMX ) {
rightMX = searchRange;
}
for ( my = -searchRange; my < rightMY; my += stepSize ) {
if ( my < leftMY ) {
continue;
}
for ( mx = -searchRange; mx < rightMX; mx += stepSize ) {
if ( mx < leftMX ) {
continue;
}
ComputeBMotionLumBlock(prev, next, by, bx, MOTION_FORWARD,
my, mx, 0, 0, forwardBlock);
newbmy = my; newbmx = mx;
diff = FindBestMatch(forwardBlock, currentBlock, next, by, bx,
&newbmy, &newbmx, bestDiff);
if ( diff < bestDiff ) {
*fmy = my;
*fmx = mx;
*bmy = newbmy;
*bmx = newbmx;
bestDiff = diff;
result = MOTION_INTERPOLATE;
}
}
}
return result;
}
/*===========================================================================*
*
* FindBestMatch
*
* given a motion-compensated block in one direction, tries to find
* the best motion vector in the opposite direction to match it
*
* RETURNS: the best vector (*motionY, *motionX), and the corresponding
* error is returned if it is better than bestSoFar. If not,
* then a number greater than bestSoFar is returned and
* (*motionY, *motionX) has no meaning.
*
* SIDE EFFECTS: none
*
*===========================================================================*/
static int32
FindBestMatch(block, currentBlock, prev, by, bx, motionY, motionX, bestSoFar)
LumBlock block;
LumBlock currentBlock;
MpegFrame *prev;
int by;
int bx;
int *motionY;
int *motionX;
int32 bestSoFar;
{
int32 result;
switch(psearchAlg) {
case PSEARCH_SUBSAMPLE:
result = FindBestMatchSubSample(block, currentBlock, prev, by, bx,
motionY, motionX, bestSoFar);
break;
case PSEARCH_EXHAUSTIVE:
result = FindBestMatchExhaust(block, currentBlock, prev, by, bx,
motionY, motionX, bestSoFar);
break;
case PSEARCH_LOGARITHMIC:
result = FindBestMatchLogarithmic(block, currentBlock, prev, by, bx,
motionY, motionX, bestSoFar);
break;
case PSEARCH_TWOLEVEL:
result = FindBestMatchTwoLevel(block, currentBlock, prev, by, bx,
motionY, motionX, bestSoFar);
break;
default:
fprintf(stderr, "ERROR: Illegal P-search alg %d\n", psearchAlg);
exit(1);
}
return result;
}
/*===========================================================================*
*
* FindBestMatchExhaust
*
* tries to find matching motion vector
* see FindBestMatch for generic description
*
* DESCRIPTION: uses an exhaustive search
*
*===========================================================================*/
static int32
FindBestMatchExhaust(block, currentBlock, prev, by, bx, motionY, motionX,
bestSoFar)
LumBlock block;
LumBlock currentBlock;
MpegFrame *prev;
int by;
int bx;
int *motionY;
int *motionX;
int32 bestSoFar;
{
register int mx, my;
int32 diff, bestDiff;
int stepSize;
int leftMY, leftMX;
int rightMY, rightMX;
int distance;
int tempRightMY, tempRightMX;
boolean changed = FALSE;
stepSize = (pixelFullSearch ? 2 : 1);
COMPUTE_MOTION_BOUNDARY(by,bx,stepSize,leftMY,leftMX,rightMY,rightMX);
/* try old motion vector first */
if ( VALID_MOTION(*motionY, *motionX) ) {
bestDiff = LumAddMotionError(currentBlock, block, prev, by, bx,
*motionY, *motionX, bestSoFar);
if ( bestSoFar < bestDiff ) {
bestDiff = bestSoFar;
}
}
else
{
*motionY = 0;
*motionX = 0;
bestDiff = bestSoFar;
}
/* maybe should try spiral pattern centered around prev motion vector? */
/* try a spiral pattern */
for ( distance = stepSize; distance <= searchRange; distance += stepSize ) {
tempRightMY = rightMY;
if ( distance < tempRightMY ) {
tempRightMY = distance;
}
tempRightMX = rightMX;
if ( distance < tempRightMX ) {
tempRightMX = distance;
}
/* do top, bottom */
for ( my = -distance; my < tempRightMY;
my += max(tempRightMY+distance-stepSize, stepSize) ) {
if ( my < leftMY ) {
continue;
}
for ( mx = -distance; mx < tempRightMX; mx += stepSize ) {
if ( mx < leftMX ) {
continue;
}
diff = LumAddMotionError(currentBlock, block, prev, by, bx,
my, mx, bestDiff);
if ( diff < bestDiff ) {
*motionY = my;
*motionX = mx;
bestDiff = diff;
}
}
}
/* do left, right */
for ( mx = -distance; mx < tempRightMX; mx += max(tempRightMX+distance-stepSize, stepSize) ) {
if ( mx < leftMX ) {
continue;
}
for ( my = -distance+stepSize; my < tempRightMY-stepSize; my += stepSize ) {
if ( my < leftMY ) {
continue;
}
diff = LumAddMotionError(currentBlock, block, prev, by, bx,
my, mx, bestDiff);
if ( diff < bestDiff ) {
*motionY = my;
*motionX = mx;
bestDiff = diff;
changed = TRUE;
}
}
}
}
if ( ! changed ) {
bestDiff++;
}
return bestDiff;
}
/*===========================================================================*
*
* FindBestMatchTwoLevel
*
* tries to find matching motion vector
* see FindBestMatch for generic description
*
* DESCRIPTION: uses an exhaustive full-pixel search, then looks at
* neighboring half-pixels
*
*===========================================================================*/
static int32
FindBestMatchTwoLevel(block, currentBlock, prev, by, bx, motionY, motionX,
bestSoFar)
LumBlock block;
LumBlock currentBlock;
MpegFrame *prev;
int by;
int bx;
int *motionY;
int *motionX;
int32 bestSoFar;
{
register int mx, my;
int32 diff, bestDiff;
int leftMY, leftMX;
int rightMY, rightMX;
int distance;
int tempRightMY, tempRightMX;
boolean changed = FALSE;
int yOffset, xOffset;
/* exhaustive full-pixel search first */
COMPUTE_MOTION_BOUNDARY(by,bx,2,leftMY,leftMX,rightMY,rightMX);
rightMY--;
rightMX--;
/* try old motion vector first */
if ( VALID_MOTION(*motionY, *motionX) ) {
bestDiff = LumAddMotionError(currentBlock, block, prev, by, bx,
*motionY, *motionX, bestSoFar);
if ( bestSoFar < bestDiff ) {
bestDiff = bestSoFar;
}
}
else
{
*motionY = 0;
*motionX = 0;
bestDiff = bestSoFar;
}
rightMY++;
rightMX++;
/* maybe should try spiral pattern centered around prev motion vector? */
/* try a spiral pattern */
for ( distance = 2; distance <= searchRange; distance += 2 ) {
tempRightMY = rightMY;
if ( distance < tempRightMY ) {
tempRightMY = distance;
}
tempRightMX = rightMX;
if ( distance < tempRightMX ) {
tempRightMX = distance;
}
/* do top, bottom */
for ( my = -distance; my < tempRightMY;
my += max(tempRightMY+distance-2, 2) ) {
if ( my < leftMY ) {
continue;
}
for ( mx = -distance; mx < tempRightMX; mx += 2 ) {
if ( mx < leftMX ) {
continue;
}
diff = LumAddMotionError(currentBlock, block, prev, by, bx,
my, mx, bestDiff);
if ( diff < bestDiff ) {
*motionY = my;
*motionX = mx;
bestDiff = diff;
}
}
}
/* do left, right */
for ( mx = -distance; mx < tempRightMX; mx += max(tempRightMX+distance-2, 2) ) {
if ( mx < leftMX ) {
continue;
}
for ( my = -distance+2; my < tempRightMY-2; my += 2 ) {
if ( my < leftMY ) {
continue;
}
diff = LumAddMotionError(currentBlock, block, prev, by, bx,
my, mx, bestDiff);
if ( diff < bestDiff ) {
*motionY = my;
*motionX = mx;
bestDiff = diff;
changed = TRUE;
}
}
}
}
/* now look at neighboring half-pixels */
my = *motionY;
mx = *motionX;
rightMY--;
rightMX--;
for ( yOffset = -1; yOffset <= 1; yOffset++ ) {
for ( xOffset = -1; xOffset <= 1; xOffset++ ) {
if ( (yOffset == 0) && (xOffset == 0) )
continue;
if ( VALID_MOTION(my+yOffset, mx+xOffset) &&
((diff = LumAddMotionError(currentBlock, block, prev, by, bx,
my+yOffset, mx+xOffset, bestDiff)) < bestDiff) ) {
*motionY = my+yOffset;
*motionX = mx+xOffset;
bestDiff = diff;
changed = TRUE;
}
}
}
if ( ! changed ) {
bestDiff++;
}
return bestDiff;
}
/*===========================================================================*
*
* FindBestMatchLogarithmic
*
* tries to find matching motion vector
* see FindBestMatch for generic description
*
* DESCRIPTION: uses a logarithmic search
*
*===========================================================================*/
static int32
FindBestMatchLogarithmic(block, currentBlock, prev, by, bx, motionY, motionX,
bestSoFar)
LumBlock block;
LumBlock currentBlock;
MpegFrame *prev;
int by;
int bx;
int *motionY;
int *motionX;
int32 bestSoFar;
{
register int mx, my;
int32 diff, bestDiff;
int stepSize;
int leftMY, leftMX;
int rightMY, rightMX;
int tempRightMY, tempRightMX;
int spacing;
int centerX, centerY;
int newCenterX, newCenterY;
stepSize = (pixelFullSearch ? 2 : 1);
COMPUTE_MOTION_BOUNDARY(by,bx,stepSize,leftMY,leftMX,rightMY,rightMX);
bestDiff = 0x7fffffff;
/* grid spacing */
if ( stepSize == 2 ) { /* make sure spacing is even */
spacing = (searchRange+1)/2;
if ( (spacing % 2) != 0 ) {
spacing++;
}
}
else
spacing = (searchRange+1)/2;
centerX = 0;
centerY = 0;
while ( spacing >= stepSize ) {
newCenterY = centerY;
newCenterX = centerX;
tempRightMY = rightMY;
if ( centerY+spacing+1 < tempRightMY ) {
tempRightMY = centerY+spacing+1;
}
tempRightMX = rightMX;
if ( centerX+spacing+1 < tempRightMX ) {
tempRightMX = centerX+spacing+1;
}
for ( my = centerY-spacing; my < tempRightMY; my += spacing ) {
if ( my < leftMY ) {
continue;
}
for ( mx = centerX-spacing; mx < tempRightMX; mx += spacing ) {
if ( mx < leftMX ) {
continue;
}
diff = LumAddMotionError(currentBlock, block, prev, by, bx,
my, mx, bestDiff);
if ( diff < bestDiff ) {
newCenterY = my;
newCenterX = mx;
bestDiff = diff;
}
}
}
centerY = newCenterY;
centerX = newCenterX;
if ( stepSize == 2 ) { /* make sure spacing is even */
if ( spacing == 2 ) {
spacing = 0;
}
else
{
spacing = (spacing+1)/2;
if ( (spacing % 2) != 0 ) {
spacing++;
}
}
}
else
{
if ( spacing == 1 ) {
spacing = 0;
}
else
spacing = (spacing+1)/2;
}
}
/* check old motion -- see if it's better */
if ( (*motionY >= leftMY) && (*motionY < rightMY) &&
(*motionX >= leftMX) && (*motionX < rightMX) ) {
diff = LumAddMotionError(currentBlock, block, prev, by, bx, *motionY, *motionX, bestDiff);
} else {
diff = 0x7fffffff;
}
if ( bestDiff < diff ) {
*motionY = centerY;
*motionX = centerX;
}
else
bestDiff = diff;
return bestDiff;
}
/*===========================================================================*
*
* FindBestMatchSubSample
*
* tries to find matching motion vector
* see FindBestMatch for generic description
*
* DESCRIPTION: should use subsampling method, but too lazy to write all
* the code for it (so instead just calls FindBestMatchExhaust)
*
*===========================================================================*/
static int32
FindBestMatchSubSample(block, currentBlock, prev, by, bx, motionY, motionX,
bestSoFar)
LumBlock block;
LumBlock currentBlock;
MpegFrame *prev;
int by;
int bx;
int *motionY;
int *motionX;
int32 bestSoFar;
{
/* too lazy to write the code for this... */
return FindBestMatchExhaust(block, currentBlock, prev,
by, bx, motionY, motionX, bestSoFar);
}
/*===========================================================================*
*
* BMotionSearchNoInterp
*
* finds the best backward and forward motion vectors
* if backNeeded == FALSE, then won't find best backward vector if it
* is worse than the best forward vector
*
* RETURNS: (*fmy,*fmx) and associated error *forwardErr
* (*bmy,*bmx) and associated error *backErr
*
* SIDE EFFECTS: none
*
*===========================================================================*/
static void
BMotionSearchNoInterp(currentBlock, prev, next, by, bx, fmy, fmx, forwardErr,
bmy, bmx, backErr, backNeeded)
LumBlock currentBlock;
MpegFrame *prev;
MpegFrame *next;
int by;
int bx;
int *fmy;
int *fmx;
int *forwardErr;
int *bmy;
int *bmx;
int *backErr;
boolean backNeeded;
{
/* CALL SEARCH PROCEDURE */
switch(psearchAlg) {
case PSEARCH_SUBSAMPLE:
*forwardErr = PSubSampleSearch(currentBlock, prev, by, bx,
fmy, fmx);
*backErr = PSubSampleSearch(currentBlock, next, by, bx, bmy, bmx);
break;
case PSEARCH_EXHAUSTIVE:
*forwardErr = PLocalSearch(currentBlock, prev, by, bx, fmy, fmx, 0x7fffffff);
if ( backNeeded ) {
*backErr = PLocalSearch(currentBlock, next, by, bx, bmy, bmx, 0x7fffffff);
} else {
*backErr = PLocalSearch(currentBlock, next, by, bx, bmy, bmx, *forwardErr);
}
break;
case PSEARCH_LOGARITHMIC:
*forwardErr = PLogarithmicSearch(currentBlock, prev, by, bx, fmy, fmx);
*backErr = PLogarithmicSearch(currentBlock, next, by, bx, bmy, bmx);
break;
case PSEARCH_TWOLEVEL:
*forwardErr = PTwoLevelSearch(currentBlock, prev, by, bx, fmy, fmx, 0x7fffffff);
if ( backNeeded ) {
*backErr = PTwoLevelSearch(currentBlock, next, by, bx, bmy, bmx, 0x7fffffff);
} else {
*backErr = PTwoLevelSearch(currentBlock, next, by, bx, bmy, bmx, *forwardErr);
}
break;
default:
fprintf(stderr, "ERROR: Illegal PSEARCH ALG: %d\n", psearchAlg);
exit(1);
break;
}
}
/*===========================================================================*
* *
* UNUSED PROCEDURES *
* *
* The following procedures are all unused by the encoder *
* *
* They are listed here for your convenience. You might want to use *
* them if you experiment with different search techniques *
* *
*===========================================================================*/
#ifdef UNUSED_PROCEDURES
/*===========================================================================*
*
* ValidBMotion
*
* decides if the given B-frame motion is valid
*
* RETURNS: TRUE if the motion is valid, FALSE otherwise
*
* SIDE EFFECTS: none
*
*===========================================================================*/
boolean
ValidBMotion(by, bx, mode, fmy, fmx, bmy, bmx)
int by;
int bx;
int mode;
int fmy;
int fmx;
int bmy;
int bmx;
{
if ( mode != MOTION_BACKWARD ) {
/* check forward motion for bounds */
if ( (by*DCTSIZE+(fmy-1)/2 < 0) || ((by+2)*DCTSIZE+(fmy+1)/2-1 >= Fsize_y) ) {
return FALSE;
}
if ( (bx*DCTSIZE+(fmx-1)/2 < 0) || ((bx+2)*DCTSIZE+(fmx+1)/2-1 >= Fsize_x) ) {
return FALSE;
}
}
if ( mode != MOTION_FORWARD ) {
/* check backward motion for bounds */
if ( (by*DCTSIZE+(bmy-1)/2 < 0) || ((by+2)*DCTSIZE+(bmy+1)/2-1 >= Fsize_y) ) {
return FALSE;
}
if ( (bx*DCTSIZE+(bmx-1)/2 < 0) || ((bx+2)*DCTSIZE+(bmx+1)/2-1 >= Fsize_x) ) {
return FALSE;
}
}
return TRUE;
}
#endif UNUSED_PROCEDURES