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, &currentBlock,
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, &currentBlock,
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