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 
167 /*==================*
168  * Global VARIABLES *
169  *==================*/
170 
171 extern boolean GammaCorrection;
172 extern float GammaValue;
173 extern int outputWidth,outputHeight;
174 boolean resizeFrame;
175 char *CurrFile;
176 
177 /*===============================*
178  * INTERNAL PROCEDURE prototypes *
179  *===============================*/
180 
181 static char *ScanNextString _ANSI_ARGS_((char *inputLine, char *string));
182 static void ReadPNM _ANSI_ARGS_((FILE * fp, MpegFrame * mf));
183 static boolean	ReadPPM _ANSI_ARGS_((MpegFrame *mf, FILE *fpointer));
184 static void ReadEYUV _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer,
185 				 int width, int height));
186 static void ReadAYUV _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer,
187 				 int width, int height));
188 static void SeparateLine _ANSI_ARGS_((FILE *fpointer, struct YuvLine *lineptr,
189 				     int width));
190 static void ReadY _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer,
191 				 int width, int height));
192 static void ReadSub4 _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer,
193 				  int width, int height));
194 static void DoGamma  _ANSI_ARGS_((MpegFrame *mf, int width, int height));
195 
196 static void DoKillDim _ANSI_ARGS_((MpegFrame *mf, int w, int h));
197 
198 #define safe_fread(ptr,sz,len,fileptr)                           \
199     if ((safe_read_count=fread(ptr,sz,len,fileptr))!=sz*len) {   \
200       fprintf(stderr,"Input file too small! (%s)\n",CurrFile);   \
201       exit(1);}                                                  \
202 
203 /*=====================*
204  * EXPORTED PROCEDURES *
205  *=====================*/
206 
207 
208 
SetResize(set)209 void	SetResize(set)
210     boolean	set;
211 {
212     resizeFrame = set;
213 }
214 
215 
216 
217 /*===========================================================================*
218  *
219  * ReadFrame
220  *
221  *	reads the given frame, performing conversion as necessary
222  *	if addPath = TRUE, then must add the current path before the
223  *	file name
224  *
225  * RETURNS:	frame modified
226  *
227  * SIDE EFFECTS:    none
228  *
229  *===========================================================================*/
230 void
ReadFrame(frame,fileName,conversion,addPath)231 ReadFrame(frame, fileName, conversion, addPath)
232     MpegFrame *frame;
233     char *fileName;
234     char *conversion;
235     boolean addPath;
236 {
237     FILE    *ifp;
238     char    command[1024];
239     char    fullFileName[1024];
240     MpegFrame    tempFrame;
241     MpegFrame    *framePtr;
242 #ifdef BLEAH
243     static int32    readDiskTime = 0;
244     int32    diskStartTime, diskEndTime;
245 
246 time(&diskStartTime);
247 #endif
248 
249     if ( resizeFrame ) {
250       tempFrame.inUse = FALSE;
251       tempFrame.ppm_data = NULL;
252       tempFrame.rgb_data = NULL;
253       tempFrame.orig_y = NULL;
254       tempFrame.y_blocks = NULL;
255       tempFrame.decoded_y = NULL;
256       tempFrame.halfX = NULL;
257       framePtr = &tempFrame;
258     } else {
259       framePtr = frame;
260     }
261 
262     if ( addPath ) {
263       sprintf(fullFileName, "%s/%s", currentPath, fileName);
264     } else {
265       sprintf(fullFileName, "%s", fileName);
266     }
267 
268     CurrFile = fullFileName;
269 
270 #ifdef BLEAH
271     if ( ! childProcess ) {
272     fprintf(stdout, "+++++READING Frame %d  (type %d):  %s\n", framePtr->id,
273             framePtr->type, fullFileName);
274     }
275 #endif
276 
277     if ( fileType == ANY_FILE_TYPE ) {
278     char *convertPtr, *commandPtr, *charPtr;
279 
280       if ( stdinUsed ) {
281         fprintf(stderr, "ERROR : cannot use stdin with INPUT_CONVERT.\n");
282         exit(1);
283       }
284 
285       /* replace every occurrence of '*' with fullFileName */
286       convertPtr = conversion;
287       commandPtr = command;
288       while ( *convertPtr != '\0' ) {
289         while ( (*convertPtr != '\0') && (*convertPtr != '*') ) {
290           *commandPtr = *convertPtr;
291           commandPtr++;
292           convertPtr++;
293         }
294 
295         if ( *convertPtr == '*' ) {
296           /* copy fullFileName */
297           charPtr = fullFileName;
298           while ( *charPtr != '\0' ) {
299             *commandPtr = *charPtr;
300             commandPtr++;
301             charPtr++;
302           }
303 
304           convertPtr++;   /* go past '*' */
305         }
306       }
307       *commandPtr = '\0';
308 
309       if ( (ifp = popen(command, "r")) == NULL ) {
310         fprintf(stderr, "ERROR:  Couldn't execute input conversion command:\n");
311         fprintf(stderr, "\t%s\n", command);
312         fprintf(stderr, "errno = %d\n", errno);
313         if ( ioServer ) {
314           fprintf(stderr, "IO SERVER:  EXITING!!!\n");
315         } else {
316           fprintf(stderr, "SLAVE EXITING!!!\n");
317         }
318         exit(1);
319       }
320     } else if (stdinUsed) {
321       ifp = stdin;
322     } else if ( (ifp = fopen(fullFileName, "rb")) == NULL ) {
323       fprintf(stderr, "ERROR:  Couldn't open input file %s\n",
324               fullFileName);
325       exit(1);
326     }
327 
328     switch(baseFormat) {
329     case YUV_FILE_TYPE:
330 
331         /* Encoder YUV */
332         if ((strncmp (yuvConversion, "EYUV", 4) == 0) ||
333             (strncmp (yuvConversion, "UCB", 3) == 0) )
334         {
335             ReadEYUV(framePtr, ifp, realWidth, realHeight);
336         }
337 
338         /* Abekas-type (interlaced) YUV */
339         else {
340             ReadAYUV(framePtr, ifp, realWidth, realHeight);
341         }
342 
343         break;
344     case Y_FILE_TYPE:
345         ReadY(framePtr, ifp, realWidth, realHeight);
346         break;
347     case PPM_FILE_TYPE:
348         if ( ! ReadPPM(framePtr, ifp) ) {
349         fprintf(stderr, "Error reading PPM input file!!! (%s)\n", CurrFile);
350         exit(1);
351         }
352         PPMtoYUV(framePtr);
353         break;
354     case PNM_FILE_TYPE:
355         ReadPNM(ifp, framePtr);
356         PNMtoYUV(framePtr);
357         break;
358     case SUB4_FILE_TYPE:
359         ReadSub4(framePtr, ifp, yuvWidth, yuvHeight);
360         break;
361     case JPEG_FILE_TYPE:
362     case JMOVIE_FILE_TYPE:
363         ReadJPEG(framePtr, ifp);
364         break;
365     default:
366         break;
367     }
368 
369     if (! stdinUsed) {
370       if ( fileType == ANY_FILE_TYPE ) {
371 	int errorcode;
372 	if ( (errorcode = pclose(ifp)) != 0) {
373 	  fprintf(stderr, "WARNING:  Pclose reported error (%d)\n", errorcode);
374 	}
375       } else {
376         fclose(ifp);
377       }
378     }
379 
380     if ( baseFormat == JMOVIE_FILE_TYPE ) {
381       remove(fullFileName);
382     }
383 
384     if ( resizeFrame ) {
385       Frame_Resize(frame, &tempFrame, Fsize_x, Fsize_y, outputWidth, outputHeight);
386     }
387 
388 #ifdef BLEAH
389 time(&diskEndTime);
390 
391 readDiskTime += (diskEndTime-diskStartTime);
392 
393 fprintf(stdout, "cumulative disk read time:  %d seconds\n", readDiskTime);
394 #endif
395 
396     if ( GammaCorrection ) {
397       DoGamma(frame, Fsize_x, Fsize_y);
398     }
399 
400     if ( kill_dim ) {
401       DoKillDim(frame, Fsize_x, Fsize_y);
402     }
403 
404     MotionSearchPreComputation(frame);
405 }
406 
407 
408 /*===========================================================================*
409  *
410  * SetFileType
411  *
412  *	set the file type to be either a base type (no conversion), or
413  *	any type (conversion required)
414  *
415  * RETURNS:	nothing
416  *
417  * SIDE EFFECTS:    fileType
418  *
419  *===========================================================================*/
420 void
SetFileType(conversion)421 SetFileType(conversion)
422     char *conversion;
423 {
424     if ( strcmp(conversion, "*") == 0 ) {
425 	fileType = BASE_FILE_TYPE;
426     } else {
427 	fileType = ANY_FILE_TYPE;
428     }
429 }
430 
431 
432 /*===========================================================================*
433  *
434  * SetFileFormat
435  *
436  *	set the file format (PPM, PNM, YUV, JPEG)
437  *
438  * RETURNS:	nothing
439  *
440  * SIDE EFFECTS:    baseFormat
441  *
442  *===========================================================================*/
443 void
SetFileFormat(format)444 SetFileFormat(format)
445     char *format;
446 {
447     if ( strcmp(format, "PPM") == 0 ) {
448 	baseFormat = PPM_FILE_TYPE;
449     } else if ( strcmp(format, "YUV") == 0 ) {
450 	baseFormat = YUV_FILE_TYPE;
451     } else if ( strcmp(format, "Y") == 0 ) {
452 	baseFormat = Y_FILE_TYPE;
453     } else if ( strcmp(format, "PNM") == 0 ) {
454 	baseFormat = PNM_FILE_TYPE;
455     } else if (( strcmp(format, "JPEG") == 0 ) || ( strcmp(format, "JPG") == 0 )) {
456 	baseFormat = JPEG_FILE_TYPE;
457     } else if ( strcmp(format, "JMOVIE") == 0 ) {
458 	baseFormat = JMOVIE_FILE_TYPE;
459     } else if ( strcmp(format, "SUB4") == 0 ) {
460 	baseFormat = SUB4_FILE_TYPE;
461     } else {
462 	fprintf(stderr, "ERROR:  Invalid file format:  %s\n", format);
463 	exit(1);
464     }
465 }
466 
467 
468 /*===========================================================================*
469  *
470  * ReadPNM
471  *
472  *	read a PNM file
473  *
474  * RETURNS:	mf modified
475  *
476  * SIDE EFFECTS:    none
477  *
478  *===========================================================================*/
479 static void
ReadPNM(fp,mf)480 ReadPNM(fp, mf)
481     FILE *fp;
482     MpegFrame *mf;
483 {
484     int x, y;
485     xelval maxval;
486     int format;
487 
488     if (mf->rgb_data) {
489 	pnm_freearray(mf->rgb_data, Fsize_y);
490     }
491     mf->rgb_data = pnm_readpnm(fp, &x, &y, &maxval, &format);
492     ERRCHK(mf, "pnm_readpnm");
493 
494     if (format != PPM_FORMAT) {
495 	if (maxval < 255) {
496 	    pnm_promoteformat(mf->rgb_data, x, y, maxval, format, 255, PPM_FORMAT);
497 	    maxval = 255;
498 	} else {
499 	    pnm_promoteformat(mf->rgb_data, x, y, maxval, format, maxval, PPM_FORMAT);
500 	}
501     }
502     if (maxval < 255) {
503 	pnm_promoteformat(mf->rgb_data, x, y, maxval, format, 255, format);
504 	maxval = 255;
505     }
506     /*
507      * if this is the first frame read, set the global frame size
508      */
509     Fsize_Note(mf->id, x, y);
510 
511     mf->rgb_maxval = maxval;
512     mf->rgb_format = PPM_FORMAT;
513 }
514 
515 
516 
517 /*===========================================================================*
518  *
519  * ReadIOConvert
520  *
521  *	do conversion; return a pointer to the appropriate file
522  *
523  * RETURNS:	pointer to the appropriate file
524  *
525  * SIDE EFFECTS:    none
526  *
527  *===========================================================================*/
528 FILE *
ReadIOConvert(fileName)529 ReadIOConvert(fileName)
530     char *fileName;
531 {
532     FILE	*ifp;
533     char	command[1024];
534     char	fullFileName[1024];
535     char *convertPtr, *commandPtr, *charPtr;
536 
537     sprintf(fullFileName, "%s/%s", currentPath, fileName);
538 
539 #ifdef BLEAH
540     if ( ! childProcess ) {
541 	fprintf(stdout, "+++++READING (IO CONVERT) Frame %d  (type %d):  %s\n", frame->id,
542 		frame->type, fullFileName); }
543 #endif
544 
545     if ( strcmp(ioConversion, "*") == 0 ) {
546       char buff[1024];
547       ifp = fopen(fullFileName, "rb");
548       sprintf(buff,"fopen \"%s\"",fullFileName);
549       ERRCHK(ifp, buff);
550       return ifp;
551     }
552 
553     /* replace every occurrence of '*' with fullFileName */
554     convertPtr = ioConversion;
555     commandPtr = command;
556     while ( *convertPtr != '\0' ) {
557 	while ( (*convertPtr != '\0') && (*convertPtr != '*') ) {
558 	    *commandPtr = *convertPtr;
559 	    commandPtr++;
560 	    convertPtr++;
561 	}
562 
563 	if ( *convertPtr == '*' ) {
564 	    /* copy fullFileName */
565 	    charPtr = fullFileName;
566 	    while ( *charPtr != '\0' ) {
567 		*commandPtr = *charPtr;
568 		commandPtr++;
569 		charPtr++;
570 	    }
571 
572 	    convertPtr++;   /* go past '*' */
573 	}
574     }
575     *commandPtr = '\0';
576 
577     if ( (ifp = popen(command, "r")) == NULL ) {
578 	fprintf(stderr, "ERROR:  Couldn't execute input conversion command:\n");
579 	fprintf(stderr, "\t%s\n", command);
580 	fprintf(stderr, "errno = %d\n", errno);
581 	if ( ioServer ) {
582 	    fprintf(stderr, "IO SERVER:  EXITING!!!\n");
583 	} else {
584 	    fprintf(stderr, "SLAVE EXITING!!!\n");
585 	}
586 	exit(1);
587     }
588 
589     return ifp;
590 }
591 
592 
593 
594 /*===========================================================================*
595  *
596  * ReadPPM
597  *
598  *	read a PPM file
599  *
600  * RETURNS:	TRUE if successful; FALSE otherwise; mf modified
601  *
602  * SIDE EFFECTS:    none
603  *
604  *===========================================================================*/
605 static boolean
ReadPPM(mf,fpointer)606 ReadPPM(mf, fpointer)
607     MpegFrame *mf;
608     FILE *fpointer;
609 {
610     char    inputBuffer[71];
611     char    string[71];
612     char    *inputLine;
613     int	    height = 0, width = 0, maxVal=255;
614     uint8   junk[4096];
615     register int y;
616     int	    state;
617     int     safe_read_count;
618 
619     state = PPM_READ_STATE_MAGIC;
620 
621     while ( state != PPM_READ_STATE_DONE ) {
622 	if ( fgets(inputBuffer, 71, fpointer) == NULL ) {
623 	    return FALSE;
624 	}
625 
626         inputLine = inputBuffer;
627 
628 	if ( inputLine[0] == '#' ) {
629 	    continue;
630 	}
631 
632 	if ( inputLine[strlen(inputLine)-1] != '\n' ) {
633 	    return FALSE;
634 	}
635 
636 	switch(state) {
637 	    case PPM_READ_STATE_MAGIC:
638 	        if ( (inputLine = ScanNextString(inputLine, string)) == NULL ) {
639 		    return FALSE;
640 		}
641 
642 		if ( strcmp(string, "P6") != 0 ) {
643 		    return FALSE;
644 		}
645 		state = PPM_READ_STATE_WIDTH;
646 		/* no break */
647 	    case PPM_READ_STATE_WIDTH:
648 	        if ( (inputLine = ScanNextString(inputLine, string)) == NULL ) {
649 		    if ( inputLine == inputBuffer ) {
650 		        return FALSE;
651 		    } else {
652 		        break;
653 		    }
654 		}
655 
656 		width = atoi(string);
657 
658 		state = PPM_READ_STATE_HEIGHT;
659 
660 		/* no break */
661 	    case PPM_READ_STATE_HEIGHT:
662 	        if ( (inputLine = ScanNextString(inputLine, string)) == NULL ) {
663 		    if ( inputLine == inputBuffer ) {
664 		        return FALSE;
665 		    } else {
666 		        break;
667 		    }
668 		}
669 
670 		height = atoi(string);
671 
672 		state = PPM_READ_STATE_MAXVAL;
673 
674 		/* no break */
675 	    case PPM_READ_STATE_MAXVAL:
676 	        if ( (inputLine = ScanNextString(inputLine, string)) == NULL ) {
677 		    if ( inputLine == inputBuffer ) {
678 		        return FALSE;
679 		    } else {
680 		        break;
681 		    }
682 		}
683 
684 		maxVal = atoi(string);
685 
686 		state = PPM_READ_STATE_DONE;
687 		break;
688 	} /* end of switch */
689     }
690 
691     Fsize_Note(mf->id, width, height);
692 
693     mf->rgb_maxval = maxVal;
694 
695     Frame_AllocPPM(mf);
696 
697     for ( y = 0; y < Fsize_y; y++ ) {
698 	safe_fread(mf->ppm_data[y], sizeof(char), 3*Fsize_x, fpointer);
699 
700 	/* read the leftover stuff on the right side */
701 	safe_fread(junk, sizeof(char), 3*(width-Fsize_x), fpointer);
702     }
703 
704     /* read the leftover stuff to prevent broken pipe */
705     for ( y=Fsize_y; y<height; ++y ) {
706       safe_fread(junk, sizeof(char), 3*Fsize_x, fpointer);
707     }
708     return TRUE;
709 }
710 
711 
712 /*===========================================================================*
713  *
714  * ReadEYUV
715  *
716  *	read a Encoder-YUV file (concatenated Y, U, and V)
717  *
718  * RETURNS:	mf modified
719  *
720  * SIDE EFFECTS:    none
721  *
722  *===========================================================================*/
723 static void
ReadEYUV(mf,fpointer,width,height)724 ReadEYUV(mf, fpointer, width, height)
725     MpegFrame *mf;
726     FILE *fpointer;
727     int width;
728     int height;
729 {
730     register int y;
731     uint8   junk[4096];
732     int     safe_read_count;
733 
734     Fsize_Note(mf->id, width, height);
735 
736     Frame_AllocYCC(mf);
737 
738     for (y = 0; y < Fsize_y; y++) {			/* Y */
739 	safe_fread(mf->orig_y[y], 1, Fsize_x, fpointer);
740 
741 	/* read the leftover stuff on the right side */
742 	if ( width != Fsize_x ) {
743 	    safe_fread(junk, 1, width-Fsize_x, fpointer);
744 	}
745     }
746 
747     /* read the leftover stuff on the bottom */
748     for (y = Fsize_y; y < height; y++) {
749 	safe_fread(junk, 1, width, fpointer);
750     }
751 
752     for (y = 0; y < (Fsize_y >> 1); y++) {			/* U */
753 	safe_fread(mf->orig_cb[y], 1, Fsize_x >> 1, fpointer);
754 
755 	/* read the leftover stuff on the right side */
756 	if ( width != Fsize_x ) {
757 	    safe_fread(junk, 1, (width-Fsize_x)>>1, fpointer);
758 	}
759     }
760 
761     /* read the leftover stuff on the bottom */
762     for (y = (Fsize_y >> 1); y < (height >> 1); y++) {
763 	safe_fread(junk, 1, width>>1, fpointer);
764     }
765 
766     for (y = 0; y < (Fsize_y >> 1); y++) {			/* V */
767 	safe_fread(mf->orig_cr[y], 1, Fsize_x >> 1, fpointer);
768 
769 	/* read the leftover stuff on the right side */
770 	if ( width != Fsize_x ) {
771 	    safe_fread(junk, 1, (width-Fsize_x)>>1, fpointer);
772 	}
773     }
774 
775     /* ignore leftover stuff on the bottom */
776 }
777 
778 /*===========================================================================*
779  *
780  * ReadAYUV
781  *
782  *	read an Abekas-YUV file
783  *
784  * RETURNS:	mf modified
785  *
786  * SIDE EFFECTS:    none
787  *
788  *===========================================================================*/
789 static void
ReadAYUV(mf,fpointer,width,height)790 ReadAYUV(mf, fpointer, width, height)
791     MpegFrame *mf;
792     FILE *fpointer;
793     int width;
794     int height;
795 {
796     register int x, y;
797     struct  YuvLine line1, line2;
798     uint8   junk[4096];
799     int8    *cbptr, *crptr;
800     int     safe_read_count;
801 
802     Fsize_Note(mf->id, width, height);
803 
804     Frame_AllocYCC(mf);
805 
806     for (y = 0; y < Fsize_y; y += 2) {
807 	SeparateLine(fpointer, &line1, width);
808 	SeparateLine(fpointer, &line2, width);
809 
810 	/* Copy the Y values for each line to the frame */
811 	for (x = 0; x < Fsize_x; x++) {
812 	    mf->orig_y[y][x]   = line1.y[x];
813 	    mf->orig_y[y+1][x] = line2.y[x];
814 	}
815 
816 	cbptr = &(mf->orig_cb[y>>1][0]);
817 	crptr = &(mf->orig_cr[y>>1][0]);
818 
819 	/* One U and one V for each two pixels horizontal as well */
820 	/* Toss the second line of Cr/Cb info, averaging was worse,
821 	   so just subsample */
822 	for (x = 0; x < (Fsize_x >> 1); x ++) {
823 	    cbptr[x] =  line1.cb[x];
824 	    crptr[x] =  line1.cr[x];
825 
826 	}
827     }
828 
829     /* read the leftover stuff on the bottom */
830     for (y = Fsize_y; y < height; y++) {
831 	safe_fread(junk, 1, width<<1, fpointer);
832     }
833 
834 }
835 
836 /*===========================================================================*
837  *
838  * SeparateLine
839  *
840  *	Separates one line of pixels into Y, U, and V components
841  *
842  * RETURNS:	lineptr modified
843  *
844  * SIDE EFFECTS:    none
845  *
846  *===========================================================================*/
847 static void
SeparateLine(fpointer,lineptr,width)848 SeparateLine(fpointer, lineptr, width)
849     FILE *fpointer;
850     struct YuvLine *lineptr;
851     int width;
852 {
853     uint8   junk[4096];
854     int8    *crptr, *cbptr;
855     uint8   *yptr;
856     int     num, length;
857     int     safe_read_count;
858 
859 
860     /* Sets the deinterlacing pattern */
861 
862 	/* shorthand for UYVY */
863     if (strncmp(yuvConversion, "ABEKAS", 6) == 0) {
864 	strcpy(yuvConversion, "UYVY");
865 
866 	/* shorthand for YUYV */
867     } else if (strncmp(yuvConversion, "PHILLIPS", 8) == 0) {
868 	strcpy(yuvConversion, "YUYV");
869     }
870 
871     length = strlen (yuvConversion);
872 
873     if ((length % 2) != 0) {
874 	fprintf (stderr, "ERROR : YUV_FORMAT must represent two pixels, hence must be even in length.\n");
875 	exit(1);
876     }
877 
878     /* each line in 4:2:2 chroma format takes 2X bytes to represent X pixels.
879      * each line in 4:4:4 chroma format takes 3X bytes to represent X pixels.
880      * Therefore, half of the length of the YUV_FORMAT represents 1 pixel.
881      */
882     safe_fread(lineptr->data, 1, Fsize_x*(length>>1), fpointer);
883 
884     /* read the leftover stuff on the right side */
885     if ( width != Fsize_x ) {
886 	safe_fread(junk, 1, (width-Fsize_x)*(length>>1), fpointer);
887     }
888 
889     crptr = &(lineptr->cr[0]);
890     cbptr = &(lineptr->cb[0]);
891     yptr = &(lineptr->y[0]);
892 
893     for (num = 0; num < (Fsize_x*(length>>1)); num++) {
894 	switch (yuvConversion[num % length]) {
895 	case 'U':
896 	case 'u':
897 	    *(cbptr++) = (lineptr->data[num]);
898 	    break;
899 	case 'V':
900 	case 'v':
901 	    *(crptr++) = (lineptr->data[num]);
902 	    break;
903 	case 'Y':
904 	case 'y':
905 	    *(yptr++) = (lineptr->data[num]);
906 	    break;
907 	default:
908             fprintf(stderr, "ERROR: YUV_FORMAT must be one of the following:\n");
909             fprintf(stderr, "       ABEKAS\n");
910             fprintf(stderr, "       EYUV\n");
911             fprintf(stderr, "       PHILLIPS\n");
912             fprintf(stderr, "       UCB\n");
913 	    fprintf(stderr, "       or any even-length string consisting of the letters U, V, and Y.\n");
914             exit(1);
915         }
916 
917     }
918 
919 }
920 
921 
922 /*===========================================================================*
923  *
924  * ReadY
925  *
926  *	read a Y file
927  *
928  * RETURNS:	mf modified
929  *
930  * SIDE EFFECTS:    none
931  *
932  *===========================================================================*/
933 static void
ReadY(mf,fpointer,width,height)934 ReadY(mf, fpointer, width, height)
935     MpegFrame *mf;
936     FILE *fpointer;
937     int width;
938     int height;
939 {
940     register int y;
941     uint8   junk[4096];
942     int     safe_read_count;
943 
944     Fsize_Note(mf->id, width, height);
945 
946     Frame_AllocYCC(mf);
947 
948     for (y = 0; y < Fsize_y; y++) {			/* Y */
949 	safe_fread(mf->orig_y[y], 1, Fsize_x, fpointer);
950 
951 	/* read the leftover stuff on the right side */
952 	if ( width != Fsize_x ) {
953 	    safe_fread(junk, 1, width-Fsize_x, fpointer);
954 	}
955     }
956 
957     /* read the leftover stuff on the bottom */
958     for (y = Fsize_y; y < height; y++) {
959 	safe_fread(junk, 1, width, fpointer);
960     }
961 
962     for (y = 0 ; y < (Fsize_y >> 1); y++) {
963       memset(mf->orig_cb[y], 128, (Fsize_x>>1));
964       memset(mf->orig_cr[y], 128, (Fsize_x>>1));
965     }
966 }
967 
968 
969 /*===========================================================================*
970  *
971  * ReadSub4
972  *
973  *	read a YUV file (subsampled even further by 4:1 ratio)
974  *
975  * RETURNS:	mf modified
976  *
977  * SIDE EFFECTS:    none
978  *
979  *===========================================================================*/
980 static void
ReadSub4(mf,fpointer,width,height)981 ReadSub4(mf, fpointer, width, height)
982     MpegFrame *mf;
983     FILE *fpointer;
984     int width;
985     int height;
986 {
987     register int y;
988     register int x;
989     uint8   buffer[1024];
990     int     safe_read_count;
991 
992     Fsize_Note(mf->id, width, height);
993 
994     Frame_AllocYCC(mf);
995 
996     for (y = 0; y < (height>>1); y++) {			/* Y */
997 	safe_fread(buffer, 1, width>>1, fpointer);
998 	for ( x = 0; x < (width>>1); x++ ) {
999 	    mf->orig_y[2*y][2*x] = buffer[x];
1000 	    mf->orig_y[2*y][2*x+1] = buffer[x];
1001 	    mf->orig_y[2*y+1][2*x] = buffer[x];
1002 	    mf->orig_y[2*y+1][2*x+1] = buffer[x];
1003 	}
1004     }
1005 
1006     for (y = 0; y < (height >> 2); y++) {			/* U */
1007 	safe_fread(buffer, 1, width>>2, fpointer);
1008 	for ( x = 0; x < (width>>2); x++ ) {
1009 	    mf->orig_cb[2*y][2*x] = buffer[x];
1010 	    mf->orig_cb[2*y][2*x+1] = buffer[x];
1011 	    mf->orig_cb[2*y+1][2*x] = buffer[x];
1012 	    mf->orig_cb[2*y+1][2*x+1] = buffer[x];
1013 	}
1014     }
1015 
1016     for (y = 0; y < (height >> 2); y++) {			/* V */
1017 	safe_fread(buffer, 1, width>>2, fpointer);
1018 	for ( x = 0; x < (width>>2); x++ ) {
1019 	    mf->orig_cr[2*y][2*x] = buffer[x];
1020 	    mf->orig_cr[2*y][2*x+1] = buffer[x];
1021 	    mf->orig_cr[2*y+1][2*x] = buffer[x];
1022 	    mf->orig_cr[2*y+1][2*x+1] = buffer[x];
1023 	}
1024     }
1025 }
1026 
1027 
1028 /*=====================*
1029  * INTERNAL PROCEDURES *
1030  *=====================*/
1031 
1032 /*===========================================================================*
1033  *
1034  * ScanNextString
1035  *
1036  *	read a string from a input line, ignoring whitespace
1037  *
1038  * RETURNS:	pointer to position in input line after string
1039  *              NULL if all whitespace
1040  *              puts string in 'string'
1041  *
1042  * SIDE EFFECTS:    file stream munched a bit
1043  *
1044  *===========================================================================*/
1045 static char *
ScanNextString(inputLine,string)1046 ScanNextString(inputLine, string)
1047     char *inputLine;
1048     char *string;
1049 {
1050     /* skip whitespace */
1051     while ( isspace(*inputLine) && (*inputLine != '\n') ) {
1052         inputLine++;
1053     }
1054 
1055     if ( *inputLine == '\n' ) {
1056         return NULL;
1057     }
1058 
1059     while ( (! isspace(*inputLine)) && (*inputLine != '\n') ) {
1060         *string = *inputLine;
1061 	string++;
1062 	inputLine++;
1063     }
1064 
1065     *string = '\0';
1066 
1067     return inputLine;
1068 }
1069 
1070 /*===========================================================================*
1071  *
1072  * DoGamma
1073  *
1074  *	Gamma Correct the Lum values
1075  *
1076  * RETURNS:	nothing
1077  *
1078  * SIDE EFFECTS:    Raises Y values to power gamma.
1079  *
1080  *===========================================================================*/
1081 static void
DoGamma(mf,w,h)1082 DoGamma(mf, w, h)
1083 MpegFrame *mf;
1084 int w,h;
1085 {
1086   static int GammaVal[256];
1087   static boolean init_done=FALSE;
1088   int i,j;
1089 
1090   if (!init_done) {
1091     for(i=0; i<256; i++)
1092       GammaVal[i]=(unsigned char) (pow(((double) i)/255.0,GammaValue)*255.0+0.5);
1093     init_done=TRUE;
1094   }
1095 
1096   for (i=0; i< h; i++) {  /* For each line */
1097     for (j=0; j<w; j++) { /* For each Y value */
1098       mf->orig_y[i][j] = GammaVal[mf->orig_y[i][j]];
1099     }}
1100 }
1101 
1102 
1103 
1104 
1105 /*===========================================================================*
1106  *
1107  * DoKillDim
1108  *
1109  *	Applies an input filter to small Y values.
1110  *
1111  * RETURNS:	nothing
1112  *
1113  * SIDE EFFECTS:    Changes Y values:
1114  *
1115  *  Output    |                 /
1116               |                /
1117               |               /
1118               |              !
1119               |             /
1120               |            !
1121               |           /
1122               |          -
1123               |        /
1124               |      --
1125               |     /
1126               |   --
1127               | /
1128               ------------------------
1129                         ^ kill_dim_break
1130                              ^kill_dim_end
1131               kill_dim_slope gives the slope (y = kill_dim_slope * x +0)
1132               from 0 to kill_dim_break
1133  *
1134  *===========================================================================*/
1135 
1136 static void
DoKillDim(mf,w,h)1137 DoKillDim(mf, w, h)
1138 MpegFrame *mf;
1139 int w,h;
1140 {
1141   static boolean init_done=FALSE;
1142   static unsigned char mapper[256];
1143   register int i,j;
1144   double slope, intercept;
1145 
1146   slope = (kill_dim_end - kill_dim_break*kill_dim_slope)*1.0 /
1147     (kill_dim_end - kill_dim_break);
1148   intercept = kill_dim_end * (1.0-slope);
1149 
1150   if (!init_done) {
1151     for(i=0; i<256; i++) {
1152       if (i >= kill_dim_end) {
1153         mapper[i] = (char) i;
1154       } else if (i >= kill_dim_break) {
1155         mapper[i] = (char) (slope*i + intercept);
1156       } else { /* i <= kill_dim_break */
1157         mapper[i] = (char) floor(i*kill_dim_slope + 0.49999);
1158       }
1159     }
1160     init_done = TRUE;
1161   }
1162 
1163   for (i=0;  i < h;  i++) {  /* For each line */
1164     for (j=0;   j < w;   j++) { /* For each Y value */
1165       mf->orig_y[i][j] = mapper[mf->orig_y[i][j]];
1166     }}
1167 }
1168