Compare commits

...

158 Commits

Author SHA1 Message Date
Isaac Connor bf6ca1547d Merge pull request #1401 from SteveGilvarry/feature-plugins
Merge Master to Feature-plugins
2016-04-06 11:53:06 -04:00
SteveGilvarry 8cec795cc2 Fix library name from zoneminder to zm 2016-04-07 00:58:27 +10:00
SteveGilvarry 25abe2aafd Fix score variable 2016-04-07 00:24:38 +10:00
SteveGilvarry 20c295ad0c Merge remote-tracking branch 'upstream/master' into feature-plugins
Conflicts:
	.travis.yml
	CMakeLists.txt
	Makefile.am
	bootstrap.sh
	configure.ac
	distros/debian8/control
	distros/debian_cmake/control
	misc/Makefile.am
	scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in
	src/CMakeLists.txt
	src/Makefile.am
	src/zm_monitor.cpp
	src/zm_monitor.h
	src/zmstreamer.cpp
	web/lang/ru_ru.php
	web/skins/classic/css/classic/views/Makefile.am
	web/skins/classic/css/flat/views/Makefile.am
	web/skins/classic/views/Makefile.am
	web/skins/classic/views/js/Makefile.am
2016-04-07 00:00:38 +10:00
Steve Gilvarry b3e18cd8ff Merge pull request #1160 from SteveGilvarry/feature-plugins
Feature plugins
2015-12-28 15:44:34 +11:00
SteveGilvarry e089805276 Merge remote-tracking branch 'upstream/master' into feature-plugins
Conflicts:
	CMakeLists.txt
	configure.ac
2015-12-28 15:24:28 +11:00
SteveGilvarry 8e603690c9 Feature-plugins sql updates now in their own file that will be renamed zm_update-1.2x.x.sql at some point 2015-11-14 15:35:04 +11:00
SteveGilvarry 76ec7a4c51 Remove feature-plugins sql from previous update file 2015-11-14 15:33:02 +11:00
SteveGilvarry fed8ea90a5 Remove debain8_cmake from distros folder 2015-11-14 02:05:14 +11:00
SteveGilvarry 2a323f6605 Comment out Autobuild 2015-11-14 01:42:23 +11:00
SteveGilvarry ea9457d7f5 Merge remote-tracking branch 'upstream/master' into feature-plugins 2015-11-14 01:18:45 +11:00
SteveGilvarry 56de7aaccd Fix merge of AC_SUBST values 2015-11-09 21:01:12 +11:00
SteveGilvarry f853059ff4 Fix Merge of score unsigned int 2015-11-09 00:09:49 +11:00
SteveGilvarry a700cbffdb Merge remote-tracking branch 'upstream/master' into feature-plugins
Conflicts:
	CMakeLists.txt
	configure.ac
	src/zm_monitor.cpp
	src/zm_monitor.h
	web/lang/big5_big5.php
	web/lang/cn_zh.php
	web/lang/cs_cz.php
	web/lang/de_de.php
	web/lang/dk_dk.php
	web/lang/en_gb.php
	web/lang/es_ar.php
	web/lang/es_es.php
	web/lang/et_ee.php
	web/lang/fr_fr.php
	web/lang/he_il.php
	web/lang/hu_hu.php
	web/lang/it_it.php
	web/lang/ja_jp.php
	web/lang/nl_nl.php
	web/lang/pl_pl.php
	web/lang/pt_br.php
	web/lang/ro_ro.php
	web/lang/ru_ru.php
	web/lang/se_se.php
	web/skins/classic/views/monitor.php
2015-11-08 21:06:21 +11:00
Emmanuel Papin 3d15eaace7 Update libzm_plugin_openalpr plugin readme file 2015-07-21 17:15:27 +02:00
Emmanuel Papin 520e0d8664 Add missing dependencies to Build-Depends for debian package building 2015-07-21 17:02:52 +02:00
Emmanuel Papin 9ee7d67056 Include openalpr plugin 2015-07-21 16:53:32 +02:00
Emmanuel Papin b294569147 Merge branch 'master' of https://github.com/ZoneMinder/ZoneMinder into plugin_support
Merging conflicts fixed in files:
	CMakeLists.txt
	configure.ac
	distros/debian_cmake/control
	src/zm_monitor.h
	web/lang/de_de.php
	web/skins/classic/views/monitor.php
2015-07-20 16:49:04 +02:00
Emmanuel Papin 1fb6ed8a06 Simplify string concatenation 2015-06-08 20:34:41 +02:00
Emmanuel Papin a32a0f2752 Merge branch 'master' of https://github.com/ZoneMinder/ZoneMinder into plugin_support 2015-06-08 19:42:57 +02:00
Emmanuel Papin 717bd7fbfb Upgrade engine version 2015-06-07 21:20:58 +02:00
Emmanuel Papin 6574a128de Do not use 'using namespace' in header files and raise an error if engine versions mismatch 2015-06-07 20:40:33 +02:00
Emmanuel Papin 2acfe5b395 Fix plugin window title name 2015-06-06 18:35:43 +02:00
Emmanuel Papin c6b081696d Install config.h also because cmake builds of plugins fail otherwize 2015-06-06 17:55:27 +02:00
Emmanuel Papin be3c431192 Fix a warning in src/CMakeLists.txt 2015-06-06 15:43:26 +02:00
Emmanuel Papin 717710f444 Fix headers installation 2015-06-06 10:09:43 +02:00
Emmanuel Papin 7e8648d563 Add missing lines in distros/debian8_cmake/rules 2015-06-04 21:39:56 +02:00
Emmanuel Papin e2957702b5 Merge branch 'master' of https://github.com/ZoneMinder/ZoneMinder into plugin_support 2015-06-04 20:57:34 +02:00
Emmanuel Papin 1b42dd90ef Merge branch 'plugin_support_cmake' into plugin_support 2015-06-04 20:54:35 +02:00
Emmanuel Papin 90fd90ae1e Add support to compile with -fPIC when using CMAKE on x86_64 architecture 2015-06-03 20:34:11 +02:00
Emmanuel Papin 5492fd9e93 Fix conflict during package installation 2015-06-03 20:10:02 +02:00
Emmanuel Papin a8524d9b3b Add debian8_cmake folder 2015-06-02 22:58:49 +02:00
Emmanuel Papin ded38268a4 Merge branch 'master' of https://github.com/ZoneMinder/ZoneMinder into plugin_support_cmake 2015-06-02 21:19:13 +02:00
Emmanuel Papin e3eee72abf Merge branch 'master' of https://github.com/ZoneMinder/ZoneMinder into plugin_support 2015-06-02 21:18:53 +02:00
Emmanuel Papin 3f20a08d16 Add cmake support 2015-05-31 02:37:58 +02:00
Emmanuel Papin 905237d7a6 Fix undefined variable issue with pOptions and call only pLang for translation 2015-05-30 14:33:15 +02:00
Emmanuel Papin 872fead1fa Rename zoneminder library 2015-05-30 14:11:42 +02:00
Emmanuel Papin 33f7342cec Enable plugin support on legacy debian folder and add a missing conditional build in zm_monitor.cpp 2015-05-30 00:30:35 +02:00
Emmanuel Papin de2ec868b4 Merge branch 'fix_iostream_include' into plugin_support
Conflicts:
	src/zm_image_analyser.h
2015-05-29 23:49:10 +02:00
Emmanuel Papin 746deece73 Rename some files, remove links to unused libraries on binaries and some cleanup 2015-05-29 22:26:11 +02:00
Emmanuel Papin eff56664c3 Merge branch 'master' of https://github.com/ZoneMinder/ZoneMinder into plugin_support
Conflicts:
	web/lang/de_de.php
	web/skins/classic/views/monitor.php
	web/skins/classic/views/plugin.php
2015-05-28 23:43:13 +02:00
Emmanuel Papin 0135b90cf6 Merge branch 'master' of https://github.com/ZoneMinder/ZoneMinder into plugin_support 2015-05-16 08:09:48 +02:00
Emmanuel Papin eb9e01eb00 Increase height of plugin window 2015-05-16 07:36:08 +02:00
Emmanuel Papin 2b770b2f58 Add an error message if plugin option is not valid 2015-05-16 06:12:38 +02:00
Emmanuel Papin 0241f844d2 Add space in array formatting 2015-05-15 08:11:51 +02:00
Emmanuel Papin 775da60382 Remove any call to ['Name'] 2015-05-14 20:49:36 +02:00
Emmanuel Papin 7766ec4c72 Rename debian dev package 2015-05-14 14:10:46 +02:00
Emmanuel Papin 676968ed04 Add list option for plugins 2015-05-14 11:38:38 +02:00
Emmanuel Papin 6b2c435460 Merge branch 'master' of https://github.com/ZoneMinder/ZoneMinder into plugin_support_list
Conflicts:
	scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in
2015-05-14 11:12:38 +02:00
Emmanuel Papin 49116a27d7 Fix a conflict with php variable 2015-05-06 23:16:09 +02:00
Emmanuel Papin 6a8eb03f0a Do not delete newly added file 2015-05-06 22:03:58 +02:00
Emmanuel Papin 96ebac4f49 Remove duplicated string 2015-05-06 20:50:17 +02:00
Emmanuel Papin 55d974a0b3 Update lang files 2015-05-06 20:46:09 +02:00
Emmanuel Papin 5283369ed6 Reintroduce modif after upstream merge 2015-05-06 01:03:36 +02:00
Emmanuel Papin 630c8f335f Merge master 2015-05-05 23:37:20 +02:00
Emmanuel Papin 56b724e161 Fix text formatting in event's note 2015-03-08 14:33:55 +01:00
Emmanuel Papin 63158ebe7d Improve management of plugin options 2015-03-08 13:13:49 +01:00
Emmanuel Papin 7fd2f367c6 Fix plugin output to event note 2015-03-07 21:46:01 +01:00
Emmanuel Papin 0988eaeb06 Merge branch 'master' of https://github.com/ZoneMinder/ZoneMinder into plugin_support 2015-03-07 14:44:05 +01:00
Emmanuel Papin a4e4db31bc Delete event data in event class, not in plugin function 2015-03-07 14:42:01 +01:00
Emmanuel Papin 40c3ba1ed3 Readd zone name in event's notes 2015-03-07 11:48:47 +01:00
Emmanuel Papin cdcac7726b Merge branch 'master' into plugin_support 2015-02-28 12:19:28 +01:00
Emmanuel Papin 0840d31011 Fix configure.ac file 2015-02-27 20:54:35 +01:00
Emmanuel Papin b1dbb23f13 Merge branch 'master' into plugin_support_test 2015-02-27 19:46:55 +01:00
Emmanuel Papin 9929233e75 Merge branch 'master' into plugin_support_test
Conflicts:
	configure.ac
	web/lang/fr_fr.php
2015-02-25 23:14:25 +01:00
Emmanuel Papin 5060fc490f Merge branch 'master' into plugin_support_test 2015-02-15 15:03:23 +01:00
Emmanuel Papin 8610f48afd Fix some type errors and remove an unneeded call to onCreateEvent 2015-02-15 14:58:51 +01:00
Emmanuel Papin e7b1ab54df Merge branch 'master' into plugin_support 2015-01-28 19:09:14 +01:00
Emmanuel Papin bfef99fc6f Do not delete the monitor directory in event path, this introduces so much troubles... 2015-01-27 21:11:00 +01:00
Emmanuel Papin 7c0dfe9a5b Merge branch 'plugin_support_new' into plugin_support
Conflicts:
	distros/debian8/changelog
2015-01-27 19:28:42 +01:00
Emmanuel Papin 4bbf1439bb Update debian changelog file 2015-01-27 19:24:50 +01:00
Emmanuel Papin cd16b7168e Merge branch 'master' into plugin_support
Conflicts:
	distros/debian8/changelog
2015-01-27 19:22:06 +01:00
Emmanuel Papin 9360837d38 Add a DeleteEvent function to Event cpp class 2015-01-26 21:13:05 +01:00
Emmanuel Papin 35ed0b475c Move a global static declaration to main binary source files. Yes this duplicates coding lines, but this allows to load plugins without destroying the variable allocation in zm binaries. 2015-01-26 20:12:20 +01:00
Emmanuel Papin a7b912b1b5 Fix call to onCloseEvent 2015-01-17 21:54:47 +01:00
Emmanuel Papin 7906307580 Fix compilation errors 2015-01-17 19:04:20 +01:00
Emmanuel Papin 53c8a3073f Update debian changelog file 2015-01-17 18:41:18 +01:00
Emmanuel Papin 9cc53883ab Merge branch 'debian_package_split' into plugin_support_new
Conflicts:
	distros/debian8/changelog
2015-01-17 18:34:11 +01:00
Emmanuel Papin 70a062a609 Remove image argument in new functions 2015-01-17 18:30:24 +01:00
Emmanuel Papin 2227d9c852 Add new fuctions for plugins 2015-01-15 16:51:46 +01:00
Emmanuel Papin abddb5d916 Readd commit 60b69a4174 from upstream master 2015-01-13 01:18:56 +01:00
Emmanuel Papin ce90a37bb8 Merge branch 'debian_package_split' into plugin_support
Conflicts:
	distros/debian8/patches/series
2015-01-13 01:11:04 +01:00
Emmanuel Papin 77138c48d2 Fix a conflict in php lang files after merge from upstream master 2015-01-10 17:55:46 +01:00
Emmanuel Papin b5ab290e78 Merge branch 'master' of https://github.com/manupap1/ZoneMinder into plugin_support
Conflicts:
	web/lang/et_ee.php
2015-01-10 17:47:30 +01:00
Emmanuel Papin 72d1581f44 Display plugins with zmu even if plugin loading is not enabled 2015-01-04 14:44:43 +01:00
Emmanuel Papin 491df7671d Fix a typo error in a variable name 2015-01-04 14:01:01 +01:00
Emmanuel Papin 39e6de8f68 Fix conflict when merging from master 2015-01-04 12:29:20 +01:00
Emmanuel Papin f551b50ec0 Merge branch 'master' of https://github.com/manupap1/ZoneMinder into plugin_support
Conflicts:
	distros/debian8/patches/01_vendor-perl.diff
	distros/debian8/patches/series
2015-01-04 12:23:29 +01:00
Emmanuel Papin 7fc359e940 Merge branch 'master' of https://github.com/manupap1/ZoneMinder into plugin_support 2015-01-03 13:46:41 +01:00
Emmanuel Papin 8619ed1322 Only load plugins when it is necessary 2015-01-01 22:33:03 +01:00
Emmanuel Papin cdfb4b4bb5 Merge branch 'plugin_support_basic' into plugin_support
Conflicts:
	distros/debian8/zoneminder.dirs
2015-01-01 19:13:53 +01:00
Emmanuel Papin ee259be366 Remove unwanted modification in configure.ac 2015-01-01 19:11:53 +01:00
Emmanuel Papin d070b36aec Merge branch 'master' of https://github.com/manupap1/ZoneMinder into plugin_support 2014-12-31 12:23:26 +01:00
Emmanuel Papin 091b31ae93 Fix conflicts when merging master 2014-12-31 12:22:55 +01:00
Emmanuel Papin 45edab3ad9 Merge branch 'master' of https://github.com/manupap1/ZoneMinder into plugin_support_basic
Conflicts:
	distros/debian/control
	distros/debian8/zoneminder.dirs
	web/skins/classic/views/js/Makefile.am
2014-12-31 12:20:56 +01:00
Emmanuel Papin a9986d6aa0 Merge branch 'debian_package_split' into plugin_support 2014-12-28 11:09:42 +01:00
Emmanuel Papin e08c706d3c Fix text encoding in french lang file 2014-12-22 02:45:01 +01:00
Emmanuel Papin 54d8e103d9 Replace short php tags in plugin.php 2014-12-22 00:28:16 +01:00
Emmanuel Papin fe0476f36b Revert commit 123326c299 2014-12-21 21:20:36 +01:00
Emmanuel Papin d9bcf3aeef Fix bad declaration in zm_detector.h 2014-12-21 20:54:42 +01:00
Emmanuel Papin 7c3ddece88 Remove some remaining files auto-generated by libtool in rules file 2014-12-21 18:50:04 +01:00
Emmanuel Papin bc89082548 Refresh a patch in the debian directory 2014-12-21 18:23:51 +01:00
Emmanuel Papin c1d7d7c744 Try to fix 'ltmain.sh not found' issue at first compilation 2014-12-21 17:40:08 +01:00
Emmanuel Papin d2b1bfae13 Fix conflict when merging debian_package_split 2014-12-21 17:04:46 +01:00
Emmanuel Papin db61f93c35 Merge branch 'debian_package_split' into plugin_support_test
Conflicts:
	distros/debian8/control
2014-12-21 16:56:10 +01:00
Emmanuel Papin 39d270a8c3 Fixed autotools build to reflect file name change 2014-12-21 16:52:01 +01:00
Emmanuel Papin cb3b8a901e Merge branch 'master' into plugin_support_test
Conflicts:
	distros/debian/control
	web/skins/classic/views/js/Makefile.am
2014-12-21 16:49:25 +01:00
Emmanuel Papin 3b4d08be81 Merge branch 'plugin_support' into plugin_support_test 2014-12-14 00:39:10 +01:00
Emmanuel Papin f79887d453 Update version in configure.ac and CMakeLists.txt 2014-12-14 00:37:54 +01:00
Emmanuel Papin b4f35c20f1 Fix a conflict when merging plugin_support 2014-12-13 22:06:30 +01:00
Emmanuel Papin f339518787 Merge branch plugin_support 2014-12-13 22:05:11 +01:00
Emmanuel Papin bff7fc1e2e Enable build of plugin support and dev package in debian8 folder 2014-12-13 21:58:17 +01:00
Emmanuel Papin 208c72b25e Add sql request for plugin support in existing sql update file 2014-12-13 21:51:48 +01:00
Emmanuel Papin f1ce69a8c1 Update version in changelog for plugin support 2014-12-13 21:49:08 +01:00
Emmanuel Papin 7bc44a22e6 Merge branch 'debconf_support' of https://github.com/manupap1/ZoneMinder into debconf_support 2014-12-13 21:41:11 +01:00
Emmanuel Papin 82ef0edac3 Restore conflictuous modifications for plugin support 2014-12-13 20:02:58 +01:00
Emmanuel Papin d961831355 Fix conflict when merging upstream master 2014-12-13 19:54:54 +01:00
Emmanuel Papin ee6fda5c67 Merge branch 'master' into debconf_support 2014-12-12 23:22:10 +01:00
Emmanuel Papin 3d65f2150d Rename SQL update file 2014-11-30 00:31:51 +01:00
Emmanuel Papin a3473b8414 Switch database engine to InnoDB for table PluginsConfig 2014-11-29 23:23:59 +01:00
Emmanuel Papin 3a51926954 Fix SQL error 'key specification without a key length' when updating the database 2014-11-29 23:07:58 +01:00
Emmanuel Papin c7fb522563 Add a sql file to update database from 1.28.0 2014-11-29 22:33:12 +01:00
Emmanuel Papin e37793f79a Upgrade version to force database update 2014-11-29 22:28:56 +01:00
Emmanuel Papin 9e39924095 Fix confict when pulling master 2014-11-29 19:11:22 +01:00
Emmanuel Papin a4c01435d7 Fix confict when pulling master 2014-11-29 03:37:06 +01:00
Emmanuel Papin dde1e13f22 Merge branch 'master' into plugin_support 2014-11-21 14:02:12 +01:00
Emmanuel Papin b5aa7371ad Add a zoneminder development package for debian 2014-11-20 00:04:16 +01:00
Emmanuel Papin 06e31f807f Do not display the note when updating event (size may exceed buffer capacity) 2014-11-19 11:13:25 +01:00
Emmanuel Papin 166b4586aa Fix an issue when updating the reference image 2014-11-19 10:50:41 +01:00
Emmanuel Papin fab48b904f Add some debugging information for reference images 2014-11-19 10:40:16 +01:00
Emmanuel Papin 123326c299 Standardize calls to image pointer 2014-11-19 10:18:11 +01:00
Emmanuel Papin ef452cb986 Fix event logging to database 2014-11-17 17:32:55 +01:00
Emmanuel Papin a03b3ce4e0 Increase buffer size for sql events 2014-11-17 00:21:03 +01:00
Emmanuel Papin ecd9ab95eb Fix error messages when loading plugins 2014-11-16 21:50:39 +01:00
Emmanuel Papin e7f1c8b5d8 Fix logging issue with plugins 2014-11-16 20:46:24 +01:00
manupap1 dac1756d0d Merge branch 'master' of https://github.com/ZoneMinder/ZoneMinder into plugin_support 2014-11-14 10:55:05 +01:00
manupap1 cee8b77bec Add plugin translations in language files 2014-11-12 10:20:18 +01:00
manupap1 eae1357a45 Support plugins in web user interface 2014-11-12 00:53:53 +01:00
manupap1 6d083fef10 Add libzmplugins.pc to .gitignore 2014-11-12 00:12:51 +01:00
manupap1 2a3068cfa7 Add an option to display the status of plugins in zmu 2014-11-12 00:11:41 +01:00
manupap1 f4bdee108f Add more files to .gitignore 2014-11-11 23:55:23 +01:00
manupap1 2033918b24 Add a pkg-config file 2014-11-11 23:53:09 +01:00
manupap1 7ff86427b3 Add config options for plugins in web ui 2014-11-11 23:40:42 +01:00
manupap1 65915c10e3 Update database schema for plugins 2014-11-11 23:35:01 +01:00
manupap1 003fafbf7d Build a convenience library for plugin development 2014-11-11 23:28:12 +01:00
manupap1 731fa96fdf Load plugins in Monitor class 2014-11-11 23:06:50 +01:00
manupap1 12f0177f14 Add plugin options in configure 2014-11-11 23:03:25 +01:00
manupap1 2796995d29 Update ImageAnalyser class 2014-11-11 22:46:58 +01:00
manupap1 199f399caf Add new files for plugin management 2014-11-11 22:39:20 +01:00
manupap1 15532e2a03 Fix issues with event notes 2014-11-11 22:31:58 +01:00
manupap1 5d5d9c5009 Add support for event with multiple causes 2014-11-11 22:08:55 +01:00
manupap1 217aafee5a Set a reference image for each zone 2014-11-11 21:48:56 +01:00
manupap1 0d430b5f4f Add new files to .gitignore 2014-11-11 21:47:42 +01:00
manupap1 9bfc64c4f9 Install the global plugin configuration file 2014-11-11 21:24:20 +01:00
manupap1 03d03bda21 Add a global configuration file for plugins 2014-11-11 20:59:58 +01:00
manupap1 e60c3d552c Remove unwanted dependencies 2014-11-11 20:24:48 +01:00
manupap1 26608afa2d Remove obsolete declaration 2014-11-11 19:49:28 +01:00
manupap1 93a29545ce Add libtool support for plugins 2014-11-11 19:46:20 +01:00
133 changed files with 4214 additions and 259 deletions

8
.gitignore vendored
View File

@ -20,11 +20,16 @@ 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/libzoneminder.pc
misc/logrotate.conf
misc/syslog.conf
misc/plugins.conf
onvif/modules/MYMETA.json
onvif/modules/MYMETA.yml
onvif/proxy/MYMETA.json
@ -56,6 +61,9 @@ scripts/zmvideo.pl
scripts/zmwatch.pl
scripts/zmx10.pl
src/.deps/
src/.libs/
src/*.la
src/*.lo
src/*.o
src/zm_config.h
src/zm_config_defines.h

View File

@ -5,6 +5,8 @@
cmake_minimum_required (VERSION 2.6)
project (zoneminder)
set(zoneminder_VERSION "1.29.0")
# Engine version is used for external plugin compilation
set(ZM_ENGINE_VERSION 29)
# make API version a minor of ZM version
set(zoneminder_API_VERSION "${zoneminder_VERSION}.1")
@ -69,12 +71,14 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
# Modules that we need:
include (GNUInstallDirs)
include (CheckIncludeFile)
include (CheckIncludeFileCXX)
include (CheckIncludeFiles)
include (CheckFunctionExists)
include (CheckPrototypeDefinition_fixed)
include (CheckTypeSize)
include (CheckStructHasMember)
include (CheckSendfile)
include (FindPkgConfig)
# Configuration options
mark_as_advanced(
@ -85,7 +89,13 @@ mark_as_advanced(
ZM_PERL_MM_PARMS
ZM_PERL_SEARCH_PATH
ZM_TARGET_DISTRO
ZM_CONFIG_DIR)
ZM_CONFIG_DIR
ZM_PLUGIN_SUPPORT
ZM_PLUGIN_COMPIL
ZM_PLUGINSLIBDIR
ZM_PLUGINSPKGLIBDIR
ZM_PLUGINSCONFDIR
ZM_PLUGINSWEBDIR)
set(ZM_RUNDIR "/var/run/zm" CACHE PATH
"Location of transient process files, default: /var/run/zm")
@ -147,7 +157,28 @@ set(ZM_PERL_SEARCH_PATH "" CACHE PATH
where ZM_PERL_MM_PARMS has been modified such that ZoneMinder's Perl modules are
installed outside Perl's default search path.")
set(ZM_TARGET_DISTRO "" CACHE STRING
"Build ZoneMinder for a specific distribution. Currently, valid names are: f22, f23, el6, el7, OS13")
"Build ZoneMinder for a specific distribution. Currently, valid names are: f21, f22, el6, el7, OS13")
set(ZM_PLUGIN_SUPPORT "OFF" CACHE BOOL
"Set to ON to enable plugin support in ZoneMinder. This is EXPERIMENTAL, default: OFF")
set(ZM_PLUGIN_COMPIL "OFF" CACHE BOOL
"Set to ON to enable compilation of internal plugins. This is EXPERIMENTAL, default: OFF")
if(ZM_PLUGIN_SUPPORT)
set(ZM_PREFIX ${CMAKE_INSTALL_PREFIX})
set(ZM_PLUGINSLIBDIR "\${prefix}/${CMAKE_INSTALL_LIBDIR}" CACHE PATH
"Location of the plugin development library, default: ${CMAKE_INSTALL_LIBDIR}")
set(ZM_PLUGINSPKGLIBDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBEXECDIR}/zoneminder/plugins" CACHE PATH
"Location of the plugin file, default: <prefix>/${CMAKE_INSTALL_LIBEXECDIR}/zoneminder/plugins")
set(ZM_PLUGINSCONFDIR "/${CMAKE_INSTALL_SYSCONFDIR}/plugins.d" CACHE PATH
"Location of the plugin configuration files, default: /${CMAKE_INSTALL_SYSCONFDIR}/plugins.d")
set(ZM_PLUGINSWEBDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/zoneminder/plugins" CACHE PATH
"Location of the plugin web files, default: <prefix>/${CMAKE_INSTALL_DATADIR}/zoneminder/plugins")
set(ZM_PROJECTNAME ${CMAKE_PROJECT_NAME})
set(ZM_PLUGINSEXT ".so" CACHE STRING
"Plugin extension, default: .so")
add_definitions(-DDEFAULT_PLUGIN_EXT=\"${ZM_PLUGIN_EXT}\")
add_definitions(-DZM_PLUGINS_ON=1)
endif(ZM_PLUGIN_SUPPORT)
# Reassign some variables if a target distro has been specified
if((ZM_TARGET_DISTRO STREQUAL "f22") OR (ZM_TARGET_DISTRO STREQUAL "f23"))
@ -247,6 +278,7 @@ find_package(ZLIB)
if(ZLIB_FOUND)
set(HAVE_LIBZLIB 1)
list(APPEND ZM_BIN_LIBS "${ZLIB_LIBRARIES}")
set(LIBS "${LIBS} -lz")
include_directories("${ZLIB_INCLUDE_DIR}")
set(CMAKE_REQUIRED_INCLUDES "${ZLIB_INCLUDE_DIR}")
check_include_file("zlib.h" HAVE_ZLIB_H)
@ -262,6 +294,7 @@ if(NOT ZM_NO_CURL)
if(CURL_FOUND)
set(HAVE_LIBCURL 1)
list(APPEND ZM_BIN_LIBS ${CURL_LIBRARIES})
set(LIBS "${LIBS} -lcurl")
include_directories(${CURL_INCLUDE_DIRS})
set(CMAKE_REQUIRED_INCLUDES ${CURL_INCLUDE_DIRS})
check_include_file("curl/curl.h" HAVE_CURL_CURL_H)
@ -276,6 +309,7 @@ find_package(JPEG)
if(JPEG_FOUND)
set(HAVE_LIBJPEG 1)
list(APPEND ZM_BIN_LIBS "${JPEG_LIBRARIES}")
set(LIBS "${LIBS} -ljpeg")
#link_directories(${JPEG_LIBRARY})
include_directories("${JPEG_INCLUDE_DIR}")
set(CMAKE_REQUIRED_INCLUDES "${JPEG_INCLUDE_DIR}")
@ -295,6 +329,7 @@ if(OPENSSL_FOUND)
set(HAVE_LIBOPENSSL 1)
set(HAVE_LIBCRYPTO 1)
list(APPEND ZM_BIN_LIBS "${OPENSSL_LIBRARIES}")
set(LIBS "${LIBS} -lssl -lcrypto")
include_directories("${OPENSSL_INCLUDE_DIR}")
set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}")
check_include_file("openssl/md5.h" HAVE_OPENSSL_MD5_H)
@ -308,6 +343,7 @@ find_library(PTHREAD_LIBRARIES pthread)
if(PTHREAD_LIBRARIES)
set(HAVE_LIBPTHREAD 1)
list(APPEND ZM_BIN_LIBS "${PTHREAD_LIBRARIES}")
set(LIBS "${LIBS} -lpthread")
find_path(PTHREAD_INCLUDE_DIR pthread.h)
if(PTHREAD_INCLUDE_DIR)
include_directories("${PTHREAD_INCLUDE_DIR}")
@ -329,6 +365,7 @@ find_library(PCRE_LIBRARIES pcre)
if(PCRE_LIBRARIES)
set(HAVE_LIBPCRE 1)
list(APPEND ZM_BIN_LIBS "${PCRE_LIBRARIES}")
set(LIBS "${LIBS} -lpcre")
find_path(PCRE_INCLUDE_DIR pcre.h)
if(PCRE_INCLUDE_DIR)
include_directories("${PCRE_INCLUDE_DIR}")
@ -346,6 +383,7 @@ find_library(GCRYPT_LIBRARIES gcrypt)
if(GCRYPT_LIBRARIES)
set(HAVE_LIBGCRYPT 1)
list(APPEND ZM_BIN_LIBS "${GCRYPT_LIBRARIES}")
set(LIBS "${LIBS} -lgcrypt")
find_path(GCRYPT_INCLUDE_DIR gcrypt.h)
if(GCRYPT_INCLUDE_DIR)
include_directories("${GCRYPT_INCLUDE_DIR}")
@ -367,6 +405,7 @@ endif(NOT GNUTLS_LIBRARIES)
if(GNUTLS_LIBRARIES)
set(HAVE_LIBGNUTLS 1)
list(APPEND ZM_BIN_LIBS "${GNUTLS_LIBRARIES}")
set(LIBS "${LIBS} -lgnutls-openssl")
find_path(GNUTLS_INCLUDE_DIR gnutls/gnutls.h)
if(GNUTLS_INCLUDE_DIR)
include_directories("${GNUTLS_INCLUDE_DIR}")
@ -385,6 +424,7 @@ find_library(MYSQLCLIENT_LIBRARIES mysqlclient PATH_SUFFIXES mysql)
if(MYSQLCLIENT_LIBRARIES)
set(HAVE_LIBMYSQLCLIENT 1)
list(APPEND ZM_BIN_LIBS "${MYSQLCLIENT_LIBRARIES}")
set(LIBS "${LIBS} -lmysqlclient")
find_path(MYSQLCLIENT_INCLUDE_DIR mysql/mysql.h)
if(MYSQLCLIENT_INCLUDE_DIR)
include_directories("${MYSQLCLIENT_INCLUDE_DIR}")
@ -410,6 +450,7 @@ if(NOT ZM_NO_FFMPEG)
if(AVFORMAT_LIBRARIES)
set(HAVE_LIBAVFORMAT 1)
list(APPEND ZM_BIN_LIBS "${AVFORMAT_LIBRARIES}")
set(LIBS "${LIBS} -lavformat")
find_path(AVFORMAT_INCLUDE_DIR "libavformat/avformat.h" /usr/include/ffmpeg)
if(AVFORMAT_INCLUDE_DIR)
include_directories("${AVFORMAT_INCLUDE_DIR}")
@ -427,6 +468,7 @@ if(NOT ZM_NO_FFMPEG)
if(AVCODEC_LIBRARIES)
set(HAVE_LIBAVCODEC 1)
list(APPEND ZM_BIN_LIBS "${AVCODEC_LIBRARIES}")
set(LIBS "${LIBS} -lavcodec")
find_path(AVCODEC_INCLUDE_DIR "libavcodec/avcodec.h" /usr/include/ffmpeg)
if(AVCODEC_INCLUDE_DIR)
include_directories("${AVCODEC_INCLUDE_DIR}")
@ -444,6 +486,7 @@ if(NOT ZM_NO_FFMPEG)
if(AVDEVICE_LIBRARIES)
set(HAVE_LIBAVDEVICE 1)
list(APPEND ZM_BIN_LIBS "${AVDEVICE_LIBRARIES}")
set(LIBS "${LIBS} -lavdevice")
find_path(AVDEVICE_INCLUDE_DIR "libavdevice/avdevice.h" /usr/include/ffmpeg)
if(AVDEVICE_INCLUDE_DIR)
include_directories("${AVDEVICE_INCLUDE_DIR}")
@ -461,6 +504,7 @@ if(NOT ZM_NO_FFMPEG)
if(AVUTIL_LIBRARIES)
set(HAVE_LIBAVUTIL 1)
list(APPEND ZM_BIN_LIBS "${AVUTIL_LIBRARIES}")
set(LIBS "${LIBS} -lavutil")
find_path(AVUTIL_INCLUDE_DIR "libavutil/avutil.h" /usr/include/ffmpeg)
if(AVUTIL_INCLUDE_DIR)
include_directories("${AVUTIL_INCLUDE_DIR}")
@ -479,6 +523,7 @@ if(NOT ZM_NO_FFMPEG)
if(SWSCALE_LIBRARIES)
set(HAVE_LIBSWSCALE 1)
list(APPEND ZM_BIN_LIBS "${SWSCALE_LIBRARIES}")
set(LIBS "${LIBS} -lswscale")
find_path(SWSCALE_INCLUDE_DIR "libswscale/swscale.h" /usr/include/ffmpeg)
if(SWSCALE_INCLUDE_DIR)
include_directories("${SWSCALE_INCLUDE_DIR}")
@ -510,6 +555,7 @@ if(NOT ZM_NO_LIBVLC)
if(LIBVLC_LIBRARIES)
set(HAVE_LIBVLC 1)
list(APPEND ZM_BIN_LIBS "${LIBVLC_LIBRARIES}")
set(LIBS "${LIBS} -lvlc")
find_path(LIBVLC_INCLUDE_DIR "vlc/vlc.h")
if(LIBVLC_INCLUDE_DIR)
include_directories("${LIBVLC_INCLUDE_DIR}")
@ -523,6 +569,29 @@ if(NOT ZM_NO_LIBVLC)
endif(LIBVLC_LIBRARIES)
endif(NOT ZM_NO_LIBVLC)
if(ZM_PLUGIN_COMPIL)
if(PKG_CONFIG_FOUND)
pkg_search_module(opencv opencv>=2.3.1)
if(NOT opencv_FOUND)
message(FATAL_ERROR "opencv.pc not found")
endif(NOT opencv_FOUND)
else(PKG_CONFIG_FOUND)
message(FATAL_ERROR "pkg-config not found")
endif(PKG_CONFIG_FOUND)
find_package(OpenCV COMPONENTS core imgproc highgui objdetect REQUIRED)
if(OpenCV_FOUND)
include_directories(${OpenCV_INCLUDE_DIR})
else(OpenCV_FOUND)
message(FATAL_ERROR "Cannot build application without OpenCV. Please set OpenCV_INCLUDE_DIR.")
endif(OpenCV_FOUND)
find_package(Boost COMPONENTS program_options REQUIRED)
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIR})
else(Boost_FOUND)
message(FATAL_ERROR "Cannot build application without Boost. Please set Boost_INCLUDE_DIR.")
endif(Boost_FOUND)
endif(ZM_PLUGIN_COMPIL)
# *** END OF LIBRARY CHECKS ***
# Check for gnutls or crypto
@ -611,6 +680,29 @@ if(HAVE_LIBCRYPTO AND HAVE_OPENSSL_MD5_H AND HAVE_MD5_OPENSSL)
set(HAVE_GNUTLS_OPENSSL_H 0)
endif(HAVE_LIBCRYPTO AND HAVE_OPENSSL_MD5_H AND HAVE_MD5_OPENSSL)
if(ZM_PLUGIN_COMPIL)
check_include_file_cxx("alpr.h" HAVE_ALPR_H)
if(NOT HAVE_ALPR_H)
message(FATAL_ERROR "Missing include file alpr.h")
endif(NOT HAVE_ALPR_H)
check_include_file_cxx("opencv2/core/core.hpp" HAVE_OPENCV2_CORE_CORE_HPP)
if(NOT HAVE_OPENCV2_CORE_CORE_HPP)
message(FATAL_ERROR "Missing include file opencv2/core/core.hpp")
endif(NOT HAVE_OPENCV2_CORE_CORE_HPP)
check_include_file_cxx("opencv2/imgproc/imgproc.hpp" HAVE_OPENCV2_IMGPROC_IMGPROC_HPP)
if(NOT HAVE_OPENCV2_IMGPROC_IMGPROC_HPP)
message(FATAL_ERROR "Missing include file opencv2/imgproc/imgproc.hpp")
endif(NOT HAVE_OPENCV2_IMGPROC_IMGPROC_HPP)
check_include_file_cxx("boost/algorithm/string.hpp" HAVE_BOOST_ALGORITHM_STRING_HPP)
if(NOT HAVE_BOOST_ALGORITHM_STRING_HPP)
message(FATAL_ERROR "Missing include file boost/algorithm/string.hpp")
endif(NOT HAVE_BOOST_ALGORITHM_STRING_HPP)
check_include_file_cxx("boost/program_options.hpp" HAVE_BOOST_PROGRAM_OPTIONS_HPP)
if(NOT HAVE_BOOST_PROGRAM_OPTIONS_HPP)
message(FATAL_ERROR "Missing include file boost/program_options.hpp")
endif(NOT HAVE_BOOST_PROGRAM_OPTIONS_HPP)
endif(ZM_PLUGIN_COMPIL)
# Check for Perl
find_package(Perl)
if(NOT PERL_FOUND)
@ -707,6 +799,11 @@ if(ZM_ONVIF)
add_subdirectory(onvif)
endif(ZM_ONVIF)
# Enable compilation of internal plugins
if(ZM_PLUGIN_COMPIL)
add_subdirectory(plugins)
endif(ZM_PLUGIN_COMPIL)
# Process distro subdirectories
if((ZM_TARGET_DISTRO STREQUAL "f22") OR (ZM_TARGET_DISTRO STREQUAL "f23"))
add_subdirectory(distros/fedora)
@ -734,6 +831,11 @@ endif(zmconfgen_result EQUAL 0)
# Install zm.conf
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm.conf" DESTINATION "${ZM_CONFIG_DIR}")
if(ZM_PLUGIN_SUPPORT)
# Install config.h
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/config.h" DESTINATION include/zoneminder)
endif(ZM_PLUGIN_SUPPORT)
# Uninstall target
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"

19
db/feature-plugins.sql Normal file
View File

@ -0,0 +1,19 @@
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

@ -386,6 +386,7 @@ CREATE TABLE `Monitors` (
`WebColour` varchar(32) NOT NULL default 'red',
`Exif` tinyint(1) unsigned NOT NULL default '0',
`Sequence` smallint(5) unsigned default NULL,
`DoNativeMotDet` tinyint(3) unsigned NOT NULL default '1',
PRIMARY KEY (`Id`)
) ENGINE=@ZM_MYSQL_ENGINE@;
@ -544,6 +545,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

@ -68,3 +68,11 @@ 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: libzoneminder-dev
Section: libdevel
Architecture: any
Depends: ${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/*/libzoneminder.a
usr/lib/*/pkgconfig/libzoneminder.pc

View File

@ -28,7 +28,7 @@ endif
dh $@ --with quilt,autoreconf
override_dh_auto_configure:
CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" dh_auto_configure -- --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --sysconfdir=/etc/zm --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --with-mysql=/usr --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
CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" dh_auto_configure -- --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --sysconfdir=/etc/zm --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --with-mysql=/usr --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 --enable-plugin-support --with-pluginsdir=/usr/lib/zoneminder/plugins
override_dh_clean:
# Add here commands to clean up after the build process.

View File

View File

@ -1,3 +1,10 @@
zoneminder (1.28.1+nmu1) experimental; urgency=medium
* Non-maintainer upload.
* Add plugin support
-- Emmanuel Papin <manupap01@gmail.com> Tue, 27 Jan 2015 19:23:07 +0100
zoneminder (1.28.0+nmu1) testing; urgency=medium
* Non-maintainer upload

View File

@ -2,7 +2,7 @@ Source: zoneminder
Section: net
Priority: optional
Maintainer: Isaac Connor <iconnor@connortechnology.com>
Build-Depends: debhelper (>= 9), po-debconf (>= 1.0), dh-systemd (>= 1.5), autoconf, automake, libphp-serialization-perl, libgnutls28-dev, libmysqlclient-dev | libmariadbclient-dev, libdbd-mysql-perl, libdate-manip-perl, libwww-perl, libjpeg8-dev | libjpeg9-dev | libjpeg62-turbo-dev, libpcre3-dev, libavcodec-dev, libavformat-dev (>= 3:0.svn20090204), libswscale-dev (>= 3:0.svn20090204), libavutil-dev, libv4l-dev (>= 0.8.3), libbz2-dev, libtool, libsys-mmap-perl, libnetpbm10-dev, libavdevice-dev, libdevice-serialport-perl, libarchive-zip-perl, libmime-lite-perl, dh-autoreconf, libvlccore-dev, libvlc-dev, libcurl4-gnutls-dev | libcurl4-nss-dev | libcurl4-openssl-dev, libgcrypt11-dev | libgcrypt20-dev, libpolkit-gobject-1-dev, libdbi-perl, libnet-sftp-foreign-perl, libexpect-perl, libmime-tools-perl
Build-Depends: debhelper (>= 9), po-debconf (>= 1.0), dh-systemd (>= 1.5), autoconf, automake, libphp-serialization-perl, libgnutls28-dev, libmysqlclient-dev | libmariadbclient-dev, libdbd-mysql-perl, libdate-manip-perl, libwww-perl, libjpeg8-dev | libjpeg9-dev | libjpeg62-turbo-dev, libpcre3-dev, libavcodec-dev, libavformat-dev (>= 3:0.svn20090204), libswscale-dev (>= 3:0.svn20090204), libavutil-dev, libv4l-dev (>= 0.8.3), libbz2-dev, libtool, libsys-mmap-perl, libnetpbm10-dev, libavdevice-dev, libdevice-serialport-perl, libarchive-zip-perl, libmime-lite-perl, dh-autoreconf, libvlccore-dev, libvlc-dev, libcurl4-gnutls-dev | libcurl4-nss-dev | libcurl4-openssl-dev, libgcrypt11-dev | libgcrypt20-dev, libpolkit-gobject-1-dev, libdbi-perl, libnet-sftp-foreign-perl, libexpect-perl, libmime-tools-perl, libopenalpr-dev (>= 2.0.0), libboost-program-options1.55-dev, libopencv-dev, libopencv-core-dev, libopencv-imgproc-dev
Standards-Version: 3.9.6
Package: zoneminder
@ -13,7 +13,9 @@ Depends: ${misc:Depends},
zoneminder-database (>= ${source:Version}),
zoneminder-core (>= ${binary:Version}),
zoneminder-ui-base (>= ${source:Version}),
zoneminder-ui-classic (>= ${source:Version})
zoneminder-ui-classic (>= ${source:Version}),
zoneminder-ui-mobile (>= ${source:Version}),
zoneminder-ui-xml (>= ${source:Version})
Description: Video camera security and surveillance solution (metapackage)
ZoneMinder is intended for use in single or multi-camera video security
applications, including commercial or home CCTV, theft prevention and child
@ -38,6 +40,15 @@ Description: Perl libraries for ZoneMinder
This package provides the libraries for the perl scripts, it can be used to
write custom interfaces as well.
Package: libzoneminder-dev
Section: libdevel
Architecture: any
Depends: ${misc:Depends}
Description: Development library for ZoneMinder plugins
ZoneMinder is a video camera security and surveillance solution.
.
This package provides the necessary files to develop video analysis plugins.
Package: zoneminder-database
Section: database
Architecture: all
@ -101,3 +112,12 @@ Description: Classic web user interface for ZoneMinder
ZoneMinder is a video camera security and surveillance solution.
.
This package provides the classic web user interface.
Package: libzoneminder-plugin-openalpr
Section: libs
Architecture: any
Depends: zoneminder-core (= ${binary:Version}), ${shlibs:Depends},
${misc:Depends}
Description: License Plate Recognition plugin with openalpr library
This plugin add support for recognition of license plate number in zoneminder
with the use of the OpenALPR library.

View File

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

View File

@ -0,0 +1,4 @@
usr/lib/zoneminder/plugins/libzm_plugin_openalpr.so
usr/share/zoneminder/plugins/libzm_plugin_openalpr/config.php
usr/share/zoneminder/plugins/libzm_plugin_openalpr/lang/*_*.php
etc/zm/plugins.d/openalpr.conf

View File

@ -53,7 +53,9 @@ 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 \
--enable-plugin-compilation=yes
override_dh_clean:
# Add here commands to clean up after the build process.
@ -72,6 +74,9 @@ override_dh_clean:
done || true
override_dh_install:
# Clean up libtool crap
find debian/tmp -name '*.la' -exec rm '{}' ';'
#
dh_install --fail-missing
#
# NOTE: This is a short-term kludge; hopefully changes in the next

View File

@ -1,4 +1,5 @@
etc/zm
etc/zm/plugins.conf
etc/zm/zm.conf
usr/bin
usr/share/polkit-1/actions
usr/share/polkit-1/rules.d

View File

@ -1,3 +1,5 @@
usr/share/zoneminder/db
usr/share/dbconfig-common/data/zoneminder/install
usr/share/dbconfig-common/data/zoneminder/upgrade/mysql
etc/zm/plugins.d
usr/share/zoneminder/plugins

View File

@ -69,3 +69,11 @@ 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: libzoneminder-dev
Section: libdevel
Architecture: any
Depends: ${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/*/libzoneminder.a
usr/lib/*/pkgconfig/libzoneminder.pc

View File

@ -22,7 +22,9 @@ override_dh_auto_configure:
-DZM_CGIDIR=/usr/lib/zoneminder/cgi-bin \
-DZM_WEB_USER=www-data \
-DZM_WEB_GROUP=www-data \
-DCMAKE_INSTALL_SYSCONFDIR=etc/zm
-DCMAKE_INSTALL_SYSCONFDIR=etc/zm \
-DZM_PLUGIN_SUPPORT=ON \
-DZM_PLUGINSPKGLIBDIR=/usr/lib/zoneminder/plugins
override_dh_auto_install:
dh_auto_install --buildsystem=cmake

View File

@ -16,3 +16,12 @@ configure_file(zoneminder-tmpfiles.conf.in "${CMAKE_CURRENT_BINARY_DIR}/zonemind
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/com.zoneminder.systemctl.policy" DESTINATION "${PC_POLKIT_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/polkit-1/actions")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/com.zoneminder.systemctl.rules" DESTINATION "${PC_POLKIT_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/polkit-1/rules.d")
if(ZM_PLUGIN_SUPPORT)
configure_file(plugins.conf.in "${CMAKE_CURRENT_BINARY_DIR}/plugins.conf" @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/plugins.conf" DESTINATION "${ZM_CONFIG_DIR}")
include(FindPkgConfig QUIET)
if(PKG_CONFIG_FOUND)
configure_file(libzoneminder.pc.in "${CMAKE_CURRENT_BINARY_DIR}/libzoneminder.pc" @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libzoneminder.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
endif()
endif(ZM_PLUGIN_SUPPORT)

17
misc/libzoneminder.pc.in Normal file
View File

@ -0,0 +1,17 @@
prefix = @ZM_PREFIX@
exec_prefix = ${prefix}
libdir = @ZM_PLUGINSLIBDIR@
pkglibdir = @ZM_PLUGINSPKGLIBDIR@
includedir = ${prefix}/include
sysconfdir = @ZM_PLUGINSCONFDIR@
webdir = @ZM_PLUGINSWEBDIR@
Name: @ZM_PROJECTNAME@
Description: ZoneMinder convenience library for plugin development.
Version: @VERSION@
Requires:
Requires.private:
Conflicts:
Libs: -L${libdir} -lzoneminder @LIBS@
Libs.private:
Cflags: -I${includedir}/zoneminder

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
# ...

4
plugins/CMakeLists.txt Normal file
View File

@ -0,0 +1,4 @@
# CMakeLists.txt for the plugins directory
# Process subdirectories
add_subdirectory(libzm_plugin_openalpr)

4
plugins/Makefile.am Normal file
View File

@ -0,0 +1,4 @@
AUTOMAKE_OPTIONS = gnu
SUBDIRS = \
libzm_plugin_openalpr

View File

@ -0,0 +1,6 @@
# CMakeLists.txt for openalpr plugin.
# Created by Emmanuel Papin (manupap01@gmail.com)
# Process subdirectories
add_subdirectory(data)
add_subdirectory(src)

View File

@ -0,0 +1,5 @@
AUTOMAKE_OPTIONS = foreign
SUBDIRS = \
data \
src

View File

@ -0,0 +1,71 @@
libzm-plugin-openalpr
=====================
## Overview
libzm-plugin-openalpr is a plugin for Automatic Licence Plate Recognition (ALPR).
The recognized license plates are added to Zoneminder's event notes.
## Requirements
libzm-plugin-openalpr is based on the OpenALPR library.
Currently this library is not packaged in distributions but it can be built and installed following the instructions on github project page (https://github.com/openalpr/openalpr).
## Configuration
After installation, please make some adjustments in file `/etc/zm/plugins.d/openalpr.conf`.
Most of default values can be kept, but if you live in Europe, you can set the `country_code` setting to `eu` to improve reading of plates with EU format
All the next configuration steps are done through the web interface.
Firstly, the plugin loading has to be enabled in ZM options (please check the `LOAD_PLUGIN` setting in `Config` tab).
Then, you can configure the plugin settings from each `Zone` configuration page.
![Zone](https://github.com/manupap1/libzoneminder-plugin-openalpr/blob/master/misc/zone.png)
Available plugins are listed with a color code under the `Plugins` row:
- `Default color` - Plugin is not enabled for the zone
- `Green` - Plugin is enabled for the zone
- `Grey` - Plugin loading is disabled (please check `LOAD_PLUGIN` setting in `Config` tab)
- `Orange` - Plugin is enabled for the zone but not active (configuration setting mismatch)
- `Red` - ZoneMinder failed to load the plugin object (software error)
Once a plugin object is loaded, the `Plugin` configuration page is accessed by clicking on the plugin name.
![Plugin](https://github.com/manupap1/libzoneminder-plugin-openalpr/blob/master/misc/plugin.png)
The first options are available for all plugins:
- `Enabled` - A yes/no select box to enable or disable the plugin
- `Require Native Detection` - A yes/no select box to specify if native detection is required before to process plugin analysis. This option allow to limit CPU usage by using the plugin for post processing after native detection. This option is recommended for this plugin as it may use a lot of CPU ressources
- `Include Native Detection` - A yes/no select box to specify if native detection shall be included in alarm score and image overlay
- `Reinit. Native Detection` - A yes/no select box to specify if native detection shall be reinitialized after detection. ZoneMinder's native detection is performed by comparing the current image to a reference image. By design, the reference image is assigned when analysis is activated, and this image is not periodically refreshed. This operating method is not necessarily optimal because some plugins may require native detection only when motion is truly detected (current image different from the previous image). This option is recommended for libzoneminder-plugin-openalpr. For example, without this option enabled, if a vehicle appears and parks in the camera field of view, the native detection will be be triggered as long as the vehicle is parked, and therefore the plugin analysis would be performed for an unnecessary period of time. With this option enabled, the plugin analysis stops when the vehicle stops.
- `Alarm Score` - A text box to enter the score provided by the plugin in case of detection
The next options are specifics to this plugin and can be used to adjust the detection accuracy:
- `Minimum Confidence` - A text box to enter the minimum confidence level. All plates with a lower confidence level will be excluded.
- `Min. Number of Characters` - A text box to enter the minimum number of characters in a license plate. All plates with a lower number of detected characters will be excluded.
- `Max. Number of Characters` - A text box to enter the maximum number of characters in a license plate. All plates with a greater number of detected characters will be excluded.
- `List of Targeted Plates` - A list to specify targeted plates (detected plates will have a 100% confidence).
- `Detect only Targeted Plates` - A yes/no select box to specify if plates not in target list shall be ignored.
- `Strict Targeting` - A yes/no select box to specify if target matching shall be strict (plates must match exactly).
- `Assume target matching` - When strict targeting is off plates included in wider strings are detected (within the max. number of characters limit). This yes/no select box allow to specify if such detected plates shall be considered as being equal to the target. If yes is selected, the plugin will report these plates with the target string and with a 100% confidence. If no is selected, the plugin will report these plates individually. This option can be helpfull if the plate format includes a field for a logo which may be considered as a character by openalpr.
The configuration is saved to the database and applied when clicking on the `Save` button.
## Using
When a license plate is detected, this triggers an event with alarmed frame(s).
Depending on your configuration settings and video content, an event may contain multiple alarmed frames.
![Events](https://github.com/manupap1/libzoneminder-plugin-openalpr/blob/master/misc/events.png)
Licenses plates are stored in the event note field accessible by a click on the event detection cause.
![Event](https://github.com/manupap1/libzoneminder-plugin-openalpr/blob/master/misc/event.png)
Alarmed frames are highlighted with the plate's detection area(s).
![Frame](https://github.com/manupap1/libzoneminder-plugin-openalpr/blob/master/misc/frame.png)
The detected plate number(s) can be added in email or sms notifications by using the %ED% token in EMAIL_BODY or MESSAGE_BODY option.

View File

@ -0,0 +1,5 @@
# CMakeLists.txt for openalpr plugin.
install (FILES openalpr.conf DESTINATION ${ZM_PLUGINSCONFDIR})
install (FILES config.php DESTINATION "${ZM_PLUGINSWEBDIR}/libzm_plugin_openalpr")
install (FILES en_gb.php fr_fr.php DESTINATION "${ZM_PLUGINSWEBDIR}/libzm_plugin_openalpr/lang")

View File

@ -0,0 +1,14 @@
AUTOMAKE_OPTIONS = foreign
sysconfdir = @ZM_PLUGINSCONFDIR@
sysconf_DATA = \
openalpr.conf
webdir = @ZM_PLUGINSWEBDIR@/libzm_plugin_openalpr
dist_web_DATA = \
config.php
langdir = $(webdir)/lang
dist_lang_DATA = \
en_gb.php \
fr_fr.php

View File

@ -0,0 +1,85 @@
<?php
/* *****************************************************************************
* Copyright (C) 2014 Emmanuel Papin <manupap01@gmail.com>
*
* Authors: Emmanuel Papin <manupap01@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
* ****************************************************************************/
$pluginOptions = array(
'MinConfidence' => array(
'Type' => 'integer',
'Min' => '0',
'Max' => '100',
'Value' => '0',
'Require' => array(
array(
'Name' => 'OnlyTargets',
'Value' => 'No',
),
),
),
'MinCharacters' => array(
'Type' => 'integer',
'Min' => '1',
'Max' => '20',
'Value' => '1',
'Require' => array(
array(
'Name' => 'OnlyTargets',
'Value' => 'No',
),
),
),
'MaxCharacters' => array(
'Type' => 'integer',
'Min' => '1',
'Max' => '20',
'Value' => '20',
'Require' => array(
array(
'Name' => 'StrictTargets',
'Value' => 'No',
),
),
),
'TargetList' => array(
'Type' => 'list',
),
'OnlyTargets' => array(
'Type' => 'select',
'Choices' => 'Yes,No',
'Value'=> 'No',
),
'StrictTargets' => array(
'Type' => 'select',
'Choices' => 'Yes,No',
'Value'=> 'No',
),
'AssumeTargets' => array(
'Type' => 'select',
'Choices' => 'Yes,No',
'Value'=> 'No',
'Require' => array(
array(
'Name' => 'StrictTargets',
'Value' => 'No',
),
),
),
);
?>

View File

@ -0,0 +1,33 @@
<?php
/* *****************************************************************************
* Copyright (C) 2014 Emmanuel Papin <manupap01@gmail.com>
*
* Authors: Emmanuel Papin <manupap01@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
* ****************************************************************************/
$PLANG = array(
'AssumeTargets' => 'Assume target matching',
'MaxCharacters' => 'Max. Number of Characters',
'MinCharacters' => 'Min. Number of Characters',
'MinConfidence' => 'Minimum Confidence',
'OnlyTargets' => 'Detect only Targeted Plates',
'StrictTargets' => 'Strict Targeting',
'TargetList' => 'List of Targeted Plates',
);
?>

View File

@ -0,0 +1,33 @@
<?php
/* *****************************************************************************
* Copyright (C) 2014 Emmanuel Papin <manupap01@gmail.com>
*
* Authors: Emmanuel Papin <manupap01@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
* ****************************************************************************/
$PLANG = array(
'AssumeTargets' => 'Supposer la correspondance',
'MaxCharacters' => 'Nombre max. de caractères',
'MinCharacters' => 'Nombre min. de caractères',
'MinConfidence' => 'Confiance minimum',
'OnlyTargets' => 'Détecter seul. plaques ciblées',
'StrictTargets' => 'Ciblage strict',
'TargetList' => 'Liste de plaques ciblées',
);
?>

View File

@ -0,0 +1,24 @@
# The options commented out show the default values
[libzm_plugin_openalpr]
# Path to the openalpr.conf file (used by openalpr library)
config_file = /etc/openalpr/openalpr.conf
# Country code to identify (either us for USA or eu for Europe)
#country_code = us
# Attempt to match the plate number against a region template (e.g., md for Maryland, ca for California)
#template_region =
# Max number of possible plate numbers to return
#topn = 10
# Attempt to detect the region of the plate image
#detect_region = false
# Detection cause for ZM events
#det_cause = Plate Detected
# Prefix for plugin entries in ZM log files
#log_prefix = OPENALPR PLUGIN

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 700 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@ -0,0 +1,17 @@
# CMakeLists.txt for openalpr plugin.
add_library(zm_plugin_openalpr SHARED openalpr_plugin.cpp)
include_directories(${zoneminder_SOURCE_DIR}/src ${zoneminder_BINARY_DIR}/src)
target_link_libraries(
zm_plugin_openalpr -lopenalpr -lboost_program_options -lopencv_core
-lopencv_imgproc)
# Do not set the soname when linking the plugin binary.
# Definition of a soname version in a plugin prevents some tools
# (like dpkg-shlibdeps for debian) to clearly identify the binary as a plugin.
# This results in a bunch of unwanted warnings about unresolvable reference to
# symbols (which are provided by the program that loads this plugins).
set_property(TARGET zm_plugin_openalpr PROPERTY NO_SONAME 1)
install (TARGETS zm_plugin_openalpr DESTINATION ${ZM_PLUGINSPKGLIBDIR})

View File

@ -0,0 +1,24 @@
AUTOMAKE_OPTIONS = gnu
pkglibdir = @ZM_PLUGINSPKGLIBDIR@
pkglib_LTLIBRARIES = libzm_plugin_openalpr.la
# This prevents to link the plugin with unnecessary libraries
LIBS=
AM_CPPFLAGS = \
-I$(top_srcdir)/src $(opencv_CFLAGS)
libzm_plugin_openalpr_la_SOURCES = \
openalpr_plugin.cpp
libzm_plugin_openalpr_la_LDFLAGS = \
-avoid-version -module -shared -export-dynamic
libzm_plugin_openalpr_la_LIBADD = \
@OPENALPR_LIBS@ @BOOST_PROGRAM_OPTION_LIBS@ @OPENCV_CORE_LIBS@ \
@OPENCV_IMGPROC_LIBS@
noinst_HEADERS = \
openalpr_plugin.h

View File

@ -0,0 +1,455 @@
/*****************************************************************************
* Copyright (C) 2014 Emmanuel Papin <manupap01@gmail.com>
*
* Authors: Emmanuel Papin <manupap01@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include "openalpr_plugin.h"
using namespace alpr;
using namespace boost::program_options;
//! Retrieve the engine version we're going to expect
extern "C" int getEngineVersion()
{
return ZM_ENGINE_VERSION;
}
//! Tells us to register our functionality to an engine kernel
extern "C" void registerPlugin(PluginManager &PlM, std::string sPluginName)
{
PlM.getImageAnalyser().addDetector(std::auto_ptr<Detector>(new OpenALPRPlugin(sPluginName)));
}
OpenALPRPlugin::OpenALPRPlugin()
: Detector(),
m_sConfigFilePath(DEFAULT_CONFIG_FILE),
m_sCountry(DEFAULT_COUNTRY_CODE),
m_sRegionTemplate(DEFAULT_TEMPLATE_REGION),
m_nMaxPlateNumber(DEFAULT_TOPN),
m_bRegionIsDet(DEFAULT_DETECT_REGION)
{
m_sDetectionCause = DEFAULT_DETECTION_CAUSE;
m_sLogPrefix = DEFAULT_PLUGIN_LOG_PREFIX;
Info("%s: Plugin object has been created", m_sLogPrefix.c_str());
}
OpenALPRPlugin::OpenALPRPlugin(std::string sPluginName)
: Detector(sPluginName),
m_sConfigFilePath(DEFAULT_CONFIG_FILE),
m_sCountry(DEFAULT_COUNTRY_CODE),
m_sRegionTemplate(DEFAULT_TEMPLATE_REGION),
m_nMaxPlateNumber(DEFAULT_TOPN),
m_bRegionIsDet(DEFAULT_DETECT_REGION)
{
m_sDetectionCause = DEFAULT_DETECTION_CAUSE;
m_sLogPrefix = DEFAULT_PLUGIN_LOG_PREFIX;
Info("%s: Plugin object has been created", m_sLogPrefix.c_str());
}
/*! \fn OpenALPRPlugin::loadConfig(std::string sConfigFileName, std::map<unsigned int,std::map<std::string,std::string> > mapPluginConf)
* \param sConfigFileName is path to configuration to load parameters from
* \param mapPluginConf is the map of configuration parameters for each zone
*/
int OpenALPRPlugin::loadConfig(std::string sConfigFileName, std::map<unsigned int,std::map<std::string,std::string> > mapPluginConf)
{
try
{
options_description config_file("Configuration file options.");
variables_map vm;
config_file.add_options()
((m_sConfigSectionName + std::string(".config_file")).c_str(),
value<std::string>()->default_value(DEFAULT_CONFIG_FILE))
((m_sConfigSectionName + std::string(".country_code")).c_str(),
value<std::string>()->default_value(DEFAULT_COUNTRY_CODE))
((m_sConfigSectionName + std::string(".template_region")).c_str(),
value<std::string>()->default_value(DEFAULT_TEMPLATE_REGION))
((m_sConfigSectionName + std::string(".topn")).c_str(),
value<int>()->default_value(DEFAULT_TOPN))
((m_sConfigSectionName + std::string(".detect_region")).c_str(),
value<bool>()->default_value(DEFAULT_DETECT_REGION))
((m_sConfigSectionName + std::string(".det_cause")).c_str(),
value<std::string>()->default_value(DEFAULT_DET_CAUSE))
((m_sConfigSectionName + std::string(".log_prefix")).c_str(),
value<std::string>()->default_value(DEFAULT_PLUGIN_LOG_PREFIX));
try
{
std::ifstream ifs(sConfigFileName.c_str());
store(parse_config_file(ifs, config_file, false), vm);
notify(vm);
}
catch(error& er)
{
Error("%s: Plugin is not configured (%s)", m_sLogPrefix.c_str(), er.what());
return 0;
}
m_sConfigFilePath = vm[(m_sConfigSectionName + std::string(".config_file")).c_str()].as<std::string>();
m_sCountry = vm[(m_sConfigSectionName + std::string(".country_code")).c_str()].as<std::string>();
m_sRegionTemplate = vm[(m_sConfigSectionName + std::string(".template_region")).c_str()].as<std::string>();
m_nMaxPlateNumber = vm[(m_sConfigSectionName + std::string(".topn")).c_str()].as<int>();
m_bRegionIsDet = vm[(m_sConfigSectionName + std::string(".detect_region")).c_str()].as<bool>();
m_sDetectionCause = vm[(m_sConfigSectionName + std::string(".det_cause")).c_str()].as<std::string>();
m_sLogPrefix = vm[(m_sConfigSectionName + std::string(".log_prefix")).c_str()].as<std::string>();
}
catch(std::exception& ex)
{
Error("%s: Plugin is not configured (%s)", m_sLogPrefix.c_str(), ex.what());
return 0;
}
pConf pluginConf;
for (std::map<unsigned int,std::map<std::string,std::string> >::iterator it = mapPluginConf.begin(); it != mapPluginConf.end(); ++it) {
while ( pluginConfig.size() < (it->first + 1) )
pluginConfig.push_back(pluginConf);
// Overwrite default values with database values
for (std::map<std::string,std::string>::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) {
if (it2->second.empty()) continue;
if (it2->first == "AlarmScore") {
pluginConfig[it->first].alarmScore = (unsigned int)strtoul(it2->second.c_str(), NULL, 0);
} else if (it2->first == "AssumeTargets") {
if (it2->second == "Yes") {
pluginConfig[it->first].assumeTargets = true;
} else {
pluginConfig[it->first].assumeTargets = false;
}
} else if (it2->first == "MaxCharacters") {
pluginConfig[it->first].maxCharacters = (unsigned int)strtoul(it2->second.c_str(), NULL, 0);
} else if (it2->first == "MinCharacters") {
pluginConfig[it->first].minCharacters = (unsigned int)strtoul(it2->second.c_str(), NULL, 0);
} else if (it2->first == "MinConfidence") {
pluginConfig[it->first].minConfidence = (unsigned int)strtoul(it2->second.c_str(), NULL, 0);
} else if (it2->first == "OnlyTargets") {
if (it2->second == "Yes") {
pluginConfig[it->first].onlyTargets = true;
} else {
pluginConfig[it->first].onlyTargets = false;
}
} else if (it2->first == "StrictTargets") {
if (it2->second == "Yes") {
pluginConfig[it->first].strictTargets = true;
} else {
pluginConfig[it->first].strictTargets = false;
}
} else if (it2->first == "TargetList") {
boost::split(pluginConfig[it->first].targetList, it2->second, boost::is_any_of(","));
}
}
}
// Create an instance of class Alpr and set basic configuration
ptrAlpr = new Alpr(m_sCountry, m_sConfigFilePath);
ptrAlpr->setTopN(m_nMaxPlateNumber);
if ( m_bRegionIsDet )
ptrAlpr->setDetectRegion(m_bRegionIsDet);
if ( !m_sRegionTemplate.empty() )
ptrAlpr->setDefaultRegion(m_sRegionTemplate);
// Initialize some lists
int nb_zones = pluginConfig.size();
plateList.resize(nb_zones);
tmpPlateList.resize(nb_zones);
if ( ptrAlpr->isLoaded() ) {
Info("%s: Plugin is configured", m_sLogPrefix.c_str());
} else {
Error("%s: Plugin is not configured (%s)", m_sLogPrefix.c_str(), strerror(errno));
delete ptrAlpr;
return 0;
}
return 1;
}
OpenALPRPlugin::~OpenALPRPlugin()
{
delete ptrAlpr;
}
/*! \fn OpenALPRPlugin::OpenALPRPlugin(const OpenALPRPlugin& source)
* \param source is the object for copying
*/
OpenALPRPlugin::OpenALPRPlugin(const OpenALPRPlugin& source)
: Detector(source),
m_sConfigFilePath(source.m_sConfigFilePath),
m_sCountry(source.m_sCountry),
m_sRegionTemplate(source.m_sRegionTemplate),
m_nMaxPlateNumber(source.m_nMaxPlateNumber),
m_bRegionIsDet(source.m_bRegionIsDet)
{
}
/*! \fn OpenALPRPlugin:: operator=(const OpenALPRPlugin& source)
* \param source is the object for copying
*/
OpenALPRPlugin & OpenALPRPlugin:: operator=(const OpenALPRPlugin& source)
{
Detector::operator=(source);
m_sConfigFilePath = source.m_sConfigFilePath;
m_sCountry = source.m_sCountry;
m_sRegionTemplate = source.m_sRegionTemplate;
m_nMaxPlateNumber = source.m_nMaxPlateNumber;
m_bRegionIsDet = source.m_bRegionIsDet;
return *this;
}
/*! \fn OpenALPRPlugin::onCreateEvent(Zone *zone, unsigned int n_zone, Event *event)
* \param zone is a pointer to the zone that triggered the event
* \param n_zone is the zone id
* \param event is a pointer the new event
*/
void OpenALPRPlugin::onCreateEvent(Zone *zone, unsigned int n_zone, Event *event)
{
Debug(1, "%s: Zone %s - Prepare plugin for event %d", m_sLogPrefix.c_str(), zone->Label(), event->Id());
/* Note: Do not clear the plate list here because in case of post processing
* the plate list is filled with results of first detection before
* event creation */
}
/*! \fn OpenALPRPlugin::onCloseEvent(Zone *zone, unsigned int n_zone, Event *event, std::string noteText)
* \param zone is a pointer to the zone that triggered the event
* \param n_zone is the zone id
* \param event is a pointer to the event that will be closed
* \param noteText is a string that can be used to output text to the event note
*/
void OpenALPRPlugin::onCloseEvent(Zone *zone, unsigned int n_zone, Event *event, std::string &noteText)
{
// Set the number of plates to output and exit if nothing to do
unsigned int topn = ( m_nMaxPlateNumber < plateList[n_zone].size() ) ? m_nMaxPlateNumber : plateList[n_zone].size();
if (topn == 0) return;
// Sort plates according confidence level (higher first)
sort(plateList[n_zone].begin(), plateList[n_zone].end(), sortByConf());
Info("%s: Zone %s - Add plates to event %d", m_sLogPrefix.c_str(), zone->Label(), event->Id());
// Output only the first topn plates to the event note
for(unsigned int i=0; i<topn;i++)
{
std::stringstream plate;
plate << plateList[n_zone][i].num << " (" << plateList[n_zone][i].conf << ")";
Debug(1, "%s: Zone %s - Plate %s detected", m_sLogPrefix.c_str(), zone->Label(), plate.str().c_str());
noteText += " " + plate.str() + "\n";
}
// Reset the lists for next use
plateList[n_zone].clear();
tmpPlateList[n_zone].clear();
}
/*! \fn OpenALPRPlugin::checkZone(Zone *zone, const Image *zmImage)
* \param zone is a zone where license plates will be detected
* \param n_zone is the zone id
* \param zmImage is an image to perform license plate detection (in the form of ZM' Image)
* \return true if there were objects detected in given image and false otherwise
*/
bool OpenALPRPlugin::checkZone(Zone *zone, unsigned int n_zone, const Image *zmImage)
{
Polygon zone_polygon = Polygon(zone->GetPolygon()); // Polygon of interest of the processed zone.
Image *pMaskImage = new Image(zmImage->Width(), zmImage->Height(), ZM_COLOUR_GRAY8, ZM_SUBPIX_ORDER_NONE );
pMaskImage->Fill(BLACK);
// An temporary image in the form of ZM for making from it CvMat.
// If don't use temp image, after rgb->bgr it will change.
Image *tempZmImage = new Image(*zmImage);
int imgtype=CV_8UC1;
if (tempZmImage->Colours() == ZM_COLOUR_RGB24)
imgtype=CV_8UC3;
cv::Mat cvInputImage = cv::Mat(
tempZmImage->Height(),
tempZmImage->Width(),
imgtype, (unsigned char*)tempZmImage->Buffer()).clone();
if (tempZmImage->Colours() == ZM_COLOUR_RGB24)
cvtColor(cvInputImage, cvInputImage, CV_RGB2BGR);
//Process image
//std::vector<unsigned char> buffer;
//cv::imencode(".bmp", cvInputImage, buffer);
std::vector<AlprRegionOfInterest> regionsOfInterest;
regionsOfInterest.push_back(AlprRegionOfInterest(0,0, cvInputImage.cols, cvInputImage.rows));
// Region of interest don't work as expected
//std::vector<AlprResults> results = ptrAlpr->recognize(buffer, regionsOfInterest);
AlprResults results = ptrAlpr->recognize(cvInputImage.data, cvInputImage.elemSize(), cvInputImage.cols, cvInputImage.rows, regionsOfInterest);
double score = 0;
for (unsigned int i = 0; i < results.plates.size(); i++) {
int x1 = results.plates[i].plate_points[0].x, y1 = results.plates[i].plate_points[0].y;
int x2 = results.plates[i].plate_points[1].x, y2 = results.plates[i].plate_points[1].y;
int x3 = results.plates[i].plate_points[2].x, y3 = results.plates[i].plate_points[2].y;
int x4 = results.plates[i].plate_points[3].x, y4 = results.plates[i].plate_points[3].y;
Coord rectVertCoords[4] = {Coord(x1, y1), Coord(x2, y2), Coord(x3, y3), Coord(x4, y4)};
int nNumVertInside = 0;
for (int p = 0; p < 4; p++)
nNumVertInside += zone_polygon.isInside(rectVertCoords[p]);
// if at least three rectangle coordinates are inside polygon,
// consider rectangle as belonging to the zone
// otherwise process next object
if (nNumVertInside < 3)
{
Debug(1, "%s: Zone %s - Skip result (outside detection zone)", m_sLogPrefix.c_str(), zone->Label());
continue;
}
int cntDetPlates = 0;
for (unsigned int k = 0; k < results.plates[i].topNPlates.size(); k++)
{
strPlate detPlate;
detPlate.num = results.plates[i].topNPlates[k].characters;
detPlate.conf = results.plates[i].topNPlates[k].overall_confidence;
bool isTarget = false;
// Check targeted plates first
for (std::vector<std::string>::iterator it = pluginConfig[n_zone].targetList.begin(); it != pluginConfig[n_zone].targetList.end(); ++it)
{
// If plates match, add targeted plate and continue with next detected plate
if (*it == detPlate.num)
{
detPlate.conf = 100;
addPlate(zone, n_zone, detPlate);
cntDetPlates++;
isTarget = true;
break;
}
// Check if targeted plate is a substring of the detected plate
else if (detPlate.num.find(*it) != std::string::npos)
{
// If yes and strict targeting is on, disqualify targeted plate
if (pluginConfig[n_zone].strictTargets)
{
Debug(1, "%s: Zone %s - Skip targeted plate %s (strict targeting is on)", m_sLogPrefix.c_str(), zone->Label(), detPlate.num.c_str());
// And continue with next targeted plate (maybe another in the list will strictly match)
continue;
}
// If yes but detected plate has too much characters, disqualify targeted plate
if (detPlate.num.size() > pluginConfig[n_zone].maxCharacters)
{
Debug(1, "%s: Zone %s - Skip targeted plate %s (number of characters is out of range)", m_sLogPrefix.c_str(), zone->Label(), detPlate.num.c_str());
// And continue with next detected plate (this one is not valid)
break;
}
// Overwrite detected plate by target if we assume the matching is correct
if (pluginConfig[n_zone].assumeTargets)
{
detPlate.conf = 100;
detPlate.num = *it;
}
// Add targeted plate to list and continue with next detected plate
addPlate(zone, n_zone, detPlate);
cntDetPlates++;
isTarget = true;
break;
}
}
// Skip detected plate if already added or if only targeted plates are accepted
if (isTarget || pluginConfig[n_zone].onlyTargets)
continue;
// Disqualify plate if under the minimum confidence level
if (detPlate.conf < pluginConfig[n_zone].minConfidence)
{
Debug(1, "%s: Zone %s - Skip plate %s (under minimum confidence level)", m_sLogPrefix.c_str(), zone->Label(), detPlate.num.c_str());
continue;
}
// Disqualify plate if not enough characters or too much characters
if ((detPlate.num.size() < pluginConfig[n_zone].minCharacters)
|| (detPlate.num.size() > pluginConfig[n_zone].maxCharacters))
{
Debug(1, "%s: Zone %s - Skip plate %s (number of characters is out of range)", m_sLogPrefix.c_str(), zone->Label(), detPlate.num.c_str());
continue;
}
// Add plate to list (if already in list, update confidence by adding new value)
addPlate(zone, n_zone, detPlate);
cntDetPlates++;
}
if (cntDetPlates == 0)
continue;
// Raise an alarm if at least one plate has been detected
score = pluginConfig[n_zone].alarmScore;
// Fill a polygon with object in the mask
Polygon platePolygon = Polygon(4, rectVertCoords);
pMaskImage->Fill(WHITE, 1, platePolygon);
}
if (score == 0) {
delete pMaskImage;
delete tempZmImage;
return false;
}
zone->SetScore((int)score);
//Get mask by highlighting contours of objects and overlaying them with previous contours.
Rgb alarm_colour = RGB_GREEN;
Image *hlZmImage = pMaskImage->HighlightEdges(alarm_colour, ZM_COLOUR_RGB24,
ZM_SUBPIX_ORDER_RGB, &zone_polygon.Extent());
if (zone->Alarmed()) {
// if there were previous detection and they have already set up alarm image
// then overlay it with current mask
Image* pPrevZoneMask = new Image(*(zone->AlarmImage()));
pPrevZoneMask->Overlay(*hlZmImage);
zone->SetAlarmImage(pPrevZoneMask);
delete pPrevZoneMask;
} else
zone->SetAlarmImage(hlZmImage);
delete pMaskImage;
delete tempZmImage;
return true;
}
bool OpenALPRPlugin::addPlate(Zone *zone, unsigned int n_zone, strPlate detPlate)
{
for (std::vector<strPlate>::iterator it = plateList[n_zone].begin(); it != plateList[n_zone].end(); ++it)
{
// If plate number exists in the list for this zone
if ((*it).num == detPlate.num)
{
// Add confidence
(*it).conf += detPlate.conf;
Debug(1, "%s: Zone %s - Raise confidence of plate %s to %f", m_sLogPrefix.c_str(), zone->Label(), (*it).num.c_str(), (*it).conf);
return false;
}
}
// Add a new plate for this zone
Debug(1, "%s: Zone %s - Add plate %s with confidence %f", m_sLogPrefix.c_str(), zone->Label(), detPlate.num.c_str(), detPlate.conf);
plateList[n_zone].push_back(detPlate);
return true;
}

View File

@ -0,0 +1,143 @@
/*****************************************************************************
* Copyright (C) 2014 Emmanuel Papin <manupap01@gmail.com>
*
* Authors: Emmanuel Papin <manupap01@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifndef OPENALPR_PLUGIN_H
#define OPENALPR_PLUGIN_H
#include <stdexcept>
#include <fstream>
#include <algorithm>
#include <alpr.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>
#include <boost/program_options/option.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/errors.hpp>
#include "zm_plugin_manager.h"
#include "zm_detector.h"
#include "zm_rgb.h"
#define DEFAULT_CONFIG_FILE "/etc/openalpr/openalpr.conf"
#define DEFAULT_COUNTRY_CODE "us"
#define DEFAULT_TEMPLATE_REGION ""
#define DEFAULT_TOPN 10
#define DEFAULT_DETECT_REGION 0
#define DEFAULT_DET_CAUSE "Plate Detected"
#define DEFAULT_PLUGIN_LOG_PREFIX "OPENALPR PLUGIN"
#define DEFAULT_ALARM_SCORE 99
#define DEFAULT_ASSUME_TARGETS 0
#define DEFAULT_MAX_CHARACTERS 99
#define DEFAULT_MIN_CHARACTERS 0
#define DEFAULT_MIN_CONFIDENCE 0
#define DEFAULT_ONLY_TARGETS 0
#define DEFAULT_STRICT_TARGETS 0
//! OpenALPR plugin class.
/*! The class derived from Detector.
* This class provides license plate detection based on tesseract OCR.
*/
class OpenALPRPlugin : public Detector {
public:
//! Default Constructor.
OpenALPRPlugin();
//! Constructor.
OpenALPRPlugin(std::string sConfigSectionName);
//! Destructor.
virtual ~OpenALPRPlugin();
//! Copy constructor.
OpenALPRPlugin(const OpenALPRPlugin& source);
//! Overloaded operator=.
OpenALPRPlugin& operator=(const OpenALPRPlugin& source);
int loadConfig(std::string sConfigFileName, std::map<unsigned int,std::map<std::string,std::string> > mapPluginConf);
protected:
void onCreateEvent(Zone *zone, unsigned int n_zone, Event *event);
void onCloseEvent(Zone *zone, unsigned int n_zone, Event *event, std::string &noteText);
bool checkZone(Zone *zone, unsigned int n_zone, const Image *zmImage);
std::string m_sConfigFilePath;
std::string m_sCountry;
std::string m_sRegionTemplate;
unsigned int m_nMaxPlateNumber;
bool m_bRegionIsDet;
private:
alpr::Alpr *ptrAlpr;
struct pConf
{
unsigned int alarmScore;
bool assumeTargets;
unsigned int maxCharacters;
unsigned int minCharacters;
unsigned int minConfidence;
bool onlyTargets;
bool strictTargets;
std::vector<std::string> targetList;
pConf():
alarmScore(DEFAULT_ALARM_SCORE),
assumeTargets(DEFAULT_ASSUME_TARGETS),
maxCharacters(DEFAULT_MAX_CHARACTERS),
minCharacters(DEFAULT_MIN_CHARACTERS),
minConfidence(DEFAULT_MIN_CONFIDENCE),
onlyTargets(DEFAULT_ONLY_TARGETS),
strictTargets(DEFAULT_STRICT_TARGETS)
{}
};
std::vector<pConf> pluginConfig;
struct strPlate
{
std::string num;
float conf;
};
struct sortByConf
{
bool operator()(const strPlate a, const strPlate b) const
{
return a.conf > b.conf;
}
};
std::vector<std::vector<strPlate> > plateList;
std::vector<std::vector<std::string> > tmpPlateList;
bool addPlate(Zone *zone, unsigned int n_zone, strPlate detPlate);
};
#endif // OPENALPR_PLUGIN_H

View File

@ -3825,6 +3825,58 @@ body = "ZM alarm detected - %EL% secs, %EF%/%EFA% frames, t%EST%/m%ESM%/a%ESA% s
readonly => 1,
category => "dynamic",
},
{
name => "ZM_PATH_PLUGINS",
default => "@ZM_PLUGINSPKGLIBDIR@",
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 => "@ZM_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 => "@ZM_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 => qqq("
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

@ -6,6 +6,22 @@ configure_file(zm_config.h.in "${CMAKE_CURRENT_BINARY_DIR}/zm_config.h" @ONLY)
# Group together all the source files that are used by all the binaries (zmc, zma, zmu, zms etc)
set(ZM_BIN_SRC_FILES zm_box.cpp 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 zm_remote_camera_rtsp.cpp zm_rtp.cpp zm_rtp_ctrl.cpp zm_rtp_data.cpp zm_rtp_source.cpp zm_rtsp.cpp zm_rtsp_auth.cpp zm_sdp.cpp zm_signal.cpp zm_stream.cpp zm_thread.cpp zm_time.cpp zm_timer.cpp zm_user.cpp zm_utils.cpp zm_zone.cpp)
if(ZM_PLUGIN_SUPPORT)
set(ZM_BIN_SRC_FILES ${ZM_BIN_SRC_FILES} zm_detector.cpp zm_image_analyser.cpp zm_plugin.cpp zm_plugin_manager.cpp)
endif(ZM_PLUGIN_SUPPORT)
# with -fPIC
IF(UNIX AND NOT WIN32)
FIND_PROGRAM(CMAKE_UNAME uname /bin /usr/bin /usr/local/bin )
IF(CMAKE_UNAME)
EXEC_PROGRAM(uname ARGS -m OUTPUT_VARIABLE CMAKE_SYSTEM_PROCESSOR)
SET(CMAKE_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR} CACHE INTERNAL "processor type (i386 and x86_64)")
IF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
ADD_DEFINITIONS(-fPIC)
ENDIF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
ENDIF(CMAKE_UNAME)
ENDIF(UNIX AND NOT WIN32)
# A fix for cmake recompiling the source files for every target.
add_library(zm STATIC ${ZM_BIN_SRC_FILES})
@ -15,11 +31,11 @@ add_executable(zmu zmu.cpp)
add_executable(zmf zmf.cpp)
add_executable(zms zms.cpp)
target_link_libraries(zmc zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
target_link_libraries(zma zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
target_link_libraries(zmu zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
target_link_libraries(zmf zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
target_link_libraries(zms zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
target_link_libraries(zmc -ldl zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
target_link_libraries(zma -ldl zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
target_link_libraries(zmu -ldl zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
target_link_libraries(zmf -ldl zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
target_link_libraries(zms -ldl zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
# Generate man files for the binaries destined for the bin folder
FOREACH(CBINARY zma zmc zmf zmu)
@ -31,3 +47,8 @@ install(TARGETS zms RUNTIME DESTINATION "${ZM_CGIDIR}" PERMISSIONS OWNER_WRITE O
install(CODE "execute_process(COMMAND ln -sf zms nph-zms WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})" )
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/nph-zms DESTINATION "${ZM_CGIDIR}")
if(ZM_PLUGIN_SUPPORT)
install(FILES jinclude.h zm_db.h zm_detector.h zm_logger.h zm_poly.h zm_mem_utils.h zm_box.h zm_ffmpeg.h zm_plugin_manager.h zm_plugin.h zm_jpeg.h zm_mpeg.h zm_image_analyser.h zm_zone.h zm_rgb.h zm_utils.h zm_event.h zm_stream.h zm_coord.h zm_image.h DESTINATION include/zoneminder)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm_config.h" "${CMAKE_CURRENT_BINARY_DIR}/zm_config_defines.h" DESTINATION include/zoneminder)
install(TARGETS zoneminder ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}")
endif(ZM_PLUGIN_SUPPORT)

View File

@ -20,7 +20,6 @@
#ifndef ZM_BOX_H
#define ZM_BOX_H
#include "zm.h"
#include "zm_coord.h"
#ifndef SOLARIS

View File

@ -20,7 +20,7 @@
#ifndef ZM_BUFFER_H
#define ZM_BUFFER_H
#include "zm.h"
#include "zm_logger.h"
#include <string.h>

View File

@ -21,6 +21,7 @@
#define ZM_COMMS_H
#include "zm_exception.h"
#include "zm_logger.h"
#include <string.h>
#include <unistd.h>

View File

@ -142,8 +142,6 @@ void zmLoadConfig()
}
}
StaticConfig staticConfig;
ConfigItem::ConfigItem( const char *p_name, const char *p_value, const char *const p_type )
{
name = new char[strlen(p_name)+1];

View File

@ -27,6 +27,7 @@
#define ZM_CONFIG "@ZM_CONFIG@" // Path to config file
#define ZM_VERSION "@VERSION@" // ZoneMinder Version
#define ZM_ENGINE_VERSION @ZM_ENGINE_VERSION@ // ZoneMinder engine Version
#define ZM_HAS_V4L1 @ZM_HAS_V4L1@
#define ZM_HAS_V4L2 @ZM_HAS_V4L2@
@ -42,6 +43,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

View File

@ -20,8 +20,6 @@
#ifndef ZM_COORD_H
#define ZM_COORD_H
#include "zm.h"
//
// Class used for storing an x,y pair, i.e. a coordinate
//

256
src/zm_detector.cpp Normal file
View File

@ -0,0 +1,256 @@
#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
*/
std::string Detector::getDetectionCause()
{
return m_sDetectionCause;
}
/*!\fn Detector::getConfigSectionName()
* return plugin name as string
*/
std::string Detector::getPluginName()
{
return m_sConfigSectionName;
}
/*!\fn Detector::EnablePlugin(std::vector<int> zoneList)
* \param vnZoneList is the list of enabled zones for the plugin
*/
void Detector::EnablePlugin(std::vector<unsigned int> vnZoneList)
{
m_vnPluginZones = vnZoneList;
m_bIsPluginEnabled = true;
}
/*!\fn Detector::getPluginZones()
* \return the list of zone which have the plugin enabled
*/
std::vector<unsigned int> Detector::getPluginZones()
{
return m_vnPluginZones;
}
/*! \fn Detector::log(int nLogLevel, std::string sLevel, std::string sMessage)
*/
void Detector::log(int nLogLevel, std::string sLevel, std::string sMessage)
{
std::string sMessageToLog = sLevel + std::string(" [") + m_sLogPrefix + std::string(": ") + sMessage + std::string("]");
syslog(nLogLevel, "%s", sMessageToLog.c_str());
}
/*! \fn int Detector::Detect(const Image &zmImage, Zone** zones, unsigned int &score)
* \param zmImage is an image to detect faces on
* \param zones is the array of detection zones
* \param score is the detection score
* \return true if detection is effective
*/
bool Detector::Detect(const Image &zmImage, Zone** zones, 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();
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();
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();
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();
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;
}
void Detector::_onCreateEvent(Zone** zones, Event* event)
{
for(std::vector<unsigned int>::iterator it = m_vnPluginZones.begin(); it != m_vnPluginZones.end(); ++it)
{
onCreateEvent(zones[*it], *it, event);
}
}
void Detector::_onCloseEvent(Zone** zones, Event* event)
{
for(std::vector<unsigned int>::iterator it = m_vnPluginZones.begin(); it != m_vnPluginZones.end(); ++it)
{
std::string noteText = " [Zone ";
noteText += zones[*it]->Label();
noteText += "]\n";
onCloseEvent(zones[*it], *it, event, noteText);
Event::StringSet noteSet;
noteSet.insert(noteText);
Event::StringSetMap noteSetMap;
noteSetMap[m_sDetectionCause] = noteSet;
event->updateNotes(noteSetMap);
}
}

142
src/zm_detector.h Normal file
View File

@ -0,0 +1,142 @@
#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"
//! 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(std::string sPluginFileName)
{
m_sLogPrefix = DEFAULT_LOG_PREFIX;
char* szPluginFileName = strdup(sPluginFileName.c_str());
std::string sPluginFileNameName = std::string(basename(szPluginFileName));
size_t idx = sPluginFileNameName.rfind('.');
if (idx == std::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, unsigned int &score);
void _onCreateEvent(Zone** zones, Event *event);
void _onCloseEvent(Zone** zones, Event *event);
//! Load detector's parameters.
virtual int loadConfig(std::string sConfigFileName, std::map<unsigned int,std::map<std::string,std::string> > mapPluginConf) = 0;
//! Returns detection case string.
std::string getDetectionCause();
//! Returns plugin name as string.
std::string getPluginName();
//! Enable the plugin for the given zones.
void EnablePlugin(std::vector<unsigned int> zoneList);
//! Return the list of enabled zones
std::vector<unsigned int> getPluginZones();
protected:
//! Do detection inside one given zone.
virtual bool checkZone(Zone *zone, unsigned int n_zone, const Image *zmImage) = 0;
virtual void onCreateEvent(Zone *zone, unsigned int n_zone, Event *event) = 0;
virtual void onCloseEvent(Zone *zone, unsigned int n_zone, Event *event, std::string &noteText) = 0;
//! Log messages to the SYSLOG.
void log(int, std::string sLevel, std::string sMessage);
//! String to be shown as detection cause for event.
std::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.
std::string m_sLogPrefix;
//! Name of config file section to search parameters.
std::string m_sConfigSectionName;
//! List of zones enabled for the plugin
std::vector<unsigned int> m_vnPluginZones;
//! Plugin status regarding zone settings
bool m_bIsPluginEnabled;
};
#endif // ZM_DETECTOR_H

View File

@ -35,6 +35,7 @@
#include "zm_signal.h"
#include "zm_event.h"
#include "zm_monitor.h"
#include "zm_utils.h"
// sendfile tricks
extern "C"
@ -69,6 +70,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 )
@ -77,10 +80,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 ) );
@ -194,7 +197,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 ) );
@ -208,15 +211,138 @@ void Event::createNotes( std::string &notes )
for ( StringSetMap::const_iterator mapIter = noteSetMap.begin(); mapIter != noteSetMap.end(); mapIter++ )
{
notes += mapIter->first;
notes += ": ";
notes += ":\n";
const StringSet &stringSet = mapIter->second;
for ( StringSet::const_iterator setIter = stringSet.begin(); setIter != stringSet.end(); setIter++ )
{
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;
}
}
void Event::Close()
{
if ( ( tot_score == 0 ) && ( alarm_frames == 0 ) )
{
Info( "Delete event's data (empty event)" );
DeleteData();
}
}
// This is the transcription of JavaScript function DeleteEvent()
void Event::DeleteData()
{
static char sql[ZM_SQL_MED_BUFSIZ];
snprintf( sql, sizeof(sql), "DELETE FROM `Events` WHERE `Id` = %d;", id );
if ( mysql_query( &dbconn, sql) )
{
Error( "Can't run query: %s", mysql_error( &dbconn ) );
exit( mysql_errno( &dbconn ) );
}
if ( !config.opt_fast_delete )
{
snprintf( sql, sizeof(sql), "DELETE FROM `Stats` WHERE `EventId` = %d;", id );
if ( mysql_query( &dbconn, sql ) )
{
Error( "Can't run query: %s", mysql_error( &dbconn ) );
exit( mysql_errno( &dbconn ) );
}
snprintf( sql, sizeof(sql), "DELETE FROM `Frames` WHERE `EventId` = %d;", id );
if ( mysql_query( &dbconn, sql ) )
{
Error( "Can't run query: %s", mysql_error( &dbconn ) );
exit( mysql_errno( &dbconn ) );
}
static char dir_events[PATH_MAX] = "";
if ( config.dir_events[0] == '/' )
snprintf( dir_events, sizeof(dir_events), "%s/%d", config.dir_events, monitor->Id() );
else
snprintf( dir_events, sizeof(dir_events), "%s/%s/%d", staticConfig.PATH_WEB.c_str(), config.dir_events, monitor->Id() );
if ( config.use_deep_storage )
{
static char event_glob[PATH_MAX] = "";
snprintf( event_glob, sizeof(event_glob), "%s/%d/*/*/*/.%d", dir_events, monitor->Id(), id );
glob_t pglob;
if( glob( event_glob, GLOB_ONLYDIR, 0, &pglob ) == 0 )
{
char *event_path = pglob.gl_pathv[0];
static char link[PATH_MAX] = "";
ssize_t len;
if ( ( len = readlink(event_path, link, sizeof(link)-1 ) ) )
{
link[len] = '\0';
int last_slash = strrchr( event_path, '/' ) - event_path;
char base_path[PATH_MAX] = "";
strncpy(base_path, event_path, last_slash);
static char link_path[PATH_MAX] = "";
snprintf( link_path, sizeof(link_path), "%s/%s", base_path, link );
// Delete linked folder (remove_dir is called with second
// argument = true to force deletion of folder content)
if (remove_dir(link_path, true, false) < 0)
return;
// Delete symlink
if (unlink(event_path) < 0)
return;
// Now we have successfully deleted all files related to the
// event we can do some cleaning on the storage directory
// The storage folders are scanned from deep to root and
// deleted if empty
for(size_t i=strlen(link_path)-1; i>strlen(dir_events); i--)
{
if(link_path[i] != '/')
continue;
char del_path[PATH_MAX] = "";
strncpy(del_path, link_path, i);
// Deletion is stopped at first non empty folder
// encountered
if(remove_dir(del_path, false, false) < 0)
break;
}
}
else
{
// Delete broken symlink
unlink(event_path);
}
}
}
else
{
static char event_path[PATH_MAX] = "";
snprintf(event_path, sizeof(event_path), "%s/%d/%d", dir_events, monitor->Id(), id);
remove_dir(event_path, true, false);
}
}
}
int Event::sd = -1;
@ -426,12 +552,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 )
@ -480,7 +606,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

@ -34,7 +34,6 @@
#include <set>
#include <map>
#include "zm.h"
#include "zm_image.h"
#include "zm_stream.h"
@ -132,9 +131,12 @@ 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 );
void Close();
private:
void AddFramesInternal( int n_frames, int start_frame, Image **images, struct timeval **timestamps );
void DeleteData();
public:
static const char *getSubPath( struct tm *time )

View File

@ -20,8 +20,6 @@
#ifndef ZM_EXCEPTION_H
#define ZM_EXCEPTION_H
#include "zm.h"
#include <string>
class Exception

View File

@ -20,7 +20,7 @@
#ifndef ZM_FFMPEG_H
#define ZM_FFMPEG_H
#include <stdint.h>
#include "zm.h"
#include "zm_image.h"
#ifdef __cplusplus

View File

@ -20,7 +20,6 @@
#ifndef ZM_IMAGE_H
#define ZM_IMAGE_H
#include "zm.h"
extern "C"
{
#include "zm_jpeg.h"
@ -31,6 +30,7 @@ extern "C"
#include "zm_poly.h"
#include "zm_mem_utils.h"
#include "zm_utils.h"
#include "zm_logger.h"
#include <errno.h>

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
@ -31,34 +41,465 @@ ImageAnalyser::~ImageAnalyser()
delete *It;
}
void ImageAnalyser::onCreateEvent(Zone** zones, Event* event)
{
for ( DetectorsList::iterator It = m_Detectors.begin();
It != m_Detectors.end();
++It )
{
(*It)->_onCreateEvent(zones, event);
}
}
void ImageAnalyser::onCloseEvent(Zone** zones, Event* event)
{
for ( DetectorsList::iterator It = m_Detectors.begin();
It != m_Detectors.end();
++It )
{
(*It)->_onCloseEvent(zones, event);
}
}
/*!\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, std::string& det_cause, unsigned int& score)
* \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, std::string& det_cause, unsigned int& score)
{
Event::StringSet zoneSet;
int score = 0;
score = 0;
bool alarm = false;
for ( DetectorsList::iterator It = m_Detectors.begin();
It != m_Detectors.end();
++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, detect_score ) )
{
alarm = true;
score += detect_score;
noteSetMap[(*It)->getDetectionCause()] = zoneSet;
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 += (*It)->getDetectionCause();
det_cause += new_cause;
}
}
return score;
}
return alarm;
}
/*!\fn ImageAnalyser::configurePlugins(std::string sConfigFileName, bool bDoNativeDet)
*\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(std::string sConfigFileName, bool bDoNativeDet)
{
std::string sLoadedPlugins;
if ( !m_bIsAnalyserEnabled ) return;
m_bIsNativeDetEnabled = bDoNativeDet;
for ( DetectorsList::iterator It = m_Detectors.begin(); It != m_Detectors.end(); ++It )
{
std::string sPluginName = (*It)->getPluginName();
try
{
if ( isValidConfigFile( sPluginName, sConfigFileName ) )
{
Info("Configure plugin '%s' with config file '%s'.", sPluginName.c_str(), sConfigFileName.c_str());
std::map<unsigned int,std::map<std::string,std::string> > mapPluginConf;
std::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(std::string sPluginName, std::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(std::string sPluginName, std::string sConfigFileName)
{
std::ifstream ifs(sConfigFileName.c_str());
std::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 = std::string(dbrow[1]);
zone.type = std::string(dbrow[2]);
m_vMonitorZones.push_back(zone);
}
}
mysql_free_result(result);
return ( m_vMonitorZones.size() );
}
/*!\fn ImageAnalyser::getPluginConfig(std::string sPluginName, std::vector<unsigned int> vnPluginZones, std::map<unsigned int,std::map<std::string,std::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(std::string sPluginName, std::vector<unsigned int> vnPluginZones, std::map<unsigned int,std::map<std::string,std::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)
{
std::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 (std::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++;
std::string name((*it)[1]);
std::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(std::string sPluginName, std::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(std::string sPluginName, std::vector<unsigned int>& vnPluginZones)
{
static char sql[ZM_SQL_MED_BUFSIZ];
bool bPluginEnabled = false;
std::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)
{
std::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);
std::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(std::string sLoadedPlugins)
* \param sLoadedPlugins is the formatted list of loaded plugins
*/
bool ImageAnalyser::getZonesConfig(std::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)
{
std::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 (std::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(std::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(std::string sPluginName, pGenConf& regPluginGenConf)
{
std::map<std::string,pGenConf>::iterator it = mapRegPluginGenConf.find( sPluginName );
if ( it == mapRegPluginGenConf.end() )
return false;
regPluginGenConf = it->second;
return true;
}
/*!\fn ImageAnalyser::getRegPluginZoneConf(std::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(std::string sPluginName, PluginZoneConf& regPluginZoneConf)
{
std::map<std::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()
{
std::string sPluginsToKeep;
std::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 plugin: %s", mysql_error( &dbconn ) );
exit( mysql_errno( &dbconn ) );
}
}

View File

@ -1,30 +1,57 @@
#ifndef ZM_IMAGE_ANALYSER_H
#define ZM_IMAGE_ANALYSER_H
#include <list>
#include <string>
#include <stdexcept>
#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();
@ -35,8 +62,86 @@ class ImageAnalyser {
//! Overloaded operator=.
ImageAnalyser& operator=(const ImageAnalyser& source);
//! Adds new plugin's detector to the list of detectors.
void addDetector(std::auto_ptr<Detector> Det)
{
m_Detectors.push_back(Det.release());
}
void onCreateEvent(Zone** zones, Event* event);
void onCloseEvent(Zone** zones, Event* event);
//! 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(std::string sConfigFileName, bool bDoNativeDet = 0);
//! Check if the configuration file contains the right section name
bool isValidConfigFile(std::string sPluginName, std::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(std::string sPluginName, std::vector<unsigned int> vnPluginZones, std::map<unsigned int,std::map<std::string,std::string> >& mapPluginConf);
//! Get enabled zones for the plugin
bool getEnabledZonesForPlugin(std::string sPluginName, std::vector<unsigned int>& vnPluginZones);
//! Get zones configuration from database
bool getZonesConfig(std::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(std::string sPluginName, pGenConf& regPluginGenConf);
//! Get the zone settings of a registered plugin
void getRegPluginZoneConf(std::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;
std::string name;
};
//! A vector filled with parameters of zones
std::vector<zConf> m_vZonesConfig;
//! A structure to store basic settings of a zone
struct zSetting {
unsigned int id;
std::string name;
std::string type;
};
//! A vector filled with settings of zones enabled for the monitor
std::vector<zSetting> m_vMonitorZones;
//! A map to store the general configuration of registered plugins
std::map<std::string,pGenConf> mapRegPluginGenConf;
//! A map to store the zone configuration of registered plugins
std::map<std::string,PluginZoneConf> mapRegPluginZoneConf;
};

View File

@ -20,7 +20,6 @@
#ifndef ZM_LOCAL_CAMERA_H
#define ZM_LOCAL_CAMERA_H
#include "zm.h"
#include "zm_camera.h"
#include "zm_image.h"

View File

@ -39,9 +39,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

@ -21,7 +21,6 @@
#define ZM_MEM_UTILS_H
#include <stdlib.h>
#include "zm.h"
inline void* zm_mallocaligned(unsigned int reqalignment, size_t reqsize) {
uint8_t* retptr;

View File

@ -70,6 +70,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
//=============================================================================
@ -301,7 +318,8 @@ Monitor::Monitor(
bool p_embed_exif,
Purpose p_purpose,
int p_n_zones,
Zone *p_zones[]
Zone *p_zones[],
int p_DoNativeMotDet
) : id( p_id ),
server_id( p_server_id ),
function( (Function)p_function ),
@ -340,7 +358,9 @@ Monitor::Monitor(
zones( p_zones ),
timestamps( 0 ),
images( 0 ),
privacy_bitmask( NULL )
privacy_bitmask( NULL ),
iDoNativeMotDet( p_DoNativeMotDet ),
ThePluginManager( p_id )
{
strncpy( name, p_name, sizeof(name)-1 );
@ -435,9 +455,35 @@ Monitor::Monitor(
shared_data->alarm_y = -1;
}
#if ZM_PLUGINS_ON
if ( ( purpose == QUERY_PLUGINS ) || ( config.load_plugins && ( purpose == ANALYSIS ) ) )
{
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 )
if ( ( purpose != QUERY ) && ( purpose != QUERY_PLUGINS ) )
{
Error( "Shared data not initialised by capture daemon for monitor %s", name );
exit( -1 );
@ -697,6 +743,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
}
}
}
void Monitor::AddPrivacyBitmask( Zone *p_zones[] )
@ -1354,7 +1418,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;
}
@ -1365,7 +1433,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;
}
@ -1403,6 +1475,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;
@ -1430,39 +1504,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) )
{
#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
{
Event::StringSet zoneSet;
int motion_score = last_motion_score;
unsigned int motion_score = last_motion_score;
bool alarm = false;
if ( !(image_count % (motion_frame_skip+1) ) )
{
// Get new score.
motion_score = last_motion_score = DetectMotion( *snap_image, zoneSet );
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 )
{
score += motion_score;
if ( cause.length() )
cause += ", ";
cause += MOTION_CAUSE;
}
else
{
score += motion_score;
event->AddCause( MOTION_CAUSE );
}
noteSetMap[MOTION_CAUSE] = zoneSet;
}
}
}
else
{
for ( int n_zone = 0; n_zone < n_zones; n_zone++ )
{
zones[n_zone]->ResetStats();
}
}
#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 )
@ -1485,6 +1605,8 @@ bool Monitor::Analyse()
first_link = false;
}
}
else
event->AddCause( LINKED_CAUSE );
noteSet.insert( linked_monitors[i]->Name() );
score += 50;
}
@ -1647,7 +1769,10 @@ bool Monitor::Analyse()
event = new Event( this, *(image_buffer[pre_index].timestamp), cause, noteSetMap );
}
shared_data->last_event = event->Id();
#if ZM_PLUGINS_ON
if (config.load_plugins)
ThePluginManager.getImageAnalyser().onCreateEvent( zones, event );
#endif // ZM_PLUGINS_ON
Info( "%s: %03d - Opening new event %d, alarm start", name, image_count, event->Id() );
if ( pre_event_images )
@ -1820,10 +1945,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;
@ -1856,7 +1982,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, LabelSize, WarmupCount, PreEventCount, PostEventCount, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, 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, LabelSize, WarmupCount, PreEventCount, PostEventCount, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, DoNativeMotDet, SignalCheckColour from Monitors where Id = '%d'", id );
if ( mysql_query( &dbconn, sql ) )
{
@ -1903,6 +2029,7 @@ void Monitor::Reload()
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);
@ -2048,7 +2175,7 @@ void Monitor::ReloadLinkedMonitors( const char *p_linked_monitors )
#if ZM_HAS_V4L
int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose purpose )
{
std::string sql = "select Id, Name, ServerId, 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, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Function != 'None' and Type = 'Local'";
std::string sql = "select Id, Name, ServerId, 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, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, DoNativeMotDet, SignalCheckColour, Exif from Monitors where Function != 'None' and Type = 'Local'";
if ( device[0] ) {
sql += " AND Device='";
sql += device;
@ -2138,6 +2265,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);
@ -2206,7 +2335,8 @@ Debug( 1, "Got %d for v4l_captures_per_frame", v4l_captures_per_frame );
embed_exif,
purpose,
0,
0
0,
doNativeMotDet
);
Zone **zones = 0;
int n_zones = Zone::Load( monitors[i], zones );
@ -2228,7 +2358,7 @@ Debug( 1, "Got %d for v4l_captures_per_frame", v4l_captures_per_frame );
int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const char *port, const char *path, Monitor **&monitors, Purpose purpose )
{
std::string sql = "select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Remote'";
std::string sql = "select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif, DoNativeMotDet from Monitors where Function != 'None' and Type = 'Remote'";
if ( staticConfig.SERVER_ID ) {
sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID );
}
@ -2302,6 +2432,8 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c
int track_motion = atoi(dbrow[col]); col++;
bool embed_exif = (*dbrow[col] != '0'); 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);
@ -2385,8 +2517,8 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c
embed_exif,
purpose,
0,
0
0,
doNativeMotDet
);
Zone **zones = 0;
int n_zones = Zone::Load( monitors[i], zones );
@ -2407,7 +2539,7 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c
int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose purpose )
{
std::string sql = "select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'File'";
std::string sql = "select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif, DoNativeMotDet from Monitors where Function != 'None' and Type = 'File'";
if ( file[0] ) {
sql += " AND Path='";
sql += file;
@ -2477,6 +2609,8 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu
int track_motion = atoi(dbrow[col]); col++;
bool embed_exif = (*dbrow[col] != '0'); 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);
@ -2528,7 +2662,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 );
@ -2550,7 +2685,7 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu
#if HAVE_LIBAVFORMAT
int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose purpose )
{
std::string sql = "select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Path, Method, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Ffmpeg'";
std::string sql = "select Id, Name, ServerId, Function+0, Enabled, LinkedMonitors, Path, Method, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif, DoNativeMotDet from Monitors where Function != 'None' and Type = 'Ffmpeg'";
if ( file[0] ) {
sql += " AND Path = '";
sql += file;
@ -2622,6 +2757,8 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose
int track_motion = atoi(dbrow[col]); col++;
bool embed_exif = (*dbrow[col] != '0'); 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);
@ -2675,7 +2812,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 );
@ -2697,7 +2835,7 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose
Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose )
{
std::string sql = stringtf( "select Id, Name, ServerId, 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, RTSPDescribe, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Id = %d", p_id );
std::string sql = stringtf( "select Id, Name, ServerId, 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, RTSPDescribe, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, DoNativeMotDet, SignalCheckColour, Exif from Monitors where Id = %d", p_id );
MYSQL_ROW dbrow = zmDbFetchOne( sql.c_str() );
if ( ! dbrow ) {
@ -2784,6 +2922,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);
@ -2989,7 +3129,8 @@ Debug( 1, "Got %d for v4l_captures_per_frame", v4l_captures_per_frame );
embed_exif,
purpose,
0,
0
0,
doNativeMotDet
);
@ -3206,6 +3347,15 @@ bool Monitor::closeEvent()
{
gettimeofday( &(event->EndTime()), NULL );
}
#if ZM_PLUGINS_ON
// Inform all plugins that we are closing the event
if ( config.load_plugins && ( purpose == ANALYSIS ) )
{
ThePluginManager.getImageAnalyser().onCloseEvent( zones, event );
}
#endif
event->Close();
delete event;
event = 0;
return( true );
@ -3398,33 +3548,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 );
for ( int n_zone = 0; n_zone < n_zones; n_zone++ )
{
Zone *zone = zones[n_zone];
if ( config.record_diag_images )
{
static char diag_path[PATH_MAX] = "";
if ( !diag_path[0] )
{
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-r.jpg", config.dir_events, id );
}
ref_image.WriteJpeg( diag_path );
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-r.jpg", config.dir_events, id, zone->Id() );
zone->WriteRefImage( 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] )
{
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-d.jpg", config.dir_events, id );
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
@ -3439,7 +3588,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
@ -3453,13 +3602,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();
zoneSet.insert( (" [Zone " + std::string(zone->Label()) + "]\n").c_str() );
if ( !zone->IsPostProcEnabled() )
{
zone->SetAlarm();
Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() );
zoneSet.insert( zone->Label() );
}
//zone->ResetStats();
} else {
// check if end of alarm
@ -3497,13 +3649,15 @@ 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();
score += zone->Score();
zoneSet.insert( (" [Zone " + std::string(zone->Label()) + "]\n").c_str() );
if ( !zone->IsPostProcEnabled() )
{
Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() );
zoneSet.insert( zone->Label() );
if ( config.opt_control && track_motion )
{
if ( (int)zone->Score() > top_score )
@ -3514,6 +3668,7 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z
}
}
}
}
if ( alarm )
{
@ -3525,13 +3680,15 @@ 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();
score += zone->Score();
zoneSet.insert( (" [Zone " + std::string(zone->Label()) + "]\n").c_str() );
if ( !zone->IsPostProcEnabled() )
{
Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() );
zoneSet.insert( zone->Label() );
if ( config.opt_control && track_motion )
{
if ( zone->Score() > (unsigned int)top_score )
@ -3543,6 +3700,7 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z
}
}
}
}
else
{
// Find all alarm pixels in exclusive zones
@ -3554,13 +3712,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();
score += zone->Score();
zoneSet.insert( (" [Zone " + std::string(zone->Label()) + "]\n").c_str() );
if ( !zone->IsPostProcEnabled() )
{
Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() );
zoneSet.insert( zone->Label() );
}
}
}
}
@ -3981,7 +4142,7 @@ void MonitorStream::processCommand( const CmdMsg *msg )
DataMsg status_msg;
status_msg.msg_type = MSG_DATA_WATCH;
memcpy( &status_msg.msg_data, &status_data, sizeof(status_data) );
memcpy( &status_msg.msg_data, &status_data, sizeof(status_msg.msg_data) );
int nbytes = 0;
if ( (nbytes = sendto( sd, &status_msg, sizeof(status_msg), MSG_DONTWAIT, (sockaddr *)&rem_addr, sizeof(rem_addr) )) < 0 )
{
@ -4524,3 +4685,35 @@ 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()
{
std::map<std::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 (std::map<std::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.
@ -53,6 +59,7 @@ public:
typedef enum
{
QUERY=0,
QUERY_PLUGINS,
CAPTURE,
ANALYSIS
} Purpose;
@ -301,13 +308,20 @@ protected:
const unsigned char *privacy_bitmask;
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, unsigned int p_server_id, 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 label_size, 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, double p_analysis_fps, unsigned int p_analysis_update_delay, 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, bool p_embed_exif, Purpose p_purpose, int p_n_zones=0, Zone *p_zones[]=0 );
Monitor( int p_id, const char *p_name, unsigned int p_server_id, 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 label_size, 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, double p_analysis_fps, unsigned int p_analysis_update_delay, 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, bool p_embed_exif, 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[] );
@ -406,7 +420,7 @@ public:
return( camera->PostCapture() );
}
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 );
@ -422,6 +436,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

119
src/zm_plugin.cpp Normal file
View File

@ -0,0 +1,119 @@
#include "zm_plugin.h"
#include "zm_config.h"
#include <sstream>
/*!\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 std::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 std::runtime_error("'" + sFilename + "' is not a valid plugin");
// Initialize a new DLL reference counter
m_pDLLRefCount = new size_t(1);
}
catch(std::runtime_error &ex)
{
dlclose(m_hDLL);
throw ex;
}
catch(...)
{
dlclose(m_hDLL);
throw std::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)
{
int pluginEngineVersion = m_pfnGetEngineVersion();
if(pluginEngineVersion == ZM_ENGINE_VERSION)
m_pfnRegisterPlugin(K, m_sPluginFileName);
else
{
// Raise an exception to inform the plugin manager that something bad happened
std::ostringstream strError;
strError << "Could not load '" << m_sPluginFileName
<< "' (engine version mistmatch: ZM=" << ZM_ENGINE_VERSION
<< " / plugin=" << pluginEngineVersion << ")";
throw std::logic_error(strError.str().c_str());
}
}

70
src/zm_plugin.h Normal file
View File

@ -0,0 +1,70 @@
#ifndef ZM_PLUGIN_H
#define ZM_PLUGIN_H
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
#include <stdexcept>
class PluginManager;
//! Signature for the version query function
typedef int fnGetEngineVersion();
//! Signature for the plugin's registration function
typedef void fnRegisterPlugin(PluginManager &, std::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.
std::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

166
src/zm_plugin_manager.cpp Normal file
View File

@ -0,0 +1,166 @@
#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 std::string& p1, const std::string& p2)
* \param p1 is the first part of desired path
* \param p2 is the second part of desired path
* \return joined path string.
*/
std::string join_paths(const std::string& p1, const std::string& p2)
{
char sep = '/';
std::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);
}
std::string PluginManager::m_sPluginExt = DEFAULT_PLUGIN_EXT;
PluginManager::PluginManager() {}
PluginManager::PluginManager(
int nMonitorId
) :
m_ImageAnalyser( nMonitorId )
{}
/*!\fn PluginManager::loadPlugin(const std::string &sFilename))
* \param sFilename is the name of plugin file to load
*/
bool PluginManager::loadPlugin(const std::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(std::runtime_error &ex)
{
Error("Runtime error: %s.", ex.what());
return false;
}
catch(std::logic_error &el)
{
Error("Logic error: %s.", el.what());
return false;
}
catch(...)
{
Error("Unknown error: Could not load %s.", sFilename.c_str());
return false;
}
return true;
}
/*!\fn PluginManager::findPlugins(const std::string &sPath, bool loadPlugins, unsigned int& nNumPlugLoaded)
* \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 std::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)
{
std::string sFileName = std::string(files[i]->d_name);
std::string sFullPath = join_paths(sPath, sFileName);
size_t idx = sFileName.rfind('.');
if (idx != std::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( std::pair<std::string,bool>(sFileName, IsPluginRegistered) );
if (IsPluginRegistered) nNumPlugLoaded++;
}
return count;
}
/*!\fn PluginManager::configurePlugins(std::string sConfigFileName, bool bDoNativeDet)
* \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(std::string sConfigFileName, bool bDoNativeDet)
{
m_ImageAnalyser.configurePlugins(sConfigFileName, bDoNativeDet);
}
/*!\fn PluginManager::getPluginsGenConf(std::map<std::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(std::map<std::string,pGenConf>& mapPluginGenConf)
{
for (std::map<std::string,bool>::iterator it = mapPluginReg.begin() ; it != mapPluginReg.end(); ++it)
{
pGenConf plugGenConf;
m_ImageAnalyser.getRegPluginGenConf( it->first, plugGenConf );
plugGenConf.Registered = it->second;
mapPluginGenConf.insert( std::pair<std::string,pGenConf>(it->first, plugGenConf) );
}
return mapPluginGenConf.size();
}
/*!\fn PluginManager::getPluginZoneConf(std::string sPluginName, PluginZoneConf& mapPluginZoneConf)
* \param sPluginName is the plugin name
* \param mapPluginZoneConf is the map of zone settings for the plugin
*/
void PluginManager::getPluginZoneConf(std::string sPluginName, PluginZoneConf& mapPluginZoneConf)
{
m_ImageAnalyser.getRegPluginZoneConf( sPluginName, mapPluginZoneConf );
}

86
src/zm_plugin_manager.h Normal file
View File

@ -0,0 +1,86 @@
#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"
//! 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.
std::string join_paths(const std::string& p1, const std::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 std::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 std::string sPath, bool loadPlugins, unsigned int& nNumPlugLoaded);
//! Get general settings of plugins
unsigned long getPluginsGenConf(std::map<std::string,pGenConf>& mapPluginGenConf);
//! Get zone settings of a plugin
void getPluginZoneConf(std::string sPluginName, PluginZoneConf& mapPluginZoneConf);
//! Configure all loaded plugins using given configuration file.
void configurePlugins(std::string sConfigFileName, bool bDoNativeDet);
//! Set plugin extension.
void setPluginExt(std::string sPluginExt) { m_sPluginExt = sPluginExt; }
//! Extension for zm plugins.
static std::string m_sPluginExt;
private:
//! All plugins currently loaded.
PluginMap m_LoadedPlugins;
//! The image analyser.
ImageAnalyser m_ImageAnalyser;
//! Plugin list
std::map<std::string,bool> mapPluginReg;
};
#endif //ZM_PLUGIN_MANAGER_H

View File

@ -20,7 +20,6 @@
#ifndef ZM_POLY_H
#define ZM_POLY_H
#include "zm.h"
#include "zm_coord.h"
#include "zm_box.h"

View File

@ -17,8 +17,6 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "zm.h"
#ifndef ZM_REGEXP_H
#define ZM_REGEXP_H

View File

@ -20,6 +20,8 @@
#ifndef ZM_RGB_H
#define ZM_RGB_H
#include <stdint.h>
typedef uint32_t Rgb; // RGB colour type
#define WHITE 0xff

View File

@ -20,8 +20,6 @@
#ifndef ZM_RTP_H
#define ZM_RTP_H
#include "zm.h"
#define RTP_VERSION 2
#endif // ZM_RTP_H

View File

@ -20,7 +20,6 @@
#ifndef ZM_RTSP_H
#define ZM_RTSP_H
#include "zm.h"
#include "zm_ffmpeg.h"
#include "zm_comms.h"
#include "zm_thread.h"

View File

@ -20,8 +20,6 @@
#ifndef ZM_SDP_H
#define ZM_SDP_H
#include "zm.h"
#include "zm_utils.h"
#include "zm_exception.h"
#include "zm_ffmpeg.h"

View File

@ -29,9 +29,6 @@
#include <ucontext.h>
#endif
#include "zm.h"
typedef RETSIGTYPE (SigHandler)( int );
extern bool zm_reload;

View File

@ -23,7 +23,6 @@
#include <sys/un.h>
#include <sys/socket.h>
#include "zm.h"
#include "zm_mpeg.h"
class Monitor;

View File

@ -20,6 +20,8 @@
#ifndef ZM_THREAD_H
#define ZM_THREAD_H
#include "zm_config.h"
#include <unistd.h>
#include <pthread.h>
#include <unistd.h>

View File

@ -20,7 +20,12 @@
#ifndef ZM_TIME_H
#define ZM_TIME_H
#include "zm.h"
#include "zm_config.h"
#include "zm_logger.h"
#ifdef HAVE_STDDEF_H
#include <stddef.h>
#endif
#include <sys/time.h>

View File

@ -17,7 +17,6 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "zm.h"
#include "zm_db.h"
#ifndef ZM_USER_H

View File

@ -17,13 +17,17 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
//#include "zm_logger.h"
#include "zm_logger.h"
#include "zm.h"
#include "zm_utils.h"
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <dirent.h>
#include <sys/stat.h>
#include <stdlib.h>
unsigned int sseversion = 0;
@ -345,3 +349,63 @@ void timespec_diff(struct timespec *start, struct timespec *end, struct timespec
}
}
int remove_dir(const char *path, bool force, bool verbose)
{
DIR *d = opendir(path);
size_t path_len = strlen(path);
int r = -1;
if (d)
{
struct dirent *p;
r = 0;
while (!r && (p=readdir(d)))
{
int r2 = -1;
char *buf;
size_t len;
if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, ".."))
continue;
if (!force)
{
if (verbose)
Error("Can't remove directory '%s/%s': (not empty)", path, p->d_name);
return r2;
}
len = path_len + strlen(p->d_name) + 2;
buf = (char*)malloc(len);
if (buf)
{
struct stat statbuf;
snprintf(buf, len, "%s/%s", path, p->d_name);
if (!stat(buf, &statbuf))
{
if (S_ISDIR(statbuf.st_mode))
{
if (((r2 = remove_dir(buf, force)) < 0) && verbose)
Error("Can't remove directory '%s': %s", buf, strerror(errno));
}
else
{
if (((r2 = unlink(buf)) < 0) && verbose)
Error("Can't remove file '%s': %s", buf, strerror(errno));
}
}
free(buf);
}
r = r2;
}
closedir(d);
}
if ((!r) && ((r = rmdir(path)) < 0) && verbose)
Error("Can't remove directory '%s': %s", path, strerror(errno));
return r;
}

View File

@ -60,4 +60,6 @@ void timespec_diff(struct timespec *start, struct timespec *end, struct timespec
extern unsigned int sseversion;
int remove_dir(const char *path, bool force = false, bool verbose = false);
#endif // ZM_UTILS_H

View File

@ -60,10 +60,19 @@ void Zone::Setup( Monitor *p_monitor, int p_id, const char *p_label, ZoneType p_
max_blob_size = 0;
image = 0;
score = 0;
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 +100,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);
}
pg_image->WriteJpeg( diag_path );
}
}
@ -142,6 +147,30 @@ void Zone::SetScore(unsigned int nScore)
score = nScore;
}
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 +178,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 +233,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 +268,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 +315,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 );
}
diff_image->WriteJpeg( diag_path );
}
@ -259,14 +326,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 +412,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 );
}
diff_image->WriteJpeg( diag_path );
}
@ -354,14 +421,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 +653,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 );
}
diff_image->WriteJpeg( diag_path );
}
if ( !alarm_blobs )
{
post_proc_in_progress = false;
return( false );
}
@ -642,10 +710,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 );
}
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 +718,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 +865,19 @@ bool Zone::CheckAlarms( const Image *delta_image )
}
}
}
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.
@ -90,9 +103,16 @@ protected:
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 );
@ -135,7 +155,13 @@ public:
inline void ClearAlarm() { alarmed = false; }
inline Coord GetAlarmCentre() const { return( alarm_centre ); }
inline unsigned int Score() const { return( score ); }
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;
@ -149,7 +175,7 @@ public:
score = 0;
}
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 );
@ -167,6 +193,13 @@ public:
int GetExtendAlarmFrames();
void SetScore(unsigned int nScore);
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

@ -57,6 +57,8 @@ behind.
#include "zm_signal.h"
#include "zm_monitor.h"
StaticConfig staticConfig;
void Usage()
{
fprintf( stderr, "zma -m <monitor_id>\n" );

View File

@ -73,6 +73,8 @@ possible, this should run at more or less constant speed.
#include "zm_signal.h"
#include "zm_monitor.h"
StaticConfig staticConfig;
void Usage()
{
fprintf( stderr, "zmc -d <device_path> or -r <proto> -H <host> -P <port> -p <path> or -f <file_path> or -m <monitor_id>\n" );

View File

@ -71,6 +71,8 @@ them itself.
#include "zmf.h"
StaticConfig staticConfig;
int OpenSocket( int monitor_id )
{
int sd = socket( AF_UNIX, SOCK_STREAM, 0);
@ -198,6 +200,7 @@ int main( int argc, char *argv[] )
char log_id_string[16];
snprintf( log_id_string, sizeof(log_id_string), "m%d", id );
StaticConfig staticConfig;
zmLoadConfig();
logInit( "zmf" );

View File

@ -26,6 +26,8 @@
#include "zm_signal.h"
#include "zm_monitor.h"
StaticConfig staticConfig;
bool ValidateAccess( User *user, int mon_id )
{
bool allowed = true;

Some files were not shown because too many files have changed in this diff Show More