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