Merge branch 'master' of https://github.com/ZoneMinder/ZoneMinder into plugin_support_list
Conflicts: scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in
This commit is contained in:
commit
6b2c435460
|
@ -107,6 +107,8 @@ if [ $1 -eq 0 ] ; then
|
||||||
# Package removal, not upgrade
|
# Package removal, not upgrade
|
||||||
/bin/systemctl --no-reload disable zoneminder.service > /dev/null 2>&1 || :
|
/bin/systemctl --no-reload disable zoneminder.service > /dev/null 2>&1 || :
|
||||||
/bin/systemctl stop zoneminder.service > /dev/null 2>&1 || :
|
/bin/systemctl stop zoneminder.service > /dev/null 2>&1 || :
|
||||||
|
echo -e "\nRemoving ZoneMinder SELinux policy module. Please wait.\n"
|
||||||
|
/usr/sbin/semodule -r local_zoneminder.pp
|
||||||
fi
|
fi
|
||||||
|
|
||||||
%postun
|
%postun
|
||||||
|
@ -128,7 +130,8 @@ fi
|
||||||
|
|
||||||
%files
|
%files
|
||||||
%defattr(-,root,root,-)
|
%defattr(-,root,root,-)
|
||||||
%doc AUTHORS COPYING README.md distros/redhat/README.Centos7 distros/redhat/jscalendar-doc
|
%doc AUTHORS BUGS ChangeLog COPYING LICENSE NEWS README.md distros/redhat/README.Centos7 distros/redhat/jscalendar-doc
|
||||||
|
%doc distros/redhat/cambozola-doc distros/redhat/local_zoneminder.te
|
||||||
%config %attr(640,root,%{zmgid_final}) /etc/zm/zm.conf
|
%config %attr(640,root,%{zmgid_final}) /etc/zm/zm.conf
|
||||||
%config(noreplace) %attr(644,root,root) /etc/httpd/conf.d/zoneminder.conf
|
%config(noreplace) %attr(644,root,root) /etc/httpd/conf.d/zoneminder.conf
|
||||||
%config(noreplace) /etc/tmpfiles.d/zoneminder.conf
|
%config(noreplace) /etc/tmpfiles.d/zoneminder.conf
|
||||||
|
@ -156,7 +159,8 @@ fi
|
||||||
%{_bindir}/zmx10.pl
|
%{_bindir}/zmx10.pl
|
||||||
|
|
||||||
%{perl_vendorlib}/ZoneMinder*
|
%{perl_vendorlib}/ZoneMinder*
|
||||||
%{perl_vendorlib}/%{_arch}-linux-thread-multi/auto/ZoneMinder*
|
%{perl_vendorarch}/auto/ZoneMinder/.packlist
|
||||||
|
#%{perl_vendorlib}/%{_arch}-linux-thread-multi/auto/ZoneMinder*
|
||||||
#%{perl_archlib}/ZoneMinder*
|
#%{perl_archlib}/ZoneMinder*
|
||||||
%{_mandir}/man*/*
|
%{_mandir}/man*/*
|
||||||
%dir %{_libexecdir}/zoneminder
|
%dir %{_libexecdir}/zoneminder
|
||||||
|
|
|
@ -36,34 +36,42 @@ use ZoneMinder::General qw(:all);
|
||||||
use ZoneMinder::Database qw(:all);
|
use ZoneMinder::Database qw(:all);
|
||||||
use ZoneMinder::Memory qw(:all);
|
use ZoneMinder::Memory qw(:all);
|
||||||
|
|
||||||
our @ISA = qw(Exporter ZoneMinder::Base ZoneMinder::Config ZoneMinder::Logger ZoneMinder::General ZoneMinder::Database ZoneMinder::Memory);
|
our @ISA = qw(
|
||||||
|
Exporter
|
||||||
|
ZoneMinder::Base
|
||||||
|
ZoneMinder::Config
|
||||||
|
ZoneMinder::Logger
|
||||||
|
ZoneMinder::General
|
||||||
|
ZoneMinder::Database
|
||||||
|
ZoneMinder::Memory
|
||||||
|
);
|
||||||
|
|
||||||
# Items to export into callers namespace by default. Note: do not export
|
# Items to export into callers namespace by default. Note: do not export
|
||||||
# names by default without a very good reason. Use EXPORT_OK instead.
|
# names by default without a very good reason. Use EXPORT_OK instead.
|
||||||
# Do not simply export all your public functions/methods/constants.
|
# Do not simply export all your public functions/methods/constants.
|
||||||
|
|
||||||
# This allows declaration use ZoneMinder ':all';
|
# This allows declaration use ZoneMinder ':all';
|
||||||
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
||||||
# will save memory.
|
# will save memory.
|
||||||
our %EXPORT_TAGS = (
|
our %EXPORT_TAGS = (
|
||||||
'base' => [
|
'base' => [
|
||||||
@ZoneMinder::Base::EXPORT_OK
|
@ZoneMinder::Base::EXPORT_OK
|
||||||
],
|
],
|
||||||
'config' => [
|
'config' => [
|
||||||
@ZoneMinder::Config::EXPORT_OK
|
@ZoneMinder::Config::EXPORT_OK
|
||||||
],
|
],
|
||||||
'debug' => [
|
'debug' => [
|
||||||
@ZoneMinder::Logger::EXPORT_OK
|
@ZoneMinder::Logger::EXPORT_OK
|
||||||
],
|
],
|
||||||
'general' => [
|
'general' => [
|
||||||
@ZoneMinder::General::EXPORT_OK
|
@ZoneMinder::General::EXPORT_OK
|
||||||
],
|
],
|
||||||
'database' => [
|
'database' => [
|
||||||
@ZoneMinder::Database::EXPORT_OK
|
@ZoneMinder::Database::EXPORT_OK
|
||||||
],
|
],
|
||||||
'memory' => [
|
'memory' => [
|
||||||
@ZoneMinder::Memory::EXPORT_OK
|
@ZoneMinder::Memory::EXPORT_OK
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#
|
#
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
#
|
#
|
||||||
# This module contains the common definitions and functions used by the rest
|
# This module contains the common definitions and functions used by the rest
|
||||||
# of the ZoneMinder scripts
|
# of the ZoneMinder scripts
|
||||||
#
|
#
|
||||||
package ZoneMinder::Base;
|
package ZoneMinder::Base;
|
||||||
|
@ -38,7 +38,7 @@ use constant ZM_VERSION => "@VERSION@";
|
||||||
# names by default without a very good reason. Use EXPORT_OK instead.
|
# names by default without a very good reason. Use EXPORT_OK instead.
|
||||||
# Do not simply export all your public functions/methods/constants.
|
# Do not simply export all your public functions/methods/constants.
|
||||||
|
|
||||||
# This allows declaration use ZoneMinder ':all';
|
# This allows declaration use ZoneMinder ':all';
|
||||||
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
||||||
# will save memory.
|
# will save memory.
|
||||||
our %EXPORT_TAGS = ( 'all' => [ qw(ZM_VERSION) ] );
|
our %EXPORT_TAGS = ( 'all' => [ qw(ZM_VERSION) ] );
|
||||||
|
@ -62,7 +62,11 @@ ZoneMinder::Base - Base perl module for ZoneMinder
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
This module is the base module for the rest of the ZoneMinder modules. It is included by each of the other modules but serves no purpose other than to propagate the perl module version amongst the other modules. You will never need to use this module directly but if you write new ZoneMinder modules they should include it.
|
This module is the base module for the rest of the ZoneMinder modules. It
|
||||||
|
is included by each of the other modules but serves no purpose other than
|
||||||
|
to propagate the perl module version amongst the other modules. You will
|
||||||
|
never need to use this module directly but if you write new ZoneMinder
|
||||||
|
modules they should include it.
|
||||||
|
|
||||||
=head2 EXPORT
|
=head2 EXPORT
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#
|
#
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
#
|
#
|
||||||
# This module contains the common definitions and functions used by the rest
|
# This module contains the common definitions and functions used by the rest
|
||||||
# of the ZoneMinder scripts
|
# of the ZoneMinder scripts
|
||||||
#
|
#
|
||||||
package ZoneMinder::Config;
|
package ZoneMinder::Config;
|
||||||
|
@ -38,15 +38,15 @@ use vars qw( %Config );
|
||||||
# names by default without a very good reason. Use EXPORT_OK instead.
|
# names by default without a very good reason. Use EXPORT_OK instead.
|
||||||
# Do not simply export all your public functions/methods/constants.
|
# Do not simply export all your public functions/methods/constants.
|
||||||
|
|
||||||
# This allows declaration use ZoneMinder ':all';
|
# This allows declaration use ZoneMinder ':all';
|
||||||
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
||||||
# will save memory.
|
# will save memory.
|
||||||
our @EXPORT_CONFIG = qw( %Config ); # Get populated by BEGIN
|
our @EXPORT_CONFIG = qw( %Config ); # Get populated by BEGIN
|
||||||
|
|
||||||
our %EXPORT_TAGS = (
|
our %EXPORT_TAGS = (
|
||||||
'constants' => [ qw(
|
'constants' => [ qw(
|
||||||
ZM_PID
|
ZM_PID
|
||||||
) ]
|
) ]
|
||||||
);
|
);
|
||||||
push( @{$EXPORT_TAGS{config}}, @EXPORT_CONFIG );
|
push( @{$EXPORT_TAGS{config}}, @EXPORT_CONFIG );
|
||||||
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
||||||
|
@ -65,39 +65,43 @@ use Carp;
|
||||||
# Load the config from the database into the symbol table
|
# Load the config from the database into the symbol table
|
||||||
BEGIN
|
BEGIN
|
||||||
{
|
{
|
||||||
my $config_file = ZM_CONFIG;
|
my $config_file = ZM_CONFIG;
|
||||||
( my $local_config_file = $config_file ) =~ s|^.*/|./|;
|
( my $local_config_file = $config_file ) =~ s|^.*/|./|;
|
||||||
if ( -s $local_config_file and -r $local_config_file )
|
if ( -s $local_config_file and -r $local_config_file )
|
||||||
{
|
{
|
||||||
print( STDERR "Warning, overriding installed $local_config_file file with local copy\n" );
|
print( STDERR "Warning, overriding installed $local_config_file file with local copy\n" );
|
||||||
$config_file = $local_config_file;
|
$config_file = $local_config_file;
|
||||||
}
|
}
|
||||||
open( my $CONFIG, "<", $config_file )
|
open( my $CONFIG, "<", $config_file )
|
||||||
or croak( "Can't open config file '$config_file': $!" );
|
or croak( "Can't open config file '$config_file': $!" );
|
||||||
foreach my $str ( <$CONFIG> )
|
foreach my $str ( <$CONFIG> )
|
||||||
{
|
{
|
||||||
next if ( $str =~ /^\s*$/ );
|
next if ( $str =~ /^\s*$/ );
|
||||||
next if ( $str =~ /^\s*#/ );
|
next if ( $str =~ /^\s*#/ );
|
||||||
my ( $name, $value ) = $str =~ /^\s*([^=\s]+)\s*=\s*(.*?)\s*$/;
|
my ( $name, $value ) = $str =~ /^\s*([^=\s]+)\s*=\s*(.*?)\s*$/;
|
||||||
if ( ! $name ) {
|
if ( ! $name ) {
|
||||||
print( STDERR "Warning, bad line in $config_file: $str\n" );
|
print( STDERR "Warning, bad line in $config_file: $str\n" );
|
||||||
next;
|
next;
|
||||||
} # end if
|
} # end if
|
||||||
$name =~ tr/a-z/A-Z/;
|
$name =~ tr/a-z/A-Z/;
|
||||||
$Config{$name} = $value;
|
$Config{$name} = $value;
|
||||||
}
|
}
|
||||||
close( $CONFIG );
|
close( $CONFIG );
|
||||||
|
|
||||||
use DBI;
|
use DBI;
|
||||||
my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$Config{ZM_DB_HOST}, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} ) or croak( "Can't connect to db" );
|
my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}
|
||||||
my $sql = 'select * from Config';
|
.";host=".$Config{ZM_DB_HOST}
|
||||||
my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
, $Config{ZM_DB_USER}
|
||||||
my $res = $sth->execute() or croak( "Can't execute: ".$sth->errstr() );
|
, $Config{ZM_DB_PASS}
|
||||||
while( my $config = $sth->fetchrow_hashref() ) {
|
) or croak( "Can't connect to db" );
|
||||||
$Config{$config->{Name}} = $config->{Value};
|
my $sql = 'select * from Config';
|
||||||
}
|
my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||||
$sth->finish();
|
my $res = $sth->execute() or croak( "Can't execute: ".$sth->errstr() );
|
||||||
#$dbh->disconnect();
|
while( my $config = $sth->fetchrow_hashref() ) {
|
||||||
|
$Config{$config->{Name}} = $config->{Value};
|
||||||
|
}
|
||||||
|
$sth->finish();
|
||||||
|
#$dbh->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -113,9 +117,16 @@ ZoneMinder::Config - ZoneMinder configuration module.
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
The ZoneMinder::Config module is used to import the ZoneMinder configuration from the database. It will do this at compile time in a BEGIN block and require access to the zm.conf file either in the current directory or in its defined location in order to determine database access details, configuration from this file will also be included. If the :all or :config tags are used then this configuration is exported into the namespace of the calling program or module.
|
The ZoneMinder::Config module is used to import the ZoneMinder
|
||||||
|
configuration from the database. It will do this at compile time in a BEGIN
|
||||||
|
block and require access to the zm.conf file either in the current
|
||||||
|
directory or in its defined location in order to determine database access
|
||||||
|
details, configuration from this file will also be included. If the :all or
|
||||||
|
:config tags are used then this configuration is exported into the
|
||||||
|
namespace of the calling program or module.
|
||||||
|
|
||||||
Once the configuration has been imported then configuration variables are defined as constants and can be accessed directory by name, e.g.
|
Once the configuration has been imported then configuration variables are
|
||||||
|
defined as constants and can be accessed directory by name, e.g.
|
||||||
|
|
||||||
$lang = $Config{ZM_LANG_DEFAULT};
|
$lang = $Config{ZM_LANG_DEFAULT};
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#
|
#
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
#
|
#
|
||||||
# This module contains the debug definitions and functions used by the rest
|
# This module contains the debug definitions and functions used by the rest
|
||||||
# of the ZoneMinder scripts
|
# of the ZoneMinder scripts
|
||||||
#
|
#
|
||||||
package ZoneMinder::ConfigAdmin;
|
package ZoneMinder::ConfigAdmin;
|
||||||
|
@ -37,14 +37,14 @@ our @ISA = qw(Exporter ZoneMinder::Base);
|
||||||
# names by default without a very good reason. Use EXPORT_OK instead.
|
# names by default without a very good reason. Use EXPORT_OK instead.
|
||||||
# Do not simply export all your public functions/methods/constants.
|
# Do not simply export all your public functions/methods/constants.
|
||||||
|
|
||||||
# This allows declaration use ZoneMinder ':all';
|
# This allows declaration use ZoneMinder ':all';
|
||||||
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
||||||
# will save memory.
|
# will save memory.
|
||||||
our %EXPORT_TAGS = (
|
our %EXPORT_TAGS = (
|
||||||
'functions' => [ qw(
|
'functions' => [ qw(
|
||||||
loadConfigFromDB
|
loadConfigFromDB
|
||||||
saveConfigToDB
|
saveConfigToDB
|
||||||
) ]
|
) ]
|
||||||
);
|
);
|
||||||
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
||||||
|
|
||||||
|
@ -67,99 +67,138 @@ use Carp;
|
||||||
|
|
||||||
sub loadConfigFromDB
|
sub loadConfigFromDB
|
||||||
{
|
{
|
||||||
print( "Loading config from DB\n" );
|
print( "Loading config from DB\n" );
|
||||||
my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$Config{ZM_DB_HOST}, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} );
|
my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}
|
||||||
|
.";host=".$Config{ZM_DB_HOST}
|
||||||
if ( !$dbh )
|
,$Config{ZM_DB_USER}
|
||||||
{
|
,$Config{ZM_DB_PASS}
|
||||||
print( "Error: unable to load options from database: $DBI::errstr\n" );
|
);
|
||||||
return( 0 );
|
|
||||||
}
|
if ( !$dbh )
|
||||||
my $sql = "select * from Config";
|
{
|
||||||
my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
print( "Error: unable to load options from database: $DBI::errstr\n" );
|
||||||
my $res = $sth->execute() or croak( "Can't execute: ".$sth->errstr() );
|
return( 0 );
|
||||||
my $option_count = 0;
|
}
|
||||||
while( my $config = $sth->fetchrow_hashref() )
|
my $sql = "select * from Config";
|
||||||
{
|
my $sth = $dbh->prepare_cached( $sql )
|
||||||
my ( $name, $value ) = ( $config->{Name}, $config->{Value} );
|
or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||||
#print( "Name = '$name'\n" );
|
my $res = $sth->execute()
|
||||||
my $option = $options_hash{$name};
|
or croak( "Can't execute: ".$sth->errstr() );
|
||||||
if ( !$option )
|
my $option_count = 0;
|
||||||
{
|
while( my $config = $sth->fetchrow_hashref() )
|
||||||
warn( "No option '$name' found, removing" );
|
{
|
||||||
next;
|
my ( $name, $value ) = ( $config->{Name}, $config->{Value} );
|
||||||
}
|
#print( "Name = '$name'\n" );
|
||||||
#next if ( $option->{category} eq 'hidden' );
|
my $option = $options_hash{$name};
|
||||||
if ( defined($value) )
|
if ( !$option )
|
||||||
{
|
{
|
||||||
if ( $option->{type} == $types{boolean} )
|
warn( "No option '$name' found, removing" );
|
||||||
{
|
next;
|
||||||
$option->{value} = $value?"yes":"no";
|
}
|
||||||
}
|
#next if ( $option->{category} eq 'hidden' );
|
||||||
else
|
if ( defined($value) )
|
||||||
{
|
{
|
||||||
$option->{value} = $value;
|
if ( $option->{type} == $types{boolean} )
|
||||||
}
|
{
|
||||||
}
|
$option->{value} = $value?"yes":"no";
|
||||||
$option_count++;;
|
}
|
||||||
}
|
else
|
||||||
$sth->finish();
|
{
|
||||||
$dbh->disconnect();
|
$option->{value} = $value;
|
||||||
return( $option_count );
|
}
|
||||||
|
}
|
||||||
|
$option_count++;;
|
||||||
|
}
|
||||||
|
$sth->finish();
|
||||||
|
$dbh->disconnect();
|
||||||
|
return( $option_count );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub saveConfigToDB
|
sub saveConfigToDB
|
||||||
{
|
{
|
||||||
print( "Saving config to DB\n" );
|
print( "Saving config to DB\n" );
|
||||||
my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$Config{ZM_DB_HOST}, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} );
|
my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}
|
||||||
|
.";host=".$Config{ZM_DB_HOST}
|
||||||
|
,$Config{ZM_DB_USER}
|
||||||
|
,$Config{ZM_DB_PASS}
|
||||||
|
);
|
||||||
|
|
||||||
if ( !$dbh )
|
if ( !$dbh )
|
||||||
{
|
{
|
||||||
print( "Error: unable to save options to database: $DBI::errstr\n" );
|
print( "Error: unable to save options to database: $DBI::errstr\n" );
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
my $ac = $dbh->{AutoCommit};
|
my $ac = $dbh->{AutoCommit};
|
||||||
$dbh->{AutoCommit} = 0;
|
$dbh->{AutoCommit} = 0;
|
||||||
|
|
||||||
$dbh->do('LOCK TABLE Config WRITE') or croak( "Can't lock Config table: " . $dbh->errstr() );
|
$dbh->do('LOCK TABLE Config WRITE')
|
||||||
|
or croak( "Can't lock Config table: " . $dbh->errstr() );
|
||||||
|
|
||||||
my $sql = "delete from Config";
|
my $sql = "delete from Config";
|
||||||
my $res = $dbh->do( $sql ) or croak( "Can't do '$sql': ".$dbh->errstr() );
|
my $res = $dbh->do( $sql )
|
||||||
|
or croak( "Can't do '$sql': ".$dbh->errstr() );
|
||||||
|
|
||||||
$sql = "replace into Config set Id = ?, Name = ?, Value = ?, Type = ?, DefaultValue = ?, Hint = ?, Pattern = ?, Format = ?, Prompt = ?, Help = ?, Category = ?, Readonly = ?, Requires = ?";
|
$sql = "replace into Config set Id = ?, Name = ?, Value = ?, Type = ?, DefaultValue = ?, Hint = ?, Pattern = ?, Format = ?, Prompt = ?, Help = ?, Category = ?, Readonly = ?, Requires = ?";
|
||||||
my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
my $sth = $dbh->prepare_cached( $sql )
|
||||||
foreach my $option ( @options )
|
or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||||
{
|
foreach my $option ( @options )
|
||||||
#next if ( $option->{category} eq 'hidden' );
|
{
|
||||||
#print( $option->{name}."\n" ) if ( !$option->{category} );
|
#next if ( $option->{category} eq 'hidden' );
|
||||||
$option->{db_type} = $option->{type}->{db_type};
|
#print( $option->{name}."\n" ) if ( !$option->{category} );
|
||||||
$option->{db_hint} = $option->{type}->{hint};
|
$option->{db_type} = $option->{type}->{db_type};
|
||||||
$option->{db_pattern} = $option->{type}->{pattern};
|
$option->{db_hint} = $option->{type}->{hint};
|
||||||
$option->{db_format} = $option->{type}->{format};
|
$option->{db_pattern} = $option->{type}->{pattern};
|
||||||
if ( $option->{db_type} eq "boolean" )
|
$option->{db_format} = $option->{type}->{format};
|
||||||
{
|
if ( $option->{db_type} eq "boolean" )
|
||||||
$option->{db_value} = ($option->{value} eq "yes")?"1":"0";
|
{
|
||||||
}
|
$option->{db_value} = ($option->{value} eq "yes")
|
||||||
else
|
? "1"
|
||||||
{
|
: "0"
|
||||||
$option->{db_value} = $option->{value};
|
;
|
||||||
}
|
}
|
||||||
if ( my $requires = $option->{requires} )
|
else
|
||||||
{
|
{
|
||||||
$option->{db_requires} = join( ";", map { my $value = $_->{value}; $value = ($value eq "yes")?1:0 if ( $options_hash{$_->{name}}->{db_type} eq "boolean" ); ( "$_->{name}=$value" ) } @$requires );
|
$option->{db_value} = $option->{value};
|
||||||
}
|
}
|
||||||
else
|
if ( my $requires = $option->{requires} )
|
||||||
{
|
{
|
||||||
}
|
$option->{db_requires} = join( ";",
|
||||||
my $res = $sth->execute( $option->{id}, $option->{name}, $option->{db_value}, $option->{db_type}, $option->{default}, $option->{db_hint}, $option->{db_pattern}, $option->{db_format}, $option->{description}, $option->{help}, $option->{category}, $option->{readonly}?1:0, $option->{db_requires} ) or croak( "Can't execute: ".$sth->errstr() );
|
map {
|
||||||
}
|
my $value = $_->{value};
|
||||||
$sth->finish();
|
$value = ($value eq "yes")
|
||||||
|
? 1
|
||||||
|
: 0
|
||||||
|
if ( $options_hash{$_->{name}}->{db_type} eq "boolean" )
|
||||||
|
; ( "$_->{name}=$value" )
|
||||||
|
} @$requires
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
}
|
||||||
|
my $res = $sth->execute(
|
||||||
|
$option->{id},
|
||||||
|
$option->{name},
|
||||||
|
$option->{db_value},
|
||||||
|
$option->{db_type},
|
||||||
|
$option->{default},
|
||||||
|
$option->{db_hint},
|
||||||
|
$option->{db_pattern},
|
||||||
|
$option->{db_format},
|
||||||
|
$option->{description},
|
||||||
|
$option->{help},
|
||||||
|
$option->{category},
|
||||||
|
$option->{readonly} ? 1 : 0,
|
||||||
|
$option->{db_requires}
|
||||||
|
) or croak( "Can't execute: ".$sth->errstr() );
|
||||||
|
}
|
||||||
|
$sth->finish();
|
||||||
|
|
||||||
$dbh->do('UNLOCK TABLES');
|
$dbh->do('UNLOCK TABLES');
|
||||||
$dbh->{AutoCommit} = $ac;
|
$dbh->{AutoCommit} = $ac;
|
||||||
|
|
||||||
$dbh->disconnect();
|
$dbh->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -179,9 +218,15 @@ ZoneMinder::ConfigAdmin - ZoneMinder Configuration Administration module
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
The ZoneMinder:ConfigAdmin module contains the master definition of the ZoneMinder configuration options as well as helper methods. This module is intended for specialist confguration management and would not normally be used by end users.
|
The ZoneMinder:ConfigAdmin module contains the master definition of the
|
||||||
|
ZoneMinder configuration options as well as helper methods. This module is
|
||||||
|
intended for specialist confguration management and would not normally be
|
||||||
|
used by end users.
|
||||||
|
|
||||||
The configuration held in this module, which was previously in zmconfig.pl, includes the name, default value, description, help text, type and category for each option, as well as a number of additional fields in a small number of cases.
|
The configuration held in this module, which was previously in zmconfig.pl,
|
||||||
|
includes the name, default value, description, help text, type and category
|
||||||
|
for each option, as well as a number of additional fields in a small number
|
||||||
|
of cases.
|
||||||
|
|
||||||
=head1 METHODS
|
=head1 METHODS
|
||||||
|
|
||||||
|
@ -189,11 +234,17 @@ The configuration held in this module, which was previously in zmconfig.pl, incl
|
||||||
|
|
||||||
=item loadConfigFromDB ();
|
=item loadConfigFromDB ();
|
||||||
|
|
||||||
Loads existing configuration from the database (if any) and merges it with the definitions held in this module. This results in the merging of any new configuration and the removal of any deprecated configuration while preserving the existing values of every else.
|
Loads existing configuration from the database (if any) and merges it with
|
||||||
|
the definitions held in this module. This results in the merging of any new
|
||||||
|
configuration and the removal of any deprecated configuration while
|
||||||
|
preserving the existing values of every else.
|
||||||
|
|
||||||
=item saveConfigToDB ();
|
=item saveConfigToDB ();
|
||||||
|
|
||||||
Saves configuration held in memory to the database. The act of loading and saving configuration is a convenient way to ensure that the configuration held in the database corresponds with the most recent definitions and that all components are using the same set of configuration.
|
Saves configuration held in memory to the database. The act of loading and
|
||||||
|
saving configuration is a convenient way to ensure that the configuration
|
||||||
|
held in the database corresponds with the most recent definitions and that
|
||||||
|
all components are using the same set of configuration.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -19,7 +19,7 @@
|
||||||
#
|
#
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
#
|
#
|
||||||
# This module contains the base class definitions for the camera control
|
# This module contains the base class definitions for the camera control
|
||||||
# protocol implementations
|
# protocol implementations
|
||||||
#
|
#
|
||||||
package ZoneMinder::Control;
|
package ZoneMinder::Control;
|
||||||
|
@ -45,17 +45,17 @@ our $AUTOLOAD;
|
||||||
|
|
||||||
sub new
|
sub new
|
||||||
{
|
{
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
my $id = shift;
|
my $id = shift;
|
||||||
my $self = {};
|
my $self = {};
|
||||||
$self->{name} = "PelcoD";
|
$self->{name} = "PelcoD";
|
||||||
if ( !defined($id) )
|
if ( !defined($id) )
|
||||||
{
|
{
|
||||||
Fatal( "No monitor defined when invoking protocol ".$self->{name} );
|
Fatal( "No monitor defined when invoking protocol ".$self->{name} );
|
||||||
}
|
}
|
||||||
$self->{id} = $id;
|
$self->{id} = $id;
|
||||||
bless( $self, $class );
|
bless( $self, $class );
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub DESTROY
|
sub DESTROY
|
||||||
|
@ -64,32 +64,32 @@ sub DESTROY
|
||||||
|
|
||||||
sub AUTOLOAD
|
sub AUTOLOAD
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $class = ref($self) || croak( "$self not object" );
|
my $class = ref($self) || croak( "$self not object" );
|
||||||
my $name = $AUTOLOAD;
|
my $name = $AUTOLOAD;
|
||||||
$name =~ s/.*://;
|
$name =~ s/.*://;
|
||||||
if ( exists($self->{$name}) )
|
if ( exists($self->{$name}) )
|
||||||
{
|
{
|
||||||
return( $self->{$name} );
|
return( $self->{$name} );
|
||||||
}
|
}
|
||||||
croak( "Can't access $name member of object of class $class" );
|
croak( "Can't access $name member of object of class $class" );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub getKey
|
sub getKey
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return( $self->{id} );
|
return( $self->{id} );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub open
|
sub open
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
Fatal( "No open method defined for protocol ".$self->{name} );
|
Fatal( "No open method defined for protocol ".$self->{name} );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub close
|
sub close
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
Fatal( "No close method defined for protocol ".$self->{name} );
|
Fatal( "No close method defined for protocol ".$self->{name} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +147,7 @@ sub executeCommand
|
||||||
|
|
||||||
sub printMsg
|
sub printMsg
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
Fatal( "No printMsg method defined for protocol ".$self->{name} );
|
Fatal( "No printMsg method defined for protocol ".$self->{name} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,10 @@
|
||||||
#
|
#
|
||||||
# This module contains the implementation of the 3S camera control
|
# This module contains the implementation of the 3S camera control
|
||||||
# protocol
|
# protocol
|
||||||
#Model: N5071
|
#Model: N5071
|
||||||
#Hardware Version: 00
|
#Hardware Version: 00
|
||||||
#Firmware Version: V1.03_STD-1
|
#Firmware Version: V1.03_STD-1
|
||||||
#Firmware Build Time: Jun 19 2012 15:28:17
|
#Firmware Build Time: Jun 19 2012 15:28:17
|
||||||
|
|
||||||
package ZoneMinder::Control::3S;
|
package ZoneMinder::Control::3S;
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ our @ISA = qw(ZoneMinder::Control);
|
||||||
# of the position of your mouse on the arrow.
|
# of the position of your mouse on the arrow.
|
||||||
# Extremity of arrow equal to fastest speed of movement
|
# Extremity of arrow equal to fastest speed of movement
|
||||||
# Close the base of arrow to lowest speed of movement
|
# Close the base of arrow to lowest speed of movement
|
||||||
# for diagonaly you can click before the begining of the arrow for low speed
|
# for diagonaly you can click before the beginning of the arrow for low speed
|
||||||
# In round center equal to stop to move and switch of latest OSD
|
# In round center equal to stop to move and switch of latest OSD
|
||||||
# -You can clic directly on the image that equal to click on arrow (for the left there is a bug in zoneminder speed is inverted)
|
# -You can clic directly on the image that equal to click on arrow (for the left there is a bug in zoneminder speed is inverted)
|
||||||
# -Zoom Tele switch ON InfraRed LED and stay to manual IR MODE
|
# -Zoom Tele switch ON InfraRed LED and stay to manual IR MODE
|
||||||
|
@ -63,7 +63,7 @@ our @ISA = qw(ZoneMinder::Control);
|
||||||
# -8 Preset PTZ are implemented and functionnal
|
# -8 Preset PTZ are implemented and functionnal
|
||||||
# -This Script use for login "admin" this hardcoded and your password must setup in "Control Device" section
|
# -This Script use for login "admin" this hardcoded and your password must setup in "Control Device" section
|
||||||
# -This script is compatible with the basic authentification method used by mostly new camera based with hi3510 chipset
|
# -This script is compatible with the basic authentification method used by mostly new camera based with hi3510 chipset
|
||||||
# -AutoStop function is active and you must set up value (in sec exemple 0.7) under AutoStop section
|
# -AutoStop function is active and you must set up value (in sec example 0.7) under AutoStop section
|
||||||
# or you can set up to 0 for disable it (in this case you need to click to the circle center for stop)
|
# or you can set up to 0 for disable it (in this case you need to click to the circle center for stop)
|
||||||
# -"White In" to control Brightness, "auto" for restore the original value of Brightness
|
# -"White In" to control Brightness, "auto" for restore the original value of Brightness
|
||||||
# -"White Out" to control Contrast, "man" for restore the original value of Contrast
|
# -"White Out" to control Contrast, "man" for restore the original value of Contrast
|
||||||
|
@ -129,7 +129,7 @@ sub printMsg
|
||||||
}
|
}
|
||||||
|
|
||||||
sub sendCmd
|
sub sendCmd
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $cmd = shift;
|
my $cmd = shift;
|
||||||
my $result = undef;
|
my $result = undef;
|
||||||
|
@ -211,7 +211,7 @@ sub moveConUp
|
||||||
if ( $tiltspeed < 10 ) {
|
if ( $tiltspeed < 10 ) {
|
||||||
$tiltspeed = 1;
|
$tiltspeed = 1;
|
||||||
}
|
}
|
||||||
Debug( "Move Up" );
|
Debug( "Move Up" );
|
||||||
if ( $osd eq "on" )
|
if ( $osd eq "on" )
|
||||||
{
|
{
|
||||||
my $cmd = "param.cgi?cmd=setoverlayattr&-region=1&-show=1&-name=Move Up $tiltspeed";
|
my $cmd = "param.cgi?cmd=setoverlayattr&-region=1&-show=1&-name=Move Up $tiltspeed";
|
||||||
|
|
|
@ -57,7 +57,7 @@ our @ISA = qw(ZoneMinder::Control);
|
||||||
# of the position of your mouse on the arrow.
|
# of the position of your mouse on the arrow.
|
||||||
# Extremity of arrow equal to fastest speed of movement
|
# Extremity of arrow equal to fastest speed of movement
|
||||||
# Close the base of arrow to lowest speed of movement
|
# Close the base of arrow to lowest speed of movement
|
||||||
# for diagonaly you can click before the begining of the arrow for low speed
|
# for diagonaly you can click before the beginning of the arrow for low speed
|
||||||
# In round center equal to stop to move
|
# In round center equal to stop to move
|
||||||
# -You can clic directly on the image that equal to click on arrow (for the left there is a bug in zoneminder speed is inverted)
|
# -You can clic directly on the image that equal to click on arrow (for the left there is a bug in zoneminder speed is inverted)
|
||||||
# -Zoom Tele/Wide with time control to simulate speed because speed value do not work (buggy firmware or not implemented on this cam)
|
# -Zoom Tele/Wide with time control to simulate speed because speed value do not work (buggy firmware or not implemented on this cam)
|
||||||
|
@ -67,7 +67,7 @@ our @ISA = qw(ZoneMinder::Control);
|
||||||
# You Need to configure ZoneMinder PANSPEED & TILTSEPPED & ZOOMSPEED 1 to 63 by 1 step
|
# You Need to configure ZoneMinder PANSPEED & TILTSEPPED & ZOOMSPEED 1 to 63 by 1 step
|
||||||
# -This Script use for login "admin" this hardcoded and your password must setup in "Control Device" section
|
# -This Script use for login "admin" this hardcoded and your password must setup in "Control Device" section
|
||||||
# -This script is compatible with the basic authentification method used by mostly new camera
|
# -This script is compatible with the basic authentification method used by mostly new camera
|
||||||
# -AutoStop function is active and you must set up value (in sec exemple 0.5) under AutoStop section
|
# -AutoStop function is active and you must set up value (in sec example 0.5) under AutoStop section
|
||||||
# or you can set up to 0 for disable it but the camera never stop to move and trust me, she can move all the night...
|
# or you can set up to 0 for disable it but the camera never stop to move and trust me, she can move all the night...
|
||||||
# (you need to click to the center arrow for stop)
|
# (you need to click to the center arrow for stop)
|
||||||
# -"White In" to control Brightness, "auto" for restore the original value of Brightness
|
# -"White In" to control Brightness, "auto" for restore the original value of Brightness
|
||||||
|
|
|
@ -43,176 +43,176 @@ use ZoneMinder::Config qw(:all);
|
||||||
use Time::HiRes qw( usleep );
|
use Time::HiRes qw( usleep );
|
||||||
|
|
||||||
sub new
|
sub new
|
||||||
{
|
{
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
my $id = shift;
|
my $id = shift;
|
||||||
my $self = ZoneMinder::Control->new( $id );
|
my $self = ZoneMinder::Control->new( $id );
|
||||||
bless( $self, $class );
|
bless( $self, $class );
|
||||||
srand( time() );
|
srand( time() );
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
our $AUTOLOAD;
|
our $AUTOLOAD;
|
||||||
|
|
||||||
sub AUTOLOAD
|
sub AUTOLOAD
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $class = ref($self) || croak( "$self not object" );
|
my $class = ref($self) || croak( "$self not object" );
|
||||||
my $name = $AUTOLOAD;
|
my $name = $AUTOLOAD;
|
||||||
$name =~ s/.*://;
|
$name =~ s/.*://;
|
||||||
if ( exists($self->{$name}) )
|
if ( exists($self->{$name}) )
|
||||||
{
|
{
|
||||||
return( $self->{$name} );
|
return( $self->{$name} );
|
||||||
}
|
}
|
||||||
Fatal( "Can't access $name member of object of class $class" );
|
Fatal( "Can't access $name member of object of class $class" );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub open
|
sub open
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
$self->loadMonitor();
|
$self->loadMonitor();
|
||||||
|
|
||||||
use LWP::UserAgent;
|
use LWP::UserAgent;
|
||||||
$self->{ua} = LWP::UserAgent->new;
|
$self->{ua} = LWP::UserAgent->new;
|
||||||
$self->{ua}->agent( "ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION );
|
$self->{ua}->agent( "ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION );
|
||||||
|
|
||||||
$self->{state} = 'open';
|
$self->{state} = 'open';
|
||||||
}
|
}
|
||||||
|
|
||||||
sub close
|
sub close
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
$self->{state} = 'closed';
|
$self->{state} = 'closed';
|
||||||
}
|
}
|
||||||
|
|
||||||
sub printMsg
|
sub printMsg
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $msg = shift;
|
my $msg = shift;
|
||||||
my $msg_len = length($msg);
|
my $msg_len = length($msg);
|
||||||
|
|
||||||
Debug( $msg."[".$msg_len."]" );
|
Debug( $msg."[".$msg_len."]" );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub sendCmd
|
sub sendCmd
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $cmd = shift;
|
my $cmd = shift;
|
||||||
my $result = undef;
|
my $result = undef;
|
||||||
|
|
||||||
my ($user, $password) = split /:/, $self->{Monitor}->{ControlDevice};
|
my ($user, $password) = split /:/, $self->{Monitor}->{ControlDevice};
|
||||||
|
|
||||||
if ( !defined $password ) {
|
if ( !defined $password ) {
|
||||||
# If value of "Control device" does not consist of two parts, then only password is given and we fallback to default user:
|
# If value of "Control device" does not consist of two parts, then only password is given and we fallback to default user:
|
||||||
$password = $user;
|
$password = $user;
|
||||||
$user = 'admin';
|
$user = 'admin';
|
||||||
}
|
}
|
||||||
|
|
||||||
$cmd .= "user=$user&pwd=$password";
|
$cmd .= "user=$user&pwd=$password";
|
||||||
|
|
||||||
printMsg( $cmd, "Tx" );
|
printMsg( $cmd, "Tx" );
|
||||||
|
|
||||||
my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$cmd" );
|
my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$cmd" );
|
||||||
my $res = $self->{ua}->request($req);
|
my $res = $self->{ua}->request($req);
|
||||||
|
|
||||||
if ( $res->is_success )
|
if ( $res->is_success )
|
||||||
{
|
{
|
||||||
$result = !undef;
|
$result = !undef;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Error( "Error check failed: '".$res->status_line()."' for URL ".$req->uri() );
|
Error( "Error check failed: '".$res->status_line()."' for URL ".$req->uri() );
|
||||||
}
|
}
|
||||||
|
|
||||||
return( $result );
|
return( $result );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub reset
|
sub reset
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
Debug( "Camera Reset" );
|
Debug( "Camera Reset" );
|
||||||
$self->sendCmd( 'reboot.cgi?' );
|
$self->sendCmd( 'reboot.cgi?' );
|
||||||
}
|
}
|
||||||
|
|
||||||
#Up Arrow
|
#Up Arrow
|
||||||
sub moveConUp
|
sub moveConUp
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
Debug( "Move Up" );
|
Debug( "Move Up" );
|
||||||
$self->sendCmd( 'decoder_control.cgi?command=0&' );
|
$self->sendCmd( 'decoder_control.cgi?command=0&' );
|
||||||
}
|
}
|
||||||
|
|
||||||
#Down Arrow
|
#Down Arrow
|
||||||
sub moveConDown
|
sub moveConDown
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
Debug( "Move Down" );
|
Debug( "Move Down" );
|
||||||
$self->sendCmd( 'decoder_control.cgi?command=2&' );
|
$self->sendCmd( 'decoder_control.cgi?command=2&' );
|
||||||
}
|
}
|
||||||
|
|
||||||
#Left Arrow
|
#Left Arrow
|
||||||
sub moveConLeft
|
sub moveConLeft
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
Debug( "Move Left" );
|
Debug( "Move Left" );
|
||||||
$self->sendCmd( 'decoder_control.cgi?command=6&' );
|
$self->sendCmd( 'decoder_control.cgi?command=6&' );
|
||||||
}
|
}
|
||||||
|
|
||||||
#Right Arrow
|
#Right Arrow
|
||||||
sub moveConRight
|
sub moveConRight
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
Debug( "Move Right" );
|
Debug( "Move Right" );
|
||||||
$self->sendCmd( 'decoder_control.cgi?command=4&' );
|
$self->sendCmd( 'decoder_control.cgi?command=4&' );
|
||||||
}
|
}
|
||||||
|
|
||||||
#Diagonally Up Right Arrow
|
#Diagonally Up Right Arrow
|
||||||
sub moveConUpRight
|
sub moveConUpRight
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
Debug( "Move Diagonally Up Right" );
|
Debug( "Move Diagonally Up Right" );
|
||||||
$self->sendCmd( 'decoder_control.cgi?command=90&' );
|
$self->sendCmd( 'decoder_control.cgi?command=90&' );
|
||||||
}
|
}
|
||||||
|
|
||||||
#Diagonally Down Right Arrow
|
#Diagonally Down Right Arrow
|
||||||
sub moveConDownRight
|
sub moveConDownRight
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
Debug( "Move Diagonally Down Right" );
|
Debug( "Move Diagonally Down Right" );
|
||||||
$self->sendCmd( 'decoder_control.cgi?command=92&' );
|
$self->sendCmd( 'decoder_control.cgi?command=92&' );
|
||||||
}
|
}
|
||||||
|
|
||||||
#Diagonally Up Left Arrow
|
#Diagonally Up Left Arrow
|
||||||
sub moveConUpLeft
|
sub moveConUpLeft
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
Debug( "Move Diagonally Up Left" );
|
Debug( "Move Diagonally Up Left" );
|
||||||
$self->sendCmd( 'decoder_control.cgi?command=91&' );
|
$self->sendCmd( 'decoder_control.cgi?command=91&' );
|
||||||
}
|
}
|
||||||
|
|
||||||
#Diagonally Down Left Arrow
|
#Diagonally Down Left Arrow
|
||||||
sub moveConDownLeft
|
sub moveConDownLeft
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
Debug( "Move Diagonally Down Left" );
|
Debug( "Move Diagonally Down Left" );
|
||||||
$self->sendCmd( 'decoder_control.cgi?command=93&' );
|
$self->sendCmd( 'decoder_control.cgi?command=93&' );
|
||||||
}
|
}
|
||||||
|
|
||||||
#Stop
|
#Stop
|
||||||
sub moveStop
|
sub moveStop
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
Debug( "Move Stop" );
|
Debug( "Move Stop" );
|
||||||
$self->sendCmd( 'decoder_control.cgi?command=1&' );
|
$self->sendCmd( 'decoder_control.cgi?command=1&' );
|
||||||
}
|
}
|
||||||
|
|
||||||
#Move Camera to Home Position
|
#Move Camera to Home Position
|
||||||
sub presetHome
|
sub presetHome
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
Debug( "Home Preset" );
|
Debug( "Home Preset" );
|
||||||
$self->sendCmd( 'decoder_control.cgi?command=25&' );
|
$self->sendCmd( 'decoder_control.cgi?command=25&' );
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -226,10 +226,11 @@ ZoneMinder::Control::FI8908W - Foscam FI8908W camera control
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
This module contains the implementation of the Foscam FI8908W / FI8918W IP camera control
|
This module contains the implementation of the Foscam FI8908W / FI8918W IP
|
||||||
protocol.
|
camera control protocol.
|
||||||
|
|
||||||
|
The module uses "Control Device" value to retrieve user and password. User
|
||||||
|
and password should be separated by colon, e.g. user:password. If colon is
|
||||||
|
not provided, then "admin" is used as a fallback value for the user.
|
||||||
|
|
||||||
The module uses "Control Device" value to retrieve user and password. User and password should
|
|
||||||
be separated by colon, e.g. user:password. If colon is not provided, then "admin" is used
|
|
||||||
as a fallback value for the user.
|
|
||||||
=cut
|
=cut
|
||||||
|
|
|
@ -102,7 +102,6 @@ sub close
|
||||||
|
|
||||||
sub printMsg
|
sub printMsg
|
||||||
{
|
{
|
||||||
my $self = shift;
|
|
||||||
my $msg = shift;
|
my $msg = shift;
|
||||||
my $msg_len = length($msg);
|
my $msg_len = length($msg);
|
||||||
Debug( $msg."[".$msg_len."]" );
|
Debug( $msg."[".$msg_len."]" );
|
||||||
|
@ -113,9 +112,28 @@ sub sendCmd
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $cmd = shift;
|
my $cmd = shift;
|
||||||
my $result = undef;
|
my $result = undef;
|
||||||
|
|
||||||
|
my ($user, $password) = split /:/, $self->{Monitor}->{ControlDevice};
|
||||||
|
if ( ! $password ) {
|
||||||
|
$password = $user;
|
||||||
|
$user = 'admin';
|
||||||
|
}
|
||||||
|
$user = 'admin' if ! $user;
|
||||||
|
$password = 'pwd' if ! $password;
|
||||||
|
|
||||||
|
$cmd .= "&usr=$user&pwd=$password";
|
||||||
|
|
||||||
printMsg( $cmd, "Tx" );
|
printMsg( $cmd, "Tx" );
|
||||||
my $temps = time();
|
my $url;
|
||||||
my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/cgi-bin/CGIProxy.fcgi?usr%3Dadmin%26pwd%3D".$self->{Monitor}->{ControlDevice}."%26cmd%3D".$cmd."%26".$temps );
|
if ( $self->{Monitor}->{ControlAddress} =~ /^http/ ) {
|
||||||
|
$url = $self->{Monitor}->{ControlAddress};
|
||||||
|
} else {
|
||||||
|
$url = "http://".$self->{Monitor}->{ControlAddress};
|
||||||
|
}
|
||||||
|
$url .= "/cgi-bin/CGIProxy.fcgi?cmd=$cmd%26".time;
|
||||||
|
printMsg( $url, "Tx" );
|
||||||
|
|
||||||
|
my $req = HTTP::Request->new( GET=>$url );
|
||||||
my $res = $self->{ua}->request($req);
|
my $res = $self->{ua}->request($req);
|
||||||
if ( $res->is_success )
|
if ( $res->is_success )
|
||||||
{
|
{
|
||||||
|
@ -134,7 +152,7 @@ sub reset
|
||||||
# Setup OSD
|
# Setup OSD
|
||||||
my $cmd = "setOSDSetting%26isEnableTimeStamp%3D0%26isEnableDevName%3D1%26dispPos%3D0%26isEnabledOSDMask%3D0";
|
my $cmd = "setOSDSetting%26isEnableTimeStamp%3D0%26isEnableDevName%3D1%26dispPos%3D0%26isEnabledOSDMask%3D0";
|
||||||
$self->sendCmd( $cmd );
|
$self->sendCmd( $cmd );
|
||||||
# Setup For Stream=0 Resolution=720p Bandwith=4M FPS=30 KeyFrameInterval/GOP=100 VBR=ON
|
# Setup For Stream=0 Resolution=720p Bandwidth=4M FPS=30 KeyFrameInterval/GOP=100 VBR=ON
|
||||||
$cmd = "setVideoStreamParam%26streamType%3D0%26resolution%3D0%26bitRate%3D4194304%26frameRate%3D30%26GOP%3D100%26isVBR%3D1";
|
$cmd = "setVideoStreamParam%26streamType%3D0%26resolution%3D0%26bitRate%3D4194304%26frameRate%3D30%26GOP%3D100%26isVBR%3D1";
|
||||||
$self->sendCmd( $cmd );
|
$self->sendCmd( $cmd );
|
||||||
# Setup For Infrared AUTO
|
# Setup For Infrared AUTO
|
||||||
|
|
|
@ -107,14 +107,18 @@ sub sendCmd {
|
||||||
printMsg( $cmd, "Tx" );
|
printMsg( $cmd, "Tx" );
|
||||||
#print( "http://$address/$cmd\n" );
|
#print( "http://$address/$cmd\n" );
|
||||||
#my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$cmd" );
|
#my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$cmd" );
|
||||||
|
|
||||||
my $url;
|
my $url;
|
||||||
if ( $self->{Monitor}->{ControlAddress} =~ /^http/ ) {
|
if ( $self->{Monitor}->{ControlAddress} =~ /^http/ ) {
|
||||||
$url = $self->{Monitor}->{ControlAddress}.'/cgi-bin/setGPIO.cgi?preventCache='.time;
|
$url = $self->{Monitor}->{ControlAddress}
|
||||||
} else {
|
.'/cgi-bin/setGPIO.cgi?preventCache='.time
|
||||||
$url = 'http://'.$self->{Monitor}->{ControlAddress}.'/cgi-bin/setGPIO.cgi?preventCache='.time;
|
;
|
||||||
} # en dif
|
} else {
|
||||||
Error("Url: $url $cmd");
|
$url = 'http://'.$self->{Monitor}->{ControlAddress}
|
||||||
|
.'/cgi-bin/setGPIO.cgi?preventCache='.time
|
||||||
|
;
|
||||||
|
} # en dif
|
||||||
|
Error("Url: $url $cmd");
|
||||||
my $uri = URI::Encode->new( { encode_reserved => 0 } );
|
my $uri = URI::Encode->new( { encode_reserved => 0 } );
|
||||||
my $encoded = $uri->encode( $cmd );
|
my $encoded = $uri->encode( $cmd );
|
||||||
my $res = $self->{ua}->post( $url, Content=>"data=$encoded" );
|
my $res = $self->{ua}->post( $url, Content=>"data=$encoded" );
|
||||||
|
@ -203,7 +207,11 @@ sub moveMap
|
||||||
my $xcoord = $self->getParam( $params, 'xcoord' );
|
my $xcoord = $self->getParam( $params, 'xcoord' );
|
||||||
my $ycoord = $self->getParam( $params, 'ycoord' );
|
my $ycoord = $self->getParam( $params, 'ycoord' );
|
||||||
Debug( "Move Map to $xcoord,$ycoord" );
|
Debug( "Move Map to $xcoord,$ycoord" );
|
||||||
my $cmd = "/axis-cgi/com/ptz.cgi?center=$xcoord,$ycoord&imagewidth=".$self->{Monitor}->{Width}."&imageheight=".$self->{Monitor}->{Height};
|
my $cmd = "/axis-cgi/com/ptz.cgi?center=$xcoord,$ycoord&imagewidth="
|
||||||
|
.$self->{Monitor}->{Width}
|
||||||
|
."&imageheight="
|
||||||
|
.$self->{Monitor}->{Height}
|
||||||
|
;
|
||||||
$self->sendCmd( $cmd );
|
$self->sendCmd( $cmd );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,16 +60,16 @@ our @ISA = qw(ZoneMinder::Control);
|
||||||
|
|
||||||
#
|
#
|
||||||
# ******** YOU MUST CHANGE THE FOLLOWING LINES TO MATCH YOUR CAMERA! **********
|
# ******** YOU MUST CHANGE THE FOLLOWING LINES TO MATCH YOUR CAMERA! **********
|
||||||
#
|
#
|
||||||
# I assume that "TV-IP672WI" would work for the TV-IP672WI, but can't test since I don't own one.
|
# I assume that "TV-IP672WI" would work for the TV-IP672WI, but can't test since I don't own one.
|
||||||
#
|
#
|
||||||
# TV-IP672PI works for the PI version, of course.
|
# TV-IP672PI works for the PI version, of course.
|
||||||
#
|
#
|
||||||
# Finally, the username is the username you'd like to authenticate as.
|
# Finally, the username is the username you'd like to authenticate as.
|
||||||
#
|
#
|
||||||
our $REALM = 'TV-IP862IC';
|
our $REALM = 'TV-IP862IC';
|
||||||
our $USERNAME = 'admin';
|
our $USERNAME = 'admin';
|
||||||
our $PASSWORD = '';
|
our $PASSWORD = '';
|
||||||
our $ADDRESS = '';
|
our $ADDRESS = '';
|
||||||
|
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
|
@ -111,26 +111,32 @@ sub open
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
$self->loadMonitor();
|
$self->loadMonitor();
|
||||||
|
|
||||||
my ( $protocol, $username, $password, $address ) = $self->{Monitor}->{ControlAddress} =~ /^(https?:\/\/)?([^:]+):([^\/@]+)@(.*)$/;
|
my ( $protocol, $username, $password, $address )
|
||||||
if ( $username ) {
|
= $self->{Monitor}->{ControlAddress} =~ /^(https?:\/\/)?([^:]+):([^\/@]+)@(.*)$/;
|
||||||
$USERNAME = $username;
|
if ( $username ) {
|
||||||
$PASSWORD = $password;
|
$USERNAME = $username;
|
||||||
$ADDRESS = $address;
|
$PASSWORD = $password;
|
||||||
} else {
|
$ADDRESS = $address;
|
||||||
Error( "Failed to parse auth from address");
|
} else {
|
||||||
$ADDRESS = $self->{Monitor}->{ControlAddress};
|
Error( "Failed to parse auth from address");
|
||||||
}
|
$ADDRESS = $self->{Monitor}->{ControlAddress};
|
||||||
if ( ! $ADDRESS =~ /:/ ) {
|
}
|
||||||
Error( "You generally need to also specify the port. I will append :80" );
|
if ( ! $ADDRESS =~ /:/ ) {
|
||||||
$ADDRESS .= ':80';
|
Error( "You generally need to also specify the port. I will append :80" );
|
||||||
}
|
$ADDRESS .= ':80';
|
||||||
|
}
|
||||||
|
|
||||||
use LWP::UserAgent;
|
use LWP::UserAgent;
|
||||||
$self->{ua} = LWP::UserAgent->new;
|
$self->{ua} = LWP::UserAgent->new;
|
||||||
$self->{ua}->agent( "ZoneMinder Control Agent/".$ZoneMinder::Base::ZM_VERSION );
|
$self->{ua}->agent( "ZoneMinder Control Agent/".$ZoneMinder::Base::ZM_VERSION );
|
||||||
$self->{state} = 'open';
|
$self->{state} = 'open';
|
||||||
# credentials: ("ip:port" (no prefix!), realm (string), username (string), password (string)
|
# credentials: ("ip:port" (no prefix!), realm (string), username (string), password (string)
|
||||||
Debug ( "sendCmd credentials control address:'".$ADDRESS."' realm:'" . $REALM . "' username:'" . $USERNAME . "' password:'".$PASSWORD."'");
|
Debug ( "sendCmd credentials control address:'".$ADDRESS
|
||||||
|
."' realm:'" . $REALM
|
||||||
|
. "' username:'" . $USERNAME
|
||||||
|
. "' password:'".$PASSWORD
|
||||||
|
."'"
|
||||||
|
);
|
||||||
$self->{ua}->credentials($ADDRESS,$REALM,$USERNAME,$PASSWORD);
|
$self->{ua}->credentials($ADDRESS,$REALM,$USERNAME,$PASSWORD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,29 +165,29 @@ sub sendCmd
|
||||||
|
|
||||||
my $result = undef;
|
my $result = undef;
|
||||||
|
|
||||||
my $url = "http://".$ADDRESS."/cgi/ptdc.cgi?command=".$cmd;
|
my $url = "http://".$ADDRESS."/cgi/ptdc.cgi?command=".$cmd;
|
||||||
my $req = HTTP::Request->new( GET=>$url );
|
my $req = HTTP::Request->new( GET=>$url );
|
||||||
|
|
||||||
Debug ("sendCmd command: " . $url );
|
Debug ("sendCmd command: " . $url );
|
||||||
|
|
||||||
my $res = $self->{ua}->request($req);
|
my $res = $self->{ua}->request($req);
|
||||||
|
|
||||||
if ( $res->is_success ) {
|
if ( $res->is_success ) {
|
||||||
$result = !undef;
|
$result = !undef;
|
||||||
} else {
|
} else {
|
||||||
if ( $res->status_line() eq '401 Unauthorized' ) {
|
if ( $res->status_line() eq '401 Unauthorized' ) {
|
||||||
Error( "Error check failed, trying again: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD );
|
Error( "Error check failed, trying again: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD );
|
||||||
Error("Content was " . $res->content() );
|
Error("Content was " . $res->content() );
|
||||||
my $res = $self->{ua}->request($req);
|
my $res = $self->{ua}->request($req);
|
||||||
if ( $res->is_success ) {
|
if ( $res->is_success ) {
|
||||||
$result = !undef;
|
$result = !undef;
|
||||||
} else {
|
} else {
|
||||||
Error("Content was " . $res->content() );
|
Error("Content was " . $res->content() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( ! $result ) {
|
if ( ! $result ) {
|
||||||
Error( "Error check failed: '".$res->status_line()."' cmd:'".$cmd."'" );
|
Error( "Error check failed: '".$res->status_line()."' cmd:'".$cmd."'" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return( $result );
|
return( $result );
|
||||||
|
@ -203,10 +209,10 @@ sub sendCmdPost
|
||||||
my $result = undef;
|
my $result = undef;
|
||||||
|
|
||||||
if ($url eq undef)
|
if ($url eq undef)
|
||||||
{
|
{
|
||||||
Error ("url passed to sendCmdPost is undefined.");
|
Error ("url passed to sendCmdPost is undefined.");
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug ("sendCmdPost url: " . $url . " cmd: " . $cmd);
|
Debug ("sendCmdPost url: " . $url . " cmd: " . $cmd);
|
||||||
|
|
||||||
|
@ -215,7 +221,7 @@ sub sendCmdPost
|
||||||
$req->content($cmd);
|
$req->content($cmd);
|
||||||
|
|
||||||
Debug ( "sendCmdPost credentials control address:'".$ADDRESS."' realm:'" . $REALM . "' username:'" . $USERNAME . "' password:'".$PASSWORD."'");
|
Debug ( "sendCmdPost credentials control address:'".$ADDRESS."' realm:'" . $REALM . "' username:'" . $USERNAME . "' password:'".$PASSWORD."'");
|
||||||
|
|
||||||
my $res = $self->{ua}->request($req);
|
my $res = $self->{ua}->request($req);
|
||||||
|
|
||||||
if ( $res->is_success )
|
if ( $res->is_success )
|
||||||
|
@ -225,11 +231,11 @@ sub sendCmdPost
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Error( "sendCmdPost Error check failed: '".$res->status_line()."' cmd:'".$cmd."'" );
|
Error( "sendCmdPost Error check failed: '".$res->status_line()."' cmd:'".$cmd."'" );
|
||||||
if ( $res->status_line() eq '401 Unauthorized' ) {
|
if ( $res->status_line() eq '401 Unauthorized' ) {
|
||||||
Error( "sendCmdPost Error check failed: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD );
|
Error( "sendCmdPost Error check failed: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD );
|
||||||
} else {
|
} else {
|
||||||
Error( "sendCmdPost Error check failed: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD );
|
Error( "sendCmdPost Error check failed: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD );
|
||||||
} # endif
|
} # endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return( $result );
|
return( $result );
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
# Rename to Wanscam
|
# Rename to Wanscam
|
||||||
# Pan Left/Right switched
|
# Pan Left/Right switched
|
||||||
# IR On/Off switched
|
# IR On/Off switched
|
||||||
# Brightness Increase/Decrease in 16 steps
|
# Brightness Increase/Decrease in 16 steps
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|
|
@ -126,32 +126,32 @@ sub sendCmd
|
||||||
sub Up
|
sub Up
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
$self->moveConUp();
|
$self->moveConUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
sub Down
|
sub Down
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
$self->moveConDown();
|
$self->moveConDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
sub Left
|
sub Left
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
$self->moveConLeft();
|
$self->moveConLeft();
|
||||||
}
|
}
|
||||||
|
|
||||||
sub Right
|
sub Right
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
$self->moveConRight();
|
$self->moveConRight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub reset
|
sub reset
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
$self->cameraReset();
|
$self->cameraReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ our %CamParams = ();
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
#
|
#
|
||||||
# ONVIF Control Protocol
|
# ONVIF Control Protocol
|
||||||
#
|
#
|
||||||
# On ControlAddress use the format :
|
# On ControlAddress use the format :
|
||||||
# USERNAME:PASSWORD@ADDRESS:PORT
|
# USERNAME:PASSWORD@ADDRESS:PORT
|
||||||
# eg : admin:@10.1.2.1:80
|
# eg : admin:@10.1.2.1:80
|
||||||
|
@ -50,7 +50,7 @@ use ZoneMinder::Config qw(:all);
|
||||||
use Time::HiRes qw( usleep );
|
use Time::HiRes qw( usleep );
|
||||||
|
|
||||||
sub new
|
sub new
|
||||||
{
|
{
|
||||||
|
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
my $id = shift;
|
my $id = shift;
|
||||||
|
@ -90,7 +90,7 @@ sub open
|
||||||
}
|
}
|
||||||
|
|
||||||
sub close
|
sub close
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
$self->{state} = 'closed';
|
$self->{state} = 'closed';
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@ sub getCamParams
|
||||||
my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/get_camera_params.cgi" );
|
my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/get_camera_params.cgi" );
|
||||||
my $res = $self->{ua}->request($req);
|
my $res = $self->{ua}->request($req);
|
||||||
|
|
||||||
if ( $res->is_success )
|
if ( $res->is_success )
|
||||||
{
|
{
|
||||||
# Parse results setting values in %FCParams
|
# Parse results setting values in %FCParams
|
||||||
my $content = $res->decoded_content;
|
my $content = $res->decoded_content;
|
||||||
|
@ -141,7 +141,7 @@ sub getCamParams
|
||||||
while ($content =~ s/var\s+([^=]+)=([^;]+);//ms) {
|
while ($content =~ s/var\s+([^=]+)=([^;]+);//ms) {
|
||||||
$CamParams{$1} = $2;
|
$CamParams{$1} = $2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Error( "Error check failed:'".$res->status_line()."'" );
|
Error( "Error check failed:'".$res->status_line()."'" );
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#
|
#
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
#
|
#
|
||||||
# This module contains the common definitions and functions used by the rest
|
# This module contains the common definitions and functions used by the rest
|
||||||
# of the ZoneMinder scripts
|
# of the ZoneMinder scripts
|
||||||
#
|
#
|
||||||
package ZoneMinder::Database;
|
package ZoneMinder::Database;
|
||||||
|
@ -37,17 +37,17 @@ our @ISA = qw(Exporter ZoneMinder::Base);
|
||||||
# names by default without a very good reason. Use EXPORT_OK instead.
|
# names by default without a very good reason. Use EXPORT_OK instead.
|
||||||
# Do not simply export all your public functions/methods/constants.
|
# Do not simply export all your public functions/methods/constants.
|
||||||
|
|
||||||
# This allows declaration use ZoneMinder ':all';
|
# This allows declaration use ZoneMinder ':all';
|
||||||
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
||||||
# will save memory.
|
# will save memory.
|
||||||
our %EXPORT_TAGS = (
|
our %EXPORT_TAGS = (
|
||||||
'functions' => [ qw(
|
'functions' => [ qw(
|
||||||
zmDbConnect
|
zmDbConnect
|
||||||
zmDbDisconnect
|
zmDbDisconnect
|
||||||
zmDbGetMonitors
|
zmDbGetMonitors
|
||||||
zmDbGetMonitor
|
zmDbGetMonitor
|
||||||
zmDbGetMonitorAndControl
|
zmDbGetMonitorAndControl
|
||||||
) ]
|
) ]
|
||||||
);
|
);
|
||||||
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
||||||
|
|
||||||
|
@ -72,35 +72,44 @@ our $dbh = undef;
|
||||||
|
|
||||||
sub zmDbConnect
|
sub zmDbConnect
|
||||||
{
|
{
|
||||||
my $force = shift;
|
my $force = shift;
|
||||||
if ( $force )
|
if ( $force )
|
||||||
{
|
{
|
||||||
zmDbDisconnect();
|
zmDbDisconnect();
|
||||||
}
|
}
|
||||||
if ( !defined( $dbh ) )
|
if ( !defined( $dbh ) )
|
||||||
{
|
{
|
||||||
my ( $host, $port ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ );
|
my ( $host, $port ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ );
|
||||||
|
|
||||||
if ( defined($port) )
|
if ( defined($port) )
|
||||||
{
|
{
|
||||||
$dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$host.";port=".$port, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} );
|
$dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}
|
||||||
|
.";host=".$host
|
||||||
|
.";port=".$port
|
||||||
|
, $Config{ZM_DB_USER}
|
||||||
|
, $Config{ZM_DB_PASS}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$Config{ZM_DB_HOST}, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} );
|
$dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}
|
||||||
|
.";host=".$Config{ZM_DB_HOST}
|
||||||
|
, $Config{ZM_DB_USER}
|
||||||
|
, $Config{ZM_DB_PASS}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
$dbh->trace( 0 );
|
$dbh->trace( 0 );
|
||||||
}
|
}
|
||||||
return( $dbh );
|
return( $dbh );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub zmDbDisconnect
|
sub zmDbDisconnect
|
||||||
{
|
{
|
||||||
if ( defined( $dbh ) )
|
if ( defined( $dbh ) )
|
||||||
{
|
{
|
||||||
$dbh->disconnect();
|
$dbh->disconnect();
|
||||||
$dbh = undef;
|
$dbh = undef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use constant DB_MON_ALL => 0; # All monitors
|
use constant DB_MON_ALL => 0; # All monitors
|
||||||
|
@ -112,76 +121,86 @@ use constant DB_MON_PASSIVE => 5; # All monitors that are in nodect state
|
||||||
|
|
||||||
sub zmDbGetMonitors
|
sub zmDbGetMonitors
|
||||||
{
|
{
|
||||||
zmDbConnect();
|
zmDbConnect();
|
||||||
|
|
||||||
my $function = shift || DB_MON_ALL;
|
my $function = shift || DB_MON_ALL;
|
||||||
my $sql = "select * from Monitors";
|
my $sql = "select * from Monitors";
|
||||||
|
|
||||||
if ( $function )
|
if ( $function )
|
||||||
{
|
{
|
||||||
if ( $function == DB_MON_CAPT )
|
if ( $function == DB_MON_CAPT )
|
||||||
{
|
{
|
||||||
$sql .= " where Function >= 'Monitor'";
|
$sql .= " where Function >= 'Monitor'";
|
||||||
}
|
}
|
||||||
elsif ( $function == DB_MON_ACTIVE )
|
elsif ( $function == DB_MON_ACTIVE )
|
||||||
{
|
{
|
||||||
$sql .= " where Function > 'Monitor'";
|
$sql .= " where Function > 'Monitor'";
|
||||||
}
|
}
|
||||||
elsif ( $function == DB_MON_MOTION )
|
elsif ( $function == DB_MON_MOTION )
|
||||||
{
|
{
|
||||||
$sql .= " where Function = 'Modect' or Function = 'Mocord'";
|
$sql .= " where Function = 'Modect' or Function = 'Mocord'";
|
||||||
}
|
}
|
||||||
elsif ( $function == DB_MON_RECORD )
|
elsif ( $function == DB_MON_RECORD )
|
||||||
{
|
{
|
||||||
$sql .= " where Function = 'Record' or Function = 'Mocord'";
|
$sql .= " where Function = 'Record' or Function = 'Mocord'";
|
||||||
}
|
}
|
||||||
elsif ( $function == DB_MON_PASSIVE )
|
elsif ( $function == DB_MON_PASSIVE )
|
||||||
{
|
{
|
||||||
$sql .= " where Function = 'Nodect'";
|
$sql .= " where Function = 'Nodect'";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
my $sth = $dbh->prepare_cached( $sql )
|
||||||
my $res = $sth->execute() or croak( "Can't execute '$sql': ".$sth->errstr() );
|
or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||||
|
my $res = $sth->execute()
|
||||||
|
or croak( "Can't execute '$sql': ".$sth->errstr() );
|
||||||
|
|
||||||
my @monitors;
|
my @monitors;
|
||||||
while( my $monitor = $sth->fetchrow_hashref() )
|
while( my $monitor = $sth->fetchrow_hashref() )
|
||||||
{
|
{
|
||||||
push( @monitors, $monitor );
|
push( @monitors, $monitor );
|
||||||
}
|
}
|
||||||
$sth->finish();
|
$sth->finish();
|
||||||
return( \@monitors );
|
return( \@monitors );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub zmDbGetMonitor
|
sub zmDbGetMonitor
|
||||||
{
|
{
|
||||||
zmDbConnect();
|
zmDbConnect();
|
||||||
|
|
||||||
my $id = shift;
|
my $id = shift;
|
||||||
|
|
||||||
return( undef ) if ( !defined($id) );
|
return( undef ) if ( !defined($id) );
|
||||||
|
|
||||||
my $sql = "select * from Monitors where Id = ?";
|
my $sql = "select * from Monitors where Id = ?";
|
||||||
my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
my $sth = $dbh->prepare_cached( $sql )
|
||||||
my $res = $sth->execute( $id ) or croak( "Can't execute '$sql': ".$sth->errstr() );
|
or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||||
|
my $res = $sth->execute( $id )
|
||||||
|
or croak( "Can't execute '$sql': ".$sth->errstr() );
|
||||||
my $monitor = $sth->fetchrow_hashref();
|
my $monitor = $sth->fetchrow_hashref();
|
||||||
|
|
||||||
return( $monitor );
|
return( $monitor );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub zmDbGetMonitorAndControl
|
sub zmDbGetMonitorAndControl
|
||||||
{
|
{
|
||||||
zmDbConnect();
|
zmDbConnect();
|
||||||
|
|
||||||
my $id = shift;
|
my $id = shift;
|
||||||
|
|
||||||
return( undef ) if ( !defined($id) );
|
return( undef ) if ( !defined($id) );
|
||||||
|
|
||||||
my $sql = "select C.*,M.*,C.Protocol from Monitors as M inner join Controls as C on (M.ControlId = C.Id) where M.Id = ?";
|
my $sql = "SELECT C.*,M.*,C.Protocol
|
||||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
FROM Monitors as M
|
||||||
my $res = $sth->execute( $id ) or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
INNER 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( $id )
|
||||||
|
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||||
my $monitor = $sth->fetchrow_hashref();
|
my $monitor = $sth->fetchrow_hashref();
|
||||||
|
|
||||||
return( $monitor );
|
return( $monitor );
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#
|
#
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
#
|
#
|
||||||
# This module contains the common definitions and functions used by the rest
|
# This module contains the common definitions and functions used by the rest
|
||||||
# of the ZoneMinder scripts
|
# of the ZoneMinder scripts
|
||||||
#
|
#
|
||||||
package ZoneMinder::General;
|
package ZoneMinder::General;
|
||||||
|
@ -203,13 +203,26 @@ sub getEventPath
|
||||||
my $event_path = "";
|
my $event_path = "";
|
||||||
if ( $Config{ZM_USE_DEEP_STORAGE} )
|
if ( $Config{ZM_USE_DEEP_STORAGE} )
|
||||||
{
|
{
|
||||||
$event_path = $Config{ZM_DIR_EVENTS}.'/'.$event->{MonitorId}.'/'.strftime( "%y/%m/%d/%H/%M/%S", localtime($event->{Time}) );
|
$event_path = $Config{ZM_DIR_EVENTS}
|
||||||
|
.'/'.$event->{MonitorId}
|
||||||
|
.'/'.strftime( "%y/%m/%d/%H/%M/%S",
|
||||||
|
localtime($event->{Time})
|
||||||
|
)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$event_path = $Config{ZM_DIR_EVENTS}.'/'.$event->{MonitorId}.'/'.$event->{Id};
|
$event_path = $Config{ZM_DIR_EVENTS}
|
||||||
|
.'/'.$event->{MonitorId}
|
||||||
|
.'/'.$event->{Id}
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( index($Config{ZM_DIR_EVENTS},'/') != 0 ){
|
||||||
|
$event_path = $Config{ZM_PATH_WEB}
|
||||||
|
.'/'.$event_path
|
||||||
|
;
|
||||||
}
|
}
|
||||||
$event_path = $Config{ZM_PATH_WEB}.'/'.$event_path if ( index($Config{ZM_DIR_EVENTS},'/') != 0 );
|
|
||||||
return( $event_path );
|
return( $event_path );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +232,9 @@ sub createEventPath
|
||||||
# WARNING assumes running from events directory
|
# WARNING assumes running from events directory
|
||||||
#
|
#
|
||||||
my $event = shift;
|
my $event = shift;
|
||||||
my $eventRootPath = ($Config{ZM_DIR_EVENTS}=~m|/|)?$Config{ZM_DIR_EVENTS}:($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS});
|
my $eventRootPath = ($Config{ZM_DIR_EVENTS}=~m|/|)
|
||||||
|
? $Config{ZM_DIR_EVENTS}
|
||||||
|
: ($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS});
|
||||||
my $eventPath = $eventRootPath.'/'.$event->{MonitorId};
|
my $eventPath = $eventRootPath.'/'.$event->{MonitorId};
|
||||||
|
|
||||||
if ( $Config{ZM_USE_DEEP_STORAGE} )
|
if ( $Config{ZM_USE_DEEP_STORAGE} )
|
||||||
|
@ -242,7 +257,8 @@ sub createEventPath
|
||||||
|
|
||||||
# Create event id symlink
|
# Create event id symlink
|
||||||
my $idFile = sprintf( "%s/.%d", $eventPath, $event->{Id} );
|
my $idFile = sprintf( "%s/.%d", $eventPath, $event->{Id} );
|
||||||
symlink( $timePath, $idFile ) or Fatal( "Can't symlink $idFile -> $eventPath: $!" );
|
symlink( $timePath, $idFile )
|
||||||
|
or Fatal( "Can't symlink $idFile -> $eventPath: $!" );
|
||||||
|
|
||||||
makePath( $timePath, $eventPath );
|
makePath( $timePath, $eventPath );
|
||||||
$eventPath .= '/'.$timePath;
|
$eventPath .= '/'.$timePath;
|
||||||
|
@ -281,8 +297,13 @@ sub _checkProcessOwner
|
||||||
my ( $processOwner ) = getpwuid( $> );
|
my ( $processOwner ) = getpwuid( $> );
|
||||||
if ( $processOwner ne $Config{ZM_WEB_USER} )
|
if ( $processOwner ne $Config{ZM_WEB_USER} )
|
||||||
{
|
{
|
||||||
# Not running as web user, so should be root in whch case chown the temporary directory
|
# Not running as web user, so should be root in which case chown
|
||||||
( my $ownerName, my $ownerPass, $_ownerUid, $_ownerGid ) = getpwnam( $Config{ZM_WEB_USER} ) or Fatal( "Can't get user details for web user '".$Config{ZM_WEB_USER}."': $!" );
|
# the temporary directory
|
||||||
|
( my $ownerName, my $ownerPass, $_ownerUid, $_ownerGid )
|
||||||
|
= getpwnam( $Config{ZM_WEB_USER} )
|
||||||
|
or Fatal( "Can't get user details for web user '"
|
||||||
|
.$Config{ZM_WEB_USER}."': $!"
|
||||||
|
);
|
||||||
$_setFileOwner = 1;
|
$_setFileOwner = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -299,7 +320,10 @@ sub setFileOwner
|
||||||
|
|
||||||
if ( _checkProcessOwner() )
|
if ( _checkProcessOwner() )
|
||||||
{
|
{
|
||||||
chown( $_ownerUid, $_ownerGid, $file ) or Fatal( "Can't change ownership of file '$file' to '".$Config{ZM_WEB_USER}.":".$Config{ZM_WEB_GROUP}."': $!" );
|
chown( $_ownerUid, $_ownerGid, $file )
|
||||||
|
or Fatal( "Can't change ownership of file '$file' to '"
|
||||||
|
.$Config{ZM_WEB_USER}.":".$Config{ZM_WEB_GROUP}."': $!"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,9 +361,14 @@ sub createEvent
|
||||||
elsif ( $event->{MonitorId} )
|
elsif ( $event->{MonitorId} )
|
||||||
{
|
{
|
||||||
my $sql = "select * from Monitors where Id = ?";
|
my $sql = "select * from Monitors where Id = ?";
|
||||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
my $sth = $dbh->prepare_cached( $sql )
|
||||||
my $res = $sth->execute( $event->{MonitorId} ) or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
||||||
$event->{monitor} = $sth->fetchrow_hashref() or Fatal( "Unable to create event, can't load monitor with id '".$event->{MonitorId}."'" );
|
my $res = $sth->execute( $event->{MonitorId} )
|
||||||
|
or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
||||||
|
$event->{monitor} = $sth->fetchrow_hashref()
|
||||||
|
or Fatal( "Unable to create event, can't load monitor with id '"
|
||||||
|
.$event->{MonitorId}."'"
|
||||||
|
);
|
||||||
$sth->finish();
|
$sth->finish();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -360,7 +389,9 @@ sub createEvent
|
||||||
my $imageInfo = Image::Info::image_info( $frame->{imagePath} );
|
my $imageInfo = Image::Info::image_info( $frame->{imagePath} );
|
||||||
if ( $imageInfo->{error} )
|
if ( $imageInfo->{error} )
|
||||||
{
|
{
|
||||||
Error( "Unable to extract image info from '".$frame->{imagePath}."': ".$imageInfo->{error} );
|
Error( "Unable to extract image info from '"
|
||||||
|
.$frame->{imagePath}."': ".$imageInfo->{error}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -396,18 +427,25 @@ sub createEvent
|
||||||
push( @values, $event->{$field} );
|
push( @values, $event->{$field} );
|
||||||
}
|
}
|
||||||
|
|
||||||
my $sql = "insert into Events (".join(',',@fields).") values (".join(',',@formats).")";
|
my $sql = "INSERT INTO Events (".join(',',@fields)
|
||||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
.") VALUES (".join(',',@formats).")"
|
||||||
my $res = $sth->execute( @values ) or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
;
|
||||||
|
my $sth = $dbh->prepare_cached( $sql )
|
||||||
|
or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
||||||
|
my $res = $sth->execute( @values )
|
||||||
|
or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
||||||
$event->{Id} = $dbh->{mysql_insertid};
|
$event->{Id} = $dbh->{mysql_insertid};
|
||||||
Info( "Created event ".$event->{Id} );
|
Info( "Created event ".$event->{Id} );
|
||||||
|
|
||||||
if ( $event->{EndTime} )
|
if ( $event->{EndTime} )
|
||||||
{
|
{
|
||||||
$event->{Name} = $event->{monitor}->{EventPrefix}.$event->{Id} if ( $event->{Name} eq 'New Event' );
|
$event->{Name} = $event->{monitor}->{EventPrefix}.$event->{Id}
|
||||||
|
if ( $event->{Name} eq 'New Event' );
|
||||||
my $sql = "update Events set Name = ? where Id = ?";
|
my $sql = "update Events set Name = ? where Id = ?";
|
||||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
my $sth = $dbh->prepare_cached( $sql )
|
||||||
my $res = $sth->execute( $event->{Name}, $event->{Id} ) or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
||||||
|
my $res = $sth->execute( $event->{Name}, $event->{Id} )
|
||||||
|
or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
||||||
}
|
}
|
||||||
|
|
||||||
my $eventPath = createEventPath( $event );
|
my $eventPath = createEventPath( $event );
|
||||||
|
@ -430,19 +468,39 @@ sub createEvent
|
||||||
push( @values, $frame->{$field} );
|
push( @values, $frame->{$field} );
|
||||||
}
|
}
|
||||||
|
|
||||||
my $sql = "insert into Frames (".join(',',@fields).") values (".join(',',@formats).")";
|
my $sql = "insert into Frames (".join(',',@fields)
|
||||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
.") values (".join(',',@formats).")"
|
||||||
my $res = $sth->execute( @values ) or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
;
|
||||||
|
my $sth = $dbh->prepare_cached( $sql )
|
||||||
|
or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
||||||
|
my $res = $sth->execute( @values )
|
||||||
|
or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
||||||
#$frame->{FrameId} = $dbh->{mysql_insertid};
|
#$frame->{FrameId} = $dbh->{mysql_insertid};
|
||||||
if ( $frame->{imagePath} )
|
if ( $frame->{imagePath} )
|
||||||
{
|
{
|
||||||
$frame->{capturePath} = sprintf( "%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg", $eventPath, $frame->{FrameId} );
|
$frame->{capturePath} = sprintf(
|
||||||
rename( $frame->{imagePath}, $frame->{capturePath} ) or Fatal( "Can't copy ".$frame->{imagePath}." to ".$frame->{capturePath}.": $!" );
|
"%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}
|
||||||
|
."d-capture.jpg"
|
||||||
|
, $eventPath
|
||||||
|
, $frame->{FrameId}
|
||||||
|
);
|
||||||
|
rename( $frame->{imagePath}, $frame->{capturePath} )
|
||||||
|
or Fatal( "Can't copy ".$frame->{imagePath}
|
||||||
|
." to ".$frame->{capturePath}.": $!"
|
||||||
|
);
|
||||||
setFileOwner( $frame->{capturePath} );
|
setFileOwner( $frame->{capturePath} );
|
||||||
if ( 0 && $Config{ZM_CREATE_ANALYSIS_IMAGES} )
|
if ( 0 && $Config{ZM_CREATE_ANALYSIS_IMAGES} )
|
||||||
{
|
{
|
||||||
$frame->{analysePath} = sprintf( "%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-analyse.jpg", $eventPath, $frame->{FrameId} );
|
$frame->{analysePath} = sprintf(
|
||||||
link( $frame->{capturePath}, $frame->{analysePath} ) or Fatal( "Can't link ".$frame->{capturePath}." to ".$frame->{analysePath}.": $!" );
|
"%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}
|
||||||
|
."d-analyse.jpg"
|
||||||
|
, $eventPath
|
||||||
|
, $frame->{FrameId}
|
||||||
|
);
|
||||||
|
link( $frame->{capturePath}, $frame->{analysePath} )
|
||||||
|
or Fatal( "Can't link ".$frame->{capturePath}
|
||||||
|
." to ".$frame->{analysePath}.": $!"
|
||||||
|
);
|
||||||
setFileOwner( $frame->{analysePath} );
|
setFileOwner( $frame->{analysePath} );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -469,7 +527,8 @@ sub updateEvent
|
||||||
|
|
||||||
my $dbh = zmDbConnect();
|
my $dbh = zmDbConnect();
|
||||||
|
|
||||||
$event->{Name} = $event->{monitor}->{EventPrefix}.$event->{Id} if ( $event->{Name} eq 'New Event' );
|
$event->{Name} = $event->{monitor}->{EventPrefix}.$event->{Id}
|
||||||
|
if ( $event->{Name} eq 'New Event' );
|
||||||
|
|
||||||
my %formats = (
|
my %formats = (
|
||||||
StartTime => 'from_unixtime(?)',
|
StartTime => 'from_unixtime(?)',
|
||||||
|
@ -486,8 +545,10 @@ sub updateEvent
|
||||||
my $sql = "update Events set ".join(',',@sets)." where Id = ?";
|
my $sql = "update Events set ".join(',',@sets)." where Id = ?";
|
||||||
push( @values, $event->{Id} );
|
push( @values, $event->{Id} );
|
||||||
|
|
||||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
my $sth = $dbh->prepare_cached( $sql )
|
||||||
my $res = $sth->execute( @values ) or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
||||||
|
my $res = $sth->execute( @values )
|
||||||
|
or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub deleteEventFiles
|
sub deleteEventFiles
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#
|
#
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
#
|
#
|
||||||
# This module contains the debug definitions and functions used by the rest
|
# This module contains the debug definitions and functions used by the rest
|
||||||
# of the ZoneMinder scripts
|
# of the ZoneMinder scripts
|
||||||
#
|
#
|
||||||
package ZoneMinder::Logger;
|
package ZoneMinder::Logger;
|
||||||
|
@ -258,7 +258,12 @@ sub initialise( @ )
|
||||||
{
|
{
|
||||||
foreach my $target ( split( /\|/, $Config{ZM_LOG_DEBUG_TARGET} ) )
|
foreach my $target ( split( /\|/, $Config{ZM_LOG_DEBUG_TARGET} ) )
|
||||||
{
|
{
|
||||||
if ( $target eq $this->{id} || $target eq "_".$this->{id} || $target eq $this->{idRoot} || $target eq "_".$this->{idRoot} || $target eq "" )
|
if ( $target eq $this->{id}
|
||||||
|
|| $target eq "_".$this->{id}
|
||||||
|
|| $target eq $this->{idRoot}
|
||||||
|
|| $target eq "_".$this->{idRoot}
|
||||||
|
|| $target eq ""
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if ( $Config{ZM_LOG_DEBUG_LEVEL} > NOLOG )
|
if ( $Config{ZM_LOG_DEBUG_LEVEL} > NOLOG )
|
||||||
{
|
{
|
||||||
|
@ -287,8 +292,15 @@ sub initialise( @ )
|
||||||
$this->{autoFlush} = $ENV{'LOG_FLUSH'}?1:0 if ( defined($ENV{'LOG_FLUSH'}) );
|
$this->{autoFlush} = $ENV{'LOG_FLUSH'}?1:0 if ( defined($ENV{'LOG_FLUSH'}) );
|
||||||
|
|
||||||
$this->{initialised} = !undef;
|
$this->{initialised} = !undef;
|
||||||
|
|
||||||
Debug( "LogOpts: level=".$codes{$this->{level}}."/".$codes{$this->{effectiveLevel}}.", screen=".$codes{$this->{termLevel}}.", database=".$codes{$this->{databaseLevel}}.", logfile=".$codes{$this->{fileLevel}}."->".$this->{logFile}.", syslog=".$codes{$this->{syslogLevel}} );
|
Debug( "LogOpts: level=".$codes{$this->{level}}
|
||||||
|
."/".$codes{$this->{effectiveLevel}}
|
||||||
|
.", screen=".$codes{$this->{termLevel}}
|
||||||
|
.", database=".$codes{$this->{databaseLevel}}
|
||||||
|
.", logfile=".$codes{$this->{fileLevel}}
|
||||||
|
."->".$this->{logFile}
|
||||||
|
.", syslog=".$codes{$this->{syslogLevel}}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub terminate
|
sub terminate
|
||||||
|
@ -452,23 +464,39 @@ sub databaseLevel
|
||||||
|
|
||||||
if ( defined($port) )
|
if ( defined($port) )
|
||||||
{
|
{
|
||||||
$this->{dbh} = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$host.";port=".$port, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} );
|
$this->{dbh} = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}
|
||||||
|
.";host=".$host
|
||||||
|
.";port=".$port
|
||||||
|
, $Config{ZM_DB_USER}
|
||||||
|
, $Config{ZM_DB_PASS}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$this->{dbh} = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$Config{ZM_DB_HOST}, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} );
|
$this->{dbh} = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}
|
||||||
|
.";host=".$Config{ZM_DB_HOST}
|
||||||
|
, $Config{ZM_DB_USER}
|
||||||
|
, $Config{ZM_DB_PASS}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if ( !$this->{dbh} )
|
if ( !$this->{dbh} )
|
||||||
{
|
{
|
||||||
$databaseLevel = NOLOG;
|
$databaseLevel = NOLOG;
|
||||||
Error( "Unable to write log entries to DB, can't connect to database '".$Config{ZM_DB_NAME}."' on host '".$Config{ZM_DB_HOST}."'" );
|
Error( "Unable to write log entries to DB, can't connect to database '"
|
||||||
|
.$Config{ZM_DB_NAME}
|
||||||
|
."' on host '"
|
||||||
|
.$Config{ZM_DB_HOST}
|
||||||
|
."'"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$this->{dbh}->{AutoCommit} = 1;
|
$this->{dbh}->{AutoCommit} = 1;
|
||||||
Fatal( "Can't set AutoCommit on in database connection" ) unless( $this->{dbh}->{AutoCommit} );
|
Fatal( "Can't set AutoCommit on in database connection" )
|
||||||
|
unless( $this->{dbh}->{AutoCommit} );
|
||||||
$this->{dbh}->{mysql_auto_reconnect} = 1;
|
$this->{dbh}->{mysql_auto_reconnect} = 1;
|
||||||
Fatal( "Can't set mysql_auto_reconnect on in database connection" ) unless( $this->{dbh}->{mysql_auto_reconnect} );
|
Fatal( "Can't set mysql_auto_reconnect on in database connection" )
|
||||||
|
unless( $this->{dbh}->{mysql_auto_reconnect} );
|
||||||
$this->{dbh}->trace( 0 );
|
$this->{dbh}->trace( 0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -559,7 +587,9 @@ sub openFile
|
||||||
if ( $> == 0 )
|
if ( $> == 0 )
|
||||||
{
|
{
|
||||||
chown( $webUid, $webGid, $this->{logFile} )
|
chown( $webUid, $webGid, $this->{logFile} )
|
||||||
or Fatal( "Can't change permissions on log file '".$this->{logFile}."': $!" )
|
or Fatal( "Can't change permissions on log file '"
|
||||||
|
.$this->{logFile}."': $!"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -588,7 +618,17 @@ sub logPrint
|
||||||
my $code = $codes{$level};
|
my $code = $codes{$level};
|
||||||
|
|
||||||
my ($seconds, $microseconds) = gettimeofday();
|
my ($seconds, $microseconds) = gettimeofday();
|
||||||
my $message = sprintf( "%s.%06d %s[%d].%s [%s]", strftime( "%x %H:%M:%S", localtime( $seconds ) ), $microseconds, $this->{id}, $$, $code, $string );
|
my $message = sprintf(
|
||||||
|
"%s.%06d %s[%d].%s [%s]"
|
||||||
|
, strftime( "%x %H:%M:%S"
|
||||||
|
,localtime( $seconds )
|
||||||
|
)
|
||||||
|
, $microseconds
|
||||||
|
, $this->{id}
|
||||||
|
, $$
|
||||||
|
, $code
|
||||||
|
, $string
|
||||||
|
);
|
||||||
if ( $this->{trace} )
|
if ( $this->{trace} )
|
||||||
{
|
{
|
||||||
$message = Carp::shortmess( $message );
|
$message = Carp::shortmess( $message );
|
||||||
|
@ -597,7 +637,8 @@ sub logPrint
|
||||||
{
|
{
|
||||||
$message = $message."\n";
|
$message = $message."\n";
|
||||||
}
|
}
|
||||||
syslog( $priorities{$level}, $code." [%s]", $string ) if ( $level <= $this->{syslogLevel} );
|
syslog( $priorities{$level}, $code." [%s]", $string )
|
||||||
|
if ( $level <= $this->{syslogLevel} );
|
||||||
print( $LOGFILE $message ) if ( $level <= $this->{fileLevel} );
|
print( $LOGFILE $message ) if ( $level <= $this->{fileLevel} );
|
||||||
if ( $level <= $this->{databaseLevel} )
|
if ( $level <= $this->{databaseLevel} )
|
||||||
{
|
{
|
||||||
|
@ -608,7 +649,14 @@ sub logPrint
|
||||||
$this->{databaseLevel} = NOLOG;
|
$this->{databaseLevel} = NOLOG;
|
||||||
Fatal( "Can't prepare log entry '$sql': ".$this->{dbh}->errstr() );
|
Fatal( "Can't prepare log entry '$sql': ".$this->{dbh}->errstr() );
|
||||||
}
|
}
|
||||||
my $res = $this->{sth}->execute( $seconds+($microseconds/1000000.0), $this->{id}, $$, $level, $code, $string, $this->{fileName} );
|
my $res = $this->{sth}->execute( $seconds+($microseconds/1000000.0)
|
||||||
|
, $this->{id}
|
||||||
|
, $$
|
||||||
|
, $level
|
||||||
|
, $code
|
||||||
|
, $string
|
||||||
|
, $this->{fileName}
|
||||||
|
);
|
||||||
if ( !$res )
|
if ( !$res )
|
||||||
{
|
{
|
||||||
$this->{databaseLevel} = NOLOG;
|
$this->{databaseLevel} = NOLOG;
|
||||||
|
@ -758,11 +806,19 @@ ZoneMinder::Logger - ZoneMinder Logger module
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
The ZoneMinder:Logger module contains the common debug and error reporting routines used by the ZoneMinder scripts.
|
The ZoneMinder:Logger module contains the common debug and error reporting
|
||||||
|
routines used by the ZoneMinder scripts.
|
||||||
|
|
||||||
To use debug in your scripts you need to include this module, and call logInit. Thereafter you can sprinkle Debug or Error calls etc throughout the code safe in the knowledge that they will be reported to your error log, and possibly the syslogger, in a meaningful and consistent format.
|
To use debug in your scripts you need to include this module, and call
|
||||||
|
logInit. Thereafter you can sprinkle Debug or Error calls etc throughout
|
||||||
|
the code safe in the knowledge that they will be reported to your error
|
||||||
|
log, and possibly the syslogger, in a meaningful and consistent format.
|
||||||
|
|
||||||
Debug is discussed in terms of levels where 1 and above (currently only 1 for scripts) is considered debug, 0 is considered as informational, -1 is a warning, -2 is an error and -3 is a fatal error or panic. Where levels are mentioned below as thresholds the value given and anything with a lower level (ie. more serious) will be included.
|
Debug is discussed in terms of levels where 1 and above (currently only 1
|
||||||
|
for scripts) is considered debug, 0 is considered as informational, -1 is a
|
||||||
|
warning, -2 is an error and -3 is a fatal error or panic. Where levels are
|
||||||
|
mentioned below as thresholds the value given and anything with a lower
|
||||||
|
level (ie. more serious) will be included.
|
||||||
|
|
||||||
=head1 METHODS
|
=head1 METHODS
|
||||||
|
|
||||||
|
@ -770,7 +826,12 @@ Debug is discussed in terms of levels where 1 and above (currently only 1 for sc
|
||||||
|
|
||||||
=item logInit ( $id, %options );
|
=item logInit ( $id, %options );
|
||||||
|
|
||||||
Initialises the debug and prepares the logging for forthcoming operations. If not called explicitly it will be called by the first debug call in your script, but with default (and probably meaningless) options. The only compulsory arguments are $id which must be a string that will identify debug coming from this script in mixed logs. Other options may be provided as below,
|
Initialises the debug and prepares the logging for forthcoming operations.
|
||||||
|
If not called explicitly it will be called by the first debug call in your
|
||||||
|
script, but with default (and probably meaningless) options. The only
|
||||||
|
compulsory arguments are $id which must be a string that will identify
|
||||||
|
debug coming from this script in mixed logs. Other options may be provided
|
||||||
|
as below,
|
||||||
|
|
||||||
Option Default Description
|
Option Default Description
|
||||||
--------- --------- -----------
|
--------- --------- -----------
|
||||||
|
@ -807,27 +868,39 @@ These methods can be used to get and set the current settings as defined in logI
|
||||||
|
|
||||||
=item Debug( $string );
|
=item Debug( $string );
|
||||||
|
|
||||||
This method will output a debug message if the current debug level permits it, otherwise does nothing. This message will be tagged with the DBG string in the logs.
|
This method will output a debug message if the current debug level permits
|
||||||
|
it, otherwise does nothing. This message will be tagged with the DBG string
|
||||||
|
in the logs.
|
||||||
|
|
||||||
=item Info( $string );
|
=item Info( $string );
|
||||||
|
|
||||||
This method will output an informational message if the current debug level permits it, otherwise does nothing. This message will be tagged with the INF string in the logs.
|
This method will output an informational message if the current debug level
|
||||||
|
permits it, otherwise does nothing. This message will be tagged with the
|
||||||
|
INF string in the logs.
|
||||||
|
|
||||||
=item Warning( $string );
|
=item Warning( $string );
|
||||||
|
|
||||||
This method will output a warning message if the current debug level permits it, otherwise does nothing. This message will be tagged with the WAR string in the logs.
|
This method will output a warning message if the current debug level
|
||||||
|
permits it, otherwise does nothing. This message will be tagged with the
|
||||||
|
WAR string in the logs.
|
||||||
|
|
||||||
=item Error( $string );
|
=item Error( $string );
|
||||||
|
|
||||||
This method will output an error message if the current debug level permits it, otherwise does nothing. This message will be tagged with the ERR string in the logs.
|
This method will output an error message if the current debug level permits
|
||||||
|
it, otherwise does nothing. This message will be tagged with the ERR string
|
||||||
|
in the logs.
|
||||||
|
|
||||||
=item Fatal( $string );
|
=item Fatal( $string );
|
||||||
|
|
||||||
This method will output a fatal error message and then die if the current debug level permits it, otherwise does nothing. This message will be tagged with the FAT string in the logs.
|
This method will output a fatal error message and then die if the current
|
||||||
|
debug level permits it, otherwise does nothing. This message will be tagged
|
||||||
|
with the FAT string in the logs.
|
||||||
|
|
||||||
=item Panic( $string );
|
=item Panic( $string );
|
||||||
|
|
||||||
This method will output a panic error message and then die with a stack trace if the current debug level permits it, otherwise does nothing. This message will be tagged with the PNC string in the logs.
|
This method will output a panic error message and then die with a stack
|
||||||
|
trace if the current debug level permits it, otherwise does nothing. This
|
||||||
|
message will be tagged with the PNC string in the logs.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
@ -845,7 +918,8 @@ The :all tag will export all above symbols.
|
||||||
Carp
|
Carp
|
||||||
Sys::Syslog
|
Sys::Syslog
|
||||||
|
|
||||||
The ZoneMinder README file Troubleshooting section for an extended discussion on the use and configuration of syslog with ZoneMinder.
|
The ZoneMinder README file Troubleshooting section for an extended
|
||||||
|
discussion on the use and configuration of syslog with ZoneMinder.
|
||||||
|
|
||||||
http://www.zoneminder.com
|
http://www.zoneminder.com
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -36,18 +36,18 @@ our @ISA = qw(Exporter ZoneMinder::Base);
|
||||||
# names by default without a very good reason. Use EXPORT_OK instead.
|
# names by default without a very good reason. Use EXPORT_OK instead.
|
||||||
# Do not simply export all your public functions/methods/constants.
|
# Do not simply export all your public functions/methods/constants.
|
||||||
|
|
||||||
# This allows declaration use ZoneMinder ':all';
|
# This allows declaration use ZoneMinder ':all';
|
||||||
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
||||||
# will save memory.
|
# will save memory.
|
||||||
our %EXPORT_TAGS = (
|
our %EXPORT_TAGS = (
|
||||||
'functions' => [ qw(
|
'functions' => [ qw(
|
||||||
zmMemKey
|
zmMemKey
|
||||||
zmMemAttach
|
zmMemAttach
|
||||||
zmMemDetach
|
zmMemDetach
|
||||||
zmMemGet
|
zmMemGet
|
||||||
zmMemPut
|
zmMemPut
|
||||||
zmMemClean
|
zmMemClean
|
||||||
) ],
|
) ],
|
||||||
);
|
);
|
||||||
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
||||||
|
|
||||||
|
@ -70,115 +70,129 @@ use Sys::Mmap;
|
||||||
|
|
||||||
sub zmMemKey
|
sub zmMemKey
|
||||||
{
|
{
|
||||||
my $monitor = shift;
|
my $monitor = shift;
|
||||||
return( defined($monitor->{MMapAddr})?$monitor->{MMapAddr}:undef );
|
return( defined($monitor->{MMapAddr})?$monitor->{MMapAddr}:undef );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub zmMemAttach
|
sub zmMemAttach
|
||||||
{
|
{
|
||||||
my ( $monitor, $size ) = @_;
|
my ( $monitor, $size ) = @_;
|
||||||
if ( ! $size ) {
|
if ( ! $size ) {
|
||||||
Error( "No size passed to zmMemAttach for monitor $$monitor{Id}\n" );
|
Error( "No size passed to zmMemAttach for monitor $$monitor{Id}\n" );
|
||||||
return( undef );
|
return( undef );
|
||||||
}
|
}
|
||||||
if ( !defined($monitor->{MMapAddr}) )
|
if ( !defined($monitor->{MMapAddr}) )
|
||||||
{
|
{
|
||||||
|
|
||||||
my $mmap_file = $Config{ZM_PATH_MAP}."/zm.mmap.".$monitor->{Id};
|
my $mmap_file = $Config{ZM_PATH_MAP}."/zm.mmap.".$monitor->{Id};
|
||||||
if ( ! -e $mmap_file ) {
|
if ( ! -e $mmap_file ) {
|
||||||
Error( sprintf( "Memory map file '%s' does not exist. zmc might not be running.", $mmap_file ) );
|
Error( sprintf( "Memory map file '%s' does not exist. zmc might not be running."
|
||||||
return ( undef );
|
, $mmap_file
|
||||||
}
|
)
|
||||||
|
);
|
||||||
|
return ( undef );
|
||||||
|
}
|
||||||
|
|
||||||
my $mmap_file_size = -s $mmap_file;
|
my $mmap_file_size = -s $mmap_file;
|
||||||
|
|
||||||
if ( $mmap_file_size < $size ) {
|
if ( $mmap_file_size < $size ) {
|
||||||
Error( sprintf( "Memory map file '%s' should have been %d but was instead %d", $mmap_file, $size, $mmap_file_size ) );
|
Error( sprintf( "Memory map file '%s' should have been %d but was instead %d"
|
||||||
return ( undef );
|
, $mmap_file
|
||||||
}
|
, $size
|
||||||
|
, $mmap_file_size
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return ( undef );
|
||||||
|
}
|
||||||
if ( !open( MMAP, "+<", $mmap_file ) )
|
if ( !open( MMAP, "+<", $mmap_file ) )
|
||||||
{
|
{
|
||||||
Error( sprintf( "Can't open memory map file '%s': $!\n", $mmap_file ) );
|
Error( sprintf( "Can't open memory map file '%s': $!\n", $mmap_file ) );
|
||||||
return( undef );
|
return( undef );
|
||||||
}
|
}
|
||||||
my $mmap = undef;
|
my $mmap = undef;
|
||||||
my $mmap_addr = mmap( $mmap, $size, PROT_READ|PROT_WRITE, MAP_SHARED, \*MMAP );
|
my $mmap_addr = mmap( $mmap, $size, PROT_READ|PROT_WRITE, MAP_SHARED, \*MMAP );
|
||||||
if ( !$mmap_addr || !$mmap )
|
if ( !$mmap_addr || !$mmap )
|
||||||
{
|
{
|
||||||
Error( sprintf( "Can't mmap to file '%s': $!\n", $mmap_file ) );
|
Error( sprintf( "Can't mmap to file '%s': $!\n", $mmap_file ) );
|
||||||
close( MMAP );
|
close( MMAP );
|
||||||
return( undef );
|
return( undef );
|
||||||
}
|
}
|
||||||
$monitor->{MMapHandle} = \*MMAP;
|
$monitor->{MMapHandle} = \*MMAP;
|
||||||
$monitor->{MMapAddr} = $mmap_addr;
|
$monitor->{MMapAddr} = $mmap_addr;
|
||||||
$monitor->{MMap} = \$mmap;
|
$monitor->{MMap} = \$mmap;
|
||||||
}
|
}
|
||||||
return( !undef );
|
return( !undef );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub zmMemDetach
|
sub zmMemDetach
|
||||||
{
|
{
|
||||||
my $monitor = shift;
|
my $monitor = shift;
|
||||||
|
|
||||||
if ( $monitor->{MMap} )
|
if ( $monitor->{MMap} )
|
||||||
{
|
{
|
||||||
if ( ! munmap( ${$monitor->{MMap}} ) ) {
|
if ( ! munmap( ${$monitor->{MMap}} ) ) {
|
||||||
Warn( "Unable to munmap for monitor $$monitor{Id}\n");
|
Warn( "Unable to munmap for monitor $$monitor{Id}\n");
|
||||||
}
|
}
|
||||||
delete $monitor->{MMap};
|
delete $monitor->{MMap};
|
||||||
}
|
}
|
||||||
if ( $monitor->{MMapAddr} )
|
if ( $monitor->{MMapAddr} )
|
||||||
{
|
{
|
||||||
delete $monitor->{MMapAddr};
|
delete $monitor->{MMapAddr};
|
||||||
}
|
}
|
||||||
if ( $monitor->{MMapHandle} )
|
if ( $monitor->{MMapHandle} )
|
||||||
{
|
{
|
||||||
close( $monitor->{MMapHandle} );
|
close( $monitor->{MMapHandle} );
|
||||||
delete $monitor->{MMapHandle};
|
delete $monitor->{MMapHandle};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub zmMemGet
|
sub zmMemGet
|
||||||
{
|
{
|
||||||
my $monitor = shift;
|
my $monitor = shift;
|
||||||
my $offset = shift;
|
my $offset = shift;
|
||||||
my $size = shift;
|
my $size = shift;
|
||||||
|
|
||||||
my $mmap = $monitor->{MMap};
|
my $mmap = $monitor->{MMap};
|
||||||
if ( !$mmap || !$$mmap )
|
if ( !$mmap || !$$mmap )
|
||||||
{
|
{
|
||||||
Error( sprintf( "Can't read from mapped memory for monitor '%d', gone away?", $monitor->{Id} ) );
|
Error( sprintf( "Can't read from mapped memory for monitor '%d', gone away?"
|
||||||
|
, $monitor->{Id}
|
||||||
|
)
|
||||||
|
);
|
||||||
return( undef );
|
return( undef );
|
||||||
}
|
}
|
||||||
my $data = substr( $$mmap, $offset, $size );
|
my $data = substr( $$mmap, $offset, $size );
|
||||||
return( $data );
|
return( $data );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub zmMemPut
|
sub zmMemPut
|
||||||
{
|
{
|
||||||
my $monitor = shift;
|
my $monitor = shift;
|
||||||
my $offset = shift;
|
my $offset = shift;
|
||||||
my $size = shift;
|
my $size = shift;
|
||||||
my $data = shift;
|
my $data = shift;
|
||||||
|
|
||||||
my $mmap = $monitor->{MMap};
|
my $mmap = $monitor->{MMap};
|
||||||
if ( !$mmap || !$$mmap )
|
if ( !$mmap || !$$mmap )
|
||||||
{
|
{
|
||||||
Error( sprintf( "Can't write mapped memory for monitor '%d', gone away?", $monitor->{Id} ) );
|
Error( sprintf( "Can't write mapped memory for monitor '%d', gone away?"
|
||||||
|
, $monitor->{Id}
|
||||||
|
)
|
||||||
|
);
|
||||||
return( undef );
|
return( undef );
|
||||||
}
|
}
|
||||||
substr( $$mmap, $offset, $size ) = $data;
|
substr( $$mmap, $offset, $size ) = $data;
|
||||||
return( !undef );
|
return( !undef );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub zmMemClean
|
sub zmMemClean
|
||||||
{
|
{
|
||||||
Debug( "Removing memory map files\n" );
|
Debug( "Removing memory map files\n" );
|
||||||
my $mapPath = $Config{ZM_PATH_MAP}."/zm.mmap.*";
|
my $mapPath = $Config{ZM_PATH_MAP}."/zm.mmap.*";
|
||||||
foreach my $mapFile( glob( $mapPath ) )
|
foreach my $mapFile( glob( $mapPath ) )
|
||||||
{
|
{
|
||||||
( $mapFile ) = $mapFile =~ /^(.+)$/;
|
( $mapFile ) = $mapFile =~ /^(.+)$/;
|
||||||
Debug( "Removing memory map file '$mapFile'\n" );
|
Debug( "Removing memory map file '$mapFile'\n" );
|
||||||
unlink( $mapFile );
|
unlink( $mapFile );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#
|
#
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
#
|
#
|
||||||
# This module contains the common definitions and functions used by the rest
|
# This module contains the common definitions and functions used by the rest
|
||||||
# of the ZoneMinder scripts
|
# of the ZoneMinder scripts
|
||||||
#
|
#
|
||||||
package ZoneMinder::Memory::Shared;
|
package ZoneMinder::Memory::Shared;
|
||||||
|
@ -39,18 +39,18 @@ eval 'sub IPC_CREAT {0001000}' unless defined &IPC_CREAT;
|
||||||
# names by default without a very good reason. Use EXPORT_OK instead.
|
# names by default without a very good reason. Use EXPORT_OK instead.
|
||||||
# Do not simply export all your public functions/methods/constants.
|
# Do not simply export all your public functions/methods/constants.
|
||||||
|
|
||||||
# This allows declaration use ZoneMinder ':all';
|
# This allows declaration use ZoneMinder ':all';
|
||||||
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
||||||
# will save memory.
|
# will save memory.
|
||||||
our %EXPORT_TAGS = (
|
our %EXPORT_TAGS = (
|
||||||
'functions' => [ qw(
|
'functions' => [ qw(
|
||||||
zmMemKey
|
zmMemKey
|
||||||
zmMemAttach
|
zmMemAttach
|
||||||
zmMemDetach
|
zmMemDetach
|
||||||
zmMemGet
|
zmMemGet
|
||||||
zmMemPut
|
zmMemPut
|
||||||
zmMemClean
|
zmMemClean
|
||||||
) ],
|
) ],
|
||||||
);
|
);
|
||||||
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
||||||
|
|
||||||
|
@ -71,77 +71,92 @@ use ZoneMinder::Logger qw(:all);
|
||||||
|
|
||||||
sub zmMemKey
|
sub zmMemKey
|
||||||
{
|
{
|
||||||
my $monitor = shift;
|
my $monitor = shift;
|
||||||
return( defined($monitor->{ShmKey})?$monitor->{ShmKey}:undef );
|
return( defined($monitor->{ShmKey})?$monitor->{ShmKey}:undef );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub zmMemAttach
|
sub zmMemAttach
|
||||||
{
|
{
|
||||||
my $monitor = shift;
|
my $monitor = shift;
|
||||||
my $size = shift;
|
my $size = shift;
|
||||||
if ( !defined($monitor->{ShmId}) )
|
if ( !defined($monitor->{ShmId}) )
|
||||||
{
|
{
|
||||||
my $shm_key = (hex($Config{ZM_SHM_KEY})&0xffff0000)|$monitor->{Id};
|
my $shm_key = (hex($Config{ZM_SHM_KEY})&0xffff0000)|$monitor->{Id};
|
||||||
my $shm_id = shmget( $shm_key, $size, &IPC_CREAT | 0777 );
|
my $shm_id = shmget( $shm_key, $size, &IPC_CREAT | 0777 );
|
||||||
if ( !defined($shm_id) )
|
if ( !defined($shm_id) )
|
||||||
{
|
{
|
||||||
Error( sprintf( "Can't get shared memory id '%x', %d: $!\n", $shm_key, $monitor->{Id} ) );
|
Error( sprintf( "Can't get shared memory id '%x', %d: $!\n"
|
||||||
return( undef );
|
, $shm_key
|
||||||
}
|
, $monitor->{Id}
|
||||||
$monitor->{ShmKey} = $shm_key;
|
)
|
||||||
$monitor->{ShmId} = $shm_id;
|
);
|
||||||
}
|
return( undef );
|
||||||
return( !undef );
|
}
|
||||||
|
$monitor->{ShmKey} = $shm_key;
|
||||||
|
$monitor->{ShmId} = $shm_id;
|
||||||
|
}
|
||||||
|
return( !undef );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub zmMemDetach
|
sub zmMemDetach
|
||||||
{
|
{
|
||||||
my $monitor = shift;
|
my $monitor = shift;
|
||||||
|
|
||||||
delete $monitor->{ShmId};
|
delete $monitor->{ShmId};
|
||||||
}
|
}
|
||||||
|
|
||||||
sub zmMemGet
|
sub zmMemGet
|
||||||
{
|
{
|
||||||
my $monitor = shift;
|
my $monitor = shift;
|
||||||
my $offset = shift;
|
my $offset = shift;
|
||||||
my $size = shift;
|
my $size = shift;
|
||||||
|
|
||||||
|
my $shm_key = $monitor->{ShmKey};
|
||||||
|
my $shm_id = $monitor->{ShmId};
|
||||||
|
|
||||||
my $shm_key = $monitor->{ShmKey};
|
|
||||||
my $shm_id = $monitor->{ShmId};
|
|
||||||
|
|
||||||
my $data;
|
my $data;
|
||||||
if ( !shmread( $shm_id, $data, $offset, $size ) )
|
if ( !shmread( $shm_id, $data, $offset, $size ) )
|
||||||
{
|
{
|
||||||
Error( sprintf( "Can't read from shared memory '%x/%d': $!", $shm_key, $shm_id ) );
|
Error( sprintf( "Can't read from shared memory '%x/%d': $!"
|
||||||
|
, $shm_key
|
||||||
|
, $shm_id
|
||||||
|
)
|
||||||
|
);
|
||||||
return( undef );
|
return( undef );
|
||||||
}
|
}
|
||||||
return( $data );
|
return( $data );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub zmMemPut
|
sub zmMemPut
|
||||||
{
|
{
|
||||||
my $monitor = shift;
|
my $monitor = shift;
|
||||||
my $offset = shift;
|
my $offset = shift;
|
||||||
my $size = shift;
|
my $size = shift;
|
||||||
my $data = shift;
|
my $data = shift;
|
||||||
|
|
||||||
|
my $shm_key = $monitor->{ShmKey};
|
||||||
|
my $shm_id = $monitor->{ShmId};
|
||||||
|
|
||||||
my $shm_key = $monitor->{ShmKey};
|
|
||||||
my $shm_id = $monitor->{ShmId};
|
|
||||||
|
|
||||||
if ( !shmwrite( $shm_id, $data, $offset, $size ) )
|
if ( !shmwrite( $shm_id, $data, $offset, $size ) )
|
||||||
{
|
{
|
||||||
Error( sprintf( "Can't write to shared memory '%x/%d': $!", $shm_key, $shm_id ) );
|
Error( sprintf( "Can't write to shared memory '%x/%d': $!"
|
||||||
|
, $shm_key
|
||||||
|
, $shm_id
|
||||||
|
)
|
||||||
|
);
|
||||||
return( undef );
|
return( undef );
|
||||||
}
|
}
|
||||||
return( !undef );
|
return( !undef );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub zmMemClean
|
sub zmMemClean
|
||||||
{
|
{
|
||||||
Debug( "Removing shared memory\n" );
|
Debug( "Removing shared memory\n" );
|
||||||
# Find ZoneMinder shared memory
|
# Find ZoneMinder shared memory
|
||||||
my $command = "ipcs -m | grep '^".substr( sprintf( "0x%x", hex($Config{ZM_SHM_KEY}) ), 0, -2 )."'";
|
my $command = "ipcs -m | grep '^"
|
||||||
|
.substr( sprintf( "0x%x", hex($Config{ZM_SHM_KEY}) ), 0, -2 )
|
||||||
|
."'"
|
||||||
|
;
|
||||||
Debug( "Checking for shared memory with '$command'\n" );
|
Debug( "Checking for shared memory with '$command'\n" );
|
||||||
open( my $CMD, '<', "$command |" )
|
open( my $CMD, '<', "$command |" )
|
||||||
or Fatal( "Can't execute '$command': $!" );
|
or Fatal( "Can't execute '$command': $!" );
|
||||||
|
|
|
@ -46,53 +46,53 @@ our $AUTOLOAD;
|
||||||
|
|
||||||
sub new
|
sub new
|
||||||
{
|
{
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
my $self = {};
|
my $self = {};
|
||||||
$self->{readable} = !undef;
|
$self->{readable} = !undef;
|
||||||
$self->{writeable} = !undef;
|
$self->{writeable} = !undef;
|
||||||
$self->{selectable} = undef;
|
$self->{selectable} = undef;
|
||||||
$self->{state} = 'closed';
|
$self->{state} = 'closed';
|
||||||
bless( $self, $class );
|
bless( $self, $class );
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub clone
|
sub clone
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $clone = { %$self };
|
my $clone = { %$self };
|
||||||
bless $clone, ref $self;
|
bless $clone, ref $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub open
|
sub open
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $class = ref($self) or croak( "Can't get class for non object $self" );
|
my $class = ref($self) or croak( "Can't get class for non object $self" );
|
||||||
croak( "Abstract base class method called for object of class $class" );
|
croak( "Abstract base class method called for object of class $class" );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub close
|
sub close
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $class = ref($self) or croak( "Can't get class for non object $self" );
|
my $class = ref($self) or croak( "Can't get class for non object $self" );
|
||||||
croak( "Abstract base class method called for object of class $class" );
|
croak( "Abstract base class method called for object of class $class" );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub getState
|
sub getState
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return( $self->{state} );
|
return( $self->{state} );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub isOpen
|
sub isOpen
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return( $self->{state} eq "open" );
|
return( $self->{state} eq "open" );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub isConnected
|
sub isConnected
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return( $self->{state} eq "connected" );
|
return( $self->{state} eq "connected" );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub DESTROY
|
sub DESTROY
|
||||||
|
@ -101,15 +101,15 @@ sub DESTROY
|
||||||
|
|
||||||
sub AUTOLOAD
|
sub AUTOLOAD
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $class = ref($self) || croak( "$self not object" );
|
my $class = ref($self) || croak( "$self not object" );
|
||||||
my $name = $AUTOLOAD;
|
my $name = $AUTOLOAD;
|
||||||
$name =~ s/.*://;
|
$name =~ s/.*://;
|
||||||
if ( !exists($self->{$name}) )
|
if ( !exists($self->{$name}) )
|
||||||
{
|
{
|
||||||
croak( "Can't access $name member of object of class $class" );
|
croak( "Can't access $name member of object of class $class" );
|
||||||
}
|
}
|
||||||
return( $self->{$name} );
|
return( $self->{$name} );
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -48,23 +48,23 @@ use Fcntl;
|
||||||
|
|
||||||
sub new
|
sub new
|
||||||
{
|
{
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
my %params = @_;
|
my %params = @_;
|
||||||
my $self = ZoneMinder::Trigger::Channel::Handle->new;
|
my $self = ZoneMinder::Trigger::Channel::Handle->new;
|
||||||
$self->{path} = $params{path};
|
$self->{path} = $params{path};
|
||||||
bless( $self, $class );
|
bless( $self, $class );
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub open
|
sub open
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
local *sfh;
|
local *sfh;
|
||||||
#sysopen( *sfh, $conn->{path}, O_NONBLOCK|O_RDONLY ) or croak( "Can't sysopen: $!" );
|
#sysopen( *sfh, $conn->{path}, O_NONBLOCK|O_RDONLY ) or croak( "Can't sysopen: $!" );
|
||||||
#open( *sfh, "<".$conn->{path} ) or croak( "Can't open: $!" );
|
#open( *sfh, "<".$conn->{path} ) or croak( "Can't open: $!" );
|
||||||
open( *sfh, "+<", $self->{path} ) or croak( "Can't open: $!" );
|
open( *sfh, "+<", $self->{path} ) or croak( "Can't open: $!" );
|
||||||
$self->{state} = 'open';
|
$self->{state} = 'open';
|
||||||
$self->{handle} = *sfh;
|
$self->{handle} = *sfh;
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -46,12 +46,12 @@ use POSIX;
|
||||||
|
|
||||||
sub new
|
sub new
|
||||||
{
|
{
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
my $port = shift;
|
my $port = shift;
|
||||||
my $self = ZoneMinder::Trigger::Channel->new();
|
my $self = ZoneMinder::Trigger::Channel->new();
|
||||||
$self->{handle} = undef;
|
$self->{handle} = undef;
|
||||||
bless( $self, $class );
|
bless( $self, $class );
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub spawns
|
sub spawns
|
||||||
|
@ -61,43 +61,49 @@ sub spawns
|
||||||
|
|
||||||
sub close
|
sub close
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
close( $self->{handle} );
|
close( $self->{handle} );
|
||||||
$self->{state} = 'closed';
|
$self->{state} = 'closed';
|
||||||
$self->{handle} = undef;
|
$self->{handle} = undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub read
|
sub read
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $buffer;
|
my $buffer;
|
||||||
my $nbytes = sysread( $self->{handle}, $buffer, POSIX::BUFSIZ );
|
my $nbytes = sysread( $self->{handle}, $buffer, POSIX::BUFSIZ );
|
||||||
if ( !$nbytes )
|
if ( !$nbytes )
|
||||||
{
|
{
|
||||||
return( undef );
|
return( undef );
|
||||||
}
|
}
|
||||||
Debug( "Read '$buffer' ($nbytes bytes)\n" );
|
Debug( "Read '$buffer' ($nbytes bytes)\n" );
|
||||||
return( $buffer );
|
return( $buffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub write
|
sub write
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $buffer = shift;
|
my $buffer = shift;
|
||||||
my $nbytes = syswrite( $self->{handle}, $buffer );
|
my $nbytes = syswrite( $self->{handle}, $buffer );
|
||||||
if ( !defined( $nbytes) || $nbytes < length($buffer) )
|
if ( !defined( $nbytes) || $nbytes < length($buffer) )
|
||||||
{
|
{
|
||||||
Error( "Unable to write buffer '".$buffer.", expected ".length($buffer)." bytes, sent ".($nbytes?$nbytes:'undefined').": $!\n" );
|
Error( "Unable to write buffer '".$buffer
|
||||||
return( undef );
|
.", expected "
|
||||||
}
|
.length($buffer)
|
||||||
Debug( "Wrote '$buffer' ($nbytes bytes)\n" );
|
." bytes, sent "
|
||||||
return( !undef );
|
.($nbytes?$nbytes:'undefined')
|
||||||
|
.": $!\n"
|
||||||
|
);
|
||||||
|
return( undef );
|
||||||
|
}
|
||||||
|
Debug( "Wrote '$buffer' ($nbytes bytes)\n" );
|
||||||
|
return( !undef );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub fileno
|
sub fileno
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return( defined($self->{handle})?fileno($self->{handle}):-1 );
|
return( defined($self->{handle})?fileno($self->{handle}):-1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -48,44 +48,45 @@ use Socket;
|
||||||
|
|
||||||
sub new
|
sub new
|
||||||
{
|
{
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
my %params = @_;
|
my %params = @_;
|
||||||
my $self = ZoneMinder::Trigger::Channel::Spawning->new();
|
my $self = ZoneMinder::Trigger::Channel::Spawning->new();
|
||||||
$self->{selectable} = !undef;
|
$self->{selectable} = !undef;
|
||||||
$self->{port} = $params{port};
|
$self->{port} = $params{port};
|
||||||
bless( $self, $class );
|
bless( $self, $class );
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub open
|
sub open
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
local *sfh;
|
local *sfh;
|
||||||
my $saddr = sockaddr_in( $self->{port}, INADDR_ANY );
|
my $saddr = sockaddr_in( $self->{port}, INADDR_ANY );
|
||||||
socket( *sfh, PF_INET, SOCK_STREAM, getprotobyname('tcp') ) or croak( "Can't open socket: $!" );
|
socket( *sfh, PF_INET, SOCK_STREAM, getprotobyname('tcp') )
|
||||||
setsockopt( *sfh, SOL_SOCKET, SO_REUSEADDR, 1 );
|
or croak( "Can't open socket: $!" );
|
||||||
bind( *sfh, $saddr ) or croak( "Can't bind: $!" );
|
setsockopt( *sfh, SOL_SOCKET, SO_REUSEADDR, 1 );
|
||||||
listen( *sfh, SOMAXCONN ) or croak( "Can't listen: $!" );
|
bind( *sfh, $saddr ) or croak( "Can't bind: $!" );
|
||||||
$self->{state} = 'open';
|
listen( *sfh, SOMAXCONN ) or croak( "Can't listen: $!" );
|
||||||
$self->{handle} = *sfh;
|
$self->{state} = 'open';
|
||||||
|
$self->{handle} = *sfh;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _spawn
|
sub _spawn
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $new_handle = shift;
|
my $new_handle = shift;
|
||||||
my $clone = $self->clone();
|
my $clone = $self->clone();
|
||||||
$clone->{handle} = $new_handle;
|
$clone->{handle} = $new_handle;
|
||||||
$clone->{state} = 'connected';
|
$clone->{state} = 'connected';
|
||||||
return( $clone );
|
return( $clone );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub accept
|
sub accept
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
local *cfh;
|
local *cfh;
|
||||||
my $paddr = accept( *cfh, $self->{handle} );
|
my $paddr = accept( *cfh, $self->{handle} );
|
||||||
return( $self->_spawn( *cfh ) );
|
return( $self->_spawn( *cfh ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -46,64 +46,70 @@ use Device::SerialPort;
|
||||||
|
|
||||||
sub new
|
sub new
|
||||||
{
|
{
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
my %params = @_;
|
my %params = @_;
|
||||||
my $self = ZoneMinder::Trigger::Channel->new;
|
my $self = ZoneMinder::Trigger::Channel->new;
|
||||||
$self->{path} = $params{path};
|
$self->{path} = $params{path};
|
||||||
bless( $self, $class );
|
bless( $self, $class );
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub open
|
sub open
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $device = new Device::SerialPort( $self->{path} );
|
my $device = new Device::SerialPort( $self->{path} );
|
||||||
$device->baudrate(9600);
|
$device->baudrate(9600);
|
||||||
$device->databits(8);
|
$device->databits(8);
|
||||||
$device->parity('none');
|
$device->parity('none');
|
||||||
$device->stopbits(1);
|
$device->stopbits(1);
|
||||||
$device->handshake('none');
|
$device->handshake('none');
|
||||||
|
|
||||||
$device->read_const_time(50);
|
$device->read_const_time(50);
|
||||||
$device->read_char_time(10);
|
$device->read_char_time(10);
|
||||||
|
|
||||||
$self->{device} = $device;
|
$self->{device} = $device;
|
||||||
$self->{state} = 'open';
|
$self->{state} = 'open';
|
||||||
$self->{state} = 'connected';
|
$self->{state} = 'connected';
|
||||||
}
|
}
|
||||||
|
|
||||||
sub close
|
sub close
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
$self->{device}->close();
|
$self->{device}->close();
|
||||||
$self->{state} = 'closed';
|
$self->{state} = 'closed';
|
||||||
}
|
}
|
||||||
|
|
||||||
sub read
|
sub read
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $buffer = $self->{device}->lookfor();
|
my $buffer = $self->{device}->lookfor();
|
||||||
if ( !$buffer || !length($buffer) )
|
if ( !$buffer || !length($buffer) )
|
||||||
{
|
{
|
||||||
return( undef );
|
return( undef );
|
||||||
}
|
}
|
||||||
Debug( "Read '$buffer' (".length($buffer)." bytes)\n" );
|
Debug( "Read '$buffer' (".length($buffer)." bytes)\n" );
|
||||||
return( $buffer );
|
return( $buffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub write
|
sub write
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $buffer = shift;
|
my $buffer = shift;
|
||||||
my $nbytes = $self->{device}->write( $buffer );
|
my $nbytes = $self->{device}->write( $buffer );
|
||||||
$self->{device}->write_drain();
|
$self->{device}->write_drain();
|
||||||
if ( !defined( $nbytes) || $nbytes < length($buffer) )
|
if ( !defined( $nbytes) || $nbytes < length($buffer) )
|
||||||
{
|
{
|
||||||
Error( "Unable to write buffer '".$buffer.", expected ".length($buffer)." bytes, sent ".$nbytes.": $!\n" );
|
Error( "Unable to write buffer '".$buffer
|
||||||
return( undef );
|
.", expected "
|
||||||
}
|
.length($buffer)
|
||||||
Debug( "Wrote '$buffer' ($nbytes bytes)\n" );
|
." bytes, sent "
|
||||||
return( !undef );
|
.$nbytes
|
||||||
|
.": $!\n"
|
||||||
|
);
|
||||||
|
return( undef );
|
||||||
|
}
|
||||||
|
Debug( "Wrote '$buffer' ($nbytes bytes)\n" );
|
||||||
|
return( !undef );
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -45,12 +45,12 @@ use ZoneMinder::Logger qw(:all);
|
||||||
|
|
||||||
sub new
|
sub new
|
||||||
{
|
{
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
my $port = shift;
|
my $port = shift;
|
||||||
my $self = ZoneMinder::Trigger::Channel::Handle->new();
|
my $self = ZoneMinder::Trigger::Channel::Handle->new();
|
||||||
$self->{spawns} = !undef;
|
$self->{spawns} = !undef;
|
||||||
bless( $self, $class );
|
bless( $self, $class );
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub spawns
|
sub spawns
|
||||||
|
|
|
@ -48,25 +48,25 @@ use Socket;
|
||||||
|
|
||||||
sub new
|
sub new
|
||||||
{
|
{
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
my %params = @_;
|
my %params = @_;
|
||||||
my $self = ZoneMinder::Trigger::Channel->new;
|
my $self = ZoneMinder::Trigger::Channel->new;
|
||||||
$self->{selectable} = !undef;
|
$self->{selectable} = !undef;
|
||||||
$self->{path} = $params{path};
|
$self->{path} = $params{path};
|
||||||
bless( $self, $class );
|
bless( $self, $class );
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub open
|
sub open
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
local *sfh;
|
local *sfh;
|
||||||
unlink( $self->{path} );
|
unlink( $self->{path} );
|
||||||
my $saddr = sockaddr_un( $self->{path} );
|
my $saddr = sockaddr_un( $self->{path} );
|
||||||
socket( *sfh, PF_UNIX, SOCK_STREAM, 0 ) or croak( "Can't open socket: $!" );
|
socket( *sfh, PF_UNIX, SOCK_STREAM, 0 ) or croak( "Can't open socket: $!" );
|
||||||
bind( *sfh, $saddr ) or croak( "Can't bind: $!" );
|
bind( *sfh, $saddr ) or croak( "Can't bind: $!" );
|
||||||
listen( *sfh, SOMAXCONN ) or croak( "Can't listen: $!" );
|
listen( *sfh, SOMAXCONN ) or croak( "Can't listen: $!" );
|
||||||
$self->{handle} = *sfh;
|
$self->{handle} = *sfh;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _spawn
|
sub _spawn
|
||||||
|
|
|
@ -46,115 +46,121 @@ our $AUTOLOAD;
|
||||||
|
|
||||||
sub new
|
sub new
|
||||||
{
|
{
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
my %params = @_;
|
my %params = @_;
|
||||||
my $self = {};
|
my $self = {};
|
||||||
$self->{name} = $params{name};
|
$self->{name} = $params{name};
|
||||||
$self->{channel} = $params{channel};
|
$self->{channel} = $params{channel};
|
||||||
$self->{input} = $params{mode} =~ /r/i;
|
$self->{input} = $params{mode} =~ /r/i;
|
||||||
$self->{output} = $params{mode} =~ /w/i;
|
$self->{output} = $params{mode} =~ /w/i;
|
||||||
bless( $self, $class );
|
bless( $self, $class );
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub clone
|
sub clone
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $clone = { %$self };
|
my $clone = { %$self };
|
||||||
bless $clone, ref $self;
|
bless $clone, ref $self;
|
||||||
return( $clone );
|
return( $clone );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub spawns
|
sub spawns
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return( $self->{channel}->spawns() );
|
return( $self->{channel}->spawns() );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _spawn
|
sub _spawn
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $new_channel = shift;
|
my $new_channel = shift;
|
||||||
my $clone = $self->clone();
|
my $clone = $self->clone();
|
||||||
$clone->{channel} = $new_channel;
|
$clone->{channel} = $new_channel;
|
||||||
return( $clone );
|
return( $clone );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub accept
|
sub accept
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $new_channel = $self->{channel}->accept();
|
my $new_channel = $self->{channel}->accept();
|
||||||
return( $self->_spawn( $new_channel ) );
|
return( $self->_spawn( $new_channel ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub open
|
sub open
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return( $self->{channel}->open() );
|
return( $self->{channel}->open() );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub close
|
sub close
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return( $self->{channel}->close() );
|
return( $self->{channel}->close() );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub fileno
|
sub fileno
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return( $self->{channel}->fileno() );
|
return( $self->{channel}->fileno() );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub isOpen
|
sub isOpen
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return( $self->{channel}->isOpen() );
|
return( $self->{channel}->isOpen() );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub isConnected
|
sub isConnected
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return( $self->{channel}->isConnected() );
|
return( $self->{channel}->isConnected() );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub canRead
|
sub canRead
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return( $self->{input} && $self->isConnected() );
|
return( $self->{input} && $self->isConnected() );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub canWrite
|
sub canWrite
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return( $self->{output} && $self->isConnected() );
|
return( $self->{output} && $self->isConnected() );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub getMessages
|
sub getMessages
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $buffer = $self->{channel}->read();
|
my $buffer = $self->{channel}->read();
|
||||||
|
|
||||||
return( undef ) if ( !defined($buffer) );
|
return( undef ) if ( !defined($buffer) );
|
||||||
|
|
||||||
my @messages = split( /\r?\n/, $buffer );
|
my @messages = split( /\r?\n/, $buffer );
|
||||||
return( \@messages );
|
return( \@messages );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub putMessages
|
sub putMessages
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $messages = shift;
|
my $messages = shift;
|
||||||
|
|
||||||
if ( @$messages )
|
if ( @$messages )
|
||||||
{
|
{
|
||||||
my $buffer = join( "\n", @$messages );
|
my $buffer = join( "\n", @$messages );
|
||||||
$buffer .= "\n";
|
$buffer .= "\n";
|
||||||
if ( !$self->{channel}->write( $buffer ) )
|
if ( !$self->{channel}->write( $buffer ) )
|
||||||
{
|
{
|
||||||
Error( "Unable to write buffer '".$buffer." to connection ".$self->{name}." (".$self->fileno().")\n" );
|
Error( "Unable to write buffer '".$buffer
|
||||||
}
|
." to connection "
|
||||||
}
|
.$self->{name}
|
||||||
return( undef );
|
." ("
|
||||||
|
.$self->fileno()
|
||||||
|
.")\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return( undef );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub timedActions
|
sub timedActions
|
||||||
|
@ -167,22 +173,22 @@ sub DESTROY
|
||||||
|
|
||||||
sub AUTOLOAD
|
sub AUTOLOAD
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $class = ref($self) || croak( "$self not object" );
|
my $class = ref($self) || croak( "$self not object" );
|
||||||
my $name = $AUTOLOAD;
|
my $name = $AUTOLOAD;
|
||||||
$name =~ s/.*://;
|
$name =~ s/.*://;
|
||||||
if ( exists($self->{$name}) )
|
if ( exists($self->{$name}) )
|
||||||
{
|
{
|
||||||
return( $self->{$name} );
|
return( $self->{$name} );
|
||||||
}
|
}
|
||||||
elsif ( defined($self->{channel}) )
|
elsif ( defined($self->{channel}) )
|
||||||
{
|
{
|
||||||
if ( exists($self->{channel}->{$name}) )
|
if ( exists($self->{channel}->{$name}) )
|
||||||
{
|
{
|
||||||
return( $self->{channel}->{$name} );
|
return( $self->{channel}->{$name} );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
croak( "Can't access $name member of object of class $class" );
|
croak( "Can't access $name member of object of class $class" );
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -44,40 +44,40 @@ use ZoneMinder::Logger qw(:all);
|
||||||
|
|
||||||
sub new
|
sub new
|
||||||
{
|
{
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
my $path = shift;
|
my $path = shift;
|
||||||
my $self = ZoneMinder::Trigger::Connection->new( @_ );
|
my $self = ZoneMinder::Trigger::Connection->new( @_ );
|
||||||
bless( $self, $class );
|
bless( $self, $class );
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub getMessages
|
sub getMessages
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $buffer = $self->{channel}->read();
|
my $buffer = $self->{channel}->read();
|
||||||
|
|
||||||
return( undef ) if ( !defined($buffer) );
|
return( undef ) if ( !defined($buffer) );
|
||||||
|
|
||||||
Debug( "Handling buffer '$buffer'\n" );
|
Debug( "Handling buffer '$buffer'\n" );
|
||||||
my @messages = grep { s/-/|/g; 1; } split( /\r?\n/, $buffer );
|
my @messages = grep { s/-/|/g; 1; } split( /\r?\n/, $buffer );
|
||||||
return( \@messages );
|
return( \@messages );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub putMessages
|
sub putMessages
|
||||||
{
|
{
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $messages = shift;
|
my $messages = shift;
|
||||||
|
|
||||||
if ( @$messages )
|
if ( @$messages )
|
||||||
{
|
{
|
||||||
my $buffer = join( "\n", grep{ s/\|/-/; 1; } @$messages );
|
my $buffer = join( "\n", grep{ s/\|/-/; 1; } @$messages );
|
||||||
$buffer .= "\n";
|
$buffer .= "\n";
|
||||||
if ( !$self->{channel}->write( $buffer ) )
|
if ( !$self->{channel}->write( $buffer ) )
|
||||||
{
|
{
|
||||||
Error( "Unable to write buffer '".$buffer." to connection ".$self->{name}." (".$self->fileno().")\n" );
|
Error( "Unable to write buffer '".$buffer." to connection ".$self->{name}." (".$self->fileno().")\n" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return( undef );
|
return( undef );
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -1554,8 +1554,10 @@ void EventStream::runStream()
|
||||||
if ( ((curr_frame_id-1)%frame_mod) == 0 )
|
if ( ((curr_frame_id-1)%frame_mod) == 0 )
|
||||||
{
|
{
|
||||||
delta_us = (unsigned int)(frame_data->delta * 1000000);
|
delta_us = (unsigned int)(frame_data->delta * 1000000);
|
||||||
if ( effective_fps < base_fps )
|
// if effective > base we should speed up frame delivery
|
||||||
delta_us = (unsigned int)((delta_us * base_fps)/effective_fps);
|
delta_us = (unsigned int)((delta_us * base_fps)/effective_fps);
|
||||||
|
// but must not exceed maxfps
|
||||||
|
delta_us = max(delta_us, 1000000 / maxfps);
|
||||||
send_frame = true;
|
send_frame = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -427,7 +427,7 @@ void *FfmpegCamera::ReopenFfmpegThreadCallback(void *ctx){
|
||||||
// Close current stream.
|
// Close current stream.
|
||||||
camera->CloseFfmpeg();
|
camera->CloseFfmpeg();
|
||||||
|
|
||||||
// Sleep if neccessary to not reconnect too fast.
|
// Sleep if necessary to not reconnect too fast.
|
||||||
int wait = config.ffmpeg_open_timeout - (time(NULL) - camera->mOpenStart);
|
int wait = config.ffmpeg_open_timeout - (time(NULL) - camera->mOpenStart);
|
||||||
wait = wait < 0 ? 0 : wait;
|
wait = wait < 0 ? 0 : wait;
|
||||||
if (wait > 0){
|
if (wait > 0){
|
||||||
|
|
|
@ -305,7 +305,7 @@ void Image::Initialise()
|
||||||
initialised = true;
|
initialised = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Requests a writeable buffer to the image. This is safer than buffer() because this way we can gurantee that a buffer of required size exists */
|
/* Requests a writeable buffer to the image. This is safer than buffer() because this way we can guarantee that a buffer of required size exists */
|
||||||
uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder) {
|
uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder) {
|
||||||
unsigned int newsize;
|
unsigned int newsize;
|
||||||
|
|
||||||
|
@ -1593,7 +1593,7 @@ Image *Image::Highlight( unsigned int n_images, Image *images[], const Rgb thres
|
||||||
return( result );
|
return( result );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* New function to allow buffer re-using instead of allocationg memory for the delta image everytime */
|
/* New function to allow buffer re-using instead of allocationg memory for the delta image every time */
|
||||||
void Image::Delta( const Image &image, Image* targetimage) const
|
void Image::Delta( const Image &image, Image* targetimage) const
|
||||||
{
|
{
|
||||||
#ifdef ZM_IMAGE_PROFILING
|
#ifdef ZM_IMAGE_PROFILING
|
||||||
|
|
|
@ -32,6 +32,13 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
|
/* Workaround for GNU/kFreeBSD */
|
||||||
|
#if defined(__FreeBSD_kernel__)
|
||||||
|
#ifndef ENODATA
|
||||||
|
#define ENODATA ENOATTR
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
static unsigned int BigEndian;
|
static unsigned int BigEndian;
|
||||||
|
|
||||||
static int vidioctl( int fd, int request, void *arg )
|
static int vidioctl( int fd, int request, void *arg )
|
||||||
|
@ -255,7 +262,7 @@ static PixelFormat getFfPixFormatFromV4lPalette( int v4l_version, int palette )
|
||||||
|
|
||||||
#if ZM_HAS_V4L2
|
#if ZM_HAS_V4L2
|
||||||
static char palette_desc[32];
|
static char palette_desc[32];
|
||||||
/* Automatic format selection prefered formats */
|
/* Automatic format selection preferred formats */
|
||||||
static const uint32_t prefered_rgb32_formats[] = {V4L2_PIX_FMT_BGR32, V4L2_PIX_FMT_RGB32, V4L2_PIX_FMT_BGR24, V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV422P, V4L2_PIX_FMT_YUV420};
|
static const uint32_t prefered_rgb32_formats[] = {V4L2_PIX_FMT_BGR32, V4L2_PIX_FMT_RGB32, V4L2_PIX_FMT_BGR24, V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV422P, V4L2_PIX_FMT_YUV420};
|
||||||
static const uint32_t prefered_rgb24_formats[] = {V4L2_PIX_FMT_BGR24, V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV422P, V4L2_PIX_FMT_YUV420};
|
static const uint32_t prefered_rgb24_formats[] = {V4L2_PIX_FMT_BGR24, V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV422P, V4L2_PIX_FMT_YUV420};
|
||||||
static const uint32_t prefered_gray8_formats[] = {V4L2_PIX_FMT_GREY, V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV422P, V4L2_PIX_FMT_YUV420};
|
static const uint32_t prefered_gray8_formats[] = {V4L2_PIX_FMT_GREY, V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV422P, V4L2_PIX_FMT_YUV420};
|
||||||
|
|
|
@ -535,7 +535,12 @@ void Logger::logPrint( bool hex, const char * const file, const int line, const
|
||||||
if (tid < 0 ) // Thread/Process id
|
if (tid < 0 ) // Thread/Process id
|
||||||
#else
|
#else
|
||||||
#ifdef HAVE_SYSCALL
|
#ifdef HAVE_SYSCALL
|
||||||
|
#ifdef __FreeBSD_kernel__
|
||||||
|
if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id
|
||||||
|
|
||||||
|
# else
|
||||||
if ( (tid = syscall(SYS_gettid)) < 0 ) // Thread/Process id
|
if ( (tid = syscall(SYS_gettid)) < 0 ) // Thread/Process id
|
||||||
|
#endif
|
||||||
#endif // HAVE_SYSCALL
|
#endif // HAVE_SYSCALL
|
||||||
#endif
|
#endif
|
||||||
tid = getpid(); // Process id
|
tid = getpid(); // Process id
|
||||||
|
|
|
@ -470,7 +470,7 @@ Monitor::Monitor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Will this not happen everytime a monitor is instantiated? Seems like all the calls to the Monitor constructor pass a zero for n_zones, then load zones after..
|
// Will this not happen every time a monitor is instantiated? Seems like all the calls to the Monitor constructor pass a zero for n_zones, then load zones after..
|
||||||
if ( !n_zones ) {
|
if ( !n_zones ) {
|
||||||
Debug( 1, "Monitor %s has no zones, adding one.", name );
|
Debug( 1, "Monitor %s has no zones, adding one.", name );
|
||||||
n_zones = 1;
|
n_zones = 1;
|
||||||
|
@ -558,14 +558,18 @@ bool Monitor::connect() {
|
||||||
Error( "Got unexpected memory map file size %ld, expected %d", map_stat.st_size, mem_size );
|
Error( "Got unexpected memory map file size %ld, expected %d", map_stat.st_size, mem_size );
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
#ifdef MAP_LOCKED
|
||||||
mem_ptr = (unsigned char *)mmap( NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, map_fd, 0 );
|
mem_ptr = (unsigned char *)mmap( NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, map_fd, 0 );
|
||||||
if ( mem_ptr == MAP_FAILED ) {
|
if ( mem_ptr == MAP_FAILED ) {
|
||||||
if ( errno == EAGAIN ) {
|
if ( errno == EAGAIN ) {
|
||||||
Debug( 1, "Unable to map file %s (%d bytes) to locked memory, trying unlocked", mem_file, mem_size );
|
Debug( 1, "Unable to map file %s (%d bytes) to locked memory, trying unlocked", mem_file, mem_size );
|
||||||
|
#endif
|
||||||
mem_ptr = (unsigned char *)mmap( NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0 );
|
mem_ptr = (unsigned char *)mmap( NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0 );
|
||||||
Debug( 1, "Mapped file %s (%d bytes) to locked memory, unlocked", mem_file, mem_size );
|
Debug( 1, "Mapped file %s (%d bytes) to locked memory, unlocked", mem_file, mem_size );
|
||||||
|
#ifdef MAP_LOCKED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if ( mem_ptr == MAP_FAILED )
|
if ( mem_ptr == MAP_FAILED )
|
||||||
Fatal( "Can't map file %s (%d bytes) to memory: %s(%d)", mem_file, mem_size, strerror(errno), errno );
|
Fatal( "Can't map file %s (%d bytes) to memory: %s(%d)", mem_file, mem_size, strerror(errno), errno );
|
||||||
}
|
}
|
||||||
|
@ -3150,7 +3154,7 @@ bool Monitor::closeEvent()
|
||||||
* comparing it with ZM_COLOUR_RGB24 or ZM_COLOUR_RGB32 is the way ), and then
|
* comparing it with ZM_COLOUR_RGB24 or ZM_COLOUR_RGB32 is the way ), and then
|
||||||
* manage che check using RGB_VAL_RED() and so on macros instead of just RED().
|
* manage che check using RGB_VAL_RED() and so on macros instead of just RED().
|
||||||
*
|
*
|
||||||
* Be carefull that in 32 bit images we need to check also where the alpha channel is, so,
|
* Be careful that in 32 bit images we need to check also where the alpha channel is, so,
|
||||||
* (RGBA and BGRA) or (ABGR and ARGB) aren't the same!
|
* (RGBA and BGRA) or (ABGR and ARGB) aren't the same!
|
||||||
*
|
*
|
||||||
* To check black pixels in 32 bit images i can do a more efficient way using
|
* To check black pixels in 32 bit images i can do a more efficient way using
|
||||||
|
|
|
@ -262,7 +262,7 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
|
||||||
/* emit one intra frame every second */
|
/* emit one intra frame every second */
|
||||||
c->gop_size = frame_rate;
|
c->gop_size = frame_rate;
|
||||||
|
|
||||||
// some formats want stream headers to be seperate
|
// some formats want stream headers to be separate
|
||||||
if ( of->flags & AVFMT_GLOBALHEADER )
|
if ( of->flags & AVFMT_GLOBALHEADER )
|
||||||
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
||||||
}
|
}
|
||||||
|
|
|
@ -392,7 +392,7 @@ int RtspThread::run()
|
||||||
if ( ( lines[i].size() > 13 ) && ( lines[i].substr( 0, 13 ) == "Content-Base:" ) )
|
if ( ( lines[i].size() > 13 ) && ( lines[i].substr( 0, 13 ) == "Content-Base:" ) )
|
||||||
{
|
{
|
||||||
mUrl = trimSpaces( lines[i].substr( 13 ) );
|
mUrl = trimSpaces( lines[i].substr( 13 ) );
|
||||||
Info("Recieved new Content-Base in DESCRIBE reponse header. Updated device Url to: '%s'", mUrl.c_str() );
|
Info("Received new Content-Base in DESCRIBE response header. Updated device Url to: '%s'", mUrl.c_str() );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,12 +64,19 @@ RETSIGTYPE zm_die_handler(int signal)
|
||||||
info->si_uid, info->si_status);
|
info->si_uid, info->si_status);
|
||||||
|
|
||||||
ucontext_t *uc = (ucontext_t *) context;
|
ucontext_t *uc = (ucontext_t *) context;
|
||||||
|
cr2 = info->si_addr;
|
||||||
#if defined(__x86_64__)
|
#if defined(__x86_64__)
|
||||||
cr2 = info->si_addr;
|
#ifdef __FreeBSD_kernel__
|
||||||
|
ip = (void *)(uc->uc_mcontext.mc_rip);
|
||||||
|
#else
|
||||||
ip = (void *)(uc->uc_mcontext.gregs[REG_RIP]);
|
ip = (void *)(uc->uc_mcontext.gregs[REG_RIP]);
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
cr2 = info->si_addr;
|
#ifdef __FreeBSD_kernel__
|
||||||
|
ip = (void *)(uc->uc_mcontext.mc_eip);
|
||||||
|
#else
|
||||||
ip = (void *)(uc->uc_mcontext.gregs[REG_EIP]);
|
ip = (void *)(uc->uc_mcontext.gregs[REG_EIP]);
|
||||||
|
#endif
|
||||||
#endif // defined(__x86_64__)
|
#endif // defined(__x86_64__)
|
||||||
|
|
||||||
// Print the signal address and instruction pointer if available
|
// Print the signal address and instruction pointer if available
|
||||||
|
|
|
@ -36,15 +36,19 @@ class ThreadException : public Exception
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
pid_t pid() {
|
pid_t pid() {
|
||||||
pid_t tid;
|
pid_t tid;
|
||||||
#ifdef __FreeBSD__
|
#ifdef __FreeBSD__
|
||||||
long lwpid;
|
long lwpid;
|
||||||
thr_self(&lwpid);
|
thr_self(&lwpid);
|
||||||
tid = lwpid;
|
tid = lwpid;
|
||||||
#else
|
#else
|
||||||
tid=syscall(SYS_gettid);
|
#ifdef __FreeBSD_kernel__
|
||||||
|
if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id
|
||||||
|
# else
|
||||||
|
tid=syscall(SYS_gettid);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
return tid;
|
return tid;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
ThreadException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)pid() ) ) {
|
ThreadException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)pid() ) ) {
|
||||||
|
@ -219,13 +223,18 @@ protected:
|
||||||
|
|
||||||
pid_t id() const
|
pid_t id() const
|
||||||
{
|
{
|
||||||
pid_t tid;
|
pid_t tid;
|
||||||
#ifdef __FreeBSD__
|
#ifdef __FreeBSD__
|
||||||
long lwpid;
|
long lwpid;
|
||||||
thr_self(&lwpid);
|
thr_self(&lwpid);
|
||||||
tid = lwpid;
|
tid = lwpid;
|
||||||
#else
|
#else
|
||||||
tid=syscall(SYS_gettid);
|
#ifdef __FreeBSD_kernel__
|
||||||
|
if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id
|
||||||
|
|
||||||
|
#else
|
||||||
|
tid=syscall(SYS_gettid);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
return tid;
|
return tid;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,11 @@ private:
|
||||||
thr_self(&lwpid);
|
thr_self(&lwpid);
|
||||||
tid = lwpid;
|
tid = lwpid;
|
||||||
#else
|
#else
|
||||||
|
#ifdef __FreeBSD_kernel__
|
||||||
|
if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id
|
||||||
|
#else
|
||||||
tid=syscall(SYS_gettid);
|
tid=syscall(SYS_gettid);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
return tid;
|
return tid;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
# We use session vars in here, so we need to restart the session because we stopped it in index.php to improve concurrency.
|
||||||
|
session_start();
|
||||||
|
|
||||||
if ( empty($_REQUEST['id']) && empty($_REQUEST['eids']) ) {
|
if ( empty($_REQUEST['id']) && empty($_REQUEST['eids']) ) {
|
||||||
ajaxError( "No event id(s) supplied" );
|
ajaxError( "No event id(s) supplied" );
|
||||||
|
|
|
@ -63,30 +63,30 @@ if ( isset($_GET['skin']) )
|
||||||
$skin = $_GET['skin'];
|
$skin = $_GET['skin'];
|
||||||
elseif ( isset($_COOKIE['zmSkin']) )
|
elseif ( isset($_COOKIE['zmSkin']) )
|
||||||
$skin = $_COOKIE['zmSkin'];
|
$skin = $_COOKIE['zmSkin'];
|
||||||
elseif ( defined(ZM_SKIN_DEFAULT) )
|
elseif ( defined('ZM_SKIN_DEFAULT') )
|
||||||
$skin = ZM_SKIN_DEFAULT;
|
$skin = ZM_SKIN_DEFAULT;
|
||||||
else
|
else
|
||||||
$skin = "classic";
|
$skin = "classic";
|
||||||
|
|
||||||
$skins = array_map( 'basename', glob('skins/*',GLOB_ONLYDIR) );
|
$skins = array_map( 'basename', glob('skins/*',GLOB_ONLYDIR) );
|
||||||
if ( ! in_array( $skin, $skins ) ) {
|
if ( ! in_array( $skin, $skins ) ) {
|
||||||
Error( "Invalid skin '$skin'" );
|
Error( "Invalid skin '$skin' setting to " . $skins[0] );
|
||||||
$skin = 'classic';
|
$skin = $skins[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isset($_GET['css']) )
|
if ( isset($_GET['css']) )
|
||||||
$css = $_GET['css'];
|
$css = $_GET['css'];
|
||||||
elseif ( isset($_COOKIE['zmCSS']) )
|
elseif ( isset($_COOKIE['zmCSS']) )
|
||||||
$css = $_COOKIE['zmCSS'];
|
$css = $_COOKIE['zmCSS'];
|
||||||
elseif (defined(ZM_CSS_DEFAULT))
|
elseif (defined('ZM_CSS_DEFAULT'))
|
||||||
$css = ZM_CSS_DEFAULT;
|
$css = ZM_CSS_DEFAULT;
|
||||||
else
|
else
|
||||||
$css = "classic";
|
$css = "classic";
|
||||||
|
|
||||||
$css_skins = array_map( 'basename', glob('skins/'.$skin.'/css/*',GLOB_ONLYDIR) );
|
$css_skins = array_map( 'basename', glob('skins/'.$skin.'/css/*',GLOB_ONLYDIR) );
|
||||||
if ( ! in_array( $css, $css_skins ) ) {
|
if ( ! in_array( $css, $css_skins ) ) {
|
||||||
Error( "Invalid skin css '$css'" );
|
Error( "Invalid skin css '$css' setting to " . $css_skins[0] );
|
||||||
$css = 'classic';
|
$css = $css_skins[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
define( "ZM_BASE_PATH", dirname( $_SERVER['REQUEST_URI'] ) );
|
define( "ZM_BASE_PATH", dirname( $_SERVER['REQUEST_URI'] ) );
|
||||||
|
@ -102,13 +102,13 @@ ini_set( "session.name", "ZMSESSID" );
|
||||||
|
|
||||||
session_start();
|
session_start();
|
||||||
|
|
||||||
if ( !isset($_SESSION['skin']) || isset($_REQUEST['skin']) )
|
if ( !isset($_SESSION['skin']) || isset($_REQUEST['skin']) || !isset($_COOKIE['zmSkin']) || $_COOKIE['zmSkin'] != $skin )
|
||||||
{
|
{
|
||||||
$_SESSION['skin'] = $skin;
|
$_SESSION['skin'] = $skin;
|
||||||
setcookie( "zmSkin", $skin, time()+3600*24*30*12*10 );
|
setcookie( "zmSkin", $skin, time()+3600*24*30*12*10 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !isset($_SESSION['css']) || isset($_REQUEST['css']) ) {
|
if ( !isset($_SESSION['css']) || isset($_REQUEST['css']) || !isset($_COOKIE['zmCSS']) || $_COOKIE['zmCSS'] != $css ) {
|
||||||
$_SESSION['css'] = $css;
|
$_SESSION['css'] = $css;
|
||||||
setcookie( "zmCSS", $css, time()+3600*24*30*12*10 );
|
setcookie( "zmCSS", $css, time()+3600*24*30*12*10 );
|
||||||
}
|
}
|
||||||
|
@ -143,6 +143,10 @@ if ( ZM_OPT_USE_AUTH && ! isset($user) && $view != 'login' ) {
|
||||||
$view = 'login';
|
$view = 'login';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Only one request can open the session file at a time, so let's close the session here to improve concurrency.
|
||||||
|
# Any file/page that uses the session must re-open it.
|
||||||
|
session_write_close();
|
||||||
|
|
||||||
if ( isset( $_REQUEST['request'] ) )
|
if ( isset( $_REQUEST['request'] ) )
|
||||||
{
|
{
|
||||||
foreach ( getSkinIncludes( 'ajax/'.$request.'.php', true, true ) as $includeFile )
|
foreach ( getSkinIncludes( 'ajax/'.$request.'.php', true, true ) as $includeFile )
|
||||||
|
|
|
@ -24,6 +24,9 @@ if ( !canView( 'Events' ) )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Must re-start session because we close it now in index.php to improve concurrency
|
||||||
|
session_start();
|
||||||
|
|
||||||
if ( isset($_SESSION['export']) )
|
if ( isset($_SESSION['export']) )
|
||||||
{
|
{
|
||||||
if ( isset($_SESSION['export']['detail']) )
|
if ( isset($_SESSION['export']['detail']) )
|
||||||
|
|
Loading…
Reference in New Issue