Merge branch 'master' of github.com:ZoneMinder/ZoneMinder
This commit is contained in:
commit
34dec24ebd
|
@ -5,6 +5,8 @@ You should only file an issue if you found a bug. Feature and enhancement reque
|
|||
|
||||
**Do not post feature or enhancement requests, general discussions or support questions here.**
|
||||
|
||||
Docker related issues should be posted here: https://github.com/ZoneMinder/zmdockerfiles
|
||||
|
||||
Make sure you are running the latest version of ZoneMinder before reporting an issue.
|
||||
|
||||
**ZoneMinder Version (`zmaudit.pl -v`):**
|
||||
|
|
12
.travis.yml
12
.travis.yml
|
@ -23,17 +23,27 @@ addons:
|
|||
- curl
|
||||
- sshfs
|
||||
- sed
|
||||
- binfmt-support
|
||||
- qemu
|
||||
- qemu-user-static
|
||||
install:
|
||||
- update-binfmts --enable qemu-arm
|
||||
|
||||
env:
|
||||
global:
|
||||
- SMPFLAGS=-j4
|
||||
matrix:
|
||||
- OS=el DIST=6
|
||||
- OS=el DIST=6 ARCH=i386 DOCKER_REPO=knnniggett/packpack
|
||||
- OS=el DIST=7
|
||||
- OS=fedora DIST=25
|
||||
- OS=fedora DIST=26 DOCKER_REPO=knnniggett/packpack
|
||||
- OS=fedora DIST=27 DOCKER_REPO=knnniggett/packpack
|
||||
- OS=ubuntu DIST=trusty
|
||||
- OS=ubuntu DIST=xenial
|
||||
- OS=ubuntu DIST=trusty ARCH=i386
|
||||
- OS=ubuntu DIST=xenial ARCH=i386
|
||||
- OS=raspbian DIST=stretch ARCH=armhf DOCKER_REPO=knnniggett/packpack
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
services:
|
||||
|
|
111
Dockerfile
111
Dockerfile
|
@ -1,111 +0,0 @@
|
|||
# ZoneMinder, you need the GIT repository code and submodules (git submodule update --init --recursive)
|
||||
|
||||
FROM ubuntu:xenial
|
||||
MAINTAINER Markos Vakondios <mvakondios@gmail.com>
|
||||
|
||||
# Resynchronize the package index files
|
||||
RUN apt-get update \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||
apache2 \
|
||||
build-essential \
|
||||
cmake \
|
||||
dh-autoreconf \
|
||||
dpatch \
|
||||
libapache2-mod-php \
|
||||
libarchive-zip-perl \
|
||||
libavcodec-dev \
|
||||
libavdevice-dev \
|
||||
libavfilter-dev \
|
||||
libavformat-dev \
|
||||
libavresample-dev \
|
||||
libav-tools \
|
||||
libavutil-dev \
|
||||
libbz2-dev \
|
||||
libcurl4-openssl-dev \
|
||||
libdate-manip-perl \
|
||||
libdbd-mysql-perl \
|
||||
libdbi-perl \
|
||||
libdevice-serialport-perl \
|
||||
libjpeg-turbo8 \
|
||||
libjpeg-turbo8-dev \
|
||||
libmime-lite-perl \
|
||||
libmime-perl \
|
||||
libmp4v2-dev \
|
||||
libmysqlclient-dev \
|
||||
libnetpbm10-dev \
|
||||
libpcre3 \
|
||||
libpcre3-dev \
|
||||
libpolkit-gobject-1-dev \
|
||||
libpostproc-dev \
|
||||
libssl-dev \
|
||||
libswscale-dev \
|
||||
libsys-mmap-perl \
|
||||
libtheora-dev \
|
||||
libtool \
|
||||
libv4l-dev \
|
||||
libvlc5 \
|
||||
libvlccore8 \
|
||||
libvlccore-dev \
|
||||
libvlc-dev \
|
||||
libvorbis-dev \
|
||||
libvpx-dev \
|
||||
libwww-perl \
|
||||
libx264-dev \
|
||||
mysql-client \
|
||||
mysql-server \
|
||||
php \
|
||||
php-cli \
|
||||
php-mysql \
|
||||
vlc-data \
|
||||
yasm \
|
||||
zip \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy local code into our container
|
||||
ADD cmake /ZoneMinder/cmake/
|
||||
ADD db /ZoneMinder/db/
|
||||
ADD misc /ZoneMinder/misc/
|
||||
ADD onvif /ZoneMinder/onvif/
|
||||
ADD scripts /ZoneMinder/scripts/
|
||||
ADD src /ZoneMinder/src/
|
||||
ADD umutils /ZoneMinder/umutils/
|
||||
ADD web /ZoneMinder/web/
|
||||
ADD cmakecacheimport.sh CMakeLists.txt version zm.conf.in zmconfgen.pl.in zmlinkcontent.sh.in zoneminder-config.cmake /ZoneMinder/
|
||||
ADD conf.d /ZoneMinder/conf.d
|
||||
|
||||
# Change into the ZoneMinder directory
|
||||
WORKDIR /ZoneMinder
|
||||
|
||||
# Setup the ZoneMinder build environment
|
||||
#RUN aclocal && autoheader && automake --force-missing --add-missing && autoconf
|
||||
|
||||
# Configure ZoneMinder
|
||||
#RUN ./configure --with-libarch=lib/$DEB_HOST_GNU_TYPE --disable-debug --host=$DEB_HOST_GNU_TYPE --build=$DEB_BUILD_GNU_TYPE --with-mysql=/usr --with-webdir=/var/www/zm --with-ffmpeg=/usr --with-cgidir=/usr/lib/cgi-bin --with-webuser=www-data --with-webgroup=www-data --enable-mmap=yes --enable-onvif ZM_SSL_LIB=openssl ZM_DB_USER=zm ZM_DB_PASS=zm
|
||||
RUN cmake .
|
||||
|
||||
# Build & install ZoneMinder
|
||||
RUN make && make install
|
||||
|
||||
# ensure writable folders
|
||||
RUN ./zmlinkcontent.sh
|
||||
|
||||
# Adding the start script
|
||||
ADD utils/docker/start.sh /tmp/start.sh
|
||||
|
||||
# Settings rights for /usr/local/share/zoneminder/
|
||||
RUN chown -R www-data:www-data /usr/local/share/zoneminder/
|
||||
|
||||
# Adding apache virtual hosts file
|
||||
RUN cp misc/apache.conf /etc/apache2/sites-available/000-default.conf
|
||||
|
||||
# Expose http port
|
||||
EXPOSE 80
|
||||
|
||||
VOLUME /var/lib/zoneminder/images /var/lib/zoneminder/events /var/lib/mysql /var/log/zm
|
||||
|
||||
# To speed up configuration testing, we put it here
|
||||
ADD utils/docker /ZoneMinder/utils/docker/
|
||||
|
||||
CMD /ZoneMinder/utils/docker/setup.sh && /ZoneMinder/utils/docker/start.sh >/var/log/start.log 2>&1 & /bin/bash
|
||||
|
||||
# Run example docker run -it -p 1080:80 -e PHP_TIMEZONE='Europe/Paris' -v /disk/zoneminder/events:/var/lib/zoneminder/events -v /disk/zoneminder/images:/var/lib/zoneminder/images -v /disk/zoneminder/mysql:/var/lib/mysql -v /disk/zoneminder/logs:/var/log/zm --name zoneminder zoneminder/zoneminder
|
|
@ -13,6 +13,10 @@ ZoneMinder is an integrated set of applications which provide a complete surveil
|
|||
Before creating an issue in our github forum, please read our posting rules:
|
||||
https://github.com/ZoneMinder/ZoneMinder/wiki/Github-Posting-Rules
|
||||
|
||||
## Our Dockerfile has moved
|
||||
Please file issues against the ZoneMinder Dockerfile here:
|
||||
https://github.com/ZoneMinder/zmdockerfiles
|
||||
|
||||
## Installation Methods
|
||||
|
||||
### Building from Source is Discouraged
|
||||
|
@ -31,6 +35,8 @@ This is the recommended method to install ZoneMinder onto your system. ZoneMinde
|
|||
- Fedora via [RPM Fusion](http://rpmfusion.org)
|
||||
- OpenSuse via [third party repository](http://www.zoneminder.com/wiki/index.php/Installing_using_ZoneMinder_RPMs_for_SuSE)
|
||||
- Mageia from their default repository
|
||||
- Arch via the [AUR](https://aur.archlinux.org/packages/zoneminder/)
|
||||
- Gentoo from their [default repository](https://packages.gentoo.org/packages/www-misc/zoneminder)
|
||||
|
||||
If a repository that hosts ZoneMinder packages is not available for your distro, then you are encouraged to build your own package, rather than build from source. While each distro is different in ways that set it apart from all the others, they are often similar enough to allow you to adapt another distro's package building instructions to your own.
|
||||
|
||||
|
|
|
@ -291,7 +291,7 @@ CREATE TABLE `MonitorPresets` (
|
|||
`Name` varchar(64) NOT NULL default '',
|
||||
`Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL') NOT NULL default 'Local',
|
||||
`Device` tinytext,
|
||||
`Channel` tinytext,
|
||||
`Channel` tinyint(3) unsigned default NULL,
|
||||
`Format` int(10) unsigned default NULL,
|
||||
`Protocol` varchar(16) default NULL,
|
||||
`Method` varchar(16) default NULL,
|
||||
|
@ -597,77 +597,81 @@ INSERT INTO `Controls` VALUES (NULL,'Foscam 9831W','Ffmpeg','FI9831W',0,0,1,0,0,
|
|||
INSERT INTO `Controls` VALUES (NULL,'Foscam FI8918W','Ffmpeg','FI8918W',0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,8,0,1,1,1,0,0,0,1,1,0,360,0,360,1,0,4,0,0,1,0,90,0,90,1,0,4,0,0,0,0);
|
||||
INSERT INTO `Controls` VALUES (NULL,'SunEyes SP-P1802SWPTZ','Libvlc','SPP1802SWPTZ',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,8,0,1,1,0,0,0,0,1,1,0,0,0,0,1,0,64,0,0,1,0,0,0,0,1,0,64,0,0,0,0);
|
||||
INSERT INTO `Controls` VALUES (NULL,'Wanscam HW0025','Libvlc','WanscamHW0025', 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 16, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 350, 0, 0, 1, 0, 10, 0, 0, 1, 0, 0, 0, 0, 1, 0, 10, 0, 0, 0, 0);
|
||||
INSERT INTO `Controls` VALUES (NULL,'IPCC 7210W','Libvlc','IPCC7210W', 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 16, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 350, 0, 0, 1, 0, 10, 0, 0, 1, 0, 0, 0, 0, 1, 0, 10, 0, 0, 0, 0);
|
||||
INSERT INTO `Controls` VALUES (NULL,'IPCC 7210W','Remote','IPCC7210W', 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 16, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
INSERT INTO `Controls` VALUES (NULL,'Vivotek ePTZ','Remote','Vivotek_ePTZ',0,0,1,1,0,0,0,1,0,0,0,0,1,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,1,0,5,0,0,1,0,0,0,0,1,0,5,0,0,0,0);
|
||||
INSERT INTO `Controls` VALUES (NULL,'Netcat ONVIF','Ffmpeg','Netcat',0,0,1,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,100,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,100,5,5,0,0,0,1,255,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO `Controls` VALUES (NULL,'Keekoon','Remote','Keekoon', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 6, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
INSERT INTO `Controls` VALUES (NULL,'HikVision','Local','',0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,20,1,1,1,1,0,0,0,1,1,0,0,0,0,1,1,100,0,0,1,0,0,0,0,1,1,100,1,0,0,0);
|
||||
INSERT INTO `Controls` VALUES (NULL,'Maginon Supra IPC','cURL','MaginonIPC',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,0,1,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO `Controls` VALUES (NULL,'Floureon 1080P','Ffmpeg','Floureon',0,0,0,1,0,0,0,1,1,18,1,1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,20,0,1,1,1,0,0,0,1,1,0,0,0,0,1,1,8,0,0,1,0,0,0,0,1,1,8,0,0,0,0);
|
||||
INSERT INTO `Controls` VALUES (NULL,'Reolink RLC-423','Ffmpeg','Reolink',0,0,1,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,64,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO `Controls` VALUES (NULL,'Reolink RLC-411','Ffmpeg','Reolink',0,0,1,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO `Controls` VALUES (NULL,'Reolink RLC-420','Ffmpeg','Reolink',0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
|
||||
--
|
||||
-- Add some monitor preset values
|
||||
--
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, mpjpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, mpjpeg, max 5 FPS','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240&req_fps=5',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, jpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, jpeg, max 5 FPS','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 640x480, mpjpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 640x480, mpjpeg, max 5 FPS','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480&req_fps=5',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 640x480, jpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 640x480, jpeg, max 5 FPS','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, mpjpeg, B&W','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240&color=0',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 640x480, mpjpeg, B&W','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480&color=0',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 320x240, mpjpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240',NULL,320,240,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 320x240, mpjpeg, max 5 FPS','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240&req_fps=5',NULL,320,240,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 320x240, jpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 320x240, jpeg, max 5 FPS','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,5.0,1,4,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 640x480, mpjpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480',NULL,640,480,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 640x480, mpjpeg, max 5 FPS','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480&req_fps=5',NULL,640,480,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 640x480, jpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 640x480, jpeg, max 5 FPS','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,5.0,1,4,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT into MonitorPresets VALUES (NULL,'Axis IP, mpeg4, unicast','Remote','rtsp','rtpUni',NULL,NULL,NULL,'<ip-address>',554,'/mpeg4/media.amp','/trackID=',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT into MonitorPresets VALUES (NULL,'Axis IP, mpeg4, multicast','Remote','rtsp','rtpMulti',NULL,NULL,NULL,'<ip-address>',554,'/mpeg4/media.amp','/trackID=',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT into MonitorPresets VALUES (NULL,'Axis IP, mpeg4, RTP/RTSP','Remote','rtsp','rtpRtsp',NULL,NULL,NULL,'<ip-address>',554,'/mpeg4/media.amp','/trackID=',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, mpjpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240&req_fps=5',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 640x480, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 640x480, mpjpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480&req_fps=5',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 640x480, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 640x480, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 320x240, mpjpeg, B&W','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240&color=0',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP, 640x480, mpjpeg, B&W','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480&color=0',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 320x240, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240',NULL,320,240,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 320x240, mpjpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=320x240&req_fps=5',NULL,320,240,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 320x240, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 320x240, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=320x240',NULL,320,240,3,5.0,1,4,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 640x480, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480',NULL,640,480,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 640x480, mpjpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/mjpg/video.cgi?resolution=640x480&req_fps=5',NULL,640,480,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 640x480, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,NULL,1,4,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis IP PTZ, 640x480, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/axis-cgi/jpg/image.cgi?resolution=640x480',NULL,640,480,3,5.0,1,4,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT into MonitorPresets VALUES (NULL,'Axis IP, mpeg4, unicast','Remote','rtsp',0,255,'rtsp','rtpUni','<ip-address>',554,'/mpeg4/media.amp','/trackID=',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT into MonitorPresets VALUES (NULL,'Axis IP, mpeg4, multicast','Remote','rtsp',0,255,'rtsp','rtpMulti','<ip-address>',554,'/mpeg4/media.amp','/trackID=',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT into MonitorPresets VALUES (NULL,'Axis IP, mpeg4, RTP/RTSP','Remote','rtsp',0,255,'rtsp','rtpRtsp','<ip-address>',554,'/mpeg4/media.amp','/trackID=',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT into MonitorPresets VALUES (NULL,'Axis IP, mpeg4, RTP/RTSP/HTTP','Remote',NULL,NULL,NULL,'rtsp','rtpRtspHttp','<ip-address>',554,'/mpeg4/media.amp','/trackID=',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 320x240, mpjpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/nphMotionJpeg?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 320x240, jpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 320x240, jpeg, max 5 FPS','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 640x480, mpjpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/nphMotionJpeg?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 640x480, jpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 640x480, jpeg, max 5 FPS','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 320x240, mpjpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/nphMotionJpeg?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,1,5,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 320x240, jpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,1,5,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 320x240, jpeg, max 5 FPS','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,5.0,1,5,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 640x480, mpjpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/nphMotionJpeg?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,1,5,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 640x480, jpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,1,5,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 640x480, jpeg, max 5 FPS','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,5.0,1,5,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Gadspot IP, jpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/Jpeg/CamImg.jpg',NULL,NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Gadspot IP, jpeg, max 5 FPS','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/Jpeg/CamImg.jpg',NULL,NULL,NULL,3,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Gadspot IP, mpjpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/GetData.cgi',NULL,NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Gadspot IP, mpjpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/Jpeg/CamImg.jpg',NULL,NULL,NULL,3,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'VEO Observer, jpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/Jpeg/CamImg.jpg',NULL,NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Blue Net Video Server, jpeg','Remote','http','simple',NULL,NULL,NULL,'<ip-address>',80,'/cgi-bin/image.cgi?control=0&id=admin&passwd=admin',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 320x240, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/nphMotionJpeg?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 320x240, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 320x240, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 640x480, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/nphMotionJpeg?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 640x480, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP, 640x480, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 320x240, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/nphMotionJpeg?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,1,5,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 320x240, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,NULL,1,5,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 320x240, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=320x240&Quality=Standard',NULL,320,240,3,5.0,1,5,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 640x480, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/nphMotionJpeg?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,1,5,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 640x480, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,NULL,1,5,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Panasonic IP PTZ, 640x480, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/SnapshotJPEG?Resolution=640x480&Quality=Standard',NULL,640,480,3,5.0,1,5,NULL,'<ip-address>:<port>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Gadspot IP, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/Jpeg/CamImg.jpg',NULL,NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Gadspot IP, jpeg, max 5 FPS','Remote','http',0,0,'http','simple','<ip-address>',80,'/Jpeg/CamImg.jpg',NULL,NULL,NULL,3,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Gadspot IP, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/GetData.cgi',NULL,NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Gadspot IP, mpjpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/Jpeg/CamImg.jpg',NULL,NULL,NULL,3,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'VEO Observer, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/Jpeg/CamImg.jpg',NULL,NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Blue Net Video Server, jpeg','Remote','http',0,0,'http','simple','<ip-address>',80,'/cgi-bin/image.cgi?control=0&id=admin&passwd=admin',NULL,320,240,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT into MonitorPresets VALUES (NULL,'ACTi IP, mpeg4, unicast','Remote',NULL,NULL,NULL,'rtsp','rtpUni','<ip-address>',7070,'','/track',NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis FFMPEG H.264','Ffmpeg',NULL,NULL,NULL,NULL,NULL,'rtsp://<host/address>/axis-media/media.amp?videocodec=h264',NULL,NULL,NULL,640,480,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Vivotek FFMPEG','Ffmpeg',NULL,NULL,NULL,NULL,NULL,'rtsp://<host/address>:554/live.sdp',NULL,NULL,NULL,352,240,NULL,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Axis FFMPEG','Ffmpeg',NULL,NULL,NULL,NULL,NULL,'rtsp://<host/address>/axis-media/media.amp',NULL,NULL,NULL,640,480,NULL,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'ACTi TCM FFMPEG','Ffmpeg',NULL,NULL,NULL,NULL,NULL,'rtsp://admin:123456@<host/address>:7070',NULL,NULL,NULL,320,240,NULL,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), PAL, 320x240','Local','/dev/video<?>','<?>',255,NULL,'v4l2',NULL,NULL,NULL,NULL,320,240,1345466932,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), PAL, 320x240, max 5 FPS','Local','/dev/video<?>','<?>',255,NULL,'v4l2',NULL,NULL,NULL,NULL,320,240,1345466932,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), PAL, 640x480','Local','/dev/video<?>','<?>',255,NULL,'v4l2',NULL,NULL,NULL,NULL,640,480,1345466932,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), PAL, 640x480, max 5 FPS','Local','/dev/video<?>','<?>',255,NULL,'v4l2',NULL,NULL,NULL,NULL,640,480,1345466932,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), NTSC, 320x240','Local','/dev/video<?>','<?>',45056,NULL,'v4l2',NULL,NULL,NULL,NULL,320,240,1345466932,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), NTSC, 320x240, max 5 FPS','Local','/dev/video<?>','<?>',45056,NULL,'v4l2',NULL,NULL,NULL,NULL,320,240,1345466932,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), NTSC, 640x480','Local','/dev/video<?>','<?>',45056,NULL,'v4l2',NULL,NULL,NULL,NULL,640,480,1345466932,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), NTSC, 640x480, max 5 FPS','Local','/dev/video<?>','<?>',45056,NULL,'v4l2',NULL,NULL,NULL,NULL,640,480,1345466932,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), PAL, 320x240','Local','/dev/video<?>','<?>',0,NULL,'v4l1',NULL,NULL,NULL,NULL,320,240,13,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), PAL, 320x240, max 5 FPS','Local','/dev/video<?>','<?>',0,NULL,'v4l1',NULL,NULL,NULL,NULL,320,240,13,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), PAL, 640x480','Local','/dev/video<?>','<?>',0,NULL,'v4l1',NULL,NULL,NULL,NULL,640,480,13,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), PAL, 640x480, max 5 FPS','Local','/dev/video<?>','<?>',0,NULL,'v4l1',NULL,NULL,NULL,NULL,640,480,13,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), NTSC, 320x240','Local','/dev/video<?>','<?>',1,NULL,'v4l1',NULL,NULL,NULL,NULL,320,240,13,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), NTSC, 320x240, max 5 FPS','Local','/dev/video<?>','<?>',1,NULL,'v4l1',NULL,NULL,NULL,NULL,320,240,13,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), NTSC, 640x480','Local','/dev/video<?>','<?>',1,NULL,'v4l1',NULL,NULL,NULL,NULL,640,480,13,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), NTSC, 640x480, max 5 FPS','Local','/dev/video<?>','<?>',1,NULL,'v4l1',NULL,NULL,NULL,NULL,640,480,13,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), PAL, 320x240','Local','/dev/video<?>',0,255,NULL,'v4l2',NULL,NULL,NULL,NULL,320,240,1345466932,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), PAL, 320x240, max 5 FPS','Local','/dev/video<?>',0,255,NULL,'v4l2',NULL,NULL,NULL,NULL,320,240,1345466932,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), PAL, 640x480','Local','/dev/video<?>',0,255,NULL,'v4l2',NULL,NULL,NULL,NULL,640,480,1345466932,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), PAL, 640x480, max 5 FPS','Local','/dev/video<?>',0,255,NULL,'v4l2',NULL,NULL,NULL,NULL,640,480,1345466932,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), NTSC, 320x240','Local','/dev/video<?>',0,45056,NULL,'v4l2',NULL,NULL,NULL,NULL,320,240,1345466932,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), NTSC, 320x240, max 5 FPS','Local','/dev/video<?>',0,45056,NULL,'v4l2',NULL,NULL,NULL,NULL,320,240,1345466932,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), NTSC, 640x480','Local','/dev/video<?>',0,45056,NULL,'v4l2',NULL,NULL,NULL,NULL,640,480,1345466932,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L2), NTSC, 640x480, max 5 FPS','Local','/dev/video<?>',0,45056,NULL,'v4l2',NULL,NULL,NULL,NULL,640,480,1345466932,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), PAL, 320x240','Local','/dev/video<?>',0,0,NULL,'v4l1',NULL,NULL,NULL,NULL,320,240,13,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), PAL, 320x240, max 5 FPS','Local','/dev/video<?>',0,0,NULL,'v4l1',NULL,NULL,NULL,NULL,320,240,13,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), PAL, 640x480','Local','/dev/video<?>',0,0,NULL,'v4l1',NULL,NULL,NULL,NULL,640,480,13,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), PAL, 640x480, max 5 FPS','Local','/dev/video<?>',0,0,NULL,'v4l1',NULL,NULL,NULL,NULL,640,480,13,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), NTSC, 320x240','Local','/dev/video<?>',0,1,NULL,'v4l1',NULL,NULL,NULL,NULL,320,240,13,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), NTSC, 320x240, max 5 FPS','Local','/dev/video<?>',0,1,NULL,'v4l1',NULL,NULL,NULL,NULL,320,240,13,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), NTSC, 640x480','Local','/dev/video<?>',0,1,NULL,'v4l1',NULL,NULL,NULL,NULL,640,480,13,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'BTTV Video (V4L1), NTSC, 640x480, max 5 FPS','Local','/dev/video<?>',0,1,NULL,'v4l1',NULL,NULL,NULL,NULL,640,480,13,5.0,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Remote ZoneMinder','Remote',NULL,NULL,NULL,'http','simple','<ip-address>',80,'/cgi-bin/nph-zms?mode=jpeg&monitor=<monitor-id>&scale=100&maxfps=5&buffer=0',NULL,NULL,NULL,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Foscam FI8620 FFMPEG H.264','Ffmpeg',NULL,NULL,NULL,NULL,'','','','rtsp://<username>:<pwd>@<ip-address>:554/11',NULL,704,576,0,NULL,1,'10','<admin_pwd>','<ip-address>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Foscam FI8608W FFMPEG H.264','Ffmpeg',NULL,NULL,NULL,NULL,'','','','rtsp://<username>:<pwd>@<ip-address>:554/11',NULL,640,480,0,NULL,1,'11','<admin_pwd>','<ip-address>',100,100);
|
||||
|
@ -675,8 +679,8 @@ INSERT INTO MonitorPresets VALUES (NULL,'Foscam FI9821W FFMPEG H.264','Ffmpeg',N
|
|||
INSERT INTO MonitorPresets VALUES (NULL,'Loftek Sentinel PTZ, 640x480, mjpeg','Remote','http',0,0,NULL,NULL,'<ip-address>','80','/videostream.cgi?user=<username>&pwd=<password>&resolution=32&rate=11',NULL,640,480,4,NULL,1,'13','','<username>:<pwd>@<ip-address>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Airlink 777W PTZ, 640x480, mjpeg','Remote','http',0,0,NULL,NULL,'<username>:<password>@<ip-address>','80','/cgi/mjpg/mjpg.cgi',NULL,640,480,4,NULL,1,'7','','<username>:<pwd>@<ip-address>',100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'SunEyes SP-P1802SWPTZ','Libvlc','/dev/video<?>','0',255,'','rtpMulti','','80','rtsp://<ip-address>:554/11','',1920,1080,0,0.00,1,'16','-speed=64','<ip-address>:<port>',100,33);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Qihan IP, 1280x720, RTP/RTSP','Ffmpeg','rtsp','rtpRtsp',255,'rtsp','rtpRtsp',NULL,554,'rtsp://<ip-address>/tcp_live/ch0_0',NULL,1280,720,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Qihan IP, 1920x1080, RTP/RTSP','Ffmpeg','rtsp','rtpRtsp',255,'rtsp','rtpRtsp',NULL,554,'rtsp://<ip-address>/tcp_live/ch0_0',NULL,1920,1080,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Qihan IP, 1280x720, RTP/RTSP','Ffmpeg','rtsp',0,255,'rtsp','rtpRtsp',NULL,554,'rtsp://<ip-address>/tcp_live/ch0_0',NULL,1280,720,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
INSERT INTO MonitorPresets VALUES (NULL,'Qihan IP, 1920x1080, RTP/RTSP','Ffmpeg','rtsp',0,255,'rtsp','rtpRtsp',NULL,554,'rtsp://<ip-address>/tcp_live/ch0_0',NULL,1920,1080,3,NULL,0,NULL,NULL,NULL,100,100);
|
||||
|
||||
--
|
||||
-- Add some zone preset values
|
||||
|
|
|
@ -83,6 +83,10 @@ BuildRequires: libcurl-devel
|
|||
BuildRequires: libv4l-devel
|
||||
BuildRequires: ffmpeg-devel
|
||||
|
||||
# Required for mp4 container support
|
||||
BuildRequires: libmp4v2-devel
|
||||
BuildRequires: x264-devel
|
||||
|
||||
%{?with_nginx:Requires: nginx}
|
||||
%{?with_nginx:Requires: fcgiwrap}
|
||||
%{?with_nginx:Requires: php-fpm}
|
||||
|
@ -110,6 +114,7 @@ Requires: perl(Net::SMTP)
|
|||
Requires: perl(Net::FTP)
|
||||
Requires: perl(LWP::Protocol::https)
|
||||
Requires: ca-certificates
|
||||
Requires: zip
|
||||
|
||||
%{?with_init_systemd:Requires(post): systemd}
|
||||
%{?with_init_systemd:Requires(post): systemd-sysv}
|
||||
|
|
|
@ -6,7 +6,6 @@ Uploaders: Vagrant Cascadian <vagrant@debian.org>
|
|||
Build-Depends: debhelper (>= 9), python-sphinx | python3-sphinx, apache2-dev, dh-linktree
|
||||
,cmake
|
||||
,libavcodec-dev, libavformat-dev (>= 3:0.svn20090204), libswscale-dev (>= 3:0.svn20090204), libavutil-dev, libavdevice-dev
|
||||
,libboost1.55-dev
|
||||
,libbz2-dev
|
||||
,libgcrypt-dev
|
||||
,libcurl4-gnutls-dev
|
||||
|
|
|
@ -38,6 +38,10 @@ if [ "$1" = "configure" ]; then
|
|||
|
||||
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
|
||||
|
|
|
@ -73,6 +73,9 @@ if [ "$dbc_install" = "true" ] && [ "$1" = "configure" ]; then
|
|||
# Run the ZoneMinder update tool
|
||||
zmupdate.pl --nointeractive
|
||||
|
||||
# Add any new PTZ control configurations to the database (will not overwrite)
|
||||
zmcamtool.pl --import >/dev/null 2>&1
|
||||
|
||||
fi
|
||||
|
||||
#DEBHELPER#
|
||||
|
|
|
@ -6,7 +6,6 @@ Uploaders: Vagrant Cascadian <vagrant@debian.org>
|
|||
Build-Depends: debhelper (>= 9), dh-systemd, python-sphinx | python3-sphinx, apache2-dev, dh-linktree
|
||||
,cmake
|
||||
,libx264-dev, libmp4v2-dev
|
||||
,libboost-dev
|
||||
,libavdevice-dev (>= 6:10~)
|
||||
,libavcodec-dev (>= 6:10~)
|
||||
,libavformat-dev (>= 6:10~)
|
||||
|
@ -17,7 +16,7 @@ Build-Depends: debhelper (>= 9), dh-systemd, python-sphinx | python3-sphinx, apa
|
|||
,libcurl4-gnutls-dev
|
||||
,libgnutls-openssl-dev
|
||||
,libjpeg8-dev | libjpeg9-dev | libjpeg62-turbo-dev
|
||||
,libmysqlclient-dev
|
||||
,default-libmysqlclient-dev | libmysqlclient-dev
|
||||
,libpcre3-dev
|
||||
,libpolkit-gobject-1-dev
|
||||
,libv4l-dev (>= 0.8.3) [!hurd-any]
|
||||
|
|
|
@ -47,6 +47,10 @@ if [ "$1" = "configure" ]; then
|
|||
|
||||
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
|
||||
|
|
33
docs/faq.rst
33
docs/faq.rst
|
@ -71,22 +71,22 @@ The 1.2 at the start is basically adding 20% on top of the calculation to accoun
|
|||
|
||||
The math breakdown for 4 cameras running at 1280x960 capture, 50 frame buffer, 24 bit color space:
|
||||
::
|
||||
1280*960 = 1,228,800 (bits)
|
||||
1,228,800 * 24 = 2,359,296,000 (bits)
|
||||
2,359,296,000 * 50 = 5,898,240,000 (bits)
|
||||
5,898,240,000 * 4 = 7,077,888,000 (bits)
|
||||
7,077,888,000 / 8 = 884,736,000 (bytes)
|
||||
884,736,000 / 1000 = 884,736 (Kilobytes)
|
||||
884,736 / 1000 = 864 (Megabytes)
|
||||
864 / 1000 = 0.9 (Gigabyte)
|
||||
1280*960 = 1,228,800 (bytes)
|
||||
1,228,800 * (3 bytes for 24 bit) = 3,686,400 (bytes)
|
||||
3,686,400 * 50 = 184,320,000 (bytes)
|
||||
184,320,000 * 4 = 737,280,000 (bytes)
|
||||
737,280,000 / 1024 = 720,000 (Kilobytes)
|
||||
720,000 / 1024 = 703.125 (Megabytes)
|
||||
703.125 / 1024 = 0.686 (Gigabytes)
|
||||
|
||||
Around 900MB of memory.
|
||||
Around 700MB of memory.
|
||||
|
||||
So if you have 2GB of memory, you should be all set. Right? **Not, really**:
|
||||
|
||||
* This is just the base memory required to capture the streams. Remember ZM is always capturing streams irrespective of whether you are actually recording or not - to make sure its image ring buffer is there with pre images when an alarm kicks in.
|
||||
* You also need to account for other processes not related to ZM running in your box
|
||||
* You also need to account for other ZM processes - for example, I noticed the audit daemon takes up a good amount of memory when it runs, DB updates also take up memory
|
||||
* If you are using H264 encoding, that buffers a lot of frames in memory as well.
|
||||
|
||||
So a good rule of thumb is to make sure you have twice the memory as the calculation above (and if you are using the ZM server for other purposes, please factor in those memory requirements as well)
|
||||
|
||||
|
@ -128,15 +128,14 @@ So, for example:
|
|||
::
|
||||
|
||||
384x288 capture resolution, that makes: 110 592 pixels
|
||||
in 24 bit color that's x24 = 2 654 208 bits per frame
|
||||
by 80 frames ring buffer x80 = 212 336 640 bits per camera
|
||||
by 4 cameras x4 = 849 346 560 bits.
|
||||
Plus 10% overhead = 934 281 216 bits
|
||||
That's 116 785 152 bytes, and
|
||||
= 114 048 kB, respectively 111.38 MB.
|
||||
If my shared memory is set to 134 217 728, which is exactly 128MB,
|
||||
in 24 bit color that's x 3 = 331,776 bytes per frame
|
||||
by 80 frames ring buffer x80 = 26,542,080 bytes per camera
|
||||
by 4 cameras x4 = 106,168,320 bytes.
|
||||
Plus 10% overhead = 116,785,152 bytes
|
||||
Thats 114,048 kB, respectively 111.38 MB.
|
||||
If my shared memory is set to 134,217,728, which is exactly 128MB,
|
||||
that means I shouldn't have any problem.
|
||||
(Note that 1 byte = 8 bits and 1kbyte = 1024bytes, 1MB = 1024 kB)
|
||||
(Note that 1kbyte = 1024bytes, 1MB = 1024 kB)
|
||||
|
||||
If for instance you were using 24bit 640x480 then this would come to about 92Mb if you are using the default buffer size of 100. If this is too large then you can either reduce the image or buffer sizes or increase the maximum amount of shared memory available. If you are using RedHat then you can get details on how to change these settings `here <http://www.redhat.com/docs/manuals/database/RHDB-2.1-Manual/admin_user/kernel-resources.html>`__
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
All Distros - A Simpler Way to Build ZoneMinder
|
||||
All Distros - A Docker Way to Build ZoneMinder
|
||||
===============================================
|
||||
|
||||
.. contents::
|
||||
|
@ -27,6 +27,8 @@ Procedure
|
|||
|
||||
- If the desired distro does not appear in either list, then unfortuantely you cannot use the procedure described here.
|
||||
|
||||
- If the desired distro architecture is arm, refer to `Appendix A - Enable Qemu On the Host`_ to enable qemu emulation on your amd64 host machine.
|
||||
|
||||
**Step 2:** Install Docker.
|
||||
|
||||
You need to have a working installation of Docker so head over to the `Docker site <https://docs.docker.com/engine/installation/>`_ and get it working. Before continuing to the next step, verify you can run the Docker "Hello World" container as a normal user. To run a Docker container as a normal user, issue the following:
|
||||
|
@ -44,7 +46,7 @@ Clone the ZoneMinder project if you have not done so already.
|
|||
|
||||
::
|
||||
|
||||
git clone ZoneMinder
|
||||
git clone https://github.com/ZoneMinder/ZoneMinder
|
||||
cd ZoneMinder
|
||||
|
||||
Alternatively, if you have already cloned the repo and wish to update it, do the following.
|
||||
|
@ -99,7 +101,27 @@ For advanced users who really want to go out into uncharted waters, it is theore
|
|||
|
||||
Building arm packages in this manner has not been tested by us, however.
|
||||
|
||||
Appendix A - Enable Qemu On the Host
|
||||
------------------------------------
|
||||
|
||||
If you intend to build ZoneMinder packages for arm on an amd64 host, then Debian users can following these steps to enable transparent Qemu emulation:
|
||||
|
||||
::
|
||||
|
||||
sudo apt-get install binfmt-support qemu qemu-user-static
|
||||
|
||||
Verify arm emulation is enabled by issuing:
|
||||
|
||||
::
|
||||
|
||||
sudo update-binfmts --enable qemu-arm
|
||||
|
||||
You may get a message stating emulation for this processor is already enabled.
|
||||
|
||||
More testing needs to be done for Redhat distros but it appears Fedora users can just run:
|
||||
|
||||
::
|
||||
|
||||
sudo systemctl start systemd-binfmt
|
||||
|
||||
TO-DO: Verify the details behind enabling qemu emulation on redhat distros. Pull requests are welcome.
|
||||
|
|
|
@ -15,9 +15,11 @@ achieve the same result by running:
|
|||
|
||||
::
|
||||
|
||||
tasksel install lamp-server
|
||||
sudo tasksel install lamp-server
|
||||
|
||||
During installation it will ask you to set up a master/root password for the MySQL.
|
||||
Installing LAMP is not ZoneMinder specific so you will find plenty of resources to
|
||||
guide you with a quick search.
|
||||
|
||||
**Step 1:** Either run commands in this install using sudo or use the below to become root
|
||||
::
|
||||
|
@ -28,9 +30,14 @@ During installation it will ask you to set up a master/root password for the MyS
|
|||
|
||||
.. topic :: Latest Release
|
||||
|
||||
ZoneMinder 1.29.0 is now part of the current standard Ubuntu repository. But
|
||||
if you wish to install the later releases of ZoneMinder you will need
|
||||
to add the iconnor/zoneminder PPA.
|
||||
ZoneMinder is now part of the current standard Ubuntu repository, but
|
||||
sometimes the official repository can lag behind. To find out check our
|
||||
`releases page <https://github.com/ZoneMinder/zoneminder/releases>`_ for
|
||||
the latest release.
|
||||
|
||||
Alternatively, the ZoneMinder project team maintains a ppa, which is updated immediately
|
||||
following a new release of ZoneMinder. To use this repository instead of the
|
||||
official Ubuntu repository, enter the following from the command line:
|
||||
|
||||
::
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
ServerAdmin webmaster@localhost
|
||||
|
||||
DocumentRoot "@WEB_PREFIX@"
|
||||
Alias /zm/ "@WEB_PREFIX@/"
|
||||
Alias /zm "@WEB_PREFIX@"
|
||||
<Directory "@WEB_PREFIX@">
|
||||
Options -Indexes +FollowSymLinks
|
||||
AllowOverride All
|
||||
|
|
|
@ -0,0 +1,390 @@
|
|||
# Modified on 2017-11-17 by Ognyan Bankov
|
||||
|
||||
# ==========================================================================
|
||||
#
|
||||
# ZoneMinder Floureon 1080p IP Control Protocol Module, $Date: 2017-11-17 09:20:00 +0000 $, $Revision: 0001 $
|
||||
# Copyright (C) 2017 Ognyan Bankov
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This module contains the implementation of the Floureon 1080p 18x (Model: BT-HD54F) IP camera control
|
||||
# protocol. It should work with other Floureon cameras too.
|
||||
#
|
||||
#
|
||||
|
||||
package MyAgent;
|
||||
|
||||
use base 'LWP::UserAgent';
|
||||
|
||||
|
||||
package ZoneMinder::Control::Floureon;
|
||||
|
||||
use 5.006;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
require ZoneMinder::Base;
|
||||
require ZoneMinder::Control;
|
||||
|
||||
our @ISA = qw(ZoneMinder::Control);
|
||||
|
||||
our $VERSION = $ZoneMinder::Base::VERSION;
|
||||
|
||||
# ==========================================================================
|
||||
#
|
||||
# Floureon IP Control Protocol
|
||||
#
|
||||
# ==========================================================================
|
||||
|
||||
use ZoneMinder::Logger qw(:all);
|
||||
use ZoneMinder::Config qw(:all);
|
||||
|
||||
use Time::HiRes qw( usleep );
|
||||
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my $id = shift;
|
||||
my $self = ZoneMinder::Control->new( $id );
|
||||
my $logindetails = "";
|
||||
bless( $self, $class );
|
||||
srand( time() );
|
||||
return $self;
|
||||
}
|
||||
|
||||
our $AUTOLOAD;
|
||||
|
||||
sub AUTOLOAD
|
||||
{
|
||||
my $self = shift;
|
||||
my $class = ref($self) || croak( "$self not object" );
|
||||
my $name = $AUTOLOAD;
|
||||
$name =~ s/.*://;
|
||||
if ( exists($self->{$name}) )
|
||||
{
|
||||
return( $self->{$name} );
|
||||
}
|
||||
Fatal( "Can't access $name member of object of class $class" );
|
||||
}
|
||||
our $stop_command;
|
||||
|
||||
sub open
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
$self->loadMonitor();
|
||||
|
||||
$self->{ua} = MyAgent->new;
|
||||
$self->{ua}->agent( "ZoneMinder Control Agent/" );
|
||||
|
||||
$self->{state} = 'open';
|
||||
}
|
||||
|
||||
sub close
|
||||
{
|
||||
my $self = shift;
|
||||
$self->{state} = 'closed';
|
||||
}
|
||||
|
||||
sub printMsg
|
||||
{
|
||||
my $self = shift;
|
||||
my $msg = shift;
|
||||
my $msg_len = length($msg);
|
||||
|
||||
Debug( $msg."[".$msg_len."]" );
|
||||
}
|
||||
|
||||
sub sendCmd
|
||||
{
|
||||
my $self = shift;
|
||||
my $cmd = shift;
|
||||
my $result = undef;
|
||||
printMsg( $cmd, "Tx" );
|
||||
|
||||
my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$cmd"."&".$self->{Monitor}->{ControlDevice});
|
||||
print ("Sending $req\n");
|
||||
my $res = $self->{ua}->request($req);
|
||||
if ( $res->is_success )
|
||||
{
|
||||
$result = !undef;
|
||||
}
|
||||
else
|
||||
{
|
||||
Error( "Error REALLY check failed:'".$res->status_line()."'" );
|
||||
Error ("Cmd:".$req);
|
||||
}
|
||||
|
||||
return( $result );
|
||||
}
|
||||
|
||||
sub reset
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Camera Reset" );
|
||||
my $cmd = "reboot.cgi?";
|
||||
$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
# PP - in all move operations, added auto stop after timeout
|
||||
|
||||
#Up Arrow
|
||||
sub moveConUp
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
|
||||
Debug( "Move Up" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Direction=1&PanSpeed=6&TiltSpeed=$tiltspeed";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop($tiltspeed);
|
||||
}
|
||||
|
||||
#Down Arrow
|
||||
sub moveConDown
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
|
||||
Debug( "Move Down" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Direction=2&PanSpeed=6&TiltSpeed=$tiltspeed";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop($tiltspeed);
|
||||
}
|
||||
|
||||
#Left Arrow
|
||||
sub moveConLeft
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $panspeed = $self->getParam( $params, 'panspeed' );
|
||||
|
||||
Debug( "Move Left" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Direction=3&PanSpeed=$panspeed&TiltSpeed=6";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop($panspeed);
|
||||
}
|
||||
|
||||
#Right Arrow
|
||||
sub moveConRight
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $panspeed = $self->getParam( $params, 'panspeed' );
|
||||
Debug( "Move Right" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Direction=4&PanSpeed=$panspeed&TiltSpeed=6";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop($panspeed);
|
||||
}
|
||||
|
||||
#Diagonally Up Right Arrow
|
||||
sub moveConUpRight
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $panspeed = $self->getParam( $params, 'panspeed' );
|
||||
my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
|
||||
Debug( "Move Diagonally Up Right" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Direction=7&PanSpeed=$panspeed&TiltSpeed=$tiltspeed";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop($tiltspeed);
|
||||
|
||||
}
|
||||
|
||||
#Diagonally Down Right Arrow
|
||||
sub moveConDownRight
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $panspeed = $self->getParam( $params, 'panspeed' );
|
||||
my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
|
||||
Debug( "Move Diagonally Down Right" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Direction=8&PanSpeed=$panspeed&TiltSpeed=$tiltspeed";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop($tiltspeed);
|
||||
}
|
||||
|
||||
#Diagonally Up Left Arrow
|
||||
sub moveConUpLeft
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $panspeed = $self->getParam( $params, 'panspeed' );
|
||||
my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
|
||||
Debug( "Move Diagonally Up Left" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Direction=5&PanSpeed=$panspeed&TiltSpeed=$tiltspeed";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop($tiltspeed);
|
||||
}
|
||||
|
||||
#Diagonally Down Left Arrow
|
||||
sub moveConDownLeft
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $panspeed = $self->getParam( $params, 'panspeed' );
|
||||
my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
|
||||
Debug( "Move Diagonally Down Left" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Direction=6&PanSpeed=$panspeed&TiltSpeed=$tiltspeed";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop($tiltspeed);
|
||||
}
|
||||
|
||||
#Stop
|
||||
sub moveStop
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Move Stop" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Stop=0";
|
||||
$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
|
||||
sub zoomConTele
|
||||
{
|
||||
my $self = shift;
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Zoom=1";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop();
|
||||
}
|
||||
|
||||
|
||||
sub zoomConWide
|
||||
{
|
||||
my $self = shift;
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Zoom=0";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop();
|
||||
}
|
||||
|
||||
|
||||
sub focusConNear
|
||||
{
|
||||
my $self = shift;
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Focus=1";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop();
|
||||
}
|
||||
|
||||
|
||||
sub focusConFar
|
||||
{
|
||||
my $self = shift;
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Focus=0";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop();
|
||||
}
|
||||
|
||||
|
||||
sub irisConOpen
|
||||
{
|
||||
my $self = shift;
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Iris=1";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop();
|
||||
}
|
||||
|
||||
|
||||
sub irisConClose
|
||||
{
|
||||
my $self = shift;
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Iris=0";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop();
|
||||
}
|
||||
|
||||
|
||||
#Set preset
|
||||
sub presetSet
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $preset = $self->getParam( $params, 'preset' );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&PresetNumber=1&Preset=0";
|
||||
$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
|
||||
#Goto preset
|
||||
sub presetGoto
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $preset = $self->getParam( $params, 'preset' );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&PresetNumber=1&Preset=1";
|
||||
$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
|
||||
sub autoStop
|
||||
{
|
||||
my $self = shift;
|
||||
my $timeout = shift;
|
||||
|
||||
if ($timeout)
|
||||
{
|
||||
if ($timeout > 1) {
|
||||
usleep(100000*$timeout);
|
||||
}
|
||||
}
|
||||
Debug( "Auto Stop" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Stop=0";
|
||||
$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
||||
=head1 Floureon
|
||||
|
||||
ZoneMinder::Database - Perl extension for Floureon 1080P
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
Control script for Floureon 1080P IP camera
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
When setuping you monitor in the "Control" tab:
|
||||
|
||||
1. Select "Control type": Floureon 1080P
|
||||
2. Leave "Control device" empty
|
||||
3. Fill "Control Address" like username:password@ip/domain. Example: admin:admin123@192.168.1.110
|
||||
|
||||
=head2 EXPORT
|
||||
|
||||
None by default.
|
||||
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Ognyan Bankov, E<lt>ogibankov@gmail.comE<gt>
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
Copyright (C) 2017 Ognyan Bankov
|
||||
|
||||
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
|
||||
|
|
@ -139,7 +139,7 @@ sub moveConUp
|
|||
my $self = shift;
|
||||
my $params = shift;
|
||||
Debug( "Move Up" );
|
||||
my $cmd = "decoder_control.cgi?command=0&onestep=1&";
|
||||
my $cmd = "decoder_control.cgi?command=2&onestep=1&";
|
||||
$self->sendCmd( $cmd );
|
||||
my $autostop = $self->getParam( $params, 'autostop', 0 );
|
||||
if ( $autostop && $self->{Monitor}->{AutoStopTimeout} )
|
||||
|
@ -155,7 +155,7 @@ sub moveConDown
|
|||
my $self = shift;
|
||||
my $params = shift;
|
||||
Debug( "Move Down" );
|
||||
my $cmd = "decoder_control.cgi?command=2&onestep=1&";
|
||||
my $cmd = "decoder_control.cgi?command=0&onestep=1&";
|
||||
$self->sendCmd( $cmd );
|
||||
my $autostop = $self->getParam( $params, 'autostop', 0 );
|
||||
if ( $autostop && $self->{Monitor}->{AutoStopTimeout} )
|
||||
|
@ -203,7 +203,7 @@ sub moveConUpRight
|
|||
my $self = shift;
|
||||
my $params = shift;
|
||||
Debug( "Move Diagonally Up Right" );
|
||||
my $cmd = "decoder_control.cgi?command=91&onestep=1&";
|
||||
my $cmd = "decoder_control.cgi?command=93&onestep=1&";
|
||||
$self->sendCmd( $cmd );
|
||||
my $autostop = $self->getParam( $params, 'autostop', 0 );
|
||||
if ( $autostop && $self->{Monitor}->{AutoStopTimeout} )
|
||||
|
@ -219,7 +219,7 @@ sub moveConDownRight
|
|||
my $self = shift;
|
||||
my $params = shift;
|
||||
Debug( "Move Diagonally Down Right" );
|
||||
my $cmd = "decoder_control.cgi?command=93&onestep=1&";
|
||||
my $cmd = "decoder_control.cgi?command=91&onestep=1&";
|
||||
$self->sendCmd( $cmd );
|
||||
my $autostop = $self->getParam( $params, 'autostop', 0 );
|
||||
if ( $autostop && $self->{Monitor}->{AutoStopTimeout} )
|
||||
|
@ -235,7 +235,7 @@ sub moveConUpLeft
|
|||
my $self = shift;
|
||||
my $params = shift;
|
||||
Debug( "Move Diagonally Up Left" );
|
||||
my $cmd = "decoder_control.cgi?command=90&onestep=1&";
|
||||
my $cmd = "decoder_control.cgi?command=92&onestep=1&";
|
||||
$self->sendCmd( $cmd );
|
||||
my $autostop = $self->getParam( $params, 'autostop', 0 );
|
||||
if ( $autostop && $self->{Monitor}->{AutoStopTimeout} )
|
||||
|
@ -251,7 +251,7 @@ sub moveConDownLeft
|
|||
my $self = shift;
|
||||
my $params = shift;
|
||||
Debug( "Move Diagonally Down Left" );
|
||||
my $cmd = "decoder_control.cgi?command=92&onestep=1&";
|
||||
my $cmd = "decoder_control.cgi?command=90&onestep=1&";
|
||||
$self->sendCmd( $cmd );
|
||||
my $autostop = $self->getParam( $params, 'autostop', 0 );
|
||||
if ( $autostop && $self->{Monitor}->{AutoStopTimeout} )
|
||||
|
@ -275,7 +275,7 @@ sub presetHome
|
|||
{
|
||||
my $self = shift;
|
||||
Debug( "Home Preset" );
|
||||
my $cmd = "decoder_control.cgi?command=25&onestep=0&";
|
||||
my $cmd = "decoder_control.cgi?command=4&onestep=0&";
|
||||
$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,630 @@
|
|||
# ==========================================================================
|
||||
#
|
||||
# ZoneMinder Reolink IP Control Protocol Module, Date: 2016-01-19
|
||||
# Converted for use with Reolink IP Camera by Chris Swertfeger
|
||||
# Copyright (C) 2016 Chris Swertfeger
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This module contains the first implementation of the Reolink IP camera control
|
||||
# protocol
|
||||
#
|
||||
package ZoneMinder::Control::Reolink;
|
||||
|
||||
use 5.006;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
require ZoneMinder::Base;
|
||||
require ZoneMinder::Control;
|
||||
|
||||
our @ISA = qw(ZoneMinder::Control);
|
||||
|
||||
our %CamParams = ();
|
||||
|
||||
# ==========================================================================
|
||||
#
|
||||
# Reolink IP Control Protocol
|
||||
# This script sends ONVIF compliant commands and may work with other cameras
|
||||
# that require authentication
|
||||
#
|
||||
# The script was developed against a RLC-423 and RLC-420.
|
||||
#
|
||||
# Basic preset functions are supported, but more advanced features, which make
|
||||
# use of abnormally high preset numbers (ir lamp control, tours, pan speed, etc)
|
||||
# may or may not work.
|
||||
#
|
||||
#
|
||||
# On ControlAddress use the format :
|
||||
# USERNAME:PASSWORD@ADDRESS:PORT
|
||||
# eg : admin:pass@10.1.2.1:8899
|
||||
# admin:password@10.0.100.1:8899
|
||||
#
|
||||
# Use port 8000 by default for Reolink cameras
|
||||
#
|
||||
# Make sure and place a value in the Auto Stop Timeout field.
|
||||
# Recommend starting with a value of 1 second, and adjust accordingly.
|
||||
#
|
||||
# ==========================================================================
|
||||
|
||||
use ZoneMinder::Logger qw(:all);
|
||||
use ZoneMinder::Config qw(:all);
|
||||
|
||||
use Time::HiRes qw( usleep );
|
||||
|
||||
use MIME::Base64;
|
||||
use Digest::SHA;
|
||||
use DateTime;
|
||||
|
||||
my ($username,$password,$host,$port);
|
||||
|
||||
sub new
|
||||
{
|
||||
|
||||
my $class = shift;
|
||||
my $id = shift;
|
||||
my $self = ZoneMinder::Control->new( $id );
|
||||
my $logindetails = "";
|
||||
bless( $self, $class );
|
||||
srand( time() );
|
||||
return $self;
|
||||
}
|
||||
|
||||
our $AUTOLOAD;
|
||||
|
||||
sub AUTOLOAD
|
||||
{
|
||||
my $self = shift;
|
||||
my $class = ref( ) || croak( "$self not object" );
|
||||
my $name = $AUTOLOAD;
|
||||
$name =~ s/.*://;
|
||||
if ( exists($self->{$name}) )
|
||||
{
|
||||
return( $self->{$name} );
|
||||
}
|
||||
Fatal( "Can't access $name member of object of class $class" );
|
||||
}
|
||||
|
||||
sub open
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
$self->loadMonitor();
|
||||
#
|
||||
# Extract the username/password host/port from ControlAddress
|
||||
#
|
||||
if( $self->{Monitor}{ControlAddress} =~ /^([^:]+):([^@]+)@(.+)/ )
|
||||
{ # user:pass@host...
|
||||
$username = $1;
|
||||
$password = $2;
|
||||
$host = $3;
|
||||
}
|
||||
elsif( $self->{Monitor}{ControlAddress} =~ /^([^@]+)@(.+)/ )
|
||||
{ # user@host...
|
||||
$username = $1;
|
||||
$host = $2;
|
||||
}
|
||||
else { # Just a host
|
||||
$host = $self->{Monitor}{ControlAddress};
|
||||
}
|
||||
# Check if it is a host and port or just a host
|
||||
if( $host =~ /([^:]+):(.+)/ )
|
||||
{
|
||||
$host = $1;
|
||||
$port = $2;
|
||||
}
|
||||
else
|
||||
{
|
||||
$port = 80;
|
||||
}
|
||||
|
||||
use LWP::UserAgent;
|
||||
$self->{ua} = LWP::UserAgent->new;
|
||||
$self->{ua}->agent( "ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION );
|
||||
|
||||
$self->{state} = 'open';
|
||||
}
|
||||
|
||||
sub close
|
||||
{
|
||||
my $self = shift;
|
||||
$self->{state} = 'closed';
|
||||
}
|
||||
|
||||
sub printMsg
|
||||
{
|
||||
my $self = shift;
|
||||
my $msg = shift;
|
||||
my $msg_len = length($msg);
|
||||
|
||||
Debug( $msg."[".$msg_len."]" );
|
||||
}
|
||||
|
||||
sub sendCmd
|
||||
{
|
||||
my $self = shift;
|
||||
my $cmd = shift;
|
||||
my $msg = shift;
|
||||
my $content_type = shift;
|
||||
my $result = undef;
|
||||
|
||||
printMsg( $cmd, "Tx" );
|
||||
|
||||
my $server_endpoint = "http://".$host.":".$port."/$cmd";
|
||||
my $req = HTTP::Request->new( POST => $server_endpoint );
|
||||
$req->header('content-type' => $content_type);
|
||||
$req->header('Host' => $host.":".$port);
|
||||
$req->header('content-length' => length($msg));
|
||||
$req->header('accept-encoding' => 'gzip, deflate');
|
||||
$req->header('connection' => 'close');
|
||||
$req->content($msg);
|
||||
|
||||
my $res = $self->{ua}->request($req);
|
||||
|
||||
if ( $res->is_success ) {
|
||||
$result = !undef;
|
||||
} else {
|
||||
Error( "After sending PTZ command, camera returned the following error:'".$res->status_line()."'" );
|
||||
}
|
||||
return( $result );
|
||||
}
|
||||
|
||||
sub getCamParams
|
||||
{
|
||||
my $self = shift;
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $msg = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><GetImagingSettings xmlns="http://www.onvif.org/ver20/imaging/wsdl"><VideoSourceToken>000</VideoSourceToken></GetImagingSettings></s:Body></s:Envelope>';
|
||||
my $server_endpoint = "http://".$self->{Monitor}->{ControlAddress}."/onvif/imaging";
|
||||
my $req = HTTP::Request->new( POST => $server_endpoint );
|
||||
$req->header('content-type' => 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/imaging/wsdl/GetImagingSettings"');
|
||||
$req->header('Host' => $host.":".$port);
|
||||
$req->header('content-length' => length($msg));
|
||||
$req->header('accept-encoding' => 'gzip, deflate');
|
||||
$req->header('connection' => 'Close');
|
||||
$req->content($msg);
|
||||
|
||||
my $res = $self->{ua}->request($req);
|
||||
|
||||
if ( $res->is_success ) {
|
||||
# We should really use an xml or soap library to parse the xml tags
|
||||
my $content = $res->decoded_content;
|
||||
|
||||
if ($content =~ /.*<tt:(Brightness)>(.+)<\/tt:Brightness>.*/) {
|
||||
$CamParams{$1} = $2;
|
||||
}
|
||||
if ($content =~ /.*<tt:(Contrast)>(.+)<\/tt:Contrast>.*/) {
|
||||
$CamParams{$1} = $2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Error( "Unable to retrieve camera image settings:'".$res->status_line()."'" );
|
||||
}
|
||||
}
|
||||
|
||||
#autoStop
|
||||
#This makes use of the ZoneMinder Auto Stop Timeout on the Control Tab
|
||||
sub autoStop
|
||||
{
|
||||
my $self = shift;
|
||||
my $autostop = shift;
|
||||
|
||||
if( $autostop ) {
|
||||
Debug( "Auto Stop" );
|
||||
my $cmd = 'onvif/PTZ';
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $msg = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><Stop xmlns="http://www.onvif.org/ver20/ptz/wsdl"><ProfileToken>000</ProfileToken><PanTilt>true</PanTilt><Zoom>false</Zoom></Stop></s:Body></s:Envelope>';
|
||||
my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"';
|
||||
usleep( $autostop );
|
||||
$self->sendCmd( $cmd, $msg, $content_type );
|
||||
}
|
||||
}
|
||||
|
||||
# Reset the Camera
|
||||
sub reset
|
||||
{
|
||||
Debug( "Camera Reset" );
|
||||
my $self = shift;
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $cmd = "";
|
||||
my $msg = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><SystemReboot xmlns="http://www.onvif.org/ver10/device/wsdl"/></s:Body></s:Envelope>';
|
||||
my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver10/device/wsdl/SystemReboot"';
|
||||
$self->sendCmd( $cmd, $msg, $content_type );
|
||||
}
|
||||
|
||||
#Up Arrow
|
||||
sub moveConUp
|
||||
{
|
||||
Debug( "Move Up" );
|
||||
my $self = shift;
|
||||
my $cmd = 'onvif/PTZ';
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><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>000</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} );
|
||||
}
|
||||
|
||||
#Down Arrow
|
||||
sub moveConDown
|
||||
{
|
||||
Debug( "Move Down" );
|
||||
my $self = shift;
|
||||
my $cmd = 'onvif/PTZ';
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><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>000</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} );
|
||||
}
|
||||
|
||||
#Left Arrow
|
||||
sub moveConLeft
|
||||
{
|
||||
Debug( "Move Left" );
|
||||
my $self = shift;
|
||||
my $cmd = 'onvif/PTZ';
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><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>000</ProfileToken><Velocity><PanTilt x="-0.49" y="0" 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} );
|
||||
}
|
||||
|
||||
#Right Arrow
|
||||
sub moveConRight
|
||||
{
|
||||
Debug( "Move Right" );
|
||||
my $self = shift;
|
||||
my $cmd = 'onvif/PTZ';
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><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>000</ProfileToken><Velocity><PanTilt x="0.49" y="0" 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} );
|
||||
}
|
||||
|
||||
#Zoom In
|
||||
sub zoomConTele
|
||||
{
|
||||
Debug( "Zoom Tele" );
|
||||
my $self = shift;
|
||||
my $cmd = 'onvif/PTZ';
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><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>000</ProfileToken><Velocity><Zoom x="0.49" 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} );
|
||||
}
|
||||
|
||||
#Zoom Out
|
||||
sub zoomConWide
|
||||
{
|
||||
Debug( "Zoom Wide" );
|
||||
my $self = shift;
|
||||
my $cmd = 'onvif/PTZ';
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><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>000</ProfileToken><Velocity><Zoom x="-0.49" 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} );
|
||||
}
|
||||
|
||||
#Diagonally Up Right Arrow
|
||||
#This camera does not have builtin diagonal commands so we emulate them
|
||||
sub moveConUpRight
|
||||
{
|
||||
Debug( "Move Diagonally Up Right" );
|
||||
my $self = shift;
|
||||
my $cmd = 'onvif/PTZ';
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><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>000</ProfileToken><Velocity><PanTilt x="0.5" 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} );
|
||||
}
|
||||
|
||||
#Diagonally Down Right Arrow
|
||||
#This camera does not have builtin diagonal commands so we emulate them
|
||||
sub moveConDownRight
|
||||
{
|
||||
Debug( "Move Diagonally Down Right" );
|
||||
my $self = shift;
|
||||
my $cmd = 'onvif/PTZ';
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><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>000</ProfileToken><Velocity><PanTilt x="0.5" 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} );
|
||||
}
|
||||
|
||||
#Diagonally Up Left Arrow
|
||||
#This camera does not have builtin diagonal commands so we emulate them
|
||||
sub moveConUpLeft
|
||||
{
|
||||
Debug( "Move Diagonally Up Left" );
|
||||
my $self = shift;
|
||||
my $cmd = 'onvif/PTZ';
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><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>000</ProfileToken><Velocity><PanTilt x="-0.5" 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} );
|
||||
}
|
||||
|
||||
#Diagonally Down Left Arrow
|
||||
#This camera does not have builtin diagonal commands so we emulate them
|
||||
sub moveConDownLeft
|
||||
{
|
||||
Debug( "Move Diagonally Down Left" );
|
||||
my $self = shift;
|
||||
my $cmd = 'onvif/PTZ';
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><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>000</ProfileToken><Velocity><PanTilt x="-0.5" 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} );
|
||||
}
|
||||
|
||||
#Stop
|
||||
sub moveStop
|
||||
{
|
||||
Debug( "Move Stop" );
|
||||
my $self = shift;
|
||||
my $cmd = 'onvif/PTZ';
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><Stop xmlns="http://www.onvif.org/ver20/ptz/wsdl"><ProfileToken>000</ProfileToken><PanTilt>true</PanTilt><Zoom>false</Zoom></Stop></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 );
|
||||
}
|
||||
|
||||
#Set Camera Preset
|
||||
sub presetSet
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $preset = $self->getParam( $params, 'preset' );
|
||||
Debug( "Set Preset $preset" );
|
||||
my $cmd = 'onvif/PTZ';
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><SetPreset xmlns="http://www.onvif.org/ver20/ptz/wsdl"><ProfileToken>000</ProfileToken><PresetToken>'.$preset.'</PresetToken></SetPreset></s:Body></s:Envelope>';
|
||||
my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/SetPreset"';
|
||||
$self->sendCmd( $cmd, $msg, $content_type );
|
||||
}
|
||||
|
||||
#Recall Camera Preset
|
||||
sub presetGoto
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $preset = $self->getParam( $params, 'preset' );
|
||||
my $num = sprintf("%03d", $preset);
|
||||
$num=~ tr/ /0/;
|
||||
Debug( "Goto Preset $preset" );
|
||||
my $cmd = 'onvif/PTZ';
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><GotoPreset xmlns="http://www.onvif.org/ver20/ptz/wsdl"><ProfileToken>000</ProfileToken><PresetToken>'.$num.'</PresetToken></GotoPreset></s:Body></s:Envelope>';
|
||||
my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/GotoPreset"';
|
||||
$self->sendCmd( $cmd, $msg, $content_type );
|
||||
}
|
||||
|
||||
#Horizontal Patrol
|
||||
#To be determined if this camera supports this feature
|
||||
sub horizontalPatrol
|
||||
{
|
||||
Debug( "Horizontal Patrol" );
|
||||
my $self = shift;
|
||||
my $cmd = '';
|
||||
my $msg ='';
|
||||
my $content_type = '';
|
||||
# $self->sendCmd( $cmd, $msg, $content_type );
|
||||
Error( "PTZ Command not implemented in control script." );
|
||||
}
|
||||
|
||||
#Horizontal Patrol Stop
|
||||
#To be determined if this camera supports this feature
|
||||
sub horizontalPatrolStop
|
||||
{
|
||||
Debug( "Horizontal Patrol Stop" );
|
||||
my $self = shift;
|
||||
my $cmd = '';
|
||||
my $msg ='';
|
||||
my $content_type = '';
|
||||
# $self->sendCmd( $cmd, $msg, $content_type );
|
||||
Error( "PTZ Command not implemented in control script." );
|
||||
}
|
||||
|
||||
# Increase Brightness
|
||||
sub irisAbsOpen
|
||||
{
|
||||
Debug( "Iris $CamParams{'Brightness'}" );
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
$self->getCamParams() unless($CamParams{'Brightness'});
|
||||
my $step = $self->getParam( $params, 'step' );
|
||||
my $max = 100;
|
||||
|
||||
$CamParams{'Brightness'} += $step;
|
||||
$CamParams{'Brightness'} = $max if ($CamParams{'Brightness'} > $max);
|
||||
|
||||
my $cmd = 'onvif/imaging';
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><SetImagingSettings xmlns="http://www.onvif.org/ver20/imaging/wsdl"><VideoSourceToken>000</VideoSourceToken><ImagingSettings><Brightness xmlns="http://www.onvif.org/ver10/schema">'.$CamParams{'Brightness'}.'</Brightness></ImagingSettings><ForcePersistence>true</ForcePersistence></SetImagingSettings></s:Body></s:Envelope>';
|
||||
my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/imaging/wsdl/SetImagingSettings"';
|
||||
$self->sendCmd( $cmd, $msg, $content_type );
|
||||
}
|
||||
|
||||
# Decrease Brightness
|
||||
sub irisAbsClose
|
||||
{
|
||||
Debug( "Iris $CamParams{'Brightness'}" );
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
$self->getCamParams() unless($CamParams{'brightness'});
|
||||
my $step = $self->getParam( $params, 'step' );
|
||||
my $min = 0;
|
||||
|
||||
$CamParams{'Brightness'} -= $step;
|
||||
$CamParams{'Brightness'} = $min if ($CamParams{'Brightness'} < $min);
|
||||
|
||||
my $cmd = 'onvif/imaging';
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><SetImagingSettings xmlns="http://www.onvif.org/ver20/imaging/wsdl"><VideoSourceToken>000</VideoSourceToken><ImagingSettings><Brightness xmlns="http://www.onvif.org/ver10/schema">'.$CamParams{'Brightness'}.'</Brightness></ImagingSettings><ForcePersistence>true</ForcePersistence></SetImagingSettings></s:Body></s:Envelope>';
|
||||
my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/imaging/wsdl/SetImagingSettings"';
|
||||
$self->sendCmd( $cmd, $msg, $content_type );
|
||||
}
|
||||
|
||||
# Increase Contrast
|
||||
sub whiteAbsIn
|
||||
{
|
||||
Debug( "Iris $CamParams{'Contrast'}" );
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
$self->getCamParams() unless($CamParams{'Contrast'});
|
||||
my $step = $self->getParam( $params, 'step' );
|
||||
my $max = 100;
|
||||
|
||||
$CamParams{'Contrast'} += $step;
|
||||
$CamParams{'Contrast'} = $max if ($CamParams{'Contrast'} > $max);
|
||||
|
||||
my $cmd = 'onvif/imaging';
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><SetImagingSettings xmlns="http://www.onvif.org/ver20/imaging/wsdl"><VideoSourceToken>000</VideoSourceToken><ImagingSettings><Contrast xmlns="http://www.onvif.org/ver10/schema">'.$CamParams{'Contrast'}.'</Contrast></ImagingSettings><ForcePersistence>true</ForcePersistence></SetImagingSettings></s:Body></s:Envelope>';
|
||||
my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/imaging/wsdl/SetImagingSettings"';
|
||||
}
|
||||
|
||||
# Decrease Contrast
|
||||
sub whiteAbsOut
|
||||
{
|
||||
Debug( "Iris $CamParams{'Contrast'}" );
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
$self->getCamParams() unless($CamParams{'Contrast'});
|
||||
my $step = $self->getParam( $params, 'step' );
|
||||
my $min = 0;
|
||||
|
||||
$CamParams{'Contrast'} -= $step;
|
||||
$CamParams{'Contrast'} = $min if ($CamParams{'Contrast'} < $min);
|
||||
|
||||
my $cmd = 'onvif/imaging';
|
||||
my $nonce;
|
||||
for (0..20){$nonce .= chr(int(rand(254)));}
|
||||
my $mydate = DateTime->now()->iso8601().'Z';
|
||||
my $sha = Digest::SHA->new(1);
|
||||
$sha->add($nonce.$mydate.$password);
|
||||
my $digest = encode_base64($sha->digest,"");
|
||||
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>'.$username.'</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$digest.'</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.encode_base64($nonce,"").'</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$mydate.'</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><SetImagingSettings xmlns="http://www.onvif.org/ver20/imaging/wsdl"><VideoSourceToken>000</VideoSourceToken><ImagingSettings><Contrast xmlns="http://www.onvif.org/ver10/schema">'.$CamParams{'Contrast'}.'</Contrast></ImagingSettings><ForcePersistence>true</ForcePersistence></SetImagingSettings></s:Body></s:Envelope>';
|
||||
my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/imaging/wsdl/SetImagingSettings"';
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
@ -8,6 +8,13 @@ exit;
|
|||
|
||||
fi
|
||||
|
||||
DEBUILD=`which debuild`;
|
||||
|
||||
if [ "$DEBUILD" == "" ]; then
|
||||
echo "You must install the devscripts package. Try sudo apt-get install devscripts";
|
||||
exit;
|
||||
fi
|
||||
|
||||
for i in "$@"
|
||||
do
|
||||
case $i in
|
||||
|
|
|
@ -1,47 +1,4 @@
|
|||
# Overview
|
||||
## Docker Support Files
|
||||
|
||||
[Docker](https://www.docker.io/) allows you to quickly spin up application containers,
|
||||
which are similar to very lightweight virtual machines. The ZoneMinder Dockerfile will
|
||||
start an Ubuntu 12.04 container with MySql, Apache, and PHP properly configured, and
|
||||
will then compile and install ZoneMinder.
|
||||
|
||||
It will also start an SSH server that you can use to log into the container.
|
||||
|
||||
This is still a bit of a work in progress.
|
||||
|
||||
## How To Use
|
||||
|
||||
1. Install [Docker](https://www.docker.io/)
|
||||
2. Build ZoneMinder container
|
||||
```sudo docker build -t yourname/zoneminder github.com/ZoneMinder/ZoneMinder```
|
||||
3. Run it
|
||||
```CID=$(sudo docker run -d -p 222:22 -p 8080:80 --name zoneminder yourname/zoneminder)```
|
||||
4. Use it -- you can now SSH to port 222 on your host as user root with password root.
|
||||
You can also browse to your host on port 8080 to access the zoneminder web interface
|
||||
|
||||
## Developing With Docker
|
||||
|
||||
If you wish to contribute to ZoneMinder, Docker can be helpful. By re-running
|
||||
```docker build``` in your working directory, any code modifications you have
|
||||
made will be pulled into a new container, compiled, and started, all without
|
||||
modifying your base system.
|
||||
|
||||
Development is not totally without annoyances, as any change
|
||||
to the project will require a full rebuild of all C++. Docker notices that the
|
||||
directory which has been ADD'ed is now different, and therefore all steps after
|
||||
the ADD command must be recomputed. A fix for this is to update the Dockerfile to
|
||||
move the configure and make commands into start.sh, and then use a volume mount
|
||||
to cache the build directory (I think it's ```/tmp```) on your host filesystem.
|
||||
This would be really useful for a developer, and would remove the annoying build
|
||||
problem, but some of the Docker push/pull benefits would be lost.
|
||||
|
||||
Docker containers can be both CPU and memory limited, so this can be a practical
|
||||
method to compile or run multiple development builds of ZoneFinder simultaneously
|
||||
without taxing your host system.
|
||||
|
||||
## Use Cases
|
||||
|
||||
## TODO
|
||||
- Describe how to connect to monitors by mounting devices
|
||||
- Create a 'development' dockerfile to remove the need to rebuild the entire project
|
||||
after each small change
|
||||
Docker support files have been moved to the zmdockerfiles repo:
|
||||
https://github.com/ZoneMinder/zmdockerfiles
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[Date]
|
||||
; Defines the default timezone used by the date functions
|
||||
; http://php.net/date.timezone
|
||||
date.timezone = GMT
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
setup_mysql_first_time(){
|
||||
if [ "$(ls /var/lib/mysql)" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
# Set MySQL in the volume
|
||||
rm -rf /var/lib/mysql/*
|
||||
chown -R mysql:mysql /var/lib/mysql
|
||||
mysqld --initialize-insecure
|
||||
|
||||
# Start MySQL
|
||||
# For Xenial the following won't start mysqld
|
||||
#/usr/bin/mysqld_safe &
|
||||
# Use this instead:
|
||||
service mysql start
|
||||
|
||||
# Give MySQL time to wake up
|
||||
SECONDS_LEFT=120
|
||||
while true; do
|
||||
sleep 1
|
||||
mysqladmin ping
|
||||
if [ $? -eq 0 ];then
|
||||
break; # Success
|
||||
fi
|
||||
let SECONDS_LEFT=SECONDS_LEFT-1
|
||||
|
||||
# If we have waited >120 seconds, give up
|
||||
# ZM should never have a database that large!
|
||||
# if $COUNTER -lt 120
|
||||
if [ $SECONDS_LEFT -eq 0 ];then
|
||||
return -1;
|
||||
fi
|
||||
done
|
||||
|
||||
# Create the ZoneMinder database
|
||||
mysql -u root < db/zm_create.sql
|
||||
|
||||
# Add the ZoneMinder DB user
|
||||
mysql -u root -e "grant insert,select,update,delete,lock tables,alter on zm.* to 'zmuser'@'localhost' identified by 'zmpass';"
|
||||
|
||||
# Shut down mysql cleanly:
|
||||
kill $(cat /var/run/mysqld/mysqld.pid)
|
||||
sleep 5
|
||||
}
|
||||
|
||||
setup_mysql() {
|
||||
# To configure MySQL if no container did it before
|
||||
setup_mysql_first_time
|
||||
|
||||
# Add configuration to avoid SQL error when adding monitor
|
||||
echo "sql_mode=NO_ENGINE_SUBSTITUTION" >> /etc/mysql/mysql.conf.d/mysqld.cnf
|
||||
}
|
||||
|
||||
setup_php() {
|
||||
# Activate CGI
|
||||
a2enmod cgi
|
||||
|
||||
# Activate modrewrite
|
||||
a2enmod rewrite
|
||||
|
||||
# Setting timezone
|
||||
sed -i "s#;date.timezone =#date.timezone = $PHP_TIMEZONE#" /etc/php/7.0/apache2/php.ini
|
||||
|
||||
# Settings rights for volume
|
||||
chown -R www-data:www-data /var/lib/zoneminder/events
|
||||
chown -R www-data:www-data /var/lib/zoneminder/images
|
||||
}
|
||||
|
||||
|
||||
setup_mysql
|
||||
setup_php
|
||||
|
||||
exit 0
|
|
@ -1,48 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Prepare proper amount of shared memory
|
||||
# For H.264 cameras it may be necessary to increase the amount of shared memory
|
||||
# to 2048 megabytes.
|
||||
umount /dev/shm
|
||||
mount -t tmpfs -o rw,nosuid,nodev,noexec,relatime,size=512M tmpfs /dev/shm
|
||||
|
||||
# Start MySQL
|
||||
test -e /var/run/mysqld || install -m 755 -o mysql -g root -d /var/run/mysqld
|
||||
su - mysql -s /bin/sh -c "/usr/bin/mysqld_safe > /dev/null 2>&1 &"
|
||||
|
||||
# Ensure we shut down mysql cleanly later:
|
||||
trap close_mysql SIGTERM
|
||||
|
||||
# Give MySQL time to wake up
|
||||
SECONDS_LEFT=120
|
||||
while true; do
|
||||
sleep 1
|
||||
mysqladmin ping
|
||||
if [ $? -eq 0 ];then
|
||||
break; # Success
|
||||
fi
|
||||
let SECONDS_LEFT=SECONDS_LEFT-1
|
||||
|
||||
# If we have waited >120 seconds, give up
|
||||
# ZM should never have a database that large!
|
||||
# if $COUNTER -lt 120
|
||||
if [ $SECONDS_LEFT -eq 0 ];then
|
||||
return -1;
|
||||
fi
|
||||
done
|
||||
|
||||
# Restart apache
|
||||
service apache2 restart
|
||||
|
||||
# Start ZoneMinder
|
||||
/usr/local/bin/zmpkg.pl start && echo "Zone Minder started"
|
||||
|
||||
while :
|
||||
do
|
||||
sleep 3600
|
||||
done
|
||||
|
||||
function close_mysql {
|
||||
kill $(cat /var/run/mysqld/mysqld.pid)
|
||||
sleep 5
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
From 634281a4204467b9a3c8a1a5febcc8dd9828e0f6 Mon Sep 17 00:00:00 2001
|
||||
From: Andy Bauer <knnniggett@hotmail.com>
|
||||
Date: Thu, 22 Feb 2018 08:53:50 -0600
|
||||
Subject: [PATCH] don't run lintian checks to speed up build
|
||||
|
||||
---
|
||||
pack/deb.mk | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/pack/deb.mk b/pack/deb.mk
|
||||
index de4a0b7..bddf9df 100644
|
||||
--- a/packpack/pack/deb.mk
|
||||
+++ b/packpack/pack/deb.mk
|
||||
@@ -130,7 +130,7 @@ $(BUILDDIR)/$(DPKG_CHANGES): $(BUILDDIR)/$(PRODUCT)-$(VERSION)/debian \
|
||||
@echo "Building Debian packages"
|
||||
@echo "-------------------------------------------------------------------"
|
||||
cd $(BUILDDIR)/$(PRODUCT)-$(VERSION) && \
|
||||
- debuild --preserve-envvar CCACHE_DIR --prepend-path=/usr/lib/ccache \
|
||||
+ debuild --no-lintian --preserve-envvar CCACHE_DIR --prepend-path=/usr/lib/ccache \
|
||||
-Z$(TARBALL_COMPRESSOR) -uc -us $(SMPFLAGS)
|
||||
rm -rf $(BUILDDIR)/$(PRODUCT)-$(VERSION)/
|
||||
@echo "------------------------------------------------------------------"
|
|
@ -0,0 +1,57 @@
|
|||
From 62a98b36fd62d328956503bc9427ae128bb811af Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Bauer <zonexpertconsulting@outlook.com>
|
||||
Date: Mon, 26 Feb 2018 10:05:02 -0600
|
||||
Subject: [PATCH] fix 32bit rpm builds
|
||||
|
||||
---
|
||||
pack/rpm.mk | 2 +-
|
||||
packpack | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/packpack/pack/rpm.mk b/packpack/pack/rpm.mk
|
||||
index c74e942..9a6b016 100644
|
||||
--- a/packpack/pack/rpm.mk
|
||||
+++ b/packpack/pack/rpm.mk
|
||||
@@ -124,7 +124,7 @@ package: $(BUILDDIR)/$(RPMSRC)
|
||||
@echo "-------------------------------------------------------------------"
|
||||
@echo "Building RPM packages"
|
||||
@echo "-------------------------------------------------------------------"
|
||||
- rpmbuild \
|
||||
+ setarch $(ARCH) rpmbuild \
|
||||
--define '_topdir $(BUILDDIR)' \
|
||||
--define '_sourcedir $(BUILDDIR)' \
|
||||
--define '_specdir $(BUILDDIR)' \
|
||||
diff --git a/packpack/packpack b/packpack/packpack
|
||||
index 6f4c80f..c329399 100755
|
||||
--- a/packpack/packpack
|
||||
+++ b/packpack/packpack
|
||||
@@ -125,7 +125,7 @@ chmod a+x ${BUILDDIR}/userwrapper.sh
|
||||
#
|
||||
# Save defined configuration variables to ./env file
|
||||
#
|
||||
-env | grep -E "^PRODUCT=|^VERSION=|^RELEASE=|^ABBREV=|^TARBALL_|^CHANGELOG_|^CCACHE_|^PACKAGECLOUD_|^SMPFLAGS=|^OS=|^DIST=" \
|
||||
+env | grep -E "^PRODUCT=|^VERSION=|^RELEASE=|^ABBREV=|^TARBALL_|^CHANGELOG_|^CCACHE_|^PACKAGECLOUD_|^SMPFLAGS=|^OS=|^DIST=|^ARCH=" \
|
||||
> ${BUILDDIR}/env
|
||||
|
||||
#
|
||||
diff --git a/packpack/packpack b/packpack/packpack
|
||||
index c329399..6ffaa9c 100755
|
||||
--- a/packpack/packpack
|
||||
+++ b/packpack/packpack
|
||||
@@ -19,11 +19,11 @@ DOCKER_REPO=${DOCKER_REPO:-packpack/packpack}
|
||||
if [ -z "${ARCH}" ]; then
|
||||
# Use uname -m instead of HOSTTYPE
|
||||
case "$(uname -m)" in
|
||||
- i*86) ARCH="i386" ;;
|
||||
- arm*) ARCH="armhf" ;;
|
||||
- x86_64) ARCH="x86_64"; ;;
|
||||
- aarch64) ARCH="aarch64" ;;
|
||||
- *) ARCH="${HOSTTYPE}" ;;
|
||||
+ i*86) export ARCH="i386" ;;
|
||||
+ arm*) export ARCH="armhf" ;;
|
||||
+ x86_64) export ARCH="x86_64"; ;;
|
||||
+ aarch64) export ARCH="aarch64" ;;
|
||||
+ *) export ARCH="${HOSTTYPE}" ;;
|
||||
esac
|
||||
fi
|
||||
|
|
@ -108,6 +108,18 @@ commonprep () {
|
|||
patch -p1 < utils/packpack/packpack-rpm.patch
|
||||
fi
|
||||
|
||||
# Skip deb lintian checks to speed up the build
|
||||
patch --dry-run --silent -f -p1 < utils/packpack/nolintian.patch
|
||||
if [ $? -eq 0 ]; then
|
||||
patch -p1 < utils/packpack/nolintian.patch
|
||||
fi
|
||||
|
||||
# fix 32bit rpm builds
|
||||
patch --dry-run --silent -f -p1 < utils/packpack/setarch.patch
|
||||
if [ $? -eq 0 ]; then
|
||||
patch -p1 < utils/packpack/setarch.patch
|
||||
fi
|
||||
|
||||
# The rpm specfile requires we download the tarball and manually move it into place
|
||||
# Might as well do this for Debian as well, rather than git submodule init
|
||||
CRUDVER="3.0.10"
|
||||
|
@ -295,7 +307,7 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then
|
|||
execpackpack
|
||||
|
||||
# Steps common to Debian based distros
|
||||
elif [ "${OS}" == "debian" ] || [ "${OS}" == "ubuntu" ]; then
|
||||
elif [ "${OS}" == "debian" ] || [ "${OS}" == "ubuntu" ] || [ "${OS}" == "raspbian" ]; then
|
||||
echo "Begin ${OS} ${DIST} build..."
|
||||
|
||||
setdebpkgname
|
||||
|
|
|
@ -10,7 +10,7 @@ configure_file(includes/config.php.in "${CMAKE_CURRENT_BINARY_DIR}/includes/conf
|
|||
|
||||
# Install the web files
|
||||
install(DIRECTORY api ajax css fonts graphics includes js lang skins tools views DESTINATION "${ZM_WEBDIR}" PATTERN "*.in" EXCLUDE PATTERN "*Make*" EXCLUDE PATTERN "*cmake*" EXCLUDE)
|
||||
install(FILES index.php DESTINATION "${ZM_WEBDIR}")
|
||||
install(FILES index.php robots.txt DESTINATION "${ZM_WEBDIR}")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/includes/config.php" DESTINATION "${ZM_WEBDIR}/includes")
|
||||
|
||||
# Install the api config files (if its not in the source directory)
|
||||
|
|
|
@ -136,6 +136,17 @@ $statusData = array(
|
|||
//"Path" => array( "postFunc" => "getEventPath" ),
|
||||
),
|
||||
),
|
||||
"frames" => array(
|
||||
"permission" => "Events",
|
||||
"table" => "Frames",
|
||||
"selector" => "EventId",
|
||||
"elements" => array(
|
||||
"EventId" => true,
|
||||
"FrameId" => true,
|
||||
"Type" => true,
|
||||
"Delta" => true,
|
||||
),
|
||||
),
|
||||
"frame" => array(
|
||||
"permission" => "Events",
|
||||
"table" => "Frames",
|
||||
|
@ -367,7 +378,7 @@ function getNearEvents() {
|
|||
else
|
||||
$midSql = '';
|
||||
|
||||
$sql = "select E.Id as Id from Events as E inner join Monitors as M on E.MonitorId = M.Id where ".dbEscape($sortColumn)." ".($sortOrder=='asc'?'<=':'>=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." order by $sortColumn ".($sortOrder=='asc'?'desc':'asc');
|
||||
$sql = "SELECT E.Id AS Id, E.StartTime AS StartTime FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE $sortColumn ".($sortOrder=='asc'?'<=':'>=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." ORDER BY $sortColumn ".($sortOrder=='asc'?'desc':'asc') . ' LIMIT 2';
|
||||
$result = dbQuery( $sql );
|
||||
while ( $id = dbFetchNext( $result, 'Id' ) ) {
|
||||
if ( $id == $eventId ) {
|
||||
|
@ -376,7 +387,7 @@ function getNearEvents() {
|
|||
}
|
||||
}
|
||||
|
||||
$sql = "select E.Id as Id from Events as E inner join Monitors as M on E.MonitorId = M.Id where $sortColumn ".($sortOrder=='asc'?'>=':'<=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." order by $sortColumn $sortOrder";
|
||||
$sql = "SELECT E.Id AS Id, E.StartTime AS StartTime FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE $sortColumn ".($sortOrder=='asc'?'>=':'<=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." ORDER BY $sortColumn $sortOrder LIMIT 2";
|
||||
$result = dbQuery( $sql );
|
||||
while ( $id = dbFetchNext( $result, 'Id' ) ) {
|
||||
if ( $id == $eventId ) {
|
||||
|
@ -388,8 +399,10 @@ function getNearEvents() {
|
|||
$result = array( 'EventId'=>$eventId );
|
||||
$result['PrevEventId'] = empty($prevEvent)?0:$prevEvent['Id'];
|
||||
$result['NextEventId'] = empty($nextEvent)?0:$nextEvent['Id'];
|
||||
$result['PrevEventDefVideoPath'] = empty($prevEvent)?0:(getEventDefaultVideoPath($prevEvent));
|
||||
$result['NextEventDefVideoPath'] = empty($nextEvent)?0:(getEventDefaultVideoPath($nextEvent));
|
||||
$result['PrevEventStartTime'] = empty($prevEvent)?0:$prevEvent['StartTime'];
|
||||
$result['NextEventStartTime'] = empty($nextEvent)?0:$nextEvent['StartTime'];
|
||||
$result['PrevEventDefVideoPath'] = empty($prevEvent)?0:(getEventDefaultVideoPath($prevEvent['Id']));
|
||||
$result['NextEventDefVideoPath'] = empty($nextEvent)?0:(getEventDefaultVideoPath($nextEvent['Id']));
|
||||
return( $result );
|
||||
}
|
||||
|
||||
|
|
|
@ -76,11 +76,10 @@ public function beforeFilter() {
|
|||
);
|
||||
$events = $this->Paginator->paginate('Event');
|
||||
|
||||
// For each event, get its thumbnail data (path, width, height)
|
||||
// For each event, get the frameID which has the largest score
|
||||
foreach ($events as $key => $value) {
|
||||
//$thumbData = $this->createThumbnail($value['Event']['Id']);
|
||||
$thumbData = "";
|
||||
$events[$key]['thumbData'] = $thumbData;
|
||||
$maxScoreFrameId = $this->getMaxScoreAlarmFrameId($value['Event']['Id']);
|
||||
$events[$key]['Event']['MaxScoreFrameId'] = $maxScoreFrameId;
|
||||
|
||||
}
|
||||
|
||||
|
@ -276,6 +275,32 @@ public function beforeFilter() {
|
|||
'results' => $results,
|
||||
'_serialize' => array('results')
|
||||
));
|
||||
}
|
||||
|
||||
public function getMaxScoreAlarmFrameId($id = null) {
|
||||
$this->Event->recursive = -1;
|
||||
|
||||
if (!$this->Event->exists($id)) {
|
||||
throw new NotFoundException(__('Invalid event'));
|
||||
}
|
||||
|
||||
$event = $this->Event->find('first', array(
|
||||
'conditions' => array('Id' => $id)
|
||||
));
|
||||
|
||||
// Find the max Frame for this Event. Error out otherwise.
|
||||
$this->loadModel('Frame');
|
||||
if (! $frame = $this->Frame->find('first', array(
|
||||
'conditions' => array(
|
||||
'EventId' => $event['Event']['Id'],
|
||||
'Score' => $event['Event']['MaxScore']
|
||||
)
|
||||
))) {
|
||||
throw new NotFoundException(__("Can not find Frame for Event " . $event['Event']['Id']));
|
||||
}
|
||||
return $frame['Frame']['Id'];
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Create a thumbnail and return the thumbnail's data for a given event id.
|
||||
|
@ -301,6 +326,7 @@ public function beforeFilter() {
|
|||
throw new NotFoundException(__("Can not find Frame for Event " . $event['Event']['Id']));
|
||||
}
|
||||
|
||||
|
||||
$this->loadModel('Config');
|
||||
|
||||
// Get the config options required for reScale and getImageSrc
|
||||
|
|
|
@ -122,7 +122,7 @@ public function beforeFilter() {
|
|||
if (!$this->Monitor->exists($id)) {
|
||||
throw new NotFoundException(__('Invalid monitor'));
|
||||
}
|
||||
if ($this->Session->Read('systemPermission') != 'Edit')
|
||||
if ($this->Session->Read('monitorPermission') != 'Edit')
|
||||
{
|
||||
throw new UnauthorizedException(__('Insufficient privileges'));
|
||||
return;
|
||||
|
|
|
@ -212,14 +212,12 @@ if ( !empty($action) ) {
|
|||
deleteEvent( $markEid );
|
||||
$refreshParent = true;
|
||||
}
|
||||
if ( isset( $_REQUEST['object'] ) and ( $_REQUEST['object'] == 'filter' ) ) {
|
||||
if ( !empty($_REQUEST['Id']) ) {
|
||||
dbQuery( 'DELETE FROM Filters WHERE Id=?', array( $_REQUEST['Id'] ) );
|
||||
if ( !empty($_REQUEST['fid']) ) {
|
||||
dbQuery( 'DELETE FROM Filters WHERE Name=?', array( $_REQUEST['fid'] ) );
|
||||
//$refreshParent = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Monitor control actions, require a monitor id and control view permissions for that monitor
|
||||
if ( !empty($_REQUEST['mid']) && canView( 'Control', $_REQUEST['mid'] ) ) {
|
||||
|
|
|
@ -452,7 +452,8 @@ function getEventPath( $event ) {
|
|||
}
|
||||
|
||||
function getEventDefaultVideoPath( $event ) {
|
||||
return ZM_DIR_EVENTS . '/' . getEventPath($event) . '/' . $event['DefaultVideo'];
|
||||
$Event = new Event( $event );
|
||||
return $Event->getStreamSrc( array( "mode"=>"mpeg", "format"=>"h264" ) );
|
||||
}
|
||||
|
||||
function deletePath( $path ) {
|
||||
|
@ -992,7 +993,7 @@ function zmaCheck( $monitor ) {
|
|||
}
|
||||
|
||||
function getImageSrc( $event, $frame, $scale=SCALE_BASE, $captureOnly=false, $overwrite=false ) {
|
||||
$eventPath = getEventPath( $event );
|
||||
$eventPath = ZM_DIR_EVENTS . '/' . getEventPath( $event );
|
||||
|
||||
if ( !is_array($frame) )
|
||||
$frame = array( 'FrameId'=>$frame, 'Type'=>'' );
|
||||
|
@ -1504,6 +1505,66 @@ function getDiskBlocks() {
|
|||
return( $space );
|
||||
}
|
||||
|
||||
function systemStats() {
|
||||
|
||||
$load = getLoad();
|
||||
$diskPercent = getDiskPercent();
|
||||
$pathMapPercent = getDiskPercent(ZM_PATH_MAP);
|
||||
$cpus = getcpus();
|
||||
|
||||
$normalized_load = $load / $cpus;
|
||||
|
||||
# Colorize the system load stat
|
||||
if ( $normalized_load <= 0.75 ) {
|
||||
$htmlLoad=$load;
|
||||
} elseif ( $normalized_load <= 0.9 ) {
|
||||
$htmlLoad="<span class=\"warning\">$load</span>";
|
||||
} elseif ( $normalized_load <= 1.1 ) {
|
||||
$htmlLoad="<span class=\"error\">$load</span>";
|
||||
} else {
|
||||
$htmlLoad="<span class=\"critical\">$load</span>";
|
||||
}
|
||||
|
||||
# Colorize the disk space stat
|
||||
if ( $diskPercent < 98 ) {
|
||||
$htmlDiskPercent="$diskPercent%";
|
||||
} elseif ( $diskPercent <= 99 ) {
|
||||
$htmlDiskPercent="<span class=\"warning\">$diskPercent%</span>";
|
||||
} else {
|
||||
$htmlDiskPercent="<span class=\"error\">$diskPercent%</span>";
|
||||
}
|
||||
|
||||
# Colorize the PATH_MAP (usually /dev/shm) stat
|
||||
if ( $pathMapPercent < 90 ) {
|
||||
if ( disk_free_space(ZM_PATH_MAP) > 209715200 ) { # have to always have at least 200MiB free
|
||||
$htmlPathMapPercent="$pathMapPercent%";
|
||||
} else {
|
||||
$htmlPathMapPercent="<span class=\"warning\">$pathMapPercent%</span>";
|
||||
}
|
||||
} elseif ( $pathMapPercent < 100 ) {
|
||||
$htmlPathMapPercent="<span class=\"warning\">$pathMapPercent%</span>";
|
||||
} else {
|
||||
$htmlPathMapPercent="<span class=\"critical\">$pathMapPercent%</span>";
|
||||
}
|
||||
|
||||
$htmlString = translate('Load').": $htmlLoad - ".translate('Disk').": $htmlDiskPercent - ".ZM_PATH_MAP.": $htmlPathMapPercent";
|
||||
|
||||
return( $htmlString );
|
||||
}
|
||||
|
||||
function getcpus() {
|
||||
|
||||
if (is_readable("/proc/cpuinfo") ) { # Works on Linux
|
||||
preg_match_all('/^processor/m', file_get_contents('/proc/cpuinfo'), $matches);
|
||||
$num_cpus = count($matches[0]);
|
||||
} else { # Works on BSD
|
||||
$matches = explode(":", shell_exec("sysctl hw.ncpu"));
|
||||
$num_cpus = trim($matches[1]);
|
||||
}
|
||||
|
||||
return( $num_cpus );
|
||||
}
|
||||
|
||||
// Function to fix a problem whereby the built in PHP session handling
|
||||
// features want to put the sid as a hidden field after the form or
|
||||
// fieldset tag, neither of which will work with strict XHTML Basic.
|
||||
|
@ -2245,6 +2306,7 @@ function getStreamMode( ) {
|
|||
$streamMode = 'single';
|
||||
Info( 'The system has fallen back to single jpeg mode for streaming. Consider enabling Cambozola or upgrading the client browser.' );
|
||||
}
|
||||
return $streamMode;
|
||||
} // end function getStreamMode
|
||||
|
||||
function folder_size($dir) {
|
||||
|
|
|
@ -37,7 +37,7 @@ function loadLanguage( $prefix="" )
|
|||
$fallbackLangFile = $prefix.'lang/en_gb.php';
|
||||
$systemLangFile = $prefix.'lang/'.ZM_LANG_DEFAULT.'.php';
|
||||
if ( isset($user['Language']) )
|
||||
$userLangFile = $prefix.$user['Language'].'.php';
|
||||
$userLangFile = $prefix.'lang/'.$user['Language'].'.php';
|
||||
|
||||
if ( isset($userLangFile) && file_exists( $userLangFile ) )
|
||||
return( $userLangFile );
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
User-agent: *
|
||||
Disallow: /
|
|
@ -12,6 +12,19 @@
|
|||
float: right;
|
||||
}
|
||||
|
||||
#systemStats .warning {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
#systemStats .error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#systemStats .critical {
|
||||
color: red;
|
||||
text-decoration: blink;
|
||||
}
|
||||
|
||||
#monitorSummary {
|
||||
float: left;
|
||||
text-align: left;
|
||||
|
|
|
@ -1,3 +1,34 @@
|
|||
#content .vjsMessage {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
margin: 0;
|
||||
font-size: 200%;
|
||||
color: white;
|
||||
background-color: black;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.alarmCue {
|
||||
background-color: #222222;
|
||||
height: 1.25em;
|
||||
text-align: left;
|
||||
margin: 0 auto 0 auto;
|
||||
border-radius: 0 0 .3em .3em;
|
||||
}
|
||||
|
||||
.alarmCue span {
|
||||
background-color:red;
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
span.noneCue {
|
||||
background: none;
|
||||
}
|
||||
|
||||
#dataBar {
|
||||
width: 100%;
|
||||
margin: 2px auto;
|
||||
|
@ -6,6 +37,7 @@
|
|||
|
||||
#dataBar #dataTable {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
#dataBar #dataTable td {
|
||||
|
@ -13,6 +45,11 @@
|
|||
padding: 2px;
|
||||
}
|
||||
|
||||
#eventVideo {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#menuBar1 {
|
||||
width: 100%;
|
||||
padding: 3px 0;
|
||||
|
@ -83,6 +120,8 @@
|
|||
}
|
||||
|
||||
#imageFeed {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
@ -147,39 +186,29 @@
|
|||
|
||||
#progressBar {
|
||||
position: relative;
|
||||
border: 1px solid #666666;
|
||||
height: 15px;
|
||||
margin: 0 auto;
|
||||
top: -1.25em;
|
||||
height: 1.25em;
|
||||
margin: 0 auto -1.25em auto;
|
||||
}
|
||||
|
||||
#progressBar .progressBox {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
height: 15px;
|
||||
background: #eeeeee;
|
||||
border-left: 1px solid #999999;
|
||||
}
|
||||
|
||||
#progressBar .complete {
|
||||
background: #aaaaaa;
|
||||
transition: width .1s;
|
||||
height: 100%;
|
||||
background: rgba(170, 170, 170, .7);
|
||||
border-radius: 0 0 .3em .3em;
|
||||
}
|
||||
|
||||
#eventStills {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#eventThumbsPanel {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
margin: 4px auto;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#eventThumbs {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
height: 300px;
|
||||
}
|
||||
|
@ -198,14 +227,19 @@
|
|||
}
|
||||
|
||||
#eventImagePanel {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#eventImageFrame {
|
||||
border: 2px solid gray;
|
||||
background-color: white;
|
||||
padding: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#eventImage {
|
||||
|
@ -215,6 +249,14 @@
|
|||
margin-top: 2px;
|
||||
}
|
||||
|
||||
#eventImageBar::after {
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
content: "";
|
||||
clear: both;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
#eventImageStats {
|
||||
float: left;
|
||||
}
|
||||
|
@ -230,6 +272,7 @@
|
|||
|
||||
#eventImageNav {
|
||||
position: relative;
|
||||
margin: 0 0 4px 0;
|
||||
}
|
||||
|
||||
#eventImageNav input {
|
||||
|
@ -238,20 +281,20 @@
|
|||
}
|
||||
|
||||
#thumbsSliderPanel {
|
||||
width: 400px;
|
||||
margin: 4px auto 0;
|
||||
background: #888888;
|
||||
padding: 1px;
|
||||
width: 80%;
|
||||
margin: 0px auto 4px auto;
|
||||
}
|
||||
|
||||
#thumbsSlider {
|
||||
width: 400px;
|
||||
height: 10px;
|
||||
background: #dddddd;
|
||||
width: 100%;
|
||||
height: 1.25em;
|
||||
position: relative;
|
||||
top: -1.25em;
|
||||
margin: 0 0 -1.25em 0;
|
||||
}
|
||||
|
||||
#thumbsKnob {
|
||||
width: 8px;
|
||||
height: 10px;
|
||||
background-color: #444444;
|
||||
width: 1em;
|
||||
height: 100%;
|
||||
background-color: #999999;
|
||||
}
|
||||
|
|
|
@ -1,33 +1,16 @@
|
|||
#scaleControl {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#controls {
|
||||
width: 80%;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#controls a {
|
||||
width: 40px;
|
||||
margin-left: -20px;
|
||||
}
|
||||
|
||||
#firstLink {
|
||||
position: absolute;
|
||||
left: 13%;
|
||||
}
|
||||
|
||||
#prevLink {
|
||||
position: absolute;
|
||||
left: 37%;
|
||||
}
|
||||
|
||||
#nextLink {
|
||||
position: absolute;
|
||||
left: 63%;
|
||||
}
|
||||
|
||||
#lastLink {
|
||||
position: absolute;
|
||||
left: 87%;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
|
||||
#monitors .alert {
|
||||
color: #ffa500;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#monitors .imageFeed {
|
||||
|
|
|
@ -12,6 +12,19 @@
|
|||
float: right;
|
||||
}
|
||||
|
||||
#systemStats .warning {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
#systemStats .error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#systemStats .critical {
|
||||
color: red;
|
||||
text-decoration: blink;
|
||||
}
|
||||
|
||||
#monitorSummary {
|
||||
float: left;
|
||||
text-align: left;
|
||||
|
|
|
@ -1,3 +1,39 @@
|
|||
#content .vjsMessage {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
margin: 0;
|
||||
font-size: 200%;
|
||||
color: white;
|
||||
background-color: black;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.alarmCue {
|
||||
background-color: #222222;
|
||||
height: 1.25em;
|
||||
text-align: left;
|
||||
margin: 0 auto 0 auto;
|
||||
border-radius: 0 0 .3em .3em;
|
||||
}
|
||||
|
||||
.alarmCue span {
|
||||
background-color:red;
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
span.noneCue {
|
||||
background: none;
|
||||
}
|
||||
|
||||
#eventVideo {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#dataBar {
|
||||
width: 100%;
|
||||
margin: 2px auto;
|
||||
|
@ -6,6 +42,7 @@
|
|||
|
||||
#dataBar #dataTable {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
#dataBar #dataTable td {
|
||||
|
@ -66,6 +103,8 @@
|
|||
}
|
||||
|
||||
#imageFeed {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
@ -130,39 +169,30 @@
|
|||
|
||||
#progressBar {
|
||||
position: relative;
|
||||
border: 1px solid #666666;
|
||||
height: 15px;
|
||||
margin: 0 auto;
|
||||
top: -1.25em;
|
||||
height: 1.25em;
|
||||
margin: 0 auto -1.25em auto;
|
||||
}
|
||||
|
||||
#progressBar .progressBox {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
height: 15px;
|
||||
background: #eeeeee;
|
||||
border-left: 1px solid #999999;
|
||||
}
|
||||
|
||||
#progressBar .complete {
|
||||
background: #aaaaaa;
|
||||
transition: width .1s;
|
||||
height: 100%;
|
||||
background: rgba(170, 170, 170, .7);
|
||||
border-radius: 0 0 .3em .3em;
|
||||
}
|
||||
|
||||
#eventStills {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#eventThumbsPanel {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
margin: 4px auto;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#eventThumbs {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
height: 300px;
|
||||
}
|
||||
|
@ -181,14 +211,19 @@
|
|||
}
|
||||
|
||||
#eventImagePanel {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#eventImageFrame {
|
||||
border: 2px solid gray;
|
||||
background-color: white;
|
||||
padding: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#eventImage {
|
||||
|
@ -198,6 +233,14 @@
|
|||
margin-top: 2px;
|
||||
}
|
||||
|
||||
#eventImageBar::after {
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
content: "";
|
||||
clear: both;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
#eventImageStats {
|
||||
float: left;
|
||||
}
|
||||
|
@ -213,6 +256,7 @@
|
|||
|
||||
#eventImageNav {
|
||||
position: relative;
|
||||
margin: 0 0 4px 0;
|
||||
}
|
||||
|
||||
#eventImageNav input {
|
||||
|
@ -222,19 +266,25 @@
|
|||
|
||||
#thumbsSliderPanel {
|
||||
width: 400px;
|
||||
margin: 4px auto 0;
|
||||
background: #888888;
|
||||
padding: 1px;
|
||||
width: 80%;
|
||||
margin: 0px auto 4px auto;
|
||||
}
|
||||
|
||||
#thumbsSlider {
|
||||
width: 400px;
|
||||
height: 10px;
|
||||
background: #dddddd;
|
||||
width: 100%;
|
||||
height: 1.25em;
|
||||
position: relative;
|
||||
top: -1.25em;
|
||||
margin: 0 0 -1.25em 0;
|
||||
}
|
||||
|
||||
#eventVideo {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#thumbsKnob {
|
||||
width: 8px;
|
||||
height: 10px;
|
||||
background-color: #444444;
|
||||
width: 1em;
|
||||
height: 100%;
|
||||
background-color: #999999;
|
||||
}
|
||||
|
|
|
@ -1,33 +1,16 @@
|
|||
#scaleControl {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#controls {
|
||||
width: 80%;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#controls a {
|
||||
width: 40px;
|
||||
margin-left: -20px;
|
||||
}
|
||||
|
||||
#firstLink {
|
||||
position: absolute;
|
||||
left: 13%;
|
||||
}
|
||||
|
||||
#prevLink {
|
||||
position: absolute;
|
||||
left: 37%;
|
||||
}
|
||||
|
||||
#nextLink {
|
||||
position: absolute;
|
||||
left: 63%;
|
||||
}
|
||||
|
||||
#lastLink {
|
||||
position: absolute;
|
||||
left: 87%;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
|
||||
#monitors .alert {
|
||||
color: #ffa500;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#monitors .imageFeed {
|
||||
|
|
|
@ -12,6 +12,19 @@
|
|||
float: right;
|
||||
}
|
||||
|
||||
#systemStats .warning {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
#systemStats .error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#systemStats .critical {
|
||||
color: red;
|
||||
text-decoration: blink;
|
||||
}
|
||||
|
||||
#monitorSummary {
|
||||
float: left;
|
||||
text-align: left;
|
||||
|
|
|
@ -1,3 +1,34 @@
|
|||
#content .vjsMessage {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
margin: 0;
|
||||
font-size: 200%;
|
||||
color: white;
|
||||
background-color: black;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.alarmCue {
|
||||
background-color: #222222;
|
||||
height: 1.25em;
|
||||
text-align: left;
|
||||
margin: 0 auto 0 auto;
|
||||
border-radius: 0 0 .3em .3em;
|
||||
}
|
||||
|
||||
.alarmCue span {
|
||||
background-color:red;
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
span.noneCue {
|
||||
background: none;
|
||||
}
|
||||
|
||||
#dataBar {
|
||||
width: 100%;
|
||||
margin: 2px auto;
|
||||
|
@ -6,6 +37,7 @@
|
|||
|
||||
#dataBar #dataTable {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
#dataBar #dataTable td {
|
||||
|
@ -64,7 +96,10 @@
|
|||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#imageFeed {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
@ -135,39 +170,30 @@
|
|||
|
||||
#progressBar {
|
||||
position: relative;
|
||||
border: 1px solid #666666;
|
||||
height: 15px;
|
||||
margin: 0 auto;
|
||||
top: -1.25em;
|
||||
height: 1.25em;
|
||||
margin: 0 auto -1.25em auto;
|
||||
}
|
||||
|
||||
#progressBar .progressBox {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
height: 15px;
|
||||
background: #eeeeee;
|
||||
border-left: 1px solid #999999;
|
||||
}
|
||||
|
||||
#progressBar .complete {
|
||||
background: #aaaaaa;
|
||||
transition: width .1s;
|
||||
height: 100%;
|
||||
background: rgba(170, 170, 170, .7);
|
||||
border-radius: 0 0 .3em .3em;
|
||||
}
|
||||
|
||||
#eventStills {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#eventThumbsPanel {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
margin: 4px auto;
|
||||
margin: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#eventThumbs {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
height: 300px;
|
||||
}
|
||||
|
@ -186,14 +212,19 @@
|
|||
}
|
||||
|
||||
#eventImagePanel {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#eventImageFrame {
|
||||
border: 2px solid gray;
|
||||
background-color: white;
|
||||
padding: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#eventImage {
|
||||
|
@ -216,8 +247,17 @@
|
|||
float: right;
|
||||
}
|
||||
|
||||
#eventImageBar::after {
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
content: "";
|
||||
clear: both;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
#eventImageNav {
|
||||
position: relative;
|
||||
margin: 0 0 4px 0;
|
||||
}
|
||||
|
||||
#eventImageNav input {
|
||||
|
@ -226,24 +266,25 @@
|
|||
}
|
||||
|
||||
#thumbsSliderPanel {
|
||||
width: 400px;
|
||||
margin: 4px auto 0;
|
||||
background: #888888;
|
||||
padding: 1px;
|
||||
width: 80%;
|
||||
margin: 0px auto 4px auto;
|
||||
}
|
||||
|
||||
#thumbsSlider {
|
||||
width: 400px;
|
||||
height: 10px;
|
||||
background: #dddddd;
|
||||
width: 100%;
|
||||
height: 1.25em;
|
||||
position: relative;
|
||||
top: -1.25em;
|
||||
margin: 0 0 -1.25em 0;
|
||||
}
|
||||
|
||||
#thumbsKnob {
|
||||
width: 8px;
|
||||
height: 10px;
|
||||
background-color: #444444;
|
||||
width: 1em;
|
||||
height: 100%;
|
||||
background-color: #999999;
|
||||
}
|
||||
#eventVideo {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
@ -274,10 +315,6 @@
|
|||
);
|
||||
}
|
||||
|
||||
#eventVideo:hover #video-controls {
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
button {
|
||||
background: rgba(0,0,0,.5);
|
||||
border: 0;
|
||||
|
|
|
@ -6,29 +6,11 @@
|
|||
width: 80%;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#controls a {
|
||||
width: 40px;
|
||||
margin-left: -20px;
|
||||
}
|
||||
|
||||
#firstLink {
|
||||
position: absolute;
|
||||
left: 13%;
|
||||
}
|
||||
|
||||
#prevLink {
|
||||
position: absolute;
|
||||
left: 37%;
|
||||
}
|
||||
|
||||
#nextLink {
|
||||
position: absolute;
|
||||
left: 63%;
|
||||
}
|
||||
|
||||
#lastLink {
|
||||
position: absolute;
|
||||
left: 87%;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
|
||||
#monitors .alert {
|
||||
color: #ffa500;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#monitors .imageFeed {
|
||||
|
|
|
@ -31,6 +31,7 @@ $rates = array(
|
|||
);
|
||||
|
||||
$scales = array(
|
||||
"auto" => translate("Scale to Fit"),
|
||||
"400" => "4x",
|
||||
"300" => "3x",
|
||||
"200" => "2x",
|
||||
|
@ -43,6 +44,8 @@ $scales = array(
|
|||
"12.5" => "1/8x",
|
||||
);
|
||||
|
||||
if (isset($_REQUEST['view']) && ($_REQUEST['view'] == 'montage')) unset($scales['auto']); //Remove auto if we aren't using event view
|
||||
|
||||
$bwArray = array(
|
||||
"high" => translate('High'),
|
||||
"medium" => translate('Medium'),
|
||||
|
|
|
@ -834,7 +834,7 @@ function exportFileList( $eid, $exportDetail, $exportFrames, $exportImages, $exp
|
|||
$filesLeft = array();
|
||||
foreach ( $files as $file )
|
||||
{
|
||||
if ( preg_match( "/\.(?:mpg|mpeg|avi|asf|3gp)$/", $file ) )
|
||||
if ( preg_match( '/\.(?:mpg|mpeg|mov|swf|mp4|mkv|avi|asf|3gp)$/', $file ) )
|
||||
{
|
||||
$exportFileList[$file] = $eventPath."/".$file;
|
||||
}
|
||||
|
|
|
@ -92,6 +92,7 @@ var $j = jQuery.noConflict();
|
|||
<?php } else if ( $title == 'Event' ) {
|
||||
?>
|
||||
<link href="skins/<?php echo $skin ?>/js/video-js.css" rel="stylesheet">
|
||||
<link href="skins/<?php echo $skin ?>/js/video-js-skin.css" rel="stylesheet">
|
||||
<script src="skins/<?php echo $skin ?>/js/video.js"></script>
|
||||
<script src="./js/videojs.zoomrotate.js"></script>
|
||||
<script src="skins/<?php echo $skin ?>/js/moment.min.js"></script>
|
||||
|
|
|
@ -262,6 +262,17 @@ function convertLabelFormat(LabelFormat, monitorName){
|
|||
}
|
||||
|
||||
function addVideoTimingTrack(video, LabelFormat, monitorName, duration, startTime){
|
||||
//This is a hacky way to handle changing the texttrack. If we ever upgrade vjs in a revamp replace this. Old method preserved because it's the right way.
|
||||
let cues = vid.textTracks()[0].cues();
|
||||
let labelFormat = convertLabelFormat(LabelFormat, monitorName);
|
||||
startTime = moment(startTime);
|
||||
|
||||
for (let i = 0; i <= duration; i++) {
|
||||
cues[i] = {id: i, index: i, startTime: i, Ca: i+1, text: startTime.format(labelFormat)};
|
||||
startTime.add(1, 's');
|
||||
}
|
||||
}
|
||||
/*
|
||||
var labelFormat = convertLabelFormat(LabelFormat, monitorName);
|
||||
var webvttformat = 'HH:mm:ss.SSS', webvttdata="WEBVTT\n\n";
|
||||
|
||||
|
@ -283,3 +294,37 @@ function addVideoTimingTrack(video, LabelFormat, monitorName, duration, startTim
|
|||
track.src = 'data:plain/text;charset=utf-8,'+encodeURIComponent(webvttdata);
|
||||
video.appendChild(track);
|
||||
}
|
||||
*/
|
||||
|
||||
var resizeTimer;
|
||||
|
||||
function endOfResize(e) {
|
||||
clearTimeout(resizeTimer);
|
||||
resizeTimer = setTimeout(changeScale, 250);
|
||||
}
|
||||
|
||||
function scaleToFit (baseWidth, baseHeight, scaleEl, bottomEl) {
|
||||
$j(window).on('resize', endOfResize) //set delayed scaling when Scale to Fit is selected
|
||||
let ratio = baseWidth / baseHeight;
|
||||
let container = $j('#content');
|
||||
let viewPort = $j(window);
|
||||
// jquery does not provide a bottom offet, and offset dows not include margins. outerHeight true minus false gives total vertical margins.
|
||||
let bottomLoc = bottomEl.offset().top + (bottomEl.outerHeight(true) - bottomEl.outerHeight()) + bottomEl.outerHeight(true);
|
||||
let newHeight = viewPort.height() - (bottomLoc - scaleEl.outerHeight(true))
|
||||
let newWidth = ratio * newHeight;
|
||||
if (newWidth > container.innerWidth()) {
|
||||
newWidth = container.innerWidth();
|
||||
newHeight = newWidth / ratio;
|
||||
}
|
||||
let autoScale = Math.round(newWidth / baseWidth * SCALE_BASE);
|
||||
let scales = $j('#scale option').map(function() {return parseInt($j(this).val());}).get();
|
||||
scales.shift();
|
||||
let closest;
|
||||
$j(scales).each(function () { //Set zms scale to nearest regular scale. Zoom does not like arbitrary scale values.
|
||||
if (closest == null || Math.abs(this - autoScale) < Math.abs(closest - autoScale)) {
|
||||
closest = this.valueOf();
|
||||
}
|
||||
});
|
||||
autoScale = closest;
|
||||
return {width: Math.floor(newWidth), height: Math.floor(newHeight), autoScale: autoScale};
|
||||
}
|
||||
|
|
|
@ -39,4 +39,4 @@ var refreshParent = <?php echo !empty($refreshParent)?'true':'false' ?>;
|
|||
|
||||
var focusWindow = <?php echo !empty($focusWindow)?'true':'false' ?>;
|
||||
|
||||
var imagePrefix = "<?php echo viewImagePath( "", '&' ) ?>";
|
||||
var imagePrefix = "<?php echo "?view=image&eid=" ?>";
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
.vjs-tech {
|
||||
pointer-events: none;
|
||||
transition: transform .25s;
|
||||
}
|
||||
|
||||
.vjs-captions-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vjs-tt-cue {
|
||||
margin-bottom: .75em;
|
||||
}
|
||||
|
||||
.vjs-menu {
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-playback-rate.vjs-menu-button .vjs-menu .vjs-menu-content {
|
||||
width: 5em;
|
||||
}
|
||||
|
||||
.vjs-default-skin.vjs-user-inactive:hover .vjs-progress-control {
|
||||
font-size: .3em;
|
||||
}
|
||||
|
||||
.vjs-default-skin.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
bottom: -2em;
|
||||
-webkit-transition: all .2s;
|
||||
-moz-transition: all .2s;
|
||||
-o-transition: all .2s;
|
||||
transition: all .2s
|
||||
}
|
||||
|
||||
.vjs-default-skin.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control,
|
||||
.vjs-default-skin.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-time-divider {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-progress-holder .vjs-play-progress, .vjs-default-skin .vjs-progress-holder .vjs-load-progress {
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.vjs-progress-holder.vjs-slider {
|
||||
background-color: transparent;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.vjs-progress-control.vjs-control {
|
||||
background-color: rgba(7, 20, 30, 0.8);
|
||||
height: 1.3em;
|
||||
top: -1.3em;
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.vjs-control div.alarmCue {
|
||||
position: relative;
|
||||
top: -1.3em;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.vjs-control .alarmCue {
|
||||
height: 1.3em;
|
||||
}
|
|
@ -154,7 +154,7 @@ xhtmlHeaders( __FILE__, translate('Console') );
|
|||
<input type="hidden" name="action" value=""/>
|
||||
<div id="header">
|
||||
<h3 id="systemTime"><?php echo preg_match( '/%/', DATE_FMT_CONSOLE_LONG )?strftime( DATE_FMT_CONSOLE_LONG ):date( DATE_FMT_CONSOLE_LONG ) ?></h3>
|
||||
<h3 id="systemStats"><?php echo translate('Load') ?>: <?php echo getLoad() ?> - <?php echo translate('Disk') ?>: <?php echo getDiskPercent() ?>% - <?php echo ZM_PATH_MAP ?>: <?php echo getDiskPercent(ZM_PATH_MAP) ?>%</h3>
|
||||
<h3 id="systemStats"><?php echo systemStats() ?></h3>
|
||||
<h2 id="title">
|
||||
<a href="http://www.zoneminder.com" target="ZoneMinder">ZoneMinder</a> <?php echo translate('Console') ?> -
|
||||
<?php echo makePopupLink( '?view=state', 'zmState', 'state', $status, canEdit( 'System' ) ) ?> -
|
||||
|
|
|
@ -43,6 +43,8 @@ else
|
|||
|
||||
if ( isset( $_REQUEST['scale'] ) ) {
|
||||
$scale = validInt($_REQUEST['scale']);
|
||||
} else if ( isset( $_COOKIE['zmEventScaleAuto'] ) ) { //If we're using scale to fit use it on all monitors
|
||||
$scale = 'auto';
|
||||
} else if ( isset( $_COOKIE['zmEventScale'.$Event->MonitorId()] ) ) {
|
||||
$scale = $_COOKIE['zmEventScale'.$Event->MonitorId()];
|
||||
} else {
|
||||
|
@ -61,6 +63,7 @@ if ( isset( $_REQUEST['streamMode'] ) )
|
|||
else
|
||||
$streamMode = 'video';
|
||||
|
||||
$replayMode = '';
|
||||
if ( isset( $_REQUEST['replayMode'] ) )
|
||||
$replayMode = validHtmlStr($_REQUEST['replayMode']);
|
||||
if ( isset( $_COOKIE['replayMode']) && preg_match('#^[a-z]+$#', $_COOKIE['replayMode']) )
|
||||
|
@ -84,10 +87,6 @@ parseSort();
|
|||
parseFilter( $_REQUEST['filter'] );
|
||||
$filterQuery = $_REQUEST['filter']['query'];
|
||||
|
||||
$panelSections = 40;
|
||||
$panelSectionWidth = (int)ceil(reScale($Event->Width(),$scale)/$panelSections);
|
||||
$panelWidth = ($panelSections*$panelSectionWidth-1);
|
||||
|
||||
$connkey = generateConnKey();
|
||||
|
||||
$focusWindow = true;
|
||||
|
@ -126,24 +125,25 @@ if ( canEdit( 'Events' ) ) {
|
|||
?>
|
||||
<div id="deleteEvent"><a href="#" onclick="deleteEvent()"><?php echo translate('Delete') ?></a></div>
|
||||
<div id="editEvent"><a href="#" onclick="editEvent()"><?php echo translate('Edit') ?></a></div>
|
||||
<div id="archiveEvent" class="hidden"><a href="#" onclick="archiveEvent()"><?php echo translate('Archive') ?></a></div>
|
||||
<div id="unarchiveEvent" class="hidden"><a href="#" onclick="unarchiveEvent()"><?php echo translate('Unarchive') ?></a></div>
|
||||
<div id="archiveEvent"<?php echo $Event->Archived == 1 ? ' class="hidden"' : '' ?>><a href="#" onclick="archiveEvent()"><?php echo translate('Archive') ?></a></div>
|
||||
<div id="unarchiveEvent"<?php echo $Event->Archived == 0 ? ' class="hidden"' : '' ?>><a href="#" onclick="unarchiveEvent()"><?php echo translate('Unarchive') ?></a></div>
|
||||
<?php
|
||||
} // end if can edit Events
|
||||
if ( $Event->DefaultVideo() ) { ?>
|
||||
<div id="downloadEventFile"><a href="<?php echo $Event->getStreamSrc()?>">Download MP4</a></div>
|
||||
?>
|
||||
<div id="framesEvent"><a href="#" onclick="showEventFrames()"><?php echo translate('Frames') ?></a></div>
|
||||
<div id="streamEvent" class="hidden"><a href="#" onclick="showStream()"><?php echo translate('Stream') ?></a></div>
|
||||
<div id="stillsEvent"><a href="#" onclick="showStills()"><?php echo translate('Stills') ?></a></div>
|
||||
<?php
|
||||
if ( $Event->DefaultVideo() ) {
|
||||
?>
|
||||
<div id="downloadEventFile"><a href="<?php echo $Event->getStreamSrc(array('mode'=>'mp4'))?>" download>Download MP4</a></div>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<div id="videoEvent"><a href="#" onclick="videoEvent();"><?php echo translate('Video') ?></a></div>
|
||||
<?php
|
||||
} // end if Event->DefaultVideo
|
||||
?>
|
||||
<div id="framesEvent"><a href="#" onclick="showEventFrames()"><?php echo translate('Frames') ?></a></div>
|
||||
<?php
|
||||
if ( $Event->SaveJPEGs() & 3 ) { // Analysis or Jpegs
|
||||
?>
|
||||
<div id="stillsEvent"<?php if ( $streamMode == 'still' ) { ?> class="hidden"<?php } ?>><a href="#" onclick="showStills()"><?php echo translate('Stills') ?></a></div>
|
||||
<?php
|
||||
} // has frames or analysis
|
||||
?>
|
||||
<div id="videoEvent"><a href="#" onclick="videoEvent();"><?php echo translate('Video') ?></a></div>
|
||||
<div id="exportEvent"><a href="#" onclick="exportEvent();"><?php echo translate('Export') ?></a></div>
|
||||
</div>
|
||||
<div id="eventVideo" class="">
|
||||
|
@ -151,23 +151,17 @@ if ( $Event->SaveJPEGs() & 3 ) { // Analysis or Jpegs
|
|||
if ( $Event->DefaultVideo() ) {
|
||||
?>
|
||||
<div id="videoFeed">
|
||||
<video id="videoobj" class="video-js vjs-default-skin" width="<?php echo reScale( $Event->Width(), $scale ) ?>" height="<?php echo reScale( $Event->Height(), $scale ) ?>" data-setup='{ "controls": true, "playbackRates": [0.5, 1, 1.5, 2, 4, 8, 16, 32, 64, 128, 256], "autoplay": true, "preload": "auto", "plugins": { "zoomrotate": { "zoom": "<?php echo $Zoom ?>"}}}'>
|
||||
<video id="videoobj" class="video-js vjs-default-skin" style="transform: matrix(1, 0, 0, 1, 0, 0)" width="<?php echo reScale( $Event->Width(), $scale ) ?>" height="<?php echo reScale( $Event->Height(), $scale ) ?>" data-setup='{ "controls": true, "autoplay": true, "preload": "auto", "plugins": { "zoomrotate": { "zoom": "<?php echo $Zoom ?>"}}}'>
|
||||
<source src="<?php echo $Event->getStreamSrc( array( 'mode'=>'mpeg','format'=>'h264' ) ); ?>" type="video/mp4">
|
||||
<track id="monitorCaption" kind="captions" label="English" srclang="en" src='data:plain/text;charset=utf-8,"WEBVTT\n\n 00:00:00.000 --> 00:00:01.000 ZoneMinder"' default>
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</div>
|
||||
<!--script>includeVideoJs();</script-->
|
||||
<script>
|
||||
var LabelFormat = "<?php echo validJsStr($Monitor->LabelFormat())?>";
|
||||
var monitorName = "<?php echo validJsStr($Monitor->Name())?>";
|
||||
var duration = <?php echo $Event->Length() ?>, startTime = '<?php echo $Event->StartTime() ?>';
|
||||
|
||||
addVideoTimingTrack(document.getElementById('videoobj'), LabelFormat, monitorName, duration, startTime);
|
||||
</script>
|
||||
</div><!--videoFeed-->
|
||||
<?php
|
||||
} // end if DefaultVideo
|
||||
?>
|
||||
<div id="imageFeed" <?php if ( $Event->DefaultVideo() ) { ?>class="hidden"<?php } ?> >
|
||||
<?php if (!$Event->DefaultVideo()) { ?>
|
||||
<div id="imageFeed">
|
||||
<?php
|
||||
if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
|
||||
$streamSrc = $Event->getStreamSrc( array( 'mode'=>'mpeg', 'scale'=>$scale, 'rate'=>$rate, 'bitrate'=>ZM_WEB_VIDEO_BITRATE, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'format'=>ZM_MPEG_REPLAY_FORMAT, 'replay'=>$replayMode ) );
|
||||
|
@ -181,34 +175,30 @@ if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
|
|||
}
|
||||
} // end if stream method
|
||||
?>
|
||||
</div>
|
||||
<div id="alarmCue" class="alarmCue"></div>
|
||||
<div id="progressBar" style="width: <?php echo reScale($Event->Width(), $scale);?>px;">
|
||||
<div class="progressBox" id="progressBox" title="" style="width: 0%;"></div>
|
||||
</div><!--progressBar-->
|
||||
</div><!--imageFeed-->
|
||||
<?php } /*end if !DefaultVideo*/ ?>
|
||||
<p id="dvrControls">
|
||||
<input type="button" value="<+" id="prevBtn" title="<?php echo translate('Prev') ?>" class="inactive" onclick="streamPrev( true );"/>
|
||||
<input type="button" value="<<" id="fastRevBtn" title="<?php echo translate('Rewind') ?>" class="inactive" disabled="disabled" onclick="streamFastRev( true );"/>
|
||||
<input type="button" value="<<" id="fastRevBtn" title="<?php echo translate('Rewind') ?>" class="inactive" onclick="streamFastRev( true );"/>
|
||||
<input type="button" value="<" id="slowRevBtn" title="<?php echo translate('StepBack') ?>" class="unavail" disabled="disabled" onclick="streamSlowRev( true );"/>
|
||||
<input type="button" value="||" id="pauseBtn" title="<?php echo translate('Pause') ?>" class="inactive" onclick="pauseClicked();"/>
|
||||
<input type="button" value="|>" id="playBtn" title="<?php echo translate('Play') ?>" class="active" disabled="disabled" onclick="playClicked();"/>
|
||||
<input type="button" value=">" id="slowFwdBtn" title="<?php echo translate('StepForward') ?>" class="unavail" disabled="disabled" onclick="streamSlowFwd( true );"/>
|
||||
<input type="button" value=">>" id="fastFwdBtn" title="<?php echo translate('FastForward') ?>" class="inactive" disabled="disabled" onclick="streamFastFwd( true );"/>
|
||||
<input type="button" value="–" id="zoomOutBtn" title="<?php echo translate('ZoomOut') ?>" class="avail" onclick="streamZoomOut();"/>
|
||||
<input type="button" value=">>" id="fastFwdBtn" title="<?php echo translate('FastForward') ?>" class="inactive" onclick="streamFastFwd( true );"/>
|
||||
<input type="button" value="–" id="zoomOutBtn" title="<?php echo translate('ZoomOut') ?>" class="unavail" disabled="disabled" onclick="streamZoomOut();"/>
|
||||
<input type="button" value="+>" id="nextBtn" title="<?php echo translate('Next') ?>" class="inactive" onclick="streamNext( true );"/>
|
||||
</p>
|
||||
<div id="replayStatus">
|
||||
<span id="mode"><?php echo translate('Mode') ?>: <span id="modeValue"> </span></span>
|
||||
<span id="rate"><?php echo translate('Rate') ?>: <span id="rateValue"></span>x</span>
|
||||
<span id="progress"><?php echo translate('Progress') ?>: <span id="progressValue"></span>s</span>
|
||||
<span id="zoom"><?php echo translate('Zoom') ?>: <span id="zoomValue"></span>x</span>
|
||||
<span id="mode"><?php echo translate('Mode') ?>: <span id="modeValue">Replay</span></span>
|
||||
<span id="rate"><?php echo translate('Rate') ?>: <span id="rateValue"><?php echo $rate/100 ?></span>x</span>
|
||||
<span id="progress"><?php echo translate('Progress') ?>: <span id="progressValue">0</span>s</span>
|
||||
<span id="zoom"><?php echo translate('Zoom') ?>: <span id="zoomValue">1</span>x</span>
|
||||
</div>
|
||||
<div id="progressBar" class="invisible">
|
||||
<?php for ( $i = 0; $i < $panelSections; $i++ ) { ?>
|
||||
<div class="progressBox" id="progressBox<?php echo $i ?>" title=""></div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
if ($Event->SaveJPEGs() & 3) { // frames or analysis
|
||||
?>
|
||||
</div><!--eventVideo-->
|
||||
<div id="eventStills" class="hidden">
|
||||
<div id="eventThumbsPanel">
|
||||
<div id="eventThumbs">
|
||||
|
@ -225,6 +215,13 @@ if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
|
|||
</div>
|
||||
</div>
|
||||
<div id="eventImageNav">
|
||||
<div id="thumbsSliderPanel">
|
||||
<div id="alarmCue" class="alarmCue"></div>
|
||||
<div id="thumbsSlider">
|
||||
<div id="thumbsKnob">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="eventImageButtons">
|
||||
<div id="prevButtonsPanel">
|
||||
<input id="prevEventBtn" type="button" value="<E" onclick="prevEvent()" disabled="disabled"/>
|
||||
|
@ -235,18 +232,12 @@ if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
|
|||
<input id="nextEventBtn" type="button" value="E>" onclick="nextEvent()" disabled="disabled"/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="thumbsSliderPanel">
|
||||
<div id="thumbsSlider">
|
||||
<div id="thumbsKnob">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
} // end if SaveJPEGs() & 3 Analysis or Jpegs
|
||||
} // end if Event exists
|
||||
?>
|
||||
</div><!--content-->
|
||||
</div><!--page-->
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -51,7 +51,7 @@ $lastFid = $maxFid;
|
|||
$alarmFrame = $Frame->Type()=='Alarm';
|
||||
|
||||
if ( isset( $_REQUEST['scale'] ) ) {
|
||||
$scale = validInt($_REQUEST['scale']);
|
||||
$scale = $_REQUEST['scale'];
|
||||
} else if ( isset( $_COOKIE['zmWatchScale'.$Monitor->Id()] ) ) {
|
||||
$scale = $_COOKIE['zmWatchScale'.$Monitor->Id()];
|
||||
} else if ( isset( $_COOKIE['zmWatchScale'] ) ) {
|
||||
|
|
|
@ -88,7 +88,7 @@ $j( function() {
|
|||
function applySort(event, ui) {
|
||||
var monitor_ids = $j(this).sortable('toArray');
|
||||
var ajax = new Request.JSON( {
|
||||
url: '/index.php?request=console',
|
||||
url: 'index.php?request=console',
|
||||
data: { monitor_ids: monitor_ids, action: 'sort' },
|
||||
method: 'post',
|
||||
timeout: AJAX_TIMEOUT
|
||||
|
|
|
@ -1,31 +1,179 @@
|
|||
var vid = null;
|
||||
|
||||
function vjsReplay() {
|
||||
let endTime = (Date.parse(eventData.EndTime)).getTime();
|
||||
switch(replayMode.value) {
|
||||
case 'none':
|
||||
break;
|
||||
case 'single':
|
||||
player.play();
|
||||
break;
|
||||
case 'all':
|
||||
if (nextEventId == 0) {
|
||||
let overLaid = $j("#videoobj");
|
||||
overLaid.append('<p class="vjsMessage" style="height: '+overLaid.height()+'px; line-height: '+overLaid.height()+'px;">No more events</p>');
|
||||
} else {
|
||||
let nextStartTime = nextEventStartTime.getTime(); //nextEventStartTime.getTime() is a mootools workaround, highjacks Date.parse
|
||||
if (nextStartTime <= endTime) {
|
||||
streamNext( true );
|
||||
return;
|
||||
}
|
||||
let overLaid = $j("#videoobj");
|
||||
vid.pause();
|
||||
overLaid.append('<p class="vjsMessage" style="height: '+overLaid.height()+'px; line-height: '+overLaid.height()+'px;"></p>');
|
||||
let gapDuration = (new Date().getTime()) + (nextStartTime - endTime);
|
||||
let messageP = $j(".vjsMessage");
|
||||
let x = setInterval(function() {
|
||||
let now = new Date().getTime();
|
||||
let remainder = new Date(Math.round(gapDuration - now)).toISOString().substr(11,8);
|
||||
messageP.html(remainder + ' to next event.');
|
||||
if (remainder < 0) {
|
||||
clearInterval(x);
|
||||
streamNext( true );
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
break;
|
||||
case 'gapless':
|
||||
streamNext( true );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$j.ajaxSetup ({timeout: AJAX_TIMEOUT }); //sets timeout for all getJSON.
|
||||
|
||||
var cueFrames = null; //make cueFrames availaible even if we don't send another ajax query
|
||||
|
||||
function initialAlarmCues (eventId) {
|
||||
$j.getJSON(thisUrl + '?view=request&request=status&entity=frames&id=' + eventId, setAlarmCues); //get frames data for alarmCues and inserts into html
|
||||
}
|
||||
|
||||
function setAlarmCues (data) {
|
||||
cueFrames = data.frames;
|
||||
alarmSpans = renderAlarmCues(vid ? $j("#videoobj") : $j("#evtStream"));//use videojs width or zms width
|
||||
$j(".alarmCue").html(alarmSpans);
|
||||
}
|
||||
|
||||
function renderAlarmCues (containerEl) {
|
||||
if (cueFrames) {
|
||||
var cueRatio = containerEl.width() / (cueFrames[cueFrames.length - 1].Delta * 100);
|
||||
var minAlarm = Math.ceil(1/cueRatio);
|
||||
var spanTimeStart = 0;
|
||||
var spanTimeEnd = 0;
|
||||
var alarmed = 0;
|
||||
var alarmHtml = "";
|
||||
var pixSkew = 0;
|
||||
var skip = 0;
|
||||
for (let i = 0; i < cueFrames.length; i++) {
|
||||
skip = 0;
|
||||
frame = cueFrames[i];
|
||||
if (frame.Type == "Alarm" && alarmed == 0) { //From nothing to alarm. End nothing and start alarm.
|
||||
alarmed = 1;
|
||||
if (frame.Delta == 0) continue; //If event starts with an alarm or too few for a nonespan
|
||||
spanTimeEnd = frame.Delta * 100;
|
||||
spanTime = spanTimeEnd - spanTimeStart;
|
||||
let pix = cueRatio * spanTime;
|
||||
pixSkew += pix - Math.round(pix);//average out the rounding errors.
|
||||
pix = Math.round(pix);
|
||||
if ((pixSkew > 1 || pixSkew < -1) && pix + Math.round(pixSkew) > 0) { //add skew if it's a pixel and won't zero out span.
|
||||
pix += Math.round(pixSkew);
|
||||
pixSkew = pixSkew - Math.round(pixSkew);
|
||||
}
|
||||
alarmHtml += '<span class="alarmCue noneCue" style="width: ' + pix + 'px;"></span>';
|
||||
spanTimeStart = spanTimeEnd;
|
||||
} else if (frame.Type !== "Alarm" && alarmed == 1) { //from alarm to nothing. End alarm and start nothing.
|
||||
futNone = 0;
|
||||
indexPlus = i+1;
|
||||
if (((frame.Delta * 100) - spanTimeStart) < minAlarm && indexPlus < cueFrames.length) continue; //alarm is too short and there is more event
|
||||
while (futNone < minAlarm) { //check ahead to see if there's enough for a nonespan
|
||||
if (indexPlus >= cueFrames.length) break; //check if end of event.
|
||||
futNone = (cueFrames[indexPlus].Delta *100) - (frame.Delta *100);
|
||||
if (cueFrames[indexPlus].Type == "Alarm") {
|
||||
i = --indexPlus;
|
||||
skip = 1;
|
||||
break;
|
||||
}
|
||||
indexPlus++;
|
||||
}
|
||||
if (skip == 1) continue; //javascript doesn't support continue 2;
|
||||
spanTimeEnd = frame.Delta *100;
|
||||
spanTime = spanTimeEnd - spanTimeStart;
|
||||
alarmed = 0;
|
||||
pix = cueRatio * spanTime;
|
||||
pixSkew += pix - Math.round(pix);
|
||||
pix = Math.round(pix);
|
||||
if ((pixSkew > 1 || pixSkew < -1) && pix + Math.round(pixSkew) > 0) {
|
||||
pix += Math.round(pixSkew);
|
||||
pixSkew = pixSkew - Math.round(pixSkew);
|
||||
}
|
||||
alarmHtml += '<span class="alarmCue" style="width: ' + pix + 'px;"></span>';
|
||||
spanTimeStart = spanTimeEnd;
|
||||
} else if (frame.Type == "Alarm" && alarmed == 1 && i + 1 >= cueFrames.length) { //event ends on an alarm
|
||||
spanTimeEnd = frame.Delta * 100;
|
||||
spanTime = spanTimeEnd - spanTimeStart;
|
||||
alarmed = 0;
|
||||
pix = Math.round(cueRatio * spanTime);
|
||||
if (pixSkew >= .5 || pixSkew <= -.5) pix += Math.round(pixSkew);
|
||||
alarmHtml += '<span class="alarmCue" style="width: ' + pix + 'px;"></span>';
|
||||
}
|
||||
}
|
||||
return alarmHtml;
|
||||
}
|
||||
}
|
||||
|
||||
function setButtonState( element, butClass ) {
|
||||
if ( element ) {
|
||||
element.className = butClass;
|
||||
element.disabled = (butClass != 'inactive');
|
||||
if (butClass == 'unavail' || (butClass == 'active' && (element.id == 'pauseBtn' || element.id == 'playBtn'))) {
|
||||
element.disabled = true;
|
||||
} else {
|
||||
element.disabled = false;
|
||||
}
|
||||
} else {
|
||||
console.log("Element was null in setButtonState");
|
||||
}
|
||||
}
|
||||
|
||||
function changeScale() {
|
||||
var scale = $('scale').get('value');
|
||||
var baseWidth = eventData.Width;
|
||||
var baseHeight = eventData.Height;
|
||||
var newWidth = ( baseWidth * scale ) / SCALE_BASE;
|
||||
var newHeight = ( baseHeight * scale ) / SCALE_BASE;
|
||||
|
||||
if ( vid ) {
|
||||
// Using video.js
|
||||
vid.width = newWidth;
|
||||
vid.height = newHeight;
|
||||
let scale = $j('#scale').val();
|
||||
let newWidth;
|
||||
let newHeight;
|
||||
let autoScale;
|
||||
let eventViewer;
|
||||
let alarmCue = $j('div.alarmCue');
|
||||
let bottomEl = streamMode == 'stills' ? $j('#eventImageNav') : $j('#replayStatus');
|
||||
if (streamMode == 'stills') {
|
||||
eventViewer = $j('#eventThumbs');
|
||||
} else {
|
||||
eventViewer = $j(vid ? '#videoobj' : '#evtStream');
|
||||
}
|
||||
if (scale == "auto") {
|
||||
let newSize = scaleToFit(eventData.Width, eventData.Height, eventViewer, bottomEl);
|
||||
newWidth = newSize.width;
|
||||
newHeight = newSize.height;
|
||||
autoScale = newSize.autoScale;
|
||||
} else {
|
||||
$j(window).off('resize', endOfResize); //remove resize handler when Scale to Fit is not active
|
||||
newWidth = eventData.Width * scale / SCALE_BASE;
|
||||
newHeight = eventData.Height * scale / SCALE_BASE;
|
||||
}
|
||||
if (!(streamMode == 'stills')) eventViewer.width(newWidth); //stills handles its own width
|
||||
eventViewer.height(newHeight);
|
||||
if ( !vid ) { // zms needs extra sizing
|
||||
streamScale(scale == "auto" ? autoScale : scale);
|
||||
drawProgressBar();
|
||||
}
|
||||
if (streamMode == 'stills') {
|
||||
slider.autosize();
|
||||
alarmCue.html(renderAlarmCues($j('#thumbsSliderPanel')));
|
||||
} else {
|
||||
alarmCue.html(renderAlarmCues(eventViewer));//just re-render alarmCues. skip ajax call
|
||||
}
|
||||
if (scale == "auto") {
|
||||
Cookie.write('zmEventScaleAuto', 'auto', {duration: 10*365});
|
||||
}else{
|
||||
streamScale( scale );
|
||||
var streamImg = document.getElementById('evtStream');
|
||||
streamImg.style.width = newWidth + "px";
|
||||
streamImg.style.height = newHeight + "px";
|
||||
Cookie.write('zmEventScale'+eventData.MonitorId, scale, {duration: 10*365});
|
||||
Cookie.dispose('zmEventScaleAuto');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,33 +190,38 @@ var streamCmdTimer = null;
|
|||
|
||||
var streamStatus = null;
|
||||
var lastEventId = 0;
|
||||
var zmsBroke = false; //Use alternate navigation if zms has crashed
|
||||
|
||||
function getCmdResponse( respObj, respText ) {
|
||||
if ( checkStreamForErrors( "getCmdResponse", respObj ) )
|
||||
if ( checkStreamForErrors( "getCmdResponse", respObj ) ) {
|
||||
console.log('Got an error from getCmdResponse');
|
||||
zmsBroke = true;
|
||||
return;
|
||||
}
|
||||
|
||||
zmsBroke = false;
|
||||
|
||||
if ( streamCmdTimer )
|
||||
streamCmdTimer = clearTimeout( streamCmdTimer );
|
||||
|
||||
streamStatus = respObj.status;
|
||||
if (streamStatus.progress >= Math.round(parseFloat(eventData.Length))) streamStatus.progress = parseFloat(eventData.Length); //Limit progress to reality
|
||||
|
||||
var eventId = streamStatus.event;
|
||||
if ( eventId != lastEventId ) {
|
||||
if ( eventId != lastEventId && lastEventId != 0) { //Doesn't run on first load, prevents a double hit on event and nearEvents ajax
|
||||
eventQuery( eventId );
|
||||
initialAlarmCues(eventId);
|
||||
lastEventId = eventId;
|
||||
}
|
||||
if (lastEventId == 0) lastEventId = eventId; //Only fires on first load.
|
||||
if ( streamStatus.paused == true ) {
|
||||
$('modeValue').set( 'text', 'Paused' );
|
||||
$('rate').addClass( 'hidden' );
|
||||
streamPause( );
|
||||
} else {
|
||||
$('modeValue').set( 'text', "Replay" );
|
||||
$('rateValue').set( 'text', streamStatus.rate );
|
||||
$('rate').removeClass( 'hidden' );
|
||||
$j('#rateValue').html(streamStatus.rate);
|
||||
streamPlay( );
|
||||
}
|
||||
$('progressValue').set( 'text', secsToTime( parseInt(streamStatus.progress) ) );
|
||||
$('zoomValue').set( 'text', streamStatus.zoom );
|
||||
$j('#progressValue').html(secsToTime(parseInt(streamStatus.progress)));
|
||||
$j('#zoomValue').html(streamStatus.zoom);
|
||||
if ( streamStatus.zoom == "1.0" )
|
||||
setButtonState( $('zoomOutBtn'), 'unavail' );
|
||||
else
|
||||
|
@ -83,17 +236,29 @@ function getCmdResponse( respObj, respText ) {
|
|||
streamImg.src = streamImg.src.replace( /auth=\w+/i, 'auth='+streamStatus.auth );
|
||||
} // end if haev a new auth hash
|
||||
|
||||
streamCmdTimer = streamQuery.delay( streamTimeout );
|
||||
streamCmdTimer = streamQuery.delay( streamTimeout ); //Timeout is refresh rate for progressBox and time display
|
||||
}
|
||||
|
||||
var streamReq = new Request.JSON( { url: thisUrl, method: 'get', timeout: AJAX_TIMEOUT, link: 'chain', onSuccess: getCmdResponse } );
|
||||
|
||||
function pauseClicked() {
|
||||
if (vid) {
|
||||
vid.pause();
|
||||
} else {
|
||||
streamReq.send( streamParms+"&command="+CMD_PAUSE );
|
||||
streamPause();
|
||||
}
|
||||
}
|
||||
|
||||
function vjsPause () {
|
||||
stopFastRev();
|
||||
streamPause();
|
||||
}
|
||||
|
||||
// Called when stream becomes paused, just updates the button status
|
||||
function streamPause( ) {
|
||||
$j('#modeValue').html('Paused');
|
||||
$j('#rateValue').html('0');
|
||||
setButtonState( $('pauseBtn'), 'active' );
|
||||
setButtonState( $('playBtn'), 'inactive' );
|
||||
setButtonState( $('fastFwdBtn'), 'unavail' );
|
||||
|
@ -103,13 +268,28 @@ function streamPause( ) {
|
|||
}
|
||||
|
||||
function playClicked( ) {
|
||||
if (vid) {
|
||||
if (vid.paused()) {
|
||||
vid.play();
|
||||
} else {
|
||||
vjsPlay(); //handles fast forward and rewind
|
||||
}
|
||||
} else {
|
||||
streamReq.send( streamParms+"&command="+CMD_PLAY );
|
||||
streamPlay();
|
||||
}
|
||||
}
|
||||
|
||||
function vjsPlay () { //catches if we change mode programatically
|
||||
stopFastRev();
|
||||
$j('#rateValue').html(vid.playbackRate());
|
||||
streamPlay();
|
||||
}
|
||||
|
||||
function streamPlay( ) {
|
||||
$j('#modeValue').html('Replay');
|
||||
setButtonState( $('pauseBtn'), 'inactive' );
|
||||
if (streamStatus)
|
||||
setButtonState( $('playBtn'), streamStatus.rate==1?'active':'inactive' );
|
||||
setButtonState( $('playBtn'), 'active' );
|
||||
setButtonState( $('fastFwdBtn'), 'inactive' );
|
||||
setButtonState( $('slowFwdBtn'), 'unavail' );
|
||||
setButtonState( $('slowRevBtn'), 'unavail' );
|
||||
|
@ -119,35 +299,44 @@ function streamPlay( ) {
|
|||
function streamFastFwd( action ) {
|
||||
setButtonState( $('pauseBtn'), 'inactive' );
|
||||
setButtonState( $('playBtn'), 'inactive' );
|
||||
setButtonState( $('fastFwdBtn'), 'inactive' );
|
||||
setButtonState( $('fastFwdBtn'), 'active' );
|
||||
setButtonState( $('slowFwdBtn'), 'unavail' );
|
||||
setButtonState( $('slowRevBtn'), 'unavail' );
|
||||
setButtonState( $('fastRevBtn'), 'inactive' );
|
||||
if (vid) {
|
||||
if (revSpeed != .5) stopFastRev();
|
||||
vid.playbackRate(rates[rates.indexOf(vid.playbackRate()*100)-1]/100);
|
||||
if (rates.indexOf(vid.playbackRate()*100)-1 == -1) setButtonState($('fastFwdBtn'), 'unavail');
|
||||
$j('#rateValue').html(vid.playbackRate());
|
||||
} else {
|
||||
streamReq.send( streamParms+"&command="+CMD_FASTFWD );
|
||||
}
|
||||
}
|
||||
|
||||
var spf = Math.round((eventData.Length / eventData.Frames)*1000000 )/1000000;//Seconds per frame for videojs frame by frame.
|
||||
var intervalRewind;
|
||||
var revSpeed = .5;
|
||||
|
||||
function streamSlowFwd( action ) {
|
||||
setButtonState( $('pauseBtn'), 'inactive' );
|
||||
setButtonState( $('playBtn'), 'inactive' );
|
||||
setButtonState( $('fastFwdBtn'), 'unavail' );
|
||||
setButtonState( $('slowFwdBtn'), 'active' );
|
||||
setButtonState( $('slowRevBtn'), 'inactive' );
|
||||
setButtonState( $('fastRevBtn'), 'unavail' );
|
||||
if (vid) {
|
||||
vid.currentTime(vid.currentTime() + spf);
|
||||
} else {
|
||||
streamReq.send( streamParms+"&command="+CMD_SLOWFWD );
|
||||
setButtonState( $('pauseBtn'), 'inactive' );
|
||||
setButtonState( $('slowFwdBtn'), 'inactive' );
|
||||
}
|
||||
}
|
||||
|
||||
function streamSlowRev( action ) {
|
||||
setButtonState( $('pauseBtn'), 'inactive' );
|
||||
setButtonState( $('playBtn'), 'inactive' );
|
||||
setButtonState( $('fastFwdBtn'), 'unavail' );
|
||||
setButtonState( $('slowFwdBtn'), 'inactive' );
|
||||
setButtonState( $('slowRevBtn'), 'active' );
|
||||
setButtonState( $('fastRevBtn'), 'unavail' );
|
||||
if (vid) {
|
||||
vid.currentTime(vid.currentTime() - spf);
|
||||
} else {
|
||||
streamReq.send( streamParms+"&command="+CMD_SLOWREV );
|
||||
setButtonState( $('pauseBtn'), 'inactive' );
|
||||
setButtonState( $('slowRevBtn'), 'inactive' );
|
||||
}
|
||||
}
|
||||
|
||||
function stopFastRev () {
|
||||
clearInterval(intervalRewind);
|
||||
vid.playbackRate(1);
|
||||
revSpeed = .5;
|
||||
}
|
||||
|
||||
function streamFastRev( action ) {
|
||||
|
@ -156,35 +345,134 @@ function streamFastRev( action ) {
|
|||
setButtonState( $('fastFwdBtn'), 'inactive' );
|
||||
setButtonState( $('slowFwdBtn'), 'unavail' );
|
||||
setButtonState( $('slowRevBtn'), 'unavail' );
|
||||
setButtonState( $('fastRevBtn'), 'inactive' );
|
||||
setButtonState( $('fastRevBtn'), 'active' );
|
||||
if (vid) { //There is no reverse play with mp4. Set the speed to 0 and manualy set the time back.
|
||||
revSpeed = rates[rates.indexOf(revSpeed*100)-1]/100;
|
||||
if (rates.indexOf(revSpeed*100) == 0) {
|
||||
setButtonState( $('fastRevBtn'), 'unavail' );
|
||||
}
|
||||
clearInterval(intervalRewind);
|
||||
$j('#rateValue').html(-revSpeed);
|
||||
intervalRewind = setInterval(function() {
|
||||
if (vid.currentTime() <= 0) {
|
||||
clearInterval(intervalRewind);
|
||||
vid.pause();
|
||||
} else {
|
||||
vid.playbackRate(0);
|
||||
vid.currentTime(vid.currentTime() - (revSpeed/2)); //Half of reverse speed because our interval is 500ms.
|
||||
}
|
||||
}, 500); //500ms is a compromise between smooth reverse and realistic performance
|
||||
} else {
|
||||
streamReq.send( streamParms+"&command="+CMD_FASTREV );
|
||||
}
|
||||
}
|
||||
|
||||
function streamPrev(action) {
|
||||
if ( action )
|
||||
if (action) {
|
||||
$j(".vjsMessage").remove();
|
||||
if (vid && PrevEventDefVideoPath.indexOf("view_video") > 0) {
|
||||
CurEventDefVideoPath = PrevEventDefVideoPath;
|
||||
eventQuery(prevEventId);
|
||||
} else if (zmsBroke || (vid && PrevEventDefVideoPath.indexOf("view_video") < 0) || $j("#vjsMessage").length || PrevEventDefVideoPath.indexOf("view_video") > 0) {//zms broke, leaving videojs, last event, moving to videojs
|
||||
location.replace(thisUrl + '?view=event&eid=' + prevEventId + filterQuery + sortQuery);
|
||||
} else {
|
||||
streamReq.send(streamParms+"&command="+CMD_PREV);
|
||||
streamPlay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function streamNext(action) {
|
||||
if ( action )
|
||||
if (action) {
|
||||
$j(".vjsMessage").remove();//This shouldn't happen
|
||||
if (nextEventId == 0) { //handles deleting last event.
|
||||
pauseClicked();
|
||||
let hideContainer = $j('#eventVideo');
|
||||
let hideStream = $j(vid ? "#videoobj" : "#evtStream").height() + (vid ? 0 :$j("#progressBar").height());
|
||||
hideContainer.prepend('<p class="vjsMessage" style="height: ' + hideStream + 'px; line-height: ' + hideStream + 'px;">No more events</p>');
|
||||
if (vid == null) zmsBroke = true;
|
||||
return;
|
||||
}
|
||||
if (vid && NextEventDefVideoPath.indexOf("view_video") > 0) { //on and staying with videojs
|
||||
CurEventDefVideoPath = NextEventDefVideoPath;
|
||||
eventQuery(nextEventId);
|
||||
} else if (zmsBroke || (vid && NextEventDefVideoPath.indexOf("view_video") < 0) || NextEventDefVideoPath.indexOf("view_video") > 0) {//reload zms, leaving vjs, moving to vjs
|
||||
location.replace(thisUrl + '?view=event&eid=' + nextEventId + filterQuery + sortQuery);
|
||||
} else {
|
||||
streamReq.send(streamParms+"&command="+CMD_NEXT);
|
||||
streamPlay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function vjsPanZoom (action, x, y) { //Pan and zoom with centering where the click occurs
|
||||
let outer = $j('#videoobj');
|
||||
let video = outer.children().first();
|
||||
let zoom = parseFloat($j('#zoomValue').html());
|
||||
let zoomRate = .5;
|
||||
let matrix = video.css('transform').split(',');
|
||||
let currentPanX = parseFloat(matrix[4]);
|
||||
let currentPanY = parseFloat(matrix[5]);
|
||||
let xDist = outer.width()/2 - x //Click distance from center of view
|
||||
let yDist = outer.height()/2 - y
|
||||
if (action == 'zoomOut') {
|
||||
zoom -= zoomRate;
|
||||
if (x && y) {
|
||||
x = (xDist + currentPanX)*((zoom-zoomRate)/zoom); // if ctrl-click Pan but use ratio of old zoom to new zoom for coords
|
||||
y = (yDist + currentPanY)*((zoom-zoomRate)/zoom);
|
||||
} else {
|
||||
x = currentPanX*((zoom-zoomRate)/zoom); //Leave zoom centered where it was
|
||||
y = currentPanY*((zoom-zoomRate)/zoom);
|
||||
}
|
||||
if (zoom <= 1) {
|
||||
zoom = 1;
|
||||
$j('#zoomOutBtn').attr('class', 'unavail').attr('disabled', 'disabled');
|
||||
}
|
||||
$j('#zoomValue').html(zoom);
|
||||
} else if (action == 'zoom') {
|
||||
zoom += zoomRate;
|
||||
x = (xDist + currentPanX)*(zoom/(zoom-zoomRate)); //Pan but use ratio of new zoom to old zoom for coords. Center on mouse click.
|
||||
y = (yDist + currentPanY)*(zoom/(zoom-zoomRate));
|
||||
$j('#zoomOutBtn').attr('class', 'inactive').removeAttr('disabled');
|
||||
$j('#zoomValue').html(zoom);
|
||||
} else if (action == 'pan') {
|
||||
x = xDist + currentPanX;
|
||||
y = yDist + currentPanY;
|
||||
}
|
||||
let limitX = ((zoom*outer.width()) - outer.width())/2; //Calculate outer bounds of video
|
||||
let limitY = ((zoom*outer.height()) - outer.height())/2;
|
||||
x = Math.min(Math.max((x),-limitX),limitX); //Limit pan to outer bounds of video
|
||||
y = Math.min(Math.max((y),-limitY),limitY);
|
||||
video.css('transform', 'matrix('+zoom+', 0, 0, '+zoom+', '+x+', '+y+')');
|
||||
}
|
||||
|
||||
function streamZoomIn( x, y ) {
|
||||
if (vid) {
|
||||
vjsPanZoom('zoom', x, y);
|
||||
} else {
|
||||
streamReq.send( streamParms+"&command="+CMD_ZOOMIN+"&x="+x+"&y="+y );
|
||||
}
|
||||
}
|
||||
|
||||
function streamZoomOut() {
|
||||
if (vid) {
|
||||
vjsPanZoom('zoomOut');
|
||||
} else {
|
||||
streamReq.send( streamParms+"&command="+CMD_ZOOMOUT );
|
||||
}
|
||||
}
|
||||
|
||||
function streamScale( scale ) {
|
||||
streamReq.send( streamParms+"&command="+CMD_SCALE+"&scale="+scale );
|
||||
}
|
||||
|
||||
function streamPan( x, y ) {
|
||||
if (vid) {
|
||||
vjsPanZoom('pan', x, y);
|
||||
} else {
|
||||
streamReq.send( streamParms+"&command="+CMD_PAN+"&x="+x+"&y="+y );
|
||||
}
|
||||
}
|
||||
|
||||
function streamSeek( offset ) {
|
||||
streamReq.send( streamParms+"&command="+CMD_SEEK+"&offset="+offset );
|
||||
|
@ -196,6 +484,8 @@ function streamQuery() {
|
|||
|
||||
var slider = null;
|
||||
var scroll = null;
|
||||
var currEventId = null;
|
||||
var CurEventDefVideoPath = null;
|
||||
|
||||
function getEventResponse( respObj, respText ) {
|
||||
if ( checkStreamForErrors( "getEventResponse", respObj ) )
|
||||
|
@ -220,7 +510,7 @@ function getEventResponse( respObj, respText ) {
|
|||
$('dataFrames').set( 'text', eventData.Frames+"/"+eventData.AlarmFrames );
|
||||
$('dataScore').set( 'text', eventData.TotScore+"/"+eventData.AvgScore+"/"+eventData.MaxScore );
|
||||
$('eventName').setProperty( 'value', eventData.Name );
|
||||
|
||||
history.replaceState(null, null, '?view=event&eid=' + eventData.Id + filterQuery + sortQuery);//if popup removed, check if this allows forward
|
||||
if ( canEditEvents ) {
|
||||
if ( parseInt(eventData.Archived) ) {
|
||||
$('archiveEvent').addClass( 'hidden' );
|
||||
|
@ -232,7 +522,18 @@ function getEventResponse( respObj, respText ) {
|
|||
}
|
||||
//var eventImg = $('eventImage');
|
||||
//eventImg.setStyles( { 'width': eventData.width, 'height': eventData.height } );
|
||||
if (vid && CurEventDefVideoPath) {
|
||||
vid.src({type: 'video/mp4', src: CurEventDefVideoPath}); //Currently mp4 is all we use
|
||||
initialAlarmCues(eventData.Id);//ajax and render, new event
|
||||
addVideoTimingTrack(vid, LabelFormat, eventData.MonitorName, eventData.Length, eventData.StartTime);
|
||||
CurEventDefVideoPath = null;
|
||||
$j('#modeValue').html('Replay');
|
||||
$j('#zoomValue').html('1');
|
||||
$j('#rateValue').html('1');
|
||||
vjsPanZoom('zoomOut');
|
||||
} else {
|
||||
drawProgressBar();
|
||||
}
|
||||
nearEventsQuery( eventData.Id );
|
||||
}
|
||||
|
||||
|
@ -245,6 +546,8 @@ function eventQuery( eventId ) {
|
|||
|
||||
var prevEventId = 0;
|
||||
var nextEventId = 0;
|
||||
var prevEventStartTime = 0;
|
||||
var nextEventStartTime = 0;
|
||||
var PrevEventDefVideoPath = "";
|
||||
var NextEventDefVideoPath = "";
|
||||
|
||||
|
@ -253,6 +556,8 @@ function getNearEventsResponse( respObj, respText ) {
|
|||
return;
|
||||
prevEventId = respObj.nearevents.PrevEventId;
|
||||
nextEventId = respObj.nearevents.NextEventId;
|
||||
prevEventStartTime = Date.parse(respObj.nearevents.PrevEventStartTime);
|
||||
nextEventStartTime = Date.parse(respObj.nearevents.NextEventStartTime);
|
||||
PrevEventDefVideoPath = respObj.nearevents.PrevEventDefVideoPath;
|
||||
NextEventDefVideoPath = respObj.nearevents.NextEventDefVideoPath;
|
||||
|
||||
|
@ -260,12 +565,14 @@ function getNearEventsResponse( respObj, respText ) {
|
|||
if ( prevEventBtn ) prevEventBtn.disabled = !prevEventId;
|
||||
var nextEventBtn = $('nextEventBtn');
|
||||
if ( nextEventBtn ) nextEventBtn.disabled = !nextEventId;
|
||||
$j('#prevBtn').prop('disabled', prevEventId == 0 ? true : false).attr('class', prevEventId == 0 ? 'unavail' : 'inactive');
|
||||
$j('#nextBtn').prop('disabled', nextEventId == 0 ? true : false).attr('class', nextEventId == 0 ? 'unavail' : 'inactive');
|
||||
}
|
||||
|
||||
var nearEventsReq = new Request.JSON( { url: thisUrl, method: 'get', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getNearEventsResponse } );
|
||||
|
||||
function nearEventsQuery( eventId ) {
|
||||
var parms = "view=request&request=status&entity=nearevents&id="+eventId;
|
||||
var parms = "view=request&request=status&entity=nearevents&id="+eventId+filterQuery+sortQuery;
|
||||
nearEventsReq.send( parms );
|
||||
}
|
||||
|
||||
|
@ -277,7 +584,7 @@ function loadEventThumb( event, frame, loadImage ) {
|
|||
console.error( "No holder found for frame "+frame.FrameId );
|
||||
return;
|
||||
}
|
||||
var img = new Asset.image( imagePrefix+frame.Image.imagePath,
|
||||
var img = new Asset.image( imagePrefix+frame.EventId+"&fid="+frame.FrameId,
|
||||
{
|
||||
'onload': ( function( loadImage ) {
|
||||
thumbImg.setProperty( 'src', img.getProperty( 'src' ) );
|
||||
|
@ -293,29 +600,6 @@ function loadEventThumb( event, frame, loadImage ) {
|
|||
);
|
||||
}
|
||||
|
||||
function updateStillsSizes( noDelay ) {
|
||||
var containerDim = $('eventThumbs').getSize();
|
||||
|
||||
var containerWidth = containerDim.x;
|
||||
var containerHeight = containerDim.y;
|
||||
var popupWidth = parseInt($('eventImage').getStyle( 'width' ));
|
||||
var popupHeight = parseInt($('eventImage').getStyle( 'height' ));
|
||||
|
||||
var left = (containerWidth - popupWidth)/2;
|
||||
if ( left < 0 ) left = 0;
|
||||
var top = (containerHeight - popupHeight)/2;
|
||||
if ( top < 0 ) top = 0;
|
||||
if ( popupHeight == 0 && !noDelay ) {
|
||||
// image not yet loaded lets give it another second
|
||||
updateStillsSizes.pass( true ).delay( 50 );
|
||||
return;
|
||||
}
|
||||
$('eventImagePanel').setStyles( {
|
||||
'left': left,
|
||||
'top': top
|
||||
} );
|
||||
}
|
||||
|
||||
function loadEventImage( event, frame ) {
|
||||
console.debug( "Loading "+event.Id+"/"+frame.FrameId );
|
||||
var eventImg = $('eventImage');
|
||||
|
@ -329,14 +613,6 @@ function loadEventImage( event, frame ) {
|
|||
lastThumbImg.setOpacity( 1.0 );
|
||||
}
|
||||
|
||||
eventImg.setProperties( {
|
||||
'class': frame.Type=='Alarm'?'alarm':'normal',
|
||||
'src': thumbImg.getProperty( 'src' ),
|
||||
'title': thumbImg.getProperty( 'title' ),
|
||||
'alt': thumbImg.getProperty( 'alt' ),
|
||||
'width': event.Width,
|
||||
'height': event.Height
|
||||
} );
|
||||
$('eventImageBar').setStyle( 'width', event.Width );
|
||||
if ( frame.Type=='Alarm' )
|
||||
$('eventImageStats').removeClass( 'hidden' );
|
||||
|
@ -347,11 +623,18 @@ function loadEventImage( event, frame ) {
|
|||
|
||||
if ( eventImagePanel.getStyle( 'display' ) == 'none' ) {
|
||||
eventImagePanel.setOpacity( 0 );
|
||||
updateStillsSizes();
|
||||
eventImagePanel.setStyle( 'display', 'block' );
|
||||
eventImagePanel.setStyle( 'display', 'inline-block' );
|
||||
new Fx.Tween( eventImagePanel, { duration: 500, transition: Fx.Transitions.Sine } ).start( 'opacity', 0, 1 );
|
||||
}
|
||||
|
||||
eventImg.setProperties( {
|
||||
'class': frame.Type=='Alarm'?'alarm':'normal',
|
||||
'src': thumbImg.getProperty( 'src' ),
|
||||
'title': thumbImg.getProperty( 'title' ),
|
||||
'alt': thumbImg.getProperty( 'alt' ),
|
||||
'height': $j('#eventThumbs').height() - $j('#eventImageBar').outerHeight(true)-10
|
||||
} );
|
||||
|
||||
$('eventImageNo').set( 'text', frame.FrameId );
|
||||
$('prevImageBtn').disabled = (frame.FrameId==1);
|
||||
$('nextImageBtn').disabled = (frame.FrameId==event.Frames);
|
||||
|
@ -392,13 +675,11 @@ function resetEventStills() {
|
|||
fid = 1;
|
||||
else if ( fid > eventData.Frames )
|
||||
fid = eventData.Frames;
|
||||
checkFrames( eventData.Id, fid );
|
||||
checkFrames( eventData.Id, fid, ($j('#eventImagePanel').css('display')=='none'?'':'true'));
|
||||
scroll.toElement( 'eventThumb'+fid );
|
||||
}
|
||||
} ).set( 0 );
|
||||
}
|
||||
if ( $('eventThumbs').getStyle( 'height' ).match( /^\d+/ ) < (parseInt(eventData.Height)+80) )
|
||||
$('eventThumbs').setStyle( 'height', (parseInt(eventData.Height)+80)+'px' );
|
||||
}
|
||||
|
||||
function getFrameResponse( respObj, respText ) {
|
||||
|
@ -548,6 +829,7 @@ function actQuery( action, parms ) {
|
|||
}
|
||||
|
||||
function deleteEvent() {
|
||||
pauseClicked(); //Provides visual feedback that your click happened.
|
||||
actQuery( 'delete' );
|
||||
streamNext( true );
|
||||
}
|
||||
|
@ -577,20 +859,19 @@ function showEventFrames() {
|
|||
createPopup( '?view=frames&eid='+eventData.Id, 'zmFrames', 'frames' );
|
||||
}
|
||||
|
||||
function showVideo() {
|
||||
function showStream() {
|
||||
$('eventStills').addClass( 'hidden' );
|
||||
$('imageFeed').addClass('hidden');
|
||||
$('eventVideo').removeClass( 'hidden' );
|
||||
|
||||
$('stillsEvent').removeClass( 'hidden' );
|
||||
$('videoEvent').addClass( 'hidden' );
|
||||
$('streamEvent').addClass( 'hidden' );
|
||||
|
||||
streamMode = 'video';
|
||||
if (scale == 'auto') changeScale();
|
||||
}
|
||||
|
||||
function showStills() {
|
||||
$('eventStills').removeClass( 'hidden' );
|
||||
$('imageFeed').removeClass('hidden');
|
||||
$('eventVideo').addClass( 'hidden' );
|
||||
|
||||
if (vid && ( vid.paused != true ) ) {
|
||||
|
@ -603,11 +884,11 @@ function showStills() {
|
|||
}
|
||||
|
||||
$('stillsEvent').addClass( 'hidden' );
|
||||
$('videoEvent').removeClass( 'hidden' );
|
||||
$('streamEvent').removeClass( 'hidden' );
|
||||
|
||||
streamMode = 'stills';
|
||||
|
||||
streamPause( true );
|
||||
pauseClicked();
|
||||
if ( !scroll ) {
|
||||
scroll = new Fx.Scroll( 'eventThumbs', {
|
||||
wait: false,
|
||||
|
@ -618,7 +899,7 @@ function showStills() {
|
|||
);
|
||||
}
|
||||
resetEventStills();
|
||||
$(window).addEvent( 'resize', updateStillsSizes );
|
||||
if (scale == 'auto') changeScale();
|
||||
}
|
||||
|
||||
function showFrameStats() {
|
||||
|
@ -630,184 +911,64 @@ function videoEvent() {
|
|||
createPopup( '?view=video&eid='+eventData.Id, 'zmVideo', 'video', eventData.Width, eventData.Height );
|
||||
}
|
||||
|
||||
|
||||
// Called on each event load because each event can be a different width
|
||||
function drawProgressBar() {
|
||||
var barWidth = 0;
|
||||
$('progressBar').addClass( 'invisible' );
|
||||
var cells = $('progressBar').getElements( 'div' );
|
||||
var cellWidth = parseInt( eventData.Width/$$(cells).length );
|
||||
$$(cells).forEach(
|
||||
function( cell, index ) {
|
||||
if ( index == 0 )
|
||||
$(cell).setStyles( { 'left': barWidth, 'width': cellWidth, 'borderLeft': 0 } );
|
||||
else
|
||||
$(cell).setStyles( { 'left': barWidth, 'width': cellWidth } );
|
||||
var offset = parseInt((index*eventData.Length)/$$(cells).length);
|
||||
$(cell).setProperty( 'title', '+'+secsToTime(offset)+'s' );
|
||||
$(cell).removeEvent( 'click' );
|
||||
$(cell).addEvent( 'click', function() { streamSeek( offset ); } );
|
||||
barWidth += $(cell).getCoordinates().width;
|
||||
}
|
||||
);
|
||||
$('progressBar').setStyle( 'width', barWidth );
|
||||
$('progressBar').removeClass( 'invisible' );
|
||||
let barWidth = $j('#evtStream').width();
|
||||
$j('#progressBar').css( 'width', barWidth );
|
||||
}
|
||||
|
||||
// Shows current stream progress.
|
||||
function updateProgressBar() {
|
||||
if ( eventData && streamStatus ) {
|
||||
var cells = $('progressBar').getElements( 'div' );
|
||||
var completeIndex = parseInt((($$(cells).length+1)*streamStatus.progress)/eventData.Length);
|
||||
$$(cells).forEach(
|
||||
function( cell, index ) {
|
||||
if ( index < completeIndex ) {
|
||||
if ( !$(cell).hasClass( 'complete' ) ) {
|
||||
$(cell).addClass( 'complete' );
|
||||
}
|
||||
} else {
|
||||
if ( $(cell).hasClass( 'complete' ) ) {
|
||||
$(cell).removeClass( 'complete' );
|
||||
}
|
||||
} // end if
|
||||
} // end function
|
||||
);
|
||||
//$('progressBar').setStyle( 'width', barWidth );
|
||||
$('progressBar').removeClass( 'invisible' );
|
||||
} // end if eventData && streamStatus
|
||||
if ( ! ( eventData && streamStatus ) ) {
|
||||
return;
|
||||
} // end if ! eventData && streamStatus
|
||||
var curWidth = (streamStatus.progress / parseFloat(eventData.Length)) * 100;
|
||||
$j("#progressBox").css('width', curWidth + '%');
|
||||
} // end function updateProgressBar()
|
||||
|
||||
// Handles seeking when clicking on the progress bar.
|
||||
function progressBarNav (){
|
||||
$j('#progressBar').click(function(e){
|
||||
var x = e.offsetX;
|
||||
var seekTime = (x / $j('#progressBar').width()) * parseFloat(eventData.Length);
|
||||
streamSeek (seekTime);
|
||||
});
|
||||
}
|
||||
|
||||
function handleClick( event ) {
|
||||
var target = event.target;
|
||||
if (vid) {
|
||||
if (target.id != 'videoobj') return; //ignore clicks on control bar
|
||||
var x = event.offsetX;
|
||||
var y = event.offsetY;
|
||||
} else {
|
||||
var x = event.page.x - $(target).getLeft();
|
||||
var y = event.page.y - $(target).getTop();
|
||||
}
|
||||
|
||||
if ( event.shift )
|
||||
if (event.shift || event.shiftKey) {//handle both jquery and mootools
|
||||
streamPan(x, y);
|
||||
else
|
||||
} else if (vid && event.ctrlKey) { //allow zoom out by control click. useful in fullscreen
|
||||
vjsPanZoom('zoomOut', x, y);
|
||||
} else {
|
||||
streamZoomIn(x, y);
|
||||
}
|
||||
|
||||
function setupListener() {
|
||||
|
||||
// Buttons
|
||||
var playButton = document.getElementById("play-pause");
|
||||
var muteButton = document.getElementById("mute");
|
||||
var fullScreenButton = document.getElementById("full-screen");
|
||||
|
||||
// Sliders
|
||||
var seekBar = document.getElementById("seekbar");
|
||||
var volumeBar = document.getElementById("volume-bar");
|
||||
|
||||
// Event listener for the play/pause button
|
||||
playButton.addEventListener( "click", function() {
|
||||
if (vid.paused == true) {
|
||||
// Play the video
|
||||
vid.play();
|
||||
|
||||
// Update the button text to 'Pause'
|
||||
playButton.innerHTML = "Pause";
|
||||
} else {
|
||||
// Pause the video
|
||||
vid.pause();
|
||||
|
||||
// Update the button text to 'Play'
|
||||
playButton.innerHTML = "Play";
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Event listener for the mute button
|
||||
muteButton.addEventListener("click", function() {
|
||||
if (vid.muted == false) {
|
||||
// Mute the video
|
||||
vid.muted = true;
|
||||
|
||||
// Update the button text
|
||||
muteButton.innerHTML = "Unmute";
|
||||
} else {
|
||||
// Unmute the video
|
||||
vid.muted = false;
|
||||
|
||||
// Update the button text
|
||||
muteButton.innerHTML = "Mute";
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Event listener for the full-screen button
|
||||
fullScreenButton.addEventListener("click", function() {
|
||||
if (vid.requestFullscreen) {
|
||||
vid.requestFullscreen();
|
||||
} else if (vid.mozRequestFullScreen) {
|
||||
vid.mozRequestFullScreen(); // Firefox
|
||||
} else if (vid.webkitRequestFullscreen) {
|
||||
vid.webkitRequestFullscreen(); // Chrome and Safari
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Event listener for the seek bar
|
||||
seekBar.addEventListener("change", function() {
|
||||
// Calculate the new time
|
||||
var time = vid.duration * (seekBar.value / 100);
|
||||
|
||||
// Update the video time
|
||||
vid.currentTime = time;
|
||||
});
|
||||
|
||||
|
||||
// Update the seek bar as the video plays
|
||||
vid.addEventListener("timeupdate", function() {
|
||||
// Calculate the slider value
|
||||
var value = (100 / vid.duration) * vid.currentTime;
|
||||
|
||||
// Update the slider value
|
||||
seekBar.value = value;
|
||||
});
|
||||
|
||||
// Pause the video when the seek handle is being dragged
|
||||
seekBar.addEventListener("mousedown", function() {
|
||||
vid.pause();
|
||||
});
|
||||
|
||||
// Play the video when the seek handle is dropped
|
||||
seekBar.addEventListener("mouseup", function() {
|
||||
vid.play();
|
||||
});
|
||||
|
||||
// Event listener for the volume bar
|
||||
volumeBar.addEventListener("change", function() {
|
||||
// Update the video volume
|
||||
vid.volume = volumeBar.value;
|
||||
});
|
||||
}
|
||||
|
||||
function initPage() {
|
||||
//FIXME prevent blocking...not sure what is happening or best way to unblock
|
||||
if ( $('videoobj') ) {
|
||||
vid = videojs("videoobj");
|
||||
}
|
||||
if ( vid ) {
|
||||
/*
|
||||
setupListener();
|
||||
vid.removeAttribute("controls");
|
||||
/* window.videoobj.oncanplay=null;
|
||||
window.videoobj.currentTime=window.videoobj.currentTime-1;
|
||||
window.videoobj.currentTime=window.videoobj.currentTime+1;//may not be symetrical of course
|
||||
|
||||
vid.onstalled=function(){window.vid.currentTime=window.vid.currentTime-1;window.vid.currentTime=window.vid.currentTime+1;}
|
||||
vid.onwaiting=function(){window.vid.currentTime=window.vid.currentTime-1;window.vid.currentTime=window.vid.currentTime+1;}
|
||||
vid.onloadstart=function(){window.vid.currentTime=window.vid.currentTime-1;window.vid.currentTime=window.vid.currentTime+1;}
|
||||
vid.onplay=function(){window.vid.currentTime=window.vid.currentTime-1;window.vid.currentTime=window.vid.currentTime+1;}
|
||||
vid.onplaying=function(){window.vid.currentTime=window.vid.currentTime-1;window.vid.currentTime=window.vid.currentTime+1;}
|
||||
//window.vid.hide();//does not help
|
||||
var sources = window.videoobj.getElementsByTagName('source');
|
||||
sources[0].src=null;
|
||||
window.videoobj.load();
|
||||
streamPlay(); */
|
||||
if ($j('#videoobj').length) {
|
||||
vid = videojs('videoobj');
|
||||
addVideoTimingTrack(vid, LabelFormat, eventData.MonitorName, eventData.Length, eventData.StartTime);
|
||||
$j('.vjs-progress-control').append('<div class="alarmCue"></div>');//add a place for videojs only on first load
|
||||
vid.on('ended', vjsReplay);
|
||||
vid.on('play', vjsPlay);
|
||||
vid.on('pause', vjsPause);
|
||||
vid.on('click', function(event){handleClick(event);});
|
||||
vid.on('timeupdate', function (){$j('#progressValue').html(secsToTime(Math.floor(vid.currentTime())))});
|
||||
} else {
|
||||
progressBarNav ();
|
||||
streamCmdTimer = streamQuery.delay( 250 );
|
||||
eventQuery.pass( eventData.Id ).delay( 500 );
|
||||
|
||||
if ( canStreamNative ) {
|
||||
var streamImg = $('imageFeed').getElement('img');
|
||||
if ( !streamImg )
|
||||
|
@ -815,6 +976,9 @@ function initPage() {
|
|||
$(streamImg).addEvent( 'click', function( event ) { handleClick( event ); } );
|
||||
}
|
||||
}
|
||||
nearEventsQuery(eventData.Id);
|
||||
initialAlarmCues(eventData.Id); //call ajax+renderAlarmCues
|
||||
if (scale == "auto") changeScale();
|
||||
}
|
||||
|
||||
// Kick everything off
|
||||
|
|
|
@ -30,17 +30,25 @@ var eventData = {
|
|||
MonitorId: '<?php echo $Event->MonitorId() ?>',
|
||||
Width: '<?php echo $Event->Width() ?>',
|
||||
Height: '<?php echo $Event->Height() ?>',
|
||||
Length: '<?php echo $Event->Length() ?>'
|
||||
Length: '<?php echo $Event->Length() ?>',
|
||||
StartTime: '<?php echo $Event->StartTime() ?>',
|
||||
EndTime: '<?php echo $Event->EndTime() ?>',
|
||||
Frames: '<?php echo $Event->Frames() ?>',
|
||||
MonitorName: '<?php echo $Monitor->Name() ?>'
|
||||
};
|
||||
|
||||
var filterQuery = '<?php echo isset($filterQuery)?validJsStr($filterQuery):'' ?>';
|
||||
var sortQuery = '<?php echo isset($sortQuery)?validJsStr($sortQuery):'' ?>';
|
||||
var filterQuery = '<?php echo isset($filterQuery)?validJsStr(htmlspecialchars_decode($filterQuery)):'' ?>';
|
||||
var sortQuery = '<?php echo isset($sortQuery)?validJsStr(htmlspecialchars_decode($sortQuery)):'' ?>';
|
||||
|
||||
var rates = <?php echo json_encode(array_keys($rates)) ?>;
|
||||
var scale = "<?php echo $scale ?>";
|
||||
var LabelFormat = "<?php echo validJsStr($Monitor->LabelFormat())?>";
|
||||
|
||||
var scale = <?php echo $scale ?>;
|
||||
var canEditEvents = <?php echo canEdit( 'Events' )?'true':'false' ?>;
|
||||
var streamTimeout = <?php echo 1000*ZM_WEB_REFRESH_STATUS ?>;
|
||||
|
||||
var canStreamNative = <?php echo canStreamNative()?'true':'false' ?>;
|
||||
var streamMode = '<?php echo $streamMode ?>';
|
||||
|
||||
//
|
||||
// Strings
|
||||
|
|
|
@ -1,15 +1,34 @@
|
|||
function changeScale() {
|
||||
var scale = $('scale').get('value');
|
||||
var img = $('frameImg');
|
||||
if ( img ) {
|
||||
var baseWidth = $('base_width').value;
|
||||
var baseHeight = $('base_height').value;
|
||||
var newWidth = ( baseWidth * scale ) / SCALE_BASE;
|
||||
var newHeight = ( baseHeight * scale ) / SCALE_BASE;
|
||||
let scale = $j('#scale').val();
|
||||
let img = $j('#frameImg');
|
||||
let controlsLinks = {
|
||||
next: $j('#nextLink'),
|
||||
prev: $j('#prevLink'),
|
||||
first: $j('#firstLink'),
|
||||
last: $j('#lastLink')
|
||||
}
|
||||
|
||||
img.style.width = newWidth + "px";
|
||||
img.style.height = newHeight + "px";
|
||||
if (img) {
|
||||
let baseWidth = $j('#base_width').val();
|
||||
let baseHeight = $j('#base_height').val();
|
||||
if (scale == "auto") {
|
||||
let newSize = scaleToFit(baseWidth, baseHeight, img, $j('#controls'));
|
||||
newWidth = newSize.width;
|
||||
newHeight = newSize.height;
|
||||
autoScale = newSize.autoScale;
|
||||
} else {
|
||||
$j(window).off('resize', endOfResize); //remove resize handler when Scale to Fit is not active
|
||||
newWidth = baseWidth * scale / SCALE_BASE;
|
||||
newHeight = baseHeight * scale / SCALE_BASE;
|
||||
}
|
||||
img.css('width', newWidth + "px");
|
||||
img.css('height', newHeight + "px");
|
||||
}
|
||||
Cookie.write( 'zmWatchScale', scale, { duration: 10*365 } );
|
||||
$j.each(controlsLinks, function(k, anchor) { //Make frames respect scale choices
|
||||
anchor.prop('href', anchor.prop('href').replace(/scale=.*&/, 'scale=' + scale + '&'));
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
if (scale == "auto") $j(document).ready(changeScale);
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
var scale = '<?php echo $scale ?>';
|
||||
|
||||
var SCALE_BASE = <?php echo SCALE_BASE ?>;
|
||||
|
|
|
@ -286,7 +286,7 @@ sortReverse: true
|
|||
warningPrefix: "",
|
||||
errorPrefix: ""
|
||||
});
|
||||
new Asset.css( "/css/spinner.css" );
|
||||
new Asset.css( "css/spinner.css" );
|
||||
fetchNextLogs();
|
||||
}
|
||||
|
||||
|
|
|
@ -25,18 +25,29 @@ function showPtzControls() {
|
|||
|
||||
function changeScale() {
|
||||
var scale = $('scale').get('value');
|
||||
var newWidth = ( monitorWidth * scale ) / SCALE_BASE;
|
||||
var newHeight = ( monitorHeight * scale ) / SCALE_BASE;
|
||||
var newWidth;
|
||||
var newHeight;
|
||||
if (scale == "auto") {
|
||||
let newSize = scaleToFit(monitorWidth, monitorHeight, $j('#liveStream'+monitorId), $j('#replayStatus'));
|
||||
newWidth = newSize.width;
|
||||
newHeight = newSize.height;
|
||||
autoScale = newSize.autoScale;
|
||||
} else {
|
||||
$j(window).off('resize', endOfResize); //remove resize handler when Scale to Fit is not active
|
||||
newWidth = monitorWidth * scale / SCALE_BASE;
|
||||
newHeight = monitorHeight * scale / SCALE_BASE;
|
||||
}
|
||||
|
||||
|
||||
Cookie.write( 'zmWatchScale'+monitorId, scale, { duration: 10*365 } );
|
||||
|
||||
/*Stream could be an applet so can't use moo tools*/
|
||||
var streamImg = document.getElementById('liveStream'+monitorId);
|
||||
var streamImg = $('liveStream'+monitorId);
|
||||
if ( streamImg ) {
|
||||
streamImg.style.width = newWidth + "px";
|
||||
streamImg.style.height = newHeight + "px";
|
||||
|
||||
streamImg.src = streamImg.src.replace(/scale=\d+/i, 'scale='+scale);
|
||||
streamImg.src = streamImg.src.replace(/scale=\d+/i, 'scale='+(scale== 'auto' ? autoScale : scale));
|
||||
} else {
|
||||
console.error("No element found for liveStream.");
|
||||
}
|
||||
|
@ -622,6 +633,7 @@ function initPage() {
|
|||
|
||||
if ( refreshApplet && appletRefreshTime )
|
||||
appletRefresh.delay( appletRefreshTime*1000 );
|
||||
if (scale == "auto") changeScale();
|
||||
}
|
||||
|
||||
// Kick everything off
|
||||
|
|
|
@ -50,7 +50,7 @@ var monitorWidth = <?php echo $monitor->Width() ?>;
|
|||
var monitorHeight = <?php echo $monitor->Height() ?>;
|
||||
var monitorUrl = '<?php echo ( $monitor->Server()->Url() ) ?>';
|
||||
|
||||
var scale = <?php echo $scale ?>;
|
||||
var scale = '<?php echo $scale ?>';
|
||||
|
||||
var statusRefreshTimeout = <?php echo 1000*ZM_WEB_REFRESH_STATUS ?>;
|
||||
var eventsRefreshTimeout = <?php echo 1000*ZM_WEB_REFRESH_EVENTS ?>;
|
||||
|
|
|
@ -66,8 +66,19 @@ if ( empty($_REQUEST['path']) ) {
|
|||
$Event = new Event( $_REQUEST['eid'] );
|
||||
$Frame = Frame::find_one( array( 'EventId' => $_REQUEST['eid'], 'FrameId' => $_REQUEST['fid'] ) );
|
||||
if ( ! $Frame ) {
|
||||
$previousBulkFrame = dbFetchOne( "SELECT * FROM Frames WHERE EventId=? AND FrameId < ? ORDER BY FrameID DESC LIMIT 1", NULL, array($_REQUEST['eid'], $_REQUEST['fid'] ) );
|
||||
$nextBulkFrame = dbFetchOne( "SELECT * FROM Frames WHERE EventId=? AND FrameId > ? ORDER BY FrameID ASC LIMIT 1", NULL, array($_REQUEST['eid'], $_REQUEST['fid'] ) );
|
||||
if ( $previousBulkFrame and $nextBulkFrame ) {
|
||||
$Frame = new Frame( $previousBulkFrame );
|
||||
$Frame->FrameId = ( $_REQUEST['fid'] );
|
||||
$percentage = ($Frame->FrameId() - $previousBulkFrame['FrameId']) / ($nextBulkFrame['FrameId'] - $previousBulkFrame['FrameId']);
|
||||
$Frame->Delta = ( $previousBulkFrame['Delta'] + floor( 100* ( $nextBulkFrame['Delta'] - $previousBulkFrame['Delta'] ) * $percentage )/100 );
|
||||
Logger::Debug("Got virtual frame from Bulk Frames previous delta: " . $previousBulkFrame['Delta'] . " + nextdelta:" . $nextBulkFrame['Delta'] . ' - ' . $previousBulkFrame['Delta'] . ' * ' . $percentage );
|
||||
} else {
|
||||
Fatal("No Frame found for event(".$_REQUEST['eid'].") and frame id(".$_REQUEST['fid'].")");
|
||||
}
|
||||
}
|
||||
// Frame can be non-existent. We have Bulk frames. So now we should try to load the bulk frame
|
||||
} else {
|
||||
# If we are only specifying fid, then the fid must be the primary key into the frames table. But when the event is specified, then it is the frame #
|
||||
$Frame = new Frame( $_REQUEST['fid'] );
|
||||
|
|
|
@ -1,25 +1,37 @@
|
|||
#!/bin/bash
|
||||
# The purpose of this file is to create the symlinks in the web folder to the content folder. It can use an existing content folder or create a new one.
|
||||
# This tool is used to verify folders critical to ZoneMinder exist and have the right permissions.
|
||||
# It will also create symlinks when necessary. It can use an existing content folder or create a new one.
|
||||
|
||||
# Set the content dir default to be the one supplied to cmake
|
||||
ZM_PATH_CONTENT="@ZM_CONTENTDIR@"
|
||||
|
||||
# Set the zoneminder log dir default to be the one supplied to cmake
|
||||
ZM_LOGDIR="@ZM_LOGDIR@"
|
||||
|
||||
# Set the zoneminder temp dir default to be the one supplied to cmake
|
||||
ZM_TMPDIR="@ZM_TMPDIR@"
|
||||
|
||||
echo "*** This bash script creates the nessecary symlinks for the zoneminder content"
|
||||
echo "*** It can use an existing content folder or create a new one"
|
||||
echo "*** For usage: use -h"
|
||||
echo "*** The default content directory is: $ZM_PATH_CONTENT"
|
||||
echo "*** The default log directory is: $ZM_LOGDIR"
|
||||
echo "*** The default temp directory is: $ZM_TMPDIR"
|
||||
echo ""
|
||||
|
||||
usage()
|
||||
{
|
||||
cat <<EOF
|
||||
Usage: $0 [-q] [-z zm.conf] [-w WEB DIRECTORY] [CONTENT DIRECTORY]
|
||||
Usage: $0 [-q] [-o] [-z zm.conf] [-w WEB DIRECTORY] [-l LOG DIRECTORY] [-t TMP DIRECTORY] [CONTENT DIRECTORY]
|
||||
|
||||
OPTIONS:
|
||||
-h Show this message and quit
|
||||
-z ZoneMinder configuration file
|
||||
-w Override the web directory from zm.conf
|
||||
-q Quick mode. Do not change ownership recursively.
|
||||
-l Override the zm log folder location
|
||||
-t Override the zm temp folder location
|
||||
-o Enable old legacy symlinks inside ZoneMinder's webroot folder
|
||||
|
||||
If the -w option is not used to specify the path to the web directory,
|
||||
the script will use the path from zoneminder's configuration file.
|
||||
|
@ -27,10 +39,14 @@ If the -z option is used, the argument will be used instead of zm.conf
|
|||
Otherwise, it will attempt to read zm.conf from the local directory.
|
||||
If that fails, it will try from /etc/zm.conf
|
||||
|
||||
Newer versions of ZoneMinder no longer require symlinks to the events and
|
||||
images folders inside the zm webroot. Indeed this is a security risk, and
|
||||
$0 will no longer create these unless the -o option is specified.
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
while getopts "hz:w:q" OPTION
|
||||
while getopts "hz:w:q:l:t:o" OPTION
|
||||
do
|
||||
case $OPTION in
|
||||
h)
|
||||
|
@ -46,6 +62,15 @@ do
|
|||
q)
|
||||
QUICK=1
|
||||
;;
|
||||
l)
|
||||
ZM_LOGDIR_FORCE=$OPTARG
|
||||
;;
|
||||
t)
|
||||
ZM_TMPDIR_FORCE=$OPTARG
|
||||
;;
|
||||
o)
|
||||
LEGACY=1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift $(( OPTIND - 1 ))
|
||||
|
@ -73,7 +98,7 @@ elif [ -f "/etc/zm.conf" ]; then
|
|||
echo "Using system zm.conf"
|
||||
source "/etc/zm.conf"
|
||||
else
|
||||
echo "Failed locating zoneminder configuration file (zm.conf)\nUse the -z option to specify the full path to the zoneminder configuration file"
|
||||
echo -e "Failed locating zoneminder configuration file (zm.conf)\nUse the -z option to specify the full path to the zoneminder configuration file"
|
||||
exit 45
|
||||
fi
|
||||
|
||||
|
@ -82,6 +107,16 @@ if [ -n "$ZM_PATH_WEB_FORCE" ]; then
|
|||
ZM_PATH_WEB="$(readlink -f $ZM_PATH_WEB_FORCE)"
|
||||
fi
|
||||
|
||||
# Override the log directory path
|
||||
if [ -n "$ZM_LOGDIR_FORCE" ]; then
|
||||
ZM_LOGDIR="$(readlink -f $ZM_LOGDIR_FORCE)"
|
||||
fi
|
||||
|
||||
# Override the tmp directory path
|
||||
if [ -n "$ZM_TMPDIR_FORCE" ]; then
|
||||
ZM_TMPDIR="$(readlink -f $ZM_TMPDIR_FORCE)"
|
||||
fi
|
||||
|
||||
# Override the default content path
|
||||
if [[ -n "$@" ]]; then
|
||||
ZM_PATH_CONTENT="$(readlink -f $@)"
|
||||
|
@ -90,6 +125,8 @@ fi
|
|||
# Print some information
|
||||
echo "Web folder : $ZM_PATH_WEB"
|
||||
echo "Content folder : $ZM_PATH_CONTENT"
|
||||
echo "Log folder : $ZM_LOGDIR"
|
||||
echo "Temp folder : $ZM_TMPDIR"
|
||||
echo ""
|
||||
|
||||
# Verify the web folder is a real directory
|
||||
|
@ -98,7 +135,7 @@ if [ -d "$ZM_PATH_WEB" ]; then
|
|||
echo "OK"
|
||||
else
|
||||
echo "Failed"
|
||||
exit 3
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Check if the content folder exists, and if not, create it
|
||||
|
@ -109,6 +146,22 @@ else
|
|||
echo "No"
|
||||
echo -n "Creating the content folder... "
|
||||
mkdir "$ZM_PATH_CONTENT"
|
||||
if [ "$?" = "0" ]; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "Failed"
|
||||
exit 3
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if the log folder exists, and if not, create the entire folder including its parents
|
||||
echo -n "Checking if the log folder exists... "
|
||||
if [ -d "$ZM_LOGDIR" ]; then
|
||||
echo "Yes"
|
||||
else
|
||||
echo "No"
|
||||
echo -n "Creating the log folder... "
|
||||
mkdir -p "$ZM_LOGDIR"
|
||||
if [ "$?" = "0" ]; then
|
||||
echo "OK"
|
||||
else
|
||||
|
@ -116,6 +169,23 @@ else
|
|||
exit 4
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if the temp folder exists, and if not, create the entire folder including its parents
|
||||
echo -n "Checking if the temp folder exists... "
|
||||
if [ -d "$ZM_TMPDIR" ]; then
|
||||
echo "Yes"
|
||||
else
|
||||
echo "No"
|
||||
echo -n "Creating the temp folder... "
|
||||
mkdir -p "$ZM_TMPDIR"
|
||||
if [ "$?" = "0" ]; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "Failed"
|
||||
exit 5
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if the content/images folder exists, and if not, create it
|
||||
echo -n "Checking if the images folder exists inside the content folder... "
|
||||
if [ -d "$ZM_PATH_CONTENT/images" ]; then
|
||||
|
@ -131,6 +201,7 @@ else
|
|||
exit 6
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if the content/events folder exists, and if not, create it
|
||||
echo -n "Checking if the events folder exists inside the content folder... "
|
||||
if [ -d "$ZM_PATH_CONTENT/events" ]; then
|
||||
|
@ -179,6 +250,7 @@ if [ -d "$ZM_PATH_WEB/events" ]; then
|
|||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$LEGACY" ]; then
|
||||
# Create the symlink for the images folder
|
||||
echo -n "Creating the symlink for the images folder... "
|
||||
ln -s -f "$ZM_PATH_CONTENT/images" "$ZM_PATH_WEB/images"
|
||||
|
@ -198,6 +270,7 @@ else
|
|||
echo "Failed"
|
||||
exit 16
|
||||
fi
|
||||
fi
|
||||
|
||||
# change ownership for the images folder. do it recursively unless -q is used
|
||||
if [ -n "$QUICK" ]; then
|
||||
|
@ -228,11 +301,32 @@ if [ -n "$QUICK" ]; then
|
|||
echo "OK"
|
||||
else
|
||||
echo "Failed"
|
||||
exit 25
|
||||
exit 23
|
||||
fi
|
||||
else
|
||||
echo -n "Changing ownership of the events folder recursively to ${ZM_WEB_USER} ${ZM_WEB_GROUP}... "
|
||||
chown -R ${ZM_WEB_USER}:${ZM_WEB_GROUP} "$ZM_PATH_CONTENT/events"
|
||||
if [ "$?" = "0" ]; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "Failed"
|
||||
exit 24
|
||||
fi
|
||||
fi
|
||||
|
||||
# change ownership for the log folder. do it recursively unless -q is used
|
||||
if [ -n "$QUICK" ]; then
|
||||
echo -n "Changing ownership of the log folder to ${ZM_WEB_USER} ${ZM_WEB_GROUP}... "
|
||||
chown ${ZM_WEB_USER}:${ZM_WEB_GROUP} "$ZM_LOGDIR"
|
||||
if [ "$?" = "0" ]; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "Failed"
|
||||
exit 25
|
||||
fi
|
||||
else
|
||||
echo -n "Changing ownership of the log folder recursively to ${ZM_WEB_USER} ${ZM_WEB_GROUP}... "
|
||||
chown -R ${ZM_WEB_USER}:${ZM_WEB_GROUP} "$ZM_LOGDIR"
|
||||
if [ "$?" = "0" ]; then
|
||||
echo "OK"
|
||||
else
|
||||
|
@ -241,6 +335,27 @@ else
|
|||
fi
|
||||
fi
|
||||
|
||||
# change ownership for the temp folder. do it recursively unless -q is used
|
||||
if [ -n "$QUICK" ]; then
|
||||
echo -n "Changing ownership of the temp folder to ${ZM_WEB_USER} ${ZM_WEB_GROUP}... "
|
||||
chown ${ZM_WEB_USER}:${ZM_WEB_GROUP} "$ZM_TMPDIR"
|
||||
if [ "$?" = "0" ]; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "Failed"
|
||||
exit 27
|
||||
fi
|
||||
else
|
||||
echo -n "Changing ownership of the temp folder recursively to ${ZM_WEB_USER} ${ZM_WEB_GROUP}... "
|
||||
chown -R ${ZM_WEB_USER}:${ZM_WEB_GROUP} "$ZM_TMPDIR"
|
||||
if [ "$?" = "0" ]; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "Failed"
|
||||
exit 28
|
||||
fi
|
||||
fi
|
||||
|
||||
# Change directory permissions for the images folder
|
||||
echo -n "Changing permissions of the images folder to 775... "
|
||||
chmod 775 "$ZM_PATH_CONTENT/images"
|
||||
|
@ -251,7 +366,6 @@ else
|
|||
exit 30
|
||||
fi
|
||||
|
||||
|
||||
# Change directory permissions for the events folder
|
||||
echo -n "Changing permissions of the events folder to 775... "
|
||||
chmod 775 "$ZM_PATH_CONTENT/events"
|
||||
|
@ -262,5 +376,35 @@ else
|
|||
exit 31
|
||||
fi
|
||||
|
||||
# Change directory permissions for the log folder
|
||||
echo -n "Changing permissions of the log folder to 775... "
|
||||
chmod 775 "$ZM_LOGDIR"
|
||||
if [ "$?" = "0" ]; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "Failed"
|
||||
exit 32
|
||||
fi
|
||||
|
||||
# Change directory permissions for the temp folder
|
||||
echo -n "Changing permissions of the temp folder to 775... "
|
||||
chmod 775 "$ZM_TMPDIR"
|
||||
if [ "$?" = "0" ]; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "Failed"
|
||||
exit 33
|
||||
fi
|
||||
|
||||
# Link the CakePHP tmp folder to the zoneminder temp folder
|
||||
echo -n "Linking CakePHP tmp folder to ${ZM_TMPDIR}... "
|
||||
ln -sfT "$ZM_TMPDIR" "$ZM_PATH_WEB/api/app/tmp"
|
||||
if [ "$?" = "0" ]; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "Failed"
|
||||
exit 40
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "All done"
|
||||
|
|
Loading…
Reference in New Issue