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