home *** CD-ROM | disk | FTP | other *** search
/ MPEG Toolkit / MPEG Toolkit.iso / os2 / mpegenc / src / mpeg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-01  |  32.3 KB  |  1,298 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. #ifdef OS2
  70. /* @@@ FAT 8.3 convention */
  71. #include "prototyp.h"
  72. #else
  73. #include "prototypes.h"
  74. #endif
  75. #include "parallel.h"
  76. #include "param.h"
  77. #ifdef OS2
  78. /* @@@ FAT 8.3 convention */
  79. #include "readfram.h"
  80. #else
  81. #include "readframe.h"
  82. #endif
  83. #include "fsize.h"
  84. #include "mheaders.h"
  85.  
  86.  
  87. /*===========*
  88.  * CONSTANTS *
  89.  *===========*/
  90.  
  91. #define FRAMES_PER_SECOND   30
  92.  
  93.  
  94. /*==================*
  95.  * STATIC VARIABLES *
  96.  *==================*/
  97.  
  98. static int32   diffTime;
  99. static int framesOutput;
  100. static int        realStart, realEnd;
  101. static int    currentGOP;
  102. static int        timeMask;
  103. static int        numI, numP, numB;
  104.  
  105.  
  106. /*==================*
  107.  * GLOBAL VARIABLES *
  108.  *==================*/
  109.  
  110. extern int  IOtime;
  111. int        gopSize = 100;  /* default */
  112. int32        tc_hrs, tc_min, tc_sec, tc_pict;
  113. int        totalFramesSent;
  114. int        yuvWidth, yuvHeight;
  115. int        realWidth, realHeight;
  116. FrameTable *frameTable;
  117. char        currentPath[MAXPATHLEN];
  118. char        statFileName[256];
  119. time_t        timeStart, timeEnd;
  120. FILE       *statFile;
  121. char       *framePattern;
  122. int        framePatternLen;
  123. int        referenceFrame;
  124.  
  125.  
  126. /*===============================*
  127.  * INTERNAL PROCEDURE prototypes *
  128.  *===============================*/
  129.  
  130. static void    ShowRemainingTime _ANSI_ARGS_((void));
  131. static void    ComputeDHMSTime _ANSI_ARGS_((int32 someTime, char *timeText));
  132. static void    ComputeGOPFrames _ANSI_ARGS_((int whichGOP, int *firstFrame,
  133.                           int *lastFrame, int numFrames));
  134. static void    PrintEndStats _ANSI_ARGS_((int inputFrameBits, int32 totalBits));
  135. static void    ComputeFrameTable _ANSI_ARGS_((void));
  136. static void    ProcessRefFrame _ANSI_ARGS_((FrameTable *entry,
  137.                           BitBucket *bb, int lastFrame,
  138.                           char *outputFileName));
  139.  
  140.  
  141. /*=====================*
  142.  * EXPORTED PROCEDURES *
  143.  *=====================*/
  144.  
  145. /*===========================================================================*
  146.  *
  147.  * SetReferenceFrameType
  148.  *
  149.  *    set the reference frame type to be original or decoded
  150.  *
  151.  * RETURNS:    nothing
  152.  *
  153.  * SIDE EFFECTS:    referenceFrame
  154.  *
  155.  *===========================================================================*/
  156. void
  157. SetReferenceFrameType(type)
  158.     char *type;
  159. {
  160.     if ( strcmp(type, "ORIGINAL") == 0 ) {
  161.     referenceFrame = ORIGINAL_FRAME;
  162.     } else if ( strcmp(type, "DECODED") == 0 ) {
  163.     referenceFrame = DECODED_FRAME;
  164.     } else {
  165.     fprintf(stderr, "ERROR:  Illegal reference frame type: '%s'\n",
  166.         type);
  167.     exit(1);
  168.     }
  169. }
  170.  
  171.  
  172. /*===========================================================================*
  173.  *
  174.  * SetFramePattern
  175.  *
  176.  *    set the IPB pattern; calls ComputeFrameTable to set up table
  177.  *
  178.  * RETURNS:    nothing
  179.  *
  180.  * SIDE EFFECTS:    framePattern, framePatternLen, frameTable
  181.  *
  182.  *===========================================================================*/
  183. void
  184. SetFramePattern(pattern)
  185.     char *pattern;
  186. {
  187.     int len = strlen(pattern);
  188.     char *buf;
  189.     int index;
  190.  
  191.     if ( ! pattern ) {
  192.     fprintf(stderr, "pattern cannot be NULL\n");
  193.     exit(1);
  194.     }
  195.  
  196.     if ( pattern[0] != 'i' && pattern[0] != 'I' ) {
  197.     fprintf(stderr, "first frame must be 'i'\n");
  198.     exit(1);
  199.     }
  200.  
  201.     buf = (char *)malloc(sizeof(char)*(len+1));
  202.     ERRCHK(buf, "malloc");
  203.  
  204.     for ( index = 0; index < len; index++ ) {
  205.     switch( pattern[index] ) {
  206.         case 'i':    case 'I':    buf[index] = 'i';        break;
  207.         case 'p':    case 'P':    buf[index] = 'p';        break;
  208.         case 'b':    case 'B':    buf[index] = 'b';        break;
  209.         default:
  210.         fprintf(stderr, "Frame type '%c' not supported.\n", pattern[index]);
  211.         exit(1);
  212.     }
  213.     }
  214.     buf[len] = 0;
  215.  
  216.     framePattern = buf;
  217.     framePatternLen = len;
  218.  
  219.     ComputeFrameTable();
  220. }
  221.  
  222.  
  223. /*===========================================================================*
  224.  *
  225.  * GenMPEGStream
  226.  *
  227.  *    generate an MPEG sequence stream (generally)
  228.  *    if whichGOP == frameStart == -1 then does complete MPEG sequence
  229.  *    if whichGOP != -1 then does numbered GOP only (without sequence
  230.  *                   header)
  231.  *    if frameStart != -1 then does numbered frames only (without any
  232.  *                 sequence or GOP headers)               
  233.  *
  234.  * RETURNS:    amount of time it took
  235.  *
  236.  * SIDE EFFECTS:    too numerous to mention
  237.  *
  238.  *===========================================================================*/
  239. int32
  240. GenMPEGStream(whichGOP, frameStart, frameEnd, numFrames, ofp, outputFileName)
  241.     int whichGOP;
  242.     int frameStart;
  243.     int frameEnd;
  244.     int numFrames;
  245.     FILE *ofp;
  246.     char *outputFileName;
  247. {
  248.     BitBucket *bb;
  249.     int i;
  250.     char frameType;
  251.     MpegFrame    *frame;
  252.     FrameTable    *entry = NULL;
  253.     int        firstFrame, lastFrame;
  254.     int  inputFrameBits = 0;
  255.     char    inputFileName[1024];
  256.     time_t  tempTimeStart, tempTimeEnd;
  257.  
  258.     time(&timeStart);
  259.  
  260.     ResetIFrameStats();
  261.     ResetPFrameStats();
  262.     ResetBFrameStats();
  263.  
  264.     Fsize_Reset();
  265.  
  266.     framesOutput = 0;
  267.  
  268.     if ( childProcess && separateConversion ) {
  269.     SetFileType(slaveConversion);
  270.     } else {
  271.     SetFileType(inputConversion);
  272.     }
  273.  
  274.     if ( whichGOP != -1 ) {
  275.     ComputeGOPFrames(whichGOP, &firstFrame, &lastFrame, numFrames);
  276.  
  277.     realStart = firstFrame;
  278.     realEnd = lastFrame;
  279.  
  280.     if ( FRAME_TYPE(firstFrame) == 'b' ) {
  281.         /* need to load in previous frame; call it an I frame */
  282.         frame = Frame_New(firstFrame-1, 'i');
  283.  
  284.         time(&tempTimeStart);
  285.  
  286.         if ( (referenceFrame == DECODED_FRAME) &&
  287.          childProcess ) {
  288.         WaitForDecodedFrame(firstFrame);
  289.  
  290.         if ( remoteIO ) {
  291.             GetRemoteDecodedRefFrame(frame, firstFrame-1);
  292.         } else {
  293.             ReadDecodedRefFrame(frame, firstFrame-1);
  294.         }
  295.         } else {
  296.         if ( remoteIO ) {
  297.             GetRemoteFrame(frame, firstFrame-1);
  298.         } else {
  299.             GetNthInputFileName(inputFileName, firstFrame-1);
  300.  
  301.             if ( childProcess && separateConversion ) {
  302.             ReadFrame(frame, inputFileName, slaveConversion, TRUE);
  303.             } else {
  304.             ReadFrame(frame, inputFileName, inputConversion, TRUE);
  305.             }
  306.         }
  307.         }
  308.  
  309.         time(&tempTimeEnd);
  310.         IOtime += (tempTimeEnd-tempTimeStart);
  311.  
  312.         /* should put in the correct frameTable place */
  313.     }
  314.     } else if ( frameStart != -1 ) {
  315.     if ( frameEnd > numFrames-1 ) {
  316.         fprintf(stdout, "ERROR:  Specified last frame is out of bounds\n");
  317.         exit(1);
  318.     }
  319.  
  320.     realStart = frameStart;
  321.     realEnd = frameEnd;
  322.  
  323.     firstFrame = frameStart;
  324.     lastFrame = frameEnd;
  325.  
  326.     /* if first frame is P or B, need to read in P or I frame before it */
  327.     if ( FRAME_TYPE(firstFrame) != 'i' ) {
  328.         entry = &(frameTable[firstFrame % framePatternLen]);
  329.  
  330.         firstFrame = firstFrame - (entry->number - entry->prev->number);
  331.     }
  332.  
  333.     /* if last frame is B, need to read in P or I frame after it */
  334.     if ( (FRAME_TYPE(lastFrame) == 'b') && (lastFrame != numFrames-1) ) {
  335.         entry = &(frameTable[lastFrame % framePatternLen]);
  336.  
  337.         lastFrame = lastFrame + (entry->next->number - entry->number);
  338.     }
  339.  
  340.     if ( lastFrame > numFrames-1 ) {        /* can't go last frame! */
  341.         lastFrame = numFrames-1;
  342.     }
  343.     } else {
  344.     firstFrame = 0;
  345.     lastFrame = numFrames-1;
  346.  
  347.     realStart = 0;
  348.     realEnd = numFrames-1;
  349.     }
  350.  
  351.     /* count number of I, P, and B frames */
  352.     numI = 0;    numP = 0;   numB = 0;
  353.     timeMask = 0;
  354.     for ( i = firstFrame; i <= lastFrame; i++ ) {
  355.     frameType = FRAME_TYPE(i);
  356.     switch(frameType) {
  357.         case 'i':    numI++;        timeMask |= 0x1;    break;
  358.         case 'p':    numP++;        timeMask |= 0x2;    break;
  359.         case 'b':    numB++;        timeMask |= 0x4;    break;
  360.     }
  361.     }
  362.  
  363.     if ( ! childProcess ) {
  364.     PrintStartStats(realStart, realEnd);
  365.     }
  366.  
  367.     if ( frameStart == -1 ) {
  368.     bb = Bitio_New(ofp);
  369.     } else {
  370.     bb = NULL;
  371.     }
  372.  
  373.     tc_hrs = 0;    tc_min = 0; tc_sec = 0; tc_pict = 0;
  374.     for ( i = 0; i < firstFrame; i++ ) {
  375.     IncrementTCTime();
  376.     }
  377.  
  378.     totalFramesSent = firstFrame;
  379.     currentGOP = gopSize;    /* so first I-frame generates GOP Header */
  380.  
  381. #ifdef BLEAH
  382. fprintf(stdout, "firstFrame, lastFrame = %d, %d;  real = %d, %d\n",
  383.     firstFrame, lastFrame, realStart, realEnd);
  384. fflush(stdout);
  385. #endif
  386.  
  387.     for ( i = firstFrame; i <= lastFrame; i++) {
  388.     frameType = FRAME_TYPE(i);
  389.  
  390.     /* skip non-reference frames */
  391.     if ( frameType == 'b' ) {
  392.         continue;
  393.     }
  394.  
  395.     frame = Frame_New(i, frameType);
  396.     if ( (i != firstFrame) && ((i % framePatternLen) == 0) ) {
  397.         entry = &(frameTable[framePatternLen]);
  398.     } else {
  399.         entry = &(frameTable[i % framePatternLen]);
  400.     }
  401.  
  402.     entry->frame = frame;
  403.  
  404.     time(&tempTimeStart);
  405.  
  406.     if ( (referenceFrame == DECODED_FRAME) &&
  407.          ((i < realStart) || (i > realEnd)) ) {
  408.         WaitForDecodedFrame(i);
  409.  
  410.         if ( remoteIO ) {
  411.         GetRemoteDecodedRefFrame(frame, i);
  412.         } else {
  413.         ReadDecodedRefFrame(frame, i);
  414.         }
  415.     } else {
  416.         if ( remoteIO ) {
  417.         GetRemoteFrame(frame, i);
  418.         } else {
  419.         GetNthInputFileName(inputFileName, i);
  420.         if ( childProcess && separateConversion ) {
  421.             ReadFrame(frame, inputFileName, slaveConversion, TRUE);
  422.         } else {
  423.             ReadFrame(frame, inputFileName, inputConversion, TRUE);
  424.         }
  425.         }
  426.     }
  427.  
  428.     time(&tempTimeEnd);
  429.     IOtime += (tempTimeEnd-tempTimeStart);
  430.  
  431.     if ( i == firstFrame ) {
  432.         inputFrameBits = 24*Fsize_x*Fsize_y;
  433.         SetBlocksPerSlice();
  434.  
  435.         if ( (whichGOP == -1) && (frameStart == -1) ) {
  436.         DBG_PRINT(("Generating sequence header\n"));
  437.         Mhead_GenSequenceHeader(bb, Fsize_x, Fsize_y, /* pratio */ 1,
  438.                /* pict_rate */ -1, /* bit_rate */ -1,
  439.                /* buf_size */ -1, /*c_param_flag */ 1,
  440.                /* iq_matrix */ NULL, /* niq_matrix */ NULL,
  441.                /* ext_data */ NULL, /* ext_data_size */ 0,
  442.                /* user_data */ NULL, /* user_data_size */ 0);
  443.         }
  444.     }
  445.  
  446.     ProcessRefFrame(entry, bb, lastFrame, outputFileName);
  447.  
  448.     /* in case this is first frame of pattern sequence; put it    
  449.         back to 0 */
  450.     if ( entry == &frameTable[framePatternLen]) {
  451.         frameTable[0].frame = frame;
  452.     }
  453.     }
  454.  
  455.     if ( entry->frame != NULL ) {
  456.     Frame_Free(entry->frame);
  457.     }
  458.  
  459.     /* SEQUENCE END CODE */
  460.     if ( (whichGOP == -1) && (frameStart == -1) ) {
  461.     Mhead_GenSequenceEnder(bb);
  462.     }
  463.  
  464.     if ( frameStart == -1 ) {
  465.     Bitio_Flush(bb);
  466.     fclose(ofp);
  467.  
  468.     time(&timeEnd);
  469.     diffTime = (int32)(timeEnd-timeStart);
  470.  
  471.     if ( ! childProcess ) {
  472.         PrintEndStats(inputFrameBits, bb->cumulativeBits);
  473.     }
  474.     } else {
  475.     time(&timeEnd);
  476.     diffTime = (int32)(timeEnd-timeStart);
  477.  
  478.     if ( ! childProcess ) {
  479.         PrintEndStats(inputFrameBits, 1);
  480.     }
  481.     }
  482.  
  483.     if ( childProcess ) {
  484.     NoteFrameDone(frameStart, frameEnd);
  485.     }
  486.  
  487.     return diffTime;
  488. }
  489.  
  490.  
  491. /*===========================================================================*
  492.  *
  493.  * IncrementTCTime
  494.  *
  495.  *    increment the tc time by one second (and update min, hrs if necessary)
  496.  *    also increments totalFramesSent
  497.  *
  498.  * RETURNS:    nothing
  499.  *
  500.  * SIDE EFFECTS:    totalFramesSent, tc_pict, tc_sec, tc_min, tc_hrs
  501.  *
  502.  *===========================================================================*/
  503. void
  504. IncrementTCTime()
  505. {
  506.     totalFramesSent++;
  507.     tc_pict++;
  508.     if ( tc_pict == FRAMES_PER_SECOND ) {
  509.     tc_pict = 0;
  510.     tc_sec++;
  511.     if ( tc_sec == 60 ) {
  512.         tc_sec = 0;
  513.         tc_min++;
  514.         if ( tc_min == 60 ) {
  515.         tc_min = 0;
  516.         tc_hrs++;
  517.         }
  518.     }
  519.     }
  520. }
  521.  
  522.  
  523. /*===========================================================================*
  524.  *
  525.  * SetStatFileName
  526.  *
  527.  *    set the statistics file name
  528.  *
  529.  * RETURNS:    nothing
  530.  *
  531.  * SIDE EFFECTS:    statFileName
  532.  *
  533.  *===========================================================================*/
  534. void
  535. SetStatFileName(fileName)
  536.     char *fileName;
  537. {
  538.     strcpy(statFileName, fileName);
  539. }
  540.  
  541.  
  542. /*===========================================================================*
  543.  *
  544.  * SetGOPSize
  545.  *
  546.  *    set the GOP size (frames per GOP)
  547.  *
  548.  * RETURNS:    nothing
  549.  *
  550.  * SIDE EFFECTS:    gopSize
  551.  *
  552.  *===========================================================================*/
  553. void
  554. SetGOPSize(size)
  555.     int size;
  556. {
  557.     gopSize = size;
  558. }
  559.  
  560.  
  561. /*===========================================================================*
  562.  *
  563.  * PrintStartStats
  564.  *
  565.  *    print out the starting statistics (stuff from the param file)
  566.  *    firstFrame, lastFrame represent the first, last frames to be
  567.  *    encoded
  568.  *
  569.  * RETURNS:    nothing
  570.  *
  571.  * SIDE EFFECTS:    none
  572.  *
  573.  *===========================================================================*/
  574. void
  575. PrintStartStats(firstFrame, lastFrame)
  576.     int firstFrame;
  577.     int lastFrame;
  578. {
  579.     FILE *fpointer;
  580.     register int i;
  581.     char    inputFileName[1024];
  582.  
  583.     if ( statFileName[0] == '\0' ) {
  584.     statFile = NULL;
  585.     } else {
  586.     statFile = fopen(statFileName, "a");    /* open for appending */
  587.     if ( statFile == NULL ) {
  588.         fprintf(stderr, "ERROR:  Could not open stat file:  %s\n", statFileName);
  589.         fprintf(stderr, "        Sending statistics to stdout only.\n");
  590.         fprintf(stderr, "\n\n");
  591.     } else {
  592.         fprintf(stdout, "Appending statistics to file:  %s\n", statFileName);
  593.         fprintf(stdout, "\n\n");
  594.     }
  595.     }
  596.     
  597.     for ( i = 0; i < 2; i++ ) {
  598.     if ( i == 0 ) {
  599.         fpointer = stdout;
  600.     } else if ( statFile != NULL ) {
  601.         fpointer = statFile;
  602.     } else {
  603.         continue;
  604.     }
  605.  
  606.     fprintf(fpointer, "MPEG ENCODER STATS\n");
  607.     fprintf(fpointer, "------------------\n");
  608.     fprintf(fpointer, "TIME STARTED:  %s", ctime(&timeStart));
  609.     if ( getenv("HOST") != NULL ) {
  610.         fprintf(fpointer, "MACHINE:  %s\n", getenv("HOST"));
  611.     } else {
  612.         fprintf(fpointer, "MACHINE:  unknown\n");
  613.     }
  614.  
  615.     if ( firstFrame == -1 ) {
  616.         fprintf(fpointer, "OUTPUT:  %s\n", outputFileName);
  617.     } else {
  618.         GetNthInputFileName(inputFileName, firstFrame);
  619.         fprintf(fpointer, "FIRST FILE:  %s/%s\n", currentPath, inputFileName);
  620.         GetNthInputFileName(inputFileName, lastFrame);
  621.         fprintf(fpointer, "LAST FILE:  %s/%s\n", currentPath,
  622.             inputFileName);
  623.     }
  624.     fprintf(fpointer, "PATTERN:  %s\n", framePattern);
  625.     fprintf(fpointer, "GOP_SIZE:  %d\n", gopSize);
  626.     fprintf(fpointer, "SLICES PER FRAME:  %d\n", slicesPerFrame);
  627.     fprintf(fpointer, "RANGE:  +/-%d\n", searchRange/2);
  628.     fprintf(fpointer, "FULL SEARCH:  %d\n", pixelFullSearch);
  629.     fprintf(fpointer, "PSEARCH:  %s\n", PSearchName());
  630.     fprintf(fpointer, "BSEARCH:  %s\n", BSearchName());
  631.     fprintf(fpointer, "QSCALE:  %d %d %d\n", qscaleI, 
  632.         GetPQScale(), GetBQScale());
  633.     if ( referenceFrame == DECODED_FRAME ) {
  634.         fprintf(fpointer, "REFERENCE FRAME:  DECODED\n");
  635.     } else if ( referenceFrame == ORIGINAL_FRAME ) {
  636.         fprintf(fpointer, "REFERENCE FRAME:  ORIGINAL\n");
  637.     } else {
  638.         fprintf(stderr, "ERROR:  Illegal referenceFrame!!!\n");
  639.         exit(1);
  640.     }
  641.     }
  642.  
  643.     fprintf(stdout, "\n\n");
  644. }
  645.  
  646.  
  647. /*===========================================================================*
  648.  *
  649.  * NonLocalRefFrame
  650.  *
  651.  *    decides if this frame can be referenced from a non-local process
  652.  *
  653.  * RETURNS:    TRUE or FALSE
  654.  *
  655.  * SIDE EFFECTS:    none
  656.  *
  657.  *===========================================================================*/
  658. boolean
  659. NonLocalRefFrame(id)
  660.     int id;
  661. {
  662.     int        lastIPid;
  663.     int        nextIPid;
  664.     FrameTable *entry = NULL;
  665.  
  666.     if ( ! childProcess ) {
  667.     return FALSE;
  668.     }
  669.  
  670.     if ( (id % framePatternLen) == 0 ) {
  671.     entry = &frameTable[framePatternLen];
  672.     } else {
  673.     entry = &(frameTable[id % framePatternLen]);
  674.     }
  675.  
  676.     if ( entry == NULL ) {
  677.     fprintf(stdout, "ENTRY == NULL!!!\n");
  678.     fflush(stdout);
  679.     exit(1);
  680.     }
  681.  
  682.     lastIPid = id - (entry->number - entry->prev->number);
  683.  
  684.     /* might be accessed by B-frame */
  685.     if ( lastIPid+1 < realStart ) {
  686.     return TRUE;
  687.     }
  688.  
  689.     entry = &(frameTable[id % framePatternLen]);
  690.  
  691.     /* if B-frame is out of range, then current frame can be ref'd by it */
  692.     nextIPid = id + (entry->next->number - entry->number);
  693.  
  694.     /* might be accessed by B-frame */
  695.     if ( nextIPid-1 > realEnd ) {
  696.     return TRUE;
  697.     }
  698.  
  699.     /* might be accessed by P-frame */
  700.     if ( (nextIPid > realEnd) && (FRAME_TYPE(nextIPid) == 'p') ) {
  701.     return TRUE;
  702.     }
  703.  
  704.     return FALSE;
  705. }
  706.     
  707.  
  708. /*=====================*
  709.  * INTERNAL PROCEDURES *
  710.  *=====================*/
  711.  
  712. /*===========================================================================*
  713.  *
  714.  * ComputeDHMSTime
  715.  *
  716.  *    turn some number of seconds (someTime) into a string which
  717.  *    summarizes that time according to scale (days, hours, minutes, or
  718.  *    seconds)
  719.  *
  720.  * RETURNS:    nothing
  721.  *
  722.  * SIDE EFFECTS:    none
  723.  *
  724.  *===========================================================================*/
  725. static void
  726. ComputeDHMSTime(someTime, timeText)
  727.     int32 someTime;
  728.     char *timeText;
  729. {
  730.     int        days, hours, mins, secs;
  731.  
  732.     days = someTime / (24*60*60);
  733.     someTime -= days*24*60*60;
  734.     hours = someTime / (60*60);
  735.     someTime -= hours*60*60;
  736.     mins = someTime / 60;
  737.     secs = someTime - mins*60;
  738.  
  739.     if ( days > 0 ) {
  740.         sprintf(timeText, "Total time:  %d days and %d hours", days, hours);
  741.     } else if ( hours > 0 ) {
  742.         sprintf(timeText, "Total time:  %d hours and %d minutes", hours, mins);
  743.     } else if ( mins > 0 ) {
  744.         sprintf(timeText, "Total time:  %d minutes and %d seconds", mins, secs);
  745.     } else {
  746.      sprintf(timeText, "Total time:  %d seconds", secs);
  747.     }
  748. }
  749.  
  750.  
  751. /*===========================================================================*
  752.  *
  753.  * ComputeGOPFrames
  754.  *
  755.  *    calculate the first, last frames of the numbered GOP
  756.  *
  757.  * RETURNS:    lastFrame, firstFrame changed
  758.  *
  759.  * SIDE EFFECTS:    none
  760.  *
  761.  *===========================================================================*/
  762. static void
  763. ComputeGOPFrames(whichGOP, firstFrame, lastFrame, numFrames)
  764.     int whichGOP;
  765.     int *firstFrame;
  766.     int *lastFrame;
  767.     int numFrames;
  768. {
  769.     int        passedB;
  770.     int        currGOP;
  771.     int        gopNum, frameNum;
  772.  
  773.     /* calculate first, last frames of whichGOP GOP */
  774.  
  775.     *firstFrame = -1;
  776.     *lastFrame = -1;
  777.     gopNum = 0;
  778.     frameNum = 0;
  779.     passedB = 0;
  780.     currGOP = 0;
  781.     while ( *lastFrame == -1 ) {
  782.     if ( frameNum >= numFrames ) {
  783.         fprintf(stderr, "ERROR:  There aren't that many GOPs!\n");
  784.         exit(1);
  785.     }
  786.  
  787. fprintf(stdout, "GOP STARTS AT %d\n", frameNum-passedB);
  788.  
  789.     if ( gopNum == whichGOP ) {
  790.         *firstFrame = frameNum-passedB;
  791.     }
  792.  
  793.     /* go past one gop */
  794.     while ( (frameNum < numFrames) && 
  795.         ((FRAME_TYPE(frameNum) != 'i') || currGOP < gopSize) ) {
  796.         currGOP += (1 + passedB);
  797.  
  798.         frameNum++;
  799.  
  800.         passedB = 0;
  801.         while ( FRAME_TYPE(frameNum) == 'b' ) {
  802.         frameNum++;
  803.         passedB++;
  804.         }
  805.     }
  806.  
  807.     currGOP -= gopSize;
  808.  
  809.     if ( gopNum == whichGOP ) {
  810.         *lastFrame = (frameNum-passedB-1);
  811.     }
  812.  
  813. fprintf(stdout, "GOP ENDS at %d\n", frameNum-passedB-1);
  814.  
  815.     gopNum++;
  816.     }
  817. }
  818.  
  819.  
  820. /*===========================================================================*
  821.  *
  822.  * PrintEndStats
  823.  *
  824.  *    print end statistics (summary, time information)
  825.  *
  826.  * RETURNS:    nothing
  827.  *
  828.  * SIDE EFFECTS:    none
  829.  *
  830.  *===========================================================================*/
  831. static void
  832. PrintEndStats(inputFrameBits, totalBits)
  833.     int inputFrameBits;
  834.     int32 totalBits;
  835. {
  836.     FILE *fpointer;
  837.     register int i;
  838.     char    timeText[256];
  839.  
  840.     fprintf(stdout, "\n\n");
  841.  
  842.     ComputeDHMSTime(diffTime, timeText);
  843.  
  844.     for ( i = 0; i < 2; i++ ) {
  845.     if ( i == 0 ) {
  846.         fpointer = stdout;
  847.     } else if ( statFile != NULL ) {
  848.         fpointer = statFile;
  849.     } else {
  850.         continue;
  851.     }
  852.  
  853.     fprintf(fpointer, "TIME COMPLETED:  %s", ctime(&timeEnd));
  854.     fprintf(fpointer, "%s\n\n", timeText);
  855.  
  856.     ShowIFrameSummary(inputFrameBits, totalBits, fpointer);
  857.     ShowPFrameSummary(inputFrameBits, totalBits, fpointer);
  858.     ShowBFrameSummary(inputFrameBits, totalBits, fpointer);
  859.     fprintf(fpointer, "---------------------------------------------\n");
  860.     fprintf(fpointer, "Total Compression:  %3d:1\n",
  861.         framesOutput*inputFrameBits/totalBits);
  862.     fprintf(fpointer, "Total Frames Per Second:  %f\n",
  863.         (float)framesOutput/(float)diffTime);
  864.     fprintf(fpointer, "Total Output Bit Rate (30 fps):  %d bits/sec\n",
  865.         30*totalBits/framesOutput);
  866.     fprintf(fpointer, "\n\n");
  867.     }
  868.  
  869.     if ( statFile != NULL ) {
  870.     fclose(statFile);
  871.     }
  872. }
  873.  
  874.  
  875. /*===========================================================================*
  876.  *
  877.  * ComputeFrameTable
  878.  *
  879.  *    compute a table of I, P, B frames to help in determining dependencies
  880.  *
  881.  * RETURNS:    nothing
  882.  *
  883.  * SIDE EFFECTS:    frameTable
  884.  *
  885.  *===========================================================================*/
  886. static void
  887. ComputeFrameTable()
  888. {
  889.     register int index;
  890.     FrameTable    *lastI, *lastIP, *firstB;
  891.     FrameTable    *ptr;
  892.     int        numberP, numberN, numberNO;
  893.  
  894.     frameTable = (FrameTable *) malloc((framePatternLen+1)*sizeof(FrameTable));
  895.  
  896.     lastI = NULL;
  897.     lastIP = NULL;
  898.     firstB = NULL;
  899.     for ( index = 0; index < framePatternLen; index++ ) {
  900.     frameTable[index].number = index;
  901.     frameTable[index].freeNow = TRUE;
  902.     frameTable[index].frame = NULL;
  903.  
  904.     switch( framePattern[index] ) {
  905.         case 'i':
  906.         ptr = firstB;
  907.         while ( ptr != NULL ) {
  908.             ptr->next = &(frameTable[index]);
  909.             ptr = ptr->nextOutput;
  910.         }
  911.         frameTable[index].nextOutput = firstB;
  912.         frameTable[index].prev = lastIP;    /* for freeing */
  913.         if ( lastIP != NULL ) {
  914.             lastIP->next = &(frameTable[index]);
  915.         }
  916.         lastIP = &(frameTable[index]);
  917.         firstB = NULL;
  918.         break;
  919.         case 'p':
  920.         ptr = firstB;
  921.         while ( ptr != NULL ) {
  922.             ptr->next = &(frameTable[index]);
  923.             ptr = ptr->nextOutput;
  924.         }
  925.         frameTable[index].nextOutput = firstB;
  926.         frameTable[index].prev = lastIP;
  927.         if ( lastIP != NULL ) {
  928.             lastIP->next = &(frameTable[index]);
  929.         }
  930.         lastIP->freeNow = FALSE;
  931.         lastIP = &(frameTable[index]);
  932.         firstB = NULL;
  933.         break;
  934.         case 'b':
  935.         if ( (index+1 == framePatternLen) ||
  936.              (framePattern[index+1] != 'b') ) {
  937.             frameTable[index].nextOutput = NULL;
  938.         } else {
  939.             frameTable[index].nextOutput = &(frameTable[index+1]);
  940.         }
  941.         frameTable[index].prev = lastIP;
  942.         lastIP->freeNow = FALSE;
  943.         if ( firstB == NULL ) {
  944.             firstB = &(frameTable[index]);
  945.         }
  946.         break;
  947.     }
  948.     }
  949.  
  950.     frameTable[framePatternLen].number = framePatternLen;
  951.     frameTable[framePatternLen].frame = NULL;
  952.  
  953.     ptr = firstB;
  954.     while ( ptr != NULL ) {
  955.     ptr->next = &(frameTable[framePatternLen]);
  956.     ptr = ptr->nextOutput;
  957.     }
  958.     frameTable[framePatternLen].nextOutput = firstB;
  959.     frameTable[framePatternLen].prev = lastIP;
  960.     frameTable[framePatternLen].freeNow = frameTable[0].freeNow;
  961.  
  962.     frameTable[0].prev = lastIP;
  963.     if ( lastIP != NULL ) {
  964.     lastIP->next = &(frameTable[framePatternLen]);
  965.     }
  966.  
  967.     for ( index = 0; index < framePatternLen+1; index++ ) {
  968.     if ( frameTable[index].prev == NULL ) {
  969.         numberP = -1;
  970.     } else {
  971.         numberP = frameTable[index].prev->number;
  972.     }
  973.  
  974.     if ( frameTable[index].next == NULL ) {
  975.         numberN = -1;
  976.     } else {
  977.         numberN = frameTable[index].next->number;
  978.     }
  979.  
  980.     if ( frameTable[index].nextOutput == NULL ) {
  981.         numberNO = -1;
  982.     } else {
  983.         numberNO = frameTable[index].nextOutput->number;
  984.     }
  985.     }
  986. }
  987.  
  988.  
  989. /*===========================================================================*
  990.  *
  991.  * ProcessRefFrame
  992.  *
  993.  *    process an I or P frame -- encode it, and process any B frames that
  994.  *    we can now
  995.  *
  996.  * RETURNS:    nothing
  997.  *
  998.  * SIDE EFFECTS:    stuff appended to bb
  999.  *
  1000.  *===========================================================================*/
  1001. static void
  1002. ProcessRefFrame(entry, bb, lastFrame, outputFileName)
  1003.     FrameTable *entry;
  1004.     BitBucket *bb;
  1005.     int lastFrame;
  1006.     char *outputFileName;
  1007. {
  1008.     FrameTable *ptr;
  1009.     char    fileName[1024];
  1010.     char    inputFileName[1024];
  1011.     FILE    *fpointer = NULL;
  1012.     boolean separateFiles;
  1013.     int        id;
  1014.     time_t  tempTimeStart, tempTimeEnd;
  1015.  
  1016.     separateFiles = (bb == NULL);
  1017.  
  1018.     if ( separateFiles && (entry->frame->id >= realStart) &&
  1019.      (entry->frame->id <= realEnd) ) {
  1020.     if ( remoteIO ) {
  1021.         bb = Bitio_New(NULL);
  1022.     } else {
  1023.         sprintf(fileName, "%s.frame.%d", outputFileName, entry->frame->id);
  1024. /* @@@ Open binary mode for OS/2, Andy Key */
  1025. #ifdef OS2
  1026.         if ( (fpointer = fopen(fileName, "wb")) == NULL ) {
  1027. #else
  1028.         if ( (fpointer = fopen(fileName, "w")) == NULL ) {
  1029. #endif
  1030.         fprintf(stderr, "ERROR:  Could not open output file:  %s\n",
  1031.             fileName);
  1032.         exit(1);
  1033.         }
  1034.  
  1035.         bb = Bitio_New(fpointer);
  1036.     }
  1037.     }
  1038.  
  1039.     /* nothing to do */
  1040.     if ( entry->frame->id < realStart ) {
  1041.     return;
  1042.     }
  1043.  
  1044.     /* first, output this frame */
  1045.     if ( entry->frame->type == TYPE_IFRAME ) {
  1046.     /* only start a new GOP with I */
  1047.     /* don't start GOP if only doing frames */
  1048.     if ( (! separateFiles) && (currentGOP >= gopSize) ) {
  1049.         int closed;
  1050.  
  1051.         /* first, check to see if closed GOP */
  1052.         if ( totalFramesSent == entry->frame->id ) {
  1053.         closed = 1;
  1054.         } else {
  1055.         closed = 0;
  1056.         }
  1057.  
  1058.         fprintf(stdout, "Creating new GOP (closed = %d) before frame %d\n",
  1059.             closed, entry->frame->id);
  1060.  
  1061.         /* new GOP */
  1062.         Mhead_GenGOPHeader(bb, /* drop_frame_flag */ 0,
  1063.                tc_hrs, tc_min, tc_sec, tc_pict,
  1064.                closed, /* broken_link */ 0,
  1065.                /* ext_data */ NULL, /* ext_data_size */ 0,
  1066.                /* user_data */ NULL, /* user_data_size */ 0);
  1067.         currentGOP -= gopSize;
  1068.         SetGOPStartTime(entry->frame->id);
  1069.     }
  1070.  
  1071.     if ( (entry->frame->id >= realStart) && (entry->frame->id <= realEnd) ) {
  1072.         GenIFrame(bb, entry->frame);
  1073.         framesOutput++;
  1074.  
  1075.         if ( separateFiles ) {
  1076.         if ( remoteIO ) {
  1077.             SendRemoteFrame(entry->frame->id, bb);
  1078.         } else {
  1079.             Bitio_Flush(bb);
  1080.             fclose(fpointer);
  1081.         }
  1082.         }
  1083.     }
  1084.  
  1085.     numI--;
  1086.     timeMask &= 0x6;
  1087.  
  1088.     currentGOP++;
  1089.     IncrementTCTime();
  1090.     } else {
  1091.     if ( (entry->frame->id >= realStart) && (entry->frame->id <= realEnd) ) {
  1092.         GenPFrame(bb, entry->frame, entry->prev->frame);
  1093.         framesOutput++;
  1094.  
  1095.         if ( separateFiles ) {
  1096.         if ( remoteIO ) {
  1097.             SendRemoteFrame(entry->frame->id, bb);
  1098.         } else {
  1099.             Bitio_Flush(bb);
  1100.             fclose(fpointer);
  1101.         }
  1102.         }
  1103.     }
  1104.  
  1105.     numP--;
  1106.     timeMask &= 0x5;
  1107.     ShowRemainingTime();
  1108.  
  1109.     currentGOP++;
  1110.     IncrementTCTime();
  1111.     }
  1112.  
  1113.     /* now, follow nextOutput and output B-frames */
  1114.     ptr = entry->nextOutput;
  1115.     while ( ptr != NULL ) {
  1116.     id = entry->frame->id - (entry->number - ptr->number);
  1117.  
  1118.     if ( (id >= realStart) && (id <= realEnd) ) {
  1119.         ptr->frame = Frame_New(id, 'b');
  1120.  
  1121.         time(&tempTimeStart);
  1122.  
  1123.         /* read B frame, output it */
  1124.         if ( remoteIO ) {
  1125.         GetRemoteFrame(ptr->frame, ptr->frame->id);
  1126.         } else {
  1127.         GetNthInputFileName(inputFileName, id);
  1128.         if ( childProcess && separateConversion ) {
  1129.             ReadFrame(ptr->frame, inputFileName, slaveConversion, TRUE);
  1130.         } else {
  1131.             ReadFrame(ptr->frame, inputFileName, inputConversion, TRUE);
  1132.         }
  1133.         }
  1134.  
  1135.         time(&tempTimeEnd);
  1136.         IOtime += (tempTimeEnd-tempTimeStart);
  1137.  
  1138.         if ( separateFiles ) {
  1139.         if ( remoteIO ) {
  1140.             bb = Bitio_New(NULL);
  1141.         } else {
  1142.             sprintf(fileName, "%s.frame.%d", outputFileName, ptr->frame->id);
  1143. /* @@@ Open binary mode for OS/2, Andy Key */
  1144. #ifdef OS2
  1145.             if ( (fpointer = fopen(fileName, "wb")) == NULL ) {
  1146. #else
  1147.             if ( (fpointer = fopen(fileName, "w")) == NULL ) {
  1148. #endif
  1149.             fprintf(stderr, "ERROR:  Could not open output file:  %s\n",
  1150.                 fileName);
  1151.             exit(1);
  1152.             }
  1153.             bb = Bitio_New(fpointer);
  1154.         }
  1155.         }
  1156.  
  1157.         GenBFrame(bb, ptr->frame, ptr->prev->frame, ptr->next->frame);
  1158.         framesOutput++;
  1159.  
  1160.         if ( separateFiles ) {
  1161.         if ( remoteIO ) {
  1162.             SendRemoteFrame(ptr->frame->id, bb);
  1163.         } else {
  1164.             Bitio_Flush(bb);
  1165.             fclose(fpointer);
  1166.         }
  1167.         }
  1168.  
  1169.         /* free this B frame right away */
  1170.         Frame_Free(ptr->frame);
  1171.         ptr->frame = NULL;
  1172.     }
  1173.  
  1174.     numB--;
  1175.     timeMask &= 0x3;
  1176.     ShowRemainingTime();
  1177.  
  1178.     currentGOP++;
  1179.     IncrementTCTime();
  1180.  
  1181.     ptr = ptr->nextOutput;
  1182.     }
  1183.  
  1184.     /* now free previous frame, if there was one */
  1185.     if ( (entry->frame->type != TYPE_IFRAME) ||
  1186.      (entry->nextOutput != NULL) ) {
  1187.     if ( entry->prev->frame != NULL ) {
  1188.         Frame_Free(entry->prev->frame);
  1189.         entry->prev->frame = NULL;
  1190.     }
  1191.     }
  1192.  
  1193.     /* check to see if we can free this frame now */
  1194.     if ( entry->freeNow || (entry->frame->id == lastFrame) ) {
  1195.     if ( entry->frame != NULL ) {
  1196.         Frame_Free(entry->frame);
  1197.         entry->frame = NULL;
  1198.     }
  1199.     }
  1200.  
  1201.     /* note, we may still not free last frame if lastFrame is incorrect
  1202.     (if the last frames are B frames, they aren't output!)
  1203.      */
  1204. }
  1205.  
  1206.  
  1207. /*===========================================================================*
  1208.  *
  1209.  * ShowRemainingTime
  1210.  *
  1211.  *    print out an estimate of the time left to encode
  1212.  *
  1213.  * RETURNS:    nothing
  1214.  *
  1215.  * SIDE EFFECTS:    none
  1216.  *
  1217.  *===========================================================================*/
  1218. static void
  1219. ShowRemainingTime()
  1220. {
  1221.     static int    lastTime = 0;
  1222.     float   timeI, timeP, timeB;
  1223.     float   total;
  1224.  
  1225.     if ( childProcess ) {
  1226.     return /* nothing */;
  1227.     }
  1228.  
  1229.     if ( numI + numP + numB == 0 ) {    /* no time left */
  1230.     return /* nothing */ ;
  1231.     }
  1232.  
  1233.     if ( timeMask != 0 ) {        /* haven't encoded all types yet */
  1234.     return /* nothing */ ;
  1235.     }
  1236.  
  1237.     timeI = EstimateSecondsPerIFrame();
  1238.     timeP = EstimateSecondsPerPFrame();
  1239.     timeB = EstimateSecondsPerBFrame();
  1240.  
  1241.     total = (float)numI*timeI + (float)numP*timeP + (float)numB*timeB;
  1242.  
  1243.     if ( (quietTime >= 0) &&
  1244.      (((lastTime-(int)total) >= quietTime) || (lastTime == 0)) ) {
  1245.     if ( total > 270.0 ) {
  1246.         fprintf(stdout, "ESTIMATED TIME OF COMPLETION:  %d minutes\n",
  1247.             ((int)total+30)/60);
  1248.     } else {
  1249.         fprintf(stdout, "ESTIMATED TIME OF COMPLETION:  %d seconds\n",
  1250.             (int)total);
  1251.     }
  1252.  
  1253.     lastTime = (int)total;
  1254.     }
  1255. }
  1256.  
  1257.  
  1258. void
  1259. ReadDecodedRefFrame(frame, frameNumber)
  1260.     MpegFrame *frame;
  1261.     int frameNumber;
  1262. {
  1263.     FILE    *fpointer;
  1264.     char    fileName[256];
  1265.     int    width, height;
  1266.     register int y;
  1267.  
  1268.     width = Fsize_x;
  1269.     height = Fsize_y;
  1270.  
  1271.     sprintf(fileName, "%s.decoded.%d", outputFileName, frameNumber);
  1272.     fprintf(stdout, "reading %s\n", fileName);
  1273.     fflush(stdout);
  1274.  
  1275. /* @@@ Open binary mode for OS/2, Andy Key */
  1276. #ifdef OS2
  1277.     fpointer = fopen(fileName, "rb");
  1278. #else
  1279.     fpointer = fopen(fileName, "r");
  1280. #endif
  1281.  
  1282.     Frame_AllocDecoded(frame, TRUE);
  1283.  
  1284.     for ( y = 0; y < height; y++ ) {
  1285.         fread(frame->decoded_y[y], 1, width, fpointer);
  1286.     }
  1287.  
  1288.     for (y = 0; y < height / 2; y++) {            /* U */
  1289.         fread(frame->decoded_cb[y], 1, width / 2, fpointer);
  1290.     }
  1291.  
  1292.     for (y = 0; y < height / 2; y++) {            /* V */
  1293.         fread(frame->decoded_cr[y], 1, width / 2, fpointer);
  1294.     }
  1295.  
  1296.     fclose(fpointer);
  1297. }
  1298.