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, 3 months ago) by wdelano
File size: 38717 byte(s)
Log Message:
initial checkin of mpeg_encode source
Line File contents
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: /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 }