32117ff23589e7cd60bc7ab24277a19a5fcaf72f
[xscreensaver] / driver / xscreensaver-getimage-video
1 #!/usr/bin/perl -w
2 # Copyright © 2001-2008 Jamie Zawinski <jwz@jwz.org>.
3 #
4 # Permission to use, copy, modify, distribute, and sell this software and its
5 # documentation for any purpose is hereby granted without fee, provided that
6 # the above copyright notice appear in all copies and that both that
7 # copyright notice and this permission notice appear in supporting
8 # documentation.  No representations are made about the suitability of this
9 # software for any purpose.  It is provided "as is" without express or 
10 # implied warranty.
11 #
12 # This program attempts to grab a single frame of video from the system's
13 # video capture card, and then load it on to the root window using the
14 # "xscreensaver-getimage-file" program.  Various frame-grabbing programs
15 # are known, and the first one found is used.
16 #
17 # The various xscreensaver hacks that manipulate images ("slidescreen",
18 # "jigsaw", etc.) get the image to manipulate by running the
19 # "xscreensaver-getimage" program.
20 #
21 # "xscreensaver-getimage" will invoke this program, depending on the
22 # value of the "grabVideoFrames" setting in the ~/.xscreensaver file
23 # (or in /usr/lib/X11/app-defaults/XScreenSaver).
24 #
25 # Created: 13-Apr-2001.
26
27 require 5;
28 #use diagnostics;       # Fails on some MacOS 10.5 systems
29 use strict;
30
31 my $progname = $0; $progname =~ s@.*/@@g;
32 my $version  = q{ $Revision: 1.18 $ }; $version =~ s/^[^0-9]+([0-9.]+).*$/$1/;
33
34 my $tmpdir   = $ENV{TMPDIR} || "/tmp";
35 my $tmpfile  = sprintf("%s/xssv.%08x.ppm", $tmpdir, rand(0xFFFFFFFF));
36
37 my $verbose           = 0;
38 my $use_stdout_p      = 0;
39 my $return_filename_p = 0;
40
41
42 # These are programs that can be used to grab a video frame.  The first one
43 # of these programs that exists on $PATH will be used, and the image file
44 # is assumed to be written to $tmpfile (in some image format acceptable to
45 # "xscreensaver-getimage-file", e.g., PPM or JPEG.)
46 #
47 # If you add other programs to this list, please let me know!
48 #
49 my @programs = (
50
51   "bttvgrab -d q -Q -l 1 -o ppm -f $tmpfile",   # BTTV
52   "qcam > $tmpfile",                            # Connectix Qcam
53   "gqcam -t PPM -d $tmpfile",                   # GTK+ Qcam clone
54
55   "v4lctl snap ppm full $tmpfile",              # XawTV 3.94.
56
57   "streamer -a -s 768x576 -o $tmpfile",         # XawTV
58   #   the "-a" option ("mute audio") arrived with XawTV 3.76.
59
60   "atitv snap $tmpfile",                        # ATI video capture card
61
62   "grab -type ppm -format ntsc -source 1 " .    # *BSD BT848 module
63         "-settle 0.75 -output $tmpfile",
64
65   "motioneye -j $tmpfile",                      # Sony Vaio MotionEye
66                                                 # (hardware jpeg encoder)
67
68   "vidcat -b -f ppm -s 640x480 > $tmpfile 2>-", # w3cam/ovcam
69
70   "vidtomem -f $tmpfile 2>&- " .                # Silicon Graphics
71         "&& mv $tmpfile-00000.rgb $tmpfile",
72 );
73
74
75 sub error($) {
76   my ($e) = @_;
77   print STDERR "$progname: $e\n";
78   exit 1;
79 }
80
81 sub pick_grabber() {
82   my @names = ();
83
84   foreach my $cmd (@programs) {
85     $_ = $cmd;
86     my ($name) = m/^([^ ]+)/;
87     push @names, "\"$name\"";
88     print STDERR "$progname: looking for $name...\n" if ($verbose > 2);
89     foreach my $dir (split (/:/, $ENV{PATH})) {
90       print STDERR "$progname:   checking $dir/$name\n" if ($verbose > 3);
91       if (-x "$dir/$name") {
92         return $cmd;
93       }
94     }
95   }
96
97   $names[$#names] = "or " . $names[$#names];
98   error ("none of: " . join (", ", @names) . " were found on \$PATH.");
99 }
100
101
102 sub grab_image() {
103   my $cmd = pick_grabber();
104   unlink $tmpfile;
105
106   print STDERR "$progname: executing \"$cmd\"\n" if ($verbose);
107   system ($cmd);
108
109   if (-z $tmpfile)
110     {
111       unlink $tmpfile;
112       error ("\"$cmd\" produced no data.");
113     }
114
115   if ($return_filename_p) {
116     print STDERR "$progname: wrote \"$tmpfile\"\n" if ($verbose);
117     print STDOUT "$tmpfile\n";
118
119   } elsif ($use_stdout_p) {
120     local *IN;
121     my $ppm = "";
122     my $reader  = "<$tmpfile";
123
124     # horrid kludge for SGIs, since they don't use PPM...
125     if ($cmd =~ m/^vidtomem\s/) {
126       $reader = "sgitopnm $tmpfile";
127       $reader .= " 2>/dev/null" if ($verbose <= 1);
128       $reader .= " |";
129     }
130
131     open(IN, $reader) || error ("reading $tmpfile: $!");
132     print STDERR "$progname: reading $tmpfile\n" if ($verbose > 1);
133     while (<IN>) { $ppm .= $_; }
134     close IN;
135     unlink $tmpfile;
136     print STDOUT $ppm;
137
138   } else {
139
140     $cmd = "xscreensaver-getimage-file";
141     $cmd .= " --verbose" if ($verbose);
142     $cmd .= " $tmpfile";
143
144     print STDERR "$progname: executing \"$cmd\"\n" if ($verbose);
145     system ($cmd);
146
147     unlink $tmpfile;
148   }
149 }
150
151
152 sub usage() {
153   print STDERR "usage: $progname [--verbose] [--name | --stdout]\n";
154   exit 1;
155 }
156
157 sub main() {
158   while ($_ = $ARGV[0]) {
159     shift @ARGV;
160     if ($_ eq "--verbose") { $verbose++; }
161     elsif (m/^-v+$/) { $verbose += length($_)-1; }
162     elsif (m/^--?stdout$/) { $use_stdout_p = 1; }
163     elsif (m/^--?name$/)   { $return_filename_p = 1; }
164     elsif (m/^-./) { usage; }
165     else { usage; }
166   }
167
168   grab_image();
169 }
170
171 main;
172 exit 0;