1 /*
2  * main.c --
3  *
4  *      Main procedure
5  *
6  */
7 
8 /*
9  * Copyright (c) 1995 The Regents of the University of California.
10  * All rights reserved.
11  *
12  * Permission to use, copy, modify, and distribute this software and its
13  * documentation for any purpose, without fee, and without written agreement is
14  * hereby granted, provided that the above copyright notice and the following
15  * two paragraphs appear in all copies of this software.
16  *
17  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
18  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
19  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
20  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21  *
22  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
23  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
24  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
25  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
26  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
27  */
28 
29 /*
30  * Portions of this software Copyright (c) 1995 Brown University.
31  * All rights reserved.
32  *
33  * Permission to use, copy, modify, and distribute this software and its
34  * documentation for any purpose, without fee, and without written agreement
35  * is hereby granted, provided that the above copyright notice and the
36  * following two paragraphs appear in all copies of this software.
37  *
38  * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR
39  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
40  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN
41  * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42  *
43  * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
44  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
45  * PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
46  * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
47  * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
48  */
49 
50 #include "video.h"
51 #include "proto.h"
52 #ifndef NOCONTROLS
53 #include "ctrlbar.h"
54 #endif
55 #include <math.h>
56 #include <sys/types.h>
57 #include <signal.h>
58 #include <netinet/in.h>
59 #include <string.h> /* strtok */
60 #include "util.h"
61 #include "dither.h"
62 
63 /*
64    Changes to make the code reentrant:
65      Got rid of setjmp, longjmp
66      deglobalized: EOF_flag, FilmState, curVidStream, bitOffset, bitLength,
67      bitBuffer, sys_layer, input, seekValue, window, X Windows globals (to
68      xinfo), curBits, ditherType, matched_depth, totNumFrames, realTimeStart
69 
70    Additional changes:
71      Ability to play >1 movie (w/out CONTROLS)
72      Make sure we do a full frame for each movie
73      DISABLE_DITHER #ifdef to avoid compiling dithering code
74      Changes to deal with non-MPEG streams
75      Now deals with NO_DITHER, PPM_DITHER and noDisplayFlag==1
76      CONTROLS version now can deal with >1 movie
77    -lsh@cs.brown.edu (Loring Holden)
78  */
79 
80 /* Make Ordered be the default dither */
81 #define DEFAULT_ORDERED_DITHER
82 
83 /* Define buffer length. */
84 #define BUF_LENGTH 80000
85 
86 /* Function return type declarations */
87 void usage();
88 
89 /* Forward declaration of functions in this file. */
90 #ifndef P
91 # ifdef __STDC__
92 #   define        P(s) s
93 # else
94 #   define P(s) ()
95 # endif
96 #endif
97 
98 #ifndef SIG_ONE_PARAM
99 void int_handler P((void ));
100 void bad_handler P((void ));
101 #else
102 void int_handler P((int signum));
103 void bad_handler P((int signum));
104 #endif
105 void usage P((char *s ));
106 
107 #ifdef DCPREC
108 /* Declaration of global variable to hold DC precision */
109 int dcprec = 0;
110 #endif
111 
112 /* Global file pointer to incoming data. */
113 FILE **input;
114 char **inputName;
115 
116 /* Loop flag. */
117 int loopFlag = 0;
118 
119 /* Shared memory flag. */
120 int shmemFlag = 0;
121 
122 /* Quiet flag. */
123 #ifdef QUIET
124 int quietFlag = 1;
125 #else
126 int quietFlag = 0;
127 #endif
128 
129 /* "Press return" flag, requires return for each new frame */
130 int requireKeypressFlag = 0;
131 
132 /* Display image on screen? */
133 int noDisplayFlag = 0;
134 
135 /* Seek Value.
136    0 means do not seek.
137    N (N>0) means seek to N after the header is parsed
138    N (N<0) means the seek has beeen done to offset N
139 */
140 
141 /* Framerate, -1: specified in stream (default)
142                0: as fast as possible
143                N (N>0): N frames/sec
144                */
145 int framerate = -1;
146 
147 /* Flags/values to control Arbitrary start/stop frames. */
148 int partialFlag = 0, startFrame = -1, endFrame = -1;
149 
150 /* Flag for gamma correction */
151 int gammaCorrectFlag = 0;
152 double gammaCorrect = 1.0;
153 
154 /* Flag for chroma correction */
155 int chromaCorrectFlag = 0;
156 double chromaCorrect = 1.0;
157 
158 /* Flag for high quality at the expense of speed */
159 #ifdef QUALITY
160 int qualityFlag = 1;
161 #else
162 int qualityFlag = 0;
163 #endif
164 
165 /* no further error messages */
166 static BOOLEAN exiting=FALSE;
167 
168 /* global variable for interrupt handlers */
169 VidStream **curVidStream;
170 
171 /* Brown - put X specific variables in xinfo struct */
172 #define NUMMOVIES 15
173 XInfo xinfo[NUMMOVIES];
174 int numInput=0;
175 
176 /*
177  #define Color16DitherImage ColorDitherImage
178  #define Color32DitherImage ColorDitherImage
179 */
180 
181 /*
182  *--------------------------------------------------------------
183  *
184  * int_handler --
185  *
186  *        Handles Cntl-C interupts..
187  *      (two different ones for different OSes)
188  * Results:    None.
189  * Side effects:   None.
190  *--------------------------------------------------------------
191  */
192 #ifndef SIG_ONE_PARAM
193 void
int_handler()194 int_handler()
195 #else
196 void
197 int_handler(signum)
198 int signum;
199 #endif
200 {
201   int i,displayClosed=0;
202 
203   if (!quietFlag && !exiting) {
204     fprintf(stderr, "Interrupted!\n");
205   }
206   exiting = TRUE;
207   for (i = 0;  i < numInput;  i++) {
208     if (curVidStream[i] != NULL)
209       DestroyVidStream(curVidStream[i], &xinfo[i]);
210     if ((xinfo[i].display != NULL) && !displayClosed) {
211       XCloseDisplay(xinfo[i].display);
212       displayClosed=1;
213     }
214   }
215   exit(1);
216 }
217 
218 
219 /*
220  *--------------------------------------------------------------
221  *
222  * bad_handler --
223  *
224  *        Handles Seg faults/bus errors...
225  *      (two different ones for different OSes)
226  * Results:    None.
227  * Side effects:   None.
228  *
229  *--------------------------------------------------------------
230  */
231 
232 #ifndef SIG_ONE_PARAM
233 void
bad_handler()234   bad_handler()
235 #else
236 void
237   bad_handler(signum)
238 int signum;
239 #endif
240 {
241   if (!exiting) {
242     fprintf(stderr, "Bad MPEG?  Giving up.\ntry 'mpeg_stat -verify' to see if the stream is valid.\n");
243   }
244   exit(0);
245 }
246 
247 
248 /*
249  *--------------------------------------------------------------
250  *
251  * getposition --
252  *
253  *--------------------------------------------------------------
254  */
getposition(arg,xpos,ypos)255 void getposition(arg, xpos, ypos)
256 char *arg;
257 int *xpos, *ypos;
258 {
259   char *pos;
260 
261   if ((pos = strtok(arg, "+-")) != NULL) {
262     *xpos = atoi(pos);
263     if ((pos = strtok(NULL, "+-")) != NULL) {
264       *ypos = atoi(pos);
265       return;
266     }
267   }
268   if (!quietFlag) {
269     fprintf(stderr, "Illegal position... Warning: argument ignored! (-position +x+y)\n");
270   }
271   return;
272 }
273 
274 
275 /*
276  *--------------------------------------------------------------
277  *
278  * main --
279  *
280  *        Parses command line, starts decoding and displaying.
281  *
282  * Results:
283  *        None.
284  *
285  * Side effects:
286  *        None.
287  *
288  *--------------------------------------------------------------
289  */
290 
291 #ifndef __STDC__
292 void
293 #endif
main(argc,argv)294 main(argc, argv)
295      int argc;
296      char **argv;
297 {
298 
299   char *name;
300   static VidStream **theStream;
301   int mark;
302   int i, mult, largy, y, lastStream, firstStream=-1, workToDo=TRUE;
303   int doDisplay=0; /* Current movie is displaying on screen */
304   long seekValue=0;/* holds value before it is put in vid_stream */
305   int  owncmFlag=0;   /* holds value before it is put in xinfo  */
306   BOOLEAN firstRead=FALSE;
307   int ppm_width = -1,  ppm_height = -1, ppm_modulus = -1;
308 
309   mark = 1;
310   argc--;
311 
312   input = (FILE **) malloc(NUMMOVIES*sizeof(FILE *));
313   inputName = (char **) malloc(NUMMOVIES *sizeof(char *));
314   theStream = (VidStream **) malloc(NUMMOVIES *sizeof(VidStream *));
315   curVidStream = (VidStream **) malloc(NUMMOVIES *sizeof(VidStream *));
316   for (i = 0; i < NUMMOVIES; i++) {
317      input[i] = NULL;
318      inputName[i] = "stdin";
319      theStream[i] = NULL;
320      curVidStream[i] = NULL;
321      xinfo[i].hints.x = -1;
322      xinfo[i].hints.y = -1;
323      xinfo[i].ExistingWindow = 0;
324   }
325   name = (char *) "";
326 
327 #ifndef DISABLE_DITHER
328 #ifndef DEFAULT_ORDERED_DITHER
329   xinfo[0].ditherType = FULL_COLOR_DITHER;
330 #else
331   xinfo[0].ditherType = ORDERED_DITHER;
332 #endif
333 #endif
334 
335   LUM_RANGE = 8;
336   CR_RANGE = CB_RANGE = 4;
337   noDisplayFlag = 0;
338 
339 #ifdef SH_MEM
340   shmemFlag = 1;
341 #endif
342 
343   while (argc) {
344     if (strcmp(argv[mark], "-nop") == 0) {
345       SetPFlag(TRUE);
346       SetBFlag(TRUE);
347       argc--; mark++;
348     } else if (strcmp(argv[mark], "-nob") == 0) {
349       SetBFlag(TRUE);
350       argc--; mark++;
351     } else if (strcmp(argv[mark], "-display") == 0) {
352       name = argv[++mark];
353       argc -= 2; mark++;
354     } else if (strcmp(argv[mark], "-position") == 0) {
355       argc--; mark++;
356       getposition(argv[mark], &xinfo[numInput].hints.x, &xinfo[numInput].hints.y);
357       argc--; mark++;
358     } else if (strcmp(argv[mark], "-xid") == 0) {
359       xinfo[numInput].ExistingWindow = atoi(argv[++mark]);
360       argc -= 2; mark++;
361     } else if (strcmp(argv[mark], "-start") == 0) {
362       if (argc < 2) usage(argv[0]);
363       partialFlag = TRUE;
364       if (seekValue != 0) {
365 	fprintf(stderr, "Cannot use -start with -seek (ignored)\n");
366       } else {
367 	startFrame = atoi(argv[++mark]);
368       }
369       argc -= 2; mark++;
370     } else if (strcmp(argv[mark], "-seek") == 0) {
371       if (argc < 2) usage(argv[0]);
372       seekValue = atoi(argv[++mark]);
373       if (startFrame != -1) startFrame = 0;
374       argc -= 2; mark++;
375     } else if (strcmp(argv[mark], "-end") == 0) {
376       if (argc < 2) usage(argv[0]);
377       endFrame = atoi(argv[++mark]);
378       partialFlag = TRUE;
379       argc -= 2; mark++;
380     } else if (strcmp(argv[mark], "-gamma") == 0) {
381       if (argc < 2) usage(argv[0]);
382       gammaCorrectFlag = 1;
383       sscanf(argv[++mark], "%lf", &gammaCorrect);
384       if (gammaCorrect <= 0.0) {
385         fprintf(stderr, "ERROR: Gamma correction must be greater than 0.\n");
386         gammaCorrect = 1.0;
387       }
388       if (!quietFlag) {
389         printf("Gamma Correction set to %4.2f.\n", gammaCorrect);
390       }
391       argc -= 2; mark++;
392     } else if (strcmp(argv[mark], "-chroma") == 0) {
393       if (argc < 2) usage(argv[0]);
394       chromaCorrectFlag = 1;
395       sscanf(argv[++mark], "%lf", &chromaCorrect);
396       if (chromaCorrect <= 0.0) {
397         fprintf(stderr, "ERROR: Chroma correction must be greater than 0.\n");
398         chromaCorrect = 1.0;
399       }
400       if (!quietFlag) {
401         printf("Chroma Correction set to %4.2f.\n",chromaCorrect);
402       }
403       argc -= 2; mark++;
404 #ifdef DCPREC
405     } else if (strcmp(argv[mark], "-dc") == 0) {
406       argc--; mark++;
407       if (argc < 1) {
408         perror("Must specify dc precision after -dc flag");
409         usage(argv[0]);
410       }
411       dcprec = atoi(argv[mark]) - 8;
412       if ((dcprec > 3) || (dcprec < 0)) {
413         perror("DC precision must be at least 8 and at most 11");
414         usage(argv[0]);
415       }
416       argc--; mark++;
417 #endif
418     } else if (strcmp(argv[mark], "-quality") == 0) {
419       argc--; mark++;
420       if (argc < 1) {
421         perror("Must specify on or off after -quality flag");
422         usage(argv[0]);
423       }
424       if (strcmp(argv[mark], "on") == 0) {
425         argc--; mark++;
426         qualityFlag = 1;
427       }
428       else if (strcmp(argv[mark], "off") == 0) {
429         argc--; mark++;
430         qualityFlag = 0;
431       }
432       else {
433         perror("Must specify on or off after -quality flag");
434         usage(argv[0]);
435       }
436     } else if (strcmp(argv[mark], "-framerate") == 0) {
437       argc--; mark++;
438       if (argc < 1) {
439         perror("Must specify framerate after -framerate flag");
440         usage(argv[0]);
441       }
442       framerate = atoi(argv[mark]);
443       argc--; mark++;
444     } else if (strcmp(argv[mark], "-ppmwidth") == 0) {
445       argc--; mark++;
446       if (argc < 1) {
447 	perror("Must specify PPM file width after -ppmwidth flag");
448 	usage(argv[0]);
449       }
450       ppm_width = atoi(argv[mark]);
451       argc--; mark++;
452     } else if (strcmp(argv[mark], "-ppmheight") == 0) {
453       argc--; mark++;
454       if (argc < 1) {
455 	perror("Must specify PPM file height after -ppmheight flag");
456 	usage(argv[0]);
457       }
458       ppm_height = atoi(argv[mark]);
459       argc--; mark++;
460     } else if (strcmp(argv[mark], "-ppmskip") == 0) {
461       argc--; mark++;
462       if (argc < 1) {
463 	perror("Must specify PPM file height after -ppmheight flag");
464 	usage(argv[0]);
465       }
466       ppm_modulus = atoi(argv[mark]);
467       argc--; mark++;
468 #ifndef DISABLE_DITHER
469     } else if (strcmp(argv[mark], "-dither") == 0) {
470       argc--; mark++;
471       if (argc < 1) {
472         perror("Must specify dither option after -dither flag");
473         usage(argv[0]);
474       }
475       if (strcmp(argv[mark], "hybrid") == 0) {
476         argc--; mark++;
477         xinfo[0].ditherType = HYBRID_DITHER;
478       } else if (strcmp(argv[mark], "hybrid2") == 0) {
479         argc--; mark++;
480         xinfo[0].ditherType = HYBRID2_DITHER;
481       } else if (strcmp(argv[mark], "fs4") == 0) {
482         argc--; mark++;
483         xinfo[0].ditherType = FS4_DITHER;
484       } else if (strcmp(argv[mark], "fs2") == 0) {
485         argc--; mark++;
486         xinfo[0].ditherType = FS2_DITHER;
487       } else if (strcmp(argv[mark], "fs2fast") == 0) {
488         argc--; mark++;
489         xinfo[0].ditherType = FS2FAST_DITHER;
490       } else if (strcmp(argv[mark], "hybrid2") == 0) {
491         argc--; mark++;
492         xinfo[0].ditherType = HYBRID2_DITHER;
493       } else if (strcmp(argv[mark], "2x2") == 0) {
494         argc--; mark++;
495         xinfo[0].ditherType = Twox2_DITHER;
496       } else if ((strcmp(argv[mark], "gray256") == 0) ||
497                  (strcmp(argv[mark], "grey256") == 0)) {
498         argc--; mark++;
499         xinfo[0].ditherType = GRAY256_DITHER;
500       } else if ((strcmp(argv[mark], "gray") == 0) ||
501                  (strcmp(argv[mark], "grey") == 0)) {
502         argc--; mark++;
503         xinfo[0].ditherType = GRAY_DITHER;
504       } else if ((strcmp(argv[mark], "gray256x2") == 0) ||
505                   (strcmp(argv[mark], "grey256x2") == 0)) {
506         argc--; mark++;
507         xinfo[0].ditherType = GRAY2562_DITHER;
508       } else if ((strcmp(argv[mark], "gray") == 0) ||
509                    (strcmp(argv[mark], "grey") == 0)) {
510         argc--; mark++;
511         xinfo[0].ditherType = GRAY_DITHER;
512       } else if ((strcmp(argv[mark], "gray2") == 0) ||
513                   (strcmp(argv[mark], "grey2") == 0)) {
514         argc--; mark++;
515         xinfo[0].ditherType = GRAY2_DITHER;
516       } else if (strcmp(argv[mark], "color") == 0 ||
517                  strcmp(argv[mark], "colour") == 0) {
518         argc--; mark++;
519         xinfo[0].ditherType = FULL_COLOR_DITHER;
520       } else if (strcmp(argv[mark], "color2") == 0 ||
521                  strcmp(argv[mark], "colour2") == 0) {
522         argc--; mark++;
523         xinfo[0].ditherType = FULL_COLOR2_DITHER;
524       } else if (strcmp(argv[mark], "none") == 0) {
525         argc--; mark++;
526         xinfo[0].ditherType = NO_DITHER;
527       } else if (strcmp(argv[mark], "ppm") == 0) {
528         argc--; mark++;
529         xinfo[0].ditherType = PPM_DITHER;
530       } else if (strcmp(argv[mark], "ordered") == 0) {
531         argc--; mark++;
532         xinfo[0].ditherType = ORDERED_DITHER;
533       } else if (strcmp(argv[mark], "ordered2") == 0) {
534         argc--; mark++;
535         xinfo[0].ditherType = ORDERED2_DITHER;
536       } else if (strcmp(argv[mark], "mbordered") == 0) {
537         argc--; mark++;
538         xinfo[0].ditherType = MBORDERED_DITHER;
539       } else if (strcmp(argv[mark], "mono") == 0) {
540         argc--; mark++;
541         xinfo[0].ditherType = MONO_DITHER;
542       } else if (strcmp(argv[mark], "threshold") == 0) {
543         argc--; mark++;
544         xinfo[0].ditherType = MONO_THRESHOLD;
545       } else {
546         perror("Illegal dither option.");
547         usage(argv[0]);
548       }
549 #endif
550     }
551     else if (strcmp(argv[mark], "-eachstat") == 0) {
552       argc--; mark++;
553 #ifdef ANALYSIS
554       showEachFlag = 1;
555 #else
556       fprintf(stderr, "To use -eachstat, recompile with -DANALYSIS in CFLAGS\n");
557       exit(1);
558 #endif
559     }
560     else if (strcmp(argv[mark], "-shmem_off") == 0) {
561       argc--; mark++;
562       shmemFlag = 0;
563     }
564 #ifdef QUIET
565     else if (strcmp(argv[mark], "-quiet") == 0) {
566       argc--; mark++;
567     }
568     else if (strcmp(argv[mark], "-noisy") == 0) {
569 #else
570     else if (strcmp(argv[mark], "-noisy") == 0) {
571       argc--; mark++;
572     }
573     else if (strcmp(argv[mark], "-quiet") == 0) {
574 #endif
575       argc--; mark++;
576       quietFlag = !quietFlag;
577     }
578     else if (strcmp(argv[mark], "-owncm") == 0) {
579       argc--; mark++;
580       owncmFlag = 1;
581     }
582     else if (strcmp(argv[mark], "-step") == 0) {
583       argc--; mark++;
584       requireKeypressFlag = 1;
585     }
586     else if (strcmp(argv[mark], "-loop") == 0) {
587       argc--; mark++;
588       loopFlag = 1;
589     }
590     else if (strcmp(argv[mark], "-no_display") == 0) {
591       argc--; mark++;
592       noDisplayFlag = 1;
593       shmemFlag = 0;
594     }
595     else if (strcmp(argv[mark], "-l_range") == 0) {
596       argc--; mark++;
597       LUM_RANGE = atoi(argv[mark]);
598       if (LUM_RANGE < 1) {
599         fprintf(stderr, "Illegal luminance range value: %d\n", LUM_RANGE);
600         exit(1);
601       }
602       argc--; mark++;
603     }
604     else if (strcmp(argv[mark], "-cr_range") == 0) {
605       argc--; mark++;
606       CR_RANGE = atoi(argv[mark]);
607       if (CR_RANGE < 1) {
608         fprintf(stderr, "Illegal cr range value: %d\n", CR_RANGE);
609         exit(1);
610       }
611       argc--; mark++;
612     }
613     else if (strcmp(argv[mark], "-cb_range") == 0) {
614       argc--; mark++;
615       CB_RANGE = atoi(argv[mark]);
616       if (CB_RANGE < 1) {
617         fprintf(stderr, "Illegal cb range value: %d\n", CB_RANGE);
618         exit(1);
619       }
620       argc--; mark++;
621     }
622 #ifndef NOCONTROLS
623     else if (strcmp(argv[mark], "-controls") == 0 ||
624 	     strcmp(argv[mark], "-controlbar") == 0 ||
625 	     strcmp(argv[mark], "-control_bar") == 0) {
626       argc--; mark++;
627       if (argc < 1) {
628         perror("Must specify on, off, or none after -controls flag");
629         usage(argv[0]);
630       }
631       if (strcmp(argv[mark], "on") == 0) {
632         argc--; mark++;
633         ControlShow = CTRLBAR_ON;
634       }
635       else if (strcmp(argv[mark], "off") == 0) {
636         argc--; mark++;
637         ControlShow = CTRLBAR_OFF;
638       }
639       else if (strcmp(argv[mark], "none") == 0) {
640         argc--; mark++;
641         ControlShow = CTRLBAR_NONE;
642       }
643       else {
644         perror("Must specify on, off, or none after -controls flag");
645         usage(argv[0]);
646       }
647     }
648 #endif /* !NOCONTROLS */
649     else if ((strcmp(argv[mark], "-?") == 0) ||
650                (strcmp(argv[mark], "-Help") == 0) ||
651                (strcmp(argv[mark], "-help") == 0)) {
652       usage(argv[0]);
653     }
654     else if (argv[mark][0] == '-' && argv[mark][1]==0) {
655       fflush(stdout);
656       if (numInput<NUMMOVIES) {
657         input[numInput]=stdin;
658         inputName[numInput++] = "stdin";
659       } else {
660           fprintf(stderr, "Can't load file %s - too many\n", "stdin");
661       }
662       argc--; mark++;
663     }
664     else if (argv[mark][0] == '-') {
665       fprintf(stderr, "Un-recognized flag %s\n",argv[mark]);
666       usage(argv[0]);
667     }
668     else {
669       fflush(stdout);
670       if (numInput<NUMMOVIES) {
671         input[numInput]=fopen(argv[mark], "r");
672         if (input[numInput] == NULL) {
673           fprintf(stderr, "Could not open file %s\n", argv[mark]);
674           usage(argv[0]);
675         }
676         inputName[numInput++] = argv[mark];
677       } else {
678           fprintf(stderr, "Can't load file %s - too many\n", argv[mark]);
679       }
680       argc--; mark++;
681     }
682   }
683 
684   lum_values = (int *) malloc(LUM_RANGE*sizeof(int));
685   cr_values = (int *) malloc(CR_RANGE*sizeof(int));
686   cb_values = (int *) malloc(CB_RANGE*sizeof(int));
687 
688   signal(SIGINT, int_handler);
689 #ifndef DEBUG
690   signal(SIGSEGV, bad_handler);
691   signal(SIGBUS,  bad_handler);
692 #endif
693   if ((startFrame != -1) && (endFrame != -1) &&
694       (endFrame < startFrame)) {
695     usage(argv[0]);
696   }
697 
698   init_tables();
699   for (i = 0;  i < numInput;  i++) {
700     xinfo[i].owncmFlag = owncmFlag;
701     xinfo[i].display = NULL;       /* xinfo.ximage is set to null later */
702     if (xinfo[i].hints.x == -1) {
703       xinfo[i].hints.x = 200;
704       xinfo[i].hints.y = 300;
705     }
706     xinfo[i].hints.width = 150;
707     xinfo[i].hints.height = 150;
708     xinfo[i].visual = NULL;
709     xinfo[i].name = inputName[i];
710     xinfo[i].cmap = 0;
711     xinfo[i].gc = 0;
712   }
713 
714 #ifndef DISABLE_DITHER
715   if (xinfo[0].ditherType == MONO_DITHER ||
716       xinfo[0].ditherType == MONO_THRESHOLD)
717     xinfo[0].depth= 1;
718 
719   switch (xinfo[0].ditherType) {
720 
721   case HYBRID_DITHER:
722     InitColor();
723     InitHybridDither();
724     InitDisplay(name, &xinfo[0]);
725     break;
726 
727   case HYBRID2_DITHER:
728     InitColor();
729     InitHybridErrorDither();
730     InitDisplay(name, &xinfo[0]);
731     break;
732 
733   case FS4_DITHER:
734     InitColor();
735     InitFS4Dither();
736       InitDisplay(name, &xinfo[0]);
737     break;
738 
739   case FS2_DITHER:
740     InitColor();
741     InitFS2Dither();
742     InitDisplay(name, &xinfo[0]);
743     break;
744 
745   case FS2FAST_DITHER:
746     InitColor();
747     InitFS2FastDither();
748     InitDisplay(name, &xinfo[0]);
749     break;
750 
751   case Twox2_DITHER:
752     InitColor();
753     Init2x2Dither();
754     InitDisplay(name, &xinfo[0]);
755     PostInit2x2Dither();
756     break;
757 
758   case GRAY_DITHER:
759   case GRAY2_DITHER:
760     InitGrayDisplay(name, &xinfo[0]);
761     break;
762 
763   case GRAY256_DITHER:
764   case GRAY2562_DITHER:
765     InitGray256Display(name, &xinfo[0]);
766     break;
767 
768   case FULL_COLOR_DITHER:
769   case FULL_COLOR2_DITHER:
770     InitColorDisplay(name, &xinfo[0]);
771     InitColorDither(xinfo[0].depth>=24);
772 #else
773     InitColorDisplay(name, &xinfo[0]);
774     InitColorDither(xinfo[0].depth>=24);
775 #endif
776 #ifndef DISABLE_DITHER
777     break;
778 
779   case NO_DITHER:
780     shmemFlag = 0;
781     break;
782 
783   case PPM_DITHER:
784     shmemFlag = 0;
785     wpixel[0] = 0xff;
786     wpixel[1] = 0xff00;
787     wpixel[2] = 0xff0000;
788     xinfo[0].depth = 24;
789     InitColorDither(1);
790     break;
791 
792   case ORDERED_DITHER:
793     InitColor();
794     InitOrderedDither();
795     InitDisplay(name, &xinfo[0]);
796     break;
797 
798   case MONO_DITHER:
799   case MONO_THRESHOLD:
800     InitMonoDisplay(name, &xinfo[0]);
801     break;
802 
803   case ORDERED2_DITHER:
804     InitColor();
805     InitDisplay(name, &xinfo[0]);
806     InitOrdered2Dither();
807     break;
808 
809   case MBORDERED_DITHER:
810     InitColor();
811     InitDisplay(name, &xinfo[0]);
812     InitMBOrderedDither();
813     break;
814   }
815 #endif
816 
817 #ifdef SH_MEM
818     if (shmemFlag && (xinfo[0].display != NULL)) {
819       if (!XShmQueryExtension(xinfo[0].display)) {
820         shmemFlag = 0;
821         if (!quietFlag) {
822           fprintf(stderr, "Shared memory not supported\n");
823           fprintf(stderr, "Reverting to normal Xlib.\n");
824         }
825       }
826     }
827 #endif
828 
829   InitCrop();
830 
831   y=300;
832   largy=0;
833   for (i=0;i<numInput;i++) {
834     doDisplay=!noDisplayFlag;
835 #ifndef DISABLE_DITHER
836     if ((xinfo[i].ditherType == NO_DITHER) ||
837         (xinfo[i].ditherType == PPM_DITHER))
838        doDisplay = FALSE;
839 #endif
840     lastStream = i-1;
841     while ((lastStream>=0) && (theStream[lastStream]==NULL)) {
842        lastStream--;
843     }
844     if ((i != 0) && doDisplay) {
845        if (lastStream > -1) {
846          xinfo[i].hints.x =
847             xinfo[lastStream].hints.x+10 + theStream[lastStream]->h_size;
848          if (theStream[lastStream]->v_size>largy)
849 	   largy = theStream[lastStream]->v_size;
850          if (xinfo[i].hints.x > DisplayWidth(xinfo[firstStream].display,
851 			       XDefaultScreen(xinfo[firstStream].display)) -80) {
852 
853 		y += largy + 30;
854 		largy = 0;
855 		xinfo[i].hints.x = 0;
856          }
857          xinfo[i].hints.y = y;
858          xinfo[i].visual = xinfo[firstStream].visual;
859          xinfo[i].cmap = xinfo[firstStream].cmap;
860          xinfo[i].gc = xinfo[firstStream].gc;
861        }
862        xinfo[i].display = xinfo[0].display;
863        xinfo[i].depth = xinfo[0].depth;
864        xinfo[i].ditherType = xinfo[0].ditherType;
865        InitColorDisplay(name, &xinfo[i]);
866     }
867     curVidStream[i] = theStream[i] = NewVidStream((unsigned int) BUF_LENGTH);
868     theStream[i]->ppm_width = ppm_width;
869     theStream[i]->ppm_height = ppm_height;
870     theStream[i]->ppm_modulus = ppm_modulus;
871     theStream[i]->input = input[i];
872     theStream[i]->seekValue = seekValue;
873     theStream[i]->filename = inputName[i];
874     theStream[i]->ditherType = xinfo[i].ditherType;
875     theStream[i]->matched_depth = xinfo[i].depth;
876     mark = quietFlag;
877     quietFlag=1;
878     if (mpegVidRsrc(0, theStream[i], 1, &xinfo[i])==NULL) {
879        if (doDisplay) {
880          XDestroyWindow(xinfo[i].display, xinfo[i].window);
881        }
882        /* stream has already been destroyed */
883        curVidStream[i] = theStream[i]=NULL;
884        fprintf(stderr, "Skipping movie %d, \"%s\" - not an MPEG stream\n",
885 	  i, inputName[i]);
886        fclose(input[i]);
887        if (i+1 == numInput) numInput--;
888     } else if (firstStream == -1) firstStream=i;
889     quietFlag = mark;
890 
891 #ifndef DISABLE_DITHER
892     if (IS_2x2_DITHER(xinfo[i].ditherType)) {
893       mult = 2;
894     }
895     else {
896       mult = 1;
897     }
898 #else
899     mult = 1;
900 #endif
901 
902     if (doDisplay && (theStream[i]!=NULL)) {
903       ResizeDisplay((unsigned int) theStream[i]->h_size* mult,
904                     (unsigned int) theStream[i]->v_size* mult,
905 		  &xinfo[i]);
906     }
907   }
908 
909   if (numInput > 1) {
910     loopFlag = TRUE;
911     framerate = 0;
912   }
913 
914 #ifndef NOCONTROLS
915   if (xinfo[0].display == NULL) {
916     ControlShow = CTRLBAR_NONE;  /* no display => no controls */
917   }
918 
919   if (ControlShow != CTRLBAR_NONE) {
920     MakeControlBar(&xinfo[0]);
921     ControlBar(theStream, xinfo, numInput);
922   }
923   for (i = 0; i < numInput; i++) {
924      if (theStream[i] != NULL) theStream[i]->realTimeStart = ReadSysClock();
925   }
926 #else
927   /* Start time for each movie - do after windows are mapped */
928   for (i = 0; i < numInput; i++) {
929      if (theStream[i] != NULL) theStream[i]->realTimeStart = ReadSysClock();
930   }
931 #endif
932 
933 
934 #ifndef NOCONTROLS
935   if (ControlShow == CTRLBAR_NONE) {
936     while (TRUE) {
937       for (i=0;i < numInput; i++) {
938         while (theStream[i]->film_has_ended != TRUE) {
939           mpegVidRsrc(0, theStream[i], 0, &xinfo[i]);
940         }
941         if (loopFlag) {
942           rewind(theStream[i]->input);
943           ResetVidStream(theStream[i]); /* Reinitialize vid_stream pointers */
944           if (theStream[i]->seekValue < 0) {
945             theStream[i]->seekValue = 0 - theStream[i]->seekValue;
946           }
947           mpegVidRsrc(0, theStream[i], 1, &xinfo[i]); /* Process start codes */
948         } else if (doDisplay) break;
949         else goto done;
950       }
951      }
952    }
953   else {
954     ControlLoop(theStream, xinfo, numInput);
955   }
956 
957 done:
958   mark=0;
959   for (i=0;i < numInput; i++) {
960     DestroyVidStream(theStream[i], &xinfo[i]);
961     if ((xinfo[i].display != NULL) && !mark) {
962       XCloseDisplay(xinfo[i].display);
963       mark=1;
964     }
965   }
966   exit(0);
967 #else /* !NOCONTROLS */
968   if (!numInput) {
969      fprintf(stderr, "Must enter MPEG file to play\n");
970      usage(argv[0]);
971   }
972   while (workToDo) {
973      workToDo = FALSE;
974      for (i = 0; i < numInput; i++) {
975        if (theStream[i] != NULL) {
976          mark = theStream[i]->totNumFrames;
977          /* make sure we do a whole frame */
978          while (mark == theStream[i]->totNumFrames) {
979              mpegVidRsrc(0, theStream[i], 0, &xinfo[i]);
980          }
981          if (theStream[i]->film_has_ended) {
982            if (loopFlag) {
983              clear_data_stream(theStream[i]);
984              /* Reinitialize vid_stream pointers */
985              ResetVidStream(theStream[i]);
986              rewind(theStream[i]->input);
987              if (theStream[i]->seekValue < 0) {
988                theStream[i]->seekValue = 0 - theStream[i]->seekValue;
989              }
990 #ifdef ANALYSIS
991              init_stats();
992 #endif
993              /* Process start codes */
994              if (mpegVidRsrc(0, theStream[i], 1, &xinfo[i])==NULL) {
995 	       /* print something sensible here,
996 		  but we only get here if the file is changed while we
997 		  are decoding, right?
998 		*/
999 	     }
1000            } /* loopFlag */
1001 	 }   /* film_has_ended */
1002          workToDo = workToDo || (!theStream[i]->film_has_ended);
1003        } /* theStream[i]!=NULL */
1004      }   /* for (i.. */
1005   }      /* while workToDo */
1006   sleep(1000);
1007     /* freeze on the last frame */
1008 #endif /* NOCONTROLS */
1009 }
1010 
1011 
1012 /*
1013  *--------------------------------------------------------------
1014  *
1015  * usage --
1016  *
1017  *        Print mpeg_play usage
1018  *
1019  * Results:
1020  *        None.
1021  *
1022  * Side effects:
1023  *        exits with a return value -1
1024  *
1025  *--------------------------------------------------------------
1026  */
1027 
1028 void
usage(s)1029 usage(s)
1030 char *s;        /* program name */
1031 {
1032     fprintf(stderr, "Usage:\n");
1033 #ifndef NOCONTROLS
1034     fprintf(stderr, "mpeg_play [options] [filename]\n");
1035 #else
1036     fprintf(stderr, "mpeg_play [[options] [filename]]  [[options] [filename]]  [..]\n");
1037 #endif
1038     fprintf(stderr, "Options :\n");
1039    fprintf(stderr, "      [-display X_display]\t[-no_display]\n");
1040 #ifndef DISABLE_DITHER
1041     fprintf(stderr, "      [-dither {ordered|ordered2|mbordered|fs4|fs2|fs2fast|hybrid|\n");
1042     fprintf(stderr, "                hybrid2|2x2|gray|gray256|color|color2|none|mono|threshold|ppm|\n");
1043     fprintf(stderr, "                gray2|gray256x2}]\n");
1044 #endif
1045     fprintf(stderr, "      [-loop]\n");
1046     fprintf(stderr, "      [-start frame_num]\t[-end frame_num]\t[-seek file_offset]\n");
1047     fprintf(stderr, "      [-gamma gamma_correction_value]\t[-chroma chroma_correction_value]\n");
1048     fprintf(stderr, "      [-framerate num_frames_per_sec]  (0 means as fast as possible)\n");
1049     fprintf(stderr, "      [-position +x+y]\t[-quality {on|off}] (compiled default is ");
1050 #ifdef QUALITY
1051     fprintf(stderr, "ON)\n");
1052 #else
1053     fprintf(stderr, "OFF)\n");
1054 #endif
1055 #ifdef QUIET
1056     fprintf(stderr, "      [-noisy] (turns on all program output)\n");
1057 #else
1058     fprintf(stderr, "      [-quiet] (turns off all program output)\n");
1059 #endif
1060 #ifndef NOCONTROLS
1061     fprintf(stderr, "      [-controls {on|off|none}] (default is on)\n");
1062 #endif
1063     fprintf(stderr, "      [-?]\t[-help] for help (this message)\n");
1064     fprintf(stderr, "Rare options:\n");
1065     fprintf(stderr, "      [-nob]\t[-nop]\n");
1066 #ifdef ANALYSIS
1067     fprintf(stderr, "      [-eachstat]\t[-owncm]\t[-shmem_off]\n");
1068 #else
1069     fprintf(stderr, "      [-owncm]\t[-shmem_off]\n");
1070 #endif
1071     fprintf(stderr, "      [-l_range num]\t[-cr_range num]\t[-cb_range num]\n");
1072 /*    fprintf(stderr, "      [-xid xid]\n"); */
1073 #ifdef DCPREC
1074     fprintf(stderr, "      [-dc {8|9|10|11}] (defaults to 8)\n");
1075 #endif
1076     fprintf(stderr, "      with -dither ppm:\n");
1077     fprintf(stderr, "          [-ppmwidth num]\t[-ppmheight num]\t[-ppmskip num]\n");
1078     exit (-1);
1079 }
1080 
1081 
1082 
1083 /*
1084  *--------------------------------------------------------------
1085  *
1086  * DoDitherImage --
1087  *
1088  *      Called when image needs to be dithered. Selects correct
1089  *      dither routine based on info in xinfo[0].ditherType.
1090  *
1091  * Results:
1092  *        None.
1093  *
1094  * Side effects:
1095  *        None.
1096  *
1097  *--------------------------------------------------------------
1098  */
1099 
1100 void
DoDitherImage(vid_stream)1101 DoDitherImage(vid_stream)
1102 VidStream *vid_stream;
1103 {
1104  unsigned char *l=vid_stream->current->luminance,
1105                *Cr=vid_stream->current->Cr,
1106                *Cb=vid_stream->current->Cb,
1107                *disp=vid_stream->current->display;
1108  int h=(int) vid_stream->mb_height * 16;
1109  int w=(int) vid_stream->mb_width * 16;
1110  int ditherType=vid_stream->ditherType;
1111  int matched_depth=vid_stream->matched_depth;
1112 
1113 #ifndef DISABLE_DITHER
1114   switch(ditherType) {
1115   case HYBRID_DITHER:
1116     HybridDitherImage(l, Cr, Cb, disp, h, w);
1117     break;
1118 
1119   case HYBRID2_DITHER:
1120     HybridErrorDitherImage(l, Cr, Cb, disp, h, w);
1121     break;
1122 
1123   case FS2FAST_DITHER:
1124     FS2FastDitherImage(l, Cr, Cb, disp, h, w);
1125     break;
1126 
1127   case FS2_DITHER:
1128     FS2DitherImage(l, Cr, Cb, disp, h, w);
1129     break;
1130 
1131   case FS4_DITHER:
1132     FS4DitherImage(l, Cr, Cb, disp, h, w);
1133     break;
1134 
1135   case Twox2_DITHER:
1136     Twox2DitherImage(l, Cr, Cb, disp, h, w);
1137     break;
1138 
1139   case FULL_COLOR2_DITHER:
1140     if (matched_depth >= 24)
1141       Twox2Color32DitherImage(l, Cr, Cb, disp, h, w);
1142     else
1143       Twox2Color16DitherImage(l, Cr, Cb, disp, h, w);
1144     break;
1145   case FULL_COLOR_DITHER:
1146     if (matched_depth >= 24)
1147 #endif
1148 
1149       Color32DitherImage(l, Cr, Cb, disp, h, w);
1150 
1151 #ifndef DISABLE_DITHER
1152     else
1153       Color16DitherImage(l, Cr, Cb, disp, h, w);
1154     break;
1155 
1156   case GRAY_DITHER:
1157   case GRAY256_DITHER:
1158     if (matched_depth == 8)
1159       GrayDitherImage(l, Cr, Cb, disp, h, w);
1160     else if (matched_depth == 16)
1161       Gray16DitherImage(l, Cr, Cb, disp, h, w);
1162     else if (matched_depth == 32 || matched_depth == 24)
1163       Gray32DitherImage(l, Cr, Cb, disp, h, w);
1164     break;
1165 
1166   case GRAY2_DITHER:
1167   case GRAY2562_DITHER:
1168     if (matched_depth == 8)
1169       Gray2DitherImage(l, Cr, Cb, disp, h, w);
1170     else if (matched_depth == 16)
1171       Gray216DitherImage(l, Cr, Cb, disp, h, w);
1172     else if (matched_depth == 32 || matched_depth == 24)
1173       Gray232DitherImage(l, Cr, Cb, disp, h, w);
1174     break;
1175 
1176   case NO_DITHER:
1177     break;
1178 
1179   case PPM_DITHER:
1180     Color32DitherImage(l, Cr, Cb, disp, h, w);
1181     break;
1182 
1183   case ORDERED_DITHER:
1184     OrderedDitherImage(l, Cr, Cb, disp, h, w);
1185     break;
1186 
1187   case MONO_DITHER:
1188     MonoDitherImage(l, Cr, Cb, disp, h, w);
1189     break;
1190 
1191   case MONO_THRESHOLD:
1192     MonoThresholdImage(l, Cr, Cb, disp, h, w);
1193     break;
1194 
1195   case ORDERED2_DITHER:
1196     Ordered2DitherImage(l, Cr, Cb, disp, h, w);
1197     break;
1198 
1199   case MBORDERED_DITHER:
1200     MBOrderedDitherImage(l, Cr, Cb, disp, h, w, vid_stream->ditherFlags);
1201     break;
1202   }
1203 #endif
1204 }
1205