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