Merge branch 'master' into api_auth

This commit is contained in:
Isaac Connor 2017-07-06 12:16:17 -04:00
commit 3bc1816cdf
79 changed files with 1745 additions and 2196 deletions

View File

@ -103,6 +103,8 @@ mark_as_advanced(
ZM_PERL_MM_PARMS
ZM_PERL_SEARCH_PATH
ZM_TARGET_DISTRO
ZM_PATH_MAP
ZM_PATH_ARP
ZM_CONFIG_DIR
ZM_CONFIG_SUBDIR
ZM_SYSTEMD)
@ -135,7 +137,21 @@ set(ZM_WEB_USER "" CACHE STRING
set(ZM_WEB_GROUP "" CACHE STRING
"The group apache or the local web server runs on,
Leave empty to be the same as the web user")
set(ZM_DIR_EVENTS "events" CACHE PATH
"Location where events are recorded to, default: events")
set(ZM_DIR_IMAGES "events" CACHE PATH
"Location where images, not directly associated with events,
are recorded to, default: images")
set(ZM_DIR_SOUNDS "sounds" CACHE PATH
"Location to look for optional sound files, default: sounds")
set(ZM_PATH_ZMS "/cgi-bin/nph-zms" CACHE PATH
"Web url to zms streaming server, default: /cgi-bin/nph-zms")
# Advanced
set(ZM_PATH_MAP "/dev/shm" CACHE PATH
"Location to save mapped memory files, default: /dev/shm")
set(ZM_PATH_ARP "" CACHE PATH
"Full path to compatible arp binary. Leave empty for automatic detection.")
set(ZM_CONFIG_DIR "/${CMAKE_INSTALL_SYSCONFDIR}" CACHE PATH
"Location of ZoneMinder configuration, default system config directory")
set(ZM_CONFIG_SUBDIR "${ZM_CONFIG_DIR}/conf.d" CACHE PATH
@ -183,6 +199,9 @@ if((ZM_TARGET_DISTRO MATCHES "^el") OR (ZM_TARGET_DISTRO MATCHES "^fc"))
set(ZM_CONFIG_SUBDIR "/etc/zm/conf.d")
set(ZM_WEBDIR "/usr/share/zoneminder/www")
set(ZM_CGIDIR "/usr/libexec/zoneminder/cgi-bin")
set(ZM_DIR_EVENTS "/var/lib/zoneminder/events")
set(ZM_DIR_IMAGES "/var/lib/zoneminder/images")
set(ZM_PATH_ZMS "/cgi-bin-zm/nph-zms")
elseif(ZM_TARGET_DISTRO STREQUAL "OS13")
set(ZM_RUNDIR "/var/run/zoneminder")
set(ZM_TMPDIR "/var/run/zoneminder")

View File

@ -70,6 +70,7 @@ ADD src /ZoneMinder/src/
ADD umutils /ZoneMinder/umutils/
ADD web /ZoneMinder/web/
ADD cmakecacheimport.sh CMakeLists.txt version zm.conf.in zmconfgen.pl.in zmlinkcontent.sh.in zoneminder-config.cmake /ZoneMinder/
ADD conf.d /ZoneMinder/conf.d
# Change into the ZoneMinder directory
WORKDIR /ZoneMinder

View File

@ -204,6 +204,7 @@ CREATE TABLE `Events` (
`Messaged` tinyint(3) unsigned NOT NULL default '0',
`Executed` tinyint(3) unsigned NOT NULL default '0',
`Notes` text,
`StateId` int(10) unsigned NOT NULL,
PRIMARY KEY (`Id`,`MonitorId`),
KEY `MonitorId` (`MonitorId`),
KEY `StartTime` (`StartTime`),
@ -330,13 +331,13 @@ CREATE TABLE `Monitors` (
`Format` int(10) unsigned NOT NULL default '0',
`V4LMultiBuffer` tinyint(1) unsigned,
`V4LCapturesPerFrame` tinyint(3) unsigned,
`Protocol` varchar(16) NOT NULL default '',
`Protocol` varchar(16) default '',
`Method` varchar(16) NOT NULL default '',
`Host` varchar(64),
`Port` varchar(8) NOT NULL default '',
`SubPath` varchar(64) NOT NULL default '',
`Path` varchar(255),
`Options` varchar(255) not null default '',
`Options` varchar(255) default '',
`User` varchar(64),
`Pass` varchar(64),
`Width` smallint(5) unsigned NOT NULL default '0',

20
db/zm_update-1.31.1.sql Normal file
View File

@ -0,0 +1,20 @@
--
-- This updates a 1.30.0 database to 1.30.1
--
-- Add StateId Column to Events.
--
SET @s = (SELECT IF(
(SELECT COUNT(*)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'Events'
AND table_schema = DATABASE()
AND column_name = 'StateId'
) > 0,
"SELECT 'Column StateId exists in Events'",
"ALTER TABLE Events ADD `StateId` int(10) unsigned default NULL AFTER `Notes`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;

View File

@ -6,3 +6,4 @@ usr/share/perl5/ZoneMinder.pm
usr/share/zoneminder/db
usr/share/zoneminder/www
etc/zm
etc/zm/conf.d/*

View File

@ -23,7 +23,10 @@ override_dh_auto_configure:
-DZM_WEB_USER=www-data \
-DZM_WEB_GROUP=www-data \
-DZM_CONFIG_SUBDIR="/etc/zm/conf.d" \
-DZM_CONFIG_DIR="/etc/zm"
-DZM_CONFIG_DIR="/etc/zm" \
-DZM_DIR_EVENTS="/var/cache/zoneminder/events" \
-DZM_DIR_IMAGES="/var/cache/zoneminder/images" \
-DZM_PATH_ZMS="/zm/cgi-bin/nph-zms"
override_dh_auto_install:
dh_auto_install --buildsystem=cmake

View File

@ -1 +1 @@
../redhat/redalert.wav
../redhat/misc/redalert.wav

View File

@ -28,7 +28,7 @@ New installs
1. Unless you are already using MariaDB server, you need to ensure that the
server is configured to start during boot and properly secured by running:
sudo dnf install mariadb-server
sudo yum install mariadb-server
sudo systemctl enable mariadb
sudo systemctl start mariadb.service
mysql_secure_installation

View File

@ -18,7 +18,7 @@ Alias /zm "@ZM_WEBDIR@"
Allow from all
</Directory>
ScriptAlias /cgi-bin/zm "@ZM_CGIDIR@"
ScriptAlias /cgi-bin-zm "@ZM_CGIDIR@"
<Directory "@ZM_CGIDIR@">
SSLRequireSSL
AllowOverride All

View File

@ -33,7 +33,7 @@
%global _hardened_build 1
Name: zoneminder
Version: 1.30.4
Version: 1.31.1
Release: 1%{?dist}
Summary: A camera monitoring and analysis tool
Group: System Environment/Daemons
@ -142,9 +142,7 @@ too much degradation of performance.
%{__mv} -f crud-%{crud_version} ./web/api/app/Plugin/Crud
# Change the following default values
./utils/zmeditconfigdata.sh ZM_PATH_ZMS /cgi-bin-zm/nph-zms
./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes
./utils/zmeditconfigdata.sh ZM_PATH_SWAP /dev/shm
./utils/zmeditconfigdata.sh ZM_UPLOAD_FTP_LOC_DIR %{_localstatedir}/spool/zoneminder-upload
./utils/zmeditconfigdata.sh ZM_OPT_CONTROL yes
./utils/zmeditconfigdata.sh ZM_CHECK_FOR_UPDATES no

View File

@ -16,16 +16,19 @@ endif
--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="/var/run/zm" \
-DZM_SOCKDIR="/var/run/zm" \
-DZM_TMPDIR="/tmp/zm" \
-DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \
-DZM_CONTENTDIR="/var/cache/zoneminder"
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="/var/run/zm" \
-DZM_SOCKDIR="/var/run/zm" \
-DZM_TMPDIR="/tmp/zm" \
-DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \
-DZM_CONTENTDIR="/var/cache/zoneminder" \
-DZM_DIR_EVENTS="/var/cache/zoneminder/events" \
-DZM_DIR_IMAGES="/var/cache/zoneminder/images" \
-DZM_PATH_ZMS="/zm/cgi-bin/nph-zms" \
override_dh_clean:
dh_clean $(MANPAGES1)

View File

@ -4,3 +4,5 @@ var/cache/zoneminder/events
var/cache/zoneminder/images
var/cache/zoneminder/temp
usr/share/zoneminder/db
etc/zm
etc/zm/conf.d

View File

@ -1,4 +1,5 @@
etc/zm/zm.conf
etc/zm/conf.d/*
usr/bin
usr/lib/zoneminder
usr/share/polkit-1

View File

@ -4,51 +4,51 @@ set -e
if [ "$1" = "configure" ]; then
. /etc/zm/zm.conf
. /etc/zm/zm.conf
# 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
# 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
# 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
# This creates the user.
echo "grant lock tables, alter,select,insert,update,delete,create,index 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,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
fi
# Ensure zoneminder is stopped
invoke-rc.d zoneminder stop || true
zmupdate.pl --nointeractive
zmupdate.pl --nointeractive -f
echo "Done Updating, starting ZoneMinder"
invoke-rc.d zoneminder start || true
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.'
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
# This creates the user.
echo "grant lock tables, alter,select,insert,update,delete,create,index 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,select,insert,update,delete,create,index 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
else
echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.'
fi
else
echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)"
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

@ -63,8 +63,10 @@ override_dh_auto_configure:
-DZM_WEB_USER=www-data \
-DZM_WEB_GROUP=www-data \
-DZM_CONFIG_SUBDIR="/etc/zm/conf.d" \
-DZM_CONFIG_DIR="/etc/zm"
-DZM_CONFIG_DIR="/etc/zm" \
-DZM_DIR_EVENTS="/var/cache/zoneminder/events" \
-DZM_DIR_IMAGES="/var/cache/zoneminder/images" \
-DZM_PATH_ZMS="/zm/cgi-bin/nph-zms"
override_dh_auto_test:
# do not run tests...

View File

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

View File

@ -1,607 +0,0 @@
zoneminder (1.29.0+dfsg-1) unstable; urgency=low
* New upstream release [February 2016] (Closes: #788317, #770851).
[ Dmitry Smirnov <onlyjob@debian.org> ]
* copyright/Files-Excluded += "onvif/*" due to licensing uncertainty.
* Fixed FTBFS when built with dpkg-buildpackage -A (Closes: #806126).
* FFmpeg 2.9 support. Thanks, Andreas Cadhalpun. (Closes: #803850).
* Use "ffmpeg" instead of "avconv":
+ "libav_path.patch" replaced with "default_ffmpeg_path.patch".
* zoneminder/Depends:
- perl-modules (package-relation-with-perl-modules)
- libav-tools
* zoneminder/Recommends:
+ ffmpeg | libav-tools
* Updated Vcs URLs.
* Build/install new man pages.
* Removed obsolete lintian-overrides.
* README: grant "index" right to DB user.
* systemd: start after MySQL but do not require the latter.
* Added new patch with spelling corrections.
* Removed obsolete patches:
- 783.patch
- 980-fix-image-size.patch
- cmake-fix-confpath.patch
- cmake.patch
- cmake-gnutls.patch
- fix-html-export.patch
- format-hardening.patch
- libv4l1-videodev.h.patch
- pod_man_fixes.patch
- pod_name_fixes.patch
- pod_zmupdate-to-pod2usage.patch
- respect-privacy.patch
- zmtrigger-plus.patch
[ Vagrant Cascadian <vagrant@debian.org> ]
* Remove myself from Uploaders.
-- Dmitry Smirnov <onlyjob@debian.org> Tue, 09 Feb 2016 15:40:32 +1100
zoneminder (1.28.1-8) unstable; urgency=medium
* Patchworks:
+ New upstream "980-fix-image-size.patch".
+ New "default_cgi-path.patch" to correct default ZM_PATH_ZMS.
* postinst: set "root" as group owner for "/var/log/zm" to silence
logrotate warnings.
* Minor correction to README.Debian.
-- Dmitry Smirnov <onlyjob@debian.org> Sun, 16 Aug 2015 19:19:50 +1000
zoneminder (1.28.1-7) unstable; urgency=medium
* Build-Depends += "cakephp (<< 3.0.0~)";
Zoneminder is not compatible with latest CakePHP.
* Handle conffile removal from maintscript.
* rules: build man pages reproducibly.
* gbp.conf: renamed old style config section [git-dch] to [dch].
* README
+ added instructions to update owner of the "/etc/zm/zm.conf"
(Closes: #789327).
+ zmupdate.pl needs CREATE rights.
+ added note about required number of "fcgiwrap" workers.
* New upstream patch: "zmtrigger-plus.patch".
-- Dmitry Smirnov <onlyjob@debian.org> Mon, 20 Jul 2015 16:30:15 +1000
zoneminder (1.28.1-6) unstable; urgency=low
* New "zoneminder-doc" and "zoneminder-dbg" packages.
-- Dmitry Smirnov <onlyjob@debian.org> Sun, 19 Apr 2015 14:50:41 +1000
zoneminder (1.28.1-5) unstable; urgency=low
* Move handling of "/var/run/zm" and "/tmp/zm" from .service into .tmpfile.
Let dh_installinit do the job. Thanks, Andrew Bauer.
* Use dh_apache2 to install Apache conf file; remove old conf and symlink.
* Promote "libapache2-mod-php5 | php5-fpm" to Recommends.
* Build-Depends:
+ dh-linktree
+ cakephp (>= 2.6.3)
+ libjs-jquery
+ libjs-mootools
* Depends:
- libjs-jquery
- libjs-mootools
* Build-time replace bundled CakePHP with system one using "dh-linktree".
* Use "dh-linktree" to handle mootools and jquery symlinks.
-- Dmitry Smirnov <onlyjob@debian.org> Sun, 19 Apr 2015 11:45:01 +1000
zoneminder (1.28.1-4) unstable; urgency=low
* New patch to fix HTML export with USE_DEEP_STORAGE (closes: #723706).
* New "783.patch" to describe potential data loss in ZM_USE_DEEP_STORAGE.
* New patch to change default date format to region-neutral ISO notation
with time zone.
* Build sphinx documentation:
+ Install "zoneminder.1" man page.
+ Build-Depends += "python-sphinx | python3-sphinx"
+ Added commented "zoneminder-doc" package.
+ Added "docs.patch" to unlink distro-specific installation docs.
* rules:
+ set ZM_CONTENTDIR, ZM_SOCKDIR and ZM_TMPDIR.
+ remove mistakengly installed Perl module templates.
* Updated startup scripts to create ZM_TMPDIR.
* Hurd improvements:
+ New patch to add PATH_MAX definitions.
+ Build without MMAP support on Hurd.
+ libsys-mmap-perl [!hurd-any].
-- Dmitry Smirnov <onlyjob@debian.org> Mon, 06 Apr 2015 18:18:55 +1000
zoneminder (1.28.1-3) unstable; urgency=low
* Updated Apache2 and nginx configuration templates to support CGI.
* Updated README.Debian to document cgi-bin setup.
* Removed "/usr/share/zoneminder/www/cgi-bin" symlink.
* Added "apache2.patch" to correct Apache2 site configuration example.
* control: Suggests += "fcgiwrap".
* rules: added dh_systemd overrides to prevent automatic service
activation and start.
* Added note about manual service activation to README.Debian
(Closes: #781733).
-- Dmitry Smirnov <onlyjob@debian.org> Thu, 02 Apr 2015 23:20:20 +1100
zoneminder (1.28.1-2) unstable; urgency=low
* Removed word "Linux" from short package description.
* Build-Depends: do not require "libv4l-dev" on Hurd i.e. [!hurd-any].
* Added run-time Perl Depends:
+ libdbd-mysql-perl
+ libimage-info-perl
+ libmodule-load-conditional-perl
+ libnet-sftp-foreign-perl
+ liburi-encode-perl
* Prepare for package split: added commented "libzoneminder-perl"
and "zoneminder-dbg" packages to "debian/control".
* rules: do not install worthless ".packlist" file.
* Updated "libv4l1-videodev.h.patch" to fix v4lv1 detection in CMake.
-- Dmitry Smirnov <onlyjob@debian.org> Thu, 02 Apr 2015 13:25:19 +1100
zoneminder (1.28.1-1) unstable; urgency=low
[ Dmitry Smirnov <onlyjob@debian.org> ]
* New upstream release [February 2015].
* Upload to unstable.
* Disabled automatic database upgrades: post(inst|rm) scripts no longer
touch database or do unexpected stuff (Closes: #779254).
See README.Debian for details.
* Updated installation paths:
+ /usr/share/zoneminder --> /usr/share/zoneminder/www
+ /usr/lib/cgi-bin --> /usr/lib/zoneminder/cgi-bin
* Added logrotate config (Closes: #544826).
Thanks, Alberto Reyes.
* Native systemd service; "--with systemd" added to dh.
* Build with CMake instead of autoconf; rules clean-up.
* Build with all hardening.
* Build and install "zmupdate.pl.1" man page.
* Added nginx/php5-fpm configuration example.
* Install upstream "apache.conf" example.
* Described setup of Zoneminer web site and database in README.Debian.
* Install "/etc/zm/zm.conf" with tighter permissions.
* Added TODO.Debian.
* Added "debian/clean"; "debian/gbp.conf"; bug-presubj.
* Remove bundled Cake tests to take ~5 MB off big-usr-share.
* Standards-Version: 3.9.6; compat/debhelper to version 9.
* Vcs links to new git repository at collab-maint.
* Build-Depends:
+ dh-systemd
+ libgcrypt11-dev --> libgcrypt-dev
+ libcurl4-gnutls-dev
+ libvlc-dev
+ policykit-1 (required by "zmsystemctl.pl")
- dh-autoreconf, autoconf, automake
* Depends:
- apache2
- libapache2-mod-php5 (moved to Suggests)
- libpcre3 (invalid)
- libmodule-load-perl (obsolete; replaced with perl-modules)
- libarchive-tar-perl (obsolete; replaced with perl-modules)
- mysql-server (moved to Recommends, Closes: #759504).
- php5
+ libav-tools
+ libjs-jquery (replaces bundled component)
+ libjs-mootool (replaces bundled component)
+ libjson-any-perl (Closes: #690803).
+ perl-modules (Closes: #745819).
* Recommends:
+ apache2 | httpd
+ mysql-server | virtual-mysql-server (Closes: #732874).
* Suggests:
+ libapache2-mod-php5 | php5-fpm
+ logrotate
* Refreshed, renamed and re-ordered patches; added DEP-3 headers.
* Removed "vendor_perl" patch (applied-upstream).
* New patches:
+ cmake-fix-confpath.patch
+ cmake-gnutls.patch
+ cmake-nossl.patch
+ cmake.patch
+ format-hardening.patch
+ pod_man_fixes.patch
+ pod_name_fixes.patch
+ pod_zmupdate-to-pod2usage.patch
* Lintianisation (incomplete):
- extra-license-file
- init.d-script-missing-lsb-description
- init.d-script-does-not-source-init-functions
- privacy-breach-generic
- package-contains-empty-directory
- manpage-has-errors-from-pod2man
- manpage-has-bad-whatis-entry
- quilt-patch-missing-description
- no-dep5-copyright
* Lintian-overrides:
+ unusual-interpreter usr/bin/zmsystemctl.pl #!/usr/bin/pkexec
+ script-not-executable usr/share/zoneminder/www/api/*
+ script-with-language-extension usr/bin/*.pl
+ source-is-missing web/tools/mootools/mootools-*-yc.js
+ source-is-missing web/skins/*/js/jquery-1.4.2.min.js
+ source-contains-prebuilt-javascript-object
* Renamed files in "debian".
* watch: dfsg repacksuffix and dversionmangle.
* "debian/copyright" to Copyright-Format-1.0.
* Set myself as new Maintainer (Closes: #760314).
[ Vagrant Cascadian <vagrant@debian.org> ]
* Removed obsolete DM-Upload-Allowed flag.
* Update debian/watch to use tarballs from github.
* Add Build-Depends on libgcrypt11-dev (Closes: #745819).
* Use canonical alioth Vcs-Hg URL.
* debian/control: Add Build-Depends: libpolkit-gobject-1-dev.
* Removed configure flag "--enable-crashtrace=no", which is no longer
present upstream.
-- Dmitry Smirnov <onlyjob@debian.org> Tue, 31 Mar 2015 15:11:13 +1100
zoneminder (1.26.5-3.1) experimental; urgency=low
* Non-maintainer upload.
* Add libav10.patch and compile against libav10 (Closes: #739461)
-- Reinhard Tartler <siretart@tauware.de> Wed, 19 Mar 2014 00:31:22 +0000
zoneminder (1.26.5-3) unstable; urgency=low
* Previous release still didn't build on PPC - this has been corrected.
(Closes: #736516)
-- Peter Howard <pjh@northern-ridge.com.au> Tue, 4 Feb 2014 02:02:10 +1000
zoneminder (1.26.5-2) unstable; urgency=low
* Remove dependency on ffmpeg
(Closes: #721161)
* Builds again on non-x86 target architectures.
-- Peter Howard <pjh@northern-ridge.com.au> Thu, 23 Jan 2014 01:02:10 +1000
zoneminder (1.26.5-1) unstable; urgency=low
* New upstream version
(Closes: #694131)
* Change Build-Depends on libgnutls-dev to libgnutls-openssl-dev
(Closes: #731560)
-- Peter Howard <pjh@northern-ridge.com.au> Tue, 17 Dec 2013 01:02:10 +1000
zoneminder (1.25.0-4) unstable; urgency=high
* Add CVE-2013-0232 patch
[SECURITY] CVE-2013-0232: Shell escape commands with untrusted content.
Thanks to James McCoy <jamessan@debian.org> (Closes: #698910)
Thanks also to Salvatore Bonaccorso <carnil@debian.org>
-- Peter Howard <pjh@northern-ridge.com.au> Tue, 12 Jun 2013 12:02:10 +1000
zoneminder (1.25.0-3) unstable; urgency=low
* debian/rules: Export CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS, to ensure
hardening build flags are enabled.
-- Vagrant Cascadian <vagrant@debian.org> Tue, 28 Aug 2012 12:10:03 -0700
zoneminder (1.25.0-2) unstable; urgency=low
[ Vagrant Cascadian ]
* Add a patch to disable checking for updated versions by default, as
upgrades should happen through package management.
* Use dpkg-buildflags in debian/rules to set default compiler flags.
* Ensure zoneminder is stopped before starting (Closes: #657407).
[ Peter Howard ]
* Fix postinst to add permission for table creation during upgrade
(Closes: #657407).
-- Vagrant Cascadian <vagrant@debian.org> Thu, 23 Aug 2012 12:40:34 -0700
zoneminder (1.25.0-1.1) unstable; urgency=low
* Non-maintainer upload.
* Fix "ftbfs with GCC-4.7": add patch Fix-FTBFS-with-gcc-4.7 from Cyril
Brulebois: fix missing <unistd.h> includes.
(Closes: #667428)
-- gregor herrmann <gregoa@debian.org> Sun, 13 May 2012 17:02:21 +0200
zoneminder (1.25.0-1) unstable; urgency=low
* Fix typo in libv4l1-videodev.h patch that caused v4l1 support to be
dropped.
* Fail to build if version in postinst doesn't match upstream version.
* Add Build-Depends: libavdevice-dev to fix MPEG streaming (Closes: #515558).
* debian/rules: Convert to using debhelper overrides.
* Set debian/compat to 7.
* Simplify debian/watch file.
* Refresh debian/patches/use_libjs-mootools.
* Refresh debian/patches/libv4l1-videodev.h.
* Remove dependencies on php4 and related packages.
* Remove build-dependencies on libmysqlclient14-dev and
libmysqlclient15-dev.
* Update Build-Depends to use libjpeg-dev instead of libjpeg62-dev
(Closes: #647114).
* Add patch to fix build by testing for C headers rather than C++ headers.
Thanks to Ryan Niebur. (Closes: #654230)
* Add a patch to fix build problems caused by API changes in libav 0.8.
Thanks again to Ryan Niebur. (Closes: #654230)
-- Vagrant Cascadian <vagrant@debian.org> Mon, 16 Jan 2012 11:58:05 -0800
zoneminder (1.24.4-1) unstable; urgency=low
[ Peter Howard ]
* Initial release of 1.24.4 (Closes: #634985).
- Fix 32/64-bit type declarations (Closes: #614404).
* Update patches.
[ Vagrant Cascadian ]
* Add patch to fix FTBFS by using libv4l1-videodev.h from libv4l-dev.
Thanks to Andreas Metzler for reporting the issue.
(Closes: #619813).
* Document adding the www-data user to the video group in README.Debian.
(Closes: #611324)
* Depend on libsys-mmap-perl to enable mapped memory support.
(Closes: #607331)
* Update libjs-mootools patch to use -nc variants (Closes: #635075).
* Depend on javascript-common, to ensure that /javascript is available in
the web server.
* Set the upstream version in postinst at build time.
* Use dh-autoreconf to properly clean up autogenerated files during build.
* Add Vcs-HG to debian/control.
* Add Build-Depends: libv4l-dev, libbz2-dev, dh-autoreconf, libsys-mmap-perl.
-- Vagrant Cascadian <vagrant@debian.org> Sun, 24 Jul 2011 16:44:30 +0200
zoneminder (1.24.2-9) unstable; urgency=low
* Apply patch from Ubuntu to fix FTBFS with ffmpeg 0.6:
- Add -D__STDC_CONSTANT_MACROS to CPPFLAGS (closes: 614080).
* Update Standards-Version to 3.9.1, no changes necessary.
-- Vagrant Cascadian <vagrant@debian.org> Sun, 20 Feb 2011 23:43:02 -0800
zoneminder (1.24.2-8) unstable; urgency=medium
[ Vagrant Cascadian ]
* Apply patch to fix V4L2 cameras without crop support (closes: #608790).
Thanks to piratebab.
* Add preinst script which aborts if dangerous symlinks exist.
(closes: #608793)
[ Peter Howard ]
* Added to README.Debian with info about images and events directories.
(closes: #608793)
-- Vagrant Cascadian <vagrant@debian.org> Sat, 15 Jan 2011 19:39:26 -0800
zoneminder (1.24.2-7) unstable; urgency=medium
* Do not set ownership of /var/cache/zoneminder when upgrading, which fixes a
regression causing upgrades to take inordinately long with large
installations (closes: #597040).
-- Vagrant Cascadian <vagrant@debian.org> Fri, 17 Sep 2010 11:24:41 -0700
zoneminder (1.24.2-6) unstable; urgency=low
* Only remove database on purge. This requires only creating the database if
it doesn't already exist, and upgrading the database only if the database
is an older version (closes: #497107).
* Do not prompt the user on database upgrades by using the --nointeractive
flag when calling zmupdate.pl from postinst (closes: #595902).
-- Vagrant Cascadian <vagrant@debian.org> Fri, 10 Sep 2010 10:06:06 -0700
zoneminder (1.24.2-5) unstable; urgency=low
[ Peter Howard ]
* Add zip dependency
(closes: #494261)
* Add debian/watch file
(closes: #545552)
* Use packaged libjs-mootools
(closes: #585590)
* Miscellaneous cleanups
[ Vagrant Cascadian ]
* Add vagrant@debian.org as uploader
* Update Standards-Version to 3.9.0, no changes necessary.
-- Vagrant Cascadian <vagrant@debian.org> Fri, 23 Jul 2010 18:12:50 -0500
zoneminder (1.24.2-4.1) unstable; urgency=low
* Non-maintainer upload.
* Fix "package removed, processes still running": apply patch to
debian/postinst by Vagrant Cascadian: use invoke-rc.d and run
mysql-related actions only when mysql is running (closes: #583648).
-- gregor herrmann <gregoa@debian.org> Thu, 01 Jul 2010 19:47:10 +0200
zoneminder (1.24.2-4) unstable; urgency=high
* Update init.d to list mysql dependency
(closes: #583505)
* Change dependency from libmime-perl to libmime-tools-perl
(closes: #585589)
* Problems in changelog format fixed
(closes: #585592)
* Fix debian-rules-ignores-make-clean-error
(closes: #585593)
-- Peter Howard <pjh@northern-ridge.com.au> Mon, 14 jun 2010 15:02:10 +1000
zoneminder (1.24.2-3) unstable; urgency=high
* Changes symbols to build with libjpeg8
(closes: #565326, #568327)
* Note: location of all perl files should have been fixed in previous release
(closes: #553096)
-- Peter Howard <pjh@northern-ridge.com.au> Mon, 26 apr 2010 15:02:10 +1000
zoneminder (1.24.2-2) unstable; urgency=high
* Remove custom perl parth from zmpkg.pl, fix location of manpages.
(closes: #551746, #553092)
* Fix GCC4.4 bug
(closes: #531717)
* Fix potential bug in postinst script
-- Peter Howard <pjh@northern-ridge.com.au> Sat, 14 Nov 2009 15:02:10 +1000
zoneminder (1.24.2-1) unstable; urgency=high
* Initial release of zoneminder 1.24.2
-- Peter Howard <pjh@northern-ridge.com.au> Fri, 11 Sep 2009 07:02:50 +1000
zoneminder (1.24.1-1) unstable; urgency=high
* Initial release of zoneminder 1.24.1, closing CVE-2008-3882,
CVE-2008-3881, CVE-2008-3880
(closes: #497640)
* Change syslog dependency to rsyslog.
(closes: #526918)
* Add missing perl dependency.
* Restore patch to disable "check for updates" by default.
* Removed spurious '$' in init script.
(closes: #486064)
* Change permission of zm.conf from 0600 to 0400 for CVE-2008-6755
(closes: #528252)
-- Peter Howard <pjh@northern-ridge.com.au> Sat, 16 May 2009 07:02:50 +1000
zoneminder (1.23.3-4) unstable; urgency=high
* update to get it building with latest unstable. Thanks to waldi@debian.org
(closes: #517569)
-- Peter Howard <pjh@northern-ridge.com.au> Thu, 16 Apr 2009 01:02:50 +1000
zoneminder (1.23.3-3) unstable; urgency=high
* ffmpeg confirmed working
(closes: #475145)
* Fix upgrade problem intrudouced in 1.23.3-1
(closes: #481637)
* Include libmime-lite-perl in dependencies
(closes: #486312)
-- Peter Howard <pjh@northern-ridge.com.au> Thu, 18 Sep 2008 01:02:50 +1000
zoneminder (1.23.3-2) unstable; urgency=high
* ffmpeg finally working?
-- Peter Howard <pjh@northern-ridge.com.au> Wed, 13 Aug 2008 01:02:50 +1000
zoneminder (1.23.3-1) unstable; urgency=high
* Initial version for 1.23.3 - security fix.
(closes: #479034)
-- Peter Howard <pjh@northern-ridge.com.au> Wed, 19 Mar 2008 01:02:50 +1000
zoneminder (1.23.2-2) unstable; urgency=low
* Update to init.d
(closes: #468856)
* Add dependency on logging daemon
(closes: #471277)
-- Peter Howard <pjh@northern-ridge.com.au> Wed, 19 Mar 2008 01:02:50 +1000
zoneminder (1.23.2-1) unstable; urgency=low
* Initial version for 1.23.2
(closes: #464152)
* Zoneminder 1.23.2 upstream includes fix for GCC 4.3
(closes: #454980)
* Includes ffmpeg patch by Alexander Kushnirenko <kushnir@uni-protvino.ru>
-- Peter Howard <pjh@northern-ridge.com.au> Sat, 01 Mar 2008 16:02:50 +1000
zoneminder (1.22.3-10) unstable; urgency=low
* Fix bug introduced in -9 where perl is put under /usr/local
(closes: #457507)
-- Peter Howard <pjh@northern-ridge.com.au> Mon, 24 Dec 2007 16:02:50 +1000
zoneminder (1.22.3-9) unstable; urgency=low
* Starting zoneminder via init script now invokes "zmfix -a"
(closes: #481637)
* Change apache2-mpm-prefork dependency to apache2
* Temp dir for export under /var/cache/zoneminder (but linked back to
/usr/share/zoneminder for now)
* Redo use of gnutls rather than openssl for md5 hashes
-- Peter Howard <pjh@northern-ridge.com.au> Mon, 10 Dec 2007 16:02:50 +1000
zoneminder (1.22.3-8) unstable; urgency=low
* Build now includes libpcre3
(closes: #437533)
* "Monitor Presets" patch now applied to package during build.
-- Peter Howard <pjh@northern-ridge.com.au> Sat, 18 Aug 2007 14:35:23 +1000
zoneminder (1.22.3-7) unstable; urgency=low
* Turn off debug trace and crash dump on build
(closes:#414857,#414891)
* Additional perl libraries added in dependencies
(closes:#416291)
* Change preferred PHP version from 4 to 5
-- Peter Howard <pjh@northern-ridge.com.au> Sun, 29 Jul 2007 15:11:13 +1000
zoneminder (1.22.3-6) unstable; urgency=low
* Removed a similar bash only statement from zmpkg.pl
(closes:414882)
-- Peter Howard <pjh@northern-ridge.com.au> Sat, 14 Apr 2007 11:46:56 +1000
zoneminder (1.22.3-5) unstable; urgency=low
* Installs with "phone home" feature turned off by default, and permissions
on /etc/zm/zm.conf fixed (now the 0600 it s hould be)
(closes:415349)
* Removed "stupid bash-ism" on mysqld check in postinst file.
-- Peter Howard <pjh@northern-ridge.com.au> Fri, 6 Apr 2007 15:50:00 +1000
zoneminder (1.22.3-4) unstable; urgency=low
* Put libmysqlclient-15-dev in front of -14-dev so sbuild works
(closes: #414410)
-- Peter Howard <pjh@northern-ridge.com.au> Mon, 12 Mar 2007 11:38:56 +1100
zoneminder (1.22.3-3) unstable; urgency=low
* Clean up of postinstall, postrm ; user "zm" definitely was a mistake
* Also in postinstall: check and start MySQL if it's not running.
* init.d script now checks if zoneminder isn't running and still returns 0
(which helps uninstalling)
* Addition of php5 dependency options as well as php4.
-- Peter Howard <pjh@northern-ridge.com.au> Mon, 26 Feb 2007 10:40:52 +1100
zoneminder (1.22.3-2) unstable; urgency=low
* Added zmuser in the mysql creation; this should fix the install problem
for people, but needs to be cleaned up (in -3)
-- Peter Howard <pjh@northern-ridge.com.au> Fri, 16 Feb 2007 14:16:03 +1100
zoneminder (1.22.3-1) unstable; urgency=low
* Initial Version. (closes: #248393)
* Patched out use of openssl; uses gnutls instead for MD5 hashes.
* Removed MakeMaker-inserted Perl licensing (with authors permission) in
various scripts; replaced with GPL.
-- Peter Howard <pjh@northern-ridge.com.au> Wed, 7 Feb 2007 14:09:01 +1100

View File

@ -25,7 +25,10 @@ override_dh_auto_configure:
-DZM_SOCKDIR="/var/run/zm" \
-DZM_TMPDIR="/tmp/zm" \
-DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \
-DZM_CONTENTDIR="/var/cache/zoneminder"
-DZM_CONTENTDIR="/var/cache/zoneminder" \
-DZM_DIR_EVENTS="/var/cache/zoneminder/events" \
-DZM_DIR_IMAGES="/var/cache/zoneminder/images" \
-DZM_PATH_ZMS="/zm/cgi-bin/nph-zms"
override_dh_clean:
dh_clean $(MANPAGES1)

View File

@ -4,3 +4,5 @@ var/cache/zoneminder/events
var/cache/zoneminder/images
var/cache/zoneminder/temp
usr/share/zoneminder/db
etc/zm/
etc/zm/conf.d

View File

@ -1,4 +1,5 @@
etc/zm/zm.conf
etc/zm/conf.d/*
usr/bin
usr/lib/zoneminder
usr/share/polkit-1

View File

@ -4,61 +4,62 @@ set -e
if [ "$1" = "configure" ]; then
. /etc/zm/zm.conf
. /etc/zm/zm.conf
# 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
if [ ! -e "/etc/apache2/mods-enabled/cgi.load" ]; then
echo "The cgi module is not enabled in apache2. I am enabling it using a2enmod cgi."
a2enmod cgi
fi
# 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
if [ ! -e "/etc/apache2/mods-enabled/cgi.load" ]; then
echo "The cgi module is not enabled in apache2. I am enabling it using a2enmod cgi."
a2enmod cgi
fi
# Do this every time the package is installed or upgraded
# Ensure zoneminder is stopped
deb-systemd-invoke stop zoneminder.service || exit $?
# Ensure zoneminder is stopped
deb-systemd-invoke stop zoneminder.service || exit $?
if [ "$ZM_DB_HOST" = "localhost" ]; then
if [ -e "/etc/init.d/mysql" ]; 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
deb-systemd-invoke start mysql.service || exit $?
fi
#
# Get mysql started if it isn't
#
if ! $(/etc/init.d/mysql status >/dev/null 2>&1); then
deb-systemd-invoke start mysql.service || exit $?
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
# This creates the user.
echo "grant lock tables,alter,select,insert,update,delete,create,index 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,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
fi
# Ensure zoneminder is stopped
deb-systemd-invoke stop zoneminder.service || exit $?
zmupdate.pl --nointeractive
zmupdate.pl --nointeractive -f
echo "Done Updating, starting ZoneMinder"
deb-systemd-invoke start zoneminder.service || exit $?
else
echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.'
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
# This creates the user.
echo "grant lock tables,alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
else
echo 'mysql not found, assuming remote server.'
echo "grant lock tables,alter,select,insert,update,delete,create,index 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
else
echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.'
fi
else
echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)"
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"
deb-systemd-invoke restart zoneminder.service || exit $?
fi
#DEBHELPER#

View File

@ -72,11 +72,12 @@ Source Tab
FFmpeg
^^^^^^
This is the recommended source type for most modern ip cameras.
Source Path
Use this field to enter the full URL of the stream or file your camera supports. This is usually an RTSP url. There are several methods to learn this:
* Check the documentation that came with your camera
* Look for your camera in the hardware compatibilty list in the wiki http://wiki.zoneminder.com/Hardware_Compatibilty_List
* Look for your camera in the hardware compatibilty list in the wiki http://wiki.zoneminder.com/Hardware_Compatibility_List
* Try ZoneMinder's new ONVIF probe feature
* Download and install the ONVIF Device Manager onto a Windows machine https://sourceforge.net/projects/onvifdm/
* Use Google to find third party sites, such as ispy, which document this information

View File

@ -11,6 +11,8 @@
@ZM_LOGDIR@/*.log {
missingok
notifempty
delaycompress
compress
sharedscripts
postrotate
/bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true

View File

@ -33,8 +33,11 @@ FOREACH(PERLSCRIPT ${perlscripts})
ENDFOREACH(PERLSCRIPT ${perlscripts})
# Install the perl scripts
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zmaudit.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmcontrol.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmdc.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmfilter.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmpkg.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtrack.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtrigger.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmupdate.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmvideo.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmwatch.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmcamtool.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmsystemctl.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtelemetry.pl" DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zmaudit.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmcontrol.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmdc.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmfilter.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmpkg.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtrack.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtrigger.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmupdate.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmvideo.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmwatch.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmcamtool.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtelemetry.pl" DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
if(NOT ZM_NO_X10)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zmx10.pl" DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
endif(NOT ZM_NO_X10)
if(WITH_SYSTEMD)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zmsystemctl.pl" DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
endif(WITH_SYSTEMD)

View File

@ -427,23 +427,6 @@ our @options = (
type => $types{string},
category => 'system',
},
{
name => 'ZM_DIR_EVENTS',
default => 'events',
description => 'Directory where events are stored',
help => q`
This is the path to the events directory where all the event
images and other miscellaneous files are stored. CAUTION: The
directory you specify here cannot be outside the web root. This
is a common mistake. Most users should never change this value.
If you intend to record events to a second disk or network
share, then you should mount the drive or share directly to the
ZoneMinder events folder or follow the instructions in the
ZoneMinder Wiki titled Using a dedicated Hard Drive.
`,
type => $types{directory},
category => 'paths',
},
{
name => 'ZM_USE_DEEP_STORAGE',
default => 'yes',
@ -465,68 +448,6 @@ our @options = (
type => $types{boolean},
category => 'hidden',
},
{
name => 'ZM_DIR_IMAGES',
default => 'images',
description => 'Directory where the images that the ZoneMinder client generates are stored',
help => q`
ZoneMinder generates a myriad of images, mostly of which are
associated with events. For those that aren't this is where
they go. CAUTION: The directory you specify here cannot be
outside the web root. This is a common mistake. Most users
should never change this value. If you intend to save images to
a second disk or network share, then you should mount the drive
or share directly to the ZoneMinder images folder or follow the
instructions in the ZoneMinder Wiki titled Using a dedicated
Hard Drive.
`,
type => $types{directory},
category => 'paths',
},
{
name => 'ZM_DIR_SOUNDS',
default => 'sounds',
description => 'Directory to the sounds that the ZoneMinder client can use',
help => q`
ZoneMinder can optionally play a sound file when an alarm is
detected. This indicates where to look for this file. CAUTION:
The directory you specify here cannot be outside the web root.
Most users should never change this value.
`,
type => $types{directory},
category => 'paths',
},
{
name => 'ZM_DIR_EXPORTS',
default => '@ZM_TMPDIR@',
description => 'Directory where exported archives are stored',
help => q`
This is the path to the exports directory where exported
tar.gz and zip archives are stored. By default this points to
ZoneMinder's temp folder, which often sits in ram. Since exported
archives can potentially become large, it is a good idea to move
this folder to some other location on machines with low memory.
`,
type => $types{directory},
category => 'paths',
},
{
name => 'ZM_PATH_ZMS',
default => '/cgi-bin/nph-zms',
description => 'Web path to zms streaming server',
help => q`
The ZoneMinder streaming server is required to send streamed
images to your browser. It will be installed into the cgi-bin
path given at configuration time. This option determines what
the web path to the server is rather than the local path on
your machine. Ordinarily the streaming server runs in
parser-header mode however if you experience problems with
streaming you can change this to non-parsed-header (nph) mode
by changing 'zms' to 'nph-zms'.
`,
type => $types{rel_path},
category => 'paths',
},
{
name => 'ZM_COLOUR_JPEG_FILES',
default => 'no',
@ -1471,83 +1392,6 @@ our @options = (
type => $types{boolean},
category => 'logging',
},
{
name => 'ZM_PATH_MAP',
default => '/dev/shm',
description => 'Path to the mapped memory files that that ZoneMinder can use',
help => q`
ZoneMinder has historically used IPC shared memory for shared
data between processes. This has it's advantages and
limitations. This version of ZoneMinder can use an alternate
method, mapped memory, instead with can be enabled with the
--enable--mmap directive to configure. This requires less
system configuration and is generally more flexible. However it
requires each shared data segment to map onto a filesystem
file. This option indicates where those mapped files go. You
should ensure that this location has sufficient space for these
files and for the best performance it should be a tmpfs file
system or ramdisk otherwise disk access may render this method
slower than the regular shared memory one.
`,
type => $types{abs_path},
category => 'paths',
},
{
name => 'ZM_PATH_SOCKS',
default => '@ZM_SOCKDIR@',
description => 'Path to the various Unix domain socket files that ZoneMinder uses',
help => q`
ZoneMinder generally uses Unix domain sockets where possible.
This reduces the need for port assignments and prevents
external applications from possibly compromising the daemons.
However each Unix socket requires a .sock file to be created.
This option indicates where those socket files go.
`,
type => $types{abs_path},
category => 'paths',
},
{
name => 'ZM_PATH_LOGS',
default => '@ZM_LOGDIR@',
description => 'Path to the various logs that the ZoneMinder daemons generate',
help => q`
There are various daemons that are used by ZoneMinder to
perform various tasks. Most generate helpful log files and this
is where they go. They can be deleted if not required for
debugging.
`,
type => $types{abs_path},
category => 'paths',
},
{
name => 'ZM_PATH_SWAP',
default => '@ZM_TMPDIR@',
description => 'Path to location for temporary swap images used in streaming',
help => q`
Buffered playback requires temporary swap images to be stored
for each instance of the streaming daemons. This option
determines where these images will be stored. The images will
actually be stored in sub directories beneath this location and
will be automatically cleaned up after a period of time.
`,
type => $types{abs_path},
category => 'paths',
},
{
name => 'ZM_PATH_ARP',
default => '',
description => 'Path to a supported ARP tool',
help => q`
The camera probe function uses Address Resolution Protocol in
order to find known devices on the network. Optionally supply
the full path to \"ip neigh\", \"arp -a\", or any other tool on
your system that returns ip/mac address pairs. If this field is
left empty, ZoneMinder will search for the command \"arp\" and
attempt to use that.
`,
type => $types{abs_path},
category => 'paths',
},
{
name => 'ZM_WEB_TITLE_PREFIX',
default => 'ZM',

View File

@ -41,7 +41,7 @@ our @ISA = qw(Exporter ZoneMinder::Base);
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
# will save memory.
our %EXPORT_TAGS = (
'constants' => [ qw(
constants => [ qw(
DEBUG
INFO
WARNING
@ -50,7 +50,7 @@ our %EXPORT_TAGS = (
PANIC
NOLOG
) ],
'functions' => [ qw(
functions => [ qw(
logInit
logReinit
logTerm
@ -72,13 +72,14 @@ our %EXPORT_TAGS = (
Panic
) ]
);
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
our @EXPORT = qw();
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our $VERSION = $ZoneMinder::Base::VERSION;
our @EXPORT = qw();
our $VERSION = $ZoneMinder::Base::VERSION;
# ==========================================================================
#
@ -86,43 +87,43 @@ our %EXPORT_TAGS = (
#
# ==========================================================================
use ZoneMinder::Config qw(:all);
use ZoneMinder::Config qw(:all);
use DBI;
use Carp;
use POSIX;
use IO::Handle;
use Data::Dumper;
use Time::HiRes qw/gettimeofday/;
use Sys::Syslog;
use DBI;
use Carp;
use POSIX;
use IO::Handle;
use Data::Dumper;
use Time::HiRes qw/gettimeofday/;
use Sys::Syslog;
use constant {
DEBUG => 1,
INFO => 0,
WARNING => -1,
ERROR => -2,
FATAL => -3,
PANIC => -4,
NOLOG => -5
};
use constant {
DEBUG => 1,
INFO => 0,
WARNING => -1,
ERROR => -2,
FATAL => -3,
PANIC => -4,
NOLOG => -5
};
our %codes = (
&DEBUG => "DBG",
&INFO => "INF",
&WARNING => "WAR",
&ERROR => "ERR",
&FATAL => "FAT",
&PANIC => "PNC",
&NOLOG => "OFF"
&DEBUG => 'DBG',
&INFO => 'INF',
&WARNING => 'WAR',
&ERROR => 'ERR',
&FATAL => 'FAT',
&PANIC => 'PNC',
&NOLOG => 'OFF'
);
our %priorities = (
&DEBUG => "debug",
&INFO => "info",
&WARNING => "warning",
&ERROR => "err",
&FATAL => "err",
&PANIC => "err"
&DEBUG => 'debug',
&INFO => 'info',
&WARNING => 'warning',
&ERROR => 'err',
&FATAL => 'err',
&PANIC => 'err'
);
our $logger;
@ -134,10 +135,10 @@ sub new {
$this->{initialised} = undef;
#$this->{id} = "zmundef";
#$this->{id} = 'zmundef';
( $this->{id} ) = $0 =~ m|^(?:.*/)?([^/]+?)(?:\.[^/.]+)?$|;
$this->{idRoot} = $this->{id};
$this->{idArgs} = "";
$this->{idArgs} = '';
$this->{level} = INFO;
$this->{termLevel} = NOLOG;
@ -151,7 +152,7 @@ sub new {
( $this->{fileName} = $0 ) =~ s|^.*/||;
$this->{logPath} = $Config{ZM_PATH_LOGS};
$this->{logFile} = $this->{logPath}."/".$this->{id}.".log";
$this->{logFile} = $this->{logPath}.'/'.$this->{id}.".log";
$this->{trace} = 0;
@ -196,7 +197,7 @@ sub initialise( @ ) {
$this->{logPath} = $options{logPath} if ( defined($options{logPath}) );
my $tempLogFile;
$tempLogFile = $this->{logPath}."/".$this->{id}.".log";
$tempLogFile = $this->{logPath}.'/'.$this->{id}.".log";
$tempLogFile = $options{logFile} if ( defined($options{logFile}) );
if ( my $logFile = $this->getTargettedEnv('LOG_FILE') ) {
$tempLogFile = $logFile;
@ -231,7 +232,6 @@ sub initialise( @ ) {
my $level;
$tempLevel = $level if ( defined($level = $this->getTargettedEnv('LOG_LEVEL')) );
$tempTermLevel = $level if ( defined($level = $this->getTargettedEnv('LOG_LEVEL_TERM')) );
$tempDatabaseLevel = $level if ( defined($level = $this->getTargettedEnv('LOG_LEVEL_DATABASE')) );
$tempFileLevel = $level if ( defined($level = $this->getTargettedEnv('LOG_LEVEL_FILE')) );
@ -240,9 +240,9 @@ sub initialise( @ ) {
if ( $Config{ZM_LOG_DEBUG} ) {
foreach my $target ( split( /\|/, $Config{ZM_LOG_DEBUG_TARGET} ) ) {
if ( $target eq $this->{id}
|| $target eq "_".$this->{id}
|| $target eq '_'.$this->{id}
|| $target eq $this->{idRoot}
|| $target eq "_".$this->{idRoot}
|| $target eq '_'.$this->{idRoot}
|| $target eq ""
) {
if ( $Config{ZM_LOG_DEBUG_LEVEL} > NOLOG ) {
@ -271,13 +271,13 @@ sub initialise( @ ) {
$this->{initialised} = !undef;
Debug( "LogOpts: level=".$codes{$this->{level}}
."/".$codes{$this->{effectiveLevel}}
.", screen=".$codes{$this->{termLevel}}
.", database=".$codes{$this->{databaseLevel}}
.", logfile=".$codes{$this->{fileLevel}}
."->".$this->{logFile}
.", syslog=".$codes{$this->{syslogLevel}}
Debug( 'LogOpts: level='.$codes{$this->{level}}
.'/'.$codes{$this->{effectiveLevel}}
.', screen='.$codes{$this->{termLevel}}
.', database='.$codes{$this->{databaseLevel}}
.', logfile='.$codes{$this->{fileLevel}}
.'->'.$this->{logFile}
.', syslog='.$codes{$this->{syslogLevel}}
);
}
@ -322,11 +322,11 @@ sub limit {
sub getTargettedEnv {
my $this = shift;
my $name = shift;
my $envName = $name."_".$this->{id};
my $envName = $name.'_'.$this->{id};
my $value;
$value = $ENV{$envName} if ( defined($ENV{$envName}) );
if ( !defined($value) && $this->{id} ne $this->{idRoot} ) {
$envName = $name."_".$this->{idRoot};
$envName = $name.'_'.$this->{idRoot};
$value = $ENV{$envName} if ( defined($ENV{$envName}) );
}
if ( !defined($value) ) {
@ -375,8 +375,8 @@ sub level {
$this->{effectiveLevel} = $this->{termLevel} if ( $this->{termLevel} > $this->{effectiveLevel} );
$this->{effectiveLevel} = $this->{databaseLevel} if ( $this->{databaseLevel} > $this->{effectiveLevel} );
$this->{effectiveLevel} = $this->{fileLevel} if ( $this->{fileLevel} > $this->{effectiveLevel} );
$this->{effectiveLevel} = $this->{syslogLevel} if ( $this->{syslogLevel} > $this->{level} );
$this->{effectiveLevel} = $this->{level} if ( $this->{effectiveLevel} > $this->{level} );
$this->{effectiveLevel} = $this->{syslogLevel} if ( $this->{syslogLevel} > $this->{effectiveLevel} );
$this->{effectiveLevel} = $this->{level} if ( $this->{effectiveLevel} > $this->{effectiveLevel} );
}
return( $this->{level} );
}
@ -490,7 +490,7 @@ sub syslogLevel {
sub openSyslog {
my $this = shift;
openlog( $this->{id}, "pid", "local1" );
openlog( $this->{id}, 'pid', "local1" );
}
sub closeSyslog {
@ -523,6 +523,7 @@ sub openFile {
}
} else {
$this->fileLevel( NOLOG );
$this->termLevel( INFO );
Error( "Can't open log file '".$this->{logFile}."': $!" );
}
}
@ -544,10 +545,8 @@ sub logPrint {
my ($seconds, $microseconds) = gettimeofday();
my $message = sprintf(
"%s.%06d %s[%d].%s [%s]"
, strftime( "%x %H:%M:%S"
,localtime( $seconds )
)
'%s.%06d %s[%d].%s [%s]'
, strftime( '%x %H:%M:%S' ,localtime( $seconds ) )
, $microseconds
, $this->{id}
, $$
@ -564,7 +563,7 @@ sub logPrint {
}
print( $LOGFILE $message ) if ( $level <= $this->{fileLevel} );
if ( $level <= $this->{databaseLevel} ) {
my $sql = "insert into Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) values ( ?, ?, ?, ?, ?, ?, ?, NULL )";
my $sql = 'insert into Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) values ( ?, ?, ?, ?, ?, ?, ?, NULL )';
$this->{sth} = $this->{dbh}->prepare_cached( $sql );
if ( !$this->{sth} ) {
$this->{databaseLevel} = NOLOG;
@ -589,7 +588,7 @@ sub logPrint {
sub logInit( ;@ ) {
my %options = @_ ? @_ : ();
$logger = ZoneMinder::Logger->new() if ( !$logger );
$logger = ZoneMinder::Logger->new() if !$logger;
$logger->initialise( %options );
}
@ -646,14 +645,14 @@ sub logSyslogLevel {
sub Mark {
my $level = shift;
$level = DEBUG unless( defined($level) );
my $tag = "Mark";
my $tag = 'Mark';
fetch()->logPrint( $level, $tag );
}
sub Dump {
my $var = shift;
my $label = shift;
$label = "VAR" unless( defined($label) );
$label = 'VAR' unless( defined($label) );
fetch()->logPrint( DEBUG, Data::Dumper->Dump( [ $var ], [ $label ] ) );
}
@ -695,10 +694,10 @@ ZoneMinder::Logger - ZoneMinder Logger module
use ZoneMinder::Logger;
use ZoneMinder::Logger qw(:all);
logInit( "myproc", DEBUG );
logInit( 'myproc', DEBUG );
Debug( "This is what is happening" );
Info( "Something interesting is happening" );
Debug( 'This is what is happening' );
Info( 'Something interesting is happening' );
Warning( "Something might be going wrong." );
Error( "Something has gone wrong!!" );
Fatal( "Something has gone badly wrong, gotta stop!!" );

View File

@ -21,6 +21,304 @@
#
# ==========================================================================
use strict;
use bytes;
@EXTRA_PERL_LIB@
use ZoneMinder;
use DBI;
use Getopt::Long;
use autouse 'Pod::Usage'=>qw(pod2usage);
use LWP::UserAgent;
use Sys::MemInfo qw(totalmem);
use Sys::CPU qw(cpu_count);
use POSIX qw(strftime uname);
$ENV{PATH} = '/bin:/usr/bin:/usr/local/bin';
$ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL};
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
use constant CHECK_INTERVAL => (14*24*60*60); # Interval between version checks
# Setting these as contants for now.
# Alternatively, we can put these in the dB and then retrieve using the Config hash.
use constant ZM_TELEMETRY_SERVER_ENDPOINT => 'https://zmanon:2b2d0b4skps@telemetry.zoneminder.com/zmtelemetry/testing5';
if ( $Config{ZM_TELEMETRY_DATA} ) {
print( 'Update agent starting at '.strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
my $lastCheck = $Config{ZM_TELEMETRY_LAST_UPLOAD};
while( 1 ) {
my $now = time();
if ( ($now-$lastCheck) > CHECK_INTERVAL ) {
Info( 'Collecting data to send to ZoneMinder Telemetry server.' );
my $dbh = zmDbConnect();
# Build the telemetry hash
# We should keep *BSD systems in mind when calling system commands
my %telemetry;
$telemetry{uuid} = getUUID($dbh);
$telemetry{ip} = getIP();
$telemetry{timestamp} = strftime( '%Y-%m-%dT%H:%M:%S%z', localtime() );
$telemetry{monitor_count} = countQuery($dbh,'Monitors');
$telemetry{event_count} = countQuery($dbh,'Events');
$telemetry{architecture} = runSysCmd('uname -p');
($telemetry{kernel}, $telemetry{distro}, $telemetry{version}) = getDistro();
$telemetry{zm_version} = ZoneMinder::Base::ZM_VERSION;
$telemetry{system_memory} = totalmem();
$telemetry{processor_count} = cpu_count();
$telemetry{monitors} = getMonitorRef($dbh);
Info( 'Sending data to ZoneMinder Telemetry server.' );
my $result = jsonEncode( \%telemetry );
if ( sendData($result) ) {
$lastCheck = $now;
my $sql = q`update Config set Value = ? where Name = 'ZM_TELEMETRY_LAST_UPLOAD'`;
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( "$lastCheck" ) or die( "Can't execute: ".$sth->errstr() );
$sth->finish();
}
}
sleep( 3600 );
}
print( 'Update agent exiting at '.strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
}
###############
# SUBROUTINES #
###############
# Find, verify, then run the supplied system command
sub runSysCmd {
my $msg = shift;
my @arguments = split(/ /,$msg);
chomp($arguments[0]);
my $path = qx( which $arguments[0] );
my $status = $? >> 8;
my $result = '';
if ( !$path || $status ) {
Warning( "Cannot find the $arguments[0] executable." );
} else {
chomp($path);
$arguments[0] = $path;
my $cmd = join(' ',@arguments);
$result = qx( $cmd );
chomp($result);
}
return $result;
}
# Upload message data to ZoneMinder telemetry server
sub sendData {
my $msg = shift;
my $ua = LWP::UserAgent->new;
my $server_endpoint = ZM_TELEMETRY_SERVER_ENDPOINT;
if ( $Config{ZM_UPDATE_CHECK_PROXY} ) {
$ua->proxy( 'https', $Config{ZM_UPDATE_CHECK_PROXY} );
}
Debug("Posting telemetry data to: $server_endpoint");
# set custom HTTP request header fields
my $req = HTTP::Request->new(POST => $server_endpoint);
$req->header('content-type' => 'application/x-www-form-urlencoded');
$req->header('content-length' => length($msg));
$req->header('connection' => 'Close');
$req->content($msg);
my $resp = $ua->request($req);
my $resp_msg = $resp->decoded_content;
my $resp_code = $resp->code;
if ($resp->is_success) {
Info('Telemetry data uploaded successfully.');
Debug("Telemetry server upload success response message: $resp_msg");
} else {
Warning("Telemetry server returned HTTP POST error code: $resp_code");
Debug("Telemetry server upload failure response message: $resp_msg");
}
return $resp->is_success;
}
# Retrieves the UUID from the database. Creates a new UUID if one does not exist.
sub getUUID {
my $dbh = shift;
my $uuid= "";
# Verify the current UUID is valid and not nil
if (( $Config{ZM_TELEMETRY_UUID} =~ /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i ) && ( $Config{ZM_TELEMETRY_UUID} ne '00000000-0000-0000-0000-000000000000' )) {
$uuid = $Config{ZM_TELEMETRY_UUID};
} else {
my $sql = 'SELECT uuid()';
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
$uuid = $Config{ZM_TELEMETRY_UUID} = $sth->fetchrow_array();
$sth->finish();
$sql = q`UPDATE Config set Value = ? WHERE Name = 'ZM_TELEMETRY_UUID'`;
$sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
$res = $sth->execute( "$uuid" ) or die( "Can't execute: ".$sth->errstr() );
$sth->finish();
}
Debug("Using UUID of: $uuid");
return $uuid;
}
# Retrieves the local server's external IP address
sub getIP {
my $ipaddr = '0.0.0.0';
my $ua = LWP::UserAgent->new;
my $server_endpoint = 'https://wiki.zoneminder.com/ip.php';
my $req = HTTP::Request->new(GET => $server_endpoint);
my $resp = $ua->request($req);
if ($resp->is_success) {
$ipaddr = $resp->decoded_content;
}
Debug("Found external ip address of: $ipaddr");
return $ipaddr;
}
# As the name implies, just your average mysql count query
sub countQuery {
my $dbh = shift;
my $table = shift;
my $sql = "SELECT count(*) FROM $table";
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
my $count = $sth->fetchrow_array();
$sth->finish();
return $count
}
# Returns a reference to an array of hashes containing data from all monitors
sub getMonitorRef {
my $dbh = shift;
my $sql = 'SELECT Id,Name,Type,Function,Width,Height,Colours,MaxFPS,AlarmMaxFPS FROM Monitors';
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
my $arrayref = $sth->fetchall_arrayref({});
return $arrayref;
}
sub getDistro {
my $kernel = '';
my $distro = '';
my $version = '';
my @uname = uname();
if ( $uname[0] =~ /Linux/ ) {
Debug('Linux distro detected.');
($kernel, $distro, $version) = linuxDistro();
} elsif ( $uname[0] =~ /.*BSD/ ) {
Debug('BSD distro detected.');
$kernel = $uname[3];
$distro = $uname[0];
$version = $uname[2];
} elsif ( $uname[0] =~ /Darwin/ ) {
Debug('Mac OS distro detected.');
$kernel = $uname[3];
$distro = runSysCmd('sw_vers -productName');
$version = runSysCmd('sw_vers -productVersion');
} elsif ( $uname[0] =~ /SunOS|Solaris/ ) {
Debug('Sun Solaris detected.');
$kernel = $uname[3];
$distro = $uname[1];
$version = $uname[2];
} else {
Warning('ZoneMinder was unable to determine the host system. Please report.');
$kernel = 'Unknown';
$distro = 'Unknown';
$version = 'Unknown';
}
return ($kernel, $distro, $version);
}
sub linuxDistro {
my @uname = uname();
my $kernel = $uname[2];
my $distro = 'Unknown Linux Distro';
my $version = 'Unknown Linux Version';
my $found = 0;
# os-release is the standard for many new distros based on systemd
if ( -f '/etc/os-release' ) {
open(my $RELFILE,'<','/etc/os-release') or die( "Can't Open file: $!\n" );
while (<$RELFILE>) {
if ( /^NAME=(")?(.*)(?(1)\1|).*$/ ) {
$distro = $2;
$found = 1;
}
if ( /^VERSION_ID=(")?(.*)(?(1)\1|).*$/ ) {
$version = $2;
$found = 1;
}
}
close $RELFILE;
# exists on many distros but does not always contain useful information, such as redhat
} elsif ( -f '/etc/lsb-release' ) {
open(my $RELFILE,'<','/etc/lsb-release') or die( "Can't Open file: $!\n" );
while (<$RELFILE>) {
if ( /^DISTRIB_DESCRIPTION=(")?(.*)(?(1)\1|).*$/ ) {
$distro = $2;
$found = 1;
}
if ( /^DISTRIB_RELEASE=(")?(.*)(?(1)\1|).*$/ ) {
$version = $2;
$found = 1;
}
}
close $RELFILE;
}
# If all else fails, search through a list of known release files until we find one
if ( !$found ) {
my @releasefile = ('/etc/SuSE-release', '/etc/redhat-release', '/etc/redhat_version',
'/etc/fedora-release', '/etc/slackware-release', '/etc/slackware-version',
'/etc/debian_release', '/etc/debian_version', '/etc/mandrake-release',
'/etc/yellowdog-release', '/etc/gentoo-release');
foreach (@releasefile) {
if ( -f $_ ) {
open(my $RELFILE,'<',$_) or die( "Can't Open file: $!\n" );
while (<$RELFILE>) {
if ( /(.*).* (\d+\.?\d*) .*/ ) {
$distro = $1;
$version = $2;
$found = 1;
}
}
close $RELFILE;
last;
}
}
}
if ( !$found ) {
Warning('ZoneMinder was unable to determine Linux distro. Please report.');
}
return ($kernel, $distro, $version);
}
1;
__END__
=head1 NAME
zmtelemetry.pl - Send usage information to the ZoneMinder development team
@ -44,300 +342,3 @@ console under Options.
none currently
=cut
use strict;
use bytes;
@EXTRA_PERL_LIB@
use ZoneMinder;
use DBI;
use Getopt::Long;
use autouse 'Pod::Usage'=>qw(pod2usage);
use LWP::UserAgent;
use Sys::MemInfo qw(totalmem);
use Sys::CPU qw(cpu_count);
use POSIX qw(strftime uname);
$ENV{PATH} = '/bin:/usr/bin:/usr/local/bin';
$ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL};
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
use constant CHECK_INTERVAL => (14*24*60*60); # Interval between version checks
# Setting these as contants for now.
# Alternatively, we can put these in the dB and then retrieve using the Config hash.
use constant ZM_TELEMETRY_SERVER_ENDPOINT => 'https://zmanon:2b2d0b4skps@telemetry.zoneminder.com/zmtelemetry/testing5';
if ( $Config{ZM_TELEMETRY_DATA} )
{
print( "Update agent starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
my $lastCheck = $Config{ZM_TELEMETRY_LAST_UPLOAD};
while( 1 ) {
my $now = time();
if ( ($now-$lastCheck) > CHECK_INTERVAL ) {
Info( "Collecting data to send to ZoneMinder Telemetry server." );
my $dbh = zmDbConnect();
# Build the telemetry hash
# We should keep *BSD systems in mind when calling system commands
my %telemetry;
$telemetry{uuid} = getUUID($dbh);
$telemetry{ip} = getIP();
$telemetry{timestamp} = strftime( "%Y-%m-%dT%H:%M:%S%z", localtime() );
$telemetry{monitor_count} = countQuery($dbh,"Monitors");
$telemetry{event_count} = countQuery($dbh,"Events");
$telemetry{architecture} = runSysCmd("uname -p");
($telemetry{kernel}, $telemetry{distro}, $telemetry{version}) = getDistro();
$telemetry{zm_version} = ZoneMinder::Base::ZM_VERSION;
$telemetry{system_memory} = totalmem();
$telemetry{processor_count} = cpu_count();
$telemetry{monitors} = getMonitorRef($dbh);
Info( "Sending data to ZoneMinder Telemetry server." );
my $result = jsonEncode( \%telemetry );
if ( sendData($result) ) {
$lastCheck = $now;
my $sql = "update Config set Value = ? where Name = 'ZM_TELEMETRY_LAST_UPLOAD'";
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( "$lastCheck" ) or die( "Can't execute: ".$sth->errstr() );
$sth->finish();
}
}
sleep( 3600 );
}
print( "Update agent exiting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
}
###############
# SUBROUTINES #
###############
# Find, verify, then run the supplied system command
sub runSysCmd {
my $msg = shift;
my @arguments = split(/ /,$msg);
chomp($arguments[0]);
my $path = qx( which $arguments[0] );
my $status = $? >> 8;
my $result = "";
if ( !$path || $status ) {
Warning( "Cannot find the $arguments[0] executable." );
} else {
chomp($path);
$arguments[0] = $path;
my $cmd = join(" ",@arguments);
$result = qx( $cmd );
chomp($result);
}
return $result;
}
# Upload message data to ZoneMinder telemetry server
sub sendData {
my $msg = shift;
my $ua = LWP::UserAgent->new;
my $server_endpoint = ZM_TELEMETRY_SERVER_ENDPOINT;
if ( $Config{ZM_UPDATE_CHECK_PROXY} ) {
$ua->proxy( "https", $Config{ZM_UPDATE_CHECK_PROXY} );
}
Debug("Posting telemetry data to: $server_endpoint");
# set custom HTTP request header fields
my $req = HTTP::Request->new(POST => $server_endpoint);
$req->header('content-type' => 'application/x-www-form-urlencoded');
$req->header('content-length' => length($msg));
$req->header('connection' => 'Close');
$req->content($msg);
my $resp = $ua->request($req);
my $resp_msg = $resp->decoded_content;
my $resp_code = $resp->code;
if ($resp->is_success) {
Info("Telemetry data uploaded successfully.");
Debug("Telemetry server upload success response message: $resp_msg");
} else {
Warning("Telemetry server returned HTTP POST error code: $resp_code");
Debug("Telemetry server upload failure response message: $resp_msg");
}
return $resp->is_success;
}
# Retrieves the UUID from the database. Creates a new UUID if one does not exist.
sub getUUID {
my $dbh = shift;
my $uuid= "";
# Verify the current UUID is valid and not nil
if (( $Config{ZM_TELEMETRY_UUID} =~ /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i ) && ( $Config{ZM_TELEMETRY_UUID} ne "00000000-0000-0000-0000-000000000000" )) {
$uuid = $Config{ZM_TELEMETRY_UUID};
} else {
my $sql = "SELECT uuid()";
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
$uuid = $Config{ZM_TELEMETRY_UUID} = $sth->fetchrow_array();
$sth->finish();
$sql = "UPDATE Config set Value = ? WHERE Name = 'ZM_TELEMETRY_UUID'";
$sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
$res = $sth->execute( "$uuid" ) or die( "Can't execute: ".$sth->errstr() );
$sth->finish();
}
Debug("Using UUID of: $uuid");
return $uuid;
}
# Retrieves the local server's external IP address
sub getIP {
my $ipaddr = "0.0.0.0";
my $ua = LWP::UserAgent->new;
my $server_endpoint = "https://wiki.zoneminder.com/ip.php";
my $req = HTTP::Request->new(GET => $server_endpoint);
my $resp = $ua->request($req);
if ($resp->is_success) {
$ipaddr = $resp->decoded_content;
}
Debug("Found external ip address of: $ipaddr");
return $ipaddr;
}
# As the name implies, just your average mysql count query
sub countQuery {
my $dbh = shift;
my $table = shift;
my $sql = "SELECT count(*) FROM $table";
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
my $count = $sth->fetchrow_array();
$sth->finish();
return $count
}
# Returns a reference to an array of hashes containing data from all monitors
sub getMonitorRef {
my $dbh = shift;
my $sql = "SELECT Id,Name,Type,Function,Width,Height,Colours,MaxFPS,AlarmMaxFPS FROM Monitors";
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
my $arrayref = $sth->fetchall_arrayref({});
return $arrayref;
}
sub getDistro {
my $kernel = "";
my $distro = "";
my $version = "";
my @uname = uname();
if ( $uname[0] =~ /Linux/ ) {
Debug("Linux distro detected.");
($kernel, $distro, $version) = linuxDistro();
} elsif ( $uname[0] =~ /.*BSD/ ) {
Debug("BSD distro detected.");
$kernel = $uname[3];
$distro = $uname[0];
$version = $uname[2];
} elsif ( $uname[0] =~ /Darwin/ ) {
Debug("Mac OS distro detected.");
$kernel = $uname[3];
$distro = runSysCmd("sw_vers -productName");
$version = runSysCmd("sw_vers -productVersion");
} elsif ( $uname[0] =~ /SunOS|Solaris/ ) {
Debug("Sun Solaris detected.");
$kernel = $uname[3];
$distro = $uname[1];
$version = $uname[2];
} else {
Warning("ZoneMinder was unable to determine the host system. Please report.");
$kernel = "Unknown";
$distro = "Unknown";
$version = "Unknown";
}
return ($kernel, $distro, $version);
}
sub linuxDistro {
my @uname = uname();
my $kernel = $uname[2];
my $distro = "Unknown Linux Distro";
my $version = "Unknown Linux Version";
my $found = 0;
# os-release is the standard for many new distros based on systemd
if ( -f "/etc/os-release" ) {
open(my $RELFILE,"<","/etc/os-release") or die( "Can't Open file: $!\n" );
while (<$RELFILE>) {
if ( /^NAME=(")?(.*)(?(1)\1|).*$/ ) {
$distro = $2;
$found = 1;
}
if ( /^VERSION_ID=(")?(.*)(?(1)\1|).*$/ ) {
$version = $2;
$found = 1;
}
}
close $RELFILE;
# exists on many distros but does not always contain useful information, such as redhat
} elsif ( -f "/etc/lsb-release" ) {
open(my $RELFILE,"<","/etc/lsb-release") or die( "Can't Open file: $!\n" );
while (<$RELFILE>) {
if ( /^DISTRIB_DESCRIPTION=(")?(.*)(?(1)\1|).*$/ ) {
$distro = $2;
$found = 1;
}
if ( /^DISTRIB_RELEASE=(")?(.*)(?(1)\1|).*$/ ) {
$version = $2;
$found = 1;
}
}
close $RELFILE;
}
# If all else fails, search through a list of known release files until we find one
if ( !$found ) {
my @releasefile = ("/etc/SuSE-release", "/etc/redhat-release", "/etc/redhat_version",
"/etc/fedora-release", "/etc/slackware-release", "/etc/slackware-version",
"/etc/debian_release", "/etc/debian_version", "/etc/mandrake-release",
"/etc/yellowdog-release", "/etc/gentoo-release");
foreach (@releasefile) {
if ( -f $_ ) {
open(my $RELFILE,"<",$_) or die( "Can't Open file: $!\n" );
while (<$RELFILE>) {
if ( /(.*).* (\d+\.?\d*) .*/ ) {
$distro = $1;
$version = $2;
$found = 1;
}
}
close $RELFILE;
last;
}
}
}
if ( !$found ) {
Warning("ZoneMinder was unable to determine Linux distro. Please report.");
}
return ($kernel, $distro, $version);
}

View File

@ -311,6 +311,7 @@ if ( $migrateEvents ) {
}
if ( $freshen ) {
print( "\nFreshening configuration in database\n" );
migratePaths();
ZoneMinder::Config::loadConfigFromDB();
ZoneMinder::Config::saveConfigToDB();
}
@ -458,6 +459,7 @@ if ( $version ) {
print( "\nUpgrading database to version ".ZM_VERSION."\n" );
# Update config first of all
migratePaths();
ZoneMinder::Config::loadConfigFromDB();
ZoneMinder::Config::saveConfigToDB();
@ -969,3 +971,61 @@ if ( $version ) {
}
zmDbDisconnect();
exit( 0 );
sub migratePaths {
my $customConfigFile = "@ZM_CONFIG_SUBDIR@/zmcustom.conf";
if ( (! -e $customConfigFile ) && ( ZM_VERSION ge '1.31.0' ) && ($Config{ZM_DYN_DB_VERSION} lt '1.31.1') ) {
my %customConfig;
# Check the traditional default values for the variables previsouly found under Options -> Paths
if ( $Config{ZM_DIR_EVENTS} ne "events" ) {
$customConfig{ZM_DIR_EVENTS} = $Config{ZM_DIR_EVENTS};
}
if ( $Config{ZM_DIR_IMAGES} ne "images" ) {
$customConfig{ZM_DIR_IMAGES} = $Config{ZM_DIR_IMAGES};
}
if ( $Config{ZM_DIR_SOUNDS} ne "sounds" ) {
$customConfig{ZM_DIR_SOUNDS} = $Config{ZM_DIR_SOUNDS};
}
if ( $Config{ZM_PATH_ZMS} ne "@ZM_PATH_ZMS@" ) {
$customConfig{ZM_PATH_ZMS} = $Config{ZM_PATH_ZMS};
}
if ( $Config{ZM_PATH_MAP} ne "/dev/shm" ) {
$customConfig{ZM_PATH_MAP} = $Config{ZM_PATH_MAP};
}
if ( $Config{ZM_PATH_SOCKS} ne "@ZM_SOCKDIR@" ) {
$customConfig{ZM_PATH_SOCKS} = $Config{ZM_PATH_SOCKS};
}
if ( $Config{ZM_PATH_LOGS} ne "@ZM_LOGDIR@" ) {
$customConfig{ZM_PATH_LOGS} = $Config{ZM_PATH_LOGS};
}
if ( $Config{ZM_PATH_SWAP} ne "@ZM_TMPDIR@" ) {
$customConfig{ZM_PATH_SWAP} = $Config{ZM_PATH_SWAP};
}
if ( $Config{ZM_PATH_ARP} ne "" ) {
$customConfig{ZM_PATH_ARP} = $Config{ZM_PATH_ARP};
}
# If any variables differ from their expected default value,
# save them to a config file before they get purged from the database
if ( %customConfig ) {
print("\nMigrating custom config values from Options -> Paths\nto $customConfigFile.\n");
print("\nPlease verify these values before starting ZoneMinder.\n\n");
open(my $fh, '>', $customConfigFile) or die "Could open $customConfigFile for writing: $!.";
print $fh "# These values were autogenerated by zmupdate.pl\n";
print $fh "# You may edit these values. ZoneMinder will not overwrite them.\n";
print $fh "#\n\n";
while (my ($key, $value) = each %customConfig) {
print $fh "$key=$value\n";
}
close $fh;
my $gid = getgrnam("@ZM_WEB_GROUP@");
chown -1, $gid, $customConfigFile;
chmod 0640, $customConfigFile;
}
}
}

View File

@ -94,20 +94,11 @@ my $size = '';
my $overwrite = 0;
my $version = 0;
my @formats = split( /\s+/, $Config{ZM_FFMPEG_FORMATS} );
for ( my $i = 0; $i < @formats; $i++ )
{
if ( $i =~ /^(.+)\*$/ )
{
$format = $formats[$i] = $1;
}
}
GetOptions(
'concat|c:s' =>\$concat_name,
'concat|c:s' =>\$concat_name,
'event|e=i' =>\$event_id,
'filter_name=s' =>\$filter_name,
'filter_id=i' =>\$filter_id,
'filter_id=i' =>\$filter_id,
'format|f=s' =>\$format,
'rate|r=f' =>\$rate,
'scale|s=f' =>\$scale,
@ -115,51 +106,51 @@ GetOptions(
'size|S=s' =>\$size,
'overwrite' =>\$overwrite,
'version' =>\$version
) or pod2usage(-exitstatus => -1);
) or pod2usage(-exitstatus => -1);
if ( $version ) {
print ZoneMinder::Base::ZM_VERSION . "\n";
exit(0);
print ZoneMinder::Base::ZM_VERSION . "\n";
exit(0);
}
if ( !( $filter_id or $filter_name or $event_id ) || $event_id < 0 )
{
print( STDERR "Please give a valid event id or filter name\n" );
pod2usage(-exitstatus => -1);
if ( !( $filter_id or $filter_name or $event_id ) || ($event_id and ( $event_id < 0 ) ) ) {
print( STDERR "Please give a valid event id or filter name\n" );
pod2usage(-exitstatus => -1);
}
if ( ! $Config{ZM_OPT_FFMPEG} )
{
print( STDERR "Mpeg encoding is not currently enabled\n" );
exit(-1);
if ( ! $Config{ZM_OPT_FFMPEG} ) {
print( STDERR "Mpeg encoding is not currently enabled\n" );
exit(-1);
}
if ( !$rate && !$fps )
{
$rate = 1;
my @formats = split( /\s+/, $Config{ZM_FFMPEG_FORMATS} );
for ( my $i = 0; $i < @formats; $i++ ) {
if ( $i =~ /^(.+)\*$/ ) {
$format = $formats[$i] = $1;
}
}
if ( !$scale && !$size )
{
$scale = 1;
if ( !$rate && !$fps ) {
$rate = 1;
}
if ( $rate && ($rate < 0.25 || $rate > 100) )
{
print( STDERR "Rate is out of range, 0.25 >= rate <= 100\n" );
pod2usage(-exitstatus => -1);
if ( !$scale && !$size ) {
$scale = 1;
}
if ( $scale && ($scale < 0.25 || $scale > 4) )
{
print( STDERR "Scale is out of range, 0.25 >= scale <= 4\n" );
pod2usage(-exitstatus => -1);
if ( $rate && ($rate < 0.25 || $rate > 100) ) {
print( STDERR "Rate is out of range, 0.25 >= rate <= 100\n" );
pod2usage(-exitstatus => -1);
}
if ( $fps && ($fps > 30) )
{
print( STDERR "FPS is out of range, <= 30\n" );
pod2usage(-exitstatus => -1);
if ( $scale && ($scale < 0.25 || $scale > 4) ) {
print( STDERR "Scale is out of range, 0.25 >= scale <= 4\n" );
pod2usage(-exitstatus => -1);
}
if ( $fps && ($fps > 30) ) {
print( STDERR "FPS is out of range, <= 30\n" );
pod2usage(-exitstatus => -1);
}
my ( $detaint_format ) = $format =~ /^(\w+)$/;
@ -181,19 +172,25 @@ my $cwd = getcwd;
my $video_name;
my @event_ids;
if ( $event_id ) {
@event_ids = ( $event_id );
@event_ids = ( $event_id );
} elsif ( $filter_name or $filter_id ) {
my $Filter = ZoneMinder::Filter->find_one(
($filter_name ? ( Name => $filter_name ) : () ),
($filter_id ? ( Id => $filter_name ) : () ),
);
if ( ! $Filter ) {
Fatal("Filter $filter_name $filter_id not found.");
}
@event_ids = map { $_->{Id} }$Filter->Execute();
Fatal( "No events found for $filter_name") if ! @event_ids;
$concat_name = $filter_name if $concat_name eq '';
my $Filter = ZoneMinder::Filter->find_one(
($filter_name ? ( Name => $filter_name ) : () ),
($filter_id ? ( Id => $filter_name ) : () ),
);
if ( ! $Filter ) {
Fatal("Filter $filter_name $filter_id not found.");
}
@event_ids = map { $_->{Id} } $Filter->Execute();
if ( ! @event_ids ) {
Fatal( "No events found for $filter_name")
} else {
Debug(@event_ids . " events found for $filter_name");
}
$concat_name = $filter_name if $concat_name eq '';
} else {
Warning("Nothing to do");
}
my $sql = " SELECT max(F.Delta)-min(F.Delta) as FullLength,
@ -207,53 +204,54 @@ my $sql = " SELECT max(F.Delta)-min(F.Delta) as FullLength,
INNER JOIN Events as E on F.EventId = E.Id
INNER JOIN Monitors as M on E.MonitorId = M.Id
WHERE EventId = ?
GROUP BY F.EventId"
;
GROUP BY F.EventId";
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
my @video_files;
foreach my $event_id ( @event_ids ) {
my $res = $sth->execute( $event_id )
or Fatal( "Can't execute: ".$sth->errstr() );
my $event = $sth->fetchrow_hashref();
my $res = $sth->execute( $event_id )
or Fatal( "Can't execute: ".$sth->errstr() );
my $event = $sth->fetchrow_hashref();
my $Event = new ZoneMinder::Event( $$event{Id}, $event );
my $video_file = $Event->GenerateVideo( $rate, $fps, $scale, $size, $overwrite, $format );
if ( $video_file ) {
push @video_files, $video_file;
print( STDOUT $video_file."\n" );
}
my $Event = new ZoneMinder::Event( $$event{Id}, $event );
my $video_file = $Event->GenerateVideo( $rate, $fps, $scale, $size, $overwrite, $format );
if ( $video_file ) {
push @video_files, $video_file;
print( STDOUT $video_file."\n" );
} else {
Warning("No video file generated for event $event_id");
}
} # end foreach event_id
if ( $concat_name ) {
($cwd) = $cwd =~ /(.*)/; # detaint
chdir( $cwd );
($concat_name ) = $concat_name =~ /([\-A-Za-z0-9_\.]*)/;
my $concat_list_file = "/tmp/$concat_name.concat.lst";
($cwd) = $cwd =~ /(.*)/; # detaint
chdir( $cwd );
($concat_name ) = $concat_name =~ /([\-A-Za-z0-9_\.]*)/;
my $concat_list_file = "/tmp/$concat_name.concat.lst";
my $video_file = $concat_name . '.'. $detaint_format;
my $video_file = $concat_name . '.'. $detaint_format;
open( my $fd, '>', $concat_list_file ) or die "Can't open $concat_list_file: $!";
foreach ( @video_files ) {
print $fd "file '$_'\n";
}
close $fd;
my $command = $Config{ZM_PATH_FFMPEG}
. " -f concat -i $concat_list_file -c copy "
." '$video_file' > ffmpeg.log 2>&1"
;
Debug( $command."\n" );
my $output = qx($command);
open( my $fd, '>', $concat_list_file ) or die "Can't open $concat_list_file: $!";
foreach ( @video_files ) {
print $fd "file '$_'\n";
}
close $fd;
my $command = $Config{ZM_PATH_FFMPEG}
. " -f concat -i $concat_list_file -c copy "
." '$video_file' > ffmpeg.log 2>&1"
;
Debug( $command."\n" );
my $output = qx($command);
my $status = $? >> 8;
my $status = $? >> 8;
unlink $concat_list_file;
if ( $status )
{
Error( "Unable to generate video, check /ffmpeg.log for details");
exit(-1);
}
print( STDOUT $video_file."\n" );
unlink $concat_list_file;
if ( $status ) {
Error( "Unable to generate video, check /ffmpeg.log for details");
exit(-1);
}
print( STDOUT $video_file."\n" );
}
exit( 0 );
__END__

View File

@ -1,9 +1,9 @@
snprintf( swap_path, sizeof(swap_path), "%s/zmswap-m%d/zmswap-q%06d", config.path_swap, monitor->Id(), connkey );
snprintf( swap_path, sizeof(swap_path), "%s/zmswap-m%d/zmswap-q%06d", staticConfig.PATH_SWAP.c_str(), monitor->Id(), connkey );
int len = snprintf(NULL, 0, "/zmswap-m%d", monitor->Id());
int swap_path_length = strlen(config.path_swap) + snprintf(NULL, 0, "/zmswap-m%d", monitor->Id() ) + snprintf(NULL, 0, "/zmswap-q%06d", connkey ) + 1; // +1 for NULL terminator
int swap_path_length = strlen(staticConfig.PATH_SWAP.c_str()) + snprintf(NULL, 0, "/zmswap-m%d", monitor->Id() ) + snprintf(NULL, 0, "/zmswap-q%06d", connkey ) + 1; // +1 for NULL terminator
if ( connkey && playback_buffer > 0 ) {
@ -11,8 +11,8 @@ int len = snprintf(NULL, 0, "/zmswap-m%d", monitor->Id());
Error( "Swap Path is too long. %d > %d ", swap_path_length+max_swap_len_suffix, PATH_MAX );
} else {
swap_path = (char *)malloc( swap_path_length+max_swap_len_suffix );
Debug( 3, "Checking swap image path %s", config.path_swap );
strncpy( swap_path, config.path_swap, swap_path_length );
Debug( 3, "Checking swap image path %s", staticConfig.PATH_SWAP.c_str() );
strncpy( swap_path, staticConfig.PATH_SWAP.c_str(), swap_path_length );
if ( checkSwapPath( swap_path, false ) ) {
snprintf( &(swap_path[swap_path_length]), max_swap_len_suffix, "/zmswap-m%d", monitor->Id() );
if ( checkSwapPath( swap_path, true ) ) {

View File

@ -30,9 +30,9 @@
#include <set>
#include <vector>
#include <sys/uio.h>
#if defined(BSD)
#include <sys/uio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#endif

View File

@ -158,6 +158,26 @@ void process_configfile( char* configFile) {
staticConfig.SERVER_NAME = std::string(val_ptr);
else if ( strcasecmp( name_ptr, "ZM_SERVER_ID" ) == 0 )
staticConfig.SERVER_ID = atoi(val_ptr);
else if ( strcasecmp( name_ptr, "ZM_DIR_EVENTS" ) == 0 )
staticConfig.DIR_EVENTS = std::string(val_ptr);
else if ( strcasecmp( name_ptr, "ZM_DIR_IMAGES" ) == 0 )
staticConfig.DIR_IMAGES = std::string(val_ptr);
else if ( strcasecmp( name_ptr, "ZM_DIR_SOUNDS" ) == 0 )
staticConfig.DIR_SOUNDS = std::string(val_ptr);
else if ( strcasecmp( name_ptr, "ZM_DIR_EXPORTS" ) == 0 )
staticConfig.DIR_EXPORTS = std::string(val_ptr);
else if ( strcasecmp( name_ptr, "ZM_PATH_ZMS" ) == 0 )
staticConfig.PATH_ZMS = std::string(val_ptr);
else if ( strcasecmp( name_ptr, "ZM_PATH_MAP" ) == 0 )
staticConfig.PATH_MAP = std::string(val_ptr);
else if ( strcasecmp( name_ptr, "ZM_PATH_SOCKS" ) == 0 )
staticConfig.PATH_SOCKS = std::string(val_ptr);
else if ( strcasecmp( name_ptr, "ZM_PATH_LOGS" ) == 0 )
staticConfig.PATH_LOGS = std::string(val_ptr);
else if ( strcasecmp( name_ptr, "ZM_PATH_SWAP" ) == 0 )
staticConfig.PATH_SWAP = std::string(val_ptr);
else if ( strcasecmp( name_ptr, "ZM_PATH_ARP" ) == 0 )
staticConfig.PATH_ARP = std::string(val_ptr);
else {
// We ignore this now as there may be more parameters than the
// c/c++ binaries are bothered about

View File

@ -70,6 +70,16 @@ struct StaticConfig
std::string PATH_WEB;
std::string SERVER_NAME;
unsigned int SERVER_ID;
std::string DIR_EVENTS;
std::string DIR_IMAGES;
std::string DIR_SOUNDS;
std::string DIR_EXPORTS;
std::string PATH_ZMS;
std::string PATH_MAP;
std::string PATH_SOCKS;
std::string PATH_LOGS;
std::string PATH_SWAP;
std::string PATH_ARP;
};
extern StaticConfig staticConfig;

View File

@ -77,10 +77,14 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
gettimeofday( &start_time, 0 );
}
static char sql[ZM_SQL_MED_BUFSIZ];
unsigned int state_id = 0;
if ( MYSQL_ROW dbrow = zmDbFetchOne( "SELECT Id FROM States WHERE IsActive=1" ) ) {
state_id = atoi(dbrow[0]);
}
static char sql[ZM_SQL_MED_BUFSIZ];
struct tm *stime = localtime( &start_time.tv_sec );
snprintf( sql, sizeof(sql), "insert into Events ( MonitorId, Name, StartTime, Width, Height, Cause, Notes, Videoed ) values ( %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', '%d' )", monitor->Id(), start_time.tv_sec, monitor->Width(), monitor->Height(), cause.c_str(), notes.c_str(), videoEvent );
snprintf( sql, sizeof(sql), "insert into Events ( MonitorId, Name, StartTime, Width, Height, Cause, Notes, StateId, Videoed ) values ( %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', '%d', '%d' )", monitor->Id(), start_time.tv_sec, monitor->Width(), monitor->Height(), cause.c_str(), notes.c_str(), state_id, videoEvent );
if ( mysql_query( &dbconn, sql ) ) {
Error( "Can't insert event: %s. sql was (%s)", mysql_error( &dbconn ), sql );
exit( mysql_errno( &dbconn ) );
@ -100,7 +104,7 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
if ( config.use_deep_storage ) {
char *path_ptr = path;
path_ptr += snprintf( path_ptr, sizeof(path), "%s/%d", config.dir_events, monitor->Id() );
path_ptr += snprintf( path_ptr, sizeof(path), "%s/%d", staticConfig.DIR_EVENTS.c_str(), monitor->Id() );
int dt_parts[6];
dt_parts[0] = stime->tm_year-100;
@ -136,7 +140,7 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
if ( symlink( time_path, id_file ) < 0 )
Fatal( "Can't symlink %s -> %s: %s", id_file, path, strerror(errno));
} else {
snprintf( path, sizeof(path), "%s/%d/%d", config.dir_events, monitor->Id(), id );
snprintf( path, sizeof(path), "%s/%d/%d", staticConfig.DIR_EVENTS.c_str(), monitor->Id(), id );
errno = 0;
stat( path, &statbuf );
@ -550,7 +554,7 @@ void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image *
if ( config.record_diag_images ) {
char diag_glob[PATH_MAX] = "";
snprintf( diag_glob, sizeof(diag_glob), "%s/%d/diag-*.jpg", config.dir_events, monitor->Id() );
snprintf( diag_glob, sizeof(diag_glob), "%s/%d/diag-*.jpg", staticConfig.DIR_EVENTS.c_str(), monitor->Id() );
glob_t pglob;
int glob_status = glob( diag_glob, 0, 0, &pglob );
if ( glob_status != 0 ) {
@ -674,15 +678,15 @@ bool EventStream::loadEventData( int event_id ) {
event_data->start_time = atoi(dbrow[2]);
if ( config.use_deep_storage ) {
struct tm *event_time = localtime( &event_data->start_time );
if ( config.dir_events[0] == '/' )
snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d", config.dir_events, event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec );
if ( staticConfig.DIR_EVENTS.c_str()[0] == '/' )
snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d", staticConfig.DIR_EVENTS.c_str(), event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec );
else
snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d", staticConfig.PATH_WEB.c_str(), config.dir_events, event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec );
snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d", staticConfig.PATH_WEB.c_str(), staticConfig.DIR_EVENTS.c_str(), event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec );
} else {
if ( config.dir_events[0] == '/' )
snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%ld", config.dir_events, event_data->monitor_id, event_data->event_id );
if ( staticConfig.DIR_EVENTS.c_str()[0] == '/' )
snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%ld", staticConfig.DIR_EVENTS.c_str(), event_data->monitor_id, event_data->event_id );
else
snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%ld", staticConfig.PATH_WEB.c_str(), config.dir_events, event_data->monitor_id, event_data->event_id );
snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%ld", staticConfig.PATH_WEB.c_str(), staticConfig.DIR_EVENTS.c_str(), event_data->monitor_id, event_data->event_id );
}
event_data->frame_count = dbrow[1] == NULL ? 0 : atoi(dbrow[1]);
event_data->duration = atof(dbrow[3]);

View File

@ -413,6 +413,27 @@ static void zm_log_fps(double d, const char *postfix) {
Debug(1, "%1.0fk %s", d / 1000, postfix);
}
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
void zm_dump_codecpar ( const AVCodecParameters *par ) {
Debug(1, "Dumping codecpar codec_type(%d) codec_id(%d) codec_tag(%d) width(%d) height(%d)",
par->codec_type,
par->codec_id,
par->codec_tag,
par->width,
par->height
);
}
#endif
void zm_dump_codec ( const AVCodecContext *codec ) {
Debug(1, "Dumping codecpar codec_type(%d) codec_id(%d) width(%d) height(%d)",
codec->codec_type,
codec->codec_id,
codec->width,
codec->height
);
}
/* "user interface" functions */
void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output) {
char buf[256];

View File

@ -323,6 +323,11 @@ static av_always_inline av_const int64_t av_clip64_c(int64_t a, int64_t amin, in
#endif
void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output);
void zm_dump_codec ( const AVCodecContext *codec );
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
void zm_dump_codecpar ( const AVCodecParameters *par );
#endif
#if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100)
#define zm_av_packet_unref( packet ) av_packet_unref( packet )
#define zm_av_packet_ref( dst, src ) av_packet_ref( dst, src )

View File

@ -146,9 +146,10 @@ int FfmpegCamera::Capture( Image &image ) {
int frameComplete = false;
while ( !frameComplete ) {
int ret;
int avResult = av_read_frame( mFormatContext, &packet );
char errbuf[AV_ERROR_MAX_STRING_SIZE];
if ( avResult < 0 ) {
char errbuf[AV_ERROR_MAX_STRING_SIZE];
av_strerror(avResult, errbuf, AV_ERROR_MAX_STRING_SIZE);
if (
// Check if EOF.
@ -166,9 +167,31 @@ int FfmpegCamera::Capture( Image &image ) {
Debug( 5, "Got packet from stream %d dts (%d) pts(%d)", packet.stream_index, packet.pts, packet.dts );
// What about audio stream? Maybe someday we could do sound detection...
if ( packet.stream_index == mVideoStreamId ) {
int ret = zm_avcodec_decode_video( mVideoCodecContext, mRawFrame, &frameComplete, &packet );
if ( ret < 0 )
Fatal( "Unable to decode frame at frame %d", frameCount );
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
ret = avcodec_send_packet( mVideoCodecContext, &packet );
if ( ret < 0 ) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf );
zm_av_packet_unref( &packet );
continue;
}
ret = avcodec_receive_frame( mVideoCodecContext, mRawFrame );
if ( ret < 0 ) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf );
zm_av_packet_unref( &packet );
continue;
}
frameComplete = 1;
# else
ret = zm_avcodec_decode_video( mVideoCodecContext, mRawFrame, &frameComplete, &packet );
if ( ret < 0 ) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
Error( "Unable to decode frame at frame %d: %s, continuing", frameCount, errbuf );
zm_av_packet_unref( &packet );
continue;
}
#endif
Debug( 4, "Decoded video packet at frame %d", frameCount );
@ -304,10 +327,14 @@ int FfmpegCamera::OpenFfmpeg() {
mVideoStreamId = -1;
mAudioStreamId = -1;
for (unsigned int i=0; i < mFormatContext->nb_streams; i++ ) {
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
if ( mFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ) {
#else
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) {
#else
if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO ) {
#endif
#endif
if ( mVideoStreamId == -1 ) {
mVideoStreamId = i;
@ -317,10 +344,14 @@ int FfmpegCamera::OpenFfmpeg() {
Debug(2, "Have another video stream." );
}
}
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
if ( mFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO ) {
#else
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO ) {
#else
if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO ) {
#endif
#endif
if ( mAudioStreamId == -1 ) {
mAudioStreamId = i;
@ -337,7 +368,12 @@ int FfmpegCamera::OpenFfmpeg() {
Debug ( 3, "Found video stream at index %d", mVideoStreamId );
Debug ( 3, "Found audio stream at index %d", mAudioStreamId );
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
mVideoCodecContext = avcodec_alloc_context3( NULL );
avcodec_parameters_to_context( mVideoCodecContext, mFormatContext->streams[mVideoStreamId]->codecpar );
#else
mVideoCodecContext = mFormatContext->streams[mVideoStreamId]->codec;
#endif
// STolen from ispy
//this fixes issues with rtsp streams!! woot.
//mVideoCodecContext->flags2 |= CODEC_FLAG2_FAST | CODEC_FLAG2_CHUNKS | CODEC_FLAG_LOW_DELAY; // Enable faster H264 decode.
@ -361,7 +397,12 @@ int FfmpegCamera::OpenFfmpeg() {
}
if ( mAudioStreamId >= 0 ) {
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
mAudioCodecContext = avcodec_alloc_context3( NULL );
avcodec_parameters_to_context( mAudioCodecContext, mFormatContext->streams[mAudioStreamId]->codecpar );
#else
mAudioCodecContext = mFormatContext->streams[mAudioStreamId]->codec;
#endif
if ((mAudioCodec = avcodec_find_decoder(mAudioCodecContext->codec_id)) == NULL) {
Debug(1, "Can't find codec for audio stream from %s", mPath.c_str());
} else {
@ -576,29 +617,33 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
//Video recording
if ( recording.tv_sec ) {
// The directory we are recording to is no longer tied to the current event.
// Need to re-init the videostore with the correct directory and start recording again
// for efficiency's sake, we should test for keyframe before we test for directory change...
if ( videoStore && key_frame && (strcmp(oldDirectory, event_file) != 0 ) ) {
// don't open new videostore until we're on a key frame..would this require an offset adjustment for the event as a result?...
// if we store our key frame location with the event will that be enough?
Info("Re-starting video storage module");
// I don't know if this is important or not... but I figure we might as well write this last packet out to the store before closing it.
// Also don't know how much it matters for audio.
if ( packet.stream_index == mVideoStreamId ) {
//Write the packet to our video store
int ret = videoStore->writeVideoFramePacket( &packet );
if ( ret < 0 ) { //Less than zero and we skipped a frame
Warning("Error writing last packet to videostore.");
}
} // end if video
uint32_t last_event_id = monitor->GetLastEventId() ;
delete videoStore;
videoStore = NULL;
if ( last_event_id != monitor->GetVideoWriterEventId() ) {
Debug(2, "Have change of event. last_event(%d), our current (%d)", last_event_id, monitor->GetVideoWriterEventId() );
if ( videoStore ) {
Info("Re-starting video storage module");
// I don't know if this is important or not... but I figure we might as well write this last packet out to the store before closing it.
// Also don't know how much it matters for audio.
if ( packet.stream_index == mVideoStreamId ) {
//Write the packet to our video store
int ret = videoStore->writeVideoFramePacket( &packet );
if ( ret < 0 ) { //Less than zero and we skipped a frame
Warning("Error writing last packet to videostore.");
}
} // end if video
delete videoStore;
videoStore = NULL;
monitor->SetVideoWriterEventId( 0 );
} // end if videoStore
} // end if end of recording
if ( ( ! videoStore ) && key_frame && ( packet.stream_index == mVideoStreamId ) ) {
if ( last_event_id and ! videoStore ) {
//Instantiate the video storage module
if (record_audio) {
@ -627,6 +672,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
this->getMonitor());
} // end if record_audio
strcpy(oldDirectory, event_file);
monitor->SetVideoWriterEventId( last_event_id );
// Need to write out all the frames from the last keyframe?
// No... need to write out all frames from when the event began. Due to PreEventFrames, this could be more than since the last keyframe.
@ -664,6 +710,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
Info("Deleting videoStore instance");
delete videoStore;
videoStore = NULL;
monitor->SetVideoWriterEventId( 0 );
}
// Buffer video packets, since we are not recording.
@ -708,7 +755,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) {
}
Debug(4, "about to decode video" );
#if LIBAVCODEC_VERSION_CHECK(58, 0, 0, 0, 0)
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
ret = avcodec_send_packet( mVideoCodecContext, &packet );
if ( ret < 0 ) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
@ -719,7 +766,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) {
ret = avcodec_receive_frame( mVideoCodecContext, mRawFrame );
if ( ret < 0 ) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf );
Debug( 1, "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf );
zm_av_packet_unref( &packet );
continue;
}

View File

@ -32,8 +32,8 @@
#include <stdlib.h>
#include <limits.h>
/* Workaround for GNU/kFreeBSD */
#if defined(__FreeBSD_kernel__)
/* Workaround for GNU/kFreeBSD and FreeBSD */
#if defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
#ifndef ENODATA
#define ENODATA ENOATTR
#endif

View File

@ -70,7 +70,7 @@ Logger::Logger() :
mFileLevel( NOLOG ),
mSyslogLevel( NOLOG ),
mEffectiveLevel( NOLOG ),
//mLogPath( config.path_logs ),
//mLogPath( staticConfig.PATH_LOGS.c_str() ),
//mLogFile( mLogPath+"/"+mId+".log" ),
mDbConnected( false ),
mLogFileFP( NULL ),
@ -195,7 +195,7 @@ void Logger::initialise( const std::string &id, const Options &options ) {
level( tempLevel );
mFlush = false;
if (envPtr = getenv( "LOG_FLUSH")) {
if ( (envPtr = getenv("LOG_FLUSH")) ) {
mFlush = atoi( envPtr );
} else if ( config.log_debug ) {
mFlush = true;
@ -422,7 +422,7 @@ void Logger::logFile( const std::string &logFile ) {
}
void Logger::openFile() {
if ( mLogFile.size() && (mLogFileFP = fopen( mLogFile.c_str() ,"w" )) == (FILE *)NULL ) {
if ( mLogFile.size() && (mLogFileFP = fopen( mLogFile.c_str() ,"a" )) == (FILE *)NULL ) {
mFileLevel = NOLOG;
Fatal( "fopen() for %s, error = %s", mLogFile.c_str(), strerror(errno) );
}
@ -577,7 +577,7 @@ void logInit( const char *name, const Logger::Options &options ) {
if ( !Logger::smInstance )
Logger::smInstance = new Logger();
Logger::Options tempOptions = options;
tempOptions.mLogPath = config.path_logs;
tempOptions.mLogPath = staticConfig.PATH_LOGS.c_str();
Logger::smInstance->initialise( name, tempOptions );
}

View File

@ -80,7 +80,7 @@ Monitor::MonitorLink::MonitorLink( int p_id, const char *p_name ) : id( p_id ) {
#if ZM_MEM_MAPPED
map_fd = -1;
snprintf( mem_file, sizeof(mem_file), "%s/zm.mmap.%d", config.path_map, id );
snprintf( mem_file, sizeof(mem_file), "%s/zm.mmap.%d", staticConfig.PATH_MAP.c_str(), id );
#else // ZM_MEM_MAPPED
shm_id = 0;
#endif // ZM_MEM_MAPPED
@ -450,7 +450,7 @@ Monitor::Monitor(
if ( purpose == ANALYSIS ) {
static char path[PATH_MAX];
strncpy( path, config.dir_events, sizeof(path) );
strncpy( path, staticConfig.DIR_EVENTS.c_str(), sizeof(path) );
struct stat statbuf;
errno = 0;
@ -461,7 +461,7 @@ Monitor::Monitor(
}
}
snprintf( path, sizeof(path), "%s/%d", config.dir_events, id );
snprintf( path, sizeof(path), "%s/%d", staticConfig.DIR_EVENTS.c_str(), id );
errno = 0;
stat( path, &statbuf );
@ -471,8 +471,8 @@ Monitor::Monitor(
}
char temp_path[PATH_MAX];
snprintf( temp_path, sizeof(temp_path), "%d", id );
if ( chdir( config.dir_events ) < 0 )
Fatal( "Can't change directory to '%s': %s", config.dir_events, strerror(errno) );
if ( chdir( staticConfig.DIR_EVENTS.c_str() ) < 0 )
Fatal( "Can't change directory to '%s': %s", staticConfig.DIR_EVENTS.c_str(), strerror(errno) );
if ( symlink( temp_path, name ) < 0 )
Fatal( "Can't symlink '%s' to '%s': %s", temp_path, name, strerror(errno) );
if ( chdir( ".." ) < 0 )
@ -497,7 +497,7 @@ Monitor::Monitor(
bool Monitor::connect() {
#if ZM_MEM_MAPPED
snprintf( mem_file, sizeof(mem_file), "%s/zm.mmap.%d", config.path_map, id );
snprintf( mem_file, sizeof(mem_file), "%s/zm.mmap.%d", staticConfig.PATH_MAP.c_str(), id );
map_fd = open( mem_file, O_RDWR|O_CREAT, (mode_t)0600 );
if ( map_fd < 0 )
Fatal( "Can't open memory map file %s, probably not enough space free: %s", mem_file, strerror(errno) );
@ -646,7 +646,7 @@ Monitor::~Monitor() {
if ( purpose == CAPTURE ) {
char mmap_path[PATH_MAX] = "";
snprintf( mmap_path, sizeof(mmap_path), "%s/zm.mmap.%d", config.path_map, id );
snprintf( mmap_path, sizeof(mmap_path), "%s/zm.mmap.%d", staticConfig.PATH_MAP.c_str(), id );
if ( unlink( mmap_path ) < 0 ) {
Warning( "Can't unlink '%s': %s", mmap_path, strerror(errno) );
@ -2991,7 +2991,7 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z
if ( config.record_diag_images ) {
static char diag_path[PATH_MAX] = "";
if ( !diag_path[0] ) {
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-r.jpg", config.dir_events, id );
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-r.jpg", staticConfig.DIR_EVENTS.c_str(), id );
}
ref_image.WriteJpeg( diag_path );
}
@ -3001,7 +3001,7 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z
if ( config.record_diag_images ) {
static char diag_path[PATH_MAX] = "";
if ( !diag_path[0] ) {
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-d.jpg", config.dir_events, id );
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-d.jpg", staticConfig.DIR_EVENTS.c_str(), id );
}
delta_image.WriteJpeg( diag_path );
}
@ -3688,7 +3688,7 @@ void MonitorStream::runStream() {
// 15 is the max length for the swap path suffix, /zmswap-whatever, assuming max 6 digits for monitor id
const int max_swap_len_suffix = 15;
int swap_path_length = strlen(config.path_swap) + 1; // +1 for NULL terminator
int swap_path_length = strlen(staticConfig.PATH_SWAP.c_str()) + 1; // +1 for NULL terminator
int subfolder1_length = snprintf(NULL, 0, "/zmswap-m%d", monitor->Id() ) + 1;
int subfolder2_length = snprintf(NULL, 0, "/zmswap-q%06d", connkey ) + 1;
int total_swap_path_length = swap_path_length + subfolder1_length + subfolder2_length;
@ -3699,7 +3699,7 @@ void MonitorStream::runStream() {
Error( "Swap Path is too long. %d > %d ", total_swap_path_length+max_swap_len_suffix, PATH_MAX );
} else {
swap_path = (char *)malloc( total_swap_path_length+max_swap_len_suffix );
strncpy( swap_path, config.path_swap, swap_path_length );
strncpy( swap_path, staticConfig.PATH_SWAP.c_str(), swap_path_length );
Debug( 3, "Checking swap path folder: %s", swap_path );
if ( checkSwapPath( swap_path, false ) ) {

View File

@ -157,6 +157,7 @@ protected:
//sizeOf(VideoStoreData) expected to be 4104 bytes on 32bit and 64bit
typedef struct {
uint32_t size;
uint32_t current_event;
char event_file[4096];
timeval recording; // used as both bool and a pointer to the timestamp when recording should begin
//uint32_t frameNumber;
@ -415,6 +416,9 @@ public:
int GetOptSaveJPEGs() const { return( savejpegspref ); }
VideoWriter GetOptVideoWriter() const { return( videowriter ); }
const std::vector<EncoderParameter_t>* GetOptEncoderParams() const { return( &encoderparamsvec ); }
uint32_t GetLastEventId() const { return shared_data->last_event; }
uint32_t GetVideoWriterEventId() const { return video_store_data->current_event; }
void SetVideoWriterEventId( uint32_t p_event_id ) { video_store_data->current_event = p_event_id; }
unsigned int GetPreEventCount() const { return pre_event_count; };
State GetState() const;

View File

@ -24,6 +24,10 @@ extern "C" {
#include <libavformat/avformat.h>
}
#ifdef __FreeBSD__
#include <sys/time.h>
#endif // __FreeBSD__
class ZMPacket {
public:

View File

@ -1,30 +1,30 @@
#ifdef HAVE_SENDFILE4_SUPPORT
#include <sys/sendfile.h>
int zm_sendfile(int out_fd, int in_fd, off_t *offset, size_t size) {
int err;
int err;
err = sendfile(out_fd, in_fd, offset, size);
if (err < 0)
return -errno;
err = sendfile(out_fd, in_fd, offset, size);
if (err < 0)
return -errno;
return err;
return err;
}
#elif HAVE_SENDFILE7_SUPPORT
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
int zm_sendfile(int out_fd, int in_fd, off_t *offset, off_t size) {
int err;
err = sendfile(in_fd, out_fd, *offset, size, NULL, &size, 0);
if (err && errno != EAGAIN)
return -errno;
int err;
err = sendfile(in_fd, out_fd, *offset, size, NULL, &size, 0);
if (err && errno != EAGAIN)
return -errno;
if (size) {
*offset += size;
return size;
}
if (size) {
*offset += size;
return size;
}
return -EAGAIN;
return -EAGAIN;
}
#else
#error "Your platform does not support sendfile. Sorry."

View File

@ -63,13 +63,13 @@ RETSIGTYPE zm_die_handler(int signal)
ucontext_t *uc = (ucontext_t *) context;
cr2 = info->si_addr;
#if defined(__x86_64__)
#ifdef __FreeBSD_kernel__
#if defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
ip = (void *)(uc->uc_mcontext.mc_rip);
#else
ip = (void *)(uc->uc_mcontext.gregs[REG_RIP]);
#endif
#else
#ifdef __FreeBSD_kernel__
#if defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
ip = (void *)(uc->uc_mcontext.mc_eip);
#else
ip = (void *)(uc->uc_mcontext.gregs[REG_EIP]);

View File

@ -291,7 +291,7 @@ void StreamBase::openComms()
if ( connkey > 0 )
{
unsigned int length = snprintf( sock_path_lock, sizeof(sock_path_lock), "%s/zms-%06d.lock", config.path_socks, connkey);
unsigned int length = snprintf( sock_path_lock, sizeof(sock_path_lock), "%s/zms-%06d.lock", staticConfig.PATH_SOCKS.c_str(), connkey);
if ( length >= sizeof(sock_path_lock) ) {
Warning("Socket lock path was truncated.");
length = sizeof(sock_path_lock)-1;
@ -321,7 +321,7 @@ void StreamBase::openComms()
Debug(3, "Have socket %d", sd );
}
length = snprintf( loc_sock_path, sizeof(loc_sock_path), "%s/zms-%06ds.sock", config.path_socks, connkey );
length = snprintf( loc_sock_path, sizeof(loc_sock_path), "%s/zms-%06ds.sock", staticConfig.PATH_SOCKS.c_str(), connkey );
if ( length >= sizeof(loc_sock_path) ) {
Warning("Socket path was truncated.");
length = sizeof(loc_sock_path)-1;
@ -339,7 +339,7 @@ void StreamBase::openComms()
Fatal( "Can't bind: %s", strerror(errno) );
}
snprintf( rem_sock_path, sizeof(rem_sock_path), "%s/zms-%06dw.sock", config.path_socks, connkey );
snprintf( rem_sock_path, sizeof(rem_sock_path), "%s/zms-%06dw.sock", staticConfig.PATH_SOCKS.c_str(), connkey );
strncpy( rem_addr.sun_path, rem_sock_path, sizeof(rem_addr.sun_path) );
rem_addr.sun_family = AF_UNIX;
} // end if connKey > 0

View File

@ -30,8 +30,7 @@ class Monitor;
#define TV_2_FLOAT( tv ) ( double((tv).tv_sec) + (double((tv).tv_usec) / 1000000.0) )
class StreamBase
{
class StreamBase {
public:
typedef enum { STREAM_JPEG, STREAM_RAW, STREAM_ZIP, STREAM_SINGLE, STREAM_MPEG } StreamType;
@ -110,8 +109,7 @@ protected:
virtual void processCommand( const CmdMsg *msg )=0;
public:
StreamBase()
{
StreamBase() {
monitor = 0;
type = DEFAULT_TYPE;
@ -145,32 +143,27 @@ public:
}
virtual ~StreamBase();
void setStreamType( StreamType p_type )
{
void setStreamType( StreamType p_type ) {
type = p_type;
}
void setStreamFormat( const char *p_format )
{
void setStreamFormat( const char *p_format ) {
format = p_format;
}
void setStreamScale( int p_scale )
{
void setStreamScale( int p_scale ) {
scale = p_scale;
if ( ! scale )
scale = DEFAULT_SCALE;
}
void setStreamReplayRate( int p_rate )
{
void setStreamReplayRate( int p_rate ) {
replay_rate = p_rate;
}
void setStreamMaxFPS( double p_maxfps )
{
void setStreamMaxFPS( double p_maxfps ) {
maxfps = p_maxfps;
}
void setStreamBitrate( int p_bitrate )
{
void setStreamBitrate( int p_bitrate ) {
bitrate = p_bitrate;
}
void setStreamQueue( int p_connkey )
{
void setStreamQueue( int p_connkey ) {
connkey = p_connkey;
}
virtual void openComms();

View File

@ -1,522 +1,577 @@
// Copyright (C) 2001-2017 ZoneMinder LLC
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
//
#include "zm.h"
#include "zm_video.h"
#include "zm_image.h"
#include "zm_utils.h"
#include "zm_rgb.h"
#include <sstream>
#include <string>
#include <vector>
VideoWriter::VideoWriter(const char* p_container, const char* p_codec, const char* p_path, const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder) :
container(p_container), codec(p_codec), path(p_path), width(p_width), height(p_height), colours(p_colours), subpixelorder(p_subpixelorder), frame_count(0) {
Debug(7,"Video object created");
/* Parameter checking */
if(path.empty()) {
Error("Invalid file path");
}
if(!width || !height) {
Error("Invalid width or height");
}
VideoWriter::VideoWriter(
const char* p_container,
const char* p_codec,
const char* p_path,
const unsigned int p_width,
const unsigned int p_height,
const unsigned int p_colours,
const unsigned int p_subpixelorder) :
container(p_container),
codec(p_codec),
path(p_path),
width(p_width),
height(p_height),
colours(p_colours),
subpixelorder(p_subpixelorder),
frame_count(0) {
Debug(7, "Video object created");
/* Parameter checking */
if ( path.empty() ) {
Error("Invalid file path");
}
if ( !width || !height ) {
Error("Invalid width or height");
}
}
VideoWriter::~VideoWriter() {
Debug(7,"Video object destroyed");
Debug(7, "Video object destroyed");
}
int VideoWriter::Reset(const char* new_path) {
/* Common variables reset */
/* Common variables reset */
/* If there is a new path, use it */
if(new_path != NULL) {
path = new_path;
}
/* If there is a new path, use it */
if ( new_path != NULL ) {
path = new_path;
}
/* Reset frame counter */
frame_count = 0;
/* Reset frame counter */
frame_count = 0;
return 0;
return 0;
}
#if ZM_HAVE_VIDEOWRITER_X264MP4
X264MP4Writer::X264MP4Writer(const char* p_path, const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder, const std::vector<EncoderParameter_t>* p_user_params) : VideoWriter("mp4", "h264", p_path, p_width, p_height, p_colours, p_subpixelorder), bOpen(false), bGotH264AVCInfo(false), bFirstFrame(true) {
/* Initialize ffmpeg if it hasn't been initialized yet */
FFMPEGInit();
X264MP4Writer::X264MP4Writer(
const char* p_path,
const unsigned int p_width,
const unsigned int p_height,
const unsigned int p_colours,
const unsigned int p_subpixelorder,
const std::vector<EncoderParameter_t>* p_user_params) :
VideoWriter(
"mp4",
"h264",
p_path,
p_width,
p_height,
p_colours,
p_subpixelorder),
bOpen(false),
bGotH264AVCInfo(false),
bFirstFrame(true) {
/* Initialize ffmpeg if it hasn't been initialized yet */
FFMPEGInit();
/* Initialize swscale */
zm_pf = GetFFMPEGPixelFormat(colours,subpixelorder);
if(zm_pf == 0) {
Error("Unable to match ffmpeg pixelformat");
}
codec_pf = AV_PIX_FMT_YUV420P;
/* Initialize swscale */
zm_pf = GetFFMPEGPixelFormat(colours, subpixelorder);
if ( zm_pf == 0 ) {
Error("Unable to match ffmpeg pixelformat");
}
codec_pf = AV_PIX_FMT_YUV420P;
swscaleobj.SetDefaults(zm_pf, codec_pf, width, height);
swscaleobj.SetDefaults(zm_pf, codec_pf, width, height);
/* Calculate the image sizes. We will need this for parameter checking */
zm_imgsize = colours * width * height;
/* Calculate the image sizes. We will need this for parameter checking */
zm_imgsize = colours * width * height;
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
codec_imgsize = av_image_get_buffer_size( codec_pf, width, height, 1 );
codec_imgsize = av_image_get_buffer_size(codec_pf, width, height, 1);
#else
codec_imgsize = avpicture_get_size( codec_pf, width, height);
codec_imgsize = avpicture_get_size(codec_pf, width, height);
#endif
if(!codec_imgsize) {
Error("Failed calculating codec pixel format image size");
}
if ( !codec_imgsize ) {
Error("Failed calculating codec pixel format image size");
}
/* If supplied with user parameters to the encoder, copy them */
if(p_user_params != NULL) {
user_params = *p_user_params;
}
/* Setup x264 parameters */
if(x264config() < 0) {
Error("Failed setting x264 parameters");
}
/* Allocate x264 input picture */
x264_picture_alloc(&x264picin, X264_CSP_I420, x264params.i_width, x264params.i_height);
/* If supplied with user parameters to the encoder, copy them */
if ( p_user_params != NULL ) {
user_params = *p_user_params;
}
/* Setup x264 parameters */
if ( x264config() < 0 ) {
Error("Failed setting x264 parameters");
}
/* Allocate x264 input picture */
x264_picture_alloc(
&x264picin,
X264_CSP_I420,
x264params.i_width,
x264params.i_height);
}
X264MP4Writer::~X264MP4Writer() {
/* Free x264 input picture */
x264_picture_clean(&x264picin);
/* Free x264 input picture */
x264_picture_clean(&x264picin);
if(bOpen)
Close();
if ( bOpen )
Close();
}
int X264MP4Writer::Open() {
/* Open the encoder */
x264enc = x264_encoder_open(&x264params);
if ( x264enc == NULL ) {
Error("Failed opening x264 encoder");
return -1;
}
/* Open the encoder */
x264enc = x264_encoder_open(&x264params);
if(x264enc == NULL) {
Error("Failed opening x264 encoder");
return -1;
}
// Debug(4,"x264 maximum delayed frames: %d",
// x264_encoder_maximum_delayed_frames(x264enc));
// Debug(4,"x264 maximum delayed frames: %d",x264_encoder_maximum_delayed_frames(x264enc));
x264_nal_t* nals;
int i_nals;
if(!x264_encoder_headers(x264enc,&nals,&i_nals)) {
Error("Failed getting encoder headers");
return -2;
}
/* Search SPS NAL for AVC information */
for(int i=0;i<i_nals;i++) {
if(nals[i].i_type == NAL_SPS) {
x264_profleindication = nals[i].p_payload[5];
x264_profilecompat = nals[i].p_payload[6];
x264_levelindication = nals[i].p_payload[7];
bGotH264AVCInfo = true;
break;
}
}
if(!bGotH264AVCInfo) {
Warning("Missing AVC information");
}
/* Create the file */
mp4h = MP4Create((path + ".incomplete").c_str());
if(mp4h == MP4_INVALID_FILE_HANDLE) {
Error("Failed creating mp4 file: %s",path.c_str());
return -10;
}
/* Set the global timescale */
if(!MP4SetTimeScale(mp4h, 1000)) {
Error("Failed setting timescale");
return -11;
}
/* Set the global video profile */
/* I am a bit confused about this one.
I couldn't find what the value should be
Some use 0x15 while others use 0x7f. */
MP4SetVideoProfileLevel(mp4h, 0x7f);
/* Add H264 video track */
mp4vtid = MP4AddH264VideoTrack(mp4h,1000,MP4_INVALID_DURATION,width,height,x264_profleindication,x264_profilecompat,x264_levelindication,3);
if(mp4vtid == MP4_INVALID_TRACK_ID) {
Error("Failed adding H264 video track");
return -12;
}
x264_nal_t* nals;
int i_nals;
if ( !x264_encoder_headers(x264enc, &nals, &i_nals) ) {
Error("Failed getting encoder headers");
return -2;
}
bOpen = true;
return 0;
/* Search SPS NAL for AVC information */
for ( unsigned int i = 0; i < i_nals; i++ ) {
if ( nals[i].i_type == NAL_SPS ) {
x264_profleindication = nals[i].p_payload[5];
x264_profilecompat = nals[i].p_payload[6];
x264_levelindication = nals[i].p_payload[7];
bGotH264AVCInfo = true;
break;
}
}
if ( !bGotH264AVCInfo ) {
Warning("Missing AVC information");
}
/* Create the file */
mp4h = MP4Create((path + ".incomplete").c_str());
if ( mp4h == MP4_INVALID_FILE_HANDLE ) {
Error("Failed creating mp4 file: %s", path.c_str());
return -10;
}
/* Set the global timescale */
if ( !MP4SetTimeScale(mp4h, 1000) ) {
Error("Failed setting timescale");
return -11;
}
/* Set the global video profile */
/* I am a bit confused about this one.
I couldn't find what the value should be
Some use 0x15 while others use 0x7f. */
MP4SetVideoProfileLevel(mp4h, 0x7f);
/* Add H264 video track */
mp4vtid = MP4AddH264VideoTrack(
mp4h,
1000,
MP4_INVALID_DURATION,
width,
height,
x264_profleindication,
x264_profilecompat,
x264_levelindication,
3);
if ( mp4vtid == MP4_INVALID_TRACK_ID ) {
Error("Failed adding H264 video track");
return -12;
}
bOpen = true;
return 0;
}
int X264MP4Writer::Close() {
/* Flush all pending frames */
for ( int i = (x264_encoder_delayed_frames(x264enc) + 1); i > 0; i-- ) {
x264encodeloop(true);
}
/* Flush all pending frames */
for(int i = (x264_encoder_delayed_frames(x264enc) + 1); i > 0; i-- ) {
x264encodeloop(true);
}
/* Close the encoder */
x264_encoder_close(x264enc);
/* Close the encoder */
x264_encoder_close(x264enc);
/* Close MP4 handle */
MP4Close(mp4h);
/* Close MP4 handle */
MP4Close(mp4h);
/* Required for proper HTTP streaming */
MP4Optimize((path + ".incomplete").c_str(), path.c_str());
/* Required for proper HTTP streaming */
MP4Optimize((path + ".incomplete").c_str(), path.c_str());
/* Delete the temporary file */
unlink((path + ".incomplete").c_str());
bOpen = false;
/* Delete the temporary file */
unlink((path + ".incomplete").c_str());
Debug(7, "Video closed. Total frames: %d", frame_count);
return 0;
bOpen = false;
Debug(7, "Video closed. Total frames: %d", frame_count);
return 0;
}
int X264MP4Writer::Reset(const char* new_path) {
/* Close the encoder and file */
if(bOpen)
Close();
/* Close the encoder and file */
if ( bOpen )
Close();
/* Reset common variables */
VideoWriter::Reset(new_path);
/* Reset common variables */
VideoWriter::Reset(new_path);
/* Reset local variables */
bFirstFrame = true;
bGotH264AVCInfo = false;
prevnals.clear();
prevpayload.clear();
/* Reset x264 parameters */
x264config();
/* Reset local variables */
bFirstFrame = true;
bGotH264AVCInfo = false;
prevnals.clear();
prevpayload.clear();
/* Open the encoder */
Open();
return 0;
/* Reset x264 parameters */
x264config();
/* Open the encoder */
Open();
return 0;
}
int X264MP4Writer::Encode(const uint8_t* data, const size_t data_size, const unsigned int frame_time) {
int X264MP4Writer::Encode(
const uint8_t* data,
const size_t data_size,
const unsigned int frame_time) {
/* Parameter checking */
if ( data == NULL ) {
Error("NULL buffer");
return -1;
}
/* Parameter checking */
if(data == NULL) {
Error("NULL buffer");
return -1;
}
if ( data_size != zm_imgsize ) {
Error("The data buffer size (%d) != expected (%d)", data_size, zm_imgsize);
return -2;
}
if(data_size != zm_imgsize) {
Error("The data buffer size does not match the expected size. Expected: %d Current: %d", zm_imgsize, data_size);
return -2;
}
if(!bOpen) {
Warning("The encoder was not initialized, initializing now");
Open();
}
/* Convert the image into the x264 input picture */
if(swscaleobj.ConvertDefaults(data, data_size, x264picin.img.plane[0], codec_imgsize) < 0) {
Error("Image conversion failed");
return -3;
}
if ( !bOpen ) {
Warning("The encoder was not initialized, initializing now");
Open();
}
/* Set PTS */
x264picin.i_pts = frame_time;
/* Convert the image into the x264 input picture */
if ( swscaleobj.ConvertDefaults(data, data_size, x264picin.img.plane[0], codec_imgsize) < 0 ) {
Error("Image conversion failed");
return -3;
}
/* Do the encoding */
x264encodeloop();
/* Set PTS */
x264picin.i_pts = frame_time;
/* Increment frame counter */
frame_count++;
/* Do the encoding */
x264encodeloop();
return 0;
/* Increment frame counter */
frame_count++;
return 0;
}
int X264MP4Writer::Encode(const Image* img, const unsigned int frame_time) {
if(img->Width() != width) {
Error("Source image width differs. Source: %d Output: %d",img->Width(), width);
return -12;
}
if ( img->Width() != width ) {
Error("Source image width differs. Source: %d Output: %d", img->Width(), width);
return -12;
}
if(img->Height() != height) {
Error("Source image height differs. Source: %d Output: %d",img->Height(), height);
return -13;
}
return Encode(img->Buffer(),img->Size(),frame_time);
if ( img->Height() != height ) {
Error("Source image height differs. Source: %d Output: %d", img->Height(), height);
return -13;
}
return Encode(img->Buffer(), img->Size(), frame_time);
}
int X264MP4Writer::x264config() {
/* Sets up the encoder configuration */
/* Sets up the encoder configuration */
int x264ret;
int x264ret;
/* Defaults */
const char* preset = "veryfast";
const char* tune = "stillimage";
const char* profile = "main";
/* Defaults */
const char* preset = "veryfast";
const char* tune = "stillimage";
const char* profile = "main";
/* Search the user parameters for preset, tune and profile */
for(unsigned int i=0; i < user_params.size(); i++) {
if(strcmp(user_params[i].pname, "preset") == 0) {
/* Got preset */
preset = user_params[i].pvalue;
} else if(strcmp(user_params[i].pname, "tune") == 0) {
/* Got tune */
tune = user_params[i].pvalue;
} else if(strcmp(user_params[i].pname, "profile") == 0) {
/* Got profile */
profile = user_params[i].pvalue;
}
}
/* Search the user parameters for preset, tune and profile */
for ( unsigned int i = 0; i < user_params.size(); i++ ) {
if ( strcmp(user_params[i].pname, "preset") == 0 ) {
/* Got preset */
preset = user_params[i].pvalue;
} else if ( strcmp(user_params[i].pname, "tune") == 0 ) {
/* Got tune */
tune = user_params[i].pvalue;
} else if ( strcmp(user_params[i].pname, "profile") == 0 ) {
/* Got profile */
profile = user_params[i].pvalue;
}
}
/* Set the defaults and preset and tune */
x264ret = x264_param_default_preset(&x264params, preset, tune);
if(x264ret != 0) {
Error("Failed setting x264 preset %s and tune %s : %d",preset,tune,x264ret);
}
/* Set the profile */
x264ret = x264_param_apply_profile(&x264params, profile);
if(x264ret != 0) {
Error("Failed setting x264 profile %s : %d",profile,x264ret);
}
/* Input format */
x264params.i_width = width;
x264params.i_height = height;
x264params.i_csp = X264_CSP_I420;
/* Quality control */
x264params.rc.i_rc_method = X264_RC_CRF;
x264params.rc.f_rf_constant = 23.0;
/* Set the defaults and preset and tune */
x264ret = x264_param_default_preset(&x264params, preset, tune);
if ( x264ret != 0 ) {
Error("Failed setting x264 preset %s and tune %s : %d", preset, tune, x264ret);
}
/* Enable b-frames */
x264params.i_bframe = 16;
x264params.i_bframe_adaptive = 1;
/* Timebase */
x264params.i_timebase_num = 1;
x264params.i_timebase_den = 1000;
/* Set the profile */
x264ret = x264_param_apply_profile(&x264params, profile);
if ( x264ret != 0 ) {
Error("Failed setting x264 profile %s : %d", profile, x264ret);
}
/* Enable variable frame rate */
x264params.b_vfr_input = 1;
/* Input format */
x264params.i_width = width;
x264params.i_height = height;
x264params.i_csp = X264_CSP_I420;
/* Disable annex-b (start codes) */
x264params.b_annexb = 0;
/* TODO: Setup error handler */
//x264params.i_log_level = X264_LOG_DEBUG;
/* Quality control */
x264params.rc.i_rc_method = X264_RC_CRF;
x264params.rc.f_rf_constant = 23.0;
/* Process user parameters (excluding preset, tune and profile) */
for(unsigned int i=0; i < user_params.size(); i++) {
/* Skip preset, tune and profile */
if( (strcmp(user_params[i].pname, "preset") == 0) || (strcmp(user_params[i].pname, "tune") == 0) || (strcmp(user_params[i].pname, "profile") == 0) ) {
continue;
}
/* Enable b-frames */
x264params.i_bframe = 16;
x264params.i_bframe_adaptive = 1;
/* Pass the name and value to x264 */
x264ret = x264_param_parse(&x264params, user_params[i].pname, user_params[i].pvalue);
/* Timebase */
x264params.i_timebase_num = 1;
x264params.i_timebase_den = 1000;
/* Error checking */
if(x264ret != 0) {
if(x264ret == X264_PARAM_BAD_NAME) {
Error("Failed processing x264 user parameter %s=%s : Bad name", user_params[i].pname, user_params[i].pvalue);
} else if(x264ret == X264_PARAM_BAD_VALUE) {
Error("Failed processing x264 user parameter %s=%s : Bad value", user_params[i].pname, user_params[i].pvalue);
} else {
Error("Failed processing x264 user parameter %s=%s : Unknown error (%d)", user_params[i].pname, user_params[i].pvalue, x264ret);
}
}
}
return 0;
/* Enable variable frame rate */
x264params.b_vfr_input = 1;
/* Disable annex-b (start codes) */
x264params.b_annexb = 0;
/* TODO: Setup error handler */
// x264params.i_log_level = X264_LOG_DEBUG;
/* Process user parameters (excluding preset, tune and profile) */
for ( unsigned int i = 0; i < user_params.size(); i++ ) {
/* Skip preset, tune and profile */
if (
(strcmp(user_params[i].pname, "preset") == 0) ||
(strcmp(user_params[i].pname, "tune") == 0) ||
(strcmp(user_params[i].pname, "profile") == 0) ) {
continue;
}
/* Pass the name and value to x264 */
x264ret = x264_param_parse(&x264params, user_params[i].pname, user_params[i].pvalue);
/* Error checking */
if ( x264ret != 0 ) {
if ( x264ret == X264_PARAM_BAD_NAME ) {
Error("Failed processing x264 user parameter %s=%s : Bad name",
user_params[i].pname, user_params[i].pvalue);
} else if ( x264ret == X264_PARAM_BAD_VALUE ) {
Error("Failed processing x264 user parameter %s=%s : Bad value",
user_params[i].pname, user_params[i].pvalue);
} else {
Error("Failed processing x264 user parameter %s=%s : Unknown error (%d)",
user_params[i].pname, user_params[i].pvalue, x264ret);
}
}
}
return 0;
}
void X264MP4Writer::x264encodeloop(bool bFlush) {
x264_nal_t* nals;
int i_nals;
int frame_size;
x264_nal_t* nals;
int i_nals;
int frame_size;
if ( bFlush ) {
frame_size = x264_encoder_encode(x264enc, &nals, &i_nals, NULL, &x264picout);
} else {
frame_size = x264_encoder_encode(x264enc, &nals, &i_nals, &x264picin, &x264picout);
}
if(bFlush) {
frame_size = x264_encoder_encode(x264enc, &nals, &i_nals, NULL, &x264picout);
} else {
frame_size = x264_encoder_encode(x264enc, &nals, &i_nals, &x264picin, &x264picout);
}
if ( frame_size > 0 || bFlush ) {
Debug(8, "x264 Frame: %d PTS: %d DTS: %d Size: %d\n",
frame_count, x264picout.i_pts, x264picout.i_dts, frame_size);
if (frame_size > 0 || bFlush) {
Debug(8, "x264 Frame: %d PTS: %d DTS: %d Size: %d\n",frame_count, x264picout.i_pts, x264picout.i_dts, frame_size);
/* Handle the previous frame */
if ( !bFirstFrame ) {
buffer.clear();
/* Handle the previous frame */
if(!bFirstFrame) {
/* Process the NALs for the previous frame */
for ( unsigned int i = 0; i < prevnals.size(); i++ ) {
Debug(9, "Processing NAL: Type %d Size %d",
prevnals[i].i_type,
prevnals[i].i_payload);
buffer.clear();
switch ( prevnals[i].i_type ) {
case NAL_PPS:
/* PPS NAL */
MP4AddH264PictureParameterSet(mp4h, mp4vtid, prevnals[i].p_payload+4, prevnals[i].i_payload-4);
break;
case NAL_SPS:
/* SPS NAL */
MP4AddH264SequenceParameterSet(mp4h, mp4vtid, prevnals[i].p_payload+4, prevnals[i].i_payload-4);
break;
default:
/* Anything else, hopefully frames, so copy it into the sample */
buffer.append(prevnals[i].p_payload, prevnals[i].i_payload);
}
}
/* Process the NALs for the previous frame */
for(unsigned int i=0; i < prevnals.size(); i++) {
Debug(9,"Processing NAL: Type %d Size %d",prevnals[i].i_type,prevnals[i].i_payload);
/* Calculate frame duration and offset */
int duration = x264picout.i_dts - prevDTS;
int offset = prevPTS - prevDTS;
switch(prevnals[i].i_type) {
case NAL_PPS:
/* PPS NAL */
MP4AddH264PictureParameterSet(mp4h, mp4vtid, prevnals[i].p_payload+4, prevnals[i].i_payload-4);
break;
case NAL_SPS:
/* SPS NAL */
MP4AddH264SequenceParameterSet(mp4h, mp4vtid, prevnals[i].p_payload+4, prevnals[i].i_payload-4);
break;
default:
/* Anything else, hopefully frames, so copy it into the sample */
buffer.append(prevnals[i].p_payload, prevnals[i].i_payload);
}
}
/* Write the sample */
if ( !buffer.empty() ) {
if ( !MP4WriteSample(
mp4h,
mp4vtid,
buffer.extract(buffer.size()),
buffer.size(),
duration,
offset,
prevKeyframe) ) {
Error("Failed writing sample");
}
}
/* Calculate frame duration and offset */
int duration = x264picout.i_dts - prevDTS;
int offset = prevPTS - prevDTS;
/* Cleanup */
prevnals.clear();
prevpayload.clear();
}
/* Write the sample */
if(!buffer.empty()) {
if(!MP4WriteSample(mp4h, mp4vtid, buffer.extract(buffer.size()), buffer.size(), duration, offset, prevKeyframe)) {
Error("Failed writing sample");
}
}
/* Got a frame. Copy this new frame into the previous frame */
if ( frame_size > 0 ) {
/* Copy the NALs and the payloads */
for ( unsigned int i = 0; i < i_nals; i++ ) {
prevnals.push_back(nals[i]);
prevpayload.append(nals[i].p_payload, nals[i].i_payload);
}
/* Cleanup */
prevnals.clear();
prevpayload.clear();
/* Update the payload pointers */
/* This is done in a separate loop because the previous loop might reallocate memory when appending,
making the pointers invalid */
unsigned int payload_offset = 0;
for ( unsigned int i = 0; i < prevnals.size(); i++ ) {
prevnals[i].p_payload = prevpayload.head() + payload_offset;
payload_offset += nals[i].i_payload;
}
}
/* We need this for the next frame */
prevPTS = x264picout.i_pts;
prevDTS = x264picout.i_dts;
prevKeyframe = x264picout.b_keyframe;
/* Got a frame. Copy this new frame into the previous frame */
if(frame_size > 0) {
/* Copy the NALs and the payloads */
for(int i=0;i<i_nals;i++) {
prevnals.push_back(nals[i]);
prevpayload.append(nals[i].p_payload, nals[i].i_payload);
}
bFirstFrame = false;
}
/* Update the payload pointers */
/* This is done in a separate loop because the previous loop might reallocate memory when appending,
making the pointers invalid */
unsigned int payload_offset = 0;
for(unsigned int i=0;i<prevnals.size();i++) {
prevnals[i].p_payload = prevpayload.head() + payload_offset;
payload_offset += nals[i].i_payload;
}
/* We need this for the next frame */
prevPTS = x264picout.i_pts;
prevDTS = x264picout.i_dts;
prevKeyframe = x264picout.b_keyframe;
bFirstFrame = false;
}
} else if(frame_size == 0) {
Debug(7,"x264 encode returned zero. Delayed frames: %d",x264_encoder_delayed_frames(x264enc));
} else {
Error("x264 encode failed: %d",frame_size);
}
} else if ( frame_size == 0 ) {
Debug(7, "x264 encode returned zero. Delayed frames: %d",
x264_encoder_delayed_frames(x264enc));
} else {
Error("x264 encode failed: %d", frame_size);
}
}
#endif // ZM_VIDEOWRITER_X264MP4
#endif // ZM_VIDEOWRITER_X264MP4
int ParseEncoderParameters(const char* str, std::vector<EncoderParameter_t>* vec) {
if(vec == NULL) {
Error("NULL Encoder parameters vector pointer");
return -1;
}
int ParseEncoderParameters(
const char* str,
std::vector<EncoderParameter_t>* vec
) {
if ( vec == NULL ) {
Error("NULL Encoder parameters vector pointer");
return -1;
}
if(str == NULL) {
Error("NULL Encoder parameters string");
return -2;
}
if ( str == NULL ) {
Error("NULL Encoder parameters string");
return -2;
}
vec->clear();
vec->clear();
if(str[0] == 0) {
/* Empty */
return 0;
}
if ( str[0] == 0 ) {
/* Empty */
return 0;
}
std::string line;
std::stringstream ss(str);
size_t valueoffset;
size_t valuelen;
unsigned int lineno = 0;
EncoderParameter_t param;
std::string line;
std::stringstream ss(str);
size_t valueoffset;
size_t valuelen;
unsigned int lineno = 0;
EncoderParameter_t param;
while(std::getline(ss, line) ) {
lineno++;
while ( std::getline(ss, line) ) {
lineno++;
/* Remove CR if exists */
if(line.length() >= 1 && line[line.length()-1] == '\r') {
line.erase(line.length()-1);
}
/* Remove CR if exists */
if ( line.length() >= 1 && line[line.length()-1] == '\r' ) {
line.erase(line.length() - 1);
}
/* Skip comments and empty lines */
if(line.empty() || line[0] == '#') {
continue;
}
/* Skip comments and empty lines */
if ( line.empty() || line[0] == '#' ) {
continue;
}
valueoffset = line.find('=');
if(valueoffset == std::string::npos || valueoffset+1 >= line.length() || valueoffset == 0) {
Warning("Failed parsing encoder parameters line %d: Invalid pair", lineno);
continue;
}
valueoffset = line.find('=');
if ( valueoffset == std::string::npos || valueoffset+1 >= line.length() || valueoffset == 0 ) {
Warning("Failed parsing encoder parameters line %d: Invalid pair", lineno);
continue;
}
if ( valueoffset > (sizeof(param.pname) - 1 ) ) {
Warning("Failed parsing encoder parameters line %d: Name too long", lineno);
continue;
}
if(valueoffset > (sizeof(param.pname)-1) ) {
Warning("Failed parsing encoder parameters line %d: Name too long", lineno);
continue;
}
valuelen = line.length() - (valueoffset+1);
valuelen = line.length() - (valueoffset+1);
if ( valuelen > (sizeof(param.pvalue) - 1 ) ) {
Warning("Failed parsing encoder parameters line %d: Value too long", lineno);
continue;
}
if( valuelen > (sizeof(param.pvalue)-1) ) {
Warning("Failed parsing encoder parameters line %d: Value too long", lineno);
continue;
}
/* Copy and NULL terminate */
line.copy(param.pname, valueoffset, 0);
line.copy(param.pvalue, valuelen, valueoffset+1);
param.pname[valueoffset] = 0;
param.pvalue[valuelen] = 0;
/* Copy and NULL terminate */
line.copy(param.pname, valueoffset, 0);
line.copy(param.pvalue, valuelen, valueoffset+1);
param.pname[valueoffset] = 0;
param.pvalue[valuelen] = 0;
/* Push to the vector */
vec->push_back(param);
/* Push to the vector */
vec->push_back(param);
Debug(7, "Parsed encoder parameter: %s = %s", param.pname, param.pvalue);
}
Debug(7, "Parsed encoder parameter: %s = %s", param.pname, param.pvalue);
}
Debug(7, "Parsed %d lines", lineno);
Debug(7, "Parsed %d lines", lineno);
return 0;
return 0;
}

View File

@ -41,9 +41,10 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
video_input_stream = p_video_input_stream;
audio_input_stream = p_audio_input_stream;
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
video_input_context = avcodec_alloc_context3( NULL );
avcodec_parameters_to_context( video_input_context, video_input_stream->codecpar );
zm_dump_codecpar( video_input_stream->codecpar );
#else
video_input_context = video_input_stream->codec;
#endif
@ -84,7 +85,8 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
oc->metadata = pmetadata;
output_format = oc->oformat;
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
// Since we are not re-encoding, all we have to do is copy the parameters
video_output_context = avcodec_alloc_context3( NULL );
@ -94,9 +96,9 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
Error( "Could not initialize context parameteres");
return;
} else {
Debug( 2, "Success getting parameters");
zm_dump_codec( video_output_context );
}
video_output_stream = avformat_new_stream( oc, NULL );
if ( ! video_output_stream ) {
Fatal("Unable to create video out stream\n");
@ -104,6 +106,11 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
Debug(2, "Success creating video out stream" );
}
if ( ! video_output_context->codec_tag ) {
video_output_context->codec_tag = av_codec_get_tag(oc->oformat->codec_tag, video_input_context->codec_id);
Debug(2, "No codec_tag, setting to %d", video_output_context->codec_tag );
}
// Now copy them to the output stream
ret = avcodec_parameters_from_context( video_output_stream->codecpar, video_output_context );
if ( ret < 0 ) {
@ -112,8 +119,8 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
} else {
Debug(2, "Success setting parameters");
}
zm_dump_codecpar( video_output_stream->codecpar );
zm_dump_stream_format( oc, 0, 0, 1 );
#else
video_output_stream = avformat_new_stream(oc, (AVCodec*)video_input_context->codec );
if ( ! video_output_stream ) {
@ -129,6 +136,15 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
} else {
Debug(3, "Success copying context" );
}
if ( ! video_output_context->codec_tag ) {
Debug(2, "No codec_tag");
if (! oc->oformat->codec_tag
|| av_codec_get_id (oc->oformat->codec_tag, video_input_context->codec_tag) == video_output_context->codec_id
|| av_codec_get_tag(oc->oformat->codec_tag, video_input_context->codec_id) <= 0) {
Warning("Setting codec tag");
video_output_context->codec_tag = video_input_context->codec_tag;
}
}
#endif
// Just copy them from the input, no reason to choose different
@ -146,17 +162,6 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
video_output_context->time_base.den
);
// WHY?
//video_output_context->codec_tag = 0;
if ( ! video_output_context->codec_tag ) {
Debug(2, "No codec_tag");
if (! oc->oformat->codec_tag
|| av_codec_get_id (oc->oformat->codec_tag, video_input_context->codec_tag) == video_output_context->codec_id
|| av_codec_get_tag(oc->oformat->codec_tag, video_input_context->codec_id) <= 0) {
Warning("Setting codec tag");
video_output_context->codec_tag = video_input_context->codec_tag;
}
}
if (oc->oformat->flags & AVFMT_GLOBALHEADER) {
video_output_context->flags |= CODEC_FLAG_GLOBAL_HEADER;
@ -190,7 +195,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
if ( audio_input_stream ) {
Debug(3, "Have audio stream" );
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
audio_input_context = avcodec_alloc_context3( NULL );
ret = avcodec_parameters_to_context( audio_input_context, audio_input_stream->codecpar );
@ -217,19 +222,32 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
} else {
Debug(2, "setting parameters");
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
audio_output_context = avcodec_alloc_context3( NULL );
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
audio_output_context = avcodec_alloc_context3( audio_output_codec );
// Copy params from inputstream to context
ret = avcodec_parameters_to_context( audio_output_context, audio_input_stream->codecpar );
if (ret < 0) {
Error("Unable to copy audio params to context %s\n", av_make_error_string(ret).c_str());
}
ret = avcodec_parameters_from_context( audio_output_stream->codecpar, audio_output_context );
if (ret < 0) {
Error("Unable to copy audio params to stream %s\n", av_make_error_string(ret).c_str());
}
if ( ! audio_output_context->codec_tag ) {
audio_output_context->codec_tag = av_codec_get_tag(oc->oformat->codec_tag, audio_input_context->codec_id);
Debug(2, "Setting audio codec tag to %d", audio_output_context->codec_tag );
}
#else
audio_output_context = audio_output_stream->codec;
ret = avcodec_copy_context(audio_output_context, audio_input_context);
audio_output_context->codec_tag = 0;
#endif
if (ret < 0) {
Error("Unable to copy audio context %s\n", av_make_error_string(ret).c_str());
audio_output_stream = NULL;
} else {
audio_output_context->codec_tag = 0;
if ( audio_output_context->channels > 1 ) {
Warning("Audio isn't mono, changing it.");
audio_output_context->channels = 1;
@ -265,10 +283,10 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
zm_dump_stream_format( oc, 1, 0, 1 );
AVDictionary * opts = NULL;
//av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
//av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
//av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov+default_base_moof", 0);
if ((ret = avformat_write_header(oc, NULL)) < 0) {
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. */
@ -307,7 +325,7 @@ VideoStore::~VideoStore(){
int64_t size;
while(1) {
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
ret = avcodec_receive_packet( audio_output_context, &pkt );
#else
ret = avcodec_encode_audio2( audio_output_context, &pkt, NULL, &got_packet );
@ -379,7 +397,7 @@ bool VideoStore::setup_resampler() {
#ifdef HAVE_LIBAVRESAMPLE
static char error_buffer[256];
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
// Newer ffmpeg wants to keep everything separate... so have to lookup our own decoder, can't reuse the one from the camera.
AVCodec *audio_input_codec = avcodec_find_decoder(audio_input_stream->codecpar->codec_id);
#else
@ -455,7 +473,7 @@ bool VideoStore::setup_resampler() {
// Now copy them to the output stream
audio_output_stream = avformat_new_stream( oc, audio_output_codec );
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
ret = avcodec_parameters_from_context( audio_output_stream->codecpar, audio_output_context );
if ( ret < 0 ) {
Error( "Could not initialize stream parameteres");
@ -720,7 +738,7 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) {
if ( audio_output_codec ) {
#ifdef HAVE_LIBAVRESAMPLE
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
ret = avcodec_send_packet( audio_input_context, ipkt );
if ( ret < 0 ) {
Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str());
@ -800,7 +818,7 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) {
* Encode the audio frame and store it in the temporary packet.
* The output audio stream encoder is used to do this.
*/
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
if (( ret = avcodec_send_frame( audio_output_context, output_frame ) ) < 0 ) {
Error( "Could not send frame (error '%s')",
av_make_error_string(ret).c_str());

View File

@ -112,7 +112,7 @@ void Zone::Setup(
if ( config.record_diag_images ) {
static char diag_path[PATH_MAX] = "";
if ( ! diag_path[0] ) {
snprintf( diag_path, sizeof(diag_path), "%s/%s/diag-%d-poly.jpg", config.dir_events, monitor->Name(), id);
snprintf( diag_path, sizeof(diag_path), "%s/%s/diag-%d-poly.jpg", staticConfig.DIR_EVENTS.c_str(), monitor->Name(), id);
}
pg_image->WriteJpeg( diag_path );
}
@ -233,7 +233,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
if ( config.record_diag_images ) {
static char diag_path[PATH_MAX] = "";
if ( ! diag_path[0] ) {
snprintf( diag_path, sizeof(diag_path), "%s/%s/diag-%d-%d.jpg", config.dir_events, monitor->Name(), id, 1 );
snprintf( diag_path, sizeof(diag_path), "%s/%s/diag-%d-%d.jpg", staticConfig.DIR_EVENTS.c_str(), monitor->Name(), id, 1 );
}
diff_image->WriteJpeg( diag_path );
}
@ -315,7 +315,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
if ( config.record_diag_images ) {
static char diag_path[PATH_MAX] = "";
if ( !diag_path[0] ) {
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-%d.jpg", config.dir_events, monitor->Id(), id, 2 );
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-%d.jpg", staticConfig.DIR_EVENTS.c_str(), monitor->Id(), id, 2 );
}
diff_image->WriteJpeg( diag_path );
}
@ -525,7 +525,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
if ( config.record_diag_images ) {
static char diag_path[PATH_MAX] = "";
if ( !diag_path[0] ) {
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-%d.jpg", config.dir_events, monitor->Id(), id, 3 );
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-%d.jpg", staticConfig.DIR_EVENTS.c_str(), monitor->Id(), id, 3 );
}
diff_image->WriteJpeg( diag_path );
}
@ -572,7 +572,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
if ( config.record_diag_images ) {
static char diag_path[PATH_MAX] = "";
if ( !diag_path[0] ) {
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-%d.jpg", config.dir_events, monitor->Id(), id, 4 );
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-%d.jpg", staticConfig.DIR_EVENTS.c_str(), monitor->Id(), id, 4 );
}
diff_image->WriteJpeg( diag_path );
}
@ -792,7 +792,7 @@ bool Zone::ParseZoneString( const char *zone_string, int &zone_id, int &colour,
zone_id = strtol( str, 0, 10 );
Debug( 3, "Got zone %d from zone string", zone_id );
if ( !ws ) {
delete str_ptr;
delete[] str_ptr;
return( true );
}
@ -806,7 +806,7 @@ bool Zone::ParseZoneString( const char *zone_string, int &zone_id, int &colour,
colour = strtol( str, 0, 16 );
Debug( 3, "Got colour %06x from zone string", colour );
if ( !ws ) {
delete str_ptr;
delete[] str_ptr;
return( true );
}
*ws = '\0';

View File

@ -77,6 +77,7 @@ protected:
// Outputs/Statistics
bool alarmed;
bool was_alarmed;
int pixel_diff;
unsigned int alarm_pixels;
int alarm_filter_pixels;

View File

@ -26,32 +26,26 @@
#include "zm_signal.h"
#include "zm_monitor.h"
bool ValidateAccess( User *user, int mon_id )
{
bool ValidateAccess( User *user, int mon_id ) {
bool allowed = true;
if ( mon_id > 0 )
{
if ( mon_id > 0 ) {
if ( user->getStream() < User::PERM_VIEW )
allowed = false;
if ( !user->canAccess( mon_id ) )
allowed = false;
}
else
{
} else {
if ( user->getEvents() < User::PERM_VIEW )
allowed = false;
}
if ( !allowed )
{
if ( !allowed ) {
Error( "Error, insufficient privileges for requested action" );
exit( -1 );
}
return( allowed );
}
int main( int argc, const char *argv[] )
{
int main( int argc, const char *argv[] ) {
self = argv[0];
srand( getpid() * time( 0 ) );
@ -82,8 +76,7 @@ int main( int argc, const char *argv[] )
else //argv[0] will not always contain the full path, but rather just the script name
basename = argv[0];
const char *nph_prefix = "nph-";
if ( basename && !strncmp( basename, nph_prefix, strlen(nph_prefix) ) )
{
if ( basename && !strncmp( basename, nph_prefix, strlen(nph_prefix) ) ) {
nph = true;
}
@ -97,8 +90,7 @@ int main( int argc, const char *argv[] )
zmSetDefaultDieHandler();
const char *query = getenv( "QUERY_STRING" );
if ( query )
{
if ( query ) {
Debug( 1, "Query: %s", query );
char temp_query[1024];
@ -106,84 +98,68 @@ int main( int argc, const char *argv[] )
char *q_ptr = temp_query;
char *parms[16]; // Shouldn't be more than this
int parm_no = 0;
while( (parm_no < 16) && (parms[parm_no] = strtok( q_ptr, "&" )) )
{
while( (parm_no < 16) && (parms[parm_no] = strtok( q_ptr, "&" )) ) {
parm_no++;
q_ptr = NULL;
}
for ( int p = 0; p < parm_no; p++ )
{
for ( int p = 0; p < parm_no; p++ ) {
char *name = strtok( parms[p], "=" );
char *value = strtok( NULL, "=" );
if ( !value )
value = (char *)"";
if ( !strcmp( name, "source" ) )
{
if ( !strcmp( name, "source" ) ) {
source = !strcmp( value, "event" )?ZMS_EVENT:ZMS_MONITOR;
}
else if ( !strcmp( name, "mode" ) )
{
} else if ( !strcmp( name, "mode" ) ) {
mode = !strcmp( value, "jpeg" )?ZMS_JPEG:ZMS_MPEG;
mode = !strcmp( value, "raw" )?ZMS_RAW:mode;
mode = !strcmp( value, "zip" )?ZMS_ZIP:mode;
mode = !strcmp( value, "single" )?ZMS_SINGLE:mode;
}
else if ( !strcmp( name, "format" ) )
} else if ( !strcmp( name, "format" ) ) {
strncpy( format, value, sizeof(format) );
else if ( !strcmp( name, "monitor" ) )
} else if ( !strcmp( name, "monitor" ) ) {
monitor_id = atoi( value );
else if ( !strcmp( name, "time" ) )
} else if ( !strcmp( name, "time" ) ) {
event_time = atoi( value );
else if ( !strcmp( name, "event" ) )
} else if ( !strcmp( name, "event" ) ) {
event_id = strtoull( value, (char **)NULL, 10 );
else if ( !strcmp( name, "frame" ) )
} else if ( !strcmp( name, "frame" ) ) {
frame_id = strtoull( value, (char **)NULL, 10 );
else if ( !strcmp( name, "scale" ) )
} else if ( !strcmp( name, "scale" ) ) {
scale = atoi( value );
else if ( !strcmp( name, "rate" ) )
} else if ( !strcmp( name, "rate" ) ) {
rate = atoi( value );
else if ( !strcmp( name, "maxfps" ) )
} else if ( !strcmp( name, "maxfps" ) ) {
maxfps = atof( value );
else if ( !strcmp( name, "bitrate" ) )
} else if ( !strcmp( name, "bitrate" ) ) {
bitrate = atoi( value );
else if ( !strcmp( name, "ttl" ) )
} else if ( !strcmp( name, "ttl" ) ) {
ttl = atoi(value);
else if ( !strcmp( name, "replay" ) )
{
} else if ( !strcmp( name, "replay" ) ) {
replay = !strcmp( value, "gapless" )?EventStream::MODE_ALL_GAPLESS:EventStream::MODE_SINGLE;
replay = !strcmp( value, "all" )?EventStream::MODE_ALL:replay;
}
else if ( !strcmp( name, "connkey" ) )
} else if ( !strcmp( name, "connkey" ) ) {
connkey = atoi(value);
else if ( !strcmp( name, "buffer" ) )
} else if ( !strcmp( name, "buffer" ) ) {
playback_buffer = atoi(value);
else if ( config.opt_use_auth )
{
if ( strcmp( config.auth_relay, "none" ) == 0 )
{
if ( !strcmp( name, "user" ) )
{
} else if ( config.opt_use_auth ) {
if ( strcmp( config.auth_relay, "none" ) == 0 ) {
if ( !strcmp( name, "user" ) ) {
username = value;
}
}
else
{
} else {
//if ( strcmp( config.auth_relay, "hashed" ) == 0 )
{
if ( !strcmp( name, "auth" ) )
{
if ( !strcmp( name, "auth" ) ) {
strncpy( auth, value, sizeof(auth) );
}
}
//else if ( strcmp( config.auth_relay, "plain" ) == 0 )
{
if ( !strcmp( name, "user" ) )
{
if ( !strcmp( name, "user" ) ) {
username = UriDecode( value );
}
if ( !strcmp( name, "pass" ) )
{
if ( !strcmp( name, "pass" ) ) {
password = UriDecode( value );
}
}
@ -192,36 +168,28 @@ int main( int argc, const char *argv[] )
}
}
if ( config.opt_use_auth )
{
if ( config.opt_use_auth ) {
User *user = 0;
if ( strcmp( config.auth_relay, "none" ) == 0 )
{
if ( username.length() )
{
if ( strcmp( config.auth_relay, "none" ) == 0 ) {
if ( username.length() ) {
user = zmLoadUser( username.c_str() );
}
}
else
{
} else {
//if ( strcmp( config.auth_relay, "hashed" ) == 0 )
{
if ( *auth )
{
if ( *auth ) {
user = zmLoadAuthUser( auth, config.auth_hash_ips );
}
}
//else if ( strcmp( config.auth_relay, "plain" ) == 0 )
{
if ( username.length() && password.length() )
{
if ( username.length() && password.length() ) {
user = zmLoadUser( username.c_str(), password.c_str() );
}
}
}
if ( !user )
{
if ( !user ) {
Error( "Unable to authenticate user" );
logTerm();
zmDbClose();
@ -231,8 +199,7 @@ int main( int argc, const char *argv[] )
}
setbuf( stdout, 0 );
if ( nph )
{
if ( nph ) {
fprintf( stdout, "HTTP/1.0 200 OK\r\n" );
}
fprintf( stdout, "Server: ZoneMinder Video Server/%s\r\n", ZM_VERSION );
@ -252,8 +219,7 @@ int main( int argc, const char *argv[] )
//fprintf( stdout, "Content-Length: 0\r\n");
//}
if ( source == ZMS_MONITOR )
{
if ( source == ZMS_MONITOR ) {
MonitorStream stream;
stream.setStreamScale( scale );
stream.setStreamReplayRate( rate );
@ -269,24 +235,15 @@ int main( int argc, const char *argv[] )
return( -1 );
}
if ( mode == ZMS_JPEG )
{
if ( mode == ZMS_JPEG ) {
stream.setStreamType( MonitorStream::STREAM_JPEG );
}
else if ( mode == ZMS_RAW )
{
} else if ( mode == ZMS_RAW ) {
stream.setStreamType( MonitorStream::STREAM_RAW );
}
else if ( mode == ZMS_ZIP )
{
} else if ( mode == ZMS_ZIP ) {
stream.setStreamType( MonitorStream::STREAM_ZIP );
}
else if ( mode == ZMS_SINGLE )
{
} else if ( mode == ZMS_SINGLE ) {
stream.setStreamType( MonitorStream::STREAM_SINGLE );
}
else
{
} else {
#if HAVE_LIBAVCODEC
stream.setStreamFormat( format );
stream.setStreamBitrate( bitrate );
@ -300,29 +257,21 @@ int main( int argc, const char *argv[] )
#endif // HAVE_LIBAVCODEC
}
stream.runStream();
}
else if ( source == ZMS_EVENT )
{
} else if ( source == ZMS_EVENT ) {
EventStream stream;
stream.setStreamScale( scale );
stream.setStreamReplayRate( rate );
stream.setStreamMaxFPS( maxfps );
stream.setStreamMode( replay );
stream.setStreamQueue( connkey );
if ( monitor_id && event_time )
{
if ( monitor_id && event_time ) {
stream.setStreamStart( monitor_id, event_time );
}
else
{
} else {
stream.setStreamStart( event_id, frame_id );
}
if ( mode == ZMS_JPEG )
{
if ( mode == ZMS_JPEG ) {
stream.setStreamType( EventStream::STREAM_JPEG );
}
else
{
} else {
#if HAVE_LIBAVCODEC
stream.setStreamFormat( format );
stream.setStreamBitrate( bitrate );

9
utils/packpack/heartbeat.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/bash
# A script to provide background noise so Travis doesn't kill us due to inactivity
# written by Andrew Bauer
while true; do
echo "$(date) - Please don't kill us Mr. Travis, we are still running!"
sleep 30s
done

View File

@ -37,7 +37,7 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ]; then
# Don't keep packages older than 5 days
find ./zmrepo/$targetfolder/ -maxdepth 1 -type f -mtime +5 -delete
rsync -vzh --ignore-errors build/* zmrepo/$targetfolder/
rsync -vzlh --ignore-errors build/* zmrepo/$targetfolder/
fusermount -zu zmrepo
else
echo

View File

@ -140,7 +140,7 @@ installtrusty () {
pkgname="build/zoneminder_${VERSION}-${RELEASE}_amd64.deb"
if [ -e $pkgname ]; then
sudo gdebi --non-interactive $pkgname
sudo gdebi --quiet --non-interactive $pkgname
mysql -uzmuser -pzmpass zm < db/test.monitor.sql
sudo /usr/bin/zmpkg.pl start
sudo /usr/bin/zmfilter.pl -f purgewhenfull
@ -255,7 +255,11 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then
setrpmchangelog
echo "Starting packpack..."
packpack/packpack -f utils/packpack/redhat_package.mk redhat_package
utils/packpack/heartbeat.sh &
mypid=$!
packpack/packpack -f utils/packpack/redhat_package.mk redhat_package > buildlog.txt 2>&1
kill $mypid
tail -n 3000 buildlog.txt | grep -v ONVIF
# Steps common to Debian based distros
elif [ "${OS}" == "debian" ] || [ "${OS}" == "ubuntu" ]; then
@ -275,8 +279,12 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then
setdebchangelog
echo "Starting packpack..."
packpack/packpack
utils/packpack/heartbeat.sh &
mypid=$!
packpack/packpack > buildlog.txt 2>&1
kill $mypid
tail -n 3000 buildlog.txt | grep -v ONVIF
if [ "${OS}" == "ubuntu" ] && [ "${DIST}" == "trusty" ] && [ "${ARCH}" == "x86_64" ] && [ "${TRAVIS}" == "true" ]; then
installtrusty
fi
@ -295,7 +303,11 @@ elif [ "${OS}" == "ubuntu" ] && [ "${DIST}" == "trusty" ] && [ "${ARCH}" == "x86
setdebchangelog
echo "Starting packpack..."
packpack/packpack
utils/packpack/heartbeat.sh &
mypid=$!
packpack/packpack > buildlog.txt 2>&1
kill $mypid
tail -n 3000 buildlog.txt | grep -v ONVIF
# If we are running inside Travis then attempt to install the deb we just built
if [ "${TRAVIS}" == "true" ]; then

View File

@ -1 +1 @@
1.31.0
1.31.1

37
web/ajax/console.php Normal file
View File

@ -0,0 +1,37 @@
<?php
if ( canEdit( 'Monitors' ) ) {
switch ( $_REQUEST['action'] ) {
case 'sort' :
{
$monitor_ids = $_POST['monitor_ids'];
# Two concurrent sorts could generate odd sortings... so lock the table.
global $dbConn;
$dbConn->beginTransaction();
$dbConn->exec( 'LOCK TABLES Monitors WRITE' );
for ( $i = 0; $i < count($monitor_ids); $i += 1 ) {
$monitor_id = $monitor_ids[$i];
$monitor_id = preg_replace( '/^monitor_id-/', '', $monitor_id );
if ( ( ! $monitor_id ) or ! ( is_integer( $monitor_id ) or ctype_digit( $monitor_id ) ) ) {
Warning( "Got $monitor_id from " . $monitor_ids[$i] );
continue;
}
dbQuery( 'UPDATE Monitors SET Sequence=? WHERE Id=?', array( $i, $monitor_id ) );
} // end for each monitor_id
$dbConn->commit();
$dbConn->exec('UNLOCK TABLES');
return;
} // end case sort
default:
{
Warning("unknown action " . $_REQUEST['action'] );
} // end ddcase default
}
} else {
Warning("Cannot edit monitors" );
}
ajaxError( 'Unrecognised action or insufficient permissions' );
?>

File diff suppressed because one or more lines are too long

View File

@ -176,8 +176,8 @@ if ( !empty($action) ) {
} else {
Error("No new Id despite new name");
}
$refreshParent = '/index.php?view=filter&Id='.$_REQUEST['Id'];
}
$refreshParent = '/index.php?view=filter&Id='.$_REQUEST['Id'];
}
} // end if canedit events
} // end if action == filter
@ -800,7 +800,6 @@ if ( !empty($action) ) {
switch( $_REQUEST['tab'] ) {
case 'system' :
case 'config' :
case 'paths' :
$restartWarning = true;
break;
case 'web' :

View File

@ -1283,6 +1283,7 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&amp;' ) {
case 'MaxScore':
case 'Cause':
case 'Notes':
case 'StateId':
case 'Archived':
$filter['sql'] .= 'E.'.$filter['terms'][$i]['attr'];
break;
@ -2137,8 +2138,7 @@ function getSkinFile( $file ) {
return( $skinFile );
}
function getSkinIncludes( $file, $includeBase=false, $asOverride=false )
{
function getSkinIncludes( $file, $includeBase=false, $asOverride=false ) {
global $skinBase;
$skinFile = false;
foreach ( $skinBase as $skin ) {

View File

@ -21,29 +21,26 @@
error_reporting( E_ALL );
$debug = false;
if ( $debug )
{
// Use these for debugging, though not both at once!
phpinfo( INFO_VARIABLES );
//error_reporting( E_ALL );
if ( $debug ) {
// Use these for debugging, though not both at once!
phpinfo( INFO_VARIABLES );
//error_reporting( E_ALL );
}
// Use new style autoglobals where possible
if ( version_compare( phpversion(), "4.1.0", "<") )
{
$_SESSION = &$HTTP_SESSION_VARS;
$_SERVER = &$HTTP_SERVER_VARS;
if ( version_compare( phpversion(), '4.1.0', '<') ) {
$_SESSION = &$HTTP_SESSION_VARS;
$_SERVER = &$HTTP_SERVER_VARS;
}
// Useful debugging lines for mobile devices
if ( false )
{
ob_start();
phpinfo( INFO_VARIABLES );
$fp = fopen( "/tmp/env.html", "w" );
fwrite( $fp, ob_get_contents() );
fclose( $fp );
ob_end_clean();
if ( false ) {
ob_start();
phpinfo( INFO_VARIABLES );
$fp = fopen( '/tmp/env.html', 'w' );
fwrite( $fp, ob_get_contents() );
fclose( $fp );
ob_end_clean();
}
require_once( 'includes/config.php' );
@ -53,26 +50,23 @@ require_once( 'includes/Storage.php' );
require_once( 'includes/Event.php' );
require_once( 'includes/Monitor.php' );
if ( isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on' )
{
$protocol = 'https';
if ( isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ) {
$protocol = 'https';
} else {
$protocol = 'http';
}
else
{
$protocol = 'http';
}
define( "ZM_BASE_PROTOCOL", $protocol );
define( 'ZM_BASE_PROTOCOL', $protocol );
// Absolute URL's are unnecessary and break compatibility with reverse proxies
// define( "ZM_BASE_URL", $protocol.'://'.$_SERVER['HTTP_HOST'] );
// Use relative URL's instead
define( "ZM_BASE_URL", "" );
define( 'ZM_BASE_URL', '' );
// Check time zone is set
if (!ini_get('date.timezone') || !date_default_timezone_set(ini_get('date.timezone'))) {
date_default_timezone_set('UTC');
Fatal( "ZoneMinder is not installed properly: php's date.timezone is not set to a valid timezone" );
date_default_timezone_set('UTC');
Fatal( "ZoneMinder is not installed properly: php's date.timezone is not set to a valid timezone" );
}
if ( isset($_GET['skin']) )
@ -82,7 +76,7 @@ elseif ( isset($_COOKIE['zmSkin']) )
elseif ( defined('ZM_SKIN_DEFAULT') )
$skin = ZM_SKIN_DEFAULT;
else
$skin = "classic";
$skin = 'classic';
$skins = array_map( 'basename', glob('skins/*',GLOB_ONLYDIR) );
if ( ! in_array( $skin, $skins ) ) {
@ -97,7 +91,7 @@ elseif ( isset($_COOKIE['zmCSS']) )
elseif (defined('ZM_CSS_DEFAULT'))
$css = ZM_CSS_DEFAULT;
else
$css = "classic";
$css = 'classic';
$css_skins = array_map( 'basename', glob('skins/'.$skin.'/css/*',GLOB_ONLYDIR) );
if ( ! in_array( $css, $css_skins ) ) {
@ -105,9 +99,9 @@ if ( ! in_array( $css, $css_skins ) ) {
$css = $css_skins[0];
}
define( "ZM_BASE_PATH", dirname( $_SERVER['REQUEST_URI'] ) );
define( "ZM_SKIN_NAME", $skin );
define( "ZM_SKIN_PATH", "skins/$skin" );
define( 'ZM_BASE_PATH', dirname( $_SERVER['REQUEST_URI'] ) );
define( 'ZM_SKIN_NAME', $skin );
define( 'ZM_SKIN_PATH', "skins/$skin" );
$skinBase = array(); // To allow for inheritance of skins
if ( !file_exists( ZM_SKIN_PATH ) )
@ -117,26 +111,25 @@ $skinBase[] = $skin;
$currentCookieParams = session_get_cookie_params();
Logger::Debug('Setting cookie parameters to lifetime('.$currentCookieParams['lifetime'].') path('.$currentCookieParams['path'].') domain ('.$currentCookieParams['domain'].') secure('.$currentCookieParams['secure'].') httpOnly(1)');
session_set_cookie_params(
$currentCookieParams["lifetime"],
$currentCookieParams["path"],
$currentCookieParams["domain"],
$currentCookieParams["secure"],
$currentCookieParams['lifetime'],
$currentCookieParams['path'],
$currentCookieParams['domain'],
$currentCookieParams['secure'],
true
);
ini_set( "session.name", "ZMSESSID" );
ini_set( 'session.name', 'ZMSESSID' );
session_start();
if ( !isset($_SESSION['skin']) || isset($_REQUEST['skin']) || !isset($_COOKIE['zmSkin']) || $_COOKIE['zmSkin'] != $skin )
{
if ( !isset($_SESSION['skin']) || isset($_REQUEST['skin']) || !isset($_COOKIE['zmSkin']) || $_COOKIE['zmSkin'] != $skin ) {
$_SESSION['skin'] = $skin;
setcookie( "zmSkin", $skin, time()+3600*24*30*12*10 );
setcookie( 'zmSkin', $skin, time()+3600*24*30*12*10 );
}
if ( !isset($_SESSION['css']) || isset($_REQUEST['css']) || !isset($_COOKIE['zmCSS']) || $_COOKIE['zmCSS'] != $css ) {
$_SESSION['css'] = $css;
setcookie( "zmCSS", $css, time()+3600*24*30*12*10 );
setcookie( 'zmCSS', $css, time()+3600*24*30*12*10 );
}
if ( ZM_OPT_USE_AUTH )
@ -149,14 +142,12 @@ else
require_once( 'includes/lang.php' );
require_once( 'includes/functions.php' );
require_once( 'includes/csrf/csrf-magic.php' );
# Add Cross domain access headers
CORSHeaders();
// Check for valid content dirs
if ( !is_writable(ZM_DIR_EVENTS) || !is_writable(ZM_DIR_IMAGES) )
{
if ( !is_writable(ZM_DIR_EVENTS) || !is_writable(ZM_DIR_IMAGES) ) {
Error( "Cannot write to content dirs('".ZM_DIR_EVENTS."','".ZM_DIR_IMAGES."'). Check that these exist and are owned by the web account user");
}
@ -177,58 +168,51 @@ isset($view) || $view = NULL;
isset($request) || $request = NULL;
isset($action) || $action = NULL;
if ( ZM_ENABLE_CSRF_MAGIC && $action != 'login' ) {
Logger::Debug("Calling csrf_check with the following values: \$request = \"$request\", \$view = \"$view\", \$action = \"$action\"");
csrf_check();
if ( ZM_ENABLE_CSRF_MAGIC && $action != 'login' && $view != 'view_video' ) {
require_once( 'includes/csrf/csrf-magic.php' );
Logger::Debug("Calling csrf_check with the following values: \$request = \"$request\", \$view = \"$view\", \$action = \"$action\"");
csrf_check();
}
require_once( 'includes/actions.php' );
# If I put this here, it protects all views and popups, but it has to go after actions.php because actions.php does the actual logging in.
if ( ZM_OPT_USE_AUTH && ! isset($user) && $view != 'login' ) {
$view = 'login';
$view = 'login';
}
# Only one request can open the session file at a time, so let's close the session here to improve concurrency.
# Any file/page that uses the session must re-open it.
session_write_close();
if ( isset( $_REQUEST['request'] ) )
{
foreach ( getSkinIncludes( 'ajax/'.$request.'.php', true, true ) as $includeFile )
{
if ( !file_exists( $includeFile ) )
Fatal( "Request '$request' does not exist" );
if ( isset( $_REQUEST['request'] ) ) {
foreach ( getSkinIncludes( 'ajax/'.$request.'.php', true, true ) as $includeFile ) {
if ( !file_exists( $includeFile ) )
Fatal( "Request '$request' does not exist" );
require_once $includeFile;
}
return;
} else {
if ( $includeFiles = getSkinIncludes( 'views/'.$view.'.php', true, true ) ) {
foreach ( $includeFiles as $includeFile ) {
if ( !file_exists( $includeFile ) )
Fatal( "View '$view' does not exist" );
require_once $includeFile;
}
// If the view overrides $view to 'error', and the user is not logged in, then the
// issue is probably resolvable by logging in, so provide the opportunity to do so.
// The login view should handle redirecting to the correct location afterward.
if ( $view == 'error' && !isset($user) ) {
$view = 'login';
foreach ( getSkinIncludes( 'views/login.php', true, true ) as $includeFile )
require_once $includeFile;
}
return;
}
else
{
if ( $includeFiles = getSkinIncludes( 'views/'.$view.'.php', true, true ) )
{
foreach ( $includeFiles as $includeFile )
{
if ( !file_exists( $includeFile ) )
Fatal( "View '$view' does not exist" );
require_once $includeFile;
}
// If the view overrides $view to 'error', and the user is not logged in, then the
// issue is probably resolvable by logging in, so provide the opportunity to do so.
// The login view should handle redirecting to the correct location afterward.
if ( $view == 'error' && !isset($user) )
{
$view = 'login';
foreach ( getSkinIncludes( 'views/login.php', true, true ) as $includeFile )
require_once $includeFile;
}
}
// If the view is missing or the view still returned error with the user logged in,
// then it is not recoverable.
if ( !$includeFiles || $view == 'error' )
{
foreach ( getSkinIncludes( 'views/error.php', true, true ) as $includeFile )
require_once $includeFile;
}
}
// If the view is missing or the view still returned error with the user logged in,
// then it is not recoverable.
if ( !$includeFiles || $view == 'error' ) {
foreach ( getSkinIncludes( 'views/error.php', true, true ) as $includeFile )
require_once $includeFile;
}
}
?>

View File

@ -125,6 +125,7 @@ $SLANG = array(
'AttrMaxScore' => 'Max. Score',
'AttrMonitorId' => 'Monitor Id',
'AttrMonitorName' => 'Monitor Name',
'AttrStateId' => 'Run State',
'AttrServer' => 'Server',
'AttrName' => 'Name',
'AttrNotes' => 'Notes',

View File

@ -336,14 +336,14 @@ th.table-th-sort span.table-th-sort-span {
float: right;
width: 12px;
height: 12px;
background: url("../graphics/arrow-s-u.gif") no-repeat 0 0;
background: url("/skins/classic/graphics/arrow-s-u.png") no-repeat 0 0;
}
th.table-th-sort-rev span.table-th-sort-span {
float: right;
width: 12px;
height: 12px;
background: url("../graphics/arrow-s-d.gif") no-repeat 0 0;
background: url("/skins/classic/graphics/arrow-s-d.png") no-repeat 0 0;
}
.table-tr-odd {

View File

@ -61,12 +61,8 @@
text-align: left;
}
#consoleTable .colOrder {
text-align: center;
}
#consoleTable .colMark {
width: 32px;
width: 62px;
text-align: center;
}
@ -85,13 +81,3 @@
#consoleTable .colLeftButtons input {
margin-right: 24px;
}
#consoleTable .colRightButtons {
text-align: right;
padding-right: 8px;
}
#consoleTable .colRightButtons input {
margin: 0 8px;
}

View File

@ -345,14 +345,14 @@ th.table-th-sort span.table-th-sort-span {
float: right;
width: 12px;
height: 12px;
background: url("../graphics/arrow-s-u.gif") no-repeat 0 0;
background: url("/skins/classic/graphics/arrow-s-u.png") no-repeat 0 0;
}
th.table-th-sort-rev span.table-th-sort-span {
float: right;
width: 12px;
height: 12px;
background: url("../graphics/arrow-s-d.gif") no-repeat 0 0;
background: url("/skins/classic/graphics/arrow-s-d.png") no-repeat 0 0;
}
.table-tr-odd {

View File

@ -61,12 +61,8 @@
text-align: left;
}
#consoleTable .colOrder {
text-align: center;
}
#consoleTable .colMark {
width: 32px;
width: 62px;
text-align: center;
}
@ -85,13 +81,3 @@
#consoleTable .colLeftButtons input {
margin-right: 24px;
}
#consoleTable .colRightButtons {
text-align: right;
padding-right: 8px;
}
#consoleTable .colRightButtons input {
margin: 0 8px;
}

View File

@ -333,14 +333,14 @@ th.table-th-sort span.table-th-sort-span {
float: right;
width: 12px;
height: 12px;
background: url("../graphics/arrow-s-u.gif") no-repeat 0 0;
background: url("/skins/classic/graphics/arrow-s-u.png") no-repeat 0 0;
}
th.table-th-sort-rev span.table-th-sort-span {
float: right;
width: 12px;
height: 12px;
background: url("../graphics/arrow-s-d.gif") no-repeat 0 0;
background: url("/skins/classic/graphics/arrow-s-d.png") no-repeat 0 0;
}
.table-tr-odd {

View File

@ -61,12 +61,8 @@
text-align: left;
}
#consoleTable .colOrder {
text-align: center;
}
#consoleTable .colMark {
width: 32px;
width: 62px;
text-align: center;
}
@ -85,13 +81,3 @@
#consoleTable .colLeftButtons input {
margin-right: 24px;
}
#consoleTable .colRightButtons {
text-align: right;
padding-right: 8px;
}
#consoleTable .colRightButtons input {
margin: 0 8px;
}

View File

@ -49,9 +49,7 @@ function xhtmlHeaders( $file, $title ) {
<link rel="shortcut icon" href="graphics/favicon.ico"/>
<link rel="stylesheet" href="css/reset.css" type="text/css"/>
<link rel="stylesheet" href="css/overlay.css" type="text/css"/>
<?php if ( in_array($basename, $new_views) ) { ?>
<link rel="stylesheet" href="css/bootstrap.min.css" type="text/css"/>
<?php } ?>
<link rel="stylesheet" href="<?php echo $skinCssFile ?>" type="text/css" media="screen"/>
<?php
if ( $viewCssFile ) {
@ -74,6 +72,19 @@ function xhtmlHeaders( $file, $title ) {
<script type="text/javascript" src="tools/mootools/mootools-core.js"></script>
<script type="text/javascript" src="tools/mootools/mootools-more.js"></script>
<script type="text/javascript" src="js/mootools.ext.js"></script>
<script type="text/javascript" src="skins/<?php echo $skin; ?>/js/jquery.js"></script>
<script type="text/javascript" src="skins/<?php echo $skin; ?>/js/jquery-ui.js"></script>
<script type="text/javascript" src="skins/<?php echo $skin; ?>/js/bootstrap.min.js"></script>
<script type="text/javascript">
//<![CDATA[
<!--
var $j = jQuery.noConflict();
// $j is now an alias to the jQuery function; creating the new alias is optional.
//-->
//]]>
</script>
<script type="text/javascript" src="js/logger.js"></script>
<script type="text/javascript" src="js/overlay.js"></script>
<?php if ( $title == 'Login' && (defined('ZM_OPT_USE_GOOG_RECAPTCHA') && ZM_OPT_USE_GOOG_RECAPTCHA) ) { ?>

1
web/skins/classic/js/jquery-ui.js vendored Symbolic link
View File

@ -0,0 +1 @@
jquery-ui-1.11.3.js

View File

@ -88,7 +88,6 @@ $maxHeight = 0;
$cycleCount = 0;
$minSequence = 0;
$maxSequence = 1;
$seqIdList = array();
$monitors = dbFetchAll( "select * from Monitors order by Sequence asc" );
$displayMonitors = array();
for ( $i = 0; $i < count($monitors); $i++ ) {
@ -99,12 +98,6 @@ for ( $i = 0; $i < count($monitors); $i++ ) {
continue;
}
$monitors[$i]['Show'] = true;
if ( empty($minSequence) || ($monitors[$i]['Sequence'] < $minSequence) ) {
$minSequence = $monitors[$i]['Sequence'];
}
if ( $monitors[$i]['Sequence'] > $maxSequence ) {
$maxSequence = $monitors[$i]['Sequence'];
}
$monitors[$i]['zmc'] = zmcStatus( $monitors[$i] );
$monitors[$i]['zma'] = zmaStatus( $monitors[$i] );
$monitors[$i]['ZoneCount'] = dbFetchOne( 'select count(Id) as ZoneCount from Zones where MonitorId = ?', 'ZoneCount', array($monitors[$i]['Id']) );
@ -125,27 +118,8 @@ for ( $i = 0; $i < count($monitors); $i++ ) {
if ( $maxHeight < $scaleHeight ) $maxHeight = $scaleHeight;
}
if ( $counts ) $monitors[$i] = array_merge( $monitors[$i], $counts );
$seqIdList[] = $monitors[$i]['Id'];
$displayMonitors[] = $monitors[$i];
}
$lastId = 0;
$seqIdUpList = array();
foreach ( $seqIdList as $seqId ) {
if ( !empty($lastId) )
$seqIdUpList[$seqId] = $lastId;
else
$seqIdUpList[$seqId] = $seqId;
$lastId = $seqId;
}
$lastId = 0;
$seqIdDownList = array();
foreach ( array_reverse($seqIdList) as $seqId ) {
if ( !empty($lastId) )
$seqIdDownList[$seqId] = $lastId;
else
$seqIdDownList[$seqId] = $seqId;
$lastId = $seqId;
}
$cycleWidth = $maxWidth;
$cycleHeight = $maxHeight;
@ -165,9 +139,6 @@ foreach( $displayMonitors as $monitor ) {
$zoneCount += $monitor['ZoneCount'];
}
$seqUpFile = getSkinFile( 'graphics/seq-u.png' );
$seqDownFile = getSkinFile( 'graphics/seq-d.png' );
$versionClass = (ZM_DYN_DB_VERSION&&(ZM_DYN_DB_VERSION!=ZM_VERSION))?'errorText':'';
$left_columns = 3;
@ -239,21 +210,14 @@ if ( ZM_OPT_USE_AUTH ) {
}
?>
<th class="colZones"><?php echo translate('Zones') ?></th>
<?php
if ( canEdit('Monitors') ) {
?>
<th class="colOrder"><?php echo translate('Order') ?></th>
<?php
}
?>
<th class="colMark"><?php echo translate('Mark') ?></th>
</tr>
</thead>
<tbody>
<tbody id="consoleTableBody">
<?php
foreach( $displayMonitors as $monitor ) {
?>
<tr>
<tr id="<?php echo 'monitor_id-'.$monitor['Id'] ?>">
<?php
if ( !$monitor['zmc'] ) {
$dclass = 'errorText';
@ -312,14 +276,10 @@ echo $Server->Name();
}
?>
<td class="colZones"><?php echo makePopupLink( '?view=zones&amp;mid='.$monitor['Id'], 'zmZones', array( 'zones', $monitor['Width'], $monitor['Height'] ), $monitor['ZoneCount'], $running && canView( 'Monitors' ) ) ?></td>
<?php
if ( canEdit('Monitors') ) {
?>
<td class="colOrder"><?php echo makeLink( '?view='.$view.'&amp;action=sequence&amp;mid='.$monitor['Id'].'&amp;smid='.$seqIdUpList[$monitor['Id']], '<img src="'.$seqUpFile.'" alt="Up"/>', $monitor['Sequence']>$minSequence ) ?><?php echo makeLink( '?view='.$view.'&amp;action=sequence&amp;mid='.$monitor['Id'].'&amp;smid='.$seqIdDownList[$monitor['Id']], '<img src="'.$seqDownFile.'" alt="Down"/>', $monitor['Sequence']<$maxSequence ) ?></td>
<?php
}
?>
<td class="colMark"><input type="checkbox" name="markMids[]" value="<?php echo $monitor['Id'] ?>" onclick="setButtonStates( this )"<?php if ( !canEdit( 'Monitors' ) ) { ?> disabled="disabled"<?php } ?>/></td>
<td class="colMark">
<input type="checkbox" name="markMids[]" value="<?php echo $monitor['Id'] ?>" onclick="setButtonStates( this )"<?php if ( !canEdit( 'Monitors' ) ) { ?> disabled="disabled"<?php } ?>/>
<span class="glyphicon glyphicon-sort"></span>
</td>
</tr>
<?php
}
@ -332,6 +292,8 @@ echo $Server->Name();
<input type="button" name="addBtn" value="<?php echo translate('AddNewMonitor') ?>" onclick="addMonitor( this )"/>
<!-- <?php echo makePopupButton( '?view=monitor', 'zmMonitor0', 'monitor', translate('AddNewMonitor'), (canEdit( 'Monitors' ) && !$user['MonitorIds']) ) ?> -->
<?php echo makePopupButton( '?view=filter&filter[terms][0][attr]=DateTime&filter[terms][0][op]=%3c&filter[terms][0][val]=now', 'zmFilter', 'filter', translate('Filters'), canView( 'Events' ) ) ?>
<input type="button" name="editBtn" value="<?php echo translate('Edit') ?>" onclick="editMonitor( this )" disabled="disabled"/>
<input type="button" name="deleteBtn" value="<?php echo translate('Delete') ?>" onclick="deleteMonitor( this )" disabled="disabled"/>
</td>
<?php
for ( $i = 0; $i < count($eventCounts); $i++ ) {
@ -342,10 +304,7 @@ for ( $i = 0; $i < count($eventCounts); $i++ ) {
}
?>
<td class="colZones"><?php echo $zoneCount ?></td>
<td class="colRightButtons" colspan="<?php echo canEdit('Monitors')?2:1 ?>">
<input type="button" name="editBtn" value="<?php echo translate('Edit') ?>" onclick="editMonitor( this )" disabled="disabled"/>
<input type="button" name="deleteBtn" value="<?php echo translate('Delete') ?>" onclick="deleteMonitor( this )" disabled="disabled"/>
</td>
<td class="colMark"></td>
</tr>
</tfoot>
</table>

View File

@ -151,7 +151,7 @@ if ( $Event->DefaultVideo() ) {
?>
<div id="videoFeed">
<video id="videoobj" class="video-js vjs-default-skin" width="<?php echo reScale( $Event->Width(), $scale ) ?>" height="<?php echo reScale( $Event->Height(), $scale ) ?>" data-setup='{ "controls": true, "playbackRates": [0.5, 1, 1.5, 2, 4, 8, 16, 32, 64, 128, 256], "autoplay": true, "preload": "auto", "plugins": { "zoomrotate": { "zoom": "<?php echo $Zoom ?>"}}}'>
<source src="<?php echo $Event->getStreamSrc( array( "mode=mpeg&format=h264" ) ); ?>" type="video/mp4">
<source src="<?php echo $Event->getStreamSrc( array( 'mode'=>'mpeg','format'=>'h264' ) ); ?>" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>

View File

@ -214,7 +214,7 @@ foreach ( $events as $event ) {
<td class="colThumbnail">
<?php
$imgSrc = '?view=image&amp;eid='.$event->Id().'&amp;fid='.$thumbData['FrameId'].'&amp;width='.$thumbData['Width'].'&amp;height='.$thumbData['Height'];
$streamSrc = getStreamSrc( array( "source=event", "mode=jpeg", "event=".$event->Id(), "scale=".$scale, "maxfps=".ZM_WEB_VIDEO_MAXFPS, "replay=single") );
$streamSrc = $event->getStreamSrc( array( 'mode'=>'jpeg', 'scale'=>$scale, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'replay'=>'single') );
$imgHtml = '<img id="thumbnail'.$event->id().'" src="'.$imgSrc.'" alt="'. validHtmlStr('Event '.$event->Id()) .'" style="width:'. validInt($thumbData['Width']) .'px;height:'. validInt( $thumbData['Height'] ).'px;" onmouseover="this.src=\''.$streamSrc.'\';" onmouseout="this.src=\''.$imgSrc.'\';"/>';

View File

@ -92,6 +92,7 @@ $attrTypes = array(
'DiskPercent' => translate('AttrDiskPercent'),
'DiskBlocks' => translate('AttrDiskBlocks'),
'SystemLoad' => translate('AttrSystemLoad'),
'StateId' => translate('AttrStateId'),
'ServerId' => translate('AttrServer'),
);
$opTypes = array(
@ -209,6 +210,15 @@ for ( $i = 0; isset($_REQUEST['filter']) && $i < count($_REQUEST['filter']['term
<script type="text/javascript">Calendar.setup( { inputField: "filter[terms][<?php echo $i ?>][val]", ifFormat: "%Y-%m-%d", showOthers: true, weekNumbers: false });</script>
<?php } ?>
</td>
<?php
} elseif ( $_REQUEST['filter']['terms'][$i]['attr'] == 'StateId' ) {
$states = array();
foreach ( dbFetchAll( 'SELECT Id,Name FROM States ORDER BY lower(Name) ASC' ) as $state_row ) {
$states[$state_row['Id']] = $state_row['Name'];
}
?>
<td><?php echo buildSelect( "filter[terms][$i][op]", $opTypes ); ?></td>
<td><?php echo buildSelect( "filter[terms][$i][val]", $states ); ?></td>
<?php
} elseif ( $_REQUEST['filter']['terms'][$i]['attr'] == 'Weekday' ) {
?>

View File

@ -74,6 +74,27 @@ function initPage() {
createPopup( '?view=version', 'zmVersion', 'version' );
if ( showDonatePopup )
createPopup( '?view=donate', 'zmDonate', 'donate' );
// Makes table sortable
$j( function() {
$j( "#consoleTableBody" ).sortable({
handle: ".glyphicon-sort",
update: applySort,
axis:'Y' } );
$j( "#consoleTableBody" ).disableSelection();
} );
}
function applySort(event, ui) {
var monitor_ids = $j(this).sortable('toArray');
var ajax = new Request.JSON( {
url: '/index.php?request=console',
data: { monitor_ids: monitor_ids, action: 'sort' },
method: 'post',
timeout: AJAX_TIMEOUT
} );
ajax.send();
} // end function applySort(event,ui)
window.addEvent( 'domready', initPage );

View File

@ -1,5 +1,5 @@
var logParms = "view=request&request=log&task=query";
var logReq = new Request.JSON( { url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: logResponse } );
var logReq = new Request.JSON( { url: thisUrl, method: 'get', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: logResponse } );
var logTimer = undefined;
var logTable = undefined;
@ -75,7 +75,7 @@ function logResponse( respObj ) {
var color = document.defaultView.getComputedStyle(row.tr, null).getPropertyValue('color');
var colorParts = color.match(/^rgb.*\((\d+),\s*(\d+),\s*(\d+)/);
rowOrigColor = '#' + parseInt(colorParts[1]).toString(16) + parseInt(colorParts[2]).toString(16) + parseInt(colorParts[3]).toString(16);
new Fx.Tween( row.tr, { duration: 10000, transition: Fx.Transitions.Sine } ).start( 'color', '#6495ED', rowOrigColor );
//new Fx.Tween( row.tr, { duration: 10000, transition: Fx.Transitions.Sine } ).start( 'color', '#6495ED', rowOrigColor );
}
}
);

View File

@ -77,33 +77,33 @@ function getMonitorObject( $mid = null ) {
} else {
$monitor = array(
'Id' => 0,
'Name' => "willbereplaced",
'Function' => "Monitor",
'Name' => 'willbereplaced',
'Function' => 'Monitor',
'Enabled' => true,
'LinkedMonitors' => "",
'Type' => "",
'Device' => "/dev/video0",
'Channel' => "0",
'LinkedMonitors' => '',
'Type' => '',
'Device' => '/dev/video0',
'Channel' => '0',
'Format' => 0x000000ff,
'Protocol' => "",
'Method' => "",
'Host' => "",
'Path' => "",
'Options' => "",
'Protocol' => '',
'Method' => '',
'Host' => '',
'Path' => '',
'Options' => '',
'Port' => "80",
'User' => "",
'Pass' => "",
'User' => '',
'Pass' => '',
'Colours' => 3,
'Palette' => 0,
'Width' => "320",
'Height' => "240",
'Orientation' => "0",
'Width' => '320',
'Height' => '240',
'Orientation' => '0',
'Deinterlacing' => 0,
'RTSPDescribe' => 0,
'SaveJPEGs' => "3",
'VideoWriter' => "0",
'SaveJPEGs' => '3',
'VideoWriter' => '0',
'EncoderParameters' => "# Lines beginning with # are a comment \n# For changing quality, use the crf option\n# 1 is best, 51 is worst quality\n#crf=23\n",
'RecordAudio' => "0",
'RecordAudio' => '0',
'LabelFormat' => '%N - %d/%m/%y %H:%M:%S',
'LabelX' => 0,
'LabelY' => 0,
@ -115,23 +115,23 @@ function getMonitorObject( $mid = null ) {
'StreamReplayBuffer' => 1000,
'AlarmFrameCount' => 1,
'Controllable' => 0,
'ControlId' => "",
'ControlId' => '',
'ControlType' => 0,
'ControlDevice' => "",
'ControlAddress' => "",
'AutoStopTimeout' => "",
'ControlDevice' => '',
'ControlAddress' => '',
'AutoStopTimeout' => '',
'TrackMotion' => 0,
'TrackDelay' => "",
'TrackDelay' => '',
'ReturnLocation' => -1,
'ReturnDelay' => "",
'ReturnDelay' => '',
'SectionLength' => 600,
'FrameSkip' => 0,
'MotionFrameSkip' => 0,
'EventPrefix' => 'Event-',
'AnalysisFPS' => "",
'AnalysisFPS' => '',
'AnalysisUpdateDelay' => 0,
'MaxFPS' => "",
'AlarmMaxFPS' => "",
'MaxFPS' => '',
'AlarmMaxFPS' => '',
'FPSReportInterval' => 1000,
'RefBlendPerc' => 6,
'AlarmRefBlendPerc' => 6,
@ -141,7 +141,7 @@ function getMonitorObject( $mid = null ) {
'SignalCheckColour' => '#0000c0',
'WebColour' => 'red',
'Exif' => '0',
'Triggers' => "",
'Triggers' => '',
'V4LMultiBuffer' => '',
'V4LCapturesPerFrame' => 1,
'ServerId' => $Server['Id'],
@ -160,7 +160,7 @@ if ( isset( $_REQUEST['newMonitor'] ) ) {
$newX10Monitor = $_REQUEST['newX10Monitor'];
} else {
$newMonitor = $monitor;
$newMonitor['Triggers'] = explode( ',', isset($monitor['Triggers'])?$monitor['Triggers']:"" );
$newMonitor['Triggers'] = explode( ',', isset($monitor['Triggers'])?$monitor['Triggers']:'' );
if ( ZM_OPT_X10 )
$newX10Monitor = $x10Monitor;
}
@ -239,9 +239,9 @@ $rtspFFMpegMethods = array(
);
$httpMethods = array(
'simple' => "Simple",
'regexp' => "Regexp",
'jpegTags' => "JPEG Tags"
'simple' => 'Simple',
'regexp' => 'Regexp',
'jpegTags' => 'JPEG Tags'
);
if ( !ZM_PCRE )
@ -264,7 +264,7 @@ if ( ZM_HAS_V4L1 ) {
$v4l1MaxChannels = 15;
$v4l1DeviceChannels = array();
for ( $i = 0; $i <= $v4l1MaxChannels; $i++ )
$v4l1DeviceChannels['$i'] = $i;
$v4l1DeviceChannels[$i] = $i;
$v4l1LocalPalettes = array(
translate('Grey') => 1,
@ -694,7 +694,7 @@ switch ( $tab ) {
<td>
<select name="monitorIds" size="4" multiple="multiple" onchange="updateLinkedMonitors( this )">
<?php
$monitors = dbFetchAll( "select Id,Name from Monitors order by Sequence asc" );
$monitors = dbFetchAll( 'select Id,Name from Monitors order by Sequence asc' );
if ( !empty($newMonitor['LinkedMonitors']) )
$monitorIds = array_flip( explode( ',', $newMonitor['LinkedMonitors'] ) );
else
@ -714,8 +714,14 @@ switch ( $tab ) {
<?php
if ( $newMonitor['Type'] != 'Local' && $newMonitor['Type'] != 'File' ) {
?>
<tr><td><?php echo translate('MaximumFPS') ?>&nbsp;(<?php echo makePopupLink('?view=optionhelp&amp;option=OPTIONS_MAXFPS', 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td><td><input type="text" onclick="document.getElementById('newMonitor[MaxFPS]').innerHTML= ' CAUTION: See the help text'" name="newMonitor[MaxFPS]" value="<?php echo validHtmlStr($newMonitor['MaxFPS']) ?>" size="5"/><span id="newMonitor[MaxFPS]" style="color:red"></span></td></tr>
<tr><td><?php echo translate('AlarmMaximumFPS') ?>&nbsp;(<?php echo makePopupLink('?view=optionhelp&amp;option=OPTIONS_MAXFPS', 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td><td><input type="text" onclick="document.getElementById('newMonitor[AlarmMaxFPS]').innerHTML= ' CAUTION: See the help text'" name="newMonitor[AlarmMaxFPS]" value="<?php echo validHtmlStr($newMonitor['AlarmMaxFPS']) ?>" size="5"/><span id="newMonitor[AlarmMaxFPS]" style="color:red"></span></td></tr>
<tr>
<td><?php echo translate('MaximumFPS') ?>&nbsp;(<?php echo makePopupLink('?view=optionhelp&amp;option=OPTIONS_MAXFPS', 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td>
<td><input type="text" onclick="document.getElementById('newMonitor[MaxFPS]').innerHTML= ' CAUTION: See the help text'" name="newMonitor[MaxFPS]" value="<?php echo validHtmlStr($newMonitor['MaxFPS']) ?>" size="5"/><span id="newMonitor[MaxFPS]" style="color:red"></span></td>
</tr>
<tr>
<td><?php echo translate('AlarmMaximumFPS') ?>&nbsp;(<?php echo makePopupLink('?view=optionhelp&amp;option=OPTIONS_MAXFPS', 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td>
<td><input type="text" onclick="document.getElementById('newMonitor[AlarmMaxFPS]').innerHTML= ' CAUTION: See the help text'" name="newMonitor[AlarmMaxFPS]" value="<?php echo validHtmlStr($newMonitor['AlarmMaxFPS']) ?>" size="5"/><span id="newMonitor[AlarmMaxFPS]" style="color:red"></span></td>
</tr>
<?php
} else {
?>

View File

@ -40,6 +40,16 @@ $maxHeight = 0;
$showControl = false;
$index = 0;
$monitors = array();
$scale = 100;
if ( isset( $_REQUEST['scale'] ) )
$scale = validInt($_REQUEST['scale']);
else if ( isset( $_COOKIE['zmMontageScale'] ) )
$scale = $_COOKIE['zmMontageScale'];
if ( ! $scale )
$scale = 100;
foreach( dbFetchAll( $sql ) as $row )
{
if ( !visibleMonitor( $row['Id'] ) )
@ -47,14 +57,17 @@ foreach( dbFetchAll( $sql ) as $row )
continue;
}
$monitor_scale = 100;
if ( isset( $_REQUEST['scale'] ) )
$scale = validInt($_REQUEST['scale']);
$monitor_scale = validInt($_REQUEST['scale']);
else if ( isset( $_COOKIE['zmMontageScale'] ) )
$scale = $_COOKIE['zmMontageScale'];
$monitor_scale = $_COOKIE['zmMontageScale'];
else
$scale = reScale( SCALE_BASE, $row['DefaultScale'], ZM_WEB_DEFAULT_SCALE );
$monitor_scale = reScale( SCALE_BASE, $row['DefaultScale'], ZM_WEB_DEFAULT_SCALE );
if ( ! $monitor_scale )
$monitor_scale = 100;
$scaleWidth = reScale( $row['Width'], $scale );
$scaleWidth = reScale( $row['Width'], $monitor_scale );
$scaleHeight = reScale( $row['Height'], $scale );
if ( $maxWidth < $scaleWidth )
$maxWidth = $scaleWidth;
@ -117,14 +130,11 @@ foreach ( $monitors as $monitor )
<div id="monitor<?php echo $monitor->index() ?>" class="monitor idle">
<div id="imageFeed<?php echo $monitor->index() ?>" class="imageFeed" onclick="createPopup( '?view=watch&amp;mid=<?php echo $monitor->Id() ?>', 'zmWatch<?php echo $monitor->Id() ?>', 'watch', <?php echo $monitor->scaleWidth() ?>, <?php echo $monitor->scaleHeight() ?> );">
<?php
if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT )
{
$streamSrc = $monitor->getStreamSrc( array( "mode=mpeg", "scale=".$scale, "bitrate=".ZM_WEB_VIDEO_BITRATE, "maxfps=".ZM_WEB_VIDEO_MAXFPS, "format=".ZM_MPEG_LIVE_FORMAT ) );
if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
$streamSrc = $monitor->getStreamSrc( array( 'mode'=>'mpeg', 'scale'=>$scale, 'bitrate'=>ZM_WEB_VIDEO_BITRATE, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'format'=>ZM_MPEG_LIVE_FORMAT ) );
outputVideoStream( "liveStream".$monitor->Id(), $streamSrc, reScale( $monitor->Width(), $scale ), reScale( $monitor->Height(), $scale ), ZM_MPEG_LIVE_FORMAT );
}
else
{
$streamSrc = $monitor->getStreamSrc( array( "mode=jpeg", "scale=".$scale, "maxfps=".ZM_WEB_VIDEO_MAXFPS ) );
} else {
$streamSrc = $monitor->getStreamSrc( array( 'mode'=>'jpeg', 'scale'=>$scale, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS ) );
if ( canStreamNative() )
{
outputImageStream( "liveStream".$monitor->Id(), $streamSrc, reScale( $monitor->Width(), $scale ), reScale( $monitor->Height(), $scale ), validHtmlStr($monitor->Name()) );

View File

@ -31,7 +31,6 @@ $tabs['skins'] = translate('Display');
$tabs['system'] = translate('System');
$tabs['config'] = translate('Config');
$tabs['servers'] = translate('Servers');
$tabs['paths'] = translate('Paths');
$tabs['web'] = translate('Web');
$tabs['images'] = translate('Images');
$tabs['logging'] = translate('Logging');

View File

@ -50,3 +50,43 @@ ZM_DB_USER=@ZM_DB_USER@
# ZoneMinder database password
ZM_DB_PASS=@ZM_DB_PASS@
# Full path to the folder events are recorded to.
# The web account user must have full read/write permission to this folder.
ZM_DIR_EVENTS=@ZM_DIR_EVENTS@
# Full path to the folder images, not directly associated with events,
# are recorded to.
# The web account user must have full read/write permission to this folder.
ZM_DIR_IMAGES=@ZM_DIR_IMAGES@
# Foldername under the webroot where ZoneMinder looks for optional sound files
# to play when an alarm is detected.
ZM_DIR_SOUNDS=@ZM_DIR_SOUNDS@
# Full path to the folder where exported archives are stored
# The web account user must have full read/write permission to this folder.
ZM_DIR_EXPORTS=@ZM_TMPDIR@
# ZoneMinder url path to the zms streaming server
ZM_PATH_ZMS=@ZM_PATH_ZMS@
# Full Path to ZoneMinder's mapped memory files
# The web account user must have full read/write permission to this folder.
ZM_PATH_MAP=@ZM_PATH_MAP@
# Full Path to ZoneMinder's socket folder
# The web account user must have full read/write permission to this folder.
ZM_PATH_SOCKS=@ZM_SOCKDIR@
# Full path to ZoneMinder's log folder
# The web account user must have full read/write permission to this folder.
ZM_PATH_LOGS=@ZM_LOGDIR@
# Full path to ZoneMinder's swap folder
# The web account user must have full read/write permission to this folder.
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@