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