Merge pull request #815 from onlyjob/PBP

last batch of POD and readability conversions for *.pl scripts
This commit is contained in:
Isaac Connor 2015-04-16 11:53:19 -04:00
commit e69fee1c94
8 changed files with 1381 additions and 1102 deletions

View File

@ -16,12 +16,12 @@ LOCKFILE=/var/lock/subsys/zm
loadconf() loadconf()
{ {
if [ -f $ZM_CONFIG ]; then if [ -f $ZM_CONFIG ]; then
. $ZM_CONFIG . $ZM_CONFIG
else else
echo "ERROR: $ZM_CONFIG not found." echo "ERROR: $ZM_CONFIG not found."
return 1 return 1
fi fi
} }
loadconf loadconf
@ -30,95 +30,95 @@ command="$ZM_PATH_BIN/zmpkg.pl"
start() start()
{ {
# Commenting out as it is not needed. Leaving as a placeholder for future use. # Commenting out as it is not needed. Leaving as a placeholder for future use.
# zmupdate || return $? # zmupdate || return $?
loadconf || return $? loadconf || return $?
#Make sure the directory for our PID folder exists or create one. #Make sure the directory for our PID folder exists or create one.
[ ! -d $pidfile ] \ [ ! -d $pidfile ] \
&& mkdir -m 774 $pidfile \ && mkdir -m 774 $pidfile \
&& chown $ZM_WEB_USER:$ZM_WEB_GROUP $pidfile && chown $ZM_WEB_USER:$ZM_WEB_GROUP $pidfile
#Make sure the folder for the socks file exists or create one #Make sure the folder for the socks file exists or create one
GetPath="select Value from Config where Name='ZM_PATH_SOCKS'" GetPath="select Value from Config where Name='ZM_PATH_SOCKS'"
dbHost=`echo $ZM_DB_HOST | cut -d: -f1` dbHost=`echo $ZM_DB_HOST | cut -d: -f1`
dbPort=`echo $ZM_DB_HOST | cut -d: -s -f2` dbPort=`echo $ZM_DB_HOST | cut -d: -s -f2`
if [ "$dbPort" = "" ] if [ "$dbPort" = "" ]
then then
ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$ZM_DB_HOST -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'` ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$ZM_DB_HOST -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'`
else else
ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$dbHost -P$dbPort -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'` ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$dbHost -P$dbPort -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'`
fi fi
[ ! -d $ZM_PATH_SOCK ] \ [ ! -d $ZM_PATH_SOCK ] \
&& mkdir -m 774 $ZM_PATH_SOCK \ && mkdir -m 774 $ZM_PATH_SOCK \
&& chown $ZM_WEB_USER:$ZM_WEB_GROUP $ZM_PATH_SOCK && chown $ZM_WEB_USER:$ZM_WEB_GROUP $ZM_PATH_SOCK
echo -n $"Starting $prog: " echo -n $"Starting $prog: "
$command start $command start
RETVAL=$? RETVAL=$?
[ $RETVAL = 0 ] && success || failure [ $RETVAL = 0 ] && success || failure
echo echo
[ $RETVAL = 0 ] && touch $LOCKFILE [ $RETVAL = 0 ] && touch $LOCKFILE
return $RETVAL return $RETVAL
} }
stop() stop()
{ {
loadconf loadconf
echo -n $"Stopping $prog: " echo -n $"Stopping $prog: "
$command stop $command stop
RETVAL=$? RETVAL=$?
[ $RETVAL = 0 ] && success || failure [ $RETVAL = 0 ] && success || failure
echo echo
[ $RETVAL = 0 ] && rm -f $LOCKFILE [ $RETVAL = 0 ] && rm -f $LOCKFILE
} }
zmstatus() zmstatus()
{ {
loadconf loadconf
result=`$command status` result=`$command status`
if [ "$result" = "running" ]; then if [ "$result" = "running" ]; then
echo "ZoneMinder is running" echo "ZoneMinder is running"
$ZM_PATH_BIN/zmu -l $ZM_PATH_BIN/zmu -l
RETVAL=0 RETVAL=0
else else
echo "ZoneMinder is stopped" echo "ZoneMinder is stopped"
RETVAL=1 RETVAL=1
fi fi
} }
zmupdate() zmupdate()
{ {
if [ -x $ZM_PATH_BIN/zmupdate.pl ]; then if [ -x $ZM_PATH_BIN/zmupdate.pl ]; then
$ZM_PATH_BIN/zmupdate.pl -f $ZM_PATH_BIN/zmupdate.pl -f
fi fi
} }
case "$1" in case "$1" in
'start') 'start')
start start
;; ;;
'stop') 'stop')
stop stop
;; ;;
'restart') 'restart')
stop stop
start start
;; ;;
'condrestart') 'condrestart')
loadconf loadconf
result=`$ZM_PATH_BIN/zmdc.pl check` result=`$ZM_PATH_BIN/zmdc.pl check`
if [ "$result" = "running" ]; then if [ "$result" = "running" ]; then
$ZM_PATH_BIN/zmdc.pl shutdown > /dev/null $ZM_PATH_BIN/zmdc.pl shutdown > /dev/null
rm -f $LOCKFILE rm -f $LOCKFILE
start start
fi fi
;; ;;
'status') 'status')
status httpd status httpd
status mysqld status mysqld
zmstatus zmstatus
;; ;;
*) *)
echo "Usage: $0 { start | stop | restart | condrestart | status }" echo "Usage: $0 { start | stop | restart | condrestart | status }"
RETVAL=1 RETVAL=1
;; ;;
esac esac
exit $RETVAL exit $RETVAL

View File

@ -2,7 +2,7 @@
# #
# ========================================================================== # ==========================================================================
# #
# ZoneMinder Update Script, $Date$, $Revision$ # ZoneMinder systemctl wrapper, $Date$, $Revision$
# Copyright (C) 2001-2008 Philip Coombes # Copyright (C) 2001-2008 Philip Coombes
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
@ -20,25 +20,39 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# #
# ========================================================================== # ==========================================================================
#
# This is a wrapper script that allows zoneminder to start and stop itself =head1 NAME
# in a manner that keeps it in-sync with systemd. This script is intended
# to be called internally by zoneminder and may not give the desired results zmsystemctl.pl - ZoneMinder systemctl wrapper
# if run from the command line.
# =head1 SYNOPSIS
zmsystemctl.pl {start|stop|restart|version}
=head1 DESCRIPTION
This is a wrapper script that allows zoneminder to start and stop itself
in a manner that keeps it in-sync with systemd. This script is intended
to be called internally by zoneminder and may not give the desired results
if run from the command line.
=cut
use warnings; use warnings;
use strict; use strict;
use bytes; use bytes;
use autouse 'Pod::Usage'=>qw(pod2usage);
@EXTRA_PERL_LIB@ @EXTRA_PERL_LIB@
use ZoneMinder::Logger qw(:all); use ZoneMinder::Logger qw(:all);
my $command = $ARGV[0]; my $command = $ARGV[0];
if ( (scalar(@ARGV) == 1) && ($command =~ /^(start|stop|restart|version)$/ )) { if ( (scalar(@ARGV) == 1)
$command = $1; && ($command =~ /^(start|stop|restart|version)$/ )
){
$command = $1;
} else { } else {
die(" USAGE: zmsystemctl.pl <start|stop|restart|version>\n"); pod2usage(-exitstatus => -1);
} }
my $path = qx(which systemctl); my $path = qx(which systemctl);
@ -46,7 +60,7 @@ chomp($path);
my $status = $? >> 8; my $status = $? >> 8;
if ( !$path || $status ) { if ( !$path || $status ) {
Fatal( "Unable to determine systemctl executable. Is systemd in use?" ); Fatal( "Unable to determine systemctl executable. Is systemd in use?" );
} }
Info( "Redirecting command through systemctl\n" ); Info( "Redirecting command through systemctl\n" );

View File

@ -20,10 +20,26 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# #
# ========================================================================== # ==========================================================================
#
# This script is used to trigger and cancel alarms from external sources =head1 NAME
# using an arbitrary text based format
# zmtrack.pl - ZoneMinder Experimental PTZ Tracking Script
=head1 SYNOPSIS
zmtrack.pl -m <monitor>
zmtrack.pl --monitor=<monitor>
=head1 OPTIONS
-m<monitor>, --monitor=<monitor> - Id of the monitor to track
=head1 DESCRIPTION
This script is used to trigger and cancel alarms from external sources
using an arbitrary text based format.
=cut
use strict; use strict;
use bytes; use bytes;
@ -45,8 +61,9 @@ use constant SLEEP_TIME => 10000; # In microseconds
use ZoneMinder; use ZoneMinder;
use DBI; use DBI;
use POSIX; use POSIX;
use Data::Dumper; use autouse 'Data::Dumper'=>qw(Dumper);
use Getopt::Long; use Getopt::Long;
use autouse 'Pod::Usage'=>qw(pod2usage);
use Time::HiRes qw( usleep ); use Time::HiRes qw( usleep );
$| = 1; $| = 1;
@ -57,20 +74,8 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
my $mid = 0; my $mid = 0;
sub Usage GetOptions( 'monitor=s'=>\$mid )
{ or pod2usage(-exitstatus => -1);
print( "
Usage: zmtrack.pl -m <monitor>,--monitor=<monitor>]
Parameters are :-
-m<monitor>, --monitor=<monitor> - Id of the monitor to track
");
exit( -1 );
}
if ( !GetOptions( 'monitor=s'=>\$mid ) )
{
Usage();
}
logInit(); logInit();
logSetSignal(); logSetSignal();
@ -78,44 +83,52 @@ logSetSignal();
my ( $detaint_mid ) = $mid =~ /^(\d+)$/; my ( $detaint_mid ) = $mid =~ /^(\d+)$/;
$mid = $detaint_mid; $mid = $detaint_mid;
print( "Tracker daemon $mid (experimental) starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" ); print( "Tracker daemon $mid (experimental) starting at "
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
."\n"
);
my $dbh = zmDbConnect(); my $dbh = zmDbConnect();
my $sql = "select C.*,M.* from Monitors as M left join Controls as C on M.ControlId = C.Id where M.Id = ?"; my $sql = "SELECT C.*,M.* FROM Monitors as M
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); LEFT JOIN Controls as C on M.ControlId = C.Id
WHERE M.Id = ?"
;
my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( $mid ) or Fatal( "Can't execute '$sql': ".$sth->errstr() ); my $res = $sth->execute( $mid )
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
my $monitor = $sth->fetchrow_hashref(); my $monitor = $sth->fetchrow_hashref();
if ( !$monitor ) if ( !$monitor )
{ {
print( "Can't find monitor '$mid'\n" ); print( "Can't find monitor '$mid'\n" );
exit( -1 ); exit( -1 );
} }
if ( !$monitor->{Controllable} ) if ( !$monitor->{Controllable} )
{ {
print( "Monitor '$mid' is not controllable\n" ); print( "Monitor '$mid' is not controllable\n" );
exit( -1 ); exit( -1 );
} }
if ( !$monitor->{TrackMotion} ) if ( !$monitor->{TrackMotion} )
{ {
print( "Monitor '$mid' is not configured to track motion\n" ); print( "Monitor '$mid' is not configured to track motion\n" );
exit( -1 ); exit( -1 );
} }
if ( !$monitor->{CanMoveMap} ) if ( !$monitor->{CanMoveMap} )
{ {
print( "Monitor '$mid' cannot move in map mode" ); print( "Monitor '$mid' cannot move in map mode" );
if ( $monitor->{CanMoveRel} ) if ( $monitor->{CanMoveRel} )
{ {
print( ", falling back to pseudo map mode\n" ); print( ", falling back to pseudo map mode\n" );
} }
else else
{ {
print( "\n" ); print( "\n" );
exit( -1 ); exit( -1 );
} }
} }
Debug( "Found monitor for id '$monitor'\n" ); Debug( "Found monitor for id '$monitor'\n" );
@ -123,84 +136,100 @@ exit( -1 ) if ( !zmMemVerify( $monitor ) );
sub Suspend sub Suspend
{ {
my $monitor = shift; my $monitor = shift;
zmMonitorSuspend( $monitor ); zmMonitorSuspend( $monitor );
} }
sub Resume sub Resume
{ {
my $monitor = shift; my $monitor = shift;
sleep( $monitor->{TrackDelay} ); sleep( $monitor->{TrackDelay} );
zmMonitorResume( $monitor ); zmMonitorResume( $monitor );
} }
sub Track sub Track
{ {
my $monitor = shift; my $monitor = shift;
my ( $x, $y ) = @_; my ( $x, $y ) = @_;
my ( $detaint_x ) = $x =~ /^(\d+)$/; $x = $detaint_x; my ( $detaint_x ) = $x =~ /^(\d+)$/; $x = $detaint_x;
my ( $detaint_y ) = $y =~ /^(\d+)$/; $y = $detaint_y; my ( $detaint_y ) = $y =~ /^(\d+)$/; $y = $detaint_y;
my $ctrlCommand = $Config{ZM_PATH_BIN}."/zmcontrol.pl -i ".$monitor->{Id}; my $ctrlCommand = $Config{ZM_PATH_BIN}
$ctrlCommand .= " --command=".($monitor->{CanMoveMap}?"moveMap":"movePseudoMap")." --xcoord=$x --ycoord=$y"; ."/zmcontrol.pl -i "
executeShellCommand( $ctrlCommand ); .$monitor->{Id}
;
$ctrlCommand .= " --command="
.( $monitor->{CanMoveMap} ? "moveMap"
: "movePseudoMap"
)
." --xcoord=$x --ycoord=$y"
;
executeShellCommand( $ctrlCommand );
} }
sub Return sub Return
{ {
my $monitor = shift; my $monitor = shift;
my $ctrlCommand = $Config{ZM_PATH_BIN}."/zmcontrol.pl -i ".$monitor->{Id}; my $ctrlCommand = $Config{ZM_PATH_BIN}
if ( $monitor->{ReturnLocation} > 0 ) ."/zmcontrol.pl -i "
{ .$monitor->{Id}
$ctrlCommand .= " --command=presetGoto --preset=".$monitor->{ReturnLocation}; ;
} if ( $monitor->{ReturnLocation} > 0 )
else {
{ $ctrlCommand .= " --command=presetGoto --preset="
$ctrlCommand .= " --command=presetHome"; .$monitor->{ReturnLocation}
} ;
executeShellCommand( $ctrlCommand ); }
else
{
$ctrlCommand .= " --command=presetHome";
}
executeShellCommand( $ctrlCommand );
} }
my $last_alarm = 0; my $last_alarm = 0;
if ( ($monitor->{ReturnLocation} >= 0) ) if ( ($monitor->{ReturnLocation} >= 0) )
{ {
Suspend( $monitor ); Suspend( $monitor );
Return( $monitor ); Return( $monitor );
Resume( $monitor ); Resume( $monitor );
} }
my $alarmed = undef; my $alarmed = undef;
while( 1 ) while( 1 )
{ {
if ( zmIsAlarmed( $monitor ) ) if ( zmIsAlarmed( $monitor ) )
{ {
my ( $alarm_x, $alarm_y ) = zmGetAlarmLocation( $monitor ); my ( $alarm_x, $alarm_y ) = zmGetAlarmLocation( $monitor );
if ( $alarm_x >= 0 && $alarm_y >= 0 ) if ( $alarm_x >= 0 && $alarm_y >= 0 )
{ {
Debug( "Got alarm at $alarm_x, $alarm_y\n" ); Debug( "Got alarm at $alarm_x, $alarm_y\n" );
Suspend( $monitor ); Suspend( $monitor );
Track( $monitor, $alarm_x, $alarm_y ); Track( $monitor, $alarm_x, $alarm_y );
Resume( $monitor ); Resume( $monitor );
$last_alarm = time(); $last_alarm = time();
$alarmed = !undef; $alarmed = !undef;
} }
} }
else else
{ {
if ( logDebugging() && $alarmed ) if ( logDebugging() && $alarmed )
{ {
print( "Left alarm state\n" ); print( "Left alarm state\n" );
$alarmed = undef; $alarmed = undef;
} }
if ( ($monitor->{ReturnLocation} >= 0) && ($last_alarm > 0) && ((time()-$last_alarm) > $monitor->{ReturnDelay}) ) if ( ($monitor->{ReturnLocation} >= 0)
{ && ($last_alarm > 0)
Debug( "Returning to location ".$monitor->{ReturnLocation}."\n" ); && ((time()-$last_alarm) > $monitor->{ReturnDelay})
Suspend( $monitor ); )
Return( $monitor ); {
Resume( $monitor ); Debug( "Returning to location ".$monitor->{ReturnLocation}."\n" );
$last_alarm = 0; Suspend( $monitor );
} Return( $monitor );
} Resume( $monitor );
usleep( SLEEP_TIME ); $last_alarm = 0;
}
}
usleep( SLEEP_TIME );
} }

View File

@ -20,11 +20,17 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# #
# ========================================================================== # ==========================================================================
#
# This script is used to trigger and cancel alarms from external connections =head1 NAME
# using an arbitrary text based format
# zmtrigger.pl - ZoneMinder External Trigger Script
# ==========================================================================
=head1 DESCRIPTION
This script is used to trigger and cancel alarms from external connections
using an arbitrary text based format
=cut
use strict; use strict;
use bytes; use bytes;
@ -52,8 +58,22 @@ use ZoneMinder::Trigger::Channel::Serial;
use ZoneMinder::Trigger::Connection; use ZoneMinder::Trigger::Connection;
my @connections; my @connections;
push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan1", channel=>ZoneMinder::Trigger::Channel::Inet->new( port=>6802 ), mode=>"rw" ) ); push( @connections,
push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan2", channel=>ZoneMinder::Trigger::Channel::Unix->new( path=>$Config{ZM_PATH_SOCKS}.'/zmtrigger.sock' ), mode=>"rw" ) ); ZoneMinder::Trigger::Connection->new(
name=>"Chan1",
channel=>ZoneMinder::Trigger::Channel::Inet->new( port=>6802 ),
mode=>"rw"
)
);
push( @connections,
ZoneMinder::Trigger::Connection->new(
name=>"Chan2",
channel=>ZoneMinder::Trigger::Channel::Unix->new(
path=>$Config{ZM_PATH_SOCKS}.'/zmtrigger.sock'
),
mode=>"rw"
)
);
#push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan3", channel=>ZoneMinder::Trigger::Channel::File->new( path=>'/tmp/zmtrigger.out' ), mode=>"w" ) ); #push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan3", channel=>ZoneMinder::Trigger::Channel::File->new( path=>'/tmp/zmtrigger.out' ), mode=>"w" ) );
#push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan4", channel=>ZoneMinder::Trigger::Channel::Serial->new( path=>'/dev/ttyS0' ), mode=>"rw" ) ); #push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan4", channel=>ZoneMinder::Trigger::Channel::Serial->new( path=>'/dev/ttyS0' ), mode=>"rw" ) );
@ -65,7 +85,7 @@ push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan2", channel
use DBI; use DBI;
#use Socket; #use Socket;
use Data::Dumper; use autouse 'Data::Dumper'=>qw(Dumper);
use POSIX qw( EINTR ); use POSIX qw( EINTR );
use Time::HiRes qw( usleep ); use Time::HiRes qw( usleep );
@ -85,8 +105,8 @@ my $dbh = zmDbConnect();
my $base_rin = ''; my $base_rin = '';
foreach my $connection ( @connections ) foreach my $connection ( @connections )
{ {
Info( "Opening connection '$connection->{name}'\n" ); Info( "Opening connection '$connection->{name}'\n" );
$connection->open(); $connection->open();
} }
my @in_select_connections = grep { $_->input() && $_->selectable() } @connections; my @in_select_connections = grep { $_->input() && $_->selectable() } @connections;
@ -95,7 +115,7 @@ my @out_connections = grep { $_->output() } @connections;
foreach my $connection ( @in_select_connections ) foreach my $connection ( @in_select_connections )
{ {
vec( $base_rin, $connection->fileno(), 1 ) = 1; vec( $base_rin, $connection->fileno(), 1 ) = 1;
} }
my %spawned_connections; my %spawned_connections;
@ -111,332 +131,387 @@ my $timeout = SELECT_TIMEOUT;
my %actions; my %actions;
while( 1 ) while( 1 )
{ {
$rin = $base_rin; $rin = $base_rin;
# Add the file descriptors of any spawned connections # Add the file descriptors of any spawned connections
foreach my $fileno ( keys(%spawned_connections) ) foreach my $fileno ( keys(%spawned_connections) )
{ {
vec( $rin, $fileno, 1 ) = 1; vec( $rin, $fileno, 1 ) = 1;
} }
my $nfound = select( my $rout = $rin, undef, my $eout = $ein, $timeout ); my $nfound = select( my $rout = $rin, undef, my $eout = $ein, $timeout );
if ( $nfound > 0 ) if ( $nfound > 0 )
{ {
Debug( "Got input from $nfound connections\n" ); Debug( "Got input from $nfound connections\n" );
foreach my $connection ( @in_select_connections ) foreach my $connection ( @in_select_connections )
{ {
if ( vec( $rout, $connection->fileno(), 1 ) ) if ( vec( $rout, $connection->fileno(), 1 ) )
{ {
Debug( "Got input from connection ".$connection->name()." (".$connection->fileno().")\n" ); Debug( "Got input from connection "
if ( $connection->spawns() ) .$connection->name()
{ ." ("
my $new_connection = $connection->accept(); .$connection->fileno()
$spawned_connections{$new_connection->fileno()} = $new_connection; .")\n"
Debug( "Added new spawned connection (".$new_connection->fileno()."), ".int(keys(%spawned_connections))." spawned connections\n" ); );
} if ( $connection->spawns() )
else {
{ my $new_connection = $connection->accept();
my $messages = $connection->getMessages(); $spawned_connections{$new_connection->fileno()} = $new_connection;
if ( defined($messages) ) Debug( "Added new spawned connection ("
{ .$new_connection->fileno()
foreach my $message ( @$messages ) ."), "
{ .int(keys(%spawned_connections))
handleMessage( $connection, $message ); ." spawned connections\n"
} );
} }
} else
} {
} my $messages = $connection->getMessages();
foreach my $connection ( values(%spawned_connections) ) if ( defined($messages) )
{ {
if ( vec( $rout, $connection->fileno(), 1 ) ) foreach my $message ( @$messages )
{ {
Debug( "Got input from spawned connection ".$connection->name()." (".$connection->fileno().")\n" ); handleMessage( $connection, $message );
my $messages = $connection->getMessages(); }
if ( defined($messages) ) }
{ }
foreach my $message ( @$messages ) }
{ }
handleMessage( $connection, $message ); foreach my $connection ( values(%spawned_connections) )
} {
} if ( vec( $rout, $connection->fileno(), 1 ) )
else {
{ Debug( "Got input from spawned connection "
delete( $spawned_connections{$connection->fileno()} ); .$connection->name()
Debug( "Removed spawned connection (".$connection->fileno()."), ".int(keys(%spawned_connections))." spawned connections\n" ); ." ("
$connection->close(); .$connection->fileno()
} .")\n"
} );
} my $messages = $connection->getMessages();
} if ( defined($messages) )
elsif ( $nfound < 0 ) {
{ foreach my $message ( @$messages )
if ( $! == EINTR ) {
{ handleMessage( $connection, $message );
# Do nothing }
} }
else else
{ {
Fatal( "Can't select: $!" ); delete( $spawned_connections{$connection->fileno()} );
} Debug( "Removed spawned connection ("
} .$connection->fileno()
."), "
.int(keys(%spawned_connections))
." spawned connections\n"
);
$connection->close();
}
}
}
}
elsif ( $nfound < 0 )
{
if ( $! == EINTR )
{
# Do nothing
}
else
{
Fatal( "Can't select: $!" );
}
}
# Check polled connections # Check polled connections
foreach my $connection ( @in_poll_connections ) foreach my $connection ( @in_poll_connections )
{ {
my $messages = $connection->getMessages(); my $messages = $connection->getMessages();
if ( defined($messages) ) if ( defined($messages) )
{ {
foreach my $message ( @$messages ) foreach my $message ( @$messages )
{ {
handleMessage( $connection, $message ); handleMessage( $connection, $message );
} }
} }
} }
# Check for alarms that might have happened # Check for alarms that might have happened
my @out_messages; my @out_messages;
foreach my $monitor ( values(%monitors) ) foreach my $monitor ( values(%monitors) )
{ {
my ( $state, $last_event ) = zmMemRead( $monitor, [ "shared_data:state", "shared_data:last_event" ] ); my ( $state, $last_event )
= zmMemRead( $monitor,
[ "shared_data:state",
"shared_data:last_event"
]
);
#print( "$monitor->{Id}: S:$state, LE:$last_event\n" ); #print( "$monitor->{Id}: S:$state, LE:$last_event\n" );
#print( "$monitor->{Id}: mS:$monitor->{LastState}, mLE:$monitor->{LastEvent}\n" ); #print( "$monitor->{Id}: mS:$monitor->{LastState}, mLE:$monitor->{LastEvent}\n" );
if ( $state == STATE_ALARM || $state == STATE_ALERT ) # In alarm state if ( $state == STATE_ALARM
{ || $state == STATE_ALERT
if ( !defined($monitor->{LastEvent}) || ($last_event != $monitor->{LastEvent}) ) # A new event ) # In alarm state
{ {
push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event ); if ( !defined($monitor->{LastEvent})
} || ($last_event != $monitor->{LastEvent})
else # The same one as last time, so ignore it ) # A new event
{ {
# Do nothing push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event );
} }
} else # The same one as last time, so ignore it
elsif ( ($state == STATE_IDLE && $monitor->{LastState} != STATE_IDLE) || ($state == STATE_TAPE && $monitor->{LastState} != STATE_TAPE) ) # Out of alarm state {
{ # Do nothing
push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event ); }
} }
elsif ( defined($monitor->{LastEvent}) && ($last_event != $monitor->{LastEvent}) ) # We've missed a whole event elsif ( ($state == STATE_IDLE
{ && $monitor->{LastState} != STATE_IDLE
push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event ); )
push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event ); || ($state == STATE_TAPE
} && $monitor->{LastState} != STATE_TAPE
$monitor->{LastState} = $state; )
$monitor->{LastEvent} = $last_event; ) # Out of alarm state
} {
foreach my $connection ( @out_connections ) push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event );
{ }
if ( $connection->canWrite() ) elsif ( defined($monitor->{LastEvent})
{ && ($last_event != $monitor->{LastEvent})
$connection->putMessages( \@out_messages ); ) # We've missed a whole event
} {
} push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event );
foreach my $connection ( values(%spawned_connections) ) push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event );
{ }
if ( $connection->canWrite() ) $monitor->{LastState} = $state;
{ $monitor->{LastEvent} = $last_event;
$connection->putMessages( \@out_messages ); }
} foreach my $connection ( @out_connections )
} {
if ( $connection->canWrite() )
{
$connection->putMessages( \@out_messages );
}
}
foreach my $connection ( values(%spawned_connections) )
{
if ( $connection->canWrite() )
{
$connection->putMessages( \@out_messages );
}
}
Debug( "Checking for timed actions\n" ) if ( int(keys(%actions)) ); Debug( "Checking for timed actions\n" )
my $now = time(); if ( int(keys(%actions)) );
foreach my $action_time ( sort( grep { $_ < $now } keys( %actions ) ) ) my $now = time();
{ foreach my $action_time ( sort( grep { $_ < $now } keys( %actions ) ) )
Info( "Found actions expiring at $action_time\n" ); {
foreach my $action ( @{$actions{$action_time}} ) Info( "Found actions expiring at $action_time\n" );
{ foreach my $action ( @{$actions{$action_time}} )
my $connection = $action->{connection}; {
my $message = $action->{message}; my $connection = $action->{connection};
Info( "Found action '$message'\n" ); my $message = $action->{message};
handleMessage( $connection, $message ); Info( "Found action '$message'\n" );
} handleMessage( $connection, $message );
delete( $actions{$action_time} ); }
} delete( $actions{$action_time} );
}
# Allow connections to do their own timed actions # Allow connections to do their own timed actions
foreach my $connection ( @connections ) foreach my $connection ( @connections )
{ {
my $messages = $connection->timedActions(); my $messages = $connection->timedActions();
if ( defined($messages) ) if ( defined($messages) )
{ {
foreach my $message ( @$messages ) foreach my $message ( @$messages )
{ {
handleMessage( $connection, $message ); handleMessage( $connection, $message );
} }
} }
} }
foreach my $connection ( values(%spawned_connections) ) foreach my $connection ( values(%spawned_connections) )
{ {
my $messages = $connection->timedActions(); my $messages = $connection->timedActions();
if ( defined($messages) ) if ( defined($messages) )
{ {
foreach my $message ( @$messages ) foreach my $message ( @$messages )
{ {
handleMessage( $connection, $message ); handleMessage( $connection, $message );
} }
} }
} }
# If necessary reload monitors # If necessary reload monitors
if ( (time() - $monitor_reload_time) > MONITOR_RELOAD_INTERVAL ) if ( (time() - $monitor_reload_time) > MONITOR_RELOAD_INTERVAL )
{ {
foreach my $monitor ( values(%monitors) ) foreach my $monitor ( values(%monitors) )
{ {
# Free up any used memory handle # Free up any used memory handle
zmMemInvalidate( $monitor ); zmMemInvalidate( $monitor );
} }
loadMonitors(); loadMonitors();
} }
} }
Info( "Trigger daemon exiting\n" ); Info( "Trigger daemon exiting\n" );
exit; exit;
sub loadMonitors sub loadMonitors
{ {
Debug( "Loading monitors\n" ); Debug( "Loading monitors\n" );
$monitor_reload_time = time(); $monitor_reload_time = time();
my %new_monitors = (); my %new_monitors = ();
my $sql = "select * from Monitors where find_in_set( Function, 'Modect,Mocord,Nodect' )"; my $sql = "SELECT * FROM Monitors
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); WHERE find_in_set( Function, 'Modect,Mocord,Nodect' )"
my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() ); ;
while( my $monitor = $sth->fetchrow_hashref() ) my $sth = $dbh->prepare_cached( $sql )
{ or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
next if ( !zmMemVerify( $monitor ) ); # Check shared memory ok my $res = $sth->execute()
or Fatal( "Can't execute: ".$sth->errstr() );
while( my $monitor = $sth->fetchrow_hashref() )
{
next if ( !zmMemVerify( $monitor ) ); # Check shared memory ok
if ( defined($monitors{$monitor->{Id}}->{LastState}) ) if ( defined($monitors{$monitor->{Id}}->{LastState}) )
{ {
$monitor->{LastState} = $monitors{$monitor->{Id}}->{LastState}; $monitor->{LastState} = $monitors{$monitor->{Id}}->{LastState};
} }
else else
{ {
$monitor->{LastState} = zmGetMonitorState( $monitor ); $monitor->{LastState} = zmGetMonitorState( $monitor );
} }
if ( defined($monitors{$monitor->{Id}}->{LastEvent}) ) if ( defined($monitors{$monitor->{Id}}->{LastEvent}) )
{ {
$monitor->{LastEvent} = $monitors{$monitor->{Id}}->{LastEvent}; $monitor->{LastEvent} = $monitors{$monitor->{Id}}->{LastEvent};
} }
else else
{ {
$monitor->{LastEvent} = zmGetLastEvent( $monitor ); $monitor->{LastEvent} = zmGetLastEvent( $monitor );
} }
$new_monitors{$monitor->{Id}} = $monitor; $new_monitors{$monitor->{Id}} = $monitor;
} }
%monitors = %new_monitors; %monitors = %new_monitors;
} }
sub handleMessage sub handleMessage
{ {
my $connection = shift; my $connection = shift;
my $message = shift; my $message = shift;
my ( $id, $action, $score, $cause, $text, $showtext ) = split( /\|/, $message ); my ( $id, $action, $score, $cause, $text, $showtext )
$score = 0 if ( !defined($score) ); = split( /\|/, $message );
$cause = "" if ( !defined($cause) ); $score = 0 if ( !defined($score) );
$text = "" if ( !defined($text) ); $cause = "" if ( !defined($cause) );
$text = "" if ( !defined($text) );
my $monitor = $monitors{$id}; my $monitor = $monitors{$id};
if ( !$monitor ) if ( !$monitor )
{ {
Warning( "Can't find monitor '$id' for message '$message'\n" ); Warning( "Can't find monitor '$id' for message '$message'\n" );
return; return;
} }
Debug( "Found monitor for id '$id'\n" ); Debug( "Found monitor for id '$id'\n" );
next if ( !zmMemVerify( $monitor ) ); next if ( !zmMemVerify( $monitor ) );
Debug( "Handling action '$action'\n" ); Debug( "Handling action '$action'\n" );
if ( $action =~ /^(enable|disable)(?:\+(\d+))?$/ ) if ( $action =~ /^(enable|disable)(?:\+(\d+))?$/ )
{ {
my $state = $1; my $state = $1;
my $delay = $2; my $delay = $2;
if ( $state eq "enable" ) if ( $state eq "enable" )
{ {
zmMonitorEnable( $monitor ); zmMonitorEnable( $monitor );
} }
else else
{ {
zmMonitorDisable( $monitor ); zmMonitorDisable( $monitor );
} }
# Force a reload # Force a reload
$monitor_reload_time = 0; $monitor_reload_time = 0;
Info( "Set monitor to $state\n" ); Info( "Set monitor to $state\n" );
if ( $delay ) if ( $delay )
{ {
my $action_time = time()+$delay; my $action_time = time()+$delay;
my $action_text = $id."|".(($state eq "enable")?"disable":"enable"); my $action_text = $id."|".( ($state eq "enable")
my $action_array = $actions{$action_time}; ? "disable"
if ( !$action_array ) : "enable"
{ )
$action_array = $actions{$action_time} = []; ;
} my $action_array = $actions{$action_time};
push( @$action_array, { connection=>$connection, message=>$action_text } ); if ( !$action_array )
Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" ); {
} $action_array = $actions{$action_time} = [];
} }
elsif ( $action =~ /^(on|off)(?:\+(\d+))?$/ ) push( @$action_array, { connection=>$connection,
{ message=>$action_text
next if ( !$monitor->{Enabled} ); }
);
Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" );
}
}
elsif ( $action =~ /^(on|off)(?:\+(\d+))?$/ )
{
next if ( !$monitor->{Enabled} );
my $trigger = $1; my $trigger = $1;
my $delay = $2; my $delay = $2;
my $trigger_data; my $trigger_data;
if ( $trigger eq "on" ) if ( $trigger eq "on" )
{ {
zmTriggerEventOn( $monitor, $score, $cause, $text ); zmTriggerEventOn( $monitor, $score, $cause, $text );
zmTriggerShowtext( $monitor, $showtext ) if defined($showtext); zmTriggerShowtext( $monitor, $showtext ) if defined($showtext);
Info( "Trigger '$trigger' '$cause'\n" ); Info( "Trigger '$trigger' '$cause'\n" );
} }
elsif ( $trigger eq "off" ) elsif ( $trigger eq "off" )
{ {
my $last_event = zmGetLastEvent( $monitor ); my $last_event = zmGetLastEvent( $monitor );
zmTriggerEventOff( $monitor ); zmTriggerEventOff( $monitor );
zmTriggerShowtext( $monitor, $showtext ) if defined($showtext); zmTriggerShowtext( $monitor, $showtext ) if defined($showtext);
Info( "Trigger '$trigger'\n" ); Info( "Trigger '$trigger'\n" );
# Wait til it's finished # Wait til it's finished
while( zmInAlarm( $monitor ) && ($last_event == zmGetLastEvent( $monitor )) ) while( zmInAlarm( $monitor )
&& ($last_event == zmGetLastEvent( $monitor ))
)
{ {
# Tenth of a second # Tenth of a second
usleep( 100000 ); usleep( 100000 );
} }
zmTriggerEventCancel( $monitor ); zmTriggerEventCancel( $monitor );
} }
else else
{ {
Info( "Trigger '$trigger'\n" ); Info( "Trigger '$trigger'\n" );
zmTriggerEventCancel( $monitor ); zmTriggerEventCancel( $monitor );
} }
if ( $delay ) if ( $delay )
{ {
my $action_time = time()+$delay; my $action_time = time()+$delay;
#my $action_text = $id."|cancel|0|".$cause."|".$text; #my $action_text = $id."|cancel|0|".$cause."|".$text;
my $action_text = $id."|cancel"; my $action_text = $id."|cancel";
my $action_array = $actions{$action_time}; my $action_array = $actions{$action_time};
if ( !$action_array ) if ( !$action_array )
{ {
$action_array = $actions{$action_time} = []; $action_array = $actions{$action_time} = [];
} }
push( @$action_array, { connection=>$connection, message=>$action_text } ); push( @$action_array, { connection=>$connection,
Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" ); message=>$action_text
} }
} );
elsif( $action eq "cancel" ) Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" );
{ }
zmTriggerEventCancel( $monitor ); }
zmTriggerShowtext( $monitor, $showtext ) if defined($showtext); elsif( $action eq "cancel" )
Info( "Cancelled event\n" ); {
} zmTriggerEventCancel( $monitor );
elsif( $action eq "show" ) zmTriggerShowtext( $monitor, $showtext ) if defined($showtext);
{ Info( "Cancelled event\n" );
zmTriggerShowtext( $monitor, $showtext ); }
Info( "Updated show text to '$showtext'\n" ); elsif( $action eq "show" )
} {
else zmTriggerShowtext( $monitor, $showtext );
{ Info( "Updated show text to '$showtext'\n" );
Error( "Unrecognised action '$action' in message '$message'\n" ); }
} else
{
Error( "Unrecognised action '$action' in message '$message'\n" );
}
} # end sub handleMessage } # end sub handleMessage
1; 1;

View File

@ -76,7 +76,7 @@ use POSIX;
use DBI; use DBI;
use Getopt::Long; use Getopt::Long;
use autouse 'Pod::Usage'=>qw(pod2usage); use autouse 'Pod::Usage'=>qw(pod2usage);
use Data::Dumper; use autouse 'Data::Dumper'=>qw(Dumper);
use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)?$Config{ZM_DIR_EVENTS}:($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS}); use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)?$Config{ZM_DIR_EVENTS}:($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS});

View File

@ -20,10 +20,37 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# #
# ========================================================================== # ==========================================================================
#
# This script is used to create MPEG videos of events for the web pages =head1 NAME
# or as email attachments.
# zmvideo.pl - ZoneMinder Video Creation Script
=head1 SYNOPSIS
zmvideo.pl -e <event_id>,--event=<event_id> [--format <format>]
[--rate=<rate>]
[--scale=<scale>]
[--fps=<fps>]
[--size=<size>]
[--overwrite]
=head1 DESCRIPTION
This script is used to create MPEG videos of events for the web pages
or as email attachments.
=head1 OPTIONS
-e<event_id>, --event=<event_id> - What event to create the video for
-f<format>, --format=<format> - What format to create the video in, default is mpg. For ffmpeg only.
-r<rate>, --rate=<rate> - Relative rate, 1 = realtime, 2 = double speed, 0.5 = half speed etc.
-s<scale>, --scale=<scale> - Scale, 1 = normal, 2 = double size, 0.5 = half size etc.
-F<fps>, --fps=<fps> - Absolute frame rate, in frames per second
-S<size>, --size=<size> - Absolute video size, WxH or other specification supported by ffmpeg
-o, --overwrite - Whether to overwrite an existing file, off by default.
-v, --version - Outputs the currently installed version of ZoneMinder
=cut
use strict; use strict;
use bytes; use bytes;
@ -36,9 +63,10 @@ use bytes;
@EXTRA_PERL_LIB@ @EXTRA_PERL_LIB@
use ZoneMinder; use ZoneMinder;
use DBI; use DBI;
use Data::Dumper; use autouse 'Data::Dumper'=>qw(Dumper);
use POSIX qw(strftime); use POSIX qw(strftime);
use Getopt::Long qw(:config no_ignore_case ); use Getopt::Long qw(:config no_ignore_case );
use autouse 'Pod::Usage'=>qw(pod2usage);
$| = 1; $| = 1;
@ -60,77 +88,66 @@ my $version = 0;
my @formats = split( /\s+/, $Config{ZM_FFMPEG_FORMATS} ); my @formats = split( /\s+/, $Config{ZM_FFMPEG_FORMATS} );
for ( my $i = 0; $i < @formats; $i++ ) for ( my $i = 0; $i < @formats; $i++ )
{ {
if ( $i =~ /^(.+)\*$/ ) if ( $i =~ /^(.+)\*$/ )
{ {
$format = $formats[$i] = $1; $format = $formats[$i] = $1;
} }
} }
sub Usage GetOptions(
{ 'event=i' =>\$event_id,
print( " 'format|f=s' =>\$format,
Usage: zmvideo.pl -e <event_id>,--event=<event_id> [--format <format>] [--rate=<rate>] [--scale=<scale>] [--fps=<fps>] [--size=<size>] [--overwrite] 'rate|r=f' =>\$rate,
Parameters are :- 'scale|s=f' =>\$scale,
-e<event_id>, --event=<event_id> - What event to create the video for 'fps|F=f' =>\$fps,
-f<format>, --format=<format> - What format to create the video in, default is mpg. For ffmpeg only. 'size|S=s' =>\$size,
-r<rate>, --rate=<rate> - Relative rate , 1 = realtime, 2 = double speed , 0.5 = half speed etc 'overwrite' =>\$overwrite,
-s<scale>, --scale=<scale> - Scale, 1 = normal, 2 = double size, 0.5 = half size etc 'version' =>\$version
-F<fps>, --fps=<fps> - Absolute frame rate, in frames per second ) or pod2usage(-exitstatus => -1);
-S<size>, --size=<size> - Absolute video size, WxH or other specification supported by ffmpeg
-o, --overwrite - Whether to overwrite an existing file, off by default.
-v, --version - Outputs the currently installed version of ZoneMinder
");
exit( -1 );
}
if ( !GetOptions( 'event=i'=>\$event_id, 'format|f=s'=>\$format, 'rate|r=f'=>\$rate, 'scale|s=f'=>\$scale, 'fps|F=f'=>\$fps, 'size|S=s'=>\$size, 'overwrite'=>\$overwrite, version=>\$version ) )
{
Usage();
}
if ( $version ) { if ( $version ) {
print ZoneMinder::Base::ZM_VERSION . "\n"; print ZoneMinder::Base::ZM_VERSION . "\n";
exit(0); exit(0);
} }
if ( !$event_id || $event_id < 0 ) if ( !$event_id || $event_id < 0 )
{ {
print( STDERR "Please give a valid event id\n" ); print( STDERR "Please give a valid event id\n" );
Usage(); pod2usage(-exitstatus => -1);
} }
if ( ! $Config{ZM_OPT_FFMPEG} ) if ( ! $Config{ZM_OPT_FFMPEG} )
{ {
print( STDERR "Mpeg encoding is not currently enabled\n" ); print( STDERR "Mpeg encoding is not currently enabled\n" );
exit(-1); exit(-1);
} }
if ( !$rate && !$fps ) if ( !$rate && !$fps )
{ {
$rate = 1; $rate = 1;
} }
if ( !$scale && !$size ) if ( !$scale && !$size )
{ {
$scale = 1; $scale = 1;
} }
if ( $rate && ($rate < 0.25 || $rate > 100) ) if ( $rate && ($rate < 0.25 || $rate > 100) )
{ {
print( STDERR "Rate is out of range, 0.25 >= rate <= 100\n" ); print( STDERR "Rate is out of range, 0.25 >= rate <= 100\n" );
Usage(); pod2usage(-exitstatus => -1);
} }
if ( $scale && ($scale < 0.25 || $scale > 4) ) if ( $scale && ($scale < 0.25 || $scale > 4) )
{ {
print( STDERR "Scale is out of range, 0.25 >= scale <= 4\n" ); print( STDERR "Scale is out of range, 0.25 >= scale <= 4\n" );
Usage(); pod2usage(-exitstatus => -1);
} }
if ( $fps && ($fps > 30) ) if ( $fps && ($fps > 30) )
{ {
print( STDERR "FPS is out of range, <= 30\n" ); print( STDERR "FPS is out of range, <= 30\n" );
Usage(); pod2usage(-exitstatus => -1);
} }
my ( $detaint_format ) = $format =~ /^(\w+)$/; my ( $detaint_format ) = $format =~ /^(\w+)$/;
@ -148,9 +165,23 @@ $size = $detaint_size;
my $dbh = zmDbConnect(); my $dbh = zmDbConnect();
my @filters; my @filters;
my $sql = "select max(F.Delta)-min(F.Delta) as FullLength, E.*, unix_timestamp(E.StartTime) as Time, M.Name as MonitorName, M.Width as MonitorWidth, M.Height as MonitorHeight, M.Palette from Frames as F inner join Events as E on F.EventId = E.Id inner join Monitors as M on E.MonitorId = M.Id where EventId = '$event_id' group by F.EventId"; my $sql = " SELECT max(F.Delta)-min(F.Delta) as FullLength,
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); E.*,
my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() ); unix_timestamp(E.StartTime) as Time,
M.Name as MonitorName,
M.Width as MonitorWidth,
M.Height as MonitorHeight,
M.Palette
FROM Frames as F
INNER JOIN Events as E on F.EventId = E.Id
INNER JOIN Monitors as M on E.MonitorId = M.Id
WHERE EventId = '$event_id'
GROUP BY F.EventId"
;
my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute()
or Fatal( "Can't execute: ".$sth->errstr() );
my $event = $sth->fetchrow_hashref(); my $event = $sth->fetchrow_hashref();
$sth->finish(); $sth->finish();
my $event_path = getEventPath( $event ); my $event_path = getEventPath( $event );
@ -160,42 +191,42 @@ chdir( $event_path );
my @file_parts; my @file_parts;
if ( $rate ) if ( $rate )
{ {
my $file_rate = $rate; my $file_rate = $rate;
$file_rate =~ s/\./_/; $file_rate =~ s/\./_/;
$file_rate =~ s/_00//; $file_rate =~ s/_00//;
$file_rate =~ s/(_\d+)0+$/$1/; $file_rate =~ s/(_\d+)0+$/$1/;
$file_rate = 'r'.$file_rate; $file_rate = 'r'.$file_rate;
push( @file_parts, $file_rate ); push( @file_parts, $file_rate );
} }
elsif ( $fps ) elsif ( $fps )
{ {
my $file_fps = $fps; my $file_fps = $fps;
$file_fps =~ s/\./_/; $file_fps =~ s/\./_/;
$file_fps =~ s/_00//; $file_fps =~ s/_00//;
$file_fps =~ s/(_\d+)0+$/$1/; $file_fps =~ s/(_\d+)0+$/$1/;
$file_fps = 'R'.$file_fps; $file_fps = 'R'.$file_fps;
push( @file_parts, $file_fps ); push( @file_parts, $file_fps );
} }
if ( $scale ) if ( $scale )
{ {
my $file_scale = $scale; my $file_scale = $scale;
$file_scale =~ s/\./_/; $file_scale =~ s/\./_/;
$file_scale =~ s/_00//; $file_scale =~ s/_00//;
$file_scale =~ s/(_\d+)0+$/$1/; $file_scale =~ s/(_\d+)0+$/$1/;
$file_scale = 's'.$file_scale; $file_scale = 's'.$file_scale;
push( @file_parts, $file_scale ); push( @file_parts, $file_scale );
} }
elsif ( $size ) elsif ( $size )
{ {
my $file_size = 'S'.$size; my $file_size = 'S'.$size;
push( @file_parts, $file_size ); push( @file_parts, $file_size );
} }
my $video_file = "$video_name-".$file_parts[0]."-".$file_parts[1].".$format"; my $video_file = "$video_name-".$file_parts[0]."-".$file_parts[1].".$format";
if ( $overwrite || !-s $video_file ) if ( $overwrite || !-s $video_file )
{ {
Info( "Creating video file $video_file for event $event->{Id}\n" ); Info( "Creating video file $video_file for event $event->{Id}\n" );
my $frame_rate = sprintf( "%.2f", $event->{Frames}/$event->{FullLength} ); my $frame_rate = sprintf( "%.2f", $event->{Frames}/$event->{FullLength} );
if ( $rate ) if ( $rate )
@ -228,22 +259,32 @@ if ( $overwrite || !-s $video_file )
$video_size = $size; $video_size = $size;
} }
my $command = $Config{ZM_PATH_FFMPEG}." -y -r $frame_rate ".$Config{ZM_FFMPEG_INPUT_OPTIONS}." -i %0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg -s $video_size ".$Config{ZM_FFMPEG_OUTPUT_OPTIONS}." '$video_file' > ffmpeg.log 2>&1"; my $command = $Config{ZM_PATH_FFMPEG}
." -y -r $frame_rate "
.$Config{ZM_FFMPEG_INPUT_OPTIONS}
." -i %0"
.$Config{ZM_EVENT_IMAGE_DIGITS}
."d-capture.jpg -s $video_size "
.$Config{ZM_FFMPEG_OUTPUT_OPTIONS}
." '$video_file' > ffmpeg.log 2>&1"
;
Debug( $command."\n" ); Debug( $command."\n" );
my $output = qx($command); my $output = qx($command);
my $status = $? >> 8; my $status = $? >> 8;
if ( $status ) if ( $status )
{ {
Error( "Unable to generate video, check ".$event_path."/ffmpeg.log for details" ); Error( "Unable to generate video, check "
.$event_path."/ffmpeg.log for details"
);
exit( -1 ); exit( -1 );
} }
Info( "Finished $video_file\n" ); Info( "Finished $video_file\n" );
} }
else else
{ {
Info( "Video file $video_file already exists for event $event->{Id}\n" ); Info( "Video file $video_file already exists for event $event->{Id}\n" );
} }
#print( STDOUT $event->{MonitorId}.'/'.$event->{Id}.'/'.$video_file."\n" ); #print( STDOUT $event->{MonitorId}.'/'.$event->{Id}.'/'.$video_file."\n" );
print( STDOUT $video_file."\n" ); print( STDOUT $video_file."\n" );

View File

@ -20,11 +20,22 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# #
# ========================================================================== # ==========================================================================
#
# This does some basic setup for ZoneMinder to run and then periodically =head1 NAME
# checks the fps output of the active daemons to check they haven't
# locked up. If they have then they are killed and restarted zmwatch.pl - ZoneMinder WatchDog Script
#
=head1 SYNOPSIS
zmwatch.pl
=head1 DESCRIPTION
This does some basic setup for ZoneMinder to run and then periodically
checks the fps output of the active daemons to check they haven't
locked up. If they have then they are killed and restarted
=cut
use strict; use strict;
use bytes; use bytes;
@ -46,7 +57,7 @@ use constant START_DELAY => 30; # To give everything else time to start
use ZoneMinder; use ZoneMinder;
use POSIX; use POSIX;
use DBI; use DBI;
use Data::Dumper; use autouse 'Data::Dumper'=>qw(Dumper);
$| = 1; $| = 1;
@ -54,14 +65,6 @@ $ENV{PATH} = '/bin:/usr/bin';
$ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL}; $ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL};
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
sub Usage
{
print( "
Usage: zmwatch.pl
");
exit( -1 );
}
logInit(); logInit();
logSetSignal(); logSetSignal();
@ -72,38 +75,49 @@ sleep( START_DELAY );
my $dbh = zmDbConnect(); my $dbh = zmDbConnect();
my $sql = "select * from Monitors"; my $sql = "select * from Monitors";
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
while( 1 ) while( 1 )
{ {
my $now = time(); my $now = time();
my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() ); my $res = $sth->execute()
while( my $monitor = $sth->fetchrow_hashref() ) or Fatal( "Can't execute: ".$sth->errstr() );
{ while( my $monitor = $sth->fetchrow_hashref() )
if ( $monitor->{Function} ne 'None' ) {
{ if ( $monitor->{Function} ne 'None' )
{
my $restart = 0; my $restart = 0;
if ( zmMemVerify( $monitor ) && zmMemRead( $monitor, "shared_data:valid" ) ) if ( zmMemVerify( $monitor )
{ && zmMemRead( $monitor, "shared_data:valid" )
# Check we have got an image recently )
my $image_time = zmGetLastWriteTime( $monitor ); {
next if ( !defined($image_time) ); # Can't read from shared data # Check we have got an image recently
next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died. my $image_time = zmGetLastWriteTime( $monitor );
next if ( !defined($image_time) ); # Can't read from shared data
next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died.
my $max_image_delay = ($monitor->{MaxFPS}&&($monitor->{MaxFPS}>0)&&($monitor->{MaxFPS}<1))?(3/$monitor->{MaxFPS}):$Config{ZM_WATCH_MAX_DELAY}; my $max_image_delay = ( $monitor->{MaxFPS}
my $image_delay = $now-$image_time; &&($monitor->{MaxFPS}>0)
Debug( "Monitor $monitor->{Id} last captured $image_delay seconds ago, max is $max_image_delay\n" ); &&($monitor->{MaxFPS}<1)
if ( $image_delay > $max_image_delay ) ) ? (3/$monitor->{MaxFPS})
{ : $Config{ZM_WATCH_MAX_DELAY}
Info( "Restarting capture daemon for ".$monitor->{Name}.", time since last capture $image_delay seconds ($now-$image_time)\n" ); ;
my $image_delay = $now-$image_time;
Debug( "Monitor $monitor->{Id} last captured $image_delay seconds ago, max is $max_image_delay\n" );
if ( $image_delay > $max_image_delay )
{
Info( "Restarting capture daemon for "
.$monitor->{Name}.", time since last capture $image_delay seconds ($now-$image_time)\n"
);
$restart = 1; $restart = 1;
} }
} }
else else
{ {
#Info( "Restarting capture daemon for ".$monitor->{Name}.", shared data not valid\n" ); #Info( "Restarting capture daemon for ".$monitor->{Name}.", shared data not valid\n" );
#$restart = 1; #$restart = 1;
} }
if ( $restart ) if ( $restart )
{ {
@ -120,19 +134,28 @@ while( 1 )
} }
elsif ( $monitor->{Function} ne 'Monitor' ) elsif ( $monitor->{Function} ne 'Monitor' )
{ {
if ( zmMemVerify( $monitor ) && zmMemRead( $monitor, "shared_data:valid" ) ) if ( zmMemVerify( $monitor )
&& zmMemRead( $monitor, "shared_data:valid" )
)
{ {
# Check we have got an image recently # Check we have got an image recently
my $image_time = zmGetLastReadTime( $monitor ); my $image_time = zmGetLastReadTime( $monitor );
next if ( !defined($image_time) ); # Can't read from shared data next if ( !defined($image_time) ); # Can't read from shared data
next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died. next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died.
my $max_image_delay = ($monitor->{MaxFPS}&&($monitor->{MaxFPS}>0)&&($monitor->{MaxFPS}<1))?(3/$monitor->{MaxFPS}):$Config{ZM_WATCH_MAX_DELAY}; my $max_image_delay = ( $monitor->{MaxFPS}
&&($monitor->{MaxFPS}>0)
&&($monitor->{MaxFPS}<1)
) ? (3/$monitor->{MaxFPS})
: $Config{ZM_WATCH_MAX_DELAY}
;
my $image_delay = $now-$image_time; my $image_delay = $now-$image_time;
Debug( "Monitor $monitor->{Id} last analysed $image_delay seconds ago, max is $max_image_delay\n" ); Debug( "Monitor $monitor->{Id} last analysed $image_delay seconds ago, max is $max_image_delay\n" );
if ( $image_delay > $max_image_delay ) if ( $image_delay > $max_image_delay )
{ {
Info( "Restarting analysis daemon for ".$monitor->{Name}.", time since last analysis $image_delay seconds ($now-$image_time)\n" ); Info( "Restarting analysis daemon for "
.$monitor->{Name}.", time since last analysis $image_delay seconds ($now-$image_time)\n"
);
my $command = "zmdc.pl restart zma -m ".$monitor->{Id}; my $command = "zmdc.pl restart zma -m ".$monitor->{Id};
runCommand( $command ); runCommand( $command );
} }
@ -141,8 +164,8 @@ while( 1 )
} }
# Prevent open handles building up if we have connect to shared memory # Prevent open handles building up if we have connect to shared memory
zmMemInvalidate( $monitor ); zmMemInvalidate( $monitor );
} }
sleep( $Config{ZM_WATCH_CHECK_INTERVAL} ); sleep( $Config{ZM_WATCH_CHECK_INTERVAL} );
} }
Info( "Watchdog exiting\n" ); Info( "Watchdog exiting\n" );
exit(); exit();

File diff suppressed because it is too large Load Diff