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, ¤tBlock);
361
362 computeMotionVectors(specificsOn, IntraPBAllowed,
363 current, prev, mbAddress, infoP,
364 QScale, ¤tBlock, 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