1 /*===========================================================================*
2  * readframe.c								     *
3  *									     *
4  *	procedures to read in frames					     *
5  *									     *
6  * EXPORTED PROCEDURES:							     *
7  *	ReadFrame							     *
8  *	SetFileType							     *
9  *	SetFileFormat							     *
10  *									     *
11  *===========================================================================*/
12 
13 /*
14  * Copyright (c) 1995 The Regents of the University of California.
15  * All rights reserved.
16  *
17  * Permission to use, copy, modify, and distribute this software and its
18  * documentation for any purpose, without fee, and without written agreement is
19  * hereby granted, provided that the above copyright notice and the following
20  * two paragraphs appear in all copies of this software.
21  *
22  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
23  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
24  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
25  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
28  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
29  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
30  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
31  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
32  */
33 
34 /*
35  *  $Header: /n/picasso/project/mpeg/mpeg_dist/mpeg_encode/RCS/readframe.c,v 1.27 1995/08/14 22:31:40 smoot Exp $
36  *  $Log: readframe.c,v $
37  *  Revision 1.27  1995/08/14 22:31:40  smoot
38  *  reads training info from PPms now (needed for piping reads)
39  *
40  *  Revision 1.26  1995/08/07 21:48:36  smoot
41  *  better error reporting, JPG == JPEG now
42  *
43  *  Revision 1.25  1995/06/12 20:30:12  smoot
44  *  added popen for OS2
45  *
46  * Revision 1.24  1995/06/08  20:34:36  smoot
47  * added "b"'s to fopen calls to make MSDOS happy
48  *
49  * Revision 1.23  1995/05/03  10:16:01  smoot
50  * minor compile bug with static f
51  *
52  * Revision 1.22  1995/05/02  22:00:12  smoot
53  * added TUNEing, setting near-black values to black
54  *
55  * Revision 1.21  1995/03/27  21:00:01  eyhung
56  * fixed bug with some long jpeg names
57  *
58  * Revision 1.20  1995/02/02  01:05:54  eyhung
59  * Fixed aAdded error checking for stdin
60  *
61  * Revision 1.19  1995/02/01  05:01:12  eyhung
62  * Removed troubleshooting printf
63  *
64  * Revision 1.18  1995/01/31  21:08:16  eyhung
65  * Improved YUV_FORMAT strings with better algorithm
66  *
67  * Revision 1.17  1995/01/27  23:34:09  eyhung
68  * Removed temporary JPEG files created by JMOVIE input
69  *
70  * Revision 1.16  1995/01/27  21:57:43  eyhung
71  * Added case for reading original JMOVIES
72  *
73  * Revision 1.14  1995/01/24  23:47:51  eyhung
74  * Confusion with Abekas format fixed : all other YUV revisions are wrong
75  *
76  * Revision 1.13  1995/01/20  00:02:30  smoot
77  * added gamma correction
78  *
79  * Revision 1.12  1995/01/19  23:09:21  eyhung
80  * Changed copyrights
81  *
82  * Revision 1.11  1995/01/17  22:23:07  aswan
83  * AbekasYUV chrominance implementation fixed
84  *
85  * Revision 1.10  1995/01/17  21:26:25  smoot
86  * Tore our average on Abekus/Phillips reconstruct
87  *
88  * Revision 1.9  1995/01/17  08:22:34  eyhung
89  * Debugging of ReadAYUV
90  *
91  * Revision 1.8  1995/01/16  13:18:24  eyhung
92  * Interlaced YUV format (e.g. Abekas) support added (slightly buggy)
93  *
94  * Revision 1.7  1995/01/16  06:58:23  eyhung
95  * Added skeleton of ReadAYUV (for Abekas YUV files)
96  *
97  * Revision 1.6  1995/01/13  23:22:23  smoot
98  * Added ReadY, so we can make black&white movies (how artsy!)
99  *
100  * Revision 1.5  1994/12/16  00:20:40  smoot
101  * Now errors out on too small an input file
102  *
103  * Revision 1.4  1994/11/12  02:11:59  keving
104  * nothing
105  *
106  * Revision 1.3  1994/03/15  00:27:11  keving
107  * nothing
108  *
109  * Revision 1.2  1993/12/22  19:19:01  keving
110  * nothing
111  *
112  * Revision 1.1  1993/07/22  22:23:43  keving
113  * nothing
114  *
115  */
116 
117 
118 /*==============*
119  * HEADER FILES *
120  *==============*/
121 
122 #include "all.h"
123 #include <time.h>
124 #include <errno.h>
125 #include <ctype.h>
126 #include <string.h>
127 //#include <unistd.h>
128 #include "mtypes.h"
129 #include "frames.h"
130 #include "prototypes.h"
131 #include "parallel.h"
132 #include "param.h"
133 #include "readframe.h"
134 #include "fsize.h"
135 #include "rgbtoycc.h"
136 #include "jpeg.h"
137 #include "opts.h"
138 
139 #define PPM_READ_STATE_MAGIC	0
140 #define PPM_READ_STATE_WIDTH	1
141 #define PPM_READ_STATE_HEIGHT	2
142 #define PPM_READ_STATE_MAXVAL	3
143 #define PPM_READ_STATE_DONE	4
144 
145 
146 /*==================*
147  * STATIC VARIABLES *
148  *==================*/
149 
150 static int  fileType = BASE_FILE_TYPE;
151 struct YuvLine {
152 	uint8	data[3072];
153 	uint8	y[1024];
154 	int8	cr[1024];
155 	int8	cb[1024];
156 };
157 
158 
159 /*==================*
160  * Portability      *
161  *==================*/
162 #ifdef __OS2__
163   #define popen _popen
164 #endif
165 
166 #if defined(WIN32) && !defined(__CYGWIN__)
167   #define popen _popen
168   #define pclose _pclose
169 #endif
170 
171 /*==================*
172  * Global VARIABLES *
173  *==================*/
174 
175 extern boolean GammaCorrection;
176 extern float GammaValue;
177 extern int outputWidth,outputHeight;
178 boolean resizeFrame;
179 char *CurrFile;
180 
181 /*===============================*
182  * INTERNAL PROCEDURE prototypes *
183  *===============================*/
184 
185 static char *ScanNextString _ANSI_ARGS_((char *inputLine, char *string));
186 static void ReadPNM _ANSI_ARGS_((FILE * fp, MpegFrame * mf));
187 static boolean	ReadPPM _ANSI_ARGS_((MpegFrame *mf, FILE *fpointer));
188 static void ReadEYUV _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer,
189 				 int width, int height));
190 static void ReadAYUV _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer,
191 				 int width, int height));
192 static void SeparateLine _ANSI_ARGS_((FILE *fpointer, struct YuvLine *lineptr,
193 				     int width));
194 static void ReadY _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer,
195 				 int width, int height));
196 static void ReadSub4 _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer,
197 				  int width, int height));
198 static void DoGamma  _ANSI_ARGS_((MpegFrame *mf, int width, int height));
199 
200 static void DoKillDim _ANSI_ARGS_((MpegFrame *mf, int w, int h));
201 
202 #define safe_fread(ptr,sz,len,fileptr)                           \
203     if ((safe_read_count=fread(ptr,sz,len,fileptr))!=sz*len) {   \
204       throw "Input file too small! (%s)";   \
205       }                                                  \
206 
207 /*=====================*
208  * EXPORTED PROCEDURES *
209  *=====================*/
210 
211 
212 
SetResize(boolean set)213 void	SetResize( boolean	set)
214 {
215     resizeFrame = set;
216 }
217 
218 
219 
220 /*===========================================================================*
221  *
222  * ReadFrame
223  *
224  *	reads the given frame, performing conversion as necessary
225  *	if addPath = TRUE, then must add the current path before the
226  *	file name
227  *
228  * RETURNS:	frame modified
229  *
230  * SIDE EFFECTS:    none
231  *
232  *===========================================================================*/
233 void
ReadFrame(MpegFrame * frame,char * fileName,char * conversion,boolean addPath)234 ReadFrame(MpegFrame *frame,
235           char *fileName,
236           char *conversion,
237           boolean addPath)
238 {
239     FILE    *ifp;
240     char    command[1024];
241     char    fullFileName[1024];
242     MpegFrame    tempFrame;
243     MpegFrame    *framePtr;
244 #ifdef BLEAH
245     static int32    readDiskTime = 0;
246     int32    diskStartTime, diskEndTime;
247 
248 time(&diskStartTime);
249 #endif
250 
251     if ( resizeFrame ) {
252       tempFrame.inUse = FALSE;
253       tempFrame.ppm_data = NULL;
254       tempFrame.rgb_data = NULL;
255       tempFrame.orig_y = NULL;
256       tempFrame.y_blocks = NULL;
257       tempFrame.decoded_y = NULL;
258       tempFrame.halfX = NULL;
259       framePtr = &tempFrame;
260     } else {
261       framePtr = frame;
262     }
263 
264     if ( addPath ) {
265       sprintf(fullFileName, "%s/%s", currentPath, fileName);
266     } else {
267       sprintf(fullFileName, "%s", fileName);
268     }
269 
270     CurrFile = fullFileName;
271 
272 #ifdef BLEAH
273     if ( ! childProcess ) {
274     fprintf(stdout, "+++++READING Frame %d  (type %d):  %s\n", framePtr->id,
275             framePtr->type, fullFileName);
276     }
277 #endif
278 
279     if ( fileType == ANY_FILE_TYPE ) {
280     char *convertPtr, *commandPtr, *charPtr;
281 
282       if ( stdinUsed ) {
283         throw "cannot use stdin with INPUT_CONVERT";
284       }
285 
286       /* replace every occurrence of '*' with fullFileName */
287       convertPtr = conversion;
288       commandPtr = command;
289       while ( *convertPtr != '\0' ) {
290         while ( (*convertPtr != '\0') && (*convertPtr != '*') ) {
291           *commandPtr = *convertPtr;
292           commandPtr++;
293           convertPtr++;
294         }
295 
296         if ( *convertPtr == '*' ) {
297           /* copy fullFileName */
298           charPtr = fullFileName;
299           while ( *charPtr != '\0' ) {
300             *commandPtr = *charPtr;
301             commandPtr++;
302             charPtr++;
303           }
304 
305           convertPtr++;   /* go past '*' */
306         }
307       }
308       *commandPtr = '\0';
309 
310       if ( (ifp = popen(command, "r")) == NULL ) {
311         fprintf(stderr, "ERROR:  Couldn't execute input conversion command:\n");
312         fprintf(stderr, "\t%s\n", command);
313         fprintf(stderr, "errno = %d\n", errno);
314         if ( ioServer ) {
315           throw "IO SERVER:  EXITING!";
316         } else {
317           throw "SLAVE EXITING!";
318         }
319       }
320     } else if (stdinUsed) {
321       ifp = stdin;
322     } else if ( (ifp = fopen(fullFileName, "rb")) == NULL ) {
323       throw "Couldn't open input file";
324     }
325 
326     switch(baseFormat) {
327     case YUV_FILE_TYPE:
328 
329         /* Encoder YUV */
330         if ((strncmp (yuvConversion, "EYUV", 4) == 0) ||
331             (strncmp (yuvConversion, "UCB", 3) == 0) )
332         {
333             ReadEYUV(framePtr, ifp, realWidth, realHeight);
334         }
335 
336         /* Abekas-type (interlaced) YUV */
337         else {
338             ReadAYUV(framePtr, ifp, realWidth, realHeight);
339         }
340 
341         break;
342     case Y_FILE_TYPE:
343         ReadY(framePtr, ifp, realWidth, realHeight);
344         break;
345     case PPM_FILE_TYPE:
346         if ( ! ReadPPM(framePtr, ifp) ) {
347         throw "Error reading PPM input file!";
348         }
349         PPMtoYUV(framePtr);
350         break;
351     case PNM_FILE_TYPE:
352         ReadPNM(ifp, framePtr);
353         PNMtoYUV(framePtr);
354         break;
355     case SUB4_FILE_TYPE:
356         ReadSub4(framePtr, ifp, yuvWidth, yuvHeight);
357         break;
358     case JPEG_FILE_TYPE:
359     case JMOVIE_FILE_TYPE:
360         ReadJPEG(framePtr, ifp);
361         break;
362     default:
363         break;
364     }
365 
366     if (! stdinUsed) {
367       if ( fileType == ANY_FILE_TYPE ) {
368 	int errorcode;
369 	if ( (errorcode = pclose(ifp)) != 0) {
370 	  fprintf(stderr, "WARNING:  Pclose reported error (%d)\n", errorcode);
371 	}
372       } else {
373         fclose(ifp);
374       }
375     }
376 
377     if ( baseFormat == JMOVIE_FILE_TYPE ) {
378       remove(fullFileName);
379     }
380 
381     if ( resizeFrame ) {
382       Frame_Resize(frame, &tempFrame, Fsize_x, Fsize_y, outputWidth, outputHeight);
383     }
384 
385 #ifdef BLEAH
386 time(&diskEndTime);
387 
388 readDiskTime += (diskEndTime-diskStartTime);
389 
390 fprintf(stdout, "cumulative disk read time:  %d seconds\n", readDiskTime);
391 #endif
392 
393     if ( GammaCorrection ) {
394       DoGamma(frame, Fsize_x, Fsize_y);
395     }
396 
397     if ( kill_dim ) {
398       DoKillDim(frame, Fsize_x, Fsize_y);
399     }
400 
401     MotionSearchPreComputation(frame);
402 }
403 
404 
405 /*===========================================================================*
406  *
407  * SetFileType
408  *
409  *	set the file type to be either a base type (no conversion), or
410  *	any type (conversion required)
411  *
412  * RETURNS:	nothing
413  *
414  * SIDE EFFECTS:    fileType
415  *
416  *===========================================================================*/
417 void
SetFileType(char * conversion)418 SetFileType(char *conversion)
419 {
420     if ( strcmp(conversion, "*") == 0 ) {
421 	fileType = BASE_FILE_TYPE;
422     } else {
423 	fileType = ANY_FILE_TYPE;
424     }
425 }
426 
427 
428 /*===========================================================================*
429  *
430  * SetFileFormat
431  *
432  *	set the file format (PPM, PNM, YUV, JPEG)
433  *
434  * RETURNS:	nothing
435  *
436  * SIDE EFFECTS:    baseFormat
437  *
438  *===========================================================================*/
439 void
SetFileFormat(char * format)440 SetFileFormat(char *format)
441 {
442     if ( strcmp(format, "PPM") == 0 ) {
443 	baseFormat = PPM_FILE_TYPE;
444     } else if ( strcmp(format, "YUV") == 0 ) {
445 	baseFormat = YUV_FILE_TYPE;
446     } else if ( strcmp(format, "Y") == 0 ) {
447 	baseFormat = Y_FILE_TYPE;
448     } else if ( strcmp(format, "PNM") == 0 ) {
449 	baseFormat = PNM_FILE_TYPE;
450     } else if (( strcmp(format, "JPEG") == 0 ) || ( strcmp(format, "JPG") == 0 )) {
451 	baseFormat = JPEG_FILE_TYPE;
452     } else if ( strcmp(format, "JMOVIE") == 0 ) {
453 	baseFormat = JMOVIE_FILE_TYPE;
454     } else if ( strcmp(format, "SUB4") == 0 ) {
455 	baseFormat = SUB4_FILE_TYPE;
456     } else {
457 	throw "Invalid file format";
458     }
459 }
460 
461 
462 /*===========================================================================*
463  *
464  * ReadPNM
465  *
466  *	read a PNM file
467  *
468  * RETURNS:	mf modified
469  *
470  * SIDE EFFECTS:    none
471  *
472  *===========================================================================*/
473 static void
ReadPNM(FILE * fp,MpegFrame * mf)474 ReadPNM(FILE *fp,
475         MpegFrame *mf)
476 {
477     int x, y;
478     xelval maxval;
479     int format;
480 
481     if (mf->rgb_data) {
482 	pnm_freearray(mf->rgb_data, Fsize_y);
483     }
484     mf->rgb_data = pnm_readpnm(fp, &x, &y, &maxval, &format);
485     ERRCHK(mf, "pnm_readpnm");
486 
487     if (format != PPM_FORMAT) {
488 	if (maxval < 255) {
489 	    pnm_promoteformat(mf->rgb_data, x, y, maxval, format, 255, PPM_FORMAT);
490 	    maxval = 255;
491 	} else {
492 	    pnm_promoteformat(mf->rgb_data, x, y, maxval, format, maxval, PPM_FORMAT);
493 	}
494     }
495     if (maxval < 255) {
496 	pnm_promoteformat(mf->rgb_data, x, y, maxval, format, 255, format);
497 	maxval = 255;
498     }
499     /*
500      * if this is the first frame read, set the global frame size
501      */
502     Fsize_Note(mf->id, x, y);
503 
504     mf->rgb_maxval = maxval;
505     mf->rgb_format = PPM_FORMAT;
506 }
507 
508 
509 
510 /*===========================================================================*
511  *
512  * ReadIOConvert
513  *
514  *	do conversion; return a pointer to the appropriate file
515  *
516  * RETURNS:	pointer to the appropriate file
517  *
518  * SIDE EFFECTS:    none
519  *
520  *===========================================================================*/
521 FILE *
ReadIOConvert(char * fileName)522 ReadIOConvert(char *fileName)
523 {
524     FILE	*ifp;
525     char	command[1024];
526     char	fullFileName[1024];
527     char *convertPtr, *commandPtr, *charPtr;
528 
529     sprintf(fullFileName, "%s/%s", currentPath, fileName);
530 
531 #ifdef BLEAH
532     if ( ! childProcess ) {
533 	fprintf(stdout, "+++++READING (IO CONVERT) Frame %d  (type %d):  %s\n", frame->id,
534 		frame->type, fullFileName); }
535 #endif
536 
537     if ( strcmp(ioConversion, "*") == 0 ) {
538       char buff[1024];
539       ifp = fopen(fullFileName, "rb");
540       sprintf(buff,"fopen \"%s\"",fullFileName);
541       ERRCHK(ifp, buff);
542       return ifp;
543     }
544 
545     /* replace every occurrence of '*' with fullFileName */
546     convertPtr = ioConversion;
547     commandPtr = command;
548     while ( *convertPtr != '\0' ) {
549 	while ( (*convertPtr != '\0') && (*convertPtr != '*') ) {
550 	    *commandPtr = *convertPtr;
551 	    commandPtr++;
552 	    convertPtr++;
553 	}
554 
555 	if ( *convertPtr == '*' ) {
556 	    /* copy fullFileName */
557 	    charPtr = fullFileName;
558 	    while ( *charPtr != '\0' ) {
559 		*commandPtr = *charPtr;
560 		commandPtr++;
561 		charPtr++;
562 	    }
563 
564 	    convertPtr++;   /* go past '*' */
565 	}
566     }
567     *commandPtr = '\0';
568 
569     if ( (ifp = popen(command, "r")) == NULL ) {
570 	fprintf(stderr, "ERROR:  Couldn't execute input conversion command:\n");
571 	fprintf(stderr, "\t%s\n", command);
572 	fprintf(stderr, "errno = %d\n", errno);
573 	if ( ioServer ) {
574 	    throw "IO SERVER:  EXITING!";
575 	} else {
576           throw "SLAVE EXITING!";
577 	}
578     }
579 
580     return ifp;
581 }
582 
583 
584 
585 /*===========================================================================*
586  *
587  * ReadPPM
588  *
589  *	read a PPM file
590  *
591  * RETURNS:	TRUE if successful; FALSE otherwise; mf modified
592  *
593  * SIDE EFFECTS:    none
594  *
595  *===========================================================================*/
596 static boolean
ReadPPM(MpegFrame * mf,FILE * fpointer)597 ReadPPM(MpegFrame *mf,
598         FILE *fpointer)
599 {
600     char    inputBuffer[71];
601     char    string[71];
602     char    *inputLine;
603     int	    height = 0, width = 0, maxVal=255;
604     uint8   junk[4096];
605     register int y;
606     int	    state;
607     int     safe_read_count;
608 
609     state = PPM_READ_STATE_MAGIC;
610 
611     while ( state != PPM_READ_STATE_DONE ) {
612 	if ( fgets(inputBuffer, 71, fpointer) == NULL ) {
613 	    return FALSE;
614 	}
615 
616         inputLine = inputBuffer;
617 
618 	if ( inputLine[0] == '#' ) {
619 	    continue;
620 	}
621 
622 	if ( inputLine[strlen(inputLine)-1] != '\n' ) {
623 	    return FALSE;
624 	}
625 
626 	switch(state) {
627 	    case PPM_READ_STATE_MAGIC:
628 	        if ( (inputLine = ScanNextString(inputLine, string)) == NULL ) {
629 		    return FALSE;
630 		}
631 
632 		if ( strcmp(string, "P6") != 0 ) {
633 		    return FALSE;
634 		}
635 		state = PPM_READ_STATE_WIDTH;
636 		/* no break */
637 	    case PPM_READ_STATE_WIDTH:
638 	        if ( (inputLine = ScanNextString(inputLine, string)) == NULL ) {
639 		    if ( inputLine == inputBuffer ) {
640 		        return FALSE;
641 		    } else {
642 		        break;
643 		    }
644 		}
645 
646 		width = atoi(string);
647 
648 		state = PPM_READ_STATE_HEIGHT;
649 
650 		/* no break */
651 	    case PPM_READ_STATE_HEIGHT:
652 	        if ( (inputLine = ScanNextString(inputLine, string)) == NULL ) {
653 		    if ( inputLine == inputBuffer ) {
654 		        return FALSE;
655 		    } else {
656 		        break;
657 		    }
658 		}
659 
660 		height = atoi(string);
661 
662 		state = PPM_READ_STATE_MAXVAL;
663 
664 		/* no break */
665 	    case PPM_READ_STATE_MAXVAL:
666 	        if ( (inputLine = ScanNextString(inputLine, string)) == NULL ) {
667 		    if ( inputLine == inputBuffer ) {
668 		        return FALSE;
669 		    } else {
670 		        break;
671 		    }
672 		}
673 
674 		maxVal = atoi(string);
675 
676 		state = PPM_READ_STATE_DONE;
677 		break;
678 	} /* end of switch */
679     }
680 
681     Fsize_Note(mf->id, width, height);
682 
683     mf->rgb_maxval = maxVal;
684 
685     Frame_AllocPPM(mf);
686 
687     for ( y = 0; y < Fsize_y; y++ ) {
688       safe_fread(mf->ppm_data[y], (int)sizeof(char), 3*Fsize_x, fpointer);
689 
690 	/* read the leftover stuff on the right side */
691       safe_fread(junk, (int)sizeof(char), 3*(width-Fsize_x), fpointer);
692     }
693 
694     /* read the leftover stuff to prevent broken pipe */
695     for ( y=Fsize_y; y<height; ++y ) {
696       safe_fread(junk, (int)sizeof(char), 3*Fsize_x, fpointer);
697     }
698     return TRUE;
699 }
700 
701 
702 /*===========================================================================*
703  *
704  * ReadEYUV
705  *
706  *	read a Encoder-YUV file (concatenated Y, U, and V)
707  *
708  * RETURNS:	mf modified
709  *
710  * SIDE EFFECTS:    none
711  *
712  *===========================================================================*/
713 static void
ReadEYUV(MpegFrame * mf,FILE * fpointer,int width,int height)714 ReadEYUV(MpegFrame *mf,
715          FILE *fpointer,
716          int width,
717          int height)
718 {
719     register int y;
720     uint8   junk[4096];
721     int     safe_read_count;
722 
723     Fsize_Note(mf->id, width, height);
724 
725     Frame_AllocYCC(mf);
726 
727     for (y = 0; y < Fsize_y; y++) {			/* Y */
728 	safe_fread(mf->orig_y[y], 1, Fsize_x, fpointer);
729 
730 	/* read the leftover stuff on the right side */
731 	if ( width != Fsize_x ) {
732 	    safe_fread(junk, 1, width-Fsize_x, fpointer);
733 	}
734     }
735 
736     /* read the leftover stuff on the bottom */
737     for (y = Fsize_y; y < height; y++) {
738 	safe_fread(junk, 1, width, fpointer);
739     }
740 
741     for (y = 0; y < (Fsize_y >> 1); y++) {			/* U */
742 	safe_fread(mf->orig_cb[y], 1, Fsize_x >> 1, fpointer);
743 
744 	/* read the leftover stuff on the right side */
745 	if ( width != Fsize_x ) {
746 	    safe_fread(junk, 1, (width-Fsize_x)>>1, fpointer);
747 	}
748     }
749 
750     /* read the leftover stuff on the bottom */
751     for (y = (Fsize_y >> 1); y < (height >> 1); y++) {
752 	safe_fread(junk, 1, width>>1, fpointer);
753     }
754 
755     for (y = 0; y < (Fsize_y >> 1); y++) {			/* V */
756 	safe_fread(mf->orig_cr[y], 1, Fsize_x >> 1, fpointer);
757 
758 	/* read the leftover stuff on the right side */
759 	if ( width != Fsize_x ) {
760 	    safe_fread(junk, 1, (width-Fsize_x)>>1, fpointer);
761 	}
762     }
763 
764     /* ignore leftover stuff on the bottom */
765 }
766 
767 /*===========================================================================*
768  *
769  * ReadAYUV
770  *
771  *	read an Abekas-YUV file
772  *
773  * RETURNS:	mf modified
774  *
775  * SIDE EFFECTS:    none
776  *
777  *===========================================================================*/
778 static void
ReadAYUV(MpegFrame * mf,FILE * fpointer,int width,int height)779 ReadAYUV(MpegFrame *mf,
780          FILE *fpointer,
781          int width,
782          int height)
783 {
784     register int x, y;
785     struct  YuvLine line1, line2;
786     uint8   junk[4096];
787     int8    *cbptr, *crptr;
788     int     safe_read_count;
789 
790     Fsize_Note(mf->id, width, height);
791 
792     Frame_AllocYCC(mf);
793 
794     for (y = 0; y < Fsize_y; y += 2) {
795 	SeparateLine(fpointer, &line1, width);
796 	SeparateLine(fpointer, &line2, width);
797 
798 	/* Copy the Y values for each line to the frame */
799 	for (x = 0; x < Fsize_x; x++) {
800 	    mf->orig_y[y][x]   = line1.y[x];
801 	    mf->orig_y[y+1][x] = line2.y[x];
802 	}
803 
804 	cbptr = (int8*)&(mf->orig_cb[y>>1][0]);
805 	crptr = (int8*)&(mf->orig_cr[y>>1][0]);
806 
807 	/* One U and one V for each two pixels horizontal as well */
808 	/* Toss the second line of Cr/Cb info, averaging was worse,
809 	   so just subsample */
810 	for (x = 0; x < (Fsize_x >> 1); x ++) {
811 	    cbptr[x] =  line1.cb[x];
812 	    crptr[x] =  line1.cr[x];
813 
814 	}
815     }
816 
817     /* read the leftover stuff on the bottom */
818     for (y = Fsize_y; y < height; y++) {
819 	safe_fread(junk, 1, width<<1, fpointer);
820     }
821 
822 }
823 
824 /*===========================================================================*
825  *
826  * SeparateLine
827  *
828  *	Separates one line of pixels into Y, U, and V components
829  *
830  * RETURNS:	lineptr modified
831  *
832  * SIDE EFFECTS:    none
833  *
834  *===========================================================================*/
835 static void
SeparateLine(FILE * fpointer,struct YuvLine * lineptr,int width)836 SeparateLine(FILE *fpointer,
837              struct YuvLine *lineptr,
838              int width)
839 {
840     uint8   junk[4096];
841     int8    *crptr, *cbptr;
842     uint8   *yptr;
843     int     num, length;
844     int     safe_read_count;
845 
846 
847     /* Sets the deinterlacing pattern */
848 
849 	/* shorthand for UYVY */
850     if (strncmp(yuvConversion, "ABEKAS", 6) == 0) {
851 	strcpy(yuvConversion, "UYVY");
852 
853 	/* shorthand for YUYV */
854     } else if (strncmp(yuvConversion, "PHILLIPS", 8) == 0) {
855 	strcpy(yuvConversion, "YUYV");
856     }
857 
858     length = strlen (yuvConversion);
859 
860     if ((length % 2) != 0) {
861 	throw "YUV_FORMAT must represent two pixels, hence must be even in length";
862     }
863 
864     /* each line in 4:2:2 chroma format takes 2X bytes to represent X pixels.
865      * each line in 4:4:4 chroma format takes 3X bytes to represent X pixels.
866      * Therefore, half of the length of the YUV_FORMAT represents 1 pixel.
867      */
868     safe_fread(lineptr->data, 1, Fsize_x*(length>>1), fpointer);
869 
870     /* read the leftover stuff on the right side */
871     if ( width != Fsize_x ) {
872 	safe_fread(junk, 1, (width-Fsize_x)*(length>>1), fpointer);
873     }
874 
875     crptr = &(lineptr->cr[0]);
876     cbptr = &(lineptr->cb[0]);
877     yptr = &(lineptr->y[0]);
878 
879     for (num = 0; num < (Fsize_x*(length>>1)); num++) {
880 	switch (yuvConversion[num % length]) {
881 	case 'U':
882 	case 'u':
883 	    *(cbptr++) = (lineptr->data[num]);
884 	    break;
885 	case 'V':
886 	case 'v':
887 	    *(crptr++) = (lineptr->data[num]);
888 	    break;
889 	case 'Y':
890 	case 'y':
891 	    *(yptr++) = (lineptr->data[num]);
892 	    break;
893 	default:
894           throw "bad YUV_FORMAT";
895         }
896 
897     }
898 
899 }
900 
901 
902 /*===========================================================================*
903  *
904  * ReadY
905  *
906  *	read a Y file
907  *
908  * RETURNS:	mf modified
909  *
910  * SIDE EFFECTS:    none
911  *
912  *===========================================================================*/
913 static void
ReadY(MpegFrame * mf,FILE * fpointer,int width,int height)914 ReadY(MpegFrame *mf,
915       FILE *fpointer,
916       int width,
917       int height)
918 {
919     register int y;
920     uint8   junk[4096];
921     int     safe_read_count;
922 
923     Fsize_Note(mf->id, width, height);
924 
925     Frame_AllocYCC(mf);
926 
927     for (y = 0; y < Fsize_y; y++) {			/* Y */
928 	safe_fread(mf->orig_y[y], 1, Fsize_x, fpointer);
929 
930 	/* read the leftover stuff on the right side */
931 	if ( width != Fsize_x ) {
932 	    safe_fread(junk, 1, width-Fsize_x, fpointer);
933 	}
934     }
935 
936     /* read the leftover stuff on the bottom */
937     for (y = Fsize_y; y < height; y++) {
938 	safe_fread(junk, 1, width, fpointer);
939     }
940 
941     for (y = 0 ; y < (Fsize_y >> 1); y++) {
942       memset(mf->orig_cb[y], 128, (Fsize_x>>1));
943       memset(mf->orig_cr[y], 128, (Fsize_x>>1));
944     }
945 }
946 
947 
948 /*===========================================================================*
949  *
950  * ReadSub4
951  *
952  *	read a YUV file (subsampled even further by 4:1 ratio)
953  *
954  * RETURNS:	mf modified
955  *
956  * SIDE EFFECTS:    none
957  *
958  *===========================================================================*/
959 static void
ReadSub4(MpegFrame * mf,FILE * fpointer,int width,int height)960 ReadSub4(MpegFrame *mf,
961          FILE *fpointer,
962          int width,
963          int height)
964 {
965     register int y;
966     register int x;
967     uint8   buffer[1024];
968     int     safe_read_count;
969 
970     Fsize_Note(mf->id, width, height);
971 
972     Frame_AllocYCC(mf);
973 
974     for (y = 0; y < (height>>1); y++) {			/* Y */
975 	safe_fread(buffer, 1, width>>1, fpointer);
976 	for ( x = 0; x < (width>>1); x++ ) {
977 	    mf->orig_y[2*y][2*x] = buffer[x];
978 	    mf->orig_y[2*y][2*x+1] = buffer[x];
979 	    mf->orig_y[2*y+1][2*x] = buffer[x];
980 	    mf->orig_y[2*y+1][2*x+1] = buffer[x];
981 	}
982     }
983 
984     for (y = 0; y < (height >> 2); y++) {			/* U */
985 	safe_fread(buffer, 1, width>>2, fpointer);
986 	for ( x = 0; x < (width>>2); x++ ) {
987 	    mf->orig_cb[2*y][2*x] = buffer[x];
988 	    mf->orig_cb[2*y][2*x+1] = buffer[x];
989 	    mf->orig_cb[2*y+1][2*x] = buffer[x];
990 	    mf->orig_cb[2*y+1][2*x+1] = buffer[x];
991 	}
992     }
993 
994     for (y = 0; y < (height >> 2); y++) {			/* V */
995 	safe_fread(buffer, 1, width>>2, fpointer);
996 	for ( x = 0; x < (width>>2); x++ ) {
997 	    mf->orig_cr[2*y][2*x] = buffer[x];
998 	    mf->orig_cr[2*y][2*x+1] = buffer[x];
999 	    mf->orig_cr[2*y+1][2*x] = buffer[x];
1000 	    mf->orig_cr[2*y+1][2*x+1] = buffer[x];
1001 	}
1002     }
1003 }
1004 
1005 
1006 /*=====================*
1007  * INTERNAL PROCEDURES *
1008  *=====================*/
1009 
1010 /*===========================================================================*
1011  *
1012  * ScanNextString
1013  *
1014  *	read a string from a input line, ignoring whitespace
1015  *
1016  * RETURNS:	pointer to position in input line after string
1017  *              NULL if all whitespace
1018  *              puts string in 'string'
1019  *
1020  * SIDE EFFECTS:    file stream munched a bit
1021  *
1022  *===========================================================================*/
1023 static char *
ScanNextString(char * inputLine,char * string)1024 ScanNextString(char *inputLine,
1025                char *string)
1026 {
1027     /* skip whitespace */
1028     while ( isspace(*inputLine) && (*inputLine != '\n') ) {
1029         inputLine++;
1030     }
1031 
1032     if ( *inputLine == '\n' ) {
1033         return NULL;
1034     }
1035 
1036     while ( (! isspace(*inputLine)) && (*inputLine != '\n') ) {
1037         *string = *inputLine;
1038 	string++;
1039 	inputLine++;
1040     }
1041 
1042     *string = '\0';
1043 
1044     return inputLine;
1045 }
1046 
1047 /*===========================================================================*
1048  *
1049  * DoGamma
1050  *
1051  *	Gamma Correct the Lum values
1052  *
1053  * RETURNS:	nothing
1054  *
1055  * SIDE EFFECTS:    Raises Y values to power gamma.
1056  *
1057  *===========================================================================*/
1058 static void
DoGamma(MpegFrame * mf,int w,int h)1059 DoGamma(MpegFrame *mf,
1060         int w, int h)
1061 {
1062   static int GammaVal[256];
1063   static boolean init_done=FALSE;
1064   int i,j;
1065 
1066   if (!init_done) {
1067     for(i=0; i<256; i++)
1068       GammaVal[i]=(unsigned char) (pow(((double) i)/255.0,(double)GammaValue)*255.0+0.5);
1069     init_done=TRUE;
1070   }
1071 
1072   for (i=0; i< h; i++) {  /* For each line */
1073     for (j=0; j<w; j++) { /* For each Y value */
1074       mf->orig_y[i][j] = GammaVal[mf->orig_y[i][j]];
1075     }}
1076 }
1077 
1078 
1079 
1080 
1081 /*===========================================================================*
1082  *
1083  * DoKillDim
1084  *
1085  *	Applies an input filter to small Y values.
1086  *
1087  * RETURNS:	nothing
1088  *
1089  * SIDE EFFECTS:    Changes Y values:
1090  *
1091  *  Output    |                 /
1092               |                /
1093               |               /
1094               |              !
1095               |             /
1096               |            !
1097               |           /
1098               |          -
1099               |        /
1100               |      --
1101               |     /
1102               |   --
1103               | /
1104               ------------------------
1105                         ^ kill_dim_break
1106                              ^kill_dim_end
1107               kill_dim_slope gives the slope (y = kill_dim_slope * x +0)
1108               from 0 to kill_dim_break
1109  *
1110  *===========================================================================*/
1111 
1112 static void
DoKillDim(MpegFrame * mf,int w,int h)1113 DoKillDim(MpegFrame *mf,
1114           int w, int h)
1115 {
1116   static boolean init_done=FALSE;
1117   static unsigned char mapper[256];
1118   register int i,j;
1119   double slope, intercept;
1120 
1121   slope = (kill_dim_end - kill_dim_break*kill_dim_slope)*1.0 /
1122     (kill_dim_end - kill_dim_break);
1123   intercept = kill_dim_end * (1.0-slope);
1124 
1125   if (!init_done) {
1126     for(i=0; i<256; i++) {
1127       if (i >= kill_dim_end) {
1128         mapper[i] = (char) i;
1129       } else if (i >= kill_dim_break) {
1130         mapper[i] = (char) (slope*i + intercept);
1131       } else { /* i <= kill_dim_break */
1132         mapper[i] = (char) floor(i*kill_dim_slope + 0.49999);
1133       }
1134     }
1135     init_done = TRUE;
1136   }
1137 
1138   for (i=0;  i < h;  i++) {  /* For each line */
1139     for (j=0;   j < w;   j++) { /* For each Y value */
1140       mf->orig_y[i][j] = mapper[mf->orig_y[i][j]];
1141     }}
1142 }
1143