1 /*
2  * gdith.c --
3  *
4  *      Procedures dealing with grey-scale and mono dithering,
5  *      as well as X Windows set up procedures.
6  *
7  */
8 
9 /*
10  * Copyright (c) 1995 The Regents of the University of California.
11  * All rights reserved.
12  *
13  * Permission to use, copy, modify, and distribute this software and its
14  * documentation for any purpose, without fee, and without written agreement is
15  * hereby granted, provided that the above copyright notice and the following
16  * two paragraphs appear in all copies of this software.
17  *
18  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
19  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
20  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
21  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22  *
23  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
24  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
26  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
27  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
28  */
29 
30 /*
31  * Portions of this software Copyright (c) 1995 Brown University.
32  * All rights reserved.
33  *
34  * Permission to use, copy, modify, and distribute this software and its
35  * documentation for any purpose, without fee, and without written agreement
36  * is hereby granted, provided that the above copyright notice and the
37  * following two paragraphs appear in all copies of this software.
38  *
39  * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR
40  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
41  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN
42  * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43  *
44  * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
45  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
46  * PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
47  * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
48  * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
49  */
50 
51 #include <math.h>
52 #include "video.h"
53 #include "proto.h"
54 #include "dither.h"
55 #ifndef NOCONTROLS
56 #include "ctrlbar.h"
57 #endif
58 #include <sys/time.h>
59 
60 #ifdef __STDC__
61 #include <stdlib.h>
62 #include <string.h>
63 #endif
64 
65 /*
66    Changes to make the code reentrant:
67       X variables now passed in xinfo: display, ximage,cmap,window, gc, etc
68       De-globalized: ditherType, matched_depth, totNumFrames
69       vid_stream->film_has_ended instead of FilmState
70 
71    Additional changes:
72       Now can name and position each movie window individually
73       DISABLE_DITHER cpp define - do not include dither code if defined
74       NOFRAMECOUNT cpp define - do not count frames when running without
75          controls
76       Short circuit InitColorDisplay if not displaying anything
77       ExistingWindow default now 0
78    -lsh@cs.brown.edu (Loring Holden)
79 */
80 
81 /* Range values for lum, cr, cb. */
82 int LUM_RANGE;
83 int CR_RANGE;
84 int CB_RANGE;
85 
86 /* Array that remaps color numbers to actual pixel values used by X server. */
87 
88 unsigned char pixel[256];
89 unsigned long wpixel[256];
90 
91 /* Arrays holding quantized value ranged for lum, cr, and cb. */
92 
93 int *lum_values;
94 int *cr_values;
95 int *cb_values;
96 
97 /* Declaration of global variable containing dither type. */
98 
99 /* Frame Rate Info */
100 extern int framerate;
101 
102 /* Video rates table */
103 /* Cheat on Vid rates, round to 30, and use 30 if illegal value
104    Except for 9, where Xing means 15, and given their popularity, we'll
105    be nice and do it */
106 static int VidRateNum[16]={30, 24, 24, 25, 30, 30, 50, 60,
107                          60, 15, 30, 30, 30, 30, 30, 30};
108 
109 /* Luminance and chrominance lookup tables */
110 static double *L_tab, *Cr_r_tab, *Cr_g_tab, *Cb_g_tab, *Cb_b_tab;
111 
112 
113 /*
114  *--------------------------------------------------------------
115  *
116  * InitColor --
117  *
118  *	Initialize lum, cr, and cb quantized range value arrays.
119  *      Also initializes the lookup tables for the possible
120  *      values of lum, cr, and cb.
121  *    Color values from ITU-R BT.470-2 System B, G and SMPTE 170M
122  *    see InitColorDither in 16bits.c for more
123  *
124  * Results:
125  *      None.
126  *
127  * Side effects:
128  *      None.
129  *
130  *--------------------------------------------------------------
131  */
132 
133 void
InitColor()134 InitColor()
135 {
136   int i, CR, CB;
137 
138   L_tab    = (double *)malloc(LUM_RANGE*sizeof(double));
139   Cr_r_tab = (double *)malloc(CR_RANGE*sizeof(double));
140   Cr_g_tab = (double *)malloc(CR_RANGE*sizeof(double));
141   Cb_g_tab = (double *)malloc(CB_RANGE*sizeof(double));
142   Cb_b_tab = (double *)malloc(CB_RANGE*sizeof(double));
143 
144   if (L_tab == NULL    || Cr_r_tab == NULL ||
145       Cr_g_tab == NULL || Cb_g_tab == NULL ||
146       Cb_b_tab == NULL) {
147     fprintf(stderr, "Could not alloc memory in InitColor\n");
148     exit(1);
149   }
150 
151   for (i=0; i<LUM_RANGE; i++) {
152     lum_values[i]  = ((i * 256) / (LUM_RANGE)) + (256/(LUM_RANGE*2));
153     L_tab[i] = lum_values[i];
154     if (gammaCorrectFlag) {
155       L_tab[i] = GAMMA_CORRECTION(L_tab[i]);
156     }
157   }
158 
159   for (i=0; i<CR_RANGE; i++) {
160     register double tmp;
161     if (chromaCorrectFlag) {
162       tmp = ((i * 256) / (CR_RANGE)) + (256/(CR_RANGE*2));
163       Cr_r_tab[i] = (int) (0.419/0.299) * CHROMA_CORRECTION128D(tmp - 128.0);
164       Cr_g_tab[i] = (int) -(0.299/0.419) * CHROMA_CORRECTION128D(tmp - 128.0);
165       cr_values[i] = CHROMA_CORRECTION256(tmp);
166     } else {
167       tmp = ((i * 256) / (CR_RANGE)) + (256/(CR_RANGE*2));
168       Cr_r_tab[i] = (int)  (0.419/0.299) * (tmp - 128.0);
169       Cr_g_tab[i] = (int) -(0.299/0.419) * (tmp - 128.0);
170       cr_values[i] = (int) tmp;
171     }
172   }
173 
174   for (i=0; i<CB_RANGE; i++) {
175     register double tmp;
176     if (chromaCorrectFlag) {
177       tmp = ((i * 256) / (CB_RANGE)) + (256/(CB_RANGE*2));
178       Cb_g_tab[i] = (int) -(0.114/0.331) * CHROMA_CORRECTION128D(tmp - 128.0);
179       Cb_b_tab[i] = (int)  (0.587/0.331) * CHROMA_CORRECTION128D(tmp - 128.0);
180       cb_values[i] = CHROMA_CORRECTION256(tmp);
181     } else {
182       tmp = ((i * 256) / (CB_RANGE)) + (256/(CB_RANGE*2));
183       Cb_g_tab[i] = (int) -(0.114/0.331) * (tmp - 128.0);
184       Cb_b_tab[i] = (int)  (0.587/0.331) * (tmp - 128.0);
185       cb_values[i] = (int) tmp;
186     }
187   }
188 
189 }
190 
191 
192 /*
193  *--------------------------------------------------------------
194  *
195  * ConvertColor --
196  *
197  *	Given a l, cr, cb tuple, converts it to r,g,b.
198  *
199  * Results:
200  *	r,g,b values returned in pointers passed as parameters.
201  *
202  * Side effects:
203  *      None.
204  *
205  *--------------------------------------------------------------
206  */
207 
208 static void
ConvertColor(l,cr,cb,r,g,b)209 ConvertColor(l, cr, cb, r, g, b)
210      unsigned int l, cr, cb;
211      unsigned char *r, *g, *b;
212 {
213   double fl, fcr, fcb, fr, fg, fb;
214 
215 /*
216  * Old method w/o lookup table
217  *
218  * fl = 1.164*(((double) l)-16.0);
219  * fcr =  ((double) cr) - 128.0;
220  * fcb =  ((double) cb) - 128.0;
221  *
222  * fr = fl + (1.366 * fcr);
223  * fg = fl - (0.700 * fcr) - (0.334 * fcb);
224  * fb = fl + (1.732 * fcb);
225  */
226 
227   fl = L_tab[l];
228 
229   fr = fl + Cr_r_tab[cr];
230   fg = fl + Cr_g_tab[cr] + Cb_g_tab[cb];
231   fb = fl + Cb_b_tab[cb];
232 
233   if (fr < 0.0) fr = 0.0;
234   else if (fr > 255.0) fr = 255.0;
235 
236   if (fg < 0.0) fg = 0.0;
237   else if (fg > 255.0) fg = 255.0;
238 
239   if (fb < 0.0) fb = 0.0;
240   else if (fb > 255.0) fb = 255.0;
241 
242   *r = (unsigned char) fr;
243   *g = (unsigned char) fg;
244   *b = (unsigned char) fb;
245 
246 }
247 
248 #ifdef SH_MEM
249 
250 int gXErrorFlag = 0;
251 
HandleXError(dpy,event)252 int HandleXError(dpy, event)
253      Display *dpy;
254      XErrorEvent *event;
255 {
256   gXErrorFlag = 1;
257 
258   return 0;
259 }
260 
261 int HandleXError();
262 
InstallXErrorHandler(display)263 void InstallXErrorHandler(display)
264    Display *display;
265 {
266   XSetErrorHandler(HandleXError);
267   XFlush(display);
268 }
269 
DeInstallXErrorHandler(display)270 void DeInstallXErrorHandler(display)
271    Display *display;
272 {
273   XSetErrorHandler(NULL);
274   XFlush(display);
275 }
276 #endif
277 
278 
279 /*
280  *--------------------------------------------------------------
281  *
282  * ResizeDisplay --
283  *
284  *	Resizes display window.
285  *
286  * Results:
287  *	None.
288  *
289  * Side effects:
290  *      None.
291  *
292  *--------------------------------------------------------------
293  */
294 
ResizeDisplay(w,h,xinfo)295 void ResizeDisplay(w, h, xinfo)
296      unsigned int w, h;
297      XInfo *xinfo;
298 {
299 
300 #ifndef DISABLE_DITHER
301   if (xinfo->ditherType == NO_DITHER || xinfo->ditherType == PPM_DITHER) return;
302 #endif
303 
304   XResizeWindow(xinfo->display, xinfo->window, w, h);
305   XFlush(xinfo->display);
306 }
307 
308 
309 /*
310  *--------------------------------------------------------------
311  *
312  * MakeWindow --
313  *
314  *	Create X Window
315  *
316  * Results:
317  *	Read the code.
318  *
319  * Side effects:
320  *      None.
321  *
322  *--------------------------------------------------------------
323  */
324 
325 #ifdef SH_MEM
326 int CompletionType = -1;
327 #endif
328 
329 static int
MakeWindow(name,xinfo)330 MakeWindow(name, xinfo)
331 char *name;
332 XInfo *xinfo;
333 {
334 
335   unsigned int fg, bg;
336   char *hello = (xinfo->name == NULL) ? "MPEG Play" : xinfo->name;
337   int screen;
338 /*  void CreateFullColorWindow();*/
339   XVisualInfo vinfo;
340   Display *display;
341 
342   if (xinfo == NULL) return 0;
343 #ifndef DISABLE_DITHER
344   if ((xinfo->ditherType == NO_DITHER) ||
345       (xinfo->ditherType == PPM_DITHER)) return 0;
346 #endif
347 
348   if (xinfo->display == NULL) {
349     display = xinfo->display = XOpenDisplay(name);
350     if (xinfo->display == NULL) {
351       fprintf(stderr, "Cannot open display\n");
352       exit(-2);
353     }
354   }
355   display = xinfo->display;
356 
357 #ifdef SH_MEM
358   if(shmemFlag)
359     CompletionType = XShmGetEventBase(display) + ShmCompletion;
360 #endif
361 
362   screen = DefaultScreen (display);
363 
364   /* Fill in hint structure */
365 
366   if (xinfo->hints.width == 0) {
367     xinfo->hints.width = 150;
368     xinfo->hints.height = 150;
369   }
370   xinfo->hints.x = xinfo->hints.x;
371   xinfo->hints.y = xinfo->hints.y;
372   xinfo->hints.flags = PPosition | PSize;
373 
374   /* Get some colors */
375 
376   bg = WhitePixel(display, screen);
377   fg = BlackPixel(display, screen);
378 
379   if (xinfo->ExistingWindow) {
380     /* This dowsnt work.  it used to.  why not? */
381     xinfo->window = xinfo->ExistingWindow;
382     if (!quietFlag) printf("Display is 0x%X, window is 0x%X\n", display, xinfo->window);
383     return TRUE;
384   }
385 
386 
387   /* Make the window */
388 
389 #ifndef DISABLE_DITHER
390   if (xinfo->ditherType == FULL_COLOR_DITHER ||
391       xinfo->ditherType == FULL_COLOR2_DITHER) {
392 #endif
393     CreateFullColorWindow (xinfo);
394     if (xinfo->window == 0) {
395       fprintf (stderr, "-color option only valid on full color display\n");
396       exit(-1);
397     }
398 #ifndef DISABLE_DITHER
399   } else {
400     if (((XMatchVisualInfo (display, screen, 24, TrueColor,   &vinfo) != 0) ||
401 	 (XMatchVisualInfo (display, screen, 24, DirectColor, &vinfo) != 0)) &&
402 	 (!quietFlag)) {
403       printf("\nOn 24 bit displays:  use -dither color to get full color\n\t\tordered dither is the default.\n");
404     }
405     if (xinfo->ditherType == MONO_DITHER ||
406 	xinfo->ditherType == MONO_THRESHOLD) {
407       xinfo->window = XCreateSimpleWindow (display,
408 				    DefaultRootWindow(display),
409 				    xinfo->hints.x, xinfo-> hints.y,
410 				    xinfo->hints.width, xinfo->hints.height,
411 				    4, fg, bg);
412       xinfo->depth = 1;
413     } else {
414       Visual *vis;
415       XSetWindowAttributes attrib;
416       unsigned long attrib_flags=0;
417 
418       if (!XMatchVisualInfo (display, screen, xinfo->depth = 8, PseudoColor,
419 			     &vinfo)) {
420 	if (xinfo->ditherType != GRAY_DITHER &&
421 	    xinfo->ditherType != GRAY2_DITHER &&
422 	    xinfo->ditherType != GRAY256_DITHER &&
423 	    xinfo->ditherType != GRAY2562_DITHER) {
424 	  fprintf(stderr, "specified dither requires 8 bit display\n");
425 	  return 0;
426 	} else if (!XMatchVisualInfo(display, screen, xinfo->depth = 32,
427 			GrayScale, &vinfo) &&
428 	           !XMatchVisualInfo(display, screen, xinfo->depth = 24,
429 			GrayScale, &vinfo) &&
430 	           !XMatchVisualInfo(display, screen, xinfo->depth = 16,
431 			GrayScale, &vinfo) &&
432 	           !XMatchVisualInfo(display, screen, xinfo->depth = 8,
433 			GrayScale, &vinfo) &&
434 	           !XMatchVisualInfo(display, screen, xinfo->depth = 32,
435 			TrueColor, &vinfo) &&
436 	           !XMatchVisualInfo(display, screen, xinfo->depth = 24,
437 			TrueColor, &vinfo) &&
438 	           !XMatchVisualInfo(display, screen, xinfo->depth = 16,
439 			TrueColor, &vinfo)) {
440 	  fprintf(stderr, "- -dither gray requires at least 8 bit display\n");
441 	  exit(-1);
442 	}
443       }
444 
445       vis = vinfo.visual;
446       if (XDefaultDepthOfScreen(XDefaultScreenOfDisplay(display)) != 8) {
447 	attrib_flags |= CWColormap;
448 	attrib.colormap = XCreateColormap(display, DefaultRootWindow(display),
449 					  vis, AllocNone);
450 	xinfo->owncmFlag = TRUE;
451       }
452 
453       attrib.background_pixel = bg;
454       attrib.border_pixel = fg;
455       attrib.backing_store = NotUseful;
456       attrib.save_under = False;
457       attrib.background_pixel = bg;
458       attrib.border_pixel = bg;
459       attrib_flags |= CWBackPixel | CWBorderPixel | CWBackingStore | CWSaveUnder;
460       xinfo->window = XCreateWindow (display,
461 			      DefaultRootWindow (display),
462 			      xinfo->hints.x, xinfo->hints.y,
463 			      xinfo->hints.width, xinfo->hints.height, 4,
464 			      xinfo->depth, InputOutput, vis,
465 			      attrib_flags, &attrib);
466     }}
467 #endif
468 
469   XSelectInput(display, xinfo->window, StructureNotifyMask);
470 
471   /* Tell other applications about this window */
472   XSetStandardProperties (display, xinfo->window, hello,
473 			  hello, None, NULL, 0, &xinfo->hints);
474   /* Map window. */
475 
476   XMapWindow(display, xinfo->window);
477   /* Wait for map. */
478   while (TRUE) {
479     XEvent	xev;
480 
481     XNextEvent(display, &xev);
482     if (xev.type == MapNotify && xev.xmap.event == xinfo->window) {
483       break;
484     }
485   }
486 
487 #ifndef NOCONTROLS
488   XSelectInput(display, xinfo->window, ExposureMask | ButtonPressMask );
489 #else
490   XSelectInput(display, xinfo->window, NoEventMask);
491 #endif
492 
493   return TRUE;
494 }
495 
496 
497 /*
498  *--------------------------------------------------------------
499  *
500  * InitDisplay --
501  *
502  *	Initialized display, sets up colormap, etc.
503  *
504  * Results:
505  *      None.
506  *
507  * Side effects:
508  *      None.
509  *
510  *--------------------------------------------------------------
511  */
512 
513 void
InitDisplay(name,xinfo)514 InitDisplay(name, xinfo)
515 char *name;
516 XInfo *xinfo;
517 {
518 
519   int ncolors = LUM_RANGE*CB_RANGE*CR_RANGE;
520   XColor xcolor;
521   int i, lum_num, cr_num, cb_num;
522   unsigned char r, g, b;
523   Colormap dcmap;
524   Display *display;
525 
526 #ifndef DISABLE_DITHER
527   if ((xinfo->ditherType == NO_DITHER) || (xinfo->ditherType == PPM_DITHER))
528      return;
529 #endif
530   if ((noDisplayFlag) || (xinfo==NULL)) return;
531 
532   if (!MakeWindow(name, xinfo)) {
533     /* Could not do that dither.  Try again if can */
534 #ifndef DISABLE_DITHER
535     switch (xinfo->ditherType) {
536     case HYBRID_DITHER:
537     case HYBRID2_DITHER:
538     case FS4_DITHER:
539     case FS2_DITHER:
540     case FS2FAST_DITHER:
541     case Twox2_DITHER:
542     case ORDERED_DITHER:
543     case ORDERED2_DITHER:
544     case MBORDERED_DITHER:
545       fprintf(stderr, "trying -dither color\n");
546       xinfo->ditherType = FULL_COLOR_DITHER;
547       InitColorDisplay(name,xinfo);
548       InitColorDither(xinfo->depth == 32);
549       return;
550 
551     case GRAY_DITHER:
552     case GRAY2_DITHER:
553     case GRAY256_DITHER:
554     case GRAY2562_DITHER:
555     case FULL_COLOR_DITHER:
556     case FULL_COLOR2_DITHER:
557     case MONO_DITHER:
558     case MONO_THRESHOLD:
559     default:
560       /* cant do anything */
561       exit(-1);
562   }
563 #else
564     exit(-1);
565 #endif
566   }
567 
568   if (xinfo != NULL) {
569     display = xinfo->display;
570     xinfo->gc = XCreateGC(display, xinfo->window, 0, 0);
571 
572     dcmap = xinfo->cmap = XDefaultColormap(display, DefaultScreen(display));
573 
574     xcolor.flags = DoRed | DoGreen | DoBlue;
575 
576     if (xinfo->owncmFlag) goto create_map;
577   }
578     retry_alloc_colors:
579   for (i=0; i<ncolors; i++) {
580 
581     lum_num = (i / (CR_RANGE*CB_RANGE))%LUM_RANGE;
582     cr_num = (i / CB_RANGE)%CR_RANGE;
583     cb_num = i % CB_RANGE;
584 
585     ConvertColor(lum_num, cr_num, cb_num, &r, &g, &b);
586 
587     xcolor.red = r * 256;
588     xcolor.green = g * 256;
589     xcolor.blue = b * 256;
590 
591     if ((xinfo != NULL) && (XAllocColor(display, xinfo->cmap, &xcolor) == 0
592 	&& xinfo->cmap == dcmap)) {
593       int j;
594       unsigned long tmp_pixel;
595       XWindowAttributes xwa;
596 
597       if (!quietFlag) {
598         fprintf(stderr, "Using private colormap.\n");
599       }
600 
601       /* Free colors. */
602       for (j = 0; j < i; j ++) {
603         tmp_pixel = wpixel[j];
604         XFreeColors(display, xinfo->cmap, &tmp_pixel, 1, 0);
605       }
606 
607       create_map:
608       XGetWindowAttributes(display, xinfo->window, &xwa);
609       xinfo->cmap = XCreateColormap(display, xinfo->window,
610 				    xwa.visual, AllocNone);
611       XSetWindowColormap(display, xinfo->window, xinfo->cmap);
612 
613       goto retry_alloc_colors;
614     }
615     pixel[i] = xcolor.pixel;
616     wpixel[i] = xcolor.pixel;
617   }
618 
619   xinfo->ximage = NULL;
620 }
621 
622 #ifndef DISABLE_DITHER
623 
624 /*
625  *--------------------------------------------------------------
626  *
627  * InitGrayDisplay --
628  *
629  *	Initialized display for gray scale dither.
630  *
631  * Results:
632  *      None.
633  *
634  * Side effects:
635  *      None.
636  *
637  *--------------------------------------------------------------
638  */
639 
InitGrayDisplay(name,xinfo)640 void InitGrayDisplay(name,xinfo)
641 char *name;
642 XInfo *xinfo;
643 {
644   int ncolors = 128;
645   XColor xcolor;
646   int i;
647   Colormap dcmap;
648   unsigned long tmp_pixels[256];
649   Window window;
650   Display *display;
651 
652   if (noDisplayFlag) return;
653   MakeWindow(name,xinfo);
654   display=xinfo->display;
655   window=xinfo->window;
656 
657   xinfo->gc = XCreateGC(display, window, 0, 0);
658 
659   dcmap = xinfo->cmap = XDefaultColormap(display, DefaultScreen(display));
660 
661   xcolor.flags = DoRed | DoGreen | DoBlue;
662 
663   if (xinfo->owncmFlag) goto create_map;
664   retry_alloc_grays:
665   for (i=0; i<ncolors; i++) {
666 
667     xcolor.red = xcolor.green = xcolor.blue = GAMMA_CORRECTION(i*2) * 256;
668 
669     if(XAllocColor(display, xinfo->cmap, &xcolor) == 0
670 		   && xinfo->cmap == dcmap) {
671       int j;
672       XWindowAttributes xwa;
673 
674       if (!quietFlag) {
675         fprintf(stderr, "Using private colormap.\n");
676       }
677 
678       /* Free colors. */
679       for(j = 0; j < i; j ++) {
680         unsigned long tmp_pixel;
681         tmp_pixel = tmp_pixels[j*2];
682         XFreeColors(display, xinfo->cmap, &tmp_pixel, 1, 0);
683       }
684 
685       create_map:
686       XGetWindowAttributes(display, window, &xwa);
687       xinfo->cmap = XCreateColormap(display, window, xwa.visual, AllocNone);
688       XSetWindowColormap(display, window, xinfo->cmap);
689 
690       goto retry_alloc_grays;
691     }
692     tmp_pixels[i*2] = pixel[i*2] = xcolor.pixel;
693     tmp_pixels[(i*2)+1] = pixel[(i*2)+1] = xcolor.pixel;
694     wpixel[(i*2)] = xcolor.pixel;
695     wpixel[(i*2)+1] = xcolor.pixel;
696     if(xinfo->depth == 8) {
697       wpixel[i*2] |= wpixel[i*2] << 8;
698       wpixel[i*2+1] |= wpixel[i*2+1] << 8;
699     }
700     if(xinfo->depth == 8 || xinfo->depth == 16) {
701       wpixel[i*2] |= wpixel[i*2] << 16;
702       wpixel[i*2+1] |= wpixel[i*2+1] << 16;
703     }
704 #ifdef SIXTYFOUR_BIT
705     if(xinfo->depth == 8 || xinfo->depth == 16 || xinfo->depth == 24 ||
706        xinfo->depth == 32) {
707       wpixel[i*2] |= wpixel[i*2] << 32;
708       wpixel[i*2+1] |= wpixel[i*2+1] << 32;
709     }
710 #endif
711 
712   }
713 
714   xinfo->ximage = NULL;
715 }
716 
717 
718 /*
719  *--------------------------------------------------------------
720  *
721  * InitGray256Display --
722  *
723  *	Initialized display for gray scale dither with 256 levels
724  *
725  * Results:
726  *      None.
727  *
728  * Side effects:
729  *      None.
730  *
731  *--------------------------------------------------------------
732  */
733 
734 
InitGray256Display(name,xinfo)735 void InitGray256Display(name, xinfo)
736 char *name;
737 XInfo *xinfo;
738 {
739   int ncolors = 256;
740   XColor xcolor;
741   int i;
742   Colormap dcmap;
743   int result;
744   XWindowAttributes xwa;
745   unsigned long tmp_pixels[256];
746   Display *display;
747 
748   if (noDisplayFlag) return;
749   MakeWindow(name,xinfo);
750   display=xinfo->display;
751 
752   xinfo->gc = XCreateGC(display, xinfo->window, 0, 0);
753 
754   dcmap = xinfo->cmap = XDefaultColormap(display, DefaultScreen(display));
755 
756   xcolor.flags = DoRed | DoGreen | DoBlue;
757 
758   if (xinfo->owncmFlag) {
759     XGetWindowAttributes(display, xinfo->window, &xwa);
760     xinfo->cmap=XCreateColormap(display, xinfo->window, xwa.visual, AllocNone);
761     XSetWindowColormap(display, xinfo->window, xinfo->cmap);
762   }
763 
764   retry_alloc_grays:
765   for (i = 0;  i < ncolors;  i++) {
766     xcolor.red = xcolor.green = xcolor.blue = GAMMA_CORRECTION(i) * 256;
767     if ((result = XAllocColor(display, xinfo->cmap, &xcolor)) == 0
768 	 && xinfo->cmap == dcmap) {
769       int j;
770       unsigned long tmp_pixel;
771 
772       if (!quietFlag) {
773         fprintf(stderr, "Using private colormap.\n");
774       }
775 
776       /* Free colors. */
777       for (j = 0; j < i; j ++) {
778         tmp_pixel = tmp_pixels[j];
779         XFreeColors(display, xinfo->cmap, &tmp_pixel, 1, 0);
780       }
781 
782       XGetWindowAttributes(display, xinfo->window, &xwa);
783       xinfo->cmap = XCreateColormap(display, xinfo->window, xwa.visual,
784 				    AllocNone);
785       XSetWindowColormap(display, xinfo->window, xinfo->cmap);
786 
787       goto retry_alloc_grays;
788     }
789     tmp_pixels[i] = pixel[i] = xcolor.pixel;
790     wpixel[i] = xcolor.pixel;
791 #ifndef DISABLE_DITHER
792     if(xinfo->depth == 8)
793 #endif
794       wpixel[i] |= wpixel[i] << 8;
795 #ifndef DISABLE_DITHER
796     if(xinfo->depth == 8 || xinfo->depth == 16) {
797 #endif
798       wpixel[i] |= wpixel[i] << 16;
799 #ifndef DISABLE_DITHER
800     }
801 #endif
802 #ifdef SIXTYFOUR_BIT
803     if(xinfo->depth == 8 || xinfo->depth == 16 || xinfo->depth == 24
804        || xinfo->depth == 32) {
805       wpixel[i] |= wpixel[i] << 32;
806     }
807 #endif
808 
809   }
810 
811   xinfo->ximage = NULL;
812 }
813 
814 
815 /*
816  *--------------------------------------------------------------
817  *
818  * InitMonoDisplay --
819  *
820  *	Initialized display for monochrome dither.
821  *
822  * Results:
823  *      None.
824  *
825  * Side effects:
826  *      None.
827  *
828  *--------------------------------------------------------------
829  */
830 
InitMonoDisplay(name,xinfo)831 void InitMonoDisplay(name, xinfo)
832 char *name;
833 XInfo *xinfo;
834 {
835   XGCValues xgcv;
836   Display *display;
837 
838   if (noDisplayFlag) return;
839   MakeWindow(name,xinfo);
840   display=xinfo->display;
841 
842   xgcv.background = BlackPixel(display, DefaultScreen(display));
843   xgcv.foreground = WhitePixel(display, DefaultScreen(display));
844 
845   xinfo->gc = XCreateGC(display, xinfo->window,
846 			GCForeground | GCBackground,
847 			&xgcv);
848 
849   xinfo->ximage = NULL;
850 }
851 #endif
852 
853 
854 
855 /*
856  *--------------------------------------------------------------
857  *
858  * InitColorDisplay --
859  *
860  *	Initialized display for full color output.
861  *
862  * Results:
863  *      None.
864  *
865  * Side effects:
866  *      None.
867  *
868  *--------------------------------------------------------------
869  */
870 
871 void
InitColorDisplay(name,xinfo)872 InitColorDisplay(name, xinfo)
873 char *name;
874 XInfo *xinfo;
875 {
876   XWindowAttributes winattr;
877 
878 #ifndef DISABLE_DITHER
879   if ((xinfo->ditherType == NO_DITHER) || (xinfo->ditherType == PPM_DITHER))
880      return;
881 #endif
882   if ((noDisplayFlag) || (xinfo==NULL)) return;
883 
884   MakeWindow(name,xinfo);
885 
886   if (xinfo->gc==0) {
887     xinfo->gc = XCreateGC(xinfo->display, xinfo->window, 0, 0);
888   }
889   xinfo->ximage = NULL;
890 
891   XGetWindowAttributes(xinfo->display, xinfo->window, &winattr);
892   /*
893    * Misuse of wpixel
894    */
895   wpixel[0] = winattr.visual->red_mask;
896   wpixel[1] = winattr.visual->green_mask;
897   wpixel[2] = winattr.visual->blue_mask;
898 }
899 
900 
901 /*
902  *--------------------------------------------------------------
903  *
904  * ExecuteDisplay --
905  *
906  *	Actually displays display plane in previously created window.
907  *
908  * Results:
909  *	None.
910  *
911  * Side effects:
912  *	None.
913  *
914  *--------------------------------------------------------------
915  */
916 
917 void
918 #ifndef NOCONTROLS
ExecuteDisplay(vid_stream,frame_increment,xinfo)919 ExecuteDisplay(vid_stream,frame_increment,xinfo)
920      VidStream *vid_stream;
921      int frame_increment;
922      XInfo *xinfo;
923 #else
924 ExecuteDisplay(vid_stream, xinfo)
925      VidStream *vid_stream;
926      XInfo *xinfo;
927 #endif
928 {
929   char dummy;
930   Visual *FindFullColorVisual();
931   Visual *fc_visual;
932   int depth, result;
933   static int rate_deal = -1;
934   static int one_frame_time;
935   static struct timeval tftarget, tfnow;
936   register int usec, sec;
937 #ifndef NOCONTROLS
938   XEvent xev;
939 #endif
940   Display *display;
941 
942   if (xinfo!=NULL) display=xinfo->display;
943 
944 #ifndef NOCONTROLS
945   vid_stream->totNumFrames+=frame_increment;
946 #else
947   vid_stream->totNumFrames++;
948 #endif
949 
950   if (partialFlag) {
951     if ((endFrame != -1) && (vid_stream->totNumFrames > endFrame)) {
952 #ifdef ANALYSIS
953       PrintAllStats(vid_stream);
954 #endif
955       PrintTimeInfo(vid_stream);
956 
957       vid_stream->film_has_ended=TRUE;
958 #ifndef NOCONTROLS
959       if ((frame_increment != 0) && (ControlShow != CTRLBAR_NONE))
960         UpdateFrameTotal(xinfo->display);
961       return;
962 #else
963       if (loopFlag) {
964               clear_data_stream(vid_stream);
965       } else DestroyVidStream(vid_stream, xinfo);
966       return;
967 #endif
968     }
969     if (vid_stream->totNumFrames < startFrame) {
970       return;
971     }
972   }
973 
974 
975   /* Do frame rate control */
976   switch (rate_deal) {
977   case 0:
978     break;
979   default:
980     gettimeofday(&tfnow, (struct timezone *)NULL);
981     usec = tftarget.tv_usec - tfnow.tv_usec;
982     sec  = tftarget.tv_sec - tfnow.tv_sec;
983     if (usec < 0) {
984       usec += 1000000;
985       sec--;
986     }
987 
988     /* If we're not behind, wait a bit */
989     if ((sec >= 0)  &&  usec > 0) {
990       tfnow.tv_sec = sec;
991       tfnow.tv_usec = usec;
992       select(0, NULL, NULL, NULL ,&tfnow);
993       gettimeofday(&tfnow, (struct timezone *)NULL);
994     }
995     /* Setup target for next frame */
996     tftarget.tv_usec = tfnow.tv_usec + one_frame_time;
997     if (tftarget.tv_usec >= 1000000) {
998       tftarget.tv_usec -= 1000000;
999       tftarget.tv_sec = tfnow.tv_sec + 1;
1000     } else tftarget.tv_sec = tfnow.tv_sec;
1001     break;
1002   case -1:
1003     switch (framerate) {
1004     case -1: /* Go with stream Value */
1005       rate_deal = VidRateNum[vid_stream->picture_rate];
1006       gettimeofday(&tftarget, (struct timezone *)NULL);
1007       one_frame_time = 1000000 / rate_deal;
1008       break;
1009     case 0: /* as fast as possible */
1010       rate_deal = 0;
1011       break;
1012     default:
1013       rate_deal = framerate;
1014       gettimeofday(&tftarget, (struct timezone *)NULL);
1015       one_frame_time = 1000000 / rate_deal;
1016       break;
1017     }
1018     break;
1019   }
1020 
1021 #ifndef NOCONTROLS
1022   if (frame_increment > 0) {
1023     TotalFrameCount++;
1024     if ((endFrame != -1) && (vid_stream->totNumFrames >= endFrame)) {
1025       vid_stream->film_has_ended=TRUE;
1026     }
1027     if (!quietFlag && ControlShow == CTRLBAR_NONE)
1028       fprintf(stderr, "%d\r", vid_stream->totNumFrames);
1029   }
1030 #else
1031 #ifndef NOFRAMECOUNT
1032   if (!quietFlag) {
1033     fprintf (stderr, "%d\r", vid_stream->totNumFrames);
1034   }
1035 #endif
1036 #endif
1037 
1038 #ifndef DISABLE_DITHER
1039   if (vid_stream->ditherType == NO_DITHER) return;
1040   if (vid_stream->ditherType == PPM_DITHER) {
1041     ExecutePPM(vid_stream);
1042     return;
1043   }
1044 #endif
1045   if (xinfo==NULL) return;
1046   if (!noDisplayFlag) {
1047   if (xinfo->ximage == NULL) {
1048 
1049     int pixels_per_mb = 16;
1050 #ifndef DISABLE_DITHER
1051     if(IS_2x2_DITHER(xinfo->ditherType)) pixels_per_mb = 32;
1052 
1053     if ((xinfo->ditherType == FULL_COLOR_DITHER) ||
1054 	(xinfo->ditherType == FULL_COLOR2_DITHER)) {
1055 #endif
1056       int w, h;
1057 
1058       w = vid_stream->mb_width  * pixels_per_mb;
1059       h = vid_stream->mb_height * pixels_per_mb;
1060 
1061       fc_visual = FindFullColorVisual(display, &depth);
1062       xinfo->ximage = XCreateImage (display,
1063 			     fc_visual, depth, ZPixmap,
1064 			     0, &dummy, w, h, 32, 0);
1065 
1066 #ifndef DISABLE_DITHER
1067     } else if (xinfo->ditherType == MONO_DITHER
1068 	    || xinfo->ditherType == MONO_THRESHOLD) {
1069       xinfo->ximage = XCreateImage (display,
1070 			     None, xinfo->depth, XYBitmap, 0, &dummy,
1071 			     vid_stream->mb_width * pixels_per_mb,
1072 			     vid_stream->mb_height * pixels_per_mb, 8, 0);
1073       xinfo->ximage->byte_order = MSBFirst;
1074       xinfo->ximage->bitmap_bit_order = MSBFirst;
1075     } else {
1076       xinfo->ximage = XCreateImage(display,
1077 		       None, xinfo->depth, ZPixmap, 0, &dummy,
1078 			    vid_stream->mb_width * pixels_per_mb,
1079 			    vid_stream->mb_height * pixels_per_mb, 8, 0);
1080     }
1081 #endif
1082   }
1083 
1084 /*
1085  * Always work in native bit and byte order. This tells Xlib to reverse
1086  * bit and byte order if necessary when crossing a network. Frankly, this
1087  * part of XImages is somewhat underdocumented, so this may not be exactly
1088  * correct.
1089  */
1090 #ifdef LITTLE_ENDIAN_ARCHITECTURE
1091     xinfo->ximage->byte_order = LSBFirst;
1092     xinfo->ximage->bitmap_bit_order = LSBFirst;
1093 #else
1094     xinfo->ximage->byte_order = MSBFirst;
1095     xinfo->ximage->bitmap_bit_order = MSBFirst;
1096 #endif
1097 
1098 
1099 #ifdef SH_MEM
1100     if (shmemFlag) {
1101            XShmPutImage(display,
1102 			xinfo->window,
1103 			xinfo->gc, vid_stream->current->ximage,
1104                         0, 0, 0, 0,
1105                         vid_stream->current->ximage->width,
1106                         vid_stream->current->ximage->height, True);
1107            XFlush(display);
1108 
1109 #ifndef NOCONTROLS
1110       /* Wait for it _without_ removing other events from queue */
1111       XIfEvent(display, &xev, IfEventType, (char *) (&CompletionType));
1112 #else
1113       while(1) {
1114         XEvent xev;
1115 
1116         XNextEvent(display, &xev);
1117         if (xev.type == CompletionType) {
1118           break;
1119         }
1120       }
1121 #endif
1122     }
1123     else
1124 #endif
1125 
1126       {
1127         xinfo->ximage->data = (char *) vid_stream->current->display;
1128 
1129         result=XPutImage(display, xinfo->window, xinfo->gc, xinfo->ximage,
1130 		  0, 0, 0, 0,
1131 		  xinfo->ximage->width,
1132 		  xinfo->ximage->height);
1133       }
1134   }
1135 #ifndef NOCONTROLS
1136       if ((frame_increment != 0) && (ControlShow != CTRLBAR_NONE)) {
1137         UpdateFrameTotal(xinfo->display);
1138       }
1139 #endif
1140   if (requireKeypressFlag) {
1141     char foo;
1142     printf("Press return (%d) ", vid_stream->totNumFrames);
1143     while ((foo = getchar()) != '\n')
1144       ;
1145   }
1146 
1147 }
1148 
1149 #ifndef DISABLE_DITHER
1150 extern char *strrchr();
1151 #define PPM_BITS 8
1152 
1153 
1154 /*
1155  *--------------------------------------------------------------
1156  *
1157  * ExecutePPM --
1158  *
1159  *	Write out a display plane as a PPM file.
1160  *
1161  * Results:
1162  *	None.
1163  *
1164  * Side effects:
1165  *	None.
1166  *
1167  *--------------------------------------------------------------
1168  */
1169 
1170 void
ExecutePPM(vid_stream)1171 ExecutePPM(vid_stream)
1172      VidStream *vid_stream;
1173 {
1174   static int munged = 0;
1175   static char mungedInputName[300];
1176   char fileName[300], cmd[400];
1177   FILE *file;
1178   int n;
1179   unsigned int *p;
1180   unsigned int r, g, b;
1181 
1182   if (!munged) {
1183     char *cp;
1184 
1185     cp = strrchr(vid_stream->filename, '/');
1186     if (cp != NULL)
1187       ++cp;
1188     else
1189       cp = vid_stream->filename;
1190     strcpy(mungedInputName, cp);
1191     cp = strrchr(mungedInputName, '.');
1192     if (cp != NULL)
1193 	*cp = '\0';
1194     munged = 1;
1195   }
1196 
1197   sprintf(fileName, "%s_%05d.ppm", mungedInputName, vid_stream->totNumFrames);
1198   file = fopen(fileName, "w");
1199   if (vid_stream->ppm_width != -1 && vid_stream->ppm_height != -1) {
1200     if ((vid_stream->ppm_modulus != -1) &&
1201 	((vid_stream->totNumFrames-1) % vid_stream->ppm_modulus != 0)) {
1202       return;
1203     } else {
1204       extern FILE *popen(const char *, const char *);
1205 
1206       sprintf(cmd, "pnmscale -xysize %d %d > %s",
1207  	      vid_stream->ppm_width, vid_stream->ppm_height, fileName);
1208       file = popen(cmd, "w");
1209     }
1210   } else {
1211     file = fopen(fileName, "w");
1212   }
1213   if (file == NULL) {
1214     perror(fileName);
1215     exit(1);
1216   }
1217 
1218   fprintf(file, "P6\n");
1219   fprintf(file, "%d %d\n", vid_stream->h_size, vid_stream->v_size);
1220   fprintf(file, "255\n");
1221 
1222   p = (unsigned int *) vid_stream->current->display;
1223   n = vid_stream->h_size * vid_stream->v_size;
1224   while (n > 0) {
1225     r = *p & 0xff;
1226     g = (*p >> PPM_BITS) & 0xff;
1227     b = (*p >> (2*PPM_BITS)) & 0xff;
1228     putc(r, file);
1229     putc(g, file);
1230     putc(b, file);
1231     ++p;
1232     --n;
1233   }
1234 
1235   if (vid_stream->ppm_width != -1 && vid_stream->ppm_height != -1) {
1236     pclose(file);
1237   } else {
1238     fclose(file);
1239   }
1240 }
1241 #endif
1242 
1243 
1244 #ifdef NO_GETTIMEOFDAY
1245 /* raw approximation */
gettimeofday(struct timeval * retval,void * unused)1246 int gettimeofday (struct timeval * retval, void * unused)
1247 {
1248 	timeb_t tm;
1249 
1250 	ftime (&tm);
1251 	retval->tv_sec=  tm.time;
1252 	retval->tv_usec= tm.millitm*1000;
1253 	return 0;
1254 }
1255 #endif
1256