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 (11 years, 10 months ago) by wdelano
File size: 31242 byte(s)
Log Message:
changes for win32
Line User Rev File contents
1 wdelano 22 /*===========================================================================*
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 wdelano 23 #ifdef WIN32
140     #define CLOCKS_PER_SEC 1000
141     #else
142 wdelano 22 #ifdef CLOCKS_PER_SEC
143     #include <times.h>
144     #else
145     #include <sys/times.h>
146     #endif
147 wdelano 23 #endif
148 wdelano 22
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     }