1 /*===========================================================================*
2  * pframe.c
3  *
4  *  Procedures concerned with generation of P-frames
5  *
6  * EXPORTED PROCEDURES:
7  *  GenPFrame
8  *  ResetPFrameStats
9  *  ShowPFrameSummary
10  *  EstimateSecondsPerPFrame
11  *  ComputeHalfPixelData
12  *  SetPQScale
13  *  GetPQScale
14  *
15  * NOTE:  when motion vectors are passed as arguments, they are passed as
16  *        twice their value.  In other words, a motion vector of (3,4) will
17  *        be passed as (6,8).  This allows half-pixel motion vectors to be
18  *        passed as integers.  This is true throughout the program.
19  *
20  *===========================================================================*/
21 
22 /*==============*
23  * HEADER FILES *
24  *==============*/
25 
26 #include <assert.h>
27 #include <sys/param.h>
28 #include "pm.h"
29 #include "pm_c_util.h"
30 #include "all.h"
31 #include "mtypes.h"
32 #include "bitio.h"
33 #include "frames.h"
34 #include "motion_search.h"
35 #include "prototypes.h"
36 #include "block.h"
37 #include "param.h"
38 #include "mheaders.h"
39 #include "fsize.h"
40 #include "postdct.h"
41 #include "mpeg.h"
42 #include "parallel.h"
43 #include "rate.h"
44 #include "opts.h"
45 #include "specifics.h"
46 
47 /*==================*
48  * STATIC VARIABLES *
49  *==================*/
50 
51 static int32    zeroDiff;
52 static int      numPIBlocks = 0;
53 static int      numPPBlocks = 0;
54 static int      numPSkipped = 0;
55 static int      numPIBits = 0;
56 static int      numPPBits = 0;
57 static int      numFrames = 0;
58 static int      numFrameBits = 0;
59 static int32    totalTime = 0;
60 static int      qscaleP;
61 static float    totalSNR = 0.0;
62 static float    totalPSNR = 0.0;
63 
64 /*=====================*
65  * INTERNAL PROCEDURES *
66  *=====================*/
67 
68 static vector
halfVector(vector const vector)69 halfVector(vector const vector) {
70     struct vector half;
71 
72     half.y = vector.y/2;
73     half.x = vector.x/2;
74 
75     return half;
76 }
77 
78 /*===========================================================================*
79  *
80  *  decide if (0,0) motion is better than the given motion vector
81  *
82  * RETURNS: TRUE if (0,0) is better, FALSE if (my,mx) is better
83  *
84  * SIDE EFFECTS:    none
85  *
86  * PRECONDITIONS:   The relevant block in 'current' is valid (it has not
87  *          been dct'd).  'zeroDiff' has already been computed
88  *          as the LumMotionError() with (0,0) motion
89  *
90  * NOTES:   This procedure follows the algorithm described on
91  *      page D-48 of the MPEG-1 specification
92  *
93  *===========================================================================*/
94 static boolean
ZeroMotionBetter(const LumBlock * const currentBlockP,MpegFrame * const prev,int const by,int const bx,vector const m)95 ZeroMotionBetter(const LumBlock * const currentBlockP,
96                  MpegFrame *      const prev,
97                  int              const by,
98                  int              const bx,
99                  vector           const m) {
100 
101     int bestDiff;
102     int CompareMode;
103 
104     /* Junk needed to adapt for TUNEing */
105     CompareMode = SearchCompareMode;
106     SearchCompareMode = DEFAULT_SEARCH;
107     bestDiff = LumMotionError(currentBlockP, prev, by, bx, m, 0x7fffffff);
108     SearchCompareMode = CompareMode;
109 
110     if ( zeroDiff < 256*3 ) {
111     if ( 2*bestDiff >= zeroDiff ) {
112         return TRUE;
113     }
114     } else {
115     if ( 11*bestDiff >= 10*zeroDiff ) {
116         return TRUE;
117     }
118     }
119     return FALSE;
120 }
121 
122 
123 /*===========================================================================*
124  *
125  *                USER-MODIFIABLE
126  *
127  * DoIntraCode
128  *
129  *  decide if intra coding is necessary
130  *
131  * RETURNS: TRUE if intra-block coding is better; FALSE if not
132  *
133  * SIDE EFFECTS:    none
134  *
135  * PRECONDITIONS:   The relevant block in 'current' is valid (it has not
136  *          been dct'd).
137  *
138  * NOTES:   This procedure follows the algorithm described on
139  *      page D-49 of the MPEG-1 specification
140  *
141  *===========================================================================*/
142 static boolean
DoIntraCode(const LumBlock * const currentBlockP,MpegFrame * const prev,int const by,int const bx,vector const motion)143 DoIntraCode(const LumBlock * const currentBlockP,
144             MpegFrame *      const prev,
145             int              const by,
146             int              const bx,
147             vector           const motion) {
148 
149     unsigned int y;
150     int32 sum = 0, vard = 0, varc = 0;
151     int32 currPixel, prevPixel;
152     LumBlock motionBlock;
153 
154     ComputeMotionLumBlock(prev, by, bx, motion, &motionBlock);
155 
156     for (y = 0; y < 16; ++y) {
157         unsigned int x;
158         for (x = 0; x < 16; ++x) {
159             currPixel = currentBlockP->l[y][x];
160             prevPixel = motionBlock.l[y][x];
161 
162             sum += currPixel;
163             varc += currPixel*currPixel;
164 
165             vard += SQR(currPixel - prevPixel);
166         }
167     }
168 
169     vard /= 256;     /* divide by 256; assumes mean is close to zero */
170     varc = (varc/256) - (sum/256) * (sum/256);
171 
172     if (vard <= 64)
173         return FALSE;
174     else if (vard < varc)
175         return FALSE;
176     else
177         return TRUE;
178 }
179 
180 
181 
182 /*===========================================================================*
183  *
184  *                USER-MODIFIABLE
185  *
186  * ZeroMotionSufficient
187  *
188  *  decide if zero motion is sufficient without DCT correction
189  *
190  * RETURNS: TRUE no DCT required; FALSE otherwise
191  *
192  * SIDE EFFECTS:    none
193  *
194  * PRECONDITIONS:   The relevant block in 'current' is raw YCC data
195  *
196  *===========================================================================*/
197 static boolean
ZeroMotionSufficient(const LumBlock * const currentBlockP,MpegFrame * const prev,int const by,int const bx)198 ZeroMotionSufficient(const LumBlock * const currentBlockP,
199                      MpegFrame *      const prev,
200                      int              const by,
201                      int              const bx) {
202 
203     LumBlock motionBlock;
204     int fy, fx;
205     unsigned int y;
206 
207     fy = by * DCTSIZE;
208     fx = bx * DCTSIZE;
209     for (y = 0; y < 16; ++y) {
210         unsigned int x;
211         for (x = 0; x < 16; ++x) {
212             motionBlock.l[y][x] = prev->ref_y[fy+y][fx+x];
213         }
214     }
215 
216     zeroDiff = LumBlockMAD(currentBlockP, &motionBlock, 0x7fffffff);
217 
218     return (zeroDiff <= 256);
219 }
220 
221 
222 
223 static void
computeCurrentBlock(MpegFrame * const current,int const y,int const x,LumBlock * const currentBlockP)224 computeCurrentBlock(MpegFrame * const current,
225                     int         const y,
226                     int         const x,
227                     LumBlock *  const currentBlockP) {
228     int fy, fx;
229     int iy;
230 
231     BLOCK_TO_FRAME_COORD(y, x, fy, fx);
232     for ( iy = 0; iy < 16; iy++ ) {
233         int ix;
234         for ( ix = 0; ix < 16; ix++ ) {
235             currentBlockP->l[iy][ix] =
236                 (int16)current->orig_y[fy+iy][fx+ix];
237         }
238     }
239 }
240 
241 
242 
243 static void
computeMotionVectors(bool const specificsOn,bool const IntraPBAllowed,MpegFrame * const current,MpegFrame * const prev,int const mbAddress,BlockMV ** const infoP,int const QScale,const LumBlock * const currentBlockP,int const y,int const x,bool * const useMotionP,vector * const motionP)244 computeMotionVectors(bool             const specificsOn,
245                      bool             const IntraPBAllowed,
246                      MpegFrame *      const current,
247                      MpegFrame *      const prev,
248                      int              const mbAddress,
249                      BlockMV **       const infoP,
250                      int              const QScale,
251                      const LumBlock * const currentBlockP,
252                      int              const y,
253                      int              const x,
254                      bool *           const useMotionP,
255                      vector *         const motionP) {
256 
257     bool useCached;
258     BlockMV * info;
259 
260     /* See if we have a cached answer */
261     if (specificsOn) {
262         SpecLookup(current->id, 2, mbAddress, &info, QScale);
263         if (info != (BlockMV*)NULL)
264             useCached = TRUE;
265         else
266             useCached = FALSE;
267     } else
268         useCached = FALSE;
269 
270     if (useCached) {
271         if (info->typ == TYP_SKIP) {
272             motionP->x = motionP->y = 0;
273             *useMotionP = TRUE;
274         } else {        /* assume P, since we're a P frame.... */
275             motionP->x = info->fx;
276             motionP->y = info->fy;
277             *useMotionP = TRUE;
278         }
279     } else {
280         /* see if we should use motion vectors, and if so, what those
281          * vectors should be
282          */
283         if (ZeroMotionSufficient(currentBlockP, prev, y, x)) {
284             motionP->x = 0;
285             motionP->y = 0;
286             *useMotionP = TRUE;
287         } else {
288             vector motion;
289             motion.y = motion.x = 0;  /* initial values */
290             PMotionSearch(currentBlockP, prev, y, x, &motion);
291             if (ZeroMotionBetter(currentBlockP, prev, y, x, motion)) {
292                 motionP->y = 0;
293                 motionP->x = 0;
294             } else
295                 *motionP = motion;
296             if (IntraPBAllowed)
297                 *useMotionP = !DoIntraCode(currentBlockP, prev, y, x, motion);
298             else
299                 *useMotionP = TRUE;
300         }
301     }
302     *infoP = info;
303 }
304 
305 
306 
307 static void
calculateForwardDcts(MpegFrame * const current,int const y,int const x,Block ** const dct)308 calculateForwardDcts(MpegFrame * const current,
309                      int const y, int const x,
310                      Block ** const dct) {
311 
312     /* calculate forward dct's */
313     if (collect_quant && (collect_quant_detailed & 1))
314         fprintf(collect_quant_fp, "l\n");
315 
316     mp_fwd_dct_block2(current->y_blocks[y][x], dct[y][x]);
317     mp_fwd_dct_block2(current->y_blocks[y][x+1], dct[y][x+1]);
318     mp_fwd_dct_block2(current->y_blocks[y+1][x], dct[y+1][x]);
319     mp_fwd_dct_block2(current->y_blocks[y+1][x+1], dct[y+1][x+1]);
320 
321     if (collect_quant && (collect_quant_detailed & 1))
322         fprintf(collect_quant_fp, "c\n");
323 
324     mp_fwd_dct_block2(current->cb_blocks[y/2][x/2], dctb[y/2][x/2]);
325 
326     mp_fwd_dct_block2(current->cr_blocks[y/2][x/2], dctr[y/2][x/2]);
327 }
328 
329 
330 
331 static void
computeMotionAndDct(int const lastBlockY,int const lastBlockX,bool const specificsOn,bool const IntraPBAllowed,MpegFrame * const current,MpegFrame * const prev,BlockMV ** const infoP,int const QScale,int const searchRangeP,Block ** const dct,int * const numPBlocksP,int * const numIBlocksP,int ** const pmvHistogram)332 computeMotionAndDct(int         const lastBlockY,
333                     int         const lastBlockX,
334                     bool        const specificsOn,
335                     bool        const IntraPBAllowed,
336                     MpegFrame * const current,
337                     MpegFrame * const prev,
338                     BlockMV **  const infoP,
339                     int         const QScale,
340                     int         const searchRangeP,
341                     Block **    const dct,
342                     int *       const numPBlocksP,
343                     int *       const numIBlocksP,
344                     int **      const pmvHistogram) {
345 /*----------------------------------------------------------------------------
346    Loop through the frame finding motion/not and DCTing
347 -----------------------------------------------------------------------------*/
348     int mbAddress;
349     int y;
350 
351     mbAddress = 0;
352 
353     for (y = 0; y < lastBlockY; y += 2) {
354         int x;
355         for (x = 0; x < lastBlockX; x += 2) {
356             LumBlock currentBlock;
357             vector motion;
358             bool useMotion;
359 
360             computeCurrentBlock(current, y, x, &currentBlock);
361 
362             computeMotionVectors(specificsOn,  IntraPBAllowed,
363                                  current, prev, mbAddress, infoP,
364                                  QScale, &currentBlock, y, x,
365                                  &useMotion, &motion);
366 
367             dct_data[y][x].useMotion = useMotion;
368 
369             if (useMotion) {
370                 int pattern;
371 
372                 (*numPBlocksP)++;
373 
374                 pattern = 63;
375                 ComputeDiffDCTs(current, prev, y, x, motion, &pattern);
376 
377                 assert(motion.x + searchRangeP + 1 >= 0);
378                 assert(motion.y + searchRangeP + 1 >= 0);
379 
380                 if (computeMVHist) {
381                     assert(motion.x + searchRangeP + 1 <= 2*searchRangeP + 2);
382                     assert(motion.y + searchRangeP + 1 <= 2*searchRangeP + 2);
383                     ++pmvHistogram[motion.x + searchRangeP + 1]
384                         [motion.y + searchRangeP + 1];
385                 }
386                 /* Save specs for next loops */
387                 dct_data[y][x].pattern  = pattern;
388                 dct_data[y][x].fmotionX = motion.x;
389                 dct_data[y][x].fmotionY = motion.y;
390             } else {
391                 /* output I-block inside a P-frame */
392                 ++*numIBlocksP;
393 
394                 calculateForwardDcts(current, y, x, dct);
395             }
396             ++mbAddress;
397         }
398     }
399 }
400 
401 
402 
403 /*=====================*
404  * EXPORTED PROCEDURES *
405  *=====================*/
406 
407 /*===========================================================================*
408  *
409  * GenPFrame
410  *
411  *  generate a P-frame from previous frame, adding the result to the
412  *  given bit bucket
413  *
414  * RETURNS: frame appended to bb
415  *
416  *===========================================================================*/
417 void
GenPFrame(BitBucket * const bb,MpegFrame * const current,MpegFrame * const prev)418 GenPFrame(BitBucket * const bb,
419           MpegFrame * const current,
420           MpegFrame * const prev) {
421 
422     extern int **pmvHistogram;
423     FlatBlock fba[6], fb[6];
424     Block   dec[6];
425     int32 y_dc_pred, cr_dc_pred, cb_dc_pred;
426     int x, y;
427     vector motion;
428     vector oldMotion;
429     int offsetX, offsetY;
430     vector motionRem;
431     vector motionQuot;
432     int pattern;
433     int mbAddrInc = 1;
434     int numIBlocks = 0;
435     int numPBlocks = 0;
436     int numSkipped = 0;
437     int numIBits = 0;
438     int numPBits = 0;
439     int totalBits;
440     int totalFrameBits;
441     int32    startTime, endTime;
442     int lastBlockX, lastBlockY;
443     int lastX, lastY;
444     int mbAddress;
445     int slicePos;
446     register int index;
447     float   snr[3], psnr[3];
448     int QScale;
449     BlockMV *info;
450     int bitstreamMode, newQScale;
451     int rc_blockStart = 0;
452     boolean overflowChange = FALSE;
453     int     overflowValue  = 0;
454 
455 
456     oldMotion.x = oldMotion.y = 0;
457 
458     if (collect_quant) {fprintf(collect_quant_fp, "# P\n");}
459     if (dct==NULL) AllocDctBlocks();
460     numFrames++;
461     totalFrameBits = bb->cumulativeBits;
462     startTime = time_elapsed();
463 
464     DBG_PRINT(("Generating pframe\n"));
465 
466     QScale = GetPQScale();
467     /*   bit allocation for rate control purposes */
468     bitstreamMode = getRateMode();
469     if (bitstreamMode == FIXED_RATE) {
470         targetRateControl(current);
471     }
472 
473     Mhead_GenPictureHeader(bb, P_FRAME, current->id, fCodeP);
474     /* Check for Qscale change */
475     if (specificsOn) {
476         /* Set a Qscale for this frame? */
477         newQScale =
478             SpecLookup(current->id, 0, 0 /* junk */, &info /*junk*/, QScale);
479         if (newQScale != -1) {
480             QScale = newQScale;
481         }
482         /* Set for slice? */
483         newQScale = SpecLookup(current->id, 1, 1, &info /*junk*/, QScale);
484         if (newQScale != -1) {
485             QScale = newQScale;
486         }
487     }
488 
489     DBG_PRINT(("Slice Header\n"));
490     Mhead_GenSliceHeader(bb, 1, QScale, NULL, 0);
491 
492     if ( referenceFrame == DECODED_FRAME ) {
493         Frame_AllocDecoded(current, TRUE);
494     } else if ( printSNR ) {
495         Frame_AllocDecoded(current, FALSE);
496     }
497 
498     /* don't do dct on blocks yet */
499     Frame_AllocBlocks(current);
500     BlockifyFrame(current);
501 
502     /* for I-blocks */
503     y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
504 
505     totalBits = bb->cumulativeBits;
506 
507     if ( (! pixelFullSearch) && (! prev->halfComputed) ) {
508         ComputeHalfPixelData(prev);
509     }
510 
511     lastBlockX = Fsize_x>>3;
512     lastBlockY = Fsize_y>>3;
513     lastX = lastBlockX-2;
514     lastY = lastBlockY-2;
515 
516     computeMotionAndDct(lastBlockY, lastBlockX,
517                         specificsOn, IntraPBAllowed, current, prev,
518                         &info, QScale, searchRangeP, dct,
519                         &numPBlocks, &numIBlocks, pmvHistogram);
520 
521     mbAddress = 0;
522     for (y = 0; y < lastBlockY; y += 2) {
523         for (x = 0; x < lastBlockX; x += 2) {
524             slicePos = (mbAddress % blocksPerSlice);
525 
526             if ( (slicePos == 0) && (mbAddress != 0) ) {
527                 if (specificsOn) {
528                     /* Make sure no slice Qscale change */
529                     newQScale =
530                         SpecLookup(current->id, 1, mbAddress/blocksPerSlice,
531                                    &info /*junk*/, QScale);
532                     if (newQScale != -1) QScale = newQScale;
533                 }
534 
535                 Mhead_GenSliceEnder(bb);
536                 Mhead_GenSliceHeader(bb, 1+(y>>1), QScale, NULL, 0);
537 
538                 /* reset everything */
539                 oldMotion.x = oldMotion.y = 0;
540                 y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
541 
542                 mbAddrInc = 1+(x>>1);
543             }
544 
545             /*  Determine if new Qscale needed for Rate Control purposes  */
546             if (bitstreamMode == FIXED_RATE) {
547                 rc_blockStart =  bb->cumulativeBits;
548                 newQScale = needQScaleChange(qscaleP,
549                                              current->y_blocks[y][x],
550                                              current->y_blocks[y][x+1],
551                                              current->y_blocks[y+1][x],
552                                              current->y_blocks[y+1][x+1]);
553                 if (newQScale > 0) {
554                     QScale = newQScale;
555                 }
556             }
557 
558             /* Check for Qscale change */
559             if (specificsOn) {
560                 newQScale =
561                     SpecLookup(current->id, 2, mbAddress, &info, QScale);
562                 if (newQScale != -1) {
563                     QScale = newQScale;
564                 }
565             }
566 
567             if (! dct_data[y][x].useMotion) {
568                 GEN_I_BLOCK(P_FRAME, current, bb, mbAddrInc, QScale);
569                 mbAddrInc = 1;
570 
571                 numIBits += (bb->cumulativeBits-totalBits);
572                 totalBits = bb->cumulativeBits;
573 
574                 /* reset because intra-coded */
575                 oldMotion.x = oldMotion.y = 0;
576 
577                 if ( decodeRefFrames ) {
578                     /* need to decode block we just encoded */
579                     Mpost_UnQuantZigBlock(fb[0], dec[0], QScale, TRUE);
580                     Mpost_UnQuantZigBlock(fb[1], dec[1], QScale, TRUE);
581                     Mpost_UnQuantZigBlock(fb[2], dec[2], QScale, TRUE);
582                     Mpost_UnQuantZigBlock(fb[3], dec[3], QScale, TRUE);
583                     Mpost_UnQuantZigBlock(fb[4], dec[4], QScale, TRUE);
584                     Mpost_UnQuantZigBlock(fb[5], dec[5], QScale, TRUE);
585 
586                     /* now, reverse the DCT transform */
587                     for ( index = 0; index < 6; index++ ) {
588                         mpeg_jrevdct((int16 *)dec[index]);
589                     }
590 
591                     /* now, unblockify */
592                     BlockToData(current->decoded_y, dec[0], y, x);
593                     BlockToData(current->decoded_y, dec[1], y, x+1);
594                     BlockToData(current->decoded_y, dec[2], y+1, x);
595                     BlockToData(current->decoded_y, dec[3], y+1, x+1);
596                     BlockToData(current->decoded_cb, dec[4], y>>1, x>>1);
597                     BlockToData(current->decoded_cr, dec[5], y>>1, x>>1);
598                 }
599             } else {
600                 int fCode = fCodeP;
601 
602                 /* reset because non-intra-coded */
603                 y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
604 
605                 pattern = dct_data[y][x].pattern;
606                 motion.x = dct_data[y][x].fmotionX;
607                 motion.y = dct_data[y][x].fmotionY;
608 
609 #ifdef BLEAH
610                 ComputeAndPrintPframeMAD(currentBlock, prev, y, x, motion,
611                                          mbAddress);
612 #endif
613 
614                 if ( pixelFullSearch ) { /* should be even */
615                     motion.y /= 2;
616                     motion.x /= 2;
617                 }
618 
619                 /* transform the motion vector into the appropriate values */
620                 offsetX = motion.x - oldMotion.x;
621                 offsetY = motion.y - oldMotion.y;
622                 /*  if ((offsetX+(8*x)) >= (Fsize_x-8)) log(10.0); */
623                 encodeMotionVector(offsetX, offsetY, &motionQuot, &motionRem,
624                                    FORW_F, fCode);
625 
626 #ifdef BLEAH
627                 if ( (motion.x != 0) || (motion.y != 0) ) {
628                     fprintf(stdout, "FRAME (y, x)  %d, %d (block %d)\n",
629                             y, x, mbAddress);
630                     fprintf(stdout, "motion.x = %d, motion.y = %d\n",
631                             motion.x, motion.y);
632                     fprintf(stdout,
633                             "    mxq, mxr = %d, %d    myq, myr = %d, %d\n",
634                             motionQuot.x, motionRem.x,
635                             motionQuot.y, motionRem.y);
636                 }
637 #endif
638 
639                 oldMotion = motion;
640 
641                 if ( pixelFullSearch ) { /* reset for use with PMotionSearch */
642                     motion.y *= 2;
643                     motion.x *= 2;
644                 }
645             calc_blocks:
646                 /* create flat blocks and update pattern if necessary */
647                 /* Note DoQuant references QScale, overflowChange,
648                    overflowValue, pattern, and the calc_blocks label */
649                 DoQuant(0x20, dct[y][x], fba[0]);
650                 DoQuant(0x10, dct[y][x+1], fba[1]);
651                 DoQuant(0x08, dct[y+1][x], fba[2]);
652                 DoQuant(0x04, dct[y+1][x+1], fba[3]);
653                 DoQuant(0x02, dctb[y/2][x/2], fba[4]);
654                 DoQuant(0x01, dctr[y/2][x/2], fba[5]);
655 
656                 if ( decodeRefFrames) {
657                     for ( index = 0; index < 6; index++ ) {
658                         if ( pattern & (1 << (5-index))) {
659                             Mpost_UnQuantZigBlock(fba[index], dec[index],
660                                                   QScale, FALSE);
661                             mpeg_jrevdct((int16 *)dec[index]);
662                         } else {
663                             memset((char *)dec[index], 0, sizeof(Block));
664                         }
665                     }
666 
667                     /* now add the motion block */
668                     AddMotionBlock(dec[0], prev->decoded_y, y, x, motion);
669                     AddMotionBlock(dec[1], prev->decoded_y, y, x+1, motion);
670                     AddMotionBlock(dec[2], prev->decoded_y, y+1, x, motion);
671                     AddMotionBlock(dec[3], prev->decoded_y, y+1, x+1, motion);
672                     AddMotionBlock(dec[4], prev->decoded_cb, y/2, x/2,
673                                    halfVector(motion));
674                     AddMotionBlock(dec[5], prev->decoded_cr, y/2, x/2,
675                                    halfVector(motion));
676 
677                     /* now, unblockify */
678                     BlockToData(current->decoded_y, dec[0], y, x);
679                     BlockToData(current->decoded_y, dec[1], y, x+1);
680                     BlockToData(current->decoded_y, dec[2], y+1, x);
681                     BlockToData(current->decoded_y, dec[3], y+1, x+1);
682                     BlockToData(current->decoded_cb, dec[4], y/2, x/2);
683                     BlockToData(current->decoded_cr, dec[5], y/2, x/2);
684                 }
685 
686                 if ((motion.x == 0) && (motion.y == 0)) {
687                     if ( pattern == 0 ) {
688                         /* can only skip if:
689                          *     1)  not the last block in frame
690                          *     2)  not the last block in slice
691                          *     3)  not the first block in slice
692                          */
693 
694                         if ( ((y < lastY) || (x < lastX)) &&
695                              (slicePos+1 != blocksPerSlice) &&
696                              (slicePos != 0) ) {
697                             mbAddrInc++;    /* skipped macroblock */
698                             numSkipped++;
699                             numPBlocks--;
700                         } else {        /* first/last macroblock */
701                             Mhead_GenMBHeader(bb, 2 /* pict_code_type */,
702                                               mbAddrInc /* addr_incr */,
703                                               QScale /* q_scale */,
704                                               fCode /* forw_f_code */,
705                                               1 /* back_f_code */,
706                                               motionRem.x /* horiz_forw_r */,
707                                               motionRem.y /* vert_forw_r */,
708                                               0 /* horiz_back_r */,
709                                               0 /* vert_back_r */,
710                                               1 /* motion_forw */,
711                                               motionQuot.x /* m_horiz_forw */,
712                                               motionQuot.y /* m_vert_forw */,
713                                               0 /* motion_back */,
714                                               0 /* m_horiz_back */,
715                                               0 /* m_vert_back */,
716                                               0 /* mb_pattern */,
717                                               0 /* mb_intra */);
718                             mbAddrInc = 1;
719                         }
720                     } else {
721                         DBG_PRINT(("MB Header(%d,%d)\n", x, y));
722                         Mhead_GenMBHeader(bb, 2 /* pict_code_type */,
723                                           mbAddrInc /* addr_incr */,
724                                           QScale /* q_scale */,
725                                           fCode /* forw_f_code */,
726                                           1 /* back_f_code */,
727                                           0 /* horiz_forw_r */,
728                                           0 /* vert_forw_r */,
729                                           0 /* horiz_back_r */,
730                                           0 /* vert_back_r */,
731                                           0 /* motion_forw */,
732                                           0 /* m_horiz_forw */,
733                                           0 /* m_vert_forw */,
734                                           0 /* motion_back */,
735                                           0 /* m_horiz_back */,
736                                           0 /* m_vert_back */,
737                                           pattern /* mb_pattern */,
738                                           0 /* mb_intra */);
739                         mbAddrInc = 1;
740                     }
741                 } else {
742                     /*      DBG_PRINT(("MB Header(%d,%d)\n", x, y));  */
743 
744                     Mhead_GenMBHeader(bb, 2 /* pict_code_type */,
745                                       mbAddrInc /* addr_incr */,
746                                       QScale /* q_scale */,
747                                       fCode /* forw_f_code */,
748                                       1 /* back_f_code */,
749                                       motionRem.x /* horiz_forw_r */,
750                                       motionRem.y /* vert_forw_r */,
751                                       0 /* horiz_back_r */,
752                                       0 /* vert_back_r */,
753                                       1 /* motion_forw */,
754                                       motionQuot.x /* m_horiz_forw */,
755                                       motionQuot.y /* m_vert_forw */,
756                                       0 /* motion_back */,
757                                       0 /* m_horiz_back */,
758                                       0 /* m_vert_back */,
759                                       pattern /* mb_pattern */,
760                                       0 /* mb_intra */);
761                     mbAddrInc = 1;
762                 }
763 
764                 /* now output the difference */
765                 {
766                     unsigned int x;
767                     for (x = 0; x < 6; ++x) {
768                         if (GET_ITH_BIT(pattern, 5-x))
769                             Mpost_RLEHuffPBlock(fba[x], bb);
770                     }
771                 }
772                 numPBits += (bb->cumulativeBits-totalBits);
773                 totalBits = bb->cumulativeBits;
774             }
775 
776             if (overflowChange) {
777                 /* undo an overflow-caused Qscale change */
778                 overflowChange = FALSE;
779                 QScale -= overflowValue;
780                 overflowValue = 0;
781             }
782 
783             mbAddress++;
784             /*   Rate Control  */
785             if (bitstreamMode == FIXED_RATE) {
786                 incMacroBlockBits( bb->cumulativeBits- rc_blockStart);
787                 rc_blockStart = bb->cumulativeBits;
788                 MB_RateOut(TYPE_PFRAME);
789             }
790         }
791     }
792 
793     if ( printSNR ) {
794         BlockComputeSNR(current,snr,psnr);
795         totalSNR += snr[0];
796         totalPSNR += psnr[0];
797     }
798 
799 #ifdef BLEAHBLEAH
800     {
801         FILE *filePtr;
802 
803         filePtr = fopen("PFRAME.yuv", "wb");
804 
805         for ( y = 0; y < Fsize_y; y++ )
806         {
807             for ( x = 0; x < Fsize_x; x++ )
808                 fprintf(filePtr, "%d ", current->decoded_y[y][x]);
809             fprintf(filePtr, "\n");
810         }
811 
812         fclose(filePtr);
813     }
814 #endif
815 
816     Mhead_GenSliceEnder(bb);
817     /*   Rate Control */
818     if (bitstreamMode == FIXED_RATE) {
819         updateRateControl(TYPE_PFRAME);
820     }
821 
822     /* UPDATE STATISTICS */
823     endTime = time_elapsed();
824     totalTime += (endTime-startTime);
825 
826     if ( showBitRatePerFrame ) {
827         /* ASSUMES 30 FRAMES PER SECOND */
828         fprintf(bitRateFile, "%5d\t%8d\n", current->id,
829                 30*(bb->cumulativeBits-totalFrameBits));
830     }
831 
832     if ( frameSummary && (! realQuiet) ) {
833         fprintf(stdout, "FRAME %d (P):  I BLOCKS:  %d;  "
834                 "P BLOCKS:  %d   SKIPPED:  %d  (%ld seconds)\n",
835                 current->id, numIBlocks, numPBlocks, numSkipped,
836                 (long)(endTime-startTime)/TIME_RATE);
837         if ( printSNR ) {
838             fprintf(stdout, "FRAME %d:  SNR:  %.1f\t%.1f\t%.1f\t"
839                     "PSNR:  %.1f\t%.1f\t%.1f\n",
840                     current->id, snr[0], snr[1], snr[2],
841                     psnr[0], psnr[1], psnr[2]);
842         }
843     }
844 
845     numFrameBits += (bb->cumulativeBits-totalFrameBits);
846     numPIBlocks += numIBlocks;
847     numPPBlocks += numPBlocks;
848     numPSkipped += numSkipped;
849     numPIBits += numIBits;
850     numPPBits += numPBits;
851 }
852 
853 
854 /*===========================================================================*
855  *
856  * ResetPFrameStats
857  *
858  *  reset the P-frame statistics
859  *
860  * RETURNS: nothing
861  *
862  * SIDE EFFECTS:    none
863  *
864  *===========================================================================*/
865 void
ResetPFrameStats()866   ResetPFrameStats()
867 {
868   numPIBlocks = 0;
869   numPPBlocks = 0;
870   numPSkipped = 0;
871   numPIBits = 0;
872   numPPBits = 0;
873   numFrames = 0;
874   numFrameBits = 0;
875   totalTime = 0;
876 }
877 
878 
879 /*===========================================================================*
880  *
881  * SetPQScale
882  *
883  *  set the P-frame Q-scale
884  *
885  * RETURNS: nothing
886  *
887  * SIDE EFFECTS:    qscaleP
888  *
889  *===========================================================================*/
890 void
SetPQScale(qP)891   SetPQScale(qP)
892 int qP;
893 {
894   qscaleP = qP;
895 }
896 
897 
898 /*===========================================================================*
899  *
900  * GetPQScale
901  *
902  *  return the P-frame Q-scale
903  *
904  * RETURNS: the P-frame Q-scale
905  *
906  * SIDE EFFECTS:    none
907  *
908  *===========================================================================*/
909 int
GetPQScale()910   GetPQScale()
911 {
912   return qscaleP;
913 }
914 
915 
916 float
PFrameTotalTime(void)917 PFrameTotalTime(void) {
918     return (float)totalTime/(float)TIME_RATE;
919 }
920 
921 
922 
923 void
ShowPFrameSummary(unsigned int const inputFrameBits,unsigned int const totalBits,FILE * const fpointer)924 ShowPFrameSummary(unsigned int const inputFrameBits,
925                   unsigned int const totalBits,
926                   FILE *       const fpointer) {
927 
928     if (numFrames > 0) {
929 
930         fprintf(fpointer, "-------------------------\n");
931         fprintf(fpointer, "*****P FRAME SUMMARY*****\n");
932         fprintf(fpointer, "-------------------------\n");
933 
934         if ( numPIBlocks != 0 ) {
935             fprintf(fpointer, "  I Blocks:  %5d     (%6d bits)     (%5d bpb)\n",
936                     numPIBlocks, numPIBits, numPIBits/numPIBlocks);
937         } else {
938             fprintf(fpointer, "  I Blocks:  %5d\n", 0);
939         }
940 
941         if ( numPPBlocks != 0 ) {
942             fprintf(fpointer, "  P Blocks:  %5d     (%6d bits)     (%5d bpb)\n",
943                     numPPBlocks, numPPBits, numPPBits/numPPBlocks);
944         } else {
945             fprintf(fpointer, "  P Blocks:  %5d\n", 0);
946         }
947 
948         fprintf(fpointer, "  Skipped:   %5d\n", numPSkipped);
949 
950         fprintf(fpointer, "  Frames:    %5d     (%6d bits)     (%5d bpf)     (%2.1f%% of total)\n",
951                 numFrames, numFrameBits, numFrameBits/numFrames,
952                 100.0*(float)numFrameBits/(float)totalBits);
953         fprintf(fpointer, "  Compression:  %3d:1     (%9.4f bpp)\n",
954                 numFrames*inputFrameBits/numFrameBits,
955                 24.0*(float)numFrameBits/(float)(numFrames*inputFrameBits));
956         if ( printSNR )
957             fprintf(fpointer, "  Avg Y SNR/PSNR:  %.1f     %.1f\n",
958                     totalSNR/(float)numFrames, totalPSNR/(float)numFrames);
959         if ( totalTime == 0 ) {
960             fprintf(fpointer, "  Seconds:  NONE\n");
961         } else {
962             fprintf(fpointer, "  Seconds:  %9ld     (%9.4f fps)  (%9ld pps)  (%9ld mps)\n",
963                     (long)(totalTime/TIME_RATE),
964                     (float)((float)(TIME_RATE*numFrames)/(float)totalTime),
965                     (long)((float)TIME_RATE*(float)numFrames*(float)inputFrameBits/(24.0*(float)totalTime)),
966                     (long)((float)TIME_RATE*(float)numFrames*(float)inputFrameBits/(256.0*24.0*(float)totalTime)));
967         }
968     }
969 }
970 
971 
972 
973 /*===========================================================================*
974  *
975  * EstimateSecondsPerPFrame
976  *
977  *  compute an estimate of the number of seconds required per P-frame
978  *
979  * RETURNS: the estimate, in seconds
980  *
981  * SIDE EFFECTS:    none
982  *
983  *===========================================================================*/
984 float
EstimateSecondsPerPFrame()985   EstimateSecondsPerPFrame()
986 {
987   if ( numFrames == 0 ) {
988     return 10.0;
989   } else {
990     return (float)totalTime/((float)TIME_RATE*(float)numFrames);
991   }
992 }
993 
994 
995 /*===========================================================================*
996  *
997  * ComputeHalfPixelData
998  *
999  *  compute all half-pixel data required for half-pixel motion vector
1000  *  search (luminance only)
1001  *
1002  * RETURNS: frame->halfX, ->halfY, and ->halfBoth modified
1003  *
1004  * SIDE EFFECTS:    none
1005  *
1006  *===========================================================================*/
1007 void
ComputeHalfPixelData(frame)1008   ComputeHalfPixelData(frame)
1009 MpegFrame *frame;
1010 {
1011   register int x, y;
1012 
1013   /* we add 1 before dividing by 2 because .5 is supposed to be rounded up
1014    * (see MPEG-1, page D-31)
1015    */
1016 
1017   if ( frame->halfX == NULL ) { /* need to allocate memory */
1018     Frame_AllocHalf(frame);
1019   }
1020 
1021   /* compute halfX */
1022   for ( y = 0; y < Fsize_y; y++ ) {
1023     for ( x = 0; x < Fsize_x-1; x++ ) {
1024       frame->halfX[y][x] = (frame->ref_y[y][x]+
1025                 frame->ref_y[y][x+1]+1)>>1;
1026     }
1027   }
1028 
1029   /* compute halfY */
1030   for ( y = 0; y < Fsize_y-1; y++ ) {
1031     for ( x = 0; x < Fsize_x; x++ ) {
1032       frame->halfY[y][x] = (frame->ref_y[y][x]+
1033                 frame->ref_y[y+1][x]+1)>>1;
1034     }
1035   }
1036 
1037   /* compute halfBoth */
1038   for ( y = 0; y < Fsize_y-1; y++ ) {
1039     for ( x = 0; x < Fsize_x-1; x++ ) {
1040       frame->halfBoth[y][x] = (frame->ref_y[y][x]+
1041                    frame->ref_y[y][x+1]+
1042                    frame->ref_y[y+1][x]+
1043                    frame->ref_y[y+1][x+1]+2)>>2;
1044     }
1045   }
1046 
1047   frame->halfComputed = TRUE;
1048 }
1049 
1050 
1051 /*
1052  * Copyright (c) 1995 The Regents of the University of California.
1053  * All rights reserved.
1054  *
1055  * Permission to use, copy, modify, and distribute this software and its
1056  * documentation for any purpose, without fee, and without written agreement is
1057  * hereby granted, provided that the above copyright notice and the following
1058  * two paragraphs appear in all copies of this software.
1059  *
1060  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
1061  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
1062  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
1063  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1064  *
1065  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
1066  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
1067  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
1068  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
1069  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1070  */
1071