Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 236 lines (187 sloc) 5.78 KB
#!/usr/bin/env perl
# TODO:
# - command queuing via file
# - (supply file like --cmd-file=/tmp/timelapse_cmd) which contains
# a list of gphoto shell commands to execute
use strict;
use warnings;
use File::Basename;
use Getopt::Long;
use File::Copy;
use IPC::Open3;
use IO::Select;
use Time::HiRes qw/usleep alarm/;
my %defaults = (
"destination" => 'img',
"cmd_file" => '/tmp/gphoto_cmd',
"dump_file" => 'dump.jpg',
"file_mask" => 'cap_%06d.jpg',
"interval" => 15, # Lowest realistic
"timeout" => 60,
"seq_start" => 1,
);
my %opts = %defaults;
my $pid;
my $sel;
my $captured;
my @cmd_init = ('set-config capture=1', # Capture mode (must be first config opt)
'set-config imagequality=2', # Superfine
'set-config imagesize=0', # 0=Large 1=Med1 2=Med2 3=Small
'set-config whitebalance=0', # Auto
'set-config photoeffect=0', # 0=None
'set-config capturetarget=0', # 0=RAM, 1=CF
'set-config flashmode=0', # 0=Off 1=Auto 2=On 3=Fill 4=Auto
'set-config zoom=0',
'set-config meteringmode=1', # 0=Center 1=Spot 2=Evaluative
'set-config focusingpoint=0', # Center
'set-config afdistance=0', # 0=Auto 1=Near 2=Far
'set-config assistlight=1', # 0=Off 1=On
'set-config shutterspeed=0', # 0=Auto
'set-config iso=4', # 4=Auto
'set-config aperture=0'); # Auto
my @cmd_shot = ('set-config focuslock=1', # 0=Lock 1=Unlock
'capture-image-and-download');
sub help {
printf("Usage: %s [args]
--destination destination path (default '%s')
--cmd-file command queue file (default '%s')
--dump-file temporary capture filename (default '%s')
--file-mask output sequence file mask (default '%s')
--interval capture interval in seconds(default '%d')
--timeout capture timeout in seconds (default '%d')
--seq-start start sequence value (default '%d')
",
basename($0),
$defaults{destination},
$defaults{cmd_file},
$defaults{dump_file},
$defaults{file_mask},
$defaults{interval},
$defaults{timeout},
$defaults{seq_start});
exit;
}
sub canon_send_seq {
my ($sel, @cmds) = @_;
my $t_beg = time();
foreach my $cmd (@cmds) {
print "<< $cmd\n";
print WRITE "$cmd\n";
my $read = 0;
while($read == 0) {
my @ready = $$sel->can_read;
foreach my $h (@ready) {
my $buf = '';
if ($h eq \*ERROR) {
sysread(ERROR, $buf, 4096);
$read++;
if($buf) {
print "\e[36m>> $buf\e[39m"
}
} else {
sysread(READ, $buf, 4096);
$read++;
if($buf) {
print "\e[36m>> $buf\e[39m"
}
}
}
}
}
my $t_end = time();
my $t_duration = $t_end - $t_beg;
printf("* Sequence took %d seconds\n",
$t_duration);
}
sub stop {
$SIG{INT} = \&stop;
canon_send_seq(\$sel, 'quit');
waitpid($pid, 0);
exit;
}
sub capture_timeout {
$SIG{ALRM} = \&capture_timeout;
$captured = 0;
print "* Capture timed out!\n";
}
my $result = GetOptions ("destination=s" => \$opts{destination},
"cmd-file=s" => \$opts{cmd_file},
"dump-file=s" => \$opts{dump_file},
"file-mask=s" => \$opts{file_mask},
"interval=i" => \$opts{interval},
"timeout=i" => \$opts{timeout},
"seq-start=i" => \$opts{seq_start},
"help" => \&help);
$opts{cmd_shell} = 'gphoto2 --shell --filename "' . $opts{dump_file} . '"';
$SIG{INT} = \&stop;
$SIG{ALRM} = \&capture_timeout;
die "* Destination path \"" . $opts{destination} . "\" doesn't exist.\n\n"
if ! -d $opts{destination};
$sel = new IO::Select();
$pid = open3(\*WRITE, \*READ,\*ERROR, $opts{cmd_shell});
$sel->add(\*READ);
$sel->add(\*ERROR);
print "* Initializing\n";
canon_send_seq(\$sel, @cmd_init);
my $seq = $opts{seq_start};
for(;;) {
my $t_beg = time();
print "* Capturing\n";
canon_send_seq(\$sel, @cmd_shot);
alarm($opts{timeout});
printf("* Waiting for captured image\n");
$captured = 1;
while($captured) {
if(-f $opts{dump_file}) {
$captured = 0;
next;
}
usleep(100000);
}
alarm(0);
my $file_dst = sprintf("%s/cap_%06d.jpg", $opts{destination}, $seq);
if(! move($opts{dump_file}, $file_dst)) {
# FIXME This might turn out to be fatal if the pipe died
printf("\e[31m* Error: move \"%s\" -> \"%s\" failed\e[39m\n",
$opts{dump_file},
$file_dst);
# print "* Re-initializing\n";
# my $t_beg = time();
# canon_send_seq(\$sel, @cmd_init);
} else {
printf("\e[32m* Stored \"%s\"\e[39m\n",
$file_dst);
$seq++;
}
my $t_duration = time() - $t_beg;
my $t_remain = $t_duration - $opts{interval};
print "* Capture took $t_duration seconds\n";
if($t_remain > 0) {
print "\e[33m* $t_remain seconds behind!\e[39m\n";
} elsif($t_remain < 0) {
$t_remain = abs($t_remain);
if($t_remain >= 2) {
if(-f $opts{cmd_file}) {
my @cmds = ();
open F, '<', $opts{cmd_file};
push @cmds, $_ for <F>;
close F;
unlink $opts{cmd_file};
print "* Executing " . @cmds . " commands from \"$opts{cmd_file}\"";
my $tt_beg = time();
canon_send_seq(\$sel, @cmds);
my $tt_duration = time() - $tt_beg;
my $tt_remain = $tt_duration - 2;
if($tt_duration - 2 > 0) { # We're behind again, damnit
print "\e[33m* $tt_remain seconds behind from additional commands\e[39m\n";
$t_remain = 0;
} else {
print "* Adjusting delay by $tt_duration seconds\e[39m\n";
$t_remain -= $tt_duration;
}
}
}
print "* $t_remain seconds until next capture\n";
sleep($t_remain);
}
}