Merge branch 'release-1.34' of github.com:ZoneMinder/zoneminder into release-1.34

This commit is contained in:
Isaac Connor 2020-09-16 15:30:05 -04:00
commit 17369e73e2
133 changed files with 2600 additions and 1247 deletions

4
.github/stale.yml vendored
View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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@"

View File

@ -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',

2
db/zm_update-1.34.20.sql Normal file
View File

@ -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);

10
distros/beowulf/NEWS Normal file
View File

@ -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 <onlyjob@debian.org> Tue, 31 Mar 2015 15:12:17 +1100

View File

@ -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 <vagrant@debian.org> Sun, 27 Mar 2011 13:06:56 -0700

View File

@ -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?).

View File

@ -0,0 +1,3 @@
zoneminder (1.31.39~20180223.27-stretch-1) unstable; urgency=low
*
-- Isaac Connor <iconnor@connortechnology.com> Fri, 23 Feb 2018 14:15:59 -0500

3
distros/beowulf/clean Normal file
View File

@ -0,0 +1,3 @@
.gitattributes
web/api/.gitattributes
web/api/.gitignore

1
distros/beowulf/compat Normal file
View File

@ -0,0 +1 @@
9

View File

@ -0,0 +1,57 @@
# Remember to enable cgi mod (i.e. "a2enmod cgi").
ScriptAlias /zm/cgi-bin "/usr/lib/zoneminder/cgi-bin"
<Directory "/usr/lib/zoneminder/cgi-bin">
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
AllowOverride All
Require all granted
</Directory>
# Order matters. This alias must come first.
Alias /zm/cache /var/cache/zoneminder/cache
<Directory /var/cache/zoneminder/cache>
Options -Indexes +FollowSymLinks
AllowOverride None
<IfModule mod_authz_core.c>
# Apache 2.4
Require all granted
</IfModule>
<IfModule !mod_authz_core.c>
# Apache 2.2
Order deny,allow
Allow from all
</IfModule>
</Directory>
Alias /zm /usr/share/zoneminder/www
<Directory /usr/share/zoneminder/www>
Options -Indexes +FollowSymLinks
<IfModule mod_dir.c>
DirectoryIndex index.php
</IfModule>
</Directory>
# For better visibility, the following directives have been migrated from the
# default .htaccess files included with the CakePHP project.
# Parameters not set here are inherited from the parent directive above.
<Directory "/usr/share/zoneminder/www/api">
RewriteEngine on
RewriteRule ^$ app/webroot/ [L]
RewriteRule (.*) app/webroot/$1 [L]
RewriteBase /zm/api
</Directory>
<Directory "/usr/share/zoneminder/www/api/app">
RewriteEngine on
RewriteRule ^$ webroot/ [L]
RewriteRule (.*) webroot/$1 [L]
RewriteBase /zm/api
</Directory>
<Directory "/usr/share/zoneminder/www/api/app/webroot">
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
RewriteBase /zm/api
</Directory>

166
distros/beowulf/control Normal file
View File

@ -0,0 +1,166 @@
Source: zoneminder
Section: net
Priority: optional
Maintainer: Isaac Connor <isaac@zoneminder.com>
Uploaders: Isaac Connor <isaac@zoneminder.com>
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

174
distros/beowulf/copyright Normal file
View File

@ -0,0 +1,174 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: ZoneMinder
Upstream-Contact: Philip Coombes <philip.coombes@zoneminder.com>
Source: https://github.com/ZoneMinder/ZoneMinder
Comment:
This package was originally debianized by matrix <matrix@cecilia>
on Mon, 7 Mar 2005 02:07:57 -0500.
It was re-done for submission to the Debian project by Peter Howard
<pjh@northern-ridge.com.au> 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 <philip.coombes@zoneminder.com>
2008 Brian Rudy <brudyNO@SPAMpraecogito.com>
2014 Vincent Giovannone
2013 Tim Craig <timcraigNO@SPAMsonic.net>
2003-2008 Corey DeLasaux
2001-2010 Chris Kistner
License: GPL-2+
Files: distros/*
Copyright: 2001-2008 Philip Coombes <philip.coombes@zoneminder.com>
2014 Isaac Connor <iconnor@connortechnology.com>
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) <metal@alucinados.com>
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 <asn@cryptomilk.org>
2009 Dario Freddi <drf@kde.org>
2008 Laurent Montel, <montel@kde.org>
2011 Nikita Krupen'ko <krnekit@gmail.com>
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 <onlyjob@debian.org>
2007-2014 Peter Howard <pjh@northern-ridge.com.au>
2010-2012 Vagrant Cascadian <vagrant@debian.org>
2001-2008 Philip Coombes <philip.coombes@zoneminder.com>
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".

View File

@ -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;
}
}

7
distros/beowulf/gbp.conf Normal file
View File

@ -0,0 +1,7 @@
[dch]
id-length = 0
[import-orig]
pristine-tar = False
merge = False

View File

@ -0,0 +1,2 @@
usr/share/man/man3
usr/share/perl5

View File

87
distros/beowulf/rules Executable file
View File

@ -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

View File

@ -0,0 +1 @@
3.0 (quilt)

View File

@ -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

View File

@ -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/*

View File

@ -0,0 +1 @@
docs/_build/html usr/share/doc/zoneminder-doc/

View File

@ -0,0 +1,2 @@
## Convenience symlink:
/usr/share/doc/zoneminder-doc/html /usr/share/doc/zoneminder/html

View File

@ -0,0 +1 @@
conf debian/conf/apache2/zoneminder.conf nginx

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
README.md

View File

@ -0,0 +1,2 @@
debian/examples/*
dbuild/misc/apache.conf

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
/var/tmp /usr/share/zoneminder/www/api/app/tmp

View File

@ -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

View File

@ -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/*

View File

@ -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
}

View File

@ -0,0 +1 @@
rm_conffile /etc/zm/apache.conf 1.28.1-5~

View File

@ -0,0 +1 @@
docs/_build/man/*.1

View File

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

View File

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

View File

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

View File

@ -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

View File

@ -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

View File

@ -1,3 +1,3 @@
zoneminder (1.31.39~20180223.27-stretch-1) unstable; urgency=low
zoneminder (1.35.6~20200825.27-xenial) xenial; urgency=low
*
-- Isaac Connor <iconnor@connortechnology.com> Fri, 23 Feb 2018 14:15:59 -0500
-- Isaac Connor <isaac@zoneminder.com> Tue, 25 Aug 2020 09:28:18 -0400

View File

@ -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})

View File

@ -69,7 +69,7 @@ sub sendCmd {
my $result = undef;
printMsg($cmd, 'Tx');
$self->printMsg($cmd, 'Tx');
my $req = HTTP::Request->new(POST=>"http://$self->{Monitor}->{ControlAddress}/$cgi.cgi");
$req->content($cmd);

View File

@ -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

View File

@ -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},

View File

@ -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
@ -191,8 +191,8 @@ if ( !$server_up ) {
my $attempts = 0;
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,7 +255,7 @@ 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;
@ -308,6 +308,7 @@ sub run {
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;

View File

@ -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)

View File

@ -119,7 +119,6 @@ if ( !$monitor->{CanMoveMap} ) {
}
}
Debug("Found monitor for id '$monitor'");
exit(-1) if !zmMemVerify($monitor);
sub Suspend {

View File

@ -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;
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() );
($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 ) {

View File

@ -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;
}

View File

@ -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; }

View File

@ -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

View File

@ -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);
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;
}

View File

@ -40,6 +40,7 @@ extern "C" {
#include <libavutil/mathematics.h>
#include <libavutil/avstring.h>
#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)

View File

@ -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,

View File

@ -46,6 +46,8 @@ class FfmpegCamera : public Camera {
int frameCount;
int alignment; /* ffmpeg wants line sizes to be 32bit aligned. Especially 4.3+ */
#if HAVE_LIBAVFORMAT
AVFormatContext *mFormatContext;
int mVideoStreamId;

View File

@ -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 ) {

View File

@ -108,6 +108,7 @@ Image::Image() {
if ( !initialised )
Initialise();
width = 0;
linesize = 0;
height = 0;
pixels = 0;
colours = 0;
@ -125,6 +126,7 @@ 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,24 +269,16 @@ 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);
delete readjpg_dcinfo;
readjpg_dcinfo = 0;
readjpg_dcinfo = NULL;
}
if ( 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] ) {
@ -268,7 +297,7 @@ 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");
} else if ( config.cpu_extensions && neonversion >= 1 ) {
@ -325,7 +354,7 @@ 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;
@ -333,7 +362,7 @@ void Image::Initialise() {
fptr_delta8_abgr = &ssse3_delta8_abgr;
fptr_delta8_gray8 = &sse2_delta8_gray8;
Debug(4, "Delta: Using SSSE3 delta functions");
} else if ( sseversion >= 20 ) {
} else if ( sse_version >= 20 ) {
/* SSE2 available */
fptr_delta8_rgba = &sse2_delta8_rgba;
fptr_delta8_bgra = &sse2_delta8_bgra;
@ -437,7 +466,7 @@ void Image::Initialise() {
#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");
} else {
@ -449,60 +478,28 @@ void Image::Initialise() {
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 ) {
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,6 +531,7 @@ 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;
@ -541,8 +540,18 @@ uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_hei
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;
@ -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 ) {
@ -649,24 +667,30 @@ void Image::Assign(const unsigned int p_width, const unsigned int p_height, cons
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;
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 ) {
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,13 +710,19 @@ void Image::Assign( const Image &image ) {
colours = image.colours;
subpixelorder = image.subpixelorder;
size = new_size;
linesize = image.linesize;
}
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);
}
@ -712,79 +742,71 @@ Image *Image::HighlightEdges( Rgb colour, unsigned int p_colours, unsigned int p
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) {
@ -886,14 +908,11 @@ bool Image::ReadJpeg(const char *filename, unsigned int p_colours, unsigned int
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,21 +986,22 @@ 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);
@ -997,14 +1013,12 @@ bool Image::WriteJpeg(const char *filename, int quality_override, struct timeval
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 ) {
@ -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);
@ -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);
@ -1386,10 +1399,11 @@ bool Image::Crop( unsigned int lo_x, unsigned int lo_y, unsigned int hi_x, unsig
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 );
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;
}
@ -1402,7 +1416,7 @@ bool Image::Crop( unsigned int lo_x, unsigned int lo_y, unsigned int hi_x, unsig
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 );
}
@ -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
@ -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;
@ -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 */
@ -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:
@ -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<y2)?1:-1;
grad *= yinc;
if ( colours == ZM_COLOUR_GRAY8 ) {
//Debug( 9, "x1:%d, x2:%d, y1:%d, y2:%d, gr:%.2f", x1, x2, y1, y2, grad );
for ( x = x1, y = y1; y != y2; y += yinc, x += grad ) {
//Debug( 9, "x:%.2f, y:%d", x, y );
buffer[(y*width)+int(round(x))] = colour;
}
} else if ( colours == ZM_COLOUR_RGB24 ) {
@ -2418,7 +2454,8 @@ void Image::Fill( Rgb colour, int density, const Polygon &polygon ) {
#ifndef ZM_DBG_OFF
if ( logLevel() >= 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
@ -2445,7 +2482,8 @@ void Image::Fill( Rgb colour, int density, const Polygon &polygon ) {
#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
@ -2503,18 +2541,12 @@ void Image::Fill( Rgb colour, const Polygon &polygon ) {
Fill(colour, 1, polygon);
}
/* RGB32 compatible: complete */
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);
@ -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++;
@ -2628,7 +2660,7 @@ void Image::Rotate( int angle ) {
}
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 ) {
@ -2685,7 +2717,6 @@ void Image::Flip( bool leftright ) {
}
AssignDirect(width, height, colours, subpixelorder, flip_buffer, size, ZM_BUFTYPE_ZM);
}
void Image::Scale(unsigned int factor) {
@ -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;
}
} // 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() {
@ -3619,6 +3648,7 @@ __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;

View File

@ -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;
@ -166,14 +168,17 @@ 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);
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,12 +198,25 @@ 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(
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 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) {
Assign(image);

View File

@ -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 {

View File

@ -131,7 +131,7 @@ 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);
@ -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
@ -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);
Event::AddPreAlarmFrame(snap_image, *timestamp, score, (got_anal_image?&alarm_image:NULL));
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);
}
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

View File

@ -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<EncoderParameter_t>* GetOptEncoderParams() const { return &encoderparamsvec; }
const std::vector<EncoderParameter_t>* 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; }

View File

@ -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;
@ -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));

View File

@ -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];
@ -901,12 +901,24 @@ int RemoteCameraHttp::GetResponse() {
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) );
} 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) );
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 {

View File

@ -35,7 +35,7 @@
#include <curl/curl.h>
#endif
unsigned int sseversion = 0;
unsigned int sse_version = 0;
unsigned int neonversion = 0;
std::string trimSet(std::string str, std::string trimset) {
@ -45,10 +45,7 @@ std::string trimSet(std::string str, std::string trimset) {
// if all spaces or empty return an empty string
if ( ( std::string::npos == startpos ) || ( std::string::npos == endpos ) )
{
return std::string("");
}
else
return str.substr(startpos, endpos-startpos+1);
}
@ -67,8 +64,7 @@ std::string replaceAll(std::string str, std::string from, std::string to) {
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;
@ -79,11 +75,10 @@ const std::string stringtf( const char *format, ... )
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;
@ -94,7 +89,7 @@ const std::string stringtf( const std::string format, ... )
tempString = tempBuffer;
return( tempString );
return tempString;
}
bool startsWith(const std::string &haystack, const std::string &needle) {
@ -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;
@ -162,39 +156,32 @@ const std::string base64Encode(const std::string &inString) {
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<std::string>& items) {
@ -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;
@ -278,31 +265,31 @@ void hwcaps_detect() {
#endif
if ( r_ebx & 0x00000020 ) {
sseversion = 52; /* AVX2 */
sse_version = 52; /* AVX2 */
Debug(1, "Detected a x86\\x86-64 processor with AVX2");
} else if ( r_ecx & 0x10000000 ) {
sseversion = 51; /* AVX */
sse_version = 51; /* AVX */
Debug(1, "Detected a x86\\x86-64 processor with AVX");
} else if ( r_ecx & 0x00100000 ) {
sseversion = 42; /* SSE4.2 */
sse_version = 42; /* SSE4.2 */
Debug(1, "Detected a x86\\x86-64 processor with SSE4.2");
} else if ( r_ecx & 0x00080000 ) {
sseversion = 41; /* SSE4.1 */
sse_version = 41; /* SSE4.1 */
Debug(1, "Detected a x86\\x86-64 processor with SSE4.1");
} else if ( r_ecx & 0x00000200 ) {
sseversion = 35; /* SSSE3 */
sse_version = 35; /* SSSE3 */
Debug(1,"Detected a x86\\x86-64 processor with SSSE3");
} else if ( r_ecx & 0x00000001 ) {
sseversion = 30; /* SSE3 */
sse_version = 30; /* SSE3 */
Debug(1, "Detected a x86\\x86-64 processor with SSE3");
} else if ( r_edx & 0x04000000 ) {
sseversion = 20; /* SSE2 */
sse_version = 20; /* SSE2 */
Debug(1, "Detected a x86\\x86-64 processor with SSE2");
} else if ( r_edx & 0x02000000 ) {
sseversion = 10; /* SSE */
sse_version = 10; /* SSE */
Debug(1, "Detected a x86\\x86-64 processor with SSE");
} else {
sseversion = 0;
sse_version = 0;
Debug(1, "Detected a x86\\x86-64 processor");
}
#elif defined(__arm__)

View File

@ -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 );

View File

@ -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,
@ -407,18 +415,36 @@ bool VideoStore::open() {
if ( audio_out_stream ) zm_dump_stream_format(oc, 1, 0, 1);
AVDictionary *opts = NULL;
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");
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 ) {

View File

@ -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;

View File

@ -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);

View File

@ -259,6 +259,7 @@ int main(int argc, char *argv[]) {
Debug(1, "Failed to prime capture of initial monitor");
}
prime_capture_log_count ++;
if ( !zm_terminate )
sleep(10);
continue;
}

View File

@ -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,15 +220,20 @@ 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
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;
fi;
if [ "$DEBEMAIL" != "" ] && [ "$DEBFULLNAME" != "" ]; then
AUTHOR="$DEBFULLNAME <$DEBEMAIL>"

View File

@ -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."

View File

@ -1 +1 @@
1.34.14
1.34.20

View File

@ -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()' ),
@ -246,7 +246,7 @@ function collectData() {
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

View File

@ -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'] );
}
}
}
}

View File

@ -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'];
)));
return empty($frame)?null:$frame['Frame']['Id'];
}
} // end class EventsController

View File

@ -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;
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);
@ -62,6 +84,13 @@ class UsersController extends AppController {
*/
public function add() {
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) ) {
return $this->flash(__('The user has been saved.'), array('action' => 'index'));
@ -82,6 +111,13 @@ class UsersController extends AppController {
public function edit($id = null) {
$this->User->id = $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'));
}
@ -93,8 +129,10 @@ class UsersController extends AppController {
$message = 'Error';
}
} else {
# 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']);
unset($this->request->data['User']['Password']);
}
$this->set(array(
@ -112,6 +150,13 @@ class UsersController extends AppController {
*/
public function delete($id = null) {
$this->User->id = $id;
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'));
}
@ -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

View File

@ -40,6 +40,7 @@ class ZonesController extends AppController {
'_serialize' => array('zones')
));
}
public function index() {
$this->Zone->recursive = -1;
@ -63,7 +64,11 @@ class ZonesController extends AppController {
* @return void
*/
public function add() {
if ( $this->request->is('post') ) {
if ( !$this->request->is('post') ) {
throw new BadRequestException(__('Invalid method. Should be post'));
return;
}
global $user;
$canEdit = (!$user) || $user['Monitors'] == 'Edit';
@ -72,14 +77,30 @@ class ZonesController extends AppController {
return;
}
$zone = null;
$this->Zone->create();
if ( $this->Zone->save($this->request->data) ) {
return $this->flash(__('The zone has been saved.'), array('action' => 'index'));
$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

View File

@ -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' => ''
)
*/
);
}

View File

@ -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;
}
}

View File

@ -0,0 +1,2 @@
echo json_encode($message);
echo json_encode($zone);

View File

@ -0,0 +1,2 @@
echo json_encode($message);
echo json_encode($zone);

View File

@ -0,0 +1,2 @@
$xml = Xml::fromArray(array('response'=>$message, 'zone'=>$zone));
echo $xml->asXML();

View File

@ -0,0 +1,2 @@
$xml = Xml::fromArray(array('response' => $message, 'zone'=>$zone));
echo $xml->asXML();

View File

@ -262,14 +262,19 @@ 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());
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'};
}
@ -389,7 +394,7 @@ class Event extends ZM_Object {
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");
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']);
@ -401,19 +406,19 @@ class Event extends ZM_Object {
$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" );
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);
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
@ -421,7 +426,7 @@ class Event extends ZM_Object {
$captPath = $eventPath.'/'.$captImage;
if ( !file_exists($captPath) ) {
Error("Capture file does not exist at $captPath");
Error('Capture file does not exist at '.$captPath);
}
$analImage = sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d-analyse.jpg', $frame['FrameId']);
@ -484,7 +489,7 @@ class Event extends ZM_Object {
);
return $imageData;
}
} # getImageSrc
public function link_to($text=null) {
if ( !$text )

View File

@ -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'};
}

View File

@ -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,7 +298,7 @@ class Monitor extends ZM_Object {
return;
}
}
Logger::Debug("sending command to $url");
Logger::Debug('sending command to '.$url);
$context = stream_context_create();
try {
@ -317,7 +322,8 @@ class Monitor extends ZM_Object {
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);
@ -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);

View File

@ -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'}]);
}

View File

@ -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' ) {

View File

@ -18,16 +18,24 @@
// 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 ( isset($_REQUEST['newUser']['Password']) ) {
if ( function_exists('password_hash') ) {
$pass_hash = '"'.password_hash($_REQUEST['newUser']['Password'], PASSWORD_BCRYPT).'"';
} else {
@ -40,6 +48,7 @@ if ( $action == 'user' ) {
} else {
unset($changes['Password']);
}
}
if ( count($changes) ) {
if ( !empty($_REQUEST['uid']) ) {

View File

@ -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

View File

@ -389,7 +389,7 @@ function csrf_conf($key, $val) {
*/
function csrf_start() {
if ($GLOBALS['csrf']['auto-session'] && !session_id()) {
session_start();
zm_session_start();
}
}

View File

@ -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;
$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;
$socket = ':host='.$host . ';port='.$portOrSocket.';';
} else {
$socket = ':unix_socket='.$portOrSocket;
$socket = ':unix_socket='.$portOrSocket.';';
}
} else {
$socket = ':host='.ZM_DB_HOST;
$socket = ':host='.ZM_DB_HOST.';';
}
} else {
$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;

View File

@ -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,8 +840,14 @@ function daemonStatus($daemon, $args=false) {
initDaemonStatus();
$string = $daemon;
if ( $args )
if ( $args ) {
if ( is_array($args) ) {
$string .= join(' ', $args);
ZM\Warning("daemonStatus args: $string");
} else {
$string .= ' ' . $args;
}
}
return ( strpos($daemon_status, "'$string' running") !== false );
}
@ -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] ) {
@ -2078,15 +2084,20 @@ function checkJsonError($value) {
$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 {

View File

@ -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.'

View File

@ -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;

View File

@ -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;

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