1 /*===========================================================================*
2  * psearch.c
3  *
4  *  Procedures concerned with the P-frame motion search
5  *
6  *===========================================================================*/
7 
8 /*==============*
9  * HEADER FILES *
10  *==============*/
11 
12 #include "all.h"
13 #include "mtypes.h"
14 #include "frames.h"
15 #include "motion_search.h"
16 #include "prototypes.h"
17 #include "fsize.h"
18 #include "param.h"
19 #include "subsample.h"
20 #include "block.h"
21 
22 
23 /*==================*
24  * STATIC VARIABLES *
25  *==================*/
26 
27 /* none */
28 
29 
30 /*==================*
31  * GLOBAL VARIABLES *
32  *==================*/
33 
34 int **pmvHistogram = NULL;  /* histogram of P-frame motion vectors */
35 int **bbmvHistogram = NULL; /* histogram of B-frame bkwd motion vectors */
36 int **bfmvHistogram = NULL; /* histogram of B-frame fwd motion vectors */
37 int pixelFullSearch;
38 int searchRangeP,searchRangeB;
39 /* The range, in half pixels in each direction, that we are to search
40        when detecting motion.  Specified by RANGE statement in parameter file.
41     */
42 int psearchAlg;
43 /* specified by parameter file. */
44 
45 /*===============================*
46  * INTERNAL PROCEDURE prototypes *
47  *===============================*/
48 
49 
50 /*=====================*
51  * EXPORTED PROCEDURES *
52  *=====================*/
53 
54 /*===========================================================================*
55  *
56  *  Compute the best P-frame motion vector we can.  If it's better than
57  *  *motionP, update *motionP to it.
58  *
59  * PRECONDITIONS:   The relevant block in 'current' is valid (it has not
60  *          been dct'd).  Thus, the data in 'current' can be
61  *          accessed through y_blocks, cr_blocks, and cb_blocks.
62  *          This is not the case for the blocks in 'prev.'
63  *          Therefore, references into 'prev' should be done
64  *          through the struct items ref_y, ref_cr, ref_cb
65  *
66  * POSTCONDITIONS:  current, prev unchanged.
67  *          Some computation could be saved by requiring
68  *          the dct'd difference to be put into current's block
69  *          elements here, depending on the search technique.
70  *          However, it was decided that it mucks up the code
71  *          organization a little, and the saving in computation
72  *          would be relatively little (if any).
73  *
74  * NOTES:   the search procedure need not check the (0,0) motion vector
75  *      the calling procedure has a preference toward (0,0) and it
76  *      will check it itself
77  *
78  * SIDE EFFECTS:    none
79  *
80  *===========================================================================*/
81 void
PMotionSearch(const LumBlock * const currentBlockP,MpegFrame * const prev,int const by,int const bx,vector * const motionP)82 PMotionSearch(const LumBlock * const currentBlockP,
83               MpegFrame *      const prev,
84               int              const by,
85               int              const bx,
86               vector *         const motionP) {
87 
88     /* CALL SEARCH PROCEDURE */
89 
90     switch(psearchAlg) {
91     case PSEARCH_SUBSAMPLE:
92         PSubSampleSearch(currentBlockP, prev, by, bx, motionP, searchRangeP);
93         break;
94     case PSEARCH_EXHAUSTIVE:
95         PLocalSearch(currentBlockP, prev, by, bx,
96                      motionP, INT_MAX, searchRangeP);
97         break;
98     case PSEARCH_LOGARITHMIC:
99         PLogarithmicSearch(currentBlockP, prev, by, bx, motionP, searchRangeP);
100         break;
101     case PSEARCH_TWOLEVEL:
102         PTwoLevelSearch(currentBlockP, prev, by, bx,
103                         motionP, INT_MAX, searchRangeP);
104         break;
105     default:
106         pm_error("IMPOSSIBLE PSEARCH ALG:  %d", psearchAlg);
107     }
108 }
109 
110 
111 
112 /*===========================================================================*
113  *
114  * SetPixelSearch
115  *
116  *  set the pixel search type (half or full)
117  *
118  * RETURNS: nothing
119  *
120  * SIDE EFFECTS:    pixelFullSearch
121  *
122  *===========================================================================*/
123 void
SetPixelSearch(const char * const searchType)124 SetPixelSearch(const char * const searchType) {
125     if ( (strcmp(searchType, "FULL") == 0 ) ||
126          ( strcmp(searchType, "WHOLE") == 0 )) {
127         pixelFullSearch = TRUE;
128     } else if ( strcmp(searchType, "HALF") == 0 ) {
129         pixelFullSearch = FALSE;
130     } else {
131         fprintf(stderr, "ERROR:  Invalid pixel search type:  %s\n",
132                 searchType);
133         exit(1);
134     }
135 }
136 
137 
138 /*===========================================================================*
139  *
140  * SetPSearchAlg
141  *
142  *  set the P-search algorithm
143  *
144  * RETURNS: nothing
145  *
146  * SIDE EFFECTS:    psearchAlg
147  *
148  *===========================================================================*/
149 void
SetPSearchAlg(const char * const alg)150 SetPSearchAlg(const char * const alg)
151 {
152     if ( strcmp(alg, "EXHAUSTIVE") == 0 ) {
153         psearchAlg = PSEARCH_EXHAUSTIVE;
154     } else if (strcmp(alg, "SUBSAMPLE") == 0 ) {
155         psearchAlg = PSEARCH_SUBSAMPLE;
156     } else if ( strcmp(alg, "LOGARITHMIC") == 0 ) {
157         psearchAlg = PSEARCH_LOGARITHMIC;
158     } else if ( strcmp(alg, "TWOLEVEL") == 0 ) {
159         psearchAlg = PSEARCH_TWOLEVEL;
160     } else {
161         fprintf(stderr, "ERROR:  Invalid psearch algorithm:  %s\n", alg);
162         exit(1);
163     }
164 }
165 
166 
167 /*===========================================================================*
168  *
169  * PSearchName
170  *
171  *  returns a string containing the name of the search algorithm
172  *
173  * RETURNS: pointer to the string
174  *
175  * SIDE EFFECTS:    none
176  *
177  *===========================================================================*/
178 const char *
PSearchName(void)179 PSearchName(void)
180 {
181     const char *retval;
182 
183     switch(psearchAlg) {
184     case PSEARCH_EXHAUSTIVE:
185         retval = "EXHAUSTIVE";break;
186     case PSEARCH_SUBSAMPLE:
187         retval = "SUBSAMPLE";break;
188     case PSEARCH_LOGARITHMIC:
189         retval = "LOGARITHMIC";break;
190     case PSEARCH_TWOLEVEL:
191         retval = "TWOLEVEL";break;
192     default:
193         fprintf(stderr, "ERROR:  Illegal PSEARCH ALG:  %d\n", psearchAlg);
194         exit(1);
195         break;
196     }
197     return retval;
198 }
199 
200 
201 /*===========================================================================*
202  *
203  * SetSearchRange
204  *
205  *  sets the range of the search to the given number of pixels,
206  *  allocate histogram storage
207  *
208  *===========================================================================*/
209 void
SetSearchRange(int const pixelsP,int const pixelsB)210 SetSearchRange(int const pixelsP, int const pixelsB) {
211 
212     searchRangeP = 2*pixelsP;   /* +/- 'pixels' pixels */
213     searchRangeB = 2*pixelsB;
214 
215     if ( computeMVHist ) {
216         int const max_search = max(searchRangeP, searchRangeB);
217 
218         int index;
219 
220         pmvHistogram = (int **) malloc((2*searchRangeP+3)*sizeof(int *));
221         bbmvHistogram = (int **) malloc((2*searchRangeB+3)*sizeof(int *));
222         bfmvHistogram = (int **) malloc((2*searchRangeB+3)*sizeof(int *));
223         for ( index = 0; index < 2*max_search+3; index++ ) {
224             pmvHistogram[index] =
225                 (int *) calloc(2*searchRangeP+3, sizeof(int));
226             bbmvHistogram[index] =
227                 (int *) calloc(2*searchRangeB+3, sizeof(int));
228             bfmvHistogram[index] =
229                 (int *) calloc(2*searchRangeB+3, sizeof(int));
230         }
231     }
232 }
233 
234 
235 /*===========================================================================*
236  *
237  *              USER-MODIFIABLE
238  *
239  * MotionSearchPreComputation
240  *
241  *  do whatever you want here; this is called once per frame, directly
242  *  after reading
243  *
244  * RETURNS: whatever
245  *
246  * SIDE EFFECTS:    whatever
247  *
248  *===========================================================================*/
249 void
MotionSearchPreComputation(MpegFrame * const frameP)250 MotionSearchPreComputation(MpegFrame * const frameP) {
251     /* do nothing */
252 }
253 
254 
255 /*===========================================================================*
256  *
257  * PSubSampleSearch
258  *
259  *  uses the subsampling algorithm to compute the P-frame vector
260  *
261  * RETURNS: motion vector
262  *
263  * SIDE EFFECTS:    none
264  *
265  * REFERENCE:  Liu and Zaccarin:  New Fast Algorithms for the Estimation
266  *      of Block Motion Vectors, IEEE Transactions on Circuits
267  *      and Systems for Video Technology, Vol. 3, No. 2, 1993.
268  *
269  *===========================================================================*/
270 int
PSubSampleSearch(const LumBlock * const currentBlockP,MpegFrame * const prev,int const by,int const bx,vector * const motionP,int const searchRange)271 PSubSampleSearch(const LumBlock * const currentBlockP,
272                  MpegFrame *      const prev,
273                  int              const by,
274                  int              const bx,
275                  vector *         const motionP,
276                  int              const searchRange) {
277 
278     int my, mx;
279     int bestBestDiff;
280     int stepSize;
281     int x;
282     int bestMY[4], bestMX[4], bestDiff[4];
283     int leftMY, leftMX;
284     int rightMY, rightMX;
285 
286     stepSize = (pixelFullSearch ? 2 : 1);
287 
288     COMPUTE_MOTION_BOUNDARY(by,bx,stepSize,leftMY,leftMX,rightMY,rightMX);
289 
290     if ( searchRange < rightMY ) {
291         rightMY = searchRange;
292     }
293 
294     if ( searchRange < rightMX ) {
295         rightMX = searchRange;
296     }
297 
298     for ( x = 0; x < 4; x++ ) {
299         bestMY[x] = 0;
300         bestMX[x] = 0;
301         bestDiff[x] = INT_MAX;
302     }
303 
304     /* do A pattern */
305     for (my = -searchRange; my < rightMY; my += 2*stepSize) {
306         if (my >= leftMY) {
307             for ( mx = -searchRange; mx < rightMX; mx += 2*stepSize ) {
308                 if (mx >= leftMX) {
309                     int diff;
310                     vector m;
311                     m.y = my; m.x = mx;
312                     diff = LumMotionErrorA(currentBlockP, prev, by, bx, m,
313                                            bestDiff[0]);
314 
315                     if (diff < bestDiff[0]) {
316                         bestMY[0] = my;
317                         bestMX[0] = mx;
318                         bestDiff[0] = diff;
319                     }
320                 }
321             }
322         }
323     }
324 
325     /* do B pattern */
326     for (my = stepSize-searchRange; my < rightMY; my += 2*stepSize) {
327         if (my >= leftMY) {
328             for (mx = -searchRange; mx < rightMX; mx += 2*stepSize) {
329                 if (mx >= leftMX) {
330                     int diff;
331                     vector m;
332                     m.y = my; m.x = mx;
333                     diff = LumMotionErrorB(currentBlockP, prev, by, bx, m,
334                                            bestDiff[1]);
335 
336                     if (diff < bestDiff[1]) {
337                         bestMY[1] = my;
338                         bestMX[1] = mx;
339                         bestDiff[1] = diff;
340                     }
341                 }
342             }
343         }
344     }
345 
346     /* do C pattern */
347     for (my = stepSize-searchRange; my < rightMY; my += 2*stepSize) {
348         if (my >= leftMY) {
349             for ( mx = stepSize-searchRange; mx < rightMX; mx += 2*stepSize ) {
350                 if (mx >= leftMX) {
351                     int diff;
352                     vector m;
353                     m.y = my; m.x = mx;
354                     diff = LumMotionErrorC(currentBlockP, prev, by, bx, m,
355                                            bestDiff[2]);
356 
357                     if (diff < bestDiff[2]) {
358                         bestMY[2] = my;
359                         bestMX[2] = mx;
360                         bestDiff[2] = diff;
361                     }
362                 }
363             }
364         }
365     }
366 
367     /* do D pattern */
368     for (my = -searchRange; my < rightMY; my += 2*stepSize) {
369         if (my >= leftMY) {
370             for (mx = stepSize-searchRange; mx < rightMX; mx += 2*stepSize) {
371                 if (mx >= leftMX) {
372                     int diff;
373                     vector m;
374                     m.y = my; m.x = mx;
375                     diff = LumMotionErrorD(currentBlockP, prev, by, bx, m,
376                                            bestDiff[3]);
377 
378                     if (diff < bestDiff[3]) {
379                         bestMY[3] = my;
380                         bestMX[3] = mx;
381                         bestDiff[3] = diff;
382                     }
383                 }
384             }
385         }
386     }
387 
388     /* first check old motion */
389     if ((motionP->y >= leftMY) && (motionP->y < rightMY) &&
390         (motionP->x >= leftMX) && (motionP->x < rightMX)) {
391         bestBestDiff = LumMotionError(currentBlockP, prev, by, bx,
392                                       *motionP, INT_MAX);
393     } else
394         bestBestDiff = INT_MAX;
395 
396     /* look at Error of 4 different motion vectors */
397     for (x = 0; x < 4; ++x) {
398         vector m;
399         m.y = bestMY[x];
400         m.x = bestMX[x];
401         bestDiff[x] = LumMotionError(currentBlockP, prev, by, bx, m,
402                                      bestBestDiff);
403 
404         if (bestDiff[x] < bestBestDiff) {
405             bestBestDiff = bestDiff[x];
406             *motionP     = m;
407         }
408     }
409     return bestBestDiff;
410 }
411 
412 
413 
414 static void
findBestSpaced(int const minMY,int const minMX,int const maxMY,int const maxMX,int const spacing,const LumBlock * const currentBlockP,MpegFrame * const prev,int const by,int const bx,int * const bestDiffP,vector * const centerP)415 findBestSpaced(int              const minMY,
416                int              const minMX,
417                int              const maxMY,
418                int              const maxMX,
419                int              const spacing,
420                const LumBlock * const currentBlockP,
421                MpegFrame *      const prev,
422                int              const by,
423                int              const bx,
424                int *            const bestDiffP,
425                vector *         const centerP) {
426 /*----------------------------------------------------------------------------
427    Examine every 'spacing'th half-pixel within the rectangle
428    ('minBoundX', 'minBoundY', 'maxBoundX', 'maxBoundY'),
429 
430    If one of the half-pixels examined has a lower "LumMotionError" value
431    than *bestDiffP, update *bestDiffP to that value and update
432    *centerP to the location of that half-pixel.
433 -----------------------------------------------------------------------------*/
434     int const minBoundY = MAX(minMY, centerP->y - spacing);
435     int const minBoundX = MAX(minMX, centerP->x - spacing);
436     int const maxBoundY = MIN(maxMY, centerP->y + spacing + 1);
437     int const maxBoundX = MIN(maxMX, centerP->x + spacing + 1);
438 
439     int my;
440 
441     for (my = minBoundY; my < maxBoundY; my += spacing) {
442         int mx;
443 
444         for (mx = minBoundX; mx < maxBoundX; mx += spacing) {
445             int diff;
446             vector m;
447 
448             m.y = my; m.x = mx;
449 
450             diff = LumMotionError(currentBlockP, prev, by, bx, m, *bestDiffP);
451 
452             if (diff < *bestDiffP) {
453                 *centerP   = m;
454                 *bestDiffP = diff;
455             }
456         }
457     }
458 }
459 
460 
461 
462 /*===========================================================================*
463  *
464  * PLogarithmicSearch
465  *
466  *  uses logarithmic search to compute the P-frame vector
467  *
468  * RETURNS: motion vector
469  *
470  * SIDE EFFECTS:    none
471  *
472  * REFERENCE:  MPEG-I specification, pages 32-33
473  *
474  *===========================================================================*/
475 int
PLogarithmicSearch(const LumBlock * const currentBlockP,MpegFrame * const prev,int const by,int const bx,vector * const motionP,int const searchRange)476 PLogarithmicSearch(const LumBlock * const currentBlockP,
477                    MpegFrame *      const prev,
478                    int              const by,
479                    int              const bx,
480                    vector *         const motionP,
481                    int              const searchRange) {
482 
483     int const stepSize = (pixelFullSearch ? 2 : 1);
484 
485     int minMY, minMX, maxMY, maxMX;
486     int spacing;  /* grid spacing */
487     vector motion;
488         /* Distance from (bx,by) (in half-pixels) of the block that is most
489            like the current block among those that we have examined so far.
490            (0,0) means we haven't examined any.
491         */
492     int bestDiff;
493         /* The difference between the current block and the block offset
494            'motion' from it.
495         */
496 
497     COMPUTE_MOTION_BOUNDARY(by, bx, stepSize, minMY, minMX, maxMY, maxMX);
498     minMX = max(minMX, - searchRange);
499     minMY = max(minMY, - searchRange);
500     maxMX = min(maxMX, + searchRange);
501     maxMY = min(maxMY, + searchRange);
502 
503     /* Note: The clipping to 'searchRange' above may seem superfluous because
504        the basic algorithm would never want to look more than 'searchRange'
505        pixels away, but with rounding error, it can.
506     */
507 
508     motion.x = motion.y = 0;
509     bestDiff = INT_MAX;
510 
511     for (spacing = searchRange; spacing >= stepSize;) {
512         if (stepSize == 2) {  /* make sure spacing is even */
513             if (spacing == 2)
514                 spacing = 0;
515             else {
516                 spacing = (spacing+1)/2;
517                 if (spacing % 2 != 0)
518                     --spacing;
519             }
520         } else {
521             if (spacing == 1) {
522                 spacing = 0;
523             } else
524                 spacing = (spacing + 1) / 2;
525         }
526         if (spacing >= stepSize)
527             findBestSpaced(minMY, minMX, maxMY, maxMX,
528                            spacing, currentBlockP, prev, by, bx,
529                            &bestDiff, &motion);
530     }
531 
532     {
533         int diff;
534         /* check old motion -- see if it's better */
535         if ((motionP->y >= minMY) && (motionP->y < maxMY) &&
536             (motionP->x >= minMX) && (motionP->x < maxMX)) {
537             diff = LumMotionError(currentBlockP, prev, by, bx,
538                                   *motionP, bestDiff);
539         } else
540             diff = INT_MAX;
541 
542         if (bestDiff < diff)
543             *motionP = motion;
544         else
545             bestDiff = diff;
546     }
547 
548     return bestDiff;
549 }
550 
551 
552 
553 /*===========================================================================*
554  *
555  * PLocalSearch
556  *
557  *  uses local exhaustive search to compute the P-frame vector
558  *
559  * RETURNS: motion vector
560  *
561  * SIDE EFFECTS:    none
562  *
563  *===========================================================================*/
564 int
PLocalSearch(const LumBlock * const currentBlockP,MpegFrame * const prev,int const by,int const bx,vector * const motionP,int const bestSoFar,int const searchRange)565 PLocalSearch(const LumBlock * const currentBlockP,
566              MpegFrame *      const prev,
567              int              const by,
568              int              const bx,
569              vector *         const motionP,
570              int              const bestSoFar,
571              int              const searchRange) {
572 
573     int mx, my;
574     int bestDiff;
575     int stepSize;
576     int leftMY, leftMX;
577     int rightMY, rightMX;
578     int distance;
579     int tempRightMY, tempRightMX;
580 
581     stepSize = (pixelFullSearch ? 2 : 1);
582 
583     COMPUTE_MOTION_BOUNDARY(by,bx,stepSize,leftMY,leftMX,rightMY,rightMX);
584 
585     /* try old motion vector first */
586     if (VALID_MOTION(*motionP)) {
587         bestDiff = LumMotionError(currentBlockP, prev, by, bx,
588                                   *motionP, bestSoFar);
589 
590         if (bestSoFar < bestDiff)
591             bestDiff = bestSoFar;
592     } else {
593         motionP->y = motionP->x = 0;
594         bestDiff = bestSoFar;
595     }
596 
597     /* try a spiral pattern */
598     for (distance = stepSize; distance <= searchRange; distance += stepSize) {
599         tempRightMY = MIN(distance, rightMY);
600         tempRightMX = MIN(distance, rightMX);
601 
602         /* do top, bottom */
603         for (my = -distance; my < tempRightMY;
604              my += max(tempRightMY+distance-stepSize, stepSize)) {
605             if (my >= leftMY) {
606                 for ( mx = -distance; mx < tempRightMX; mx += stepSize ) {
607                     if (mx >= leftMX) {
608                         int diff;
609                         vector m;
610 
611                         m.y = my; m.x = mx;
612                         diff = LumMotionError(currentBlockP, prev, by, bx, m,
613                                               bestDiff);
614 
615                         if (diff < bestDiff) {
616                             *motionP = m;
617                             bestDiff = diff;
618                         }
619                     }
620                 }
621             }
622         }
623 
624         /* do left, right */
625         for (mx = -distance; mx < tempRightMX;
626              mx += max(tempRightMX+distance-stepSize, stepSize)) {
627 
628             if (mx >= leftMX) {
629                 for (my = -distance+stepSize; my < tempRightMY-stepSize;
630                      my += stepSize) {
631                     if (my >= leftMY) {
632                         int diff;
633                         vector m;
634 
635                         m.y = my; m.x = mx;
636                         diff = LumMotionError(currentBlockP, prev, by, bx, m,
637                                               bestDiff);
638 
639                         if (diff < bestDiff) {
640                             *motionP = m;
641                             bestDiff = diff;
642                         }
643                     }
644                 }
645             }
646         }
647     }
648     return bestDiff;
649 }
650 
651 
652 /*===========================================================================*
653  *
654  * PTwoLevelSearch
655  *
656  *  uses two-level search to compute the P-frame vector
657  *  first does exhaustive full-pixel search, then looks at neighboring
658  *  half-pixel motion vectors
659  *
660  * RETURNS: motion vector
661  *
662  * SIDE EFFECTS:    none
663  *
664  *===========================================================================*/
665 int
PTwoLevelSearch(const LumBlock * const currentBlockP,MpegFrame * const prev,int const by,int const bx,vector * const motionP,int const bestSoFar,int const searchRange)666 PTwoLevelSearch(const LumBlock * const currentBlockP,
667                 MpegFrame *      const prev,
668                 int              const by,
669                 int              const bx,
670                 vector *         const motionP,
671                 int              const bestSoFar,
672                 int              const searchRange) {
673     int mx, my;
674     int loopInc;
675     int diff, bestDiff;
676     int leftMY, leftMX;
677     int rightMY, rightMX;
678     int distance;
679     int tempRightMY, tempRightMX;
680     int xOffset, yOffset;
681 
682     /* exhaustive full-pixel search first */
683 
684     COMPUTE_MOTION_BOUNDARY(by,bx,2,leftMY,leftMX,rightMY,rightMX);
685 
686     rightMY--;
687     rightMX--;
688 
689     /* convert vector into full-pixel vector */
690     if (motionP->y > 0) {
691         if ((motionP->y % 2) == 1) {
692             --motionP->y;
693         }
694     } else if (((-motionP->y) % 2) == 1)
695         ++motionP->y;
696 
697     if (motionP->x > 0) {
698         if ((motionP->x % 2) == 1)
699             --motionP->x;
700     } else if ((-motionP->x % 2) == 1)
701         ++motionP->x;
702 
703     /* try old motion vector first */
704     if (VALID_MOTION(*motionP)) {
705         bestDiff = LumMotionError(currentBlockP, prev, by, bx,
706                                   *motionP, bestSoFar);
707 
708         if ( bestSoFar < bestDiff ) {
709             bestDiff = bestSoFar;
710         }
711     } else {
712         motionP->y = motionP->x = 0;
713         bestDiff = bestSoFar;
714     }
715 
716     ++rightMY;
717     ++rightMX;
718 
719     /* try a spiral pattern */
720     for ( distance = 2; distance <= searchRange; distance += 2 ) {
721         tempRightMY = MIN(distance, rightMY);
722         tempRightMX = MIN(distance, rightMX);
723 
724         /* do top, bottom */
725         loopInc = max(tempRightMY + distance - 2, 2);
726         for (my = -distance; my < tempRightMY; my += loopInc) {
727             if (my >= leftMY) {
728                 for (mx = -distance; mx < tempRightMX; mx += 2) {
729                     if (mx >= leftMX) {
730                         vector m;
731                         m.y = my; m.x = mx;
732                         diff = LumMotionError(currentBlockP, prev, by, bx, m,
733                                               bestDiff);
734 
735                         if (diff < bestDiff) {
736                             *motionP = m;
737                             bestDiff = diff;
738                         }
739                     }
740                 }
741             }
742         }
743 
744         /* do left, right */
745         loopInc = max(tempRightMX+distance-2, 2);
746         for (mx = -distance; mx < tempRightMX; mx += loopInc) {
747             if (mx >= leftMX) {
748                 for ( my = -distance+2; my < tempRightMY-2; my += 2 ) {
749                     if (my >= leftMY) {
750                         int diff;
751                         vector m;
752                         m.y = my; m.x = mx;
753                         diff = LumMotionError(currentBlockP, prev, by, bx, m,
754                                               bestDiff);
755 
756                         if ( diff < bestDiff ) {
757                             *motionP = m;
758                             bestDiff = diff;
759                         }
760                     }
761                 }
762             }
763         }
764     }
765 
766     /* now look at neighboring half-pixels */
767     my = motionP->y;
768     mx = motionP->x;
769 
770     --rightMY;
771     --rightMX;
772 
773     for (yOffset = -1; yOffset <= 1; ++yOffset) {
774         for (xOffset = -1; xOffset <= 1; ++xOffset) {
775             if ((yOffset != 0) || (xOffset != 0)) {
776                 vector m;
777                 m.y = my+yOffset; m.x = mx+xOffset;
778                 if (VALID_MOTION(m)) {
779                     int diff;
780                     diff = LumMotionError(currentBlockP, prev, by, bx,
781                                           m, bestDiff);
782                     if (diff < bestDiff) {
783                         *motionP = m;
784                         bestDiff = diff;
785                     }
786                 }
787             }
788         }
789     }
790     return bestDiff;
791 }
792 
793 
794 
795 void
ShowPMVHistogram(fpointer)796 ShowPMVHistogram(fpointer)
797     FILE *fpointer;
798 {
799     register int x, y;
800     int *columnTotals;
801     int rowTotal;
802 
803     columnTotals = (int *) calloc(2*searchRangeP+3, sizeof(int));
804 
805 #ifdef COMPLETE_DISPLAY
806     fprintf(fpointer, "    ");
807     for ( y = 0; y < 2*searchRange+3; y++ ) {
808         fprintf(fpointer, "%3d ", y-searchRangeP-1);
809     }
810     fprintf(fpointer, "\n");
811 #endif
812 
813     for ( x = 0; x < 2*searchRangeP+3; x++ ) {
814 #ifdef COMPLETE_DISPLAY
815         fprintf(fpointer, "%3d ", x-searchRangeP-1);
816 #endif
817         rowTotal = 0;
818         for ( y = 0; y < 2*searchRangeP+3; y++ ) {
819             fprintf(fpointer, "%3d ", pmvHistogram[x][y]);
820             rowTotal += pmvHistogram[x][y];
821             columnTotals[y] += pmvHistogram[x][y];
822         }
823 #ifdef COMPLETE_DISPLAY
824         fprintf(fpointer, "%4d\n", rowTotal);
825 #else
826         fprintf(fpointer, "\n");
827 #endif
828     }
829 
830 #ifdef COMPLETE_DISPLAY
831     fprintf(fpointer, "Tot ");
832     for ( y = 0; y < 2*searchRangeP+3; y++ ) {
833         fprintf(fpointer, "%3d ", columnTotals[y]);
834     }
835 #endif
836     fprintf(fpointer, "\n");
837 }
838 
839 
840 void
ShowBBMVHistogram(fpointer)841 ShowBBMVHistogram(fpointer)
842     FILE *fpointer;
843 {
844     register int x, y;
845     int *columnTotals;
846     int rowTotal;
847 
848     fprintf(fpointer, "B-frame Backwards:\n");
849 
850     columnTotals = (int *) calloc(2*searchRangeB+3, sizeof(int));
851 
852 #ifdef COMPLETE_DISPLAY
853     fprintf(fpointer, "    ");
854     for ( y = 0; y < 2*searchRangeB+3; y++ ) {
855         fprintf(fpointer, "%3d ", y-searchRangeB-1);
856     }
857     fprintf(fpointer, "\n");
858 #endif
859 
860     for ( x = 0; x < 2*searchRangeB+3; x++ ) {
861 #ifdef COMPLETE_DISPLAY
862         fprintf(fpointer, "%3d ", x-searchRangeB-1);
863 #endif
864         rowTotal = 0;
865         for ( y = 0; y < 2*searchRangeB+3; y++ ) {
866             fprintf(fpointer, "%3d ", bbmvHistogram[x][y]);
867             rowTotal += bbmvHistogram[x][y];
868             columnTotals[y] += bbmvHistogram[x][y];
869         }
870 #ifdef COMPLETE_DISPLAY
871         fprintf(fpointer, "%4d\n", rowTotal);
872 #else
873         fprintf(fpointer, "\n");
874 #endif
875     }
876 
877 #ifdef COMPLETE_DISPLAY
878     fprintf(fpointer, "Tot ");
879     for ( y = 0; y < 2*searchRangeB+3; y++ ) {
880         fprintf(fpointer, "%3d ", columnTotals[y]);
881     }
882 #endif
883     fprintf(fpointer, "\n");
884 }
885 
886 
887 void
ShowBFMVHistogram(fpointer)888 ShowBFMVHistogram(fpointer)
889     FILE *fpointer;
890 {
891     register int x, y;
892     int *columnTotals;
893     int rowTotal;
894 
895     fprintf(fpointer, "B-frame Forwards:\n");
896 
897     columnTotals = (int *) calloc(2*searchRangeB+3, sizeof(int));
898 
899 #ifdef COMPLETE_DISPLAY
900     fprintf(fpointer, "    ");
901     for ( y = 0; y < 2*searchRangeB+3; y++ ) {
902         fprintf(fpointer, "%3d ", y-searchRangeB-1);
903     }
904     fprintf(fpointer, "\n");
905 #endif
906 
907     for ( x = 0; x < 2*searchRangeB+3; x++ ) {
908 #ifdef COMPLETE_DISPLAY
909         fprintf(fpointer, "%3d ", x-searchRangeB-1);
910 #endif
911         rowTotal = 0;
912         for ( y = 0; y < 2*searchRangeB+3; y++ ) {
913             fprintf(fpointer, "%3d ", bfmvHistogram[x][y]);
914             rowTotal += bfmvHistogram[x][y];
915             columnTotals[y] += bfmvHistogram[x][y];
916         }
917 #ifdef COMPLETE_DISPLAY
918         fprintf(fpointer, "%4d\n", rowTotal);
919 #else
920         fprintf(fpointer, "\n");
921 #endif
922     }
923 
924 #ifdef COMPLETE_DISPLAY
925     fprintf(fpointer, "Tot ");
926     for ( y = 0; y < 2*searchRangeB+3; y++ ) {
927         fprintf(fpointer, "%3d ", columnTotals[y]);
928     }
929 #endif
930     fprintf(fpointer, "\n");
931 }
932 
933 
934 /*
935  * Copyright (c) 1995 The Regents of the University of California.
936  * All rights reserved.
937  *
938  * Permission to use, copy, modify, and distribute this software and its
939  * documentation for any purpose, without fee, and without written agreement is
940  * hereby granted, provided that the above copyright notice and the following
941  * two paragraphs appear in all copies of this software.
942  *
943  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
944  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
945  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
946  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
947  *
948  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
949  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
950  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
951  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
952  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
953  */
954 
955 /*
956  *  $Header: /u/smoot/md/mpeg_encode/RCS/psearch.c,v 1.9 1995/01/19 23:09:12 eyhung Exp $
957  *  $Log: psearch.c,v $
958  * Revision 1.9  1995/01/19  23:09:12  eyhung
959  * Changed copyrights
960  *
961  * Revision 1.9  1995/01/19  23:09:12  eyhung
962  * Changed copyrights
963  *
964  * Revision 1.8  1994/12/07  00:40:36  smoot
965  * Added separate P and B search ranges
966  *
967  * Revision 1.7  1994/11/12  02:09:45  eyhung
968  * full pixel bug
969  * fixed on lines 512 and 563
970  *
971  * Revision 1.6  1994/03/15  00:27:11  keving
972  * nothing
973  *
974  * Revision 1.5  1993/12/22  19:19:01  keving
975  * nothing
976  *
977  * Revision 1.4  1993/07/22  22:23:43  keving
978  * nothing
979  *
980  * Revision 1.3  1993/06/30  20:06:09  keving
981  * nothing
982  *
983  * Revision 1.2  1993/06/03  21:08:08  keving
984  * nothing
985  *
986  * Revision 1.1  1993/03/02  18:27:05  keving
987  * nothing
988  *
989  */
990 
991 
992