ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/freemol/trunk/src/mpeg_encode/src/pframe.c
Revision: 22
Committed: Mon Jul 7 22:16:37 2008 UTC (11 years, 4 months ago) by wdelano
File size: 30325 byte(s)
Log Message:
initial checkin of mpeg_encode source
Line File contents
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 <sys/param.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
205 GenPFrame(bb, current, prev)
206 BitBucket *bb;
207 MpegFrame *current;
208 MpegFrame *prev;
209 {
210 extern int **pmvHistogram;
211 FlatBlock fba[6], fb[6];
212 Block dec[6];
213 int32 y_dc_pred, cr_dc_pred, cb_dc_pred;
214 int x, y;
215 int motionX = 0, motionY = 0;
216 int oldMotionX = 0, oldMotionY = 0;
217 int offsetX, offsetY;
218 int tempX, tempY;
219 int motionXrem, motionXquot;
220 int motionYrem, motionYquot;
221 int pattern;
222 int mbAddrInc = 1;
223 boolean useMotion;
224 int numIBlocks = 0;
225 int numPBlocks = 0;
226 int numSkipped = 0;
227 int numIBits = 0;
228 int numPBits = 0;
229 int totalBits;
230 int totalFrameBits;
231 int32 startTime, endTime;
232 int lastBlockX, lastBlockY;
233 int lastX, lastY;
234 int fy, fx;
235 LumBlock currentBlock;
236 register int ix, iy;
237 int mbAddress;
238 int slicePos;
239 register int index;
240 float snr[3], psnr[3];
241 int QScale;
242 BlockMV *info;
243 int bitstreamMode, newQScale;
244 int rc_blockStart = 0;
245 boolean overflowChange = FALSE;
246 int overflowValue = 0;
247
248
249 if (collect_quant) {fprintf(collect_quant_fp, "# P\n");}
250 if (dct==NULL) AllocDctBlocks();
251 numFrames++;
252 totalFrameBits = bb->cumulativeBits;
253 startTime = time_elapsed();
254
255 DBG_PRINT(("Generating pframe\n"));
256
257 QScale = GetPQScale();
258 /* bit allocation for rate control purposes */
259 bitstreamMode = getRateMode();
260 if (bitstreamMode == FIXED_RATE) {
261 targetRateControl(current);
262 }
263
264 Mhead_GenPictureHeader(bb, P_FRAME, current->id, fCodeP);
265 /* Check for Qscale change */
266 if (specificsOn) {
267 /* Set a Qscale for this frame? */
268 newQScale = SpecLookup(current->id, 0, 0 /* junk */, &info /*junk*/, QScale);
269 if (newQScale != -1) {
270 QScale = newQScale;
271 }
272 /* Set for slice? */
273 newQScale = SpecLookup(current->id, 1, 1, &info /*junk*/, QScale);
274 if (newQScale != -1) {
275 QScale = newQScale;
276 }
277 }
278
279 DBG_PRINT(("Slice Header\n"));
280 Mhead_GenSliceHeader(bb, 1, QScale, NULL, 0);
281
282 if ( referenceFrame == DECODED_FRAME ) {
283 Frame_AllocDecoded(current, TRUE);
284 } else if ( printSNR ) {
285 Frame_AllocDecoded(current, FALSE);
286 }
287
288 /* don't do dct on blocks yet */
289 Frame_AllocBlocks(current);
290 BlockifyFrame(current);
291
292 /* for I-blocks */
293 y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
294
295 totalBits = bb->cumulativeBits;
296
297 if ( (! pixelFullSearch) && (! prev->halfComputed) ) {
298 ComputeHalfPixelData(prev);
299 }
300
301 lastBlockX = Fsize_x>>3;
302 lastBlockY = Fsize_y>>3;
303 lastX = lastBlockX-2;
304 lastY = lastBlockY-2;
305 mbAddress = 0;
306
307 /* First loop though finding motion/not and DCTing */
308 for (y = 0; y < lastBlockY; y += 2) {
309 for (x = 0; x < lastBlockX; x += 2) {
310 /* compute currentBlock */
311 BLOCK_TO_FRAME_COORD(y, x, fy, fx);
312 for ( iy = 0; iy < 16; iy++ ) {
313 for ( ix = 0; ix < 16; ix++ ) {
314 currentBlock[iy][ix] = (int16)current->orig_y[fy+iy][fx+ix];
315 }
316 }
317
318 /* See if we have a cached answer */
319 if (specificsOn) {
320 (void) SpecLookup(current->id, 2, mbAddress, &info, QScale);
321 if (info != (BlockMV*)NULL) {
322 if (info->typ == TYP_SKIP) {
323 motionX = motionY = 0;
324 useMotion = TRUE;
325 goto no_search;
326 } else { /* assume P, since we're a P frame.... */
327 motionX = info->fx;
328 motionY = info->fy;
329 useMotion = TRUE;
330 goto no_search;
331 }}
332 /* if unspecified, just look */
333 }
334
335 /* see if we should use motion vectors, and if so, what those
336 * vectors should be
337 */
338 if ( ZeroMotionSufficient(currentBlock, prev, y, x) ) {
339 motionX = 0;
340 motionY = 0;
341 useMotion = TRUE;
342 } else {
343 useMotion = PMotionSearch(currentBlock, prev, y, x,
344 &motionY, &motionX);
345 if ( useMotion ) {
346 if ( ZeroMotionBetter(currentBlock, prev, y, x, motionY,
347 motionX) ) {
348 motionX = 0;
349 motionY = 0;
350 }
351 if (IntraPBAllowed)
352 useMotion = (! DoIntraCode(currentBlock, prev, y, x,
353 motionY, motionX));
354 }
355 }
356
357 no_search:
358
359 dct_data[y][x].useMotion = useMotion;
360 if ( ! useMotion ) {
361 /* output I-block inside a P-frame */
362 numIBlocks++;
363
364 /* calculate forward dct's */
365 if (collect_quant && (collect_quant_detailed & 1)) fprintf(collect_quant_fp, "l\n");
366 mp_fwd_dct_block2(current->y_blocks[y][x], dct[y][x]);
367 mp_fwd_dct_block2(current->y_blocks[y][x+1], dct[y][x+1]);
368 mp_fwd_dct_block2(current->y_blocks[y+1][x], dct[y+1][x]);
369 mp_fwd_dct_block2(current->y_blocks[y+1][x+1], dct[y+1][x+1]);
370 if (collect_quant && (collect_quant_detailed & 1)) fprintf(collect_quant_fp, "c\n");
371 mp_fwd_dct_block2(current->cb_blocks[y>>1][x>>1], dctb[y>>1][x>>1]);
372 mp_fwd_dct_block2(current->cr_blocks[y>>1][x>>1], dctr[y>>1][x>>1]);
373
374 } else {
375 /* USE MOTION VECTORS */
376 numPBlocks++;
377
378 pattern = 63;
379 ComputeDiffDCTs(current, prev, y, x, motionY, motionX,
380 &pattern);
381
382 assert(motionX+searchRangeP+1 >= 0);
383 assert(motionY+searchRangeP+1 >= 0);
384
385 #ifdef BLEAH
386 if ( motionX+searchRangeP+1 > 2*searchRangeP+2 )
387 {
388 fprintf(stdout, "motionX = %d, searchRangeP = %d\n",
389 motionX, searchRangeP);
390 }
391 #endif
392
393 if ( computeMVHist ) {
394 assert(motionX+searchRangeP+1 <= 2*searchRangeP+2);
395 assert(motionY+searchRangeP+1 <= 2*searchRangeP+2);
396 pmvHistogram[motionX+searchRangeP+1][motionY+searchRangeP+1]++;
397 }
398 /* Save specs for next loops */
399 dct_data[y][x].pattern = pattern;
400 dct_data[y][x].fmotionX = motionX;
401 dct_data[y][x].fmotionY = motionY;
402
403 }
404 mbAddress++;
405 }}
406
407 mbAddress = 0;
408 for (y = 0; y < lastBlockY; y += 2) {
409 for (x = 0; x < lastBlockX; x += 2) {
410 slicePos = (mbAddress % blocksPerSlice);
411
412 if ( (slicePos == 0) && (mbAddress != 0) ) {
413 if (specificsOn) {
414 /* Make sure no slice Qscale change */
415 newQScale = SpecLookup(current->id, 1, mbAddress/blocksPerSlice,
416 &info /*junk*/, QScale);
417 if (newQScale != -1) QScale = newQScale;
418 }
419
420 Mhead_GenSliceEnder(bb);
421 Mhead_GenSliceHeader(bb, 1+(y>>1), QScale, NULL, 0);
422
423 /* reset everything */
424 oldMotionX = 0; oldMotionY = 0;
425 y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
426
427 mbAddrInc = 1+(x>>1);
428 }
429
430 /* Determine if new Qscale needed for Rate Control purposes */
431 if (bitstreamMode == FIXED_RATE) {
432 rc_blockStart = bb->cumulativeBits;
433 newQScale = needQScaleChange(qscaleP,
434 current->y_blocks[y][x],
435 current->y_blocks[y][x+1],
436 current->y_blocks[y+1][x],
437 current->y_blocks[y+1][x+1]);
438 if (newQScale > 0) {
439 QScale = newQScale;
440 }
441 }
442
443 /* Check for Qscale change */
444 if (specificsOn) {
445 newQScale = SpecLookup(current->id, 2, mbAddress, &info, QScale);
446 if (newQScale != -1) {
447 QScale = newQScale;
448 }
449 }
450
451 if (! dct_data[y][x].useMotion) {
452 GEN_I_BLOCK(P_FRAME, current, bb, mbAddrInc, QScale);
453 mbAddrInc = 1;
454
455 numIBits += (bb->cumulativeBits-totalBits);
456 totalBits = bb->cumulativeBits;
457
458 /* reset because intra-coded */
459 oldMotionX = 0; oldMotionY = 0;
460
461 if ( decodeRefFrames ) {
462 /* need to decode block we just encoded */
463 Mpost_UnQuantZigBlock(fb[0], dec[0], QScale, TRUE);
464 Mpost_UnQuantZigBlock(fb[1], dec[1], QScale, TRUE);
465 Mpost_UnQuantZigBlock(fb[2], dec[2], QScale, TRUE);
466 Mpost_UnQuantZigBlock(fb[3], dec[3], QScale, TRUE);
467 Mpost_UnQuantZigBlock(fb[4], dec[4], QScale, TRUE);
468 Mpost_UnQuantZigBlock(fb[5], dec[5], QScale, TRUE);
469
470 /* now, reverse the DCT transform */
471 for ( index = 0; index < 6; index++ ) {
472 mpeg_jrevdct((int16 *)dec[index]);
473 }
474
475 /* now, unblockify */
476 BlockToData(current->decoded_y, dec[0], y, x);
477 BlockToData(current->decoded_y, dec[1], y, x+1);
478 BlockToData(current->decoded_y, dec[2], y+1, x);
479 BlockToData(current->decoded_y, dec[3], y+1, x+1);
480 BlockToData(current->decoded_cb, dec[4], y>>1, x>>1);
481 BlockToData(current->decoded_cr, dec[5], y>>1, x>>1);
482 }
483 } else {
484 int fCode = fCodeP;
485
486 /* reset because non-intra-coded */
487 y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
488
489 pattern = dct_data[y][x].pattern;
490 motionX = dct_data[y][x].fmotionX;
491 motionY = dct_data[y][x].fmotionY;
492
493 #ifdef BLEAH
494 ComputeAndPrintPframeMAD(currentBlock, prev, y, x, motionY, motionX, mbAddress);
495 #endif
496
497 if ( pixelFullSearch ) { /* should be even */
498 motionY /= 2;
499 motionX /= 2;
500 }
501
502 /* transform the motion vector into the appropriate values */
503 offsetX = motionX - oldMotionX;
504 offsetY = motionY - oldMotionY;
505 /* if ((offsetX+(8*x)) >= (Fsize_x-8)) log(10.0); */
506 ENCODE_MOTION_VECTOR(offsetX, offsetY, motionXquot,
507 motionYquot, motionXrem, motionYrem,
508 FORW_F);
509
510 #ifdef BLEAH
511 if ( (motionX != 0) || (motionY != 0) ) {
512 fprintf(stdout, "FRAME (y, x) %d, %d (block %d)\n", y, x, mbAddress);
513 fprintf(stdout, "motionX = %d, motionY = %d\n", motionX, motionY);
514 fprintf(stdout, " mxq, mxr = %d, %d myq, myr = %d, %d\n",
515 motionXquot, motionXrem, motionYquot, motionYrem);
516 }
517 #endif
518
519 oldMotionX = motionX;
520 oldMotionY = motionY;
521
522 if ( pixelFullSearch ) { /* reset for use with PMotionSearch */
523 motionY *= 2;
524 motionX *= 2;
525 }
526 calc_blocks:
527 /* create flat blocks and update pattern if necessary */
528 /* Note DoQuant references QScale, overflowChange, overflowValue,
529 pattern, and the calc_blocks label */
530 DoQuant(0x20, dct[y][x], fba[0]);
531 DoQuant(0x10, dct[y][x+1], fba[1]);
532 DoQuant(0x08, dct[y+1][x], fba[2]);
533 DoQuant(0x04, dct[y+1][x+1], fba[3]);
534 DoQuant(0x02, dctb[y>>1][x>>1], fba[4]);
535 DoQuant(0x01, dctr[y>>1][x>>1], fba[5]);
536
537 if ( decodeRefFrames) {
538 for ( index = 0; index < 6; index++ ) {
539 if ( pattern & (1 << (5-index))) {
540 Mpost_UnQuantZigBlock(fba[index], dec[index], QScale, FALSE);
541 mpeg_jrevdct((int16 *)dec[index]);
542 } else {
543 memset((char *)dec[index], 0, sizeof(Block));
544 }
545 }
546
547 /* now add the motion block */
548 AddMotionBlock(dec[0], prev->decoded_y, y, x, motionY, motionX);
549 AddMotionBlock(dec[1], prev->decoded_y, y, x+1, motionY, motionX);
550 AddMotionBlock(dec[2], prev->decoded_y, y+1, x, motionY, motionX);
551 AddMotionBlock(dec[3], prev->decoded_y, y+1, x+1, motionY, motionX);
552 AddMotionBlock(dec[4], prev->decoded_cb, y>>1, x>>1, motionY/2, motionX/2);
553 AddMotionBlock(dec[5], prev->decoded_cr, y>>1, x>>1, motionY/2, motionX/2);
554
555 /* now, unblockify */
556 BlockToData(current->decoded_y, dec[0], y, x);
557 BlockToData(current->decoded_y, dec[1], y, x+1);
558 BlockToData(current->decoded_y, dec[2], y+1, x);
559 BlockToData(current->decoded_y, dec[3], y+1, x+1);
560 BlockToData(current->decoded_cb, dec[4], y>>1, x>>1);
561 BlockToData(current->decoded_cr, dec[5], y>>1, x>>1);
562 }
563
564 if ( (motionX == 0) && (motionY == 0) ) {
565 if ( pattern == 0 ) {
566 /* can only skip if:
567 * 1) not the last block in frame
568 * 2) not the last block in slice
569 * 3) not the first block in slice
570 */
571
572 if ( ((y < lastY) || (x < lastX)) &&
573 (slicePos+1 != blocksPerSlice) &&
574 (slicePos != 0) ) {
575 mbAddrInc++; /* skipped macroblock */
576 numSkipped++;
577 numPBlocks--;
578 } else { /* first/last macroblock */
579 Mhead_GenMBHeader(bb, 2 /* pict_code_type */, mbAddrInc /* addr_incr */,
580 QScale /* q_scale */,
581 fCode /* forw_f_code */, 1 /* back_f_code */,
582 motionXrem /* horiz_forw_r */, motionYrem /* vert_forw_r */,
583 0 /* horiz_back_r */, 0 /* vert_back_r */,
584 1 /* motion_forw */, motionXquot /* m_horiz_forw */,
585 motionYquot /* m_vert_forw */, 0 /* motion_back */,
586 0 /* m_horiz_back */, 0 /* m_vert_back */,
587 0 /* mb_pattern */, 0 /* mb_intra */);
588 mbAddrInc = 1;
589 }
590 } else {
591 DBG_PRINT(("MB Header(%d,%d)\n", x, y));
592 Mhead_GenMBHeader(bb, 2 /* pict_code_type */, mbAddrInc /* addr_incr */,
593 QScale /* q_scale */,
594 fCode /* forw_f_code */, 1 /* back_f_code */,
595 0 /* horiz_forw_r */, 0 /* vert_forw_r */,
596 0 /* horiz_back_r */, 0 /* vert_back_r */,
597 0 /* motion_forw */, 0 /* m_horiz_forw */,
598 0 /* m_vert_forw */, 0 /* motion_back */,
599 0 /* m_horiz_back */, 0 /* m_vert_back */,
600 pattern /* mb_pattern */, 0 /* mb_intra */);
601 mbAddrInc = 1;
602 }
603 } else {
604 /* DBG_PRINT(("MB Header(%d,%d)\n", x, y)); */
605
606 Mhead_GenMBHeader(bb, 2 /* pict_code_type */, mbAddrInc /* addr_incr */,
607 QScale /* q_scale */,
608 fCode /* forw_f_code */, 1 /* back_f_code */,
609 motionXrem /* horiz_forw_r */, motionYrem /* vert_forw_r */,
610 0 /* horiz_back_r */, 0 /* vert_back_r */,
611 1 /* motion_forw */, motionXquot /* m_horiz_forw */,
612 motionYquot /* m_vert_forw */, 0 /* motion_back */,
613 0 /* m_horiz_back */, 0 /* m_vert_back */,
614 pattern /* mb_pattern */, 0 /* mb_intra */);
615 mbAddrInc = 1;
616 }
617
618 /* now output the difference */
619 for ( tempX = 0; tempX < 6; tempX++ ) {
620 if ( GET_ITH_BIT(pattern, 5-tempX) ) {
621 Mpost_RLEHuffPBlock(fba[tempX], bb);
622 }
623 }
624
625 numPBits += (bb->cumulativeBits-totalBits);
626 totalBits = bb->cumulativeBits;
627 }
628
629 if (overflowChange) {
630 /* undo an overflow-caused Qscale change */
631 overflowChange = FALSE;
632 QScale -= overflowValue;
633 overflowValue = 0;
634 }
635
636 mbAddress++;
637 /* Rate Control */
638 if (bitstreamMode == FIXED_RATE) {
639 incMacroBlockBits( bb->cumulativeBits- rc_blockStart);
640 rc_blockStart = bb->cumulativeBits;
641 MB_RateOut(TYPE_PFRAME);
642 }
643 }
644 }
645
646 if ( printSNR ) {
647 BlockComputeSNR(current,snr,psnr);
648 totalSNR += snr[0];
649 totalPSNR += psnr[0];
650 }
651
652 #ifdef BLEAHBLEAH
653 {
654 FILE *filePtr;
655
656 filePtr = fopen("PFRAME.yuv", "wb");
657
658 for ( y = 0; y < Fsize_y; y++ )
659 {
660 for ( x = 0; x < Fsize_x; x++ )
661 fprintf(filePtr, "%d ", current->decoded_y[y][x]);
662 fprintf(filePtr, "\n");
663 }
664
665 fclose(filePtr);
666 }
667 #endif
668
669 Mhead_GenSliceEnder(bb);
670 /* Rate Control */
671 if (bitstreamMode == FIXED_RATE) {
672 updateRateControl(TYPE_PFRAME);
673 }
674
675 /* UPDATE STATISTICS */
676 endTime = time_elapsed();
677 totalTime += (endTime-startTime);
678
679 if ( ( ! childProcess) && showBitRatePerFrame ) {
680 /* ASSUMES 30 FRAMES PER SECOND */
681 fprintf(bitRateFile, "%5d\t%8d\n", current->id,
682 30*(bb->cumulativeBits-totalFrameBits));
683 }
684
685 if ( (! childProcess) && frameSummary && (! realQuiet) ) {
686 fprintf(stdout, "FRAME %d (P): I BLOCKS: %d; P BLOCKS: %d SKIPPED: %d (%ld seconds)\n",
687 current->id, numIBlocks, numPBlocks, numSkipped, (long)(endTime-startTime)/TIME_RATE);
688 if ( printSNR ) {
689 fprintf(stdout, "FRAME %d: SNR: %.1f\t%.1f\t%.1f\tPSNR: %.1f\t%.1f\t%.1f\n",
690 current->id, snr[0], snr[1], snr[2],
691 psnr[0], psnr[1], psnr[2]);
692 }
693 }
694
695 numFrameBits += (bb->cumulativeBits-totalFrameBits);
696 numPIBlocks += numIBlocks;
697 numPPBlocks += numPBlocks;
698 numPSkipped += numSkipped;
699 numPIBits += numIBits;
700 numPPBits += numPBits;
701
702 if ( (referenceFrame == DECODED_FRAME) && NonLocalRefFrame(current->id) ) {
703 if ( remoteIO ) {
704 SendDecodedFrame(current);
705 } else {
706 WriteDecodedFrame(current);
707 }
708
709 NotifyDecodeServerReady(current->id);
710 }
711 }
712
713
714 /*===========================================================================*
715 *
716 * ResetPFrameStats
717 *
718 * reset the P-frame statistics
719 *
720 * RETURNS: nothing
721 *
722 * SIDE EFFECTS: none
723 *
724 *===========================================================================*/
725 void
726 ResetPFrameStats()
727 {
728 numPIBlocks = 0;
729 numPPBlocks = 0;
730 numPSkipped = 0;
731 numPIBits = 0;
732 numPPBits = 0;
733 numFrames = 0;
734 numFrameBits = 0;
735 totalTime = 0;
736 }
737
738
739 /*===========================================================================*
740 *
741 * SetPQScale
742 *
743 * set the P-frame Q-scale
744 *
745 * RETURNS: nothing
746 *
747 * SIDE EFFECTS: qscaleP
748 *
749 *===========================================================================*/
750 void
751 SetPQScale(qP)
752 int qP;
753 {
754 qscaleP = qP;
755 }
756
757
758 /*===========================================================================*
759 *
760 * GetPQScale
761 *
762 * return the P-frame Q-scale
763 *
764 * RETURNS: the P-frame Q-scale
765 *
766 * SIDE EFFECTS: none
767 *
768 *===========================================================================*/
769 int
770 GetPQScale()
771 {
772 return qscaleP;
773 }
774
775
776 /*===========================================================================*
777 *
778 * ShowPFrameSummary
779 *
780 * print a summary of information on encoding P-frames
781 *
782 * RETURNS: time taken for P-frames (in seconds)
783 *
784 * SIDE EFFECTS: none
785 *
786 *===========================================================================*/
787 float
788 ShowPFrameSummary(inputFrameBits, totalBits, fpointer)
789 int inputFrameBits;
790 int32 totalBits;
791 FILE *fpointer;
792 {
793 if ( numFrames == 0 ) {
794 return 0.0;
795 }
796
797 fprintf(fpointer, "-------------------------\n");
798 fprintf(fpointer, "*****P FRAME SUMMARY*****\n");
799 fprintf(fpointer, "-------------------------\n");
800
801 if ( numPIBlocks != 0 ) {
802 fprintf(fpointer, " I Blocks: %5d (%6d bits) (%5d bpb)\n",
803 numPIBlocks, numPIBits, numPIBits/numPIBlocks);
804 } else {
805 fprintf(fpointer, " I Blocks: %5d\n", 0);
806 }
807
808 if ( numPPBlocks != 0 ) {
809 fprintf(fpointer, " P Blocks: %5d (%6d bits) (%5d bpb)\n",
810 numPPBlocks, numPPBits, numPPBits/numPPBlocks);
811 } else {
812 fprintf(fpointer, " P Blocks: %5d\n", 0);
813 }
814
815 fprintf(fpointer, " Skipped: %5d\n", numPSkipped);
816
817 fprintf(fpointer, " Frames: %5d (%6d bits) (%5d bpf) (%2.1f%% of total)\n",
818 numFrames, numFrameBits, numFrameBits/numFrames,
819 100.0*(float)numFrameBits/(float)totalBits);
820 fprintf(fpointer, " Compression: %3d:1 (%9.4f bpp)\n",
821 numFrames*inputFrameBits/numFrameBits,
822 24.0*(float)numFrameBits/(float)(numFrames*inputFrameBits));
823 if ( printSNR )
824 fprintf(fpointer, " Avg Y SNR/PSNR: %.1f %.1f\n",
825 totalSNR/(float)numFrames, totalPSNR/(float)numFrames);
826 if ( totalTime == 0 ) {
827 fprintf(fpointer, " Seconds: NONE\n");
828 } else {
829 fprintf(fpointer, " Seconds: %9ld (%9.4f fps) (%9ld pps) (%9ld mps)\n",
830 (long)(totalTime/TIME_RATE),
831 (float)((float)(TIME_RATE*numFrames)/(float)totalTime),
832 (long)((float)TIME_RATE*(float)numFrames*(float)inputFrameBits/(24.0*(float)totalTime)),
833 (long)((float)TIME_RATE*(float)numFrames*(float)inputFrameBits/(256.0*24.0*(float)totalTime)));
834 }
835
836 return (float)totalTime/(float)TIME_RATE;
837 }
838
839
840 /*===========================================================================*
841 *
842 * EstimateSecondsPerPFrame
843 *
844 * compute an estimate of the number of seconds required per P-frame
845 *
846 * RETURNS: the estimate, in seconds
847 *
848 * SIDE EFFECTS: none
849 *
850 *===========================================================================*/
851 float
852 EstimateSecondsPerPFrame()
853 {
854 if ( numFrames == 0 ) {
855 return 10.0;
856 } else {
857 return (float)totalTime/((float)TIME_RATE*(float)numFrames);
858 }
859 }
860
861
862 /*===========================================================================*
863 *
864 * ComputeHalfPixelData
865 *
866 * compute all half-pixel data required for half-pixel motion vector
867 * search (luminance only)
868 *
869 * RETURNS: frame->halfX, ->halfY, and ->halfBoth modified
870 *
871 * SIDE EFFECTS: none
872 *
873 *===========================================================================*/
874 void
875 ComputeHalfPixelData(frame)
876 MpegFrame *frame;
877 {
878 register int x, y;
879
880 /* we add 1 before dividing by 2 because .5 is supposed to be rounded up
881 * (see MPEG-1, page D-31)
882 */
883
884 if ( frame->halfX == NULL ) { /* need to allocate memory */
885 Frame_AllocHalf(frame);
886 }
887
888 /* compute halfX */
889 for ( y = 0; y < Fsize_y; y++ ) {
890 for ( x = 0; x < Fsize_x-1; x++ ) {
891 frame->halfX[y][x] = (frame->ref_y[y][x]+
892 frame->ref_y[y][x+1]+1)>>1;
893 }
894 }
895
896 /* compute halfY */
897 for ( y = 0; y < Fsize_y-1; y++ ) {
898 for ( x = 0; x < Fsize_x; x++ ) {
899 frame->halfY[y][x] = (frame->ref_y[y][x]+
900 frame->ref_y[y+1][x]+1)>>1;
901 }
902 }
903
904 /* compute halfBoth */
905 for ( y = 0; y < Fsize_y-1; y++ ) {
906 for ( x = 0; x < Fsize_x-1; x++ ) {
907 frame->halfBoth[y][x] = (frame->ref_y[y][x]+
908 frame->ref_y[y][x+1]+
909 frame->ref_y[y+1][x]+
910 frame->ref_y[y+1][x+1]+2)>>2;
911 }
912 }
913
914 frame->halfComputed = TRUE;
915 }
916
917
918 /*=====================*
919 * INTERNAL PROCEDURES *
920 *=====================*/
921
922 /*===========================================================================*
923 *
924 * USER-MODIFIABLE
925 *
926 * ZeroMotionBetter
927 *
928 * decide if (0,0) motion is better than the given motion vector
929 *
930 * RETURNS: TRUE if (0,0) is better, FALSE if (my,mx) is better
931 *
932 * SIDE EFFECTS: none
933 *
934 * PRECONDITIONS: The relevant block in 'current' is valid (it has not
935 * been dct'd). 'zeroDiff' has already been computed
936 * as the LumMotionError() with (0,0) motion
937 *
938 * NOTES: This procedure follows the algorithm described on
939 * page D-48 of the MPEG-1 specification
940 *
941 *===========================================================================*/
942 static boolean
943 ZeroMotionBetter(currentBlock, prev, by, bx, my, mx)
944 LumBlock currentBlock;
945 MpegFrame *prev;
946 int by;
947 int bx;
948 int my;
949 int mx;
950 {
951 int bestDiff;
952 int CompareMode;
953
954 /* Junk needed to adapt for TUNEing */
955 CompareMode = SearchCompareMode;
956 SearchCompareMode = DEFAULT_SEARCH;
957 bestDiff = LumMotionError(currentBlock, prev, by, bx, my, mx, 0x7fffffff);
958 SearchCompareMode = CompareMode;
959
960 if ( zeroDiff < 256*3 ) {
961 if ( 2*bestDiff >= zeroDiff ) {
962 return TRUE;
963 }
964 } else {
965 if ( 11*bestDiff >= 10*zeroDiff ) {
966 return TRUE;
967 }
968 }
969
970 return FALSE;
971 }
972
973
974 /*===========================================================================*
975 *
976 * USER-MODIFIABLE
977 *
978 * DoIntraCode
979 *
980 * decide if intra coding is necessary
981 *
982 * RETURNS: TRUE if intra-block coding is better; FALSE if not
983 *
984 * SIDE EFFECTS: none
985 *
986 * PRECONDITIONS: The relevant block in 'current' is valid (it has not
987 * been dct'd).
988 *
989 * NOTES: This procedure follows the algorithm described on
990 * page D-49 of the MPEG-1 specification
991 *
992 *===========================================================================*/
993 static boolean
994 DoIntraCode(currentBlock, prev, by, bx, motionY, motionX)
995 LumBlock currentBlock;
996 MpegFrame *prev;
997 int by;
998 int bx;
999 int motionY;
1000 int motionX;
1001 {
1002 int x, y;
1003 int32 sum = 0, vard = 0, varc = 0, dif;
1004 int32 currPixel, prevPixel;
1005 LumBlock motionBlock;
1006
1007 ComputeMotionLumBlock(prev, by, bx, motionY, motionX, motionBlock);
1008
1009 for ( y = 0; y < 16; y++ ) {
1010 for ( x = 0; x < 16; x++ ) {
1011 currPixel = currentBlock[y][x];
1012 prevPixel = motionBlock[y][x];
1013
1014 sum += currPixel;
1015 varc += currPixel*currPixel;
1016
1017 dif = currPixel - prevPixel;
1018 vard += dif*dif;
1019 }
1020 }
1021
1022 vard >>= 8; /* divide by 256; assumes mean is close to zero */
1023 varc = (varc>>8) - (sum>>8)*(sum>>8);
1024
1025 if ( vard <= 64 ) {
1026 return FALSE;
1027 } else if ( vard < varc ) {
1028 return FALSE;
1029 } else {
1030 return TRUE;
1031 }
1032 }
1033
1034
1035 /*===========================================================================*
1036 *
1037 * USER-MODIFIABLE
1038 *
1039 * ZeroMotionSufficient
1040 *
1041 * decide if zero motion is sufficient without DCT correction
1042 *
1043 * RETURNS: TRUE no DCT required; FALSE otherwise
1044 *
1045 * SIDE EFFECTS: none
1046 *
1047 * PRECONDITIONS: The relevant block in 'current' is raw YCC data
1048 *
1049 *===========================================================================*/
1050 static boolean
1051 ZeroMotionSufficient(currentBlock, prev, by, bx)
1052 LumBlock currentBlock;
1053 MpegFrame *prev;
1054 int by;
1055 int bx;
1056 {
1057 LumBlock motionBlock;
1058 register int fy, fx;
1059 register int x, y;
1060
1061 fy = by*DCTSIZE;
1062 fx = bx*DCTSIZE;
1063 for ( y = 0; y < 16; y++ ) {
1064 for ( x = 0; x < 16; x++ ) {
1065 motionBlock[y][x] = prev->ref_y[fy+y][fx+x];
1066 }
1067 }
1068
1069 zeroDiff = LumBlockMAD(currentBlock, motionBlock, 0x7fffffff);
1070
1071 return (zeroDiff <= 256);
1072 }
1073
1074
1075 #ifdef UNUSED_PROCEDURES
1076 static void
1077 ComputeAndPrintPframeMAD(currentBlock, prev, by, bx, my, mbx, numBlock)
1078 LumBlock currentBlock;
1079 MpegFrame *prev;
1080 int by;
1081 int bx;
1082 int my;
1083 int mx;
1084 int numBlock;
1085 {
1086 LumBlock lumMotionBlock;
1087 int32 mad;
1088
1089 ComputeMotionLumBlock(prev, by, bx, my, mx, lumMotionBlock);
1090
1091 mad = LumBlockMAD(currentBlock, lumMotionBlock, 0x7fffffff);
1092
1093 if (! realQuiet) {
1094 fprintf(stdout, "%d %d\n", numBlock, mad);
1095 }
1096 }
1097 #endif