diff --git a/.github/stale.yml b/.github/stale.yml
index 9ff190b1f..4dde9b5a7 100644
--- a/.github/stale.yml
+++ b/.github/stale.yml
@@ -1,10 +1,10 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an issue becomes stale
-daysUntilStale: 60
+daysUntilStale: 180
# Number of days of inactivity before a stale issue is closed
-daysUntilClose: 7
+daysUntilClose: 30
# Issues with these labels will never be considered stale
exemptLabels:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cca9fe82e..6d453f498 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -875,7 +875,6 @@ configure_file(zmlinkcontent.sh.in "${CMAKE_CURRENT_BINARY_DIR}/zmlinkcontent.sh
# Create a target for man pages
include(Pod2Man)
-ADD_MANPAGE_TARGET()
# Process subdirectories
diff --git a/cmake/Modules/Pod2Man.cmake b/cmake/Modules/Pod2Man.cmake
index 734be239b..f1c0e400a 100644
--- a/cmake/Modules/Pod2Man.cmake
+++ b/cmake/Modules/Pod2Man.cmake
@@ -53,8 +53,7 @@ MACRO(POD2MAN PODFILE MANFILE SECTION MANPAGE_DEST_PREFIX)
SET(MANPAGE_TARGET "man-${MANFILE}")
- ADD_CUSTOM_TARGET(${MANPAGE_TARGET} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${MANFILE}.${SECTION}.gz)
- ADD_DEPENDENCIES(man ${MANPAGE_TARGET})
+ ADD_CUSTOM_TARGET(${MANPAGE_TARGET} ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${MANFILE}.${SECTION}.gz)
INSTALL(
FILES ${CMAKE_CURRENT_BINARY_DIR}/${MANFILE}.${SECTION}.gz
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 6b561a116..eb687e2e3 100644
--- a/db/zm_create.sql.in
+++ b/db/zm_create.sql.in
@@ -476,7 +476,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.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/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/distros/beowulf/patches/series b/distros/beowulf/patches/series
new file mode 100644
index 000000000..e69de29bb
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/zoneminder.spec b/distros/redhat/zoneminder.spec
index c3458074c..637630324 100644
--- a/distros/redhat/zoneminder.spec
+++ b/distros/redhat/zoneminder.spec
@@ -28,7 +28,7 @@
%global _hardened_build 1
Name: zoneminder
-Version: 1.34.14
+Version: 1.34.20
Release: 1%{?dist}
Summary: A camera monitoring and analysis tool
Group: System Environment/Daemons
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/scripts/CMakeLists.txt b/scripts/CMakeLists.txt
index bd1885fbe..891e5583a 100644
--- a/scripts/CMakeLists.txt
+++ b/scripts/CMakeLists.txt
@@ -29,7 +29,7 @@ configure_file(zm.in "${CMAKE_CURRENT_BINARY_DIR}/zm" @ONLY)
#configure_file(zmeventdump.in zmeventdump @ONLY)
# Generate man files for the perl scripts destined for the bin folder
-file(GLOB perlscripts "*.pl")
+file(GLOB perlscripts "${CMAKE_CURRENT_BINARY_DIR}/*.pl")
FOREACH(PERLSCRIPT ${perlscripts})
get_filename_component(PERLSCRIPTNAME ${PERLSCRIPT} NAME)
POD2MAN(${PERLSCRIPT} zoneminder-${PERLSCRIPTNAME} 8 ${ZM_MANPAGE_DEST_PREFIX})
diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/DCS5020L.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/DCS5020L.pm
index 4f14e787a..2b2cf3fd2 100644
--- a/scripts/ZoneMinder/lib/ZoneMinder/Control/DCS5020L.pm
+++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/DCS5020L.pm
@@ -69,9 +69,9 @@ sub sendCmd {
my $result = undef;
- printMsg($cmd, 'Tx');
+ $self->printMsg($cmd, 'Tx');
- my $req = HTTP::Request->new( POST=>"http://$self->{Monitor}->{ControlAddress}/$cgi.cgi" );
+ my $req = HTTP::Request->new(POST=>"http://$self->{Monitor}->{ControlAddress}/$cgi.cgi");
$req->content($cmd);
my $res = $self->{ua}->request($req);
diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/HikVision.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/HikVision.pm
index a9f8d8f1b..a62c756d8 100644
--- a/scripts/ZoneMinder/lib/ZoneMinder/Control/HikVision.pm
+++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/HikVision.pm
@@ -143,10 +143,10 @@ sub PutCmd {
} else {
Info('Missing username and password in Control Address.');
}
- Fatal($res->status_line);
+ Error($res->status_line);
}
} else {
- Fatal($res->status_line);
+ Error($res->status_line);
}
} # end unless res->is_success
} # end sub putCmd
diff --git a/scripts/zmcontrol.pl.in b/scripts/zmcontrol.pl.in
index eb1718655..74886b4d4 100644
--- a/scripts/zmcontrol.pl.in
+++ b/scripts/zmcontrol.pl.in
@@ -49,9 +49,9 @@ my %options;
GetOptions(
'id=i' =>\$id,
'command=s' =>\$options{command},
- 'xcoord=i' =>\$options{xcoord},
- 'ycoord=i' =>\$options{ycoord},
- 'speed=i' =>\$options{speed},
+ 'xcoord=f' =>\$options{xcoord},
+ 'ycoord=f' =>\$options{ycoord},
+ 'speed=f' =>\$options{speed},
'step=i' =>\$options{step},
'panspeed=i' =>\$options{panspeed},
'tiltspeed=i' =>\$options{tiltspeed},
diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in
index 4ebb9211b..3ab910469 100644
--- a/scripts/zmdc.pl.in
+++ b/scripts/zmdc.pl.in
@@ -160,7 +160,7 @@ if ( !$server_up ) {
use ZoneMinder::Server qw(CpuLoad);
if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef,
'NotRunning', &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) {
- Error("Failed Updating status of Server record to Not RUnning for Id=$Config{ZM_SERVER_ID}" . $dbh->errstr());
+ Error('Failed Updating status of Server record to Not Running for Id='.$Config{ZM_SERVER_ID}.': '.$dbh->errstr());
}
}
# Server is not up. Some commands can still be handled
@@ -173,7 +173,7 @@ if ( !$server_up ) {
print("stopped\n");
exit();
} elsif ( $command ne 'startup' ) {
- print('Unable to connect to server using socket at ' . SOCK_FILE . "\n");
+ print('Unable to connect to server using socket at '.SOCK_FILE."\n");
exit(-1);
}
@@ -189,10 +189,10 @@ if ( !$server_up ) {
socket(CLIENT, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!");
my $attempts = 0;
- while( !connect(CLIENT, $saddr) ) {
+ while ( !connect(CLIENT, $saddr) ) {
$attempts++;
- Debug('Waiting for zmdc.pl server process at '.SOCK_FILE.", attempt $attempts");
- Fatal("Can't connect: $!") if $attempts > MAX_CONNECT_DELAY;
+ Debug('Waiting for zmdc.pl server process at '.SOCK_FILE.', attempt '.$attempts);
+ Fatal('Can\'t connect to zmdc.pl server process at '.SOCK_FILE.': '.$!) if $attempts > MAX_CONNECT_DELAY;
usleep(200000);
} # end while
} elsif ( defined($cpid) ) {
@@ -255,13 +255,13 @@ sub run {
close($PID);
} else {
# Log not initialized at this point so use die instead
- die "Can't open pid file at ".ZM_PID."\n";
+ die 'Can\'t open pid file at '.ZM_PID."\n";
}
my $fd = 0;
# This also closes dbh and CLIENT and SERVER
- while( $fd < POSIX::sysconf(&POSIX::_SC_OPEN_MAX) ) {
+ while ( $fd < POSIX::sysconf(&POSIX::_SC_OPEN_MAX) ) {
POSIX::close($fd++);
}
@@ -301,13 +301,14 @@ sub run {
my $timeout = 1;
my $secs_count = 0;
- while( !$zm_terminate ) {
+ while ( !$zm_terminate ) {
if ( $Config{ZM_SERVER_ID} ) {
if ( ! ( $secs_count % 60 ) ) {
while ( (!$zm_terminate) and !($dbh and $dbh->ping()) ) {
Warning("Not connected to db ($dbh)".($dbh?' ping('.$dbh->ping().')':''). ($DBI::errstr?" errstr($DBI::errstr)":'').' Reconnecting');
$dbh = zmDbConnect();
+ sleep 10 if !$dbh;
}
last if $zm_terminate;
diff --git a/scripts/zmstats.pl.in b/scripts/zmstats.pl.in
index 044f7e1ce..555d9c602 100644
--- a/scripts/zmstats.pl.in
+++ b/scripts/zmstats.pl.in
@@ -48,6 +48,49 @@ while( 1 ) {
$dbh->do('DELETE FROM Events_Week WHERE StartTime < DATE_SUB(NOW(), INTERVAL 1 week)') or Error($dbh->errstr());
$dbh->do('DELETE FROM Events_Month WHERE StartTime < DATE_SUB(NOW(), INTERVAL 1 month)') or Error($dbh->errstr());
+ # Prune the Logs table if required
+ if ( $Config{ZM_LOG_DATABASE_LIMIT} ) {
+ if ( $Config{ZM_LOG_DATABASE_LIMIT} =~ /^\d+$/ ) {
+ # Number of rows
+ my $selectLogRowCountSql = 'SELECT count(*) AS `Rows` FROM `Logs`';
+ my $selectLogRowCountSth = $dbh->prepare_cached( $selectLogRowCountSql )
+ or Fatal("Can't prepare '$selectLogRowCountSql': ".$dbh->errstr());
+ my $res = $selectLogRowCountSth->execute()
+ or Fatal("Can't execute: ".$selectLogRowCountSth->errstr());
+ my $row = $selectLogRowCountSth->fetchrow_hashref();
+ my $logRows = $row->{Rows};
+ if ( $logRows > $Config{ZM_LOG_DATABASE_LIMIT} ) {
+ my $deleteLogByRowsSql = 'DELETE low_priority FROM `Logs` ORDER BY `TimeKey` ASC LIMIT ?';
+ my $deleteLogByRowsSth = $dbh->prepare_cached( $deleteLogByRowsSql )
+ or Fatal("Can't prepare '$deleteLogByRowsSql': ".$dbh->errstr());
+ $res = $deleteLogByRowsSth->execute( $logRows - $Config{ZM_LOG_DATABASE_LIMIT} )
+ or Fatal("Can't execute: ".$deleteLogByRowsSth->errstr());
+ if ( $deleteLogByRowsSth->rows() ) {
+ Debug('Deleted '.$deleteLogByRowsSth->rows().' log table entries by count');
+ }
+ }
+ } else {
+ # Time of record
+
+ # 7 days is invalid. We need to remove the s
+ if ( $Config{ZM_LOG_DATABASE_LIMIT} =~ /^(.*)s$/ ) {
+ $Config{ZM_LOG_DATABASE_LIMIT} = $1;
+ }
+ my $deleted_rows;
+ do {
+ my $deleteLogByTimeSql =
+ 'DELETE FROM `Logs`
+ WHERE `TimeKey` < unix_timestamp(now() - interval '.$Config{ZM_LOG_DATABASE_LIMIT}.') LIMIT 100';
+ my $deleteLogByTimeSth = $dbh->prepare_cached( $deleteLogByTimeSql )
+ or Fatal("Can't prepare '$deleteLogByTimeSql': ".$dbh->errstr());
+ my $res = $deleteLogByTimeSth->execute()
+ or Fatal("Can't execute: ".$deleteLogByTimeSth->errstr());
+ $deleted_rows = $deleteLogByTimeSth->rows();
+ Debug("Deleted $deleted_rows log table entries by time");
+ } while ( $deleted_rows );
+ }
+ } # end if ZM_LOG_DATABASE_LIMIT
+
sleep($Config{ZM_STATS_UPDATE_INTERVAL});
} # end while (1)
diff --git a/scripts/zmtrack.pl.in b/scripts/zmtrack.pl.in
index 58798e5de..10db09664 100644
--- a/scripts/zmtrack.pl.in
+++ b/scripts/zmtrack.pl.in
@@ -119,7 +119,6 @@ if ( !$monitor->{CanMoveMap} ) {
}
}
-Debug("Found monitor for id '$monitor'");
exit(-1) if !zmMemVerify($monitor);
sub Suspend {
diff --git a/scripts/zmupdate.pl.in b/scripts/zmupdate.pl.in
index 3662b6655..925e58006 100644
--- a/scripts/zmupdate.pl.in
+++ b/scripts/zmupdate.pl.in
@@ -121,6 +121,8 @@ GetOptions(
my $dbh = zmDbConnect(undef, { mysql_multi_statements=>1 } );
$Config{ZM_DB_USER} = $dbUser;
$Config{ZM_DB_PASS} = $dbPass;
+# we escape dbpass with single quotes so that $ in the password has no effect, but dbpass could have a ' in it.
+$dbPass =~ s/'/\\'/g;
if ( ! ($check || $freshen || $rename || $zoneFix || $migrateEvents || $version) ) {
if ( $Config{ZM_DYN_DB_VERSION} ) {
@@ -384,21 +386,22 @@ if ( $version ) {
my $command = 'mysqldump';
if ( defined($portOrSocket) ) {
if ( $portOrSocket =~ /^\// ) {
- $command .= " -S".$portOrSocket;
+ $command .= ' -S'.$portOrSocket;
} else {
- $command .= " -h".$host." -P".$portOrSocket;
+ $command .= ' -h'.$host.' -P'.$portOrSocket;
}
} else {
- $command .= " -h".$host;
+ $command .= ' -h'.$host;
}
if ( $dbUser ) {
$command .= ' -u'.$dbUser;
- $command .= ' -p"'.$dbPass.'"' if $dbPass;
+ $command .= ' -p\''.$dbPass.'\'' if $dbPass;
}
- my $backup = "@ZM_TMPDIR@/".$Config{ZM_DB_NAME}."-".$version.".dump";
- $command .= " --add-drop-table --databases ".$Config{ZM_DB_NAME}." > ".$backup;
- print( "Creating backup to $backup. This may take several minutes.\n" );
- print( "Executing '$command'\n" ) if ( logDebugging() );
+ my $backup = '@ZM_TMPDIR@/'.$Config{ZM_DB_NAME}.'-'.$version.'.dump';
+ $command .= ' --add-drop-table --databases '.$Config{ZM_DB_NAME}.' > '.$backup;
+ print("Creating backup to $backup. This may take several minutes.\n");
+ ($command) = $command =~ /(.*)/; # detaint
+ print("Executing '$command'\n") if logDebugging();
my $output = qx($command);
my $status = $? >> 8;
if ( $status || logDebugging() ) {
@@ -969,7 +972,7 @@ sub patchDB {
my $dbh = shift;
my $version = shift;
- my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ );
+ my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ ) if $Config{ZM_DB_HOST};
my $command = 'mysql';
if ( defined($portOrSocket) ) {
if ( $portOrSocket =~ /^\// ) {
@@ -977,12 +980,12 @@ sub patchDB {
} else {
$command .= ' -h'.$host.' -P'.$portOrSocket;
}
- } else {
+ } elsif ( $host ) {
$command .= ' -h'.$host;
}
if ( $dbUser ) {
$command .= ' -u'.$dbUser;
- $command .= ' -p"'.$dbPass.'"' if $dbPass;
+ $command .= ' -p\''.$dbPass.'\'' if $dbPass;
}
$command .= ' '.$Config{ZM_DB_NAME}.' < ';
if ( $updateDir ) {
diff --git a/src/zm_camera.cpp b/src/zm_camera.cpp
index 420d5961a..5cb558645 100644
--- a/src/zm_camera.cpp
+++ b/src/zm_camera.cpp
@@ -48,11 +48,12 @@ Camera::Camera(
record_audio(p_record_audio),
bytes(0)
{
+ linesize = width * colours;
pixels = width * height;
- imagesize = pixels * colours;
+ imagesize = height * linesize;
- Debug(2,"New camera id: %d width: %d height: %d colours: %d subpixelorder: %d capture: %d",
- monitor_id, width, height, colours, subpixelorder, capture);
+ 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;
}
diff --git a/src/zm_camera.h b/src/zm_camera.h
index a6f576af2..32517814b 100644
--- a/src/zm_camera.h
+++ b/src/zm_camera.h
@@ -41,6 +41,7 @@ protected:
Monitor * monitor; // Null on instantiation, set as soon as possible.
SourceType type;
unsigned int width;
+ unsigned int linesize;
unsigned int height;
unsigned int colours;
unsigned int subpixelorder;
@@ -69,6 +70,7 @@ public:
bool IsLibvlc() const { return type == LIBVLC_SRC; }
bool IscURL() const { return type == CURL_SRC; }
unsigned int Width() const { return width; }
+ unsigned int LineSize() const { return linesize; }
unsigned int Height() const { return height; }
unsigned int Colours() const { return colours; }
unsigned int SubpixelOrder() const { return subpixelorder; }
diff --git a/src/zm_event.cpp b/src/zm_event.cpp
index e564479f3..803724bf5 100644
--- a/src/zm_event.cpp
+++ b/src/zm_event.cpp
@@ -206,7 +206,12 @@ Event::Event(
/* X264 MP4 video writer */
if ( monitor->GetOptVideoWriter() == Monitor::X264ENCODE ) {
#if ZM_HAVE_VIDEOWRITER_X264MP4
- videowriter = new X264MP4Writer(video_file, monitor->Width(), monitor->Height(), monitor->Colours(), monitor->SubpixelOrder(), monitor->GetOptEncoderParams());
+ videowriter = new X264MP4Writer(video_file,
+ monitor->Width(),
+ monitor->Height(),
+ monitor->Colours(),
+ monitor->SubpixelOrder(),
+ monitor->GetOptEncoderParamsVec());
#else
Error("ZoneMinder was not compiled with the X264 MP4 video writer, check dependencies (x264 and mp4v2)");
#endif
diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp
index d081f4e76..8eaa9cc8f 100644
--- a/src/zm_eventstream.cpp
+++ b/src/zm_eventstream.cpp
@@ -807,29 +807,38 @@ Debug(1, "Loading image");
if ( send_raw ) {
#if HAVE_SENDFILE
- fprintf(stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size);
+ 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 );
+ 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 */
- Error("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
+ Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
return false;
}
}
#else
- fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size);
- if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
+ 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 */
- Error("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
+ 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);
- fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size);
- if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
+ 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;
}
diff --git a/src/zm_ffmpeg.h b/src/zm_ffmpeg.h
index 73afff3e3..8adad7301 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 11c25addc..2ca712db8 100644
--- a/src/zm_ffmpeg_camera.cpp
+++ b/src/zm_ffmpeg_camera.cpp
@@ -63,31 +63,31 @@ static enum AVPixelFormat get_hw_format(
}
#if !LIBAVUTIL_VERSION_CHECK(56, 22, 0, 14, 0)
static enum AVPixelFormat find_fmt_by_hw_type(const enum AVHWDeviceType type) {
- enum AVPixelFormat fmt;
- switch (type) {
+ enum AVPixelFormat fmt;
+ switch (type) {
case AV_HWDEVICE_TYPE_VAAPI:
- fmt = AV_PIX_FMT_VAAPI;
- break;
+ fmt = AV_PIX_FMT_VAAPI;
+ break;
case AV_HWDEVICE_TYPE_DXVA2:
- fmt = AV_PIX_FMT_DXVA2_VLD;
- break;
+ fmt = AV_PIX_FMT_DXVA2_VLD;
+ break;
case AV_HWDEVICE_TYPE_D3D11VA:
- fmt = AV_PIX_FMT_D3D11;
- break;
+ fmt = AV_PIX_FMT_D3D11;
+ break;
case AV_HWDEVICE_TYPE_VDPAU:
- fmt = AV_PIX_FMT_VDPAU;
- break;
+ fmt = AV_PIX_FMT_VDPAU;
+ break;
case AV_HWDEVICE_TYPE_CUDA:
- fmt = AV_PIX_FMT_CUDA;
- break;
+ fmt = AV_PIX_FMT_CUDA;
+ break;
case AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
- fmt = AV_PIX_FMT_VIDEOTOOLBOX;
- break;
+ fmt = AV_PIX_FMT_VIDEOTOOLBOX;
+ break;
default:
- fmt = AV_PIX_FMT_NONE;
- break;
- }
- return fmt;
+ fmt = AV_PIX_FMT_NONE;
+ break;
+ }
+ return fmt;
}
#endif
#endif
@@ -174,6 +174,20 @@ FfmpegCamera::FfmpegCamera(
} else {
Panic("Unexpected colours: %d", colours);
}
+
+ // 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;
+ imagesize = av_image_get_buffer_size(imagePixFormat, width, height, alignment);
+ // av_image_get_linesize isn't aligned, so we have to do that.
+ linesize = FFALIGN(av_image_get_linesize(imagePixFormat, width, 0), alignment);
+#else
+ alignment = 1;
+ linesize = FFALIGN(av_image_get_linesize(imagePixFormat, width, 0), alignment);
+ imagesize = avpicture_get_size(imagePixFormat, width, height);
+#endif
+
+ Debug(1, "ffmpegcamera: width %d height %d linesize %d colours %d imagesize %d", width, height, linesize, colours, imagesize);
} // FfmpegCamera::FfmpegCamera
FfmpegCamera::~FfmpegCamera() {
@@ -194,12 +208,12 @@ void FfmpegCamera::Terminate() {
int FfmpegCamera::PrimeCapture() {
if ( mCanCapture ) {
- Info("Priming capture from %s, Closing", mPath.c_str());
+ Debug(1, "Priming capture from %s, Closing", mPath.c_str());
Close();
}
mVideoStreamId = -1;
mAudioStreamId = -1;
- Info("Priming capture from %s", mPath.c_str());
+ Debug(1, "Priming capture from %s", mPath.c_str());
return OpenFfmpeg();
}
@@ -608,16 +622,6 @@ int FfmpegCamera::OpenFfmpeg() {
mFrame->width = width;
mFrame->height = height;
-#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
- int pSize = av_image_get_buffer_size(imagePixFormat, width, height, 1);
-#else
- int pSize = avpicture_get_size(imagePixFormat, width, height);
-#endif
-
- if ( (unsigned int)pSize != imagesize ) {
- Error("Image size mismatch. Required: %d Available: %d", pSize, imagesize);
- return -1;
- }
#if HAVE_LIBSWSCALE
if ( !sws_isSupportedInput(mVideoCodecContext->pix_fmt) ) {
@@ -976,10 +980,12 @@ int FfmpegCamera::CaptureAndRecord(
return -1;
}
#if HAVE_LIBAVUTIL_HWCONTEXT_H
+#if LIBAVCODEC_VERSION_CHECK(57, 89, 0, 89, 0)
if ( (ret == AVERROR_INVALIDDATA ) && (hw_pix_fmt != AV_PIX_FMT_NONE) ) {
use_hwaccel = false;
return -1;
}
+#endif
#endif
}
zm_av_packet_unref(&packet);
@@ -1087,11 +1093,18 @@ int FfmpegCamera::transfer_to_image(
int size = av_image_fill_arrays(
output_frame->data, output_frame->linesize,
directbuffer, imagePixFormat, width, height,
- (AV_PIX_FMT_RGBA == imagePixFormat ? 32 : 1)
+ alignment
);
if ( size < 0 ) {
Error("Problem setting up data pointers into image %s",
av_make_error_string(size).c_str());
+ } else {
+ Debug(4, "av_image_fill_array %dx%d alignment: %d = %d, buffer size is %d",
+ width, height, alignment, size, image.Size());
+ }
+ Debug(1, "ffmpegcamera: width %d height %d linesize %d colours %d imagesize %d", width, height, linesize, colours, imagesize);
+ if ( linesize != (unsigned int)output_frame->linesize[0] ) {
+ Error("Bad linesize expected %d got %d", linesize, output_frame->linesize[0]);
}
#else
avpicture_fill((AVPicture *)output_frame, directbuffer,
diff --git a/src/zm_ffmpeg_camera.h b/src/zm_ffmpeg_camera.h
index badf90834..ce5868690 100644
--- a/src/zm_ffmpeg_camera.h
+++ b/src/zm_ffmpeg_camera.h
@@ -45,6 +45,8 @@ class FfmpegCamera : public Camera {
std::string hwaccel_device;
int frameCount;
+
+ int alignment; /* ffmpeg wants line sizes to be 32bit aligned. Especially 4.3+ */
#if HAVE_LIBAVFORMAT
AVFormatContext *mFormatContext;
diff --git a/src/zm_ffmpeg_input.cpp b/src/zm_ffmpeg_input.cpp
index 28ecd4ac7..06857a281 100644
--- a/src/zm_ffmpeg_input.cpp
+++ b/src/zm_ffmpeg_input.cpp
@@ -19,7 +19,7 @@ FFmpeg_Input::~FFmpeg_Input() {
avcodec_close(streams[i].context);
streams[i].context = NULL;
}
- delete streams;
+ delete[] streams;
streams = NULL;
}
if ( frame ) {
diff --git a/src/zm_image.cpp b/src/zm_image.cpp
index 31c71037f..1b8b33c8a 100644
--- a/src/zm_image.cpp
+++ b/src/zm_image.cpp
@@ -108,6 +108,7 @@ Image::Image() {
if ( !initialised )
Initialise();
width = 0;
+ linesize = 0;
height = 0;
pixels = 0;
colours = 0;
@@ -121,10 +122,11 @@ Image::Image() {
blend = fptr_blend;
}
-Image::Image( const char *filename ) {
+Image::Image(const char *filename) {
if ( !initialised )
Initialise();
width = 0;
+ linesize = 0;
height = 0;
pixels = 0;
colours = 0;
@@ -139,15 +141,42 @@ Image::Image( const char *filename ) {
update_function_pointers();
}
-Image::Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer ) {
+Image::Image(int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer, unsigned int p_padding) {
if ( !initialised )
Initialise();
width = p_width;
height = p_height;
pixels = width*height;
colours = p_colours;
+ linesize = p_width * p_colours;
+ padding = p_padding;
subpixelorder = p_subpixelorder;
- size = pixels*colours;
+ size = linesize*height + padding;
+ buffer = 0;
+ holdbuffer = 0;
+ if ( p_buffer ) {
+ allocation = size;
+ buffertype = ZM_BUFTYPE_DONTFREE;
+ buffer = p_buffer;
+ } else {
+ AllocImgBuffer(size);
+ }
+ text[0] = '\0';
+
+ update_function_pointers();
+}
+
+Image::Image(int p_width, int p_linesize, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer, unsigned int p_padding) {
+ if ( !initialised )
+ Initialise();
+ width = p_width;
+ linesize = p_linesize;
+ height = p_height;
+ pixels = width*height;
+ colours = p_colours;
+ padding = p_padding;
+ subpixelorder = p_subpixelorder;
+ size = linesize*height + padding;
buffer = 0;
holdbuffer = 0;
if ( p_buffer ) {
@@ -169,18 +198,25 @@ Image::Image(const AVFrame *frame) {
width = frame->width;
height = frame->height;
pixels = width*height;
-
colours = ZM_COLOUR_RGB32;
subpixelorder = ZM_SUBPIX_ORDER_RGBA;
- size = pixels*colours;
+ #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
+ size = av_image_get_buffer_size(AV_PIX_FMT_RGBA, width, height, 32);
+ // av_image_get_linesize isn't aligned, so we have to do that.
+ linesize = FFALIGN(av_image_get_linesize(AV_PIX_FMT_RGBA, width, 0), 32);
+#else
+ linesize = FFALIGN(av_image_get_linesize(AV_PIX_FMT_RGBA, width, 0), 1);
+ size = avpicture_get_size(AV_PIX_FMT_RGBA, width, height);
+#endif
+
buffer = 0;
holdbuffer = 0;
AllocImgBuffer(size);
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
av_image_fill_arrays(dest_frame->data, dest_frame->linesize,
- buffer, AV_PIX_FMT_RGBA, width, height, 1);
+ buffer, AV_PIX_FMT_RGBA, width, height, 32);
#else
avpicture_fill( (AVPicture *)dest_frame, buffer,
AV_PIX_FMT_RGBA, width, height);
@@ -212,6 +248,7 @@ Image::Image(const Image &p_image) {
if ( !initialised )
Initialise();
width = p_image.width;
+ linesize = p_image.linesize;
height = p_image.height;
pixels = p_image.pixels;
colours = p_image.colours;
@@ -232,28 +269,20 @@ Image::~Image() {
/* Should be called as part of program shutdown to free everything */
void Image::Deinitialise() {
if ( !initialised ) return;
- /*
- delete[] y_table;
- delete[] uv_table;
- delete[] r_v_table;
- delete[] g_v_table;
- delete[] g_u_table;
- delete[] b_u_table;
- */
initialised = false;
if ( readjpg_dcinfo ) {
- jpeg_destroy_decompress( readjpg_dcinfo );
+ jpeg_destroy_decompress(readjpg_dcinfo);
delete readjpg_dcinfo;
- readjpg_dcinfo = 0;
+ readjpg_dcinfo = NULL;
}
if ( decodejpg_dcinfo ) {
- jpeg_destroy_decompress( decodejpg_dcinfo );
+ jpeg_destroy_decompress(decodejpg_dcinfo);
delete decodejpg_dcinfo;
- decodejpg_dcinfo = 0;
+ decodejpg_dcinfo = NULL;
}
for ( unsigned int quality=0; quality <= 100; quality += 1 ) {
if ( writejpg_ccinfo[quality] ) {
- jpeg_destroy_compress( writejpg_ccinfo[quality] );
+ jpeg_destroy_compress(writejpg_ccinfo[quality]);
delete writejpg_ccinfo[quality];
writejpg_ccinfo[quality] = NULL;
}
@@ -268,26 +297,26 @@ void Image::Deinitialise() {
void Image::Initialise() {
/* Assign the blend pointer to function */
if ( config.fast_image_blends ) {
- if ( config.cpu_extensions && sseversion >= 20 ) {
+ if ( config.cpu_extensions && sse_version >= 20 ) {
fptr_blend = &sse2_fastblend; /* SSE2 fast blend */
- Debug(4,"Blend: Using SSE2 fast blend function");
+ Debug(4, "Blend: Using SSE2 fast blend function");
} else if ( config.cpu_extensions && neonversion >= 1 ) {
#if defined(__aarch64__)
fptr_blend = &neon64_armv8_fastblend; /* ARM Neon (AArch64) fast blend */
- Debug(4,"Blend: Using ARM Neon (AArch64) fast blend function");
+ Debug(4, "Blend: Using ARM Neon (AArch64) fast blend function");
#elif defined(__arm__)
fptr_blend = &neon32_armv7_fastblend; /* ARM Neon (AArch32) fast blend */
- Debug(4,"Blend: Using ARM Neon (AArch32) fast blend function");
+ Debug(4, "Blend: Using ARM Neon (AArch32) fast blend function");
#else
Panic("Bug: Non ARM platform but neon present");
#endif
} else {
fptr_blend = &std_fastblend; /* standard fast blend */
- Debug(4,"Blend: Using fast blend function");
+ Debug(4, "Blend: Using fast blend function");
}
} else {
fptr_blend = &std_blend;
- Debug(4,"Blend: Using standard blend function");
+ Debug(4, "Blend: Using standard blend function");
}
__attribute__((aligned(64))) uint8_t blend1[128] = {
@@ -314,7 +343,7 @@ void Image::Initialise() {
(*fptr_blend)(blend1,blend2,blendres,128,12.0);
/* Compare results with expected results */
- for ( int i=0; i < 128; i ++ ) {
+ for ( int i=0; i < 128; i++ ) {
if ( abs(blendexp[i] - blendres[i]) > 3 ) {
Panic("Blend function failed self-test: Results differ from the expected results. Column %u Expected %u Got %u",i,blendexp[i],blendres[i]);
}
@@ -325,22 +354,22 @@ void Image::Initialise() {
/* Assign the delta functions */
if ( config.cpu_extensions ) {
- if ( sseversion >= 35 ) {
+ if ( sse_version >= 35 ) {
/* SSSE3 available */
fptr_delta8_rgba = &ssse3_delta8_rgba;
fptr_delta8_bgra = &ssse3_delta8_bgra;
fptr_delta8_argb = &ssse3_delta8_argb;
fptr_delta8_abgr = &ssse3_delta8_abgr;
fptr_delta8_gray8 = &sse2_delta8_gray8;
- Debug(4,"Delta: Using SSSE3 delta functions");
- } else if ( sseversion >= 20 ) {
+ Debug(4, "Delta: Using SSSE3 delta functions");
+ } else if ( sse_version >= 20 ) {
/* SSE2 available */
fptr_delta8_rgba = &sse2_delta8_rgba;
fptr_delta8_bgra = &sse2_delta8_bgra;
fptr_delta8_argb = &sse2_delta8_argb;
fptr_delta8_abgr = &sse2_delta8_abgr;
fptr_delta8_gray8 = &sse2_delta8_gray8;
- Debug(4,"Delta: Using SSE2 delta functions");
+ Debug(4, "Delta: Using SSE2 delta functions");
} else if ( neonversion >= 1 ) {
/* ARM Neon available */
#if defined(__aarch64__)
@@ -349,14 +378,14 @@ void Image::Initialise() {
fptr_delta8_argb = &neon64_armv8_delta8_argb;
fptr_delta8_abgr = &neon64_armv8_delta8_abgr;
fptr_delta8_gray8 = &neon64_armv8_delta8_gray8;
- Debug(4,"Delta: Using ARM Neon (AArch64) delta functions");
+ Debug(4, "Delta: Using ARM Neon (AArch64) delta functions");
#elif defined(__arm__)
fptr_delta8_rgba = &neon32_armv7_delta8_rgba;
fptr_delta8_bgra = &neon32_armv7_delta8_bgra;
fptr_delta8_argb = &neon32_armv7_delta8_argb;
fptr_delta8_abgr = &neon32_armv7_delta8_abgr;
fptr_delta8_gray8 = &neon32_armv7_delta8_gray8;
- Debug(4,"Delta: Using ARM Neon (AArch32) delta functions");
+ Debug(4, "Delta: Using ARM Neon (AArch32) delta functions");
#else
Panic("Bug: Non ARM platform but neon present");
#endif
@@ -414,7 +443,7 @@ void Image::Initialise() {
}
/* Run the delta8 RGBA function */
- (*fptr_delta8_rgba)(delta8_1,delta8_2,delta8_rgba_res,32);
+ (*fptr_delta8_rgba)(delta8_1,delta8_2,delta8_rgba_res, 32);
/* Compare results with expected results */
for ( int i=0; i < 32; i++ ) {
@@ -433,77 +462,45 @@ void Image::Initialise() {
fptr_deinterlace_4field_argb = &std_deinterlace_4field_argb;
fptr_deinterlace_4field_abgr = &std_deinterlace_4field_abgr;
fptr_deinterlace_4field_gray8 = &std_deinterlace_4field_gray8;
- Debug(4,"Deinterlace: Using standard functions");
+ Debug(4, "Deinterlace: Using standard functions");
#if defined(__i386__) && !defined(__x86_64__)
/* Use SSE2 aligned memory copy? */
- if ( config.cpu_extensions && sseversion >= 20 ) {
+ if ( config.cpu_extensions && sse_version >= 20 ) {
fptr_imgbufcpy = &sse2_aligned_memcpy;
- Debug(4,"Image buffer copy: Using SSE2 aligned memcpy");
+ Debug(4, "Image buffer copy: Using SSE2 aligned memcpy");
} else {
fptr_imgbufcpy = &memcpy;
- Debug(4,"Image buffer copy: Using standard memcpy");
+ Debug(4, "Image buffer copy: Using standard memcpy");
}
#else
fptr_imgbufcpy = &memcpy;
- Debug(4,"Image buffer copy: Using standard memcpy");
+ Debug(4, "Image buffer copy: Using standard memcpy");
#endif
- /* Code below relocated from zm_local_camera */
- Debug( 3, "Setting up static colour tables" );
-
y_table = y_table_global;
uv_table = uv_table_global;
r_v_table = r_v_table_global;
g_v_table = g_v_table_global;
g_u_table = g_u_table_global;
b_u_table = b_u_table_global;
- /*
- y_table = new unsigned char[256];
- for ( int i = 0; i <= 255; i++ )
- {
- unsigned char c = i;
- if ( c <= 16 )
- y_table[c] = 0;
- else if ( c >= 235 )
- y_table[c] = 255;
- else
- y_table[c] = (255*(c-16))/219;
- }
-
- uv_table = new signed char[256];
- for ( int i = 0; i <= 255; i++ )
- {
- unsigned char c = i;
- if ( c <= 16 )
- uv_table[c] = -127;
- else if ( c >= 240 )
- uv_table[c] = 127;
- else
- uv_table[c] = (127*(c-128))/112;
- }
-
- r_v_table = new short[255];
- g_v_table = new short[255];
- g_u_table = new short[255];
- b_u_table = new short[255];
- for ( int i = 0; i < 255; i++ )
- {
- r_v_table[i] = (1402*(i-128))/1000;
- g_u_table[i] = (344*(i-128))/1000;
- g_v_table[i] = (714*(i-128))/1000;
- b_u_table[i] = (1772*(i-128))/1000;
- }
- */
initialised = true;
}
/* Requests a writeable buffer to the image. This is safer than buffer() because this way we can guarantee that a buffer of required size exists */
-uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder) {
+uint8_t* Image::WriteBuffer(
+ const unsigned int p_width,
+ const unsigned int p_height,
+ const unsigned int p_colours,
+ const unsigned int p_subpixelorder) {
- if ( p_colours != ZM_COLOUR_GRAY8 && p_colours != ZM_COLOUR_RGB24 && p_colours != ZM_COLOUR_RGB32 ) {
- Error("WriteBuffer called with unexpected colours: %d",p_colours);
+ if ( p_colours != ZM_COLOUR_GRAY8
+ &&
+ p_colours != ZM_COLOUR_RGB24
+ &&
+ p_colours != ZM_COLOUR_RGB32 ) {
+ Error("WriteBuffer called with unexpected colours: %d", p_colours);
return NULL;
}
@@ -513,6 +510,7 @@ uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_hei
}
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 ) {
@@ -533,23 +531,34 @@ uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_hei
width = p_width;
height = p_height;
colours = p_colours;
+ linesize = p_width * p_colours;
subpixelorder = p_subpixelorder;
pixels = height*width;
size = newsize;
- } // end if need to re-alloc buffer
+ } // end if need to re-alloc buffer
return buffer;
}
-/* Assign an existing buffer to the image instead of copying from a source buffer. The goal is to reduce the amount of memory copying and increase efficiency and buffer reusing. */
-void Image::AssignDirect( const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder, uint8_t *new_buffer, const size_t buffer_size, const int p_buffertype) {
+/* Assign an existing buffer to the image instead of copying from a source buffer.
+ The goal is to reduce the amount of memory copying and increase efficiency and buffer reusing.
+*/
+void Image::AssignDirect(
+ const unsigned int p_width,
+ const unsigned int p_height,
+ const unsigned int p_colours,
+ const unsigned int p_subpixelorder,
+ uint8_t *new_buffer,
+ const size_t buffer_size,
+ const int p_buffertype) {
+
if ( new_buffer == NULL ) {
Error("Attempt to directly assign buffer from a NULL pointer");
return;
}
if ( !p_height || !p_width ) {
- Error("Attempt to directly assign buffer with invalid width or height: %d %d",p_width,p_height);
+ Error("Attempt to directly assign buffer with invalid width or height: %d %d", p_width, p_height);
return;
}
@@ -561,7 +570,8 @@ void Image::AssignDirect( const unsigned int p_width, const unsigned int p_heigh
unsigned int new_buffer_size = ((p_width*p_height)*p_colours);
if ( buffer_size < new_buffer_size ) {
- Error("Attempt to directly assign buffer from an undersized buffer of size: %zu, needed %dx%d*%d colours = %zu",buffer_size, p_width, p_height, p_colours, new_buffer_size );
+ Error("Attempt to directly assign buffer from an undersized buffer of size: %zu, needed %dx%d*%d colours = %zu",
+ buffer_size, p_width, p_height, p_colours, new_buffer_size);
return;
}
@@ -573,13 +583,15 @@ void Image::AssignDirect( const unsigned int p_width, const unsigned int p_heigh
width = p_width;
height = p_height;
colours = p_colours;
+ linesize = width * colours;
subpixelorder = p_subpixelorder;
pixels = height*width;
size = new_buffer_size; // was pixels*colours, but we already calculated it above as new_buffer_size
/* Copy into the held buffer */
- if ( new_buffer != buffer )
+ if ( new_buffer != buffer ) {
(*fptr_imgbufcpy)(buffer, new_buffer, size);
+ }
/* Free the new buffer */
DumpBuffer(new_buffer, p_buffertype);
@@ -591,6 +603,7 @@ void Image::AssignDirect( const unsigned int p_width, const unsigned int p_heigh
width = p_width;
height = p_height;
colours = p_colours;
+ linesize = width*colours;
subpixelorder = p_subpixelorder;
pixels = height*width;
size = new_buffer_size; // was pixels*colours, but we already calculated it above as new_buffer_size
@@ -599,10 +612,15 @@ void Image::AssignDirect( const unsigned int p_width, const unsigned int p_heigh
buffertype = p_buffertype;
buffer = new_buffer;
}
+} // end void Image::AssignDirect
-}
-
-void Image::Assign(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder, const uint8_t* new_buffer, const size_t buffer_size) {
+void Image::Assign(
+ const unsigned int p_width,
+ const unsigned int p_height,
+ const unsigned int p_colours,
+ const unsigned int p_subpixelorder,
+ const uint8_t* new_buffer,
+ const size_t buffer_size) {
unsigned int new_size = (p_width * p_height) * p_colours;
if ( new_buffer == NULL ) {
@@ -611,17 +629,17 @@ void Image::Assign(const unsigned int p_width, const unsigned int p_height, cons
}
if ( buffer_size < new_size ) {
- Error("Attempt to assign buffer from an undersized buffer of size: %zu",buffer_size);
+ Error("Attempt to assign buffer from an undersized buffer of size: %zu", buffer_size);
return;
}
if ( !p_height || !p_width ) {
- Error("Attempt to assign buffer with invalid width or height: %d %d",p_width,p_height);
+ Error("Attempt to assign buffer with invalid width or height: %d %d", p_width, p_height);
return;
}
if ( p_colours != ZM_COLOUR_GRAY8 && p_colours != ZM_COLOUR_RGB24 && p_colours != ZM_COLOUR_RGB32 ) {
- Error("Attempt to assign buffer with unexpected colours per pixel: %d",p_colours);
+ Error("Attempt to assign buffer with unexpected colours per pixel: %d", p_colours);
return;
}
@@ -647,26 +665,32 @@ void Image::Assign(const unsigned int p_width, const unsigned int p_height, cons
size = new_size;
}
- if(new_buffer != buffer)
+ if ( new_buffer != buffer )
(*fptr_imgbufcpy)(buffer, new_buffer, size);
-
}
-void Image::Assign( const Image &image ) {
- unsigned int new_size = (image.width * image.height) * image.colours;
+void Image::Assign(const Image &image) {
+ unsigned int new_size = image.height * image.linesize;
if ( image.buffer == NULL ) {
Error("Attempt to assign image with an empty buffer");
return;
}
- if ( image.colours != ZM_COLOUR_GRAY8 && image.colours != ZM_COLOUR_RGB24 && image.colours != ZM_COLOUR_RGB32 ) {
- Error("Attempt to assign image with unexpected colours per pixel: %d",image.colours);
+ if ( image.colours != ZM_COLOUR_GRAY8
+ &&
+ image.colours != ZM_COLOUR_RGB24
+ &&
+ image.colours != ZM_COLOUR_RGB32 ) {
+ Error("Attempt to assign image with unexpected colours per pixel: %d", image.colours);
return;
}
- if ( !buffer || image.width != width || image.height != height
- || image.colours != colours || image.subpixelorder != subpixelorder) {
+ if ( !buffer
+ || image.width != width || image.height != height
+ || image.colours != colours || image.subpixelorder != subpixelorder
+ || image.linesize != linesize
+ ) {
if ( holdbuffer && buffer ) {
if ( new_size > allocation ) {
@@ -686,110 +710,108 @@ void Image::Assign( const Image &image ) {
colours = image.colours;
subpixelorder = image.subpixelorder;
size = new_size;
+ linesize = image.linesize;
}
- if(image.buffer != buffer)
+ if ( image.buffer != buffer )
(*fptr_imgbufcpy)(buffer, image.buffer, size);
}
-Image *Image::HighlightEdges( Rgb colour, unsigned int p_colours, unsigned int p_subpixelorder, const Box *limits ) {
+Image *Image::HighlightEdges(
+ Rgb colour,
+ unsigned int p_colours,
+ unsigned int p_subpixelorder,
+ const Box *limits
+ ) {
if ( colours != ZM_COLOUR_GRAY8 ) {
Panic("Attempt to highlight image edges when colours = %d", colours);
}
/* Convert the colour's RGBA subpixel order into the image's subpixel order */
- colour = rgb_convert(colour,p_subpixelorder);
+ colour = rgb_convert(colour, p_subpixelorder);
/* Create a new image of the target format */
- Image *high_image = new Image( width, height, p_colours, p_subpixelorder );
+ Image *high_image = new Image(width, height, p_colours, p_subpixelorder);
uint8_t* high_buff = high_image->WriteBuffer(width, height, p_colours, p_subpixelorder);
/* Set image to all black */
high_image->Clear();
- unsigned int lo_x = limits?limits->Lo().X():0;
- unsigned int lo_y = limits?limits->Lo().Y():0;
- unsigned int hi_x = limits?limits->Hi().X():width-1;
- unsigned int hi_y = limits?limits->Hi().Y():height-1;
+ unsigned int lo_x = limits ? limits->Lo().X() : 0;
+ unsigned int lo_y = limits ? limits->Lo().Y() : 0;
+ unsigned int hi_x = limits ? limits->Hi().X() : width-1;
+ unsigned int hi_y = limits ? limits->Hi().Y() : height-1;
- if ( p_colours == ZM_COLOUR_GRAY8 )
- {
- for ( unsigned int y = lo_y; y <= hi_y; y++ )
- {
- const uint8_t* p = buffer + (y * width) + lo_x;
- uint8_t* phigh = high_buff + (y * width) + lo_x;
- for ( unsigned int x = lo_x; x <= hi_x; x++, p++, phigh++ )
- {
+ if ( p_colours == ZM_COLOUR_GRAY8 ) {
+ for ( unsigned int y = lo_y; y <= hi_y; y++ ) {
+ const uint8_t* p = buffer + (y * linesize) + lo_x;
+ uint8_t* phigh = high_buff + (y * linesize) + lo_x;
+ for ( unsigned int x = lo_x; x <= hi_x; x++, p++, phigh++ ) {
bool edge = false;
- if ( *p )
- {
+ if ( *p ) {
+ edge = (x > 0 && !*(p-1)) || (x < (width-1) && !*(p+1)) || (y > 0 && !*(p-width)) || (y < (height-1) && !*(p+width));
+#if 0
if ( !edge && x > 0 && !*(p-1) ) edge = true;
if ( !edge && x < (width-1) && !*(p+1) ) edge = true;
if ( !edge && y > 0 && !*(p-width) ) edge = true;
if ( !edge && y < (height-1) && !*(p+width) ) edge = true;
+#endif
}
- if ( edge )
- {
+ if ( edge ) {
*phigh = colour;
}
}
}
- }
- else if ( p_colours == ZM_COLOUR_RGB24 )
- {
- for ( unsigned int y = lo_y; y <= hi_y; y++ )
- {
- const uint8_t* p = buffer + (y * width) + lo_x;
- uint8_t* phigh = high_buff + (((y * width) + lo_x) * 3);
- for ( unsigned int x = lo_x; x <= hi_x; x++, p++, phigh += 3 )
- {
+ } else if ( p_colours == ZM_COLOUR_RGB24 ) {
+ for ( unsigned int y = lo_y; y <= hi_y; y++ ) {
+ const uint8_t* p = buffer + (y * linesize) + lo_x;
+ uint8_t* phigh = high_buff + (((y * linesize) + lo_x) * 3);
+ for ( unsigned int x = lo_x; x <= hi_x; x++, p++, phigh += 3 ) {
bool edge = false;
- if ( *p )
- {
+ if ( *p ) {
+ edge = (x > 0 && !*(p-1)) || (x < (width-1) && !*(p+1)) || (y > 0 && !*(p-width)) || (y < (height-1) && !*(p+width));
+#if 0
if ( !edge && x > 0 && !*(p-1) ) edge = true;
if ( !edge && x < (width-1) && !*(p+1) ) edge = true;
if ( !edge && y > 0 && !*(p-width) ) edge = true;
if ( !edge && y < (height-1) && !*(p+width) ) edge = true;
+#endif
}
- if ( edge )
- {
+ if ( edge ) {
RED_PTR_RGBA(phigh) = RED_VAL_RGBA(colour);
GREEN_PTR_RGBA(phigh) = GREEN_VAL_RGBA(colour);
BLUE_PTR_RGBA(phigh) = BLUE_VAL_RGBA(colour);
}
}
}
- }
- else if ( p_colours == ZM_COLOUR_RGB32 )
- {
- for ( unsigned int y = lo_y; y <= hi_y; y++ )
- {
- const uint8_t* p = buffer + (y * width) + lo_x;
- Rgb* phigh = (Rgb*)(high_buff + (((y * width) + lo_x) * 4));
- for ( unsigned int x = lo_x; x <= hi_x; x++, p++, phigh++ )
- {
+ } else if ( p_colours == ZM_COLOUR_RGB32 ) {
+ for ( unsigned int y = lo_y; y <= hi_y; y++ ) {
+ const uint8_t* p = buffer + (y * linesize) + lo_x;
+ Rgb* phigh = (Rgb*)(high_buff + (((y * linesize) + lo_x) * 4));
+ for ( unsigned int x = lo_x; x <= hi_x; x++, p++, phigh++ ) {
bool edge = false;
- if ( *p )
- {
+ if ( *p ) {
+ edge = (x > 0 && !*(p-1)) || (x < (width-1) && !*(p+1)) || (y > 0 && !*(p-width)) || (y < (height-1) && !*(p+width));
+#if 0
if ( !edge && x > 0 && !*(p-1) ) edge = true;
if ( !edge && x < (width-1) && !*(p+1) ) edge = true;
if ( !edge && y > 0 && !*(p-width) ) edge = true;
if ( !edge && y < (height-1) && !*(p+width) ) edge = true;
+#endif
}
- if ( edge )
- {
+ if ( edge ) {
*phigh = colour;
}
}
}
}
- return( high_image );
+ return high_image;
}
-bool Image::ReadRaw( const char *filename ) {
+bool Image::ReadRaw(const char *filename) {
FILE *infile;
- if ( (infile = fopen( filename, "rb" )) == NULL ) {
+ if ( (infile = fopen(filename, "rb")) == NULL ) {
Error("Can't open %s: %s", filename, strerror(errno));
return false;
}
@@ -881,19 +903,16 @@ bool Image::ReadJpeg(const char *filename, unsigned int p_colours, unsigned int
new_height = cinfo->image_height;
if ( width != new_width || height != new_height ) {
- Debug(9,"Image dimensions differ. Old: %ux%u New: %ux%u",width,height,new_width,new_height);
+ Debug(9, "Image dimensions differ. Old: %ux%u New: %ux%u", width, height, new_width, new_height);
}
- switch(p_colours) {
+ switch ( p_colours ) {
case ZM_COLOUR_GRAY8:
- {
cinfo->out_color_space = JCS_GRAYSCALE;
new_colours = ZM_COLOUR_GRAY8;
new_subpixelorder = ZM_SUBPIX_ORDER_NONE;
break;
- }
case ZM_COLOUR_RGB32:
- {
#ifdef JCS_EXTENSIONS
new_colours = ZM_COLOUR_RGB32;
if ( p_subpixelorder == ZM_SUBPIX_ORDER_BGRA ) {
@@ -914,10 +933,8 @@ bool Image::ReadJpeg(const char *filename, unsigned int p_colours, unsigned int
#else
Warning("libjpeg-turbo is required for reading a JPEG directly into a RGB32 buffer, reading into a RGB24 buffer instead.");
#endif
- }
case ZM_COLOUR_RGB24:
default:
- {
new_colours = ZM_COLOUR_RGB24;
if ( p_subpixelorder == ZM_SUBPIX_ORDER_BGR ) {
#ifdef JCS_EXTENSIONS
@@ -941,8 +958,7 @@ cinfo->out_color_space = JCS_RGB;
new_subpixelorder = ZM_SUBPIX_ORDER_RGB;
}
break;
- }
- }
+ } // end switch p_colours
if ( WriteBuffer(new_width, new_height, new_colours, new_subpixelorder) == NULL ) {
Error("Failed requesting writeable buffer for reading JPEG image.");
@@ -953,11 +969,10 @@ cinfo->out_color_space = JCS_RGB;
jpeg_start_decompress(cinfo);
- JSAMPROW row_pointer; /* pointer to a single row */
- int row_stride = width * colours; /* physical row width in buffer */
+ JSAMPROW row_pointer = buffer;
while ( cinfo->output_scanline < cinfo->output_height ) {
- row_pointer = &buffer[cinfo->output_scanline * row_stride];
jpeg_read_scanlines(cinfo, &row_pointer, 1);
+ row_pointer += linesize;
}
jpeg_finish_decompress(cinfo);
@@ -971,40 +986,39 @@ cinfo->out_color_space = JCS_RGB;
// Note quality=zero means default
bool Image::WriteJpeg(const char *filename, int quality_override) const {
- return Image::WriteJpeg(filename, quality_override, (timeval){0,0});
+ return Image::WriteJpeg(filename, quality_override, (timeval){0,0}, false);
}
bool Image::WriteJpeg(const char *filename) const {
- return Image::WriteJpeg(filename, 0, (timeval){0,0});
+ return Image::WriteJpeg(filename, 0, (timeval){0,0}, false);
}
bool Image::WriteJpeg(const char *filename, bool on_blocking_abort) const {
return Image::WriteJpeg(filename, 0, (timeval){0,0}, on_blocking_abort);
}
bool Image::WriteJpeg(const char *filename, struct timeval timestamp) const {
- return Image::WriteJpeg(filename, 0, timestamp);
+ return Image::WriteJpeg(filename, 0, timestamp, false);
}
bool Image::WriteJpeg(const char *filename, int quality_override, struct timeval timestamp) const {
return Image::WriteJpeg(filename, quality_override, timestamp, false);
}
+
bool Image::WriteJpeg(const char *filename, int quality_override, struct timeval timestamp, bool on_blocking_abort) const {
if ( config.colour_jpeg_files && (colours == ZM_COLOUR_GRAY8) ) {
Image temp_image(*this);
temp_image.Colourise(ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB);
return temp_image.WriteJpeg(filename, quality_override, timestamp, on_blocking_abort);
}
- int quality = quality_override?quality_override:config.jpeg_file_quality;
+ int quality = quality_override ? quality_override : config.jpeg_file_quality;
struct jpeg_compress_struct *cinfo = writejpg_ccinfo[quality];
FILE *outfile = NULL;
static int raw_fd = 0;
- bool need_create_comp = false;
raw_fd = 0;
if ( !cinfo ) {
cinfo = writejpg_ccinfo[quality] = new jpeg_compress_struct;
cinfo->err = jpeg_std_error(&jpg_err.pub);
jpeg_create_compress(cinfo);
- need_create_comp = true;
}
if ( !on_blocking_abort ) {
jpg_err.pub.error_exit = zm_jpeg_error_exit;
@@ -1022,8 +1036,6 @@ bool Image::WriteJpeg(const char *filename, int quality_override, struct timeval
return false;
}
}
- if ( need_create_comp )
- jpeg_create_compress(cinfo);
if ( !on_blocking_abort ) {
if ( (outfile = fopen(filename, "wb")) == NULL ) {
@@ -1046,7 +1058,7 @@ bool Image::WriteJpeg(const char *filename, int quality_override, struct timeval
cinfo->image_width = width; /* image width and height, in pixels */
cinfo->image_height = height;
- switch (colours) {
+ switch ( colours ) {
case ZM_COLOUR_GRAY8:
cinfo->input_components = 1;
cinfo->in_color_space = JCS_GRAYSCALE;
@@ -1054,13 +1066,16 @@ bool Image::WriteJpeg(const char *filename, int quality_override, struct timeval
case ZM_COLOUR_RGB32:
#ifdef JCS_EXTENSIONS
cinfo->input_components = 4;
- if ( subpixelorder == ZM_SUBPIX_ORDER_BGRA ) {
+ if ( subpixelorder == ZM_SUBPIX_ORDER_RGBA ) {
+ cinfo->in_color_space = JCS_EXT_RGBX;
+ } else if ( subpixelorder == ZM_SUBPIX_ORDER_BGRA ) {
cinfo->in_color_space = JCS_EXT_BGRX;
} else if ( subpixelorder == ZM_SUBPIX_ORDER_ARGB ) {
cinfo->in_color_space = JCS_EXT_XRGB;
} else if ( subpixelorder == ZM_SUBPIX_ORDER_ABGR ) {
cinfo->in_color_space = JCS_EXT_XBGR;
} else {
+ Warning("Unknwon subpixelorder %d", subpixelorder);
/* Assume RGBA */
cinfo->in_color_space = JCS_EXT_RGBX;
}
@@ -1130,15 +1145,12 @@ cinfo->out_color_space = JCS_RGB;
jpeg_write_marker(cinfo, EXIF_CODE, (const JOCTET *)exiftimes, sizeof(exiftimes));
}
- JSAMPROW row_pointer; /* pointer to a single row */
- int row_stride = cinfo->image_width * colours; /* physical row width in buffer */
+ JSAMPROW row_pointer = buffer; /* pointer to a single row */
while ( cinfo->next_scanline < cinfo->image_height ) {
- row_pointer = &buffer[cinfo->next_scanline * row_stride];
jpeg_write_scanlines(cinfo, &row_pointer, 1);
+ row_pointer += linesize;
}
-
jpeg_finish_compress(cinfo);
-
fclose(outfile);
return true;
@@ -1252,11 +1264,10 @@ cinfo->out_color_space = JCS_RGB;
jpeg_start_decompress(cinfo);
- JSAMPROW row_pointer; /* pointer to a single row */
- int row_stride = width * colours; /* physical row width in buffer */
+ JSAMPROW row_pointer = buffer; /* pointer to a single row */
while ( cinfo->output_scanline < cinfo->output_height ) {
- row_pointer = &buffer[cinfo->output_scanline * row_stride];
jpeg_read_scanlines(cinfo, &row_pointer, 1);
+ row_pointer += linesize;
}
jpeg_finish_decompress(cinfo);
@@ -1271,7 +1282,7 @@ bool Image::EncodeJpeg(JOCTET *outbuffer, int *outbuffer_size, int quality_overr
return temp_image.EncodeJpeg(outbuffer, outbuffer_size, quality_override);
}
- int quality = quality_override?quality_override:config.jpeg_stream_quality;
+ int quality = quality_override ? quality_override : config.jpeg_stream_quality;
struct jpeg_compress_struct *cinfo = encodejpg_ccinfo[quality];
@@ -1288,7 +1299,7 @@ bool Image::EncodeJpeg(JOCTET *outbuffer, int *outbuffer_size, int quality_overr
cinfo->image_width = width; /* image width and height, in pixels */
cinfo->image_height = height;
- switch (colours) {
+ switch ( colours ) {
case ZM_COLOUR_GRAY8:
cinfo->input_components = 1;
cinfo->in_color_space = JCS_GRAYSCALE;
@@ -1296,13 +1307,16 @@ bool Image::EncodeJpeg(JOCTET *outbuffer, int *outbuffer_size, int quality_overr
case ZM_COLOUR_RGB32:
#ifdef JCS_EXTENSIONS
cinfo->input_components = 4;
- if ( subpixelorder == ZM_SUBPIX_ORDER_BGRA ) {
+ if ( subpixelorder == ZM_SUBPIX_ORDER_RGBA ) {
+ cinfo->in_color_space = JCS_EXT_RGBX;
+ } else if ( subpixelorder == ZM_SUBPIX_ORDER_BGRA ) {
cinfo->in_color_space = JCS_EXT_BGRX;
} else if ( subpixelorder == ZM_SUBPIX_ORDER_ARGB ) {
cinfo->in_color_space = JCS_EXT_XRGB;
} else if ( subpixelorder == ZM_SUBPIX_ORDER_ABGR ) {
cinfo->in_color_space = JCS_EXT_XBGR;
} else {
+ Warning("unknown subpixelorder %d", subpixelorder);
/* Assume RGBA */
cinfo->in_color_space = JCS_EXT_RGBX;
}
@@ -1343,11 +1357,10 @@ cinfo->out_color_space = JCS_RGB;
jpeg_start_compress(cinfo, TRUE);
- JSAMPROW row_pointer; /* pointer to a single row */
- int row_stride = cinfo->image_width * colours; /* physical row width in buffer */
+ JSAMPROW row_pointer = buffer;
while ( cinfo->next_scanline < cinfo->image_height ) {
- row_pointer = &buffer[cinfo->next_scanline * row_stride];
jpeg_write_scanlines(cinfo, &row_pointer, 1);
+ row_pointer += linesize;
}
jpeg_finish_compress(cinfo);
@@ -1385,11 +1398,12 @@ bool Image::Crop( unsigned int lo_x, unsigned int lo_y, unsigned int hi_x, unsig
unsigned int new_height = (hi_y-lo_y)+1;
if ( lo_x > hi_x || lo_y > hi_y ) {
- Error( "Invalid or reversed crop region %d,%d -> %d,%d", lo_x, lo_y, hi_x, hi_y );
- return( false );
+ Error("Invalid or reversed crop region %d,%d -> %d,%d", lo_x, lo_y, hi_x, hi_y);
+ return false;
}
if ( hi_x > (width-1) || ( hi_y > (height-1) ) ) {
- Error( "Attempting to crop outside image, %d,%d -> %d,%d not in %d,%d", lo_x, lo_y, hi_x, hi_y, width-1, height-1 );
+ Error("Attempting to crop outside image, %d,%d -> %d,%d not in %d,%d",
+ lo_x, lo_y, hi_x, hi_y, width-1, height-1);
return false;
}
@@ -1400,9 +1414,9 @@ bool Image::Crop( unsigned int lo_x, unsigned int lo_y, unsigned int hi_x, unsig
unsigned int new_size = new_width*new_height*colours;
uint8_t *new_buffer = AllocBuffer(new_size);
- unsigned int new_stride = new_width*colours;
+ unsigned int new_stride = new_width * colours;
for ( unsigned int y = lo_y, ny = 0; y <= hi_y; y++, ny++ ) {
- unsigned char *pbuf = &buffer[((y*width)+lo_x)*colours];
+ unsigned char *pbuf = &buffer[((y*linesize)+lo_x)];
unsigned char *pnbuf = &new_buffer[(ny*new_width)*colours];
memcpy( pnbuf, pbuf, new_stride );
}
@@ -1412,8 +1426,8 @@ bool Image::Crop( unsigned int lo_x, unsigned int lo_y, unsigned int hi_x, unsig
return true;
}
-bool Image::Crop( const Box &limits ) {
- return Crop( limits.LoX(), limits.LoY(), limits.HiX(), limits.HiY() );
+bool Image::Crop(const Box &limits) {
+ return Crop(limits.LoX(), limits.LoY(), limits.HiX(), limits.HiY());
}
/* Far from complete */
@@ -1434,7 +1448,7 @@ void Image::Overlay( const Image &image ) {
const uint8_t* psrc = image.buffer;
uint8_t* pdest = buffer;
- while( pdest < max_ptr ) {
+ while ( pdest < max_ptr ) {
if ( *psrc ) {
*pdest = *psrc;
}
@@ -1450,7 +1464,7 @@ void Image::Overlay( const Image &image ) {
const uint8_t* psrc = image.buffer;
uint8_t* pdest = buffer;
- while( pdest < max_ptr ) {
+ while ( pdest < max_ptr ) {
if ( RED_PTR_RGBA(psrc) || GREEN_PTR_RGBA(psrc) || BLUE_PTR_RGBA(psrc) ) {
RED_PTR_RGBA(pdest) = RED_PTR_RGBA(psrc);
GREEN_PTR_RGBA(pdest) = GREEN_PTR_RGBA(psrc);
@@ -1461,7 +1475,7 @@ void Image::Overlay( const Image &image ) {
}
/* RGB32 ontop of grayscale - convert to same format first - complete */
- } else if( colours == ZM_COLOUR_GRAY8 && image.colours == ZM_COLOUR_RGB32 ) {
+ } else if ( colours == ZM_COLOUR_GRAY8 && image.colours == ZM_COLOUR_RGB32 ) {
Colourise(image.colours, image.subpixelorder);
const Rgb* const max_ptr = (Rgb*)(buffer+size);
@@ -1470,7 +1484,7 @@ void Image::Overlay( const Image &image ) {
if ( subpixelorder == ZM_SUBPIX_ORDER_RGBA || subpixelorder == ZM_SUBPIX_ORDER_BGRA ) {
/* RGB\BGR\RGBA\BGRA subpixel order - Alpha byte is last */
- while (prdest < max_ptr) {
+ while ( prdest < max_ptr) {
if ( RED_PTR_RGBA(prsrc) || GREEN_PTR_RGBA(prsrc) || BLUE_PTR_RGBA(prsrc) ) {
*prdest = *prsrc;
}
@@ -1479,7 +1493,7 @@ void Image::Overlay( const Image &image ) {
}
} else {
/* ABGR\ARGB subpixel order - Alpha byte is first */
- while (prdest < max_ptr) {
+ while ( prdest < max_ptr) {
if ( RED_PTR_ABGR(prsrc) || GREEN_PTR_ABGR(prsrc) || BLUE_PTR_ABGR(prsrc) ) {
*prdest = *prsrc;
}
@@ -1494,7 +1508,7 @@ void Image::Overlay( const Image &image ) {
const uint8_t* psrc = image.buffer;
uint8_t* pdest = buffer;
- while( pdest < max_ptr ) {
+ while ( pdest < max_ptr ) {
if ( *psrc ) {
RED_PTR_RGBA(pdest) = GREEN_PTR_RGBA(pdest) = BLUE_PTR_RGBA(pdest) = *psrc;
}
@@ -1508,7 +1522,7 @@ void Image::Overlay( const Image &image ) {
const uint8_t* psrc = image.buffer;
uint8_t* pdest = buffer;
- while( pdest < max_ptr ) {
+ while ( pdest < max_ptr ) {
if ( RED_PTR_RGBA(psrc) || GREEN_PTR_RGBA(psrc) || BLUE_PTR_RGBA(psrc) ) {
RED_PTR_RGBA(pdest) = RED_PTR_RGBA(psrc);
GREEN_PTR_RGBA(pdest) = GREEN_PTR_RGBA(psrc);
@@ -1631,8 +1645,7 @@ void Image::Overlay( const Image &image, unsigned int x, unsigned int y ) {
} else {
Error("Overlay called with unexpected colours: %d", colours);
}
-
-}
+} // end void Image::Overlay( const Image &image, unsigned int x, unsigned int y )
void Image::Blend( const Image &image, int transparency ) {
#ifdef ZM_IMAGE_PROFILING
@@ -1675,7 +1688,7 @@ void Image::Blend( const Image &image, int transparency ) {
AssignDirect(width, height, colours, subpixelorder, new_buffer, size, ZM_BUFTYPE_ZM);
}
-Image *Image::Merge( unsigned int n_images, Image *images[] ) {
+Image *Image::Merge(unsigned int n_images, Image *images[]) {
if ( n_images == 1 ) return new Image(*images[0]);
unsigned int width = images[0]->width;
@@ -1704,7 +1717,7 @@ Image *Image::Merge( unsigned int n_images, Image *images[] ) {
return result;
}
-Image *Image::Merge( unsigned int n_images, Image *images[], double weight ) {
+Image *Image::Merge(unsigned int n_images, Image *images[], double weight) {
if ( n_images == 1 ) return new Image(*images[0]);
unsigned int width = images[0]->width;
@@ -1717,7 +1730,7 @@ Image *Image::Merge( unsigned int n_images, Image *images[], double weight ) {
}
}
- Image *result = new Image( *images[0] );
+ Image *result = new Image(*images[0]);
unsigned int size = result->size;
double factor = 1.0*weight;
for ( unsigned int i = 1; i < n_images; i++ ) {
@@ -1746,7 +1759,7 @@ Image *Image::Highlight( unsigned int n_images, Image *images[], const Rgb thres
}
}
- Image *result = new Image( width, height, images[0]->colours, images[0]->subpixelorder );
+ Image *result = new Image(width, height, images[0]->colours, images[0]->subpixelorder);
unsigned int size = result->size;
for ( unsigned int c = 0; c < colours; c++ ) {
unsigned int ref_colour_rgb = RGB_VAL(ref_colour,c);
@@ -1771,7 +1784,7 @@ Image *Image::Highlight( unsigned int n_images, Image *images[], const Rgb thres
return result;
}
-/* New function to allow buffer re-using instead of allocationg memory for the delta image every time */
+/* New function to allow buffer re-using instead of allocating memory for the delta image every time */
void Image::Delta( const Image &image, Image* targetimage) const {
#ifdef ZM_IMAGE_PROFILING
struct timespec start,end,diff;
@@ -1794,7 +1807,7 @@ void Image::Delta( const Image &image, Image* targetimage) const {
clock_gettime(CLOCK_THREAD_CPUTIME_ID,&start);
#endif
- switch (colours) {
+ switch ( colours ) {
case ZM_COLOUR_RGB24:
if ( subpixelorder == ZM_SUBPIX_ORDER_BGR ) {
/* BGR subpixel order */
@@ -1858,7 +1871,7 @@ const Coord Image::centreCoord( const char *text ) const {
}
int x = (width - (max_line_len * ZM_CHAR_WIDTH) ) / 2;
int y = (height - (line_no * LINE_HEIGHT) ) / 2;
- return( Coord( x, y ) );
+ return Coord(x, y);
}
/* RGB32 compatible: complete */
@@ -1905,11 +1918,11 @@ void Image::MaskPrivacy( const unsigned char *p_bitmask, const Rgb pixel_colour
/* RGB32 compatible: complete */
void Image::Annotate( const char *p_text, const Coord &coord, const unsigned int size, const Rgb fg_colour, const Rgb bg_colour )
{
- strncpy( text, p_text, sizeof(text)-1 );
+ strncpy(text, p_text, sizeof(text)-1);
unsigned int index = 0;
unsigned int line_no = 0;
- unsigned int text_len = strlen( text );
+ unsigned int text_len = strlen(text);
unsigned int line_len = 0;
const char *line = text;
@@ -1928,10 +1941,10 @@ void Image::Annotate( const char *p_text, const Coord &coord, const unsigned int
const bool bg_trans = (bg_colour == RGB_TRANSPARENT);
int zm_text_bitmask = 0x80;
- if (size == 2)
+ if ( size == 2 )
zm_text_bitmask = 0x8000;
- while ( (index < text_len) && (line_len = strcspn( line, "\n" )) ) {
+ while ( (index < text_len) && (line_len = strcspn(line, "\n")) ) {
unsigned int line_width = line_len * ZM_CHAR_WIDTH * size;
@@ -1967,10 +1980,19 @@ void Image::Annotate( const char *p_text, const Coord &coord, const unsigned int
unsigned char *temp_ptr = ptr;
for ( unsigned int x = lo_line_x, c = 0; x < hi_line_x && c < line_len; c++ ) {
int f;
- if (size == 2)
+ if ( size == 2 ) {
+ if ( (line[c] * ZM_CHAR_HEIGHT * size) + r > sizeof(bigfontdata) ) {
+ Warning("Unsupported character %c in %s", line[c], line);
+ continue;
+ }
f = bigfontdata[(line[c] * ZM_CHAR_HEIGHT * size) + r];
- else
+ } else {
+ if ( (line[c] * ZM_CHAR_HEIGHT) + r > sizeof(fontdata) ) {
+ Warning("Unsupported character %c in %s", line[c], line);
+ continue;
+ }
f = fontdata[(line[c] * ZM_CHAR_HEIGHT) + r];
+ }
for ( unsigned int i = 0; i < (ZM_CHAR_WIDTH * size) && x < hi_line_x; i++, x++, temp_ptr++ ) {
if ( f & (zm_text_bitmask >> i) ) {
if ( !fg_trans )
@@ -1989,10 +2011,19 @@ void Image::Annotate( const char *p_text, const Coord &coord, const unsigned int
unsigned char *temp_ptr = ptr;
for ( unsigned int x = lo_line_x, c = 0; x < hi_line_x && c < line_len; c++ ) {
int f;
- if (size == 2)
+ if ( size == 2 ) {
+ if ( (line[c] * ZM_CHAR_HEIGHT * size) + r > sizeof(bigfontdata) ) {
+ Warning("Unsupported character %c in %s", line[c], line);
+ continue;
+ }
f = bigfontdata[(line[c] * ZM_CHAR_HEIGHT * size) + r];
- else
+ } else {
+ if ( (line[c] * ZM_CHAR_HEIGHT) + r > sizeof(fontdata) ) {
+ Warning("Unsupported character %c in %s", line[c], line);
+ continue;
+ }
f = fontdata[(line[c] * ZM_CHAR_HEIGHT) + r];
+ }
for ( unsigned int i = 0; i < (ZM_CHAR_WIDTH * size) && x < hi_line_x; i++, x++, temp_ptr += colours ) {
if ( f & (zm_text_bitmask >> i) ) {
if ( !fg_trans ) {
@@ -2016,10 +2047,19 @@ void Image::Annotate( const char *p_text, const Coord &coord, const unsigned int
Rgb* temp_ptr = (Rgb*)ptr;
for ( unsigned int x = lo_line_x, c = 0; x < hi_line_x && c < line_len; c++ ) {
int f;
- if (size == 2)
+ if ( size == 2 ) {
+ if ( (line[c] * ZM_CHAR_HEIGHT * size) + r > sizeof(bigfontdata) ) {
+ Warning("Unsupported character %c in %s", line[c], line);
+ continue;
+ }
f = bigfontdata[(line[c] * ZM_CHAR_HEIGHT * size) + r];
- else
+ } else {
+ if ( (line[c] * ZM_CHAR_HEIGHT) + r > sizeof(fontdata) ) {
+ Warning("Unsupported character %c in %s", line[c], line);
+ continue;
+ }
f = fontdata[(line[c] * ZM_CHAR_HEIGHT) + r];
+ }
for ( unsigned int i = 0; i < (ZM_CHAR_WIDTH * size) && x < hi_line_x; i++, x++, temp_ptr++ ) {
if ( f & (zm_text_bitmask >> i) ) {
if ( !fg_trans ) {
@@ -2033,7 +2073,7 @@ void Image::Annotate( const char *p_text, const Coord &coord, const unsigned int
}
} else {
- Panic("Annotate called with unexpected colours: %d",colours);
+ Error("Annotate called with unexpected colours: %d", colours);
return;
}
@@ -2123,7 +2163,7 @@ void Image::DeColourise() {
subpixelorder = ZM_SUBPIX_ORDER_NONE;
size = width * height;
- if ( colours == ZM_COLOUR_RGB32 && config.cpu_extensions && sseversion >= 35 ) {
+ if ( colours == ZM_COLOUR_RGB32 && config.cpu_extensions && sse_version >= 35 ) {
/* Use SSSE3 functions */
switch (subpixelorder) {
case ZM_SUBPIX_ORDER_BGRA:
@@ -2250,12 +2290,12 @@ void Image::Fill( Rgb colour, int density, const Box *limits ) {
if ( density <= 1 )
return Fill(colour,limits);
- if ( !(colours == ZM_COLOUR_GRAY8 || colours == ZM_COLOUR_RGB24 || colours == ZM_COLOUR_RGB32 ) ) {
+ if ( !(colours == ZM_COLOUR_GRAY8 || colours == ZM_COLOUR_RGB24 || colours == ZM_COLOUR_RGB32 ) ) {
Panic("Attempt to fill image with unexpected colours %d", colours);
}
/* Convert the colour's RGBA subpixel order into the image's subpixel order */
- colour = rgb_convert(colour,subpixelorder);
+ colour = rgb_convert(colour, subpixelorder);
unsigned int lo_x = limits?limits->Lo().X():0;
unsigned int lo_y = limits?limits->Lo().Y():0;
@@ -2317,9 +2357,7 @@ void Image::Outline( Rgb colour, const Polygon &polygon ) {
double grad;
- //Debug( 9, "dx: %.2lf, dy: %.2lf", dx, dy );
if ( fabs(dx) <= fabs(dy) ) {
- //Debug( 9, "dx <= dy" );
if ( y1 != y2 )
grad = dx/dy;
else
@@ -2329,9 +2367,7 @@ void Image::Outline( Rgb colour, const Polygon &polygon ) {
int y, yinc = (y1= Logger::DEBUG9 ) {
for ( int i = 0; i < n_global_edges; i++ ) {
- Debug( 9, "%d: min_y: %d, max_y:%d, min_x:%.2f, 1/m:%.2f", i, global_edges[i].min_y, global_edges[i].max_y, global_edges[i].min_x, global_edges[i]._1_m );
+ Debug(9, "%d: min_y: %d, max_y:%d, min_x:%.2f, 1/m:%.2f",
+ i, global_edges[i].min_y, global_edges[i].max_y, global_edges[i].min_x, global_edges[i]._1_m);
}
}
#endif
@@ -2441,11 +2478,12 @@ void Image::Fill( Rgb colour, int density, const Polygon &polygon ) {
break;
}
}
- qsort( active_edges, n_active_edges, sizeof(*active_edges), Edge::CompareX );
+ qsort(active_edges, n_active_edges, sizeof(*active_edges), Edge::CompareX);
#ifndef ZM_DBG_OFF
if ( logLevel() >= Logger::DEBUG9 ) {
for ( int i = 0; i < n_active_edges; i++ ) {
- Debug( 9, "%d - %d: min_y: %d, max_y:%d, min_x:%.2f, 1/m:%.2f", y, i, active_edges[i].min_y, active_edges[i].max_y, active_edges[i].min_x, active_edges[i]._1_m );
+ Debug(9, "%d - %d: min_y: %d, max_y:%d, min_x:%.2f, 1/m:%.2f",
+ y, i, active_edges[i].min_y, active_edges[i].max_y, active_edges[i].min_x, active_edges[i]._1_m );
}
}
#endif
@@ -2486,7 +2524,7 @@ void Image::Fill( Rgb colour, int density, const Polygon &polygon ) {
for ( int i = n_active_edges-1; i >= 0; i-- ) {
if ( y >= active_edges[i].max_y ) {
// Or >= as per sheets
- Debug( 9, "Deleting active_edge" );
+ Debug(9, "Deleting active_edge");
if ( i < (n_active_edges-1) ) {
//memcpy( &active_edges[i], &active_edges[i+1], sizeof(*active_edges)*(n_active_edges-i) );
memmove( &active_edges[i], &active_edges[i+1], sizeof(*active_edges)*(n_active_edges-i) );
@@ -2499,27 +2537,21 @@ void Image::Fill( Rgb colour, int density, const Polygon &polygon ) {
} while ( n_global_edges || n_active_edges );
}
-void Image::Fill( Rgb colour, const Polygon &polygon ) {
- Fill( colour, 1, polygon );
+void Image::Fill(Rgb colour, const Polygon &polygon) {
+ Fill(colour, 1, polygon);
}
-/* RGB32 compatible: complete */
-void Image::Rotate( int angle ) {
-
+void Image::Rotate(int angle) {
angle %= 360;
- if ( !angle ) {
+ if ( !angle || angle%90 ) {
return;
}
- if ( angle%90 ) {
- return;
- }
-
unsigned int new_height = height;
unsigned int new_width = width;
uint8_t* rotate_buffer = AllocBuffer(size);
- switch( angle ) {
+ switch ( angle ) {
case 90 :
{
new_height = width;
@@ -2538,17 +2570,17 @@ void Image::Rotate( int angle ) {
}
} else if ( colours == ZM_COLOUR_RGB32 ) {
Rgb* s_rptr = (Rgb*)s_ptr;
- for ( unsigned int i = new_width; i > 0; i-- ) {
+ for ( unsigned int i = new_width; i; i-- ) {
Rgb* d_rptr = (Rgb*)(rotate_buffer+((i-1)<<2));
- for ( unsigned int j = new_height; j > 0; j-- ) {
+ for ( unsigned int j = new_height; j; j-- ) {
*d_rptr = *s_rptr++;
d_rptr += new_width;
}
}
} else /* Assume RGB24 */ {
- for ( unsigned int i = new_width; i > 0; i-- ) {
+ for ( unsigned int i = new_width; i; i-- ) {
unsigned char *d_ptr = rotate_buffer+((i-1)*3);
- for ( unsigned int j = new_height; j > 0; j-- ) {
+ for ( unsigned int j = new_height; j; j-- ) {
*d_ptr = *s_ptr++;
*(d_ptr+1) = *s_ptr++;
*(d_ptr+2) = *s_ptr++;
@@ -2627,8 +2659,8 @@ void Image::Rotate( int angle ) {
}
}
- AssignDirect( new_width, new_height, colours, subpixelorder, rotate_buffer, size, ZM_BUFTYPE_ZM);
-}
+ AssignDirect(new_width, new_height, colours, subpixelorder, rotate_buffer, size, ZM_BUFTYPE_ZM);
+} // void Image::Rotate(int angle)
/* RGB32 compatible: complete */
void Image::Flip( bool leftright ) {
@@ -2677,20 +2709,19 @@ void Image::Flip( bool leftright ) {
unsigned char *s_ptr = buffer+(height*line_bytes);
unsigned char *d_ptr = flip_buffer;
- while( s_ptr > buffer ) {
+ while ( s_ptr > buffer ) {
s_ptr -= line_bytes;
- memcpy( d_ptr, s_ptr, line_bytes );
+ memcpy(d_ptr, s_ptr, line_bytes);
d_ptr += line_bytes;
}
}
- AssignDirect( width, height, colours, subpixelorder, flip_buffer, size, ZM_BUFTYPE_ZM);
-
+ AssignDirect(width, height, colours, subpixelorder, flip_buffer, size, ZM_BUFTYPE_ZM);
}
-void Image::Scale( unsigned int factor ) {
+void Image::Scale(unsigned int factor) {
if ( !factor ) {
- Error( "Bogus scale factor %d found", factor );
+ Error("Bogus scale factor %d found", factor);
return;
}
if ( factor == ZM_SCALE_BASE ) {
@@ -2700,6 +2731,7 @@ void Image::Scale( unsigned int factor ) {
unsigned int new_width = (width*factor)/ZM_SCALE_BASE;
unsigned int new_height = (height*factor)/ZM_SCALE_BASE;
+ // Why larger than we need?
size_t scale_buffer_size = (new_width+1) * (new_height+1) * colours;
uint8_t* scale_buffer = AllocBuffer(scale_buffer_size);
@@ -2747,7 +2779,7 @@ void Image::Scale( unsigned int factor ) {
unsigned int last_h_index = 0;
unsigned int last_w_index = 0;
unsigned int h_index;
- for ( unsigned int y = 0; y < (unsigned int)height; y++ ) {
+ for ( unsigned int y = 0; y < height; y++ ) {
h_count += factor;
h_index = h_count/ZM_SCALE_BASE;
if ( h_index > last_h_index ) {
@@ -2756,7 +2788,7 @@ void Image::Scale( unsigned int factor ) {
last_w_index = 0;
unsigned char *ps = &buffer[y*wc];
- for ( unsigned int x = 0; x < (unsigned int)width; x++ ) {
+ for ( unsigned int x = 0; x < width; x++ ) {
w_count += factor;
w_index = w_count/ZM_SCALE_BASE;
@@ -2774,10 +2806,8 @@ void Image::Scale( unsigned int factor ) {
}
new_width = last_w_index;
new_height = last_h_index;
- }
-
- AssignDirect( new_width, new_height, colours, subpixelorder, scale_buffer, scale_buffer_size, ZM_BUFTYPE_ZM);
-
+ } // end foreach line
+ AssignDirect(new_width, new_height, colours, subpixelorder, scale_buffer, scale_buffer_size, ZM_BUFTYPE_ZM);
}
void Image::Deinterlace_Discard() {
@@ -2818,7 +2848,6 @@ void Image::Deinterlace_Discard() {
} else {
Error("Deinterlace called with unexpected colours: %d", colours);
}
-
}
void Image::Deinterlace_Linear() {
@@ -3456,7 +3485,7 @@ __attribute__((noinline)) void fast_delta8_bgr(const uint8_t* col1, const uint8_
int r,g,b;
const uint8_t* const max_ptr = result + count;
- while(result < max_ptr) {
+ while (result < max_ptr) {
b = abs(col1[0] - col2[0]);
g = abs(col1[1] - col2[1]);
r = abs(col1[2] - col2[2]);
@@ -3485,7 +3514,7 @@ __attribute__((noinline)) void std_delta8_bgr(const uint8_t* col1, const uint8_t
int r,g,b;
const uint8_t* const max_ptr = result + count;
- while(result < max_ptr) {
+ while (result < max_ptr) {
b = abs(col1[0] - col2[0]);
g = abs(col1[1] - col2[1]);
r = abs(col1[2] - col2[2]);
@@ -3503,7 +3532,7 @@ __attribute__((noinline)) void fast_delta8_rgba(const uint8_t* col1, const uint8
int r,g,b;
const uint8_t* const max_ptr = result + count;
- while(result < max_ptr) {
+ while (result < max_ptr) {
r = abs(col1[0] - col2[0]);
g = abs(col1[1] - col2[1]);
b = abs(col1[2] - col2[2]);
@@ -3532,7 +3561,7 @@ __attribute__((noinline)) void std_delta8_rgba(const uint8_t* col1, const uint8_
int r,g,b;
const uint8_t* const max_ptr = result + count;
- while(result < max_ptr) {
+ while (result < max_ptr) {
r = abs(col1[0] - col2[0]);
g = abs(col1[1] - col2[1]);
b = abs(col1[2] - col2[2]);
@@ -3550,7 +3579,7 @@ __attribute__((noinline)) void fast_delta8_bgra(const uint8_t* col1, const uint8
int r,g,b;
const uint8_t* const max_ptr = result + count;
- while(result < max_ptr) {
+ while (result < max_ptr) {
b = abs(col1[0] - col2[0]);
g = abs(col1[1] - col2[1]);
r = abs(col1[2] - col2[2]);
@@ -3578,7 +3607,7 @@ __attribute__((noinline)) void std_delta8_bgra(const uint8_t* col1, const uint8_
int r,g,b;
const uint8_t* const max_ptr = result + count;
- while(result < max_ptr) {
+ while (result < max_ptr) {
b = abs(col1[0] - col2[0]);
g = abs(col1[1] - col2[1]);
r = abs(col1[2] - col2[2]);
@@ -3596,7 +3625,7 @@ __attribute__((noinline)) void fast_delta8_argb(const uint8_t* col1, const uint8
int r,g,b;
const uint8_t* const max_ptr = result + count;
- while(result < max_ptr) {
+ while (result < max_ptr) {
r = abs(col1[1] - col2[1]);
g = abs(col1[2] - col2[2]);
b = abs(col1[3] - col2[3]);
@@ -3619,12 +3648,13 @@ __attribute__((noinline)) void fast_delta8_argb(const uint8_t* col1, const uint8
result += 4;
}
}
+
__attribute__((noinline)) void std_delta8_argb(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count) {
/* Loop unrolling is used to work on 16 bytes (4 rgb32 pixels) at a time */
int r,g,b;
const uint8_t* const max_ptr = result + count;
- while(result < max_ptr) {
+ while (result < max_ptr) {
r = abs(col1[1] - col2[1]);
g = abs(col1[2] - col2[2]);
b = abs(col1[3] - col2[3]);
@@ -3642,7 +3672,7 @@ __attribute__((noinline)) void fast_delta8_abgr(const uint8_t* col1, const uint8
int r,g,b;
const uint8_t* const max_ptr = result + count;
- while(result < max_ptr) {
+ while (result < max_ptr) {
b = abs(col1[1] - col2[1]);
g = abs(col1[2] - col2[2]);
r = abs(col1[3] - col2[3]);
@@ -3669,7 +3699,7 @@ __attribute__((noinline)) void std_delta8_abgr(const uint8_t* col1, const uint8_
int r,g,b;
const uint8_t* const max_ptr = result + count;
- while(result < max_ptr) {
+ while (result < max_ptr) {
b = abs(col1[1] - col2[1]);
g = abs(col1[2] - col2[2]);
r = abs(col1[3] - col2[3]);
diff --git a/src/zm_image.h b/src/zm_image.h
index 6be574dfb..1b8f614b9 100644
--- a/src/zm_image.h
+++ b/src/zm_image.h
@@ -152,9 +152,11 @@ protected:
static struct zm_error_mgr jpg_err;
unsigned int width;
+ unsigned int linesize;
unsigned int height;
unsigned int pixels;
unsigned int colours;
+ unsigned int padding;
unsigned int size;
unsigned int subpixelorder;
unsigned long allocation;
@@ -165,15 +167,18 @@ protected:
public:
Image();
- explicit Image( const char *filename );
- Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer=0);
+ explicit Image(const char *filename);
+ Image(int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer=0, unsigned int padding=0);
+ Image(int p_width, int p_linesize, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer=0, unsigned int padding=0);
explicit Image( const Image &p_image );
explicit Image( const AVFrame *frame );
+
~Image();
static void Initialise();
static void Deinitialise();
inline unsigned int Width() const { return width; }
+ inline unsigned int LineSize() const { return linesize; }
inline unsigned int Height() const { return height; }
inline unsigned int Pixels() const { return pixels; }
inline unsigned int Colours() const { return colours; }
@@ -182,7 +187,7 @@ public:
/* Internal buffer should not be modified from functions outside of this class */
inline const uint8_t* Buffer() const { return buffer; }
- inline const uint8_t* Buffer( unsigned int x, unsigned int y= 0 ) const { return &buffer[colours*((y*width)+x)]; }
+ inline const uint8_t* Buffer( unsigned int x, unsigned int y= 0 ) const { return &buffer[(y*linesize)+x]; }
/* Request writeable buffer */
uint8_t* WriteBuffer(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder);
@@ -193,21 +198,34 @@ public:
if ( !holdbuffer )
DumpImgBuffer();
- width = height = colours = size = pixels = subpixelorder = 0;
+ width = linesize = height = colours = size = pixels = subpixelorder = 0;
}
- void Assign( unsigned int p_width, unsigned int p_height, unsigned int p_colours, unsigned int p_subpixelorder, const uint8_t* new_buffer, const size_t buffer_size);
- void Assign( const Image &image );
- void AssignDirect( const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder, uint8_t *new_buffer, const size_t buffer_size, const int p_buffertype);
+ void Assign(
+ unsigned int p_width,
+ unsigned int p_height,
+ unsigned int p_colours,
+ unsigned int p_subpixelorder,
+ const uint8_t* new_buffer,
+ const size_t buffer_size);
+ void Assign(const Image &image);
+ void AssignDirect(
+ const unsigned int p_width,
+ const unsigned int p_height,
+ const unsigned int p_colours,
+ const unsigned int p_subpixelorder,
+ uint8_t *new_buffer,
+ const size_t buffer_size,
+ const int p_buffertype);
- inline void CopyBuffer( const Image &image ) {
+ inline void CopyBuffer(const Image &image) {
Assign(image);
}
- inline Image &operator=( const Image &image ) {
+ inline Image &operator=(const Image &image) {
Assign(image);
return *this;
}
- inline Image &operator=( const unsigned char *new_buffer ) {
+ inline Image &operator=(const unsigned char *new_buffer) {
(*fptr_imgbufcpy)(buffer, new_buffer, size);
return *this;
}
diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp
index c6030f08a..8274c1ce5 100644
--- a/src/zm_local_camera.cpp
+++ b/src/zm_local_camera.cpp
@@ -504,7 +504,7 @@ LocalCamera::LocalCamera(
subpixelorder = ZM_SUBPIX_ORDER_NONE;
} else if ( palette == V4L2_PIX_FMT_YUYV && colours == ZM_COLOUR_GRAY8 ) {
/* Fast YUYV->Grayscale conversion by extracting the Y channel */
- if ( config.cpu_extensions && sseversion >= 35 ) {
+ if ( config.cpu_extensions && sse_version >= 35 ) {
conversion_fptr = &ssse3_convert_yuyv_gray8;
Debug(2,"Using SSSE3 YUYV->grayscale fast conversion");
} else {
@@ -616,7 +616,7 @@ LocalCamera::LocalCamera(
}
} else if ( (palette == VIDEO_PALETTE_YUYV || palette == VIDEO_PALETTE_YUV422) && colours == ZM_COLOUR_GRAY8 ) {
/* Fast YUYV->Grayscale conversion by extracting the Y channel */
- if ( config.cpu_extensions && sseversion >= 35 ) {
+ if ( config.cpu_extensions && sse_version >= 35 ) {
conversion_fptr = &ssse3_convert_yuyv_gray8;
Debug(2,"Using SSSE3 YUYV->grayscale fast conversion");
} else {
diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp
index d06baf271..31ece8a0e 100644
--- a/src/zm_monitor.cpp
+++ b/src/zm_monitor.cpp
@@ -131,12 +131,12 @@ Monitor::MonitorLink::~MonitorLink() {
}
bool Monitor::MonitorLink::connect() {
- if ( !last_connect_time || (time( 0 ) - last_connect_time) > 60 ) {
+ if ( !last_connect_time || (time( 0 ) - last_connect_time) > ZM_MAX_RESTART_DELAY ) {
last_connect_time = time( 0 );
mem_size = sizeof(SharedData) + sizeof(TriggerData);
- Debug( 1, "link.mem.size=%d", mem_size );
+ Debug(1, "link.mem.size=%d", mem_size);
#if ZM_MEM_MAPPED
map_fd = open( mem_file, O_RDWR, (mode_t)0600 );
if ( map_fd < 0 ) {
@@ -379,6 +379,7 @@ Monitor::Monitor(
strncpy(event_prefix, p_event_prefix, sizeof(event_prefix)-1);
strncpy(label_format, p_label_format, sizeof(label_format)-1);
+ Debug(1, "encoder params %s", encoderparams.c_str());
// Change \n to actual line feeds
char *token_ptr = label_format;
@@ -531,6 +532,7 @@ Monitor::Monitor(
shared_data->last_write_index, shared_data->last_write_time );
sleep(1);
}
+
ref_image.Assign( width, height, camera->Colours(), camera->SubpixelOrder(),
image_buffer[shared_data->last_write_index].image->Buffer(), camera->ImageSize());
adaptive_skip = true;
@@ -605,7 +607,7 @@ bool Monitor::connect() {
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 ) {
- Error("mmap gave a null address:");
+ Error("mmap gave a NULL address:");
} else {
Debug(3, "mmapped to %p", mem_ptr);
}
@@ -1406,9 +1408,6 @@ bool Monitor::Analyse() {
score += trigger_data->trigger_score;
Debug(1, "Triggered on score += %d => %d", trigger_data->trigger_score, score);
if ( !event ) {
- // How could it have a length already?
- //if ( cause.length() )
- //cause += ", ";
cause += trigger_data->trigger_cause;
}
Event::StringSet noteSet;
@@ -1488,6 +1487,7 @@ bool Monitor::Analyse() {
score += 50;
}
} else {
+ Debug(1, "Linked monitor %d %d is not connected. Connecting.", i, linked_monitors[i]->Id());
linked_monitors[i]->connect();
}
} // end foreach linked_monit
@@ -1502,7 +1502,7 @@ bool Monitor::Analyse() {
if ( section_length
&& ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= section_length )
- && ( (event_close_mode != CLOSE_TIME) || ! ( timestamp->tv_sec % section_length ) )
+ && ( (function == MOCORD && (event_close_mode != CLOSE_TIME)) || ! ( timestamp->tv_sec % section_length ) )
) {
Info("%s: %03d - Closing event %" PRIu64 ", section end forced %d - %d = %d >= %d",
name, image_count, event->Id(),
@@ -1515,7 +1515,6 @@ bool Monitor::Analyse() {
} // end if event
if ( !event ) {
-
// Create event
event = new Event(this, *timestamp, "Continuous", noteSetMap, videoRecording);
shared_data->last_event = event->Id();
@@ -1529,7 +1528,6 @@ bool Monitor::Analyse() {
if ( state == IDLE ) {
shared_data->state = state = TAPE;
}
-
} // end if ! event
} // end if function == RECORD || function == MOCORD)
} // end if !signal_change && signal
@@ -1542,7 +1540,7 @@ bool Monitor::Analyse() {
&& (event_close_mode == CLOSE_ALARM)
&& ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= min_section_length )
) {
- Info("%s: %03d - Closing event %" PRIu64 ", continuous end, alarm begins",
+ Info("%s: %03d - Closing event %" PRIu64 ", continuous end, alarm begins",
name, image_count, event->Id());
closeEvent();
} else if ( event ) {
@@ -1553,7 +1551,6 @@ bool Monitor::Analyse() {
);
}
if ( (!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count-1) ) {
- shared_data->state = state = ALARM;
// lets construct alarm cause. It will contain cause + names of zones alarmed
std::string alarm_cause = "";
for ( int i=0; i < n_zones; i++ ) {
@@ -1638,6 +1635,7 @@ bool Monitor::Analyse() {
event->SavePreAlarmFrames();
}
}
+ shared_data->state = state = ALARM;
} else if ( state != PREALARM ) {
Info("%s: %03d - Gone into prealarm state", name, image_count);
shared_data->state = state = PREALARM;
@@ -1697,17 +1695,10 @@ bool Monitor::Analyse() {
} // end if zone is alarmed
} // end foreach zone
- if ( got_anal_image ) {
- if ( state == PREALARM )
- Event::AddPreAlarmFrame(snap_image, *timestamp, score, &alarm_image);
- else
- event->AddFrame(snap_image, *timestamp, score, &alarm_image);
- } else {
- if ( state == PREALARM )
- Event::AddPreAlarmFrame(snap_image, *timestamp, score);
- else
- event->AddFrame(snap_image, *timestamp, score);
- }
+ if ( state == PREALARM )
+ Event::AddPreAlarmFrame(snap_image, *timestamp, score, (got_anal_image?&alarm_image:NULL));
+ else
+ event->AddFrame(snap_image, *timestamp, score, (got_anal_image?&alarm_image:NULL));
} else {
// Not doing alarm frame storage
if ( state == PREALARM ) {
@@ -1743,7 +1734,6 @@ bool Monitor::Analyse() {
//set up video store data
snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile());
video_store_data->recording = event->StartTime();
-
}
} // end if event
@@ -2498,7 +2488,7 @@ int Monitor::Capture() {
if ( capture_image->Size() > camera->ImageSize() ) {
Error("Captured image %d does not match expected size %d check width, height and colour depth",
- capture_image->Size(),camera->ImageSize() );
+ capture_image->Size(), camera->ImageSize() );
return -1;
}
diff --git a/src/zm_monitor.h b/src/zm_monitor.h
index 9109c9c72..5c6a60c91 100644
--- a/src/zm_monitor.h
+++ b/src/zm_monitor.h
@@ -220,7 +220,7 @@ protected:
}
inline bool isConnected() const {
- return( connected );
+ return connected && shared_data->valid;
}
inline time_t getLastConnectTime() const {
return( last_connect_time );
@@ -463,7 +463,8 @@ public:
int GetOptSaveJPEGs() const { return savejpegs; }
VideoWriter GetOptVideoWriter() const { return videowriter; }
- const std::vector* GetOptEncoderParams() const { return &encoderparamsvec; }
+ const std::vector* GetOptEncoderParamsVec() const { return &encoderparamsvec; }
+ const std::string GetOptEncoderParams() const { return encoderparams; }
uint64_t GetVideoWriterEventId() const { return video_store_data->current_event; }
void SetVideoWriterEventId( unsigned long long p_event_id ) { video_store_data->current_event = p_event_id; }
struct timeval GetVideoWriterStartTime() const { return video_store_data->recording; }
diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp
index 49d617f7d..8a3b5511e 100644
--- a/src/zm_monitorstream.cpp
+++ b/src/zm_monitorstream.cpp
@@ -329,8 +329,11 @@ bool MonitorStream::sendFrame(const char *filepath, struct timeval *timestamp) {
gettimeofday(&frameStartTime, NULL);
fputs("--ZoneMinderFrame\r\nContent-Type: image/jpeg\r\n", stdout);
- fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size);
- if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
+ if (
+ (0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size))
+ ||
+ (fwrite(img_buffer, img_buffer_size, 1, stdout) != 1)
+ ) {
if ( !zm_terminate )
Warning("Unable to send stream frame: %s", strerror(errno));
return false;
@@ -385,7 +388,7 @@ bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) {
gettimeofday(&frameStartTime, NULL);
fputs("--ZoneMinderFrame\r\n", stdout);
- switch( type ) {
+ switch ( type ) {
case STREAM_JPEG :
send_image->EncodeJpeg(img_buffer, &img_buffer_size);
fputs("Content-Type: image/jpeg\r\n", stdout);
@@ -410,8 +413,11 @@ bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) {
Error("Unexpected frame type %d", type);
return false;
}
- fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size);
- if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
+ if (
+ (0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size))
+ ||
+ (fwrite(img_buffer, img_buffer_size, 1, stdout) != 1)
+ ) {
if ( !zm_terminate ) {
// If the pipe was closed, we will get signalled SIGPIPE to exit, which will set zm_terminate
Warning("Unable to send stream frame: %s", strerror(errno));
diff --git a/src/zm_remote_camera_http.cpp b/src/zm_remote_camera_http.cpp
index f725d17b9..57a677a7b 100644
--- a/src/zm_remote_camera_http.cpp
+++ b/src/zm_remote_camera_http.cpp
@@ -618,8 +618,8 @@ int RemoteCameraHttp::GetResponse() {
static char *content_type_header;
static char *boundary_header;
static char *authenticate_header;
- static char subcontent_length_header[32];
- static char subcontent_type_header[64];
+ static char subcontent_length_header[33];
+ static char subcontent_type_header[65];
static char http_version[16];
static char status_code[16];
@@ -892,25 +892,37 @@ int RemoteCameraHttp::GetResponse() {
}
}
- Debug( 6, "%d: %s", subheader_len, subheader_ptr );
+ Debug(6, "%d: %s", subheader_len, subheader_ptr);
- if ( (crlf = mempbrk( subheader_ptr, "\r\n", subheader_len )) ) {
+ if ( (crlf = mempbrk(subheader_ptr, "\r\n", subheader_len)) ) {
//subheaders[n_subheaders++] = subheader_ptr;
n_subheaders++;
- if ( !boundary_header && (strncasecmp( subheader_ptr, content_boundary, content_boundary_len ) == 0) ) {
+ if ( !boundary_header && (strncasecmp(subheader_ptr, content_boundary, content_boundary_len) == 0) ) {
boundary_header = subheader_ptr;
- Debug( 4, "Got boundary subheader '%s'", subheader_ptr );
- } else if ( !subcontent_length_header[0] && (strncasecmp( subheader_ptr, content_length_match, content_length_match_len) == 0) ) {
- strncpy( subcontent_length_header, subheader_ptr+content_length_match_len, sizeof(subcontent_length_header) );
- *(subcontent_length_header+strcspn( subcontent_length_header, "\r\n" )) = '\0';
- Debug( 4, "Got content length subheader '%s'", subcontent_length_header );
+ Debug(4, "Got boundary subheader '%s'", subheader_ptr);
+ } else if (
+ !subcontent_length_header[0]
+ &&
+ (strncasecmp(subheader_ptr, content_length_match, content_length_match_len) == 0)
+ ) {
+ strncpy(
+ subcontent_length_header,
+ subheader_ptr+content_length_match_len,
+ sizeof(subcontent_length_header)-1
+ );
+ *(subcontent_length_header+strcspn(subcontent_length_header, "\r\n")) = '\0';
+ Debug(4, "Got content length subheader '%s'", subcontent_length_header);
} else if ( !subcontent_type_header[0] && (strncasecmp( subheader_ptr, content_type_match, content_type_match_len) == 0) ) {
- strncpy( subcontent_type_header, subheader_ptr+content_type_match_len, sizeof(subcontent_type_header) );
- *(subcontent_type_header+strcspn( subcontent_type_header, "\r\n" )) = '\0';
- Debug( 4, "Got content type subheader '%s'", subcontent_type_header );
+ strncpy(
+ subcontent_type_header,
+ subheader_ptr+content_type_match_len,
+ sizeof(subcontent_type_header)-1
+ );
+ *(subcontent_type_header+strcspn(subcontent_type_header, "\r\n")) = '\0';
+ Debug(4, "Got content type subheader '%s'", subcontent_type_header);
} else {
- Debug( 6, "Got ignored subheader '%s' found", subheader_ptr );
+ Debug(6, "Got ignored subheader '%s' found", subheader_ptr);
}
subheader_ptr = crlf;
subheader_len -= buffer.consume( subheader_ptr-(char *)buffer );
diff --git a/src/zm_utils.cpp b/src/zm_utils.cpp
index ad1bfd001..323d3c3b4 100644
--- a/src/zm_utils.cpp
+++ b/src/zm_utils.cpp
@@ -35,7 +35,7 @@
#include
#endif
-unsigned int sseversion = 0;
+unsigned int sse_version = 0;
unsigned int neonversion = 0;
std::string trimSet(std::string str, std::string trimset) {
@@ -44,12 +44,9 @@ std::string trimSet(std::string str, std::string trimset) {
size_t endpos = str.find_last_not_of(trimset); // Find the first character position from reverse af
// if all spaces or empty return an empty string
- if(( std::string::npos == startpos ) || ( std::string::npos == endpos))
- {
+ if ( ( std::string::npos == startpos ) || ( std::string::npos == endpos ) )
return std::string("");
- }
- else
- return str.substr( startpos, endpos-startpos+1 );
+ return str.substr(startpos, endpos-startpos+1);
}
std::string trimSpaces(const std::string &str) {
@@ -57,48 +54,46 @@ std::string trimSpaces(const std::string &str) {
}
std::string replaceAll(std::string str, std::string from, std::string to) {
- if(from.empty())
+ if ( from.empty() )
return str;
size_t start_pos = 0;
- while((start_pos = str.find(from, start_pos)) != std::string::npos) {
+ while ( (start_pos = str.find(from, start_pos)) != std::string::npos ) {
str.replace(start_pos, from.length(), to);
start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
}
return str;
}
-const std::string stringtf( const char *format, ... )
-{
+const std::string stringtf( const char *format, ... ) {
va_list ap;
char tempBuffer[8192];
std::string tempString;
- va_start(ap, format );
- vsnprintf( tempBuffer, sizeof(tempBuffer), format , ap );
+ va_start(ap, format);
+ vsnprintf(tempBuffer, sizeof(tempBuffer), format , ap);
va_end(ap);
tempString = tempBuffer;
- return( tempString );
+ return tempString;
}
-const std::string stringtf( const std::string format, ... )
-{
+const std::string stringtf(const std::string format, ...) {
va_list ap;
char tempBuffer[8192];
std::string tempString;
- va_start(ap, format );
- vsnprintf( tempBuffer, sizeof(tempBuffer), format.c_str() , ap );
+ va_start(ap, format);
+ vsnprintf(tempBuffer, sizeof(tempBuffer), format.c_str(), ap);
va_end(ap);
tempString = tempBuffer;
- return( tempString );
+ return tempString;
}
bool startsWith(const std::string &haystack, const std::string &needle) {
- return( haystack.substr(0, needle.length()) == needle );
+ return ( haystack.substr(0, needle.length()) == needle );
}
StringVector split(const std::string &string, const std::string &chars, int limit) {
@@ -145,8 +140,7 @@ const std::string join(const StringVector &v, const char * delim=",") {
const std::string base64Encode(const std::string &inString) {
static char base64_table[64] = { '\0' };
- if ( !base64_table[0] )
- {
+ if ( !base64_table[0] ) {
int i = 0;
for ( char c = 'A'; c <= 'Z'; c++ )
base64_table[i++] = c;
@@ -159,59 +153,52 @@ const std::string base64Encode(const std::string &inString) {
}
std::string outString;
- outString.reserve( 2 * inString.size() );
+ outString.reserve(2 * inString.size());
const char *inPtr = inString.c_str();
- while( *inPtr )
- {
+ while ( *inPtr ) {
unsigned char selection = *inPtr >> 2;
unsigned char remainder = (*inPtr++ & 0x03) << 4;
outString += base64_table[selection];
- if ( *inPtr )
- {
+ if ( *inPtr ) {
selection = remainder | (*inPtr >> 4);
remainder = (*inPtr++ & 0x0f) << 2;
outString += base64_table[selection];
- if ( *inPtr )
- {
+ if ( *inPtr ) {
selection = remainder | (*inPtr >> 6);
outString += base64_table[selection];
selection = (*inPtr++ & 0x3f);
outString += base64_table[selection];
- }
- else
- {
+ } else {
outString += base64_table[remainder];
outString += '=';
}
- }
- else
- {
+ } else {
outString += base64_table[remainder];
outString += '=';
outString += '=';
}
}
- return( outString );
+ return outString;
}
int split(const char* string, const char delim, std::vector& items) {
- if(string == NULL)
+ if ( string == NULL )
return -1;
- if(string[0] == 0)
+ if ( string[0] == 0 )
return -2;
std::string str(string);
- while(true) {
+ while ( true ) {
size_t pos = str.find(delim);
items.push_back(str.substr(0, pos));
str.erase(0, pos+1);
- if(pos == std::string::npos)
+ if ( pos == std::string::npos )
break;
}
@@ -219,16 +206,16 @@ 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 == NULL )
return -1;
- if(string[0] == 0)
+ if ( string[0] == 0 )
return -2;
std::string str(string);
size_t pos = str.find(delim);
- if(pos == std::string::npos || pos == 0 || pos >= str.length())
+ if ( pos == std::string::npos || pos == 0 || pos >= str.length() )
return -3;
name = str.substr(0, pos);
@@ -240,7 +227,7 @@ int pairsplit(const char* string, const char delim, std::string& name, std::stri
/* Detect special hardware features, such as SIMD instruction sets */
void hwcaps_detect() {
neonversion = 0;
- sseversion = 0;
+ sse_version = 0;
#if (defined(__i386__) || defined(__x86_64__))
/* x86 or x86-64 processor */
uint32_t r_edx, r_ecx, r_ebx;
@@ -277,33 +264,33 @@ void hwcaps_detect() {
);
#endif
- if (r_ebx & 0x00000020) {
- sseversion = 52; /* AVX2 */
- Debug(1,"Detected a x86\\x86-64 processor with AVX2");
- } else if (r_ecx & 0x10000000) {
- sseversion = 51; /* AVX */
- Debug(1,"Detected a x86\\x86-64 processor with AVX");
- } else if (r_ecx & 0x00100000) {
- sseversion = 42; /* SSE4.2 */
- Debug(1,"Detected a x86\\x86-64 processor with SSE4.2");
- } else if (r_ecx & 0x00080000) {
- sseversion = 41; /* SSE4.1 */
- Debug(1,"Detected a x86\\x86-64 processor with SSE4.1");
- } else if (r_ecx & 0x00000200) {
- sseversion = 35; /* SSSE3 */
+ if ( r_ebx & 0x00000020 ) {
+ sse_version = 52; /* AVX2 */
+ Debug(1, "Detected a x86\\x86-64 processor with AVX2");
+ } else if ( r_ecx & 0x10000000 ) {
+ sse_version = 51; /* AVX */
+ Debug(1, "Detected a x86\\x86-64 processor with AVX");
+ } else if ( r_ecx & 0x00100000 ) {
+ sse_version = 42; /* SSE4.2 */
+ Debug(1, "Detected a x86\\x86-64 processor with SSE4.2");
+ } else if ( r_ecx & 0x00080000 ) {
+ sse_version = 41; /* SSE4.1 */
+ Debug(1, "Detected a x86\\x86-64 processor with SSE4.1");
+ } else if ( r_ecx & 0x00000200 ) {
+ sse_version = 35; /* SSSE3 */
Debug(1,"Detected a x86\\x86-64 processor with SSSE3");
- } else if (r_ecx & 0x00000001) {
- sseversion = 30; /* SSE3 */
- Debug(1,"Detected a x86\\x86-64 processor with SSE3");
- } else if (r_edx & 0x04000000) {
- sseversion = 20; /* SSE2 */
- Debug(1,"Detected a x86\\x86-64 processor with SSE2");
- } else if (r_edx & 0x02000000) {
- sseversion = 10; /* SSE */
- Debug(1,"Detected a x86\\x86-64 processor with SSE");
+ } else if ( r_ecx & 0x00000001 ) {
+ sse_version = 30; /* SSE3 */
+ Debug(1, "Detected a x86\\x86-64 processor with SSE3");
+ } else if ( r_edx & 0x04000000 ) {
+ sse_version = 20; /* SSE2 */
+ Debug(1, "Detected a x86\\x86-64 processor with SSE2");
+ } else if ( r_edx & 0x02000000 ) {
+ sse_version = 10; /* SSE */
+ Debug(1, "Detected a x86\\x86-64 processor with SSE");
} else {
- sseversion = 0;
- Debug(1,"Detected a x86\\x86-64 processor");
+ sse_version = 0;
+ Debug(1, "Detected a x86\\x86-64 processor");
}
#elif defined(__arm__)
// ARM processor in 32bit mode
diff --git a/src/zm_utils.h b/src/zm_utils.h
index 9a8dd1948..9c8cc01a0 100644
--- a/src/zm_utils.h
+++ b/src/zm_utils.h
@@ -59,7 +59,7 @@ void* sse2_aligned_memcpy(void* dest, const void* src, size_t bytes);
void timespec_diff(struct timespec *start, struct timespec *end, struct timespec *diff);
void hwcaps_detect();
-extern unsigned int sseversion;
+extern unsigned int sse_version;
extern unsigned int neonversion;
char *timeval_to_string( struct timeval tv );
diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp
index 6acee0cfd..19f1251e2 100644
--- a/src/zm_videostore.cpp
+++ b/src/zm_videostore.cpp
@@ -37,11 +37,12 @@ VideoStore::VideoStore(
const char *format_in,
AVStream *p_video_in_stream,
AVStream *p_audio_in_stream,
- Monitor *monitor
+ Monitor *p_monitor
) {
video_in_stream = p_video_in_stream;
audio_in_stream = p_audio_in_stream;
+ monitor = p_monitor;
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
//video_in_ctx = avcodec_alloc_context3(NULL);
@@ -213,11 +214,18 @@ VideoStore::VideoStore(
}
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
+#if 0
+# This is commented out because we are only doing passthrough right now
/* I'm not entirely sure that this is a good idea. We may have to do it someday but really only when transcoding
* * think what I was trying to achieve here was to have zm_dump_codecpar output nice info
* */
-#if 0
+
AVDictionary *opts = 0;
+ ret = av_dict_parse_string(&opts, monitor->GetOptEncoderParams().c_str(), "=", ",", 0);
+ if ( ret < 0 ) {
+ Warning("Could not parse ffmpeg encoder options '%s'", monitor->GetOptEncoderParams().c_str());
+ }
+
if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) {
Warning("Can't open video codec (%s) %s",
video_out_codec->name,
@@ -404,21 +412,39 @@ bool VideoStore::open() {
}
zm_dump_stream_format(oc, 0, 0, 1);
- if (audio_out_stream) zm_dump_stream_format(oc, 1, 0, 1);
+ if ( audio_out_stream ) zm_dump_stream_format(oc, 1, 0, 1);
AVDictionary *opts = NULL;
- // av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
- // Shiboleth reports that this may break seeking in mp4 before it downloads
- av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
- // av_dict_set(&opts, "movflags",
- // "frag_keyframe+empty_moov+default_base_moof", 0);
+
+ std::string option_string = monitor->GetOptEncoderParams();
+ ret = av_dict_parse_string(&opts, option_string.c_str(), "=", ",\n", 0);
+ if ( ret < 0 ) {
+ 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);
+ if ( !movflags_entry ) {
+ Debug(1, "setting movflags to frag_keyframe+empty_moov");
+ // av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
+ // Shiboleth reports that this may break seeking in mp4 before it downloads
+ av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
+ // av_dict_set(&opts, "movflags",
+ // "frag_keyframe+empty_moov+default_base_moof", 0);
+ } else {
+ Debug(1, "using movflags %s", movflags_entry->value);
+ }
if ( (ret = avformat_write_header(oc, &opts)) < 0 ) {
- // if ((ret = avformat_write_header(oc, &opts)) < 0) {
- Warning("Unable to set movflags to frag_custom+dash+delay_moov");
- /* Write the stream header, if any. */
+ Warning("Unable to set movflags trying with defaults.");
ret = avformat_write_header(oc, NULL);
- } else if (av_dict_count(opts) != 0) {
- Warning("some options not set");
+ } 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 ) {
+ Debug(1, "Encoder Option %s=>%s", e->key, e->value);
+ if ( !e->value ) {
+ av_dict_set(&opts, e->key, NULL, 0);
+ }
+ }
}
if ( opts ) av_dict_free(&opts);
if ( ret < 0 ) {
diff --git a/src/zm_videostore.h b/src/zm_videostore.h
index 7c465ea4b..64c2296ba 100644
--- a/src/zm_videostore.h
+++ b/src/zm_videostore.h
@@ -19,7 +19,6 @@ extern "C" {
class VideoStore {
private:
-
AVOutputFormat *out_format;
AVFormatContext *oc;
@@ -30,6 +29,7 @@ private:
AVStream *video_in_stream;
AVStream *audio_in_stream;
+ Monitor *monitor;
// Move this into the object so that we aren't constantly allocating/deallocating it on the stack
AVPacket opkt;
diff --git a/src/zm_zone.cpp b/src/zm_zone.cpp
index 1e0a16cda..ea6c170ac 100644
--- a/src/zm_zone.cpp
+++ b/src/zm_zone.cpp
@@ -227,7 +227,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
Debug(4, "Checking alarms for zone %d/%s in lines %d -> %d", id, label, lo_y, hi_y);
- /* if(config.cpu_extensions && sseversion >= 20) {
+ /* if(config.cpu_extensions && sse_version >= 20) {
sse2_alarmedpixels(diff_image, pg_image, &alarm_pixels, &pixel_diff_count);
} else {
std_alarmedpixels(diff_image, pg_image, &alarm_pixels, &pixel_diff_count);
diff --git a/src/zmc.cpp b/src/zmc.cpp
index 511e019ab..22132e668 100644
--- a/src/zmc.cpp
+++ b/src/zmc.cpp
@@ -259,7 +259,8 @@ int main(int argc, char *argv[]) {
Debug(1, "Failed to prime capture of initial monitor");
}
prime_capture_log_count ++;
- sleep(10);
+ if ( !zm_terminate )
+ sleep(10);
continue;
}
diff --git a/utils/do_debian_package.sh b/utils/do_debian_package.sh
index f6a5c6bec..c907fa64d 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,disco,eoan,focal,trusty"
+ DISTROS="xenial,bionic,focal,trusty"
else
DISTROS=`lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'`;
fi;
@@ -220,14 +220,19 @@ IFS=',' ;for DISTRO in `echo "$DISTROS"`; do
fi;
# Generate Changlog
- if [ "$DISTRO" == "trusty" ] || [ "$DISTRO" == "precise" ]; then
+ if [ "$DISTRO" == "trusty" ] || [ "$DISTRO" == "precise" ]
+ then
cp -Rpd distros/ubuntu1204 debian
- else
- if [ "$DISTRO" == "wheezy" ]; then
- cp -Rpd distros/debian debian
- else
- cp -Rpd distros/ubuntu1604 debian
- fi;
+
+ elif [ "$DISTRO" == "wheezy" ]
+ then
+ cp -Rpd distros/debian debian
+
+ elif [ "$DISTRO" == "beowulf" ]
+ then
+ cp -Rpd distros/beowulf debian
+ else
+ cp -Rpd distros/ubuntu1604 debian
fi;
if [ "$DEBEMAIL" != "" ] && [ "$DEBFULLNAME" != "" ]; then
diff --git a/utils/packpack/rsync_xfer.sh b/utils/packpack/rsync_xfer.sh
index c9a737a03..5078194a4 100755
--- a/utils/packpack/rsync_xfer.sh
+++ b/utils/packpack/rsync_xfer.sh
@@ -37,7 +37,7 @@ echo "Target subfolder set to $targetfolder"
echo
echo "Running \$(rsync -v -e 'ssh -vvv' build/*.{rpm,deb,dsc,tar.xz,buildinfo,changes} zmrepo@zmrepo.zoneminder.com:${targetfolder}/ 2>&1)"
-rsync -v --ignore-missing-args --exclude 'external-repo.noarch.rpm' -e 'ssh -vvv' build/*.{rpm,deb,dsc,tar.xz,buildinfo,changes} zmrepo@zmrepo.zoneminder.com:${targetfolder}/ 2>&1
+rsync -v --ignore-missing-args --exclude 'external-repo.noarch.rpm' -e 'ssh -v' build/*.{rpm,deb,dsc,tar.xz,buildinfo,changes} zmrepo@zmrepo.zoneminder.com:${targetfolder}/ 2>&1
if [ "$?" -eq 0 ]; then
echo
echo "Files copied successfully."
diff --git a/version b/version
index 46a99f18d..f883b434e 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-1.34.14
+1.34.20
diff --git a/web/ajax/status.php b/web/ajax/status.php
index fea5943ca..e34f6fe6f 100644
--- a/web/ajax/status.php
+++ b/web/ajax/status.php
@@ -19,7 +19,7 @@ $statusData = array(
'limit' => 1,
'elements' => array(
'MonitorCount' => array( 'sql' => 'count(*)' ),
- 'ActiveMonitorCount' => array( 'sql' => 'count(if(Function != \'None\',1,NULL))' ),
+ 'ActiveMonitorCount' => array( 'sql' => 'count(if(`Function` != \'None\',1,NULL))' ),
'State' => array( 'func' => 'daemonCheck()?'.translate('Running').':'.translate('Stopped') ),
'Load' => array( 'func' => 'getLoad()' ),
'Disk' => array( 'func' => 'getDiskPercent()' ),
@@ -211,17 +211,17 @@ function collectData() {
$values = array();
$elements = &$entitySpec['elements'];
- $lc_elements = array_change_key_case( $elements );
+ $lc_elements = array_change_key_case($elements);
$id = false;
if ( isset($_REQUEST['id']) )
if ( !is_array($_REQUEST['id']) )
$id = array( validJsStr($_REQUEST['id']) );
else
- $id = array_values( $_REQUEST['id'] );
+ $id = array_values($_REQUEST['id']);
if ( !isset($_REQUEST['element']) )
- $_REQUEST['element'] = array_keys( $elements );
+ $_REQUEST['element'] = array_keys($elements);
else if ( !is_array($_REQUEST['element']) )
$_REQUEST['element'] = array( validJsStr($_REQUEST['element']) );
@@ -235,18 +235,18 @@ function collectData() {
foreach ( $_REQUEST['element'] as $element ) {
if ( !($elementData = $lc_elements[strtolower($element)]) )
- ajaxError( 'Bad '.validJsStr($_REQUEST['entity']).' element '.$element );
+ ajaxError('Bad '.validJsStr($_REQUEST['entity']).' element '.$element);
if ( isset($elementData['func']) )
- $data[$element] = eval( 'return( '.$elementData['func'].' );' );
+ $data[$element] = eval('return( '.$elementData['func'].' );');
else if ( isset($elementData['postFunc']) )
$postFuncs[$element] = $elementData['postFunc'];
else if ( isset($elementData['zmu']) )
- $data[$element] = exec( escapeshellcmd( getZmuCommand( ' '.$elementData['zmu'] ) ) );
+ $data[$element] = exec(escapeshellcmd(getZmuCommand(' '.$elementData['zmu'])));
else {
if ( isset($elementData['sql']) )
$fieldSql[] = $elementData['sql'].' as '.$element;
else
- $fieldSql[] = $element;
+ $fieldSql[] = '`'.$element.'`';
if ( isset($elementData['table']) && isset($elementData['join']) ) {
$joinSql[] = 'left join '.$elementData['table'].' on '.$elementData['join'];
}
@@ -285,7 +285,7 @@ function collectData() {
preg_match('/^(\w+)\s*(ASC|DESC)?( NULLS FIRST)?$/i', $sort_field, $matches);
if ( count($matches) ) {
- if ( in_array($matches[1], $fieldSql) ) {
+ if ( in_array($matches[1], $fieldSql) or in_array('`'.$matches[1].'`', $fieldSql) ) {
$sql .= $matches[1];
} else {
ZM\Error('Sort field ' . $matches[1] . ' not in SQL Fields');
@@ -296,7 +296,7 @@ function collectData() {
$sql .= ' '.strtoupper($matches[3]);
}
} else {
- ZM\Error("Sort field didn't match regexp $sort_field");
+ ZM\Error('Sort field didn\'t match regexp '.$sort_field);
}
} # end foreach sort field
} # end if has sort
@@ -310,7 +310,7 @@ function collectData() {
if ( !empty( $limit ) )
$sql .= ' limit '.$limit_offset.$limit;
if ( isset($limit) && $limit == 1 ) {
- if ( $sqlData = dbFetchOne( $sql, NULL, $values ) ) {
+ if ( $sqlData = dbFetchOne($sql, NULL, $values) ) {
foreach ( $postFuncs as $element=>$func )
$sqlData[$element] = eval( 'return( '.$func.'( $sqlData ) );' );
$data = array_merge( $data, $sqlData );
diff --git a/web/api/app/Config/bootstrap.php.in b/web/api/app/Config/bootstrap.php.in
index 881c08eb5..894b3ec00 100644
--- a/web/api/app/Config/bootstrap.php.in
+++ b/web/api/app/Config/bootstrap.php.in
@@ -102,21 +102,21 @@ CakeLog::config('debug', array(
'engine' => 'File',
'types' => array('notice', 'info', 'debug'),
'file' => 'cake_debug',
- 'path' => '@ZM_LOGDIR@/'
+ 'path' => '@ZM_LOGDIR@/'
));
CakeLog::config('error', array(
'engine' => 'File',
'types' => array('warning', 'error', 'critical', 'alert', 'emergency'),
'file' => 'cake_error',
- 'path' => '@ZM_LOGDIR@/'
+ 'path' => '@ZM_LOGDIR@/'
));
CakeLog::config('custom_path', array(
- 'engine' => 'File',
- 'path' => '@ZM_LOGDIR@/'
+ 'engine' => 'File',
+ 'path' => '@ZM_LOGDIR@/'
));
-Configure::write('ZM_CONFIG', '@ZM_CONFIG@');
-Configure::write('ZM_CONFIG_SUBDIR', '@ZM_CONFIG_SUBDIR@');
+Configure::write('ZM_CONFIG', '@ZM_CONFIG@');
+Configure::write('ZM_CONFIG_SUBDIR', '@ZM_CONFIG_SUBDIR@');
Configure::write('ZM_VERSION', '@VERSION@');
Configure::write('ZM_API_VERSION', '@API_VERSION@');
@@ -128,27 +128,3 @@ global $configvals;
foreach( $configvals as $key => $value) {
Configure::write($key, $value);
}
-if ( 0 ) {
- // No longer needed, but I want to keep the code for reference
- //
-// For Human-readability, use ZM_SERVER_HOST or ZM_SERVER_NAME in zm.conf, and convert it here to a ZM_SERVER_ID
-if ( ! defined('ZM_SERVER_ID') ) {
- App::uses('ClassRegistry', 'Utility');
- $ServerModel = ClassRegistry::init('Server');
- if ( defined('ZM_SERVER_NAME') and ZM_SERVER_NAME ) {
- $Server = $ServerModel->find( 'first', array( 'conditions'=>array('Name'=>ZM_SERVER_NAME) ) );
- if ( ! $Server ) {
- Error('Invalid Multi-Server configration detected. ZM_SERVER_NAME set to ' . ZM_SERVER_NAME . ' in zm.conf, but no corresponding entry found in Servers table.');
- } else {
- define( 'ZM_SERVER_ID', $Server['Server']['Id'] );
- }
- } else if ( defined('ZM_SERVER_HOST') and ZM_SERVER_HOST ) {
- $Server = $ServerModel->find( 'first', array( 'conditions'=>array('Name'=>ZM_SERVER_HOST) ) );
- if ( ! $Server ) {
- Error('Invalid Multi-Server configration detected. ZM_SERVER_HOST set to ' . ZM_SERVER_HOST . ' in zm.conf, but no corresponding entry found in Servers table.');
- } else {
- define( 'ZM_SERVER_ID', $Server['Server']['Id'] );
- }
- }
-}
-}
diff --git a/web/api/app/Controller/EventsController.php b/web/api/app/Controller/EventsController.php
index 5188c18b4..3b132e932 100644
--- a/web/api/app/Controller/EventsController.php
+++ b/web/api/app/Controller/EventsController.php
@@ -434,14 +434,11 @@ class EventsController extends AppController {
// Find the max Frame for this Event. Error out otherwise.
$this->loadModel('Frame');
- if (! $frame = $this->Frame->find('first', array(
+ $frame = $this->Frame->find('first', array(
'conditions' => array(
- 'EventId' => $event['Event']['Id'],
- 'Score' => $event['Event']['MaxScore']
- )
- ))) {
- throw new NotFoundException(__('Can not find Frame for Event ' . $event['Event']['Id']));
- }
- return $frame['Frame']['Id'];
+ 'EventId' => $event['Event']['Id'],
+ 'Score' => $event['Event']['MaxScore']
+ )));
+ return empty($frame)?null:$frame['Frame']['Id'];
}
} // end class EventsController
diff --git a/web/api/app/Controller/UsersController.php b/web/api/app/Controller/UsersController.php
index 6b691cee1..502a929ff 100644
--- a/web/api/app/Controller/UsersController.php
+++ b/web/api/app/Controller/UsersController.php
@@ -14,6 +14,18 @@ class UsersController extends AppController {
*/
public $components = array('RequestHandler', 'Paginator');
+ public function beforeFilter() {
+ parent::beforeFilter();
+
+ global $user;
+ # We already tested for auth in appController, so we just need to test for specific permission
+ $canView = (!$user) || ($user['System'] != 'None');
+ if ( !$canView ) {
+ throw new UnauthorizedException(__('Insufficient Privileges'));
+ return;
+ }
+ }
+
/**
* index method
*
@@ -23,6 +35,12 @@ class UsersController extends AppController {
public function index() {
$this->User->recursive = 0;
+ global $user;
+ # We should actually be able to list our own user, but I'm not bothering at this time.
+ if ( $user['System'] == 'None' ) {
+ throw new UnauthorizedException(__('Insufficient Privileges'));
+ return;
+ }
$users = $this->Paginator->paginate('User');
$this->set(compact('users'));
@@ -36,16 +54,20 @@ class UsersController extends AppController {
* @return void
*/
public function view($id = null) {
- $this->loadModel('Config');
- $configs = $this->Config->find('list', array(
- 'fields' => array('Name', 'Value'),
- 'conditions' => array('Name' => array('ZM_DIR_EVENTS'))
- ));
-
$this->User->recursive = 1;
- if (!$this->User->exists($id)) {
+
+ global $user;
+ # We can view ourselves
+ $canView = ($user['System'] != 'None') or ($user['Id'] == $id);
+ if ( !$canView ) {
+ throw new UnauthorizedException(__('Insufficient Privileges'));
+ return;
+ }
+
+ if ( !$this->User->exists($id) ) {
throw new NotFoundException(__('Invalid user'));
}
+
$options = array('conditions' => array('User.' . $this->User->primaryKey => $id));
$user = $this->User->find('first', $options);
@@ -61,9 +83,16 @@ class UsersController extends AppController {
* @return void
*/
public function add() {
- if ($this->request->is('post')) {
+ if ( $this->request->is('post') ) {
+
+ global $user;
+ if ( $user['System'] != 'Edit' ) {
+ throw new UnauthorizedException(__('Insufficient Privileges'));
+ return;
+ }
+
$this->User->create();
- if ($this->User->save($this->request->data)) {
+ if ( $this->User->save($this->request->data) ) {
return $this->flash(__('The user has been saved.'), array('action' => 'index'));
}
$this->Session->setFlash(
@@ -82,20 +111,29 @@ class UsersController extends AppController {
public function edit($id = null) {
$this->User->id = $id;
- if (!$this->User->exists($id)) {
+ global $user;
+ $canEdit = ($user['System'] == 'Edit') or (($user['Id'] == $id) and ZM_USER_SELF_EDIT);
+ if ( !$canEdit ) {
+ throw new UnauthorizedException(__('Insufficient Privileges'));
+ return;
+ }
+
+ if ( !$this->User->exists($id) ) {
throw new NotFoundException(__('Invalid user'));
}
- if ($this->request->is('post') || $this->request->is('put')) {
- if ($this->User->save($this->request->data)) {
+ if ( $this->request->is('post') || $this->request->is('put') ) {
+ if ( $this->User->save($this->request->data) ) {
$message = 'Saved';
} else {
$message = 'Error';
}
} else {
- $this->request->data = $this->User->read(null, $id);
- unset($this->request->data['User']['password']);
- }
+ # What is this doing? Resetting the request data? I understand clearing the password field
+ # but generally I feel like the request data should be read only
+ $this->request->data = $this->User->read(null, $id);
+ unset($this->request->data['User']['Password']);
+ }
$this->set(array(
'message' => $message,
@@ -112,11 +150,18 @@ class UsersController extends AppController {
*/
public function delete($id = null) {
$this->User->id = $id;
- if (!$this->User->exists()) {
+
+ global $user;
+ # Can't delete ourselves
+ if ( ($user['System'] != 'Edit') or ($user['Id'] == $id) ) {
+ throw new UnauthorizedException(__('Insufficient Privileges'));
+ return;
+ }
+ if ( !$this->User->exists() ) {
throw new NotFoundException(__('Invalid user'));
}
$this->request->allowMethod('post', 'delete');
- if ($this->User->delete()) {
+ if ( $this->User->delete() ) {
$message = 'The user has been deleted.';
} else {
$message = 'The user could not be deleted. Please, try again.';
@@ -126,47 +171,4 @@ class UsersController extends AppController {
'_serialize' => array('message')
));
}
-
- public function beforeFilter() {
- parent::beforeFilter();
-
- $this->loadModel('Config');
- $configs = $this->Config->find('list', array(
- 'fields' => array('Name', 'Value'),
- 'conditions' => array('Name' => array('ZM_OPT_USE_AUTH'))
- ));
- if ( $configs['ZM_OPT_USE_AUTH'] ) {
- $this->Auth->allow('add','logout');
- } else {
- $this->Auth->allow();
- }
- }
-
- public function login() {
- $this->loadModel('Config');
- $configs = $this->Config->find('list', array(
- 'fields' => array('Name', 'Value'),
- 'conditions' => array('Name' => array('ZM_OPT_USE_AUTH'))
- ));
-
- if ( ! $configs['ZM_OPT_USE_AUTH'] ) {
- $this->set(array(
- 'message' => 'Login is not required.',
- '_serialize' => array('message')
- ));
- return;
- }
-
- if ($this->request->is('post')) {
- if ($this->Auth->login()) {
- return $this->redirect($this->Auth->redirectUrl());
- }
- $this->Session->setFlash(__('Invalid username or password, try again'));
- }
- }
-
- public function logout() {
- return $this->redirect($this->Auth->logout());
- }
-
-}
+} # end class UsersController
diff --git a/web/api/app/Controller/ZonesController.php b/web/api/app/Controller/ZonesController.php
index 5b8c3f1a3..f01931f65 100644
--- a/web/api/app/Controller/ZonesController.php
+++ b/web/api/app/Controller/ZonesController.php
@@ -40,6 +40,7 @@ class ZonesController extends AppController {
'_serialize' => array('zones')
));
}
+
public function index() {
$this->Zone->recursive = -1;
@@ -63,23 +64,43 @@ class ZonesController extends AppController {
* @return void
*/
public function add() {
- if ( $this->request->is('post') ) {
- global $user;
- $canEdit = (!$user) || $user['Monitors'] == 'Edit';
- if ( !$canEdit ) {
- throw new UnauthorizedException(__('Insufficient Privileges'));
- return;
- }
+ if ( !$this->request->is('post') ) {
+ throw new BadRequestException(__('Invalid method. Should be post'));
+ return;
+ }
- $this->Zone->create();
- if ( $this->Zone->save($this->request->data) ) {
- return $this->flash(__('The zone has been saved.'), array('action' => 'index'));
+ global $user;
+ $canEdit = (!$user) || $user['Monitors'] == 'Edit';
+ if ( !$canEdit ) {
+ throw new UnauthorizedException(__('Insufficient Privileges'));
+ return;
+ }
+
+ $zone = null;
+
+ $this->Zone->create();
+ $zone = $this->Zone->save($this->request->data);
+ if ( $zone ) {
+ require_once __DIR__ .'/../../../includes/Monitor.php';
+ $monitor = new ZM\Monitor($zone['Zone']['MonitorId']);
+ $monitor->zmaControl('restart');
+ $message = 'Saved';
+ //$zone = $this->Zone->find('first', array('conditions' => array( array('Zone.' . $this->Zone->primaryKey => $this->Zone),
+ } else {
+ $message = 'Error: ';
+ // if there is a validation message, use it
+ if ( !$this->Zone->validates() ) {
+ $message = $this->Zone->validationErrors;
}
}
- $monitors = $this->Zone->Monitor->find('list');
- $this->set(compact('monitors'));
- }
+
+ $this->set(array(
+ 'message' => $message,
+ 'zone' => $zone,
+ '_serialize' => array('message','zone')
+ ));
+ } // end function add()
/**
* edit method
diff --git a/web/api/app/Model/User.php b/web/api/app/Model/User.php
index 9137ebfc5..1548aaee3 100644
--- a/web/api/app/Model/User.php
+++ b/web/api/app/Model/User.php
@@ -3,8 +3,6 @@ App::uses('AppModel', 'Model');
/**
* User Model
*
- * @property Monitor $Monitor
- * @property Frame $Frame
*/
class User extends AppModel {
@@ -23,6 +21,20 @@ class User extends AppModel {
)
);
+ function beforeFind($query) {
+ if ( empty($query['fields']) ) {
+ $schema = $this->schema();
+ unset($schema['Password']);
+
+ foreach (array_keys($schema) as $field) {
+ $query['fields'][] = $this->alias . '.' . $field;
+ }
+ return $query;
+ }
+ return parent::beforeFind($query);
+ }
+
+
/**
* Use table
*
@@ -53,14 +65,6 @@ class User extends AppModel {
* @var array
*/
public $belongsTo = array(
- /*'Monitor' => array(
- 'className' => 'Monitor',
- 'foreignKey' => 'MonitorId',
- 'conditions' => '',
- 'fields' => '',
- 'order' => ''
- )
-*/
);
/**
@@ -69,21 +73,6 @@ class User extends AppModel {
* @var array
*/
public $hasMany = array(
-/*
- 'Frame' => array(
- 'className' => 'Frame',
- 'foreignKey' => 'UserId',
- 'dependent' => true,
- 'conditions' => '',
- 'fields' => '',
- 'order' => '',
- 'limit' => '',
- 'offset' => '',
- 'exclusive' => '',
- 'finderQuery' => '',
- 'counterQuery' => ''
- )
-*/
);
}
diff --git a/web/api/app/Model/Zone.php b/web/api/app/Model/Zone.php
index 8cdc8131b..0f5e4d653 100644
--- a/web/api/app/Model/Zone.php
+++ b/web/api/app/Model/Zone.php
@@ -30,6 +30,32 @@ class Zone extends AppModel {
public $recursive = -1;
+ /**
+ * Validation rules
+ *
+ * @var array
+ */
+ public $validate = array(
+ 'MonitorId' => array(
+ 'rule' => 'checkMonitorId',
+ //array('naturalNumber'),
+ 'message' => 'Zones must have a valid MonitorId',
+ 'allowEmpty' => false,
+ 'required' => true,
+ //'last' => false, // Stop validation after this rule
+ //'on' => 'create', // Limit validation to 'create' or 'update' operations
+ ),
+ 'Name' => array(
+ 'required' => array(
+ //'on' => 'create',
+ 'rule' => 'notBlank',
+ 'message' => 'Zone Name must be specified for creation',
+ 'required' => true,
+ ),
+ )
+
+ );
+
//The Associations below have been created with all possible keys, those that are not needed can be removed
/**
@@ -41,9 +67,17 @@ class Zone extends AppModel {
'Monitor' => array(
'className' => 'Monitor',
'foreignKey' => 'MonitorId',
- 'conditions' => '',
- 'fields' => '',
- 'order' => ''
+ //'conditions' => '',
+ //'fields' => '',
+ //'order' => ''
)
);
+
+ public function checkMonitorId($data) {
+ if ( !$this->Monitor->find('first', array('conditions'=>array('Id'=>$data['MonitorId']))) ) {
+ //$this->invalidate('MonitorId', 'Invalid Monitor Id');
+ return false;
+ }
+ return true;
+ }
}
diff --git a/web/api/app/View/Zones/json/add.ctp b/web/api/app/View/Zones/json/add.ctp
new file mode 100644
index 000000000..1675fa9be
--- /dev/null
+++ b/web/api/app/View/Zones/json/add.ctp
@@ -0,0 +1,2 @@
+echo json_encode($message);
+echo json_encode($zone);
diff --git a/web/api/app/View/Zones/json/edit.ctp b/web/api/app/View/Zones/json/edit.ctp
new file mode 100644
index 000000000..1675fa9be
--- /dev/null
+++ b/web/api/app/View/Zones/json/edit.ctp
@@ -0,0 +1,2 @@
+echo json_encode($message);
+echo json_encode($zone);
diff --git a/web/api/app/View/Zones/xml/add.ctp b/web/api/app/View/Zones/xml/add.ctp
new file mode 100644
index 000000000..a8fcec73b
--- /dev/null
+++ b/web/api/app/View/Zones/xml/add.ctp
@@ -0,0 +1,2 @@
+$xml = Xml::fromArray(array('response'=>$message, 'zone'=>$zone));
+echo $xml->asXML();
diff --git a/web/api/app/View/Zones/xml/edit.ctp b/web/api/app/View/Zones/xml/edit.ctp
new file mode 100644
index 000000000..cb6f92f66
--- /dev/null
+++ b/web/api/app/View/Zones/xml/edit.ctp
@@ -0,0 +1,2 @@
+$xml = Xml::fromArray(array('response' => $message, 'zone'=>$zone));
+echo $xml->asXML();
diff --git a/web/includes/Event.php b/web/includes/Event.php
index f1ba99626..2f9fa4d20 100644
--- a/web/includes/Event.php
+++ b/web/includes/Event.php
@@ -262,13 +262,18 @@ class Event extends ZM_Object {
return $streamSrc;
} // end function getStreamSrc
+ # The new='' is to so that if we pass null, we reset the value of DiskSpace.
+ # '' is not a valid DiskSpace so that tells us that nothing was passed whereas null (unknown) is.
function DiskSpace( $new='' ) {
if ( is_null($new) or ( $new != '' ) ) {
$this->{'DiskSpace'} = $new;
}
if ( (!property_exists($this, 'DiskSpace')) or (null === $this->{'DiskSpace'}) ) {
$this->{'DiskSpace'} = folder_size($this->Path());
- dbQuery('UPDATE Events SET DiskSpace=? WHERE Id=?', array($this->{'DiskSpace'}, $this->{'Id'}));
+ if ( $this->{'EndTime'} ) {
+ # Finished events shouldn't grow in size much so we can commit it to the db.
+ dbQuery('UPDATE Events SET DiskSpace=? WHERE Id=?', array($this->{'DiskSpace'}, $this->{'Id'}));
+ }
}
return $this->{'DiskSpace'};
}
@@ -380,54 +385,54 @@ class Event extends ZM_Object {
$Event = $this;
$eventPath = $Event->Path();
- if ( $frame and ! is_array($frame) ) {
+ if ( $frame and !is_array($frame) ) {
# Must be an Id
Logger::Debug("Assuming that $frame is an Id");
- $frame = array( 'FrameId'=>$frame, 'Type'=>'', 'Delta'=>0 );
+ $frame = array('FrameId'=>$frame, 'Type'=>'', 'Delta'=>0);
}
- if ( ( ! $frame ) and file_exists($eventPath.'/snapshot.jpg') ) {
+ if ( ( !$frame ) and file_exists($eventPath.'/snapshot.jpg') ) {
# No frame specified, so look for a snapshot to use
$captImage = 'snapshot.jpg';
- Logger::Debug("Frame not specified, using snapshot");
- $frame = array('FrameId'=>'snapshot', 'Type'=>'','Delta'=>0);
+ Logger::Debug('Frame not specified, using snapshot');
+ $frame = array('FrameId'=>'snapshot', 'Type'=>'', 'Delta'=>0);
} else {
- $captImage = sprintf( '%0'.ZM_EVENT_IMAGE_DIGITS.'d-analyze.jpg', $frame['FrameId'] );
+ $captImage = sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d-analyze.jpg', $frame['FrameId']);
if ( ! file_exists( $eventPath.'/'.$captImage ) ) {
- $captImage = sprintf( '%0'.ZM_EVENT_IMAGE_DIGITS.'d-capture.jpg', $frame['FrameId'] );
- if ( ! file_exists( $eventPath.'/'.$captImage ) ) {
+ $captImage = sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d-capture.jpg', $frame['FrameId']);
+ if ( !file_exists($eventPath.'/'.$captImage) ) {
# Generate the frame JPG
if ( $Event->DefaultVideo() ) {
$videoPath = $eventPath.'/'.$Event->DefaultVideo();
- if ( ! file_exists( $videoPath ) ) {
- Error("Event claims to have a video file, but it does not seem to exist at $videoPath" );
+ if ( !file_exists($videoPath) ) {
+ Error('Event claims to have a video file, but it does not seem to exist at '.$videoPath);
return '';
}
#$command ='ffmpeg -v 0 -i '.$videoPath.' -vf "select=gte(n\\,'.$frame['FrameId'].'),setpts=PTS-STARTPTS" '.$eventPath.'/'.$captImage;
$command ='ffmpeg -ss '. $frame['Delta'] .' -i '.$videoPath.' -frames:v 1 '.$eventPath.'/'.$captImage;
- Logger::Debug( "Running $command" );
+ Logger::Debug('Running '.$command);
$output = array();
$retval = 0;
- exec( $command, $output, $retval );
+ exec($command, $output, $retval);
Logger::Debug("Retval: $retval, output: " . implode("\n", $output));
} else {
- Error("Can't create frame images from video because there is no video file for event ".$Event->Id().' at ' .$Event->Path() );
+ Error('Can\'t create frame images from video because there is no video file for event '.$Event->Id().' at ' .$Event->Path());
}
} // end if capture file exists
} // end if analyze file exists
} // end if frame or snapshot
$captPath = $eventPath.'/'.$captImage;
- if ( ! file_exists($captPath) ) {
- Error("Capture file does not exist at $captPath");
+ if ( !file_exists($captPath) ) {
+ Error('Capture file does not exist at '.$captPath);
}
$analImage = sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d-analyse.jpg', $frame['FrameId']);
$analPath = $eventPath.'/'.$analImage;
- $alarmFrame = $frame['Type']=='Alarm';
+ $alarmFrame = $frame['Type'] == 'Alarm';
$hasAnalImage = $alarmFrame && file_exists($analPath) && filesize($analPath);
$isAnalImage = $hasAnalImage && !$captureOnly;
@@ -443,8 +448,8 @@ class Event extends ZM_Object {
$fraction = sprintf('%.3f', $scale/SCALE_BASE);
$scale = (int)round($scale);
- $thumbCaptPath = preg_replace( '/\.jpg$/', "-$scale.jpg", $captPath );
- $thumbAnalPath = preg_replace( '/\.jpg$/', "-$scale.jpg", $analPath );
+ $thumbCaptPath = preg_replace('/\.jpg$/', "-$scale.jpg", $captPath);
+ $thumbAnalPath = preg_replace('/\.jpg$/', "-$scale.jpg", $analPath);
if ( $isAnalImage ) {
$imagePath = $analPath;
@@ -457,7 +462,7 @@ class Event extends ZM_Object {
$thumbFile = $thumbPath;
if ( $overwrite || ! file_exists($thumbFile) || ! filesize($thumbFile) ) {
// Get new dimensions
- list( $imageWidth, $imageHeight ) = getimagesize($imagePath);
+ list($imageWidth, $imageHeight) = getimagesize($imagePath);
$thumbWidth = $imageWidth * $fraction;
$thumbHeight = $imageHeight * $fraction;
@@ -484,7 +489,7 @@ class Event extends ZM_Object {
);
return $imageData;
- }
+ } # getImageSrc
public function link_to($text=null) {
if ( !$text )
diff --git a/web/includes/Group.php b/web/includes/Group.php
index 3a34e0af4..f5a78f875 100644
--- a/web/includes/Group.php
+++ b/web/includes/Group.php
@@ -19,9 +19,9 @@ class Group extends ZM_Object {
public function delete() {
if ( property_exists($this, 'Id') ) {
- dbQuery('DELETE FROM Groups_Monitors WHERE GroupId=?', array($this->{'Id'}));
- dbQuery('UPDATE Groups SET ParentId=NULL WHERE ParentId=?', array($this->{'Id'}));
- dbQuery('DELETE FROM Groups WHERE Id=?', array($this->{'Id'}));
+ dbQuery('DELETE FROM `Groups_Monitors` WHERE `GroupId`=?', array($this->{'Id'}));
+ dbQuery('UPDATE `Groups` SET `ParentId`=NULL WHERE `ParentId`=?', array($this->{'Id'}));
+ dbQuery('DELETE FROM `Groups` WHERE Id=?', array($this->{'Id'}));
if ( isset($_COOKIE['zmGroup']) ) {
if ( $this->{'Id'} == $_COOKIE['zmGroup'] ) {
unset($_COOKIE['zmGroup']);
@@ -47,7 +47,7 @@ class Group extends ZM_Object {
public function MonitorIds( ) {
if ( ! property_exists($this, 'MonitorIds') ) {
- $this->{'MonitorIds'} = dbFetchAll('SELECT MonitorId FROM Groups_Monitors WHERE GroupId=?', 'MonitorId', array($this->{'Id'}));
+ $this->{'MonitorIds'} = dbFetchAll('SELECT `MonitorId` FROM `Groups_Monitors` WHERE `GroupId`=?', 'MonitorId', array($this->{'Id'}));
}
return $this->{'MonitorIds'};
}
@@ -65,7 +65,7 @@ class Group extends ZM_Object {
session_write_close();
}
- return htmlSelect( 'GroupId[]', Group::get_dropdown_options(), isset($_SESSION['GroupId'])?$_SESSION['GroupId']:null, array(
+ return htmlSelect('GroupId[]', Group::get_dropdown_options(), isset($_SESSION['GroupId'])?$_SESSION['GroupId']:null, array(
'data-on-change' => 'submitThisForm',
'class'=>'chosen',
'multiple'=>'multiple',
diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php
index 066625c20..12da03c8a 100644
--- a/web/includes/Monitor.php
+++ b/web/includes/Monitor.php
@@ -201,6 +201,11 @@ class Monitor extends ZM_Object {
if ( ZM_RAND_STREAM ) {
$args['rand'] = time();
}
+ foreach ( array('scale') as $int_arg ) {
+ if ( isset($args[$int_arg]) and (!is_numeric($args[$int_arg]) or !$args[$int_arg] ) ) {
+ unset($args[$int_arg]);
+ }
+ }
$streamSrc .= '?'.http_build_query($args, '', $querySep);
@@ -293,12 +298,12 @@ class Monitor extends ZM_Object {
return;
}
}
- Logger::Debug("sending command to $url");
+ Logger::Debug('sending command to '.$url);
$context = stream_context_create();
try {
$result = file_get_contents($url, false, $context);
- if ($result === FALSE) { /* Handle error */
+ if ( $result === FALSE ) { /* Handle error */
Error("Error restarting zmc using $url");
}
} catch ( Exception $e ) {
@@ -310,14 +315,15 @@ class Monitor extends ZM_Object {
} // end function zmcControl
function zmaControl($mode=false) {
- if ( ! $this->{'Id'} ) {
+ if ( !$this->{'Id'} ) {
Warning('Attempt to control a monitor with no Id');
return;
}
if ( (!defined('ZM_SERVER_ID')) or ( property_exists($this, 'ServerId') and (ZM_SERVER_ID==$this->{'ServerId'}) ) ) {
if ( $this->{'Function'} == 'None' || $this->{'Function'} == 'Monitor' || $mode == 'stop' ) {
- if ( ZM_OPT_CONTROL ) {
+ if ( ZM_OPT_CONTROL && $this->Controllable() && $this->TrackMotion() &&
+ ( $this->{'Function'} == 'Modect' || $this->{'Function'} == 'Mocord' ) ) {
daemonControl('stop', 'zmtrack.pl', '-m '.$this->{'Id'});
}
daemonControl('stop', 'zma', '-m '.$this->{'Id'});
@@ -340,7 +346,7 @@ class Monitor extends ZM_Object {
} else if ( $this->ServerId() ) {
$Server = $this->Server();
- $url = ZM_BASE_PROTOCOL . '://'.$Server->Hostname().'/zm/api/monitors/daemonControl/'.$this->{'Id'}.'/'.$mode.'/zma.json';
+ $url = $Server->UrlToApi().'/monitors/daemonControl/'.$this->{'Id'}.'/'.$mode.'/zma.json';
if ( ZM_OPT_USE_AUTH ) {
if ( ZM_AUTH_RELAY == 'hashed' ) {
$url .= '?auth='.generateAuthHash(ZM_AUTH_HASH_IPS);
@@ -354,10 +360,10 @@ class Monitor extends ZM_Object {
}
Logger::Debug("sending command to $url");
- $context = stream_context_create();
+ $context = stream_context_create();
try {
$result = file_get_contents($url, false, $context);
- if ($result === FALSE) { /* Handle error */
+ if ( $result === FALSE ) { /* Handle error */
Error("Error restarting zma using $url");
}
} catch ( Exception $e ) {
@@ -490,12 +496,11 @@ class Monitor extends ZM_Object {
foreach ( explode(' ', $command) as $option ) {
if ( preg_match('/--([^=]+)(?:=(.+))?/', $option, $matches) ) {
$options[$matches[1]] = $matches[2]?$matches[2]:1;
- } else if ( $option != '' and $option != 'quit' ) {
+ } else if ( $option != '' and $option != 'quit' and $option != 'start' and $option != 'stop' ) {
Warning("Ignored command for zmcontrol $option in $command");
}
}
if ( !count($options) ) {
-
if ( $command == 'quit' or $command == 'start' or $command == 'stop' ) {
# These are special as we now run zmcontrol as a daemon through zmdc.
$status = daemonStatus('zmcontrol.pl', array('--id', $this->{'Id'}));
@@ -539,7 +544,7 @@ class Monitor extends ZM_Object {
} else if ( $this->ServerId() ) {
$Server = $this->Server();
- $url = ZM_BASE_PROTOCOL . '://'.$Server->Hostname().'/zm/api/monitors/daemonControl/'.$this->{'Id'}.'/'.$command.'/zmcontrol.pl.json';
+ $url = $Server->UrlToApi().'/monitors/daemonControl/'.$this->{'Id'}.'/'.$command.'/zmcontrol.pl.json';
if ( ZM_OPT_USE_AUTH ) {
if ( ZM_AUTH_RELAY == 'hashed' ) {
$url .= '?auth='.generateAuthHash(ZM_AUTH_HASH_IPS);
diff --git a/web/includes/Object.php b/web/includes/Object.php
index 09be86a9e..1fd704ec9 100644
--- a/web/includes/Object.php
+++ b/web/includes/Object.php
@@ -306,7 +306,7 @@ class ZM_Object {
$fields = array_keys($fields);
if ( $this->Id() ) {
- $sql = 'UPDATE '.$table.' SET '.implode(', ', array_map(function($field) {return '`'.$field.'`=?';}, $fields)).' WHERE Id=?';
+ $sql = 'UPDATE `'.$table.'` SET '.implode(', ', array_map(function($field) {return '`'.$field.'`=?';}, $fields)).' WHERE Id=?';
$values = array_map(function($field){ return $this->{$field};}, $fields);
$values[] = $this->{'Id'};
if ( dbQuery($sql, $values) )
@@ -314,8 +314,8 @@ class ZM_Object {
} else {
unset($fields['Id']);
- $sql = 'INSERT INTO '.$table.
- ' ('.implode(', ', array_map(function($field) {return '`'.$field.'`';}, $fields)).
+ $sql = 'INSERT INTO `'.$table.
+ '` ('.implode(', ', array_map(function($field) {return '`'.$field.'`';}, $fields)).
') VALUES ('.
implode(', ', array_map(function($field){return '?';}, $fields)).')';
@@ -331,7 +331,7 @@ class ZM_Object {
public function delete() {
$class = get_class($this);
$table = $class::$table;
- dbQuery("DELETE FROM $table WHERE Id=?", array($this->{'Id'}));
+ dbQuery("DELETE FROM `$table` WHERE Id=?", array($this->{'Id'}));
if ( isset($object_cache[$class]) and isset($object_cache[$class][$this->{'Id'}]) )
unset($object_cache[$class][$this->{'Id'}]);
}
diff --git a/web/includes/actions/filter.php b/web/includes/actions/filter.php
index ac2435302..a2e272025 100644
--- a/web/includes/actions/filter.php
+++ b/web/includes/actions/filter.php
@@ -85,8 +85,6 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) {
// We update the request id so that the newly saved filter is auto-selected
$_REQUEST['Id'] = $filter->Id();
}
- if ( $filter->Background() )
- $filter->control('start');
if ( $action == 'execute' ) {
$filter->execute();
@@ -94,6 +92,8 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) {
$filter->delete();
$view = 'events';
+ } else if ( $filter->Background() ) {
+ $filter->control('start');
}
} else if ( $action == 'control' ) {
diff --git a/web/includes/actions/user.php b/web/includes/actions/user.php
index fde1c0d0f..acbcdab7e 100644
--- a/web/includes/actions/user.php
+++ b/web/includes/actions/user.php
@@ -18,27 +18,36 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
-if ( $action == 'user' ) {
+if ( $action == 'Save' ) {
if ( canEdit('System') ) {
- if ( !empty($_REQUEST['uid']) )
+ if ( !empty($_REQUEST['uid']) ) {
$dbUser = dbFetchOne('SELECT * FROM Users WHERE Id=?', NULL, array($_REQUEST['uid']));
- else
+ } else {
$dbUser = array();
+ }
$types = array();
+ if ( isset($_REQUEST['newUser']['MonitorIds']) and is_array($_REQUEST['newUser']['MonitorIds']) )
+ $_REQUEST['newUser']['MonitorIds'] = implode(',', $_REQUEST['newUser']['MonitorIds']);
+ if ( !$_REQUEST['newUser']['Password'] )
+ unset($_REQUEST['newUser']['Password']);
+
$changes = getFormChanges($dbUser, $_REQUEST['newUser'], $types);
- if ( function_exists('password_hash') ) {
- $pass_hash = '"'.password_hash($_REQUEST['newUser']['Password'], PASSWORD_BCRYPT).'"';
- } else {
- $pass_hash = ' PASSWORD('.dbEscape($_REQUEST['newUser']['Password']).') ';
- ZM\Info('Cannot use bcrypt as you are using PHP < 5.3');
- }
-
- if ( $_REQUEST['newUser']['Password'] ) {
- $changes['Password'] = 'Password = '.$pass_hash;
- } else {
- unset($changes['Password']);
+
+ if ( isset($_REQUEST['newUser']['Password']) ) {
+ if ( function_exists('password_hash') ) {
+ $pass_hash = '"'.password_hash($_REQUEST['newUser']['Password'], PASSWORD_BCRYPT).'"';
+ } else {
+ $pass_hash = ' PASSWORD('.dbEscape($_REQUEST['newUser']['Password']).') ';
+ ZM\Info('Cannot use bcrypt as you are using PHP < 5.3');
+ }
+
+ if ( $_REQUEST['newUser']['Password'] ) {
+ $changes['Password'] = 'Password = '.$pass_hash;
+ } else {
+ unset($changes['Password']);
+ }
}
if ( count($changes) ) {
diff --git a/web/includes/auth.php b/web/includes/auth.php
index c3a34405d..e49f5876b 100644
--- a/web/includes/auth.php
+++ b/web/includes/auth.php
@@ -260,6 +260,22 @@ function userFromSession() {
return $user;
}
+function get_auth_relay() {
+ if ( ZM_OPT_USE_AUTH ) {
+ if ( ZM_AUTH_RELAY == 'hashed' ) {
+ return 'auth='.generateAuthHash(ZM_AUTH_HASH_IPS);
+ } else if ( ZM_AUTH_RELAY == 'plain' ) {
+ // password probably needs to be escaped
+ return 'username='.$_SESSION['username'].'&password='.urlencode($_SESSION['password']);
+ } else if ( ZM_AUTH_RELAY == 'none' ) {
+ return 'username='.$_SESSION['username'];
+ } else {
+ ZM\Error('Unknown value for ZM_AUTH_RELAY ' . ZM_AUTH_RELAY);
+ }
+ }
+ return '';
+} // end function get_auth_relay
+
if ( ZM_OPT_USE_AUTH ) {
if ( !empty($_REQUEST['token']) ) {
// we only need to get the username here
diff --git a/web/includes/csrf/csrf-magic.php b/web/includes/csrf/csrf-magic.php
index d96165eb9..edb04002a 100644
--- a/web/includes/csrf/csrf-magic.php
+++ b/web/includes/csrf/csrf-magic.php
@@ -389,7 +389,7 @@ function csrf_conf($key, $val) {
*/
function csrf_start() {
if ($GLOBALS['csrf']['auto-session'] && !session_id()) {
- session_start();
+ zm_session_start();
}
}
diff --git a/web/includes/database.php b/web/includes/database.php
index d0124656d..2fb2db108 100644
--- a/web/includes/database.php
+++ b/web/includes/database.php
@@ -25,20 +25,26 @@ define('DB_LOG_DEBUG', 2);
$GLOBALS['dbLogLevel'] = DB_LOG_OFF;
$GLOBALS['dbConn'] = false;
+require_once('logger.php');
function dbConnect() {
global $dbConn;
- if ( strpos(ZM_DB_HOST, ':') ) {
- // Host variable may carry a port or socket.
- list($host, $portOrSocket) = explode(':', ZM_DB_HOST, 2);
- if ( ctype_digit($portOrSocket) ) {
- $socket = ':host='.$host . ';port='.$portOrSocket;
+ $socket = '';
+ if ( ZM_DB_HOST ) {
+ if ( strpos(ZM_DB_HOST, ':') ) {
+ // Host variable may carry a port or socket.
+ list($host, $portOrSocket) = explode(':', ZM_DB_HOST, 2);
+ if ( ctype_digit($portOrSocket) ) {
+ $socket = ':host='.$host . ';port='.$portOrSocket.';';
+ } else {
+ $socket = ':unix_socket='.$portOrSocket.';';
+ }
} else {
- $socket = ':unix_socket='.$portOrSocket;
+ $socket = ':host='.ZM_DB_HOST.';';
}
} else {
- $socket = ':host='.ZM_DB_HOST;
+ $socket = ':host=localhost;';
}
try {
@@ -49,9 +55,9 @@ function dbConnect() {
PDO::MYSQL_ATTR_SSL_KEY => ZM_DB_SSL_CLIENT_KEY,
PDO::MYSQL_ATTR_SSL_CERT => ZM_DB_SSL_CLIENT_CERT,
);
- $dbConn = new PDO(ZM_DB_TYPE . $socket . ';dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS, $dbOptions);
+ $dbConn = new PDO(ZM_DB_TYPE.$socket.'dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS, $dbOptions);
} else {
- $dbConn = new PDO(ZM_DB_TYPE . $socket . ';dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS);
+ $dbConn = new PDO(ZM_DB_TYPE.$socket.'dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS);
}
$dbConn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
@@ -61,9 +67,12 @@ function dbConnect() {
error_log('Unable to connect to ZM DB ' . $ex->getMessage());
$dbConn = null;
}
-}
+ return $dbConn;
+} // end function dbConnect
-dbConnect();
+if ( !dbConnect() ) {
+ ZM\Fatal("Failed db connection to $socket");
+}
function dbDisconnect() {
global $dbConn;
diff --git a/web/includes/functions.php b/web/includes/functions.php
index c31347a6f..8081314e2 100644
--- a/web/includes/functions.php
+++ b/web/includes/functions.php
@@ -40,7 +40,7 @@ function CSPHeaders($view, $nonce) {
if ( ! $Servers )
$Servers = ZM\Server::find();
- $additionalScriptSrc = implode(' ', array_map(function($S){return $S->Url();}, $Servers));
+ $additionalScriptSrc = implode(' ', array_map(function($S){return $S->Hostname();}, $Servers));
switch ($view) {
case 'login': {
if (defined('ZM_OPT_USE_GOOG_RECAPTCHA')
@@ -840,9 +840,15 @@ function daemonStatus($daemon, $args=false) {
initDaemonStatus();
$string = $daemon;
- if ( $args )
- $string .= ' ' . $args;
- return( strpos($daemon_status, "'$string' running") !== false );
+ if ( $args ) {
+ if ( is_array($args) ) {
+ $string .= join(' ', $args);
+ZM\Warning("daemonStatus args: $string");
+ } else {
+ $string .= ' ' . $args;
+ }
+ }
+ return ( strpos($daemon_status, "'$string' running") !== false );
}
function zmcStatus($monitor) {
@@ -1484,15 +1490,15 @@ function getLoad() {
function getDiskPercent($path = ZM_DIR_EVENTS) {
$total = disk_total_space($path);
if ( $total === false ) {
- Error('disk_total_space returned false. Verify the web account user has access to ' . $path);
+ ZM\Error('disk_total_space returned false. Verify the web account user has access to ' . $path);
return 0;
} elseif ( $total == 0 ) {
- Error('disk_total_space indicates the following path has a filesystem size of zero bytes ' . $path);
+ ZM\Error('disk_total_space indicates the following path has a filesystem size of zero bytes ' . $path);
return 100;
}
$free = disk_free_space($path);
if ( $free === false ) {
- Error('disk_free_space returned false. Verify the web account user has access to ' . $path);
+ ZM\Error('disk_free_space returned false. Verify the web account user has access to ' . $path);
}
$space = round((($total - $free) / $total) * 100);
return $space;
@@ -2048,7 +2054,7 @@ function logState() {
if ( $count['Level'] <= ZM\Logger::PANIC )
$count['Level'] = ZM\Logger::FATAL;
if ( !($levelCount = $levelCounts[$count['Level']]) ) {
- Error('Unexpected Log level '.$count['Level']);
+ ZM\Error('Unexpected Log level '.$count['Level']);
next;
}
if ( $levelCount[1] && $count['LevelCount'] >= $levelCount[1] ) {
@@ -2075,18 +2081,23 @@ function isVector(&$array) {
function checkJsonError($value) {
if ( function_exists('json_last_error') ) {
- $value = var_export($value,true);
- switch( json_last_error() ) {
+ $value = var_export($value, true);
+ switch ( json_last_error() ) {
case JSON_ERROR_DEPTH :
- ZM\Fatal("Unable to decode JSON string '$value', maximum stack depth exceeded");
+ ZM\Error("Unable to decode JSON string '$value', maximum stack depth exceeded");
+ break;
case JSON_ERROR_CTRL_CHAR :
- ZM\Fatal("Unable to decode JSON string '$value', unexpected control character found");
+ ZM\Error("Unable to decode JSON string '$value', unexpected control character found");
+ break;
case JSON_ERROR_STATE_MISMATCH :
- ZM\Fatal("Unable to decode JSON string '$value', invalid or malformed JSON");
+ ZM\Error("Unable to decode JSON string '$value', invalid or malformed JSON");
+ break;
case JSON_ERROR_SYNTAX :
- ZM\Fatal("Unable to decode JSON string '$value', syntax error");
+ ZM\Error("Unable to decode JSON string '$value', syntax error");
+ break;
default :
- ZM\Fatal("Unable to decode JSON string '$value', unexpected error ".json_last_error());
+ ZM\Error("Unable to decode JSON string '$value', unexpected error ".json_last_error());
+ break;
case JSON_ERROR_NONE:
break;
}
@@ -2290,7 +2301,8 @@ function validHtmlStr($input) {
function getStreamHTML($monitor, $options = array()) {
if ( isset($options['scale']) ) {
- if ( $options['scale'] != 'auto' && $options['scale'] != '0' ) {
+ if ( $options['scale'] != 'auto' && $options['scale'] != '0' and $options['scale'] != '' ) {
+ ZM\Logger::Debug("Setting dimensions from scale:".$options['scale']);
$options['width'] = reScale($monitor->ViewWidth(), $options['scale']).'px';
$options['height'] = reScale($monitor->ViewHeight(), $options['scale']).'px';
} else {
diff --git a/web/lang/en_gb.php b/web/lang/en_gb.php
index 6b60c0099..c423a3507 100644
--- a/web/lang/en_gb.php
+++ b/web/lang/en_gb.php
@@ -87,6 +87,7 @@ $SLANG = array(
'Actual' => 'Actual',
'AddNewControl' => 'Add New Control',
'AddNewMonitor' => 'Add',
+ 'AddMonitorDisabled' => 'Your user is not allowed to add a new monitor',
'AddNewServer' => 'Add New Server',
'AddNewStorage' => 'Add New Storage',
'AddNewUser' => 'Add New User',
@@ -983,6 +984,18 @@ $OLANG = array(
"loglevel=debug" Set verbosity of FFmpeg (quiet, panic, fatal, error, warning, info, verbose, debug)
'
),
+ 'OPTIONS_ENCODER_PARAMETERS' => array(
+ 'Help' => '
+ Parameters passed to the encoding codec. name=value separated by either , or newline.~~
+ For example to changing quality, use the crf option. 1 is best, 51 is worst 23 is default.~~
+~~
+ crf=23~~
+ ~~
+ You might want to alter the movflags value to support different behaviours. Some people have troubles viewing videos due to the frag_keyframe option, but that option is supposed to allow viewing of incomplete events. See
+ [https://ffmpeg.org/ffmpeg-formats.html](https://ffmpeg.org/ffmpeg-formats.html)
+ for more information. ZoneMinder\'s default is frag_keyframe,empty_moov~~
+ ',
+ ),
'OPTIONS_DECODERHWACCELNAME' => array(
'Help' => '
This is equivalent to the ffmpeg -hwaccel command line option. With intel graphics support, use "vaapi". For NVIDIA cuda support use "cuda". To check for support, run ffmpeg -hwaccels on the command line.'
diff --git a/web/skins/classic/css/base/skin.css b/web/skins/classic/css/base/skin.css
index cc58073e1..a8b28848c 100644
--- a/web/skins/classic/css/base/skin.css
+++ b/web/skins/classic/css/base/skin.css
@@ -509,7 +509,7 @@ th.table-th-sort-rev span.table-th-sort-span {
}
#content {
- width: 96%;
+ width: 100%;
margin: 0 auto 8px auto;
line-height: 130%;
text-align: center;
diff --git a/web/skins/classic/css/base/views/monitor.css b/web/skins/classic/css/base/views/monitor.css
index c0f4a36d9..2cdc0c400 100644
--- a/web/skins/classic/css/base/views/monitor.css
+++ b/web/skins/classic/css/base/views/monitor.css
@@ -11,10 +11,30 @@
textarea,
input[name="newMonitor[Name]"],
+input[name="newMonitor[LabelFormat]"],
input[name="newMonitor[ControlDevice]"],
input[name="newMonitor[ControlAddress]"] {
width: 100%;
}
+input[name="newMonitor[AnalysisFPSLimit]"],
+input[name="newMonitor[MaxFPS]"],
+input[name="newMonitor[AlarmMaxFPS]"],
+input[name="newMonitor[V4LCapturesPerFrame]"]{
+ width: 60px;
+}
+input[name="newMonitor[Port]"],
+input[name="newMonitor[Refresh]"],
+input[name="newMonitor[LabelX]"],
+input[name="newMonitor[LabelY]"],
+input[name="newMonitor[ImageBufferCount]"],
+input[name="newMonitor[WarmupCount]"],
+input[name="newMonitor[PreEventCount]"],
+input[name="newMonitor[PostEventCount]"],
+input[name="newMonitor[StreamReplayBuffer]"],
+input[name="newMonitor[AlarmFrameCount]"],
+input[name="newMonitor[AutoStopTimeout]"],
+input[name="newMonitor[TrackDelay]"],
+input[name="newMonitor[ReturnDelay]"],
input[name="newMonitor[Width]"],
input[name="newMonitor[Height]"] {
width: 80px;
diff --git a/web/skins/classic/css/base/views/montage.css b/web/skins/classic/css/base/views/montage.css
index e9ec28bd0..aef963e79 100644
--- a/web/skins/classic/css/base/views/montage.css
+++ b/web/skins/classic/css/base/views/montage.css
@@ -3,7 +3,9 @@
}
#content {
+ /*
width: 99%;
+ */
}
#monitors:after {
diff --git a/web/skins/classic/css/base/views/zone.css b/web/skins/classic/css/base/views/zone.css
index 44cd1a115..4e9d8d479 100644
--- a/web/skins/classic/css/base/views/zone.css
+++ b/web/skins/classic/css/base/views/zone.css
@@ -4,11 +4,13 @@
}
#settingsPanel,
#zonePoints {
- width: 600px;
+ max-width: 600px;
+ width: 50%;
}
#zoneSettings {
border-collapse: collapse;
+ width: 100%;
}
#zoneSettings th,
@@ -132,5 +134,22 @@ width: 100%;
input[name="newAlarmRgbR"],
input[name="newAlarmRgbG"],
input[name="newAlarmRgbB"] {
-width: 30%;
+width: 25%;
+}
+input[name="newZone[MinPixelThreshold]"],
+input[name="newZone[MaxPixelThreshold]"],
+input[name="newZone[FilterX]"],
+input[name="newZone[FilterY]"],
+input[name="newZone[MinFilterPixels]"],
+input[name="newZone[MaxFilterPixels]"],
+input[name="newZone[MinBlobPixels]"],
+input[name="newZone[MaxBlobPixels]"],
+input[name="newZone[MinBlobs]"],
+input[name="newZone[MaxBlobs]"],
+input[name="newZone[MinAlarmPixels]"],
+input[name="newZone[MaxAlarmPixels]"] {
+ width: 90px;
+}
+input.ZonePoint {
+ width: 75px;
}
diff --git a/web/skins/classic/js/base.js b/web/skins/classic/js/base.js
index 48747b98d..86f4e2533 100644
--- a/web/skins/classic/js/base.js
+++ b/web/skins/classic/js/base.js
@@ -59,7 +59,7 @@ var popupSizes = {
'options': {'width': 1000, 'height': 660},
'preset': {'width': 300, 'height': 220},
'server': {'width': 600, 'height': 405},
- 'settings': {'width': 220, 'height': 235},
+ 'settings': {'width': 250, 'height': 335},
'shutdown': {'width': 400, 'height': 400},
'state': {'width': 400, 'height': 170},
'stats': {'width': 840, 'height': 200},
diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js
index 2012837e8..067c39391 100644
--- a/web/skins/classic/js/skin.js
+++ b/web/skins/classic/js/skin.js
@@ -236,7 +236,7 @@ window.addEventListener("DOMContentLoaded", function onSkinDCL() {
console.error("Nothing found to bind to " + fnName);
return;
}
- el.onchange = window[fnName].bind(el, el);
+ el.oninput = window[fnName].bind(el, el);
});
});
diff --git a/web/skins/classic/js/skin.js.php b/web/skins/classic/js/skin.js.php
index 5250e654f..2855b404d 100644
--- a/web/skins/classic/js/skin.js.php
+++ b/web/skins/classic/js/skin.js.php
@@ -70,23 +70,5 @@ var focusWindow = ;
var imagePrefix = "";
-var auth_hash;
-var auth_relay;
-
+var auth_hash = '';
+var auth_relay = '';
diff --git a/web/skins/classic/views/_monitor_filters.php b/web/skins/classic/views/_monitor_filters.php
index 62a91d7f3..f144c17fa 100644
--- a/web/skins/classic/views/_monitor_filters.php
+++ b/web/skins/classic/views/_monitor_filters.php
@@ -23,7 +23,7 @@ $ServersById = array();
foreach ( $servers as $S ) {
$ServersById[$S->Id()] = $S;
}
-session_start();
+zm_session_start();
foreach ( array('GroupId','Function','ServerId','StorageId','Status','MonitorId','MonitorName','Source') as $var ) {
if ( isset($_REQUEST[$var]) ) {
if ( $_REQUEST[$var] != '' ) {
diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php
index 71c60b6f0..73f79185d 100644
--- a/web/skins/classic/views/console.php
+++ b/web/skins/classic/views/console.php
@@ -178,7 +178,7 @@ getBodyTopHTML();
diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php
index f8bceb837..464c68b14 100644
--- a/web/skins/classic/views/event.php
+++ b/web/skins/classic/views/event.php
@@ -58,7 +58,7 @@ if ( isset($_REQUEST['scale']) ) {
$codec = 'auto';
if ( isset($_REQUEST['codec']) ) {
$codec = $_REQUEST['codec'];
- session_start();
+ zm_session_start();
$_SESSION['zmEventCodec'.$Event->MonitorId()] = $codec;
session_write_close();
} else if ( isset($_SESSION['zmEventCodec'.$Event->MonitorId()]) ) {
diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php
index 034e908ef..db9f11d4a 100644
--- a/web/skins/classic/views/events.php
+++ b/web/skins/classic/views/events.php
@@ -106,7 +106,7 @@ xhtmlHeaders(__FILE__, translate('Events') );
-
+
@@ -138,6 +138,7 @@ if ( $pages > 1 ) {
+
diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php
index 1f696dd70..56a355263 100644
--- a/web/skins/classic/views/filter.php
+++ b/web/skins/classic/views/filter.php
@@ -145,7 +145,7 @@ foreach ( dbFetchAll('SELECT `Id`, `Name` FROM `Servers` ORDER BY lower(`Name`)
$monitors = array();
foreach ( dbFetchAll('SELECT `Id`, `Name` FROM `Monitors` ORDER BY lower(`Name`) ASC') as $monitor ) {
if ( visibleMonitor($monitor['Id']) ) {
- $monitors[$monitor['Name']] = validHtmlStr($monitor['Name']);
+ $monitors[$monitor['Name']] = $monitor;
}
}
diff --git a/web/skins/classic/views/frame.php b/web/skins/classic/views/frame.php
index 64f1035b3..1ac65212c 100644
--- a/web/skins/classic/views/frame.php
+++ b/web/skins/classic/views/frame.php
@@ -26,16 +26,17 @@ if ( !canView('Events') ) {
require_once('includes/Frame.php');
$eid = validInt($_REQUEST['eid']);
-if ( !empty($_REQUEST['fid']) )
- $fid = validInt($_REQUEST['fid']);
+$fid = empty($_REQUEST['fid']) ? 0 : validInt($_REQUEST['fid']);
$Event = new ZM\Event($eid);
$Monitor = $Event->Monitor();
+# This is kinda weird.. so if we pass fid=0 or some other non-integer, then it loads max score
+# perhaps we should consider being explicit, like fid = maxscore
if ( !empty($fid) ) {
$sql = 'SELECT * FROM Frames WHERE EventId = ? AND FrameId = ?';
- if ( !($frame = dbFetchOne( $sql, NULL, array($eid, $fid) )) )
- $frame = array( 'EventId'=>$eid, 'FrameId'=>$fid, 'Type'=>'Normal', 'Score'=>0 );
+ if ( !($frame = dbFetchOne($sql, NULL, array($eid, $fid))) )
+ $frame = array('EventId'=>$eid, 'FrameId'=>$fid, 'Type'=>'Normal', 'Score'=>0);
} else {
$frame = dbFetchOne('SELECT * FROM Frames WHERE EventId = ? AND Score = ?', NULL, array($eid, $Event->MaxScore()));
}
@@ -61,7 +62,7 @@ if ( isset( $_REQUEST['scale'] ) ) {
}
$scale = $scale ?: 'auto';
-$imageData = $Event->getImageSrc( $frame, $scale, 0 );
+$imageData = $Event->getImageSrc($frame, $scale, 0);
if ( ! $imageData ) {
ZM\Error("No data found for Event $eid frame $fid");
$imageData = array();
diff --git a/web/skins/classic/views/js/cycle.js b/web/skins/classic/views/js/cycle.js
index f9b1d19fc..6d2c3bdd4 100644
--- a/web/skins/classic/views/js/cycle.js
+++ b/web/skins/classic/views/js/cycle.js
@@ -9,24 +9,27 @@ function cyclePause() {
$('pauseBtn').disabled = true;
$('playBtn').disabled = false;
}
+
function cycleStart() {
periodical_id = nextCycleView.periodical(cycleRefreshTimeout);
$('pauseBtn').disabled = false;
$('playBtn').disabled = true;
}
+
function cycleNext() {
monIdx ++;
if ( monIdx >= monitorData.length ) {
monIdx = 0;
}
if ( !monitorData[monIdx] ) {
- console.log("No monitorData for " + monIdx);
+ console.log('No monitorData for ' + monIdx);
}
window.location.replace('?view=cycle&mid='+monitorData[monIdx].id+'&mode='+mode, cycleRefreshTimeout);
}
+
function cyclePrev() {
- if (monIdx) {
+ if ( monIdx ) {
monIdx -= 1;
} else {
monIdx = monitorData.length - 1;
@@ -71,7 +74,7 @@ function changeSize() {
streamImg.style.width = width ? width : null;
streamImg.style.height = height ? height : null;
} else {
- console.log("Did not find liveStream"+monitorData[monIdx].id);
+ console.log('Did not find liveStream'+monitorData[monIdx].id);
}
$('scale').set('value', '');
Cookie.write('zmCycleScale', '', {duration: 10*365});
@@ -96,7 +99,7 @@ function changeScale() {
return;
}
- if ( scale != '0' ) {
+ if ( scale != '0' && scale != '' && scale != 'auto' ) {
if ( newWidth ) {
monitor_frame.css('width', newWidth+'px');
}
@@ -107,33 +110,36 @@ function changeScale() {
monitor_frame.css('width', '100%');
monitor_frame.css('height', 'auto');
}
+
/*Stream could be an applet so can't use moo tools*/
var streamImg = $j('#liveStream'+monitorData[monIdx].id)[0];
- if ( streamImg ) {
- if ( streamImg.nodeName == 'IMG' ) {
- var src = streamImg.src;
- streamImg.src = '';
-
- //src = src.replace(/rand=\d+/i,'rand='+Math.floor((Math.random() * 1000000) ));
- src = src.replace(/scale=[\.\d]+/i, 'scale='+scale);
- if ( scale != '0' ) {
- src = src.replace(/width=[\.\d]+/i, 'width='+newWidth);
- src = src.replace(/height=[\.\d]+/i, 'height='+newHeight);
- } else {
- src = src.replace(/width=[\.\d]+/i, 'width='+monitorData[monIdx].width);
- src = src.replace(/height=[\.\d]+/i, 'height='+monitorData[monIdx].height);
- }
- streamImg.src = src;
- }
- if ( scale != '0' ) {
- streamImg.style.width = newWidth+'px';
- streamImg.style.height = newHeight+'px';
- } else {
- streamImg.style.width = '100%';
- streamImg.style.height = 'auto';
- }
- } else {
+ if ( !streamImg ) {
console.log("Did not find liveStream"+monitorData[monIdx].id);
+ return;
+ }
+
+ if ( streamImg.nodeName == 'IMG' ) {
+ var src = streamImg.src;
+ streamImg.src = '';
+
+ //src = src.replace(/rand=\d+/i,'rand='+Math.floor((Math.random() * 1000000) ));
+ src = src.replace(/scale=[\.\d]+/i, 'scale='+scale);
+ if ( scale != '0' && scale != '' && scale != 'auto' ) {
+ src = src.replace(/width=[\.\d]+/i, 'width='+newWidth);
+ src = src.replace(/height=[\.\d]+/i, 'height='+newHeight);
+ } else {
+ src = src.replace(/width=[\.\d]+/i, 'width='+monitorData[monIdx].width);
+ src = src.replace(/height=[\.\d]+/i, 'height='+monitorData[monIdx].height);
+ }
+ streamImg.src = src;
+ }
+
+ if ( scale != '0' && scale != '' && scale != 'auto' ) {
+ streamImg.style.width = newWidth+'px';
+ streamImg.style.height = newHeight+'px';
+ } else {
+ streamImg.style.width = '100%';
+ streamImg.style.height = 'auto';
}
} // end function changeScale()
diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js
index 69b34d055..683f144f6 100644
--- a/web/skins/classic/views/js/event.js
+++ b/web/skins/classic/views/js/event.js
@@ -308,8 +308,7 @@ function pauseClicked() {
streamPause();
}
-function streamPause( ) {
-
+function streamPause() {
$j('#modeValue').html('Paused');
setButtonState( $('pauseBtn'), 'active' );
setButtonState( $('playBtn'), 'inactive' );
@@ -1078,6 +1077,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/filter.js b/web/skins/classic/views/js/filter.js
index 5b01d150f..a77b757ec 100644
--- a/web/skins/classic/views/js/filter.js
+++ b/web/skins/classic/views/js/filter.js
@@ -7,7 +7,7 @@ function validateForm( form ) {
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,43 @@ 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[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;
}
@@ -143,8 +177,8 @@ function deleteFilter( element ) {
}
var escape = document.createElement('textarea');
function escapeHTML(html) {
- escape.textContent = html;
- return escape.innerHTML;
+ escape.textContent = html;
+ return escape.innerHTML;
}
function parseRows(rows) {
diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js
index d0e0c348c..0ebc328bd 100644
--- a/web/skins/classic/views/js/montage.js
+++ b/web/skins/classic/views/js/montage.js
@@ -212,7 +212,8 @@ function Monitor(monitorData) {
* @param {*} element - the event data passed by onchange callback
*/
function selectLayout(element) {
- layout = $j(element).val();
+ var ddm = $j('#zmMontageLayout');
+ layout = ddm.val();
if ( layout_id = parseInt(layout) ) {
layout = layouts[layout];
@@ -231,6 +232,7 @@ function selectLayout(element) {
if ( layout.Positions['default'] ) {
styles = layout.Positions['default'];
for ( style in styles ) {
+ console.log("Applying " + style + ' ' + styles[style]);
monitor_frame.css(style, styles[style]);
}
} else {
@@ -241,7 +243,6 @@ function selectLayout(element) {
styles = layout.Positions['mId'+monitor.id];
for ( style in styles ) {
monitor_frame.css(style, styles[style]);
- console.log("Applying " + style + ' : ' + styles[style]);
}
} else {
console.log("No Monitor styles to apply");
@@ -284,8 +285,8 @@ function selectLayout(element) {
* called when the widthControl|heightControl select elements are changed
*/
function changeSize() {
- var width = $('width').get('value');
- var height = $('height').get('value');
+ var width = parseInt($('width').get('value'));
+ var height = parseInt($('height').get('value'));
for ( var i = 0, length = monitors.length; i < length; i++ ) {
var monitor = monitors[i];
@@ -296,12 +297,8 @@ function changeSize() {
console.log("Error finding frame for " + monitor.id);
continue;
}
- if ( width ) {
- monitor_frame.css('width', width);
- }
- if ( height ) {
- monitor_frame.css('height', height);
- }
+ monitor_frame.css('width', ( width ? width+'px' : 'auto'));
+ monitor_frame.css('height', ( height ? height+'px' : 'auto'));
/*Stream could be an applet so can't use moo tools*/
var streamImg = $('liveStream'+monitor.id);
@@ -314,8 +311,8 @@ function changeSize() {
src = src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) ));
streamImg.src = src;
}
- streamImg.style.width = width ? width : null;
- streamImg.style.height = height ? height : null;
+ streamImg.style.width = width ? width+'px' : null;
+ streamImg.style.height = height ? height+'px' : null;
//streamImg.style.height = '';
}
}
@@ -382,8 +379,8 @@ function changeScale() {
streamImg.src = src;
}
if ( scale != '0' ) {
- streamImg.style.width = newWidth + "px";
- streamImg.style.height = newHeight + "px";
+ streamImg.style.width = newWidth + 'px';
+ streamImg.style.height = newHeight + 'px';
} else {
streamImg.style.width = '100%';
streamImg.style.height = 'auto';
diff --git a/web/skins/classic/views/js/timeline.js b/web/skins/classic/views/js/timeline.js
index 0b4d1d5fc..8742ac67b 100644
--- a/web/skins/classic/views/js/timeline.js
+++ b/web/skins/classic/views/js/timeline.js
@@ -208,7 +208,9 @@ window.addEventListener('DOMContentLoaded', function() {
el.onmouseover = window[el.getAttribute('data-on-mouseover-this')].bind(el, el);
});
document.querySelectorAll('div.zoom').forEach(function(el) {
- el.onclick = function(ev) { window[el.getAttribute('data-on-click')](ev); };
+ el.onclick = function(ev) {
+ window[el.getAttribute('data-on-click')](ev);
+ };
});
});
diff --git a/web/skins/classic/views/js/user.js b/web/skins/classic/views/js/user.js
index 65c05c546..d491514e3 100644
--- a/web/skins/classic/views/js/user.js
+++ b/web/skins/classic/views/js/user.js
@@ -12,16 +12,22 @@ function validateForm( form, newUser ) {
} else if ( newUser ) {
errors[errors.length] = "You must supply a password";
}
- var monitorIds = new Array();
- for ( var i = 0; i < form.elements['monitorIds'].options.length; i++ ) {
- if ( form.elements['monitorIds'].options[i].selected ) {
- monitorIds[monitorIds.length] = form.elements['monitorIds'].options[i].value;
- }
- }
- form.elements['newUser[MonitorIds]'].value = monitorIds.join( ',' );
if ( errors.length ) {
- alert( errors.join( "\n" ) );
- return ( false );
+ alert(errors.join("\n"));
+ return false;
}
- return ( true );
+ return true;
}
+
+function initPage() {
+ $j('#contentForm').submit(function(event) {
+ if ( validateForm(this) ) {
+ $j('#contentButtons').hide();
+ return true;
+ } else {
+ return false;
+ };
+ });
+} // end function initPage
+
+window.addEventListener('DOMContentLoaded', initPage);
diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js
index 0056f0a08..19f74333b 100644
--- a/web/skins/classic/views/js/watch.js
+++ b/web/skins/classic/views/js/watch.js
@@ -635,7 +635,7 @@ function getEventCmdResponse( respObj, respText ) {
row.removeClass('recent');
}
row.addClass('updated');
- } // end foreach event
+ } // end foreach event
var rows = $(eventListBody).getElements('tr');
for ( var i = 0; i < rows.length; i++ ) {
@@ -651,7 +651,7 @@ function getEventCmdResponse( respObj, respText ) {
}
} else {
checkStreamForErrors('getEventCmdResponse', respObj);
- } // end if objresult == ok
+ } // end if objresult == ok
var eventCmdTimeout = eventsRefreshTimeout;
if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT ) {
diff --git a/web/skins/classic/views/js/zone.js b/web/skins/classic/views/js/zone.js
index 2ea02cfd9..9071cfb24 100644
--- a/web/skins/classic/views/js/zone.js
+++ b/web/skins/classic/views/js/zone.js
@@ -178,13 +178,23 @@ 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', 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);
}
function applyZoneUnits() {
@@ -307,8 +317,8 @@ function updateActivePoint(index) {
zone['Points'][index].x = x;
zone['Points'][index].y = y;
var Point = $('zonePoly').points.getItem(index);
- Point.x =x;
- Point.y =y;
+ Point.x = x;
+ Point.y = y;
updateArea();
}
@@ -317,17 +327,15 @@ function addPoint(index) {
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) {
@@ -349,15 +357,17 @@ function updateArea( ) {
} else if ( form.elements['newZone[Units]'].value == 'Pixels' ) {
form.elements['newZone[TempArea]'].value = area;
} else {
- alert("Unknown units: " + form.elements['newZone[Units]'].value);
+ alert('Unknown units: ' + form.elements['newZone[Units]'].value);
}
}
-function updateX(index) {
- limitPointValue($('newZone[Points]['+index+'][x]'), 0, maxX);
+function updateX(input) {
+ index = input.getAttribute('data-point-index');
+
+ limitPointValue(input, 0, maxX);
var point = $('point'+index);
- var x = $('newZone[Points]['+index+'][x]').get('value');
+ var x = input.value;
point.setStyle('left', x+'px');
zone['Points'][index].x = x;
@@ -366,11 +376,12 @@ function updateX(index) {
updateArea();
}
-function updateY(index) {
- limitPointValue($('newZone[Points]['+index+'][y]'), 0, maxY);
+function updateY(input) {
+ index = input.getAttribute('data-point-index');
+ limitPointValue(input, 0, maxY);
var point = $('point'+index);
- var y = $('newZone[Points]['+index+'][y]').get('value');
+ var y = input.value;
point.setStyle('top', y+'px');
zone['Points'][index].y = y;
@@ -384,7 +395,7 @@ function saveChanges(element) {
if ( validateForm(form) ) {
submitForm(form);
if ( form.elements['newZone[Type]'].value == 'Privacy' ) {
- alert( 'Capture process for this monitor will be restarted for the Privacy zone changes to take effect.' );
+ alert('Capture process for this monitor will be restarted for the Privacy zone changes to take effect.');
}
return true;
}
@@ -399,6 +410,7 @@ function drawZonePoints() {
for ( var i = 0; i < zone['Points'].length; i++ ) {
var div = new Element('div', {
'id': 'point'+i,
+ 'data-index': i,
'class': 'zonePoint',
'title': 'Point '+(i+1),
'styles': {
@@ -408,6 +420,7 @@ function drawZonePoints() {
});
div.addEvent('mouseover', highlightOn.pass(i));
div.addEvent('mouseout', highlightOff.pass(i));
+
div.inject($('imageFrame'));
div.makeDraggable( {
'container': $('imageFrame'),
@@ -435,9 +448,13 @@ function drawZonePoints() {
'id': 'newZone[Points]['+i+'][x]',
'name': 'newZone[Points]['+i+'][x]',
'value': zone['Points'][i].x,
- 'size': 5
+ 'type': 'number',
+ 'class': 'ZonePoint',
+ 'min': '0',
+ 'max': maxX,
+ 'data-point-index': i
});
- input.addEvent('input', updateX.pass(i));
+ input.oninput = window['updateX'].bind(input, input);
input.inject(cell);
cell.inject(row);
@@ -446,9 +463,13 @@ function drawZonePoints() {
'id': 'newZone[Points]['+i+'][y]',
'name': 'newZone[Points]['+i+'][y]',
'value': zone['Points'][i].y,
- 'size': 5
+ 'type': 'number',
+ 'class': 'ZonePoint',
+ 'min': '0',
+ 'max': maxY,
+ 'data-point-index': i
} );
- input.addEvent('input', updateY.pass(i));
+ input.oninput = window['updateY'].bind(input, input);
input.inject(cell);
cell.inject(row);
@@ -468,7 +489,7 @@ function drawZonePoints() {
cell.inject(row);
row.inject(tables[i%tables.length].getElement('tbody'));
- }
+ } // end foreach point
// Sets up the SVG polygon
updateZoneImage();
}
@@ -495,34 +516,6 @@ function setAlarmState( currentAlarmState ) {
} else {
$('stateValue').removeProperty('class');
}
-
- var isAlarmed = ( alarmState == STATE_ALARM || alarmState == STATE_ALERT );
- var wasAlarmed = ( lastAlarmState == STATE_ALARM || lastAlarmState == STATE_ALERT );
-
- var newAlarm = ( isAlarmed && !wasAlarmed );
- var oldAlarm = ( !isAlarmed && wasAlarmed );
-
- if ( newAlarm ) {
- if ( SOUND_ON_ALARM ) {
- // Enable the alarm sound
- if ( !canPlayPauseAudio ) {
- $('alarmSound').removeClass('hidden');
- } else {
- $('MediaPlayer').Play();
- }
- }
- }
- if ( SOUND_ON_ALARM ) {
- if ( oldAlarm ) {
- // Disable alarm sound
- if ( !canPlayPauseAudio ) {
- $('alarmSound').addClass('hidden');
- } else {
- $('MediaPlayer').Stop();
- }
- }
- }
- lastAlarmState = alarmState;
}
var streamCmdParms = "view=request&request=stream&connkey="+connKey;
@@ -684,7 +677,6 @@ var watchdogFunctions = {
//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 {
diff --git a/web/skins/classic/views/js/zone.js.php b/web/skins/classic/views/js/zone.js.php
index 41f384250..c03264d7a 100644
--- a/web/skins/classic/views/js/zone.js.php
+++ b/web/skins/classic/views/js/zone.js.php
@@ -1,3 +1,14 @@
+
+
var presets = new Object();
] = {
'ExtendAlarmFrames': ''
};
var zone = {
diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php
index 5ac52494e..faa06bebf 100644
--- a/web/skins/classic/views/monitor.php
+++ b/web/skins/classic/views/monitor.php
@@ -21,7 +21,7 @@
require_once('includes/Server.php');
require_once('includes/Storage.php');
-if ( !canView('Monitors') ) {
+if ( !canEdit('Monitors', empty($_REQUEST['mid'])?0:$_REQUEST['mid']) ) {
$view = 'error';
return;
}
@@ -170,14 +170,14 @@ unset($httpMethods['jpegTags']);
if ( ZM_HAS_V4L1 ) {
$v4l1DeviceFormats = array(
- 'PAL' => 0,
- 'NTSC' => 1,
- 'SECAM' => 2,
- 'AUTO' => 3,
- 'FMT4' => 4,
- 'FMT5' => 5,
- 'FMT6' => 6,
- 'FMT7' => 7
+ 0 => 'PAL',
+ 1 => 'NTSC',
+ 2 => 'SECAM',
+ 3 => 'AUTO',
+ 4 => 'FMT4',
+ 5 => 'FMT5',
+ 6 => 'FMT6',
+ 7 => 'FMT7'
);
$v4l1MaxChannels = 15;
@@ -186,48 +186,48 @@ if ( ZM_HAS_V4L1 ) {
$v4l1DeviceChannels[$i] = $i;
$v4l1LocalPalettes = array(
- translate('Grey') => 1,
- 'BGR32' => 5,
- 'BGR24' => 4,
- '*YUYV' => 8,
- '*RGB565' => 3,
- '*RGB555' => 6,
- '*YUV422' => 7,
- '*YUV422P' => 13,
- '*YUV420P' => 15
+ 1 => translate('Grey'),
+ 5 => 'BGR32',
+ 4 => 'BGR24',
+ 8 => '*YUYV',
+ 3 => '*RGB565',
+ 6 => '*RGB555',
+ 7 => '*YUV422',
+ 13 => '*YUV422P',
+ 15 => '*YUV420P',
);
}
if ( ZM_HAS_V4L2 ) {
$v4l2DeviceFormats = array(
- 'PAL' => 0x000000ff,
- 'NTSC' => 0x0000b000,
- 'PAL B' => 0x00000001,
- 'PAL B1' => 0x00000002,
- 'PAL G' => 0x00000004,
- 'PAL H' => 0x00000008,
- 'PAL I' => 0x00000010,
- 'PAL D' => 0x00000020,
- 'PAL D1' => 0x00000040,
- 'PAL K' => 0x00000080,
- 'PAL M' => 0x00000100,
- 'PAL N' => 0x00000200,
- 'PAL Nc' => 0x00000400,
- 'PAL 60' => 0x00000800,
- 'NTSC M' => 0x00001000,
- 'NTSC M JP' => 0x00002000,
- 'NTSC 443' => 0x00004000,
- 'NTSC M KR' => 0x00008000,
- 'SECAM B' => 0x00010000,
- 'SECAM D' => 0x00020000,
- 'SECAM G' => 0x00040000,
- 'SECAM H' => 0x00080000,
- 'SECAM K' => 0x00100000,
- 'SECAM K1' => 0x00200000,
- 'SECAM L' => 0x00400000,
- 'SECAM LC' => 0x00800000,
- 'ATSC 8 VSB' => 0x01000000,
- 'ATSC 16 VSB' => 0x02000000,
+ 0x000000ff => 'PAL',
+ 0x0000b000 => 'NTSC',
+ 0x00000001 => 'PAL B',
+ 0x00000002 => 'PAL B1',
+ 0x00000004 => 'PAL G',
+ 0x00000008 => 'PAL H',
+ 0x00000010 => 'PAL I',
+ 0x00000020 => 'PAL D',
+ 0x00000040 => 'PAL D1',
+ 0x00000080 => 'PAL K',
+ 0x00000100 => 'PAL M',
+ 0x00000200 => 'PAL N',
+ 0x00000400 => 'PAL Nc',
+ 0x00000800 => 'PAL 60',
+ 0x00001000 => 'NTSC M',
+ 0x00002000 => 'NTSC M JP',
+ 0x00004000 => 'NTSC 443',
+ 0x00008000 => 'NTSC M KR',
+ 0x00010000 => 'SECAM B',
+ 0x00020000 => 'SECAM D',
+ 0x00040000 => 'SECAM G',
+ 0x00080000 => 'SECAM H',
+ 0x00100000 => 'SECAM K',
+ 0x00200000 => 'SECAM K1',
+ 0x00400000 => 'SECAM L',
+ 0x00800000 => 'SECAM LC',
+ 0x01000000 => 'ATSC 8 VSB',
+ 0x02000000 => 'ATSC 16 VSB',
);
$v4l2MaxChannels = 31;
@@ -236,57 +236,58 @@ if ( ZM_HAS_V4L2 ) {
$v4l2DeviceChannels[$i] = $i;
$v4l2LocalPalettes = array(
- 'Auto' => 0, /* Automatic palette selection */
+ 0 => 'Auto', /* Automatic palette selection */
- /* Pixel format FOURCC depth Description */
- translate('Grey') => fourcc('G','R','E','Y'), /* 8 Greyscale */
- 'BGR32' => fourcc('B','G','R','4'), /* 32 BGR-8-8-8-8 */
- 'RGB32' => fourcc('R','G','B','4'), /* 32 RGB-8-8-8-8 */
- 'BGR24' => fourcc('B','G','R','3'), /* 24 BGR-8-8-8 */
- 'RGB24' => fourcc('R','G','B','3'), /* 24 RGB-8-8-8 */
- '*YUYV' => fourcc('Y','U','Y','V'), /* 16 YUV 4:2:2 */
+ /* FOURCC => Pixel format depth Description */
+ fourcc('G','R','E','Y') => translate('Grey'), /* 8 Greyscale */
+ fourcc('B','G','R','4') => 'BGR32', /* 32 BGR-8-8-8-8 */
+ fourcc('R','G','B','4') => 'RGB32', /* 32 RGB-8-8-8-8 */
+ fourcc('B','G','R','3') => 'BGR24', /* 24 BGR-8-8-8 */
+ fourcc('R','G','B','3') => 'RGB24', /* 24 RGB-8-8-8 */
+ fourcc('Y','U','Y','V') => '*YUYV', /* 16 YUV 4:2:2 */
/* compressed formats */
- '*JPEG' => fourcc('J','P','E','G'), /* JFIF JPEG */
- '*MJPEG' => fourcc('M','J','P','G'), /* Motion-JPEG */
- //'DV' => fourcc('d','v','s','d'), /* 1394 */
- //'MPEG' => fourcc('M','P','E','G'), /* MPEG-1/2/4 */
+ fourcc('J','P','E','G') => '*JPEG', /* JFIF JPEG */
+ fourcc('M','J','P','G') => '*MJPEG', /* Motion-JPEG */
+ // fourcc('d','v','s','d') => 'DV', /* 1394 */
+ // fourcc('M','P','E','G') => 'MPEG', /* MPEG-1/2/4 */
- //'RGB332' => fourcc('R','G','B','1'), /* 8 RGB-3-3-2 */
- '*RGB444' => fourcc('R','4','4','4'), /* 16 xxxxrrrr ggggbbbb */
- '*RGB555' => fourcc('R','G','B','O'), /* 16 RGB-5-5-5 */
- '*RGB565' => fourcc('R','G','B','P'), /* 16 RGB-5-6-5 */
- //'RGB555X' => fourcc('R','G','B','Q'), /* 16 RGB-5-5-5 BE */
- //'RGB565X' => fourcc('R','G','B','R'), /* 16 RGB-5-6-5 BE */
- //'Y16' => fourcc('Y','1','6',''), /* 16 Greyscale */
- //'PAL8' => fourcc('P','A','L','8'), /* 8 8-bit palette */
- //'YVU410' => fourcc('Y','V','U','9'), /* 9 YVU 4:1:0 */
- //'YVU420' => fourcc('Y','V','1','2'), /* 12 YVU 4:2:0 */
+ //
+ fourcc('R','G','B','1') => 'RGB332', /* 8 RGB-3-3-2 */
+ fourcc('R','4','4','4') => '*RGB444', /* 16 xxxxrrrr ggggbbbb */
+ fourcc('R','G','B','O') => '*RGB555', /* 16 RGB-5-5-5 */
+ fourcc('R','G','B','P') => '*RGB565', /* 16 RGB-5-6-5 */
+ // fourcc('R','G','B','Q') => 'RGB555X', /* 16 RGB-5-5-5 BE */
+ // fourcc('R','G','B','R') => 'RGB565X', /* 16 RGB-5-6-5 BE */
+ // fourcc('Y','1','6','') => 'Y16', /* 16 Greyscale */
+ // fourcc('P','A','L','8') => 'PAL8', /* 8 8-bit palette */
+ // fourcc('Y','V','U','9') => 'YVU410', /* 9 YVU 4:1:0 */
+ // fourcc('Y','V','1','2') => 'YVU420', /* 12 YVU 4:2:0 */
- '*UYVY' => fourcc('U','Y','V','Y'), /* 16 YUV 4:2:2 */
- '*YUV422P' => fourcc('4','2','2','P'), /* 16 YVU422 planar */
- '*YUV411P' => fourcc('4','1','1','P'), /* 16 YVU411 planar */
- //'Y41P' => fourcc('Y','4','1','P'), /* 12 YUV 4:1:1 */
- '*YUV444' => fourcc('Y','4','4','4'), /* 16 xxxxyyyy uuuuvvvv */
- //'YUV555' => fourcc('Y','U','V','O'), /* 16 YUV-5-5-5 */
- //'YUV565' => fourcc('Y','U','V','P'), /* 16 YUV-5-6-5 */
- //'YUV32' => fourcc('Y','U','V','4'), /* 32 YUV-8-8-8-8 */
+ fourcc('U','Y','V','Y') => '*UYVY', /* 16 YUV 4:2:2 */
+ fourcc('4','2','2','P') => '*YUV422P', /* 16 YVU422 planar */
+ fourcc('4','1','1','P') => '*YUV411P', /* 16 YVU411 planar */
+ // fourcc('Y','4','1','P') => 'Y41P', /* 12 YUV 4:1:1 */
+ fourcc('Y','4','4','4') => '*YUV444', /* 16 xxxxyyyy uuuuvvvv */
+ // fourcc('Y','U','V','O') => 'YUV555', /* 16 YUV-5-5-5 */
+ // fourcc('Y','U','V','P') => 'YUV565', /* 16 YUV-5-6-5 */
+ // fourcc('Y','U','V','4') => 'YUV32', /* 32 YUV-8-8-8-8 */
/* two planes -- one Y, one Cr + Cb interleaved */
- //'NV12' => fourcc('N','V','1','2'), /* 12 Y/CbCr 4:2:0 */
- //'NV21' => fourcc('N','V','2','1'), /* 12 Y/CrCb 4:2:0 */
+ fourcc('N','V','1','2') => 'NV12', /* 12 Y/CbCr 4:2:0 */
+ // fourcc('N','V','2','1') => 'NV21', /* 12 Y/CrCb 4:2:0 */
/* The following formats are not defined in the V4L2 specification */
- '*YUV410' => fourcc('Y','U','V','9'), /* 9 YUV 4:1:0 */
- '*YUV420' => fourcc('Y','U','1','2'), /* 12 YUV 4:2:0 */
- //'YYUV' => fourcc('Y','Y','U','V'), /* 16 YUV 4:2:2 */
- //'HI240' => fourcc('H','I','2','4'), /* 8 8-bit color */
- //'HM12' => fourcc('H','M','1','2'), /* 8 YUV 4:2:0 16x16 macroblocks */
+ fourcc('Y','U','V','9') => '*YUV410', /* 9 YUV 4:1:0 */
+ fourcc('Y','U','1','2') => '*YUV420', /* 12 YUV 4:2:0 */
+ // fourcc('Y','Y','U','V') => 'YYUV', /* 16 YUV 4:2:2 */
+ // fourcc('H','I','2','4') => 'HI240', /* 8 8-bit color */
+ // fourcc('H','M','1','2') => 'HM12', /* 8 YUV 4:2:0 16x16 macroblocks */
/* see http://www.siliconimaging.com/RGB%20Bayer.htm */
- //'SBGGR8' => fourcc('B','A','8','1'), /* 8 BGBG.. GRGR.. */
- //'SGBRG8' => fourcc('G','B','R','G'), /* 8 GBGB.. RGRG.. */
- //'SBGGR16' => fourcc('B','Y','R','2'), /* 16 BGBG.. GRGR.. */
+ // fourcc('B','A','8','1') => 'SBGGR8', /* 8 BGBG.. GRGR.. */
+ // fourcc('G','B','R','G') => 'SGBRG8', /* 8 GBGB.. RGRG.. */
+ // fourcc('B','Y','R','2') => 'SBGGR16', /* 16 BGBG.. GRGR.. */
/* Vendor-specific formats */
//'WNVA' => fourcc('W','N','V','A'), /* Winnov hw compress */
@@ -320,50 +321,50 @@ $orientations = array(
);
$deinterlaceopts = array(
- 'Disabled' => 0x00000000,
- 'Four field motion adaptive - Soft' => 0x00001E04, /* 30 change */
- 'Four field motion adaptive - Medium' => 0x00001404, /* 20 change */
- 'Four field motion adaptive - Hard' => 0x00000A04, /* 10 change */
- 'Discard' => 0x00000001,
- 'Linear' => 0x00000002,
- 'Blend' => 0x00000003,
- 'Blend (25%)' => 0x00000205
- );
+ 0x00000000 => 'Disabled',
+ 0x00001E04 => 'Four field motion adaptive - Soft', /* 30 change */
+ 0x00001404 => 'Four field motion adaptive - Medium', /* 20 change */
+ 0x00000A04 => 'Four field motion adaptive - Hard', /* 10 change */
+ 0x00000001 => 'Discard',
+ 0x00000002 => 'Linear',
+ 0x00000003 => 'Blend',
+ 0x00000205 => 'Blend (25%)',
+);
$deinterlaceopts_v4l2 = array(
- 'Disabled' => 0x00000000,
- 'Four field motion adaptive - Soft' => 0x00001E04, /* 30 change */
- 'Four field motion adaptive - Medium' => 0x00001404, /* 20 change */
- 'Four field motion adaptive - Hard' => 0x00000A04, /* 10 change */
- 'Discard' => 0x00000001,
- 'Linear' => 0x00000002,
- 'Blend' => 0x00000003,
- 'Blend (25%)' => 0x00000205,
- 'V4L2: Capture top field only' => 0x02000000,
- 'V4L2: Capture bottom field only' => 0x03000000,
- 'V4L2: Alternate fields (Bob)' => 0x07000000,
- 'V4L2: Progressive' => 0x01000000,
- 'V4L2: Interlaced' => 0x04000000
- );
+ 0x00000000 => 'Disabled',
+ 0x00001E04 => 'Four field motion adaptive - Soft', /* 30 change */
+ 0x00001404 => 'Four field motion adaptive - Medium', /* 20 change */
+ 0x00000A04 => 'Four field motion adaptive - Hard', /* 10 change */
+ 0x00000001 => 'Discard',
+ 0x00000002 => 'Linear',
+ 0x00000003 => 'Blend',
+ 0x00000205 => 'Blend (25%)',
+ 0x02000000 => 'V4L2: Capture top field only',
+ 0x03000000 => 'V4L2: Capture bottom field only',
+ 0x07000000 => 'V4L2: Alternate fields (Bob)',
+ 0x01000000 => 'V4L2: Progressive',
+ 0x04000000 => 'V4L2: Interlaced',
+);
$fastblendopts = array(
- 'No blending' => 0,
- '1.5625%' => 1,
- '3.125%' => 3,
- '6.25% (Indoor)' => 6,
- '12.5% (Outdoor)' => 12,
- '25%' => 25,
- '50%' => 50
+ 0 => 'No blending',
+ 1 => '1.5625%',
+ 3 => '3.125%',
+ 6 => '6.25% (Indoor)',
+ 12 => '12.5% (Outdoor)',
+ 25 => '25%',
+ 50 => '50%',
);
$fastblendopts_alarm = array(
- 'No blending (Alarm lasts forever)' => 0,
- '1.5625%' => 1,
- '3.125%' => 3,
- '6.25%' => 6,
- '12.5%' => 12,
- '25%' => 25,
- '50% (Alarm lasts a moment)' => 50
+ 0 => 'No blending (Alarm lasts forever)',
+ 1 => '1.5625%',
+ 3 => '3.125%',
+ 6 => '6.25%',
+ 12 => '12.5%',
+ 25 => '25%',
+ 50 => '50% (Alarm lasts a moment)',
);
$label_size = array(
@@ -671,45 +672,50 @@ switch ( $tab ) {
echo htmlOptions(ZM\Group::get_dropdown_options(), $monitor->GroupIds());
?>
- | |
+
+ |
+ |
+
Type() != 'Local' && $monitor->Type() != 'File' && $monitor->Type() != 'NVSocket' ) {
?>
() |
-
+
CAUTION: See the help text
|
() |
-
+
CAUTION: See the help text
|
- | |
- | |
+
+ |
+ |
+
+
+ |
+ |
+
|
- |
+ RefBlendPerc()); ?> |
|
-
- |
+ AlarmRefBlendPerc()); ?> |
+
@@ -729,8 +735,8 @@ switch ( $tab ) {
continue;
if ( $optCount && ($optCount%$breakCount == 0) )
echo '';
- echo 'Triggers()) && in_array($optTrigger, $monitor->Triggers()) ) ? ' checked="checked"' : ''). '/> '. $optTrigger;
+ echo 'Triggers()) && in_array($optTrigger, $monitor->Triggers()) ) ? ' checked="checked"' : ''). '/> '. $optTrigger;
$optCount ++;
} # end foreach trigger option
if ( !$optCount ) {
@@ -746,23 +752,41 @@ switch ( $tab ) {
{
if ( ZM_HAS_V4L && $monitor->Type() == 'Local' ) {
?>
- | |
- | Method(), "submitTab( '$tab' );" ); ?> |
+ | |
+
+ |
+ Method(), array('onchange'=>'submitTab', 'data-tab-name'=>$tab) ); ?> |
+
Method() == 'v4l1' ) {
?>
|
- |
+ Channel()); ?> |
+
+
+ |
+ Format()); ?> |
+
+
+ |
+ Palette()); ?> |
- | |
- | |
- | |
- | |
- | |
+
+ |
+ Channel()); ?> |
+
+
+ |
+ Format()); ?> |
+
+
+ |
+ Palette()); ?> |
+
@@ -774,35 +798,39 @@ switch ( $tab ) {
V4LMultiBuffer() == '' ? 'checked="checked"' : '' ) ?>/>
- | |
+
+ |
+ |
+
Type() == 'NVSocket' ) {
include('_monitor_source_nvsocket.php');
} else if ( $monitor->Type() == 'Remote' ) {
?>
- | Protocol(), "updateMethods( this );if(this.value=='rtsp'){\$('RTSPDescribe').setStyle('display','table-row');}else{\$('RTSPDescribe').hide();}" ); ?> |
-
+
+ |
+ Protocol(), "updateMethods( this );if(this.value=='rtsp'){\$('RTSPDescribe').setStyle('display','table-row');}else{\$('RTSPDescribe').hide();}" ); ?> |
+
|
-Protocol() || $monitor->Protocol() == 'http' ) {
- echo htmlSelect('newMonitor[Method]', $httpMethods, $monitor->Method() );
+ echo htmlSelect('newMonitor[Method]', $httpMethods, $monitor->Method());
} else {
- echo htmlSelect('newMonitor[Method]', $rtspMethods, $monitor->Method() );
+ echo htmlSelect('newMonitor[Method]', $rtspMethods, $monitor->Method());
}
?>
|
| |
- | |
+ | |
| |
Type() == 'File' ) {
?>
- | |
+ | |
Type() == 'cURL' ) {
?>
@@ -818,15 +846,15 @@ include('_monitor_source_nvsocket.php');
() |
- |
+ |
() |
- |
+ |
|
- |
+ |
Type() == 'Ffmpeg' || $monitor->Type() == 'Libvlc' ) {
@@ -873,8 +901,8 @@ include('_monitor_source_nvsocket.php');
() |
-
-
+
+
translate('Custom'),
'176x120'=>'176x120 QCIF',
@@ -978,8 +1006,11 @@ include('_monitor_source_nvsocket.php');
?>
|
- |
- |
+ () |
+
+
+ |
+
|
Type() == 'Ffmpeg' ) { ?>
RecordAudio() ) { ?> checked="checked"/>
@@ -1000,11 +1031,11 @@ include('_monitor_source_nvsocket.php');
|
|
- |
+ |
|
- |
+ |
|
@@ -1018,27 +1049,27 @@ include('_monitor_source_nvsocket.php');
?>
|
- |
+ |
|
- |
+ |
|
- |
+ |
|
- |
+ |
|
- |
+ |
|
- |
+ |
|
- ControlId());
+ | ControlId());
if ( canEdit('Control') ) {
echo ' '.makePopupLink('?view=controlcaps', 'zmControlCaps', 'controlcaps', translate('Edit'));
}
@@ -1068,7 +1099,7 @@ if ( canEdit('Control') ) {
|
|
- |
+ |
|
@@ -1076,11 +1107,11 @@ if ( canEdit('Control') ) {
|
- |
+ |
|
- translate('None'),
'0' => translate('Home'),
@@ -1090,7 +1121,7 @@ echo htmlSelect('newMonitor[ReturnLocation]', $return_options, $monitor->ReturnL
|
|
- |
+ |
ReturnL
|
-
+
|
|
-
+
|
|
-
+
|
|
-
+
|
|
-
+
|
|
-
+
|
@@ -1167,7 +1198,7 @@ echo htmlSelect('newMonitor[ReturnLocation]', $return_options, $monitor->ReturnL
|
-
+
|
@@ -1182,7 +1213,7 @@ echo htmlSelect('newMonitor[ReturnLocation]', $return_options, $monitor->ReturnL
- sync
+ sync
|
diff --git a/web/skins/classic/views/monitorprobe.php b/web/skins/classic/views/monitorprobe.php
index 9cab32b3e..a76c67810 100644
--- a/web/skins/classic/views/monitorprobe.php
+++ b/web/skins/classic/views/monitorprobe.php
@@ -39,16 +39,18 @@ function probeV4L() {
}
$monitors = array();
- foreach ( dbFetchAll("SELECT Id, Name, Device,Channel FROM Monitors WHERE Type = 'Local' ORDER BY Device, Channel" ) as $monitor )
+ foreach ( dbFetchAll("SELECT Id, Name, Device, Channel FROM Monitors WHERE Type = 'Local' ORDER BY Device, Channel" ) as $monitor )
$monitors[$monitor['Device'].':'.$monitor['Channel']] = $monitor;
$devices = array();
$preferredStandards = array('PAL', 'NTSC');
$preferredFormats = array('BGR3', 'RGB3', 'YUYV', 'UYVY', 'JPEG', 'MJPG', '422P', 'YU12', 'GREY');
foreach ( $output as $line ) {
- if ( !preg_match('/^d:([^|]+).*S:([^|]*).*F:([^|]+).*I:(\d+)\|(.+)$/', $line, $deviceMatches) )
- ZM\Fatal("Can't parse command output '$line'");
- $standards = explode('/',$deviceMatches[2]);
+ if ( !preg_match('/^d:([^|]+).*S:([^|]*).*F:([^|]+).*I:(\d+)\|(.+)$/', $line, $deviceMatches) ) {
+ ZM\Error("Can't parse command output '$line'");
+ continue;
+ }
+ $standards = explode('/', $deviceMatches[2]);
$preferredStandard = false;
foreach ( $preferredStandards as $standard ) {
if ( in_array( $standard, $standards ) ) {
@@ -56,7 +58,7 @@ function probeV4L() {
break;
}
}
- $formats = explode('/',$deviceMatches[3]);
+ $formats = explode('/', $deviceMatches[3]);
$preferredFormat = false;
foreach ( $preferredFormats as $format ) {
if ( in_array($format, $formats) ) {
@@ -73,8 +75,10 @@ function probeV4L() {
);
$inputs = array();
for ( $i = 0; $i < $deviceMatches[4]; $i++ ) {
- if ( !preg_match('/i'.$i.':([^|]+)\|i'.$i.'T:([^|]+)\|/', $deviceMatches[5], $inputMatches) )
- ZM\Fatal("Can't parse input '".$deviceMatches[5]."'");
+ if ( !preg_match('/i'.$i.':([^|]+)\|i'.$i.'T:([^|]+)\|/', $deviceMatches[5], $inputMatches) ) {
+ ZM\Error("Can't parse input '".$deviceMatches[5]."'");
+ continue;
+ }
if ( $inputMatches[2] == 'Camera' ) {
$input = array(
'index' => $i,
@@ -101,7 +105,7 @@ function probeV4L() {
$inputMonitor['Colours'] = 1;
$inputMonitor['SignalCheckColour'] = '#000023';
}
- $inputDesc = base64_encode(serialize($inputMonitor));
+ $inputDesc = base64_encode(json_encode($inputMonitor));
$inputString = $deviceMatches[1].', chan '.$i.($input['free']?(' - '.translate('Available')):(' ('.$monitors[$input['id']]['Name'].')'));
$inputs[] = $input;
$cameras[$inputDesc] = $inputString;
@@ -288,7 +292,7 @@ function probeNetwork() {
if ( isset($macBases[$macRoot]) ) {
$macBase = $macBases[$macRoot];
$camera = call_user_func($macBase['probeFunc'], $ip);
- $sourceDesc = base64_encode(serialize($camera['monitor']));
+ $sourceDesc = base64_encode(json_encode($camera['monitor']));
$sourceString = $camera['model'].' @ '.$host;
if ( isset($monitors[$ip]) ) {
$monitor = $monitors[$ip];
@@ -330,7 +334,7 @@ xhtmlHeaders(__FILE__, translate('MonitorProbe') );
-
+ 'configureButtons(this)')); ?>
diff --git a/web/skins/classic/views/montage.php b/web/skins/classic/views/montage.php
index e04ce8f68..7a591bfeb 100644
--- a/web/skins/classic/views/montage.php
+++ b/web/skins/classic/views/montage.php
@@ -33,20 +33,20 @@ if ( isset($_REQUEST['showZones']) ) {
}
}
$widths = array(
- 'auto' => 'auto',
- '160px' => '160px',
- '320px' => '320px',
- '352px' => '352px',
- '640px' => '640px',
- '1280px' => '1280px' );
+ '0' => 'auto',
+ '160' => '160px',
+ '320' => '320px',
+ '352' => '352px',
+ '640' => '640px',
+ '1280' => '1280px' );
$heights = array(
- 'auto' => 'auto',
- '240px' => '240px',
- '320px' => '320px',
- '480px' => '480px',
- '720px' => '720px',
- '1080px' => '1080px',
+ '0' => 'auto',
+ '240' => '240px',
+ '320' => '320px',
+ '480' => '480px',
+ '720' => '720px',
+ '1080' => '1080px',
);
$scale = '100'; # actual
@@ -54,7 +54,7 @@ $scale = '100'; # actual
if ( isset($_REQUEST['scale']) ) {
$scale = validInt($_REQUEST['scale']);
} else if ( isset($_COOKIE['zmMontageScale']) ) {
- $scale = $_COOKIE['zmMontageScale'];
+ $scale = validInt($_COOKIE['zmMontageScale']);
}
$layouts = ZM\MontageLayout::find(NULL, array('order'=>"lower('Name')"));
@@ -75,10 +75,8 @@ zm_session_start();
$layout_id = '';
if ( isset($_COOKIE['zmMontageLayout']) ) {
$layout_id = $_SESSION['zmMontageLayout'] = $_COOKIE['zmMontageLayout'];
- ZM\Logger::Debug("Using layout $layout_id");
} elseif ( isset($_SESSION['zmMontageLayout']) ) {
$layout_id = $_SESSION['zmMontageLayout'];
- ZM\Logger::Debug("Using layout $layout_id from session");
}
$options = array();
@@ -88,25 +86,26 @@ if ( $layout_id and is_numeric($layout_id) and isset($layoutsById[$layout_id]) )
$Layout = $layoutsById[$layout_id];
$Positions = json_decode($Layout->Positions(), true);
} else {
- ZM\Logger::Debug("Layout not found");
+ ZM\Logger::Debug('Layout not found');
}
if ( $Layout and ( $Layout->Name() != 'Freeform' ) ) {
// Use layout instead of other options
}
-if ( isset($_COOKIE['zmMontageWidth']) and $_COOKIE['zmMontageWidth'] ) {
- $_SESSION['zmMontageWidth'] = $options['width'] = $_COOKIE['zmMontageWidth'];
+if ( isset($_COOKIE['zmMontageWidth']) ) {
+ $_SESSION['zmMontageWidth'] = $options['width'] = validInt($_COOKIE['zmMontageWidth']);
#} elseif ( isset($_SESSION['zmMontageWidth']) and $_SESSION['zmMontageWidth'] ) {
#$options['width'] = $_SESSION['zmMontageWidth'];
} else
- $options['width'] = '';
+ $options['width'] = 0;
-if ( isset($_COOKIE['zmMontageHeight']) and $_COOKIE['zmMontageHeight'] )
- $_SESSION['zmMontageHeight'] = $options['height'] = $_COOKIE['zmMontageHeight'];
+if ( isset($_COOKIE['zmMontageHeight']) ) {
+ $_SESSION['zmMontageHeight'] = $options['height'] = validInt($_COOKIE['zmMontageHeight']);
#else if ( isset($_SESSION['zmMontageHeight']) and $_SESSION['zmMontageHeight'] )
#$options['height'] = $_SESSION['zmMontageHeight'];
-else
- $options['height'] = '';
+} else {
+ $options['height'] = 0;
+}
#if ( $scale )
$options['scale'] = $scale;
@@ -130,10 +129,10 @@ foreach( $displayMonitors as &$row ) {
$showControl = true;
$row['connKey'] = generateConnKey();
if ( ! isset($widths[$row['Width']]) ) {
- $widths[$row['Width'].'px'] = $row['Width'].'px';
+ $widths[$row['Width']] = $row['Width'].'px';
}
if ( ! isset($heights[$row['Height']]) ) {
- $heights[$row['Height'].'px'] = $row['Height'].'px';
+ $heights[$row['Height']] = $row['Height'].'px';
}
$monitors[] = new ZM\Monitor($row);
} # end foreach Monitor
@@ -185,7 +184,7 @@ if ( $showZones ) {
- 'selectLayout')); ?>
+ 'selectLayout')); ?>
@@ -202,23 +201,28 @@ if ( $showZones ) {
connKey(); // Minor hack
?>
+ data-width="ViewWidth(), $monitor->PopupScale()); ?>"
+ data-height="ViewHeight(), $monitor->PopupScale()); ?>"
+ >
connKey();
+
+ ZM\Logger::Debug("Options: " . print_r($monitor_options,true));
if (0 and $Positions ) {
$monitor_options['width'] = '100%';
$monitor_options['height'] = '100%';
@@ -237,8 +241,8 @@ foreach ( $monitors as $monitor ) {
echo getWebSiteUrl(
'liveStream'.$monitor->Id(),
$monitor->Path(),
- (isset($options['width']) ? $options['width'] : reScale($monitor->Width(), $scale).'px' ),
- ( isset($options['height']) ? $options['height'] : reScale($monitor->Height(), $scale).'px' ),
+ (isset($options['width']) ? $options['width'].'px' : reScale($monitor->ViewWidth(), $scale).'px' ),
+ ( isset($options['height']) ? $options['height'].'px' : reScale($monitor->ViewHeight(), $scale).'px' ),
$monitor->Name()
);
} else {
@@ -251,17 +255,17 @@ foreach ( $monitors as $monitor ) {
$width = $options['width'];
if ( !$options['height'] ) {
$scale = (int)( 100 * $options['width'] / $monitor->Width() );
- $height = reScale($monitor->Height(), $scale).'px';
+ $height = reScale($monitor->Height(), $scale);
}
} else if ( $options['height'] ) {
$height = $options['height'];
if ( !$options['width'] ) {
$scale = (int)( 100 * $options['height'] / $monitor->Height() );
- $width = reScale($monitor->Width(), $scale).'px';
+ $width = reScale($monitor->Width(), $scale);
}
} else if ( $scale ) {
- $width = reScale($monitor->Width(), $scale).'px';
- $height = reScale($monitor->Height(), $scale).'px';
+ $width = reScale($monitor->Width(), $scale);
+ $height = reScale($monitor->Height(), $scale);
}
$zones = array();
@@ -272,8 +276,8 @@ foreach ( $monitors as $monitor ) {
limitPoints($row['Points'], 0, 0, $monitor->Width(), $monitor->Height());
} else {
limitPoints($row['Points'], 0, 0,
- ( $width ? $width-1 : $monitor->Width()-1 ),
- ( $height ? $height-1 : $monitor->Height()-1 )
+ ( $width ? $width-1 : $monitor->ViewWidth()-1 ),
+ ( $height ? $height-1 : $monitor->ViewHeight()-1 )
);
}
$row['Coords'] = pointsToCoords($row['Points']);
@@ -282,7 +286,7 @@ foreach ( $monitors as $monitor ) {
} // end foreach Zone
?>
-