home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 9 / CD_ASCQ_09_1193.iso / news / 4441 / mpegcode / src / pframe.ori < prev    next >
Text File  |  1993-09-27  |  27KB  |  945 lines

  1. /*===========================================================================*
  2.  * pframe.c                                     *
  3.  *                                         *
  4.  *    Procedures concerned with generation of P-frames             *
  5.  *                                         *
  6.  * EXPORTED PROCEDURES:                                 *
  7.  *    GenPFrame                                 *
  8.  *    ResetPFrameStats                             *
  9.  *    ShowPFrameSummary                             *
  10.  *    EstimateSecondsPerPFrame                         *
  11.  *    ComputeHalfPixelData                             *
  12.  *    SetPQScale                                 *
  13.  *    GetPQScale                                 *
  14.  *                                                                           *
  15.  * NOTE:  when motion vectors are passed as arguments, they are passed as    *
  16.  *        twice their value.  In other words, a motion vector of (3,4) will  *
  17.  *        be passed as (6,8).  This allows half-pixel motion vectors to be   *
  18.  *        passed as integers.  This is true throughout the program.          *
  19.  *                                         *
  20.  *===========================================================================*/
  21.  
  22. /*
  23.  * Copyright (c) 1993 The Regents of the University of California.
  24.  * All rights reserved.
  25.  *
  26.  * Permission to use, copy, modify, and distribute this software and its
  27.  * documentation for any purpose, without fee, and without written agreement is
  28.  * hereby granted, provided that the above copyright notice and the following
  29.  * two paragraphs appear in all copies of this software.
  30.  *
  31.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  32.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  33.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  34.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  35.  *
  36.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  37.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  38.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  39.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  40.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  41.  */
  42.  
  43. /*  
  44.  *  $Header: /n/picasso/users/keving/encode/src/RCS/pframe.c,v 1.5 1993/07/22 22:23:43 keving Exp keving $
  45.  *  $Log: pframe.c,v $
  46.  * Revision 1.5  1993/07/22  22:23:43  keving
  47.  * nothing
  48.  *
  49.  * Revision 1.4  1993/06/30  20:06:09  keving
  50.  * nothing
  51.  *
  52.  * Revision 1.3  1993/06/03  21:08:08  keving
  53.  * nothing
  54.  *
  55.  * Revision 1.2  1993/03/02  23:03:42  keving
  56.  * nothing
  57.  *
  58.  * Revision 1.1  1993/02/19  19:14:12  keving
  59.  * nothing
  60.  *
  61.  */
  62.  
  63.  
  64. /*==============*
  65.  * HEADER FILES *
  66.  *==============*/
  67.  
  68. #include <sys/times.h>
  69. #include "all.h"
  70. #include "mtypes.h"
  71. #include "bitio.h"
  72. #include "frames.h"
  73. #include "prototypes.h"
  74. #include "param.h"
  75. #include "mheaders.h"
  76. #include "fsize.h"
  77. #include "postdct.h"
  78.  
  79.  
  80. /*==================*
  81.  * STATIC VARIABLES *
  82.  *==================*/
  83.  
  84. static int32    zeroDiff;
  85. static int numPIBlocks = 0;
  86. static int numPPBlocks = 0;
  87. static int numPSkipped = 0;
  88. static int numPIBits = 0;
  89. static int numPPBits = 0;
  90. static int numFrames = 0;
  91. static int numFrameBits = 0;
  92. static int32 totalTime = 0;
  93. static int qscaleP;
  94. static float    totalSNR = 0.0;
  95. static float    totalPSNR = 0.0;
  96.  
  97.  
  98. /*===============================*
  99.  * INTERNAL PROCEDURE prototypes *
  100.  *===============================*/
  101.  
  102. static boolean    ZeroMotionBetter _ANSI_ARGS_((LumBlock currentBlock,
  103.                           MpegFrame *prev, int by, int bx,
  104.                           int my, int mx));
  105. static boolean    DoIntraCode _ANSI_ARGS_((LumBlock currentBlock,
  106.                      MpegFrame *prev, int by, int bx,
  107.                      int motionY, int motionX));
  108. static boolean    ZeroMotionSufficient _ANSI_ARGS_((LumBlock currentBlock,
  109.                           MpegFrame *prev,
  110.                           int by, int bx));
  111.  
  112. #ifdef BLEAH
  113. static void    ComputeAndPrintPframeMAD _ANSI_ARGS_((LumBlock currentBlock,
  114.                               MpegFrame *prev,
  115.                               int by, int bx,
  116.                               int my, int mx,
  117.                               int numBlock));
  118. #endif
  119.  
  120. /*=====================*
  121.  * EXPORTED PROCEDURES *
  122.  *=====================*/
  123.  
  124. /*===========================================================================*
  125.  *
  126.  * GenPFrame
  127.  *
  128.  *    generate a P-frame from previous frame, adding the result to the
  129.  *    given bit bucket
  130.  *
  131.  * RETURNS:    frame appended to bb
  132.  *
  133.  * SIDE EFFECTS:    none
  134.  *
  135.  *===========================================================================*/
  136. void
  137. GenPFrame(bb, current, prev)
  138.     BitBucket *bb;
  139.     MpegFrame *current;
  140.     MpegFrame *prev;
  141. {
  142.     FlatBlock fba[6], fb[6];
  143.     Block    dec[6];
  144.     int32 y_dc_pred, cr_dc_pred, cb_dc_pred;
  145.     int x, y;
  146.     int    motionX = 0, motionY = 0;
  147.     int    oldMotionX = 0, oldMotionY = 0;
  148.     int    offsetX, offsetY;
  149.     int    tempX, tempY;
  150.     int    motionXrem, motionXquot;
  151.     int    motionYrem, motionYquot;
  152.     int    pattern;
  153.     int        mbAddrInc = 1;
  154.     boolean    useMotion;
  155.     int numIBlocks = 0;
  156.     int    numPBlocks = 0;
  157.     int    numSkipped = 0;
  158.     int    numIBits = 0;
  159.     int numPBits = 0;
  160.     int totalBits;
  161.     int    totalFrameBits;
  162.     struct tms timeBuffer;
  163.     int32    startTime, endTime;
  164.     int numBlocks = -1;
  165.     int    lastBlockX, lastBlockY;
  166.     int    lastX, lastY;
  167.     int    fy, fx;
  168.     LumBlock currentBlock;
  169.     register int ix, iy;
  170.     int    frameBlocks;
  171.     int slicePos;
  172.     register int index;
  173.     float   snr[3], psnr[3];
  174.  
  175.     numFrames++;
  176.     totalFrameBits = bb->cumulativeBits;
  177.     times(&timeBuffer);
  178.     startTime = timeBuffer.tms_utime + timeBuffer.tms_stime;
  179.  
  180.     DBG_PRINT(("Generating pframe\n"));
  181.  
  182.     Mhead_GenPictureHeader(bb, P_FRAME, current->id, fCode);
  183.  
  184.     DBG_PRINT(("Slice Header\n"));
  185.     Mhead_GenSliceHeader(bb, 1, qscaleP, NULL, 0);
  186.  
  187.     if ( referenceFrame == DECODED_FRAME ) {
  188.     Frame_AllocDecoded(current, TRUE);
  189.     } else if ( printSNR ) {
  190.     Frame_AllocDecoded(current, FALSE);
  191.     }
  192.  
  193.     /* don't do dct on blocks yet */
  194.     Frame_AllocBlocks(current);
  195.     BlockifyFrame(current);
  196.  
  197.     /* for I-blocks */
  198.     y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
  199.  
  200.     totalBits = bb->cumulativeBits;
  201.  
  202.     if ( (! pixelFullSearch) && (! prev->halfComputed) ) {
  203.     ComputeHalfPixelData(prev);
  204.     }
  205.  
  206.     lastBlockX = Fsize_x/8;
  207.     lastBlockY = Fsize_y/8;
  208.     lastX = lastBlockX-2;
  209.     lastY = lastBlockY-2;
  210.     frameBlocks = 0;
  211.  
  212.     for (y = 0; y < lastBlockY; y += 2) {
  213.     for (x = 0; x < lastBlockX; x += 2) {
  214.         slicePos = (frameBlocks % blocksPerSlice);
  215.  
  216.         if ( (slicePos == 0) && (frameBlocks != 0) ) {
  217.         Mhead_GenSliceEnder(bb);
  218.         Mhead_GenSliceHeader(bb, 1+(y/2), qscaleP, NULL, 0);
  219.  
  220.         /* reset everything */
  221.         oldMotionX = 0;        oldMotionY = 0;
  222.         y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
  223.  
  224.         mbAddrInc = 1+(x/2);
  225.         }
  226.  
  227.         numBlocks++;
  228.         frameBlocks++;
  229.  
  230.         /* compute currentBlock */
  231.         BLOCK_TO_FRAME_COORD(y, x, fy, fx);
  232.         for ( iy = 0; iy < 16; iy++ ) {
  233.         for ( ix = 0; ix < 16; ix++ ) {
  234.             currentBlock[iy][ix] = (int16)current->orig_y[fy+iy][fx+ix];
  235.         }
  236.         }
  237.  
  238.         /* see if we should use motion vectors, and if so, what those
  239.          * vectors should be
  240.          */
  241.         if ( ZeroMotionSufficient(currentBlock, prev, y, x) ) {
  242.         motionX = 0;
  243.         motionY = 0;
  244.         pattern = 63;
  245.         useMotion = TRUE;
  246.         } else {
  247.         useMotion = PMotionSearch(currentBlock, prev, y, x,
  248.                       &motionY, &motionX);
  249.  
  250.         pattern = 63;
  251.  
  252.         if ( useMotion ) {
  253.             if ( ZeroMotionBetter(currentBlock, prev, y, x, motionY,
  254.                       motionX) ) {
  255.             motionX = 0;
  256.             motionY = 0;
  257.             pattern = 63;
  258.             }
  259.  
  260.             useMotion = (! DoIntraCode(currentBlock, prev, y, x,
  261.                            motionY, motionX));
  262.         }
  263.         }
  264.  
  265.         if ( ! useMotion ) {
  266.         /* output I-block inside a P-frame */
  267.         numIBlocks++;
  268.  
  269.         /* calculate forward dct's */
  270.         mp_fwd_dct_block(current->y_blocks[y][x]);
  271.         mp_fwd_dct_block(current->y_blocks[y][x+1]);
  272.         mp_fwd_dct_block(current->y_blocks[y+1][x]);
  273.         mp_fwd_dct_block(current->y_blocks[y+1][x+1]);
  274.         mp_fwd_dct_block(current->cb_blocks[y >> 1][x >> 1]);
  275.         mp_fwd_dct_block(current->cr_blocks[y >> 1][x >> 1]);
  276.  
  277.         GEN_I_BLOCK(P_FRAME, current, bb, mbAddrInc, qscaleP);
  278.         mbAddrInc = 1;
  279.  
  280.         numIBits += (bb->cumulativeBits-totalBits);
  281.         totalBits = bb->cumulativeBits;
  282.  
  283.         /* reset because intra-coded */
  284.         oldMotionX = 0;        oldMotionY = 0;
  285.  
  286.         if ( decodeRefFrames ) {
  287.             /* need to decode block we just encoded */
  288.             Mpost_UnQuantZigBlock(fb[0], dec[0], qscaleP, TRUE);
  289.             Mpost_UnQuantZigBlock(fb[1], dec[1], qscaleP, TRUE);
  290.             Mpost_UnQuantZigBlock(fb[2], dec[2], qscaleP, TRUE);
  291.             Mpost_UnQuantZigBlock(fb[3], dec[3], qscaleP, TRUE);
  292.             Mpost_UnQuantZigBlock(fb[4], dec[4], qscaleP, TRUE);
  293.             Mpost_UnQuantZigBlock(fb[5], dec[5], qscaleP, TRUE);
  294.  
  295.             /* now, reverse the DCT transform */
  296.             for ( index = 0; index < 6; index++ ) {
  297.             j_rev_dct((int16 *)dec[index]);
  298.             }
  299.  
  300.             /* now, unblockify */
  301.             BlockToData(current->decoded_y, dec[0], y, x);
  302.             BlockToData(current->decoded_y, dec[1], y, x+1);
  303.             BlockToData(current->decoded_y, dec[2], y+1, x);
  304.             BlockToData(current->decoded_y, dec[3], y+1, x+1);
  305.             BlockToData(current->decoded_cb, dec[4], y>>1, x>>1);
  306.             BlockToData(current->decoded_cr, dec[5], y>>1, x>>1);
  307.         }
  308.         } else {
  309.         /* USE MOTION VECTORS */
  310.         numPBlocks++;
  311.  
  312.         /* reset because non-intra-coded */
  313.         y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
  314.  
  315. #ifdef BLEAH
  316.     ComputeAndPrintPframeMAD(currentBlock, prev, y, x, motionY, motionX, numBlocks);
  317. #endif
  318.  
  319.         ComputeDiffDCTs(current, prev, y, x, motionY, motionX,
  320.                 pattern);
  321.  
  322.         if ( pixelFullSearch ) {    /* should be even */
  323.             motionY /= 2;
  324.             motionX /= 2;
  325.         }
  326.  
  327.         /* transform the motion vector into the appropriate values */
  328.         offsetX = motionX - oldMotionX;
  329.         offsetY = motionY - oldMotionY;
  330.  
  331.         ENCODE_MOTION_VECTOR(offsetX, offsetY, motionXquot,
  332.                      motionYquot, motionXrem, motionYrem,
  333.                      FORW_F);
  334.  
  335. #ifdef BLEAH
  336.     if ( (motionX != 0) || (motionY != 0) ) {
  337.     fprintf(stdout, "FRAME (y, x)  %d, %d (block %d)\n", y, x, numBlocks);
  338.     fprintf(stdout, "motionX = %d, motionY = %d\n", motionX, motionY);
  339.     fprintf(stdout, "    mxq, mxr = %d, %d    myq, myr = %d, %d\n",
  340.         motionXquot, motionXrem, motionYquot, motionYrem);
  341. }
  342. #endif
  343.  
  344.         oldMotionX = motionX;
  345.         oldMotionY = motionY;
  346.  
  347.         if ( pixelFullSearch ) {/* reset for use with PMotionSearch */
  348.             motionY *= 2;
  349.             motionX *= 2;
  350.         }
  351.  
  352.         /* create flat blocks and update pattern if necessary */
  353.     if ( (pattern & 0x20) && 
  354.          (! Mpost_QuantZigBlock(current->y_blocks[y][x], fba[0],
  355.                    qscaleP, FALSE)) ) {
  356.         pattern ^= 0x20;
  357.     }
  358.     if ( (pattern & 0x10) && 
  359.          (! Mpost_QuantZigBlock(current->y_blocks[y][x+1], fba[1],
  360.                    qscaleP, FALSE)) ) {
  361.         pattern ^= 0x10;
  362.     }
  363.     if ( (pattern & 0x8) && 
  364.          (! Mpost_QuantZigBlock(current->y_blocks[y+1][x], fba[2],
  365.                    qscaleP, FALSE)) ) {
  366.         pattern ^= 0x8;
  367.     }
  368.     if ( (pattern & 0x4) && 
  369.          (! Mpost_QuantZigBlock(current->y_blocks[y+1][x+1], fba[3],
  370.                    qscaleP, FALSE)) ) {
  371.         pattern ^= 0x4;
  372.     }
  373.     if ( (pattern & 0x2) && 
  374.          (! Mpost_QuantZigBlock(current->cb_blocks[y >> 1][x >> 1], fba[4],
  375.                    qscaleP, FALSE)) ) {
  376.         pattern ^= 0x2;
  377.     }
  378.     if ( (pattern & 0x1) && 
  379.          (! Mpost_QuantZigBlock(current->cr_blocks[y >> 1][x >> 1], fba[5],
  380.                    qscaleP, FALSE)) ) {
  381.         pattern ^= 0x1;
  382.     }
  383.  
  384.     if ( decodeRefFrames ) {
  385.         if ( pattern & 0x20 ) {
  386.         Mpost_UnQuantZigBlock(fba[0], dec[0], qscaleP, FALSE);
  387.         } else {
  388.         bzero((char *)dec[0], sizeof(Block));
  389.         }
  390.         if ( pattern & 0x10 ) {
  391.         Mpost_UnQuantZigBlock(fba[1], dec[1], qscaleP, FALSE);
  392.         } else {
  393.         bzero((char *)dec[1], sizeof(Block));
  394.         }
  395.         if ( pattern & 0x8 ) {
  396.         Mpost_UnQuantZigBlock(fba[2], dec[2], qscaleP, FALSE);
  397.         } else {
  398.         bzero((char *)dec[2], sizeof(Block));
  399.         }
  400.         if ( pattern & 0x4 ) {
  401.         Mpost_UnQuantZigBlock(fba[3], dec[3], qscaleP, FALSE);
  402.         } else {
  403.         bzero((char *)dec[3], sizeof(Block));
  404.         }
  405.         if ( pattern & 0x2 ) {
  406.         Mpost_UnQuantZigBlock(fba[4], dec[4], qscaleP, FALSE);
  407.         } else {
  408.         bzero((char *)dec[4], sizeof(Block));
  409.         }
  410.         if ( pattern & 0x1 ) {
  411.         Mpost_UnQuantZigBlock(fba[5], dec[5], qscaleP, FALSE);
  412.         } else {
  413.         bzero((char *)dec[5], sizeof(Block));
  414.         }
  415.  
  416.         /* now, reverse the DCT transform */
  417.         for ( index = 0; index < 6; index++ ) {
  418.         if ( GET_ITH_BIT(pattern, 5-index) ) {
  419.             j_rev_dct((int16 *)dec[index]);
  420.         }
  421.         }
  422.  
  423.         /* now add the motion block */
  424.         AddMotionBlock(dec[0], prev->decoded_y, y, x, motionY, motionX);
  425.         AddMotionBlock(dec[1], prev->decoded_y, y, x+1, motionY, motionX);
  426.         AddMotionBlock(dec[2], prev->decoded_y, y+1, x, motionY, motionX);
  427.         AddMotionBlock(dec[3], prev->decoded_y, y+1, x+1, motionY, motionX);
  428.         AddMotionBlock(dec[4], prev->decoded_cb, y>>1, x>>1, motionY/2, motionX/2);
  429.         AddMotionBlock(dec[5], prev->decoded_cr, y>>1, x>>1, motionY/2, motionX/2);
  430.  
  431.         /* now, unblockify */
  432.         BlockToData(current->decoded_y, dec[0], y, x);
  433.         BlockToData(current->decoded_y, dec[1], y, x+1);
  434.         BlockToData(current->decoded_y, dec[2], y+1, x);
  435.         BlockToData(current->decoded_y, dec[3], y+1, x+1);
  436.         BlockToData(current->decoded_cb, dec[4], y>>1, x>>1);
  437.         BlockToData(current->decoded_cr, dec[5], y>>1, x>>1);
  438.     }
  439.  
  440.         if ( (motionX == 0) && (motionY == 0) ) {
  441.             if ( pattern == 0 ) {
  442.             /* don't skip if last frame of slice */
  443.             if ( ((y < lastY) || (x < lastX)) &&
  444.                  (slicePos+1 != blocksPerSlice) ) {
  445.                 mbAddrInc++;    /* skipped macroblock */
  446.                 numSkipped++;
  447.                 numPBlocks--;
  448.             } else {    /* last macroblock */
  449.         Mhead_GenMBHeader(bb, 2 /* pict_code_type */, mbAddrInc /* addr_incr */,
  450.               0 /* mb_quant */, 0 /* q_scale */,
  451.               fCode /* forw_f_code */, 1 /* back_f_code */,
  452.               0 /* horiz_forw_r */, 0 /* vert_forw_r */,
  453.               0 /* horiz_back_r */, 0 /* vert_back_r */,
  454.               0 /* motion_forw */, 0 /* m_horiz_forw */,
  455.               0 /* m_vert_forw */, 0 /* motion_back */,
  456.               0 /* m_horiz_back */, 0 /* m_vert_back */,
  457.               1 /* mb_pattern */, 0 /* mb_intra */);
  458.             mbAddrInc = 1;
  459.  
  460.                 Bitio_Write(bb, 0x2, 2); /* first coeff */
  461.                 Bitio_Write(bb, 0x2, 2); /* end of block */
  462.             }
  463.             } else {
  464.             DBG_PRINT(("MB Header(%d,%d)\n", x, y));
  465.         Mhead_GenMBHeader(bb, 2 /* pict_code_type */, mbAddrInc /* addr_incr */,
  466.               0 /* mb_quant */, 0 /* q_scale */,
  467.               fCode /* forw_f_code */, 1 /* back_f_code */,
  468.               0 /* horiz_forw_r */, 0 /* vert_forw_r */,
  469.               0 /* horiz_back_r */, 0 /* vert_back_r */,
  470.               0 /* motion_forw */, 0 /* m_horiz_forw */,
  471.               0 /* m_vert_forw */, 0 /* motion_back */,
  472.               0 /* m_horiz_back */, 0 /* m_vert_back */,
  473.               pattern /* mb_pattern */, 0 /* mb_intra */);
  474.             mbAddrInc = 1;
  475.             }
  476.         } else {
  477.         DBG_PRINT(("MB Header(%d,%d)\n", x, y));
  478.         Mhead_GenMBHeader(bb, 2 /* pict_code_type */, mbAddrInc /* addr_incr */,
  479.               0 /* mb_quant */, 0 /* q_scale */,
  480.               fCode /* forw_f_code */, 1 /* back_f_code */,
  481.               motionXrem /* horiz_forw_r */, motionYrem /* vert_forw_r */,
  482.               0 /* horiz_back_r */, 0 /* vert_back_r */,
  483.               1 /* motion_forw */, motionXquot /* m_horiz_forw */,
  484.               motionYquot /* m_vert_forw */, 0 /* motion_back */,
  485.               0 /* m_horiz_back */, 0 /* m_vert_back */,
  486.               pattern /* mb_pattern */, 0 /* mb_intra */);
  487.             mbAddrInc = 1;
  488.         }
  489.  
  490.         /* now output the difference */
  491.         for ( tempX = 0; tempX < 6; tempX++ ) {
  492.             if ( GET_ITH_BIT(pattern, 5-tempX) ) {
  493.             Mpost_RLEHuffPBlock(fba[tempX], bb);
  494.             }
  495.         }
  496.  
  497.         numPBits += (bb->cumulativeBits-totalBits);
  498.         totalBits = bb->cumulativeBits;
  499.         }
  500.     }
  501.     }
  502.  
  503.     if ( printSNR ) {
  504.         ComputeSNR(current->orig_y, current->decoded_y, Fsize_y, Fsize_x,
  505.            &snr[0], &psnr[0]);
  506.         ComputeSNR(current->orig_cb, current->decoded_cb, Fsize_y/2, Fsize_x/2,
  507.            &snr[1], &psnr[1]);
  508.         ComputeSNR(current->orig_cr, current->decoded_cr, Fsize_y/2, Fsize_x/2,
  509.            &snr[2], &psnr[2]);
  510.  
  511.     totalSNR += snr[0];
  512.     totalPSNR += psnr[0];
  513.     }
  514.  
  515.     Mhead_GenSliceEnder(bb);
  516.  
  517.     /* UPDATE STATISTICS */
  518.     times(&timeBuffer);
  519.     endTime = timeBuffer.tms_utime + timeBuffer.tms_stime;
  520.     totalTime += (endTime-startTime);
  521.  
  522.     if ( (! childProcess) && frameSummary ) {
  523.     fprintf(stdout, "FRAME %d (P):  I BLOCKS:  %d;  P BLOCKS:  %d   SKIPPED:  %d  (%ld seconds)\n",
  524.         current->id, numIBlocks, numPBlocks, numSkipped, (long)(endTime-startTime)/60);
  525.     if ( printSNR ) {
  526.         fprintf(stdout, "FRAME %d:  SNR:  %.1f\t%.1f\t%.1f\tPSNR:  %.1f\t%.1f\t%.1f\n",
  527.             current->id, snr[0], snr[1], snr[2],
  528.             psnr[0], psnr[1], psnr[2]);
  529.     }
  530.     }
  531.  
  532.     numFrameBits += (bb->cumulativeBits-totalFrameBits);
  533.     numPIBlocks += numIBlocks;
  534.     numPPBlocks += numPBlocks;
  535.     numPSkipped += numSkipped;
  536.     numPIBits += numIBits;
  537.     numPPBits += numPBits;
  538.  
  539. #ifdef BLEAH
  540. if ( decodeRefFrames ) {
  541.     FILE    *fpointer;
  542.     char    fileName[256];
  543.     int    width, height;
  544.  
  545.     /* output the decoded frame */
  546.  
  547.     width = Fsize_x;
  548.     height = Fsize_y;
  549.  
  550.     sprintf(fileName, "/tmp/decoded%d.yuv", current->id);
  551.     fprintf(stdout, "outputting to %s\n", fileName);
  552.  
  553.     fpointer = fopen(fileName, "wb");
  554.  
  555.     for ( y = 0; y < height; y++ ) {
  556.         fwrite(current->decoded_y[y], 1, width, fpointer);
  557.     }
  558.  
  559.     for (y = 0; y < height / 2; y++) {            /* U */
  560.         fwrite(current->decoded_cb[y], 1, width / 2, fpointer);
  561.     }
  562.  
  563.     for (y = 0; y < height / 2; y++) {            /* V */
  564.         fwrite(current->decoded_cr[y], 1, width / 2, fpointer);
  565.     }
  566.  
  567.     fclose(fpointer);
  568. }
  569. #endif
  570.  
  571. }
  572.  
  573.  
  574. /*===========================================================================*
  575.  *
  576.  * ResetPFrameStats
  577.  *
  578.  *    reset the P-frame statistics
  579.  *
  580.  * RETURNS:    nothing
  581.  *
  582.  * SIDE EFFECTS:    none
  583.  *
  584.  *===========================================================================*/
  585. void
  586. ResetPFrameStats()
  587. {
  588.     numPIBlocks = 0;
  589.     numPPBlocks = 0;
  590.     numPSkipped = 0;
  591.     numPIBits = 0;
  592.     numPPBits = 0;
  593.     numFrames = 0;
  594.     numFrameBits = 0;
  595.     totalTime = 0;
  596. }
  597.  
  598.  
  599. /*===========================================================================*
  600.  *
  601.  * SetPQScale
  602.  *
  603.  *    set the P-frame Q-scale
  604.  *
  605.  * RETURNS:    nothing
  606.  *
  607.  * SIDE EFFECTS:    qscaleP
  608.  *
  609.  *===========================================================================*/
  610. void
  611. SetPQScale(qP)
  612.     int qP;
  613. {
  614.     qscaleP = qP;
  615. }
  616.  
  617.  
  618. /*===========================================================================*
  619.  *
  620.  * GetPQScale
  621.  *
  622.  *    return the P-frame Q-scale
  623.  *
  624.  * RETURNS:    the P-frame Q-scale
  625.  *
  626.  * SIDE EFFECTS:    none
  627.  *
  628.  *===========================================================================*/
  629. int
  630. GetPQScale()
  631. {
  632.     return qscaleP;
  633. }
  634.  
  635.  
  636. /*===========================================================================*
  637.  *
  638.  * ShowPFrameSummary
  639.  *
  640.  *    print a summary of information on encoding P-frames
  641.  *
  642.  * RETURNS:    nothing
  643.  *
  644.  * SIDE EFFECTS:    none
  645.  *
  646.  *===========================================================================*/
  647. void
  648. ShowPFrameSummary(inputFrameBits, totalBits, fpointer)
  649.     int inputFrameBits;
  650.     int32 totalBits;
  651.     FILE *fpointer;
  652. {
  653.     if ( numFrames == 0 ) {
  654.     return;
  655.     }
  656.  
  657.     fprintf(fpointer, "-------------------------\n");
  658.     fprintf(fpointer, "*****P FRAME SUMMARY*****\n");
  659.     fprintf(fpointer, "-------------------------\n");
  660.  
  661.     if ( numPIBlocks != 0 ) {
  662.     fprintf(fpointer, "  I Blocks:  %5d     (%6d bits)     (%5d bpb)\n",
  663.         numPIBlocks, numPIBits, numPIBits/numPIBlocks);
  664.     } else {
  665.     fprintf(fpointer, "  I Blocks:  %5d\n", 0);
  666.     }
  667.  
  668.     if ( numPPBlocks != 0 ) {
  669.     fprintf(fpointer, "  P Blocks:  %5d     (%6d bits)     (%5d bpb)\n",
  670.         numPPBlocks, numPPBits, numPPBits/numPPBlocks);
  671.     } else {
  672.     fprintf(fpointer, "  P Blocks:  %5d\n", 0);
  673.     }
  674.  
  675.     fprintf(fpointer, "  Skipped:   %5d\n", numPSkipped);
  676.  
  677.     fprintf(fpointer, "  Frames:    %5d     (%6d bits)     (%5d bpf)     (%2.1f%% of total)\n",
  678.         numFrames, numFrameBits, numFrameBits/numFrames,
  679.         100.0*(float)numFrameBits/(float)totalBits);
  680.     fprintf(fpointer, "  Compression:  %3d:1\n",
  681.         numFrames*inputFrameBits/numFrameBits);
  682.     if ( printSNR )
  683.     fprintf(fpointer, "  Avg Y SNR/PSNR:  %.1f     %.1f\n",
  684.         totalSNR/(float)numFrames, totalPSNR/(float)numFrames);
  685.     fprintf(fpointer, "  Seconds:  %9ld     (%9ld spf)     (%9ld bps)\n",
  686.         (long)(totalTime/60), (long)(totalTime/(60*numFrames)),
  687.         (long)(60.0*(float)numFrames*(float)inputFrameBits/(float)totalTime));
  688. }
  689.  
  690.  
  691. /*===========================================================================*
  692.  *
  693.  * EstimateSecondsPerPFrame
  694.  *
  695.  *    compute an estimate of the number of seconds required per P-frame
  696.  *
  697.  * RETURNS:    the estimate, in seconds
  698.  *
  699.  * SIDE EFFECTS:    none
  700.  *
  701.  *===========================================================================*/
  702. float
  703. EstimateSecondsPerPFrame()
  704. {
  705.     if ( numFrames == 0 ) {
  706.     return 10.0;
  707.     } else {
  708.     return (float)totalTime/(60.0*(float)numFrames);
  709.     }
  710. }
  711.  
  712.  
  713. /*===========================================================================*
  714.  *
  715.  * ComputeHalfPixelData
  716.  *
  717.  *    compute all half-pixel data required for half-pixel motion vector
  718.  *    search (luminance only)
  719.  *
  720.  * RETURNS:    frame->halfX, ->halfY, and ->halfBoth modified
  721.  *
  722.  * SIDE EFFECTS:    none
  723.  *
  724.  *===========================================================================*/
  725. void
  726. ComputeHalfPixelData(frame)
  727.     MpegFrame *frame;
  728. {
  729.     register int x, y;
  730.  
  731.     /* we add 1 before dividing by 2 because .5 is supposed to be rounded up
  732.      * (see MPEG-1, page D-31)
  733.      */
  734.  
  735.     if ( frame->halfX == NULL ) {        /* need to allocate memory */
  736.         Frame_AllocHalf(frame);
  737.     }
  738.  
  739.     /* compute halfX */
  740.     for ( y = 0; y < Fsize_y; y++ ) {
  741.     for ( x = 0; x < Fsize_x-1; x++ ) {
  742.         frame->halfX[y][x] = (frame->ref_y[y][x]+
  743.                   frame->ref_y[y][x+1]+1)/2;
  744.     }
  745.     }
  746.  
  747.     /* compute halfY */
  748.     for ( y = 0; y < Fsize_y-1; y++ ) {
  749.     for ( x = 0; x < Fsize_x; x++ ) {
  750.         frame->halfY[y][x] = (frame->ref_y[y][x]+
  751.                   frame->ref_y[y+1][x]+1)/2;
  752.     }
  753.     }
  754.  
  755.     /* compute halfBoth */
  756.     for ( y = 0; y < Fsize_y-1; y++ ) {
  757.     for ( x = 0; x < Fsize_x-1; x++ ) {
  758.         frame->halfBoth[y][x] = (frame->ref_y[y][x]+
  759.                      frame->ref_y[y][x+1]+
  760.                      frame->ref_y[y+1][x]+
  761.                      frame->ref_y[y+1][x+1]+2)/4;
  762.     }
  763.     }
  764.  
  765.     frame->halfComputed = TRUE;
  766. }
  767.  
  768.  
  769. /*=====================*
  770.  * INTERNAL PROCEDURES *
  771.  *=====================*/
  772.  
  773. /*===========================================================================*
  774.  *
  775.  *                  USER-MODIFIABLE
  776.  *
  777.  * ZeroMotionBetter
  778.  *
  779.  *    decide if (0,0) motion is better than the given motion vector
  780.  *
  781.  * RETURNS:    TRUE if (0,0) is better, FALSE if (my,mx) is better
  782.  *
  783.  * SIDE EFFECTS:    none
  784.  *
  785.  * PRECONDITIONS:    The relevant block in 'current' is valid (it has not
  786.  *            been dct'd).  'zeroDiff' has already been computed
  787.  *            as the LumMotionError() with (0,0) motion
  788.  *
  789.  * NOTES:    This procedure follows the algorithm described on
  790.  *        page D-48 of the MPEG-1 specification
  791.  *
  792.  *===========================================================================*/
  793. static boolean
  794. ZeroMotionBetter(currentBlock, prev, by, bx, my, mx)
  795.     LumBlock currentBlock;
  796.     MpegFrame *prev;
  797.     int by;
  798.     int bx;
  799.     int my;
  800.     int mx;
  801. {
  802.     int    bestDiff;
  803.  
  804.     bestDiff = LumMotionError(currentBlock, prev, by, bx, my, mx, 0x7fffffff);
  805.  
  806.     if ( zeroDiff < 256*3 ) {
  807.     if ( 2*bestDiff >= zeroDiff ) {
  808.         return TRUE;
  809.     }
  810.     } else {
  811.     if ( 11*bestDiff >= 10*zeroDiff ) {
  812.         return TRUE;
  813.     }
  814.     }
  815.  
  816.     return FALSE;
  817. }
  818.  
  819.  
  820. /*===========================================================================*
  821.  *
  822.  *                  USER-MODIFIABLE
  823.  *
  824.  * DoIntraCode
  825.  *
  826.  *    decide if intra coding is necessary
  827.  *
  828.  * RETURNS:    TRUE if intra-block coding is better; FALSE if not
  829.  *
  830.  * SIDE EFFECTS:    none
  831.  *
  832.  * PRECONDITIONS:    The relevant block in 'current' is valid (it has not
  833.  *            been dct'd).
  834.  *
  835.  * NOTES:    This procedure follows the algorithm described on
  836.  *        page D-49 of the MPEG-1 specification
  837.  *
  838.  *===========================================================================*/
  839. static boolean
  840. DoIntraCode(currentBlock, prev, by, bx, motionY, motionX)
  841.     LumBlock currentBlock;
  842.     MpegFrame *prev;
  843.     int by;
  844.     int bx;
  845.     int motionY;
  846.     int motionX;
  847. {
  848.     int        x, y;
  849.     int32 sum = 0, vard = 0, varc = 0, dif;
  850.     int32 currPixel, prevPixel;
  851.     LumBlock    motionBlock;
  852.     int        fy, fx;
  853.  
  854.     ComputeMotionLumBlock(prev, by, bx, motionY, motionX, motionBlock);
  855.  
  856.     MOTION_TO_FRAME_COORD(by, bx, 0, 0, fy, fx);
  857.  
  858.     for ( y = 0; y < 16; y++ ) {
  859.     for ( x = 0; x < 16; x++ ) {
  860.         currPixel = currentBlock[y][x];
  861.         prevPixel = motionBlock[y][x];
  862.  
  863.         sum += currPixel;
  864.         varc += currPixel*currPixel;
  865.  
  866.         dif = currPixel - prevPixel;
  867.         vard += dif*dif;
  868.     }
  869.     }
  870.  
  871.     vard /= 256;    /* assumes mean is close to zero */
  872.     varc = varc/256 - (sum/256)*(sum/256);
  873.  
  874.     if ( vard <= 64 ) {
  875.     return FALSE;
  876.     } else if ( vard < varc ) {
  877.     return FALSE;
  878.     } else {
  879.     return TRUE;
  880.     }
  881. }
  882.  
  883.  
  884. /*===========================================================================*
  885.  *
  886.  *                  USER-MODIFIABLE
  887.  *
  888.  * ZeroMotionSufficient
  889.  *
  890.  *    decide if zero motion is sufficient without DCT correction
  891.  *
  892.  * RETURNS:    TRUE no DCT required; FALSE otherwise
  893.  *
  894.  * SIDE EFFECTS:    none
  895.  *
  896.  * PRECONDITIONS:    The relevant block in 'current' is raw YCC data
  897.  *
  898.  *===========================================================================*/
  899. static boolean
  900. ZeroMotionSufficient(currentBlock, prev, by, bx)
  901.     LumBlock currentBlock;
  902.     MpegFrame *prev;
  903.     int by;
  904.     int bx;
  905. {
  906.     LumBlock    motionBlock;
  907.     register int    fy, fx;
  908.     register int    x, y;
  909.  
  910.     fy = by*DCTSIZE;
  911.     fx = bx*DCTSIZE;
  912.     for ( y = 0; y < 16; y++ ) {
  913.     for ( x = 0; x < 16; x++ ) {
  914.         motionBlock[y][x] = prev->ref_y[fy+y][fx+x];
  915.     }
  916.     }
  917.  
  918.     zeroDiff = LumBlockMAD(currentBlock, motionBlock, 0x7fffffff);
  919.  
  920.     return (zeroDiff <= 256);
  921. }
  922.                  
  923.  
  924. #ifdef UNUSED_PROCEDURES
  925. static void
  926. ComputeAndPrintPframeMAD(currentBlock, prev, by, bx, my, mbx, numBlock)
  927.     LumBlock currentBlock;
  928.     MpegFrame *prev;
  929.     int by;
  930.     int bx;
  931.     int my;
  932.     int mx;
  933.     int numBlock;
  934. {
  935.     LumBlock    lumMotionBlock;
  936.     int32   mad;
  937.  
  938.     ComputeMotionLumBlock(prev, by, bx, my, mx, lumMotionBlock);
  939.  
  940.     mad = LumBlockMAD(currentBlock, lumMotionBlock, 0x7fffffff);
  941.  
  942.     fprintf(stdout, "%d %d\n", numBlock, mad);
  943. }
  944. #endif
  945.