home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 9
/
CD_ASCQ_09_1193.iso
/
news
/
4441
/
mpegcode
/
src
/
mpeg.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-09-27
|
29KB
|
1,102 lines
/*===========================================================================*
* mpeg.c *
* *
* Procedures to generate the MPEG sequence *
* *
* EXPORTED PROCEDURES: *
* SetFramePattern *
* GetMPEGStream *
* IncrementTCTime *
* SetStatFileName *
* SetGOPSize *
* PrintStartStats *
* *
*===========================================================================*/
/*
* Copyright (c) 1993 The Regents of the University of California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose, without fee, and without written agreement is
* hereby granted, provided that the above copyright notice and the following
* two paragraphs appear in all copies of this software.
*
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
* CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
/*
* $Header: /n/picasso/users/keving/encode/src/RCS/mpeg.c,v 1.6 1993/07/22 22:23:43 keving Exp keving $
* $Log: mpeg.c,v $
* Revision 1.6 1993/07/22 22:23:43 keving
* nothing
*
* Revision 1.5 1993/06/30 20:06:09 keving
* nothing
*
* Revision 1.4 1993/06/03 21:08:08 keving
* nothing
*
* Revision 1.3 1993/02/19 18:10:12 keving
* nothing
*
* Revision 1.2 1993/02/17 23:18:20 dwallach
* checkin prior to keving's joining the project
*
*/
/*==============*
* HEADER FILES *
*==============*/
#include "all.h"
#include <time.h>
#include <errno.h>
#include "mtypes.h"
#include "frames.h"
#include "search.h"
#include "mpeg.h"
#include "prototypes.h"
#include "parallel.h"
#include "param.h"
#include "readframe.h"
#include "fsize.h"
#include "mheaders.h"
/*===========*
* CONSTANTS *
*===========*/
#define FRAMES_PER_SECOND 30
/*==================*
* STATIC VARIABLES *
*==================*/
static int32 diffTime;
static int framesOutput;
static int realStart, realEnd;
static int currentGOP;
static int timeMask;
static int numI, numP, numB;
/*==================*
* GLOBAL VARIABLES *
*==================*/
int gopSize = 100; /* default */
int32 tc_hrs, tc_min, tc_sec, tc_pict;
int totalFramesSent;
int yuvWidth, yuvHeight;
FrameTable *frameTable;
char currentPath[MAXPATHLEN];
char statFileName[256];
time_t timeStart, timeEnd;
FILE *statFile;
char *framePattern;
int framePatternLen;
int referenceFrame;
/*===============================*
* INTERNAL PROCEDURE prototypes *
*===============================*/
static void ShowRemainingTime _ANSI_ARGS_((void));
static void ComputeDHMSTime _ANSI_ARGS_((int32 someTime, char *timeText));
static void ComputeGOPFrames _ANSI_ARGS_((int whichGOP, int *firstFrame,
int *lastFrame, int numFrames));
static void PrintEndStats _ANSI_ARGS_((int inputFrameBits, int32 totalBits));
static void ComputeFrameTable _ANSI_ARGS_((void));
static void ProcessNonBFrame _ANSI_ARGS_((FrameTable *entry,
BitBucket *bb, int lastFrame,
char *outputFileName,
boolean remoteIO));
/*=====================*
* EXPORTED PROCEDURES *
*=====================*/
/*===========================================================================*
*
* SetReferenceFrameType
*
* set the reference frame type to be original or decoded
*
* RETURNS: nothing
*
* SIDE EFFECTS: referenceFrame
*
*===========================================================================*/
void
SetReferenceFrameType(type)
char *type;
{
if ( strcmp(type, "ORIGINAL") == 0 ) {
referenceFrame = ORIGINAL_FRAME;
} else if ( strcmp(type, "DECODED") == 0 ) {
referenceFrame = DECODED_FRAME;
} else {
fprintf(stderr, "ERROR: Illegal reference frame type: '%s'\n",
type);
exit(1);
}
}
/*===========================================================================*
*
* SetFramePattern
*
* set the IPB pattern; calls ComputeFrameTable to set up table
*
* RETURNS: nothing
*
* SIDE EFFECTS: framePattern, framePatternLen, frameTable
*
*===========================================================================*/
void
SetFramePattern(pattern)
char *pattern;
{
int len = strlen(pattern);
char *buf;
int index;
if ( ! pattern ) {
fprintf(stderr, "pattern cannot be NULL\n");
exit(1);
}
if ( pattern[0] != 'i' && pattern[0] != 'I' ) {
fprintf(stderr, "first frame must be 'i'\n");
exit(1);
}
buf = (char *)malloc(sizeof(char)*(len+1));
ERRCHK(buf, "malloc");
for ( index = 0; index < len; index++ ) {
switch( pattern[index] ) {
case 'i': case 'I': buf[index] = 'i'; break;
case 'p': case 'P': buf[index] = 'p'; break;
case 'b': case 'B': buf[index] = 'b'; break;
default:
fprintf(stderr, "Frame type '%c' not supported.\n", pattern[index]);
exit(1);
}
}
buf[len] = 0;
framePattern = buf;
framePatternLen = len;
ComputeFrameTable();
}
/*===========================================================================*
*
* GenMPEGStream
*
* generate an MPEG sequence stream (generally)
* if whichGOP == frameStart == -1 then does complete MPEG sequence
* if whichGOP != -1 then does numbered GOP only (without sequence
* header)
* if frameStart != -1 then does numbered frames only (without any
* sequence or GOP headers)
* if remoteIO == TRUE then uses the I/O server
*
* RETURNS: amount of time it took
*
* SIDE EFFECTS: too numerous to mention
*
*===========================================================================*/
int32
GenMPEGStream(whichGOP, frameStart, frameEnd, numFrames, ofp, outputFileName,
remoteIO)
int whichGOP;
int frameStart;
int frameEnd;
int numFrames;
FILE *ofp;
char *outputFileName;
boolean remoteIO;
{
BitBucket *bb;
int i;
char frameType;
MpegFrame *frame;
FrameTable *entry = NULL;
int firstFrame, lastFrame;
int inputFrameBits = 0;
char inputFileName[1024];
ResetIFrameStats();
ResetPFrameStats();
ResetBFrameStats();
Fsize_Reset();
framesOutput = 0;
if ( whichGOP != -1 ) {
ComputeGOPFrames(whichGOP, &firstFrame, &lastFrame, numFrames);
realStart = firstFrame;
realEnd = lastFrame;
} else if ( frameStart != -1 ) {
if ( frameEnd > numFrames-1 ) {
fprintf(stdout, "ERROR: Specified last frame is out of bounds\n");
exit(1);
}
realStart = frameStart;
realEnd = frameEnd;
firstFrame = frameStart;
lastFrame = frameEnd;
/* if first frame is P or B, need to read in P or I frame before it */
if ( FRAME_TYPE(firstFrame) != 'i' ) {
entry = &(frameTable[firstFrame % framePatternLen]);
firstFrame = firstFrame - (entry->number - entry->prev->number);
}
/* if last frame is B, need to read in P or I frame after it */
if ( (FRAME_TYPE(lastFrame) == 'b') && (lastFrame != numFrames-1) ) {
entry = &(frameTable[lastFrame % framePatternLen]);
lastFrame = lastFrame + (entry->next->number - entry->number);
}
if ( lastFrame > numFrames-1 ) { /* can't go last frame! */
lastFrame = numFrames-1;
}
} else {
firstFrame = 0;
lastFrame = numFrames-1;
realStart = 0;
realEnd = numFrames-1;
}
/* count number of I, P, and B frames */
numI = 0; numP = 0; numB = 0;
timeMask = 0;
for ( i = firstFrame; i <= lastFrame; i++ ) {
frameType = FRAME_TYPE(i);
switch(frameType) {
case 'i': numI++; timeMask |= 0x1; break;
case 'p': numP++; timeMask |= 0x2; break;
case 'b': numB++; timeMask |= 0x4; break;
}
}
time(&timeStart);
if ( ! childProcess ) {
PrintStartStats(realStart, realEnd);
}
if ( frameStart == -1 ) {
bb = Bitio_New(ofp);
} else {
bb = NULL;
}
SetFileType();
tc_hrs = 0; tc_min = 0; tc_sec = 0; tc_pict = 0;
for ( i = 0; i < firstFrame; i++ ) {
IncrementTCTime();
}
totalFramesSent = firstFrame;
currentGOP = gopSize; /* so first I-frame generates GOP Header */
if ( FRAME_TYPE(firstFrame) == 'b' ) {
/* need to load in previous frame; call it an I frame */
frame = Frame_New(firstFrame-1, 'i');
if ( remoteIO ) {
GetRemoteFrame(frame, firstFrame-1);
} else {
GetNthInputFileName(inputFileName, firstFrame-1);
ReadFrame(frame, inputFileName, inputConversion, TRUE);
}
/* should put in the correct frameTable place */
}
for ( i = firstFrame; i <= lastFrame; i++) {
frameType = FRAME_TYPE(i);
if ( frameType == 'b' ) {
continue;
}
frame = Frame_New(i, frameType);
if ( (i != firstFrame) && ((i % framePatternLen) == 0) ) {
entry = &(frameTable[framePatternLen]);
} else {
entry = &(frameTable[i % framePatternLen]);
}
entry->frame = frame;
if ( remoteIO ) {
GetRemoteFrame(frame, i);
} else {
GetNthInputFileName(inputFileName, i);
ReadFrame(frame, inputFileName, inputConversion, TRUE);
}
if ( i == firstFrame ) {
inputFrameBits = 24*Fsize_x*Fsize_y;
SetBlocksPerSlice();
if ( (whichGOP == -1) && (frameStart == -1) ) {
DBG_PRINT(("Generating sequence header\n"));
Mhead_GenSequenceHeader(bb, Fsize_x, Fsize_y, /* pratio */ 1,
/* pict_rate */ -1, /* bit_rate */ -1,
/* buf_size */ -1, /*c_param_flag */ 1,
/* iq_matrix */ NULL, /* niq_matrix */ NULL,
/* ext_data */ NULL, /* ext_data_size */ 0,
/* user_data */ NULL, /* user_data_size */ 0);
}
}
ProcessNonBFrame(entry, bb, lastFrame, outputFileName, remoteIO);
/* in case this is first frame of pattern sequence; put it
back to 0 */
if ( entry == &frameTable[framePatternLen]) {
frameTable[0].frame = frame;
}
}
if ( entry->frame != NULL ) {
Frame_Free(entry->frame);
}
/* SEQUENCE END CODE */
if ( (whichGOP == -1) && (frameStart == -1) ) {
Mhead_GenSequenceEnder(bb);
}
if ( frameStart == -1 ) {
Bitio_Flush(bb);
fclose(ofp);
time(&timeEnd);
diffTime = (int32)(timeEnd-timeStart);
if ( ! childProcess ) {
PrintEndStats(inputFrameBits, bb->cumulativeBits);
}
} else {
time(&timeEnd);
diffTime = (int32)(timeEnd-timeStart);
if ( ! childProcess ) {
PrintEndStats(inputFrameBits, 1);
}
}
if ( childProcess ) {
NoteFrameDone(frameStart, frameEnd);
}
return diffTime;
}
/*===========================================================================*
*
* IncrementTCTime
*
* increment the tc time by one second (and update min, hrs if necessary)
* also increments totalFramesSent
*
* RETURNS: nothing
*
* SIDE EFFECTS: totalFramesSent, tc_pict, tc_sec, tc_min, tc_hrs
*
*===========================================================================*/
void
IncrementTCTime()
{
totalFramesSent++;
tc_pict++;
if ( tc_pict == FRAMES_PER_SECOND ) {
tc_pict = 0;
tc_sec++;
if ( tc_sec == 60 ) {
tc_sec = 0;
tc_min++;
if ( tc_min == 60 ) {
tc_min = 0;
tc_hrs++;
}
}
}
}
/*===========================================================================*
*
* SetStatFileName
*
* set the statistics file name
*
* RETURNS: nothing
*
* SIDE EFFECTS: statFileName
*
*===========================================================================*/
void
SetStatFileName(fileName)
char *fileName;
{
strcpy(statFileName, fileName);
}
/*===========================================================================*
*
* SetGOPSize
*
* set the GOP size (frames per GOP)
*
* RETURNS: nothing
*
* SIDE EFFECTS: gopSize
*
*===========================================================================*/
void
SetGOPSize(size)
int size;
{
gopSize = size;
}
/*===========================================================================*
*
* PrintStartStats
*
* print out the starting statistics (stuff from the param file)
* firstFrame, lastFrame represent the first, last frames to be
* encoded
*
* RETURNS: nothing
*
* SIDE EFFECTS: none
*
*===========================================================================*/
void
PrintStartStats(firstFrame, lastFrame)
int firstFrame;
int lastFrame;
{
FILE *fpointer;
register int i;
char inputFileName[1024];
if ( statFileName[0] == '\0' ) {
statFile = NULL;
} else {
statFile = fopen(statFileName, "a"); /* open for appending */
if ( statFile == NULL ) {
fprintf(stderr, "ERROR: Could not open stat file: %s\n", statFileName);
fprintf(stderr, " Sending statistics to stdout only.\n");
fprintf(stderr, "\n\n");
} else {
fprintf(stdout, "Appending statistics to file: %s\n", statFileName);
fprintf(stdout, "\n\n");
}
}
for ( i = 0; i < 2; i++ ) {
if ( i == 0 ) {
fpointer = stdout;
} else if ( statFile != NULL ) {
fpointer = statFile;
} else {
continue;
}
fprintf(fpointer, "MPEG ENCODER STATS\n");
fprintf(fpointer, "------------------\n");
fprintf(fpointer, "TIME STARTED: %s", ctime(&timeStart));
if ( getenv("HOST") != NULL ) {
fprintf(fpointer, "MACHINE: %s\n", getenv("HOST"));
} else {
fprintf(fpointer, "MACHINE: unknown\n");
}
if ( firstFrame == -1 ) {
fprintf(fpointer, "OUTPUT: %s\n", outputFileName);
} else {
GetNthInputFileName(inputFileName, firstFrame);
fprintf(fpointer, "FIRST FILE: %s/%s\n", currentPath, inputFileName);
GetNthInputFileName(inputFileName, lastFrame);
fprintf(fpointer, "LAST FILE: %s/%s\n", currentPath,
inputFileName);
}
fprintf(fpointer, "PATTERN: %s\n", framePattern);
fprintf(fpointer, "GOP_SIZE: %d\n", gopSize);
fprintf(fpointer, "SLICES PER FRAME: %d\n", slicesPerFrame);
fprintf(fpointer, "RANGE: +/-%d\n", searchRange/2);
fprintf(fpointer, "FULL SEARCH: %d\n", pixelFullSearch);
fprintf(fpointer, "PSEARCH: %s\n", PSearchName());
fprintf(fpointer, "BSEARCH: %s\n", BSearchName());
fprintf(fpointer, "QSCALE: %d %d %d\n", qscaleI,
GetPQScale(), GetBQScale());
if ( referenceFrame == DECODED_FRAME ) {
fprintf(fpointer, "REFERENCE FRAME: DECODED\n");
} else if ( referenceFrame == ORIGINAL_FRAME ) {
fprintf(fpointer, "REFERENCE FRAME: ORIGINAL\n");
} else {
fprintf(stderr, "ERROR: Illegal referenceFrame!!!\n");
exit(1);
}
}
fprintf(stdout, "\n\n");
}
/*=====================*
* INTERNAL PROCEDURES *
*=====================*/
/*===========================================================================*
*
* ComputeDHMSTime
*
* turn some number of seconds (someTime) into a string which
* summarizes that time according to scale (days, hours, minutes, or
* seconds)
*
* RETURNS: nothing
*
* SIDE EFFECTS: none
*
*===========================================================================*/
static void
ComputeDHMSTime(someTime, timeText)
int32 someTime;
char *timeText;
{
int days, hours, mins, secs;
days = someTime / (24*60*60);
someTime -= days*24*60*60;
hours = someTime / (60*60);
someTime -= hours*60*60;
mins = someTime / 60;
secs = someTime - mins*60;
if ( days > 0 ) {
sprintf(timeText, "Total time: %d days and %d hours", days, hours);
} else if ( hours > 0 ) {
sprintf(timeText, "Total time: %d hours and %d minutes", hours, mins);
} else if ( mins > 0 ) {
sprintf(timeText, "Total time: %d minutes and %d seconds", mins, secs);
} else {
sprintf(timeText, "Total time: %d seconds", secs);
}
}
/*===========================================================================*
*
* ComputeGOPFrames
*
* calculate the first, last frames of the numbered GOP
*
* RETURNS: lastFrame, firstFrame changed
*
* SIDE EFFECTS: none
*
*===========================================================================*/
static void
ComputeGOPFrames(whichGOP, firstFrame, lastFrame, numFrames)
int whichGOP;
int *firstFrame;
int *lastFrame;
int numFrames;
{
int passedB;
int currGOP;
int gopNum, frameNum;
/* calculate first, last frames of whichGOP GOP */
*firstFrame = -1;
*lastFrame = -1;
gopNum = 0;
frameNum = 0;
passedB = 0;
currGOP = 0;
while ( *lastFrame == -1 ) {
if ( frameNum >= numFrames ) {
fprintf(stderr, "ERROR: There aren't that many GOPs!\n");
exit(1);
}
fprintf(stdout, "GOP STARTS AT %d\n", frameNum-passedB);
if ( gopNum == whichGOP ) {
*firstFrame = frameNum-passedB;
}
/* go past one gop */
while ( (frameNum < numFrames) &&
((FRAME_TYPE(frameNum) != 'i') || currGOP < gopSize) ) {
currGOP += (1 + passedB);
frameNum++;
passedB = 0;
while ( FRAME_TYPE(frameNum) == 'b' ) {
frameNum++;
passedB++;
}
}
currGOP -= gopSize;
if ( gopNum == whichGOP ) {
*lastFrame = (frameNum-passedB-1);
}
fprintf(stdout, "GOP ENDS at %d\n", frameNum-passedB-1);
gopNum++;
}
}
/*===========================================================================*
*
* PrintEndStats
*
* print end statistics (summary, time information)
*
* RETURNS: nothing
*
* SIDE EFFECTS: none
*
*===========================================================================*/
static void
PrintEndStats(inputFrameBits, totalBits)
int inputFrameBits;
int32 totalBits;
{
FILE *fpointer;
register int i;
char timeText[256];
fprintf(stdout, "\n\n");
ComputeDHMSTime(diffTime, timeText);
for ( i = 0; i < 2; i++ ) {
if ( i == 0 ) {
fpointer = stdout;
} else if ( statFile != NULL ) {
fpointer = statFile;
} else {
continue;
}
fprintf(fpointer, "TIME COMPLETED: %s", ctime(&timeEnd));
fprintf(fpointer, "%s\n\n", timeText);
ShowIFrameSummary(inputFrameBits, totalBits, fpointer);
ShowPFrameSummary(inputFrameBits, totalBits, fpointer);
ShowBFrameSummary(inputFrameBits, totalBits, fpointer);
fprintf(fpointer, "---------------------------------------------\n");
fprintf(fpointer, "Total Compression: %3d:1\n",
framesOutput*inputFrameBits/totalBits);
fprintf(fpointer, "Total Frames Per Second: %f\n",
(float)framesOutput/(float)diffTime);
fprintf(fpointer, "Total Output Bit Rate (30 fps): %d bits/sec\n",
30*totalBits/framesOutput);
fprintf(fpointer, "\n\n");
}
if ( statFile != NULL ) {
fclose(statFile);
}
}
/*===========================================================================*
*
* ComputeFrameTable
*
* compute a table of I, P, B frames to help in determining dependencies
*
* RETURNS: nothing
*
* SIDE EFFECTS: frameTable
*
*===========================================================================*/
static void
ComputeFrameTable()
{
register int index;
FrameTable *lastI, *lastIP, *firstB;
FrameTable *ptr;
int numberP, numberN, numberNO;
frameTable = (FrameTable *) malloc((framePatternLen+1)*sizeof(FrameTable));
lastI = NULL;
lastIP = NULL;
firstB = NULL;
for ( index = 0; index < framePatternLen; index++ ) {
frameTable[index].number = index;
frameTable[index].freeNow = TRUE;
frameTable[index].frame = NULL;
switch( framePattern[index] ) {
case 'i':
ptr = firstB;
while ( ptr != NULL ) {
ptr->next = &(frameTable[index]);
ptr = ptr->nextOutput;
}
frameTable[index].nextOutput = firstB;
frameTable[index].prev = lastIP; /* for freeing */
lastIP = &(frameTable[index]);
firstB = NULL;
break;
case 'p':
ptr = firstB;
while ( ptr != NULL ) {
ptr->next = &(frameTable[index]);
ptr = ptr->nextOutput;
}
frameTable[index].nextOutput = firstB;
frameTable[index].prev = lastIP;
lastIP->freeNow = FALSE;
lastIP = &(frameTable[index]);
firstB = NULL;
break;
case 'b':
if ( (index+1 == framePatternLen) ||
(framePattern[index+1] != 'b') ) {
frameTable[index].nextOutput = NULL;
} else {
frameTable[index].nextOutput = &(frameTable[index+1]);
}
frameTable[index].prev = lastIP;
lastIP->freeNow = FALSE;
if ( firstB == NULL ) {
firstB = &(frameTable[index]);
}
break;
}
}
frameTable[framePatternLen].number = framePatternLen;
frameTable[framePatternLen].frame = NULL;
ptr = firstB;
while ( ptr != NULL ) {
ptr->next = &(frameTable[framePatternLen]);
ptr = ptr->nextOutput;
}
frameTable[framePatternLen].nextOutput = firstB;
frameTable[framePatternLen].prev = lastIP;
frameTable[framePatternLen].freeNow = frameTable[0].freeNow;
for ( index = 0; index < framePatternLen+1; index++ ) {
if ( frameTable[index].prev == NULL ) {
numberP = -1;
} else {
numberP = frameTable[index].prev->number;
}
if ( frameTable[index].next == NULL ) {
numberN = -1;
} else {
numberN = frameTable[index].next->number;
}
if ( frameTable[index].nextOutput == NULL ) {
numberNO = -1;
} else {
numberNO = frameTable[index].nextOutput->number;
}
}
}
/*===========================================================================*
*
* ProcessNonBFrame
*
* process an I or P frame -- encode it, and process any B frames that
* we can now
*
* RETURNS: nothing
*
* SIDE EFFECTS: stuff appended to bb
*
*===========================================================================*/
static void
ProcessNonBFrame(entry, bb, lastFrame, outputFileName, remoteIO)
FrameTable *entry;
BitBucket *bb;
int lastFrame;
char *outputFileName;
boolean remoteIO;
{
FrameTable *ptr;
char fileName[1024];
char inputFileName[1024];
FILE *fpointer = NULL;
boolean separateFiles;
int id;
separateFiles = (bb == NULL);
if ( separateFiles && (entry->frame->id >= realStart) &&
(entry->frame->id <= realEnd) ) {
if ( remoteIO ) {
bb = Bitio_New(NULL);
} else {
sprintf(fileName, "%s.frame.%d", outputFileName, entry->frame->id);
if ( (fpointer = fopen(fileName, "wb")) == NULL ) {
fprintf(stderr, "ERROR: Could not open output file: %s\n",
fileName);
exit(1);
}
bb = Bitio_New(fpointer);
}
}
/* nothing to do */
if ( entry->frame->id < realStart ) {
return;
}
/* first, output this frame */
if ( entry->frame->type == TYPE_IFRAME ) {
/* only start a new GOP with I */
/* don't start GOP if only doing frames */
if ( (! separateFiles) && (currentGOP >= gopSize) ) {
int closed;
/* first, check to see if closed GOP */
if ( totalFramesSent == entry->frame->id ) {
closed = 1;
} else {
closed = 0;
}
fprintf(stdout, "Creating new GOP (closed = %d) before frame %d\n",
closed, entry->frame->id);
/* new GOP */
Mhead_GenGOPHeader(bb, /* drop_frame_flag */ 0,
tc_hrs, tc_min, tc_sec, tc_pict,
closed, /* broken_link */ 0,
/* ext_data */ NULL, /* ext_data_size */ 0,
/* user_data */ NULL, /* user_data_size */ 0);
currentGOP -= gopSize;
}
if ( (entry->frame->id >= realStart) && (entry->frame->id <= realEnd) ) {
GenIFrame(bb, entry->frame);
framesOutput++;
if ( separateFiles ) {
if ( remoteIO ) {
SendRemoteFrame(entry->frame->id, bb);
} else {
Bitio_Flush(bb);
fclose(fpointer);
}
}
}
numI--;
timeMask &= 0x6;
currentGOP++;
IncrementTCTime();
} else {
if ( (entry->frame->id >= realStart) && (entry->frame->id <= realEnd) ) {
GenPFrame(bb, entry->frame, entry->prev->frame);
framesOutput++;
if ( separateFiles ) {
if ( remoteIO ) {
SendRemoteFrame(entry->frame->id, bb);
} else {
Bitio_Flush(bb);
fclose(fpointer);
}
}
}
numP--;
timeMask &= 0x5;
ShowRemainingTime();
currentGOP++;
IncrementTCTime();
}
/* now, follow nextOutput and output B-frames */
ptr = entry->nextOutput;
while ( ptr != NULL ) {
id = entry->frame->id - (entry->number - ptr->number);
if ( (id >= realStart) && (id <= realEnd) ) {
ptr->frame = Frame_New(id, 'b');
/* read B frame, output it */
if ( remoteIO ) {
GetRemoteFrame(ptr->frame, ptr->frame->id);
} else {
GetNthInputFileName(inputFileName, id);
ReadFrame(ptr->frame, inputFileName, inputConversion, TRUE);
}
if ( separateFiles ) {
if ( remoteIO ) {
bb = Bitio_New(NULL);
} else {
sprintf(fileName, "%s.frame.%d", outputFileName, ptr->frame->id);
if ( (fpointer = fopen(fileName, "wb")) == NULL ) {
fprintf(stderr, "ERROR: Could not open output file: %s\n",
fileName);
exit(1);
}
bb = Bitio_New(fpointer);
}
}
GenBFrame(bb, ptr->frame, ptr->prev->frame, ptr->next->frame);
framesOutput++;
if ( separateFiles ) {
if ( remoteIO ) {
SendRemoteFrame(ptr->frame->id, bb);
} else {
Bitio_Flush(bb);
fclose(fpointer);
}
}
/* free this B frame right away */
Frame_Free(ptr->frame);
ptr->frame = NULL;
}
numB--;
timeMask &= 0x3;
ShowRemainingTime();
currentGOP++;
IncrementTCTime();
ptr = ptr->nextOutput;
}
/* now free previous frame, if there was one */
if ( (entry->frame->type != TYPE_IFRAME) ||
(entry->nextOutput != NULL) ) {
if ( entry->prev->frame != NULL ) {
Frame_Free(entry->prev->frame);
entry->prev->frame = NULL;
}
}
/* check to see if we can free this frame now */
if ( entry->freeNow || (entry->frame->id == lastFrame) ) {
if ( entry->frame != NULL ) {
Frame_Free(entry->frame);
entry->frame = NULL;
}
}
/* note, we may still not free last frame if lastFrame is incorrect
(if the last frames are B frames, they aren't output!)
*/
}
/*===========================================================================*
*
* ShowRemainingTime
*
* print out an estimate of the time left to encode
*
* RETURNS: nothing
*
* SIDE EFFECTS: none
*
*===========================================================================*/
static void
ShowRemainingTime()
{
static int lastTime = 0;
float timeI, timeP, timeB;
float total;
if ( childProcess ) {
return /* nothing */;
}
if ( numI + numP + numB == 0 ) { /* no time left */
return /* nothing */ ;
}
if ( timeMask != 0 ) { /* haven't encoded all types yet */
return /* nothing */ ;
}
timeI = EstimateSecondsPerIFrame();
timeP = EstimateSecondsPerPFrame();
timeB = EstimateSecondsPerBFrame();
total = (float)numI*timeI + (float)numP*timeP + (float)numB*timeB;
if ( (quietTime >= 0) &&
(((lastTime-(int)total) >= quietTime) || (lastTime == 0)) ) {
if ( total > 270.0 ) {
fprintf(stdout, "ESTIMATED TIME OF COMPLETION: %d minutes\n",
((int)total+30)/60);
} else {
fprintf(stdout, "ESTIMATED TIME OF COMPLETION: %d seconds\n",
(int)total);
}
lastTime = (int)total;
}
}