1 /*===========================================================================*
2  * block.c								     *
3  *									     *
4  *	Block routines							     *
5  *									     *
6  * EXPORTED PROCEDURES:							     *
7  *	ComputeDiffDCTBlock						     *
8  *	ComputeDiffDCTs							     *
9  *	ComputeMotionBlock						     *
10  *	ComputeMotionLumBlock						     *
11  *	LumBlockMAD							     *
12  *	LumMotionError							     *
13  *	LumMotionErrorSubSampled					     *
14  *	LumAddMotionError						     *
15  *	AddMotionBlock							     *
16  *	BlockToData							     *
17  *	BlockifyFrame							     *
18  *									     *
19  * NOTES:   MAD	=   Mean Absolute Difference				     *
20  *									     *
21  *===========================================================================*/
22 
23 /*
24  * Copyright (c) 1995 The Regents of the University of California.
25  * All rights reserved.
26  *
27  * Permission to use, copy, modify, and distribute this software and its
28  * documentation for any purpose, without fee, and without written agreement is
29  * hereby granted, provided that the above copyright notice and the following
30  * two paragraphs appear in all copies of this software.
31  *
32  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
33  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
34  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
35  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  *
37  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
38  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
39  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
40  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
41  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
42  */
43 
44 /*
45  *  $Header: /n/picasso/project/mpeg/mpeg_dist/mpeg_encode/RCS/block.c,v 1.16 1995/08/07 21:43:29 smoot Exp $
46  *  $Log: block.c,v $
47  *  Revision 1.16  1995/08/07 21:43:29  smoot
48  *  restructured lumdiff so it read better and used a switch instead of ifs
49  *
50  *  Revision 1.15  1995/06/21 22:21:16  smoot
51  *  added TUNEing options
52  *
53  * Revision 1.14  1995/05/08  22:47:45  smoot
54  * typechecking better
55  *
56  * Revision 1.13  1995/05/08  22:44:14  smoot
57  * added prototypes (postdct.h)
58  *
59  * Revision 1.12  1995/05/02  21:44:07  smoot
60  * added tuneing parameters
61  *
62  * Revision 1.11  1995/03/31  23:50:45  smoot
63  * removed block bound (moved to opts.c)
64  *
65  * Revision 1.10  1995/03/29  20:12:39  smoot
66  * added block_bound for TUNEing
67  *
68  * Revision 1.9  1995/02/01  21:43:55  smoot
69  * cleanup
70  *
71  * Revision 1.8  1995/01/19  23:52:43  smoot
72  * Made computeDiffDCTs able to rule out changes to the pattern (diff too small)
73  *
74  * Revision 1.7  1995/01/19  23:07:17  eyhung
75  * Changed copyrights
76  *
77  * Revision 1.6  1994/11/12  02:11:44  keving
78  * nothing
79  *
80  * Revision 1.5  1993/12/22  19:19:01  keving
81  * nothing
82  *
83  * Revision 1.5  1993/12/22  19:19:01  keving
84  * nothing
85  *
86  * Revision 1.4  1993/07/22  22:23:43  keving
87  * nothing
88  *
89  * Revision 1.3  1993/06/30  20:06:09  keving
90  * nothing
91  *
92  * Revision 1.2  1993/06/03  21:08:08  keving
93  * nothing
94  *
95  * Revision 1.1  1993/04/08  21:31:59  keving
96  * nothing
97  *
98  */
99 
100 
101 /*==============*
102  * HEADER FILES *
103  *==============*/
104 
105 #include <string.h>
106 #include "all.h"
107 #include "mtypes.h"
108 #include "frames.h"
109 #include "bitio.h"
110 #include "prototypes.h"
111 #include "fsize.h"
112 #include "opts.h"
113 #include "postdct.h"
114 
115 #undef ABS
116 #define ABS(x)	((x < 0) ? (-x) : x)
117 
118 #define TRUNCATE_UINT8(x)	((x < 0) ? 0 : ((x > 255) ? 255 : x))
119 
120 /*==================*
121  * GLOBAL VARIABLES *
122  *==================*/
123 
124 
125 extern Block **dct, **dctb, **dctr;
126 
127 /*===========================*
128  * COMPUTE DCT OF DIFFERENCE *
129  *===========================*/
130 
131 /*===========================================================================*
132  *
133  * ComputeDiffDCTBlock
134  *
135  *	compute current-motionBlock, take the DCT, and put the difference
136  *	back into current
137  *
138  * RETURNS:	current block modified
139  *
140  * SIDE EFFECTS:    none
141  *
142  *===========================================================================*/
143 boolean
ComputeDiffDCTBlock(Block current,Block dest,Block motionBlock)144 ComputeDiffDCTBlock(Block current, Block dest, Block motionBlock)
145 {
146     register int x, y, diff = 0;
147 
148     for ( y = 0; y < 8; y++ ) {
149 	for ( x = 0; x < 8; x++ ) {
150 	  current[y][x] -= motionBlock[y][x];
151 	  diff += ABS(current[y][x]);
152 	}
153     }
154     /* Kill the block if change is too small     */
155     /* (block_bound defaults to 128, see opts.c) */
156     if (diff < block_bound) return FALSE;
157 
158     mp_fwd_dct_block2(current, dest);
159 
160     return TRUE;
161 }
162 
163 /*===========================================================================*
164  *
165  * ComputeDiffDCTs
166  *
167  *	appropriate (according to pattern, the coded block pattern) blocks
168  *	of 'current' are diff'ed and DCT'd.
169  *
170  * RETURNS:	current blocks modified
171  *
172  * SIDE EFFECTS:    Can remove too-small difference blocks from pattern
173  *
174  * PRECONDITIONS:	appropriate blocks of 'current' have not yet been
175  *			modified
176  *
177  *===========================================================================*/
178 void
ComputeDiffDCTs(MpegFrame * current,MpegFrame * prev,int by,int bx,int my,int mx,int * pattern)179 ComputeDiffDCTs(MpegFrame *current,
180                 MpegFrame *prev,
181                 int by,
182                 int bx,
183                 int my,
184                 int mx,
185                 int *pattern)
186 {
187     Block   motionBlock;
188 
189     if (collect_quant && (collect_quant_detailed & 1)) fprintf(collect_quant_fp, "l\n");
190     if ( *pattern & 0x20 ) {
191 	ComputeMotionBlock(prev->ref_y, by, bx, my, mx, motionBlock);
192 	if (!ComputeDiffDCTBlock(current->y_blocks[by][bx], dct[by][bx], motionBlock))
193 	  *pattern^=0x20;
194     }
195 
196     if ( *pattern & 0x10 ) {
197 	ComputeMotionBlock(prev->ref_y, by, bx+1, my, mx, motionBlock);
198 	if (!ComputeDiffDCTBlock(current->y_blocks[by][bx+1], dct[by][bx+1], motionBlock))
199 	  *pattern^=0x10;
200     }
201 
202     if ( *pattern & 0x8 ) {
203 	ComputeMotionBlock(prev->ref_y, by+1, bx, my, mx, motionBlock);
204 	if (!ComputeDiffDCTBlock(current->y_blocks[by+1][bx], dct[by+1][bx], motionBlock))
205 	  *pattern^=0x8;
206     }
207 
208     if ( *pattern & 0x4 ) {
209 	ComputeMotionBlock(prev->ref_y, by+1, bx+1, my, mx, motionBlock);
210 	if (!ComputeDiffDCTBlock(current->y_blocks[by+1][bx+1], dct[by+1][bx+1], motionBlock))
211 	  *pattern^=0x4;
212     }
213 
214     if (collect_quant && (collect_quant_detailed & 1)) fprintf(collect_quant_fp, "c\n");
215     if ( *pattern & 0x2 ) {
216 	ComputeMotionBlock(prev->ref_cb, by >> 1, bx >> 1, my/2, mx/2, motionBlock);
217 	if (!ComputeDiffDCTBlock(current->cb_blocks[by >> 1][bx >> 1], dctb[by >> 1][bx >> 1], motionBlock))
218 	  *pattern^=0x2;
219     }
220 
221     if ( *pattern & 0x1 ) {
222 	ComputeMotionBlock(prev->ref_cr, by >> 1, bx >> 1, my/2, mx/2, motionBlock);
223 	if (!ComputeDiffDCTBlock(current->cr_blocks[by >> 1][bx >> 1], dctr[by >> 1][bx >> 1], motionBlock))
224 	  *pattern^=0x1;
225     }
226 }
227 
228 
229 	/*======================*
230 	 * COMPUTE MOTION BLOCK *
231 	 *======================*/
232 
233 /*===========================================================================*
234  *
235  * ComputeMotionBlock
236  *
237  *	compute the motion-compensated block
238  *
239  * RETURNS:	motionBlock
240  *
241  * SIDE EFFECTS:    none
242  *
243  * PRECONDITIONS:	motion vector MUST be valid
244  *
245  * NOTE:  could try to speed this up using halfX, halfY, halfBoth,
246  *	  but then would have to compute for chrominance, and it's just
247  *	  not worth the trouble (this procedure is not called relatively
248  *	  often -- a constant number of times per macroblock)
249  *
250  *===========================================================================*/
251 void
ComputeMotionBlock(uint8 ** prev,int by,int bx,int my,int mx,Block motionBlock)252 ComputeMotionBlock(uint8 **prev,
253                    int by,
254                    int bx,
255                    int my,
256                    int mx,
257                    Block motionBlock)
258 {
259     register int   fy, fx;
260     register int   y;
261     register int16 *destPtr;
262     register uint8 *srcPtr;
263     register uint8 *srcPtr2;
264     boolean xHalf, yHalf;
265 
266     xHalf = (ABS(mx) % 2 == 1);
267     yHalf = (ABS(my) % 2 == 1);
268 
269     MOTION_TO_FRAME_COORD(by, bx, (my/2), (mx/2), fy, fx);
270 
271     if ( xHalf && yHalf ) {
272 	/* really should be fy+y-1 and fy+y so do (fy-1)+y = fy+y-1 and
273 	   (fy-1)+y+1 = fy+y
274 	 */
275 	if ( my < 0 ) {
276 	    fy--;
277 	}
278 	if ( mx < 0 ) {
279 	    fx--;
280 	}
281 
282 	for ( y = 0; y < 8; y++ ) {
283 	    destPtr = motionBlock[y];
284 	    srcPtr = &(prev[fy+y][fx]);
285 	    srcPtr2 = &(prev[fy+y+1][fx]);
286 
287 	    destPtr[0] = (srcPtr[0]+srcPtr[1]+srcPtr2[0]+srcPtr2[1]+2)>>2;
288 	    destPtr[1] = (srcPtr[1]+srcPtr[2]+srcPtr2[1]+srcPtr2[2]+2)>>2;
289 	    destPtr[2] = (srcPtr[2]+srcPtr[3]+srcPtr2[2]+srcPtr2[3]+2)>>2;
290 	    destPtr[3] = (srcPtr[3]+srcPtr[4]+srcPtr2[3]+srcPtr2[4]+2)>>2;
291 	    destPtr[4] = (srcPtr[4]+srcPtr[5]+srcPtr2[4]+srcPtr2[5]+2)>>2;
292 	    destPtr[5] = (srcPtr[5]+srcPtr[6]+srcPtr2[5]+srcPtr2[6]+2)>>2;
293 	    destPtr[6] = (srcPtr[6]+srcPtr[7]+srcPtr2[6]+srcPtr2[7]+2)>>2;
294 	    destPtr[7] = (srcPtr[7]+srcPtr[8]+srcPtr2[7]+srcPtr2[8]+2)>>2;
295 	}
296     } else if ( xHalf ) {
297 	if ( mx < 0 ) {
298 	    fx--;
299 	}
300 
301 	for ( y = 0; y < 8; y++ ) {
302 	    destPtr = motionBlock[y];
303 	    srcPtr = &(prev[fy+y][fx]);
304 
305 	    destPtr[0] = (srcPtr[0]+srcPtr[1]+1)>>1;
306 	    destPtr[1] = (srcPtr[1]+srcPtr[2]+1)>>1;
307 	    destPtr[2] = (srcPtr[2]+srcPtr[3]+1)>>1;
308 	    destPtr[3] = (srcPtr[3]+srcPtr[4]+1)>>1;
309 	    destPtr[4] = (srcPtr[4]+srcPtr[5]+1)>>1;
310 	    destPtr[5] = (srcPtr[5]+srcPtr[6]+1)>>1;
311 	    destPtr[6] = (srcPtr[6]+srcPtr[7]+1)>>1;
312 	    destPtr[7] = (srcPtr[7]+srcPtr[8]+1)>>1;
313 	}
314     } else if ( yHalf ) {
315 	if ( my < 0 ) {
316 	    fy--;
317 	}
318 
319 	for ( y = 0; y < 8; y++ ) {
320 	    destPtr = motionBlock[y];
321 	    srcPtr = &(prev[fy+y][fx]);
322 	    srcPtr2 = &(prev[fy+y+1][fx]);
323 
324 	    destPtr[0] = (srcPtr[0]+srcPtr2[0]+1)>>1;
325 	    destPtr[1] = (srcPtr[1]+srcPtr2[1]+1)>>1;
326 	    destPtr[2] = (srcPtr[2]+srcPtr2[2]+1)>>1;
327 	    destPtr[3] = (srcPtr[3]+srcPtr2[3]+1)>>1;
328 	    destPtr[4] = (srcPtr[4]+srcPtr2[4]+1)>>1;
329 	    destPtr[5] = (srcPtr[5]+srcPtr2[5]+1)>>1;
330 	    destPtr[6] = (srcPtr[6]+srcPtr2[6]+1)>>1;
331 	    destPtr[7] = (srcPtr[7]+srcPtr2[7]+1)>>1;
332 	}
333     } else {
334 	for ( y = 0; y < 8; y++ ) {
335 	    destPtr = motionBlock[y];
336 	    srcPtr = &(prev[fy+y][fx]);
337 
338 	    destPtr[0] = (uint8) srcPtr[0];
339 	    destPtr[1] = (uint8) srcPtr[1];
340 	    destPtr[2] = (uint8) srcPtr[2];
341 	    destPtr[3] = (uint8) srcPtr[3];
342 	    destPtr[4] = (uint8) srcPtr[4];
343 	    destPtr[5] = (uint8) srcPtr[5];
344 	    destPtr[6] = (uint8) srcPtr[6];
345 	    destPtr[7] = (uint8) srcPtr[7];
346 	}
347     }
348 }
349 
350 
351 /*===========================================================================*
352  *
353  * ComputeMotionLumBlock
354  *
355  *	compute the motion-compensated luminance block
356  *
357  * RETURNS:	motionBlock
358  *
359  * SIDE EFFECTS:    none
360  *
361  * PRECONDITIONS:	motion vector MUST be valid
362  *
363  * NOTE:  see ComputeMotionBlock
364  *
365  *===========================================================================*/
366 void
ComputeMotionLumBlock(MpegFrame * prevFrame,int by,int bx,int my,int mx,LumBlock motionBlock)367 ComputeMotionLumBlock(MpegFrame *prevFrame,
368                       int by,
369                       int bx,
370                       int my,
371                       int mx,
372                       LumBlock motionBlock)
373 {
374     register uint8 *across;
375     register int32 *macross;
376     register int y;
377     uint8 **prev;
378     int	    fy, fx;
379     boolean xHalf, yHalf;
380 
381     xHalf = (ABS(mx) % 2 == 1);
382     yHalf = (ABS(my) % 2 == 1);
383 
384     MOTION_TO_FRAME_COORD(by, bx, my/2, mx/2, fy, fx);
385 
386     if ( xHalf ) {
387 	if ( mx < 0 ) {
388 	    fx--;
389 	}
390 
391 	if ( yHalf ) {
392 	    if ( my < 0 ) {
393 		fy--;
394 	    }
395 
396 	    prev = prevFrame->halfBoth;
397 	} else {
398 	    prev = prevFrame->halfX;
399 	}
400     } else if ( yHalf ) {
401 	if ( my < 0 ) {
402 	    fy--;
403 	}
404 
405 	prev = prevFrame->halfY;
406     } else {
407 	prev = prevFrame->ref_y;
408     }
409 
410     for ( y = 0; y < 16; y++ ) {
411 	across = &(prev[fy+y][fx]);
412 	macross = motionBlock[y];
413 
414 	macross[0] = across[0];
415 	macross[1] = across[1];
416 	macross[2] = across[2];
417 	macross[3] = across[3];
418 	macross[4] = across[4];
419 	macross[5] = across[5];
420 	macross[6] = across[6];
421 	macross[7] = across[7];
422 	macross[8] = across[8];
423 	macross[9] = across[9];
424 	macross[10] = across[10];
425 	macross[11] = across[11];
426 	macross[12] = across[12];
427 	macross[13]= across[13];
428 	macross[14] = across[14];
429 	macross[15] = across[15];
430     }
431 
432     /* this is what's really happening, in slow motion:
433      *
434      *	for ( y = 0; y < 16; y++, py++ )
435      *      for ( x = 0; x < 16; x++, px++ )
436      *		motionBlock[y][x] = prev[fy+y][fx+x];
437      *
438      */
439 }
440 
441 
442 /*=======================*
443  * BASIC ERROR FUNCTIONS *
444  *=======================*/
445 
446 
447 /*===========================================================================*
448  *
449  * LumBlockMAD
450  *
451  *	return the MAD of two luminance blocks
452  *
453  * RETURNS:	the MAD, if less than bestSoFar, or
454  *		some number bigger if not
455  *
456  * SIDE EFFECTS:    none
457  *
458  *===========================================================================*/
459 int32
LumBlockMAD(LumBlock currentBlock,LumBlock motionBlock,int32 bestSoFar)460 LumBlockMAD(LumBlock currentBlock,
461             LumBlock motionBlock,
462             int32 bestSoFar)
463 {
464     register int32   diff = 0;    /* max value of diff is 255*256 = 65280 */
465     register int32 localDiff;
466     register int y, x;
467 
468     for ( y = 0; y < 16; y++ ) {
469 	for ( x = 0; x < 16; x++ ) {
470 	    localDiff = currentBlock[y][x] - motionBlock[y][x];
471 	    diff += ABS(localDiff);
472 	}
473 
474 	if ( diff > bestSoFar ) {
475 	    return diff;
476 	}
477     }
478 
479     return (int32)diff;
480 }
481 
482 
483 /*===========================================================================*
484  *
485  * LumMotionError
486  *
487  *	return the MAD of the currentBlock and the motion-compensated block
488  *      (without TUNEing)
489  *
490  * RETURNS:	the MAD, if less than bestSoFar, or
491  *		some number bigger if not
492  *
493  * SIDE EFFECTS:    none
494  *
495  * PRECONDITIONS:  motion vector MUST be valid
496  *
497  * NOTES:  this is the procedure that is called the most, and should therefore
498  *         be the most optimized!!!
499  *
500  *===========================================================================*/
501 int32
LumMotionError(LumBlock currentBlock,MpegFrame * prevFrame,int by,int bx,int my,int mx,int32 bestSoFar)502 LumMotionError(LumBlock currentBlock,
503                MpegFrame *prevFrame,
504                int by,
505                int bx,
506                int my,
507                int mx,
508                int32 bestSoFar)
509 {
510     register int32 adiff = 0,  diff = 0;    /* max value of diff is 255*256 = 65280 */
511     register int32 localDiff;
512     register uint8 *across;
513     register int32 *cacross;
514     register int y;
515     uint8 **prev;
516     int	    fy, fx;
517     boolean xHalf, yHalf;
518 
519     xHalf = (ABS(mx) % 2 == 1);
520     yHalf = (ABS(my) % 2 == 1);
521 
522     MOTION_TO_FRAME_COORD(by, bx, my/2, mx/2, fy, fx);
523 
524     if ( xHalf ) {
525 	if ( mx < 0 ) {
526 	    fx--;
527 	}
528 
529 	if ( yHalf ) {
530 	    if ( my < 0 ) {
531 		fy--;
532 	    }
533 
534 	    prev = prevFrame->halfBoth;
535 	} else {
536 	    prev = prevFrame->halfX;
537 	}
538     } else if ( yHalf ) {
539 	if ( my < 0 ) {
540 	    fy--;
541 	}
542 
543 	prev = prevFrame->halfY;
544     } else {
545 	prev = prevFrame->ref_y;
546     }
547 
548     switch (SearchCompareMode) {
549     case DEFAULT_SEARCH: /* Default. */
550       /* this is what's happening:
551        *	ComputeMotionLumBlock(prevFrame, by, bx, my, mx, lumMotionBlock);
552        *	for ( y = 0; y < 16; y++ )
553        *	    for ( x = 0; x < 16; x++ )
554        *	    {
555        *		localDiff = currentBlock[y][x] - lumMotionBlock[y][x];
556        *		diff += ABS(localDiff);
557        *	    }
558        */
559       for ( y = 0; y < 16; y++ ) {
560 	across = &(prev[fy+y][fx]);
561 	cacross = currentBlock[y];
562 
563 	localDiff = across[0]-cacross[0];     diff += ABS(localDiff);
564 	localDiff = across[1]-cacross[1];     diff += ABS(localDiff);
565 	localDiff = across[2]-cacross[2];     diff += ABS(localDiff);
566 	localDiff = across[3]-cacross[3];     diff += ABS(localDiff);
567 	localDiff = across[4]-cacross[4];     diff += ABS(localDiff);
568 	localDiff = across[5]-cacross[5];     diff += ABS(localDiff);
569 	localDiff = across[6]-cacross[6];     diff += ABS(localDiff);
570 	localDiff = across[7]-cacross[7];     diff += ABS(localDiff);
571 	localDiff = across[8]-cacross[8];     diff += ABS(localDiff);
572 	localDiff = across[9]-cacross[9];     diff += ABS(localDiff);
573 	localDiff = across[10]-cacross[10];     diff += ABS(localDiff);
574 	localDiff = across[11]-cacross[11];     diff += ABS(localDiff);
575 	localDiff = across[12]-cacross[12];     diff += ABS(localDiff);
576 	localDiff = across[13]-cacross[13];     diff += ABS(localDiff);
577 	localDiff = across[14]-cacross[14];     diff += ABS(localDiff);
578 	localDiff = across[15]-cacross[15];     diff += ABS(localDiff);
579 
580 	if ( diff > bestSoFar ) {
581 	  return diff;
582 	}
583       }
584       break;
585 
586     case LOCAL_DCT: {
587       Block     dctdiff[4], dctquant[4];
588       FlatBlock quant;
589       int x, i, tmp;
590       int distortion=0, datarate=0;
591       int pq = GetPQScale();
592 
593       for (y = 0;  y < 16;  y++) {
594 	across = &(prev[fy+y][fx]);
595 	cacross = currentBlock[y];
596 	for (x = 0;  x < 16;  x++) {
597 	  dctdiff[(x>7)+2*(y>7)][y%8][x%8] = cacross[x]-across[x];
598 	}}
599 
600       /* Calculate rate */
601       for (i = 0;  i < 4;  i++) {
602 	mp_fwd_dct_block2(dctdiff[i], dctdiff[i]);
603 	if (Mpost_QuantZigBlock(dctdiff[i], quant, pq, FALSE) == MPOST_ZERO) {
604 	  /* no sense in continuing */
605 	  memset((char *)dctquant[i], 0, sizeof(Block));
606 	} else {
607 	  Mpost_UnQuantZigBlock(quant, dctquant[i], pq, FALSE);
608 	  mpeg_jrevdct((int16 *)dctquant[i]);
609 	  datarate += CalcRLEHuffLength(quant);
610 	}
611       }
612 
613       /* Calculate distortion */
614       for (y = 0;  y < 16;  y++) {
615 	across = &(prev[fy+y][fx]);
616 	cacross = currentBlock[y];
617 	for (x = 0;  x < 16;  x++) {
618 	  tmp = across[x] - cacross[x] + dctquant[(x>7)+2*(y>7)][y%8][x%8];
619 	  distortion += tmp*tmp;
620 	}}
621       distortion /= 256;
622       distortion *= (int)LocalDCTDistortScale;
623       datarate *= (int)LocalDCTRateScale;
624       diff = (int) sqrt((double)(distortion*distortion + datarate*datarate));
625       break;
626     }
627 
628     case NO_DC_SEARCH: {
629       extern int32 niqtable[];
630       int pq = niqtable[0]*GetPQScale();
631 
632       for ( y = 0; y < 16; y++ ) {
633 	across = &(prev[fy+y][fx]);
634 	cacross = currentBlock[y];
635 
636 	localDiff = across[0]-cacross[0];  diff += localDiff; adiff += ABS(localDiff);
637 	localDiff = across[1]-cacross[1];  diff += localDiff; adiff += ABS(localDiff);
638 	localDiff = across[2]-cacross[2];  diff += localDiff; adiff += ABS(localDiff);
639 	localDiff = across[3]-cacross[3];  diff += localDiff; adiff += ABS(localDiff);
640 	localDiff = across[4]-cacross[4];  diff += localDiff; adiff += ABS(localDiff);
641 	localDiff = across[5]-cacross[5];  diff += localDiff; adiff += ABS(localDiff);
642 	localDiff = across[6]-cacross[6];  diff += localDiff; adiff += ABS(localDiff);
643 	localDiff = across[7]-cacross[7];  diff += localDiff; adiff += ABS(localDiff);
644 	localDiff = across[8]-cacross[8];  diff += localDiff; adiff += ABS(localDiff);
645 	localDiff = across[9]-cacross[9];  diff += localDiff; adiff += ABS(localDiff);
646 	localDiff = across[10]-cacross[10];  diff += localDiff; adiff += ABS(localDiff);
647 	localDiff = across[11]-cacross[11];  diff += localDiff; adiff += ABS(localDiff);
648 	localDiff = across[12]-cacross[12];  diff += localDiff; adiff += ABS(localDiff);
649 	localDiff = across[13]-cacross[13];  diff += localDiff; adiff += ABS(localDiff);
650 	localDiff = across[14]-cacross[14];  diff += localDiff; adiff += ABS(localDiff);
651 	localDiff = across[15]-cacross[15];  diff += localDiff; adiff += ABS(localDiff);
652 
653       }
654 
655       diff /= 64*pq;  /* diff is now the DC difference (with QSCALE 1) */
656       adiff -= 64*pq*ABS(diff);
657       diff = adiff;
658     }
659       break;
660 
661     case DO_Mean_Squared_Distortion:
662       for ( y = 0; y < 16; y++ ) {
663 	across = &(prev[fy+y][fx]);
664 	cacross = currentBlock[y];
665 
666 	localDiff = across[0]-cacross[0];     diff += localDiff*localDiff;
667 	localDiff = across[1]-cacross[1];     diff += localDiff*localDiff;
668 	localDiff = across[2]-cacross[2];     diff += localDiff*localDiff;
669 	localDiff = across[3]-cacross[3];     diff += localDiff*localDiff;
670 	localDiff = across[4]-cacross[4];     diff += localDiff*localDiff;
671 	localDiff = across[5]-cacross[5];     diff += localDiff*localDiff;
672 	localDiff = across[6]-cacross[6];     diff += localDiff*localDiff;
673 	localDiff = across[7]-cacross[7];     diff += localDiff*localDiff;
674 	localDiff = across[8]-cacross[8];     diff += localDiff*localDiff;
675 	localDiff = across[9]-cacross[9];     diff += localDiff*localDiff;
676 	localDiff = across[10]-cacross[10];     diff += localDiff*localDiff;
677 	localDiff = across[11]-cacross[11];     diff += localDiff*localDiff;
678 	localDiff = across[12]-cacross[12];     diff += localDiff*localDiff;
679 	localDiff = across[13]-cacross[13];     diff += localDiff*localDiff;
680 	localDiff = across[14]-cacross[14];     diff += localDiff*localDiff;
681 	localDiff = across[15]-cacross[15];     diff += localDiff*localDiff;
682 
683 	if ( diff > bestSoFar ) {
684 	  return diff;
685 	}
686       }
687       break;
688     } /* End of Switch */
689 
690     return diff;
691 }
692 
693 
694 /*===========================================================================*
695  *
696  * LumAddMotionError
697  *
698  *	return the MAD of the currentBlock and the average of the blockSoFar
699  *	and the motion-compensated block (this is used for B-frame searches)
700  *
701  * RETURNS:	the MAD, if less than bestSoFar, or
702  *		some number bigger if not
703  *
704  * SIDE EFFECTS:    none
705  *
706  * PRECONDITIONS:  motion vector MUST be valid
707  *
708  *===========================================================================*/
709 int32
LumAddMotionError(LumBlock currentBlock,LumBlock blockSoFar,MpegFrame * prevFrame,int by,int bx,int my,int mx,int32 bestSoFar)710 LumAddMotionError(LumBlock currentBlock,
711                   LumBlock blockSoFar,
712                   MpegFrame *prevFrame,
713                   int by,
714                   int bx,
715                   int my,
716                   int mx,
717                   int32 bestSoFar)
718 {
719     register int32   diff = 0;    /* max value of diff is 255*256 = 65280 */
720     register int32 localDiff;
721     register uint8 *across;
722     register int32 *bacross;
723     register int32 *cacross;
724     register int y;
725     uint8 **prev;
726     int	    fy, fx;
727     boolean xHalf, yHalf;
728 
729     xHalf = (ABS(mx) % 2 == 1);
730     yHalf = (ABS(my) % 2 == 1);
731 
732     MOTION_TO_FRAME_COORD(by, bx, my/2, mx/2, fy, fx);
733 
734     if ( xHalf ) {
735 	if ( mx < 0 ) {
736 	    fx--;
737 	}
738 
739 	if ( yHalf ) {
740 	    if ( my < 0 ) {
741 		fy--;
742 	    }
743 
744 	    prev = prevFrame->halfBoth;
745 	} else {
746 	    prev = prevFrame->halfX;
747 	}
748     } else if ( yHalf ) {
749 	if ( my < 0 ) {
750 	    fy--;
751 	}
752 
753 	prev = prevFrame->halfY;
754     } else {
755 	prev = prevFrame->ref_y;
756     }
757 
758 /* do we add 1 before dividing by two?  Yes -- see MPEG-1 doc page 46 */
759 
760 #define ADD_ADD_DIFF(d,l,a,b,c,i)       \
761     l = ((a[i]+b[i]+1)>>1)-c[i];        \
762     d += ABS(l)
763 
764     for ( y = 0; y < 16; y++ ) {
765 	across = &(prev[fy+y][fx]);
766 	bacross = blockSoFar[y];
767 	cacross = currentBlock[y];
768 
769 	ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,0);
770 	ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,1);
771 	ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,2);
772 	ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,3);
773 	ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,4);
774 	ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,5);
775 	ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,6);
776 	ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,7);
777 	ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,8);
778 	ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,9);
779 	ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,10);
780 	ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,11);
781 	ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,12);
782 	ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,13);
783 	ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,14);
784 	ADD_ADD_DIFF(diff,localDiff,across,bacross,cacross,15);
785 
786 	if ( diff > bestSoFar ) {
787 	    return diff;
788 	}
789     }
790 
791     /* this is what's happening:
792      *
793      *	ComputeMotionLumBlock(prevFrame, by, bx, my, mx, lumMotionBlock);
794      *
795      *	for ( y = 0; y < 16; y++ )
796      *	    for ( x = 0; x < 16; x++ )
797      *	    {
798      *		localDiff = currentBlock[y][x] - lumMotionBlock[y][x];
799      *		diff += ABS(localDiff);
800      *	    }
801      *
802      */
803 
804     return diff;
805 }
806 
807 
808 /*===========================================================================*
809  *
810  * AddMotionBlock
811  *
812  *	adds the motion-compensated block to the given block
813  *
814  * RETURNS:	block modified
815  *
816  * SIDE EFFECTS:    none
817  *
818  * PRECONDITIONS:  motion vector MUST be valid
819  *
820  *===========================================================================*/
821 void
AddMotionBlock(Block block,uint8 ** prev,int by,int bx,int my,int mx)822 AddMotionBlock(Block block,
823                uint8 **prev,
824                int by,
825                int bx,
826                int my,
827                int mx)
828 {
829     int	    fy, fx;
830     int	    x, y;
831     boolean xHalf, yHalf;
832 
833     xHalf = (ABS(mx) % 2 == 1);
834     yHalf = (ABS(my) % 2 == 1);
835 
836     MOTION_TO_FRAME_COORD(by, bx, (my/2), (mx/2), fy, fx);
837 
838     if ( xHalf && yHalf ) {
839 	/* really should be fy+y-1 and fy+y so do (fy-1)+y = fy+y-1 and
840 	   (fy-1)+y+1 = fy+y
841 	 */
842 	if ( my < 0 ) {
843 	    fy--;
844 	}
845 	if ( mx < 0 ) {
846 	    fx--;
847 	}
848 
849 	for ( y = 0; y < 8; y++ ) {
850 	    for ( x = 0; x < 8; x++ ) {
851 		block[y][x] += (prev[fy+y][fx+x]+prev[fy+y][fx+x+1]+
852 				    prev[fy+y+1][fx+x]+prev[fy+y+1][fx+x+1]+2)>>2;
853 	    }
854 	}
855     } else if ( xHalf ) {
856 	if ( mx < 0 ) {
857 	    fx--;
858 	}
859 
860 	for ( y = 0; y < 8; y++ ) {
861 	    for ( x = 0; x < 8; x++ ) {
862 		block[y][x] += (prev[fy+y][fx+x]+prev[fy+y][fx+x+1]+1)>>1;
863 	    }
864 	}
865     } else if ( yHalf ) {
866 	if ( my < 0 ) {
867 	    fy--;
868 	}
869 
870 	for ( y = 0; y < 8; y++ ) {
871 	    for ( x = 0; x < 8; x++ ) {
872 		block[y][x] += (prev[fy+y][fx+x]+prev[fy+y+1][fx+x]+1)>>1;
873 	    }
874 	}
875     } else {
876 	for ( y = 0; y < 8; y++ ) {
877 	    for ( x = 0; x < 8; x++ ) {
878 		block[y][x] += (int16)prev[fy+y][fx+x];
879 	    }
880 	}
881     }
882 }
883 
884 
885 /*===========================================================================*
886  *
887  * AddBMotionBlock
888  *
889  *	adds the motion-compensated B-frame block to the given block
890  *
891  * RETURNS:	block modified
892  *
893  * SIDE EFFECTS:    none
894  *
895  * PRECONDITIONS:  motion vectors MUST be valid
896  *
897  *===========================================================================*/
898 void
AddBMotionBlock(Block block,uint8 ** prev,uint8 ** next,int by,int bx,int mode,int fmy,int fmx,int bmy,int bmx)899 AddBMotionBlock(Block block,
900                 uint8 **prev,
901                 uint8 **next,
902                 int by,
903                 int bx,
904                 int	mode,
905                 int fmy,
906                 int fmx,
907                 int bmy,
908                 int bmx)
909 {
910     int	    x, y;
911     Block   prevBlock, nextBlock;
912 
913     if ( mode == MOTION_FORWARD ) {
914 	AddMotionBlock(block, prev, by, bx, fmy, fmx);
915     } else if ( mode == MOTION_BACKWARD ) {
916 	AddMotionBlock(block, next, by, bx, bmy, bmx);
917     } else {
918 	ComputeMotionBlock(prev, by, bx, fmy, fmx, prevBlock);
919 	ComputeMotionBlock(next, by, bx, bmy, bmx, nextBlock);
920 
921 	for ( y = 0; y < 8; y++ ) {
922 	    for ( x = 0; x < 8; x++ ) {
923 		block[y][x] += (prevBlock[y][x]+nextBlock[y][x]+1)/2;
924 	    }
925 	}
926     }
927 }
928 
929 
930 /*===========================================================================*
931  *
932  * BlockToData
933  *
934  *	copies the given block into the appropriate data area
935  *
936  * RETURNS:	data modified
937  *
938  * SIDE EFFECTS:    none
939  *
940  *===========================================================================*/
941 void
BlockToData(uint8 ** data,Block block,int by,int bx)942 BlockToData(uint8 **data,
943             Block block,
944             int by,
945             int bx)
946 {
947     register int x, y;
948     register int fy, fx;
949     register int16    blockItem;
950 
951     BLOCK_TO_FRAME_COORD(by, bx, fy, fx);
952 
953     for ( y = 0; y < 8; y++ ) {
954 	for ( x = 0; x < 8; x++ ) {
955 	    blockItem = block[y][x];
956 	    data[fy+y][fx+x] = TRUNCATE_UINT8(blockItem);
957 	}
958     }
959 }
960 
961 
962 /*===========================================================================*
963  *
964  * BlockifyFrame
965  *
966  *	copies data into appropriate blocks
967  *
968  * RETURNS:	mf modified
969  *
970  * SIDE EFFECTS:    none
971  *
972  * NOTES:  probably shouldn't be in this file
973  *
974  *===========================================================================*/
975 void
BlockifyFrame(MpegFrame * framePtr)976 BlockifyFrame(MpegFrame *framePtr)
977 {
978     register int dctx, dcty;
979     register int x, y;
980     register int bx, by;
981     register int fy, fx;
982     register int16  *destPtr;
983     register uint8  *srcPtr;
984     register int16  *destPtr2;
985     register uint8  *srcPtr2;
986     Block   *blockPtr;
987     Block   *blockPtr2;
988 
989     dctx = Fsize_x / DCTSIZE;
990     dcty = Fsize_y / DCTSIZE;
991 
992     /*
993      * copy y data into y_blocks
994      */
995     for (by = 0; by < dcty; by++) {
996 	fy = by*DCTSIZE;
997 	for (bx = 0; bx < dctx; bx++) {
998 	    fx = bx*DCTSIZE;
999 	    blockPtr = (Block *) &(framePtr->y_blocks[by][bx][0][0]);
1000 	    for (y = 0; y < DCTSIZE; y++) {
1001 		destPtr = &((*blockPtr)[y][0]);
1002 		srcPtr = &(framePtr->orig_y[fy+y][fx]);
1003 		for (x = 0; x < DCTSIZE; x++) {
1004 		    destPtr[x] = srcPtr[x];
1005 		}
1006 	    }
1007 	}
1008     }
1009 
1010     /*
1011      * copy cr/cb data into cr/cb_blocks
1012      */
1013     for (by = 0; by < (dcty >> 1); by++) {
1014 	fy = by*DCTSIZE;
1015 	for (bx = 0; bx < (dctx >> 1); bx++) {
1016 	    fx = bx*DCTSIZE;
1017 	    blockPtr = (Block *) &(framePtr->cr_blocks[by][bx][0][0]);
1018 	    blockPtr2 = (Block *) &(framePtr->cb_blocks[by][bx][0][0]);
1019 	    for (y = 0; y < DCTSIZE; y++) {
1020 		destPtr = &((*blockPtr)[y][0]);
1021 		srcPtr = &(framePtr->orig_cr[fy+y][fx]);
1022 		destPtr2 = &((*blockPtr2)[y][0]);
1023 		srcPtr2 = &(framePtr->orig_cb[fy+y][fx]);
1024 		for (x = 0; x < DCTSIZE; x++) {
1025 		    destPtr[x] = srcPtr[x];
1026 		    destPtr2[x] = srcPtr2[x];
1027 		}
1028 	    }
1029 	}
1030     }
1031 }
1032 
1033 
1034 /*===========================================================================*
1035  *									     *
1036  * UNUSED PROCEDURES							     *
1037  *									     *
1038  *	The following procedures are all unused by the encoder		     *
1039  *									     *
1040  *	They are listed here for your convenience.  You might want to use    *
1041  *	them if you experiment with different search techniques		     *
1042  *									     *
1043  *===========================================================================*/
1044 
1045 #ifdef UNUSED_PROCEDURES
1046 
1047 /* this procedure calculates the subsampled motion block (obviously)
1048  *
1049  * for speed, this procedure is probably not called anywhere (it is
1050  * incorporated directly into LumDiffA, LumDiffB, etc.
1051  *
1052  * but leave it here anyway for clarity
1053  *
1054  * (startY, startX) = (0,0) for A....(0,1) for B...(1,0) for C...(1,1) for D
1055  *
1056  */
1057 void
1058 ComputeSubSampledMotionLumBlock(prevFrame, by, bx, my, mx, motionBlock,
1059 				startY, startX)
1060     MpegFrame *prevFrame;
1061     int by;
1062     int bx;
1063     int my;
1064     int mx;
1065     LumBlock motionBlock;
1066     int startY;
1067     int startX;
1068 {
1069     register uint8 *across;
1070     register int32 *macross;
1071     register int32 *lastx;
1072     register int y;
1073     uint8 **prev;
1074     int    fy, fx;
1075     boolean xHalf, yHalf;
1076 
1077     xHalf = (ABS(mx) % 2 == 1);
1078     yHalf = (ABS(my) % 2 == 1);
1079 
1080     MOTION_TO_FRAME_COORD(by, bx, my/2, mx/2, fy, fx);
1081 
1082     if ( xHalf ) {
1083 	if ( mx < 0 ) {
1084 	    fx--;
1085 	}
1086 
1087 	if ( yHalf ) {
1088 	    if ( my < 0 ) {
1089 		fy--;
1090 	    }
1091 
1092 	    prev = prevFrame->halfBoth;
1093 	} else {
1094 	    prev = prevFrame->halfX;
1095 	}
1096     } else if ( yHalf ) {
1097 	if ( my < 0 ) {
1098 	    fy--;
1099 	}
1100 
1101 	prev = prevFrame->halfY;
1102     } else {
1103 	prev = prevFrame->ref_y;
1104     }
1105 
1106     for ( y = startY; y < 16; y += 2 ) {
1107 	across = &(prev[fy+y][fx+startX]);
1108 	macross = &(motionBlock[y][startX]);
1109 	lastx = &(motionBlock[y][16]);
1110 	while ( macross < lastx ) {
1111 	    (*macross) = (*across);
1112 	    across += 2;
1113 	    macross += 2;
1114 	}
1115     }
1116 
1117     /* this is what's really going on in slow motion:
1118      *
1119      *	for ( y = startY; y < 16; y += 2 )
1120      *	    for ( x = startX; x < 16; x += 2 )
1121      *		motionBlock[y][x] = prev[fy+y][fx+x];
1122      *
1123      */
1124 }
1125 
1126 
1127 /*===========================================================================*
1128  *
1129  * LumMotionErrorSubSampled
1130  *
1131  *	return the MAD of the currentBlock and the motion-compensated block,
1132  *	subsampled 4:1 with given starting coordinates (startY, startX)
1133  *
1134  * RETURNS:	the MAD
1135  *
1136  * SIDE EFFECTS:    none
1137  *
1138  * PRECONDITIONS:  motion vector MUST be valid
1139  *
1140  * NOTES:  this procedure is never called.  Instead, see subsample.c.  This
1141  *         procedure is provided only for possible use in extensions
1142  *
1143  *===========================================================================*/
1144 int32
1145 LumMotionErrorSubSampled(currentBlock, prevFrame, by, bx, my, mx, startY,
1146 			 startX)
1147     LumBlock currentBlock;
1148     MpegFrame *prevFrame;
1149     int by;
1150     int bx;
1151     int my;
1152     int mx;
1153     int startY;
1154     int startX;
1155 {
1156     register int32    diff = 0;	    /* max value of diff is 255*256 = 65280 */
1157     register int32 localDiff;
1158     register int32 *cacross;
1159     register uint8 *macross;
1160     register int32 *lastx;
1161     register int y;
1162     uint8 **prev;
1163     int    fy, fx;
1164     boolean xHalf, yHalf;
1165 
1166     xHalf = (ABS(mx) % 2 == 1);
1167     yHalf = (ABS(my) % 2 == 1);
1168 
1169     MOTION_TO_FRAME_COORD(by, bx, my/2, mx/2, fy, fx);
1170 
1171     if ( xHalf ) {
1172 	if ( mx < 0 ) {
1173 	    fx--;
1174 	}
1175 
1176 	if ( yHalf ) {
1177 	    if ( my < 0 ) {
1178 		fy--;
1179 	    }
1180 
1181 	    prev = prevFrame->halfBoth;
1182 	} else {
1183 	    prev = prevFrame->halfX;
1184 	}
1185     } else if ( yHalf ) {
1186 	if ( my < 0 ) {
1187 	    fy--;
1188 	}
1189 
1190 	prev = prevFrame->halfY;
1191     } else {
1192 	prev = prevFrame->ref_y;
1193     }
1194 
1195     for ( y = startY; y < 16; y += 2 ) {
1196 	macross = &(prev[fy+y][fx+startX]);
1197 	cacross = &(currentBlock[y][startX]);
1198 	lastx = &(currentBlock[y][16]);
1199 	while ( cacross < lastx ) {
1200 	    localDiff = (*cacross)-(*macross);
1201 	    diff += ABS(localDiff);
1202 	    macross += 2;
1203 	    cacross += 2;
1204 	}
1205     }
1206 
1207     /* this is what's really happening:
1208      *
1209      *	ComputeSubSampledMotionLumBlock(prevFrame, by, bx, my, mx,
1210      *					lumMotionBlock, startY, startX);
1211      *
1212      *	for ( y = startY; y < 16; y += 2 )
1213      *	    for ( x = startX; x < 16; x += 2 )
1214      *	    {
1215      *	     	localDiff = currentBlock[y][x] - lumMotionBlock[y][x];
1216      *		diff += ABS(localDiff);
1217      *	    }
1218      *
1219      */
1220 
1221     return (int32)diff;
1222 }
1223 
1224 
1225 #endif /* UNUSED_PROCEDURES */
1226