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