1 /*===========================================================================*
2  * bframe.c								     *
3  *									     *
4  *	Procedures concerned with the B-frame encoding			     *
5  *									     *
6  * EXPORTED PROCEDURES:							     *
7  *	GenBFrame							     *
8  *	ResetBFrameStats						     *
9  *	ShowBFrameSummary						     *
10  *	EstimateSecondsPerBFrame					     *
11  *	ComputeBMotionLumBlock						     *
12  *	SetBQScale							     *
13  *	GetBQScale							     *
14  *									     *
15  *===========================================================================*/
16 
17 /*
18  * Copyright (c) 1995 The Regents of the University of California.
19  * All rights reserved.
20  *
21  * Permission to use, copy, modify, and distribute this software and its
22  * documentation for any purpose, without fee, and without written agreement is
23  * hereby granted, provided that the above copyright notice and the following
24  * two paragraphs appear in all copies of this software.
25  *
26  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
27  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
28  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
29  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
32  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
33  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
34  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
35  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
36  */
37 
38 /*
39  *  $Header$
40  *  $Log$
41  *  Revision 1.4  2004/04/02 15:12:39  rwcox
42  *  Cput
43  *
44  *  Revision 1.3  2003/12/23 13:50:08  rwcox
45  *  Cput
46  *
47  *  Revision 1.2  2003/12/03 14:46:14  rwcox
48  *  Cput
49  *
50  *  Revision 1.1  2001/12/17 16:11:53  rwcox
51  *  Cadd
52  *
53  *  Revision 1.20  1995/08/14 22:28:11  smoot
54  *  renamed index to idx
55  *  added option to not skip in B frames
56  *
57  *  Revision 1.19  1995/08/07 21:52:11  smoot
58  *  added Color to skip routine
59  *  fixed full/half bug in intial loop
60  *  added comments
61  *  removed buggy "extra skips" code
62  *
63  *  Revision 1.18  1995/06/21 22:22:24  smoot
64  *  generalized time checking, fixed bug in specifics filesm
65  *  and added TUNEing stuff
66  *
67  * Revision 1.17  1995/04/14  23:08:02  smoot
68  * reorganized to ease rate control experimentation
69  *
70  * Revision 1.16  1995/02/24  23:49:10  smoot
71  * added Spec version 2
72  *
73  * Revision 1.15  1995/01/30  19:45:45  smoot
74  * Fixed a cr/cb screwup
75  *
76  * Revision 1.14  1995/01/23  02:46:43  darryl
77  * initialized variable
78  *
79  * Revision 1.13  1995/01/19  23:07:12  eyhung
80  * Changed copyrights
81  *
82  * Revision 1.12  1995/01/16  07:44:11  eyhung
83  * Added realQuiet
84  *
85  * Revision 1.11  1994/12/07  00:40:36  smoot
86  * Added seperate P and B search ranges
87  *
88  * Revision 1.10  1994/11/24  00:35:47  smoot
89  * fixed bug (divide by 0) in B fram statsitics
90  *
91  * Revision 1.9  1994/11/14  22:26:48  smoot
92  * Merged specifics and rate control.
93  *
94  * Revision 1.8  1994/11/01  05:01:16  darryl
95  *  with rate control changes added
96  *
97  * Revision 2.0  1994/10/24  02:38:51  darryl
98  * will be adding the experiment code
99  *
100  * Revision 1.1  1994/09/27  00:16:04  darryl
101  * Initial revision
102  *
103  * Revision 1.7  1994/03/15  00:27:11  keving
104  * nothing
105  *
106  * Revision 1.6  1993/12/22  19:19:01  keving
107  * nothing
108  *
109  * Revision 1.5  1993/07/30  19:24:04  keving
110  * nothing
111  *
112  * Revision 1.4  1993/07/22  22:23:43  keving
113  * nothing
114  *
115  * Revision 1.3  1993/06/30  20:06:09  keving
116  * nothing
117  *
118  * Revision 1.2  1993/06/03  21:08:08  keving
119  * nothing
120  *
121  * Revision 1.1  1993/02/19  19:14:28  keving
122  * nothing
123  *
124  */
125 
126 
127 /*==============*
128  * HEADER FILES *
129  *==============*/
130 
131 #include "all.h"
132 #include <sys/param.h>
133 #include <assert.h>
134 #include "mtypes.h"
135 #include "bitio.h"
136 #include "frames.h"
137 #include "prototypes.h"
138 #include "fsize.h"
139 #include "param.h"
140 #include "mheaders.h"
141 #include "postdct.h"
142 #include "rate.h"
143 #include "opts.h"
144 
145 /*==================*
146  * STATIC VARIABLES *
147  *==================*/
148 
149 static int numBIBlocks = 0;
150 static int numBBBlocks = 0;
151 static int numBSkipped = 0;
152 static int numBIBits = 0;
153 static int numBBBits = 0;
154 static int numFrames = 0;
155 static int numFrameBits = 0;
156 static int32 totalTime = 0;
157 static int qscaleB;
158 static float    totalSNR = 0.0;
159 static float	totalPSNR = 0.0;
160 
161 static int numBFOBlocks = 0;    /* forward only */
162 static int numBBABlocks = 0;    /* backward only */
163 static int numBINBlocks = 0;    /* interpolate */
164 static int numBFOBits = 0;
165 static int numBBABits = 0;
166 static int numBINBits = 0;
167 
168 /*====================*
169  * EXTERNAL VARIABLES *
170  *====================*/
171 
172 extern Block **dct, **dctr, **dctb;
173 extern dct_data_type **dct_data;
174 #define NO_MOTION 0
175 #define MOTION 1
176 #define SKIP 2  /* used in useMotion in dct_data */
177 
178 /*===============================*
179  * INTERNAL PROCEDURE prototypes *
180  *===============================*/
181 
182 static boolean	MotionSufficient _ANSI_ARGS_((MpegFrame *curr, LumBlock currBlock, MpegFrame *prev, MpegFrame *next,
183 			 int by, int bx, int mode, int fmy, int fmx,
184 			 int bmy, int bmx));
185 static void	ComputeBMotionBlock _ANSI_ARGS_((MpegFrame *prev, MpegFrame *next,
186 			       int by, int bx, int mode, int fmy, int fmx,
187 			       int bmy, int bmx, Block motionBlock, int type));
188 static void	ComputeBDiffDCTs _ANSI_ARGS_((MpegFrame *current, MpegFrame *prev, MpegFrame *next,
189 			 int by, int bx, int mode, int fmy, int fmx,
190 			 int bmy, int bmx, int *pattern));
191 static boolean	DoBIntraCode _ANSI_ARGS_((MpegFrame *current, MpegFrame *prev, MpegFrame *next,
192 		     int by, int bx, int mode, int fmy, int fmx, int bmy,
193 		     int bmx));
194 
195 static int ComputeBlockColorDiff _ANSI_ARGS_((Block current, Block motionBlock));
196 
197 /*=====================*
198  * EXPORTED PROCEDURES *
199  *=====================*/
200 
201 /*===========================================================================*
202  *
203  * GenBFrame
204  *
205  *	generate a B-frame from previous and next frames, adding the result
206  *	to the given bit bucket
207  *
208  * RETURNS:	frame appended to bb
209  *
210  * SIDE EFFECTS:    none
211  *
212  *===========================================================================*/
213 void
GenBFrame(bb,curr,prev,next)214 GenBFrame(bb, curr, prev, next)
215     BitBucket *bb;
216     MpegFrame *curr;
217     MpegFrame *prev;
218     MpegFrame *next;
219 {
220     extern int **bfmvHistogram;
221     extern int **bbmvHistogram;
222     FlatBlock fba[6], fb[6];
223     Block     dec[6];
224     int32 y_dc_pred, cr_dc_pred, cb_dc_pred;
225     int x, y;
226     int	fMotionX = 0, fMotionY = 0;
227     int bMotionX = 0, bMotionY = 0;
228     int	oldFMotionX = 0, oldFMotionY = 0;
229     int oldBMotionX = 0, oldBMotionY = 0;
230     int	oldMode = MOTION_FORWARD;
231     int	mode = MOTION_FORWARD;
232     int	offsetX, offsetY;
233     int	tempX, tempY;
234     int	fMotionXrem = 0, fMotionXquot = 0;
235     int	fMotionYrem = 0, fMotionYquot = 0;
236     int	bMotionXrem = 0, bMotionXquot = 0;
237     int	bMotionYrem = 0, bMotionYquot = 0;
238     int	pattern;
239     int	numIBlocks = 0, numBBlocks = 0;
240     int numSkipped = 0, totalBits;
241     int	numIBits = 0,   numBBits = 0;
242     boolean	lastIntra = TRUE;
243     boolean    motionForward, motionBackward;
244     int	    totalFrameBits;
245     int32    startTime, endTime;
246     int lastX, lastY;
247     int lastBlockX, lastBlockY;
248     register int ix, iy;
249     LumBlock currentBlock;
250     int         fy, fx;
251     boolean	make_skip_block;
252     int	mbAddrInc = 1;
253     int	mbAddress;
254     int	    slicePos;
255     float   snr[3], psnr[3];
256     int	    idx;
257     int     QScale;
258     BlockMV *info;
259     int     bitstreamMode, newQScale;
260     int     rc_blockStart=0;
261     boolean overflowChange=FALSE;
262     int overflowValue = 0;
263 
264     if (collect_quant) {fprintf(collect_quant_fp, "# B\n");}
265     if (dct == NULL) AllocDctBlocks();
266     numFrames++;
267     totalFrameBits = bb->cumulativeBits;
268     startTime = time_elapsed();
269 
270     /*   Rate Control */
271     bitstreamMode = getRateMode();
272     if (bitstreamMode == FIXED_RATE) {
273       targetRateControl(curr);
274     }
275 
276     QScale = GetBQScale();
277     Mhead_GenPictureHeader(bb, B_FRAME, curr->id, fCodeB);
278     /* Check for Qscale change */
279     if (specificsOn) {
280       newQScale = SpecLookup(curr->id, 0, 0 /* junk */, &info, QScale);
281       if (newQScale != -1) {
282 	QScale = newQScale;
283       }
284       /* check for slice */
285       newQScale = SpecLookup(curr->id, 1, 1, &info, QScale);
286       if (newQScale != -1) {
287 	QScale = newQScale;
288       }
289     }
290 
291     Mhead_GenSliceHeader(bb, 1, QScale, NULL, 0);
292 
293     Frame_AllocBlocks(curr);
294     BlockifyFrame(curr);
295 
296     if ( printSNR ) {
297 	Frame_AllocDecoded(curr, FALSE);
298     }
299 
300     /* for I-blocks */
301     y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
302 
303     totalBits = bb->cumulativeBits;
304 
305     if ( ! pixelFullSearch ) {
306 	if ( ! prev->halfComputed && (prev != NULL)) {
307 	    ComputeHalfPixelData(prev);
308 	}
309 
310 	if ( ! next->halfComputed ) {
311 	    ComputeHalfPixelData(next);
312 	}
313     }
314 
315     lastBlockX = Fsize_x>>3;
316     lastBlockY = Fsize_y>>3;
317     lastX = lastBlockX-2;
318     lastY = lastBlockY-2;
319     mbAddress = 0;
320 
321     /* find motion vectors and do dcts */
322     /* In this first loop, all MVs are in half-pixel scope, (if FULL is set
323        then they will be multiples of 2).  This is not true in the second loop. */
324     for (y = 0;  y < lastBlockY;  y += 2) {
325       for (x = 0;  x < lastBlockX;  x += 2) {
326 	slicePos = (mbAddress % blocksPerSlice);
327 
328 	/* compute currentBlock */
329 	BLOCK_TO_FRAME_COORD(y, x, fy, fx);
330 	for ( iy = 0; iy < 16; iy++ ) {
331 	  for ( ix = 0; ix < 16; ix++ ) {
332 	    currentBlock[iy][ix] = (int16)curr->orig_y[fy+iy][fx+ix];
333 	  }
334 	}
335 
336 	if (slicePos == 0) {
337 	  oldFMotionX = 0;	oldFMotionY = 0;
338 	  oldBMotionX = 0;	oldBMotionY = 0;
339 	  oldMode = MOTION_FORWARD;
340 	  lastIntra = TRUE;
341 	}
342 
343 	/* STEP 1:  Select Forward, Backward, or Interpolated motion vectors */
344 	/* see if old motion is good enough */
345 	/* but force last block to be non-skipped */
346 	/* can only skip if:
347 	 *     1)  not the last block in frame
348 	 *     2)  not the last block in slice
349 	 *     3)  not the first block in slice
350 	 *     4)  previous block was not intra-coded
351 	 */
352 	if ( ((y < lastY) || (x < lastX)) &&
353 	    (slicePos+1 != blocksPerSlice) &&
354 	    (slicePos != 0) &&
355 	    (! lastIntra) &&
356 	    (BSkipBlocks) ) {
357 	  make_skip_block = MotionSufficient(curr, currentBlock, prev, next, y, x, oldMode,
358 					     oldFMotionY, oldFMotionX,
359 					     oldBMotionY, oldBMotionX);
360 	} else {
361 	  make_skip_block = FALSE;
362 	}
363 
364 	if ( make_skip_block ) {
365 	skip_it:
366 	  /* skipped macro block */
367 	  dct_data[y][x].useMotion = SKIP;
368 	} else {
369 	  if (specificsOn) {
370 	    (void) SpecLookup(curr->id, 2, mbAddress, &info, QScale);
371 	    if (info == (BlockMV*)NULL) goto gosearch;
372 	    else {
373 	      switch (info->typ) {
374 	      case TYP_SKIP:
375 		goto skip_it;
376 	      case TYP_FORW:
377 		fMotionX = info->fx;
378 		fMotionY = info->fy;
379 		mode = MOTION_FORWARD;
380 		break;
381 	      case TYP_BACK:
382 		bMotionX = info->bx;
383 		bMotionY = info->by;
384 		mode = MOTION_BACKWARD;
385 		break;
386 	      case TYP_BOTH:
387 		fMotionX = info->fx;
388 		fMotionY = info->fy;
389 		bMotionX = info->bx;
390 		bMotionY = info->by;
391 		mode = MOTION_INTERPOLATE;
392 		break;
393 	      default:
394 		fprintf(stderr,"Unreachable code in GenBFrame!\n");
395 		goto gosearch;
396 	      }
397 	      goto skipsearch;
398 	    }}
399 	gosearch:		/* do bsearch */
400 	  mode = BMotionSearch(currentBlock, prev, next, y, x, &fMotionY,
401 			       &fMotionX, &bMotionY, &bMotionX, mode);
402 	skipsearch:
403 
404 	  /* STEP 2:  INTRA OR NON-INTRA CODING */
405 	  if ( IntraPBAllowed && DoBIntraCode(curr, prev, next, y, x, mode, fMotionY,
406 			    fMotionX, bMotionY, bMotionX) ) {
407 	    /* output I-block inside a B-frame */
408 	    numIBlocks++;
409 	    oldFMotionX = 0;	oldFMotionY = 0;
410 	    oldBMotionX = 0;	oldBMotionY = 0;
411 	    lastIntra = TRUE;
412 	    dct_data[y][x].useMotion = NO_MOTION;
413 	    oldMode = MOTION_FORWARD;
414 	    /* calculate forward dct's */
415 	    if (collect_quant && (collect_quant_detailed & 1)) fprintf(collect_quant_fp, "l\n");
416 	    mp_fwd_dct_block2(curr->y_blocks[y][x], dct[y][x]);
417 	    mp_fwd_dct_block2(curr->y_blocks[y][x+1], dct[y][x+1]);
418 	    mp_fwd_dct_block2(curr->y_blocks[y+1][x], dct[y+1][x]);
419 	    mp_fwd_dct_block2(curr->y_blocks[y+1][x+1], dct[y+1][x+1]);
420 	    if (collect_quant && (collect_quant_detailed & 1)) {fprintf(collect_quant_fp, "c\n");}
421 	    mp_fwd_dct_block2(curr->cb_blocks[y>>1][x>>1], dctb[y>>1][x>>1]);
422 	    mp_fwd_dct_block2(curr->cr_blocks[y>>1][x>>1], dctr[y>>1][x>>1]);
423 
424 	  } else { /* dct P/Bi/B block */
425 
426 	    pattern = 63;
427 	    lastIntra = FALSE;
428 	    numBBlocks++;
429 	    dct_data[y][x].mode = mode;
430 	    oldMode = mode;
431 	    dct_data[y][x].fmotionX = fMotionX;
432 	    dct_data[y][x].fmotionY = fMotionY;
433 	    dct_data[y][x].bmotionX = bMotionX;
434 	    dct_data[y][x].bmotionY = bMotionY;
435 	    switch (mode) {
436 	    case MOTION_FORWARD:
437 	      numBFOBlocks++;
438 	      oldFMotionX = fMotionX;		oldFMotionY = fMotionY;
439 	      break;
440 	    case MOTION_BACKWARD:
441 	      numBBABlocks++;
442 	      oldBMotionX = bMotionX;		oldBMotionY = bMotionY;
443 	      break;
444 	    case MOTION_INTERPOLATE:
445 	      numBINBlocks++;
446 	      oldFMotionX = fMotionX;		oldFMotionY = fMotionY;
447 	      oldBMotionX = bMotionX;		oldBMotionY = bMotionY;
448 	      break;
449 	    default:
450 	      fprintf(stderr, "PROGRAMMER ERROR:  Illegal mode: %d\n", mode);
451 	      exit(1);
452 	    }
453 
454 	    ComputeBDiffDCTs(curr, prev, next, y, x, mode, fMotionY,
455 			     fMotionX, bMotionY, bMotionX, &pattern);
456 
457 	    dct_data[y][x].pattern = pattern;
458 	    dct_data[y][x].useMotion = MOTION;
459 	    if ( computeMVHist ) {
460 	      assert(fMotionX+searchRangeB+1 >= 0);
461 	      assert(fMotionY+searchRangeB+1 >= 0);
462 	      assert(fMotionX+searchRangeB+1 <= 2*searchRangeB+2);
463 	      assert(fMotionY+searchRangeB+1 <= 2*searchRangeB+2);
464 	      assert(bMotionX+searchRangeB+1 >= 0);
465 	      assert(bMotionY+searchRangeB+1 >= 0);
466 	      assert(bMotionX+searchRangeB+1 <= 2*searchRangeB+2);
467 	      assert(bMotionY+searchRangeB+1 <= 2*searchRangeB+2);
468 
469 	      bfmvHistogram[fMotionX+searchRangeB+1][fMotionY+searchRangeB+1]++;
470 	      bbmvHistogram[bMotionX+searchRangeB+1][bMotionY+searchRangeB+1]++;
471 	    }
472 	  } /* motion-block */
473 	} /* not skipped */
474 	mbAddress++;
475       }}
476 
477     /* reset everything */
478     oldFMotionX = 0;	oldFMotionY = 0;
479     oldBMotionX = 0;	oldBMotionY = 0;
480     oldMode = MOTION_FORWARD;
481     lastIntra = TRUE;
482     y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
483     mbAddress = 0;
484 
485     /* Now generate the frame */
486     for (y = 0; y < lastBlockY; y += 2) {
487       for (x = 0; x < lastBlockX; x += 2) {
488 	slicePos = (mbAddress % blocksPerSlice);
489 
490 	if ( (slicePos == 0) && (mbAddress != 0) ) {
491 	  if (specificsOn) {
492 	    /* Make sure no slice Qscale change */
493 	    newQScale = SpecLookup(curr->id,1,mbAddress/blocksPerSlice, &info, QScale);
494 	    if (newQScale != -1) QScale = newQScale;
495 	  }
496 	  Mhead_GenSliceEnder(bb);
497 	  Mhead_GenSliceHeader(bb, 1+(y>>1), QScale, NULL, 0);
498 
499 	  /* reset everything */
500 	  oldFMotionX = 0;	oldFMotionY = 0;
501 	  oldBMotionX = 0;	oldBMotionY = 0;
502 	  oldMode = MOTION_FORWARD;
503 	  lastIntra = TRUE;
504 	  y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
505 
506 	  mbAddrInc = 1+(x>>1);
507 	}
508 
509 	/*  Determine if new Qscale needed for Rate Control purposes */
510 	if (bitstreamMode == FIXED_RATE) {
511 	  rc_blockStart =  bb->cumulativeBits;
512 	  newQScale = needQScaleChange(QScale,
513 				       curr->y_blocks[y][x],
514 				       curr->y_blocks[y][x+1],
515 				       curr->y_blocks[y+1][x],
516 				       curr->y_blocks[y+1][x+1]);
517 	  if (newQScale > 0) {
518 	    QScale = newQScale;
519 	  }
520 	}
521 
522 	if (specificsOn) {
523 	  newQScale = SpecLookup(curr->id, 2, mbAddress, &info, QScale);
524 	  if (newQScale != -1) {
525 	    QScale = newQScale;
526 	  }}
527 
528 	if (dct_data[y][x].useMotion == NO_MOTION) {
529 
530 	  GEN_I_BLOCK(B_FRAME, curr, bb, mbAddrInc, QScale);
531 	  mbAddrInc = 1;
532 	  numIBits += (bb->cumulativeBits-totalBits);
533 	  totalBits = bb->cumulativeBits;
534 
535 	  /* reset because intra-coded */
536 	  oldFMotionX = 0;		oldFMotionY = 0;
537 	  oldBMotionX = 0;		oldBMotionY = 0;
538 	  oldMode = MOTION_FORWARD;
539 	  lastIntra = TRUE;
540 
541 	  if ( printSNR ) {
542 	    /* need to decode block we just encoded */
543 	    /* and reverse the DCT transform */
544 	    for ( idx = 0; idx < 6; idx++ ) {
545 	      Mpost_UnQuantZigBlock(fb[idx], dec[idx], QScale, TRUE);
546 	      mpeg_jrevdct((int16 *)dec[idx]);
547 	    }
548 
549 	    /* now, unblockify */
550 	    BlockToData(curr->decoded_y, dec[0], y, x);
551 	    BlockToData(curr->decoded_y, dec[1], y, x+1);
552 	    BlockToData(curr->decoded_y, dec[2], y+1, x);
553 	    BlockToData(curr->decoded_y, dec[3], y+1, x+1);
554 	    BlockToData(curr->decoded_cb, dec[4], y>>1, x>>1);
555 	    BlockToData(curr->decoded_cr, dec[5], y>>1, x>>1);
556 	  }
557 	} else if (dct_data[y][x].useMotion == SKIP) {
558 	skip_block:
559 	  numSkipped++;
560 	  mbAddrInc++;
561 
562 	  /* decode skipped block */
563 	  if ( printSNR ) {
564 	    int	fmy, fmx, bmy, bmx;
565 
566 	    for ( idx = 0; idx < 6; idx++ ) {
567 	      memset((char *)dec[idx], 0, sizeof(Block));
568 	    }
569 
570 	    if ( pixelFullSearch ) {
571 	      fmy = 2*oldFMotionY;
572 	      fmx = 2*oldFMotionX;
573 	      bmy = 2*oldBMotionY;
574 	      bmx = 2*oldBMotionX;
575 	    } else {
576 	      fmy = oldFMotionY;
577 	      fmx = oldFMotionX;
578 	      bmy = oldBMotionY;
579 	      bmx = oldBMotionX;
580 	    }
581 
582 	    /* now add the motion block */
583 	    AddBMotionBlock(dec[0], prev->decoded_y,
584 			    next->decoded_y, y, x, mode,
585 			    fmy, fmx, bmy, bmx);
586 	    AddBMotionBlock(dec[1], prev->decoded_y,
587 			    next->decoded_y, y, x+1, mode,
588 			    fmy, fmx, bmy, bmx);
589 	    AddBMotionBlock(dec[2], prev->decoded_y,
590 			    next->decoded_y, y+1, x, mode,
591 			    fmy, fmx, bmy, bmx);
592 	    AddBMotionBlock(dec[3], prev->decoded_y,
593 			    next->decoded_y, y+1, x+1, mode,
594 			    fmy, fmx, bmy, bmx);
595 	    AddBMotionBlock(dec[4], prev->decoded_cb,
596 			    next->decoded_cb, y>>1, x>>1, mode,
597 			    fmy/2, fmx/2,
598 			    bmy/2, bmx/2);
599 	    AddBMotionBlock(dec[5], prev->decoded_cr,
600 			    next->decoded_cr, y>>1, x>>1, mode,
601 			    fmy/2, fmx/2,
602 			    bmy/2, bmx/2);
603 
604 	    /* now, unblockify */
605 	    BlockToData(curr->decoded_y, dec[0], y, x);
606 	    BlockToData(curr->decoded_y, dec[1], y, x+1);
607 	    BlockToData(curr->decoded_y, dec[2], y+1, x);
608 	    BlockToData(curr->decoded_y, dec[3], y+1, x+1);
609 	    BlockToData(curr->decoded_cb, dec[4], y>>1, x>>1);
610 	    BlockToData(curr->decoded_cr, dec[5], y>>1, x>>1);
611 	  }
612 	} else   /* B block */ {
613 	  int fCode = fCodeB;
614 
615 	  pattern = dct_data[y][x].pattern;
616 	  fMotionX = dct_data[y][x].fmotionX;
617 	  fMotionY = dct_data[y][x].fmotionY;
618 	  bMotionX = dct_data[y][x].bmotionX;
619 	  bMotionY = dct_data[y][x].bmotionY;
620 
621 	  if ( pixelFullSearch ) {
622 	    fMotionX /= 2;	    fMotionY /= 2;
623 	    bMotionX /= 2;	    bMotionY /= 2;
624 	  }
625 
626 	  /* create flat blocks and update pattern if necessary */
627 	calc_blocks:
628 	/* Note DoQuant references QScale, overflowChange, overflowValue,
629            pattern, and the calc_blocks label                 */
630 	  DoQuant(0x20, dct[y][x], fba[0]);
631 	  DoQuant(0x10, dct[y][x+1], fba[1]);
632 	  DoQuant(0x08, dct[y+1][x], fba[2]);
633 	  DoQuant(0x04, dct[y+1][x+1], fba[3]);
634 	  DoQuant(0x02, dctb[y>>1][x>>1], fba[4]);
635 	  DoQuant(0x01, dctr[y>>1][x>>1], fba[5]);
636 
637 	  motionForward  = (dct_data[y][x].mode != MOTION_BACKWARD);
638 	  motionBackward = (dct_data[y][x].mode != MOTION_FORWARD);
639 
640 #ifdef BUGGY_CODE
641 	  /*
642 	  send us mail if you can tell me why this code
643           doesnt work.  Generates some bad vectors.
644           I suspect 'cuz oldMode/motions aren't being set right,
645           but am unsure.
646 	  */
647 	  /* Check to see if we should have skipped */
648 	  if ((pattern == 0) &&
649 	      ((y < lastY) || (x < lastX)) &&
650 	      (slicePos+1 != blocksPerSlice) &&
651 	      (slicePos != 0) &&
652 	      (!lastIntra) &&
653 	      ( (!motionForward) ||
654 	       (motionForward &&
655 		fMotionX == oldFMotionX && fMotionY == oldFMotionY)) &&
656 	      ( (!motionBackward) ||
657 	       (motionBackward &&
658 		bMotionX == oldBMotionX && bMotionY == oldBMotionY))
659 	      ) {
660 	    /* Now *thats* an if statement! */
661 	    goto skip_block;
662 	  }
663 #endif
664 	  /* Encode Vectors */
665 	  if ( motionForward ) {
666 	    /* transform the fMotion vector into the appropriate values */
667 	    offsetX = fMotionX - oldFMotionX;
668 	    offsetY = fMotionY - oldFMotionY;
669 
670 	    ENCODE_MOTION_VECTOR(offsetX, offsetY, fMotionXquot,
671 				 fMotionYquot, fMotionXrem, fMotionYrem,
672 				 FORW_F);
673 	    oldFMotionX = fMotionX;		oldFMotionY = fMotionY;
674 	  }
675 
676 	  if ( motionBackward ) {
677 	    /* transform the bMotion vector into the appropriate values */
678 	    offsetX = bMotionX - oldBMotionX;
679 	    offsetY = bMotionY - oldBMotionY;
680 	    ENCODE_MOTION_VECTOR(offsetX, offsetY, bMotionXquot,
681 				 bMotionYquot, bMotionXrem, bMotionYrem,
682 				 BACK_F);
683 	    oldBMotionX = bMotionX;		oldBMotionY = bMotionY;
684 	  }
685 
686 	  oldMode = dct_data[y][x].mode;
687 
688 	  if ( printSNR ) { /* Need to decode */
689 	    if ( pixelFullSearch ) {
690 	      fMotionX *= 2;	fMotionY *= 2;
691 	      bMotionX *= 2;	bMotionY *= 2;
692 	    }
693 	    for ( idx = 0; idx < 6; idx++ ) {
694 	      if ( pattern & (1 << (5-idx)) ) {
695 		Mpost_UnQuantZigBlock(fba[idx], dec[idx], QScale, FALSE);
696 		mpeg_jrevdct((int16 *)dec[idx]);
697 	      } else {
698 		memset((char *)dec[idx], 0, sizeof(Block));
699 	      }
700 	    }
701 
702 	    /* now add the motion block */
703 	    AddBMotionBlock(dec[0], prev->decoded_y,
704 			    next->decoded_y, y, x, mode,
705 			    fMotionY, fMotionX, bMotionY, bMotionX);
706 	    AddBMotionBlock(dec[1], prev->decoded_y,
707 			    next->decoded_y, y, x+1, mode,
708 			    fMotionY, fMotionX, bMotionY, bMotionX);
709 	    AddBMotionBlock(dec[2], prev->decoded_y,
710 			    next->decoded_y, y+1, x, mode,
711 			    fMotionY, fMotionX, bMotionY, bMotionX);
712 	    AddBMotionBlock(dec[3], prev->decoded_y,
713 			    next->decoded_y, y+1, x+1, mode,
714 			    fMotionY, fMotionX, bMotionY, bMotionX);
715 	    AddBMotionBlock(dec[4], prev->decoded_cb,
716 			    next->decoded_cb, y>>1, x>>1, mode,
717 			    fMotionY/2, fMotionX/2,
718 			    bMotionY/2, bMotionX/2);
719 	    AddBMotionBlock(dec[5], prev->decoded_cr,
720 			    next->decoded_cr, y>>1, x>>1, mode,
721 			    fMotionY/2, fMotionX/2,
722 			    bMotionY/2, bMotionX/2);
723 
724 	    /* now, unblockify */
725 	    BlockToData(curr->decoded_y,  dec[0], y,    x);
726 	    BlockToData(curr->decoded_y,  dec[1], y,    x+1);
727 	    BlockToData(curr->decoded_y,  dec[2], y+1,  x);
728 	    BlockToData(curr->decoded_y,  dec[3], y+1,  x+1);
729 	    BlockToData(curr->decoded_cb, dec[4], y>>1, x>>1);
730 	    BlockToData(curr->decoded_cr, dec[5], y>>1, x>>1);
731 	  }
732 
733 	  /* reset because non-intra-coded */
734 	  y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
735 	  lastIntra = FALSE;
736 	  mode = dct_data[y][x].mode;
737 
738 	  /*      DBG_PRINT(("MB Header(%d,%d)\n", x, y));  */
739 	  Mhead_GenMBHeader(bb, 3 /* pict_code_type */, mbAddrInc /* addr_incr */,
740 	    QScale /* q_scale */,
741 	    fCodeB /* forw_f_code */, fCodeB /* back_f_code */,
742 	    fMotionXrem /* horiz_forw_r */, fMotionYrem /* vert_forw_r */,
743 	    bMotionXrem /* horiz_back_r */, bMotionYrem /* vert_back_r */,
744 	    motionForward /* motion_forw */, fMotionXquot /* m_horiz_forw */,
745 	    fMotionYquot /* m_vert_forw */, motionBackward /* motion_back */,
746 	    bMotionXquot /* m_horiz_back */, bMotionYquot /* m_vert_back */,
747 	    pattern /* mb_pattern */, FALSE /* mb_intra */);
748 	  mbAddrInc = 1;
749 
750 	  /* now output the difference */
751 	  for ( tempX = 0; tempX < 6; tempX++ ) {
752 	    if ( GET_ITH_BIT(pattern, 5-tempX) ) {
753 	      Mpost_RLEHuffPBlock(fba[tempX], bb);
754 	    }
755 	  }
756 
757 
758 	  switch (mode) {
759 	  case MOTION_FORWARD:
760 	    numBFOBits += (bb->cumulativeBits-totalBits);
761 	    break;
762 	  case MOTION_BACKWARD:
763 	    numBBABits += (bb->cumulativeBits-totalBits);
764 	    break;
765 	  case MOTION_INTERPOLATE:
766 	    numBINBits += (bb->cumulativeBits-totalBits);
767 	    break;
768 	  default:
769 	    fprintf(stderr, "PROGRAMMER ERROR:  Illegal mode: %d\n",
770 		    mode);
771 	    exit(1);
772 	  }
773 
774 	  numBBits += (bb->cumulativeBits-totalBits);
775 	  totalBits = bb->cumulativeBits;
776 
777 	  if (overflowChange) {
778 	    /* undo an overflow-caused Qscale change */
779 	    overflowChange = FALSE;
780 	    QScale -= overflowValue;
781 	    overflowValue = 0;
782 	  }
783 	} /* if I-block, skip, or B */
784 
785 	mbAddress++;
786 	/*   Rate Control  */
787 	if (bitstreamMode == FIXED_RATE) {
788 	  incMacroBlockBits( bb->cumulativeBits - rc_blockStart);
789 	  rc_blockStart = bb->cumulativeBits;
790 	  MB_RateOut(TYPE_BFRAME);
791 	}
792 
793       }
794     }
795 
796     if ( printSNR ) {
797       BlockComputeSNR(curr,snr,psnr);
798       totalSNR += snr[0];
799       totalPSNR += psnr[0];
800     }
801 
802     Mhead_GenSliceEnder(bb);
803     /*   Rate Control  */
804     if (bitstreamMode == FIXED_RATE) {
805       updateRateControl(TYPE_BFRAME);
806     }
807 
808     endTime = time_elapsed();
809     totalTime += (endTime-startTime);
810 
811     if ( ( ! childProcess) && showBitRatePerFrame ) {
812       /* ASSUMES 30 FRAMES PER SECOND */
813       fprintf(bitRateFile, "%5d\t%8d\n", curr->id,
814 	      30*(bb->cumulativeBits-totalFrameBits));
815     }
816 
817     if ( (! childProcess) && frameSummary && !realQuiet) {
818       fprintf(stdout, "FRAME %d (B):  I BLOCKS:  %d;  B BLOCKS:  %d   SKIPPED:  %d (%ld seconds)\n",
819 	      curr->id, numIBlocks, numBBlocks, numSkipped, (long)((endTime-startTime)/TIME_RATE));
820       if ( printSNR )
821 	fprintf(stdout, "FRAME %d:  SNR:  %.1f\t%.1f\t%.1f\tPSNR:  %.1f\t%.1f\t%.1f\n",
822 		curr->id, snr[0], snr[1], snr[2],
823 		psnr[0], psnr[1], psnr[2]);
824     }
825 
826     numFrameBits += (bb->cumulativeBits-totalFrameBits);
827     numBIBlocks += numIBlocks;
828     numBBBlocks += numBBlocks;
829     numBSkipped += numSkipped;
830     numBIBits += numIBits;
831     numBBBits += numBBits;
832   }
833 
834 
835 /*===========================================================================*
836  *
837  * SetBQScale
838  *
839  *	set the B-frame Q-scale
840  *
841  * RETURNS:	nothing
842  *
843  * SIDE EFFECTS:    qscaleB
844  *
845  *===========================================================================*/
846 void
SetBQScale(qB)847 SetBQScale(qB)
848     int qB;
849 {
850     qscaleB = qB;
851 }
852 
853 
854 /*===========================================================================*
855  *
856  * GetBQScale
857  *
858  *	get the B-frame Q-scale
859  *
860  * RETURNS:	the Q-scale
861  *
862  * SIDE EFFECTS:    none
863  *
864  *===========================================================================*/
865 int
GetBQScale()866 GetBQScale()
867 {
868     return qscaleB;
869 }
870 
871 
872 /*===========================================================================*
873  *
874  * ResetBFrameStats
875  *
876  *	reset the B-frame stats
877  *
878  * RETURNS:	nothing
879  *
880  * SIDE EFFECTS:    none
881  *
882  *===========================================================================*/
883 void
ResetBFrameStats()884 ResetBFrameStats()
885 {
886     numBIBlocks = 0;
887     numBBBlocks = 0;
888     numBSkipped = 0;
889     numBIBits = 0;
890     numBBBits = 0;
891     numFrames = 0;
892     numFrameBits = 0;
893     totalTime = 0;
894 }
895 
896 
897 /*===========================================================================*
898  *
899  * ShowBFrameSummary
900  *
901  *	print out statistics on all B-frames
902  *
903  * RETURNS:	time taken for B-frames (in seconds)
904  *
905  * SIDE EFFECTS:    none
906  *
907  *===========================================================================*/
908 float
ShowBFrameSummary(inputFrameBits,totalBits,fpointer)909 ShowBFrameSummary(inputFrameBits, totalBits, fpointer)
910     int inputFrameBits;
911     int32 totalBits;
912     FILE *fpointer;
913 {
914     if ( numFrames == 0 ) {
915 	return 0.0;
916     }
917 
918     fprintf(fpointer, "-------------------------\n");
919     fprintf(fpointer, "*****B FRAME SUMMARY*****\n");
920     fprintf(fpointer, "-------------------------\n");
921 
922     if ( numBIBlocks != 0 ) {
923 	fprintf(fpointer, "  I Blocks:  %5d     (%6d bits)     (%5d bpb)\n",
924 		numBIBlocks, numBIBits, numBIBits/numBIBlocks);
925     } else {
926 	fprintf(fpointer, "  I Blocks:  %5d\n", 0);
927     }
928 
929     if ( numBBBlocks != 0 ) {
930 	fprintf(fpointer, "  B Blocks:  %5d     (%6d bits)     (%5d bpb)\n",
931 		numBBBlocks, numBBBits, numBBBits/numBBBlocks);
932 	fprintf(fpointer, "  B types:   %5d     (%4d bpb) forw  %5d (%4d bpb) back   %5d (%4d bpb) bi\n",
933 		numBFOBlocks, (numBFOBlocks==0)?0:numBFOBits/numBFOBlocks,
934 		numBBABlocks, (numBBABlocks==0)?0:numBBABits/numBBABlocks,
935 		numBINBlocks, (numBINBlocks==0)?0:numBINBits/numBINBlocks);
936     } else {
937 	fprintf(fpointer, "  B Blocks:  %5d\n", 0);
938     }
939 
940     fprintf(fpointer, "  Skipped:   %5d\n", numBSkipped);
941 
942     fprintf(fpointer, "  Frames:    %5d     (%6d bits)     (%5d bpf)     (%2.1f%% of total)\n",
943 	    numFrames, numFrameBits, numFrameBits/numFrames,
944 	    100.0*(float)numFrameBits/(float)totalBits);
945     fprintf(fpointer, "  Compression:  %3d:1     (%9.4f bpp)\n",
946 	    numFrames*inputFrameBits/numFrameBits,
947 	    24.0*(float)numFrameBits/(float)(numFrames*inputFrameBits));
948     if ( printSNR )
949 	fprintf(fpointer, "  Avg Y SNR/PSNR:  %.1f     %.1f\n",
950 		totalSNR/(float)numFrames, totalPSNR/(float)numFrames);
951     if ( totalTime == 0 ) {
952 	fprintf(fpointer, "  Seconds:  NONE\n");
953     } else {
954 	fprintf(fpointer, "  Seconds:  %9ld     (%9.4f fps)  (%9ld pps)  (%9ld mps)\n",
955 		(long)(totalTime/TIME_RATE),
956 		(float)((float)(TIME_RATE*numFrames)/(float)totalTime),
957 		(long)((float)TIME_RATE*(float)numFrames*(float)inputFrameBits/(24.0*(float)totalTime)),
958 		(long)((float)TIME_RATE*(float)numFrames*(float)inputFrameBits/(256.0*24.0*(float)totalTime)));
959     }
960 
961     return (float)totalTime/TIME_RATE;
962 }
963 
964 
965 /*===========================================================================*
966  *
967  * ComputeBMotionLumBlock
968  *
969  *	compute the luminance block resulting from motion compensation
970  *
971  * RETURNS:	motionBlock modified
972  *
973  * SIDE EFFECTS:    none
974  *
975  * PRECONDITION:	the motion vectors must be valid!
976  *
977  *===========================================================================*/
978 void
ComputeBMotionLumBlock(prev,next,by,bx,mode,fmy,fmx,bmy,bmx,motionBlock)979 ComputeBMotionLumBlock(prev, next, by, bx, mode, fmy, fmx, bmy, bmx, motionBlock)
980     MpegFrame *prev;
981     MpegFrame *next;
982     int by;
983     int bx;
984     int mode;
985     int fmy;
986     int fmx;
987     int bmy;
988     int bmx;
989     LumBlock motionBlock;
990 {
991     LumBlock	prevBlock, nextBlock;
992     register int	y, x;
993 
994     switch(mode) {
995     case MOTION_FORWARD:
996       ComputeMotionLumBlock(prev, by, bx, fmy, fmx, motionBlock);
997       break;
998     case MOTION_BACKWARD:
999       ComputeMotionLumBlock(next, by, bx, bmy, bmx, motionBlock);
1000       break;
1001     case MOTION_INTERPOLATE:
1002       ComputeMotionLumBlock(prev, by, bx, fmy, fmx, prevBlock);
1003       ComputeMotionLumBlock(next, by, bx, bmy, bmx, nextBlock);
1004 
1005       for ( y = 0; y < 16; y++ ) {
1006 	for ( x = 0; x < 16; x++ ) {
1007 	  motionBlock[y][x] = (prevBlock[y][x]+nextBlock[y][x]+1)/2;
1008 	}
1009       }
1010       break;
1011     default:
1012       fprintf(stderr, "Bad mode!\nProgrammer error!\n");
1013       break;
1014 
1015     }
1016 }
1017 
1018 
1019 /*===========================================================================*
1020  *
1021  * EstimateSecondsPerBFrame
1022  *
1023  *	estimate the seconds to compute a B-frame
1024  *
1025  * RETURNS:	the time, in seconds
1026  *
1027  * SIDE EFFECTS:    none
1028  *
1029  *===========================================================================*/
1030 float
EstimateSecondsPerBFrame()1031 EstimateSecondsPerBFrame()
1032 {
1033     if ( numFrames == 0 ) {
1034 	return 20.0;
1035     } else {
1036 	return (float)totalTime/((float)TIME_RATE*(float)numFrames);
1037     }
1038 }
1039 
1040 
1041 /*=====================*
1042  * INTERNAL PROCEDURES *
1043  *=====================*/
1044 
1045 /*===========================================================================*
1046  *
1047  * ComputeBMotionBlock
1048  *
1049  *	compute the block resulting from motion compensation
1050  *
1051  * RETURNS:	motionBlock is modified
1052  *
1053  * SIDE EFFECTS:    none
1054  *
1055  * PRECONDITION:	the motion vectors must be valid!
1056  *
1057  *===========================================================================*/
1058 static void
ComputeBMotionBlock(prev,next,by,bx,mode,fmy,fmx,bmy,bmx,motionBlock,type)1059 ComputeBMotionBlock(prev, next, by, bx, mode, fmy, fmx, bmy, bmx, motionBlock, type)
1060     MpegFrame *prev;
1061     MpegFrame *next;
1062     int by;
1063     int bx;
1064     int mode;
1065     int fmy;
1066     int fmx;
1067     int bmy;
1068     int bmx;
1069     Block motionBlock;
1070     int type;
1071 {
1072     Block	prevBlock, nextBlock;
1073     register int	y, x;
1074 
1075     switch(mode) {
1076 	case MOTION_FORWARD:
1077 	    if ( type == LUM_BLOCK ) {
1078 		ComputeMotionBlock(prev->ref_y, by, bx, fmy, fmx, motionBlock);
1079 	    } else if ( type == CB_BLOCK ) {
1080 		ComputeMotionBlock(prev->ref_cb, by, bx, fmy, fmx, motionBlock);
1081 	    } else if ( type == CR_BLOCK ) {
1082 		ComputeMotionBlock(prev->ref_cr, by, bx, fmy, fmx, motionBlock);
1083 	    }
1084 	    break;
1085 	case MOTION_BACKWARD:
1086 	    if ( type == LUM_BLOCK ) {
1087 		ComputeMotionBlock(next->ref_y, by, bx, bmy, bmx, motionBlock);
1088 	    } else if ( type == CB_BLOCK ) {
1089 		ComputeMotionBlock(next->ref_cb, by, bx, bmy, bmx, motionBlock);
1090 	    } else if ( type == CR_BLOCK ) {
1091 		ComputeMotionBlock(next->ref_cr, by, bx, bmy, bmx, motionBlock);
1092 	    }
1093 	    break;
1094 	case MOTION_INTERPOLATE:
1095 	    if ( type == LUM_BLOCK ) {
1096 		ComputeMotionBlock(prev->ref_y, by, bx, fmy, fmx, prevBlock);
1097 		ComputeMotionBlock(next->ref_y, by, bx, bmy, bmx, nextBlock);
1098 	    } else if ( type == CB_BLOCK ) {
1099 		ComputeMotionBlock(prev->ref_cb, by, bx, fmy, fmx, prevBlock);
1100 		ComputeMotionBlock(next->ref_cb, by, bx, bmy, bmx, nextBlock);
1101 	    } else if ( type == CR_BLOCK ) {
1102 		ComputeMotionBlock(prev->ref_cr, by, bx, fmy, fmx, prevBlock);
1103 		ComputeMotionBlock(next->ref_cr, by, bx, bmy, bmx, nextBlock);
1104 	    }
1105 
1106 	    for ( y = 0; y < 8; y++ ) {
1107 		for ( x = 0; x < 8; x++ ) {
1108 		    motionBlock[y][x] = (prevBlock[y][x]+nextBlock[y][x]+1)/2;
1109 		}
1110 	    }
1111 	    break;
1112     }
1113 }
1114 
1115 
1116 /*===========================================================================*
1117  *
1118  * ComputeBDiffDCTs
1119  *
1120  *	compute the DCT of the error term
1121  *
1122  * RETURNS:	appropriate blocks of current will contain the DCTs
1123  *
1124  * SIDE EFFECTS:    none
1125  *
1126  * PRECONDITION:	the motion vectors must be valid!
1127  *
1128  *===========================================================================*/
1129 static void
ComputeBDiffDCTs(current,prev,next,by,bx,mode,fmy,fmx,bmy,bmx,pattern)1130 ComputeBDiffDCTs(current, prev, next, by, bx, mode, fmy, fmx, bmy, bmx, pattern)
1131     MpegFrame *current;
1132     MpegFrame *prev;
1133     MpegFrame *next;
1134     int by;
1135     int bx;
1136     int mode;
1137     int fmy;
1138     int fmx;
1139     int bmy;
1140     int bmx;
1141     int *pattern;
1142 {
1143     Block   motionBlock;
1144 
1145     if ( *pattern & 0x20 ) {
1146 	ComputeBMotionBlock(prev, next, by, bx, mode, fmy, fmx,
1147 			    bmy, bmx, motionBlock, LUM_BLOCK);
1148 	if (! ComputeDiffDCTBlock(current->y_blocks[by][bx], dct[by][bx], motionBlock)) {
1149 	  *pattern ^=  0x20;
1150 	}
1151     }
1152 
1153     if ( *pattern & 0x10 ) {
1154 	ComputeBMotionBlock(prev, next, by, bx+1, mode, fmy, fmx,
1155 			    bmy, bmx, motionBlock, LUM_BLOCK);
1156 	if (! ComputeDiffDCTBlock(current->y_blocks[by][bx+1], dct[by][bx+1], motionBlock)) {
1157 	  *pattern ^=  0x10;
1158 	}
1159     }
1160 
1161     if ( *pattern & 0x8 ) {
1162 	ComputeBMotionBlock(prev, next, by+1, bx, mode, fmy, fmx,
1163 			    bmy, bmx, motionBlock, LUM_BLOCK);
1164 	if (! ComputeDiffDCTBlock(current->y_blocks[by+1][bx], dct[by+1][bx], motionBlock)) {
1165 	  *pattern ^= 0x8;
1166 	}
1167     }
1168 
1169     if ( *pattern & 0x4 ) {
1170 	ComputeBMotionBlock(prev, next, by+1, bx+1, mode, fmy, fmx,
1171 			    bmy, bmx, motionBlock, LUM_BLOCK);
1172 	if (! ComputeDiffDCTBlock(current->y_blocks[by+1][bx+1], dct[by+1][bx+1], motionBlock)) {
1173 	  *pattern ^= 0x4;
1174 	}
1175     }
1176 
1177     if ( *pattern & 0x2 ) {
1178 	ComputeBMotionBlock(prev, next, by>>1, bx>>1, mode, fmy/2, fmx/2,
1179 			    bmy/2, bmx/2, motionBlock, CB_BLOCK);
1180 	if (! ComputeDiffDCTBlock(current->cb_blocks[by >> 1][bx >> 1], dctb[by >> 1][bx >> 1], motionBlock)) {
1181 	  *pattern ^= 0x2;
1182 	}
1183     }
1184 
1185     if ( *pattern & 0x1 ) {
1186 	ComputeBMotionBlock(prev, next, by>>1, bx>>1, mode, fmy/2, fmx/2,
1187 			    bmy/2, bmx/2, motionBlock, CR_BLOCK);
1188 	if (! ComputeDiffDCTBlock(current->cr_blocks[by >> 1][bx >> 1], dctr[by >> 1][bx >> 1], motionBlock)) {
1189 	  *pattern ^= 0x1;
1190 	}
1191     }
1192 }
1193 
1194 
1195 /*===========================================================================*
1196  *
1197  *			    USER-MODIFIABLE
1198  *
1199  * DoBIntraCode
1200  *
1201  *	decides if this block should be coded as intra-block
1202  *
1203  * RETURNS:	TRUE if intra-coding should be used; FALSE otherwise
1204  *
1205  * SIDE EFFECTS:    none
1206  *
1207  * PRECONDITION:	the motion vectors must be valid!
1208  *
1209  *===========================================================================*/
1210 static boolean
DoBIntraCode(current,prev,next,by,bx,mode,fmy,fmx,bmy,bmx)1211 DoBIntraCode(current, prev, next, by, bx, mode, fmy, fmx, bmy, bmx)
1212     MpegFrame *current;
1213     MpegFrame *prev;
1214     MpegFrame *next;
1215     int by;
1216     int bx;
1217     int mode;
1218     int fmy;
1219     int fmx;
1220     int bmy;
1221     int bmx;
1222 {
1223     int	    x, y;
1224     int32 sum = 0, vard = 0, varc = 0, dif;
1225     int32 currPixel, prevPixel;
1226     LumBlock	motionBlock;
1227     int	    fy, fx;
1228 
1229     ComputeBMotionLumBlock(prev, next, by, bx, mode, fmy, fmx,
1230 			   bmy, bmx, motionBlock);
1231 
1232     MOTION_TO_FRAME_COORD(by, bx, 0, 0, fy, fx);
1233 
1234     for ( y = 0; y < 16; y++ ) {
1235 	for ( x = 0; x < 16; x++ ) {
1236 	    currPixel = current->orig_y[fy+y][fx+x];
1237 	    prevPixel = motionBlock[y][x];
1238 
1239 	    sum += currPixel;
1240 	    varc += currPixel*currPixel;
1241 
1242 	    dif = currPixel - prevPixel;
1243 	    vard += dif*dif;
1244 	}
1245     }
1246 
1247     vard >>= 8;		/* divide by 256; assumes mean is close to zero */
1248     varc = (varc>>8) - (sum>>8)*(sum>>8);
1249 
1250     if ( vard <= 64 ) {
1251 	return FALSE;
1252     } else if ( vard < varc ) {
1253 	return FALSE;
1254     } else {
1255 	return TRUE;
1256     }
1257 }
1258 
1259 static int
ComputeBlockColorDiff(current,motionBlock)1260 ComputeBlockColorDiff(current, motionBlock)
1261     Block current, motionBlock;
1262 {
1263   register int x, y, diff_total = 0, diff_tmp;
1264 
1265   for ( y = 0; y < 8; y++ ) {
1266     for ( x = 0; x < 8; x++ ) {
1267       diff_tmp = current[y][x] - motionBlock[y][x];
1268       diff_total += ABS(diff_tmp);
1269     }
1270   }
1271   return diff_total;
1272 }
1273 
1274 /*===========================================================================*
1275  *
1276  *			    USER-MODIFIABLE
1277  *
1278  * MotionSufficient
1279  *
1280  *	decides if this motion vector is sufficient without DCT coding
1281  *
1282  * RETURNS:	TRUE if no DCT is needed; FALSE otherwise
1283  *
1284  * SIDE EFFECTS:    none
1285  *
1286  * PRECONDITION:	the motion vectors must be valid!
1287  *
1288  *===========================================================================*/
1289 static boolean
MotionSufficient(curr,currBlock,prev,next,by,bx,mode,fmy,fmx,bmy,bmx)1290 MotionSufficient(curr, currBlock, prev, next, by, bx, mode, fmy, fmx, bmy, bmx)
1291     MpegFrame *curr;
1292     LumBlock currBlock;
1293     MpegFrame *prev;
1294     MpegFrame *next;
1295     int by, bx;
1296     int mode;
1297     int fmy, fmx;
1298     int bmy, bmx;
1299 {
1300     LumBlock   mLumBlock;
1301     Block mColorBlock;
1302     int lumErr, colorErr;
1303 
1304     /* check bounds */
1305     if ( mode != MOTION_BACKWARD ) {
1306 	if ( (by*DCTSIZE+(fmy-1)/2 < 0) || ((by+2)*DCTSIZE+(fmy+1)/2-1 >= Fsize_y) ) {
1307 	    return FALSE;
1308 	}
1309 	if ( (bx*DCTSIZE+(fmx-1)/2 < 0) || ((bx+2)*DCTSIZE+(fmx+1)/2-1 >= Fsize_x) ) {
1310 	    return FALSE;
1311 	}
1312     }
1313 
1314     if ( mode != MOTION_FORWARD ) {
1315 	if ( (by*DCTSIZE+(bmy-1)/2 < 0) || ((by+2)*DCTSIZE+(bmy+1)/2-1 >= Fsize_y) ) {
1316 	    return FALSE;
1317 	}
1318 	if ( (bx*DCTSIZE+(bmx-1)/2 < 0) || ((bx+2)*DCTSIZE+(bmx+1)/2-1 >= Fsize_x) ) {
1319 	    return FALSE;
1320 	}
1321     }
1322 
1323     /* check Lum */
1324     ComputeBMotionLumBlock(prev, next, by, bx, mode, fmy, fmx,
1325 			   bmy, bmx, mLumBlock);
1326     lumErr =  LumBlockMAD(currBlock, mLumBlock, 0x7fffffff);
1327     if (lumErr > 512) {
1328       return FALSE;
1329     }
1330 
1331     /* check color */
1332     ComputeBMotionBlock(prev, next, by>>1, bx>>1, mode, fmy/2, fmx/2,
1333 			bmy/2, bmx/2, mColorBlock, CR_BLOCK);
1334     colorErr = ComputeBlockColorDiff(curr->cr_blocks[by >> 1][bx >> 1], mColorBlock);
1335     ComputeBMotionBlock(prev, next, by>>1, bx>>1, mode, fmy/2, fmx/2,
1336 			bmy/2, bmx/2, mColorBlock, CB_BLOCK);
1337     colorErr += ComputeBlockColorDiff(curr->cr_blocks[by >> 1][bx >> 1], mColorBlock);
1338 
1339     return (colorErr < 256); /* lumErr checked above */
1340 }
1341 
1342 
1343