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