http://apple.doit.wisc.edu/mirrors/amug/linux/linuxppc/sources/tarballs/xscreensaver...
[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 use_stdin=false
20
21 pid=""
22 tmp=/tmp/vd$$
23 tmp_rgb=$tmp-00000.rgb
24 tmp_ppm0=$tmp-0.ppm
25 tmp_ppm1=$tmp-1.ppm
26 tmp_ppm2=$tmp-2.ppm
27 tmp_ppm3=$tmp-3.ppm
28 tmp_ppm4=$tmp-4.ppm
29
30
31 getargs() {
32
33   while [ $# != 0 ]; do
34     case "$1" in
35     -root )
36       onroot=true
37       ;;
38     -verbose )
39       verbose=true
40       ;;
41     -stdin )
42       use_stdin=true
43       ;;
44     * )
45       echo "usage: $0 [ -root | -verbose | -stdin ]" >&2
46       exit 1
47       ;;
48     esac
49     shift
50   done
51
52   xvargs="-quick24"
53
54   if [ "$onroot" = true ]; then
55     xvargs="$xvargs -root -rmode 5 -noresetroot -rfg black -rbg black -viewonly"
56   else
57     xvargs="$xvargs -geom +0+0"
58   fi
59
60   screen_width=`xdpyinfo | sed -n 's/.* dimensions: *\([0-9]*\).*/\1/p'`
61 }
62
63
64 clean() {
65   rm -f $tmp_rgb $tmp_ppm1 $tmp_ppm2 $tmp_ppm3 $tmp_ppm4
66 }
67
68 clean2() {
69   clean
70   rm -f $tmp_ppm0
71 }
72
73
74 # Grab a frame of video.
75 #
76 grab() {
77   uname=`uname`
78   if [ $uname = IRIX ]; then
79     #
80     # SGI's "vidtomem" returns an SGI RGB image of the default video input,
81     # and has stupid non-overridable ouput-file-naming conventions.  So, let 
82     # it write its file; and then convert it to a pgm.
83     #
84     
85     vidtomem -f $tmp
86     sgitopnm $tmp_rgb > $tmp_ppm1
87
88     # Cut off the close-captioning blips in the NTSC overscan region.  YMMV.
89     #  | pnmcut 12 7 695 477 
90
91   elif [ $uname = Linux ]; then
92
93     # Marcus Herbert says the following works with his Connectix Qcam.
94     # Don't have qcam?  Well, do something else then...  and send me a patch.
95
96     qcam > $tmp_ppm1
97
98     # Friedrich Delgado Friedrichs says the following works with a
99     # Brooktree 848 or 878 tuner card:
100     #
101     #   bttvgrab -Q -d q -l 1 -F /dev/null -o gif -f ${tmp}.gif -N PAL
102     #   giftopnm ${tmp}.gif > $tmp_ppm1
103     #   rm ${tmp}.gif
104     #
105     # He notes that you might need to run a TV application (e.g., xawtv)
106     # before the first time you run vidwhacker in order to initialize the
107     # tuner card and kernel modules.
108
109
110   else
111     echo "$0: don't know how to grab video on this OS." >&2
112     clean2
113     exit 1
114   fi
115 }
116
117
118 # Use perl to pick a random foreground/background color in pbm's syntax.
119 #
120 randcolor() {
121   perl -e 'srand; 
122            printf("#%02x%02x%02x-#%02x%02x%02x",
123                   int(rand()*60),
124                   int(rand()*60),
125                   int(rand()*60),
126                   120+int(rand()*135),
127                   120+int(rand()*135),
128                   120+int(rand()*135))'
129 }
130
131 # Frobnicate the image in some random way.
132 #
133 frob() {
134
135   w_h=`head -2 $tmp_ppm1 | tail -1`
136   width=`echo $w_h | awk '{print $1}'`
137   height=`echo $w_h | awk '{print $2}'`
138
139   N=`perl -e 'srand; print int(rand() * 17)'`
140
141   if [ "$verbose" = true ]; then
142     echo "mode $N..." >&2
143   fi
144
145   if   [ $N = 0 ]; then
146     ppmtopgm $tmp_ppm1 | pgmedge | pgmtoppm `randcolor` | ppmnorm
147
148   elif [ $N = 1 ]; then
149     ppmtopgm $tmp_ppm1 | 
150     pgmenhance | 
151     pgmtoppm `randcolor`
152
153   elif [ $N = 2 ]; then
154     ppmtopgm $tmp_ppm1 | pgmoil | pgmtoppm `randcolor`
155
156   elif [ $N = 3 ]; then 
157     ppmrelief $tmp_ppm1 | ppmtopgm | pgmedge | ppmrelief | ppmtopgm |
158       pgmedge | pnminvert | pgmtoppm `randcolor`
159
160   elif [ $N = 4 ]; then
161     ppmspread 71 $tmp_ppm1 > $tmp_ppm2
162     pnmarith -add $tmp_ppm1 $tmp_ppm2
163
164   elif [ $N = 5 ]; then
165     pnmflip -lr $tmp_ppm1 > $tmp_ppm2
166     pnmarith -multiply $tmp_ppm1 $tmp_ppm2 > $tmp_ppm3
167     pnmflip -tb $tmp_ppm3 | ppmnorm > $tmp_ppm2
168     pnmarith -multiply $tmp_ppm1 $tmp_ppm2
169
170   elif [ $N = 6 ]; then
171     N2=`perl -e 'srand; print int(rand() * 3)'`
172     if [ $N2 = 0 ]; then
173       pnmflip -lr $tmp_ppm1 > $tmp_ppm2
174     elif [ $N2 = 1 ]; then
175       pnmflip -tb $tmp_ppm1 > $tmp_ppm2
176     else
177       pnmflip -lr $tmp_ppm1 > $tmp_ppm2
178       pnmflip -tb $tmp_ppm2 > $tmp_ppm3
179       cp $tmp_ppm3 $tmp_ppm2
180     fi
181
182     pnmarith -difference $tmp_ppm1 $tmp_ppm2
183
184   elif [ $N = 7 ]; then
185
186     for i in 1 2 3 ; do
187       ppmtopgm $tmp_ppm1 | pgmedge > $tmp_ppm2
188       pnmarith -difference $tmp_ppm1 $tmp_ppm2 > $tmp_ppm3
189       cp $tmp_ppm3 $tmp_ppm1
190     done
191     ppmnorm < $tmp_ppm1
192
193   elif [ $N = 8 ]; then
194     pnmflip -lr $tmp_ppm1 > $tmp_ppm2
195     pnmarith -multiply $tmp_ppm1 $tmp_ppm2 | ppmrelief | ppmnorm | pnminvert
196
197   elif [ $N = 9 ]; then
198     pnmflip -lr $tmp_ppm1 > $tmp_ppm2
199     pnmarith -subtract $tmp_ppm1 $tmp_ppm2 | ppmrelief | ppmtopgm | pgmedge
200
201   elif [ $N = 10 ]; then
202     ppmtopgm $tmp_ppm1 | pgmbentley | pgmtoppm `randcolor`
203
204   elif [ $N = 11 ]; then
205     pgmcrater -number 20000 -height $height -width $width | pgmtoppm `randcolor` > $tmp_ppm2
206     pnmarith -difference $tmp_ppm1 $tmp_ppm2 > $tmp_ppm3
207     pnmflip -tb $tmp_ppm3 | ppmnorm > $tmp_ppm2
208     pnmarith -multiply $tmp_ppm1 $tmp_ppm2
209
210   elif [ $N = 12 ]; then
211     ppmshift 30 $tmp_ppm1 | ppmtopgm | pgmoil | pgmedge |  pgmtoppm `randcolor` > $tmp_ppm2
212     pnmarith -difference $tmp_ppm1 $tmp_ppm2 
213
214  elif [ $N = 13 ]; then
215     ppmpat -madras $width $height | pnmdepth 255 > $tmp_ppm2
216     pnmarith -difference $tmp_ppm1 $tmp_ppm2
217  
218   elif [ $N = 14 ]; then
219     ppmpat -tartan $width $height | pnmdepth 255 > $tmp_ppm2
220     pnmarith -difference  $tmp_ppm1 $tmp_ppm2 
221   
222   elif [ $N = 15 ]; then
223     ppmpat -camo $width $height | pnmdepth 255 | ppmshift 50 > $tmp_ppm2
224     pnmarith -multiply $tmp_ppm1 $tmp_ppm2
225   
226   elif [ $N = 16 ]; then
227     pgmnoise $width $height | pgmedge | pgmtoppm `randcolor` > $tmp_ppm2
228     pnmarith -difference $tmp_ppm1 $tmp_ppm2 | pnmdepth 255 | pnmsmooth
229
230   else cat $tmp_ppm1
231   fi
232 }
233
234
235 # Grab a frame and frob it.  leave it in $tmp_ppm3.
236 #
237 whack() {
238   clean
239
240   while [ ! -f $tmp_ppm1 ]; do
241     if [ "$use_stdin" != true ]; then
242       grab
243     else
244       cp $tmp_ppm0 $tmp_ppm1
245     fi
246   done
247
248   rm -f $tmp_rgb
249   frob | pnmscale -width $screen_width > $tmp_ppm3
250   rm -f $tmp_ppm1 $tmp_ppm2
251 }
252
253
254 # Kill off the xv subprocess, if it's running
255 #
256 kill_pid() {
257   if [ "$pid" != "" ]; then
258
259     if [ "$verbose" = true ]; then
260       echo "killing pid $pid..." >&2
261     fi
262
263     # need to do this to avoid "6898 Terminated" messages!
264     # apparently one can't redirect the output of the builtin `kill' command.
265 #    ( sh -c "kill $pid" ) >/dev/null 2>/dev/null </dev/null
266
267     # wtf?  that doesn't work either.  Is it writing to /dev/tty??
268     kill $pid >&- >&-
269
270     pid=""
271   fi
272 }
273
274 # called when this process is signalled (for cleanup)
275 #
276 my_trap() {
277   if [ "$verbose" = true ]; then
278     echo "trapped signal!" >&2
279   fi
280   kill_pid
281   clean2
282   exit 1
283 }
284
285 main() {
286
287   getargs $@
288
289   trap my_trap 0 1 2 3 6 9 13 15
290
291   if [ "$use_stdin" = true ]; then
292    cat > $tmp_ppm0
293   fi
294
295   while true; do
296
297     # Loop grabbing and frobbing images.
298     #
299     # If we're running on the root, run xv in the foreground (with -exit)
300     # and then wait.
301     #
302     # If we're running in a window, spawn xv in the background; then when
303     # it's time to put up the new image, kill off the currently-running xv.
304
305     if [ "$verbose" = true ]; then
306       whack
307     else
308       whack >&- 2>&-
309     fi
310
311     kill_pid
312
313     if [ ! -s $tmp_ppm3 ]; then
314       echo "$0: no image grabbed" >&2
315     else
316
317       pnmtosgi < $tmp_ppm3 > $tmp_ppm2
318       rm -f $tmp_ppm3
319
320       if [ -s $tmp_ppm2 ]; then
321         if [ "$verbose" = true ]; then
322           echo "launching xv $xvargs $tmp_ppm2" >&2
323           ls -lF $tmp_ppm2
324         fi
325
326         mv $tmp_ppm2 $tmp_ppm0
327         xv $xvargs $tmp_ppm0 &
328
329 # this doesn't work -- leaves xv processes around, instead of stray xset
330 # data.  Sigh.
331 #
332 #       # cat the file so that we can nuke it without racing against xv.
333 #        cat $tmp_ppm2 | xv $xvargs - &
334
335         pid=$!
336       fi
337     fi
338
339     clean
340     sleep $delay
341
342   done
343   exit 1
344 }
345
346 main $@
347
348 # to find stray xv data:
349 # xwininfo -root -children|grep 'xv image comments' | awk '{print "xkill -id ", $1}'