mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-11-05 04:02:56 -05:00
Merge branch 'master' of github.com:zoneminder/ZoneMinder
This commit is contained in:
commit
dbb2535a6b
190 files changed
+16148
-4638
No files matched your search
@@ -3,6 +3,7 @@
|
||||
module.exports = {
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
},
|
||||
"extends": ["google"],
|
||||
"overrides": [{
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
# Configuration for probot-stale - https://github.com/probot/stale
|
||||
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 60
|
||||
daysUntilStale: 180
|
||||
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
daysUntilClose: 30
|
||||
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
|
||||
+5
-10
@@ -32,25 +32,20 @@ install:
|
||||
- update-binfmts --enable qemu-arm
|
||||
|
||||
env:
|
||||
- SMPFLAGS=-j4 OS=el DIST=7
|
||||
- SMPFLAGS=-j4 OS=eslint DIST=eslint
|
||||
- SMPFLAGS=-j4 OS=el DIST=7 DOCKER_REPO=knnniggett/packpack
|
||||
- SMPFLAGS=-j4 OS=el DIST=8 DOCKER_REPO=knnniggett/packpack
|
||||
- SMPFLAGS=-j4 OS=fedora DIST=30
|
||||
- SMPFLAGS=-j4 OS=fedora DIST=31
|
||||
- SMPFLAGS=-j4 OS=fedora DIST=31 DOCKER_REPO=knnniggett/packpack
|
||||
- SMPFLAGS=-j4 OS=fedora DIST=32 DOCKER_REPO=knnniggett/packpack
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=trusty DOCKER_REPO=iconzm/packpack
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=xenial DOCKER_REPO=iconzm/packpack
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=bionic DOCKER_REPO=iconzm/packpack
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=disco DOCKER_REPO=iconzm/packpack
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=eoan DOCKER_REPO=iconzm/packpack
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=eoan DOCKER_REPO=knnniggett/packpack:ubuntu-eoan
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=focal DOCKER_REPO=iconzm/packpack
|
||||
- SMPFLAGS=-j4 OS=debian DIST=jessie DOCKER_REPO=iconzm/packpack
|
||||
- SMPFLAGS=-j4 OS=debian DIST=stretch DOCKER_REPO=iconzm/packpack
|
||||
- SMPFLAGS=-j4 OS=debian DIST=buster DOCKER_REPO=iconzm/packpack
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=trusty ARCH=i386
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=xenial ARCH=i386
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=disco ARCH=i386
|
||||
- SMPFLAGS=-j4 OS=debian DIST=buster ARCH=i386
|
||||
- SMPFLAGS=-j4 OS=debian DIST=stretch ARCH=i386
|
||||
- SMPFLAGS=-j4 OS=eslint DIST=eslint
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
|
||||
@@ -899,7 +899,6 @@ configure_file(zmlinkcontent.sh.in "${CMAKE_CURRENT_BINARY_DIR}/zmlinkcontent.sh
|
||||
|
||||
# Create a target for man pages
|
||||
include(Pod2Man)
|
||||
ADD_MANPAGE_TARGET()
|
||||
|
||||
# Process subdirectories
|
||||
|
||||
|
||||
@@ -53,8 +53,7 @@ MACRO(POD2MAN PODFILE MANFILE SECTION MANPAGE_DEST_PREFIX)
|
||||
|
||||
SET(MANPAGE_TARGET "man-${MANFILE}")
|
||||
|
||||
ADD_CUSTOM_TARGET(${MANPAGE_TARGET} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${MANFILE}.${SECTION}.gz)
|
||||
ADD_DEPENDENCIES(man ${MANPAGE_TARGET})
|
||||
ADD_CUSTOM_TARGET(${MANPAGE_TARGET} ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${MANFILE}.${SECTION}.gz)
|
||||
|
||||
INSTALL(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/${MANFILE}.${SECTION}.gz
|
||||
|
||||
@@ -46,3 +46,6 @@ ZM_PATH_SWAP=@ZM_TMPDIR@
|
||||
# Full path to optional arp binary
|
||||
# ZoneMinder will find the arp binary automatically on most systems
|
||||
ZM_PATH_ARP="@ZM_PATH_ARP@"
|
||||
|
||||
#Full path to shutdown binary
|
||||
ZM_PATH_SHUTDOWN="@ZM_PATH_SHUTDOWN@"
|
||||
@@ -282,6 +282,7 @@ DROP TABLE IF EXISTS `Filters`;
|
||||
CREATE TABLE `Filters` (
|
||||
`Id` int(10) unsigned NOT NULL auto_increment,
|
||||
`Name` varchar(64) NOT NULL default '',
|
||||
`UserId` int(10) unsigned,
|
||||
`Query_json` text NOT NULL,
|
||||
`AutoArchive` tinyint(3) unsigned NOT NULL default '0',
|
||||
`AutoVideo` tinyint(3) unsigned NOT NULL default '0',
|
||||
@@ -787,6 +788,7 @@ INSERT INTO `Filters`
|
||||
`AutoCopy`,
|
||||
`AutoCopyTo`,
|
||||
`UpdateDiskSpace`,
|
||||
`UserId`,
|
||||
`Background`,
|
||||
`Concurrent`
|
||||
)
|
||||
@@ -807,6 +809,7 @@ INSERT INTO `Filters`
|
||||
0/*AutoMove*/,0/*MoveTo*/,
|
||||
0/*AutoCopy*/,0/*CopyTo*/,
|
||||
0/*UpdateDiskSpace*/,
|
||||
1/*UserId = admin*/,
|
||||
1/*Background*/,
|
||||
0/*Concurrent*/
|
||||
);
|
||||
@@ -830,6 +833,7 @@ INSERT INTO `Filters`
|
||||
`AutoCopy`,
|
||||
`AutoCopyTo`,
|
||||
`UpdateDiskSpace`,
|
||||
`UserId`,
|
||||
`Background`,
|
||||
`Concurrent`
|
||||
)
|
||||
@@ -849,6 +853,7 @@ VALUES (
|
||||
0/*AutoMove*/,0/*MoveTo*/,
|
||||
0/*AutoCopy*/,0/*CopyTo*/,
|
||||
1/*UpdateDiskSpace*/,
|
||||
1/*UserId=admin*/,
|
||||
1/*Background*/,
|
||||
0/*Concurrent*/
|
||||
);
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Filters'
|
||||
AND column_name = 'UserId'
|
||||
) > 0,
|
||||
"SELECT 'Column UserId already exists in Filters'",
|
||||
"ALTER TABLE `Filters` ADD `UserId` int(10) unsigned AFTER `Name`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
@@ -0,0 +1,2 @@
|
||||
/* This was done in 1.31.0 but zm_create.sql.in wasn't updated to match */
|
||||
ALTER TABLE Monitors MODIFY LinkedMonitors varchar(255);
|
||||
@@ -0,0 +1,10 @@
|
||||
zoneminder (1.28.1-1) unstable; urgency=low
|
||||
|
||||
This version is no longer automatically initialize or upgrade database.
|
||||
See README.Debian for details.
|
||||
|
||||
Changed installation paths (please correct your web server configuration):
|
||||
/usr/share/zoneminder --> /usr/share/zoneminder/www
|
||||
/usr/lib/cgi-bin --> /usr/lib/zoneminder/cgi-bin
|
||||
|
||||
-- Dmitry Smirnov <onlyjob@debian.org> Tue, 31 Mar 2015 15:12:17 +1100
|
||||
@@ -0,0 +1,130 @@
|
||||
Zoneminder for Debian
|
||||
---------------------
|
||||
|
||||
Initializing database
|
||||
---------------------
|
||||
|
||||
pv /usr/share/zoneminder/db/zm_create.sql | sudo mysql --defaults-file=/etc/mysql/debian.cnf
|
||||
OR
|
||||
cat /usr/share/zoneminder/db/zm_create.sql | sudo mysql --defaults-file=/etc/mysql/debian.cnf
|
||||
|
||||
echo 'grant lock tables,alter,create,index,select,insert,update,delete on zm.* to 'zmuser'@localhost identified by "zmpass";'\
|
||||
| sudo mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||
|
||||
Hint: generate secure password with `pwgen` and update "/etc/zm/zm.conf"
|
||||
accordingly.
|
||||
|
||||
The following command can help to ensure that zoneminder can read its
|
||||
configuration file:
|
||||
|
||||
chgrp -c www-data /etc/zm/zm.conf
|
||||
|
||||
|
||||
Upgrading database
|
||||
------------------
|
||||
|
||||
The database is updated automatically on installation. You should not need to take this step.
|
||||
|
||||
Assuming that database is on "localhost" then the following command can be
|
||||
used to upgrade "zm" database:
|
||||
|
||||
zmupdate.pl
|
||||
|
||||
Additional permissions may be required to perform upgrade:
|
||||
|
||||
echo 'grant lock tables, create, alter on zm.* to 'zmuser'@localhost identified by "zmpass";'\
|
||||
| sudo mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||
|
||||
The following command prints the current version of zoneminder database:
|
||||
|
||||
echo 'select Value from Config where Name = "ZM_DYN_CURR_VERSION";' \
|
||||
| sudo mysql --defaults-file=/etc/mysql/debian.cnf --skip-column-names zm
|
||||
|
||||
|
||||
Enabling service
|
||||
----------------
|
||||
|
||||
By default Zoneminder service is not automatically started and needs to be
|
||||
manually enabled once database is configured:
|
||||
|
||||
sudo systemctl enable zoneminder.service
|
||||
|
||||
|
||||
Web server set-up
|
||||
-----------------
|
||||
|
||||
There are few manual steps to get the web interface working:
|
||||
|
||||
## Apache2
|
||||
|
||||
Apache can be configured as folder "/zm" using sample .conf:
|
||||
|
||||
sudo a2enconf zoneminder
|
||||
|
||||
Alternatively Apache web site configuration template can be used to setup
|
||||
zoneminder as "http://zoneminder":
|
||||
|
||||
sudo cp -v /usr/share/doc/zoneminder/examples/apache.conf /etc/apache2/sites-available/
|
||||
sudo a2ensite zoneminder.conf
|
||||
|
||||
Common configuration steps for Apache2:
|
||||
|
||||
sudo a2enmod cgi
|
||||
sudo service apache2 reload
|
||||
|
||||
|
||||
## nginx / fcgiwrap
|
||||
|
||||
Nginx needs "php-fpm" package to support PHP and "fcgiwrap" package
|
||||
for binary "cgi-bin" applications:
|
||||
|
||||
sudo apt-get install php-fpm fcgiwrap
|
||||
|
||||
To enable a URL alias that makes Zoneminder available from
|
||||
|
||||
http://yourserver/zm
|
||||
|
||||
the following line is to be added to "server" section of a web site
|
||||
configuration:
|
||||
|
||||
include /usr/share/doc/zoneminder/examples/nginx.conf;
|
||||
|
||||
For "default" web site it would be sufficient to include the above
|
||||
statement to the file
|
||||
|
||||
/etc/nginx/sites-enabled/default
|
||||
|
||||
To avoid problems with feeds from multiple cameras "fcgiwrap" should be
|
||||
configured to start at least as many processes as there are cameras.
|
||||
It can be done by adjusting DAEMON_OPTS in "/etc/default/fcgiwrap".
|
||||
Systemd users may be affected by the following bug:
|
||||
|
||||
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=792705
|
||||
|
||||
|
||||
## Note:
|
||||
|
||||
When Zoneminder web site is running it may be necessary to set
|
||||
Options/Paths/PATH_ZMS to "/zm/cgi-bin/nph-zms" or according to chosen web
|
||||
site configuration.
|
||||
|
||||
|
||||
Changing the location for images and events
|
||||
-------------------------------------------
|
||||
|
||||
ZoneMinder is now able to be configured to use an alternative location for storing
|
||||
events and images at compile time. This package makes use of that, so symlinks in
|
||||
/usr/share/zoneminder/www are no longer necessary.
|
||||
|
||||
Access to /dev/video*
|
||||
---------------------
|
||||
|
||||
For cameras which require access to /dev/video*, zoneminder may need the
|
||||
www-data user added to the video group in order to see those cameras:
|
||||
|
||||
adduser www-data video
|
||||
|
||||
Note that all web applications running on the zoneminder server will then have
|
||||
access to all video devices on the system.
|
||||
|
||||
-- Vagrant Cascadian <vagrant@debian.org> Sun, 27 Mar 2011 13:06:56 -0700
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
## Separate substantial /usr/share into its own arch-all package.
|
||||
|
||||
## Decide how to handle database updates.
|
||||
|
||||
* Consider possibility that database may be on another machine (#469239).
|
||||
* Consider dbconfig-common? Probably not (what if database is not on localhost?).
|
||||
|
||||
### Run `zmupdate.pl` from service control scripts (init.d, service) on start?
|
||||
|
||||
Automatic upgrade will break "one DB, many zoneminders" setup (unimportant?).
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
zoneminder (1.31.39~20180223.27-stretch-1) unstable; urgency=low
|
||||
*
|
||||
-- Isaac Connor <iconnor@connortechnology.com> Fri, 23 Feb 2018 14:15:59 -0500
|
||||
@@ -0,0 +1,3 @@
|
||||
.gitattributes
|
||||
web/api/.gitattributes
|
||||
web/api/.gitignore
|
||||
@@ -0,0 +1 @@
|
||||
9
|
||||
@@ -0,0 +1,57 @@
|
||||
# Remember to enable cgi mod (i.e. "a2enmod cgi").
|
||||
ScriptAlias /zm/cgi-bin "/usr/lib/zoneminder/cgi-bin"
|
||||
<Directory "/usr/lib/zoneminder/cgi-bin">
|
||||
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
|
||||
AllowOverride All
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
|
||||
# Order matters. This alias must come first.
|
||||
Alias /zm/cache /var/cache/zoneminder/cache
|
||||
<Directory /var/cache/zoneminder/cache>
|
||||
Options -Indexes +FollowSymLinks
|
||||
AllowOverride None
|
||||
<IfModule mod_authz_core.c>
|
||||
# Apache 2.4
|
||||
Require all granted
|
||||
</IfModule>
|
||||
<IfModule !mod_authz_core.c>
|
||||
# Apache 2.2
|
||||
Order deny,allow
|
||||
Allow from all
|
||||
</IfModule>
|
||||
</Directory>
|
||||
|
||||
Alias /zm /usr/share/zoneminder/www
|
||||
<Directory /usr/share/zoneminder/www>
|
||||
Options -Indexes +FollowSymLinks
|
||||
<IfModule mod_dir.c>
|
||||
DirectoryIndex index.php
|
||||
</IfModule>
|
||||
</Directory>
|
||||
|
||||
# For better visibility, the following directives have been migrated from the
|
||||
# default .htaccess files included with the CakePHP project.
|
||||
# Parameters not set here are inherited from the parent directive above.
|
||||
<Directory "/usr/share/zoneminder/www/api">
|
||||
RewriteEngine on
|
||||
RewriteRule ^$ app/webroot/ [L]
|
||||
RewriteRule (.*) app/webroot/$1 [L]
|
||||
RewriteBase /zm/api
|
||||
</Directory>
|
||||
|
||||
<Directory "/usr/share/zoneminder/www/api/app">
|
||||
RewriteEngine on
|
||||
RewriteRule ^$ webroot/ [L]
|
||||
RewriteRule (.*) webroot/$1 [L]
|
||||
RewriteBase /zm/api
|
||||
</Directory>
|
||||
|
||||
<Directory "/usr/share/zoneminder/www/api/app/webroot">
|
||||
RewriteEngine On
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ index.php [L]
|
||||
RewriteBase /zm/api
|
||||
</Directory>
|
||||
@@ -0,0 +1,166 @@
|
||||
Source: zoneminder
|
||||
Section: net
|
||||
Priority: optional
|
||||
Maintainer: Isaac Connor <isaac@zoneminder.com>
|
||||
Uploaders: Isaac Connor <isaac@zoneminder.com>
|
||||
Build-Depends: debhelper, sphinx-doc, dh-linktree, dh-apache2
|
||||
,cmake
|
||||
,libx264-dev, libmp4v2-dev
|
||||
,libavdevice-dev
|
||||
,libavcodec-dev
|
||||
,libavformat-dev
|
||||
,libavutil-dev
|
||||
,libswresample-dev
|
||||
,libswscale-dev
|
||||
,ffmpeg
|
||||
,net-tools
|
||||
,libbz2-dev
|
||||
,libgcrypt20-dev
|
||||
,libcurl4-gnutls-dev
|
||||
,libturbojpeg0-dev
|
||||
,default-libmysqlclient-dev | libmysqlclient-dev | libmariadbclient-dev-compat
|
||||
,libpcre3-dev
|
||||
,libpolkit-gobject-1-dev
|
||||
,libv4l-dev [!hurd-any]
|
||||
,libvlc-dev
|
||||
,libdate-manip-perl
|
||||
,libdbd-mysql-perl
|
||||
,libphp-serialization-perl
|
||||
,libsys-mmap-perl [!hurd-any]
|
||||
,libwww-perl
|
||||
,libdata-uuid-perl
|
||||
,libssl-dev
|
||||
,libcrypt-eksblowfish-perl
|
||||
,libdata-entropy-perl
|
||||
# Unbundled (dh_linktree):
|
||||
,libjs-jquery
|
||||
,libjs-mootools
|
||||
Standards-Version: 3.9.8
|
||||
Homepage: http://www.zoneminder.com/
|
||||
Vcs-Browser: http://anonscm.debian.org/cgit/collab-maint/zoneminder.git
|
||||
Vcs-Git: git://anonscm.debian.org/collab-maint/zoneminder.git
|
||||
|
||||
Package: zoneminder
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
|
||||
,javascript-common
|
||||
,libmp4v2-2, libx264-155
|
||||
,libswscale5
|
||||
,libswresample3
|
||||
,ffmpeg
|
||||
,libdate-manip-perl, libmime-lite-perl, libmime-tools-perl
|
||||
,libdbd-mysql-perl
|
||||
,libphp-serialization-perl
|
||||
,libmodule-load-conditional-perl
|
||||
,libnet-sftp-foreign-perl
|
||||
,libarchive-zip-perl
|
||||
,libdbd-mysql-perl
|
||||
,libdevice-serialport-perl
|
||||
,libimage-info-perl
|
||||
,libjson-maybexs-perl
|
||||
,libsys-mmap-perl [!hurd-any]
|
||||
,liburi-encode-perl
|
||||
,libwww-perl, liburi-perl
|
||||
,libdata-dump-perl
|
||||
,libdatetime-perl
|
||||
,libclass-std-fast-perl
|
||||
,libsoap-wsdl-perl
|
||||
,libio-socket-multicast-perl
|
||||
,libdigest-sha-perl
|
||||
,libsys-cpu-perl, libsys-meminfo-perl
|
||||
,libdata-uuid-perl
|
||||
,libnumber-bytes-human-perl
|
||||
,libfile-slurp-perl
|
||||
,mysql-client | mariadb-client | virtual-mysql-client
|
||||
,perl-modules
|
||||
,php-mysql, php-gd, php-apcu, php-apc | php-apcu-bc, php-json
|
||||
,policykit-1
|
||||
,rsyslog | system-log-daemon
|
||||
,zip
|
||||
,libpcre3
|
||||
,libcrypt-eksblowfish-perl
|
||||
,libdata-entropy-perl
|
||||
Recommends: ${misc:Recommends}
|
||||
,libapache2-mod-php | php-fpm
|
||||
,mysql-server | mariadb-server | virtual-mysql-server
|
||||
,zoneminder-doc (>= ${source:Version})
|
||||
,ffmpeg
|
||||
Suggests: fcgiwrap, logrotate
|
||||
Description: video camera security and surveillance solution
|
||||
ZoneMinder is intended for use in single or multi-camera video security
|
||||
applications, including commercial or home CCTV, theft prevention and child
|
||||
or family member or home monitoring and other care scenarios. It
|
||||
supports capture, analysis, recording, and monitoring of video data coming
|
||||
from one or more video or network cameras attached to a Linux system.
|
||||
ZoneMinder also support web and semi-automatic control of Pan/Tilt/Zoom
|
||||
cameras using a variety of protocols. It is suitable for use as a home
|
||||
video security system and for commercial or professional video security
|
||||
and surveillance. It can also be integrated into a home automation system
|
||||
via X.10 or other protocols.
|
||||
|
||||
#Package: libzoneminder-perl
|
||||
#Section: perl
|
||||
#Architecture: all
|
||||
#Multi-Arch: foreign
|
||||
#Depends: ${misc:Depends}, ${perl:Depends}
|
||||
# ,libarchive-zip-perl
|
||||
# ,libdbd-mysql-perl
|
||||
# ,libdevice-serialport-perl
|
||||
# ,libimage-info-perl
|
||||
# ,libjson-maybexs-perl
|
||||
# ,libsys-mmap-perl [!hurd-any]
|
||||
# ,liburi-encode-perl
|
||||
# ,libwww-perl
|
||||
#Description: ZoneMinder Perl libraries
|
||||
# ZoneMinder is intended for use in single or multi-camera video security
|
||||
# applications, including commercial or home CCTV, theft prevention and child
|
||||
# or family member or home monitoring and other care scenarios. It
|
||||
# supports capture, analysis, recording, and monitoring of video data coming
|
||||
# from one or more video or network cameras attached to a Linux system.
|
||||
# ZoneMinder also support web and semi-automatic control of Pan/Tilt/Zoom
|
||||
# cameras using a variety of protocols. It is suitable for use as a home
|
||||
# video security system and for commercial or professional video security
|
||||
# and surveillance. It can also be integrated into a home automation system
|
||||
# via X.10 or other protocols.
|
||||
# .
|
||||
# This package provides ZoneMinder Perl libraries; it can be used to
|
||||
# write custom interfaces as well.
|
||||
|
||||
Package: zoneminder-doc
|
||||
Section: doc
|
||||
Architecture: all
|
||||
Multi-Arch: foreign
|
||||
Depends: ${misc:Depends}, ${sphinxdoc:Depends}, python-sphinx-rtd-theme | python3-sphinx-rtd-theme
|
||||
Suggests: www-browser
|
||||
Description: ZoneMinder documentation
|
||||
ZoneMinder is intended for use in single or multi-camera video security
|
||||
applications, including commercial or home CCTV, theft prevention and child
|
||||
or family member or home monitoring and other care scenarios. It
|
||||
supports capture, analysis, recording, and monitoring of video data coming
|
||||
from one or more video or network cameras attached to a Linux system.
|
||||
ZoneMinder also support web and semi-automatic control of Pan/Tilt/Zoom
|
||||
cameras using a variety of protocols. It is suitable for use as a home
|
||||
video security system and for commercial or professional video security
|
||||
and surveillance. It can also be integrated into a home automation system
|
||||
via X.10 or other protocols.
|
||||
.
|
||||
This package provides ZoneMinder documentation in HTML format.
|
||||
|
||||
Package: zoneminder-dbg
|
||||
Section: debug
|
||||
Priority: extra
|
||||
Architecture: any
|
||||
Depends: zoneminder (= ${binary:Version}), ${misc:Depends}
|
||||
Description: Zoneminder -- debugging symbols
|
||||
ZoneMinder is intended for use in single or multi-camera video security
|
||||
applications, including commercial or home CCTV, theft prevention and child
|
||||
or family member or home monitoring and other care scenarios. It
|
||||
supports capture, analysis, recording, and monitoring of video data coming
|
||||
from one or more video or network cameras attached to a Linux system.
|
||||
ZoneMinder also support web and semi-automatic control of Pan/Tilt/Zoom
|
||||
cameras using a variety of protocols. It is suitable for use as a home
|
||||
video security system and for commercial or professional video security
|
||||
and surveillance. It can also be integrated into a home automation system
|
||||
via X.10 or other protocols.
|
||||
.
|
||||
This package provides debugging symbols
|
||||
@@ -0,0 +1,174 @@
|
||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: ZoneMinder
|
||||
Upstream-Contact: Philip Coombes <philip.coombes@zoneminder.com>
|
||||
Source: https://github.com/ZoneMinder/ZoneMinder
|
||||
Comment:
|
||||
This package was originally debianized by matrix <matrix@cecilia>
|
||||
on Mon, 7 Mar 2005 02:07:57 -0500.
|
||||
It was re-done for submission to the Debian project by Peter Howard
|
||||
<pjh@northern-ridge.com.au> on Fri, 8 Dec 2006 10:19:43 +1100
|
||||
Files-Excluded:
|
||||
web/skins/*/js/jquery-*
|
||||
web/tools/mootools/*-yc.js
|
||||
|
||||
Files: *
|
||||
Copyright: 2001-2014 Philip Coombes <philip.coombes@zoneminder.com>
|
||||
2008 Brian Rudy <brudyNO@SPAMpraecogito.com>
|
||||
2014 Vincent Giovannone
|
||||
2013 Tim Craig <timcraigNO@SPAMsonic.net>
|
||||
2003-2008 Corey DeLasaux
|
||||
2001-2010 Chris Kistner
|
||||
License: GPL-2+
|
||||
|
||||
Files: distros/*
|
||||
Copyright: 2001-2008 Philip Coombes <philip.coombes@zoneminder.com>
|
||||
2014 Isaac Connor <iconnor@connortechnology.com>
|
||||
2005 Serg Oskin
|
||||
License: GPL-2+
|
||||
|
||||
Files: web/skins/*/js/jquery-*
|
||||
Copyright: 2010 John Resig
|
||||
2010 The Dojo Foundation
|
||||
License: GPL-2 or Expat
|
||||
Comment:
|
||||
Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
http://jquery.org/license
|
||||
.
|
||||
Includes Sizzle.js http://sizzlejs.com/
|
||||
Released under the MIT, BSD, and GPL Licenses.
|
||||
|
||||
Files: web/tools/mootools/*.js
|
||||
Copyright: 2009 Marcelo Jorge Vieira (metal) <metal@alucinados.com>
|
||||
2006-2010 Valerio Proietti (http://mad4milk.net/)
|
||||
License: Expat
|
||||
|
||||
Files: web/api/*
|
||||
Copyright: 2005-2013 Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
License: Expat
|
||||
|
||||
Files:
|
||||
cmake/Modules/CheckPrototypeDefinition*.cmake
|
||||
cmake/Modules/FindGLIB2.cmake
|
||||
cmake/Modules/FindPolkit.cmake
|
||||
cmake/Modules/GNUInstallDirs.cmake
|
||||
Copyright:
|
||||
2005-2011 Kitware, Inc.
|
||||
2010-2011 Andreas Schneider <asn@cryptomilk.org>
|
||||
2009 Dario Freddi <drf@kde.org>
|
||||
2008 Laurent Montel, <montel@kde.org>
|
||||
2011 Nikita Krupen'ko <krnekit@gmail.com>
|
||||
License: BSD-3-clause
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
.
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
.
|
||||
* The names of Kitware, Inc., the Insight Consortium, or the names of
|
||||
any consortium members, or of any contributors, may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Files: cmake/Modules/FindPerlModules.cmake
|
||||
Copyright: 2012 Iowa State University
|
||||
License: Boost-1.0
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
.
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
.
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Files: debian/*
|
||||
Copyright: 2015 Dmitry Smirnov <onlyjob@debian.org>
|
||||
2007-2014 Peter Howard <pjh@northern-ridge.com.au>
|
||||
2010-2012 Vagrant Cascadian <vagrant@debian.org>
|
||||
2001-2008 Philip Coombes <philip.coombes@zoneminder.com>
|
||||
License: GPL-2+
|
||||
|
||||
License: Expat
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
.
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
License: GPL-2+
|
||||
This package is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
.
|
||||
This package is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this package; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
.
|
||||
The complete text of the GNU General Public License version 2
|
||||
can be found in "/usr/share/common-licenses/GPL-2".
|
||||
|
||||
License: GPL-2
|
||||
This package is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; version 2 of the License.
|
||||
.
|
||||
This package is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this package; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
.
|
||||
The complete text of the GNU General Public License version 2
|
||||
can be found in "/usr/share/common-licenses/GPL-2".
|
||||
@@ -0,0 +1,32 @@
|
||||
location /zm/cgi-bin {
|
||||
gzip off;
|
||||
alias /usr/lib/zoneminder/cgi-bin;
|
||||
|
||||
include /etc/nginx/fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $request_filename;
|
||||
fastcgi_pass unix:/var/run/fcgiwrap.socket;
|
||||
}
|
||||
|
||||
location /zm {
|
||||
# if ($scheme ~ ^http:){
|
||||
# rewrite ^(.*)$ https://$host$1 permanent;
|
||||
# }
|
||||
|
||||
gzip off;
|
||||
alias /usr/share/zoneminder/www;
|
||||
index index.php;
|
||||
|
||||
location ~ \.php$ {
|
||||
if (!-f $request_filename) { return 404; }
|
||||
expires epoch;
|
||||
include /etc/nginx/fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $request_filename;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_pass unix:/var/run/php5-fpm.sock;
|
||||
}
|
||||
|
||||
location ~ \.(jpg|jpeg|gif|png|ico)$ {
|
||||
access_log off;
|
||||
expires 33d;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
[dch]
|
||||
id-length = 0
|
||||
|
||||
[import-orig]
|
||||
pristine-tar = False
|
||||
merge = False
|
||||
@@ -0,0 +1,2 @@
|
||||
usr/share/man/man3
|
||||
usr/share/perl5
|
||||
Whitespace-only changes.
Executable
+87
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||
export DEB_LDFLAGS_MAINT_APPEND += -Wl,--as-needed
|
||||
|
||||
ifeq ($(DEB_BUILD_ARCH_OS),hurd)
|
||||
ARGS:= -DZM_NO_MMAP=ON
|
||||
endif
|
||||
|
||||
%:
|
||||
dh $@ --parallel --buildsystem=cmake --builddirectory=dbuild \
|
||||
--with sphinxdoc,apache2,linktree
|
||||
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- $(ARGS) \
|
||||
-DCMAKE_VERBOSE_MAKEFILE=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DZM_CONFIG_DIR="/etc/zm" \
|
||||
-DZM_CONFIG_SUBDIR="/etc/zm/conf.d" \
|
||||
-DZM_RUNDIR="/run/zm" \
|
||||
-DZM_SOCKDIR="/run/zm" \
|
||||
-DZM_TMPDIR="/tmp/zm" \
|
||||
-DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \
|
||||
-DZM_CACHEDIR="/var/cache/zoneminder/cache" \
|
||||
-DZM_DIR_EVENTS="/var/cache/zoneminder/events" \
|
||||
-DZM_PATH_SHUTDOWN="/sbin/shutdown" \
|
||||
-DZM_PATH_ZMS="/zm/cgi-bin/nph-zms"
|
||||
|
||||
override_dh_clean:
|
||||
dh_clean $(MANPAGES1)
|
||||
$(RM) -r docs/_build
|
||||
|
||||
build-indep:
|
||||
#$(MAKE) -C docs text
|
||||
$(MAKE) -C docs html
|
||||
|
||||
MANPAGES1 = dbuild/scripts/zmupdate.pl.1
|
||||
$(MANPAGES1):
|
||||
# generate man page(s):
|
||||
pod2man -s1 --stderr --utf8 $(patsubst %.1, %, $@) $@
|
||||
|
||||
## reproducible build:
|
||||
LAST_CHANGE=$(shell dpkg-parsechangelog -S Date)
|
||||
BUILD_DATE=$(shell LC_ALL=C date -u "+%B %d, %Y" -d "$(LAST_CHANGE)")
|
||||
override_dh_installman: $(MANPAGES1)
|
||||
$(MAKE) -C docs man SPHINXOPTS="-D today=\"$(BUILD_DATE)\""
|
||||
dh_installman --language=C $(MANPAGES1)
|
||||
|
||||
override_dh_auto_install:
|
||||
dh_auto_install --destdir=$(CURDIR)/debian/tmp
|
||||
# remove worthless files:
|
||||
$(RM) -v $(CURDIR)/debian/tmp/usr/share/perl5/*/*/*/.packlist
|
||||
$(RM) -v $(CURDIR)/debian/tmp/usr/share/perl5/*/*.in
|
||||
# remove empty directories:
|
||||
find $(CURDIR)/debian/tmp/usr -type d -empty -delete -printf 'removed %p\n'
|
||||
# remove extra-license-file:
|
||||
$(RM) -v $(CURDIR)/debian/tmp/usr/share/zoneminder/www/api/lib/Cake/LICENSE.txt
|
||||
|
||||
override_dh_fixperms:
|
||||
dh_fixperms
|
||||
#
|
||||
# As requested by the Debian Webapps Policy Manual §3.2.1
|
||||
chown root:www-data $(CURDIR)/debian/zoneminder/etc/zm/zm.conf
|
||||
chmod 640 $(CURDIR)/debian/zoneminder/etc/zm/zm.conf
|
||||
|
||||
override_dh_strip:
|
||||
[ -d "$(CURDIR)/debian/zoneminder-dbg" ] \
|
||||
&& dh_strip --dbg-package=zoneminder-dbg \
|
||||
|| dh_strip
|
||||
|
||||
#%:
|
||||
# dh $@ --parallel --buildsystem=autoconf --with autoreconf
|
||||
#
|
||||
#override_dh_auto_configure:
|
||||
# dh_auto_configure -- \
|
||||
# --sysconfdir=/etc/zm \
|
||||
# --with-mysql=/usr \
|
||||
# --with-webdir=/usr/share/zoneminder \
|
||||
# --with-ffmpeg=/usr \
|
||||
# --with-cgidir=/usr/lib/cgi-bin \
|
||||
# --with-webuser=www-data \
|
||||
# --with-webgroup=www-data \
|
||||
# --enable-mmap=yes
|
||||
@@ -0,0 +1 @@
|
||||
3.0 (quilt)
|
||||
@@ -0,0 +1,9 @@
|
||||
## Actually sources are there: "*-nc.js".
|
||||
source-is-missing web/tools/mootools/mootools-*-yc.js
|
||||
|
||||
## We're using "libjs-jquery" instead.
|
||||
source-is-missing web/skins/*/js/jquery-1.4.2.min.js
|
||||
|
||||
## Acknowledged, will repack eventually.
|
||||
source-contains-prebuilt-javascript-object web/tools/mootools/mootools-*-yc.js
|
||||
source-contains-prebuilt-javascript-object web/skins/*/js/jquery-1.4.2.min.js
|
||||
@@ -0,0 +1,8 @@
|
||||
Document: zoneminder-doc
|
||||
Title: Zoneminder documentation
|
||||
Abstract: This document describes how to use Zoneminder.
|
||||
Section: System/Administration
|
||||
|
||||
Format: HTML
|
||||
Index: /usr/share/doc/zoneminder-doc/html/index.html
|
||||
Files: /usr/share/doc/zoneminder-doc/html/*
|
||||
@@ -0,0 +1 @@
|
||||
docs/_build/html usr/share/doc/zoneminder-doc/
|
||||
@@ -0,0 +1,2 @@
|
||||
## Convenience symlink:
|
||||
/usr/share/doc/zoneminder-doc/html /usr/share/doc/zoneminder/html
|
||||
@@ -0,0 +1 @@
|
||||
conf debian/conf/apache2/zoneminder.conf nginx
|
||||
@@ -0,0 +1,5 @@
|
||||
Unless bug is specific to Debian please consider reporting it directly to
|
||||
upstream developer(s):
|
||||
|
||||
https://github.com/ZoneMinder/ZoneMinder/issues
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
var/log/zm
|
||||
var/lib/zm
|
||||
var/cache/zoneminder/events
|
||||
var/cache/zoneminder/images
|
||||
var/cache/zoneminder/temp
|
||||
var/cache/zoneminder/cache
|
||||
usr/share/zoneminder/db
|
||||
etc/zm/
|
||||
etc/zm/conf.d
|
||||
@@ -0,0 +1 @@
|
||||
README.md
|
||||
@@ -0,0 +1,2 @@
|
||||
debian/examples/*
|
||||
dbuild/misc/apache.conf
|
||||
@@ -0,0 +1,91 @@
|
||||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: zoneminder
|
||||
# Required-Start: $network $remote_fs $syslog
|
||||
# Required-Stop: $network $remote_fs $syslog
|
||||
# Should-Start: mysql
|
||||
# Should-Stop: mysql
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Control ZoneMinder as a Service
|
||||
# Description: ZoneMinder CCTV recording and surveillance system
|
||||
### END INIT INFO
|
||||
# chkconfig: 2345 20 20
|
||||
|
||||
# Source function library.
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
prog=ZoneMinder
|
||||
ZM_PATH_BIN="/usr/bin"
|
||||
RUNDIR="/run/zm"
|
||||
TMPDIR="/tmp/zm"
|
||||
command="$ZM_PATH_BIN/zmpkg.pl"
|
||||
|
||||
start() {
|
||||
echo -n "Starting $prog: "
|
||||
export TZ=:/etc/localtime
|
||||
mkdir -p "$RUNDIR" && chown www-data:www-data "$RUNDIR"
|
||||
mkdir -p "$TMPDIR" && chown www-data:www-data "$TMPDIR"
|
||||
$command start
|
||||
RETVAL=$?
|
||||
[ $RETVAL = 0 ] && echo success
|
||||
[ $RETVAL != 0 ] && echo failure
|
||||
echo
|
||||
[ $RETVAL = 0 ] && touch /var/lock/zm
|
||||
return $RETVAL
|
||||
}
|
||||
stop() {
|
||||
echo -n "Stopping $prog: "
|
||||
#
|
||||
# Why is this status check being done?
|
||||
# as $command stop returns 1 if zoneminder
|
||||
# is stopped, which will result in
|
||||
# this returning 1, which will stuff
|
||||
# dpkg when it tries to stop zoneminder before
|
||||
# uninstalling . . .
|
||||
#
|
||||
result=`$command status`
|
||||
if [ ! "$result" = "running" ]; then
|
||||
echo "Zoneminder already stopped"
|
||||
echo
|
||||
RETVAL=0
|
||||
else
|
||||
$command stop
|
||||
RETVAL=$?
|
||||
[ $RETVAL = 0 ] && echo success
|
||||
[ $RETVAL != 0 ] && echo failure
|
||||
echo
|
||||
[ $RETVAL = 0 ] && rm -f /var/lock/zm
|
||||
fi
|
||||
}
|
||||
status() {
|
||||
result=`$command status`
|
||||
if [ "$result" = "running" ]; then
|
||||
echo "ZoneMinder is running"
|
||||
RETVAL=0
|
||||
else
|
||||
echo "ZoneMinder is stopped"
|
||||
RETVAL=1
|
||||
fi
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
'start')
|
||||
start
|
||||
;;
|
||||
'stop')
|
||||
stop
|
||||
;;
|
||||
'restart' | 'force-reload')
|
||||
stop
|
||||
start
|
||||
;;
|
||||
'status')
|
||||
status
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 { start | stop | restart | status }"
|
||||
RETVAL=1
|
||||
;;
|
||||
esac
|
||||
exit $RETVAL
|
||||
@@ -0,0 +1,11 @@
|
||||
etc/zm/zm.conf
|
||||
etc/zm/conf.d/*
|
||||
usr/bin
|
||||
usr/lib/zoneminder
|
||||
usr/share/polkit-1
|
||||
usr/share/zoneminder/db
|
||||
usr/share/zoneminder/www
|
||||
|
||||
# libzoneminder-perl files:
|
||||
usr/share/man/man3
|
||||
usr/share/perl5
|
||||
@@ -0,0 +1 @@
|
||||
/var/tmp /usr/share/zoneminder/www/api/app/tmp
|
||||
@@ -0,0 +1,14 @@
|
||||
## cakephp
|
||||
#replace /usr/share/php/Cake /usr/share/zoneminder/www/api/lib/Cake
|
||||
|
||||
## libjs-mootools
|
||||
replace /usr/share/javascript/mootools/mootools.js /usr/share/zoneminder/www/tools/mootools/mootools-core.js
|
||||
replace /usr/share/javascript/mootools/mootools.js /usr/share/zoneminder/www/tools/mootools/mootools-core-1.3.2-nc.js
|
||||
replace /usr/share/javascript/mootools/mootools.js /usr/share/zoneminder/www/tools/mootools/mootools-core-1.3.2-yc.js
|
||||
replace /usr/share/javascript/mootools/mootools-more.js /usr/share/zoneminder/www/tools/mootools/mootools-more.js
|
||||
replace /usr/share/javascript/mootools/mootools-more.js /usr/share/zoneminder/www/tools/mootools/mootools-more-1.3.2.1-nc.js
|
||||
replace /usr/share/javascript/mootools/mootools-more.js /usr/share/zoneminder/www/tools/mootools/mootools-more-1.3.2.1-yc.js
|
||||
|
||||
## libjs-jquery
|
||||
replace /usr/share/javascript/jquery/jquery.min.js /usr/share/zoneminder/www/skins/classic/js/jquery-1.4.2.min.js
|
||||
replace /usr/share/javascript/jquery/jquery.min.js /usr/share/zoneminder/www/skins/flat/js/jquery-1.4.2.min.js
|
||||
@@ -0,0 +1,14 @@
|
||||
# Depends: policykit-1
|
||||
unusual-interpreter usr/bin/zmsystemctl.pl #!/usr/bin/pkexec
|
||||
|
||||
# Intentionally not others-readable, #637685.
|
||||
non-standard-file-perm etc/zm/zm.conf 0640 != 0644
|
||||
|
||||
# Bundled Cake PHP framework, not intended for direct execution:
|
||||
script-not-executable usr/share/zoneminder/www/api/*
|
||||
|
||||
# Annoying but seems to be too much troubles to fix; should be fixed upstream:
|
||||
script-with-language-extension usr/bin/*.pl
|
||||
|
||||
# dh-linktree:
|
||||
package-contains-broken-symlink usr/share/zoneminder/www/api/lib/Cake/*
|
||||
@@ -0,0 +1,13 @@
|
||||
/var/log/zm/*.log {
|
||||
missingok
|
||||
notifempty
|
||||
sharedscripts
|
||||
delaycompress
|
||||
compress
|
||||
postrotate
|
||||
/usr/bin/zmpkg.pl logrot >>/dev/null 2>&1 || :
|
||||
endscript
|
||||
daily
|
||||
rotate 7
|
||||
maxage 7
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
rm_conffile /etc/zm/apache.conf 1.28.1-5~
|
||||
@@ -0,0 +1 @@
|
||||
docs/_build/man/*.1
|
||||
@@ -0,0 +1,66 @@
|
||||
#! /bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$1" = "configure" ]; then
|
||||
|
||||
. /etc/zm/zm.conf
|
||||
for i in /etc/zm/conf.d/*.conf; do
|
||||
. $i
|
||||
done;
|
||||
|
||||
|
||||
# The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group
|
||||
chown www-data:root /var/log/zm
|
||||
chown www-data:www-data /var/lib/zm
|
||||
if [ -z "$2" ]; then
|
||||
chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/*
|
||||
fi
|
||||
|
||||
# Do this every time the package is installed or upgraded
|
||||
# Ensure zoneminder is stopped
|
||||
invoke-rc.d zoneminder stop || true
|
||||
|
||||
if [ "$ZM_DB_HOST" = "localhost" ]; then
|
||||
if [ -e "/etc/init.d/mysql" ]; then
|
||||
#
|
||||
# Get mysql started if it isn't
|
||||
#
|
||||
if ! $(/etc/init.d/mysql status >/dev/null 2>&1); then
|
||||
invoke-rc.d mysql start
|
||||
fi
|
||||
if $(/etc/init.d/mysql status >/dev/null 2>&1); then
|
||||
mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload
|
||||
# test if database if already present...
|
||||
if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then
|
||||
cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error creating db."
|
||||
exit 1;
|
||||
fi
|
||||
# This creates the user.
|
||||
echo "grant lock tables, alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||
else
|
||||
echo "grant lock tables, alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||
fi
|
||||
|
||||
zmupdate.pl --nointeractive
|
||||
zmupdate.pl --nointeractive -f
|
||||
|
||||
# Add any new PTZ control configurations to the database (will not overwrite)
|
||||
zmcamtool.pl --import >/dev/null 2>&1
|
||||
|
||||
else
|
||||
echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.'
|
||||
fi
|
||||
else
|
||||
echo 'mysql not found, assuming remote server.'
|
||||
fi
|
||||
else
|
||||
echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)"
|
||||
fi
|
||||
echo "Done Updating, starting ZoneMinder"
|
||||
invoke-rc.d zoneminder start || true
|
||||
fi
|
||||
|
||||
#DEBHELPER#
|
||||
@@ -0,0 +1,14 @@
|
||||
#! /bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$1" = "purge" ]; then
|
||||
echo "
|
||||
Reminder: to completely remove \"zoneminder\" it may be necessary
|
||||
* to delete database using the following sample command:
|
||||
sudo mysqladmin --defaults-file=/etc/mysql/debian.cnf -f drop zm
|
||||
* to delete remaining data files in "/var/cache/zoneminder".
|
||||
"
|
||||
fi
|
||||
|
||||
#DEBHELPER#
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
## Remove obsolete symlink which is in the way of dh_apache2:
|
||||
ol="/etc/apache2/conf-available/zoneminder.conf"
|
||||
if [ -h "${ol}" ]; then
|
||||
[ "$(readlink ${ol})" = "/etc/zm/apache.conf" ] && rm -f "${ol}"
|
||||
fi
|
||||
|
||||
#DEBHELPER#
|
||||
@@ -0,0 +1,4 @@
|
||||
d /run/zm 0755 www-data www-data
|
||||
d /tmp/zm 0755 www-data www-data
|
||||
d /var/tmp/zm 0755 www-data www-data
|
||||
d /var/cache/zoneminder/cache 0755 www-data www-data
|
||||
@@ -28,7 +28,7 @@
|
||||
%global _hardened_build 1
|
||||
|
||||
Name: zoneminder
|
||||
Version: 1.35.4
|
||||
Version: 1.35.5
|
||||
Release: 1%{?dist}
|
||||
Summary: A camera monitoring and analysis tool
|
||||
Group: System Environment/Daemons
|
||||
@@ -43,6 +43,7 @@ Source0: https://github.com/ZoneMinder/ZoneMinder/archive/%{version}.tar.gz#/zon
|
||||
Source1: https://github.com/ZoneMinder/crud/archive/v%{crud_version}.tar.gz#/crud-%{crud_version}.tar.gz
|
||||
Source2: https://github.com/ZoneMinder/CakePHP-Enum-Behavior/archive/%{ceb_version}.tar.gz#/cakephp-enum-behavior-%{ceb_version}.tar.gz
|
||||
|
||||
%{?rhel:BuildRequires: epel-rpm-macros}
|
||||
BuildRequires: systemd-devel
|
||||
BuildRequires: mariadb-devel
|
||||
BuildRequires: perl-podlators
|
||||
@@ -206,16 +207,20 @@ mv -f CakePHP-Enum-Behavior-%{ceb_version} ./web/api/app/Plugin/CakePHP-Enum-Beh
|
||||
./utils/zmeditconfigdata.sh ZM_OPT_FAST_DELETE no
|
||||
|
||||
%build
|
||||
# Disable LTO due to top level asm
|
||||
# See https://fedoraproject.org/wiki/LTOByDefault
|
||||
%define _lto_cflags %{nil}
|
||||
|
||||
%cmake3 \
|
||||
-DZM_WEB_USER="%{zmuid_final}" \
|
||||
-DZM_WEB_GROUP="%{zmgid_final}" \
|
||||
-DZM_TARGET_DISTRO="%{zmtargetdistro}" \
|
||||
.
|
||||
|
||||
%make_build
|
||||
%cmake3_build
|
||||
|
||||
%install
|
||||
%make_install
|
||||
%cmake3_install
|
||||
|
||||
desktop-file-install \
|
||||
--dir %{buildroot}%{_datadir}/applications \
|
||||
@@ -357,6 +362,7 @@ EOF
|
||||
%{_bindir}/zmtelemetry.pl
|
||||
%{_bindir}/zmx10.pl
|
||||
%{_bindir}/zmonvif-probe.pl
|
||||
%{_bindir}/zmonvif-trigger.pl
|
||||
%{_bindir}/zmstats.pl
|
||||
%{_bindir}/zmrecover.pl
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
|
||||
,libssl | libssl1.0.0 | libssl1.1
|
||||
,libcrypt-eksblowfish-perl
|
||||
,libdata-entropy-perl
|
||||
,libvncclient1
|
||||
,libvncclient1|libvncclient0
|
||||
Recommends: ${misc:Recommends}
|
||||
,libapache2-mod-php5 | libapache2-mod-php | php5-fpm | php-fpm
|
||||
,mysql-server | mariadb-server | virtual-mysql-server
|
||||
|
||||
@@ -21,8 +21,8 @@ override_dh_auto_configure:
|
||||
-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_RUNDIR="/run/zm" \
|
||||
-DZM_SOCKDIR="/run/zm" \
|
||||
-DZM_TMPDIR="/tmp/zm" \
|
||||
-DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \
|
||||
-DZM_CACHEDIR="/var/cache/zoneminder/cache" \
|
||||
|
||||
@@ -3,7 +3,7 @@ Section: net
|
||||
Priority: optional
|
||||
Maintainer: Isaac Connor <isaac@zoneminder.com>
|
||||
Uploaders: Isaac Connor <isaac@zoneminder.com>
|
||||
Build-Depends: debhelper, dh-systemd, python3-sphinx, dh-linktree, dh-systemd, dh-apache2
|
||||
Build-Depends: debhelper, dh-systemd, sphinx-doc, dh-linktree, dh-systemd, dh-apache2
|
||||
,cmake
|
||||
,libx264-dev, libmp4v2-dev
|
||||
,libavdevice-dev
|
||||
|
||||
@@ -21,8 +21,8 @@ override_dh_auto_configure:
|
||||
-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_RUNDIR="/run/zm" \
|
||||
-DZM_SOCKDIR="/run/zm" \
|
||||
-DZM_TMPDIR="/tmp/zm" \
|
||||
-DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \
|
||||
-DZM_CACHEDIR="/var/cache/zoneminder/cache" \
|
||||
|
||||
@@ -3,10 +3,157 @@ Debian
|
||||
|
||||
.. contents::
|
||||
|
||||
Easy Way: Debian Buster
|
||||
------------------------
|
||||
|
||||
This procedure will guide you through the installation of ZoneMinder on Debian 10 (Buster).
|
||||
|
||||
**Step 1:** Make sure your system is up to date
|
||||
|
||||
Open a console and use ``su`` command to become root.
|
||||
|
||||
::
|
||||
|
||||
apt update
|
||||
apt upgrade
|
||||
|
||||
|
||||
**Step 2:** Setup Sudo (optional but recommended)
|
||||
|
||||
By default Debian does not come with sudo, so you have to install it and configure it manually.
|
||||
This step is optional but recommended and the following instructions assume that you have setup sudo.
|
||||
If you prefer to setup ZoneMinder as root, do it at your own risk and adapt the following instructions accordingly.
|
||||
|
||||
::
|
||||
|
||||
apt install sudo
|
||||
usermod -a -G sudo <username>
|
||||
exit
|
||||
|
||||
Now your terminal session is back under your normal user. You can check that
|
||||
you are now part of the sudo group with the command ``groups``, "sudo" should
|
||||
appear in the list. If not, run ``newgrp sudo`` and check again with ``groups``.
|
||||
|
||||
|
||||
**Step 3:** Install Apache and MySQL
|
||||
|
||||
These are not dependencies for the ZoneMinder package as they could be
|
||||
installed elsewhere. If they are not installed yet in your system, you have to
|
||||
trigger their installation manually.
|
||||
|
||||
::
|
||||
|
||||
sudo apt install apache2 mysql-server
|
||||
|
||||
**Step 4:** Add ZoneMinder's Package repository to your apt sources
|
||||
|
||||
ZoneMinder's Debian packages are not included in Debian's official package
|
||||
repositories. To be able to install ZoneMinder with APT, you have to edit the
|
||||
list of apt sources and add ZoneMinder's repository.
|
||||
|
||||
::
|
||||
|
||||
sudo nano /etc/apt/sources.list
|
||||
|
||||
Add the following to the bottom of the file
|
||||
|
||||
::
|
||||
|
||||
# ZoneMinder repository
|
||||
deb https://zmrepo.zoneminder.com/debian/release-1.34 buster/
|
||||
|
||||
CTRL+o and <Enter> to save
|
||||
CTRL+x to exit
|
||||
|
||||
Because ZoneMinder's package repository provides a secure connection through HTTPS, apt must be enabled for HTTPS.
|
||||
::
|
||||
|
||||
sudo apt install apt-transport-https
|
||||
|
||||
Finally, download the GPG key for ZoneMinder's repository:
|
||||
::
|
||||
|
||||
wget -O - https://zmrepo.zoneminder.com/debian/archive-keyring.gpg | sudo apt-key add -
|
||||
|
||||
|
||||
**Step 5:** Install ZoneMinder
|
||||
|
||||
::
|
||||
|
||||
sudo apt update
|
||||
sudo apt install zoneminder
|
||||
|
||||
**Step 6:** Read the Readme
|
||||
|
||||
The rest of the install process is covered in the README.Debian, so feel free to have
|
||||
a read.
|
||||
|
||||
::
|
||||
|
||||
zcat /usr/share/doc/zoneminder/README.Debian.gz
|
||||
|
||||
|
||||
**Step 7:** Enable ZoneMinder service
|
||||
|
||||
::
|
||||
|
||||
sudo systemctl enable zoneminder.service
|
||||
|
||||
**Step 8:** Configure Apache
|
||||
|
||||
The following commands will setup the default /zm virtual directory and configure
|
||||
required apache modules.
|
||||
|
||||
::
|
||||
|
||||
sudo a2enconf zoneminder
|
||||
sudo a2enmod rewrite
|
||||
sudo a2enmod cgi # this is done automatically when installing the package. Redo this command manually only for troubleshooting.
|
||||
|
||||
|
||||
**Step 9:** Edit Timezone in PHP
|
||||
|
||||
Automated way:
|
||||
::
|
||||
|
||||
sudo sed -i "s/;date.timezone =/date.timezone = $(sed 's/\//\\\//' /etc/timezone)/g" /etc/php/7.0/apache2/php.ini
|
||||
|
||||
Manual way
|
||||
::
|
||||
|
||||
sudo nano /etc/php/7.0/apache2/php.ini
|
||||
|
||||
Search for [Date] (Ctrl + w then type Date and press Enter) and change
|
||||
date.timezone for your time zone. Don't forget to remove the ; from in front
|
||||
of date.timezone.
|
||||
|
||||
::
|
||||
|
||||
[Date]
|
||||
; Defines the default timezone used by the date functions
|
||||
; http://php.net/date.timezone
|
||||
date.timezone = America/New_York
|
||||
|
||||
CTRL+o then [Enter] to save
|
||||
|
||||
CTRL+x to exit
|
||||
|
||||
|
||||
**Step 10:** Start ZoneMinder
|
||||
|
||||
Reload Apache to enable your changes and then start ZoneMinder.
|
||||
|
||||
::
|
||||
|
||||
sudo systemctl reload apache2
|
||||
sudo systemctl start zoneminder
|
||||
|
||||
You are now ready to go with ZoneMinder. Open a browser and type either ``localhost/zm`` one the local machine or ``{IP-OF-ZM-SERVER}/zm`` if you connect from a remote computer.
|
||||
|
||||
Easy Way: Debian Stretch
|
||||
------------------------
|
||||
|
||||
This procedure will guide you through the installation of ZoneMinder on Debian 9 (Stretch). This section has been tested with ZoneMinder 1.32.3 on Debian 9.8.
|
||||
This procedure will guide you through the installation of ZoneMinder on Debian 9 (Stretch). This section has been tested with ZoneMinder 1.34 on Debian 9.8.
|
||||
|
||||
**Step 1:** Make sure your system is up to date
|
||||
|
||||
@@ -52,7 +199,7 @@ Add the following to the bottom of the file
|
||||
::
|
||||
|
||||
# ZoneMinder repository
|
||||
deb https://zmrepo.zoneminder.com/debian/release stretch/
|
||||
deb https://zmrepo.zoneminder.com/debian/release-1.34 stretch/
|
||||
|
||||
CTRL+o and <Enter> to save
|
||||
CTRL+x to exit
|
||||
@@ -275,7 +422,6 @@ CTRL+x to exit
|
||||
|
||||
**Step 12:** Please check the configuration
|
||||
|
||||
Zoneminder 1.32.x
|
||||
1. Check path of ZM_PATH in '/etc/zm/conf.d/zmcustom.conf' is ZM_PATH_ZMS=/zm/cgi-bin/nph-zms
|
||||
::
|
||||
cat /etc/zm/conf.d/zmcustom.conf
|
||||
@@ -309,8 +455,8 @@ Reload Apache to enable your changes and then start ZoneMinder.
|
||||
::
|
||||
|
||||
{
|
||||
"version": "1.29.0",
|
||||
"apiversion": "1.29.0.1"
|
||||
"version": "1.34.0",
|
||||
"apiversion": "1.34.0.1"
|
||||
}
|
||||
|
||||
**Congratulations** Your installation is complete
|
||||
@@ -53,7 +53,7 @@ ZoneMinder releases are now being hosted at RPM Fusion. New users should navigat
|
||||
|
||||
Note that RHEL/CentOS 7 users should use yum instead of dnf.
|
||||
|
||||
Once ZoneMinder has been installed, it is critically important that you read the README file under /usr/share/doc/zoneminder. ZoneMinder will not run without completing the steps outlined in the README.
|
||||
Once ZoneMinder has been installed, it is critically important that you read the README file under /usr/share/doc/zoneminder-common. ZoneMinder will not run without completing the steps outlined in the README.
|
||||
|
||||
How to Install Nightly Development Builds
|
||||
-----------------------------------------
|
||||
@@ -191,7 +191,7 @@ Now clone the ZoneMinder git repository from your home folder:
|
||||
git clone https://github.com/ZoneMinder/zoneminder
|
||||
cd zoneminder
|
||||
|
||||
This will create a sub-folder called ZoneMinder, which will contain the latest development source code.
|
||||
This will create a sub-folder called zoneminder, which will contain the latest development source code.
|
||||
|
||||
If you have previsouly cloned the ZoneMinder git repo and wish to update it to the most recent, then issue these commands instead:
|
||||
|
||||
|
||||
@@ -32,12 +32,10 @@ BULK_FRAME_INTERVAL - Traditionally ZoneMinder writes an entry into the Frames d
|
||||
|
||||
EVENT_CLOSE_MODE - When a monitor is running in a continuous recording mode (Record or Mocord) events are usually closed after a fixed period of time (the section length). However in Mocord mode it is possible that motion detection may occur near the end of a section. This option controls what happens when an alarm occurs in Mocord mode. The 'time' setting means that the event will be closed at the end of the section regardless of alarm activity. The 'idle' setting means that the event will be closed at the end of the section if there is no alarm activity occurring at the time otherwise it will be closed once the alarm is over meaning the event may end up being longer than the normal section length. The 'alarm' setting means that if an alarm occurs during the event, the event will be closed once the alarm is over regardless of when this occurs. This has the effect of limiting the number of alarms to one per event and the events will be shorter than the section length if an alarm has occurred.
|
||||
|
||||
CREATE_ANALYSIS_IMAGES - By default during an alarm ZoneMinder records both the raw captured image and one that has been analysed and had areas where motion was detected outlined. This can be very useful during zone configuration or in analysing why events occurred. However it also incurs some overhead and in a stable system may no longer be necessary. This parameter allows you to switch the generation of these images off.
|
||||
|
||||
WEIGHTED_ALARM_CENTRES - ZoneMinder will always calculate the centre point of an alarm in a zone to give some indication of where on the screen it is. This can be used by the experimental motion tracking feature or your own custom extensions. In the alarmed or filtered pixels mode this is a simple midpoint between the extents of the detected pxiesl. However in the blob method this can instead be calculated using weighted pixel locations to give more accurate positioning for irregularly shaped blobs. This method, while more precise is also slower and so is turned off by default.
|
||||
|
||||
EVENT_IMAGE_DIGITS - As event images are captured they are stored to the filesystem with a numerical index. By default this index has three digits so the numbers start 001, 002 etc. This works works for most scenarios as events with more than 999 frames are rarely captured. However if you have extremely long events and use external applications then you may wish to increase this to ensure correct sorting of images in listings etc. Warning, increasing this value on a live system may render existing events unviewable as the event will have been saved with the previous scheme. Decreasing this value should have no ill effects.
|
||||
|
||||
DEFAULT_ASPECT_RATIO - When specifying the dimensions of monitors you can click a checkbox to ensure that the width stays in the correct ratio to the height, or vice versa. This setting allows you to indicate what the ratio of these settings should be. This should be specified in the format <width value>:<height value> and the default of 4:3 normally be acceptable but 11:9 is another common setting. If the checkbox is not clicked when specifying monitor dimensions this setting has no effect.
|
||||
|
||||
USER_SELF_EDIT - Ordinarily only users with system edit privilege are able to change users details. Switching this option on allows ordinary users to change their passwords and their language settings
|
||||
USER_SELF_EDIT - Ordinarily only users with system edit privilege are able to change users details. Switching this option on allows ordinary users to change their passwords and their language settings
|
||||
+23
-34
@@ -20,18 +20,16 @@ sub START {
|
||||
sub Subscribe {
|
||||
my ($self, $body, $header) = @_;
|
||||
die "Subscribe must be called as object method (\$self is <$self>)" if not blessed($self);
|
||||
#print " proxy/lib/WSNotification/Interfaces/WSBaseNotificationSender/NotificationProducerPort.pm Subscribe\n";
|
||||
return $self->SUPER::call({
|
||||
operation => 'Subscribe',
|
||||
soap_action => 'http://docs.oasis-open.org/wsn/bw-2/Subscribe',
|
||||
style => 'document',
|
||||
body => {
|
||||
|
||||
|
||||
'use' => 'literal',
|
||||
namespace => 'http://schemas.xmlsoap.org/wsdl/soap/',
|
||||
encodingStyle => '',
|
||||
parts => [qw( WSNotification::Elements::Subscribe )],
|
||||
|
||||
use => 'literal',
|
||||
namespace => 'http://schemas.xmlsoap.org/wsdl/soap/',
|
||||
encodingStyle => '',
|
||||
parts => [qw( WSNotification::Elements::Subscribe )],
|
||||
},
|
||||
header => {
|
||||
|
||||
@@ -42,39 +40,30 @@ sub Subscribe {
|
||||
}, $body, $header);
|
||||
}
|
||||
|
||||
|
||||
sub GetCurrentMessage {
|
||||
my ($self, $body, $header) = @_;
|
||||
die "GetCurrentMessage must be called as object method (\$self is <$self>)" if not blessed($self);
|
||||
return $self->SUPER::call({
|
||||
operation => 'GetCurrentMessage',
|
||||
soap_action => 'http://docs.oasis-open.org/wsn/bw-2/GetCurrentMessage',
|
||||
style => 'document',
|
||||
body => {
|
||||
|
||||
my ($self, $body, $header) = @_;
|
||||
die "GetCurrentMessage must be called as object method (\$self is <$self>)" if not blessed($self);
|
||||
return $self->SUPER::call({
|
||||
operation => 'GetCurrentMessage',
|
||||
soap_action => 'http://docs.oasis-open.org/wsn/bw-2/GetCurrentMessage',
|
||||
style => 'document',
|
||||
body => {
|
||||
use => 'literal',
|
||||
namespace => 'http://schemas.xmlsoap.org/wsdl/soap/',
|
||||
encodingStyle => '',
|
||||
parts => [qw( WSNotification::Elements::GetCurrentMessage )],
|
||||
|
||||
'use' => 'literal',
|
||||
namespace => 'http://schemas.xmlsoap.org/wsdl/soap/',
|
||||
encodingStyle => '',
|
||||
parts => [qw( WSNotification::Elements::GetCurrentMessage )],
|
||||
},
|
||||
header => {
|
||||
|
||||
},
|
||||
header => {
|
||||
|
||||
},
|
||||
headerfault => {
|
||||
|
||||
}
|
||||
}, $body, $header);
|
||||
},
|
||||
headerfault => {
|
||||
|
||||
}
|
||||
}, $body, $header);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
1;
|
||||
|
||||
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
@@ -30,10 +30,10 @@ configure_file(zm.in "${CMAKE_CURRENT_BINARY_DIR}/zm" @ONLY)
|
||||
#configure_file(zmeventdump.in zmeventdump @ONLY)
|
||||
|
||||
# Generate man files for the perl scripts destined for the bin folder
|
||||
file(GLOB perlscripts "*.pl")
|
||||
file(GLOB perlscripts "${CMAKE_CURRENT_BINARY_DIR}/*.pl")
|
||||
FOREACH(PERLSCRIPT ${perlscripts})
|
||||
get_filename_component(PERLSCRIPTNAME ${PERLSCRIPT} NAME)
|
||||
POD2MAN(${PERLSCRIPT} zoneminder-${PERLSCRIPTNAME} 8 ${ZM_MANPAGE_DEST_PREFIX})
|
||||
POD2MAN(${PERLSCRIPT} ${PERLSCRIPTNAME} 8 ${ZM_MANPAGE_DEST_PREFIX})
|
||||
ENDFOREACH(PERLSCRIPT ${perlscripts})
|
||||
|
||||
# Install the perl scripts
|
||||
|
||||
@@ -252,7 +252,7 @@ our @options = (
|
||||
authentication which passes an independently authentication
|
||||
'remote' user via http. In this case ZoneMinder would use the
|
||||
supplied user without additional authentication provided such a
|
||||
user is configured ion ZoneMinder.
|
||||
user is configured in ZoneMinder.
|
||||
`,
|
||||
requires => [ { name=>'ZM_OPT_USE_AUTH', value=>'yes' } ],
|
||||
type => {
|
||||
@@ -1513,6 +1513,26 @@ our @options = (
|
||||
type => $types{boolean},
|
||||
category => 'logging',
|
||||
},
|
||||
{
|
||||
name => 'ZM_WEB_NAVBAR_TYPE',
|
||||
default => 'normal',
|
||||
description => 'Style of the web console navigation bar',
|
||||
help => q`
|
||||
Choose between different navigation bar styles for the web
|
||||
console. The "normal" style has a menu across the top, which
|
||||
collapses to a pull down menu on small screens. The "collapsed"
|
||||
style is collapsed all the time. Instead of a menu across the
|
||||
top, menu items are accessed from the drop down menu on the
|
||||
right.
|
||||
`,
|
||||
type => {
|
||||
db_type => 'string',
|
||||
hint => 'normal|collapsed',
|
||||
pattern => qr|^([nc])|i,
|
||||
format => q( ($1 =~ /^n/) ? 'normal' : 'collapsed' )
|
||||
},
|
||||
category => 'web',
|
||||
},
|
||||
{
|
||||
name => 'ZM_WEB_TITLE',
|
||||
default => 'ZoneMinder',
|
||||
@@ -1558,6 +1578,20 @@ our @options = (
|
||||
type => $types{string},
|
||||
category => 'web',
|
||||
},
|
||||
{
|
||||
name => 'ZM_HOME_ABOUT',
|
||||
default => 'yes',
|
||||
description => 'Whether to enable the ZoneMinder About menu.',
|
||||
help => q`
|
||||
When enabled, the ZoneMinder logo in the top left corner of the
|
||||
navigation bar becomes a menu with links to: the ZoneMinder
|
||||
website, ZoneMinder Documentation, and the ZoneMinder forum.
|
||||
End users wishing to rebrand their system may want to disable this
|
||||
as the menu items are currently hard coded.
|
||||
`,
|
||||
type => $types{boolean},
|
||||
category => 'web',
|
||||
},
|
||||
{
|
||||
name => 'ZM_WEB_CONSOLE_BANNER',
|
||||
default => '',
|
||||
@@ -2635,22 +2669,6 @@ our @options = (
|
||||
type => $types{boolean},
|
||||
category => 'hidden',
|
||||
},
|
||||
{
|
||||
name => 'ZM_CREATE_ANALYSIS_IMAGES',
|
||||
default => 'yes',
|
||||
description => 'Create analysed alarm images with motion outlined',
|
||||
help => q`
|
||||
By default during an alarm ZoneMinder records both the raw
|
||||
captured image and one that has been analysed and had areas
|
||||
where motion was detected outlined. This can be very useful
|
||||
during zone configuration or in analysing why events occurred.
|
||||
However it also incurs some overhead and in a stable system may
|
||||
no longer be necessary. This parameter allows you to switch the
|
||||
generation of these images off.
|
||||
`,
|
||||
type => $types{boolean},
|
||||
category => 'config',
|
||||
},
|
||||
{
|
||||
name => 'ZM_WEIGHTED_ALARM_CENTRES',
|
||||
default => 'no',
|
||||
|
||||
@@ -45,7 +45,7 @@ use ZoneMinder::Config qw(:all);
|
||||
use Time::HiRes qw( usleep );
|
||||
use URI;
|
||||
|
||||
our $ADDRESS;
|
||||
our $uri;
|
||||
|
||||
sub open {
|
||||
my $self = shift;
|
||||
@@ -55,8 +55,7 @@ sub open {
|
||||
# Has no scheme at the beginning, so won't parse as a URI
|
||||
$self->{Monitor}->{ControlAddress} = 'http://'.$self->{Monitor}->{ControlAddress};
|
||||
}
|
||||
my $uri = URI->new($self->{Monitor}->{ControlAddress});
|
||||
$ADDRESS = $uri->scheme.'://'.$uri->authority().$uri->path().($uri->port()?':'.$uri->port():'');
|
||||
$uri = URI->new($self->{Monitor}->{ControlAddress});
|
||||
|
||||
use LWP::UserAgent;
|
||||
$self->{ua} = LWP::UserAgent->new;
|
||||
@@ -65,14 +64,21 @@ sub open {
|
||||
$self->{state} = 'closed';
|
||||
|
||||
my ( $username, $password, $host ) = ( $uri->authority() =~ /^([^:]+):([^@]*)@(.+)$/ );
|
||||
|
||||
$uri->userinfo(undef);
|
||||
|
||||
my $realm = $self->{Monitor}->{ControlDevice};
|
||||
|
||||
$self->{ua}->credentials($ADDRESS, $realm, $username, $password);
|
||||
$self->{ua}->credentials($uri->host_port(), $realm, $username, $password);
|
||||
my $url = '/axis-cgi/param.cgi?action=list&group=Properties.PTZ.PTZ';
|
||||
|
||||
# test auth
|
||||
my $res = $self->{ua}->get($ADDRESS.'/cgi/ptdc.cgi');
|
||||
my $res = $self->{ua}->get($uri->canonical().$url);
|
||||
|
||||
if ( $res->is_success ) {
|
||||
if ( $res->content() ne "Properties.PTZ.PTZ=yes\n" ) {
|
||||
Warning('Response suggests that camera doesn\'t support PTZ. Content:('.$res->content().')');
|
||||
}
|
||||
$self->{state} = 'open';
|
||||
return;
|
||||
}
|
||||
@@ -85,23 +91,18 @@ sub open {
|
||||
}
|
||||
|
||||
if ( $$headers{'www-authenticate'} ) {
|
||||
Debug('Authenticating');
|
||||
my ( $auth, $tokens ) = $$headers{'www-authenticate'} =~ /^(\w+)\s+(.*)$/;
|
||||
if ( $tokens =~ /\w+="([^"]+)"/i ) {
|
||||
if ( $realm ne $1 ) {
|
||||
$realm = $1;
|
||||
Debug("Changing REALM to $realm");
|
||||
$self->{ua}->credentials($host, $realm, $username, $password);
|
||||
$res = $self->{ua}->get($ADDRESS);
|
||||
$self->{ua}->credentials($uri->host_port(), $realm, $username, $password);
|
||||
$res = $self->{ua}->get($uri->canonical().$url);
|
||||
if ( $res->is_success() ) {
|
||||
Info("Auth succeeded after setting realm to $realm. You can set this value in the Control Device field to speed up connections and remove these log entries.");
|
||||
$self->{state} = 'open';
|
||||
return;
|
||||
}
|
||||
Error('Authentication still failed after updating REALM'.$res->status_line);
|
||||
$headers = $res->headers();
|
||||
foreach my $k ( keys %$headers ) {
|
||||
Debug("Initial Header $k => $$headers{$k}");
|
||||
} # end foreach
|
||||
Error('Authentication still failed after updating REALM status: '.$res->status_line);
|
||||
} else {
|
||||
Error('Authentication failed, not a REALM problem');
|
||||
}
|
||||
@@ -111,6 +112,8 @@ sub open {
|
||||
} else {
|
||||
Debug('No headers line');
|
||||
} # end if headers
|
||||
} else {
|
||||
Debug('Failed to open '.$uri->canonical().$url.' status: '.$res->status_line());
|
||||
} # end if $res->status_line() eq '401 Unauthorized'
|
||||
} # end sub open
|
||||
|
||||
@@ -120,11 +123,11 @@ sub sendCmd {
|
||||
|
||||
$self->printMsg($cmd, 'Tx');
|
||||
|
||||
my $url = $ADDRESS.$cmd;
|
||||
my $url = $uri->canonical().$cmd;
|
||||
my $res = $self->{ua}->get($url);
|
||||
|
||||
if ( $res->is_success ) {
|
||||
Debug('sndCmd command: ' . $url . ' content: '.$res->content);
|
||||
Debug('sndCmd command: '.$url.' content: '.$res->content);
|
||||
return !undef;
|
||||
}
|
||||
|
||||
|
||||
@@ -143,10 +143,10 @@ sub PutCmd {
|
||||
} else {
|
||||
Info('Missing username and password in Control Address.');
|
||||
}
|
||||
Fatal($res->status_line);
|
||||
Error($res->status_line);
|
||||
}
|
||||
} else {
|
||||
Fatal($res->status_line);
|
||||
Error($res->status_line);
|
||||
}
|
||||
} # end unless res->is_success
|
||||
} # end sub putCmd
|
||||
|
||||
@@ -133,6 +133,7 @@ sub sendCmd {
|
||||
my $result = undef;
|
||||
|
||||
$self->printMsg($cmd, 'Tx');
|
||||
$self->printMsg($msg, 'Tx');
|
||||
|
||||
my $server_endpoint = 'http://'.$address.':'.$port.'/'.$cmd;
|
||||
my $req = HTTP::Request->new(POST => $server_endpoint);
|
||||
@@ -147,6 +148,7 @@ sub sendCmd {
|
||||
|
||||
if ( $res->is_success ) {
|
||||
$result = !undef;
|
||||
Debug("Result: " . $res->content());
|
||||
} else {
|
||||
Error("After sending PTZ command, camera returned the following error:'".$res->status_line()."'\nMSG:$msg\nResponse:".$res->content);
|
||||
}
|
||||
@@ -208,12 +210,56 @@ sub reset {
|
||||
$self->sendCmd($cmd, $msg, $content_type);
|
||||
}
|
||||
|
||||
sub moveMap {
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $x = $self->getParam($params,'xcoord');
|
||||
my $y = $self->getParam($params,'ycoord');
|
||||
Debug("Move map to $x x $y");
|
||||
|
||||
my $cmd = 'onvif/PTZ';
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">' . ((%identity) ? authentificationHeader($identity{username}, $identity{password}) : '') . '<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<AbsoluteMove xmlns="http://www.onvif.org/ver20/ptz/wsdl">
|
||||
<ProfileToken>' . $profileToken . '</ProfileToken>
|
||||
<Position><PanTilt x="'.$x.'" y="'.$y.'" xmlns="http://www.onvif.org/ver10/schema"/></Position>
|
||||
<Speed><Zoom x="1" xmlns="http://www.onvif.org/ver10/schema"/></Speed>
|
||||
</AbsoluteMove></s:Body></s:Envelope>';
|
||||
my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"';
|
||||
$self->sendCmd($cmd, $msg, $content_type);
|
||||
}
|
||||
|
||||
sub moveRel {
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $x = $self->getParam($params,'xcoord');
|
||||
my $speed = $self->getParam($params,'speed');
|
||||
my $y = $self->getParam($params,'ycoord');
|
||||
Debug("Move rel to $x x $y");
|
||||
|
||||
my $cmd = 'onvif/PTZ';
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">' . ((%identity) ? authentificationHeader($identity{username}, $identity{password}) : '') . '<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<RelativeMove xmlns="http://www.onvif.org/ver20/ptz/wsdl">
|
||||
<ProfileToken>' . $profileToken . '</ProfileToken>
|
||||
<Translation>
|
||||
<PanTilt x="'.$x.'" y="'.$y.'" xmlns="http://www.onvif.org/ver10/schema" space="http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace"/>
|
||||
<Zoom x="1"/>
|
||||
</Translation>
|
||||
<!--<Speed><Zoom x="'.$speed.'" xmlns="http://www.onvif.org/ver10/schema" space="http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace"/></Speed>_-->
|
||||
</RelativeMove></s:Body></s:Envelope>';
|
||||
my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"';
|
||||
$self->sendCmd($cmd, $msg, $content_type);
|
||||
}
|
||||
|
||||
#Up Arrow
|
||||
sub moveConUp {
|
||||
Debug('Move Up');
|
||||
my $self = shift;
|
||||
my $cmd = 'onvif/PTZ';
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">' . ((%identity) ? authentificationHeader($identity{username}, $identity{password}) : '') . '<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><ContinuousMove xmlns="http://www.onvif.org/ver20/ptz/wsdl"><ProfileToken>' . $profileToken . '</ProfileToken><Velocity><PanTilt x="0" y="0.5" xmlns="http://www.onvif.org/ver10/schema"/></Velocity></ContinuousMove></s:Body></s:Envelope>';
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">' . ((%identity) ? authentificationHeader($identity{username}, $identity{password}) : '') . '<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<ContinuousMove xmlns="http://www.onvif.org/ver20/ptz/wsdl">
|
||||
<ProfileToken>' . $profileToken . '</ProfileToken>
|
||||
<Velocity><PanTilt x="0" y="0.5" xmlns="http://www.onvif.org/ver10/schema"/></Velocity>
|
||||
</ContinuousMove></s:Body></s:Envelope>';
|
||||
my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"';
|
||||
$self->sendCmd($cmd, $msg, $content_type);
|
||||
$self->autoStop($self->{Monitor}->{AutoStopTimeout});
|
||||
|
||||
@@ -82,6 +82,13 @@ sub sendCmd {
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub reboot {
|
||||
my $self = shift;
|
||||
Debug('Camera Rebot');
|
||||
my $cmd = '/admin/reboot.cgi?type=0';
|
||||
$self->sendCmd($cmd);
|
||||
}
|
||||
|
||||
sub reset {
|
||||
my $self = shift;
|
||||
Debug('Camera Reset');
|
||||
|
||||
@@ -146,15 +146,15 @@ sub zmDbGetMonitors {
|
||||
|
||||
if ( $function ) {
|
||||
if ( $function == DB_MON_CAPT ) {
|
||||
$sql .= " where Function >= 'Monitor'";
|
||||
$sql .= " where `Function` >= 'Monitor'";
|
||||
} elsif ( $function == DB_MON_ACTIVE ) {
|
||||
$sql .= " where Function > 'Monitor'";
|
||||
$sql .= " where `Function` > 'Monitor'";
|
||||
} elsif ( $function == DB_MON_MOTION ) {
|
||||
$sql .= " where Function = 'Modect' or Function = 'Mocord'";
|
||||
$sql .= " where `Function` = 'Modect' or Function = 'Mocord'";
|
||||
} elsif ( $function == DB_MON_RECORD ) {
|
||||
$sql .= " where Function = 'Record' or Function = 'Mocord'";
|
||||
$sql .= " where `Function` = 'Record' or Function = 'Mocord'";
|
||||
} elsif ( $function == DB_MON_PASSIVE ) {
|
||||
$sql .= " where Function = 'Nodect'";
|
||||
$sql .= " where `Function` = 'Nodect'";
|
||||
}
|
||||
}
|
||||
my $sth = $dbh->prepare_cached( $sql );
|
||||
|
||||
@@ -352,6 +352,11 @@ sub GenerateVideo {
|
||||
sub delete {
|
||||
my $event = $_[0];
|
||||
|
||||
if ( !$event->canEdit() ) {
|
||||
Warning('No permission to delete event.');
|
||||
return 'No permission to delete event.';
|
||||
}
|
||||
|
||||
my $in_zmaudit = ( $0 =~ 'zmaudit.pl$');
|
||||
|
||||
if ( ! $in_zmaudit ) {
|
||||
@@ -363,7 +368,7 @@ sub delete {
|
||||
return;
|
||||
}
|
||||
if ( !($event->Storage()->Path() and -e $event->Storage()->Path()) ) {
|
||||
Warning('Not deleting event because storage path doesn\'t exist');
|
||||
Warning('Not deleting event because storage path ('.$event->Storage()->Path().') doesn\'t exist');
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -402,6 +407,11 @@ sub delete {
|
||||
sub delete_files {
|
||||
my $event = shift;
|
||||
|
||||
if ( !$event->canEdit() ) {
|
||||
Warning('No permission to delete event.');
|
||||
return 'No permission to delete event.';
|
||||
}
|
||||
|
||||
foreach my $Storage (
|
||||
@_ ? ($_[0]) : (
|
||||
new ZoneMinder::Storage($$event{StorageId}),
|
||||
@@ -570,6 +580,11 @@ sub DiskSpace {
|
||||
sub CopyTo {
|
||||
my ( $self, $NewStorage ) = @_;
|
||||
|
||||
if ( !$self->canEdit() ) {
|
||||
Warning('No permission to copy event.');
|
||||
return 'No permission to copy event.';
|
||||
}
|
||||
|
||||
my $OldStorage = $self->Storage(undef);
|
||||
my ( $OldPath ) = ( $self->Path() =~ /^(.*)$/ ); # De-taint
|
||||
if ( ! -e $OldPath ) {
|
||||
@@ -734,8 +749,13 @@ sub CopyTo {
|
||||
} # end sub CopyTo
|
||||
|
||||
sub MoveTo {
|
||||
|
||||
my ( $self, $NewStorage ) = @_;
|
||||
|
||||
if ( !$self->canEdit() ) {
|
||||
Warning('No permission to move event.');
|
||||
return 'No permission to move event.';
|
||||
}
|
||||
|
||||
my $OldStorage = $self->Storage(undef);
|
||||
|
||||
my $error = $self->CopyTo($NewStorage);
|
||||
@@ -857,16 +877,32 @@ sub files {
|
||||
|
||||
sub has_capture_jpegs {
|
||||
@{$_[0]{capture_jpegs}} = grep(/^\d+\-capture\.jpg$/, $_[0]->files());
|
||||
Debug("have " . @{$_[0]{capture_jpegs}} . " capture jpegs");
|
||||
Debug('have ' . @{$_[0]{capture_jpegs}} . ' capture jpegs');
|
||||
return @{$_[0]{capture_jpegs}} ? 1 : 0;
|
||||
}
|
||||
|
||||
sub has_analyse_jpegs {
|
||||
@{$_[0]{analyse_jpegs}} = grep(/^\d+\-analyse\.jpg$/, $_[0]->files());
|
||||
Debug("have " . @{$_[0]{analyse_jpegs}} . " analyse jpegs");
|
||||
Debug('have ' . @{$_[0]{analyse_jpegs}} . ' analyse jpegs');
|
||||
return @{$_[0]{analyse_jpegs}} ? 1 : 0;
|
||||
}
|
||||
|
||||
sub canEdit {
|
||||
my $self = shift;
|
||||
if ( !$ZoneMinder::user ) {
|
||||
# No user loaded... assume running as system
|
||||
return 1;
|
||||
}
|
||||
if ( !$$ZoneMinder::user{MonitorIds} ) {
|
||||
# User has no monitor limitations
|
||||
return 1;
|
||||
}
|
||||
if ( $$ZoneMinder::user{Events} eq 'Edit' ) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
} # end sub canEdit
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
||||
|
||||
@@ -49,49 +49,34 @@ use ZoneMinder::Database qw(:all);
|
||||
require ZoneMinder::Storage;
|
||||
require ZoneMinder::Server;
|
||||
|
||||
sub Name {
|
||||
if ( @_ > 1 ) {
|
||||
$_[0]{Name} = $_[1];
|
||||
}
|
||||
return $_[0]{Name};
|
||||
} # end sub Path
|
||||
use vars qw/ $table $primary_key %fields /;
|
||||
$table = 'Users';
|
||||
$primary_key = 'Id';
|
||||
|
||||
sub find {
|
||||
shift if $_[0] eq 'ZoneMinder::Filter';
|
||||
my %sql_filters = @_;
|
||||
|
||||
my $sql = 'SELECT * FROM Filters';
|
||||
my @sql_filters;
|
||||
my @sql_values;
|
||||
|
||||
if ( exists $sql_filters{Name} ) {
|
||||
push @sql_filters , ' Name = ? ';
|
||||
push @sql_values, $sql_filters{Name};
|
||||
}
|
||||
|
||||
$sql .= ' WHERE ' . join(' AND ', @sql_filters ) if @sql_filters;
|
||||
$sql .= ' LIMIT ' . $sql_filters{limit} if $sql_filters{limit};
|
||||
|
||||
my $sth = $ZoneMinder::Database::dbh->prepare_cached($sql)
|
||||
or Fatal("Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr());
|
||||
my $res = $sth->execute(@sql_values)
|
||||
or Fatal("Can't execute '$sql': ".$sth->errstr());
|
||||
|
||||
my @results;
|
||||
|
||||
while( my $db_filter = $sth->fetchrow_hashref() ) {
|
||||
my $filter = new ZoneMinder::Filter($$db_filter{Id}, $db_filter);
|
||||
push @results, $filter;
|
||||
} # end while
|
||||
$sth->finish();
|
||||
|
||||
return @results;
|
||||
}
|
||||
|
||||
sub find_one {
|
||||
my @results = find(@_);
|
||||
return $results[0] if @results;
|
||||
}
|
||||
%fields = map { $_ => $_ } qw(
|
||||
Id
|
||||
Name
|
||||
Query_json
|
||||
AutoArchive
|
||||
AutoVideo
|
||||
AutoUpload
|
||||
AutoEmail
|
||||
EmailTo
|
||||
EmailSubject
|
||||
EmailBody
|
||||
AutoMessage
|
||||
AutoExecute
|
||||
AutoExecuteCmd
|
||||
AutoDelete
|
||||
AutoMove
|
||||
AutoMoveTo
|
||||
AutoCopy
|
||||
AutoCopyTo
|
||||
UpdateDiskSpace
|
||||
UserId
|
||||
Background
|
||||
Concurrent
|
||||
);
|
||||
|
||||
sub Execute {
|
||||
my $self = $_[0];
|
||||
@@ -324,14 +309,9 @@ sub Sql {
|
||||
} # end if terms
|
||||
|
||||
if ( $self->{Sql} ) {
|
||||
if ( $self->{AutoMessage} ) {
|
||||
# Include all events, including events that are still ongoing
|
||||
# and have no EndTime yet
|
||||
$sql .= ' WHERE ( '.$self->{Sql}.' )';
|
||||
} else {
|
||||
# Only include closed events (events with valid EndTime)
|
||||
$sql .= ' WHERE (E.EndTime IS NOT NULL) AND ( '.$self->{Sql}.' )';
|
||||
}
|
||||
$sql .= ' WHERE ( '.$self->{Sql}.' )';
|
||||
}
|
||||
my @auto_terms;
|
||||
if ( $self->{AutoArchive} ) {
|
||||
@@ -458,6 +438,15 @@ sub DateTimeToSQL {
|
||||
return POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime($dt_val));
|
||||
}
|
||||
|
||||
sub User {
|
||||
my $self = shift;
|
||||
$$self{User} = shift if @_;
|
||||
if ( ! $$self{User} and $$self{UserId} ) {
|
||||
$$self{User} = ZoneMinder::User->find_one(Id=>$$self{UserId});
|
||||
}
|
||||
return $$self{User};
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
# Below is stub documentation for your module. You'd better edit it!
|
||||
|
||||
@@ -28,6 +28,9 @@ our %EXPORT_TAGS = (
|
||||
makePath
|
||||
jsonEncode
|
||||
jsonDecode
|
||||
systemStatus
|
||||
packageControl
|
||||
daemonControl
|
||||
) ]
|
||||
);
|
||||
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
||||
@@ -342,7 +345,7 @@ sub createEvent {
|
||||
." to ".$frame->{capturePath}.": $!"
|
||||
);
|
||||
setFileOwner( $frame->{capturePath} );
|
||||
if ( 0 && $Config{ZM_CREATE_ANALYSIS_IMAGES} ) {
|
||||
if ( $event->{SaveJPEGs} > 1 ) {
|
||||
$frame->{analysePath} = sprintf(
|
||||
"%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}
|
||||
."d-analyse.jpg"
|
||||
@@ -531,6 +534,38 @@ sub jsonDecode {
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub packageControl {
|
||||
my $command = shift;
|
||||
my $string = $Config{ZM_PATH_BIN}.'/zmpkg.pl '.$command;
|
||||
$string .= ' 2>/dev/null >&- <&- >/dev/null';
|
||||
executeShellCommand($string);
|
||||
}
|
||||
|
||||
sub daemonControl {
|
||||
my ($command, $daemon, $args) = @_;
|
||||
my $string = $Config{ZM_PATH_BIN}.'/zmdc.pl '.$command;
|
||||
if ( $daemon ) {
|
||||
$string .= ' ' . $daemon;
|
||||
if ( $args ) {
|
||||
$string .= ' ' . $args;
|
||||
}
|
||||
}
|
||||
#$string .= ' 2>/dev/null >&- <&- >/dev/null';
|
||||
executeShellCommand($string);
|
||||
}
|
||||
|
||||
sub systemStatus {
|
||||
my $command = $Config{ZM_PATH_BIN}.'/zmdc.pl check';
|
||||
my $output = qx($command);
|
||||
my $status = $? >> 8;
|
||||
if ( $status || logDebugging() ) {
|
||||
$output = '' if !defined($output);
|
||||
chomp($output);
|
||||
Debug("Command: $command Output: $output");
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
# Below is stub documentation for your module. You'd better edit it!
|
||||
@@ -542,7 +577,6 @@ ZoneMinder::General - Utility Functions for ZoneMinder
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use ZoneMinder::General;
|
||||
blah blah blah
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
@@ -561,6 +595,9 @@ of the ZoneMinder scripts
|
||||
makePath
|
||||
jsonEncode
|
||||
jsonDecode
|
||||
packageControl
|
||||
daemonControl
|
||||
systemStatus
|
||||
) ]
|
||||
|
||||
|
||||
|
||||
@@ -162,6 +162,8 @@ our $mem_data = {
|
||||
imagesize => { type=>'uint32', seq=>$mem_seq++ },
|
||||
epadding1 => { type=>'uint32', seq=>$mem_seq++ },
|
||||
startup_time => { type=>'time_t64', seq=>$mem_seq++ },
|
||||
zmc_heartbeat_time => { type=>'time_t64', seq=>$mem_seq++ },
|
||||
zma_heartbeat_time => { type=>'time_t64', seq=>$mem_seq++ },
|
||||
last_write_time => { type=>'time_t64', seq=>$mem_seq++ },
|
||||
last_read_time => { type=>'time_t64', seq=>$mem_seq++ },
|
||||
control_state => { type=>'uint8[256]', seq=>$mem_seq++ },
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
# ==========================================================================
|
||||
#
|
||||
# ZoneMinder User Module
|
||||
# Copyright (C) 2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# ==========================================================================
|
||||
|
||||
package ZoneMinder::Frame;
|
||||
|
||||
use 5.006;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
require ZoneMinder::Base;
|
||||
require ZoneMinder::Object;
|
||||
|
||||
use parent qw(ZoneMinder::Object);
|
||||
|
||||
use vars qw/ $table $primary_key %fields /;
|
||||
$table = 'Users';
|
||||
$primary_key = 'Id';
|
||||
|
||||
%fields = map { $_ => $_ } qw(
|
||||
Id
|
||||
Username
|
||||
Password
|
||||
Language
|
||||
Enabled
|
||||
Stream
|
||||
Events
|
||||
Control
|
||||
Monitors
|
||||
Groups
|
||||
Devices
|
||||
System
|
||||
MaxBandwidth
|
||||
MonitorIds
|
||||
TokenMinExpiry
|
||||
APIEnabled
|
||||
);
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
ZoneMinder::User - Perl Class for Users
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use ZoneMinder::User;
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Isaac Connor, E<lt>isaac@zoneminder.comE<gt>
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
Copyright (C) 2001-2017 ZoneMinder LLC
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the same terms as Perl itself, either Perl version 5.8.3 or,
|
||||
at your option, any later version of Perl 5 you may have available.
|
||||
|
||||
|
||||
=cut
|
||||
@@ -1059,6 +1059,7 @@ sub delete_empty_directories {
|
||||
}
|
||||
} # end sub delete_empty_directories
|
||||
|
||||
# The idea is that the youngest file in the event directory gives us the event starttime
|
||||
sub time_of_youngest_file {
|
||||
my $dir = shift;
|
||||
|
||||
@@ -1067,14 +1068,13 @@ sub time_of_youngest_file {
|
||||
return;
|
||||
}
|
||||
my $youngest = (stat($dir))[9];
|
||||
Debug("stat of $dir is $youngest");
|
||||
Debug("stat of dir $dir is $youngest");
|
||||
foreach my $file ( readdir( DIR ) ) {
|
||||
next if $file =~ /^\./;
|
||||
$_ = (stat($dir))[9];
|
||||
$youngest = $_ if $_ and ( $_ < $youngest );
|
||||
#Debug("stat of $dir is $_ < $youngest");
|
||||
Debug("Found younger file $file at $youngest");
|
||||
}
|
||||
Debug("stat of $dir is $youngest");
|
||||
return $youngest;
|
||||
} # end sub time_of_youngest_file
|
||||
|
||||
|
||||
@@ -49,9 +49,9 @@ my %options;
|
||||
GetOptions(
|
||||
'id=i' =>\$id,
|
||||
'command=s' =>\$options{command},
|
||||
'xcoord=i' =>\$options{xcoord},
|
||||
'ycoord=i' =>\$options{ycoord},
|
||||
'speed=i' =>\$options{speed},
|
||||
'xcoord=f' =>\$options{xcoord},
|
||||
'ycoord=f' =>\$options{ycoord},
|
||||
'speed=f' =>\$options{speed},
|
||||
'step=i' =>\$options{step},
|
||||
'panspeed=i' =>\$options{panspeed},
|
||||
'tiltspeed=i' =>\$options{tiltspeed},
|
||||
|
||||
+9
-8
@@ -160,7 +160,7 @@ if ( !$server_up ) {
|
||||
use ZoneMinder::Server qw(CpuLoad);
|
||||
if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef,
|
||||
'NotRunning', &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) {
|
||||
Error("Failed Updating status of Server record to Not RUnning for Id=$Config{ZM_SERVER_ID}" . $dbh->errstr());
|
||||
Error('Failed Updating status of Server record to Not Running for Id='.$Config{ZM_SERVER_ID}.': '.$dbh->errstr());
|
||||
}
|
||||
}
|
||||
# Server is not up. Some commands can still be handled
|
||||
@@ -173,7 +173,7 @@ if ( !$server_up ) {
|
||||
print("stopped\n");
|
||||
exit();
|
||||
} elsif ( $command ne 'startup' ) {
|
||||
print('Unable to connect to server using socket at ' . SOCK_FILE . "\n");
|
||||
print('Unable to connect to server using socket at '.SOCK_FILE."\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
@@ -189,10 +189,10 @@ if ( !$server_up ) {
|
||||
|
||||
socket(CLIENT, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!");
|
||||
my $attempts = 0;
|
||||
while( !connect(CLIENT, $saddr) ) {
|
||||
while ( !connect(CLIENT, $saddr) ) {
|
||||
$attempts++;
|
||||
Debug('Waiting for zmdc.pl server process at '.SOCK_FILE.", attempt $attempts");
|
||||
Fatal("Can't connect: $!") if $attempts > MAX_CONNECT_DELAY;
|
||||
Debug('Waiting for zmdc.pl server process at '.SOCK_FILE.', attempt '.$attempts);
|
||||
Fatal('Can\'t connect to zmdc.pl server process at '.SOCK_FILE.': '.$!) if $attempts > MAX_CONNECT_DELAY;
|
||||
usleep(200000);
|
||||
} # end while
|
||||
} elsif ( defined($cpid) ) {
|
||||
@@ -255,13 +255,13 @@ sub run {
|
||||
close($PID);
|
||||
} else {
|
||||
# Log not initialized at this point so use die instead
|
||||
die "Can't open pid file at ".ZM_PID."\n";
|
||||
die 'Can\'t open pid file at '.ZM_PID."\n";
|
||||
}
|
||||
|
||||
my $fd = 0;
|
||||
|
||||
# This also closes dbh and CLIENT and SERVER
|
||||
while( $fd < POSIX::sysconf(&POSIX::_SC_OPEN_MAX) ) {
|
||||
while ( $fd < POSIX::sysconf(&POSIX::_SC_OPEN_MAX) ) {
|
||||
POSIX::close($fd++);
|
||||
}
|
||||
|
||||
@@ -301,13 +301,14 @@ sub run {
|
||||
my $timeout = 1;
|
||||
my $secs_count = 0;
|
||||
|
||||
while( !$zm_terminate ) {
|
||||
while ( !$zm_terminate ) {
|
||||
|
||||
if ( $Config{ZM_SERVER_ID} ) {
|
||||
if ( ! ( $secs_count % 60 ) ) {
|
||||
while ( (!$zm_terminate) and !($dbh and $dbh->ping()) ) {
|
||||
Warning("Not connected to db ($dbh)".($dbh?' ping('.$dbh->ping().')':''). ($DBI::errstr?" errstr($DBI::errstr)":'').' Reconnecting');
|
||||
$dbh = zmDbConnect();
|
||||
sleep 10 if !$dbh;
|
||||
}
|
||||
last if $zm_terminate;
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ $SIG{__DIE__} = \&handler;
|
||||
# =========================================================================
|
||||
# Debug
|
||||
|
||||
use Data::Hexdumper qw(hexdump);
|
||||
#use Data::Hexdumper qw(hexdump);
|
||||
#use Devel::Peek;
|
||||
|
||||
sub dump_mapped {
|
||||
@@ -116,12 +116,12 @@ sub dump_mapped {
|
||||
printf("Mapped at %x\n", $monitor->{MMapAddr});
|
||||
# Dump($mmap);
|
||||
if ( $mmap && $$mmap ) {
|
||||
print hexdump(
|
||||
data => $$mmap, # what to dump
|
||||
output_format => ' %4a : %S %S %S %S %S %S %S %S : %d',
|
||||
# start_position => 336, # start at this offset ...
|
||||
end_position => 400 # ... and end at this offset
|
||||
);
|
||||
#print hexdump(
|
||||
#data => $$mmap, # what to dump
|
||||
#output_format => ' %4a : %S %S %S %S %S %S %S %S : %d',
|
||||
## start_position => 336, # start at this offset ...
|
||||
#end_position => 400 # ... and end at this offset
|
||||
#);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,49 @@ while( 1 ) {
|
||||
$dbh->do('DELETE FROM Events_Week WHERE StartTime < DATE_SUB(NOW(), INTERVAL 1 week)') or Error($dbh->errstr());
|
||||
$dbh->do('DELETE FROM Events_Month WHERE StartTime < DATE_SUB(NOW(), INTERVAL 1 month)') or Error($dbh->errstr());
|
||||
|
||||
# Prune the Logs table if required
|
||||
if ( $Config{ZM_LOG_DATABASE_LIMIT} ) {
|
||||
if ( $Config{ZM_LOG_DATABASE_LIMIT} =~ /^\d+$/ ) {
|
||||
# Number of rows
|
||||
my $selectLogRowCountSql = 'SELECT count(*) AS `Rows` FROM `Logs`';
|
||||
my $selectLogRowCountSth = $dbh->prepare_cached( $selectLogRowCountSql )
|
||||
or Fatal("Can't prepare '$selectLogRowCountSql': ".$dbh->errstr());
|
||||
my $res = $selectLogRowCountSth->execute()
|
||||
or Fatal("Can't execute: ".$selectLogRowCountSth->errstr());
|
||||
my $row = $selectLogRowCountSth->fetchrow_hashref();
|
||||
my $logRows = $row->{Rows};
|
||||
if ( $logRows > $Config{ZM_LOG_DATABASE_LIMIT} ) {
|
||||
my $deleteLogByRowsSql = 'DELETE low_priority FROM `Logs` ORDER BY `TimeKey` ASC LIMIT ?';
|
||||
my $deleteLogByRowsSth = $dbh->prepare_cached( $deleteLogByRowsSql )
|
||||
or Fatal("Can't prepare '$deleteLogByRowsSql': ".$dbh->errstr());
|
||||
$res = $deleteLogByRowsSth->execute( $logRows - $Config{ZM_LOG_DATABASE_LIMIT} )
|
||||
or Fatal("Can't execute: ".$deleteLogByRowsSth->errstr());
|
||||
if ( $deleteLogByRowsSth->rows() ) {
|
||||
Debug('Deleted '.$deleteLogByRowsSth->rows().' log table entries by count');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
# Time of record
|
||||
|
||||
# 7 days is invalid. We need to remove the s
|
||||
if ( $Config{ZM_LOG_DATABASE_LIMIT} =~ /^(.*)s$/ ) {
|
||||
$Config{ZM_LOG_DATABASE_LIMIT} = $1;
|
||||
}
|
||||
my $deleted_rows;
|
||||
do {
|
||||
my $deleteLogByTimeSql =
|
||||
'DELETE FROM `Logs`
|
||||
WHERE `TimeKey` < unix_timestamp(now() - interval '.$Config{ZM_LOG_DATABASE_LIMIT}.') LIMIT 100';
|
||||
my $deleteLogByTimeSth = $dbh->prepare_cached( $deleteLogByTimeSql )
|
||||
or Fatal("Can't prepare '$deleteLogByTimeSql': ".$dbh->errstr());
|
||||
my $res = $deleteLogByTimeSth->execute()
|
||||
or Fatal("Can't execute: ".$deleteLogByTimeSth->errstr());
|
||||
$deleted_rows = $deleteLogByTimeSth->rows();
|
||||
Debug("Deleted $deleted_rows log table entries by time");
|
||||
} while ( $deleted_rows );
|
||||
}
|
||||
} # end if ZM_LOG_DATABASE_LIMIT
|
||||
|
||||
sleep($Config{ZM_STATS_UPDATE_INTERVAL});
|
||||
} # end while (1)
|
||||
|
||||
|
||||
@@ -119,7 +119,6 @@ if ( !$monitor->{CanMoveMap} ) {
|
||||
}
|
||||
}
|
||||
|
||||
Debug("Found monitor for id '$monitor'");
|
||||
exit(-1) if !zmMemVerify($monitor);
|
||||
|
||||
sub Suspend {
|
||||
|
||||
+112
-85
@@ -119,6 +119,9 @@ GetOptions(
|
||||
) or pod2usage(-exitstatus => -1);
|
||||
|
||||
my $dbh = zmDbConnect(undef, { mysql_multi_statements=>1 } );
|
||||
if ( !$dbh ) {
|
||||
die "Unable to connect to db\n";
|
||||
}
|
||||
$Config{ZM_DB_USER} = $dbUser;
|
||||
$Config{ZM_DB_PASS} = $dbPass;
|
||||
# we escape dbpass with single quotes so that $ in the password has no effect, but dbpass could have a ' in it.
|
||||
@@ -128,18 +131,18 @@ if ( ! ($check || $freshen || $rename || $zoneFix || $migrateEvents || $version)
|
||||
if ( $Config{ZM_DYN_DB_VERSION} ) {
|
||||
$version = $Config{ZM_DYN_DB_VERSION};
|
||||
} else {
|
||||
print( STDERR "Please give a valid option\n" );
|
||||
print(STDERR "Please give a valid option\n");
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ($check + $freshen + $rename + $zoneFix + $migrateEvents + ($version?1:0)) > 1 ) {
|
||||
print( STDERR "Please give only one option\n" );
|
||||
print(STDERR "Please give only one option\n");
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
|
||||
if ( $check && $Config{ZM_CHECK_FOR_UPDATES} ) {
|
||||
print( "Update agent starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
|
||||
print('Update agent starting at '.strftime('%y/%m/%d %H:%M:%S', localtime() )."\n");
|
||||
|
||||
my $currVersion = $Config{ZM_DYN_CURR_VERSION};
|
||||
my $lastVersion = $Config{ZM_DYN_LAST_VERSION};
|
||||
@@ -149,23 +152,23 @@ if ( $check && $Config{ZM_CHECK_FOR_UPDATES} ) {
|
||||
$currVersion = $Config{ZM_VERSION};
|
||||
|
||||
my $sql = "update Config set Value = ? where Name = 'ZM_DYN_CURR_VERSION'";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( "$currVersion" ) or die( "Can't execute: ".$sth->errstr() );
|
||||
my $sth = $dbh->prepare_cached($sql) or die("Can't prepare '$sql': ".$dbh->errstr());
|
||||
my $res = $sth->execute($currVersion) or die("Can't execute: ".$sth->errstr());
|
||||
$sth->finish();
|
||||
}
|
||||
|
||||
while( 1 ) {
|
||||
while ( 1 ) {
|
||||
my $now = time();
|
||||
if ( !$lastVersion || !$lastCheck || (($now-$lastCheck) > CHECK_INTERVAL) ) {
|
||||
Info( "Checking for updates\n" );
|
||||
Info('Checking for updates');
|
||||
|
||||
use LWP::UserAgent;
|
||||
my $ua = LWP::UserAgent->new;
|
||||
$ua->agent( "ZoneMinder Update Agent/".ZM_VERSION );
|
||||
$ua->agent('ZoneMinder Update Agent/'.ZM_VERSION);
|
||||
if ( $Config{ZM_UPDATE_CHECK_PROXY} ) {
|
||||
$ua->proxy( 'http', $Config{ZM_UPDATE_CHECK_PROXY} );
|
||||
$ua->proxy('http', $Config{ZM_UPDATE_CHECK_PROXY});
|
||||
}
|
||||
my $req = HTTP::Request->new( GET=>'https://update.zoneminder.com/version.txt' );
|
||||
my $req = HTTP::Request->new(GET=>'https://update.zoneminder.com/version.txt');
|
||||
my $res = $ua->request($req);
|
||||
|
||||
if ( $res->is_success ) {
|
||||
@@ -173,63 +176,63 @@ if ( $check && $Config{ZM_CHECK_FOR_UPDATES} ) {
|
||||
chomp($lastVersion);
|
||||
$lastCheck = $now;
|
||||
|
||||
Info( "Got version: '".$lastVersion."'\n" );
|
||||
Info('Got version: '.$lastVersion);
|
||||
|
||||
my $lv_sql = "update Config set Value = ? where Name = 'ZM_DYN_LAST_VERSION'";
|
||||
my $lv_sth = $dbh->prepare_cached( $lv_sql ) or die( "Can't prepare '$lv_sql': ".$dbh->errstr() );
|
||||
my $lv_res = $lv_sth->execute( $lastVersion ) or die( "Can't execute: ".$lv_sth->errstr() );
|
||||
my $lv_sql = 'UPDATE Config SET Value = ? WHERE Name = \'ZM_DYN_LAST_VERSION\'';
|
||||
my $lv_sth = $dbh->prepare_cached($lv_sql) or die("Can't prepare '$lv_sql': ".$dbh->errstr());
|
||||
my $lv_res = $lv_sth->execute($lastVersion) or die("Can't execute: ".$lv_sth->errstr());
|
||||
$lv_sth->finish();
|
||||
|
||||
my $lc_sql = "update Config set Value = ? where Name = 'ZM_DYN_LAST_CHECK'";
|
||||
my $lc_sth = $dbh->prepare_cached( $lc_sql ) or die( "Can't prepare '$lc_sql': ".$dbh->errstr() );
|
||||
my $lc_res = $lc_sth->execute( $lastCheck ) or die( "Can't execute: ".$lc_sth->errstr() );
|
||||
my $lc_sql = 'UPDATE Config SET Value = ? WHERE Name = \'ZM_DYN_LAST_CHECK\'';
|
||||
my $lc_sth = $dbh->prepare_cached($lc_sql) or die("Can't prepare '$lc_sql': ".$dbh->errstr());
|
||||
my $lc_res = $lc_sth->execute($lastCheck) or die("Can't execute: ".$lc_sth->errstr());
|
||||
$lc_sth->finish();
|
||||
} else {
|
||||
Error( "Error check failed: '".$res->status_line()."'\n" );
|
||||
Error('Error check failed: \''.$res->status_line().'\'');
|
||||
}
|
||||
}
|
||||
sleep( 3600 );
|
||||
sleep(3600);
|
||||
}
|
||||
print( "Update agent exiting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
|
||||
print('Update agent exiting at '.strftime('%y/%m/%d %H:%M:%S', localtime())."\n");
|
||||
}
|
||||
|
||||
if ( $rename ) {
|
||||
require File::Find;
|
||||
|
||||
chdir( EVENT_PATH );
|
||||
chdir(EVENT_PATH);
|
||||
|
||||
sub renameImage {
|
||||
my $file = $_;
|
||||
|
||||
# Ignore directories
|
||||
if ( -d $file ) {
|
||||
print( "Checking directory '$file'\n" );
|
||||
print("Checking directory '$file'\n");
|
||||
return;
|
||||
}
|
||||
if ( $file !~ /(capture|analyse)-(\d+)(\.jpg)/ ) {
|
||||
return;
|
||||
}
|
||||
my $newFile = "$2-$1$3";
|
||||
my $newFile = $2.'-'.$1.$3;
|
||||
|
||||
print( "Renaming '$file' to '$newFile'\n" );
|
||||
rename( $file, $newFile ) or warn( "Can't rename '$file' to '$newFile'" );
|
||||
print("Renaming '$file' to '$newFile'\n");
|
||||
rename($file, $newFile) or warn("Can't rename '$file' to '$newFile'");
|
||||
}
|
||||
|
||||
File::Find::find( \&renameImage, '.' );
|
||||
}
|
||||
if ( $zoneFix ) {
|
||||
File::Find::find(\&renameImage, '.');
|
||||
} # end if rename
|
||||
|
||||
my $sql = "select Z.*, M.Width as MonitorWidth, M.Height as MonitorHeight from Zones as Z inner join Monitors as M on Z.MonitorId = M.Id where Z.Units = 'Percent'";
|
||||
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() );
|
||||
if ( $zoneFix ) {
|
||||
my $sql = "SELECT Z.*, M.Width AS MonitorWidth, M.Height AS MonitorHeight FROM Zones AS Z INNER JOIN Monitors AS M ON Z.MonitorId = M.Id WHERE Z.Units = 'Percent'";
|
||||
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 @zones;
|
||||
while( my $zone = $sth->fetchrow_hashref() ) {
|
||||
push( @zones, $zone );
|
||||
while ( my $zone = $sth->fetchrow_hashref() ) {
|
||||
push(@zones, $zone);
|
||||
}
|
||||
$sth->finish();
|
||||
|
||||
$sql = 'update Zones set MinAlarmPixels = ?, MaxAlarmPixels = ?, MinFilterPixels = ?, MaxFilterPixels = ?, MinBlobPixels = ?, MaxBlobPixels = ? where Id = ?';
|
||||
$sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
$sql = 'UPDATE Zones SET MinAlarmPixels = ?, MaxAlarmPixels = ?, MinFilterPixels = ?, MaxFilterPixels = ?, MinBlobPixels = ?, MaxBlobPixels = ? WHERE Id = ?';
|
||||
$sth = $dbh->prepare_cached($sql) or die("Can't prepare '$sql': ".$dbh->errstr());
|
||||
foreach my $zone ( @zones ) {
|
||||
my $zone_width = (($zone->{HiX}*$zone->{MonitorWidth})-($zone->{LoX}*$zone->{MonitorWidth}))/100;
|
||||
my $zone_height = (($zone->{HiY}*$zone->{MonitorHeight})-($zone->{LoY}*$zone->{MonitorHeight}))/100;
|
||||
@@ -243,78 +246,84 @@ if ( $zoneFix ) {
|
||||
($zone->{MinBlobPixels}*$monitor_area)/$zone_area,
|
||||
($zone->{MaxBlobPixels}*$monitor_area)/$zone_area,
|
||||
$zone->{Id}
|
||||
) or die( "Can't execute: ".$sth->errstr() );
|
||||
) or die("Can't execute: ".$sth->errstr());
|
||||
}
|
||||
$sth->finish();
|
||||
}
|
||||
} # end if zoneFix
|
||||
|
||||
if ( $migrateEvents ) {
|
||||
my $webUid = (getpwnam( $Config{ZM_WEB_USER} ))[2];
|
||||
my $webGid = (getgrnam( $Config{ZM_WEB_USER} ))[2];
|
||||
my $webUid = (getpwnam($Config{ZM_WEB_USER}))[2];
|
||||
my $webGid = (getgrnam($Config{ZM_WEB_USER}))[2];
|
||||
|
||||
if ( !(($> == 0) || ($> == $webUid)) ) {
|
||||
print( "Error, migrating events can only be done as user root or ".$Config{ZM_WEB_USER}.".\n" );
|
||||
exit( -1 );
|
||||
print("Error, migrating events can only be done as user root or ".$Config{ZM_WEB_USER}.".\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
# Run as web user/group
|
||||
$( = $webGid;
|
||||
$) = $webGid;
|
||||
$) = $webGid;
|
||||
$< = $webUid;
|
||||
$> = $webUid;
|
||||
|
||||
print( "\nAbout to convert saved events to deep storage, please ensure that ZoneMinder is fully stopped before proceeding.\nThis process is not easily reversible. Are you sure you wish to proceed?\n\nPress 'y' to continue or 'n' to abort : " );
|
||||
print('
|
||||
About to convert saved events to deep storage, please ensure that ZoneMinder is fully stopped before proceeding.
|
||||
This process is not easily reversible. Are you sure you wish to proceed?
|
||||
|
||||
Press \'y\' to continue or \'n\' to abort : ');
|
||||
my $response = <STDIN>;
|
||||
chomp( $response );
|
||||
chomp($response);
|
||||
while ( $response !~ /^[yYnN]$/ ) {
|
||||
print( "Please press 'y' to continue or 'n' to abort only : " );
|
||||
print("Please press 'y' to continue or 'n' to abort only : ");
|
||||
$response = <STDIN>;
|
||||
chomp( $response );
|
||||
chomp($response);
|
||||
}
|
||||
|
||||
if ( $response =~ /^[yY]$/ ) {
|
||||
print( "Converting all events to deep storage.\n" );
|
||||
print("Converting all events to deep storage.\n");
|
||||
|
||||
chdir( $Config{ZM_PATH_WEB} );
|
||||
my $sql = "select *, unix_timestamp(StartTime) as UnixStartTime from Events";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
chdir($Config{ZM_PATH_WEB});
|
||||
my $sql = 'SELECT *, unix_timestamp(StartTime) AS UnixStartTime FROM Events';
|
||||
my $sth = $dbh->prepare_cached($sql) or Fatal("Can't prepare '$sql': ".$dbh->errstr());
|
||||
my $res = $sth->execute();
|
||||
if ( !$res ) {
|
||||
Fatal( "Can't fetch Events: ".$sth->errstr() );
|
||||
Fatal("Can't fetch Events: ".$sth->errstr());
|
||||
}
|
||||
|
||||
while( my $event = $sth->fetchrow_hashref() ) {
|
||||
my $oldEventPath = $Config{ZM_DIR_EVENTS}.'/'.$event->{MonitorId}.'/'.$event->{Id};
|
||||
|
||||
if ( !-d $oldEventPath ) {
|
||||
print( "Warning, can't find old event path '$oldEventPath', already converted?\n" );
|
||||
print("Warning, can't find old event path '$oldEventPath', already converted?\n");
|
||||
next;
|
||||
}
|
||||
|
||||
print( "Converting event ".$event->{Id}."\n" );
|
||||
my $newDatePath = $Config{ZM_DIR_EVENTS}.'/'.$event->{MonitorId}.'/'.strftime( "%y/%m/%d", localtime($event->{UnixStartTime}) );
|
||||
my $newTimePath = strftime( "%H/%M/%S", localtime($event->{UnixStartTime}) );
|
||||
print('Converting event '.$event->{Id}."\n");
|
||||
my $newDatePath = $Config{ZM_DIR_EVENTS}.'/'.$event->{MonitorId}.'/'.strftime('%y/%m/%d', localtime($event->{UnixStartTime}));
|
||||
my $newTimePath = strftime('%H/%M/%S', localtime($event->{UnixStartTime}));
|
||||
my $newEventPath = $newDatePath.'/'.$newTimePath;
|
||||
( my $truncEventPath = $newEventPath ) =~ s|/\d+$||;
|
||||
makePath( $truncEventPath, $Config{ZM_PATH_WEB} );
|
||||
makePath($truncEventPath, $Config{ZM_PATH_WEB});
|
||||
my $idLink = $newDatePath.'/.'.$event->{Id};
|
||||
symlink( $newTimePath, $idLink ) or die( "Can't symlink $newTimePath -> $idLink: $!" );
|
||||
rename( $oldEventPath, $newEventPath ) or die( "Can't move $oldEventPath -> $newEventPath: $!" );
|
||||
symlink($newTimePath, $idLink) or die("Can't symlink $newTimePath -> $idLink: $!");
|
||||
rename($oldEventPath, $newEventPath) or die("Can't move $oldEventPath -> $newEventPath: $!");
|
||||
}
|
||||
$sth->finish();
|
||||
|
||||
print( "Updating configuration.\n" );
|
||||
print("Updating configuration.\n");
|
||||
$sql = "UPDATE `Config` SET `Value` = ? WHERE `Name` = 'ZM_USE_DEEP_STORAGE'";
|
||||
$sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
$res = $sth->execute( 1 ) or die( "Can't execute: ".$sth->errstr() );
|
||||
$sth = $dbh->prepare_cached($sql) or die( "Can't prepare '$sql': ".$dbh->errstr());
|
||||
$res = $sth->execute(1) or die("Can't execute: ".$sth->errstr());
|
||||
$sth->finish();
|
||||
|
||||
print( "All events converted.\n\n" );
|
||||
print("All events converted.\n\n");
|
||||
} else {
|
||||
print( "Aborting event conversion.\n\n" );
|
||||
print("Aborting event conversion.\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
if ( $freshen ) {
|
||||
print( "\nFreshening configuration in database\n" );
|
||||
print("\nFreshening configuration in database\n");
|
||||
migratePaths();
|
||||
migratePasswords();
|
||||
ZoneMinder::Config::loadConfigFromDB();
|
||||
@@ -326,8 +335,8 @@ if ( $interactive ) {
|
||||
# Now check for MyISAM Tables
|
||||
my @MyISAM_Tables;
|
||||
my $sql = "SELECT `table_name` FROM INFORMATION_SCHEMA.TABLES WHERE `table_schema`='zm' AND `engine` = 'MyISAM'";
|
||||
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 $sth = $dbh->prepare_cached($sql) or die("Can't prepare '$sql': ".$dbh->errstr());
|
||||
my $res = $sth->execute() or die("Can't execute: ".$sth->errstr());
|
||||
|
||||
while( my $dbTable = $sth->fetchrow() ) {
|
||||
push @MyISAM_Tables, $dbTable;
|
||||
@@ -335,17 +344,22 @@ if ( $interactive ) {
|
||||
$sth->finish();
|
||||
|
||||
if ( @MyISAM_Tables ) {
|
||||
print( "\nPrevious versions of ZoneMinder used the MyISAM database engine.\nHowever, the recommended database engine is InnoDB.\n");
|
||||
print( "\nHint: InnoDB tables are much less likely to be corrupted during an unclean shutdown.\n\nPress 'y' to convert your tables to InnoDB or 'n' to skip : ");
|
||||
print('
|
||||
Previous versions of ZoneMinder used the MyISAM database engine.
|
||||
However, the recommended database engine is InnoDB.
|
||||
|
||||
Hint: InnoDB tables are much less likely to be corrupted during an unclean shutdown.
|
||||
|
||||
Press \'y\' to convert your tables to InnoDB or \'n\' to skip : ');
|
||||
my $response = <STDIN>;
|
||||
chomp( $response );
|
||||
if ( $response =~ /^[yY]$/ ) {
|
||||
$dbh->do(q|SET sql_mode='traditional'|); # Elevate warnings to errors
|
||||
print "\nConverting MyISAM tables to InnoDB. Please wait.\n";
|
||||
foreach (@MyISAM_Tables) {
|
||||
print "\nConverting MyISAM tables to InnoDB. Please wait.\n";
|
||||
foreach ( @MyISAM_Tables ) {
|
||||
my $sql = "ALTER TABLE `$_` ENGINE = InnoDB";
|
||||
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 $sth = $dbh->prepare_cached($sql) or die("Can't prepare '$sql': ".$dbh->errstr());
|
||||
my $res = $sth->execute() or die("Can't execute: ".$sth->errstr());
|
||||
$sth->finish();
|
||||
}
|
||||
$dbh->do(q|SET sql_mode=''|); # Set mode back to default
|
||||
@@ -362,23 +376,31 @@ if ( $version ) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
print( "\nInitiating database upgrade to version ".ZM_VERSION." from version $version\n" );
|
||||
my $start_zm = 0;
|
||||
print("\nInitiating database upgrade to version ".ZM_VERSION." from version $version\n");
|
||||
if ( $interactive ) {
|
||||
if ( $Config{ZM_DYN_DB_VERSION} && $Config{ZM_DYN_DB_VERSION} ne $version ) {
|
||||
print( "\nWARNING - You have specified an upgrade from version $version but the database version found is ".$Config{ZM_DYN_DB_VERSION}.". Is this correct?\nPress enter to continue or ctrl-C to abort : " );
|
||||
if ( $Config{ZM_DYN_DB_VERSION} && ($Config{ZM_DYN_DB_VERSION} ne $version) ) {
|
||||
print("\nWARNING - You have specified an upgrade from version $version but the database version found is $Config{ZM_DYN_DB_VERSION}. Is this correct?\nPress enter to continue or ctrl-C to abort : ");
|
||||
my $response = <STDIN>;
|
||||
}
|
||||
|
||||
print( "\nPlease ensure that ZoneMinder is stopped on your system prior to upgrading the database.\nPress enter to continue or ctrl-C to stop : " );
|
||||
my $response = <STDIN>;
|
||||
if ( systemStatus() eq 'running' ) {
|
||||
print"\nZoneMinder system appears to be running. While not strictly required, it is advised to stop ZM during the update process. Would you like to stop ZM now? [Yn]:";
|
||||
my $response = <STDIN>;
|
||||
chomp($response);
|
||||
if ( $response !~ /Yy/ ) {
|
||||
packageControl('stop');
|
||||
$start_zm = 1;
|
||||
}
|
||||
}
|
||||
|
||||
print( "\nDo you wish to take a backup of your database prior to upgrading?\nThis may result in a large file in @ZM_TMPDIR@ if you have a lot of events.\nPress 'y' for a backup or 'n' to continue : " );
|
||||
$response = <STDIN>;
|
||||
chomp( $response );
|
||||
print("\nDo you wish to take a backup of your database prior to upgrading?\nThis may result in a large file in @ZM_TMPDIR@ if you have a lot of events.\nPress 'y' for a backup or 'n' to continue : ");
|
||||
my $response = <STDIN>;
|
||||
chomp($response);
|
||||
while ( $response !~ /^[yYnN]$/ ) {
|
||||
print( "Please press 'y' for a backup or 'n' to continue only : " );
|
||||
print("Please press 'y' for a backup or 'n' to continue only : ");
|
||||
$response = <STDIN>;
|
||||
chomp( $response );
|
||||
chomp($response);
|
||||
}
|
||||
|
||||
if ( $response =~ /^[yY]$/ ) {
|
||||
@@ -400,8 +422,8 @@ if ( $version ) {
|
||||
my $backup = '@ZM_TMPDIR@/'.$Config{ZM_DB_NAME}.'-'.$version.'.dump';
|
||||
$command .= ' --add-drop-table --databases '.$Config{ZM_DB_NAME}.' > '.$backup;
|
||||
print("Creating backup to $backup. This may take several minutes.\n");
|
||||
print("Executing '$command'\n") if logDebugging();
|
||||
($command) = $command =~ /(.*)/; # detaint
|
||||
print("Executing '$command'\n") if logDebugging();
|
||||
my $output = qx($command);
|
||||
my $status = $? >> 8;
|
||||
if ( $status || logDebugging() ) {
|
||||
@@ -936,7 +958,12 @@ if ( $version ) {
|
||||
#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() );
|
||||
#$sth->finish();
|
||||
|
||||
print("\nDatabase upgrade to version ".ZM_VERSION." successful.\n\n");
|
||||
if ( $start_zm ) {
|
||||
print("Starting ZM since we stopped it for the update\n");
|
||||
packageControl('start');
|
||||
}
|
||||
} # end if version
|
||||
|
||||
zmDbDisconnect();
|
||||
@@ -972,7 +999,7 @@ sub patchDB {
|
||||
my $dbh = shift;
|
||||
my $version = shift;
|
||||
|
||||
my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ );
|
||||
my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ ) if $Config{ZM_DB_HOST};
|
||||
my $command = 'mysql';
|
||||
if ( defined($portOrSocket) ) {
|
||||
if ( $portOrSocket =~ /^\// ) {
|
||||
@@ -980,7 +1007,7 @@ sub patchDB {
|
||||
} else {
|
||||
$command .= ' -h'.$host.' -P'.$portOrSocket;
|
||||
}
|
||||
} else {
|
||||
} elsif ( $host ) {
|
||||
$command .= ' -h'.$host;
|
||||
}
|
||||
if ( $dbUser ) {
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ target_link_libraries(zms zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS} ${CMAKE_DL_LIBS} bc
|
||||
|
||||
# Generate man files for the binaries destined for the bin folder
|
||||
FOREACH(CBINARY zma zmc zmu)
|
||||
POD2MAN(${CMAKE_CURRENT_SOURCE_DIR}/${CBINARY}.cpp zoneminder-${CBINARY} 8 ${ZM_MANPAGE_DEST_PREFIX})
|
||||
POD2MAN(${CMAKE_CURRENT_SOURCE_DIR}/${CBINARY}.cpp ${CBINARY} 8 ${ZM_MANPAGE_DEST_PREFIX})
|
||||
ENDFOREACH(CBINARY zma zmc zmu)
|
||||
|
||||
install(TARGETS zmc zma zmu RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
|
||||
+4
-3
@@ -48,11 +48,12 @@ Camera::Camera(
|
||||
record_audio(p_record_audio),
|
||||
bytes(0)
|
||||
{
|
||||
linesize = width * colours;
|
||||
pixels = width * height;
|
||||
imagesize = pixels * colours;
|
||||
imagesize = height * linesize;
|
||||
|
||||
Debug(2,"New camera id: %d width: %d height: %d colours: %d subpixelorder: %d capture: %d",
|
||||
monitor_id, width, height, colours, subpixelorder, capture);
|
||||
Debug(2, "New camera id: %d width: %d line size: %d height: %d colours: %d subpixelorder: %d capture: %d",
|
||||
monitor_id, width, linesize, height, colours, subpixelorder, capture);
|
||||
|
||||
monitor = NULL;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ protected:
|
||||
Monitor * monitor; // Null on instantiation, set as soon as possible.
|
||||
SourceType type;
|
||||
unsigned int width;
|
||||
unsigned int linesize;
|
||||
unsigned int height;
|
||||
unsigned int colours;
|
||||
unsigned int subpixelorder;
|
||||
@@ -70,6 +71,7 @@ public:
|
||||
bool IscURL() const { return type == CURL_SRC; }
|
||||
bool IsVNC() const { return type == VNC_SRC; }
|
||||
unsigned int Width() const { return width; }
|
||||
unsigned int LineSize() const { return linesize; }
|
||||
unsigned int Height() const { return height; }
|
||||
unsigned int Colours() const { return colours; }
|
||||
unsigned int SubpixelOrder() const { return subpixelorder; }
|
||||
|
||||
+4
-4
@@ -96,10 +96,10 @@ void zmLoadConfig() {
|
||||
}
|
||||
|
||||
if ( staticConfig.SERVER_ID ) {
|
||||
Debug(3, "Multi-server configuration detected. Server is %d.", staticConfig.SERVER_ID);
|
||||
} else {
|
||||
Debug(3, "Single server configuration assumed because no Server ID or Name was specified.");
|
||||
}
|
||||
Debug(3, "Multi-server configuration detected. Server is %d.", staticConfig.SERVER_ID);
|
||||
} else {
|
||||
Debug(3, "Single server configuration assumed because no Server ID or Name was specified.");
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(staticConfig.capture_file_format, sizeof(staticConfig.capture_file_format), "%%s/%%0%dd-capture.jpg", config.event_image_digits);
|
||||
|
||||
+82
-94
@@ -87,7 +87,7 @@ Event::Event(
|
||||
|
||||
char sql[ZM_SQL_MED_BUFSIZ];
|
||||
struct tm *stime = localtime(&start_time.tv_sec);
|
||||
snprintf(sql, sizeof(sql), "INSERT INTO Events ( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed, DefaultVideo, SaveJPEGs, Scheme ) VALUES ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d, '', %d, '%s' )",
|
||||
snprintf(sql, sizeof(sql), "INSERT INTO Events ( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed, DefaultVideo, SaveJPEGs, Scheme ) VALUES ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d, '%s', %d, '%s' )",
|
||||
monitor->Id(),
|
||||
storage->Id(),
|
||||
start_time.tv_sec,
|
||||
@@ -98,6 +98,7 @@ Event::Event(
|
||||
state_id,
|
||||
monitor->getOrientation(),
|
||||
videoEvent,
|
||||
( monitor->GetOptVideoWriter() != 0 ? "video.mp4" : "" ),
|
||||
monitor->GetOptSaveJPEGs(),
|
||||
storage->SchemeString().c_str()
|
||||
);
|
||||
@@ -108,23 +109,7 @@ Event::Event(
|
||||
return;
|
||||
}
|
||||
id = mysql_insert_id(&dbconn);
|
||||
//
|
||||
|
||||
/* Update event record with DefaultVideo name if possible so image.php can extract frames
|
||||
if needed, while recording is in progress */
|
||||
if ( monitor->GetOptVideoWriter() != 0 ) {
|
||||
video_name[0] = 0;
|
||||
snprintf(video_name, sizeof(video_name), "%" PRIu64 "-%s", id, "video.mp4");
|
||||
Debug(1, "Updating inserted event with DefaultVideo=%s",video_name);
|
||||
snprintf(sql, sizeof(sql), "UPDATE Events SET DefaultVideo = '%s' WHERE Id=%" PRIu64, video_name,id);
|
||||
if ( mysql_query(&dbconn, sql) ) {
|
||||
Error("Can't update event: %s. sql was (%s)", mysql_error(&dbconn), sql);
|
||||
db_mutex.unlock();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Debug (1, "GetOptVideoWriter() returned 0, not updating DefaultVideo");
|
||||
}
|
||||
db_mutex.unlock();
|
||||
if ( untimedEvent ) {
|
||||
Warning("Event %d has zero time, setting to current", id);
|
||||
@@ -136,14 +121,13 @@ Event::Event(
|
||||
max_score = 0;
|
||||
alarm_frame_written = false;
|
||||
|
||||
char id_file[PATH_MAX];
|
||||
std::string id_file;
|
||||
|
||||
char *path_ptr = path;
|
||||
path_ptr += snprintf(path_ptr, sizeof(path), "%s/%d", storage->Path(), monitor->Id());
|
||||
path = stringtf("%s/%d", storage->Path(), monitor->Id());
|
||||
// Try to make the Monitor Dir. Normally this would exist, but in odd cases might not.
|
||||
if ( mkdir(path, 0755) ) {
|
||||
if ( mkdir(path.c_str(), 0755) ) {
|
||||
if ( errno != EEXIST )
|
||||
Error("Can't mkdir %s: %s", path, strerror(errno));
|
||||
Error("Can't mkdir %s: %s", path.c_str(), strerror(errno));
|
||||
}
|
||||
|
||||
if ( storage->Scheme() == Storage::DEEP ) {
|
||||
@@ -156,97 +140,105 @@ Event::Event(
|
||||
dt_parts[4] = stime->tm_min;
|
||||
dt_parts[5] = stime->tm_sec;
|
||||
|
||||
char date_path[PATH_MAX] = "";
|
||||
char time_path[PATH_MAX] = "";
|
||||
char *time_path_ptr = time_path;
|
||||
for ( unsigned int i = 0; i < sizeof(dt_parts)/sizeof(*dt_parts); i++ ) {
|
||||
path_ptr += snprintf(path_ptr, sizeof(path)-(path_ptr-path), "/%02d", dt_parts[i]);
|
||||
std::string date_path;
|
||||
std::string time_path;
|
||||
|
||||
errno = 0;
|
||||
if ( mkdir(path, 0755) ) {
|
||||
for ( unsigned int i = 0; i < sizeof(dt_parts)/sizeof(*dt_parts); i++ ) {
|
||||
path += stringtf("/%02d", dt_parts[i]);
|
||||
|
||||
if ( mkdir(path.c_str(), 0755) ) {
|
||||
// FIXME This should not be fatal. Should probably move to a different storage area.
|
||||
if ( errno != EEXIST )
|
||||
Error("Can't mkdir %s: %s", path, strerror(errno));
|
||||
Error("Can't mkdir %s: %s", path.c_str(), strerror(errno));
|
||||
}
|
||||
if ( i == 2 )
|
||||
strncpy(date_path, path, sizeof(date_path));
|
||||
else if ( i >= 3 )
|
||||
time_path_ptr += snprintf(time_path_ptr, sizeof(time_path)-(time_path_ptr-time_path), "%s%02d", i>3?"/":"", dt_parts[i]);
|
||||
date_path = path;
|
||||
}
|
||||
time_path = stringtf("%02d/%02d/%02d", stime->tm_hour, stime->tm_min, stime->tm_sec);
|
||||
|
||||
// Create event id symlink
|
||||
snprintf(id_file, sizeof(id_file), "%s/.%" PRIu64, date_path, id);
|
||||
if ( symlink(time_path, id_file) < 0 )
|
||||
Error("Can't symlink %s -> %s: %s", id_file, path, strerror(errno));
|
||||
id_file = stringtf("%s/.%" PRIu64, date_path.c_str(), id);
|
||||
if ( symlink(time_path.c_str(), id_file.c_str()) < 0 )
|
||||
Error("Can't symlink %s -> %s: %s", id_file.c_str(), time_path.c_str(), strerror(errno));
|
||||
} else if ( storage->Scheme() == Storage::MEDIUM ) {
|
||||
path_ptr += snprintf(
|
||||
path_ptr, sizeof(path), "/%04d-%02d-%02d",
|
||||
path += stringtf("/%04d-%02d-%02d",
|
||||
stime->tm_year+1900, stime->tm_mon+1, stime->tm_mday
|
||||
);
|
||||
if ( mkdir(path, 0755) ) {
|
||||
if ( mkdir(path.c_str(), 0755) ) {
|
||||
if ( errno != EEXIST )
|
||||
Error("Can't mkdir %s: %s", path, strerror(errno));
|
||||
Error("Can't mkdir %s: %s", path.c_str(), strerror(errno));
|
||||
}
|
||||
path_ptr += snprintf(path_ptr, sizeof(path), "/%" PRIu64, id);
|
||||
if ( mkdir(path, 0755) ) {
|
||||
path += stringtf("/%" PRIu64, id);
|
||||
if ( mkdir(path.c_str(), 0755) ) {
|
||||
if ( errno != EEXIST )
|
||||
Error("Can't mkdir %s: %s", path, strerror(errno));
|
||||
Error("Can't mkdir %s: %s", path.c_str(), strerror(errno));
|
||||
}
|
||||
} else {
|
||||
path_ptr += snprintf(path_ptr, sizeof(path), "/%" PRIu64, id);
|
||||
if ( mkdir(path, 0755) ) {
|
||||
path += stringtf("/%" PRIu64, id);
|
||||
if ( mkdir(path.c_str(), 0755) ) {
|
||||
if ( errno != EEXIST )
|
||||
Error("Can't mkdir %s: %s", path, strerror(errno));
|
||||
Error("Can't mkdir %s: %s", path.c_str(), strerror(errno));
|
||||
}
|
||||
|
||||
// Create empty id tag file
|
||||
snprintf(id_file, sizeof(id_file), "%s/.%" PRIu64, path, id);
|
||||
if ( FILE *id_fp = fopen(id_file, "w") )
|
||||
id_file = stringtf("%s/.%" PRIu64, path.c_str(), id);
|
||||
if ( FILE *id_fp = fopen(id_file.c_str(), "w") ) {
|
||||
fclose(id_fp);
|
||||
else
|
||||
Error("Can't fopen %s: %s", id_file, strerror(errno));
|
||||
} else {
|
||||
Error("Can't fopen %s: %s", id_file.c_str(), strerror(errno));
|
||||
}
|
||||
} // deep storage or not
|
||||
|
||||
last_db_frame = 0;
|
||||
|
||||
video_name[0] = 0;
|
||||
video_name = "";
|
||||
|
||||
snprintf(snapshot_file, sizeof(snapshot_file), "%s/snapshot.jpg", path);
|
||||
snprintf(alarm_file, sizeof(alarm_file), "%s/alarm.jpg", path);
|
||||
snapshot_file = path + "/snapshot.jpg";
|
||||
alarm_file = path + "/alarm.jpg";
|
||||
|
||||
/* Save as video */
|
||||
|
||||
if ( monitor->GetOptVideoWriter() != 0 ) {
|
||||
snprintf(video_name, sizeof(video_name), "%" PRIu64 "-%s", id, "video.mp4");
|
||||
snprintf(video_file, sizeof(video_file), staticConfig.video_file_format, path, video_name);
|
||||
Debug(1,"Writing video file to %s", video_file );
|
||||
video_name = stringtf("%" PRIu64 "-%s", id, "video.mp4");
|
||||
snprintf(sql, sizeof(sql), "UPDATE Events SET DefaultVideo = '%s' WHERE Id=%" PRIu64, video_name.c_str(), id);
|
||||
if ( mysql_query(&dbconn, sql) ) {
|
||||
Error("Can't update event: %s. sql was (%s)", mysql_error(&dbconn), sql);
|
||||
db_mutex.unlock();
|
||||
return;
|
||||
}
|
||||
video_file = path + "/" + video_name;
|
||||
Debug(1, "Writing video file to %s", video_file.c_str());
|
||||
|
||||
/* X264 MP4 video writer */
|
||||
if ( monitor->GetOptVideoWriter() == Monitor::X264ENCODE ) {
|
||||
#if ZM_HAVE_VIDEOWRITER_X264MP4
|
||||
videowriter = new X264MP4Writer(video_file, monitor->Width(), monitor->Height(), monitor->Colours(), monitor->SubpixelOrder(), monitor->GetOptEncoderParams());
|
||||
videowriter = new X264MP4Writer(video_file.c_str(),
|
||||
monitor->Width(),
|
||||
monitor->Height(),
|
||||
monitor->Colours(),
|
||||
monitor->SubpixelOrder(),
|
||||
monitor->GetOptEncoderParamsVec());
|
||||
#else
|
||||
Error("ZoneMinder was not compiled with the X264 MP4 video writer, check dependencies (x264 and mp4v2)");
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( videowriter != NULL ) {
|
||||
/* Open the video stream */
|
||||
int nRet = videowriter->Open();
|
||||
if ( nRet != 0 ) {
|
||||
Error("Failed opening video stream");
|
||||
delete videowriter;
|
||||
videowriter = NULL;
|
||||
}
|
||||
}
|
||||
if ( videowriter != NULL ) {
|
||||
/* Open the video stream */
|
||||
int nRet = videowriter->Open();
|
||||
if ( nRet != 0 ) {
|
||||
Error("Failed opening video stream");
|
||||
delete videowriter;
|
||||
videowriter = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* No video object */
|
||||
videowriter = NULL;
|
||||
}
|
||||
|
||||
} // Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap, bool p_videoEvent )
|
||||
|
||||
Event::~Event() {
|
||||
|
||||
// We close the videowriter first, because if we finish the event, we might try to view the file, but we aren't done writing it yet.
|
||||
|
||||
/* Close the video file */
|
||||
@@ -276,13 +268,12 @@ Event::~Event() {
|
||||
// update frame deltas to refer to video start time which may be a few frames before event start
|
||||
struct timeval video_offset = {0};
|
||||
struct timeval video_start_time = monitor->GetVideoWriterStartTime();
|
||||
if (video_start_time.tv_sec > 0) {
|
||||
if ( video_start_time.tv_sec > 0 ) {
|
||||
timersub(&video_start_time, &start_time, &video_offset);
|
||||
Debug(1, "Updating frames delta by %d sec %d usec",
|
||||
video_offset.tv_sec, video_offset.tv_usec);
|
||||
UpdateFramesDelta(video_offset.tv_sec + video_offset.tv_usec*1e-6);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Debug(3, "Video start_time %d sec %d usec not valid -- frame deltas not updated",
|
||||
video_start_time.tv_sec, video_start_time.tv_usec);
|
||||
}
|
||||
@@ -290,12 +281,12 @@ Event::~Event() {
|
||||
// Should not be static because we might be multi-threaded
|
||||
char sql[ZM_SQL_LGE_BUFSIZ];
|
||||
snprintf(sql, sizeof(sql),
|
||||
"UPDATE Events SET Name='%s %" PRIu64 "', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' WHERE Id = %" PRIu64,
|
||||
"UPDATE Events SET Name='%s%" PRIu64 "', EndTime = from_unixtime(%ld), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64,
|
||||
monitor->EventPrefix(), id, end_time.tv_sec,
|
||||
delta_time.positive?"":"-", delta_time.sec, delta_time.fsec,
|
||||
frames, alarm_frames,
|
||||
tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score,
|
||||
video_name, id );
|
||||
id);
|
||||
db_mutex.lock();
|
||||
while ( mysql_query(&dbconn, sql) && !zm_terminate ) {
|
||||
db_mutex.unlock();
|
||||
@@ -304,7 +295,6 @@ Event::~Event() {
|
||||
db_mutex.lock();
|
||||
}
|
||||
db_mutex.unlock();
|
||||
|
||||
} // Event::~Event()
|
||||
|
||||
void Event::createNotes(std::string ¬es) {
|
||||
@@ -329,7 +319,7 @@ bool Event::WriteFrameImage(
|
||||
|
||||
int thisquality =
|
||||
(alarm_frame && (config.jpeg_alarm_file_quality > config.jpeg_file_quality)) ?
|
||||
config.jpeg_alarm_file_quality : 0 ; // quality to use, zero is default
|
||||
config.jpeg_alarm_file_quality : 0; // quality to use, zero is default
|
||||
|
||||
bool rc;
|
||||
|
||||
@@ -507,17 +497,16 @@ void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, str
|
||||
frames++;
|
||||
|
||||
if ( monitor->GetOptSaveJPEGs() & 1 ) {
|
||||
static char event_file[PATH_MAX];
|
||||
snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames);
|
||||
std::string event_file = stringtf(staticConfig.capture_file_format, path.c_str(), frames);
|
||||
Debug(1, "Writing pre-capture frame %d", frames);
|
||||
WriteFrameImage(images[i], *(timestamps[i]), event_file);
|
||||
WriteFrameImage(images[i], *(timestamps[i]), event_file.c_str());
|
||||
}
|
||||
//If this is the first frame, we should add a thumbnail to the event directory
|
||||
// ICON: We are working through the pre-event frames so this snapshot won't
|
||||
// neccessarily be of the motion. But some events are less than 10 frames,
|
||||
// so I am changing this to 1, but we should overwrite it later with a better snapshot.
|
||||
if ( frames == 1 ) {
|
||||
WriteFrameImage(images[i], *(timestamps[i]), snapshot_file);
|
||||
WriteFrameImage(images[i], *(timestamps[i]), snapshot_file.c_str());
|
||||
}
|
||||
|
||||
if ( videowriter != NULL ) {
|
||||
@@ -589,14 +578,14 @@ void Event::WriteDbFrames() {
|
||||
void Event::UpdateFramesDelta(double offset) {
|
||||
char sql[ZM_SQL_MED_BUFSIZ];
|
||||
|
||||
if (offset == 0.0) return;
|
||||
if ( offset == 0.0 ) return;
|
||||
// the table is set to auto update timestamp so we force it to keep current value
|
||||
snprintf(sql, sizeof(sql),
|
||||
"UPDATE Frames SET timestamp = timestamp, Delta = Delta - (%.4f) WHERE EventId = %" PRIu64,
|
||||
offset, id);
|
||||
|
||||
db_mutex.lock();
|
||||
if (mysql_query(&dbconn, sql)) {
|
||||
if ( mysql_query(&dbconn, sql) ) {
|
||||
db_mutex.unlock();
|
||||
Error("Can't update frames: %s, sql was %s", mysql_error(&dbconn), sql);
|
||||
return;
|
||||
@@ -605,7 +594,6 @@ void Event::UpdateFramesDelta(double offset) {
|
||||
Info("Updating frames delta by %0.2f sec to match video file", offset);
|
||||
}
|
||||
|
||||
|
||||
void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *alarm_image) {
|
||||
if ( !timestamp.tv_sec ) {
|
||||
Debug(1, "Not adding new frame, zero timestamp");
|
||||
@@ -620,10 +608,9 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
|
||||
score = 0;
|
||||
|
||||
if ( monitor->GetOptSaveJPEGs() & 1 ) {
|
||||
static char event_file[PATH_MAX];
|
||||
snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames);
|
||||
Debug(1, "Writing capture frame %d to %s", frames, event_file);
|
||||
if ( !WriteFrameImage(image, timestamp, event_file) ) {
|
||||
std::string event_file = stringtf(staticConfig.capture_file_format, path.c_str(), frames);
|
||||
Debug(1, "Writing capture frame %d to %s", frames, event_file.c_str());
|
||||
if ( !WriteFrameImage(image, timestamp, event_file.c_str()) ) {
|
||||
Error("Failed to write frame image");
|
||||
}
|
||||
}
|
||||
@@ -631,7 +618,7 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
|
||||
// If this is the first frame, we should add a thumbnail to the event directory
|
||||
if ( (frames == 1) || (score > (int)max_score) ) {
|
||||
write_to_db = true; // web ui might show this as thumbnail, so db needs to know about it.
|
||||
WriteFrameImage(image, timestamp, snapshot_file);
|
||||
WriteFrameImage(image, timestamp, snapshot_file.c_str());
|
||||
}
|
||||
|
||||
// We are writing an Alarm frame
|
||||
@@ -640,7 +627,7 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
|
||||
if ( !alarm_frame_written ) {
|
||||
write_to_db = true; // OD processing will need it, so the db needs to know about it
|
||||
alarm_frame_written = true;
|
||||
WriteFrameImage(image, timestamp, alarm_file);
|
||||
WriteFrameImage(image, timestamp, alarm_file.c_str());
|
||||
}
|
||||
alarm_frames++;
|
||||
|
||||
@@ -650,10 +637,9 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
|
||||
|
||||
if ( alarm_image ) {
|
||||
if ( monitor->GetOptSaveJPEGs() & 2 ) {
|
||||
static char event_file[PATH_MAX];
|
||||
snprintf(event_file, sizeof(event_file), staticConfig.analyse_file_format, path, frames);
|
||||
std::string event_file = stringtf(staticConfig.analyse_file_format, path.c_str(), frames);
|
||||
Debug(1, "Writing analysis frame %d", frames);
|
||||
if ( ! WriteFrameImage(alarm_image, timestamp, event_file, true) ) {
|
||||
if ( ! WriteFrameImage(alarm_image, timestamp, event_file.c_str(), true) ) {
|
||||
Error("Failed to write analysis frame image");
|
||||
}
|
||||
}
|
||||
@@ -673,10 +659,12 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
|
||||
|
||||
// The idea is to write out 1/sec
|
||||
frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score));
|
||||
if ( write_to_db || (frame_data.size() > (int)monitor->get_fps()) ) {
|
||||
Debug(1, "Adding %d frames to DB", frame_data.size());
|
||||
if ( write_to_db || ( monitor->get_fps() && (frame_data.size() > monitor->get_fps())) ) {
|
||||
Debug(1, "Adding %d frames to DB because write_to_db:%d or frames > analysis fps %f",
|
||||
frame_data.size(), write_to_db, monitor->get_fps());
|
||||
WriteDbFrames();
|
||||
last_db_frame = frames;
|
||||
Debug(1, "Adding %d frames to DB, done", frame_data.size());
|
||||
}
|
||||
|
||||
// We are writing a Bulk frame
|
||||
|
||||
+32
-23
@@ -89,15 +89,17 @@ class Event {
|
||||
bool alarm_frame_written;
|
||||
unsigned int tot_score;
|
||||
unsigned int max_score;
|
||||
char path[PATH_MAX];
|
||||
char snapshot_file[PATH_MAX];
|
||||
char alarm_file[PATH_MAX];
|
||||
std::string path;
|
||||
std::string snapshot_file;
|
||||
std::string alarm_file;
|
||||
|
||||
VideoWriter* videowriter;
|
||||
FILE* timecodes_fd;
|
||||
char video_name[PATH_MAX];
|
||||
char video_file[PATH_MAX];
|
||||
char timecodes_name[PATH_MAX];
|
||||
char timecodes_file[PATH_MAX];
|
||||
std::string video_name;
|
||||
std::string video_file;
|
||||
|
||||
std::string timecodes_name;
|
||||
std::string timecodes_file;
|
||||
int last_db_frame;
|
||||
Storage::Schemes scheme;
|
||||
|
||||
@@ -137,15 +139,15 @@ class Event {
|
||||
public:
|
||||
static const char *getSubPath( struct tm *time ) {
|
||||
static char subpath[PATH_MAX] = "";
|
||||
snprintf( subpath, sizeof(subpath), "%02d/%02d/%02d/%02d/%02d/%02d", time->tm_year-100, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec );
|
||||
return( subpath );
|
||||
snprintf(subpath, sizeof(subpath), "%02d/%02d/%02d/%02d/%02d/%02d", time->tm_year-100, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec);
|
||||
return subpath;
|
||||
}
|
||||
static const char *getSubPath( time_t *time ) {
|
||||
return Event::getSubPath( localtime( time ) );
|
||||
}
|
||||
|
||||
char* getEventFile(void) {
|
||||
return video_file;
|
||||
const char* getEventFile(void) {
|
||||
return video_file.c_str();
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -153,28 +155,35 @@ class Event {
|
||||
return pre_alarm_count;
|
||||
}
|
||||
static void EmptyPreAlarmFrames() {
|
||||
if ( pre_alarm_count > 0 ) {
|
||||
for ( int i = 0; i < MAX_PRE_ALARM_FRAMES; i++ ) {
|
||||
delete pre_alarm_data[i].image;
|
||||
delete pre_alarm_data[i].alarm_frame;
|
||||
}
|
||||
memset( pre_alarm_data, 0, sizeof(pre_alarm_data) );
|
||||
}
|
||||
while ( pre_alarm_count > 0 ) {
|
||||
int i = pre_alarm_count - 1;
|
||||
delete pre_alarm_data[i].image;
|
||||
pre_alarm_data[i].image = NULL;
|
||||
if ( pre_alarm_data[i].alarm_frame ) {
|
||||
delete pre_alarm_data[i].alarm_frame;
|
||||
pre_alarm_data[i].alarm_frame = NULL;
|
||||
}
|
||||
pre_alarm_count--;
|
||||
}
|
||||
pre_alarm_count = 0;
|
||||
}
|
||||
static void AddPreAlarmFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL ) {
|
||||
pre_alarm_data[pre_alarm_count].image = new Image( *image );
|
||||
static void AddPreAlarmFrame(Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL) {
|
||||
pre_alarm_data[pre_alarm_count].image = new Image(*image);
|
||||
pre_alarm_data[pre_alarm_count].timestamp = timestamp;
|
||||
pre_alarm_data[pre_alarm_count].score = score;
|
||||
if ( alarm_frame ) {
|
||||
pre_alarm_data[pre_alarm_count].alarm_frame = new Image( *alarm_frame );
|
||||
pre_alarm_data[pre_alarm_count].alarm_frame = new Image(*alarm_frame);
|
||||
}
|
||||
pre_alarm_count++;
|
||||
}
|
||||
void SavePreAlarmFrames() {
|
||||
for ( int i = 0; i < pre_alarm_count; i++ ) {
|
||||
AddFrame( pre_alarm_data[i].image, pre_alarm_data[i].timestamp, pre_alarm_data[i].score, pre_alarm_data[i].alarm_frame );
|
||||
}
|
||||
AddFrame(
|
||||
pre_alarm_data[i].image,
|
||||
pre_alarm_data[i].timestamp,
|
||||
pre_alarm_data[i].score,
|
||||
pre_alarm_data[i].alarm_frame);
|
||||
}
|
||||
EmptyPreAlarmFrames();
|
||||
}
|
||||
};
|
||||
|
||||
+24
-15
@@ -187,13 +187,13 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
||||
|
||||
if ( storage_path[0] == '/' )
|
||||
snprintf(event_data->path, sizeof(event_data->path),
|
||||
"%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d",
|
||||
"%s/%d/%02d/%02d/%02d/%02d/%02d/%02d",
|
||||
storage_path, 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",
|
||||
"%s/%s/%d/%02d/%02d/%02d/%02d/%02d/%02d",
|
||||
staticConfig.PATH_WEB.c_str(), storage_path, 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);
|
||||
@@ -201,23 +201,23 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
||||
struct tm *event_time = localtime(&event_data->start_time);
|
||||
if ( storage_path[0] == '/' )
|
||||
snprintf(event_data->path, sizeof(event_data->path),
|
||||
"%s/%ld/%04d-%02d-%02d/%" PRIu64,
|
||||
"%s/%d/%04d-%02d-%02d/%" PRIu64,
|
||||
storage_path, event_data->monitor_id,
|
||||
event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday,
|
||||
event_data->event_id);
|
||||
else
|
||||
snprintf(event_data->path, sizeof(event_data->path),
|
||||
"%s/%s/%ld/%04d-%02d-%02d/%" PRIu64,
|
||||
"%s/%s/%d/%04d-%02d-%02d/%" PRIu64,
|
||||
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id,
|
||||
event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday,
|
||||
event_data->event_id);
|
||||
|
||||
} else {
|
||||
if ( storage_path[0] == '/' )
|
||||
snprintf(event_data->path, sizeof(event_data->path), "%s/%ld/%" PRIu64,
|
||||
snprintf(event_data->path, sizeof(event_data->path), "%s/%d/%" PRIu64,
|
||||
storage_path, event_data->monitor_id, event_data->event_id);
|
||||
else
|
||||
snprintf(event_data->path, sizeof(event_data->path), "%s/%s/%ld/%" PRIu64,
|
||||
snprintf(event_data->path, sizeof(event_data->path), "%s/%s/%d/%" PRIu64,
|
||||
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id,
|
||||
event_data->event_id);
|
||||
}
|
||||
@@ -566,11 +566,11 @@ bool EventStream::checkEventLoaded() {
|
||||
|
||||
if ( curr_frame_id <= 0 ) {
|
||||
snprintf(sql, sizeof(sql),
|
||||
"SELECT `Id` FROM `Events` WHERE `MonitorId` = %ld AND `Id` < %" PRIu64 " ORDER BY `Id` DESC LIMIT 1",
|
||||
"SELECT `Id` FROM `Events` WHERE `MonitorId` = %d AND `Id` < %" PRIu64 " ORDER BY `Id` DESC LIMIT 1",
|
||||
event_data->monitor_id, event_data->event_id);
|
||||
} else if ( (unsigned int)curr_frame_id > event_data->frame_count ) {
|
||||
snprintf(sql, sizeof(sql),
|
||||
"SELECT `Id` FROM `Events` WHERE `MonitorId` = %ld AND `Id` > %" PRIu64 " ORDER BY `Id` ASC LIMIT 1",
|
||||
"SELECT `Id` FROM `Events` WHERE `MonitorId` = %d AND `Id` > %" PRIu64 " ORDER BY `Id` ASC LIMIT 1",
|
||||
event_data->monitor_id, event_data->event_id);
|
||||
} else {
|
||||
// No event change required
|
||||
@@ -810,29 +810,38 @@ bool EventStream::sendFrame(int delta_us) {
|
||||
|
||||
if ( send_raw ) {
|
||||
#if HAVE_SENDFILE
|
||||
fprintf(stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size);
|
||||
if ( 0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size) ) {
|
||||
fclose(fdj); /* Close the file handle */
|
||||
Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
if ( zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size) != (int)filestat.st_size ) {
|
||||
/* sendfile() failed, use standard way instead */
|
||||
img_buffer_size = fread(img_buffer, 1, sizeof(temp_img_buffer), fdj);
|
||||
if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
|
||||
fclose(fdj); /* Close the file handle */
|
||||
Error("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
||||
Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size);
|
||||
if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
|
||||
if (
|
||||
(0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size) )
|
||||
||
|
||||
( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 )
|
||||
) {
|
||||
fclose(fdj); /* Close the file handle */
|
||||
Error("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
||||
Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
fclose(fdj); /* Close the file handle */
|
||||
} else {
|
||||
Debug(3, "Content length: %d", img_buffer_size);
|
||||
fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size);
|
||||
if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
|
||||
if (
|
||||
(0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size) )
|
||||
||
|
||||
( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) ) {
|
||||
Error("Unable to send stream frame: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ class EventStream : public StreamBase {
|
||||
|
||||
struct EventData {
|
||||
uint64_t event_id;
|
||||
unsigned long monitor_id;
|
||||
unsigned int monitor_id;
|
||||
unsigned long storage_id;
|
||||
unsigned long frame_count;
|
||||
time_t start_time;
|
||||
|
||||
+83
-47
@@ -63,31 +63,31 @@ static enum AVPixelFormat get_hw_format(
|
||||
}
|
||||
#if !LIBAVUTIL_VERSION_CHECK(56, 22, 0, 14, 0)
|
||||
static enum AVPixelFormat find_fmt_by_hw_type(const enum AVHWDeviceType type) {
|
||||
enum AVPixelFormat fmt;
|
||||
switch (type) {
|
||||
enum AVPixelFormat fmt;
|
||||
switch (type) {
|
||||
case AV_HWDEVICE_TYPE_VAAPI:
|
||||
fmt = AV_PIX_FMT_VAAPI;
|
||||
break;
|
||||
fmt = AV_PIX_FMT_VAAPI;
|
||||
break;
|
||||
case AV_HWDEVICE_TYPE_DXVA2:
|
||||
fmt = AV_PIX_FMT_DXVA2_VLD;
|
||||
break;
|
||||
fmt = AV_PIX_FMT_DXVA2_VLD;
|
||||
break;
|
||||
case AV_HWDEVICE_TYPE_D3D11VA:
|
||||
fmt = AV_PIX_FMT_D3D11;
|
||||
break;
|
||||
fmt = AV_PIX_FMT_D3D11;
|
||||
break;
|
||||
case AV_HWDEVICE_TYPE_VDPAU:
|
||||
fmt = AV_PIX_FMT_VDPAU;
|
||||
break;
|
||||
fmt = AV_PIX_FMT_VDPAU;
|
||||
break;
|
||||
case AV_HWDEVICE_TYPE_CUDA:
|
||||
fmt = AV_PIX_FMT_CUDA;
|
||||
break;
|
||||
fmt = AV_PIX_FMT_CUDA;
|
||||
break;
|
||||
case AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
|
||||
fmt = AV_PIX_FMT_VIDEOTOOLBOX;
|
||||
break;
|
||||
fmt = AV_PIX_FMT_VIDEOTOOLBOX;
|
||||
break;
|
||||
default:
|
||||
fmt = AV_PIX_FMT_NONE;
|
||||
break;
|
||||
}
|
||||
return fmt;
|
||||
fmt = AV_PIX_FMT_NONE;
|
||||
break;
|
||||
}
|
||||
return fmt;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -174,6 +174,26 @@ FfmpegCamera::FfmpegCamera(
|
||||
} else {
|
||||
Panic("Unexpected colours: %d", colours);
|
||||
}
|
||||
|
||||
frame_buffer = NULL;
|
||||
// sws_scale needs 32bit aligned width and an extra 16 bytes padding, so recalculate imagesize, which was width*height*bytes_per_pixel
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
alignment = 32;
|
||||
imagesize = av_image_get_buffer_size(imagePixFormat, width, height, alignment);
|
||||
// av_image_get_linesize isn't aligned, so we have to do that.
|
||||
linesize = FFALIGN(av_image_get_linesize(imagePixFormat, width, 0), alignment);
|
||||
#else
|
||||
alignment = 1;
|
||||
linesize = FFALIGN(av_image_get_linesize(imagePixFormat, width, 0), alignment);
|
||||
imagesize = avpicture_get_size(imagePixFormat, width, height);
|
||||
#endif
|
||||
if ( linesize != width * colours ) {
|
||||
Debug(1, "linesize %d != width %d * colours %d = %d, allocating frame_buffer", linesize, width, colours, width*colours);
|
||||
frame_buffer = (uint8_t *)av_malloc(imagesize);
|
||||
}
|
||||
|
||||
Debug(1, "ffmpegcamera: width %d height %d linesize %d colours %d image linesize %d imagesize %d",
|
||||
width, height, linesize, colours, width*colours, imagesize);
|
||||
} // FfmpegCamera::FfmpegCamera
|
||||
|
||||
FfmpegCamera::~FfmpegCamera() {
|
||||
@@ -194,12 +214,12 @@ void FfmpegCamera::Terminate() {
|
||||
|
||||
int FfmpegCamera::PrimeCapture() {
|
||||
if ( mCanCapture ) {
|
||||
Info("Priming capture from %s, Closing", mPath.c_str());
|
||||
Debug(1, "Priming capture from %s, Closing", mPath.c_str());
|
||||
Close();
|
||||
}
|
||||
mVideoStreamId = -1;
|
||||
mAudioStreamId = -1;
|
||||
Info("Priming capture from %s", mPath.c_str());
|
||||
Debug(1, "Priming capture from %s", mPath.c_str());
|
||||
|
||||
return OpenFfmpeg();
|
||||
}
|
||||
@@ -608,16 +628,6 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||
mFrame->width = width;
|
||||
mFrame->height = height;
|
||||
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
int pSize = av_image_get_buffer_size(imagePixFormat, width, height, 1);
|
||||
#else
|
||||
int pSize = avpicture_get_size(imagePixFormat, width, height);
|
||||
#endif
|
||||
|
||||
if ( (unsigned int)pSize != imagesize ) {
|
||||
Error("Image size mismatch. Required: %d Available: %d", pSize, imagesize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if HAVE_LIBSWSCALE
|
||||
if ( !sws_isSupportedInput(mVideoCodecContext->pix_fmt) ) {
|
||||
@@ -976,10 +986,12 @@ int FfmpegCamera::CaptureAndRecord(
|
||||
return -1;
|
||||
}
|
||||
#if HAVE_LIBAVUTIL_HWCONTEXT_H
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 89, 0, 89, 0)
|
||||
if ( (ret == AVERROR_INVALIDDATA ) && (hw_pix_fmt != AV_PIX_FMT_NONE) ) {
|
||||
use_hwaccel = false;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
zm_av_packet_unref(&packet);
|
||||
@@ -1074,29 +1086,41 @@ int FfmpegCamera::transfer_to_image(
|
||||
AVFrame *output_frame,
|
||||
AVFrame *input_frame
|
||||
) {
|
||||
uint8_t* directbuffer;
|
||||
uint8_t* image_buffer; // pointer to buffer in image
|
||||
uint8_t* buffer; // pointer to either image_buffer or frame_buffer
|
||||
|
||||
/* Request a writeable buffer of the target image */
|
||||
directbuffer = image.WriteBuffer(width, height, colours, subpixelorder);
|
||||
if ( directbuffer == NULL ) {
|
||||
image_buffer = image.WriteBuffer(width, height, colours, subpixelorder);
|
||||
if ( image_buffer == NULL ) {
|
||||
Error("Failed requesting writeable buffer for the captured image.");
|
||||
return -1;
|
||||
}
|
||||
// if image_buffer was allocated then use it.
|
||||
buffer = frame_buffer ? frame_buffer : image_buffer;
|
||||
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
// From what I've read, we should align the linesizes to 32bit so that ffmpeg can use SIMD instructions too.
|
||||
int size = av_image_fill_arrays(
|
||||
output_frame->data, output_frame->linesize,
|
||||
directbuffer, imagePixFormat, width, height,
|
||||
(AV_PIX_FMT_RGBA == imagePixFormat ? 32 : 1)
|
||||
buffer, imagePixFormat, width, height,
|
||||
alignment
|
||||
);
|
||||
if ( size < 0 ) {
|
||||
Error("Problem setting up data pointers into image %s",
|
||||
av_make_error_string(size).c_str());
|
||||
} else {
|
||||
Debug(4, "av_image_fill_array %dx%d alignment: %d = %d, buffer size is %d",
|
||||
width, height, alignment, size, image.Size());
|
||||
}
|
||||
Debug(1, "ffmpegcamera: width %d height %d linesize %d colours %d imagesize %d", width, height, linesize, colours, imagesize);
|
||||
if ( linesize != (unsigned int)output_frame->linesize[0] ) {
|
||||
Error("Bad linesize expected %d got %d", linesize, output_frame->linesize[0]);
|
||||
}
|
||||
#else
|
||||
avpicture_fill((AVPicture *)output_frame, directbuffer,
|
||||
avpicture_fill((AVPicture *)output_frame, buffer,
|
||||
imagePixFormat, width, height);
|
||||
#endif
|
||||
|
||||
#if HAVE_LIBSWSCALE
|
||||
if ( !mConvertContext ) {
|
||||
mConvertContext = sws_getContext(
|
||||
@@ -1141,21 +1165,33 @@ int FfmpegCamera::transfer_to_image(
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
Debug(4, "Able to convert format %u %s linesize %d,%d height %d to format %u %s linesize %d,%d at frame %d codec %u %s %dx%d ",
|
||||
input_frame->format, av_get_pix_fmt_name((AVPixelFormat)input_frame->format),
|
||||
input_frame->linesize[0], input_frame->linesize[1], mVideoCodecContext->height,
|
||||
imagePixFormat,
|
||||
av_get_pix_fmt_name(imagePixFormat),
|
||||
output_frame->linesize[0], output_frame->linesize[1],
|
||||
frameCount,
|
||||
mVideoCodecContext->pix_fmt, av_get_pix_fmt_name(mVideoCodecContext->pix_fmt),
|
||||
output_frame->width,
|
||||
output_frame->height
|
||||
);
|
||||
Debug(4, "Able to convert format %u %s linesize %d,%d height %d to format %u %s linesize %d,%d at frame %d codec %u %s %dx%d ",
|
||||
input_frame->format, av_get_pix_fmt_name((AVPixelFormat)input_frame->format),
|
||||
input_frame->linesize[0], input_frame->linesize[1], mVideoCodecContext->height,
|
||||
imagePixFormat,
|
||||
av_get_pix_fmt_name(imagePixFormat),
|
||||
output_frame->linesize[0], output_frame->linesize[1],
|
||||
frameCount,
|
||||
mVideoCodecContext->pix_fmt, av_get_pix_fmt_name(mVideoCodecContext->pix_fmt),
|
||||
output_frame->width,
|
||||
output_frame->height
|
||||
);
|
||||
#else // HAVE_LIBSWSCALE
|
||||
Fatal("You must compile ffmpeg with the --enable-swscale "
|
||||
"option to use ffmpeg cameras");
|
||||
#endif // HAVE_LIBSWSCALE
|
||||
if ( buffer != image_buffer ) {
|
||||
Debug(1, "Copying image-buffer to buffer");
|
||||
// Have to copy contents of image_buffer to directbuffer.
|
||||
// Since linesize isn't the same have to copy line by line
|
||||
uint8_t *image_buffer_ptr = image_buffer;
|
||||
int row_size = output_frame->width * colours;
|
||||
for ( int i = 0; i < output_frame->height; i++ ) {
|
||||
memcpy(image_buffer_ptr, buffer, row_size);
|
||||
image_buffer_ptr += row_size;
|
||||
buffer += output_frame->linesize[0];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
} // end int FfmpegCamera::transfer_to_image
|
||||
|
||||
|
||||
@@ -45,6 +45,8 @@ class FfmpegCamera : public Camera {
|
||||
std::string hwaccel_device;
|
||||
|
||||
int frameCount;
|
||||
|
||||
int alignment; /* ffmpeg wants line sizes to be 32bit aligned. Especially 4.3+ */
|
||||
|
||||
#if HAVE_LIBAVFORMAT
|
||||
AVFormatContext *mFormatContext;
|
||||
@@ -82,6 +84,7 @@ class FfmpegCamera : public Camera {
|
||||
#if HAVE_LIBSWSCALE
|
||||
struct SwsContext *mConvertContext;
|
||||
#endif
|
||||
uint8_t *frame_buffer;
|
||||
|
||||
int error_count;
|
||||
|
||||
|
||||
+269
-266
File diff suppressed because it is too large.
Load diff
+28
-10
@@ -152,9 +152,11 @@ protected:
|
||||
static struct zm_error_mgr jpg_err;
|
||||
|
||||
unsigned int width;
|
||||
unsigned int linesize;
|
||||
unsigned int height;
|
||||
unsigned int pixels;
|
||||
unsigned int colours;
|
||||
unsigned int padding;
|
||||
unsigned int size;
|
||||
unsigned int subpixelorder;
|
||||
unsigned long allocation;
|
||||
@@ -165,15 +167,18 @@ protected:
|
||||
|
||||
public:
|
||||
Image();
|
||||
explicit Image( const char *filename );
|
||||
Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer=0);
|
||||
explicit Image(const char *filename);
|
||||
Image(int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer=0, unsigned int padding=0);
|
||||
Image(int p_width, int p_linesize, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer=0, unsigned int padding=0);
|
||||
explicit Image( const Image &p_image );
|
||||
explicit Image( const AVFrame *frame );
|
||||
|
||||
~Image();
|
||||
static void Initialise();
|
||||
static void Deinitialise();
|
||||
|
||||
inline unsigned int Width() const { return width; }
|
||||
inline unsigned int LineSize() const { return linesize; }
|
||||
inline unsigned int Height() const { return height; }
|
||||
inline unsigned int Pixels() const { return pixels; }
|
||||
inline unsigned int Colours() const { return colours; }
|
||||
@@ -182,7 +187,7 @@ public:
|
||||
|
||||
/* Internal buffer should not be modified from functions outside of this class */
|
||||
inline const uint8_t* Buffer() const { return buffer; }
|
||||
inline const uint8_t* Buffer( unsigned int x, unsigned int y= 0 ) const { return &buffer[colours*((y*width)+x)]; }
|
||||
inline const uint8_t* Buffer( unsigned int x, unsigned int y= 0 ) const { return &buffer[(y*linesize)+x]; }
|
||||
/* Request writeable buffer */
|
||||
uint8_t* WriteBuffer(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder);
|
||||
|
||||
@@ -193,21 +198,34 @@ public:
|
||||
if ( !holdbuffer )
|
||||
DumpImgBuffer();
|
||||
|
||||
width = height = colours = size = pixels = subpixelorder = 0;
|
||||
width = linesize = height = colours = size = pixels = subpixelorder = 0;
|
||||
}
|
||||
|
||||
void Assign( unsigned int p_width, unsigned int p_height, unsigned int p_colours, unsigned int p_subpixelorder, const uint8_t* new_buffer, const size_t buffer_size);
|
||||
void Assign( const Image &image );
|
||||
void AssignDirect( const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder, uint8_t *new_buffer, const size_t buffer_size, const int p_buffertype);
|
||||
void Assign(
|
||||
unsigned int p_width,
|
||||
unsigned int p_height,
|
||||
unsigned int p_colours,
|
||||
unsigned int p_subpixelorder,
|
||||
const uint8_t* new_buffer,
|
||||
const size_t buffer_size);
|
||||
void Assign(const Image &image);
|
||||
void AssignDirect(
|
||||
const unsigned int p_width,
|
||||
const unsigned int p_height,
|
||||
const unsigned int p_colours,
|
||||
const unsigned int p_subpixelorder,
|
||||
uint8_t *new_buffer,
|
||||
const size_t buffer_size,
|
||||
const int p_buffertype);
|
||||
|
||||
inline void CopyBuffer( const Image &image ) {
|
||||
inline void CopyBuffer(const Image &image) {
|
||||
Assign(image);
|
||||
}
|
||||
inline Image &operator=( const Image &image ) {
|
||||
inline Image &operator=(const Image &image) {
|
||||
Assign(image);
|
||||
return *this;
|
||||
}
|
||||
inline Image &operator=( const unsigned char *new_buffer ) {
|
||||
inline Image &operator=(const unsigned char *new_buffer) {
|
||||
(*fptr_imgbufcpy)(buffer, new_buffer, size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -198,8 +198,7 @@ void LibvlcCamera::Terminate() {
|
||||
}
|
||||
|
||||
int LibvlcCamera::PrimeCapture() {
|
||||
Info("Priming capture from %s", mPath.c_str());
|
||||
Info("Libvlc Version %s", (*libvlc_get_version_f)());
|
||||
Debug(1, "Priming capture from %s, libvlc version %s", mPath.c_str(), (*libvlc_get_version_f)());
|
||||
|
||||
StringVector opVect = split(Options(), ",");
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ void VncCamera::Terminate() {
|
||||
}
|
||||
|
||||
int VncCamera::PrimeCapture() {
|
||||
Info("Priming capture from %s", mHost.c_str());
|
||||
Debug(1, "Priming capture from %s", mHost.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+216
-175
@@ -504,7 +504,7 @@ LocalCamera::LocalCamera(
|
||||
subpixelorder = ZM_SUBPIX_ORDER_NONE;
|
||||
} else if ( palette == V4L2_PIX_FMT_YUYV && colours == ZM_COLOUR_GRAY8 ) {
|
||||
/* Fast YUYV->Grayscale conversion by extracting the Y channel */
|
||||
if ( config.cpu_extensions && sseversion >= 35 ) {
|
||||
if ( config.cpu_extensions && sse_version >= 35 ) {
|
||||
conversion_fptr = &ssse3_convert_yuyv_gray8;
|
||||
Debug(2,"Using SSSE3 YUYV->grayscale fast conversion");
|
||||
} else {
|
||||
@@ -616,7 +616,7 @@ LocalCamera::LocalCamera(
|
||||
}
|
||||
} else if ( (palette == VIDEO_PALETTE_YUYV || palette == VIDEO_PALETTE_YUV422) && colours == ZM_COLOUR_GRAY8 ) {
|
||||
/* Fast YUYV->Grayscale conversion by extracting the Y channel */
|
||||
if ( config.cpu_extensions && sseversion >= 35 ) {
|
||||
if ( config.cpu_extensions && sse_version >= 35 ) {
|
||||
conversion_fptr = &ssse3_convert_yuyv_gray8;
|
||||
Debug(2,"Using SSSE3 YUYV->grayscale fast conversion");
|
||||
} else {
|
||||
@@ -1274,56 +1274,62 @@ uint32_t LocalCamera::AutoSelectFormat(int p_colours) {
|
||||
#define capString(test,prefix,yesString,noString,capability) \
|
||||
(test) ? (prefix yesString " " capability "\n") : (prefix noString " " capability "\n")
|
||||
|
||||
bool LocalCamera::GetCurrentSettings( const char *device, char *output, int version, bool verbose ) {
|
||||
bool LocalCamera::GetCurrentSettings(const char *device, char *output, int version, bool verbose) {
|
||||
output[0] = 0;
|
||||
char *output_ptr = output;
|
||||
|
||||
char queryDevice[PATH_MAX] = "";
|
||||
int devIndex = 0;
|
||||
do {
|
||||
if ( device )
|
||||
if ( device ) {
|
||||
strncpy(queryDevice, device, sizeof(queryDevice)-1);
|
||||
else
|
||||
} else {
|
||||
sprintf(queryDevice, "/dev/video%d", devIndex);
|
||||
}
|
||||
|
||||
if ( (vid_fd = open(queryDevice, O_RDWR)) <= 0 ) {
|
||||
if ( device ) {
|
||||
Error("Failed to open video device %s: %s", queryDevice, strerror(errno));
|
||||
if ( verbose )
|
||||
sprintf(output+strlen(output), "Error, failed to open video device %s: %s\n",
|
||||
output_ptr += sprintf(output_ptr, "Error, failed to open video device %s: %s\n",
|
||||
queryDevice, strerror(errno));
|
||||
else
|
||||
sprintf(output+strlen(output), "error%d\n", errno);
|
||||
output_ptr += sprintf(output_ptr, "error%d\n", errno);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ( verbose )
|
||||
sprintf(output+strlen(output), "Video Device: %s\n", queryDevice);
|
||||
else
|
||||
sprintf(output+strlen(output), "d:%s|", queryDevice);
|
||||
if ( verbose ) {
|
||||
output_ptr += sprintf(output_ptr, "Video Device: %s\n", queryDevice);
|
||||
} else {
|
||||
output_ptr += sprintf(output_ptr, "d:%s|", queryDevice);
|
||||
}
|
||||
|
||||
#if ZM_HAS_V4L2
|
||||
if ( version == 2 ) {
|
||||
struct v4l2_capability vid_cap;
|
||||
if ( vidioctl(vid_fd, VIDIOC_QUERYCAP, &vid_cap) < 0 ) {
|
||||
Error("Failed to query video device: %s", strerror(errno));
|
||||
if ( verbose )
|
||||
sprintf(output, "Error, failed to query video capabilities %s: %s\n",
|
||||
if ( verbose ) {
|
||||
output_ptr += sprintf(output_ptr, "Error, failed to query video capabilities %s: %s\n",
|
||||
queryDevice, strerror(errno));
|
||||
else
|
||||
sprintf(output, "error%d\n", errno);
|
||||
return false;
|
||||
} else {
|
||||
output_ptr += sprintf(output_ptr, "error%d\n", errno);
|
||||
}
|
||||
if ( device )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( verbose ) {
|
||||
sprintf(output+strlen(output), "General Capabilities\n");
|
||||
sprintf(output+strlen(output), " Driver: %s\n", vid_cap.driver);
|
||||
sprintf(output+strlen(output), " Card: %s\n", vid_cap.card);
|
||||
sprintf(output+strlen(output), " Bus: %s\n", vid_cap.bus_info);
|
||||
sprintf(output+strlen(output), " Version: %u.%u.%u\n",
|
||||
(vid_cap.version>>16)&0xff, (vid_cap.version>>8)&0xff, vid_cap.version&0xff);
|
||||
sprintf(output+strlen(output), " Type: 0x%x\n%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
output_ptr += sprintf(output_ptr, "General Capabilities\n"
|
||||
" Driver: %s\n"
|
||||
" Card: %s\n"
|
||||
" Bus: %s\n"
|
||||
" Version: %u.%u.%u\n"
|
||||
" Type: 0x%x\n%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
vid_cap.driver, vid_cap.card, vid_cap.bus_info,
|
||||
(vid_cap.version>>16)&0xff, (vid_cap.version>>8)&0xff, vid_cap.version&0xff,
|
||||
vid_cap.capabilities,
|
||||
capString(vid_cap.capabilities&V4L2_CAP_VIDEO_CAPTURE, " ", "Supports", "Does not support", "video capture (X)"),
|
||||
capString(vid_cap.capabilities&V4L2_CAP_VIDEO_OUTPUT, " ", "Supports", "Does not support", "video output"),
|
||||
@@ -1345,17 +1351,16 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
|
||||
capString(vid_cap.capabilities&V4L2_CAP_STREAMING, " ", "Supports", "Does not support", "streaming i/o (X)")
|
||||
);
|
||||
} else {
|
||||
sprintf(output+strlen(output), "D:%s|", vid_cap.driver);
|
||||
sprintf(output+strlen(output), "C:%s|", vid_cap.card);
|
||||
sprintf(output+strlen(output), "B:%s|", vid_cap.bus_info);
|
||||
sprintf(output+strlen(output), "V:%u.%u.%u|", (vid_cap.version>>16)&0xff, (vid_cap.version>>8)&0xff, vid_cap.version&0xff);
|
||||
sprintf(output+strlen(output), "T:0x%x|", vid_cap.capabilities);
|
||||
output_ptr += sprintf(output_ptr, "D:%s|C:%s|B:%s|V:%u.%u.%u|T:0x%x|"
|
||||
, vid_cap.driver
|
||||
, vid_cap.card
|
||||
, vid_cap.bus_info
|
||||
, (vid_cap.version>>16)&0xff, (vid_cap.version>>8)&0xff, vid_cap.version&0xff
|
||||
, vid_cap.capabilities);
|
||||
}
|
||||
|
||||
if ( verbose )
|
||||
sprintf(output+strlen(output), " Standards:\n");
|
||||
else
|
||||
sprintf(output+strlen(output), "S:");
|
||||
output_ptr += sprintf(output_ptr, verbose ? " Standards:\n" : "S:");
|
||||
|
||||
struct v4l2_standard standard;
|
||||
int standardIndex = 0;
|
||||
do {
|
||||
@@ -1370,25 +1375,20 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
|
||||
} else {
|
||||
Error("Failed to enumerate standard %d: %d %s", standard.index, errno, strerror(errno));
|
||||
if ( verbose )
|
||||
sprintf(output, "Error, failed to enumerate standard %d: %d %s\n", standard.index, errno, strerror(errno));
|
||||
output_ptr += sprintf(output_ptr, "Error, failed to enumerate standard %d: %d %s\n", standard.index, errno, strerror(errno));
|
||||
else
|
||||
sprintf(output, "error%d\n", errno);
|
||||
output_ptr += sprintf(output_ptr, "error%d\n", errno);
|
||||
// Why return? Why not continue trying other things?
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ( verbose )
|
||||
sprintf(output+strlen(output), " %s\n", standard.name);
|
||||
else
|
||||
sprintf(output+strlen(output), "%s/", standard.name);
|
||||
}
|
||||
while ( standardIndex++ >= 0 );
|
||||
if ( !verbose && output[strlen(output)-1] == '/')
|
||||
output[strlen(output)-1] = '|';
|
||||
output_ptr += sprintf(output_ptr, (verbose ? " %s\n" : "%s/"), standard.name);
|
||||
} while ( standardIndex++ >= 0 );
|
||||
|
||||
if ( verbose )
|
||||
sprintf(output+strlen(output), " Formats:\n");
|
||||
else
|
||||
sprintf(output+strlen(output), "F:");
|
||||
if ( !verbose && (*(output_ptr-1) == '/') )
|
||||
*(output_ptr-1) = '|';
|
||||
|
||||
output_ptr += sprintf(output_ptr, verbose ? " Formats:\n" : "F:");
|
||||
struct v4l2_fmtdesc format;
|
||||
int formatIndex = 0;
|
||||
do {
|
||||
@@ -1403,15 +1403,15 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
|
||||
} else {
|
||||
Error("Failed to enumerate format %d: %s", format.index, strerror(errno));
|
||||
if ( verbose )
|
||||
sprintf(output, "Error, failed to enumerate format %d: %s\n", format.index, strerror(errno));
|
||||
output_ptr += sprintf(output_ptr, "Error, failed to enumerate format %d: %s\n", format.index, strerror(errno));
|
||||
else
|
||||
sprintf(output, "error%d\n", errno);
|
||||
output_ptr += sprintf(output_ptr, "error%d\n", errno);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ( verbose )
|
||||
sprintf(
|
||||
output+strlen(output),
|
||||
output_ptr += sprintf(
|
||||
output_ptr,
|
||||
" %s (0x%02hhx%02hhx%02hhx%02hhx)\n",
|
||||
format.description,
|
||||
(format.pixelformat>>24)&0xff,
|
||||
@@ -1419,33 +1419,34 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
|
||||
(format.pixelformat>>8)&0xff,
|
||||
format.pixelformat&0xff);
|
||||
else
|
||||
sprintf(
|
||||
output+strlen(output),
|
||||
output_ptr += sprintf(
|
||||
output_ptr,
|
||||
"0x%02hhx%02hhx%02hhx%02hhx/",
|
||||
(format.pixelformat>>24)&0xff,
|
||||
(format.pixelformat>>16)&0xff,
|
||||
(format.pixelformat>>8)&0xff,
|
||||
(format.pixelformat)&0xff);
|
||||
} while ( formatIndex++ >= 0 );
|
||||
|
||||
if ( !verbose )
|
||||
output[strlen(output)-1] = '|';
|
||||
*(output_ptr-1) = '|';
|
||||
else
|
||||
sprintf(output+strlen(output), "Crop Capabilities\n");
|
||||
output_ptr += sprintf(output_ptr, "Crop Capabilities\n");
|
||||
|
||||
struct v4l2_cropcap cropcap;
|
||||
memset(&cropcap, 0, sizeof(cropcap));
|
||||
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if ( vidioctl( vid_fd, VIDIOC_CROPCAP, &cropcap ) < 0 ) {
|
||||
if ( vidioctl(vid_fd, VIDIOC_CROPCAP, &cropcap) < 0 ) {
|
||||
if ( errno != EINVAL ) {
|
||||
/* Failed querying crop capability, write error to the log and continue as if crop is not supported */
|
||||
Error("Failed to query crop capabilities: %s", strerror(errno));
|
||||
}
|
||||
|
||||
if ( verbose ) {
|
||||
sprintf(output+strlen(output), " Cropping is not supported\n");
|
||||
output_ptr += sprintf(output_ptr, " Cropping is not supported\n");
|
||||
} else {
|
||||
/* Send fake crop bounds to not confuse things parsing this, such as monitor probe */
|
||||
sprintf(output+strlen(output), "B:%dx%d|",0,0);
|
||||
output_ptr += sprintf(output_ptr, "B:%dx%d|", 0, 0);
|
||||
}
|
||||
} else {
|
||||
struct v4l2_crop crop;
|
||||
@@ -1459,19 +1460,23 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
|
||||
}
|
||||
|
||||
if ( verbose ) {
|
||||
sprintf(output+strlen(output), " Cropping is not supported\n");
|
||||
output_ptr += sprintf(output_ptr, " Cropping is not supported\n");
|
||||
} else {
|
||||
/* Send fake crop bounds to not confuse things parsing this, such as monitor probe */
|
||||
sprintf(output+strlen(output), "B:%dx%d|",0,0);
|
||||
output_ptr += sprintf(output_ptr, "B:%dx%d|",0,0);
|
||||
}
|
||||
} else {
|
||||
/* Cropping supported */
|
||||
if ( verbose ) {
|
||||
sprintf(output+strlen(output), " Bounds: %d x %d\n", cropcap.bounds.width, cropcap.bounds.height);
|
||||
sprintf(output+strlen(output), " Default: %d x %d\n", cropcap.defrect.width, cropcap.defrect.height);
|
||||
sprintf(output+strlen(output), " Current: %d x %d\n", crop.c.width, crop.c.height);
|
||||
output_ptr += sprintf(output_ptr,
|
||||
" Bounds: %d x %d\n"
|
||||
" Default: %d x %d\n"
|
||||
" Current: %d x %d\n"
|
||||
, cropcap.bounds.width, cropcap.bounds.height
|
||||
, cropcap.defrect.width, cropcap.defrect.height
|
||||
, crop.c.width, crop.c.height);
|
||||
} else {
|
||||
sprintf(output+strlen(output), "B:%dx%d|", cropcap.bounds.width, cropcap.bounds.height);
|
||||
output_ptr += sprintf(output_ptr, "B:%dx%d|", cropcap.bounds.width, cropcap.bounds.height);
|
||||
}
|
||||
}
|
||||
} /* Crop code */
|
||||
@@ -1488,17 +1493,14 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
|
||||
}
|
||||
Error("Failed to enumerate input %d: %s", input.index, strerror(errno));
|
||||
if ( verbose )
|
||||
sprintf(output, "Error, failed to enumerate input %d: %s\n", input.index, strerror(errno));
|
||||
output_ptr += sprintf(output_ptr, "Error, failed to enumerate input %d: %s\n", input.index, strerror(errno));
|
||||
else
|
||||
sprintf(output, "error%d\n", errno);
|
||||
output_ptr += sprintf(output_ptr, "error%d\n", errno);
|
||||
return false;
|
||||
}
|
||||
} while ( inputIndex++ >= 0 );
|
||||
|
||||
if ( verbose )
|
||||
sprintf(output+strlen(output), "Inputs: %d\n", inputIndex);
|
||||
else
|
||||
sprintf(output+strlen(output), "I:%d|", inputIndex);
|
||||
output_ptr += sprintf(output_ptr, verbose?"Inputs: %d\n":"I:%d|", inputIndex);
|
||||
|
||||
inputIndex = 0;
|
||||
do {
|
||||
@@ -1512,65 +1514,84 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
|
||||
}
|
||||
Error("Failed to enumerate input %d: %s", input.index, strerror(errno));
|
||||
if ( verbose )
|
||||
sprintf(output, "Error, failed to enumerate input %d: %s\n", input.index, strerror(errno));
|
||||
output_ptr += sprintf(output_ptr, "Error, failed to enumerate input %d: %s\n", input.index, strerror(errno));
|
||||
else
|
||||
sprintf(output, "error%d\n", errno);
|
||||
output_ptr += sprintf(output_ptr, "error%d\n", errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( vidioctl(vid_fd, VIDIOC_S_INPUT, &input.index) < 0 ) {
|
||||
Error("Failed to set video input %d: %s", input.index, strerror(errno));
|
||||
if ( verbose )
|
||||
sprintf(output, "Error, failed to switch to input %d: %s\n", input.index, strerror(errno));
|
||||
output_ptr += sprintf(output_ptr, "Error, failed to switch to input %d: %s\n", input.index, strerror(errno));
|
||||
else
|
||||
sprintf(output, "error%d\n", errno);
|
||||
output_ptr += sprintf(output_ptr, "error%d\n", errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( verbose ) {
|
||||
sprintf( output+strlen(output), " Input %d\n", input.index );
|
||||
sprintf( output+strlen(output), " Name: %s\n", input.name );
|
||||
sprintf( output+strlen(output), " Type: %s\n", input.type==V4L2_INPUT_TYPE_TUNER?"Tuner":(input.type==V4L2_INPUT_TYPE_CAMERA?"Camera":"Unknown") );
|
||||
sprintf( output+strlen(output), " Audioset: %08x\n", input.audioset );
|
||||
sprintf( output+strlen(output), " Standards: 0x%llx\n", input.std );
|
||||
output_ptr += sprintf( output,
|
||||
" Input %d\n"
|
||||
" Name: %s\n"
|
||||
" Type: %s\n"
|
||||
" Audioset: %08x\n"
|
||||
" Standards: 0x%llx\n"
|
||||
, input.index
|
||||
, input.name
|
||||
, input.type==V4L2_INPUT_TYPE_TUNER?"Tuner":(input.type==V4L2_INPUT_TYPE_CAMERA?"Camera":"Unknown")
|
||||
, input.audioset
|
||||
, input.std );
|
||||
} else {
|
||||
sprintf( output+strlen(output), "i%d:%s|", input.index, input.name );
|
||||
sprintf( output+strlen(output), "i%dT:%s|", input.index, input.type==V4L2_INPUT_TYPE_TUNER?"Tuner":(input.type==V4L2_INPUT_TYPE_CAMERA?"Camera":"Unknown") );
|
||||
sprintf( output+strlen(output), "i%dS:%llx|", input.index, input.std );
|
||||
output_ptr += sprintf( output_ptr, "i%d:%s|i%dT:%s|i%dS:%llx|"
|
||||
, input.index, input.name
|
||||
, input.index, input.type==V4L2_INPUT_TYPE_TUNER?"Tuner":(input.type==V4L2_INPUT_TYPE_CAMERA?"Camera":"Unknown")
|
||||
, input.index, input.std);
|
||||
}
|
||||
|
||||
if ( verbose ) {
|
||||
sprintf( output+strlen(output), " %s", capString( input.status&V4L2_IN_ST_NO_POWER, "Power ", "off", "on", " (X)" ) );
|
||||
sprintf( output+strlen(output), " %s", capString( input.status&V4L2_IN_ST_NO_SIGNAL, "Signal ", "not detected", "detected", " (X)" ) );
|
||||
sprintf( output+strlen(output), " %s", capString( input.status&V4L2_IN_ST_NO_COLOR, "Colour Signal ", "not detected", "detected", "" ) );
|
||||
sprintf( output+strlen(output), " %s", capString( input.status&V4L2_IN_ST_NO_H_LOCK, "Horizontal Lock ", "not detected", "detected", "" ) );
|
||||
output_ptr += sprintf( output_ptr, " %s %s %s %s"
|
||||
, capString(input.status&V4L2_IN_ST_NO_POWER, "Power ", "off", "on", " (X)")
|
||||
, capString(input.status&V4L2_IN_ST_NO_SIGNAL, "Signal ", "not detected", "detected", " (X)")
|
||||
, capString(input.status&V4L2_IN_ST_NO_COLOR, "Colour Signal ", "not detected", "detected", "")
|
||||
, capString(input.status&V4L2_IN_ST_NO_H_LOCK, "Horizontal Lock ", "not detected", "detected", ""));
|
||||
} else {
|
||||
sprintf( output+strlen(output), "i%dSP:%d|", input.index, (input.status&V4L2_IN_ST_NO_POWER)?0:1 );
|
||||
sprintf( output+strlen(output), "i%dSS:%d|", input.index, (input.status&V4L2_IN_ST_NO_SIGNAL)?0:1 );
|
||||
sprintf( output+strlen(output), "i%dSC:%d|", input.index, (input.status&V4L2_IN_ST_NO_COLOR)?0:1 );
|
||||
sprintf( output+strlen(output), "i%dHP:%d|", input.index, (input.status&V4L2_IN_ST_NO_H_LOCK)?0:1 );
|
||||
output_ptr += sprintf( output_ptr, "i%dSP:%d|i%dSS:%d|i%dSC:%d|i%dHP:%d|"
|
||||
, input.index, (input.status&V4L2_IN_ST_NO_POWER)?0:1
|
||||
, input.index, (input.status&V4L2_IN_ST_NO_SIGNAL)?0:1
|
||||
, input.index, (input.status&V4L2_IN_ST_NO_COLOR)?0:1
|
||||
, input.index, (input.status&V4L2_IN_ST_NO_H_LOCK)?0:1 );
|
||||
}
|
||||
} while ( inputIndex++ >= 0 );
|
||||
if ( !verbose )
|
||||
output[strlen(output)-1] = '\n';
|
||||
*(output_ptr-1) = '\n';
|
||||
}
|
||||
#endif // ZM_HAS_V4L2
|
||||
#if ZM_HAS_V4L1
|
||||
if ( version == 1 ) {
|
||||
struct video_capability vid_cap;
|
||||
memset( &vid_cap, 0, sizeof(video_capability) );
|
||||
if ( ioctl( vid_fd, VIDIOCGCAP, &vid_cap ) < 0 ) {
|
||||
Error( "Failed to get video capabilities: %s", strerror(errno) );
|
||||
memset(&vid_cap, 0, sizeof(video_capability));
|
||||
if ( ioctl(vid_fd, VIDIOCGCAP, &vid_cap) < 0 ) {
|
||||
Error("Failed to get video capabilities: %s", strerror(errno));
|
||||
if ( verbose )
|
||||
sprintf( output, "Error, failed to get video capabilities %s: %s\n", queryDevice, strerror(errno) );
|
||||
output_ptr += sprintf(output_ptr,
|
||||
"Error, failed to get video capabilities %s: %s\n",
|
||||
queryDevice, strerror(errno));
|
||||
else
|
||||
sprintf( output, "error%d\n", errno );
|
||||
return( false );
|
||||
output_ptr += sprintf(output_ptr, "error%d\n", errno);
|
||||
return false;
|
||||
}
|
||||
if ( verbose ) {
|
||||
sprintf( output+strlen(output), "Video Capabilities\n" );
|
||||
sprintf( output+strlen(output), " Name: %s\n", vid_cap.name );
|
||||
sprintf( output+strlen(output), " Type: %d\n%s%s%s%s%s%s%s%s%s%s%s%s%s%s", vid_cap.type,
|
||||
output_ptr += sprintf( output_ptr, "Video Capabilities\n"
|
||||
" Name: %s\n"
|
||||
" Type: %d\n%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
|
||||
" Video Channels: %d\n"
|
||||
" Audio Channels: %d\n"
|
||||
" Maximum Width: %d\n"
|
||||
" Maximum Height: %d\n"
|
||||
" Minimum Width: %d\n"
|
||||
" Minimum Height: %d\n",
|
||||
vid_cap.name,
|
||||
vid_cap.type,
|
||||
(vid_cap.type&VID_TYPE_CAPTURE)?" Can capture\n":"",
|
||||
(vid_cap.type&VID_TYPE_TUNER)?" Can tune\n":"",
|
||||
(vid_cap.type&VID_TYPE_TELETEXT)?" Does teletext\n":"",
|
||||
@@ -1584,63 +1605,72 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
|
||||
(vid_cap.type&VID_TYPE_MPEG_DECODER)?" Can decode MPEG streams\n":"",
|
||||
(vid_cap.type&VID_TYPE_MPEG_ENCODER)?" Can encode MPEG streams\n":"",
|
||||
(vid_cap.type&VID_TYPE_MJPEG_DECODER)?" Can decode MJPEG streams\n":"",
|
||||
(vid_cap.type&VID_TYPE_MJPEG_ENCODER)?" Can encode MJPEG streams\n":""
|
||||
);
|
||||
sprintf( output+strlen(output), " Video Channels: %d\n", vid_cap.channels );
|
||||
sprintf( output+strlen(output), " Audio Channels: %d\n", vid_cap.audios );
|
||||
sprintf( output+strlen(output), " Maximum Width: %d\n", vid_cap.maxwidth );
|
||||
sprintf( output+strlen(output), " Maximum Height: %d\n", vid_cap.maxheight );
|
||||
sprintf( output+strlen(output), " Minimum Width: %d\n", vid_cap.minwidth );
|
||||
sprintf( output+strlen(output), " Minimum Height: %d\n", vid_cap.minheight );
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf( output+strlen(output), "N:%s|", vid_cap.name );
|
||||
sprintf( output+strlen(output), "T:%d|", vid_cap.type );
|
||||
sprintf( output+strlen(output), "nC:%d|", vid_cap.channels );
|
||||
sprintf( output+strlen(output), "nA:%d|", vid_cap.audios );
|
||||
sprintf( output+strlen(output), "mxW:%d|", vid_cap.maxwidth );
|
||||
sprintf( output+strlen(output), "mxH:%d|", vid_cap.maxheight );
|
||||
sprintf( output+strlen(output), "mnW:%d|", vid_cap.minwidth );
|
||||
sprintf( output+strlen(output), "mnH:%d|", vid_cap.minheight );
|
||||
(vid_cap.type&VID_TYPE_MJPEG_ENCODER)?" Can encode MJPEG streams\n":"",
|
||||
vid_cap.channels,
|
||||
vid_cap.audios,
|
||||
vid_cap.maxwidth,
|
||||
vid_cap.maxheight,
|
||||
vid_cap.minwidth,
|
||||
vid_cap.minheight );
|
||||
} else {
|
||||
output_ptr += sprintf(output_ptr, "N:%s|T:%d|nC:%d|nA:%d|mxW:%d|mxH:%d|mnW:%d|mnH:%d|"
|
||||
, vid_cap.name
|
||||
, vid_cap.type
|
||||
, vid_cap.channels
|
||||
, vid_cap.audios
|
||||
, vid_cap.maxwidth
|
||||
, vid_cap.maxheight
|
||||
, vid_cap.minwidth
|
||||
, vid_cap.minheight);
|
||||
}
|
||||
|
||||
struct video_window vid_win;
|
||||
memset( &vid_win, 0, sizeof(video_window) );
|
||||
if ( ioctl( vid_fd, VIDIOCGWIN, &vid_win ) < 0 ) {
|
||||
Error( "Failed to get window attributes: %s", strerror(errno) );
|
||||
memset(&vid_win, 0, sizeof(video_window));
|
||||
if ( ioctl(vid_fd, VIDIOCGWIN, &vid_win) < 0 ) {
|
||||
Error("Failed to get window attributes: %s", strerror(errno));
|
||||
if ( verbose )
|
||||
sprintf( output, "Error, failed to get window attributes: %s\n", strerror(errno) );
|
||||
output_ptr += sprintf(output_ptr, "Error, failed to get window attributes: %s\n", strerror(errno));
|
||||
else
|
||||
sprintf( output, "error%d\n", errno );
|
||||
output_ptr += sprintf(output_ptr, "error%d\n", errno);
|
||||
return false;
|
||||
}
|
||||
if ( verbose ) {
|
||||
sprintf( output+strlen(output), "Window Attributes\n" );
|
||||
sprintf( output+strlen(output), " X Offset: %d\n", vid_win.x );
|
||||
sprintf( output+strlen(output), " Y Offset: %d\n", vid_win.y );
|
||||
sprintf( output+strlen(output), " Width: %d\n", vid_win.width );
|
||||
sprintf( output+strlen(output), " Height: %d\n", vid_win.height );
|
||||
output_ptr += sprintf(output_ptr,
|
||||
"Window Attributes\n"
|
||||
" X Offset: %d\n"
|
||||
" Y Offset: %d\n"
|
||||
" Width: %d\n"
|
||||
" Height: %d\n"
|
||||
, vid_win.x
|
||||
, vid_win.y
|
||||
, vid_win.width
|
||||
, vid_win.height );
|
||||
} else {
|
||||
sprintf( output+strlen(output), "X:%d|", vid_win.x );
|
||||
sprintf( output+strlen(output), "Y:%d|", vid_win.y );
|
||||
sprintf( output+strlen(output), "W:%d|", vid_win.width );
|
||||
sprintf( output+strlen(output), "H:%d|", vid_win.height );
|
||||
output_ptr += sprintf(output_ptr, "X:%d|Y:%d|W:%d|H:%d|",
|
||||
vid_win.height, vid_win.x, vid_win.y, vid_win.width);
|
||||
}
|
||||
|
||||
struct video_picture vid_pic;
|
||||
memset( &vid_pic, 0, sizeof(video_picture) );
|
||||
if ( ioctl( vid_fd, VIDIOCGPICT, &vid_pic ) < 0 ) {
|
||||
Error( "Failed to get picture attributes: %s", strerror(errno) );
|
||||
memset(&vid_pic, 0, sizeof(video_picture));
|
||||
if ( ioctl(vid_fd, VIDIOCGPICT, &vid_pic) < 0 ) {
|
||||
Error("Failed to get picture attributes: %s", strerror(errno));
|
||||
if ( verbose )
|
||||
sprintf( output, "Error, failed to get picture attributes: %s\n", strerror(errno) );
|
||||
output_ptr += sprintf(output_ptr, "Error, failed to get picture attributes: %s\n", strerror(errno));
|
||||
else
|
||||
sprintf( output, "error%d\n", errno );
|
||||
output_ptr += sprintf(output_ptr, "error%d\n", errno);
|
||||
return false;
|
||||
}
|
||||
if ( verbose ) {
|
||||
sprintf( output+strlen(output), "Picture Attributes\n" );
|
||||
sprintf( output+strlen(output), " Palette: %d - %s\n", vid_pic.palette,
|
||||
output_ptr += sprintf(output_ptr,
|
||||
"Picture Attributes\n"
|
||||
" Palette: %d - %s\n"
|
||||
" Colour Depth: %d\n"
|
||||
" Brightness: %d\n"
|
||||
" Hue: %d\n"
|
||||
" Colour :%d\n"
|
||||
" Contrast: %d\n"
|
||||
" Whiteness: %d\n"
|
||||
, vid_pic.palette,
|
||||
vid_pic.palette==VIDEO_PALETTE_GREY?"Linear greyscale":(
|
||||
vid_pic.palette==VIDEO_PALETTE_HI240?"High 240 cube (BT848)":(
|
||||
vid_pic.palette==VIDEO_PALETTE_RGB565?"565 16 bit RGB":(
|
||||
@@ -1659,66 +1689,77 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
|
||||
vid_pic.palette==VIDEO_PALETTE_YUV411P?"YUV 4:1:1 Planar":(
|
||||
vid_pic.palette==VIDEO_PALETTE_YUV420P?"YUV 4:2:0 Planar":(
|
||||
vid_pic.palette==VIDEO_PALETTE_YUV410P?"YUV 4:1:0 Planar":"Unknown"
|
||||
))))))))))))))))));
|
||||
sprintf( output+strlen(output), " Colour Depth: %d\n", vid_pic.depth );
|
||||
sprintf( output+strlen(output), " Brightness: %d\n", vid_pic.brightness );
|
||||
sprintf( output+strlen(output), " Hue: %d\n", vid_pic.hue );
|
||||
sprintf( output+strlen(output), " Colour :%d\n", vid_pic.colour );
|
||||
sprintf( output+strlen(output), " Contrast: %d\n", vid_pic.contrast );
|
||||
sprintf( output+strlen(output), " Whiteness: %d\n", vid_pic.whiteness );
|
||||
))))))))))))))))),
|
||||
vid_pic.depth,
|
||||
vid_pic.brightness,
|
||||
vid_pic.hue,
|
||||
vid_pic.colour,
|
||||
vid_pic.contrast,
|
||||
vid_pic.whiteness
|
||||
);
|
||||
} else {
|
||||
sprintf( output+strlen(output), "P:%d|", vid_pic.palette );
|
||||
sprintf( output+strlen(output), "D:%d|", vid_pic.depth );
|
||||
sprintf( output+strlen(output), "B:%d|", vid_pic.brightness );
|
||||
sprintf( output+strlen(output), "h:%d|", vid_pic.hue );
|
||||
sprintf( output+strlen(output), "Cl:%d|", vid_pic.colour );
|
||||
sprintf( output+strlen(output), "Cn:%d|", vid_pic.contrast );
|
||||
sprintf( output+strlen(output), "w:%d|", vid_pic.whiteness );
|
||||
output_ptr += sprintf(output_ptr, "P:%d|D:%d|B:%d|h:%d|Cl:%d|Cn:%d|w:%d|",
|
||||
vid_pic.palette,
|
||||
vid_pic.depth,
|
||||
vid_pic.brightness,
|
||||
vid_pic.hue,
|
||||
vid_pic.colour,
|
||||
vid_pic.contrast,
|
||||
vid_pic.whiteness
|
||||
);
|
||||
}
|
||||
|
||||
for ( int chan = 0; chan < vid_cap.channels; chan++ ) {
|
||||
struct video_channel vid_src;
|
||||
memset( &vid_src, 0, sizeof(video_channel) );
|
||||
memset(&vid_src, 0, sizeof(video_channel));
|
||||
vid_src.channel = chan;
|
||||
if ( ioctl( vid_fd, VIDIOCGCHAN, &vid_src ) < 0 ) {
|
||||
Error( "Failed to get channel %d attributes: %s", chan, strerror(errno) );
|
||||
if ( ioctl(vid_fd, VIDIOCGCHAN, &vid_src) < 0 ) {
|
||||
Error("Failed to get channel %d attributes: %s", chan, strerror(errno));
|
||||
if ( verbose )
|
||||
sprintf( output, "Error, failed to get channel %d attributes: %s\n", chan, strerror(errno) );
|
||||
output_ptr += sprintf(output_ptr, "Error, failed to get channel %d attributes: %s\n", chan, strerror(errno));
|
||||
else
|
||||
sprintf( output, "error%d\n", errno );
|
||||
output_ptr += sprintf(output_ptr, "error%d\n", errno);
|
||||
return false;
|
||||
}
|
||||
if ( verbose ) {
|
||||
sprintf( output+strlen(output), "Channel %d Attributes\n", chan );
|
||||
sprintf( output+strlen(output), " Name: %s\n", vid_src.name );
|
||||
sprintf( output+strlen(output), " Channel: %d\n", vid_src.channel );
|
||||
sprintf( output+strlen(output), " Flags: %d\n%s%s", vid_src.flags,
|
||||
(vid_src.flags&VIDEO_VC_TUNER)?" Channel has a tuner\n":"",
|
||||
(vid_src.flags&VIDEO_VC_AUDIO)?" Channel has audio\n":""
|
||||
);
|
||||
sprintf( output+strlen(output), " Type: %d - %s\n", vid_src.type,
|
||||
output_ptr += sprintf(output_ptr,
|
||||
"Channel %d Attributes\n"
|
||||
" Name: %s\n"
|
||||
" Channel: %d\n"
|
||||
" Flags: %d\n%s%s"
|
||||
" Type: %d - %s\n"
|
||||
" Format: %d - %s\n"
|
||||
, chan
|
||||
, vid_src.name
|
||||
, vid_src.channel
|
||||
, vid_src.flags
|
||||
, (vid_src.flags&VIDEO_VC_TUNER)?" Channel has a tuner\n":""
|
||||
, (vid_src.flags&VIDEO_VC_AUDIO)?" Channel has audio\n":""
|
||||
, vid_src.type,
|
||||
vid_src.type==VIDEO_TYPE_TV?"TV":(
|
||||
vid_src.type==VIDEO_TYPE_CAMERA?"Camera":"Unknown"
|
||||
));
|
||||
sprintf( output+strlen(output), " Format: %d - %s\n", vid_src.norm,
|
||||
)
|
||||
, vid_src.norm,
|
||||
vid_src.norm==VIDEO_MODE_PAL?"PAL":(
|
||||
vid_src.norm==VIDEO_MODE_NTSC?"NTSC":(
|
||||
vid_src.norm==VIDEO_MODE_SECAM?"SECAM":(
|
||||
vid_src.norm==VIDEO_MODE_AUTO?"AUTO":"Unknown"
|
||||
))));
|
||||
} else {
|
||||
sprintf( output+strlen(output), "n%d:%s|", chan, vid_src.name );
|
||||
sprintf( output+strlen(output), "C%d:%d|", chan, vid_src.channel );
|
||||
sprintf( output+strlen(output), "Fl%d:%x|", chan, vid_src.flags );
|
||||
sprintf( output+strlen(output), "T%d:%d|", chan, vid_src.type );
|
||||
sprintf( output+strlen(output), "F%d:%d%s|", chan, vid_src.norm, chan==(vid_cap.channels-1)?"":"," );
|
||||
output_ptr += sprintf(output_ptr, "n%d:%s|C%d:%d|Fl%d:%x|T%d:%d|F%d:%d%s|"
|
||||
, chan, vid_src.name
|
||||
, chan, vid_src.channel
|
||||
, chan, vid_src.flags
|
||||
, chan, vid_src.type
|
||||
, chan, vid_src.norm, chan==(vid_cap.channels-1)?"":","
|
||||
);
|
||||
}
|
||||
}
|
||||
if ( !verbose )
|
||||
output[strlen(output)-1] = '\n';
|
||||
*output_ptr = '\n';
|
||||
}
|
||||
#endif // ZM_HAS_V4L1
|
||||
close( vid_fd );
|
||||
close(vid_fd);
|
||||
if ( device )
|
||||
break;
|
||||
} while ( ++devIndex < 32 );
|
||||
|
||||
+76
-78
@@ -106,17 +106,17 @@ std::vector<std::string> split(const std::string &s, char delim) {
|
||||
return elems;
|
||||
}
|
||||
|
||||
Monitor::MonitorLink::MonitorLink( int p_id, const char *p_name ) :
|
||||
id( p_id ),
|
||||
Monitor::MonitorLink::MonitorLink(unsigned int p_id, const char *p_name) :
|
||||
id(p_id),
|
||||
shared_data(NULL),
|
||||
trigger_data(NULL),
|
||||
video_store_data(NULL)
|
||||
{
|
||||
strncpy( name, p_name, sizeof(name)-1 );
|
||||
strncpy(name, p_name, sizeof(name)-1);
|
||||
|
||||
#if ZM_MEM_MAPPED
|
||||
map_fd = -1;
|
||||
snprintf( mem_file, sizeof(mem_file), "%s/zm.mmap.%d", staticConfig.PATH_MAP.c_str(), 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
|
||||
@@ -135,61 +135,61 @@ Monitor::MonitorLink::~MonitorLink() {
|
||||
}
|
||||
|
||||
bool Monitor::MonitorLink::connect() {
|
||||
if ( !last_connect_time || (time( 0 ) - last_connect_time) > 60 ) {
|
||||
last_connect_time = time( 0 );
|
||||
if ( !last_connect_time || (time(0) - last_connect_time) > 60 ) {
|
||||
last_connect_time = time(0);
|
||||
|
||||
mem_size = sizeof(SharedData) + sizeof(TriggerData);
|
||||
|
||||
Debug( 1, "link.mem.size=%d", mem_size );
|
||||
Debug(1, "link.mem.size=%d", mem_size);
|
||||
#if ZM_MEM_MAPPED
|
||||
map_fd = open( mem_file, O_RDWR, (mode_t)0600 );
|
||||
map_fd = open(mem_file, O_RDWR, (mode_t)0600);
|
||||
if ( map_fd < 0 ) {
|
||||
Debug( 3, "Can't open linked memory map file %s: %s", mem_file, strerror(errno) );
|
||||
Debug(3, "Can't open linked memory map file %s: %s", mem_file, strerror(errno));
|
||||
disconnect();
|
||||
return( false );
|
||||
return false;
|
||||
}
|
||||
while ( map_fd <= 2 ) {
|
||||
int new_map_fd = dup(map_fd);
|
||||
Warning( "Got one of the stdio fds for our mmap handle. map_fd was %d, new one is %d", map_fd, new_map_fd );
|
||||
Warning("Got one of the stdio fds for our mmap handle. map_fd was %d, new one is %d", map_fd, new_map_fd);
|
||||
close(map_fd);
|
||||
map_fd = new_map_fd;
|
||||
}
|
||||
|
||||
struct stat map_stat;
|
||||
if ( fstat( map_fd, &map_stat ) < 0 ) {
|
||||
Error( "Can't stat linked memory map file %s: %s", mem_file, strerror(errno) );
|
||||
if ( fstat(map_fd, &map_stat) < 0 ) {
|
||||
Error("Can't stat linked memory map file %s: %s", mem_file, strerror(errno));
|
||||
disconnect();
|
||||
return( false );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( map_stat.st_size == 0 ) {
|
||||
Error( "Linked memory map file %s is empty: %s", mem_file, strerror(errno) );
|
||||
Error("Linked memory map file %s is empty: %s", mem_file, strerror(errno));
|
||||
disconnect();
|
||||
return( false );
|
||||
return false;
|
||||
} else if ( map_stat.st_size < mem_size ) {
|
||||
Error( "Got unexpected memory map file size %ld, expected %d", map_stat.st_size, mem_size );
|
||||
Error("Got unexpected memory map file size %ld, expected %d", map_stat.st_size, mem_size);
|
||||
disconnect();
|
||||
return( false );
|
||||
return false;
|
||||
}
|
||||
|
||||
mem_ptr = (unsigned char *)mmap( NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0 );
|
||||
mem_ptr = (unsigned char *)mmap(NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0);
|
||||
if ( mem_ptr == MAP_FAILED ) {
|
||||
Error( "Can't map file %s (%d bytes) to memory: %s", mem_file, mem_size, strerror(errno) );
|
||||
Error("Can't map file %s (%d bytes) to memory: %s", mem_file, mem_size, strerror(errno));
|
||||
disconnect();
|
||||
return( false );
|
||||
return false;
|
||||
}
|
||||
#else // ZM_MEM_MAPPED
|
||||
shm_id = shmget( (config.shm_key&0xffff0000)|id, mem_size, 0700 );
|
||||
if ( shm_id < 0 ) {
|
||||
Debug( 3, "Can't shmget link memory: %s", strerror(errno) );
|
||||
Debug(3, "Can't shmget link memory: %s", strerror(errno );
|
||||
connected = false;
|
||||
return( false );
|
||||
return false;
|
||||
}
|
||||
mem_ptr = (unsigned char *)shmat( shm_id, 0, 0 );
|
||||
mem_ptr = (unsigned char *)shmat(shm_id, 0, 0);
|
||||
if ( mem_ptr < (void *)0 ) {
|
||||
Debug( 3, "Can't shmat link memory: %s", strerror(errno) );
|
||||
Debug(3, "Can't shmat link memory: %s", strerror(errno));
|
||||
connected = false;
|
||||
return( false );
|
||||
return false;
|
||||
}
|
||||
#endif // ZM_MEM_MAPPED
|
||||
|
||||
@@ -197,18 +197,18 @@ bool Monitor::MonitorLink::connect() {
|
||||
trigger_data = (TriggerData *)((char *)shared_data + sizeof(SharedData));
|
||||
|
||||
if ( !shared_data->valid ) {
|
||||
Debug( 3, "Linked memory not initialised by capture daemon" );
|
||||
Debug(3, "Linked memory not initialised by capture daemon");
|
||||
disconnect();
|
||||
return( false );
|
||||
return false;
|
||||
}
|
||||
|
||||
last_state = shared_data->state;
|
||||
last_event = shared_data->last_event;
|
||||
connected = true;
|
||||
|
||||
return( true );
|
||||
return true;
|
||||
}
|
||||
return( false );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Monitor::MonitorLink::disconnect() {
|
||||
@@ -276,7 +276,7 @@ bool Monitor::MonitorLink::hasAlarmed() {
|
||||
}
|
||||
|
||||
Monitor::Monitor(
|
||||
int p_id,
|
||||
unsigned int p_id,
|
||||
const char *p_name,
|
||||
const unsigned int p_server_id,
|
||||
const unsigned int p_storage_id,
|
||||
@@ -383,6 +383,7 @@ Monitor::Monitor(
|
||||
|
||||
strncpy(event_prefix, p_event_prefix, sizeof(event_prefix)-1);
|
||||
strncpy(label_format, p_label_format, sizeof(label_format)-1);
|
||||
Debug(1, "encoder params %s", encoderparams.c_str());
|
||||
|
||||
// Change \n to actual line feeds
|
||||
char *token_ptr = label_format;
|
||||
@@ -529,7 +530,8 @@ Monitor::Monitor(
|
||||
shared_data->last_write_index, shared_data->last_write_time );
|
||||
sleep(1);
|
||||
}
|
||||
ref_image.Assign( width, height, camera->Colours(), camera->SubpixelOrder(),
|
||||
|
||||
ref_image.Assign(width, height, camera->Colours(), camera->SubpixelOrder(),
|
||||
image_buffer[shared_data->last_write_index].image->Buffer(), camera->ImageSize());
|
||||
adaptive_skip = true;
|
||||
|
||||
@@ -538,7 +540,7 @@ Monitor::Monitor(
|
||||
if ( config.record_diag_images ) {
|
||||
diag_path_r = stringtf(config.record_diag_images_fifo ? "%s/%d/diagpipe-r.jpg" : "%s/%d/diag-r.jpg", storage->Path(), id);
|
||||
diag_path_d = stringtf(config.record_diag_images_fifo ? "%s/%d/diagpipe-d.jpg" : "%s/%d/diag-d.jpg", storage->Path(), id);
|
||||
if (config.record_diag_images_fifo){
|
||||
if ( config.record_diag_images_fifo ) {
|
||||
FifoStream::fifo_create_if_missing(diag_path_r.c_str());
|
||||
FifoStream::fifo_create_if_missing(diag_path_d.c_str());
|
||||
}
|
||||
@@ -602,7 +604,7 @@ bool Monitor::connect() {
|
||||
if ( mem_ptr == MAP_FAILED )
|
||||
Fatal("Can't map file %s (%d bytes) to memory: %s(%d)", mem_file, mem_size, strerror(errno), errno);
|
||||
if ( mem_ptr == NULL ) {
|
||||
Error("mmap gave a null address:");
|
||||
Error("mmap gave a NULL address:");
|
||||
} else {
|
||||
Debug(3, "mmapped to %p", mem_ptr);
|
||||
}
|
||||
@@ -631,13 +633,13 @@ bool Monitor::connect() {
|
||||
image_buffer = new Snapshot[image_buffer_count];
|
||||
for ( int i = 0; i < image_buffer_count; i++ ) {
|
||||
image_buffer[i].timestamp = &(shared_timestamps[i]);
|
||||
image_buffer[i].image = new Image( width, height, camera->Colours(), camera->SubpixelOrder(), &(shared_images[i*camera->ImageSize()]) );
|
||||
image_buffer[i].image = new Image(width, height, camera->Colours(), camera->SubpixelOrder(), &(shared_images[i*camera->ImageSize()]));
|
||||
image_buffer[i].image->HoldBuffer(true); /* Don't release the internal buffer or replace it with another */
|
||||
}
|
||||
if ( (deinterlacing & 0xff) == 4) {
|
||||
if ( (deinterlacing & 0xff) == 4 ) {
|
||||
/* Four field motion adaptive deinterlacing in use */
|
||||
/* Allocate a buffer for the next image */
|
||||
next_buffer.image = new Image( width, height, camera->Colours(), camera->SubpixelOrder());
|
||||
next_buffer.image = new Image(width, height, camera->Colours(), camera->SubpixelOrder());
|
||||
next_buffer.timestamp = new struct timeval;
|
||||
}
|
||||
if ( purpose == ANALYSIS ) {
|
||||
@@ -726,9 +728,11 @@ Monitor::~Monitor() {
|
||||
}
|
||||
delete[] pre_event_buffer;
|
||||
}
|
||||
if ( Event::PreAlarmCount() )
|
||||
Event::EmptyPreAlarmFrames();
|
||||
} else if ( purpose == CAPTURE ) {
|
||||
shared_data->valid = false;
|
||||
memset( mem_ptr, 0, mem_size );
|
||||
memset(mem_ptr, 0, mem_size);
|
||||
}
|
||||
|
||||
#if ZM_MEM_MAPPED
|
||||
@@ -1403,9 +1407,6 @@ bool Monitor::Analyse() {
|
||||
score += trigger_data->trigger_score;
|
||||
Debug(1, "Triggered on score += %d => %d", trigger_data->trigger_score, score);
|
||||
if ( !event ) {
|
||||
// How could it have a length already?
|
||||
//if ( cause.length() )
|
||||
//cause += ", ";
|
||||
cause += trigger_data->trigger_cause;
|
||||
}
|
||||
Event::StringSet noteSet;
|
||||
@@ -1485,6 +1486,7 @@ bool Monitor::Analyse() {
|
||||
score += 50;
|
||||
}
|
||||
} else {
|
||||
Debug(1, "Linked monitor %d %d is not connected. Connecting.", i, linked_monitors[i]->Id());
|
||||
linked_monitors[i]->connect();
|
||||
}
|
||||
} // end foreach linked_monit
|
||||
@@ -1499,7 +1501,7 @@ bool Monitor::Analyse() {
|
||||
|
||||
if ( section_length
|
||||
&& ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= section_length )
|
||||
&& ( (event_close_mode != CLOSE_TIME) || ! ( timestamp->tv_sec % section_length ) )
|
||||
&& ( (function == MOCORD && (event_close_mode != CLOSE_TIME)) || ! ( timestamp->tv_sec % section_length ) )
|
||||
) {
|
||||
Info("%s: %03d - Closing event %" PRIu64 ", section end forced %d - %d = %d >= %d",
|
||||
name, image_count, event->Id(),
|
||||
@@ -1512,7 +1514,6 @@ bool Monitor::Analyse() {
|
||||
} // end if event
|
||||
|
||||
if ( !event ) {
|
||||
|
||||
// Create event
|
||||
event = new Event(this, *timestamp, "Continuous", noteSetMap, videoRecording);
|
||||
shared_data->last_event = event->Id();
|
||||
@@ -1526,7 +1527,6 @@ bool Monitor::Analyse() {
|
||||
if ( state == IDLE ) {
|
||||
shared_data->state = state = TAPE;
|
||||
}
|
||||
|
||||
} // end if ! event
|
||||
} // end if function == RECORD || function == MOCORD)
|
||||
} // end if !signal_change && signal
|
||||
@@ -1538,23 +1538,24 @@ bool Monitor::Analyse() {
|
||||
&& (!event->AlarmFrames())
|
||||
&& (event_close_mode == CLOSE_ALARM)
|
||||
&& ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= min_section_length )
|
||||
&& ( (!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count-1) )
|
||||
) {
|
||||
Info("%s: %03d - Closing event %" PRIu64 ", continuous end, alarm begins",
|
||||
Info("%s: %03d - Closing event %" PRIu64 ", continuous end, alarm begins",
|
||||
name, image_count, event->Id());
|
||||
closeEvent();
|
||||
} else if ( event ) {
|
||||
// This is so if we need more than 1 alarm frame before going into alarm, so it is basically if we have enough alarm frames
|
||||
Debug(3, "pre-alarm-count in event %d, event frames %d, alarm frames %d event length %d >=? %d",
|
||||
Event::PreAlarmCount(), event->Frames(), event->AlarmFrames(),
|
||||
( timestamp->tv_sec - video_store_data->recording.tv_sec ), min_section_length
|
||||
);
|
||||
}
|
||||
if ( (!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count-1) ) {
|
||||
shared_data->state = state = ALARM;
|
||||
// lets construct alarm cause. It will contain cause + names of zones alarmed
|
||||
std::string alarm_cause = "";
|
||||
for ( int i=0; i < n_zones; i++ ) {
|
||||
if ( zones[i]->Alarmed() ) {
|
||||
// This is so if we need more than 1 alarm frame before going into alarm, so it is basically if we have enough alarm frames
|
||||
Debug(3, "pre-alarm-count in event %d, event frames %d, alarm frames %d event length %d >=? %d min",
|
||||
Event::PreAlarmCount(), event->Frames(), event->AlarmFrames(),
|
||||
( timestamp->tv_sec - video_store_data->recording.tv_sec ), min_section_length
|
||||
);
|
||||
}
|
||||
|
||||
if ( (!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count-1) ) {
|
||||
// lets construct alarm cause. It will contain cause + names of zones alarmed
|
||||
std::string alarm_cause = "";
|
||||
for ( int i=0; i < n_zones; i++ ) {
|
||||
if ( zones[i]->Alarmed() ) {
|
||||
alarm_cause = alarm_cause + "," + std::string(zones[i]->Label());
|
||||
}
|
||||
}
|
||||
@@ -1630,11 +1631,14 @@ bool Monitor::Analyse() {
|
||||
}
|
||||
}
|
||||
event->AddFrames(pre_event_images, images, timestamps);
|
||||
}
|
||||
if ( alarm_frame_count ) {
|
||||
} // end if pre_event_images
|
||||
|
||||
if ( ( alarm_frame_count > 1 ) && Event::PreAlarmCount() ) {
|
||||
Debug(1, "alarm frame count so SavePreAlarmFrames");
|
||||
event->SavePreAlarmFrames();
|
||||
}
|
||||
}
|
||||
} // end if event
|
||||
shared_data->state = state = ALARM;
|
||||
} else if ( state != PREALARM ) {
|
||||
Info("%s: %03d - Gone into prealarm state", name, image_count);
|
||||
shared_data->state = state = PREALARM;
|
||||
@@ -1673,14 +1677,15 @@ bool Monitor::Analyse() {
|
||||
} else {
|
||||
shared_data->state = state = TAPE;
|
||||
}
|
||||
}
|
||||
if ( Event::PreAlarmCount() )
|
||||
Event::EmptyPreAlarmFrames();
|
||||
} // end if score or not
|
||||
// Not in PREALARM state anymore, can clear PreAlarmCount
|
||||
if ( Event::PreAlarmCount() )
|
||||
Event::EmptyPreAlarmFrames();
|
||||
}
|
||||
} // end if score or not
|
||||
|
||||
if ( state != IDLE ) {
|
||||
if ( state == PREALARM || state == ALARM ) {
|
||||
if ( config.create_analysis_images ) {
|
||||
if ( savejpegs > 1 ) {
|
||||
bool got_anal_image = false;
|
||||
alarm_image.Assign(*snap_image);
|
||||
for ( int i = 0; i < n_zones; i++ ) {
|
||||
@@ -1694,17 +1699,11 @@ bool Monitor::Analyse() {
|
||||
} // end if zone is alarmed
|
||||
} // end foreach zone
|
||||
|
||||
if ( got_anal_image ) {
|
||||
if ( state == PREALARM )
|
||||
Event::AddPreAlarmFrame(snap_image, *timestamp, score, &alarm_image);
|
||||
else
|
||||
event->AddFrame(snap_image, *timestamp, score, &alarm_image);
|
||||
if ( state == PREALARM ) {
|
||||
Event::AddPreAlarmFrame(snap_image, *timestamp, score, (got_anal_image?&alarm_image:NULL));
|
||||
} else {
|
||||
if ( state == PREALARM )
|
||||
Event::AddPreAlarmFrame(snap_image, *timestamp, score);
|
||||
else
|
||||
event->AddFrame(snap_image, *timestamp, score);
|
||||
}
|
||||
event->AddFrame(snap_image, *timestamp, score, (got_anal_image?&alarm_image:NULL));
|
||||
}
|
||||
} else {
|
||||
// Not doing alarm frame storage
|
||||
if ( state == PREALARM ) {
|
||||
@@ -1718,7 +1717,7 @@ bool Monitor::Analyse() {
|
||||
}
|
||||
} // end if config.record_event_stats
|
||||
}
|
||||
} // end if config.create_analysis_images
|
||||
} // end if savejpegs > 1
|
||||
|
||||
if ( event ) {
|
||||
if ( noteSetMap.size() > 0 )
|
||||
@@ -1740,7 +1739,6 @@ bool Monitor::Analyse() {
|
||||
//set up video store data
|
||||
snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile());
|
||||
video_store_data->recording = event->StartTime();
|
||||
|
||||
}
|
||||
} // end if event
|
||||
|
||||
@@ -2516,7 +2514,7 @@ int Monitor::Capture() {
|
||||
|
||||
if ( capture_image->Size() > camera->ImageSize() ) {
|
||||
Error("Captured image %d does not match expected size %d check width, height and colour depth",
|
||||
capture_image->Size(),camera->ImageSize() );
|
||||
capture_image->Size(), camera->ImageSize() );
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
+25
-15
@@ -138,15 +138,23 @@ protected:
|
||||
time_t startup_time; /* When the zmc process started. zmwatch uses this to see how long the process has been running without getting any images */
|
||||
uint64_t extrapad1;
|
||||
};
|
||||
union { /* +72 */
|
||||
time_t last_write_time;
|
||||
union { /* +72 */
|
||||
time_t zmc_heartbeat_time; /* Constantly updated by zmc. Used to determine if the process is alive or hung or dead */
|
||||
uint64_t extrapad2;
|
||||
};
|
||||
union { /* +80 */
|
||||
time_t last_read_time;
|
||||
union { /* +80 */
|
||||
time_t zma_heartbeat_time; /* Constantly updated by zma. Used to determine if the process is alive or hung or dead */
|
||||
uint64_t extrapad3;
|
||||
};
|
||||
uint8_t control_state[256]; /* +88 */
|
||||
union { /* +88 */
|
||||
time_t last_write_time;
|
||||
uint64_t extrapad4;
|
||||
};
|
||||
union { /* +96 */
|
||||
time_t last_read_time;
|
||||
uint64_t extrapad5;
|
||||
};
|
||||
uint8_t control_state[256]; /* +104 */
|
||||
|
||||
char alarm_cause[256];
|
||||
|
||||
@@ -210,21 +218,21 @@ protected:
|
||||
uint64_t last_event;
|
||||
|
||||
public:
|
||||
MonitorLink( int p_id, const char *p_name );
|
||||
MonitorLink(unsigned int p_id, const char *p_name);
|
||||
~MonitorLink();
|
||||
|
||||
inline int Id() const {
|
||||
inline unsigned int Id() const {
|
||||
return id;
|
||||
}
|
||||
inline const char *Name() const {
|
||||
return( name );
|
||||
return name;
|
||||
}
|
||||
|
||||
inline bool isConnected() const {
|
||||
return( connected );
|
||||
return connected && shared_data->valid;
|
||||
}
|
||||
inline time_t getLastConnectTime() const {
|
||||
return( last_connect_time );
|
||||
return last_connect_time;
|
||||
}
|
||||
|
||||
bool connect();
|
||||
@@ -358,12 +366,12 @@ protected:
|
||||
std::vector<Group *> groups;
|
||||
|
||||
public:
|
||||
explicit Monitor( int p_id );
|
||||
explicit Monitor(unsigned int p_id);
|
||||
|
||||
// OurCheckAlarms seems to be unused. Check it on zm_monitor.cpp for more info.
|
||||
//bool OurCheckAlarms( Zone *zone, const Image *pImage );
|
||||
Monitor(
|
||||
int p_id,
|
||||
unsigned int p_id,
|
||||
const char *p_name,
|
||||
unsigned int p_server_id,
|
||||
unsigned int p_storage_id,
|
||||
@@ -415,11 +423,12 @@ public:
|
||||
void AddPrivacyBitmask( Zone *p_zones[] );
|
||||
|
||||
bool connect();
|
||||
|
||||
inline int ShmValid() const {
|
||||
return( shared_data->valid );
|
||||
return shared_data->valid;
|
||||
}
|
||||
|
||||
inline int Id() const {
|
||||
inline unsigned int Id() const {
|
||||
return id;
|
||||
}
|
||||
inline const char *Name() const {
|
||||
@@ -464,7 +473,8 @@ public:
|
||||
|
||||
int GetOptSaveJPEGs() const { return savejpegs; }
|
||||
VideoWriter GetOptVideoWriter() const { return videowriter; }
|
||||
const std::vector<EncoderParameter_t>* GetOptEncoderParams() const { return &encoderparamsvec; }
|
||||
const std::vector<EncoderParameter_t>* GetOptEncoderParamsVec() const { return &encoderparamsvec; }
|
||||
const std::string GetOptEncoderParams() const { return encoderparams; }
|
||||
uint64_t GetVideoWriterEventId() const { return video_store_data->current_event; }
|
||||
void SetVideoWriterEventId( unsigned long long p_event_id ) { video_store_data->current_event = p_event_id; }
|
||||
struct timeval GetVideoWriterStartTime() const { return video_store_data->recording; }
|
||||
|
||||
+16
-12
@@ -76,9 +76,9 @@ bool MonitorStream::checkSwapPath(const char *path, bool create_path) {
|
||||
} // end bool MonitorStream::checkSwapPath( const char *path, bool create_path )
|
||||
|
||||
void MonitorStream::processCommand(const CmdMsg *msg) {
|
||||
Debug( 2, "Got message, type %d, msg %d", msg->msg_type, msg->msg_data[0] );
|
||||
Debug(2, "Got message, type %d, msg %d", msg->msg_type, msg->msg_data[0]);
|
||||
// Check for incoming command
|
||||
switch( (MsgCommand)msg->msg_data[0] ) {
|
||||
switch ( (MsgCommand)msg->msg_data[0] ) {
|
||||
case CMD_PAUSE :
|
||||
Debug(1, "Got PAUSE command");
|
||||
paused = true;
|
||||
@@ -328,11 +328,12 @@ bool MonitorStream::sendFrame(const char *filepath, struct timeval *timestamp) {
|
||||
struct timeval frameStartTime;
|
||||
gettimeofday(&frameStartTime, NULL);
|
||||
|
||||
fputs("--" BOUNDARY "\r\nContent-Type: image/jpeg\r\n", stdout);
|
||||
fprintf(stdout, "Content-Length: %d\r\n"
|
||||
"X-Timestamp: %d.%06d\r\n"
|
||||
"\r\n", img_buffer_size, (int)timestamp->tv_sec, (int)timestamp->tv_usec);
|
||||
if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
|
||||
if (
|
||||
(0 > fprintf(stdout, "Content-Length: %d\r\nX-Timestamp: %d.%06d\r\n\r\n",
|
||||
img_buffer_size, (int)timestamp->tv_sec, (int)timestamp->tv_usec))
|
||||
||
|
||||
(fwrite(img_buffer, img_buffer_size, 1, stdout) != 1)
|
||||
) {
|
||||
if ( !zm_terminate )
|
||||
Warning("Unable to send stream frame: %s", strerror(errno));
|
||||
return false;
|
||||
@@ -387,7 +388,8 @@ bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) {
|
||||
struct timeval frameStartTime;
|
||||
gettimeofday(&frameStartTime, NULL);
|
||||
|
||||
switch( type ) {
|
||||
fputs("--ZoneMinderFrame\r\n", stdout);
|
||||
switch ( type ) {
|
||||
case STREAM_JPEG :
|
||||
send_image->EncodeJpeg(img_buffer, &img_buffer_size);
|
||||
fputs("Content-Type: image/jpeg\r\n", stdout);
|
||||
@@ -412,10 +414,12 @@ bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) {
|
||||
Error("Unexpected frame type %d", type);
|
||||
return false;
|
||||
}
|
||||
fprintf(stdout, "Content-Length: %d\r\n"
|
||||
"X-Timestamp: %d.%06d\r\n"
|
||||
"\r\n", img_buffer_size, (int)timestamp->tv_sec, (int)timestamp->tv_usec);
|
||||
if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
|
||||
if (
|
||||
( 0 > fprintf(stdout, "Content-Length: %d\r\nX-Timestamp: %d.%06d\r\n\r\n",
|
||||
img_buffer_size, (int)timestamp->tv_sec, (int)timestamp->tv_usec) )
|
||||
||
|
||||
(fwrite(img_buffer, img_buffer_size, 1, stdout) != 1)
|
||||
) {
|
||||
if ( !zm_terminate ) {
|
||||
// If the pipe was closed, we will get signalled SIGPIPE to exit, which will set zm_terminate
|
||||
Warning("Unable to send stream frame: %s", strerror(errno));
|
||||
|
||||
+11
-13
@@ -44,19 +44,17 @@ class MonitorStream : public StreamBase {
|
||||
time_t ttl;
|
||||
int playback_buffer;
|
||||
bool delayed;
|
||||
|
||||
int frame_count;
|
||||
|
||||
protected:
|
||||
bool checkSwapPath( const char *path, bool create_path );
|
||||
|
||||
bool sendFrame( const char *filepath, struct timeval *timestamp );
|
||||
bool sendFrame( Image *image, struct timeval *timestamp );
|
||||
void processCommand( const CmdMsg *msg );
|
||||
void SingleImage( int scale=100 );
|
||||
void SingleImageRaw( int scale=100 );
|
||||
bool checkSwapPath(const char *path, bool create_path);
|
||||
bool sendFrame(const char *filepath, struct timeval *timestamp);
|
||||
bool sendFrame(Image *image, struct timeval *timestamp);
|
||||
void processCommand(const CmdMsg *msg);
|
||||
void SingleImage(int scale=100);
|
||||
void SingleImageRaw(int scale=100);
|
||||
#ifdef HAVE_ZLIB_H
|
||||
void SingleImageZip( int scale=100 );
|
||||
void SingleImageZip(int scale=100);
|
||||
#endif
|
||||
|
||||
public:
|
||||
@@ -64,14 +62,14 @@ class MonitorStream : public StreamBase {
|
||||
temp_image_buffer(NULL), temp_image_buffer_count(0), temp_read_index(0), temp_write_index(0),
|
||||
ttl(0), playback_buffer(0), delayed(false), frame_count(0) {
|
||||
}
|
||||
void setStreamBuffer( int p_playback_buffer ) {
|
||||
void setStreamBuffer(int p_playback_buffer) {
|
||||
playback_buffer = p_playback_buffer;
|
||||
}
|
||||
void setStreamTTL( time_t p_ttl ) {
|
||||
void setStreamTTL(time_t p_ttl) {
|
||||
ttl = p_ttl;
|
||||
}
|
||||
bool setStreamStart( int monitor_id ) {
|
||||
return loadMonitor( monitor_id );
|
||||
bool setStreamStart(int monitor_id) {
|
||||
return loadMonitor(monitor_id);
|
||||
}
|
||||
void runStream();
|
||||
};
|
||||
|
||||
+31
-40
@@ -40,16 +40,7 @@ VideoStream::MimeData VideoStream::mime_data[] = {
|
||||
};
|
||||
|
||||
void VideoStream::Initialise( ) {
|
||||
if ( logDebugging() ) {
|
||||
av_log_set_level( AV_LOG_DEBUG );
|
||||
} else {
|
||||
av_log_set_level( AV_LOG_QUIET );
|
||||
}
|
||||
|
||||
av_register_all( );
|
||||
#if LIBAVFORMAT_VERSION_CHECK(53, 13, 0, 19, 0)
|
||||
avformat_network_init();
|
||||
#endif
|
||||
FFMPEGInit();
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
@@ -57,23 +48,23 @@ void VideoStream::SetupFormat( ) {
|
||||
/* allocate the output media context */
|
||||
ofc = NULL;
|
||||
#if (LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 2, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100))
|
||||
avformat_alloc_output_context2( &ofc, NULL, format, filename );
|
||||
avformat_alloc_output_context2(&ofc, NULL, format, filename);
|
||||
#else
|
||||
AVFormatContext *s= avformat_alloc_context();
|
||||
if(!s) {
|
||||
Fatal( "avformat_alloc_context failed %d \"%s\"", (size_t)ofc, av_err2str((size_t)ofc) );
|
||||
AVFormatContext *s = avformat_alloc_context();
|
||||
if ( !s ) {
|
||||
Fatal("avformat_alloc_context failed %d \"%s\"", (size_t)ofc, av_err2str((size_t)ofc));
|
||||
return;
|
||||
}
|
||||
|
||||
AVOutputFormat *oformat;
|
||||
if (format) {
|
||||
if ( format ) {
|
||||
#if LIBAVFORMAT_VERSION_CHECK(52, 45, 0, 45, 0)
|
||||
oformat = av_guess_format(format, NULL, NULL);
|
||||
#else
|
||||
oformat = guess_format(format, NULL, NULL);
|
||||
#endif
|
||||
if (!oformat) {
|
||||
Fatal( "Requested output format '%s' is not a suitable output format", format );
|
||||
if ( !oformat ) {
|
||||
Fatal("Requested output format '%s' is not a suitable output format", format);
|
||||
}
|
||||
} else {
|
||||
#if LIBAVFORMAT_VERSION_CHECK(52, 45, 0, 45, 0)
|
||||
@@ -81,47 +72,47 @@ void VideoStream::SetupFormat( ) {
|
||||
#else
|
||||
oformat = guess_format(NULL, filename, NULL);
|
||||
#endif
|
||||
if (!oformat) {
|
||||
Fatal( "Unable to find a suitable output format for '%s'", format );
|
||||
if ( !oformat ) {
|
||||
Fatal("Unable to find a suitable output format for '%s'", format);
|
||||
}
|
||||
}
|
||||
s->oformat = oformat;
|
||||
|
||||
if (s->oformat->priv_data_size > 0) {
|
||||
if ( s->oformat->priv_data_size > 0 ) {
|
||||
s->priv_data = av_mallocz(s->oformat->priv_data_size);
|
||||
if ( !(s->priv_data) ) {
|
||||
Fatal( "Could not allocate private data for output format." );
|
||||
Fatal("Could not allocate private data for output format.");
|
||||
}
|
||||
#if LIBAVFORMAT_VERSION_CHECK(52, 92, 0, 92, 0)
|
||||
if (s->oformat->priv_class) {
|
||||
if ( s->oformat->priv_class ) {
|
||||
*(const AVClass**)s->priv_data = s->oformat->priv_class;
|
||||
av_opt_set_defaults(s->priv_data);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
Debug(1,"No allocating priv_data");
|
||||
Debug(1, "No allocating priv_data");
|
||||
s->priv_data = NULL;
|
||||
}
|
||||
|
||||
if ( filename ) {
|
||||
snprintf( s->filename, sizeof(s->filename), "%s", filename );
|
||||
snprintf(s->filename, sizeof(s->filename), "%s", filename);
|
||||
}
|
||||
|
||||
ofc = s;
|
||||
#endif
|
||||
if ( !ofc ) {
|
||||
Fatal( "avformat_alloc_..._context failed: %d", ofc );
|
||||
Fatal("avformat_alloc_..._context failed: %d", ofc);
|
||||
}
|
||||
|
||||
of = ofc->oformat;
|
||||
Debug( 1, "Using output format: %s (%s)", of->name, of->long_name );
|
||||
Debug(1, "Using output format: %s (%s)", of->name, of->long_name);
|
||||
}
|
||||
|
||||
void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int height, int bitrate, double frame_rate ) {
|
||||
/* ffmpeg format matching */
|
||||
switch(colours) {
|
||||
switch ( colours ) {
|
||||
case ZM_COLOUR_RGB24:
|
||||
if(subpixelorder == ZM_SUBPIX_ORDER_BGR) {
|
||||
if ( subpixelorder == ZM_SUBPIX_ORDER_BGR ) {
|
||||
/* BGR subpixel order */
|
||||
pf = AV_PIX_FMT_BGR24;
|
||||
} else {
|
||||
@@ -130,13 +121,13 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
|
||||
}
|
||||
break;
|
||||
case ZM_COLOUR_RGB32:
|
||||
if(subpixelorder == ZM_SUBPIX_ORDER_ARGB) {
|
||||
if ( subpixelorder == ZM_SUBPIX_ORDER_ARGB ) {
|
||||
/* ARGB subpixel order */
|
||||
pf = AV_PIX_FMT_ARGB;
|
||||
} else if(subpixelorder == ZM_SUBPIX_ORDER_ABGR) {
|
||||
} else if ( subpixelorder == ZM_SUBPIX_ORDER_ABGR ) {
|
||||
/* ABGR subpixel order */
|
||||
pf = AV_PIX_FMT_ABGR;
|
||||
} else if(subpixelorder == ZM_SUBPIX_ORDER_BGRA) {
|
||||
} else if ( subpixelorder == ZM_SUBPIX_ORDER_BGRA ) {
|
||||
/* BGRA subpixel order */
|
||||
pf = AV_PIX_FMT_BGRA;
|
||||
} else {
|
||||
@@ -152,7 +143,7 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
|
||||
break;
|
||||
}
|
||||
|
||||
if ( strcmp( "rtp", of->name ) == 0 ) {
|
||||
if ( strcmp("rtp", of->name) == 0 ) {
|
||||
// RTP must have a packet_size.
|
||||
// Not sure what this value should be really...
|
||||
ofc->packet_size = width*height;
|
||||
@@ -169,12 +160,12 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
|
||||
AVCodec *a = avcodec_find_encoder_by_name(codec_name);
|
||||
if ( a ) {
|
||||
codec_id = a->id;
|
||||
Debug( 1, "Using codec \"%s\"", codec_name );
|
||||
Debug(1, "Using codec \"%s\"", codec_name);
|
||||
} else {
|
||||
#if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100))
|
||||
Debug( 1, "Could not find codec \"%s\". Using default \"%s\"", codec_name, avcodec_get_name( codec_id ) );
|
||||
Debug(1, "Could not find codec \"%s\". Using default \"%s\"", codec_name, avcodec_get_name(codec_id));
|
||||
#else
|
||||
Debug( 1, "Could not find codec \"%s\". Using default \"%d\"", codec_name, codec_id );
|
||||
Debug(1, "Could not find codec \"%s\". Using default \"%d\"", codec_name, codec_id);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -183,19 +174,19 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
|
||||
and initialize the codecs */
|
||||
ost = NULL;
|
||||
if ( codec_id != AV_CODEC_ID_NONE ) {
|
||||
codec = avcodec_find_encoder( codec_id );
|
||||
codec = avcodec_find_encoder(codec_id);
|
||||
if ( !codec ) {
|
||||
#if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100))
|
||||
Fatal( "Could not find encoder for '%s'", avcodec_get_name( codec_id ) );
|
||||
Fatal("Could not find encoder for '%s'", avcodec_get_name(codec_id));
|
||||
#else
|
||||
Fatal( "Could not find encoder for '%d'", codec_id );
|
||||
Fatal("Could not find encoder for '%d'", codec_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100))
|
||||
Debug( 1, "Found encoder for '%s'", avcodec_get_name( codec_id ) );
|
||||
Debug(1, "Found encoder for '%s'", avcodec_get_name(codec_id));
|
||||
#else
|
||||
Debug( 1, "Found encoder for '%d'", codec_id );
|
||||
Debug(1, "Found encoder for '%d'", codec_id);
|
||||
#endif
|
||||
|
||||
#if LIBAVFORMAT_VERSION_CHECK(53, 10, 0, 17, 0)
|
||||
|
||||
@@ -624,8 +624,8 @@ int RemoteCameraHttp::GetResponse() {
|
||||
static char *content_type_header;
|
||||
static char *boundary_header;
|
||||
static char *authenticate_header;
|
||||
static char subcontent_length_header[32];
|
||||
static char subcontent_type_header[64];
|
||||
static char subcontent_length_header[33];
|
||||
static char subcontent_type_header[65];
|
||||
|
||||
static char http_version[16];
|
||||
static char status_code[16];
|
||||
@@ -896,25 +896,37 @@ int RemoteCameraHttp::GetResponse() {
|
||||
}
|
||||
}
|
||||
|
||||
Debug( 6, "%d: %s", subheader_len, subheader_ptr );
|
||||
Debug(6, "%d: %s", subheader_len, subheader_ptr);
|
||||
|
||||
if ( (crlf = mempbrk( subheader_ptr, "\r\n", subheader_len )) ) {
|
||||
if ( (crlf = mempbrk(subheader_ptr, "\r\n", subheader_len)) ) {
|
||||
//subheaders[n_subheaders++] = subheader_ptr;
|
||||
n_subheaders++;
|
||||
|
||||
if ( !boundary_header && (strncasecmp( subheader_ptr, content_boundary, content_boundary_len ) == 0) ) {
|
||||
if ( !boundary_header && (strncasecmp(subheader_ptr, content_boundary, content_boundary_len) == 0) ) {
|
||||
boundary_header = subheader_ptr;
|
||||
Debug( 4, "Got boundary subheader '%s'", subheader_ptr );
|
||||
} else if ( !subcontent_length_header[0] && (strncasecmp( subheader_ptr, content_length_match, content_length_match_len) == 0) ) {
|
||||
strncpy( subcontent_length_header, subheader_ptr+content_length_match_len, sizeof(subcontent_length_header) );
|
||||
*(subcontent_length_header+strcspn( subcontent_length_header, "\r\n" )) = '\0';
|
||||
Debug( 4, "Got content length subheader '%s'", subcontent_length_header );
|
||||
Debug(4, "Got boundary subheader '%s'", subheader_ptr);
|
||||
} else if (
|
||||
!subcontent_length_header[0]
|
||||
&&
|
||||
(strncasecmp(subheader_ptr, content_length_match, content_length_match_len) == 0)
|
||||
) {
|
||||
strncpy(
|
||||
subcontent_length_header,
|
||||
subheader_ptr+content_length_match_len,
|
||||
sizeof(subcontent_length_header)-1
|
||||
);
|
||||
*(subcontent_length_header+strcspn(subcontent_length_header, "\r\n")) = '\0';
|
||||
Debug(4, "Got content length subheader '%s'", subcontent_length_header);
|
||||
} else if ( !subcontent_type_header[0] && (strncasecmp( subheader_ptr, content_type_match, content_type_match_len) == 0) ) {
|
||||
strncpy( subcontent_type_header, subheader_ptr+content_type_match_len, sizeof(subcontent_type_header) );
|
||||
*(subcontent_type_header+strcspn( subcontent_type_header, "\r\n" )) = '\0';
|
||||
Debug( 4, "Got content type subheader '%s'", subcontent_type_header );
|
||||
strncpy(
|
||||
subcontent_type_header,
|
||||
subheader_ptr+content_type_match_len,
|
||||
sizeof(subcontent_type_header)-1
|
||||
);
|
||||
*(subcontent_type_header+strcspn(subcontent_type_header, "\r\n")) = '\0';
|
||||
Debug(4, "Got content type subheader '%s'", subcontent_type_header);
|
||||
} else {
|
||||
Debug( 6, "Got ignored subheader '%s' found", subheader_ptr );
|
||||
Debug(6, "Got ignored subheader '%s' found", subheader_ptr);
|
||||
}
|
||||
subheader_ptr = crlf;
|
||||
subheader_len -= buffer.consume( subheader_ptr-(char *)buffer );
|
||||
@@ -1057,6 +1069,18 @@ int RemoteCameraHttp::GetResponse() {
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int RemoteCameraHttp::PrimeCapture() {
|
||||
if ( sd < 0 ) {
|
||||
Connect();
|
||||
if ( sd < 0 ) {
|
||||
return -1;
|
||||
}
|
||||
mode = SINGLE_IMAGE;
|
||||
buffer.clear();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RemoteCameraHttp::PreCapture() {
|
||||
if ( sd < 0 ) {
|
||||
Connect();
|
||||
|
||||
@@ -55,6 +55,7 @@ public:
|
||||
int ReadData( Buffer &buffer, unsigned int bytes_expected=0 );
|
||||
int GetData();
|
||||
int GetResponse();
|
||||
int PrimeCapture();
|
||||
int PreCapture();
|
||||
int Capture( Image &image );
|
||||
int PostCapture();
|
||||
|
||||
+19
-20
@@ -104,13 +104,13 @@ protected:
|
||||
CmdMsg msg;
|
||||
|
||||
protected:
|
||||
bool loadMonitor( int monitor_id );
|
||||
bool loadMonitor(int monitor_id);
|
||||
bool checkInitialised();
|
||||
void updateFrameRate( double fps );
|
||||
Image *prepareImage( Image *image );
|
||||
bool sendTextFrame( const char *text );
|
||||
void updateFrameRate(double fps);
|
||||
Image *prepareImage(Image *image);
|
||||
bool sendTextFrame(const char *text);
|
||||
bool checkCommandQueue();
|
||||
virtual void processCommand( const CmdMsg *msg )=0;
|
||||
virtual void processCommand(const CmdMsg *msg)=0;
|
||||
|
||||
public:
|
||||
StreamBase():
|
||||
@@ -135,13 +135,12 @@ public:
|
||||
lock_fd(0),
|
||||
paused(false),
|
||||
step(0)
|
||||
|
||||
{
|
||||
memset( &loc_sock_path, 0, sizeof(loc_sock_path) );
|
||||
memset( &loc_addr, 0, sizeof(loc_addr) );
|
||||
memset( &rem_sock_path, 0, sizeof(rem_sock_path) );
|
||||
memset( &rem_addr, 0, sizeof(rem_addr) );
|
||||
memset( &sock_path_lock, 0, sizeof(sock_path_lock) );
|
||||
memset(&loc_sock_path, 0, sizeof(loc_sock_path));
|
||||
memset(&loc_addr, 0, sizeof(loc_addr));
|
||||
memset(&rem_sock_path, 0, sizeof(rem_sock_path));
|
||||
memset(&rem_addr, 0, sizeof(rem_addr));
|
||||
memset(&sock_path_lock, 0, sizeof(sock_path_lock));
|
||||
|
||||
base_fps = 0.0;
|
||||
effective_fps = 0.0;
|
||||
@@ -156,28 +155,28 @@ 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 )
|
||||
if ( !scale )
|
||||
scale = DEFAULT_SCALE;
|
||||
}
|
||||
void setStreamReplayRate( int p_rate ) {
|
||||
Debug(2,"Setting replay_rate %d", p_rate);
|
||||
void setStreamReplayRate(int p_rate) {
|
||||
Debug(2, "Setting replay_rate %d", 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();
|
||||
|
||||
+57
-70
@@ -35,7 +35,7 @@
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
|
||||
unsigned int sseversion = 0;
|
||||
unsigned int sse_version = 0;
|
||||
unsigned int neonversion = 0;
|
||||
|
||||
std::string trimSet(std::string str, std::string trimset) {
|
||||
@@ -44,12 +44,9 @@ std::string trimSet(std::string str, std::string trimset) {
|
||||
size_t endpos = str.find_last_not_of(trimset); // Find the first character position from reverse af
|
||||
|
||||
// if all spaces or empty return an empty string
|
||||
if(( std::string::npos == startpos ) || ( std::string::npos == endpos))
|
||||
{
|
||||
if ( ( std::string::npos == startpos ) || ( std::string::npos == endpos ) )
|
||||
return std::string("");
|
||||
}
|
||||
else
|
||||
return str.substr( startpos, endpos-startpos+1 );
|
||||
return str.substr(startpos, endpos-startpos+1);
|
||||
}
|
||||
|
||||
std::string trimSpaces(const std::string &str) {
|
||||
@@ -57,48 +54,46 @@ std::string trimSpaces(const std::string &str) {
|
||||
}
|
||||
|
||||
std::string replaceAll(std::string str, std::string from, std::string to) {
|
||||
if(from.empty())
|
||||
if ( from.empty() )
|
||||
return str;
|
||||
size_t start_pos = 0;
|
||||
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
|
||||
while ( (start_pos = str.find(from, start_pos)) != std::string::npos ) {
|
||||
str.replace(start_pos, from.length(), to);
|
||||
start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
const std::string stringtf( const char *format, ... )
|
||||
{
|
||||
const std::string stringtf( const char *format, ... ) {
|
||||
va_list ap;
|
||||
char tempBuffer[8192];
|
||||
std::string tempString;
|
||||
|
||||
va_start(ap, format );
|
||||
vsnprintf( tempBuffer, sizeof(tempBuffer), format , ap );
|
||||
va_start(ap, format);
|
||||
vsnprintf(tempBuffer, sizeof(tempBuffer), format , ap);
|
||||
va_end(ap);
|
||||
|
||||
tempString = tempBuffer;
|
||||
|
||||
return( tempString );
|
||||
return tempString;
|
||||
}
|
||||
|
||||
const std::string stringtf( const std::string format, ... )
|
||||
{
|
||||
const std::string stringtf(const std::string format, ...) {
|
||||
va_list ap;
|
||||
char tempBuffer[8192];
|
||||
std::string tempString;
|
||||
|
||||
va_start(ap, format );
|
||||
vsnprintf( tempBuffer, sizeof(tempBuffer), format.c_str() , ap );
|
||||
va_start(ap, format);
|
||||
vsnprintf(tempBuffer, sizeof(tempBuffer), format.c_str(), ap);
|
||||
va_end(ap);
|
||||
|
||||
tempString = tempBuffer;
|
||||
|
||||
return( tempString );
|
||||
return tempString;
|
||||
}
|
||||
|
||||
bool startsWith(const std::string &haystack, const std::string &needle) {
|
||||
return( haystack.substr(0, needle.length()) == needle );
|
||||
return ( haystack.substr(0, needle.length()) == needle );
|
||||
}
|
||||
|
||||
StringVector split(const std::string &string, const std::string &chars, int limit) {
|
||||
@@ -145,8 +140,7 @@ const std::string join(const StringVector &v, const char * delim=",") {
|
||||
const std::string base64Encode(const std::string &inString) {
|
||||
static char base64_table[64] = { '\0' };
|
||||
|
||||
if ( !base64_table[0] )
|
||||
{
|
||||
if ( !base64_table[0] ) {
|
||||
int i = 0;
|
||||
for ( char c = 'A'; c <= 'Z'; c++ )
|
||||
base64_table[i++] = c;
|
||||
@@ -159,59 +153,52 @@ const std::string base64Encode(const std::string &inString) {
|
||||
}
|
||||
|
||||
std::string outString;
|
||||
outString.reserve( 2 * inString.size() );
|
||||
outString.reserve(2 * inString.size());
|
||||
|
||||
const char *inPtr = inString.c_str();
|
||||
while( *inPtr )
|
||||
{
|
||||
while ( *inPtr ) {
|
||||
unsigned char selection = *inPtr >> 2;
|
||||
unsigned char remainder = (*inPtr++ & 0x03) << 4;
|
||||
outString += base64_table[selection];
|
||||
|
||||
if ( *inPtr )
|
||||
{
|
||||
if ( *inPtr ) {
|
||||
selection = remainder | (*inPtr >> 4);
|
||||
remainder = (*inPtr++ & 0x0f) << 2;
|
||||
outString += base64_table[selection];
|
||||
|
||||
if ( *inPtr )
|
||||
{
|
||||
if ( *inPtr ) {
|
||||
selection = remainder | (*inPtr >> 6);
|
||||
outString += base64_table[selection];
|
||||
selection = (*inPtr++ & 0x3f);
|
||||
outString += base64_table[selection];
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
outString += base64_table[remainder];
|
||||
outString += '=';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
outString += base64_table[remainder];
|
||||
outString += '=';
|
||||
outString += '=';
|
||||
}
|
||||
}
|
||||
return( outString );
|
||||
return outString;
|
||||
}
|
||||
|
||||
int split(const char* string, const char delim, std::vector<std::string>& items) {
|
||||
if(string == NULL)
|
||||
if ( string == NULL )
|
||||
return -1;
|
||||
|
||||
if(string[0] == 0)
|
||||
if ( string[0] == 0 )
|
||||
return -2;
|
||||
|
||||
std::string str(string);
|
||||
|
||||
while(true) {
|
||||
while ( true ) {
|
||||
size_t pos = str.find(delim);
|
||||
items.push_back(str.substr(0, pos));
|
||||
str.erase(0, pos+1);
|
||||
|
||||
if(pos == std::string::npos)
|
||||
if ( pos == std::string::npos )
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -219,16 +206,16 @@ int split(const char* string, const char delim, std::vector<std::string>& items)
|
||||
}
|
||||
|
||||
int pairsplit(const char* string, const char delim, std::string& name, std::string& value) {
|
||||
if(string == NULL)
|
||||
if ( string == NULL )
|
||||
return -1;
|
||||
|
||||
if(string[0] == 0)
|
||||
if ( string[0] == 0 )
|
||||
return -2;
|
||||
|
||||
std::string str(string);
|
||||
size_t pos = str.find(delim);
|
||||
|
||||
if(pos == std::string::npos || pos == 0 || pos >= str.length())
|
||||
if ( pos == std::string::npos || pos == 0 || pos >= str.length() )
|
||||
return -3;
|
||||
|
||||
name = str.substr(0, pos);
|
||||
@@ -240,7 +227,7 @@ int pairsplit(const char* string, const char delim, std::string& name, std::stri
|
||||
/* Detect special hardware features, such as SIMD instruction sets */
|
||||
void hwcaps_detect() {
|
||||
neonversion = 0;
|
||||
sseversion = 0;
|
||||
sse_version = 0;
|
||||
#if (defined(__i386__) || defined(__x86_64__))
|
||||
/* x86 or x86-64 processor */
|
||||
uint32_t r_edx, r_ecx, r_ebx;
|
||||
@@ -277,33 +264,33 @@ void hwcaps_detect() {
|
||||
);
|
||||
#endif
|
||||
|
||||
if (r_ebx & 0x00000020) {
|
||||
sseversion = 52; /* AVX2 */
|
||||
Debug(1,"Detected a x86\\x86-64 processor with AVX2");
|
||||
} else if (r_ecx & 0x10000000) {
|
||||
sseversion = 51; /* AVX */
|
||||
Debug(1,"Detected a x86\\x86-64 processor with AVX");
|
||||
} else if (r_ecx & 0x00100000) {
|
||||
sseversion = 42; /* SSE4.2 */
|
||||
Debug(1,"Detected a x86\\x86-64 processor with SSE4.2");
|
||||
} else if (r_ecx & 0x00080000) {
|
||||
sseversion = 41; /* SSE4.1 */
|
||||
Debug(1,"Detected a x86\\x86-64 processor with SSE4.1");
|
||||
} else if (r_ecx & 0x00000200) {
|
||||
sseversion = 35; /* SSSE3 */
|
||||
if ( r_ebx & 0x00000020 ) {
|
||||
sse_version = 52; /* AVX2 */
|
||||
Debug(1, "Detected a x86\\x86-64 processor with AVX2");
|
||||
} else if ( r_ecx & 0x10000000 ) {
|
||||
sse_version = 51; /* AVX */
|
||||
Debug(1, "Detected a x86\\x86-64 processor with AVX");
|
||||
} else if ( r_ecx & 0x00100000 ) {
|
||||
sse_version = 42; /* SSE4.2 */
|
||||
Debug(1, "Detected a x86\\x86-64 processor with SSE4.2");
|
||||
} else if ( r_ecx & 0x00080000 ) {
|
||||
sse_version = 41; /* SSE4.1 */
|
||||
Debug(1, "Detected a x86\\x86-64 processor with SSE4.1");
|
||||
} else if ( r_ecx & 0x00000200 ) {
|
||||
sse_version = 35; /* SSSE3 */
|
||||
Debug(1,"Detected a x86\\x86-64 processor with SSSE3");
|
||||
} else if (r_ecx & 0x00000001) {
|
||||
sseversion = 30; /* SSE3 */
|
||||
Debug(1,"Detected a x86\\x86-64 processor with SSE3");
|
||||
} else if (r_edx & 0x04000000) {
|
||||
sseversion = 20; /* SSE2 */
|
||||
Debug(1,"Detected a x86\\x86-64 processor with SSE2");
|
||||
} else if (r_edx & 0x02000000) {
|
||||
sseversion = 10; /* SSE */
|
||||
Debug(1,"Detected a x86\\x86-64 processor with SSE");
|
||||
} else if ( r_ecx & 0x00000001 ) {
|
||||
sse_version = 30; /* SSE3 */
|
||||
Debug(1, "Detected a x86\\x86-64 processor with SSE3");
|
||||
} else if ( r_edx & 0x04000000 ) {
|
||||
sse_version = 20; /* SSE2 */
|
||||
Debug(1, "Detected a x86\\x86-64 processor with SSE2");
|
||||
} else if ( r_edx & 0x02000000 ) {
|
||||
sse_version = 10; /* SSE */
|
||||
Debug(1, "Detected a x86\\x86-64 processor with SSE");
|
||||
} else {
|
||||
sseversion = 0;
|
||||
Debug(1,"Detected a x86\\x86-64 processor");
|
||||
sse_version = 0;
|
||||
Debug(1, "Detected a x86\\x86-64 processor");
|
||||
}
|
||||
#elif defined(__arm__)
|
||||
// ARM processor in 32bit mode
|
||||
@@ -333,7 +320,7 @@ __attribute__((noinline,__target__("sse2")))
|
||||
#endif
|
||||
void* sse2_aligned_memcpy(void* dest, const void* src, size_t bytes) {
|
||||
#if ((defined(__i386__) || defined(__x86_64__) || defined(ZM_KEEP_SSE)) && !defined(ZM_STRIP_SSE))
|
||||
if(bytes > 128) {
|
||||
if ( bytes > 128 ) {
|
||||
unsigned int remainder = bytes % 128;
|
||||
const uint8_t* lastsrc = (uint8_t*)src + (bytes - remainder);
|
||||
|
||||
@@ -375,7 +362,7 @@ void* sse2_aligned_memcpy(void* dest, const void* src, size_t bytes) {
|
||||
}
|
||||
#else
|
||||
/* Non x86\x86-64 platform, use memcpy */
|
||||
memcpy(dest,src,bytes);
|
||||
memcpy(dest, src, bytes);
|
||||
#endif
|
||||
return dest;
|
||||
}
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ void* sse2_aligned_memcpy(void* dest, const void* src, size_t bytes);
|
||||
void timespec_diff(struct timespec *start, struct timespec *end, struct timespec *diff);
|
||||
|
||||
void hwcaps_detect();
|
||||
extern unsigned int sseversion;
|
||||
extern unsigned int sse_version;
|
||||
extern unsigned int neonversion;
|
||||
|
||||
char *timeval_to_string( struct timeval tv );
|
||||
|
||||
+39
-13
@@ -37,11 +37,12 @@ VideoStore::VideoStore(
|
||||
const char *format_in,
|
||||
AVStream *p_video_in_stream,
|
||||
AVStream *p_audio_in_stream,
|
||||
Monitor *monitor
|
||||
Monitor *p_monitor
|
||||
) {
|
||||
|
||||
video_in_stream = p_video_in_stream;
|
||||
audio_in_stream = p_audio_in_stream;
|
||||
monitor = p_monitor;
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
//video_in_ctx = avcodec_alloc_context3(NULL);
|
||||
@@ -213,11 +214,18 @@ VideoStore::VideoStore(
|
||||
}
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
|
||||
#if 0
|
||||
# This is commented out because we are only doing passthrough right now
|
||||
/* I'm not entirely sure that this is a good idea. We may have to do it someday but really only when transcoding
|
||||
* * think what I was trying to achieve here was to have zm_dump_codecpar output nice info
|
||||
* */
|
||||
#if 0
|
||||
|
||||
AVDictionary *opts = 0;
|
||||
ret = av_dict_parse_string(&opts, monitor->GetOptEncoderParams().c_str(), "=", ",", 0);
|
||||
if ( ret < 0 ) {
|
||||
Warning("Could not parse ffmpeg encoder options '%s'", monitor->GetOptEncoderParams().c_str());
|
||||
}
|
||||
|
||||
if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) {
|
||||
Warning("Can't open video codec (%s) %s",
|
||||
video_out_codec->name,
|
||||
@@ -404,21 +412,39 @@ bool VideoStore::open() {
|
||||
}
|
||||
|
||||
zm_dump_stream_format(oc, 0, 0, 1);
|
||||
if (audio_out_stream) zm_dump_stream_format(oc, 1, 0, 1);
|
||||
if ( audio_out_stream ) zm_dump_stream_format(oc, 1, 0, 1);
|
||||
|
||||
AVDictionary *opts = NULL;
|
||||
// av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
|
||||
// Shiboleth reports that this may break seeking in mp4 before it downloads
|
||||
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
|
||||
// av_dict_set(&opts, "movflags",
|
||||
// "frag_keyframe+empty_moov+default_base_moof", 0);
|
||||
|
||||
std::string option_string = monitor->GetOptEncoderParams();
|
||||
ret = av_dict_parse_string(&opts, option_string.c_str(), "=", ",\n", 0);
|
||||
if ( ret < 0 ) {
|
||||
Warning("Could not parse ffmpeg output options '%s'", option_string.c_str());
|
||||
}
|
||||
|
||||
const AVDictionaryEntry *movflags_entry = av_dict_get(opts, "movflags", NULL, AV_DICT_MATCH_CASE);
|
||||
if ( !movflags_entry ) {
|
||||
Debug(1, "setting movflags to frag_keyframe+empty_moov");
|
||||
// av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
|
||||
// Shiboleth reports that this may break seeking in mp4 before it downloads
|
||||
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
|
||||
// av_dict_set(&opts, "movflags",
|
||||
// "frag_keyframe+empty_moov+default_base_moof", 0);
|
||||
} else {
|
||||
Debug(1, "using movflags %s", movflags_entry->value);
|
||||
}
|
||||
if ( (ret = avformat_write_header(oc, &opts)) < 0 ) {
|
||||
// if ((ret = avformat_write_header(oc, &opts)) < 0) {
|
||||
Warning("Unable to set movflags to frag_custom+dash+delay_moov");
|
||||
/* Write the stream header, if any. */
|
||||
Warning("Unable to set movflags trying with defaults.");
|
||||
ret = avformat_write_header(oc, NULL);
|
||||
} else if (av_dict_count(opts) != 0) {
|
||||
Warning("some options not set");
|
||||
} else if ( av_dict_count(opts) != 0 ) {
|
||||
Info("some options not used, turn on debugging for a list.");
|
||||
AVDictionaryEntry *e = NULL;
|
||||
while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
||||
Debug(1, "Encoder Option %s=>%s", e->key, e->value);
|
||||
if ( !e->value ) {
|
||||
av_dict_set(&opts, e->key, NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( opts ) av_dict_free(&opts);
|
||||
if ( ret < 0 ) {
|
||||
|
||||
+1
-1
@@ -19,7 +19,6 @@ extern "C" {
|
||||
|
||||
class VideoStore {
|
||||
private:
|
||||
|
||||
AVOutputFormat *out_format;
|
||||
AVFormatContext *oc;
|
||||
|
||||
@@ -30,6 +29,7 @@ private:
|
||||
AVStream *video_in_stream;
|
||||
|
||||
AVStream *audio_in_stream;
|
||||
Monitor *monitor;
|
||||
|
||||
// Move this into the object so that we aren't constantly allocating/deallocating it on the stack
|
||||
AVPacket opkt;
|
||||
|
||||
Loaded 100 of 190 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user