Merge branch 'storageareas' into zma_to_thread
This commit is contained in:
commit
f6139d33ed
|
@ -1,7 +1,7 @@
|
||||||
[submodule "web/api/app/Plugin/Crud"]
|
[submodule "web/api/app/Plugin/Crud"]
|
||||||
path = web/api/app/Plugin/Crud
|
path = web/api/app/Plugin/Crud
|
||||||
url = https://github.com/FriendsOfCake/crud.git
|
url = https://github.com/ZoneMinder/crud.git
|
||||||
branch = 3.0
|
branch = 3.0
|
||||||
[submodule "web/api/app/Plugin/CakePHP-Enum-Behavior"]
|
[submodule "web/api/app/Plugin/CakePHP-Enum-Behavior"]
|
||||||
path = web/api/app/Plugin/CakePHP-Enum-Behavior
|
path = web/api/app/Plugin/CakePHP-Enum-Behavior
|
||||||
url = https://github.com/connortechnology/CakePHP-Enum-Behavior.git
|
url = https://github.com/ZoneMinder/CakePHP-Enum-Behavior.git
|
||||||
|
|
|
@ -26,6 +26,8 @@ addons:
|
||||||
- binfmt-support
|
- binfmt-support
|
||||||
- qemu
|
- qemu
|
||||||
- qemu-user-static
|
- qemu-user-static
|
||||||
|
- dnsutils
|
||||||
|
- traceroute
|
||||||
install:
|
install:
|
||||||
- update-binfmts --enable qemu-arm
|
- update-binfmts --enable qemu-arm
|
||||||
|
|
||||||
|
@ -33,8 +35,6 @@ env:
|
||||||
global:
|
global:
|
||||||
- SMPFLAGS=-j4
|
- SMPFLAGS=-j4
|
||||||
matrix:
|
matrix:
|
||||||
- OS=el DIST=6
|
|
||||||
- OS=el DIST=6 ARCH=i386 DOCKER_REPO=knnniggett/packpack
|
|
||||||
- OS=el DIST=7
|
- OS=el DIST=7
|
||||||
- OS=fedora DIST=26 DOCKER_REPO=knnniggett/packpack
|
- OS=fedora DIST=26 DOCKER_REPO=knnniggett/packpack
|
||||||
- OS=fedora DIST=27 DOCKER_REPO=knnniggett/packpack
|
- OS=fedora DIST=27 DOCKER_REPO=knnniggett/packpack
|
||||||
|
|
|
@ -143,6 +143,8 @@ set(ZM_WEBDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/zoneminder/www"
|
||||||
"Location of the web files, default: <prefix>/${CMAKE_INSTALL_DATADIR}/zoneminder/www")
|
"Location of the web files, default: <prefix>/${CMAKE_INSTALL_DATADIR}/zoneminder/www")
|
||||||
set(ZM_CGIDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBEXECDIR}/zoneminder/cgi-bin" CACHE PATH
|
set(ZM_CGIDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBEXECDIR}/zoneminder/cgi-bin" CACHE PATH
|
||||||
"Location of the cgi-bin files, default: <prefix>/${CMAKE_INSTALL_LIBEXECDIR}/zoneminder/cgi-bin")
|
"Location of the cgi-bin files, default: <prefix>/${CMAKE_INSTALL_LIBEXECDIR}/zoneminder/cgi-bin")
|
||||||
|
set(ZM_CACHEDIR "/var/cache/zoneminder" CACHE PATH
|
||||||
|
"Location of the web server cache busting files, default: /var/cache/zoneminder")
|
||||||
set(ZM_CONTENTDIR "/var/lib/zoneminder" CACHE PATH
|
set(ZM_CONTENTDIR "/var/lib/zoneminder" CACHE PATH
|
||||||
"Location of dynamic content (events and images), default: /var/lib/zoneminder")
|
"Location of dynamic content (events and images), default: /var/lib/zoneminder")
|
||||||
set(ZM_DB_HOST "localhost" CACHE STRING
|
set(ZM_DB_HOST "localhost" CACHE STRING
|
||||||
|
@ -207,7 +209,7 @@ set(ZM_PERL_SEARCH_PATH "" CACHE PATH
|
||||||
where ZM_PERL_MM_PARMS has been modified such that ZoneMinder's Perl modules are
|
where ZM_PERL_MM_PARMS has been modified such that ZoneMinder's Perl modules are
|
||||||
installed outside Perl's default search path.")
|
installed outside Perl's default search path.")
|
||||||
set(ZM_TARGET_DISTRO "" CACHE STRING
|
set(ZM_TARGET_DISTRO "" CACHE STRING
|
||||||
"Build ZoneMinder for a specific distribution. Currently, valid names are: fc24, fc25, el6, el7, OS13, FreeBSD")
|
"Build ZoneMinder for a specific distribution. Currently, valid names are: fc27, fc26, el7, OS13, FreeBSD")
|
||||||
set(ZM_SYSTEMD "OFF" CACHE BOOL
|
set(ZM_SYSTEMD "OFF" CACHE BOOL
|
||||||
"Set to ON to force building ZM with systemd support. default: OFF")
|
"Set to ON to force building ZM with systemd support. default: OFF")
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
ZoneMinder
|
ZoneMinder
|
||||||
==========
|
==========
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/ZoneMinder/ZoneMinder.png)](https://travis-ci.org/ZoneMinder/ZoneMinder) [![Bountysource](https://api.bountysource.com/badge/team?team_id=204&style=bounties_received)](https://www.bountysource.com/teams/zoneminder/issues?utm_source=ZoneMinder&utm_medium=shield&utm_campaign=bounties_received)
|
[![Build Status](https://travis-ci.org/ZoneMinder/zoneminder.png)](https://travis-ci.org/ZoneMinder/zoneminder) [![Bountysource](https://api.bountysource.com/badge/team?team_id=204&style=bounties_received)](https://www.bountysource.com/teams/zoneminder/issues?utm_source=ZoneMinder&utm_medium=shield&utm_campaign=bounties_received)
|
||||||
|
|
||||||
All documentation for ZoneMinder is now online at https://zoneminder.readthedocs.org
|
All documentation for ZoneMinder is now online at https://zoneminder.readthedocs.org
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
# Create files from the .in files
|
# Create files from the .in files
|
||||||
configure_file(zm_create.sql.in "${CMAKE_CURRENT_BINARY_DIR}/zm_create.sql" @ONLY)
|
configure_file(zm_create.sql.in "${CMAKE_CURRENT_BINARY_DIR}/zm_create.sql" @ONLY)
|
||||||
|
configure_file(zm_update-1.31.30.sql.in "${CMAKE_CURRENT_BINARY_DIR}/zm_update-1.31.30.sql" @ONLY)
|
||||||
|
|
||||||
# Glob all database upgrade scripts
|
# Glob all database upgrade scripts
|
||||||
file(GLOB dbfileslist RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "zm_update-*.sql")
|
file(GLOB dbfileslist RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "zm_update-*.sql")
|
||||||
|
@ -9,8 +10,12 @@ file(GLOB dbfileslist RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "zm_update-*.sql")
|
||||||
# Install the database upgrade scripts
|
# Install the database upgrade scripts
|
||||||
install(FILES ${dbfileslist} DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db")
|
install(FILES ${dbfileslist} DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db")
|
||||||
|
|
||||||
|
# install zm_update-1.31.30.sql
|
||||||
|
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm_update-1.31.30.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db")
|
||||||
|
|
||||||
# install zm_create.sql
|
# install zm_create.sql
|
||||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm_create.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db")
|
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm_create.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db")
|
||||||
|
|
||||||
# install triggers.sql
|
# install triggers.sql
|
||||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/triggers.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db")
|
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/triggers.sql" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/db")
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ DROP TABLE IF EXISTS `Controls`;
|
||||||
CREATE TABLE `Controls` (
|
CREATE TABLE `Controls` (
|
||||||
`Id` int(10) unsigned NOT NULL auto_increment,
|
`Id` int(10) unsigned NOT NULL auto_increment,
|
||||||
`Name` varchar(64) NOT NULL default '',
|
`Name` varchar(64) NOT NULL default '',
|
||||||
`Type` enum('Local','Remote','Ffmpeg','Libvlc','cURL') NOT NULL default 'Local',
|
`Type` enum('Local','Remote','Ffmpeg','Libvlc','cURL','WebSite') NOT NULL default 'Local',
|
||||||
`Protocol` varchar(64) default NULL,
|
`Protocol` varchar(64) default NULL,
|
||||||
`CanWake` tinyint(3) unsigned NOT NULL default '0',
|
`CanWake` tinyint(3) unsigned NOT NULL default '0',
|
||||||
`CanSleep` tinyint(3) unsigned NOT NULL default '0',
|
`CanSleep` tinyint(3) unsigned NOT NULL default '0',
|
||||||
|
@ -500,6 +500,7 @@ CREATE TABLE `Monitors` (
|
||||||
`DefaultView` enum('Events','Control') NOT NULL default 'Events',
|
`DefaultView` enum('Events','Control') NOT NULL default 'Events',
|
||||||
`DefaultRate` smallint(5) unsigned NOT NULL default '100',
|
`DefaultRate` smallint(5) unsigned NOT NULL default '100',
|
||||||
`DefaultScale` smallint(5) unsigned NOT NULL default '100',
|
`DefaultScale` smallint(5) unsigned NOT NULL default '100',
|
||||||
|
`SignalCheckPoints` INT UNSIGNED NOT NULL default '0',
|
||||||
`SignalCheckColour` varchar(32) NOT NULL default '#0000BE',
|
`SignalCheckColour` varchar(32) NOT NULL default '#0000BE',
|
||||||
`WebColour` varchar(32) NOT NULL default 'red',
|
`WebColour` varchar(32) NOT NULL default 'red',
|
||||||
`Exif` tinyint(1) unsigned NOT NULL default '0',
|
`Exif` tinyint(1) unsigned NOT NULL default '0',
|
||||||
|
@ -528,6 +529,7 @@ CREATE TABLE `Monitor_Status` (
|
||||||
`Status` enum('Unknown','NotRunning','Running','Connected','Signal') NOT NULL default 'Unknown',
|
`Status` enum('Unknown','NotRunning','Running','Connected','Signal') NOT NULL default 'Unknown',
|
||||||
`CaptureFPS` DECIMAL(10,2) NOT NULL default 0,
|
`CaptureFPS` DECIMAL(10,2) NOT NULL default 0,
|
||||||
`AnalysisFPS` DECIMAL(5,2) NOT NULL default 0,
|
`AnalysisFPS` DECIMAL(5,2) NOT NULL default 0,
|
||||||
|
`CaptureBandwidth` INT NOT NULL default 0,
|
||||||
PRIMARY KEY (`MonitorId`)
|
PRIMARY KEY (`MonitorId`)
|
||||||
) ENGINE=MEMORY;
|
) ENGINE=MEMORY;
|
||||||
--
|
--
|
||||||
|
@ -714,7 +716,7 @@ CREATE TABLE `Storage` (
|
||||||
--
|
--
|
||||||
-- Create a default storage location
|
-- Create a default storage location
|
||||||
--
|
--
|
||||||
insert into Storage VALUES (NULL, '/var/cache/zoneminder/events', 'Default', 'local', NULL, 'Medium', 0 );
|
insert into Storage VALUES (NULL, '@ZM_DIR_EVENTS@', 'Default', 'local', NULL, NULL, 'Medium', 0, true );
|
||||||
|
|
||||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||||
|
@ -891,7 +893,7 @@ INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('4 Wide', '{ "default":{
|
||||||
INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('5 Wide', '{ "default":{"float":"left", "width":"19%","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' );
|
INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('5 Wide', '{ "default":{"float":"left", "width":"19%","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' );
|
||||||
|
|
||||||
-- We generally don't alter triggers, we drop and re-create them, so let's keep them in a separate file that we can just source in update scripts.
|
-- We generally don't alter triggers, we drop and re-create them, so let's keep them in a separate file that we can just source in update scripts.
|
||||||
source @ZM_PATH_DATA@/db/triggers.sql
|
source @PKGDATADIR@/db/triggers.sql
|
||||||
--
|
--
|
||||||
-- Apply the initial configuration
|
-- Apply the initial configuration
|
||||||
--
|
--
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
DROP TABLE IF EXISTS `Monitor_Status`;
|
||||||
|
CREATE TABLE `Monitor_Status` (
|
||||||
|
`MonitorId` int(10) unsigned NOT NULL,
|
||||||
|
`Status` enum('Unknown','NotRunning','Running','Connected','Signal') NOT NULL default 'Unknown',
|
||||||
|
`CaptureFPS` DECIMAL(10,2) NOT NULL default 0,
|
||||||
|
`AnalysisFPS` DECIMAL(5,2) NOT NULL default 0,
|
||||||
|
PRIMARY KEY (`MonitorId`)
|
||||||
|
) ENGINE=MEMORY;
|
||||||
|
|
||||||
|
SET SESSION sql_mode='NO_AUTO_VALUE_ON_ZERO';
|
||||||
|
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*) FROM Storage WHERE Name = 'Default' AND Id=0 AND Path='@ZM_DIR_EVENTS@'
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Default Storage Area already exists.'",
|
||||||
|
"INSERT INTO Storage (Id,Name,Path,Scheme,ServerId) VALUES (0,'Default','@ZM_DIR_EVENTS@','Medium',NULL)"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'Monitors'
|
||||||
|
AND column_name = 'SignalCheckPoints'
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Column SignalCheckPoints already exists in Storage'",
|
||||||
|
"ALTER TABLE `Monitors` ADD `SignalCheckPoints` INT UNSIGNED NOT NULL default '0' AFTER `DefaultScale`"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
|
@ -0,0 +1,24 @@
|
||||||
|
--
|
||||||
|
-- This updates a 1.31.42 database to 1.31.43
|
||||||
|
--
|
||||||
|
-- Add WebSite enum to Monitor.Type
|
||||||
|
-- Add Refresh column to Monitors table
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE `zm`.`Monitors`
|
||||||
|
CHANGE COLUMN `Type` `Type` ENUM('Local', 'Remote', 'File', 'Ffmpeg', 'Libvlc', 'cURL', 'WebSite') NOT NULL DEFAULT 'Local' ;
|
||||||
|
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*)
|
||||||
|
FROM INFORMATION_SCHEMA.COLUMNS
|
||||||
|
WHERE table_name = 'Monitors'
|
||||||
|
AND table_schema = DATABASE()
|
||||||
|
AND column_name = 'Refresh'
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Column Refresh exists in Monitors'",
|
||||||
|
"ALTER TABLE Monitors ADD `Refresh` int(10) unsigned default NULL"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'Monitor_Status'
|
||||||
|
AND column_name = 'CaptureBandwidth'
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Column CaptureBandwidth already exists in Monitor_Status'",
|
||||||
|
"ALTER TABLE `Monitor_Status` ADD `CaptureBandwidth` INT NOT NULL default 0 AFTER `AnalysisFPS`"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
|
@ -14,24 +14,18 @@ if((NOT ZM_TARGET_DISTRO MATCHES "^fc") AND (ZM_WEB_USER STREQUAL "nginx"))
|
||||||
endif((NOT ZM_TARGET_DISTRO MATCHES "^fc") AND (ZM_WEB_USER STREQUAL "nginx"))
|
endif((NOT ZM_TARGET_DISTRO MATCHES "^fc") AND (ZM_WEB_USER STREQUAL "nginx"))
|
||||||
|
|
||||||
# Configure the zoneminder service files
|
# Configure the zoneminder service files
|
||||||
if(ZM_TARGET_DISTRO STREQUAL "el6")
|
configure_file(systemd/zoneminder.logrotate.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.logrotate @ONLY)
|
||||||
configure_file(sysvinit/zoneminder.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.sysvinit @ONLY)
|
if(ZM_WEB_USER STREQUAL "nginx")
|
||||||
configure_file(sysvinit/zoneminder.logrotate.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.logrotate @ONLY)
|
configure_file(nginx/zoneminder.service.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.service @ONLY)
|
||||||
|
configure_file(nginx/zoneminder.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.conf @ONLY)
|
||||||
|
configure_file(nginx/zoneminder.tmpfiles.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.tmpfiles @ONLY)
|
||||||
|
configure_file(nginx/zoneminder.php-fpm.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.php-fpm.conf @ONLY)
|
||||||
|
configure_file(nginx/README.Fedora ${CMAKE_CURRENT_SOURCE_DIR}/readme/README.Fedora COPYONLY)
|
||||||
|
else(ZM_WEB_USER STREQUAL "nginx")
|
||||||
|
configure_file(systemd/zoneminder.service.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.service @ONLY)
|
||||||
configure_file(apache/zoneminder.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.conf @ONLY)
|
configure_file(apache/zoneminder.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.conf @ONLY)
|
||||||
else(ZM_TARGET_DISTRO STREQUAL "el6")
|
configure_file(systemd/zoneminder.tmpfiles.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.tmpfiles @ONLY)
|
||||||
configure_file(systemd/zoneminder.logrotate.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.logrotate @ONLY)
|
endif(ZM_WEB_USER STREQUAL "nginx")
|
||||||
if(ZM_WEB_USER STREQUAL "nginx")
|
|
||||||
configure_file(nginx/zoneminder.service.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.service @ONLY)
|
|
||||||
configure_file(nginx/zoneminder.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.conf @ONLY)
|
|
||||||
configure_file(nginx/zoneminder.tmpfiles.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.tmpfiles @ONLY)
|
|
||||||
configure_file(nginx/zoneminder.php-fpm.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.php-fpm.conf @ONLY)
|
|
||||||
configure_file(nginx/README.Fedora ${CMAKE_CURRENT_SOURCE_DIR}/readme/README.Fedora COPYONLY)
|
|
||||||
else(ZM_WEB_USER STREQUAL "nginx")
|
|
||||||
configure_file(systemd/zoneminder.service.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.service @ONLY)
|
|
||||||
configure_file(apache/zoneminder.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.conf @ONLY)
|
|
||||||
configure_file(systemd/zoneminder.tmpfiles.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.tmpfiles @ONLY)
|
|
||||||
endif(ZM_WEB_USER STREQUAL "nginx")
|
|
||||||
endif(ZM_TARGET_DISTRO STREQUAL "el6")
|
|
||||||
|
|
||||||
# Unpack jscalendar & move files into position
|
# Unpack jscalendar & move files into position
|
||||||
message(STATUS "Unpacking and Installing jscalendar...")
|
message(STATUS "Unpacking and Installing jscalendar...")
|
||||||
|
@ -52,6 +46,7 @@ file(MAKE_DIRECTORY sock swap zoneminder zoneminder-upload events images temp)
|
||||||
install(DIRECTORY sock swap DESTINATION /var/lib/zoneminder DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
install(DIRECTORY sock swap DESTINATION /var/lib/zoneminder DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||||
install(DIRECTORY zoneminder DESTINATION /var/log DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
install(DIRECTORY zoneminder DESTINATION /var/log DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||||
install(DIRECTORY zoneminder DESTINATION /var/run DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
install(DIRECTORY zoneminder DESTINATION /var/run DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||||
|
install(DIRECTORY zoneminder DESTINATION /var/cache DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||||
install(DIRECTORY zoneminder-upload DESTINATION /var/spool DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
install(DIRECTORY zoneminder-upload DESTINATION /var/spool DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||||
install(DIRECTORY events images temp DESTINATION /var/lib/zoneminder DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
install(DIRECTORY events images temp DESTINATION /var/lib/zoneminder DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||||
|
|
||||||
|
@ -61,23 +56,18 @@ install(CODE "execute_process(COMMAND ln -sf ../../../../../../var/lib/zoneminde
|
||||||
# Link to Cambozola
|
# Link to Cambozola
|
||||||
install(CODE "execute_process(COMMAND ln -sf ../../java/cambozola.jar \"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/cambozola.jar\")")
|
install(CODE "execute_process(COMMAND ln -sf ../../java/cambozola.jar \"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/cambozola.jar\")")
|
||||||
|
|
||||||
# Install auxiliary files required to run zoneminder on CentOS
|
# Install auxiliary files
|
||||||
install(FILES misc/redalert.wav DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/sounds PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
install(FILES misc/redalert.wav DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/sounds PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||||
install(DIRECTORY jscalendar-1.0/ DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/tools/jscalendar)
|
install(DIRECTORY jscalendar-1.0/ DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/tools/jscalendar)
|
||||||
|
|
||||||
|
# Install zoneminder service files
|
||||||
install(FILES zoneminder.logrotate DESTINATION /etc/logrotate.d RENAME zoneminder PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
install(FILES zoneminder.logrotate DESTINATION /etc/logrotate.d RENAME zoneminder PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
||||||
|
install(FILES zoneminder.conf DESTINATION /etc/zm/www PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
||||||
|
|
||||||
if(ZM_WEB_USER STREQUAL "nginx")
|
if(ZM_WEB_USER STREQUAL "nginx")
|
||||||
install(FILES zoneminder.conf DESTINATION /etc/nginx/default.d PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
|
||||||
install(FILES zoneminder.php-fpm.conf DESTINATION /etc/php-fpm.d PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ RENAME zoneminder.conf)
|
install(FILES zoneminder.php-fpm.conf DESTINATION /etc/php-fpm.d PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ RENAME zoneminder.conf)
|
||||||
else(ZM_WEB_USER STREQUAL "nginx")
|
|
||||||
install(FILES zoneminder.conf DESTINATION /etc/httpd/conf.d PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
|
||||||
endif(ZM_WEB_USER STREQUAL "nginx")
|
endif(ZM_WEB_USER STREQUAL "nginx")
|
||||||
|
|
||||||
if(ZM_TARGET_DISTRO STREQUAL "el6")
|
install(FILES zoneminder.service DESTINATION /usr/lib/systemd/system PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
||||||
install(FILES zoneminder.sysvinit DESTINATION /etc/rc.d/init.d RENAME zoneminder PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
install(FILES zoneminder.tmpfiles DESTINATION /usr/lib/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
||||||
else(ZM_TARGET_DISTRO STREQUAL "el6")
|
|
||||||
install(FILES zoneminder.service DESTINATION /usr/lib/systemd/system PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
|
||||||
install(FILES zoneminder.tmpfiles DESTINATION /usr/lib/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
|
||||||
endif(ZM_TARGET_DISTRO STREQUAL "el6")
|
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,23 @@ RewriteEngine On
|
||||||
RewriteCond %{HTTPS} !=on
|
RewriteCond %{HTTPS} !=on
|
||||||
RewriteRule ^/?(zm)(.*) https://%{SERVER_NAME}/$1$2 [R,L]
|
RewriteRule ^/?(zm)(.*) https://%{SERVER_NAME}/$1$2 [R,L]
|
||||||
|
|
||||||
|
# Order matters. This alias must come first.
|
||||||
|
Alias /zm/cache "@ZM_CACHEDIR@"
|
||||||
|
<Directory "@ZM_CACHEDIR@">
|
||||||
|
SSLRequireSSL
|
||||||
|
Options -Indexes +MultiViews +FollowSymLinks
|
||||||
|
AllowOverride None
|
||||||
|
<IfModule mod_authz_core.c>
|
||||||
|
# Apache 2.4
|
||||||
|
Require all granted
|
||||||
|
</IfModule>
|
||||||
|
<IfModule !mod_authz_core.c>
|
||||||
|
# Apache 2.2
|
||||||
|
Order deny,allow
|
||||||
|
Allow from all
|
||||||
|
</IfModule>
|
||||||
|
</Directory>
|
||||||
|
|
||||||
Alias /zm "@ZM_WEBDIR@"
|
Alias /zm "@ZM_WEBDIR@"
|
||||||
<Directory "@ZM_WEBDIR@">
|
<Directory "@ZM_WEBDIR@">
|
||||||
# explicitly set index.php as the only directoryindex
|
# explicitly set index.php as the only directoryindex
|
||||||
|
|
|
@ -1,37 +1,19 @@
|
||||||
What's New
|
What's New
|
||||||
==========
|
==========
|
||||||
|
|
||||||
1. ZoneMinder now uses a conf.d subfolder to process custom changes to
|
1. See the ZoneMinder release notes for a list of new features:
|
||||||
variables found in zm.conf. Changes to zm.conf will be overwritten
|
https://github.com/ZoneMinder/zoneminder/releases
|
||||||
during an upgrade. Instead, create a file with a ".conf" extension under
|
|
||||||
the conf.d folder and make your changes there.
|
|
||||||
|
|
||||||
2. ZoneMinder now supports recording directly to video container! This feature
|
|
||||||
is new and should be treated as experimental. Refer to the documentation
|
|
||||||
regarding how to use this feature.
|
|
||||||
|
|
||||||
3. The Apache ScriptAlias has been changed from "/cgi-bin/zm/zms" to
|
|
||||||
"/cgi-bin-zm/zms". This has been to done to avoid this bug:
|
|
||||||
https://bugzilla.redhat.com/show_bug.cgi?id=973067
|
|
||||||
|
|
||||||
IMPORTANT: You must manually inspect the value for PATH_ZMS under Options
|
|
||||||
and verify it is set to "/cgi-bin-zm/nph-zms". Failure to do so will result
|
|
||||||
in a broken system. You have been warned.
|
|
||||||
|
|
||||||
4. This package uses the HTTPS protocol by default to access the web portal.
|
|
||||||
Requests using HTTP will auto-redirect to HTTPS. See README.https for
|
|
||||||
more information.
|
|
||||||
|
|
||||||
New installs
|
New installs
|
||||||
============
|
============
|
||||||
|
|
||||||
1. Unless you are already using MariaDB server, you need to ensure that the
|
1. Unless you are already using MariaDB server, you need to ensure that the
|
||||||
server is configured to start during boot and properly secured by running:
|
server is configured to start during boot and properly secured by running:
|
||||||
|
|
||||||
sudo dnf install mariadb-server
|
sudo dnf install mariadb-server
|
||||||
sudo systemctl enable mariadb
|
sudo systemctl enable mariadb
|
||||||
sudo systemctl start mariadb.service
|
sudo systemctl start mariadb.service
|
||||||
mysql_secure_installation
|
mysql_secure_installation
|
||||||
|
|
||||||
2. Assuming the database is local and using the password for the root account
|
2. Assuming the database is local and using the password for the root account
|
||||||
set during the previous step, you will need to create the ZoneMinder
|
set during the previous step, you will need to create the ZoneMinder
|
||||||
|
@ -50,13 +32,13 @@ New installs
|
||||||
/etc/zm/conf.d and set your credentials there. For example, create the file
|
/etc/zm/conf.d and set your credentials there. For example, create the file
|
||||||
/etc/zm/conf.d/zm-db-user.conf and add the following content to it:
|
/etc/zm/conf.d/zm-db-user.conf and add the following content to it:
|
||||||
|
|
||||||
ZM_DB_USER = {username of the sql account you want to use}
|
ZM_DB_USER = {username of the sql account you want to use}
|
||||||
ZM_DB_PASS = {password of the sql account you want to use}
|
ZM_DB_PASS = {password of the sql account you want to use}
|
||||||
|
|
||||||
Once the file has been saved, set proper file & ownership permissions on it:
|
Once the file has been saved, set proper file & ownership permissions on it:
|
||||||
|
|
||||||
sudo chown root:apache *.conf
|
sudo chown root:apache *.conf
|
||||||
sudo chmod 640 *.conf
|
sudo chmod 640 *.conf
|
||||||
|
|
||||||
4. Edit /etc/php.ini, uncomment the date.timezone line, and add your local
|
4. Edit /etc/php.ini, uncomment the date.timezone line, and add your local
|
||||||
timezone. PHP will complain loudly if this is not set, or if it is set
|
timezone. PHP will complain loudly if this is not set, or if it is set
|
||||||
|
@ -82,34 +64,62 @@ New installs
|
||||||
SELINUX line from "enforcing" to "disabled". This change will take
|
SELINUX line from "enforcing" to "disabled". This change will take
|
||||||
effect after a reboot.
|
effect after a reboot.
|
||||||
|
|
||||||
6. Install mod_ssl or configure /etc/httpd/conf.d/zoneminder.conf to meet your
|
6. Configure the web server
|
||||||
needs. This package comes preconfigured for HTTPS using the default self
|
|
||||||
signed certificate on your system. The recommended way to complete this step
|
|
||||||
is to simply install mod_ssl:
|
|
||||||
|
|
||||||
sudo dnf install mod_ssl
|
This package uses the HTTPS protocol by default to access the web portal,
|
||||||
|
using rhe default self signed certificate on your system. Requests using
|
||||||
|
HTTP will auto-redirect to HTTPS.
|
||||||
|
|
||||||
If this does not meet your needs, then read README.https to
|
Inspect the web server configuration file and verify it meets your needs:
|
||||||
learn about alternatives. When in doubt, install mod_ssl.
|
|
||||||
|
/etc/zm/www/zoneminder.conf
|
||||||
|
|
||||||
|
If you are running other web enabled services then you may need to edit
|
||||||
|
this file to suite. See README.https to learn about other alternatives.
|
||||||
|
|
||||||
|
When in doubt, proceed with the default:
|
||||||
|
|
||||||
|
sudo ln -s /etc/zm/www/zoneminder.conf /etc/httpd/conf.d/
|
||||||
|
sudo dnf install mod_ssl
|
||||||
|
|
||||||
7. Now start the web server:
|
7. Now start the web server:
|
||||||
|
|
||||||
sudo systemctl enable httpd
|
sudo systemctl enable httpd
|
||||||
sudo systemctl start httpd
|
sudo systemctl start httpd
|
||||||
|
|
||||||
8. Now start zoneminder:
|
8. Now start zoneminder:
|
||||||
|
|
||||||
sudo systemctl enable zoneminder
|
sudo systemctl enable zoneminder
|
||||||
sudo systemctl start zoneminder
|
sudo systemctl start zoneminder
|
||||||
|
|
||||||
9. The Fedora repos have a ZoneMinder package available, but it does not
|
9. Optionally configure the firewall
|
||||||
support ffmpeg or libvlc, which many modern IP cameras require. Most users
|
|
||||||
will want to prevent the ZoneMinder package in the Fedora repos from
|
All Redhat distros ship with the firewall enabled. That means you will not
|
||||||
overwriting the ZoneMinder package in zmrepo, during a future dnf update. To
|
be able to access the ZoneMinder web console from a remote machine until
|
||||||
prevent that from happening you must edit /etc/yum.repos.d/fedora.repo
|
changes are made to the firewall.
|
||||||
and /etc/yum.repos.d/fedora-updates.repo. Add the line "exclude=zoneminder*"
|
|
||||||
without the quotes under the [fedora] and [fedora-updates] blocks,
|
What follows are a set of minimal commands to allow remote access to the
|
||||||
respectively.
|
ZoneMinder web console and also allow ZoneMinder's ONVIF discovery to
|
||||||
|
work. The following commands do not put any restrictions on which remote
|
||||||
|
machine(s) have access to the listed ports or services.
|
||||||
|
|
||||||
|
sudo firewall-cmd --permanent --zone=public --add-service=http
|
||||||
|
sudo firewall-cmd --permanent --zone=public --add-service=https
|
||||||
|
sudo firewall-cmd --permanent --zone=public --add-port=3702/udp
|
||||||
|
sudo firewall-cmd --reload
|
||||||
|
|
||||||
|
Additional changes to the firewall may be required, depending on your
|
||||||
|
security requirements and how you use the system. It is up to you to verify
|
||||||
|
these commands are sufficient.
|
||||||
|
|
||||||
|
10. Access the ZoneMinder web console
|
||||||
|
|
||||||
|
You may now access the ZoneMinder web console from your web browser using
|
||||||
|
an appropriate url. Here are some examples:
|
||||||
|
|
||||||
|
http://localhost/zm (works from the local machine only)
|
||||||
|
http://{machine name}/zm (works only if dns is configured for your network)
|
||||||
|
http://{ip address}/zm
|
||||||
|
|
||||||
Upgrades
|
Upgrades
|
||||||
========
|
========
|
||||||
|
@ -131,7 +141,7 @@ Upgrades
|
||||||
See step 2 of the Installation section to add missing permissions.
|
See step 2 of the Installation section to add missing permissions.
|
||||||
|
|
||||||
3. Verify the ZoneMinder Apache configuration file in the folder
|
3. Verify the ZoneMinder Apache configuration file in the folder
|
||||||
/etc/httpd/conf.d. You will have a file called "zoneminder.conf" and there
|
/etc/zm/www. You will have a file called "zoneminder.conf" and there
|
||||||
may also be a file called "zoneminder.conf.rpmnew". If the rpmnew file
|
may also be a file called "zoneminder.conf.rpmnew". If the rpmnew file
|
||||||
exists, inspect it and merge anything new in that file with zoneminder.conf.
|
exists, inspect it and merge anything new in that file with zoneminder.conf.
|
||||||
Verify the SSL REquirements meet your needs. Read README.https if necessary.
|
Verify the SSL REquirements meet your needs. Read README.https if necessary.
|
||||||
|
|
|
@ -1,161 +0,0 @@
|
||||||
What's New
|
|
||||||
==========
|
|
||||||
|
|
||||||
1. ***EOL NOTICE***
|
|
||||||
It has become increasingly difficult to maintain the ZoneMinder project such
|
|
||||||
that it remains compatible with EL6 distros. The version of php shipped with
|
|
||||||
EL6 distros and the version of ffmpeg which will build against EL6 are too
|
|
||||||
old. It is with regret that I must announce our plans to stop supporting
|
|
||||||
ZoneMinder on EL6 distros soon. Your best option is to upgrade to an EL7
|
|
||||||
distro or another distro with newer php & ffmpeg packages. Please note that
|
|
||||||
replacing core packages, such as php, will not be supported by us. You are
|
|
||||||
on your own should you choose to go down that path.
|
|
||||||
|
|
||||||
2. ZoneMinder now uses a conf.d subfolder to process custom changes to
|
|
||||||
variables found in zm.conf. Changes to zm.conf will be overwritten
|
|
||||||
during an upgrade. Instead, create a file with a ".conf" extension under
|
|
||||||
th2 conf.d folder and make your changes there.
|
|
||||||
|
|
||||||
3. ZoneMinder now supports recording directly to video container! This feature
|
|
||||||
is new and should be treated as experimental. Refer to the documentation
|
|
||||||
regarding how to use this feature.
|
|
||||||
|
|
||||||
4. The Apache ScriptAlias has been changed from "/cgi-bin/zm/zms" to
|
|
||||||
"/cgi-bin-zm/zms". This has been to done match the configuration of
|
|
||||||
CentOS7/Fedora and simplify the build process.
|
|
||||||
|
|
||||||
IMPORTANT: You must manually verify the value of PATH_ZMS under Options.
|
|
||||||
Make sure it is set to "/cgi-bin-zm/nph-zms". Failure to do so will result
|
|
||||||
in a broken system. You have been warned.
|
|
||||||
|
|
||||||
5. This package uses the HTTPS protocol by default to access the web portal.
|
|
||||||
Requests using HTTP will auto-redirect to HTTPS. See README.https for
|
|
||||||
more information.
|
|
||||||
|
|
||||||
6. The php package that ships with CentOS 6 does not support the new ZoneMinder
|
|
||||||
API. If you require API functionality (such as using a mobile app) then you
|
|
||||||
should consider an upgrade to CentOS 7 or use Fedora.
|
|
||||||
|
|
||||||
New installs
|
|
||||||
============
|
|
||||||
|
|
||||||
1. Unless you are already using MySQL server, you need to ensure that
|
|
||||||
the server is confired to start during boot and properly secured
|
|
||||||
by running:
|
|
||||||
|
|
||||||
sudo yum install mysql-server
|
|
||||||
sudo service mysqld start
|
|
||||||
/usr/bin/mysql_secure_installation
|
|
||||||
sudo chkconfig mysqld on
|
|
||||||
|
|
||||||
2. Using the password for the root account set during the previous step, you
|
|
||||||
will need to create the ZoneMinder database and configure a database
|
|
||||||
account for ZoneMinder to use:
|
|
||||||
|
|
||||||
mysql -uroot -p < /usr/share/zoneminder/db/zm_create.sql
|
|
||||||
mysql -uroot -p -e "grant all on zm.* to \
|
|
||||||
'zmuser'@localhost identified by 'zmpass';"
|
|
||||||
mysqladmin -uroot -p reload
|
|
||||||
|
|
||||||
The database account credentials, zmuser/zmpass, are arbitrary. Set them to
|
|
||||||
anything that suits your environment.
|
|
||||||
|
|
||||||
3. If you have chosen to change the zoneminder database account credentials to
|
|
||||||
something other than zmuser/zmpass, you must now create a config file under
|
|
||||||
/etc/zm/conf.d and set your credentials there. For example, create the file
|
|
||||||
/etc/zm/conf.d/zm-db-user.conf and add the following content to it:
|
|
||||||
|
|
||||||
ZM_DB_USER = {username of the sql account you want to use}
|
|
||||||
ZM_DB_PASS = {password of the sql account you want to use}
|
|
||||||
|
|
||||||
Once the file has been saved, set proper file & ownership permissions on it:
|
|
||||||
|
|
||||||
sudo chown root:apache *.conf
|
|
||||||
sudo chmod 640 *.conf
|
|
||||||
|
|
||||||
4. Edit /etc/php.ini, uncomment the date.timezone line, and add your local
|
|
||||||
timezone. PHP will complain loudly if this is not set, or if it is set
|
|
||||||
incorrectly, and these complaints will show up in the zoneminder logging
|
|
||||||
system as errors
|
|
||||||
|
|
||||||
If you are not sure of the proper timezone specification to use, look at
|
|
||||||
http://php.net/date.timezone
|
|
||||||
|
|
||||||
5. Install mod_ssl or configure /etc/httpd/conf.d/zoneminder.conf to meet your
|
|
||||||
needs. This package comes preconfigured for HTTPS using the default self
|
|
||||||
signed certificate on your system. The recommended way to complete this step
|
|
||||||
is to simply install mod_ssl:
|
|
||||||
|
|
||||||
sudo yum install mod_ssl
|
|
||||||
|
|
||||||
If this does not meet your needs, then read README.https to
|
|
||||||
learn about alternatives. When in doubt, install mod_ssl.
|
|
||||||
|
|
||||||
6. Configure the web server to start automatically:
|
|
||||||
|
|
||||||
sudo chkconfig httpd on
|
|
||||||
sudo service httpd start
|
|
||||||
|
|
||||||
7. This package will automatically configure and install an SELinux policy
|
|
||||||
called local_zoneminder. A copy of this policy is in the documentation
|
|
||||||
folder.
|
|
||||||
|
|
||||||
It is still possible to run into SELinux issues, however. If this is case,
|
|
||||||
you can disable SELinux permanently by editing the following:
|
|
||||||
|
|
||||||
/etc/selinux/conf
|
|
||||||
|
|
||||||
Change SELINUX line from "enforcing" to "disabled". This change will not
|
|
||||||
take effect until a reboot, however. To avoid a reboot, execute the
|
|
||||||
following from the commandline:
|
|
||||||
|
|
||||||
sudo setenforce 0
|
|
||||||
|
|
||||||
8. Finally, you may start the ZoneMinder service:
|
|
||||||
|
|
||||||
sudo service zoneminder start
|
|
||||||
|
|
||||||
Then point your web browser to http://<machine name or ip>/zm
|
|
||||||
|
|
||||||
Upgrades
|
|
||||||
========
|
|
||||||
|
|
||||||
1. Conf.d folder support has been added to ZoneMinder 1.31.0. Any custom
|
|
||||||
changes previously made to zm.conf must now be made in one or more custom
|
|
||||||
config files, created under the conf.d folder. Do this now. See
|
|
||||||
/etc/zm/conf.d/README for details. Once you recreate any custom config changes
|
|
||||||
under the conf.d folder, they will remain in place indefinitely.
|
|
||||||
|
|
||||||
2. Verify permissions of the zmuser account.
|
|
||||||
|
|
||||||
Over time, the database account permissions required for normal operation
|
|
||||||
have increased. Verify the zmuser database account has been granted all
|
|
||||||
permission to the ZoneMinder database:
|
|
||||||
|
|
||||||
mysql -uroot -p -e "show grants for zmuser@localhost;"
|
|
||||||
|
|
||||||
See step 2 of the Installation section to add missing permissions.
|
|
||||||
|
|
||||||
3. Verify the ZoneMinder Apache configuration file in the folder
|
|
||||||
/etc/httpd/conf.d. You will have a file called "zoneminder.conf" and there
|
|
||||||
may also be a file called "zoneminder.conf.rpmnew". If the rpmnew file
|
|
||||||
exists, inspect it and merge anything new in that file with zoneminder.conf.
|
|
||||||
Verify the SSL REquirements meet your needs. Read README.https if necessary.
|
|
||||||
|
|
||||||
4. Upgrade the database before starting ZoneMinder.
|
|
||||||
|
|
||||||
Most upgrades can be performed by executing the following command:
|
|
||||||
|
|
||||||
sudo zmupdate.pl
|
|
||||||
|
|
||||||
Recent versions of ZoneMinder don't require any parameters added to the
|
|
||||||
zmupdate command. However, if ZoneMinder complains, you may need to call
|
|
||||||
zmupdate in the following manner:
|
|
||||||
|
|
||||||
sudo zmupdate.pl --user=root --pass=<mysql_root_pwd> --version=<from version>
|
|
||||||
|
|
||||||
5. Now restart the web server then start zoneminder:
|
|
||||||
|
|
||||||
sudo service httpd restart
|
|
||||||
sudo service zoneminder start
|
|
||||||
|
|
|
@ -1,26 +1,8 @@
|
||||||
What's New
|
What's New
|
||||||
==========
|
==========
|
||||||
|
|
||||||
1. ZoneMinder now uses a conf.d subfolder to process custom changes to
|
1. See the ZoneMinder release notes for a list of new features:
|
||||||
variables found in zm.conf. Changes to zm.conf will be overwritten
|
https://github.com/ZoneMinder/zoneminder/releases
|
||||||
during an upgrade. Instead, create a file with a ".conf" extension under
|
|
||||||
the conf.d folder and make your changes there.
|
|
||||||
|
|
||||||
2. ZoneMinder now supports recording directly to video container! This feature
|
|
||||||
is new and should be treated as experimental. Refer to the documentation
|
|
||||||
regarding how to use this feature.
|
|
||||||
|
|
||||||
3. The Apache ScriptAlias has been changed from "/cgi-bin/zm/zms" to
|
|
||||||
"/cgi-bin-zm/zms". This has been to done to avoid this bug:
|
|
||||||
https://bugzilla.redhat.com/show_bug.cgi?id=973067
|
|
||||||
|
|
||||||
IMPORTANT: You must manually inspect the value for PATH_ZMS under Options
|
|
||||||
and verify it is set to "/cgi-bin-zm/nph-zms". Failure to do so will result
|
|
||||||
in a broken system. You have been warned.
|
|
||||||
|
|
||||||
4. This package uses the HTTPS protocol by default to access the web portal.
|
|
||||||
Requests using HTTP will auto-redirect to HTTPS. See README.https for
|
|
||||||
more information.
|
|
||||||
|
|
||||||
New installs
|
New installs
|
||||||
============
|
============
|
||||||
|
@ -28,10 +10,10 @@ New installs
|
||||||
1. Unless you are already using MariaDB server, you need to ensure that the
|
1. Unless you are already using MariaDB server, you need to ensure that the
|
||||||
server is configured to start during boot and properly secured by running:
|
server is configured to start during boot and properly secured by running:
|
||||||
|
|
||||||
sudo yum install mariadb-server
|
sudo yum install mariadb-server
|
||||||
sudo systemctl enable mariadb
|
sudo systemctl enable mariadb
|
||||||
sudo systemctl start mariadb.service
|
sudo systemctl start mariadb.service
|
||||||
mysql_secure_installation
|
mysql_secure_installation
|
||||||
|
|
||||||
2. Using the password for the root account set during the previous step, you
|
2. Using the password for the root account set during the previous step, you
|
||||||
will need to create the ZoneMinder database and configure a database
|
will need to create the ZoneMinder database and configure a database
|
||||||
|
@ -50,13 +32,13 @@ New installs
|
||||||
/etc/zm/conf.d and set your credentials there. For example, create the file
|
/etc/zm/conf.d and set your credentials there. For example, create the file
|
||||||
/etc/zm/conf.d/zm-db-user.conf and add the following content to it:
|
/etc/zm/conf.d/zm-db-user.conf and add the following content to it:
|
||||||
|
|
||||||
ZM_DB_USER = {username of the sql account you want to use}
|
ZM_DB_USER = {username of the sql account you want to use}
|
||||||
ZM_DB_PASS = {password of the sql account you want to use}
|
ZM_DB_PASS = {password of the sql account you want to use}
|
||||||
|
|
||||||
Once the file has been saved, set proper file & ownership permissions on it:
|
Once the file has been saved, set proper file & ownership permissions on it:
|
||||||
|
|
||||||
sudo chown root:apache *.conf
|
sudo chown root:apache *.conf
|
||||||
sudo chmod 640 *.conf
|
sudo chmod 640 *.conf
|
||||||
|
|
||||||
4. Edit /etc/php.ini, uncomment the date.timezone line, and add your local
|
4. Edit /etc/php.ini, uncomment the date.timezone line, and add your local
|
||||||
timezone. PHP will complain loudly if this is not set, or if it is set
|
timezone. PHP will complain loudly if this is not set, or if it is set
|
||||||
|
@ -82,25 +64,62 @@ New installs
|
||||||
SELINUX line from "enforcing" to "disabled". This change will take
|
SELINUX line from "enforcing" to "disabled". This change will take
|
||||||
effect after a reboot.
|
effect after a reboot.
|
||||||
|
|
||||||
6. Install mod_ssl or configure /etc/httpd/conf.d/zoneminder.conf to meet your
|
6. Configure the web server
|
||||||
needs. This package comes preconfigured for HTTPS using the default self
|
|
||||||
signed certificate on your system. The recommended way to complete this step
|
|
||||||
is to simply install mod_ssl:
|
|
||||||
|
|
||||||
sudo yum install mod_ssl
|
This package uses the HTTPS protocol by default to access the web portal,
|
||||||
|
using rhe default self signed certificate on your system. Requests using
|
||||||
|
HTTP will auto-redirect to HTTPS.
|
||||||
|
|
||||||
If this does not meet your needs, then read README.https to
|
Inspect the web server configuration file and verify it meets your needs:
|
||||||
learn about alternatives. When in doubt, install mod_ssl.
|
|
||||||
|
/etc/zm/www/zoneminder.conf
|
||||||
|
|
||||||
|
If you are running other web enabled services then you may need to edit
|
||||||
|
this file to suite. See README.https to learn about other alternatives.
|
||||||
|
|
||||||
|
When in doubt, proceed with the default:
|
||||||
|
|
||||||
|
sudo ln -s /etc/zm/www/zoneminder.conf /etc/httpd/conf.d/
|
||||||
|
sudo dnf install mod_ssl
|
||||||
|
|
||||||
7. Now start the web server:
|
7. Now start the web server:
|
||||||
|
|
||||||
sudo systemctl enable httpd
|
sudo systemctl enable httpd
|
||||||
sudo systemctl start httpd
|
sudo systemctl start httpd
|
||||||
|
|
||||||
8. Now start zoneminder:
|
8. Now start zoneminder:
|
||||||
|
|
||||||
sudo systemctl enable zoneminder
|
sudo systemctl enable zoneminder
|
||||||
sudo systemctl start zoneminder
|
sudo systemctl start zoneminder
|
||||||
|
|
||||||
|
9. Optionally configure the firewall
|
||||||
|
|
||||||
|
All Redhat distros ship with the firewall enabled. That means you will not
|
||||||
|
be able to access the ZoneMinder web console from a remote machine until
|
||||||
|
changes are made to the firewall.
|
||||||
|
|
||||||
|
What follows are a set of minimal commands to allow remote access to the
|
||||||
|
ZoneMinder web console and also allow ZoneMinder's ONVIF discovery to
|
||||||
|
work. The following commands do not put any restrictions on which remote
|
||||||
|
machine(s) have access to the listed ports or services.
|
||||||
|
|
||||||
|
sudo firewall-cmd --permanent --zone=public --add-service=http
|
||||||
|
sudo firewall-cmd --permanent --zone=public --add-service=https
|
||||||
|
sudo firewall-cmd --permanent --zone=public --add-port=3702/udp
|
||||||
|
sudo firewall-cmd --reload
|
||||||
|
|
||||||
|
Additional changes to the firewall may be required, depending on your
|
||||||
|
security requirements and how you use the system. It is up to you to verify
|
||||||
|
these commands are sufficient.
|
||||||
|
|
||||||
|
10. Access the ZoneMinder web console
|
||||||
|
|
||||||
|
You may now access the ZoneMinder web console from your web browser using
|
||||||
|
an appropriate url. Here are some examples:
|
||||||
|
|
||||||
|
http://localhost/zm (works from the local machine only)
|
||||||
|
http://{machine name}/zm (works only if dns is configured for your network)
|
||||||
|
http://{ip address}/zm
|
||||||
|
|
||||||
Upgrades
|
Upgrades
|
||||||
========
|
========
|
||||||
|
@ -122,7 +141,7 @@ Upgrades
|
||||||
See step 2 of the Installation section to add missing permissions.
|
See step 2 of the Installation section to add missing permissions.
|
||||||
|
|
||||||
3. Verify the ZoneMinder Apache configuration file in the folder
|
3. Verify the ZoneMinder Apache configuration file in the folder
|
||||||
/etc/httpd/conf.d. You will have a file called "zoneminder.conf" and there
|
/etc/zm/www. You will have a file called "zoneminder.conf" and there
|
||||||
may also be a file called "zoneminder.conf.rpmnew". If the rpmnew file
|
may also be a file called "zoneminder.conf.rpmnew". If the rpmnew file
|
||||||
exists, inspect it and merge anything new in that file with zoneminder.conf.
|
exists, inspect it and merge anything new in that file with zoneminder.conf.
|
||||||
Verify the SSL REquirements meet your needs. Read README.https if necessary.
|
Verify the SSL REquirements meet your needs. Read README.https if necessary.
|
||||||
|
|
|
@ -1,29 +1,26 @@
|
||||||
HTTPS is now a requirement
|
HTTPS is now the default
|
||||||
==========================
|
========================
|
||||||
|
|
||||||
This package now depends on Apache's mod_ssl package. This will automatically
|
By default, ZoneMinder will use the certifciate created when the mod_ssl
|
||||||
be installed along with ZoneMinder. Upon installation, the mod_ssl package
|
pacakge was installed on your system.
|
||||||
will create a default, self-signed certificate. This is the certificate that
|
|
||||||
ZoneMinder will use out of the box.
|
|
||||||
|
|
||||||
Since the certificate is self-signed, you will get a warning from your browser
|
Since the certificate is self-signed, you will get a warning from your browser
|
||||||
the first time you access the web portal. This is normal.
|
the first time you access the web portal. This is normal.
|
||||||
|
|
||||||
This is not intended to be an all encompasing solution for everyone. ZoneMinder
|
This is not intended to be an all encompasing solution for everyone. ZoneMinder
|
||||||
will work just fine over HTTPS the way it is currently configured. However,
|
will work just fine over HTTPS the way it is currently configured. However,
|
||||||
here are a couple of considerations you may want to take.
|
here are a couple of considerations you may want to take to improve your
|
||||||
|
experience.
|
||||||
|
|
||||||
1. Create your own certificate. The CentOS wiki has a guide that describes how
|
1. Install a fully signed certificate from letsencrypt, using certbot. See the
|
||||||
|
certbot site for more information. This free service is very easy to set up.
|
||||||
|
https://certbot.eff.org/all-instructions/
|
||||||
|
|
||||||
|
2. Create your own certificate. The CentOS wiki has a guide that describes how
|
||||||
to do this: https://wiki.centos.org/HowTos/Https . Additionally, Googling
|
to do this: https://wiki.centos.org/HowTos/Https . Additionally, Googling
|
||||||
"centos certificate" reveals many articles on the subject. Note that some
|
"centos certificate" reveals many articles on the subject.
|
||||||
third party applications, such as zmNinja, will require you to create a
|
|
||||||
certificate different than the default certificate on your machine.
|
|
||||||
|
|
||||||
2. You can turn off HTTPS entirely by simply commenting out the SSLRequireSSL
|
3. You can turn off HTTPS entirely by simply commenting out the SSLRequireSSL
|
||||||
directives found in /etc/httpd/conf.d/zoneminder.conf. You should also
|
directives found in /etc/httpd/conf.d/zoneminder.conf. You should also
|
||||||
comment out the HTTP -> HTTPS Rewrite rule.
|
comment out the HTTP -> HTTPS Rewrite rule.
|
||||||
|
|
||||||
3. Install a fully signed certificate from letsencrypt. See the Letsencrypt
|
|
||||||
site for more information. https://letsencrypt.org/
|
|
||||||
This service is totally free!
|
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,5 @@
|
||||||
D @ZM_TMPDIR@ 0755 @WEB_USER@ @WEB_GROUP@
|
D @ZM_TMPDIR@ 0755 @WEB_USER@ @WEB_GROUP@
|
||||||
D @ZM_SOCKDIR@ 0755 @WEB_USER@ @WEB_GROUP@
|
D @ZM_SOCKDIR@ 0755 @WEB_USER@ @WEB_GROUP@
|
||||||
|
D @ZM_CACHEDIR@ 0755 @WEB_USER@ @WEB_GROUP@
|
||||||
|
D @ZM_DIR_EVENTS@ 0755 @WEB_USER@ @WEB_GROUP@
|
||||||
|
D @ZM_DIR_IMAGES@ 0755 @WEB_USER@ @WEB_GROUP@
|
||||||
|
|
|
@ -1,121 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
# description: ZoneMinder is the top Linux video camera security and surveillance solution. ZoneMinder is intended for use in single or multi-camera video security applications.Copyright: Philip Coombes, Corey DeLasaux 2003-2008
|
|
||||||
# chkconfig: - 99 00
|
|
||||||
# processname: zmpkg.pl
|
|
||||||
|
|
||||||
# Source function library.
|
|
||||||
. /etc/rc.d/init.d/functions
|
|
||||||
|
|
||||||
prog=ZoneMinder
|
|
||||||
ZM_CONFIG="@ZM_CONFIG@"
|
|
||||||
pidfile="@ZM_RUNDIR@"
|
|
||||||
LOCKFILE=/var/lock/subsys/zm
|
|
||||||
|
|
||||||
loadconf()
|
|
||||||
{
|
|
||||||
if [ -f $ZM_CONFIG ]; then
|
|
||||||
. $ZM_CONFIG
|
|
||||||
else
|
|
||||||
echo "ERROR: $ZM_CONFIG not found."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
loadconf
|
|
||||||
command="$ZM_PATH_BIN/zmpkg.pl"
|
|
||||||
|
|
||||||
start()
|
|
||||||
{
|
|
||||||
# Commenting out as it is not needed. Leaving as a placeholder for future use.
|
|
||||||
# zmupdate || return $?
|
|
||||||
loadconf || return $?
|
|
||||||
#Make sure the directory for our PID folder exists or create one.
|
|
||||||
[ ! -d $pidfile ] \
|
|
||||||
&& mkdir -m 774 $pidfile \
|
|
||||||
&& chown $ZM_WEB_USER:$ZM_WEB_GROUP $pidfile
|
|
||||||
#Make sure the folder for the socks file exists or create one
|
|
||||||
GetPath="select Value from Config where Name='ZM_PATH_SOCKS'"
|
|
||||||
dbHost=`echo $ZM_DB_HOST | cut -d: -f1`
|
|
||||||
dbPort=`echo $ZM_DB_HOST | cut -d: -s -f2`
|
|
||||||
if [ "$dbPort" = "" ]
|
|
||||||
then
|
|
||||||
ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$ZM_DB_HOST -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'`
|
|
||||||
else
|
|
||||||
ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$dbHost -P$dbPort -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'`
|
|
||||||
fi
|
|
||||||
[ ! -d $ZM_PATH_SOCK ] \
|
|
||||||
&& mkdir -m 774 $ZM_PATH_SOCK \
|
|
||||||
&& chown $ZM_WEB_USER:$ZM_WEB_GROUP $ZM_PATH_SOCK
|
|
||||||
echo -n $"Starting $prog: "
|
|
||||||
$command start
|
|
||||||
RETVAL=$?
|
|
||||||
[ $RETVAL = 0 ] && success || failure
|
|
||||||
echo
|
|
||||||
[ $RETVAL = 0 ] && touch $LOCKFILE
|
|
||||||
return $RETVAL
|
|
||||||
}
|
|
||||||
|
|
||||||
stop()
|
|
||||||
{
|
|
||||||
loadconf
|
|
||||||
echo -n $"Stopping $prog: "
|
|
||||||
$command stop
|
|
||||||
RETVAL=$?
|
|
||||||
[ $RETVAL = 0 ] && success || failure
|
|
||||||
echo
|
|
||||||
[ $RETVAL = 0 ] && rm -f $LOCKFILE
|
|
||||||
}
|
|
||||||
|
|
||||||
zmstatus()
|
|
||||||
{
|
|
||||||
loadconf
|
|
||||||
result=`$command status`
|
|
||||||
if [ "$result" = "running" ]; then
|
|
||||||
echo "ZoneMinder is running"
|
|
||||||
$ZM_PATH_BIN/zmu -l
|
|
||||||
RETVAL=0
|
|
||||||
else
|
|
||||||
echo "ZoneMinder is stopped"
|
|
||||||
RETVAL=1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
zmupdate()
|
|
||||||
{
|
|
||||||
if [ -x $ZM_PATH_BIN/zmupdate.pl ]; then
|
|
||||||
$ZM_PATH_BIN/zmupdate.pl -f
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
'start')
|
|
||||||
start
|
|
||||||
;;
|
|
||||||
'stop')
|
|
||||||
stop
|
|
||||||
;;
|
|
||||||
'restart')
|
|
||||||
stop
|
|
||||||
start
|
|
||||||
;;
|
|
||||||
'condrestart')
|
|
||||||
loadconf
|
|
||||||
result=`$ZM_PATH_BIN/zmdc.pl check`
|
|
||||||
if [ "$result" = "running" ]; then
|
|
||||||
$ZM_PATH_BIN/zmdc.pl shutdown > /dev/null
|
|
||||||
rm -f $LOCKFILE
|
|
||||||
start
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
'status')
|
|
||||||
status httpd
|
|
||||||
status mysqld
|
|
||||||
zmstatus
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Usage: $0 { start | stop | restart | condrestart | status }"
|
|
||||||
RETVAL=1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
exit $RETVAL
|
|
|
@ -1,7 +0,0 @@
|
||||||
@ZM_LOGDIR@/*log
|
|
||||||
{
|
|
||||||
weekly
|
|
||||||
notifempty
|
|
||||||
missingok
|
|
||||||
create 660 @WEB_USER@ @WEB_GROUP@
|
|
||||||
}
|
|
|
@ -2,13 +2,13 @@
|
||||||
%global zmgid_final apache
|
%global zmgid_final apache
|
||||||
|
|
||||||
# Crud is configured as a git submodule
|
# Crud is configured as a git submodule
|
||||||
%global crud_version 3.0.10
|
%global crud_version 3.1.0-zm
|
||||||
|
|
||||||
|
# CakePHP-Enum-Behavior is configured as a git submodule
|
||||||
|
%global ceb_version 1.0-zm
|
||||||
|
|
||||||
%if "%{zmuid_final}" == "nginx"
|
%if "%{zmuid_final}" == "nginx"
|
||||||
%global with_nginx 1
|
%global with_nginx 1
|
||||||
%global wwwconfdir %{_sysconfdir}/nginx/default.d
|
|
||||||
%else
|
|
||||||
%global wwwconfdir %{_sysconfdir}/httpd/conf.d
|
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
%global sslcert %{_sysconfdir}/pki/tls/certs/localhost.crt
|
%global sslcert %{_sysconfdir}/pki/tls/certs/localhost.crt
|
||||||
|
@ -22,18 +22,11 @@
|
||||||
%global with_apcu_bc 1
|
%global with_apcu_bc 1
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
# Include files for SysV init or systemd
|
|
||||||
%if 0%{?fedora} >= 15 || 0%{?rhel} >= 7
|
|
||||||
%global with_init_systemd 1
|
|
||||||
%else
|
|
||||||
%global with_init_sysv 1
|
|
||||||
%endif
|
|
||||||
|
|
||||||
%global readme_suffix %{?rhel:Redhat%{?rhel}}%{!?rhel:Fedora}
|
%global readme_suffix %{?rhel:Redhat%{?rhel}}%{!?rhel:Fedora}
|
||||||
%global _hardened_build 1
|
%global _hardened_build 1
|
||||||
|
|
||||||
Name: zoneminder
|
Name: zoneminder
|
||||||
Version: 1.31.1
|
Version: 1.31.43
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: A camera monitoring and analysis tool
|
Summary: A camera monitoring and analysis tool
|
||||||
Group: System Environment/Daemons
|
Group: System Environment/Daemons
|
||||||
|
@ -41,18 +34,18 @@ Group: System Environment/Daemons
|
||||||
# Mootools is inder the MIT license: http://mootools.net/
|
# Mootools is inder the MIT license: http://mootools.net/
|
||||||
# CakePHP is under the MIT license: https://github.com/cakephp/cakephp
|
# CakePHP is under the MIT license: https://github.com/cakephp/cakephp
|
||||||
# Crud is under the MIT license: https://github.com/FriendsOfCake/crud
|
# Crud is under the MIT license: https://github.com/FriendsOfCake/crud
|
||||||
|
# CakePHP-Enum-Behavior is under the MIT license: https://github.com/asper/CakePHP-Enum-Behavior
|
||||||
License: GPLv2+ and LGPLv2+ and MIT
|
License: GPLv2+ and LGPLv2+ and MIT
|
||||||
URL: http://www.zoneminder.com/
|
URL: http://www.zoneminder.com/
|
||||||
|
|
||||||
Source0: https://github.com/ZoneMinder/ZoneMinder/archive/%{version}.tar.gz#/zoneminder-%{version}.tar.gz
|
Source0: https://github.com/ZoneMinder/ZoneMinder/archive/%{version}.tar.gz#/zoneminder-%{version}.tar.gz
|
||||||
Source1: https://github.com/FriendsOfCake/crud/archive/v%{crud_version}.tar.gz#/crud-%{crud_version}.tar.gz
|
Source1: https://github.com/ZoneMinder/crud/archive/v%{crud_version}.tar.gz#/crud-%{crud_version}.tar.gz
|
||||||
|
Source2: https://github.com/ZoneMinder/CakePHP-Enum-Behavior/archive/%{ceb_version}.tar.gz#/cakephp-enum-behavior-%{ceb_version}.tar.gz
|
||||||
|
|
||||||
%{?with_init_systemd:BuildRequires: systemd-devel}
|
BuildRequires: systemd-devel
|
||||||
%{?with_init_systemd:BuildRequires: mariadb-devel}
|
BuildRequires: mariadb-devel
|
||||||
%{?with_init_systemd:BuildRequires: perl-podlators}
|
BuildRequires: perl-podlators
|
||||||
%{?with_init_systemd:BuildRequires: polkit-devel}
|
BuildRequires: polkit-devel
|
||||||
%{?with_init_sysv:BuildRequires: mysql-devel}
|
|
||||||
%{?el6:BuildRequires: epel-rpm-macros}
|
|
||||||
BuildRequires: cmake >= 2.8.7
|
BuildRequires: cmake >= 2.8.7
|
||||||
BuildRequires: gnutls-devel
|
BuildRequires: gnutls-devel
|
||||||
BuildRequires: bzip2-devel
|
BuildRequires: bzip2-devel
|
||||||
|
@ -82,6 +75,7 @@ BuildRequires: vlc-devel
|
||||||
BuildRequires: libcurl-devel
|
BuildRequires: libcurl-devel
|
||||||
BuildRequires: libv4l-devel
|
BuildRequires: libv4l-devel
|
||||||
BuildRequires: ffmpeg-devel
|
BuildRequires: ffmpeg-devel
|
||||||
|
BuildRequires: desktop-file-utils
|
||||||
|
|
||||||
# Required for mp4 container support
|
# Required for mp4 container support
|
||||||
BuildRequires: libmp4v2-devel
|
BuildRequires: libmp4v2-devel
|
||||||
|
@ -116,19 +110,10 @@ Requires: perl(LWP::Protocol::https)
|
||||||
Requires: ca-certificates
|
Requires: ca-certificates
|
||||||
Requires: zip
|
Requires: zip
|
||||||
|
|
||||||
%{?with_init_systemd:Requires(post): systemd}
|
Requires(post): systemd
|
||||||
%{?with_init_systemd:Requires(post): systemd-sysv}
|
Requires(post): systemd-sysv
|
||||||
%{?with_init_systemd:Requires(preun): systemd}
|
Requires(preun): systemd
|
||||||
%{?with_init_systemd:Requires(postun): systemd}
|
Requires(postun): systemd
|
||||||
|
|
||||||
%{?with_init_sysv:Requires(post): /sbin/chkconfig}
|
|
||||||
%{?with_init_sysv:Requires(post): %{_bindir}/checkmodule}
|
|
||||||
%{?with_init_sysv:Requires(post): %{_bindir}/semodule_package}
|
|
||||||
%{?with_init_sysv:Requires(post): %{_sbindir}/semodule}
|
|
||||||
%{?with_init_sysv:Requires(preun): /sbin/chkconfig}
|
|
||||||
%{?with_init_sysv:Requires(preun): /sbin/service}
|
|
||||||
%{?with_init_sysv:Requires(preun): %{_sbindir}/semodule}
|
|
||||||
%{?with_init_sysv:Requires(postun): /sbin/service}
|
|
||||||
|
|
||||||
Requires(post): %{_bindir}/gpasswd
|
Requires(post): %{_bindir}/gpasswd
|
||||||
Requires(post): %{_bindir}/less
|
Requires(post): %{_bindir}/less
|
||||||
|
@ -147,6 +132,11 @@ too much degradation of performance.
|
||||||
%{__rm} -rf ./web/api/app/Plugin/Crud
|
%{__rm} -rf ./web/api/app/Plugin/Crud
|
||||||
%{__mv} -f crud-%{crud_version} ./web/api/app/Plugin/Crud
|
%{__mv} -f crud-%{crud_version} ./web/api/app/Plugin/Crud
|
||||||
|
|
||||||
|
# The all powerful autosetup macro does not work after the second source tarball
|
||||||
|
%{__gzip} -dc %{_sourcedir}/cakephp-enum-behavior-%{ceb_version}.tar.gz | tar -xvvf -
|
||||||
|
%{__rm} -rf ./web/api/app/Plugin/CakePHP-Enum-Behavior
|
||||||
|
%{__mv} -f CakePHP-Enum-Behavior-%{ceb_version} ./web/api/app/Plugin/CakePHP-Enum-Behavior
|
||||||
|
|
||||||
# Change the following default values
|
# Change the following default values
|
||||||
./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes
|
./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes
|
||||||
./utils/zmeditconfigdata.sh ZM_UPLOAD_FTP_LOC_DIR %{_localstatedir}/spool/zoneminder-upload
|
./utils/zmeditconfigdata.sh ZM_UPLOAD_FTP_LOC_DIR %{_localstatedir}/spool/zoneminder-upload
|
||||||
|
@ -167,6 +157,12 @@ too much degradation of performance.
|
||||||
%install
|
%install
|
||||||
%make_install
|
%make_install
|
||||||
|
|
||||||
|
desktop-file-install \
|
||||||
|
--dir %{buildroot}%{_datadir}/applications \
|
||||||
|
--delete-original \
|
||||||
|
--mode 644 \
|
||||||
|
%{buildroot}%{_datadir}/applications/zoneminder.desktop
|
||||||
|
|
||||||
# Remove unwanted files and folders
|
# Remove unwanted files and folders
|
||||||
find %{buildroot} \( -name .htaccess -or -name .editorconfig -or -name .packlist -or -name .git -or -name .gitignore -or -name .gitattributes -or -name .travis.yml \) -type f -delete > /dev/null 2>&1 || :
|
find %{buildroot} \( -name .htaccess -or -name .editorconfig -or -name .packlist -or -name .git -or -name .gitignore -or -name .gitattributes -or -name .travis.yml \) -type f -delete > /dev/null 2>&1 || :
|
||||||
|
|
||||||
|
@ -178,24 +174,10 @@ find %{buildroot}%{_datadir}/zoneminder/www/api \( -name cake -or -name cake.php
|
||||||
%{__ln_s} ../../../../../../../..%{_sysconfdir}/pki/tls/certs/ca-bundle.crt %{buildroot}%{_datadir}/zoneminder/www/api/lib/Cake/Config/cacert.pem
|
%{__ln_s} ../../../../../../../..%{_sysconfdir}/pki/tls/certs/ca-bundle.crt %{buildroot}%{_datadir}/zoneminder/www/api/lib/Cake/Config/cacert.pem
|
||||||
|
|
||||||
%post
|
%post
|
||||||
%if 0%{?with_init_sysv}
|
|
||||||
/sbin/chkconfig --add zoneminder
|
|
||||||
/sbin/chkconfig zoneminder on
|
|
||||||
|
|
||||||
# Create and load zoneminder selinux policy module
|
|
||||||
echo -e "\nCreating and installing a ZoneMinder SELinux policy module. Please wait.\n"
|
|
||||||
%{_bindir}/checkmodule -M -m -o %{_docdir}/%{name}-%{version}/local_zoneminder.mod %{_docdir}/%{name}-%{version}/local_zoneminder.te > /dev/null 2>&1 || :
|
|
||||||
%{_bindir}/semodule_package -o %{_docdir}/%{name}-%{version}/local_zoneminder.pp -m %{_docdir}/%{name}-%{version}/local_zoneminder.mod > /dev/null 2>&1 || :
|
|
||||||
%{_sbindir}/semodule -i %{_docdir}/%{name}-%{version}/local_zoneminder.pp > /dev/null 2>&1 || :
|
|
||||||
|
|
||||||
%endif
|
|
||||||
|
|
||||||
%if 0%{?with_init_systemd}
|
|
||||||
# Initial installation
|
# Initial installation
|
||||||
if [ $1 -eq 1 ] ; then
|
if [ $1 -eq 1 ] ; then
|
||||||
%systemd_post %{name}.service
|
%systemd_post %{name}.service
|
||||||
fi
|
fi
|
||||||
%endif
|
|
||||||
|
|
||||||
# Upgrade from a previous version of zoneminder
|
# Upgrade from a previous version of zoneminder
|
||||||
if [ $1 -eq 2 ] ; then
|
if [ $1 -eq 2 ] ; then
|
||||||
|
@ -249,34 +231,11 @@ EOF
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
%preun
|
%preun
|
||||||
%if 0%{?with_init_sysv}
|
|
||||||
if [ $1 -eq 0 ]; then
|
|
||||||
/sbin/service zoneminder stop > /dev/null 2>&1 || :
|
|
||||||
/sbin/chkconfig --del zoneminder
|
|
||||||
echo -e "\nRemoving ZoneMinder SELinux policy module. Please wait.\n"
|
|
||||||
%{_sbindir}/semodule -r local_zoneminder.pp
|
|
||||||
fi
|
|
||||||
%endif
|
|
||||||
|
|
||||||
%if 0%{?with_init_systemd}
|
|
||||||
%systemd_preun %{name}.service
|
%systemd_preun %{name}.service
|
||||||
%endif
|
|
||||||
|
|
||||||
%postun
|
%postun
|
||||||
%if 0%{?with_init_sysv}
|
|
||||||
if [ $1 -ge 1 ]; then
|
|
||||||
/sbin/service zoneminder condrestart > /dev/null 2>&1 || :
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Remove the doc folder.
|
|
||||||
rm -rf %{_docdir}/%{name}-%{version}
|
|
||||||
%endif
|
|
||||||
|
|
||||||
%if 0%{?with_init_systemd}
|
|
||||||
%systemd_postun_with_restart %{name}.service
|
%systemd_postun_with_restart %{name}.service
|
||||||
%endif
|
|
||||||
|
|
||||||
%if 0%{?with_init_systemd}
|
|
||||||
%triggerun -- zoneminder < 1.25.0-4
|
%triggerun -- zoneminder < 1.25.0-4
|
||||||
# Save the current service runlevel info
|
# Save the current service runlevel info
|
||||||
# User must manually run systemd-sysv-convert --apply zoneminder
|
# User must manually run systemd-sysv-convert --apply zoneminder
|
||||||
|
@ -286,7 +245,6 @@ rm -rf %{_docdir}/%{name}-%{version}
|
||||||
# Run these because the SysV package being removed won't do them
|
# Run these because the SysV package being removed won't do them
|
||||||
/sbin/chkconfig --del zoneminder >/dev/null 2>&1 || :
|
/sbin/chkconfig --del zoneminder >/dev/null 2>&1 || :
|
||||||
/bin/systemctl try-restart zoneminder.service >/dev/null 2>&1 || :
|
/bin/systemctl try-restart zoneminder.service >/dev/null 2>&1 || :
|
||||||
%endif
|
|
||||||
|
|
||||||
%files
|
%files
|
||||||
%license COPYING
|
%license COPYING
|
||||||
|
@ -304,25 +262,18 @@ rm -rf %{_docdir}/%{name}-%{version}
|
||||||
%config(noreplace) %attr(640,root,%{zmgid_final}) %{_sysconfdir}/zm/conf.d/*.conf
|
%config(noreplace) %attr(640,root,%{zmgid_final}) %{_sysconfdir}/zm/conf.d/*.conf
|
||||||
%ghost %attr(640,root,%{zmgid_final}) %{_sysconfdir}/zm/conf.d/zmcustom.conf
|
%ghost %attr(640,root,%{zmgid_final}) %{_sysconfdir}/zm/conf.d/zmcustom.conf
|
||||||
|
|
||||||
%config(noreplace) %attr(644,root,root) %{wwwconfdir}/zoneminder.conf
|
%config(noreplace) %attr(644,root,root) /etc/zm/www/zoneminder.conf
|
||||||
%config(noreplace) %{_sysconfdir}/logrotate.d/zoneminder
|
%config(noreplace) %{_sysconfdir}/logrotate.d/zoneminder
|
||||||
|
|
||||||
%if 0%{?with_nginx}
|
%if 0%{?with_nginx}
|
||||||
%config(noreplace) %{_sysconfdir}/php-fpm.d/zoneminder.conf
|
%config(noreplace) %{_sysconfdir}/php-fpm.d/zoneminder.conf
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
%if 0%{?with_init_systemd}
|
|
||||||
%{_tmpfilesdir}/zoneminder.conf
|
%{_tmpfilesdir}/zoneminder.conf
|
||||||
%{_unitdir}/zoneminder.service
|
%{_unitdir}/zoneminder.service
|
||||||
%{_datadir}/polkit-1/actions/com.zoneminder.systemctl.policy
|
%{_datadir}/polkit-1/actions/com.zoneminder.systemctl.policy
|
||||||
%{_datadir}/polkit-1/rules.d/com.zoneminder.systemctl.rules
|
%{_datadir}/polkit-1/rules.d/com.zoneminder.systemctl.rules
|
||||||
%{_bindir}/zmsystemctl.pl
|
%{_bindir}/zmsystemctl.pl
|
||||||
%endif
|
|
||||||
|
|
||||||
%if 0%{?with_init_sysv}
|
|
||||||
%doc distros/redhat/misc/local_zoneminder.te
|
|
||||||
%attr(755,root,root) %{_initrddir}/zoneminder
|
|
||||||
%endif
|
|
||||||
|
|
||||||
%{_bindir}/zma
|
%{_bindir}/zma
|
||||||
%{_bindir}/zmaudit.pl
|
%{_bindir}/zmaudit.pl
|
||||||
|
@ -341,6 +292,7 @@ rm -rf %{_docdir}/%{name}-%{version}
|
||||||
%{_bindir}/zmtelemetry.pl
|
%{_bindir}/zmtelemetry.pl
|
||||||
%{_bindir}/zmx10.pl
|
%{_bindir}/zmx10.pl
|
||||||
%{_bindir}/zmonvif-probe.pl
|
%{_bindir}/zmonvif-probe.pl
|
||||||
|
%{_bindir}/zmstats.pl
|
||||||
|
|
||||||
%{perl_vendorlib}/ZoneMinder*
|
%{perl_vendorlib}/ZoneMinder*
|
||||||
%{perl_vendorlib}/ONVIF*
|
%{perl_vendorlib}/ONVIF*
|
||||||
|
@ -351,6 +303,7 @@ rm -rf %{_docdir}/%{name}-%{version}
|
||||||
|
|
||||||
%{_libexecdir}/zoneminder/
|
%{_libexecdir}/zoneminder/
|
||||||
%{_datadir}/zoneminder/
|
%{_datadir}/zoneminder/
|
||||||
|
%{_datadir}/applications/*%{name}.desktop
|
||||||
|
|
||||||
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder
|
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder
|
||||||
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/events
|
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/events
|
||||||
|
@ -358,11 +311,18 @@ rm -rf %{_docdir}/%{name}-%{version}
|
||||||
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/sock
|
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/sock
|
||||||
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/swap
|
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/swap
|
||||||
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/temp
|
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/temp
|
||||||
|
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/cache/zoneminder
|
||||||
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/log/zoneminder
|
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/log/zoneminder
|
||||||
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/spool/zoneminder-upload
|
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/spool/zoneminder-upload
|
||||||
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/run/zoneminder
|
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/run/zoneminder
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Sun Apr 22 2018 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.31.42-1
|
||||||
|
- Remove support for sysvinit a.k.a. el6
|
||||||
|
- use desktop-file-install for new zoneminder.desktop file
|
||||||
|
- add new web cache folder
|
||||||
|
- 1.31.42 development snapshot
|
||||||
|
|
||||||
* Tue May 09 2017 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.30.4-1
|
* Tue May 09 2017 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.30.4-1
|
||||||
- modify autosetup macro parameters
|
- modify autosetup macro parameters
|
||||||
- modify requirements for php-pecl-acpu-bc package
|
- modify requirements for php-pecl-acpu-bc package
|
||||||
|
|
|
@ -6,6 +6,12 @@ ScriptAlias /zm/cgi-bin "/usr/lib/zoneminder/cgi-bin"
|
||||||
Require all granted
|
Require all granted
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
|
# Order matters. This Alias must come first
|
||||||
|
Alias /zm/cache /var/cache/zoneminder/cache
|
||||||
|
<Directory /var/cache/zoneminder/cache>
|
||||||
|
Options -Indexes +FollowSymLinks
|
||||||
|
</Directory>
|
||||||
|
|
||||||
Alias /zm /usr/share/zoneminder/www
|
Alias /zm /usr/share/zoneminder/www
|
||||||
<Directory /usr/share/zoneminder/www>
|
<Directory /usr/share/zoneminder/www>
|
||||||
php_flag register_globals off
|
php_flag register_globals off
|
||||||
|
@ -15,6 +21,28 @@ Alias /zm /usr/share/zoneminder/www
|
||||||
</IfModule>
|
</IfModule>
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
<Directory /usr/share/zoneminder/www/api>
|
# For better visibility, the following directives have been migrated from the
|
||||||
AllowOverride All
|
# default .htaccess files included with the CakePHP project.
|
||||||
|
# Parameters not set here are inherited from the parent directive above.
|
||||||
|
<Directory "/usr/share/zoneminder/www/api">
|
||||||
|
RewriteEngine on
|
||||||
|
RewriteRule ^$ app/webroot/ [L]
|
||||||
|
RewriteRule (.*) app/webroot/$1 [L]
|
||||||
|
RewriteBase /zm/api
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
|
<Directory "/usr/share/zoneminder/www/api/app">
|
||||||
|
RewriteEngine on
|
||||||
|
RewriteRule ^$ webroot/ [L]
|
||||||
|
RewriteRule (.*) webroot/$1 [L]
|
||||||
|
RewriteBase /zm/api
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
<Directory "/usr/share/zoneminder/www/api/app/webroot">
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteRule ^ index.php [L]
|
||||||
|
RewriteBase /zm/api
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
|
||||||
,liburi-encode-perl
|
,liburi-encode-perl
|
||||||
,libwww-perl
|
,libwww-perl
|
||||||
,libdata-uuid-perl
|
,libdata-uuid-perl
|
||||||
,libnumber-bytes-human
|
,libnumber-bytes-human-perl
|
||||||
,libfile-slurp-perl
|
,libfile-slurp-perl
|
||||||
,mysql-client | virtual-mysql-client
|
,mysql-client | virtual-mysql-client
|
||||||
,perl-modules
|
,perl-modules
|
||||||
|
|
|
@ -25,6 +25,7 @@ override_dh_auto_configure:
|
||||||
-DZM_SOCKDIR="/var/run/zm" \
|
-DZM_SOCKDIR="/var/run/zm" \
|
||||||
-DZM_TMPDIR="/tmp/zm" \
|
-DZM_TMPDIR="/tmp/zm" \
|
||||||
-DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \
|
-DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \
|
||||||
|
-DZM_CACHEDIR="/var/cache/zoneminder/cache" \
|
||||||
-DZM_DIR_EVENTS="/var/cache/zoneminder/events" \
|
-DZM_DIR_EVENTS="/var/cache/zoneminder/events" \
|
||||||
-DZM_DIR_IMAGES="/var/cache/zoneminder/images" \
|
-DZM_DIR_IMAGES="/var/cache/zoneminder/images" \
|
||||||
-DZM_PATH_ZMS="/zm/cgi-bin/nph-zms" \
|
-DZM_PATH_ZMS="/zm/cgi-bin/nph-zms" \
|
||||||
|
|
|
@ -3,6 +3,7 @@ var/lib/zm
|
||||||
var/cache/zoneminder/events
|
var/cache/zoneminder/events
|
||||||
var/cache/zoneminder/images
|
var/cache/zoneminder/images
|
||||||
var/cache/zoneminder/temp
|
var/cache/zoneminder/temp
|
||||||
|
var/cache/zoneminder/cache
|
||||||
usr/share/zoneminder/db
|
usr/share/zoneminder/db
|
||||||
etc/zm
|
etc/zm
|
||||||
etc/zm/conf.d
|
etc/zm/conf.d
|
||||||
|
|
|
@ -6,6 +6,12 @@ ScriptAlias /zm/cgi-bin "/usr/lib/zoneminder/cgi-bin"
|
||||||
Require all granted
|
Require all granted
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
|
# Order matters. This alias must come first.
|
||||||
|
Alias /zm/cache /var/cache/zoneminder/cache
|
||||||
|
<Directory /var/cache/zoneminder/cache>
|
||||||
|
Options -Indexes +FollowSymLinks
|
||||||
|
</Directory>
|
||||||
|
|
||||||
Alias /zm /usr/share/zoneminder/www
|
Alias /zm /usr/share/zoneminder/www
|
||||||
<Directory /usr/share/zoneminder/www>
|
<Directory /usr/share/zoneminder/www>
|
||||||
Options -Indexes +FollowSymLinks
|
Options -Indexes +FollowSymLinks
|
||||||
|
@ -14,6 +20,27 @@ Alias /zm /usr/share/zoneminder/www
|
||||||
</IfModule>
|
</IfModule>
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
<Directory /usr/share/zoneminder/www/api>
|
# For better visibility, the following directives have been migrated from the
|
||||||
AllowOverride All
|
# default .htaccess files included with the CakePHP project.
|
||||||
|
# Parameters not set here are inherited from the parent directive above.
|
||||||
|
<Directory "/usr/share/zoneminder/www/api">
|
||||||
|
RewriteEngine on
|
||||||
|
RewriteRule ^$ app/webroot/ [L]
|
||||||
|
RewriteRule (.*) app/webroot/$1 [L]
|
||||||
|
RewriteBase /zm/api
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
<Directory "/usr/share/zoneminder/www/api/app">
|
||||||
|
RewriteEngine on
|
||||||
|
RewriteRule ^$ webroot/ [L]
|
||||||
|
RewriteRule (.*) webroot/$1 [L]
|
||||||
|
RewriteBase /zm/api
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
<Directory "/usr/share/zoneminder/www/api/app/webroot">
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteRule ^ index.php [L]
|
||||||
|
RewriteBase /zm/api
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
|
@ -59,7 +59,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
|
||||||
,libsoap-wsdl-perl
|
,libsoap-wsdl-perl
|
||||||
,libio-socket-multicast-perl
|
,libio-socket-multicast-perl
|
||||||
,libdigest-sha-perl
|
,libdigest-sha-perl
|
||||||
,libsys-cpu-perl, libsys-cpuload-perl, libsys-meminfo-perl
|
,libsys-cpu-perl, libsys-meminfo-perl
|
||||||
,libdata-uuid-perl
|
,libdata-uuid-perl
|
||||||
,libnumber-bytes-human-perl
|
,libnumber-bytes-human-perl
|
||||||
,libfile-slurp-perl
|
,libfile-slurp-perl
|
||||||
|
|
|
@ -25,6 +25,7 @@ override_dh_auto_configure:
|
||||||
-DZM_SOCKDIR="/var/run/zm" \
|
-DZM_SOCKDIR="/var/run/zm" \
|
||||||
-DZM_TMPDIR="/tmp/zm" \
|
-DZM_TMPDIR="/tmp/zm" \
|
||||||
-DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \
|
-DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \
|
||||||
|
-DZM_CACHEDIR="/var/cache/zoneminder/cache" \
|
||||||
-DZM_DIR_EVENTS="/var/cache/zoneminder/events" \
|
-DZM_DIR_EVENTS="/var/cache/zoneminder/events" \
|
||||||
-DZM_DIR_IMAGES="/var/cache/zoneminder/images" \
|
-DZM_DIR_IMAGES="/var/cache/zoneminder/images" \
|
||||||
-DZM_PATH_ZMS="/zm/cgi-bin/nph-zms"
|
-DZM_PATH_ZMS="/zm/cgi-bin/nph-zms"
|
||||||
|
|
|
@ -3,7 +3,7 @@ var/lib/zm
|
||||||
var/cache/zoneminder/events
|
var/cache/zoneminder/events
|
||||||
var/cache/zoneminder/images
|
var/cache/zoneminder/images
|
||||||
var/cache/zoneminder/temp
|
var/cache/zoneminder/temp
|
||||||
|
var/cache/zoneminder/cache
|
||||||
usr/share/zoneminder/db
|
usr/share/zoneminder/db
|
||||||
usr/share/zoneminder/www/cache
|
|
||||||
etc/zm/
|
etc/zm/
|
||||||
etc/zm/conf.d
|
etc/zm/conf.d
|
||||||
|
|
|
@ -13,7 +13,7 @@ if [ "$1" = "configure" ]; then
|
||||||
chown www-data:root /var/log/zm
|
chown www-data:root /var/log/zm
|
||||||
chown www-data:www-data /var/lib/zm
|
chown www-data:www-data /var/lib/zm
|
||||||
if [ -z "$2" ]; then
|
if [ -z "$2" ]; then
|
||||||
chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/* /usr/share/zoneminder/www/cache
|
chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/*
|
||||||
fi
|
fi
|
||||||
if [ ! -e "/etc/apache2/mods-enabled/cgi.load" ] && [ "$(command -v a2enmod)" != "" ]; then
|
if [ ! -e "/etc/apache2/mods-enabled/cgi.load" ] && [ "$(command -v a2enmod)" != "" ]; then
|
||||||
echo "The cgi module is not enabled in apache2. I am enabling it using a2enmod cgi."
|
echo "The cgi module is not enabled in apache2. I am enabling it using a2enmod cgi."
|
||||||
|
@ -35,6 +35,7 @@ if [ "$1" = "configure" ]; then
|
||||||
else
|
else
|
||||||
DBSERVICE="mysql.service"
|
DBSERVICE="mysql.service"
|
||||||
fi
|
fi
|
||||||
|
echo "Detected db service is $DBSERVICE"
|
||||||
if systemctl is-failed --quiet $DBSERVICE; then
|
if systemctl is-failed --quiet $DBSERVICE; then
|
||||||
echo "$DBSERVICE is in a failed state; it will not be started."
|
echo "$DBSERVICE is in a failed state; it will not be started."
|
||||||
echo "If you have already resolved the problem preventing $DBSERVICE from running,"
|
echo "If you have already resolved the problem preventing $DBSERVICE from running,"
|
||||||
|
@ -53,13 +54,20 @@ if [ "$1" = "configure" ]; then
|
||||||
mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload
|
mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload
|
||||||
# test if database if already present...
|
# test if database if already present...
|
||||||
if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then
|
if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then
|
||||||
|
echo "Creating zm db"
|
||||||
cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf
|
cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf
|
||||||
# This creates the user.
|
# This creates the user.
|
||||||
echo "grant lock tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
echo "grant lock tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||||
else
|
else
|
||||||
|
echo "Updating permissions"
|
||||||
echo "grant lock tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
echo "grant lock tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
zmupdate.pl --nointeractive
|
||||||
|
zmupdate.pl --nointeractive -f
|
||||||
|
|
||||||
|
# Add any new PTZ control configurations to the database (will not overwrite)
|
||||||
|
zmcamtool.pl --import >/dev/null 2>&1
|
||||||
else
|
else
|
||||||
echo 'NOTE: MySQL/MariaDB not running; please start mysql and run dpkg-reconfigure zoneminder when it is running.'
|
echo 'NOTE: MySQL/MariaDB not running; please start mysql and run dpkg-reconfigure zoneminder when it is running.'
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
d /var/run/zm 0755 www-data www-data
|
d /var/run/zm 0755 www-data www-data
|
||||||
d /tmp/zm 0755 www-data www-data
|
d /tmp/zm 0755 www-data www-data
|
||||||
d /var/tmp/zm 0755 www-data www-data
|
d /var/tmp/zm 0755 www-data www-data
|
||||||
d /usr/share/zoneminder/www/cache 0755 www-data www-data
|
d /var/cache/zoneminder/cache 0755 www-data www-data
|
||||||
|
|
|
@ -45,8 +45,6 @@ The following notes are based on real problems which have occurred by those who
|
||||||
How to Install ZoneMinder
|
How to Install ZoneMinder
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
These instructions apply to all redhat distros and compatible clones, except for RHEL/CentOS 6.
|
|
||||||
|
|
||||||
ZoneMinder releases are now being hosted at RPM Fusion. New users should navigate the `RPM Fusion site <https://rpmfusion.org>`_ then follow the instructions to enable that repo. RHEL/CentOS users must also navaigate to the `EPEL Site <https://fedoraproject.org/wiki/EPEL>`_ and enable that repo as well. Once enabled, install ZoneMinder from the commandline:
|
ZoneMinder releases are now being hosted at RPM Fusion. New users should navigate the `RPM Fusion site <https://rpmfusion.org>`_ then follow the instructions to enable that repo. RHEL/CentOS users must also navaigate to the `EPEL Site <https://fedoraproject.org/wiki/EPEL>`_ and enable that repo as well. Once enabled, install ZoneMinder from the commandline:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
@ -57,13 +55,6 @@ Note that RHEL/CentOS 7 users should use yum instead of dnf.
|
||||||
|
|
||||||
Once ZoneMinder has been installed, it is critically important that you read the README file under /usr/share/doc/zoneminder. ZoneMinder will not run without completing the steps outlined in the README.
|
Once ZoneMinder has been installed, it is critically important that you read the README file under /usr/share/doc/zoneminder. ZoneMinder will not run without completing the steps outlined in the README.
|
||||||
|
|
||||||
How to Install ZoneMinder on RHEL/CentOS 6
|
|
||||||
------------------------------------------
|
|
||||||
|
|
||||||
We continue to encounter build problems, caused by the age of this distro. It is unforuntate, but we can see the writing on the wall. We do not have a date set, but the end of the line for this distros is near.
|
|
||||||
|
|
||||||
Please be advised that we do not recommend any new ZoneMinder installations using CentOS 6. However, for the time being, ZoneMinder rpms will continue to be hosted at `zmrepo <https://www.zoneminder.com>`_.
|
|
||||||
|
|
||||||
How to Install Nightly Development Builds
|
How to Install Nightly Development Builds
|
||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -147,6 +147,23 @@ Keep aspect ratio
|
||||||
Orientation
|
Orientation
|
||||||
As per local devices.
|
As per local devices.
|
||||||
|
|
||||||
|
WebSite
|
||||||
|
^^^^^^^
|
||||||
|
|
||||||
|
This Source Type allows one to configure an arbitrary website as a non-reocrdable, fully interactive, monitor in ZoneMinder. Note that sites with self-signed certificates will not display until the end user first manually navigates to the site and accpets the unsigned certificate. Also note that some sites will set an X-Frame option in the header, which discourages their site from being displayed within a frame. ZoneMinder will detect this condition and present a warning in the log. When this occurs, the end user can choose to install a browser plugin or extension to workaround this issue.
|
||||||
|
|
||||||
|
Website URL
|
||||||
|
Enter the full http or https url to the desired website.
|
||||||
|
|
||||||
|
Width (pixels)
|
||||||
|
Chose a desired width in pixels that gives an acceptable appearance. This may take some expirimentation.
|
||||||
|
|
||||||
|
Height (pixels)
|
||||||
|
Chose a desired height in pixels that gives an acceptable appearance. This may take some expirimentation.
|
||||||
|
|
||||||
|
Web Site Refresh
|
||||||
|
If the website in question has static content, optionally enter a time period in seconds for ZoneMinder to refresh the content.
|
||||||
|
|
||||||
Timestamp Tab
|
Timestamp Tab
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,23 @@
|
||||||
ServerAdmin webmaster@localhost
|
ServerAdmin webmaster@localhost
|
||||||
|
|
||||||
DocumentRoot "@WEB_PREFIX@"
|
DocumentRoot "@WEB_PREFIX@"
|
||||||
|
|
||||||
|
# Order matters. This alias must come first.
|
||||||
|
Alias /zm/cache "@ZM_CACHEDIR@"
|
||||||
|
<Directory "@ZM_CACHEDIR@">
|
||||||
|
Options -Indexes +FollowSymLinks
|
||||||
|
AllowOverride None
|
||||||
|
<IfModule mod_authz_core.c>
|
||||||
|
# Apache 2.4
|
||||||
|
Require all granted
|
||||||
|
</IfModule>
|
||||||
|
<IfModule !mod_authz_core.c>
|
||||||
|
# Apache 2.2
|
||||||
|
Order deny,allow
|
||||||
|
Allow from all
|
||||||
|
</IfModule>
|
||||||
|
</Directory>
|
||||||
|
|
||||||
Alias /zm "@WEB_PREFIX@"
|
Alias /zm "@WEB_PREFIX@"
|
||||||
<Directory "@WEB_PREFIX@">
|
<Directory "@WEB_PREFIX@">
|
||||||
Options -Indexes +FollowSymLinks
|
Options -Indexes +FollowSymLinks
|
||||||
|
@ -38,6 +55,31 @@
|
||||||
</IfModule>
|
</IfModule>
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
|
# For better visibility, the following directives have been migrated from the
|
||||||
|
# default .htaccess files included with the CakePHP project.
|
||||||
|
# Parameters not set here are inherited from the parent directive above.
|
||||||
|
<Directory "@ZM_WEBDIR@/api">
|
||||||
|
RewriteEngine on
|
||||||
|
RewriteRule ^$ app/webroot/ [L]
|
||||||
|
RewriteRule (.*) app/webroot/$1 [L]
|
||||||
|
RewriteBase /zm/api
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
<Directory "@ZM_WEBDIR@/api/app">
|
||||||
|
RewriteEngine on
|
||||||
|
RewriteRule ^$ webroot/ [L]
|
||||||
|
RewriteRule (.*) webroot/$1 [L]
|
||||||
|
RewriteBase /zm/api
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
<Directory "@ZM_WEBDIR@/api/app/webroot">
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteRule ^ index.php [L]
|
||||||
|
RewriteBase /zm/api
|
||||||
|
</Directory>
|
||||||
|
|
||||||
# Use the first option to have Apache logs written to the general log
|
# Use the first option to have Apache logs written to the general log
|
||||||
# directory, or the second to have them written to the regular Apache
|
# directory, or the second to have them written to the regular Apache
|
||||||
# directory (you may have to change the path to that used on your system)
|
# directory (you may have to change the path to that used on your system)
|
||||||
|
|
|
@ -5,4 +5,3 @@ Name=ZoneMinder
|
||||||
Comment=
|
Comment=
|
||||||
Icon=@PKGDATADIR@/icons/16x16/icon.xpm
|
Icon=@PKGDATADIR@/icons/16x16/icon.xpm
|
||||||
URL=http://localhost/zm/\r
|
URL=http://localhost/zm/\r
|
||||||
Categories=GNOME;AudioVideo;Video;Recorder;
|
|
||||||
|
|
|
@ -1723,26 +1723,6 @@ our @options = (
|
||||||
type => $types{abs_path},
|
type => $types{abs_path},
|
||||||
category => 'config',
|
category => 'config',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name => 'ZM_SIGNAL_CHECK_POINTS',
|
|
||||||
default => '10',
|
|
||||||
description => 'How many points in a captured image to check for signal loss',
|
|
||||||
help => q`
|
|
||||||
For locally attached video cameras ZoneMinder can check for
|
|
||||||
signal loss by looking at a number of random points on each
|
|
||||||
captured image. If all of these points are set to the same
|
|
||||||
fixed colour then the camera is assumed to have lost signal.
|
|
||||||
When this happens any open events are closed and a short one
|
|
||||||
frame signal loss event is generated, as is another when the
|
|
||||||
signal returns. This option defines how many points on each
|
|
||||||
image to check. Note that this is a maximum, any points found
|
|
||||||
to not have the check colour will abort any further checks so
|
|
||||||
in most cases on a couple of points will actually be checked.
|
|
||||||
Network and file based cameras are never checked.
|
|
||||||
`,
|
|
||||||
type => $types{integer},
|
|
||||||
category => 'config',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name => 'ZM_V4L_MULTI_BUFFER',
|
name => 'ZM_V4L_MULTI_BUFFER',
|
||||||
default => 'yes',
|
default => 'yes',
|
||||||
|
@ -2966,6 +2946,23 @@ our @options = (
|
||||||
type => $types{boolean},
|
type => $types{boolean},
|
||||||
category => 'web',
|
category => 'web',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name => 'ZM_WEB_XFRAME_WARN',
|
||||||
|
default => 'yes',
|
||||||
|
description => 'Warn when website X-Frame-Options is set to sameorigin',
|
||||||
|
help => q`
|
||||||
|
When creating a Web Site monitor, if the target web site has
|
||||||
|
X-Frame-Options set to sameorigin in the header, the site will
|
||||||
|
not display in ZoneMinder. This is a design feature in most modern
|
||||||
|
browsers. When this condiction has occured, ZoneMinder will write a
|
||||||
|
warning to the log file. To get around this, one can install a browser
|
||||||
|
plugin or extension to ignore X-Frame headers, and then the page will
|
||||||
|
display properly. Once the plugin or extenstion has ben installed,
|
||||||
|
the end user may choose to turn this warning off.
|
||||||
|
`,
|
||||||
|
type => $types{boolean},
|
||||||
|
category => 'web',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name => 'ZM_WEB_H_REFRESH_MAIN',
|
name => 'ZM_WEB_H_REFRESH_MAIN',
|
||||||
default => '60',
|
default => '60',
|
||||||
|
|
|
@ -397,7 +397,7 @@ sub delete {
|
||||||
if ( (! $Config{ZM_OPT_FAST_DELETE}) and $event->Storage()->DoDelete() ) {
|
if ( (! $Config{ZM_OPT_FAST_DELETE}) and $event->Storage()->DoDelete() ) {
|
||||||
$event->delete_files( );
|
$event->delete_files( );
|
||||||
} else {
|
} else {
|
||||||
Debug('Not deleting frames, stats and files for speed.');
|
Debug('Not deleting event files from '.$event->Path().' for speed.');
|
||||||
}
|
}
|
||||||
} # end sub delete
|
} # end sub delete
|
||||||
|
|
||||||
|
@ -519,6 +519,22 @@ sub DiskSpace {
|
||||||
sub MoveTo {
|
sub MoveTo {
|
||||||
my ( $self, $NewStorage ) = @_;
|
my ( $self, $NewStorage ) = @_;
|
||||||
|
|
||||||
|
my $OldStorage = $self->Storage(undef);
|
||||||
|
my ( $OldPath ) = ( $self->Path() =~ /^(.*)$/ ); # De-taint
|
||||||
|
if ( ! -e $OldPath ) {
|
||||||
|
return "Old path $OldPath does not exist.";
|
||||||
|
}
|
||||||
|
# First determine if we can move it to the dest.
|
||||||
|
# We do this before bothering to lock the event
|
||||||
|
my ( $NewPath ) = ( $NewStorage->Path() =~ /^(.*)$/ ); # De-taint
|
||||||
|
if ( ! $$NewStorage{Id} ) {
|
||||||
|
return "New storage does not have an id. Moving will not happen.";
|
||||||
|
} elsif ( !$NewPath ) {
|
||||||
|
return "New path ($NewPath) is empty.";
|
||||||
|
} elsif ( ! -e $NewPath ) {
|
||||||
|
return "New path $NewPath does not exist.";
|
||||||
|
}
|
||||||
|
|
||||||
$ZoneMinder::Database::dbh->begin_work();
|
$ZoneMinder::Database::dbh->begin_work();
|
||||||
$self->lock_and_load();
|
$self->lock_and_load();
|
||||||
# data is reloaded, so need to check that the move hasn't already happened.
|
# data is reloaded, so need to check that the move hasn't already happened.
|
||||||
|
@ -526,25 +542,13 @@ sub MoveTo {
|
||||||
$ZoneMinder::Database::dbh->commit();
|
$ZoneMinder::Database::dbh->commit();
|
||||||
return "Event has already been moved by someone else.";
|
return "Event has already been moved by someone else.";
|
||||||
}
|
}
|
||||||
my $OldStorage = $self->Storage(undef);
|
|
||||||
my ( $OldPath ) = ( $self->Path() =~ /^(.*)$/ ); # De-taint
|
if ( $$OldStorage{Id} != $$self{StorageId} ) {
|
||||||
|
$ZoneMinder::Database::dbh->commit();
|
||||||
|
return "Old Storage path changed, Event has moved somewhere else.";
|
||||||
|
}
|
||||||
|
|
||||||
$$self{Storage} = $NewStorage;
|
$$self{Storage} = $NewStorage;
|
||||||
|
|
||||||
my ( $NewPath ) = ( $NewStorage->Path() =~ /^(.*)$/ ); # De-taint
|
|
||||||
if ( ! $$NewStorage{Id} ) {
|
|
||||||
$ZoneMinder::Database::dbh->commit();
|
|
||||||
return "New storage does not have an id. Moving will not happen.";
|
|
||||||
} elsif ( !$NewPath ) {
|
|
||||||
$ZoneMinder::Database::dbh->commit();
|
|
||||||
return "New path ($NewPath) is empty.";
|
|
||||||
} elsif ( ! -e $NewPath ) {
|
|
||||||
$ZoneMinder::Database::dbh->commit();
|
|
||||||
return "New path $NewPath does not exist.";
|
|
||||||
} elsif ( ! -e $OldPath ) {
|
|
||||||
$ZoneMinder::Database::dbh->commit();
|
|
||||||
return "Old path $OldPath does not exist.";
|
|
||||||
}
|
|
||||||
( $NewPath ) = ( $self->Path(undef) =~ /^(.*)$/ ); # De-taint
|
( $NewPath ) = ( $self->Path(undef) =~ /^(.*)$/ ); # De-taint
|
||||||
if ( $NewPath eq $OldPath ) {
|
if ( $NewPath eq $OldPath ) {
|
||||||
$ZoneMinder::Database::dbh->commit();
|
$ZoneMinder::Database::dbh->commit();
|
||||||
|
|
|
@ -160,9 +160,12 @@ sub Sql {
|
||||||
if ( $term->{attr} =~ /^Monitor/ ) {
|
if ( $term->{attr} =~ /^Monitor/ ) {
|
||||||
my ( $temp_attr_name ) = $term->{attr} =~ /^Monitor(.+)$/;
|
my ( $temp_attr_name ) = $term->{attr} =~ /^Monitor(.+)$/;
|
||||||
$self->{Sql} .= 'M.'.$temp_attr_name;
|
$self->{Sql} .= 'M.'.$temp_attr_name;
|
||||||
} elsif ( $term->{attr} =~ /^Server/ ) {
|
} elsif ( $term->{attr} eq 'ServerId' or $term->{attr} eq 'MonitorServerId' ) {
|
||||||
|
$self->{Sql} .= 'M.'.$term->{attr};
|
||||||
|
} elsif ( $term->{attr} eq 'StorageServerId' ) {
|
||||||
$self->{Sql} .= 'S.'.$term->{attr};
|
$self->{Sql} .= 'S.'.$term->{attr};
|
||||||
|
} elsif ( $term->{attr} eq 'FilterServerId' ) {
|
||||||
|
$self->{Sql} .= $Config{ZM_SERVER_ID};
|
||||||
# StartTime options
|
# StartTime options
|
||||||
} elsif ( $term->{attr} eq 'DateTime' ) {
|
} elsif ( $term->{attr} eq 'DateTime' ) {
|
||||||
$self->{Sql} .= 'E.StartTime';
|
$self->{Sql} .= 'E.StartTime';
|
||||||
|
@ -172,7 +175,7 @@ sub Sql {
|
||||||
$self->{Sql} .= 'to_days( E.StartTime )';
|
$self->{Sql} .= 'to_days( E.StartTime )';
|
||||||
} elsif ( $term->{attr} eq 'StartDate' ) {
|
} elsif ( $term->{attr} eq 'StartDate' ) {
|
||||||
$self->{Sql} .= 'to_days( E.StartTime )';
|
$self->{Sql} .= 'to_days( E.StartTime )';
|
||||||
} elsif ( $term->{attr} eq 'Time' ) {
|
} elsif ( $term->{attr} eq 'Time' or $term->{attr} eq 'StartTime' ) {
|
||||||
$self->{Sql} .= 'extract( hour_second from E.StartTime )';
|
$self->{Sql} .= 'extract( hour_second from E.StartTime )';
|
||||||
} elsif ( $term->{attr} eq 'Weekday' ) {
|
} elsif ( $term->{attr} eq 'Weekday' ) {
|
||||||
$self->{Sql} .= 'weekday( E.StartTime )';
|
$self->{Sql} .= 'weekday( E.StartTime )';
|
||||||
|
@ -208,7 +211,7 @@ sub Sql {
|
||||||
foreach my $temp_value ( split( /["'\s]*?,["'\s]*?/, $stripped_value ) ) {
|
foreach my $temp_value ( split( /["'\s]*?,["'\s]*?/, $stripped_value ) ) {
|
||||||
if ( $term->{attr} =~ /^MonitorName/ ) {
|
if ( $term->{attr} =~ /^MonitorName/ ) {
|
||||||
$value = "'$temp_value'";
|
$value = "'$temp_value'";
|
||||||
} elsif ( $term->{attr} eq 'ServerId' ) {
|
} elsif ( $term->{attr} =~ /ServerId/) {
|
||||||
Debug("ServerId, temp_value is ($temp_value) ($ZoneMinder::Config::Config{ZM_SERVER_ID})");
|
Debug("ServerId, temp_value is ($temp_value) ($ZoneMinder::Config::Config{ZM_SERVER_ID})");
|
||||||
if ( $temp_value eq 'ZM_SERVER_ID' ) {
|
if ( $temp_value eq 'ZM_SERVER_ID' ) {
|
||||||
$value = "'$ZoneMinder::Config::Config{ZM_SERVER_ID}'";
|
$value = "'$ZoneMinder::Config::Config{ZM_SERVER_ID}'";
|
||||||
|
@ -241,7 +244,7 @@ sub Sql {
|
||||||
}
|
}
|
||||||
$value = "'$value'";
|
$value = "'$value'";
|
||||||
}
|
}
|
||||||
} elsif ( $term->{attr} eq 'Date' or $term->{attr} eq 'StartDate' or $term->{attr} eq 'EndDate' ) {
|
} elsif ( $term->{attr} eq 'Date' or $term->{attr} eq 'StartDate' or $term->{attr} eq 'EndDate' ) {
|
||||||
if ( $temp_value eq 'NULL' ) {
|
if ( $temp_value eq 'NULL' ) {
|
||||||
$value = $temp_value;
|
$value = $temp_value;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -147,7 +147,7 @@ our $mem_data = {
|
||||||
last_write_index => { type=>'uint32', seq=>$mem_seq++ },
|
last_write_index => { type=>'uint32', seq=>$mem_seq++ },
|
||||||
last_read_index => { type=>'uint32', seq=>$mem_seq++ },
|
last_read_index => { type=>'uint32', seq=>$mem_seq++ },
|
||||||
state => { type=>'uint32', seq=>$mem_seq++ },
|
state => { type=>'uint32', seq=>$mem_seq++ },
|
||||||
last_event => { type=>'uint32', seq=>$mem_seq++ },
|
last_event => { type=>'uint64', seq=>$mem_seq++ },
|
||||||
action => { type=>'uint32', seq=>$mem_seq++ },
|
action => { type=>'uint32', seq=>$mem_seq++ },
|
||||||
brightness => { type=>'int32', seq=>$mem_seq++ },
|
brightness => { type=>'int32', seq=>$mem_seq++ },
|
||||||
hue => { type=>'int32', seq=>$mem_seq++ },
|
hue => { type=>'int32', seq=>$mem_seq++ },
|
||||||
|
@ -167,7 +167,6 @@ our $mem_data = {
|
||||||
last_read_time => { type=>'time_t64', seq=>$mem_seq++ },
|
last_read_time => { type=>'time_t64', seq=>$mem_seq++ },
|
||||||
control_state => { type=>'uint8[256]', seq=>$mem_seq++ },
|
control_state => { type=>'uint8[256]', seq=>$mem_seq++ },
|
||||||
alarm_cause => { type=>'int8[256]', seq=>$mem_seq++ },
|
alarm_cause => { type=>'int8[256]', seq=>$mem_seq++ },
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
trigger_data => { type=>'TriggerData', seq=>$mem_seq++, 'contents'=> {
|
trigger_data => { type=>'TriggerData', seq=>$mem_seq++, 'contents'=> {
|
||||||
|
|
|
@ -42,6 +42,7 @@ our @ISA = qw(Exporter ZoneMinder::Base);
|
||||||
# will save memory.
|
# will save memory.
|
||||||
our %EXPORT_TAGS = (
|
our %EXPORT_TAGS = (
|
||||||
'functions' => [ qw(
|
'functions' => [ qw(
|
||||||
|
CpuLoad
|
||||||
) ]
|
) ]
|
||||||
);
|
);
|
||||||
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
||||||
|
@ -107,6 +108,17 @@ sub Hostname {
|
||||||
return $_[0]{Hostname};
|
return $_[0]{Hostname};
|
||||||
} # end sub Hostname
|
} # end sub Hostname
|
||||||
|
|
||||||
|
sub CpuLoad {
|
||||||
|
my $output = qx(uptime);
|
||||||
|
my @sysloads = split ', ', (split ': ', $output)[-1];
|
||||||
|
|
||||||
|
if (join(', ',@sysloads) =~ /(\d+\.\d+)\s*,\s+(\d+\.\d+)\s*,\s+(\d+\.\d+)\s*$/) {
|
||||||
|
return @sysloads;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (undef, undef, undef);
|
||||||
|
} # end sub CpuLoad
|
||||||
|
|
||||||
1;
|
1;
|
||||||
__END__
|
__END__
|
||||||
# Below is stub documentation for your module. You'd better edit it!
|
# Below is stub documentation for your module. You'd better edit it!
|
||||||
|
|
|
@ -113,6 +113,15 @@ sub Name {
|
||||||
return $_[0]{Name};
|
return $_[0]{Name};
|
||||||
} # end sub Path
|
} # end sub Path
|
||||||
|
|
||||||
|
sub DoDelete {
|
||||||
|
my $self = shift;
|
||||||
|
$$self{DoDelete} = shift if @_;
|
||||||
|
if ( ! defined $$self{DoDelete} ) {
|
||||||
|
$$self{DoDelete} = 1;
|
||||||
|
}
|
||||||
|
return $$self{DoDelete};
|
||||||
|
}
|
||||||
|
|
||||||
sub Server {
|
sub Server {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
if ( ! $$self{Server} ) {
|
if ( ! $$self{Server} ) {
|
||||||
|
|
|
@ -63,6 +63,7 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
|
||||||
my $report = 0;
|
my $report = 0;
|
||||||
my $interactive = 0;
|
my $interactive = 0;
|
||||||
my $continuous = 0;
|
my $continuous = 0;
|
||||||
|
my $level = 1;
|
||||||
my $monitor_id = 0;
|
my $monitor_id = 0;
|
||||||
my $version;
|
my $version;
|
||||||
my $force = 0;
|
my $force = 0;
|
||||||
|
@ -74,6 +75,7 @@ GetOptions(
|
||||||
continuous =>\$continuous,
|
continuous =>\$continuous,
|
||||||
force =>\$force,
|
force =>\$force,
|
||||||
interactive =>\$interactive,
|
interactive =>\$interactive,
|
||||||
|
level =>\$level,
|
||||||
'monitor_id=i' =>\$monitor_id,
|
'monitor_id=i' =>\$monitor_id,
|
||||||
report =>\$report,
|
report =>\$report,
|
||||||
'storage_id=i' =>\$storage_id,
|
'storage_id=i' =>\$storage_id,
|
||||||
|
@ -485,7 +487,9 @@ MAIN: while( $loop ) {
|
||||||
redo MAIN;
|
redo MAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( $level > 1 ) {
|
||||||
# Remove orphaned events (with no monitor)
|
# Remove orphaned events (with no monitor)
|
||||||
|
# Shouldn't be possible anymore with FOREIGN KEYS in place
|
||||||
$cleaned = 0;
|
$cleaned = 0;
|
||||||
Debug("Checking for Orphaned Events");
|
Debug("Checking for Orphaned Events");
|
||||||
my $selectOrphanedEventsSql = 'SELECT Events.Id, Events.Name
|
my $selectOrphanedEventsSql = 'SELECT Events.Id, Events.Name
|
||||||
|
@ -507,6 +511,7 @@ MAIN: while( $loop ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
redo MAIN if $cleaned;
|
redo MAIN if $cleaned;
|
||||||
|
} # end if level > 1
|
||||||
|
|
||||||
# Remove empty events (with no frames)
|
# Remove empty events (with no frames)
|
||||||
$cleaned = 0;
|
$cleaned = 0;
|
||||||
|
@ -537,7 +542,7 @@ MAIN: while( $loop ) {
|
||||||
$cleaned = 0;
|
$cleaned = 0;
|
||||||
Debug("Checking for Orphaned Frames");
|
Debug("Checking for Orphaned Frames");
|
||||||
my $selectOrphanedFramesSql = 'SELECT DISTINCT EventId FROM Frames
|
my $selectOrphanedFramesSql = 'SELECT DISTINCT EventId FROM Frames
|
||||||
WHERE EventId NOT IN (SELECT Id FROM Events)';
|
WHERE (SELECT COUNT(*) FROM Events WHERE Events.Id=EventId)=0';
|
||||||
my $selectOrphanedFramesSth = $dbh->prepare_cached( $selectOrphanedFramesSql )
|
my $selectOrphanedFramesSth = $dbh->prepare_cached( $selectOrphanedFramesSql )
|
||||||
or Fatal( "Can't prepare '$selectOrphanedFramesSql': ".$dbh->errstr() );
|
or Fatal( "Can't prepare '$selectOrphanedFramesSql': ".$dbh->errstr() );
|
||||||
$res = $selectOrphanedFramesSth->execute()
|
$res = $selectOrphanedFramesSth->execute()
|
||||||
|
@ -552,6 +557,7 @@ MAIN: while( $loop ) {
|
||||||
}
|
}
|
||||||
redo MAIN if $cleaned;
|
redo MAIN if $cleaned;
|
||||||
|
|
||||||
|
if ( $level > 1 ) {
|
||||||
# Remove orphaned stats records
|
# Remove orphaned stats records
|
||||||
$cleaned = 0;
|
$cleaned = 0;
|
||||||
Debug("Checking for Orphaned Stats");
|
Debug("Checking for Orphaned Stats");
|
||||||
|
@ -570,6 +576,7 @@ MAIN: while( $loop ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
redo MAIN if ( $cleaned );
|
redo MAIN if ( $cleaned );
|
||||||
|
}
|
||||||
|
|
||||||
# New audit to close any events that were left open for longer than MIN_AGE seconds
|
# New audit to close any events that were left open for longer than MIN_AGE seconds
|
||||||
my $selectUnclosedEventsSql =
|
my $selectUnclosedEventsSql =
|
||||||
|
|
|
@ -104,23 +104,23 @@ my @daemons = (
|
||||||
'zmtelemetry.pl'
|
'zmtelemetry.pl'
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($Config{ZM_OPT_USE_EVENTNOTIFICATION}) {
|
if ( $Config{ZM_OPT_USE_EVENTNOTIFICATION} ) {
|
||||||
push @daemons,'zmeventnotification.pl';
|
push @daemons,'zmeventnotification.pl';
|
||||||
}
|
}
|
||||||
|
|
||||||
my $command = shift @ARGV;
|
my $command = shift @ARGV;
|
||||||
if( ! $command ) {
|
if ( !$command ) {
|
||||||
print( STDERR "No command given\n" );
|
print(STDERR "No command given\n");
|
||||||
pod2usage(-exitstatus => -1);
|
pod2usage(-exitstatus => -1);
|
||||||
}
|
}
|
||||||
if ( $command eq 'version' ) {
|
if ( $command eq 'version' ) {
|
||||||
print ZoneMinder::Base::ZM_VERSION."\n";
|
print ZoneMinder::Base::ZM_VERSION."\n";
|
||||||
exit( 0 );
|
exit(0);
|
||||||
}
|
}
|
||||||
my $needs_daemon = $command !~ /(?:startup|shutdown|status|check|logrot|version)/;
|
my $needs_daemon = $command !~ /(?:startup|shutdown|status|check|logrot|version)/;
|
||||||
my $daemon = shift( @ARGV );
|
my $daemon = shift @ARGV;
|
||||||
if ( $needs_daemon && ! $daemon ) {
|
if ( $needs_daemon && ! $daemon ) {
|
||||||
print( STDERR "No daemon given\n" );
|
print(STDERR "No daemon given\n");
|
||||||
pod2usage(-exitstatus => -1);
|
pod2usage(-exitstatus => -1);
|
||||||
}
|
}
|
||||||
my @args;
|
my @args;
|
||||||
|
@ -130,7 +130,7 @@ if ( $needs_daemon ) {
|
||||||
if ( $daemon =~ /^${daemon_patt}$/ ) {
|
if ( $daemon =~ /^${daemon_patt}$/ ) {
|
||||||
$daemon = $1;
|
$daemon = $1;
|
||||||
} else {
|
} else {
|
||||||
print( STDERR "Invalid daemon '$daemon' specified" );
|
print(STDERR "Invalid daemon '$daemon' specified");
|
||||||
pod2usage(-exitstatus => -1);
|
pod2usage(-exitstatus => -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,22 +141,22 @@ foreach my $arg ( @ARGV ) {
|
||||||
if ( $arg =~ /^(-{0,2}[\w\/?&=.-]+)$/ ) {
|
if ( $arg =~ /^(-{0,2}[\w\/?&=.-]+)$/ ) {
|
||||||
push( @args, $1 );
|
push( @args, $1 );
|
||||||
} else {
|
} else {
|
||||||
print( STDERR "Bogus argument '$arg' found" );
|
print(STDERR "Bogus argument '$arg' found");
|
||||||
exit( -1 );
|
exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
my $dbh = zmDbConnect();
|
my $dbh = zmDbConnect();
|
||||||
|
|
||||||
socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" );
|
socket(CLIENT, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!");
|
||||||
|
|
||||||
my $saddr = sockaddr_un( SOCK_FILE );
|
my $saddr = sockaddr_un(SOCK_FILE);
|
||||||
my $server_up = connect( CLIENT, $saddr );
|
my $server_up = connect(CLIENT, $saddr);
|
||||||
|
|
||||||
if ( ! $server_up ) {
|
if ( !$server_up ) {
|
||||||
if ( $Config{ZM_SERVER_ID} ) {
|
if ( $Config{ZM_SERVER_ID} ) {
|
||||||
use Sys::MemInfo qw(totalmem freemem totalswap freeswap);
|
use Sys::MemInfo qw(totalmem freemem totalswap freeswap);
|
||||||
use Sys::CpuLoad;
|
use ZoneMinder::Server qw(CpuLoad);
|
||||||
if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef,
|
if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef,
|
||||||
'NotRunning', &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) {
|
'NotRunning', &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) {
|
||||||
Error("Failed Updating status of Server record to Not RUnning for Id=$Config{ZM_SERVER_ID}" . $dbh->errstr());
|
Error("Failed Updating status of Server record to Not RUnning for Id=$Config{ZM_SERVER_ID}" . $dbh->errstr());
|
||||||
|
@ -168,16 +168,16 @@ use Sys::CpuLoad;
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
if ( $command eq 'check' ) {
|
if ( $command eq 'check' ) {
|
||||||
print( "stopped\n" );
|
print("stopped\n");
|
||||||
exit();
|
exit();
|
||||||
} elsif ( $command ne 'startup' ) {
|
} elsif ( $command ne 'startup' ) {
|
||||||
print( "Unable to connect to server using socket at " . SOCK_FILE . "\n" );
|
print("Unable to connect to server using socket at " . SOCK_FILE . "\n");
|
||||||
exit( -1 );
|
exit( -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
# The server isn't there
|
# The server isn't there
|
||||||
print( "Starting server\n" );
|
print("Starting server\n");
|
||||||
close( CLIENT );
|
close(CLIENT);
|
||||||
|
|
||||||
if ( my $cpid = fork() ) {
|
if ( my $cpid = fork() ) {
|
||||||
# Parent process just sleep and fall through
|
# Parent process just sleep and fall through
|
||||||
|
@ -185,7 +185,7 @@ use Sys::CpuLoad;
|
||||||
# I'm still not sure why we need to re-init the logs
|
# I'm still not sure why we need to re-init the logs
|
||||||
logInit();
|
logInit();
|
||||||
|
|
||||||
socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" );
|
socket(CLIENT, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!");
|
||||||
my $attempts = 0;
|
my $attempts = 0;
|
||||||
while( !connect(CLIENT, $saddr) ) {
|
while( !connect(CLIENT, $saddr) ) {
|
||||||
$attempts++;
|
$attempts++;
|
||||||
|
@ -209,7 +209,6 @@ if ( ($command eq 'check') && !$daemon ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
# The server is there, connect to it
|
# The server is there, connect to it
|
||||||
#print( "Writing commands\n" );
|
|
||||||
CLIENT->autoflush();
|
CLIENT->autoflush();
|
||||||
my $message = join(';', $command, ( $daemon ? $daemon : () ), @args );
|
my $message = join(';', $command, ( $daemon ? $daemon : () ), @args );
|
||||||
print(CLIENT $message);
|
print(CLIENT $message);
|
||||||
|
@ -218,9 +217,7 @@ while( my $line = <CLIENT> ) {
|
||||||
chomp($line);
|
chomp($line);
|
||||||
print("$line\n");
|
print("$line\n");
|
||||||
}
|
}
|
||||||
# And we're done!
|
|
||||||
close(CLIENT);
|
close(CLIENT);
|
||||||
#print( "Finished writing, bye\n" );
|
|
||||||
|
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
|
@ -237,45 +234,46 @@ use Socket;
|
||||||
use IO::Handle;
|
use IO::Handle;
|
||||||
use Time::HiRes qw(usleep);
|
use Time::HiRes qw(usleep);
|
||||||
use Sys::MemInfo qw(totalmem freemem totalswap freeswap);
|
use Sys::MemInfo qw(totalmem freemem totalswap freeswap);
|
||||||
use Sys::CpuLoad;
|
use ZoneMinder::Server qw(CpuLoad);
|
||||||
#use Data::Dumper;
|
#use Data::Dumper;
|
||||||
|
|
||||||
# We count 10 of these, so total timeout is this value *10.
|
use constant KILL_DELAY => 60; # seconds to wait between sending TERM and sending KILL
|
||||||
use constant KILL_DELAY => 1; # seconds
|
|
||||||
|
|
||||||
our %cmd_hash;
|
our %cmd_hash;
|
||||||
our %pid_hash;
|
our %pid_hash;
|
||||||
|
our %terminating_processes;
|
||||||
|
|
||||||
sub run {
|
sub run {
|
||||||
my $fd = 0;
|
my $fd = 0;
|
||||||
while( $fd < POSIX::sysconf( &POSIX::_SC_OPEN_MAX ) ) {
|
while( $fd < POSIX::sysconf(&POSIX::_SC_OPEN_MAX) ) {
|
||||||
POSIX::close( $fd++ );
|
POSIX::close($fd++);
|
||||||
}
|
}
|
||||||
|
|
||||||
setpgrp();
|
setpgrp();
|
||||||
|
|
||||||
logInit();
|
logInit();
|
||||||
|
|
||||||
dPrint( ZoneMinder::Logger::INFO, 'Server starting at '
|
dPrint(ZoneMinder::Logger::INFO, 'Server starting at '
|
||||||
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
|
.strftime('%y/%m/%d %H:%M:%S', localtime())
|
||||||
."\n"
|
."\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( open( my $PID, '>', ZM_PID ) ) {
|
if ( open(my $PID, '>', ZM_PID) ) {
|
||||||
print( $PID $$ );
|
print($PID $$);
|
||||||
close( $PID );
|
close($PID);
|
||||||
} else {
|
} else {
|
||||||
Error( "Can't open pid file at " . ZM_PID );
|
Error("Can't open pid file at " . ZM_PID);
|
||||||
}
|
}
|
||||||
|
|
||||||
killAll( 1 );
|
# Tell any existing processes to die, wait 1 second between TERM and KILL
|
||||||
|
killAll(1);
|
||||||
|
|
||||||
dPrint( ZoneMinder::Logger::INFO, 'Socket should be open at ' .main::SOCK_FILE );
|
dPrint(ZoneMinder::Logger::INFO, 'Socket should be open at ' .main::SOCK_FILE);
|
||||||
my $dbh = zmDbConnect(1);
|
my $dbh = zmDbConnect(1);
|
||||||
socket( SERVER, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" );
|
socket(SERVER, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!");
|
||||||
unlink( main::SOCK_FILE ) or Error( 'Unable to unlink ' . main::SOCK_FILE .". Error message was: $!" ) if -e main::SOCK_FILE;
|
unlink(main::SOCK_FILE) or Error('Unable to unlink ' . main::SOCK_FILE .". Error message was: $!") if -e main::SOCK_FILE;
|
||||||
bind( SERVER, $saddr ) or Fatal( "Can't bind to " . main::SOCK_FILE . ": $!" );
|
bind(SERVER, $saddr) or Fatal("Can't bind to " . main::SOCK_FILE . ": $!");
|
||||||
listen( SERVER, SOMAXCONN ) or Fatal( "Can't listen: $!" );
|
listen(SERVER, SOMAXCONN) or Fatal("Can't listen: $!");
|
||||||
|
|
||||||
$SIG{CHLD} = \&reaper;
|
$SIG{CHLD} = \&reaper;
|
||||||
$SIG{INT} = \&shutdownAll;
|
$SIG{INT} = \&shutdownAll;
|
||||||
|
@ -284,7 +282,7 @@ sub run {
|
||||||
$SIG{HUP} = \&logrot;
|
$SIG{HUP} = \&logrot;
|
||||||
|
|
||||||
my $rin = '';
|
my $rin = '';
|
||||||
vec( $rin, fileno(SERVER), 1 ) = 1;
|
vec($rin, fileno(SERVER), 1) = 1;
|
||||||
my $win = $rin;
|
my $win = $rin;
|
||||||
my $ein = $win;
|
my $ein = $win;
|
||||||
my $timeout = 1;
|
my $timeout = 1;
|
||||||
|
@ -293,8 +291,8 @@ sub run {
|
||||||
|
|
||||||
if ( $Config{ZM_SERVER_ID} ) {
|
if ( $Config{ZM_SERVER_ID} ) {
|
||||||
require ZoneMinder::Server;
|
require ZoneMinder::Server;
|
||||||
$Server = new ZoneMinder::Server( $Config{ZM_SERVER_ID} );
|
$Server = new ZoneMinder::Server($Config{ZM_SERVER_ID});
|
||||||
dPrint( ZoneMinder::Logger::INFO, 'Loading Server record have ' . $$Server{Name} );
|
dPrint(ZoneMinder::Logger::INFO, 'Loading Server record have ' . $$Server{Name});
|
||||||
}
|
}
|
||||||
|
|
||||||
while( 1 ) {
|
while( 1 ) {
|
||||||
|
@ -302,8 +300,7 @@ sub run {
|
||||||
if ( $Config{ZM_SERVER_ID} ) {
|
if ( $Config{ZM_SERVER_ID} ) {
|
||||||
if ( ! ( $secs_count % 60 ) ) {
|
if ( ! ( $secs_count % 60 ) ) {
|
||||||
$dbh = zmDbConnect() if ! $dbh->ping();
|
$dbh = zmDbConnect() if ! $dbh->ping();
|
||||||
my @cpuload = Sys::CpuLoad::load();
|
my @cpuload = CpuLoad();
|
||||||
dPrint( ZoneMinder::Logger::DEBUG, 'Updating Server record' );
|
|
||||||
if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,CpuLoad=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef,
|
if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,CpuLoad=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef,
|
||||||
'Running', $cpuload[0], &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) {
|
'Running', $cpuload[0], &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) {
|
||||||
Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr());
|
Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr());
|
||||||
|
@ -311,52 +308,51 @@ sub run {
|
||||||
}
|
}
|
||||||
$secs_count += 1;
|
$secs_count += 1;
|
||||||
}
|
}
|
||||||
my $nfound = select( my $rout = $rin, undef, undef, $timeout );
|
my $nfound = select(my $rout = $rin, undef, undef, $timeout);
|
||||||
if ( $nfound > 0 ) {
|
if ( $nfound > 0 ) {
|
||||||
if ( vec( $rout, fileno(SERVER), 1 ) ) {
|
if ( vec($rout, fileno(SERVER), 1) ) {
|
||||||
my $paddr = accept( CLIENT, SERVER );
|
my $paddr = accept(CLIENT, SERVER);
|
||||||
my $message = <CLIENT>;
|
my $message = <CLIENT>;
|
||||||
|
|
||||||
next if !$message;
|
next if !$message;
|
||||||
|
|
||||||
my ( $command, $daemon, @args ) = split( /;/, $message );
|
my ( $command, $daemon, @args ) = split(';', $message);
|
||||||
|
|
||||||
if ( $command eq 'start' ) {
|
if ( $command eq 'start' ) {
|
||||||
start( $daemon, @args );
|
start($daemon, @args);
|
||||||
} elsif ( $command eq 'stop' ) {
|
} elsif ( $command eq 'stop' ) {
|
||||||
stop( $daemon, @args );
|
stop($daemon, @args);
|
||||||
} elsif ( $command eq 'restart' ) {
|
} elsif ( $command eq 'restart' ) {
|
||||||
restart( $daemon, @args );
|
restart($daemon, @args);
|
||||||
} elsif ( $command eq 'reload' ) {
|
} elsif ( $command eq 'reload' ) {
|
||||||
reload( $daemon, @args );
|
reload($daemon, @args);
|
||||||
} elsif ( $command eq 'startup' ) {
|
} elsif ( $command eq 'startup' ) {
|
||||||
# Do nothing, this is all we're here for
|
# Do nothing, this is all we're here for
|
||||||
dPrint( ZoneMinder::Logger::WARNING, "Already running, ignoring command '$command'\n" );
|
dPrint(ZoneMinder::Logger::WARNING, "Already running, ignoring command '$command'\n");
|
||||||
} elsif ( $command eq 'shutdown' ) {
|
} elsif ( $command eq 'shutdown' ) {
|
||||||
shutdownAll();
|
shutdownAll();
|
||||||
} elsif ( $command eq 'check' ) {
|
} elsif ( $command eq 'check' ) {
|
||||||
check( $daemon, @args );
|
check($daemon, @args);
|
||||||
} elsif ( $command eq 'status' ) {
|
} elsif ( $command eq 'status' ) {
|
||||||
if ( $daemon ) {
|
if ( $daemon ) {
|
||||||
status( $daemon, @args );
|
status($daemon, @args);
|
||||||
} else {
|
} else {
|
||||||
status();
|
status();
|
||||||
}
|
}
|
||||||
} elsif ( $command eq 'logrot' ) {
|
} elsif ( $command eq 'logrot' ) {
|
||||||
logrot();
|
logrot();
|
||||||
} else {
|
} else {
|
||||||
dPrint( ZoneMinder::Logger::ERROR, "Invalid command '$command'\n" );
|
dPrint(ZoneMinder::Logger::ERROR, "Invalid command '$command'\n");
|
||||||
}
|
}
|
||||||
close(CLIENT);
|
close(CLIENT);
|
||||||
} else {
|
} else {
|
||||||
Fatal('Bogus descriptor');
|
Error('Bogus descriptor');
|
||||||
}
|
}
|
||||||
} elsif ( $nfound < 0 ) {
|
} elsif ( $nfound < 0 ) {
|
||||||
if ( $! == EINTR ) {
|
if ( $! == EINTR ) {
|
||||||
# Dead child, will be reaped
|
# Dead child, will be reaped
|
||||||
#print( "Probable dead child\n" );
|
#print( "Probable dead child\n" );
|
||||||
# See if it needs to start up again
|
# See if it needs to start up again
|
||||||
restartPending();
|
|
||||||
} elsif ( $! == EPIPE ) {
|
} elsif ( $! == EPIPE ) {
|
||||||
Error("Can't select: $!");
|
Error("Can't select: $!");
|
||||||
} else {
|
} else {
|
||||||
|
@ -364,21 +360,25 @@ sub run {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#print( "Select timed out\n" );
|
#print( "Select timed out\n" );
|
||||||
restartPending();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
dPrint( ZoneMinder::Logger::INFO, 'Server exiting at '
|
restartPending();
|
||||||
|
check_for_processes_to_kill();
|
||||||
|
|
||||||
|
} # end while
|
||||||
|
|
||||||
|
dPrint(ZoneMinder::Logger::INFO, 'Server exiting at '
|
||||||
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
|
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
|
||||||
."\n"
|
."\n"
|
||||||
);
|
);
|
||||||
if ( $Config{ZM_SERVER_ID} ) {
|
if ( $Config{ZM_SERVER_ID} ) {
|
||||||
$dbh = zmDbConnect() if ! $dbh->ping();
|
$dbh = zmDbConnect() if ! $dbh->ping();
|
||||||
if ( ! defined $dbh->do(q{UPDATE Servers SET Status='NotRunning' WHERE Id=?}, undef, $Config{ZM_SERVER_ID} ) ) {
|
if ( ! defined $dbh->do(q{UPDATE Servers SET Status='NotRunning' WHERE Id=?}, undef, $Config{ZM_SERVER_ID}) ) {
|
||||||
Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr());
|
Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unlink( main::SOCK_FILE ) or Error( 'Unable to unlink ' . main::SOCK_FILE .". Error message was: $!" ) if ( -e main::SOCK_FILE );
|
unlink(main::SOCK_FILE) or Error('Unable to unlink ' . main::SOCK_FILE .". Error message was: $!") if ( -e main::SOCK_FILE );
|
||||||
unlink( ZM_PID ) or Error( 'Unable to unlink ' . ZM_PID .". Error message was: $!" ) if ( -e ZM_PID );
|
unlink(ZM_PID) or Error('Unable to unlink ' . ZM_PID .". Error message was: $!") if ( -e ZM_PID );
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,15 +395,15 @@ sub dPrint {
|
||||||
print CLIENT @_
|
print CLIENT @_
|
||||||
}
|
}
|
||||||
if ( $logLevel == ZoneMinder::Logger::DEBUG ) {
|
if ( $logLevel == ZoneMinder::Logger::DEBUG ) {
|
||||||
Debug( @_ );
|
Debug(@_);
|
||||||
} elsif ( $logLevel == ZoneMinder::Logger::INFO ) {
|
} elsif ( $logLevel == ZoneMinder::Logger::INFO ) {
|
||||||
Info( @_ );
|
Info(@_);
|
||||||
} elsif ( $logLevel == ZoneMinder::Logger::WARNING ) {
|
} elsif ( $logLevel == ZoneMinder::Logger::WARNING ) {
|
||||||
Warning( @_ );
|
Warning(@_);
|
||||||
} elsif ( $logLevel == ZoneMinder::Logger::ERROR ) {
|
} elsif ( $logLevel == ZoneMinder::Logger::ERROR ) {
|
||||||
Error( @_ );
|
Error(@_);
|
||||||
} elsif ( $logLevel == ZoneMinder::Logger::FATAL ) {
|
} elsif ( $logLevel == ZoneMinder::Logger::FATAL ) {
|
||||||
Fatal( @_ );
|
Fatal(@_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,61 +411,60 @@ sub start {
|
||||||
my $daemon = shift;
|
my $daemon = shift;
|
||||||
my @args = @_;
|
my @args = @_;
|
||||||
|
|
||||||
my $command = join(' ', $daemon, @args );
|
my $command = join(' ', $daemon, @args);
|
||||||
my $process = $cmd_hash{$command};
|
my $process = $cmd_hash{$command};
|
||||||
|
|
||||||
if ( !$process ) {
|
if ( !$process ) {
|
||||||
# It's not running, or at least it's not been started by us
|
# It's not running, or at least it's not been started by us
|
||||||
$process = { daemon=>$daemon, args=>\@args, command=>$command, keepalive=>!undef };
|
$process = { daemon=>$daemon, args=>\@args, command=>$command, keepalive=>!undef };
|
||||||
} elsif ( $process->{pid} && $pid_hash{$process->{pid}} ) {
|
} elsif ( $process->{pid} && $pid_hash{$process->{pid}} ) {
|
||||||
dPrint( ZoneMinder::Logger::INFO, "'$process->{command}' already running at "
|
dPrint(ZoneMinder::Logger::INFO, "'$process->{command}' already running at "
|
||||||
.strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) )
|
.strftime('%y/%m/%d %H:%M:%S', localtime($process->{started}))
|
||||||
.", pid = $process->{pid}\n"
|
.", pid = $process->{pid}\n"
|
||||||
);
|
);
|
||||||
return();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $sigset = POSIX::SigSet->new;
|
my $sigset = POSIX::SigSet->new;
|
||||||
my $blockset = POSIX::SigSet->new( SIGCHLD );
|
my $blockset = POSIX::SigSet->new( SIGCHLD );
|
||||||
sigprocmask( SIG_BLOCK, $blockset, $sigset ) or Fatal( "Can't block SIGCHLD: $!" );
|
sigprocmask(SIG_BLOCK, $blockset, $sigset) or Fatal("Can't block SIGCHLD: $!");
|
||||||
if ( my $cpid = fork() ) {
|
if ( my $cpid = fork() ) {
|
||||||
logReinit();
|
logReinit();
|
||||||
|
|
||||||
$process->{pid} = $cpid;
|
$process->{pid} = $cpid;
|
||||||
$process->{started} = time();
|
$process->{started} = time();
|
||||||
delete( $process->{pending} );
|
delete $process->{pending};
|
||||||
|
|
||||||
dPrint( ZoneMinder::Logger::INFO, "'$command' starting at "
|
dPrint(ZoneMinder::Logger::INFO, "'$command' starting at "
|
||||||
.strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) )
|
.strftime('%y/%m/%d %H:%M:%S', localtime($process->{started}))
|
||||||
.", pid = $process->{pid}\n"
|
.", pid = $process->{pid}\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
$cmd_hash{$process->{command}} = $pid_hash{$cpid} = $process;
|
$cmd_hash{$process->{command}} = $pid_hash{$cpid} = $process;
|
||||||
sigprocmask( SIG_SETMASK, $sigset ) or Fatal( "Can't restore SIGCHLD: $!" );
|
sigprocmask(SIG_SETMASK, $sigset) or Fatal("Can't restore SIGCHLD: $!");
|
||||||
} elsif ( defined($cpid ) ) {
|
} elsif ( defined($cpid) ) {
|
||||||
# Force reconnection to the db.
|
# Force reconnection to the db.
|
||||||
$dbh = zmDbConnect(1);
|
$dbh = zmDbConnect(1);
|
||||||
logReinit();
|
logReinit();
|
||||||
|
|
||||||
dPrint( ZoneMinder::Logger::INFO, "'".join( ' ', ( $daemon, @args ) )
|
dPrint(ZoneMinder::Logger::INFO, "'$command' started at "
|
||||||
."' started at "
|
.strftime('%y/%m/%d %H:%M:%S', localtime())
|
||||||
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
|
|
||||||
."\n"
|
."\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( $daemon =~ /^${daemon_patt}$/ ) {
|
if ( $daemon =~ /^${daemon_patt}$/ ) {
|
||||||
$daemon = $Config{ZM_PATH_BIN}.'/'.$1;
|
$daemon = $Config{ZM_PATH_BIN}.'/'.$1;
|
||||||
} else {
|
} else {
|
||||||
Fatal( "Invalid daemon '$daemon' specified" );
|
Fatal("Invalid daemon '$daemon' specified");
|
||||||
}
|
}
|
||||||
|
|
||||||
my @good_args;
|
my @good_args;
|
||||||
foreach my $arg ( @args ) {
|
foreach my $arg ( @args ) {
|
||||||
# Detaint arguments, if they look ok
|
# Detaint arguments, if they look ok
|
||||||
if ( $arg =~ /^(-{0,2}[\w\/?&=.-]+)$/ ) {
|
if ( $arg =~ /^(-{0,2}[\w\/?&=.-]+)$/ ) {
|
||||||
push( @good_args, $1 );
|
push @good_args, $1;
|
||||||
} else {
|
} else {
|
||||||
Fatal( "Bogus argument '$arg' found" );
|
Fatal("Bogus argument '$arg' found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,8 +472,8 @@ sub start {
|
||||||
zmDbDisconnect();
|
zmDbDisconnect();
|
||||||
|
|
||||||
my $fd = 0;
|
my $fd = 0;
|
||||||
while( $fd < POSIX::sysconf( &POSIX::_SC_OPEN_MAX ) ) {
|
while( $fd < POSIX::sysconf(&POSIX::_SC_OPEN_MAX) ) {
|
||||||
POSIX::close( $fd++ );
|
POSIX::close($fd++);
|
||||||
}
|
}
|
||||||
|
|
||||||
# Child process
|
# Child process
|
||||||
|
@ -483,11 +482,11 @@ sub start {
|
||||||
$SIG{TERM} = 'DEFAULT';
|
$SIG{TERM} = 'DEFAULT';
|
||||||
$SIG{ABRT} = 'DEFAULT';
|
$SIG{ABRT} = 'DEFAULT';
|
||||||
|
|
||||||
exec( $daemon, @good_args ) or Fatal( "Can't exec: $!" );
|
exec($daemon, @good_args) or Fatal("Can't exec: $!");
|
||||||
} else {
|
} else {
|
||||||
Fatal( "Can't fork: $!" );
|
Fatal("Can't fork: $!");
|
||||||
}
|
}
|
||||||
}
|
} # end sub start
|
||||||
|
|
||||||
# Sends the stop signal, without waiting around to see if the process died.
|
# Sends the stop signal, without waiting around to see if the process died.
|
||||||
sub send_stop {
|
sub send_stop {
|
||||||
|
@ -496,9 +495,9 @@ sub send_stop {
|
||||||
my $command = $process->{command};
|
my $command = $process->{command};
|
||||||
if ( $process->{pending} ) {
|
if ( $process->{pending} ) {
|
||||||
|
|
||||||
delete( $cmd_hash{$command} );
|
delete $cmd_hash{$command};
|
||||||
dPrint( ZoneMinder::Logger::INFO, "Command '$command' removed from pending list at "
|
dPrint(ZoneMinder::Logger::INFO, "Command '$command' removed from pending list at "
|
||||||
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
|
.strftime('%y/%m/%d %H:%M:%S', localtime())
|
||||||
."\n"
|
."\n"
|
||||||
);
|
);
|
||||||
return();
|
return();
|
||||||
|
@ -506,130 +505,114 @@ sub send_stop {
|
||||||
|
|
||||||
my $pid = $process->{pid};
|
my $pid = $process->{pid};
|
||||||
if ( !$pid_hash{$pid} ) {
|
if ( !$pid_hash{$pid} ) {
|
||||||
dPrint( ZoneMinder::Logger::ERROR, "No process with command of '$command' pid $pid is running\n" );
|
dPrint(ZoneMinder::Logger::ERROR, "No process with command of '$command' pid $pid is running\n");
|
||||||
return();
|
return();
|
||||||
}
|
}
|
||||||
|
|
||||||
dPrint( ZoneMinder::Logger::INFO, "'$command' sending stop to pid $pid at "
|
dPrint(ZoneMinder::Logger::INFO, "'$command' sending stop to pid $pid at "
|
||||||
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
|
.strftime('%y/%m/%d %H:%M:%S', localtime())
|
||||||
."\n"
|
."\n"
|
||||||
);
|
);
|
||||||
$process->{keepalive} = !$final;
|
$process->{keepalive} = !$final;
|
||||||
kill( 'TERM', $pid );
|
$process->{term_sent_at} = time;
|
||||||
|
$process->{pending} = 0;
|
||||||
|
$terminating_processes{$command} = $process;
|
||||||
|
|
||||||
|
kill('TERM', $pid);
|
||||||
return $pid;
|
return $pid;
|
||||||
} # end sub send_stop
|
} # end sub send_stop
|
||||||
|
|
||||||
sub kill_until_dead {
|
sub check_for_processes_to_kill {
|
||||||
my ( $process ) = @_;
|
# Turn off SIGCHLD
|
||||||
# Now check it has actually gone away, if not kill -9 it
|
|
||||||
my $count = 0;
|
|
||||||
my $sigset = POSIX::SigSet->new;
|
my $sigset = POSIX::SigSet->new;
|
||||||
my $blockset = POSIX::SigSet->new(SIGCHLD);
|
my $blockset = POSIX::SigSet->new(SIGCHLD);
|
||||||
sigprocmask(SIG_BLOCK, $blockset, $sigset ) or die "dying at block...\n";
|
sigprocmask(SIG_BLOCK, $blockset, $sigset) or die "dying at block...\n";
|
||||||
while( $process and $$process{pid} and kill( 0, $$process{pid} ) ) {
|
foreach my $command ( %terminating_processes ) {
|
||||||
if ( $count++ > 10 ) {
|
my $process = $cmd_hash{$command};
|
||||||
dPrint( ZoneMinder::Logger::WARNING, "'$$process{command}' has not stopped at "
|
Debug("Have process $command at pid $$process{pid} $$process{term_sent_at}");
|
||||||
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
|
if ( $$process{term_sent_at} and ( $$process{term_sent_at} - time > KILL_DELAY ) ) {
|
||||||
.". Sending KILL to pid $$process{pid}\n"
|
dPrint(ZoneMinder::Logger::WARNING, "'$$process{command}' has not stopped at "
|
||||||
);
|
.strftime('%y/%m/%d %H:%M:%S', localtime())
|
||||||
kill( 'KILL', $$process{pid} );
|
.' after ' . KILL_DELAY . ' seconds.'
|
||||||
last;
|
." Sending KILL to pid $$process{pid}\n"
|
||||||
|
);
|
||||||
|
kill('KILL', $$process{pid});
|
||||||
}
|
}
|
||||||
|
|
||||||
# THe purpose of the signal blocking is to simplify the concurrency
|
|
||||||
sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n";
|
|
||||||
sleep( KILL_DELAY );
|
|
||||||
sigprocmask(SIG_BLOCK, $blockset, $sigset ) or die "dying at block...\n";
|
|
||||||
}
|
}
|
||||||
sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n";
|
sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n";
|
||||||
}
|
} # end sub check_for_processess_to_kill
|
||||||
|
|
||||||
sub _stop {
|
|
||||||
my ($final, $process ) = @_;
|
|
||||||
|
|
||||||
my $pid = send_stop( $final, $process );
|
|
||||||
return if ! $pid;
|
|
||||||
delete( $cmd_hash{$$process{command}} );
|
|
||||||
kill_until_dead( $process );
|
|
||||||
}
|
|
||||||
|
|
||||||
sub stop {
|
sub stop {
|
||||||
my ( $daemon, @args ) = @_;
|
my ( $daemon, @args ) = @_;
|
||||||
my $command = join(' ', $daemon, @args );
|
my $command = join(' ', $daemon, @args );
|
||||||
my $process = $cmd_hash{$command};
|
my $process = $cmd_hash{$command};
|
||||||
if ( !$process ) {
|
if ( !$process ) {
|
||||||
dPrint( ZoneMinder::Logger::WARNING, "Can't find process with command of '$command'\n" );
|
dPrint(ZoneMinder::Logger::WARNING, "Can't find process with command of '$command'\n");
|
||||||
return();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_stop( 1, $process );
|
send_stop(1, $process);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# restart is the same as stop, except that we flag the processes for restarting once it dies
|
||||||
|
# One difference is that if we don't know about the process, then we start it.
|
||||||
sub restart {
|
sub restart {
|
||||||
my $daemon = shift;
|
my ( $daemon, @args ) = @_;
|
||||||
my @args = @_;
|
|
||||||
|
|
||||||
my $command = $daemon;
|
my $command = join(' ', $daemon, @args);
|
||||||
$command .= ' '.join( ' ', ( @args ) ) if @args;
|
dPrint(ZoneMinder::Logger::DEBUG, "Restarting $command\n");
|
||||||
dPrint ( ZoneMinder::Logger::DEBUG, "Restarting $command\n");
|
|
||||||
my $process = $cmd_hash{$command};
|
my $process = $cmd_hash{$command};
|
||||||
if ( $process ) {
|
if ( !$process ) {
|
||||||
dPrint( ZoneMinder::Logger::DEBUG, "Have process" );
|
dPrint(ZoneMinder::Logger::WARNING, "Can't find process with command of '$command'\n");
|
||||||
if ( $process->{pid} ) {
|
start($daemon, @args);
|
||||||
dPrint( ZoneMinder::Logger::DEBUG, "Have process pid " .$process->{pid} );
|
return;
|
||||||
my $cpid = $process->{pid};
|
|
||||||
if ( defined($pid_hash{$cpid}) ) {
|
|
||||||
dPrint( ZoneMinder::Logger::DEBUG, "Have process pid hash " .$process->{pid} );
|
|
||||||
_stop( 0, $process );
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
dPrint( ZoneMinder::Logger::DEBUG, "Not sending stop" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
start( $daemon, @args );
|
# Start will be handled by the reaper
|
||||||
|
send_stop(0, $process);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub reload {
|
sub reload {
|
||||||
my $daemon = shift;
|
my $daemon = shift;
|
||||||
my @args = @_;
|
my @args = @_;
|
||||||
|
|
||||||
my $command = $daemon;
|
my $command = join(' ', $daemon, @args);
|
||||||
$command .= ' '.join( ' ', ( @args ) ) if ( @args );
|
|
||||||
my $process = $cmd_hash{$command};
|
my $process = $cmd_hash{$command};
|
||||||
if ( $process ) {
|
if ( $process ) {
|
||||||
if ( $process->{pid} ) {
|
if ( $process->{pid} ) {
|
||||||
kill( 'HUP', $process->{pid} );
|
kill('HUP', $process->{pid});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub logrot {
|
sub logrot {
|
||||||
logReinit();
|
logReinit();
|
||||||
foreach my $process ( values( %pid_hash ) ) {
|
foreach my $process ( values %pid_hash ) {
|
||||||
if ( $process->{pid} ) {
|
if ( $process->{pid} ) {
|
||||||
# && $process->{command} =~ /^zm.*\.pl/ ) {
|
# && $process->{command} =~ /^zm.*\.pl/ ) {
|
||||||
kill( 'HUP', $process->{pid} );
|
kill('HUP', $process->{pid});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub reaper {
|
sub reaper {
|
||||||
my $saved_status = $!;
|
my $saved_status = $!;
|
||||||
while ( (my $cpid = waitpid( -1, WNOHANG )) > 0 ) {
|
while ( (my $cpid = waitpid(-1, WNOHANG)) > 0 ) {
|
||||||
my $status = $?;
|
my $status = $?;
|
||||||
|
|
||||||
my $process = $pid_hash{$cpid};
|
my $process = $pid_hash{$cpid};
|
||||||
delete( $pid_hash{$cpid} );
|
delete $pid_hash{$cpid};
|
||||||
|
|
||||||
if ( !$process ) {
|
if ( !$process ) {
|
||||||
dPrint( ZoneMinder::Logger::INFO, "Can't find child with pid of '$cpid'\n" );
|
dPrint(ZoneMinder::Logger::INFO, "Can't find child with pid of '$cpid'\n");
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
|
delete $terminating_processes{$$process{command}};
|
||||||
|
delete $$process{term_sent_at};
|
||||||
|
|
||||||
$process->{stopped} = time();
|
$process->{stopped} = time();
|
||||||
$process->{runtime} = ($process->{stopped}-$process->{started});
|
$process->{runtime} = ($process->{stopped}-$process->{started});
|
||||||
delete( $process->{pid} );
|
delete $process->{pid};
|
||||||
|
|
||||||
my $exit_status = $status>>8;
|
my $exit_status = $status>>8;
|
||||||
my $exit_signal = $status&0xfe;
|
my $exit_signal = $status&0xfe;
|
||||||
|
@ -656,9 +639,9 @@ sub reaper {
|
||||||
$out_str .= "\n";
|
$out_str .= "\n";
|
||||||
|
|
||||||
if ( $exit_status == 0 ) {
|
if ( $exit_status == 0 ) {
|
||||||
Info( $out_str );
|
Info($out_str);
|
||||||
} else {
|
} else {
|
||||||
Error( $out_str );
|
Error($out_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $process->{keepalive} ) {
|
if ( $process->{keepalive} ) {
|
||||||
|
@ -676,6 +659,8 @@ sub reaper {
|
||||||
$process->{delay} = $Config{ZM_MAX_RESTART_DELAY};
|
$process->{delay} = $Config{ZM_MAX_RESTART_DELAY};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
delete $cmd_hash{$$process{command}};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$SIG{CHLD} = \&reaper;
|
$SIG{CHLD} = \&reaper;
|
||||||
|
@ -686,8 +671,8 @@ sub restartPending {
|
||||||
# Restart any pending processes
|
# Restart any pending processes
|
||||||
foreach my $process ( values( %cmd_hash ) ) {
|
foreach my $process ( values( %cmd_hash ) ) {
|
||||||
if ( $process->{pending} && $process->{pending} <= time() ) {
|
if ( $process->{pending} && $process->{pending} <= time() ) {
|
||||||
dPrint( ZoneMinder::Logger::INFO, "Starting pending process, $process->{command}\n" );
|
dPrint(ZoneMinder::Logger::INFO, "Starting pending process, $process->{command}\n");
|
||||||
start( $process->{daemon}, @{$process->{args}} );
|
start($process->{daemon}, @{$process->{args}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -696,29 +681,20 @@ sub shutdownAll {
|
||||||
foreach my $pid ( keys %pid_hash ) {
|
foreach my $pid ( keys %pid_hash ) {
|
||||||
# This is a quick fix because a SIGCHLD can happen and alter pid_hash while we are in here.
|
# This is a quick fix because a SIGCHLD can happen and alter pid_hash while we are in here.
|
||||||
next if ! $pid_hash{$pid};
|
next if ! $pid_hash{$pid};
|
||||||
send_stop( 1, $pid_hash{$pid} );
|
send_stop(1, $pid_hash{$pid});
|
||||||
}
|
}
|
||||||
foreach my $pid ( keys %pid_hash ) {
|
while ( %terminating_processes ) {
|
||||||
# This is a quick fix because a SIGCHLD can happen and alter pid_hash while we are in here.
|
check_for_processes_to_kill();
|
||||||
next if ! $pid_hash{$pid};
|
sleep(1) if %terminating_processes;
|
||||||
|
|
||||||
my $process = $pid_hash{$pid};
|
|
||||||
|
|
||||||
kill_until_dead( $process );
|
|
||||||
delete( $cmd_hash{$$process{command}} );
|
|
||||||
delete( $pid_hash{$pid} );
|
|
||||||
}
|
}
|
||||||
if ( 0 ) {
|
dPrint(ZoneMinder::Logger::INFO, "Server shutdown at "
|
||||||
killAll( 5 );
|
.strftime('%y/%m/%d %H:%M:%S', localtime())
|
||||||
}
|
|
||||||
dPrint( ZoneMinder::Logger::INFO, "Server shutdown at "
|
|
||||||
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
|
|
||||||
."\n"
|
."\n"
|
||||||
);
|
);
|
||||||
unlink( main::SOCK_FILE ) or Error( "Unable to unlink " . main::SOCK_FILE .". Error message was: $!" ) if ( -e main::SOCK_FILE );
|
unlink(main::SOCK_FILE) or Error("Unable to unlink " . main::SOCK_FILE .". Error message was: $!") if ( -e main::SOCK_FILE );
|
||||||
unlink( ZM_PID ) or Error( "Unable to unlink " . ZM_PID .". Error message was: $!" ) if ( -e ZM_PID );
|
unlink(ZM_PID) or Error("Unable to unlink " . ZM_PID .". Error message was: $!") if ( -e ZM_PID );
|
||||||
close( CLIENT );
|
close(CLIENT);
|
||||||
close( SERVER );
|
close(SERVER);
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -726,18 +702,18 @@ sub check {
|
||||||
my $daemon = shift;
|
my $daemon = shift;
|
||||||
my @args = @_;
|
my @args = @_;
|
||||||
|
|
||||||
my $command = join( ' ', $daemon, @args );
|
my $command = join(' ', $daemon, @args);
|
||||||
my $process = $cmd_hash{$command};
|
my $process = $cmd_hash{$command};
|
||||||
if ( !$process ) {
|
if ( !$process ) {
|
||||||
cPrint( "unknown\n" );
|
cPrint("unknown\n");
|
||||||
} elsif ( $process->{pending} ) {
|
} elsif ( $process->{pending} ) {
|
||||||
cPrint( "pending\n" );
|
cPrint("pending\n");
|
||||||
} else {
|
} else {
|
||||||
my $cpid = $process->{pid};
|
my $cpid = $process->{pid};
|
||||||
if ( ! $pid_hash{$cpid} ) {
|
if ( ! $pid_hash{$cpid} ) {
|
||||||
cPrint( "stopped\n" );
|
cPrint("stopped\n");
|
||||||
} else {
|
} else {
|
||||||
cPrint( "running\n" );
|
cPrint("running\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -747,53 +723,54 @@ sub status {
|
||||||
my @args = @_;
|
my @args = @_;
|
||||||
|
|
||||||
if ( defined($daemon) ) {
|
if ( defined($daemon) ) {
|
||||||
my $command = join( ' ', $daemon, @args );
|
my $command = join(' ', $daemon, @args);
|
||||||
my $process = $cmd_hash{$command};
|
my $process = $cmd_hash{$command};
|
||||||
if ( ! $process ) {
|
if ( ! $process ) {
|
||||||
dPrint( ZoneMinder::Logger::DEBUG, "'$command' not running\n" );
|
dPrint(ZoneMinder::Logger::DEBUG, "'$command' not running\n");
|
||||||
return();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $process->{pending} ) {
|
if ( $process->{pending} ) {
|
||||||
dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at "
|
dPrint(ZoneMinder::Logger::DEBUG, "'$command' pending at "
|
||||||
.strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending} ) )
|
.strftime('%y/%m/%d %H:%M:%S', localtime($process->{pending}))
|
||||||
."\n"
|
."\n"
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
my $cpid = $process->{pid};
|
my $pid = $process->{pid};
|
||||||
if ( ! $pid_hash{$cpid} ) {
|
if ( ! $pid_hash{$pid} ) {
|
||||||
dPrint( ZoneMinder::Logger::DEBUG, "'$command' not running\n" );
|
dPrint(ZoneMinder::Logger::DEBUG, "'$command' not running\n");
|
||||||
return();
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' running since "
|
dPrint(ZoneMinder::Logger::DEBUG, "'$command' running since "
|
||||||
.strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started} ) )
|
.strftime('%y/%m/%d %H:%M:%S', localtime($process->{started}))
|
||||||
.", pid = $process->{pid}"
|
.", pid = $process->{pid}"
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
foreach my $process ( values(%pid_hash) ) {
|
foreach my $process ( values %pid_hash ) {
|
||||||
my $out_str = "'$process->{command}' running since "
|
my $out_str = "'$process->{command}' running since "
|
||||||
.strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) )
|
.strftime('%y/%m/%d %H:%M:%S', localtime($process->{started}))
|
||||||
.", pid = $process->{pid}"
|
.", pid = $process->{pid}"
|
||||||
;
|
;
|
||||||
$out_str .= ", valid" if ( kill( 0, $process->{pid} ) );
|
$out_str .= ", valid" if ( kill(0, $process->{pid}) );
|
||||||
$out_str .= "\n";
|
$out_str .= "\n";
|
||||||
dPrint( ZoneMinder::Logger::DEBUG, $out_str );
|
dPrint(ZoneMinder::Logger::DEBUG, $out_str);
|
||||||
}
|
}
|
||||||
foreach my $process ( values( %cmd_hash ) ) {
|
foreach my $process ( values %cmd_hash ) {
|
||||||
if ( $process->{pending} ) {
|
if ( $process->{pending} ) {
|
||||||
dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at "
|
dPrint(ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at "
|
||||||
.strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending} ) )
|
.strftime( '%y/%m/%d %H:%M:%S', localtime($process->{pending}))
|
||||||
."\n"
|
."\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} # end foreach process
|
} # end foreach process
|
||||||
}
|
}
|
||||||
}
|
} # end sub status
|
||||||
|
|
||||||
sub killAll {
|
sub killAll {
|
||||||
my $delay = shift;
|
my $delay = shift;
|
||||||
sleep( $delay );
|
# Why sleep before sending term?
|
||||||
|
#sleep( $delay );
|
||||||
my $killall;
|
my $killall;
|
||||||
if ( '@HOST_OS@' eq 'BSD' ) {
|
if ( '@HOST_OS@' eq 'BSD' ) {
|
||||||
$killall = 'killall -q -';
|
$killall = 'killall -q -';
|
||||||
|
@ -804,16 +781,15 @@ sub killAll {
|
||||||
}
|
}
|
||||||
foreach my $daemon ( @daemons ) {
|
foreach my $daemon ( @daemons ) {
|
||||||
my $cmd = $killall ."TERM $daemon";
|
my $cmd = $killall ."TERM $daemon";
|
||||||
Debug( $cmd );
|
Debug($cmd);
|
||||||
qx( $cmd );
|
qx($cmd);
|
||||||
}
|
}
|
||||||
sleep( $delay );
|
sleep($delay);
|
||||||
foreach my $daemon ( @daemons ) {
|
foreach my $daemon ( @daemons ) {
|
||||||
my $cmd = $killall."KILL $daemon";
|
my $cmd = $killall."KILL $daemon";
|
||||||
Debug( $cmd );
|
Debug($cmd);
|
||||||
qx( $cmd );
|
qx($cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
__END__
|
__END__
|
||||||
|
|
|
@ -283,6 +283,8 @@ sub checkFilter {
|
||||||
|
|
||||||
foreach my $event ( @Events ) {
|
foreach my $event ( @Events ) {
|
||||||
last if $zm_terminate;
|
last if $zm_terminate;
|
||||||
|
my $Event = new ZoneMinder::Event( $$event{Id}, $event );
|
||||||
|
|
||||||
Debug( "Checking event $event->{Id}" );
|
Debug( "Checking event $event->{Id}" );
|
||||||
my $delete_ok = !undef;
|
my $delete_ok = !undef;
|
||||||
$dbh->ping();
|
$dbh->ping();
|
||||||
|
@ -302,7 +304,7 @@ sub checkFilter {
|
||||||
}
|
}
|
||||||
if ( $Config{ZM_OPT_EMAIL} && $filter->{AutoEmail} ) {
|
if ( $Config{ZM_OPT_EMAIL} && $filter->{AutoEmail} ) {
|
||||||
if ( !$event->{Emailed} ) {
|
if ( !$event->{Emailed} ) {
|
||||||
$delete_ok = undef if ( !sendEmail( $filter, $event ) );
|
$delete_ok = undef if ( !sendEmail( $filter, $Event ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( $Config{ZM_OPT_MESSAGE} && $filter->{AutoMessage} ) {
|
if ( $Config{ZM_OPT_MESSAGE} && $filter->{AutoMessage} ) {
|
||||||
|
@ -322,7 +324,6 @@ sub checkFilter {
|
||||||
}
|
}
|
||||||
if ( $filter->{AutoDelete} ) {
|
if ( $filter->{AutoDelete} ) {
|
||||||
if ( $delete_ok ) {
|
if ( $delete_ok ) {
|
||||||
my $Event = new ZoneMinder::Event( $$event{Id}, $event );
|
|
||||||
$Event->delete();
|
$Event->delete();
|
||||||
} else {
|
} else {
|
||||||
Error( "Unable toto delete event $event->{Id} as previous operations failed\n" );
|
Error( "Unable toto delete event $event->{Id} as previous operations failed\n" );
|
||||||
|
@ -330,19 +331,23 @@ sub checkFilter {
|
||||||
} # end if AutoDelete
|
} # end if AutoDelete
|
||||||
|
|
||||||
if ( $filter->{AutoMove} ) {
|
if ( $filter->{AutoMove} ) {
|
||||||
my $Event = new ZoneMinder::Event( $$event{Id}, $event );
|
|
||||||
my $NewStorage = new ZoneMinder::Storage( $filter->{AutoMoveTo} );
|
my $NewStorage = new ZoneMinder::Storage( $filter->{AutoMoveTo} );
|
||||||
$_ = $Event->MoveTo( $NewStorage );
|
$_ = $Event->MoveTo( $NewStorage );
|
||||||
Error($_) if $_;
|
Error($_) if $_;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $filter->{UpdateDiskSpace} ) {
|
if ( $filter->{UpdateDiskSpace} ) {
|
||||||
my $Event = new ZoneMinder::Event( $$event{Id}, $event );
|
|
||||||
$ZoneMinder::Database::dbh->begin_work();
|
$ZoneMinder::Database::dbh->begin_work();
|
||||||
$Event->lock_and_load();
|
$Event->lock_and_load();
|
||||||
|
|
||||||
my $old_diskspace = $$Event{DiskSpace};
|
my $old_diskspace = $$Event{DiskSpace};
|
||||||
if ( $old_diskspace != $Event->DiskSpace(undef) ) {
|
my $new_diskspace = $Event->DiskSpace(undef);
|
||||||
|
|
||||||
|
if (
|
||||||
|
( (!defined $old_diskspace) and defined $new_diskspace)
|
||||||
|
or
|
||||||
|
( (defined $old_diskspace) and (defined $new_diskspace) and ( $old_diskspace != $Event->DiskSpace(undef) ) )
|
||||||
|
) {
|
||||||
$Event->save();
|
$Event->save();
|
||||||
}
|
}
|
||||||
$ZoneMinder::Database::dbh->commit();
|
$ZoneMinder::Database::dbh->commit();
|
||||||
|
@ -393,25 +398,25 @@ sub generateVideo {
|
||||||
chomp( $output );
|
chomp( $output );
|
||||||
my $status = $? >> 8;
|
my $status = $? >> 8;
|
||||||
if ( $status || logDebugging() ) {
|
if ( $status || logDebugging() ) {
|
||||||
Debug( "Output: $output\n" );
|
Debug("Output: $output\n");
|
||||||
}
|
}
|
||||||
if ( $status ) {
|
if ( $status ) {
|
||||||
Error( "Video generation '$command' failed with status: $status\n" );
|
Error("Video generation '$command' failed with status: $status\n");
|
||||||
if ( wantarray() ) {
|
if ( wantarray() ) {
|
||||||
return( undef, undef );
|
return( undef, undef );
|
||||||
}
|
}
|
||||||
return( 0 );
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
my $sql = 'UPDATE Events SET Videoed = 1 WHERE Id = ?';
|
my $sql = 'UPDATE Events SET Videoed = 1 WHERE Id = ?';
|
||||||
my $sth = $dbh->prepare_cached( $sql )
|
my $sth = $dbh->prepare_cached( $sql )
|
||||||
or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
|
or Fatal( "Unable to prepare '$sql': ".$dbh->errstr());
|
||||||
my $res = $sth->execute( $event->{Id} )
|
my $res = $sth->execute( $event->{Id} )
|
||||||
or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
|
or Fatal("Unable toexecute '$sql': ".$sth->errstr());
|
||||||
if ( wantarray() ) {
|
if ( wantarray() ) {
|
||||||
return( $format, $output );
|
return( $format, $output );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return( 1 );
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Returns an image absolute path for given event and frame
|
# Returns an image absolute path for given event and frame
|
||||||
|
@ -419,13 +424,14 @@ sub generateVideo {
|
||||||
# If neither capture nor analyse image exists it will try to extract a frame from .mp4 file if exists
|
# If neither capture nor analyse image exists it will try to extract a frame from .mp4 file if exists
|
||||||
# An empty string is returned if no one from methods above works
|
# An empty string is returned if no one from methods above works
|
||||||
sub generateImage {
|
sub generateImage {
|
||||||
my $event = shift;
|
my $Event = shift;
|
||||||
my $frame = shift;
|
my $frame = shift;
|
||||||
my $analyse = do { @_ ? shift : 0 }; # don't return analyse image by default
|
my $analyse = @_ ? shift : 0; # don't return analyse image by default
|
||||||
|
|
||||||
my $capture_image_path = sprintf('%s/%0'.$Config{ZM_EVENT_IMAGE_DIGITS}.'d-capture.jpg', getEventPath($event), $frame->{FrameId});
|
my $event_path = $Event->Path();
|
||||||
my $analyse_image_path = sprintf('%s/%0'.$Config{ZM_EVENT_IMAGE_DIGITS}.'d-analyse.jpg', getEventPath($event), $frame->{FrameId}) if $analyse;
|
my $capture_image_path = sprintf('%s/%0'.$Config{ZM_EVENT_IMAGE_DIGITS}.'d-capture.jpg', $event_path, $frame->{FrameId});
|
||||||
my $video_path = sprintf('%s/%d-video.mp4', getEventPath($event), $event->{Id});
|
my $analyse_image_path = sprintf('%s/%0'.$Config{ZM_EVENT_IMAGE_DIGITS}.'d-analyse.jpg', $event_path, $frame->{FrameId}) if $analyse;
|
||||||
|
my $video_path = sprintf('%s/%d-video.mp4', $event_path, $Event->{Id});
|
||||||
my $image_path = '';
|
my $image_path = '';
|
||||||
|
|
||||||
# check if the image file exists. If the file doesn't exist and we use H264 try to extract it from .mp4 video
|
# check if the image file exists. If the file doesn't exist and we use H264 try to extract it from .mp4 video
|
||||||
|
@ -433,8 +439,18 @@ sub generateImage {
|
||||||
$image_path = $analyse_image_path;
|
$image_path = $analyse_image_path;
|
||||||
} elsif ( -r $capture_image_path ) {
|
} elsif ( -r $capture_image_path ) {
|
||||||
$image_path = $capture_image_path;
|
$image_path = $capture_image_path;
|
||||||
} elsif ( -e $video_path ) {
|
} elsif ( -r $video_path ) {
|
||||||
if ( !system('ffmpeg -y -v 0 -i '.$video_path." -vf 'select=gte(n\\,".$frame->{FrameId}."),setpts=PTS-STARTPTS' -vframes 1 -f image2 ".$capture_image_path) ) {
|
my $command ="ffmpeg -ss $$frame{Delta} -i '$video_path' -frames:v 1 '$capture_image_path'";
|
||||||
|
#$command = "ffmpeg -y -v 0 -i $video_path -vf 'select=gte(n\\,$$frame{FrameId}),setpts=PTS-STARTPTS' -vframes 1 -f image2 $capture_image_path";
|
||||||
|
my $output = qx($command);
|
||||||
|
chomp( $output );
|
||||||
|
my $status = $? >> 8;
|
||||||
|
if ( $status || logDebugging() ) {
|
||||||
|
Debug("Output: $output\n");
|
||||||
|
}
|
||||||
|
if ( $status ) {
|
||||||
|
Error("Failed $command status $status");
|
||||||
|
} else {
|
||||||
$image_path = $capture_image_path;
|
$image_path = $capture_image_path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -581,7 +597,7 @@ sub uploadArchFile {
|
||||||
sub substituteTags {
|
sub substituteTags {
|
||||||
my $text = shift;
|
my $text = shift;
|
||||||
my $filter = shift;
|
my $filter = shift;
|
||||||
my $event = shift;
|
my $Event = shift;
|
||||||
my $attachments_ref = shift;
|
my $attachments_ref = shift;
|
||||||
|
|
||||||
# First we'd better check what we need to get
|
# First we'd better check what we need to get
|
||||||
|
@ -589,35 +605,7 @@ sub substituteTags {
|
||||||
# monitor information?
|
# monitor information?
|
||||||
my $need_monitor = $text =~ /%(?:MET|MEH|MED|MEW|MEN|MEA)%/;
|
my $need_monitor = $text =~ /%(?:MET|MEH|MED|MEW|MEN|MEA)%/;
|
||||||
|
|
||||||
my $monitor = {};
|
my $Monitor = $Event->Monitor() if $need_monitor;
|
||||||
if ( $need_monitor ) {
|
|
||||||
my $db_now = strftime( '%Y-%m-%d %H:%M:%S', localtime() );
|
|
||||||
my $sql = "SELECT
|
|
||||||
M.Id,
|
|
||||||
count(E.Id) as EventCount,
|
|
||||||
count(if(E.Archived,1,NULL))
|
|
||||||
as ArchEventCount,
|
|
||||||
count(if(E.StartTime>'$db_now' - INTERVAL 1 HOUR && E.Archived = 0,1,NULL))
|
|
||||||
as HourEventCount,
|
|
||||||
count(if(E.StartTime>'$db_now' - INTERVAL 1 DAY && E.Archived = 0,1,NULL))
|
|
||||||
as DayEventCount,
|
|
||||||
count(if(E.StartTime>'$db_now' - INTERVAL 7 DAY && E.Archived = 0,1,NULL))
|
|
||||||
as WeekEventCount,
|
|
||||||
count(if(E.StartTime>'$db_now' - INTERVAL 1 MONTH && E.Archived = 0,1,NULL))
|
|
||||||
as MonthEventCount
|
|
||||||
FROM Monitors as M LEFT JOIN Events as E on E.MonitorId = M.Id
|
|
||||||
WHERE MonitorId = ?
|
|
||||||
GROUP BY E.MonitorId
|
|
||||||
ORDER BY Id"
|
|
||||||
;
|
|
||||||
my $sth = $dbh->prepare_cached( $sql )
|
|
||||||
or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
|
|
||||||
my $res = $sth->execute( $event->{MonitorId} )
|
|
||||||
or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
|
|
||||||
$monitor = $sth->fetchrow_hashref();
|
|
||||||
$sth->finish();
|
|
||||||
return() if ( !$monitor );
|
|
||||||
}
|
|
||||||
|
|
||||||
# Do we need the image information too?
|
# Do we need the image information too?
|
||||||
my $need_images = $text =~ /%(?:EPI1|EPIM|EI1|EIM|EI1A|EIMA)%/;
|
my $need_images = $text =~ /%(?:EPI1|EPIM|EI1|EIM|EI1A|EIMA)%/;
|
||||||
|
@ -631,8 +619,9 @@ sub substituteTags {
|
||||||
;
|
;
|
||||||
my $sth = $dbh->prepare_cached( $sql )
|
my $sth = $dbh->prepare_cached( $sql )
|
||||||
or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
|
or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
|
||||||
my $res = $sth->execute( $event->{Id} )
|
my $res = $sth->execute( $Event->{Id} )
|
||||||
or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
|
or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
|
||||||
|
my $rows = 0;
|
||||||
while( my $frame = $sth->fetchrow_hashref() ) {
|
while( my $frame = $sth->fetchrow_hashref() ) {
|
||||||
if ( !$first_alarm_frame ) {
|
if ( !$first_alarm_frame ) {
|
||||||
$first_alarm_frame = $frame;
|
$first_alarm_frame = $frame;
|
||||||
|
@ -641,62 +630,68 @@ sub substituteTags {
|
||||||
$max_alarm_frame = $frame;
|
$max_alarm_frame = $frame;
|
||||||
$max_alarm_score = $frame->{Score};
|
$max_alarm_score = $frame->{Score};
|
||||||
}
|
}
|
||||||
|
$rows ++;
|
||||||
}
|
}
|
||||||
|
Debug("Frames: rows: $rows first alarm frame: $first_alarm_frame max_alaarm_frame: $max_alarm_frame, score: $max_alarm_score");
|
||||||
$sth->finish();
|
$sth->finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
my $url = $Config{ZM_URL};
|
my $url = $Config{ZM_URL};
|
||||||
$text =~ s/%ZP%/$url/g;
|
$text =~ s/%ZP%/$url/g;
|
||||||
$text =~ s/%MN%/$event->{MonitorName}/g;
|
$text =~ s/%MN%/$Event->{MonitorName}/g;
|
||||||
$text =~ s/%MET%/$monitor->{EventCount}/g;
|
$text =~ s/%MET%/$Monitor->{TotalEvents}/g;
|
||||||
$text =~ s/%MEH%/$monitor->{HourEventCount}/g;
|
$text =~ s/%MEH%/$Monitor->{HourEvents}/g;
|
||||||
$text =~ s/%MED%/$monitor->{DayEventCount}/g;
|
$text =~ s/%MED%/$Monitor->{DayEvents}/g;
|
||||||
$text =~ s/%MEW%/$monitor->{WeekEventCount}/g;
|
$text =~ s/%MEW%/$Monitor->{WeekEvents}/g;
|
||||||
$text =~ s/%MEM%/$monitor->{MonthEventCount}/g;
|
$text =~ s/%MEM%/$Monitor->{MonthEvents}/g;
|
||||||
$text =~ s/%MEA%/$monitor->{ArchEventCount}/g;
|
$text =~ s/%MEA%/$Monitor->{ArchivedEvents}/g;
|
||||||
$text =~ s/%MP%/$url?view=watch&mid=$event->{MonitorId}/g;
|
$text =~ s/%MP%/$url?view=watch&mid=$Event->{MonitorId}/g;
|
||||||
$text =~ s/%MPS%/$url?view=watchfeed&mid=$event->{MonitorId}&mode=stream/g;
|
$text =~ s/%MPS%/$url?view=watch&mid=$Event->{MonitorId}&mode=stream/g;
|
||||||
$text =~ s/%MPI%/$url?view=watchfeed&mid=$event->{MonitorId}&mode=still/g;
|
$text =~ s/%MPI%/$url?view=watch&mid=$Event->{MonitorId}&mode=still/g;
|
||||||
$text =~ s/%EP%/$url?view=event&mid=$event->{MonitorId}&eid=$event->{Id}/g;
|
$text =~ s/%EP%/$url?view=event&mid=$Event->{MonitorId}&eid=$Event->{Id}/g;
|
||||||
$text =~ s/%EPS%/$url?view=event&mode=stream&mid=$event->{MonitorId}&eid=$event->{Id}/g;
|
$text =~ s/%EPS%/$url?view=event&mode=stream&mid=$Event->{MonitorId}&eid=$Event->{Id}/g;
|
||||||
$text =~ s/%EPI%/$url?view=event&mode=still&mid=$event->{MonitorId}&eid=$event->{Id}/g;
|
$text =~ s/%EPI%/$url?view=event&mode=still&mid=$Event->{MonitorId}&eid=$Event->{Id}/g;
|
||||||
$text =~ s/%EI%/$event->{Id}/g;
|
$text =~ s/%EI%/$Event->{Id}/g;
|
||||||
$text =~ s/%EN%/$event->{Name}/g;
|
$text =~ s/%EN%/$Event->{Name}/g;
|
||||||
$text =~ s/%EC%/$event->{Cause}/g;
|
$text =~ s/%EC%/$Event->{Cause}/g;
|
||||||
$text =~ s/%ED%/$event->{Notes}/g;
|
$text =~ s/%ED%/$Event->{Notes}/g;
|
||||||
$text =~ s/%ET%/$event->{StartTime}/g;
|
$text =~ s/%ET%/$Event->{StartTime}/g;
|
||||||
$text =~ s/%EL%/$event->{Length}/g;
|
$text =~ s/%EL%/$Event->{Length}/g;
|
||||||
$text =~ s/%EF%/$event->{Frames}/g;
|
$text =~ s/%EF%/$Event->{Frames}/g;
|
||||||
$text =~ s/%EFA%/$event->{AlarmFrames}/g;
|
$text =~ s/%EFA%/$Event->{AlarmFrames}/g;
|
||||||
$text =~ s/%EST%/$event->{TotScore}/g;
|
$text =~ s/%EST%/$Event->{TotScore}/g;
|
||||||
$text =~ s/%ESA%/$event->{AvgScore}/g;
|
$text =~ s/%ESA%/$Event->{AvgScore}/g;
|
||||||
$text =~ s/%ESM%/$event->{MaxScore}/g;
|
$text =~ s/%ESM%/$Event->{MaxScore}/g;
|
||||||
|
|
||||||
if ( $first_alarm_frame ) {
|
if ( $first_alarm_frame ) {
|
||||||
$text =~ s/%EPI1%/$url?view=frame&mid=$event->{MonitorId}&eid=$event->{Id}&fid=$first_alarm_frame->{FrameId}/g;
|
$text =~ s/%EPI1%/$url?view=frame&mid=$Event->{MonitorId}&eid=$Event->{Id}&fid=$first_alarm_frame->{FrameId}/g;
|
||||||
$text =~ s/%EPIM%/$url?view=frame&mid=$event->{MonitorId}&eid=$event->{Id}&fid=$max_alarm_frame->{FrameId}/g;
|
$text =~ s/%EPIM%/$url?view=frame&mid=$Event->{MonitorId}&eid=$Event->{Id}&fid=$max_alarm_frame->{FrameId}/g;
|
||||||
if ( $attachments_ref && $text =~ s/%EI1%//g ) {
|
if ( $attachments_ref && $text =~ s/%EI1%//g ) {
|
||||||
my $path = generateImage( $event, $first_alarm_frame );
|
my $path = generateImage($Event, $first_alarm_frame);
|
||||||
if ( -e $path ) {
|
if ( -e $path ) {
|
||||||
push( @$attachments_ref, { type=>'image/jpeg', path=>$path } );
|
push @$attachments_ref, { type=>'image/jpeg', path=>$path };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $attachments_ref && $text =~ s/%EIM%//g ) {
|
if ( $attachments_ref && ( $text =~ s/%EIM%//g ) ) {
|
||||||
# Don't attach the same image twice
|
# Don't attach the same image twice
|
||||||
if ( !@$attachments_ref
|
if ( !@$attachments_ref
|
||||||
|| ($first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId} )
|
|| ( $first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId} )
|
||||||
) {
|
) {
|
||||||
my $path = generateImage( $event, $max_alarm_frame );
|
my $path = generateImage($Event, $max_alarm_frame);
|
||||||
if ( -e $path ) {
|
if ( -e $path ) {
|
||||||
push( @$attachments_ref, { type=>'image/jpeg', path=>$path } );
|
push @$attachments_ref, { type=>'image/jpeg', path=>$path };
|
||||||
|
} else {
|
||||||
|
Warning("No image for EIM");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( $attachments_ref && $text =~ s/%EI1A%//g ) {
|
if ( $attachments_ref && $text =~ s/%EI1A%//g ) {
|
||||||
my $path = generateImage( $event, $first_alarm_frame, 'analyse' );
|
my $path = generateImage($Event, $first_alarm_frame, 'analyse');
|
||||||
if ( -e $path ) {
|
if ( -e $path ) {
|
||||||
push( @$attachments_ref, { type=>'image/jpeg', path=>$path } );
|
push @$attachments_ref, { type=>'image/jpeg', path=>$path };
|
||||||
|
} else {
|
||||||
|
Warning("No image for EI1A");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( $attachments_ref && $text =~ s/%EIMA%//g ) {
|
if ( $attachments_ref && $text =~ s/%EIMA%//g ) {
|
||||||
|
@ -704,9 +699,11 @@ sub substituteTags {
|
||||||
if ( !@$attachments_ref
|
if ( !@$attachments_ref
|
||||||
|| ($first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId} )
|
|| ($first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId} )
|
||||||
) {
|
) {
|
||||||
my $path = generateImage( $event, $max_alarm_frame, 'analyse');
|
my $path = generateImage($Event, $max_alarm_frame, 'analyse');
|
||||||
if ( -e $path ) {
|
if ( -e $path ) {
|
||||||
push( @$attachments_ref, { type=>'image/jpeg', path=>$path } );
|
push @$attachments_ref, { type=>'image/jpeg', path=>$path };
|
||||||
|
} else {
|
||||||
|
Warning("No image for EIMA");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -714,49 +711,49 @@ sub substituteTags {
|
||||||
|
|
||||||
if ( $attachments_ref && $Config{ZM_OPT_FFMPEG} ) {
|
if ( $attachments_ref && $Config{ZM_OPT_FFMPEG} ) {
|
||||||
if ( $text =~ s/%EV%//g ) {
|
if ( $text =~ s/%EV%//g ) {
|
||||||
my ( $format, $path ) = generateVideo( $filter, $event );
|
my ( $format, $path ) = generateVideo($filter, $Event);
|
||||||
if ( !$format ) {
|
if ( !$format ) {
|
||||||
return( undef );
|
return undef;
|
||||||
}
|
}
|
||||||
push( @$attachments_ref, { type=>"video/$format", path=>$path } );
|
push( @$attachments_ref, { type=>"video/$format", path=>$path } );
|
||||||
}
|
}
|
||||||
if ( $text =~ s/%EVM%//g ) {
|
if ( $text =~ s/%EVM%//g ) {
|
||||||
my ( $format, $path ) = generateVideo( $filter, $event, 1 );
|
my ( $format, $path ) = generateVideo($filter, $Event, 1);
|
||||||
if ( !$format ) {
|
if ( !$format ) {
|
||||||
return( undef );
|
return undef;
|
||||||
}
|
}
|
||||||
push( @$attachments_ref, { type=>"video/$format", path=>$path } );
|
push @$attachments_ref, { type=>"video/$format", path=>$path };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$text =~ s/%FN%/$filter->{Name}/g;
|
$text =~ s/%FN%/$filter->{Name}/g;
|
||||||
( my $filter_name = $filter->{Name} ) =~ s/ /+/g;
|
( my $filter_name = $filter->{Name} ) =~ s/ /+/g;
|
||||||
$text =~ s/%FP%/$url?view=filter&mid=$event->{MonitorId}&filter_name=$filter_name/g;
|
$text =~ s/%FP%/$url?view=filter&mid=$Event->{MonitorId}&filter_name=$filter_name/g;
|
||||||
|
|
||||||
return( $text );
|
return $text;
|
||||||
} # end subsitituteTags
|
} # end subsitituteTags
|
||||||
|
|
||||||
sub sendEmail {
|
sub sendEmail {
|
||||||
my $filter = shift;
|
my $filter = shift;
|
||||||
my $event = shift;
|
my $Event = shift;
|
||||||
|
|
||||||
if ( ! $Config{ZM_FROM_EMAIL} ) {
|
if ( ! $Config{ZM_FROM_EMAIL} ) {
|
||||||
Error( "No 'from' email address defined, not sending email" );
|
Error("No 'from' email address defined, not sending email");
|
||||||
return( 0 );
|
return 0;
|
||||||
}
|
}
|
||||||
if ( ! $Config{ZM_EMAIL_ADDRESS} ) {
|
if ( ! $Config{ZM_EMAIL_ADDRESS} ) {
|
||||||
Error( 'No email address defined, not sending email' );
|
Error('No email address defined, not sending email');
|
||||||
return( 0 );
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Info( "Creating notification email\n" );
|
Info("Creating notification email\n");
|
||||||
|
|
||||||
my $subject = substituteTags( $Config{ZM_EMAIL_SUBJECT}, $filter, $event );
|
my $subject = substituteTags($Config{ZM_EMAIL_SUBJECT}, $filter, $Event);
|
||||||
return( 0 ) if ( !$subject );
|
return 0 if !$subject;
|
||||||
my @attachments;
|
my @attachments;
|
||||||
my $body = substituteTags( $Config{ZM_EMAIL_BODY}, $filter, $event, \@attachments );
|
my $body = substituteTags($Config{ZM_EMAIL_BODY}, $filter, $Event, \@attachments);
|
||||||
return( 0 ) if ( !$body );
|
return 0 if !$body;
|
||||||
|
|
||||||
Info( "Sending notification email '$subject'\n" );
|
Info("Sending notification email '$subject'\n");
|
||||||
|
|
||||||
eval {
|
eval {
|
||||||
if ( $Config{ZM_NEW_MAIL_MODULES} ) {
|
if ( $Config{ZM_NEW_MAIL_MODULES} ) {
|
||||||
|
@ -829,9 +826,9 @@ sub sendEmail {
|
||||||
Info( "Notification email sent\n" );
|
Info( "Notification email sent\n" );
|
||||||
}
|
}
|
||||||
my $sql = 'update Events set Emailed = 1 where Id = ?';
|
my $sql = 'update Events set Emailed = 1 where Id = ?';
|
||||||
my $sth = $dbh->prepare_cached( $sql )
|
my $sth = $dbh->prepare_cached($sql)
|
||||||
or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
|
or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
|
||||||
my $res = $sth->execute( $event->{Id} )
|
my $res = $sth->execute($Event->{Id})
|
||||||
or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
|
or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
|
||||||
|
|
||||||
return( 1 );
|
return( 1 );
|
||||||
|
|
|
@ -211,7 +211,7 @@ if ( $command =~ /^(?:start|restart)$/ ) {
|
||||||
my $res = $sth->execute( @values )
|
my $res = $sth->execute( @values )
|
||||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||||
while( my $monitor = $sth->fetchrow_hashref() ) {
|
while( my $monitor = $sth->fetchrow_hashref() ) {
|
||||||
if ( $monitor->{Function} ne 'None' ) {
|
if ( $monitor->{Function} ne 'None' && $monitor->{Type} ne 'WebSite' ) {
|
||||||
if ( $monitor->{Type} eq 'Local' ) {
|
if ( $monitor->{Type} eq 'Local' ) {
|
||||||
runCommand( "zmdc.pl start zmc -d $monitor->{Device}" );
|
runCommand( "zmdc.pl start zmc -d $monitor->{Device}" );
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -84,6 +84,7 @@ while( 1 ) {
|
||||||
while( my $monitor = $sth->fetchrow_hashref() ) {
|
while( my $monitor = $sth->fetchrow_hashref() ) {
|
||||||
my $now = time();
|
my $now = time();
|
||||||
next if $monitor->{Function} eq 'None';
|
next if $monitor->{Function} eq 'None';
|
||||||
|
next if $monitor->{Type} eq 'WebSite';
|
||||||
my $restart = 0;
|
my $restart = 0;
|
||||||
if ( zmMemVerify( $monitor ) ) {
|
if ( zmMemVerify( $monitor ) ) {
|
||||||
# Check we have got an image recently
|
# Check we have got an image recently
|
||||||
|
@ -147,11 +148,11 @@ while( 1 ) {
|
||||||
if ( !defined($image_time) ) {
|
if ( !defined($image_time) ) {
|
||||||
# Can't read from shared data
|
# Can't read from shared data
|
||||||
$restart = 1;
|
$restart = 1;
|
||||||
Error( "Error reading shared data for $$monitor{Id} $$monitor{Name}\n");
|
Error("Error reading shared data for $$monitor{Id} $$monitor{Name}\n");
|
||||||
} elsif ( !$image_time ) {
|
} elsif ( !$image_time ) {
|
||||||
# We can't get the last capture time so can't be sure it's died.
|
# We can't get the last capture time so can't be sure it's died.
|
||||||
$restart = 1;
|
$restart = 1;
|
||||||
Error( "Error getting last analyse time for $$monitor{Id} $$monitor{Name}\n");
|
Error("Last analyse time for $$monitor{Id} $$monitor{Name} was zero.\n");
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
my $max_image_delay = ( $monitor->{MaxFPS}
|
my $max_image_delay = ( $monitor->{MaxFPS}
|
||||||
|
|
|
@ -53,6 +53,8 @@ protected:
|
||||||
int contrast;
|
int contrast;
|
||||||
bool capture;
|
bool capture;
|
||||||
bool record_audio;
|
bool record_audio;
|
||||||
|
unsigned int bytes;
|
||||||
|
|
||||||
|
|
||||||
int mVideoStreamId;
|
int mVideoStreamId;
|
||||||
int mAudioStreamId;
|
int mAudioStreamId;
|
||||||
|
@ -93,6 +95,7 @@ public:
|
||||||
unsigned int SubpixelOrder() const { return( subpixelorder ); }
|
unsigned int SubpixelOrder() const { return( subpixelorder ); }
|
||||||
unsigned int Pixels() const { return( pixels ); }
|
unsigned int Pixels() const { return( pixels ); }
|
||||||
unsigned int ImageSize() const { return( imagesize ); }
|
unsigned int ImageSize() const { return( imagesize ); }
|
||||||
|
unsigned int Bytes() const { return bytes; };
|
||||||
|
|
||||||
virtual int Brightness( int/*p_brightness*/=-1 ) { return( -1 ); }
|
virtual int Brightness( int/*p_brightness*/=-1 ) { return( -1 ); }
|
||||||
virtual int Hue( int/*p_hue*/=-1 ) { return( -1 ); }
|
virtual int Hue( int/*p_hue*/=-1 ) { return( -1 ); }
|
||||||
|
@ -113,6 +116,7 @@ public:
|
||||||
virtual AVCodecContext *get_AudioCodecContext() { return NULL; };
|
virtual AVCodecContext *get_AudioCodecContext() { return NULL; };
|
||||||
int get_VideoStreamId() { return mVideoStreamId; };
|
int get_VideoStreamId() { return mVideoStreamId; };
|
||||||
int get_AudioStreamId() { return mAudioStreamId; };
|
int get_AudioStreamId() { return mAudioStreamId; };
|
||||||
|
virtual int Close()=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ZM_CAMERA_H
|
#endif // ZM_CAMERA_H
|
||||||
|
|
|
@ -73,6 +73,7 @@ public:
|
||||||
|
|
||||||
void Initialise();
|
void Initialise();
|
||||||
void Terminate();
|
void Terminate();
|
||||||
|
int Close() { return 0; };
|
||||||
|
|
||||||
int PrimeCapture();
|
int PrimeCapture();
|
||||||
int PreCapture();
|
int PreCapture();
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
#include "zm.h"
|
#include "zm.h"
|
||||||
#include "zm_db.h"
|
#include "zm_db.h"
|
||||||
|
|
||||||
// From what I read, we need one of these per thread
|
|
||||||
MYSQL dbconn;
|
MYSQL dbconn;
|
||||||
Mutex db_mutex;
|
Mutex db_mutex;
|
||||||
|
|
||||||
|
@ -31,8 +30,11 @@ bool zmDbConnected = false;
|
||||||
|
|
||||||
bool zmDbConnect() {
|
bool zmDbConnect() {
|
||||||
// For some reason having these lines causes memory corruption and crashing on newer debian/ubuntu
|
// For some reason having these lines causes memory corruption and crashing on newer debian/ubuntu
|
||||||
//if ( zmDbConnected )
|
// But they really need to be here in order to prevent a double open of mysql
|
||||||
//return;
|
if ( zmDbConnected ) {
|
||||||
|
Warning("Calling zmDbConnect when already connected");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if ( !mysql_init(&dbconn) ) {
|
if ( !mysql_init(&dbconn) ) {
|
||||||
Error("Can't initialise database connection: %s", mysql_error(&dbconn));
|
Error("Can't initialise database connection: %s", mysql_error(&dbconn));
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
|
#include <cinttypes>
|
||||||
|
|
||||||
#include "zm.h"
|
#include "zm.h"
|
||||||
#include "zm_db.h"
|
#include "zm_db.h"
|
||||||
|
@ -149,7 +150,7 @@ Event::Event(
|
||||||
time_path_ptr += snprintf(time_path_ptr, sizeof(time_path)-(time_path_ptr-time_path), "%s%02d", i>3?"/":"", dt_parts[i]);
|
time_path_ptr += snprintf(time_path_ptr, sizeof(time_path)-(time_path_ptr-time_path), "%s%02d", i>3?"/":"", dt_parts[i]);
|
||||||
}
|
}
|
||||||
// Create event id symlink
|
// Create event id symlink
|
||||||
std::string id_file = stringtf("%s/.%llu", date_path, id);
|
std::string id_file = stringtf("%s/.%" PRIu64, date_path, id);
|
||||||
if ( symlink(time_path, id_file.c_str()) < 0 )
|
if ( symlink(time_path, id_file.c_str()) < 0 )
|
||||||
Error("Can't symlink %s -> %s: %s", id_file.c_str(), path.c_str(), strerror(errno));
|
Error("Can't symlink %s -> %s: %s", id_file.c_str(), path.c_str(), strerror(errno));
|
||||||
} else if ( storage->Scheme() == Storage::MEDIUM ) {
|
} else if ( storage->Scheme() == Storage::MEDIUM ) {
|
||||||
|
@ -161,7 +162,7 @@ Event::Event(
|
||||||
if ( errno != EEXIST )
|
if ( errno != EEXIST )
|
||||||
Error("Can't mkdir %s: %s", path.c_str(), strerror(errno));
|
Error("Can't mkdir %s: %s", path.c_str(), strerror(errno));
|
||||||
}
|
}
|
||||||
path += stringtf("/%llu", id);
|
path += stringtf("/%" PRIu64, id);
|
||||||
if ( mkdir(path.c_str(), 0755) ) {
|
if ( mkdir(path.c_str(), 0755) ) {
|
||||||
// FIXME This should not be fatal. Should probably move to a different storage area.
|
// FIXME This should not be fatal. Should probably move to a different storage area.
|
||||||
if ( errno != EEXIST )
|
if ( errno != EEXIST )
|
||||||
|
@ -169,7 +170,7 @@ Event::Event(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Shallow Storage
|
// Shallow Storage
|
||||||
path = stringtf("%s/%d/%llu", storage->Path(), monitor->Id(), id);
|
path = stringtf("%s/%d/%" PRIu64, storage->Path(), monitor->Id(), id);
|
||||||
if ( mkdir(path.c_str(), 0755) ) {
|
if ( mkdir(path.c_str(), 0755) ) {
|
||||||
if ( errno != EEXIST ) {
|
if ( errno != EEXIST ) {
|
||||||
Error("Can't mkdir %s: %s", path.c_str(), strerror(errno));
|
Error("Can't mkdir %s: %s", path.c_str(), strerror(errno));
|
||||||
|
@ -177,7 +178,7 @@ Event::Event(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create empty id tag file
|
// Create empty id tag file
|
||||||
std::string id_file = stringtf("%s/.%llu", path, id);
|
std::string id_file = stringtf("%s/.%" PRIu64, path, id);
|
||||||
if ( FILE *id_fp = fopen(id_file.c_str(), "w") )
|
if ( FILE *id_fp = fopen(id_file.c_str(), "w") )
|
||||||
fclose(id_fp);
|
fclose(id_fp);
|
||||||
else
|
else
|
||||||
|
@ -238,7 +239,7 @@ Event::~Event() {
|
||||||
if ( frames > last_db_frame ) {
|
if ( frames > last_db_frame ) {
|
||||||
Debug(1, "Adding closing frame %d to DB", frames);
|
Debug(1, "Adding closing frame %d to DB", frames);
|
||||||
snprintf(sql, sizeof(sql),
|
snprintf(sql, sizeof(sql),
|
||||||
"INSERT INTO Frames ( EventId, FrameId, TimeStamp, Delta ) VALUES ( %llu, %d, from_unixtime( %ld ), %s%ld.%02ld )",
|
"INSERT INTO Frames ( EventId, FrameId, TimeStamp, Delta ) VALUES ( %" PRIu64 ", %d, from_unixtime( %ld ), %s%ld.%02ld )",
|
||||||
id, frames, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec);
|
id, frames, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec);
|
||||||
db_mutex.lock();
|
db_mutex.lock();
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
if ( mysql_query(&dbconn, sql) ) {
|
||||||
|
@ -250,7 +251,7 @@ Event::~Event() {
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(sql, sizeof(sql),
|
snprintf(sql, sizeof(sql),
|
||||||
"UPDATE Events SET Name='%s %llu', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' where Id = %llu",
|
"UPDATE Events SET Name='%s %" PRIu64 "', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' WHERE Id = %" PRIu64,
|
||||||
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, video_name, id );
|
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, video_name, id );
|
||||||
db_mutex.lock();
|
db_mutex.lock();
|
||||||
while ( mysql_query(&dbconn, sql) ) {
|
while ( mysql_query(&dbconn, sql) ) {
|
||||||
|
@ -397,7 +398,7 @@ void Event::updateNotes( const StringSetMap &newNoteSetMap ) {
|
||||||
|
|
||||||
mysql_real_escape_string(&dbconn, escapedNotes, notes.c_str(), notes.length());
|
mysql_real_escape_string(&dbconn, escapedNotes, notes.c_str(), notes.length());
|
||||||
|
|
||||||
snprintf(sql, sizeof(sql), "UPDATE Events SET Notes = '%s' WHERE Id = %llu", escapedNotes, id);
|
snprintf(sql, sizeof(sql), "UPDATE Events SET Notes = '%s' WHERE Id = %" PRIu64, escapedNotes, id);
|
||||||
db_mutex.lock();
|
db_mutex.lock();
|
||||||
if ( mysql_query( &dbconn, sql ) ) {
|
if ( mysql_query( &dbconn, sql ) ) {
|
||||||
Error( "Can't insert event: %s", mysql_error( &dbconn ) );
|
Error( "Can't insert event: %s", mysql_error( &dbconn ) );
|
||||||
|
@ -456,7 +457,7 @@ void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, str
|
||||||
}
|
}
|
||||||
|
|
||||||
int sql_len = strlen(sql);
|
int sql_len = strlen(sql);
|
||||||
snprintf( sql+sql_len, sizeof(sql)-sql_len, "( %llu, %d, from_unixtime(%ld), %s%ld.%02ld ), ", id, frames, timestamps[i]->tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec );
|
snprintf( sql+sql_len, sizeof(sql)-sql_len, "( %" PRIu64 ", %d, from_unixtime(%ld), %s%ld.%02ld ), ", id, frames, timestamps[i]->tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec );
|
||||||
|
|
||||||
frameCount++;
|
frameCount++;
|
||||||
}
|
}
|
||||||
|
@ -531,7 +532,7 @@ void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image *
|
||||||
|
|
||||||
Debug(1, "Adding frame %d of type \"%s\" to DB", frames, Event::frame_type_names[frame_type]);
|
Debug(1, "Adding frame %d of type \"%s\" to DB", frames, Event::frame_type_names[frame_type]);
|
||||||
static char sql[ZM_SQL_MED_BUFSIZ];
|
static char sql[ZM_SQL_MED_BUFSIZ];
|
||||||
snprintf(sql, sizeof(sql), "INSERT INTO Frames ( EventId, FrameId, Type, TimeStamp, Delta, Score ) values ( %llu, %d, '%s', from_unixtime( %ld ), %s%ld.%02ld, %d )", id, frames, frame_type_names[frame_type], timestamp.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, score);
|
snprintf(sql, sizeof(sql), "INSERT INTO Frames ( EventId, FrameId, Type, TimeStamp, Delta, Score ) values ( %" PRIu64 ", %d, '%s', from_unixtime( %ld ), %s%ld.%02ld, %d )", id, frames, frame_type_names[frame_type], timestamp.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, score);
|
||||||
db_mutex.lock();
|
db_mutex.lock();
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
if ( mysql_query(&dbconn, sql) ) {
|
||||||
Error("Can't insert frame: %s", mysql_error(&dbconn));
|
Error("Can't insert frame: %s", mysql_error(&dbconn));
|
||||||
|
@ -545,7 +546,7 @@ void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image *
|
||||||
// We are writing a Bulk frame
|
// We are writing a Bulk frame
|
||||||
if ( frame_type == BULK ) {
|
if ( frame_type == BULK ) {
|
||||||
snprintf( sql, sizeof(sql),
|
snprintf( sql, sizeof(sql),
|
||||||
"UPDATE Events SET Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d where Id = %llu",
|
"UPDATE Events SET Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d where Id = %" PRIu64,
|
||||||
( delta_time.positive?"":"-" ),
|
( delta_time.positive?"":"-" ),
|
||||||
delta_time.sec, delta_time.fsec,
|
delta_time.sec, delta_time.fsec,
|
||||||
frames,
|
frames,
|
||||||
|
|
|
@ -75,7 +75,7 @@ class Event {
|
||||||
static int pre_alarm_count;
|
static int pre_alarm_count;
|
||||||
static PreAlarmData pre_alarm_data[MAX_PRE_ALARM_FRAMES];
|
static PreAlarmData pre_alarm_data[MAX_PRE_ALARM_FRAMES];
|
||||||
|
|
||||||
unsigned long long int id;
|
uint64_t id;
|
||||||
Monitor *monitor;
|
Monitor *monitor;
|
||||||
struct timeval start_time;
|
struct timeval start_time;
|
||||||
struct timeval end_time;
|
struct timeval end_time;
|
||||||
|
@ -102,7 +102,7 @@ class Event {
|
||||||
Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap );
|
Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap );
|
||||||
~Event();
|
~Event();
|
||||||
|
|
||||||
unsigned long long int Id() const { return id; }
|
uint64_t Id() const { return id; }
|
||||||
const std::string &Cause() { return cause; }
|
const std::string &Cause() { return cause; }
|
||||||
int Frames() const { return frames; }
|
int Frames() const { return frames; }
|
||||||
int AlarmFrames() const { return alarm_frames; }
|
int AlarmFrames() const { return alarm_frames; }
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
|
#include <cinttypes>
|
||||||
|
|
||||||
#include "zm.h"
|
#include "zm.h"
|
||||||
#include "zm_db.h"
|
#include "zm_db.h"
|
||||||
|
@ -62,7 +63,7 @@ bool EventStream::loadInitialEventData( int monitor_id, time_t event_time ) {
|
||||||
exit( mysql_errno(&dbconn));
|
exit( mysql_errno(&dbconn));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long long init_event_id = atoll(dbrow[0]);
|
uint64_t init_event_id = atoll(dbrow[0]);
|
||||||
|
|
||||||
mysql_free_result(result);
|
mysql_free_result(result);
|
||||||
|
|
||||||
|
@ -87,7 +88,7 @@ bool EventStream::loadInitialEventData( int monitor_id, time_t event_time ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EventStream::loadInitialEventData( unsigned long long init_event_id, unsigned int init_frame_id ) {
|
bool EventStream::loadInitialEventData( uint64_t init_event_id, unsigned int init_frame_id ) {
|
||||||
loadEventData(init_event_id);
|
loadEventData(init_event_id);
|
||||||
|
|
||||||
if ( init_frame_id ) {
|
if ( init_frame_id ) {
|
||||||
|
@ -105,10 +106,10 @@ bool EventStream::loadInitialEventData( unsigned long long init_event_id, unsign
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EventStream::loadEventData(unsigned long long event_id) {
|
bool EventStream::loadEventData(uint64_t event_id) {
|
||||||
static char sql[ZM_SQL_MED_BUFSIZ];
|
static char sql[ZM_SQL_MED_BUFSIZ];
|
||||||
|
|
||||||
snprintf(sql, sizeof(sql), "SELECT MonitorId, StorageId, Frames, unix_timestamp( StartTime ) AS StartTimestamp, (SELECT max(Delta)-min(Delta) FROM Frames WHERE EventId=Events.Id) AS Duration, DefaultVideo, Scheme FROM Events WHERE Id = %llu", event_id);
|
snprintf(sql, sizeof(sql), "SELECT MonitorId, StorageId, Frames, unix_timestamp( StartTime ) AS StartTimestamp, (SELECT max(Delta)-min(Delta) FROM Frames WHERE EventId=Events.Id) AS Duration, DefaultVideo, Scheme FROM Events WHERE Id = %" PRIu64, event_id);
|
||||||
|
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
if ( mysql_query(&dbconn, sql) ) {
|
||||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||||
|
@ -167,26 +168,26 @@ bool EventStream::loadEventData(unsigned long long event_id) {
|
||||||
} else if ( event_data->scheme == Storage::MEDIUM ) {
|
} else if ( event_data->scheme == Storage::MEDIUM ) {
|
||||||
struct tm *event_time = localtime( &event_data->start_time );
|
struct tm *event_time = localtime( &event_data->start_time );
|
||||||
if ( storage_path[0] == '/' )
|
if ( storage_path[0] == '/' )
|
||||||
snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%04d-%02d-%02d/%llu",
|
snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%04d-%02d-%02d/%" PRIu64,
|
||||||
storage_path, event_data->monitor_id, event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday, event_data->event_id );
|
storage_path, event_data->monitor_id, event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday, event_data->event_id );
|
||||||
else
|
else
|
||||||
snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%04d-%02d-%02d/%llu",
|
snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%04d-%02d-%02d/%" PRIu64,
|
||||||
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday,
|
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday,
|
||||||
event_data->event_id );
|
event_data->event_id );
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if ( storage_path[0] == '/' )
|
if ( storage_path[0] == '/' )
|
||||||
snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%llu",
|
snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%" PRIu64,
|
||||||
storage_path, event_data->monitor_id, event_data->event_id );
|
storage_path, event_data->monitor_id, event_data->event_id );
|
||||||
else
|
else
|
||||||
snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%llu",
|
snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%" PRIu64,
|
||||||
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_data->event_id );
|
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_data->event_id );
|
||||||
}
|
}
|
||||||
delete storage; storage = NULL;
|
delete storage; storage = NULL;
|
||||||
|
|
||||||
updateFrameRate( (double)event_data->frame_count/event_data->duration );
|
updateFrameRate( (double)event_data->frame_count/event_data->duration );
|
||||||
|
|
||||||
snprintf(sql, sizeof(sql), "SELECT FrameId, unix_timestamp( `TimeStamp` ), Delta FROM Frames where EventId = %llu ORDER BY FrameId ASC", event_id);
|
snprintf(sql, sizeof(sql), "SELECT FrameId, unix_timestamp( `TimeStamp` ), Delta FROM Frames where EventId = %" PRIu64 " ORDER BY FrameId ASC", event_id);
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
if ( mysql_query(&dbconn, sql) ) {
|
||||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||||
exit(mysql_errno(&dbconn));
|
exit(mysql_errno(&dbconn));
|
||||||
|
@ -254,7 +255,7 @@ bool EventStream::loadEventData(unsigned long long event_id) {
|
||||||
else
|
else
|
||||||
curr_stream_time = event_data->frames[event_data->frame_count-1].timestamp;
|
curr_stream_time = event_data->frames[event_data->frame_count-1].timestamp;
|
||||||
}
|
}
|
||||||
Debug(2, "Event:%llu, Frames:%ld, Duration: %.2f", event_data->event_id, event_data->frame_count, event_data->duration);
|
Debug(2, "Event:%" PRIu64 ", Frames:%ld, Duration: %.2f", event_data->event_id, event_data->frame_count, event_data->duration);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} // bool EventStream::loadEventData( int event_id )
|
} // bool EventStream::loadEventData( int event_id )
|
||||||
|
@ -450,7 +451,7 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
struct {
|
struct {
|
||||||
unsigned long long event_id;
|
uint64_t event_id;
|
||||||
int progress;
|
int progress;
|
||||||
int rate;
|
int rate;
|
||||||
int zoom;
|
int zoom;
|
||||||
|
@ -462,7 +463,7 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
||||||
status_data.rate = replay_rate;
|
status_data.rate = replay_rate;
|
||||||
status_data.zoom = zoom;
|
status_data.zoom = zoom;
|
||||||
status_data.paused = paused;
|
status_data.paused = paused;
|
||||||
Debug( 2, "Event:%llu, Paused:%d, progress:%d Rate:%d, Zoom:%d",
|
Debug( 2, "Event:%" PRIu64 ", Paused:%d, progress:%d Rate:%d, Zoom:%d",
|
||||||
status_data.event_id,
|
status_data.event_id,
|
||||||
status_data.paused,
|
status_data.paused,
|
||||||
status_data.progress,
|
status_data.progress,
|
||||||
|
@ -492,10 +493,10 @@ void EventStream::checkEventLoaded() {
|
||||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||||
|
|
||||||
if ( curr_frame_id <= 0 ) {
|
if ( curr_frame_id <= 0 ) {
|
||||||
snprintf( sql, sizeof(sql), "SELECT Id FROM Events WHERE MonitorId = %ld AND Id < %llu ORDER BY Id DESC LIMIT 1", event_data->monitor_id, event_data->event_id );
|
snprintf( sql, sizeof(sql), "SELECT Id FROM Events WHERE MonitorId = %ld AND Id < %" PRIu64 " ORDER BY Id DESC LIMIT 1", event_data->monitor_id, event_data->event_id );
|
||||||
reload_event = true;
|
reload_event = true;
|
||||||
} else if ( (unsigned int)curr_frame_id > event_data->frame_count ) {
|
} else if ( (unsigned int)curr_frame_id > event_data->frame_count ) {
|
||||||
snprintf( sql, sizeof(sql), "SELECT Id FROM Events WHERE MonitorId = %ld AND Id > %llu ORDER BY Id ASC LIMIT 1", event_data->monitor_id, event_data->event_id );
|
snprintf( sql, sizeof(sql), "SELECT Id FROM Events WHERE MonitorId = %ld AND Id > %" PRIu64 " ORDER BY Id ASC LIMIT 1", event_data->monitor_id, event_data->event_id );
|
||||||
reload_event = true;
|
reload_event = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,8 +521,8 @@ void EventStream::checkEventLoaded() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( dbrow ) {
|
if ( dbrow ) {
|
||||||
unsigned long long event_id = atoll(dbrow[0]);
|
uint64_t event_id = atoll(dbrow[0]);
|
||||||
Debug( 1, "Loading new event %llu", event_id );
|
Debug( 1, "Loading new event %" PRIu64, event_id );
|
||||||
|
|
||||||
loadEventData(event_id);
|
loadEventData(event_id);
|
||||||
|
|
||||||
|
@ -846,7 +847,7 @@ void EventStream::runStream() {
|
||||||
|
|
||||||
closeComms();
|
closeComms();
|
||||||
}
|
}
|
||||||
void EventStream::setStreamStart( unsigned long long init_event_id, unsigned int init_frame_id=0 ) {
|
void EventStream::setStreamStart( uint64_t init_event_id, unsigned int init_frame_id=0 ) {
|
||||||
loadInitialEventData( init_event_id, init_frame_id );
|
loadInitialEventData( init_event_id, init_frame_id );
|
||||||
if ( !(monitor = Monitor::Load( event_data->monitor_id, false, Monitor::QUERY )) ) {
|
if ( !(monitor = Monitor::Load( event_data->monitor_id, false, Monitor::QUERY )) ) {
|
||||||
Fatal( "Unable to load monitor id %d for streaming", event_data->monitor_id );
|
Fatal( "Unable to load monitor id %d for streaming", event_data->monitor_id );
|
||||||
|
|
|
@ -54,7 +54,7 @@ class EventStream : public StreamBase {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EventData {
|
struct EventData {
|
||||||
unsigned long long event_id;
|
uint64_t event_id;
|
||||||
unsigned long monitor_id;
|
unsigned long monitor_id;
|
||||||
unsigned long storage_id;
|
unsigned long storage_id;
|
||||||
unsigned long frame_count;
|
unsigned long frame_count;
|
||||||
|
@ -83,8 +83,8 @@ class EventStream : public StreamBase {
|
||||||
FFmpeg_Input *ffmpeg_input;
|
FFmpeg_Input *ffmpeg_input;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool loadEventData( unsigned long long event_id );
|
bool loadEventData( uint64_t event_id );
|
||||||
bool loadInitialEventData( unsigned long long init_event_id, unsigned int init_frame_id );
|
bool loadInitialEventData( uint64_t init_event_id, unsigned int init_frame_id );
|
||||||
bool loadInitialEventData( int monitor_id, time_t event_time );
|
bool loadInitialEventData( int monitor_id, time_t event_time );
|
||||||
|
|
||||||
void checkEventLoaded();
|
void checkEventLoaded();
|
||||||
|
@ -110,7 +110,7 @@ class EventStream : public StreamBase {
|
||||||
ffmpeg_input = NULL;
|
ffmpeg_input = NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
void setStreamStart( unsigned long long init_event_id, unsigned int init_frame_id );
|
void setStreamStart( uint64_t init_event_id, unsigned int init_frame_id );
|
||||||
void setStreamStart( int monitor_id, time_t event_time );
|
void setStreamStart( int monitor_id, time_t event_time );
|
||||||
void setStreamMode( StreamMode p_mode ) {
|
void setStreamMode( StreamMode p_mode ) {
|
||||||
mode = p_mode;
|
mode = p_mode;
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
#include <cinttypes>
|
||||||
|
|
||||||
#include "zm_ffmpeg.h"
|
#include "zm_ffmpeg.h"
|
||||||
#include "zm_image.h"
|
#include "zm_image.h"
|
||||||
|
@ -27,9 +28,9 @@ void FFMPEGInit() {
|
||||||
static bool bInit = false;
|
static bool bInit = false;
|
||||||
|
|
||||||
if ( !bInit ) {
|
if ( !bInit ) {
|
||||||
if ( logDebugging() )
|
//if ( logDebugging() )
|
||||||
av_log_set_level( AV_LOG_DEBUG );
|
//av_log_set_level( AV_LOG_DEBUG );
|
||||||
else
|
//else
|
||||||
av_log_set_level( AV_LOG_QUIET );
|
av_log_set_level( AV_LOG_QUIET );
|
||||||
av_register_all();
|
av_register_all();
|
||||||
avformat_network_init();
|
avformat_network_init();
|
||||||
|
|
|
@ -113,7 +113,7 @@ FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::stri
|
||||||
|
|
||||||
FfmpegCamera::~FfmpegCamera() {
|
FfmpegCamera::~FfmpegCamera() {
|
||||||
|
|
||||||
CloseFfmpeg();
|
Close();
|
||||||
|
|
||||||
avformat_network_deinit();
|
avformat_network_deinit();
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ FfmpegCamera::~FfmpegCamera() {
|
||||||
int FfmpegCamera::PrimeCapture() {
|
int FfmpegCamera::PrimeCapture() {
|
||||||
if ( mCanCapture ) {
|
if ( mCanCapture ) {
|
||||||
Info("Priming capture from %s, Closing", mPath.c_str());
|
Info("Priming capture from %s, Closing", mPath.c_str());
|
||||||
CloseFfmpeg();
|
Close();
|
||||||
}
|
}
|
||||||
mVideoStreamId = -1;
|
mVideoStreamId = -1;
|
||||||
mAudioStreamId = -1;
|
mAudioStreamId = -1;
|
||||||
|
@ -166,6 +166,7 @@ int FfmpegCamera::Capture(ZMPacket &zm_packet) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bytes += packet.size;
|
||||||
zm_packet.set_packet(&packet);
|
zm_packet.set_packet(&packet);
|
||||||
zm_av_packet_unref(&packet);
|
zm_av_packet_unref(&packet);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -435,7 +436,7 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||||
return 1;
|
return 1;
|
||||||
} // int FfmpegCamera::OpenFfmpeg()
|
} // int FfmpegCamera::OpenFfmpeg()
|
||||||
|
|
||||||
int FfmpegCamera::CloseFfmpeg() {
|
int FfmpegCamera::Close() {
|
||||||
|
|
||||||
Debug(2, "CloseFfmpeg called.");
|
Debug(2, "CloseFfmpeg called.");
|
||||||
|
|
||||||
|
@ -476,6 +477,6 @@ int FfmpegCamera::CloseFfmpeg() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} // end int FfmpegCamera::CloseFfmpeg()
|
} // end FfmpegCamera::Close
|
||||||
|
|
||||||
#endif // HAVE_LIBAVFORMAT
|
#endif // HAVE_LIBAVFORMAT
|
||||||
|
|
|
@ -69,7 +69,7 @@ class FfmpegCamera : public Camera {
|
||||||
AVPacket packet;
|
AVPacket packet;
|
||||||
|
|
||||||
int OpenFfmpeg();
|
int OpenFfmpeg();
|
||||||
int CloseFfmpeg();
|
int Close();
|
||||||
bool mCanCapture;
|
bool mCanCapture;
|
||||||
#endif // HAVE_LIBAVFORMAT
|
#endif // HAVE_LIBAVFORMAT
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ public:
|
||||||
int PreCapture();
|
int PreCapture();
|
||||||
int Capture( ZMPacket &p );
|
int Capture( ZMPacket &p );
|
||||||
int PostCapture();
|
int PostCapture();
|
||||||
|
int Close() { return 0; };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ZM_FILE_CAMERA_H
|
#endif // ZM_FILE_CAMERA_H
|
||||||
|
|
|
@ -69,6 +69,7 @@ public:
|
||||||
int PreCapture();
|
int PreCapture();
|
||||||
int Capture( ZMPacket &p );
|
int Capture( ZMPacket &p );
|
||||||
int PostCapture();
|
int PostCapture();
|
||||||
|
int Close() { return 0; };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // HAVE_LIBVLC
|
#endif // HAVE_LIBVLC
|
||||||
|
|
|
@ -158,6 +158,7 @@ public:
|
||||||
int PreCapture();
|
int PreCapture();
|
||||||
int Capture(ZMPacket &p);
|
int Capture(ZMPacket &p);
|
||||||
int PostCapture();
|
int PostCapture();
|
||||||
|
int Close() { return 0; };
|
||||||
static bool GetCurrentSettings( const char *device, char *output, int version, bool verbose );
|
static bool GetCurrentSettings( const char *device, char *output, int version, bool verbose );
|
||||||
AVStream* get_VideoStream();
|
AVStream* get_VideoStream();
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
|
#include <cinttypes>
|
||||||
|
|
||||||
#include "zm.h"
|
#include "zm.h"
|
||||||
#include "zm_db.h"
|
#include "zm_db.h"
|
||||||
|
@ -77,7 +78,7 @@ std::string load_monitor_sql =
|
||||||
"EventPrefix, LabelFormat, LabelX, LabelY, LabelSize,"
|
"EventPrefix, LabelFormat, LabelX, LabelY, LabelSize,"
|
||||||
"ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, "
|
"ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, "
|
||||||
"SectionLength, FrameSkip, MotionFrameSkip, "
|
"SectionLength, FrameSkip, MotionFrameSkip, "
|
||||||
"FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif, SignalCheckColour FROM Monitors";
|
"FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif, SignalCheckPoints, SignalCheckColour FROM Monitors";
|
||||||
|
|
||||||
std::string CameraType_Strings[] = {
|
std::string CameraType_Strings[] = {
|
||||||
"Local",
|
"Local",
|
||||||
|
@ -316,6 +317,7 @@ Monitor::Monitor()
|
||||||
ref_blend_perc(0),
|
ref_blend_perc(0),
|
||||||
alarm_ref_blend_perc(0),
|
alarm_ref_blend_perc(0),
|
||||||
track_motion(0),
|
track_motion(0),
|
||||||
|
signal_check_points(0),
|
||||||
signal_check_colour(0),
|
signal_check_colour(0),
|
||||||
embed_exif(0),
|
embed_exif(0),
|
||||||
purpose(QUERY),
|
purpose(QUERY),
|
||||||
|
@ -543,7 +545,8 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) {
|
||||||
+ (image_buffer_count * width * height * colours)
|
+ (image_buffer_count * width * height * colours)
|
||||||
+ 64; /* Padding used to permit aligning the images buffer to 64 byte boundary */
|
+ 64; /* Padding used to permit aligning the images buffer to 64 byte boundary */
|
||||||
|
|
||||||
Debug(1, "mem.size=%d", mem_size);
|
Debug(1, "mem.size SharedData=%d TriggerData=%d VideoStoreData=%d total=%d",
|
||||||
|
sizeof(SharedData), sizeof(TriggerData), sizeof(VideoStoreData), mem_size);
|
||||||
mem_ptr = NULL;
|
mem_ptr = NULL;
|
||||||
|
|
||||||
Zone **zones = 0;
|
Zone **zones = 0;
|
||||||
|
@ -551,6 +554,13 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) {
|
||||||
this->AddZones(n_zones, zones);
|
this->AddZones(n_zones, zones);
|
||||||
this->AddPrivacyBitmask(zones);
|
this->AddPrivacyBitmask(zones);
|
||||||
|
|
||||||
|
// maybe unneeded
|
||||||
|
storage = new Storage(storage_id);
|
||||||
|
Debug(1, "Storage path: %s", storage->Path());
|
||||||
|
// Should maybe store this for later use
|
||||||
|
char monitor_dir[PATH_MAX] = "";
|
||||||
|
snprintf(monitor_dir, sizeof(monitor_dir), "%s/%d", storage->Path(), id);
|
||||||
|
|
||||||
//this0>delta_image( width, height, ZM_COLOUR_GRAY8, ZM_SUBPIX_ORDER_NONE ),
|
//this0>delta_image( width, height, ZM_COLOUR_GRAY8, ZM_SUBPIX_ORDER_NONE ),
|
||||||
//ref_image( width, height, p_camera->Colours(), p_camera->SubpixelOrder() ),
|
//ref_image( width, height, p_camera->Colours(), p_camera->SubpixelOrder() ),
|
||||||
Debug(1, "Loaded monitor %d(%s), %d zones", id, name, n_zones);
|
Debug(1, "Loaded monitor %d(%s), %d zones", id, name, n_zones);
|
||||||
|
@ -824,7 +834,7 @@ bool Monitor::connect() {
|
||||||
shared_images = (uint8_t*)((unsigned long)shared_images + (64 - ((unsigned long)shared_images % 64)));
|
shared_images = (uint8_t*)((unsigned long)shared_images + (64 - ((unsigned long)shared_images % 64)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug(3, "Allocating %d image buffers", image_buffer_count );
|
Debug(3, "Allocating %d image buffers", image_buffer_count);
|
||||||
image_buffer = new ZMPacket[image_buffer_count];
|
image_buffer = new ZMPacket[image_buffer_count];
|
||||||
for ( int i = 0; i < image_buffer_count; i++ ) {
|
for ( int i = 0; i < image_buffer_count; i++ ) {
|
||||||
image_buffer[i].image_index = i;
|
image_buffer[i].image_index = i;
|
||||||
|
@ -887,7 +897,7 @@ Monitor::~Monitor() {
|
||||||
|
|
||||||
if ( mem_ptr ) {
|
if ( mem_ptr ) {
|
||||||
if ( event ) {
|
if ( event ) {
|
||||||
Info( "%s: image_count:%d - Closing event %llu, shutting down", name, image_count, event->Id() );
|
Info( "%s: image_count:%d - Closing event %" PRIu64 ", shutting down", name, image_count, event->Id() );
|
||||||
closeEvent();
|
closeEvent();
|
||||||
|
|
||||||
// closeEvent may start another thread to close the event, so wait for it to finish
|
// closeEvent may start another thread to close the event, so wait for it to finish
|
||||||
|
@ -1082,7 +1092,7 @@ unsigned int Monitor::GetLastWriteIndex() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Monitor::GetLastEventId() const {
|
uint64_t Monitor::GetLastEventId() const {
|
||||||
Debug(2, "mem_ptr(%x), size(%d) State(%d) last_read_index(%d) last_read_time(%d) last_event(%llu)",
|
Debug(2, "mem_ptr(%x), size(%d) State(%d) last_read_index(%d) last_read_time(%d) last_event(%" PRIu64 ")",
|
||||||
mem_ptr,
|
mem_ptr,
|
||||||
shared_data->size,
|
shared_data->size,
|
||||||
shared_data->state,
|
shared_data->state,
|
||||||
|
@ -1105,7 +1115,7 @@ double Monitor::GetFPS() const {
|
||||||
ZMPacket *snap1 = &image_buffer[index1];
|
ZMPacket *snap1 = &image_buffer[index1];
|
||||||
if ( !snap1->timestamp->tv_sec ) {
|
if ( !snap1->timestamp->tv_sec ) {
|
||||||
// This should be impossible
|
// This should be impossible
|
||||||
Warning("Impossible situation. No timestamp on captured image");
|
Warning("Impossible situation. No timestamp on captured image index was %d, image-buffer_count was (%d)", index1, image_buffer_count);
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
struct timeval time1 = *snap1->timestamp;
|
struct timeval time1 = *snap1->timestamp;
|
||||||
|
@ -1196,9 +1206,9 @@ void Monitor::actionReload() {
|
||||||
void Monitor::actionEnable() {
|
void Monitor::actionEnable() {
|
||||||
shared_data->action |= RELOAD;
|
shared_data->action |= RELOAD;
|
||||||
|
|
||||||
|
db_mutex.lock();
|
||||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||||
snprintf(sql, sizeof(sql), "UPDATE Monitors SET Enabled = 1 WHERE Id = %d", id);
|
snprintf(sql, sizeof(sql), "UPDATE Monitors SET Enabled = 1 WHERE Id = %d", id);
|
||||||
db_mutex.lock();
|
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
if ( mysql_query(&dbconn, sql) ) {
|
||||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||||
}
|
}
|
||||||
|
@ -1374,7 +1384,7 @@ void Monitor::DumpZoneImage( const char *zone_string ) {
|
||||||
if ( eventid_row.fetch(sql.c_str()) ) {
|
if ( eventid_row.fetch(sql.c_str()) ) {
|
||||||
uint64_t event_id = atoll(eventid_row[0]);
|
uint64_t event_id = atoll(eventid_row[0]);
|
||||||
|
|
||||||
Debug(3, "Got event %llu", event_id);
|
Debug(3, "Got event %" PRIu64, event_id);
|
||||||
EventStream *stream = new EventStream();
|
EventStream *stream = new EventStream();
|
||||||
stream->setStreamStart(event_id, (unsigned int)1);
|
stream->setStreamStart(event_id, (unsigned int)1);
|
||||||
zone_image = stream->getImage();
|
zone_image = stream->getImage();
|
||||||
|
@ -1446,7 +1456,7 @@ bool Monitor::CheckSignal( const Image *image ) {
|
||||||
static Rgb colour_val; /* RGB32 color */
|
static Rgb colour_val; /* RGB32 color */
|
||||||
static int usedsubpixorder;
|
static int usedsubpixorder;
|
||||||
|
|
||||||
if ( config.signal_check_points > 0 ) {
|
if ( signal_check_points > 0 ) {
|
||||||
if ( static_undef ) {
|
if ( static_undef ) {
|
||||||
static_undef = false;
|
static_undef = false;
|
||||||
usedsubpixorder = camera->SubpixelOrder();
|
usedsubpixorder = camera->SubpixelOrder();
|
||||||
|
@ -1464,8 +1474,9 @@ bool Monitor::CheckSignal( const Image *image ) {
|
||||||
int colours = image->Colours();
|
int colours = image->Colours();
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for ( int i = 0; i < config.signal_check_points; i++ ) {
|
for ( int i = 0; i < signal_check_points; i++ ) {
|
||||||
while( true ) {
|
while( true ) {
|
||||||
|
// Why the casting to long long? also note that on a 64bit cpu, long long is 128bits
|
||||||
index = (int)(((long long)rand()*(long long)(pixels-1))/RAND_MAX);
|
index = (int)(((long long)rand()*(long long)(pixels-1))/RAND_MAX);
|
||||||
if ( !config.timestamp_on_capture || !label_format[0] )
|
if ( !config.timestamp_on_capture || !label_format[0] )
|
||||||
break;
|
break;
|
||||||
|
@ -1501,6 +1512,7 @@ bool Monitor::CheckSignal( const Image *image ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // end for < signal_check_points
|
} // end for < signal_check_points
|
||||||
|
Debug(1,"SignalCheck: %d points, colour_val(%d)", signal_check_points, colour_val);
|
||||||
return false;
|
return false;
|
||||||
} // end if signal_check_points
|
} // end if signal_check_points
|
||||||
return true;
|
return true;
|
||||||
|
@ -1650,7 +1662,7 @@ bool Monitor::Analyse() {
|
||||||
if ( !signal ) {
|
if ( !signal ) {
|
||||||
signalText = "Lost";
|
signalText = "Lost";
|
||||||
if ( event ) {
|
if ( event ) {
|
||||||
Info( "%s: %03d - Closing event %d, signal loss", name, analysis_image_count, event->Id() );
|
Info( "%s: %03d - Closing event %" PRIu64 ", signal loss", name, analysis_image_count, event->Id() );
|
||||||
closeEvent();
|
closeEvent();
|
||||||
last_section_mod = 0;
|
last_section_mod = 0;
|
||||||
}
|
}
|
||||||
|
@ -1757,7 +1769,7 @@ bool Monitor::Analyse() {
|
||||||
alarm_cause = cause+" "+alarm_cause;
|
alarm_cause = cause+" "+alarm_cause;
|
||||||
strncpy( shared_data->alarm_cause,alarm_cause.c_str() , sizeof(shared_data->alarm_cause) );
|
strncpy( shared_data->alarm_cause,alarm_cause.c_str() , sizeof(shared_data->alarm_cause) );
|
||||||
video_store_data->recording = event->StartTime();
|
video_store_data->recording = event->StartTime();
|
||||||
Info( "%s: %03d - Opening new event %llu, section start", name, analysis_image_count, event->Id() );
|
Info( "%s: %03d - Opening new event %" PRIu64 ", section start", name, analysis_image_count, event->Id() );
|
||||||
/* To prevent cancelling out an existing alert\prealarm\alarm state */
|
/* To prevent cancelling out an existing alert\prealarm\alarm state */
|
||||||
if ( state == IDLE ) {
|
if ( state == IDLE ) {
|
||||||
shared_data->state = state = TAPE;
|
shared_data->state = state = TAPE;
|
||||||
|
@ -1798,15 +1810,15 @@ bool Monitor::Analyse() {
|
||||||
last_alarm_count = analysis_image_count;
|
last_alarm_count = analysis_image_count;
|
||||||
} else { // no score?
|
} else { // no score?
|
||||||
if ( state == ALARM ) {
|
if ( state == ALARM ) {
|
||||||
Info( "%s: %03d - Gone into alert state", name, analysis_image_count );
|
Info("%s: %03d - Gone into alert state", name, analysis_image_count );
|
||||||
shared_data->state = state = ALERT;
|
shared_data->state = state = ALERT;
|
||||||
} else if ( state == ALERT ) {
|
} else if ( state == ALERT ) {
|
||||||
if ( analysis_image_count-last_alarm_count > post_event_count ) {
|
if ( analysis_image_count-last_alarm_count > post_event_count ) {
|
||||||
Info( "%s: %03d - Left alarm state (%llu) - %d(%d) images", name, analysis_image_count, event->Id(), event->Frames(), event->AlarmFrames() );
|
Info("%s: %03d - Left alarm state (%" PRIu64 ") - %d(%d) images", name, analysis_image_count, event->Id(), event->Frames(), event->AlarmFrames() );
|
||||||
//if ( function != MOCORD || event_close_mode == CLOSE_ALARM || event->Cause() == SIGNAL_CAUSE )
|
//if ( function != MOCORD || event_close_mode == CLOSE_ALARM || event->Cause() == SIGNAL_CAUSE )
|
||||||
if ( (function != RECORD && function != MOCORD ) || event_close_mode == CLOSE_ALARM ) {
|
if ( (function != RECORD && function != MOCORD ) || event_close_mode == CLOSE_ALARM ) {
|
||||||
shared_data->state = state = IDLE;
|
shared_data->state = state = IDLE;
|
||||||
Info( "%s: %03d - Closing event %llu, alarm end%s", name, analysis_image_count, event->Id(), (function==MOCORD)?", section truncated":"" );
|
Info("%s: %03d - Closing event %" PRIu64 ", alarm end%s", name, analysis_image_count, event->Id(), (function==MOCORD)?", section truncated":"" );
|
||||||
closeEvent();
|
closeEvent();
|
||||||
} else {
|
} else {
|
||||||
shared_data->state = state = TAPE;
|
shared_data->state = state = TAPE;
|
||||||
|
@ -1881,7 +1893,7 @@ bool Monitor::Analyse() {
|
||||||
} else {
|
} else {
|
||||||
Debug(3, "trigger == off");
|
Debug(3, "trigger == off");
|
||||||
if ( event ) {
|
if ( event ) {
|
||||||
Info( "%s: %03d - Closing event %llu, trigger off", name, analysis_image_count, event->Id() );
|
Info("%s: %03d - Closing event %" PRIu64 ", trigger off", name, analysis_image_count, event->Id());
|
||||||
closeEvent();
|
closeEvent();
|
||||||
}
|
}
|
||||||
shared_data->state = state = IDLE;
|
shared_data->state = state = IDLE;
|
||||||
|
@ -1935,7 +1947,7 @@ void Monitor::Reload() {
|
||||||
Debug(1, "Reloading monitor %s", name);
|
Debug(1, "Reloading monitor %s", name);
|
||||||
|
|
||||||
if ( event ) {
|
if ( event ) {
|
||||||
Info("%s: %03d - Closing event %llu, reloading", name, image_count, event->Id());
|
Info( "%s: %03d - Closing event %" PRIu64 ", reloading", name, image_count, event->Id() );
|
||||||
closeEvent();
|
closeEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2001,8 +2013,8 @@ void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) {
|
||||||
if ( dest_ptr != link_id_str ) {
|
if ( dest_ptr != link_id_str ) {
|
||||||
*dest_ptr = '\0';
|
*dest_ptr = '\0';
|
||||||
unsigned int link_id = atoi(link_id_str);
|
unsigned int link_id = atoi(link_id_str);
|
||||||
if ( link_id > 0 && link_id != id) {
|
if ( link_id > 0 && link_id != id ) {
|
||||||
Debug( 3, "Found linked monitor id %d", link_id );
|
Debug(3, "Found linked monitor id %d", link_id);
|
||||||
int j;
|
int j;
|
||||||
for ( j = 0; j < n_link_ids; j++ ) {
|
for ( j = 0; j < n_link_ids; j++ ) {
|
||||||
if ( link_ids[j] == link_id )
|
if ( link_ids[j] == link_id )
|
||||||
|
@ -2022,15 +2034,16 @@ void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ( n_link_ids > 0 ) {
|
if ( n_link_ids > 0 ) {
|
||||||
Debug( 1, "Linking to %d monitors", n_link_ids );
|
Debug(1, "Linking to %d monitors", n_link_ids);
|
||||||
linked_monitors = new MonitorLink *[n_link_ids];
|
linked_monitors = new MonitorLink *[n_link_ids];
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for ( int i = 0; i < n_link_ids; i++ ) {
|
for ( int i = 0; i < n_link_ids; i++ ) {
|
||||||
Debug(1, "Checking linked monitor %d", link_ids[i]);
|
Debug(1, "Checking linked monitor %d", link_ids[i]);
|
||||||
|
|
||||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
|
||||||
snprintf(sql, sizeof(sql), "SELECT Id, Name FROM Monitors WHERE Id = %d AND Function != 'None' AND Function != 'Monitor' AND Enabled = 1", link_ids[i] );
|
|
||||||
db_mutex.lock();
|
db_mutex.lock();
|
||||||
|
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||||
|
db_mutex.lock();
|
||||||
|
snprintf(sql, sizeof(sql), "SELECT Id, Name FROM Monitors WHERE Id = %d AND Function != 'None' AND Function != 'Monitor' AND Enabled = 1", link_ids[i] );
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
if ( mysql_query(&dbconn, sql) ) {
|
||||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||||
db_mutex.unlock();
|
db_mutex.unlock();
|
||||||
|
@ -2052,11 +2065,11 @@ void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) {
|
||||||
Warning("Can't link to monitor %d, invalid id, function or not enabled", link_ids[i]);
|
Warning("Can't link to monitor %d, invalid id, function or not enabled", link_ids[i]);
|
||||||
}
|
}
|
||||||
mysql_free_result(result);
|
mysql_free_result(result);
|
||||||
} // end foreach n_link_id
|
} // end foreach link_id
|
||||||
n_linked_monitors = count;
|
n_linked_monitors = count;
|
||||||
} // end if n_link_ids > 0
|
} // end if has link_ids
|
||||||
}
|
} // end if p_linked_monitors
|
||||||
}
|
} // end void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors)
|
||||||
|
|
||||||
int Monitor::LoadMonitors(std::string sql, Monitor **&monitors, Purpose purpose) {
|
int Monitor::LoadMonitors(std::string sql, Monitor **&monitors, Purpose purpose) {
|
||||||
|
|
||||||
|
@ -2131,7 +2144,6 @@ int Monitor::LoadFfmpegMonitors(const char *file, Monitor **&monitors, Purpose p
|
||||||
}
|
}
|
||||||
#endif // HAVE_LIBAVFORMAT
|
#endif // HAVE_LIBAVFORMAT
|
||||||
|
|
||||||
|
|
||||||
/* Returns 0 on success, even if no new images are available (transient error)
|
/* Returns 0 on success, even if no new images are available (transient error)
|
||||||
* Returns -1 on failure.
|
* Returns -1 on failure.
|
||||||
*/
|
*/
|
||||||
|
@ -2285,7 +2297,7 @@ int Monitor::Capture() {
|
||||||
capture_image->Flip( orientation==FLIP_HORI );
|
capture_image->Flip( orientation==FLIP_HORI );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} // end if have rotation
|
||||||
|
|
||||||
if ( privacy_bitmask )
|
if ( privacy_bitmask )
|
||||||
capture_image->MaskPrivacy( privacy_bitmask );
|
capture_image->MaskPrivacy( privacy_bitmask );
|
||||||
|
@ -2294,27 +2306,32 @@ int Monitor::Capture() {
|
||||||
TimestampImage( capture_image, packet->timestamp );
|
TimestampImage( capture_image, packet->timestamp );
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_data->signal = CheckSignal(capture_image);
|
shared_data->signal = signal_check_points ? CheckSignal(capture_image) : true;
|
||||||
shared_data->last_write_index = index;
|
shared_data->last_write_index = index;
|
||||||
shared_data->last_write_time = image_buffer[index].timestamp->tv_sec;
|
shared_data->last_write_time = image_buffer[index].timestamp->tv_sec;
|
||||||
image_count++;
|
image_count++;
|
||||||
packet->unlock();
|
packet->unlock();
|
||||||
|
|
||||||
if ( fps_report_interval && !(image_count%fps_report_interval) ) {
|
if ( fps_report_interval && ( !(image_count%fps_report_interval) || image_count == 5 ) ) {
|
||||||
time_t now = image_buffer[index].timestamp->tv_sec;
|
time_t now = image_buffer[index].timestamp->tv_sec;
|
||||||
// If we are too fast, we get div by zero. This seems to happen in the case of audio packets.
|
// If we are too fast, we get div by zero. This seems to happen in the case of audio packets.
|
||||||
if ( now != last_fps_time ) {
|
if ( now != last_fps_time ) {
|
||||||
// # of images per interval / the amount of time it took
|
// # of images per interval / the amount of time it took
|
||||||
double new_capture_fps = double(fps_report_interval)/(now-last_fps_time);
|
double new_capture_fps = double((image_count < fps_report_interval ? image_count : fps_report_interval))/(now-last_fps_time);
|
||||||
|
unsigned int new_camera_bytes = camera->Bytes();
|
||||||
|
unsigned int new_capture_bandwidth = (new_camera_bytes - last_camera_bytes)/(now-last_fps_time);
|
||||||
|
last_camera_bytes = new_camera_bytes;
|
||||||
//Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time );
|
//Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time );
|
||||||
//Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps );
|
//Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps );
|
||||||
Info("%s: %d - Capturing at %.2lf fps", name, image_count, new_capture_fps);
|
Info("%s: images:%d - Capturing at %.2lf fps, capturing bandwidth %ubytes/sec", name, image_count, new_capture_fps, new_capture_bandwidth);
|
||||||
if ( new_capture_fps != capture_fps ) {
|
if ( new_capture_fps != capture_fps ) {
|
||||||
capture_fps = new_capture_fps;
|
capture_fps = new_capture_fps;
|
||||||
last_fps_time = now;
|
last_fps_time = now;
|
||||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||||
db_mutex.lock();
|
db_mutex.lock();
|
||||||
snprintf(sql, sizeof(sql), "INSERT INTO Monitor_Status (MonitorId,CaptureFPS) VALUES (%d, %.2lf) ON DUPLICATE KEY UPDATE CaptureFPS = %.2lf", id, capture_fps, capture_fps);
|
snprintf(sql, sizeof(sql),
|
||||||
|
"INSERT INTO Monitor_Status (MonitorId,CaptureFPS,CaptureBandwidth) VALUES (%d, %.2lf,%u) ON DUPLICATE KEY UPDATE CaptureFPS = %.2lf, CaptureBandwidth=%u",
|
||||||
|
id, capture_fps, new_capture_bandwidth, capture_fps, new_capture_bandwidth);
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
if ( mysql_query(&dbconn, sql) ) {
|
||||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||||
}
|
}
|
||||||
|
@ -2330,6 +2347,7 @@ int Monitor::Capture() {
|
||||||
} // end if result
|
} // end if result
|
||||||
} // end if deinterlacing
|
} // end if deinterlacing
|
||||||
|
|
||||||
|
|
||||||
// Icon: I'm not sure these should be here. They have nothing to do with capturing
|
// Icon: I'm not sure these should be here. They have nothing to do with capturing
|
||||||
if ( shared_data->action & GET_SETTINGS ) {
|
if ( shared_data->action & GET_SETTINGS ) {
|
||||||
shared_data->brightness = camera->Brightness();
|
shared_data->brightness = camera->Brightness();
|
||||||
|
@ -2647,6 +2665,7 @@ int Monitor::PrimeCapture() {
|
||||||
|
|
||||||
int Monitor::PreCapture() const { return camera->PreCapture(); }
|
int Monitor::PreCapture() const { return camera->PreCapture(); }
|
||||||
int Monitor::PostCapture() const { return camera->PostCapture() ; }
|
int Monitor::PostCapture() const { return camera->PostCapture() ; }
|
||||||
|
int Monitor::Close() { return camera->Close(); };
|
||||||
Monitor::Orientation Monitor::getOrientation() const { return orientation; }
|
Monitor::Orientation Monitor::getOrientation() const { return orientation; }
|
||||||
|
|
||||||
// Wait for camera to get an image, and then assign it as the base reference image. So this should be done as the first task in the analysis thread startup.
|
// Wait for camera to get an image, and then assign it as the base reference image. So this should be done as the first task in the analysis thread startup.
|
||||||
|
|
|
@ -117,38 +117,38 @@ protected:
|
||||||
uint32_t last_write_index; /* +4 */
|
uint32_t last_write_index; /* +4 */
|
||||||
uint32_t last_read_index; /* +8 */
|
uint32_t last_read_index; /* +8 */
|
||||||
uint32_t state; /* +12 */
|
uint32_t state; /* +12 */
|
||||||
uint32_t last_event_id; /* +16 */
|
uint64_t last_event_id; /* +16 */
|
||||||
uint32_t action; /* +20 */
|
uint32_t action; /* +24 */
|
||||||
int32_t brightness; /* +24 */
|
int32_t brightness; /* +28 */
|
||||||
int32_t hue; /* +28 */
|
int32_t hue; /* +32 */
|
||||||
int32_t colour; /* +32 */
|
int32_t colour; /* +36 */
|
||||||
int32_t contrast; /* +36 */
|
int32_t contrast; /* +40 */
|
||||||
int32_t alarm_x; /* +40 */
|
int32_t alarm_x; /* +44 */
|
||||||
int32_t alarm_y; /* +44 */
|
int32_t alarm_y; /* +48 */
|
||||||
uint8_t valid; /* +48 */
|
uint8_t valid; /* +52 */
|
||||||
uint8_t active; /* +49 */
|
uint8_t active; /* +53 */
|
||||||
uint8_t signal; /* +50 */
|
uint8_t signal; /* +54 */
|
||||||
uint8_t format; /* +51 */
|
uint8_t format; /* +55 */
|
||||||
uint32_t imagesize; /* +52 */
|
uint32_t imagesize; /* +56 */
|
||||||
uint32_t epadding1; /* +56 */
|
uint32_t epadding1; /* +60 */
|
||||||
uint32_t epadding2; /* +60 */
|
uint32_t epadding2; /* +64 */
|
||||||
/*
|
/*
|
||||||
** This keeps 32bit time_t and 64bit time_t identical and compatible as long as time is before 2038.
|
** This keeps 32bit time_t and 64bit time_t identical and compatible as long as time is before 2038.
|
||||||
** Shared memory layout should be identical for both 32bit and 64bit and is multiples of 16.
|
** Shared memory layout should be identical for both 32bit and 64bit and is multiples of 16.
|
||||||
*/
|
*/
|
||||||
union { /* +64 */
|
union { /* +68 */
|
||||||
time_t startup_time; /* When the zmc process started. zmwatch uses this to see how long the process has been running without getting any images */
|
time_t startup_time; /* When the zmc process started. zmwatch uses this to see how long the process has been running without getting any images */
|
||||||
uint64_t extrapad1;
|
uint64_t extrapad1;
|
||||||
};
|
};
|
||||||
union { /* +72 */
|
union { /* +76 */
|
||||||
time_t last_write_time;
|
time_t last_write_time;
|
||||||
uint64_t extrapad2;
|
uint64_t extrapad2;
|
||||||
};
|
};
|
||||||
union { /* +80 */
|
union { /* +84 */
|
||||||
time_t last_read_time;
|
time_t last_read_time;
|
||||||
uint64_t extrapad3;
|
uint64_t extrapad3;
|
||||||
};
|
};
|
||||||
uint8_t control_state[256]; /* +88 */
|
uint8_t control_state[256]; /* +92 */
|
||||||
|
|
||||||
char alarm_cause[256];
|
char alarm_cause[256];
|
||||||
|
|
||||||
|
@ -299,13 +299,16 @@ protected:
|
||||||
int fps_report_interval; // How many images should be captured/processed between reporting the current FPS
|
int fps_report_interval; // How many images should be captured/processed between reporting the current FPS
|
||||||
int ref_blend_perc; // Percentage of new image going into reference image.
|
int ref_blend_perc; // Percentage of new image going into reference image.
|
||||||
int alarm_ref_blend_perc; // Percentage of new image going into reference image during alarm.
|
int alarm_ref_blend_perc; // Percentage of new image going into reference image during alarm.
|
||||||
bool track_motion; // Whether this monitor tries to track detected motion
|
bool track_motion; // Whether this monitor tries to track detected motion
|
||||||
|
int signal_check_points; // Number of points in the image to check for signal
|
||||||
Rgb signal_check_colour; // The colour that the camera will emit when no video signal detected
|
Rgb signal_check_colour; // The colour that the camera will emit when no video signal detected
|
||||||
bool embed_exif; // Whether to embed Exif data into each image frame or not
|
bool embed_exif; // Whether to embed Exif data into each image frame or not
|
||||||
|
|
||||||
double capture_fps; // Current capturing fps
|
double capture_fps; // Current capturing fps
|
||||||
double analysis_fps; // Current analysis fps
|
double analysis_fps; // Current analysis fps
|
||||||
|
|
||||||
|
unsigned int last_camera_bytes;
|
||||||
|
|
||||||
Image delta_image;
|
Image delta_image;
|
||||||
Image ref_image;
|
Image ref_image;
|
||||||
Image alarm_image; // Used in creating analysis images, will be initialized in Analysis
|
Image alarm_image; // Used in creating analysis images, will be initialized in Analysis
|
||||||
|
@ -339,8 +342,6 @@ protected:
|
||||||
#endif // ZM_MEM_MAPPED
|
#endif // ZM_MEM_MAPPED
|
||||||
off_t mem_size;
|
off_t mem_size;
|
||||||
unsigned char *mem_ptr;
|
unsigned char *mem_ptr;
|
||||||
Storage *storage;
|
|
||||||
|
|
||||||
SharedData *shared_data;
|
SharedData *shared_data;
|
||||||
TriggerData *trigger_data;
|
TriggerData *trigger_data;
|
||||||
VideoStoreData *video_store_data;
|
VideoStoreData *video_store_data;
|
||||||
|
@ -353,7 +354,8 @@ protected:
|
||||||
int video_stream_id; // will be filled in PrimeCapture
|
int video_stream_id; // will be filled in PrimeCapture
|
||||||
|
|
||||||
Camera *camera;
|
Camera *camera;
|
||||||
Event *event;
|
Event *event;
|
||||||
|
Storage *storage;
|
||||||
|
|
||||||
int n_zones;
|
int n_zones;
|
||||||
Zone **zones;
|
Zone **zones;
|
||||||
|
@ -487,6 +489,7 @@ public:
|
||||||
int PreCapture() const;
|
int PreCapture() const;
|
||||||
int Capture();
|
int Capture();
|
||||||
int PostCapture() const;
|
int PostCapture() const;
|
||||||
|
int Close();
|
||||||
|
|
||||||
void CheckAction();
|
void CheckAction();
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "zm_rtsp_auth.h"
|
#include "zm_rtsp_auth.h"
|
||||||
|
|
||||||
#include "zm_mem_utils.h"
|
#include "zm_mem_utils.h"
|
||||||
|
#include "zm_signal.h"
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
@ -185,24 +186,24 @@ int RemoteCameraHttp::ReadData( Buffer &buffer, unsigned int bytes_expected ) {
|
||||||
|
|
||||||
struct timeval temp_timeout = timeout;
|
struct timeval temp_timeout = timeout;
|
||||||
|
|
||||||
int n_found = select( sd+1, &rfds, NULL, NULL, &temp_timeout );
|
int n_found = select(sd+1, &rfds, NULL, NULL, &temp_timeout);
|
||||||
if( n_found == 0 ) {
|
if( n_found == 0 ) {
|
||||||
Debug( 4, "Select timed out timeout was %d secs %d usecs", temp_timeout.tv_sec, temp_timeout.tv_usec );
|
Debug( 1, "Select timed out timeout was %d secs %d usecs", temp_timeout.tv_sec, temp_timeout.tv_usec );
|
||||||
int error = 0;
|
int error = 0;
|
||||||
socklen_t len = sizeof (error);
|
socklen_t len = sizeof (error);
|
||||||
int retval = getsockopt (sd, SOL_SOCKET, SO_ERROR, &error, &len);
|
int retval = getsockopt (sd, SOL_SOCKET, SO_ERROR, &error, &len);
|
||||||
if(retval != 0 ) {
|
if(retval != 0 ) {
|
||||||
Debug( 1, "error getting socket error code %s", strerror(retval) );
|
Debug( 1, "error getting socket error code %s", strerror(retval) );
|
||||||
}
|
}
|
||||||
if (error != 0) {
|
if (error != 0 ) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// Why are we disconnecting? It's just a timeout, meaning that data wasn't available.
|
// Why are we disconnecting? It's just a timeout, meaning that data wasn't available.
|
||||||
//Disconnect();
|
//Disconnect();
|
||||||
return( 0 );
|
return 0;
|
||||||
} else if ( n_found < 0) {
|
} else if ( n_found < 0) {
|
||||||
Error( "Select error: %s", strerror(errno) );
|
Error("Select error: %s", strerror(errno));
|
||||||
return( -1 );
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int total_bytes_to_read = 0;
|
unsigned int total_bytes_to_read = 0;
|
||||||
|
@ -298,13 +299,14 @@ int RemoteCameraHttp::GetResponse() {
|
||||||
static RegExpr *content_length_expr = 0;
|
static RegExpr *content_length_expr = 0;
|
||||||
static RegExpr *content_type_expr = 0;
|
static RegExpr *content_type_expr = 0;
|
||||||
|
|
||||||
while ( ! ( buffer_len = ReadData( buffer ) ) ) {
|
while ( !( buffer_len = ReadData(buffer) ) && !zm_terminate ) {
|
||||||
Debug(4, "Timeout waiting for REGEXP HEADER");
|
Debug(4, "Timeout waiting for REGEXP HEADER");
|
||||||
}
|
}
|
||||||
if ( buffer_len < 0 ) {
|
if ( buffer_len < 0 ) {
|
||||||
Error( "Unable to read header data" );
|
Error( "Unable to read header data" );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
bytes += buffer_len;
|
||||||
if ( !header_expr )
|
if ( !header_expr )
|
||||||
header_expr = new RegExpr( "^(.+?\r?\n\r?\n)", PCRE_DOTALL );
|
header_expr = new RegExpr( "^(.+?\r?\n\r?\n)", PCRE_DOTALL );
|
||||||
if ( header_expr->Match( (char*)buffer, buffer.size() ) == 2 ) {
|
if ( header_expr->Match( (char*)buffer, buffer.size() ) == 2 ) {
|
||||||
|
@ -449,13 +451,14 @@ int RemoteCameraHttp::GetResponse() {
|
||||||
state = CONTENT;
|
state = CONTENT;
|
||||||
} else {
|
} else {
|
||||||
Debug( 3, "Unable to extract subheader from stream, retrying" );
|
Debug( 3, "Unable to extract subheader from stream, retrying" );
|
||||||
while ( ! ( buffer_len = ReadData( buffer ) ) ) {
|
while ( !( buffer_len = ReadData(buffer) ) && !zm_terminate ) {
|
||||||
Debug(4, "Timeout waiting to extract subheader");
|
Debug(4, "Timeout waiting to extract subheader");
|
||||||
}
|
}
|
||||||
if ( buffer_len < 0 ) {
|
if ( buffer_len < 0 ) {
|
||||||
Error( "Unable to extract subheader data" );
|
Error( "Unable to extract subheader data" );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
bytes += buffer_len;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -480,23 +483,27 @@ int RemoteCameraHttp::GetResponse() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( content_length ) {
|
if ( content_length ) {
|
||||||
while ( (long)buffer.size() < content_length ) {
|
while ( ((long)buffer.size() < content_length ) && ! zm_terminate ) {
|
||||||
Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_length );
|
Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_length );
|
||||||
if ( ReadData( buffer ) < 0 ) {
|
int bytes_read = ReadData( buffer );
|
||||||
|
|
||||||
|
if ( bytes_read < 0 ) {
|
||||||
Error( "Unable to read content" );
|
Error( "Unable to read content" );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
bytes += bytes_read;
|
||||||
}
|
}
|
||||||
Debug( 3, "Got end of image by length, content-length = %d", content_length );
|
Debug( 3, "Got end of image by length, content-length = %d", content_length );
|
||||||
} else {
|
} else {
|
||||||
while ( !content_length ) {
|
while ( !content_length ) {
|
||||||
while ( ! ( buffer_len = ReadData( buffer ) ) ) {
|
while ( !( buffer_len = ReadData(buffer) ) && !zm_terminate ) {
|
||||||
Debug(4, "Timeout waiting for content");
|
Debug(4, "Timeout waiting for content");
|
||||||
}
|
}
|
||||||
if ( buffer_len < 0 ) {
|
if ( buffer_len < 0 ) {
|
||||||
Error( "Unable to read content" );
|
Error( "Unable to read content" );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
bytes += buffer_len;
|
||||||
static RegExpr *content_expr = 0;
|
static RegExpr *content_expr = 0;
|
||||||
if ( mode == MULTI_IMAGE ) {
|
if ( mode == MULTI_IMAGE ) {
|
||||||
if ( !content_expr ) {
|
if ( !content_expr ) {
|
||||||
|
@ -603,13 +610,14 @@ int RemoteCameraHttp::GetResponse() {
|
||||||
}
|
}
|
||||||
case HEADERCONT :
|
case HEADERCONT :
|
||||||
{
|
{
|
||||||
while ( ! ( buffer_len = ReadData( buffer ) ) ) {
|
while ( !( buffer_len = ReadData(buffer) ) && !zm_terminate ) {
|
||||||
Debug(4, "Timeout waiting for HEADERCONT");
|
Debug(4, "Timeout waiting for HEADERCONT");
|
||||||
}
|
}
|
||||||
if ( buffer_len < 0 ) {
|
if ( buffer_len < 0 ) {
|
||||||
Error( "Unable to read header" );
|
Error( "Unable to read header" );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
bytes += buffer_len;
|
||||||
|
|
||||||
char *crlf = 0;
|
char *crlf = 0;
|
||||||
char *header_ptr = (char *)buffer;
|
char *header_ptr = (char *)buffer;
|
||||||
|
@ -888,13 +896,14 @@ int RemoteCameraHttp::GetResponse() {
|
||||||
state = CONTENT;
|
state = CONTENT;
|
||||||
} else {
|
} else {
|
||||||
Debug( 3, "Unable to extract subheader from stream, retrying" );
|
Debug( 3, "Unable to extract subheader from stream, retrying" );
|
||||||
while ( ! ( buffer_len = ReadData( buffer ) ) ) {
|
while ( !( buffer_len = ReadData(buffer) ) &&!zm_terminate ) {
|
||||||
Debug(1, "Timeout waiting to extra subheader non regexp");
|
Debug(1, "Timeout waiting to extra subheader non regexp");
|
||||||
}
|
}
|
||||||
if ( buffer_len < 0 ) {
|
if ( buffer_len < 0 ) {
|
||||||
Error( "Unable to read subheader" );
|
Error( "Unable to read subheader" );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
bytes += buffer_len;
|
||||||
state = SUBHEADERCONT;
|
state = SUBHEADERCONT;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -927,18 +936,19 @@ int RemoteCameraHttp::GetResponse() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( content_length ) {
|
if ( content_length ) {
|
||||||
while ( (long)buffer.size() < content_length ) {
|
while ( ( (long)buffer.size() < content_length ) && ! zm_terminate ) {
|
||||||
//int buffer_len = ReadData( buffer, content_length-buffer.size() );
|
|
||||||
Debug(4, "getting more data");
|
Debug(4, "getting more data");
|
||||||
if ( ReadData( buffer ) < 0 ) {
|
int bytes_read = ReadData(buffer);
|
||||||
Error( "Unable to read content" );
|
if ( bytes_read < 0 ) {
|
||||||
return( -1 );
|
Error("Unable to read content");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
bytes += bytes_read;
|
||||||
}
|
}
|
||||||
Debug( 3, "Got end of image by length, content-length = %d", content_length );
|
Debug( 3, "Got end of image by length, content-length = %d", content_length );
|
||||||
} else {
|
} else {
|
||||||
// Read until we find the end of image or the stream closes.
|
// Read until we find the end of image or the stream closes.
|
||||||
while ( !content_length ) {
|
while ( !content_length && !zm_terminate ) {
|
||||||
Debug(4, "!content_length, ReadData");
|
Debug(4, "!content_length, ReadData");
|
||||||
buffer_len = ReadData( buffer );
|
buffer_len = ReadData( buffer );
|
||||||
if ( buffer_len < 0 )
|
if ( buffer_len < 0 )
|
||||||
|
@ -946,6 +956,7 @@ int RemoteCameraHttp::GetResponse() {
|
||||||
Error( "Unable to read content" );
|
Error( "Unable to read content" );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
bytes += buffer_len;
|
||||||
int buffer_size = buffer.size();
|
int buffer_size = buffer.size();
|
||||||
if ( buffer_len ) {
|
if ( buffer_len ) {
|
||||||
// Got some data
|
// Got some data
|
||||||
|
|
|
@ -72,7 +72,8 @@ public:
|
||||||
int PreCapture();
|
int PreCapture();
|
||||||
int Capture( ZMPacket &p );
|
int Capture( ZMPacket &p );
|
||||||
int PostCapture();
|
int PostCapture();
|
||||||
AVStream* get_VideoStream();
|
AVStream* get_VideoStream();
|
||||||
|
int Close() { return 0; };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ZM_REMOTE_CAMERA_HTTP_H
|
#endif // ZM_REMOTE_CAMERA_HTTP_H
|
||||||
|
|
|
@ -189,13 +189,14 @@ int RemoteCameraNVSocket::Capture( ZMPacket &zm_packet ) {
|
||||||
Warning( "Unable to capture image, retrying" );
|
Warning( "Unable to capture image, retrying" );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if ( Read( sd, buffer, imagesize ) < imagesize ) {
|
int bytes_read = Read(sd, buffer, imagesize);
|
||||||
Warning( "Unable to capture image, retrying" );
|
if ( (bytes_read < 0) || ( (unsigned int)bytes_read < imagesize ) ) {
|
||||||
|
Warning("Unable to capture image, retrying");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uint32_t end;
|
uint32_t end;
|
||||||
if ( Read(sd, (char *) &end , sizeof(end)) < 0 ) {
|
if ( Read(sd, (char *) &end , sizeof(end)) < 0 ) {
|
||||||
Warning( "Unable to capture image, retrying" );
|
Warning("Unable to capture image, retrying");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if ( end != 0xFFFFFFFF) {
|
if ( end != 0xFFFFFFFF) {
|
||||||
|
@ -203,7 +204,7 @@ int RemoteCameraNVSocket::Capture( ZMPacket &zm_packet ) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
zm_packet.image->Assign( width, height, colours, subpixelorder, buffer, imagesize );
|
zm_packet.image->Assign(width, height, colours, subpixelorder, buffer, imagesize);
|
||||||
zm_packet.keyframe = 1;
|
zm_packet.keyframe = 1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,8 @@ public:
|
||||||
int PrimeCapture();
|
int PrimeCapture();
|
||||||
int Capture( ZMPacket &p );
|
int Capture( ZMPacket &p );
|
||||||
int PostCapture();
|
int PostCapture();
|
||||||
AVStream* get_VideoStream();
|
AVStream* get_VideoStream();
|
||||||
|
int Close() { return 0; };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ZM_REMOTE_CAMERA_NVSOCKET_H
|
#endif // ZM_REMOTE_CAMERA_NVSOCKET_H
|
||||||
|
|
|
@ -85,6 +85,7 @@ public:
|
||||||
int PreCapture();
|
int PreCapture();
|
||||||
int Capture( ZMPacket &p );
|
int Capture( ZMPacket &p );
|
||||||
int PostCapture();
|
int PostCapture();
|
||||||
|
int Close() { return 0; };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ZM_REMOTE_CAMERA_RTSP_H
|
#endif // ZM_REMOTE_CAMERA_RTSP_H
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
#define __STDC_FORMAT_MACROS 1
|
#define __STDC_FORMAT_MACROS 1
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <cinttypes>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
348
src/zm_zone.cpp
348
src/zm_zone.cpp
|
@ -108,14 +108,12 @@ void Zone::Setup(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Is this not a problem? If you had two zones for a monitor.. then these would conflict. You would only get 1 dump file
|
|
||||||
if ( config.record_diag_images ) {
|
if ( config.record_diag_images ) {
|
||||||
static char diag_path[PATH_MAX] = "";
|
snprintf(diag_path, sizeof(diag_path), "%s/diag-%d-poly.jpg", monitor->getStorage()->Path(), id);
|
||||||
if ( ! diag_path[0] ) {
|
pg_image->WriteJpeg(diag_path);
|
||||||
snprintf( diag_path, sizeof(diag_path), "%s/diag-%d-poly.jpg", monitor->getStorage()->Path(), id);
|
} else {
|
||||||
}
|
diag_path[0] = 0;
|
||||||
pg_image->WriteJpeg( diag_path );
|
}
|
||||||
}
|
|
||||||
} // end Zone::Setup
|
} // end Zone::Setup
|
||||||
|
|
||||||
Zone::~Zone() {
|
Zone::~Zone() {
|
||||||
|
@ -127,21 +125,22 @@ Zone::~Zone() {
|
||||||
|
|
||||||
void Zone::RecordStats( const Event *event ) {
|
void Zone::RecordStats( const Event *event ) {
|
||||||
static char sql[ZM_SQL_MED_BUFSIZ];
|
static char sql[ZM_SQL_MED_BUFSIZ];
|
||||||
snprintf( sql, sizeof(sql), "insert into Stats set MonitorId=%d, ZoneId=%d, EventId=%d, FrameId=%d, PixelDiff=%d, AlarmPixels=%d, FilterPixels=%d, BlobPixels=%d, Blobs=%d, MinBlobSize=%d, MaxBlobSize=%d, MinX=%d, MinY=%d, MaxX=%d, MaxY=%d, Score=%d", monitor->Id(), id, event->Id(), event->Frames()+1, pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, min_blob_size, max_blob_size, alarm_box.LoX(), alarm_box.LoY(), alarm_box.HiX(), alarm_box.HiY(), score );
|
|
||||||
db_mutex.lock();
|
db_mutex.lock();
|
||||||
if ( mysql_query( &dbconn, sql ) ) {
|
snprintf(sql, sizeof(sql),
|
||||||
Error( "Can't insert event stats: %s", mysql_error( &dbconn ) );
|
"INSERT INTO Stats SET MonitorId=%d, ZoneId=%d, EventId=%" PRIu64 ", FrameId=%d, PixelDiff=%d, AlarmPixels=%d, FilterPixels=%d, BlobPixels=%d, Blobs=%d, MinBlobSize=%d, MaxBlobSize=%d, MinX=%d, MinY=%d, MaxX=%d, MaxY=%d, Score=%d",
|
||||||
|
monitor->Id(), id, event->Id(), event->Frames()+1, pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, min_blob_size, max_blob_size, alarm_box.LoX(), alarm_box.LoY(), alarm_box.HiX(), alarm_box.HiY(), score
|
||||||
|
);
|
||||||
|
if ( mysql_query(&dbconn, sql) ) {
|
||||||
|
Error("Can't insert event stats: %s", mysql_error(&dbconn));
|
||||||
}
|
}
|
||||||
db_mutex.unlock();
|
db_mutex.unlock();
|
||||||
} // end void Zone::RecordStats( const Event *event )
|
} // end void Zone::RecordStats( const Event *event )
|
||||||
|
|
||||||
bool Zone::CheckOverloadCount() {
|
bool Zone::CheckOverloadCount() {
|
||||||
Info("Overloaded count: %d, Overloaded frames: %d", overload_count, overload_frames);
|
|
||||||
if ( overload_count ) {
|
if ( overload_count ) {
|
||||||
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);
|
||||||
Debug( 4, "In overload mode, %d frames of %d remaining", overload_count, overload_frames );
|
|
||||||
overload_count--;
|
overload_count--;
|
||||||
return( false );
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} // end bool Zone::CheckOverloadCount()
|
} // end bool Zone::CheckOverloadCount()
|
||||||
|
@ -180,28 +179,27 @@ int Zone::GetExtendAlarmFrames() {
|
||||||
} // end int Zone::GetExtendAlarmFrames()
|
} // end int Zone::GetExtendAlarmFrames()
|
||||||
|
|
||||||
bool Zone::CheckExtendAlarmCount() {
|
bool Zone::CheckExtendAlarmCount() {
|
||||||
Info( "ExtendAlarm count: %d, ExtendAlarm frames: %d", extend_alarm_count, extend_alarm_frames );
|
Info("ExtendAlarm count: %d, ExtendAlarm frames: %d", extend_alarm_count, extend_alarm_frames);
|
||||||
if ( extend_alarm_count ) {
|
if ( extend_alarm_count ) {
|
||||||
Debug( 3, "In extend mode, %d frames of %d remaining", extend_alarm_count, extend_alarm_frames );
|
Debug(3, "In extend mode, %d frames of %d remaining", extend_alarm_count, extend_alarm_frames);
|
||||||
extend_alarm_count--;
|
extend_alarm_count--;
|
||||||
return( true );
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} // end bool Zone::CheckExtendAlarmCount
|
} // end bool Zone::CheckExtendAlarmCount
|
||||||
|
|
||||||
bool Zone::CheckAlarms( const Image *delta_image ) {
|
bool Zone::CheckAlarms(const Image *delta_image) {
|
||||||
ResetStats();
|
ResetStats();
|
||||||
|
|
||||||
if ( overload_count ) {
|
if ( overload_count ) {
|
||||||
Info( "In overload mode, %d frames of %d remaining", overload_count, overload_frames );
|
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--;
|
overload_count--;
|
||||||
return( false );
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete image;
|
delete image;
|
||||||
// Get the difference 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();
|
int diff_width = diff_image->Width();
|
||||||
uint8_t* diff_buff = (uint8_t*)diff_image->Buffer();
|
uint8_t* diff_buff = (uint8_t*)diff_image->Buffer();
|
||||||
uint8_t* pdiff;
|
uint8_t* pdiff;
|
||||||
|
@ -221,7 +219,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
||||||
unsigned int hi_x = polygon.HiX();
|
unsigned int hi_x = polygon.HiX();
|
||||||
unsigned int hi_y = polygon.HiY();
|
unsigned int hi_y = polygon.HiY();
|
||||||
|
|
||||||
Debug( 4, "Checking alarms for zone %d/%s in lines %d -> %d", id, label, lo_y, hi_y );
|
Debug(4, "Checking alarms for zone %d/%s in lines %d -> %d", id, label, lo_y, hi_y);
|
||||||
|
|
||||||
/* if(config.cpu_extensions && sseversion >= 20) {
|
/* if(config.cpu_extensions && sseversion >= 20) {
|
||||||
sse2_alarmedpixels(diff_image, pg_image, &alarm_pixels, &pixel_diff_count);
|
sse2_alarmedpixels(diff_image, pg_image, &alarm_pixels, &pixel_diff_count);
|
||||||
|
@ -230,36 +228,31 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
||||||
} */
|
} */
|
||||||
std_alarmedpixels(diff_image, pg_image, &alarm_pixels, &pixel_diff_count);
|
std_alarmedpixels(diff_image, pg_image, &alarm_pixels, &pixel_diff_count);
|
||||||
|
|
||||||
if ( config.record_diag_images ) {
|
if ( config.record_diag_images )
|
||||||
static char diag_path[PATH_MAX] = "";
|
diff_image->WriteJpeg(diag_path);
|
||||||
if ( ! diag_path[0] ) {
|
|
||||||
snprintf( diag_path, sizeof(diag_path), "%s/diag-%d-%d.jpg", monitor->getStorage()->Path(), id, 1 );
|
|
||||||
}
|
|
||||||
diff_image->WriteJpeg( diag_path );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( pixel_diff_count && alarm_pixels )
|
if ( pixel_diff_count && alarm_pixels )
|
||||||
pixel_diff = pixel_diff_count/alarm_pixels;
|
pixel_diff = pixel_diff_count/alarm_pixels;
|
||||||
Debug( 5, "Got %d alarmed pixels, need %d -> %d, avg pixel diff %d", alarm_pixels, min_alarm_pixels, max_alarm_pixels, pixel_diff );
|
Debug(5, "Got %d alarmed pixels, need %d -> %d, avg pixel diff %d", alarm_pixels, min_alarm_pixels, max_alarm_pixels, pixel_diff);
|
||||||
|
|
||||||
if( alarm_pixels ) {
|
if ( alarm_pixels ) {
|
||||||
if( min_alarm_pixels && (alarm_pixels < (unsigned int)min_alarm_pixels) ) {
|
if ( min_alarm_pixels && (alarm_pixels < (unsigned int)min_alarm_pixels) ) {
|
||||||
/* Not enough pixels alarmed */
|
/* Not enough pixels alarmed */
|
||||||
return (false);
|
return false;
|
||||||
} else if( max_alarm_pixels && (alarm_pixels > (unsigned int)max_alarm_pixels) ) {
|
} else if ( max_alarm_pixels && (alarm_pixels > (unsigned int)max_alarm_pixels) ) {
|
||||||
/* Too many pixels alarmed */
|
/* Too many pixels alarmed */
|
||||||
overload_count = overload_frames;
|
overload_count = overload_frames;
|
||||||
return (false);
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* No alarmed pixels */
|
/* No alarmed pixels */
|
||||||
return (false);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
score = (100*alarm_pixels)/polygon.Area();
|
score = (100*alarm_pixels)/polygon.Area();
|
||||||
if ( score < 1 )
|
if ( score < 1 )
|
||||||
score = 1; /* Fix for score of 0 when frame meets thresholds but alarmed area is not big enough */
|
score = 1; /* Fix for score of 0 when frame meets thresholds but alarmed area is not big enough */
|
||||||
Debug( 5, "Current score is %d", score );
|
Debug(5, "Current score is %d", score);
|
||||||
|
|
||||||
if ( check_method >= FILTERED_PIXELS ) {
|
if ( check_method >= FILTERED_PIXELS ) {
|
||||||
int bx = filter_box.X();
|
int bx = filter_box.X();
|
||||||
|
@ -268,7 +261,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
||||||
int by1 = by-1;
|
int by1 = by-1;
|
||||||
|
|
||||||
|
|
||||||
Debug( 5, "Checking for filtered pixels" );
|
Debug(5, "Checking for filtered pixels");
|
||||||
if ( bx > 1 || by > 1 ) {
|
if ( bx > 1 || by > 1 ) {
|
||||||
// Now remove any pixels smaller than our filter size
|
// Now remove any pixels smaller than our filter size
|
||||||
unsigned char *cpdiff;
|
unsigned char *cpdiff;
|
||||||
|
@ -306,47 +299,42 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
alarm_filter_pixels++;
|
alarm_filter_pixels++;
|
||||||
}
|
} // end if white
|
||||||
}
|
} // end for x
|
||||||
}
|
} // end foreach y line
|
||||||
} else {
|
} else {
|
||||||
alarm_filter_pixels = alarm_pixels;
|
alarm_filter_pixels = alarm_pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( config.record_diag_images ) {
|
if ( config.record_diag_images )
|
||||||
static char diag_path[PATH_MAX] = "";
|
diff_image->WriteJpeg(diag_path);
|
||||||
if ( !diag_path[0] ) {
|
|
||||||
snprintf( diag_path, sizeof(diag_path), "%s/diag-%d-%d.jpg", monitor->getStorage()->Path(), id, 2 );
|
|
||||||
}
|
|
||||||
diff_image->WriteJpeg( diag_path );
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug( 5, "Got %d filtered pixels, need %d -> %d", alarm_filter_pixels, min_filter_pixels, max_filter_pixels );
|
Debug(5, "Got %d filtered pixels, need %d -> %d", alarm_filter_pixels, min_filter_pixels, max_filter_pixels);
|
||||||
|
|
||||||
if( alarm_filter_pixels ) {
|
if ( alarm_filter_pixels ) {
|
||||||
if( min_filter_pixels && (alarm_filter_pixels < min_filter_pixels) ) {
|
if ( min_filter_pixels && (alarm_filter_pixels < min_filter_pixels) ) {
|
||||||
/* Not enough pixels alarmed */
|
/* Not enough pixels alarmed */
|
||||||
return (false);
|
return false;
|
||||||
} else if( max_filter_pixels && (alarm_filter_pixels > max_filter_pixels) ) {
|
} else if ( max_filter_pixels && (alarm_filter_pixels > max_filter_pixels) ) {
|
||||||
/* Too many pixels alarmed */
|
/* Too many pixels alarmed */
|
||||||
overload_count = overload_frames;
|
overload_count = overload_frames;
|
||||||
return (false);
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* No filtered pixels */
|
/* No filtered pixels */
|
||||||
return (false);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
score = (100*alarm_filter_pixels)/(polygon.Area());
|
score = (100*alarm_filter_pixels)/(polygon.Area());
|
||||||
if ( score < 1 )
|
if ( score < 1 )
|
||||||
score = 1; /* Fix for score of 0 when frame meets thresholds but alarmed area is not big enough */
|
score = 1; /* Fix for score of 0 when frame meets thresholds but alarmed area is not big enough */
|
||||||
Debug( 5, "Current score is %d", score );
|
Debug(5, "Current score is %d", score);
|
||||||
|
|
||||||
if ( check_method >= BLOBS ) {
|
if ( check_method >= BLOBS ) {
|
||||||
Debug( 5, "Checking for blob pixels" );
|
Debug(5, "Checking for blob pixels");
|
||||||
typedef struct { unsigned char tag; int count; int lo_x; int hi_x; int lo_y; int hi_y; } BlobStats;
|
typedef struct { unsigned char tag; int count; int lo_x; int hi_x; int lo_y; int hi_y; } BlobStats;
|
||||||
BlobStats blob_stats[256];
|
BlobStats blob_stats[256];
|
||||||
memset( blob_stats, 0, sizeof(BlobStats)*256 );
|
memset(blob_stats, 0, sizeof(BlobStats)*256);
|
||||||
uint8_t *spdiff;
|
uint8_t *spdiff;
|
||||||
uint8_t last_x, last_y;
|
uint8_t last_x, last_y;
|
||||||
BlobStats *bsx, *bsy;
|
BlobStats *bsx, *bsy;
|
||||||
|
@ -358,32 +346,32 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
||||||
pdiff = (uint8_t*)diff_image->Buffer( lo_x, y );
|
pdiff = (uint8_t*)diff_image->Buffer( lo_x, y );
|
||||||
for ( int x = lo_x; x <= hi_x; x++, pdiff++ ) {
|
for ( int x = lo_x; x <= hi_x; x++, pdiff++ ) {
|
||||||
if ( *pdiff == WHITE ) {
|
if ( *pdiff == WHITE ) {
|
||||||
Debug( 9, "Got white pixel at %d,%d (%p)", x, y, pdiff );
|
Debug(9, "Got white pixel at %d,%d (%p)", x, y, pdiff);
|
||||||
//last_x = (x>lo_x)?*(pdiff-1):0;
|
//last_x = (x>lo_x)?*(pdiff-1):0;
|
||||||
//last_y = (y>lo_y&&x>=last_lo_x&&x<=last_hi_x)?*(pdiff-diff_width):0;
|
//last_y = (y>lo_y&&x>=last_lo_x&&x<=last_hi_x)?*(pdiff-diff_width):0;
|
||||||
|
|
||||||
last_x = 0;
|
last_x = 0;
|
||||||
if(x > 0) {
|
if ( x > 0 ) {
|
||||||
if((x-1) >= lo_x) {
|
if ( (x-1) >= lo_x ) {
|
||||||
last_x = *(pdiff-1);
|
last_x = *(pdiff-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
last_y = 0;
|
last_y = 0;
|
||||||
if(y > 0) {
|
if (y > 0 ) {
|
||||||
if((y-1) >= lo_y && ranges[(y-1)].lo_x <= x && ranges[(y-1)].hi_x >= x) {
|
if ( (y-1) >= lo_y && ranges[(y-1)].lo_x <= x && ranges[(y-1)].hi_x >= x ) {
|
||||||
last_y = *(pdiff-diff_width);
|
last_y = *(pdiff-diff_width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( last_x ) {
|
if ( last_x ) {
|
||||||
Debug( 9, "Left neighbour is %d", last_x );
|
Debug(9, "Left neighbour is %d", last_x);
|
||||||
bsx = &blob_stats[last_x];
|
bsx = &blob_stats[last_x];
|
||||||
if ( last_y ) {
|
if ( last_y ) {
|
||||||
Debug( 9, "Top neighbour is %d", last_y );
|
Debug(9, "Top neighbour is %d", last_y);
|
||||||
bsy = &blob_stats[last_y];
|
bsy = &blob_stats[last_y];
|
||||||
if ( last_x == last_y ) {
|
if ( last_x == last_y ) {
|
||||||
Debug( 9, "Matching neighbours, setting to %d", last_x );
|
Debug(9, "Matching neighbours, setting to %d", last_x);
|
||||||
// Add to the blob from the x side (either side really)
|
// Add to the blob from the x side (either side really)
|
||||||
*pdiff = last_x;
|
*pdiff = last_x;
|
||||||
alarm_blob_pixels++;
|
alarm_blob_pixels++;
|
||||||
|
@ -395,22 +383,29 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
||||||
bsm = bsx->count>=bsy->count?bsx:bsy;
|
bsm = bsx->count>=bsy->count?bsx:bsy;
|
||||||
bss = bsm==bsx?bsy:bsx;
|
bss = bsm==bsx?bsy:bsx;
|
||||||
|
|
||||||
Debug( 9, "Different neighbours, setting pixels of %d to %d", bss->tag, bsm->tag );
|
Debug(9,
|
||||||
Debug( 9, "Master blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d", bsm->tag, bsm->count, bsm->lo_x, bsm->hi_x, bsm->lo_y, bsm->hi_y );
|
"Different neighbours, setting pixels of %d to %d\n"
|
||||||
Debug( 9, "Slave blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d", bss->tag, bss->count, bss->lo_x, bss->hi_x, bss->lo_y, bss->hi_y );
|
"Master blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d\n"
|
||||||
|
"Slave blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d\n",
|
||||||
|
bss->tag, bsm->tag,
|
||||||
|
bsm->tag, bsm->count, bsm->lo_x, bsm->hi_x, bsm->lo_y, bsm->hi_y,
|
||||||
|
bss->tag, bss->count, bss->lo_x, bss->hi_x, bss->lo_y, bss->hi_y
|
||||||
|
);
|
||||||
// Now change all those pixels to the other setting
|
// Now change all those pixels to the other setting
|
||||||
int changed = 0;
|
int changed = 0;
|
||||||
for ( int sy = bss->lo_y; sy <= bss->hi_y; sy++) {
|
for ( int sy = bss->lo_y; sy <= bss->hi_y; sy++ ) {
|
||||||
int lo_sx = bss->lo_x>=ranges[sy].lo_x?bss->lo_x:ranges[sy].lo_x;
|
int lo_sx = bss->lo_x>=ranges[sy].lo_x?bss->lo_x:ranges[sy].lo_x;
|
||||||
int hi_sx = bss->hi_x<=ranges[sy].hi_x?bss->hi_x:ranges[sy].hi_x;
|
int hi_sx = bss->hi_x<=ranges[sy].hi_x?bss->hi_x:ranges[sy].hi_x;
|
||||||
|
|
||||||
Debug( 9, "Changing %d, %d->%d", sy, lo_sx, hi_sx );
|
Debug(9,
|
||||||
Debug( 9, "Range %d, %d->%d", sy, ranges[sy].lo_x, ranges[sy].hi_x );
|
"Changing %d, %d->%d Range %d->%d",
|
||||||
|
sy, lo_sx, hi_sx, ranges[sy].lo_x, ranges[sy].hi_x
|
||||||
|
);
|
||||||
spdiff = diff_buff + ((diff_width * sy) + lo_sx);
|
spdiff = diff_buff + ((diff_width * sy) + lo_sx);
|
||||||
for ( int sx = lo_sx; sx <= hi_sx; sx++, spdiff++ ) {
|
for ( int sx = lo_sx; sx <= hi_sx; sx++, spdiff++ ) {
|
||||||
Debug( 9, "Pixel at %d,%d (%p) is %d", sx, sy, spdiff, *spdiff );
|
Debug(9, "Pixel at %d,%d (%p) is %d", sx, sy, spdiff, *spdiff);
|
||||||
if ( *spdiff == bss->tag ) {
|
if ( *spdiff == bss->tag ) {
|
||||||
Debug( 9, "Setting pixel" );
|
Debug(9, "Setting pixel");
|
||||||
*spdiff = bsm->tag;
|
*spdiff = bsm->tag;
|
||||||
changed++;
|
changed++;
|
||||||
}
|
}
|
||||||
|
@ -419,10 +414,14 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
||||||
*pdiff = bsm->tag;
|
*pdiff = bsm->tag;
|
||||||
alarm_blob_pixels++;
|
alarm_blob_pixels++;
|
||||||
if ( !changed ) {
|
if ( !changed ) {
|
||||||
Info( "Master blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d", bsm->tag, bsm->count, bsm->lo_x, bsm->hi_x, bsm->lo_y, bsm->hi_y );
|
Info(
|
||||||
Info( "Slave blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d", bss->tag, bss->count, bss->lo_x, bss->hi_x, bss->lo_y, bss->hi_y );
|
"Master blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d\n"
|
||||||
Error( "No pixels changed, exiting" );
|
"Slave blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d",
|
||||||
exit( -1 );
|
bsm->tag, bsm->count, bsm->lo_x, bsm->hi_x, bsm->lo_y, bsm->hi_y,
|
||||||
|
bss->tag, bss->count, bss->lo_x, bss->hi_x, bss->lo_y, bss->hi_y
|
||||||
|
);
|
||||||
|
Error("No pixels changed, exiting");
|
||||||
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge the slave blob into the master
|
// Merge the slave blob into the master
|
||||||
|
@ -436,7 +435,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
||||||
|
|
||||||
alarm_blobs--;
|
alarm_blobs--;
|
||||||
|
|
||||||
Debug( 6, "Merging blob %d with %d at %d,%d, %d current blobs", bss->tag, bsm->tag, x, y, alarm_blobs );
|
Debug(6, "Merging blob %d with %d at %d,%d, %d current blobs", bss->tag, bsm->tag, x, y, alarm_blobs);
|
||||||
|
|
||||||
// Clear out the old blob
|
// Clear out the old blob
|
||||||
bss->tag = 0;
|
bss->tag = 0;
|
||||||
|
@ -447,7 +446,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
||||||
bss->hi_y = 0;
|
bss->hi_y = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Debug( 9, "Setting to left neighbour %d", last_x );
|
Debug(9, "Setting to left neighbour %d", last_x);
|
||||||
// Add to the blob from the x side
|
// Add to the blob from the x side
|
||||||
*pdiff = last_x;
|
*pdiff = last_x;
|
||||||
alarm_blob_pixels++;
|
alarm_blob_pixels++;
|
||||||
|
@ -457,8 +456,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ( last_y ) {
|
if ( last_y ) {
|
||||||
Debug( 9, "Top neighbour is %d", last_y );
|
Debug(9, "Top neighbour is %d", last_y);
|
||||||
Debug( 9, "Setting to top neighbour %d", last_y );
|
|
||||||
|
|
||||||
// Add to the blob from the y side
|
// Add to the blob from the y side
|
||||||
BlobStats *bsy = &blob_stats[last_y];
|
BlobStats *bsy = &blob_stats[last_y];
|
||||||
|
@ -489,7 +487,8 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
||||||
alarm_blobs--;
|
alarm_blobs--;
|
||||||
alarm_blob_pixels -= bs->count;
|
alarm_blob_pixels -= bs->count;
|
||||||
|
|
||||||
Debug( 6, "Eliminated blob %d, %d pixels (%d,%d - %d,%d), %d current blobs", i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs );
|
Debug(6, "Eliminated blob %d, %d pixels (%d,%d - %d,%d), %d current blobs",
|
||||||
|
i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs);
|
||||||
|
|
||||||
bs->tag = 0;
|
bs->tag = 0;
|
||||||
bs->count = 0;
|
bs->count = 0;
|
||||||
|
@ -500,7 +499,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( !bs->count ) {
|
if ( !bs->count ) {
|
||||||
Debug( 9, "Creating new blob %d", i );
|
Debug(9, "Creating new blob %d", i);
|
||||||
*pdiff = i;
|
*pdiff = i;
|
||||||
alarm_blob_pixels++;
|
alarm_blob_pixels++;
|
||||||
bs->tag = i;
|
bs->tag = i;
|
||||||
|
@ -509,12 +508,12 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
||||||
bs->lo_y = bs->hi_y = y;
|
bs->lo_y = bs->hi_y = y;
|
||||||
alarm_blobs++;
|
alarm_blobs++;
|
||||||
|
|
||||||
Debug( 6, "Created blob %d at %d,%d, %d current blobs", bs->tag, x, y, alarm_blobs );
|
Debug(6, "Created blob %d at %d,%d, %d current blobs", bs->tag, x, y, alarm_blobs);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( i == 0 ) {
|
if ( i == 0 ) {
|
||||||
Warning( "Max blob count reached. Unable to allocate new blobs so terminating. Zone settings may be too sensitive." );
|
Warning("Max blob count reached. Unable to allocate new blobs so terminating. Zone settings may be too sensitive.");
|
||||||
x = hi_x+1;
|
x = hi_x+1;
|
||||||
y = hi_y+1;
|
y = hi_y+1;
|
||||||
}
|
}
|
||||||
|
@ -523,19 +522,15 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( config.record_diag_images ) {
|
if ( config.record_diag_images )
|
||||||
static char diag_path[PATH_MAX] = "";
|
diff_image->WriteJpeg(diag_path);
|
||||||
if ( !diag_path[0] ) {
|
|
||||||
snprintf( diag_path, sizeof(diag_path), "%s/diag-%d-%d.jpg", monitor->getStorage()->Path(), id, 3 );
|
|
||||||
}
|
|
||||||
diff_image->WriteJpeg( diag_path );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !alarm_blobs ) {
|
if ( !alarm_blobs ) {
|
||||||
return( false );
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug( 5, "Got %d raw blob pixels, %d raw blobs, need %d -> %d, %d -> %d", alarm_blob_pixels, alarm_blobs, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs );
|
Debug(5, "Got %d raw blob pixels, %d raw blobs, need %d -> %d, %d -> %d",
|
||||||
|
alarm_blob_pixels, alarm_blobs, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs);
|
||||||
|
|
||||||
// Now eliminate blobs under the threshold
|
// Now eliminate blobs under the threshold
|
||||||
for ( int i = 1; i < WHITE; i++ ) {
|
for ( int i = 1; i < WHITE; i++ ) {
|
||||||
|
@ -555,7 +550,8 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
||||||
alarm_blobs--;
|
alarm_blobs--;
|
||||||
alarm_blob_pixels -= bs->count;
|
alarm_blob_pixels -= bs->count;
|
||||||
|
|
||||||
Debug( 6, "Eliminated blob %d, %d pixels (%d,%d - %d,%d), %d current blobs", i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs );
|
Debug(6, "Eliminated blob %d, %d pixels (%d,%d - %d,%d), %d current blobs",
|
||||||
|
i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs );
|
||||||
|
|
||||||
bs->tag = 0;
|
bs->tag = 0;
|
||||||
bs->count = 0;
|
bs->count = 0;
|
||||||
|
@ -564,39 +560,37 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
||||||
bs->hi_x = 0;
|
bs->hi_x = 0;
|
||||||
bs->hi_y = 0;
|
bs->hi_y = 0;
|
||||||
} else {
|
} else {
|
||||||
Debug( 6, "Preserved blob %d, %d pixels (%d,%d - %d,%d), %d current blobs", i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs );
|
Debug(6, "Preserved blob %d, %d pixels (%d,%d - %d,%d), %d current blobs",
|
||||||
|
i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs );
|
||||||
if ( !min_blob_size || bs->count < min_blob_size ) min_blob_size = bs->count;
|
if ( !min_blob_size || bs->count < min_blob_size ) min_blob_size = bs->count;
|
||||||
if ( !max_blob_size || bs->count > max_blob_size ) max_blob_size = bs->count;
|
if ( !max_blob_size || bs->count > max_blob_size ) max_blob_size = bs->count;
|
||||||
}
|
}
|
||||||
}
|
} // end if bs_count
|
||||||
}
|
} // end for i < WHITE
|
||||||
if ( config.record_diag_images ) {
|
if ( config.record_diag_images )
|
||||||
static char diag_path[PATH_MAX] = "";
|
diff_image->WriteJpeg(diag_path);
|
||||||
if ( !diag_path[0] ) {
|
|
||||||
snprintf( diag_path, sizeof(diag_path), "%s/diag-%d-%d.jpg", monitor->getStorage()->Path(), 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 );
|
|
||||||
|
|
||||||
if( alarm_blobs ) {
|
Debug(5, "Got %d blob pixels, %d blobs, need %d -> %d, %d -> %d",
|
||||||
if( min_blobs && (alarm_blobs < min_blobs) ) {
|
alarm_blob_pixels, alarm_blobs, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs);
|
||||||
|
|
||||||
|
if ( alarm_blobs ) {
|
||||||
|
if ( min_blobs && (alarm_blobs < min_blobs) ) {
|
||||||
/* Not enough pixels alarmed */
|
/* Not enough pixels alarmed */
|
||||||
return (false);
|
return false;
|
||||||
} else if(max_blobs && (alarm_blobs > max_blobs) ) {
|
} else if ( max_blobs && (alarm_blobs > max_blobs) ) {
|
||||||
/* Too many pixels alarmed */
|
/* Too many pixels alarmed */
|
||||||
overload_count = overload_frames;
|
overload_count = overload_frames;
|
||||||
return (false);
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* No blobs */
|
/* No blobs */
|
||||||
return (false);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
score = (100*alarm_blob_pixels)/(polygon.Area());
|
score = (100*alarm_blob_pixels)/(polygon.Area());
|
||||||
if ( score < 1 )
|
if ( score < 1 )
|
||||||
score = 1; /* Fix for score of 0 when frame meets thresholds but alarmed area is not big enough */
|
score = 1; /* Fix for score of 0 when frame meets thresholds but alarmed area is not big enough */
|
||||||
Debug( 5, "Current score is %d", score );
|
Debug(5, "Current score is %d", score);
|
||||||
|
|
||||||
alarm_lo_x = polygon.HiX()+1;
|
alarm_lo_x = polygon.HiX()+1;
|
||||||
alarm_hi_x = polygon.LoX()-1;
|
alarm_hi_x = polygon.LoX()-1;
|
||||||
|
@ -648,15 +642,15 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
||||||
score *= 2;
|
score *= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug( 5, "Adjusted score is %d", score );
|
Debug(5, "Adjusted score is %d", score);
|
||||||
|
|
||||||
// Now outline the changed region
|
// Now outline the changed region
|
||||||
if ( score ) {
|
if ( score ) {
|
||||||
alarm_box = Box( Coord( alarm_lo_x, alarm_lo_y ), Coord( alarm_hi_x, alarm_hi_y ) );
|
alarm_box = Box(Coord(alarm_lo_x, alarm_lo_y), Coord(alarm_hi_x, alarm_hi_y));
|
||||||
|
|
||||||
//if ( monitor->followMotion() )
|
//if ( monitor->followMotion() )
|
||||||
if ( true ) {
|
if ( true ) {
|
||||||
alarm_centre = Coord( alarm_mid_x, alarm_mid_y );
|
alarm_centre = Coord(alarm_mid_x, alarm_mid_y);
|
||||||
} else {
|
} else {
|
||||||
alarm_centre = alarm_box.Centre();
|
alarm_centre = alarm_box.Centre();
|
||||||
}
|
}
|
||||||
|
@ -698,9 +692,9 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( monitor->Colours() == ZM_COLOUR_GRAY8 ) {
|
if ( monitor->Colours() == ZM_COLOUR_GRAY8 ) {
|
||||||
image = diff_image->HighlightEdges( alarm_rgb, ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB, &polygon.Extent() );
|
image = diff_image->HighlightEdges(alarm_rgb, ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB, &polygon.Extent());
|
||||||
} else {
|
} else {
|
||||||
image = diff_image->HighlightEdges( alarm_rgb, monitor->Colours(), monitor->SubpixelOrder(), &polygon.Extent() );
|
image = diff_image->HighlightEdges(alarm_rgb, monitor->Colours(), monitor->SubpixelOrder(), &polygon.Extent());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only need to delete this when 'image' becomes detached and points somewhere else
|
// Only need to delete this when 'image' becomes detached and points somewhere else
|
||||||
|
@ -710,18 +704,18 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
||||||
image = 0;
|
image = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug( 1, "%s: Pixel Diff: %d, Alarm Pixels: %d, Filter Pixels: %d, Blob Pixels: %d, Blobs: %d, Score: %d",
|
Debug(1, "%s: Pixel Diff: %d, Alarm Pixels: %d, Filter Pixels: %d, Blob Pixels: %d, Blobs: %d, Score: %d",
|
||||||
Label(), pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, score );
|
Label(), pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, score);
|
||||||
}
|
}
|
||||||
return( true );
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Zone::ParsePolygonString( const char *poly_string, Polygon &polygon ) {
|
bool Zone::ParsePolygonString(const char *poly_string, Polygon &polygon) {
|
||||||
Debug( 3, "Parsing polygon string '%s'", poly_string );
|
Debug(3, "Parsing polygon string '%s'", poly_string);
|
||||||
|
|
||||||
char *str_ptr = new char[strlen(poly_string)+1];
|
char *str_ptr = new char[strlen(poly_string)+1];
|
||||||
char *str = str_ptr;
|
char *str = str_ptr;
|
||||||
strcpy( str, poly_string );
|
strcpy(str, poly_string);
|
||||||
|
|
||||||
char *ws;
|
char *ws;
|
||||||
int n_coords = 0;
|
int n_coords = 0;
|
||||||
|
@ -731,16 +725,16 @@ bool Zone::ParsePolygonString( const char *poly_string, Polygon &polygon ) {
|
||||||
if ( *str == '\0' ) {
|
if ( *str == '\0' ) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ws = strchr( str, ' ' );
|
ws = strchr(str, ' ');
|
||||||
if ( ws ) {
|
if ( ws ) {
|
||||||
*ws = '\0';
|
*ws = '\0';
|
||||||
}
|
}
|
||||||
char *cp = strchr( str, ',' );
|
char *cp = strchr(str, ',');
|
||||||
if ( !cp ) {
|
if ( !cp ) {
|
||||||
Error( "Bogus coordinate %s found in polygon string", str );
|
Error("Bogus coordinate %s found in polygon string", str);
|
||||||
delete[] coords;
|
delete[] coords;
|
||||||
delete[] str_ptr;
|
delete[] str_ptr;
|
||||||
return( false );
|
return false;
|
||||||
} else {
|
} else {
|
||||||
*cp = '\0';
|
*cp = '\0';
|
||||||
char *xp = str;
|
char *xp = str;
|
||||||
|
@ -749,7 +743,7 @@ bool Zone::ParsePolygonString( const char *poly_string, Polygon &polygon ) {
|
||||||
int x = atoi(xp);
|
int x = atoi(xp);
|
||||||
int y = atoi(yp);
|
int y = atoi(yp);
|
||||||
|
|
||||||
Debug( 3, "Got coordinate %d,%d from polygon string", x, y );
|
Debug(3, "Got coordinate %d,%d from polygon string", x, y);
|
||||||
#if 0
|
#if 0
|
||||||
if ( x < 0 )
|
if ( x < 0 )
|
||||||
x = 0;
|
x = 0;
|
||||||
|
@ -767,82 +761,83 @@ bool Zone::ParsePolygonString( const char *poly_string, Polygon &polygon ) {
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
polygon = Polygon( n_coords, coords );
|
polygon = Polygon(n_coords, coords);
|
||||||
|
|
||||||
Debug( 3, "Successfully parsed polygon string" );
|
Debug(3, "Successfully parsed polygon string");
|
||||||
//printf( "Area: %d\n", pg.Area() );
|
//printf( "Area: %d\n", pg.Area() );
|
||||||
//printf( "Centre: %d,%d\n", pg.Centre().X(), pg.Centre().Y() );
|
//printf( "Centre: %d,%d\n", pg.Centre().X(), pg.Centre().Y() );
|
||||||
|
|
||||||
delete[] coords;
|
delete[] coords;
|
||||||
delete[] str_ptr;
|
delete[] str_ptr;
|
||||||
|
|
||||||
return( true );
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Zone::ParseZoneString( const char *zone_string, int &zone_id, int &colour, Polygon &polygon ) {
|
bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, Polygon &polygon) {
|
||||||
Debug( 3, "Parsing zone string '%s'", zone_string );
|
Debug(3, "Parsing zone string '%s'", zone_string);
|
||||||
|
|
||||||
char *str_ptr = new char[strlen(zone_string)+1];
|
char *str_ptr = new char[strlen(zone_string)+1];
|
||||||
char *str = str_ptr;
|
char *str = str_ptr;
|
||||||
strcpy( str, zone_string );
|
strcpy(str, zone_string);
|
||||||
|
|
||||||
char *ws = strchr( str, ' ' );
|
char *ws = strchr(str, ' ');
|
||||||
if ( !ws ) {
|
if ( !ws ) {
|
||||||
Debug( 3, "No initial whitespace found in zone string '%s', finishing", str );
|
Debug(3, "No initial whitespace found in zone string '%s', finishing", str);
|
||||||
}
|
}
|
||||||
zone_id = strtol( str, 0, 10 );
|
zone_id = strtol(str, 0, 10);
|
||||||
Debug( 3, "Got zone %d from zone string", zone_id );
|
Debug(3, "Got zone %d from zone string", zone_id);
|
||||||
if ( !ws ) {
|
if ( !ws ) {
|
||||||
delete[] str_ptr;
|
delete[] str_ptr;
|
||||||
return( true );
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
*ws = '\0';
|
*ws = '\0';
|
||||||
str = ws+1;
|
str = ws+1;
|
||||||
|
|
||||||
ws = strchr( str, ' ' );
|
ws = strchr(str, ' ');
|
||||||
if ( !ws ) {
|
if ( !ws ) {
|
||||||
Debug( 3, "No secondary whitespace found in zone string '%s', finishing", zone_string );
|
Debug(3, "No secondary whitespace found in zone string '%s', finishing", zone_string);
|
||||||
}
|
}
|
||||||
colour = strtol( str, 0, 16 );
|
colour = strtol(str, 0, 16);
|
||||||
Debug( 3, "Got colour %06x from zone string", colour );
|
Debug(3, "Got colour %06x from zone string", colour);
|
||||||
if ( !ws ) {
|
if ( !ws ) {
|
||||||
delete[] str_ptr;
|
delete[] str_ptr;
|
||||||
return( true );
|
return true;
|
||||||
}
|
}
|
||||||
*ws = '\0';
|
*ws = '\0';
|
||||||
str = ws+1;
|
str = ws+1;
|
||||||
|
|
||||||
bool result = ParsePolygonString( str, polygon );
|
bool result = ParsePolygonString(str, polygon);
|
||||||
|
|
||||||
//printf( "Area: %d\n", pg.Area() );
|
//printf( "Area: %d\n", pg.Area() );
|
||||||
//printf( "Centre: %d,%d\n", pg.Centre().X(), pg.Centre().Y() );
|
//printf( "Centre: %d,%d\n", pg.Centre().X(), pg.Centre().Y() );
|
||||||
|
|
||||||
delete[] str_ptr;
|
delete[] str_ptr;
|
||||||
|
|
||||||
return( result );
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Zone::Load( Monitor *monitor, Zone **&zones ) {
|
int Zone::Load(Monitor *monitor, Zone **&zones) {
|
||||||
static char sql[ZM_SQL_MED_BUFSIZ];
|
static char sql[ZM_SQL_MED_BUFSIZ];
|
||||||
snprintf( sql, sizeof(sql), "select Id,Name,Type+0,Units,Coords,AlarmRGB,CheckMethod+0,MinPixelThreshold,MaxPixelThreshold,MinAlarmPixels,MaxAlarmPixels,FilterX,FilterY,MinFilterPixels,MaxFilterPixels,MinBlobPixels,MaxBlobPixels,MinBlobs,MaxBlobs,OverloadFrames,ExtendAlarmFrames from Zones where MonitorId = %d order by Type, Id", monitor->Id() );
|
|
||||||
db_mutex.lock();
|
db_mutex.lock();
|
||||||
if ( mysql_query( &dbconn, sql ) ) {
|
snprintf(sql, sizeof(sql), "select Id,Name,Type+0,Units,Coords,AlarmRGB,CheckMethod+0,MinPixelThreshold,MaxPixelThreshold,MinAlarmPixels,MaxAlarmPixels,FilterX,FilterY,MinFilterPixels,MaxFilterPixels,MinBlobPixels,MaxBlobPixels,MinBlobs,MaxBlobs,OverloadFrames,ExtendAlarmFrames from Zones where MonitorId = %d order by Type, Id", monitor->Id());
|
||||||
Error( "Can't run query: %s", mysql_error( &dbconn ) );
|
if ( mysql_query(&dbconn, sql) ) {
|
||||||
exit( mysql_errno( &dbconn ) );
|
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||||
|
db_mutex.unlock();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
MYSQL_RES *result = mysql_store_result( &dbconn );
|
MYSQL_RES *result = mysql_store_result( &dbconn );
|
||||||
db_mutex.unlock();
|
db_mutex.unlock();
|
||||||
if ( !result ) {
|
if ( !result ) {
|
||||||
Error( "Can't use query result: %s", mysql_error( &dbconn ) );
|
Error("Can't use query result: %s", mysql_error(&dbconn));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int n_zones = mysql_num_rows( result );
|
int n_zones = mysql_num_rows(result);
|
||||||
Debug( 1, "Got %d zones for monitor %s", n_zones, monitor->Name() );
|
Debug(1, "Got %d zones for monitor %s", n_zones, monitor->Name());
|
||||||
delete[] zones;
|
delete[] zones;
|
||||||
zones = new Zone *[n_zones];
|
zones = new Zone *[n_zones];
|
||||||
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) {
|
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) {
|
||||||
int col = 0;
|
int col = 0;
|
||||||
|
|
||||||
int Id = atoi(dbrow[col++]);
|
int Id = atoi(dbrow[col++]);
|
||||||
|
@ -870,17 +865,18 @@ int Zone::Load( Monitor *monitor, Zone **&zones ) {
|
||||||
/* HTML colour code is actually BGR in memory, we want RGB */
|
/* HTML colour code is actually BGR in memory, we want RGB */
|
||||||
AlarmRGB = rgb_convert(AlarmRGB, ZM_SUBPIX_ORDER_BGR);
|
AlarmRGB = rgb_convert(AlarmRGB, ZM_SUBPIX_ORDER_BGR);
|
||||||
|
|
||||||
Debug( 5, "Parsing polygon %s", Coords );
|
Debug(5, "Parsing polygon %s", Coords);
|
||||||
Polygon polygon;
|
Polygon polygon;
|
||||||
if ( !ParsePolygonString( Coords, polygon ) ) {
|
if ( !ParsePolygonString(Coords, polygon) ) {
|
||||||
Error( "Unable to parse polygon string '%s' for zone %d/%s for monitor %s, ignoring", Coords, Id, Name, monitor->Name() );
|
Error("Unable to parse polygon string '%s' for zone %d/%s for monitor %s, ignoring", Coords, Id, Name, monitor->Name());
|
||||||
n_zones -= 1;
|
n_zones -= 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( polygon.LoX() < 0 || polygon.HiX() >= (int)monitor->Width()
|
if ( polygon.LoX() < 0 || polygon.HiX() >= (int)monitor->Width()
|
||||||
|| polygon.LoY() < 0 || polygon.HiY() >= (int)monitor->Height() ) {
|
|| polygon.LoY() < 0 || polygon.HiY() >= (int)monitor->Height() ) {
|
||||||
Error( "Zone %d/%s for monitor %s extends outside of image dimensions, (%d,%d), (%d,%d), ignoring", Id, Name, monitor->Name(), polygon.LoX(), polygon.LoY(), polygon.HiX(), polygon.HiY() );
|
Error("Zone %d/%s for monitor %s extends outside of image dimensions, (%d,%d), (%d,%d), ignoring",
|
||||||
|
Id, Name, monitor->Name(), polygon.LoX(), polygon.LoY(), polygon.HiX(), polygon.HiY());
|
||||||
n_zones -= 1;
|
n_zones -= 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -895,21 +891,17 @@ int Zone::Load( Monitor *monitor, Zone **&zones ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( atoi(dbrow[2]) == Zone::INACTIVE ) {
|
if ( atoi(dbrow[2]) == Zone::INACTIVE ) {
|
||||||
zones[i] = new Zone( monitor, Id, Name, polygon );
|
zones[i] = new Zone(monitor, Id, Name, polygon);
|
||||||
} else if ( atoi(dbrow[2]) == Zone::PRIVACY ) {
|
} else if ( atoi(dbrow[2]) == Zone::PRIVACY ) {
|
||||||
zones[i] = new Zone( monitor, Id, Name, (Zone::ZoneType)Type, polygon );
|
zones[i] = new Zone(monitor, Id, Name, (Zone::ZoneType)Type, polygon);
|
||||||
}
|
}
|
||||||
zones[i] = new Zone( monitor, Id, Name, (Zone::ZoneType)Type, polygon, AlarmRGB, (Zone::CheckMethod)CheckMethod, MinPixelThreshold, MaxPixelThreshold, MinAlarmPixels, MaxAlarmPixels, Coord( FilterX, FilterY ), MinFilterPixels, MaxFilterPixels, MinBlobPixels, MaxBlobPixels, MinBlobs, MaxBlobs, OverloadFrames, ExtendAlarmFrames );
|
zones[i] = new Zone(monitor, Id, Name, (Zone::ZoneType)Type, polygon, AlarmRGB, (Zone::CheckMethod)CheckMethod, MinPixelThreshold, MaxPixelThreshold, MinAlarmPixels, MaxAlarmPixels, Coord( FilterX, FilterY ), MinFilterPixels, MaxFilterPixels, MinBlobPixels, MaxBlobPixels, MinBlobs, MaxBlobs, OverloadFrames, ExtendAlarmFrames);
|
||||||
}
|
} // end foreach row
|
||||||
if ( mysql_errno( &dbconn ) ) {
|
mysql_free_result(result);
|
||||||
Error( "Can't fetch row: %s", mysql_error( &dbconn ) );
|
return n_zones;
|
||||||
exit( mysql_errno( &dbconn ) );
|
} // end int Zone::Load(Monitor *monitor, Zone **&zones)
|
||||||
}
|
|
||||||
mysql_free_result( result );
|
|
||||||
return( n_zones );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Zone::DumpSettings( char *output, bool /*verbose*/ ) {
|
bool Zone::DumpSettings(char *output, bool /*verbose*/) {
|
||||||
output[0] = 0;
|
output[0] = 0;
|
||||||
|
|
||||||
sprintf( output+strlen(output), " Id : %d\n", id );
|
sprintf( output+strlen(output), " Id : %d\n", id );
|
||||||
|
@ -953,7 +945,7 @@ void Zone::std_alarmedpixels(Image* pdiff_image, const Image* ppoly_image, unsig
|
||||||
unsigned int lo_y;
|
unsigned int lo_y;
|
||||||
unsigned int hi_y;
|
unsigned int hi_y;
|
||||||
|
|
||||||
if(max_pixel_threshold)
|
if ( max_pixel_threshold )
|
||||||
calc_max_pixel_threshold = max_pixel_threshold;
|
calc_max_pixel_threshold = max_pixel_threshold;
|
||||||
|
|
||||||
lo_y = polygon.LoY();
|
lo_y = polygon.LoY();
|
||||||
|
@ -962,9 +954,9 @@ void Zone::std_alarmedpixels(Image* pdiff_image, const Image* ppoly_image, unsig
|
||||||
unsigned int lo_x = ranges[y].lo_x;
|
unsigned int lo_x = ranges[y].lo_x;
|
||||||
unsigned int hi_x = ranges[y].hi_x;
|
unsigned int hi_x = ranges[y].hi_x;
|
||||||
|
|
||||||
Debug( 7, "Checking line %d from %d -> %d", y, lo_x, hi_x );
|
Debug(7, "Checking line %d from %d -> %d", y, lo_x, hi_x);
|
||||||
uint8_t *pdiff = (uint8_t*)pdiff_image->Buffer( lo_x, y );
|
uint8_t *pdiff = (uint8_t*)pdiff_image->Buffer(lo_x, y);
|
||||||
const uint8_t *ppoly = ppoly_image->Buffer( lo_x, y );
|
const uint8_t *ppoly = ppoly_image->Buffer(lo_x, y);
|
||||||
|
|
||||||
for ( unsigned int x = lo_x; x <= hi_x; x++, pdiff++, ppoly++ ) {
|
for ( unsigned int x = lo_x; x <= hi_x; x++, pdiff++, ppoly++ ) {
|
||||||
if ( *ppoly && (*pdiff > min_pixel_threshold) && (*pdiff <= calc_max_pixel_threshold) ) {
|
if ( *ppoly && (*pdiff > min_pixel_threshold) && (*pdiff <= calc_max_pixel_threshold) ) {
|
||||||
|
|
|
@ -94,6 +94,7 @@ protected:
|
||||||
|
|
||||||
int overload_count;
|
int overload_count;
|
||||||
int extend_alarm_count;
|
int extend_alarm_count;
|
||||||
|
char diag_path[PATH_MAX];
|
||||||
|
|
||||||
protected:
|
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 );
|
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 );
|
||||||
|
|
|
@ -146,7 +146,7 @@ int main( int argc, char *argv[] ) {
|
||||||
monitor->UpdateAdaptiveSkip();
|
monitor->UpdateAdaptiveSkip();
|
||||||
last_analysis_update_time = time( 0 );
|
last_analysis_update_time = time( 0 );
|
||||||
|
|
||||||
while( !zm_terminate ) {
|
while( (!zm_terminate) && monitor->ShmValid() ) {
|
||||||
// Process the next image
|
// Process the next image
|
||||||
sigprocmask(SIG_BLOCK, &block_set, 0);
|
sigprocmask(SIG_BLOCK, &block_set, 0);
|
||||||
|
|
||||||
|
|
59
src/zmc.cpp
59
src/zmc.cpp
|
@ -1,21 +1,21 @@
|
||||||
//
|
//
|
||||||
// ZoneMinder Capture Daemon, $Date$, $Revision$
|
// ZoneMinder Capture Daemon, $Date$, $Revision$
|
||||||
// Copyright (C) 2001-2008 Philip Coombes
|
// Copyright (C) 2001-2008 Philip Coombes
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or
|
// This program is free software; you can redistribute it and/or
|
||||||
// modify it under the terms of the GNU General Public License
|
// modify it under the terms of the GNU General Public License
|
||||||
// as published by the Free Software Foundation; either version 2
|
// as published by the Free Software Foundation; either version 2
|
||||||
// of the License, or (at your option) any later version.
|
// of the License, or (at your option) any later version.
|
||||||
//
|
//
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program; if not, write to the Free Software
|
// along with this program; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
//
|
//
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ zmc - The ZoneMinder Capture daemon
|
||||||
=head1 DESCRIPTION
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
This binary's job is to sit on a video device and suck frames off it as fast as
|
This binary's job is to sit on a video device and suck frames off it as fast as
|
||||||
possible, this should run at more or less constant speed.
|
possible, this should run at more or less constant speed.
|
||||||
|
|
||||||
=head1 OPTIONS
|
=head1 OPTIONS
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ int main(int argc, char *argv[]) {
|
||||||
std::cout << ZM_VERSION << "\n";
|
std::cout << ZM_VERSION << "\n";
|
||||||
exit(0);
|
exit(0);
|
||||||
default:
|
default:
|
||||||
//fprintf( stderr, "?? getopt returned character code 0%o ??\n", c );
|
// fprintf(stderr, "?? getopt returned character code 0%o ??\n", c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,7 +162,7 @@ int main(int argc, char *argv[]) {
|
||||||
Usage();
|
Usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
int modes = ( (device[0]?1:0) + (host[0]?1:0) + (file[0]?1:0) + (monitor_id > 0 ? 1 : 0));
|
int modes = ( (device[0]?1:0) + (host[0]?1:0) + (file[0]?1:0) + (monitor_id > 0 ? 1 : 0) );
|
||||||
if ( modes > 1 ) {
|
if ( modes > 1 ) {
|
||||||
fprintf(stderr, "Only one of device, host/port/path, file or monitor id allowed\n");
|
fprintf(stderr, "Only one of device, host/port/path, file or monitor id allowed\n");
|
||||||
Usage();
|
Usage();
|
||||||
|
@ -200,7 +200,7 @@ int main(int argc, char *argv[]) {
|
||||||
if ( device[0] ) {
|
if ( device[0] ) {
|
||||||
n_monitors = Monitor::LoadLocalMonitors(device, monitors, Monitor::CAPTURE);
|
n_monitors = Monitor::LoadLocalMonitors(device, monitors, Monitor::CAPTURE);
|
||||||
} else
|
} else
|
||||||
#endif // ZM_HAS_V4L
|
#endif // ZM_HAS_V4L
|
||||||
if ( host[0] ) {
|
if ( host[0] ) {
|
||||||
if ( !port )
|
if ( !port )
|
||||||
port = "80";
|
port = "80";
|
||||||
|
@ -222,26 +222,31 @@ int main(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Info("Starting Capture version %s", ZM_VERSION);
|
Info("Starting Capture version %s", ZM_VERSION);
|
||||||
|
zmSetDefaultHupHandler();
|
||||||
zmSetDefaultTermHandler();
|
zmSetDefaultTermHandler();
|
||||||
zmSetDefaultDieHandler();
|
zmSetDefaultDieHandler();
|
||||||
|
|
||||||
sigset_t block_set;
|
sigset_t block_set;
|
||||||
sigemptyset(&block_set);
|
sigemptyset(&block_set);
|
||||||
|
|
||||||
|
sigaddset(&block_set, SIGHUP);
|
||||||
sigaddset(&block_set, SIGUSR1);
|
sigaddset(&block_set, SIGUSR1);
|
||||||
sigaddset(&block_set, SIGUSR2);
|
sigaddset(&block_set, SIGUSR2);
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
while( ! zm_terminate ) {
|
|
||||||
|
while ( !zm_terminate ) {
|
||||||
result = 0;
|
result = 0;
|
||||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||||
for ( int i = 0; i < n_monitors; i ++ ) {
|
for ( int i = 0; i < n_monitors; i++ ) {
|
||||||
time_t now = (time_t)time(NULL);
|
time_t now = (time_t)time(NULL);
|
||||||
monitors[i]->setStartupTime(now);
|
monitors[i]->setStartupTime(now);
|
||||||
|
|
||||||
snprintf(sql, sizeof(sql), "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','Running')", monitors[i]->Id());
|
snprintf(sql, sizeof(sql),
|
||||||
|
"REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','Running')",
|
||||||
|
monitors[i]->Id());
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
if ( mysql_query(&dbconn, sql) ) {
|
||||||
Error( "Can't run query: %s", mysql_error( &dbconn ) );
|
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Outer primary loop, handles connection to camera
|
// Outer primary loop, handles connection to camera
|
||||||
|
@ -250,16 +255,19 @@ int main(int argc, char *argv[]) {
|
||||||
sleep(10);
|
sleep(10);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for ( int i = 0; i < n_monitors; i ++ ) {
|
for ( int i = 0; i < n_monitors; i++ ) {
|
||||||
snprintf(sql, sizeof(sql), "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','Connected')", monitors[i]->Id());
|
snprintf(sql, sizeof(sql),
|
||||||
|
"REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','Connected')",
|
||||||
|
monitors[i]->Id());
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
if ( mysql_query(&dbconn, sql) ) {
|
||||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnalysisThread **analysis_threads = new AnalysisThread *[n_monitors];
|
AnalysisThread **analysis_threads = new AnalysisThread *[n_monitors];
|
||||||
long *capture_delays = new long[n_monitors];
|
int *capture_delays = new int[n_monitors];
|
||||||
long *alarm_capture_delays = new long[n_monitors];
|
int *alarm_capture_delays = new int[n_monitors];
|
||||||
|
int *next_delays = new int[n_monitors];
|
||||||
struct timeval * last_capture_times = new struct timeval[n_monitors];
|
struct timeval * last_capture_times = new struct timeval[n_monitors];
|
||||||
for ( int i = 0; i < n_monitors; i++ ) {
|
for ( int i = 0; i < n_monitors; i++ ) {
|
||||||
last_capture_times[i].tv_sec = last_capture_times[i].tv_usec = 0;
|
last_capture_times[i].tv_sec = last_capture_times[i].tv_usec = 0;
|
||||||
|
@ -288,16 +296,19 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
if ( monitors[i]->PreCapture() < 0 ) {
|
if ( monitors[i]->PreCapture() < 0 ) {
|
||||||
Error("Failed to pre-capture monitor %d %d (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors);
|
Error("Failed to pre-capture monitor %d %d (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors);
|
||||||
|
monitors[i]->Close();
|
||||||
result = -1;
|
result = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ( monitors[i]->Capture() < 0 ) {
|
if ( monitors[i]->Capture() < 0 ) {
|
||||||
Error("Failed to capture image from monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors);
|
Error("Failed to capture image from monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors);
|
||||||
|
monitors[i]->Close();
|
||||||
result = -1;
|
result = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ( monitors[i]->PostCapture() < 0 ) {
|
if ( monitors[i]->PostCapture() < 0 ) {
|
||||||
Error("Failed to post-capture monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors);
|
Error("Failed to post-capture monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors);
|
||||||
|
monitors[i]->Close();
|
||||||
result = -1;
|
result = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -305,9 +316,9 @@ int main(int argc, char *argv[]) {
|
||||||
gettimeofday(&now, NULL);
|
gettimeofday(&now, NULL);
|
||||||
// capture_delay is the amount of time we should sleep to achieve the desired framerate.
|
// capture_delay is the amount of time we should sleep to achieve the desired framerate.
|
||||||
if ( last_capture_times[i].tv_sec ) {
|
if ( last_capture_times[i].tv_sec ) {
|
||||||
long sleep_time;
|
int sleep_time;
|
||||||
DELTA_TIMEVAL(delta_time, now, last_capture_times[i], DT_PREC_3);
|
DELTA_TIMEVAL(delta_time, now, last_capture_times[i], DT_PREC_3);
|
||||||
long delay = monitors[i]->GetState() == Monitor::ALARM ? alarm_capture_delays[i] : capture_delays[i];
|
int delay = monitors[i]->GetState() == Monitor::ALARM ? alarm_capture_delays[i] : capture_delays[i];
|
||||||
|
|
||||||
sleep_time = delay - delta_time.delta;
|
sleep_time = delay - delta_time.delta;
|
||||||
Debug(3, "Sleep time is %d from now:%d.%d last:%d.%d delay: %d", sleep_time, now.tv_sec, now.tv_usec, last_capture_times[i].tv_sec, last_capture_times[i].tv_usec, delay );
|
Debug(3, "Sleep time is %d from now:%d.%d last:%d.%d delay: %d", sleep_time, now.tv_sec, now.tv_usec, last_capture_times[i].tv_sec, last_capture_times[i].tv_usec, delay );
|
||||||
|
@ -334,7 +345,7 @@ int main(int argc, char *argv[]) {
|
||||||
monitors[i]->Reload();
|
monitors[i]->Reload();
|
||||||
}
|
}
|
||||||
logTerm();
|
logTerm();
|
||||||
logInit( log_id_string );
|
logInit(log_id_string);
|
||||||
zm_reload = false;
|
zm_reload = false;
|
||||||
} // end if zm_reload
|
} // end if zm_reload
|
||||||
} // end while ! zm_terminate and connected
|
} // end while ! zm_terminate and connected
|
||||||
|
@ -353,16 +364,16 @@ int main(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
} // end foreach monitor
|
} // end foreach monitor
|
||||||
delete [] analysis_threads;
|
delete [] analysis_threads;
|
||||||
if ( !zm_terminate )
|
|
||||||
sleep(10);
|
|
||||||
} // end while ! zm_terminate outer connection loop
|
} // end while ! zm_terminate outer connection loop
|
||||||
Debug(1,"Updating Monitor status");
|
Debug(1,"Updating Monitor status");
|
||||||
|
|
||||||
for ( int i = 0; i < n_monitors; i++ ) {
|
for ( int i = 0; i < n_monitors; i++ ) {
|
||||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||||
snprintf( sql, sizeof(sql), "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','NotRunning')", monitors[i]->Id() );
|
snprintf(sql, sizeof(sql),
|
||||||
if ( mysql_query( &dbconn, sql ) ) {
|
"REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','NotRunning')",
|
||||||
Error( "Can't run query: %s", mysql_error( &dbconn ) );
|
monitors[i]->Id());
|
||||||
|
if ( mysql_query(&dbconn, sql) ) {
|
||||||
|
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||||
}
|
}
|
||||||
delete monitors[i];
|
delete monitors[i];
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include <sys/ipc.h>
|
#include <sys/ipc.h>
|
||||||
#include <sys/msg.h>
|
#include <sys/msg.h>
|
||||||
|
#include <cinttypes>
|
||||||
|
|
||||||
#include "zm.h"
|
#include "zm.h"
|
||||||
#include "zm_db.h"
|
#include "zm_db.h"
|
||||||
|
@ -58,7 +59,7 @@ int main( int argc, const char *argv[] ) {
|
||||||
char format[32] = "";
|
char format[32] = "";
|
||||||
int monitor_id = 0;
|
int monitor_id = 0;
|
||||||
time_t event_time = 0;
|
time_t event_time = 0;
|
||||||
unsigned long long event_id = 0;
|
uint64_t event_id = 0;
|
||||||
unsigned int frame_id = 1;
|
unsigned int frame_id = 1;
|
||||||
unsigned int scale = 100;
|
unsigned int scale = 100;
|
||||||
unsigned int rate = 100;
|
unsigned int rate = 100;
|
||||||
|
@ -174,7 +175,7 @@ int main( int argc, const char *argv[] ) {
|
||||||
if ( monitor_id ) {
|
if ( monitor_id ) {
|
||||||
snprintf(log_id_string, sizeof(log_id_string), "zms_m%d", monitor_id);
|
snprintf(log_id_string, sizeof(log_id_string), "zms_m%d", monitor_id);
|
||||||
} else {
|
} else {
|
||||||
snprintf(log_id_string, sizeof(log_id_string), "zms_e%llu", event_id);
|
snprintf(log_id_string, sizeof(log_id_string), "zms_e%" PRIu64, event_id);
|
||||||
}
|
}
|
||||||
logInit( log_id_string );
|
logInit( log_id_string );
|
||||||
|
|
||||||
|
|
218
src/zmu.cpp
218
src/zmu.cpp
|
@ -87,6 +87,7 @@ Options for use with monitors:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include <cinttypes>
|
||||||
|
|
||||||
#include "zm.h"
|
#include "zm.h"
|
||||||
#include "zm_db.h"
|
#include "zm_db.h"
|
||||||
|
@ -95,49 +96,51 @@ Options for use with monitors:
|
||||||
#include "zm_monitor.h"
|
#include "zm_monitor.h"
|
||||||
#include "zm_local_camera.h"
|
#include "zm_local_camera.h"
|
||||||
|
|
||||||
void Usage( int status=-1 ) {
|
void Usage(int status=-1) {
|
||||||
fprintf( stderr, "zmu <-d device_path> [-v] [function] [-U<username> -P<password>]\n" );
|
fputs(
|
||||||
fprintf( stderr, "zmu <-m monitor_id> [-v] [function] [-U<username> -P<password>]\n" );
|
"zmu <-d device_path> [-v] [function] [-U<username> -P<password>]\n"
|
||||||
fprintf( stderr, "General options:\n" );
|
"zmu <-m monitor_id> [-v] [function] [-U<username> -P<password>]\n"
|
||||||
fprintf( stderr, " -h, --help : This screen\n" );
|
"General options:\n"
|
||||||
fprintf( stderr, " -v, --verbose : Produce more verbose output\n" );
|
" -h, --help : This screen\n"
|
||||||
fprintf( stderr, " -l, --list : List the current status of active (or all with -v) monitors\n" );
|
" -v, --verbose : Produce more verbose output\n"
|
||||||
fprintf( stderr, "Options for use with devices:\n" );
|
" -l, --list : List the current status of active (or all with -v) monitors\n"
|
||||||
fprintf( stderr, " -d, --device [device_path] : Get the current video device settings for [device_path] or all devices\n" );
|
"Options for use with devices:\n"
|
||||||
fprintf( stderr, " -V, --version <V4L version> : Set the Video 4 Linux API version to use for the query, use 1 or 2\n" );
|
" -d, --device [device_path] : Get the current video device settings for [device_path] or all devices\n"
|
||||||
fprintf( stderr, " -q, --query : Query the current settings for the device\n" );
|
" -V, --version <V4L version> : Set the Video 4 Linux API version to use for the query, use 1 or 2\n"
|
||||||
fprintf( stderr, "Options for use with monitors:\n" );
|
" -q, --query : Query the current settings for the device\n"
|
||||||
fprintf( stderr, " -m, --monitor <monitor_id> : Specify which monitor to address, default 1 if absent\n" );
|
"Options for use with monitors:\n"
|
||||||
fprintf( stderr, " -q, --query : Query the current settings for the monitor\n" );
|
" -m, --monitor <monitor_id> : Specify which monitor to address, default 1 if absent\n"
|
||||||
fprintf( stderr, " -s, --state : Output the current monitor state, 0 = idle, 1 = prealarm, 2 = alarm,\n" );
|
" -q, --query : Query the current settings for the monitor\n"
|
||||||
fprintf( stderr, " 3 = alert, 4 = tape\n" );
|
" -s, --state : Output the current monitor state, 0 = idle, 1 = prealarm, 2 = alarm,\n"
|
||||||
fprintf( stderr, " -B, --brightness [value] : Output the current brightness, set to value if given \n" );
|
" 3 = alert, 4 = tape\n"
|
||||||
fprintf( stderr, " -C, --contrast [value] : Output the current contrast, set to value if given \n" );
|
" -B, --brightness [value] : Output the current brightness, set to value if given \n"
|
||||||
fprintf( stderr, " -H, --hue [value] : Output the current hue, set to value if given \n" );
|
" -C, --contrast [value] : Output the current contrast, set to value if given \n"
|
||||||
fprintf( stderr, " -O, --colour [value] : Output the current colour, set to value if given \n" );
|
" -H, --hue [value] : Output the current hue, set to value if given \n"
|
||||||
fprintf( stderr, " -i, --image [image_index] : Write captured image to disk as <monitor_name>.jpg, last image captured\n" );
|
" -O, --colour [value] : Output the current colour, set to value if given \n"
|
||||||
fprintf( stderr, " or specified ring buffer index if given.\n" );
|
" -i, --image [image_index] : Write captured image to disk as <monitor_name>.jpg, last image captured\n"
|
||||||
fprintf( stderr, " -S, --scale <scale_%%ge> : With --image specify any scaling (in %%) to be applied to the image\n" );
|
" or specified ring buffer index if given.\n"
|
||||||
fprintf( stderr, " -t, --timestamp [image_index] : Output captured image timestamp, last image captured or specified\n" );
|
" -S, --scale <scale_%%ge> : With --image specify any scaling (in %%) to be applied to the image\n"
|
||||||
fprintf( stderr, " ring buffer index if given\n" );
|
" -t, --timestamp [image_index] : Output captured image timestamp, last image captured or specified\n"
|
||||||
fprintf( stderr, " -R, --read_index : Output ring buffer read index\n" );
|
" ring buffer index if given\n"
|
||||||
fprintf( stderr, " -W, --write_index : Output ring buffer write index\n" );
|
" -R, --read_index : Output ring buffer read index\n"
|
||||||
fprintf( stderr, " -e, --event : Output last event index\n" );
|
" -W, --write_index : Output ring buffer write index\n"
|
||||||
fprintf( stderr, " -f, --fps : Output last Frames Per Second captured reading\n" );
|
" -e, --event : Output last event index\n"
|
||||||
fprintf( stderr, " -z, --zones : Write last captured image overlaid with zones to <monitor_name>-Zones.jpg\n" );
|
" -f, --fps : Output last Frames Per Second captured reading\n"
|
||||||
fprintf( stderr, " -a, --alarm : Force alarm in monitor, this will trigger recording until cancelled with -c\n" );
|
" -z, --zones : Write last captured image overlaid with zones to <monitor_name>-Zones.jpg\n"
|
||||||
fprintf( stderr, " -n, --noalarm : Force no alarms in monitor, this will prevent alarms until cancelled with -c\n" );
|
" -a, --alarm : Force alarm in monitor, this will trigger recording until cancelled with -c\n"
|
||||||
fprintf( stderr, " -c, --cancel : Cancel a forced alarm/noalarm in monitor, required after being enabled with -a or -n\n" );
|
" -n, --noalarm : Force no alarms in monitor, this will prevent alarms until cancelled with -c\n"
|
||||||
fprintf( stderr, " -L, --reload : Signal monitor to reload settings\n" );
|
" -c, --cancel : Cancel a forced alarm/noalarm in monitor, required after being enabled with -a or -n\n"
|
||||||
fprintf( stderr, " -E, --enable : Enable detection, wake monitor up\n" );
|
" -L, --reload : Signal monitor to reload settings\n"
|
||||||
fprintf( stderr, " -D, --disable : Disable detection, put monitor to sleep\n" );
|
" -E, --enable : Enable detection, wake monitor up\n"
|
||||||
fprintf( stderr, " -u, --suspend : Suspend detection, useful to prevent bogus alarms when panning etc\n" );
|
" -D, --disable : Disable detection, put monitor to sleep\n"
|
||||||
fprintf( stderr, " -r, --resume : Resume detection after a suspend\n" );
|
" -u, --suspend : Suspend detection, useful to prevent bogus alarms when panning etc\n"
|
||||||
fprintf( stderr, " -U, --username <username> : When running in authenticated mode the username and\n" );
|
" -r, --resume : Resume detection after a suspend\n"
|
||||||
fprintf( stderr, " -P, --password <password> : password combination of the given user\n" );
|
" -U, --username <username> : When running in authenticated mode the username and\n"
|
||||||
fprintf( stderr, " -A, --auth <authentication> : Pass authentication hash string instead of user details\n" );
|
" -P, --password <password> : password combination of the given user\n"
|
||||||
|
" -A, --auth <authentication> : Pass authentication hash string instead of user details\n"
|
||||||
|
"", stderr );
|
||||||
|
|
||||||
exit( status );
|
exit(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -166,7 +169,7 @@ typedef enum {
|
||||||
ZMU_LIST = 0x10000000,
|
ZMU_LIST = 0x10000000,
|
||||||
} Function;
|
} Function;
|
||||||
|
|
||||||
bool ValidateAccess( User *user, int mon_id, int function ) {
|
bool ValidateAccess(User *user, int mon_id, int function) {
|
||||||
bool allowed = true;
|
bool allowed = true;
|
||||||
if ( function & (ZMU_STATE|ZMU_IMAGE|ZMU_TIME|ZMU_READ_IDX|ZMU_WRITE_IDX|ZMU_FPS) ) {
|
if ( function & (ZMU_STATE|ZMU_IMAGE|ZMU_TIME|ZMU_READ_IDX|ZMU_WRITE_IDX|ZMU_FPS) ) {
|
||||||
if ( user->getStream() < User::PERM_VIEW )
|
if ( user->getStream() < User::PERM_VIEW )
|
||||||
|
@ -185,26 +188,30 @@ bool ValidateAccess( User *user, int mon_id, int function ) {
|
||||||
allowed = false;
|
allowed = false;
|
||||||
}
|
}
|
||||||
if ( mon_id > 0 ) {
|
if ( mon_id > 0 ) {
|
||||||
if ( !user->canAccess( mon_id ) ) {
|
if ( !user->canAccess(mon_id) ) {
|
||||||
allowed = false;
|
allowed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( !allowed ) {
|
return allowed;
|
||||||
fprintf( stderr, "Error, insufficient privileges for requested action\n" );
|
|
||||||
exit( -1 );
|
|
||||||
}
|
|
||||||
return( allowed );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main( int argc, char *argv[] ) {
|
int exit_zmu(int exit_code) {
|
||||||
|
logTerm();
|
||||||
|
zmDbClose();
|
||||||
|
|
||||||
|
exit(exit_code);
|
||||||
|
return exit_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
if ( access(ZM_CONFIG, R_OK) != 0 ) {
|
if ( access(ZM_CONFIG, R_OK) != 0 ) {
|
||||||
fprintf( stderr, "Can't open %s: %s\n", ZM_CONFIG, strerror(errno) );
|
fprintf(stderr, "Can't open %s: %s\n", ZM_CONFIG, strerror(errno));
|
||||||
exit( -1 );
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
self = argv[0];
|
self = argv[0];
|
||||||
|
|
||||||
srand( getpid() * time( 0 ) );
|
srand(getpid() * time(0));
|
||||||
|
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{"device", 2, 0, 'd'},
|
{"device", 2, 0, 'd'},
|
||||||
|
@ -266,8 +273,8 @@ int main( int argc, char *argv[] ) {
|
||||||
while (1) {
|
while (1) {
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
|
|
||||||
int c = getopt_long (argc, argv, "d:m:vsEDLurwei::S:t::fz::ancqhlB::C::H::O::U:P:A:V:", long_options, &option_index);
|
int c = getopt_long(argc, argv, "d:m:vsEDLurwei::S:t::fz::ancqhlB::C::H::O::U:P:A:V:", long_options, &option_index);
|
||||||
if (c == -1) {
|
if ( c == -1 ) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,7 +295,7 @@ int main( int argc, char *argv[] ) {
|
||||||
case 'i':
|
case 'i':
|
||||||
function |= ZMU_IMAGE;
|
function |= ZMU_IMAGE;
|
||||||
if ( optarg )
|
if ( optarg )
|
||||||
image_idx = atoi( optarg );
|
image_idx = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 'S':
|
case 'S':
|
||||||
scale = atoi(optarg);
|
scale = atoi(optarg);
|
||||||
|
@ -296,7 +303,7 @@ int main( int argc, char *argv[] ) {
|
||||||
case 't':
|
case 't':
|
||||||
function |= ZMU_TIME;
|
function |= ZMU_TIME;
|
||||||
if ( optarg )
|
if ( optarg )
|
||||||
image_idx = atoi( optarg );
|
image_idx = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 'R':
|
case 'R':
|
||||||
function |= ZMU_READ_IDX;
|
function |= ZMU_READ_IDX;
|
||||||
|
@ -345,22 +352,22 @@ int main( int argc, char *argv[] ) {
|
||||||
case 'B':
|
case 'B':
|
||||||
function |= ZMU_BRIGHTNESS;
|
function |= ZMU_BRIGHTNESS;
|
||||||
if ( optarg )
|
if ( optarg )
|
||||||
brightness = atoi( optarg );
|
brightness = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
function |= ZMU_CONTRAST;
|
function |= ZMU_CONTRAST;
|
||||||
if ( optarg )
|
if ( optarg )
|
||||||
contrast = atoi( optarg );
|
contrast = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 'H':
|
case 'H':
|
||||||
function |= ZMU_HUE;
|
function |= ZMU_HUE;
|
||||||
if ( optarg )
|
if ( optarg )
|
||||||
hue = atoi( optarg );
|
hue = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 'O':
|
case 'O':
|
||||||
function |= ZMU_COLOUR;
|
function |= ZMU_COLOUR;
|
||||||
if ( optarg )
|
if ( optarg )
|
||||||
colour = atoi( optarg );
|
colour = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 'U':
|
case 'U':
|
||||||
username = optarg;
|
username = optarg;
|
||||||
|
@ -377,41 +384,39 @@ int main( int argc, char *argv[] ) {
|
||||||
break;
|
break;
|
||||||
#endif // ZM_HAS_V4L
|
#endif // ZM_HAS_V4L
|
||||||
case 'h':
|
case 'h':
|
||||||
Usage( 0 );
|
case '?':
|
||||||
|
Usage(0);
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
function |= ZMU_LIST;
|
function |= ZMU_LIST;
|
||||||
break;
|
break;
|
||||||
case '?':
|
|
||||||
Usage();
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
//fprintf( stderr, "?? getopt returned character code 0%o ??\n", c );
|
//fprintf( stderr, "?? getopt returned character code 0%o ??\n", c );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (optind < argc) {
|
if ( optind < argc ) {
|
||||||
fprintf( stderr, "Extraneous options, " );
|
fprintf(stderr, "Extraneous options, ");
|
||||||
while (optind < argc)
|
while (optind < argc)
|
||||||
fprintf( stderr, "%s ", argv[optind++]);
|
fprintf(stderr, "%s ", argv[optind++]);
|
||||||
fprintf( stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
Usage();
|
Usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( device && !(function&ZMU_QUERY) ) {
|
if ( device && !(function&ZMU_QUERY) ) {
|
||||||
fprintf( stderr, "Error, -d option cannot be used with this option\n" );
|
fprintf(stderr, "Error, -d option cannot be used with this option\n");
|
||||||
Usage();
|
Usage();
|
||||||
}
|
}
|
||||||
if ( scale != -1 && !(function&ZMU_IMAGE) ) {
|
if ( scale != -1 && !(function&ZMU_IMAGE) ) {
|
||||||
fprintf( stderr, "Error, -S option cannot be used with this option\n" );
|
fprintf(stderr, "Error, -S option cannot be used with this option\n");
|
||||||
Usage();
|
Usage();
|
||||||
}
|
}
|
||||||
//printf( "Monitor %d, Function %d\n", mon_id, function );
|
//printf( "Monitor %d, Function %d\n", mon_id, function );
|
||||||
|
|
||||||
zmLoadConfig();
|
zmLoadConfig();
|
||||||
|
|
||||||
logInit( "zmu" );
|
logInit("zmu");
|
||||||
|
|
||||||
zmSetDefaultTermHandler();
|
zmSetDefaultTermHandler();
|
||||||
zmSetDefaultDieHandler();
|
zmSetDefaultDieHandler();
|
||||||
|
@ -419,62 +424,66 @@ int main( int argc, char *argv[] ) {
|
||||||
User *user = 0;
|
User *user = 0;
|
||||||
|
|
||||||
if ( config.opt_use_auth ) {
|
if ( config.opt_use_auth ) {
|
||||||
if ( strcmp( config.auth_relay, "none" ) == 0 ) {
|
if ( strcmp(config.auth_relay, "none") == 0 ) {
|
||||||
if ( !username ) {
|
if ( !username ) {
|
||||||
fprintf( stderr, "Error, username must be supplied\n" );
|
fprintf(stderr, "Error, username must be supplied\n");
|
||||||
exit( -1 );
|
exit_zmu(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( username ) {
|
if ( username ) {
|
||||||
user = zmLoadUser( username );
|
user = zmLoadUser(username);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ( !(username && password) && !auth ) {
|
if ( !(username && password) && !auth ) {
|
||||||
fprintf( stderr, "Error, username and password or auth string must be supplied\n" );
|
fprintf(stderr, "Error, username and password or auth string must be supplied\n");
|
||||||
exit( -1 );
|
exit_zmu(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//if ( strcmp( config.auth_relay, "hashed" ) == 0 )
|
//if ( strcmp( config.auth_relay, "hashed" ) == 0 )
|
||||||
{
|
{
|
||||||
if ( auth ) {
|
if ( auth ) {
|
||||||
user = zmLoadAuthUser( auth, false );
|
user = zmLoadAuthUser(auth, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//else if ( strcmp( config.auth_relay, "plain" ) == 0 )
|
//else if ( strcmp( config.auth_relay, "plain" ) == 0 )
|
||||||
{
|
{
|
||||||
if ( username && password ) {
|
if ( username && password ) {
|
||||||
user = zmLoadUser( username, password );
|
user = zmLoadUser(username, password);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( !user ) {
|
if ( !user ) {
|
||||||
fprintf( stderr, "Error, unable to authenticate user\n" );
|
fprintf(stderr, "Error, unable to authenticate user\n");
|
||||||
exit( -1 );
|
return exit_zmu(-1);
|
||||||
}
|
}
|
||||||
ValidateAccess( user, mon_id, function );
|
if ( !ValidateAccess(user, mon_id, function) ) {
|
||||||
}
|
fprintf(stderr, "Error, insufficient privileges for requested action\n");
|
||||||
|
exit_zmu(-1);
|
||||||
|
}
|
||||||
|
} // end if auth
|
||||||
|
|
||||||
if ( mon_id > 0 ) {
|
if ( mon_id > 0 ) {
|
||||||
Monitor *monitor = Monitor::Load( mon_id, function&(ZMU_QUERY|ZMU_ZONES), Monitor::QUERY );
|
fprintf(stderr,"Monitor %d\n", mon_id);
|
||||||
|
Monitor *monitor = Monitor::Load(mon_id, function&(ZMU_QUERY|ZMU_ZONES), Monitor::QUERY);
|
||||||
if ( monitor ) {
|
if ( monitor ) {
|
||||||
|
fprintf(stderr,"Monitor %d(%s)\n", monitor->Id(), monitor->Name());
|
||||||
if ( verbose ) {
|
if ( verbose ) {
|
||||||
printf( "Monitor %d(%s)\n", monitor->Id(), monitor->Name() );
|
printf("Monitor %d(%s)\n", monitor->Id(), monitor->Name());
|
||||||
}
|
}
|
||||||
if ( ! monitor->connect() ) {
|
if ( ! monitor->connect() ) {
|
||||||
Error( "Can't connect to capture daemon: %d %s", monitor->Id(), monitor->Name() );
|
Error("Can't connect to capture daemon: %d %s", monitor->Id(), monitor->Name());
|
||||||
exit( -1 );
|
exit_zmu(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
char separator = ' ';
|
char separator = ' ';
|
||||||
bool have_output = false;
|
bool have_output = false;
|
||||||
if ( function & ZMU_STATE ) {
|
if ( function & ZMU_STATE ) {
|
||||||
Monitor::State state = monitor->GetState();
|
Monitor::State state = monitor->GetState();
|
||||||
if ( verbose )
|
if ( verbose )
|
||||||
printf( "Current state: %s\n", state==Monitor::ALARM?"Alarm":(state==Monitor::ALERT?"Alert":"Idle") );
|
printf("Current state: %s\n", state==Monitor::ALARM?"Alarm":(state==Monitor::ALERT?"Alert":"Idle"));
|
||||||
else {
|
else {
|
||||||
if ( have_output ) printf( "%c", separator );
|
if ( have_output ) printf("%c", separator);
|
||||||
printf( "%d", state );
|
printf("%d", state);
|
||||||
have_output = true;
|
have_output = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -514,10 +523,10 @@ int main( int argc, char *argv[] ) {
|
||||||
}
|
}
|
||||||
if ( function & ZMU_EVENT ) {
|
if ( function & ZMU_EVENT ) {
|
||||||
if ( verbose )
|
if ( verbose )
|
||||||
printf( "Last event id: %d\n", monitor->GetLastEventId() );
|
printf( "Last event id: %" PRIu64 "\n", monitor->GetLastEventId() );
|
||||||
else {
|
else {
|
||||||
if ( have_output ) printf( "%c", separator );
|
if ( have_output ) printf( "%c", separator );
|
||||||
printf( "%d", monitor->GetLastEventId() );
|
printf( "%" PRIu64, monitor->GetLastEventId() );
|
||||||
have_output = true;
|
have_output = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -660,8 +669,8 @@ int main( int argc, char *argv[] ) {
|
||||||
}
|
}
|
||||||
delete monitor;
|
delete monitor;
|
||||||
} else {
|
} else {
|
||||||
fprintf( stderr, "Error, invalid monitor id %d\n", mon_id );
|
fprintf(stderr, "Error, invalid monitor id %d\n", mon_id);
|
||||||
exit( -1 );
|
exit_zmu(-1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ( function & ZMU_QUERY ) {
|
if ( function & ZMU_QUERY ) {
|
||||||
|
@ -669,10 +678,10 @@ int main( int argc, char *argv[] ) {
|
||||||
char vidString[0x10000] = "";
|
char vidString[0x10000] = "";
|
||||||
bool ok = LocalCamera::GetCurrentSettings( device, vidString, v4lVersion, verbose );
|
bool ok = LocalCamera::GetCurrentSettings( device, vidString, v4lVersion, verbose );
|
||||||
printf( "%s", vidString );
|
printf( "%s", vidString );
|
||||||
exit( ok?0:-1 );
|
exit_zmu( ok?0:-1 );
|
||||||
#else // ZM_HAS_V4L
|
#else // ZM_HAS_V4L
|
||||||
fprintf( stderr, "Error, video4linux is required for device querying\n" );
|
fprintf( stderr, "Error, video4linux is required for device querying\n" );
|
||||||
exit( -1 );
|
exit_zmu( -1 );
|
||||||
#endif // ZM_HAS_V4L
|
#endif // ZM_HAS_V4L
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -685,13 +694,13 @@ int main( int argc, char *argv[] ) {
|
||||||
|
|
||||||
if ( mysql_query( &dbconn, sql.c_str() ) ) {
|
if ( mysql_query( &dbconn, sql.c_str() ) ) {
|
||||||
Error( "Can't run query: %s", mysql_error( &dbconn ) );
|
Error( "Can't run query: %s", mysql_error( &dbconn ) );
|
||||||
exit( mysql_errno( &dbconn ) );
|
exit_zmu( mysql_errno( &dbconn ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
MYSQL_RES *result = mysql_store_result( &dbconn );
|
MYSQL_RES *result = mysql_store_result( &dbconn );
|
||||||
if ( !result ) {
|
if ( !result ) {
|
||||||
Error( "Can't use query result: %s", mysql_error( &dbconn ) );
|
Error( "Can't use query result: %s", mysql_error( &dbconn ) );
|
||||||
exit( mysql_errno( &dbconn ) );
|
exit_zmu( mysql_errno( &dbconn ) );
|
||||||
}
|
}
|
||||||
Debug( 1, "Got %d monitors", mysql_num_rows( result ) );
|
Debug( 1, "Got %d monitors", mysql_num_rows( result ) );
|
||||||
|
|
||||||
|
@ -704,7 +713,7 @@ int main( int argc, char *argv[] ) {
|
||||||
Monitor *monitor = Monitor::Load( mon_id, false, Monitor::QUERY );
|
Monitor *monitor = Monitor::Load( mon_id, false, Monitor::QUERY );
|
||||||
if ( monitor && monitor->connect() ) {
|
if ( monitor && monitor->connect() ) {
|
||||||
struct timeval tv = monitor->GetTimestamp();
|
struct timeval tv = monitor->GetTimestamp();
|
||||||
printf( "%4d%5d%6d%9d%11ld.%02ld%6d%6d%8d%8.2f\n",
|
printf( "%4d%5d%6d%9d%11ld.%02ld%6d%6d%8" PRIu64 "%8.2f\n",
|
||||||
monitor->Id(),
|
monitor->Id(),
|
||||||
function,
|
function,
|
||||||
monitor->GetState(),
|
monitor->GetState(),
|
||||||
|
@ -738,8 +747,5 @@ int main( int argc, char *argv[] ) {
|
||||||
}
|
}
|
||||||
delete user;
|
delete user;
|
||||||
|
|
||||||
logTerm();
|
return exit_zmu(0);
|
||||||
zmDbClose();
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ]; then
|
||||||
echo
|
echo
|
||||||
|
|
||||||
mkdir -p ./zmrepo
|
mkdir -p ./zmrepo
|
||||||
ssh_mntchk="$(sshfs zmrepo@zmrepo.zoneminder.com:./ ./zmrepo -o workaround=rename,reconnect)"
|
ssh_mntchk="$(sshfs zmrepo@zmrepo.zoneminder.com:./ ./zmrepo -o workaround=rename,reconnect 2>&1)"
|
||||||
|
|
||||||
if [ -z "$ssh_mntchk" ]; then
|
if [ -z "$ssh_mntchk" ]; then
|
||||||
echo
|
echo
|
||||||
|
|
|
@ -19,20 +19,7 @@ checksanity () {
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ "${OS}" == "el" ] && [ "${DIST}" == "6" ]; then
|
|
||||||
type repoquery 2>&1 > /dev/null
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo
|
|
||||||
echo "ERROR: The script cannot find the required command \"reqoquery\"."
|
|
||||||
echo "This command is required in order to build ZoneMinder on el6."
|
|
||||||
echo "Please install the \"yum-utils\" package then try again."
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Verify OS & DIST environment variables have been set before calling this script
|
# Verify OS & DIST environment variables have been set before calling this script
|
||||||
if [ -z "${OS}" ] || [ -z "${DIST}" ]; then
|
if [ -z "${OS}" ] || [ -z "${DIST}" ]; then
|
||||||
echo "ERROR: both OS and DIST environment variables must be set"
|
echo "ERROR: both OS and DIST environment variables must be set"
|
||||||
|
@ -103,7 +90,7 @@ commonprep () {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Rpm builds are broken in latest packpack master. Temporarily roll back.
|
# Rpm builds are broken in latest packpack master. Temporarily roll back.
|
||||||
git -C packpack checkout 7cf23ee
|
#git -C packpack checkout 7cf23ee
|
||||||
|
|
||||||
# Patch packpack
|
# Patch packpack
|
||||||
patch --dry-run --silent -f -p1 < utils/packpack/packpack-rpm.patch
|
patch --dry-run --silent -f -p1 < utils/packpack/packpack-rpm.patch
|
||||||
|
@ -118,27 +105,40 @@ commonprep () {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# fix 32bit rpm builds
|
# fix 32bit rpm builds
|
||||||
patch --dry-run --silent -f -p1 < utils/packpack/setarch.patch
|
# FIXME: breaks arm rpm builds
|
||||||
if [ $? -eq 0 ]; then
|
#patch --dry-run --silent -f -p1 < utils/packpack/setarch.patch
|
||||||
patch -p1 < utils/packpack/setarch.patch
|
#if [ $? -eq 0 ]; then
|
||||||
fi
|
# patch -p1 < utils/packpack/setarch.patch
|
||||||
|
#fi
|
||||||
|
|
||||||
# The rpm specfile requires we download the tarball and manually move it into place
|
# The rpm specfile requires we download each submodule as a tarball then manually move it into place
|
||||||
# Might as well do this for Debian as well, rather than git submodule init
|
# Might as well do this for Debian as well, rather than git submodule init
|
||||||
CRUDVER="3.0.10"
|
CRUDVER="3.1.0-zm"
|
||||||
if [ -e "build/crud-${CRUDVER}.tar.gz" ]; then
|
if [ -e "build/crud-${CRUDVER}.tar.gz" ]; then
|
||||||
echo "Found existing Crud ${CRUDVER} tarball..."
|
echo "Found existing Crud ${CRUDVER} tarball..."
|
||||||
else
|
else
|
||||||
echo "Retrieving Crud ${CRUDVER} submodule..."
|
echo "Retrieving Crud ${CRUDVER} submodule..."
|
||||||
curl -L https://github.com/FriendsOfCake/crud/archive/v${CRUDVER}.tar.gz > build/crud-${CRUDVER}.tar.gz
|
curl -L https://github.com/ZoneMinder/crud/archive/v${CRUDVER}.tar.gz > build/crud-${CRUDVER}.tar.gz
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "ERROR: Crud tarball retreival failed..."
|
echo "ERROR: Crud tarball retreival failed..."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
CEBVER="1.0-zm"
|
||||||
|
if [ -e "build/cakephp-enum-behavior-${CEBVER}.tar.gz" ]; then
|
||||||
|
echo "Found existing CakePHP-Enum-Behavior ${CEBVER} tarball..."
|
||||||
|
else
|
||||||
|
echo "Retrieving CakePHP-Enum-Behavior ${CEBVER} submodule..."
|
||||||
|
curl -L https://github.com/ZoneMinder/CakePHP-Enum-Behavior/archive/${CEBVER}.tar.gz > build/cakephp-enum-behavior-${CEBVER}.tar.gz
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "ERROR: CakePHP-Enum-Behavior tarball retreival failed..."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Uncompress the Crud tarball and move it into place
|
# Uncompress the submodule tarballs and move them into place
|
||||||
movecrud () {
|
movecrud () {
|
||||||
if [ -e "web/api/app/Plugin/Crud/LICENSE.txt" ]; then
|
if [ -e "web/api/app/Plugin/Crud/LICENSE.txt" ]; then
|
||||||
echo "Crud plugin already installed..."
|
echo "Crud plugin already installed..."
|
||||||
|
@ -148,6 +148,14 @@ movecrud () {
|
||||||
rmdir web/api/app/Plugin/Crud
|
rmdir web/api/app/Plugin/Crud
|
||||||
mv -f crud-${CRUDVER} web/api/app/Plugin/Crud
|
mv -f crud-${CRUDVER} web/api/app/Plugin/Crud
|
||||||
fi
|
fi
|
||||||
|
if [ -e "web/api/app/Plugin/CakePHP-Enum-Behavior/readme.md" ]; then
|
||||||
|
echo "CakePHP-Enum-Behavior plugin already installed..."
|
||||||
|
else
|
||||||
|
echo "Unpacking CakePHP-Enum-Behavior plugin..."
|
||||||
|
tar -xzf build/cakephp-enum-behavior-${CEBVER}.tar.gz
|
||||||
|
rmdir web/api/app/Plugin/CakePHP-Enum-Behavior
|
||||||
|
mv -f crud-${CEBVER} web/api/app/Plugin/CakePHP-Enum-Behavior
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# previsouly part of installzm.sh
|
# previsouly part of installzm.sh
|
||||||
|
@ -259,10 +267,43 @@ execpackpack () {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Check for connectivity with the deploy target host
|
||||||
|
checkdeploytarget () {
|
||||||
|
echo
|
||||||
|
echo "Checking Internet connectivity with the deploy host ${DEPLOYTARGET}"
|
||||||
|
echo
|
||||||
|
|
||||||
|
ping -c 1 ${DEPLOYTARGET}
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo
|
||||||
|
echo "*** WARNING: THERE WAS A PROBLEM CONNECTING TO THE DEPLOY HOST ***"
|
||||||
|
echo
|
||||||
|
echo "Printing additional diagnostic information..."
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "*** NSLOOKUP ***"
|
||||||
|
echo
|
||||||
|
nslookup ${DEPLOYTARGET}
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "*** TRACEROUTE ***"
|
||||||
|
echo
|
||||||
|
traceroute -w 2 -m 15 ${DEPLOYTARGET}
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
################
|
################
|
||||||
# MAIN PROGRAM #
|
# MAIN PROGRAM #
|
||||||
################
|
################
|
||||||
|
|
||||||
|
# Set the hostname we will deploy packages to
|
||||||
|
DEPLOYTARGET="zmrepo.zoneminder.com"
|
||||||
|
|
||||||
|
# If we are running inside Travis then verify we can connect to the target host machine
|
||||||
|
if [ "${TRAVIS}" == "true" ]; then
|
||||||
|
checkdeploytarget
|
||||||
|
fi
|
||||||
checksanity
|
checksanity
|
||||||
|
|
||||||
# We don't want to build packages for all supported distros after every commit
|
# We don't want to build packages for all supported distros after every commit
|
||||||
|
@ -283,20 +324,12 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then
|
||||||
rm -rf web/api/app/Plugin/Crud
|
rm -rf web/api/app/Plugin/Crud
|
||||||
mkdir web/api/app/Plugin/Crud
|
mkdir web/api/app/Plugin/Crud
|
||||||
|
|
||||||
# We use zmrepo to build el6 only. All other redhat distros use rpm fusion
|
reporpm="rpmfusion-free-release"
|
||||||
if [ "${OS}" == "el" ] && [ "${DIST}" == "6" ]; then
|
dlurl="https://download1.rpmfusion.org/free/${OS}/${reporpm}-${DIST}.noarch.rpm"
|
||||||
baseurl="https://zmrepo.zoneminder.com/el/${DIST}/x86_64/"
|
|
||||||
reporpm="zmrepo"
|
|
||||||
# Let repoquery determine the full url and filename to the latest zmrepo package
|
|
||||||
dlurl=`repoquery --archlist=noarch --repofrompath=zmpackpack,${baseurl} --repoid=zmpackpack --qf="%{location}" ${reporpm} 2> /dev/null`
|
|
||||||
else
|
|
||||||
reporpm="rpmfusion-free-release"
|
|
||||||
dlurl="https://download1.rpmfusion.org/free/${OS}/${reporpm}-${DIST}.noarch.rpm"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Give our downloaded repo rpm a common name so redhat_package.mk can find it
|
# Give our downloaded repo rpm a common name so redhat_package.mk can find it
|
||||||
if [ -n "$dlurl" ] && [ $? -eq 0 ]; then
|
if [ -n "$dlurl" ] && [ $? -eq 0 ]; then
|
||||||
echo "Retrieving ${reporpm} repo rpm..."gd
|
echo "Retrieving ${reporpm} repo rpm..."
|
||||||
curl $dlurl > build/external-repo.noarch.rpm
|
curl $dlurl > build/external-repo.noarch.rpm
|
||||||
else
|
else
|
||||||
echo "ERROR: Failed to retrieve ${reporpm} repo rpm..."
|
echo "ERROR: Failed to retrieve ${reporpm} repo rpm..."
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
<IfModule mod_rewrite.c>
|
|
||||||
RewriteEngine on
|
|
||||||
RewriteRule ^$ app/webroot/ [L]
|
|
||||||
RewriteRule (.*) app/webroot/$1 [L]
|
|
||||||
</IfModule>
|
|
|
@ -109,83 +109,83 @@ $statusData = array(
|
||||||
'MaxScore' => true,
|
'MaxScore' => true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'event' => array(
|
'event' => array(
|
||||||
'permission' => 'Events',
|
'permission' => 'Events',
|
||||||
'table' => 'Events',
|
'table' => 'Events',
|
||||||
'limit' => 1,
|
'limit' => 1,
|
||||||
'selector' => 'Events.Id',
|
'selector' => 'Events.Id',
|
||||||
'elements' => array(
|
'elements' => array(
|
||||||
'Id' => array( 'sql' => 'Events.Id' ),
|
'Id' => array( 'sql' => 'Events.Id' ),
|
||||||
'MonitorId' => true,
|
'MonitorId' => true,
|
||||||
'MonitorName' => array('sql' => '(SELECT Monitors.Name FROM Monitors WHERE Monitors.Id = Events.MonitorId)'),
|
'MonitorName' => array('sql' => '(SELECT Monitors.Name FROM Monitors WHERE Monitors.Id = Events.MonitorId)'),
|
||||||
'Name' => true,
|
'Name' => true,
|
||||||
'Cause' => true,
|
'Cause' => true,
|
||||||
'StartTime' => true,
|
'StartTime' => true,
|
||||||
'StartTimeShort' => array( 'sql' => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ),
|
'StartTimeShort' => array( 'sql' => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ),
|
||||||
'EndTime' => true,
|
'EndTime' => true,
|
||||||
'Width' => true,
|
'Width' => true,
|
||||||
'Height' => true,
|
'Height' => true,
|
||||||
'Length' => true,
|
'Length' => true,
|
||||||
'Frames' => true,
|
'Frames' => true,
|
||||||
'DefaultVideo' => true,
|
'DefaultVideo' => true,
|
||||||
'AlarmFrames' => true,
|
'AlarmFrames' => true,
|
||||||
'TotScore' => true,
|
'TotScore' => true,
|
||||||
'AvgScore' => true,
|
'AvgScore' => true,
|
||||||
'MaxScore' => true,
|
'MaxScore' => true,
|
||||||
'Archived' => true,
|
'Archived' => true,
|
||||||
'Videoed' => true,
|
'Videoed' => true,
|
||||||
'Uploaded' => true,
|
'Uploaded' => true,
|
||||||
'Emailed' => true,
|
'Emailed' => true,
|
||||||
'Messaged' => true,
|
'Messaged' => true,
|
||||||
'Executed' => true,
|
'Executed' => true,
|
||||||
'Notes' => true,
|
'Notes' => true,
|
||||||
'MinFrameId' => array( 'sql' => '(SELECT min(Frames.FrameId) FROM Frames WHERE EventId=Events.Id)' ),
|
'MinFrameId' => array( 'sql' => '(SELECT min(Frames.FrameId) FROM Frames WHERE EventId=Events.Id)' ),
|
||||||
'MaxFrameId' => array( 'sql' => '(SELECT max(Frames.FrameId) FROM Frames WHERE Events.Id = Frames.EventId)' ),
|
'MaxFrameId' => array( 'sql' => '(SELECT max(Frames.FrameId) FROM Frames WHERE Events.Id = Frames.EventId)' ),
|
||||||
'MinFrameDelta' => array( 'sql' => '(SELECT min(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)' ),
|
'MinFrameDelta' => array( 'sql' => '(SELECT min(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)' ),
|
||||||
'MaxFrameDelta' => array( 'sql' => '(SELECT max(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)' ),
|
'MaxFrameDelta' => array( 'sql' => '(SELECT max(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)' ),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'frames' => array(
|
'frames' => array(
|
||||||
'permission' => 'Events',
|
'permission' => 'Events',
|
||||||
'table' => 'Frames',
|
'table' => 'Frames',
|
||||||
'selector' => 'EventId',
|
'selector' => 'EventId',
|
||||||
'elements' => array(
|
'elements' => array(
|
||||||
'EventId' => true,
|
'EventId' => true,
|
||||||
'FrameId' => true,
|
'FrameId' => true,
|
||||||
'Type' => true,
|
'Type' => true,
|
||||||
'Delta' => true,
|
'Delta' => true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'frame' => array(
|
'frame' => array(
|
||||||
'permission' => 'Events',
|
'permission' => 'Events',
|
||||||
'table' => 'Frames',
|
'table' => 'Frames',
|
||||||
'limit' => 1,
|
'limit' => 1,
|
||||||
'selector' => array( array( 'table' => 'Events', 'join' => 'Events.Id = Frames.EventId', 'selector'=>'Events.Id' ), 'Frames.FrameId' ),
|
'selector' => array( array( 'table' => 'Events', 'join' => 'Events.Id = Frames.EventId', 'selector'=>'Events.Id' ), 'Frames.FrameId' ),
|
||||||
'elements' => array(
|
'elements' => array(
|
||||||
//'Id' => array( 'sql' => 'Frames.FrameId' ),
|
//'Id' => array( 'sql' => 'Frames.FrameId' ),
|
||||||
'FrameId' => true,
|
'FrameId' => true,
|
||||||
'EventId' => true,
|
'EventId' => true,
|
||||||
'Type' => true,
|
'Type' => true,
|
||||||
'TimeStamp' => true,
|
'TimeStamp' => true,
|
||||||
'TimeStampShort' => array( 'sql' => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ),
|
'TimeStampShort' => array( 'sql' => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ),
|
||||||
'Delta' => true,
|
'Delta' => true,
|
||||||
'Score' => true,
|
'Score' => true,
|
||||||
//'Image' => array( 'postFunc' => 'getFrameImage' ),
|
//'Image' => array( 'postFunc' => 'getFrameImage' ),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'frameimage' => array(
|
'frameimage' => array(
|
||||||
'permission' => 'Events',
|
'permission' => 'Events',
|
||||||
'func' => 'getFrameImage()'
|
'func' => 'getFrameImage()'
|
||||||
),
|
),
|
||||||
'nearframe' => array(
|
'nearframe' => array(
|
||||||
'permission' => 'Events',
|
'permission' => 'Events',
|
||||||
'func' => 'getNearFrame()'
|
'func' => 'getNearFrame()'
|
||||||
),
|
),
|
||||||
'nearevents' => array(
|
'nearevents' => array(
|
||||||
'permission' => 'Events',
|
'permission' => 'Events',
|
||||||
'func' => 'getNearEvents()'
|
'func' => 'getNearEvents()'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
function collectData() {
|
function collectData() {
|
||||||
global $statusData;
|
global $statusData;
|
||||||
|
@ -302,8 +302,8 @@ function collectData() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#print_r( $data );
|
#Logger::Debug(print_r($data, true));
|
||||||
return( $data );
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = collectData();
|
$data = collectData();
|
||||||
|
@ -345,8 +345,8 @@ function getFrameImage() {
|
||||||
$eventId = $_REQUEST['id'][0];
|
$eventId = $_REQUEST['id'][0];
|
||||||
$frameId = $_REQUEST['id'][1];
|
$frameId = $_REQUEST['id'][1];
|
||||||
|
|
||||||
$sql = 'select * from Frames where EventId = ? and FrameId = ?';
|
$sql = 'SELECT * FROM Frames WHERE EventId = ? AND FrameId = ?';
|
||||||
if ( !($frame = dbFetchOne( $sql, NULL, array( $eventId, $frameId ) )) ) {
|
if ( !($frame = dbFetchOne( $sql, NULL, array($eventId, $frameId ) )) ) {
|
||||||
$frame = array();
|
$frame = array();
|
||||||
$frame['EventId'] = $eventId;
|
$frame['EventId'] = $eventId;
|
||||||
$frame['FrameId'] = $frameId;
|
$frame['FrameId'] = $frameId;
|
||||||
|
|
|
@ -145,7 +145,7 @@ if ( sem_acquire($semaphore,1) !== false ) {
|
||||||
}
|
}
|
||||||
case MSG_DATA_EVENT :
|
case MSG_DATA_EVENT :
|
||||||
{
|
{
|
||||||
$data = unpack( "ltype/ievent/iprogress/irate/izoom/Cpaused", $msg );
|
$data = unpack( "ltype/Pevent/iprogress/irate/izoom/Cpaused", $msg );
|
||||||
//$data['progress'] = sprintf( "%.2f", $data['progress'] );
|
//$data['progress'] = sprintf( "%.2f", $data['progress'] );
|
||||||
$data['rate'] /= RATE_BASE;
|
$data['rate'] /= RATE_BASE;
|
||||||
$data['zoom'] = round( $data['zoom']/SCALE_BASE, 1 );
|
$data['zoom'] = round( $data['zoom']/SCALE_BASE, 1 );
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
<IfModule mod_rewrite.c>
|
|
||||||
RewriteEngine on
|
|
||||||
RewriteRule ^$ app/webroot/ [L]
|
|
||||||
RewriteRule (.*) app/webroot/$1 [L]
|
|
||||||
RewriteBase /zm/api
|
|
||||||
</IfModule>
|
|
|
@ -1,6 +0,0 @@
|
||||||
<IfModule mod_rewrite.c>
|
|
||||||
RewriteEngine on
|
|
||||||
RewriteRule ^$ webroot/ [L]
|
|
||||||
RewriteRule (.*) webroot/$1 [L]
|
|
||||||
RewriteBase /zm/api
|
|
||||||
</IfModule>
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 1351dde6b4c75b215099ae8bcf5a21d6c6e10298
|
Subproject commit c3976f1478c681b0bbc132ec3a3e82c3984eeed5
|
|
@ -1,7 +0,0 @@
|
||||||
<IfModule mod_rewrite.c>
|
|
||||||
RewriteEngine On
|
|
||||||
RewriteCond %{REQUEST_FILENAME} !-d
|
|
||||||
RewriteCond %{REQUEST_FILENAME} !-f
|
|
||||||
RewriteRule ^ index.php [L]
|
|
||||||
RewriteBase /zm/api
|
|
||||||
</IfModule>
|
|
|
@ -1,5 +0,0 @@
|
||||||
<IfModule mod_rewrite.c>
|
|
||||||
RewriteEngine on
|
|
||||||
RewriteRule ^$ webroot/ [L]
|
|
||||||
RewriteRule (.*) webroot/$1 [L]
|
|
||||||
</IfModule>
|
|
|
@ -1,30 +1,30 @@
|
||||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
::
|
::
|
||||||
:: Bake is a shell script for running CakePHP bake script
|
:: Bake is a shell script for running CakePHP bake script
|
||||||
::
|
::
|
||||||
:: CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
:: CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||||
:: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
:: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||||
::
|
::
|
||||||
:: Licensed under The MIT License
|
:: Licensed under The MIT License
|
||||||
:: Redistributions of files must retain the above copyright notice.
|
:: Redistributions of files must retain the above copyright notice.
|
||||||
::
|
::
|
||||||
:: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
:: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||||
:: @link https://cakephp.org CakePHP(tm) Project
|
:: @link https://cakephp.org CakePHP(tm) Project
|
||||||
:: @package app.Console
|
:: @package app.Console
|
||||||
:: @since CakePHP(tm) v 2.0
|
:: @since CakePHP(tm) v 2.0
|
||||||
::
|
::
|
||||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
|
||||||
:: In order for this script to work as intended, the cake\console\ folder must be in your PATH
|
:: In order for this script to work as intended, the cake\console\ folder must be in your PATH
|
||||||
|
|
||||||
@echo.
|
@echo.
|
||||||
@echo off
|
@echo off
|
||||||
|
|
||||||
SET app=%0
|
SET app=%0
|
||||||
SET lib=%~dp0
|
SET lib=%~dp0
|
||||||
|
|
||||||
php -q "%lib%cake.php" -working "%CD% " %*
|
php -q "%lib%cake.php" -working "%CD% " %*
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
|
|
||||||
exit /B %ERRORLEVEL%
|
exit /B %ERRORLEVEL%
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
<IfModule mod_rewrite.c>
|
|
||||||
RewriteEngine On
|
|
||||||
RewriteCond %{REQUEST_FILENAME} !-d
|
|
||||||
RewriteCond %{REQUEST_FILENAME} !-f
|
|
||||||
RewriteRule ^ index.php [L]
|
|
||||||
</IfModule>
|
|
|
@ -1,28 +1,28 @@
|
||||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
::
|
::
|
||||||
:: Bake is a shell script for running CakePHP bake script
|
:: Bake is a shell script for running CakePHP bake script
|
||||||
::
|
::
|
||||||
:: CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
:: CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
||||||
:: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
:: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||||
::
|
::
|
||||||
:: Licensed under The MIT License
|
:: Licensed under The MIT License
|
||||||
:: Redistributions of files must retain the above copyright notice.
|
:: Redistributions of files must retain the above copyright notice.
|
||||||
::
|
::
|
||||||
:: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
:: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
||||||
:: @link https://cakephp.org CakePHP(tm) Project
|
:: @link https://cakephp.org CakePHP(tm) Project
|
||||||
:: @package Cake.Console
|
:: @package Cake.Console
|
||||||
:: @since CakePHP(tm) v 1.2.0.5012
|
:: @since CakePHP(tm) v 1.2.0.5012
|
||||||
:: @license https://opensource.org/licenses/mit-license.php MIT License
|
:: @license https://opensource.org/licenses/mit-license.php MIT License
|
||||||
::
|
::
|
||||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
|
||||||
@echo off
|
@echo off
|
||||||
|
|
||||||
SET app=%0
|
SET app=%0
|
||||||
SET lib=%~dp0
|
SET lib=%~dp0
|
||||||
|
|
||||||
php -q "%lib%cake.php" -working "%CD% " %*
|
php -q "%lib%cake.php" -working "%CD% " %*
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
|
|
||||||
exit /B %ERRORLEVEL%
|
exit /B %ERRORLEVEL%
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
$event_cache = array();
|
||||||
|
|
||||||
class Event {
|
class Event {
|
||||||
|
|
||||||
private $fields = array(
|
private $fields = array(
|
||||||
|
@ -15,12 +17,12 @@ class Event {
|
||||||
public function __construct( $IdOrRow = null ) {
|
public function __construct( $IdOrRow = null ) {
|
||||||
$row = NULL;
|
$row = NULL;
|
||||||
if ( $IdOrRow ) {
|
if ( $IdOrRow ) {
|
||||||
if ( is_integer( $IdOrRow ) or is_numeric( $IdOrRow ) ) {
|
if ( is_integer($IdOrRow) or is_numeric($IdOrRow) ) {
|
||||||
$row = dbFetchOne( 'SELECT *,unix_timestamp(StartTime) as Time FROM Events WHERE Id=?', NULL, array( $IdOrRow ) );
|
$row = dbFetchOne('SELECT *,unix_timestamp(StartTime) as Time FROM Events WHERE Id=?', NULL, array($IdOrRow));
|
||||||
if ( ! $row ) {
|
if ( ! $row ) {
|
||||||
Error('Unable to load Event record for Id=' . $IdOrRow );
|
Error('Unable to load Event record for Id=' . $IdOrRow );
|
||||||
}
|
}
|
||||||
} elseif ( is_array( $IdOrRow ) ) {
|
} elseif ( is_array($IdOrRow) ) {
|
||||||
$row = $IdOrRow;
|
$row = $IdOrRow;
|
||||||
} else {
|
} else {
|
||||||
$backTrace = debug_backtrace();
|
$backTrace = debug_backtrace();
|
||||||
|
@ -31,16 +33,18 @@ class Event {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $row ) {
|
if ( $row ) {
|
||||||
foreach ($row as $k => $v) {
|
foreach ($row as $k => $v) {
|
||||||
$this->{$k} = $v;
|
$this->{$k} = $v;
|
||||||
}
|
}
|
||||||
} else {
|
global $event_cache;
|
||||||
|
$event_cache[$row['Id']] = $this;
|
||||||
|
} else {
|
||||||
$backTrace = debug_backtrace();
|
$backTrace = debug_backtrace();
|
||||||
$file = $backTrace[1]['file'];
|
$file = $backTrace[1]['file'];
|
||||||
$line = $backTrace[1]['line'];
|
$line = $backTrace[1]['line'];
|
||||||
Error('No row for Event ' . $IdOrRow . " from $file:$line");
|
Error('No row for Event ' . $IdOrRow . " from $file:$line");
|
||||||
}
|
}
|
||||||
} # end if isset($IdOrRow)
|
} # end if isset($IdOrRow)
|
||||||
} // end function __construct
|
} // end function __construct
|
||||||
|
|
||||||
|
@ -48,10 +52,11 @@ class Event {
|
||||||
if ( $new ) {
|
if ( $new ) {
|
||||||
$this->{'Storage'} = $new;
|
$this->{'Storage'} = $new;
|
||||||
}
|
}
|
||||||
if ( ! ( array_key_exists( 'Storage', $this ) and $this->{'Storage'} ) ) {
|
if ( ! ( array_key_exists('Storage', $this) and $this->{'Storage'} ) ) {
|
||||||
$this->{'Storage'} = isset($this->{'StorageId'}) ?
|
if ( isset($this->{'StorageId'}) and $this->{'StorageId'} )
|
||||||
Storage::find_one(array('Id'=>$this->{'StorageId'})) :
|
$this->{'Storage'} = Storage::find_one(array('Id'=>$this->{'StorageId'}));
|
||||||
new Storage(NULL);
|
if ( ! ( array_key_exists('Storage', $this) and $this->{'Storage'} ) )
|
||||||
|
$this->{'Storage'} = new Storage(NULL);
|
||||||
}
|
}
|
||||||
return $this->{'Storage'};
|
return $this->{'Storage'};
|
||||||
}
|
}
|
||||||
|
@ -70,12 +75,12 @@ class Event {
|
||||||
$backTrace = debug_backtrace();
|
$backTrace = debug_backtrace();
|
||||||
$file = $backTrace[1]['file'];
|
$file = $backTrace[1]['file'];
|
||||||
$line = $backTrace[1]['line'];
|
$line = $backTrace[1]['line'];
|
||||||
Warning( "Unknown function call Event->$fn from $file:$line" );
|
Warning("Unknown function call Event->$fn from $file:$line");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function Time() {
|
public function Time() {
|
||||||
if ( ! isset( $this->{'Time'} ) ) {
|
if ( ! isset($this->{'Time'}) ) {
|
||||||
$this->{'Time'} = strtotime($this->{'StartTime'});
|
$this->{'Time'} = strtotime($this->{'StartTime'});
|
||||||
}
|
}
|
||||||
return $this->{'Time'};
|
return $this->{'Time'};
|
||||||
|
@ -97,7 +102,7 @@ class Event {
|
||||||
$event_path = $this->{'MonitorId'} .'/'.$this->{'Id'};
|
$event_path = $this->{'MonitorId'} .'/'.$this->{'Id'};
|
||||||
}
|
}
|
||||||
|
|
||||||
return( $event_path );
|
return $event_path;
|
||||||
} // end function Relative_Path()
|
} // end function Relative_Path()
|
||||||
|
|
||||||
public function Link_Path() {
|
public function Link_Path() {
|
||||||
|
@ -161,6 +166,8 @@ class Event {
|
||||||
} # end Event->delete
|
} # end Event->delete
|
||||||
|
|
||||||
public function getStreamSrc( $args=array(), $querySep='&' ) {
|
public function getStreamSrc( $args=array(), $querySep='&' ) {
|
||||||
|
|
||||||
|
|
||||||
if ( $this->{'DefaultVideo'} and $args['mode'] != 'jpeg' ) {
|
if ( $this->{'DefaultVideo'} and $args['mode'] != 'jpeg' ) {
|
||||||
$streamSrc = ZM_BASE_PROTOCOL.'://';
|
$streamSrc = ZM_BASE_PROTOCOL.'://';
|
||||||
$Monitor = $this->Monitor();
|
$Monitor = $this->Monitor();
|
||||||
|
@ -174,7 +181,19 @@ class Event {
|
||||||
$args['eid'] = $this->{'Id'};
|
$args['eid'] = $this->{'Id'};
|
||||||
$args['view'] = 'view_video';
|
$args['view'] = 'view_video';
|
||||||
} else {
|
} else {
|
||||||
$streamSrc = ZM_BASE_URL.ZM_PATH_ZMS;
|
$streamSrc = ZM_BASE_PROTOCOL.'://';
|
||||||
|
if ( $this->Storage()->ServerId() ) {
|
||||||
|
$Server = $this->Storage()->Server();
|
||||||
|
$streamSrc .= $Server->Hostname();
|
||||||
|
if ( ZM_MIN_STREAMING_PORT ) {
|
||||||
|
$streamSrc .= ':'.(ZM_MIN_STREAMING_PORT+$this->{'MonitorId'});
|
||||||
|
}
|
||||||
|
} else if ( ZM_MIN_STREAMING_PORT ) {
|
||||||
|
$streamSrc .= $_SERVER['SERVER_NAME'].':'.(ZM_MIN_STREAMING_PORT+$this->{'MonitorId'});
|
||||||
|
} else {
|
||||||
|
$streamSrc .= $_SERVER['HTTP_HOST'];
|
||||||
|
}
|
||||||
|
$streamSrc .= ZM_PATH_ZMS;
|
||||||
|
|
||||||
$args['source'] = 'event';
|
$args['source'] = 'event';
|
||||||
$args['event'] = $this->{'Id'};
|
$args['event'] = $this->{'Id'};
|
||||||
|
@ -207,8 +226,8 @@ class Event {
|
||||||
$this->{'DiskSpace'} = $new;
|
$this->{'DiskSpace'} = $new;
|
||||||
}
|
}
|
||||||
if ( null === $this->{'DiskSpace'} ) {
|
if ( null === $this->{'DiskSpace'} ) {
|
||||||
$this->{'DiskSpace'} = folder_size( $this->Path() );
|
$this->{'DiskSpace'} = folder_size($this->Path());
|
||||||
dbQuery( 'UPDATE Events SET DiskSpace=? WHERE Id=?', array( $this->{'DiskSpace'}, $this->{'Id'} ) );
|
dbQuery('UPDATE Events SET DiskSpace=? WHERE Id=?', array($this->{'DiskSpace'}, $this->{'Id'}));
|
||||||
}
|
}
|
||||||
return $this->{'DiskSpace'};
|
return $this->{'DiskSpace'};
|
||||||
}
|
}
|
||||||
|
@ -253,7 +272,7 @@ class Event {
|
||||||
|
|
||||||
// frame is an array representing the db row for a frame.
|
// frame is an array representing the db row for a frame.
|
||||||
function getImageSrc($frame, $scale=SCALE_BASE, $captureOnly=false, $overwrite=false) {
|
function getImageSrc($frame, $scale=SCALE_BASE, $captureOnly=false, $overwrite=false) {
|
||||||
$Storage = new Storage(isset($this->{'StorageId'}) ? $this->{'StorageId'} : NULL);
|
$Storage = $this->Storage();
|
||||||
$Event = $this;
|
$Event = $this;
|
||||||
$eventPath = $Event->Path();
|
$eventPath = $Event->Path();
|
||||||
|
|
||||||
|
@ -370,6 +389,25 @@ class Event {
|
||||||
return $imageData;
|
return $imageData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function find_one( $parameters = null, $options = null ) {
|
||||||
|
global $event_cache;
|
||||||
|
if (
|
||||||
|
( count($parameters) == 1 ) and
|
||||||
|
isset($parameters['Id']) and
|
||||||
|
isset($event_cache[$parameters['Id']]) ) {
|
||||||
|
return $event_cache[$parameters['Id']];
|
||||||
|
}
|
||||||
|
$results = Event::find_all( $parameters, $options );
|
||||||
|
if ( count($results) > 1 ) {
|
||||||
|
Error("Event Returned more than 1");
|
||||||
|
return $results[0];
|
||||||
|
} else if ( count($results) ) {
|
||||||
|
return $results[0];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static function find_all( $parameters = null, $options = null ) {
|
public static function find_all( $parameters = null, $options = null ) {
|
||||||
$filters = array();
|
$filters = array();
|
||||||
$sql = 'SELECT * FROM Events ';
|
$sql = 'SELECT * FROM Events ';
|
||||||
|
|
|
@ -73,18 +73,19 @@ class Frame {
|
||||||
$file = $backTrace[1]['file'];
|
$file = $backTrace[1]['file'];
|
||||||
$line = $backTrace[1]['line'];
|
$line = $backTrace[1]['line'];
|
||||||
Error("Invalid value for limit($limit) passed to Frame::find from $file:$line");
|
Error("Invalid value for limit($limit) passed to Frame::find from $file:$line");
|
||||||
return;
|
return array();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$results = dbFetchAll( $sql, NULL, $values );
|
$results = dbFetchAll($sql, NULL, $values);
|
||||||
if ( $results ) {
|
if ( $results ) {
|
||||||
return array_map( function($id){ return new Frame($id); }, $results );
|
return array_map( function($id){ return new Frame($id); }, $results );
|
||||||
}
|
}
|
||||||
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function find_one( $parameters = array() ) {
|
public static function find_one( $parameters = array() ) {
|
||||||
$results = Frame::find( $parameters, 1 );
|
$results = Frame::find( $parameters, 1 );
|
||||||
if ( ! sizeof( $results ) ) {
|
if ( ! sizeof($results) ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return $results[0];
|
return $results[0];
|
||||||
|
|
|
@ -20,7 +20,7 @@ class Group {
|
||||||
if ( ! $row ) {
|
if ( ! $row ) {
|
||||||
Error('Unable to load Group record for Id=' . $IdOrRow);
|
Error('Unable to load Group record for Id=' . $IdOrRow);
|
||||||
}
|
}
|
||||||
} elseif ( is_array( $IdOrRow ) ) {
|
} elseif ( is_array($IdOrRow) ) {
|
||||||
$row = $IdOrRow;
|
$row = $IdOrRow;
|
||||||
} else {
|
} else {
|
||||||
$backTrace = debug_backtrace();
|
$backTrace = debug_backtrace();
|
||||||
|
@ -36,8 +36,8 @@ class Group {
|
||||||
foreach ($row as $k => $v) {
|
foreach ($row as $k => $v) {
|
||||||
$this->{$k} = $v;
|
$this->{$k} = $v;
|
||||||
}
|
}
|
||||||
|
$group_cache[$row['Id']] = $this;
|
||||||
}
|
}
|
||||||
$group_cache[$row['Id']] = $this;
|
|
||||||
} // end function __construct
|
} // end function __construct
|
||||||
|
|
||||||
public function __call($fn, array $args) {
|
public function __call($fn, array $args) {
|
||||||
|
@ -58,7 +58,7 @@ class Group {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function find_one( $parameters = null, $options = null ) {
|
public static function find_one($parameters = null, $options = null) {
|
||||||
global $group_cache;
|
global $group_cache;
|
||||||
if (
|
if (
|
||||||
( count($parameters) == 1 ) and
|
( count($parameters) == 1 ) and
|
||||||
|
@ -109,13 +109,13 @@ class Group {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete() {
|
public function delete() {
|
||||||
if ( array_key_exists( 'Id', $this ) ) {
|
if ( array_key_exists('Id', $this) ) {
|
||||||
dbQuery( 'DELETE FROM Groups WHERE Id=?', array($this->{'Id'}) );
|
|
||||||
dbQuery( 'DELETE FROM Groups_Monitors WHERE GroupId=?', array($this->{'Id'}) );
|
dbQuery( 'DELETE FROM Groups_Monitors WHERE GroupId=?', array($this->{'Id'}) );
|
||||||
|
dbQuery( 'DELETE FROM Groups WHERE Id=?', array($this->{'Id'}) );
|
||||||
if ( isset($_COOKIE['zmGroup']) ) {
|
if ( isset($_COOKIE['zmGroup']) ) {
|
||||||
if ( $this->{'Id'} == $_COOKIE['zmGroup'] ) {
|
if ( $this->{'Id'} == $_COOKIE['zmGroup'] ) {
|
||||||
unset( $_COOKIE['zmGroup'] );
|
unset($_COOKIE['zmGroup']);
|
||||||
setcookie( 'zmGroup', '', time()-3600*24*2 );
|
setcookie('zmGroup', '', time()-3600*24*2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,16 +123,16 @@ class Group {
|
||||||
|
|
||||||
public function set( $data ) {
|
public function set( $data ) {
|
||||||
foreach ($data as $k => $v) {
|
foreach ($data as $k => $v) {
|
||||||
if ( is_array( $v ) ) {
|
if ( is_array($v) ) {
|
||||||
$this->{$k} = $v;
|
$this->{$k} = $v;
|
||||||
} else if ( is_string( $v ) ) {
|
} else if ( is_string($v) ) {
|
||||||
$this->{$k} = trim( $v );
|
$this->{$k} = trim( $v );
|
||||||
} else if ( is_integer( $v ) ) {
|
} else if ( is_integer($v) ) {
|
||||||
$this->{$k} = $v;
|
$this->{$k} = $v;
|
||||||
} else if ( is_bool( $v ) ) {
|
} else if ( is_bool($v) ) {
|
||||||
$this->{$k} = $v;
|
$this->{$k} = $v;
|
||||||
} else {
|
} else {
|
||||||
Error( "Unknown type $k => $v of var " . gettype( $v ) );
|
Error("Unknown type $k => $v of var " . gettype($v));
|
||||||
$this->{$k} = $v;
|
$this->{$k} = $v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,10 +141,10 @@ class Group {
|
||||||
if ( isset($new) ) {
|
if ( isset($new) ) {
|
||||||
$this->{'depth'} = $new;
|
$this->{'depth'} = $new;
|
||||||
}
|
}
|
||||||
if ( ! array_key_exists( 'depth', $this ) or ( $this->{'depth'} == null ) ) {
|
if ( ! array_key_exists('depth', $this) or ($this->{'depth'} == null) ) {
|
||||||
$this->{'depth'} = 1;
|
$this->{'depth'} = 1;
|
||||||
if ( $this->{'ParentId'} != null ) {
|
if ( $this->{'ParentId'} != null ) {
|
||||||
$Parent = new Group( $this->{'ParentId'} );
|
$Parent = Group::find_one(array('Id'=>$this->{'ParentId'}));
|
||||||
$this->{'depth'} += $Parent->depth();
|
$this->{'depth'} += $Parent->depth();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,8 +152,8 @@ class Group {
|
||||||
} // end public function depth
|
} // end public function depth
|
||||||
|
|
||||||
public function MonitorIds( ) {
|
public function MonitorIds( ) {
|
||||||
if ( ! array_key_exists( 'MonitorIds', $this ) ) {
|
if ( ! array_key_exists('MonitorIds', $this) ) {
|
||||||
$this->{'MonitorIds'} = dbFetchAll( 'SELECT MonitorId FROM Groups_Monitors WHERE GroupId=?', 'MonitorId', array($this->{'Id'}) );
|
$this->{'MonitorIds'} = dbFetchAll('SELECT MonitorId FROM Groups_Monitors WHERE GroupId=?', 'MonitorId', array($this->{'Id'}));
|
||||||
}
|
}
|
||||||
return $this->{'MonitorIds'};
|
return $this->{'MonitorIds'};
|
||||||
}
|
}
|
||||||
|
@ -198,12 +198,12 @@ class Group {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_options( $Group ) {
|
function get_options($Group) {
|
||||||
global $children;
|
global $children;
|
||||||
$options = array( $Group->Id() => str_repeat(' ', $Group->depth() ) . $Group->Name() );
|
$options = array($Group->Id() => str_repeat(' ', $Group->depth()) . $Group->Name());
|
||||||
if ( isset($children[$Group->Id()]) ) {
|
if ( isset($children[$Group->Id()]) ) {
|
||||||
foreach ( $children[$Group->Id()] as $child ) {
|
foreach ( $children[$Group->Id()] as $child ) {
|
||||||
$options += get_options( $child );
|
$options += get_options($child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $options;
|
return $options;
|
||||||
|
@ -211,83 +211,34 @@ class Group {
|
||||||
$group_options = array();
|
$group_options = array();
|
||||||
foreach ( $Groups as $id=>$Group ) {
|
foreach ( $Groups as $id=>$Group ) {
|
||||||
if ( ! $Group->ParentId() ) {
|
if ( ! $Group->ParentId() ) {
|
||||||
$group_options += get_options( $Group );
|
$group_options += get_options($Group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $group_options;
|
return $group_options;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function get_group_dropdowns( $selected = null ) {
|
public static function get_group_sql($group_id) {
|
||||||
# This will end up with the group_id of the deepest selection
|
|
||||||
$group_id = 0;
|
|
||||||
$depth = 0;
|
|
||||||
$groups = array();
|
|
||||||
$parent_group_ids = null;
|
|
||||||
session_start();
|
|
||||||
|
|
||||||
$group_options = array(0=>'All');
|
|
||||||
while(1) {
|
|
||||||
$Groups = Group::find_all( array('ParentId'=>$parent_group_ids) );
|
|
||||||
if ( ! count( $Groups ) )
|
|
||||||
break;
|
|
||||||
|
|
||||||
$parent_group_ids = array();
|
|
||||||
if ( ! $selected ) {
|
|
||||||
$selected_group_id = 0;
|
|
||||||
if ( isset($_REQUEST['group'.$depth]) ) {
|
|
||||||
$selected_group_id = $group_id = $_SESSION['group'.$depth] = $_REQUEST['group'.$depth];
|
|
||||||
} else if ( isset( $_SESSION['group'.$depth] ) ) {
|
|
||||||
$selected_group_id = $group_id = $_SESSION['group'.$depth];
|
|
||||||
} else if ( isset($_REQUEST['filtering']) ) {
|
|
||||||
unset($_SESSION['group'.$depth]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$selected_group_id = $selected;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ( $Groups as $Group ) {
|
|
||||||
if ( ! isset( $groups[$depth] ) ) {
|
|
||||||
$groups[$depth] = array(0=>'All');
|
|
||||||
}
|
|
||||||
$group_options[$Group->Id()] = str_repeat( ' ', $depth ) . $Group->Name();
|
|
||||||
$groups[$depth][$Group->Id()] = $Group->Name();
|
|
||||||
if ( $selected_group_id and ( $selected_group_id == $Group->Id() ) )
|
|
||||||
$parent_group_ids[] = $Group->Id();
|
|
||||||
}
|
|
||||||
|
|
||||||
//echo htmlSelect( 'group'.$depth, $groups[$depth], $selected_group_id, "this.form.submit();" );
|
|
||||||
if ( ! count($parent_group_ids) ) break;
|
|
||||||
$depth += 1;
|
|
||||||
}
|
|
||||||
echo htmlSelect( 'groups', $group_options, $selected_group_id, 'this.form.submit();' );
|
|
||||||
session_write_close();
|
|
||||||
|
|
||||||
return $group_id;
|
|
||||||
} # end public static function get_group_dropdowns()
|
|
||||||
|
|
||||||
|
|
||||||
public static function get_group_sql( $group_id ) {
|
|
||||||
$groupSql = '';
|
$groupSql = '';
|
||||||
if ( $group_id ) {
|
if ( $group_id ) {
|
||||||
if ( is_array( $group_id ) ) {
|
if ( is_array($group_id) ) {
|
||||||
$group_id_sql_part = ' IN ('.implode(',', array_map(function(){return '?';}, $group_id ) ).')';
|
$group_id_sql_part = ' IN ('.implode(',', array_map(function(){return '?';}, $group_id ) ).')';
|
||||||
|
|
||||||
$MonitorIds = dbFetchAll( 'SELECT MonitorId FROM Groups_Monitors WHERE GroupId'.$group_id_sql_part, 'MonitorId', $group_id );
|
$MonitorIds = dbFetchAll('SELECT MonitorId FROM Groups_Monitors WHERE GroupId'.$group_id_sql_part, 'MonitorId', $group_id);
|
||||||
|
|
||||||
$MonitorIds = array_merge( $MonitorIds, dbFetchAll( 'SELECT MonitorId FROM Groups_Monitors WHERE GroupId IN (SELECT Id FROM Groups WHERE ParentId'.$group_id_sql_part.')', 'MonitorId', $group_id ) );
|
$MonitorIds = array_merge($MonitorIds, dbFetchAll('SELECT MonitorId FROM Groups_Monitors WHERE GroupId IN (SELECT Id FROM Groups WHERE ParentId'.$group_id_sql_part.')', 'MonitorId', $group_id));
|
||||||
} else {
|
} else {
|
||||||
$MonitorIds = dbFetchAll( 'SELECT MonitorId FROM Groups_Monitors WHERE GroupId=?', 'MonitorId', array($group_id) );
|
$MonitorIds = dbFetchAll('SELECT MonitorId FROM Groups_Monitors WHERE GroupId=?', 'MonitorId', array($group_id));
|
||||||
|
|
||||||
$MonitorIds = array_merge( $MonitorIds, dbFetchAll( 'SELECT MonitorId FROM Groups_Monitors WHERE GroupId IN (SELECT Id FROM Groups WHERE ParentId = ?)', 'MonitorId', array($group_id) ) );
|
$MonitorIds = array_merge($MonitorIds, dbFetchAll('SELECT MonitorId FROM Groups_Monitors WHERE GroupId IN (SELECT Id FROM Groups WHERE ParentId = ?)', 'MonitorId', array($group_id)));
|
||||||
}
|
}
|
||||||
$groupSql = " find_in_set( M.Id, '".implode( ',', $MonitorIds )."' )";
|
$groupSql = " find_in_set( M.Id, '".implode(',', $MonitorIds)."' )";
|
||||||
}
|
}
|
||||||
return $groupSql;
|
return $groupSql;
|
||||||
} # end public static function get_group_sql( $group_id )
|
} # end public static function get_group_sql( $group_id )
|
||||||
|
|
||||||
public static function get_monitors_dropdown( $options = null ) {
|
public static function get_monitors_dropdown($options = null) {
|
||||||
$monitor_id = 0;
|
$monitor_id = 0;
|
||||||
if ( isset( $_REQUEST['monitor_id'] ) ) {
|
if ( isset($_REQUEST['monitor_id']) ) {
|
||||||
$monitor_id = $_REQUEST['monitor_id'];
|
$monitor_id = $_REQUEST['monitor_id'];
|
||||||
} else if ( isset($_COOKIE['zmMonitorId']) ) {
|
} else if ( isset($_COOKIE['zmMonitorId']) ) {
|
||||||
$monitor_id = $_COOKIE['zmMonitorId'];
|
$monitor_id = $_COOKIE['zmMonitorId'];
|
||||||
|
@ -300,14 +251,14 @@ $group_options[$Group->Id()] = str_repeat( ' ', $depth ) . $Group->Name();
|
||||||
}
|
}
|
||||||
$monitors_dropdown = array(''=>'All');
|
$monitors_dropdown = array(''=>'All');
|
||||||
|
|
||||||
foreach ( dbFetchAll( $sql ) as $monitor ) {
|
foreach ( dbFetchAll($sql) as $monitor ) {
|
||||||
if ( !visibleMonitor( $monitor['Id'] ) ) {
|
if ( !visibleMonitor($monitor['Id']) ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$monitors_dropdown[$monitor['Id']] = $monitor['Name'];
|
$monitors_dropdown[$monitor['Id']] = $monitor['Name'];
|
||||||
}
|
}
|
||||||
|
|
||||||
echo htmlSelect( 'monitor_id', $monitors_dropdown, $monitor_id, array('onchange'=>'changeMonitor(this);') );
|
echo htmlSelect('monitor_id', $monitors_dropdown, $monitor_id, array('onchange'=>'changeMonitor(this);'));
|
||||||
return $monitor_id;
|
return $monitor_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,6 +280,4 @@ public function Parents() {
|
||||||
}
|
}
|
||||||
|
|
||||||
} # end class Group
|
} # end class Group
|
||||||
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -27,6 +27,7 @@ private $defaults = array(
|
||||||
private $status_fields = array(
|
private $status_fields = array(
|
||||||
'AnalysisFPS' => null,
|
'AnalysisFPS' => null,
|
||||||
'CaptureFPS' => null,
|
'CaptureFPS' => null,
|
||||||
|
'CaptureBandwidth' => null,
|
||||||
);
|
);
|
||||||
private $control_fields = array(
|
private $control_fields = array(
|
||||||
'Name' => '',
|
'Name' => '',
|
||||||
|
@ -171,6 +172,7 @@ private $control_fields = array(
|
||||||
}
|
}
|
||||||
} # end if isset($IdOrRow)
|
} # end if isset($IdOrRow)
|
||||||
} // end function __construct
|
} // end function __construct
|
||||||
|
|
||||||
public function Server() {
|
public function Server() {
|
||||||
return new Server( $this->{'ServerId'} );
|
return new Server( $this->{'ServerId'} );
|
||||||
}
|
}
|
||||||
|
@ -182,7 +184,7 @@ private $control_fields = array(
|
||||||
return $this->{$fn};
|
return $this->{$fn};
|
||||||
#array_unshift($args, $this);
|
#array_unshift($args, $this);
|
||||||
#call_user_func_array( $this->{$fn}, $args);
|
#call_user_func_array( $this->{$fn}, $args);
|
||||||
} else {
|
} else {
|
||||||
if ( array_key_exists($fn, $this->control_fields) ) {
|
if ( array_key_exists($fn, $this->control_fields) ) {
|
||||||
return $this->control_fields{$fn};
|
return $this->control_fields{$fn};
|
||||||
} else if ( array_key_exists( $fn, $this->defaults ) ) {
|
} else if ( array_key_exists( $fn, $this->defaults ) ) {
|
||||||
|
@ -255,22 +257,26 @@ private $control_fields = array(
|
||||||
return $this->{'Height'};
|
return $this->{'Height'};
|
||||||
}
|
}
|
||||||
|
|
||||||
public function set( $data ) {
|
public function set($data) {
|
||||||
foreach ($data as $k => $v) {
|
foreach ($data as $k => $v) {
|
||||||
if ( is_array( $v ) ) {
|
if ( method_exists($this, $k) ) {
|
||||||
# perhaps should turn into a comma-separated string
|
$this->{$k}($v);
|
||||||
$this->{$k} = implode(',',$v);
|
|
||||||
} else if ( is_string( $v ) ) {
|
|
||||||
$this->{$k} = trim( $v );
|
|
||||||
} else if ( is_integer( $v ) ) {
|
|
||||||
$this->{$k} = $v;
|
|
||||||
} else if ( is_bool( $v ) ) {
|
|
||||||
$this->{$k} = $v;
|
|
||||||
} else {
|
} else {
|
||||||
Error( "Unknown type $k => $v of var " . gettype( $v ) );
|
if ( is_array( $v ) ) {
|
||||||
$this->{$k} = $v;
|
# perhaps should turn into a comma-separated string
|
||||||
}
|
$this->{$k} = implode(',',$v);
|
||||||
}
|
} else if ( is_string( $v ) ) {
|
||||||
|
$this->{$k} = trim( $v );
|
||||||
|
} else if ( is_integer( $v ) ) {
|
||||||
|
$this->{$k} = $v;
|
||||||
|
} else if ( is_bool( $v ) ) {
|
||||||
|
$this->{$k} = $v;
|
||||||
|
} else {
|
||||||
|
Error( "Unknown type $k => $v of var " . gettype( $v ) );
|
||||||
|
$this->{$k} = $v;
|
||||||
|
}
|
||||||
|
} # end if method_exists
|
||||||
|
} # end foreach $data as $k=>$v
|
||||||
}
|
}
|
||||||
public static function find_all( $parameters = null, $options = null ) {
|
public static function find_all( $parameters = null, $options = null ) {
|
||||||
$filters = array();
|
$filters = array();
|
||||||
|
@ -306,7 +312,7 @@ private $control_fields = array(
|
||||||
return $filters;
|
return $filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save( $new_values = null ) {
|
public function save($new_values = null) {
|
||||||
|
|
||||||
if ( $new_values ) {
|
if ( $new_values ) {
|
||||||
foreach ( $new_values as $k=>$v ) {
|
foreach ( $new_values as $k=>$v ) {
|
||||||
|
@ -314,12 +320,12 @@ private $control_fields = array(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$fields = array_keys( $this->defaults );
|
$fields = array_keys($this->defaults);
|
||||||
|
|
||||||
$sql = 'UPDATE Monitors SET '.implode(', ', array_map( function($field) {return $field.'=?';}, $fields ) ) . ' WHERE Id=?';
|
$sql = 'UPDATE Monitors SET '.implode(', ', array_map(function($field) {return $field.'=?';}, $fields )) . ' WHERE Id=?';
|
||||||
$values = array_map( function($field){return $this->{$field};}, $fields );
|
$values = array_map(function($field){return $this->{$field};}, $fields);
|
||||||
$values[] = $this->{'Id'};
|
$values[] = $this->{'Id'};
|
||||||
dbQuery( $sql, $values );
|
dbQuery($sql, $values);
|
||||||
} // end function save
|
} // end function save
|
||||||
|
|
||||||
function zmcControl( $mode=false ) {
|
function zmcControl( $mode=false ) {
|
||||||
|
@ -401,10 +407,20 @@ private $control_fields = array(
|
||||||
}
|
}
|
||||||
} // end if we are on the recording server
|
} // end if we are on the recording server
|
||||||
}
|
}
|
||||||
public function GroupIds( ) {
|
public function GroupIds( $new='') {
|
||||||
|
if ( $new != '' ) {
|
||||||
|
if(!is_array($new)) {
|
||||||
|
$this->{'GroupIds'} = array($new);
|
||||||
|
} else {
|
||||||
|
$this->{'GroupIds'} = $new;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( !array_key_exists('GroupIds', $this) ) {
|
if ( !array_key_exists('GroupIds', $this) ) {
|
||||||
if ( array_key_exists('Id', $this) and $this->{'Id'} ) {
|
if ( array_key_exists('Id', $this) and $this->{'Id'} ) {
|
||||||
$this->{'GroupIds'} = dbFetchAll( 'SELECT GroupId FROM Groups_Monitors WHERE MonitorId=?', 'GroupId', array($this->{'Id'}) );
|
$this->{'GroupIds'} = dbFetchAll('SELECT GroupId FROM Groups_Monitors WHERE MonitorId=?', 'GroupId', array($this->{'Id'}) );
|
||||||
|
if ( ! $this->{'GroupIds'} )
|
||||||
|
$this->{'GroupIds'} = array();
|
||||||
} else {
|
} else {
|
||||||
$this->{'GroupIds'} = array();
|
$this->{'GroupIds'} = array();
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ class Storage {
|
||||||
if ( ! $row ) {
|
if ( ! $row ) {
|
||||||
Error("Unable to load Storage record for Id=" . $IdOrRow );
|
Error("Unable to load Storage record for Id=" . $IdOrRow );
|
||||||
}
|
}
|
||||||
} elseif ( is_array( $IdOrRow ) ) {
|
} else if ( is_array($IdOrRow) ) {
|
||||||
$row = $IdOrRow;
|
$row = $IdOrRow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ class Storage {
|
||||||
foreach ($row as $k => $v) {
|
foreach ($row as $k => $v) {
|
||||||
$this->{$k} = $v;
|
$this->{$k} = $v;
|
||||||
}
|
}
|
||||||
$storage_cache[$IdOrRow] = $this;
|
$storage_cache[$row['Id']] = $this;
|
||||||
} else {
|
} else {
|
||||||
$this->{'Name'} = '';
|
$this->{'Name'} = '';
|
||||||
$this->{'Path'} = '';
|
$this->{'Path'} = '';
|
||||||
|
@ -97,7 +97,7 @@ class Storage {
|
||||||
$fields[] = $field.' IS NULL';
|
$fields[] = $field.' IS NULL';
|
||||||
} else if ( is_array( $value ) ) {
|
} else if ( is_array( $value ) ) {
|
||||||
$func = function(){return '?';};
|
$func = function(){return '?';};
|
||||||
$fields[] = $field.' IN ('.implode(',', array_map( $func, $value ) ). ')';
|
$fields[] = $field.' IN ('.implode(',', array_map($func, $value)). ')';
|
||||||
$values += $value;
|
$values += $value;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -105,10 +105,10 @@ class Storage {
|
||||||
$values[] = $value;
|
$values[] = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$sql .= implode(' AND ', $fields );
|
$sql .= implode(' AND ', $fields);
|
||||||
}
|
}
|
||||||
if ( $options and isset($options['order']) ) {
|
if ( $options and isset($options['order']) ) {
|
||||||
$sql .= ' ORDER BY ' . $options['order'];
|
$sql .= ' ORDER BY ' . $options['order'];
|
||||||
}
|
}
|
||||||
$result = dbQuery($sql, $values);
|
$result = dbQuery($sql, $values);
|
||||||
if ( $result ) {
|
if ( $result ) {
|
||||||
|
@ -140,16 +140,17 @@ class Storage {
|
||||||
return $usage;
|
return $usage;
|
||||||
}
|
}
|
||||||
public function disk_total_space() {
|
public function disk_total_space() {
|
||||||
if ( ! array_key_exists( 'disk_total_space', $this ) ) {
|
if ( ! array_key_exists('disk_total_space', $this) ) {
|
||||||
$this->{'disk_total_space'} = disk_total_space( $this->Path() );
|
$this->{'disk_total_space'} = disk_total_space($this->Path());
|
||||||
}
|
}
|
||||||
return $this->{'disk_total_space'};
|
return $this->{'disk_total_space'};
|
||||||
}
|
}
|
||||||
|
|
||||||
public function disk_used_space() {
|
public function disk_used_space() {
|
||||||
# This isn't a function like this in php, so we have to add up the space used in each event.
|
# This isn't a function like this in php, so we have to add up the space used in each event.
|
||||||
if ( (! array_key_exists( 'DiskSpace', $this )) or (!$this->{'DiskSpace'}) ) {
|
if ( (! array_key_exists('disk_used_space', $this)) or (!$this->{'disk_used_space'}) ) {
|
||||||
$used = 0;
|
|
||||||
if ( $this->{'Type'} == 's3fs' ) {
|
if ( $this->{'Type'} == 's3fs' ) {
|
||||||
|
<<<<<<< HEAD
|
||||||
$used = dbFetchOne('SELECT SUM(DiskSpace) AS DiskSpace FROM Events WHERE StorageId=? AND DiskSpace IS NOT NULL', 'DiskSpace', array($this->Id()) );
|
$used = dbFetchOne('SELECT SUM(DiskSpace) AS DiskSpace FROM Events WHERE StorageId=? AND DiskSpace IS NOT NULL', 'DiskSpace', array($this->Id()) );
|
||||||
if ( 0 ) {
|
if ( 0 ) {
|
||||||
foreach ( Event::find_all( array( 'StorageId'=>$this->Id(), 'DiskSpace'=>null ) ) as $Event ) {
|
foreach ( Event::find_all( array( 'StorageId'=>$this->Id(), 'DiskSpace'=>null ) ) as $Event ) {
|
||||||
|
@ -157,14 +158,35 @@ if ( 0 ) {
|
||||||
$used += $Event->DiskSpace();
|
$used += $Event->DiskSpace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
=======
|
||||||
|
$this->{'disk_used_space'} = $this->disk_event_space();
|
||||||
|
>>>>>>> storageareas
|
||||||
} else {
|
} else {
|
||||||
$path = $this->Path();
|
$path = $this->Path();
|
||||||
$used = disk_total_space( $path ) - disk_free_space( $path );;
|
$this->{'disk_used_space'} = disk_total_space($path) - disk_free_space($path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->{'disk_used_space'};
|
||||||
|
} // end function disk_used_space
|
||||||
|
|
||||||
|
public function event_disk_space() {
|
||||||
|
# This isn't a function like this in php, so we have to add up the space used in each event.
|
||||||
|
if ( (! array_key_exists('DiskSpace', $this)) or (!$this->{'DiskSpace'}) ) {
|
||||||
|
$used = dbFetchOne('SELECT SUM(DiskSpace) AS DiskSpace FROM Events WHERE StorageId=? AND DiskSpace IS NOT NULL', 'DiskSpace', array($this->Id()) );
|
||||||
|
|
||||||
|
foreach ( Event::find_all( array('StorageId'=>$this->Id(), 'DiskSpace'=>null) ) as $Event ) {
|
||||||
|
$Event->Storage( $this ); // Prevent further db hit
|
||||||
|
$used += $Event->DiskSpace();
|
||||||
}
|
}
|
||||||
$this->{'DiskSpace'} = $used;
|
$this->{'DiskSpace'} = $used;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->{'DiskSpace'};
|
return $this->{'DiskSpace'};
|
||||||
|
} // end function event_disk_space
|
||||||
|
public function Server() {
|
||||||
|
if ( ! array_key_exists('Server',$this) ) {
|
||||||
|
$this->{'Server'}= new Server( $this->{'ServerId'} );
|
||||||
|
}
|
||||||
|
return $this->{'Server'};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -145,7 +145,7 @@ if ( $action == 'login' && isset($_REQUEST['username']) && ( ZM_AUTH_TYPE == 're
|
||||||
}
|
}
|
||||||
|
|
||||||
// Event scope actions, view permissions only required
|
// Event scope actions, view permissions only required
|
||||||
if ( canView( 'Events' ) ) {
|
if ( canView('Events') ) {
|
||||||
|
|
||||||
if ( isset( $_REQUEST['object'] ) and ( $_REQUEST['object'] == 'filter' ) ) {
|
if ( isset( $_REQUEST['object'] ) and ( $_REQUEST['object'] == 'filter' ) ) {
|
||||||
if ( $action == 'addterm' ) {
|
if ( $action == 'addterm' ) {
|
||||||
|
@ -155,7 +155,7 @@ if ( canView( 'Events' ) ) {
|
||||||
} else if ( canEdit( 'Events' ) ) {
|
} else if ( canEdit( 'Events' ) ) {
|
||||||
if ( $action == 'delete' ) {
|
if ( $action == 'delete' ) {
|
||||||
if ( ! empty($_REQUEST['Id']) ) {
|
if ( ! empty($_REQUEST['Id']) ) {
|
||||||
dbQuery( 'DELETE FROM Filters WHERE Id=?', array( $_REQUEST['Id'] ) );
|
dbQuery('DELETE FROM Filters WHERE Id=?', array($_REQUEST['Id']));
|
||||||
}
|
}
|
||||||
} else if ( ( $action == 'Save' ) or ( $action == 'SaveAs' ) or ( $action == 'execute' ) ) {
|
} else if ( ( $action == 'Save' ) or ( $action == 'SaveAs' ) or ( $action == 'execute' ) ) {
|
||||||
# or ( $action == 'submit' ) ) {
|
# or ( $action == 'submit' ) ) {
|
||||||
|
@ -189,9 +189,9 @@ if ( canView( 'Events' ) ) {
|
||||||
$sql .= ', Concurrent = '. ( !empty($_REQUEST['filter']['Concurrent']) ? 1 : 0);
|
$sql .= ', Concurrent = '. ( !empty($_REQUEST['filter']['Concurrent']) ? 1 : 0);
|
||||||
|
|
||||||
if ( $_REQUEST['Id'] and ( $action == 'Save' ) ) {
|
if ( $_REQUEST['Id'] and ( $action == 'Save' ) ) {
|
||||||
dbQuery( 'UPDATE Filters SET ' . $sql. ' WHERE Id=?', array($_REQUEST['Id']) );
|
dbQuery('UPDATE Filters SET ' . $sql. ' WHERE Id=?', array($_REQUEST['Id']));
|
||||||
} else {
|
} else {
|
||||||
dbQuery( 'INSERT INTO Filters SET' . $sql );
|
dbQuery('INSERT INTO Filters SET' . $sql);
|
||||||
$_REQUEST['Id'] = dbInsertId();
|
$_REQUEST['Id'] = dbInsertId();
|
||||||
}
|
}
|
||||||
if ( $action == 'execute' ) {
|
if ( $action == 'execute' ) {
|
||||||
|
@ -207,7 +207,7 @@ if ( canView( 'Events' ) ) {
|
||||||
// Event scope actions, edit permissions required
|
// Event scope actions, edit permissions required
|
||||||
if ( canEdit('Events') ) {
|
if ( canEdit('Events') ) {
|
||||||
if ( ($action == 'rename') && isset($_REQUEST['eventName']) && !empty($_REQUEST['eid']) ) {
|
if ( ($action == 'rename') && isset($_REQUEST['eventName']) && !empty($_REQUEST['eid']) ) {
|
||||||
dbQuery( 'UPDATE Events SET Name=? WHERE Id=?', array( $_REQUEST['eventName'], $_REQUEST['eid'] ) );
|
dbQuery('UPDATE Events SET Name=? WHERE Id=?', array($_REQUEST['eventName'], $_REQUEST['eid']));
|
||||||
} else if ( $action == 'eventdetail' ) {
|
} else if ( $action == 'eventdetail' ) {
|
||||||
if ( !empty($_REQUEST['eid']) ) {
|
if ( !empty($_REQUEST['eid']) ) {
|
||||||
dbQuery( 'UPDATE Events SET Cause=?, Notes=? WHERE Id=?', array( $_REQUEST['newEvent']['Cause'], $_REQUEST['newEvent']['Notes'], $_REQUEST['eid'] ) );
|
dbQuery( 'UPDATE Events SET Cause=?, Notes=? WHERE Id=?', array( $_REQUEST['newEvent']['Cause'], $_REQUEST['newEvent']['Notes'], $_REQUEST['eid'] ) );
|
||||||
|
@ -299,10 +299,12 @@ if ( isset($_REQUEST['object']) and $_REQUEST['object'] == 'Monitor' ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$Monitor = new Monitor( $mid );
|
$Monitor = new Monitor( $mid );
|
||||||
$Monitor->zmaControl('stop');
|
if ( $Monitor->Type() != 'WebSite' ) {
|
||||||
$Monitor->zmcControl('stop');
|
$Monitor->zmaControl('stop');
|
||||||
|
$Monitor->zmcControl('stop');
|
||||||
|
}
|
||||||
$Monitor->save( $_REQUEST['newMonitor'] );
|
$Monitor->save( $_REQUEST['newMonitor'] );
|
||||||
if ($Monitor->Function() != 'None' ) {
|
if ($Monitor->Function() != 'None' && $Monitor->Type() != 'WebSite' ) {
|
||||||
$Monitor->zmcControl('start');
|
$Monitor->zmcControl('start');
|
||||||
if ( $Monitor->Enabled() ) {
|
if ( $Monitor->Enabled() ) {
|
||||||
$Monitor->zmaControl('start');
|
$Monitor->zmaControl('start');
|
||||||
|
@ -330,7 +332,7 @@ if ( !empty($_REQUEST['mid']) && canEdit( 'Monitors', $_REQUEST['mid'] ) ) {
|
||||||
|
|
||||||
$monitor['Function'] = $newFunction;
|
$monitor['Function'] = $newFunction;
|
||||||
$monitor['Enabled'] = $newEnabled;
|
$monitor['Enabled'] = $newEnabled;
|
||||||
if ( daemonCheck() ) {
|
if ( daemonCheck() && $monitor['Type'] != 'WebSite' ) {
|
||||||
$restart = ($oldFunction == 'None') || ($newFunction == 'None') || ($newEnabled != $oldEnabled);
|
$restart = ($oldFunction == 'None') || ($newFunction == 'None') || ($newEnabled != $oldEnabled);
|
||||||
zmaControl( $monitor, 'stop' );
|
zmaControl( $monitor, 'stop' );
|
||||||
zmcControl( $monitor, $restart?'restart':'' );
|
zmcControl( $monitor, $restart?'restart':'' );
|
||||||
|
@ -371,7 +373,7 @@ if ( !empty($_REQUEST['mid']) && canEdit( 'Monitors', $_REQUEST['mid'] ) ) {
|
||||||
} else {
|
} else {
|
||||||
dbQuery( 'INSERT INTO Zones SET MonitorId=?, '.implode( ', ', $changes ), array( $mid ) );
|
dbQuery( 'INSERT INTO Zones SET MonitorId=?, '.implode( ', ', $changes ), array( $mid ) );
|
||||||
}
|
}
|
||||||
if ( daemonCheck() ) {
|
if ( daemonCheck() && $monitor['Type'] != 'WebSite' ) {
|
||||||
if ( $_REQUEST['newZone']['Type'] == 'Privacy' ) {
|
if ( $_REQUEST['newZone']['Type'] == 'Privacy' ) {
|
||||||
zmaControl( $monitor, 'stop' );
|
zmaControl( $monitor, 'stop' );
|
||||||
zmcControl( $monitor, 'restart' );
|
zmcControl( $monitor, 'restart' );
|
||||||
|
@ -399,7 +401,7 @@ if ( !empty($_REQUEST['mid']) && canEdit( 'Monitors', $_REQUEST['mid'] ) ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if($changes>0) {
|
if($changes>0) {
|
||||||
if ( daemonCheck() ) {
|
if ( daemonCheck() && $monitor['Type'] != 'WebSite' ) {
|
||||||
zmaControl( $mid, 'restart' );
|
zmaControl( $mid, 'restart' );
|
||||||
}
|
}
|
||||||
$refreshParent = true;
|
$refreshParent = true;
|
||||||
|
@ -424,7 +426,7 @@ if ( !empty($_REQUEST['mid']) && canEdit( 'Monitors', $_REQUEST['mid'] ) ) {
|
||||||
$deletedZid = 1;
|
$deletedZid = 1;
|
||||||
}
|
}
|
||||||
if ( $deletedZid ) {
|
if ( $deletedZid ) {
|
||||||
if ( daemonCheck() ) {
|
if ( daemonCheck() && $monitor['Type'] != 'WebSite' ) {
|
||||||
if ( $zone['Type'] == 'Privacy' ) {
|
if ( $zone['Type'] == 'Privacy' ) {
|
||||||
zmaControl( $mid, 'stop' );
|
zmaControl( $mid, 'stop' );
|
||||||
zmcControl( $mid, 'restart' );
|
zmcControl( $mid, 'restart' );
|
||||||
|
@ -458,7 +460,7 @@ if ( canEdit( 'Monitors' ) ) {
|
||||||
$x10Monitor = array();
|
$x10Monitor = array();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$Monitor = new Monitor( $monitor );
|
$Monitor = new Monitor($monitor);
|
||||||
|
|
||||||
// Define a field type for anything that's not simple text equivalent
|
// Define a field type for anything that's not simple text equivalent
|
||||||
$types = array(
|
$types = array(
|
||||||
|
@ -475,7 +477,7 @@ if ( canEdit( 'Monitors' ) ) {
|
||||||
|
|
||||||
if ( $_REQUEST['newMonitor']['ServerId'] == 'auto' ) {
|
if ( $_REQUEST['newMonitor']['ServerId'] == 'auto' ) {
|
||||||
Logger::Debug("Auto selecting server");
|
Logger::Debug("Auto selecting server");
|
||||||
$_REQUEST['newMonitor']['ServerId'] = dbFetchOne( 'SELECT Id FROM Servers WHERE Status=\'Running\' ORDER BY FreeMem DESC, CpuLoad ASC LIMIT 1', 'Id' );
|
$_REQUEST['newMonitor']['ServerId'] = dbFetchOne('SELECT Id FROM Servers WHERE Status=\'Running\' ORDER BY FreeMem DESC, CpuLoad ASC LIMIT 1', 'Id');
|
||||||
Logger::Debug("Auto selecting server: Got " . $_REQUEST['newMonitor']['ServerId'] );
|
Logger::Debug("Auto selecting server: Got " . $_REQUEST['newMonitor']['ServerId'] );
|
||||||
if ( ( ! $_REQUEST['newMonitor'] ) and defined('ZM_SERVER_ID') ) {
|
if ( ( ! $_REQUEST['newMonitor'] ) and defined('ZM_SERVER_ID') ) {
|
||||||
$_REQUEST['newMonitor']['ServerId'] = ZM_SERVER_ID;
|
$_REQUEST['newMonitor']['ServerId'] = ZM_SERVER_ID;
|
||||||
|
@ -485,15 +487,17 @@ if ( canEdit( 'Monitors' ) ) {
|
||||||
Logger::Debug("NOT Auto selecting server" . $_REQUEST['newMonitor']['ServerId']);
|
Logger::Debug("NOT Auto selecting server" . $_REQUEST['newMonitor']['ServerId']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$columns = getTableColumns( 'Monitors' );
|
$columns = getTableColumns('Monitors');
|
||||||
$changes = getFormChanges( $monitor, $_REQUEST['newMonitor'], $types, $columns );
|
$changes = getFormChanges($monitor, $_REQUEST['newMonitor'], $types, $columns);
|
||||||
|
|
||||||
if ( count( $changes ) ) {
|
if ( count( $changes ) ) {
|
||||||
if ( $mid ) {
|
if ( $mid ) {
|
||||||
|
|
||||||
# If we change anything that changes the shared mem size, zma can complain. So let's stop first.
|
# If we change anything that changes the shared mem size, zma can complain. So let's stop first.
|
||||||
zmaControl( $monitor, 'stop' );
|
if ( $monitor['Type'] != 'WebSite' ) {
|
||||||
zmcControl( $monitor, 'stop' );
|
zmaControl( $monitor, 'stop' );
|
||||||
|
zmcControl( $monitor, 'stop' );
|
||||||
|
}
|
||||||
dbQuery( 'UPDATE Monitors SET '.implode( ', ', $changes ).' WHERE Id=?', array($mid) );
|
dbQuery( 'UPDATE Monitors SET '.implode( ', ', $changes ).' WHERE Id=?', array($mid) );
|
||||||
// Groups will be added below
|
// Groups will be added below
|
||||||
if ( isset($changes['Name']) or isset($changes['StorageId']) ) {
|
if ( isset($changes['Name']) or isset($changes['StorageId']) ) {
|
||||||
|
@ -564,7 +568,16 @@ if ( canEdit( 'Monitors' ) ) {
|
||||||
Error("Users with Monitors restrictions cannot create new monitors.");
|
Error("Users with Monitors restrictions cannot create new monitors.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ( count($_POST['newMonitor']['GroupIds']) != count($Monitor->GroupIds()) or array_diff($_POST['newMonitor']['GroupIds'], $Monitor->GroupIds() ) ) {
|
|
||||||
|
$restart = true;
|
||||||
|
} # end if count(changes)
|
||||||
|
if (
|
||||||
|
( !isset($_POST['newMonitor']['GroupIds']) )
|
||||||
|
or
|
||||||
|
( count($_POST['newMonitor']['GroupIds']) != count($Monitor->GroupIds()) )
|
||||||
|
or
|
||||||
|
array_diff($_POST['newMonitor']['GroupIds'], $Monitor->GroupIds())
|
||||||
|
) {
|
||||||
if ( $Monitor->Id() )
|
if ( $Monitor->Id() )
|
||||||
dbQuery('DELETE FROM Groups_Monitors WHERE MonitorId=?', array($mid));
|
dbQuery('DELETE FROM Groups_Monitors WHERE MonitorId=?', array($mid));
|
||||||
|
|
||||||
|
@ -574,8 +587,6 @@ if ( canEdit( 'Monitors' ) ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // end if there has been a change of groups
|
} // end if there has been a change of groups
|
||||||
$restart = true;
|
|
||||||
} # end if count(changes)
|
|
||||||
|
|
||||||
if ( ZM_OPT_X10 ) {
|
if ( ZM_OPT_X10 ) {
|
||||||
$x10Changes = getFormChanges( $x10Monitor, $_REQUEST['newX10Monitor'] );
|
$x10Changes = getFormChanges( $x10Monitor, $_REQUEST['newX10Monitor'] );
|
||||||
|
@ -599,8 +610,10 @@ if ( canEdit( 'Monitors' ) ) {
|
||||||
$new_monitor = new Monitor($mid);
|
$new_monitor = new Monitor($mid);
|
||||||
//fixDevices();
|
//fixDevices();
|
||||||
|
|
||||||
$new_monitor->zmcControl('start');
|
if ( $monitor['Type'] != 'WebSite' ) {
|
||||||
$new_monitor->zmaControl('start');
|
$new_monitor->zmcControl('start');
|
||||||
|
$new_monitor->zmaControl('start');
|
||||||
|
}
|
||||||
|
|
||||||
if ( $new_monitor->Controllable() ) {
|
if ( $new_monitor->Controllable() ) {
|
||||||
require_once( 'control_functions.php' );
|
require_once( 'control_functions.php' );
|
||||||
|
|
|
@ -26,6 +26,7 @@ define( 'ZM_CONFIG_SUBDIR', '@ZM_CONFIG_SUBDIR@' ); // Path to config subfolder
|
||||||
// Define, and override any given in config file
|
// Define, and override any given in config file
|
||||||
define( 'ZM_VERSION', '@VERSION@' ); // Version
|
define( 'ZM_VERSION', '@VERSION@' ); // Version
|
||||||
define( 'ZM_DIR_TEMP', '@ZM_TMPDIR@' );
|
define( 'ZM_DIR_TEMP', '@ZM_TMPDIR@' );
|
||||||
|
define( 'ZM_DIR_CACHE', '@ZM_CACHEDIR@' );
|
||||||
global $configvals;
|
global $configvals;
|
||||||
|
|
||||||
$configFile = ZM_CONFIG;
|
$configFile = ZM_CONFIG;
|
||||||
|
|
|
@ -133,10 +133,7 @@ function dbQuery( $sql, $params=NULL ) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ( defined('ZM_DB_DEBUG') ) {
|
if ( defined('ZM_DB_DEBUG') ) {
|
||||||
if ( $params )
|
Logger::Debug("SQL: $sql values:" . ($params?implode(',',$params):'') );
|
||||||
Warning("SQL: $sql" . implode(',',$params) );
|
|
||||||
else
|
|
||||||
Warning("SQL: $sql:" );
|
|
||||||
}
|
}
|
||||||
$result = $dbConn->query($sql);
|
$result = $dbConn->query($sql);
|
||||||
}
|
}
|
||||||
|
@ -164,16 +161,16 @@ function dbFetchOne( $sql, $col=false, $params=NULL ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $result && $dbRow = $result->fetch( PDO::FETCH_ASSOC ) ) {
|
if ( $result && $dbRow = $result->fetch(PDO::FETCH_ASSOC) ) {
|
||||||
if ( $col ) {
|
if ( $col ) {
|
||||||
if ( ! isset( $dbRow[$col] ) ) {
|
if ( ! array_key_exists($col, $dbRow) ) {
|
||||||
Warning( "$col does not exist in the returned row " . print_r($dbRow, true) );
|
Warning("$col does not exist in the returned row " . print_r($dbRow, true));
|
||||||
}
|
}
|
||||||
return $dbRow[$col];
|
return $dbRow[$col];
|
||||||
}
|
}
|
||||||
return $dbRow;
|
return $dbRow;
|
||||||
}
|
}
|
||||||
return( false );
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbFetchAll( $sql, $col=false, $params=NULL ) {
|
function dbFetchAll( $sql, $col=false, $params=NULL ) {
|
||||||
|
@ -186,7 +183,7 @@ function dbFetchAll( $sql, $col=false, $params=NULL ) {
|
||||||
$dbRows = array();
|
$dbRows = array();
|
||||||
while( $dbRow = $result->fetch( PDO::FETCH_ASSOC ) )
|
while( $dbRow = $result->fetch( PDO::FETCH_ASSOC ) )
|
||||||
$dbRows[] = $col?$dbRow[$col]:$dbRow;
|
$dbRows[] = $col?$dbRow[$col]:$dbRow;
|
||||||
return( $dbRows );
|
return $dbRows;
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbFetchAssoc( $sql, $indexCol, $dataCol=false ) {
|
function dbFetchAssoc( $sql, $indexCol, $dataCol=false ) {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue