Merge branch plugin_support

This commit is contained in:
Emmanuel Papin 2014-12-13 22:05:11 +01:00
commit f339518787
71 changed files with 2694 additions and 257 deletions

12
.gitignore vendored
View File

@ -1,5 +1,6 @@
configure
config.h.in
config.h.in~
autom4te.cache
aclocal.m4
depcomp
@ -12,18 +13,23 @@ scripts/ZoneMinder/blib
Makefile.in
Makefile
docs/_build
compile
config.guess
config.h
config.log
config.status
config.sub
db/zm_create.sql
libtool
ltmain.sh
m4/*
misc/apache.conf
misc/com.zoneminder.systemctl.policy
misc/com.zoneminder.systemctl.rules
misc/logrotate.conf
misc/syslog.conf
misc/plugins.conf
scripts/ZoneMinder/MYMETA.json
scripts/ZoneMinder/MYMETA.yml
scripts/ZoneMinder/lib/ZoneMinder/Base.pm
scripts/ZoneMinder/lib/ZoneMinder/Config.pm
@ -49,7 +55,11 @@ scripts/zmvideo.pl
scripts/zmwatch.pl
scripts/zmx10.pl
src/.deps/
src/.libs/
src/*.la
src/*.lo
src/*.o
src/libzmplugins.pc
src/zm_config.h
src/zm_config_defines.h
src/zma

View File

@ -10,7 +10,7 @@
#
cmake_minimum_required (VERSION 2.6)
project (zoneminder)
set(zoneminder_VERSION "1.28.0")
set(zoneminder_VERSION "1.28.0wps1")
# CMake does not allow out-of-source build if CMakeCache.exists in the source folder. Abort and notify the user to save him from headache why it doesn't work.
if((NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) AND (EXISTS "${CMAKE_SOURCE_DIR}/CMakeCache.txt"))

View File

@ -1,5 +1,7 @@
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4
# And these to the user and group of your webserver
webuser = @WEB_USER@
webgroup = @WEB_GROUP@

View File

@ -1,4 +1,5 @@
#!/bin/bash
libtoolize
aclocal
autoheader
automake --add-missing

View File

@ -1,6 +1,9 @@
AC_PREREQ(2.59)
AC_INIT(zm,1.28.0,[http://www.zoneminder.com/forums/ - Please check FAQ first],zoneminder,http://www.zoneminder.com/downloads.html)
AC_INIT(zm,1.28.0wps1,[http://www.zoneminder.com/forums/ - Please check FAQ first],zoneminder,http://www.zoneminder.com/downloads.html)
AM_INIT_AUTOMAKE
LT_PREREQ([2.4.2])
LT_INIT([dlopen])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR(src/zm.h)
AC_CONFIG_HEADERS(config.h)
@ -197,6 +200,50 @@ AC_ARG_WITH(cgidir,
)
AC_SUBST(CGI_PREFIX)
ENABLE_PLUGIN_SUPPORT=no
AC_ARG_ENABLE([plugin-support],
[ --enable-plugin-support=<yes|no> enable or disable plugin support, default disabled],
[ENABLE_PLUGIN_SUPPORT=$enable_plugin_support],
[AC_MSG_WARN([You can call configure with the --enable-plugin-support=<yes|no>
or --disable-plugin-support option.
This tells configure whether to compile ZoneMinder with plugin support.
e.g. --enable-plugin-support=yes or --disable-plugin-support])]
)
if test "$ENABLE_PLUGIN_SUPPORT" == "yes"; then
if test "$enable_shared" = "no"; then
AC_MSG_ERROR([Plugin support is enabled and shared library are disabled.
If you really want plugin support you must not call configure with
--enable-shared=no or --disabled-shared])
fi
AC_ARG_WITH(pluginsdir,
[ --with-pluginsdir=<path> plugins directory (requires --enable-plugin-support=yes)],
[PLUGINSLIBDIR=$with_pluginsdir],
AC_MSG_ERROR([Plugin support is enabled.
You must call configure with the --with-pluginsdir options.
This tells configure where to install plugin library files.
e.g. --with-pluginsdir=/usr/lib/zoneminder/plugins])
)
AC_SUBST(PLUGINSLIBDIR)
PLUGINSCONFDIR="${sysconfdir}/plugins.d"
AC_ARG_WITH(pluginsconfdir,
[ --with-pluginsconfdir=<path> directory of plugin configuration files (requires --enable-plugin-support=yes)],
[PLUGINSCONFDIR=$with_pluginsconfdir],
AC_MSG_WARN([You can call configure with the --with-pluginsconfdir options.
This tells configure where to install the plugin configuration files.
The default is "${PLUGINSCONFDIR}".
e.g. --with-pluginsconfdir=/etc/zm/plugins.d])
)
AC_SUBST(PLUGINSCONFDIR)
PLUGINSWEBDIR="$WEB_PREFIX/plugins"
AC_SUBST(PLUGINSWEBDIR)
AC_DEFINE(ZM_PLUGINS_ON,1,"Whether plugin support is switched on and compiled")
PLUGINSEXT=".so"
AC_SUBST(PLUGINSEXT)
AC_DEFINE_UNQUOTED(DEFAULT_PLUGIN_EXT,"${PLUGINSEXT}",[File extension to detect plugins])
fi
AM_CONDITIONAL([ZM_HAS_PLUGIN_SUPPORT], [test "x$ENABLE_PLUGIN_SUPPORT" = xyes])
WEB_USER=apache
AC_ARG_WITH(webuser,
[ --with-webuser=<user> name of web user, default apache],
@ -269,7 +316,6 @@ AC_PROG_CXX
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_RANLIB
AC_PROG_MAKE_SET
# Checks for typedefs, structures, and compiler characteristics.
@ -311,10 +357,18 @@ fi
AC_SEARCH_LIBS(mysql_init,[mysqlclient mariadbclient],,AC_MSG_ERROR(zm requires libmysqlclient.a or libmariadbclient.a))
AC_CHECK_LIB(jpeg,jpeg_start_compress,,AC_MSG_ERROR(zm requires libjpeg.a))
AC_CHECK_LIB(pthread,pthread_create,,AC_MSG_ERROR(zm requires libpthread.a))
AC_CHECK_LIB(dl,dlsym,,AC_MSG_ERROR(zm requires libdl.a))
AC_CHECK_LIB([dl],
[dlsym],
[AC_SUBST([DL_LIBS],["-ldl"])AC_DEFINE([HAVE_LIBDL],[1],[Define to 1 if you have the 'dl' library (-ldl).])],
[AC_MSG_ERROR(zm requires libdl.a)]
)
if test "$ZM_SSL_LIB" == "openssl"; then
AC_CHECK_HEADERS(openssl/md5.h,,AC_MSG_WARN(zm requires openssl/md5.h header to be installed for openssl),)
AC_CHECK_LIB(crypto,MD5,,AC_MSG_WARN([libcrypto.a is required for authenticated streaming - use ZM_SSL_LIB option to select gnutls instead]))
AC_CHECK_LIB([crypto],
[MD5],
[AC_SUBST([CRYPTO_LIBS],["-lcrypto"])AC_DEFINE([HAVE_LIBCRYPTO],[1],[Define to 1 if you have the 'crypto' library (-lcrypto).])],
[AC_MSG_WARN([libcrypto.a is required for authenticated streaming - use ZM_SSL_LIB option to select gnutls instead])]
)
else
AC_CHECK_HEADERS(gnutls/openssl.h,AC_SUBST(ZM_HAS_GNUTLS_OPENSSL,1),AC_SUBST(ZM_HAS_GNUTLS_OPENSSL,0),)
AC_CHECK_HEADERS(gnutls/gnutls.h,AC_SUBST(ZM_HAS_GNUTLS,1),AC_SUBST(ZM_HAS_GNUTLS,0),)
@ -322,28 +376,80 @@ if test "$ZM_HAS_GNUTLS_OPENSSL" == "0" && test "$ZM_HAS_GNUTLS" == "0"; then
AC_MSG_WARN(gnutls is required for authenticated streaming - use ZM_SSL_LIB option to select openssl instead)
fi
AC_CHECK_HEADERS(gcrypt.h,,AC_MSG_WARN(zm requires libgcrypt headers to be installed for gnutls),)
AC_CHECK_LIB(gcrypt,gcry_check_version,,AC_MSG_WARN([libgcrypt.a is required for authenticated streaming - use ZM_SSL_LIB option to select openssl instead]))
AC_CHECK_LIB(gnutls,gnutls_fingerprint,,AC_MSG_WARN([libgnutls.a is required for authenticated streaming - use ZM_SSL_LIB option to select openssl instead]))
AC_CHECK_LIB([gcrypt],
[gcry_check_version],
[AC_SUBST([GCRYPT_LIBS],["-lgcrypt"])AC_DEFINE([HAVE_LIBGCRYPT],[1],[Define to 1 if you have the 'gcrypt' library (-lgcrypt).])],
[AC_MSG_WARN([libgcrypt.a is required for authenticated streaming - use ZM_SSL_LIB option to select openssl instead])]
)
AC_CHECK_LIB([gnutls],
[gnutls_fingerprint],
[AC_SUBST([GNUTLS_LIBS],["-lgnutls"])AC_DEFINE([HAVE_LIBGNUTLS],[1],[Define to 1 if you have the 'gnutls' library (-lgnutls).])],
[AC_MSG_WARN([libgnutls.a is required for authenticated streaming - use ZM_SSL_LIB option to select openssl instead])]
)
if test "$ZM_HAS_GNUTLS_OPENSSL" == "1"; then
AC_CHECK_LIB(gnutls-openssl,MD5,,AC_MSG_WARN([libgnutls.a is required for authenticated streaming - use ZM_SSL_LIB option to select openssl instead]))
AC_CHECK_LIB([gnutls-openssl],
[MD5],
[AC_SUBST([GNUTLS_OPENSSL_LIBS],["-lgnutls-openssl"])AC_DEFINE([HAVE_LIBGNUTLS_OPENSSL],[1],[Define to 1 if you have the 'gnutls-openssl' library (-lgnutls-openssl).])],
[AC_MSG_WARN([libgnutls.a is required for authenticated streaming - use ZM_SSL_LIB option to select openssl instead])]
)
fi
fi
AC_CHECK_LIB(pcre,pcre_compile,,AC_MSG_WARN(libpcre.a may be required for remote/network camera support))
AC_CHECK_LIB([pcre],
[pcre_compile],
[AC_SUBST([PCRE_LIBS],["-lpcre"])AC_DEFINE([HAVE_LIBPCRE],[1],[Define to 1 if you have the 'pcre' library (-lpcre).])],
[AC_MSG_WARN([libpcre.a may be required for remote/network camera support])]
)
AC_CHECK_LIB(z,zlibVersion)
AC_CHECK_LIB(x264,x264_predict_16x16_init)
AC_CHECK_LIB(avutil,av_malloc,,AC_MSG_WARN(libavutil.a may be required for MPEG streaming))
AC_CHECK_LIB([x264],
[x264_predict_16x16_init],
[AC_SUBST([X264_LIBS],["-lx264"])AC_DEFINE([HAVE_LIBX264],[1],[Define to 1 if you have the 'x264' library (-lx264).])],
)
AC_CHECK_LIB([avutil],
[av_malloc],
[AC_SUBST([AVUTIL_LIBS],["-lavutil"])AC_DEFINE([HAVE_LIBAVUTIL],[1],[Define to 1 if you have the 'avutil' library (-lavutil).])],
[AC_MSG_WARN([libavutil.a may be required for MPEG streaming])]
)
# Don't bother to warn about this one
AC_CHECK_LIB(avcore,av_image_copy,,)
AC_CHECK_LIB(avcodec,avcodec_version,,AC_MSG_WARN(libavcodec.a is required for MPEG streaming))
AC_CHECK_LIB(avformat,avformat_version,,AC_MSG_WARN(libavformat.a is required for MPEG streaming))
AC_CHECK_LIB([avcore],
[av_image_copy],
[AC_SUBST([AVCORE_LIBS],["-lavcore"])AC_DEFINE([HAVE_LIBAVCORE],[1],[Define to 1 if you have the 'avcore' library (-lavcore).])]
)
AC_CHECK_LIB([avcodec],
[avcodec_version],
[AC_SUBST([AVCODEC_LIBS],["-lavcodec"])AC_DEFINE([HAVE_LIBAVCODEC],[1],[Define to 1 if you have the 'avcodec' library (-lavcodec).])],
[AC_MSG_WARN([libavcodec.a is required for MPEG streaming])]
)
AC_CHECK_LIB([avformat],
[avformat_version],
[AC_SUBST([AVFORMAT_LIBS],["-lavformat"])AC_DEFINE([HAVE_LIBAVFORMAT],[1],[Define to 1 if you have the 'avformat' library (-lavformat).])],
[AC_MSG_WARN([libavformat.a is required for MPEG streaming])]
)
#AC_CHECK_LIB(avcodec,avcodec_open,,AC_MSG_WARN(libavcodec.a is required for MPEG streaming))
#AC_CHECK_LIB(avformat,av_new_stream,,AC_MSG_WARN(libavformat.a is required for MPEG streaming))
AC_CHECK_LIB(avdevice,avdevice_register_all,,AC_MSG_WARN(libavdevice.a may be required for MPEG streaming))
AC_CHECK_LIB(swscale,sws_scale,,,-lswscale)
AC_CHECK_LIB(vlc,libvlc_new,,AC_MSG_WARN(libvlc.a may be required for streaming))
AC_CHECK_LIB(bz2,BZ2_bzCompress,,AC_MSG_WARN(zm requires libbz2.a for recent versions of ffmpeg))
AC_CHECK_LIB([avdevice],
[avdevice_register_all],
[AC_SUBST([AVDEVICE_LIBS],["-lavdevice"])AC_DEFINE([HAVE_LIBAVDEVICE],[1],[Define to 1 if you have the 'avdevice' library (-lavdevice).])],
[AC_MSG_WARN([libavdevice.a may be required for MPEG streaming])]
)
AC_CHECK_LIB([swscale],
[sws_scale],
[AC_SUBST([SWSCALE_LIBS],["-lswscale"])AC_DEFINE([HAVE_LIBSWSCALE],[1],[Define to 1 if you have the 'swscale' library (-lswscale).])]
)
AC_CHECK_LIB([vlc],
[libvlc_new],
[AC_SUBST([VLC_LIBS],["-lvlc"])AC_DEFINE([HAVE_LIBVLC],[1],[Define to 1 if you have the 'vlc' library (-lvlc).])],
[AC_MSG_WARN([libvlc.a may be required for streaming])]
)
AC_CHECK_LIB([bz2],
[BZ2_bzCompress],
[AC_SUBST([BZ2_LIBS],["-lbz2"])AC_DEFINE([HAVE_LIBBZ2],[1],[Define to 1 if you have the 'bz2' library (-lbz2).])],
[AC_MSG_WARN([zm requires libbz2.a for recent versions of ffmpeg])]
)
AC_CHECK_LIB(z,compress,,)
AC_CHECK_LIB(curl,curl_global_init,,)
AC_CHECK_LIB([curl],
[curl_global_init],
[AC_SUBST([CURL_LIBS],["-lcurl"])AC_DEFINE([HAVE_LIBCURL],[1],[Define to 1 if you have the 'curl' library (-lcurl).])]
)
# Checks for header files.
AC_FUNC_ALLOCA
@ -452,7 +558,7 @@ AC_SUBST(PERL_MM_PARMS)
AC_SUBST(EXTRA_PERL_LIB)
AC_CONFIG_FILES([Makefile zm.conf zmconfgen.pl db/Makefile db/zm_create.sql misc/Makefile misc/apache.conf misc/logrotate.conf misc/syslog.conf misc/com.zoneminder.systemctl.policy misc/com.zoneminder.systemctl.rules scripts/Makefile scripts/zm scripts/zmaudit.pl scripts/zmcontrol.pl scripts/zmdc.pl scripts/zmfilter.pl scripts/zmpkg.pl scripts/zmtrack.pl scripts/zmcamtool.pl scripts/zmsystemctl.pl scripts/zmtrigger.pl scripts/zmupdate.pl scripts/zmvideo.pl scripts/zmwatch.pl scripts/zmx10.pl scripts/zmdbbackup scripts/zmdbrestore scripts/zmeventdump scripts/zmlogrotate.conf scripts/ZoneMinder/lib/ZoneMinder/Base.pm scripts/ZoneMinder/lib/ZoneMinder/Config.pm scripts/ZoneMinder/lib/ZoneMinder/Memory.pm scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm src/Makefile src/zm_config.h web/Makefile web/ajax/Makefile web/css/Makefile web/graphics/Makefile web/includes/Makefile web/includes/config.php web/js/Makefile web/lang/Makefile web/skins/Makefile web/skins/classic/Makefile web/skins/classic/ajax/Makefile web/skins/classic/css/Makefile web/skins/classic/css/classic/Makefile web/skins/classic/css/classic/views/Makefile web/skins/classic/css/flat/Makefile web/skins/classic/css/flat/views/Makefile web/skins/classic/graphics/Makefile web/skins/classic/includes/Makefile web/skins/classic/js/Makefile web/skins/classic/lang/Makefile web/skins/classic/views/Makefile web/skins/classic/views/js/Makefile web/skins/mobile/Makefile web/skins/mobile/ajax/Makefile web/skins/mobile/css/Makefile web/skins/mobile/graphics/Makefile web/skins/mobile/includes/Makefile web/skins/mobile/lang/Makefile web/skins/mobile/views/Makefile web/skins/mobile/views/css/Makefile web/tools/Makefile web/tools/mootools/Makefile web/views/Makefile web/skins/xml/Makefile web/skins/xml/views/Makefile web/skins/xml/includes/Makefile])
AC_CONFIG_FILES([Makefile zm.conf zmconfgen.pl db/Makefile db/zm_create.sql misc/Makefile misc/apache.conf misc/logrotate.conf misc/syslog.conf misc/com.zoneminder.systemctl.policy misc/com.zoneminder.systemctl.rules misc/plugins.conf scripts/Makefile scripts/zm scripts/zmaudit.pl scripts/zmcontrol.pl scripts/zmdc.pl scripts/zmfilter.pl scripts/zmpkg.pl scripts/zmtrack.pl scripts/zmcamtool.pl scripts/zmsystemctl.pl scripts/zmtrigger.pl scripts/zmupdate.pl scripts/zmvideo.pl scripts/zmwatch.pl scripts/zmx10.pl scripts/zmdbbackup scripts/zmdbrestore scripts/zmeventdump scripts/zmlogrotate.conf scripts/ZoneMinder/lib/ZoneMinder/Base.pm scripts/ZoneMinder/lib/ZoneMinder/Config.pm scripts/ZoneMinder/lib/ZoneMinder/Memory.pm scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm src/Makefile src/zm_config.h src/libzmplugins.pc web/Makefile web/ajax/Makefile web/css/Makefile web/graphics/Makefile web/includes/Makefile web/includes/config.php web/js/Makefile web/lang/Makefile web/skins/Makefile web/skins/classic/Makefile web/skins/classic/ajax/Makefile web/skins/classic/css/Makefile web/skins/classic/css/classic/Makefile web/skins/classic/css/classic/views/Makefile web/skins/classic/css/flat/Makefile web/skins/classic/css/flat/views/Makefile web/skins/classic/graphics/Makefile web/skins/classic/includes/Makefile web/skins/classic/js/Makefile web/skins/classic/lang/Makefile web/skins/classic/views/Makefile web/skins/classic/views/js/Makefile web/skins/mobile/Makefile web/skins/mobile/ajax/Makefile web/skins/mobile/css/Makefile web/skins/mobile/graphics/Makefile web/skins/mobile/includes/Makefile web/skins/mobile/lang/Makefile web/skins/mobile/views/Makefile web/skins/mobile/views/css/Makefile web/tools/Makefile web/tools/mootools/Makefile web/views/Makefile web/skins/xml/Makefile web/skins/xml/views/Makefile web/skins/xml/includes/Makefile])
# Create the definitions for compilation and defaults for the database
AC_CONFIG_COMMANDS([src/zm_config_defines.h],[perl ./zmconfgen.pl])

View File

@ -377,6 +377,7 @@ CREATE TABLE `Monitors` (
`SignalCheckColour` varchar(32) NOT NULL default '#0000BE',
`WebColour` varchar(32) NOT NULL default 'red',
`Sequence` smallint(5) unsigned default NULL,
`DoNativeMotDet` tinyint(3) unsigned NOT NULL default '1',
PRIMARY KEY (`Id`)
) ENGINE=@ZM_MYSQL_ENGINE@;
@ -516,6 +517,25 @@ CREATE TABLE `Zones` (
KEY `MonitorId` (`MonitorId`)
) ENGINE=@ZM_MYSQL_ENGINE@;
DROP TABLE IF EXISTS `PluginsConfig`;
CREATE TABLE `PluginsConfig` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`Name` varchar(32) NOT NULL DEFAULT '',
`Value` text NOT NULL,
`Type` tinytext NOT NULL,
`Choices` text default NULL,
`Min` int(10) unsigned NULL default NULL,
`Max` int(10) unsigned NULL default NULL,
`MonitorId` int(10) unsigned NOT NULL,
`ZoneId` int(10) unsigned NOT NULL,
`pluginName` varchar(64) NOT NULL,
PRIMARY KEY (`Id`),
KEY `ZoneId` (`ZoneId`),
KEY `MonitorId` (`MonitorId`),
KEY `Name` (`Name`),
KEY `pluginName` (`pluginName`)
) ENGINE=@ZM_MYSQL_ENGINE@;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;

View File

@ -1 +1,21 @@
ALTER TABLE Monitors MODIFY Device tinytext;
CREATE TABLE `PluginsConfig` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`Name` varchar(32) NOT NULL DEFAULT '',
`Value` text NOT NULL,
`Type` tinytext NOT NULL,
`Choices` text default NULL,
`Min` int(10) unsigned NULL default NULL,
`Max` int(10) unsigned NULL default NULL,
`MonitorId` int(10) unsigned NOT NULL,
`ZoneId` int(10) unsigned NOT NULL,
`pluginName` varchar(255) NOT NULL,
PRIMARY KEY (`Id`),
KEY `ZoneId` (`ZoneId`),
KEY `MonitorId` (`MonitorId`),
KEY `Name` (`Name`),
KEY `pluginName` (`pluginName`)
) ENGINE=InnoDB;
ALTER TABLE `Monitors` ADD `DoNativeMotDet` tinyint(3) unsigned NOT NULL default '1' AFTER `Sequence`;

View File

@ -23,9 +23,7 @@ Description: A video camera security and surveillance solution
Package: zoneminder-dbg
Architecture: any
Depends:
zoneminder (= ${binary:Version}),
${misc:Depends}
Depends: zoneminder (= ${binary:Version}), ${misc:Depends}
Description: debugging syumbols for zoneminder.
ZoneMinder is a video camera security and surveillance solution.
ZoneMinder is intended for use in single or multi-camera video security
@ -38,3 +36,11 @@ Description: debugging syumbols for zoneminder.
video security system and for commercial or professional video security
and surveillance. It can also be integrated into a home automation system
via X.10 or other protocols.
Package: zoneminder-dev
Section: libdevel
Architecture: any
Depends: zoneminder (= ${binary:Version}), ${misc:Depends}
Description: Development files for ZoneMinder plugins
This package add the necessary files to develop video analysis plugins for
the ZoneMinder camera security and surveillance solution.

View File

@ -0,0 +1,3 @@
usr/include/zoneminder/*
usr/lib/*/libzmplugins.a
usr/lib/*/pkgconfig/libzmplugins.pc

View File

@ -1,3 +1,10 @@
zoneminder (1.28.1-0.1) testing; urgency=medium
* Non-maintainer upload.
* Add plugin support
-- Emmanuel Papin <manupap01@gmail.com> Sat, 13 Dec 2014 21:43:14 +0100
zoneminder (1.28.0-0.2) testing; urgency=medium
* Non-maintainer upload.

View File

@ -38,3 +38,12 @@ Description: Debugging symbols for zoneminder.
video security system and for commercial or professional video security
and surveillance. It can also be integrated into a home automation system
via X.10 or other protocols.
Package: zoneminder-dev
Priority: optional
Section: libdevel
Architecture: any
Depends: zoneminder (= ${binary:Version}), ${misc:Depends}
Description: Development files for ZoneMinder plugins
This package add the necessary files to develop video analysis plugins for
the ZoneMinder camera security and surveillance solution.

View File

@ -53,7 +53,8 @@ override_dh_auto_configure:
--with-mariadb=/usr --with-webdir=/usr/share/zoneminder \
--with-ffmpeg=/usr --with-cgidir=/usr/lib/cgi-bin \
--with-webuser=www-data --with-webgroup=www-data \
--enable-crashtrace=no --enable-mmap=yes $(DEBOPT)
--enable-crashtrace=no --enable-mmap=yes $(DEBOPT) \
--enable-plugin-support --with-pluginsdir=/usr/lib/zoneminder/plugins
override_dh_clean:
# Add here commands to clean up after the build process.

View File

@ -0,0 +1,3 @@
usr/include/zoneminder
usr/lib/*/libzmplugins.a
usr/lib/*/pkgconfig/libzmplugins.pc

View File

@ -6,7 +6,8 @@ EXTRA_DIST = \
syslog.conf.in \
zoneminder.service.in \
com.zoneminder.systemctl.policy.in \
com.zoneminder.systemctl.rules.in
com.zoneminder.systemctl.rules.in \
plugins.conf.in
polkit_actiondir = @POLKIT_PREFIX@/share/polkit-1/actions
dist_polkit_action_DATA = com.zoneminder.systemctl.policy
@ -14,3 +15,5 @@ dist_polkit_action_DATA = com.zoneminder.systemctl.policy
polkit_rulesdir = @POLKIT_PREFIX@/share/polkit-1/rules.d
dist_polkit_rules_DATA = com.zoneminder.systemctl.rules
sysconf_DATA = plugins.conf

13
misc/plugins.conf.in Normal file
View File

@ -0,0 +1,13 @@
# Zoneminder global configuration file for plugins
# Add here a section for each plugins or add separated configuration files
# under @PLUGINSCONFDIR@
#
# Syntax:
# [plugin_name_A]
# parameter1 = value1
# parameter2 = value2
# ...
# [plugin_name_B]
# parameter1 = value1
# parameter2 = value2
# ...

View File

@ -1926,6 +1926,54 @@ body = "ZM alarm detected - %EL% secs, %EF%/%EFA% frames, t%EST%/m%ESM%/a%ESA% s
type => $types{string},
category => "eyeZm",
},
{
name => "ZM_PATH_PLUGINS",
default => "@PLUGINSLIBDIR@",
description => "Path to the plugin folder",
help => "3d-party plugins have to be placed here.",
type => $types{abs_path},
category => "paths",
},
{
name => "ZM_PLUGIN_EXTENSION",
default => "@PLUGINSEXT@",
description => "Default extension of plugins to found.",
help => "Default extension of plugins to found.",
type => $types{rel_path},
category => "paths",
},
{
name => "ZM_PLUGINS_CONFIG_PATH",
default => "@SYSCONFDIR@/plugins.conf",
description => "Path to the config file for plugins.",
help => "Path to the config file for plugins.",
type => $types{abs_path},
category => "paths",
},
{
name => "ZM_PLUGINS_CONFIG_DIR",
default => "@PLUGINSCONFDIR@",
description => "Path to the config folder for plugins.",
help => "Path to the config folder for plugins.",
type => $types{abs_path},
category => "paths",
},
{
name => "ZM_LOAD_PLUGINS",
default => "no",
description => "Load and use 3d-party plugins",
help => "3d-party plugins will be loaded and used for analysing.",
type => $types{boolean},
category => "config",
},
{
name => "ZM_TURNOFF_NATIVE_ANALYSIS",
default => "no",
description => "Turn native ZM\'s image analysis possibility off",
help => "Image analysis with ZM\'s motion detected function will be turned off. Only detection functions from loaded plugins will be used. Note, that if no plugins have be loaded, no detection will be done.",
type => $types{boolean},
category => "config",
},
);
our %options_hash = map { ( $_->{name}, $_ ) } @options;

View File

@ -1,7 +1,9 @@
AUTOMAKE_OPTIONS = gnu
AM_CPPFLAGS = @MYSQL_CFLAGS@ @MARIADB_CFLAGS@ @FFMPEG_CFLAGS@ -Wall -finline-functions -fomit-frame-pointer
#AM_CXXFLAGS = -frepo
# Compile zm binaries with -rdynamic to enable visiblily of global static
# variables in shared libraries (plugins)
AM_CXXFLAGS = -rdynamic
CLEANFILES = *.rpo
@ -24,24 +26,18 @@ zm_SOURCES = \
zm_buffer.cpp \
zm_camera.cpp \
zm_comms.cpp \
zm_config.cpp \
zm_coord.cpp \
zm_curl_camera.cpp \
zm.cpp \
zm_db.cpp \
zm_logger.cpp \
zm_event.cpp \
zm_exception.cpp \
zm_file_camera.cpp \
zm_ffmpeg_camera.cpp \
zm_image.cpp \
zm_jpeg.cpp \
zm_libvlc_camera.cpp \
zm_local_camera.cpp \
zm_monitor.cpp \
zm_ffmpeg.cpp \
zm_mpeg.cpp \
zm_poly.cpp \
zm_regexp.cpp \
zm_remote_camera.cpp \
zm_remote_camera_http.cpp \
@ -55,13 +51,47 @@ zm_SOURCES = \
zm_sdp.cpp \
zm_signal.cpp \
zm_stream.cpp \
zm_thread.cpp \
zm_time.cpp \
zm_timer.cpp \
zm_user.cpp \
$(SOURCES_common)
# These source files are used both for zm binaries and the libzmplugins
# convenience library
SOURCES_common = \
zm_config.cpp \
zm_db.cpp \
zm_image.cpp \
zm_jpeg.cpp \
zm_logger.cpp \
zm_poly.cpp \
zm_utils.cpp \
zm_thread.cpp \
zm_zone.cpp
# These header files are used both for zm binaries and the libzmplugins
# convenience library
HEADERS_common = \
jinclude.h \
zm.h \
zm_box.h \
zm_config_defines.h \
zm_config.h \
zm_coord.h \
zm_db.h \
zm_event.h \
zm_ffmpeg.h \
zm_image.h \
zm_jpeg.h \
zm_logger.h \
zm_mem_utils.h \
zm_mpeg.h \
zm_poly.h \
zm_rgb.h \
zm_stream.h \
zm_utils.h \
zm_zone.h
zmc_SOURCES = zmc.cpp $(zm_SOURCES)
zma_SOURCES = zma.cpp $(zm_SOURCES)
zms_SOURCES = zms.cpp $(zm_SOURCES)
@ -69,40 +99,37 @@ zmu_SOURCES = zmu.cpp $(zm_SOURCES)
zmf_SOURCES = zmf.cpp $(zm_SOURCES)
zmstreamer_SOURCES = zmstreamer.cpp $(zm_SOURCES)
# These libraries are linked only to zm binaries in order to avoid detection
# of unwanted dependencies during plugin packaging
zm_LDADD = @DL_LIBS@ @PCRE_LIBS@ @CURL_LIBS@ @BZ2_LIBS@ @X264_LIBS@ \
@SWSCALE_LIBS@ @AVFORMAT_LIBS@ @AVCODEC_LIBS@ @AVUTIL_LIBS@ \
@AVDEVICE_LIBS@ @AVCORE_LIBS@ @VLC_LIBS@ @CRYPTO_LIBS@ @GCRYPT_LIBS@ \
@GNUTLS_LIBS@ @GNUTLS_OPENSSL_LIBS@
zmc_LDADD = $(zm_LDADD)
zma_LDADD = $(zm_LDADD)
zms_LDADD = $(zm_LDADD)
zmu_LDADD = $(zm_LDADD)
zmf_LDADD = $(zm_LDADD)
zmstreamer_LDADD = $(zm_LDADD)
noinst_HEADERS = \
jinclude.h \
zm_box.h \
zm_buffer.h \
zm_camera.h \
zm_comms.h \
zm_config_defines.h \
zm_config.h \
zm_coord.h \
zm_curl_camera.h \
zm_db.h \
zm_logger.h \
zm_event.h \
zm_exception.h \
zmf.h \
zm_file_camera.h \
zm_ffmpeg_camera.h \
zm_font.h \
zm_font.h \
zm.h \
zm_image.h \
zm_jpeg.h \
zm_libvlc_camera.h \
zm_local_camera.h \
zm_mem_utils.h \
zm_monitor.h \
zm_ffmpeg.h \
zm_mpeg.h \
zm_poly.h \
zm_regexp.h \
zm_remote_camera.h \
zm_remote_camera_http.h \
zm_remote_camera_rtsp.h \
zm_rgb.h \
zm_rtp_ctrl.h \
zm_rtp_data.h \
zm_rtp.h \
@ -110,13 +137,48 @@ noinst_HEADERS = \
zm_rtsp.h \
zm_sdp.h \
zm_signal.h \
zm_stream.h \
zm_thread.h \
zm_time.h \
zm_timer.h \
zm_user.h \
zm_utils.h \
zm_zone.h
zm_user.h
if ZM_HAS_PLUGIN_SUPPORT
# Add objects to zm binaries for plugins management
zm_SOURCES += \
zm_detector.cpp \
zm_image_analyser.cpp \
zm_plugin.cpp \
zm_plugin_manager.cpp
# Build a convenience library for plugin development
noinst_LTLIBRARIES = libzmplugins.la
libzmplugins_la_SOURCES = zm_detector.cpp $(SOURCES_common)
# A hack to avoid conflicts between objects created both with libtool
# and without (objects will be prefixed with "libzmplugins_la")
libzmplugins_la_CPPFLAGS = $(AM_CPPFLAGS)
# Install the necessary headers for plugin development
pkginclude_HEADERS = \
zm_detector.h \
zm_image_analyser.h \
zm_plugin.h \
zm_plugin_manager.h \
$(HEADERS_common)
# Install a pkg-config file for a proper handling of the libzmplugins
# convenience library
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libzmplugins.pc
else
# Don't intall plugin headers if no support
noinst_HEADERS += \
zm_detector.h \
zm_plugin.h \
zm_plugin_manager.h \
zm_image_analyser.h \
$(HEADERS_common)
endif
EXTRA_DIST = \
zm_config.h.in \
@ -126,10 +188,14 @@ dist-hook:
@( rm $(distdir)/zm_config.h )
# Yes, you are correct. This is a HACK!
# And the manual installation of libzmplugins.a is necessary because libtool has
# no option to force installation of convenience libraries.
install-exec-hook:
( cd $(DESTDIR)@bindir@; mkdir -p $(DESTDIR)$(cgidir); mv zms $(DESTDIR)$(cgidir) )
( cd $(DESTDIR)$(cgidir); chown $(webuser):$(webgroup) zms; ln -f zms nph-zms )
install -D -m 644 .libs/libzmplugins.a $(DESTDIR)$(libdir)/libzmplugins.a
uninstall-hook:
( cd $(DESTDIR)$(cgidir); rm -f zms nph-zms )
( cd $(DESTDIR)$(libdir); rm -f libzmplugins.a )

17
src/libzmplugins.pc.in Normal file
View File

@ -0,0 +1,17 @@
prefix=@prefix@
exec_prefix=${prefix}
libdir=@libdir@
pkglibdir = @PLUGINSLIBDIR@
includedir=@includedir@
sysconfdir = @PLUGINSCONFDIR@
webdir = @PLUGINSWEBDIR@
Name: : ZoneMinder convenience library for plugin development.
Description: ZoneMinder convenience library for plugin development.
Version: @PACKAGE_VERSION@
Requires:
Requires.private:
Conflicts:
Libs: -L${libdir} -lzmplugins @LIBS@
Libs.private :
Cflags: -I${includedir}/@PACKAGE@

View File

@ -42,6 +42,8 @@
#define ZM_MAX_IMAGE_DIM (ZM_MAX_IMAGE_WIDTH*ZM_MAX_IMAGE_HEIGHT)
#define ZM_MAX_IMAGE_SIZE (ZM_MAX_IMAGE_DIM*ZM_MAX_IMAGE_COLOURS)
#define ZM_NOTES_MAX_SIZE 4096 // The maximum size of a note
#define ZM_SCALE_BASE 100 // The factor by which we bump up 'scale' to simulate FP
#define ZM_RATE_BASE 100 // The factor by which we bump up 'rate' to simulate FP

232
src/zm_detector.cpp Normal file
View File

@ -0,0 +1,232 @@
#include "zm_detector.h"
/*!\fn Detector::Detector(const Detector& source)
* \param source is the object to copy
*/
Detector::Detector(const Detector& source)
: m_sDetectionCause(source.m_sDetectionCause),
m_fMinAlarmScore(source.m_fMinAlarmScore),
m_fMaxAlarmScore(source.m_fMaxAlarmScore),
m_fImageScaleFactor(source.m_fImageScaleFactor),
m_nNewWidth(source.m_nNewWidth),
m_nNewHeight(source.m_nNewHeight),
m_sLogPrefix(source.m_sLogPrefix),
m_sConfigSectionName(source.m_sConfigSectionName),
m_vnPluginZones(source.m_vnPluginZones)
{
m_bIsPluginEnabled = false;
}
/*!\fn Detector& ImageAnalyser::Detector::operator=(const ImageAnalyser::Detector& source)
* \param source is the object to copy
*/
Detector& Detector::operator=(const Detector& source)
{
m_sDetectionCause = source.m_sDetectionCause;
m_fMinAlarmScore = source.m_fMinAlarmScore;
m_fMaxAlarmScore = source.m_fMaxAlarmScore;
m_fImageScaleFactor = source.m_fImageScaleFactor;
m_sLogPrefix = source.m_sLogPrefix;
m_nNewWidth = source.m_nNewWidth;
m_nNewHeight = source.m_nNewHeight;
m_sConfigSectionName = source.m_sConfigSectionName;
m_vnPluginZones = source.m_vnPluginZones;
return *this;
}
/*!\fn Detector::getDetectionCause()
* return detection cause as string
*/
string Detector::getDetectionCause()
{
return m_sDetectionCause;
}
/*!\fn Detector::getConfigSectionName()
* return plugin name as string
*/
string Detector::getPluginName()
{
return m_sConfigSectionName;
}
/*!\fn Detector::EnablePlugin(vector<int> zoneList)
* \param vnZoneList is the list of enabled zones for the plugin
*/
void Detector::EnablePlugin(vector<unsigned int> vnZoneList)
{
m_vnPluginZones = vnZoneList;
m_bIsPluginEnabled = true;
}
/*!\fn Detector::getPluginZones()
* \return the list of zone which have the plugin enabled
*/
vector<unsigned int> Detector::getPluginZones()
{
return m_vnPluginZones;
}
/*! \fn Detector::log(int nLogLevel, string sLevel, string sMessage)
*/
void Detector::log(int nLogLevel, string sLevel, string sMessage)
{
string sMessageToLog = sLevel + string(" [") + m_sLogPrefix + string(": ") + sMessage + string("]");
syslog(nLogLevel, "%s", sMessageToLog.c_str());
}
/*! \fn int Detector::Detect(const Image &image, Event::StringSet &zoneSet)
* \param zmImage is an image to detect faces on
* \param zoneSet is set of zone names (see zm_zone.h)
* \param score is the detection score
* \return true if detection is effective
*/
bool Detector::Detect(const Image* zmImage, Zone** zones, Event::StringSet &zoneSet, unsigned int &score)
{
bool alarm = false;
char szMessage[100];
score = 0;
if (!m_bIsPluginEnabled) return (alarm);
// Check preclusive zones first
for(std::vector<unsigned int>::iterator it = m_vnPluginZones.begin(); it != m_vnPluginZones.end(); ++it)
{
Zone *zone = zones[*it];
if (!zone->IsPreclusive())
continue;
if (zone->IsPostProcEnabled() && !zone->IsPostProcInProgress())
continue;
sprintf(szMessage, "Checking preclusive zone %s", zone->Label());
log(LOG_DEBUG, "DEBUG", szMessage);
if (checkZone(zone, *it, *zmImage))
{
alarm = true;
score += zone->Score();
zoneSet.insert(zone->Text());
if (zone->IsPostProcEnabled())
{
zone->StopPostProcessing();
sprintf(szMessage, "Zone is alarmed, zone score = %d (post-processing)", zone->Score());
}
else
{
sprintf(szMessage, "Zone is alarmed, zone score = %d", zone->Score());
}
log(LOG_DEBUG, "DEBUG", szMessage);
}
}
if ( alarm )
{
alarm = false;
score = 0;
}
else
{
// Find all alarm pixels in active zones
for(std::vector<unsigned int>::iterator it = m_vnPluginZones.begin(); it != m_vnPluginZones.end(); ++it)
{
Zone *zone = zones[*it];
if (!zone->IsActive())
continue;
if (zone->IsPostProcEnabled() && !zone->IsPostProcInProgress())
continue;
if (checkZone(zone, *it, *zmImage))
{
alarm = true;
score += zone->Score();
zoneSet.insert(zone->Text());
if (zone->IsPostProcEnabled())
{
zone->StopPostProcessing();
sprintf(szMessage, "Zone is alarmed, zone score = %d (post-processing)", zone->Score());
}
else
{
zone->SetAlarm();
sprintf(szMessage, "Zone is alarmed, zone score = %d", zone->Score());
}
log(LOG_DEBUG, "DEBUG", szMessage);
}
}
if ( alarm )
{
// Checking inclusive zones
for(std::vector<unsigned int>::iterator it = m_vnPluginZones.begin(); it != m_vnPluginZones.end(); ++it)
{
Zone *zone = zones[*it];
if (!zone->IsInclusive())
continue;
if (zone->IsPostProcEnabled() && !zone->IsPostProcInProgress())
continue;
sprintf(szMessage, "Checking inclusive zone %s", zone->Label());
log(LOG_DEBUG, "DEBUG", szMessage);
if (checkZone(zone, *it, *zmImage))
{
alarm = true;
score += zone->Score();
zoneSet.insert(zone->Text());
if (zone->IsPostProcEnabled())
{
zone->StopPostProcessing();
sprintf(szMessage, "Zone is alarmed, zone score = %d (post-processing)", zone->Score());
}
else
{
zone->SetAlarm();
sprintf(szMessage, "Zone is alarmed, zone score = %d", zone->Score());
}
log(LOG_DEBUG, "DEBUG", szMessage);
}
}
}
else
{
// Find all alarm pixels in exclusive zones
for(std::vector<unsigned int>::iterator it = m_vnPluginZones.begin(); it != m_vnPluginZones.end(); ++it)
{
Zone *zone = zones[*it];
if (!zone->IsExclusive())
continue;
if (zone->IsPostProcEnabled() && !zone->IsPostProcInProgress())
continue;
sprintf(szMessage, "Checking exclusive zone %s", zone->Label());
log(LOG_DEBUG, "DEBUG", szMessage);
if (checkZone(zone, *it, *zmImage))
{
alarm = true;
score += zone->Score();
zoneSet.insert(zone->Text());
if (zone->IsPostProcEnabled())
{
zone->StopPostProcessing();
sprintf(szMessage, "Zone is alarmed, zone score = %d (post-processing)", zone->Score());
}
else
{
zone->SetAlarm();
sprintf(szMessage, "Zone is alarmed, zone score = %d", zone->Score());
}
log(LOG_DEBUG, "DEBUG", szMessage);
}
}
}
}
return alarm;
}

137
src/zm_detector.h Normal file
View File

@ -0,0 +1,137 @@
#ifndef ZM_DETECTOR_H
#define ZM_DETECTOR_H
#include <string>
#include <algorithm>
#include <syslog.h>
#include <libgen.h>
#include "zm_image.h"
#include "zm_zone.h"
#include "zm_event.h"
#define DEFAULT_DETECTION_CAUSE "Object Detected"
#define DEFAULT_MIN_ALARM_SCORE 1.0
#define DEFAULT_MAX_ALARM_SCORE 99.0
#define DEFAULT_IMAGE_SCALE_FACTOR 1.0
#define DEFAULT_LOG_PREFIX "ZM PLUGIN"
#define LOG_LEVEL LOG_NOTICE
#define DEFAULT_CONFIGFILE_SECTION "libzm_vscvl_plugin"
using namespace std;
//! Base class for object detectors, defined in plugins.
class Detector
{
public:
//! Destructor
virtual ~Detector() {}
//! Default constructor
Detector()
{
m_sLogPrefix = DEFAULT_LOG_PREFIX;
m_sDetectionCause = DEFAULT_DETECTION_CAUSE;
m_fMinAlarmScore = DEFAULT_MIN_ALARM_SCORE;
m_fMaxAlarmScore = DEFAULT_MAX_ALARM_SCORE;
m_fImageScaleFactor = DEFAULT_IMAGE_SCALE_FACTOR;
m_sConfigSectionName = DEFAULT_CONFIGFILE_SECTION;
m_nNewWidth = 0;
m_nNewHeight = 0;
}
//! Constructor with section name parameter.
Detector(string sPluginFileName)
{
m_sLogPrefix = DEFAULT_LOG_PREFIX;
char* szPluginFileName = strdup(sPluginFileName.c_str());
string sPluginFileNameName = string(basename(szPluginFileName));
size_t idx = sPluginFileNameName.rfind('.');
if (idx == string::npos)
m_sConfigSectionName = sPluginFileNameName;
else
m_sConfigSectionName = sPluginFileNameName.substr(0, idx);
m_sDetectionCause = DEFAULT_DETECTION_CAUSE;
m_fMinAlarmScore = DEFAULT_MIN_ALARM_SCORE;
m_fMaxAlarmScore = DEFAULT_MAX_ALARM_SCORE;
m_fImageScaleFactor = DEFAULT_IMAGE_SCALE_FACTOR;
m_nNewWidth = 0;
m_nNewHeight = 0;
}
//! Copy constructor
Detector(const Detector& source);
//! Assignment operator
Detector& operator=(const Detector& source);
//! Detect (in an image later)
bool Detect(const Image* image, Zone** zones, Event::StringSet &zoneSet, unsigned int &score);
//! Load detector's parameters.
virtual int loadConfig(string sConfigFileName, map<unsigned int,map<string,string> > mapPluginConf) = 0;
//! Returns detection case string.
string getDetectionCause();
//! Returns plugin name as string.
string getPluginName();
//! Enable the plugin for the given zones.
void EnablePlugin(vector<unsigned int> zoneList);
//! Return the list of enabled zones
vector<unsigned int> getPluginZones();
protected:
//! Do detection inside one given zone.
virtual bool checkZone(Zone *zone, unsigned int n_zone, const Image &zmImage) = 0;
//! Log messages to the SYSLOG.
void log(int, string sLevel, string sMessage);
//! String to be shown as detection cause for event.
string m_sDetectionCause;
//! Minimum score value to consider frame as to be alarmed.
double m_fMinAlarmScore;
//! Maximum score value to consider frame as to be alarmed.
double m_fMaxAlarmScore;
//! Maximum allowed width of frame image.
double m_fImageScaleFactor;
//! Width of image to resize.
int m_nNewWidth;
//! Height of image to resize.
int m_nNewHeight;
//! String prefix for SYSLOG messages.
string m_sLogPrefix;
//! Name of config file section to search parameters.
string m_sConfigSectionName;
//! List of zones enabled for the plugin
vector<unsigned int> m_vnPluginZones;
//! Plugin status regarding zone settings
bool m_bIsPluginEnabled;
};
#endif // ZM_DETECTOR_H

View File

@ -63,6 +63,8 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
std::string notes;
createNotes( notes );
static char escapedNotes[ZM_NOTES_MAX_SIZE*2 + 1];
mysql_real_escape_string( &dbconn, escapedNotes, notes.c_str(), notes.length() );
bool untimedEvent = false;
if ( !start_time.tv_sec )
@ -71,10 +73,10 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
gettimeofday( &start_time, 0 );
}
static char sql[ZM_SQL_MED_BUFSIZ];
static char sql[ZM_SQL_LGE_BUFSIZ];
struct tm *stime = localtime( &start_time.tv_sec );
snprintf( sql, sizeof(sql), "insert into Events ( MonitorId, Name, StartTime, Width, Height, Cause, Notes ) values ( %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s' )", monitor->Id(), start_time.tv_sec, monitor->Width(), monitor->Height(), cause.c_str(), notes.c_str() );
snprintf( sql, sizeof(sql), "insert into Events ( MonitorId, Name, StartTime, Width, Height, Cause, Notes ) values ( %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s' )", monitor->Id(), start_time.tv_sec, monitor->Width(), monitor->Height(), cause.c_str(), escapedNotes );
if ( mysql_query( &dbconn, sql ) )
{
Error( "Can't insert event: %s", mysql_error( &dbconn ) );
@ -185,7 +187,7 @@ Event::~Event()
struct DeltaTimeval delta_time;
DELTA_TIMEVAL( delta_time, end_time, start_time, DT_PREC_2 );
snprintf( sql, sizeof(sql), "update Events set Name='%s%d', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d where Id = %d", monitor->EventPrefix(), id, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, id );
snprintf( sql, sizeof(sql), "update Events set Name='%s%d', Cause='%s', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d where Id = %d", monitor->EventPrefix(), id, cause.c_str(), end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, id );
if ( mysql_query( &dbconn, sql ) )
{
Error( "Can't update event: %s", mysql_error( &dbconn ) );
@ -198,16 +200,34 @@ void Event::createNotes( std::string &notes )
notes.clear();
for ( StringSetMap::const_iterator mapIter = noteSetMap.begin(); mapIter != noteSetMap.end(); mapIter++ )
{
notes += mapIter->first;
notes += ": ";
// No need to display the cause inside the note
//notes += mapIter->first;
//notes += ": ";
const StringSet &stringSet = mapIter->second;
for ( StringSet::const_iterator setIter = stringSet.begin(); setIter != stringSet.end(); setIter++ )
{
if ( setIter != stringSet.begin() )
notes += ", ";
// Don't format here
//if ( setIter != stringSet.begin() )
// notes += ", ";
notes += *setIter;
}
}
if (notes.length() > ZM_NOTES_MAX_SIZE)
{
std::string sTrunc = "... (content truncated)";
notes = notes.substr(0, (ZM_NOTES_MAX_SIZE - sTrunc.length()));
notes += sTrunc;
}
}
void Event::AddCause( const std::string new_cause )
{
if ( cause.find( new_cause ) == std::string::npos )
{
if ( cause.length() )
cause += ", ";
cause += new_cause;
}
}
int Event::sd = -1;
@ -421,12 +441,12 @@ void Event::updateNotes( const StringSetMap &newNoteSetMap )
std::string notes;
createNotes( notes );
Debug( 2, "Updating notes for event %d, '%s'", id, notes.c_str() );
static char sql[ZM_SQL_MED_BUFSIZ];
Debug( 2, "Updating notes for event %d", id );
static char sql[ZM_SQL_LGE_BUFSIZ];
#if USE_PREPARED_SQL
static MYSQL_STMT *stmt = 0;
char notesStr[ZM_SQL_MED_BUFSIZ] = "";
char notesStr[ZM_NOTES_MAX_SIZE] = "";
unsigned long notesLen = 0;
if ( !stmt )
@ -475,7 +495,7 @@ void Event::updateNotes( const StringSetMap &newNoteSetMap )
Fatal( "Unable to execute sql '%s': %s", sql, mysql_stmt_error(stmt) );
}
#else
static char escapedNotes[ZM_SQL_MED_BUFSIZ];
static char escapedNotes[ZM_NOTES_MAX_SIZE*2 + 1];
mysql_real_escape_string( &dbconn, escapedNotes, notes.c_str(), notes.length() );

View File

@ -132,6 +132,7 @@ public:
void AddFrames( int n_frames, Image **images, struct timeval **timestamps );
void AddFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL );
void AddCause( const std::string new_cause );
private:
void AddFramesInternal( int n_frames, int start_frame, Image **images, struct timeval **timestamps );

View File

@ -1,6 +1,16 @@
#include "zm_image_analyser.h"
ImageAnalyser::ImageAnalyser( int nMonitorId )
{
if ( nMonitorId > 0 )
{
m_nMonitorId = nMonitorId;
m_bIsAnalyserEnabled = getMonitorZones();
}
else
m_bIsAnalyserEnabled = false;
m_bIsNativeDetEnabled = false;
}
/*!\fn ImageAnalyser::ImageAnalyser(const ImageAnalyser& source)
* \param source is the object to copy
@ -33,32 +43,445 @@ ImageAnalyser::~ImageAnalyser()
/*!\fn ImageAnalyser::DoDetection(const Image &comp_image, Zone** zones, int n_numZones, Event::StringSetMap noteSetMap, std::string& det_cause)
/*!\fn ImageAnalyser::DoDetection(const Image &comp_image, Zone** zones, Event::StringSetMap noteSetMap, string& det_cause)
* \param comp_image is the image to analyse
* \param zones is the zones array to analyse
* \param n_numZones is the number of zones
* \param noteSetMap is the map of events descriptions
* \param det_cause is a string describing detection cause
* \param score is the plugin score
*/
int ImageAnalyser::DoDetection(const Image &comp_image, Zone** zones, int n_numZones, Event::StringSetMap noteSetMap, std::string& det_cause)
bool ImageAnalyser::DoDetection(const Image &comp_image, Zone** zones, Event::StringSetMap& noteSetMap, string& det_cause, unsigned int& score)
{
Event::StringSet zoneSet;
int score = 0;
score = 0;
bool alarm = false;
for(DetectorsList::iterator It = m_Detectors.begin();
for ( DetectorsList::iterator It = m_Detectors.begin();
It != m_Detectors.end();
++It)
++It )
{
int detect_score = (*It)->Detect(comp_image, zones, n_numZones, zoneSet);
if (detect_score)
unsigned int detect_score = 0;
if ( (*It)->Detect( &comp_image, zones, zoneSet, detect_score ) )
{
alarm = true;
score += detect_score;
noteSetMap[(*It)->getDetectionCause()] = zoneSet;
if (det_cause.length())
det_cause += ", ";
det_cause += (*It)->getDetectionCause();
std::string new_cause = (*It)->getDetectionCause();
noteSetMap[new_cause] = zoneSet;
if ( det_cause.find( new_cause ) == std::string::npos )
{
if ( det_cause.length() )
det_cause += ", ";
det_cause += new_cause;
}
}
}
return score;
return alarm;
}
/*!\fn ImageAnalyser::configurePlugins(string sConfigFileName)
*\param sConfigFileName is the path to the configuration file, where parameters for all plugins are given.
* \param bDoNativeDet is true if native detection will be performed
*/
void ImageAnalyser::configurePlugins(string sConfigFileName, bool bDoNativeDet)
{
string sLoadedPlugins;
if ( !m_bIsAnalyserEnabled ) return;
m_bIsNativeDetEnabled = bDoNativeDet;
for ( DetectorsList::iterator It = m_Detectors.begin(); It != m_Detectors.end(); ++It )
{
string sPluginName = (*It)->getPluginName();
try
{
if ( isValidConfigFile( sPluginName, sConfigFileName ) )
{
Info("Configure plugin '%s' with config file '%s'.", sPluginName.c_str(), sConfigFileName.c_str());
map<unsigned int,map<string,string> > mapPluginConf;
vector<unsigned int> vnPluginZones;
bool plugEnabled = getEnabledZonesForPlugin( sPluginName, vnPluginZones );
if ( getPluginConfig( sPluginName, vnPluginZones, mapPluginConf )
&& (*It)->loadConfig( sConfigFileName, mapPluginConf ) )
{
mapRegPluginGenConf[sPluginName].Configured = true;
if ( plugEnabled )
{
(*It)->EnablePlugin( vnPluginZones );
if ( sLoadedPlugins.length() )
sLoadedPlugins += ", ";
sLoadedPlugins += "'" + sPluginName + "'";
}
}
}
}
catch(...)
{
Error("Plugin '%s' couldn't be loaded", sPluginName.c_str());
}
}
getZonesConfig( sLoadedPlugins );
}
/*!\fn ImageAnalyser::isValidConfigFile(string sPluginName, string sConfigFileName)
* \param sPluginName is the name of the plugin (filename without extension)
* \param sConfigFileName is the path to the configuration file which should include configuration directives for the plugin
* \return true if the config file contains the right section name
*/
bool ImageAnalyser::isValidConfigFile(string sPluginName, string sConfigFileName)
{
ifstream ifs(sConfigFileName.c_str());
string line;
bool rtnVal = false;
while (getline(ifs, line))
{
if (line == "[" + sPluginName + "]")
{
rtnVal = true;
break;
}
}
ifs.close();
return rtnVal;
}
/*!\fn ImageAnalyser::getMonitorZones()
* \return true if at least a zone is configured for the monitor
*/
bool ImageAnalyser::getMonitorZones()
{
static char sql[ZM_SQL_MED_BUFSIZ];
// We use the same ordering as in Monitor::Load
snprintf(sql, sizeof(sql), "SELECT `Id`, `Name`, `Type` FROM `Zones` WHERE `MonitorId` = %d ORDER BY `Type`, `Id`;", m_nMonitorId);
if (mysql_query(&dbconn, sql))
{
Error("Can't run query: %s", mysql_error(&dbconn));
exit(mysql_errno(&dbconn));
}
MYSQL_RES *result = mysql_store_result(&dbconn);
if (!result)
{
Error("Can't use query result: %s", mysql_error(&dbconn));
exit(mysql_errno(&dbconn));
}
if (mysql_num_rows(result) > 0)
{
for (unsigned int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++)
{
if (mysql_errno(&dbconn))
{
Error("Can't fetch row: %s", mysql_error(&dbconn));
exit(mysql_errno(&dbconn));
}
zSetting zone;
zone.id = (unsigned int)strtoul(dbrow[0], NULL, 0);
zone.name = string(dbrow[1]);
zone.type = string(dbrow[2]);
m_vMonitorZones.push_back(zone);
}
}
mysql_free_result(result);
return ( m_vMonitorZones.size() );
}
/*!\fn ImageAnalyser::getPluginConfig(string sPluginName, map<unsigned int,map<string,string> >& mapPluginConf)
* \param sPluginName is the name of the plugin (filename without extension)
* \param vnPluginZones is a vector containing the index of zones enabled for the plugin (not the zone Id in the database)
* \param mapPluginConf is the map filled with configuration parameters for the plugin
* \return true if all found parameters are applied to the map
*/
bool ImageAnalyser::getPluginConfig(string sPluginName, vector<unsigned int> vnPluginZones, map<unsigned int,map<string,string> >& mapPluginConf)
{
static char sql[ZM_SQL_MED_BUFSIZ];
// Get plugin configuration parameters from `PluginsConfig` table
snprintf(sql, sizeof(sql), "SELECT `ZoneId`, `Name`, `Value` FROM `PluginsConfig` WHERE `MonitorId`=%d AND `pluginName`='%s' ORDER BY `ZoneId` ASC;", m_nMonitorId, sPluginName.c_str());
if (mysql_query(&dbconn, sql))
{
Error("Can't run query: %s", mysql_error(&dbconn));
exit(mysql_errno(&dbconn));
}
MYSQL_RES *result = mysql_store_result(&dbconn);
if (!result)
{
Error("Can't use query result: %s", mysql_error(&dbconn));
exit(mysql_errno(&dbconn));
}
size_t nParamCnt = 0;
size_t nParamNum = mysql_num_rows(result);
if (nParamNum > 0)
{
vector<MYSQL_ROW> vRows;
for (unsigned int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++)
{
if (mysql_errno(&dbconn))
{
Error("Can't fetch row: %s", mysql_error(&dbconn));
mysql_free_result(result);
exit(mysql_errno(&dbconn));
}
vRows.push_back(dbrow);
}
// Iterate over the zones
for (size_t i = 0; i < m_vMonitorZones.size(); i++)
{
// Iterate over the configuration parameters
for (vector<MYSQL_ROW>::iterator it = vRows.begin(); it != vRows.end(); it++)
{
// Add the parameter to the map if the zone id is found
if ( (unsigned int)strtoul((*it)[0], NULL, 0) == m_vMonitorZones[i].id )
{
nParamCnt++;
string name((*it)[1]);
string value((*it)[2]);
if((name == "Enabled") && (value == "Yes")) {
mapRegPluginZoneConf[sPluginName][m_vMonitorZones[i].id].Enabled = true;
} else if((name == "RequireNatDet") && (value == "Yes")) {
mapRegPluginZoneConf[sPluginName][m_vMonitorZones[i].id].RequireNatDet = true;
} else if((name == "IncludeNatDet") && (value == "Yes")) {
mapRegPluginZoneConf[sPluginName][m_vMonitorZones[i].id].IncludeNatDet = true;
} else if((name == "ReInitNatDet") && (value == "Yes")) {
mapRegPluginZoneConf[sPluginName][m_vMonitorZones[i].id].ReInitNatDet = true;
}
// Keep only enabled zones in mapPluginConf
if (binary_search(vnPluginZones.begin(), vnPluginZones.end(), i)) {
mapPluginConf[i][name] = value;
}
}
}
if ( mapRegPluginZoneConf[sPluginName][m_vMonitorZones[i].id].Enabled
&& mapRegPluginZoneConf[sPluginName][m_vMonitorZones[i].id].RequireNatDet
&& !m_bIsNativeDetEnabled )
Warning("Plugin '%s' will never enter in alarm because native detection is required but not enabled", sPluginName.c_str());
}
}
mysql_free_result(result);
return ( nParamNum == nParamCnt );
}
/*!\fn ImageAnalyser::getEnabledZonesForPlugin(string sPluginName, vector<unsigned int>& vnPluginZones)
* \param sPluginName is the name of the plugin (filename without extension)
* \param vnPluginZones is the vector list filled with zones enabled for this plugin
* \return true if at least one active or exclusive zone exist
*/
bool ImageAnalyser::getEnabledZonesForPlugin(string sPluginName, vector<unsigned int>& vnPluginZones)
{
static char sql[ZM_SQL_MED_BUFSIZ];
bool bPluginEnabled = false;
string sZones;
// Get the sorted list of zones ids which have the plugin enabled
snprintf(sql, sizeof(sql), "SELECT `ZoneId` FROM `PluginsConfig` WHERE `MonitorId`=%d AND `pluginName`='%s' AND `Name`='Enabled' AND `Value`='yes' ORDER BY `ZoneId` ASC;", m_nMonitorId, sPluginName.c_str());
if (mysql_query( &dbconn, sql))
{
Error("Can't run query: %s", mysql_error(&dbconn));
exit(mysql_errno(&dbconn));
}
MYSQL_RES *result = mysql_store_result(&dbconn);
if (!result)
{
Error("Can't use query result: %s", mysql_error(&dbconn));
exit(mysql_errno(&dbconn));
}
if (mysql_num_rows(result) > 0)
{
vector<unsigned int> vnEnabledZoneIds;
for (unsigned int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++)
{
if (mysql_errno(&dbconn))
{
Error("Can't fetch row: %s", mysql_error(&dbconn));
mysql_free_result(result);
exit(mysql_errno(&dbconn));
}
vnEnabledZoneIds.push_back(atoi(dbrow[0]));
}
// Iterate over the zones
for (size_t i = 0; i < m_vMonitorZones.size(); i++)
{
if (binary_search(vnEnabledZoneIds.begin(), vnEnabledZoneIds.end(), m_vMonitorZones[i].id))
{
// Add the index to the vector if the zone id is found
vnPluginZones.push_back(i);
string sZoneType = m_vMonitorZones[i].type;
if ((sZoneType == "Active") || (sZoneType == "Exclusive"))
bPluginEnabled = true;
if ( sZones.length() )
sZones += ", ";
sZones += m_vMonitorZones[i].name + " (" + sZoneType + ")";
}
}
}
mysql_free_result(result);
if (bPluginEnabled)
{
Info("Plugin '%s' is enabled for zone(s): %s", sPluginName.c_str(), sZones.c_str());
}
else
{
Info("Plugin '%s' is disabled (not enabled for any active or exclusive zones)", sPluginName.c_str());
}
return bPluginEnabled;
}
/*!\fn ImageAnalyser::getZonesConfig()
* \param sLoadedPlugins is the formatted list of loaded plugins
*/
bool ImageAnalyser::getZonesConfig(string sLoadedPlugins)
{
static char sql[ZM_SQL_MED_BUFSIZ];
if ( !sLoadedPlugins.length() ) return false;
// Get the sorted list of zones and which have a setting enabled
snprintf(sql, sizeof(sql), "SELECT DISTINCT `ZoneId`, `Name` FROM `PluginsConfig` WHERE `MonitorId` = %d AND `pluginName` IN (%s) AND `Name` IN ('RequireNatDet', 'IncludeNatDet', 'ReInitNatDet') AND `Value` = 'yes' ORDER BY `ZoneId` ASC;", m_nMonitorId, sLoadedPlugins.c_str());
if (mysql_query(&dbconn, sql))
{
Error("Can't run query: %s", mysql_error(&dbconn));
exit(mysql_errno(&dbconn));
}
MYSQL_RES *result = mysql_store_result(&dbconn);
if (!result)
{
Error("Can't use query result: %s", mysql_error(&dbconn));
exit(mysql_errno(&dbconn));
}
if (mysql_num_rows(result) > 0)
{
vector<zIdName> vSettings;
for (unsigned int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++)
{
if (mysql_errno(&dbconn))
{
Error("Can't fetch row: %s", mysql_error(&dbconn));
mysql_free_result(result);
exit(mysql_errno(&dbconn));
}
zIdName setting;
setting.zoneId = (unsigned int)strtoul(dbrow[0], NULL, 0);
setting.name = dbrow[1];
vSettings.push_back(setting);
}
// Iterate over the zones and add the index to the vector if the zone id is found
for (size_t i = 0; i != m_vMonitorZones.size(); i++)
{
zConf zoneConf;
for (vector<zIdName>::iterator it = vSettings.begin(); it != vSettings.end(); it++)
{
if (it->zoneId == m_vMonitorZones[i].id)
{
if (it->name == "RequireNatDet")
zoneConf.RequireNatDet = true;
else if (it->name == "IncludeNatDet")
zoneConf.IncludeNatDet = true;
else if (it->name == "ReInitNatDet")
zoneConf.ReInitNatDet = true;
}
}
m_vZonesConfig.push_back(zoneConf);
}
}
mysql_free_result(result);
return true;
}
/*!\fn ImageAnalyser::getZoneConfig(int nZone, zConf& zoneConf)
* \param nZone is the zone index (not the id in sql database)
* \param zoneConf is a structure filled with the plugin settings of nZone
*/
bool ImageAnalyser::getZoneConfig(unsigned int nZone, zConf& zoneConf)
{
if (nZone < m_vZonesConfig.size())
zoneConf = m_vZonesConfig[nZone];
else
return false;
return true;
}
/*!\fn ImageAnalyser::getRegPluginGenConf(string sPluginName, pGenConf& regPluginGenConf)
* \param sPluginName is the name of the plugin (filename without extension)
* \param regPluginGenConf is a structure filled with the general settings of the plugin
* \return false if no setting is found
*/
bool ImageAnalyser::getRegPluginGenConf(string sPluginName, pGenConf& regPluginGenConf)
{
map<string,pGenConf>::iterator it = mapRegPluginGenConf.find( sPluginName );
if ( it == mapRegPluginGenConf.end() )
return false;
regPluginGenConf = it->second;
return true;
}
/*!\fn ImageAnalyser::getRegPluginZoneConf(string sPluginName, PluginZoneConf& regPluginZoneConf)
* \param sPluginName is the name of the plugin (filename without extension)
* \param regPluginZoneConf is a map filled with the zone settings of the plugin
*/
void ImageAnalyser::getRegPluginZoneConf(string sPluginName, PluginZoneConf& regPluginZoneConf)
{
map<string,PluginZoneConf>::iterator it = mapRegPluginZoneConf.find( sPluginName );
if ( it != mapRegPluginZoneConf.end() )
regPluginZoneConf = it->second;
pZoneConf empty;
for (size_t i = 0; i != m_vMonitorZones.size(); i++)
{
PluginZoneConf::iterator it2 = regPluginZoneConf.find( m_vMonitorZones[i].id );
if ( it2 == regPluginZoneConf.end() )
regPluginZoneConf[m_vMonitorZones[i].id] = empty;
}
}
void ImageAnalyser::cleanupPlugins()
{
string sPluginsToKeep;
string sRequest;
static char sql[ZM_SQL_MED_BUFSIZ];
for ( DetectorsList::iterator It = m_Detectors.begin(); It != m_Detectors.end(); ++It )
{
if ( sPluginsToKeep.length() )
sPluginsToKeep += ", ";
sPluginsToKeep += "'" + (*It)->getPluginName() + "'";
}
if ( sPluginsToKeep.length() )
sRequest = " AND `pluginName` NOT IN (" + sPluginsToKeep + ")";
snprintf(sql, sizeof(sql), "DELETE FROM `PluginsConfig` WHERE `MonitorId` = %d%s;", m_nMonitorId, sRequest.c_str());
if ( mysql_query( &dbconn, sql ) )
{
Error( "Can't delete plugint: %s", mysql_error( &dbconn ) );
exit( mysql_errno( &dbconn ) );
}
}

View File

@ -7,25 +7,58 @@
#include <string>
#include <stdexcept>
#include <iostream>
#include <fstream>
#include <memory>
#include <algorithm>
#include "zm.h"
#include "zm_detector.h"
#include "zm_image.h"
#include "zm_zone.h"
#include "zm_event.h"
#include "zm_db.h"
using namespace std;
//! List of available detectors.
typedef std::list<Detector *> DetectorsList;
//! A structure to store the general configuration of a plugin
struct pGenConf {
bool Registered;
bool Configured;
pGenConf():
Registered(false),
Configured(false)
{}
};
//! A structure to store the zone configuration of a plugin
struct pZoneConf {
bool Enabled;
bool RequireNatDet;
bool IncludeNatDet;
bool ReInitNatDet;
pZoneConf():
Enabled(false),
RequireNatDet(false),
IncludeNatDet(false),
ReInitNatDet(false)
{}
};
//! Map of zone configuration for a plugin
typedef std::map<unsigned int,pZoneConf> PluginZoneConf;
//! Class for handling image detection.
class ImageAnalyser {
public:
//!Default constructor.
ImageAnalyser() {};
ImageAnalyser( int nMonitorId = 0 );
//! Destructor.
~ImageAnalyser();
@ -36,8 +69,83 @@ class ImageAnalyser {
//! Overloaded operator=.
ImageAnalyser& operator=(const ImageAnalyser& source);
private:
//! Adds new plugin's detector to the list of detectors.
void addDetector(std::auto_ptr<Detector> Det)
{
m_Detectors.push_back(Det.release());
}
//! Do detection in an image by calling all available detectors.
bool DoDetection(const Image &comp_image, Zone** zones, Event::StringSetMap& noteSetMap, std::string& det_cause, unsigned int& score);
//! Configure all loaded plugins using given configuration file.
void configurePlugins(string sConfigFileName, bool bDoNativeDet = 0);
//! Check if the configuration file contains the right section name
bool isValidConfigFile(string sPluginName, string sConfigFileName);
//! Get index of enabled zones for this monitor (same ordering as in Monitor::Load)
bool getMonitorZones();
//! Get plugin configuration from database
bool getPluginConfig(string sPluginName, vector<unsigned int> vnPluginZones, map<unsigned int,map<string,string> >& mapPluginConf);
//! Get enabled zones for the plugin
bool getEnabledZonesForPlugin(string sPluginName, vector<unsigned int>& vnPluginZones);
//! Get zones configuration from database
bool getZonesConfig(string sLoadedPlugins);
//! Get Zone configuration from this class
bool getZoneConfig(unsigned int nZone, zConf& zoneConf);
//! Get the general settings of a registered plugin
bool getRegPluginGenConf(string sPluginName, pGenConf& regPluginGenConf);
//! Get the zone settings of a registered plugin
void getRegPluginZoneConf(string sPluginName, PluginZoneConf& regPluginZoneConf);
//! Remove from db plugins no longer detected
void cleanupPlugins();
private:
//! All available detectors.
DetectorsList m_Detectors;
//! The monitor id
int m_nMonitorId;
//! Native detection is enabled
bool m_bIsNativeDetEnabled;
//! Analyser is enabled
bool m_bIsAnalyserEnabled;
//! A structure to store a plugin parameter
struct zIdName {
unsigned int zoneId;
string name;
};
//! A vector filled with parameters of zones
vector<zConf> m_vZonesConfig;
//! A structure to store basic settings of a zone
struct zSetting {
unsigned int id;
string name;
string type;
};
//! A vector filled with settings of zones enabled for the monitor
vector<zSetting> m_vMonitorZones;
//! A map to store the general configuration of registered plugins
map<string,pGenConf> mapRegPluginGenConf;
//! A map to store the zone configuration of registered plugins
map<string,PluginZoneConf> mapRegPluginZoneConf;
};

View File

@ -35,9 +35,6 @@
bool Logger::smInitialised = false;
Logger *Logger::smInstance = 0;
Logger::StringMap Logger::smCodes;
Logger::IntMap Logger::smSyslogPriorities;
#if 0
static void subtractTime( struct timeval * const tp1, struct timeval * const tp2 )
{

View File

@ -84,8 +84,8 @@ private:
static bool smInitialised;
static Logger *smInstance;
static StringMap smCodes;
static IntMap smSyslogPriorities;
StringMap smCodes;
IntMap smSyslogPriorities;
private:
bool mInitialised;

View File

@ -65,6 +65,23 @@ std::vector<std::string> split(const std::string &s, char delim) {
}
return elems;
}
#if ZM_PLUGINS_ON
int conf_select(const struct direct *entry)
{
char *ptr;
if ((strcmp(entry->d_name, ".")== 0) || (strcmp(entry->d_name, "..") == 0))
return 0;
// Check for filename extensions.
ptr = rindex((char*)entry->d_name, '.');
if ((ptr != NULL) && (strcmp(ptr, ".conf") == 0))
return 1;
else
return 0;
}
#endif // ZM_PLUGINS_ON
//=============================================================================
@ -286,7 +303,8 @@ Monitor::Monitor(
Rgb p_signal_check_colour,
Purpose p_purpose,
int p_n_zones,
Zone *p_zones[]
Zone *p_zones[],
int p_DoNativeMotDet
) : id( p_id ),
function( (Function)p_function ),
enabled( p_enabled ),
@ -311,15 +329,15 @@ Monitor::Monitor(
alarm_ref_blend_perc( p_alarm_ref_blend_perc ),
track_motion( p_track_motion ),
signal_check_colour( p_signal_check_colour ),
delta_image( width, height, ZM_COLOUR_GRAY8, ZM_SUBPIX_ORDER_NONE ),
ref_image( width, height, p_camera->Colours(), p_camera->SubpixelOrder() ),
purpose( p_purpose ),
last_motion_score(0),
camera( p_camera ),
n_zones( p_n_zones ),
zones( p_zones ),
timestamps( 0 ),
images( 0 )
images( 0 ),
iDoNativeMotDet( p_DoNativeMotDet ),
ThePluginManager( p_id )
{
strncpy( name, p_name, sizeof(name) );
@ -414,6 +432,35 @@ Monitor::Monitor(
shared_data->alarm_y = -1;
}
#if ZM_PLUGINS_ON
if ( purpose == ANALYSIS || purpose == QUERY )
{
if ( config.load_plugins || purpose == QUERY )
{
Info("Load plugins from the directory %s ... ", config.path_plugins);
ThePluginManager.setPluginExt(std::string(config.plugin_extension));
unsigned int nNumPlugLoaded = 0;
unsigned int nNumPlugFound = ThePluginManager.findPlugins(
std::string(config.path_plugins), (purpose == ANALYSIS), nNumPlugLoaded );
Info("Found %u plugin(s) - %u loaded", nNumPlugFound, nNumPlugLoaded);
if (nNumPlugFound > 0)
{
ThePluginManager.configurePlugins(
std::string(config.plugins_config_path),
(!config.turnoff_native_analysis && iDoNativeMotDet));
struct direct **files;
int count = scandir(config.plugins_config_dir, &files, conf_select, alphasort);
if (count > 0)
Info("Load plugin configuration files from directory %s ... ", config.plugins_config_dir);
for (int i = 0; i < count; ++i)
ThePluginManager.configurePlugins(
join_paths(config.plugins_config_dir, files[i]->d_name),
(!config.turnoff_native_analysis && iDoNativeMotDet));
}
}
}
#endif // ZM_PLUGINS_ON
if ( ( ! mem_ptr ) || ! shared_data->valid )
{
if ( purpose != QUERY )
@ -486,7 +533,6 @@ Monitor::Monitor(
Warning( "Waiting for capture daemon" );
sleep( 1 );
}
ref_image.Assign( width, height, camera->Colours(), camera->SubpixelOrder(), image_buffer[shared_data->last_write_index].image->Buffer(), camera->ImageSize());
n_linked_monitors = 0;
linked_monitors = 0;
@ -645,6 +691,24 @@ void Monitor::AddZones( int p_n_zones, Zone *p_zones[] )
delete[] zones;
n_zones = p_n_zones;
zones = p_zones;
for ( int i = 0; i < n_zones; i++ )
{
if ( purpose == ANALYSIS )
{
Zone *zone = zones[i];
Debug( 4, "Assign reference image of zone %s", zone->Label() );
zone->AssignRefImage( width, height, camera->Colours(), camera->SubpixelOrder(),
image_buffer[shared_data->last_write_index].image->Buffer(), camera->ImageSize() );
#if ZM_PLUGINS_ON
zConf zone_conf;
if ( ThePluginManager.getImageAnalyser().getZoneConfig( i, zone_conf ) )
{
Debug( 4, "Configure zone %s for plugins", zone->Label() );
zone->SetConfig( zone_conf );
}
#endif // ZM_PLUGINS_ON
}
}
}
Monitor::State Monitor::GetState() const
@ -1227,7 +1291,11 @@ bool Monitor::Analyse()
{
Info( "Received resume indication at count %d", image_count );
shared_data->active = true;
ref_image = *snap_image;
for ( int n_zone = 0; n_zone < n_zones; n_zone++ )
{
Debug( 4, "Set reference image of zone %s", zones[n_zone]->Label() );
zones[n_zone]->SetRefImage(*snap_image);
}
ready_count = image_count+(warmup_count/2);
shared_data->alarm_x = shared_data->alarm_y = -1;
}
@ -1238,7 +1306,11 @@ bool Monitor::Analyse()
{
Info( "Auto resuming at count %d", image_count );
shared_data->active = true;
ref_image = *snap_image;
for ( int n_zone = 0; n_zone < n_zones; n_zone++ )
{
Debug( 4, "Set reference image of zone %s", zones[n_zone]->Label() );
zones[n_zone]->SetRefImage(*snap_image);
}
ready_count = image_count+(warmup_count/2);
auto_resume_time = 0;
}
@ -1276,6 +1348,8 @@ bool Monitor::Analyse()
cause += ", ";
cause += trigger_data->trigger_cause;
}
else
event->AddCause( trigger_data->trigger_cause );
Event::StringSet noteSet;
noteSet.insert( trigger_data->trigger_text );
noteSetMap[trigger_data->trigger_cause] = noteSet;
@ -1303,39 +1377,85 @@ bool Monitor::Analyse()
cause += ", ";
cause += SIGNAL_CAUSE;
}
else
event->AddCause( SIGNAL_CAUSE );
Event::StringSet noteSet;
noteSet.insert( signalText );
noteSetMap[SIGNAL_CAUSE] = noteSet;
shared_data->state = state = IDLE;
shared_data->active = signal;
ref_image = *snap_image;
for ( int n_zone = 0; n_zone < n_zones; n_zone++ )
{
Debug( 4, "Set reference image of zone %s", zones[n_zone]->Label() );
zones[n_zone]->SetRefImage(*snap_image);
}
}
else if ( signal && Active() && (function == MODECT || function == MOCORD) )
{
Event::StringSet zoneSet;
int motion_score = last_motion_score;
if ( !(image_count % (motion_frame_skip+1) ) )
#if ZM_PLUGINS_ON
if ((config.turnoff_native_analysis && !config.load_plugins) || (!config.turnoff_native_analysis && (iDoNativeMotDet || (!iDoNativeMotDet && !config.load_plugins))) )
#else // ZM_PLUGINS_ON
if (!config.turnoff_native_analysis && iDoNativeMotDet)
#endif // ZM_PLUGINS_ON
{
// Get new score.
motion_score = last_motion_score = DetectMotion( *snap_image, zoneSet );
Event::StringSet zoneSet;
unsigned int motion_score = last_motion_score;
bool alarm = false;
if ( !(image_count % (motion_frame_skip+1) ) )
{
// Get new score.
alarm = DetectMotion( *snap_image, zoneSet, motion_score );
last_motion_score = motion_score;
}
//int motion_score = DetectBlack( *snap_image, zoneSet );
if ( alarm )
{
if ( motion_score )
{
score += motion_score;
if ( !event )
{
if ( cause.length() )
cause += ", ";
cause += MOTION_CAUSE;
}
else
{
event->AddCause( MOTION_CAUSE );
}
noteSetMap[MOTION_CAUSE] = zoneSet;
}
}
}
//int motion_score = DetectBlack( *snap_image, zoneSet );
if ( motion_score )
else
{
if ( !event )
for ( int n_zone = 0; n_zone < n_zones; n_zone++ )
{
score += motion_score;
if ( cause.length() )
cause += ", ";
cause += MOTION_CAUSE;
zones[n_zone]->ResetStats();
}
else
{
score += motion_score;
}
noteSetMap[MOTION_CAUSE] = zoneSet;
}
#if ZM_PLUGINS_ON
if (config.load_plugins)
{
std::string det_cause; // detection cause to fill in plugin's detectors
unsigned int plugin_score = 0;
if ( ThePluginManager.getImageAnalyser().DoDetection( *snap_image, zones, noteSetMap, det_cause, plugin_score ) )
{
score += plugin_score;
if ( !event )
{
if ( det_cause.length() )
{
if ( cause.length() )
cause += ", ";
cause += det_cause;
}
}
else
event->AddCause( det_cause );
}
}
#endif // ZM_PLUGINS_ON
shared_data->active = signal;
}
if ( (!signal_change && signal) && n_linked_monitors > 0 )
@ -1358,6 +1478,8 @@ bool Monitor::Analyse()
first_link = false;
}
}
else
event->AddCause( LINKED_CAUSE );
noteSet.insert( linked_monitors[i]->Name() );
score += 50;
}
@ -1457,7 +1579,6 @@ bool Monitor::Analyse()
pre_index = (pre_index+1)%image_buffer_count;
pre_event_images--;
}
event = new Event( this, *(image_buffer[pre_index].timestamp), cause, noteSetMap );
shared_data->last_event = event->Id();
@ -1625,10 +1746,11 @@ bool Monitor::Analyse()
}
if ( (!signal_change && signal) && (function == MODECT || function == MOCORD) )
{
if ( state == ALARM ) {
ref_image.Blend( *snap_image, alarm_ref_blend_perc );
} else {
ref_image.Blend( *snap_image, ref_blend_perc );
int ref_blend = ( state == ALARM ) ? alarm_ref_blend_perc : ref_blend_perc;
for ( int n_zone = 0; n_zone < n_zones; n_zone++ )
{
Debug( 4, "Blend reference image of zone %s", zones[n_zone]->Label() );
zones[n_zone]->BlendRefImage( *snap_image, ref_blend );
}
}
last_signal = signal;
@ -1652,7 +1774,7 @@ void Monitor::Reload()
closeEvent();
static char sql[ZM_SQL_MED_BUFSIZ];
snprintf( sql, sizeof(sql), "select Function+0, Enabled, LinkedMonitors, EventPrefix, LabelFormat, LabelX, LabelY, WarmupCount, PreEventCount, PostEventCount, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Id = '%d'", id );
snprintf( sql, sizeof(sql), "select Function+0, Enabled, LinkedMonitors, EventPrefix, LabelFormat, LabelX, LabelY, WarmupCount, PreEventCount, PostEventCount, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, DoNativeMotDet, SignalCheckColour from Monitors where Id = '%d'", id );
if ( mysql_query( &dbconn, sql ) )
{
@ -1695,7 +1817,8 @@ void Monitor::Reload()
ref_blend_perc = atoi(dbrow[index++]);
alarm_ref_blend_perc = atoi(dbrow[index++]);
track_motion = atoi(dbrow[index++]);
iDoNativeMotDet = atoi(dbrow[index++]);
if ( dbrow[index][0] == '#' )
signal_check_colour = strtol(dbrow[index]+1,0,16);
@ -1844,11 +1967,11 @@ int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose
static char sql[ZM_SQL_MED_BUFSIZ];
if ( !device[0] )
{
strncpy( sql, "select Id, Name, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Function != 'None' and Type = 'Local' order by Device, Channel", sizeof(sql) );
strncpy( sql, "select Id, Name, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, DoNativeMotDet, SignalCheckColour from Monitors where Function != 'None' and Type = 'Local' order by Device, Channel", sizeof(sql) );
}
else
{
snprintf( sql, sizeof(sql), "select Id, Name, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Function != 'None' and Type = 'Local' and Device = '%s' order by Channel", device );
snprintf( sql, sizeof(sql), "select Id, Name, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, DoNativeMotDet, SignalCheckColour from Monitors where Function != 'None' and Type = 'Local' and Device = '%s' order by Channel", device );
}
if ( mysql_query( &dbconn, sql ) )
{
@ -1934,6 +2057,8 @@ Debug( 1, "Got %d for v4l_captures_per_frame", v4l_captures_per_frame );
int alarm_ref_blend_perc = atoi(dbrow[col]); col++;
int track_motion = atoi(dbrow[col]); col++;
int doNativeMotDet = atoi(dbrow[col]); col++;
int signal_check_colour;
if ( dbrow[col][0] == '#' )
signal_check_colour = strtol(dbrow[col]+1,0,16);
@ -1996,7 +2121,8 @@ Debug( 1, "Got %d for v4l_captures_per_frame", v4l_captures_per_frame );
signal_check_colour,
purpose,
0,
0
0,
doNativeMotDet
);
Zone **zones = 0;
int n_zones = Zone::Load( monitors[i], zones );
@ -2020,11 +2146,11 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c
static char sql[ZM_SQL_MED_BUFSIZ];
if ( !protocol )
{
strncpy( sql, "select Id, Name, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion from Monitors where Function != 'None' and Type = 'Remote'", sizeof(sql) );
strncpy( sql, "select Id, Name, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, DoNativeMotDet from Monitors where Function != 'None' and Type = 'Remote'", sizeof(sql) );
}
else
{
snprintf( sql, sizeof(sql), "select Id, Name, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion from Monitors where Function != 'None' and Type = 'Remote' and Protocol = '%s' and Host = '%s' and Port = '%s' and Path = '%s'", protocol, host, port, path );
snprintf( sql, sizeof(sql), "select Id, Name, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, DoNativeMotDet from Monitors where Function != 'None' and Type = 'Remote' and Protocol = '%s' and Host = '%s' and Port = '%s' and Path = '%s'", protocol, host, port, path );
}
if ( mysql_query( &dbconn, sql ) )
{
@ -2091,6 +2217,7 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c
int alarm_ref_blend_perc = atoi(dbrow[col]); col++;
int track_motion = atoi(dbrow[col]); col++;
int doNativeMotDet = atoi(dbrow[col]); col++;
int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width);
int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height);
@ -2169,8 +2296,8 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c
RGB_WHITE,
purpose,
0,
0
0,
doNativeMotDet
);
Zone **zones = 0;
int n_zones = Zone::Load( monitors[i], zones );
@ -2193,11 +2320,11 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu
static char sql[ZM_SQL_MED_BUFSIZ];
if ( !file[0] )
{
strncpy( sql, "select Id, Name, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion from Monitors where Function != 'None' and Type = 'File'", sizeof(sql) );
strncpy( sql, "select Id, Name, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, DoNativeMotDet from Monitors where Function != 'None' and Type = 'File'", sizeof(sql) );
}
else
{
snprintf( sql, sizeof(sql), "select Id, Name, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion from Monitors where Function != 'None' and Type = 'File' and Path = '%s'", file );
snprintf( sql, sizeof(sql), "select Id, Name, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, DoNativeMotDet from Monitors where Function != 'None' and Type = 'File' and Path = '%s'", file );
}
if ( mysql_query( &dbconn, sql ) )
{
@ -2260,6 +2387,8 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu
int alarm_ref_blend_perc = atoi(dbrow[col]); col++;
int track_motion = atoi(dbrow[col]); col++;
int doNativeMotDet = atoi(dbrow[col]); col++;
int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width);
int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height);
@ -2306,7 +2435,8 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu
RGB_WHITE,
purpose,
0,
0
0,
doNativeMotDet
);
Zone **zones = 0;
int n_zones = Zone::Load( monitors[i], zones );
@ -2330,11 +2460,11 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose
static char sql[ZM_SQL_MED_BUFSIZ];
if ( !file[0] )
{
strncpy( sql, "select Id, Name, Function+0, Enabled, LinkedMonitors, Path, Method, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion from Monitors where Function != 'None' and Type = 'Ffmpeg'", sizeof(sql) );
strncpy( sql, "select Id, Name, Function+0, Enabled, LinkedMonitors, Path, Method, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, DoNativeMotDet from Monitors where Function != 'None' and Type = 'Ffmpeg'", sizeof(sql) );
}
else
{
snprintf( sql, sizeof(sql), "select Id, Name, Function+0, Enabled, LinkedMonitors, Path, Method, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion from Monitors where Function != 'None' and Type = 'Ffmpeg' and Path = '%s'", file );
snprintf( sql, sizeof(sql), "select Id, Name, Function+0, Enabled, LinkedMonitors, Path, Method, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, DoNativeMotDet from Monitors where Function != 'None' and Type = 'Ffmpeg' and Path = '%s'", file );
}
if ( mysql_query( &dbconn, sql ) )
{
@ -2399,6 +2529,8 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose
int alarm_ref_blend_perc = atoi(dbrow[col]); col++;
int track_motion = atoi(dbrow[col]); col++;
int doNativeMotDet = atoi(dbrow[col]); col++;
int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width);
int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height);
@ -2447,7 +2579,8 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose
RGB_WHITE,
purpose,
0,
0
0,
doNativeMotDet
);
Zone **zones = 0;
int n_zones = Zone::Load( monitors[i], zones );
@ -2469,7 +2602,7 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose
Monitor *Monitor::Load( int id, bool load_zones, Purpose purpose )
{
static char sql[ZM_SQL_MED_BUFSIZ];
snprintf( sql, sizeof(sql), "select Id, Name, Type, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Protocol, Method, Host, Port, Path, Options, User, Pass, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Id = %d", id );
snprintf( sql, sizeof(sql), "select Id, Name, Type, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Protocol, Method, Host, Port, Path, Options, User, Pass, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, DoNativeMotDet, SignalCheckColour from Monitors where Id = %d", id );
if ( mysql_query( &dbconn, sql ) )
{
Error( "Can't run query: %s", mysql_error( &dbconn ) );
@ -2563,6 +2696,8 @@ Debug( 1, "Got %d for v4l_captures_per_frame", v4l_captures_per_frame );
int alarm_ref_blend_perc = atoi(dbrow[col]); col++;
int track_motion = atoi(dbrow[col]); col++;
int doNativeMotDet = atoi(dbrow[col]); col++;
int signal_check_colour;
if ( dbrow[col][0] == '#' )
signal_check_colour = strtol(dbrow[col]+1,0,16);
@ -2760,8 +2895,8 @@ Debug( 1, "Got %d for v4l_captures_per_frame", v4l_captures_per_frame );
signal_check_colour,
purpose,
0,
0
0,
doNativeMotDet
);
int n_zones = 0;
@ -3174,33 +3309,32 @@ unsigned int Monitor::DetectBlack(const Image &comp_image, Event::StringSet &zon
unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &zoneSet )
unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &zoneSet, unsigned int &score )
{
bool alarm = false;
unsigned int score = 0;
score = 0;
if ( n_zones <= 0 ) return( alarm );
if ( config.record_diag_images )
for ( int n_zone = 0; n_zone < n_zones; n_zone++ )
{
static char diag_path[PATH_MAX] = "";
if ( !diag_path[0] )
Zone *zone = zones[n_zone];
if ( config.record_diag_images )
{
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-r.jpg", config.dir_events, id );
static char diag_path[PATH_MAX] = "";
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-r.jpg", config.dir_events, id, zone->Id() );
zone->WriteRefImage( diag_path );
}
ref_image.WriteJpeg( diag_path );
}
ref_image.Delta( comp_image, &delta_image);
Debug( 4, "Set delta image of zone %s", zone->Label() );
zone->SetDeltaImage( comp_image );
if ( config.record_diag_images )
{
static char diag_path[PATH_MAX] = "";
if ( !diag_path[0] )
if ( config.record_diag_images )
{
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-d.jpg", config.dir_events, id );
static char diag_path[PATH_MAX] = "";
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-d.jpg", config.dir_events, id, zone->Id() );
zone->WriteDeltaImage( diag_path );
}
delta_image.WriteJpeg( diag_path );
}
// Blank out all exclusion zones
@ -3215,7 +3349,7 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z
continue;
}
Debug( 3, "Blanking inactive zone %s", zone->Label() );
delta_image.Fill( RGB_BLACK, zone->GetPolygon() );
zone->FillDeltaImage( RGB_BLACK );
}
// Check preclusive zones first
@ -3229,13 +3363,16 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z
int old_zone_score = zone->Score();
bool old_zone_alarmed = zone->Alarmed();
Debug( 3, "Checking preclusive zone %s - old score: %d, state: %s", zone->Label(),old_zone_score, zone->Alarmed()?"alarmed":"quiet" );
if ( zone->CheckAlarms( &delta_image ) )
if ( zone->CheckAlarms( &comp_image ) )
{
alarm = true;
score += zone->Score();
zone->SetAlarm();
Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() );
zoneSet.insert( zone->Label() );
if ( !zone->IsPostProcEnabled() )
{
zone->SetAlarm();
Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() );
zoneSet.insert( ("[Zone " + std::string(zone->Label()) + "]\n").c_str() );
}
//zone->ResetStats();
} else {
// check if end of alarm
@ -3273,24 +3410,26 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z
continue;
}
Debug( 3, "Checking active zone %s", zone->Label() );
if ( zone->CheckAlarms( &delta_image ) )
if ( zone->CheckAlarms( &comp_image ) )
{
alarm = true;
score += zone->Score();
zone->SetAlarm();
Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() );
zoneSet.insert( zone->Label() );
if ( config.opt_control && track_motion )
score += zone->Score();
if ( !zone->IsPostProcEnabled() )
{
if ( (int)zone->Score() > top_score )
Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() );
zoneSet.insert( ("[Zone " + std::string(zone->Label()) + "]\n").c_str() );
if ( config.opt_control && track_motion )
{
top_score = zone->Score();
alarm_centre = zone->GetAlarmCentre();
if ( (int)zone->Score() > top_score )
{
top_score = zone->Score();
alarm_centre = zone->GetAlarmCentre();
}
}
}
}
}
if ( alarm )
{
for ( int n_zone = 0; n_zone < n_zones; n_zone++ )
@ -3301,19 +3440,22 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z
continue;
}
Debug( 3, "Checking inclusive zone %s", zone->Label() );
if ( zone->CheckAlarms( &delta_image ) )
if ( zone->CheckAlarms( &comp_image ) )
{
alarm = true;
score += zone->Score();
zone->SetAlarm();
Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() );
zoneSet.insert( zone->Label() );
if ( config.opt_control && track_motion )
score += zone->Score();
if ( !zone->IsPostProcEnabled() )
{
if ( zone->Score() > (unsigned int)top_score )
Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() );
zoneSet.insert( ("[Zone " + std::string(zone->Label()) + "]\n").c_str() );
if ( config.opt_control && track_motion )
{
top_score = zone->Score();
alarm_centre = zone->GetAlarmCentre();
if ( zone->Score() > (unsigned int)top_score )
{
top_score = zone->Score();
alarm_centre = zone->GetAlarmCentre();
}
}
}
}
@ -3330,13 +3472,16 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z
continue;
}
Debug( 3, "Checking exclusive zone %s", zone->Label() );
if ( zone->CheckAlarms( &delta_image ) )
if ( zone->CheckAlarms( &comp_image ) )
{
alarm = true;
score += zone->Score();
zone->SetAlarm();
Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() );
zoneSet.insert( zone->Label() );
score += zone->Score();
if ( !zone->IsPostProcEnabled() )
{
Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() );
zoneSet.insert( ("[Zone " + std::string(zone->Label()) + "]\n").c_str() );
}
}
}
}
@ -3354,9 +3499,8 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z
shared_data->alarm_x = shared_data->alarm_y = -1;
}
// This is a small and innocent hack to prevent scores of 0 being returned in alarm state
return( score?score:alarm );
}
return alarm;
}
bool Monitor::DumpSettings( char *output, bool verbose )
{
@ -4286,3 +4430,36 @@ void Monitor::SingleImageZip( int scale)
fprintf( stdout, "Content-Type: image/x-rgbz\r\n\r\n" );
fwrite( img_buffer, img_buffer_size, 1, stdout );
}
#if ZM_PLUGINS_ON
void Monitor::DumpPluginStatus()
{
map<string,pGenConf> mapPluginGenConf;
unsigned int nNumPlugins = ThePluginManager.getPluginsGenConf(mapPluginGenConf);
bool bDoNativeDet = !config.turnoff_native_analysis && iDoNativeMotDet;
if ( nNumPlugins == 0)
{
printf("No plugin found\n");
return;
}
printf("%79sNATIVE DETECTION\n", " ");
printf("PLUGIN NAME%*sREGISTERED CONFIGURED ZONE ENABLED ACTIVE REQUIRE INCLUDE REINIT\n", 19, " ");
for (map<string,pGenConf>::iterator it = mapPluginGenConf.begin() ; it != mapPluginGenConf.end(); ++it)
{
PluginZoneConf mapPluginZoneConf;
ThePluginManager.getPluginZoneConf( it->first, mapPluginZoneConf );
int padLen = 34 - it->first.length();
if(padLen < 0) padLen = 0;
printf("%s%*s%d%*s%d%*s", it->first.c_str(), padLen, " ", it->second.Registered, 10, " ", it->second.Configured, 8, " ");
for (PluginZoneConf::iterator it2 = mapPluginZoneConf.begin() ; it2 != mapPluginZoneConf.end(); ++it2)
{
if (it2 != mapPluginZoneConf.begin())
printf("%*s", 54, " ");
bool bIsActive = it2->second.Enabled && ( !it2->second.RequireNatDet || ( it2->second.RequireNatDet && bDoNativeDet ) );
printf("%d%*s%d%*s%d%*s%d%*s%d%*s%d\n", it2->first, 7, " ", it2->second.Enabled, 7, " ", bIsActive, 8, " ", it2->second.RequireNatDet, 7, " ", it2->second.IncludeNatDet, 6, " ", it2->second.ReInitNatDet);
}
}
ThePluginManager.getImageAnalyser().cleanupPlugins();
}
#endif // ZM_PLUGINS_ON

View File

@ -32,7 +32,10 @@
#include "zm_camera.h"
#include "zm_utils.h"
#if ZM_PLUGINS_ON
#include "zm_plugin_manager.h"
#include "zm_image_analyser.h"
#endif
#include <sys/time.h>
#include <stdint.h>
@ -41,6 +44,9 @@
#define MOTION_CAUSE "Motion"
#define LINKED_CAUSE "Linked"
int conf_select(const struct direct *entry);
//
// This is the main class for monitors. Each monitor is associated
// with a camera and is effectively a collector for events.
@ -244,8 +250,6 @@ protected:
Rgb signal_check_colour; // The colour that the camera will emit when no video signal detected
double fps;
Image delta_image;
Image ref_image;
Purpose purpose; // What this monitor has been created to do
int event_count;
@ -289,14 +293,18 @@ protected:
Image **images;
int iDoNativeMotDet;
#if ZM_PLUGINS_ON
PluginManager ThePluginManager;
#else
int ThePluginManager;
#endif
int n_linked_monitors;
MonitorLink **linked_monitors;
public:
// OurCheckAlarms seems to be unused. Check it on zm_monitor.cpp for more info.
//bool OurCheckAlarms( Zone *zone, const Image *pImage );
Monitor( int p_id, const char *p_name, int p_function, bool p_enabled, const char *p_linked_monitors, Camera *p_camera, int p_orientation, unsigned int p_deinterlacing, const char *p_event_prefix, const char *p_label_format, const Coord &p_label_coord, int p_image_buffer_count, int p_warmup_count, int p_pre_event_count, int p_post_event_count, int p_stream_replay_buffer, int p_alarm_frame_count, int p_section_length, int p_frame_skip, int p_motion_frame_skip, int p_capture_delay, int p_alarm_capture_delay, int p_fps_report_interval, int p_ref_blend_perc, int p_alarm_ref_blend_perc, bool p_track_motion, Rgb p_signal_check_colour, Purpose p_purpose, int p_n_zones=0, Zone *p_zones[]=0 );
Monitor( int p_id, const char *p_name, int p_function, bool p_enabled, const char *p_linked_monitors, Camera *p_camera, int p_orientation, unsigned int p_deinterlacing, const char *p_event_prefix, const char *p_label_format, const Coord &p_label_coord, int p_image_buffer_count, int p_warmup_count, int p_pre_event_count, int p_post_event_count, int p_stream_replay_buffer, int p_alarm_frame_count, int p_section_length, int p_frame_skip, int p_motion_frame_skip, int p_capture_delay, int p_alarm_capture_delay, int p_fps_report_interval, int p_ref_blend_perc, int p_alarm_ref_blend_perc, bool p_track_motion, Rgb p_signal_check_colour, Purpose p_purpose, int p_n_zones=0, Zone *p_zones[]=0, int p_DoNativeMotDet=1 );
~Monitor();
void AddZones( int p_n_zones, Zone *p_zones[] );
@ -388,6 +396,7 @@ public:
}
unsigned int DetectMotion( const Image &comp_image, Event::StringSet &zoneSet );
unsigned int DetectMotion( const Image &comp_image, Event::StringSet &zoneSet, unsigned int &score );
// DetectBlack seems to be unused. Check it on zm_monitor.cpp for more info.
//unsigned int DetectBlack( const Image &comp_image, Event::StringSet &zoneSet );
bool CheckSignal( const Image *image );
@ -403,6 +412,8 @@ public:
bool DumpSettings( char *output, bool verbose );
void DumpZoneImage( const char *zone_string=0 );
void DumpPluginStatus();
#if ZM_HAS_V4L
static int LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose purpose );
#endif // ZM_HAS_V4L

105
src/zm_plugin.cpp Normal file
View File

@ -0,0 +1,105 @@
#include "zm_plugin.h"
/*!\fn Plugin::Plugin(const std::string &sFilename)
* \param sFilename is the name of plugin file to load
*/
Plugin::Plugin(const std::string &sFilename)
: m_sPluginFileName(sFilename),
m_hDLL(0),
m_pDLLRefCount(0),
m_pfnGetEngineVersion(0),
m_pfnRegisterPlugin(0)
{
// Try to load the plugin as a dynamic library
m_hDLL = dlopen(sFilename.c_str(), RTLD_LAZY|RTLD_GLOBAL);
if(!m_hDLL) // if library hasn't been loaded successfully
{
throw runtime_error("Could not load '" + sFilename + "' (" + dlerror() + ")");
}
// Locate the plugin's exported functions
try
{
m_pfnGetEngineVersion = reinterpret_cast<fnGetEngineVersion *>(dlsym(m_hDLL, "getEngineVersion"));
m_pfnRegisterPlugin = reinterpret_cast<fnRegisterPlugin *>(dlsym(m_hDLL, "registerPlugin"));
// If the functions aren't found, we're going to assume this is
// a plain simple DLL and not one of our plugins
if(!m_pfnGetEngineVersion || ! m_pfnRegisterPlugin)
throw runtime_error("'" + sFilename + "' is not a valid plugin");
// Initialize a new DLL reference counter
m_pDLLRefCount = new size_t(1);
}
catch(runtime_error &ex)
{
dlclose(m_hDLL);
throw ex;
}
catch(...)
{
dlclose(m_hDLL);
throw runtime_error("Unknown exception while loading plugin '" + sFilename + "'");
}
}
/*!\fn Plugin::Plugin(const Plugin &Other)
* \param Other is the other plugin instance to copy
*/
Plugin::Plugin(const Plugin &Other)
: m_sPluginFileName(Other.m_sPluginFileName),
m_hDLL(Other.m_hDLL),
m_pDLLRefCount(Other.m_pDLLRefCount),
m_pfnGetEngineVersion(Other.m_pfnGetEngineVersion),
m_pfnRegisterPlugin(Other.m_pfnRegisterPlugin)
{
// Increase DLL reference counter
++*m_pDLLRefCount;
}
/*!\fn Plugin::operator=(const Plugin &Other)
* \param Other is the other plugin instance to copy
* return copy of object
*/
Plugin& Plugin::operator=(const Plugin &Other)
{
m_hDLL = Other.m_hDLL;
m_pfnGetEngineVersion = Other.m_pfnGetEngineVersion;
m_pfnRegisterPlugin = Other.m_pfnRegisterPlugin;
m_pDLLRefCount = Other.m_pDLLRefCount;
m_sPluginFileName = Other.m_sPluginFileName;
// Increase DLL reference counter
++*m_pDLLRefCount;
return *this;
}
Plugin::~Plugin()
{
// Only unload the DLL if there are no more references to it
if(!--*m_pDLLRefCount)
{
delete m_pDLLRefCount;
dlclose(m_hDLL);
}
}
/*!\fn Plugin::registerPlugin(PluginManager &K)
* \param K is the pointer to plugin manager
*/
void Plugin::registerPlugin(PluginManager &K)
{
m_pfnRegisterPlugin(K, m_sPluginFileName);
}

77
src/zm_plugin.h Normal file
View File

@ -0,0 +1,77 @@
#ifndef ZM_PLUGIN_H
#define ZM_PLUGIN_H
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
#include <stdexcept>
using namespace std;
class PluginManager;
//! Signature for the version query function
typedef int fnGetEngineVersion();
//! Signature for the plugin's registration function
typedef void fnRegisterPlugin(PluginManager &, string);
//! Representation of a plugin.
/*! Use for loading plugin's shared library
* and registration of it to the PluginManager.
*/
class Plugin
{
public:
//! Initialize and load plugin
Plugin(const std::string &sFilename);
//! Copy existing plugin instance
Plugin(const Plugin &Other);
//! Operator =.
Plugin &operator =(const Plugin &Other);
//! Unload a plugin
~Plugin();
//! Query the plugin for its expected engine version
int getEngineVersion() const { return m_pfnGetEngineVersion();}
//! Register the plugin to a PluginManager
void registerPlugin(PluginManager &K);
private:
//! Shared file name.
string m_sPluginFileName;
//! DLL handle
void* m_hDLL;
//! Number of references to the DLL
size_t *m_pDLLRefCount;
//! Version query function
fnGetEngineVersion *m_pfnGetEngineVersion;
//! Plugin registration function
fnRegisterPlugin *m_pfnRegisterPlugin;
};
#endif //ZM_PLUGIN_H

160
src/zm_plugin_manager.cpp Normal file
View File

@ -0,0 +1,160 @@
#include "zm_plugin_manager.h"
/*! \fn file_select(const struct direct *entry)
* A functor for selection of files with specified extension.
* \param entry is file structure
* \return 1 if file match selection criteria and
* 0 otherwise.
* NOTE: file extension is specified by PluginManager::m_sPluginExt
* static variable.
*/
int file_select(const struct direct *entry)
{
char *ptr;
if ((strcmp(entry->d_name, ".")== 0) || (strcmp(entry->d_name, "..") == 0))
return 0;
// Check for filename extensions.
ptr = rindex((char*)entry->d_name, '.');
if ((ptr != NULL) && (strcmp(ptr, (PluginManager::m_sPluginExt).c_str()) == 0))
return 1;
else
return 0;
}
/*! \fn join_paths(const string& p1, const string& p2)
* \param p1 is the first part of desired path
* \param p2 is the second part of desired path
* \return joined path string.
*/
string join_paths(const string& p1, const string& p2)
{
char sep = '/';
string tmp = p1;
#ifdef _WIN32
sep = '\\';
#endif
if (p1[p1.length()] != sep)
{ // Need to add a path separator
tmp += sep;
return(tmp + p2);
}
else
return(p1 + p2);
}
string PluginManager::m_sPluginExt = DEFAULT_PLUGIN_EXT;
PluginManager::PluginManager() {}
PluginManager::PluginManager(
int nMonitorId
) :
m_ImageAnalyser( nMonitorId )
{}
/*!\fn PluginManager::loadPlugin(const string &sFilename))
* \param sFilename is the name of plugin file to load
*/
bool PluginManager::loadPlugin(const string &sFilename)
{
try
{
if(m_LoadedPlugins.find(sFilename) == m_LoadedPlugins.end())
m_LoadedPlugins.insert(PluginMap::value_type(sFilename, Plugin(sFilename))).first->second.registerPlugin(*this);
}
catch(runtime_error &ex)
{
Error("Runtime error: %s", ex.what());
return false;
}
catch(...)
{
Error("Unknown exception. Could not load %s.", sFilename.c_str());
return false;
}
return true;
}
/*!\fn PluginManager::findPlugins(const string &sPath, bool loadPlugins)
* \param sPath is the path to folder to search plugins
* \param loadPlugins is a flag to allow loading of plugins
* \param nNumPlugLoaded is the number of loaded plugins
* \return the number of found plugins
*/
int PluginManager::findPlugins(const string sPath, bool loadPlugins, unsigned int& nNumPlugLoaded)
{
struct direct **files;
int count = scandir(sPath.c_str(), &files, file_select, alphasort);
if(count <= 0) count = 0;
for (int i = 0; i < count; ++i)
{
string sFileName = string(files[i]->d_name);
string sFullPath = join_paths(sPath, sFileName);
size_t idx = sFileName.rfind('.');
if (idx != string::npos)
sFileName = sFileName.substr(0, idx);
bool IsPluginRegistered = false;
if(config.load_plugins || loadPlugins)
{
Info("Loading plugin %s ... ", sFullPath.c_str());
IsPluginRegistered = loadPlugin(sFullPath);
}
mapPluginReg.insert( pair<string,bool>(sFileName, IsPluginRegistered) );
if (IsPluginRegistered) nNumPlugLoaded++;
}
return count;
}
/*!\fn PluginManager::configurePlugins(string sConfigFileName)
* \param sConfigFileName is the path to the configuration file, where parameters for all plugins are given.
* \param bDoNativeDet is true if native detection will be performed
*/
void PluginManager::configurePlugins(string sConfigFileName, bool bDoNativeDet)
{
m_ImageAnalyser.configurePlugins(sConfigFileName, bDoNativeDet);
}
/*!\fn PluginManager::getPluginsGenConf(map<string,pGenConf>& mapPluginGenConf)
* \param mapPluginGenConf is the map of general settings for the plugins
* \param mapPluginZoneConf is the map of zone settings for the plugins
* \return the number of found plugins
*/
unsigned long PluginManager::getPluginsGenConf(map<string,pGenConf>& mapPluginGenConf)
{
for (map<string,bool>::iterator it = mapPluginReg.begin() ; it != mapPluginReg.end(); ++it)
{
pGenConf plugGenConf;
m_ImageAnalyser.getRegPluginGenConf( it->first, plugGenConf );
plugGenConf.Registered = it->second;
mapPluginGenConf.insert( pair<string,pGenConf>(it->first, plugGenConf) );
}
return mapPluginGenConf.size();
}
/*!\fn PluginManager::getPluginZoneConf(string sPluginName, PluginZoneConf& mapPluginZoneConf)
* \param mapPluginZoneConf is the map of zone settings for the plugin
*/
void PluginManager::getPluginZoneConf(string sPluginName, PluginZoneConf& mapPluginZoneConf)
{
m_ImageAnalyser.getRegPluginZoneConf( sPluginName, mapPluginZoneConf );
}

94
src/zm_plugin_manager.h Normal file
View File

@ -0,0 +1,94 @@
#ifndef ZM_PLUGIN_MANAGER_H
#define ZM_PLUGIN_MANAGER_H
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <fstream>
#include <map>
#include <sys/types.h>
#include <sys/dir.h>
#include <sys/param.h>
#include <unistd.h>
#include "zm_image_analyser.h"
#include "zm_detector.h"
#include "zm_plugin.h"
using namespace std;
#define ZM_ENGINE_VERSION 24
//! Map of plugins by their associated file names.
typedef std::map<std::string, Plugin> PluginMap;
//! External function for sorting of files in directory.
extern int alphasort();
//! Function to select files with plugins by extension.
int file_select(const struct direct *entry);
//! Join two path strings.
string join_paths(const string& p1, const string& p2);
//! Class for managing all loaded plugins.
class PluginManager
{
public:
//! Default constructor.
PluginManager();
//! Constructor with parameters
PluginManager(int nMonitorId);
//! Access the image analyser.
ImageAnalyser &getImageAnalyser() {return m_ImageAnalyser;}
//! Loads a plugin.
bool loadPlugin(const string &sFilename);
//! Find all plugins from given directory, load them if required and
//! return the number of found plugins and the number of loaded plugins
int findPlugins(const string sPath, bool loadPlugins, unsigned int& nNumPlugLoaded);
//! Get general settings of plugins
unsigned long getPluginsGenConf(map<string,pGenConf>& mapPluginGenConf);
//! Get zone settings of a plugin
void getPluginZoneConf(string sPluginName, PluginZoneConf& mapPluginZoneConf);
//! Configure all loaded plugins using given configuration file.
void configurePlugins(string sConfigFileName, bool bDoNativeDet);
//! Set plugin extension.
void setPluginExt(string sPluginExt) { m_sPluginExt = sPluginExt; }
//! Extension for zm plugins.
static string m_sPluginExt;
private:
//! All plugins currently loaded.
PluginMap m_LoadedPlugins;
//! The image analyser.
ImageAnalyser m_ImageAnalyser;
//! Plugin list
map<string,bool> mapPluginReg;
};
#endif //ZM_PLUGIN_MANAGER_H

View File

@ -60,10 +60,20 @@ void Zone::Setup( Monitor *p_monitor, int p_id, const char *p_label, ZoneType p_
max_blob_size = 0;
image = 0;
score = 0;
text = "";
post_proc_enabled = false;
post_proc_in_progress = false;
include_nat_det = true;
reinit_nat_det = false;
overload_count = 0;
extend_alarm_count = 0;
delta_image = Image( monitor->Width(), monitor->Height(), ZM_COLOUR_GRAY8, ZM_SUBPIX_ORDER_NONE );
ref_image = Image( monitor->Width(), monitor->Height(), monitor->Colours(), monitor->SubpixelOrder());
bl_image = Image( monitor->Width(), monitor->Height(), monitor->Colours(), monitor->SubpixelOrder());
bl_image.Fill( RGB_BLACK );
pg_image = new Image( monitor->Width(), monitor->Height(), 1, ZM_SUBPIX_ORDER_NONE);
pg_image->Clear();
pg_image->Fill( 0xff, polygon );
@ -91,14 +101,10 @@ void Zone::Setup( Monitor *p_monitor, int p_id, const char *p_label, ZoneType p_
}
}
}
if ( config.record_diag_images )
if ( config.record_diag_images && (id > 0))
{
static char diag_path[PATH_MAX] = "";
if ( !diag_path[0] )
{
snprintf( diag_path, sizeof(diag_path), "%s/%s/diag-%d-poly.jpg", config.dir_events, monitor->Name(), id);
}
snprintf( diag_path, sizeof(diag_path), "%s/%s/diag-%d-poly.jpg", config.dir_events, monitor->Name(), id);
pg_image->WriteJpeg( diag_path );
}
}
@ -142,6 +148,37 @@ void Zone::SetScore(unsigned int nScore)
score = nScore;
}
void Zone::SetText(std::string sText)
{
text = "[Zone ";
text += label;
text += "]\n" + sText;
}
void Zone::AssignRefImage( unsigned int p_width, unsigned int p_height, unsigned int p_colours, unsigned int p_subpixelorder, const uint8_t* new_buffer, const size_t buffer_size )
{
ref_image.Assign( p_width, p_height, p_colours, p_subpixelorder, new_buffer, buffer_size);
}
void Zone::SetRefImage(const Image &srcImage)
{
ref_image = srcImage;
}
void Zone::BlendRefImage( const Image &srcImage, int transparency )
{
ref_image.Blend( srcImage, transparency );
}
void Zone::SetDeltaImage( const Image &srcImage )
{
ref_image.Delta( srcImage, &delta_image );
}
void Zone::FillDeltaImage( Rgb colour )
{
delta_image.Fill( colour, polygon);
}
void Zone::SetAlarmImage(const Image* srcImage)
{
@ -149,6 +186,16 @@ void Zone::SetAlarmImage(const Image* srcImage)
image = new Image(*srcImage);
}
bool Zone::WriteRefImage( const char *filename, int quality_override ) const
{
return ref_image.WriteJpeg( filename, quality_override );
}
bool Zone::WriteDeltaImage( const char *filename, int quality_override ) const
{
return delta_image.WriteJpeg( filename, quality_override );
}
int Zone::GetOverloadCount()
{
return overload_count;
@ -194,9 +241,33 @@ bool Zone::CheckExtendAlarmCount()
//===========================================================================
void Zone::SetConfig( zConf zone_conf )
{
post_proc_enabled = zone_conf.RequireNatDet;
include_nat_det = zone_conf.IncludeNatDet;
reinit_nat_det = zone_conf.ReInitNatDet;
if ( post_proc_enabled ) {
std::string sMessage;
if ( include_nat_det ) {
sMessage = "(native detection included";
}
if ( reinit_nat_det ) {
if (sMessage.empty()) {
sMessage = "(native detection will be reinitialized";
} else {
sMessage += ", reinitialization is required";
}
}
if (!sMessage.empty()) {
sMessage += ")";
}
Info("Post processing enabled for zone '%s' %s", label, sMessage.c_str());
}
}
bool Zone::CheckAlarms( const Image *delta_image )
bool Zone::CheckAlarms( const Image *comp_image )
{
ResetStats();
@ -205,12 +276,19 @@ bool Zone::CheckAlarms( const Image *delta_image )
Info( "In overload mode, %d frames of %d remaining", overload_count, overload_frames );
Debug( 4, "In overload mode, %d frames of %d remaining", overload_count, overload_frames );
overload_count--;
post_proc_in_progress = false;
return( false );
}
if ( reinit_nat_det )
{
Debug( 4, "Update reference image of zone %s", label );
ref_image = *comp_image;
}
delete image;
// Get the difference image
Image *diff_image = image = new Image( *delta_image );
Image *diff_image = image = new Image( delta_image );
int diff_width = diff_image->Width();
uint8_t* diff_buff = (uint8_t*)diff_image->Buffer();
uint8_t* pdiff;
@ -245,10 +323,7 @@ bool Zone::CheckAlarms( const Image *delta_image )
if ( config.record_diag_images )
{
static char diag_path[PATH_MAX] = "";
if ( !diag_path[0] )
{
snprintf( diag_path, sizeof(diag_path), "%s/%s/diag-%d-%d.jpg", config.dir_events, monitor->Name(), id, 1 );
}
snprintf( diag_path, sizeof(diag_path), "%s/%s/diag-%d-%d.jpg", config.dir_events, monitor->Name(), id, 1 );
diff_image->WriteJpeg( diag_path );
}
@ -259,14 +334,17 @@ bool Zone::CheckAlarms( const Image *delta_image )
if( alarm_pixels ) {
if( min_alarm_pixels && (alarm_pixels < (unsigned int)min_alarm_pixels) ) {
/* Not enough pixels alarmed */
post_proc_in_progress = false;
return (false);
} else if( max_alarm_pixels && (alarm_pixels > (unsigned int)max_alarm_pixels) ) {
/* Too many pixels alarmed */
overload_count = overload_frames;
post_proc_in_progress = false;
return (false);
}
} else {
/* No alarmed pixels */
post_proc_in_progress = false;
return (false);
}
@ -342,10 +420,7 @@ bool Zone::CheckAlarms( const Image *delta_image )
if ( config.record_diag_images )
{
static char diag_path[PATH_MAX] = "";
if ( !diag_path[0] )
{
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-%d.jpg", config.dir_events, monitor->Id(), id, 2 );
}
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-%d.jpg", config.dir_events, monitor->Id(), id, 2 );
diff_image->WriteJpeg( diag_path );
}
@ -354,14 +429,17 @@ bool Zone::CheckAlarms( const Image *delta_image )
if( alarm_filter_pixels ) {
if( min_filter_pixels && (alarm_filter_pixels < min_filter_pixels) ) {
/* Not enough pixels alarmed */
post_proc_in_progress = false;
return (false);
} else if( max_filter_pixels && (alarm_filter_pixels > max_filter_pixels) ) {
/* Too many pixels alarmed */
overload_count = overload_frames;
post_proc_in_progress = false;
return (false);
}
} else {
/* No filtered pixels */
post_proc_in_progress = false;
return (false);
}
@ -583,15 +661,13 @@ bool Zone::CheckAlarms( const Image *delta_image )
if ( config.record_diag_images )
{
static char diag_path[PATH_MAX] = "";
if ( !diag_path[0] )
{
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-%d.jpg", config.dir_events, monitor->Id(), id, 3 );
}
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-%d.jpg", config.dir_events, monitor->Id(), id, 3 );
diff_image->WriteJpeg( diag_path );
}
if ( !alarm_blobs )
{
post_proc_in_progress = false;
return( false );
}
@ -642,10 +718,7 @@ bool Zone::CheckAlarms( const Image *delta_image )
if ( config.record_diag_images )
{
static char diag_path[PATH_MAX] = "";
if ( !diag_path[0] )
{
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-%d.jpg", config.dir_events, monitor->Id(), id, 4 );
}
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-%d.jpg", config.dir_events, monitor->Id(), id, 4 );
diff_image->WriteJpeg( diag_path );
}
Debug( 5, "Got %d blob pixels, %d blobs, need %d -> %d, %d -> %d", alarm_blob_pixels, alarm_blobs, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs );
@ -653,14 +726,17 @@ bool Zone::CheckAlarms( const Image *delta_image )
if( alarm_blobs ) {
if( min_blobs && (alarm_blobs < min_blobs) ) {
/* Not enough pixels alarmed */
post_proc_in_progress = false;
return (false);
} else if(max_blobs && (alarm_blobs > max_blobs) ) {
/* Too many pixels alarmed */
overload_count = overload_frames;
post_proc_in_progress = false;
return (false);
}
} else {
/* No blobs */
post_proc_in_progress = false;
return (false);
}
@ -797,13 +873,19 @@ bool Zone::CheckAlarms( const Image *delta_image )
}
}
}
if( monitor->Colours() == ZM_COLOUR_GRAY8 ) {
image = diff_image->HighlightEdges( alarm_rgb, ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB, &polygon.Extent() );
} else {
image = diff_image->HighlightEdges( alarm_rgb, monitor->Colours(), monitor->SubpixelOrder(), &polygon.Extent() );
if ( post_proc_enabled ) {
post_proc_in_progress = true;
}
if ( include_nat_det ) {
if( monitor->Colours() == ZM_COLOUR_GRAY8 ) {
image = diff_image->HighlightEdges( alarm_rgb, ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB, &polygon.Extent() );
} else {
image = diff_image->HighlightEdges( alarm_rgb, monitor->Colours(), monitor->SubpixelOrder(), &polygon.Extent() );
}
} else {
score = 0;
image = new Image( bl_image );
}
// Only need to delete this when 'image' becomes detached and points somewhere else
delete diff_image;
}

View File

@ -28,6 +28,19 @@
class Monitor;
//! A structure to store the post processing configuration for the zone
struct zConf
{
bool RequireNatDet;
bool IncludeNatDet;
bool ReInitNatDet;
zConf():
RequireNatDet(false),
IncludeNatDet(false),
ReInitNatDet(false)
{}
};
//
// This describes a 'zone', or an area of an image that has certain
// detection characteristics.
@ -87,12 +100,20 @@ protected:
Box alarm_box;
Coord alarm_centre;
unsigned int score;
std::string text;
Image *pg_image;
Range *ranges;
Image *image;
Image delta_image;
Image ref_image;
Image bl_image;
int overload_count;
int extend_alarm_count;
bool post_proc_enabled;
bool include_nat_det;
bool reinit_nat_det;
bool post_proc_in_progress;
protected:
void Setup( Monitor *p_monitor, int p_id, const char *p_label, ZoneType p_type, const Polygon &p_polygon, const Rgb p_alarm_rgb, CheckMethod p_check_method, int p_min_pixel_threshold, int p_max_pixel_threshold, int p_min_alarm_pixels, int p_max_alarm_pixels, const Coord &p_filter_box, int p_min_filter_pixels, int p_max_filter_pixels, int p_min_blob_pixels, int p_max_blob_pixels, int p_min_blobs, int p_max_blobs, int p_overload_frames, int p_extend_alarm_frames );
@ -130,7 +151,14 @@ public:
inline void ClearAlarm() { alarmed = false; }
inline Coord GetAlarmCentre() const { return( alarm_centre ); }
inline unsigned int Score() const { return( score ); }
inline std::string Text() const { return( text ); }
void SetConfig( zConf zone_conf );
inline bool IsPostProcEnabled() const { return post_proc_enabled; }
inline bool IsNatDetIncluded() const { return include_nat_det; }
inline bool IsNatDetReInitialized() const { return reinit_nat_det; }
inline void StartPostProcessing() { post_proc_in_progress = true; }
inline void StopPostProcessing() { post_proc_in_progress = false; }
inline bool IsPostProcInProgress() { return post_proc_in_progress; }
inline void ResetStats()
{
alarmed = false;
@ -142,9 +170,10 @@ public:
min_blob_size = 0;
max_blob_size = 0;
score = 0;
text = "";
}
void RecordStats( const Event *event );
bool CheckAlarms( const Image *delta_image );
bool CheckAlarms( const Image *comp_image );
bool DumpSettings( char *output, bool verbose );
static bool ParsePolygonString( const char *polygon_string, Polygon &polygon );
@ -161,7 +190,15 @@ public:
void SetExtendAlarmCount(int nOverCount);
int GetExtendAlarmFrames();
void SetScore(unsigned int nScore);
void SetText(std::string sText);
void SetAlarmImage(const Image* srcImage);
void AssignRefImage( unsigned int p_width, unsigned int p_height, unsigned int p_colours, unsigned int p_subpixelorder, const uint8_t* new_buffer, const size_t buffer_size );
void SetRefImage( const Image &srcImage);
void BlendRefImage( const Image &srcImage, int transparency=12 );
void SetDeltaImage( const Image &srcImage );
void FillDeltaImage( Rgb colour );
bool WriteRefImage( const char *filename, int quality_override=0 ) const;
bool WriteDeltaImage( const char *filename, int quality_override=0 ) const;
inline const Image *getPgImage() const { return( pg_image ); }
inline const Range *getRanges() const { return( ranges ); }

View File

@ -68,7 +68,9 @@ void Usage( int status=-1 )
fprintf( stderr, " -U, --username <username> : When running in authenticated mode the username and\n" );
fprintf( stderr, " -P, --password <password> : password combination of the given user\n" );
fprintf( stderr, " -A, --auth <authentication> : Pass authentication hash string instead of user details\n" );
#if ZM_PLUGINS_ON
fprintf( stderr, " -p, --plugin-status : Display the status of detected plugins\n" );
#endif // ZM_PLUGINS_ON
exit( status );
}
@ -96,6 +98,7 @@ typedef enum {
ZMU_SUSPEND = 0x00400000,
ZMU_RESUME = 0x00800000,
ZMU_LIST = 0x10000000,
ZMU_LIST_PLUG = 0x20000000
} Function;
bool ValidateAccess( User *user, int mon_id, int function )
@ -111,7 +114,7 @@ bool ValidateAccess( User *user, int mon_id, int function )
if ( user->getEvents() < User::PERM_VIEW )
allowed = false;
}
if ( function & (ZMU_ZONES|ZMU_QUERY|ZMU_LIST) )
if ( function & (ZMU_ZONES|ZMU_QUERY|ZMU_LIST|ZMU_LIST_PLUG) )
{
if ( user->getMonitors() < User::PERM_VIEW )
allowed = false;
@ -180,6 +183,9 @@ int main( int argc, char *argv[] )
{"version", 1, 0, 'V'},
{"help", 0, 0, 'h'},
{"list", 0, 0, 'l'},
#if ZM_PLUGINS_ON
{"list_plugins", 0, 0, 'p'},
#endif // ZM_PLUGINS_ON
{0, 0, 0, 0}
};
@ -209,7 +215,7 @@ int main( int argc, char *argv[] )
{
int option_index = 0;
int c = getopt_long (argc, argv, "d:m:vsEDLurwei::S:t::fz::ancqhlB::C::H::O::U:P:A:V:", long_options, &option_index);
int c = getopt_long (argc, argv, "d:m:vsEDLurwei::S:t::fz::ancqhlpB::C::H::O::U:P:A:V:", long_options, &option_index);
if (c == -1)
{
break;
@ -327,6 +333,11 @@ int main( int argc, char *argv[] )
case 'l':
function |= ZMU_LIST;
break;
#if ZM_PLUGINS_ON
case 'p':
function |= ZMU_LIST_PLUG;
break;
#endif // ZM_PLUGINS_ON
case '?':
Usage();
break;
@ -415,7 +426,7 @@ int main( int argc, char *argv[] )
if ( mon_id > 0 )
{
Monitor *monitor = Monitor::Load( mon_id, function&(ZMU_QUERY|ZMU_ZONES), Monitor::QUERY );
Monitor *monitor = Monitor::Load( mon_id, function&(ZMU_QUERY|ZMU_ZONES|ZMU_LIST_PLUG), Monitor::QUERY );
if ( monitor )
{
if ( verbose )
@ -655,6 +666,12 @@ int main( int argc, char *argv[] )
have_output = true;
}
}
#if ZM_PLUGINS_ON
if ( function & ZMU_LIST_PLUG )
{
monitor->DumpPluginStatus();
}
#endif // ZM_PLUGINS_ON
if ( have_output )
{
printf( "\n" );

View File

@ -372,11 +372,14 @@ if ( !empty($action) )
$changes=0;
foreach( $pconfs as $pconf )
{
$value=$_REQUEST['pluginOpt'][$pconf['Name']];
if(array_key_exists($pconf['Name'], $_REQUEST['pluginOpt']) && ($pconf['Value']!=$value))
if(isset($_REQUEST['pluginOpt'][$pconf['Name']]))
{
dbQuery("UPDATE PluginsConfig SET Value=? WHERE id=?", array( $value, $pconf['Id'] ) );
$changes++;
$value=$_REQUEST['pluginOpt'][$pconf['Name']];
if(array_key_exists($pconf['Name'], $_REQUEST['pluginOpt']) && ($pconf['Value']!=$value))
{
dbQuery("UPDATE PluginsConfig SET Value=? WHERE id=?", array( $value, $pconf['Id'] ) );
$changes++;
}
}
}
if($changes>0)
@ -409,6 +412,7 @@ if ( !empty($action) )
foreach( $_REQUEST['markZids'] as $markZid )
{
dbQuery( "delete from Zones WHERE MonitorId=? AND Id=?", array( $mid, $markZid) );
dbQuery( "delete from PluginsConfig WHERE MonitorId=? AND ZoneId=?", array( $mid, $markZid) );
$deletedZid = 1;
}
if ( $deletedZid )
@ -593,6 +597,7 @@ if ( !empty($action) )
// This is the important stuff
dbQuery( "delete from Monitors where Id = ?", array($markMid) );
dbQuery( "delete from Zones where MonitorId = ?", array($markMid) );
dbQuery( "delete from PluginsConfig where MonitorId = ?", array($markMid) );
if ( ZM_OPT_X10 )
dbQuery( "delete from TriggersX10 where MonitorId=?", array($markMid) );

View File

@ -92,6 +92,7 @@ $SLANG = array(
'AlarmMaximumFPS' => 'Alarm Maximum FPS',
'AlarmPx' => 'Alarm Px',
'AlarmRGBUnset' => 'You must set an alarm RGB colour',
'AlarmScore' => 'Alarme Score',
'Alert' => '警告',
'All' => '全部',
'Apply' => '確定',
@ -375,6 +376,7 @@ $SLANG = array(
'Images' => 'Images',
'In' => 'In',
'Include' => '包含',
'IncludeNatDet' => 'Include Native Detection',
'Inverted' => '反轉',
'Iris' => 'Iris',
'KeyString' => 'Key String',
@ -547,6 +549,7 @@ $SLANG = array(
'Play' => 'Play',
'PlayAll' => '全部播放',
'PleaseWait' => 'Please Wait',
'Plugin' => 'Plugin',
'Plugins' => 'Plugins',
'Point' => '點',
'PostEventImageBuffer' => '後置事件影像緩衝',
@ -562,6 +565,7 @@ $SLANG = array(
'Record' => '錄影',
'RefImageBlendPct' => '參考影像混合 %ge',
'Refresh' => '更新',
'ReInitNatDet' => 'Reinit. Native Detection',
'Remote' => 'Remote',
'RemoteHostName' => '遠端主機名稱',
'RemoteHostPath' => '遠端主機路徑',
@ -575,6 +579,7 @@ $SLANG = array(
'ReplayAll' => 'All Events',
'ReplayGapless' => 'Gapless Events',
'ReplaySingle' => 'Single Event',
'RequireNatDet' => 'Require Native Detection',
'Reset' => 'Reset',
'ResetEventCounts' => 'Reset Event Counts',
'Restart' => '重新啟動',

View File

@ -88,6 +88,7 @@ $SLANG = array(
'AlarmMaximumFPS' => '报警最大帧率FPS',
'AlarmPx' => '报警像素',
'AlarmRGBUnset' => '你必须设置一个报警颜色(RGB)',
'AlarmScore' => 'Alarme Score',
'Alert' => '警报',
'All' => '全部',
'Apply' => '应用',
@ -371,6 +372,7 @@ $SLANG = array(
'Images' => '影像',
'In' => '在',
'Include' => '包含',
'IncludeNatDet' => 'Include Native Detection',
'Inverted' => '反向',
'Iris' => '光圈',
'KeyString' => '密钥字符',
@ -543,6 +545,7 @@ $SLANG = array(
'Play' => '播放',
'PlayAll' => '播放全部',
'PleaseWait' => '请等待',
'Plugin' => 'Plugin',
'Plugins' => 'Plugins',
'Point' => '点',
'PostEventImageBuffer' => '事件之后影像数',
@ -558,6 +561,7 @@ $SLANG = array(
'Record' => '记录',
'RefImageBlendPct' => '参考影像混合 %ge',
'Refresh' => '刷新',
'ReInitNatDet' => 'Reinit. Native Detection',
'Remote' => '远程',
'RemoteHostName' => '远程主机名',
'RemoteHostPath' => '远程主机路径',
@ -571,6 +575,7 @@ $SLANG = array(
'ReplayAll' => '全部事件',
'ReplayGapless' => '无间隙事件',
'ReplaySingle' => '单一事件',
'RequireNatDet' => 'Require Native Detection',
'Reset' => '重置',
'ResetEventCounts' => '重置事件数',
'Restart' => '重启动',

View File

@ -88,6 +88,7 @@ $SLANG = array(
'AlarmMaximumFPS' => 'Alarm Maximum FPS',
'AlarmPx' => 'Alarm Px',
'AlarmRGBUnset' => 'You must set an alarm RGB colour',
'AlarmScore' => 'Alarme Score',
'Alert' => 'Pozor',
'All' => 'V¹echny',
'Apply' => 'Pou¾ít',
@ -371,6 +372,7 @@ $SLANG = array(
'Images' => 'Images',
'In' => 'Dovnitø',
'Include' => 'Vlo¾it',
'IncludeNatDet' => 'Include Native Detection',
'Inverted' => 'Pøevrácenì',
'Iris' => 'Iris',
'KeyString' => 'Key String',
@ -543,6 +545,7 @@ $SLANG = array(
'Play' => 'Play',
'PlayAll' => 'Pøehrát v¹e',
'PleaseWait' => 'Prosím èekejte',
'Plugin' => 'Plugin',
'Plugins' => 'Plugins',
'Point' => 'Point',
'PostEventImageBuffer' => 'Pozáznamový bufer',
@ -558,6 +561,7 @@ $SLANG = array(
'Record' => 'Nahrávat',
'RefImageBlendPct' => 'Reference Image Blend %ge',
'Refresh' => 'Obnovit',
'ReInitNatDet' => 'Reinit. Native Detection',
'Remote' => 'Sí»ová',
'RemoteHostName' => 'Adresa',
'RemoteHostPath' => 'Cesta',
@ -571,6 +575,7 @@ $SLANG = array(
'ReplayAll' => 'All Events',
'ReplayGapless' => 'Gapless Events',
'ReplaySingle' => 'Single Event',
'RequireNatDet' => 'Require Native Detection',
'Reset' => 'Reset',
'ResetEventCounts' => 'Resetovat poèty záznamù',
'Restart' => 'Restartovat',

View File

@ -88,6 +88,7 @@ $SLANG = array(
'AlarmMaximumFPS' => 'Alarm-Maximum-FPS',
'AlarmPx' => 'Alarm-Pixel',
'AlarmRGBUnset' => 'Sie m&uuml;ssen eine RGB-Alarmfarbe setzen',
'AlarmScore' => 'Alarme Score',
'Alert' => 'Alarm',
'All' => 'Alle',
'Apply' => 'OK',
@ -371,6 +372,7 @@ $SLANG = array(
'Images' => 'Bilder',
'In' => 'In',
'Include' => 'Einschluss',
'IncludeNatDet' => 'Include Native Detection',
'Inverted' => 'Invertiert',
'Iris' => 'Iris',
'KeyString' => 'Schl&uuml;sselwort',
@ -543,6 +545,7 @@ $SLANG = array(
'Play' => 'Abspielen',
'PlayAll' => 'Alle zeigen',
'PleaseWait' => 'Bitte warten',
'Plugin' => 'Plugin',
'Plugins' => 'Plugins',
'Point' => 'Punkt',
'PostEventImageBuffer' => 'Nachereignispuffer',
@ -558,6 +561,7 @@ $SLANG = array(
'Record' => 'Aufnahme',
'RefImageBlendPct' => 'Referenz-Bildblende',
'Refresh' => 'Aktualisieren',
'ReInitNatDet' => 'Reinit. Native Detection',
'Remote' => 'Entfernt',
'RemoteHostName' => 'Entfernter Hostname',
'RemoteHostPath' => 'Entfernter Hostpfad',
@ -571,6 +575,7 @@ $SLANG = array(
'ReplayAll' => 'Alle Ereignisse',
'ReplayGapless' => 'L&uuml;ckenlose Ereignisse',
'ReplaySingle' => 'Einzelereignis',
'RequireNatDet' => 'Require Native Detection',
'Reset' => 'Zur&uuml;cksetzen',
'ResetEventCounts' => 'L&ouml;sche Ereignispunktzahl',
'Restart' => 'Neustart',

View File

@ -89,6 +89,7 @@ $SLANG = array(
'AlarmMaximumFPS' => 'Alarm Maximum FPS',
'AlarmPx' => 'Alarm Px',
'AlarmRGBUnset' => 'You must set an alarm RGB colour',
'AlarmScore' => 'Alarme Score',
'Alert' => 'Alarm',
'All' => 'Alle',
'Apply' => 'Aktiver',
@ -372,6 +373,7 @@ $SLANG = array(
'Images' => 'Images',
'In' => 'Ind',
'Include' => 'Inkluder',
'IncludeNatDet' => 'Include Native Detection',
'Inverted' => 'Inverteret',
'Iris' => 'Iris',
'KeyString' => 'Key String',
@ -544,6 +546,7 @@ $SLANG = array(
'Play' => 'Play',
'PlayAll' => 'Afspil Alle',
'PleaseWait' => 'Vent venligst',
'Plugin' => 'Plugin',
'Plugins' => 'Plugins',
'Point' => 'Point',
'PostEventImageBuffer' => 'Efter Event Billed Buffer',
@ -559,6 +562,7 @@ $SLANG = array(
'Record' => 'Optag',
'RefImageBlendPct' => 'Reference Billede Blend %ge',
'Refresh' => 'Opdater',
'ReInitNatDet' => 'Reinit. Native Detection',
'Remote' => 'Remote',
'RemoteHostName' => 'Remote Host Navn',
'RemoteHostPath' => 'Remote Host Stig',
@ -572,6 +576,7 @@ $SLANG = array(
'ReplayAll' => 'All Events',
'ReplayGapless' => 'Gapless Events',
'ReplaySingle' => 'Single Event',
'RequireNatDet' => 'Require Native Detection',
'Reset' => 'Nulstil',
'ResetEventCounts' => 'Reset Event Counts',
'Restart' => 'Genstart',

View File

@ -97,6 +97,7 @@ $SLANG = array(
'AlarmMaximumFPS' => 'Alarm Maximum FPS',
'AlarmPx' => 'Alarm Px',
'AlarmRGBUnset' => 'You must set an alarm RGB colour',
'AlarmScore' => 'Alarme Score',
'Alert' => 'Alert',
'All' => 'All',
'Apply' => 'Apply',
@ -377,6 +378,7 @@ $SLANG = array(
'Image' => 'Image',
'Images' => 'Images',
'Include' => 'Include',
'IncludeNatDet' => 'Include Native Detection',
'In' => 'In',
'Inverted' => 'Inverted',
'Iris' => 'Iris',
@ -544,6 +546,7 @@ $SLANG = array(
'Pixels' => 'pixels',
'PlayAll' => 'Play All',
'Play' => 'Play',
'Plugin' => 'Plugin',
'Plugins' => 'Plugins',
'PleaseWait' => 'Please Wait',
'Point' => 'Point',
@ -560,6 +563,7 @@ $SLANG = array(
'Record' => 'Record',
'RefImageBlendPct' => 'Reference Image Blend %ge',
'Refresh' => 'Refresh',
'ReInitNatDet' => 'Reinit. Native Detection',
'RemoteHostName' => 'Remote Host Name',
'RemoteHostPath' => 'Remote Host Path',
'RemoteHostSubPath' => 'Remote Host SubPath',
@ -573,6 +577,7 @@ $SLANG = array(
'ReplayGapless' => 'Gapless Events',
'Replay' => 'Replay',
'ReplaySingle' => 'Single Event',
'RequireNatDet' => 'Require Native Detection',
'ResetEventCounts' => 'Reset Event Counts',
'Reset' => 'Reset',
'Restarting' => 'Restarting',

View File

@ -39,6 +39,7 @@ $SLANG = array(
'AlarmMaximumFPS' => 'Alarm Maximum FPS',
'AlarmPx' => 'Alarm Px',
'AlarmRGBUnset' => 'You must set an alarm RGB colour',
'AlarmScore' => 'Alarme Score',
'Alert' => 'Alerta',
'All' => 'Todo',
'Apply' => 'Aplicar',
@ -322,6 +323,7 @@ $SLANG = array(
'Images' => 'Images',
'In' => 'In',
'Include' => 'Incluir',
'IncludeNatDet' => 'Include Native Detection',
'Inverted' => 'Invertido',
'Iris' => 'Iris',
'KeyString' => 'Key String',
@ -494,6 +496,7 @@ $SLANG = array(
'Play' => 'Play',
'PlayAll' => 'Play All',
'PleaseWait' => 'Espere por favor',
'Plugin' => 'Plugin',
'Plugins' => 'Plugins',
'Point' => 'Point',
'PostEventImageBuffer' => 'Buffer Imagenes despues evento',
@ -509,6 +512,7 @@ $SLANG = array(
'Record' => 'Registro',
'RefImageBlendPct' => 'Reference Image Blend %ge',
'Refresh' => 'Actualizar',
'ReInitNatDet' => 'Reinit. Native Detection',
'Remote' => 'Remote',
'RemoteHostName' => 'Nombre Servidor Remoto',
'RemoteHostPath' => 'Enlace Servidor Remoto',
@ -522,6 +526,7 @@ $SLANG = array(
'ReplayAll' => 'All Events',
'ReplayGapless' => 'Gapless Events',
'ReplaySingle' => 'Single Event',
'RequireNatDet' => 'Require Native Detection',
'Reset' => 'Reset',
'ResetEventCounts' => 'Borrar Contador Eventos',
'Restart' => 'Reiniciar',

View File

@ -87,6 +87,7 @@ $SLANG = array(
'AlarmMaximumFPS' => 'Máximos MPS alarma',
'AlarmPx' => 'Px alarma',
'AlarmRGBUnset' => 'Debe establecer un color RGB para alarma',
'AlarmScore' => 'Alarme Score',
'Alert' => 'Alerta',
'All' => 'Todo',
'Apply' => 'Aplicar',
@ -368,6 +369,7 @@ $SLANG = array(
'Images' => 'Imágenes',
'In' => 'En',
'Include' => 'Incluir',
'IncludeNatDet' => 'Include Native Detection',
'Inverted' => 'Invertido',
'Iris' => 'Iris',
'KeyString' => 'Cadena clave',
@ -540,6 +542,8 @@ $SLANG = array(
'Play' => 'Reproducir',
'PlayAll' => 'Reproducir rodo',
'PleaseWait' => 'Espere por favor',
'Plugin' => 'Plugin',
'Plugins' => 'Plugins',
'Point' => 'Punto',
'PostEventImageBuffer' => 'Cuenta de imagen post evento',
'PreEventImageBuffer' => 'Cuenta de imagen pre evento',
@ -554,6 +558,7 @@ $SLANG = array(
'Record' => 'Grabar',
'RefImageBlendPct' => 'Referencia de mezcla de imagen %ge',
'Refresh' => 'Refrescar',
'ReInitNatDet' => 'Reinit. Native Detection',
'Remote' => 'Remoto',
'RemoteHostName' => 'Nombre del host remoto',
'RemoteHostPath' => 'Nombre de ruta del host',
@ -567,6 +572,7 @@ $SLANG = array(
'ReplayAll' => 'Todos los eventos',
'ReplayGapless' => 'Eventos sin espacios',
'ReplaySingle' => 'Evento individual',
'RequireNatDet' => 'Require Native Detection',
'Reset' => 'Restablecer',
'ResetEventCounts' => 'Restablecer número de eventos',
'Restart' => 'Reiniciar',
@ -669,6 +675,7 @@ $SLANG = array(
'UpdateNotNecessary' => 'No es necesario actualizar.',
'Updated' => 'Actualizado',
'Upload' => 'Upload', // Added - 2011-08-23
'UsedPlugins' => 'Used Plugins',
'UseFilter' => 'Usar filtro',
'UseFilterExprsPost' => '&nbsp;filtros&nbsp;de expresión', // This is used at the end of the phrase 'use N filter expressions'
'UseFilterExprsPre' => 'Usar&nbsp;', // This is used at the beginning of the phrase 'use N filter expressions'

View File

@ -89,6 +89,7 @@ $SLANG = array(
'AlarmMaximumFPS' => 'Alarmi Maksimaalne FPS',
'AlarmPx' => 'Alarm Px',
'AlarmRGBUnset' => 'Sa pead panema alarmi RGB värvi',
'AlarmScore' => 'Alarme Score',
'Alert' => 'Hoiatus',
'All' => 'All',
'Apply' => 'Apply',
@ -371,6 +372,7 @@ $SLANG = array(
'Images' => 'Pildid',
'In' => 'In',
'Include' => 'Include',
'IncludeNatDet' => 'Include Native Detection',
'Inverted' => 'Inverted',
'Iris' => 'Iris',
'KeyString' => 'Key String',
@ -543,6 +545,7 @@ $SLANG = array(
'Play' => 'Play',
'PlayAll' => 'Play Kõike',
'PleaseWait' => 'Palun Oota',
'Plugin' => 'Plugin',
'Plugins' => 'Pluginad',
'Point' => 'Punkt',
'PostEventImageBuffer' => 'Post Event Image Count',
@ -558,6 +561,7 @@ $SLANG = array(
'Record' => 'Salvesta',
'RefImageBlendPct' => 'Reference Image Blend %ge',
'Refresh' => 'Värskenda',
'ReInitNatDet' => 'Reinit. Native Detection',
'Remote' => 'Remote',
'RemoteHostName' => 'Remote Host Name',
'RemoteHostPath' => 'Remote Host Path',
@ -571,6 +575,7 @@ $SLANG = array(
'ReplayAll' => 'Kõik sündmused',
'ReplayGapless' => 'Lünkadeta sündmused',
'ReplaySingle' => 'Üksik sündmus',
'RequireNatDet' => 'Require Native Detection',
'Reset' => 'Reset',
'ResetEventCounts' => 'Reset Event Counts',
'Restart' => 'Taaskäivita',
@ -673,6 +678,7 @@ $SLANG = array(
'UpdateNotNecessary' => 'Uuendus ei ole vajalik.',
'Updated' => 'Uuendatud', // Added - 2011-06-16
'Upload' => 'Üles laadimine', // Added - 2011-08-23
'UsedPlugins' => 'Used Plugins',
'UseFilter' => 'Kasuta Filtrit',
'UseFilterExprsPost' => '&nbsp;filter&nbsp;expressions', // This is used at the end of the phrase 'use N filter expressions'
'UseFilterExprsPre' => 'Use&nbsp;', // This is used at the beginning of the phrase 'use N filter expressions'

View File

@ -88,6 +88,7 @@ $SLANG = array(
'AlarmMaximumFPS' => 'Alarm Maximum FPS',
'AlarmPx' => 'Px Alarme',
'AlarmRGBUnset' => 'You must set an alarm RGB colour',
'AlarmeScore' => 'Score alarme',
'Alert' => 'Alerte',
'All' => 'Tous',
'Apply' => 'Appliquer',
@ -371,7 +372,8 @@ $SLANG = array(
'Images' => 'Images',
'In' => 'In',
'Include' => 'Inclure',
'Inverted' => 'Inversé',
'IncludeNatDet' => 'Inclure détection native',
'Inverted' => 'Inversé',
'Iris' => 'Iris',
'KeyString' => 'Key String',
'Label' => 'Label',
@ -543,6 +545,7 @@ $SLANG = array(
'Play' => 'Play',
'PlayAll' => 'Play All',
'PleaseWait' => 'Attendez',
'Plugin' => 'Plugin',
'Plugins' => 'Plugins',
'Point' => 'Point',
'PostEventImageBuffer' => 'Post Event Image Count',
@ -557,7 +560,8 @@ $SLANG = array(
'Real' => 'Réel',
'Record' => 'Enreg.',
'RefImageBlendPct' => 'Reference Image Blend %ge',
'Refresh' => 'Rafraîchir',
'Refresh' => 'Rafraîchir',
'ReInitNatDet' => 'Réinit. détection native',
'Remote' => 'Remote',
'RemoteHostName' => 'Remote Host Name',
'RemoteHostPath' => 'Remote Host Path',
@ -571,6 +575,7 @@ $SLANG = array(
'ReplayAll' => 'All Events',
'ReplayGapless' => 'Gapless Events',
'ReplaySingle' => 'Single Event',
'RequireNatDet' => 'Détection native requise',
'Reset' => 'Reset',
'ResetEventCounts' => 'Rem. à 0 comptage des évts',
'Restart' => 'Redémarrer',

View File

@ -88,6 +88,7 @@ $SLANG = array(
'AlarmMaximumFPS' => 'Alarm Maximum FPS',
'AlarmPx' => 'àæò÷ú Px',
'AlarmRGBUnset' => 'äéðê çééá ìàúçì àæò÷ú öáò',
'AlarmScore' => 'Alarme Score',
'Alert' => 'äúøàä',
'All' => 'äëì',
'Apply' => 'äçì',
@ -371,6 +372,7 @@ $SLANG = array(
'Images' => 'úîåðåú',
'In' => 'áúåê',
'Include' => 'ëìåì',
'IncludeNatDet' => 'Include Native Detection',
'Inverted' => 'äôåê',
'Iris' => 'Iris',
'KeyString' => 'îçøåæú úåéí',
@ -543,6 +545,7 @@ $SLANG = array(
'Play' => 'Play',
'PlayAll' => 'ðâï äëì',
'PleaseWait' => 'äîúï áá÷ùä',
'Plugin' => 'Plugin',
'Plugins' => 'Plugins',
'Point' => 'ð÷åãä',
'PostEventImageBuffer' => 'Post Event Image Count',
@ -558,6 +561,7 @@ $SLANG = array(
'Record' => 'ä÷ìèä',
'RefImageBlendPct' => 'Reference Image Blend %ge',
'Refresh' => 'øòðåï',
'ReInitNatDet' => 'Reinit. Native Detection',
'Remote' => 'îøåç÷',
'RemoteHostName' => 'ùí îàøç îøåç÷',
'RemoteHostPath' => 'ðúéá îàøç îøåç÷',
@ -571,6 +575,7 @@ $SLANG = array(
'ReplayAll' => 'All Events',
'ReplayGapless' => 'Gapless Events',
'ReplaySingle' => 'Single Event',
'RequireNatDet' => 'Require Native Detection',
'Reset' => 'àôñ',
'ResetEventCounts' => 'Reset Event Counts',
'Restart' => 'àúçì',

View File

@ -130,6 +130,7 @@ $SLANG = array(
'AlarmMaximumFPS' => 'Maximális FPS riasztott állapotban',
'AlarmPx' => 'Riasztó képpont',
'AlarmRGBUnset' => 'Be kell állítani egy RGB színt a riasztáshoz',
'AlarmScore' => 'Alarme Score',
'Alert' => 'Figyelem',
'All' => 'Mind',
'Apply' => 'Alkalmaz',
@ -411,6 +412,7 @@ $SLANG = array(
'Images' => 'Kép',
'In' => 'In',
'Include' => 'Beágyaz',
'IncludeNatDet' => 'Include Native Detection',
'Inverted' => 'Invertálva',
'Iris' => 'Írisz',
'KeyString' => 'Kulcs karaktersor',
@ -583,6 +585,8 @@ $SLANG = array(
'Play' => 'Lejátszás',
'PlayAll' => 'Mind lejátszása',
'PleaseWait' => 'Kérlek várj...',
'Plugin' => 'Plugin',
'Plugins' => 'Plugins',
'Point' => 'Pont',
'PostEventImageBuffer' => 'Esemény utáni képkockák a pufferben',
'PreEventImageBuffer' => 'Esemény elötti képkockák a pufferben',
@ -597,6 +601,7 @@ $SLANG = array(
'Record' => 'Felvétel',
'RefImageBlendPct' => 'Változás a referenciaképtől %-ban',
'Refresh' => 'Frissítés',
'ReInitNatDet' => 'Reinit. Native Detection',
'Remote' => 'Hálózati',
'RemoteHostName' => 'Hálózati IP cím/hosztnév',
'RemoteHostPath' => 'A kép elérési útvonala',
@ -610,6 +615,7 @@ $SLANG = array(
'ReplayAll' => 'Mindet',
'ReplayGapless' => 'Szünet nélkülieket',
'ReplaySingle' => 'Egyenként',
'RequireNatDet' => 'Require Native Detection',
'Reset' => 'Alapértékre',
'ResetEventCounts' => 'Eseményszámláló nullázása',
'Restart' => 'A szolgáltatás újraindítása',
@ -712,6 +718,7 @@ $SLANG = array(
'UpdateNotNecessary' => 'Nem szükséges a frissítés.',
'Updated' => 'Frissítve',
'Upload' => 'Feltöltés',
'UsedPlugins' => 'Used Plugins',
'UseFilter' => 'Szűrőt használ',
'UseFilterExprsPost' => '&nbsp;szürés&nbsp; használata', // This is used at the end of the phrase 'use N filter expressions'
'UseFilterExprsPre' => '&nbsp;', // This is used at the beginning of the phrase 'use N filter expressions'

View File

@ -93,6 +93,7 @@ $SLANG = array(
'AlarmMaximumFPS' => 'FPS massimi durante l\'allarme',
'AlarmPx' => 'Pixel Allarme',
'AlarmRGBUnset' => 'Devi settare un colore RGB di allarme',
'AlarmScore' => 'Alarme Score',
'Alert' => 'Attenzione',
'All' => 'Tutto',
'Apply' => 'Applica',
@ -376,6 +377,7 @@ $SLANG = array(
'Images' => 'Immagini',
'In' => 'In',
'Include' => 'Includi',
'IncludeNatDet' => 'Include Native Detection',
'Inverted' => 'Invertito',
'Iris' => 'Iris',
'KeyString' => 'Stringa Chiave',
@ -548,6 +550,7 @@ $SLANG = array(
'Play' => 'Play',
'PlayAll' => 'Vedi tutti',
'PleaseWait' => 'Attendere prego',
'Plugin' => 'Plugin',
'Plugins' => 'Plugins',
'Point' => 'Punto',
'PostEventImageBuffer' => 'Buffer di immagini Dopo Evento',
@ -563,6 +566,7 @@ $SLANG = array(
'Record' => 'Registra',
'RefImageBlendPct' => 'Riferimento Miscela Immagine percentuale',
'Refresh' => 'Aggiorna',
'ReInitNatDet' => 'Reinit. Native Detection',
'Remote' => 'Remoto',
'RemoteHostName' => 'Nome dell\'Host Remoto',
'RemoteHostPath' => 'Percorso dell\'Host Remoto',
@ -576,6 +580,7 @@ $SLANG = array(
'ReplayAll' => 'All Events',
'ReplayGapless' => 'Gapless Events',
'ReplaySingle' => 'Single Event',
'RequireNatDet' => 'Require Native Detection',
'Reset' => 'Resetta',
'ResetEventCounts' => 'Resetta Contatore Eventi',
'Restart' => 'Riavvia',

View File

@ -88,6 +88,7 @@ $SLANG = array(
'AlarmMaximumFPS' => 'Alarm Maximum FPS',
'AlarmPx' => 'アラーム Px',
'AlarmRGBUnset' => 'You must set an alarm RGB colour',
'AlarmScore' => 'Alarme Score',
'Alert' => '警告',
'All' => '全て',
'Apply' => '適用',
@ -371,6 +372,7 @@ $SLANG = array(
'Images' => 'Images',
'In' => 'In',
'Include' => '組み込む',
'IncludeNatDet' => 'Include Native Detection',
'Inverted' => '反転',
'Iris' => 'Iris',
'KeyString' => 'Key String',
@ -543,6 +545,7 @@ $SLANG = array(
'Play' => 'Play',
'PlayAll' => 'Play All',
'PleaseWait' => 'お待ちください',
'Plugin' => 'Plugin',
'Plugins' => 'Plugins',
'Point' => 'Point',
'PostEventImageBuffer' => 'イベント イメージ バッファ後',
@ -558,6 +561,7 @@ $SLANG = array(
'Record' => '録画',
'RefImageBlendPct' => 'イメージ ブレンド 参照 %',
'Refresh' => '最新の情報に更新',
'ReInitNatDet' => 'Reinit. Native Detection',
'Remote' => 'リモート',
'RemoteHostName' => 'リモート ホスト 名',
'RemoteHostPath' => 'リモート ホスト パス',
@ -571,6 +575,7 @@ $SLANG = array(
'ReplayAll' => 'All Events',
'ReplayGapless' => 'Gapless Events',
'ReplaySingle' => 'Single Event',
'RequireNatDet' => 'Require Native Detection',
'Reset' => 'Reset',
'ResetEventCounts' => 'イベント カウント リセット',
'Restart' => '再起動',

View File

@ -87,6 +87,7 @@ $SLANG = array(
'AlarmMaximumFPS' => 'Alarm Maximum FPS',
'AlarmPx' => 'Alarm Px',
'AlarmRGBUnset' => 'U moet een RGB alarm kleur keizen',
'AlarmScore' => 'Alarme Score',
'Alert' => 'Waarschuwing',
'All' => 'Alle',
'Apply' => 'Voer uit',
@ -368,6 +369,7 @@ $SLANG = array(
'Images' => 'Fotos',
'In' => 'In',
'Include' => 'voeg in',
'IncludeNatDet' => 'Include Native Detection',
'Inverted' => 'Omgedraaid',
'Iris' => 'Iris',
'KeyString' => 'Sleutel waarde',
@ -540,6 +542,8 @@ $SLANG = array(
'Play' => 'Speel',
'PlayAll' => 'Speel Alles',
'PleaseWait' => 'Wacht A.U.B.',
'Plugin' => 'Plugin',
'Plugins' => 'Plugins',
'Point' => 'Punt',
'PostEventImageBuffer' => 'Post gebeurtenis foto Buffer',
'PreEventImageBuffer' => 'Pre gebeurtenis foto Buffer',
@ -554,6 +558,7 @@ $SLANG = array(
'Record' => 'Record',
'RefImageBlendPct' => 'Referentie foto Blend %ge',
'Refresh' => 'Ververs',
'ReInitNatDet' => 'Reinit. Native Detection',
'Remote' => 'Remote',
'RemoteHostName' => 'Remote Host Naam',
'RemoteHostPath' => 'Remote Host Pad',
@ -567,6 +572,7 @@ $SLANG = array(
'ReplayAll' => 'Alle Gebeurtenissen',
'ReplayGapless' => 'Opvolgende Gebeurtenissen',
'ReplaySingle' => 'Enkele Gebeurtenis',
'RequireNatDet' => 'Require Native Detection',
'Reset' => 'Herstel',
'ResetEventCounts' => 'Herstel gebeurtenis teller',
'Restart' => 'Herstart',
@ -668,6 +674,7 @@ $SLANG = array(
'UpdateAvailable' => 'Een update voor ZoneMinder is beschikbaar',
'UpdateNotNecessary' => 'Geen update noodzakelijk',
'Updated' => 'Ververst', // Added - 2011-06-16
'UsedPlugins' => 'Used Plugins',
'UseFilter' => 'Gebruik Filter',
'UseFilterExprsPost' => '&nbsp;filter&nbsp;expressies', // This is used at the end of the phrase 'use N filter expressions'
'UseFilterExprsPre' => 'Gebruik&nbsp;', // This is used at the beginning of the phrase 'use N filter expressions'

View File

@ -88,6 +88,7 @@ $SLANG = array(
'AlarmMaximumFPS' => 'Alarm Maximum FPS',
'AlarmPx' => 'Alarm Px',
'AlarmRGBUnset' => 'You must set an alarm RGB colour',
'AlarmScore' => 'Alarme Score',
'Alert' => 'Gotowosc',
'All' => 'Wszystko',
'Apply' => 'Zastosuj',
@ -371,6 +372,7 @@ $SLANG = array(
'Images' => 'Images',
'In' => 'In',
'Include' => 'Do³±cz',
'IncludeNatDet' => 'Include Native Detection',
'Inverted' => 'Odwrócony',
'Iris' => 'Iris',
'KeyString' => 'Key String',
@ -543,6 +545,7 @@ $SLANG = array(
'Play' => 'Play',
'PlayAll' => 'Play All',
'PleaseWait' => 'Proszê czekaæ',
'Plugin' => 'Plugin',
'Plugins' => 'Plugins',
'Point' => 'Point',
'PostEventImageBuffer' => 'Bufor obrazów po zdarzeniu',
@ -558,6 +561,7 @@ $SLANG = array(
'Record' => 'Zapis',
'RefImageBlendPct' => 'Miks z obrazem odniesienia',
'Refresh' => 'Od¶wie¿',
'ReInitNatDet' => 'Reinit. Native Detection',
'Remote' => 'Zdalny',
'RemoteHostName' => 'Nazwa zdalnego hosta',
'RemoteHostPath' => 'Scie¿ka zdalnego hosta',
@ -571,6 +575,7 @@ $SLANG = array(
'ReplayAll' => 'All Events',
'ReplayGapless' => 'Gapless Events',
'ReplaySingle' => 'Single Event',
'RequireNatDet' => 'Require Native Detection',
'Reset' => 'Reset',
'ResetEventCounts' => 'Kasuj licznik zdarzeñ',
'Restart' => 'Restart',

View File

@ -28,6 +28,7 @@ $SLANG = array(
'AlarmMaximumFPS' => 'Alarm Maximum FPS',
'AlarmPx' => 'Pixel de Alarme',
'AlarmRGBUnset' => 'You must set an alarm RGB colour',
'AlarmScore' => 'Alarme Score',
'Alert' => 'Alerta',
'All' => 'Tudo',
'Apply' => 'Aplicar',
@ -311,6 +312,7 @@ $SLANG = array(
'Images' => 'Images',
'In' => 'In',
'Include' => 'Incluir',
'IncludeNatDet' => 'Include Native Detection',
'Inverted' => 'Invertido',
'Iris' => 'Iris',
'KeyString' => 'Key String',
@ -483,6 +485,7 @@ $SLANG = array(
'Play' => 'Play',
'PlayAll' => 'Play All',
'PleaseWait' => 'Por Favor Espere',
'Plugin' => 'Plugin',
'Plugins' => 'Plugins',
'Point' => 'Point',
'PostEventImageBuffer' => 'Buffer de imagem pós evento',
@ -498,6 +501,7 @@ $SLANG = array(
'Record' => 'Gravar',
'RefImageBlendPct' => 'Referência de imagem Blend %ge',
'Refresh' => 'Atualizar',
'ReInitNatDet' => 'Reinit. Native Detection',
'Remote' => 'Remoto',
'RemoteHostName' => 'Nome do host remoto',
'RemoteHostPath' => 'Caminho do host remoto',
@ -511,6 +515,7 @@ $SLANG = array(
'ReplayAll' => 'All Events',
'ReplayGapless' => 'Gapless Events',
'ReplaySingle' => 'Single Event',
'RequireNatDet' => 'Require Native Detection',
'Reset' => 'Reset',
'ResetEventCounts' => 'Resetar contagem de eventos',
'Restart' => 'Reiniciar',

View File

@ -59,6 +59,7 @@ $SLANG = array(
'AlarmMaximumFPS' => 'Alarm Maximum FPS',
'AlarmPx' => 'Alarm Px',
'AlarmRGBUnset' => 'You must set an alarm RGB colour',
'AlarmScore' => 'Alarme Score',
'Alert' => 'Alert',
'All' => 'Toate',
'Apply' => 'Accept',
@ -342,6 +343,7 @@ $SLANG = array(
'Images' => 'Images',
'In' => 'In',
'Include' => 'Includ',
'IncludeNatDet' => 'Include Native Detection',
'Inverted' => 'Invers&#259;',
'Iris' => 'Iris',
'KeyString' => 'Key String',
@ -514,6 +516,7 @@ $SLANG = array(
'Play' => 'Play',
'PlayAll' => 'Play All',
'PleaseWait' => 'V&#259; rug&#259;m a&#351;tepta&#355;i',
'Plugin' => 'Plugin',
'Plugins' => 'Plugins',
'Point' => 'Point',
'PostEventImageBuffer' => 'Zona tampon post eveniment',
@ -529,6 +532,7 @@ $SLANG = array(
'Record' => '&#206;nregistrare',
'RefImageBlendPct' => 'Combinare imagine referinta(%)',
'Refresh' => 'Actualizeaz&#259;',
'ReInitNatDet' => 'Reinit. Native Detection',
'Remote' => 'Remote',
'RemoteHostName' => 'Remote Host Name',
'RemoteHostPath' => 'Remote Host Path',
@ -542,6 +546,7 @@ $SLANG = array(
'ReplayAll' => 'All Events',
'ReplayGapless' => 'Gapless Events',
'ReplaySingle' => 'Single Event',
'RequireNatDet' => 'Require Native Detection',
'Reset' => 'Reset',
'ResetEventCounts' => 'Reset Event Counts',
'Restart' => 'Reporne&#351;te',

View File

@ -88,6 +88,7 @@ $SLANG = array(
'AlarmMaximumFPS' => 'Alarm Maximum FPS',
'AlarmPx' => 'ðËÓ&nbsp;ÔÒÅ×.',
'AlarmRGBUnset' => 'You must set an alarm RGB colour',
'AlarmScore' => 'Alarme Score',
'Alert' => 'îÁÓÔÏÒÏÖÅ',
'All' => '÷ÓÅ',
'Apply' => 'ðÒÉÍÅÎÉÔØ',
@ -371,6 +372,7 @@ $SLANG = array(
'Images' => 'Images',
'In' => 'In',
'Include' => '÷ËÌÀÞÉÔØ',
'IncludeNatDet' => 'Include Native Detection',
'Inverted' => 'éÎ×ÅÒÔÉÒÏ×ÁÔØ',
'Iris' => 'Iris',
'KeyString' => 'Key String',
@ -543,6 +545,7 @@ $SLANG = array(
'Play' => 'Play',
'PlayAll' => 'Play All',
'PleaseWait' => 'ðÏÖÁÌÕÊÓÔÁ ÐÏÄÏÖÄÉÔÅ',
'Plugin' => 'Plugin',
'Plugins' => 'Plugins',
'Point' => 'Point',
'PostEventImageBuffer' => 'âÕÆÅÒ ÐÏÓÌÅ ÓÏÂÙÔÉÑ',
@ -558,6 +561,7 @@ $SLANG = array(
'Record' => 'Record',
'RefImageBlendPct' => 'ðÒÏÚÒÁÞÎÏÓÔØ ÏÐÏÒÎÏÇÏ ËÁÄÒÁ, %',
'Refresh' => 'ïÂÎÏ×ÉÔØ',
'ReInitNatDet' => 'Reinit. Native Detection',
'Remote' => 'õÄÁÌÅÎÎÙÊ',
'RemoteHostName' => 'éÍÑ ÕÄÁÌÅÎÎÏÇÏ ÈÏÓÔÁ',
'RemoteHostPath' => 'ðÕÔØ ÎÁ ÕÄÁÌÅÎÎÏÍ ÈÏÓÔÅ',
@ -571,6 +575,7 @@ $SLANG = array(
'ReplayAll' => 'All Events',
'ReplayGapless' => 'Gapless Events',
'ReplaySingle' => 'Single Event',
'RequireNatDet' => 'Require Native Detection',
'Reset' => 'Reset',
'ResetEventCounts' => 'ïÂÎÕÌÉÔØ ÓÞÅÔÞÉË ÓÏÂÙÔÉÊ',
'Restart' => 'ðÅÒÅÚÁÐÕÓÔÉÔØ',

View File

@ -89,6 +89,7 @@ $SLANG = array(
'AlarmMaximumFPS' => 'Max. ramar/s för larm',
'AlarmPx' => 'Larmpunkter',
'AlarmRGBUnset' => 'Du måste sätta en färg för RGB-larm',
'AlarmScore' => 'Alarme Score',
'Alert' => 'Varning',
'All' => 'Alla',
'Apply' => 'Lägg till',
@ -372,6 +373,7 @@ $SLANG = array(
'Images' => 'Images',
'In' => 'I',
'Include' => 'Inkludera',
'IncludeNatDet' => 'Include Native Detection',
'Inverted' => 'Inverterad',
'Iris' => 'Iris',
'KeyString' => 'Nyckelsträng',
@ -544,6 +546,7 @@ $SLANG = array(
'Play' => 'Spela',
'PlayAll' => 'Visa alla',
'PleaseWait' => 'Vänta...',
'Plugin' => 'Plugin',
'Plugins' => 'Plugins',
'Point' => 'Punkt',
'PostEventImageBuffer' => 'Post Event Image Count',
@ -559,6 +562,7 @@ $SLANG = array(
'Record' => 'Spela in',
'RefImageBlendPct' => 'Reference Image Blend %ge',
'Refresh' => 'Uppdatera',
'ReInitNatDet' => 'Reinit. Native Detection',
'Remote' => 'Fjärr',
'RemoteHostName' => 'Fjärrnamn',
'RemoteHostPath' => 'Fjärrsökväg',
@ -572,6 +576,7 @@ $SLANG = array(
'ReplayAll' => 'Alla händelser',
'ReplayGapless' => 'Gapless Events',
'ReplaySingle' => 'Ensam händelse',
'RequireNatDet' => 'Require Native Detection',
'Reset' => 'Återställ',
'ResetEventCounts' => 'Återställ händelseräknare',
'Restart' => 'Återstart',

View File

@ -23,6 +23,7 @@ dist_web_DATA = \
montage.css \
montage_freeform.css \
options.css \
plugin.css \
stats.css \
timeline.css \
timeline.css.php \

View File

@ -3,6 +3,10 @@
margin: 0 2px;
}
#settingsPanel input[type=submit] {
margin: 8px 4px;
}
#pluginSettings {
border-collapse: collapse;
}

View File

@ -93,3 +93,22 @@
#zonePoints table a {
margin: 0 2px;
}
a.pluginNotEnabled {
text-decoration: none;
color: grey;
}
a.pluginError {
text-decoration: none;
color: red;
}
a.pluginNotActive {
color: orange;
}
a.pluginActive {
color: green;
}

View File

@ -23,6 +23,7 @@ dist_web_DATA = \
montage.css \
montage_freeform.css \
options.css \
plugin.css \
stats.css \
timeline.css \
timeline.css.php \

View File

@ -3,6 +3,10 @@
margin: 0 2px;
}
#settingsPanel input[type=submit] {
margin: 8px 4px;
}
#pluginSettings {
border-collapse: collapse;
}

View File

@ -93,3 +93,22 @@
#zonePoints table a {
margin: 0 2px;
}
a.pluginNotEnabled {
text-decoration: none;
color: grey;
}
a.pluginError {
text-decoration: none;
color: red;
}
a.pluginNotActive {
color: orange;
}
a.pluginActive {
color: green;
}

View File

@ -55,6 +55,7 @@ var popupSizes = {
'montage': { 'width': -1, 'height': -1 },
'optionhelp': { 'width': 400, 'height': 320 },
'options': { 'width': 1000, 'height': 660 },
'plugin': { 'addWidth': 16, 'addHeight': 48 },
'preset': { 'width': 300, 'height': 120 },
'settings': { 'width': 220, 'height': 225 },
'state': { 'width': 370, 'height': 134 },

View File

@ -40,6 +40,7 @@ dist_web_DATA = \
none.php \
optionhelp.php \
options.php \
plugin.php \
postlogin.php \
settings.php \
state.php \

View File

@ -33,6 +33,8 @@ dist_web_DATA = \
montage.js \
montage.js.php \
options.js.php \
plugin.js \
plugin.js.php \
postlogin.js \
state.js \
state.js.php \

View File

@ -5,9 +5,49 @@ function validateForm( form )
function submitForm( form )
{
var cb = form.getElementsByTagName('input');
for ( var i = 0; i < cb.length; i++)
{
if ( cb[i].type == 'checkbox' && !cb[i].checked ) // if this is an unchecked checkbox
{
cb[i].value = 0; // set the value to "off"
cb[i].checked = true; // make sure it submits
}
}
form.submit();
}
function saveChanges( element )
{
var form = element.form;
if ( validateForm( form ) )
{
submitForm( form );
return( true );
}
return( false );
}
function applyDependencies()
{
var form = document.pluginForm;
for ( var option in dependencies )
{
var enabled = true;
for ( var name in dependencies[option] )
{
if (form.elements['pluginOpt[' + name + ']'].value != dependencies[option][name])
{
form.elements['pluginOpt[' + option + ']'].disabled = true;
enabled = false;
break;
}
}
if (enabled)
form.elements['pluginOpt[' + option + ']'].disabled = false;
}
}
function limitRange( field, minValue, maxValue )
{

View File

@ -0,0 +1,17 @@
var dependencies = {};
<?php
foreach ( $options as $option )
{
if (!isset($option['Require']))
continue;
?>
dependencies['<?= $option['Name'] ?>'] = {};
<?php
foreach($option['Require'] as $req_couple)
{
?>
dependencies['<?= $option['Name'] ?>']['<?= $req_couple['Name'] ?>'] = '<?= $req_couple['Value'] ?>';
<?php
}
}
?>

View File

@ -106,6 +106,7 @@ if ( ! empty($_REQUEST['mid']) ) {
'Triggers' => "",
'V4LMultiBuffer' => '',
'V4LCapturesPerFrame' => 1,
'DoNativeMotDet' => true
);
}
@ -471,6 +472,7 @@ if ( $tab != 'general' )
<input type="hidden" name="newMonitor[Enabled]" value="<?php echo validHtmlStr($newMonitor['Enabled']) ?>"/>
<input type="hidden" name="newMonitor[RefBlendPerc]" value="<?php echo validHtmlStr($newMonitor['RefBlendPerc']) ?>"/>
<input type="hidden" name="newMonitor[AlarmRefBlendPerc]" value="<?php echo validHtmlStr($newMonitor['AlarmRefBlendPerc']) ?>"/>
<input type="hidden" name="newMonitor[DoNativeMotDet]" value="<?php echo validHtmlStr($newMonitor['DoNativeMotDet']) ?>"/>
<input type="hidden" name="newMonitor[MaxFPS]" value="<?php echo validHtmlStr($newMonitor['MaxFPS']) ?>"/>
<input type="hidden" name="newMonitor[AlarmMaxFPS]" value="<?php echo validHtmlStr($newMonitor['AlarmMaxFPS']) ?>"/>
<?php
@ -655,6 +657,7 @@ switch ( $tab )
<?php
}
?>
<tr><td><?php echo $SLANG['DoNativeMotionDetection'] ?></td><td><input type="checkbox" name="newMonitor[DoNativeMotDet]" value="1"<?php if ( !empty($newMonitor['DoNativeMotDet']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><td><?php echo $SLANG['Triggers'] ?></td><td>
<?php
$optTriggers = getSetValues( 'Monitors', 'Triggers' );

View File

@ -38,67 +38,200 @@ if ( $zid > 0 ) {
$monitor = dbFetchMonitor ( $mid );
$plugin = $_REQUEST['pl'];
$plugin_path = dirname(ZM_PLUGINS_CONFIG_PATH)."/".$plugin;
$plugin_path = dirname($_SERVER['SCRIPT_FILENAME'])."/plugins/".$plugin;
$focusWindow = true;
xhtmlHeaders(__FILE__, $SLANG['Plugin'] );
$pluginOptions=array(
'Enabled'=>array(
'Type'=>'select',
'Name'=>'Enabled',
'Choices'=>'yes,no',
'Value'=>'no'
)
);
$generalOptions=array(
'Enabled'=>array(
'Type'=>'select',
'Name'=>'Enabled',
'Choices'=>'Yes,No',
'Value'=>'No'
),
'RequireNatDet'=>array(
'Type'=>'select',
'Name'=>'RequireNatDet',
'Choices'=>'Yes,No',
'Value'=>'No',
'Require'=>array(
array(
'Name'=>'Enabled',
'Value'=>'Yes'
)
)
),
'IncludeNatDet'=>array(
'Type'=>'select',
'Name'=>'IncludeNatDet',
'Choices'=>'Yes,No',
'Value'=>'No',
'Require'=>array(
array(
'Name'=>'Enabled',
'Value'=>'Yes'
),
array(
'Name'=>'RequireNatDet',
'Value'=>'Yes'
)
)
),
'ReInitNatDet'=>array(
'Type'=>'select',
'Name'=>'ReInitNatDet',
'Choices'=>'Yes,No',
'Value'=>'No',
'Require'=>array(
array(
'Name'=>'Enabled',
'Value'=>'Yes'
),
array(
'Name'=>'RequireNatDet',
'Value'=>'Yes'
)
)
),
'AlarmeScore'=>array(
'Type'=>'integer',
'Name'=>'AlarmeScore',
'Min'=>'1',
'Max'=>'100',
'Value'=>'99',
'Require'=>array(
array(
'Name'=>'Enabled',
'Value'=>'Yes'
)
)
)
);
$options=$generalOptions;
$optionNames=array();
if(file_exists($plugin_path."/config.php"))
{
include_once($plugin_path."/config.php");
}
if(isset($pluginOptions))
foreach( $pluginOptions as $optionKey => $optionValue )
{
// Set default dependency information if not set in configuration file
if(!isset($optionValue['Require']))
$optionValue['Require'] = array (
array(
'Name'=>'Enabled',
'Value'=>'Yes'
)
);
$options[$optionKey]=$optionValue;
}
}
$sql='SELECT * FROM PluginsConfig WHERE MonitorId=? AND ZoneId=? AND pluginName=?';
foreach( dbFetchAll( $sql, NULL, array( $mid, $zid, $plugin ) ) as $popt )
{
if(array_key_exists($popt['Name'], $pluginOptions)
&& $popt['Type']==$pluginOptions[$popt['Name']]['Type']
&& $popt['Choices']==$pluginOptions[$popt['Name']]['Choices']
)
if(array_key_exists($popt['Name'], $options)
&& $popt['Type']==$options[$popt['Name']]['Type'])
{
$pluginOptions[$popt['Name']]=$popt;
array_push($optionNames, $popt['Name']);
// Backup dependency information
$require = '';
if(isset($options[$popt['Name']]['Require']))
$require = $options[$popt['Name']]['Require'];
// Set value from database
$options[$popt['Name']]=$popt;
// Restore dependancy information from backup
if(!empty($require))
$options[$popt['Name']]['Require'] = $require;
// Set default dependancy information if not set in configuration
else if($popt['Name'] != 'Enabled')
$options[$popt['Name']]['Require'] = array (
array(
'Name'=>'Enabled',
'Value'=>'Yes'
)
);
} else {
dbQuery('DELETE FROM PluginsConfig WHERE Id=?', array( $popt['Id'] ) );
}
}
foreach($pluginOptions as $name => $values)
foreach($options as $name => $values)
{
if(!in_array($name, $optionNames))
{
$popt=$pluginOptions[$name];
$sql="INSERT INTO PluginsConfig VALUES ('',?,?,?,?,?,?,?)";
dbQuery($sql, array( $popt['Name'], $popt['Value'], $popt['Type'], $popt['Choices'], $mid, $zid, $plugin ) );
$popt=$options[$name];
switch($popt['Type'])
{
case "select":
$sql="INSERT INTO PluginsConfig VALUES ('',?,?,?,?,'','',?,?,?)";
dbQuery($sql, array( $popt['Name'], $popt['Value'], $popt['Type'], $popt['Choices'], $mid, $zid, $plugin ) );
break;
case "integer":
$sql="INSERT INTO PluginsConfig VALUES ('',?,?,?,'',?,?,?,?,?)";
dbQuery($sql, array( $popt['Name'], $popt['Value'], $popt['Type'], $popt['Min'], $popt['Max'], $mid, $zid, $plugin ) );
break;
case "checkbox":
case "text":
default:
$sql="INSERT INTO PluginsConfig VALUES ('',?,?,?,'','','',?,?,?)";
dbQuery($sql, array( $popt['Name'], $popt['Value'], $popt['Type'], $mid, $zid, $plugin ) );
}
}
}
$PLANG=array();
if(file_exists($plugin_path."/lang/".$user['Language'].".php")) {
include_once($plugin_path."/lang/".$user['Language'].".php");
$lang_path = $plugin_path."/lang";
$userLangFile = $lang_path."/".$user['Language'].".php";
if (isset($user['Language']) && file_exists($userLangFile)) {
include_once($userLangFile);
} else {
$systemLangFile = $lang_path."/".ZM_LANG_DEFAULT.".php";
if (file_exists($systemLangFile)) {
include_once($systemLangFile);
} else {
$fallbackLangFile = $lang_path."/en_gb.php";
if (file_exists($fallbackLangFile)) {
include_once($fallbackLangFile);
}
}
}
function pLang($name)
{
global $SLANG;
global $PLANG;
if(array_key_exists($name, $PLANG))
if(array_key_exists($name, $SLANG))
return $SLANG[$name];
else if(array_key_exists($name, $PLANG))
return $PLANG[$name];
else
return $name;
}
function isEnabled($param)
{
global $options;
$option = $options[$param];
if (!isset($option['Require']))
return true;
foreach($option['Require'] as $req_couple)
{
$name = $req_couple['Name'];
if (!array_key_exists($name, $options))
continue;
if ($req_couple['Value'] != $options[$name]['Value'])
return false;
}
return true;
}
xhtmlHeaders(__FILE__, $SLANG['Plugin'] );
?>
<body>
<div id="page">
@ -117,7 +250,7 @@ function pLang($name)
<table id="pluginSettings" cellspacing="0">
<tbody>
<?
foreach($pluginOptions as $name => $popt)
foreach($options as $name => $popt)
{
?>
<tr><th scope="row"><?php echo pLang($name) ?></th>
@ -125,13 +258,15 @@ foreach($pluginOptions as $name => $popt)
switch($popt['Type'])
{
case "checkbox":
echo "CHECKBOX";
?>
<td><input type="checkbox" name="pluginOpt[<?= $popt['Name'] ?>]" id="pluginOpt[<?= $popt['Name'] ?>]" <? if ($popt['Value']) echo 'checked="checked"'; if (!isEnabled($popt['Name'])) echo 'disabled="disabled"'; ?>></td>
<?
break;
case "select":
$pchoices=explode(',',$popt['Choices']);
?>
<td colspan="2">
<select name="pluginOpt[<?php echo $popt['Name'] ?>]" id="pluginOpt[<?php echo $popt['Name'] ?>]">
<select name="pluginOpt[<?php echo $popt['Name'] ?>]" id="pluginOpt[<?php echo $popt['Name'] ?>]" <? if (!isEnabled($popt['Name'])) echo 'disabled="disabled"'; ?> onchange="applyDependencies()" >
<?
foreach($pchoices as $pchoice)
{
@ -143,13 +278,22 @@ foreach($pluginOptions as $name => $popt)
<?
}
?>
</td>
</select>
</td>
<?
break;
case "text":
?>
<td><input type="text" name="pluginOpt[<?= $popt['Name'] ?>]" id="pluginOpt[<?= $popt['Name'] ?>]" value="<?= $popt['Value'] ?>" <? if (!isEnabled($popt['Name'])) echo 'disabled="disabled"'; ?>></td>
<?
break;
case "integer":
?>
<td><input type="text" name="pluginOpt[<?= $popt['Name'] ?>]" id="pluginOpt[<?= $popt['Name'] ?>]" onchange="limitRange( this, <?= $popt['Min'] ?>, <?= $popt['Max'] ?> )" value="<?= $popt['Value'] ?>" size="4" <? if (!isEnabled($popt['Name'])) echo 'disabled="disabled"'; ?>></td>
<?
break;
default:
echo "DEFAULT";
echo "Type '".$popt['Type']."' is not implemented<br>";
}
?>
</tr>

View File

@ -212,6 +212,60 @@ xhtmlHeaders(__FILE__, $SLANG['Zone'] );
<th scope="row"><?php echo $SLANG['ZoneExtendAlarmFrames'] ?></th>
<td colspan="2"><input type="text" name="newZone[ExtendAlarmFrames]" value="<?php echo $newZone['ExtendAlarmFrames'] ?>" size="4"/></td>
</tr>
<?php
if ($zid > 0)
{
// Get plugin status from zmu command line
exec(escapeshellcmd(getZmuCommand(" -p -m".$mid)), $cmdOutput, $retval);
if($retval == 0)
{
echo "<tr><th scope=\"row\">".$SLANG['Plugins']."</th><td colspan=2>\n";
$plName = "";
$plReg = "0";
$plConf = "0";
foreach($cmdOutput as $key => $line)
{
// Skip header lines or "No plugin found"
if($key < 2) continue;
// Parse line
$pl = preg_split ('/[\s]+/ ', trim($line));
$offset = 0;
if(sizeof($pl) == 9)
{
$plName = $pl[0];
$plReg = $pl[1];
$plConf = $pl[2];
$offset = 3;
}
// Skip line if zone mismatch
if($pl[$offset] != $zid) continue;
// Select class and set display setting
$class = '';
$dspPlConf = true;
if(!ZM_LOAD_PLUGINS) {
$class = " class=\"pluginNotEnabled\"";
$dspPlConf = false;
} else if($plReg == "0" || (($plReg == "1") && ($plConf == "0"))) {
$class = " class=\"pluginError\"";
$dspPlConf = false;
} else if(($pl[1 + $offset] == "1") && ($pl[2 + $offset] == "0")) {
$class = " class=\"pluginNotActive\"";
} else if($pl[2 + $offset] == "1") {
$class = " class=\"pluginActive\"";
}
// Display plugin name and enable link
if($dspPlConf)
echo "<a".$class." href='?view=plugin&amp;mid=".$monitor['Id']."&amp;zid=".
$zid."&amp;pl=".urlencode($plName)."' onclick=\"createPopup('?view=plugin&amp;mid=".
$monitor['Id']."&amp;zid=".$zid."&amp;pl=".urlencode($plName)."','plugin','plugin',".
"500,400); return(false)\">".$plName."</a><br>\n";
else
echo "<a".$class.">".$plName."</a><br>\n";
}
echo "</td></tr>\n";
}
}
?>
</tbody>
</table>
</div>