445219637485f95e68a6643a36f4264348b28a3a
[xscreensaver] / hacks / vidwhacker
1 #!/bin/sh
2 #
3 # vidwhacker, for xscreensaver.  Copyright (c) 1998 Jamie Zawinski.
4 #
5 # This script grabs a frame of video, then uses various pbm filters to
6 # munge the image in random nefarious ways, then uses xv to put it on
7 # the root window.  This works out really nicely if you just feed some
8 # random TV station into it...
9 #
10 # The video grabbing part is SGI-specific -- if you want to use this on
11 # another system, add a new clause to the grab() procedure.
12
13
14 # Process command-line args...
15
16 onroot=false
17 verbose=false
18 delay=3
19
20 if [ "$1" = "-root" ]; then
21   onroot=true
22   shift
23 fi
24
25 if [ "$1" = "-verbose" ]; then
26   verbose=true
27   shift
28 fi
29
30 if [ "$1" != "" ]; then
31   echo "usage: $0 [-root] [-verbose]" >&2
32   exit 1
33 fi
34
35
36 xvargs="-quick24"
37
38 if [ "$onroot" = true ]; then
39   xvargs="$xvargs -root -rmode 5 -quit"
40 else
41   xvargs="$xvargs -geom +0+0"
42 fi
43
44 screen_width=`xdpyinfo | sed -n 's/.* dimensions: *\([0-9]*\).*/\1/p'`
45
46 # global vars...
47
48 tmp=/tmp/vd$$
49 tmp_rgb=$tmp-00000.rgb
50 tmp_ppm=$tmp.ppm
51 tmp_ppm2=$tmp-2.ppm
52 tmp_ppm3=$tmp-3.ppm
53
54 clean() {
55   rm -f $tmp_rgb $tmp_ppm $tmp_ppm2 $tmp_ppm3
56 }
57
58
59 # Grab a frame of video.
60 #
61 grab() {
62   if [ `uname` = IRIX ]; then
63     #
64     # SGI's "vidtomem" returns an SGI RGB image of the default video input,
65     # and has stupid non-overridable ouput-file-naming conventions.  So, let 
66     # it write its file; and then convert it to a pgm.
67     #
68     vidtomem -f $tmp
69     sgitopnm $tmp_rgb > $tmp_ppm
70     # Cut off the close-captioning blips in the NTSC overscan region.  YMMV.
71     #  | pnmcut 12 7 695 477 
72
73   else
74     echo "$0: don't know how to grab video on this OS." >&2
75     clean
76     exit 1
77   fi
78
79
80   # I got this message from Marcus Herbert <rhoenie@chillout.org>.
81   # I'm not sure of the best way to make the presence of qcam be
82   #  auto-detected, but here's what he said, FYI...
83   #
84   #    i am using a black/white Connectix Qcam on linux and its very simple
85   #    to adept the script:
86   #
87   #    # qcam: Version 0.91
88   #    #   Options:
89   #    #   O  -x width   Set width
90   #    #   O  y height   Setheight
91   #    #   O  B bpp      Setbits per pixel
92   #    #   O  W         Auto-set white balance
93   #    #   O  E "vals"  Autoexposure mode, parameters required
94   #    #   O  D         Remove dark speckling
95   #    #   O  s val     Set scaling factor (1, 2, or 4)
96   #    #
97   #    qcam -x 320 -y 240 -B 6 -W -E 1 -D -s 1 > $tmp_ppm
98   #
99   #   You dont really need the parameters for qcam as it reads out a system
100   #   config file where you store the values for brightnes, contrast and
101   #   white balance.  But with this parameters you are independant of the
102   #   light ratios at the place the cam is set up.
103   #
104   #   Other versions of qcam (0.7, 0.96..) don't support the autoexposure and
105   #   auto- whitebalance commandline parameters. On such systems (and on
106   #   color-qcam systems) a simple qcam > $tmp_ppm (or cqcam > $tmp_ppm) is
107   #   enough.
108   #
109   #   I dont know about other systems but afaik fBSD uses the Qcam in this way:
110   #
111   #     qcamcontrol -bla -foo -bar > picture.pgm    
112   #
113 }
114
115
116 # Use perl to pick a random foreground/background color in pbm's syntax.
117 #
118 randcolor() {
119   perl -e 'srand; 
120            printf("#%02x%02x%02x-#%02x%02x%02x",
121                   int(rand()*60),
122                   int(rand()*60),
123                   int(rand()*60),
124                   120+int(rand()*135),
125                   120+int(rand()*135),
126                   120+int(rand()*135))'
127 }
128
129 # Frobnicate the image in some random way.
130 #
131 frob() {
132
133   N=`perl -e 'srand; print int(rand() * 10)'`
134
135   if [ "$verbose" = true ]; then
136     echo "mode $N..." >&2
137   fi
138
139   if   [ $N = 0 ]; then
140     ppmtopgm $tmp_ppm | pgmedge | pgmtoppm `randcolor` | ppmnorm
141
142   elif [ $N = 1 ]; then
143     ppmtopgm $tmp_ppm | 
144     pgmenhance | 
145     pgmtoppm `randcolor`
146
147   elif [ $N = 2 ]; then
148     ppmtopgm $tmp_ppm | pgmoil | pgmtoppm `randcolor`
149
150   elif [ $N = 3 ]; then 
151     ppmrelief $tmp_ppm | ppmtopgm | pgmedge | ppmrelief | ppmtopgm |
152       pgmedge | pnminvert | pgmtoppm `randcolor`
153
154   elif [ $N = 4 ]; then
155     ppmspread 71 $tmp_ppm > $tmp_ppm2
156     pnmarith -add $tmp_ppm $tmp_ppm2
157
158   elif [ $N = 5 ]; then
159     pnmflip -lr $tmp_ppm > $tmp_ppm2
160     pnmarith -multiply $tmp_ppm $tmp_ppm2 > $tmp_ppm3
161     pnmflip -tb $tmp_ppm3 | ppmnorm > $tmp_ppm2
162     pnmarith -multiply $tmp_ppm $tmp_ppm2
163
164   elif [ $N = 6 ]; then
165     N2=`perl -e 'srand; print int(rand() * 3)'`
166     if [ $N2 = 0 ]; then
167       pnmflip -lr $tmp_ppm > $tmp_ppm2
168     elif [ $N2 = 1 ]; then
169       pnmflip -tb $tmp_ppm > $tmp_ppm2
170     else
171       pnmflip -lr $tmp_ppm > $tmp_ppm2
172       pnmflip -tb $tmp_ppm2 > $tmp_ppm3
173       cp $tmp_ppm3 $tmp_ppm2
174     fi
175
176     pnmarith -difference $tmp_ppm $tmp_ppm2
177
178   elif [ $N = 7 ]; then
179
180     for i in 1 2 3 ; do
181       ppmtopgm $tmp_ppm | pgmedge > $tmp_ppm2
182       pnmarith -difference $tmp_ppm $tmp_ppm2 > $tmp_ppm3
183       cp $tmp_ppm3 $tmp_ppm
184     done
185     ppmnorm < $tmp_ppm
186
187   elif [ $N = 8 ]; then
188     pnmflip -lr $tmp_ppm > $tmp_ppm2
189     pnmarith -multiply $tmp_ppm $tmp_ppm2 | ppmrelief | ppmnorm | pnminvert
190
191   elif [ $N = 9 ]; then
192     pnmflip -lr $tmp_ppm > $tmp_ppm2
193     pnmarith -subtract $tmp_ppm $tmp_ppm2 | ppmrelief | ppmtopgm | pgmedge
194
195   else cat $tmp_ppm
196   fi
197 }
198
199
200
201 # Grab a frame and frob it.  leave it in $tmp_ppm3.
202 #
203 whack() {
204   clean
205
206   while [ ! -f $tmp_ppm ]; do
207    grab
208   done
209
210   rm -f $tmp_rgb
211   frob | pnmscale -width $screen_width > $tmp_ppm3
212   rm -f $tmp_ppm $tmp_ppm2
213 }
214
215
216 pid=""
217
218 if [ "$onroot" != true ]; then
219   trap "kill \$pid; clean; exit 1" 2 15
220 fi
221
222 while true; do
223
224   # Loop grabbing and frobbing images.
225   #
226   # If we're running on the root, run xv in the foreground (with -exit)
227   # and then wait.
228   #
229   # If we're running in a window, spawn xv in the background; then when
230   # it's time to put up the new image, kill off the currently-running xv.
231
232   if [ "$verbose" = true ]; then
233     whack
234   else
235     whack >&- 2>&-
236   fi
237
238   if [ "$pid" != "" ]; then
239     kill $pid
240     pid=""
241   fi
242
243   if [ ! -s $tmp_ppm3 ]; then
244     echo "$0: no image grabbed" >&2
245   else
246
247     pnmtosgi < $tmp_ppm3 > $tmp_ppm2
248     rm -f $tmp_ppm3
249
250     if [ "$onroot" = true ]; then
251       xv $xvargs $tmp_ppm2
252     else
253       xv $xvargs $tmp_ppm2 &
254       pid=$!
255     fi
256
257     #xv -geom =320x220 $tmp_ppm3 &
258     #pid=
259   fi
260
261   clean
262   sleep $delay
263
264 done