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