Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

iframe.c

Go to the documentation of this file.
00001 /*===========================================================================*
00002  * iframe.c                                                                  *
00003  *                                                                           *
00004  *      Procedures concerned with the I-frame encoding                       *
00005  *                                                                           *
00006  * EXPORTED PROCEDURES:                                                      *
00007  *      GenIFrame                                                            *
00008  *      SetSlicesPerFrame                                                    *
00009  *      SetBlocksPerSlice                                                    *
00010  *      SetIQScale                                                           *
00011  *      GetIQScale                                                           *
00012  *      ResetIFrameStats                                                     *
00013  *      ShowIFrameSummary                                                    *
00014  *      EstimateSecondsPerIFrame                                             *
00015  *      EncodeYDC                                                            *
00016  *      EncodeCDC                                                            *
00017  *      time_elapsed                                                         *
00018  *                                                                           *
00019  *===========================================================================*/
00020 
00021 /*
00022  * Copyright (c) 1995 The Regents of the University of California.
00023  * All rights reserved.
00024  *
00025  * Permission to use, copy, modify, and distribute this software and its
00026  * documentation for any purpose, without fee, and without written agreement is
00027  * hereby granted, provided that the above copyright notice and the following
00028  * two paragraphs appear in all copies of this software.
00029  *
00030  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
00031  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
00032  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
00033  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034  *
00035  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
00036  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
00037  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
00038  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
00039  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
00040  */
00041 
00042 /*
00043  *  $Header: /misc/elrond0/share/cvs/AFNI/src/mpeg_encodedir/iframe.c,v 1.4 2004/04/02 15:12:40 rwcox Exp $
00044  *  $Log: iframe.c,v $
00045  *  Revision 1.4  2004/04/02 15:12:40  rwcox
00046  *  Cput
00047  *
00048  *  Revision 1.3  2003/12/23 13:50:08  rwcox
00049  *  Cput
00050  *
00051  *  Revision 1.2  2003/12/03 14:46:14  rwcox
00052  *  Cput
00053  *
00054  *  Revision 1.1  2001/12/17 16:11:54  rwcox
00055  *  Cadd
00056  *
00057  *  Revision 1.23  1995/08/14 22:29:49  smoot
00058  *  changed inits in BlockComputeSNR so sgi compiler would be happy
00059  *
00060  *  Revision 1.22  1995/08/07 21:50:51  smoot
00061  *  spacing
00062  *  simplified some code
00063  *  added Laplace stuff
00064  *  minor error check bug in alloc
00065  *
00066  * Revision 1.21  1995/06/21  22:24:25  smoot
00067  * added CalcDistortion (TUNEing)
00068  * fixed timeing stuff for ANSI
00069  * fixed specifics bug
00070  *
00071  * Revision 1.20  1995/05/02  21:59:43  smoot
00072  * fixed BlockComputeSNR bugs
00073  *
00074  * Revision 1.19  1995/04/24  23:02:50  smoot
00075  * Fixed BlockComputeSNR for Linux and others
00076  *
00077  * Revision 1.18  1995/04/14  23:08:02  smoot
00078  * reorganized to ease rate control experimentation
00079  *
00080  * Revision 1.17  1995/02/24  23:49:38  smoot
00081  * added support for Specifics file version 2
00082  *
00083  * Revision 1.16  1995/01/30  20:02:34  smoot
00084  * cleanup, killed a couple warnings
00085  *
00086  * Revision 1.15  1995/01/30  19:49:17  smoot
00087  * cosmetic
00088  *
00089  * Revision 1.14  1995/01/23  02:49:34  darryl
00090  * initialized variable
00091  *
00092  * Revision 1.13  1995/01/19  23:08:30  eyhung
00093  * Changed copyrights
00094  *
00095  * Revision 1.12  1995/01/16  08:01:34  eyhung
00096  * Added realQuiet
00097  *
00098  * Revision 1.11  1994/12/07  00:40:36  smoot
00099  * Added seperate P and B search ranges
00100  *
00101  * Revision 1.10  1994/11/14  22:30:30  smoot
00102  * Merged specifics and rate control
00103  *
00104  * Revision 1.9  1994/11/01  05:00:48  darryl
00105  * with rate control changes added
00106  *
00107  * Revision 2.2  1994/10/31  00:06:07  darryl
00108  * version before, hopefully, final changes
00109  *
00110  * Revision 2.1  1994/10/24  22:03:01  darryl
00111  * put in preliminary experiments code
00112  *
00113  * Revision 2.0  1994/10/24  02:38:04  darryl
00114  * will be adding the experiment stuff.
00115  *
00116  * Revision 1.1  1994/09/27  00:15:24  darryl
00117  * Initial revision
00118  *
00119  * Revision 1.8  1994/03/15  00:27:11  keving
00120  * nothing
00121  *
00122  * Revision 1.7  1993/12/22  19:19:01  keving
00123  * nothing
00124  *
00125  * Revision 1.6  1993/07/22  22:23:43  keving
00126  * nothing
00127  *
00128  * Revision 1.5  1993/06/30  20:06:09  keving
00129  * nothing
00130  *
00131  * Revision 1.4  1993/06/03  21:08:08  keving
00132  * nothing
00133  *
00134  * Revision 1.3  1993/03/04  22:24:06  keving
00135  * nothing
00136  *
00137  * Revision 1.2  1993/02/19  18:10:02  keving
00138  * nothing
00139  *
00140  * Revision 1.1  1993/02/18  22:56:39  keving
00141  * nothing
00142  *
00143  *
00144  */
00145 
00146 
00147 /*==============*
00148  * HEADER FILES *
00149  *==============*/
00150 
00151 
00152 #ifdef CLOCKS_PER_SEC
00153 #include <times.h>
00154 #else
00155 #include <sys/times.h>
00156 #endif
00157 
00158 #include <sys/param.h>
00159 #include "all.h"
00160 #include "mtypes.h"
00161 #include "frames.h"
00162 #include "prototypes.h"
00163 #include "mpeg.h"
00164 #include "param.h"
00165 #include "mheaders.h"
00166 #include "fsize.h"
00167 #include "parallel.h"
00168 #include "postdct.h"
00169 #include "rate.h"
00170 #include "opts.h"
00171 
00172 /*==================*
00173  * STATIC VARIABLES *
00174  *==================*/
00175 
00176 static  int     lastNumBits = 0;
00177 static  int     lastIFrame = 0;
00178 static int numBlocks = 0;
00179 static int numBits;
00180 static int numFrames = 0;
00181 static int numFrameBits = 0;
00182 static int32 totalTime = 0;
00183 static float    totalSNR = 0.0;
00184 static float    totalPSNR = 0.0;
00185 
00186 static int lengths[256] = {
00187     0, 1, 2, 2, 3, 3, 3, 3,         /* 0 - 7 */
00188     4, 4, 4, 4, 4, 4, 4, 4,         /* 8 - 15 */
00189     5, 5, 5, 5, 5, 5, 5, 5,         /* 16 - 31 */
00190     5, 5, 5, 5, 5, 5, 5, 5,
00191     6, 6, 6, 6, 6, 6, 6, 6,         /* 32 - 63 */
00192     6, 6, 6, 6, 6, 6, 6, 6,
00193     6, 6, 6, 6, 6, 6, 6, 6,
00194     6, 6, 6, 6, 6, 6, 6, 6,
00195     7, 7, 7, 7, 7, 7, 7, 7,         /* 64 - 127 */
00196     7, 7, 7, 7, 7, 7, 7, 7,
00197     7, 7, 7, 7, 7, 7, 7, 7,
00198     7, 7, 7, 7, 7, 7, 7, 7,
00199     7, 7, 7, 7, 7, 7, 7, 7,
00200     7, 7, 7, 7, 7, 7, 7, 7,
00201     7, 7, 7, 7, 7, 7, 7, 7,
00202     7, 7, 7, 7, 7, 7, 7, 7,
00203     8, 8, 8, 8, 8, 8, 8, 8,
00204     8, 8, 8, 8, 8, 8, 8, 8,
00205     8, 8, 8, 8, 8, 8, 8, 8,
00206     8, 8, 8, 8, 8, 8, 8, 8,
00207     8, 8, 8, 8, 8, 8, 8, 8,
00208     8, 8, 8, 8, 8, 8, 8, 8,
00209     8, 8, 8, 8, 8, 8, 8, 8,
00210     8, 8, 8, 8, 8, 8, 8, 8,
00211     8, 8, 8, 8, 8, 8, 8, 8,
00212     8, 8, 8, 8, 8, 8, 8, 8,
00213     8, 8, 8, 8, 8, 8, 8, 8,
00214     8, 8, 8, 8, 8, 8, 8, 8,
00215     8, 8, 8, 8, 8, 8, 8, 8,
00216     8, 8, 8, 8, 8, 8, 8, 8,
00217     8, 8, 8, 8, 8, 8, 8, 8,
00218     8, 8, 8, 8, 8, 8, 8, 8
00219 };
00220 
00221 
00222 /*==================*
00223  * GLOBAL VARIABLES *
00224  *==================*/
00225 
00226 int     qscaleI;
00227 int     slicesPerFrame;
00228 int     blocksPerSlice;
00229 int     fCodeI, fCodeP, fCodeB;
00230 boolean printSNR = FALSE;
00231 boolean printMSE = FALSE;
00232 boolean decodeRefFrames = FALSE;
00233 Block **dct=NULL, **dctr=NULL, **dctb=NULL;
00234 dct_data_type   **dct_data; /* used in p/bframe.c */
00235 int  TIME_RATE;
00236 
00237 
00238 /*=====================*
00239  * EXPORTED PROCEDURES *
00240  *=====================*/
00241 extern void     PrintItoIBitRate _ANSI_ARGS_((int numBits, int frameNum));
00242 
00243 /*===============================*
00244  * INTERNAL PROCEDURE prototypes *
00245  *===============================*/
00246 void AllocDctBlocks _ANSI_ARGS_((void ));
00247 int SetFCodeHelper _ANSI_ARGS_((int sr));
00248 void CalcDistortion _ANSI_ARGS_((MpegFrame *current, int y, int x));
00249 
00250 int
00251   SetFCodeHelper(SR)
00252 int SR;
00253 {
00254     int     range,fCode;
00255 
00256     if ( pixelFullSearch ) {
00257         range = SR;
00258     } else {
00259         range = SR*2;
00260     }
00261 
00262     if ( range < 256 ) {
00263         if ( range < 64 ) {
00264             if ( range < 32 ) {
00265                 fCode = 1;
00266             } else {
00267                 fCode = 2;
00268             }
00269         } else {
00270             if ( range < 128 ) {
00271                 fCode = 3;
00272             } else {
00273                 fCode = 4;
00274             }
00275         }
00276     } else {
00277         if ( range < 1024 ) {
00278             if ( range < 512 ) {
00279                 fCode = 5;
00280             } else {
00281                 fCode = 6;
00282             }
00283         } else {
00284             if ( range < 2048 ) {
00285                 fCode = 7;
00286             } else {
00287                 fprintf(stderr, "ERROR:  INVALID SEARCH RANGE!!!\n");
00288                 exit(1);
00289             }
00290         }
00291       }
00292     return fCode;
00293 }
00294 
00295 /*===========================================================================*
00296  *
00297  * SetFCode
00298  *
00299  *      set the forward_f_code and backward_f_code according to the search
00300  *      range.  Must be called AFTER pixelFullSearch and searchRange have
00301  *      been initialized.  Irrelevant for I-frames, but computation is
00302  *      negligible (done only once, as well)
00303  *
00304  * RETURNS:     nothing
00305  *
00306  * SIDE EFFECTS:    fCodeI,fCodeP,fCodeB
00307  *
00308  *===========================================================================*/
00309 void
00310 SetFCode()
00311 {
00312   fCodeI = SetFCodeHelper(1); /* GenIFrame ignores value */
00313   fCodeP = SetFCodeHelper(searchRangeP);
00314   fCodeB = SetFCodeHelper(searchRangeB);
00315 }
00316 
00317 /*===========================================================================*
00318  *
00319  * SetSlicesPerFrame
00320  *
00321  *      set the number of slices per frame
00322  *
00323  * RETURNS:     nothing
00324  *
00325  * SIDE EFFECTS:    slicesPerFrame
00326  *
00327  *===========================================================================*/
00328 void
00329 SetSlicesPerFrame(number)
00330     int number;
00331 {
00332     slicesPerFrame = number;
00333 }
00334 
00335 
00336 /*===========================================================================*
00337  *
00338  * SetBlocksPerSlice
00339  *
00340  *      set the number of blocks per slice, based on slicesPerFrame
00341  *
00342  * RETURNS:     nothing
00343  *
00344  * SIDE EFFECTS:    blocksPerSlice
00345  *
00346  *===========================================================================*/
00347 void
00348 SetBlocksPerSlice()
00349 {
00350     int     totalBlocks;
00351 
00352     totalBlocks = (Fsize_y>>4)*(Fsize_x>>4);
00353 
00354     if ( slicesPerFrame > totalBlocks ) {
00355         blocksPerSlice = 1;
00356     } else {
00357         blocksPerSlice = totalBlocks/slicesPerFrame;
00358     }
00359 }
00360 
00361 
00362 /*===========================================================================*
00363  *
00364  * SetIQScale
00365  *
00366  *      set the I-frame Q-scale
00367  *
00368  * RETURNS:     nothing
00369  *
00370  * SIDE EFFECTS:    qscaleI
00371  *
00372  *===========================================================================*/
00373 void
00374 SetIQScale(qI)
00375 int qI;
00376 {
00377     qscaleI = qI;
00378 }
00379 
00380 /*===========================================================================*
00381  *
00382  * GetIQScale
00383  *
00384  *      Get the I-frame Q-scale
00385  *
00386  * RETURNS:     the Iframe Qscale
00387  *
00388  * SIDE EFFECTS:    none
00389  *
00390  *===========================================================================*/
00391 int
00392 GetIQScale()
00393 {
00394     return qscaleI;
00395 }
00396 
00397 /*===========================================================================*
00398  *
00399  * GenIFrame
00400  *
00401  *      generate an I-frame; appends result to bb
00402  *
00403  * RETURNS:     I-frame appended to bb
00404  *
00405  * SIDE EFFECTS:    none
00406  *
00407  *===========================================================================*/
00408 void
00409 GenIFrame(bb, current)
00410      BitBucket *bb;
00411      MpegFrame *current;
00412 {
00413     register int x, y;
00414     register int index;
00415     FlatBlock    fb[6];
00416     Block        dec[6];
00417     int32 y_dc_pred, cr_dc_pred, cb_dc_pred;
00418     int          totalBits;
00419     int          totalFrameBits;
00420     int32        startTime, endTime;
00421     float        snr[3], psnr[3];
00422     int          mbAddress;
00423     int          QScale;
00424     BlockMV      *info; /* Not used in Iframes, but nice to pass in anyway */
00425     int          bitstreamMode, newQScale;
00426     int          rc_blockStart=0;
00427 
00428     if (dct==NULL) AllocDctBlocks();
00429     if (collect_quant) {fprintf(collect_quant_fp, "# I\n");}
00430 
00431     /* set-up for statistics */
00432     numFrames++;
00433     totalFrameBits = bb->cumulativeBits;
00434     if ( ( ! childProcess) && showBitRatePerFrame ) {
00435       if ( lastNumBits == 0 ) {
00436         lastNumBits = bb->cumulativeBits;
00437         lastIFrame = current->id;
00438       } else {
00439         /* ASSUMES 30 FRAMES PER SECOND */
00440         
00441         if (! realQuiet) {
00442           fprintf(stdout, "I-to-I (frames %5d to %5d) bitrate:  %8d\n",
00443                   lastIFrame, current->id-1,
00444                   ((bb->cumulativeBits-lastNumBits)*30)/
00445                   (current->id-lastIFrame));
00446         }
00447         
00448         fprintf(bitRateFile, "I-to-I (frames %5d to %5d) bitrate:  %8d\n",
00449                 lastIFrame, current->id-1,
00450                 ((bb->cumulativeBits-lastNumBits)*30)/
00451                 (current->id-lastIFrame));
00452         lastNumBits = bb->cumulativeBits;           
00453         lastIFrame = current->id;
00454       }
00455     }
00456     
00457     startTime = time_elapsed();
00458     
00459     Frame_AllocBlocks(current);
00460     BlockifyFrame(current);
00461 
00462     DBG_PRINT(("Generating iframe\n"));
00463     QScale = GetIQScale();
00464     /*   Allocate bits for this frame for rate control purposes */
00465     bitstreamMode = getRateMode();
00466     if (bitstreamMode == FIXED_RATE) {
00467       targetRateControl(current);
00468     }
00469 
00470     Mhead_GenPictureHeader(bb, I_FRAME, current->id, fCodeI);
00471     /* Check for Qscale change */
00472     if (specificsOn) {
00473       newQScale = SpecLookup(current->id, 0, 0 /* junk */, &info, QScale);
00474       if (newQScale != -1) {
00475         QScale = newQScale;
00476       }
00477       /* check for slice */
00478       newQScale = SpecLookup(current->id, 1, 1, &info, QScale);
00479       if (newQScale != -1) {
00480         QScale = newQScale;
00481       }
00482     }
00483     Mhead_GenSliceHeader(bb, 1, QScale, NULL, 0);
00484     
00485     if ( referenceFrame == DECODED_FRAME ) {
00486       Frame_AllocDecoded(current, TRUE);
00487     } else if ( printSNR ) {
00488       Frame_AllocDecoded(current, FALSE);
00489     }
00490     
00491     y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
00492     totalBits = bb->cumulativeBits;
00493     mbAddress = 0;
00494 
00495     /* DCT the macroblocks */
00496     for (y = 0;  y < (Fsize_y >> 3);  y += 2) {
00497       for (x = 0;  x < (Fsize_x >> 3);  x += 2) {
00498         if (collect_quant && (collect_quant_detailed & 1)) fprintf(collect_quant_fp, "l\n");
00499         if (DoLaplace) {LaplaceCnum = 0;}
00500         mp_fwd_dct_block2(current->y_blocks[y][x], dct[y][x]);
00501         mp_fwd_dct_block2(current->y_blocks[y][x+1], dct[y][x+1]);
00502         mp_fwd_dct_block2(current->y_blocks[y+1][x], dct[y+1][x]);
00503         mp_fwd_dct_block2(current->y_blocks[y+1][x+1], dct[y+1][x+1]);
00504         if (collect_quant && (collect_quant_detailed & 1)) fprintf(collect_quant_fp, "c\n");
00505         if (DoLaplace) {LaplaceCnum = 1;}
00506         mp_fwd_dct_block2(current->cb_blocks[y>>1][x>>1], dctb[y>>1][x>>1]);
00507         if (DoLaplace) {LaplaceCnum = 2;}
00508         mp_fwd_dct_block2(current->cr_blocks[y>>1][x>>1], dctr[y>>1][x>>1]);
00509       }}
00510         
00511     if (DoLaplace) {
00512       extern void CalcLambdas();
00513       CalcLambdas();
00514     }
00515 
00516     for (y = 0;  y < (Fsize_y >> 3);  y += 2) {
00517       for (x = 0;  x < (Fsize_x >> 3);  x += 2) {
00518         /* Check for Qscale change */
00519         if (specificsOn) {
00520           newQScale = SpecLookup(current->id, 2, mbAddress, &info, QScale);
00521           if (newQScale != -1) {
00522             QScale = newQScale;
00523           }
00524         }
00525         
00526         /*  Determine if new Qscale needed for Rate Control purposes  */
00527         if (bitstreamMode == FIXED_RATE) {
00528           rc_blockStart = bb->cumulativeBits;
00529           newQScale = needQScaleChange(qscaleI,
00530                                        current->y_blocks[y][x],
00531                                        current->y_blocks[y][x+1],
00532                                        current->y_blocks[y+1][x],
00533                                        current->y_blocks[y+1][x+1]);
00534           if (newQScale > 0) {
00535             QScale = newQScale;
00536           }
00537         }
00538         
00539         if ( (mbAddress % blocksPerSlice == 0) && (mbAddress != 0) ) {
00540           /* create a new slice */
00541           if (specificsOn) {
00542             /* Make sure no slice Qscale change */
00543             newQScale = SpecLookup(current->id,1,mbAddress/blocksPerSlice, &info, QScale);
00544             if (newQScale != -1) QScale = newQScale;
00545           }
00546           Mhead_GenSliceEnder(bb);
00547           Mhead_GenSliceHeader(bb, 1+(y>>1), QScale, NULL, 0);
00548           y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
00549           
00550           GEN_I_BLOCK(I_FRAME, current, bb, 1+(x>>1), QScale);
00551         } else {
00552           GEN_I_BLOCK(I_FRAME, current, bb, 1, QScale);
00553         }
00554 
00555         if (WriteDistortionNumbers) {
00556           CalcDistortion(current, y, x);
00557         }
00558         
00559         if ( decodeRefFrames ) {
00560           /* now, reverse the DCT transform */
00561           LaplaceCnum = 0;
00562           for ( index = 0; index < 6; index++ ) {
00563             if (!DoLaplace) {
00564               Mpost_UnQuantZigBlock(fb[index], dec[index], QScale, TRUE);
00565             } else {
00566               if (index == 4) {LaplaceCnum = 1;}
00567               if (index == 5) {LaplaceCnum = 2;}
00568               Mpost_UnQuantZigBlockLaplace(fb[index], dec[index], QScale, TRUE);
00569             }
00570             mpeg_jrevdct((int16 *)dec[index]);          
00571             }
00572           
00573           /* now, unblockify */
00574           BlockToData(current->decoded_y, dec[0], y, x);
00575           BlockToData(current->decoded_y, dec[1], y, x+1);
00576           BlockToData(current->decoded_y, dec[2], y+1, x);
00577           BlockToData(current->decoded_y, dec[3], y+1, x+1);
00578           BlockToData(current->decoded_cb, dec[4], y>>1, x>>1);
00579           BlockToData(current->decoded_cr, dec[5], y>>1, x>>1);
00580         }
00581         
00582         numBlocks++;
00583         mbAddress++;
00584         /*   Rate Control */
00585         if (bitstreamMode == FIXED_RATE) {
00586           incMacroBlockBits(bb->cumulativeBits - rc_blockStart);
00587           rc_blockStart = bb->cumulativeBits;
00588           MB_RateOut(TYPE_IFRAME);
00589         }
00590       }
00591     }
00592     
00593     if ( printSNR ) {
00594       BlockComputeSNR(current,snr,psnr);
00595       totalSNR += snr[0];
00596       totalPSNR += psnr[0];
00597     }
00598     
00599     if ( (referenceFrame == DECODED_FRAME) && NonLocalRefFrame(current->id) ) {
00600       if ( remoteIO ) {
00601         SendDecodedFrame(current);
00602       } else {
00603         WriteDecodedFrame(current);
00604       }
00605       
00606       /* now, tell decode server it is ready */
00607       NotifyDecodeServerReady(current->id);
00608     }
00609     
00610     numBits += (bb->cumulativeBits-totalBits);
00611     
00612     DBG_PRINT(("End of frame\n"));
00613     
00614     Mhead_GenSliceEnder(bb);
00615     /*   Rate Control  */
00616     if (bitstreamMode == FIXED_RATE) {
00617       updateRateControl(TYPE_IFRAME);
00618     }
00619     
00620     endTime = time_elapsed();
00621     totalTime += (endTime-startTime);
00622     
00623     numFrameBits += (bb->cumulativeBits-totalFrameBits);
00624     
00625     if ( ( ! childProcess) && showBitRatePerFrame ) {
00626       /* ASSUMES 30 FRAMES PER SECOND */
00627       fprintf(bitRateFile, "%5d\t%8d\n", current->id,
00628               30*(bb->cumulativeBits-totalFrameBits));
00629     }
00630     
00631     if ( (! childProcess) && frameSummary && (! realQuiet) ) {
00632       
00633       /* ASSUMES 30 FRAMES PER SECOND */
00634       fprintf(stdout, "FRAME %d (I):  %ld seconds  (%d bits/s output)\n", 
00635               current->id, (long)((endTime-startTime)/TIME_RATE),
00636               30*(bb->cumulativeBits-totalFrameBits));
00637       if ( printSNR ) {
00638         fprintf(stdout, "FRAME %d:  SNR:  %.1f\t%.1f\t%.1f\tPSNR:  %.1f\t%.1f\t%.1f\n",
00639                 current->id, snr[0], snr[1], snr[2],
00640                 psnr[0], psnr[1], psnr[2]);
00641       }
00642     }
00643 }
00644 
00645 
00646 /*===========================================================================*
00647  *
00648  * ResetIFrameStats
00649  *
00650  *      reset the I-frame statistics
00651  *
00652  * RETURNS:     nothing
00653  *
00654  * SIDE EFFECTS:    none
00655  *
00656  *===========================================================================*/
00657 void
00658 ResetIFrameStats()
00659 {
00660     numBlocks = 0;
00661     numBits = 0;
00662     numFrames = 0;
00663     numFrameBits = 0;
00664     totalTime = 0;
00665 }
00666 
00667 
00668 /*===========================================================================*
00669  *
00670  * ShowIFrameSummary
00671  *
00672  *      prints out statistics on all I-frames
00673  *
00674  * RETURNS:     time taken for I-frames (in seconds)
00675  *
00676  * SIDE EFFECTS:    none
00677  *
00678  *===========================================================================*/
00679 float
00680 ShowIFrameSummary(inputFrameBits, totalBits, fpointer)
00681     int inputFrameBits;
00682     int32 totalBits;
00683     FILE *fpointer;
00684 {
00685     if ( numFrames == 0 ) {
00686         return 0.0;
00687     }
00688 
00689     fprintf(fpointer, "-------------------------\n");
00690     fprintf(fpointer, "*****I FRAME SUMMARY*****\n");
00691     fprintf(fpointer, "-------------------------\n");
00692 
00693     fprintf(fpointer, "  Blocks:    %5d     (%6d bits)     (%5d bpb)\n",
00694             numBlocks, numBits, numBits/numBlocks);
00695     fprintf(fpointer, "  Frames:    %5d     (%6d bits)     (%5d bpf)     (%2.1f%% of total)\n",
00696             numFrames, numFrameBits, numFrameBits/numFrames,
00697             100.0*(float)numFrameBits/(float)totalBits);
00698     fprintf(fpointer, "  Compression:  %3d:1     (%9.4f bpp)\n",
00699             numFrames*inputFrameBits/numFrameBits,
00700             24.0*(float)numFrameBits/(float)(numFrames*inputFrameBits));
00701     if ( printSNR )
00702         fprintf(fpointer, "  Avg Y SNR/PSNR:  %.1f     %.1f\n",
00703                 totalSNR/(float)numFrames, totalPSNR/(float)numFrames);
00704     if ( totalTime == 0 ) {
00705         fprintf(fpointer, "  Seconds:  NONE\n");
00706     } else {
00707         fprintf(fpointer, "  Seconds:  %9ld     (%9.4f fps)  (%9ld pps)  (%9ld mps)\n",
00708                 (long)(totalTime/TIME_RATE),
00709                 (float)((float)(TIME_RATE*numFrames)/(float)totalTime),
00710                 (long)((float)TIME_RATE*(float)numFrames*(float)inputFrameBits/(24.0*(float)totalTime)),
00711                 (long)((float)TIME_RATE*(float)numFrames*(float)inputFrameBits/(256.0*24.0*(float)totalTime)));
00712     }
00713 
00714     return (float)totalTime/(float)TIME_RATE;
00715 }
00716 
00717 
00718 /*===========================================================================*
00719  *
00720  * EstimateSecondsPerIFrame
00721  *
00722  *      estimates the number of seconds required per I-frame
00723  *
00724  * RETURNS:     seconds (floating point value)
00725  *
00726  * SIDE EFFECTS:    none
00727  *
00728  *===========================================================================*/
00729 float
00730 EstimateSecondsPerIFrame()
00731 {
00732     return (float)totalTime/((float)TIME_RATE*(float)numFrames);
00733 }
00734 
00735 
00736 /*===========================================================================*
00737  *
00738  * EncodeYDC
00739  *
00740  *      Encode the DC portion of a DCT of a luminance block
00741  *
00742  * RETURNS:     result appended to bb
00743  *
00744  * SIDE EFFECTS:    updates pred_term
00745  *
00746  *===========================================================================*/
00747 void
00748 EncodeYDC(dc_term, pred_term, bb)
00749     int32 dc_term;
00750     int32 *pred_term;
00751     BitBucket *bb;
00752 {
00753     /* see Table B.5a -- MPEG-I doc */
00754     static int codes[9] = {
00755         0x4, 0x0, 0x1, 0x5, 0x6, 0xe, 0x1e, 0x3e, 0x7e
00756     };
00757     static int codeLengths[9] = {
00758         3,   2,   2,   3,   3,   4,   5,    6,    7
00759     };
00760     int ydiff, ydiff_abs;
00761     int length;
00762 
00763     ydiff = (dc_term - (*pred_term));
00764     if (ydiff > 255) {
00765 #ifdef BLEAH 
00766       fprintf(stdout, "TRUNCATED\n");
00767 #endif
00768         ydiff = 255;
00769     } else if (ydiff < -255) {
00770 #ifdef BLEAH 
00771       fprintf(stdout, "TRUNCATED\n");
00772 #endif
00773         ydiff = -255;
00774     }
00775 
00776     ydiff_abs = ABS(ydiff);
00777     length = lengths[ydiff_abs];
00778     Bitio_Write(bb, codes[length], codeLengths[length]);
00779     if ( length != 0 ) {
00780         if ( ydiff > 0 ) {
00781             Bitio_Write(bb, ydiff_abs, length);
00782         } else {
00783             Bitio_Write(bb, ~ydiff_abs, length);
00784         }
00785     }
00786 
00787     (*pred_term) += ydiff;
00788 }
00789 
00790 
00791 /*===========================================================================*
00792  *
00793  * EncodeCDC
00794  *
00795  *      Encode the DC portion of a DCT of a chrominance block
00796  *
00797  * RETURNS:     result appended to bb
00798  *
00799  * SIDE EFFECTS:    updates pred_term
00800  *
00801  *===========================================================================*/
00802 void
00803 EncodeCDC(dc_term, pred_term, bb)
00804     int32 dc_term;
00805     int32 *pred_term;
00806     BitBucket *bb;
00807 {
00808     /* see Table B.5b -- MPEG-I doc */
00809     static int codes[9] = {
00810         0x0, 0x1, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe
00811     };
00812     static int codeLengths[9] = {
00813         2,   2,   2,   3,   4,   5,    6,    7,    8
00814     };
00815     int cdiff, cdiff_abs;
00816     int length;
00817 
00818     cdiff = (dc_term - (*pred_term));
00819     if (cdiff > 255) {
00820 #ifdef BLEAH
00821 fprintf(stdout, "TRUNCATED\n"); 
00822 #endif
00823         cdiff = 255;
00824     } else if (cdiff < -255) {
00825 #ifdef BLEAH
00826 fprintf(stdout, "TRUNCATED\n"); 
00827 #endif
00828         cdiff = -255;
00829     }
00830 
00831     cdiff_abs = ABS(cdiff);
00832     length = lengths[cdiff_abs];
00833     Bitio_Write(bb, codes[length], codeLengths[length]);
00834     if ( length != 0 ) {
00835         if ( cdiff > 0 ) {
00836             Bitio_Write(bb, cdiff_abs, length);
00837         } else {
00838             Bitio_Write(bb, ~cdiff_abs, length);
00839         }
00840     }
00841 
00842     (*pred_term) += cdiff;
00843 }
00844 
00845 
00846 void
00847 BlockComputeSNR(current, snr, psnr)
00848      MpegFrame *current;
00849      float snr[];
00850      float psnr[];
00851 {
00852   register int32        tempInt;
00853   register int y, x;
00854   int32 varDiff[3];
00855   double        ratio[3];
00856   double        total[3];
00857   register uint8 **origY=current->orig_y, **origCr=current->orig_cr, 
00858   **origCb=current->orig_cb;
00859   register uint8 **newY=current->decoded_y, **newCr=current->decoded_cr, 
00860   **newCb=current->decoded_cb;
00861   static int32       **SignalY,  **NoiseY;
00862   static int32       **SignalCb, **NoiseCb;
00863   static int32       **SignalCr, **NoiseCr;
00864   static short   ySize[3], xSize[3];
00865   static boolean needs_init=TRUE;
00866   
00867   /* Init */
00868   if (needs_init) {
00869     int ysz = (Fsize_y>>3) * sizeof(int32 *);
00870     int xsz = (Fsize_x>>3);
00871     
00872     needs_init = FALSE;
00873     for (y=0; y<3; y++) {
00874       varDiff[y] = ratio[y] = total[y] = 0.0;
00875     }
00876     ySize[0]=Fsize_y;     xSize[0]=Fsize_x;
00877     ySize[1]=Fsize_y>>1;  xSize[1]=Fsize_x>>1;
00878     ySize[2]=Fsize_y>>1;  xSize[2]=Fsize_x>>1;
00879     SignalY  = (int32 **) malloc(ysz);
00880     NoiseY   = (int32 **) malloc(ysz);
00881     SignalCb = (int32 **) malloc(ysz);
00882     NoiseCb  = (int32 **) malloc(ysz);
00883     SignalCr = (int32 **) malloc(ysz);
00884     NoiseCr  = (int32 **) malloc(ysz);
00885     if (SignalY == NULL || NoiseY == NULL || SignalCr == NULL || 
00886         NoiseCb == NULL || SignalCb == NULL || NoiseCr == NULL) {
00887       fprintf(stderr, "Out of memory in BlockComputeSNR\n");
00888       exit(-1);
00889     }
00890     for (y = 0; y < ySize[0]>>3; y++) {
00891       SignalY[y]  = (int32 *) calloc(xsz,4);
00892       SignalCr[y]  = (int32 *) calloc(xsz,4);
00893       SignalCb[y]  = (int32 *) calloc(xsz,4);
00894       NoiseY[y]  = (int32 *) calloc(xsz,4);
00895       NoiseCr[y]  = (int32 *) calloc(xsz,4);
00896       NoiseCb[y]  = (int32 *) calloc(xsz,4);
00897     }
00898   } else {
00899     for (y = 0; y < ySize[0]>>3; y++) {
00900       memset((char *) &NoiseY[y][0], 0, (xSize[0]>>3) * 4);
00901       memset((char *) &SignalY[y][0], 0, (xSize[0]>>3) * 4);
00902       memset((char *) &NoiseCb[y][0], 0, (xSize[0]>>3) * 4);
00903       memset((char *) &NoiseCr[y][0], 0, (xSize[0]>>3) * 4);
00904       memset((char *) &SignalCb[y][0], 0, (xSize[0]>>3) * 4);
00905       memset((char *) &SignalCr[y][0], 0, (xSize[0]>>3) * 4);
00906     }
00907   }
00908   
00909   /* find all the signal and noise */
00910   for (y = 0; y < ySize[0]; y++) {
00911     for (x = 0; x < xSize[0]; x++) {
00912       tempInt = (origY[y][x] - newY[y][x]);
00913       NoiseY[y>>4][x>>4] += tempInt*tempInt;
00914       total[0] += (double)abs(tempInt);
00915       tempInt = origY[y][x];
00916       SignalY[y>>4][x>>4] += tempInt*tempInt;
00917     }}
00918   for (y = 0; y < ySize[1]; y++) {
00919     for (x = 0; x < xSize[1]; x ++) {
00920       tempInt = (origCb[y][x] - newCb[y][x]);
00921       NoiseCb[y>>3][x>>3] += tempInt*tempInt;
00922       total[1] += (double)abs(tempInt);
00923       tempInt = origCb[y][x];
00924       SignalCb[y>>3][x>>3] += tempInt*tempInt;
00925       tempInt = (origCr[y][x]-newCr[y][x]);
00926       NoiseCr[y>>3][x>>3] += tempInt*tempInt;
00927       total[2] += (double)abs(tempInt);
00928       tempInt = origCr[y][x];
00929       SignalCr[y>>3][x>>3] += tempInt*tempInt;
00930     }}
00931   
00932   /* Now sum up that noise */
00933   for(y=0; y<Fsize_y>>4; y++){
00934     for(x=0; x<Fsize_x>>4; x++){
00935       varDiff[0] += NoiseY[y][x];
00936       varDiff[1] += NoiseCb[y][x];
00937       varDiff[2] += NoiseCr[y][x];
00938       if (printMSE) printf("%4d ",(int)(NoiseY[y][x]/256.0));
00939     }
00940     if (printMSE) puts("");
00941   }
00942   
00943   /* Now look at those ratios! */
00944   for(y=0; y<Fsize_y>>4; y++){
00945     for(x=0; x<Fsize_x>>4; x++){
00946       ratio[0] += (double)SignalY[y][x]/(double)varDiff[0];
00947       ratio[1] += (double)SignalCb[y][x]/(double)varDiff[1];
00948       ratio[2] += (double)SignalCr[y][x]/(double)varDiff[2];
00949     }}
00950   
00951   for (x=0; x<3; x++) {
00952     snr[x] = 10.0*log10(ratio[x]);
00953     psnr[x] = 20.0*log10(255.0/sqrt((double)varDiff[x]/(double)(ySize[x]*xSize[x])));
00954 
00955     if (! realQuiet) {
00956       fprintf(stdout, "Mean error[%1d]:  %f\n", x, total[x]/(double)(xSize[x]*ySize[x]));
00957     }
00958 
00959   }
00960 }
00961 
00962 void
00963 WriteDecodedFrame(frame)
00964     MpegFrame *frame;
00965 {
00966     FILE    *fpointer;
00967     char    fileName[256];
00968     int width, height;
00969     register int y;
00970 
00971     /* need to save decoded frame to disk because it might be accessed
00972        by another process */
00973 
00974     width = Fsize_x;
00975     height = Fsize_y;
00976 
00977     sprintf(fileName, "%s.decoded.%d", outputFileName, frame->id);
00978 
00979     if (!realQuiet) {
00980         fprintf(stdout, "Outputting to %s\n", fileName);
00981         fflush(stdout);
00982     }
00983 
00984     fpointer = fopen(fileName, "wb");
00985 
00986         for ( y = 0; y < height; y++ ) {
00987             fwrite(frame->decoded_y[y], 1, width, fpointer);
00988         }
00989 
00990         for (y = 0; y < (height >> 1); y++) {                   /* U */
00991             fwrite(frame->decoded_cb[y], 1, width >> 1, fpointer);
00992         }
00993 
00994         for (y = 0; y < (height >> 1); y++) {                   /* V */
00995             fwrite(frame->decoded_cr[y], 1, width >> 1, fpointer);
00996         }
00997     fflush(fpointer);
00998     fclose(fpointer);
00999 }
01000 
01001 
01002 void
01003 PrintItoIBitRate(numBits, frameNum)
01004     int     numBits;
01005     int     frameNum;
01006 {
01007     if ( ( ! childProcess) && showBitRatePerFrame ) {
01008         /* ASSUMES 30 FRAMES PER SECOND */
01009 
01010         if (! realQuiet) {
01011         fprintf(stdout, "I-to-I (frames %5d to %5d) bitrate:  %8d\n",
01012                 lastIFrame, frameNum-1,
01013                 ((numBits-lastNumBits)*30)/
01014                 (frameNum-lastIFrame));
01015         }
01016 
01017         fprintf(bitRateFile, "I-to-I (frames %5d to %5d) bitrate:  %8d\n",
01018                 lastIFrame, frameNum-1,
01019                 ((numBits-lastNumBits)*30)/
01020                 (frameNum-lastIFrame));
01021     }
01022 }
01023 
01024 
01025 /*===========================================================================*
01026  *
01027  * AllocDctBlocks
01028  *
01029  *      allocate memory for dct blocks
01030  *
01031  * RETURNS:     nothing
01032  *
01033  * SIDE EFFECTS:    creates dct, dctr, dctb
01034  *
01035  *===========================================================================*/
01036 void
01037 AllocDctBlocks()
01038 {
01039     int dctx, dcty;
01040     int i;
01041 
01042     dctx = Fsize_x / DCTSIZE;
01043     dcty = Fsize_y / DCTSIZE;
01044 
01045     dct = (Block **) malloc(sizeof(Block *) * dcty);
01046     ERRCHK(dct, "malloc");
01047     for (i = 0; i < dcty; i++) {
01048         dct[i] = (Block *) malloc(sizeof(Block) * dctx);
01049         ERRCHK(dct[i], "malloc");
01050     }
01051 
01052     dct_data = (dct_data_type **) malloc(sizeof(dct_data_type *) * dcty);
01053     ERRCHK(dct_data, "malloc");
01054     for (i = 0; i < dcty; i++) {
01055         dct_data[i] = (dct_data_type *) malloc(sizeof(dct_data_type) * dctx);
01056         ERRCHK(dct[i], "malloc");
01057     }
01058 
01059     dctr = (Block **) malloc(sizeof(Block *) * (dcty >> 1));
01060     dctb = (Block **) malloc(sizeof(Block *) * (dcty >> 1));
01061     ERRCHK(dctr, "malloc");
01062     ERRCHK(dctb, "malloc");
01063     for (i = 0; i < (dcty >> 1); i++) {
01064         dctr[i] = (Block *) malloc(sizeof(Block) * (dctx >> 1));
01065         dctb[i] = (Block *) malloc(sizeof(Block) * (dctx >> 1));
01066         ERRCHK(dctr[i], "malloc");
01067         ERRCHK(dctb[i], "malloc");
01068     }
01069 }
01070 
01071 
01072 /*======================================================================*
01073  *
01074  * time_elapsed
01075  *
01076  *     Handle different time systems on different machines
01077  *
01078  *  RETURNS number of seconds process time used
01079  *
01080  *======================================================================*/
01081 int32 time_elapsed()
01082 {
01083 #ifdef CLOCKS_PER_SEC
01084  /* ANSI C */
01085   TIME_RATE = CLOCKS_PER_SEC;
01086   return (int32) clock();
01087 #else
01088   struct tms   timeBuffer;
01089   TIME_RATE = 60;
01090   times(&timeBuffer);
01091   return timeBuffer.tms_utime + timeBuffer.tms_stime;
01092 #endif
01093 }
01094 
01095 
01096 void
01097 CalcDistortion(current, y, x)
01098 MpegFrame *current;
01099 int y,x;
01100 {
01101 
01102   int qscale, distort=0;
01103   Block decblk;
01104   FlatBlock fblk;
01105   int datarate = 0;
01106   
01107   for (qscale = 1; qscale < 32; qscale ++) {
01108     distort = 0;
01109     datarate = 0;
01110     Mpost_QuantZigBlock(dct[y][x], fblk, qscale, TRUE);
01111     Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
01112     if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
01113     mpeg_jrevdct((int16 *)decblk);
01114     distort += mse(current->y_blocks[y][x], decblk);
01115 
01116     Mpost_QuantZigBlock(dct[y][x+1], fblk, qscale, TRUE);
01117     Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
01118     if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
01119     mpeg_jrevdct((int16 *)decblk);
01120     distort += mse(current->y_blocks[y][x+1], decblk);
01121 
01122     Mpost_QuantZigBlock(dct[y+1][x], fblk, qscale, TRUE);
01123     Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
01124     if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
01125     mpeg_jrevdct((int16 *)decblk);
01126     distort += mse(current->y_blocks[y+1][x], decblk);
01127 
01128     Mpost_QuantZigBlock(dct[y+1][x+1], fblk, qscale, TRUE);
01129     Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
01130     if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
01131     mpeg_jrevdct((int16 *)decblk);
01132     distort += mse(current->y_blocks[y+1][x+1], decblk);
01133 
01134     Mpost_QuantZigBlock(dctb[y >> 1][x >> 1], fblk, qscale, TRUE);
01135     Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
01136     if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
01137     mpeg_jrevdct((int16 *)decblk);
01138     distort += mse(current->cb_blocks[y>>1][x>>1], decblk);
01139 
01140     Mpost_QuantZigBlock(dctr[y >> 1][x >> 1], fblk, qscale, TRUE);
01141     Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
01142     if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
01143     mpeg_jrevdct((int16 *)decblk);
01144     distort += mse(current->cr_blocks[y >> 1][x >> 1], decblk);
01145 
01146     if (!collect_distortion_detailed) {
01147       fprintf(distortion_fp, "\t%d\n", distort);
01148     } else if (collect_distortion_detailed == 1) {
01149       fprintf(distortion_fp, "\t%d\t%d\n", distort, datarate);
01150     } else {
01151       fprintf(fp_table_rate[qscale-1], "%d\n", datarate);
01152       fprintf(fp_table_dist[qscale-1], "%d\n", distort);
01153     }
01154   }
01155 }
01156 
01157 
01158 
01159 
 

Powered by Plone

This site conforms to the following standards: