3 # vidwhacker, for xscreensaver. Copyright (c) 1998, 1999 Jamie Zawinski.
5 # Permission to use, copy, modify, distribute, and sell this software and its
6 # documentation for any purpose is hereby granted without fee, provided that
7 # the above copyright notice appear in all copies and that both that
8 # copyright notice and this permission notice appear in supporting
9 # documentation. No representations are made about the suitability of this
10 # software for any purpose. It is provided "as is" without express or
14 # This script grabs a frame of video, then uses various pbm filters to
15 # munge the image in random nefarious ways, then uses xv to put it on
16 # the root window. This works out really nicely if you just feed some
17 # random TV station into it...
19 # The video grabbing part is SGI-specific -- if you want to use this on
20 # another system, add a new clause to the grab() procedure.
23 # Process command-line args...
32 tmp=${TMPDIR:-/tmp}/vidwhacker.$$
33 tmp_rgb=$tmp-00000.rgb
46 -display | -disp | -dis | -dpy | -d )
71 echo "VidWhacker, Copyright (c) 1999 Jamie Zawinski <jwz@jwz.org>" >&2
72 echo " http://www.jwz.org/xscreensaver/" >&2
74 echo "usage: $0 [-display dpy] [-verbose] [-root | -window]" >&2
75 echo " [-stdin] [-stdout] [-delay secs]" >&2
84 if [ "$onroot" = true ]; then
85 xvargs="$xvargs -root -rmode 5 -noresetroot -rfg black -rbg black -viewonly"
87 xvargs="$xvargs -geom +0+0"
92 if [ "$use_stdout" = false ]; then
93 screen_width=`xdpyinfo 2>/dev/null |
94 sed -n 's/.* dimensions: *\([0-9]*\).*/\1/p'`
95 if [ "$screen_width" = "" ]; then
103 rm -f $tmp_rgb $tmp_ppm1 $tmp_ppm2 $tmp_ppm3 $tmp_ppm4
108 rm -f $tmp_ppm0 $tmp_ppmS
112 # Grab a frame of video. leaves it in $tmp_ppm1.
116 if [ $uname = IRIX ]; then
118 # SGI's "vidtomem" returns an SGI RGB image of the default video input,
119 # and has stupid non-overridable ouput-file-naming conventions. So, let
120 # it write its file; and then convert it to a pgm.
124 sgitopnm $tmp_rgb > $tmp_ppm1
126 # Cut off the close-captioning blips in the NTSC overscan region. YMMV.
127 # | pnmcut 12 7 695 477
129 elif [ $uname = Linux ]; then
131 # Marcus Herbert says the following works with his Connectix Qcam.
132 # Don't have qcam? Well, do something else then... and send me a patch.
136 # Friedrich Delgado Friedrichs says the following works with a
137 # Brooktree 848 or 878 tuner card:
139 # bttvgrab -Q -d q -l 1 -F /dev/null -o gif -f ${tmp}.gif -N PAL
140 # giftopnm ${tmp}.gif > $tmp_ppm1
143 # He notes that you might need to run a TV application (e.g., xawtv)
144 # before the first time you run vidwhacker in order to initialize the
145 # tuner card and kernel modules.
149 echo "$0: don't know how to grab video on this OS." >&2
156 # Use perl to pick a random foreground/background color in pbm's syntax.
160 printf("#%02x%02x%02x-#%02x%02x%02x",
166 120+int(rand()*135))'
169 # Frobnicate the image in some random way.
173 w_h=`head -2 $tmp_ppm1 | tail -1`
174 width=`echo $w_h | awk '{print $1}'`
175 height=`echo $w_h | awk '{print $2}'`
177 N=`perl -e 'srand; print int(rand() * 17)'`
179 if [ "$verbose" = true ]; then
180 echo "mode $N..." >&2
184 ppmtopgm $tmp_ppm1 | pgmedge | pgmtoppm `randcolor` | ppmnorm
186 elif [ $N = 1 ]; then
191 elif [ $N = 2 ]; then
192 ppmtopgm $tmp_ppm1 | pgmoil | pgmtoppm `randcolor`
194 elif [ $N = 3 ]; then
195 ppmrelief $tmp_ppm1 | ppmtopgm | pgmedge | ppmrelief | ppmtopgm |
196 pgmedge | pnminvert | pgmtoppm `randcolor`
198 elif [ $N = 4 ]; then
199 ppmspread 71 $tmp_ppm1 > $tmp_ppm2
200 pnmarith -add $tmp_ppm1 $tmp_ppm2
202 elif [ $N = 5 ]; then
203 pnmflip -lr $tmp_ppm1 > $tmp_ppm2
204 pnmarith -multiply $tmp_ppm1 $tmp_ppm2 > $tmp_ppm3
205 pnmflip -tb $tmp_ppm3 | ppmnorm > $tmp_ppm2
206 pnmarith -multiply $tmp_ppm1 $tmp_ppm2
208 elif [ $N = 6 ]; then
209 N2=`perl -e 'srand; print int(rand() * 3)'`
211 pnmflip -lr $tmp_ppm1 > $tmp_ppm2
212 elif [ $N2 = 1 ]; then
213 pnmflip -tb $tmp_ppm1 > $tmp_ppm2
215 pnmflip -lr $tmp_ppm1 > $tmp_ppm2
216 pnmflip -tb $tmp_ppm2 > $tmp_ppm3
217 cp $tmp_ppm3 $tmp_ppm2
220 pnmarith -difference $tmp_ppm1 $tmp_ppm2
222 elif [ $N = 7 ]; then
225 ppmtopgm $tmp_ppm1 | pgmedge > $tmp_ppm2
226 pnmarith -difference $tmp_ppm1 $tmp_ppm2 > $tmp_ppm3
227 cp $tmp_ppm3 $tmp_ppm1
231 elif [ $N = 8 ]; then
232 pnmflip -lr $tmp_ppm1 > $tmp_ppm2
233 pnmarith -multiply $tmp_ppm1 $tmp_ppm2 | ppmrelief | ppmnorm | pnminvert
235 elif [ $N = 9 ]; then
236 pnmflip -lr $tmp_ppm1 > $tmp_ppm2
237 pnmarith -subtract $tmp_ppm1 $tmp_ppm2 | ppmrelief | ppmtopgm | pgmedge
239 elif [ $N = 10 ]; then
240 ppmtopgm $tmp_ppm1 | pgmbentley | pgmtoppm `randcolor`
242 elif [ $N = 11 ]; then
243 pgmcrater -number 20000 -height $height -width $width | pgmtoppm `randcolor` > $tmp_ppm2
244 pnmarith -difference $tmp_ppm1 $tmp_ppm2 > $tmp_ppm3
245 pnmflip -tb $tmp_ppm3 | ppmnorm > $tmp_ppm2
246 pnmarith -multiply $tmp_ppm1 $tmp_ppm2
248 elif [ $N = 12 ]; then
249 ppmshift 30 $tmp_ppm1 | ppmtopgm | pgmoil | pgmedge | pgmtoppm `randcolor` > $tmp_ppm2
250 pnmarith -difference $tmp_ppm1 $tmp_ppm2
252 elif [ $N = 13 ]; then
253 ppmpat -madras $width $height | pnmdepth 255 > $tmp_ppm2
254 pnmarith -difference $tmp_ppm1 $tmp_ppm2
256 elif [ $N = 14 ]; then
257 ppmpat -tartan $width $height | pnmdepth 255 > $tmp_ppm2
258 pnmarith -difference $tmp_ppm1 $tmp_ppm2
260 elif [ $N = 15 ]; then
261 ppmpat -camo $width $height | pnmdepth 255 | ppmshift 50 > $tmp_ppm2
262 pnmarith -multiply $tmp_ppm1 $tmp_ppm2
264 elif [ $N = 16 ]; then
265 pgmnoise $width $height | pgmedge | pgmtoppm `randcolor` > $tmp_ppm2
266 pnmarith -difference $tmp_ppm1 $tmp_ppm2 | pnmdepth 255 | pnmsmooth
273 # Grab a frame and frob it. leave it in $tmp_ppm3.
278 while [ ! -f $tmp_ppm1 ]; do
279 if [ "$use_stdin" != true ]; then
282 cp $tmp_ppmS $tmp_ppm0
283 cp $tmp_ppm0 $tmp_ppm1
289 if [ "$screen_width" != "" ]; then
290 frob | pnmscale -width $screen_width > $tmp_ppm3
295 rm -f $tmp_ppm1 $tmp_ppm2
299 # Kill off the xv subprocess, if it's running
302 if [ "$pid" != "" ]; then
304 if [ "$verbose" = true ]; then
305 echo "killing pid $pid..." >&2
308 # need to do this to avoid "6898 Terminated" messages!
309 # apparently one can't redirect the output of the builtin `kill' command.
310 # ( sh -c "kill $pid" ) >/dev/null 2>/dev/null </dev/null
312 # wtf? that doesn't work either. Is it writing to /dev/tty??
313 kill $pid >/dev/null 2>&1
319 # called when this process is signalled (for cleanup)
322 if [ "$verbose" = true ]; then
323 echo "trapped signal!" >&2
334 trap my_trap 1 2 3 6 9 13 15
336 if [ "$use_stdin" = true ]; then
342 # Loop grabbing and frobbing images.
344 # If we're running on the root, run xv in the foreground (with -exit)
347 # If we're running in a window, spawn xv in the background; then when
348 # it's time to put up the new image, kill off the currently-running xv.
350 if [ "$verbose" = true ]; then
353 whack >/dev/null 2>&1
358 if [ ! -s $tmp_ppm3 ]; then
359 echo "$0: no image grabbed" >&2
361 elif [ "$use_stdout" = true ]; then
369 pnmtosgi < $tmp_ppm3 > $tmp_ppm2
372 if [ -s $tmp_ppm2 ]; then
373 if [ "$verbose" = true ]; then
374 echo "launching xv $xvargs $tmp_ppm2" >&2
378 mv $tmp_ppm2 $tmp_ppm0
379 xv $xvargs $tmp_ppm0 &
381 # this doesn't work -- leaves xv processes around, instead of stray xset
384 # # cat the file so that we can nuke it without racing against xv.
385 # cat $tmp_ppm2 | xv $xvargs - &
400 # to find stray xv data:
401 # xwininfo -root -children|grep 'xv image comments' | awk '{print "xkill -id ", $1}'