Merge branch 'master' into api_auth
This commit is contained in:
commit
3bc1816cdf
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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;
|
||||
|
|
@ -6,3 +6,4 @@ usr/share/perl5/ZoneMinder.pm
|
|||
usr/share/zoneminder/db
|
||||
usr/share/zoneminder/www
|
||||
etc/zm
|
||||
etc/zm/conf.d/*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1 +1 @@
|
|||
../redhat/redalert.wav
|
||||
../redhat/misc/redalert.wav
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
etc/zm/zm.conf
|
||||
etc/zm/conf.d/*
|
||||
usr/bin
|
||||
usr/lib/zoneminder
|
||||
usr/share/polkit-1
|
||||
|
|
|
@ -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#
|
||||
|
|
|
@ -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...
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
etc/zm
|
||||
etc/zm/conf.d/*
|
||||
usr/bin
|
||||
usr/share/polkit-1/actions
|
||||
usr/share/polkit-1/rules.d
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
etc/zm/zm.conf
|
||||
etc/zm/conf.d/*
|
||||
usr/bin
|
||||
usr/lib/zoneminder
|
||||
usr/share/polkit-1
|
||||
|
|
|
@ -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#
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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!!" );
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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 ) ) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ) ) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -24,6 +24,10 @@ extern "C" {
|
|||
#include <libavformat/avformat.h>
|
||||
}
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/time.h>
|
||||
#endif // __FreeBSD__
|
||||
|
||||
class ZMPacket {
|
||||
public:
|
||||
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
849
src/zm_video.cpp
849
src/zm_video.cpp
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -77,6 +77,7 @@ protected:
|
|||
|
||||
// Outputs/Statistics
|
||||
bool alarmed;
|
||||
bool was_alarmed;
|
||||
int pixel_diff;
|
||||
unsigned int alarm_pixels;
|
||||
int alarm_filter_pixels;
|
||||
|
|
151
src/zms.cpp
151
src/zms.cpp
|
@ -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 );
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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' :
|
||||
|
|
|
@ -1283,6 +1283,7 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) {
|
|||
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 ) {
|
||||
|
|
152
web/index.php
152
web/index.php
|
@ -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;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -125,6 +125,7 @@ $SLANG = array(
|
|||
'AttrMaxScore' => 'Max. Score',
|
||||
'AttrMonitorId' => 'Monitor Id',
|
||||
'AttrMonitorName' => 'Monitor Name',
|
||||
'AttrStateId' => 'Run State',
|
||||
'AttrServer' => 'Server',
|
||||
'AttrName' => 'Name',
|
||||
'AttrNotes' => 'Notes',
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) ) { ?>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
jquery-ui-1.11.3.js
|
|
@ -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&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.'&action=sequence&mid='.$monitor['Id'].'&smid='.$seqIdUpList[$monitor['Id']], '<img src="'.$seqUpFile.'" alt="Up"/>', $monitor['Sequence']>$minSequence ) ?><?php echo makeLink( '?view='.$view.'&action=sequence&mid='.$monitor['Id'].'&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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -214,7 +214,7 @@ foreach ( $events as $event ) {
|
|||
<td class="colThumbnail">
|
||||
<?php
|
||||
$imgSrc = '?view=image&eid='.$event->Id().'&fid='.$thumbData['FrameId'].'&width='.$thumbData['Width'].'&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.'\';"/>';
|
||||
|
||||
|
|
|
@ -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' ) {
|
||||
?>
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -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') ?> (<?php echo makePopupLink('?view=optionhelp&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') ?> (<?php echo makePopupLink('?view=optionhelp&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') ?> (<?php echo makePopupLink('?view=optionhelp&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') ?> (<?php echo makePopupLink('?view=optionhelp&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 {
|
||||
?>
|
||||
|
|
|
@ -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&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()) );
|
||||
|
|
|
@ -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');
|
||||
|
|
40
zm.conf.in
40
zm.conf.in
|
@ -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@
|
||||
|
||||
|
|
Loading…
Reference in New Issue