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

  1. /*===========================================================================*
  2.  * bframe.c                                     *
  3.  *                                         *
  4.  *    Procedures concerned with the B-frame encoding                 *
  5.  *                                         *
  6.  * EXPORTED PROCEDURES:                                 *
  7.  *    GenBFrame                                 *
  8.  *    ResetBFrameStats                             *
  9.  *    ShowBFrameSummary                             *
  10.  *    EstimateSecondsPerBFrame                         *
  11.  *    ComputeBMotionLumBlock                             *
  12.  *    SetBQScale                                 *
  13.  *    GetBQScale                                 *
  14.  *                                         *
  15.  *===========================================================================*/
  16.  
  17. /*
  18.  * Copyright (c) 1993 The Regents of the University of California.
  19.  * All rights reserved.
  20.  *
  21.  * Permission to use, copy, modify, and distribute this software and its
  22.  * documentation for any purpose, without fee, and without written agreement is
  23.  * hereby granted, provided that the above copyright notice and the following
  24.  * two paragraphs appear in all copies of this software.
  25.  *
  26.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  27.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  28.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  29.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30.  *
  31.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  32.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  33.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  34.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  35.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  36.  */
  37.  
  38. /*  
  39.  *  $Header: /n/picasso/users/keving/encode/src/RCS/bframe.c,v 1.5 1993/07/30 19:24:04 keving Exp keving $
  40.  *  $Log: bframe.c,v $
  41.  * Revision 1.5  1993/07/30  19:24:04  keving
  42.  * nothing
  43.  *
  44.  * Revision 1.4  1993/07/22  22:23:43  keving
  45.  * nothing
  46.  *
  47.  * Revision 1.3  1993/06/30  20:06:09  keving
  48.  * nothing
  49.  *
  50.  * Revision 1.2  1993/06/03  21:08:08  keving
  51.  * nothing
  52.  *
  53.  * Revision 1.1  1993/02/19  19:14:28  keving
  54.  * nothing
  55.  *
  56.  */
  57.  
  58.  
  59. /*==============*
  60.  * HEADER FILES *
  61.  *==============*/
  62.  
  63. #include "all.h"
  64. #include <sys/times.h>
  65. #include "mtypes.h"
  66. #include "bitio.h"
  67. #include "frames.h"
  68. #include "prototypes.h"
  69. #include "fsize.h"
  70. #include "param.h"
  71. #include "mheaders.h"
  72. #include "postdct.h"
  73.  
  74.  
  75. /*==================*
  76.  * STATIC VARIABLES *
  77.  *==================*/
  78.  
  79. static int numBIBlocks = 0;
  80. static int numBBBlocks = 0;
  81. static int numBSkipped = 0;
  82. static int numBIBits = 0;
  83. static int numBBBits = 0;
  84. static int numFrames = 0;
  85. static int numFrameBits = 0;
  86. static int32 totalTime = 0;
  87. static int qscaleB;
  88. static float    totalSNR = 0.0;
  89. static float    totalPSNR = 0.0;
  90.  
  91.  
  92. /*===============================*
  93.  * INTERNAL PROCEDURE prototypes *
  94.  *===============================*/
  95.  
  96. static boolean    MotionSufficient _ANSI_ARGS_((LumBlock currBlock, MpegFrame *prev, MpegFrame *next,
  97.              int by, int bx, int mode, int fmy, int fmx,
  98.              int bmy, int bmx));
  99. static void    ComputeBMotionBlock _ANSI_ARGS_((MpegFrame *prev, MpegFrame *next,
  100.                    int by, int bx, int mode, int fmy, int fmx,
  101.                    int bmy, int bmx, Block motionBlock, int type));
  102. static void    ComputeBDiffDCTs _ANSI_ARGS_((MpegFrame *current, MpegFrame *prev, MpegFrame *next,
  103.              int by, int bx, int mode, int fmy, int fmx, 
  104.              int bmy, int bmx, int pattern));
  105. static boolean    DoBIntraCode _ANSI_ARGS_((MpegFrame *current, MpegFrame *prev, MpegFrame *next,
  106.              int by, int bx, int mode, int fmy, int fmx, int bmy,
  107.              int bmx));
  108.  
  109. /*=====================*
  110.  * EXPORTED PROCEDURES *
  111.  *=====================*/
  112.  
  113. /*===========================================================================*
  114.  *
  115.  * GenBFrame
  116.  *
  117.  *    generate a B-frame from previous and next frames, adding the result
  118.  *    to the given bit bucket
  119.  *
  120.  * RETURNS:    frame appended to bb
  121.  *
  122.  * SIDE EFFECTS:    none
  123.  *
  124.  *===========================================================================*/
  125. void
  126. GenBFrame(bb, curr, prev, next)
  127.     BitBucket *bb;
  128.     MpegFrame *curr;
  129.     MpegFrame *prev;
  130.     MpegFrame *next;
  131. {
  132.     FlatBlock fba[6], fb[6];
  133.     Block    dec[6];
  134.     int32 y_dc_pred, cr_dc_pred, cb_dc_pred;
  135.     int x, y;
  136.     int    fMotionX = 0, fMotionY = 0;
  137.     int bMotionX = 0, bMotionY = 0;
  138.     int    oldFMotionX = 0, oldFMotionY = 0;
  139.     int oldBMotionX = 0, oldBMotionY = 0;
  140.     int    oldMode = MOTION_FORWARD;
  141.     int    mode = MOTION_FORWARD;
  142.     int    offsetX, offsetY;
  143.     int    tempX, tempY;
  144.     int    fMotionXrem = 0, fMotionXquot = 0;
  145.     int    fMotionYrem = 0, fMotionYquot = 0;
  146.     int    bMotionXrem = 0, bMotionXquot = 0;
  147.     int    bMotionYrem = 0, bMotionYquot = 0;
  148.     int    pattern;
  149.     int    numIBlocks = 0;
  150.     int numBBlocks = 0;
  151.     int numSkipped = 0;
  152.     int    numIBits = 0;
  153.     int    numBBits = 0;
  154.     int    totalBits;
  155.     int    mbAddrInc = 1;
  156.     boolean    lastIntra = TRUE;
  157.     int        motionForward, motionBackward;
  158.     int        totalFrameBits;
  159.     struct tms timeBuffer;
  160.     int32    startTime, endTime;
  161.     int lastX, lastY;
  162.     int lastBlockX, lastBlockY;
  163.     register int ix, iy;
  164.     LumBlock currentBlock;
  165.     int fy, fx;
  166.     boolean    result;
  167.     int    frameBlocks;
  168.     int        slicePos;
  169.     float   snr[3], psnr[3];
  170.     int        index;
  171.  
  172.     numFrames++;
  173.     totalFrameBits = bb->cumulativeBits;
  174.     times(&timeBuffer);
  175.     startTime = timeBuffer.tms_utime + timeBuffer.tms_stime;
  176.  
  177.     Mhead_GenPictureHeader(bb, B_FRAME, curr->id, fCode);
  178.     Mhead_GenSliceHeader(bb, 1, qscaleB, NULL, 0);
  179.  
  180.     Frame_AllocBlocks(curr);
  181.     BlockifyFrame(curr);
  182.  
  183.     if ( printSNR ) {
  184.     Frame_AllocDecoded(curr, FALSE);
  185.     }
  186.  
  187.     /* for I-blocks */
  188.     y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
  189.  
  190.     totalBits = bb->cumulativeBits;
  191.  
  192.     if ( ! pixelFullSearch ) {
  193.     if ( ! prev->halfComputed ) {
  194.         ComputeHalfPixelData(prev);
  195.     }
  196.  
  197.     if ( ! next->halfComputed ) {
  198.         ComputeHalfPixelData(next);
  199.     }
  200.     }
  201.  
  202.     lastBlockX = Fsize_x/8;
  203.     lastBlockY = Fsize_y/8;
  204.     lastX = lastBlockX-2;
  205.     lastY = lastBlockY-2;
  206.     frameBlocks = 0;
  207.  
  208.     for (y = 0; y < lastBlockY; y += 2) {
  209.     for (x = 0; x < lastBlockX; x += 2) {
  210.         slicePos = (frameBlocks % blocksPerSlice);
  211.  
  212.         if ( (slicePos == 0) && (frameBlocks != 0) ) {
  213.         Mhead_GenSliceEnder(bb);
  214.         Mhead_GenSliceHeader(bb, 1+(y/2), qscaleB, NULL, 0);
  215.  
  216.         /* reset everything */
  217.         oldFMotionX = 0;    oldFMotionY = 0;
  218.         oldBMotionX = 0;    oldBMotionY = 0;
  219.         oldMode = MOTION_FORWARD;
  220.         lastIntra = TRUE;
  221.         y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
  222.  
  223.         mbAddrInc = 1+(x/2);
  224.         }
  225.  
  226.         frameBlocks++;
  227.  
  228.         /* compute currentBlock */
  229.         BLOCK_TO_FRAME_COORD(y, x, fy, fx);
  230.         for ( iy = 0; iy < 16; iy++ ) {
  231.         for ( ix = 0; ix < 16; ix++ ) {
  232.             currentBlock[iy][ix] = (int16)curr->orig_y[fy+iy][fx+ix];
  233.         }
  234.         }
  235.  
  236. /* STEP 1:  Select Forward, Backward, or Interpolated motion vectors */
  237.         /* see if old motion is good enough */
  238.         /* but force last block to be non-skipped */
  239.         if ( (! lastIntra) && ((y < lastY) || (x < lastX)) ) {
  240.         if ( pixelFullSearch ) {
  241.             result = MotionSufficient(currentBlock, prev, next, y, x, oldMode,
  242.                           2*oldFMotionY, 2*oldFMotionX,
  243.                           2*oldBMotionY, 2*oldBMotionX);
  244.         } else {
  245.             result = MotionSufficient(currentBlock, prev, next, y, x, oldMode,
  246.                       oldFMotionY, oldFMotionX,
  247.                       oldBMotionY, oldBMotionX);
  248.         }
  249.         } else {
  250.         result = FALSE;
  251.         }
  252.  
  253.         if ( result ) {
  254.         /* skipped macro block */
  255.         mbAddrInc++;
  256.         numSkipped++;
  257.  
  258.         /* decode skipped block */
  259.         if ( printSNR ) {
  260.             int    fmy, fmx, bmy, bmx;
  261.  
  262.             bzero((char *)dec[0], sizeof(Block));
  263.             bzero((char *)dec[1], sizeof(Block));
  264.             bzero((char *)dec[2], sizeof(Block));
  265.             bzero((char *)dec[3], sizeof(Block));
  266.             bzero((char *)dec[4], sizeof(Block));
  267.             bzero((char *)dec[5], sizeof(Block));
  268.  
  269.             if ( pixelFullSearch ) {
  270.             fmy = 2*oldFMotionY;
  271.             fmx = 2*oldFMotionX;
  272.             bmy = 2*oldBMotionY;
  273.             bmx = 2*oldBMotionX;
  274.             } else {
  275.             fmy = oldFMotionY;
  276.             fmx = oldFMotionX;
  277.             bmy = oldBMotionY;
  278.             bmx = oldBMotionX;
  279.             }
  280.  
  281.             /* now add the motion block */
  282.             AddBMotionBlock(dec[0], prev->decoded_y,
  283.                     next->decoded_y, y, x, mode,
  284.                     fmy, fmx, bmy, bmx);
  285.             AddBMotionBlock(dec[1], prev->decoded_y,
  286.                     next->decoded_y, y, x+1, mode,
  287.                     fmy, fmx, bmy, bmx);
  288.             AddBMotionBlock(dec[2], prev->decoded_y,
  289.                     next->decoded_y, y+1, x, mode,
  290.                     fmy, fmx, bmy, bmx);
  291.             AddBMotionBlock(dec[3], prev->decoded_y,
  292.                     next->decoded_y, y+1, x+1, mode,
  293.                     fmy, fmx, bmy, bmx);
  294.             AddBMotionBlock(dec[4], prev->decoded_cb,
  295.                     next->decoded_cb, y>>1, x>>1, mode,
  296.                     fmy/2, fmx/2,
  297.                     bmy/2, bmx/2);
  298.             AddBMotionBlock(dec[5], prev->decoded_cr,
  299.                     next->decoded_cb, y>>1, x>>1, mode,
  300.                     fmy/2, fmx/2,
  301.                     bmy/2, bmx/2);
  302.  
  303.             /* now, unblockify */
  304.             BlockToData(curr->decoded_y, dec[0], y, x);
  305.             BlockToData(curr->decoded_y, dec[1], y, x+1);
  306.             BlockToData(curr->decoded_y, dec[2], y+1, x);
  307.             BlockToData(curr->decoded_y, dec[3], y+1, x+1);
  308.             BlockToData(curr->decoded_cb, dec[4], y>>1, x>>1);
  309.             BlockToData(curr->decoded_cr, dec[5], y>>1, x>>1);
  310.         }
  311.         } else {
  312.         /* do bsearch */
  313.         mode = BMotionSearch(currentBlock, prev, next, y, x, &fMotionY,
  314.                      &fMotionX, &bMotionY, &bMotionX, mode);
  315.  
  316.         pattern = 63;
  317.  
  318. /* STEP 2:  INTRA OR NON-INTRA CODING */
  319.         if ( DoBIntraCode(curr, prev, next, y, x, mode, fMotionY,
  320.                   fMotionX, bMotionY, bMotionX) ) {
  321.             /* output I-block inside a P-frame */
  322.             numIBlocks++;
  323.  
  324.             /* calculate forward dct's */
  325.             mp_fwd_dct_block(curr->y_blocks[y][x]);
  326.             mp_fwd_dct_block(curr->y_blocks[y][x+1]);
  327.             mp_fwd_dct_block(curr->y_blocks[y+1][x]);
  328.             mp_fwd_dct_block(curr->y_blocks[y+1][x+1]);
  329.             mp_fwd_dct_block(curr->cb_blocks[y >> 1][x >> 1]);
  330.             mp_fwd_dct_block(curr->cr_blocks[y >> 1][x >> 1]);
  331.  
  332.             GEN_I_BLOCK(B_FRAME, curr, bb, mbAddrInc, qscaleB);
  333.  
  334.             mbAddrInc = 1;
  335.  
  336.             numIBits += (bb->cumulativeBits-totalBits);
  337.             totalBits = bb->cumulativeBits;
  338.  
  339.             /* reset because intra-coded */
  340.             oldFMotionX = 0;        oldFMotionY = 0;
  341.             oldBMotionX = 0;        oldBMotionY = 0;
  342.             oldMode = MOTION_FORWARD;
  343.             lastIntra = TRUE;
  344.  
  345.             if ( printSNR ) {
  346.             /* need to decode block we just encoded */
  347.             Mpost_UnQuantZigBlock(fb[0], dec[0], qscaleB, TRUE);
  348.             Mpost_UnQuantZigBlock(fb[1], dec[1], qscaleB, TRUE);
  349.             Mpost_UnQuantZigBlock(fb[2], dec[2], qscaleB, TRUE);
  350.             Mpost_UnQuantZigBlock(fb[3], dec[3], qscaleB, TRUE);
  351.             Mpost_UnQuantZigBlock(fb[4], dec[4], qscaleB, TRUE);
  352.             Mpost_UnQuantZigBlock(fb[5], dec[5], qscaleB, TRUE);
  353.  
  354.             /* now, reverse the DCT transform */
  355.             for ( index = 0; index < 6; index++ ) {
  356.                 j_rev_dct((int16 *)dec[index]);
  357.             }
  358.  
  359.             /* now, unblockify */
  360.             BlockToData(curr->decoded_y, dec[0], y, x);
  361.             BlockToData(curr->decoded_y, dec[1], y, x+1);
  362.             BlockToData(curr->decoded_y, dec[2], y+1, x);
  363.             BlockToData(curr->decoded_y, dec[3], y+1, x+1);
  364.             BlockToData(curr->decoded_cb, dec[4], y>>1, x>>1);
  365.             BlockToData(curr->decoded_cr, dec[5], y>>1, x>>1);
  366.             }
  367.         } else {
  368. /* STEP 3:  CODED OR NOT CODED */            
  369.             /* make special cases for (0,0) motion???? */
  370.             lastIntra = FALSE;
  371.             /* USE MOTION VECTORS */
  372.             numBBlocks++;
  373.  
  374.             /* reset because non-intra-coded */
  375.             y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
  376.  
  377.             ComputeBDiffDCTs(curr, prev, next, y, x, mode, fMotionY,
  378.                      fMotionX, bMotionY, bMotionX, pattern);
  379.  
  380.             if ( pixelFullSearch ) {
  381.             fMotionX /= 2;        fMotionY /= 2;
  382.             bMotionX /= 2;        bMotionY /= 2;
  383.             }
  384.  
  385. /* should really check to see if same motion as previous block, and see if
  386. pattern is 0, then skip it! */
  387.  
  388.              motionForward = ((mode != MOTION_BACKWARD) ? 1 : 0);
  389.             motionBackward = ((mode != MOTION_FORWARD) ? 1 : 0);
  390.  
  391.             if ( motionForward ) {
  392.             /* transform the fMotion vector into the appropriate values */
  393.             offsetX = fMotionX - oldFMotionX;
  394.             offsetY = fMotionY - oldFMotionY;
  395.  
  396.             ENCODE_MOTION_VECTOR(offsetX, offsetY, fMotionXquot,
  397.                      fMotionYquot, fMotionXrem, fMotionYrem,
  398.                      FORW_F);
  399.  
  400.             oldFMotionX = fMotionX;        oldFMotionY = fMotionY;
  401.             }
  402.  
  403.             if ( motionBackward ) {
  404.             /* transform the bMotion vector into the appropriate values */
  405.             offsetX = bMotionX - oldBMotionX;
  406.             offsetY = bMotionY - oldBMotionY;
  407.             ENCODE_MOTION_VECTOR(offsetX, offsetY, bMotionXquot,
  408.                      bMotionYquot, bMotionXrem, bMotionYrem,
  409.                      BACK_F);
  410.  
  411.             oldBMotionX = bMotionX;        oldBMotionY = bMotionY;
  412.             }
  413.  
  414.             oldMode = mode;
  415.  
  416.             if ( pixelFullSearch ) {
  417.             fMotionX *= 2;    fMotionY *= 2;
  418.             bMotionX *= 2;    bMotionY *= 2;
  419.             }
  420.  
  421.         /* create flat blocks and update pattern if necessary */
  422.     if ( (pattern & 0x20) && 
  423.          (! Mpost_QuantZigBlock(curr->y_blocks[y][x], fba[0],
  424.                    qscaleB, FALSE)) ) {
  425.         pattern ^= 0x20;
  426.     }
  427.     if ( (pattern & 0x10) && 
  428.          (! Mpost_QuantZigBlock(curr->y_blocks[y][x+1], fba[1],
  429.                    qscaleB, FALSE)) ) {
  430.         pattern ^= 0x10;
  431.     }
  432.     if ( (pattern & 0x8) && 
  433.          (! Mpost_QuantZigBlock(curr->y_blocks[y+1][x], fba[2],
  434.                    qscaleB, FALSE)) ) {
  435.         pattern ^= 0x8;
  436.     }
  437.     if ( (pattern & 0x4) && 
  438.          (! Mpost_QuantZigBlock(curr->y_blocks[y+1][x+1], fba[3],
  439.                    qscaleB, FALSE)) ) {
  440.         pattern ^= 0x4;
  441.     }
  442.     if ( (pattern & 0x2) && 
  443.          (! Mpost_QuantZigBlock(curr->cb_blocks[y >> 1][x >> 1], fba[4],
  444.                    qscaleB, FALSE)) ) {
  445.         pattern ^= 0x2;
  446.     }
  447.     if ( (pattern & 0x1) && 
  448.          (! Mpost_QuantZigBlock(curr->cr_blocks[y >> 1][x >> 1], fba[5],
  449.                    qscaleB, FALSE)) ) {
  450.         pattern ^= 0x1;
  451.     }
  452.  
  453.             if ( printSNR ) {
  454.             if ( pattern & 0x20 ) {
  455.                 Mpost_UnQuantZigBlock(fba[0], dec[0], qscaleB, FALSE);
  456.             } else {
  457.                 bzero((char *)dec[0], sizeof(Block));
  458.             }
  459.             if ( pattern & 0x10 ) {
  460.                 Mpost_UnQuantZigBlock(fba[1], dec[1], qscaleB, FALSE);
  461.             } else {
  462.                 bzero((char *)dec[1], sizeof(Block));
  463.             }
  464.             if ( pattern & 0x8 ) {
  465.                 Mpost_UnQuantZigBlock(fba[2], dec[2], qscaleB, FALSE);
  466.             } else {
  467.                 bzero((char *)dec[2], sizeof(Block));
  468.             }
  469.             if ( pattern & 0x4 ) {
  470.                 Mpost_UnQuantZigBlock(fba[3], dec[3], qscaleB, FALSE);
  471.             } else {
  472.                 bzero((char *)dec[3], sizeof(Block));
  473.             }
  474.             if ( pattern & 0x2 ) {
  475.                 Mpost_UnQuantZigBlock(fba[4], dec[4], qscaleB, FALSE);
  476.             } else {
  477.                 bzero((char *)dec[4], sizeof(Block));
  478.             }
  479.             if ( pattern & 0x1 ) {
  480.                 Mpost_UnQuantZigBlock(fba[5], dec[5], qscaleB, FALSE);
  481.             } else {
  482.                 bzero((char *)dec[5], sizeof(Block));
  483.             }
  484.  
  485.             /* now, reverse the DCT transform */
  486.             for ( index = 0; index < 6; index++ ) {
  487.                 if ( GET_ITH_BIT(pattern, 5-index) ) {
  488.                 j_rev_dct((int16 *)dec[index]);
  489.                 }
  490.             }
  491.  
  492.             /* now add the motion block */
  493.             AddBMotionBlock(dec[0], prev->decoded_y,
  494.                     next->decoded_y, y, x, mode,
  495.                     fMotionY, fMotionX, bMotionY, bMotionX);
  496.             AddBMotionBlock(dec[1], prev->decoded_y,
  497.                     next->decoded_y, y, x+1, mode,
  498.                     fMotionY, fMotionX, bMotionY, bMotionX);
  499.             AddBMotionBlock(dec[2], prev->decoded_y,
  500.                     next->decoded_y, y+1, x, mode,
  501.                     fMotionY, fMotionX, bMotionY, bMotionX);
  502.             AddBMotionBlock(dec[3], prev->decoded_y,
  503.                     next->decoded_y, y+1, x+1, mode,
  504.                     fMotionY, fMotionX, bMotionY, bMotionX);
  505.             AddBMotionBlock(dec[4], prev->decoded_cb,
  506.                     next->decoded_cb, y>>1, x>>1, mode,
  507.                     fMotionY/2, fMotionX/2,
  508.                     bMotionY/2, bMotionX/2);
  509.             AddBMotionBlock(dec[5], prev->decoded_cr,
  510.                     next->decoded_cr, y>>1, x>>1, mode,
  511.                     fMotionY/2, fMotionX/2,
  512.                     bMotionY/2, bMotionX/2);
  513.  
  514.             /* now, unblockify */
  515.             BlockToData(curr->decoded_y, dec[0], y, x);
  516.             BlockToData(curr->decoded_y, dec[1], y, x+1);
  517.             BlockToData(curr->decoded_y, dec[2], y+1, x);
  518.             BlockToData(curr->decoded_y, dec[3], y+1, x+1);
  519.             BlockToData(curr->decoded_cb, dec[4], y>>1, x>>1);
  520.             BlockToData(curr->decoded_cr, dec[5], y>>1, x>>1);
  521.             }
  522.  
  523. #ifdef BLEAH
  524.     fprintf(stdout, "BFRAME PATTERN = %d...FORW = %d, BACK = %d\n", pattern,
  525.         motionForward, motionBackward);
  526.     fprintf(stdout, "fMotionX = %d, fMotionY = %d, bMotionX = %d, bMotionY = %d\n",
  527.         fMotionX, fMotionY, bMotionX, bMotionY);
  528. #endif
  529.  
  530.         DBG_PRINT(("MB Header(%d,%d)\n", x, y));
  531.         Mhead_GenMBHeader(bb, 3 /* pict_code_type */, mbAddrInc /* addr_incr */,
  532.               0 /* mb_quant */, 0 /* q_scale */,
  533.               fCode /* forw_f_code */, fCode /* back_f_code */,
  534.               fMotionXrem /* horiz_forw_r */, fMotionYrem /* vert_forw_r */,
  535.               bMotionXrem /* horiz_back_r */, bMotionYrem /* vert_back_r */,
  536.               motionForward /* motion_forw */, fMotionXquot /* m_horiz_forw */,
  537.               fMotionYquot /* m_vert_forw */, motionBackward /* motion_back */,
  538.               bMotionXquot /* m_horiz_back */, bMotionYquot /* m_vert_back */,
  539.               pattern /* mb_pattern */, 0 /* mb_intra */);
  540.             mbAddrInc = 1;
  541.  
  542.         /* now output the difference */
  543.         for ( tempX = 0; tempX < 6; tempX++ ) {
  544.             if ( GET_ITH_BIT(pattern, 5-tempX) ) {
  545.             Mpost_RLEHuffPBlock(fba[tempX], bb);
  546.             }
  547.         }
  548.  
  549.             numBBits += (bb->cumulativeBits-totalBits);
  550.             totalBits = bb->cumulativeBits;
  551.         }
  552.         }
  553.     }
  554.     }
  555.  
  556.     if ( printSNR ) {
  557.         ComputeSNR(curr->orig_y, curr->decoded_y, Fsize_y, Fsize_x,
  558.            &snr[0], &psnr[0]);
  559.         ComputeSNR(curr->orig_cb, curr->decoded_cb, Fsize_y/2, Fsize_x/2,
  560.            &snr[1], &psnr[1]);
  561.         ComputeSNR(curr->orig_cr, curr->decoded_cr, Fsize_y/2, Fsize_x/2,
  562.            &snr[2], &psnr[2]);
  563.  
  564.     totalSNR += snr[0];
  565.     totalPSNR += psnr[0];
  566.     }
  567.  
  568. #ifdef BLEAH
  569.  
  570. if ( printSNR ) {
  571.     FILE    *fpointer;
  572.     char    fileName[256];
  573.     int    width, height;
  574.  
  575.     /* output the decoded frame */
  576.  
  577.     width = Fsize_x;
  578.     height = Fsize_y;
  579.  
  580.     sprintf(fileName, "/tmp/decoded%d.yuv", curr->id);
  581.     fprintf(stdout, "outputting to %s\n", fileName);
  582.  
  583.     fpointer = fopen(fileName, "wb");
  584.  
  585.     for ( y = 0; y < height; y++ ) {
  586.         fwrite(curr->decoded_y[y], 1, width, fpointer);
  587.     }
  588.  
  589.     for (y = 0; y < height / 2; y++) {            /* U */
  590.         fwrite(curr->decoded_cb[y], 1, width / 2, fpointer);
  591.     }
  592.  
  593.     for (y = 0; y < height / 2; y++) {            /* V */
  594.         fwrite(curr->decoded_cr[y], 1, width / 2, fpointer);
  595.     }
  596.  
  597.     fclose(fpointer);
  598. }
  599. #endif
  600.  
  601.     Mhead_GenSliceEnder(bb);
  602.  
  603.     times(&timeBuffer);
  604.     endTime = timeBuffer.tms_utime + timeBuffer.tms_stime;
  605.     totalTime += (endTime-startTime);
  606.  
  607.     if ( (! childProcess) && frameSummary ) {
  608.     fprintf(stdout, "FRAME %d (B):  I BLOCKS:  %d;  B BLOCKS:  %d   SKIPPED:  %d (%ld seconds)\n",
  609.         curr->id, numIBlocks, numBBlocks, numSkipped, (long)((endTime-startTime)/60));
  610.     if ( printSNR )
  611.         fprintf(stdout, "FRAME %d:  SNR:  %.1f\t%.1f\t%.1f\tPSNR:  %.1f\t%.1f\t%.1f\n",
  612.             curr->id, snr[0], snr[1], snr[2],
  613.             psnr[0], psnr[1], psnr[2]);
  614.     }
  615.  
  616.     numFrameBits += (bb->cumulativeBits-totalFrameBits);
  617.     numBIBlocks += numIBlocks;
  618.     numBBBlocks += numBBlocks;
  619.     numBSkipped += numSkipped;
  620.     numBIBits += numIBits;
  621.     numBBBits += numBBits;
  622. }
  623.  
  624.  
  625. /*===========================================================================*
  626.  *
  627.  * SetBQScale
  628.  *
  629.  *    set the B-frame Q-scale
  630.  *
  631.  * RETURNS:    nothing
  632.  *
  633.  * SIDE EFFECTS:    qscaleB
  634.  *
  635.  *===========================================================================*/
  636. void
  637. SetBQScale(qB)
  638.     int qB;
  639. {
  640.     qscaleB = qB;
  641. }
  642.  
  643.  
  644. /*===========================================================================*
  645.  *
  646.  * GetBQScale
  647.  *
  648.  *    get the B-frame Q-scale
  649.  *
  650.  * RETURNS:    the Q-scale
  651.  *
  652.  * SIDE EFFECTS:    none
  653.  *
  654.  *===========================================================================*/
  655. int
  656. GetBQScale()
  657. {
  658.     return qscaleB;
  659. }
  660.  
  661.  
  662. /*===========================================================================*
  663.  *
  664.  * ResetBFrameStats
  665.  *
  666.  *    reset the B-frame stats
  667.  *
  668.  * RETURNS:    nothing
  669.  *
  670.  * SIDE EFFECTS:    none
  671.  *
  672.  *===========================================================================*/
  673. void
  674. ResetBFrameStats()
  675. {
  676.     numBIBlocks = 0;
  677.     numBBBlocks = 0;
  678.     numBSkipped = 0;
  679.     numBIBits = 0;
  680.     numBBBits = 0;
  681.     numFrames = 0;
  682.     numFrameBits = 0;
  683.     totalTime = 0;
  684. }
  685.  
  686.  
  687. /*===========================================================================*
  688.  *
  689.  * ShowBFrameSummary
  690.  *
  691.  *    print out statistics on all B-frames
  692.  *
  693.  * RETURNS:    nothing
  694.  *
  695.  * SIDE EFFECTS:    none
  696.  *
  697.  *===========================================================================*/
  698. void
  699. ShowBFrameSummary(inputFrameBits, totalBits, fpointer)
  700.     int inputFrameBits;
  701.     int32 totalBits;
  702.     FILE *fpointer;
  703. {
  704.     if ( numFrames == 0 ) {
  705.     return;
  706.     }
  707.  
  708.     fprintf(fpointer, "-------------------------\n");
  709.     fprintf(fpointer, "*****B FRAME SUMMARY*****\n");
  710.     fprintf(fpointer, "-------------------------\n");
  711.  
  712.     if ( numBIBlocks != 0 ) {
  713.     fprintf(fpointer, "  I Blocks:  %5d     (%6d bits)     (%5d bpb)\n",
  714.         numBIBlocks, numBIBits, numBIBits/numBIBlocks);
  715.     } else {
  716.     fprintf(fpointer, "  I Blocks:  %5d\n", 0);
  717.     }
  718.  
  719.     if ( numBBBlocks != 0 ) {
  720.     fprintf(fpointer, "  B Blocks:  %5d     (%6d bits)     (%5d bpb)\n",
  721.         numBBBlocks, numBBBits, numBBBits/numBBBlocks);
  722.     } else {
  723.     fprintf(fpointer, "  B Blocks:  %5d\n", 0);
  724.     }
  725.  
  726.     fprintf(fpointer, "  Skipped:   %5d\n", numBSkipped);
  727.  
  728.     fprintf(fpointer, "  Frames:    %5d     (%6d bits)     (%5d bpf)     (%2.1f%% of total)\n",
  729.         numFrames, numFrameBits, numFrameBits/numFrames,
  730.         100.0*(float)numFrameBits/(float)totalBits);        
  731.     fprintf(fpointer, "  Compression:  %3d:1\n",
  732.         numFrames*inputFrameBits/numFrameBits);
  733.     if ( printSNR )
  734.     fprintf(fpointer, "  Avg Y SNR/PSNR:  %.1f     %.1f\n",
  735.         totalSNR/(float)numFrames, totalPSNR/(float)numFrames);
  736.     fprintf(fpointer, "  Seconds:  %9ld     (%9ld spf)     (%9ld bps)\n",
  737.         (long)(totalTime/60), (long)(totalTime/(60*numFrames)),
  738.         (long)(60.0*(float)numFrames*(float)inputFrameBits/(float)totalTime));
  739. }
  740.  
  741.  
  742. /*===========================================================================*
  743.  *
  744.  * ComputeBMotionLumBlock
  745.  *
  746.  *    compute the luminance block resulting from motion compensation
  747.  *
  748.  * RETURNS:    motionBlock modified
  749.  *
  750.  * SIDE EFFECTS:    none
  751.  *
  752.  * PRECONDITION:    the motion vectors must be valid!
  753.  *
  754.  *===========================================================================*/
  755. void
  756. ComputeBMotionLumBlock(prev, next, by, bx, mode, fmy, fmx, bmy, bmx, motionBlock)
  757.     MpegFrame *prev;
  758.     MpegFrame *next;
  759.     int by;
  760.     int bx;
  761.     int mode;
  762.     int fmy;
  763.     int fmx;
  764.     int bmy;
  765.     int bmx;
  766.     LumBlock motionBlock;
  767. {
  768.     LumBlock    prevBlock, nextBlock;
  769.     register int    y, x;
  770.  
  771.     switch(mode) {
  772.     case MOTION_FORWARD:
  773.         ComputeMotionLumBlock(prev, by, bx, fmy, fmx, motionBlock);
  774.         break;
  775.     case MOTION_BACKWARD:
  776.         ComputeMotionLumBlock(next, by, bx, bmy, bmx, motionBlock);
  777.         break;
  778.     case MOTION_INTERPOLATE:
  779.         ComputeMotionLumBlock(prev, by, bx, fmy, fmx, prevBlock);
  780.         ComputeMotionLumBlock(next, by, bx, bmy, bmx, nextBlock);
  781.  
  782.         for ( y = 0; y < 16; y++ ) {
  783.         for ( x = 0; x < 16; x++ ) {
  784.             motionBlock[y][x] = (prevBlock[y][x]+nextBlock[y][x]+1)/2;
  785.         }
  786.         }
  787.         break;
  788.     }
  789. }
  790.  
  791.  
  792. /*===========================================================================*
  793.  *
  794.  * EstimateSecondsPerBFrame
  795.  *
  796.  *    estimate the seconds to compute a B-frame
  797.  *
  798.  * RETURNS:    the time, in seconds
  799.  *
  800.  * SIDE EFFECTS:    none
  801.  *
  802.  *===========================================================================*/
  803. float
  804. EstimateSecondsPerBFrame()
  805. {
  806.     if ( numFrames == 0 ) {
  807.     return 20.0;
  808.     } else {
  809.     return (float)totalTime/(60.0*(float)numFrames);
  810.     }
  811. }
  812.  
  813.  
  814. /*=====================*
  815.  * INTERNAL PROCEDURES *
  816.  *=====================*/
  817.  
  818. /*===========================================================================*
  819.  *
  820.  * ComputeBMotionBlock
  821.  *
  822.  *    compute the block resulting from motion compensation
  823.  *
  824.  * RETURNS:    motionBlock is modified
  825.  *
  826.  * SIDE EFFECTS:    none
  827.  *
  828.  * PRECONDITION:    the motion vectors must be valid!
  829.  *
  830.  *===========================================================================*/
  831. static void
  832. ComputeBMotionBlock(prev, next, by, bx, mode, fmy, fmx, bmy, bmx, motionBlock, type)
  833.     MpegFrame *prev;
  834.     MpegFrame *next;
  835.     int by;
  836.     int bx;
  837.     int mode;
  838.     int fmy;
  839.     int fmx;
  840.     int bmy;
  841.     int bmx;
  842.     Block motionBlock;
  843.     int type;
  844. {
  845.     Block    prevBlock, nextBlock;
  846.     register int    y, x;
  847.  
  848.     switch(mode) {
  849.     case MOTION_FORWARD:
  850.         if ( type == LUM_BLOCK ) {
  851.         ComputeMotionBlock(prev->ref_y, by, bx, fmy, fmx, motionBlock);
  852.         } else if ( type == CB_BLOCK ) {
  853.         ComputeMotionBlock(prev->ref_cb, by, bx, fmy, fmx, motionBlock);
  854.         } else if ( type == CR_BLOCK ) {
  855.         ComputeMotionBlock(prev->ref_cr, by, bx, fmy, fmx, motionBlock);
  856.         }
  857.         break;
  858.     case MOTION_BACKWARD:
  859.         if ( type == LUM_BLOCK ) {
  860.         ComputeMotionBlock(next->ref_y, by, bx, bmy, bmx, motionBlock);
  861.         } else if ( type == CB_BLOCK ) {
  862.         ComputeMotionBlock(next->ref_cb, by, bx, bmy, bmx, motionBlock);
  863.         } else if ( type == CR_BLOCK ) {
  864.         ComputeMotionBlock(next->ref_cr, by, bx, bmy, bmx, motionBlock);
  865.         }
  866.         break;
  867.     case MOTION_INTERPOLATE:
  868.         if ( type == LUM_BLOCK ) {
  869.         ComputeMotionBlock(prev->ref_y, by, bx, fmy, fmx, prevBlock);
  870.         ComputeMotionBlock(next->ref_y, by, bx, bmy, bmx, nextBlock);
  871.         } else if ( type == CB_BLOCK ) {
  872.         ComputeMotionBlock(prev->ref_cb, by, bx, fmy, fmx, prevBlock);
  873.         ComputeMotionBlock(next->ref_cb, by, bx, bmy, bmx, nextBlock);
  874.         } else if ( type == CR_BLOCK ) {
  875.         ComputeMotionBlock(prev->ref_cr, by, bx, fmy, fmx, prevBlock);
  876.         ComputeMotionBlock(next->ref_cr, by, bx, bmy, bmx, nextBlock);
  877.         }
  878.  
  879.         for ( y = 0; y < 8; y++ ) {
  880.         for ( x = 0; x < 8; x++ ) {
  881.             motionBlock[y][x] = (prevBlock[y][x]+nextBlock[y][x]+1)/2;
  882.         }
  883.         }
  884.         break;
  885.     }
  886. }
  887.  
  888.  
  889. /*===========================================================================*
  890.  *
  891.  * ComputeBDiffDCTs
  892.  *
  893.  *    compute the DCT of the error term
  894.  *
  895.  * RETURNS:    appropriate blocks of current will contain the DCTs
  896.  *
  897.  * SIDE EFFECTS:    none
  898.  *
  899.  * PRECONDITION:    the motion vectors must be valid!
  900.  *
  901.  *===========================================================================*/
  902. static void
  903. ComputeBDiffDCTs(current, prev, next, by, bx, mode, fmy, fmx, bmy, bmx, pattern)
  904.     MpegFrame *current;
  905.     MpegFrame *prev;
  906.     MpegFrame *next;
  907.     int by;
  908.     int bx;
  909.     int mode;
  910.     int fmy;
  911.     int fmx;
  912.     int bmy;
  913.     int bmx;
  914.     int pattern;
  915. {
  916.     Block   motionBlock;
  917.  
  918.     if ( pattern & 0x20 ) {
  919.     ComputeBMotionBlock(prev, next, by, bx, mode, fmy, fmx,
  920.                 bmy, bmx, motionBlock, LUM_BLOCK);
  921.     ComputeDiffDCTBlock(current->y_blocks[by][bx], motionBlock);
  922.     }
  923.  
  924.     if ( pattern & 0x10 ) {
  925.     ComputeBMotionBlock(prev, next, by, bx+1, mode, fmy, fmx,
  926.                 bmy, bmx, motionBlock, LUM_BLOCK);
  927.     ComputeDiffDCTBlock(current->y_blocks[by][bx+1], motionBlock);
  928.     }
  929.  
  930.     if ( pattern & 0x8 ) {
  931.     ComputeBMotionBlock(prev, next, by+1, bx, mode, fmy, fmx,
  932.                 bmy, bmx, motionBlock, LUM_BLOCK);
  933.     ComputeDiffDCTBlock(current->y_blocks[by+1][bx], motionBlock);
  934.     }
  935.  
  936.     if ( pattern & 0x4 ) {
  937.     ComputeBMotionBlock(prev, next, by+1, bx+1, mode, fmy, fmx,
  938.                 bmy, bmx, motionBlock, LUM_BLOCK);
  939.     ComputeDiffDCTBlock(current->y_blocks[by+1][bx+1], motionBlock);
  940.     }
  941.  
  942.     if ( pattern & 0x2 ) {
  943.     ComputeBMotionBlock(prev, next, by>>1, bx>>1, mode, fmy/2, fmx/2,
  944.                 bmy/2, bmx/2, motionBlock, CB_BLOCK);
  945.     ComputeDiffDCTBlock(current->cb_blocks[by >> 1][bx >> 1], motionBlock);
  946.     }
  947.  
  948.     if ( pattern & 0x1 ) {
  949.     ComputeBMotionBlock(prev, next, by>>1, bx>>1, mode, fmy/2, fmx/2,
  950.                 bmy/2, bmx/2, motionBlock, CR_BLOCK);
  951.     ComputeDiffDCTBlock(current->cr_blocks[by >> 1][bx >> 1], motionBlock);
  952.     }
  953. }
  954.  
  955.  
  956. /*===========================================================================*
  957.  *
  958.  *                USER-MODIFIABLE
  959.  *
  960.  * DoBIntraCode
  961.  *
  962.  *    decides if this block should be coded as intra-block
  963.  *
  964.  * RETURNS:    TRUE if intra-coding should be used; FALSE otherwise
  965.  *
  966.  * SIDE EFFECTS:    none
  967.  *
  968.  * PRECONDITION:    the motion vectors must be valid!
  969.  *
  970.  *===========================================================================*/
  971. static boolean
  972. DoBIntraCode(current, prev, next, by, bx, mode, fmy, fmx, bmy, bmx)
  973.     MpegFrame *current;
  974.     MpegFrame *prev;
  975.     MpegFrame *next;
  976.     int by;
  977.     int bx;
  978.     int mode;
  979.     int fmy;
  980.     int fmx;
  981.     int bmy;
  982.     int bmx;
  983. {
  984.     int        x, y;
  985.     int32 sum = 0, vard = 0, varc = 0, dif;
  986.     int32 currPixel, prevPixel;
  987.     LumBlock    motionBlock;
  988.     int        fy, fx;
  989.  
  990.     ComputeBMotionLumBlock(prev, next, by, bx, mode, fmy, fmx,
  991.                bmy, bmx, motionBlock);
  992.  
  993.     MOTION_TO_FRAME_COORD(by, bx, 0, 0, fy, fx);
  994.  
  995.     for ( y = 0; y < 16; y++ ) {
  996.     for ( x = 0; x < 16; x++ ) {
  997.         currPixel = current->orig_y[fy+y][fx+x];
  998.         prevPixel = motionBlock[y][x];
  999.  
  1000.         sum += currPixel;
  1001.         varc += currPixel*currPixel;
  1002.  
  1003.         dif = currPixel - prevPixel;
  1004.         vard += dif*dif;
  1005.     }
  1006.     }
  1007.  
  1008.     vard /= 256;    /* assumes mean is close to zero */
  1009.     varc = varc/256 - (sum/256)*(sum/256);
  1010.  
  1011.     if ( vard <= 64 ) {
  1012.     return FALSE;
  1013.     } else if ( vard < varc ) {
  1014.     return FALSE;
  1015.     } else {
  1016.     return TRUE;
  1017.     }
  1018. }
  1019.  
  1020. /*===========================================================================*
  1021.  *
  1022.  *                USER-MODIFIABLE
  1023.  *
  1024.  * MotionSufficient
  1025.  *
  1026.  *    decides if this motion vector is sufficient without DCT coding
  1027.  *
  1028.  * RETURNS:    TRUE if no DCT is needed; FALSE otherwise
  1029.  *
  1030.  * SIDE EFFECTS:    none
  1031.  *
  1032.  * PRECONDITION:    the motion vectors must be valid!
  1033.  *
  1034.  *===========================================================================*/
  1035. static boolean
  1036. MotionSufficient(currBlock, prev, next, by, bx, mode, fmy, fmx, bmy, bmx)
  1037.     LumBlock currBlock;
  1038.     MpegFrame *prev;
  1039.     MpegFrame *next;
  1040.     int by;
  1041.     int bx;
  1042.     int mode;
  1043.     int fmy;
  1044.     int fmx;
  1045.     int bmy;
  1046.     int bmx;
  1047. {
  1048.     LumBlock   motionBlock;
  1049.  
  1050.     if ( mode != MOTION_BACKWARD ) {
  1051.     /* check forward motion for bounds */
  1052.     if ( (by*DCTSIZE+(fmy-1)/2 < 0) || ((by+2)*DCTSIZE+(fmy+1)/2-1 >= Fsize_y) ) {
  1053.         return FALSE;
  1054.     }
  1055.     if ( (bx*DCTSIZE+(fmx-1)/2 < 0) || ((bx+2)*DCTSIZE+(fmx+1)/2-1 >= Fsize_x) ) {
  1056.         return FALSE;
  1057.     }
  1058.     }
  1059.  
  1060.     if ( mode != MOTION_FORWARD ) {
  1061.     /* check backward motion for bounds */
  1062.     if ( (by*DCTSIZE+(bmy-1)/2 < 0) || ((by+2)*DCTSIZE+(bmy+1)/2-1 >= Fsize_y) ) {
  1063.         return FALSE;
  1064.     }
  1065.     if ( (bx*DCTSIZE+(bmx-1)/2 < 0) || ((bx+2)*DCTSIZE+(bmx+1)/2-1 >= Fsize_x) ) {
  1066.         return FALSE;
  1067.     }
  1068.     }
  1069.  
  1070.     ComputeBMotionLumBlock(prev, next, by, bx, mode, fmy, fmx,
  1071.                bmy, bmx, motionBlock);
  1072.  
  1073.     return (LumBlockMAD(currBlock, motionBlock, 0x7fffffff) <= 512);
  1074. }
  1075.