ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/freemol/trunk/src/mpeg_encode/src/iframe.c
Revision: 23
Committed: Mon Jul 7 23:06:52 2008 UTC (12 years, 4 months ago) by wdelano
File size: 31242 byte(s)
Log Message:
changes for win32
Line File contents
1 /*===========================================================================*
2 * iframe.c *
3 * *
4 * Procedures concerned with the I-frame encoding *
5 * *
6 * EXPORTED PROCEDURES: *
7 * GenIFrame *
8 * SetSlicesPerFrame *
9 * SetBlocksPerSlice *
10 * SetIQScale *
11 * GetIQScale *
12 * ResetIFrameStats *
13 * ShowIFrameSummary *
14 * EstimateSecondsPerIFrame *
15 * EncodeYDC *
16 * EncodeCDC *
17 * time_elapsed *
18 * *
19 *===========================================================================*/
20
21 /*
22 * Copyright (c) 1995 The Regents of the University of California.
23 * All rights reserved.
24 *
25 * Permission to use, copy, modify, and distribute this software and its
26 * documentation for any purpose, without fee, and without written agreement is
27 * hereby granted, provided that the above copyright notice and the following
28 * two paragraphs appear in all copies of this software.
29 *
30 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
31 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
32 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
33 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *
35 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
36 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
37 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
38 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
39 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
40 */
41
42 /*
43 * $Header: /n/picasso/project/mpeg/mpeg_dist/mpeg_encode/RCS/iframe.c,v 1.23 1995/08/14 22:29:49 smoot Exp $
44 * $Log: iframe.c,v $
45 * Revision 1.23 1995/08/14 22:29:49 smoot
46 * changed inits in BlockComputeSNR so sgi compiler would be happy
47 *
48 * Revision 1.22 1995/08/07 21:50:51 smoot
49 * spacing
50 * simplified some code
51 * added Laplace stuff
52 * minor error check bug in alloc
53 *
54 * Revision 1.21 1995/06/21 22:24:25 smoot
55 * added CalcDistortion (TUNEing)
56 * fixed timeing stuff for ANSI
57 * fixed specifics bug
58 *
59 * Revision 1.20 1995/05/02 21:59:43 smoot
60 * fixed BlockComputeSNR bugs
61 *
62 * Revision 1.19 1995/04/24 23:02:50 smoot
63 * Fixed BlockComputeSNR for Linux and others
64 *
65 * Revision 1.18 1995/04/14 23:08:02 smoot
66 * reorganized to ease rate control experimentation
67 *
68 * Revision 1.17 1995/02/24 23:49:38 smoot
69 * added support for Specifics file version 2
70 *
71 * Revision 1.16 1995/01/30 20:02:34 smoot
72 * cleanup, killed a couple warnings
73 *
74 * Revision 1.15 1995/01/30 19:49:17 smoot
75 * cosmetic
76 *
77 * Revision 1.14 1995/01/23 02:49:34 darryl
78 * initialized variable
79 *
80 * Revision 1.13 1995/01/19 23:08:30 eyhung
81 * Changed copyrights
82 *
83 * Revision 1.12 1995/01/16 08:01:34 eyhung
84 * Added realQuiet
85 *
86 * Revision 1.11 1994/12/07 00:40:36 smoot
87 * Added seperate P and B search ranges
88 *
89 * Revision 1.10 1994/11/14 22:30:30 smoot
90 * Merged specifics and rate control
91 *
92 * Revision 1.9 1994/11/01 05:00:48 darryl
93 * with rate control changes added
94 *
95 * Revision 2.2 1994/10/31 00:06:07 darryl
96 * version before, hopefully, final changes
97 *
98 * Revision 2.1 1994/10/24 22:03:01 darryl
99 * put in preliminary experiments code
100 *
101 * Revision 2.0 1994/10/24 02:38:04 darryl
102 * will be adding the experiment stuff.
103 *
104 * Revision 1.1 1994/09/27 00:15:24 darryl
105 * Initial revision
106 *
107 * Revision 1.8 1994/03/15 00:27:11 keving
108 * nothing
109 *
110 * Revision 1.7 1993/12/22 19:19:01 keving
111 * nothing
112 *
113 * Revision 1.6 1993/07/22 22:23:43 keving
114 * nothing
115 *
116 * Revision 1.5 1993/06/30 20:06:09 keving
117 * nothing
118 *
119 * Revision 1.4 1993/06/03 21:08:08 keving
120 * nothing
121 *
122 * Revision 1.3 1993/03/04 22:24:06 keving
123 * nothing
124 *
125 * Revision 1.2 1993/02/19 18:10:02 keving
126 * nothing
127 *
128 * Revision 1.1 1993/02/18 22:56:39 keving
129 * nothing
130 *
131 *
132 */
133
134
135 /*==============*
136 * HEADER FILES *
137 *==============*/
138
139 #ifdef WIN32
140 #define CLOCKS_PER_SEC 1000
141 #else
142 #ifdef CLOCKS_PER_SEC
143 #include <times.h>
144 #else
145 #include <sys/times.h>
146 #endif
147 #endif
148
149 #include <sys/param.h>
150 #include "all.h"
151 #include "mtypes.h"
152 #include "frames.h"
153 #include "prototypes.h"
154 #include "mpeg.h"
155 #include "param.h"
156 #include "mheaders.h"
157 #include "fsize.h"
158 #include "parallel.h"
159 #include "postdct.h"
160 #include "rate.h"
161 #include "opts.h"
162
163 /*==================*
164 * STATIC VARIABLES *
165 *==================*/
166
167 static int lastNumBits = 0;
168 static int lastIFrame = 0;
169 static int numBlocks = 0;
170 static int numBits;
171 static int numFrames = 0;
172 static int numFrameBits = 0;
173 static int32 totalTime = 0;
174 static float totalSNR = 0.0;
175 static float totalPSNR = 0.0;
176
177 static int lengths[256] = {
178 0, 1, 2, 2, 3, 3, 3, 3, /* 0 - 7 */
179 4, 4, 4, 4, 4, 4, 4, 4, /* 8 - 15 */
180 5, 5, 5, 5, 5, 5, 5, 5, /* 16 - 31 */
181 5, 5, 5, 5, 5, 5, 5, 5,
182 6, 6, 6, 6, 6, 6, 6, 6, /* 32 - 63 */
183 6, 6, 6, 6, 6, 6, 6, 6,
184 6, 6, 6, 6, 6, 6, 6, 6,
185 6, 6, 6, 6, 6, 6, 6, 6,
186 7, 7, 7, 7, 7, 7, 7, 7, /* 64 - 127 */
187 7, 7, 7, 7, 7, 7, 7, 7,
188 7, 7, 7, 7, 7, 7, 7, 7,
189 7, 7, 7, 7, 7, 7, 7, 7,
190 7, 7, 7, 7, 7, 7, 7, 7,
191 7, 7, 7, 7, 7, 7, 7, 7,
192 7, 7, 7, 7, 7, 7, 7, 7,
193 7, 7, 7, 7, 7, 7, 7, 7,
194 8, 8, 8, 8, 8, 8, 8, 8,
195 8, 8, 8, 8, 8, 8, 8, 8,
196 8, 8, 8, 8, 8, 8, 8, 8,
197 8, 8, 8, 8, 8, 8, 8, 8,
198 8, 8, 8, 8, 8, 8, 8, 8,
199 8, 8, 8, 8, 8, 8, 8, 8,
200 8, 8, 8, 8, 8, 8, 8, 8,
201 8, 8, 8, 8, 8, 8, 8, 8,
202 8, 8, 8, 8, 8, 8, 8, 8,
203 8, 8, 8, 8, 8, 8, 8, 8,
204 8, 8, 8, 8, 8, 8, 8, 8,
205 8, 8, 8, 8, 8, 8, 8, 8,
206 8, 8, 8, 8, 8, 8, 8, 8,
207 8, 8, 8, 8, 8, 8, 8, 8,
208 8, 8, 8, 8, 8, 8, 8, 8,
209 8, 8, 8, 8, 8, 8, 8, 8
210 };
211
212
213 /*==================*
214 * GLOBAL VARIABLES *
215 *==================*/
216
217 int qscaleI;
218 int slicesPerFrame;
219 int blocksPerSlice;
220 int fCodeI, fCodeP, fCodeB;
221 boolean printSNR = FALSE;
222 boolean printMSE = FALSE;
223 boolean decodeRefFrames = FALSE;
224 Block **dct=NULL, **dctr=NULL, **dctb=NULL;
225 dct_data_type **dct_data; /* used in p/bframe.c */
226 int TIME_RATE;
227
228
229 /*=====================*
230 * EXPORTED PROCEDURES *
231 *=====================*/
232 extern void PrintItoIBitRate _ANSI_ARGS_((int numBits, int frameNum));
233
234 /*===============================*
235 * INTERNAL PROCEDURE prototypes *
236 *===============================*/
237 void AllocDctBlocks _ANSI_ARGS_((void ));
238 int SetFCodeHelper _ANSI_ARGS_((int sr));
239 void CalcDistortion _ANSI_ARGS_((MpegFrame *current, int y, int x));
240
241 int
242 SetFCodeHelper(SR)
243 int SR;
244 {
245 int range,fCode;
246
247 if ( pixelFullSearch ) {
248 range = SR;
249 } else {
250 range = SR*2;
251 }
252
253 if ( range < 256 ) {
254 if ( range < 64 ) {
255 if ( range < 32 ) {
256 fCode = 1;
257 } else {
258 fCode = 2;
259 }
260 } else {
261 if ( range < 128 ) {
262 fCode = 3;
263 } else {
264 fCode = 4;
265 }
266 }
267 } else {
268 if ( range < 1024 ) {
269 if ( range < 512 ) {
270 fCode = 5;
271 } else {
272 fCode = 6;
273 }
274 } else {
275 if ( range < 2048 ) {
276 fCode = 7;
277 } else {
278 fprintf(stderr, "ERROR: INVALID SEARCH RANGE!!!\n");
279 exit(1);
280 }
281 }
282 }
283 return fCode;
284 }
285
286 /*===========================================================================*
287 *
288 * SetFCode
289 *
290 * set the forward_f_code and backward_f_code according to the search
291 * range. Must be called AFTER pixelFullSearch and searchRange have
292 * been initialized. Irrelevant for I-frames, but computation is
293 * negligible (done only once, as well)
294 *
295 * RETURNS: nothing
296 *
297 * SIDE EFFECTS: fCodeI,fCodeP,fCodeB
298 *
299 *===========================================================================*/
300 void
301 SetFCode()
302 {
303 fCodeI = SetFCodeHelper(1); /* GenIFrame ignores value */
304 fCodeP = SetFCodeHelper(searchRangeP);
305 fCodeB = SetFCodeHelper(searchRangeB);
306 }
307
308 /*===========================================================================*
309 *
310 * SetSlicesPerFrame
311 *
312 * set the number of slices per frame
313 *
314 * RETURNS: nothing
315 *
316 * SIDE EFFECTS: slicesPerFrame
317 *
318 *===========================================================================*/
319 void
320 SetSlicesPerFrame(number)
321 int number;
322 {
323 slicesPerFrame = number;
324 }
325
326
327 /*===========================================================================*
328 *
329 * SetBlocksPerSlice
330 *
331 * set the number of blocks per slice, based on slicesPerFrame
332 *
333 * RETURNS: nothing
334 *
335 * SIDE EFFECTS: blocksPerSlice
336 *
337 *===========================================================================*/
338 void
339 SetBlocksPerSlice()
340 {
341 int totalBlocks;
342
343 totalBlocks = (Fsize_y>>4)*(Fsize_x>>4);
344
345 if ( slicesPerFrame > totalBlocks ) {
346 blocksPerSlice = 1;
347 } else {
348 blocksPerSlice = totalBlocks/slicesPerFrame;
349 }
350 }
351
352
353 /*===========================================================================*
354 *
355 * SetIQScale
356 *
357 * set the I-frame Q-scale
358 *
359 * RETURNS: nothing
360 *
361 * SIDE EFFECTS: qscaleI
362 *
363 *===========================================================================*/
364 void
365 SetIQScale(qI)
366 int qI;
367 {
368 qscaleI = qI;
369 }
370
371 /*===========================================================================*
372 *
373 * GetIQScale
374 *
375 * Get the I-frame Q-scale
376 *
377 * RETURNS: the Iframe Qscale
378 *
379 * SIDE EFFECTS: none
380 *
381 *===========================================================================*/
382 int
383 GetIQScale()
384 {
385 return qscaleI;
386 }
387
388 /*===========================================================================*
389 *
390 * GenIFrame
391 *
392 * generate an I-frame; appends result to bb
393 *
394 * RETURNS: I-frame appended to bb
395 *
396 * SIDE EFFECTS: none
397 *
398 *===========================================================================*/
399 void
400 GenIFrame(bb, current)
401 BitBucket *bb;
402 MpegFrame *current;
403 {
404 register int x, y;
405 register int index;
406 FlatBlock fb[6];
407 Block dec[6];
408 int32 y_dc_pred, cr_dc_pred, cb_dc_pred;
409 int totalBits;
410 int totalFrameBits;
411 int32 startTime, endTime;
412 float snr[3], psnr[3];
413 int mbAddress;
414 int QScale;
415 BlockMV *info; /* Not used in Iframes, but nice to pass in anyway */
416 int bitstreamMode, newQScale;
417 int rc_blockStart=0;
418
419 if (dct==NULL) AllocDctBlocks();
420 if (collect_quant) {fprintf(collect_quant_fp, "# I\n");}
421
422 /* set-up for statistics */
423 numFrames++;
424 totalFrameBits = bb->cumulativeBits;
425 if ( ( ! childProcess) && showBitRatePerFrame ) {
426 if ( lastNumBits == 0 ) {
427 lastNumBits = bb->cumulativeBits;
428 lastIFrame = current->id;
429 } else {
430 /* ASSUMES 30 FRAMES PER SECOND */
431
432 if (! realQuiet) {
433 fprintf(stdout, "I-to-I (frames %5d to %5d) bitrate: %8d\n",
434 lastIFrame, current->id-1,
435 ((bb->cumulativeBits-lastNumBits)*30)/
436 (current->id-lastIFrame));
437 }
438
439 fprintf(bitRateFile, "I-to-I (frames %5d to %5d) bitrate: %8d\n",
440 lastIFrame, current->id-1,
441 ((bb->cumulativeBits-lastNumBits)*30)/
442 (current->id-lastIFrame));
443 lastNumBits = bb->cumulativeBits;
444 lastIFrame = current->id;
445 }
446 }
447
448 startTime = time_elapsed();
449
450 Frame_AllocBlocks(current);
451 BlockifyFrame(current);
452
453 DBG_PRINT(("Generating iframe\n"));
454 QScale = GetIQScale();
455 /* Allocate bits for this frame for rate control purposes */
456 bitstreamMode = getRateMode();
457 if (bitstreamMode == FIXED_RATE) {
458 targetRateControl(current);
459 }
460
461 Mhead_GenPictureHeader(bb, I_FRAME, current->id, fCodeI);
462 /* Check for Qscale change */
463 if (specificsOn) {
464 newQScale = SpecLookup(current->id, 0, 0 /* junk */, &info, QScale);
465 if (newQScale != -1) {
466 QScale = newQScale;
467 }
468 /* check for slice */
469 newQScale = SpecLookup(current->id, 1, 1, &info, QScale);
470 if (newQScale != -1) {
471 QScale = newQScale;
472 }
473 }
474 Mhead_GenSliceHeader(bb, 1, QScale, NULL, 0);
475
476 if ( referenceFrame == DECODED_FRAME ) {
477 Frame_AllocDecoded(current, TRUE);
478 } else if ( printSNR ) {
479 Frame_AllocDecoded(current, FALSE);
480 }
481
482 y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
483 totalBits = bb->cumulativeBits;
484 mbAddress = 0;
485
486 /* DCT the macroblocks */
487 for (y = 0; y < (Fsize_y >> 3); y += 2) {
488 for (x = 0; x < (Fsize_x >> 3); x += 2) {
489 if (collect_quant && (collect_quant_detailed & 1)) fprintf(collect_quant_fp, "l\n");
490 if (DoLaplace) {LaplaceCnum = 0;}
491 mp_fwd_dct_block2(current->y_blocks[y][x], dct[y][x]);
492 mp_fwd_dct_block2(current->y_blocks[y][x+1], dct[y][x+1]);
493 mp_fwd_dct_block2(current->y_blocks[y+1][x], dct[y+1][x]);
494 mp_fwd_dct_block2(current->y_blocks[y+1][x+1], dct[y+1][x+1]);
495 if (collect_quant && (collect_quant_detailed & 1)) fprintf(collect_quant_fp, "c\n");
496 if (DoLaplace) {LaplaceCnum = 1;}
497 mp_fwd_dct_block2(current->cb_blocks[y>>1][x>>1], dctb[y>>1][x>>1]);
498 if (DoLaplace) {LaplaceCnum = 2;}
499 mp_fwd_dct_block2(current->cr_blocks[y>>1][x>>1], dctr[y>>1][x>>1]);
500 }}
501
502 if (DoLaplace) {
503 extern void CalcLambdas();
504 CalcLambdas();
505 }
506
507 for (y = 0; y < (Fsize_y >> 3); y += 2) {
508 for (x = 0; x < (Fsize_x >> 3); x += 2) {
509 /* Check for Qscale change */
510 if (specificsOn) {
511 newQScale = SpecLookup(current->id, 2, mbAddress, &info, QScale);
512 if (newQScale != -1) {
513 QScale = newQScale;
514 }
515 }
516
517 /* Determine if new Qscale needed for Rate Control purposes */
518 if (bitstreamMode == FIXED_RATE) {
519 rc_blockStart = bb->cumulativeBits;
520 newQScale = needQScaleChange(qscaleI,
521 current->y_blocks[y][x],
522 current->y_blocks[y][x+1],
523 current->y_blocks[y+1][x],
524 current->y_blocks[y+1][x+1]);
525 if (newQScale > 0) {
526 QScale = newQScale;
527 }
528 }
529
530 if ( (mbAddress % blocksPerSlice == 0) && (mbAddress != 0) ) {
531 /* create a new slice */
532 if (specificsOn) {
533 /* Make sure no slice Qscale change */
534 newQScale = SpecLookup(current->id,1,mbAddress/blocksPerSlice, &info, QScale);
535 if (newQScale != -1) QScale = newQScale;
536 }
537 Mhead_GenSliceEnder(bb);
538 Mhead_GenSliceHeader(bb, 1+(y>>1), QScale, NULL, 0);
539 y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
540
541 GEN_I_BLOCK(I_FRAME, current, bb, 1+(x>>1), QScale);
542 } else {
543 GEN_I_BLOCK(I_FRAME, current, bb, 1, QScale);
544 }
545
546 if (WriteDistortionNumbers) {
547 CalcDistortion(current, y, x);
548 }
549
550 if ( decodeRefFrames ) {
551 /* now, reverse the DCT transform */
552 LaplaceCnum = 0;
553 for ( index = 0; index < 6; index++ ) {
554 if (!DoLaplace) {
555 Mpost_UnQuantZigBlock(fb[index], dec[index], QScale, TRUE);
556 } else {
557 if (index == 4) {LaplaceCnum = 1;}
558 if (index == 5) {LaplaceCnum = 2;}
559 Mpost_UnQuantZigBlockLaplace(fb[index], dec[index], QScale, TRUE);
560 }
561 mpeg_jrevdct((int16 *)dec[index]);
562 }
563
564 /* now, unblockify */
565 BlockToData(current->decoded_y, dec[0], y, x);
566 BlockToData(current->decoded_y, dec[1], y, x+1);
567 BlockToData(current->decoded_y, dec[2], y+1, x);
568 BlockToData(current->decoded_y, dec[3], y+1, x+1);
569 BlockToData(current->decoded_cb, dec[4], y>>1, x>>1);
570 BlockToData(current->decoded_cr, dec[5], y>>1, x>>1);
571 }
572
573 numBlocks++;
574 mbAddress++;
575 /* Rate Control */
576 if (bitstreamMode == FIXED_RATE) {
577 incMacroBlockBits(bb->cumulativeBits - rc_blockStart);
578 rc_blockStart = bb->cumulativeBits;
579 MB_RateOut(TYPE_IFRAME);
580 }
581 }
582 }
583
584 if ( printSNR ) {
585 BlockComputeSNR(current,snr,psnr);
586 totalSNR += snr[0];
587 totalPSNR += psnr[0];
588 }
589
590 if ( (referenceFrame == DECODED_FRAME) && NonLocalRefFrame(current->id) ) {
591 if ( remoteIO ) {
592 SendDecodedFrame(current);
593 } else {
594 WriteDecodedFrame(current);
595 }
596
597 /* now, tell decode server it is ready */
598 NotifyDecodeServerReady(current->id);
599 }
600
601 numBits += (bb->cumulativeBits-totalBits);
602
603 DBG_PRINT(("End of frame\n"));
604
605 Mhead_GenSliceEnder(bb);
606 /* Rate Control */
607 if (bitstreamMode == FIXED_RATE) {
608 updateRateControl(TYPE_IFRAME);
609 }
610
611 endTime = time_elapsed();
612 totalTime += (endTime-startTime);
613
614 numFrameBits += (bb->cumulativeBits-totalFrameBits);
615
616 if ( ( ! childProcess) && showBitRatePerFrame ) {
617 /* ASSUMES 30 FRAMES PER SECOND */
618 fprintf(bitRateFile, "%5d\t%8d\n", current->id,
619 30*(bb->cumulativeBits-totalFrameBits));
620 }
621
622 if ( (! childProcess) && frameSummary && (! realQuiet) ) {
623
624 /* ASSUMES 30 FRAMES PER SECOND */
625 fprintf(stdout, "FRAME %d (I): %ld seconds (%d bits/s output)\n",
626 current->id, (long)((endTime-startTime)/TIME_RATE),
627 30*(bb->cumulativeBits-totalFrameBits));
628 if ( printSNR ) {
629 fprintf(stdout, "FRAME %d: SNR: %.1f\t%.1f\t%.1f\tPSNR: %.1f\t%.1f\t%.1f\n",
630 current->id, snr[0], snr[1], snr[2],
631 psnr[0], psnr[1], psnr[2]);
632 }
633 }
634 }
635
636
637 /*===========================================================================*
638 *
639 * ResetIFrameStats
640 *
641 * reset the I-frame statistics
642 *
643 * RETURNS: nothing
644 *
645 * SIDE EFFECTS: none
646 *
647 *===========================================================================*/
648 void
649 ResetIFrameStats()
650 {
651 numBlocks = 0;
652 numBits = 0;
653 numFrames = 0;
654 numFrameBits = 0;
655 totalTime = 0;
656 }
657
658
659 /*===========================================================================*
660 *
661 * ShowIFrameSummary
662 *
663 * prints out statistics on all I-frames
664 *
665 * RETURNS: time taken for I-frames (in seconds)
666 *
667 * SIDE EFFECTS: none
668 *
669 *===========================================================================*/
670 float
671 ShowIFrameSummary(inputFrameBits, totalBits, fpointer)
672 int inputFrameBits;
673 int32 totalBits;
674 FILE *fpointer;
675 {
676 if ( numFrames == 0 ) {
677 return 0.0;
678 }
679
680 fprintf(fpointer, "-------------------------\n");
681 fprintf(fpointer, "*****I FRAME SUMMARY*****\n");
682 fprintf(fpointer, "-------------------------\n");
683
684 fprintf(fpointer, " Blocks: %5d (%6d bits) (%5d bpb)\n",
685 numBlocks, numBits, numBits/numBlocks);
686 fprintf(fpointer, " Frames: %5d (%6d bits) (%5d bpf) (%2.1f%% of total)\n",
687 numFrames, numFrameBits, numFrameBits/numFrames,
688 100.0*(float)numFrameBits/(float)totalBits);
689 fprintf(fpointer, " Compression: %3d:1 (%9.4f bpp)\n",
690 numFrames*inputFrameBits/numFrameBits,
691 24.0*(float)numFrameBits/(float)(numFrames*inputFrameBits));
692 if ( printSNR )
693 fprintf(fpointer, " Avg Y SNR/PSNR: %.1f %.1f\n",
694 totalSNR/(float)numFrames, totalPSNR/(float)numFrames);
695 if ( totalTime == 0 ) {
696 fprintf(fpointer, " Seconds: NONE\n");
697 } else {
698 fprintf(fpointer, " Seconds: %9ld (%9.4f fps) (%9ld pps) (%9ld mps)\n",
699 (long)(totalTime/TIME_RATE),
700 (float)((float)(TIME_RATE*numFrames)/(float)totalTime),
701 (long)((float)TIME_RATE*(float)numFrames*(float)inputFrameBits/(24.0*(float)totalTime)),
702 (long)((float)TIME_RATE*(float)numFrames*(float)inputFrameBits/(256.0*24.0*(float)totalTime)));
703 }
704
705 return (float)totalTime/(float)TIME_RATE;
706 }
707
708
709 /*===========================================================================*
710 *
711 * EstimateSecondsPerIFrame
712 *
713 * estimates the number of seconds required per I-frame
714 *
715 * RETURNS: seconds (floating point value)
716 *
717 * SIDE EFFECTS: none
718 *
719 *===========================================================================*/
720 float
721 EstimateSecondsPerIFrame()
722 {
723 return (float)totalTime/((float)TIME_RATE*(float)numFrames);
724 }
725
726
727 /*===========================================================================*
728 *
729 * EncodeYDC
730 *
731 * Encode the DC portion of a DCT of a luminance block
732 *
733 * RETURNS: result appended to bb
734 *
735 * SIDE EFFECTS: updates pred_term
736 *
737 *===========================================================================*/
738 void
739 EncodeYDC(dc_term, pred_term, bb)
740 int32 dc_term;
741 int32 *pred_term;
742 BitBucket *bb;
743 {
744 /* see Table B.5a -- MPEG-I doc */
745 static int codes[9] = {
746 0x4, 0x0, 0x1, 0x5, 0x6, 0xe, 0x1e, 0x3e, 0x7e
747 };
748 static int codeLengths[9] = {
749 3, 2, 2, 3, 3, 4, 5, 6, 7
750 };
751 int ydiff, ydiff_abs;
752 int length;
753
754 ydiff = (dc_term - (*pred_term));
755 if (ydiff > 255) {
756 #ifdef BLEAH
757 fprintf(stdout, "TRUNCATED\n");
758 #endif
759 ydiff = 255;
760 } else if (ydiff < -255) {
761 #ifdef BLEAH
762 fprintf(stdout, "TRUNCATED\n");
763 #endif
764 ydiff = -255;
765 }
766
767 ydiff_abs = ABS(ydiff);
768 length = lengths[ydiff_abs];
769 Bitio_Write(bb, codes[length], codeLengths[length]);
770 if ( length != 0 ) {
771 if ( ydiff > 0 ) {
772 Bitio_Write(bb, ydiff_abs, length);
773 } else {
774 Bitio_Write(bb, ~ydiff_abs, length);
775 }
776 }
777
778 (*pred_term) += ydiff;
779 }
780
781
782 /*===========================================================================*
783 *
784 * EncodeCDC
785 *
786 * Encode the DC portion of a DCT of a chrominance block
787 *
788 * RETURNS: result appended to bb
789 *
790 * SIDE EFFECTS: updates pred_term
791 *
792 *===========================================================================*/
793 void
794 EncodeCDC(dc_term, pred_term, bb)
795 int32 dc_term;
796 int32 *pred_term;
797 BitBucket *bb;
798 {
799 /* see Table B.5b -- MPEG-I doc */
800 static int codes[9] = {
801 0x0, 0x1, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe
802 };
803 static int codeLengths[9] = {
804 2, 2, 2, 3, 4, 5, 6, 7, 8
805 };
806 int cdiff, cdiff_abs;
807 int length;
808
809 cdiff = (dc_term - (*pred_term));
810 if (cdiff > 255) {
811 #ifdef BLEAH
812 fprintf(stdout, "TRUNCATED\n");
813 #endif
814 cdiff = 255;
815 } else if (cdiff < -255) {
816 #ifdef BLEAH
817 fprintf(stdout, "TRUNCATED\n");
818 #endif
819 cdiff = -255;
820 }
821
822 cdiff_abs = ABS(cdiff);
823 length = lengths[cdiff_abs];
824 Bitio_Write(bb, codes[length], codeLengths[length]);
825 if ( length != 0 ) {
826 if ( cdiff > 0 ) {
827 Bitio_Write(bb, cdiff_abs, length);
828 } else {
829 Bitio_Write(bb, ~cdiff_abs, length);
830 }
831 }
832
833 (*pred_term) += cdiff;
834 }
835
836
837 void
838 BlockComputeSNR(current, snr, psnr)
839 MpegFrame *current;
840 float snr[];
841 float psnr[];
842 {
843 register int32 tempInt;
844 register int y, x;
845 int32 varDiff[3];
846 double ratio[3];
847 double total[3];
848 register uint8 **origY=current->orig_y, **origCr=current->orig_cr,
849 **origCb=current->orig_cb;
850 register uint8 **newY=current->decoded_y, **newCr=current->decoded_cr,
851 **newCb=current->decoded_cb;
852 static int32 **SignalY, **NoiseY;
853 static int32 **SignalCb, **NoiseCb;
854 static int32 **SignalCr, **NoiseCr;
855 static short ySize[3], xSize[3];
856 static boolean needs_init=TRUE;
857
858 /* Init */
859 if (needs_init) {
860 int ysz = (Fsize_y>>3) * sizeof(int32 *);
861 int xsz = (Fsize_x>>3);
862
863 needs_init = FALSE;
864 for (y=0; y<3; y++) {
865 varDiff[y] = ratio[y] = total[y] = 0.0;
866 }
867 ySize[0]=Fsize_y; xSize[0]=Fsize_x;
868 ySize[1]=Fsize_y>>1; xSize[1]=Fsize_x>>1;
869 ySize[2]=Fsize_y>>1; xSize[2]=Fsize_x>>1;
870 SignalY = (int32 **) malloc(ysz);
871 NoiseY = (int32 **) malloc(ysz);
872 SignalCb = (int32 **) malloc(ysz);
873 NoiseCb = (int32 **) malloc(ysz);
874 SignalCr = (int32 **) malloc(ysz);
875 NoiseCr = (int32 **) malloc(ysz);
876 if (SignalY == NULL || NoiseY == NULL || SignalCr == NULL ||
877 NoiseCb == NULL || SignalCb == NULL || NoiseCr == NULL) {
878 fprintf(stderr, "Out of memory in BlockComputeSNR\n");
879 exit(-1);
880 }
881 for (y = 0; y < ySize[0]>>3; y++) {
882 SignalY[y] = (int32 *) calloc(xsz,4);
883 SignalCr[y] = (int32 *) calloc(xsz,4);
884 SignalCb[y] = (int32 *) calloc(xsz,4);
885 NoiseY[y] = (int32 *) calloc(xsz,4);
886 NoiseCr[y] = (int32 *) calloc(xsz,4);
887 NoiseCb[y] = (int32 *) calloc(xsz,4);
888 }
889 } else {
890 for (y = 0; y < ySize[0]>>3; y++) {
891 memset((char *) &NoiseY[y][0], 0, (xSize[0]>>3) * 4);
892 memset((char *) &SignalY[y][0], 0, (xSize[0]>>3) * 4);
893 memset((char *) &NoiseCb[y][0], 0, (xSize[0]>>3) * 4);
894 memset((char *) &NoiseCr[y][0], 0, (xSize[0]>>3) * 4);
895 memset((char *) &SignalCb[y][0], 0, (xSize[0]>>3) * 4);
896 memset((char *) &SignalCr[y][0], 0, (xSize[0]>>3) * 4);
897 }
898 }
899
900 /* find all the signal and noise */
901 for (y = 0; y < ySize[0]; y++) {
902 for (x = 0; x < xSize[0]; x++) {
903 tempInt = (origY[y][x] - newY[y][x]);
904 NoiseY[y>>4][x>>4] += tempInt*tempInt;
905 total[0] += (double)abs(tempInt);
906 tempInt = origY[y][x];
907 SignalY[y>>4][x>>4] += tempInt*tempInt;
908 }}
909 for (y = 0; y < ySize[1]; y++) {
910 for (x = 0; x < xSize[1]; x ++) {
911 tempInt = (origCb[y][x] - newCb[y][x]);
912 NoiseCb[y>>3][x>>3] += tempInt*tempInt;
913 total[1] += (double)abs(tempInt);
914 tempInt = origCb[y][x];
915 SignalCb[y>>3][x>>3] += tempInt*tempInt;
916 tempInt = (origCr[y][x]-newCr[y][x]);
917 NoiseCr[y>>3][x>>3] += tempInt*tempInt;
918 total[2] += (double)abs(tempInt);
919 tempInt = origCr[y][x];
920 SignalCr[y>>3][x>>3] += tempInt*tempInt;
921 }}
922
923 /* Now sum up that noise */
924 for(y=0; y<Fsize_y>>4; y++){
925 for(x=0; x<Fsize_x>>4; x++){
926 varDiff[0] += NoiseY[y][x];
927 varDiff[1] += NoiseCb[y][x];
928 varDiff[2] += NoiseCr[y][x];
929 if (printMSE) printf("%4d ",(int)(NoiseY[y][x]/256.0));
930 }
931 if (printMSE) puts("");
932 }
933
934 /* Now look at those ratios! */
935 for(y=0; y<Fsize_y>>4; y++){
936 for(x=0; x<Fsize_x>>4; x++){
937 ratio[0] += (double)SignalY[y][x]/(double)varDiff[0];
938 ratio[1] += (double)SignalCb[y][x]/(double)varDiff[1];
939 ratio[2] += (double)SignalCr[y][x]/(double)varDiff[2];
940 }}
941
942 for (x=0; x<3; x++) {
943 snr[x] = 10.0*log10(ratio[x]);
944 psnr[x] = 20.0*log10(255.0/sqrt((double)varDiff[x]/(double)(ySize[x]*xSize[x])));
945
946 if (! realQuiet) {
947 fprintf(stdout, "Mean error[%1d]: %f\n", x, total[x]/(double)(xSize[x]*ySize[x]));
948 }
949
950 }
951 }
952
953 void
954 WriteDecodedFrame(frame)
955 MpegFrame *frame;
956 {
957 FILE *fpointer;
958 char fileName[256];
959 int width, height;
960 register int y;
961
962 /* need to save decoded frame to disk because it might be accessed
963 by another process */
964
965 width = Fsize_x;
966 height = Fsize_y;
967
968 sprintf(fileName, "%s.decoded.%d", outputFileName, frame->id);
969
970 if (!realQuiet) {
971 fprintf(stdout, "Outputting to %s\n", fileName);
972 fflush(stdout);
973 }
974
975 fpointer = fopen(fileName, "wb");
976
977 for ( y = 0; y < height; y++ ) {
978 fwrite(frame->decoded_y[y], 1, width, fpointer);
979 }
980
981 for (y = 0; y < (height >> 1); y++) { /* U */
982 fwrite(frame->decoded_cb[y], 1, width >> 1, fpointer);
983 }
984
985 for (y = 0; y < (height >> 1); y++) { /* V */
986 fwrite(frame->decoded_cr[y], 1, width >> 1, fpointer);
987 }
988 fflush(fpointer);
989 fclose(fpointer);
990 }
991
992
993 void
994 PrintItoIBitRate(numBits, frameNum)
995 int numBits;
996 int frameNum;
997 {
998 if ( ( ! childProcess) && showBitRatePerFrame ) {
999 /* ASSUMES 30 FRAMES PER SECOND */
1000
1001 if (! realQuiet) {
1002 fprintf(stdout, "I-to-I (frames %5d to %5d) bitrate: %8d\n",
1003 lastIFrame, frameNum-1,
1004 ((numBits-lastNumBits)*30)/
1005 (frameNum-lastIFrame));
1006 }
1007
1008 fprintf(bitRateFile, "I-to-I (frames %5d to %5d) bitrate: %8d\n",
1009 lastIFrame, frameNum-1,
1010 ((numBits-lastNumBits)*30)/
1011 (frameNum-lastIFrame));
1012 }
1013 }
1014
1015
1016 /*===========================================================================*
1017 *
1018 * AllocDctBlocks
1019 *
1020 * allocate memory for dct blocks
1021 *
1022 * RETURNS: nothing
1023 *
1024 * SIDE EFFECTS: creates dct, dctr, dctb
1025 *
1026 *===========================================================================*/
1027 void
1028 AllocDctBlocks()
1029 {
1030 int dctx, dcty;
1031 int i;
1032
1033 dctx = Fsize_x / DCTSIZE;
1034 dcty = Fsize_y / DCTSIZE;
1035
1036 dct = (Block **) malloc(sizeof(Block *) * dcty);
1037 ERRCHK(dct, "malloc");
1038 for (i = 0; i < dcty; i++) {
1039 dct[i] = (Block *) malloc(sizeof(Block) * dctx);
1040 ERRCHK(dct[i], "malloc");
1041 }
1042
1043 dct_data = (dct_data_type **) malloc(sizeof(dct_data_type *) * dcty);
1044 ERRCHK(dct_data, "malloc");
1045 for (i = 0; i < dcty; i++) {
1046 dct_data[i] = (dct_data_type *) malloc(sizeof(dct_data_type) * dctx);
1047 ERRCHK(dct[i], "malloc");
1048 }
1049
1050 dctr = (Block **) malloc(sizeof(Block *) * (dcty >> 1));
1051 dctb = (Block **) malloc(sizeof(Block *) * (dcty >> 1));
1052 ERRCHK(dctr, "malloc");
1053 ERRCHK(dctb, "malloc");
1054 for (i = 0; i < (dcty >> 1); i++) {
1055 dctr[i] = (Block *) malloc(sizeof(Block) * (dctx >> 1));
1056 dctb[i] = (Block *) malloc(sizeof(Block) * (dctx >> 1));
1057 ERRCHK(dctr[i], "malloc");
1058 ERRCHK(dctb[i], "malloc");
1059 }
1060 }
1061
1062
1063 /*======================================================================*
1064 *
1065 * time_elapsed
1066 *
1067 * Handle different time systems on different machines
1068 *
1069 * RETURNS number of seconds process time used
1070 *
1071 *======================================================================*/
1072 int32 time_elapsed()
1073 {
1074 #ifdef CLOCKS_PER_SEC
1075 /* ANSI C */
1076 TIME_RATE = CLOCKS_PER_SEC;
1077 return (int32) clock();
1078 #else
1079 struct tms timeBuffer;
1080 TIME_RATE = 60;
1081 times(&timeBuffer);
1082 return timeBuffer.tms_utime + timeBuffer.tms_stime;
1083 #endif
1084 }
1085
1086
1087 void
1088 CalcDistortion(current, y, x)
1089 MpegFrame *current;
1090 int y,x;
1091 {
1092
1093 int qscale, distort=0;
1094 Block decblk;
1095 FlatBlock fblk;
1096 int datarate = 0;
1097
1098 for (qscale = 1; qscale < 32; qscale ++) {
1099 distort = 0;
1100 datarate = 0;
1101 Mpost_QuantZigBlock(dct[y][x], fblk, qscale, TRUE);
1102 Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
1103 if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
1104 mpeg_jrevdct((int16 *)decblk);
1105 distort += mse(current->y_blocks[y][x], decblk);
1106
1107 Mpost_QuantZigBlock(dct[y][x+1], fblk, qscale, TRUE);
1108 Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
1109 if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
1110 mpeg_jrevdct((int16 *)decblk);
1111 distort += mse(current->y_blocks[y][x+1], decblk);
1112
1113 Mpost_QuantZigBlock(dct[y+1][x], fblk, qscale, TRUE);
1114 Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
1115 if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
1116 mpeg_jrevdct((int16 *)decblk);
1117 distort += mse(current->y_blocks[y+1][x], decblk);
1118
1119 Mpost_QuantZigBlock(dct[y+1][x+1], fblk, qscale, TRUE);
1120 Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
1121 if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
1122 mpeg_jrevdct((int16 *)decblk);
1123 distort += mse(current->y_blocks[y+1][x+1], decblk);
1124
1125 Mpost_QuantZigBlock(dctb[y >> 1][x >> 1], fblk, qscale, TRUE);
1126 Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
1127 if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
1128 mpeg_jrevdct((int16 *)decblk);
1129 distort += mse(current->cb_blocks[y>>1][x>>1], decblk);
1130
1131 Mpost_QuantZigBlock(dctr[y >> 1][x >> 1], fblk, qscale, TRUE);
1132 Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
1133 if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
1134 mpeg_jrevdct((int16 *)decblk);
1135 distort += mse(current->cr_blocks[y >> 1][x >> 1], decblk);
1136
1137 if (!collect_distortion_detailed) {
1138 fprintf(distortion_fp, "\t%d\n", distort);
1139 } else if (collect_distortion_detailed == 1) {
1140 fprintf(distortion_fp, "\t%d\t%d\n", distort, datarate);
1141 } else {
1142 fprintf(fp_table_rate[qscale-1], "%d\n", datarate);
1143 fprintf(fp_table_dist[qscale-1], "%d\n", distort);
1144 }
1145 }
1146 }