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  

pframe.c

Go to the documentation of this file.
00001 /*===========================================================================*
00002  * pframe.c                                                                  *
00003  *                                                                           *
00004  *      Procedures concerned with generation of P-frames                     *
00005  *                                                                           *
00006  * EXPORTED PROCEDURES:                                                      *
00007  *      GenPFrame                                                            *
00008  *      ResetPFrameStats                                                     *
00009  *      ShowPFrameSummary                                                    *
00010  *      EstimateSecondsPerPFrame                                             *
00011  *      ComputeHalfPixelData                                                 *
00012  *      SetPQScale                                                           *
00013  *      GetPQScale                                                           *
00014  *                                                                           *
00015  * NOTE:  when motion vectors are passed as arguments, they are passed as    *
00016  *        twice their value.  In other words, a motion vector of (3,4) will  *
00017  *        be passed as (6,8).  This allows half-pixel motion vectors to be   *
00018  *        passed as integers.  This is true throughout the program.          *
00019  *                                                                           *
00020  *===========================================================================*/
00021 
00022 /*
00023  * Copyright (c) 1995 The Regents of the University of California.
00024  * All rights reserved.
00025  *
00026  * Permission to use, copy, modify, and distribute this software and its
00027  * documentation for any purpose, without fee, and without written agreement is
00028  * hereby granted, provided that the above copyright notice and the following
00029  * two paragraphs appear in all copies of this software.
00030  *
00031  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
00032  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
00033  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
00034  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00035  *
00036  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
00037  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
00038  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
00039  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
00040  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
00041  */
00042 
00043 /*  
00044  *  $Header: /misc/elrond0/share/cvs/AFNI/src/mpeg_encodedir/pframe.c,v 1.4 2004/04/02 15:12:41 rwcox Exp $
00045  *  $Log: pframe.c,v $
00046  *  Revision 1.4  2004/04/02 15:12:41  rwcox
00047  *  Cput
00048  *
00049  *  Revision 1.3  2003/12/23 13:50:08  rwcox
00050  *  Cput
00051  *
00052  *  Revision 1.2  2003/12/03 14:46:14  rwcox
00053  *  Cput
00054  *
00055  *  Revision 1.1  2001/12/17 16:11:55  rwcox
00056  *  Cadd
00057  *
00058  *  Revision 1.22  1995/08/07 21:51:23  smoot
00059  *  fixed  LumMotionError call, simpler now with option type
00060  *
00061  *  Revision 1.21  1995/06/21 22:23:16  smoot
00062  *  fixed specifics file bug
00063  *  generalized timeing stuff
00064  *  binary writes
00065  *  TUNEing stuff
00066  *
00067  * Revision 1.20  1995/04/14  23:07:41  smoot
00068  * reorganized to ease rate control experimentation
00069  *
00070  * Revision 1.19  1995/02/24  23:49:27  smoot
00071  * added specifications file format 2
00072  *
00073  * Revision 1.18  1995/02/01  21:48:17  smoot
00074  * cleanup
00075  *
00076  * Revision 1.17  1995/01/23  06:30:01  darryl
00077  * fixed bug in "MMB Type "pattern" and Rate control
00078  *
00079  * Revision 1.15  1995/01/19  23:49:28  smoot
00080  * moved rev_dct, make pattern changable by ComputeDiffDCTs
00081  *
00082  * Revision 1.14  1995/01/19  23:09:07  eyhung
00083  * Changed copyrights
00084  *
00085  * Revision 1.13  1995/01/19  23:00:26  smoot
00086  * Fixed 1st/last MB in slice color bug in P-frames
00087  *
00088  * Revision 1.12  1995/01/17  22:10:27  smoot
00089  * Fixed B/P Qscale bug
00090  *
00091  * Revision 1.11  1995/01/16  08:14:41  eyhung
00092  * added realQuiet
00093  *
00094  * Revision 1.10  1994/12/07  00:40:36  smoot
00095  * Added seperate P and B search ranges
00096  *
00097  * Revision 1.9  1994/11/14  22:38:18  smoot
00098  * merged specifics and rate control
00099  *
00100  * Revision 1.8  1994/11/01  05:01:09  darryl
00101  *  with rate control changes added
00102  *
00103  * Revision 2.1  1994/10/31  00:05:39  darryl
00104  * version before, hopefully, final changes
00105  *
00106  * Revision 2.0  1994/10/24  02:38:26  darryl
00107  * will be adding the experiment code
00108  *
00109  * Revision 1.1  1994/09/27  00:15:44  darryl
00110  * Initial revision
00111  *
00112  * Revision 1.7  1994/03/15  00:27:11  keving
00113  * nothing
00114  *
00115  * Revision 1.6  1993/12/22  19:19:01  keving
00116  * nothing
00117  *
00118  * Revision 1.5  1993/07/22  22:23:43  keving
00119  * nothing
00120  *
00121  * Revision 1.4  1993/06/30  20:06:09  keving
00122  * nothing
00123  *
00124  * Revision 1.3  1993/06/03  21:08:08  keving
00125  * nothing
00126  *
00127  * Revision 1.2  1993/03/02  23:03:42  keving
00128  * nothing
00129  *
00130  * Revision 1.1  1993/02/19  19:14:12  keving
00131  * nothing
00132  *
00133  */
00134 
00135 
00136 /*==============*
00137  * HEADER FILES *
00138  *==============*/
00139 
00140 #include <assert.h>
00141 #include <sys/param.h>
00142 #include "all.h"
00143 #include "mtypes.h"
00144 #include "bitio.h"
00145 #include "frames.h"
00146 #include "prototypes.h"
00147 #include "param.h"
00148 #include "mheaders.h"
00149 #include "fsize.h"
00150 #include "postdct.h"
00151 #include "mpeg.h"
00152 #include "parallel.h"
00153 #include "rate.h"
00154 #include "opts.h"
00155 
00156 /*==================*
00157  * STATIC VARIABLES *
00158  *==================*/
00159 
00160 static int32    zeroDiff;
00161 static int      numPIBlocks = 0;
00162 static int      numPPBlocks = 0;
00163 static int      numPSkipped = 0;
00164 static int      numPIBits = 0;
00165 static int      numPPBits = 0;
00166 static int      numFrames = 0;
00167 static int      numFrameBits = 0;
00168 static int32    totalTime = 0;
00169 static int      qscaleP;
00170 static float    totalSNR = 0.0;
00171 static float    totalPSNR = 0.0;
00172 extern Block    **dct, **dctr, **dctb;
00173 extern dct_data_type   **dct_data;
00174 
00175 /*===============================*
00176  * INTERNAL PROCEDURE prototypes *
00177  *===============================*/
00178 
00179 static boolean  ZeroMotionBetter _ANSI_ARGS_((LumBlock currentBlock,
00180                                               MpegFrame *prev, int by, int bx,
00181                                               int my, int mx));
00182 
00183 static boolean  DoIntraCode _ANSI_ARGS_((LumBlock currentBlock,
00184                                          MpegFrame *prev, int by, int bx,
00185                                          int motionY, int motionX));
00186 
00187 static boolean  ZeroMotionSufficient _ANSI_ARGS_((LumBlock currentBlock,
00188                                                   MpegFrame *prev,
00189                                                   int by, int bx));
00190      
00191 #ifdef BLEAH
00192 static void     ComputeAndPrintPframeMAD _ANSI_ARGS_((LumBlock currentBlock,
00193                                                       MpegFrame *prev,
00194                                                       int by, int bx,
00195                                                       int my, int mx,
00196                                                       int numBlock));
00197 #endif
00198      
00199     
00200 /*=====================*
00201  * EXPORTED PROCEDURES *
00202  *=====================*/
00203 
00204 /*===========================================================================*
00205  *
00206  * GenPFrame
00207  *
00208  *      generate a P-frame from previous frame, adding the result to the
00209  *      given bit bucket
00210  *
00211  * RETURNS:     frame appended to bb
00212  *
00213  * SIDE EFFECTS:    none
00214  *
00215  *===========================================================================*/
00216 void
00217   GenPFrame(bb, current, prev)
00218 BitBucket *bb;
00219 MpegFrame *current;
00220 MpegFrame *prev;
00221 {
00222   extern int **pmvHistogram;
00223   FlatBlock fba[6], fb[6];
00224   Block dec[6];
00225   int32 y_dc_pred, cr_dc_pred, cb_dc_pred;
00226   int x, y;
00227   int   motionX = 0, motionY = 0;
00228   int   oldMotionX = 0, oldMotionY = 0;
00229   int   offsetX, offsetY;
00230   int   tempX, tempY;
00231   int   motionXrem, motionXquot;
00232   int   motionYrem, motionYquot;
00233   int   pattern;
00234   int   mbAddrInc = 1;
00235   boolean       useMotion;
00236   int numIBlocks = 0;
00237   int   numPBlocks = 0;
00238   int   numSkipped = 0;
00239   int   numIBits = 0;
00240   int numPBits = 0;
00241   int totalBits;
00242   int   totalFrameBits;
00243   int32    startTime, endTime;
00244   int   lastBlockX, lastBlockY;
00245   int   lastX, lastY;
00246   int   fy, fx;
00247   LumBlock currentBlock;
00248   register int ix, iy;
00249   int   mbAddress;
00250   int slicePos;
00251   register int index;
00252   float   snr[3], psnr[3];
00253   int QScale;
00254   BlockMV *info;
00255   int bitstreamMode, newQScale;
00256   int rc_blockStart = 0;
00257   boolean overflowChange = FALSE;
00258   int     overflowValue  = 0;
00259 
00260 
00261   if (collect_quant) {fprintf(collect_quant_fp, "# P\n");}
00262   if (dct==NULL) AllocDctBlocks();
00263   numFrames++;
00264   totalFrameBits = bb->cumulativeBits;
00265   startTime = time_elapsed();
00266 
00267   DBG_PRINT(("Generating pframe\n"));
00268 
00269   QScale = GetPQScale();
00270   /*   bit allocation for rate control purposes */
00271   bitstreamMode = getRateMode();
00272   if (bitstreamMode == FIXED_RATE) {
00273     targetRateControl(current);
00274   }
00275  
00276   Mhead_GenPictureHeader(bb, P_FRAME, current->id, fCodeP);
00277   /* Check for Qscale change */  
00278   if (specificsOn) {
00279     /* Set a Qscale for this frame? */
00280     newQScale = SpecLookup(current->id, 0, 0 /* junk */, &info /*junk*/, QScale);
00281     if (newQScale != -1) {
00282       QScale = newQScale;
00283     }
00284     /* Set for slice? */
00285     newQScale = SpecLookup(current->id, 1, 1, &info /*junk*/, QScale);
00286     if (newQScale != -1) {
00287       QScale = newQScale;
00288     }
00289   }
00290 
00291   DBG_PRINT(("Slice Header\n"));
00292   Mhead_GenSliceHeader(bb, 1, QScale, NULL, 0);
00293 
00294   if ( referenceFrame == DECODED_FRAME ) {
00295     Frame_AllocDecoded(current, TRUE);
00296   } else if ( printSNR ) {
00297     Frame_AllocDecoded(current, FALSE);
00298   }
00299 
00300   /* don't do dct on blocks yet */
00301   Frame_AllocBlocks(current);
00302   BlockifyFrame(current);
00303 
00304   /* for I-blocks */
00305   y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
00306 
00307   totalBits = bb->cumulativeBits;
00308 
00309   if ( (! pixelFullSearch) && (! prev->halfComputed) ) {
00310     ComputeHalfPixelData(prev);
00311   }
00312 
00313   lastBlockX = Fsize_x>>3;
00314   lastBlockY = Fsize_y>>3;
00315   lastX = lastBlockX-2;
00316   lastY = lastBlockY-2;
00317   mbAddress = 0;
00318 
00319   /* First loop though finding motion/not and DCTing */
00320   for (y = 0; y < lastBlockY; y += 2) {
00321     for (x = 0; x < lastBlockX; x += 2) {
00322       /* compute currentBlock */
00323       BLOCK_TO_FRAME_COORD(y, x, fy, fx);
00324       for ( iy = 0; iy < 16; iy++ ) {
00325         for ( ix = 0; ix < 16; ix++ ) {
00326           currentBlock[iy][ix] = (int16)current->orig_y[fy+iy][fx+ix];
00327         }
00328       }
00329 
00330       /* See if we have a cached answer */
00331       if (specificsOn) {
00332         (void) SpecLookup(current->id, 2, mbAddress, &info, QScale);
00333         if (info != (BlockMV*)NULL) {
00334           if (info->typ == TYP_SKIP) {
00335             motionX = motionY = 0;
00336             useMotion = TRUE;
00337             goto no_search;
00338           } else {              /* assume P, since we're a P frame.... */
00339             motionX = info->fx;
00340             motionY = info->fy;
00341             useMotion = TRUE;
00342             goto no_search;
00343           }}
00344         /* if unspecified, just look */
00345       }
00346 
00347       /* see if we should use motion vectors, and if so, what those
00348        * vectors should be
00349        */
00350       if ( ZeroMotionSufficient(currentBlock, prev, y, x) ) {
00351         motionX = 0;
00352         motionY = 0;
00353         useMotion = TRUE;
00354       } else {
00355         useMotion = PMotionSearch(currentBlock, prev, y, x,
00356                                   &motionY, &motionX);
00357         if ( useMotion ) {
00358           if ( ZeroMotionBetter(currentBlock, prev, y, x, motionY,
00359                                 motionX) ) {
00360             motionX = 0;
00361             motionY = 0;
00362           }
00363           if (IntraPBAllowed) 
00364             useMotion = (! DoIntraCode(currentBlock, prev, y, x,
00365                                        motionY, motionX));
00366         }
00367       }
00368 
00369     no_search:
00370 
00371       dct_data[y][x].useMotion = useMotion;
00372       if ( ! useMotion ) {
00373         /* output I-block inside a P-frame */
00374         numIBlocks++;
00375 
00376         /* calculate forward dct's */
00377         if (collect_quant && (collect_quant_detailed & 1)) fprintf(collect_quant_fp, "l\n");
00378         mp_fwd_dct_block2(current->y_blocks[y][x], dct[y][x]);
00379         mp_fwd_dct_block2(current->y_blocks[y][x+1], dct[y][x+1]);
00380         mp_fwd_dct_block2(current->y_blocks[y+1][x], dct[y+1][x]);
00381         mp_fwd_dct_block2(current->y_blocks[y+1][x+1], dct[y+1][x+1]);
00382         if (collect_quant && (collect_quant_detailed & 1)) fprintf(collect_quant_fp, "c\n");
00383         mp_fwd_dct_block2(current->cb_blocks[y>>1][x>>1], dctb[y>>1][x>>1]);
00384         mp_fwd_dct_block2(current->cr_blocks[y>>1][x>>1], dctr[y>>1][x>>1]);
00385 
00386       } else {
00387         /* USE MOTION VECTORS */
00388         numPBlocks++;
00389 
00390         pattern = 63;
00391         ComputeDiffDCTs(current, prev, y, x, motionY, motionX,
00392                         &pattern);
00393 
00394         assert(motionX+searchRangeP+1 >= 0);
00395         assert(motionY+searchRangeP+1 >= 0);
00396 
00397 #ifdef BLEAH
00398         if ( motionX+searchRangeP+1 > 2*searchRangeP+2 )
00399           {
00400             fprintf(stdout, "motionX = %d, searchRangeP = %d\n",
00401                     motionX, searchRangeP);
00402           }
00403 #endif
00404 
00405         if ( computeMVHist ) {
00406           assert(motionX+searchRangeP+1 <= 2*searchRangeP+2);
00407           assert(motionY+searchRangeP+1 <= 2*searchRangeP+2);
00408           pmvHistogram[motionX+searchRangeP+1][motionY+searchRangeP+1]++;
00409         }
00410         /* Save specs for next loops */
00411         dct_data[y][x].pattern = pattern;
00412         dct_data[y][x].fmotionX = motionX;
00413         dct_data[y][x].fmotionY = motionY;
00414 
00415       }
00416       mbAddress++;
00417     }}
00418 
00419   mbAddress = 0;
00420   for (y = 0; y < lastBlockY; y += 2) {
00421     for (x = 0; x < lastBlockX; x += 2) {
00422       slicePos = (mbAddress % blocksPerSlice);
00423 
00424       if ( (slicePos == 0) && (mbAddress != 0) ) {
00425         if (specificsOn) {
00426           /* Make sure no slice Qscale change */
00427           newQScale = SpecLookup(current->id, 1, mbAddress/blocksPerSlice,
00428                                  &info /*junk*/, QScale);
00429           if (newQScale != -1) QScale = newQScale;
00430         }
00431 
00432         Mhead_GenSliceEnder(bb);
00433         Mhead_GenSliceHeader(bb, 1+(y>>1), QScale, NULL, 0);
00434 
00435         /* reset everything */
00436         oldMotionX = 0;         oldMotionY = 0;
00437         y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
00438 
00439         mbAddrInc = 1+(x>>1);
00440       }
00441             
00442       /*  Determine if new Qscale needed for Rate Control purposes  */
00443       if (bitstreamMode == FIXED_RATE) {
00444         rc_blockStart =  bb->cumulativeBits;
00445         newQScale = needQScaleChange(qscaleP,
00446                                      current->y_blocks[y][x],
00447                                      current->y_blocks[y][x+1],
00448                                      current->y_blocks[y+1][x],
00449                                      current->y_blocks[y+1][x+1]);
00450         if (newQScale > 0) {
00451           QScale = newQScale;
00452         }
00453       }
00454             
00455       /* Check for Qscale change */
00456       if (specificsOn) {
00457         newQScale = SpecLookup(current->id, 2, mbAddress, &info, QScale);
00458         if (newQScale != -1) {
00459           QScale = newQScale;
00460         }
00461       }
00462 
00463       if (! dct_data[y][x].useMotion) {
00464         GEN_I_BLOCK(P_FRAME, current, bb, mbAddrInc, QScale);
00465         mbAddrInc = 1;
00466 
00467         numIBits += (bb->cumulativeBits-totalBits);
00468         totalBits = bb->cumulativeBits;
00469 
00470         /* reset because intra-coded */
00471         oldMotionX = 0;         oldMotionY = 0;
00472 
00473         if ( decodeRefFrames ) {
00474           /* need to decode block we just encoded */
00475           Mpost_UnQuantZigBlock(fb[0], dec[0], QScale, TRUE);
00476           Mpost_UnQuantZigBlock(fb[1], dec[1], QScale, TRUE);
00477           Mpost_UnQuantZigBlock(fb[2], dec[2], QScale, TRUE);
00478           Mpost_UnQuantZigBlock(fb[3], dec[3], QScale, TRUE);
00479           Mpost_UnQuantZigBlock(fb[4], dec[4], QScale, TRUE);
00480           Mpost_UnQuantZigBlock(fb[5], dec[5], QScale, TRUE);
00481 
00482           /* now, reverse the DCT transform */
00483           for ( index = 0; index < 6; index++ ) {
00484             mpeg_jrevdct((int16 *)dec[index]);
00485           }
00486 
00487           /* now, unblockify */
00488           BlockToData(current->decoded_y, dec[0], y, x);
00489           BlockToData(current->decoded_y, dec[1], y, x+1);
00490           BlockToData(current->decoded_y, dec[2], y+1, x);
00491           BlockToData(current->decoded_y, dec[3], y+1, x+1);
00492           BlockToData(current->decoded_cb, dec[4], y>>1, x>>1);
00493           BlockToData(current->decoded_cr, dec[5], y>>1, x>>1);
00494         }
00495       } else {
00496         int fCode = fCodeP;
00497 
00498         /* reset because non-intra-coded */
00499         y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
00500 
00501         pattern = dct_data[y][x].pattern;
00502         motionX = dct_data[y][x].fmotionX;
00503         motionY = dct_data[y][x].fmotionY;
00504 
00505 #ifdef BLEAH
00506         ComputeAndPrintPframeMAD(currentBlock, prev, y, x, motionY, motionX, mbAddress);
00507 #endif
00508 
00509         if ( pixelFullSearch ) { /* should be even */
00510           motionY /= 2;
00511           motionX /= 2;
00512         }
00513 
00514         /* transform the motion vector into the appropriate values */
00515         offsetX = motionX - oldMotionX;
00516         offsetY = motionY - oldMotionY;
00517 /*      if ((offsetX+(8*x)) >= (Fsize_x-8)) log(10.0); */
00518         ENCODE_MOTION_VECTOR(offsetX, offsetY, motionXquot,
00519                              motionYquot, motionXrem, motionYrem,
00520                              FORW_F);
00521 
00522 #ifdef BLEAH
00523         if ( (motionX != 0) || (motionY != 0) ) {
00524           fprintf(stdout, "FRAME (y, x)  %d, %d (block %d)\n", y, x, mbAddress);
00525           fprintf(stdout, "motionX = %d, motionY = %d\n", motionX, motionY);
00526           fprintf(stdout, "    mxq, mxr = %d, %d    myq, myr = %d, %d\n",
00527                   motionXquot, motionXrem, motionYquot, motionYrem);
00528         }
00529 #endif
00530 
00531         oldMotionX = motionX;
00532         oldMotionY = motionY;
00533 
00534         if ( pixelFullSearch ) { /* reset for use with PMotionSearch */
00535           motionY *= 2;
00536           motionX *= 2;
00537         }
00538         calc_blocks:
00539         /* create flat blocks and update pattern if necessary */
00540         /* Note DoQuant references QScale, overflowChange, overflowValue,
00541            pattern, and the calc_blocks label                 */
00542           DoQuant(0x20, dct[y][x], fba[0]);
00543           DoQuant(0x10, dct[y][x+1], fba[1]);
00544           DoQuant(0x08, dct[y+1][x], fba[2]);
00545           DoQuant(0x04, dct[y+1][x+1], fba[3]);
00546           DoQuant(0x02, dctb[y>>1][x>>1], fba[4]);
00547           DoQuant(0x01, dctr[y>>1][x>>1], fba[5]);
00548 
00549         if ( decodeRefFrames) {
00550           for ( index = 0; index < 6; index++ ) {
00551             if ( pattern & (1 << (5-index))) {
00552               Mpost_UnQuantZigBlock(fba[index], dec[index], QScale, FALSE);
00553               mpeg_jrevdct((int16 *)dec[index]);
00554             } else {
00555               memset((char *)dec[index], 0, sizeof(Block));
00556             }
00557           }
00558 
00559           /* now add the motion block */
00560           AddMotionBlock(dec[0], prev->decoded_y, y, x, motionY, motionX);
00561           AddMotionBlock(dec[1], prev->decoded_y, y, x+1, motionY, motionX);
00562           AddMotionBlock(dec[2], prev->decoded_y, y+1, x, motionY, motionX);
00563           AddMotionBlock(dec[3], prev->decoded_y, y+1, x+1, motionY, motionX);
00564           AddMotionBlock(dec[4], prev->decoded_cb, y>>1, x>>1, motionY/2, motionX/2);
00565           AddMotionBlock(dec[5], prev->decoded_cr, y>>1, x>>1, motionY/2, motionX/2);
00566 
00567           /* now, unblockify */
00568           BlockToData(current->decoded_y, dec[0], y, x);
00569           BlockToData(current->decoded_y, dec[1], y, x+1);
00570           BlockToData(current->decoded_y, dec[2], y+1, x);
00571           BlockToData(current->decoded_y, dec[3], y+1, x+1);
00572           BlockToData(current->decoded_cb, dec[4], y>>1, x>>1);
00573           BlockToData(current->decoded_cr, dec[5], y>>1, x>>1);
00574         } 
00575 
00576         if ( (motionX == 0) && (motionY == 0) ) {
00577           if ( pattern == 0 ) {
00578             /* can only skip if:
00579              *     1)  not the last block in frame
00580              *     2)  not the last block in slice
00581              *     3)  not the first block in slice
00582              */
00583 
00584             if ( ((y < lastY) || (x < lastX)) &&
00585                 (slicePos+1 != blocksPerSlice) &&
00586                 (slicePos != 0) ) {
00587               mbAddrInc++;      /* skipped macroblock */
00588               numSkipped++;
00589               numPBlocks--;
00590             } else {            /* first/last macroblock */
00591               Mhead_GenMBHeader(bb, 2 /* pict_code_type */, mbAddrInc /* addr_incr */,
00592                                 QScale /* q_scale */,
00593                                 fCode /* forw_f_code */, 1 /* back_f_code */,
00594                                 motionXrem /* horiz_forw_r */, motionYrem /* vert_forw_r */,
00595                                 0 /* horiz_back_r */, 0 /* vert_back_r */,
00596                                 1 /* motion_forw */, motionXquot /* m_horiz_forw */,
00597                                 motionYquot /* m_vert_forw */, 0 /* motion_back */,
00598                                 0 /* m_horiz_back */, 0 /* m_vert_back */,
00599                                 0 /* mb_pattern */, 0 /* mb_intra */);
00600               mbAddrInc = 1;
00601             }
00602           } else {
00603             DBG_PRINT(("MB Header(%d,%d)\n", x, y));
00604             Mhead_GenMBHeader(bb, 2 /* pict_code_type */, mbAddrInc /* addr_incr */,
00605                               QScale /* q_scale */,
00606                               fCode /* forw_f_code */, 1 /* back_f_code */,
00607                               0 /* horiz_forw_r */, 0 /* vert_forw_r */,
00608                               0 /* horiz_back_r */, 0 /* vert_back_r */,
00609                               0 /* motion_forw */, 0 /* m_horiz_forw */,
00610                               0 /* m_vert_forw */, 0 /* motion_back */,
00611                               0 /* m_horiz_back */, 0 /* m_vert_back */,
00612                               pattern /* mb_pattern */, 0 /* mb_intra */);
00613             mbAddrInc = 1;
00614           }
00615         } else {
00616           /*      DBG_PRINT(("MB Header(%d,%d)\n", x, y));  */
00617                   
00618           Mhead_GenMBHeader(bb, 2 /* pict_code_type */, mbAddrInc /* addr_incr */,
00619                             QScale /* q_scale */,
00620                             fCode /* forw_f_code */, 1 /* back_f_code */,
00621                             motionXrem /* horiz_forw_r */, motionYrem /* vert_forw_r */,
00622                             0   /* horiz_back_r */, 0 /* vert_back_r */,
00623                             1   /* motion_forw */, motionXquot /* m_horiz_forw */,
00624                             motionYquot /* m_vert_forw */, 0 /* motion_back */,
00625                             0   /* m_horiz_back */, 0 /* m_vert_back */,
00626                             pattern /* mb_pattern */, 0 /* mb_intra */);
00627           mbAddrInc = 1;
00628         }
00629 
00630         /* now output the difference */
00631         for ( tempX = 0; tempX < 6; tempX++ ) {
00632           if ( GET_ITH_BIT(pattern, 5-tempX) ) {
00633             Mpost_RLEHuffPBlock(fba[tempX], bb);
00634           }
00635         }
00636 
00637         numPBits += (bb->cumulativeBits-totalBits);
00638         totalBits = bb->cumulativeBits;
00639       }
00640 
00641       if (overflowChange) {
00642         /* undo an overflow-caused Qscale change */
00643         overflowChange = FALSE;
00644         QScale -= overflowValue;
00645         overflowValue = 0;
00646       }
00647 
00648       mbAddress++;
00649       /*   Rate Control  */
00650       if (bitstreamMode == FIXED_RATE) {
00651         incMacroBlockBits( bb->cumulativeBits- rc_blockStart);
00652         rc_blockStart = bb->cumulativeBits;
00653         MB_RateOut(TYPE_PFRAME);
00654       }
00655     }
00656   }
00657 
00658   if ( printSNR ) {
00659     BlockComputeSNR(current,snr,psnr);
00660     totalSNR += snr[0];
00661     totalPSNR += psnr[0];
00662   }
00663 
00664 #ifdef BLEAHBLEAH
00665   {
00666     FILE *filePtr;
00667 
00668     filePtr = fopen("PFRAME.yuv", "wb");
00669 
00670     for ( y = 0; y < Fsize_y; y++ )
00671       {
00672         for ( x = 0; x < Fsize_x; x++ )
00673           fprintf(filePtr, "%d ", current->decoded_y[y][x]);
00674         fprintf(filePtr, "\n");
00675       }
00676 
00677     fclose(filePtr);
00678   }
00679 #endif
00680 
00681   Mhead_GenSliceEnder(bb);
00682   /*   Rate Control */
00683   if (bitstreamMode == FIXED_RATE) {
00684     updateRateControl(TYPE_PFRAME);
00685   }
00686 
00687   /* UPDATE STATISTICS */
00688   endTime = time_elapsed();
00689   totalTime += (endTime-startTime);
00690 
00691   if ( ( ! childProcess) && showBitRatePerFrame ) {
00692     /* ASSUMES 30 FRAMES PER SECOND */
00693     fprintf(bitRateFile, "%5d\t%8d\n", current->id,
00694             30*(bb->cumulativeBits-totalFrameBits));
00695   }
00696 
00697   if ( (! childProcess) && frameSummary && (! realQuiet) ) {
00698     fprintf(stdout, "FRAME %d (P):  I BLOCKS:  %d;  P BLOCKS:  %d   SKIPPED:  %d  (%ld seconds)\n",
00699             current->id, numIBlocks, numPBlocks, numSkipped, (long)(endTime-startTime)/TIME_RATE);
00700     if ( printSNR ) {
00701       fprintf(stdout, "FRAME %d:  SNR:  %.1f\t%.1f\t%.1f\tPSNR:  %.1f\t%.1f\t%.1f\n",
00702               current->id, snr[0], snr[1], snr[2],
00703               psnr[0], psnr[1], psnr[2]);
00704     }
00705   }
00706 
00707   numFrameBits += (bb->cumulativeBits-totalFrameBits);
00708   numPIBlocks += numIBlocks;
00709   numPPBlocks += numPBlocks;
00710   numPSkipped += numSkipped;
00711   numPIBits += numIBits;
00712   numPPBits += numPBits;
00713 
00714   if ( (referenceFrame == DECODED_FRAME) && NonLocalRefFrame(current->id) ) {
00715     if ( remoteIO ) {
00716       SendDecodedFrame(current);
00717     } else {
00718       WriteDecodedFrame(current);
00719     }
00720 
00721     NotifyDecodeServerReady(current->id);
00722   }
00723 }
00724 
00725 
00726 /*===========================================================================*
00727  *
00728  * ResetPFrameStats
00729  *
00730  *      reset the P-frame statistics
00731  *
00732  * RETURNS:     nothing
00733  *
00734  * SIDE EFFECTS:    none
00735  *
00736  *===========================================================================*/
00737 void
00738   ResetPFrameStats()
00739 {
00740   numPIBlocks = 0;
00741   numPPBlocks = 0;
00742   numPSkipped = 0;
00743   numPIBits = 0;
00744   numPPBits = 0;
00745   numFrames = 0;
00746   numFrameBits = 0;
00747   totalTime = 0;
00748 }
00749 
00750 
00751 /*===========================================================================*
00752  *
00753  * SetPQScale
00754  *
00755  *      set the P-frame Q-scale
00756  *
00757  * RETURNS:     nothing
00758  *
00759  * SIDE EFFECTS:    qscaleP
00760  *
00761  *===========================================================================*/
00762 void
00763   SetPQScale(qP)
00764 int qP;
00765 {
00766   qscaleP = qP;
00767 }
00768 
00769 
00770 /*===========================================================================*
00771  *
00772  * GetPQScale
00773  *
00774  *      return the P-frame Q-scale
00775  *
00776  * RETURNS:     the P-frame Q-scale
00777  *
00778  * SIDE EFFECTS:    none
00779  *
00780  *===========================================================================*/
00781 int
00782   GetPQScale()
00783 {
00784   return qscaleP;
00785 }
00786 
00787 
00788 /*===========================================================================*
00789  *
00790  * ShowPFrameSummary
00791  *
00792  *      print a summary of information on encoding P-frames
00793  *
00794  * RETURNS:     time taken for P-frames (in seconds)
00795  *
00796  * SIDE EFFECTS:    none
00797  *
00798  *===========================================================================*/
00799 float
00800   ShowPFrameSummary(inputFrameBits, totalBits, fpointer)
00801 int inputFrameBits;
00802 int32 totalBits;
00803 FILE *fpointer;
00804 {
00805   if ( numFrames == 0 ) {
00806     return 0.0;
00807   }
00808 
00809   fprintf(fpointer, "-------------------------\n");
00810   fprintf(fpointer, "*****P FRAME SUMMARY*****\n");
00811   fprintf(fpointer, "-------------------------\n");
00812 
00813   if ( numPIBlocks != 0 ) {
00814     fprintf(fpointer, "  I Blocks:  %5d     (%6d bits)     (%5d bpb)\n",
00815             numPIBlocks, numPIBits, numPIBits/numPIBlocks);
00816   } else {
00817     fprintf(fpointer, "  I Blocks:  %5d\n", 0);
00818   }
00819 
00820   if ( numPPBlocks != 0 ) {
00821     fprintf(fpointer, "  P Blocks:  %5d     (%6d bits)     (%5d bpb)\n",
00822             numPPBlocks, numPPBits, numPPBits/numPPBlocks);
00823   } else {
00824     fprintf(fpointer, "  P Blocks:  %5d\n", 0);
00825   }
00826 
00827   fprintf(fpointer, "  Skipped:   %5d\n", numPSkipped);
00828 
00829   fprintf(fpointer, "  Frames:    %5d     (%6d bits)     (%5d bpf)     (%2.1f%% of total)\n",
00830           numFrames, numFrameBits, numFrameBits/numFrames,
00831           100.0*(float)numFrameBits/(float)totalBits);
00832   fprintf(fpointer, "  Compression:  %3d:1     (%9.4f bpp)\n",
00833           numFrames*inputFrameBits/numFrameBits,
00834           24.0*(float)numFrameBits/(float)(numFrames*inputFrameBits));
00835   if ( printSNR )
00836     fprintf(fpointer, "  Avg Y SNR/PSNR:  %.1f     %.1f\n",
00837             totalSNR/(float)numFrames, totalPSNR/(float)numFrames);
00838   if ( totalTime == 0 ) {
00839     fprintf(fpointer, "  Seconds:  NONE\n");
00840   } else {
00841     fprintf(fpointer, "  Seconds:  %9ld     (%9.4f fps)  (%9ld pps)  (%9ld mps)\n",
00842             (long)(totalTime/TIME_RATE),
00843             (float)((float)(TIME_RATE*numFrames)/(float)totalTime),
00844             (long)((float)TIME_RATE*(float)numFrames*(float)inputFrameBits/(24.0*(float)totalTime)),
00845             (long)((float)TIME_RATE*(float)numFrames*(float)inputFrameBits/(256.0*24.0*(float)totalTime)));
00846   }
00847 
00848   return (float)totalTime/(float)TIME_RATE;
00849 }
00850 
00851 
00852 /*===========================================================================*
00853  *
00854  * EstimateSecondsPerPFrame
00855  *
00856  *      compute an estimate of the number of seconds required per P-frame
00857  *
00858  * RETURNS:     the estimate, in seconds
00859  *
00860  * SIDE EFFECTS:    none
00861  *
00862  *===========================================================================*/
00863 float
00864   EstimateSecondsPerPFrame()
00865 {
00866   if ( numFrames == 0 ) {
00867     return 10.0;
00868   } else {
00869     return (float)totalTime/((float)TIME_RATE*(float)numFrames);
00870   }
00871 }
00872 
00873 
00874 /*===========================================================================*
00875  *
00876  * ComputeHalfPixelData
00877  *
00878  *      compute all half-pixel data required for half-pixel motion vector
00879  *      search (luminance only)
00880  *
00881  * RETURNS:     frame->halfX, ->halfY, and ->halfBoth modified
00882  *
00883  * SIDE EFFECTS:    none
00884  *
00885  *===========================================================================*/
00886 void
00887   ComputeHalfPixelData(frame)
00888 MpegFrame *frame;
00889 {
00890   register int x, y;
00891 
00892   /* we add 1 before dividing by 2 because .5 is supposed to be rounded up
00893    * (see MPEG-1, page D-31)
00894    */
00895 
00896   if ( frame->halfX == NULL ) { /* need to allocate memory */
00897     Frame_AllocHalf(frame);
00898   }
00899 
00900   /* compute halfX */
00901   for ( y = 0; y < Fsize_y; y++ ) {
00902     for ( x = 0; x < Fsize_x-1; x++ ) {
00903       frame->halfX[y][x] = (frame->ref_y[y][x]+
00904                             frame->ref_y[y][x+1]+1)>>1;
00905     }
00906   }
00907 
00908   /* compute halfY */
00909   for ( y = 0; y < Fsize_y-1; y++ ) {
00910     for ( x = 0; x < Fsize_x; x++ ) {
00911       frame->halfY[y][x] = (frame->ref_y[y][x]+
00912                             frame->ref_y[y+1][x]+1)>>1;
00913     }
00914   }
00915 
00916   /* compute halfBoth */
00917   for ( y = 0; y < Fsize_y-1; y++ ) {
00918     for ( x = 0; x < Fsize_x-1; x++ ) {
00919       frame->halfBoth[y][x] = (frame->ref_y[y][x]+
00920                                frame->ref_y[y][x+1]+
00921                                frame->ref_y[y+1][x]+
00922                                frame->ref_y[y+1][x+1]+2)>>2;
00923     }
00924   }
00925 
00926   frame->halfComputed = TRUE;
00927 }
00928 
00929 
00930 /*=====================*
00931  * INTERNAL PROCEDURES *
00932  *=====================*/
00933 
00934 /*===========================================================================*
00935  *
00936  *                            USER-MODIFIABLE
00937  *
00938  * ZeroMotionBetter
00939  *
00940  *      decide if (0,0) motion is better than the given motion vector
00941  *
00942  * RETURNS:     TRUE if (0,0) is better, FALSE if (my,mx) is better
00943  *
00944  * SIDE EFFECTS:    none
00945  *
00946  * PRECONDITIONS:       The relevant block in 'current' is valid (it has not
00947  *                      been dct'd).  'zeroDiff' has already been computed
00948  *                      as the LumMotionError() with (0,0) motion
00949  *
00950  * NOTES:       This procedure follows the algorithm described on
00951  *              page D-48 of the MPEG-1 specification
00952  *
00953  *===========================================================================*/
00954 static boolean
00955 ZeroMotionBetter(currentBlock, prev, by, bx, my, mx)
00956     LumBlock currentBlock;
00957     MpegFrame *prev;
00958     int by;
00959     int bx;
00960     int my;
00961     int mx;
00962 {
00963     int bestDiff;
00964     int CompareMode;
00965 
00966     /* Junk needed to adapt for TUNEing */ 
00967     CompareMode = SearchCompareMode;
00968     SearchCompareMode = DEFAULT_SEARCH;
00969     bestDiff = LumMotionError(currentBlock, prev, by, bx, my, mx, 0x7fffffff);
00970     SearchCompareMode = CompareMode;
00971 
00972     if ( zeroDiff < 256*3 ) {
00973         if ( 2*bestDiff >= zeroDiff ) {
00974             return TRUE;
00975         }
00976     } else {
00977         if ( 11*bestDiff >= 10*zeroDiff ) {
00978             return TRUE;
00979         }
00980     }
00981 
00982     return FALSE;
00983 }
00984 
00985 
00986 /*===========================================================================*
00987  *
00988  *                            USER-MODIFIABLE
00989  *
00990  * DoIntraCode
00991  *
00992  *      decide if intra coding is necessary
00993  *
00994  * RETURNS:     TRUE if intra-block coding is better; FALSE if not
00995  *
00996  * SIDE EFFECTS:    none
00997  *
00998  * PRECONDITIONS:       The relevant block in 'current' is valid (it has not
00999  *                      been dct'd).
01000  *
01001  * NOTES:       This procedure follows the algorithm described on
01002  *              page D-49 of the MPEG-1 specification
01003  *
01004  *===========================================================================*/
01005 static boolean
01006 DoIntraCode(currentBlock, prev, by, bx, motionY, motionX)
01007     LumBlock currentBlock;
01008     MpegFrame *prev;
01009     int by;
01010     int bx;
01011     int motionY;
01012     int motionX;
01013 {
01014     int     x, y;
01015     int32 sum = 0, vard = 0, varc = 0, dif;
01016     int32 currPixel, prevPixel;
01017     LumBlock    motionBlock;
01018 
01019     ComputeMotionLumBlock(prev, by, bx, motionY, motionX, motionBlock);
01020 
01021     for ( y = 0; y < 16; y++ ) {
01022         for ( x = 0; x < 16; x++ ) {
01023             currPixel = currentBlock[y][x];
01024             prevPixel = motionBlock[y][x];
01025 
01026             sum += currPixel;
01027             varc += currPixel*currPixel;
01028 
01029             dif = currPixel - prevPixel;
01030             vard += dif*dif;
01031         }
01032     }
01033 
01034     vard >>= 8;         /* divide by 256; assumes mean is close to zero */
01035     varc = (varc>>8) - (sum>>8)*(sum>>8);
01036 
01037     if ( vard <= 64 ) {
01038         return FALSE;
01039     } else if ( vard < varc ) {
01040         return FALSE;
01041     } else {
01042         return TRUE;
01043     }
01044 }
01045 
01046 
01047 /*===========================================================================*
01048  *
01049  *                            USER-MODIFIABLE
01050  *
01051  * ZeroMotionSufficient
01052  *
01053  *      decide if zero motion is sufficient without DCT correction
01054  *
01055  * RETURNS:     TRUE no DCT required; FALSE otherwise
01056  *
01057  * SIDE EFFECTS:    none
01058  *
01059  * PRECONDITIONS:       The relevant block in 'current' is raw YCC data
01060  *
01061  *===========================================================================*/
01062 static boolean
01063 ZeroMotionSufficient(currentBlock, prev, by, bx)
01064     LumBlock currentBlock;
01065     MpegFrame *prev;
01066     int by;
01067     int bx;
01068 {
01069     LumBlock    motionBlock;
01070     register int    fy, fx;
01071     register int    x, y;
01072 
01073     fy = by*DCTSIZE;
01074     fx = bx*DCTSIZE;
01075     for ( y = 0; y < 16; y++ ) {
01076         for ( x = 0; x < 16; x++ ) {
01077             motionBlock[y][x] = prev->ref_y[fy+y][fx+x];
01078         }
01079     }
01080 
01081     zeroDiff = LumBlockMAD(currentBlock, motionBlock, 0x7fffffff);
01082 
01083     return (zeroDiff <= 256);
01084 }
01085                              
01086 
01087 #ifdef UNUSED_PROCEDURES
01088 static void
01089 ComputeAndPrintPframeMAD(currentBlock, prev, by, bx, my, mbx, numBlock)
01090     LumBlock currentBlock;
01091     MpegFrame *prev;
01092     int by;
01093     int bx;
01094     int my;
01095     int mx;
01096     int numBlock;
01097 {
01098     LumBlock    lumMotionBlock;
01099     int32   mad;
01100 
01101     ComputeMotionLumBlock(prev, by, bx, my, mx, lumMotionBlock);
01102 
01103     mad = LumBlockMAD(currentBlock, lumMotionBlock, 0x7fffffff);
01104 
01105     if (! realQuiet) {
01106         fprintf(stdout, "%d %d\n", numBlock, mad);
01107     }
01108 }
01109 #endif
 

Powered by Plone

This site conforms to the following standards: