ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/freemol/trunk/src/mpeg_encode/src/mpeg.c
Revision: 22
Committed: Mon Jul 7 22:16:37 2008 UTC (11 years ago) by wdelano
File size: 43770 byte(s)
Log Message:
initial checkin of mpeg_encode source
Line File contents
1 /*===========================================================================*
2 * mpeg.c *
3 * *
4 * Procedures to generate the MPEG sequence *
5 * *
6 * EXPORTED PROCEDURES: *
7 * GetMPEGStream *
8 * IncrementTCTime *
9 * SetStatFileName *
10 * SetGOPSize *
11 * PrintStartStats *
12 * *
13 *===========================================================================*/
14
15 /*
16 * Copyright (c) 1995 The Regents of the University of California.
17 * All rights reserved.
18 *
19 * Permission to use, copy, modify, and distribute this software and its
20 * documentation for any purpose, without fee, and without written agreement is
21 * hereby granted, provided that the above copyright notice and the following
22 * two paragraphs appear in all copies of this software.
23 *
24 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
25 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
26 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
27 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
30 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
31 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
32 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
33 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
34 */
35
36 /*
37 * $Header: /n/picasso/project/mpeg/mpeg_dist/mpeg_encode/RCS/mpeg.c,v 1.24 1995/08/16 18:10:48 smoot Exp $
38 * $Log: mpeg.c,v $
39 * Revision 1.24 1995/08/16 18:10:48 smoot
40 * *** empty log message ***
41 *
42 * Revision 1.23 1995/08/07 21:48:08 smoot
43 * stdin bugs fixed
44 *
45 * Revision 1.22 1995/06/26 21:49:19 smoot
46 * added new frame ordering (hacks)^H^H^H^H^H code ;-)
47 *
48 * Revision 1.21 1995/06/21 18:30:41 smoot
49 * changed time structure to be ANSI
50 * changed file access to be binary (DOS!)
51 * added time to userdata
52 * Added a sleep to remote reads (NFS delay)
53 *
54 * Revision 1.20 1995/05/02 01:49:21 eyhung
55 * prints out true output bit rate and slightly untabified
56 *
57 * Revision 1.19 1995/05/02 00:45:35 eyhung
58 * endstats now contain correct output fbit rate at the specified frame rate
59 *
60 * Revision 1.18 1995/03/27 23:43:20 smoot
61 * killed printing long as int (compiler warning)
62 *
63 * Revision 1.17 1995/03/27 19:18:54 smoot
64 * fixed divide by zero for very quick encodings
65 *
66 * Revision 1.16 1995/02/02 22:03:37 smoot
67 * added types for MIPS
68 *
69 * Revision 1.15 1995/02/02 07:26:58 eyhung
70 * removed unused tempframe
71 *
72 * Revision 1.14 1995/02/01 05:01:35 eyhung
73 * Completed infinite coding-on-the-fly
74 *
75 * Revision 1.13 1995/02/01 02:34:02 eyhung
76 * Added full coding-on-the-fly
77 *
78 * Revision 1.12 1995/01/31 23:05:14 eyhung
79 * Added some stdin stuff
80 *
81 * Revision 1.11 1995/01/20 00:01:16 eyhung
82 * Added output file to PrintEndStats
83 *
84 * Revision 1.10 1995/01/19 23:08:51 eyhung
85 * Changed copyrights
86 *
87 * Revision 1.9 1995/01/17 18:55:54 smoot
88 * added right version number, and error if no frames selected
89 *
90 * Revision 1.8 1995/01/16 08:12:54 eyhung
91 * added realQuiet
92 *
93 * Revision 1.7 1994/12/07 00:40:36 smoot
94 * Added seperate P and B search ranges
95 *
96 * Revision 1.6 1994/11/28 21:46:45 smoot
97 * Added version printing
98 *
99 * Revision 1.5 1994/11/19 01:33:05 smoot
100 * put in userdata
101 *
102 * Revision 1.4 1994/11/14 22:36:22 smoot
103 * Merged specifics and rate control
104 *
105 * Revision 1.2 1994/03/15 00:27:11 keving
106 * nothing
107 *
108 * Revision 1.1 1993/12/22 19:19:01 keving
109 * nothing
110 *
111 * Revision 1.6 1993/07/22 22:23:43 keving
112 * nothing
113 *
114 * Revision 1.5 1993/06/30 20:06:09 keving
115 * nothing
116 *
117 * Revision 1.4 1993/06/03 21:08:08 keving
118 * nothing
119 *
120 * Revision 1.3 1993/02/19 18:10:12 keving
121 * nothing
122 *
123 * Revision 1.2 1993/02/17 23:18:20 dwallach
124 * checkin prior to keving's joining the project
125 *
126 */
127
128
129 /*==============*
130 * HEADER FILES *
131 *==============*/
132
133 #include "all.h"
134 #include <time.h>
135 #include <errno.h>
136 #include <unistd.h>
137 #include "mtypes.h"
138 #include "frames.h"
139 #include "search.h"
140 #include "mpeg.h"
141 #include "prototypes.h"
142 #include "parallel.h"
143 #include "param.h"
144 #include "readframe.h"
145 #include "fsize.h"
146 #include "mheaders.h"
147 #include "rate.h"
148 #ifdef MIPS
149 #include <sys/types.h>
150 #endif
151 #include <sys/stat.h>
152
153 /*===========*
154 * VERSION *
155 *===========*/
156
157 #define VERSION "1.5b"
158
159
160 /*===========*
161 * CONSTANTS *
162 *===========*/
163
164 #define FPS_30 0x5 /* from MPEG standard sect. 2.4.3.2 */
165 #define ASPECT_1 0x1 /* aspect ratio, from MPEG standard sect. 2.4.3.2 */
166
167
168 /*==================*
169 * STATIC VARIABLES *
170 *==================*/
171
172 static int32 diffTime;
173 static int framesOutput;
174 static int realStart, realEnd;
175 static int currentGOP;
176 static int timeMask;
177 static int numI, numP, numB;
178
179
180 /*==================*
181 * GLOBAL VARIABLES *
182 *==================*/
183
184 /* important -- don't initialize anything here */
185 /* must be re-initted anyway in GenMPEGStream */
186
187 extern int IOtime;
188 extern boolean resizeFrame;
189 extern int outputWidth, outputHeight;
190 int gopSize = 100; /* default */
191 int32 tc_hrs, tc_min, tc_sec, tc_pict, tc_extra;
192 int totalFramesSent;
193 int yuvWidth, yuvHeight;
194 int realWidth, realHeight;
195 char currentPath[MAXPATHLEN];
196 char statFileName[256];
197 char bitRateFileName[256];
198 time_t timeStart, timeEnd;
199 FILE *statFile;
200 FILE *bitRateFile = NULL;
201 char *framePattern;
202 int framePatternLen;
203 int referenceFrame;
204 static int framesRead;
205 MpegFrame *pastRefFrame;
206 MpegFrame *futureRefFrame;
207 int frameRate = FPS_30;
208 int frameRateRounded = 30;
209 boolean frameRateInteger = TRUE;
210 int aspectRatio = ASPECT_1;
211 extern unsigned char userDataFileName[];
212 extern int mult_seq_headers;
213
214 int32 bit_rate, buf_size;
215
216 /*===============================*
217 * INTERNAL PROCEDURE prototypes *
218 *===============================*/
219
220 static void ShowRemainingTime _ANSI_ARGS_((void));
221 static void ComputeDHMSTime _ANSI_ARGS_((int32 someTime, char *timeText));
222 static void ComputeGOPFrames _ANSI_ARGS_((int whichGOP, int *firstFrame,
223 int *lastFrame, int numFrames));
224 static void PrintEndStats _ANSI_ARGS_((int inputFrameBits, int32 totalBits));
225 static void ProcessRefFrame _ANSI_ARGS_((MpegFrame *frame,
226 BitBucket *bb, int lastFrame,
227 char *outputFileName));
228 static void OpenBitRateFile _ANSI_ARGS_((void));
229 static void CloseBitRateFile _ANSI_ARGS_((void));
230
231
232 /*=====================*
233 * EXPORTED PROCEDURES *
234 *=====================*/
235
236 /*===========================================================================*
237 *
238 * SetReferenceFrameType
239 *
240 * set the reference frame type to be original or decoded
241 *
242 * RETURNS: nothing
243 *
244 * SIDE EFFECTS: referenceFrame
245 *
246 *===========================================================================*/
247 void
248 SetReferenceFrameType(type)
249 char *type;
250 {
251 if ( strcmp(type, "ORIGINAL") == 0 ) {
252 referenceFrame = ORIGINAL_FRAME;
253 } else if ( strcmp(type, "DECODED") == 0 ) {
254 referenceFrame = DECODED_FRAME;
255 } else {
256 fprintf(stderr, "ERROR: Illegal reference frame type: '%s'\n",
257 type);
258 exit(1);
259 }
260 }
261
262 void
263 SetBitRateFileName(fileName)
264 char *fileName;
265 {
266 strcpy(bitRateFileName, fileName);
267 }
268
269
270 /*===========================================================================*
271 *
272 * GenMPEGStream
273 *
274 * generate an MPEG sequence stream (generally)
275 * if whichGOP == frameStart == -1 then does complete MPEG sequence
276 * if whichGOP != -1 then does numbered GOP only (without sequence
277 * header)
278 * if frameStart != -1 then does numbered frames only (without any
279 * sequence or GOP headers)
280 *
281 * RETURNS: amount of time it took
282 *
283 * SIDE EFFECTS: too numerous to mention
284 *
285 *===========================================================================*/
286 int32
287 GenMPEGStream(whichGOP, frameStart, frameEnd, qtable, niqtable, numFrames,
288 ofp, outputFileName)
289 int whichGOP;
290 int frameStart;
291 int frameEnd;
292 int32 qtable[];
293 int32 niqtable[];
294 int numFrames;
295 FILE *ofp;
296 char *outputFileName;
297 {
298 extern void PrintItoIBitRate _ANSI_ARGS_((int numBits, int frameNum));
299 BitBucket *bb;
300 int i;
301 char frameType;
302 MpegFrame *frame = NULL;
303 MpegFrame *tempFrame;
304 int firstFrame, lastFrame;
305 int inputFrameBits = 0;
306 char inputFileName[1024];
307 time_t tempTimeStart, tempTimeEnd;
308 boolean firstFrameDone = FALSE;
309 int numBits;
310 int32 bitstreamMode, res;
311
312 if ( (whichGOP == -1) && (frameStart == -1) &&
313 (! stdinUsed) && (FType_Type(numFrames-1) == 'b') ) {
314 fprintf(stderr, "\n");
315 fprintf(stderr, "WARNING: One or more B-frames at end will not be encoded.\n");
316 fprintf(stderr, " See FORCE_ENCODE_LAST_FRAME option in man page.\n");
317 fprintf(stderr, "\n");
318 }
319
320 time(&timeStart);
321
322 framesRead = 0;
323
324 ResetIFrameStats();
325 ResetPFrameStats();
326 ResetBFrameStats();
327
328 Fsize_Reset();
329
330 framesOutput = 0;
331
332 if ( childProcess && separateConversion ) {
333 SetFileType(slaveConversion);
334 } else {
335 SetFileType(inputConversion);
336 }
337
338 if ( whichGOP != -1 ) {
339 ComputeGOPFrames(whichGOP, &firstFrame, &lastFrame, numFrames);
340
341 realStart = firstFrame;
342 realEnd = lastFrame;
343
344 if ( FType_Type(firstFrame) == 'b' ) {
345
346 /* can't find the previous frame interactively */
347 if ( stdinUsed ) {
348 fprintf(stderr, "ERROR: Cannot encode GOP from stdin when first frame is a B-frame.\n");
349 exit(1);
350 }
351
352 /* need to load in previous frame; call it an I frame */
353 frame = Frame_New(firstFrame-1, 'i');
354
355 time(&tempTimeStart);
356
357 if ( (referenceFrame == DECODED_FRAME) &&
358 childProcess ) {
359 WaitForDecodedFrame(firstFrame);
360
361 if ( remoteIO ) {
362 GetRemoteDecodedRefFrame(frame, firstFrame-1);
363 } else {
364 ReadDecodedRefFrame(frame, firstFrame-1);
365 }
366 } else {
367 if ( remoteIO ) {
368 GetRemoteFrame(frame, firstFrame-1);
369 } else {
370 GetNthInputFileName(inputFileName, firstFrame-1);
371
372 if ( childProcess && separateConversion ) {
373 ReadFrame(frame, inputFileName, slaveConversion, TRUE);
374 } else {
375 ReadFrame(frame, inputFileName, inputConversion, TRUE);
376 }
377 }
378 }
379
380 framesRead++;
381
382 time(&tempTimeEnd);
383 IOtime += (tempTimeEnd-tempTimeStart);
384 }
385 } else if ( frameStart != -1 ) {
386 if ( frameEnd > numFrames-1 ) {
387 fprintf(stderr, "ERROR: Specified last frame is out of bounds\n");
388 exit(1);
389 }
390
391 realStart = frameStart;
392 realEnd = frameEnd;
393
394 firstFrame = frameStart;
395 lastFrame = frameEnd;
396
397 /* if first frame is P or B, need to read in P or I frame before it */
398 if ( FType_Type(firstFrame) != 'i' ) {
399
400 /* can't find the previous frame interactively */
401 if ( stdinUsed ) {
402 fprintf(stderr, "ERROR: Cannot encode frames from stdin when first frame is not an I-frame.\n");
403 exit(1);
404 }
405
406 firstFrame = FType_PastRef(firstFrame);
407 }
408
409 /* if last frame is B, need to read in P or I frame after it */
410 if ( (FType_Type(lastFrame) == 'b') && (lastFrame != numFrames-1) ) {
411
412 /* can't find the next reference frame interactively */
413 if ( stdinUsed ) {
414 fprintf(stderr, "ERROR: Cannot encode frames from stdin when last frame is a B-frame.\n");
415 exit(1);
416 }
417
418 lastFrame = FType_FutureRef(lastFrame);
419 }
420
421 if ( lastFrame > numFrames-1 ) { /* can't go last frame! */
422 lastFrame = numFrames-1;
423 }
424
425 } else {
426 firstFrame = 0;
427 lastFrame = numFrames-1;
428
429 realStart = 0;
430 realEnd = numFrames-1;
431 if ( numFrames == 0 ) {
432 fprintf(stderr, "ERROR: No frames selected!\n");
433 exit(1);
434 }
435 }
436
437 /* count number of I, P, and B frames */
438 numI = 0; numP = 0; numB = 0;
439 timeMask = 0;
440 if (stdinUsed) {
441 numI = numP = numB = MAXINT/4;
442 } else {
443 for ( i = firstFrame; i <= lastFrame; i++ ) {
444 frameType = FType_Type(i);
445 switch(frameType) {
446 case 'i': numI++; timeMask |= 0x1; break;
447 case 'p': numP++; timeMask |= 0x2; break;
448 case 'b': numB++; timeMask |= 0x4; break;
449 }
450 }
451 }
452
453 if ( ! childProcess ) {
454 if ( showBitRatePerFrame )
455 OpenBitRateFile();
456 PrintStartStats(realStart, realEnd);
457 }
458
459 if ( frameStart == -1 ) {
460 bb = Bitio_New(ofp);
461 } else {
462 bb = NULL;
463 }
464
465 tc_hrs = 0; tc_min = 0; tc_sec = 0; tc_pict = 0; tc_extra = 0;
466 for ( i = 0; i < firstFrame; i++ ) {
467 IncrementTCTime();
468 }
469
470 totalFramesSent = firstFrame;
471 currentGOP = gopSize; /* so first I-frame generates GOP Header */
472
473 /* Rate Control Initialization */
474 bitstreamMode = getRateMode();
475 if (bitstreamMode == FIXED_RATE) {
476 res = initRateControl();
477 /*
478 SetFrameRate();
479 */
480 }
481
482 #ifdef BLEAH
483 fprintf(stdout, "firstFrame, lastFrame = %d, %d; real = %d, %d\n",
484 firstFrame, lastFrame, realStart, realEnd);
485 fflush(stdout);
486 #endif
487
488 pastRefFrame = NULL;
489 futureRefFrame = NULL;
490 for ( i = firstFrame; i <= lastFrame; i++) {
491
492 /* break out of the near-infinite loop if input from stdin is done */
493 #if 0
494 char eofcheck[1];
495 if ( stdinUsed ) {
496 if (scanf("%c", eofcheck) != EOF) {
497 ungetc(eofcheck[0], stdin);
498 } else {
499 break;
500 }
501 }
502 #else
503 /*
504 ** For some reason the above version of this stdin EOF check does not
505 ** work right with jpeg files, the ungetc() is not padding anything to
506 ** stdin, I have no idea why (perhaps because a char is passed instead
507 ** of an int?), and it drove me nuts, so I wrote my own, slightly
508 ** cleaner version, and this one seems to work.
509 ** Dave Scott (dhs), UofO, 7/19/95.
510 */
511 if ( stdinUsed) {
512 int eofcheck_;
513 eofcheck_ = fgetc(stdin);
514 if ( eofcheck_ == EOF)
515 break;
516 else
517 ungetc(eofcheck_, stdin);
518 }
519 #endif
520 frameType = FType_Type(i);
521
522 time(&tempTimeStart);
523
524 /* skip non-reference frames if non-interactive
525 * read in non-reference frames if interactive */
526 if ( frameType == 'b' ) {
527 if ( stdinUsed ) {
528 frame = Frame_New(i, frameType);
529 ReadFrame(frame, "stdin", inputConversion, TRUE);
530
531 framesRead++;
532
533 time(&tempTimeEnd);
534 IOtime += (tempTimeEnd-tempTimeStart);
535
536 /* Add the B frame to the end of the queue of B-frames
537 * for later encoding
538 */
539
540 if (futureRefFrame != NULL) {
541 tempFrame = futureRefFrame;
542 while (tempFrame->next != NULL) {
543 tempFrame = tempFrame->next;
544 }
545 tempFrame->next = frame;
546 } else {
547 fprintf(stderr, "Yow, something wrong in neverland! (hit bad code in mpeg.c\n");
548 }
549 }
550 continue;
551 }
552
553 frame = Frame_New(i, frameType);
554
555 pastRefFrame = futureRefFrame;
556 futureRefFrame = frame;
557
558 if ( (referenceFrame == DECODED_FRAME) &&
559 ((i < realStart) || (i > realEnd)) ) {
560 WaitForDecodedFrame(i);
561
562 if ( remoteIO ) {
563 GetRemoteDecodedRefFrame(frame, i);
564 } else {
565 ReadDecodedRefFrame(frame, i);
566 }
567 } else {
568 if ( remoteIO ) {
569 GetRemoteFrame(frame, i);
570 } else {
571 GetNthInputFileName(inputFileName, i);
572 if ( childProcess && separateConversion ) {
573 ReadFrame(frame, inputFileName, slaveConversion, TRUE);
574 } else {
575 ReadFrame(frame, inputFileName, inputConversion, TRUE);
576 }
577 }
578 }
579
580 framesRead++;
581
582 time(&tempTimeEnd);
583 IOtime += (tempTimeEnd-tempTimeStart);
584
585 if ( ! firstFrameDone ) {
586 char *userData = (char *)NULL;
587 int userDataSize = 0;
588
589 inputFrameBits = 24*Fsize_x*Fsize_y;
590 SetBlocksPerSlice();
591
592 if ( (whichGOP == -1) && (frameStart == -1) ) {
593 DBG_PRINT(("Generating sequence header\n"));
594 bitstreamMode = getRateMode();
595 if (bitstreamMode == FIXED_RATE) {
596 bit_rate = getBitRate();
597 buf_size = getBufferSize();
598 }
599 else {
600 bit_rate = -1;
601 buf_size = -1;
602 }
603
604 if (strlen(userDataFileName) != 0) {
605 struct stat statbuf;
606 FILE *fp;
607
608 stat(userDataFileName,&statbuf);
609 userDataSize = statbuf.st_size;
610 userData = malloc(userDataSize);
611 if ((fp = fopen(userDataFileName,"rb")) == NULL) {
612 fprintf(stderr,"Could not open userdata file-%s.\n",
613 userDataFileName);
614 userData = NULL;
615 userDataSize = 0;
616 goto write;
617 }
618 if (fread(userData,1,userDataSize,fp) != userDataSize) {
619 fprintf(stderr,"Could not read %d bytes from userdata file-%s.\n",
620 userDataSize,userDataFileName);
621 userData = NULL;
622 userDataSize = 0;
623 goto write;
624 }
625 } else { /* Put in our UserData Header */
626 time_t now;
627
628 time(&now);
629 userData = malloc(100);
630 sprintf(userData,"MPEG stream encoded by UCB Encoder (mpeg_encode) v%s on %s.",
631 VERSION, ctime(&now));
632 userDataSize = strlen(userData);
633 }
634 write:
635 Mhead_GenSequenceHeader(bb, Fsize_x, Fsize_y,
636 /* pratio */ aspectRatio,
637 /* pict_rate */ frameRate, /* bit_rate */ bit_rate,
638 /* buf_size */ buf_size, /*c_param_flag */ 1,
639 /* iq_matrix */ qtable, /* niq_matrix */ niqtable,
640 /* ext_data */ NULL, /* ext_data_size */ 0,
641 /* user_data */ userData, /* user_data_size */ userDataSize);
642 }
643
644 firstFrameDone = TRUE;
645 }
646
647 ProcessRefFrame(frame, bb, lastFrame, outputFileName);
648
649 }
650
651 if ( frame != NULL ) {
652 Frame_Free(frame);
653 }
654
655 /* SEQUENCE END CODE */
656 if ( (whichGOP == -1) && (frameStart == -1) ) {
657 Mhead_GenSequenceEnder(bb);
658 }
659
660 if ( frameStart == -1 ) {
661 /* I think this is right, since (bb == NULL) if (frameStart != -1).
662 See above where "bb" is initialized */
663 numBits = bb->cumulativeBits;
664 } else {
665 /* What should the correct value be? Most likely 1. "numBits" is
666 used below, so we need to make sure it's properly initialized
667 to somthing (anything). */
668 numBits = 1;
669 }
670
671 if ( frameStart == -1 ) {
672 Bitio_Flush(bb);
673 bb = NULL;
674 fclose(ofp);
675
676 time(&timeEnd);
677 diffTime = (int32)(timeEnd-timeStart);
678
679 if ( ! childProcess ) {
680 PrintEndStats(inputFrameBits, numBits);
681 }
682 } else {
683 time(&timeEnd);
684 diffTime = (int32)(timeEnd-timeStart);
685
686 if ( ! childProcess ) {
687 PrintEndStats(inputFrameBits, 1);
688 }
689 }
690
691 if ( FType_Type(realEnd) != 'i' ) {
692 PrintItoIBitRate(numBits, realEnd+1);
693 }
694
695 if ( (! childProcess) && showBitRatePerFrame )
696 CloseBitRateFile();
697
698 #ifdef BLEAH
699 if ( childProcess ) {
700 NoteFrameDone(frameStart, frameEnd);
701 }
702 #endif
703
704 if (! realQuiet) {
705 fprintf(stdout, "======FRAMES READ: %d\n", framesRead);
706 fflush(stdout);
707 }
708
709 return diffTime;
710 }
711
712
713 /*===========================================================================*
714 *
715 * IncrementTCTime
716 *
717 * increment the tc time by one second (and update min, hrs if necessary)
718 * also increments totalFramesSent
719 *
720 * RETURNS: nothing
721 *
722 * SIDE EFFECTS: totalFramesSent, tc_pict, tc_sec, tc_min, tc_hrs, tc_extra
723 *
724 *===========================================================================*/
725 void
726 IncrementTCTime()
727 {
728 /* if fps = an integer, then tc_extra = 0 and is ignored
729
730 otherwise, it is the number of extra 1/1001 frames we've passed by
731
732 so far; for example, if fps = 24000/1001, then 24 frames = 24024/24000
733 seconds = 1 second + 24/24000 seconds = 1 + 1/1000 seconds; similary,
734 if fps = 30000/1001, then 30 frames = 30030/30000 = 1 + 1/1000 seconds
735 and if fps = 60000/1001, then 60 frames = 1 + 1/1000 seconds
736
737 if fps = 24000/1001, then 1/1000 seconds = 24/1001 frames
738 if fps = 30000/1001, then 1/1000 seconds = 30/1001 frames
739 if fps = 60000/1001, then 1/1000 seconds = 60/1001 frames
740 */
741
742 totalFramesSent++;
743 tc_pict++;
744 if ( tc_pict >= frameRateRounded ) {
745 tc_pict = 0;
746 tc_sec++;
747 if ( tc_sec == 60 ) {
748 tc_sec = 0;
749 tc_min++;
750 if ( tc_min == 60 ) {
751 tc_min = 0;
752 tc_hrs++;
753 }
754 }
755 if ( ! frameRateInteger ) {
756 tc_extra += frameRateRounded;
757 if ( tc_extra >= 1001 ) { /* a frame's worth */
758 tc_pict++;
759 tc_extra -= 1001;
760 }
761 }
762 }
763 }
764
765
766 /*===========================================================================*
767 *
768 * SetStatFileName
769 *
770 * set the statistics file name
771 *
772 * RETURNS: nothing
773 *
774 * SIDE EFFECTS: statFileName
775 *
776 *===========================================================================*/
777 void
778 SetStatFileName(fileName)
779 char *fileName;
780 {
781 strcpy(statFileName, fileName);
782 }
783
784
785 /*===========================================================================*
786 *
787 * SetGOPSize
788 *
789 * set the GOP size (frames per GOP)
790 *
791 * RETURNS: nothing
792 *
793 * SIDE EFFECTS: gopSize
794 *
795 *===========================================================================*/
796 void
797 SetGOPSize(size)
798 int size;
799 {
800 gopSize = size;
801 }
802
803
804 /*===========================================================================*
805 *
806 * PrintStartStats
807 *
808 * print out the starting statistics (stuff from the param file)
809 * firstFrame, lastFrame represent the first, last frames to be
810 * encoded
811 *
812 * RETURNS: nothing
813 *
814 * SIDE EFFECTS: none
815 *
816 *===========================================================================*/
817 void
818 PrintStartStats(firstFrame, lastFrame)
819 int firstFrame;
820 int lastFrame;
821 {
822 FILE *fpointer;
823 register int i;
824 char inputFileName[1024];
825
826 if ( statFileName[0] == '\0' ) {
827 statFile = NULL;
828 } else {
829 statFile = fopen(statFileName, "a"); /* open for appending */
830 if ( statFile == NULL ) {
831 fprintf(stderr, "ERROR: Could not open stat file: %s\n", statFileName);
832 fprintf(stderr, " Sending statistics to stdout only.\n");
833 fprintf(stderr, "\n\n");
834 } else if (! realQuiet) {
835 fprintf(stdout, "Appending statistics to file: %s\n", statFileName);
836 fprintf(stdout, "\n\n");
837 }
838 }
839
840 for ( i = 0; i < 2; i++ ) {
841 if ( ( i == 0 ) && (! realQuiet) ) {
842 fpointer = stdout;
843 } else if ( statFile != NULL ) {
844 fpointer = statFile;
845 } else {
846 continue;
847 }
848
849 fprintf(fpointer, "MPEG ENCODER STATS (%s)\n",VERSION);
850 fprintf(fpointer, "------------------------\n");
851 fprintf(fpointer, "TIME STARTED: %s", ctime(&timeStart));
852 if ( getenv("HOST") != NULL ) {
853 fprintf(fpointer, "MACHINE: %s\n", getenv("HOST"));
854 } else {
855 fprintf(fpointer, "MACHINE: unknown\n");
856 }
857
858 if ( stdinUsed ) {
859 fprintf(fpointer, "INPUT: stdin\n");
860 }
861
862
863 if ( firstFrame == -1 ) {
864 fprintf(fpointer, "OUTPUT: %s\n", outputFileName);
865 } else if ( ! stdinUsed ) {
866 GetNthInputFileName(inputFileName, firstFrame);
867 fprintf(fpointer, "FIRST FILE: %s/%s\n", currentPath, inputFileName);
868 GetNthInputFileName(inputFileName, lastFrame);
869 fprintf(fpointer, "LAST FILE: %s/%s\n", currentPath,
870 inputFileName);
871 }
872 if ( resizeFrame )
873 fprintf(fpointer, "RESIZED TO: %dx%d\n",
874 outputWidth, outputHeight);
875 fprintf(fpointer, "PATTERN: %s\n", framePattern);
876 fprintf(fpointer, "GOP_SIZE: %d\n", gopSize);
877 fprintf(fpointer, "SLICES PER FRAME: %d\n", slicesPerFrame);
878 if (searchRangeP==searchRangeB)
879 fprintf(fpointer, "RANGE: +/-%d\n", searchRangeP/2);
880 else fprintf(fpointer, "RANGES: +/-%d %d\n",
881 searchRangeP/2,searchRangeB/2);
882 fprintf(fpointer, "PIXEL SEARCH: %s\n", pixelFullSearch ? "FULL" : "HALF");
883 fprintf(fpointer, "PSEARCH: %s\n", PSearchName());
884 fprintf(fpointer, "BSEARCH: %s\n", BSearchName());
885 fprintf(fpointer, "QSCALE: %d %d %d\n", qscaleI,
886 GetPQScale(), GetBQScale());
887 if (specificsOn)
888 fprintf(fpointer, "(Except as modified by Specifics file)\n");
889 if ( referenceFrame == DECODED_FRAME ) {
890 fprintf(fpointer, "REFERENCE FRAME: DECODED\n");
891 } else if ( referenceFrame == ORIGINAL_FRAME ) {
892 fprintf(fpointer, "REFERENCE FRAME: ORIGINAL\n");
893 } else {
894 fprintf(stderr, "ERROR: Illegal referenceFrame!!!\n");
895 exit(1);
896 }
897 /* For new Rate control parameters */
898 if (getRateMode() == FIXED_RATE) {
899 fprintf(fpointer, "PICTURE RATE: %d\n", frameRateRounded);
900 if (getBitRate() != -1) {
901 fprintf(fpointer, "\nBIT RATE: %d\n", getBitRate());
902 }
903 if (getBufferSize() != -1) {
904 fprintf(fpointer, "BUFFER SIZE: %d\n", getBufferSize());
905 }
906 }
907 }
908 if (! realQuiet) {
909 fprintf(stdout, "\n\n");
910 }
911 }
912
913
914 /*===========================================================================*
915 *
916 * NonLocalRefFrame
917 *
918 * decides if this frame can be referenced from a non-local process
919 *
920 * RETURNS: TRUE or FALSE
921 *
922 * SIDE EFFECTS: none
923 *
924 *===========================================================================*/
925 boolean
926 NonLocalRefFrame(id)
927 int id;
928 {
929 int lastIPid;
930 int nextIPid;
931
932 if ( ! childProcess ) {
933 return FALSE;
934 }
935
936 lastIPid = FType_PastRef(id);
937
938 /* might be accessed by B-frame */
939 if ( lastIPid+1 < realStart ) {
940 return TRUE;
941 }
942
943 /* if B-frame is out of range, then current frame can be ref'd by it */
944 nextIPid = FType_FutureRef(id);
945
946 /* might be accessed by B-frame */
947 if ( nextIPid-1 > realEnd ) {
948 return TRUE;
949 }
950
951 /* might be accessed by P-frame */
952 if ( (nextIPid > realEnd) && (FType_Type(nextIPid) == 'p') ) {
953 return TRUE;
954 }
955
956 return FALSE;
957 }
958
959
960
961 /*===========================================================================*
962 *
963 * SetFrameRate
964 *
965 * sets global frame rate variables. value passed is MPEG frame rate code.
966 *
967 * RETURNS: TRUE or FALSE
968 *
969 * SIDE EFFECTS: frameRateRounded, frameRateInteger
970 *
971 *===========================================================================*/
972 void
973 SetFrameRate()
974 {
975 switch(frameRate) {
976 case 1:
977 frameRateRounded = 24;
978 frameRateInteger = FALSE;
979 break;
980 case 2:
981 frameRateRounded = 24;
982 frameRateInteger = TRUE;
983 break;
984 case 3:
985 frameRateRounded = 25;
986 frameRateInteger = TRUE;
987 break;
988 case 4:
989 frameRateRounded = 30;
990 frameRateInteger = FALSE;
991 break;
992 case 5:
993 frameRateRounded = 30;
994 frameRateInteger = TRUE;
995 break;
996 case 6:
997 frameRateRounded = 50;
998 frameRateInteger = TRUE;
999 break;
1000 case 7:
1001 frameRateRounded = 60;
1002 frameRateInteger = FALSE;
1003 break;
1004 case 8:
1005 frameRateRounded = 60;
1006 frameRateInteger = TRUE;
1007 break;
1008 }
1009 printf("frame rate(%d) set to %d\n", frameRate, frameRateRounded);
1010 }
1011
1012
1013 /*=====================*
1014 * INTERNAL PROCEDURES *
1015 *=====================*/
1016
1017 /*===========================================================================*
1018 *
1019 * ComputeDHMSTime
1020 *
1021 * turn some number of seconds (someTime) into a string which
1022 * summarizes that time according to scale (days, hours, minutes, or
1023 * seconds)
1024 *
1025 * RETURNS: nothing
1026 *
1027 * SIDE EFFECTS: none
1028 *
1029 *===========================================================================*/
1030 static void
1031 ComputeDHMSTime(someTime, timeText)
1032 int32 someTime;
1033 char *timeText;
1034 {
1035 int days, hours, mins, secs;
1036
1037 days = someTime / (24*60*60);
1038 someTime -= days*24*60*60;
1039 hours = someTime / (60*60);
1040 someTime -= hours*60*60;
1041 mins = someTime / 60;
1042 secs = someTime - mins*60;
1043
1044 if ( days > 0 ) {
1045 sprintf(timeText, "Total time: %d days and %d hours", days, hours);
1046 } else if ( hours > 0 ) {
1047 sprintf(timeText, "Total time: %d hours and %d minutes", hours, mins);
1048 } else if ( mins > 0 ) {
1049 sprintf(timeText, "Total time: %d minutes and %d seconds", mins, secs);
1050 } else {
1051 sprintf(timeText, "Total time: %d seconds", secs);
1052 }
1053 }
1054
1055
1056 /*===========================================================================*
1057 *
1058 * ComputeGOPFrames
1059 *
1060 * calculate the first, last frames of the numbered GOP
1061 *
1062 * RETURNS: lastFrame, firstFrame changed
1063 *
1064 * SIDE EFFECTS: none
1065 *
1066 *===========================================================================*/
1067 static void
1068 ComputeGOPFrames(whichGOP, firstFrame, lastFrame, numFrames)
1069 int whichGOP;
1070 int *firstFrame;
1071 int *lastFrame;
1072 int numFrames;
1073 {
1074 int passedB;
1075 int currGOP;
1076 int gopNum, frameNum;
1077
1078 /* calculate first, last frames of whichGOP GOP */
1079
1080 *firstFrame = -1;
1081 *lastFrame = -1;
1082 gopNum = 0;
1083 frameNum = 0;
1084 passedB = 0;
1085 currGOP = 0;
1086 while ( *lastFrame == -1 ) {
1087 if ( frameNum >= numFrames ) {
1088 fprintf(stderr, "ERROR: There aren't that many GOPs!\n");
1089 exit(1);
1090 }
1091
1092 #ifdef BLEAH
1093 if (! realQuiet) {
1094 fprintf(stdout, "GOP STARTS AT %d\n", frameNum-passedB);
1095 }
1096 #endif
1097
1098 if ( gopNum == whichGOP ) {
1099 *firstFrame = frameNum;
1100 }
1101
1102 /* go past one gop */
1103 /* must go past at least one frame */
1104 do {
1105 currGOP += (1 + passedB);
1106
1107 frameNum++;
1108
1109 passedB = 0;
1110 while ( (frameNum < numFrames) && (FType_Type(frameNum) == 'b') ) {
1111 frameNum++;
1112 passedB++;
1113 }
1114 } while ( (frameNum < numFrames) &&
1115 ((FType_Type(frameNum) != 'i') || (currGOP < gopSize)) );
1116
1117 currGOP -= gopSize;
1118
1119 if ( gopNum == whichGOP ) {
1120 *lastFrame = (frameNum-passedB-1);
1121 }
1122
1123 #ifdef BLEAH
1124 if (! realQuiet) {
1125 fprintf(stdout, "GOP ENDS at %d\n", frameNum-passedB-1);
1126 }
1127 #endif
1128
1129 gopNum++;
1130 }
1131 }
1132
1133
1134 /*===========================================================================*
1135 *
1136 * PrintEndStats
1137 *
1138 * print end statistics (summary, time information)
1139 *
1140 * RETURNS: nothing
1141 *
1142 * SIDE EFFECTS: none
1143 *
1144 *===========================================================================*/
1145 static void
1146 PrintEndStats(inputFrameBits, totalBits)
1147 int inputFrameBits;
1148 int32 totalBits;
1149 {
1150 FILE *fpointer;
1151 register int i;
1152 char timeText[256];
1153 float totalCPU;
1154
1155 if (! realQuiet) {
1156 fprintf(stdout, "\n\n");
1157 }
1158
1159 ComputeDHMSTime(diffTime, timeText);
1160
1161 for ( i = 0; i < 2; i++ ) {
1162 if ( ( i == 0 ) && (! realQuiet) ) {
1163 fpointer = stdout;
1164 } else if ( statFile != NULL ) {
1165 fpointer = statFile;
1166 } else {
1167 continue;
1168 }
1169
1170 fprintf(fpointer, "TIME COMPLETED: %s", ctime(&timeEnd));
1171 fprintf(fpointer, "%s\n\n", timeText);
1172
1173 totalCPU = 0.0;
1174 totalCPU += ShowIFrameSummary(inputFrameBits, totalBits, fpointer);
1175 totalCPU += ShowPFrameSummary(inputFrameBits, totalBits, fpointer);
1176 totalCPU += ShowBFrameSummary(inputFrameBits, totalBits, fpointer);
1177 fprintf(fpointer, "---------------------------------------------\n");
1178 fprintf(fpointer, "Total Compression: %3d:1 (%9.4f bpp)\n",
1179 framesOutput*inputFrameBits/totalBits,
1180 24.0*(float)(totalBits)/(float)(framesOutput*inputFrameBits));
1181 if (diffTime > 0) {
1182 fprintf(fpointer, "Total Frames Per Second: %f (%ld mps)\n",
1183 (float)framesOutput/(float)diffTime,
1184 (long)((float)framesOutput*(float)inputFrameBits/(256.0*24.0*(float)diffTime)));
1185 } else {
1186 fprintf(fpointer, "Total Frames Per Second: Infinite!\n");
1187 }
1188 if ( totalCPU == 0.0 ) {
1189 fprintf(fpointer, "CPU Time: NONE!\n");
1190 } else {
1191 fprintf(fpointer, "CPU Time: %f fps (%ld mps)\n",
1192 (float)framesOutput/totalCPU,
1193 (long)((float)framesOutput*(float)inputFrameBits/(256.0*24.0*totalCPU)));
1194 }
1195 fprintf(fpointer, "Total Output Bit Rate (%d fps): %d bits/sec\n",
1196 frameRateRounded, frameRateRounded*totalBits/framesOutput);
1197 fprintf(fpointer, "MPEG file created in : %s\n", outputFileName);
1198 fprintf(fpointer, "\n\n");
1199
1200 if ( computeMVHist ) {
1201 ShowPMVHistogram(fpointer);
1202 ShowBBMVHistogram(fpointer);
1203 ShowBFMVHistogram(fpointer);
1204 }
1205 }
1206
1207 if ( statFile != NULL ) {
1208 fclose(statFile);
1209 }
1210 }
1211
1212
1213 /*===========================================================================*
1214 *
1215 * ProcessRefFrame
1216 *
1217 * process an I or P frame -- encode it, and process any B frames that
1218 * we can now
1219 *
1220 * RETURNS: nothing
1221 *
1222 * SIDE EFFECTS: stuff appended to bb
1223 *
1224 *===========================================================================*/
1225 static void
1226 ProcessRefFrame(frame, bb, lastFrame, outputFileName)
1227 MpegFrame *frame;
1228 BitBucket *bb;
1229 int lastFrame;
1230 char *outputFileName;
1231 {
1232 MpegFrame *bFrame = NULL;
1233 char fileName[1024];
1234 char inputFileName[1024];
1235 FILE *fpointer = NULL;
1236 boolean separateFiles;
1237 int id;
1238 time_t tempTimeStart, tempTimeEnd;
1239
1240 separateFiles = (bb == NULL);
1241
1242 if ( separateFiles && (frame->id >= realStart) &&
1243 (frame->id <= realEnd) ) {
1244 if ( remoteIO ) {
1245 bb = Bitio_New(NULL);
1246 } else {
1247 sprintf(fileName, "%s.frame.%d", outputFileName, frame->id);
1248 if ( (fpointer = fopen(fileName, "wb")) == NULL ) {
1249 fprintf(stderr, "ERROR: Could not open output file(1): %s\n",
1250 fileName);
1251 exit(1);
1252 }
1253
1254 bb = Bitio_New(fpointer);
1255 }
1256 }
1257
1258 /* nothing to do */
1259 if ( frame->id < realStart ) {
1260 return;
1261 }
1262
1263 /* first, output this frame */
1264 if ( frame->type == TYPE_IFRAME ) {
1265
1266 #ifdef BLEAH
1267 fprintf(stdout, "I-frame %d, currentGOP = %d\n",
1268 frame->id, currentGOP);
1269 fflush(stdout);
1270 #endif
1271
1272 /* only start a new GOP with I */
1273 /* don't start GOP if only doing frames */
1274 if ( (! separateFiles) && (currentGOP >= gopSize) ) {
1275 int closed;
1276 static int num_gop = 0;
1277
1278 /* first, check to see if closed GOP */
1279 if ( totalFramesSent == frame->id || pastRefFrame == NULL) {
1280 closed = 1;
1281 } else {
1282 closed = 0;
1283 }
1284
1285 /* new GOP */
1286 if (num_gop != 0 && mult_seq_headers && num_gop % mult_seq_headers == 0) {
1287 if (! realQuiet) {
1288 fprintf(stdout, "Creating new Sequence before GOP %d\n", num_gop);
1289 fflush(stdout);
1290 }
1291
1292 Mhead_GenSequenceHeader(bb, Fsize_x, Fsize_y,
1293 /* pratio */ aspectRatio,
1294 /* pict_rate */ frameRate, /* bit_rate */ bit_rate,
1295 /* buf_size */ buf_size, /* c_param_flag */ 1,
1296 /* iq_matrix */ customQtable, /* niq_matrix */ customNIQtable,
1297 /* ext_data */ NULL, /* ext_data_size */ 0,
1298 /* user_data */ NULL, /* user_data_size */ 0);
1299 }
1300
1301 if (! realQuiet) {
1302 fprintf(stdout, "Creating new GOP (closed = %c) before frame %d\n",
1303 "FT"[closed], frame->id);
1304 fflush(stdout);
1305 }
1306
1307 num_gop++;
1308 Mhead_GenGOPHeader(bb, /* drop_frame_flag */ 0,
1309 tc_hrs, tc_min, tc_sec, tc_pict,
1310 closed, /* broken_link */ 0,
1311 /* ext_data */ NULL, /* ext_data_size */ 0,
1312 /* user_data */ NULL, /* user_data_size */ 0);
1313 currentGOP -= gopSize;
1314 if (pastRefFrame == NULL) {
1315 SetGOPStartTime(0);
1316 } else {
1317 SetGOPStartTime(pastRefFrame->id+1);
1318 }
1319 }
1320
1321 if ( (frame->id >= realStart) && (frame->id <= realEnd) ) {
1322 GenIFrame(bb, frame);
1323
1324 framesOutput++;
1325
1326 if ( separateFiles ) {
1327 if ( remoteIO ) {
1328 SendRemoteFrame(frame->id, bb);
1329 } else {
1330 Bitio_Flush(bb);
1331 fclose(fpointer);
1332 }
1333 }
1334 }
1335
1336 numI--;
1337 timeMask &= 0x6;
1338
1339 currentGOP++;
1340 IncrementTCTime();
1341 } else {
1342 if ( (frame->id >= realStart) && (frame->id <= realEnd) ) {
1343 GenPFrame(bb, frame, pastRefFrame);
1344
1345 framesOutput++;
1346
1347 if ( separateFiles ) {
1348 if ( remoteIO ) {
1349 SendRemoteFrame(frame->id, bb);
1350 } else {
1351 Bitio_Flush(bb);
1352 fclose(fpointer);
1353 }
1354 }
1355 }
1356
1357 numP--;
1358 timeMask &= 0x5;
1359 ShowRemainingTime();
1360
1361 currentGOP++;
1362 IncrementTCTime();
1363 }
1364
1365 /* now, output B-frames */
1366 if ( pastRefFrame != NULL ) {
1367 for ( id = pastRefFrame->id+1; id < futureRefFrame->id; id++ ) {
1368 if ( ! ((id >= realStart) && (id <= realEnd)) )
1369 continue;
1370
1371 if ( ! stdinUsed ) {
1372 bFrame = Frame_New(id, 'b');
1373
1374 time(&tempTimeStart);
1375
1376 /* read B frame, output it */
1377 if ( remoteIO ) {
1378 GetRemoteFrame(bFrame, bFrame->id);
1379 } else {
1380 GetNthInputFileName(inputFileName, id);
1381 if ( childProcess && separateConversion ) {
1382 ReadFrame(bFrame, inputFileName, slaveConversion, TRUE);
1383 } else {
1384 ReadFrame(bFrame, inputFileName, inputConversion, TRUE);
1385 }
1386 }
1387
1388 time(&tempTimeEnd);
1389 IOtime += (tempTimeEnd-tempTimeStart);
1390
1391 framesRead++;
1392 } else {
1393
1394 /* retrieve and remove B-frame from queue set up in
1395 * GenMPEGStream
1396 */
1397 bFrame = pastRefFrame->next;
1398 pastRefFrame->next = bFrame->next;
1399 }
1400
1401
1402 if ( separateFiles ) {
1403 if ( remoteIO ) {
1404 bb = Bitio_New(NULL);
1405 } else {
1406 sprintf(fileName, "%s.frame.%d", outputFileName,
1407 bFrame->id);
1408 if ( (fpointer = fopen(fileName, "wb")) == NULL ) {
1409 fprintf(stderr, "ERROR: Could not open output file(2): %s\n",
1410 fileName);
1411 exit(1);
1412 }
1413 bb = Bitio_New(fpointer);
1414 }
1415 }
1416
1417 GenBFrame(bb, bFrame, pastRefFrame, futureRefFrame);
1418 framesOutput++;
1419
1420 if ( separateFiles ) {
1421 if ( remoteIO ) {
1422 SendRemoteFrame(bFrame->id, bb);
1423 } else {
1424 Bitio_Flush(bb);
1425 fclose(fpointer);
1426 }
1427 }
1428
1429 /* free this B frame right away */
1430 Frame_Free(bFrame);
1431
1432 numB--;
1433 timeMask &= 0x3;
1434 ShowRemainingTime();
1435
1436 currentGOP++;
1437 IncrementTCTime();
1438 }
1439 } else {
1440 /* SRS replicated code */
1441 for ( id = 0; id < futureRefFrame->id; id++ ) {
1442 if ( ! ((id >= realStart) && (id <= realEnd)) )
1443 continue;
1444
1445 if ( ! stdinUsed ) {
1446 bFrame = Frame_New(id, 'b');
1447
1448 time(&tempTimeStart);
1449
1450 /* read B frame, output it */
1451 if ( remoteIO ) {
1452 GetRemoteFrame(bFrame, bFrame->id);
1453 } else {
1454 GetNthInputFileName(inputFileName, id);
1455 if ( childProcess && separateConversion ) {
1456 ReadFrame(bFrame, inputFileName, slaveConversion, TRUE);
1457 } else {
1458 ReadFrame(bFrame, inputFileName, inputConversion, TRUE);
1459 }
1460 }
1461
1462 time(&tempTimeEnd);
1463 IOtime += (tempTimeEnd-tempTimeStart);
1464
1465 framesRead++;
1466 } else {
1467
1468 /* retrieve and remove B-frame from queue set up in
1469 * GenMPEGStream
1470 */
1471 printf("Yow, I doubt this works!\n");
1472 bFrame = pastRefFrame->next;
1473 pastRefFrame->next = bFrame->next;
1474 }
1475
1476
1477 if ( separateFiles ) {
1478 if ( remoteIO ) {
1479 bb = Bitio_New(NULL);
1480 } else {
1481 sprintf(fileName, "%s.frame.%d", outputFileName,
1482 bFrame->id);
1483 if ( (fpointer = fopen(fileName, "wb")) == NULL ) {
1484 fprintf(stderr, "ERROR: Could not open output file(2): %s\n",
1485 fileName);
1486 exit(1);
1487 }
1488 bb = Bitio_New(fpointer);
1489 }
1490 }
1491
1492 GenBFrame(bb, bFrame, (MpegFrame *)NULL, futureRefFrame);
1493 framesOutput++;
1494
1495 if ( separateFiles ) {
1496 if ( remoteIO ) {
1497 SendRemoteFrame(bFrame->id, bb);
1498 } else {
1499 Bitio_Flush(bb);
1500 fclose(fpointer);
1501 }
1502 }
1503
1504 /* free this B frame right away */
1505 Frame_Free(bFrame);
1506
1507 numB--;
1508 timeMask &= 0x3;
1509 ShowRemainingTime();
1510
1511 currentGOP++;
1512 IncrementTCTime();
1513 }
1514
1515 }
1516
1517 /* now free previous frame, if there was one */
1518 if ( pastRefFrame != NULL ) {
1519 Frame_Free(pastRefFrame);
1520 }
1521
1522 /* note, we may still not free last frame if lastFrame is incorrect
1523 * (if the last frames are B frames, they aren't output!)
1524 */
1525 }
1526
1527
1528 /*===========================================================================*
1529 *
1530 * ShowRemainingTime
1531 *
1532 * print out an estimate of the time left to encode
1533 *
1534 * RETURNS: nothing
1535 *
1536 * SIDE EFFECTS: none
1537 *
1538 *===========================================================================*/
1539 static void
1540 ShowRemainingTime()
1541 {
1542 static int lastTime = 0;
1543 float total;
1544 time_t nowTime;
1545 float secondsPerFrame;
1546
1547 if ( childProcess ) {
1548 return /* nothing */;
1549 }
1550
1551 if ( numI + numP + numB == 0 ) { /* no time left */
1552 return /* nothing */ ;
1553 }
1554
1555 if ( timeMask != 0 ) { /* haven't encoded all types yet */
1556 return /* nothing */ ;
1557 }
1558
1559 time(&nowTime);
1560 secondsPerFrame = (nowTime-timeStart)/(float)framesOutput;
1561 total = secondsPerFrame*(float)(numI+numP+numB);
1562
1563 #ifdef BLEAH
1564 float timeI, timeP, timeB;
1565
1566 timeI = EstimateSecondsPerIFrame();
1567 timeP = EstimateSecondsPerPFrame();
1568 timeB = EstimateSecondsPerBFrame();
1569 total = (float)numI*timeI + (float)numP*timeP + (float)numB*timeB;
1570 #endif
1571
1572 if ( (quietTime >= 0) && (! realQuiet) && (! stdinUsed) &&
1573 ((lastTime < (int)total) || ((lastTime-(int)total) >= quietTime) ||
1574 (lastTime == 0) || (quietTime == 0)) ) {
1575 if ( total > 270.0 ) {
1576 fprintf(stdout, "ESTIMATED TIME OF COMPLETION: %d minutes\n",
1577 ((int)total+30)/60);
1578 } else {
1579 fprintf(stdout, "ESTIMATED TIME OF COMPLETION: %d seconds\n",
1580 (int)total);
1581 }
1582
1583 lastTime = (int)total;
1584 }
1585 }
1586
1587
1588 void
1589 ReadDecodedRefFrame(frame, frameNumber)
1590 MpegFrame *frame;
1591 int frameNumber;
1592 {
1593 FILE *fpointer;
1594 char fileName[256];
1595 int width, height;
1596 register int y;
1597
1598 width = Fsize_x;
1599 height = Fsize_y;
1600
1601 sprintf(fileName, "%s.decoded.%d", outputFileName, frameNumber);
1602 if (! realQuiet) {
1603 fprintf(stdout, "reading %s\n", fileName);
1604 fflush(stdout);
1605 }
1606
1607 if ((fpointer = fopen(fileName, "rb")) == NULL) {
1608 sleep(1);
1609 if ((fpointer = fopen(fileName, "rb")) == NULL) {
1610 fprintf(stderr, "Cannot open %s\n", fileName);
1611 exit(1);
1612 }}
1613
1614 Frame_AllocDecoded(frame, TRUE);
1615
1616 for ( y = 0; y < height; y++ ) {
1617 if (fread(frame->decoded_y[y], 1, width, fpointer) != width) {
1618 fprintf(stderr, "Could not read enough bytes from %s\n", fileName);
1619 }
1620 }
1621
1622 for (y = 0; y < (height >> 1); y++) { /* U */
1623 if (fread(frame->decoded_cb[y], 1, width >> 1, fpointer) != (width>>1)) {
1624 fprintf(stderr, "Could not read enough bytes from %s\n", fileName);
1625 }
1626 }
1627
1628 for (y = 0; y < (height >> 1); y++) { /* V */
1629 if (fread(frame->decoded_cr[y], 1, width >> 1, fpointer) != (width>>1)) {
1630 fprintf(stderr, "Could not read enough bytes from %s\n", fileName);
1631 }
1632 }
1633
1634 fclose(fpointer);
1635 }
1636
1637
1638 static void
1639 OpenBitRateFile()
1640 {
1641 bitRateFile = fopen(bitRateFileName, "w");
1642 if ( bitRateFile == NULL ) {
1643 fprintf(stderr, "ERROR: Could not open bit rate file: %s\n", bitRateFileName);
1644 fprintf(stderr, "\n\n");
1645 showBitRatePerFrame = FALSE;
1646 }
1647 }
1648
1649
1650 static void
1651 CloseBitRateFile()
1652 {
1653 #ifdef BLEAH
1654 char command[256];
1655 #endif
1656
1657 fclose(bitRateFile);
1658 #ifdef BLEAH
1659 sprintf(command, "sort -n %s > /tmp/fubahr", bitRateFileName);
1660 system(command);
1661 sprintf(command, "mv /tmp/fubahr %s", bitRateFileName);
1662 system(command);
1663 #endif
1664 }