home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 9 / CD_ASCQ_09_1193.iso / news / 4441 / mpegcode / src / mpeg.c < prev    next >
C/C++ Source or Header  |  1993-09-27  |  29KB  |  1,102 lines

  1. /*===========================================================================*
  2.  * mpeg.c                                     *
  3.  *                                         *
  4.  *    Procedures to generate the MPEG sequence                 *
  5.  *                                         *
  6.  * EXPORTED PROCEDURES:                                 *
  7.  *    SetFramePattern                                 *
  8.  *    GetMPEGStream                                 *
  9.  *    IncrementTCTime                                 *
  10.  *    SetStatFileName                                 *
  11.  *    SetGOPSize                                 *
  12.  *    PrintStartStats                                 *
  13.  *                                         *
  14.  *===========================================================================*/
  15.  
  16. /*
  17.  * Copyright (c) 1993 The Regents of the University of California.
  18.  * All rights reserved.
  19.  *
  20.  * Permission to use, copy, modify, and distribute this software and its
  21.  * documentation for any purpose, without fee, and without written agreement is
  22.  * hereby granted, provided that the above copyright notice and the following
  23.  * two paragraphs appear in all copies of this software.
  24.  *
  25.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  26.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  27.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  28.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29.  *
  30.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  31.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  32.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  33.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  34.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  35.  */
  36.  
  37. /*  
  38.  *  $Header: /n/picasso/users/keving/encode/src/RCS/mpeg.c,v 1.6 1993/07/22 22:23:43 keving Exp keving $
  39.  *  $Log: mpeg.c,v $
  40.  * Revision 1.6  1993/07/22  22:23:43  keving
  41.  * nothing
  42.  *
  43.  * Revision 1.5  1993/06/30  20:06:09  keving
  44.  * nothing
  45.  *
  46.  * Revision 1.4  1993/06/03  21:08:08  keving
  47.  * nothing
  48.  *
  49.  * Revision 1.3  1993/02/19  18:10:12  keving
  50.  * nothing
  51.  *
  52.  * Revision 1.2  1993/02/17  23:18:20  dwallach
  53.  * checkin prior to keving's joining the project
  54.  *
  55.  */
  56.  
  57.  
  58. /*==============*
  59.  * HEADER FILES *
  60.  *==============*/
  61.  
  62. #include "all.h"
  63. #include <time.h>
  64. #include <errno.h>
  65. #include "mtypes.h"
  66. #include "frames.h"
  67. #include "search.h"
  68. #include "mpeg.h"
  69. #include "prototypes.h"
  70. #include "parallel.h"
  71. #include "param.h"
  72. #include "readframe.h"
  73. #include "fsize.h"
  74. #include "mheaders.h"
  75.  
  76.  
  77. /*===========*
  78.  * CONSTANTS *
  79.  *===========*/
  80.  
  81. #define FRAMES_PER_SECOND   30
  82.  
  83.  
  84. /*==================*
  85.  * STATIC VARIABLES *
  86.  *==================*/
  87.  
  88. static int32   diffTime;
  89. static int framesOutput;
  90. static int        realStart, realEnd;
  91. static int    currentGOP;
  92. static int        timeMask;
  93. static int        numI, numP, numB;
  94.  
  95.  
  96. /*==================*
  97.  * GLOBAL VARIABLES *
  98.  *==================*/
  99.  
  100. int        gopSize = 100;  /* default */
  101. int32        tc_hrs, tc_min, tc_sec, tc_pict;
  102. int        totalFramesSent;
  103. int        yuvWidth, yuvHeight;
  104. FrameTable *frameTable;
  105. char        currentPath[MAXPATHLEN];
  106. char        statFileName[256];
  107. time_t        timeStart, timeEnd;
  108. FILE       *statFile;
  109. char       *framePattern;
  110. int        framePatternLen;
  111. int        referenceFrame;
  112.  
  113.  
  114. /*===============================*
  115.  * INTERNAL PROCEDURE prototypes *
  116.  *===============================*/
  117.  
  118. static void    ShowRemainingTime _ANSI_ARGS_((void));
  119. static void    ComputeDHMSTime _ANSI_ARGS_((int32 someTime, char *timeText));
  120. static void    ComputeGOPFrames _ANSI_ARGS_((int whichGOP, int *firstFrame,
  121.                           int *lastFrame, int numFrames));
  122. static void    PrintEndStats _ANSI_ARGS_((int inputFrameBits, int32 totalBits));
  123. static void    ComputeFrameTable _ANSI_ARGS_((void));
  124. static void    ProcessNonBFrame _ANSI_ARGS_((FrameTable *entry,
  125.                           BitBucket *bb, int lastFrame,
  126.                           char *outputFileName,
  127.                           boolean remoteIO));
  128.  
  129.  
  130. /*=====================*
  131.  * EXPORTED PROCEDURES *
  132.  *=====================*/
  133.  
  134. /*===========================================================================*
  135.  *
  136.  * SetReferenceFrameType
  137.  *
  138.  *    set the reference frame type to be original or decoded
  139.  *
  140.  * RETURNS:    nothing
  141.  *
  142.  * SIDE EFFECTS:    referenceFrame
  143.  *
  144.  *===========================================================================*/
  145. void
  146. SetReferenceFrameType(type)
  147.     char *type;
  148. {
  149.     if ( strcmp(type, "ORIGINAL") == 0 ) {
  150.     referenceFrame = ORIGINAL_FRAME;
  151.     } else if ( strcmp(type, "DECODED") == 0 ) {
  152.     referenceFrame = DECODED_FRAME;
  153.     } else {
  154.     fprintf(stderr, "ERROR:  Illegal reference frame type: '%s'\n",
  155.         type);
  156.     exit(1);
  157.     }
  158. }
  159.  
  160.  
  161. /*===========================================================================*
  162.  *
  163.  * SetFramePattern
  164.  *
  165.  *    set the IPB pattern; calls ComputeFrameTable to set up table
  166.  *
  167.  * RETURNS:    nothing
  168.  *
  169.  * SIDE EFFECTS:    framePattern, framePatternLen, frameTable
  170.  *
  171.  *===========================================================================*/
  172. void
  173. SetFramePattern(pattern)
  174.     char *pattern;
  175. {
  176.     int len = strlen(pattern);
  177.     char *buf;
  178.     int index;
  179.  
  180.     if ( ! pattern ) {
  181.     fprintf(stderr, "pattern cannot be NULL\n");
  182.     exit(1);
  183.     }
  184.  
  185.     if ( pattern[0] != 'i' && pattern[0] != 'I' ) {
  186.     fprintf(stderr, "first frame must be 'i'\n");
  187.     exit(1);
  188.     }
  189.  
  190.     buf = (char *)malloc(sizeof(char)*(len+1));
  191.     ERRCHK(buf, "malloc");
  192.  
  193.     for ( index = 0; index < len; index++ ) {
  194.     switch( pattern[index] ) {
  195.         case 'i':    case 'I':    buf[index] = 'i';        break;
  196.         case 'p':    case 'P':    buf[index] = 'p';        break;
  197.         case 'b':    case 'B':    buf[index] = 'b';        break;
  198.         default:
  199.         fprintf(stderr, "Frame type '%c' not supported.\n", pattern[index]);
  200.         exit(1);
  201.     }
  202.     }
  203.     buf[len] = 0;
  204.  
  205.     framePattern = buf;
  206.     framePatternLen = len;
  207.  
  208.     ComputeFrameTable();
  209. }
  210.  
  211.  
  212. /*===========================================================================*
  213.  *
  214.  * GenMPEGStream
  215.  *
  216.  *    generate an MPEG sequence stream (generally)
  217.  *    if whichGOP == frameStart == -1 then does complete MPEG sequence
  218.  *    if whichGOP != -1 then does numbered GOP only (without sequence
  219.  *                   header)
  220.  *    if frameStart != -1 then does numbered frames only (without any
  221.  *                 sequence or GOP headers)               
  222.  *    if remoteIO == TRUE then uses the I/O server
  223.  *
  224.  * RETURNS:    amount of time it took
  225.  *
  226.  * SIDE EFFECTS:    too numerous to mention
  227.  *
  228.  *===========================================================================*/
  229. int32
  230. GenMPEGStream(whichGOP, frameStart, frameEnd, numFrames, ofp, outputFileName,
  231.           remoteIO)
  232.     int whichGOP;
  233.     int frameStart;
  234.     int frameEnd;
  235.     int numFrames;
  236.     FILE *ofp;
  237.     char *outputFileName;
  238.     boolean remoteIO;
  239. {
  240.     BitBucket *bb;
  241.     int i;
  242.     char frameType;
  243.     MpegFrame    *frame;
  244.     FrameTable    *entry = NULL;
  245.     int        firstFrame, lastFrame;
  246.     int  inputFrameBits = 0;
  247.     char    inputFileName[1024];
  248.  
  249.     ResetIFrameStats();
  250.     ResetPFrameStats();
  251.     ResetBFrameStats();
  252.  
  253.     Fsize_Reset();
  254.  
  255.     framesOutput = 0;
  256.  
  257.     if ( whichGOP != -1 ) {
  258.     ComputeGOPFrames(whichGOP, &firstFrame, &lastFrame, numFrames);
  259.  
  260.     realStart = firstFrame;
  261.     realEnd = lastFrame;
  262.     } else if ( frameStart != -1 ) {
  263.     if ( frameEnd > numFrames-1 ) {
  264.         fprintf(stdout, "ERROR:  Specified last frame is out of bounds\n");
  265.         exit(1);
  266.     }
  267.  
  268.     realStart = frameStart;
  269.     realEnd = frameEnd;
  270.  
  271.     firstFrame = frameStart;
  272.     lastFrame = frameEnd;
  273.  
  274.     /* if first frame is P or B, need to read in P or I frame before it */
  275.     if ( FRAME_TYPE(firstFrame) != 'i' ) {
  276.         entry = &(frameTable[firstFrame % framePatternLen]);
  277.  
  278.         firstFrame = firstFrame - (entry->number - entry->prev->number);
  279.     }
  280.  
  281.     /* if last frame is B, need to read in P or I frame after it */
  282.     if ( (FRAME_TYPE(lastFrame) == 'b') && (lastFrame != numFrames-1) ) {
  283.         entry = &(frameTable[lastFrame % framePatternLen]);
  284.  
  285.         lastFrame = lastFrame + (entry->next->number - entry->number);
  286.     }
  287.  
  288.     if ( lastFrame > numFrames-1 ) {        /* can't go last frame! */
  289.         lastFrame = numFrames-1;
  290.     }
  291.     } else {
  292.     firstFrame = 0;
  293.     lastFrame = numFrames-1;
  294.  
  295.     realStart = 0;
  296.     realEnd = numFrames-1;
  297.     }
  298.  
  299.     /* count number of I, P, and B frames */
  300.     numI = 0;    numP = 0;   numB = 0;
  301.     timeMask = 0;
  302.     for ( i = firstFrame; i <= lastFrame; i++ ) {
  303.     frameType = FRAME_TYPE(i);
  304.     switch(frameType) {
  305.         case 'i':    numI++;        timeMask |= 0x1;    break;
  306.         case 'p':    numP++;        timeMask |= 0x2;    break;
  307.         case 'b':    numB++;        timeMask |= 0x4;    break;
  308.     }
  309.     }
  310.  
  311.     time(&timeStart);
  312.  
  313.     if ( ! childProcess ) {
  314.     PrintStartStats(realStart, realEnd);
  315.     }
  316.  
  317.     if ( frameStart == -1 ) {
  318.     bb = Bitio_New(ofp);
  319.     } else {
  320.     bb = NULL;
  321.     }
  322.  
  323.     SetFileType();
  324.  
  325.     tc_hrs = 0;    tc_min = 0; tc_sec = 0; tc_pict = 0;
  326.     for ( i = 0; i < firstFrame; i++ ) {
  327.     IncrementTCTime();
  328.     }
  329.  
  330.     totalFramesSent = firstFrame;
  331.     currentGOP = gopSize;    /* so first I-frame generates GOP Header */
  332.  
  333.     if ( FRAME_TYPE(firstFrame) == 'b' ) {
  334.     /* need to load in previous frame; call it an I frame */
  335.     frame = Frame_New(firstFrame-1, 'i');
  336.     if ( remoteIO ) {
  337.         GetRemoteFrame(frame, firstFrame-1);
  338.     } else {
  339.         GetNthInputFileName(inputFileName, firstFrame-1);
  340.         ReadFrame(frame, inputFileName, inputConversion, TRUE);
  341.     }
  342.  
  343.     /* should put in the correct frameTable place */
  344.     }
  345.  
  346.     for ( i = firstFrame; i <= lastFrame; i++) {
  347.     frameType = FRAME_TYPE(i);
  348.  
  349.     if ( frameType == 'b' ) {
  350.         continue;
  351.     }
  352.  
  353.     frame = Frame_New(i, frameType);
  354.     if ( (i != firstFrame) && ((i % framePatternLen) == 0) ) {
  355.         entry = &(frameTable[framePatternLen]);
  356.     } else {
  357.         entry = &(frameTable[i % framePatternLen]);
  358.     }
  359.  
  360.     entry->frame = frame;
  361.  
  362.     if ( remoteIO ) {
  363.         GetRemoteFrame(frame, i);
  364.     } else {
  365.         GetNthInputFileName(inputFileName, i);
  366.         ReadFrame(frame, inputFileName, inputConversion, TRUE);
  367.     }
  368.  
  369.     if ( i == firstFrame ) {
  370.         inputFrameBits = 24*Fsize_x*Fsize_y;
  371.         SetBlocksPerSlice();
  372.  
  373.         if ( (whichGOP == -1) && (frameStart == -1) ) {
  374.         DBG_PRINT(("Generating sequence header\n"));
  375.         Mhead_GenSequenceHeader(bb, Fsize_x, Fsize_y, /* pratio */ 1,
  376.                /* pict_rate */ -1, /* bit_rate */ -1,
  377.                /* buf_size */ -1, /*c_param_flag */ 1,
  378.                /* iq_matrix */ NULL, /* niq_matrix */ NULL,
  379.                /* ext_data */ NULL, /* ext_data_size */ 0,
  380.                /* user_data */ NULL, /* user_data_size */ 0);
  381.         }
  382.     }
  383.  
  384.     ProcessNonBFrame(entry, bb, lastFrame, outputFileName, remoteIO);
  385.  
  386.     /* in case this is first frame of pattern sequence; put it    
  387.         back to 0 */
  388.     if ( entry == &frameTable[framePatternLen]) {
  389.         frameTable[0].frame = frame;
  390.     }
  391.     }
  392.  
  393.     if ( entry->frame != NULL ) {
  394.     Frame_Free(entry->frame);
  395.     }
  396.  
  397.     /* SEQUENCE END CODE */
  398.     if ( (whichGOP == -1) && (frameStart == -1) ) {
  399.     Mhead_GenSequenceEnder(bb);
  400.     }
  401.  
  402.     if ( frameStart == -1 ) {
  403.     Bitio_Flush(bb);
  404.     fclose(ofp);
  405.  
  406.     time(&timeEnd);
  407.     diffTime = (int32)(timeEnd-timeStart);
  408.  
  409.     if ( ! childProcess ) {
  410.         PrintEndStats(inputFrameBits, bb->cumulativeBits);
  411.     }
  412.     } else {
  413.     time(&timeEnd);
  414.     diffTime = (int32)(timeEnd-timeStart);
  415.  
  416.     if ( ! childProcess ) {
  417.         PrintEndStats(inputFrameBits, 1);
  418.     }
  419.     }
  420.  
  421.     if ( childProcess ) {
  422.     NoteFrameDone(frameStart, frameEnd);
  423.     }
  424.  
  425.     return diffTime;
  426. }
  427.  
  428.  
  429. /*===========================================================================*
  430.  *
  431.  * IncrementTCTime
  432.  *
  433.  *    increment the tc time by one second (and update min, hrs if necessary)
  434.  *    also increments totalFramesSent
  435.  *
  436.  * RETURNS:    nothing
  437.  *
  438.  * SIDE EFFECTS:    totalFramesSent, tc_pict, tc_sec, tc_min, tc_hrs
  439.  *
  440.  *===========================================================================*/
  441. void
  442. IncrementTCTime()
  443. {
  444.     totalFramesSent++;
  445.     tc_pict++;
  446.     if ( tc_pict == FRAMES_PER_SECOND ) {
  447.     tc_pict = 0;
  448.     tc_sec++;
  449.     if ( tc_sec == 60 ) {
  450.         tc_sec = 0;
  451.         tc_min++;
  452.         if ( tc_min == 60 ) {
  453.         tc_min = 0;
  454.         tc_hrs++;
  455.         }
  456.     }
  457.     }
  458. }
  459.  
  460.  
  461. /*===========================================================================*
  462.  *
  463.  * SetStatFileName
  464.  *
  465.  *    set the statistics file name
  466.  *
  467.  * RETURNS:    nothing
  468.  *
  469.  * SIDE EFFECTS:    statFileName
  470.  *
  471.  *===========================================================================*/
  472. void
  473. SetStatFileName(fileName)
  474.     char *fileName;
  475. {
  476.     strcpy(statFileName, fileName);
  477. }
  478.  
  479.  
  480. /*===========================================================================*
  481.  *
  482.  * SetGOPSize
  483.  *
  484.  *    set the GOP size (frames per GOP)
  485.  *
  486.  * RETURNS:    nothing
  487.  *
  488.  * SIDE EFFECTS:    gopSize
  489.  *
  490.  *===========================================================================*/
  491. void
  492. SetGOPSize(size)
  493.     int size;
  494. {
  495.     gopSize = size;
  496. }
  497.  
  498.  
  499. /*===========================================================================*
  500.  *
  501.  * PrintStartStats
  502.  *
  503.  *    print out the starting statistics (stuff from the param file)
  504.  *    firstFrame, lastFrame represent the first, last frames to be
  505.  *    encoded
  506.  *
  507.  * RETURNS:    nothing
  508.  *
  509.  * SIDE EFFECTS:    none
  510.  *
  511.  *===========================================================================*/
  512. void
  513. PrintStartStats(firstFrame, lastFrame)
  514.     int firstFrame;
  515.     int lastFrame;
  516. {
  517.     FILE *fpointer;
  518.     register int i;
  519.     char    inputFileName[1024];
  520.  
  521.     if ( statFileName[0] == '\0' ) {
  522.     statFile = NULL;
  523.     } else {
  524.     statFile = fopen(statFileName, "a");    /* open for appending */
  525.     if ( statFile == NULL ) {
  526.         fprintf(stderr, "ERROR:  Could not open stat file:  %s\n", statFileName);
  527.         fprintf(stderr, "        Sending statistics to stdout only.\n");
  528.         fprintf(stderr, "\n\n");
  529.     } else {
  530.         fprintf(stdout, "Appending statistics to file:  %s\n", statFileName);
  531.         fprintf(stdout, "\n\n");
  532.     }
  533.     }
  534.     
  535.     for ( i = 0; i < 2; i++ ) {
  536.     if ( i == 0 ) {
  537.         fpointer = stdout;
  538.     } else if ( statFile != NULL ) {
  539.         fpointer = statFile;
  540.     } else {
  541.         continue;
  542.     }
  543.  
  544.     fprintf(fpointer, "MPEG ENCODER STATS\n");
  545.     fprintf(fpointer, "------------------\n");
  546.     fprintf(fpointer, "TIME STARTED:  %s", ctime(&timeStart));
  547.     if ( getenv("HOST") != NULL ) {
  548.         fprintf(fpointer, "MACHINE:  %s\n", getenv("HOST"));
  549.     } else {
  550.         fprintf(fpointer, "MACHINE:  unknown\n");
  551.     }
  552.  
  553.     if ( firstFrame == -1 ) {
  554.         fprintf(fpointer, "OUTPUT:  %s\n", outputFileName);
  555.     } else {
  556.         GetNthInputFileName(inputFileName, firstFrame);
  557.         fprintf(fpointer, "FIRST FILE:  %s/%s\n", currentPath, inputFileName);
  558.         GetNthInputFileName(inputFileName, lastFrame);
  559.         fprintf(fpointer, "LAST FILE:  %s/%s\n", currentPath,
  560.             inputFileName);
  561.     }
  562.     fprintf(fpointer, "PATTERN:  %s\n", framePattern);
  563.     fprintf(fpointer, "GOP_SIZE:  %d\n", gopSize);
  564.     fprintf(fpointer, "SLICES PER FRAME:  %d\n", slicesPerFrame);
  565.     fprintf(fpointer, "RANGE:  +/-%d\n", searchRange/2);
  566.     fprintf(fpointer, "FULL SEARCH:  %d\n", pixelFullSearch);
  567.     fprintf(fpointer, "PSEARCH:  %s\n", PSearchName());
  568.     fprintf(fpointer, "BSEARCH:  %s\n", BSearchName());
  569.     fprintf(fpointer, "QSCALE:  %d %d %d\n", qscaleI, 
  570.         GetPQScale(), GetBQScale());
  571.     if ( referenceFrame == DECODED_FRAME ) {
  572.         fprintf(fpointer, "REFERENCE FRAME:  DECODED\n");
  573.     } else if ( referenceFrame == ORIGINAL_FRAME ) {
  574.         fprintf(fpointer, "REFERENCE FRAME:  ORIGINAL\n");
  575.     } else {
  576.         fprintf(stderr, "ERROR:  Illegal referenceFrame!!!\n");
  577.         exit(1);
  578.     }
  579.     }
  580.  
  581.     fprintf(stdout, "\n\n");
  582. }
  583.  
  584.  
  585. /*=====================*
  586.  * INTERNAL PROCEDURES *
  587.  *=====================*/
  588.  
  589. /*===========================================================================*
  590.  *
  591.  * ComputeDHMSTime
  592.  *
  593.  *    turn some number of seconds (someTime) into a string which
  594.  *    summarizes that time according to scale (days, hours, minutes, or
  595.  *    seconds)
  596.  *
  597.  * RETURNS:    nothing
  598.  *
  599.  * SIDE EFFECTS:    none
  600.  *
  601.  *===========================================================================*/
  602. static void
  603. ComputeDHMSTime(someTime, timeText)
  604.     int32 someTime;
  605.     char *timeText;
  606. {
  607.     int        days, hours, mins, secs;
  608.  
  609.     days = someTime / (24*60*60);
  610.     someTime -= days*24*60*60;
  611.     hours = someTime / (60*60);
  612.     someTime -= hours*60*60;
  613.     mins = someTime / 60;
  614.     secs = someTime - mins*60;
  615.  
  616.     if ( days > 0 ) {
  617.         sprintf(timeText, "Total time:  %d days and %d hours", days, hours);
  618.     } else if ( hours > 0 ) {
  619.         sprintf(timeText, "Total time:  %d hours and %d minutes", hours, mins);
  620.     } else if ( mins > 0 ) {
  621.         sprintf(timeText, "Total time:  %d minutes and %d seconds", mins, secs);
  622.     } else {
  623.      sprintf(timeText, "Total time:  %d seconds", secs);
  624.     }
  625. }
  626.  
  627.  
  628. /*===========================================================================*
  629.  *
  630.  * ComputeGOPFrames
  631.  *
  632.  *    calculate the first, last frames of the numbered GOP
  633.  *
  634.  * RETURNS:    lastFrame, firstFrame changed
  635.  *
  636.  * SIDE EFFECTS:    none
  637.  *
  638.  *===========================================================================*/
  639. static void
  640. ComputeGOPFrames(whichGOP, firstFrame, lastFrame, numFrames)
  641.     int whichGOP;
  642.     int *firstFrame;
  643.     int *lastFrame;
  644.     int numFrames;
  645. {
  646.     int        passedB;
  647.     int        currGOP;
  648.     int        gopNum, frameNum;
  649.  
  650.     /* calculate first, last frames of whichGOP GOP */
  651.  
  652.     *firstFrame = -1;
  653.     *lastFrame = -1;
  654.     gopNum = 0;
  655.     frameNum = 0;
  656.     passedB = 0;
  657.     currGOP = 0;
  658.     while ( *lastFrame == -1 ) {
  659.     if ( frameNum >= numFrames ) {
  660.         fprintf(stderr, "ERROR:  There aren't that many GOPs!\n");
  661.         exit(1);
  662.     }
  663.  
  664. fprintf(stdout, "GOP STARTS AT %d\n", frameNum-passedB);
  665.  
  666.     if ( gopNum == whichGOP ) {
  667.         *firstFrame = frameNum-passedB;
  668.     }
  669.  
  670.     /* go past one gop */
  671.     while ( (frameNum < numFrames) && 
  672.         ((FRAME_TYPE(frameNum) != 'i') || currGOP < gopSize) ) {
  673.         currGOP += (1 + passedB);
  674.  
  675.         frameNum++;
  676.  
  677.         passedB = 0;
  678.         while ( FRAME_TYPE(frameNum) == 'b' ) {
  679.         frameNum++;
  680.         passedB++;
  681.         }
  682.     }
  683.  
  684.     currGOP -= gopSize;
  685.  
  686.     if ( gopNum == whichGOP ) {
  687.         *lastFrame = (frameNum-passedB-1);
  688.     }
  689.  
  690. fprintf(stdout, "GOP ENDS at %d\n", frameNum-passedB-1);
  691.  
  692.     gopNum++;
  693.     }
  694. }
  695.  
  696.  
  697. /*===========================================================================*
  698.  *
  699.  * PrintEndStats
  700.  *
  701.  *    print end statistics (summary, time information)
  702.  *
  703.  * RETURNS:    nothing
  704.  *
  705.  * SIDE EFFECTS:    none
  706.  *
  707.  *===========================================================================*/
  708. static void
  709. PrintEndStats(inputFrameBits, totalBits)
  710.     int inputFrameBits;
  711.     int32 totalBits;
  712. {
  713.     FILE *fpointer;
  714.     register int i;
  715.     char    timeText[256];
  716.  
  717.     fprintf(stdout, "\n\n");
  718.  
  719.     ComputeDHMSTime(diffTime, timeText);
  720.  
  721.     for ( i = 0; i < 2; i++ ) {
  722.     if ( i == 0 ) {
  723.         fpointer = stdout;
  724.     } else if ( statFile != NULL ) {
  725.         fpointer = statFile;
  726.     } else {
  727.         continue;
  728.     }
  729.  
  730.     fprintf(fpointer, "TIME COMPLETED:  %s", ctime(&timeEnd));
  731.     fprintf(fpointer, "%s\n\n", timeText);
  732.  
  733.     ShowIFrameSummary(inputFrameBits, totalBits, fpointer);
  734.     ShowPFrameSummary(inputFrameBits, totalBits, fpointer);
  735.     ShowBFrameSummary(inputFrameBits, totalBits, fpointer);
  736.     fprintf(fpointer, "---------------------------------------------\n");
  737.     fprintf(fpointer, "Total Compression:  %3d:1\n",
  738.         framesOutput*inputFrameBits/totalBits);
  739.     fprintf(fpointer, "Total Frames Per Second:  %f\n",
  740.         (float)framesOutput/(float)diffTime);
  741.     fprintf(fpointer, "Total Output Bit Rate (30 fps):  %d bits/sec\n",
  742.         30*totalBits/framesOutput);
  743.     fprintf(fpointer, "\n\n");
  744.     }
  745.  
  746.     if ( statFile != NULL ) {
  747.     fclose(statFile);
  748.     }
  749. }
  750.  
  751.  
  752. /*===========================================================================*
  753.  *
  754.  * ComputeFrameTable
  755.  *
  756.  *    compute a table of I, P, B frames to help in determining dependencies
  757.  *
  758.  * RETURNS:    nothing
  759.  *
  760.  * SIDE EFFECTS:    frameTable
  761.  *
  762.  *===========================================================================*/
  763. static void
  764. ComputeFrameTable()
  765. {
  766.     register int index;
  767.     FrameTable    *lastI, *lastIP, *firstB;
  768.     FrameTable    *ptr;
  769.     int        numberP, numberN, numberNO;
  770.  
  771.     frameTable = (FrameTable *) malloc((framePatternLen+1)*sizeof(FrameTable));
  772.  
  773.     lastI = NULL;
  774.     lastIP = NULL;
  775.     firstB = NULL;
  776.     for ( index = 0; index < framePatternLen; index++ ) {
  777.     frameTable[index].number = index;
  778.     frameTable[index].freeNow = TRUE;
  779.     frameTable[index].frame = NULL;
  780.  
  781.     switch( framePattern[index] ) {
  782.         case 'i':
  783.         ptr = firstB;
  784.         while ( ptr != NULL ) {
  785.             ptr->next = &(frameTable[index]);
  786.             ptr = ptr->nextOutput;
  787.         }
  788.         frameTable[index].nextOutput = firstB;
  789.         frameTable[index].prev = lastIP;    /* for freeing */
  790.         lastIP = &(frameTable[index]);
  791.         firstB = NULL;
  792.         break;
  793.         case 'p':
  794.         ptr = firstB;
  795.         while ( ptr != NULL ) {
  796.             ptr->next = &(frameTable[index]);
  797.             ptr = ptr->nextOutput;
  798.         }
  799.         frameTable[index].nextOutput = firstB;
  800.         frameTable[index].prev = lastIP;
  801.         lastIP->freeNow = FALSE;
  802.         lastIP = &(frameTable[index]);
  803.         firstB = NULL;
  804.         break;
  805.         case 'b':
  806.         if ( (index+1 == framePatternLen) ||
  807.              (framePattern[index+1] != 'b') ) {
  808.             frameTable[index].nextOutput = NULL;
  809.         } else {
  810.             frameTable[index].nextOutput = &(frameTable[index+1]);
  811.         }
  812.         frameTable[index].prev = lastIP;
  813.         lastIP->freeNow = FALSE;
  814.         if ( firstB == NULL ) {
  815.             firstB = &(frameTable[index]);
  816.         }
  817.         break;
  818.     }
  819.     }
  820.  
  821.     frameTable[framePatternLen].number = framePatternLen;
  822.     frameTable[framePatternLen].frame = NULL;
  823.  
  824.     ptr = firstB;
  825.     while ( ptr != NULL ) {
  826.     ptr->next = &(frameTable[framePatternLen]);
  827.     ptr = ptr->nextOutput;
  828.     }
  829.     frameTable[framePatternLen].nextOutput = firstB;
  830.     frameTable[framePatternLen].prev = lastIP;
  831.     frameTable[framePatternLen].freeNow = frameTable[0].freeNow;
  832.  
  833.     for ( index = 0; index < framePatternLen+1; index++ ) {
  834.     if ( frameTable[index].prev == NULL ) {
  835.         numberP = -1;
  836.     } else {
  837.         numberP = frameTable[index].prev->number;
  838.     }
  839.  
  840.     if ( frameTable[index].next == NULL ) {
  841.         numberN = -1;
  842.     } else {
  843.         numberN = frameTable[index].next->number;
  844.     }
  845.  
  846.     if ( frameTable[index].nextOutput == NULL ) {
  847.         numberNO = -1;
  848.     } else {
  849.         numberNO = frameTable[index].nextOutput->number;
  850.     }
  851.     }
  852. }
  853.  
  854.  
  855. /*===========================================================================*
  856.  *
  857.  * ProcessNonBFrame
  858.  *
  859.  *    process an I or P frame -- encode it, and process any B frames that
  860.  *    we can now
  861.  *
  862.  * RETURNS:    nothing
  863.  *
  864.  * SIDE EFFECTS:    stuff appended to bb
  865.  *
  866.  *===========================================================================*/
  867. static void
  868. ProcessNonBFrame(entry, bb, lastFrame, outputFileName, remoteIO)
  869.     FrameTable *entry;
  870.     BitBucket *bb;
  871.     int lastFrame;
  872.     char *outputFileName;
  873.     boolean remoteIO;
  874. {
  875.     FrameTable *ptr;
  876.     char    fileName[1024];
  877.     char    inputFileName[1024];
  878.     FILE    *fpointer = NULL;
  879.     boolean separateFiles;
  880.     int        id;
  881.  
  882.     separateFiles = (bb == NULL);
  883.  
  884.     if ( separateFiles && (entry->frame->id >= realStart) &&
  885.      (entry->frame->id <= realEnd) ) {
  886.     if ( remoteIO ) {
  887.         bb = Bitio_New(NULL);
  888.     } else {
  889.         sprintf(fileName, "%s.frame.%d", outputFileName, entry->frame->id);
  890.         if ( (fpointer = fopen(fileName, "wb")) == NULL ) {
  891.         fprintf(stderr, "ERROR:  Could not open output file:  %s\n",
  892.             fileName);
  893.         exit(1);
  894.         }
  895.  
  896.         bb = Bitio_New(fpointer);
  897.     }
  898.     }
  899.  
  900.     /* nothing to do */
  901.     if ( entry->frame->id < realStart ) {
  902.     return;
  903.     }
  904.  
  905.     /* first, output this frame */
  906.     if ( entry->frame->type == TYPE_IFRAME ) {
  907.     /* only start a new GOP with I */
  908.     /* don't start GOP if only doing frames */
  909.     if ( (! separateFiles) && (currentGOP >= gopSize) ) {
  910.         int closed;
  911.  
  912.         /* first, check to see if closed GOP */
  913.         if ( totalFramesSent == entry->frame->id ) {
  914.         closed = 1;
  915.         } else {
  916.         closed = 0;
  917.         }
  918.  
  919.         fprintf(stdout, "Creating new GOP (closed = %d) before frame %d\n",
  920.             closed, entry->frame->id);
  921.  
  922.         /* new GOP */
  923.         Mhead_GenGOPHeader(bb, /* drop_frame_flag */ 0,
  924.                tc_hrs, tc_min, tc_sec, tc_pict,
  925.                closed, /* broken_link */ 0,
  926.                /* ext_data */ NULL, /* ext_data_size */ 0,
  927.                /* user_data */ NULL, /* user_data_size */ 0);
  928.         currentGOP -= gopSize;
  929.     }
  930.  
  931.     if ( (entry->frame->id >= realStart) && (entry->frame->id <= realEnd) ) {
  932.         GenIFrame(bb, entry->frame);
  933.         framesOutput++;
  934.  
  935.         if ( separateFiles ) {
  936.         if ( remoteIO ) {
  937.             SendRemoteFrame(entry->frame->id, bb);
  938.         } else {
  939.             Bitio_Flush(bb);
  940.             fclose(fpointer);
  941.         }
  942.         }
  943.     }
  944.  
  945.     numI--;
  946.     timeMask &= 0x6;
  947.  
  948.     currentGOP++;
  949.     IncrementTCTime();
  950.     } else {
  951.     if ( (entry->frame->id >= realStart) && (entry->frame->id <= realEnd) ) {
  952.         GenPFrame(bb, entry->frame, entry->prev->frame);
  953.         framesOutput++;
  954.  
  955.         if ( separateFiles ) {
  956.         if ( remoteIO ) {
  957.             SendRemoteFrame(entry->frame->id, bb);
  958.         } else {
  959.             Bitio_Flush(bb);
  960.             fclose(fpointer);
  961.         }
  962.         }
  963.     }
  964.  
  965.     numP--;
  966.     timeMask &= 0x5;
  967.     ShowRemainingTime();
  968.  
  969.     currentGOP++;
  970.     IncrementTCTime();
  971.     }
  972.  
  973.     /* now, follow nextOutput and output B-frames */
  974.     ptr = entry->nextOutput;
  975.     while ( ptr != NULL ) {
  976.     id = entry->frame->id - (entry->number - ptr->number);
  977.  
  978.     if ( (id >= realStart) && (id <= realEnd) ) {
  979.         ptr->frame = Frame_New(id, 'b');
  980.  
  981.         /* read B frame, output it */
  982.         if ( remoteIO ) {
  983.         GetRemoteFrame(ptr->frame, ptr->frame->id);
  984.         } else {
  985.         GetNthInputFileName(inputFileName, id);
  986.         ReadFrame(ptr->frame, inputFileName, inputConversion, TRUE);
  987.         }
  988.  
  989.         if ( separateFiles ) {
  990.         if ( remoteIO ) {
  991.             bb = Bitio_New(NULL);
  992.         } else {
  993.             sprintf(fileName, "%s.frame.%d", outputFileName, ptr->frame->id);
  994.             if ( (fpointer = fopen(fileName, "wb")) == NULL ) {
  995.             fprintf(stderr, "ERROR:  Could not open output file:  %s\n",
  996.                 fileName);
  997.             exit(1);
  998.             }
  999.             bb = Bitio_New(fpointer);
  1000.         }
  1001.         }
  1002.  
  1003.         GenBFrame(bb, ptr->frame, ptr->prev->frame, ptr->next->frame);
  1004.         framesOutput++;
  1005.  
  1006.         if ( separateFiles ) {
  1007.         if ( remoteIO ) {
  1008.             SendRemoteFrame(ptr->frame->id, bb);
  1009.         } else {
  1010.             Bitio_Flush(bb);
  1011.             fclose(fpointer);
  1012.         }
  1013.         }
  1014.  
  1015.         /* free this B frame right away */
  1016.         Frame_Free(ptr->frame);
  1017.         ptr->frame = NULL;
  1018.     }
  1019.  
  1020.     numB--;
  1021.     timeMask &= 0x3;
  1022.     ShowRemainingTime();
  1023.  
  1024.     currentGOP++;
  1025.     IncrementTCTime();
  1026.  
  1027.     ptr = ptr->nextOutput;
  1028.     }
  1029.  
  1030.     /* now free previous frame, if there was one */
  1031.     if ( (entry->frame->type != TYPE_IFRAME) ||
  1032.      (entry->nextOutput != NULL) ) {
  1033.     if ( entry->prev->frame != NULL ) {
  1034.         Frame_Free(entry->prev->frame);
  1035.         entry->prev->frame = NULL;
  1036.     }
  1037.     }
  1038.  
  1039.     /* check to see if we can free this frame now */
  1040.     if ( entry->freeNow || (entry->frame->id == lastFrame) ) {
  1041.     if ( entry->frame != NULL ) {
  1042.         Frame_Free(entry->frame);
  1043.         entry->frame = NULL;
  1044.     }
  1045.     }
  1046.  
  1047.     /* note, we may still not free last frame if lastFrame is incorrect
  1048.     (if the last frames are B frames, they aren't output!)
  1049.      */
  1050. }
  1051.  
  1052.  
  1053. /*===========================================================================*
  1054.  *
  1055.  * ShowRemainingTime
  1056.  *
  1057.  *    print out an estimate of the time left to encode
  1058.  *
  1059.  * RETURNS:    nothing
  1060.  *
  1061.  * SIDE EFFECTS:    none
  1062.  *
  1063.  *===========================================================================*/
  1064. static void
  1065. ShowRemainingTime()
  1066. {
  1067.     static int    lastTime = 0;
  1068.     float   timeI, timeP, timeB;
  1069.     float   total;
  1070.  
  1071.     if ( childProcess ) {
  1072.     return /* nothing */;
  1073.     }
  1074.  
  1075.     if ( numI + numP + numB == 0 ) {    /* no time left */
  1076.     return /* nothing */ ;
  1077.     }
  1078.  
  1079.     if ( timeMask != 0 ) {        /* haven't encoded all types yet */
  1080.     return /* nothing */ ;
  1081.     }
  1082.  
  1083.     timeI = EstimateSecondsPerIFrame();
  1084.     timeP = EstimateSecondsPerPFrame();
  1085.     timeB = EstimateSecondsPerBFrame();
  1086.  
  1087.     total = (float)numI*timeI + (float)numP*timeP + (float)numB*timeB;
  1088.  
  1089.     if ( (quietTime >= 0) &&
  1090.      (((lastTime-(int)total) >= quietTime) || (lastTime == 0)) ) {
  1091.     if ( total > 270.0 ) {
  1092.         fprintf(stdout, "ESTIMATED TIME OF COMPLETION:  %d minutes\n",
  1093.             ((int)total+30)/60);
  1094.     } else {
  1095.         fprintf(stdout, "ESTIMATED TIME OF COMPLETION:  %d seconds\n",
  1096.             (int)total);
  1097.     }
  1098.  
  1099.     lastTime = (int)total;
  1100.     }
  1101. }
  1102.