diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 610480e8e..7751de627 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,3 +1,5 @@ + **Describe Your Environment** + **If the issue concerns a camera** + **Describe the bug** + **To Reproduce** + **Expected behavior** + **Debug Logs** ``` + ``` diff --git a/.gitignore b/.gitignore index 3167e62a6..152802d29 100644 --- a/.gitignore +++ b/.gitignore @@ -120,7 +120,7 @@ src/CMakeFiles/ src/cmake_install.cmake src/libzm.a src/nph-zms -src/zm_config.h +src/zm_config_data.h src/zm_config_defines.h src/zma src/zmc diff --git a/.travis.yml b/.travis.yml index de71ce36e..da05d8970 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: cpp sudo: required -dist: xenial +dist: bionic git: depth: 9999999 notifications: @@ -32,20 +32,17 @@ install: - update-binfmts --enable qemu-arm env: + - SMPFLAGS=-j4 OS=eslint DIST=eslint - SMPFLAGS=-j4 OS=el DIST=7 DOCKER_REPO=knnniggett/packpack - SMPFLAGS=-j4 OS=el DIST=8 DOCKER_REPO=knnniggett/packpack - SMPFLAGS=-j4 OS=fedora DIST=31 DOCKER_REPO=knnniggett/packpack - SMPFLAGS=-j4 OS=fedora DIST=32 DOCKER_REPO=knnniggett/packpack - - SMPFLAGS=-j4 OS=ubuntu DIST=trusty DOCKER_REPO=iconzm/packpack + - SMPFLAGS=-j4 OS=fedora DIST=33 DOCKER_REPO=knnniggett/packpack - SMPFLAGS=-j4 OS=ubuntu DIST=xenial DOCKER_REPO=iconzm/packpack - SMPFLAGS=-j4 OS=ubuntu DIST=bionic DOCKER_REPO=iconzm/packpack - - SMPFLAGS=-j4 OS=ubuntu DIST=disco DOCKER_REPO=iconzm/packpack - - SMPFLAGS=-j4 OS=ubuntu DIST=eoan DOCKER_REPO=iconzm/packpack - SMPFLAGS=-j4 OS=ubuntu DIST=focal DOCKER_REPO=iconzm/packpack - - SMPFLAGS=-j4 OS=debian DIST=jessie DOCKER_REPO=iconzm/packpack - SMPFLAGS=-j4 OS=debian DIST=stretch DOCKER_REPO=iconzm/packpack - SMPFLAGS=-j4 OS=debian DIST=buster DOCKER_REPO=iconzm/packpack - - SMPFLAGS=-j4 OS=eslint DIST=eslint compiler: - gcc diff --git a/README.md b/README.md index ab946c04c..c7bd801b7 100644 --- a/README.md +++ b/README.md @@ -70,18 +70,19 @@ Docker is a system to run applications inside isolated containers. ZoneMinder, a Dockerfile contained in this repository. However, there is still work needed to ensure that the main ZM features work properly and are documented. -## Contribution Model and Development +## Contribution Model and Development * Source hosted at [GitHub](https://github.com/ZoneMinder/ZoneMinder/) -* Report issues/questions/feature requests on [GitHub Issues](https://github.com/ZoneMinder/ZoneMinder/issues) +* Report issues at [GitHub Issues](https://github.com/ZoneMinder/ZoneMinder/issues) +* Questions/feature requests in [Slack](https://zoneminder-chat.slack.com/) or [forums](https://forums.zoneminder.com) Pull requests are very welcome! If you would like to contribute, please follow the following steps. While step 3 is optional, it is preferred. 1. Fork the repo 2. Open an issue at our [GitHub Issues Tracker](https://github.com/ZoneMinder/ZoneMinder/issues). - Describe the bug that you've found, or the feature which you're asking for. - Jot down the issue number (e.g. 456) + Follow the issue template to describe the bug or security issue you found. Please note feature + requests or questions should be posted in our user forum or Slack channel. 3. Create your feature branch (`git checkout -b 456-my-new-feature`) 4. Commit your changes (`git commit -am 'Added some feature'`) It is preferred that you 'commit early and often' instead of bunching all diff --git a/conf.d/01-system-paths.conf.in b/conf.d/01-system-paths.conf.in index e1aaf0bef..277f63b70 100644 --- a/conf.d/01-system-paths.conf.in +++ b/conf.d/01-system-paths.conf.in @@ -46,3 +46,6 @@ ZM_PATH_SWAP=@ZM_TMPDIR@ # Full path to optional arp binary # ZoneMinder will find the arp binary automatically on most systems ZM_PATH_ARP="@ZM_PATH_ARP@" + +#Full path to shutdown binary +ZM_PATH_SHUTDOWN="@ZM_PATH_SHUTDOWN@" diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 877cde38a..092fce14f 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -485,7 +485,7 @@ CREATE TABLE `Monitors` ( `Hue` mediumint(7) NOT NULL default '-1', `Colour` mediumint(7) NOT NULL default '-1', `EventPrefix` varchar(32) NOT NULL default 'Event-', - `LabelFormat` varchar(64) default '%N - %y/%m/%d %H:%M:%S', + `LabelFormat` varchar(64), `LabelX` smallint(5) unsigned NOT NULL default '0', `LabelY` smallint(5) unsigned NOT NULL default '0', `LabelSize` smallint(5) unsigned NOT NULL DEFAULT '1', diff --git a/db/zm_update-1.31.13.sql b/db/zm_update-1.31.13.sql index dd63b347a..150264027 100644 --- a/db/zm_update-1.31.13.sql +++ b/db/zm_update-1.31.13.sql @@ -13,6 +13,8 @@ SET @s = (SELECT IF( PREPARE stmt FROM @s; EXECUTE stmt; +UPDATE `Events` SET `SaveJPEGs`=(SELECT `SaveJPEGs` FROM `Monitors` WHERE Monitors.Id = MonitorId) WHERE `SaveJPEGs` IS NULL; + SET @s = (SELECT IF( (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() AND table_name = 'Storage' diff --git a/db/zm_update-1.34.20.sql b/db/zm_update-1.34.20.sql new file mode 100644 index 000000000..3512534be --- /dev/null +++ b/db/zm_update-1.34.20.sql @@ -0,0 +1,2 @@ +/* This was done in 1.31.0 but zm_create.sql.in wasn't updated to match. */ +ALTER TABLE Monitors MODIFY LinkedMonitors varchar(255); diff --git a/db/zm_update-1.35.6.sql b/db/zm_update-1.35.6.sql new file mode 100644 index 000000000..3512534be --- /dev/null +++ b/db/zm_update-1.35.6.sql @@ -0,0 +1,2 @@ +/* This was done in 1.31.0 but zm_create.sql.in wasn't updated to match. */ +ALTER TABLE Monitors MODIFY LinkedMonitors varchar(255); diff --git a/distros/beowulf/NEWS b/distros/beowulf/NEWS new file mode 100644 index 000000000..6200726cf --- /dev/null +++ b/distros/beowulf/NEWS @@ -0,0 +1,10 @@ +zoneminder (1.28.1-1) unstable; urgency=low + + This version is no longer automatically initialize or upgrade database. + See README.Debian for details. + + Changed installation paths (please correct your web server configuration): + /usr/share/zoneminder --> /usr/share/zoneminder/www + /usr/lib/cgi-bin --> /usr/lib/zoneminder/cgi-bin + + -- Dmitry Smirnov Tue, 31 Mar 2015 15:12:17 +1100 diff --git a/distros/beowulf/README.Debian b/distros/beowulf/README.Debian new file mode 100644 index 000000000..4fe3464d2 --- /dev/null +++ b/distros/beowulf/README.Debian @@ -0,0 +1,130 @@ +Zoneminder for Debian +--------------------- + +Initializing database +--------------------- + + pv /usr/share/zoneminder/db/zm_create.sql | sudo mysql --defaults-file=/etc/mysql/debian.cnf +OR + cat /usr/share/zoneminder/db/zm_create.sql | sudo mysql --defaults-file=/etc/mysql/debian.cnf + + echo 'grant lock tables,alter,create,index,select,insert,update,delete on zm.* to 'zmuser'@localhost identified by "zmpass";'\ + | sudo mysql --defaults-file=/etc/mysql/debian.cnf mysql + +Hint: generate secure password with `pwgen` and update "/etc/zm/zm.conf" +accordingly. + +The following command can help to ensure that zoneminder can read its +configuration file: + + chgrp -c www-data /etc/zm/zm.conf + + +Upgrading database +------------------ + +The database is updated automatically on installation. You should not need to take this step. + +Assuming that database is on "localhost" then the following command can be +used to upgrade "zm" database: + + zmupdate.pl + +Additional permissions may be required to perform upgrade: + + echo 'grant lock tables, create, alter on zm.* to 'zmuser'@localhost identified by "zmpass";'\ + | sudo mysql --defaults-file=/etc/mysql/debian.cnf mysql + +The following command prints the current version of zoneminder database: + + echo 'select Value from Config where Name = "ZM_DYN_CURR_VERSION";' \ + | sudo mysql --defaults-file=/etc/mysql/debian.cnf --skip-column-names zm + + +Enabling service +---------------- + +By default Zoneminder service is not automatically started and needs to be +manually enabled once database is configured: + + sudo systemctl enable zoneminder.service + + +Web server set-up +----------------- + +There are few manual steps to get the web interface working: + +## Apache2 + +Apache can be configured as folder "/zm" using sample .conf: + + sudo a2enconf zoneminder + +Alternatively Apache web site configuration template can be used to setup +zoneminder as "http://zoneminder": + + sudo cp -v /usr/share/doc/zoneminder/examples/apache.conf /etc/apache2/sites-available/ + sudo a2ensite zoneminder.conf + +Common configuration steps for Apache2: + + sudo a2enmod cgi + sudo service apache2 reload + + +## nginx / fcgiwrap + +Nginx needs "php-fpm" package to support PHP and "fcgiwrap" package +for binary "cgi-bin" applications: + + sudo apt-get install php-fpm fcgiwrap + +To enable a URL alias that makes Zoneminder available from + + http://yourserver/zm + +the following line is to be added to "server" section of a web site +configuration: + + include /usr/share/doc/zoneminder/examples/nginx.conf; + +For "default" web site it would be sufficient to include the above +statement to the file + + /etc/nginx/sites-enabled/default + +To avoid problems with feeds from multiple cameras "fcgiwrap" should be +configured to start at least as many processes as there are cameras. +It can be done by adjusting DAEMON_OPTS in "/etc/default/fcgiwrap". +Systemd users may be affected by the following bug: + + http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=792705 + + +## Note: + +When Zoneminder web site is running it may be necessary to set +Options/Paths/PATH_ZMS to "/zm/cgi-bin/nph-zms" or according to chosen web +site configuration. + + +Changing the location for images and events +------------------------------------------- + +ZoneMinder is now able to be configured to use an alternative location for storing +events and images at compile time. This package makes use of that, so symlinks in +/usr/share/zoneminder/www are no longer necessary. + +Access to /dev/video* +--------------------- + +For cameras which require access to /dev/video*, zoneminder may need the +www-data user added to the video group in order to see those cameras: + + adduser www-data video + +Note that all web applications running on the zoneminder server will then have +access to all video devices on the system. + + -- Vagrant Cascadian Sun, 27 Mar 2011 13:06:56 -0700 diff --git a/distros/beowulf/TODO.Debian b/distros/beowulf/TODO.Debian new file mode 100644 index 000000000..9dc59613b --- /dev/null +++ b/distros/beowulf/TODO.Debian @@ -0,0 +1,12 @@ + +## Separate substantial /usr/share into its own arch-all package. + +## Decide how to handle database updates. + + * Consider possibility that database may be on another machine (#469239). + * Consider dbconfig-common? Probably not (what if database is not on localhost?). + +### Run `zmupdate.pl` from service control scripts (init.d, service) on start? + + Automatic upgrade will break "one DB, many zoneminders" setup (unimportant?). + diff --git a/distros/beowulf/changelog b/distros/beowulf/changelog new file mode 100644 index 000000000..616f75178 --- /dev/null +++ b/distros/beowulf/changelog @@ -0,0 +1,3 @@ +zoneminder (1.31.39~20180223.27-stretch-1) unstable; urgency=low + * + -- Isaac Connor Fri, 23 Feb 2018 14:15:59 -0500 diff --git a/distros/beowulf/clean b/distros/beowulf/clean new file mode 100644 index 000000000..941ef2a3a --- /dev/null +++ b/distros/beowulf/clean @@ -0,0 +1,3 @@ +.gitattributes +web/api/.gitattributes +web/api/.gitignore diff --git a/distros/beowulf/compat b/distros/beowulf/compat new file mode 100644 index 000000000..ec635144f --- /dev/null +++ b/distros/beowulf/compat @@ -0,0 +1 @@ +9 diff --git a/distros/beowulf/conf/apache2/zoneminder.conf b/distros/beowulf/conf/apache2/zoneminder.conf new file mode 100644 index 000000000..e3164d36c --- /dev/null +++ b/distros/beowulf/conf/apache2/zoneminder.conf @@ -0,0 +1,57 @@ +# Remember to enable cgi mod (i.e. "a2enmod cgi"). +ScriptAlias /zm/cgi-bin "/usr/lib/zoneminder/cgi-bin" + + Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch + AllowOverride All + Require all granted + + + +# Order matters. This alias must come first. +Alias /zm/cache /var/cache/zoneminder/cache + + Options -Indexes +FollowSymLinks + AllowOverride None + + # Apache 2.4 + Require all granted + + + # Apache 2.2 + Order deny,allow + Allow from all + + + +Alias /zm /usr/share/zoneminder/www + + Options -Indexes +FollowSymLinks + + DirectoryIndex index.php + + + +# 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. + + RewriteEngine on + RewriteRule ^$ app/webroot/ [L] + RewriteRule (.*) app/webroot/$1 [L] + RewriteBase /zm/api + + + + RewriteEngine on + RewriteRule ^$ webroot/ [L] + RewriteRule (.*) webroot/$1 [L] + RewriteBase /zm/api + + + + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + RewriteBase /zm/api + diff --git a/distros/beowulf/control b/distros/beowulf/control new file mode 100644 index 000000000..dd410c0ba --- /dev/null +++ b/distros/beowulf/control @@ -0,0 +1,166 @@ +Source: zoneminder +Section: net +Priority: optional +Maintainer: Isaac Connor +Uploaders: Isaac Connor +Build-Depends: debhelper, sphinx-doc, dh-linktree, dh-apache2 + ,cmake + ,libx264-dev, libmp4v2-dev + ,libavdevice-dev + ,libavcodec-dev + ,libavformat-dev + ,libavutil-dev + ,libswresample-dev + ,libswscale-dev + ,ffmpeg + ,net-tools + ,libbz2-dev + ,libgcrypt20-dev + ,libcurl4-gnutls-dev + ,libturbojpeg0-dev + ,default-libmysqlclient-dev | libmysqlclient-dev | libmariadbclient-dev-compat + ,libpcre3-dev + ,libpolkit-gobject-1-dev + ,libv4l-dev [!hurd-any] + ,libvlc-dev + ,libdate-manip-perl + ,libdbd-mysql-perl + ,libphp-serialization-perl + ,libsys-mmap-perl [!hurd-any] + ,libwww-perl + ,libdata-uuid-perl + ,libssl-dev + ,libcrypt-eksblowfish-perl + ,libdata-entropy-perl +# Unbundled (dh_linktree): + ,libjs-jquery + ,libjs-mootools +Standards-Version: 3.9.8 +Homepage: http://www.zoneminder.com/ +Vcs-Browser: http://anonscm.debian.org/cgit/collab-maint/zoneminder.git +Vcs-Git: git://anonscm.debian.org/collab-maint/zoneminder.git + +Package: zoneminder +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends} + ,javascript-common + ,libmp4v2-2, libx264-155 + ,libswscale5 + ,libswresample3 + ,ffmpeg + ,libdate-manip-perl, libmime-lite-perl, libmime-tools-perl + ,libdbd-mysql-perl + ,libphp-serialization-perl + ,libmodule-load-conditional-perl + ,libnet-sftp-foreign-perl + ,libarchive-zip-perl + ,libdbd-mysql-perl + ,libdevice-serialport-perl + ,libimage-info-perl + ,libjson-maybexs-perl + ,libsys-mmap-perl [!hurd-any] + ,liburi-encode-perl + ,libwww-perl, liburi-perl + ,libdata-dump-perl + ,libdatetime-perl + ,libclass-std-fast-perl + ,libsoap-wsdl-perl + ,libio-socket-multicast-perl + ,libdigest-sha-perl + ,libsys-cpu-perl, libsys-meminfo-perl + ,libdata-uuid-perl + ,libnumber-bytes-human-perl + ,libfile-slurp-perl + ,mysql-client | mariadb-client | virtual-mysql-client + ,perl-modules + ,php-mysql, php-gd, php-apcu, php-apc | php-apcu-bc, php-json + ,policykit-1 + ,rsyslog | system-log-daemon + ,zip + ,libpcre3 + ,libcrypt-eksblowfish-perl + ,libdata-entropy-perl +Recommends: ${misc:Recommends} + ,libapache2-mod-php | php-fpm + ,mysql-server | mariadb-server | virtual-mysql-server + ,zoneminder-doc (>= ${source:Version}) + ,ffmpeg +Suggests: fcgiwrap, logrotate +Description: video camera security and surveillance solution + ZoneMinder is intended for use in single or multi-camera video security + applications, including commercial or home CCTV, theft prevention and child + or family member or home monitoring and other care scenarios. It + supports capture, analysis, recording, and monitoring of video data coming + from one or more video or network cameras attached to a Linux system. + ZoneMinder also support web and semi-automatic control of Pan/Tilt/Zoom + cameras using a variety of protocols. It is suitable for use as a home + video security system and for commercial or professional video security + and surveillance. It can also be integrated into a home automation system + via X.10 or other protocols. + +#Package: libzoneminder-perl +#Section: perl +#Architecture: all +#Multi-Arch: foreign +#Depends: ${misc:Depends}, ${perl:Depends} +# ,libarchive-zip-perl +# ,libdbd-mysql-perl +# ,libdevice-serialport-perl +# ,libimage-info-perl +# ,libjson-maybexs-perl +# ,libsys-mmap-perl [!hurd-any] +# ,liburi-encode-perl +# ,libwww-perl +#Description: ZoneMinder Perl libraries +# ZoneMinder is intended for use in single or multi-camera video security +# applications, including commercial or home CCTV, theft prevention and child +# or family member or home monitoring and other care scenarios. It +# supports capture, analysis, recording, and monitoring of video data coming +# from one or more video or network cameras attached to a Linux system. +# ZoneMinder also support web and semi-automatic control of Pan/Tilt/Zoom +# cameras using a variety of protocols. It is suitable for use as a home +# video security system and for commercial or professional video security +# and surveillance. It can also be integrated into a home automation system +# via X.10 or other protocols. +# . +# This package provides ZoneMinder Perl libraries; it can be used to +# write custom interfaces as well. + +Package: zoneminder-doc +Section: doc +Architecture: all +Multi-Arch: foreign +Depends: ${misc:Depends}, ${sphinxdoc:Depends}, python-sphinx-rtd-theme | python3-sphinx-rtd-theme +Suggests: www-browser +Description: ZoneMinder documentation + ZoneMinder is intended for use in single or multi-camera video security + applications, including commercial or home CCTV, theft prevention and child + or family member or home monitoring and other care scenarios. It + supports capture, analysis, recording, and monitoring of video data coming + from one or more video or network cameras attached to a Linux system. + ZoneMinder also support web and semi-automatic control of Pan/Tilt/Zoom + cameras using a variety of protocols. It is suitable for use as a home + video security system and for commercial or professional video security + and surveillance. It can also be integrated into a home automation system + via X.10 or other protocols. + . + This package provides ZoneMinder documentation in HTML format. + +Package: zoneminder-dbg +Section: debug +Priority: extra +Architecture: any +Depends: zoneminder (= ${binary:Version}), ${misc:Depends} +Description: Zoneminder -- debugging symbols + ZoneMinder is intended for use in single or multi-camera video security + applications, including commercial or home CCTV, theft prevention and child + or family member or home monitoring and other care scenarios. It + supports capture, analysis, recording, and monitoring of video data coming + from one or more video or network cameras attached to a Linux system. + ZoneMinder also support web and semi-automatic control of Pan/Tilt/Zoom + cameras using a variety of protocols. It is suitable for use as a home + video security system and for commercial or professional video security + and surveillance. It can also be integrated into a home automation system + via X.10 or other protocols. + . + This package provides debugging symbols diff --git a/distros/beowulf/copyright b/distros/beowulf/copyright new file mode 100644 index 000000000..c48025a25 --- /dev/null +++ b/distros/beowulf/copyright @@ -0,0 +1,174 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: ZoneMinder +Upstream-Contact: Philip Coombes +Source: https://github.com/ZoneMinder/ZoneMinder +Comment: + This package was originally debianized by matrix + on Mon, 7 Mar 2005 02:07:57 -0500. + It was re-done for submission to the Debian project by Peter Howard + on Fri, 8 Dec 2006 10:19:43 +1100 +Files-Excluded: + web/skins/*/js/jquery-* + web/tools/mootools/*-yc.js + +Files: * +Copyright: 2001-2014 Philip Coombes + 2008 Brian Rudy + 2014 Vincent Giovannone + 2013 Tim Craig + 2003-2008 Corey DeLasaux + 2001-2010 Chris Kistner +License: GPL-2+ + +Files: distros/* +Copyright: 2001-2008 Philip Coombes + 2014 Isaac Connor + 2005 Serg Oskin +License: GPL-2+ + +Files: web/skins/*/js/jquery-* +Copyright: 2010 John Resig + 2010 The Dojo Foundation +License: GPL-2 or Expat +Comment: + Dual licensed under the MIT or GPL Version 2 licenses. + http://jquery.org/license + . + Includes Sizzle.js http://sizzlejs.com/ + Released under the MIT, BSD, and GPL Licenses. + +Files: web/tools/mootools/*.js +Copyright: 2009 Marcelo Jorge Vieira (metal) + 2006-2010 Valerio Proietti (http://mad4milk.net/) +License: Expat + +Files: web/api/* +Copyright: 2005-2013 Cake Software Foundation, Inc. (http://cakefoundation.org) +License: Expat + +Files: + cmake/Modules/CheckPrototypeDefinition*.cmake + cmake/Modules/FindGLIB2.cmake + cmake/Modules/FindPolkit.cmake + cmake/Modules/GNUInstallDirs.cmake +Copyright: + 2005-2011 Kitware, Inc. + 2010-2011 Andreas Schneider + 2009 Dario Freddi + 2008 Laurent Montel, + 2011 Nikita Krupen'ko +License: BSD-3-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + . + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + . + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + . + * The names of Kitware, Inc., the Insight Consortium, or the names of + any consortium members, or of any contributors, may not be used to + endorse or promote products derived from this software without + specific prior written permission. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Files: cmake/Modules/FindPerlModules.cmake +Copyright: 2012 Iowa State University +License: Boost-1.0 + Boost Software License - Version 1.0 - August 17th, 2003 + . + Permission is hereby granted, free of charge, to any person or organization + obtaining a copy of the software and accompanying documentation covered by + this license (the "Software") to use, reproduce, display, distribute, + execute, and transmit the Software, and to prepare derivative works of the + Software, and to permit third-parties to whom the Software is furnished to + do so, all subject to the following: + . + The copyright notices in the Software and this entire statement, including + the above license grant, this restriction and the following disclaimer, + must be included in all copies of the Software, in whole or in part, and + all derivative works of the Software, unless such copies or derivative + works are solely in the form of machine-executable object code generated by + a source language processor. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + +Files: debian/* +Copyright: 2015 Dmitry Smirnov + 2007-2014 Peter Howard + 2010-2012 Vagrant Cascadian + 2001-2008 Philip Coombes +License: GPL-2+ + +License: Expat + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + . + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +License: GPL-2+ + This package is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + . + You should have received a copy of the GNU General Public + License along with this package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + . + The complete text of the GNU General Public License version 2 + can be found in "/usr/share/common-licenses/GPL-2". + +License: GPL-2 + This package is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + . + You should have received a copy of the GNU General Public + License along with this package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + . + The complete text of the GNU General Public License version 2 + can be found in "/usr/share/common-licenses/GPL-2". diff --git a/distros/beowulf/examples/nginx.conf b/distros/beowulf/examples/nginx.conf new file mode 100644 index 000000000..5636ca3e1 --- /dev/null +++ b/distros/beowulf/examples/nginx.conf @@ -0,0 +1,32 @@ +location /zm/cgi-bin { + gzip off; + alias /usr/lib/zoneminder/cgi-bin; + + include /etc/nginx/fastcgi_params; + fastcgi_param SCRIPT_FILENAME $request_filename; + fastcgi_pass unix:/var/run/fcgiwrap.socket; +} + +location /zm { +# if ($scheme ~ ^http:){ +# rewrite ^(.*)$ https://$host$1 permanent; +# } + + gzip off; + alias /usr/share/zoneminder/www; + index index.php; + + location ~ \.php$ { + if (!-f $request_filename) { return 404; } + expires epoch; + include /etc/nginx/fastcgi_params; + fastcgi_param SCRIPT_FILENAME $request_filename; + fastcgi_index index.php; + fastcgi_pass unix:/var/run/php5-fpm.sock; + } + + location ~ \.(jpg|jpeg|gif|png|ico)$ { + access_log off; + expires 33d; + } +} diff --git a/distros/beowulf/gbp.conf b/distros/beowulf/gbp.conf new file mode 100644 index 000000000..4608913d9 --- /dev/null +++ b/distros/beowulf/gbp.conf @@ -0,0 +1,7 @@ + +[dch] +id-length = 0 + +[import-orig] +pristine-tar = False +merge = False diff --git a/distros/beowulf/libzoneminder-perl.install b/distros/beowulf/libzoneminder-perl.install new file mode 100644 index 000000000..67191d9cf --- /dev/null +++ b/distros/beowulf/libzoneminder-perl.install @@ -0,0 +1,2 @@ +usr/share/man/man3 +usr/share/perl5 diff --git a/onvif/modules/pm_to_blib b/distros/beowulf/patches/series similarity index 100% rename from onvif/modules/pm_to_blib rename to distros/beowulf/patches/series diff --git a/distros/beowulf/rules b/distros/beowulf/rules new file mode 100755 index 000000000..e26f1bb91 --- /dev/null +++ b/distros/beowulf/rules @@ -0,0 +1,87 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +export DEB_BUILD_MAINT_OPTIONS = hardening=+all +export DEB_LDFLAGS_MAINT_APPEND += -Wl,--as-needed + +ifeq ($(DEB_BUILD_ARCH_OS),hurd) +ARGS:= -DZM_NO_MMAP=ON +endif + +%: + dh $@ --parallel --buildsystem=cmake --builddirectory=dbuild \ + --with sphinxdoc,apache2,linktree + +override_dh_auto_configure: + dh_auto_configure -- $(ARGS) \ + -DCMAKE_VERBOSE_MAKEFILE=ON \ + -DCMAKE_BUILD_TYPE=Release \ + -DZM_CONFIG_DIR="/etc/zm" \ + -DZM_CONFIG_SUBDIR="/etc/zm/conf.d" \ + -DZM_RUNDIR="/run/zm" \ + -DZM_SOCKDIR="/run/zm" \ + -DZM_TMPDIR="/tmp/zm" \ + -DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \ + -DZM_CACHEDIR="/var/cache/zoneminder/cache" \ + -DZM_DIR_EVENTS="/var/cache/zoneminder/events" \ + -DZM_PATH_SHUTDOWN="/sbin/shutdown" \ + -DZM_PATH_ZMS="/zm/cgi-bin/nph-zms" + +override_dh_clean: + dh_clean $(MANPAGES1) + $(RM) -r docs/_build + +build-indep: + #$(MAKE) -C docs text + $(MAKE) -C docs html + +MANPAGES1 = dbuild/scripts/zmupdate.pl.1 +$(MANPAGES1): + # generate man page(s): + pod2man -s1 --stderr --utf8 $(patsubst %.1, %, $@) $@ + +## reproducible build: +LAST_CHANGE=$(shell dpkg-parsechangelog -S Date) +BUILD_DATE=$(shell LC_ALL=C date -u "+%B %d, %Y" -d "$(LAST_CHANGE)") +override_dh_installman: $(MANPAGES1) + $(MAKE) -C docs man SPHINXOPTS="-D today=\"$(BUILD_DATE)\"" + dh_installman --language=C $(MANPAGES1) + +override_dh_auto_install: + dh_auto_install --destdir=$(CURDIR)/debian/tmp + # remove worthless files: + $(RM) -v $(CURDIR)/debian/tmp/usr/share/perl5/*/*/*/.packlist + $(RM) -v $(CURDIR)/debian/tmp/usr/share/perl5/*/*.in + # remove empty directories: + find $(CURDIR)/debian/tmp/usr -type d -empty -delete -printf 'removed %p\n' + # remove extra-license-file: + $(RM) -v $(CURDIR)/debian/tmp/usr/share/zoneminder/www/api/lib/Cake/LICENSE.txt + +override_dh_fixperms: + dh_fixperms + # + # As requested by the Debian Webapps Policy Manual ยง3.2.1 + chown root:www-data $(CURDIR)/debian/zoneminder/etc/zm/zm.conf + chmod 640 $(CURDIR)/debian/zoneminder/etc/zm/zm.conf + +override_dh_strip: + [ -d "$(CURDIR)/debian/zoneminder-dbg" ] \ + && dh_strip --dbg-package=zoneminder-dbg \ + || dh_strip + +#%: +# dh $@ --parallel --buildsystem=autoconf --with autoreconf +# +#override_dh_auto_configure: +# dh_auto_configure -- \ +# --sysconfdir=/etc/zm \ +# --with-mysql=/usr \ +# --with-webdir=/usr/share/zoneminder \ +# --with-ffmpeg=/usr \ +# --with-cgidir=/usr/lib/cgi-bin \ +# --with-webuser=www-data \ +# --with-webgroup=www-data \ +# --enable-mmap=yes diff --git a/distros/beowulf/source/format b/distros/beowulf/source/format new file mode 100644 index 000000000..163aaf8d8 --- /dev/null +++ b/distros/beowulf/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/distros/beowulf/source/lintian-overrides b/distros/beowulf/source/lintian-overrides new file mode 100644 index 000000000..3669e5de8 --- /dev/null +++ b/distros/beowulf/source/lintian-overrides @@ -0,0 +1,9 @@ +## Actually sources are there: "*-nc.js". +source-is-missing web/tools/mootools/mootools-*-yc.js + +## We're using "libjs-jquery" instead. +source-is-missing web/skins/*/js/jquery-1.4.2.min.js + +## Acknowledged, will repack eventually. +source-contains-prebuilt-javascript-object web/tools/mootools/mootools-*-yc.js +source-contains-prebuilt-javascript-object web/skins/*/js/jquery-1.4.2.min.js diff --git a/distros/beowulf/zoneminder-doc.doc-base b/distros/beowulf/zoneminder-doc.doc-base new file mode 100644 index 000000000..c43dc4336 --- /dev/null +++ b/distros/beowulf/zoneminder-doc.doc-base @@ -0,0 +1,8 @@ +Document: zoneminder-doc +Title: Zoneminder documentation +Abstract: This document describes how to use Zoneminder. +Section: System/Administration + +Format: HTML +Index: /usr/share/doc/zoneminder-doc/html/index.html +Files: /usr/share/doc/zoneminder-doc/html/* diff --git a/distros/beowulf/zoneminder-doc.install b/distros/beowulf/zoneminder-doc.install new file mode 100644 index 000000000..c19bc6f3a --- /dev/null +++ b/distros/beowulf/zoneminder-doc.install @@ -0,0 +1 @@ +docs/_build/html usr/share/doc/zoneminder-doc/ diff --git a/distros/beowulf/zoneminder-doc.links b/distros/beowulf/zoneminder-doc.links new file mode 100644 index 000000000..cc09f6462 --- /dev/null +++ b/distros/beowulf/zoneminder-doc.links @@ -0,0 +1,2 @@ +## Convenience symlink: +/usr/share/doc/zoneminder-doc/html /usr/share/doc/zoneminder/html diff --git a/distros/beowulf/zoneminder.apache2 b/distros/beowulf/zoneminder.apache2 new file mode 100644 index 000000000..466144fa7 --- /dev/null +++ b/distros/beowulf/zoneminder.apache2 @@ -0,0 +1 @@ +conf debian/conf/apache2/zoneminder.conf nginx diff --git a/distros/beowulf/zoneminder.bug-presubj b/distros/beowulf/zoneminder.bug-presubj new file mode 100644 index 000000000..990fc1d94 --- /dev/null +++ b/distros/beowulf/zoneminder.bug-presubj @@ -0,0 +1,5 @@ +Unless bug is specific to Debian please consider reporting it directly to +upstream developer(s): + + https://github.com/ZoneMinder/ZoneMinder/issues + diff --git a/distros/beowulf/zoneminder.dirs b/distros/beowulf/zoneminder.dirs new file mode 100644 index 000000000..6db3d5a95 --- /dev/null +++ b/distros/beowulf/zoneminder.dirs @@ -0,0 +1,9 @@ +var/log/zm +var/lib/zm +var/cache/zoneminder/events +var/cache/zoneminder/images +var/cache/zoneminder/temp +var/cache/zoneminder/cache +usr/share/zoneminder/db +etc/zm/ +etc/zm/conf.d diff --git a/distros/beowulf/zoneminder.docs b/distros/beowulf/zoneminder.docs new file mode 100644 index 000000000..b43bf86b5 --- /dev/null +++ b/distros/beowulf/zoneminder.docs @@ -0,0 +1 @@ +README.md diff --git a/distros/beowulf/zoneminder.examples b/distros/beowulf/zoneminder.examples new file mode 100644 index 000000000..3b8befe7b --- /dev/null +++ b/distros/beowulf/zoneminder.examples @@ -0,0 +1,2 @@ +debian/examples/* +dbuild/misc/apache.conf diff --git a/distros/beowulf/zoneminder.init b/distros/beowulf/zoneminder.init new file mode 100644 index 000000000..6132481f3 --- /dev/null +++ b/distros/beowulf/zoneminder.init @@ -0,0 +1,91 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: zoneminder +# Required-Start: $network $remote_fs $syslog +# Required-Stop: $network $remote_fs $syslog +# Should-Start: mysql +# Should-Stop: mysql +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Control ZoneMinder as a Service +# Description: ZoneMinder CCTV recording and surveillance system +### END INIT INFO +# chkconfig: 2345 20 20 + +# Source function library. +. /lib/lsb/init-functions + +prog=ZoneMinder +ZM_PATH_BIN="/usr/bin" +RUNDIR="/run/zm" +TMPDIR="/tmp/zm" +command="$ZM_PATH_BIN/zmpkg.pl" + +start() { + echo -n "Starting $prog: " + export TZ=:/etc/localtime + mkdir -p "$RUNDIR" && chown www-data:www-data "$RUNDIR" + mkdir -p "$TMPDIR" && chown www-data:www-data "$TMPDIR" + $command start + RETVAL=$? + [ $RETVAL = 0 ] && echo success + [ $RETVAL != 0 ] && echo failure + echo + [ $RETVAL = 0 ] && touch /var/lock/zm + return $RETVAL +} +stop() { + echo -n "Stopping $prog: " + # + # Why is this status check being done? + # as $command stop returns 1 if zoneminder + # is stopped, which will result in + # this returning 1, which will stuff + # dpkg when it tries to stop zoneminder before + # uninstalling . . . + # + result=`$command status` + if [ ! "$result" = "running" ]; then + echo "Zoneminder already stopped" + echo + RETVAL=0 + else + $command stop + RETVAL=$? + [ $RETVAL = 0 ] && echo success + [ $RETVAL != 0 ] && echo failure + echo + [ $RETVAL = 0 ] && rm -f /var/lock/zm + fi +} +status() { + result=`$command status` + if [ "$result" = "running" ]; then + echo "ZoneMinder is running" + RETVAL=0 + else + echo "ZoneMinder is stopped" + RETVAL=1 + fi +} + +case "$1" in +'start') + start + ;; +'stop') + stop + ;; +'restart' | 'force-reload') + stop + start + ;; +'status') + status + ;; +*) + echo "Usage: $0 { start | stop | restart | status }" + RETVAL=1 + ;; +esac +exit $RETVAL diff --git a/distros/beowulf/zoneminder.install b/distros/beowulf/zoneminder.install new file mode 100644 index 000000000..67b135de5 --- /dev/null +++ b/distros/beowulf/zoneminder.install @@ -0,0 +1,11 @@ +etc/zm/zm.conf +etc/zm/conf.d/* +usr/bin +usr/lib/zoneminder +usr/share/polkit-1 +usr/share/zoneminder/db +usr/share/zoneminder/www + +# libzoneminder-perl files: +usr/share/man/man3 +usr/share/perl5 diff --git a/distros/beowulf/zoneminder.links b/distros/beowulf/zoneminder.links new file mode 100644 index 000000000..b7258c3c4 --- /dev/null +++ b/distros/beowulf/zoneminder.links @@ -0,0 +1 @@ +/var/tmp /usr/share/zoneminder/www/api/app/tmp diff --git a/distros/beowulf/zoneminder.linktrees b/distros/beowulf/zoneminder.linktrees new file mode 100644 index 000000000..2e843bbf1 --- /dev/null +++ b/distros/beowulf/zoneminder.linktrees @@ -0,0 +1,14 @@ +## cakephp +#replace /usr/share/php/Cake /usr/share/zoneminder/www/api/lib/Cake + +## libjs-mootools +replace /usr/share/javascript/mootools/mootools.js /usr/share/zoneminder/www/tools/mootools/mootools-core.js +replace /usr/share/javascript/mootools/mootools.js /usr/share/zoneminder/www/tools/mootools/mootools-core-1.3.2-nc.js +replace /usr/share/javascript/mootools/mootools.js /usr/share/zoneminder/www/tools/mootools/mootools-core-1.3.2-yc.js +replace /usr/share/javascript/mootools/mootools-more.js /usr/share/zoneminder/www/tools/mootools/mootools-more.js +replace /usr/share/javascript/mootools/mootools-more.js /usr/share/zoneminder/www/tools/mootools/mootools-more-1.3.2.1-nc.js +replace /usr/share/javascript/mootools/mootools-more.js /usr/share/zoneminder/www/tools/mootools/mootools-more-1.3.2.1-yc.js + +## libjs-jquery +replace /usr/share/javascript/jquery/jquery.min.js /usr/share/zoneminder/www/skins/classic/js/jquery-1.4.2.min.js +replace /usr/share/javascript/jquery/jquery.min.js /usr/share/zoneminder/www/skins/flat/js/jquery-1.4.2.min.js diff --git a/distros/beowulf/zoneminder.lintian-overrides b/distros/beowulf/zoneminder.lintian-overrides new file mode 100644 index 000000000..90be05a9f --- /dev/null +++ b/distros/beowulf/zoneminder.lintian-overrides @@ -0,0 +1,14 @@ +# Depends: policykit-1 +unusual-interpreter usr/bin/zmsystemctl.pl #!/usr/bin/pkexec + +# Intentionally not others-readable, #637685. +non-standard-file-perm etc/zm/zm.conf 0640 != 0644 + +# Bundled Cake PHP framework, not intended for direct execution: +script-not-executable usr/share/zoneminder/www/api/* + +# Annoying but seems to be too much troubles to fix; should be fixed upstream: +script-with-language-extension usr/bin/*.pl + +# dh-linktree: +package-contains-broken-symlink usr/share/zoneminder/www/api/lib/Cake/* diff --git a/distros/beowulf/zoneminder.logrotate b/distros/beowulf/zoneminder.logrotate new file mode 100644 index 000000000..6162e9c4d --- /dev/null +++ b/distros/beowulf/zoneminder.logrotate @@ -0,0 +1,13 @@ +/var/log/zm/*.log { + missingok + notifempty + sharedscripts + delaycompress + compress + postrotate + /usr/bin/zmpkg.pl logrot >>/dev/null 2>&1 || : + endscript + daily + rotate 7 + maxage 7 +} diff --git a/distros/beowulf/zoneminder.maintscript b/distros/beowulf/zoneminder.maintscript new file mode 100644 index 000000000..3aa20b3a0 --- /dev/null +++ b/distros/beowulf/zoneminder.maintscript @@ -0,0 +1 @@ +rm_conffile /etc/zm/apache.conf 1.28.1-5~ diff --git a/distros/beowulf/zoneminder.manpages b/distros/beowulf/zoneminder.manpages new file mode 100644 index 000000000..d2053d688 --- /dev/null +++ b/distros/beowulf/zoneminder.manpages @@ -0,0 +1 @@ +docs/_build/man/*.1 diff --git a/distros/beowulf/zoneminder.postinst b/distros/beowulf/zoneminder.postinst new file mode 100644 index 000000000..603786ff6 --- /dev/null +++ b/distros/beowulf/zoneminder.postinst @@ -0,0 +1,66 @@ +#! /bin/sh + +set -e + +if [ "$1" = "configure" ]; then + + . /etc/zm/zm.conf + for i in /etc/zm/conf.d/*.conf; do + . $i + done; + + + # The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group + chown www-data:root /var/log/zm + chown www-data:www-data /var/lib/zm + if [ -z "$2" ]; then + chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/* + fi + + # Do this every time the package is installed or upgraded + # Ensure zoneminder is stopped + invoke-rc.d zoneminder stop || true + + if [ "$ZM_DB_HOST" = "localhost" ]; then + if [ -e "/etc/init.d/mysql" ]; then + # + # Get mysql started if it isn't + # + if ! $(/etc/init.d/mysql status >/dev/null 2>&1); then + invoke-rc.d mysql start + fi + if $(/etc/init.d/mysql status >/dev/null 2>&1); then + mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload + # test if database if already present... + if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then + cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf + if [ $? -ne 0 ]; then + echo "Error creating db." + exit 1; + fi + # 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 + else + 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 + + 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 + echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.' + fi + else + echo 'mysql not found, assuming remote server.' + fi + else + echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)" + fi + echo "Done Updating, starting ZoneMinder" + invoke-rc.d zoneminder start || true +fi + +#DEBHELPER# diff --git a/distros/beowulf/zoneminder.postrm b/distros/beowulf/zoneminder.postrm new file mode 100644 index 000000000..ba2066c8d --- /dev/null +++ b/distros/beowulf/zoneminder.postrm @@ -0,0 +1,14 @@ +#! /bin/sh + +set -e + +if [ "$1" = "purge" ]; then + echo " +Reminder: to completely remove \"zoneminder\" it may be necessary + * to delete database using the following sample command: + sudo mysqladmin --defaults-file=/etc/mysql/debian.cnf -f drop zm + * to delete remaining data files in "/var/cache/zoneminder". +" +fi + +#DEBHELPER# diff --git a/distros/beowulf/zoneminder.preinst b/distros/beowulf/zoneminder.preinst new file mode 100644 index 000000000..6088c3ea9 --- /dev/null +++ b/distros/beowulf/zoneminder.preinst @@ -0,0 +1,11 @@ +#!/bin/sh + +set -e + +## Remove obsolete symlink which is in the way of dh_apache2: +ol="/etc/apache2/conf-available/zoneminder.conf" +if [ -h "${ol}" ]; then + [ "$(readlink ${ol})" = "/etc/zm/apache.conf" ] && rm -f "${ol}" +fi + +#DEBHELPER# diff --git a/distros/beowulf/zoneminder.tmpfile b/distros/beowulf/zoneminder.tmpfile new file mode 100644 index 000000000..cbfdec1de --- /dev/null +++ b/distros/beowulf/zoneminder.tmpfile @@ -0,0 +1,4 @@ +d /run/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/cache/zoneminder/cache 0755 www-data www-data diff --git a/distros/redhat/CMakeLists.txt b/distros/redhat/CMakeLists.txt index f1a1bc75b..45cafe57d 100644 --- a/distros/redhat/CMakeLists.txt +++ b/distros/redhat/CMakeLists.txt @@ -21,7 +21,7 @@ endif(ZM_TARGET_DISTRO MATCHES "^el") # Configure the common zoneminder files configure_file(common/zoneminder.logrotate.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.logrotate @ONLY) configure_file(common/zoneminder.service.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.service @ONLY) -file(MAKE_DIRECTORY sock swap zoneminder zoneminder-upload events temp) +file(MAKE_DIRECTORY sock swap zoneminder events temp) # Configure the Apache zoneminder files configure_file(httpd/zm-httpd.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zm-httpd.conf @ONLY) @@ -51,7 +51,6 @@ install(DIRECTORY sock swap DESTINATION /var/lib/zoneminder DIRECTORY_PERMISSION 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/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 events temp DESTINATION /var/lib/zoneminder DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) # Install the Apache zoneminder files diff --git a/distros/redhat/common/zoneminder.service.in b/distros/redhat/common/zoneminder.service.in index 8551a60e2..f4b3aad9b 100644 --- a/distros/redhat/common/zoneminder.service.in +++ b/distros/redhat/common/zoneminder.service.in @@ -5,6 +5,7 @@ Description=ZoneMinder CCTV recording and security system After=network.target mariadb.service Requires=mariadb.service +BindsTo=mariadb.service [Service] Type=forking diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 834cdecb8..8a03de245 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -28,14 +28,18 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.35.5 +Version: 1.35.6 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons -# Mootools is inder the MIT license: http://mootools.net/ +# Mootools is under the MIT license: http://mootools.net/ +# jQuery is under the MIT license: https://jquery.org/license/ # CakePHP is under the MIT license: https://github.com/cakephp/cakephp # 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 +# Bootstrap is under the MIT license: https://getbootstrap.com/docs/4.5/about/license/ +# Bootstrap-table is under the MIT license: https://bootstrap-table.com/docs/about/license/ +# font-awesome is under CC-BY license: https://fontawesome.com/license/free License: GPLv2+ and LGPLv2+ and MIT URL: http://www.zoneminder.com/ @@ -200,11 +204,8 @@ mv -f CakePHP-Enum-Behavior-%{ceb_version} ./web/api/app/Plugin/CakePHP-Enum-Beh # Change the following default values ./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes -./utils/zmeditconfigdata.sh ZM_UPLOAD_FTP_LOC_DIR %{_localstatedir}/spool/zoneminder-upload ./utils/zmeditconfigdata.sh ZM_OPT_CONTROL yes ./utils/zmeditconfigdata.sh ZM_CHECK_FOR_UPDATES no -./utils/zmeditconfigdata.sh ZM_DYN_SHOW_DONATE_REMINDER no -./utils/zmeditconfigdata.sh ZM_OPT_FAST_DELETE no %build # Disable LTO due to top level asm @@ -395,7 +396,6 @@ EOF %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}/spool/zoneminder-upload %files nginx %config(noreplace) %attr(640,root,nginx) %{_sysconfdir}/zm/zm.conf @@ -419,7 +419,6 @@ EOF %dir %attr(755,nginx,nginx) %{_sharedstatedir}/zoneminder/temp %dir %attr(755,nginx,nginx) %{_localstatedir}/cache/zoneminder %dir %attr(755,nginx,nginx) %{_localstatedir}/log/zoneminder -%dir %attr(755,nginx,nginx) %{_localstatedir}/spool/zoneminder-upload %changelog * Tue Feb 04 2020 Andrew Bauer - 1.34.2-1 diff --git a/distros/ubuntu1604/changelog b/distros/ubuntu1604/changelog index 616f75178..0fc2fda2e 100644 --- a/distros/ubuntu1604/changelog +++ b/distros/ubuntu1604/changelog @@ -1,3 +1,3 @@ -zoneminder (1.31.39~20180223.27-stretch-1) unstable; urgency=low - * - -- Isaac Connor Fri, 23 Feb 2018 14:15:59 -0500 +zoneminder (1.35.6~20200825.27-xenial) xenial; urgency=low + * + -- Isaac Connor Tue, 25 Aug 2020 09:28:18 -0400 diff --git a/distros/ubuntu2004/control b/distros/ubuntu2004/control index 3647dfab5..0a1f9e0de 100644 --- a/distros/ubuntu2004/control +++ b/distros/ubuntu2004/control @@ -3,7 +3,7 @@ Section: net Priority: optional Maintainer: Isaac Connor Uploaders: Isaac Connor -Build-Depends: debhelper, dh-systemd, sphinx-doc, dh-linktree, dh-systemd, dh-apache2 +Build-Depends: debhelper, dh-systemd, sphinx-doc, python3-sphinx, dh-linktree, dh-systemd, dh-apache2 ,cmake ,libx264-dev, libmp4v2-dev ,libavdevice-dev diff --git a/distros/ubuntu2004/rules b/distros/ubuntu2004/rules index 9a16b1f8f..5a1cdb500 100755 --- a/distros/ubuntu2004/rules +++ b/distros/ubuntu2004/rules @@ -23,7 +23,7 @@ override_dh_auto_configure: -DZM_CONFIG_SUBDIR="/etc/zm/conf.d" \ -DZM_RUNDIR="/run/zm" \ -DZM_SOCKDIR="/run/zm" \ - -DZM_TMPDIR="/tmp/zm" \ + -DZM_TMPDIR="/var/tmp/zm" \ -DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \ -DZM_CACHEDIR="/var/cache/zoneminder/cache" \ -DZM_DIR_EVENTS="/var/cache/zoneminder/events" \ diff --git a/distros/ubuntu2004/zoneminder.init b/distros/ubuntu2004/zoneminder.init new file mode 100644 index 000000000..6132481f3 --- /dev/null +++ b/distros/ubuntu2004/zoneminder.init @@ -0,0 +1,91 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: zoneminder +# Required-Start: $network $remote_fs $syslog +# Required-Stop: $network $remote_fs $syslog +# Should-Start: mysql +# Should-Stop: mysql +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Control ZoneMinder as a Service +# Description: ZoneMinder CCTV recording and surveillance system +### END INIT INFO +# chkconfig: 2345 20 20 + +# Source function library. +. /lib/lsb/init-functions + +prog=ZoneMinder +ZM_PATH_BIN="/usr/bin" +RUNDIR="/run/zm" +TMPDIR="/tmp/zm" +command="$ZM_PATH_BIN/zmpkg.pl" + +start() { + echo -n "Starting $prog: " + export TZ=:/etc/localtime + mkdir -p "$RUNDIR" && chown www-data:www-data "$RUNDIR" + mkdir -p "$TMPDIR" && chown www-data:www-data "$TMPDIR" + $command start + RETVAL=$? + [ $RETVAL = 0 ] && echo success + [ $RETVAL != 0 ] && echo failure + echo + [ $RETVAL = 0 ] && touch /var/lock/zm + return $RETVAL +} +stop() { + echo -n "Stopping $prog: " + # + # Why is this status check being done? + # as $command stop returns 1 if zoneminder + # is stopped, which will result in + # this returning 1, which will stuff + # dpkg when it tries to stop zoneminder before + # uninstalling . . . + # + result=`$command status` + if [ ! "$result" = "running" ]; then + echo "Zoneminder already stopped" + echo + RETVAL=0 + else + $command stop + RETVAL=$? + [ $RETVAL = 0 ] && echo success + [ $RETVAL != 0 ] && echo failure + echo + [ $RETVAL = 0 ] && rm -f /var/lock/zm + fi +} +status() { + result=`$command status` + if [ "$result" = "running" ]; then + echo "ZoneMinder is running" + RETVAL=0 + else + echo "ZoneMinder is stopped" + RETVAL=1 + fi +} + +case "$1" in +'start') + start + ;; +'stop') + stop + ;; +'restart' | 'force-reload') + stop + start + ;; +'status') + status + ;; +*) + echo "Usage: $0 { start | stop | restart | status }" + RETVAL=1 + ;; +esac +exit $RETVAL diff --git a/distros/ubuntu2004/zoneminder.postinst b/distros/ubuntu2004/zoneminder.postinst index a7f8f3131..39a2fa1b0 100644 --- a/distros/ubuntu2004/zoneminder.postinst +++ b/distros/ubuntu2004/zoneminder.postinst @@ -2,13 +2,47 @@ set +e +create_db () { + echo "Checking for db" + mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload + # test if database if already present... + 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 + if [ $? -ne 0 ]; then + echo "Error creating db." + exit 1; + fi + else + echo "Db exists." + fi + USER_EXISTS="$(mysql --defaults-file=/etc/mysql/debian.cnf -sse "SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = '$ZM_DB_USER')")" + if [ $USER_EXISTS -ne 1 ]; then + echo "Creating zm user $ZM_DB_USER" + # This creates the user. + echo "CREATE USER '${ZM_DB_USER}'@${ZM_DB_HOST} IDENTIFIED BY '${ZM_DB_PASS}';" | mysql --defaults-file=/etc/mysql/debian.cnf mysql + fi +} + +update_db () { + 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}'@${ZM_DB_HOST};" | mysql --defaults-file=/etc/mysql/debian.cnf mysql + + 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 + echo "Done Updating" +} + if [ "$1" = "configure" ]; then - + . /etc/zm/zm.conf for CONFFILE in /etc/zm/conf.d/*.conf; do . "$CONFFILE" done - + # The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group chown www-data:root /var/log/zm chown www-data:www-data /var/lib/zm @@ -20,16 +54,24 @@ if [ "$1" = "configure" ]; then a2enmod cgi fi + SYSTEMD=0 + if [ -e "/run/systemd/system" ]; then + SYSTEMD=1 + echo "detected systemd" + # Ensure zoneminder is stopped + deb-systemd-invoke stop zoneminder.service || exit $? + else + # Ensure zoneminder is stopped + invoke-rc.d zoneminder stop || true + fi + if [ "$ZM_DB_HOST" = "localhost" ]; then - if [ -e "/lib/systemd/system/mysql.service" ] || [ -e "/lib/systemd/system/mariadb.service" ] || [ -e "/etc/init.d/mysql" ]; then - # Ensure zoneminder is stopped - deb-systemd-invoke stop zoneminder.service || exit $? - + if [ $SYSTEMD -eq 1 ] && ([ -e "/lib/systemd/system/mysql.service" ] || [ -e "/lib/systemd/system/mariadb.service" ]); then # # Get mysql started if it isn't running # - + if [ -e "/lib/systemd/system/mariadb.service" ]; then DBSERVICE="mariadb.service" else @@ -42,48 +84,48 @@ if [ "$1" = "configure" ]; then echo "run sudo systemctl restart $DBSERVICE then run sudo dpkg-reconfigure zoneminder." exit 1 fi - + if ! systemctl is-active --quiet mysql.service mariadb.service; then # Due to /etc/init.d service autogeneration, mysql.service always returns the status of mariadb.service # However, mariadb.service will not return the status of mysql.service. deb-systemd-invoke start $DBSERVICE fi - + # Make sure systemctl status exit code is 0; i.e. the DB is running if systemctl is-active --quiet "$DBSERVICE"; then - mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload - # test if database if already present... - 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 - if [ $? -ne 0 ]; then - echo "Error creating db." - exit 1; - fi - # This creates the user. - echo "CREATE USER '${ZM_DB_USER}'@localhost IDENTIFIED BY '${ZM_DB_PASS}';" | mysql --defaults-file=/etc/mysql/debian.cnf mysql - fi - 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 - - 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 - echo "Done Updating; starting ZoneMinder." + create_db + update_db else echo 'NOTE: MySQL/MariaDB not running; please start mysql and run dpkg-reconfigure zoneminder when it is running.' fi + + elif [ -e "/etc/init.d/mysql" ]; then + # + # Get mysql started if it isn't + # + if ! $(/etc/init.d/mysql status >/dev/null 2>&1); then + service mysql start + fi + if $(/etc/init.d/mysql status >/dev/null 2>&1); then + create_db + update_db + else + echo 'NOTE: MySQL/MariaDB not running; please start mysql and run dpkg-reconfigure zoneminder when it is running.' + fi + else echo 'MySQL/MariaDB not found; assuming remote server.' fi - - else - echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)." fi - deb-systemd-invoke restart zoneminder.service +else + echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)." +fi + +if [ $SYSTEMD -eq 1 ]; then + deb-systemd-invoke restart zoneminder.service +#else + #service zoneminder start || true fi #DEBHELPER# diff --git a/docs/installationguide/debian.rst b/docs/installationguide/debian.rst index 080b95d5b..d09423bd9 100644 --- a/docs/installationguide/debian.rst +++ b/docs/installationguide/debian.rst @@ -43,7 +43,7 @@ trigger their installation manually. :: - sudo apt install apache2 mysql-server + sudo apt install apache2 default-mysql-server **Step 4:** Add ZoneMinder's Package repository to your apt sources @@ -51,25 +51,29 @@ ZoneMinder's Debian packages are not included in Debian's official package repositories. To be able to install ZoneMinder with APT, you have to edit the list of apt sources and add ZoneMinder's repository. -:: - - sudo nano /etc/apt/sources.list - -Add the following to the bottom of the file +Add the following to the /etc/apt/sources.list.d/zoneminder.list file :: # ZoneMinder repository deb https://zmrepo.zoneminder.com/debian/release-1.34 buster/ -CTRL+o and to save -CTRL+x to exit +You can do this using: + +:: + echo "deb https://zmrepo.zoneminder.com/debian/release-1.34 buster/" | sudo tee /etc/apt/sources.list.d/zoneminder.list Because ZoneMinder's package repository provides a secure connection through HTTPS, apt must be enabled for HTTPS. :: sudo apt install apt-transport-https +Ensure you have gnupg installed before importing the apt key in the following step. +:: + + sudo apt install gnupg + + Finally, download the GPG key for ZoneMinder's repository: :: @@ -107,7 +111,7 @@ required apache modules. :: sudo a2enconf zoneminder - sudo a2enmod rewrite + sudo a2enmod rewrite # this is enabled by default sudo a2enmod cgi # this is done automatically when installing the package. Redo this command manually only for troubleshooting. @@ -116,12 +120,12 @@ required apache modules. Automated way: :: - sudo sed -i "s/;date.timezone =/date.timezone = $(sed 's/\//\\\//' /etc/timezone)/g" /etc/php/7.0/apache2/php.ini + sudo sed -i "s/;date.timezone =/date.timezone = $(sed 's/\//\\\//' /etc/timezone)/g" /etc/php/7.*/apache2/php.ini Manual way :: - sudo nano /etc/php/7.0/apache2/php.ini + sudo nano /etc/php/7.*/apache2/php.ini Search for [Date] (Ctrl + w then type Date and press Enter) and change date.timezone for your time zone. Don't forget to remove the ; from in front diff --git a/docs/userguide/gettingstarted.rst b/docs/userguide/gettingstarted.rst index 0b40d7fb9..99f2ea4ba 100644 --- a/docs/userguide/gettingstarted.rst +++ b/docs/userguide/gettingstarted.rst @@ -51,7 +51,7 @@ This screen is called the "console" screen in ZoneMinder and shows a summary of * **A**: The options menu lets you configure many aspects of ZoneMinder. Refer to :doc:`options`. * **B**: This brings up a color coded log window that shows various system and component level logs. This window is useful if you are trying to diagnose issues. Refer to :doc:`logging`. -* **C**: ZoneMinder allows you to group monitors gor logical separation. This option lets you create new groups, associate monitors to them and edit/delete existing groups. +* **C**: ZoneMinder allows you to group monitors for logical separation. This option lets you create new groups, associate monitors to them and edit/delete existing groups. * **D**: Filters are a powerful mechanism to perform actions when certain conditions are met. ZoneMinder comes with some preset filters that keep a tab of disk space and others. Many users create their own filters for more advanced actions like sending emails when certain events occur and more. Refer to :doc:`filterevents`. * **E**: The Cycle option allows you to rotate between live views of each cofigured monitor. * **F**: The Montage option shows a collage of your monitors. You can customize them including moving them around. diff --git a/onvif/modules/MYMETA.json b/onvif/modules/MYMETA.json deleted file mode 100644 index cab2ae939..000000000 --- a/onvif/modules/MYMETA.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "abstract" : "unknown", - "author" : [ - "Jan Hochstein" - ], - "dynamic_config" : 0, - "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010", - "license" : [ - "unknown" - ], - "meta-spec" : { - "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", - "version" : 2 - }, - "name" : "ONVIF", - "no_index" : { - "directory" : [ - "t", - "inc" - ] - }, - "prereqs" : { - "build" : { - "requires" : { - "ExtUtils::MakeMaker" : "0" - } - }, - "configure" : { - "requires" : { - "ExtUtils::MakeMaker" : "0" - } - }, - "runtime" : { - "requires" : {} - } - }, - "release_status" : "stable", - "version" : "", - "x_serialization_backend" : "JSON::PP version 4.02" -} diff --git a/onvif/modules/MYMETA.yml b/onvif/modules/MYMETA.yml deleted file mode 100644 index ea47256fc..000000000 --- a/onvif/modules/MYMETA.yml +++ /dev/null @@ -1,22 +0,0 @@ ---- -abstract: unknown -author: - - 'Jan Hochstein' -build_requires: - ExtUtils::MakeMaker: '0' -configure_requires: - ExtUtils::MakeMaker: '0' -dynamic_config: 0 -generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010' -license: unknown -meta-spec: - url: http://module-build.sourceforge.net/META-spec-v1.4.html - version: '1.4' -name: ONVIF -no_index: - directory: - - t - - inc -requires: {} -version: '' -x_serialization_backend: 'CPAN::Meta::YAML version 0.018' diff --git a/onvif/proxy/MYMETA.json b/onvif/proxy/MYMETA.json deleted file mode 100644 index cab2ae939..000000000 --- a/onvif/proxy/MYMETA.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "abstract" : "unknown", - "author" : [ - "Jan Hochstein" - ], - "dynamic_config" : 0, - "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010", - "license" : [ - "unknown" - ], - "meta-spec" : { - "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", - "version" : 2 - }, - "name" : "ONVIF", - "no_index" : { - "directory" : [ - "t", - "inc" - ] - }, - "prereqs" : { - "build" : { - "requires" : { - "ExtUtils::MakeMaker" : "0" - } - }, - "configure" : { - "requires" : { - "ExtUtils::MakeMaker" : "0" - } - }, - "runtime" : { - "requires" : {} - } - }, - "release_status" : "stable", - "version" : "", - "x_serialization_backend" : "JSON::PP version 4.02" -} diff --git a/onvif/proxy/MYMETA.yml b/onvif/proxy/MYMETA.yml deleted file mode 100644 index ea47256fc..000000000 --- a/onvif/proxy/MYMETA.yml +++ /dev/null @@ -1,22 +0,0 @@ ---- -abstract: unknown -author: - - 'Jan Hochstein' -build_requires: - ExtUtils::MakeMaker: '0' -configure_requires: - ExtUtils::MakeMaker: '0' -dynamic_config: 0 -generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010' -license: unknown -meta-spec: - url: http://module-build.sourceforge.net/META-spec-v1.4.html - version: '1.4' -name: ONVIF -no_index: - directory: - - t - - inc -requires: {} -version: '' -x_serialization_backend: 'CPAN::Meta::YAML version 0.018' diff --git a/onvif/proxy/pm_to_blib b/onvif/proxy/pm_to_blib deleted file mode 100644 index e69de29bb..000000000 diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in index 10e4b4733..21f9a2d02 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in @@ -76,39 +76,42 @@ BEGIN { require ZoneMinder::Database; # Process name, value pairs from the main config file first - my $config_file = ZM_CONFIG; - process_configfile($config_file); + process_configfile(ZM_CONFIG); # Search for user created config files. If one or more are found then # update the Config hash with those values if ( ZM_CONFIG_SUBDIR and -d ZM_CONFIG_SUBDIR ) { if ( -R ZM_CONFIG_SUBDIR ) { - foreach my $filename ( glob ZM_CONFIG_SUBDIR.'/*.conf' ) { + foreach my $filename (glob ZM_CONFIG_SUBDIR.'/*.conf' ) { process_configfile($filename); } } else { - print( STDERR 'WARNING: ZoneMinder configuration subfolder found but is not readable. Check folder permissions on '.ZM_CONFIG_SUBDIR.".\n" ); + print(STDERR 'WARNING: ZoneMinder configuration subfolder found but is not readable. Check folder permissions on '.ZM_CONFIG_SUBDIR.".\n"); } } my $dbh = ZoneMinder::Database::zmDbConnect(); + die "Unable to connect to DB. ZM Cannot continue.\n" if !$dbh; + my $sql = 'SELECT Name,Value FROM Config'; my $sth = $dbh->prepare_cached($sql) or croak("Can't prepare '$sql': ".$dbh->errstr()); my $res = $sth->execute() or croak("Can't execute: ".$sth->errstr()); - while( my $config = $sth->fetchrow_hashref() ) { + while ( my $config = $sth->fetchrow_hashref() ) { + # If already defined skip it because we want the values in /etc/zm.conf to override the values in Config Table + next if exists $Config{$config->{Name}}; $Config{$config->{Name}} = $config->{Value}; } $sth->finish(); - if ( ! $Config{ZM_SERVER_ID} ) { + if ( !$Config{ZM_SERVER_ID} ) { $Config{ZM_SERVER_ID} = undef; - $sth = $dbh->prepare_cached( 'SELECT * FROM Servers WHERE Name=?' ); + $sth = $dbh->prepare_cached('SELECT * FROM Servers WHERE Name=?'); if ( $Config{ZM_SERVER_NAME} ) { - $res = $sth->execute( $Config{ZM_SERVER_NAME} ); + $res = $sth->execute($Config{ZM_SERVER_NAME}); my $result = $sth->fetchrow_hashref(); $Config{ZM_SERVER_ID} = $$result{Id}; } elsif ( $Config{ZM_SERVER_HOST} ) { - $res = $sth->execute( $Config{ZM_SERVER_HOST} ); + $res = $sth->execute($Config{ZM_SERVER_HOST}); my $result = $sth->fetchrow_hashref(); $Config{ZM_SERVER_ID} = $$result{Id}; } @@ -126,20 +129,20 @@ require ZoneMinder::Database; open( my $CONFIG, '<', $config_file ) or croak("Can't open config file '$config_file': $!"); foreach my $str ( <$CONFIG> ) { - next if ( $str =~ /^\s*$/ ); + next if ( $str =~ /^\s*$/ ); next if ( $str =~ /^\s*#/ ); my ( $name, $value ) = $str =~ /^\s*([^=\s]+)\s*=\s*[\'"]*(.*?)[\'"]*\s*$/; if ( !$name ) { print(STDERR "Warning, bad line in $config_file: $str\n"); next; } # end if - $name =~ tr/a-z/A-Z/; + $name = uc $name; #if ( !$ZoneMinder::ConfigData::options_hash{$name} ) { - #print(STDERR "Warning, unknown config option name $name in $config_file\n"); -#} else { - #print(STDERR "Warning, known config option name $name in $config_file\n"); - #} - $Config{$name} = $value; + #print(STDERR "Warning, unknown config option name $name in $config_file\n"); + #} else { + #print(STDERR "Warning, known config option name $name in $config_file\n"); + #} + $Config{$name} = $value; } # end foreach config line close($CONFIG); } # end sub process_configfile @@ -147,11 +150,11 @@ require ZoneMinder::Database; } # end BEGIN sub loadConfigFromDB { - print( 'Loading config from DB' ); + print('Loading config from DB'); my $dbh = ZoneMinder::Database::zmDbConnect(); if ( !$dbh ) { - print( "Error: unable to load options from database: $DBI::errstr\n" ); - return( 0 ); + print("Error: unable to load options from database: $DBI::errstr\n"); + return(0); } my $sql = "select * from Config"; my $sth = $dbh->prepare_cached( $sql ) @@ -161,13 +164,13 @@ sub loadConfigFromDB { my $option_count = 0; while( my $config = $sth->fetchrow_hashref() ) { my ( $name, $value ) = ( $config->{Name}, $config->{Value} ); -#print( "Name = '$name'\n" ); + #print( "Name = '$name'\n" ); my $option = $options_hash{$name}; if ( !$option ) { warn( "No option '$name' found, removing.\n" ); next; } -#next if ( $option->{category} eq 'hidden' ); + #next if ( $option->{category} eq 'hidden' ); if ( defined($value) ) { if ( $option->{type} == $types{boolean} ) { $option->{value} = $value?'yes':'no'; @@ -204,8 +207,8 @@ sub saveConfigToDB { my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() ); foreach my $option ( @options ) { -#next if ( $option->{category} eq 'hidden' ); -#print( $option->{name}."\n" ) if ( !$option->{category} ); + #next if ( $option->{category} eq 'hidden' ); + #print( $option->{name}."\n" ) if ( !$option->{category} ); $option->{db_type} = $option->{type}->{db_type}; $option->{db_hint} = $option->{type}->{hint}; $option->{db_pattern} = $option->{type}->{pattern}; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index 8310d8e1d..cf2b59c85 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -582,26 +582,6 @@ our @options = ( type => $types{integer}, category => 'images', }, -# Deprecated, now stream quality - { - name => 'ZM_JPEG_IMAGE_QUALITY', - default => '70', - description => q`Set the JPEG quality setting for the streamed 'live' images (1-100)`, - help => q` - When viewing a 'live' stream for a monitor ZoneMinder will grab - an image from the buffer and encode it into JPEG format before - sending it. This option specifies what image quality should be - used to encode these images. A higher number means better - quality but less compression so will take longer to view over a - slow connection. By contrast a low number means quicker to view - images but at the price of lower quality images. This option - does not apply when viewing events or still images as these are - usually just read from disk and so will be encoded at the - quality specified by the previous options. - `, - type => $types{integer}, - category => 'hidden', - }, { name => 'ZM_JPEG_STREAM_QUALITY', default => '70', @@ -877,38 +857,6 @@ our @options = ( type => $types{integer}, category => 'config', }, -# Deprecated, really no longer necessary - { - name => 'ZM_OPT_REMOTE_CAMERAS', - default => 'no', - description => 'Are you going to use remote/networked cameras', - help => q` - ZoneMinder can work with both local cameras, ie. those attached - physically to your computer and remote or network cameras. If - you will be using networked cameras select this option. - `, - type => $types{boolean}, - category => 'hidden', - }, -# Deprecated, now set on a per monitor basis using the Method field - { - name => 'ZM_NETCAM_REGEXPS', - default => 'yes', - description => 'Use regular expression matching with network cameras', - help => q` - Traditionally ZoneMinder has used complex regular regular - expressions to handle the multitude of formats that network - cameras produce. In versions from 1.21.1 the default is to use - a simpler and faster built in pattern matching methodology. - This works well with most networks cameras but if you have - problems you can try the older, but more flexible, regular - expression based method by selecting this option. Note, to use - this method you must have libpcre installed on your system. - `, - requires => [ { name => 'ZM_OPT_REMOTE_CAMERAS', value => 'yes' } ], - type => $types{boolean}, - category => 'hidden', - }, { name => 'ZM_HTTP_VERSION', default => '1.0', @@ -1974,19 +1922,6 @@ our @options = ( }, category => 'upload', }, - { - name => 'ZM_UPLOAD_FTP_HOST', - default => '', - description => 'The remote server to upload to', - help => q` - You can use filters to instruct ZoneMinder to upload events to - a remote ftp server. This option indicates the name, or ip - address, of the server to use. - `, - requires => [ { name => 'ZM_OPT_UPLOAD', value => 'yes' } ], - type => $types{hostname}, - category => 'hidden', - }, { name => 'ZM_UPLOAD_HOST', default => '', @@ -2015,19 +1950,6 @@ our @options = ( type => $types{integer}, category => 'upload', }, - { - name => 'ZM_UPLOAD_FTP_USER', - default => '', - description => 'Your ftp username', - help => q` - You can use filters to instruct ZoneMinder to upload events to - a remote ftp server. This option indicates the username that - ZoneMinder should use to log in for ftp transfer. - `, - requires => [ { name => 'ZM_OPT_UPLOAD', value => 'yes' } ], - type => $types{alphanum}, - category => 'hidden', - }, { name => 'ZM_UPLOAD_USER', default => '', @@ -2041,19 +1963,6 @@ our @options = ( type => $types{alphanum}, category => 'upload', }, - { - name => 'ZM_UPLOAD_FTP_PASS', - default => '', - description => 'Your ftp password', - help => q` - You can use filters to instruct ZoneMinder to upload events to - a remote ftp server. This option indicates the password that - ZoneMinder should use to log in for ftp transfer. - `, - requires => [ { name => 'ZM_OPT_UPLOAD', value => 'yes' } ], - type => $types{string}, - category => 'hidden', - }, { name => 'ZM_UPLOAD_PASS', default => '', @@ -2069,21 +1978,6 @@ our @options = ( type => $types{string}, category => 'upload', }, - { - name => 'ZM_UPLOAD_FTP_LOC_DIR', - default => '@ZM_TMPDIR@', - description => 'The local directory in which to create upload files', - help => q` - You can use filters to instruct ZoneMinder to upload events to - a remote ftp server. This option indicates the local directory - that ZoneMinder should use for temporary upload files. These - are files that are created from events, uploaded and then - deleted. - `, - requires => [ { name => 'ZM_OPT_UPLOAD', value => 'yes' } ], - type => $types{abs_path}, - category => 'hidden', - }, { name => 'ZM_UPLOAD_LOC_DIR', default => '@ZM_TMPDIR@', @@ -2098,19 +1992,6 @@ our @options = ( type => $types{abs_path}, category => 'upload', }, - { - name => 'ZM_UPLOAD_FTP_REM_DIR', - default => '', - description => 'The remote directory to upload to', - help => q` - You can use filters to instruct ZoneMinder to upload events to - a remote ftp server. This option indicates the remote directory - that ZoneMinder should use to upload event files to. - `, - requires => [ { name => 'ZM_OPT_UPLOAD', value => 'yes' } ], - type => $types{rel_path}, - category => 'hidden', - }, { name => 'ZM_UPLOAD_REM_DIR', default => '', @@ -2124,21 +2005,6 @@ our @options = ( type => $types{rel_path}, category => 'upload', }, - { - name => 'ZM_UPLOAD_FTP_TIMEOUT', - default => '120', - description => 'How long to allow the transfer to take for each file', - help => q` - You can use filters to instruct ZoneMinder to upload events to - a remote ftp server. This option indicates the maximum ftp - inactivity timeout (in seconds) that should be tolerated before - ZoneMinder determines that the transfer has failed and closes - down the connection. - `, - requires => [ { name => 'ZM_OPT_UPLOAD', value => 'yes' } ], - type => $types{integer}, - category => 'hidden', - }, { name => 'ZM_UPLOAD_TIMEOUT', default => '120', @@ -2191,20 +2057,6 @@ our @options = ( type => $types{boolean}, category => 'upload', }, - { - name => 'ZM_UPLOAD_FTP_DEBUG', - default => 'no', - description => 'Switch ftp debugging on', - help => q` - You can use filters to instruct ZoneMinder to upload events to - a remote ftp server. If you are having (or expecting) troubles - with uploading events then setting this to 'yes' permits - additional information to be included in the zmfilter log file. - `, - requires => [ { name => 'ZM_OPT_UPLOAD', value => 'yes' } ], - type => $types{boolean}, - category => 'hidden', - }, { name => 'ZM_UPLOAD_DEBUG', default => 'no', @@ -2237,85 +2089,6 @@ our @options = ( type => $types{boolean}, category => 'mail', }, - { - name => 'ZM_EMAIL_ADDRESS', - default => '', - description => 'The email address to send matching event details to', - requires => [ { name => 'ZM_OPT_EMAIL', value => 'yes' } ], - help => q` - This option is used to define the email address that any events - that match the appropriate filters will be sent to. - `, - type => $types{email}, - category => 'hidden', - }, - { - name => 'ZM_EMAIL_TEXT', - default => 'subject = "ZoneMinder: Alarm - %MN%-%EI% (%ESM% - %ESA% %EFA%)" - body = " - Hello, - - An alarm has been detected on your installation of the ZoneMinder. - - The details are as follows :- - - Monitor : %MN% - Event Id : %EI% - Length : %EL% - Frames : %EF% (%EFA%) - Scores : t%EST% m%ESM% a%ESA% - - This alarm was matched by the %FN% filter and can be viewed at %EPS% - - ZoneMinder"', - description => 'The text of the email used to send matching event details', - requires => [ { name => 'ZM_OPT_EMAIL', value => 'yes' } ], - help => q` - This option is used to define the content of the email that is - sent for any events that match the appropriate filters. - `, - type => $types{text}, - category => 'hidden', - }, - { - name => 'ZM_EMAIL_SUBJECT', - default => 'ZoneMinder: Alarm - %MN%-%EI% (%ESM% - %ESA% %EFA%)', - description => 'The subject of the email used to send matching event details', - requires => [ { name => 'ZM_OPT_EMAIL', value => 'yes' } ], - help => q` - This option is used to define the subject of the email that is - sent for any events that match the appropriate filters. - `, - type => $types{string}, - category => 'hidden', - }, - { - name => 'ZM_EMAIL_BODY', - default => ' - Hello, - - An alarm has been detected on your installation of the ZoneMinder. - - The details are as follows :- - - Monitor : %MN% - Event Id : %EI% - Length : %EL% - Frames : %EF% (%EFA%) - Scores : t%EST% m%ESM% a%ESA% - - This alarm was matched by the %FN% filter and can be viewed at %EPS% - - ZoneMinder', - description => 'The body of the email used to send matching event details', - requires => [ { name => 'ZM_OPT_EMAIL', value => 'yes' } ], - help => q` - This option is used to define the content of the email that is - sent for any events that match the appropriate filters. - `, - type => $types{text}, - category => 'hidden', - }, { name => 'ZM_OPT_MESSAGE', default => 'no', @@ -2347,19 +2120,6 @@ our @options = ( type => $types{email}, category => 'mail', }, - { - name => 'ZM_MESSAGE_TEXT', - default => 'subject = "ZoneMinder: Alarm - %MN%-%EI%" - body = "ZM alarm detected - %EL% secs, %EF%/%EFA% frames, t%EST%/m%ESM%/a%ESA% score."', - description => 'The text of the message used to send matching event details', - requires => [ { name => 'ZM_OPT_MESSAGE', value => 'yes' } ], - help => q` - This option is used to define the content of the message that - is sent for any events that match the appropriate filters. - `, - type => $types{text}, - category => 'hidden', - }, { name => 'ZM_MESSAGE_SUBJECT', default => 'ZoneMinder: Alarm - %MN%-%EI%', @@ -2652,23 +2412,6 @@ our @options = ( category => 'config', }, # Deprecated, superseded by event close mode - { - name => 'ZM_FORCE_CLOSE_EVENTS', - default => 'no', - description => 'Close events at section ends.', - help => q` - When a monitor is running in a continuous recording mode - (Record or Mocord) events are usually closed after a fixed - period of time (the section length). However in Mocord mode it - is possible that motion detection may occur near the end of a - section and ordinarily this will prevent the event being closed - until the motion has ceased. Switching this option on will - force the event closed at the specified time regardless of any - motion activity. - `, - type => $types{boolean}, - category => 'hidden', - }, { name => 'ZM_WEIGHTED_ALARM_CENTRES', default => 'no', @@ -2876,37 +2619,9 @@ our @options = ( type => $types{hexadecimal}, category => 'system', }, -# Deprecated, really no longer necessary - { - name => 'ZM_WEB_REFRESH_METHOD', - default => 'javascript', - description => 'What method windows should use to refresh themselves', - help => q` - Many windows in ZoneMinder need to refresh themselves to keep - their information current. This option determines what method - they should use to do this. Choosing 'javascript' means that - each window will have a short JavaScript statement in with a - timer to prompt the refresh. This is the most compatible - method. Choosing 'http' means the refresh instruction is put in - the HTTP header. This is a cleaner method but refreshes are - interrupted or cancelled when a link in the window is clicked - meaning that the window will no longer refresh and this would - have to be done manually. - `, - type => { - db_type =>'string', - hint =>'javascript|http', - pattern =>qr|^([jh])|i, - format =>q( $1 =~ /^j/ - ? 'javascript' - : 'http' - ) - }, - category => 'hidden', - }, { name => 'ZM_WEB_EVENT_SORT_FIELD', - default => 'DateTime', + default => 'StartDateTime', description => 'Default field the event lists are sorted by', help => q` Events in lists can be initially ordered in any way you want. @@ -2918,7 +2633,7 @@ our @options = ( `, type => { db_type =>'string', - hint =>'Id|Name|Cause|MonitorName|DateTime|Length|Frames|AlarmFrames|TotScore|AvgScore|MaxScore', + hint =>'Id|Name|Cause|DiskSpace|MonitorName|StartDateTime|Length|Frames|AlarmFrames|TotScore|AvgScore|MaxScore', pattern =>qr|.|, format =>q( $1 ) }, @@ -4043,7 +3758,6 @@ sub initialiseConfig { } else { $option->{value} = ''; } -#next if ( $option->{category} eq 'hidden' ); $option->{id} = $option_id++; } $configInitialised = 1; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/AxisV2.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/AxisV2.pm index 709f86940..64e284278 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/AxisV2.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/AxisV2.pm @@ -113,7 +113,7 @@ sub open { Debug('No headers line'); } # end if headers } else { - Warning('Failed to open '.$uri->canonical().$url.' status: '.$res->status_line()); + Debug('Failed to open '.$uri->canonical().$url.' status: '.$res->status_line()); } # end if $res->status_line() eq '401 Unauthorized' } # end sub open diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Database.pm b/scripts/ZoneMinder/lib/ZoneMinder/Database.pm index 827936b86..3fdcab5e2 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Database.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Database.pm @@ -146,15 +146,15 @@ sub zmDbGetMonitors { if ( $function ) { if ( $function == DB_MON_CAPT ) { - $sql .= " where `Function` >= 'Monitor'"; + $sql .= " WHERE `Function` >= 'Monitor'"; } elsif ( $function == DB_MON_ACTIVE ) { - $sql .= " where `Function` > 'Monitor'"; + $sql .= " WHERE `Function` > 'Monitor'"; } elsif ( $function == DB_MON_MOTION ) { - $sql .= " where `Function` = 'Modect' or Function = 'Mocord'"; + $sql .= " WHERE `Function` = 'Modect' OR `Function` = 'Mocord'"; } elsif ( $function == DB_MON_RECORD ) { - $sql .= " where `Function` = 'Record' or Function = 'Mocord'"; + $sql .= " WHERE `Function` = 'Record' OR `Function` = 'Mocord'"; } elsif ( $function == DB_MON_PASSIVE ) { - $sql .= " where `Function` = 'Nodect'"; + $sql .= " WHERE `Function` = 'Nodect'"; } } my $sth = $dbh->prepare_cached( $sql ); diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm index 91b87e615..b48946d1f 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm @@ -82,6 +82,13 @@ sub Execute { my $self = $_[0]; my $sql = $self->Sql(undef); + if ( $$self{PreSQLConditions} and @{$$self{PreSQLConditions}} ) { + foreach my $term ( @{$$self{PreSQLConditions}} ) { + if ( $$term{attr} eq 'DiskPercent' ) { + } + } + } + if ( $self->{HasDiskPercent} ) { my $disk_percent = getDiskPercent($$self{Storage} ? $$self{Storage}->Path() : ()); $sql =~ s/zmDiskPercent/$disk_percent/g; @@ -104,14 +111,27 @@ sub Execute { return; } my @results; - while ( my $event = $sth->fetchrow_hashref() ) { push @results, $event; } $sth->finish(); - Debug('Loaded ' . @results . " events for filter $_[0]{Name} using query ($sql)"); + Debug('Loaded ' . @results . ' events for filter '.$$self{Name}.' using query ('.$sql.')"'); + if ( $self->{PostSQLConditions} ) { + my @filtered_events; + foreach my $term ( @{$$self{PostSQLConditions}} ) { + if ( $$term{attr} eq 'ExistsInFileSystem' ) { + foreach my $row ( @results ) { + my $event = new ZoneMinder::Event($row); + if ( -e $event->Path() ) { + push @filtered_events, $row; + } + } + } + } # end foreach term + @results = @filtered_events; + } # end if has PostSQLConditions return @results; -} +} # end sub Execute sub Sql { my $self = shift; @@ -183,18 +203,22 @@ sub Sql { $self->{Sql} .= "weekday( E.EndTime )"; # + } elsif ( $term->{attr} eq 'ExistsInFileSystem' ) { + push @{$self->{PostSQLConditions}}, $term; } elsif ( $term->{attr} eq 'DiskSpace' ) { $self->{Sql} .= 'E.DiskSpace'; - $self->{HasDiskPercent} = !undef; } elsif ( $term->{attr} eq 'DiskPercent' ) { $self->{Sql} .= 'zmDiskPercent'; $self->{HasDiskPercent} = !undef; + $self->{HasPreCondition} = !undef; } elsif ( $term->{attr} eq 'DiskBlocks' ) { $self->{Sql} .= 'zmDiskBlocks'; $self->{HasDiskBlocks} = !undef; + $self->{HasPreCondition} = !undef; } elsif ( $term->{attr} eq 'SystemLoad' ) { $self->{Sql} .= 'zmSystemLoad'; $self->{HasSystemLoad} = !undef; + $self->{HasPreCondition} = !undef; } else { $self->{Sql} .= 'E.'.$term->{attr}; } diff --git a/scripts/zmcontrol.pl.in b/scripts/zmcontrol.pl.in index 74886b4d4..c9a548eef 100644 --- a/scripts/zmcontrol.pl.in +++ b/scripts/zmcontrol.pl.in @@ -83,7 +83,7 @@ if ( $options{command} ) { my $server_up; while ( $tries and ! ( $server_up = connect(CLIENT, $saddr) ) ) { Debug("Failed to connect to zmcontrol server at $sock_file"); - runCommand("zmdc.pl start zmcontrol.pl --id=$id"); + runCommand("zmdc.pl start zmcontrol.pl --id $id"); sleep 1; $tries -= 1; } @@ -142,9 +142,9 @@ if ( $options{command} ) { .strftime('%y/%m/%d %H:%M:%S', localtime()) ); - $0 = $0." --id=$id"; + $0 = $0.' --id '.$id; - my $control = "ZoneMinder::Control::$protocol"->new($id); + my $control = ('ZoneMinder::Control::'.$protocol)->new($id); my $control_key = $control->getKey(); $control->loadMonitor(); diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index 5b478316d..5ff316078 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -691,6 +691,7 @@ sub substituteTags { $text =~ s/%EC%/$Event->{Cause}/g; $text =~ s/%ED%/$Event->{Notes}/g; $text =~ s/%ET%/$Event->{StartTime}/g; + $text =~ s/%EVF%/$$Event{DefaultVideo}/g; # Event video filename $text =~ s/%EL%/$Event->{Length}/g; $text =~ s/%EF%/$Event->{Frames}/g; $text =~ s/%EFA%/$Event->{AlarmFrames}/g; @@ -1017,8 +1018,7 @@ sub executeCommand { my $event_path = $Event->Path(); - my $command = $filter->{AutoExecuteCmd}; - $command .= " $event_path"; + my $command = $filter->{AutoExecuteCmd}.' '.$event_path; $command = substituteTags($command, $filter, $Event); Info("Executing '$command'"); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9e3e004ee..d0248fb4d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ # CMakeLists.txt for the ZoneMinder binaries # Create files from the .in files -configure_file(zm_config.h.in "${CMAKE_CURRENT_BINARY_DIR}/zm_config.h" @ONLY) +configure_file(zm_config_data.h.in "${CMAKE_CURRENT_BINARY_DIR}/zm_config_data.h" @ONLY) # Group together all the source files that are used by all the binaries (zmc, zmu, zms etc) set(ZM_BIN_SRC_FILES diff --git a/src/zm.cpp b/src/zm.cpp index e25ce45ce..e541b322f 100644 --- a/src/zm.cpp +++ b/src/zm.cpp @@ -20,4 +20,4 @@ #include "zm.h" /* This is our argv[0], we need it for backtrace */ -const char* self = 0; +const char* self = nullptr; diff --git a/src/zm_buffer.h b/src/zm_buffer.h index 8f47c7cbc..a4b373b6b 100644 --- a/src/zm_buffer.h +++ b/src/zm_buffer.h @@ -34,7 +34,7 @@ protected: unsigned char *mTail; public: - Buffer() : mStorage( 0 ), mAllocation( 0 ), mSize( 0 ), mHead( 0 ), mTail( 0 ) { + Buffer() : mStorage( nullptr ), mAllocation( 0 ), mSize( 0 ), mHead( nullptr ), mTail( nullptr ) { } explicit Buffer( unsigned int pSize ) : mAllocation( pSize ), mSize( 0 ) { mHead = mStorage = new unsigned char[mAllocation]; diff --git a/src/zm_camera.cpp b/src/zm_camera.cpp index 17f370f49..133e50209 100644 --- a/src/zm_camera.cpp +++ b/src/zm_camera.cpp @@ -60,7 +60,7 @@ Camera::Camera( Debug(2, "New camera id: %d width: %d line size: %d height: %d colours: %d subpixelorder: %d capture: %d", monitor_id, width, linesize, height, colours, subpixelorder, capture); - monitor = NULL; + monitor = nullptr; } Camera::~Camera() { diff --git a/src/zm_comms.cpp b/src/zm_comms.cpp index 4744388af..b7231d4fd 100644 --- a/src/zm_comms.cpp +++ b/src/zm_comms.cpp @@ -142,13 +142,13 @@ SockAddr *SockAddr::newSockAddr( const struct sockaddr &addr, socklen_t len ) return( new SockAddrUnix( (const struct sockaddr_un *)&addr ) ); } Error( "Unable to create new SockAddr from addr family %d with size %d", addr.sa_family, len ); - return( 0 ); + return nullptr; } SockAddr *SockAddr::newSockAddr( const SockAddr *addr ) { if ( !addr ) - return( 0 ); + return nullptr; if ( addr->getDomain() == AF_INET ) { @@ -159,7 +159,7 @@ SockAddr *SockAddr::newSockAddr( const SockAddr *addr ) return( new SockAddrUnix( *(SockAddrUnix *)addr ) ); } Error( "Unable to create new SockAddr from addr family %d", addr->getDomain() ); - return( 0 ); + return nullptr; } SockAddrInet::SockAddrInet() : SockAddr( (struct sockaddr *)&mAddrIn ) @@ -170,14 +170,14 @@ bool SockAddrInet::resolve( const char *host, const char *serv, const char *prot { memset( &mAddrIn, 0, sizeof(mAddrIn) ); - struct hostent *hostent=0; + struct hostent *hostent=nullptr; if ( !(hostent = ::gethostbyname( host ) ) ) { Error( "gethostbyname( %s ), h_errno = %d", host, h_errno ); return( false ); } - struct servent *servent=0; + struct servent *servent=nullptr; if ( !(servent = ::getservbyname( serv, proto ) ) ) { Error( "getservbyname( %s ), errno = %d, error = %s", serv, errno, strerror(errno) ); @@ -195,7 +195,7 @@ bool SockAddrInet::resolve( const char *host, int port, const char *proto ) { memset( &mAddrIn, 0, sizeof(mAddrIn) ); - struct hostent *hostent=0; + struct hostent *hostent=nullptr; if ( !(hostent = ::gethostbyname( host ) ) ) { Error( "gethostbyname( %s ), h_errno = %d", host, h_errno ); @@ -212,7 +212,7 @@ bool SockAddrInet::resolve( const char *serv, const char *proto ) { memset( &mAddrIn, 0, sizeof(mAddrIn) ); - struct servent *servent=0; + struct servent *servent=nullptr; if ( !(servent = ::getservbyname( serv, proto ) ) ) { Error( "getservbyname( %s ), errno = %d, error = %s", serv, errno, strerror(errno) ); @@ -541,7 +541,7 @@ bool InetSocket::connect( const char *host, const char *serv ) * If socket(2) (or connect(2)) fails, we (close the socket * and) try the next address. */ - for (rp = result; rp != NULL; rp = rp->ai_next) { + for (rp = result; rp != nullptr; rp = rp->ai_next) { if (mSd != -1) { if (::connect(mSd, rp->ai_addr, rp->ai_addrlen) != -1) break; /* Success */ @@ -576,7 +576,7 @@ bool InetSocket::connect( const char *host, const char *serv ) freeaddrinfo(result); /* No longer needed */ - if (rp == NULL) { /* No address succeeded */ + if (rp == nullptr) { /* No address succeeded */ Error( "connect(), Could not connect" ); mAddressFamily = AF_UNSPEC; return( false ); @@ -607,9 +607,9 @@ bool InetSocket::bind( const char * host, const char * serv ) hints.ai_socktype = getType(); hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ hints.ai_protocol = 0; /* Any protocol */ - hints.ai_canonname = NULL; - hints.ai_addr = NULL; - hints.ai_next = NULL; + hints.ai_canonname = nullptr; + hints.ai_addr = nullptr; + hints.ai_next = nullptr; s = getaddrinfo(host, serv, &hints, &result); if (s != 0) { @@ -621,7 +621,7 @@ bool InetSocket::bind( const char * host, const char * serv ) * Try each address until we successfully bind(2). * If socket(2) (or bind(2)) fails, we (close the socket * and) try the next address. */ - for (rp = result; rp != NULL; rp = rp->ai_next) { + for (rp = result; rp != nullptr; rp = rp->ai_next) { memset(&buf, 0, sizeof(buf)); if (rp->ai_family == AF_INET) { inet_ntop(AF_INET, &((struct sockaddr_in *)rp->ai_addr)->sin_addr, buf, sizeof(buf)-1); @@ -645,7 +645,7 @@ bool InetSocket::bind( const char * host, const char * serv ) mSd = -1; } - if (rp == NULL) { /* No address succeeded */ + if (rp == nullptr) { /* No address succeeded */ Error( "bind(), Could not bind" ); return( false ); } @@ -657,7 +657,7 @@ bool InetSocket::bind( const char * host, const char * serv ) bool InetSocket::bind( const char * serv ) { - return bind( NULL, serv); + return bind( nullptr, serv); } bool InetSocket::bind( const char * host, int port ) @@ -673,7 +673,7 @@ bool InetSocket::bind( int port ) char serv[8]; snprintf(serv, sizeof(serv), "%d", port); - return bind( NULL, serv ); + return bind( nullptr, serv ); } bool TcpInetServer::listen() @@ -689,7 +689,7 @@ bool TcpInetServer::accept() bool TcpInetServer::accept( TcpInetSocket *&newSocket ) { int newSd = -1; - newSocket = 0; + newSocket = nullptr; if ( !Socket::accept( newSd ) ) return( false ); @@ -702,7 +702,7 @@ bool TcpInetServer::accept( TcpInetSocket *&newSocket ) bool TcpUnixServer::accept( TcpUnixSocket *&newSocket ) { int newSd = -1; - newSocket = 0; + newSocket = nullptr; if ( !Socket::accept( newSd ) ) return( false ); @@ -830,7 +830,7 @@ void Select::clearWriters() int Select::wait() { struct timeval tempTimeout = mTimeout; - struct timeval *selectTimeout = mHasTimeout?&tempTimeout:NULL; + struct timeval *selectTimeout = mHasTimeout?&tempTimeout:nullptr; fd_set rfds; fd_set wfds; @@ -845,7 +845,7 @@ int Select::wait() for ( CommsSet::iterator iter = mWriters.begin(); iter != mWriters.end(); ++iter ) FD_SET((*iter)->getWriteDesc(),&wfds); - int nFound = select( mMaxFd+1, &rfds, &wfds, NULL, selectTimeout ); + int nFound = select( mMaxFd+1, &rfds, &wfds, nullptr, selectTimeout ); if( nFound == 0 ) { Debug( 1, "Select timed out" ); diff --git a/src/zm_comms.h b/src/zm_comms.h index e93951a85..46face33c 100644 --- a/src/zm_comms.h +++ b/src/zm_comms.h @@ -416,8 +416,8 @@ public: } public: - virtual int sendto( const void *msg, int len, const SockAddr *addr=0 ) const { - ssize_t nBytes = ::sendto( mSd, msg, len, 0, addr?addr->getAddr():NULL, addr?addr->getAddrSize():0 ); + virtual int sendto( const void *msg, int len, const SockAddr *addr=nullptr ) const { + ssize_t nBytes = ::sendto( mSd, msg, len, 0, addr?addr->getAddr():nullptr, addr?addr->getAddrSize():0 ); if ( nBytes < 0 ) Debug( 1, "Sendto of %d bytes on sd %d failed: %s", len, mSd, strerror(errno) ); return( nBytes ); @@ -432,7 +432,7 @@ public: Debug( 1, "Recvfrom of %d bytes max on sd %d (with address) failed: %s", len, mSd, strerror(errno) ); } } else { - nBytes = ::recvfrom( mSd, msg, len, 0, NULL, 0 ); + nBytes = ::recvfrom( mSd, msg, len, 0, nullptr, 0 ); if ( nBytes < 0 ) Debug( 1, "Recvfrom of %d bytes max on sd %d (no address) failed: %s", len, mSd, strerror(errno) ); } diff --git a/src/zm_config.cpp b/src/zm_config.cpp index 273c1100e..8cf57b1bb 100644 --- a/src/zm_config.cpp +++ b/src/zm_config.cpp @@ -37,8 +37,7 @@ void zmLoadConfig() { // Process name, value pairs from the main config file first - char configFile[PATH_MAX] = ZM_CONFIG; - process_configfile(configFile); + process_configfile(ZM_CONFIG); // Search for user created config files. If one or more are found then // update the Config hash with those values @@ -109,14 +108,14 @@ void zmLoadConfig() { snprintf(staticConfig.video_file_format, sizeof(staticConfig.video_file_format), "%%s/%%s"); } -void process_configfile(char* configFile) { +void process_configfile(char const *configFile) { FILE *cfg; char line[512]; - if ( (cfg = fopen(configFile, "r")) == NULL ) { + if ( (cfg = fopen(configFile, "r")) == nullptr ) { Fatal("Can't open %s: %s", configFile, strerror(errno)); return; } - while ( fgets(line, sizeof(line), cfg) != NULL ) { + while ( fgets(line, sizeof(line), cfg) != nullptr ) { char *line_ptr = line; // Trim off any cr/lf line endings @@ -261,16 +260,16 @@ ConfigItem::~ConfigItem() { void ConfigItem::ConvertValue() const { if ( !strcmp( type, "boolean" ) ) { cfg_type = CFG_BOOLEAN; - cfg_value.boolean_value = (bool)strtol(value, 0, 0); + cfg_value.boolean_value = (bool)strtol(value, nullptr, 0); } else if ( !strcmp(type, "integer") ) { cfg_type = CFG_INTEGER; - cfg_value.integer_value = strtol(value, 0, 10); + cfg_value.integer_value = strtol(value, nullptr, 10); } else if ( !strcmp(type, "hexadecimal") ) { cfg_type = CFG_INTEGER; - cfg_value.integer_value = strtol(value, 0, 16); + cfg_value.integer_value = strtol(value, nullptr, 16); } else if ( !strcmp(type, "decimal") ) { cfg_type = CFG_DECIMAL; - cfg_value.decimal_value = strtod(value, 0); + cfg_value.decimal_value = strtod(value, nullptr); } else { cfg_type = CFG_STRING; cfg_value.string_value = value; @@ -335,10 +334,10 @@ Config::~Config() { if ( items ) { for ( int i = 0; i < n_items; i++ ) { delete items[i]; - items[i] = NULL; + items[i] = nullptr; } delete[] items; - items = NULL; + items = nullptr; } } diff --git a/src/zm_config.h.in b/src/zm_config.h similarity index 91% rename from src/zm_config.h.in rename to src/zm_config.h index 9831677f0..d348f38e9 100644 --- a/src/zm_config.h.in +++ b/src/zm_config.h @@ -1,21 +1,21 @@ // // ZoneMinder Configuration, $Date$, $Revision$ // Copyright (C) 2001-2008 Philip Coombes -// +// // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// +// #ifndef ZM_CONFIG_H #define ZM_CONFIG_H @@ -23,19 +23,13 @@ #if !defined(PATH_MAX) #define PATH_MAX 1024 #endif + #include "config.h" #include "zm_config_defines.h" +#include "zm_config_data.h" #include -#define ZM_CONFIG "@ZM_CONFIG@" // Path to config file -#define ZM_CONFIG_SUBDIR "@ZM_CONFIG_SUBDIR@" // Path to the ZoneMinder config subfolder -#define ZM_VERSION "@VERSION@" // ZoneMinder Version - -#define ZM_HAS_V4L1 @ZM_HAS_V4L1@ -#define ZM_HAS_V4L2 @ZM_HAS_V4L2@ -#define ZM_HAS_V4L @ZM_HAS_V4L@ - #ifdef HAVE_LIBAVFORMAT #define ZM_HAS_FFMPEG 1 #endif // HAVE_LIBAVFORMAT @@ -62,7 +56,7 @@ extern void zmLoadConfig(); -extern void process_configfile( char* configFile ); +extern void process_configfile(char const *configFile); struct StaticConfig { std::string DB_HOST; diff --git a/src/zm_config_data.h.in b/src/zm_config_data.h.in new file mode 100644 index 000000000..1209dcbf5 --- /dev/null +++ b/src/zm_config_data.h.in @@ -0,0 +1,31 @@ +// +// ZoneMinder Configuration, $Date$, $Revision$ +// Copyright (C) 2001-2008 Philip Coombes +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// + +#ifndef ZM_CONFIG_DATA_H +#define ZM_CONFIG_DATA_H + +#define ZM_CONFIG "@ZM_CONFIG@" // Path to config file +#define ZM_CONFIG_SUBDIR "@ZM_CONFIG_SUBDIR@" // Path to the ZoneMinder config subfolder +#define ZM_VERSION "@VERSION@" // ZoneMinder Version + +#define ZM_HAS_V4L1 @ZM_HAS_V4L1@ +#define ZM_HAS_V4L2 @ZM_HAS_V4L2@ +#define ZM_HAS_V4L @ZM_HAS_V4L@ + +#endif // ZM_CONFIG_DATA_H diff --git a/src/zm_curl_camera.cpp b/src/zm_curl_camera.cpp index 3d9a92058..cedce9850 100644 --- a/src/zm_curl_camera.cpp +++ b/src/zm_curl_camera.cpp @@ -106,26 +106,26 @@ void cURLCamera::Initialise() { Debug(2,"libcurl version: %s", (*curl_version_f)()); /* Create the shared data mutex */ - int nRet = pthread_mutex_init(&shareddata_mutex, NULL); + int nRet = pthread_mutex_init(&shareddata_mutex, nullptr); if(nRet != 0) { Error("Shared data mutex creation failed: %s",strerror(nRet)); return; } /* Create the data available condition variable */ - nRet = pthread_cond_init(&data_available_cond, NULL); + nRet = pthread_cond_init(&data_available_cond, nullptr); if(nRet != 0) { Error("Data available condition variable creation failed: %s",strerror(nRet)); return; } /* Create the request complete condition variable */ - nRet = pthread_cond_init(&request_complete_cond, NULL); + nRet = pthread_cond_init(&request_complete_cond, nullptr); if(nRet != 0) { Error("Request complete condition variable creation failed: %s",strerror(nRet)); return; } /* Create the thread */ - nRet = pthread_create(&thread, NULL, thread_func_dispatcher, this); + nRet = pthread_create(&thread, nullptr, thread_func_dispatcher, this); if(nRet != 0) { Error("Thread creation failed: %s",strerror(nRet)); return; @@ -137,7 +137,7 @@ void cURLCamera::Terminate() { bTerminate = true; /* Wait for thread termination */ - pthread_join(thread, NULL); + pthread_join(thread, nullptr); /* Destroy condition variables */ pthread_cond_destroy(&request_complete_cond); @@ -419,7 +419,7 @@ void* cURLCamera::thread_func() { double dSize; c = (*curl_easy_init_f)(); - if(c == NULL) { + if(c == nullptr) { dlclose(curl_lib); Error("Failed getting easy handle from libcurl"); tRet = -51; @@ -566,7 +566,7 @@ void* cURLCamera::thread_func() { /* Cleanup */ (*curl_easy_cleanup_f)(c); - c = NULL; + c = nullptr; return (void*)tRet; } diff --git a/src/zm_db.cpp b/src/zm_db.cpp index 35982ce50..37c3cd0f7 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -48,10 +48,10 @@ bool zmDbConnect() { staticConfig.DB_SSL_CLIENT_KEY.c_str(), staticConfig.DB_SSL_CLIENT_CERT.c_str(), staticConfig.DB_SSL_CA_CERT.c_str(), - NULL, NULL); + nullptr, nullptr); std::string::size_type colonIndex = staticConfig.DB_HOST.find(":"); if ( colonIndex == std::string::npos ) { - if ( !mysql_real_connect(&dbconn, staticConfig.DB_HOST.c_str(), staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), NULL, 0, NULL, 0) ) { + if ( !mysql_real_connect(&dbconn, staticConfig.DB_HOST.c_str(), staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), nullptr, 0, nullptr, 0) ) { Error( "Can't connect to server: %s", mysql_error(&dbconn)); return false; } @@ -59,12 +59,12 @@ bool zmDbConnect() { std::string dbHost = staticConfig.DB_HOST.substr( 0, colonIndex ); std::string dbPortOrSocket = staticConfig.DB_HOST.substr( colonIndex+1 ); if ( dbPortOrSocket[0] == '/' ) { - if ( !mysql_real_connect(&dbconn, NULL, staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), NULL, 0, dbPortOrSocket.c_str(), 0) ) { + if ( !mysql_real_connect(&dbconn, nullptr, staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), nullptr, 0, dbPortOrSocket.c_str(), 0) ) { Error("Can't connect to server: %s", mysql_error(&dbconn)); return false; } } else { - if ( !mysql_real_connect( &dbconn, dbHost.c_str(), staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), NULL, atoi(dbPortOrSocket.c_str()), NULL, 0 ) ) { + if ( !mysql_real_connect( &dbconn, dbHost.c_str(), staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), nullptr, atoi(dbPortOrSocket.c_str()), nullptr, 0 ) ) { Error( "Can't connect to server: %s", mysql_error( &dbconn ) ); return false; } @@ -94,20 +94,20 @@ void zmDbClose() { MYSQL_RES * zmDbFetch(const char * query) { if ( !zmDbConnected ) { Error("Not connected."); - return NULL; + return nullptr; } db_mutex.lock(); // Might have been disconnected while we waited for the lock if ( !zmDbConnected ) { db_mutex.unlock(); Error("Not connected."); - return NULL; + return nullptr; } if ( mysql_query(&dbconn, query) ) { db_mutex.unlock(); Error("Can't run query: %s", mysql_error(&dbconn)); - return NULL; + return nullptr; } Debug(4, "Success running query: %s", query); MYSQL_RES *result = mysql_store_result(&dbconn); @@ -124,7 +124,7 @@ zmDbRow *zmDbFetchOne(const char *query) { return row; } delete row; - return NULL; + return nullptr; } MYSQL_RES *zmDbRow::fetch(const char *query) { @@ -135,14 +135,14 @@ MYSQL_RES *zmDbRow::fetch(const char *query) { if ( n_rows != 1 ) { Error("Bogus number of lines return from query, %d returned for query %s.", n_rows, query); mysql_free_result(result_set); - result_set = NULL; + result_set = nullptr; return result_set; } row = mysql_fetch_row(result_set); if ( ! row ) { mysql_free_result(result_set); - result_set = NULL; + result_set = nullptr; Error("Error getting row from query %s. Error is %s", query, mysql_error(&dbconn)); } else { Debug(5, "Success"); @@ -153,6 +153,6 @@ MYSQL_RES *zmDbRow::fetch(const char *query) { zmDbRow::~zmDbRow() { if ( result_set ) { mysql_free_result(result_set); - result_set = NULL; + result_set = nullptr; } } diff --git a/src/zm_db.h b/src/zm_db.h index c707ad2b7..11fc9faaa 100644 --- a/src/zm_db.h +++ b/src/zm_db.h @@ -28,7 +28,7 @@ class zmDbRow { MYSQL_RES *result_set; MYSQL_ROW row; public: - zmDbRow() { result_set = NULL; row = NULL; }; + zmDbRow() { result_set = nullptr; row = nullptr; }; MYSQL_RES *fetch( const char *query ); zmDbRow( MYSQL_RES *, MYSQL_ROW *row ); ~zmDbRow(); diff --git a/src/zm_event.cpp b/src/zm_event.cpp index c73e643f8..f69723bb6 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -224,18 +224,18 @@ Event::Event( return; } video_file = path + "/" + video_name; - Debug(1,"Writing video file to %s", video_file.c_str()); + Debug(1, "Writing video file to %s", video_file.c_str()); Camera * camera = monitor->getCamera(); videoStore = new VideoStore( video_file.c_str(), container.c_str(), camera->get_VideoStream(), - ( monitor->RecordAudio() ? camera->get_AudioStream() : NULL ), + ( monitor->RecordAudio() ? camera->get_AudioStream() : nullptr ), monitor ); if ( !videoStore->open() ) { delete videoStore; - videoStore = NULL; + videoStore = nullptr; save_jpegs |= 1; // Turn on jpeg storage } } @@ -245,10 +245,10 @@ Event::~Event() { // We close the videowriter first, because if we finish the event, we might try to view the file, but we aren't done writing it yet. /* Close the video file */ - if ( videoStore ) { + if ( videoStore != nullptr ) { Debug(2, "Deleting video store"); delete videoStore; - videoStore = NULL; + videoStore = nullptr; } struct DeltaTimeval delta_time; @@ -280,8 +280,8 @@ Event::~Event() { // Should not be static because we might be multi-threaded char sql[ZM_SQL_LGE_BUFSIZ]; - snprintf(sql, sizeof(sql), - "UPDATE Events SET Name='%s %" PRIu64 "', EndTime = from_unixtime(%ld), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64, + snprintf(sql, sizeof(sql), + "UPDATE Events SET Name='%s%" PRIu64 "', EndTime = from_unixtime(%ld), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64 " AND Name='New Event'", monitor->EventPrefix(), id, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, @@ -294,6 +294,22 @@ Event::~Event() { sleep(1); db_mutex.lock(); } + if ( !mysql_affected_rows(&dbconn) ) { + // Name might have been changed during recording, so just do the update without changing the name. + snprintf(sql, sizeof(sql), + "UPDATE Events SET EndTime = from_unixtime(%ld), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64, + end_time.tv_sec, + delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, + frames, alarm_frames, + tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, + id); + while ( mysql_query(&dbconn, sql) && !zm_terminate ) { + db_mutex.unlock(); + Error("Can't update event: %s reason: %s", sql, mysql_error(&dbconn)); + sleep(1); + db_mutex.lock(); + } + } // end if no changed rows due to Name change during recording db_mutex.unlock(); } // Event::~Event() diff --git a/src/zm_event.h b/src/zm_event.h index 2e7b1aef3..ea6dd53aa 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -128,8 +128,8 @@ class Event { void updateNotes( const StringSetMap &stringSetMap ); void AddFrames( int n_frames, Image **images, struct timeval **timestamps ); - void AddFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL ); - void AddPacket( ZMPacket *p, int score=0, Image *alarm_frame=NULL ); + void AddFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=nullptr ); + void AddPacket( ZMPacket *p, int score=0, Image *alarm_frame=nullptr ); bool WritePacket( ZMPacket &p ); private: @@ -159,16 +159,16 @@ class Event { while ( pre_alarm_count > 0 ) { int i = pre_alarm_count - 1; delete pre_alarm_data[i].image; - pre_alarm_data[i].image = NULL; + pre_alarm_data[i].image = nullptr; if ( pre_alarm_data[i].alarm_frame ) { delete pre_alarm_data[i].alarm_frame; - pre_alarm_data[i].alarm_frame = NULL; + pre_alarm_data[i].alarm_frame = nullptr; } pre_alarm_count--; } pre_alarm_count = 0; } - static void AddPreAlarmFrame(Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL) { + static void AddPreAlarmFrame(Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=nullptr) { pre_alarm_data[pre_alarm_count].image = new Image(*image); pre_alarm_data[pre_alarm_count].timestamp = timestamp; pre_alarm_data[pre_alarm_count].score = score; diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 09335ddf1..b9abf5e76 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -148,7 +148,7 @@ bool EventStream::loadEventData(uint64_t event_id) { event_data->monitor_id = atoi(dbrow[0]); event_data->storage_id = dbrow[1] ? atoi(dbrow[1]) : 0; - event_data->frame_count = dbrow[2] == NULL ? 0 : atoi(dbrow[2]); + event_data->frame_count = dbrow[2] == nullptr ? 0 : atoi(dbrow[2]); event_data->start_time = atoi(dbrow[3]); event_data->duration = dbrow[4] ? atof(dbrow[4]) : 0.0; strncpy(event_data->video_file, dbrow[5], sizeof(event_data->video_file)-1); @@ -160,8 +160,8 @@ bool EventStream::loadEventData(uint64_t event_id) { } else { event_data->scheme = Storage::SHALLOW; } - event_data->SaveJPEGs = dbrow[7] == NULL ? 0 : atoi(dbrow[7]); - event_data->Orientation = (Monitor::Orientation)(dbrow[8] == NULL ? 0 : atoi(dbrow[8])); + event_data->SaveJPEGs = dbrow[7] == nullptr ? 0 : atoi(dbrow[7]); + event_data->Orientation = (Monitor::Orientation)(dbrow[8] == nullptr ? 0 : atoi(dbrow[8])); mysql_free_result(result); if ( !monitor ) { @@ -303,7 +303,7 @@ bool EventStream::loadEventData(uint64_t event_id) { if ( 0 > ffmpeg_input->Open(filepath.c_str()) ) { Warning("Unable to open ffmpeg_input %s", filepath.c_str()); delete ffmpeg_input; - ffmpeg_input = NULL; + ffmpeg_input = nullptr; } } @@ -646,7 +646,6 @@ bool EventStream::sendFrame(int delta_us) { static char filepath[PATH_MAX]; static struct stat filestat; - FILE *fdj = NULL; // This needs to be abstracted. If we are saving jpgs, then load the capture file. // If we are only saving analysis frames, then send that. @@ -662,7 +661,6 @@ bool EventStream::sendFrame(int delta_us) { filepath[0] = 0; } } - } else if ( !ffmpeg_input ) { Fatal("JPEGS not saved. zms is not capable of streaming jpegs from mp4 yet"); return false; @@ -684,34 +682,22 @@ bool EventStream::sendFrame(int delta_us) { } else #endif // HAVE_LIBAVCODEC { - static unsigned char temp_img_buffer[ZM_MAX_IMAGE_SIZE]; + static unsigned char temp_img_buffer[ZM_MAX_IMAGE_SIZE]; int img_buffer_size = 0; uint8_t *img_buffer = temp_img_buffer; - bool send_raw = ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE)) && filepath[0]; + bool send_raw = (type == STREAM_JPEG) && ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE)) && filepath[0]; - fprintf(stdout, "--ZoneMinderFrame\r\n"); - - if ( (type != STREAM_JPEG) || (!filepath[0]) ) - send_raw = false; + fprintf(stdout, "--" BOUNDARY "\r\n"); if ( send_raw ) { - fdj = fopen(filepath, "rb"); - if ( !fdj ) { - Error("Can't open %s: %s", filepath, strerror(errno)); - return true; // returning false will cause us to terminate. - } -#if HAVE_SENDFILE - if ( fstat(fileno(fdj),&filestat) < 0 ) { - Error("Failed getting information about file %s: %s", filepath, strerror(errno)); + if ( !send_file(filepath) ) { + Error("Can't send %s: %s", filepath, strerror(errno)); return false; } -#else - img_buffer_size = fread(img_buffer, 1, sizeof(temp_img_buffer), fdj); -#endif } else { - Image *image = NULL; + Image *image = nullptr; if ( filepath[0] ) { image = new Image(filepath); @@ -765,91 +751,33 @@ bool EventStream::sendFrame(int delta_us) { switch ( type ) { case STREAM_JPEG : - if ( send_image->EncodeJpeg(img_buffer, &img_buffer_size) ) { - Debug(1, "encoded JPEG"); - } else { - // Failed - } + send_image->EncodeJpeg(img_buffer, &img_buffer_size); + fputs("Content-Type: image/jpeg\r\n", stdout); break; case STREAM_ZIP : -#if HAVE_ZLIB_H unsigned long zip_buffer_size; send_image->Zip(img_buffer, &zip_buffer_size); img_buffer_size = zip_buffer_size; + fputs("Content-Type: image/x-rgbz\r\n", stdout); break; -#else - Error("zlib is required for zipped images. Falling back to raw image"); - type = STREAM_RAW; -#endif // HAVE_ZLIB_H case STREAM_RAW : img_buffer = (uint8_t*)(send_image->Buffer()); img_buffer_size = send_image->Size(); + fputs("Content-Type: image/x-rgb\r\n", stdout); break; default: Fatal("Unexpected frame type %d", type); break; } + send_buffer(img_buffer, img_buffer_size); delete image; - image = NULL; - } // end if send_raw or not - - switch ( type ) { - case STREAM_JPEG : - fputs("Content-Type: image/jpeg\r\n", stdout); - break; - case STREAM_RAW : - fputs("Content-Type: image/x-rgb\r\n", stdout); - break; - case STREAM_ZIP : - fputs("Content-Type: image/x-rgbz\r\n", stdout); - break; - default : - Fatal("Unexpected frame type %d", type); - break; - } - - if ( send_raw ) { -#if HAVE_SENDFILE - if ( 0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size) ) { - fclose(fdj); /* Close the file handle */ - Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno)); - return false; - } - if ( zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size) != (int)filestat.st_size ) { - /* sendfile() failed, use standard way instead */ - img_buffer_size = fread(img_buffer, 1, sizeof(temp_img_buffer), fdj); - if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) { - fclose(fdj); /* Close the file handle */ - Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno)); - return false; - } - } -#else - if ( - (0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size) ) - || - ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) - ) { - fclose(fdj); /* Close the file handle */ - Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno)); - return false; - } -#endif - fclose(fdj); /* Close the file handle */ - } else { - Debug(3, "Content length: %d", img_buffer_size); - if ( - (0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size) ) - || - ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) ) { - Error("Unable to send stream frame: %s", strerror(errno)); - return false; - } + image = nullptr; } // end if send_raw or not - fputs("\r\n\r\n", stdout); - fflush(stdout); } // end if stream MPEG or other + + fputs("\r\n\r\n", stdout); + fflush(stdout); last_frame_sent = TV_2_FLOAT(now); return true; } // bool EventStream::sendFrame( int delta_us ) @@ -860,7 +788,7 @@ void EventStream::runStream() { checkInitialised(); if ( type == STREAM_JPEG ) - fputs("Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame\r\n\r\n", stdout); + fputs("Content-Type: multipart/x-mixed-replace;boundary=" BOUNDARY "\r\n\r\n", stdout); if ( !event_data ) { sendTextFrame("No event data found"); @@ -869,7 +797,7 @@ void EventStream::runStream() { Debug(3, "frame rate is: (%f)", (double)event_data->frame_count/event_data->duration); updateFrameRate((double)event_data->frame_count/event_data->duration); - gettimeofday(&start, NULL); + gettimeofday(&start, nullptr); uint64_t start_usec = start.tv_sec * 1000000 + start.tv_usec; uint64_t last_frame_offset = 0; @@ -877,7 +805,7 @@ void EventStream::runStream() { double time_to_event = 0; while ( !zm_terminate ) { - gettimeofday(&now, NULL); + gettimeofday(&now, nullptr); int delta_us = 0; send_frame = false; @@ -981,7 +909,7 @@ void EventStream::runStream() { // +/- 1? What if we are skipping frames? curr_frame_id += (replay_rate>0) ? frame_mod : -1*frame_mod; // sending the frame may have taken some time, so reload now - gettimeofday(&now, NULL); + gettimeofday(&now, nullptr); uint64_t now_usec = (now.tv_sec * 1000000 + now.tv_usec); // we incremented by replay_rate, so might have jumped past frame_count @@ -1078,7 +1006,65 @@ void EventStream::runStream() { #endif // HAVE_LIBAVCODEC closeComms(); -} // void EventStream::runStream() +} // end void EventStream::runStream() + +bool EventStream::send_file(const char * filepath) { + static unsigned char temp_img_buffer[ZM_MAX_IMAGE_SIZE]; + + int img_buffer_size = 0; + uint8_t *img_buffer = temp_img_buffer; + + FILE *fdj = NULL; + fdj = fopen(filepath, "rb"); + if ( !fdj ) { + Error("Can't open %s: %s", filepath, strerror(errno)); + return false; + } + bool size_sent = false; + +#if HAVE_SENDFILE + static struct stat filestat; + if ( fstat(fileno(fdj), &filestat) < 0 ) { + Error("Failed getting information about file %s: %s", filepath, strerror(errno)); + return false; + } + if ( 0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size) ) { + fclose(fdj); /* Close the file handle */ + Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno)); + return false; + } + size_sent = true; + + if ( zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size) != (int)filestat.st_size ) { + fclose(fdj); /* Close the file handle */ + return true; + } +#endif + img_buffer_size = fread(img_buffer, 1, sizeof(temp_img_buffer), fdj); + if ( !size_sent ) { + if ( 0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size) ) { + fclose(fdj); /* Close the file handle */ + Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno)); + return false; + } + } + if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) { + Error("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno)); + return false; + } + + fclose(fdj); /* Close the file handle */ + return true; +} // end bool EventStream::send_file(const char * filepath) + +bool EventStream::send_buffer(uint8_t* buffer, int size) { + fprintf(stdout, "Content-Length: %d\r\n\r\n", size); + if ( fwrite(buffer, size, 1, stdout) != 1 ) { + Error("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno)); + return false; + } + return true; +} // end bool EventStream::send_buffer(uint8_t* buffer, int size) void EventStream::setStreamStart( uint64_t init_event_id, diff --git a/src/zm_eventstream.h b/src/zm_eventstream.h index c075892bc..023dd7a99 100644 --- a/src/zm_eventstream.h +++ b/src/zm_eventstream.h @@ -97,33 +97,33 @@ class EventStream : public StreamBase { curr_frame_id(0), curr_stream_time(0.0), send_frame(false), - event_data(0), - storage(NULL), - ffmpeg_input(NULL), + event_data(nullptr), + storage(nullptr), + ffmpeg_input(nullptr), // Used when loading frames from an mp4 - input_codec_context(0), - input_codec(0) + input_codec_context(nullptr), + input_codec(nullptr) {} ~EventStream() { if ( event_data ) { if ( event_data->frames ) { delete[] event_data->frames; - event_data->frames = NULL; + event_data->frames = nullptr; } delete event_data; - event_data = NULL; + event_data = nullptr; } if ( monitor ) { delete monitor; - monitor = NULL; + monitor = nullptr; } if ( storage ) { delete storage; - storage = NULL; + storage = nullptr; } if ( ffmpeg_input ) { delete ffmpeg_input; - ffmpeg_input = NULL; + ffmpeg_input = nullptr; } } void setStreamStart( uint64_t init_event_id, unsigned int init_frame_id ); @@ -134,6 +134,8 @@ class EventStream : public StreamBase { void runStream(); Image *getImage(); private: + bool send_file( const char *file_path ); + bool send_buffer( uint8_t * buffer, int size ); Storage *storage; FFmpeg_Input *ffmpeg_input; AVCodecContext *input_codec_context; diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index a913e6275..161827f64 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -81,7 +81,7 @@ void FFMPEGInit() { av_log_set_callback(log_libav_callback); Info("Enabling ffmpeg logs, as LOG_DEBUG+LOG_FFMPEG are enabled in options"); } else { - Info("Not enabling ffmpeg logs, as LOG_FFMPEG and/or LOG_DEBUG is disabled in options, or this monitor is not part of your debug targets"); + Debug(1,"Not enabling ffmpeg logs, as LOG_FFMPEG and/or LOG_DEBUG is disabled in options, or this monitor is not part of your debug targets"); av_log_set_level(AV_LOG_QUIET); } #if !LIBAVFORMAT_VERSION_CHECK(58, 9, 0, 64, 0) @@ -151,7 +151,7 @@ static int parse_key_value_pair(AVDictionary **pm, const char **buf, int flags) { char *key = av_get_token(buf, key_val_sep); - char *val = NULL; + char *val = nullptr; int ret; if (key && *key && strspn(*buf, key_val_sep)) { @@ -225,7 +225,7 @@ int hacked_up_context2_for_older_ffmpeg(AVFormatContext **avctx, AVOutputFormat AVFormatContext *s = avformat_alloc_context(); int ret = 0; - *avctx = NULL; + *avctx = nullptr; if (!s) { av_log(s, AV_LOG_ERROR, "Out of memory\n"); ret = AVERROR(ENOMEM); @@ -234,13 +234,13 @@ int hacked_up_context2_for_older_ffmpeg(AVFormatContext **avctx, AVOutputFormat if (!oformat) { if (format) { - oformat = av_guess_format(format, NULL, NULL); + oformat = av_guess_format(format, nullptr, nullptr); if (!oformat) { av_log(s, AV_LOG_ERROR, "Requested output format '%s' is not a suitable output format\n", format); ret = AVERROR(EINVAL); } } else { - oformat = av_guess_format(NULL, filename, NULL); + oformat = av_guess_format(nullptr, filename, nullptr); if (!oformat) { ret = AVERROR(EINVAL); av_log(s, AV_LOG_ERROR, "Unable to find a suitable output format for '%s'\n", filename); @@ -267,7 +267,7 @@ int hacked_up_context2_for_older_ffmpeg(AVFormatContext **avctx, AVOutputFormat ret = AVERROR(ENOMEM); return ret; } - s->priv_data = NULL; + s->priv_data = nullptr; } #endif @@ -335,7 +335,7 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output) Debug(1, "Dumping stream index i(%d) index(%d)", i, index ); int flags = (is_output ? ic->oformat->flags : ic->iformat->flags); AVStream *st = ic->streams[i]; - AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0); + AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", nullptr, 0); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) AVCodecParameters *codec = st->codecpar; #else @@ -533,7 +533,7 @@ int zm_receive_packet(AVCodecContext *context, AVPacket &packet) { return 1; #else int got_packet = 0; - int ret = avcodec_encode_audio2(context, &packet, NULL, &got_packet); + int ret = avcodec_encode_audio2(context, &packet, nullptr, &got_packet); if ( ret < 0 ) { Error("Error encoding (%d) (%s)", ret, av_err2str(ret)); } @@ -730,7 +730,7 @@ int zm_resample_audio( Error("Flushing resampler not supported by AVRESAMPLE"); return 0; } - int ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, + int ret = avresample_convert(resample_ctx, nullptr, 0, 0, in_frame->data, 0, in_frame->nb_samples); if ( ret < 0 ) { Error("Could not resample frame (error '%s')", diff --git a/src/zm_ffmpeg.h b/src/zm_ffmpeg.h index ccae7793f..2a25acba7 100644 --- a/src/zm_ffmpeg.h +++ b/src/zm_ffmpeg.h @@ -40,6 +40,7 @@ extern "C" { #include #include #include "libavutil/audio_fifo.h" +#include "libavutil/imgutils.h" /* LIBAVUTIL_VERSION_CHECK checks for the right version of libav and FFmpeg * The original source is vlc (in modules/codec/avcodec/avcommon_compat.h) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 2be6c2480..f7bf1c2cc 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -132,29 +132,29 @@ FfmpegCamera::FfmpegCamera( FFMPEGInit(); } - mFormatContext = NULL; + mFormatContext = nullptr; mVideoStreamId = -1; mAudioStreamId = -1; - mVideoCodecContext = NULL; - mAudioCodecContext = NULL; - mVideoCodec = NULL; - mAudioCodec = NULL; - mRawFrame = NULL; - mFrame = NULL; + mVideoCodecContext = nullptr; + mAudioCodecContext = nullptr; + mVideoCodec = nullptr; + mAudioCodec = nullptr; + mRawFrame = nullptr; + mFrame = nullptr; frameCount = 0; mCanCapture = false; error_count = 0; use_hwaccel = true; #if HAVE_LIBAVUTIL_HWCONTEXT_H - hwFrame = NULL; - hw_device_ctx = NULL; + hwFrame = nullptr; + hw_device_ctx = nullptr; #if LIBAVCODEC_VERSION_CHECK(57, 89, 0, 89, 0) hw_pix_fmt = AV_PIX_FMT_NONE; #endif #endif #if HAVE_LIBSWSCALE - mConvertContext = NULL; + mConvertContext = nullptr; #endif /* Has to be located inside the constructor so other components such as zma * will receive correct colours and subpixel order */ @@ -171,7 +171,7 @@ FfmpegCamera::FfmpegCamera( Panic("Unexpected colours: %d", colours); } - frame_buffer = NULL; + frame_buffer = nullptr; // sws_scale needs 32bit aligned width and an extra 16 bytes padding, so recalculate imagesize, which was width*height*bytes_per_pixel #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) alignment = 32; @@ -255,10 +255,10 @@ int FfmpegCamera::OpenFfmpeg() { // Open the input, not necessarily a file #if !LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 4, 0) - if ( av_open_input_file(&mFormatContext, mPath.c_str(), NULL, 0, NULL) != 0 ) + if ( av_open_input_file(&mFormatContext, mPath.c_str(), nullptr, 0, nullptr) != 0 ) #else // Handle options - AVDictionary *opts = NULL; + AVDictionary *opts = nullptr; ret = av_dict_parse_string(&opts, Options().c_str(), "=", ",", 0); if ( ret < 0 ) { Warning("Could not parse ffmpeg input options '%s'", Options().c_str()); @@ -296,8 +296,7 @@ int FfmpegCamera::OpenFfmpeg() { mFormatContext->interrupt_callback.callback = FfmpegInterruptCallback; mFormatContext->interrupt_callback.opaque = this; - ret = avformat_open_input(&mFormatContext, mPath.c_str(), NULL, &opts); - Debug(1, "Have %d from open_input", ret); + ret = avformat_open_input(&mFormatContext, mPath.c_str(), nullptr, &opts); if ( ret != 0 ) #endif { @@ -308,15 +307,15 @@ int FfmpegCamera::OpenFfmpeg() { #else if ( mFormatContext ) { avformat_close_input(&mFormatContext); - mFormatContext = NULL; + mFormatContext = nullptr; } #endif av_dict_free(&opts); return -1; } - AVDictionaryEntry *e = NULL; - while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { + AVDictionaryEntry *e = nullptr; + while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != nullptr ) { Warning("Option %s not recognized by ffmpeg", e->key); } av_dict_free(&opts); @@ -325,7 +324,7 @@ int FfmpegCamera::OpenFfmpeg() { #if !LIBAVFORMAT_VERSION_CHECK(53, 6, 0, 6, 0) ret = av_find_stream_info(mFormatContext); #else - ret = avformat_find_stream_info(mFormatContext, 0); + ret = avformat_find_stream_info(mFormatContext, nullptr); #endif if ( ret < 0 ) { Error("Unable to find stream info from %s due to: %s", @@ -355,6 +354,7 @@ int FfmpegCamera::OpenFfmpeg() { } } } // end foreach stream + if ( mVideoStreamId == -1 ) { Error("Unable to locate video stream in %s", mPath.c_str()); return -1; @@ -378,7 +378,7 @@ int FfmpegCamera::OpenFfmpeg() { #endif if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H264 ) { - if ( (mVideoCodec = avcodec_find_decoder_by_name("h264_mmal")) == NULL ) { + if ( (mVideoCodec = avcodec_find_decoder_by_name("h264_mmal")) == nullptr ) { Debug(1, "Failed to find decoder (h264_mmal)"); } else { Debug(1, "Success finding decoder (h264_mmal)"); @@ -399,8 +399,8 @@ int FfmpegCamera::OpenFfmpeg() { if ( use_hwaccel && (hwaccel_name != "") ) { #if HAVE_LIBAVUTIL_HWCONTEXT_H // 3.2 doesn't seem to have all the bits in place, so let's require 3.3 and up -#if LIBAVCODEC_VERSION_CHECK(57, 89, 0, 89, 0) -// Print out available types + #if LIBAVCODEC_VERSION_CHECK(57, 89, 0, 89, 0) + // Print out available types enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE; while ( (type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE ) Debug(1, "%s", av_hwdevice_get_type_name(type)); @@ -413,7 +413,7 @@ int FfmpegCamera::OpenFfmpeg() { Debug(1, "Found hwdevice %s", av_hwdevice_get_type_name(type)); } -#if LIBAVUTIL_VERSION_CHECK(56, 22, 0, 14, 0) + #if LIBAVUTIL_VERSION_CHECK(56, 22, 0, 14, 0) // Get hw_pix_fmt for ( int i = 0;; i++ ) { const AVCodecHWConfig *config = avcodec_get_hw_config(mVideoCodec, i); @@ -436,15 +436,15 @@ int FfmpegCamera::OpenFfmpeg() { ); } } // end foreach hwconfig -#else + #else hw_pix_fmt = find_fmt_by_hw_type(type); -#endif + #endif if ( hw_pix_fmt != AV_PIX_FMT_NONE ) { Debug(1, "Selected hw_pix_fmt %d %s", hw_pix_fmt, av_get_pix_fmt_name(hw_pix_fmt)); ret = av_hwdevice_ctx_create(&hw_device_ctx, type, - (hwaccel_device != "" ? hwaccel_device.c_str(): NULL), NULL, 0); + (hwaccel_device != "" ? hwaccel_device.c_str(): nullptr), nullptr, 0); if ( ret < 0 ) { Error("Failed to create hwaccel device. %s",av_make_error_string(ret).c_str()); hw_pix_fmt = AV_PIX_FMT_NONE; @@ -457,9 +457,9 @@ int FfmpegCamera::OpenFfmpeg() { } else { Debug(1, "Failed to find suitable hw_pix_fmt."); } -#else + #else Debug(1, "AVCodec not new enough for hwaccel"); -#endif + #endif #else Warning("HWAccel support not compiled in."); #endif @@ -470,8 +470,8 @@ int FfmpegCamera::OpenFfmpeg() { #else ret = avcodec_open2(mVideoCodecContext, mVideoCodec, &opts); #endif - e = NULL; - while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { + e = nullptr; + while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != nullptr ) { Warning("Option %s not recognized by ffmpeg", e->key); } if ( ret < 0 ) { @@ -490,7 +490,7 @@ int FfmpegCamera::OpenFfmpeg() { #else mFormatContext->streams[mAudioStreamId]->codec->codec_id #endif - )) == NULL ) { + )) == nullptr ) { Debug(1, "Can't find codec for audio stream from %s", mPath.c_str()); } else { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) @@ -509,7 +509,7 @@ int FfmpegCamera::OpenFfmpeg() { #if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0) if ( avcodec_open(mAudioCodecContext, mAudioCodec) < 0 ) #else - if ( avcodec_open2(mAudioCodecContext, mAudioCodec, 0) < 0 ) + if ( avcodec_open2(mAudioCodecContext, mAudioCodec, nullptr) < 0 ) #endif { Error("Unable to open codec for audio stream from %s", mPath.c_str()); @@ -537,16 +537,16 @@ int FfmpegCamera::Close() { if ( mFrame ) { av_frame_free(&mFrame); - mFrame = NULL; + mFrame = nullptr; } if ( mRawFrame ) { av_frame_free(&mRawFrame); - mRawFrame = NULL; + mRawFrame = nullptr; } #if HAVE_LIBAVUTIL_HWCONTEXT_H if ( hwFrame ) { av_frame_free(&hwFrame); - hwFrame = NULL; + hwFrame = nullptr; } #endif @@ -555,14 +555,14 @@ int FfmpegCamera::Close() { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // avcodec_free_context(&mVideoCodecContext); #endif - mVideoCodecContext = NULL; // Freed by av_close_input_file + mVideoCodecContext = nullptr; // Freed by av_close_input_file } if ( mAudioCodecContext ) { avcodec_close(mAudioCodecContext); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) avcodec_free_context(&mAudioCodecContext); #endif - mAudioCodecContext = NULL; // Freed by av_close_input_file + mAudioCodecContext = nullptr; // Freed by av_close_input_file } #if HAVE_LIBAVUTIL_HWCONTEXT_H @@ -577,7 +577,7 @@ int FfmpegCamera::Close() { #else avformat_close_input(&mFormatContext); #endif - mFormatContext = NULL; + mFormatContext = nullptr; } return 0; @@ -593,7 +593,7 @@ int FfmpegCamera::transfer_to_image( /* Request a writeable buffer of the target image */ image_buffer = image.WriteBuffer(width, height, colours, subpixelorder); - if ( image_buffer == NULL ) { + if ( image_buffer == nullptr ) { Error("Failed requesting writeable buffer for the captured image."); return -1; } @@ -630,9 +630,9 @@ int FfmpegCamera::transfer_to_image( input_frame->height, (AVPixelFormat)input_frame->format, width, height, - imagePixFormat, SWS_BICUBIC, NULL, - NULL, NULL); - if ( mConvertContext == NULL ) { + imagePixFormat, SWS_BICUBIC, nullptr, + nullptr, nullptr); + if ( mConvertContext == nullptr ) { Error("Unable to create conversion context for %s from %s to %s", mPath.c_str(), av_get_pix_fmt_name((AVPixelFormat)input_frame->format), diff --git a/src/zm_ffmpeg_camera.h b/src/zm_ffmpeg_camera.h index b25e39da8..35df3a65e 100644 --- a/src/zm_ffmpeg_camera.h +++ b/src/zm_ffmpeg_camera.h @@ -62,7 +62,7 @@ class FfmpegCamera : public Camera { AVFrame *hwFrame; // Will also be used to indicate if hwaccel is in use bool use_hwaccel; //will default to on if hwaccel specified, will get turned off if there is a failure #if HAVE_LIBAVUTIL_HWCONTEXT_H - AVBufferRef *hw_device_ctx = NULL; + AVBufferRef *hw_device_ctx = nullptr; #endif // Used to store the incoming packet, it will get copied when queued. diff --git a/src/zm_ffmpeg_input.cpp b/src/zm_ffmpeg_input.cpp index 980c2e50b..bcf612a7b 100644 --- a/src/zm_ffmpeg_input.cpp +++ b/src/zm_ffmpeg_input.cpp @@ -4,12 +4,12 @@ #include "zm_ffmpeg.h" FFmpeg_Input::FFmpeg_Input() { - input_format_context = NULL; + input_format_context = nullptr; video_stream_id = -1; audio_stream_id = -1; FFMPEGInit(); - streams = NULL; - frame = NULL; + streams = nullptr; + frame = nullptr; last_seek_request = -1; } @@ -20,14 +20,14 @@ FFmpeg_Input::~FFmpeg_Input() { if ( streams ) { for ( unsigned int i = 0; i < input_format_context->nb_streams; i += 1 ) { avcodec_close(streams[i].context); - streams[i].context = NULL; + streams[i].context = nullptr; } delete[] streams; - streams = NULL; + streams = nullptr; } if ( frame ) { av_frame_free(&frame); - frame = NULL; + frame = nullptr; } if ( input_format_context ) { #if !LIBAVFORMAT_VERSION_CHECK(53, 17, 0, 25, 0) @@ -35,7 +35,7 @@ FFmpeg_Input::~FFmpeg_Input() { #else avformat_close_input(&input_format_context); #endif - input_format_context = NULL; + input_format_context = nullptr; } } // end ~FFmpeg_Input() @@ -58,16 +58,16 @@ int FFmpeg_Input::Open(const char *filepath) { int error; /** Open the input file to read from it. */ - error = avformat_open_input(&input_format_context, filepath, NULL, NULL); + error = avformat_open_input(&input_format_context, filepath, nullptr, nullptr); if ( error < 0 ) { Error("Could not open input file '%s' (error '%s')", filepath, av_make_error_string(error).c_str()); - input_format_context = NULL; + input_format_context = nullptr; return error; } /** Get information on the input file (number of streams etc.). */ - if ( (error = avformat_find_stream_info(input_format_context, NULL)) < 0 ) { + if ( (error = avformat_find_stream_info(input_format_context, nullptr)) < 0 ) { Error( "Could not open find stream info (error '%s')", av_make_error_string(error).c_str() @@ -101,7 +101,7 @@ int FFmpeg_Input::Open(const char *filepath) { streams[i].frame_count = 0; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - streams[i].context = avcodec_alloc_context3(NULL); + streams[i].context = avcodec_alloc_context3(nullptr); avcodec_parameters_to_context(streams[i].context, input_format_context->streams[i]->codecpar); #else streams[i].context = input_format_context->streams[i]->codec; @@ -115,7 +115,7 @@ int FFmpeg_Input::Open(const char *filepath) { Debug(1, "Using codec (%s) for stream %d", streams[i].codec->name, i); } - error = avcodec_open2(streams[i].context, streams[i].codec, NULL); + error = avcodec_open2(streams[i].context, streams[i].codec, nullptr); if ( error < 0 ) { Error("Could not open input codec (error '%s')", av_make_error_string(error).c_str()); @@ -123,7 +123,7 @@ int FFmpeg_Input::Open(const char *filepath) { avcodec_free_context(&streams[i].context); #endif avformat_close_input(&input_format_context); - input_format_context = NULL; + input_format_context = nullptr; return error; } } // end foreach stream @@ -174,11 +174,11 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id) { (ret == -110) ) { Info("av_read_frame returned %s.", av_make_error_string(ret).c_str()); - return NULL; + return nullptr; } Error("Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, av_make_error_string(ret).c_str()); - return NULL; + return nullptr; } dumpPacket(input_format_context->streams[packet.stream_index], &packet, "Received packet"); @@ -216,7 +216,7 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id) { } // end while !frameComplete return frame; -} // end AVFrame *FFmpeg_Input::get_frame +} // end AVFrame *FFmpeg_Input::get_frame AVFrame *FFmpeg_Input::get_frame(int stream_id, double at) { Debug(1, "Getting frame from stream %d at %f", stream_id, at); @@ -233,7 +233,7 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id, double at) { ret = av_seek_frame(input_format_context, stream_id, seek_target, AVSEEK_FLAG_FRAME); if ( ret < 0 ) { Error("Unable to seek in stream"); - return NULL; + return nullptr; } // Have to grab a frame to update our current frame to know where we are get_frame(stream_id); @@ -241,7 +241,7 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id, double at) { if ( !frame ) { Warning("Unable to get frame."); - return NULL; + return nullptr; } if ( @@ -257,7 +257,7 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id, double at) { AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME ) < 0 ) ) { Error("Unable to seek in stream"); - return NULL; + return nullptr; } // Have to grab a frame to update our current frame to know where we are get_frame(stream_id); diff --git a/src/zm_fifo.cpp b/src/zm_fifo.cpp index 0c0f836bd..53025f597 100644 --- a/src/zm_fifo.cpp +++ b/src/zm_fifo.cpp @@ -30,13 +30,13 @@ #include "zm_fifo.h" #define RAW_BUFFER 512 static bool zm_fifodbg_inited = false; -FILE *zm_fifodbg_log_fd = 0; +FILE *zm_fifodbg_log_fd = nullptr; char zm_fifodbg_log[PATH_MAX] = ""; static bool zmFifoDbgOpen() { if ( zm_fifodbg_log_fd ) fclose(zm_fifodbg_log_fd); - zm_fifodbg_log_fd = NULL; + zm_fifodbg_log_fd = nullptr; signal(SIGPIPE, SIG_IGN); FifoStream::fifo_create_if_missing(zm_fifodbg_log); int fd = open(zm_fifodbg_log, O_WRONLY|O_NONBLOCK|O_TRUNC); @@ -48,7 +48,7 @@ static bool zmFifoDbgOpen() { return false; } zm_fifodbg_log_fd = fdopen(fd, "wb"); - if ( zm_fifodbg_log_fd == NULL ) { + if ( zm_fifodbg_log_fd == nullptr ) { close(fd); return false; } @@ -95,7 +95,7 @@ void zmFifoDbgOutput( int res = fwrite(dbg_string, dbg_ptr-dbg_string, 1, zm_fifodbg_log_fd); if ( res != 1 ) { fclose(zm_fifodbg_log_fd); - zm_fifodbg_log_fd = NULL; + zm_fifodbg_log_fd = nullptr; } else { fflush(zm_fifodbg_log_fd); } @@ -249,7 +249,7 @@ void FifoStream::runStream() { } while ( !zm_terminate ) { - gettimeofday(&now, NULL); + gettimeofday(&now, nullptr); checkCommandQueue(); if ( stream_type == MJPEG ) { if ( !sendMJEGFrames() ) diff --git a/src/zm_file_camera.cpp b/src/zm_file_camera.cpp index 98583dbcb..8ba71bcd1 100644 --- a/src/zm_file_camera.cpp +++ b/src/zm_file_camera.cpp @@ -88,7 +88,7 @@ int FileCamera::PreCapture() { // This waits until 1 second has passed since it was modified. Effectively limiting fps to 60. // Which is kinda bogus. If we were writing to this jpg constantly faster than we are monitoring it here // we would never break out of this loop - while ( (time(0) - statbuf.st_mtime) < 1 ) { + while ( (time(nullptr) - statbuf.st_mtime) < 1 ) { usleep(100000); } return 0; diff --git a/src/zm_image.cpp b/src/zm_image.cpp index 920715cdf..4e4ef62f1 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -48,12 +48,12 @@ static short *g_v_table; static short *g_u_table; static short *b_u_table; -struct SwsContext *sws_convert_context = NULL; +struct SwsContext *sws_convert_context = nullptr; -jpeg_compress_struct *Image::writejpg_ccinfo[101] = { 0 }; -jpeg_compress_struct *Image::encodejpg_ccinfo[101] = { 0 }; -jpeg_decompress_struct *Image::readjpg_dcinfo = 0; -jpeg_decompress_struct *Image::decodejpg_dcinfo = 0; +jpeg_compress_struct *Image::writejpg_ccinfo[101] = { }; +jpeg_compress_struct *Image::encodejpg_ccinfo[101] = { }; +jpeg_decompress_struct *Image::readjpg_dcinfo = nullptr; +jpeg_decompress_struct *Image::decodejpg_dcinfo = nullptr; struct zm_error_mgr Image::jpg_err; /* Pointer to blend function. */ @@ -152,7 +152,7 @@ Image::Image(int p_width, int p_height, int p_colours, int p_subpixelorder, uint padding = p_padding; subpixelorder = p_subpixelorder; size = linesize*height + padding; - buffer = 0; + buffer = nullptr; holdbuffer = 0; if ( p_buffer ) { allocation = size; @@ -177,7 +177,7 @@ Image::Image(int p_width, int p_linesize, int p_height, int p_colours, int p_sub padding = p_padding; subpixelorder = p_subpixelorder; size = linesize*height + padding; - buffer = 0; + buffer = nullptr; holdbuffer = 0; if ( p_buffer ) { allocation = size; @@ -210,7 +210,7 @@ Image::Image(const AVFrame *frame) { size = avpicture_get_size(AV_PIX_FMT_RGBA, width, height); #endif - buffer = 0; + buffer = nullptr; holdbuffer = 0; AllocImgBuffer(size); this->Assign(frame); @@ -237,9 +237,9 @@ void Image::Assign(const AVFrame *frame) { height, (AVPixelFormat)frame->format, width, height, - format, SWS_BICUBIC, NULL, - NULL, NULL); - if ( sws_convert_context == NULL ) + format, SWS_BICUBIC, nullptr, + nullptr, nullptr); + if ( sws_convert_context == nullptr ) Fatal("Unable to create conversion context"); if ( sws_scale(sws_convert_context, frame->data, frame->linesize, 0, frame->height, @@ -262,7 +262,7 @@ Image::Image(const Image &p_image) { colours = p_image.colours; subpixelorder = p_image.subpixelorder; size = p_image.size; // allocation is set in AllocImgBuffer - buffer = 0; + buffer = nullptr; holdbuffer = 0; AllocImgBuffer(size); (*fptr_imgbufcpy)(buffer, p_image.buffer, size); @@ -281,24 +281,24 @@ void Image::Deinitialise() { if ( readjpg_dcinfo ) { jpeg_destroy_decompress(readjpg_dcinfo); delete readjpg_dcinfo; - readjpg_dcinfo = NULL; + readjpg_dcinfo = nullptr; } if ( decodejpg_dcinfo ) { jpeg_destroy_decompress(decodejpg_dcinfo); delete decodejpg_dcinfo; - decodejpg_dcinfo = NULL; + decodejpg_dcinfo = nullptr; } for ( unsigned int quality=0; quality <= 100; quality += 1 ) { if ( writejpg_ccinfo[quality] ) { jpeg_destroy_compress(writejpg_ccinfo[quality]); delete writejpg_ccinfo[quality]; - writejpg_ccinfo[quality] = NULL; + writejpg_ccinfo[quality] = nullptr; } } // end foreach quality if ( sws_convert_context ) { sws_freeContext(sws_convert_context); - sws_convert_context = NULL; + sws_convert_context = nullptr; } } // end void Image::Deinitialise() @@ -509,25 +509,25 @@ uint8_t* Image::WriteBuffer( && p_colours != ZM_COLOUR_RGB32 ) { Error("WriteBuffer called with unexpected colours: %d", p_colours); - return NULL; + return nullptr; } if ( ! ( p_height > 0 && p_width > 0 ) ) { Error("WriteBuffer called with invalid width or height: %d %d", p_width, p_height); - return NULL; + return nullptr; } if ( p_width != width || p_height != height || p_colours != colours || p_subpixelorder != subpixelorder ) { unsigned int newsize = (p_width * p_height) * p_colours; - if ( buffer == NULL ) { + if ( buffer == nullptr ) { AllocImgBuffer(newsize); } else { if ( allocation < newsize ) { if ( holdbuffer ) { Error("Held buffer is undersized for requested buffer"); - return NULL; + return nullptr; } else { /* Replace buffer with a bigger one */ //DumpImgBuffer(); // Done in AllocImgBuffer too @@ -560,7 +560,7 @@ void Image::AssignDirect( const size_t buffer_size, const int p_buffertype) { - if ( new_buffer == NULL ) { + if ( new_buffer == nullptr ) { Error("Attempt to directly assign buffer from a NULL pointer"); return; } @@ -631,7 +631,7 @@ void Image::Assign( const size_t buffer_size) { unsigned int new_size = (p_width * p_height) * p_colours; - if ( new_buffer == NULL ) { + if ( new_buffer == nullptr ) { Error("Attempt to assign buffer from a NULL pointer"); return; } @@ -681,7 +681,7 @@ void Image::Assign( void Image::Assign(const Image &image) { unsigned int new_size = image.height * image.linesize; - if ( image.buffer == NULL ) { + if ( image.buffer == nullptr ) { Error("Attempt to assign image with an empty buffer"); return; } @@ -820,7 +820,7 @@ Image *Image::HighlightEdges( bool Image::ReadRaw(const char *filename) { FILE *infile; - if ( (infile = fopen(filename, "rb")) == NULL ) { + if ( (infile = fopen(filename, "rb")) == nullptr ) { Error("Can't open %s: %s", filename, strerror(errno)); return false; } @@ -851,7 +851,7 @@ bool Image::ReadRaw(const char *filename) { bool Image::WriteRaw(const char *filename) const { FILE *outfile; - if ( (outfile = fopen(filename, "wb")) == NULL ) { + if ( (outfile = fopen(filename, "wb")) == nullptr ) { Error("Can't open %s: %s", filename, strerror(errno)); return false; } @@ -880,7 +880,7 @@ bool Image::ReadJpeg(const char *filename, unsigned int p_colours, unsigned int } FILE *infile; - if ( (infile = fopen(filename, "rb")) == NULL ) { + if ( (infile = fopen(filename, "rb")) == nullptr ) { Error("Can't open %s: %s", filename, strerror(errno)); return false; } @@ -904,7 +904,7 @@ bool Image::ReadJpeg(const char *filename, unsigned int p_colours, unsigned int /* Check if the image has at least one huffman table defined. If not, use the standard ones */ /* This is required for the MJPEG capture palette of USB devices */ - if ( cinfo->dc_huff_tbl_ptrs[0] == NULL ) { + if ( cinfo->dc_huff_tbl_ptrs[0] == nullptr ) { zm_use_std_huff_tables(cinfo); } @@ -969,7 +969,7 @@ cinfo->out_color_space = JCS_RGB; break; } // end switch p_colours - if ( WriteBuffer(new_width, new_height, new_colours, new_subpixelorder) == NULL ) { + if ( WriteBuffer(new_width, new_height, new_colours, new_subpixelorder) == nullptr ) { Error("Failed requesting writeable buffer for reading JPEG image."); jpeg_abort_decompress(cinfo); fclose(infile); @@ -1020,7 +1020,7 @@ bool Image::WriteJpeg(const char *filename, int quality_override, struct timeval int quality = quality_override ? quality_override : config.jpeg_file_quality; struct jpeg_compress_struct *cinfo = writejpg_ccinfo[quality]; - FILE *outfile = NULL; + FILE *outfile = nullptr; static int raw_fd = 0; raw_fd = 0; @@ -1037,7 +1037,7 @@ bool Image::WriteJpeg(const char *filename, int quality_override, struct timeval jpg_err.pub.emit_message = zm_jpeg_emit_silence; if ( setjmp(jpg_err.setjmp_buffer) ) { jpeg_abort_compress(cinfo); - Debug(1, "Aborted a write mid-stream and %s and %d", (outfile == NULL) ? "closing file" : "file not opened", raw_fd); + Debug(1, "Aborted a write mid-stream and %s and %d", (outfile == nullptr) ? "closing file" : "file not opened", raw_fd); if ( raw_fd ) close(raw_fd); if ( outfile ) @@ -1047,7 +1047,7 @@ bool Image::WriteJpeg(const char *filename, int quality_override, struct timeval } if ( !on_blocking_abort ) { - if ( (outfile = fopen(filename, "wb")) == NULL ) { + if ( (outfile = fopen(filename, "wb")) == nullptr ) { Error("Can't open %s for writing: %s", filename, strerror(errno)); return false; } @@ -1056,7 +1056,7 @@ bool Image::WriteJpeg(const char *filename, int quality_override, struct timeval if ( raw_fd < 0 ) return false; outfile = fdopen(raw_fd, "wb"); - if ( outfile == NULL ) { + if ( outfile == nullptr ) { close(raw_fd); return false; } @@ -1199,7 +1199,7 @@ bool Image::DecodeJpeg( /* Check if the image has at least one huffman table defined. If not, use the standard ones */ /* This is required for the MJPEG capture palette of USB devices */ - if ( cinfo->dc_huff_tbl_ptrs[0] == NULL ) { + if ( cinfo->dc_huff_tbl_ptrs[0] == nullptr ) { zm_use_std_huff_tables(cinfo); } @@ -1265,7 +1265,7 @@ cinfo->out_color_space = JCS_RGB; break; } // end switch - if ( WriteBuffer(new_width, new_height, new_colours, new_subpixelorder) == NULL ) { + if ( WriteBuffer(new_width, new_height, new_colours, new_subpixelorder) == nullptr ) { Error("Failed requesting writeable buffer for reading JPEG image."); jpeg_abort_decompress(cinfo); return false; @@ -1808,7 +1808,7 @@ void Image::Delta(const Image &image, Image* targetimage) const { uint8_t *pdiff = targetimage->WriteBuffer(width, height, ZM_COLOUR_GRAY8, ZM_SUBPIX_ORDER_NONE); - if ( pdiff == NULL ) { + if ( pdiff == nullptr ) { Panic("Failed requesting writeable buffer for storing the delta image"); } diff --git a/src/zm_image.h b/src/zm_image.h index 0bc431448..7095a1b5a 100644 --- a/src/zm_image.h +++ b/src/zm_image.h @@ -57,7 +57,7 @@ extern imgbufcpy_fptr_t fptr_imgbufcpy; /* Should be called from Image class functions */ inline static uint8_t* AllocBuffer(size_t p_bufsize) { uint8_t* buffer = (uint8_t*)zm_mallocaligned(64, p_bufsize); - if ( buffer == NULL ) + if ( buffer == nullptr ) Fatal("Memory allocation failed: %s", strerror(errno)); return buffer; @@ -123,7 +123,7 @@ protected: inline void DumpImgBuffer() { DumpBuffer(buffer, buffertype); - buffer = NULL; + buffer = nullptr; allocation = 0; } diff --git a/src/zm_jpeg.cpp b/src/zm_jpeg.cpp index 8e8899227..9865d4db4 100644 --- a/src/zm_jpeg.cpp +++ b/src/zm_jpeg.cpp @@ -192,7 +192,7 @@ void zm_jpeg_mem_dest (j_compress_ptr cinfo, JOCTET *outbuffer, int *outbuffer_s * manager serially with the same JPEG object, because their private object * sizes may be different. Caveat programmer. */ - if ( cinfo->dest == NULL ) + if ( cinfo->dest == nullptr ) { /* first time for this JPEG object? */ cinfo->dest = (struct jpeg_destination_mgr *)(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(mem_destination_mgr)); @@ -369,7 +369,7 @@ void zm_jpeg_mem_src( j_decompress_ptr cinfo, const JOCTET *inbuffer, int inbuff * This makes it unsafe to use this manager and a different source * manager serially with the same JPEG object. Caveat programmer. */ - if ( cinfo->src == NULL ) + if ( cinfo->src == nullptr ) { /* first time for this JPEG object? */ cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(mem_source_mgr)); @@ -396,7 +396,7 @@ void zm_jpeg_mem_src( j_decompress_ptr cinfo, const JOCTET *inbuffer, int inbuff src->inbuffer = (JOCTET *)inbuffer; src->inbuffer_size = inbuffer_size; src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ - src->pub.next_input_byte = NULL; /* until buffer loaded */ + src->pub.next_input_byte = nullptr; /* until buffer loaded */ } void zm_use_std_huff_tables( j_decompress_ptr cinfo ) { diff --git a/src/zm_libvlc_camera.cpp b/src/zm_libvlc_camera.cpp index b41b36e7c..0edd206cd 100644 --- a/src/zm_libvlc_camera.cpp +++ b/src/zm_libvlc_camera.cpp @@ -72,7 +72,7 @@ void* LibvlcLockBuffer(void* opaque, void** planes) { data->prevBuffer = buffer; *planes = data->buffer; - return NULL; + return nullptr; } void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) { @@ -129,12 +129,12 @@ LibvlcCamera::LibvlcCamera( mMethod(p_method), mOptions(p_options) { - mLibvlcInstance = NULL; - mLibvlcMedia = NULL; - mLibvlcMediaPlayer = NULL; - mLibvlcData.buffer = NULL; - mLibvlcData.prevBuffer = NULL; - mOptArgV = NULL; + mLibvlcInstance = nullptr; + mLibvlcMedia = nullptr; + mLibvlcMediaPlayer = nullptr; + mLibvlcData.buffer = nullptr; + mLibvlcData.prevBuffer = nullptr; + mOptArgV = nullptr; /* Has to be located inside the constructor so other components such as zma will receive correct colours and subpixel order */ if ( colours == ZM_COLOUR_RGB32 ) { @@ -163,19 +163,19 @@ LibvlcCamera::~LibvlcCamera() { if ( capture ) { Terminate(); } - if ( mLibvlcMediaPlayer != NULL ) { + if ( mLibvlcMediaPlayer != nullptr ) { (*libvlc_media_player_release_f)(mLibvlcMediaPlayer); - mLibvlcMediaPlayer = NULL; + mLibvlcMediaPlayer = nullptr; } - if ( mLibvlcMedia != NULL ) { + if ( mLibvlcMedia != nullptr ) { (*libvlc_media_release_f)(mLibvlcMedia); - mLibvlcMedia = NULL; + mLibvlcMedia = nullptr; } - if ( mLibvlcInstance != NULL ) { + if ( mLibvlcInstance != nullptr ) { (*libvlc_release_f)(mLibvlcInstance); - mLibvlcInstance = NULL; + mLibvlcInstance = nullptr; } - if ( mOptArgV != NULL ) { + if ( mOptArgV != nullptr ) { delete[] mOptArgV; } } @@ -188,12 +188,12 @@ void LibvlcCamera::Terminate() { (*libvlc_media_player_stop_f)(mLibvlcMediaPlayer); if ( mLibvlcData.buffer ) { zm_freealigned(mLibvlcData.buffer); - mLibvlcData.buffer = NULL; + mLibvlcData.buffer = nullptr; } if ( mLibvlcData.prevBuffer ) { zm_freealigned(mLibvlcData.prevBuffer); - mLibvlcData.prevBuffer = NULL; + mLibvlcData.prevBuffer = nullptr; } } @@ -223,27 +223,27 @@ int LibvlcCamera::PrimeCapture() { } mLibvlcInstance = (*libvlc_new_f)(opVect.size(), (const char* const*)mOptArgV); - if ( mLibvlcInstance == NULL ) { + if ( mLibvlcInstance == nullptr ) { Error("Unable to create libvlc instance due to: %s", (*libvlc_errmsg_f)()); return -1; } - (*libvlc_log_set_f)(mLibvlcInstance, LibvlcCamera::log_callback, NULL); + (*libvlc_log_set_f)(mLibvlcInstance, LibvlcCamera::log_callback, nullptr); mLibvlcMedia = (*libvlc_media_new_location_f)(mLibvlcInstance, mPath.c_str()); - if ( mLibvlcMedia == NULL ) { + if ( mLibvlcMedia == nullptr ) { Error("Unable to open input %s due to: %s", mPath.c_str(), (*libvlc_errmsg_f)()); return -1; } mLibvlcMediaPlayer = (*libvlc_media_player_new_from_media_f)(mLibvlcMedia); - if ( mLibvlcMediaPlayer == NULL ) { + if ( mLibvlcMediaPlayer == nullptr ) { Error("Unable to create player for %s due to: %s", mPath.c_str(), (*libvlc_errmsg_f)()); return -1; } (*libvlc_video_set_format_f)(mLibvlcMediaPlayer, mTargetChroma.c_str(), width, height, width * mBpp); - (*libvlc_video_set_callbacks_f)(mLibvlcMediaPlayer, &LibvlcLockBuffer, &LibvlcUnlockBuffer, NULL, &mLibvlcData); + (*libvlc_video_set_callbacks_f)(mLibvlcMediaPlayer, &LibvlcLockBuffer, &LibvlcUnlockBuffer, nullptr, &mLibvlcData); mLibvlcData.bufferSize = width * height * mBpp; // Libvlc wants 32 byte alignment for images (should in theory do this for all image lines) diff --git a/src/zm_libvnc_camera.cpp b/src/zm_libvnc_camera.cpp index c88a1c3b2..315cc19dd 100644 --- a/src/zm_libvnc_camera.cpp +++ b/src/zm_libvnc_camera.cpp @@ -19,12 +19,12 @@ static int (*WaitForMessage_f)(rfbClient*, unsigned int) = nullptr; static rfbBool (*HandleRFBServerMessage_f)(rfbClient*) = nullptr; void bind_libvnc_symbols() { - if(libvnc_lib != nullptr) // Safe-check + if ( libvnc_lib != nullptr ) // Safe-check return; libvnc_lib = dlopen("libvncclient.so", RTLD_LAZY | RTLD_GLOBAL); - if(!libvnc_lib){ - Error("Error loading libvlc: %s", dlerror()); + if ( !libvnc_lib ) { + Error("Error loading libvncclient: %s", dlerror()); return; } @@ -49,8 +49,8 @@ static char* GetPasswordCallback(rfbClient* cl){ static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){ rfbCredential *c = (rfbCredential *)malloc(sizeof(rfbCredential)); if ( credentialType != rfbCredentialTypeUser ) { - free(c); - return NULL; + free(c); + return nullptr; } c->userCredential.password = strdup((const char *)(*rfbClientGetClientData_f)(cl, &TAG_1)); @@ -116,7 +116,7 @@ VncCamera::VncCamera( VncCamera::~VncCamera() { - if( capture ) + if ( capture ) Terminate(); } @@ -136,12 +136,11 @@ void VncCamera::Initialise() { mRfb->programName = "Zoneminder VNC Monitor"; mRfb->serverHost = strdup(mHost.c_str()); mRfb->serverPort = atoi(mPort.c_str()); - (*rfbInitClient_f)(mRfb, 0, nullptr); scale.init(); } void VncCamera::Terminate() { - if(mRfb->frameBuffer) + if ( mRfb->frameBuffer ) free(mRfb->frameBuffer); (*rfbClientCleanup_f)(mRfb); return; @@ -149,20 +148,38 @@ void VncCamera::Terminate() { int VncCamera::PrimeCapture() { Debug(1, "Priming capture from %s", mHost.c_str()); + if ( ! (*rfbInitClient_f)(mRfb, 0, nullptr) ) { + return -1; + } return 0; } int VncCamera::PreCapture() { Debug(2, "PreCapture"); - (*WaitForMessage_f)(mRfb, 500); + int rc = (*WaitForMessage_f)(mRfb, 500); + if ( rc < 0 ) { + return -1; + } else if ( !rc ) { + return rc; + } rfbBool res = (*HandleRFBServerMessage_f)(mRfb); - return res == TRUE ? 1 : -1 ; + return res == TRUE ? 1 : -1; } int VncCamera::Capture(Image &image) { Debug(2, "Capturing"); uint8_t *directbuffer = image.WriteBuffer(width, height, colours, subpixelorder); - scale.Convert(mVncData.buffer, mRfb->si.framebufferHeight * mRfb->si.framebufferWidth * 4, directbuffer, width * height * mBpp, AV_PIX_FMT_RGBA, mImgPixFmt, mRfb->si.framebufferWidth, mRfb->si.framebufferHeight, width, height); + scale.Convert( + mVncData.buffer, + mRfb->si.framebufferHeight * mRfb->si.framebufferWidth * 4, + directbuffer, + width * height * mBpp, + AV_PIX_FMT_RGBA, + mImgPixFmt, + mRfb->si.framebufferWidth, + mRfb->si.framebufferHeight, + width, + height); return 1; } diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index 89e791e32..808b3e149 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -301,10 +301,10 @@ LocalCamera::V4L1Data LocalCamera::v4l1_data; #endif // ZM_HAS_V4L1 #if HAVE_LIBSWSCALE -AVFrame **LocalCamera::capturePictures = 0; +AVFrame **LocalCamera::capturePictures = nullptr; #endif // HAVE_LIBSWSCALE -LocalCamera *LocalCamera::last_camera = NULL; +LocalCamera *LocalCamera::last_camera = nullptr; LocalCamera::LocalCamera( int p_id, @@ -668,14 +668,14 @@ LocalCamera::LocalCamera( Fatal("Image size mismatch. Required: %d Available: %u", pSize, imagesize); } - imgConversionContext = sws_getContext(width, height, capturePixFormat, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL); + imgConversionContext = sws_getContext(width, height, capturePixFormat, width, height, imagePixFormat, SWS_BICUBIC, nullptr, nullptr, nullptr); if ( !imgConversionContext ) { Fatal("Unable to initialise image scaling context"); } } else { - tmpPicture = NULL; - imgConversionContext = NULL; + tmpPicture = nullptr; + imgConversionContext = nullptr; } // end if capture and conversion_tye == swscale #endif mVideoStreamId = 0; @@ -691,7 +691,7 @@ LocalCamera::~LocalCamera() { /* Clean up swscale stuff */ if ( capture && conversion_type == 1 ) { sws_freeContext(imgConversionContext); - imgConversionContext = NULL; + imgConversionContext = nullptr; av_frame_free(&tmpPicture); } @@ -903,7 +903,7 @@ void LocalCamera::Initialise() { Fatal("Unable to query video buffer: %s", strerror(errno)); v4l2_data.buffers[i].length = vid_buf.length; - v4l2_data.buffers[i].start = mmap(NULL, vid_buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, vid_fd, vid_buf.m.offset); + v4l2_data.buffers[i].start = mmap(nullptr, vid_buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, vid_fd, vid_buf.m.offset); if ( v4l2_data.buffers[i].start == MAP_FAILED ) Fatal("Can't map video buffer %u (%u bytes) to memory: %s(%d)", @@ -1998,7 +1998,7 @@ int LocalCamera::PrimeCapture() { if ( vidioctl(vid_fd, VIDIOC_QBUF, &vid_buf) < 0 ) Fatal("Failed to queue buffer %d: %s", frame, strerror(errno)); } - v4l2_data.bufptr = NULL; + v4l2_data.bufptr = nullptr; Debug(3, "Starting video stream"); //enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; @@ -2029,10 +2029,9 @@ int LocalCamera::PreCapture() { return 0; } -int LocalCamera::Capture( ZMPacket &zm_packet ) { - +int LocalCamera::Capture(ZMPacket &zm_packet) { // We assume that the avpacket is allocated, and just needs to be filled - static uint8_t* buffer = NULL; + static uint8_t* buffer = nullptr; int buffer_bytesused = 0; int capture_frame = -1; @@ -2134,7 +2133,7 @@ int LocalCamera::Capture( ZMPacket &zm_packet ) { /* Request a writeable buffer of the target image */ uint8_t *directbuffer = zm_packet.image->WriteBuffer(width, height, colours, subpixelorder); - if ( directbuffer == NULL ) { + if ( directbuffer == nullptr ) { Error("Failed requesting writeable buffer for the captured image."); return -1; } diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index 43327ba36..619cba115 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -39,7 +39,7 @@ #include bool Logger::smInitialised = false; -Logger *Logger::smInstance = NULL; +Logger *Logger::smInstance = nullptr; Logger::StringMap Logger::smCodes; Logger::IntMap Logger::smSyslogPriorities; @@ -75,7 +75,7 @@ Logger::Logger() : mDbConnected(false), mLogPath(staticConfig.PATH_LOGS.c_str()), //mLogFile( mLogPath+"/"+mId+".log" ), - mLogFileFP(NULL), + mLogFileFP(nullptr), mHasTerminal(false), mFlush(false) { @@ -412,7 +412,7 @@ void Logger::logFile(const std::string &logFile) { void Logger::openFile() { if ( mLogFile.size() ) { - if ( (mLogFileFP = fopen(mLogFile.c_str(), "a")) == (FILE *)NULL ) { + if ( (mLogFileFP = fopen(mLogFile.c_str(), "a")) == nullptr ) { mFileLevel = NOLOG; Error("fopen() for %s, error = %s", mLogFile.c_str(), strerror(errno)); } @@ -425,10 +425,10 @@ void Logger::closeFile() { if ( mLogFileFP ) { fflush(mLogFileFP); if ( fclose(mLogFileFP) < 0 ) { - mLogFileFP = (FILE *)NULL; + mLogFileFP = nullptr; Error("fclose(), error = %s", strerror(errno)); } - mLogFileFP = (FILE *)NULL; + mLogFileFP = nullptr; } } @@ -463,7 +463,7 @@ void Logger::logPrint(bool hex, const char * const filepath, const int line, con if ( level < PANIC || level > DEBUG9 ) Panic("Invalid logger level %d", level); - gettimeofday(&timeVal, NULL); + gettimeofday(&timeVal, nullptr); #if 0 if ( logRuntime ) { @@ -610,7 +610,7 @@ void Logger::logPrint(bool hex, const char * const filepath, const int line, con void logInit(const char *name, const Logger::Options &options) { if ( Logger::smInstance ) { delete Logger::smInstance; - Logger::smInstance = NULL; + Logger::smInstance = nullptr; } Logger::smInstance = new Logger(); @@ -620,6 +620,6 @@ void logInit(const char *name, const Logger::Options &options) { void logTerm() { if ( Logger::smInstance ) { delete Logger::smInstance; - Logger::smInstance = NULL; + Logger::smInstance = nullptr; } } diff --git a/src/zm_mem_utils.h b/src/zm_mem_utils.h index 8d841d670..6ef1bdac5 100644 --- a/src/zm_mem_utils.h +++ b/src/zm_mem_utils.h @@ -27,15 +27,15 @@ inline void* zm_mallocaligned(unsigned int reqalignment, size_t reqsize) { uint8_t* retptr; #if HAVE_POSIX_MEMALIGN if ( posix_memalign((void**)&retptr,reqalignment,reqsize) != 0 ) - return NULL; + return nullptr; return retptr; #else uint8_t* alloc; retptr = (uint8_t*)malloc(reqsize+reqalignment+sizeof(void*)); - if ( retptr == NULL ) - return NULL; + if ( retptr == nullptr ) + return nullptr; alloc = retptr + sizeof(void*); @@ -60,7 +60,7 @@ inline void zm_freealigned(void* ptr) { inline char *mempbrk(const char *s, const char *accept, size_t limit) { if ( limit == 0 || !s || !accept || !*accept ) - return 0; + return nullptr; unsigned int i,j; size_t acc_len = strlen(accept); @@ -72,12 +72,12 @@ inline char *mempbrk(const char *s, const char *accept, size_t limit) { } } } - return 0; + return nullptr; } inline char *memstr(const char *s, const char *n, size_t limit) { if ( limit == 0 || !s || !n ) - return 0; + return nullptr; if ( !*n ) return (char *)s; @@ -97,7 +97,7 @@ inline char *memstr(const char *s, const char *n, size_t limit) { break; } } - return 0; + return nullptr; } inline size_t memspn(const char *s, const char *accept, size_t limit) { diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index accdddef3..ffa0ec23c 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -98,9 +98,9 @@ std::string CameraType_Strings[] = { Monitor::MonitorLink::MonitorLink(unsigned int p_id, const char *p_name) : id(p_id), - shared_data(NULL), - trigger_data(NULL), - video_store_data(NULL) + shared_data(nullptr), + trigger_data(nullptr), + video_store_data(nullptr) { strncpy(name, p_name, sizeof(name)-1); @@ -111,7 +111,7 @@ Monitor::MonitorLink::MonitorLink(unsigned int p_id, const char *p_name) : shm_id = 0; #endif // ZM_MEM_MAPPED mem_size = 0; - mem_ptr = 0; + mem_ptr = nullptr; last_event_id = 0; last_state = IDLE; @@ -125,8 +125,8 @@ Monitor::MonitorLink::~MonitorLink() { } bool Monitor::MonitorLink::connect() { - if ( !last_connect_time || (time(0) - last_connect_time) > 60 ) { - last_connect_time = time(0); + if ( !last_connect_time || (time(nullptr) - last_connect_time) > 60 ) { + last_connect_time = time(nullptr); mem_size = sizeof(SharedData) + sizeof(TriggerData); @@ -162,7 +162,7 @@ bool Monitor::MonitorLink::connect() { return false; } - mem_ptr = (unsigned char *)mmap(NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0); + mem_ptr = (unsigned char *)mmap(nullptr, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0); if ( mem_ptr == MAP_FAILED ) { Error("Can't map file %s (%d bytes) to memory: %s", mem_file, mem_size, strerror(errno)); disconnect(); @@ -237,7 +237,7 @@ bool Monitor::MonitorLink::disconnect() { #endif // ZM_MEM_MAPPED mem_size = 0; - mem_ptr = 0; + mem_ptr = nullptr; } return( true ); } @@ -334,13 +334,13 @@ Monitor::Monitor() last_motion_score(0), camera(0), n_zones(0), - zones(NULL), + zones(nullptr), timestamps(0), images(0), - privacy_bitmask( NULL ), - event_delete_thread(NULL), + privacy_bitmask( nullptr ), + event_delete_thread(nullptr), n_linked_monitors(0), - linked_monitors(NULL) + linked_monitors(nullptr) { if ( strcmp(config.event_close_mode, "time") == 0 ) @@ -356,7 +356,7 @@ Monitor::Monitor() adaptive_skip = true; - videoStore = NULL; + videoStore = nullptr; } // Monitor::Monitor /* @@ -581,7 +581,7 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) { (image_buffer_count*sizeof(struct timeval)), image_buffer_count, image_size, (image_buffer_count*image_size), mem_size); - mem_ptr = NULL; + mem_ptr = nullptr; Zone **zones = 0; int n_zones = Zone::Load(this, zones); @@ -851,12 +851,12 @@ bool Monitor::connect() { Debug(3, "MMap file size is %ld", map_stat.st_size); #ifdef MAP_LOCKED - mem_ptr = (unsigned char *)mmap(NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, map_fd, 0); + mem_ptr = (unsigned char *)mmap(nullptr, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, map_fd, 0); if ( mem_ptr == MAP_FAILED ) { if ( errno == EAGAIN ) { Debug(1, "Unable to map file %s (%d bytes) to locked memory, trying unlocked", mem_file, mem_size); #endif - mem_ptr = (unsigned char *)mmap(NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0); + mem_ptr = (unsigned char *)mmap(nullptr, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0); Debug(1, "Mapped file %s (%d bytes) to unlocked memory", mem_file, mem_size); #ifdef MAP_LOCKED } else { @@ -866,7 +866,7 @@ bool Monitor::connect() { #endif if ( mem_ptr == MAP_FAILED ) Fatal("Can't map file %s (%d bytes) to memory: %s(%d)", mem_file, mem_size, strerror(errno), errno); - if ( mem_ptr == NULL ) { + if ( mem_ptr == nullptr ) { Error("mmap gave a NULL address:"); } else { Debug(3, "mmapped to %p", mem_ptr); @@ -976,13 +976,13 @@ Monitor::~Monitor() { if ( event_delete_thread ) { event_delete_thread->join(); delete event_delete_thread; - event_delete_thread = NULL; + event_delete_thread = nullptr; } } if ( event_delete_thread ) { event_delete_thread->join(); delete event_delete_thread; - event_delete_thread = NULL; + event_delete_thread = nullptr; } if ( deinterlacing_value == 4 ) { @@ -1083,9 +1083,9 @@ void Monitor::AddZones(int p_n_zones, Zone *p_zones[]) { void Monitor::AddPrivacyBitmask(Zone *p_zones[]) { if ( privacy_bitmask ) { delete[] privacy_bitmask; - privacy_bitmask = NULL; + privacy_bitmask = nullptr; } - Image *privacy_image = NULL; + Image *privacy_image = nullptr; for ( int i=0; i < n_zones; i++ ) { if ( p_zones[i]->IsPrivacy() ) { @@ -1444,7 +1444,7 @@ void Monitor::DumpZoneImage(const char *zone_string) { } } - Image *zone_image = NULL; + Image *zone_image = nullptr; if ( ( (!staticConfig.SERVER_ID) || ( staticConfig.SERVER_ID == server_id ) ) && mem_ptr ) { Debug(3, "Trying to load from local zmc"); int index = shared_data->last_write_index; @@ -1463,7 +1463,7 @@ void Monitor::DumpZoneImage(const char *zone_string) { stream->setStreamStart(event_id, (unsigned int)1); zone_image = stream->getImage(); delete stream; - stream = NULL; + stream = nullptr; } else { Error("Unable to load an event for monitor %d", id); return; @@ -1594,7 +1594,8 @@ bool Monitor::CheckSignal(const Image *image) { void Monitor::CheckAction() { struct timeval now; - gettimeofday(&now, NULL); + gettimeofday(&now, nullptr); + if ( shared_data->action ) { // Can there be more than 1 bit set in the action? Shouldn't these be elseifs? if ( shared_data->action & RELOAD ) { @@ -2096,7 +2097,7 @@ void Monitor::ReloadZones() { delete zones[i]; } delete[] zones; - zones = 0; + zones = nullptr; n_zones = Zone::Load(this, zones); //DumpZoneImage(); } // end void Monitor::ReloadZones() @@ -2108,7 +2109,7 @@ void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) { delete linked_monitors[i]; } delete[] linked_monitors; - linked_monitors = 0; + linked_monitors = nullptr; } n_linked_monitors = 0; @@ -2538,13 +2539,13 @@ bool Monitor::closeEvent() { } event_delete_thread = new std::thread([](Event *event) { Event * e = event; - event = NULL; + event = nullptr; delete e; - e = NULL; + e = nullptr; }, event); #else delete event; - event = NULL; + event = nullptr; #endif video_store_data->recording = (struct timeval){0}; return true; diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 9b5130a59..2ca6bba42 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -93,6 +93,7 @@ public: } Orientation; typedef enum { + UNKNOWN=-1, IDLE, PREALARM, ALARM, @@ -403,7 +404,7 @@ public: bool connect(); inline int ShmValid() const { - return shared_data->valid; + return shared_data && shared_data->valid; } Camera *getCamera(); diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index 406f8a566..e586a0910 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -251,20 +251,29 @@ void MonitorStream::processCommand(const CmdMsg *msg) { } status_data; status_data.id = monitor->Id(); - status_data.fps = monitor->GetFPS(); - status_data.state = monitor->shared_data->state; - if ( playback_buffer > 0 ) - status_data.buffer_level = (MOD_ADD( (temp_write_index-temp_read_index), 0, temp_image_buffer_count )*100)/temp_image_buffer_count; - else + if ( ! monitor->ShmValid() ) { + status_data.fps = 0.0; + status_data.state = Monitor::UNKNOWN; + //status_data.enabled = monitor->shared_data->active; + status_data.enabled = false; + status_data.forced = false; status_data.buffer_level = 0; + } else { + status_data.fps = monitor->GetFPS(); + status_data.state = monitor->shared_data->state; + //status_data.enabled = monitor->shared_data->active; + status_data.enabled = monitor->trigger_data->trigger_state!=Monitor::TRIGGER_OFF; + status_data.forced = monitor->trigger_data->trigger_state==Monitor::TRIGGER_ON; + if ( playback_buffer > 0 ) + status_data.buffer_level = (MOD_ADD( (temp_write_index-temp_read_index), 0, temp_image_buffer_count )*100)/temp_image_buffer_count; + else + status_data.buffer_level = 0; + } status_data.delayed = delayed; status_data.paused = paused; status_data.rate = replay_rate; - status_data.delay = TV_2_FLOAT( now ) - TV_2_FLOAT( last_frame_timestamp ); + status_data.delay = TV_2_FLOAT(now) - TV_2_FLOAT(last_frame_timestamp); status_data.zoom = zoom; - //status_data.enabled = monitor->shared_data->active; - status_data.enabled = monitor->trigger_data->trigger_state!=Monitor::TRIGGER_OFF; - status_data.forced = monitor->trigger_data->trigger_state==Monitor::TRIGGER_ON; Debug(2, "Buffer Level:%d, Delayed:%d, Paused:%d, Rate:%d, delay:%.3f, Zoom:%d, Enabled:%d Forced:%d", status_data.buffer_level, status_data.delayed, @@ -291,12 +300,13 @@ void MonitorStream::processCommand(const CmdMsg *msg) { // quit after sending a status, if this was a quit request if ( (MsgCommand)msg->msg_data[0]==CMD_QUIT ) { - Debug(2,"Quitting"); - exit(0); + zm_terminate = true; + Debug(2, "Quitting"); + return; } - Debug(2,"Updating framerate"); - updateFrameRate(monitor->GetFPS()); + //Debug(2,"Updating framerate"); + //updateFrameRate(monitor->GetFPS()); } // end void MonitorStream::processCommand(const CmdMsg *msg) bool MonitorStream::sendFrame(const char *filepath, struct timeval *timestamp) { @@ -317,7 +327,7 @@ bool MonitorStream::sendFrame(const char *filepath, struct timeval *timestamp) { int img_buffer_size = 0; static unsigned char img_buffer[ZM_MAX_IMAGE_SIZE]; - FILE *fdj = NULL; + FILE *fdj = nullptr; if ( (fdj = fopen(filepath, "r")) ) { img_buffer_size = fread(img_buffer, 1, sizeof(img_buffer), fdj); fclose(fdj); @@ -328,7 +338,7 @@ bool MonitorStream::sendFrame(const char *filepath, struct timeval *timestamp) { // Calculate how long it takes to actually send the frame struct timeval frameStartTime; - gettimeofday(&frameStartTime, NULL); + gettimeofday(&frameStartTime, nullptr); if ( (0 > fprintf(stdout, "Content-Length: %d\r\nX-Timestamp: %d.%06d\r\n\r\n", @@ -344,7 +354,7 @@ bool MonitorStream::sendFrame(const char *filepath, struct timeval *timestamp) { fflush(stdout); struct timeval frameEndTime; - gettimeofday(&frameEndTime, NULL); + gettimeofday(&frameEndTime, nullptr); int frameSendTime = tvDiffMsec(frameStartTime, frameEndTime); if ( frameSendTime > 1000/maxfps ) { @@ -388,9 +398,8 @@ bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) { // Calculate how long it takes to actually send the frame struct timeval frameStartTime; - gettimeofday(&frameStartTime, NULL); + gettimeofday(&frameStartTime, nullptr); - fputs("--ZoneMinderFrame\r\n", stdout); switch ( type ) { case STREAM_JPEG : send_image->EncodeJpeg(img_buffer, &img_buffer_size); @@ -432,7 +441,7 @@ bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) { fflush(stdout); struct timeval frameEndTime; - gettimeofday(&frameEndTime, NULL); + gettimeofday(&frameEndTime, nullptr); int frameSendTime = tvDiffMsec(frameStartTime, frameEndTime); if ( frameSendTime > 1000/maxfps ) { @@ -454,16 +463,23 @@ void MonitorStream::runStream() { openComms(); + if ( type == STREAM_JPEG ) + fputs("Content-Type: multipart/x-mixed-replace; boundary=" BOUNDARY "\r\n\r\n", stdout); + if ( !checkInitialised() ) { Error("Not initialized"); - return; + while ( !(loadMonitor(monitor_id) || zm_terminate) ) { + sendTextFrame("Not connected"); + if ( connkey ) + checkCommandQueue(); + sleep(1); + } + if ( zm_terminate ) + return; } updateFrameRate(monitor->GetFPS()); - if ( type == STREAM_JPEG ) - fputs("Content-Type: multipart/x-mixed-replace; boundary=" BOUNDARY "\r\n\r\n", stdout); - // point to end which is theoretically not a valid value because all indexes are % image_buffer_count unsigned int last_read_index = monitor->image_buffer_count; @@ -472,7 +488,7 @@ void MonitorStream::runStream() { frame_count = 0; - temp_image_buffer = 0; + temp_image_buffer = nullptr; temp_image_buffer_count = playback_buffer; temp_read_index = temp_image_buffer_count; temp_write_index = temp_image_buffer_count; @@ -483,7 +499,7 @@ void MonitorStream::runStream() { bool buffered_playback = false; // Last image and timestamp when paused, will be resent occasionally to prevent timeout - Image *paused_image = NULL; + Image *paused_image = nullptr; struct timeval paused_timestamp; if ( connkey && ( playback_buffer > 0 ) ) { @@ -491,8 +507,8 @@ void MonitorStream::runStream() { const int max_swap_len_suffix = 15; int swap_path_length = staticConfig.PATH_SWAP.length() + 1; // +1 for NULL terminator - int subfolder1_length = snprintf(NULL, 0, "/zmswap-m%d", monitor->Id()) + 1; - int subfolder2_length = snprintf(NULL, 0, "/zmswap-q%06d", connkey) + 1; + int subfolder1_length = snprintf(nullptr, 0, "/zmswap-m%d", monitor->Id()) + 1; + int subfolder2_length = snprintf(nullptr, 0, "/zmswap-q%06d", connkey) + 1; int total_swap_path_length = swap_path_length + subfolder1_length + subfolder2_length; if ( total_swap_path_length + max_swap_len_suffix > PATH_MAX ) { @@ -549,7 +565,7 @@ void MonitorStream::runStream() { break; } - gettimeofday(&now, NULL); + gettimeofday(&now, nullptr); bool was_paused = paused; if ( connkey ) { @@ -575,7 +591,7 @@ void MonitorStream::runStream() { } else if ( paused_image ) { Debug(1, "Clearing paused_image"); delete paused_image; - paused_image = NULL; + paused_image = nullptr; } if ( buffered_playback && delayed ) { diff --git a/src/zm_monitorstream.h b/src/zm_monitorstream.h index cb502efc3..24655b636 100644 --- a/src/zm_monitorstream.h +++ b/src/zm_monitorstream.h @@ -59,7 +59,7 @@ class MonitorStream : public StreamBase { public: MonitorStream() : - temp_image_buffer(NULL), temp_image_buffer_count(0), temp_read_index(0), temp_write_index(0), + temp_image_buffer(nullptr), temp_image_buffer_count(0), temp_read_index(0), temp_write_index(0), ttl(0), playback_buffer(0), delayed(false), frame_count(0) { } void setStreamBuffer(int p_playback_buffer) { diff --git a/src/zm_mpeg.cpp b/src/zm_mpeg.cpp index c6b1ebc7d..225cdaa5e 100644 --- a/src/zm_mpeg.cpp +++ b/src/zm_mpeg.cpp @@ -46,9 +46,9 @@ void VideoStream::Initialise( ) { void VideoStream::SetupFormat( ) { /* allocate the output media context */ - ofc = NULL; + ofc = nullptr; #if (LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 2, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100)) - avformat_alloc_output_context2(&ofc, NULL, format, filename); + avformat_alloc_output_context2(&ofc, nullptr, format, filename); #else AVFormatContext *s = avformat_alloc_context(); if ( !s ) { @@ -59,18 +59,18 @@ void VideoStream::SetupFormat( ) { AVOutputFormat *oformat; if ( format ) { #if LIBAVFORMAT_VERSION_CHECK(52, 45, 0, 45, 0) - oformat = av_guess_format(format, NULL, NULL); + oformat = av_guess_format(format, nullptr, nullptr); #else - oformat = guess_format(format, NULL, NULL); + oformat = guess_format(format, nullptr, nullptr); #endif if ( !oformat ) { Fatal("Requested output format '%s' is not a suitable output format", format); } } else { #if LIBAVFORMAT_VERSION_CHECK(52, 45, 0, 45, 0) - oformat = av_guess_format(NULL, filename, NULL); + oformat = av_guess_format(nullptr, filename, nullptr); #else - oformat = guess_format(NULL, filename, NULL); + oformat = guess_format(nullptr, filename, nullptr); #endif if ( !oformat ) { Fatal("Unable to find a suitable output format for '%s'", format); @@ -91,7 +91,7 @@ void VideoStream::SetupFormat( ) { #endif } else { Debug(1, "No allocating priv_data"); - s->priv_data = NULL; + s->priv_data = nullptr; } if ( filename ) { @@ -172,7 +172,7 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei /* add the video streams using the default format codecs and initialize the codecs */ - ost = NULL; + ost = nullptr; if ( codec_id != AV_CODEC_ID_NONE ) { codec = avcodec_find_encoder(codec_id); if ( !codec ) { @@ -204,7 +204,7 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - codec_context = avcodec_alloc_context3(NULL); + codec_context = avcodec_alloc_context3(nullptr); //avcodec_parameters_to_context(codec_context, ost->codecpar); #else codec_context = ost->codec; @@ -296,7 +296,7 @@ bool VideoStream::OpenStream( ) { #if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0) if ( (ret = avcodec_open(codec_context, codec)) < 0 ) #else - if ( (ret = avcodec_open2(codec_context, codec, 0)) < 0 ) + if ( (ret = avcodec_open2(codec_context, codec, nullptr)) < 0 ) #endif { Error("Could not open codec. Error code %d \"%s\"", ret, av_err2str(ret)); @@ -338,7 +338,7 @@ bool VideoStream::OpenStream( ) { /* if the output format is not identical to the input format, then a temporary picture is needed too. It is then converted to the required output format */ - tmp_opicture = NULL; + tmp_opicture = nullptr; if ( codec_context->pix_fmt != pf ) { #if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) tmp_opicture = av_frame_alloc( ); @@ -374,7 +374,7 @@ bool VideoStream::OpenStream( ) { /* open the output file, if needed */ if ( !(of->flags & AVFMT_NOFILE) ) { #if LIBAVFORMAT_VERSION_CHECK(53, 15, 0, 21, 0) - ret = avio_open2( &ofc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL ); + ret = avio_open2( &ofc->pb, filename, AVIO_FLAG_WRITE, nullptr, nullptr ); #elif LIBAVFORMAT_VERSION_CHECK(52, 102, 0, 102, 0) ret = avio_open( &ofc->pb, filename, AVIO_FLAG_WRITE ); #else @@ -391,7 +391,7 @@ bool VideoStream::OpenStream( ) { return false; } - video_outbuf = NULL; + video_outbuf = nullptr; #if LIBAVFORMAT_VERSION_CHECK(57, 0, 0, 0, 0) if (codec_context->codec_type == AVMEDIA_TYPE_VIDEO && codec_context->codec_id == AV_CODEC_ID_RAWVIDEO) { @@ -403,7 +403,7 @@ bool VideoStream::OpenStream( ) { // TODO: Make buffer dynamic. video_outbuf_size = 4000000; video_outbuf = (uint8_t *)malloc( video_outbuf_size ); - if ( video_outbuf == NULL ) { + if ( video_outbuf == nullptr ) { Fatal("Unable to malloc memory for outbuf"); } } @@ -417,7 +417,7 @@ bool VideoStream::OpenStream( ) { #if !LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 4, 0) ret = av_write_header(ofc); #else - ret = avformat_write_header(ofc, NULL); + ret = avformat_write_header(ofc, nullptr); #endif if ( ret < 0 ) { @@ -430,16 +430,16 @@ bool VideoStream::OpenStream( ) { VideoStream::VideoStream( const char *in_filename, const char *in_format, int bitrate, double frame_rate, int colours, int subpixelorder, int width, int height ) : filename(in_filename), format(in_format), - opicture(NULL), - tmp_opicture(NULL), - video_outbuf(NULL), + opicture(nullptr), + tmp_opicture(nullptr), + video_outbuf(nullptr), video_outbuf_size(0), last_pts( -1 ), streaming_thread(0), do_streaming(true), add_timestamp(false), timestamp(0), - buffer_copy(NULL), + buffer_copy(nullptr), buffer_copy_lock(new pthread_mutex_t), buffer_copy_size(0), buffer_copy_used(0), @@ -454,15 +454,15 @@ VideoStream::VideoStream( const char *in_filename, const char *in_format, int bi codec_and_format = new char[length+1];; strcpy( codec_and_format, format ); format = codec_and_format; - codec_name = NULL; + codec_name = nullptr; char *f = strchr(codec_and_format, '/'); - if (f != NULL) { + if (f != nullptr) { *f = 0; codec_name = f+1; } } - codec_context = NULL; + codec_context = nullptr; SetupFormat( ); SetupCodec( colours, subpixelorder, width, height, bitrate, frame_rate ); SetParameters( ); @@ -474,7 +474,7 @@ VideoStream::VideoStream( const char *in_filename, const char *in_format, int bi packet_index = 0; // Initialize mutex used by streaming thread. - if ( pthread_mutex_init( buffer_copy_lock, NULL ) != 0 ) { + if ( pthread_mutex_init( buffer_copy_lock, nullptr ) != 0 ) { Fatal("pthread_mutex_init failed"); } @@ -494,7 +494,7 @@ VideoStream::~VideoStream( ) { pthread_join(streaming_thread, &thread_exit_code); } - if ( buffer_copy != NULL ) { + if ( buffer_copy != nullptr ) { av_free( buffer_copy ); } @@ -582,7 +582,7 @@ double VideoStream::EncodeFrame( const uint8_t *buffer, int buffer_size, bool _a Debug( 1, "Starting streaming thread" ); // Start a thread for streaming encoded video. - if (pthread_create( &streaming_thread, NULL, StreamingThreadCallback, (void*) this) != 0){ + if (pthread_create( &streaming_thread, nullptr, StreamingThreadCallback, (void*) this) != 0){ // Log a fatal error and exit the process. Fatal( "VideoStream failed to create streaming thread." ); } @@ -597,12 +597,12 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, if ( codec_context->pix_fmt != pf ) { #ifdef HAVE_LIBSWSCALE - static struct SwsContext *img_convert_ctx = 0; + static struct SwsContext *img_convert_ctx = nullptr; #endif // HAVE_LIBSWSCALE memcpy( tmp_opicture->data[0], buffer, buffer_size ); #ifdef HAVE_LIBSWSCALE if ( !img_convert_ctx ) { - img_convert_ctx = sws_getCachedContext( NULL, codec_context->width, codec_context->height, pf, codec_context->width, codec_context->height, codec_context->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL ); + img_convert_ctx = sws_getCachedContext( nullptr, codec_context->width, codec_context->height, pf, codec_context->width, codec_context->height, codec_context->pix_fmt, SWS_BICUBIC, nullptr, nullptr, nullptr ); if ( !img_convert_ctx ) Panic( "Unable to initialise image scaling context" ); } @@ -659,7 +659,7 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, #else int out_size = avcodec_encode_video( codec_context, video_outbuf, video_outbuf_size, opicture_ptr ); got_packet = out_size > 0 ? 1 : 0; - pkt->data = got_packet ? video_outbuf : NULL; + pkt->data = got_packet ? video_outbuf : nullptr; pkt->size = got_packet ? out_size : 0; #endif #endif @@ -705,7 +705,7 @@ void *VideoStream::StreamingThreadCallback(void *ctx){ Debug( 1, "StreamingThreadCallback started" ); - if (ctx == NULL) return NULL; + if (ctx == nullptr) return nullptr; VideoStream* videoStream = reinterpret_cast(ctx); @@ -765,7 +765,7 @@ void *VideoStream::StreamingThreadCallback(void *ctx){ frame_count++; } - return 0; + return nullptr; } #endif // HAVE_LIBAVCODEC diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index a49ab06e2..7656c0236 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -24,36 +24,36 @@ using namespace std; -ZMPacket::ZMPacket( ) { +ZMPacket::ZMPacket() { keyframe = 0; // frame from decoded packet, to be used in generating image - in_frame = NULL; - out_frame = NULL; - image = NULL; - buffer = NULL; + in_frame = nullptr; + out_frame = nullptr; + image = nullptr; + buffer = nullptr; av_init_packet(&packet); packet.size = 0; // So we can detect whether it has been filled. - timestamp = NULL; - analysis_image = NULL; + timestamp = nullptr; + analysis_image = nullptr; image_index = -1; score = -1; codec_imgsize = 0; } -ZMPacket::ZMPacket( ZMPacket &p ) { +ZMPacket::ZMPacket(ZMPacket &p) { keyframe = 0; // frame from decoded packet, to be used in generating image - in_frame = NULL; - out_frame = NULL; - image = NULL; - buffer = NULL; + in_frame = nullptr; + out_frame = nullptr; + image = nullptr; + buffer = nullptr; av_init_packet(&packet); if ( zm_av_packet_ref(&packet, &p.packet) < 0 ) { Error("error refing packet"); } timestamp = new struct timeval; *timestamp = *p.timestamp; - analysis_image = NULL; + analysis_image = nullptr; image_index = -1; score = -1; } @@ -73,11 +73,11 @@ ZMPacket::~ZMPacket() { } if ( analysis_image ) { delete analysis_image; - analysis_image = NULL; + analysis_image = nullptr; } // We assume the image was allocated elsewhere, so we just unref it. - image = NULL; - timestamp = NULL; + image = nullptr; + timestamp = nullptr; } void ZMPacket::reset() { @@ -98,7 +98,7 @@ void ZMPacket::reset() { } if ( analysis_image ) { delete analysis_image; - analysis_image = NULL; + analysis_image = nullptr; } #if 0 if ( (! image) && timestamp ) { @@ -176,12 +176,12 @@ int ZMPacket::decode( AVCodecContext *ctx ) { Image *ZMPacket::get_image(Image *i) { if ( !in_frame ) { Error("Can't get image without frame.. maybe need to decode first"); - return NULL; + return nullptr; } if ( !image ) { if ( !i ) { Error("Need a pre-allocated image buffer"); - return NULL; + return nullptr; } image = i; } @@ -199,7 +199,7 @@ AVPacket *ZMPacket::set_packet(AVPacket *p) { Error("error refing packet"); } //dumpPacket(&packet, "zmpacket:"); - gettimeofday(timestamp, NULL); + gettimeofday(timestamp, nullptr); keyframe = p->flags & AV_PKT_FLAG_KEY; return &packet; } @@ -209,7 +209,7 @@ AVFrame *ZMPacket::get_out_frame( const AVCodecContext *ctx ) { out_frame = zm_av_frame_alloc(); if ( !out_frame ) { Error("Unable to allocate a frame"); - return NULL; + return nullptr; } #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) codec_imgsize = av_image_get_buffer_size( diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 2ca976657..25e218eb0 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -41,9 +41,9 @@ zm_packetqueue::zm_packetqueue( int video_image_count, int p_video_stream_id, in zm_packetqueue::~zm_packetqueue() { clearQueue(); delete[] packet_counts; - packet_counts = NULL; + packet_counts = nullptr; delete condition; - condition = NULL; + condition = nullptr; } /* Enqueues the given packet. Will maintain the analysis_it pointer and image packet counts. @@ -87,7 +87,7 @@ bool zm_packetqueue::queuePacket(ZMPacket* zm_packet) { ZMPacket* zm_packetqueue::popPacket( ) { if ( pktQueue.empty() ) { - return NULL; + return nullptr; } Debug(2, "poPacket Mutex locking"); mutex.lock(); @@ -131,7 +131,7 @@ unsigned int zm_packetqueue::clearQueue(unsigned int frames_to_keep, int stream_ int packets_to_delete = pktQueue.size(); std::list::reverse_iterator it; - ZMPacket *packet = NULL; + ZMPacket *packet = nullptr; for ( it = pktQueue.rbegin(); frames_to_keep && (it != pktQueue.rend()); ++it ) { ZMPacket *zm_packet = *it; @@ -201,7 +201,7 @@ unsigned int zm_packetqueue::clearQueue(unsigned int frames_to_keep, int stream_ delete_count += 1; } // while our iterator is not the first packet } // end if have packet_delete_count - packet = NULL; // tidy up for valgrind + packet = nullptr; // tidy up for valgrind Debug(3, "Deleted %d packets, %d remaining", delete_count, pktQueue.size()); #if 0 @@ -220,7 +220,7 @@ unsigned int zm_packetqueue::clearQueue(unsigned int frames_to_keep, int stream_ void zm_packetqueue::clearQueue() { mutex.lock(); - ZMPacket *packet = NULL; + ZMPacket *packet = nullptr; int delete_count = 0; while ( !pktQueue.empty() ) { packet = pktQueue.front(); @@ -290,7 +290,7 @@ unsigned int zm_packetqueue::clearQueue(struct timeval *duration, int streamId) } unsigned int deleted_frames = 0; - ZMPacket *zm_packet = NULL; + ZMPacket *zm_packet = nullptr; while (distance(it, pktQueue.rend()) > 1) { zm_packet = pktQueue.front(); pktQueue.pop_front(); @@ -298,7 +298,7 @@ unsigned int zm_packetqueue::clearQueue(struct timeval *duration, int streamId) delete zm_packet; deleted_frames += 1; } - zm_packet = NULL; + zm_packet = nullptr; Debug(3, "Deleted %d frames", deleted_frames); return deleted_frames; diff --git a/src/zm_poly.h b/src/zm_poly.h index be039ef3e..53eafcf84 100644 --- a/src/zm_poly.h +++ b/src/zm_poly.h @@ -61,7 +61,7 @@ protected: min_x = 0; max_x = 0; n_edges = 0; - edges = 0; + edges = nullptr; } ~Slice() { delete edges; @@ -83,7 +83,7 @@ protected: void calcCentre(); public: - inline Polygon() : n_coords(0), coords(0), area(0), edges(0), slices(0) { + inline Polygon() : n_coords(0), coords(nullptr), area(0), edges(nullptr), slices(nullptr) { } Polygon(int p_n_coords, const Coord *p_coords); Polygon(const Polygon &p_polygon); diff --git a/src/zm_regexp.cpp b/src/zm_regexp.cpp index 90c000028..fa3bc2de7 100644 --- a/src/zm_regexp.cpp +++ b/src/zm_regexp.cpp @@ -24,7 +24,7 @@ #if HAVE_LIBPCRE -RegExpr::RegExpr( const char *pattern, int flags, int p_max_matches ) : max_matches( p_max_matches ), match_buffers( 0 ), match_lengths( 0 ), match_valid( 0 ) +RegExpr::RegExpr( const char *pattern, int flags, int p_max_matches ) : max_matches( p_max_matches ), match_buffers( nullptr ), match_lengths( nullptr ), match_valid( nullptr ) { const char *errstr; int erroffset = 0; @@ -50,7 +50,7 @@ RegExpr::RegExpr( const char *pattern, int flags, int p_max_matches ) : max_matc match_valid = new bool[max_matches]; memset( match_valid, 0, sizeof(*match_valid)*max_matches ); } else { - match_vectors = NULL; + match_vectors = nullptr; } match_string = ""; n_matches = 0; diff --git a/src/zm_remote_camera.cpp b/src/zm_remote_camera.cpp index d80532d54..dce4daf5c 100644 --- a/src/zm_remote_camera.cpp +++ b/src/zm_remote_camera.cpp @@ -44,20 +44,20 @@ RemoteCamera::RemoteCamera( path( p_path ), hp( 0 ), mNeedAuth(false), - mAuthenticator(NULL) + mAuthenticator(nullptr) { if ( path[0] != '/' ) path = '/'+path; } RemoteCamera::~RemoteCamera() { - if ( hp != NULL ) { + if ( hp != nullptr ) { freeaddrinfo(hp); - hp = NULL; + hp = nullptr; } if ( mAuthenticator ) { delete mAuthenticator; - mAuthenticator = NULL; + mAuthenticator = nullptr; } } @@ -99,9 +99,9 @@ void RemoteCamera::Initialise() { if ( ret != 0 ) { Fatal( "Can't getaddrinfo(%s port %s): %s", host.c_str(), port.c_str(), gai_strerror(ret) ); } - struct addrinfo *p = NULL; + struct addrinfo *p = nullptr; int addr_count = 0; - for ( p = hp; p != NULL; p = p->ai_next ) { + for ( p = hp; p != nullptr; p = p->ai_next ) { addr_count++; } Debug(1, "%d addresses returned", addr_count); diff --git a/src/zm_remote_camera_http.cpp b/src/zm_remote_camera_http.cpp index 20b309c75..c016965d8 100644 --- a/src/zm_remote_camera_http.cpp +++ b/src/zm_remote_camera_http.cpp @@ -36,11 +36,11 @@ #endif #if HAVE_LIBPCRE -static RegExpr *header_expr = 0; -static RegExpr *status_expr = 0; -static RegExpr *connection_expr = 0; -static RegExpr *content_length_expr = 0; -static RegExpr *content_type_expr = 0; +static RegExpr *header_expr = nullptr; +static RegExpr *status_expr = nullptr; +static RegExpr *connection_expr = nullptr; +static RegExpr *content_length_expr = nullptr; +static RegExpr *content_type_expr = nullptr; #endif RemoteCameraHttp::RemoteCameraHttp( @@ -141,9 +141,9 @@ void RemoteCameraHttp::Initialise() { } // end void RemoteCameraHttp::Initialise() int RemoteCameraHttp::Connect() { - struct addrinfo *p = NULL; + struct addrinfo *p = nullptr; - for ( p = hp; p != NULL; p = p->ai_next ) { + for ( p = hp; p != nullptr; p = p->ai_next ) { sd = socket( p->ai_family, p->ai_socktype, p->ai_protocol ); if ( sd < 0 ) { Warning("Can't create socket: %s", strerror(errno) ); @@ -166,7 +166,7 @@ int RemoteCameraHttp::Connect() { break; } - if ( p == NULL ) { + if ( p == nullptr ) { Error("Unable to connect to the remote camera, aborting"); return -1; } @@ -208,7 +208,7 @@ int RemoteCameraHttp::ReadData( Buffer &buffer, unsigned int bytes_expected ) { struct timeval temp_timeout = timeout; - int n_found = select(sd+1, &rfds, NULL, NULL, &temp_timeout); + int n_found = select(sd+1, &rfds, nullptr, nullptr, &temp_timeout); if( n_found == 0 ) { Debug( 1, "Select timed out timeout was %d secs %d usecs", temp_timeout.tv_sec, temp_timeout.tv_usec ); int error = 0; @@ -294,10 +294,10 @@ int RemoteCameraHttp::ReadData( Buffer &buffer, unsigned int bytes_expected ) { } int RemoteCameraHttp::GetData() { - time_t start_time = time(NULL); + time_t start_time = time(nullptr); int buffer_len = 0; while ( !( buffer_len = ReadData(buffer) ) ) { - if ( zm_terminate || ( start_time - time(NULL) < ZM_WATCH_MAX_DELAY )) + if ( zm_terminate || ( start_time - time(nullptr) < ZM_WATCH_MAX_DELAY )) return -1; Debug(4, "Timeout waiting for REGEXP HEADER"); usleep(100000); @@ -309,16 +309,16 @@ int RemoteCameraHttp::GetResponse() { int buffer_len; #if HAVE_LIBPCRE if ( method == REGEXP ) { - const char *header = 0; + const char *header = nullptr; int header_len = 0; - const char *http_version = 0; + const char *http_version = nullptr; int status_code = 0; - const char *status_mesg = 0; + const char *status_mesg = nullptr; const char *connection_type = ""; int content_length = 0; const char *content_type = ""; const char *content_boundary = ""; - const char *subheader = 0; + const char *subheader = nullptr; int subheader_len = 0; //int subcontent_length = 0; //const char *subcontent_type = ""; @@ -435,9 +435,9 @@ int RemoteCameraHttp::GetResponse() { } case SUBHEADER : { - static RegExpr *subheader_expr = 0; - static RegExpr *subcontent_length_expr = 0; - static RegExpr *subcontent_type_expr = 0; + static RegExpr *subheader_expr = nullptr; + static RegExpr *subcontent_length_expr = nullptr; + static RegExpr *subcontent_type_expr = nullptr; if ( !subheader_expr ) { char subheader_pattern[256] = ""; @@ -605,11 +605,11 @@ int RemoteCameraHttp::GetResponse() { case HEADER : { n_headers = 0; - http_header = 0; - connection_header = 0; - content_length_header = 0; - content_type_header = 0; - authenticate_header = 0; + http_header = nullptr; + connection_header = nullptr; + content_length_header = nullptr; + content_type_header = nullptr; + authenticate_header = nullptr; http_version[0] = '\0'; status_code [0]= '\0'; @@ -629,7 +629,7 @@ int RemoteCameraHttp::GetResponse() { } bytes += buffer_len; - char *crlf = 0; + char *crlf = nullptr; char *header_ptr = (char *)buffer; int header_len = buffer.size(); bool all_headers = false; @@ -834,7 +834,7 @@ int RemoteCameraHttp::GetResponse() { } case SUBHEADERCONT : { - char *crlf = 0; + char *crlf = nullptr; char *subheader_ptr = (char *)buffer; int subheader_len = buffer.size(); bool all_headers = false; @@ -1033,6 +1033,18 @@ int RemoteCameraHttp::GetResponse() { return( 0 ); } // end RemoteCameraHttp::GetResponse +int RemoteCameraHttp::PrimeCapture() { + if ( sd < 0 ) { + Connect(); + if ( sd < 0 ) { + return -1; + } + mode = SINGLE_IMAGE; + buffer.clear(); + } + return 0; +} + int RemoteCameraHttp::PreCapture() { if ( sd < 0 ) { Connect(); diff --git a/src/zm_remote_camera_http.h b/src/zm_remote_camera_http.h index 2da0d1917..34193cb33 100644 --- a/src/zm_remote_camera_http.h +++ b/src/zm_remote_camera_http.h @@ -70,6 +70,7 @@ public: int ReadData( Buffer &buffer, unsigned int bytes_expected=0 ); int GetData(); int GetResponse(); + int PrimeCapture(); int PreCapture(); int Capture( ZMPacket &p ); int PostCapture(); diff --git a/src/zm_remote_camera_rtsp.cpp b/src/zm_remote_camera_rtsp.cpp index 654a97b97..26b0cac41 100644 --- a/src/zm_remote_camera_rtsp.cpp +++ b/src/zm_remote_camera_rtsp.cpp @@ -64,18 +64,18 @@ RemoteCameraRtsp::RemoteCameraRtsp( Initialise(); } - mFormatContext = NULL; + mFormatContext = nullptr; mVideoStreamId = -1; mAudioStreamId = -1; - mCodecContext = NULL; - mCodec = NULL; - mRawFrame = NULL; - mFrame = NULL; + mCodecContext = nullptr; + mCodec = nullptr; + mRawFrame = nullptr; + mFrame = nullptr; frameCount = 0; startTime=0; #if HAVE_LIBSWSCALE - mConvertContext = NULL; + mConvertContext = nullptr; #endif /* Has to be located inside the constructor so other components such as zma will receive correct colours and subpixel order */ if ( colours == ZM_COLOUR_RGB32 ) { @@ -99,13 +99,13 @@ RemoteCameraRtsp::~RemoteCameraRtsp() { #if HAVE_LIBSWSCALE if ( mConvertContext ) { sws_freeContext(mConvertContext); - mConvertContext = NULL; + mConvertContext = nullptr; } #endif if ( mCodecContext ) { avcodec_close(mCodecContext); - mCodecContext = NULL; // Freed by avformat_free_context in the destructor of RtspThread class + mCodecContext = nullptr; // Freed by avformat_free_context in the destructor of RtspThread class } if ( capture ) { @@ -144,7 +144,7 @@ int RemoteCameraRtsp::Disconnect() { rtspThread->stop(); rtspThread->join(); delete rtspThread; - rtspThread = 0; + rtspThread = nullptr; } return 0; } @@ -203,7 +203,7 @@ int RemoteCameraRtsp::PrimeCapture() { // Find the decoder for the video stream mCodec = avcodec_find_decoder(mCodecContext->codec_id); - if ( mCodec == NULL ) + if ( mCodec == nullptr ) Panic("Unable to locate codec %d decoder", mCodecContext->codec_id); // Open codec @@ -220,7 +220,7 @@ int RemoteCameraRtsp::PrimeCapture() { // Allocate space for the converted video frame mFrame = zm_av_frame_alloc(); - if ( mRawFrame == NULL || mFrame == NULL ) + if ( mRawFrame == nullptr || mFrame == nullptr ) Fatal("Unable to allocate frame(s)"); #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) @@ -275,7 +275,7 @@ int RemoteCameraRtsp::Capture( ZMPacket &zm_packet ) { /* Request a writeable buffer of the target image */ directbuffer = zm_packet.image->WriteBuffer(width, height, colours, subpixelorder); - if ( directbuffer == NULL ) { + if ( directbuffer == nullptr ) { Error("Failed requesting writeable buffer for the captured image."); return -1; } @@ -339,12 +339,12 @@ int RemoteCameraRtsp::Capture( ZMPacket &zm_packet ) { if ( frameComplete ) { #if HAVE_LIBSWSCALE - if ( mConvertContext == NULL ) { + if ( mConvertContext == nullptr ) { mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, - width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL); + width, height, imagePixFormat, SWS_BICUBIC, nullptr, nullptr, nullptr); - if ( mConvertContext == NULL ) + if ( mConvertContext == nullptr ) Fatal("Unable to create conversion context"); if ( diff --git a/src/zm_rtp_ctrl.cpp b/src/zm_rtp_ctrl.cpp index bc6725c5d..2ffc0c404 100644 --- a/src/zm_rtp_ctrl.cpp +++ b/src/zm_rtp_ctrl.cpp @@ -272,12 +272,12 @@ int RtpCtrlThread::run() { unsigned char buffer[ZM_NETWORK_BUFSIZ]; - time_t last_receive = time(NULL); + time_t last_receive = time(nullptr); bool timeout = false; // used as a flag that we had a timeout, and then sent an RR to see if we wake back up. Real timeout will happen when this is true. while ( !mStop && select.wait() >= 0 ) { - time_t now = time(NULL); + time_t now = time(nullptr); Select::CommsList readable = select.getReadable(); if ( readable.size() == 0 ) { if ( ! timeout ) { @@ -300,7 +300,7 @@ int RtpCtrlThread::run() { } } else { timeout = false; - last_receive = time(NULL); + last_receive = time(nullptr); } for ( Select::CommsList::iterator iter = readable.begin(); iter != readable.end(); ++iter ) { if ( UdpInetSocket *socket = dynamic_cast(*iter) ) { diff --git a/src/zm_rtsp.cpp b/src/zm_rtsp.cpp index 59d8ab171..53452bb94 100644 --- a/src/zm_rtsp.cpp +++ b/src/zm_rtsp.cpp @@ -198,14 +198,14 @@ RtspThread::~RtspThread() { #else av_free_format_context(mFormatContext); #endif - mFormatContext = NULL; + mFormatContext = nullptr; } if ( mSessDesc ) { delete mSessDesc; - mSessDesc = NULL; + mSessDesc = nullptr; } delete mAuthenticator; - mAuthenticator = NULL; + mAuthenticator = nullptr; } int RtspThread::run() { @@ -387,7 +387,7 @@ int RtspThread::run() { if ( !mAuth.empty() ) authUrl.insert( authUrl.find( "://" )+3, mAuth+"@" ); - if ( av_open_input_file( &mFormatContext, authUrl.c_str(), NULL, 0, NULL ) != 0 ) + if ( av_open_input_file( &mFormatContext, authUrl.c_str(), nullptr, 0, nullptr ) != 0 ) { Error( "Unable to open input '%s'", authUrl.c_str() ); return( -1 ); @@ -499,26 +499,26 @@ int RtspThread::run() { method = "RTP/UNICAST"; StringVector subparts = split( parts[i], "=" ); StringVector ports = split( subparts[1], "-" ); - remotePorts[0] = strtol( ports[0].c_str(), NULL, 10 ); - remotePorts[1] = strtol( ports[1].c_str(), NULL, 10 ); + remotePorts[0] = strtol( ports[0].c_str(), nullptr, 10 ); + remotePorts[1] = strtol( ports[1].c_str(), nullptr, 10 ); } else if ( startsWith( parts[i], "interleaved=" ) ) { method = "RTP/RTSP"; StringVector subparts = split( parts[i], "=" ); StringVector channels = split( subparts[1], "-" ); - remoteChannels[0] = strtol( channels[0].c_str(), NULL, 10 ); - remoteChannels[1] = strtol( channels[1].c_str(), NULL, 10 ); + remoteChannels[0] = strtol( channels[0].c_str(), nullptr, 10 ); + remoteChannels[1] = strtol( channels[1].c_str(), nullptr, 10 ); } else if ( startsWith( parts[i], "port=" ) ) { method = "RTP/MULTICAST"; StringVector subparts = split( parts[i], "=" ); StringVector ports = split( subparts[1], "-" ); - localPorts[0] = strtol( ports[0].c_str(), NULL, 10 ); - localPorts[1] = strtol( ports[1].c_str(), NULL, 10 ); + localPorts[0] = strtol( ports[0].c_str(), nullptr, 10 ); + localPorts[1] = strtol( ports[1].c_str(), nullptr, 10 ); } else if ( startsWith( parts[i], "destination=" ) ) { StringVector subparts = split( parts[i], "=" ); localHost = subparts[1]; } else if ( startsWith( parts[i], "ssrc=" ) ) { StringVector subparts = split( parts[i], "=" ); - ssrc = strtoll( subparts[1].c_str(), NULL, 16 ); + ssrc = strtoll( subparts[1].c_str(), nullptr, 16 ); } } @@ -568,10 +568,10 @@ int RtspThread::run() { for ( size_t j = 0; j < parts.size(); j++ ) { if ( startsWith( parts[j], "seq=" ) ) { StringVector subparts = split( parts[j], "=" ); - seq = strtol( subparts[1].c_str(), NULL, 10 ); + seq = strtol( subparts[1].c_str(), nullptr, 10 ); } else if ( startsWith( parts[j], "rtptime=" ) ) { StringVector subparts = split( parts[j], "=" ); - rtpTime = strtol( subparts[1].c_str(), NULL, 10 ); + rtpTime = strtol( subparts[1].c_str(), nullptr, 10 ); } } break; @@ -582,7 +582,7 @@ int RtspThread::run() { Debug( 2, "RTSP Seq is %d", seq ); Debug( 2, "RTSP Rtptime is %ld", rtpTime ); - time_t lastKeepalive = time(NULL); + time_t lastKeepalive = time(nullptr); time_t now; message = "GET_PARAMETER "+mUrl+" RTSP/1.0\r\nSession: "+session+"\r\n"; @@ -598,7 +598,7 @@ int RtspThread::run() { rtpCtrlThread.start(); while( !mStop ) { - now = time(NULL); + now = time(nullptr); // Send a keepalive message if the server supports this feature and we are close to the timeout expiration Debug(5, "sendkeepalive %d, timeout %d, now: %d last: %d since: %d", sendKeepalive, timeout, now, lastKeepalive, (now-lastKeepalive) ); @@ -721,7 +721,7 @@ int RtspThread::run() { } // Send a keepalive message if the server supports this feature and we are close to the timeout expiration // FIXME: Is this really necessary when using tcp ? - now = time(NULL); + now = time(nullptr); // Send a keepalive message if the server supports this feature and we are close to the timeout expiration Debug(5, "sendkeepalive %d, timeout %d, now: %d last: %d since: %d", sendKeepalive, timeout, now, lastKeepalive, (now-lastKeepalive) ); if ( sendKeepalive && (timeout > 0) && ((now-lastKeepalive) > (timeout-5)) ) @@ -761,10 +761,10 @@ Debug(5, "sendkeepalive %d, timeout %d, now: %d last: %d since: %d", sendKeepali while ( !mStop ) { // Send a keepalive message if the server supports this feature and we are close to the timeout expiration - if ( sendKeepalive && (timeout > 0) && ((time(NULL)-lastKeepalive) > (timeout-5)) ) { + if ( sendKeepalive && (timeout > 0) && ((time(nullptr)-lastKeepalive) > (timeout-5)) ) { if ( !sendCommand( message ) ) return -1; - lastKeepalive = time(NULL); + lastKeepalive = time(nullptr); } usleep(100000); } diff --git a/src/zm_sdp.cpp b/src/zm_sdp.cpp index 15f6ad5e3..de48e169d 100644 --- a/src/zm_sdp.cpp +++ b/src/zm_sdp.cpp @@ -152,16 +152,16 @@ SessionDescriptor::MediaDescriptor::MediaDescriptor( mWidth( 0 ), mHeight( 0 ), mSprops( "" ), - mConnInfo( 0 ) + mConnInfo( nullptr ) { } SessionDescriptor::SessionDescriptor( const std::string &url, const std::string &sdp ) : mUrl( url ), - mConnInfo( 0 ), - mBandInfo( 0 ) + mConnInfo( nullptr ), + mBandInfo( nullptr ) { - MediaDescriptor *currMedia = 0; + MediaDescriptor *currMedia = nullptr; StringVector lines = split( sdp, "\r\n" ); for ( StringVector::const_iterator iter = lines.begin(); iter != lines.end(); ++iter ) { @@ -344,12 +344,12 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const { #if !LIBAVFORMAT_VERSION_CHECK(53, 10, 0, 17, 0) AVStream *stream = av_new_stream(formatContext, i); #else - AVStream *stream = avformat_new_stream(formatContext, NULL); + AVStream *stream = avformat_new_stream(formatContext, nullptr); stream->id = i; #endif #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - AVCodecContext *codec_context = avcodec_alloc_context3(NULL); + AVCodecContext *codec_context = avcodec_alloc_context3(nullptr); avcodec_parameters_to_context(codec_context, stream->codecpar); stream->codec = codec_context; #else @@ -434,7 +434,7 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const { if ( codec_context->codec_id == AV_CODEC_ID_H264 && mediaDesc->getSprops().size()) { uint8_t start_sequence[]= { 0, 0, 1 }; codec_context->extradata_size= 0; - codec_context->extradata= NULL; + codec_context->extradata= nullptr; char pvalue[1024], *value = pvalue; strcpy(pvalue, mediaDesc->getSprops().c_str()); diff --git a/src/zm_sdp.h b/src/zm_sdp.h index ae7cd67a2..403c8a740 100644 --- a/src/zm_sdp.h +++ b/src/zm_sdp.h @@ -211,7 +211,7 @@ public: MediaDescriptor *getStream( int index ) { if ( index < 0 || (unsigned int)index >= mMediaList.size() ) - return( 0 ); + return nullptr; return( mMediaList[index] ); } diff --git a/src/zm_sendfile.h b/src/zm_sendfile.h index 2f892d693..593a94833 100644 --- a/src/zm_sendfile.h +++ b/src/zm_sendfile.h @@ -11,7 +11,7 @@ int zm_sendfile(int out_fd, int in_fd, off_t *offset, size_t size) { int err; err = sendfile(out_fd, in_fd, offset, size); - if (err < 0) + if ( err < 0 ) return -errno; return err; @@ -22,7 +22,7 @@ int zm_sendfile(int out_fd, int in_fd, off_t *offset, size_t size) { #include int zm_sendfile(int out_fd, int in_fd, off_t *offset, off_t size) { int err; - err = sendfile(in_fd, out_fd, *offset, size, NULL, &size, 0); + err = sendfile(in_fd, out_fd, *offset, size, nullptr, &size, 0); if (err && errno != EAGAIN) return -errno; diff --git a/src/zm_signal.cpp b/src/zm_signal.cpp index e13bfdc9c..81012c07e 100644 --- a/src/zm_signal.cpp +++ b/src/zm_signal.cpp @@ -53,8 +53,8 @@ RETSIGTYPE zm_die_handler(int signal) #if (defined(__i386__) || defined(__x86_64__)) // Get more information if available #if ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T ) - void *ip = 0; - void *cr2 = 0; + void *ip = nullptr; + void *cr2 = nullptr; if (info && context) { Debug(1, diff --git a/src/zm_stream.cpp b/src/zm_stream.cpp index 258e04d52..05236c3ba 100644 --- a/src/zm_stream.cpp +++ b/src/zm_stream.cpp @@ -33,13 +33,21 @@ StreamBase::~StreamBase() { #if HAVE_LIBAVCODEC if ( vid_stream ) { delete vid_stream; - vid_stream = NULL; + vid_stream = nullptr; } #endif closeComms(); + if ( monitor ) { + delete monitor; + monitor = NULL; + } } -bool StreamBase::loadMonitor(int monitor_id) { +bool StreamBase::loadMonitor(int p_monitor_id) { + monitor_id = p_monitor_id; + if ( monitor ) + delete monitor; + if ( !(monitor = Monitor::Load(monitor_id, false, Monitor::QUERY)) ) { Error("Unable to load monitor id %d for streaming", monitor_id); return false; @@ -59,7 +67,15 @@ bool StreamBase::loadMonitor(int monitor_id) { bool StreamBase::checkInitialised() { if ( !monitor ) { - Fatal("Cannot stream, not initialised"); + Error("Cannot stream, not initialised"); + return false; + } + if ( monitor->GetFunction() == Monitor::NONE ) { + Error("Monitor %d has function NONE. Will not be able to connect to it.", monitor_id); + return false; + } + if ( !monitor->ShmValid() ) { + Error("Monitor shm is not connected"); return false; } return true; @@ -248,7 +264,7 @@ bool StreamBase::sendTextFrame(const char *frame_text) { fprintf(stdout, "Content-type: %s\r\n\r\n", vid_stream->MimeType()); vid_stream->OpenStream(); } - /* double pts = */ vid_stream->EncodeFrame( image.Buffer(), image.Size() ); + /* double pts = */ vid_stream->EncodeFrame(image.Buffer(), image.Size()); } else #endif // HAVE_LIBAVCODEC { @@ -257,13 +273,13 @@ bool StreamBase::sendTextFrame(const char *frame_text) { image.EncodeJpeg(buffer, &n_bytes); - fputs("--ZoneMinderFrame\r\nContent-Type: image/jpeg\r\n", stdout); + fputs("--" BOUNDARY "\r\nContent-Type: image/jpeg\r\n", stdout); fprintf(stdout, "Content-Length: %d\r\n\r\n", n_bytes); if ( fwrite(buffer, n_bytes, 1, stdout) != 1 ) { Error("Unable to send stream text frame: %s", strerror(errno)); return false; } - fputs("\r\n\r\n",stdout); + fputs("\r\n\r\n", stdout); fflush(stdout); } last_frame_sent = TV_2_FLOAT(now); @@ -351,7 +367,7 @@ void StreamBase::openComms() { strncpy(rem_addr.sun_path, rem_sock_path, sizeof(rem_addr.sun_path)); rem_addr.sun_family = AF_UNIX; - gettimeofday(&last_comm_update, NULL); + gettimeofday(&last_comm_update, nullptr); } // end if connKey > 0 Debug(3, "comms open at %s", loc_sock_path); } // end void StreamBase::openComms() diff --git a/src/zm_stream.h b/src/zm_stream.h index 6024d9823..d906b2de6 100644 --- a/src/zm_stream.h +++ b/src/zm_stream.h @@ -61,6 +61,7 @@ protected: typedef enum { CMD_NONE=0, CMD_PAUSE, CMD_PLAY, CMD_STOP, CMD_FASTFWD, CMD_SLOWFWD, CMD_SLOWREV, CMD_FASTREV, CMD_ZOOMIN, CMD_ZOOMOUT, CMD_PAN, CMD_SCALE, CMD_PREV, CMD_NEXT, CMD_SEEK, CMD_VARPLAY, CMD_GET_IMAGE, CMD_QUIT, CMD_QUERY=99 } MsgCommand; protected: + int monitor_id; Monitor *monitor; StreamType type; @@ -114,6 +115,7 @@ protected: public: StreamBase(): + monitor_id(0), monitor(0), type(DEFAULT_TYPE), format(""), @@ -157,6 +159,13 @@ public: void setStreamType(StreamType p_type) { type = p_type; +#if ! HAVE_ZLIB_H + if ( type == STREAM_ZIP ) { + Error("zlib is required for zipped images. Falling back to raw image"); + type = STREAM_RAW; + } +#endif + } void setStreamFormat(const char *p_format) { format = p_format; diff --git a/src/zm_swscale.cpp b/src/zm_swscale.cpp index 5830f402a..90a1b0412 100644 --- a/src/zm_swscale.cpp +++ b/src/zm_swscale.cpp @@ -24,7 +24,7 @@ #include "zm_swscale.h" #if HAVE_LIBSWSCALE && HAVE_LIBAVUTIL -SWScale::SWScale() : gotdefaults(false), swscale_ctx(NULL), input_avframe(NULL), output_avframe(NULL) { +SWScale::SWScale() : gotdefaults(false), swscale_ctx(nullptr), input_avframe(nullptr), output_avframe(nullptr) { Debug(4,"SWScale object created"); } @@ -36,7 +36,7 @@ bool SWScale::init() { #else input_avframe = avcodec_alloc_frame(); #endif - if ( input_avframe == NULL ) { + if ( input_avframe == nullptr ) { Error("Failed allocating AVFrame for the input"); return false; } @@ -47,7 +47,7 @@ bool SWScale::init() { #else output_avframe = avcodec_alloc_frame(); #endif - if ( output_avframe == NULL ) { + if ( output_avframe == nullptr ) { Error("Failed allocating AVFrame for the output"); return false; } @@ -65,7 +65,7 @@ SWScale::~SWScale() { if ( swscale_ctx ) { sws_freeContext(swscale_ctx); - swscale_ctx = NULL; + swscale_ctx = nullptr; } Debug(4,"SWScale object destroyed"); @@ -139,7 +139,7 @@ int SWScale::Convert( unsigned int new_height ) { /* Parameter checking */ - if(in_buffer == NULL || out_buffer == NULL) { + if(in_buffer == nullptr || out_buffer == nullptr) { Error("NULL Input or output buffer"); return -1; } @@ -202,8 +202,8 @@ int SWScale::Convert( } /* Get the context */ - swscale_ctx = sws_getCachedContext(swscale_ctx, width, height, in_pf, new_width, new_height, out_pf, SWS_FAST_BILINEAR, NULL, NULL, NULL); - if ( swscale_ctx == NULL ) { + swscale_ctx = sws_getCachedContext( swscale_ctx, width, height, in_pf, new_width, new_height, out_pf, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr ); + if ( swscale_ctx == nullptr ) { Error("Failed getting swscale context"); return -6; } diff --git a/src/zm_thread.cpp b/src/zm_thread.cpp index 3e43cced3..60a282c18 100644 --- a/src/zm_thread.cpp +++ b/src/zm_thread.cpp @@ -30,7 +30,7 @@ struct timespec getTimeout( int secs ) { struct timespec timeout; struct timeval temp_timeout; - gettimeofday(&temp_timeout, 0); + gettimeofday(&temp_timeout, nullptr); timeout.tv_sec = temp_timeout.tv_sec + secs; timeout.tv_nsec = temp_timeout.tv_usec*1000; return timeout; @@ -39,7 +39,7 @@ struct timespec getTimeout( int secs ) { struct timespec getTimeout( double secs ) { struct timespec timeout; struct timeval temp_timeout; - gettimeofday( &temp_timeout, 0 ); + gettimeofday( &temp_timeout, nullptr ); timeout.tv_sec = temp_timeout.tv_sec + int(secs); timeout.tv_nsec = temp_timeout.tv_usec += (long int)(1000000000.0*(secs-int(secs))); if ( timeout.tv_nsec > 1000000000 ) { @@ -50,7 +50,7 @@ struct timespec getTimeout( double secs ) { } Mutex::Mutex() { - if ( pthread_mutex_init(&mMutex, NULL) < 0 ) + if ( pthread_mutex_init(&mMutex, nullptr) < 0 ) Error("Unable to create pthread mutex: %s", strerror(errno)); } @@ -107,8 +107,8 @@ RecursiveMutex::RecursiveMutex() { } Condition::Condition( Mutex &mutex ) : mMutex( mutex ) { - if ( pthread_cond_init( &mCondition, NULL ) < 0 ) - Fatal( "Unable to create pthread condition: %s", strerror(errno) ); + if ( pthread_cond_init(&mCondition, nullptr) < 0 ) + throw ThreadException(stringtf("Unable to create pthread condition: %s", strerror(errno))); } Condition::~Condition() { diff --git a/src/zm_time.h b/src/zm_time.h index a9af32777..0f7dbc794 100644 --- a/src/zm_time.h +++ b/src/zm_time.h @@ -86,7 +86,7 @@ inline int tvDiffUsec( struct timeval first, struct timeval last ) inline int tvDiffUsec( struct timeval first ) { struct timeval now; - gettimeofday( &now, NULL ); + gettimeofday( &now, nullptr ); return( tvDiffUsec( first, now ) ); } @@ -98,7 +98,7 @@ inline int tvDiffMsec( struct timeval first, struct timeval last ) inline int tvDiffMsec( struct timeval first ) { struct timeval now; - gettimeofday( &now, NULL ); + gettimeofday( &now, nullptr ); return( tvDiffMsec( first, now ) ); } @@ -110,7 +110,7 @@ inline double tvDiffSec( struct timeval first, struct timeval last ) inline double tvDiffSec( struct timeval first ) { struct timeval now; - gettimeofday( &now, NULL ); + gettimeofday( &now, nullptr ); return( tvDiffSec( first, now ) ); } @@ -146,7 +146,7 @@ inline int tvEq( struct timeval t1, struct timeval t2 ) inline struct timeval tvNow( void ) { struct timeval t; - gettimeofday( &t, NULL ); + gettimeofday( &t, nullptr ); return( t ); } diff --git a/src/zm_user.cpp b/src/zm_user.cpp index 3be4e274a..9a20aefaa 100644 --- a/src/zm_user.cpp +++ b/src/zm_user.cpp @@ -116,7 +116,7 @@ User *zmLoadUser(const char *username, const char *password) { " FROM `Users` WHERE `Username` = '%s' AND `Enabled` = 1", safer_username); delete[] safer_username; - safer_username = NULL; + safer_username = nullptr; if ( mysql_query(&dbconn, sql) ) { Error("Can't run query: %s", mysql_error(&dbconn)); @@ -145,7 +145,7 @@ User *zmLoadUser(const char *username, const char *password) { mysql_free_result(result); Warning("Unable to authenticate user %s", username); - return NULL; + return nullptr; } // end User *zmLoadUser(const char *username, const char *password) User *zmLoadTokenUser(std::string jwt_token_str, bool use_remote_addr) { @@ -169,7 +169,7 @@ User *zmLoadTokenUser(std::string jwt_token_str, bool use_remote_addr) { Debug(1, "retrieved user '%s' from token", username.c_str()); if ( username == "" ) { - return NULL; + return nullptr; } char sql[ZM_SQL_MED_BUFSIZ] = ""; @@ -180,30 +180,30 @@ User *zmLoadTokenUser(std::string jwt_token_str, bool use_remote_addr) { if ( mysql_query(&dbconn, sql) ) { Error("Can't run query: %s", mysql_error(&dbconn)); - return NULL; + return nullptr; } MYSQL_RES *result = mysql_store_result(&dbconn); if ( !result ) { Error("Can't use query result: %s", mysql_error(&dbconn)); - return NULL; + return nullptr; } int n_users = mysql_num_rows(result); if ( n_users != 1 ) { mysql_free_result(result); Error("Unable to authenticate user '%s'", username.c_str()); - return NULL; + return nullptr; } MYSQL_ROW dbrow = mysql_fetch_row(result); User *user = new User(dbrow); - unsigned int stored_iat = strtoul(dbrow[10], NULL, 0); + unsigned int stored_iat = strtoul(dbrow[10], nullptr, 0); if ( stored_iat > iat ) { // admin revoked tokens mysql_free_result(result); Error("Token was revoked for '%s'", username.c_str()); - return NULL; + return nullptr; } Debug(1, "Authenticated user '%s' via token with last revoke time: %u", @@ -248,17 +248,17 @@ User *zmLoadAuthUser(const char *auth, bool use_remote_addr) { MYSQL_RES *result = mysql_store_result(&dbconn); if ( !result ) { Error("Can't use query result: %s", mysql_error(&dbconn)); - return NULL; + return nullptr; } int n_users = mysql_num_rows(result); if ( n_users < 1 ) { mysql_free_result(result); Warning("Unable to authenticate user"); - return NULL; + return nullptr; } // getting the time is expensive, so only do it once. - time_t now = time(0); + time_t now = time(nullptr); unsigned int hours = config.auth_hash_ttl; if ( !hours ) { Warning("No value set for ZM_AUTH_HASH_TTL. Defaulting to 2."); @@ -324,7 +324,7 @@ User *zmLoadAuthUser(const char *auth, bool use_remote_addr) { Error("You need to build with gnutls or openssl to use hash based auth"); #endif // HAVE_DECL_MD5 || HAVE_DECL_GNUTLS_FINGERPRINT Debug(1, "No user found for auth_key %s", auth); - return NULL; + return nullptr; } // end User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) // Function to check Username length diff --git a/src/zm_utils.cpp b/src/zm_utils.cpp index ddf533f46..67fcc0669 100644 --- a/src/zm_utils.cpp +++ b/src/zm_utils.cpp @@ -195,7 +195,7 @@ const std::string base64Encode(const std::string &inString) { } int split(const char* string, const char delim, std::vector& items) { - if ( string == NULL ) + if ( string == nullptr ) return -1; if ( string[0] == 0 ) @@ -216,7 +216,7 @@ int split(const char* string, const char delim, std::vector& items) } int pairsplit(const char* string, const char delim, std::string& name, std::string& value) { - if ( string == NULL ) + if ( string == nullptr ) return -1; if ( string[0] == 0 ) diff --git a/src/zm_video.cpp b/src/zm_video.cpp index 309c507c0..d97c75167 100644 --- a/src/zm_video.cpp +++ b/src/zm_video.cpp @@ -57,7 +57,7 @@ int VideoWriter::Reset(const char* new_path) { /* Common variables reset */ /* If there is a new path, use it */ - if ( new_path != NULL ) { + if ( new_path != nullptr ) { path = new_path; } @@ -116,7 +116,7 @@ X264MP4Writer::X264MP4Writer( } /* If supplied with user parameters to the encoder, copy them */ - if ( p_user_params != NULL ) { + if ( p_user_params != nullptr ) { user_params = *p_user_params; } @@ -144,7 +144,7 @@ X264MP4Writer::~X264MP4Writer() { int X264MP4Writer::Open() { /* Open the encoder */ x264enc = x264_encoder_open(&x264params); - if ( x264enc == NULL ) { + if ( x264enc == nullptr ) { Error("Failed opening x264 encoder"); return -1; } @@ -269,7 +269,7 @@ int X264MP4Writer::Encode( const size_t data_size, const unsigned int frame_time) { /* Parameter checking */ - if ( data == NULL ) { + if ( data == nullptr ) { Error("NULL buffer"); return -1; } @@ -418,7 +418,7 @@ int X264MP4Writer::x264encodeloop(bool bFlush) { int frame_size; if ( bFlush ) { - frame_size = x264_encoder_encode(x264enc, &nals, &i_nals, NULL, &x264picout); + frame_size = x264_encoder_encode(x264enc, &nals, &i_nals, nullptr, &x264picout); } else { frame_size = x264_encoder_encode(x264enc, &nals, &i_nals, &x264picin, &x264picout); } @@ -515,12 +515,12 @@ int ParseEncoderParameters( const char* str, std::vector* vec ) { - if ( vec == NULL ) { + if ( vec == nullptr ) { Error("NULL Encoder parameters vector pointer"); return -1; } - if ( str == NULL ) { + if ( str == nullptr ) { Error("NULL Encoder parameters string"); return -2; } diff --git a/src/zm_video.h b/src/zm_video.h index 46d7c3635..e185f82fc 100644 --- a/src/zm_video.h +++ b/src/zm_video.h @@ -81,7 +81,7 @@ public: virtual int Encode(const Image* img, const unsigned int frame_time) = 0; virtual int Open() = 0; virtual int Close() = 0; - virtual int Reset(const char* new_path = NULL); + virtual int Reset(const char* new_path = nullptr); const char* GetContainer() const { return container.c_str(); @@ -160,13 +160,13 @@ protected: public: - X264MP4Writer(const char* p_path, const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder, const std::vector* p_user_params = NULL); + X264MP4Writer(const char* p_path, const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder, const std::vector* p_user_params = nullptr); ~X264MP4Writer(); int Encode(const uint8_t* data, const size_t data_size, const unsigned int frame_time); int Encode(const Image* img, const unsigned int frame_time); int Open(); int Close(); - int Reset(const char* new_path = NULL); + int Reset(const char* new_path = nullptr); }; #endif // HAVE_LIBX264 && HAVE_LIBMP4V2 && HAVE_LIBAVUTIL && HAVE_LIBSWSCALE diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index a9361b675..514518e09 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -93,7 +93,7 @@ VideoStore::VideoStore( bool VideoStore::open() { Info("Opening video storage stream %s format: %s", filename, format); - int ret = avformat_alloc_output_context2(&oc, NULL, NULL, filename); + int ret = avformat_alloc_output_context2(&oc, nullptr, nullptr, filename); if ( ret < 0 ) { Warning( "Could not create video storage stream %s as no out ctx" @@ -103,7 +103,7 @@ bool VideoStore::open() { // Couldn't deduce format from filename, trying from format name if ( !oc ) { - avformat_alloc_output_context2(&oc, NULL, format, filename); + avformat_alloc_output_context2(&oc, nullptr, format, filename); if ( !oc ) { Error( "Could not create video storage stream %s as no out ctx" @@ -113,7 +113,7 @@ bool VideoStore::open() { } } // end if ! oc - AVDictionary *pmetadata = NULL; + AVDictionary *pmetadata = nullptr; ret = av_dict_set(&pmetadata, "title", "Zoneminder Security Recording", 0); if ( ret < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); @@ -152,8 +152,6 @@ bool VideoStore::open() { wanted_codec = AV_CODEC_ID_H264; } - //max_stream_index = video_out_stream->index; - // FIXME Should check that we are set to passthrough. Might be same codec, but want privacy overlays if ( video_in_ctx->codec_id == wanted_codec ) { // Copy params from instream to ctx @@ -298,6 +296,7 @@ bool VideoStore::open() { Error("Unable to create video out stream"); return false; } + max_stream_index = video_out_stream->index; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx); if ( ret < 0 ) { @@ -308,16 +307,16 @@ bool VideoStore::open() { avcodec_copy_context(video_out_stream->codec, video_out_ctx); #endif - converted_in_samples = NULL; - audio_out_codec = NULL; - audio_in_codec = NULL; - audio_in_ctx = NULL; - audio_out_stream = NULL; - in_frame = NULL; - out_frame = NULL; + converted_in_samples = nullptr; + audio_out_codec = nullptr; + audio_in_codec = nullptr; + audio_in_ctx = nullptr; + audio_out_stream = nullptr; + in_frame = nullptr; + out_frame = nullptr; #if defined(HAVE_LIBSWRESAMPLE) || defined(HAVE_LIBAVRESAMPLE) - resample_ctx = NULL; - fifo = NULL; + resample_ctx = nullptr; + fifo = nullptr; #endif video_first_pts = 0; video_first_dts = 0; @@ -352,11 +351,11 @@ bool VideoStore::open() { } #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - audio_out_stream = avformat_new_stream(oc, NULL); + audio_out_stream = avformat_new_stream(oc, nullptr); audio_out_ctx = avcodec_alloc_context3(audio_out_codec); if ( !audio_out_ctx ) { Error("could not allocate codec ctx for AAC"); - audio_out_stream = NULL; + audio_out_stream = nullptr; return false; } #else @@ -371,7 +370,7 @@ bool VideoStore::open() { } else { Debug(2, "Got AAC"); - audio_out_stream = avformat_new_stream(oc, NULL); + audio_out_stream = avformat_new_stream(oc, nullptr); if ( !audio_out_stream ) { Error("Could not allocate new stream"); return false; @@ -408,7 +407,7 @@ bool VideoStore::open() { if ( ret < 0 ) { Error("Unable to copy audio ctx %s", av_make_error_string(ret).c_str()); - audio_out_stream = NULL; + audio_out_stream = nullptr; return; } // end if audio_out_ctx->codec_tag = 0; @@ -442,7 +441,8 @@ bool VideoStore::open() { /* open the out file, if needed */ if ( !(out_format->flags & AVFMT_NOFILE) ) { - if ( (ret = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL) ) < 0 ) { + ret = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, nullptr, nullptr); + if ( ret < 0 ) { Error("Could not open out file '%s': %s", filename, av_make_error_string(ret).c_str()); return false; @@ -452,7 +452,7 @@ bool VideoStore::open() { zm_dump_stream_format(oc, 0, 0, 1); if ( audio_out_stream ) zm_dump_stream_format(oc, 1, 0, 1); - AVDictionary *opts = NULL; + AVDictionary *opts = nullptr; std::string option_string = monitor->GetEncoderOptions(); ret = av_dict_parse_string(&opts, option_string.c_str(), "=", ",\n", 0); @@ -460,7 +460,7 @@ bool VideoStore::open() { Warning("Could not parse ffmpeg output options '%s'", option_string.c_str()); } - const AVDictionaryEntry *movflags_entry = av_dict_get(opts, "movflags", NULL, AV_DICT_MATCH_CASE); + const AVDictionaryEntry *movflags_entry = av_dict_get(opts, "movflags", nullptr, AV_DICT_MATCH_CASE); if ( !movflags_entry ) { Debug(1, "setting movflags to frag_keyframe+empty_moov"); // av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); @@ -473,14 +473,14 @@ bool VideoStore::open() { } if ( (ret = avformat_write_header(oc, &opts)) < 0 ) { Warning("Unable to set movflags trying with defaults."); - ret = avformat_write_header(oc, NULL); + ret = avformat_write_header(oc, nullptr); } else if ( av_dict_count(opts) != 0 ) { Info("some options not used, turn on debugging for a list."); - AVDictionaryEntry *e = NULL; - while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { + AVDictionaryEntry *e = nullptr; + while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != nullptr ) { Debug(1, "Encoder Option %s=>%s", e->key, e->value); if ( !e->value ) { - av_dict_set(&opts, e->key, NULL, 0); + av_dict_set(&opts, e->key, nullptr, 0); } } } @@ -516,7 +516,7 @@ void VideoStore::flush_codecs() { while (1) { AVPacket pkt; // Without these we seg fault I don't know why. - pkt.data = NULL; + pkt.data = nullptr; pkt.size = 0; av_init_packet(&pkt); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) @@ -546,7 +546,7 @@ void VideoStore::flush_codecs() { // The codec queues data. We need to send a flush command and out // whatever we get. Failures are not fatal. AVPacket pkt; - pkt.data = NULL; + pkt.data = nullptr; pkt.size = 0; av_init_packet(&pkt); @@ -555,7 +555,7 @@ void VideoStore::flush_codecs() { * At the end of the file, we pass the remaining samples to * the encoder. */ while ( zm_resample_get_delay(resample_ctx, audio_out_ctx->sample_rate) ) { - zm_resample_audio(resample_ctx, NULL, out_frame); + zm_resample_audio(resample_ctx, nullptr, out_frame); if ( zm_add_samples_to_fifo(fifo, out_frame) ) { // Should probably set the frame size to what is reported FIXME @@ -595,8 +595,8 @@ void VideoStore::flush_codecs() { } // end while still data in the fifo #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - // Put encoder into flushing mode - avcodec_send_frame(audio_out_ctx, NULL); + // Put encoder into flushing mode + avcodec_send_frame(audio_out_ctx, nullptr); #endif while (1) { @@ -623,7 +623,7 @@ VideoStore::~VideoStore() { // Flush Queues Debug(1, "Flushing interleaved queues"); - av_interleaved_write_frame(oc, NULL); + av_interleaved_write_frame(oc, nullptr); Debug(1, "Writing trailer"); /* Write the trailer before close */ @@ -638,7 +638,7 @@ VideoStore::~VideoStore() { /* Close the out file. */ Debug(2, "Closing"); if ( int rc = avio_close(oc->pb) ) { - oc->pb = NULL; + oc->pb = nullptr; Error("Error closing avio %s", av_err2str(rc)); } } else { @@ -657,24 +657,24 @@ VideoStore::~VideoStore() { // We allocate and copy in newer ffmpeg, so need to free it //avcodec_free_context(&video_in_ctx); #endif - video_in_ctx = NULL; + video_in_ctx = nullptr; if ( video_out_codec ) { avcodec_close(video_out_ctx); Debug(4, "Success closing video_out_ctx"); - video_out_codec = NULL; + video_out_codec = nullptr; } // end if video_out_codec #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) avcodec_free_context(&video_out_ctx); #endif - video_out_ctx = NULL; + video_out_ctx = nullptr; } // end if video_out_stream if ( audio_out_stream ) { if ( audio_in_codec ) { avcodec_close(audio_in_ctx); Debug(4, "Success closing audio_in_ctx"); - audio_in_codec = NULL; + audio_in_codec = nullptr; } // end if audio_in_codec #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) @@ -682,7 +682,7 @@ VideoStore::~VideoStore() { avcodec_free_context(&audio_in_ctx); #endif Debug(4, "Success freeing audio_in_ctx"); - audio_in_ctx = NULL; + audio_in_ctx = nullptr; if ( audio_out_ctx ) { avcodec_close(audio_out_ctx); @@ -691,13 +691,13 @@ VideoStore::~VideoStore() { avcodec_free_context(&audio_out_ctx); #endif } - audio_out_ctx = NULL; + audio_out_ctx = nullptr; #if defined(HAVE_LIBAVRESAMPLE) || defined(HAVE_LIBSWRESAMPLE) if ( resample_ctx ) { if ( fifo ) { av_audio_fifo_free(fifo); - fifo = NULL; + fifo = nullptr; } #if defined(HAVE_LIBSWRESAMPLE) swr_free(&resample_ctx); @@ -710,15 +710,15 @@ VideoStore::~VideoStore() { } if ( in_frame ) { av_frame_free(&in_frame); - in_frame = NULL; + in_frame = nullptr; } if ( out_frame ) { av_frame_free(&out_frame); - out_frame = NULL; + out_frame = nullptr; } if ( converted_in_samples ) { av_free(converted_in_samples); - converted_in_samples = NULL; + converted_in_samples = nullptr; } #endif } // end if audio_out_stream @@ -775,7 +775,7 @@ bool VideoStore::setup_resampler() { #endif // if the codec is already open, nothing is done. - if ( (ret = avcodec_open2(audio_in_ctx, audio_in_codec, NULL)) < 0 ) { + if ( (ret = avcodec_open2(audio_in_ctx, audio_in_codec, nullptr)) < 0 ) { Error("Can't open audio in codec!"); return false; } @@ -834,7 +834,7 @@ bool VideoStore::setup_resampler() { // Example code doesn't set the codec tb. I think it just uses whatever defaults //audio_out_ctx->time_base = (AVRational){1, audio_out_ctx->sample_rate}; - AVDictionary *opts = NULL; + AVDictionary *opts = nullptr; // Needed to allow AAC if ( (ret = av_dict_set(&opts, "strict", "experimental", 0)) < 0 ) { Error("Couldn't set experimental"); @@ -844,9 +844,9 @@ bool VideoStore::setup_resampler() { if ( ret < 0 ) { Error("could not open codec (%d) (%s)", ret, av_make_error_string(ret).c_str()); - audio_out_codec = NULL; - audio_out_ctx = NULL; - audio_out_stream = NULL; + audio_out_codec = nullptr; + audio_out_ctx = nullptr; + audio_out_stream = nullptr; return false; } zm_dump_codec(audio_out_ctx); @@ -922,14 +922,14 @@ bool VideoStore::setup_resampler() { return false; } #if defined(HAVE_LIBSWRESAMPLE) - resample_ctx = swr_alloc_set_opts(NULL, + resample_ctx = swr_alloc_set_opts(nullptr, audio_out_ctx->channel_layout, audio_out_ctx->sample_fmt, audio_out_ctx->sample_rate, audio_in_ctx->channel_layout, audio_in_ctx->sample_fmt, audio_in_ctx->sample_rate, - 0, NULL); + 0, nullptr); if ( !resample_ctx ) { Error("Could not allocate resample context"); av_frame_free(&in_frame); @@ -993,7 +993,7 @@ bool VideoStore::setup_resampler() { // The codec gives us the frame size, in samples, we calculate the size of the // samples buffer in bytes unsigned int audioSampleBuffer_size = av_samples_get_buffer_size( - NULL, audio_out_ctx->channels, + nullptr, audio_out_ctx->channels, audio_out_ctx->frame_size, audio_out_ctx->sample_fmt, 0); converted_in_samples = reinterpret_cast(av_malloc(audioSampleBuffer_size)); @@ -1295,7 +1295,7 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { if ( zm_resample_get_delay(resample_ctx, out_frame->sample_rate) < out_frame->nb_samples) break; // This will send a null frame, emptying out the resample buffer - input_frame = NULL; + input_frame = nullptr; } // end while there is data in the resampler } else { diff --git a/src/zm_zone.cpp b/src/zm_zone.cpp index c7db7e3da..de2964283 100644 --- a/src/zm_zone.cpp +++ b/src/zm_zone.cpp @@ -83,7 +83,7 @@ void Zone::Setup( alarm_blobs = 0; min_blob_size = 0; max_blob_size = 0; - image = 0; + image = nullptr; score = 0; overload_count = 0; @@ -136,7 +136,7 @@ void Zone::RecordStats(const Event *event) { db_mutex.lock(); snprintf(sql, sizeof(sql), "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 + monitor->Id(), id, event->Id(), event->Frames(), 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)); @@ -247,7 +247,7 @@ bool Zone::CheckAlarms(const Image *delta_image) { if ( config.record_diag_images_fifo ) { FifoDebug(5, "{\"zone\":%d,\"type\":\"ALRM\",\"pixels\":%d,\"avg_diff\":%d}", - id,alarm_pixels, pixel_diff); + id, alarm_pixels, pixel_diff); } if ( alarm_pixels ) { @@ -264,11 +264,7 @@ bool Zone::CheckAlarms(const Image *delta_image) { return false; } - if ( max_alarm_pixels != 0 ) - score = (100*alarm_pixels)/max_alarm_pixels; - else - score = (100*alarm_pixels)/polygon.Area(); - + score = (100*alarm_pixels)/(max_alarm_pixels?max_alarm_pixels:polygon.Area()); if ( score < 1 ) 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); @@ -358,8 +354,7 @@ bool Zone::CheckAlarms(const Image *delta_image) { if ( check_method >= BLOBS ) { 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; - BlobStats blob_stats[256]; + // ICON FIXME Would like to get rid of this memset memset(blob_stats, 0, sizeof(BlobStats)*256); uint8_t *spdiff; uint8_t last_x, last_y; @@ -369,22 +364,15 @@ bool Zone::CheckAlarms(const Image *delta_image) { int lo_x = ranges[y].lo_x; int hi_x = ranges[y].hi_x; - 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++ ) { if ( *pdiff == WHITE ) { Debug(9, "Got white pixel at %d,%d (%p)", x, y, pdiff); - //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_x = 0; - if ( x > 0 ) { - if ( (x-1) >= lo_x ) { - last_x = *(pdiff-1); - } - } + last_x = ((x > 0) && ( (x-1) >= lo_x )) ? *(pdiff-1) : 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 ) { last_y = *(pdiff-diff_width); } @@ -631,7 +619,7 @@ bool Zone::CheckAlarms(const Image *delta_image) { } if ( max_blob_pixels != 0 ) - score = (100*alarm_blob_pixels)/(max_blob_pixels); + score = (100*alarm_blob_pixels)/max_blob_pixels; else score = (100*alarm_blob_pixels)/polygon.Area(); @@ -758,67 +746,42 @@ bool Zone::CheckAlarms(const Image *delta_image) { } bool Zone::ParsePolygonString(const char *poly_string, Polygon &polygon) { - Debug(3, "Parsing polygon string '%s'", poly_string); - - char *str_ptr = new char[strlen(poly_string)+1]; - char *str = str_ptr; - strcpy(str, poly_string); + char *str = (char *)poly_string; char *ws; + char *cp; int n_coords = 0; int max_n_coords = strlen(str)/4; Coord *coords = new Coord[max_n_coords]; - while( true ) { - if ( *str == '\0' ) { - break; - } - ws = strchr(str, ' '); - if ( ws ) { - *ws = '\0'; - } - char *cp = strchr(str, ','); + while ( *str != '\0' ) { + cp = strchr(str, ','); if ( !cp ) { Error("Bogus coordinate %s found in polygon string", str); - delete[] coords; - delete[] str_ptr; - return false; - } else { - *cp = '\0'; - char *xp = str; - char *yp = cp+1; + break; + } + int x = atoi(str); + int y = atoi(cp+1); + Debug(3, "Got coordinate %d,%d from polygon string", x, y); + coords[n_coords++] = Coord(x, y); - int x = atoi(xp); - int y = atoi(yp); - - Debug(3, "Got coordinate %d,%d from polygon string", x, y); -#if 0 - if ( x < 0 ) - x = 0; - else if ( x >= width ) - x = width-1; - if ( y < 0 ) - y = 0; - else if ( y >= height ) - y = height-1; -#endif - coords[n_coords++] = Coord( x, y ); - } + ws = strchr(cp+2, ' '); if ( ws ) str = ws+1; else break; - } - polygon = Polygon(n_coords, coords); + } // end while ! end of string - Debug(3, "Successfully parsed polygon string"); - //printf( "Area: %d\n", pg.Area() ); - //printf( "Centre: %d,%d\n", pg.Centre().X(), pg.Centre().Y() ); + if ( n_coords > 2 ) { + Debug(3, "Successfully parsed polygon string %s", str); + polygon = Polygon(n_coords, coords); + } else { + Error("Not enough coordinates to form a polygon!"); + n_coords = 0; + } delete[] coords; - delete[] str_ptr; - - return true; -} + return n_coords ? true : false; +} // end bool Zone::ParsePolygonString(const char *poly_string, Polygon &polygon) bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, Polygon &polygon) { Debug(3, "Parsing zone string '%s'", zone_string); @@ -827,13 +790,12 @@ bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, P char *str = str_ptr; strcpy(str, zone_string); + zone_id = strtol(str, 0, 10); + Debug(3, "Got zone %d from zone string", zone_id); + char *ws = strchr(str, ' '); if ( !ws ) { Debug(3, "No initial whitespace found in zone string '%s', finishing", str); - } - zone_id = strtol(str, 0, 10); - Debug(3, "Got zone %d from zone string", zone_id); - if ( !ws ) { delete[] str_ptr; return true; } @@ -841,13 +803,11 @@ bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, P *ws = '\0'; str = ws+1; + colour = strtol(str, 0, 16); + Debug(3, "Got colour %06x from zone string", colour); ws = strchr(str, ' '); if ( !ws ) { Debug(3, "No secondary whitespace found in zone string '%s', finishing", zone_string); - } - colour = strtol(str, 0, 16); - Debug(3, "Got colour %06x from zone string", colour); - if ( !ws ) { delete[] str_ptr; return true; } @@ -855,34 +815,33 @@ bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, P str = ws+1; bool result = ParsePolygonString(str, polygon); - - //printf( "Area: %d\n", pg.Area() ); - //printf( "Centre: %d,%d\n", pg.Centre().X(), pg.Centre().Y() ); - delete[] str_ptr; return result; -} +} // end bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, Polygon &polygon) int Zone::Load(Monitor *monitor, Zone **&zones) { static char sql[ZM_SQL_MED_BUFSIZ]; db_mutex.lock(); - 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()); + 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()); if ( mysql_query(&dbconn, sql) ) { 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(); if ( !result ) { Error("Can't use query result: %s", mysql_error(&dbconn)); - db_mutex.unlock(); return 0; } - db_mutex.unlock(); int n_zones = mysql_num_rows(result); Debug(1, "Got %d zones for monitor %s", n_zones, monitor->Name()); delete[] zones; @@ -945,7 +904,13 @@ int Zone::Load(Monitor *monitor, Zone **&zones) { } 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, 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 mysql_free_result(result); return n_zones; @@ -954,9 +919,9 @@ int Zone::Load(Monitor *monitor, Zone **&zones) { bool Zone::DumpSettings(char *output, bool /*verbose*/) { output[0] = 0; - sprintf( output+strlen(output), " Id : %d\n", id ); - sprintf( output+strlen(output), " Label : %s\n", label ); - sprintf( output+strlen(output), " Type: %d - %s\n", type, + sprintf(output+strlen(output), " Id : %d\n", id ); + sprintf(output+strlen(output), " Label : %s\n", label ); + sprintf(output+strlen(output), " Type: %d - %s\n", type, type==ACTIVE?"Active":( type==INCLUSIVE?"Inclusive":( type==EXCLUSIVE?"Exclusive":( @@ -1021,10 +986,10 @@ void Zone::std_alarmedpixels( *pdiff = BLACK; } } - } + } // end for y = lo_y to hi_y /* Store the results */ *pixel_count = pixelsalarmed; *pixel_sum = pixelsdifference; Debug(7, "STORED pixelsalarmed(%d), pixelsdifference(%d)", pixelsalarmed, pixelsdifference); -} +} // end void Zone::std_alarmedpixels(Image* pdiff_image, const Image* ppoly_image, unsigned int* pixel_count, unsigned int* pixel_sum) diff --git a/src/zm_zone.h b/src/zm_zone.h index 0c7b26a57..7d7797725 100644 --- a/src/zm_zone.h +++ b/src/zm_zone.h @@ -32,15 +32,14 @@ class Monitor; // This describes a 'zone', or an area of an image that has certain // detection characteristics. // -class Zone -{ +class Zone { protected: - struct Range - { + struct Range { int lo_x; int hi_x; int off_x; }; + typedef struct { unsigned char tag; int count; int lo_x; int hi_x; int lo_y; int hi_y; } BlobStats; public: typedef enum { ACTIVE=1, INCLUSIVE, EXCLUSIVE, PRECLUSIVE, INACTIVE, PRIVACY } ZoneType; @@ -52,8 +51,8 @@ protected: int id; char *label; - ZoneType type; - Polygon polygon; + ZoneType type; + Polygon polygon; Rgb alarm_rgb; CheckMethod check_method; @@ -67,17 +66,18 @@ protected: int min_filter_pixels; int max_filter_pixels; + BlobStats blob_stats[256]; int min_blob_pixels; int max_blob_pixels; int min_blobs; int max_blobs; - int overload_frames; + int overload_frames; int extend_alarm_frames; // Outputs/Statistics - bool alarmed; - bool was_alarmed; + bool alarmed; + bool was_alarmed; int pixel_diff; unsigned int alarm_pixels; int alarm_filter_pixels; @@ -139,8 +139,7 @@ public: inline Coord GetAlarmCentre() const { return( alarm_centre ); } inline unsigned int Score() const { return( score ); } - inline void ResetStats() - { + inline void ResetStats() { alarmed = false; was_alarmed = false; pixel_diff = 0; diff --git a/src/zma.cpp b/src/zma.cpp index a0cb048bf..edaf9c722 100644 --- a/src/zma.cpp +++ b/src/zma.cpp @@ -70,15 +70,15 @@ void Usage() { int main( int argc, char *argv[] ) { self = argv[0]; - srand(getpid() * time(0)); + srand(getpid() * time(nullptr)); int id = -1; static struct option long_options[] = { - {"monitor", 1, 0, 'm'}, - {"help", 0, 0, 'h'}, - {"version", 0, 0, 'v'}, - {0, 0, 0, 0} + {"monitor", 1, nullptr, 'm'}, + {"help", 0, nullptr, 'h'}, + {"version", 0, nullptr, 'v'}, + {nullptr, 0, nullptr, 0} }; while (1) { @@ -146,15 +146,15 @@ int main( int argc, char *argv[] ) { unsigned int analysis_update_delay = monitor->GetAnalysisUpdateDelay(); time_t last_analysis_update_time, cur_time; monitor->UpdateAdaptiveSkip(); - last_analysis_update_time = time(0); + last_analysis_update_time = time(nullptr); while( (!zm_terminate) && monitor->ShmValid() ) { // Process the next image - sigprocmask(SIG_BLOCK, &block_set, 0); + sigprocmask(SIG_BLOCK, &block_set, nullptr); // Some periodic updates are required for variable capturing framerate if ( analysis_update_delay ) { - cur_time = time(0); + cur_time = time(nullptr); if ( (unsigned int)( cur_time - last_analysis_update_time ) > analysis_update_delay ) { analysis_rate = monitor->GetAnalysisRate(); monitor->UpdateAdaptiveSkip(); @@ -174,7 +174,7 @@ int main( int argc, char *argv[] ) { logInit(log_id_string); zm_reload = false; } - sigprocmask(SIG_UNBLOCK, &block_set, 0); + sigprocmask(SIG_UNBLOCK, &block_set, nullptr); } // end while ! zm_terminate delete monitor; } else { diff --git a/src/zmc.cpp b/src/zmc.cpp index a08aff1f4..509183bb0 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -91,7 +91,7 @@ void Usage() { int main(int argc, char *argv[]) { self = argv[0]; - srand(getpid() * time(0)); + srand(getpid() * time(nullptr)); const char *device = ""; const char *protocol = ""; @@ -102,16 +102,16 @@ int main(int argc, char *argv[]) { int monitor_id = -1; static struct option long_options[] = { - {"device", 1, 0, 'd'}, - {"protocol", 1, 0, 'r'}, - {"host", 1, 0, 'H'}, - {"port", 1, 0, 'P'}, - {"path", 1, 0, 'p'}, - {"file", 1, 0, 'f'}, - {"monitor", 1, 0, 'm'}, - {"help", 0, 0, 'h'}, - {"version", 0, 0, 'v'}, - {0, 0, 0, 0} + {"device", 1, nullptr, 'd'}, + {"protocol", 1, nullptr, 'r'}, + {"host", 1, nullptr, 'H'}, + {"port", 1, nullptr, 'P'}, + {"path", 1, nullptr, 'p'}, + {"file", 1, nullptr, 'f'}, + {"monitor", 1, nullptr, 'm'}, + {"help", 0, nullptr, 'h'}, + {"version", 0, nullptr, 'v'}, + {nullptr, 0, nullptr, 0} }; while (1) { @@ -194,7 +194,7 @@ int main(int argc, char *argv[]) { hwcaps_detect(); - Monitor **monitors = 0; + Monitor **monitors = nullptr; int n_monitors = 0; #if ZM_HAS_V4L if ( device[0] ) { @@ -245,7 +245,7 @@ int main(int argc, char *argv[]) { } if ( ! monitors[i]->connect() ) { } - time_t now = (time_t)time(NULL); + time_t now = (time_t)time(nullptr); monitors[i]->setStartupTime(now); snprintf(sql, sizeof(sql), @@ -328,7 +328,7 @@ int main(int argc, char *argv[]) { break; } - gettimeofday(&now, NULL); + gettimeofday(&now, nullptr); // capture_delay is the amount of time we should sleep to achieve the desired framerate. int delay = monitors[i]->GetState() == Monitor::ALARM ? alarm_capture_delays[i] : capture_delays[i]; if ( delay && last_capture_times[i].tv_sec ) { diff --git a/src/zms.cpp b/src/zms.cpp index ad7076e7a..9b661c564 100644 --- a/src/zms.cpp +++ b/src/zms.cpp @@ -50,10 +50,10 @@ bool ValidateAccess(User *user, int mon_id) { return allowed; } -int main(int argc, const char *argv[]) { +int main(int argc, const char *argv[], char **envp) { self = argv[0]; - srand(getpid() * time(0)); + srand(getpid() * time(nullptr)); enum { ZMS_UNKNOWN, ZMS_MONITOR, ZMS_EVENT, ZMS_FIFO } source = ZMS_UNKNOWN; enum { ZMS_JPEG, ZMS_MPEG, ZMS_RAW, ZMS_ZIP, ZMS_SINGLE } mode = ZMS_JPEG; @@ -89,6 +89,10 @@ int main(int argc, const char *argv[]) { zmLoadConfig(); char log_id_string[32] = "zms"; logInit(log_id_string); + for (char **env = envp; *env != 0; env++) { + char *thisEnv = *env; + Debug(1, "env: %s", thisEnv); + } const char *query = getenv("QUERY_STRING"); if ( query ) { @@ -101,12 +105,12 @@ int main(int argc, const char *argv[]) { int parm_no = 0; while ( (parm_no < 16) && (parms[parm_no] = strtok(q_ptr, "&")) ) { parm_no++; - q_ptr = NULL; + q_ptr = nullptr; } for ( int p = 0; p < parm_no; p++ ) { char *name = strtok(parms[p], "="); - char const *value = strtok(NULL, "="); + char const *value = strtok(nullptr, "="); if ( !value ) value = ""; if ( !strcmp(name, "source") ) { @@ -127,10 +131,10 @@ int main(int argc, const char *argv[]) { } else if ( !strcmp(name, "time") ) { event_time = atoi(value); } else if ( !strcmp(name, "event") ) { - event_id = strtoull(value, NULL, 10); + event_id = strtoull(value, nullptr, 10); source = ZMS_EVENT; } else if ( !strcmp(name, "frame") ) { - frame_id = strtoull(value, NULL, 10); + frame_id = strtoull(value, nullptr, 10); source = ZMS_EVENT; } else if ( !strcmp(name, "scale") ) { scale = atoi(value); @@ -184,7 +188,7 @@ int main(int argc, const char *argv[]) { logInit(log_id_string); if ( config.opt_use_auth ) { - User *user = NULL; + User *user = nullptr; if ( jwt_token_str != "" ) { // user = zmLoadTokenUser(jwt_token_str, config.auth_hash_ips); @@ -204,34 +208,36 @@ int main(int argc, const char *argv[]) { } if ( !user ) { fputs("HTTP/1.0 403 Forbidden\r\n\r\n", stdout); - Error("Unable to authenticate user"); + + const char *referer = getenv("HTTP_REFERER"); + Error("Unable to authenticate user from %s", referer); logTerm(); zmDbClose(); return 0; } if ( !ValidateAccess(user, monitor_id) ) { delete user; - user = NULL; + user = nullptr; fputs("HTTP/1.0 403 Forbidden\r\n\r\n", stdout); logTerm(); zmDbClose(); return 0; } delete user; - user = NULL; + user = nullptr; } // end if config.opt_use_auth hwcaps_detect(); zmSetDefaultTermHandler(); zmSetDefaultDieHandler(); - setbuf(stdout, 0); + setbuf(stdout, nullptr); if ( nph ) { fputs("HTTP/1.0 200 OK\r\n", stdout); } fprintf(stdout, "Server: ZoneMinder Video Server/%s\r\n", ZM_VERSION); - time_t now = time(0); + time_t now = time(nullptr); char date_string[64]; strftime(date_string, sizeof(date_string)-1, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now)); @@ -253,14 +259,7 @@ int main(int argc, const char *argv[]) { stream.setStreamTTL(ttl); stream.setStreamQueue(connkey); stream.setStreamBuffer(playback_buffer); - if ( !stream.setStreamStart(monitor_id) ) { - Error("Unable to connect to zmc process for monitor %d", monitor_id); - fprintf(stderr, "Unable to connect to zmc process. " - " Please ensure that it is running."); - logTerm(); - zmDbClose(); - return -1; - } + stream.setStreamStart(monitor_id); if ( mode == ZMS_JPEG ) { stream.setStreamType(MonitorStream::STREAM_JPEG); diff --git a/src/zmu.cpp b/src/zmu.cpp index 412bc816c..bdc467812 100644 --- a/src/zmu.cpp +++ b/src/zmu.cpp @@ -211,45 +211,45 @@ int main(int argc, char *argv[]) { self = argv[0]; - srand(getpid() * time(0)); + srand(getpid() * time(nullptr)); static struct option long_options[] = { - {"device", 2, 0, 'd'}, - {"monitor", 1, 0, 'm'}, - {"verbose", 0, 0, 'v'}, - {"image", 2, 0, 'i'}, - {"scale", 1, 0, 'S'}, - {"timestamp", 2, 0, 't'}, - {"state", 0, 0, 's'}, - {"brightness", 2, 0, 'B'}, - {"contrast", 2, 0, 'C'}, - {"hue", 2, 0, 'H'}, - {"contrast", 2, 0, 'O'}, - {"read_index", 0, 0, 'R'}, - {"write_index", 0, 0, 'W'}, - {"event", 0, 0, 'e'}, - {"fps", 0, 0, 'f'}, - {"zones", 2, 0, 'z'}, - {"alarm", 0, 0, 'a'}, - {"noalarm", 0, 0, 'n'}, - {"cancel", 0, 0, 'c'}, - {"reload", 0, 0, 'L'}, - {"enable", 0, 0, 'E'}, - {"disable", 0, 0, 'D'}, - {"suspend", 0, 0, 'u'}, - {"resume", 0, 0, 'r'}, - {"query", 0, 0, 'q'}, - {"username", 1, 0, 'U'}, - {"password", 1, 0, 'P'}, - {"auth", 1, 0, 'A'}, - {"token", 1, 0, 'T'}, - {"version", 1, 0, 'V'}, - {"help", 0, 0, 'h'}, - {"list", 0, 0, 'l'}, - {0, 0, 0, 0} + {"device", 2, nullptr, 'd'}, + {"monitor", 1, nullptr, 'm'}, + {"verbose", 0, nullptr, 'v'}, + {"image", 2, nullptr, 'i'}, + {"scale", 1, nullptr, 'S'}, + {"timestamp", 2, nullptr, 't'}, + {"state", 0, nullptr, 's'}, + {"brightness", 2, nullptr, 'B'}, + {"contrast", 2, nullptr, 'C'}, + {"hue", 2, nullptr, 'H'}, + {"contrast", 2, nullptr, 'O'}, + {"read_index", 0, nullptr, 'R'}, + {"write_index", 0, nullptr, 'W'}, + {"event", 0, nullptr, 'e'}, + {"fps", 0, nullptr, 'f'}, + {"zones", 2, nullptr, 'z'}, + {"alarm", 0, nullptr, 'a'}, + {"noalarm", 0, nullptr, 'n'}, + {"cancel", 0, nullptr, 'c'}, + {"reload", 0, nullptr, 'L'}, + {"enable", 0, nullptr, 'E'}, + {"disable", 0, nullptr, 'D'}, + {"suspend", 0, nullptr, 'u'}, + {"resume", 0, nullptr, 'r'}, + {"query", 0, nullptr, 'q'}, + {"username", 1, nullptr, 'U'}, + {"password", 1, nullptr, 'P'}, + {"auth", 1, nullptr, 'A'}, + {"token", 1, nullptr, 'T'}, + {"version", 1, nullptr, 'V'}, + {"help", 0, nullptr, 'h'}, + {"list", 0, nullptr, 'l'}, + {nullptr, 0, nullptr, 0} }; - const char *device = 0; + const char *device = nullptr; int mon_id = 0; bool verbose = false; int function = ZMU_BOGUS; @@ -260,10 +260,10 @@ int main(int argc, char *argv[]) { int contrast = -1; int hue = -1; int colour = -1; - char *zoneString = 0; - char *username = 0; - char *password = 0; - char *auth = 0; + char *zoneString = nullptr; + char *username = nullptr; + char *password = nullptr; + char *auth = nullptr; std::string jwt_token_str = ""; #if ZM_HAS_V4L #if ZM_HAS_V4L2 @@ -487,7 +487,7 @@ int main(int argc, char *argv[]) { if ( !monitor->connect() ) { Error("Can't connect to capture daemon: %d %s", monitor->Id(), monitor->Name()); delete monitor; - monitor = NULL; + monitor = nullptr; exit_zmu(-1); } @@ -701,7 +701,7 @@ int main(int argc, char *argv[]) { Usage(); } delete monitor; - monitor = NULL; + monitor = nullptr; } else { // non monitor functions if ( function & ZMU_QUERY ) { #if ZM_HAS_V4L diff --git a/utils/do_debian_package.sh b/utils/do_debian_package.sh index f09b879fd..d6107c5a9 100755 --- a/utils/do_debian_package.sh +++ b/utils/do_debian_package.sh @@ -80,7 +80,7 @@ fi; if [ "$DISTROS" == "" ]; then if [ "$RELEASE" != "" ]; then - DISTROS="xenial,bionic,eoan,focal" + DISTROS="xenial,bionic,focal" else DISTROS=`lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'`; fi; @@ -156,10 +156,14 @@ if [ ! -d "${GITHUB_FORK}_zoneminder_release" ]; then if [ -d "${GITHUB_FORK}_ZoneMinder.git" ]; then echo "Using local clone ${GITHUB_FORK}_ZoneMinder.git to pull from." cd "${GITHUB_FORK}_ZoneMinder.git" - echo "git pull..." - git pull + echo "git fetch..." + git fetch echo "git checkout $BRANCH" git checkout $BRANCH + if [ $? -ne 0 ]; then + echo "Failed to switch to branch." + exit 1; + fi; echo "git pull..." git pull cd ../ @@ -227,12 +231,11 @@ IFS=',' ;for DISTRO in `echo "$DISTROS"`; do # Generate Changlog if [ "$DISTRO" == "focal" ] || [ "$DISTRO" == "buster" ]; then cp -Rpd distros/ubuntu2004 debian - else - if [ "$DISTRO" == "wheezy" ]; then - cp -Rpd distros/debian debian - else - cp -Rpd distros/ubuntu1604 debian - fi; + elif [ "$DISTRO" == "beowulf" ] + then + cp -Rpd distros/beowulf debian + else + cp -Rpd distros/ubuntu1604 debian fi; if [ "$DEBEMAIL" != "" ] && [ "$DEBFULLNAME" != "" ]; then @@ -336,7 +339,7 @@ EOF dput="Y"; if [ "$INTERACTIVE" != "no" ]; then - read -p "Ready to dput $SC to $PPA ? Y/N..."; + read -p "Ready to dput $SC to $PPA ? Y/n..."; if [[ "$REPLY" == [yY] ]]; then dput $PPA $SC fi; diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index 6a51e2995..1b2eafd8f 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -1,4 +1,7 @@ #!/bin/bash + +set -o pipefail + # packpack setup file for the ZoneMinder project # Written by Andrew Bauer @@ -250,6 +253,13 @@ execpackpack () { else packpack/packpack $parms fi + + if [ $? -ne 0 ]; then + echo + echo "ERROR: An error occurred while executing packpack." + echo + exit 1 + fi } # Check for connectivity with the deploy target host @@ -337,10 +347,10 @@ elif [ "${OS}" == "debian" ] || [ "${OS}" == "ubuntu" ] || [ "${OS}" == "raspbia setdebpkgname movecrud - if [ "${DIST}" == "trusty" ] || [ "${DIST}" == "precise" ]; then - ln -sfT distros/ubuntu1204 debian - elif [ "${DIST}" == "wheezy" ]; then - ln -sfT distros/debian debian + if [ "${DIST}" == "focal" ] || [ "${DIST}" == "buster" ]; then + ln -sfT distros/ubuntu2004 debian + elif [ "${DIST}" == "beowulf" ]; then + ln -sfT distros/beowulf debian else ln -sfT distros/ubuntu1604 debian fi @@ -351,7 +361,7 @@ elif [ "${OS}" == "debian" ] || [ "${OS}" == "ubuntu" ] || [ "${OS}" == "raspbia execpackpack # Try to install and run the newly built zoneminder package - if [ "${OS}" == "ubuntu" ] && [ "${DIST}" == "xenial" ] && [ "${ARCH}" == "x86_64" ] && [ "${TRAVIS}" == "true" ]; then + if [ "${OS}" == "ubuntu" ] && [ "${DIST}" == "bionic" ] && [ "${ARCH}" == "x86_64" ] && [ "${TRAVIS}" == "true" ]; then echo "Begin Deb package installation..." install_deb fi diff --git a/utils/resample_event_video.sh b/utils/resample_event_video.sh new file mode 100755 index 000000000..845216cc0 --- /dev/null +++ b/utils/resample_event_video.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +FFMPEG=`which ffmpeg`; + +if [ -z "$FFMPEG" ]; then + echo "You must install the ffmpeg package. Try sudo apt-get install ffmpeg"; + exit; +fi + +for i in "$@" +do +case $i in + -r=*|--rate=*) + FPS="${i#*=}" + shift + ;; + -f=*|--file=*) + VIDEO_FILE="${i#*=}" + shift + ;; + + *) + EVENT_PATH="${i#*=}" + shift + ;; +esac +done + +if [ -z "$EVENT_PATH" ]; then + echo "You must specify the path to the event."; + exit 255 +fi; + +if [ -z "$FPS" ]; then + echo "You must specify the new fps."; + exit 255 +fi; + +$FFMPEG -i "$EVENT_PATH/$VIDEO_FILE" -filter:v fps=fps=$FPS "$EVENT_PATH/output.mp4" +echo $? +if [ $? -eq 0 ]; then + mv "$EVENT_PATH/output.mp4" "$EVENT_PATH/$VIDEO_FILE" +fi; + +exit 0; diff --git a/utils/travis/bootstrap-zm.sh b/utils/travis/bootstrap-zm.sh deleted file mode 100644 index 397a8f90e..000000000 --- a/utils/travis/bootstrap-zm.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -x - -set -e -set -o pipefail -set -x - -with_timestamps() { - while read -r line; do - echo -e "$(date +%T)\t$line"; - done -} - - -bootstrap_zm() { - - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then libtoolize --force; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then aclocal; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then autoheader; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then automake --force-missing --add-missing; fi - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then autoconf; fi - - mysql -uroot -e "CREATE DATABASE IF NOT EXISTS zm" - mysql -uroot -e "GRANT ALL ON zm.* TO 'zmuser'@'localhost' IDENTIFIED BY 'zmpass'"; - mysql -uroot -e "FLUSH PRIVILEGES" - mysql -uzmuser -pzmpass < ${TRAVIS_BUILD_DIR}/db/zm_create.sql - -} - -bootstrap_zm | with_timestamps diff --git a/utils/travis/build-zm.sh b/utils/travis/build-zm.sh deleted file mode 100644 index 2d758f61b..000000000 --- a/utils/travis/build-zm.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -set -e -set -o pipefail - -with_timestamps() { - while read -r line; do - echo -e "$(date +%T)\t$line"; - done -} - -cd $TRAVIS_BUILD_DIR - -build_zm() { - - if [ "$ZM_BUILDMETHOD" = "autotools" ]; then - ./configure --prefix=/usr --with-libarch=lib/$DEB_HOST_GNU_TYPE --host=$DEB_HOST_GNU_TYPE --build=$DEB_BUILD_GNU_TYPE --with-mysql=/usr --with-ffmpeg=/usr --with-webdir=/usr/share/zoneminder/www --with-cgidir=/usr/libexec/zoneminder/cgi-bin --with-webuser=www-data --with-webgroup=www-data --enable-crashtrace=yes --disable-debug --enable-mmap=yes ZM_SSL_LIB=openssl - fi - - if [ "$ZM_BUILDMETHOD" = "cmake" ]; then - cmake -DCMAKE_INSTALL_PREFIX="/usr" - fi - - make - sudo make install - - if [ "$ZM_BUILDMETHOD" = "cmake" ]; then - sudo ./zmlinkcontent.sh - fi - -} - -build_zm | with_timestamps diff --git a/utils/travis/install-deps.sh b/utils/travis/install-deps.sh deleted file mode 100644 index d7981cb5a..000000000 --- a/utils/travis/install-deps.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -set -e -set -o pipefail - -with_timestamps() { - while read -r line; do - echo -e "$(date +%T)\t$line"; - done -} - - -install_deps() { - - sudo apt-get update -qq - sudo apt-get install -y -qq zlib1g-dev apache2 mysql-server php5 php5-mysql build-essential libmysqlclient-dev libssl-dev libbz2-dev libpcre3-dev libdbi-perl libarchive-zip-perl libdate-manip-perl libdevice-serialport-perl libmime-perl libwww-perl libdbd-mysql-perl libsys-mmap-perl yasm automake autoconf cmake libjpeg-turbo8-dev apache2-mpm-prefork libapache2-mod-php5 php5-cli libtheora-dev libvorbis-dev libvpx-dev libx264-dev 2>&1 > /dev/null - -} - -install_deps | with_timestamps diff --git a/utils/travis/install-ffmpeg.sh b/utils/travis/install-ffmpeg.sh deleted file mode 100644 index c2a2e9733..000000000 --- a/utils/travis/install-ffmpeg.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -set -e - - -git clone --depth=10 --branch=master git://source.ffmpeg.org/ffmpeg.git -cd ffmpeg -./configure --enable-shared --enable-swscale --enable-gpl --enable-libx264 --enable-libvpx --enable-libvorbis --enable-libtheora -make -j `grep processor /proc/cpuinfo|wc -l` -sudo make install -sudo make install-libs diff --git a/utils/travis/run-tests.sh b/utils/travis/run-tests.sh deleted file mode 100644 index c3bb392d9..000000000 --- a/utils/travis/run-tests.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -set -e -set -o pipefail - -with_timestamps() { - while read -r line; do - echo -e "$(date +%T)\t$line"; - done -} - -run_tests() { - mysql -uzmuser -pzmpass zm < ../../db/test.monitor.sql - sudo zmu -l - sudo zmc -m1 & - sudo zma -m1 & - sudo zmu -l - sudo grep ERR /var/log/syslog - sudo zmpkg.pl start - sudo zmfilter.pl -f purgewhenfull -} - -run_tests | with_timestamps diff --git a/version b/version index 00bedd170..21cbe96c2 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.35.5 +1.35.6 diff --git a/web/ajax/events.php b/web/ajax/events.php new file mode 100644 index 000000000..16c777ebf --- /dev/null +++ b/web/ajax/events.php @@ -0,0 +1,41 @@ +Id() ) { + $message[] = array($eid=>'Event not found.'); + } else if ( $event->Archived() ) { + $message[] = array($eid=>'Event is archived, cannot delete it.'); + } else { + $event->delete(); + } + break; + } // end switch action + } // end foreach + ajaxResponse($message); +} // end if canEdit('Events') + +ajaxError('Unrecognised action '.$_REQUEST['action'].' or insufficient permissions for user '.$user['Username']); +?> diff --git a/web/ajax/log.php b/web/ajax/log.php index d5483b7ca..16f7ac573 100644 --- a/web/ajax/log.php +++ b/web/ajax/log.php @@ -185,7 +185,7 @@ switch ( $_REQUEST['task'] ) { $Servers = ZM\Server::find(); $servers_by_Id = array(); # There is probably a better way to do this. - foreach ( $servers as $server ) { + foreach ( $Servers as $server ) { $servers_by_Id[$server->Id()] = $server; } @@ -245,6 +245,9 @@ switch ( $_REQUEST['task'] ) { } $exportKey = substr(md5(rand()), 0, 8); $exportFile = 'zm-log.'.$exportExt; + + // mkdir will generate a warning if it exists, but that is ok + error_reporting(0); if ( ! ( mkdir(ZM_DIR_EXPORTS) || file_exists(ZM_DIR_EXPORTS) ) ) { ZM\Fatal('Can\'t create exports dir at \''.ZM_DIR_EXPORTS.'\''); } @@ -371,8 +374,16 @@ switch ( $_REQUEST['task'] ) { <'.strtolower($field).'>'.htmlspecialchars($value).' ' ); fwrite( $exportFP, - ' - '.translate('DateTime').''.translate('Component').''.translate('Pid').''.translate('Level').''.translate('Message').''.translate('File').''.translate('Line').' + ' + + '.translate('DateTime').' + '.translate('Component').' + '.translate('Server').' + '.translate('Pid').' + '.translate('Level').' + '.translate('Message').' + '.translate('File').' + '.translate('Line').' ' ); diff --git a/web/ajax/modal.php b/web/ajax/modal.php new file mode 100644 index 000000000..bd96b137f --- /dev/null +++ b/web/ajax/modal.php @@ -0,0 +1,24 @@ + diff --git a/web/ajax/modals/delconfirm.php b/web/ajax/modals/delconfirm.php new file mode 100644 index 000000000..9aec739f4 --- /dev/null +++ b/web/ajax/modals/delconfirm.php @@ -0,0 +1,24 @@ + + + diff --git a/web/skins/classic/views/donate.php b/web/ajax/modals/donate.php similarity index 56% rename from web/skins/classic/views/donate.php rename to web/ajax/modals/donate.php index 6cf873bd4..374d4e0d2 100644 --- a/web/skins/classic/views/donate.php +++ b/web/ajax/modals/donate.php @@ -18,10 +18,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // -if ( !canEdit('System') ) { - $view = 'error'; - return; -} +if ( !canEdit('System') ) return; $options = array( 'go' => translate('DonateYes'), @@ -33,18 +30,23 @@ $options = array( 'already' => translate('DonateAlready'), ); -$focusWindow = true; - -xhtmlHeaders(__FILE__, translate('Donate')); ?> - -
- -
-
+ +
+ diff --git a/web/ajax/modals/enoperm.php b/web/ajax/modals/enoperm.php new file mode 100644 index 000000000..6fd2fbe23 --- /dev/null +++ b/web/ajax/modals/enoperm.php @@ -0,0 +1,24 @@ + + + diff --git a/web/ajax/modals/eventdetail.php b/web/ajax/modals/eventdetail.php new file mode 100644 index 000000000..bb2f53ecc --- /dev/null +++ b/web/ajax/modals/eventdetail.php @@ -0,0 +1,89 @@ +'; + $newEvent = dbFetchOne('SELECT E.* FROM Events AS E WHERE E.Id = ?', NULL, array($eid)); + +} elseif ( $eids ) { // Multi Event Mode + + $title = translate('Events'); + $sql = 'SELECT E.* FROM Events AS E WHERE '; + $sqlWhere = array(); + $sqlValues = array(); + foreach ( $eids as $eid ) { + $eid = validInt($eid); + $inputs .= ''; + $sqlWhere[] = 'E.Id = ?'; + $sqlValues[] = $eid; + } + unset($eid); + $sql .= join(' OR ', $sqlWhere); + foreach( dbFetchAll( $sql, NULL, $sqlValues ) as $row ) { + if ( !isset($newEvent) ) { + $newEvent = $row; + } else { + if ( $newEvent['Cause'] && $newEvent['Cause'] != $row['Cause'] ) + $newEvent['Cause'] = ''; + if ( $newEvent['Notes'] && $newEvent['Notes'] != $row['Notes'] ) + $newEvent['Notes'] = ''; + } + } + +} else { // Event Mode not specified - should we really proceed if neither eid nor eids is set? + $title = translate('Events'); +} + +?> + + diff --git a/web/ajax/modals/filterdebug.php b/web/ajax/modals/filterdebug.php new file mode 100644 index 000000000..725539a99 --- /dev/null +++ b/web/ajax/modals/filterdebug.php @@ -0,0 +1,35 @@ + diff --git a/web/ajax/modals/function.php b/web/ajax/modals/function.php new file mode 100644 index 000000000..e6bab2718 --- /dev/null +++ b/web/ajax/modals/function.php @@ -0,0 +1,53 @@ + + diff --git a/web/ajax/modals/log_export.php b/web/ajax/modals/log_export.php new file mode 100644 index 000000000..8f359bb86 --- /dev/null +++ b/web/ajax/modals/log_export.php @@ -0,0 +1,46 @@ +
- + @@ -476,6 +490,7 @@ if ( canEdit('Events') ) { } } ?> +
diff --git a/web/skins/classic/views/frame.php b/web/skins/classic/views/frame.php index c40b393d7..dc9ef9c4f 100644 --- a/web/skins/classic/views/frame.php +++ b/web/skins/classic/views/frame.php @@ -85,22 +85,26 @@ $focusWindow = true; xhtmlHeaders(__FILE__, translate('Frame').' - '.$Event->Id().' - '.$Frame->FrameId()); ?> -
- - - + diff --git a/web/skins/classic/views/js/console.js b/web/skins/classic/views/js/console.js index ede1d9e33..47201689d 100644 --- a/web/skins/classic/views/js/console.js +++ b/web/skins/classic/views/js/console.js @@ -1,11 +1,28 @@ +function thumbnail_onmouseover(event) { + var img = event.target; + img.src = ''; + img.src = img.getAttribute('stream_src'); +} + +function thumbnail_onmouseout(event) { + var img = event.target; + img.src = ''; + img.src = img.getAttribute('still_src'); +} + +function initThumbAnimation() { + $j('.colThumbnail img').each(function() { + this.addEventListener('mouseover', thumbnail_onmouseover, false); + this.addEventListener('mouseout', thumbnail_onmouseout, false); + }); +} function setButtonStates( element ) { var form = element.form; var checked = 0; for ( var i=0; i < form.elements.length; i++ ) { if ( - form.elements[i].type=="checkbox" - && + form.elements[i].type=="checkbox" && form.elements[i].name=="markMids[]" ) { var tr = $j(form.elements[i]).closest("tr"); @@ -35,7 +52,7 @@ function setButtonStates( element ) { } function addMonitor(element) { - createPopup( '?view=monitor', 'zmMonitor0', 'monitor' ); + window.location.assign('?view=monitor'); } function cloneMonitor(element) { @@ -44,10 +61,8 @@ function cloneMonitor(element) { // get the value of the first checkbox for ( var i = 0; i < form.elements.length; i++ ) { if ( - form.elements[i].type == "checkbox" - && - form.elements[i].name == "markMids[]" - && + form.elements[i].type == "checkbox" && + form.elements[i].name == "markMids[]" && form.elements[i].checked ) { monitorId = form.elements[i].value; @@ -55,7 +70,7 @@ function cloneMonitor(element) { } } // end foreach element if ( monitorId != -1 ) { - createPopup( '?view=monitor&dupId='+monitorId, 'zmMonitor0', 'monitor' ); + window.location.assign('?view=monitor&dupId='+monitorId); } } @@ -65,10 +80,8 @@ function editMonitor( element ) { for ( var i = 0; i < form.elements.length; i++ ) { if ( - form.elements[i].type == "checkbox" - && - form.elements[i].name == "markMids[]" - && + form.elements[i].type == "checkbox" && + form.elements[i].name == "markMids[]" && form.elements[i].checked ) { monitorIds.push( form.elements[i].value ); @@ -79,11 +92,11 @@ function editMonitor( element ) { } } // end foreach checkboxes if ( monitorIds.length == 1 ) { - createPopup( '?view=monitor&mid='+monitorIds[0], 'zmMonitor'+monitorIds[0], 'monitor' ); + window.location.assign('?view=monitor&mid='+monitorIds[0]); } else if ( monitorIds.length > 1 ) { - createPopup( '?view=monitors&'+(monitorIds.map(function(mid) { + window.location.assign( '?view=monitors&'+(monitorIds.map(function(mid) { return 'mids[]='+mid; - }).join('&')), 'zmMonitors', 'monitors' ); + }).join('&'))); } } @@ -100,10 +113,8 @@ function selectMonitor(element) { var url = thisUrl+'?view=console'; for ( var i = 0; i < form.elements.length; i++ ) { if ( - form.elements[i].type == 'checkbox' - && - form.elements[i].name == 'markMids[]' - && + form.elements[i].type == 'checkbox' && + form.elements[i].name == 'markMids[]' && form.elements[i].checked ) { url += '&MonitorId[]='+form.elements[i].value; @@ -116,13 +127,68 @@ function reloadWindow() { window.location.replace( thisUrl ); } +// Manage the the Function modal and its buttons +function manageFunctionModal() { + $j('.functionLnk').click(function(evt) { + evt.preventDefault(); + if ( !canEditEvents ) { + enoperm(); + return; + } + var mid = evt.currentTarget.getAttribute('data-mid'); + monitor = monitors[mid]; + if ( !monitor ) { + console.error("No monitor found for mid " + mid); + return; + } + + var function_form = document.getElementById('function_form'); + if ( !function_form ) { + console.error("Unable to find form with id function_form"); + return; + } + function_form.elements['newFunction'].value = monitor.Function; + function_form.elements['newEnabled'].checked = monitor.Enabled == '1'; + function_form.elements['mid'].value = mid; + document.getElementById('function_monitor_name').innerHTML = monitor.Name; + + $j('#modalFunction').modal('show'); + }); + + // Manage the CANCEL modal buttons + $j('.funcCancelBtn').click(function(evt) { + evt.preventDefault(); + $j('#modalFunction').modal('hide'); + }); + + // Manage the SAVE modal buttons + $j('.funcSaveBtn').click(function(evt) { + evt.preventDefault(); + $j('#function_form').submit(); + }); +} + function initPage() { reloadWindow.periodical(consoleRefreshTimeout); if ( showVersionPopup ) { - createPopup('?view=version', 'zmVersion', 'version'); + window.location.assign('?view=version'); } if ( showDonatePopup ) { - createPopup('?view=donate', 'zmDonate', 'donate'); + $j.getJSON(thisUrl + '?request=modal&modal=donate') + .done(function(data) { + if ( $j('#donate').length ) { + $j('#donate').replaceWith(data.html); + } else { + $j("body").append(data.html); + } + $j('#donate').modal('show'); + // Manage the Apply button + $j('#donateApplyBtn').click(function(evt) { + evt.preventDefault(); + $j('#donateForm').submit(); + }); + }) + .fail(logAjaxFail); } // Makes table sortable @@ -133,6 +199,22 @@ function initPage() { axis: 'Y'} ); $j( "#consoleTableBody" ).disableSelection(); } ); + + // Setup the thumbnail video animation + initThumbAnimation(); + + // Load the Function modal on page load + $j.getJSON(thisUrl + '?request=modal&modal=function') + .done(function(data) { + if ( $j('#modalFunction').length ) { + $j('#modalFunction').replaceWith(data.html); + } else { + $j("body").append(data.html); + } + // Manage the Function modal + manageFunctionModal(); + }) + .fail(logAjaxFail); } function applySort(event, ui) { diff --git a/web/skins/classic/views/js/console.js.php b/web/skins/classic/views/js/console.js.php index e6af2a8b6..6ef6c199c 100644 --- a/web/skins/classic/views/js/console.js.php +++ b/web/skins/classic/views/js/console.js.php @@ -22,3 +22,21 @@ if ( canEdit('System') ) { ?> var showVersionPopup = ; var showDonatePopup = ; +var monitors = new Array(); + + monitors[Id() ?>] = { + 'Id': Id() ?>, + 'Name': 'Name() ?>', + 'ViewWidth': ViewWidth() ?>, + 'ViewHeight':ViewHeight() ?>, + 'Url': 'UrlToIndex( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>', + 'Type': 'Type() ?>', + 'Function': 'Function() ?>', + 'Enabled': 'Enabled() ?>' +}; + diff --git a/web/skins/classic/views/js/controlcap.js b/web/skins/classic/views/js/controlcap.js index a94f14acd..ff21286c2 100644 --- a/web/skins/classic/views/js/controlcap.js +++ b/web/skins/classic/views/js/controlcap.js @@ -4,12 +4,9 @@ function validateForm( form ) { // If "Can Move" is enabled, then the end user must also select at least one of the other check boxes (excluding Can Move Diagonally) if ( form.elements['newControl[CanMove]'].checked ) { if ( !( - form.elements['newControl[CanMoveCon]'].checked - || - form.elements['newControl[CanMoveRel]'].checked - || - form.elements['newControl[CanMoveAbs]'].checked - || + form.elements['newControl[CanMoveCon]'].checked || + form.elements['newControl[CanMoveRel]'].checked || + form.elements['newControl[CanMoveAbs]'].checked || form.elements['newControl[CanMoveMap]'].checked ) ) { errors[errors.length] = 'In addition to "Can Move", you also must select at least one of: "Can Move Mapped", "Can Move Absolute", "Can Move Relative", or "Can Move Continuous"'; @@ -17,14 +14,10 @@ function validateForm( form ) { } else { // Now lets check for the opposite condition. If any of the boxes below Can Move are checked, but Can Move is not checked then signal an error - if ( form.elements['newControl[CanMoveCon]'].checked - || - form.elements['newControl[CanMoveRel]'].checked - || - form.elements['newControl[CanMoveAbs]'].checked - || - form.elements['newControl[CanMoveMap]'].checked - || + if ( form.elements['newControl[CanMoveCon]'].checked || + form.elements['newControl[CanMoveRel]'].checked || + form.elements['newControl[CanMoveAbs]'].checked || + form.elements['newControl[CanMoveMap]'].checked || form.elements['newControl[CanMoveDiag]'].checked ) { errors[errors.length] = '"Can Move" must also be selected if any one of the movement types are selected.'; @@ -33,10 +26,8 @@ function validateForm( form ) { // If "Can Zoom" is enabled, then the end user must also select at least one of the other check boxes if ( form.elements['newControl[CanZoom]'].checked ) { if ( !( - form.elements['newControl[CanZoomCon]'].checked - || - form.elements['newControl[CanZoomRel]'].checked - || + form.elements['newControl[CanZoomCon]'].checked || + form.elements['newControl[CanZoomRel]'].checked || form.elements['newControl[CanZoomAbs]'].checked ) ) { errors[errors.length] = 'In addition to "Can Zoom", you also must select at least one of: "Can Zoom Absolute", "Can Zoom Relative", or "Can Zoom Continuous"'; @@ -44,10 +35,8 @@ function validateForm( form ) { } else { // Now lets check for the opposite condition. If any of the boxes below Can Zoom are checked, but Can Zoom is not checked then signal an error - if ( form.elements['newControl[CanZoomCon]'].checked - || - form.elements['newControl[CanZoomRel]'].checked - || + if ( form.elements['newControl[CanZoomCon]'].checked || + form.elements['newControl[CanZoomRel]'].checked || form.elements['newControl[CanZoomAbs]'].checked ) { errors[errors.length] = '"Can Move" must also be selected if any one of the zoom types are selected.'; @@ -56,10 +45,8 @@ function validateForm( form ) { // If "Can Zoom" is enabled, then the end user must also select at least one of the other check boxes if ( form.elements['newControl[CanFocus]'].checked ) { if ( !( - form.elements['newControl[CanFocusCon]'].checked - || - form.elements['newControl[CanFocusRel]'].checked - || + form.elements['newControl[CanFocusCon]'].checked || + form.elements['newControl[CanFocusRel]'].checked || form.elements['newControl[CanFocusAbs]'].checked ) ) { errors[errors.length] = 'In addition to "Can Focus", you also must select at least one of: "Can Focus Absolute", "Can Focus Relative", or "Can Focus Continuous"'; @@ -67,10 +54,8 @@ function validateForm( form ) { } else { // Now lets check for the opposite condition. If any of the boxes below Can Zoom are checked, but Can Zoom is not checked then signal an error - if ( form.elements['newControl[CanFocusCon]'].checked - || - form.elements['newControl[CanFocusRel]'].checked - || + if ( form.elements['newControl[CanFocusCon]'].checked || + form.elements['newControl[CanFocusRel]'].checked || form.elements['newControl[CanFocusAbs]'].checked ) { errors[errors.length] = '"Can Focus" must also be selected if any one of the focus types are selected.'; @@ -79,10 +64,8 @@ function validateForm( form ) { // If "Can White" is enabled, then the end user must also select at least one of the other check boxes if ( form.elements['newControl[CanWhite]'].checked ) { if ( !( - form.elements['newControl[CanWhiteCon]'].checked - || - form.elements['newControl[CanWhiteRel]'].checked - || + form.elements['newControl[CanWhiteCon]'].checked || + form.elements['newControl[CanWhiteRel]'].checked || form.elements['newControl[CanWhiteAbs]'].checked ) ) { errors[errors.length] = 'In addition to "Can White Balance", you also must select at least one of: "Can White Bal Absolute", "Can White Bal Relative", or "Can White Bal Continuous"'; @@ -90,10 +73,8 @@ function validateForm( form ) { } else { // Now lets check for the opposite condition. If any of the boxes below Can Zoom are checked, but Can Zoom is not checked then signal an error - if ( form.elements['newControl[CanWhiteCon]'].checked - || - form.elements['newControl[CanWhiteRel]'].checked - || + if ( form.elements['newControl[CanWhiteCon]'].checked || + form.elements['newControl[CanWhiteRel]'].checked || form.elements['newControl[CanWhiteAbs]'].checked ) { errors[errors.length] = '"Can White Balance" must also be selected if any one of the white balance types are selected.'; @@ -103,10 +84,8 @@ function validateForm( form ) { // If "Can Iris" is enabled, then the end user must also select at least one of the other check boxes if ( form.elements['newControl[CanIris]'].checked ) { if ( !( - form.elements['newControl[CanIrisCon]'].checked - || - form.elements['newControl[CanIrisRel]'].checked - || + form.elements['newControl[CanIrisCon]'].checked || + form.elements['newControl[CanIrisRel]'].checked || form.elements['newControl[CanIrisAbs]'].checked ) ) { errors[errors.length] = 'In addition to "Can Iris", you also must select at least one of: "Can Iris Absolute", "Can Iris Relative", or "Can Iris Continuous"'; @@ -114,10 +93,8 @@ function validateForm( form ) { } else { // Now lets check for the opposite condition. If any of the boxes below Can Zoom are checked, but Can Zoom is not checked then signal an error - if ( form.elements['newControl[CanIrisCon]'].checked - || - form.elements['newControl[CanIrisRel]'].checked - || + if ( form.elements['newControl[CanIrisCon]'].checked || + form.elements['newControl[CanIrisRel]'].checked || form.elements['newControl[CanIrisAbs]'].checked ) { errors[errors.length] = '"Can Iris" must also be selected if any one of the iris types are selected.'; diff --git a/web/skins/classic/views/js/controlpreset.js.php b/web/skins/classic/views/js/controlpreset.js.php index d358b3369..9bd8155f1 100644 --- a/web/skins/classic/views/js/controlpreset.js.php +++ b/web/skins/classic/views/js/controlpreset.js.php @@ -1,3 +1,6 @@ + var labels = new Array(); $label ) { diff --git a/web/skins/classic/views/js/donate.js b/web/skins/classic/views/js/donate.js deleted file mode 100644 index eb3c25f50..000000000 --- a/web/skins/classic/views/js/donate.js +++ /dev/null @@ -1,3 +0,0 @@ -if ( action == 'donate' && option == 'go' ) { - zmWindow('/donate/'); -} diff --git a/web/skins/classic/views/js/donate.js.php b/web/skins/classic/views/js/donate.js.php deleted file mode 100644 index 4fc36d5bb..000000000 --- a/web/skins/classic/views/js/donate.js.php +++ /dev/null @@ -1,2 +0,0 @@ -var action = ''; -var option = ''; diff --git a/web/skins/classic/views/js/download.js b/web/skins/classic/views/js/download.js index 717ab76de..16b47c8b4 100644 --- a/web/skins/classic/views/js/download.js +++ b/web/skins/classic/views/js/download.js @@ -29,11 +29,11 @@ function exportProgress() { function exportResponse(respObj, respText) { console.log(respObj); window.location.replace( - thisUrl+'?view='+currentView+'&'+eidParm - +'&exportFormat='+respObj.exportFormat - +'&exportFile='+respObj.exportFile - +'&generated='+((respObj.result=='Ok')?1:0) - +'&connkey='+connkey + thisUrl+'?view='+currentView+'&'+eidParm+ + '&exportFormat='+respObj.exportFormat+ + '&exportFile='+respObj.exportFile+ + '&generated='+((respObj.result=='Ok')?1:0)+ + '&connkey='+connkey ); } diff --git a/web/skins/classic/views/js/download.js.php b/web/skins/classic/views/js/download.js.php index 0d0c05679..390c9d17f 100644 --- a/web/skins/classic/views/js/download.js.php +++ b/web/skins/classic/views/js/download.js.php @@ -1,16 +1,19 @@ var eidParm = ''; var eidParm = 'eid='; var exportReady = ; diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index bddeaaee9..e20d460cf 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -49,7 +49,8 @@ $j.ajaxSetup({timeout: AJAX_TIMEOUT}); //sets timeout for all getJSON. var cueFrames = null; //make cueFrames available even if we don't send another ajax query function initialAlarmCues(eventId) { - $j.getJSON(thisUrl + '?view=request&request=status&entity=frames&id=' + eventId, setAlarmCues); //get frames data for alarmCues and inserts into html + $j.getJSON(thisUrl + '?view=request&request=status&entity=frames&id=' + eventId, setAlarmCues) //get frames data for alarmCues and inserts into html + .fail(logAjaxFail); } function setAlarmCues(data) { @@ -161,7 +162,7 @@ function changeScale() { newWidth = eventData.Width * scale / SCALE_BASE; newHeight = eventData.Height * scale / SCALE_BASE; } - if ( !(streamMode == 'stills') ) { + if ( streamMode != 'stills' ) { eventViewer.width(newWidth); } // stills handles its own width eventViewer.height(newHeight); @@ -181,7 +182,7 @@ function changeScale() { Cookie.write('zmEventScale'+eventData.MonitorId, scale, {duration: 10*365}); Cookie.dispose('zmEventScaleAuto'); } -} +} // end function changeScale function changeReplayMode() { var replayMode = $('replayMode').get('value'); @@ -1077,6 +1078,12 @@ function initPage() { vid.on('click', function(event) { handleClick(event); }); + vid.on('volumechange', function() { + Cookie.write('volume', vid.volume(), {duration: 10*365}); + }); + if ( Cookie.read('volume') != null ) { + vid.volume(Cookie.read('volume')); + } vid.on('timeupdate', function() { $j('#progressValue').html(secsToTime(Math.floor(vid.currentTime()))); }); diff --git a/web/skins/classic/views/js/event.js.php b/web/skins/classic/views/js/event.js.php index 70d7561a1..b3f746e07 100644 --- a/web/skins/classic/views/js/event.js.php +++ b/web/skins/classic/views/js/event.js.php @@ -2,7 +2,7 @@ global $connkey; global $Event; global $Monitor; - global $FilterQuery; + global $filterQuery; global $sortQuery; global $rates; global $rate; diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index e32281c81..9334927f0 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -1,179 +1,276 @@ -function closeWindows() { - window.close(); - // This is a hack. The only way to close an existing window is to try and open it! - var filterWindow = window.open( thisUrl+'?view=none', 'zmFilter', 'width=1,height=1' ); - filterWindow.close(); -} - -function setButtonStates( element ) { - var form = element.form; - var checked = element.checked; - form.viewBtn.disabled = !(canViewEvents && checked); - form.editBtn.disabled = !(canEditEvents && checked); - form.archiveBtn.disabled = unarchivedEvents?!checked:true; - form.unarchiveBtn.disabled = !(canEditEvents && archivedEvents && checked); - form.downloadBtn.disabled = !(canViewEvents && checked); - form.exportBtn.disabled = !(canViewEvents && checked); - form.deleteBtn.disabled = !(canEditEvents && checked); -} - -function configureButton(event) { - var element = event.target; - var form = element.form; - var checked = element.checked; - if ( !checked ) { - for (var i = 0, len=form.elements.length; i < len; i++) { - if ( form.elements[i].name.indexOf('eids') == 0) { - if ( form.elements[i].checked ) { - checked = true; - break; - } - } - } - } - if ( !element.checked ) { - form.toggleCheck.checked = false; - } - form.viewBtn.disabled = !(canViewEvents && checked); - form.editBtn.disabled = !(canEditEvents && checked); - form.archiveBtn.disabled = (!checked)||(!unarchivedEvents); - form.unarchiveBtn.disabled = !(canEditEvents && checked && archivedEvents); - form.downloadBtn.disabled = !(canViewEvents && checked); - form.exportBtn.disabled = !(canViewEvents && checked); - form.deleteBtn.disabled = !(canEditEvents && checked); -} - -function deleteEvents( element ) { - if ( ! canEditEvents ) { - alert("You do not have permission to delete events."); - return; - } - var form = element.form; - - var count = 0; - // This is slightly more efficient than a jquery selector because we stop after finding one. - for (var i = 0; i < form.elements.length; i++) { - if (form.elements[i].name.indexOf('eids') == 0) { - if ( form.elements[i].checked ) { - count++; - break; - } - } - } - if ( count > 0 ) { - if ( confirm(confirmDeleteEventsString) ) { - form.elements['action'].value = 'delete'; - form.submit(); - } - } -} - -function editEvents( element ) { - if ( ! canEditEvents ) { - alert("You do not have permission to delete events."); - return; - } - var form = element.form; - var eids = new Array(); - for (var i = 0, len=form.elements.length; i < len; i++) { - if (form.elements[i].name.indexOf('eids') == 0) { - if ( form.elements[i].checked ) { - eids[eids.length] = 'eids[]='+form.elements[i].value; - } - } - } - createPopup('?view=eventdetail&'+eids.join('&'), 'zmEventDetail', 'eventdetail'); -} - -function downloadVideo( element ) { - var form = element.form; - var eids = new Array(); - for (var i = 0, len=form.elements.length; i < len; i++) { - if (form.elements[i].name.indexOf('eids') == 0 ) { - if ( form.elements[i].checked ) { - eids[eids.length] = 'eids[]='+form.elements[i].value; - } - } - } - createPopup( '?view=download&'+eids.join('&'), 'zmDownload', 'download' ); -} - -function exportEvents( element ) { - var form = element.form; - console.log(form); - form.action = '?view=export'; - form.elements['view'].value='export'; - form.submit(); -} - -function viewEvents( element ) { - var form = element.form; - var events = new Array(); - for (var i = 0, len=form.elements.length; i < len; i++) { - if ( form.elements[i].name.indexOf('eids') == 0 ) { - if ( form.elements[i].checked ) { - events[events.length] = form.elements[i].value; - } - } - } - if ( events.length > 0 ) { - var filter = '&filter[Query][terms][0][attr]=Id&filter[Query][terms][0][op]=%3D%5B%5D&filter[Query][terms][0][val]='+events.join('%2C'); - window.location.href = thisUrl+'?view=event&eid='+events[0]+filter+sortQuery+'&page=1&play=1'; - } -} - -function archiveEvents(element) { - var form = element.form; - form.elements['action'].value = 'archive'; - form.submit(); -} - -function unarchiveEvents(element) { - if ( ! canEditEvents ) { - alert("You do not have permission to delete events."); - return; - } - var form = element.form; - form.elements['action'].value = 'unarchive'; - form.submit(); -} - -if ( openFilterWindow ) { - //opener.location.reload(true); - createPopup( '?view=filter&page='+thisPage+filterQuery, 'zmFilter', 'filter' ); - location.replace( '?view='+currentView+'&page='+thisPage+filterQuery ); -} - function thumbnail_onmouseover(event) { var img = event.target; img.src = ''; img.src = img.getAttribute('stream_src'); } + function thumbnail_onmouseout(event) { var img = event.target; img.src = ''; img.src = img.getAttribute('still_src'); } -function initPage() { - if ( window.history.length == 1 ) { - $j('#controls').children().eq(0).html(''); - } +function initThumbAnimation() { $j('.colThumbnail img').each(function() { this.addEventListener('mouseover', thumbnail_onmouseover, false); this.addEventListener('mouseout', thumbnail_onmouseout, false); }); - $j('input[name=eids\\[\\]]').each(function() { - this.addEventListener('click', configureButton, false); - }); - document.getElementById("refreshLink").addEventListener("click", function onRefreshClick(evt) { - evt.preventDefault(); - window.location.reload(true); - }); - document.getElementById("backLink").addEventListener("click", function onBackClick(evt) { - evt.preventDefault(); - window.history.back(); +} + +// Returns the event id's of the selected rows +function getIdSelections() { + var table = $j('#eventTable'); + + return $j.map(table.bootstrapTable('getSelections'), function(row) { + return row.Id.replace(/(<([^>]+)>)/gi, ''); // strip the html from the element before sending }); } -$j(document).ready(initPage); +// Returns a boolen to indicate at least one selected row is archived +function getArchivedSelections() { + var table = $j('#eventTable'); + var selection = $j.map(table.bootstrapTable('getSelections'), function(row) { + return row.Archived; + }); + return selection.includes("Yes"); +} + +// Load the Delete Confirmation Modal HTML via Ajax call +function getDelConfirmModal() { + $j.getJSON(thisUrl + '?request=modal&modal=delconfirm') + .done(function(data) { + if ( $j('#deleteConfirm').length ) { + $j('#deleteConfirm').replaceWith(data.html); + } else { + $j("body").append(data.html); + } + manageDelConfirmModalBtns(); + }) + .fail(logAjaxFail); +} + +// Manage the DELETE CONFIRMATION modal button +function manageDelConfirmModalBtns() { + document.getElementById("delConfirmBtn").addEventListener("click", function onDelConfirmClick(evt) { + if ( ! canEditEvents ) { + enoperm(); + return; + } + + var selections = getIdSelections(); + + evt.preventDefault(); + $j.getJSON(thisUrl + '?request=events&action=delete&eids[]='+selections.join('&eids[]=')) + .done( function(data) { + $j('#eventTable').bootstrapTable('refresh'); + window.location.reload(true); + }) + .fail(logAjaxFail); + }); + + // Manage the CANCEL modal button + document.getElementById("delCancelBtn").addEventListener("click", function onDelCancelClick(evt) { + $j('#deleteConfirm').modal('hide'); + }); +} + +function getEventDetailModal(eid) { + $j.getJSON(thisUrl + '?request=modal&modal=eventdetail&eids[]=' + eid) + .done(function(data) { + if ( $j('#eventDetailModal').length ) { + $j('#eventDetailModal').replaceWith(data.html); + } else { + $j("body").append(data.html); + } + $j('#eventDetailModal').modal('show'); + // Manage the Save button + $j('#eventDetailSaveBtn').click(function(evt) { + evt.preventDefault(); + $j('#eventDetailForm').submit(); + }); + }) + .fail(logAjaxFail); +} + +function initPage() { + var backBtn = $j('#backBtn'); + var viewBtn = $j('#viewBtn'); + var archiveBtn = $j('#archiveBtn'); + var unarchiveBtn = $j('#unarchiveBtn'); + var editBtn = $j('#editBtn'); + var exportBtn = $j('#exportBtn'); + var downloadBtn = $j('#downloadBtn'); + var deleteBtn = $j('#deleteBtn'); + var table = $j('#eventTable'); + + // Load the delete confirmation modal into the DOM + getDelConfirmModal(); + + // Init the bootstrap-table + table.bootstrapTable({icons: icons}); + + // Hide these columns on first run when no cookie is saved + if ( !getCookie("zmEventsTable.bs.table.columns") ) { + table.bootstrapTable('hideColumn', 'Archived'); + table.bootstrapTable('hideColumn', 'Emailed'); + } + + // enable or disable buttons based on current selection and user rights + table.on('check.bs.table uncheck.bs.table ' + + 'check-all.bs.table uncheck-all.bs.table', + function() { + selections = table.bootstrapTable('getSelections'); + + viewBtn.prop('disabled', !(selections.length && canViewEvents)); + archiveBtn.prop('disabled', !(selections.length && canEditEvents)); + unarchiveBtn.prop('disabled', !(getArchivedSelections()) && canEditEvents); + editBtn.prop('disabled', !(selections.length && canEditEvents)); + exportBtn.prop('disabled', !(selections.length && canViewEvents)); + downloadBtn.prop('disabled', !(selections.length && canViewEvents)); + deleteBtn.prop('disabled', !(selections.length && canEditEvents)); + }); + + // Don't enable the back button if there is no previous zm page to go back to + backBtn.prop('disabled', !document.referrer.length); + + // Setup the thumbnail video animation + initThumbAnimation(); + + // Some toolbar events break the thumbnail animation, so re-init eventlistener + table.on('all.bs.table', initThumbAnimation); + + // Manage the BACK button + document.getElementById("backBtn").addEventListener("click", function onBackClick(evt) { + evt.preventDefault(); + window.history.back(); + }); + + // Manage the REFRESH Button + document.getElementById("refreshBtn").addEventListener("click", function onRefreshClick(evt) { + evt.preventDefault(); + window.location.reload(true); + }); + + // Manage the TIMELINE Button + document.getElementById("tlineBtn").addEventListener("click", function onTlineClick(evt) { + evt.preventDefault(); + window.location.assign('?view=timeline'+filterQuery); + }); + + // Manage the VIEW button + document.getElementById("viewBtn").addEventListener("click", function onViewClick(evt) { + var selections = getIdSelections(); + + evt.preventDefault(); + var filter = '&filter[Query][terms][0][attr]=Id&filter[Query][terms][0][op]=%3D%5B%5D&filter[Query][terms][0][val]='+selections.join('%2C'); + window.location.href = thisUrl+'?view=event&eid='+selections[0]+filter+sortQuery+'&page=1&play=1'; + }); + + // Manage the ARCHIVE button + document.getElementById("archiveBtn").addEventListener("click", function onArchiveClick(evt) { + var selections = getIdSelections(); + + evt.preventDefault(); + $j.getJSON(thisUrl + '?request=events&action=archive&eids[]='+selections.join('&eids[]=')) + .done( function(data) { + $j('#eventTable').bootstrapTable('refresh'); + window.location.reload(true); + }) + .fail(logAjaxFail); + }); + + // Manage the UNARCHIVE button + document.getElementById("unarchiveBtn").addEventListener("click", function onUnarchiveClick(evt) { + if ( ! canEditEvents ) { + enoperm(); + return; + } + + var selections = getIdSelections(); + console.log(selections); + + evt.preventDefault(); + $j.getJSON(thisUrl + '?request=events&action=unarchive&eids[]='+selections.join('&eids[]=')) + .done( function(data) { + $j('#eventTable').bootstrapTable('refresh'); + window.location.reload(true); + }) + .fail(logAjaxFail); + + if ( openFilterWindow ) { + //opener.location.reload(true); + createPopup( '?view=filter&page='+thisPage+filterQuery, 'zmFilter', 'filter' ); + location.replace( '?view='+currentView+'&page='+thisPage+filterQuery ); + } else { + window.location.reload(true); + } + }); + + // Manage the EDIT button + document.getElementById("editBtn").addEventListener("click", function onEditClick(evt) { + if ( ! canEditEvents ) { + enoperm(); + return; + } + + var selections = getIdSelections(); + + evt.preventDefault(); + $j.getJSON(thisUrl + '?request=modal&modal=eventdetail&eids[]='+selections.join('&eids[]=')) + .done(function(data) { + if ( $j('#eventDetailModal').length ) { + $j('#eventDetailModal').replaceWith(data.html); + } else { + $j("body").append(data.html); + } + $j('#eventDetailModal').modal('show'); + // Manage the Save button + $j('#eventDetailSaveBtn').click(function(evt) { + evt.preventDefault(); + $j('#eventDetailForm').submit(); + }); + }) + .fail(logAjaxFail); + }); + + // Manage the EXPORT button + document.getElementById("exportBtn").addEventListener("click", function onExportClick(evt) { + var selections = getIdSelections(); + + evt.preventDefault(); + window.location.assign('?view=export&eids[]='+selections.join('&eids[]=')); + }); + + // Manage the DOWNLOAD VIDEO button + document.getElementById("downloadBtn").addEventListener("click", function onDownloadClick(evt) { + var selections = getIdSelections(); + + evt.preventDefault(); + createPopup('?view=download&eids[]='+selections.join('&eids[]='), 'zmDownload', 'download'); + }); + + // Manage the DELETE button + document.getElementById("deleteBtn").addEventListener("click", function onDeleteClick(evt) { + if ( ! canEditEvents ) { + enoperm(); + return; + } + + evt.preventDefault(); + $j('#deleteConfirm').modal('show'); + }); + + // Manage the eventdetail links in the events list + $j(".eDetailLink").click(function(evt) { + evt.preventDefault(); + var eid = $j(this).data('eid'); + getEventDetailModal(eid); + }); + + // The table is initially given a hidden style, so now that we are done rendering, show it + table.show(); +} + +$j(document).ready(function() { + initPage(); +}); diff --git a/web/skins/classic/views/js/events.js.php b/web/skins/classic/views/js/events.js.php index 8a49c00c3..0b96f12c5 100644 --- a/web/skins/classic/views/js/events.js.php +++ b/web/skins/classic/views/js/events.js.php @@ -1,9 +1,10 @@ + //var openFilterWindow = ; var openFilterWindow = false; -var archivedEvents = ; -var unarchivedEvents = ; - var filterQuery = ''; var sortQuery = ''; diff --git a/web/skins/classic/views/js/export.js b/web/skins/classic/views/js/export.js index 7dd7f6c6d..dfe74ebe3 100644 --- a/web/skins/classic/views/js/export.js +++ b/web/skins/classic/views/js/export.js @@ -18,10 +18,8 @@ function configureExportButton(element) { form.elements['exportImages'].checked || form.elements['exportVideo'].checked || form.elements['exportMisc'].checked - ) - && - ( form.elements['exportFormat'][0].checked || form.elements['exportFormat'][1].checked ) - && + ) && + ( form.elements['exportFormat'][0].checked || form.elements['exportFormat'][1].checked ) && ( form.elements['exportCompress'][0].checked || form.elements['exportCompress'][1].checked ) ); } @@ -82,12 +80,36 @@ function exportEvents( ) { exportTimer = exportProgress.periodical( 500 ); } +function getEventDetailModal(eid) { + $j.getJSON(thisUrl + '?request=modal&modal=eventdetail&eids[]=' + eid) + .done(function(data) { + if ( $j('#eventDetailModal').length ) { + $j('#eventDetailModal').replaceWith(data.html); + } else { + $j("body").append(data.html); + } + $j('#eventDetailModal').modal('show'); + // Manage the Save button + $j('#eventDetailSaveBtn').click(function(evt) { + evt.preventDefault(); + $j('#eventDetailForm').submit(); + }); + }) + .fail(logAjaxFail); +} + function initPage() { configureExportButton( $('exportButton') ); if ( exportReady ) { startDownload.pass(exportFile).delay(1500); } document.getElementById('exportButton').addEventListener('click', exportEvents); + // Manage the eventdetail link in the export list + $j(".eDetailLink").click(function(evt) { + evt.preventDefault(); + var eid = $j(this).data('eid'); + getEventDetailModal(eid); + }); } window.addEventListener('DOMContentLoaded', initPage); diff --git a/web/skins/classic/views/js/filter.js b/web/skins/classic/views/js/filter.js index bcf67c00b..163a7fdde 100644 --- a/web/skins/classic/views/js/filter.js +++ b/web/skins/classic/views/js/filter.js @@ -2,12 +2,12 @@ function selectFilter(element) { element.form.submit(); } -function validateForm( form ) { +function validateForm(form) { var rows = $j(form).find('tbody').eq(0).find('tr'); var obrCount = 0; var cbrCount = 0; for ( var i = 0; i < rows.length; i++ ) { - if (rows.length > 2) { + if ( rows.length > 2 ) { obrCount += parseInt(form.elements['filter[Query][terms][' + i + '][obr]'].value); cbrCount += parseInt(form.elements['filter[Query][terms][' + i + '][cbr]'].value); } @@ -22,9 +22,52 @@ function validateForm( form ) { } var numbers_reg = /\D/; if ( numbers_reg.test(form.elements['filter[Query][limit]'].value) ) { - alert("There appear to be non-numeric characters in your limit. Limit must be a positive integer value or empty."); + alert('There appear to be non-numeric characters in your limit. Limit must be a positive integer value or empty.'); return false; } + if ( form.elements['filter[AutoDelete]'].checked ) { + // if Delete action is Enabled should also have an unarchived term + var have_archivestatus_term = false; + for ( var i = 0; i < rows.length; i++ ) { + if ( form.elements['filter[Query][terms][' + i + '][attr]'].value == 'Archived' ) { + have_archivestatus_term = true; + } + } + if ( ! have_archivestatus_term ) { + return confirm('You have enabled deleting events but do not have a term referencing the archived status of the event. This filter may delete events that you want to save! Are you sure?'); + } + } else if ( form.elements['filter[UpdateDiskSpace]'].checked ) { + var have_endtime_term = false; + for ( var i = 0; i < rows.length; i++ ) { + if ( + ( form.elements['filter[Query][terms][' + i + '][attr]'].value == 'EndDateTime' ) + || + ( form.elements['filter[Query][terms][' + i + '][attr]'].value == 'EndTime' ) + || + ( form.elements['filter[Query][terms][' + i + '][attr]'].value == 'EndDate' ) + ) { + have_endtime_term = true; + break; + } + } + if ( ! have_endtime_term ) { + return confirm('You don\'t have an End Date/Time term in your filter. This might match recordings that are still in progress and so the UpdateDiskSpace action will be a waste of time and resources. Ideally you should have an End Date/Time IS NOT NULL term. Do you want to continue?'); + } + } else if ( form.elements['filter[Background]'].checked ) { + if ( ! ( + form.elements['filter[AutoArchive]'].checked || + form.elements['filter[UpdateDiskSpace]'].checked || + form.elements['filter[AutoVideo]'].checked || + form.elements['filter[AutoEmail]'].checked || + form.elements['filter[AutoMessage]'].checked || + form.elements['filter[AutoExecute]'].checked || + form.elements['filter[AutoDelete]'].checked || + form.elements['filter[AutoCopy]'].checked || + form.elements['filter[AutoMove]'].checked + ) ) { + alert('You have chosen to run this filter in the background but not selected any actions.'); + } + } return true; } @@ -108,10 +151,14 @@ function resetFilter( element ) { $j('#contentForm')[0].reset(); } -function submitToEvents( element ) { +function submitToEvents(element) { var form = element.form; - form.action = thisUrl + '?view=events'; - history.replaceState(null, null, '?view=filter&' + $j(form).serialize()); + //form.action = '?view=events'; + //form.submit(); + //console.log(form); + //console.log($j(form).serialize()); + //history.replaceState(null, null, '?view=filter&' + $j(form).serialize()); + window.location.assign('?view=events&'+$j(form).serialize()); } function submitToMontageReview(element) { @@ -254,6 +301,14 @@ function parseRows(rows) { } var monitorVal = inputTds.eq(4).children().val(); inputTds.eq(4).html(monitorSelect).children().val(monitorVal); + } else if ( attr == 'ExistsInFileSystem' ) { + var select = $j('').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); + for ( var booleanVal in booleanValues ) { + select.append(''); + } + var val = inputTds.eq(4).children().val(); + if ( ! val ) val = 'false'; // default to the first option false + inputTds.eq(4).html(select).children().val(val); } else { // Reset to regular text field and operator for everything that isn't special var textInput = $j('').attr('type', 'text').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]'); var textVal = inputTds.eq(4).children().val(); @@ -263,13 +318,23 @@ function parseRows(rows) { // Validate the operator var opSelect = $j('').attr('name', queryPrefix + rowNum + '][op]').attr('id', queryPrefix + rowNum + '][op]'); var opVal = inputTds.eq(3).children().val(); - if ( ! opVal ) { - // Default to equals so that something gets selected - console.log("No value for operator. Defaulting to ="); - opVal = '='; - } - for ( var key in opTypes ) { - opSelect.append(''); + if ( attr == 'ExistsInFileSystem' ) { + if ( ! opVal ) { + // Default to equals so that something gets selected + opVal = 'IS'; + } + for ( var key of ['IS', 'IS NOT'] ) { + opSelect.append(''); + } + } else { + if ( ! opVal ) { + // Default to equals so that something gets selected + console.log("No value for operator. Defaulting to ="); + opVal = '='; + } + for ( var key in opTypes ) { + opSelect.append(''); + } } inputTds.eq(3).html(opSelect).children().val(opVal).chosen({width: "101%"}); if ( attr.endsWith('DateTime') ) { //Start/End DateTime @@ -289,7 +354,7 @@ function parseRows(rows) { inputTds.eq(2).children().eq(0).attr('id', 'filter'+stringFilter(term)); } //End for each term/row history.replaceState(null, null, '?view=filter&' + $j('#contentForm').serialize()); -} +} // parseRows function stringFilter(term) { var termString = ''; @@ -330,11 +395,53 @@ function delTerm( element ) { parseRows(rows); } +function debugFilter() { + getModal('filterdebug'); +} + +// Load the Delete Confirmation Modal HTML via Ajax call +function getModal(id) { + $j.getJSON(thisUrl + '?request=modal&modal='+id+'&fid='+filterid) + .done(function(data) { + if ( !data ) { + console.error("Get modal returned no data"); + return; + } + + if ( $j('#'+id).length ) { + console.log("replacing"); + $j('#'+id).replaceWith(data.html); + } else { + console.log("Adding to body"+data.html); + $j('body').append(data.html); + } + manageModalBtns(id); + modal = $j('#'+id+'Modal'); + if ( ! modal.length ) { + console.log("No modal found"); + } + $j('#'+id+'Modal').modal('show'); + }) + .fail(logAjaxFail); +} + +function manageModalBtns(id) { + console.log(id); + // Manage the CANCEL modal button + var cancelBtn = document.getElementById(id+"CancelBtn"); + if ( cancelBtn ) { + document.getElementById(id+"CancelBtn").addEventListener("click", function onCancelClick(evt) { + $j('#'+id).modal('hide'); + }); + } +} + function init() { updateButtons( $('executeButton') ); $j('#Id').chosen(); $j('#fieldsTable select').not("[name$='br\\]'], [name$='cnj\\]']").chosen({width: '101%'}); //Every select except brackets/and $j("#sortTable [name$='sort_field\\]']").chosen(); + parseRows($j('#fieldsTable tbody').children()); } window.addEventListener( 'DOMContentLoaded', init ); diff --git a/web/skins/classic/views/js/filter.js.php b/web/skins/classic/views/js/filter.js.php index 108dbddce..f7f7547f2 100644 --- a/web/skins/classic/views/js/filter.js.php +++ b/web/skins/classic/views/js/filter.js.php @@ -10,7 +10,10 @@ global $storageareas; global $monitors; global $zones; + global $booleanValues; + global $filter; ?> + var filterid = 'Id() ?>'; var filterQuery = ''; var sortQuery = ''; @@ -24,6 +27,7 @@ var servers = ; var storageareas = ; var monitors = ; var zones = ; +var booleanValues = ; var errorBrackets = ''; var errorValue = ''; diff --git a/web/skins/classic/views/js/frame.js b/web/skins/classic/views/js/frame.js index 37dae96ec..5375bb098 100644 --- a/web/skins/classic/views/js/frame.js +++ b/web/skins/classic/views/js/frame.js @@ -37,5 +37,36 @@ if ( !scale ) { } document.addEventListener('DOMContentLoaded', function onDCL() { - document.getElementById('scale').addEventListener('change', changeScale); + document.getElementById('scaleControl').addEventListener('change', changeScale); +}); + +function initPage() { + var backBtn = $j('#backBtn'); + + if ( scale == '0' || scale == 'auto' ) changeScale(); + + // Don't enable the back button if there is no previous zm page to go back to + backBtn.prop('disabled', !document.referrer.length); + + // Manage the BACK button + document.getElementById("backBtn").addEventListener("click", function onBackClick(evt) { + evt.preventDefault(); + window.history.back(); + }); + + // Manage the REFRESH Button + document.getElementById("refreshBtn").addEventListener("click", function onRefreshClick(evt) { + evt.preventDefault(); + window.location.reload(true); + }); + + // Manage the STATS button + document.getElementById("statsBtn").addEventListener("click", function onViewClick(evt) { + evt.preventDefault(); + window.location.href = thisUrl+'?view=stats&eid='+eid+'&fid='+fid; + }); +} + +$j(document).ready(function() { + initPage(); }); diff --git a/web/skins/classic/views/js/frame.js.php b/web/skins/classic/views/js/frame.js.php index 572587f82..9bd2f4236 100644 --- a/web/skins/classic/views/js/frame.js.php +++ b/web/skins/classic/views/js/frame.js.php @@ -1,3 +1,15 @@ + + var scale = ''; var SCALE_BASE = ; + +var eid = ; +var fid = ; +var record_event_stats = ; +var alarmFrame = ; diff --git a/web/skins/classic/views/js/frames.js b/web/skins/classic/views/js/frames.js new file mode 100644 index 000000000..57bf8e4b0 --- /dev/null +++ b/web/skins/classic/views/js/frames.js @@ -0,0 +1,78 @@ +function thumbnail_onmouseover(event) { + var img = event.target; + img.src = ''; + img.src = img.getAttribute('full_img_src'); +} + +function thumbnail_onmouseout(event) { + var img = event.target; + img.src = ''; + img.src = img.getAttribute('img_src'); +} + +function initThumbAnimation() { + $j('.colThumbnail img').each(function() { + this.addEventListener('mouseover', thumbnail_onmouseover, false); + this.addEventListener('mouseout', thumbnail_onmouseout, false); + }); +} + +function processClicks(event, field, value, row, $element) { + if ( field == 'FrameScore' ) { + window.location.assign('?view=stats&eid='+row.EventId+'&fid='+row.FrameId); + } else { + window.location.assign('?view=frame&eid='+row.EventId+'&fid='+row.FrameId); + } +} + +// This function handles when the user clicks a "+" link to retrieve stats for a frame +function detailFormatter(index, row, $detail) { + $detail.html('Please wait. Loading from ajax request...'); + $j.get(thisUrl + '?request=stats&eid=' + row.EventId + '&fid=' + row.FrameId + '&row=' + index) + .done(function(data) { + $detail.html(data.html); + }) + .fail(logAjaxFail); +} +function initPage() { + var backBtn = $j('#backBtn'); + var table = $j('#framesTable'); + + // Init the bootstrap-table + table.bootstrapTable({icons: icons}); + + // Hide these columns on first run when no cookie is saved + if ( !getCookie("zmFramesTable.bs.table.columns") ) { + table.bootstrapTable('hideColumn', 'EventId'); + } + + // Hide the stats tables on init + $j(".contentStatsTable").hide(); + + // Disable the back button if there is nothing to go back to + backBtn.prop('disabled', !document.referrer.length); + + // Setup the thumbnail animation + initThumbAnimation(); + + // Some toolbar events break the thumbnail animation, so re-init eventlistener + table.on('all.bs.table', initThumbAnimation); + + // Load the associated frame image when the user clicks on a row + table.on('click-cell.bs.table', processClicks); + + // Manage the BACK button + document.getElementById("backBtn").addEventListener("click", function onBackClick(evt) { + evt.preventDefault(); + window.history.back(); + }); + // Manage the REFRESH Button + document.getElementById("refreshBtn").addEventListener("click", function onRefreshClick(evt) { + evt.preventDefault(); + window.location.reload(true); + }); +} + +$j(document).ready(function() { + initPage(); +}); diff --git a/web/skins/classic/views/js/log.js b/web/skins/classic/views/js/log.js index f0aee7c00..53f197eab 100644 --- a/web/skins/classic/views/js/log.js +++ b/web/skins/classic/views/js/log.js @@ -210,22 +210,31 @@ function resetLog() { refreshLog(); } -var exportFormValidator; +var exportFormValidator = null; function exportLog() { - exportFormValidator.reset(); - $('exportLog').overlayShow(); + getModal('log_export'); + + if ( !exportFormValidator ) { + exportFormValidator = new Form.Validator.Inline($('exportForm'), { + useTitles: true, + warningPrefix: '', + errorPrefix: '' + }); + } else { + exportFormValidator.reset(); + } } function exportResponse( response ) { - $('exportLog').unspin(); + $('log_exportModal').unspin(); if ( response.result == 'Ok' ) { window.location.replace( thisUrl+'?view=request&request=log&task=download&key='+response.key+'&format='+response.format ); } } function exportFail( request ) { - $('exportLog').unspin(); + $('log_exportModal').unspin(); $('exportErrorText').set('text', request.status+' / '+request.statusText); $('exportError').show(); Error('Export request failed: '+request.status+' / '+request.statusText); @@ -233,12 +242,18 @@ function exportFail( request ) { function exportRequest() { var form = $('exportForm'); + console.log(form); $('exportErrorText').set('text', ''); $('exportError').hide(); if ( form.validate() ) { var exportParms = "view=request&request=log&task=export"; var exportReq = new Request.JSON({url: thisUrl, method: 'post', link: 'cancel', onSuccess: exportResponse, onFailure: exportFail}); - var selection = form.getElement('input[name=selector]:checked').get('value'); + var selector = form.querySelectorAll('input[name=selector]:checked'); + if ( !selector.length ) { + alert("Please select how to filter logs"); + return; + } + var selection = selector[0].get('value'); if ( selection == 'filter' || selection == 'current' ) { $$('#filters select').each( function( select ) { @@ -257,7 +272,7 @@ function exportRequest() { } } exportReq.send(exportParms+"&"+form.toQueryString()); - $('exportLog').spin(); + $('log_exportModal').spin(); } } @@ -294,6 +309,8 @@ function updateFilterSelectors() { if ( filter[key] ) { selector.set('value', filter[key]); } + $j(selector).chosen('destroy'); + $j(selector).chosen(); } ); } @@ -331,11 +348,6 @@ function initPage() { } // end if loCount > displayLimit } ); - exportFormValidator = new Form.Validator.Inline($('exportForm'), { - useTitles: true, - warningPrefix: '', - errorPrefix: '' - }); new Asset.css('css/spinner.css'); fetchNextLogs(); } diff --git a/web/skins/classic/views/js/monitor.js b/web/skins/classic/views/js/monitor.js index 3f962ebfb..0bedf5303 100644 --- a/web/skins/classic/views/js/monitor.js +++ b/web/skins/classic/views/js/monitor.js @@ -68,6 +68,9 @@ function loadLocations( element ) { } function initPage() { + var backBtn = $j('#backBtn'); + var onvifBtn = $j('#onvifBtn'); + //var protocolSelector = $('contentForm').elements['newMonitor[Protocol]']; //if ( $(protocolSelector).getTag() == 'select' ) //updateMethods( $(protocolSelector) ); @@ -134,9 +137,72 @@ function initPage() { document.querySelectorAll('input[name="newMonitor[WebColour]"]').forEach(function(el) { el.onchange = window['change_WebColour'].bind(el); }); - + document.querySelectorAll('select[name="newMonitor[Type]"]').forEach(function(el) { + el.onchange = function() { + var form = document.getElementById('contentForm'); + form.tab.value = 'general'; + form.submit(); + }; + }); + document.querySelectorAll('input[name="newMonitor[ImageBufferCount]"],input[name="newMonitor[Width]"],input[name="newMonitor[Height]"]').forEach(function(el) { + el.oninput = window['update_estimated_ram_use'].bind(el); + }); $j('.chosen').chosen(); + + // Don't enable the back button if there is no previous zm page to go back to + backBtn.prop('disabled', !document.referrer.length); + + // Manage the BACK button + document.getElementById("backBtn").addEventListener("click", function onBackClick(evt) { + evt.preventDefault(); + window.history.back(); + }); + + // Manage the REFRESH Button + document.getElementById("refreshBtn").addEventListener("click", function onRefreshClick(evt) { + evt.preventDefault(); + window.location.reload(true); + }); + + // Manage the PROBE button + $j('#probeBtn').click(function(evt) { + var mid = evt.currentTarget.getAttribute("data-mid"); + evt.preventDefault(); + + //FIX-ME: MAKE THIS A MODAL + //$j('#modalFunction-'+mid).modal('show'); + window.location.assign('?view=monitorprobe&mid='+mid); + }); + + // Manage the ONVIF button + $j('#onvifBtn').click(function(evt) { + var mid = evt.currentTarget.getAttribute("data-mid"); + evt.preventDefault(); + + //FIX-ME: MAKE THIS A MODAL + //$j('#modalFunction-'+mid).modal('show'); + window.location.assign('?view=onvifprobe&mid='+mid); + }); + + // Don't enable the onvif button if there is no previous zm page to go back to + onvifBtn.prop('disabled', !hasOnvif); + + // Manage the PRESET button + $j('#presetBtn').click(function(evt) { + var mid = evt.currentTarget.getAttribute("data-mid"); + evt.preventDefault(); + + //FIX-ME: MAKE THIS A MODAL + //$j('#modalFunction-'+mid).modal('show'); + window.location.assign('?view=monitorpreset&mid='+mid); + }); + + // Manage the CANCEL Button + document.getElementById("cancelBtn").addEventListener("click", function onCancelClick(evt) { + evt.preventDefault(); + window.location.assign('?view=console'); + }); } // end function initPage() function change_WebColour() { @@ -163,4 +229,17 @@ function random_WebColour() { ); } +function update_estimated_ram_use() { + var buffer_count = document.querySelectorAll('input[name="newMonitor[ImageBufferCount]"]')[0].value; + console.log(buffer_count); + var width = document.querySelectorAll('input[name="newMonitor[Width]"]')[0].value; + console.log(width); + var height = document.querySelectorAll('input[name="newMonitor[Height]"]')[0].value; + console.log(height); + var colours = document.querySelectorAll('select[name="newMonitor[Colours]"]')[0].value; + console.log(colours); + + document.getElementById('estimated_ram_use').innerHTML = human_filesize(buffer_count * width * height * colours, 0); +} + window.addEventListener('DOMContentLoaded', initPage); diff --git a/web/skins/classic/views/js/monitor.js.php b/web/skins/classic/views/js/monitor.js.php index 42ca58899..b59049f12 100644 --- a/web/skins/classic/views/js/monitor.js.php +++ b/web/skins/classic/views/js/monitor.js.php @@ -1,4 +1,5 @@ var optControl = ; +var hasOnvif = ; var defaultAspectRatio = ''; var controlOptions = new Object(); translate('None') ); - # Temporary workaround to show all ptz control types regardless of monitor source type - # $sql = "select * from Controls where Type = '".$newMonitor['Type']."'"; - $sql = 'SELECT `Id`,`Name`,`HasHomePreset`,`NumPresets` FROM `Controls` ORDER BY lower(`Name`)'; - foreach( dbFetchAll($sql) as $row ) { - $controlTypes[$row['Id']] = $row['Name']; + global $controls; + foreach ( $controls as $control ) { echo ' -controlOptions['.$row['Id'].'] = new Array(); -controlOptions['.$row['Id'].'][0] = '. - ( $row['HasHomePreset'] ? '\''.translate('Home').'\'' : 'null' ).' -'; - for ( $i = 1; $i <= $row['NumPresets']; $i++ ) { - echo 'controlOptions['. $row['Id'].']['.$i.'] = \''.translate('Preset').' '.$i .'\'; -'; +controlOptions['.$control->Id().'] = new Array(); +controlOptions['.$control->Id().'][0] = '. + ( $control->HasHomePreset() ? '\''.translate('Home').'\'' : 'null' ).PHP_EOL; + for ( $i = 1; $i <= $control->NumPresets(); $i++ ) { + echo 'controlOptions['. $control->Id().']['.$i.'] = \''.translate('Preset').' '.$i .'\';'.PHP_EOL; } } # end foreach row } # end if ZM_OPT_CONTROL diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index 0679b8781..03fc5c3f8 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -2,210 +2,6 @@ var requestQueue = new Request.Queue({ concurrent: monitorData.length, stopOnFailure: false }); - -function Monitor(monitorData) { - this.id = monitorData.id; - this.connKey = monitorData.connKey; - this.url = monitorData.url; - this.status = null; - this.alarmState = STATE_IDLE; - this.lastAlarmState = STATE_IDLE; - this.streamCmdParms = 'view=request&request=stream&connkey='+this.connKey; - if ( auth_hash ) { - this.streamCmdParms += '&auth='+auth_hash; - } else if ( auth_relay ) { - this.streamCmdParms += '&'+auth_relay; - } - this.streamCmdTimer = null; - this.type = monitorData.type; - this.refresh = monitorData.refresh; - this.start = function(delay) { - if ( this.streamCmdQuery ) { - this.streamCmdTimer = this.streamCmdQuery.delay(delay, this); - } else { - console.log("No streamCmdQuery"); - } - }; - - this.eventHandler = function(event) { - console.log(event); - }; - - this.onclick = function(evt) { - var el = evt.currentTarget; - var tag = 'watch'; - var id = el.getAttribute("data-monitor-id"); - var width = el.getAttribute("data-width"); - var height = el.getAttribute("data-height"); - var url = '?view=watch&mid='+id; - var name = 'zmWatch'+id; - evt.preventDefault(); - createPopup(url, name, tag, width, height); - }; - - this.setup_onclick = function() { - var el = document.getElementById('imageFeed'+this.id); - if ( el ) el.addEventListener('click', this.onclick, false); - }; - this.disable_onclick = function() { - document.getElementById('imageFeed'+this.id).removeEventListener('click', this.onclick ); - }; - - this.setStateClass = function(element, stateClass) { - if ( !element.hasClass( stateClass ) ) { - if ( stateClass != 'alarm' ) { - element.removeClass('alarm'); - } - if ( stateClass != 'alert' ) { - element.removeClass('alert'); - } - if ( stateClass != 'idle' ) { - element.removeClass('idle'); - } - element.addClass(stateClass); - } - }; - - this.onError = function(text, error) { - console.log('onerror: ' + text + ' error:'+error); - // Requeue, but want to wait a while. - var streamCmdTimeout = 10*statusRefreshTimeout; - this.streamCmdTimer = this.streamCmdQuery.delay(streamCmdTimeout, this); - }; - this.onFailure = function(xhr) { - console.log('onFailure: ' + this.connKey); - console.log(xhr); - if ( ! requestQueue.hasNext("cmdReq"+this.id) ) { - console.log("Not requeuing because there is one already"); - requestQueue.addRequest("cmdReq"+this.id, this.streamCmdReq); - } - if ( 0 ) { - // Requeue, but want to wait a while. - if ( this.streamCmdTimer ) { - this.streamCmdTimer = clearTimeout( this.streamCmdTimer ); - } - var streamCmdTimeout = 1000*statusRefreshTimeout; - this.streamCmdTimer = this.streamCmdQuery.delay( streamCmdTimeout, this, true ); - requestQueue.resume(); - } - console.log("done failure"); - }; - - this.getStreamCmdResponse = function(respObj, respText) { - if ( this.streamCmdTimer ) { - this.streamCmdTimer = clearTimeout( this.streamCmdTimer ); - } - - var stream = $j('#liveStream'+this.id)[0]; - - if ( respObj.result == 'Ok' ) { - if ( respObj.status ) { - this.status = respObj.status; - this.alarmState = this.status.state; - - var stateClass = ""; - if ( this.alarmState == STATE_ALARM ) { - stateClass = "alarm"; - } else if ( this.alarmState == STATE_ALERT ) { - stateClass = "alert"; - } else { - stateClass = "idle"; - } - - if ( (!COMPACT_MONTAGE) && (this.type != 'WebSite') ) { - $('fpsValue'+this.id).set('text', this.status.fps); - $('stateValue'+this.id).set('text', stateStrings[this.alarmState]); - this.setStateClass($('monitorState'+this.id), stateClass); - } - this.setStateClass($('monitor'+this.id), stateClass); - - /*Stream could be an applet so can't use moo tools*/ - stream.className = stateClass; - - var isAlarmed = ( this.alarmState == STATE_ALARM || this.alarmState == STATE_ALERT ); - var wasAlarmed = ( this.lastAlarmState == STATE_ALARM || this.lastAlarmState == STATE_ALERT ); - - var newAlarm = ( isAlarmed && !wasAlarmed ); - var oldAlarm = ( !isAlarmed && wasAlarmed ); - - if ( newAlarm ) { - if ( false && SOUND_ON_ALARM ) { - // Enable the alarm sound - $('alarmSound').removeClass('hidden'); - } - if ( POPUP_ON_ALARM ) { - windowToFront(); - } - } - if ( false && SOUND_ON_ALARM ) { - if ( oldAlarm ) { - // Disable alarm sound - $('alarmSound').addClass('hidden'); - } - } - if ( this.status.auth ) { - if ( this.status.auth != auth_hash ) { - // Try to reload the image stream. - if ( stream ) { - stream.src = stream.src.replace(/auth=\w+/i, 'auth='+this.status.auth); - } - console.log("Changed auth from " + auth_hash + " to " + this.status.auth); - auth_hash = this.status.auth; - } - } // end if have a new auth hash - } // end if has state - } else { - console.error(respObj.message); - // Try to reload the image stream. - if ( stream ) { - if ( stream.src ) { - console.log('Reloading stream: ' + stream.src); - stream.src = stream.src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) )); - } else { - } - } else { - console.log('No stream to reload?'); - } - } // end if Ok or not - - var streamCmdTimeout = statusRefreshTimeout; - // The idea here is if we are alarmed, do updates faster. - // However, there is a timeout in the php side which isn't getting modified, - // so this may cause a problem. Also the server may only be able to update so fast. - //if ( this.alarmState == STATE_ALARM || this.alarmState == STATE_ALERT ) { - //streamCmdTimeout = streamCmdTimeout/5; - //} - this.streamCmdTimer = this.streamCmdQuery.delay(streamCmdTimeout, this); - this.lastAlarmState = this.alarmState; - }; - - this.streamCmdQuery = function(resent) { - if ( resent ) { - console.log(this.connKey+": timeout: Resending"); - this.streamCmdReq.cancel(); - } - //console.log("Starting CmdQuery for " + this.connKey ); - if ( this.type != 'WebSite' ) { - this.streamCmdReq.send(this.streamCmdParms+"&command="+CMD_QUERY); - } - }; - - if ( this.type != 'WebSite' ) { - this.streamCmdReq = new Request.JSON( { - url: this.url, - method: 'get', - timeout: AJAX_TIMEOUT, - onSuccess: this.getStreamCmdResponse.bind(this), - onTimeout: this.streamCmdQuery.bind(this, true), - onError: this.onError.bind(this), - onFailure: this.onFailure.bind(this), - link: 'cancel' - } ); - console.log("queueing for " + this.id + " " + this.connKey + " timeout is: " + AJAX_TIMEOUT); - requestQueue.addRequest("cmdReq"+this.id, this.streamCmdReq); - } -} // end function Monitor - /** * called when the layoutControl select element is changed, or the page * is rendered @@ -254,31 +50,44 @@ function selectLayout(element) { } Cookie.write('zmMontageLayout', layout_id, {duration: 10*365}); if ( layouts[layout_id].Name != 'Freeform' ) { // 'montage_freeform.css' ) { - Cookie.write( 'zmMontageScale', '', {duration: 10*365} ); + Cookie.write('zmMontageScale', '', {duration: 10*365}); $('scale').set('value', ''); - $('width').set('value', 'auto'); - for ( var i = 0, length = monitors.length; i < length; i++ ) { - var monitor = monitors[i]; - var streamImg = $('liveStream'+monitor.id); - if ( streamImg ) { - if ( streamImg.nodeName == 'IMG' ) { - var src = streamImg.src; - src = src.replace(/width=[\.\d]+/i, 'width=0' ); - if ( $j('#height').val() == 'auto' ) { - src = src.replace(/height=[\.\d]+/i, 'height=0' ); - streamImg.style.height = 'auto'; - } - if ( src != streamImg.src ) { - streamImg.src = ''; - streamImg.src = src; - } - } else if ( streamImg.nodeName == 'APPLET' || streamImg.nodeName == 'OBJECT' ) { - // APPLET's and OBJECTS need to be re-initialized - } - streamImg.style.width = '100%'; - } - } // end foreach monitor + $('width').set('value', '0'); + } else { + // Is freeform, we don't touch the width/height/scale settings, but we may need to update sizing and scales } + var width = parseInt($('width').get('value')); + var height = parseInt($('height').get('value')); + var scale = $('scale').get('value'); + + for ( var i = 0, length = monitors.length; i < length; i++ ) { + var monitor = monitors[i]; + + if ( scale ) { + stream_scale = scale; + } else if ( width ) { + stream_scale = parseInt(100*width/monitor.width); + } else if ( height ) { + stream_scale = parseInt(100*height/monitor.height); + } + var streamImg = $('liveStream'+monitor.id); + if ( streamImg ) { + if ( streamImg.nodeName == 'IMG' ) { + var src = streamImg.src; + src = src.replace(/scale=\d*/i, 'scale='+scale); + if ( height == '0' ) { + streamImg.style.height = 'auto'; + } + if ( src != streamImg.src ) { + streamImg.src = ''; + streamImg.src = src; + } + } else if ( streamImg.nodeName == 'APPLET' || streamImg.nodeName == 'OBJECT' ) { + // APPLET's and OBJECTS need to be re-initialized + } + streamImg.style.width = '100%'; + } + } // end foreach monitor } // end function selectLayout(element) /** @@ -306,8 +115,15 @@ function changeSize() { if ( streamImg.nodeName == 'IMG' ) { var src = streamImg.src; streamImg.src = ''; - src = src.replace(/width=[\.\d]+/i, 'width='+width); - src = src.replace(/height=[\.\d]+/i, 'height='+height); + var scale = 100; + if ( width ) { + scale = parseInt(100*width/monitor.width); + } else if ( height ) { + scale = parseInt(100*height/monitor.height); + } + // Note zms ignores width and height + src = src.replace(/scale=\d*/i, 'scale='+scale); + src = src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) )); streamImg.src = src; } @@ -320,6 +136,7 @@ function changeSize() { Cookie.write('zmMontageScale', '', {duration: 10*365}); Cookie.write('zmMontageWidth', width, {duration: 10*365}); Cookie.write('zmMontageHeight', height, {duration: 10*365}); + jQuery("#zmMontageLayout option:selected").removeAttr("selected"); //selectLayout('#zmMontageLayout'); } // end function changeSize() @@ -328,8 +145,8 @@ function changeSize() { */ function changeScale() { var scale = $('scale').get('value'); - $('width').set('value', 'auto'); - $('height').set('value', 'auto'); + $('width').set('value', '0'); //auto + $('height').set('value', '0'); //auto Cookie.write('zmMontageScale', scale, {duration: 10*365}); Cookie.write('zmMontageWidth', '', {duration: 10*365}); Cookie.write('zmMontageHeight', '', {duration: 10*365}); @@ -369,12 +186,8 @@ function changeScale() { //src = src.replace(/rand=\d+/i,'rand='+Math.floor((Math.random() * 1000000) )); if ( scale != '0' ) { src = src.replace(/scale=[\.\d]+/i, 'scale='+scale); - src = src.replace(/width=[\.\d]+/i, 'width='+newWidth); - src = src.replace(/height=[\.\d]+/i, 'height='+newHeight); } else { src = src.replace(/scale=[\.\d]+/i, 'scale=100'); - src = src.replace(/width=[\.\d]+/i, 'width='+monitorData[i].width); - src = src.replace(/height=[\.\d]+/i, 'height='+monitorData[i].height); } streamImg.src = src; } @@ -385,8 +198,8 @@ function changeScale() { streamImg.style.width = '100%'; streamImg.style.height = 'auto'; } - } - } + } // end if StreamImg + } // end foreach Monitor } function toGrid(value) { @@ -477,7 +290,7 @@ function initPage() { } for ( var i = 0, length = monitorData.length; i < length; i++ ) { - monitors[i] = new Monitor(monitorData[i]); + monitors[i] = new MonitorStream(monitorData[i]); // Start the fps and status updates. give a random delay so that we don't assault the server var delay = Math.round( (Math.random()+0.5)*statusRefreshTimeout ); diff --git a/web/skins/classic/views/js/montage.js.php b/web/skins/classic/views/js/montage.js.php index fc9a96b03..5a2aef2ed 100644 --- a/web/skins/classic/views/js/montage.js.php +++ b/web/skins/classic/views/js/montage.js.php @@ -50,7 +50,7 @@ layouts[0] = {}; // reserved, should hold which fields to clear when transitioni global $layouts; foreach ( $layouts as $layout ) { ?> -layouts[Id() ?>] = {"Name":"Name()?>","Positions":Positions() ?>}; +layouts[Id() ?>] = {"Name":"Name()?>","Positions":Positions())?$layout->Positions():'{}' ?>}; diff --git a/web/skins/classic/views/js/montagereview.js b/web/skins/classic/views/js/montagereview.js index fe9ccd3cd..5207f24d5 100644 --- a/web/skins/classic/views/js/montagereview.js +++ b/web/skins/classic/views/js/montagereview.js @@ -48,8 +48,7 @@ function evaluateLoadTimes() { function getFrame(monId, time, last_Frame) { if ( last_Frame ) { if ( - (last_Frame.TimeStampSecs <= time) - && + (last_Frame.TimeStampSecs <= time) && (last_Frame.EndTimeStampSecs >= time) ) { return last_Frame; @@ -104,12 +103,11 @@ function getFrame(monId, time, last_Frame) { continue; } if ( - e.FramesById[frame_id].TimeStampSecs == time - || ( - e.FramesById[frame_id].TimeStampSecs < time - && ( - (!e.FramesById[frame_id].NextTimeStampSecs) // only if event.EndTime is null - || + e.FramesById[frame_id].TimeStampSecs == time || + ( + e.FramesById[frame_id].TimeStampSecs < time && + ( + (!e.FramesById[frame_id].NextTimeStampSecs) || // only if event.EndTime is null (e.FramesById[frame_id].NextTimeStampSecs > time) ) ) diff --git a/web/skins/classic/views/js/newlog.js b/web/skins/classic/views/js/newlog.js new file mode 100644 index 000000000..f0b827912 --- /dev/null +++ b/web/skins/classic/views/js/newlog.js @@ -0,0 +1,101 @@ +var table = $j('#logTable'); + +/* +This is the format of the json object sent by bootstrap-table + +var params = +{ +"type":"get", +"data": + { + "search":"some search text", + "sort":"DateTime", + "order":"asc", + "offset":0, + "limit":25 + "filter": + { + "message":"some advanced search text" + "level":"some more advanced search text" + } + }, +"cache":true, +"contentType":"application/json", +"dataType":"json" +}; +*/ + +// Called by bootstrap-table to retrieve zm log data +function ajaxRequest(params) { + $j.getJSON(thisUrl + '?view=request&request=newlog&task=query', params.data) + .done(function(data) { + //console.log('Ajax parameters: ' + JSON.stringify(params)); + // rearrange the result into what bootstrap-table expects + params.success({total: data.total, totalNotFiltered: data.totalNotFiltered, rows: data.rows}); + updateHeaderStats(data); + }) + .fail(logAjaxFail); +} + +function updateHeaderStats(data) { + var pageNum = table.bootstrapTable('getOptions').pageNumber; + var pageSize = table.bootstrapTable('getOptions').pageSize; + var startRow = ( (pageNum - 1 ) * pageSize ) + 1; + var stopRow = pageNum * pageSize; + var newClass = (data.logstate == 'ok') ? 'text-success' : (data.logstate == 'alert' ? 'text-warning' : ((data.logstate == 'alarm' ? 'text-danger' : ''))); + + $j('#logState').text(data.logstate); + $j('#logState').removeClass('text-success'); + $j('#logState').removeClass('text-warning'); + $j('#logState').removeClass('text-danger'); + $j('#logState').addClass(newClass); + + $j('#totalLogs').text(data.total); + $j('#availLogs').text(data.totalNotFiltered); + $j('#lastUpdate').text(data.updated); + $j('#displayLogs').text(startRow + ' to ' + stopRow); +} + +function initPage() { + var backBtn = $j('#backBtn'); + + // Init the bootstrap-table with custom icons + table.bootstrapTable({icons: icons}); + + // Assign inf, err, fat, dbg color classes to the rows in the table + table.on('post-body.bs.table', function(data) { + $j('#logTable tr').each(function(ndx, row) { + var row = $j(row); + var level = row.find('td:eq(4)').text(); + + if (( level == 'FAT' ) || ( level == 'PNC' )) { + row.addClass('log-fat'); + } else if ( level == 'ERR' ) { + row.addClass('log-err'); + } else if ( level == 'WAR' ) { + row.addClass('log-war'); + } else if ( level == 'DBG' ) { + row.addClass('log-dbg'); + } + }); + }); + + // Don't enable the back button if there is no previous zm page to go back to + backBtn.prop('disabled', !document.referrer.length); + + // Manage the BACK button + document.getElementById("backBtn").addEventListener("click", function onBackClick(evt) { + evt.preventDefault(); + window.history.back(); + }); + + // Manage the REFRESH Button + document.getElementById("refreshBtn").addEventListener("click", function onRefreshClick(evt) { + evt.preventDefault(); + window.location.reload(true); + }); +} + +$j(document).ready(function() { + initPage(); +}); diff --git a/web/skins/classic/views/js/options.js b/web/skins/classic/views/js/options.js new file mode 100644 index 000000000..843225a67 --- /dev/null +++ b/web/skins/classic/views/js/options.js @@ -0,0 +1,76 @@ +// Load the Server Modal HTML via Ajax call +function getServerModal(sid) { + $j.getJSON(thisUrl + '?request=modal&modal=server&id=' + sid) + .done(function(data) { + if ( $j('#ServerModal').length ) { + $j('#ServerModal').replaceWith(data.html); + } else { + $j("body").append(data.html); + } + $j('#ServerModal').modal('show'); + // Manage the Save button + $j('#serverSubmitBtn').click(function(evt) { + evt.preventDefault(); + $j('#serverModalForm').submit(); + }); + }) + .fail(logAjaxFail); +} + +function enableServerModal() { + $j(".serverCol").click(function(evt) { + evt.preventDefault(); + var sid = $j(this).data('sid'); + getServerModal(sid); + }); + $j('#NewServerBtn').click(function(evt) { + evt.preventDefault(); + getServerModal(0); + }); +} + +// Load the Storage Modal HTML via Ajax call +function getStorageModal(sid) { + $j.getJSON(thisUrl + '?request=modal&modal=storage&id=' + sid) + .done(function(data) { + if ( $j('#storageModal').length ) { + $j('#storageModal').replaceWith(data.html); + } else { + $j("body").append(data.html); + } + $j('#storageModal').modal('show'); + // Manage the Save button + $j('#storageSubmitBtn').click(function(evt) { + evt.preventDefault(); + $j('#storageModalForm').submit(); + }); + }) + .fail(logAjaxFail); +} + +function enableStorageModal() { + $j(".storageCol").click(function(evt) { + evt.preventDefault(); + var sid = $j(this).data('sid'); + getStorageModal(sid); + }); + $j('#NewStorageBtn').click(function(evt) { + evt.preventDefault(); + getStorageModal(0); + }); +} + +function initPage() { + var NewStorageBtn = $j('#NewStorageBtn'); + var NewServerBtn = $j('#NewServerBtn'); + + if ( canEditSystem ) enableStorageModal(); + if ( canEditSystem ) enableServerModal(); + + NewStorageBtn.prop('disabled', !canEditSystem); + NewServerBtn.prop('disabled', !canEditSystem); +} + +$j(document).ready(function() { + initPage(); +}); diff --git a/web/skins/classic/views/js/options.js.php b/web/skins/classic/views/js/options.js.php index 88387134a..5281cde8c 100644 --- a/web/skins/classic/views/js/options.js.php +++ b/web/skins/classic/views/js/options.js.php @@ -1,4 +1,7 @@ + var restartWarning = ; if ( restartWarning ) { alert( "" ); } + +var canEditSystem = ; diff --git a/web/skins/classic/views/js/state.js b/web/skins/classic/views/js/state.js deleted file mode 100644 index e8b4db36d..000000000 --- a/web/skins/classic/views/js/state.js +++ /dev/null @@ -1,62 +0,0 @@ -$j(document).ready(function() { - // Enable or disable the Delete button depending on the selected run state - $j("#runState").change(function() { - runstate = $j(this).val(); - - if ( (runstate == 'stop') || (runstate == 'restart') || (runstate == 'start') || (runstate == 'default') ) { - $j("#btnDelete").prop("disabled", true); - } else { - $j("#btnDelete").prop("disabled", false); - } - }); - - // Enable or disable the Save button when entering a new state - $j("#newState").keyup(function() { - length = $j(this).val().length; - if ( length < 1 ) { - $j("#btnSave").prop("disabled", true); - } else { - $j("#btnSave").prop("disabled", false); - } - }); - - - // Delete a state - $j("#btnDelete").click(function() { - stateStuff('delete', $j("#runState").val()); - }); - - - // Save a new state - $j("#btnSave").click(function() { - stateStuff('save', undefined, $j("#newState").val()); - }); - - // Change state - $j("#btnApply").click(function() { - stateStuff('state', $j("#runState").val()); - }); - - function stateStuff(action, runState, newState) { - // the state action will redirect to console - var formData = { - 'view': 'state', - 'action': action, - 'apply': 1, - 'runState': runState, - 'newState': newState - }; - - $j("#pleasewait").toggleClass("hidden"); - - $j.ajax({ - type: 'POST', - url: thisUrl, - data: formData, - dataType: 'html', - timeout: 0 - }).done(function(data) { - location.reload(); - }); - } -}); diff --git a/web/skins/classic/views/js/state.js.php b/web/skins/classic/views/js/state.js.php deleted file mode 100644 index a7c14a0dc..000000000 --- a/web/skins/classic/views/js/state.js.php +++ /dev/null @@ -1,2 +0,0 @@ -var running = ; -var applying = ; diff --git a/web/skins/classic/views/js/stats.js b/web/skins/classic/views/js/stats.js new file mode 100644 index 000000000..ede551e31 --- /dev/null +++ b/web/skins/classic/views/js/stats.js @@ -0,0 +1,21 @@ +function initPage() { + var backBtn = $j('#backBtn'); + + // Disable the back button if there is nothing to go back to + backBtn.prop('disabled', !document.referrer.length); + + // Manage the BACK button + document.getElementById("backBtn").addEventListener("click", function onBackClick(evt) { + evt.preventDefault(); + window.history.back(); + }); + // Manage the REFRESH Button + document.getElementById("refreshBtn").addEventListener("click", function onRefreshClick(evt) { + evt.preventDefault(); + window.location.reload(true); + }); +} + +$j(document).ready(function() { + initPage(); +}); diff --git a/web/skins/classic/views/js/timeline.js b/web/skins/classic/views/js/timeline.js index 8742ac67b..85c73baa6 100644 --- a/web/skins/classic/views/js/timeline.js +++ b/web/skins/classic/views/js/timeline.js @@ -214,3 +214,30 @@ window.addEventListener('DOMContentLoaded', function() { }); }); +function initPage() { + var backBtn = $j('#backBtn'); + + // Don't enable the back button if there is no previous zm page to go back to + backBtn.prop('disabled', !document.referrer.length); + + // Manage the BACK button + document.getElementById("backBtn").addEventListener("click", function onBackClick(evt) { + evt.preventDefault(); + window.history.back(); + }); + + // Manage the REFRESH Button + document.getElementById("refreshBtn").addEventListener("click", function onRefreshClick(evt) { + evt.preventDefault(); + window.location.reload(true); + }); + // Manage the LIST Button + document.getElementById("listBtn").addEventListener("click", function onListClick(evt) { + evt.preventDefault(); + window.location.assign('?view=events'+filterQuery); + }); +} + +$j(document).ready(function() { + initPage(); +}); diff --git a/web/skins/classic/views/js/timeline.js.php b/web/skins/classic/views/js/timeline.js.php index b48fd83f6..474e403e0 100644 --- a/web/skins/classic/views/js/timeline.js.php +++ b/web/skins/classic/views/js/timeline.js.php @@ -1,6 +1,11 @@ var filterQuery = ''; diff --git a/web/skins/classic/views/js/video.js.php b/web/skins/classic/views/js/video.js.php index 0ee2214f5..e9bb78878 100644 --- a/web/skins/classic/views/js/video.js.php +++ b/web/skins/classic/views/js/video.js.php @@ -1,3 +1,6 @@ + var eventId = 'Id() ?>'; var videoGenSuccessString = ''; diff --git a/web/skins/classic/views/js/zone.js b/web/skins/classic/views/js/zone.js index b8926d789..22c7689cb 100644 --- a/web/skins/classic/views/js/zone.js +++ b/web/skins/classic/views/js/zone.js @@ -1,3 +1,7 @@ +var requestQueue = new Request.Queue({ + concurrent: monitorData.length, + stopOnFailure: false +}); function validateForm( form ) { var errors = new Array(); if ( selfIntersecting ) { @@ -178,14 +182,19 @@ function applyPreset() { function toPixels(field, maxValue) { if ( field.value != '' ) { field.value = Math.round((field.value*maxValue)/100); + if ( field.value > maxValue ) field.value = maxValue; } field.setAttribute('step', 1); - field.setAttribute('max', monitorArea); + field.setAttribute('max', maxValue); } +// maxValue is the max Pixels value which is normally the max area function toPercent(field, maxValue) { if ( field.value != '' ) { field.value = Math.round((100*100*field.value)/maxValue)/100; + if ( field.value > 100 ) { + field.value = 100; + } } field.setAttribute('step', 0.01); field.setAttribute('max', 100); @@ -244,15 +253,18 @@ function limitArea(field) { limitRange(field, minValue, maxValue); } -function highlightOn(point) { - var index = point.getAttribute('data-index'); +function highlightOn(index) { $('row'+index).addClass('highlight'); $('point'+index).addClass('highlight'); } -function highlightOff(point) { - var index = point.getAttribute('data-index'); - $('row'+index).removeClass('highlight'); +function highlightOff(index) { + row = $('row'+index); + if ( row ) { + row.removeClass('highlight'); + } else { + console.log("No row for index " + index); + } $('point'+index).removeClass('highlight'); } @@ -276,13 +288,18 @@ function getCoordString() { } function updateZoneImage() { + var imageFrame = $('imageFrame'); + var style = imageFrame.currentStyle || window.getComputedStyle(imageFrame); + + scale = (imageFrame.clientWidth - ( style.paddingLeft.toInt() + style.paddingRight.toInt() )) / maxX; var SVG = $('zoneSVG'); var Poly = $('zonePoly'); Poly.points.clear(); for ( var i = 0; i < zone['Points'].length; i++ ) { var Point = SVG.createSVGPoint(); Point.x = zone['Points'][i].x; - Point.y = zone['Points'][i].y; + //+ 2*padding_left; + Point.y = zone['Points'][i].y;// + 2*padding_top; Poly.points.appendItem(Point); } } @@ -305,37 +322,49 @@ function constrainValue(value, loVal, hiVal) { function updateActivePoint(index) { var point = $('point'+index); - var x = constrainValue(point.getStyle('left').toInt(), 0, maxX); - var y = constrainValue(point.getStyle('top').toInt(), 0, maxY); + var imageFrame = $('imageFrame'); + var style = imageFrame.currentStyle || window.getComputedStyle(imageFrame); + var padding_left = style.paddingLeft.toInt(); + var padding_top = style.paddingTop.toInt(); - $('newZone[Points]['+index+'][x]').value = x; - $('newZone[Points]['+index+'][y]').value = y; - zone['Points'][index].x = x; - zone['Points'][index].y = y; - console.log('hello'); + scale = (imageFrame.clientWidth - ( style.paddingLeft.toInt() + style.paddingRight.toInt() )) / maxX; + var left = point.getStyle('left').toInt(); + + if ( left < padding_left ) { + point.setStyle('left', style.paddingLeft); + left = padding_left.toInt(); + } + var top = point.getStyle('top').toInt(); + if ( top < padding_top ) { + point.setStyle('top', style.paddingTop); + top = padding_top; + } + + var x = constrainValue(Math.ceil(left / scale)-Math.ceil(padding_left/scale), 0, maxX); + var y = constrainValue(Math.ceil(top / scale)-Math.ceil(padding_top/scale), 0, maxY); + + zone['Points'][index].x = $('newZone[Points]['+index+'][x]').value = x; + zone['Points'][index].y = $('newZone[Points]['+index+'][y]').value = y; var Point = $('zonePoly').points.getItem(index); - console.log('hello'); Point.x = x; Point.y = y; updateArea(); -} +} // end function updateActivePoint(index) function addPoint(index) { var nextIndex = index+1; if ( index >= (zone['Points'].length-1) ) { nextIndex = 0; } + var newX = parseInt(Math.round((zone['Points'][index]['x']+zone['Points'][nextIndex]['x'])/2)); var newY = parseInt(Math.round((zone['Points'][index]['y']+zone['Points'][nextIndex]['y'])/2)); if ( nextIndex == 0 ) { zone['Points'][zone['Points'].length] = {'x': newX, 'y': newY}; } else { - zone['Points'].splice( nextIndex, 0, {'x': newX, 'y': newY} ); + zone['Points'].splice(nextIndex, 0, {'x': newX, 'y': newY}); } drawZonePoints(); - // drawZonePoints calls updateZoneImage - //updateZoneImage(); - //setActivePoint( nextIndex ); } function delPoint(index) { @@ -403,33 +432,37 @@ function saveChanges(element) { } function drawZonePoints() { - $('imageFrame').getElements('div.zonePoint').each( + var imageFrame = $('imageFrame'); + imageFrame.getElements('.zonePoint').each( function(element) { element.destroy(); }); + var style = imageFrame.currentStyle || window.getComputedStyle(imageFrame); + scale = (imageFrame.clientWidth - ( style.paddingLeft.toInt() + style.paddingRight.toInt() )) / maxX; + console.log("Scale = width: " + imageFrame.clientWidth); + for ( var i = 0; i < zone['Points'].length; i++ ) { + console.log("scale: " + scale + " x " + zone['Points'][i].x + " = " + Math.round(zone['Points'][i].x * scale)); var div = new Element('div', { 'id': 'point'+i, - 'data-index': i, + 'data-point-index': i, 'class': 'zonePoint', 'title': 'Point '+(i+1), 'styles': { - 'left': zone['Points'][i].x, - 'top': zone['Points'][i].y + 'left': (Math.round(zone['Points'][i].x * scale) + style.paddingLeft.toInt())+"px", + 'top': ((zone['Points'][i].y * scale).toInt() + style.paddingTop.toInt()) +"px" } }); - //div.addEvent('mouseover', highlightOn.pass(i)); - div.onmouseover = window['highlightOn'].bind(div, div); - div.onmouseout = window['highlightOff'].bind(div, div); + div.addEvent('mouseover', highlightOn.pass(i)); div.addEvent('mouseout', highlightOff.pass(i)); - div.inject($('imageFrame')); + div.inject(imageFrame); div.makeDraggable( { - 'container': $('imageFrame'), + 'container': imageFrame, 'onStart': setActivePoint.pass(i), 'onComplete': fixActivePoint.pass(i), 'onDrag': updateActivePoint.pass(i) } ); - } + } // end foreach point var tables = $('zonePoints').getElement('table').getElements('table'); tables.each( function(table) { @@ -439,7 +472,10 @@ function drawZonePoints() { for ( var i = 0; i < zone['Points'].length; i++ ) { var row; row = new Element('tr', {'id': 'row'+i}); - row.addEvents({'mouseover': highlightOn.pass(i), 'mouseout': highlightOff.pass(i)}); + row.addEvent('mouseover', highlightOn.pass(i)); + row.addEvent('mouseout', highlightOff.pass(i)); + //row.onmouseover = highlightOn.pass(i) + //row.onmouseout = window['highlightOff'].bind(div, div); var cell = new Element('td'); cell.set('text', i+1); cell.inject(row); @@ -490,195 +526,30 @@ function drawZonePoints() { cell.inject(row); row.inject(tables[i%tables.length].getElement('tbody')); - } + } // end foreach point // Sets up the SVG polygon updateZoneImage(); } -// -// Imported from watch.js and modified for new zone edit view -// - -var alarmState = STATE_IDLE; -var lastAlarmState = STATE_IDLE; - -function setAlarmState( currentAlarmState ) { - alarmState = currentAlarmState; - - var stateClass = ''; - if ( alarmState == STATE_ALARM ) { - stateClass = 'alarm'; - } else if ( alarmState == STATE_ALERT ) { - stateClass = 'alert'; - } - $('stateValue').set('text', stateStrings[alarmState]); - if ( stateClass ) { - $('stateValue').setProperty('class', stateClass); - } else { - $('stateValue').removeProperty('class'); +function streamCmdPause() { + for ( var i = 0, length = monitors.length; i < length; i++ ) { + monitors[i].pause(); } + document.getElementById('pauseBtn').style.display = 'none'; + document.getElementById('playBtn').style.display = 'inline'; } -var streamCmdParms = "view=request&request=stream&connkey="+connKey; -if ( auth_hash ) { - streamCmdParms += '&auth='+auth_hash; -} -var streamCmdReq = new Request.JSON( { - url: monitorUrl, - method: 'get', - timeout: AJAX_TIMEOUT, - link: 'cancel', - onSuccess: getStreamCmdResponse -} ); -var streamCmdTimer = null; - -var streamStatus; - -function getStreamCmdResponse(respObj, respText) { - watchdogOk("stream"); - if ( streamCmdTimer ) { - streamCmdTimer = clearTimeout(streamCmdTimer); - } - - if ( respObj.result == 'Ok' ) { - streamStatus = respObj.status; - $('fpsValue').set('text', streamStatus.fps); - - setAlarmState(streamStatus.state); - - if ( streamStatus.paused == true ) { - streamCmdPause(false); - } else if ( streamStatus.delayed == true && streamStatus.rate == 1 ) { - streamCmdPlay(false); - } - } else { - checkStreamForErrors('getStreamCmdResponse', respObj);//log them - if ( ! streamPause ) { - // Try to reload the image stream. - var streamImg = $('liveStream'+monitorId); - if ( streamImg ) { - streamImg.src = streamImg.src.replace(/rand=\d+/i, 'rand='+Math.floor(Math.random() * 1000000)); - } - } - } - - if ( !streamPause ) { - var streamCmdTimeout = statusRefreshTimeout; - if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT ) { - streamCmdTimeout = streamCmdTimeout/5; - } - streamCmdTimer = streamCmdQuery.delay(streamCmdTimeout); +function streamCmdPlay() { + for ( var i = 0, length = monitors.length; i < length; i++ ) { + monitors[i].play(); } + document.getElementById('playBtn').style.display = 'none'; + document.getElementById('pauseBtn').style.display = 'inline'; } -var streamPause = false; - -function streamCmdPauseToggle() { - if ( streamPause == true ) { - streamCmdPlay(true); - streamPause = false; - document.getElementById('pauseBtn').innerHTML = pauseString; - } else { - streamCmdPause(true); - streamPause = true; - document.getElementById('pauseBtn').innerHTML = playString; - } -} - -function streamCmdPause(action) { - if ( action ) { - streamCmdReq.send(streamCmdParms+"&command="+CMD_PAUSE); - } -} - -function streamCmdPlay(action) { - if ( action ) { - streamCmdReq.send(streamCmdParms+"&command="+CMD_PLAY); - } -} - -function streamCmdStop(action) { - if ( action ) { - streamCmdReq.send(streamCmdParms+"&command="+CMD_STOP); - } -} - -function streamCmdQuery() { - streamCmdReq.send(streamCmdParms+"&command="+CMD_QUERY); -} - -var statusCmdParms = "view=request&request=status&entity=monitor&id="+monitorId+"&element[]=Status&element[]=FrameRate"; -if ( auth_hash ) { - statusCmdParms += '&auth='+auth_hash; -} -var statusCmdReq = new Request.JSON( { - url: monitorUrl, - method: 'get', - data: statusCmdParms, - timeout: AJAX_TIMEOUT, - link: 'cancel', - onSuccess: getStatusCmdResponse -} ); -var statusCmdTimer = null; - -function getStatusCmdResponse(respObj, respText) { - watchdogOk("status"); - if ( statusCmdTimer ) { - statusCmdTimer = clearTimeout(statusCmdTimer); - } - - if ( respObj.result == 'Ok' ) { - $('fpsValue').set('text', respObj.monitor.FrameRate); - setAlarmState(respObj.monitor.Status); - } else { - checkStreamForErrors("getStatusCmdResponse", respObj); - } - - if ( ! streamPause ) { - var statusCmdTimeout = statusRefreshTimeout; - if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT ) { - statusCmdTimeout = statusCmdTimeout/5; - } - statusCmdTimer = statusCmdQuery.delay(statusCmdTimeout); - } -} - -function statusCmdQuery() { - statusCmdReq.send(); -} - -function fetchImage( streamImage ) { - streamImage.src = streamImage.src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) )); -} - -function appletRefresh() { - if ( streamStatus && (!streamStatus.paused && !streamStatus.delayed) ) { - var streamImg = $('liveStream'); - var parent = streamImg.getParent(); - streamImg.dispose(); - streamImg.inject( parent ); - if ( appletRefreshTime ) { - appletRefresh.delay( appletRefreshTime*1000 ); - } - } else { - appletRefresh.delay( 15*1000 ); //if we are paused or delayed check every 15 seconds if we are live yet... - } -} - -var watchdogInactive = { - 'stream': false, - 'status': false -}; - -var watchdogFunctions = { - 'stream': streamCmdQuery, - 'status': statusCmdQuery -}; - //Make sure the various refreshes are still taking effect function watchdogCheck(type) { if ( watchdogInactive[type] ) { - console.log("Detected streamWatch of type: " + type + " stopped, restarting"); watchdogFunctions[type](); watchdogInactive[type] = false; } else { @@ -689,6 +560,11 @@ function watchdogCheck(type) { function watchdogOk(type) { watchdogInactive[type] = false; } +function presetSelectorBlur() { + this.selectedIndex = 0; +} + +var monitors = new Array(); function initPage() { var form = document.zoneForm; @@ -696,6 +572,7 @@ function initPage() { //form.elements['newZone[Name]'].disabled = true; //form.elements['newZone[Type]'].disabled = true; form.presetSelector.disabled = true; + form.presetSelector.onblur = window['presetSelectorBlur'].bind(form.presetSelector, form.presetSelector); //form.elements['newZone[Units]'].disabled = true; if ( CheckMethod = form.elements['newZone[CheckMethod]'] ) { CheckMethod.disabled = true; @@ -761,11 +638,15 @@ function initPage() { } applyCheckMethod(); - drawZonePoints(); $('pauseBtn').onclick = function() { - streamCmdPauseToggle(); + streamCmdPause(); }; + $('playBtn').style.display = 'none'; // hide pause initially + $('playBtn').onclick = function() { + streamCmdPlay(); + }; + if ( el = $('saveBtn') ) { el.onclick = window['saveChanges'].bind(el, el); } @@ -776,34 +657,42 @@ function initPage() { }; } - // - // Imported from watch.js and modified for new zone edit view - // + for ( var i = 0, length = monitorData.length; i < length; i++ ) { + monitors[i] = new MonitorStream(monitorData[i]); - var delay = (Math.random()+0.1) * statusRefreshTimeout; - //console.log("Delay for status updates is: " + delay ); - if ( streamMode == 'single' ) { - statusCmdTimer = statusCmdQuery.delay(delay); - watchdogCheck.pass('status').periodical(statusRefreshTimeout*2); - } else { - streamCmdTimer = streamCmdQuery.delay(delay); - watchdogCheck.pass('stream').periodical(statusRefreshTimeout*2); + // Start the fps and status updates. give a random delay so that we don't assault the server + var delay = Math.round( (Math.random()+0.5)*statusRefreshTimeout ); + monitors[i].start(delay); } - if ( canStreamNative || (streamMode == 'single') ) { - var streamImg = $('imageFrame').getElement('img'); - if ( !streamImg ) { - streamImg = $('imageFrame').getElement('object'); - } - if ( streamMode == 'single' ) { - streamImg.addEvent('click', fetchImage.pass(streamImg)); - fetchImage.pass(streamImg).periodical(imageRefreshTimeout); - } - } + document.querySelectorAll('#imageFrame img').forEach(function(el) { + el.addEventListener("load", imageLoadEvent, {passive: true}); + }); + window.addEventListener("resize", drawZonePoints, {passive: true}); - if ( refreshApplet && appletRefreshTime ) { - appletRefresh.delay(appletRefreshTime*1000); - } + // Manage the BACK button + document.getElementById("backBtn").addEventListener("click", function onBackClick(evt) { + evt.preventDefault(); + window.history.back(); + }); + + // Disable the back button if there is nothing to go back to + $j('#backBtn').prop('disabled', !document.referrer.length); + + // Manage the REFRESH Button + document.getElementById("refreshBtn").addEventListener("click", function onRefreshClick(evt) { + evt.preventDefault(); + window.location.reload(true); + }); +} // initPage + +function imageLoadEvent() { + // We only need this event on the first image load to set dimensions. + // Turn it off after it has been called. + document.querySelectorAll('#imageFrame img').forEach(function(el) { + el.removeEventListener("load", imageLoadEvent, {passive: true}); + }); + drawZonePoints(); } function Polygon_calcArea(coords) { diff --git a/web/skins/classic/views/js/zone.js.php b/web/skins/classic/views/js/zone.js.php index c03264d7a..9fadea32c 100644 --- a/web/skins/classic/views/js/zone.js.php +++ b/web/skins/classic/views/js/zone.js.php @@ -58,6 +58,18 @@ zone['Points'][] = { 'x': ViewWidth()-1 ?>; var maxY = ViewHeight()-1 ?>; var monitorArea = ViewWidth() * $monitor->ViewHeight() ?>; + +var monitorData = new Array(); +monitorData[monitorData.length] = { + 'id': Id() ?>, + 'connKey': connKey() ?>, + 'width': ViewWidth() ?>, + 'height':ViewHeight() ?>, + 'url': 'UrlToIndex( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>', + 'type': 'Type() ?>', + 'refresh': 'Refresh() ?>' +}; + var selfIntersecting = ; var selfIntersectingString = ''; @@ -76,6 +88,7 @@ var minBlobLtMinFilterString = ''; var minBlobsLtMaxString = ''; +var deleteString = ""; // // Imported from watch.js.php and modified for new zone edit view // @@ -93,10 +106,6 @@ stateStrings[STATE_ALARM] = ""; stateStrings[STATE_ALERT] = ""; stateStrings[STATE_TAPE] = ""; -var pauseString = ""; -var playString = ""; - -var deleteString = ""; var CMD_PAUSE = ; var CMD_PLAY = ; diff --git a/web/skins/classic/views/js/zones.js b/web/skins/classic/views/js/zones.js index 3e5306930..a0eec294e 100644 --- a/web/skins/classic/views/js/zones.js +++ b/web/skins/classic/views/js/zones.js @@ -1,9 +1,46 @@ -var streamCmdParms = "view=request&request=stream&connkey="+connKey; -var streamCmdReq = new Request.JSON( {url: monitorUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel'} ); -function streamCmdQuit( action ) { +var requestQueue = new Request.Queue({ + concurrent: monitorData.length, + stopOnFailure: false +}); +function streamCmdQuit( ) { if ( action ) { streamCmdReq.send( streamCmdParms+"&command="+CMD_QUIT ); } } +// Manage the Add New Zone button +function AddNewZone(el) { + url = el.getAttribute('data-url'); + window.location.assign(url); +} + +var monitors = new Array(); + +function initPage() { + for ( var i = 0, length = monitorData.length; i < length; i++ ) { + monitors[i] = new MonitorStream(monitorData[i]); + + // Start the fps and status updates. give a random delay so that we don't assault the server + var delay = Math.round( (Math.random()+0.5)*statusRefreshTimeout ); + monitors[i].start(delay); + } + + // Manage the BACK button + document.getElementById("backBtn").addEventListener("click", function onBackClick(evt) { + evt.preventDefault(); + window.history.back(); + }); + + // Disable the back button if there is nothing to go back to + $j('#backBtn').prop('disabled', !document.referrer.length); + + // Manage the REFRESH Button + document.getElementById("refreshBtn").addEventListener("click", function onRefreshClick(evt) { + evt.preventDefault(); + window.location.reload(true); + }); +} + +window.addEventListener('DOMContentLoaded', initPage); + diff --git a/web/skins/classic/views/js/zones.js.php b/web/skins/classic/views/js/zones.js.php index 81248d94c..180a19d81 100644 --- a/web/skins/classic/views/js/zones.js.php +++ b/web/skins/classic/views/js/zones.js.php @@ -1,8 +1,40 @@ +var monitorData = new Array(); -var connKey = ''; -var monitorUrl = 'UrlToIndex() ) ?>'; +monitorData[monitorData.length] = { + 'id': Id() ?>, + 'connKey': connKey() ?>, + 'width': ViewWidth() ?>, + 'height':ViewHeight() ?>, + 'url': 'UrlToIndex( ZM_MIN_STREAMING_PORT ? ($monitor->Id() + ZM_MIN_STREAMING_PORT) : '') ?>', + 'type': 'Type() ?>', + 'refresh': 'Refresh() ?>' +}; + + +var STATE_IDLE = ; +var STATE_PREALARM = ; +var STATE_ALARM = ; +var STATE_ALERT = ; +var STATE_TAPE = ; + +var stateStrings = new Array(); +stateStrings[STATE_IDLE] = ""; +stateStrings[STATE_PREALARM] = ""; +stateStrings[STATE_ALARM] = ""; +stateStrings[STATE_ALERT] = ""; +stateStrings[STATE_TAPE] = ""; + + +var CMD_PAUSE = ; +var CMD_PLAY = ; +var CMD_STOP = ; +var CMD_QUERY = ; var CMD_QUIT = ; + +var statusRefreshTimeout = ; diff --git a/web/skins/classic/views/log.php b/web/skins/classic/views/log.php index c4343d4d1..8d2e9f293 100644 --- a/web/skins/classic/views/log.php +++ b/web/skins/classic/views/log.php @@ -28,6 +28,7 @@ $focusWindow = true; xhtmlHeaders(__FILE__, translate('SystemLog')); ?> +
-
-
-
-
-
-
-
-
- - - - - - - -
-
- - - - - -
-
- : -
- - -
-
-
-
- - + diff --git a/web/skins/classic/views/login.php b/web/skins/classic/views/login.php index 296a54887..e08bf91bc 100644 --- a/web/skins/classic/views/login.php +++ b/web/skins/classic/views/login.php @@ -36,5 +36,4 @@ if (
- - + diff --git a/web/skins/classic/views/logout.php b/web/skins/classic/views/logout.php deleted file mode 100644 index d68bd2b82..000000000 --- a/web/skins/classic/views/logout.php +++ /dev/null @@ -1,48 +0,0 @@ - - -
- -
-
- - -

-

- - - -

-
-
-
- - diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 43ed0b178..bab87da40 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -379,37 +379,17 @@ $codecs = array( 'MJPEG' => translate('MJPEG'), ); +$controls = ZM\Control::find(null, array('order'=>'lower(Name)')); + xhtmlHeaders(__FILE__, translate('Monitor').' - '.validHtmlStr($monitor->Name())); getBodyTopHTML(); +echo getNavBarHTML(); ?> -
- -
-
    +
    + +
    + + +
    + +
    +
    + + +
    + +

    - Name()) ?>Id() ) { ?> (Id()?>)

    + +
    + Configuration cloned from Monitor: +
    + +
    + + + +
    + +
    + + +
    + + +
    $value ) { + echo '
    '; ?> - - - - -GroupIds() as $group_id ) { -echo ''; -} -?> - - - - - - - - -Triggers() ) { - foreach ( explode(',', $monitor->Triggers()) as $newTrigger ) { -?> - -Type() != 'Local') ) { -?> - - - - - - - - - - - -Type()!= 'Remote' ) { -?> - - - -Type()!= 'Local' && $monitor->Type()!= 'Remote' && $monitor->Type()!= 'Ffmpeg' && $monitor->Type()!= 'Libvlc') ) { -?> - -Type()!= 'Ffmpeg' && $monitor->Type()!= 'Libvlc' )) { -?> - -Type()!= 'Remote' && $monitor->Type()!= 'File' && $monitor->Type()!= 'Ffmpeg' && $monitor->Type()!= 'Libvlc' && $monitor->Type()!= 'cURL' && $monitor->Type() != 'WebSite') ) { -?> - - - - - - - - - - - - - - - - - - -Type() != 'Remote' && $monitor->Protocol()!= 'rtsp') ) { -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
    - + - + - - + - + - + Type() != 'WebSite' ) { ?> - + - + - + Type() != 'Local' && $monitor->Type() != 'File' && $monitor->Type() != 'NVSocket' ) { ?> - + - + - + - + - + - + - - + + - - + - + - + - + Type() == 'Local' ) { ?> - + @@ -796,36 +656,36 @@ switch ( $tab ) { if ( ZM_HAS_V4L1 && $monitor->Method() == 'v4l1' ) { ?> - + - + - + - + - + - - + + - + - - + Type() == 'VNC' ) { ?> - + - + - + - + Type() == 'Remote' ) { ?> - + - + - + Type() == 'File' ) { ?> - + Type() == 'cURL' ) { ?> - - - + + + Type() == 'WebSite' ) { ?> - + @@ -903,29 +763,27 @@ include('_monitor_source_nvsocket.php'); - + - + Type() == 'Ffmpeg' || $monitor->Type() == 'Libvlc' ) { ?> - + - + - + Type() == 'Ffmpeg' ) { ?> - - @@ -949,11 +807,11 @@ include('_monitor_source_nvsocket.php'); if ( $monitor->Type() != 'NVSocket' && $monitor->Type() != 'WebSite' ) { ?> - + - + - + - + Type() == 'Local' ) { ?> - + Type() != 'WebSite' ) { ?> - + Type() == 'Remote' ) { ?> Protocol()!= 'rtsp' ) { echo ' style="display:none;"'; } ?>> - + - + - + - - + - - + - - + + - - + + - + - + - + - + - + - + - + + + + + - + - - + + - + - + - + - + - + - + - + ReturnL case 'x10' : { ?> - - - + + + ReturnL { ?> - + - + - + - + - + - + - + - + - + - + - + - + - + - + ReturnL ?>
    + 'None','auto'=>'Auto'); foreach ( ZM\Server::find(NULL, array('order'=>'lower(Name)')) as $Server ) { @@ -636,11 +496,11 @@ switch ( $tab ) {
    Type()); ?>
    Enabled() ? ' checked="checked"' : '' ?>/>
     ()
     () CAUTION: See the help text
     () CAUTION: See the help text @@ -710,11 +570,11 @@ switch ( $tab ) { } else { ?>
    RefBlendPerc()); ?>
    AlarmRefBlendPerc()); ?>
    +
    Method(), array('onchange'=>'submitTab', 'data-tab-name'=>$tab) ); ?>
    Channel()); ?>
    Format()); ?>
    Palette()); ?>
    Channel()); ?>
    Format()); ?>
    Palette()); ?>
    +
    V4LMultiBuffer() == '1' ? 'checked="checked"' : '' ) ?>/> V4LMultiBuffer() == '0' ? 'checked="checked"' : '' ) ?>/> @@ -834,7 +694,7 @@ switch ( $tab ) {
    Protocol(), "updateMethods( this );if(this.value=='rtsp'){\$('RTSPDescribe').setStyle('display','table-row');}else{\$('RTSPDescribe').hide();}" ); ?>
    Protocol() || $monitor->Protocol() == 'http' ) { @@ -878,24 +738,24 @@ include('_monitor_source_nvsocket.php'); ?>
    () ()
    ) + Method()) ?>
     (Type()), 'zmOptionHelp', 'optionhelp', '?' ) ?>)Type())) ?>
    - () + +
    - () + +
    Colours()) ?>
    () () @@ -984,11 +842,11 @@ include('_monitor_source_nvsocket.php');
    Orientation());?>
    Deinterlacing())?>
    Deinterlacing())?>
     () RTSPDescribe() ) { ?> checked="checked"/>
    'Default'); @@ -1033,7 +891,7 @@ include('_monitor_source_nvsocket.php');
    +
    'Disabled', @@ -1104,12 +962,12 @@ echo htmlSelect('newMonitor[OutputContainer]', $videowriter_containers, $monitor
     ()
    +
    Type() == 'Ffmpeg' ) { ?> RecordAudio() ) { ?> checked="checked"/> @@ -1124,19 +982,19 @@ echo htmlSelect('newMonitor[OutputContainer]', $videowriter_containers, $monitor { ?>
    LabelSize()) ?>
    ImageBufferCount() * $monitor->Width() * $monitor->Height() * $monitor->Colours(), 0) ?>
    Controllable() ) { ?> checked="checked"/>
    ControlId()); -if ( canEdit('Control') ) { - echo ' '.makePopupLink('?view=controlcaps', 'zmControlCaps', 'controlcaps', translate('Edit')); -} -?> +translate('None')); + foreach ( $controls as $control ) { + $controlTypes[$control->Id()] = $control->Name(); + } + + echo htmlSelect('newMonitor[ControlId]', $controlTypes, $monitor->ControlId()); + if ( canEdit('Control') ) { + echo ' '.makePopupLink('?view=controlcaps', 'zmControlCaps', 'controlcaps', translate('Edit')); + } +?> +
    TrackMotion() ) { ?> checked="checked"/>
    translate('None'), @@ -1218,7 +1088,7 @@ if ( canEdit('Control') ) { echo htmlSelect('newMonitor[ReturnLocation]', $return_options, $monitor->ReturnLocation()); ?>
    DefaultRate()); ?>
    DefaultScale()); ?>
    DefaultCodec()); ?>
        
         @@ -1316,7 +1186,7 @@ echo htmlSelect('newMonitor[ReturnLocation]', $return_options, $monitor->ReturnL
     () Exif() ) { ?> checked="checked"/>
    -
    - - +
    + +
    +
    + +
    - - +
    +
    + diff --git a/web/skins/classic/views/monitorpreset.php b/web/skins/classic/views/monitorpreset.php index ef5a6ac01..22c960587 100644 --- a/web/skins/classic/views/monitorpreset.php +++ b/web/skins/classic/views/monitorpreset.php @@ -36,10 +36,9 @@ $focusWindow = true; xhtmlHeaders(__FILE__, translate('MonitorPreset') ); ?> +
    -
    @@ -57,5 +56,4 @@ xhtmlHeaders(__FILE__, translate('MonitorPreset') );
    - - + diff --git a/web/skins/classic/views/monitorprobe.php b/web/skins/classic/views/monitorprobe.php index a76c67810..d670e0fcc 100644 --- a/web/skins/classic/views/monitorprobe.php +++ b/web/skins/classic/views/monitorprobe.php @@ -321,10 +321,9 @@ $focusWindow = true; xhtmlHeaders(__FILE__, translate('MonitorProbe') ); ?> +
    - +

    @@ -344,5 +343,4 @@ xhtmlHeaders(__FILE__, translate('MonitorProbe') );
    - - + diff --git a/web/skins/classic/views/montage.php b/web/skins/classic/views/montage.php index dfcba186e..1c62fddf4 100644 --- a/web/skins/classic/views/montage.php +++ b/web/skins/classic/views/montage.php @@ -49,13 +49,6 @@ $heights = array( '1080' => '1080px', ); -$scale = '100'; # actual - -if ( isset($_REQUEST['scale']) ) { - $scale = validInt($_REQUEST['scale']); -} else if ( isset($_COOKIE['zmMontageScale']) ) { - $scale = validInt($_COOKIE['zmMontageScale']); -} $layouts = ZM\MontageLayout::find(NULL, array('order'=>"lower('Name')")); $layoutsById = array(); @@ -96,8 +89,9 @@ if ( isset($_COOKIE['zmMontageWidth']) ) { $_SESSION['zmMontageWidth'] = $options['width'] = validInt($_COOKIE['zmMontageWidth']); #} elseif ( isset($_SESSION['zmMontageWidth']) and $_SESSION['zmMontageWidth'] ) { #$options['width'] = $_SESSION['zmMontageWidth']; -} else +} else { $options['width'] = 0; +} if ( isset($_COOKIE['zmMontageHeight']) ) { $_SESSION['zmMontageHeight'] = $options['height'] = validInt($_COOKIE['zmMontageHeight']); @@ -107,8 +101,14 @@ if ( isset($_COOKIE['zmMontageHeight']) ) { $options['height'] = 0; } -#if ( $scale ) - $options['scale'] = $scale; +$scale = '100'; # actual + +if ( isset($_REQUEST['scale']) ) { + $scale = validInt($_REQUEST['scale']); +} else if ( isset($_COOKIE['zmMontageScale']) ) { + $scale = validInt($_COOKIE['zmMontageScale']); +} +$options['scale'] = $scale; session_write_close(); @@ -118,7 +118,7 @@ $filterbar = ob_get_contents(); ob_end_clean(); $monitors = array(); -foreach( $displayMonitors as &$row ) { +foreach ( $displayMonitors as &$row ) { if ( $row['Function'] == 'None' ) continue; @@ -127,7 +127,6 @@ foreach( $displayMonitors as &$row ) { if ( ZM_OPT_CONTROL && $row['ControlId'] && $row['Controllable'] ) $showControl = true; - $row['connKey'] = generateConnKey(); if ( ! isset($widths[$row['Width']]) ) { $widths[$row['Width']] = $row['Width'].'px'; } @@ -142,9 +141,14 @@ xhtmlHeaders(__FILE__, translate('Montage'));
    -
    +ZM_PATH_SHUTDOWN is not defined. This is normally configured in /etc/zm/conf.d/01-system-paths.conf
    '; + } else if ( !file_exists(ZM_PATH_SHUTDOWN) ) { + echo '
    Path does not exist for ZM_PATH_SHUTDOWN. Current value is '.ZM_PATH_SHUTDOWN.'
    '; + } else { +?> +
    '.implode('
    ', $output).'

    '; - } - if ( isset($_POST['when']) and ($_POST['when'] != 'NOW') and ($action != 'cancel') ) { - echo '

    You may cancel this shutdown by clicking '.translate('Cancel').'

    '; - } + if ( isset($output) ) { + echo '

    '.implode('
    ', $output).'

    '; + } + if ( isset($_POST['when']) and ($_POST['when'] != 'NOW') and ($action != 'cancel') ) { + echo '

    You may cancel this shutdown by clicking '.translate('Cancel').'

    '; + } ?>

    Warning

    This command will either shutdown or restart all ZoneMinder Servers
    @@ -52,18 +60,20 @@ xhtmlHeaders(__FILE__, translate('Shutdown').' '.translate('Restart'));

    +
    - - + diff --git a/web/skins/classic/views/state.php b/web/skins/classic/views/state.php deleted file mode 100644 index 56227c37e..000000000 --- a/web/skins/classic/views/state.php +++ /dev/null @@ -1,87 +0,0 @@ - - diff --git a/web/skins/classic/views/stats.php b/web/skins/classic/views/stats.php index 6ad8edc1c..2cd5c69e4 100644 --- a/web/skins/classic/views/stats.php +++ b/web/skins/classic/views/stats.php @@ -27,85 +27,27 @@ if ( !canView( 'Events' ) ) $eid = validInt($_REQUEST['eid']); $fid = validInt($_REQUEST['fid']); -$sql = 'SELECT S.*,E.*,Z.Name AS ZoneName,Z.Units,Z.Area,M.Name AS MonitorName FROM Stats AS S LEFT JOIN Events AS E ON S.EventId = E.Id LEFT JOIN Zones AS Z ON S.ZoneId = Z.Id LEFT JOIN Monitors AS M ON E.MonitorId = M.Id WHERE S.EventId = ? AND S.FrameId = ? ORDER BY S.ZoneId'; -$stats = dbFetchAll( $sql, NULL, array( $eid, $fid ) ); - $focusWindow = true; xhtmlHeaders(__FILE__, translate('Stats')." - ".$eid." - ".$fid ); ?> +
    -
    - - + diff --git a/web/skins/classic/views/storage.php b/web/skins/classic/views/storage.php deleted file mode 100644 index e1642b142..000000000 --- a/web/skins/classic/views/storage.php +++ /dev/null @@ -1,115 +0,0 @@ -$_REQUEST['id'])) ) ) { - $view = 'error'; - return; - } -} else { - $newStorage = new ZM\Storage(); - $newStorage->Name(translate('NewStorage')); -} - -$type_options = array( 'local' => translate('Local'), 's3fs' => translate('s3fs') ); -$scheme_options = array( - 'Deep' => translate('Deep'), - 'Medium' => translate('Medium'), - 'Shallow' => translate('Shallow'), -); - -$servers = ZM\Server::find( null, array('order'=>'lower(Name)') ); -$ServersById = array(); -foreach ( $servers as $S ) { - $ServersById[$S->Id()] = $S; -} -$focusWindow = true; - -xhtmlHeaders(__FILE__, translate('Storage').' - '.$newStorage->Name()); -?> - -
    - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    'Remote / No Specific Server') + $ServersById, $newStorage->ServerId()); ?>
    Type()); ?>
    Scheme()); ?>
    - DoDelete() ? 'checked="checked"' : '' ?>/>Yes - DoDelete() ? '' : 'checked="checked"' ?>/>No -
    - Enabled() ? 'checked="checked"' : '' ?>/>Yes - Enabled() ? '' : 'checked="checked"' ?>/>No -
    -
    - - -
    -
    -
    -
    - - diff --git a/web/skins/classic/views/timeline.php b/web/skins/classic/views/timeline.php index cab313f52..d0d17d721 100644 --- a/web/skins/classic/views/timeline.php +++ b/web/skins/classic/views/timeline.php @@ -142,8 +142,11 @@ if ( !empty($user['MonitorIds']) ) { } $tree = false; -if ( isset($_REQUEST['filter']) ) - $tree = parseFilterToTree($_REQUEST['filter']['Query']); +if ( isset($_REQUEST['filter']) ) { + $filter = ZM\Filter::parse($_REQUEST['filter']); + $tree = $filter->tree(); + ZM\Warning("Parse tree: " . print_r($tree,true)); +} if ( isset($_REQUEST['range']) ) $range = validHtmlStr($_REQUEST['range']); @@ -497,7 +500,7 @@ for ( $i = 0; $i < $chart['graph']['width']; $i++ ) { } # end foreach MonitorId } # end foreach x -ZM\Logger::Debug(print_r( $monEventSlots,true )); +//ZM\Logger::Debug(print_r( $monEventSlots,true )); //print_r( $monFrameSlots ); //print_r( $chart ); @@ -673,18 +676,17 @@ $focusWindow = true; xhtmlHeaders(__FILE__, translate('Timeline')); ?> -
    -