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