Merge branch 'storageareas' of github.com:ZoneMinder/ZoneMinder into storageareas
This commit is contained in:
commit
408fba8d24
|
@ -45,4 +45,4 @@ script:
|
||||||
- mysql -uzmuser -pzmpass < db/zm_create.sql
|
- mysql -uzmuser -pzmpass < db/zm_create.sql
|
||||||
- mysql -uzmuser -pzmpass zm < db/test.monitor.sql
|
- mysql -uzmuser -pzmpass zm < db/test.monitor.sql
|
||||||
- sudo zmpkg.pl start
|
- sudo zmpkg.pl start
|
||||||
- sudo zmfilter.pl -f purgewhenfull
|
- sudo zmfilter.pl --filter purgewhenfull
|
||||||
|
|
|
@ -3,6 +3,19 @@
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
if [ "$1" = "configure" ]; then
|
if [ "$1" = "configure" ]; then
|
||||||
|
|
||||||
|
. /etc/zm/zm.conf
|
||||||
|
|
||||||
|
# The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group.
|
||||||
|
chown www-data:root /var/log/zm
|
||||||
|
chown www-data:www-data /var/lib/zm
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/*
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Do this every time the package is installed or upgraded
|
||||||
|
|
||||||
|
if [ "$ZM_DB_HOST" = "localhost" ]; then
|
||||||
if [ -e "/etc/init.d/mysql" ]; then
|
if [ -e "/etc/init.d/mysql" ]; then
|
||||||
#
|
#
|
||||||
# Get mysql started if it isn't
|
# Get mysql started if it isn't
|
||||||
|
@ -15,39 +28,26 @@ if [ "$1" = "configure" ]; then
|
||||||
# test if database if already present...
|
# test if database if already present...
|
||||||
if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then
|
if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then
|
||||||
cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf
|
cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf
|
||||||
echo 'grant lock tables, alter,select,insert,update,delete on zm.* to 'zmuser'@localhost identified by "zmpass";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
# This creates the user.
|
||||||
|
echo "grant lock tables, alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||||
|
else
|
||||||
|
echo "grant lock tables, alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Ensure zoneminder is stopped
|
||||||
invoke-rc.d zoneminder stop || true
|
invoke-rc.d zoneminder stop || true
|
||||||
zmupdate.pl --nointeractive
|
zmupdate.pl --nointeractive
|
||||||
|
zmupdate.pl --nointeractive -f
|
||||||
|
invoke-rc.d zoneminder start || true
|
||||||
else
|
else
|
||||||
echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.'
|
echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.'
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo 'mysql not found, assuming remote server.'
|
echo 'mysql not found, assuming remote server.'
|
||||||
fi
|
fi
|
||||||
chown www-data:www-data /var/log/zm
|
|
||||||
chown www-data:www-data /var/lib/zm/
|
|
||||||
if [ -z "$2" ]; then
|
|
||||||
chown www-data:www-data -R /var/cache/zoneminder
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
# Ensure zoneminder is stopped...
|
|
||||||
if [ -x "/etc/init.d/zoneminder" ]; then
|
|
||||||
if invoke-rc.d zoneminder status ; then
|
|
||||||
invoke-rc.d zoneminder stop || exit $?
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$1" = "configure" ]; then
|
|
||||||
if [ -z "$2" ]; then
|
|
||||||
chown www-data:www-data /var/log/zm
|
|
||||||
chown www-data:www-data /var/lib/zm/
|
|
||||||
chown www-data:www-data -R /var/cache/zoneminder
|
|
||||||
else
|
else
|
||||||
chown www-data:www-data /var/log/zm
|
echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)"
|
||||||
zmupdate.pl
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
fi
|
fi
|
||||||
#DEBHELPER#
|
#DEBHELPER#
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
zoneminder (1.30.2-trusty-2016042801) trusty; urgency=medium
|
||||||
|
|
||||||
|
* Merge video
|
||||||
|
|
||||||
|
-- Isaac Connor <iconnor@connortechnology.com> Thu, 28 Apr 2016 12:54:08 -0400
|
||||||
|
|
||||||
zoneminder (1.28.1+1-vivid-SNAPSHOT2015081701) vivid; urgency=medium
|
zoneminder (1.28.1+1-vivid-SNAPSHOT2015081701) vivid; urgency=medium
|
||||||
|
|
||||||
* include api, switch to cmake build
|
* include api, switch to cmake build
|
||||||
|
|
|
@ -3,10 +3,50 @@
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
if [ "$1" = "configure" ]; then
|
if [ "$1" = "configure" ]; then
|
||||||
|
|
||||||
|
. /etc/zm/zm.conf
|
||||||
|
|
||||||
|
# The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group
|
||||||
chown www-data:root /var/log/zm
|
chown www-data:root /var/log/zm
|
||||||
chown www-data:www-data /var/lib/zm
|
chown www-data:www-data /var/lib/zm
|
||||||
if [ -z "$2" ]; then
|
if [ -z "$2" ]; then
|
||||||
chown www-data:www-data -R /var/cache/zoneminder
|
chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/*
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Do this every time the package is installed or upgraded
|
||||||
|
|
||||||
|
if [ "$ZM_DB_HOST" = "localhost" ]; then
|
||||||
|
if [ -e "/etc/init.d/mysql" ]; then
|
||||||
|
#
|
||||||
|
# Get mysql started if it isn't
|
||||||
|
#
|
||||||
|
if ! $(/etc/init.d/mysql status >/dev/null 2>&1); then
|
||||||
|
invoke-rc.d mysql start
|
||||||
|
fi
|
||||||
|
if $(/etc/init.d/mysql status >/dev/null 2>&1); then
|
||||||
|
mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload
|
||||||
|
# test if database if already present...
|
||||||
|
if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then
|
||||||
|
cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf
|
||||||
|
# This creates the user.
|
||||||
|
echo "grant lock tables, alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||||
|
else
|
||||||
|
echo "grant lock tables, alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure zoneminder is stopped
|
||||||
|
invoke-rc.d zoneminder stop || true
|
||||||
|
zmupdate.pl --nointeractive
|
||||||
|
zmupdate.pl --nointeractive -f
|
||||||
|
invoke-rc.d zoneminder start || true
|
||||||
|
else
|
||||||
|
echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.'
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo 'mysql not found, assuming remote server.'
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,15 @@
|
||||||
|
zoneminder (1.30.2-trusty-2016033001) trusty; urgency=medium
|
||||||
|
|
||||||
|
* merge master
|
||||||
|
|
||||||
|
-- Isaac Connor <iconnor@connortechnology.com> Wed, 30 Mar 2016 14:09:48 -0400
|
||||||
|
|
||||||
|
zoneminder (1.30.2-trusty-2016032901) trusty; urgency=medium
|
||||||
|
|
||||||
|
* filter fixes, merge options rework by Kyle
|
||||||
|
|
||||||
|
-- Isaac Connor <iconnor@connortechnology.com> Tue, 29 Mar 2016 12:27:57 -0400
|
||||||
|
|
||||||
zoneminder (1.30.2-trusty-2016030702) trusty; urgency=medium
|
zoneminder (1.30.2-trusty-2016030702) trusty; urgency=medium
|
||||||
|
|
||||||
*
|
*
|
||||||
|
|
|
@ -6,6 +6,7 @@ Uploaders: Vagrant Cascadian <vagrant@debian.org>
|
||||||
Build-Depends: debhelper (>= 9), dh-systemd, python-sphinx | python3-sphinx, apache2-dev, dh-linktree
|
Build-Depends: debhelper (>= 9), dh-systemd, python-sphinx | python3-sphinx, apache2-dev, dh-linktree
|
||||||
,cmake
|
,cmake
|
||||||
,libavcodec-ffmpeg-dev, libavformat-ffmpeg-dev, libswscale-ffmpeg-dev, libavutil-ffmpeg-dev, libavdevice-ffmpeg-dev
|
,libavcodec-ffmpeg-dev, libavformat-ffmpeg-dev, libswscale-ffmpeg-dev, libavutil-ffmpeg-dev, libavdevice-ffmpeg-dev
|
||||||
|
,libx264-dev, libmp4v2-dev,
|
||||||
,libbz2-dev
|
,libbz2-dev
|
||||||
,libgcrypt-dev
|
,libgcrypt-dev
|
||||||
,libcurl4-gnutls-dev
|
,libcurl4-gnutls-dev
|
||||||
|
@ -34,10 +35,8 @@ Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
|
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
|
||||||
,javascript-common
|
,javascript-common
|
||||||
,libav-tools
|
,libav-tools
|
||||||
,libdate-manip-perl
|
,libdate-manip-perl, libmime-lite-perl, libmime-tools-perl
|
||||||
,libdbd-mysql-perl
|
,libdbd-mysql-perl
|
||||||
,libmime-lite-perl
|
|
||||||
,libmime-tools-perl
|
|
||||||
,libphp-serialization-perl
|
,libphp-serialization-perl
|
||||||
,libmodule-load-conditional-perl
|
,libmodule-load-conditional-perl
|
||||||
,libnet-sftp-foreign-perl
|
,libnet-sftp-foreign-perl
|
||||||
|
@ -57,12 +56,12 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
|
||||||
,libsys-cpu-perl, libsys-meminfo-perl
|
,libsys-cpu-perl, libsys-meminfo-perl
|
||||||
,mysql-client | virtual-mysql-client
|
,mysql-client | virtual-mysql-client
|
||||||
,perl-modules
|
,perl-modules
|
||||||
,php5-mysql
|
,php5-mysql | php-mysql, php5-gd | php-gd
|
||||||
,policykit-1
|
,policykit-1
|
||||||
,rsyslog | system-log-daemon
|
,rsyslog | system-log-daemon
|
||||||
,zip
|
,zip
|
||||||
Recommends: ${misc:Recommends}
|
Recommends: ${misc:Recommends}
|
||||||
,libapache2-mod-php5 | php5-fpm
|
,libapache2-mod-php5 | libapache2-mod-php7 | php5-fpm
|
||||||
,mysql-server | virtual-mysql-server
|
,mysql-server | virtual-mysql-server
|
||||||
,zoneminder-doc (>= ${source:Version})
|
,zoneminder-doc (>= ${source:Version})
|
||||||
Suggests: fcgiwrap, logrotate
|
Suggests: fcgiwrap, logrotate
|
||||||
|
|
|
@ -2,28 +2,57 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
. /etc/zm/zm.conf
|
|
||||||
|
|
||||||
if [ "$1" = "configure" ]; then
|
if [ "$1" = "configure" ]; then
|
||||||
|
|
||||||
|
. /etc/zm/zm.conf
|
||||||
|
|
||||||
|
# The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group
|
||||||
chown www-data:root /var/log/zm
|
chown www-data:root /var/log/zm
|
||||||
chown www-data:www-data /var/lib/zm
|
chown www-data:www-data /var/lib/zm
|
||||||
if [ -z "$2" ]; then
|
if [ -z "$2" ]; then
|
||||||
chown www-data:www-data -R /var/cache/zoneminder
|
chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/*
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Do this every time the package is installed or upgraded
|
# Do this every time the package is installed or upgraded
|
||||||
# Test for database presence to avoid failure of zmupdate.pl
|
|
||||||
|
if [ "$ZM_DB_HOST" = "localhost" ]; then
|
||||||
|
|
||||||
|
if [ -e "/etc/init.d/mysql" ]; then
|
||||||
|
|
||||||
|
#
|
||||||
|
# Get mysql started if it isn't
|
||||||
|
#
|
||||||
|
if ! $(/etc/init.d/mysql status >/dev/null 2>&1); then
|
||||||
|
deb-systemd-invoke start mysql.service || exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
if $(/etc/init.d/mysql status >/dev/null 2>&1); then
|
||||||
|
mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload
|
||||||
|
# test if database if already present...
|
||||||
|
if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then
|
||||||
|
cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf
|
||||||
|
# This creates the user.
|
||||||
|
echo "grant lock tables,alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||||
|
else
|
||||||
|
echo "grant lock tables,alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||||
|
fi
|
||||||
|
|
||||||
# Ensure zoneminder is stopped
|
# Ensure zoneminder is stopped
|
||||||
deb-systemd-invoke stop zoneminder.service || exit $?
|
deb-systemd-invoke stop zoneminder.service || exit $?
|
||||||
|
|
||||||
if [ "$ZM_DB_HOST" = "localhost" ]; then
|
|
||||||
echo 'grant lock tables, create, index, alter on zm.* to 'zmuser'@localhost identified by "zmpass";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
|
||||||
# Run the ZoneMinder update tool
|
|
||||||
zmupdate.pl --nointeractive
|
zmupdate.pl --nointeractive
|
||||||
|
zmupdate.pl --nointeractive -f
|
||||||
|
deb-systemd-invoke start zoneminder.service || exit $?
|
||||||
|
|
||||||
|
else
|
||||||
|
echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.'
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo 'mysql not found, assuming remote server.'
|
||||||
|
fi
|
||||||
|
|
||||||
else
|
else
|
||||||
echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)"
|
echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)"
|
||||||
fi;
|
fi
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -514,6 +514,8 @@ You do not need to rebuild ZM for X10 support. You will need to install the perl
|
||||||
|
|
||||||
Extending Zoneminder
|
Extending Zoneminder
|
||||||
------------------------
|
------------------------
|
||||||
|
.. _runstate_cron_example:
|
||||||
|
|
||||||
How can I get ZM to do different things at different times of day or week?
|
How can I get ZM to do different things at different times of day or week?
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
|
|
@ -67,8 +67,14 @@ own empty screen.
|
||||||
* **D**: This is the core of ZoneMinder - recording events. It gives you a count of how many events were recorded over the hour, day, week, month.
|
* **D**: This is the core of ZoneMinder - recording events. It gives you a count of how many events were recorded over the hour, day, week, month.
|
||||||
* **E**: These are the "Zones". Zones are areas within the camera that you mark as 'hotspots' for motion detection. Simply put, when you first configure your monitors (cameras), by default Zoneminder uses the entire field of view of the camera to detect motion. You may not want this. You may want to create "zones" specifically for detecting motion and ignore others. For example, lets consider a room with a fan that spins. You surely don't want to consider the fan moving continuously a reason for triggering a record? Probably not - in that case, you'd leave the fan out while making your zones.
|
* **E**: These are the "Zones". Zones are areas within the camera that you mark as 'hotspots' for motion detection. Simply put, when you first configure your monitors (cameras), by default Zoneminder uses the entire field of view of the camera to detect motion. You may not want this. You may want to create "zones" specifically for detecting motion and ignore others. For example, lets consider a room with a fan that spins. You surely don't want to consider the fan moving continuously a reason for triggering a record? Probably not - in that case, you'd leave the fan out while making your zones.
|
||||||
* **F**: This is the "source" column that tells you the type of the camera - if its an IP camera, a USB camera or more. In this example, they are all IP cameras. Note the color red on item F ? Well that means there is something wrong with that camera. No wonder the log also shows red. Good indication for you to tap on logs and investigate
|
* **F**: This is the "source" column that tells you the type of the camera - if its an IP camera, a USB camera or more. In this example, they are all IP cameras. Note the color red on item F ? Well that means there is something wrong with that camera. No wonder the log also shows red. Good indication for you to tap on logs and investigate
|
||||||
* **G**: This defines how Zoneminder will record events. There are various modes. In brief Modect == record if a motion is detected,Record = always record 24x7, Mocord = always record PLUS detect motion, Monitor = just provide a live view but don't record anytime, Nodect = Don't record till an externa entity via zmtrigger tells Zoneminder to (this is advanced usage).
|
* **G**: This defines how Zoneminder will record events. There are various modes. In brief Modect == record if a motion is detected,Record = always record 24x7, Mocord = always record PLUS detect motion, Monitor = just provide a live view but don't record anytime, Nodect = Don't record till an external entity via zmtrigger tells Zoneminder to (this is advanced usage).
|
||||||
* **H**: If you click on these links you can view a "Montage" of all your configured monitors or cycle through each one
|
* **H**: If you click on these links you can view a "Montage" of all your configured monitors or cycle through each one
|
||||||
|
* **I**: One of the most often missed features is the ability of ZoneMinder to maintain "run states". If you click on the "Running" text, ZoneMinder brings up a popup that allows you to define additional "states" (referred to as runstates). A runstate is essentially a snapshot that records the state of each monitor and you can switch between states easily. For example, you might have a run state defined that switches all monitors to "monitor" mode in which they are not recording anything while another state that sets some of the monitors to "modect". Why would you want this? A great example is to disable recording when you are at home and enable when you are away, based on time of day or other triggers. You can switch states by selecting an appropriate state manually, or do it automatically via cron jobs, for example. An example of using cron to automatically switch is provided in the :ref:`FAQ <runstate_cron_example>`. More esoteric examples of switching run states based on phone location can be found `here <https://forums.zoneminder.com/viewtopic.php?f=9&t=23026>`__.
|
||||||
|
|
||||||
|
Here is an example of multiple run states that I've defined. Each one of these runstates changes the mode of specific monitors depending on time of day and other conditions. Use your imagination to decide which conditions require state changes.
|
||||||
|
|
||||||
|
.. image:: images/runstates.png
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Adding Monitors
|
Adding Monitors
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 230 KiB After Width: | Height: | Size: 230 KiB |
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
|
@ -3825,6 +3825,41 @@ body = "ZM alarm detected - %EL% secs, %EF%/%EFA% frames, t%EST%/m%ESM%/a%ESA% s
|
||||||
readonly => 1,
|
readonly => 1,
|
||||||
category => "dynamic",
|
category => "dynamic",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name => "ZM_SSMTP_MAIL",
|
||||||
|
default => "no",
|
||||||
|
description => qqq("
|
||||||
|
Use a SSMTP mail server if available.
|
||||||
|
NEW_MAIL_MODULES must be enabled
|
||||||
|
"),
|
||||||
|
requires => [
|
||||||
|
{ name => "ZM_OPT_EMAIL", value => "yes" },
|
||||||
|
{ name => "ZM_OPT_MESSAGE", value => "yes" },
|
||||||
|
{ name => "ZM_NEW_MAIL_MODULES", value => "yes" }
|
||||||
|
],
|
||||||
|
help => qqq("
|
||||||
|
SSMTP is a lightweight and efficient method to send email.
|
||||||
|
The SSMTP application is not installed by default.
|
||||||
|
NEW_MAIL_MODULES must also be enabled.
|
||||||
|
Please visit: http://www.zoneminder.com/wiki/index.php/How_to_get_ssmtp_working_with_Zoneminder
|
||||||
|
for setup and configuration help.
|
||||||
|
"),
|
||||||
|
type => $types{boolean},
|
||||||
|
category => "mail",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name => "ZM_SSMTP_PATH",
|
||||||
|
default => "",
|
||||||
|
description => "SSMTP executable path",
|
||||||
|
requires => [{ name => "ZM_SSMTP_MAIL", value => "yes" }],
|
||||||
|
help => qqq("
|
||||||
|
Recommend setting the path to the SSMTP application.
|
||||||
|
If path is not defined. Zoneminder will try to determine
|
||||||
|
the path via shell command. Example path: /usr/sbin/ssmtp.
|
||||||
|
"),
|
||||||
|
type => $types{string},
|
||||||
|
category => "mail",
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
our %options_hash = map { ( $_->{name}, $_ ) } @options;
|
our %options_hash = map { ( $_->{name}, $_ ) } @options;
|
||||||
|
|
|
@ -155,10 +155,12 @@ MAIN: while( $loop ) {
|
||||||
Fatal("ZM_AUDIT_MIN_AGE is not set in config.");
|
Fatal("ZM_AUDIT_MIN_AGE is not set in config.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my %Monitors;
|
||||||
my $db_monitors;
|
my $db_monitors;
|
||||||
my $monitorSelectSql = "select Id from Monitors order by Id";
|
my $monitorSelectSql = "select * from Monitors order by Id";
|
||||||
my $monitorSelectSth = $dbh->prepare_cached( $monitorSelectSql )
|
my $monitorSelectSth = $dbh->prepare_cached( $monitorSelectSql )
|
||||||
or Fatal( "Can't prepare '$monitorSelectSql': ".$dbh->errstr() );
|
or Fatal( "Can't prepare '$monitorSelectSql': ".$dbh->errstr() );
|
||||||
|
|
||||||
my $eventSelectSql = "SELECT Id, (unix_timestamp() - unix_timestamp(StartTime)) as Age
|
my $eventSelectSql = "SELECT Id, (unix_timestamp() - unix_timestamp(StartTime)) as Age
|
||||||
FROM Events WHERE MonitorId = ? ORDER BY Id";
|
FROM Events WHERE MonitorId = ? ORDER BY Id";
|
||||||
my $eventSelectSth = $dbh->prepare_cached( $eventSelectSql )
|
my $eventSelectSth = $dbh->prepare_cached( $eventSelectSql )
|
||||||
|
@ -169,6 +171,8 @@ MAIN: while( $loop ) {
|
||||||
or Fatal( "Can't execute: ".$monitorSelectSth->errstr() );
|
or Fatal( "Can't execute: ".$monitorSelectSth->errstr() );
|
||||||
while( my $monitor = $monitorSelectSth->fetchrow_hashref() )
|
while( my $monitor = $monitorSelectSth->fetchrow_hashref() )
|
||||||
{
|
{
|
||||||
|
$Monitors{$$monitor{Id}} = $monitor;
|
||||||
|
|
||||||
Debug( "Found database monitor '$monitor->{Id}'" );
|
Debug( "Found database monitor '$monitor->{Id}'" );
|
||||||
my $db_events = $db_monitors->{$monitor->{Id}} = {};
|
my $db_events = $db_monitors->{$monitor->{Id}} = {};
|
||||||
my $res = $eventSelectSth->execute( $monitor->{Id} )
|
my $res = $eventSelectSth->execute( $monitor->{Id} )
|
||||||
|
@ -467,20 +471,30 @@ MAIN: while( $loop ) {
|
||||||
|
|
||||||
# New audit to close any events that were left open for longer than MIN_AGE seconds
|
# New audit to close any events that were left open for longer than MIN_AGE seconds
|
||||||
my $selectUnclosedEventsSql =
|
my $selectUnclosedEventsSql =
|
||||||
"SELECT E.Id,
|
#"SELECT E.Id, ANY_VALUE(E.MonitorId),
|
||||||
max(F.TimeStamp) as EndTime,
|
#
|
||||||
unix_timestamp(max(F.TimeStamp)) - unix_timestamp(E.StartTime) as Length,
|
#max(F.TimeStamp) as EndTime,
|
||||||
max(F.FrameId) as Frames,
|
#unix_timestamp(max(F.TimeStamp)) - unix_timestamp(E.StartTime) as Length,
|
||||||
|
#max(F.FrameId) as Frames,
|
||||||
|
#count(if(F.Score>0,1,NULL)) as AlarmFrames,
|
||||||
|
#sum(F.Score) as TotScore,
|
||||||
|
#max(F.Score) as MaxScore
|
||||||
|
#FROM Events as E
|
||||||
|
#INNER JOIN Frames as F on E.Id = F.EventId
|
||||||
|
#WHERE isnull(E.Frames) or isnull(E.EndTime)
|
||||||
|
#GROUP BY E.Id HAVING EndTime < (now() - interval ".$Config{ZM_AUDIT_MIN_AGE}." second)"
|
||||||
|
#;
|
||||||
|
"SELECT *, unix_timestamp(StartTime) AS TimeStamp FROM Events WHERE EndTime IS NULL AND StartTime < (now() - interval ".$Config{ZM_AUDIT_MIN_AGE}." second)";
|
||||||
|
|
||||||
|
my $selectFrameDataSql = "SELECT max(TimeStamp) as EndTime, unix_timestamp(max(TimeStamp)) AS EndTimeStamp, max(FrameId) as Frames,
|
||||||
count(if(F.Score>0,1,NULL)) as AlarmFrames,
|
count(if(F.Score>0,1,NULL)) as AlarmFrames,
|
||||||
sum(F.Score) as TotScore,
|
sum(F.Score) as TotScore,
|
||||||
max(F.Score) as MaxScore,
|
max(F.Score) as MaxScore
|
||||||
M.EventPrefix as Prefix
|
FROM Frames WHERE EventId=?";
|
||||||
FROM Events as E
|
my $selectFrameDataSth = $dbh->prepare_cached($selectFrameDataSql)
|
||||||
LEFT JOIN Monitors as M on E.MonitorId = M.Id
|
or Fatal( "Can't prepare '$selectFrameDataSql': ".$dbh->errstr() );
|
||||||
INNER JOIN Frames as F on E.Id = F.EventId
|
|
||||||
WHERE isnull(E.Frames) or isnull(E.EndTime)
|
|
||||||
GROUP BY E.Id HAVING EndTime < (now() - interval ".$Config{ZM_AUDIT_MIN_AGE}." second)"
|
|
||||||
;
|
|
||||||
my $selectUnclosedEventsSth = $dbh->prepare_cached( $selectUnclosedEventsSql )
|
my $selectUnclosedEventsSth = $dbh->prepare_cached( $selectUnclosedEventsSql )
|
||||||
or Fatal( "Can't prepare '$selectUnclosedEventsSql': ".$dbh->errstr() );
|
or Fatal( "Can't prepare '$selectUnclosedEventsSql': ".$dbh->errstr() );
|
||||||
my $updateUnclosedEventsSql =
|
my $updateUnclosedEventsSql =
|
||||||
|
@ -505,26 +519,32 @@ MAIN: while( $loop ) {
|
||||||
aud_print( "Found open event '$event->{Id}'" );
|
aud_print( "Found open event '$event->{Id}'" );
|
||||||
if ( confirm( 'close', 'closing' ) )
|
if ( confirm( 'close', 'closing' ) )
|
||||||
{
|
{
|
||||||
|
$res = $selectFrameDataSth->execute( $event->{Id} );
|
||||||
|
my $frame = $selectFrameDataSth->fetchrow_hashref();
|
||||||
|
if ( $frame ) {
|
||||||
$res = $updateUnclosedEventsSth->execute
|
$res = $updateUnclosedEventsSth->execute
|
||||||
(
|
(
|
||||||
sprintf("%s%d%s",
|
sprintf("%s%d%s",
|
||||||
$event->{Prefix},
|
$Monitors{$event->{MonitorId}}->{EventPrefix},
|
||||||
$event->{Id},
|
$event->{Id},
|
||||||
RECOVER_TAG
|
RECOVER_TAG
|
||||||
),
|
),
|
||||||
$event->{EndTime},
|
$frame->{EndTime},
|
||||||
$event->{Length},
|
$frame->{EndTimeStamp} - $event->{TimeStamp},
|
||||||
$event->{Frames},
|
$frame->{Frames},
|
||||||
$event->{AlarmFrames},
|
$frame->{AlarmFrames},
|
||||||
$event->{TotScore},
|
$frame->{TotScore},
|
||||||
$event->{AlarmFrames}
|
$frame->{AlarmFrames}
|
||||||
? int($event->{TotScore} / $event->{AlarmFrames})
|
? int($frame->{TotScore} / $frame->{AlarmFrames})
|
||||||
: 0
|
: 0
|
||||||
,
|
,
|
||||||
$event->{MaxScore},
|
$frame->{MaxScore},
|
||||||
RECOVER_TEXT,
|
RECOVER_TEXT,
|
||||||
$event->{Id}
|
$event->{Id}
|
||||||
) or Fatal( "Can't execute: ".$updateUnclosedEventsSth->errstr() );
|
) or Fatal( "Can't execute: ".$updateUnclosedEventsSth->errstr() );
|
||||||
|
} else {
|
||||||
|
Error("SHOULD DELETE");
|
||||||
|
} # end if has frame data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -862,7 +862,7 @@ sub killAll
|
||||||
my $killall;
|
my $killall;
|
||||||
if ( '@HOST_OS@' eq 'BSD' )
|
if ( '@HOST_OS@' eq 'BSD' )
|
||||||
{
|
{
|
||||||
$killall = 'killall -';
|
$killall = 'killall -q -';
|
||||||
} elsif ( '@HOST_OS@' eq 'solaris' ) {
|
} elsif ( '@HOST_OS@' eq 'solaris' ) {
|
||||||
$killall = 'pkill -';
|
$killall = 'pkill -';
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -779,10 +779,32 @@ sub sendEmail
|
||||||
Disposition => "attachment"
|
Disposition => "attachment"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
### Send the Message
|
if ( $Config{ZM_SSMTP_MAIL} ){
|
||||||
|
|
||||||
|
my $ssmtp_location = $Config{ZM_SSMTP_PATH};
|
||||||
|
|
||||||
|
if( ! $ssmtp_location ){
|
||||||
|
|
||||||
|
$ssmtp_location = qx('which ssmtp');
|
||||||
|
|
||||||
|
if ( logDebugging() )
|
||||||
|
{
|
||||||
|
Debug( "which ssmtp: $ssmtp_location - set ssmtp path in options to suppress this message\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$mail->send( 'sendmail', $ssmtp_location, $Config{ZM_EMAIL_ADDRESS} );
|
||||||
|
|
||||||
|
}else{
|
||||||
|
|
||||||
MIME::Lite->send( "smtp", $Config{ZM_EMAIL_HOST}, Timeout=>60 );
|
MIME::Lite->send( "smtp", $Config{ZM_EMAIL_HOST}, Timeout=>60 );
|
||||||
$mail->send();
|
$mail->send();
|
||||||
}
|
}
|
||||||
|
### Send the Message
|
||||||
|
#MIME::Lite->send( "smtp", $Config{ZM_EMAIL_HOST}, Timeout=>60 );
|
||||||
|
#$mail->send();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
my $mail = MIME::Entity->build(
|
my $mail = MIME::Entity->build(
|
||||||
|
|
|
@ -117,7 +117,8 @@ void zmLoadConfig()
|
||||||
|
|
||||||
Debug( 1, "Fetching ZM_SERVER_ID For Name = %s", staticConfig.SERVER_NAME.c_str() );
|
Debug( 1, "Fetching ZM_SERVER_ID For Name = %s", staticConfig.SERVER_NAME.c_str() );
|
||||||
std::string sql = stringtf("SELECT Id FROM Servers WHERE Name='%s'", staticConfig.SERVER_NAME.c_str() );
|
std::string sql = stringtf("SELECT Id FROM Servers WHERE Name='%s'", staticConfig.SERVER_NAME.c_str() );
|
||||||
if ( MYSQL_ROW dbrow = zmDbFetchOne( sql.c_str() ) ) {
|
zmDbRow dbrow;
|
||||||
|
if ( dbrow.fetch( sql.c_str() ) ) {
|
||||||
staticConfig.SERVER_ID = atoi(dbrow[0]);
|
staticConfig.SERVER_ID = atoi(dbrow[0]);
|
||||||
} else {
|
} else {
|
||||||
Fatal("Can't get ServerId for Server %s", staticConfig.SERVER_NAME.c_str() );
|
Fatal("Can't get ServerId for Server %s", staticConfig.SERVER_NAME.c_str() );
|
||||||
|
@ -128,7 +129,8 @@ void zmLoadConfig()
|
||||||
Debug( 1, "Fetching ZM_SERVER_NAME For Id = %d", staticConfig.SERVER_ID );
|
Debug( 1, "Fetching ZM_SERVER_NAME For Id = %d", staticConfig.SERVER_ID );
|
||||||
std::string sql = stringtf("SELECT Name FROM Servers WHERE Id='%d'", staticConfig.SERVER_ID );
|
std::string sql = stringtf("SELECT Name FROM Servers WHERE Id='%d'", staticConfig.SERVER_ID );
|
||||||
|
|
||||||
if ( MYSQL_ROW dbrow = zmDbFetchOne( sql.c_str() ) ) {
|
zmDbRow dbrow;
|
||||||
|
if ( dbrow.fetch( sql.c_str() ) ) {
|
||||||
staticConfig.SERVER_NAME = std::string(dbrow[0]);
|
staticConfig.SERVER_NAME = std::string(dbrow[0]);
|
||||||
} else {
|
} else {
|
||||||
Fatal("Can't get ServerName for Server ID %d", staticConfig.SERVER_ID );
|
Fatal("Can't get ServerName for Server ID %d", staticConfig.SERVER_ID );
|
||||||
|
|
|
@ -95,19 +95,38 @@ MYSQL_RES * zmDbFetch( const char * query ) {
|
||||||
return result;
|
return result;
|
||||||
} // end MYSQL_RES * zmDbFetch( const char * query );
|
} // end MYSQL_RES * zmDbFetch( const char * query );
|
||||||
|
|
||||||
MYSQL_ROW zmDbFetchOne( const char *query ) {
|
zmDbRow *zmDbFetchOne( const char *query ) {
|
||||||
MYSQL_RES *result = zmDbFetch( query );
|
zmDbRow *row = new zmDbRow();
|
||||||
int n_rows = mysql_num_rows( result );
|
if ( row->fetch( query ) ) {
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
delete row;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
MYSQL_RES *zmDbRow::fetch( const char *query ) {
|
||||||
|
result_set = zmDbFetch( query );
|
||||||
|
if ( ! result_set ) return result_set;
|
||||||
|
|
||||||
|
int n_rows = mysql_num_rows( result_set );
|
||||||
if ( n_rows != 1 ) {
|
if ( n_rows != 1 ) {
|
||||||
Error( "Bogus number of lines return from query, %d returned for query %s.", n_rows, query );
|
Error( "Bogus number of lines return from query, %d returned for query %s.", n_rows, query );
|
||||||
return NULL;
|
mysql_free_result( result_set );
|
||||||
|
result_set = NULL;
|
||||||
|
return result_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
MYSQL_ROW dbrow = mysql_fetch_row( result );
|
row = mysql_fetch_row( result_set );
|
||||||
mysql_free_result( result );
|
if ( ! row ) {
|
||||||
if ( ! dbrow ) {
|
mysql_free_result( result_set );
|
||||||
|
result_set = NULL;
|
||||||
Error("Error getting row from query %s. Error is %s", query, mysql_error( &dbconn ) );
|
Error("Error getting row from query %s. Error is %s", query, mysql_error( &dbconn ) );
|
||||||
return NULL;
|
} else {
|
||||||
|
Debug(3, "Succes");
|
||||||
}
|
}
|
||||||
return dbrow;
|
return result_set;
|
||||||
|
}
|
||||||
|
zmDbRow::~zmDbRow() {
|
||||||
|
if ( result_set )
|
||||||
|
mysql_free_result( result_set );
|
||||||
}
|
}
|
||||||
|
|
17
src/zm_db.h
17
src/zm_db.h
|
@ -22,6 +22,21 @@
|
||||||
|
|
||||||
#include <mysql/mysql.h>
|
#include <mysql/mysql.h>
|
||||||
|
|
||||||
|
class zmDbRow {
|
||||||
|
private:
|
||||||
|
MYSQL_RES *result_set;
|
||||||
|
MYSQL_ROW row;
|
||||||
|
public:
|
||||||
|
zmDbRow() { result_set = NULL; row = NULL; };
|
||||||
|
MYSQL_RES *fetch( const char *query );
|
||||||
|
zmDbRow( MYSQL_RES *, MYSQL_ROW *row );
|
||||||
|
~zmDbRow();
|
||||||
|
|
||||||
|
char *operator[](unsigned int index) const {
|
||||||
|
return row[index];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
@ -33,7 +48,7 @@ void zmDbConnect();
|
||||||
void zmDbClose();
|
void zmDbClose();
|
||||||
|
|
||||||
MYSQL_RES * zmDbFetch( const char *query );
|
MYSQL_RES * zmDbFetch( const char *query );
|
||||||
MYSQL_ROW zmDbFetchOne( const char *query );
|
zmDbRow *zmDbFetchOne( const char *query );
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|
|
@ -840,7 +840,7 @@ bool EventStream::loadInitialEventData( int monitor_id, time_t event_time )
|
||||||
return( true );
|
return( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EventStream::loadInitialEventData( int init_event_id, int init_frame_id )
|
bool EventStream::loadInitialEventData( int init_event_id, unsigned int init_frame_id )
|
||||||
{
|
{
|
||||||
loadEventData( init_event_id );
|
loadEventData( init_event_id );
|
||||||
|
|
||||||
|
|
|
@ -49,23 +49,23 @@ class Monitor;
|
||||||
//
|
//
|
||||||
class Event
|
class Event
|
||||||
{
|
{
|
||||||
friend class EventStream;
|
friend class EventStream;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static bool initialised;
|
static bool initialised;
|
||||||
static char capture_file_format[PATH_MAX];
|
static char capture_file_format[PATH_MAX];
|
||||||
static char analyse_file_format[PATH_MAX];
|
static char analyse_file_format[PATH_MAX];
|
||||||
static char general_file_format[PATH_MAX];
|
static char general_file_format[PATH_MAX];
|
||||||
static char video_file_format[PATH_MAX];
|
static char video_file_format[PATH_MAX];
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static int sd;
|
static int sd;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef std::set<std::string> StringSet;
|
typedef std::set<std::string> StringSet;
|
||||||
typedef std::map<std::string,StringSet> StringSetMap;
|
typedef std::map<std::string,StringSet> StringSetMap;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef enum { NORMAL, BULK, ALARM } FrameType;
|
typedef enum { NORMAL, BULK, ALARM } FrameType;
|
||||||
|
|
||||||
struct PreAlarmData
|
struct PreAlarmData
|
||||||
|
@ -79,7 +79,7 @@ protected:
|
||||||
static int pre_alarm_count;
|
static int pre_alarm_count;
|
||||||
static PreAlarmData pre_alarm_data[MAX_PRE_ALARM_FRAMES];
|
static PreAlarmData pre_alarm_data[MAX_PRE_ALARM_FRAMES];
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
Monitor *monitor;
|
Monitor *monitor;
|
||||||
struct timeval start_time;
|
struct timeval start_time;
|
||||||
|
@ -99,10 +99,10 @@ protected:
|
||||||
char timecodes_name[PATH_MAX];
|
char timecodes_name[PATH_MAX];
|
||||||
char timecodes_file[PATH_MAX];
|
char timecodes_file[PATH_MAX];
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int last_db_frame;
|
int last_db_frame;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void Initialise()
|
static void Initialise()
|
||||||
{
|
{
|
||||||
if ( initialised )
|
if ( initialised )
|
||||||
|
@ -118,11 +118,11 @@ protected:
|
||||||
|
|
||||||
void createNotes( std::string ¬es );
|
void createNotes( std::string ¬es );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static bool OpenFrameSocket( int );
|
static bool OpenFrameSocket( int );
|
||||||
static bool ValidateFrameSocket( int );
|
static bool ValidateFrameSocket( int );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap, bool p_videoEvent=false );
|
Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap, bool p_videoEvent=false );
|
||||||
~Event();
|
~Event();
|
||||||
|
|
||||||
|
@ -144,10 +144,10 @@ public:
|
||||||
void AddFrames( int n_frames, Image **images, struct timeval **timestamps );
|
void AddFrames( int n_frames, Image **images, struct timeval **timestamps );
|
||||||
void AddFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL );
|
void AddFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void AddFramesInternal( int n_frames, int start_frame, Image **images, struct timeval **timestamps );
|
void AddFramesInternal( int n_frames, int start_frame, Image **images, struct timeval **timestamps );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const char *getSubPath( struct tm *time )
|
static const char *getSubPath( struct tm *time )
|
||||||
{
|
{
|
||||||
static char subpath[PATH_MAX] = "";
|
static char subpath[PATH_MAX] = "";
|
||||||
|
@ -163,7 +163,7 @@ public:
|
||||||
return video_file;
|
return video_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static int PreAlarmCount()
|
static int PreAlarmCount()
|
||||||
{
|
{
|
||||||
return( pre_alarm_count );
|
return( pre_alarm_count );
|
||||||
|
@ -204,10 +204,10 @@ public:
|
||||||
|
|
||||||
class EventStream : public StreamBase
|
class EventStream : public StreamBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef enum { MODE_SINGLE, MODE_ALL, MODE_ALL_GAPLESS } StreamMode;
|
typedef enum { MODE_SINGLE, MODE_ALL, MODE_ALL_GAPLESS } StreamMode;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct FrameData {
|
struct FrameData {
|
||||||
//unsigned long id;
|
//unsigned long id;
|
||||||
time_t timestamp;
|
time_t timestamp;
|
||||||
|
@ -230,31 +230,31 @@ protected:
|
||||||
char video_file[PATH_MAX];
|
char video_file[PATH_MAX];
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static const int STREAM_PAUSE_WAIT = 250000; // Microseconds
|
static const int STREAM_PAUSE_WAIT = 250000; // Microseconds
|
||||||
|
|
||||||
static const StreamMode DEFAULT_MODE = MODE_SINGLE;
|
static const StreamMode DEFAULT_MODE = MODE_SINGLE;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
StreamMode mode;
|
StreamMode mode;
|
||||||
bool forceEventChange;
|
bool forceEventChange;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int curr_frame_id;
|
int curr_frame_id;
|
||||||
double curr_stream_time;
|
double curr_stream_time;
|
||||||
|
|
||||||
EventData *event_data;
|
EventData *event_data;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool loadEventData( int event_id );
|
bool loadEventData( int event_id );
|
||||||
bool loadInitialEventData( int init_event_id, int init_frame_id );
|
bool loadInitialEventData( int init_event_id, unsigned int init_frame_id );
|
||||||
bool loadInitialEventData( int monitor_id, time_t event_time );
|
bool loadInitialEventData( int monitor_id, time_t event_time );
|
||||||
|
|
||||||
void checkEventLoaded();
|
void checkEventLoaded();
|
||||||
void processCommand( const CmdMsg *msg );
|
void processCommand( const CmdMsg *msg );
|
||||||
bool sendFrame( int delta_us );
|
bool sendFrame( int delta_us );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EventStream()
|
EventStream()
|
||||||
{
|
{
|
||||||
mode = DEFAULT_MODE;
|
mode = DEFAULT_MODE;
|
||||||
|
@ -266,7 +266,7 @@ public:
|
||||||
|
|
||||||
event_data = 0;
|
event_data = 0;
|
||||||
}
|
}
|
||||||
void setStreamStart( int init_event_id, int init_frame_id=0 )
|
void setStreamStart( int init_event_id, unsigned int init_frame_id=0 )
|
||||||
{
|
{
|
||||||
loadInitialEventData( init_event_id, init_frame_id );
|
loadInitialEventData( init_event_id, init_frame_id );
|
||||||
loadMonitor( event_data->monitor_id );
|
loadMonitor( event_data->monitor_id );
|
||||||
|
|
|
@ -167,12 +167,21 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Check the buffer sizes */
|
/* Check the buffer sizes */
|
||||||
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
|
size_t insize = av_image_get_buffer_size(in_pf, width, height,1);
|
||||||
|
#else
|
||||||
size_t insize = avpicture_get_size(in_pf, width, height);
|
size_t insize = avpicture_get_size(in_pf, width, height);
|
||||||
|
#endif
|
||||||
if(insize != in_buffer_size) {
|
if(insize != in_buffer_size) {
|
||||||
Error("The input buffer size does not match the expected size for the input format. Required: %d Available: %d", insize, in_buffer_size);
|
Error("The input buffer size does not match the expected size for the input format. Required: %d Available: %d", insize, in_buffer_size);
|
||||||
return -4;
|
return -4;
|
||||||
}
|
}
|
||||||
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
|
size_t outsize = av_image_get_buffer_size(out_pf, width, height,1);
|
||||||
|
#else
|
||||||
size_t outsize = avpicture_get_size(out_pf, width, height);
|
size_t outsize = avpicture_get_size(out_pf, width, height);
|
||||||
|
#endif
|
||||||
|
|
||||||
if(outsize < out_buffer_size) {
|
if(outsize < out_buffer_size) {
|
||||||
Error("The output buffer is undersized for the output format. Required: %d Available: %d", outsize, out_buffer_size);
|
Error("The output buffer is undersized for the output format. Required: %d Available: %d", outsize, out_buffer_size);
|
||||||
return -5;
|
return -5;
|
||||||
|
@ -186,11 +195,27 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in the buffers */
|
/* Fill in the buffers */
|
||||||
if(!avpicture_fill( (AVPicture*)input_avframe, (uint8_t*)in_buffer, in_pf, width, height ) ) {
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
|
if(av_image_fill_arrays(input_avframe->data, input_avframe->linesize,
|
||||||
|
(uint8_t*)in_buffer, in_pf, width, height, 1) <= 0)
|
||||||
|
{
|
||||||
|
#else
|
||||||
|
if(avpicture_fill( (AVPicture*)input_avframe, (uint8_t*)in_buffer,
|
||||||
|
in_pf, width, height ) <= 0)
|
||||||
|
{
|
||||||
|
#endif
|
||||||
Error("Failed filling input frame with input buffer");
|
Error("Failed filling input frame with input buffer");
|
||||||
return -7;
|
return -7;
|
||||||
}
|
}
|
||||||
if(!avpicture_fill( (AVPicture*)output_avframe, out_buffer, out_pf, width, height ) ) {
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
|
if(av_image_fill_arrays(output_avframe->data, output_avframe->linesize,
|
||||||
|
out_buffer, out_pf, width, height, 1) <= 0)
|
||||||
|
{
|
||||||
|
#else
|
||||||
|
if(avpicture_fill( (AVPicture*)output_avframe, out_buffer,
|
||||||
|
out_pf, width, height ) <= 0)
|
||||||
|
{
|
||||||
|
#endif
|
||||||
Error("Failed filling output frame with output buffer");
|
Error("Failed filling output frame with output buffer");
|
||||||
return -8;
|
return -8;
|
||||||
}
|
}
|
||||||
|
@ -338,15 +363,9 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output)
|
||||||
int flags = (is_output ? ic->oformat->flags : ic->iformat->flags);
|
int flags = (is_output ? ic->oformat->flags : ic->iformat->flags);
|
||||||
AVStream *st = ic->streams[i];
|
AVStream *st = ic->streams[i];
|
||||||
AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0);
|
AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0);
|
||||||
unsigned char *separator = ic->dump_separator;
|
char separator = '\n';
|
||||||
char **codec_separator = (char **)av_opt_ptr(st->codec->av_class, st->codec, "dump_separator");
|
|
||||||
int use_format_separator = !*codec_separator;
|
|
||||||
|
|
||||||
if (use_format_separator)
|
|
||||||
*codec_separator = av_strdup((const char *)separator);
|
|
||||||
avcodec_string(buf, sizeof(buf), st->codec, is_output);
|
avcodec_string(buf, sizeof(buf), st->codec, is_output);
|
||||||
if (use_format_separator)
|
|
||||||
av_freep(codec_separator);
|
|
||||||
Debug(3, " Stream #%d:%d", index, i);
|
Debug(3, " Stream #%d:%d", index, i);
|
||||||
|
|
||||||
/* the pid is an important information, so we display it */
|
/* the pid is an important information, so we display it */
|
||||||
|
|
|
@ -48,6 +48,12 @@ extern "C" {
|
||||||
#else
|
#else
|
||||||
#include <libavcodec/opt.h>
|
#include <libavcodec/opt.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
|
#include <libavutil/imgutils.h>
|
||||||
|
#else
|
||||||
|
#include <libavutil/avutil.h>
|
||||||
|
#endif
|
||||||
#elif HAVE_FFMPEG_AVUTIL_H
|
#elif HAVE_FFMPEG_AVUTIL_H
|
||||||
#include <ffmpeg/avutil.h>
|
#include <ffmpeg/avutil.h>
|
||||||
#include <ffmpeg/base64.h>
|
#include <ffmpeg/base64.h>
|
||||||
|
|
|
@ -61,6 +61,7 @@ FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::stri
|
||||||
mOpenStart = 0;
|
mOpenStart = 0;
|
||||||
mReopenThread = 0;
|
mReopenThread = 0;
|
||||||
wasRecording = false;
|
wasRecording = false;
|
||||||
|
videoStore = NULL;
|
||||||
|
|
||||||
#if HAVE_LIBSWSCALE
|
#if HAVE_LIBSWSCALE
|
||||||
mConvertContext = NULL;
|
mConvertContext = NULL;
|
||||||
|
@ -99,6 +100,7 @@ void FfmpegCamera::Initialise()
|
||||||
av_log_set_level( AV_LOG_QUIET );
|
av_log_set_level( AV_LOG_QUIET );
|
||||||
|
|
||||||
av_register_all();
|
av_register_all();
|
||||||
|
avformat_network_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FfmpegCamera::Terminate()
|
void FfmpegCamera::Terminate()
|
||||||
|
@ -191,7 +193,13 @@ int FfmpegCamera::Capture( Image &image )
|
||||||
if ( frameComplete ) {
|
if ( frameComplete ) {
|
||||||
Debug( 4, "Got frame %d", frameCount );
|
Debug( 4, "Got frame %d", frameCount );
|
||||||
|
|
||||||
avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height);
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
|
av_image_fill_arrays(mFrame->data, mFrame->linesize,
|
||||||
|
directbuffer, imagePixFormat, width, height, 1);
|
||||||
|
#else
|
||||||
|
avpicture_fill( (AVPicture *)mFrame, directbuffer,
|
||||||
|
imagePixFormat, width, height);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if HAVE_LIBSWSCALE
|
#if HAVE_LIBSWSCALE
|
||||||
if(mConvertContext == NULL) {
|
if(mConvertContext == NULL) {
|
||||||
|
@ -350,7 +358,8 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||||
if ( mAudioStreamId == -1 )
|
if ( mAudioStreamId == -1 )
|
||||||
Debug( 2, "Unable to locate audio stream in %s", mPath.c_str() );
|
Debug( 2, "Unable to locate audio stream in %s", mPath.c_str() );
|
||||||
|
|
||||||
Debug ( 1, "Found video stream" );
|
Debug ( 3, "Found video stream at index %d", mVideoStreamId );
|
||||||
|
Debug ( 3, "Found audio stream at index %d", mAudioStreamId );
|
||||||
|
|
||||||
mCodecContext = mFormatContext->streams[mVideoStreamId]->codec;
|
mCodecContext = mFormatContext->streams[mVideoStreamId]->codec;
|
||||||
|
|
||||||
|
@ -392,12 +401,17 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||||
|
|
||||||
Debug ( 1, "Allocated frames" );
|
Debug ( 1, "Allocated frames" );
|
||||||
|
|
||||||
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
|
int pSize = av_image_get_buffer_size( imagePixFormat, width, height,1 );
|
||||||
|
#else
|
||||||
int pSize = avpicture_get_size( imagePixFormat, width, height );
|
int pSize = avpicture_get_size( imagePixFormat, width, height );
|
||||||
|
#endif
|
||||||
|
|
||||||
if( (unsigned int)pSize != imagesize) {
|
if( (unsigned int)pSize != imagesize) {
|
||||||
Fatal("Image size mismatch. Required: %d Available: %d",pSize,imagesize);
|
Fatal("Image size mismatch. Required: %d Available: %d",pSize,imagesize);
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug ( 1, "Validated imagesize" );
|
Debug ( 1, "Validated imagesize %d", pSize );
|
||||||
|
|
||||||
#if HAVE_LIBSWSCALE
|
#if HAVE_LIBSWSCALE
|
||||||
Debug ( 1, "Calling sws_isSupportedInput" );
|
Debug ( 1, "Calling sws_isSupportedInput" );
|
||||||
|
@ -579,9 +593,11 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi
|
||||||
avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height);
|
avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height);
|
||||||
|
|
||||||
//Keep the last keyframe so we can establish immediate video
|
//Keep the last keyframe so we can establish immediate video
|
||||||
/*if(packet.flags & AV_PKT_FLAG_KEY)
|
if(packet.flags & AV_PKT_FLAG_KEY) {
|
||||||
av_copy_packet(&lastKeyframePkt, &packet);*/
|
//Debug(4, "Have keyframe");
|
||||||
|
//av_copy_packet(&lastKeyframePkt, &packet);
|
||||||
//TODO I think we need to store the key frame location for seeking as part of the event
|
//TODO I think we need to store the key frame location for seeking as part of the event
|
||||||
|
}
|
||||||
|
|
||||||
//Video recording
|
//Video recording
|
||||||
if ( recording && !wasRecording ) {
|
if ( recording && !wasRecording ) {
|
||||||
|
@ -592,6 +608,9 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi
|
||||||
wasRecording = true;
|
wasRecording = true;
|
||||||
strcpy(oldDirectory, event_file);
|
strcpy(oldDirectory, event_file);
|
||||||
|
|
||||||
|
|
||||||
|
// Need to write out all the frames from the last keyframe?
|
||||||
|
|
||||||
} else if ( ( ! recording ) && wasRecording && videoStore ) {
|
} else if ( ( ! recording ) && wasRecording && videoStore ) {
|
||||||
Info("Deleting videoStore instance");
|
Info("Deleting videoStore instance");
|
||||||
delete videoStore;
|
delete videoStore;
|
||||||
|
@ -649,9 +668,10 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi
|
||||||
}
|
}
|
||||||
if ( videoStore && recording ) {
|
if ( videoStore && recording ) {
|
||||||
if ( record_audio ) {
|
if ( record_audio ) {
|
||||||
Debug(3, "Recording audio packet" );
|
Debug(3, "Recording audio packet streamindex(%d) packetstreamindex(%d)", mAudioStreamId, packet.stream_index );
|
||||||
//Write the packet to our video store
|
//Write the packet to our video store
|
||||||
int ret = videoStore->writeAudioFramePacket(&packet, mFormatContext->streams[packet.stream_index]); //FIXME no relevance of last key frame
|
//FIXME no relevance of last key frame
|
||||||
|
int ret = videoStore->writeAudioFramePacket( &packet, mFormatContext->streams[packet.stream_index] );
|
||||||
if ( ret < 0 ) {//Less than zero and we skipped a frame
|
if ( ret < 0 ) {//Less than zero and we skipped a frame
|
||||||
av_free_packet( &packet );
|
av_free_packet( &packet );
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -661,7 +681,11 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
#if LIBAVUTIL_VERSION_CHECK(54, 23, 0, 23, 0)
|
||||||
Debug( 3, "Some other stream index %d, %s", packet.stream_index, av_get_media_type_string( mFormatContext->streams[packet.stream_index]->codec->codec_type) );
|
Debug( 3, "Some other stream index %d, %s", packet.stream_index, av_get_media_type_string( mFormatContext->streams[packet.stream_index]->codec->codec_type) );
|
||||||
|
#else
|
||||||
|
Debug( 3, "Some other stream index %d", packet.stream_index );
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
av_free_packet( &packet );
|
av_free_packet( &packet );
|
||||||
} // end while ! frameComplete
|
} // end while ! frameComplete
|
||||||
|
|
|
@ -64,7 +64,9 @@ protected:
|
||||||
bool wasRecording;
|
bool wasRecording;
|
||||||
VideoStore *videoStore;
|
VideoStore *videoStore;
|
||||||
char oldDirectory[4096];
|
char oldDirectory[4096];
|
||||||
//AVPacket lastKeyframePkt;
|
|
||||||
|
// Last Key frame
|
||||||
|
AVPacket lastKeyframePkt;
|
||||||
|
|
||||||
#if HAVE_LIBSWSCALE
|
#if HAVE_LIBSWSCALE
|
||||||
struct SwsContext *mConvertContext;
|
struct SwsContext *mConvertContext;
|
||||||
|
|
|
@ -644,7 +644,11 @@ LocalCamera::LocalCamera(
|
||||||
if ( !tmpPicture )
|
if ( !tmpPicture )
|
||||||
Fatal( "Could not allocate temporary picture" );
|
Fatal( "Could not allocate temporary picture" );
|
||||||
|
|
||||||
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
|
int pSize = av_image_get_buffer_size( imagePixFormat, width, height,1 );
|
||||||
|
#else
|
||||||
int pSize = avpicture_get_size( imagePixFormat, width, height );
|
int pSize = avpicture_get_size( imagePixFormat, width, height );
|
||||||
|
#endif
|
||||||
if( (unsigned int)pSize != imagesize) {
|
if( (unsigned int)pSize != imagesize) {
|
||||||
Fatal("Image size mismatch. Required: %d Available: %d",pSize,imagesize);
|
Fatal("Image size mismatch. Required: %d Available: %d",pSize,imagesize);
|
||||||
}
|
}
|
||||||
|
@ -877,7 +881,18 @@ void LocalCamera::Initialise()
|
||||||
#endif
|
#endif
|
||||||
if ( !capturePictures[i] )
|
if ( !capturePictures[i] )
|
||||||
Fatal( "Could not allocate picture" );
|
Fatal( "Could not allocate picture" );
|
||||||
avpicture_fill( (AVPicture *)capturePictures[i], (uint8_t*)v4l2_data.buffers[i].start, capturePixFormat, v4l2_data.fmt.fmt.pix.width, v4l2_data.fmt.fmt.pix.height );
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
|
av_image_fill_arrays(capturePictures[i]->data,
|
||||||
|
capturePictures[i]->linesize,
|
||||||
|
(uint8_t*)v4l2_data.buffers[i].start,capturePixFormat,
|
||||||
|
v4l2_data.fmt.fmt.pix.width,
|
||||||
|
v4l2_data.fmt.fmt.pix.height, 1);
|
||||||
|
#else
|
||||||
|
avpicture_fill( (AVPicture *)capturePictures[i],
|
||||||
|
(uint8_t*)v4l2_data.buffers[i].start, capturePixFormat,
|
||||||
|
v4l2_data.fmt.fmt.pix.width,
|
||||||
|
v4l2_data.fmt.fmt.pix.height );
|
||||||
|
#endif
|
||||||
#endif // HAVE_LIBSWSCALE
|
#endif // HAVE_LIBSWSCALE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1035,7 +1050,16 @@ void LocalCamera::Initialise()
|
||||||
#endif
|
#endif
|
||||||
if ( !capturePictures[i] )
|
if ( !capturePictures[i] )
|
||||||
Fatal( "Could not allocate picture" );
|
Fatal( "Could not allocate picture" );
|
||||||
avpicture_fill( (AVPicture *)capturePictures[i], (unsigned char *)v4l1_data.bufptr+v4l1_data.frames.offsets[i], capturePixFormat, width, height );
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
|
av_image_fill_arrays(capturePictures[i]->data,
|
||||||
|
capturePictures[i]->linesize,
|
||||||
|
(unsigned char *)v4l1_data.bufptr+v4l1_data.frames.offsets[i],
|
||||||
|
capturePixFormat, width, height, 1);
|
||||||
|
#else
|
||||||
|
avpicture_fill( (AVPicture *)capturePictures[i],
|
||||||
|
(unsigned char *)v4l1_data.bufptr+v4l1_data.frames.offsets[i],
|
||||||
|
capturePixFormat, width, height );
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif // HAVE_LIBSWSCALE
|
#endif // HAVE_LIBSWSCALE
|
||||||
|
|
||||||
|
@ -2131,7 +2155,14 @@ int LocalCamera::Capture( Image &image )
|
||||||
|
|
||||||
Debug( 9, "Calling sws_scale to perform the conversion" );
|
Debug( 9, "Calling sws_scale to perform the conversion" );
|
||||||
/* Use swscale to convert the image directly into the shared memory */
|
/* Use swscale to convert the image directly into the shared memory */
|
||||||
avpicture_fill( (AVPicture *)tmpPicture, directbuffer, imagePixFormat, width, height );
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
|
av_image_fill_arrays(tmpPicture->data,
|
||||||
|
tmpPicture->linesize, directbuffer,
|
||||||
|
imagePixFormat, width, height, 1);
|
||||||
|
#else
|
||||||
|
avpicture_fill( (AVPicture *)tmpPicture, directbuffer,
|
||||||
|
imagePixFormat, width, height );
|
||||||
|
#endif
|
||||||
sws_scale( imgConversionContext, capturePictures[capture_frame]->data, capturePictures[capture_frame]->linesize, 0, height, tmpPicture->data, tmpPicture->linesize );
|
sws_scale( imgConversionContext, capturePictures[capture_frame]->data, capturePictures[capture_frame]->linesize, 0, height, tmpPicture->data, tmpPicture->linesize );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -615,7 +615,7 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co
|
||||||
{
|
{
|
||||||
int priority = smSyslogPriorities[level];
|
int priority = smSyslogPriorities[level];
|
||||||
//priority |= LOG_DAEMON;
|
//priority |= LOG_DAEMON;
|
||||||
syslog( priority, "%s [%s]", classString, syslogStart );
|
syslog( priority, "%s [%s] [%s]", classString, mId.c_str(), syslogStart );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( level <= FATAL )
|
if ( level <= FATAL )
|
||||||
|
|
|
@ -1119,13 +1119,13 @@ void Monitor::DumpZoneImage( const char *zone_string ) {
|
||||||
Debug(3, "Trying to load from event");
|
Debug(3, "Trying to load from event");
|
||||||
// Grab the most revent event image
|
// Grab the most revent event image
|
||||||
std::string sql = stringtf( "SELECT MAX(Id) FROM Events WHERE MonitorId=%d AND Frames > 0", id );
|
std::string sql = stringtf( "SELECT MAX(Id) FROM Events WHERE MonitorId=%d AND Frames > 0", id );
|
||||||
MYSQL_ROW eventid_row = zmDbFetchOne(sql.c_str() );
|
zmDbRow eventid_row;
|
||||||
if ( eventid_row ) {
|
if ( eventid_row.fetch( sql.c_str() ) ) {
|
||||||
int event_id = atoi( eventid_row[0] );
|
int event_id = atoi( eventid_row[0] );
|
||||||
|
|
||||||
Debug( 3, "Got event %d", event_id );
|
Debug( 3, "Got event %d", event_id );
|
||||||
EventStream *stream = new EventStream();
|
EventStream *stream = new EventStream();
|
||||||
stream->setStreamStart( event_id, 1 );
|
stream->setStreamStart( event_id, (unsigned int)1 );
|
||||||
zone_image = stream->getImage();
|
zone_image = stream->getImage();
|
||||||
} else {
|
} else {
|
||||||
Error("Unable to load an event for monitor %d", id );
|
Error("Unable to load an event for monitor %d", id );
|
||||||
|
@ -1279,6 +1279,7 @@ bool Monitor::Analyse()
|
||||||
{
|
{
|
||||||
if ( shared_data->last_read_index == shared_data->last_write_index )
|
if ( shared_data->last_read_index == shared_data->last_write_index )
|
||||||
{
|
{
|
||||||
|
// I wonder how often this happens. Maybe if this happens we should sleep or something?
|
||||||
return( false );
|
return( false );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1299,8 +1300,10 @@ bool Monitor::Analyse()
|
||||||
if ( read_margin < 0 ) read_margin += image_buffer_count;
|
if ( read_margin < 0 ) read_margin += image_buffer_count;
|
||||||
|
|
||||||
int step = 1;
|
int step = 1;
|
||||||
|
// Isn't read_margin always > 0 here?
|
||||||
if ( read_margin > 0 )
|
if ( read_margin > 0 )
|
||||||
{
|
{
|
||||||
|
// TODO explain this so... 90% of image buffer / 50% of read margin?
|
||||||
step = (9*image_buffer_count)/(5*read_margin);
|
step = (9*image_buffer_count)/(5*read_margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1380,6 +1383,7 @@ bool Monitor::Analyse()
|
||||||
|
|
||||||
if ( static_undef )
|
if ( static_undef )
|
||||||
{
|
{
|
||||||
|
// Sure would be nice to be able to assume that these were already initialized. It's just 1 compare/branch, but really not neccessary.
|
||||||
static_undef = false;
|
static_undef = false;
|
||||||
timestamps = new struct timeval *[pre_event_count];
|
timestamps = new struct timeval *[pre_event_count];
|
||||||
images = new Image *[pre_event_count];
|
images = new Image *[pre_event_count];
|
||||||
|
@ -1392,6 +1396,7 @@ bool Monitor::Analyse()
|
||||||
bool signal_change = (signal != last_signal);
|
bool signal_change = (signal != last_signal);
|
||||||
|
|
||||||
//Set video recording flag for event start constructor and easy reference in code
|
//Set video recording flag for event start constructor and easy reference in code
|
||||||
|
// TODO: Use enum instead of the # 2. Makes for easier reading
|
||||||
bool videoRecording = ((GetOptVideoWriter() == 2) && camera->SupportsNativeVideo());
|
bool videoRecording = ((GetOptVideoWriter() == 2) && camera->SupportsNativeVideo());
|
||||||
|
|
||||||
if ( trigger_data->trigger_state != TRIGGER_OFF )
|
if ( trigger_data->trigger_state != TRIGGER_OFF )
|
||||||
|
@ -2177,9 +2182,6 @@ int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose
|
||||||
col++;
|
col++;
|
||||||
bool embed_exif = (*dbrow[col] != '0'); col++;
|
bool embed_exif = (*dbrow[col] != '0'); col++;
|
||||||
|
|
||||||
int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width);
|
|
||||||
int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height);
|
|
||||||
|
|
||||||
int extras = (deinterlacing>>24)&0xff;
|
int extras = (deinterlacing>>24)&0xff;
|
||||||
|
|
||||||
Camera *camera = new LocalCamera(
|
Camera *camera = new LocalCamera(
|
||||||
|
@ -2190,8 +2192,8 @@ int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose
|
||||||
v4l_multi_buffer,
|
v4l_multi_buffer,
|
||||||
v4l_captures_per_frame,
|
v4l_captures_per_frame,
|
||||||
method,
|
method,
|
||||||
cam_width,
|
width,
|
||||||
cam_height,
|
height,
|
||||||
colours,
|
colours,
|
||||||
palette,
|
palette,
|
||||||
brightness,
|
brightness,
|
||||||
|
@ -2344,9 +2346,6 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c
|
||||||
int track_motion = atoi(dbrow[col]); col++;
|
int track_motion = atoi(dbrow[col]); col++;
|
||||||
bool embed_exif = (*dbrow[col] != '0'); col++;
|
bool embed_exif = (*dbrow[col] != '0'); col++;
|
||||||
|
|
||||||
int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width);
|
|
||||||
int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height);
|
|
||||||
|
|
||||||
Camera *camera = 0;
|
Camera *camera = 0;
|
||||||
if ( protocol == "http" ) {
|
if ( protocol == "http" ) {
|
||||||
camera = new RemoteCameraHttp(
|
camera = new RemoteCameraHttp(
|
||||||
|
@ -2355,8 +2354,8 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c
|
||||||
host, // Host
|
host, // Host
|
||||||
port, // Port
|
port, // Port
|
||||||
path, // Path
|
path, // Path
|
||||||
cam_width,
|
width,
|
||||||
cam_height,
|
height,
|
||||||
colours,
|
colours,
|
||||||
brightness,
|
brightness,
|
||||||
contrast,
|
contrast,
|
||||||
|
@ -2374,8 +2373,8 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c
|
||||||
host, // Host
|
host, // Host
|
||||||
port, // Port
|
port, // Port
|
||||||
path, // Path
|
path, // Path
|
||||||
cam_width,
|
width,
|
||||||
cam_height,
|
height,
|
||||||
rtsp_describe,
|
rtsp_describe,
|
||||||
colours,
|
colours,
|
||||||
brightness,
|
brightness,
|
||||||
|
@ -2526,14 +2525,11 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu
|
||||||
int track_motion = atoi(dbrow[col]); col++;
|
int track_motion = atoi(dbrow[col]); col++;
|
||||||
bool embed_exif = (*dbrow[col] != '0'); col++;
|
bool embed_exif = (*dbrow[col] != '0'); col++;
|
||||||
|
|
||||||
int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width);
|
|
||||||
int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height);
|
|
||||||
|
|
||||||
Camera *camera = new FileCamera(
|
Camera *camera = new FileCamera(
|
||||||
id,
|
id,
|
||||||
path, // File
|
path, // File
|
||||||
cam_width,
|
width,
|
||||||
cam_height,
|
height,
|
||||||
colours,
|
colours,
|
||||||
brightness,
|
brightness,
|
||||||
contrast,
|
contrast,
|
||||||
|
@ -2683,16 +2679,13 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose
|
||||||
int track_motion = atoi(dbrow[col]); col++;
|
int track_motion = atoi(dbrow[col]); col++;
|
||||||
bool embed_exif = (*dbrow[col] != '0'); col++;
|
bool embed_exif = (*dbrow[col] != '0'); col++;
|
||||||
|
|
||||||
int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width);
|
|
||||||
int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height);
|
|
||||||
|
|
||||||
Camera *camera = new FfmpegCamera(
|
Camera *camera = new FfmpegCamera(
|
||||||
id,
|
id,
|
||||||
path, // File
|
path, // File
|
||||||
method,
|
method,
|
||||||
options,
|
options,
|
||||||
cam_width,
|
width,
|
||||||
cam_height,
|
height,
|
||||||
colours,
|
colours,
|
||||||
brightness,
|
brightness,
|
||||||
contrast,
|
contrast,
|
||||||
|
@ -2765,8 +2758,8 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose
|
||||||
Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) {
|
Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) {
|
||||||
std::string sql = stringtf( "select Id, Name, ServerId, StorageId, Type, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Protocol, Method, Host, Port, Path, Options, User, Pass, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Id = %d", p_id );
|
std::string sql = stringtf( "select Id, Name, ServerId, StorageId, Type, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Protocol, Method, Host, Port, Path, Options, User, Pass, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Id = %d", p_id );
|
||||||
|
|
||||||
MYSQL_ROW dbrow = zmDbFetchOne( sql.c_str() );
|
zmDbRow dbrow;
|
||||||
if ( ! dbrow ) {
|
if ( ! dbrow.fetch( sql.c_str() ) ) {
|
||||||
Error( "Can't use query result: %s", mysql_error( &dbconn ) );
|
Error( "Can't use query result: %s", mysql_error( &dbconn ) );
|
||||||
exit( mysql_errno( &dbconn ) );
|
exit( mysql_errno( &dbconn ) );
|
||||||
}
|
}
|
||||||
|
@ -2864,9 +2857,6 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) {
|
||||||
col++;
|
col++;
|
||||||
bool embed_exif = (*dbrow[col] != '0'); col++;
|
bool embed_exif = (*dbrow[col] != '0'); col++;
|
||||||
|
|
||||||
int cam_width = ((orientation==ROTATE_90||orientation==ROTATE_270)?height:width);
|
|
||||||
int cam_height = ((orientation==ROTATE_90||orientation==ROTATE_270)?width:height);
|
|
||||||
|
|
||||||
int extras = (deinterlacing>>24)&0xff;
|
int extras = (deinterlacing>>24)&0xff;
|
||||||
|
|
||||||
Camera *camera = 0;
|
Camera *camera = 0;
|
||||||
|
@ -2880,8 +2870,8 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) {
|
||||||
v4l_multi_buffer,
|
v4l_multi_buffer,
|
||||||
v4l_captures_per_frame,
|
v4l_captures_per_frame,
|
||||||
method,
|
method,
|
||||||
cam_width,
|
width,
|
||||||
cam_height,
|
height,
|
||||||
colours,
|
colours,
|
||||||
palette,
|
palette,
|
||||||
brightness,
|
brightness,
|
||||||
|
@ -2903,8 +2893,8 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) {
|
||||||
host.c_str(),
|
host.c_str(),
|
||||||
port.c_str(),
|
port.c_str(),
|
||||||
path.c_str(),
|
path.c_str(),
|
||||||
cam_width,
|
width,
|
||||||
cam_height,
|
height,
|
||||||
colours,
|
colours,
|
||||||
brightness,
|
brightness,
|
||||||
contrast,
|
contrast,
|
||||||
|
@ -2921,8 +2911,8 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) {
|
||||||
host.c_str(),
|
host.c_str(),
|
||||||
port.c_str(),
|
port.c_str(),
|
||||||
path.c_str(),
|
path.c_str(),
|
||||||
cam_width,
|
width,
|
||||||
cam_height,
|
height,
|
||||||
rtsp_describe,
|
rtsp_describe,
|
||||||
colours,
|
colours,
|
||||||
brightness,
|
brightness,
|
||||||
|
@ -2942,8 +2932,8 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) {
|
||||||
camera = new FileCamera(
|
camera = new FileCamera(
|
||||||
id,
|
id,
|
||||||
path.c_str(),
|
path.c_str(),
|
||||||
cam_width,
|
width,
|
||||||
cam_height,
|
height,
|
||||||
colours,
|
colours,
|
||||||
brightness,
|
brightness,
|
||||||
contrast,
|
contrast,
|
||||||
|
@ -2959,8 +2949,8 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) {
|
||||||
path.c_str(),
|
path.c_str(),
|
||||||
method,
|
method,
|
||||||
options,
|
options,
|
||||||
cam_width,
|
width,
|
||||||
cam_height,
|
height,
|
||||||
colours,
|
colours,
|
||||||
brightness,
|
brightness,
|
||||||
contrast,
|
contrast,
|
||||||
|
@ -2979,8 +2969,8 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) {
|
||||||
path.c_str(),
|
path.c_str(),
|
||||||
method,
|
method,
|
||||||
options,
|
options,
|
||||||
cam_width,
|
width,
|
||||||
cam_height,
|
height,
|
||||||
colours,
|
colours,
|
||||||
brightness,
|
brightness,
|
||||||
contrast,
|
contrast,
|
||||||
|
@ -2999,8 +2989,8 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) {
|
||||||
path.c_str(),
|
path.c_str(),
|
||||||
user.c_str(),
|
user.c_str(),
|
||||||
pass.c_str(),
|
pass.c_str(),
|
||||||
cam_width,
|
width,
|
||||||
cam_height,
|
height,
|
||||||
colours,
|
colours,
|
||||||
brightness,
|
brightness,
|
||||||
contrast,
|
contrast,
|
||||||
|
@ -3281,191 +3271,6 @@ bool Monitor::closeEvent()
|
||||||
return( false );
|
return( false );
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NOTE Nextime's comment:
|
|
||||||
*
|
|
||||||
* OurCheckAlarms seems to be called only by DetectBlack method, and DetectBlack
|
|
||||||
* method is only called in a commented line instead of DetectMotion in zm_monitor.cpp.
|
|
||||||
*
|
|
||||||
* Probably this is just a dead code used for debugghing purpose, so, instead of fixing it
|
|
||||||
* it seems to be safe to just comment it out.
|
|
||||||
*
|
|
||||||
* Anyway, the issues with this code is that it assumes the image to be an RGB24 image,
|
|
||||||
* so, as i've discussed on IRC with mastertheknife, changes needed are:
|
|
||||||
*
|
|
||||||
* Check if the image is 24 or 32 bits ( pImage->Colours() says 3 for 24 and 4 for 32 bits,
|
|
||||||
* comparing it with ZM_COLOUR_RGB24 or ZM_COLOUR_RGB32 is the way ), and then
|
|
||||||
* manage che check using RGB_VAL_RED() and so on macros instead of just RED().
|
|
||||||
*
|
|
||||||
* Be careful that in 32 bit images we need to check also where the alpha channel is, so,
|
|
||||||
* (RGBA and BGRA) or (ABGR and ARGB) aren't the same!
|
|
||||||
*
|
|
||||||
* To check black pixels in 32 bit images i can do a more efficient way using
|
|
||||||
* RGBA_ZERO_ALPHA(pixel) == RGBA_ZERO_ALPHA(RGB_BLACK), but before of that i need to
|
|
||||||
* check where the alpha channel is and maybe convert it.
|
|
||||||
* Maybe this won't work as they assign "23" to black_thr, so, they are not checking
|
|
||||||
* if the pixel is black, but just "quasi" black is enough.
|
|
||||||
*
|
|
||||||
* Anyway, for the moment, comment out whole part.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
bool Monitor::OurCheckAlarms( Zone *zone, const Image *pImage )
|
|
||||||
{
|
|
||||||
Info("Entering OurCheckAlarms >>>>>>>>>>>>>>>>>>>>>>>>>>>>");
|
|
||||||
unsigned char black_thr = 23;
|
|
||||||
int min_alarm_score = 10;
|
|
||||||
int max_alarm_score = 99;
|
|
||||||
//bool alarm = false;
|
|
||||||
unsigned int score;
|
|
||||||
Polygon zone_polygon = zone->GetPolygon();
|
|
||||||
Info("Got polygon of a zone. It has %d vertices.", zone_polygon.getNumCoords());
|
|
||||||
|
|
||||||
zone->ResetStats();
|
|
||||||
Info("ResetStats done.");
|
|
||||||
|
|
||||||
if ( !zone->CheckOverloadCount() )
|
|
||||||
{
|
|
||||||
Info("CheckOverloadCount() return false, we'll return false.");
|
|
||||||
return( false );
|
|
||||||
}
|
|
||||||
|
|
||||||
Image *pMaskImage = new Image(pImage->Width(), pImage->Height(), ZM_COLOUR_GRAY8, pImage->SubpixelOrder());
|
|
||||||
Info("Mask image created.");
|
|
||||||
|
|
||||||
pMaskImage->Fill(BLACK);
|
|
||||||
Info("Mask image filled with BLACK.");
|
|
||||||
if (pImage->Colours() == ZM_COLOUR_GRAY8)
|
|
||||||
{
|
|
||||||
Info("Analysed image is not colored! Set score = 0.");
|
|
||||||
score = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Info("Start processing image.");
|
|
||||||
//Process image
|
|
||||||
unsigned char *buffer = (unsigned char*)pImage->Buffer();
|
|
||||||
unsigned char *mask_buffer = (unsigned char*)pMaskImage->Buffer();
|
|
||||||
|
|
||||||
int black_pixels_count = 0;
|
|
||||||
Info("Loop for black pixels counting and mask filling.");
|
|
||||||
while (buffer < (pImage->Buffer() + pImage->Size()))
|
|
||||||
{
|
|
||||||
if ( (RED(buffer) < black_thr) && (GREEN(buffer) < black_thr) && (BLUE(buffer) < black_thr) )
|
|
||||||
{
|
|
||||||
*mask_buffer = WHITE;
|
|
||||||
black_pixels_count++;
|
|
||||||
}
|
|
||||||
buffer += pImage->Colours();
|
|
||||||
mask_buffer++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !black_pixels_count )
|
|
||||||
{
|
|
||||||
delete pMaskImage;
|
|
||||||
return( false );
|
|
||||||
}
|
|
||||||
score = (100*black_pixels_count)/zone_polygon.Area();
|
|
||||||
Info("Number of black pixels is %d, zone polygon area is %d, score is %d", black_pixels_count, zone_polygon.Area(), score);
|
|
||||||
|
|
||||||
if ( min_alarm_score && ( score < min_alarm_score) )
|
|
||||||
{
|
|
||||||
delete pMaskImage;
|
|
||||||
return( false );
|
|
||||||
}
|
|
||||||
if ( max_alarm_score && (score > max_alarm_score) )
|
|
||||||
{
|
|
||||||
zone->SetOverloadCount(zone->GetOverloadFrames());
|
|
||||||
delete pMaskImage;
|
|
||||||
return( false );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
zone->SetScore(score);
|
|
||||||
Info("Score have been set in zone.");
|
|
||||||
//Get mask
|
|
||||||
Rgb alarm_colour = RGB_RED;
|
|
||||||
Image *tempImage = pMaskImage->HighlightEdges(alarm_colour, &zone_polygon.Extent() );
|
|
||||||
Info("After HighlightEdges");
|
|
||||||
|
|
||||||
zone->SetAlarmImage(tempImage);
|
|
||||||
Info("After SetAlarmImage");
|
|
||||||
delete pMaskImage;
|
|
||||||
Info("After Delete pMaskImage");
|
|
||||||
delete tempImage;
|
|
||||||
|
|
||||||
Info("Leaving OurCheckAlarms >>>>>>>>>>>>>>>>>>>>>>>>>>>>");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int Monitor::DetectBlack(const Image &comp_image, Event::StringSet &zoneSet )
|
|
||||||
{
|
|
||||||
Info("Entering DetectBlack >>>>>>>>>>>>>>>>>>>>>>>>>>");
|
|
||||||
bool alarm = false;
|
|
||||||
unsigned int score = 0;
|
|
||||||
|
|
||||||
if ( n_zones <= 0 ) return( alarm );
|
|
||||||
|
|
||||||
// Coord alarm_centre;
|
|
||||||
// int top_score = -1;
|
|
||||||
|
|
||||||
// Find all alarm pixels in active zones
|
|
||||||
Info("Number of zones to process %d", n_zones);
|
|
||||||
for ( int n_zone = 0; n_zone < n_zones; n_zone++ )
|
|
||||||
{
|
|
||||||
Zone *zone = zones[n_zone];
|
|
||||||
if ( !zone->IsActive() )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Debug( 3, "Checking active zone %s", zone->Label() );
|
|
||||||
Info( "Checking active zone %s", zone->Label() );
|
|
||||||
if ( OurCheckAlarms( zone, &comp_image ) )
|
|
||||||
{
|
|
||||||
Info("OurCheckAlarm is TRUE!!!!!!");
|
|
||||||
alarm = true;
|
|
||||||
score += zone->Score();
|
|
||||||
zone->SetAlarm();
|
|
||||||
Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() );
|
|
||||||
Info( "Zone is alarmed, zone score = %d", zone->Score() );
|
|
||||||
zoneSet.insert( zone->Label() );
|
|
||||||
// if ( config.opt_control && track_motion )
|
|
||||||
// {
|
|
||||||
// if ( (int)zone->Score() > top_score )
|
|
||||||
// {
|
|
||||||
// top_score = zone->Score();
|
|
||||||
// alarm_centre = zone->GetAlarmCentre();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
Info( "Finish checking active zone %s", zone->Label() );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// if ( top_score > 0 )
|
|
||||||
// {
|
|
||||||
// shared_data->alarm_x = alarm_centre.X();
|
|
||||||
// shared_data->alarm_y = alarm_centre.Y();
|
|
||||||
//
|
|
||||||
// Info( "Got alarm centre at %d,%d, at count %d", shared_data->alarm_x, shared_data->alarm_y, image_count );
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// shared_data->alarm_x = shared_data->alarm_y = -1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// This is a small and innocent hack to prevent scores of 0 being returned in alarm state
|
|
||||||
Info("Leaving DetectBlack <<<<<<<<<<<<<<<<<<<<<<<<<<<");
|
|
||||||
return( score?score:alarm );
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
//-----------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &zoneSet )
|
unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &zoneSet )
|
||||||
{
|
{
|
||||||
bool alarm = false;
|
bool alarm = false;
|
||||||
|
|
|
@ -48,9 +48,9 @@
|
||||||
//
|
//
|
||||||
class Monitor
|
class Monitor
|
||||||
{
|
{
|
||||||
friend class MonitorStream;
|
friend class MonitorStream;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
QUERY=0,
|
QUERY=0,
|
||||||
|
@ -87,7 +87,7 @@ public:
|
||||||
TAPE
|
TAPE
|
||||||
} State;
|
} State;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef std::set<Zone *> ZoneSet;
|
typedef std::set<Zone *> ZoneSet;
|
||||||
|
|
||||||
typedef enum { GET_SETTINGS=0x1, SET_SETTINGS=0x2, RELOAD=0x4, SUSPEND=0x10, RESUME=0x20 } Action;
|
typedef enum { GET_SETTINGS=0x1, SET_SETTINGS=0x2, RELOAD=0x4, SUSPEND=0x10, RESUME=0x20 } Action;
|
||||||
|
@ -218,7 +218,7 @@ protected:
|
||||||
bool hasAlarmed();
|
bool hasAlarmed();
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// These are read from the DB and thereafter remain unchanged
|
// These are read from the DB and thereafter remain unchanged
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
char name[64];
|
char name[64];
|
||||||
|
@ -325,9 +325,9 @@ protected:
|
||||||
int n_linked_monitors;
|
int n_linked_monitors;
|
||||||
MonitorLink **linked_monitors;
|
MonitorLink **linked_monitors;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// OurCheckAlarms seems to be unused. Check it on zm_monitor.cpp for more info.
|
// OurCheckAlarms seems to be unused. Check it on zm_monitor.cpp for more info.
|
||||||
//bool OurCheckAlarms( Zone *zone, const Image *pImage );
|
//bool OurCheckAlarms( Zone *zone, const Image *pImage );
|
||||||
Monitor(
|
Monitor(
|
||||||
int p_id,
|
int p_id,
|
||||||
const char *p_name,
|
const char *p_name,
|
||||||
|
@ -417,8 +417,8 @@ public:
|
||||||
return( embed_exif );
|
return( embed_exif );
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Width() const { return( width ); }
|
unsigned int Width() const { return width; }
|
||||||
unsigned int Height() const { return( height ); }
|
unsigned int Height() const { return height; }
|
||||||
unsigned int Colours() const { return( camera->Colours() ); }
|
unsigned int Colours() const { return( camera->Colours() ); }
|
||||||
unsigned int SubpixelOrder() const { return( camera->SubpixelOrder() ); }
|
unsigned int SubpixelOrder() const { return( camera->SubpixelOrder() ); }
|
||||||
|
|
||||||
|
@ -505,36 +505,36 @@ public:
|
||||||
#define MOD_ADD( var, delta, limit ) (((var)+(limit)+(delta))%(limit))
|
#define MOD_ADD( var, delta, limit ) (((var)+(limit)+(delta))%(limit))
|
||||||
|
|
||||||
class MonitorStream : public StreamBase {
|
class MonitorStream : public StreamBase {
|
||||||
protected:
|
protected:
|
||||||
typedef struct SwapImage {
|
typedef struct SwapImage {
|
||||||
bool valid;
|
bool valid;
|
||||||
struct timeval timestamp;
|
struct timeval timestamp;
|
||||||
char file_name[PATH_MAX];
|
char file_name[PATH_MAX];
|
||||||
} SwapImage;
|
} SwapImage;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SwapImage *temp_image_buffer;
|
SwapImage *temp_image_buffer;
|
||||||
int temp_image_buffer_count;
|
int temp_image_buffer_count;
|
||||||
int temp_read_index;
|
int temp_read_index;
|
||||||
int temp_write_index;
|
int temp_write_index;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
time_t ttl;
|
time_t ttl;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int playback_buffer;
|
int playback_buffer;
|
||||||
bool delayed;
|
bool delayed;
|
||||||
|
|
||||||
int frame_count;
|
int frame_count;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool checkSwapPath( const char *path, bool create_path );
|
bool checkSwapPath( const char *path, bool create_path );
|
||||||
|
|
||||||
bool sendFrame( const char *filepath, struct timeval *timestamp );
|
bool sendFrame( const char *filepath, struct timeval *timestamp );
|
||||||
bool sendFrame( Image *image, struct timeval *timestamp );
|
bool sendFrame( Image *image, struct timeval *timestamp );
|
||||||
void processCommand( const CmdMsg *msg );
|
void processCommand( const CmdMsg *msg );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MonitorStream() : playback_buffer( 0 ), delayed( false ), frame_count( 0 ) {
|
MonitorStream() : playback_buffer( 0 ), delayed( false ), frame_count( 0 ) {
|
||||||
}
|
}
|
||||||
void setStreamBuffer( int p_playback_buffer ) {
|
void setStreamBuffer( int p_playback_buffer ) {
|
||||||
|
|
|
@ -333,7 +333,13 @@ void VideoStream::OpenStream( )
|
||||||
Panic( "Could not allocate opicture" );
|
Panic( "Could not allocate opicture" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
|
int size = av_image_get_buffer_size( c->pix_fmt, c->width,
|
||||||
|
c->height, 1 );
|
||||||
|
#else
|
||||||
int size = avpicture_get_size( c->pix_fmt, c->width, c->height );
|
int size = avpicture_get_size( c->pix_fmt, c->width, c->height );
|
||||||
|
#endif
|
||||||
|
|
||||||
uint8_t *opicture_buf = (uint8_t *)av_malloc( size );
|
uint8_t *opicture_buf = (uint8_t *)av_malloc( size );
|
||||||
if ( !opicture_buf )
|
if ( !opicture_buf )
|
||||||
{
|
{
|
||||||
|
@ -344,7 +350,13 @@ void VideoStream::OpenStream( )
|
||||||
#endif
|
#endif
|
||||||
Panic( "Could not allocate opicture_buf" );
|
Panic( "Could not allocate opicture_buf" );
|
||||||
}
|
}
|
||||||
avpicture_fill( (AVPicture *)opicture, opicture_buf, c->pix_fmt, c->width, c->height );
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
|
av_image_fill_arrays(opicture->data, opicture->linesize,
|
||||||
|
opicture_buf, c->pix_fmt, c->width, c->height, 1);
|
||||||
|
#else
|
||||||
|
avpicture_fill( (AVPicture *)opicture, opicture_buf, c->pix_fmt,
|
||||||
|
c->width, c->height );
|
||||||
|
#endif
|
||||||
|
|
||||||
/* if the output format is not identical to the input format, then a temporary
|
/* if the output format is not identical to the input format, then a temporary
|
||||||
picture is needed too. It is then converted to the required
|
picture is needed too. It is then converted to the required
|
||||||
|
@ -361,7 +373,12 @@ void VideoStream::OpenStream( )
|
||||||
{
|
{
|
||||||
Panic( "Could not allocate tmp_opicture" );
|
Panic( "Could not allocate tmp_opicture" );
|
||||||
}
|
}
|
||||||
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
|
int size = av_image_get_buffer_size( pf, c->width,
|
||||||
|
c->height,1 );
|
||||||
|
#else
|
||||||
int size = avpicture_get_size( pf, c->width, c->height );
|
int size = avpicture_get_size( pf, c->width, c->height );
|
||||||
|
#endif
|
||||||
uint8_t *tmp_opicture_buf = (uint8_t *)av_malloc( size );
|
uint8_t *tmp_opicture_buf = (uint8_t *)av_malloc( size );
|
||||||
if ( !tmp_opicture_buf )
|
if ( !tmp_opicture_buf )
|
||||||
{
|
{
|
||||||
|
@ -372,7 +389,14 @@ void VideoStream::OpenStream( )
|
||||||
#endif
|
#endif
|
||||||
Panic( "Could not allocate tmp_opicture_buf" );
|
Panic( "Could not allocate tmp_opicture_buf" );
|
||||||
}
|
}
|
||||||
avpicture_fill( (AVPicture *)tmp_opicture, tmp_opicture_buf, pf, c->width, c->height );
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
|
av_image_fill_arrays(tmp_opicture->data,
|
||||||
|
tmp_opicture->linesize, tmp_opicture_buf, pf,
|
||||||
|
c->width, c->height, 1);
|
||||||
|
#else
|
||||||
|
avpicture_fill( (AVPicture *)tmp_opicture,
|
||||||
|
tmp_opicture_buf, pf, c->width, c->height );
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -678,14 +702,14 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size,
|
||||||
#endif
|
#endif
|
||||||
if ( got_packet )
|
if ( got_packet )
|
||||||
{
|
{
|
||||||
if ( c->coded_frame->key_frame )
|
// if ( c->coded_frame->key_frame )
|
||||||
{
|
// {
|
||||||
#if LIBAVCODEC_VERSION_CHECK(52, 30, 2, 30, 2)
|
//#if LIBAVCODEC_VERSION_CHECK(52, 30, 2, 30, 2)
|
||||||
pkt->flags |= AV_PKT_FLAG_KEY;
|
// pkt->flags |= AV_PKT_FLAG_KEY;
|
||||||
#else
|
//#else
|
||||||
pkt->flags |= PKT_FLAG_KEY;
|
// pkt->flags |= PKT_FLAG_KEY;
|
||||||
#endif
|
//#endif
|
||||||
}
|
// }
|
||||||
|
|
||||||
if ( pkt->pts != (int64_t)AV_NOPTS_VALUE )
|
if ( pkt->pts != (int64_t)AV_NOPTS_VALUE )
|
||||||
{
|
{
|
||||||
|
|
|
@ -241,7 +241,12 @@ int RemoteCameraRtsp::PrimeCapture()
|
||||||
if(mRawFrame == NULL || mFrame == NULL)
|
if(mRawFrame == NULL || mFrame == NULL)
|
||||||
Fatal( "Unable to allocate frame(s)");
|
Fatal( "Unable to allocate frame(s)");
|
||||||
|
|
||||||
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
|
int pSize = av_image_get_buffer_size( imagePixFormat, width, height, 1 );
|
||||||
|
#else
|
||||||
int pSize = avpicture_get_size( imagePixFormat, width, height );
|
int pSize = avpicture_get_size( imagePixFormat, width, height );
|
||||||
|
#endif
|
||||||
|
|
||||||
if( (unsigned int)pSize != imagesize) {
|
if( (unsigned int)pSize != imagesize) {
|
||||||
Fatal("Image size mismatch. Required: %d Available: %d",pSize,imagesize);
|
Fatal("Image size mismatch. Required: %d Available: %d",pSize,imagesize);
|
||||||
}
|
}
|
||||||
|
@ -299,24 +304,6 @@ int RemoteCameraRtsp::Capture( Image &image ) {
|
||||||
if ( !buffer.size() )
|
if ( !buffer.size() )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
int avResult = av_read_frame( mFormatContext, &packet );
|
|
||||||
if ( avResult < 0 ) {
|
|
||||||
char errbuf[AV_ERROR_MAX_STRING_SIZE];
|
|
||||||
av_strerror(avResult, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
|
||||||
if (
|
|
||||||
// Check if EOF.
|
|
||||||
(avResult == AVERROR_EOF || (mFormatContext->pb && mFormatContext->pb->eof_reached)) ||
|
|
||||||
// Check for Connection failure.
|
|
||||||
(avResult == -110)
|
|
||||||
) {
|
|
||||||
Info( "av_read_frame returned \"%s\". Reopening stream.", errbuf);
|
|
||||||
//ReopenFfmpeg();
|
|
||||||
}
|
|
||||||
|
|
||||||
Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, avResult, errbuf );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mCodecContext->codec_id == AV_CODEC_ID_H264) {
|
if(mCodecContext->codec_id == AV_CODEC_ID_H264) {
|
||||||
// SPS and PPS frames should be saved and appended to IDR frames
|
// SPS and PPS frames should be saved and appended to IDR frames
|
||||||
int nalType = (buffer.head()[3] & 0x1f);
|
int nalType = (buffer.head()[3] & 0x1f);
|
||||||
|
@ -339,6 +326,8 @@ int avResult = av_read_frame( mFormatContext, &packet );
|
||||||
buffer += lastSps;
|
buffer += lastSps;
|
||||||
buffer += lastPps;
|
buffer += lastPps;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Debug(3, "Not an h264 packet");
|
||||||
}
|
}
|
||||||
|
|
||||||
av_init_packet( &packet );
|
av_init_packet( &packet );
|
||||||
|
@ -498,7 +487,13 @@ int RemoteCameraRtsp::CaptureAndRecord( Image &image, bool recording, char* even
|
||||||
|
|
||||||
Debug( 3, "Got frame %d", frameCount );
|
Debug( 3, "Got frame %d", frameCount );
|
||||||
|
|
||||||
avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height );
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
|
av_image_fill_arrays(mFrame->data, mFrame->linesize,
|
||||||
|
directbuffer, imagePixFormat, width, height, 1);
|
||||||
|
#else
|
||||||
|
avpicture_fill( (AVPicture *)mFrame, directbuffer,
|
||||||
|
imagePixFormat, width, height);
|
||||||
|
#endif
|
||||||
|
|
||||||
//Video recording
|
//Video recording
|
||||||
if ( recording && !wasRecording ) {
|
if ( recording && !wasRecording ) {
|
||||||
|
|
|
@ -47,15 +47,12 @@ RETSIGTYPE zm_die_handler(int signal, siginfo_t * info, void *context)
|
||||||
RETSIGTYPE zm_die_handler(int signal)
|
RETSIGTYPE zm_die_handler(int signal)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#if (defined(__i386__) || defined(__x86_64__))
|
|
||||||
void *cr2 = 0;
|
|
||||||
void *ip = 0;
|
|
||||||
#endif
|
|
||||||
Error("Got signal %d (%s), crashing", signal, strsignal(signal));
|
Error("Got signal %d (%s), crashing", signal, strsignal(signal));
|
||||||
|
|
||||||
#if (defined(__i386__) || defined(__x86_64__))
|
#if (defined(__i386__) || defined(__x86_64__))
|
||||||
// Get more information if available
|
// Get more information if available
|
||||||
#if ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T )
|
#if ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T )
|
||||||
|
void *ip = 0;
|
||||||
|
void *cr2 = 0;
|
||||||
if (info && context) {
|
if (info && context) {
|
||||||
|
|
||||||
Debug(1,
|
Debug(1,
|
||||||
|
@ -65,19 +62,19 @@ RETSIGTYPE zm_die_handler(int signal)
|
||||||
|
|
||||||
ucontext_t *uc = (ucontext_t *) context;
|
ucontext_t *uc = (ucontext_t *) context;
|
||||||
cr2 = info->si_addr;
|
cr2 = info->si_addr;
|
||||||
#if defined(__x86_64__)
|
#if defined(__x86_64__)
|
||||||
#ifdef __FreeBSD_kernel__
|
#ifdef __FreeBSD_kernel__
|
||||||
ip = (void *)(uc->uc_mcontext.mc_rip);
|
ip = (void *)(uc->uc_mcontext.mc_rip);
|
||||||
#else
|
#else
|
||||||
ip = (void *)(uc->uc_mcontext.gregs[REG_RIP]);
|
ip = (void *)(uc->uc_mcontext.gregs[REG_RIP]);
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#ifdef __FreeBSD_kernel__
|
#ifdef __FreeBSD_kernel__
|
||||||
ip = (void *)(uc->uc_mcontext.mc_eip);
|
ip = (void *)(uc->uc_mcontext.mc_eip);
|
||||||
#else
|
#else
|
||||||
ip = (void *)(uc->uc_mcontext.gregs[REG_EIP]);
|
ip = (void *)(uc->uc_mcontext.gregs[REG_EIP]);
|
||||||
#endif
|
#endif
|
||||||
#endif // defined(__x86_64__)
|
#endif // defined(__x86_64__)
|
||||||
|
|
||||||
// Print the signal address and instruction pointer if available
|
// Print the signal address and instruction pointer if available
|
||||||
if (ip) {
|
if (ip) {
|
||||||
|
@ -86,11 +83,11 @@ RETSIGTYPE zm_die_handler(int signal)
|
||||||
Error("Signal address is %p, no instruction pointer", cr2);
|
Error("Signal address is %p, no instruction pointer", cr2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T )
|
#endif // ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T )
|
||||||
|
|
||||||
|
|
||||||
// Print backtrace if enabled and available
|
// Print backtrace if enabled and available
|
||||||
#if ( !defined(ZM_NO_CRASHTRACE) && HAVE_DECL_BACKTRACE && HAVE_DECL_BACKTRACE_SYMBOLS )
|
#if ( !defined(ZM_NO_CRASHTRACE) && HAVE_DECL_BACKTRACE && HAVE_DECL_BACKTRACE_SYMBOLS )
|
||||||
void *trace[TRACE_SIZE];
|
void *trace[TRACE_SIZE];
|
||||||
int trace_size = 0;
|
int trace_size = 0;
|
||||||
trace_size = backtrace(trace, TRACE_SIZE);
|
trace_size = backtrace(trace, TRACE_SIZE);
|
||||||
|
@ -111,7 +108,7 @@ RETSIGTYPE zm_die_handler(int signal)
|
||||||
|
|
||||||
Info("Backtrace complete, please execute the following command for more information");
|
Info("Backtrace complete, please execute the following command for more information");
|
||||||
Info(cmd);
|
Info(cmd);
|
||||||
#endif // ( !defined(ZM_NO_CRASHTRACE) && HAVE_DECL_BACKTRACE && HAVE_DECL_BACKTRACE_SYMBOLS )
|
#endif // ( !defined(ZM_NO_CRASHTRACE) && HAVE_DECL_BACKTRACE && HAVE_DECL_BACKTRACE_SYMBOLS )
|
||||||
#endif // (defined(__i386__) || defined(__x86_64__)
|
#endif // (defined(__i386__) || defined(__x86_64__)
|
||||||
exit(signal);
|
exit(signal);
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,8 +50,8 @@ Storage::Storage( unsigned int p_id ) {
|
||||||
char sql[ZM_SQL_SML_BUFSIZ];
|
char sql[ZM_SQL_SML_BUFSIZ];
|
||||||
snprintf( sql, sizeof(sql), "SELECT Id, Name, Path from Storage WHERE Id=%d", p_id );
|
snprintf( sql, sizeof(sql), "SELECT Id, Name, Path from Storage WHERE Id=%d", p_id );
|
||||||
Debug(1,"Loading Storage for %d using %s", p_id, sql );
|
Debug(1,"Loading Storage for %d using %s", p_id, sql );
|
||||||
MYSQL_ROW dbrow = zmDbFetchOne( sql );
|
zmDbRow dbrow;
|
||||||
if ( ! dbrow ) {
|
if ( ! dbrow.fetch( sql ) ) {
|
||||||
Error( "Unable to load storage area for id %d: %s", p_id, mysql_error( &dbconn ) );
|
Error( "Unable to load storage area for id %d: %s", p_id, mysql_error( &dbconn ) );
|
||||||
} else {
|
} else {
|
||||||
unsigned int index = 0;
|
unsigned int index = 0;
|
||||||
|
|
|
@ -253,7 +253,7 @@ void *Thread::mThreadFunc( void *arg )
|
||||||
Debug( 2, "Invoking thread" );
|
Debug( 2, "Invoking thread" );
|
||||||
|
|
||||||
Thread *thisPtr = (Thread *)arg;
|
Thread *thisPtr = (Thread *)arg;
|
||||||
void *status = 0;
|
thisPtr->status = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
thisPtr->mThreadMutex.lock();
|
thisPtr->mThreadMutex.lock();
|
||||||
|
@ -261,19 +261,18 @@ void *Thread::mThreadFunc( void *arg )
|
||||||
thisPtr->mThreadCondition.signal();
|
thisPtr->mThreadCondition.signal();
|
||||||
thisPtr->mThreadMutex.unlock();
|
thisPtr->mThreadMutex.unlock();
|
||||||
thisPtr->mRunning = true;
|
thisPtr->mRunning = true;
|
||||||
int run=(thisPtr->run());
|
thisPtr->status = thisPtr->run();
|
||||||
status = (void *)&run;
|
|
||||||
thisPtr->mRunning = false;
|
thisPtr->mRunning = false;
|
||||||
Debug( 2, "Exiting thread, status %p", status );
|
Debug( 2, "Exiting thread, status %p", (void *)&(thisPtr->status) );
|
||||||
|
return (void *)&(thisPtr->status);
|
||||||
}
|
}
|
||||||
catch ( const ThreadException &e )
|
catch ( const ThreadException &e )
|
||||||
{
|
{
|
||||||
Error( "%s", e.getMessage().c_str() );
|
Error( "%s", e.getMessage().c_str() );
|
||||||
thisPtr->mRunning = false;
|
thisPtr->mRunning = false;
|
||||||
status = (void *)-1;
|
Debug( 2, "Exiting thread after exception, status %p", (void *)-1 );
|
||||||
Debug( 2, "Exiting thread after exception, status %p", status );
|
return (void *)-1;
|
||||||
}
|
}
|
||||||
return( status );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::start()
|
void Thread::start()
|
||||||
|
|
|
@ -36,7 +36,7 @@ class ThreadException : public Exception
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
#ifndef SOLARIS
|
#ifndef SOLARIS
|
||||||
pid_t pid() {
|
pid_t pid() {
|
||||||
pid_t tid;
|
pid_t tid;
|
||||||
#ifdef __FreeBSD__
|
#ifdef __FreeBSD__
|
||||||
long lwpid;
|
long lwpid;
|
||||||
|
@ -50,9 +50,9 @@ pid_t pid() {
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
return tid;
|
return tid;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
pthread_t pid() { return( pthread_self() ); }
|
pthread_t pid() { return( pthread_self() ); }
|
||||||
#endif
|
#endif
|
||||||
public:
|
public:
|
||||||
ThreadException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)pid() ) ) {
|
ThreadException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)pid() ) ) {
|
||||||
|
@ -224,6 +224,7 @@ protected:
|
||||||
#endif
|
#endif
|
||||||
bool mStarted;
|
bool mStarted;
|
||||||
bool mRunning;
|
bool mRunning;
|
||||||
|
int status; // Used in various funcions to get around return a local variable
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Thread();
|
Thread();
|
||||||
|
@ -253,10 +254,10 @@ return tid;
|
||||||
return( pthread_self() );
|
return( pthread_self() );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
void exit( int status = 0 )
|
void exit( int p_status = 0 )
|
||||||
{
|
{
|
||||||
//INFO( "Exiting" );
|
//INFO( "Exiting" );
|
||||||
pthread_exit( (void *)&status );
|
pthread_exit( (void *)&p_status );
|
||||||
}
|
}
|
||||||
static void *mThreadFunc( void *arg );
|
static void *mThreadFunc( void *arg );
|
||||||
|
|
||||||
|
|
|
@ -29,11 +29,12 @@
|
||||||
#include "zm_videostore.h"
|
#include "zm_videostore.h"
|
||||||
|
|
||||||
extern "C"{
|
extern "C"{
|
||||||
#include "libavutil/time.h"
|
#include "libavutil/time.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
||||||
AVStream *input_st, AVStream *inpaud_st,
|
AVStream *input_st,
|
||||||
|
AVStream *inpaud_st,
|
||||||
int64_t nStartTime) {
|
int64_t nStartTime) {
|
||||||
|
|
||||||
AVDictionary *pmetadata = NULL;
|
AVDictionary *pmetadata = NULL;
|
||||||
|
@ -46,14 +47,20 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
||||||
keyframeMessage = false;
|
keyframeMessage = false;
|
||||||
keyframeSkipNumber = 0;
|
keyframeSkipNumber = 0;
|
||||||
|
|
||||||
|
Info("Opening video storage stream %s format: %d\n", filename, format);
|
||||||
Info("Opening video storage stream %s\n", filename);
|
|
||||||
|
|
||||||
//Init everything we need
|
//Init everything we need
|
||||||
int ret;
|
int ret;
|
||||||
av_register_all();
|
av_register_all();
|
||||||
|
|
||||||
avformat_alloc_output_context2(&oc, NULL, NULL, filename);
|
ret = avformat_alloc_output_context2(&oc, NULL, NULL, filename);
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
Warning("Could not create video storage stream %s as no output context"
|
||||||
|
" could be assigned based on filename: %s",
|
||||||
|
filename,
|
||||||
|
av_make_error_string(ret).c_str()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
//Couldn't deduce format from filename, trying from format name
|
//Couldn't deduce format from filename, trying from format name
|
||||||
if (!oc) {
|
if (!oc) {
|
||||||
|
@ -72,15 +79,15 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
||||||
|
|
||||||
fmt = oc->oformat;
|
fmt = oc->oformat;
|
||||||
|
|
||||||
video_st = avformat_new_stream(oc, input_st->codec->codec);
|
video_st = avformat_new_stream(oc, (AVCodec *)input_st->codec->codec);
|
||||||
if (!video_st) {
|
if (!video_st) {
|
||||||
Fatal("Unable to create video out stream\n");
|
Fatal("Unable to create video out stream\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = avcodec_copy_context(video_st->codec, input_st->codec);
|
ret = avcodec_copy_context(video_st->codec, input_st->codec);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
Fatal("Unable to copy input video context to output video context "
|
Fatal("Unable to copy input video context to output video context %s\n",
|
||||||
"%s\n", av_make_error_string(ret).c_str());
|
av_make_error_string(ret).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
video_st->codec->codec_tag = 0;
|
video_st->codec->codec_tag = 0;
|
||||||
|
@ -89,19 +96,27 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inpaud_st) {
|
if (inpaud_st) {
|
||||||
audio_st = avformat_new_stream(oc, inpaud_st->codec->codec);
|
|
||||||
|
audio_st = avformat_new_stream(oc, (AVCodec *)inpaud_st->codec->codec);
|
||||||
if (!audio_st) {
|
if (!audio_st) {
|
||||||
Fatal("Unable to create audio out stream\n");
|
Error("Unable to create audio out stream\n");
|
||||||
}
|
audio_st = NULL;
|
||||||
ret=avcodec_copy_context(audio_st->codec, inpaud_st->codec);
|
} else {
|
||||||
|
ret = avcodec_copy_context(audio_st->codec, inpaud_st->codec);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
Fatal("Unable to copy audio context %s\n", av_make_error_string(ret).c_str());
|
Fatal("Unable to copy audio context %s\n", av_make_error_string(ret).c_str());
|
||||||
}
|
}
|
||||||
audio_st->codec->codec_tag = 0;
|
audio_st->codec->codec_tag = 0;
|
||||||
|
if ( audio_st->codec->channels > 1 ) {
|
||||||
|
Warning("Audio isn't mono, changing it.");
|
||||||
|
audio_st->codec->channels = 1;
|
||||||
|
}
|
||||||
if (oc->oformat->flags & AVFMT_GLOBALHEADER) {
|
if (oc->oformat->flags & AVFMT_GLOBALHEADER) {
|
||||||
audio_st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
audio_st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
Debug(3, "No Audio output stream");
|
||||||
audio_st = NULL;
|
audio_st = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,11 +129,19 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
|
||||||
|
//if ((ret = avformat_write_header(ctx, &opts)) < 0) {
|
||||||
|
//}
|
||||||
|
//os->ctx_inited = 1;
|
||||||
|
//avio_flush(ctx->pb);
|
||||||
|
//av_dict_free(&opts);
|
||||||
|
|
||||||
/* Write the stream header, if any. */
|
/* Write the stream header, if any. */
|
||||||
ret = avformat_write_header(oc, NULL);
|
ret = avformat_write_header(oc, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
Fatal("Error occurred when writing output file header: %s\n",
|
zm_dump_stream_format( oc, 0, 0, 1 );
|
||||||
|
Fatal("Error occurred when writing output file header to %s: %s\n",
|
||||||
|
filename,
|
||||||
av_make_error_string(ret).c_str());
|
av_make_error_string(ret).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +152,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
||||||
|
|
||||||
startTime=av_gettime()-nStartTime;//oc->start_time;
|
startTime=av_gettime()-nStartTime;//oc->start_time;
|
||||||
Info("VideoStore startTime=%d\n",startTime);
|
Info("VideoStore startTime=%d\n",startTime);
|
||||||
}
|
} // VideoStore::VideoStore
|
||||||
|
|
||||||
|
|
||||||
VideoStore::~VideoStore(){
|
VideoStore::~VideoStore(){
|
||||||
|
@ -140,16 +163,24 @@ VideoStore::~VideoStore(){
|
||||||
Debug(3, "Sucess Writing trailer");
|
Debug(3, "Sucess Writing trailer");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// I wonder if we should be closing the file first.
|
||||||
|
// I also wonder if we really need to be doing all the context allocation/de-allocation constantly, or whether we can just re-use it. Just do a file open/close/writeheader/etc.
|
||||||
|
// What if we were only doing audio recording?
|
||||||
|
if ( video_st ) {
|
||||||
avcodec_close(video_st->codec);
|
avcodec_close(video_st->codec);
|
||||||
|
}
|
||||||
if (audio_st) {
|
if (audio_st) {
|
||||||
avcodec_close(audio_st->codec);
|
avcodec_close(audio_st->codec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WHen will be not using a file ?
|
||||||
if (!(fmt->flags & AVFMT_NOFILE)) {
|
if (!(fmt->flags & AVFMT_NOFILE)) {
|
||||||
/* Close the output file. */
|
/* Close the output file. */
|
||||||
if ( int rc= avio_close(oc->pb) ) {
|
if ( int rc = avio_close(oc->pb) ) {
|
||||||
Error("Error closing avio %s", av_err2str( rc ) );
|
Error("Error closing avio %s", av_err2str( rc ) );
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Debug(3, "Not closing avio because we are not writing to a file.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* free the stream */
|
/* free the stream */
|
||||||
|
@ -247,34 +278,47 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt, AVStream *input_st){//, AV
|
||||||
|
|
||||||
int VideoStore::writeAudioFramePacket(AVPacket *ipkt, AVStream *input_st){
|
int VideoStore::writeAudioFramePacket(AVPacket *ipkt, AVStream *input_st){
|
||||||
|
|
||||||
if(!audio_st)
|
if(!audio_st) {
|
||||||
|
Error("Called writeAudioFramePacket when no audio_st");
|
||||||
return -1;//FIXME -ve return codes do not free packet in ffmpeg_camera at the moment
|
return -1;//FIXME -ve return codes do not free packet in ffmpeg_camera at the moment
|
||||||
|
}
|
||||||
/*if(!keyframeMessage)
|
/*if(!keyframeMessage)
|
||||||
return -1;*/
|
return -1;*/
|
||||||
|
//zm_dump_stream_format( oc, ipkt->stream_index, 0, 1 );
|
||||||
|
|
||||||
int64_t ost_tb_start_time = av_rescale_q(startTime, AV_TIME_BASE_Q, video_st->time_base);
|
// What is this doing? Getting the time of the start of this video chunk? Does that actually make sense?
|
||||||
|
int64_t ost_tb_start_time = av_rescale_q(startTime, AV_TIME_BASE_Q, audio_st->time_base);
|
||||||
|
|
||||||
AVPacket opkt;
|
AVPacket opkt;
|
||||||
|
|
||||||
av_init_packet(&opkt);
|
av_init_packet(&opkt);
|
||||||
|
Debug(3, "after init packet" );
|
||||||
|
|
||||||
|
|
||||||
//Scale the PTS of the outgoing packet to be the correct time base
|
//Scale the PTS of the outgoing packet to be the correct time base
|
||||||
if (ipkt->pts != AV_NOPTS_VALUE)
|
if (ipkt->pts != AV_NOPTS_VALUE) {
|
||||||
|
Debug(3, "Rescaling output pts");
|
||||||
opkt.pts = av_rescale_q(ipkt->pts-startPts, input_st->time_base, audio_st->time_base) - ost_tb_start_time;
|
opkt.pts = av_rescale_q(ipkt->pts-startPts, input_st->time_base, audio_st->time_base) - ost_tb_start_time;
|
||||||
else
|
} else {
|
||||||
|
Debug(3, "Setting output pts to AV_NOPTS_VALUE");
|
||||||
opkt.pts = AV_NOPTS_VALUE;
|
opkt.pts = AV_NOPTS_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
//Scale the DTS of the outgoing packet to be the correct time base
|
//Scale the DTS of the outgoing packet to be the correct time base
|
||||||
if(ipkt->dts == AV_NOPTS_VALUE) {
|
if(ipkt->dts == AV_NOPTS_VALUE) {
|
||||||
|
Debug(4, "ipkt->dts == AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
|
||||||
opkt.dts = av_rescale_q(input_st->cur_dts-startDts, AV_TIME_BASE_Q, audio_st->time_base);
|
opkt.dts = av_rescale_q(input_st->cur_dts-startDts, AV_TIME_BASE_Q, audio_st->time_base);
|
||||||
Debug(3, "ipkt->dts == AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
|
Debug(4, "ipkt->dts == AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
|
||||||
} else
|
} else {
|
||||||
|
Debug(4, "ipkt->dts != AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
|
||||||
opkt.dts = av_rescale_q(ipkt->dts-startDts, input_st->time_base, audio_st->time_base);
|
opkt.dts = av_rescale_q(ipkt->dts-startDts, input_st->time_base, audio_st->time_base);
|
||||||
|
Debug(4, "ipkt->dts != AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
|
||||||
|
}
|
||||||
opkt.dts -= ost_tb_start_time;
|
opkt.dts -= ost_tb_start_time;
|
||||||
|
|
||||||
|
// Seems like it would be really weird for the codec type to NOT be audiu
|
||||||
if (audio_st->codec->codec_type == AVMEDIA_TYPE_AUDIO && ipkt->dts != AV_NOPTS_VALUE) {
|
if (audio_st->codec->codec_type == AVMEDIA_TYPE_AUDIO && ipkt->dts != AV_NOPTS_VALUE) {
|
||||||
Debug( 3, "code is audio, dts != AV_NOPTS_VALUE " );
|
Debug( 4, "code is audio, dts != AV_NOPTS_VALUE " );
|
||||||
int duration = av_get_audio_frame_duration(input_st->codec, ipkt->size);
|
int duration = av_get_audio_frame_duration(input_st->codec, ipkt->size);
|
||||||
if(!duration)
|
if(!duration)
|
||||||
duration = input_st->codec->frame_size;
|
duration = input_st->codec->frame_size;
|
||||||
|
@ -299,7 +343,7 @@ Debug(3, "ipkt->dts == AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
|
||||||
if(ret!=0){
|
if(ret!=0){
|
||||||
Fatal("Error encoding audio frame packet: %s\n", av_make_error_string(ret).c_str());
|
Fatal("Error encoding audio frame packet: %s\n", av_make_error_string(ret).c_str());
|
||||||
}
|
}
|
||||||
|
Debug(4,"Success writing audio frame" );
|
||||||
av_free_packet(&opkt);
|
av_free_packet(&opkt);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ int main( int argc, const char *argv[] )
|
||||||
int monitor_id = 0;
|
int monitor_id = 0;
|
||||||
time_t event_time = 0;
|
time_t event_time = 0;
|
||||||
int event_id = 0;
|
int event_id = 0;
|
||||||
int frame_id = 1;
|
unsigned int frame_id = 1;
|
||||||
unsigned int scale = 100;
|
unsigned int scale = 100;
|
||||||
unsigned int rate = 100;
|
unsigned int rate = 100;
|
||||||
double maxfps = 10.0;
|
double maxfps = 10.0;
|
||||||
|
|
|
@ -0,0 +1,252 @@
|
||||||
|
//
|
||||||
|
// ZoneMinder Streamer, $Date: 2010-10-14 23:21:00 +0200 (Thu, 14 Oct 2010) $
|
||||||
|
// Copyright (C) 2001-2010 Philip Coombes, Chris Kistner
|
||||||
|
//
|
||||||
|
// This program is based on revision 3143 of
|
||||||
|
// http://svn.zoneminder.com/svn/zm/trunk/src/zms.cpp
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
zmstreamer - eyeZM video streamer
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
zmstreamer -e <mode>
|
||||||
|
zmstreamer -o <format>
|
||||||
|
zmstreamer -u <buffer size>
|
||||||
|
zmstreamer -f <maximum fps>
|
||||||
|
zmstreamer -s <scale>
|
||||||
|
zmstreamer -b <bitrate in bps>
|
||||||
|
zmstreamer -m <monitor id>
|
||||||
|
zmstreamer -d <debug mode>
|
||||||
|
zmstreamer -i
|
||||||
|
zmstreamer -?
|
||||||
|
zmstreamer -h
|
||||||
|
zmstreamer -v
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
*DEPRECIATED* The xml skin and all files associated with the xml skin are now
|
||||||
|
depreciated. Please use the ZoneMinder API instead.
|
||||||
|
|
||||||
|
This binary works in conjunction with the XML skin to stream video to iPhones
|
||||||
|
running the eyeZm app.
|
||||||
|
|
||||||
|
=head1 OPTIONS
|
||||||
|
|
||||||
|
-e <mode> - Specify output mode: mpeg/jpg/zip/single/raw.
|
||||||
|
-o <format> - Specify output format.
|
||||||
|
-u <buffer size> - Specify buffer size in ms.
|
||||||
|
-f <maximum fps> - Specify maximum framerate.
|
||||||
|
-s <scale> - Specify scale.
|
||||||
|
-b <bitrate in bps> - Specify bitrate.
|
||||||
|
-m <monitor id> - Specify monitor id.
|
||||||
|
-d <debug mode> - 0 = off, 1 = no streaming, 2 = with streaming.
|
||||||
|
-i, -?, -h - Display usage information
|
||||||
|
-v - Print the installed version of ZoneMinder
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <sys/ipc.h>
|
||||||
|
#include <sys/msg.h>
|
||||||
|
|
||||||
|
#include "zm.h"
|
||||||
|
#include "zm_db.h"
|
||||||
|
#include "zm_user.h"
|
||||||
|
#include "zm_signal.h"
|
||||||
|
#include "zm_monitor.h"
|
||||||
|
#include "zm_stream.h"
|
||||||
|
|
||||||
|
// Possible command-line options
|
||||||
|
#define OPTIONS "e:o:u:f:s:b:m:d:i:?:h:v"
|
||||||
|
|
||||||
|
// Default ZMS values
|
||||||
|
#define ZMS_DEFAULT_DEBUG 0
|
||||||
|
#define ZMS_DEFAULT_ID 1
|
||||||
|
#define ZMS_DEFAULT_BITRATE 100000
|
||||||
|
#define ZMS_DEFAULT_SCALE 100
|
||||||
|
#define ZMS_DEFAULT_MODE "mpeg"
|
||||||
|
#define ZMS_DEFAULT_FORMAT "asf"
|
||||||
|
#define ZMS_DEFAULT_FPS 25.0
|
||||||
|
#define ZMS_DEFAULT_BUFFER 1000
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
self = argv[0];
|
||||||
|
// Set initial values to the default values
|
||||||
|
int debug = ZMS_DEFAULT_DEBUG;
|
||||||
|
int id = ZMS_DEFAULT_ID;
|
||||||
|
int bitrate = ZMS_DEFAULT_BITRATE;
|
||||||
|
int scale = ZMS_DEFAULT_SCALE;
|
||||||
|
char mode[32];
|
||||||
|
sprintf(mode, "%s", ZMS_DEFAULT_MODE);
|
||||||
|
char format[32];
|
||||||
|
sprintf(format, "%s", ZMS_DEFAULT_FORMAT);
|
||||||
|
double maxfps = ZMS_DEFAULT_FPS;
|
||||||
|
int buffer = ZMS_DEFAULT_BUFFER;
|
||||||
|
|
||||||
|
// Parse command-line options
|
||||||
|
int arg;
|
||||||
|
while ((arg = getopt(argc, argv, OPTIONS)) != -1) {
|
||||||
|
switch (arg) {
|
||||||
|
case 'e':
|
||||||
|
sprintf(mode, "%s", optarg);
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
sprintf(format, "%s", optarg);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
buffer = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
maxfps = atof(optarg);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
scale = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
bitrate = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
id = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
debug = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
case 'i':
|
||||||
|
case '?':
|
||||||
|
printf("-e <mode> : Specify output mode: mpeg/jpg/zip/single/raw. Default = %s\n", ZMS_DEFAULT_MODE);
|
||||||
|
printf("-o <format> : Specify output format. Default = %s\n", ZMS_DEFAULT_FORMAT);
|
||||||
|
printf("-u <buffer size> : Specify buffer size in ms. Default = %d\n", ZMS_DEFAULT_BUFFER);
|
||||||
|
printf("-f <maximum fps> : Specify maximum framerate. Default = %lf\n", ZMS_DEFAULT_FPS);
|
||||||
|
printf("-s <scale> : Specify scale. Default = %d\n", ZMS_DEFAULT_SCALE);
|
||||||
|
printf("-b <bitrate in bps> : Specify bitrate. Default = %d\n", ZMS_DEFAULT_BITRATE);
|
||||||
|
printf("-m <monitor id> : Specify monitor id. Default = %d\n", ZMS_DEFAULT_ID);
|
||||||
|
printf("-d <debug mode> : 0 = off, 1 = no streaming, 2 = with streaming. Default = 0\n");
|
||||||
|
printf("-i or -? or -h: This information\n");
|
||||||
|
printf("-v : This installed version of ZoneMinder\n");
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
case 'v':
|
||||||
|
std::cout << ZM_VERSION << "\n";
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set stream type
|
||||||
|
StreamBase::StreamType streamtype;
|
||||||
|
if (!strcasecmp("raw", mode))
|
||||||
|
streamtype = MonitorStream::STREAM_RAW;
|
||||||
|
else if (!strcasecmp("mpeg", mode))
|
||||||
|
streamtype = MonitorStream::STREAM_MPEG;
|
||||||
|
else if (!strcasecmp("jpg", mode))
|
||||||
|
streamtype = MonitorStream::STREAM_JPEG;
|
||||||
|
else if (!strcasecmp("single", mode))
|
||||||
|
streamtype = MonitorStream::STREAM_SINGLE;
|
||||||
|
else if (!strcasecmp("zip", mode))
|
||||||
|
streamtype = MonitorStream::STREAM_ZIP;
|
||||||
|
else
|
||||||
|
streamtype = MonitorStream::STREAM_MPEG;
|
||||||
|
|
||||||
|
if (debug) {
|
||||||
|
// Show stream parameters
|
||||||
|
printf("Stream parameters:\n");
|
||||||
|
switch (streamtype) {
|
||||||
|
case MonitorStream::STREAM_MPEG:
|
||||||
|
printf("Output mode (-e) = %s\n", "mpeg");
|
||||||
|
printf("Output format (-o) = %s\n", format);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Output mode (-e) = %s\n", mode);
|
||||||
|
}
|
||||||
|
printf("Buffer size (-u) = %d ms\n", buffer);
|
||||||
|
printf("Maximum FPS (-f) = %lf FPS\n", maxfps);
|
||||||
|
printf("Scale (-s) = %d%%\n", scale);
|
||||||
|
printf("Bitrate (-b) = %d bps\n", bitrate);
|
||||||
|
printf("Monitor Id (-m) = %d\n", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug) {
|
||||||
|
// Set ZM debugger to print to stdout
|
||||||
|
printf("Setting up ZoneMinder debugger to print to stdout...");
|
||||||
|
setenv("ZM_DBG_PRINT", "1", 1);
|
||||||
|
printf("Done.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loading ZM configurations
|
||||||
|
printf("Loading ZoneMinder configurations...");
|
||||||
|
zmLoadConfig();
|
||||||
|
printf("Done.\n");
|
||||||
|
|
||||||
|
logInit("zmstreamer");
|
||||||
|
|
||||||
|
ssedetect();
|
||||||
|
|
||||||
|
// Setting stream parameters
|
||||||
|
MonitorStream stream;
|
||||||
|
stream.setStreamScale(scale); // default = 100 (scale)
|
||||||
|
stream.setStreamReplayRate(100); // default = 100 (rate)
|
||||||
|
stream.setStreamMaxFPS(maxfps); // default = 10 (maxfps)
|
||||||
|
if (debug) stream.setStreamTTL(1);
|
||||||
|
else stream.setStreamTTL(0); // default = 0 (ttl)
|
||||||
|
stream.setStreamQueue(0); // default = 0 (connkey)
|
||||||
|
stream.setStreamBuffer(buffer); // default = 0 (buffer)
|
||||||
|
stream.setStreamStart(id); // default = 0 (monitor_id)
|
||||||
|
stream.setStreamType(streamtype);
|
||||||
|
if (streamtype == MonitorStream::STREAM_MPEG) {
|
||||||
|
#if HAVE_LIBAVCODEC
|
||||||
|
if (debug) printf("HAVE_LIBAVCODEC is set\n");
|
||||||
|
stream.setStreamFormat(format); // default = "" (format)
|
||||||
|
stream.setStreamBitrate(bitrate); // default = 100000 (bitrate)
|
||||||
|
#else
|
||||||
|
fprintf(stderr, "MPEG streaming is disabled.\nYou should configure with the --with-ffmpeg option and rebuild to use this functionality.\n");
|
||||||
|
logTerm();
|
||||||
|
zmDbClose();
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug != 1) {
|
||||||
|
if (debug) printf("Running stream...");
|
||||||
|
|
||||||
|
// Output headers
|
||||||
|
fprintf(stdout, "Server: ZoneMinder Video Server/%s\r\n", ZM_VERSION);
|
||||||
|
time_t now = time(0);
|
||||||
|
char date_string[64];
|
||||||
|
strftime(date_string, sizeof (date_string) - 1, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now));
|
||||||
|
fprintf(stdout, "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n");
|
||||||
|
fprintf(stdout, "Last-Modified: %s\r\n", date_string);
|
||||||
|
fprintf(stdout, "Cache-Control: no-store, no-cache, must-revalidate\r\n");
|
||||||
|
fprintf(stdout, "Cache-Control: post-check=0, pre-check=0\r\n");
|
||||||
|
fprintf(stdout, "Pragma: no-cache\r\n");
|
||||||
|
|
||||||
|
// Run stream
|
||||||
|
stream.runStream();
|
||||||
|
}
|
||||||
|
if (debug) printf("Done.\n");
|
||||||
|
|
||||||
|
logTerm();
|
||||||
|
zmDbClose();
|
||||||
|
|
||||||
|
return (EXIT_SUCCESS);
|
||||||
|
}
|
|
@ -756,15 +756,14 @@ int main( int argc, char *argv[] )
|
||||||
|
|
||||||
if ( function & ZMU_LIST )
|
if ( function & ZMU_LIST )
|
||||||
{
|
{
|
||||||
char sql[ZM_SQL_SML_BUFSIZ];
|
std::string sql = "select Id, Function+0 from Monitors";
|
||||||
strncpy( sql, "select Id, Function+0 from Monitors", sizeof(sql) );
|
|
||||||
if ( !verbose )
|
if ( !verbose )
|
||||||
{
|
{
|
||||||
strncat( sql, " where Function != 'None'", sizeof(sql)-strlen(sql) );
|
sql += "where Function != 'None'";
|
||||||
}
|
}
|
||||||
strncat( sql, " order by Id asc", sizeof(sql)-strlen(sql) );
|
sql += " order by Id asc";
|
||||||
|
|
||||||
if ( mysql_query( &dbconn, sql ) )
|
if ( mysql_query( &dbconn, sql.c_str() ) )
|
||||||
{
|
{
|
||||||
Error( "Can't run query: %s", mysql_error( &dbconn ) );
|
Error( "Can't run query: %s", mysql_error( &dbconn ) );
|
||||||
exit( mysql_errno( &dbconn ) );
|
exit( mysql_errno( &dbconn ) );
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?php
|
||||||
|
require_once( 'database.php' );
|
||||||
|
require_once( 'Event.php' );
|
||||||
|
|
||||||
|
class Frame {
|
||||||
|
public function __construct( $IdOrRow ) {
|
||||||
|
$row = NULL;
|
||||||
|
if ( $IdOrRow ) {
|
||||||
|
if ( is_integer( $IdOrRow ) or is_numeric( $IdOrRow ) ) {
|
||||||
|
$row = dbFetchOne( 'SELECT * FROM Frames WHERE Id=?', NULL, array( $IdOrRow ) );
|
||||||
|
if ( ! $row ) {
|
||||||
|
Error("Unable to load Frame record for Id=" . $IdOrRow );
|
||||||
|
}
|
||||||
|
} elseif ( is_array( $IdOrRow ) ) {
|
||||||
|
$row = $IdOrRow;
|
||||||
|
} else {
|
||||||
|
Error("Unknown argument passed to Frame Constructor ($IdOrRow)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} # end if isset($IdOrRow)
|
||||||
|
|
||||||
|
if ( $row ) {
|
||||||
|
foreach ($row as $k => $v) {
|
||||||
|
$this->{$k} = $v;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Error("No row for Frame " . $IdOrRow );
|
||||||
|
}
|
||||||
|
} // end function __construct
|
||||||
|
public function Storage() {
|
||||||
|
return $this->Event()->Storage();
|
||||||
|
}
|
||||||
|
public function Event() {
|
||||||
|
return new Event( $this->{'EventId'} );
|
||||||
|
}
|
||||||
|
public function __call( $fn, array $args){
|
||||||
|
if(isset($this->{$fn})){
|
||||||
|
return $this->{$fn};
|
||||||
|
#array_unshift($args, $this);
|
||||||
|
#call_user_func_array( $this->{$fn}, $args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function Path() {
|
||||||
|
$Storage = $this->Storage();
|
||||||
|
return $Storage->Path().'/'.$this->Relative_Path();
|
||||||
|
}
|
||||||
|
public function Relative_Path() {
|
||||||
|
$event_path = "";
|
||||||
|
|
||||||
|
if ( ZM_USE_DEEP_STORAGE )
|
||||||
|
{
|
||||||
|
$event_path =
|
||||||
|
$this->{'MonitorId'}
|
||||||
|
.'/'.strftime( "%y/%m/%d/%H/%M/%S",
|
||||||
|
$this->Time()
|
||||||
|
)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$event_path =
|
||||||
|
$this->{'MonitorId'}
|
||||||
|
.'/'.$this->{'Id'}
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
return( $event_path );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getImageSrc( ) {
|
||||||
|
return ZM_BASE_URL.'/index.php?view=image&fid='.$this->{'Id'};
|
||||||
|
} // end function getImageSrc
|
||||||
|
} # end class
|
||||||
|
?>
|
|
@ -527,6 +527,7 @@ if ( !empty($action) )
|
||||||
'DoNativeMotDet' => 'toggle',
|
'DoNativeMotDet' => 'toggle',
|
||||||
'Exif' => 'toggle',
|
'Exif' => 'toggle',
|
||||||
'RTSPDescribe' => 'toggle',
|
'RTSPDescribe' => 'toggle',
|
||||||
|
'RecordAudio' => 'toggle',
|
||||||
);
|
);
|
||||||
|
|
||||||
$columns = getTableColumns( 'Monitors' );
|
$columns = getTableColumns( 'Monitors' );
|
||||||
|
|
|
@ -104,6 +104,7 @@ define( "CMD_PREV", 12 );
|
||||||
define( "CMD_NEXT", 13 );
|
define( "CMD_NEXT", 13 );
|
||||||
define( "CMD_SEEK", 14 );
|
define( "CMD_SEEK", 14 );
|
||||||
define( "CMD_VARPLAY", 15 );
|
define( "CMD_VARPLAY", 15 );
|
||||||
|
define( "CMD_QUIT", 17 );
|
||||||
define( "CMD_QUERY", 99 );
|
define( "CMD_QUERY", 99 );
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -217,14 +217,20 @@ function getMimeType( $file )
|
||||||
return( trim( exec( 'file -bi '.escapeshellarg( $file ).' 2>/dev/null' ) ) );
|
return( trim( exec( 'file -bi '.escapeshellarg( $file ).' 2>/dev/null' ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
function outputVideoStream( $id, $src, $width, $height, $format, $title="" )
|
function outputVideoStream( $id, $src, $width, $height, $format, $title="" ) {
|
||||||
{
|
echo getVideoStreamHTML( $id, $src, $width, $height, $format, $title );
|
||||||
if ( file_exists( $src ) )
|
}
|
||||||
|
|
||||||
|
function getVideoStreamHTML( $id, $src, $width, $height, $format, $title="" ) {
|
||||||
|
$html = '';
|
||||||
|
$width = validInt($width);
|
||||||
|
$height = validInt($height);
|
||||||
|
$title = validHtmlStr($title);
|
||||||
|
|
||||||
|
if ( file_exists( $src ) ) {
|
||||||
$mimeType = getMimeType( $src );
|
$mimeType = getMimeType( $src );
|
||||||
else
|
} else {
|
||||||
{
|
switch( $format ) {
|
||||||
switch( $format )
|
|
||||||
{
|
|
||||||
case 'asf' :
|
case 'asf' :
|
||||||
$mimeType = "video/x-ms-asf";
|
$mimeType = "video/x-ms-asf";
|
||||||
break;
|
break;
|
||||||
|
@ -252,118 +258,95 @@ function outputVideoStream( $id, $src, $width, $height, $format, $title="" )
|
||||||
}
|
}
|
||||||
if ( !$mimeType || ($mimeType == 'application/octet-stream') )
|
if ( !$mimeType || ($mimeType == 'application/octet-stream') )
|
||||||
$mimeType = 'video/'.$format;
|
$mimeType = 'video/'.$format;
|
||||||
$objectTag = false;
|
if ( ZM_WEB_USE_OBJECT_TAGS ) {
|
||||||
if ( ZM_WEB_USE_OBJECT_TAGS )
|
switch( $mimeType ) {
|
||||||
{
|
|
||||||
switch( $mimeType )
|
|
||||||
{
|
|
||||||
case "video/x-ms-asf" :
|
case "video/x-ms-asf" :
|
||||||
case "video/x-msvideo" :
|
case "video/x-msvideo" :
|
||||||
case "video/mp4" :
|
case "video/mp4" :
|
||||||
{
|
{
|
||||||
if ( isWindows() )
|
if ( isWindows() ) {
|
||||||
{
|
return '<object id="'.$id.'" width="'.$width.'" height="'.$height.'
|
||||||
?>
|
|
||||||
<object id="<?php echo $id ?>" width="<?php echo validNum($width) ?>" height="<?php echo validNum($height) ?>"
|
|
||||||
classid="CLSID:22D6F312-B0F6-11D0-94AB-0080C74C7E95"
|
classid="CLSID:22D6F312-B0F6-11D0-94AB-0080C74C7E95"
|
||||||
codebase="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=6,0,02,902"
|
codebase="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=6,0,02,902"
|
||||||
standby="Loading Microsoft Windows Media Player components..."
|
standby="Loading Microsoft Windows Media Player components..."
|
||||||
type="<?php echo $mimeType ?>">
|
type="'.$mimeType.'">
|
||||||
<param name="FileName" value="<?php echo $src ?>"/>
|
<param name="FileName" value="'.$src.'"/>
|
||||||
<param name="autoStart" value="1"/>
|
<param name="autoStart" value="1"/>
|
||||||
<param name="showControls" value="0"/>
|
<param name="showControls" value="0"/>
|
||||||
<embed type="<?php echo $mimeType ?>"
|
<embed type="'.$mimeType.'"
|
||||||
pluginspage="http://www.microsoft.com/Windows/MediaPlayer/"
|
pluginspage="http://www.microsoft.com/Windows/MediaPlayer/"
|
||||||
src="<?php echo $src ?>"
|
src="'.$src.'"
|
||||||
name="<?php echo validHtmlStr($title) ?>"
|
name="'.$title.'"
|
||||||
width="<?php echo validNum($width) ?>"
|
width="'.$width.'"
|
||||||
height="<?php echo validInt($height) ?>"
|
height="'.$height.'"
|
||||||
autostart="1"
|
autostart="1"
|
||||||
showcontrols="0">
|
showcontrols="0">
|
||||||
</embed>
|
</embed>
|
||||||
</object>
|
</object>';
|
||||||
<?php
|
|
||||||
$objectTag = true;
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case "video/quicktime" :
|
case "video/quicktime" :
|
||||||
{
|
{
|
||||||
?>
|
return '<object id="'.$id.'" width="'.$width.'" height="'.$height.'"
|
||||||
<object id="<?php echo $id ?>" width="<?php echo $width ?>" height="<?php echo $height ?>"
|
|
||||||
classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"
|
classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"
|
||||||
codebase="http://www.apple.com/qtactivex/qtplugin.cab"
|
codebase="http://www.apple.com/qtactivex/qtplugin.cab"
|
||||||
type="<?php echo $mimeType ?>">
|
type="'.$mimeType.'">
|
||||||
<param name="src" value="<?php echo $src ?>"/>
|
<param name="src" value="'.$src.'"/>
|
||||||
<param name="autoplay" VALUE="true"/>
|
<param name="autoplay" VALUE="true"/>
|
||||||
<param name="controller" VALUE="false"/>
|
<param name="controller" VALUE="false"/>
|
||||||
<embed type="<?php echo $mimeType ?>"
|
<embed type="'.$mimeType.'"
|
||||||
src="<?php echo $src ?>"
|
src="'.$src.'"
|
||||||
pluginspage="http://www.apple.com/quicktime/download/"
|
pluginspage="http://www.apple.com/quicktime/download/"
|
||||||
name="<?php echo validHtmlStr($title) ?>"
|
name="'.$title.'" width="'.$width.'" height="'.$height.'"
|
||||||
width="<?php echo validInt($width) ?>"
|
|
||||||
height="<?php echo validInt($height) ?>"
|
|
||||||
autoplay="true"
|
autoplay="true"
|
||||||
controller="true">
|
controller="true">
|
||||||
</embed>
|
</embed>
|
||||||
</object>
|
</object>';
|
||||||
<?php
|
|
||||||
$objectTag = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case "application/x-shockwave-flash" :
|
case "application/x-shockwave-flash" :
|
||||||
{
|
{
|
||||||
?>
|
return '<object id="'.$id.'" width="'.$width.'" height="'.$height.'"
|
||||||
<object id="<?php echo $id ?>" width="<?php echo $width ?>" height="<?php echo $height ?>"
|
|
||||||
classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
|
classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
|
||||||
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"
|
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"
|
||||||
type="<?php echo $mimeType ?>">
|
type="'.$mimeType.'">
|
||||||
<param name="movie" value="<?php echo $src ?>"/>
|
<param name="movie" value="'.$src.'"/>
|
||||||
<param name="quality" value="high"/>
|
<param name="quality" value="high"/>
|
||||||
<param name="bgcolor" value="#ffffff"/>
|
<param name="bgcolor" value="#ffffff"/>
|
||||||
<embed type="<?php echo $mimeType ?>"
|
<embed type="'.$mimeType.'"
|
||||||
pluginspage="http://www.macromedia.com/go/getflashplayer"
|
pluginspage="http://www.macromedia.com/go/getflashplayer"
|
||||||
src="<?php echo $src ?>"
|
src="'.$src.'"
|
||||||
name="<?php echo validHtmlStr($title) ?>"
|
name="'.$title.'"
|
||||||
width="<?php echo validInt($width) ?>"
|
width="'.$width.'"
|
||||||
height="<?php echo validInt($height) ?>"
|
height="'.$height.'"
|
||||||
quality="high"
|
quality="high"
|
||||||
bgcolor="#ffffff">
|
bgcolor="#ffffff">
|
||||||
</embed>
|
</embed>
|
||||||
</object>
|
</object>';
|
||||||
<?php
|
|
||||||
$objectTag = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
} # end switch
|
||||||
}
|
} # end if use object tags
|
||||||
if ( !$objectTag )
|
return '<embed'. ( isset($mimeType)?(' type="'.$mimeType.'"'):'' ). '
|
||||||
{
|
src="'.$src.'"
|
||||||
?>
|
name="'.$title.'"
|
||||||
<embed<?php echo isset($mimeType)?(' type="'.$mimeType.'"'):"" ?>
|
width="'.$width.'"
|
||||||
src="<?php echo $src ?>"
|
height="'.$height.'"
|
||||||
name="<?php echo validHtmlStr($title) ?>"
|
|
||||||
width="<?php echo validInt($width) ?>"
|
|
||||||
height="<?php echo validInt($height) ?>"
|
|
||||||
autostart="1"
|
autostart="1"
|
||||||
autoplay="1"
|
autoplay="1"
|
||||||
showcontrols="0"
|
showcontrols="0"
|
||||||
controller="0">
|
controller="0">
|
||||||
</embed>
|
</embed>';
|
||||||
<?php
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function outputImageStream( $id, $src, $width, $height, $title="" )
|
function outputImageStream( $id, $src, $width, $height, $title="" ) {
|
||||||
{
|
echo getImageStream( $id, $src, $width, $height, $title );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getImageStream( $id, $src, $width, $height, $title="" ) {
|
||||||
if ( canStreamIframe() ) {
|
if ( canStreamIframe() ) {
|
||||||
?>
|
return '<iframe id="'.$id.'" src="'.$src.'" alt="'. validHtmlStr($title) .'" width="'. validInt($width)." height=".validInt($height).'"/>';
|
||||||
<iframe id="<?php echo $id ?>" src="<?php echo $src ?>" alt="<?php echo validHtmlStr($title) ?>" width="<?php echo $width ?>" height="<?php echo $height ?>"/>
|
|
||||||
<?php
|
|
||||||
} else {
|
} else {
|
||||||
?>
|
return '<img id="'.$id.'" src="'.$src.'" alt="'. validHtmlStr($title) .'" width="'. validInt($width) .'" height="'. validInt( $height ).'"/>';
|
||||||
<img id="<?php echo $id ?>" src="<?php echo $src ?>" alt="<?php echo validHtmlStr($title) ?>" width="<?php echo $width ?>" height="<?php echo $height ?>"/>
|
|
||||||
<?php
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1685,7 +1668,11 @@ function getDiskPercent()
|
||||||
Error("disk_total_space returned false for " . ZM_DIR_EVENTS );
|
Error("disk_total_space returned false for " . ZM_DIR_EVENTS );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
$space = round(($total - disk_free_space(ZM_DIR_EVENTS)) / $total * 100);
|
$free = disk_free_space(ZM_DIR_EVENTS);
|
||||||
|
if ( ! $free ) {
|
||||||
|
Error("disk_free_space returned false for " . ZM_DIR_EVENTS );
|
||||||
|
}
|
||||||
|
$space = round(($total - $free) / $total * 100);
|
||||||
return( $space );
|
return( $space );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2507,11 +2494,11 @@ function getStreamHTML( $monitor, $scale=100 ) {
|
||||||
//FIXME, the width and height of the image need to be scaled.
|
//FIXME, the width and height of the image need to be scaled.
|
||||||
if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
|
if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
|
||||||
$streamSrc = $monitor->getStreamSrc( array( "mode=mpeg", "scale=".$scale, "bitrate=".ZM_WEB_VIDEO_BITRATE, "maxfps=".ZM_WEB_VIDEO_MAXFPS, "format=".ZM_MPEG_LIVE_FORMAT ) );
|
$streamSrc = $monitor->getStreamSrc( array( "mode=mpeg", "scale=".$scale, "bitrate=".ZM_WEB_VIDEO_BITRATE, "maxfps=".ZM_WEB_VIDEO_MAXFPS, "format=".ZM_MPEG_LIVE_FORMAT ) );
|
||||||
outputVideoStream( "liveStream", $streamSrc, reScale( $monitor->Width(), $scale ), reScale( $monitor->Height(), $scale ), ZM_MPEG_LIVE_FORMAT, $monitor->Name() );
|
return getVideoStream( "liveStream", $streamSrc, reScale( $monitor->Width(), $scale ), reScale( $monitor->Height(), $scale ), ZM_MPEG_LIVE_FORMAT, $monitor->Name() );
|
||||||
} else if ( canStream() ) {
|
} else if ( canStream() ) {
|
||||||
$streamSrc = $monitor->getStreamSrc( array( 'mode=jpeg', 'scale='.$scale, 'maxfps='.ZM_WEB_VIDEO_MAXFPS, 'buffer='.$monitor->StreamReplayBuffer() ) );
|
$streamSrc = $monitor->getStreamSrc( array( 'mode=jpeg', 'scale='.$scale, 'maxfps='.ZM_WEB_VIDEO_MAXFPS, 'buffer='.$monitor->StreamReplayBuffer() ) );
|
||||||
if ( canStreamNative() )
|
if ( canStreamNative() )
|
||||||
outputImageStream( "liveStream", $streamSrc, reScale( $monitor->Width(), $scale ), reScale( $monitor->Height(), $scale ), $monitor->Name() );
|
return getImageStream( "liveStream", $streamSrc, reScale( $monitor->Width(), $scale ), reScale( $monitor->Height(), $scale ), $monitor->Name() );
|
||||||
elseif ( canStreamApplet() )
|
elseif ( canStreamApplet() )
|
||||||
outputHelperStream( "liveStream", $streamSrc, reScale( $monitor->Width(), $scale ), reScale( $monitor->Height(), $scale ), $monitor->Name() );
|
outputHelperStream( "liveStream", $streamSrc, reScale( $monitor->Width(), $scale ), reScale( $monitor->Height(), $scale ), $monitor->Name() );
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -230,6 +230,7 @@ $SLANG = array(
|
||||||
'ChooseLogFormat' => 'Choose a log format',
|
'ChooseLogFormat' => 'Choose a log format',
|
||||||
'ChooseLogSelection' => 'Choose a log selection',
|
'ChooseLogSelection' => 'Choose a log selection',
|
||||||
'ChoosePreset' => 'Choose Preset',
|
'ChoosePreset' => 'Choose Preset',
|
||||||
|
'CloneMonitor' => 'Clone Monitor',
|
||||||
'Close' => 'Close',
|
'Close' => 'Close',
|
||||||
'Colour' => 'Colour',
|
'Colour' => 'Colour',
|
||||||
'Command' => 'Command',
|
'Command' => 'Command',
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
|
|
||||||
#menuBar1 {
|
#menuBar1 {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 1.5em;
|
|
||||||
padding: 3px 0;
|
padding: 3px 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
clear: both;
|
clear: both;
|
||||||
|
@ -41,7 +40,6 @@
|
||||||
|
|
||||||
#menuBar2 {
|
#menuBar2 {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 1.2em;
|
|
||||||
padding: 3px 0;
|
padding: 3px 0;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
@ -57,6 +55,16 @@
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#menuBar1:after,
|
||||||
|
#menuBar2:after {
|
||||||
|
content: ".";
|
||||||
|
display: block;
|
||||||
|
height: 0;
|
||||||
|
font-size: 0;
|
||||||
|
clear: both;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
#imageFeed {
|
#imageFeed {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,12 @@
|
||||||
|
|
||||||
#menuBar1 {
|
#menuBar1 {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 1.5em;
|
|
||||||
padding: 3px 0;
|
padding: 3px 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#menuBar1 #nameControl {
|
#menuBar1 #nameControl {
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,6 @@
|
||||||
|
|
||||||
#menuBar2 {
|
#menuBar2 {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 1.2em;
|
|
||||||
padding: 3px 0;
|
padding: 3px 0;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
@ -56,6 +55,15 @@
|
||||||
float: right;
|
float: right;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
#menuBar1:after,
|
||||||
|
#menuBar2:after {
|
||||||
|
content: ".";
|
||||||
|
display: block;
|
||||||
|
height: 0;
|
||||||
|
font-size: 0;
|
||||||
|
clear: both;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
#imageFeed {
|
#imageFeed {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
|
@ -30,7 +30,7 @@ function getControlCommands( $monitor )
|
||||||
$cmds['PresetGoto'] = "presetGoto";
|
$cmds['PresetGoto'] = "presetGoto";
|
||||||
$cmds['PresetHome'] = "presetHome";
|
$cmds['PresetHome'] = "presetHome";
|
||||||
|
|
||||||
if ( !empty($monitor->CanZoom) )
|
if ( !empty($monitor->CanZoom()) )
|
||||||
{
|
{
|
||||||
if ( $monitor->CanZoomCon() )
|
if ( $monitor->CanZoomCon() )
|
||||||
$cmds['ZoomRoot'] = "zoomCon";
|
$cmds['ZoomRoot'] = "zoomCon";
|
||||||
|
@ -45,7 +45,7 @@ function getControlCommands( $monitor )
|
||||||
$cmds['ZoomMan'] = "zoomMan";
|
$cmds['ZoomMan'] = "zoomMan";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !empty($monitor->CanFocus) )
|
if ( !empty($monitor->CanFocus()) )
|
||||||
{
|
{
|
||||||
if ( $monitor->CanFocusCon() )
|
if ( $monitor->CanFocusCon() )
|
||||||
$cmds['FocusRoot'] = "focusCon";
|
$cmds['FocusRoot'] = "focusCon";
|
||||||
|
@ -60,7 +60,7 @@ function getControlCommands( $monitor )
|
||||||
$cmds['FocusMan'] = "focusMan";
|
$cmds['FocusMan'] = "focusMan";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !empty($monitor->CanIris) )
|
if ( !empty($monitor->CanIris()) )
|
||||||
{
|
{
|
||||||
if ( $monitor->CanIrisCon() )
|
if ( $monitor->CanIrisCon() )
|
||||||
$cmds['IrisRoot'] = "irisCon";
|
$cmds['IrisRoot'] = "irisCon";
|
||||||
|
@ -75,7 +75,7 @@ function getControlCommands( $monitor )
|
||||||
$cmds['IrisMan'] = "irisMan";
|
$cmds['IrisMan'] = "irisMan";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !empty($monitor->CanWhite) )
|
if ( !empty($monitor->CanWhite()) )
|
||||||
{
|
{
|
||||||
if ( $monitor->CanWhiteCon() )
|
if ( $monitor->CanWhiteCon() )
|
||||||
$cmds['WhiteRoot'] = "whiteCon";
|
$cmds['WhiteRoot'] = "whiteCon";
|
||||||
|
@ -89,7 +89,7 @@ function getControlCommands( $monitor )
|
||||||
$cmds['WhiteMan'] = "whiteMan";
|
$cmds['WhiteMan'] = "whiteMan";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !empty($monitor->CanGain) )
|
if ( !empty($monitor->CanGain()) )
|
||||||
{
|
{
|
||||||
if ( $monitor->CanGainCon() )
|
if ( $monitor->CanGainCon() )
|
||||||
$cmds['GainRoot'] = "gainCon";
|
$cmds['GainRoot'] = "gainCon";
|
||||||
|
@ -103,7 +103,7 @@ function getControlCommands( $monitor )
|
||||||
$cmds['GainMan'] = "gainMan";
|
$cmds['GainMan'] = "gainMan";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !empty($monitor->CanMove) )
|
if ( !empty($monitor->CanMove()) )
|
||||||
{
|
{
|
||||||
if ( $monitor->CanMoveCon() )
|
if ( $monitor->CanMoveCon() )
|
||||||
{
|
{
|
||||||
|
@ -246,9 +246,9 @@ function controlPanTilt( $monitor, $cmds )
|
||||||
<div class="pantiltLabel"><?php echo translate('PanTilt') ?></div>
|
<div class="pantiltLabel"><?php echo translate('PanTilt') ?></div>
|
||||||
<div class="pantiltButtons">
|
<div class="pantiltButtons">
|
||||||
<?php
|
<?php
|
||||||
$hasPan = $monitor->CanPan;
|
$hasPan = $monitor->CanPan();
|
||||||
$hasTilt = $monitor->CanTilt;
|
$hasTilt = $monitor->CanTilt();
|
||||||
$hasDiag = $hasPan && $hasTilt && $monitor->CanMoveDiag;
|
$hasDiag = $hasPan && $hasTilt && $monitor->CanMoveDiag();
|
||||||
?>
|
?>
|
||||||
<div class="arrowBtn upLeftBtn<?php echo $hasDiag?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveUpLeft'] ?>',event,-1,-1)"></div>
|
<div class="arrowBtn upLeftBtn<?php echo $hasDiag?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveUpLeft'] ?>',event,-1,-1)"></div>
|
||||||
<div class="arrowBtn upBtn<?php echo $hasTilt?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveUp'] ?>',event,0,-1)"></div>
|
<div class="arrowBtn upBtn<?php echo $hasTilt?'':' invisible' ?>" onclick="controlCmd('<?php echo $cmds['MoveUp'] ?>',event,0,-1)"></div>
|
||||||
|
@ -278,7 +278,7 @@ function controlPresets( $monitor, $cmds )
|
||||||
$labels[$row['Preset']] = $row['Label'];
|
$labels[$row['Preset']] = $row['Label'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$presetBreak = (int)(($monitor->NumPresets+1)/((int)(($monitor->NumPresets-1)/MAX_PRESETS)+1));
|
$presetBreak = (int)(($monitor->NumPresets()+1)/((int)(($monitor->NumPresets()-1)/MAX_PRESETS)+1));
|
||||||
|
|
||||||
ob_start();
|
ob_start();
|
||||||
?>
|
?>
|
||||||
|
@ -286,7 +286,7 @@ function controlPresets( $monitor, $cmds )
|
||||||
<!--<div><?php echo translate('Presets') ?></div>-->
|
<!--<div><?php echo translate('Presets') ?></div>-->
|
||||||
<div>
|
<div>
|
||||||
<?php
|
<?php
|
||||||
for ( $i = 1; $i <= $monitor->NumPresets; $i++ )
|
for ( $i = 1; $i <= $monitor->NumPresets(); $i++ )
|
||||||
{
|
{
|
||||||
?><input type="button" class="ptzNumBtn" title="<?php echo isset($labels[$i])?$labels[$i]:"" ?>" value="<?php echo $i ?>" onclick="controlCmd('<?php echo $cmds['PresetGoto'] ?><?php echo $i ?>');"/><?php
|
?><input type="button" class="ptzNumBtn" title="<?php echo isset($labels[$i])?$labels[$i]:"" ?>" value="<?php echo $i ?>" onclick="controlCmd('<?php echo $cmds['PresetGoto'] ?><?php echo $i ?>');"/><?php
|
||||||
if ( $i && (($i%$presetBreak) == 0) )
|
if ( $i && (($i%$presetBreak) == 0) )
|
||||||
|
|
|
@ -589,7 +589,6 @@ else if (document.layers) window.onload=start_slider;
|
||||||
|
|
||||||
function exportEventImagesMaster( $eids )
|
function exportEventImagesMaster( $eids )
|
||||||
{
|
{
|
||||||
global $SLANG;
|
|
||||||
ob_start();
|
ob_start();
|
||||||
exportHeader( translate('Images').' Master' );
|
exportHeader( translate('Images').' Master' );
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -48,7 +48,7 @@ var popupSizes = {
|
||||||
'log': { 'width': 1080, 'height': 720 },
|
'log': { 'width': 1080, 'height': 720 },
|
||||||
'login': { 'width': 720, 'height': 480 },
|
'login': { 'width': 720, 'height': 480 },
|
||||||
'logout': { 'width': 260, 'height': 100 },
|
'logout': { 'width': 260, 'height': 100 },
|
||||||
'monitor': { 'width': 450, 'height': 440 },
|
'monitor': { 'width': 700, 'height': 640 },
|
||||||
'monitorpreset':{ 'width': 440, 'height': 200 },
|
'monitorpreset':{ 'width': 440, 'height': 200 },
|
||||||
'monitorprobe': { 'width': 500, 'height': 240 },
|
'monitorprobe': { 'width': 500, 'height': 240 },
|
||||||
'monitorselect':{ 'width': 160, 'height': 200 },
|
'monitorselect':{ 'width': 160, 'height': 200 },
|
||||||
|
|
|
@ -48,7 +48,7 @@ var popupSizes = {
|
||||||
'log': { 'width': 1080, 'height': 720 },
|
'log': { 'width': 1080, 'height': 720 },
|
||||||
'login': { 'width': 720, 'height': 480 },
|
'login': { 'width': 720, 'height': 480 },
|
||||||
'logout': { 'width': 260, 'height': 150 },
|
'logout': { 'width': 260, 'height': 150 },
|
||||||
'monitor': { 'width': 600, 'height': 780 },
|
'monitor': { 'width': 800, 'height': 780 },
|
||||||
'monitorpreset':{ 'width': 440, 'height': 200 },
|
'monitorpreset':{ 'width': 440, 'height': 200 },
|
||||||
'monitorprobe': { 'width': 500, 'height': 240 },
|
'monitorprobe': { 'width': 500, 'height': 240 },
|
||||||
'monitorselect':{ 'width': 160, 'height': 200 },
|
'monitorselect':{ 'width': 160, 'height': 200 },
|
||||||
|
|
|
@ -54,7 +54,9 @@ if ( canEdit('Monitors') )
|
||||||
if ( $show_storage_areas ) { $columns += 1; }
|
if ( $show_storage_areas ) { $columns += 1; }
|
||||||
echo $columns;
|
echo $columns;
|
||||||
?>">
|
?>">
|
||||||
<input type="button" class="btn btn-default" value="<?php echo translate('AddNewMonitor'); ?>" onclick="createPopup( '?view=monitor', 'zmMonitor0', 'monitor' ); return( false );"></input>
|
<input type="button" name="addBtn" value="<?php echo translate('AddNewMonitor') ?>" onclick="addMonitor( this )"/>
|
||||||
|
<!-- <?php echo makePopupButton( '?view=monitor', 'zmMonitor0', 'monitor', translate('AddNewMonitor'), (canEdit( 'Monitors' ) && !$user['MonitorIds']) ) ?> -->
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<?php
|
<?php
|
||||||
for ( $i = 0; $i < count($eventCounts); $i++ )
|
for ( $i = 0; $i < count($eventCounts); $i++ )
|
||||||
|
|
|
@ -27,7 +27,7 @@ if ( !canView( 'Events' ) )
|
||||||
$eid = validInt( $_REQUEST['eid'] );
|
$eid = validInt( $_REQUEST['eid'] );
|
||||||
$fid = !empty($_REQUEST['fid'])?validInt($_REQUEST['fid']):1;
|
$fid = !empty($_REQUEST['fid'])?validInt($_REQUEST['fid']):1;
|
||||||
|
|
||||||
$sql = 'SELECT E.*,M.Name AS MonitorName,M.Width,M.Height,M.DefaultRate,M.DefaultScale,M.VideoWriter,M.SaveJPEGs,M.Orientation,M.LabelFormat FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE E.Id = ?';
|
$sql = 'SELECT E.*,M.Name AS MonitorName,E.Width,E.Height,M.DefaultRate,M.DefaultScale,M.VideoWriter,M.SaveJPEGs,M.Orientation,M.LabelFormat FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE E.Id = ?';
|
||||||
$sql_values = array( $eid );
|
$sql_values = array( $eid );
|
||||||
|
|
||||||
if ( $user['MonitorIds'] ) {
|
if ( $user['MonitorIds'] ) {
|
||||||
|
|
|
@ -66,13 +66,11 @@ if ( !empty($limit) && $nEvents > $limit )
|
||||||
$nEvents = $limit;
|
$nEvents = $limit;
|
||||||
}
|
}
|
||||||
$pages = (int)ceil($nEvents/ZM_WEB_EVENTS_PER_PAGE);
|
$pages = (int)ceil($nEvents/ZM_WEB_EVENTS_PER_PAGE);
|
||||||
if ( $pages > 1 ) {
|
if ( !empty($page) ) {
|
||||||
if ( !empty($page) ) {
|
|
||||||
if ( $page < 0 )
|
if ( $page < 0 )
|
||||||
$page = 1;
|
$page = 1;
|
||||||
if ( $page > $pages )
|
if ( $page > $pages )
|
||||||
$page = $pages;
|
$page = $pages;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if ( !empty($page) ) {
|
if ( !empty($page) ) {
|
||||||
$limitStart = (($page-1)*ZM_WEB_EVENTS_PER_PAGE);
|
$limitStart = (($page-1)*ZM_WEB_EVENTS_PER_PAGE);
|
||||||
|
|
|
@ -23,6 +23,7 @@ if ( !canView( 'Events' ) )
|
||||||
$view = "error";
|
$view = "error";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
require_once('includes/Frame.php');
|
||||||
|
|
||||||
$eid = validInt($_REQUEST['eid']);
|
$eid = validInt($_REQUEST['eid']);
|
||||||
if ( !empty($_REQUEST['fid']) )
|
if ( !empty($_REQUEST['fid']) )
|
||||||
|
@ -38,58 +39,60 @@ if ( !empty($fid) ) {
|
||||||
} else {
|
} else {
|
||||||
$frame = dbFetchOne( 'SELECT * FROM Frames WHERE EventId = ? AND Score = ?', NULL, array( $eid, $event['MaxScore'] ) );
|
$frame = dbFetchOne( 'SELECT * FROM Frames WHERE EventId = ? AND Score = ?', NULL, array( $eid, $event['MaxScore'] ) );
|
||||||
}
|
}
|
||||||
|
$frame = new Frame( $frame );
|
||||||
|
|
||||||
$maxFid = $event['Frames'];
|
$maxFid = $event['Frames'];
|
||||||
|
|
||||||
$firstFid = 1;
|
$firstFid = 1;
|
||||||
$prevFid = $frame['FrameId']-1;
|
$prevFid = $frame->FrameId()-1;
|
||||||
$nextFid = $frame['FrameId']+1;
|
$nextFid = $frame->FrameId()+1;
|
||||||
$lastFid = $maxFid;
|
$lastFid = $maxFid;
|
||||||
|
|
||||||
$alarmFrame = $frame['Type']=='Alarm';
|
$alarmFrame = $frame->Type()=='Alarm';
|
||||||
|
|
||||||
if ( isset( $_REQUEST['scale'] ) )
|
if ( isset( $_REQUEST['scale'] ) )
|
||||||
$scale = validInt($_REQUEST['scale']);
|
$scale = validInt($_REQUEST['scale']);
|
||||||
else
|
else
|
||||||
$scale = max( reScale( SCALE_BASE, $event['DefaultScale'], ZM_WEB_DEFAULT_SCALE ), SCALE_BASE );
|
$scale = max( reScale( SCALE_BASE, $event['DefaultScale'], ZM_WEB_DEFAULT_SCALE ), SCALE_BASE );
|
||||||
|
|
||||||
$imageData = getImageSrc( $event, $frame, $scale, (isset($_REQUEST['show']) && $_REQUEST['show']=="capt") );
|
$imageData = getImageSrc( $event, $frame->FrameId(), $scale, (isset($_REQUEST['show']) && $_REQUEST['show']=="capt") );
|
||||||
|
|
||||||
$imagePath = $imageData['thumbPath'];
|
$imagePath = $imageData['thumbPath'];
|
||||||
$eventPath = $imageData['eventPath'];
|
$eventPath = $imageData['eventPath'];
|
||||||
$dImagePath = sprintf( "%s/%0".ZM_EVENT_IMAGE_DIGITS."d-diag-d.jpg", $eventPath, $frame['FrameId'] );
|
$dImagePath = sprintf( "%s/%0".ZM_EVENT_IMAGE_DIGITS."d-diag-d.jpg", $eventPath, $frame->FrameId() );
|
||||||
$rImagePath = sprintf( "%s/%0".ZM_EVENT_IMAGE_DIGITS."d-diag-r.jpg", $eventPath, $frame['FrameId'] );
|
$rImagePath = sprintf( "%s/%0".ZM_EVENT_IMAGE_DIGITS."d-diag-r.jpg", $eventPath, $frame->FrameId() );
|
||||||
|
|
||||||
$focusWindow = true;
|
$focusWindow = true;
|
||||||
|
|
||||||
xhtmlHeaders(__FILE__, translate('Frame')." - ".$event['Id']." - ".$frame['FrameId'] );
|
xhtmlHeaders(__FILE__, translate('Frame')." - ".$event['Id']." - ".$frame->FrameId() );
|
||||||
?>
|
?>
|
||||||
<body>
|
<body>
|
||||||
<div id="page">
|
<div id="page">
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<div id="headerButtons">
|
<div id="headerButtons">
|
||||||
<?php if ( ZM_RECORD_EVENT_STATS && $alarmFrame ) { echo makePopupLink( '?view=stats&eid='.$event['Id'].'&fid='.$frame['FrameId'], 'zmStats', 'stats', translate('Stats') ); } ?>
|
<?php if ( ZM_RECORD_EVENT_STATS && $alarmFrame ) { echo makePopupLink( '?view=stats&eid='.$event['Id'].'&fid='.$frame->FrameId(), 'zmStats', 'stats', translate('Stats') ); } ?>
|
||||||
<?php if ( canEdit( 'Events' ) ) { ?><a href="?view=none&action=delete&markEid=<?php echo $event['Id'] ?>"><?php echo translate('Delete') ?></a><?php } ?>
|
<?php if ( canEdit( 'Events' ) ) { ?><a href="?view=none&action=delete&markEid=<?php echo $event['Id'] ?>"><?php echo translate('Delete') ?></a><?php } ?>
|
||||||
<a href="#" onclick="closeWindow(); return( false );"><?php echo translate('Close') ?></a>
|
<a href="#" onclick="closeWindow(); return( false );"><?php echo translate('Close') ?></a>
|
||||||
</div>
|
</div>
|
||||||
<h2><?php echo translate('Frame') ?> <?php echo $event['Id']."-".$frame['FrameId']." (".$frame['Score'].")" ?></h2>
|
<h2><?php echo translate('Frame') ?> <?php echo $event['Id']."-".$frame->FrameId()." (".$frame->Score().")" ?></h2>
|
||||||
</div>
|
</div>
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<p id="image">
|
<p id="image">
|
||||||
<?php if ( in_array($event['VideoWriter'],array("1","2")) ) { ?>
|
<?php if ( in_array($event['VideoWriter'],array("1","2")) ) { ?>
|
||||||
<img src="?view=image-ffmpeg&eid=<?php echo $event['Id'] ?>&fid=<?php echo $frame['FrameId'] ?>&scale=<?php echo $event['DefaultScale'] ?>" class="<?php echo $imageData['imageClass'] ?>">
|
<img src="?view=image-ffmpeg&eid=<?php echo $event['Id'] ?>&fid=<?php echo $frame->FrameId() ?>&scale=<?php echo $event['DefaultScale'] ?>" class="<?php echo $imageData['imageClass'] ?>">
|
||||||
<?php } else {
|
<?php } else {
|
||||||
if ( $imageData['hasAnalImage'] ) { ?><a href="?view=frame&eid=<?php echo $event['Id'] ?>&fid=<?php echo $frame['FrameId'] ?>&scale=<?php echo $scale ?>&show=<?php echo $imageData['isAnalImage']?"capt":"anal" ?>"><?php } ?><img src="<?php echo viewImagePath( $imagePath ) ?>" width="<?php echo reScale( $event['Width'], $event['DefaultScale'], $scale ) ?>" height="<?php echo reScale( $event['Height'], $event['DefaultScale'], $scale ) ?>" alt="<?php echo $frame['EventId']."-".$frame['FrameId'] ?>" class="<?php echo $imageData['imageClass'] ?>"/><?php if ( $imageData['hasAnalImage'] ) { ?></a><?php } ?>
|
if ( $imageData['hasAnalImage'] ) { ?><a href="?view=frame&eid=<?php echo $event['Id'] ?>&fid=<?php echo $frame->FrameId() ?>&scale=<?php echo $scale ?>&show=<?php echo $imageData['isAnalImage']?"capt":"anal" ?>"><?php } ?>
|
||||||
|
<img src="<?php echo $frame->getImageSrc() ?>" width="<?php echo reScale( $event['Width'], $event['DefaultScale'], $scale ) ?>" height="<?php echo reScale( $event['Height'], $event['DefaultScale'], $scale ) ?>" alt="<?php echo $frame->EventId()."-".$frame->FrameId() ?>" class="<?php echo $imageData['imageClass'] ?>"/><?php if ( $imageData['hasAnalImage'] ) { ?></a><?php } ?>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
</p>
|
</p>
|
||||||
<p id="controls">
|
<p id="controls">
|
||||||
<?php if ( $frame['FrameId'] > 1 ) { ?>
|
<?php if ( $frame->FrameId() > 1 ) { ?>
|
||||||
<a id="firstLink" href="?view=frame&eid=<?php echo $event['Id'] ?>&fid=<?php echo $firstFid ?>&scale=<?php echo $scale ?>"><?php echo translate('First') ?></a>
|
<a id="firstLink" href="?view=frame&eid=<?php echo $event['Id'] ?>&fid=<?php echo $firstFid ?>&scale=<?php echo $scale ?>"><?php echo translate('First') ?></a>
|
||||||
<?php } if ( $frame['FrameId'] > 1 ) { ?>
|
<?php } if ( $frame->FrameId() > 1 ) { ?>
|
||||||
<a id="prevLink" href="?view=frame&eid=<?php echo $event['Id'] ?>&fid=<?php echo $prevFid ?>&scale=<?php echo $scale ?>"><?php echo translate('Prev') ?></a>
|
<a id="prevLink" href="?view=frame&eid=<?php echo $event['Id'] ?>&fid=<?php echo $prevFid ?>&scale=<?php echo $scale ?>"><?php echo translate('Prev') ?></a>
|
||||||
<?php } if ( $frame['FrameId'] < $maxFid ) { ?>
|
<?php } if ( $frame->FrameId() < $maxFid ) { ?>
|
||||||
<a id="nextLink" href="?view=frame&eid=<?php echo $event['Id'] ?>&fid=<?php echo $nextFid ?>&scale=<?php echo $scale ?>"><?php echo translate('Next') ?></a>
|
<a id="nextLink" href="?view=frame&eid=<?php echo $event['Id'] ?>&fid=<?php echo $nextFid ?>&scale=<?php echo $scale ?>"><?php echo translate('Next') ?></a>
|
||||||
<?php } if ( $frame['FrameId'] < $maxFid ) { ?>
|
<?php } if ( $frame->FrameId() < $maxFid ) { ?>
|
||||||
<a id="lastLink" href="?view=frame&eid=<?php echo $event['Id'] ?>&fid=<?php echo $lastFid ?>&scale=<?php echo $scale ?>"><?php echo translate('Last') ?></a>
|
<a id="lastLink" href="?view=frame&eid=<?php echo $event['Id'] ?>&fid=<?php echo $lastFid ?>&scale=<?php echo $scale ?>"><?php echo translate('Last') ?></a>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -205,14 +205,9 @@ $versionClass = (ZM_DYN_DB_VERSION&&(ZM_DYN_DB_VERSION!=ZM_VERSION))?'errorText'
|
||||||
<?php if ( canView( 'Stream' ) && $cycleCount > 1 ) {
|
<?php if ( canView( 'Stream' ) && $cycleCount > 1 ) {
|
||||||
$cycleGroup = isset($_COOKIE['zmGroup'])?$_COOKIE['zmGroup']:0;
|
$cycleGroup = isset($_COOKIE['zmGroup'])?$_COOKIE['zmGroup']:0;
|
||||||
?>
|
?>
|
||||||
<li class="dropdown">
|
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Montage <span class="caret"></span></a>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li><?php echo makePopupLink( '?view=cycle&group='.$cycleGroup, 'zmCycle'.$cycleGroup, array( 'cycle', $cycleWidth, $cycleHeight ), translate('Cycle'), $running ) ?></li>
|
<li><?php echo makePopupLink( '?view=cycle&group='.$cycleGroup, 'zmCycle'.$cycleGroup, array( 'cycle', $cycleWidth, $cycleHeight ), translate('Cycle'), $running ) ?></li>
|
||||||
<li><?php echo makePopupLink( '?view=montage&group='.$cycleGroup, 'zmMontage'.$cycleGroup, 'montage', translate('Montage'), $running ) ?></li>
|
<li><?php echo makePopupLink( '?view=montage&group='.$cycleGroup, 'zmMontage'.$cycleGroup, 'montage', translate('Montage'), $running ) ?></li>
|
||||||
<li><?php echo makePopupLink( '?view=montagereview&group='.$cycleGroup, 'zmMontage'.$cycleGroup, 'montagereview', translate('Montage Review'), $running ) ?></li>
|
<li><?php echo makePopupLink( '?view=montagereview&group='.$cycleGroup, 'zmMontage'.$cycleGroup, 'montagereview', translate('Montage Review'), $running ) ?></li>
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
var jsTranslatedAddText;
|
||||||
|
var jsTranslatedCloneText;
|
||||||
|
|
||||||
function setButtonStates( element )
|
function setButtonStates( element )
|
||||||
{
|
{
|
||||||
var form = element.form;
|
var form = element.form;
|
||||||
|
@ -12,21 +15,37 @@ function setButtonStates( element )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( form.elements[i].length )
|
}
|
||||||
|
$(element).getParent( 'tr' ).toggleClass( 'highlight' );
|
||||||
|
form.editBtn.disabled = (checked!=1);
|
||||||
|
form.addBtn.value = (checked==1) ? jsTranslatedCloneText:jsTranslatedAddText;
|
||||||
|
|
||||||
|
form.deleteBtn.disabled = (checked==0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addMonitor( element)
|
||||||
|
{
|
||||||
|
|
||||||
|
var form = element.form;
|
||||||
|
var dupParam;
|
||||||
|
var monitorId=-1;
|
||||||
|
if (form.addBtn.value == jsTranslatedCloneText)
|
||||||
{
|
{
|
||||||
for( var j = 0, j_length = form.elements[i].length; j < j_length; j += 1 ) {
|
// get the value of the first checkbox
|
||||||
if ( form.elements[j].type == "checkbox" ) {
|
for ( var i = 0; i < form.elements.length; i++ )
|
||||||
if ( form.elements[j].checked ) {
|
{
|
||||||
if ( checked++ > 1 )
|
if ( form.elements[i].type == "checkbox" )
|
||||||
|
{
|
||||||
|
if ( form.elements[i].checked )
|
||||||
|
{
|
||||||
|
monitorId = form.elements[i].value;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // end foreach element in array
|
|
||||||
}
|
}
|
||||||
} // end foreach element in array
|
}
|
||||||
$(element).getParent( 'tr' ).toggleClass( 'highlight' );
|
dupParam = (monitorId == -1 ) ? '': '&dupId='+monitorId;
|
||||||
form.editBtn.disabled = (checked!=1);
|
createPopup( '?view=monitor'+dupParam, 'zmMonitor0','monitor' );
|
||||||
form.deleteBtn.disabled = (checked==0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function editMonitor( element )
|
function editMonitor( element )
|
||||||
|
@ -66,6 +85,8 @@ function reloadWindow()
|
||||||
|
|
||||||
function initPage()
|
function initPage()
|
||||||
{
|
{
|
||||||
|
jsTranslatedAddText = translatedAddText;
|
||||||
|
jsTranslatedCloneText = translatedCloneText;
|
||||||
reloadWindow.periodical( consoleRefreshTimeout );
|
reloadWindow.periodical( consoleRefreshTimeout );
|
||||||
if ( showVersionPopup )
|
if ( showVersionPopup )
|
||||||
createPopup( '?view=version', 'zmVersion', 'version' );
|
createPopup( '?view=version', 'zmVersion', 'version' );
|
||||||
|
|
|
@ -26,7 +26,7 @@ elseif ( ZM_DYN_SHOW_DONATE_REMINDER )
|
||||||
?>
|
?>
|
||||||
var showVersionPopup = <?php echo isset($showVersionPopup )?'true':'false' ?>;
|
var showVersionPopup = <?php echo isset($showVersionPopup )?'true':'false' ?>;
|
||||||
var showDonatePopup = <?php echo isset($showDonatePopup )?'true':'false' ?>;
|
var showDonatePopup = <?php echo isset($showDonatePopup )?'true':'false' ?>;
|
||||||
|
var translatedAddText = "<?php echo translate('AddNewMonitor') ?>";
|
||||||
|
var translatedCloneText = "<?php echo translate('CloneMonitor') ?>";
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ function Monitor( index, id, connKey )
|
||||||
if ( this.streamCmdTimer )
|
if ( this.streamCmdTimer )
|
||||||
this.streamCmdTimer = clearTimeout( this.streamCmdTimer );
|
this.streamCmdTimer = clearTimeout( this.streamCmdTimer );
|
||||||
|
|
||||||
|
var stream = document.getElementById( "liveStream"+this.id );
|
||||||
if ( respObj.result == 'Ok' )
|
if ( respObj.result == 'Ok' )
|
||||||
{
|
{
|
||||||
this.status = respObj.status;
|
this.status = respObj.status;
|
||||||
|
@ -57,7 +58,6 @@ function Monitor( index, id, connKey )
|
||||||
this.setStateClass( $('monitor'+this.index), stateClass );
|
this.setStateClass( $('monitor'+this.index), stateClass );
|
||||||
|
|
||||||
/*Stream could be an applet so can't use moo tools*/
|
/*Stream could be an applet so can't use moo tools*/
|
||||||
var stream = document.getElementById( "liveStream"+this.id );
|
|
||||||
stream.className = stateClass;
|
stream.className = stateClass;
|
||||||
|
|
||||||
var isAlarmed = ( this.alarmState == STATE_ALARM || this.alarmState == STATE_ALERT );
|
var isAlarmed = ( this.alarmState == STATE_ALARM || this.alarmState == STATE_ALERT );
|
||||||
|
@ -90,6 +90,10 @@ function Monitor( index, id, connKey )
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
console.error( respObj.message );
|
console.error( respObj.message );
|
||||||
|
// Try to reload the image stream.
|
||||||
|
if ( stream )
|
||||||
|
stream.src = stream.src.replace(/rand=\d+/i,'rand='+Math.floor((Math.random() * 1000000) ));
|
||||||
|
|
||||||
}
|
}
|
||||||
var streamCmdTimeout = statusRefreshTimeout;
|
var streamCmdTimeout = statusRefreshTimeout;
|
||||||
if ( this.alarmState == STATE_ALARM || this.alarmState == STATE_ALERT )
|
if ( this.alarmState == STATE_ALARM || this.alarmState == STATE_ALERT )
|
||||||
|
|
|
@ -475,8 +475,211 @@ function drawZonePoints()
|
||||||
updateZoneImage();
|
updateZoneImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
function initPage()
|
//
|
||||||
|
// Imported from watch.js and modified for new zone edit view
|
||||||
|
//
|
||||||
|
|
||||||
|
var alarmState = STATE_IDLE;
|
||||||
|
var lastAlarmState = STATE_IDLE;
|
||||||
|
|
||||||
|
function setAlarmState( currentAlarmState ) {
|
||||||
|
alarmState = currentAlarmState;
|
||||||
|
|
||||||
|
var stateString = "Unknown";
|
||||||
|
var stateClass = "";
|
||||||
|
if ( alarmState == STATE_ALARM )
|
||||||
|
stateClass = "alarm";
|
||||||
|
else if ( alarmState == STATE_ALERT )
|
||||||
|
stateClass = "alert";
|
||||||
|
$('stateValue').set( 'text', stateStrings[alarmState] );
|
||||||
|
if ( stateClass )
|
||||||
|
$('stateValue').setProperty( 'class', stateClass );
|
||||||
|
else
|
||||||
|
$('stateValue').removeProperty( 'class' );
|
||||||
|
|
||||||
|
var isAlarmed = ( alarmState == STATE_ALARM || alarmState == STATE_ALERT );
|
||||||
|
var wasAlarmed = ( lastAlarmState == STATE_ALARM || lastAlarmState == STATE_ALERT );
|
||||||
|
|
||||||
|
var newAlarm = ( isAlarmed && !wasAlarmed );
|
||||||
|
var oldAlarm = ( !isAlarmed && wasAlarmed );
|
||||||
|
|
||||||
|
if ( newAlarm )
|
||||||
|
{
|
||||||
|
if ( SOUND_ON_ALARM )
|
||||||
|
{
|
||||||
|
// Enable the alarm sound
|
||||||
|
if ( !canPlayPauseAudio )
|
||||||
|
$('alarmSound').removeClass( 'hidden' );
|
||||||
|
else
|
||||||
|
$('MediaPlayer').Play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( SOUND_ON_ALARM )
|
||||||
|
{
|
||||||
|
if ( oldAlarm )
|
||||||
|
{
|
||||||
|
// Disable alarm sound
|
||||||
|
if ( !canPlayPauseAudio )
|
||||||
|
$('alarmSound').addClass( 'hidden' );
|
||||||
|
else
|
||||||
|
$('MediaPlayer').Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastAlarmState = alarmState;
|
||||||
|
}
|
||||||
|
|
||||||
|
var streamCmdParms = "view=request&request=stream&connkey="+connKey;
|
||||||
|
var streamCmdReq = new Request.JSON( { url: monitorUrl+thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getStreamCmdResponse } );
|
||||||
|
var streamCmdTimer = null;
|
||||||
|
|
||||||
|
var streamStatus;
|
||||||
|
|
||||||
|
function getStreamCmdResponse( respObj, respText ) {
|
||||||
|
watchdogOk("stream");
|
||||||
|
if ( streamCmdTimer )
|
||||||
|
streamCmdTimer = clearTimeout( streamCmdTimer );
|
||||||
|
|
||||||
|
if ( respObj.result == 'Ok' ) {
|
||||||
|
streamStatus = respObj.status;
|
||||||
|
$('fpsValue').set( 'text', streamStatus.fps );
|
||||||
|
|
||||||
|
setAlarmState( streamStatus.state );
|
||||||
|
|
||||||
|
var delayString = secsToTime( streamStatus.delay );
|
||||||
|
|
||||||
|
if ( streamStatus.paused == true )
|
||||||
|
{
|
||||||
|
streamCmdPause( false );
|
||||||
|
} else if ( streamStatus.delayed == true && streamStatus.rate == 1 ) {
|
||||||
|
streamCmdPlay( false );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
checkStreamForErrors("getStreamCmdResponse",respObj);//log them
|
||||||
|
// Try to reload the image stream.
|
||||||
|
var streamImg = document.getElementById('liveStream');
|
||||||
|
if ( streamImg )
|
||||||
|
streamImg.src = streamImg.src.replace(/rand=\d+/i,'rand='+Math.floor((Math.random() * 1000000) ));
|
||||||
|
}
|
||||||
|
|
||||||
|
var streamCmdTimeout = statusRefreshTimeout;
|
||||||
|
if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT )
|
||||||
|
streamCmdTimeout = streamCmdTimeout/5;
|
||||||
|
streamCmdTimer = streamCmdQuery.delay( streamCmdTimeout );
|
||||||
|
}
|
||||||
|
|
||||||
|
var streamPause = false;
|
||||||
|
|
||||||
|
function streamCmdPauseToggle() {
|
||||||
|
if ( streamPause == true ) {
|
||||||
|
streamCmdPlay( true );
|
||||||
|
streamPause = false;
|
||||||
|
document.getElementById("pauseBtn").value = pauseString;
|
||||||
|
} else {
|
||||||
|
streamCmdPause( true );
|
||||||
|
streamPause = true;
|
||||||
|
document.getElementById("pauseBtn").value = playString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function streamCmdPause( action ) {
|
||||||
|
if ( action )
|
||||||
|
streamCmdReq.send( streamCmdParms+"&command="+CMD_PAUSE );
|
||||||
|
}
|
||||||
|
|
||||||
|
function streamCmdPlay( action )
|
||||||
{
|
{
|
||||||
|
if ( action )
|
||||||
|
streamCmdReq.send( streamCmdParms+"&command="+CMD_PLAY );
|
||||||
|
}
|
||||||
|
|
||||||
|
function streamCmdStop( action ) {
|
||||||
|
if ( action )
|
||||||
|
streamCmdReq.send( streamCmdParms+"&command="+CMD_STOP );
|
||||||
|
}
|
||||||
|
|
||||||
|
function streamCmdQuery() {
|
||||||
|
streamCmdReq.send( streamCmdParms+"&command="+CMD_QUERY );
|
||||||
|
}
|
||||||
|
|
||||||
|
var statusCmdParms = "view=request&request=status&entity=monitor&id="+monitorId+"&element[]=Status&element[]=FrameRate";
|
||||||
|
var statusCmdReq = new Request.JSON( { url: monitorUrl+thisUrl, method: 'post', data: statusCmdParms, timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getStatusCmdResponse } );
|
||||||
|
var statusCmdTimer = null;
|
||||||
|
|
||||||
|
function getStatusCmdResponse( respObj, respText ) {
|
||||||
|
watchdogOk("status");
|
||||||
|
if ( statusCmdTimer )
|
||||||
|
statusCmdTimer = clearTimeout( statusCmdTimer );
|
||||||
|
|
||||||
|
if ( respObj.result == 'Ok' )
|
||||||
|
{
|
||||||
|
$('fpsValue').set( 'text', respObj.monitor.FrameRate );
|
||||||
|
setAlarmState( respObj.monitor.Status );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
checkStreamForErrors("getStatusCmdResponse",respObj);
|
||||||
|
|
||||||
|
var statusCmdTimeout = statusRefreshTimeout;
|
||||||
|
if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT )
|
||||||
|
statusCmdTimeout = statusCmdTimeout/5;
|
||||||
|
statusCmdTimer = statusCmdQuery.delay( statusCmdTimeout );
|
||||||
|
}
|
||||||
|
|
||||||
|
function statusCmdQuery() {
|
||||||
|
statusCmdReq.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
var tempImage = null;
|
||||||
|
|
||||||
|
function fetchImage( streamImage ) {
|
||||||
|
var now = new Date();
|
||||||
|
if ( !tempImage )
|
||||||
|
tempImage = new Element( 'img' );
|
||||||
|
tempImage.setProperty( 'src', streamSrc+'&'+now.getTime() );
|
||||||
|
$(streamImage).setProperty( 'src', tempImage.getProperty( 'src' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
function appletRefresh() {
|
||||||
|
if ( streamStatus && (!streamStatus.paused && !streamStatus.delayed) )
|
||||||
|
{
|
||||||
|
var streamImg = $('liveStream');
|
||||||
|
var parent = streamImg.getParent();
|
||||||
|
streamImg.dispose();
|
||||||
|
streamImg.inject( parent );
|
||||||
|
if ( appletRefreshTime )
|
||||||
|
appletRefresh.delay( appletRefreshTime*1000 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
appletRefresh.delay( 15*1000 ); //if we are paused or delayed check every 15 seconds if we are live yet...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var watchdogInactive = {
|
||||||
|
'stream': false,
|
||||||
|
'status': false
|
||||||
|
};
|
||||||
|
|
||||||
|
var watchdogFunctions = {
|
||||||
|
'stream': streamCmdQuery,
|
||||||
|
'status': statusCmdQuery
|
||||||
|
};
|
||||||
|
|
||||||
|
//Make sure the various refreshes are still taking effect
|
||||||
|
function watchdogCheck( type ) {
|
||||||
|
if ( watchdogInactive[type] ) {
|
||||||
|
console.log( "Detected streamWatch of type: " + type + " stopped, restarting" );
|
||||||
|
watchdogFunctions[type]();
|
||||||
|
watchdogInactive[type] = false;
|
||||||
|
} else {
|
||||||
|
watchdogInactive[type] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function watchdogOk( type ) {
|
||||||
|
watchdogInactive[type] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initPage() {
|
||||||
var form = document.zoneForm;
|
var form = document.zoneForm;
|
||||||
|
|
||||||
//form.elements['newZone[Name]'].disabled = true;
|
//form.elements['newZone[Name]'].disabled = true;
|
||||||
|
@ -503,13 +706,37 @@ function initPage()
|
||||||
|
|
||||||
applyZoneType();
|
applyZoneType();
|
||||||
|
|
||||||
if ( form.elements['newZone[Units]'].value == 'Percent' )
|
if ( form.elements['newZone[Units]'].value == 'Percent' ) {
|
||||||
{
|
|
||||||
applyZoneUnits();
|
applyZoneUnits();
|
||||||
}
|
}
|
||||||
|
|
||||||
applyCheckMethod();
|
applyCheckMethod();
|
||||||
drawZonePoints();
|
drawZonePoints();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Imported from watch.js and modified for new zone edit view
|
||||||
|
//
|
||||||
|
|
||||||
|
if ( streamMode == "single" ) {
|
||||||
|
statusCmdTimer = statusCmdQuery.delay( (Math.random()+0.1)*statusRefreshTimeout );
|
||||||
|
watchdogCheck.pass('status').periodical(statusRefreshTimeout*2);
|
||||||
|
} else {
|
||||||
|
streamCmdTimer = streamCmdQuery.delay( (Math.random()+0.1)*statusRefreshTimeout );
|
||||||
|
watchdogCheck.pass('stream').periodical(statusRefreshTimeout*2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( canStreamNative || streamMode == "single" ) {
|
||||||
|
var streamImg = $('imageFrame').getElement('img');
|
||||||
|
if ( !streamImg )
|
||||||
|
streamImg = $('imageFrame').getElement('object');
|
||||||
|
if ( streamMode == "single" ) {
|
||||||
|
streamImg.addEvent( 'click', fetchImage.pass( streamImg ) );
|
||||||
|
fetchImage.pass( streamImg ).periodical( imageRefreshTimeout );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( refreshApplet && appletRefreshTime )
|
||||||
|
appletRefresh.delay( appletRefreshTime*1000 );
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEvent( 'domready', initPage );
|
window.addEvent( 'domready', initPage );
|
||||||
|
|
|
@ -65,3 +65,55 @@ var minBlobAreaLtMaxString = '<?php echo addslashes(translate('MinBlobAreaLtMax'
|
||||||
var minBlobLtMinFilterString = '<?php echo addslashes(translate('MinBlobLtMinFilter')) ?>';
|
var minBlobLtMinFilterString = '<?php echo addslashes(translate('MinBlobLtMinFilter')) ?>';
|
||||||
var minBlobsUnsetString = '<?php echo addslashes(translate('MinBlobsUnset')) ?>';
|
var minBlobsUnsetString = '<?php echo addslashes(translate('MinBlobsUnset')) ?>';
|
||||||
var minBlobsLtMaxString = '<?php echo addslashes(translate('MinBlobsLtMax')) ?>';
|
var minBlobsLtMaxString = '<?php echo addslashes(translate('MinBlobsLtMax')) ?>';
|
||||||
|
|
||||||
|
//
|
||||||
|
// Imported from watch.js.php and modified for new zone edit view
|
||||||
|
//
|
||||||
|
|
||||||
|
var STATE_IDLE = <?php echo STATE_IDLE ?>;
|
||||||
|
var STATE_PREALARM = <?php echo STATE_PREALARM ?>;
|
||||||
|
var STATE_ALARM = <?php echo STATE_ALARM ?>;
|
||||||
|
var STATE_ALERT = <?php echo STATE_ALERT ?>;
|
||||||
|
var STATE_TAPE = <?php echo STATE_TAPE ?>;
|
||||||
|
|
||||||
|
var stateStrings = new Array();
|
||||||
|
stateStrings[STATE_IDLE] = "<?php echo translate('Idle') ?>";
|
||||||
|
stateStrings[STATE_PREALARM] = "<?php echo translate('Idle') ?>";
|
||||||
|
stateStrings[STATE_ALARM] = "<?php echo translate('Alarm') ?>";
|
||||||
|
stateStrings[STATE_ALERT] = "<?php echo translate('Alert') ?>";
|
||||||
|
stateStrings[STATE_TAPE] = "<?php echo translate('Record') ?>";
|
||||||
|
|
||||||
|
var pauseString = "<?php echo translate('Pause') ?>";
|
||||||
|
var playString = "<?php echo translate('Play') ?>";
|
||||||
|
|
||||||
|
var deleteString = "<?php echo translate('Delete') ?>";
|
||||||
|
|
||||||
|
var CMD_PAUSE = <?php echo CMD_PAUSE ?>;
|
||||||
|
var CMD_PLAY = <?php echo CMD_PLAY ?>;
|
||||||
|
var CMD_STOP = <?php echo CMD_STOP ?>;
|
||||||
|
var CMD_QUERY = <?php echo CMD_QUERY ?>;
|
||||||
|
|
||||||
|
var SCALE_BASE = <?php echo SCALE_BASE ?>;
|
||||||
|
|
||||||
|
var SOUND_ON_ALARM = <?php echo ZM_WEB_SOUND_ON_ALARM ?>;
|
||||||
|
|
||||||
|
var streamMode = "<?php echo $streamMode ?>";
|
||||||
|
|
||||||
|
var connKey = '<?php echo $connkey ?>';
|
||||||
|
|
||||||
|
var monitorId = <?php echo $monitor->Id() ?>;
|
||||||
|
var monitorUrl = '<?php echo ( $monitor->Server()->Url() ) ?>';
|
||||||
|
|
||||||
|
var streamSrc = "<?php echo preg_replace( '/&/', '&', $streamSrc ) ?>";
|
||||||
|
|
||||||
|
var statusRefreshTimeout = <?php echo 1000*ZM_WEB_REFRESH_STATUS ?>;
|
||||||
|
var imageRefreshTimeout = <?php echo 1000*ZM_WEB_REFRESH_IMAGE ?>;
|
||||||
|
|
||||||
|
var canEditMonitors = <?php echo canEdit( 'Monitors' )?'true':'false' ?>;
|
||||||
|
var canStreamNative = <?php echo canStreamNative()?'true':'false' ?>;
|
||||||
|
|
||||||
|
var canPlayPauseAudio = Browser.ie;
|
||||||
|
|
||||||
|
var refreshApplet = <?php echo (canStreamApplet() && $streamMode == "jpeg")?'true':'false' ?>;
|
||||||
|
var appletRefreshTime = <?php echo ZM_RELOAD_CAMBOZOLA ?>;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
var streamCmdParms = "view=request&request=stream&connkey="+connKey;
|
||||||
|
var streamCmdReq = new Request.JSON( { url: monitorUrl+thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel' } );
|
||||||
|
|
||||||
|
function streamCmdQuit( action ) {
|
||||||
|
if ( action )
|
||||||
|
streamCmdReq.send( streamCmdParms+"&command="+CMD_QUIT );
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
var connKey = '<?php echo $connkey ?>';
|
||||||
|
var monitorUrl = '<?php echo ( $monitor->Server()->Url() ) ?>';
|
||||||
|
var CMD_QUIT = <?php echo CMD_QUIT ?>;
|
||||||
|
|
|
@ -58,6 +58,13 @@ if ( ! empty($_REQUEST['mid']) ) {
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
$nextId = getTableAutoInc( 'Monitors' );
|
$nextId = getTableAutoInc( 'Monitors' );
|
||||||
|
if ( ! empty( $_REQUEST['dupId'] ) ) {
|
||||||
|
$monitor = new Monitor( $_REQUEST['dupId'] );
|
||||||
|
if ( ZM_OPT_X10 )
|
||||||
|
$x10Monitor = dbFetchOne( 'SELECT * FROM TriggersX10 WHERE MonitorId = ?', NULL, array($_REQUEST['dupId']) );
|
||||||
|
$clonedName = $monitor->Name();
|
||||||
|
$monitor->Name( translate('Monitor').'-'.$nextId );
|
||||||
|
} else {
|
||||||
$monitor = new Monitor();
|
$monitor = new Monitor();
|
||||||
$monitor->set( array(
|
$monitor->set( array(
|
||||||
'Id' => 0,
|
'Id' => 0,
|
||||||
|
@ -131,7 +138,8 @@ if ( ! empty($_REQUEST['mid']) ) {
|
||||||
'ServerId' => $Server['Id'],
|
'ServerId' => $Server['Id'],
|
||||||
'StorageId' => '',
|
'StorageId' => '',
|
||||||
) );
|
) );
|
||||||
}
|
} # end if $_REQUEST['dupID']
|
||||||
|
} # end if $_REQUEST['mid']
|
||||||
|
|
||||||
if ( ZM_OPT_X10 && empty($x10Monitor) ) {
|
if ( ZM_OPT_X10 && empty($x10Monitor) ) {
|
||||||
$x10Monitor = array(
|
$x10Monitor = array(
|
||||||
|
@ -143,6 +151,7 @@ if ( ZM_OPT_X10 && empty($x10Monitor) ) {
|
||||||
|
|
||||||
function fourcc( $a, $b, $c, $d ) {
|
function fourcc( $a, $b, $c, $d ) {
|
||||||
return( ord($a) | (ord($b) << 8) | (ord($c) << 16) | (ord($d) << 24) );
|
return( ord($a) | (ord($b) << 8) | (ord($c) << 16) | (ord($d) << 24) );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isset( $_REQUEST['newMonitor'] ) ) {
|
if ( isset( $_REQUEST['newMonitor'] ) ) {
|
||||||
|
@ -455,23 +464,22 @@ $videowriteropts = array(
|
||||||
xhtmlHeaders(__FILE__, translate('Monitor')." - ".validHtmlStr($monitor->Name) );
|
xhtmlHeaders(__FILE__, translate('Monitor')." - ".validHtmlStr($monitor->Name) );
|
||||||
?>
|
?>
|
||||||
<body>
|
<body>
|
||||||
<div id="page">
|
<div id="page">
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<?php if ( canEdit( 'Monitors' ) ) { ?>
|
<?php if ( canEdit( 'Monitors' ) ) { ?>
|
||||||
|
<?php if ( isset ($_REQUEST['dupId'])) { ?>
|
||||||
|
<div class="alert alert-info">
|
||||||
|
Configuration cloned from Monitor: <?php echo $clonedName ?>
|
||||||
|
</div>
|
||||||
|
<?php } ?>
|
||||||
<div id="headerButtons">
|
<div id="headerButtons">
|
||||||
<a href="#" onclick="createPopup( '?view=monitorprobe&mid=<?php echo $monitor->Id ?>', 'zmMonitorProbe<?php echo $monitor->Id ?>', 'monitorprobe' ); return( false );"><?php echo translate('Probe') ?></a>
|
<a href="#" onclick="createPopup( '?view=monitorprobe&mid=<?php echo $monitor->Id ?>', 'zmMonitorProbe<?php echo $monitor->Id ?>', 'monitorprobe' ); return( false );"><?php echo translate('Probe') ?></a>
|
||||||
<?php
|
<?php if ( ZM_HAS_ONVIF ) { ?>
|
||||||
if ( ZM_HAS_ONVIF ) {
|
|
||||||
?>
|
|
||||||
<a href="#" onclick="createPopup( '?view=onvifprobe&mid=<?php echo $monitor->Id ?>', 'zmOnvifProbe<?php echo $monitor->Id ?>', 'onvifprobe' ); return( false );"><?php echo translate('OnvifProbe') ?></a>
|
<a href="#" onclick="createPopup( '?view=onvifprobe&mid=<?php echo $monitor->Id ?>', 'zmOnvifProbe<?php echo $monitor->Id ?>', 'onvifprobe' ); return( false );"><?php echo translate('OnvifProbe') ?></a>
|
||||||
<?php
|
<?php } ?>
|
||||||
}
|
|
||||||
?>
|
|
||||||
<a href="#" onclick="createPopup( '?view=monitorpreset&mid=<?php echo $monitor->Id ?>', 'zmMonitorPreset<?php echo $monitor->Id ?>', 'monitorpreset' ); return( false );"><?php echo translate('Presets') ?></a>
|
<a href="#" onclick="createPopup( '?view=monitorpreset&mid=<?php echo $monitor->Id ?>', 'zmMonitorPreset<?php echo $monitor->Id ?>', 'monitorpreset' ); return( false );"><?php echo translate('Presets') ?></a>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php } ?>
|
||||||
}
|
|
||||||
?>
|
|
||||||
<h2><?php echo translate('Monitor') ?> - <?php echo validHtmlStr($monitor->Name) ?><?php if ( !empty($monitor->Id) ) { ?> (<?php echo $monitor->Id ?>)<?php } ?></h2>
|
<h2><?php echo translate('Monitor') ?> - <?php echo validHtmlStr($monitor->Name) ?><?php if ( !empty($monitor->Id) ) { ?> (<?php echo $monitor->Id ?>)<?php } ?></h2>
|
||||||
</div>
|
</div>
|
||||||
<div id="content">
|
<div id="content">
|
||||||
|
@ -717,21 +725,21 @@ switch ( $tab )
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr><td><?php echo translate('AnalysisFPS') ?></td><td><input type="text" name="newMonitor[AnalysisFPS]" value="<?php echo validHtmlStr($monitor->AnalysisFPS) ?>" size="6"/></td></tr>
|
<tr><td><?php echo translate('AnalysisFPS') ?></td><td><input type="text" name="newMonitor[AnalysisFPS]" value="<?php echo validHtmlStr($monitor->AnalysisFPS) ?>" size="6"/></td></tr>
|
||||||
<?php
|
<?php if ( $monitor->Type != "Local" && $monitor->Type != "File" ) { ?>
|
||||||
if ( $monitor->Type != "Local" && $monitor->Type != "File" )
|
<tr>
|
||||||
{
|
<td><?php echo translate('MaximumFPS') ?> (<?php echo makePopupLink('?view=optionhelp&option=OPTIONS_MAXFPS', 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td>
|
||||||
?>
|
<td><input type="text" onclick="document.getElementById('newMonitor[MaxFPS]').innerHTML= ' CAUTION: See the help text'" name="newMonitor[MaxFPS]" value="<?php echo validHtmlStr($monitor->MaxFPS) ?>" size="5"/><span id="newMonitor[MaxFPS]" style="color:red"></span></td>
|
||||||
<tr><td><?php echo translate('MaximumFPS') ?> (<?php echo makePopupLink('?view=optionhelp&option=OPTIONS_MAXFPS', 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td><td><input type="text" onclick="document.getElementById('newMonitor[MaxFPS]').innerHTML= ' CAUTION: See the help text'" name="newMonitor[MaxFPS]" value="<?php echo validHtmlStr($monitor->MaxFPS) ?>" size="5"/><span id="newMonitor[MaxFPS]" style="color:red"></span></td></tr>
|
</tr>
|
||||||
<tr><td><?php echo translate('AlarmMaximumFPS') ?> (<?php echo makePopupLink('?view=optionhelp&option=OPTIONS_MAXFPS', 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td><td><input type="text" onclick="document.getElementById('newMonitor[AlarmMaxFPS]').innerHTML= ' CAUTION: See the help text'" name="newMonitor[AlarmMaxFPS]" value="<?php echo validHtmlStr($monitor->AlarmMaxFPS) ?>" size="5"/><span id="newMonitor[AlarmMaxFPS]" style="color:red"></span></td></tr>
|
<tr>
|
||||||
<?php
|
<td><?php echo translate('AlarmMaximumFPS') ?> (<?php echo makePopupLink('?view=optionhelp&option=OPTIONS_MAXFPS', 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td>
|
||||||
} else {
|
<td><input type="text" onclick="document.getElementById('newMonitor[AlarmMaxFPS]').innerHTML= ' CAUTION: See the help text'" name="newMonitor[AlarmMaxFPS]" value="<?php echo validHtmlStr($monitor->AlarmMaxFPS) ?>" size="5"/><span id="newMonitor[AlarmMaxFPS]" style="color:red"></span></td>
|
||||||
?>
|
</tr>
|
||||||
|
<?php } else { ?>
|
||||||
<tr><td><?php echo translate('MaximumFPS') ?></td><td><input type="text" name="newMonitor[MaxFPS]" value="<?php echo validHtmlStr($monitor->MaxFPS) ?>" size="5"/></td></tr>
|
<tr><td><?php echo translate('MaximumFPS') ?></td><td><input type="text" name="newMonitor[MaxFPS]" value="<?php echo validHtmlStr($monitor->MaxFPS) ?>" size="5"/></td></tr>
|
||||||
<tr><td><?php echo translate('AlarmMaximumFPS') ?></td><td><input type="text" name="newMonitor[AlarmMaxFPS]" value="<?php echo validHtmlStr($monitor->AlarmMaxFPS) ?>" size="5"/></td></tr>
|
<tr><td><?php echo translate('AlarmMaximumFPS') ?></td><td><input type="text" name="newMonitor[AlarmMaxFPS]" value="<?php echo validHtmlStr($monitor->AlarmMaxFPS) ?>" size="5"/></td></tr>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
if ( ZM_FAST_IMAGE_BLENDS )
|
if ( ZM_FAST_IMAGE_BLENDS ) {
|
||||||
{
|
|
||||||
?>
|
?>
|
||||||
<tr><td><?php echo translate('RefImageBlendPct') ?></td><td><select name="newMonitor[RefBlendPerc]"><?php foreach ( $fastblendopts as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->RefBlendPerc ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
|
<tr><td><?php echo translate('RefImageBlendPct') ?></td><td><select name="newMonitor[RefBlendPerc]"><?php foreach ( $fastblendopts as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->RefBlendPerc ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
|
||||||
<tr><td><?php echo translate('AlmRefImageBlendPct') ?></td><td><select name="newMonitor[AlarmRefBlendPerc]"><?php foreach ( $fastblendopts_alarm as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->AlarmRefBlendPerc ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
|
<tr><td><?php echo translate('AlmRefImageBlendPct') ?></td><td><select name="newMonitor[AlarmRefBlendPerc]"><?php foreach ( $fastblendopts_alarm as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->AlarmRefBlendPerc ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
|
||||||
|
@ -970,13 +978,14 @@ switch ( $tab )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div id="contentButtons">
|
<div id="contentButtons">
|
||||||
<input type="submit" value="<?php echo translate('Save') ?>"<?php if ( !canEdit( 'Monitors' ) ) { ?> disabled="disabled"<?php } ?>/><input type="button" value="<?php echo translate('Cancel') ?>" onclick="closeWindow()"/>
|
<input type="submit" value="<?php echo translate('Save') ?>"<?php if ( !canEdit( 'Monitors' ) ) { ?> disabled="disabled"<?php } ?>/><input type="button" value="<?php echo translate('Cancel') ?>" onclick="closeWindow()"/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
</div>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -115,7 +115,10 @@ if ( canEdit( 'Monitors' ) )
|
||||||
if ( canEdit( 'Monitors' ) )
|
if ( canEdit( 'Monitors' ) )
|
||||||
{
|
{
|
||||||
?>
|
?>
|
||||||
<div id="forceCancelAlarm"><a id="forceAlarmLink" href="#" onclick="cmdForceAlarm()" class="hidden"><?php echo translate('ForceAlarm') ?></a><a id="cancelAlarmLink" href="#" onclick="cmdCancelForcedAlarm()" class="hidden"><?php echo translate('CancelForcedAlarm') ?></a></div>
|
<div id="forceCancelAlarm">
|
||||||
|
<a id="forceAlarmLink" href="#" onclick="cmdForceAlarm();"><?php echo translate('ForceAlarm') ?></a>
|
||||||
|
<a id="cancelAlarmLink" href="#" onclick="cmdCancelForcedAlarm();" class="hidden"><?php echo translate('CancelForcedAlarm') ?></a>
|
||||||
|
</div>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -117,6 +117,11 @@ $newZone['Area'] = getPolyArea( $newZone['Points'] );
|
||||||
$selfIntersecting = isSelfIntersecting( $newZone['Points'] );
|
$selfIntersecting = isSelfIntersecting( $newZone['Points'] );
|
||||||
|
|
||||||
$focusWindow = true;
|
$focusWindow = true;
|
||||||
|
$connkey = generateConnKey();
|
||||||
|
$streamSrc = '';
|
||||||
|
$streamMode = '';
|
||||||
|
# Have to do this here, because the .js.php references somethings figured out when generating the streamHTML
|
||||||
|
$StreamHTML = getStreamHTML( $monitor, $scale );
|
||||||
|
|
||||||
xhtmlHeaders(__FILE__, translate('Zone') );
|
xhtmlHeaders(__FILE__, translate('Zone') );
|
||||||
?>
|
?>
|
||||||
|
@ -210,13 +215,14 @@ xhtmlHeaders(__FILE__, translate('Zone') );
|
||||||
<div id="definitionPanel">
|
<div id="definitionPanel">
|
||||||
<div id="imagePanel">
|
<div id="imagePanel">
|
||||||
<div id="imageFrame" style="width: <?php echo reScale( $monitor->Width(), $scale ) ?>px; height: <?php echo reScale( $monitor->Height(), $scale ) ?>px;">
|
<div id="imageFrame" style="width: <?php echo reScale( $monitor->Width(), $scale ) ?>px; height: <?php echo reScale( $monitor->Height(), $scale ) ?>px;">
|
||||||
<?php echo getStreamHTML( $monitor, $scale ); ?>
|
<?php $StreamHTML; ?>
|
||||||
<svg id="zoneSVG" class="zones" style="width: <?php echo reScale( $monitor->Width(), $scale ) ?>px; height: <?php echo reScale( $monitor->Height(), $scale ) ?>px;margin-top: -<?php echo $monitor->Height ?>px;background: none;">
|
<svg id="zoneSVG" class="zones" style="width: <?php echo reScale( $monitor->Width(), $scale ) ?>px; height: <?php echo reScale( $monitor->Height(), $scale ) ?>px;margin-top: -<?php echo $monitor->Height ?>px;background: none;">
|
||||||
<polygon id="zonePoly" points="<?php echo $zone['AreaCoords'] ?>" class="<?php echo $zone['Type'] ?>"/>
|
<polygon id="zonePoly" points="<?php echo $zone['AreaCoords'] ?>" class="<?php echo $zone['Type'] ?>"/>
|
||||||
Sorry, your browser does not support inline SVG
|
Sorry, your browser does not support inline SVG
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="monitorState"><?php echo translate('State') ?>: <span id="stateValue"></span> - <span id="fpsValue"></span> fps</div>
|
||||||
<table id="zonePoints" cellspacing="0">
|
<table id="zonePoints" cellspacing="0">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -265,7 +271,7 @@ for ( $i = 0; $i < $pointCols; $i++ )
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<input type="submit" id="submitBtn" name="submitBtn" value="<?php echo translate('Save') ?>" onclick="return saveChanges( this )"<?php if (!canEdit( 'Monitors' ) || (false && $selfIntersecting)) { ?> disabled="disabled"<?php } ?>/><input type="button" value="<?php echo translate('Cancel') ?>" onclick="closeWindow()"/>
|
<input id="pauseBtn" type="button" value="<?php echo translate('Pause') ?>" onclick="streamCmdPauseToggle()"/><input type="submit" id="submitBtn" name="submitBtn" value="<?php echo translate('Save') ?>" onclick="return saveChanges( this )"<?php if (!canEdit( 'Monitors' ) || (false && $selfIntersecting)) { ?> disabled="disabled"<?php } ?>/><input type="button" value="<?php echo translate('Cancel') ?>" onclick="refreshParentWindow(); closeWindow();"/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -37,6 +37,8 @@ foreach( dbFetchAll( 'select * from Zones where MonitorId = ? order by Area desc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$connkey = generateConnKey();
|
||||||
|
|
||||||
xhtmlHeaders(__FILE__, translate('Zones') );
|
xhtmlHeaders(__FILE__, translate('Zones') );
|
||||||
?>
|
?>
|
||||||
<body>
|
<body>
|
||||||
|
@ -51,7 +53,7 @@ xhtmlHeaders(__FILE__, translate('Zones') );
|
||||||
<?php
|
<?php
|
||||||
foreach( array_reverse($zones) as $zone ) {
|
foreach( array_reverse($zones) as $zone ) {
|
||||||
?>
|
?>
|
||||||
<polygon points="<?php echo $zone['AreaCoords'] ?>" class="<?php echo $zone['Type']?>" onclick="createPopup( '?view=zone&mid=<?php echo $mid ?>&zid=<?php echo $zone['Id'] ?>', 'zmZone', 'zone', <?php echo $monitor->Width ?>, <?php echo $monitor->Height ?> ); return( false );"/>
|
<polygon points="<?php echo $zone['AreaCoords'] ?>" class="<?php echo $zone['Type']?>" onclick="streamCmdQuit( true ); createPopup( '?view=zone&mid=<?php echo $mid ?>&zid=<?php echo $zone['Id'] ?>', 'zmZone', 'zone', <?php echo $monitor->Width ?>, <?php echo $monitor->Height ?> ); return( false );"/>
|
||||||
<?php
|
<?php
|
||||||
} // end foreach zone
|
} // end foreach zone
|
||||||
?>
|
?>
|
||||||
|
@ -76,7 +78,7 @@ foreach( $zones as $zone )
|
||||||
{
|
{
|
||||||
?>
|
?>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="colName"><a href="#" onclick="createPopup( '?view=zone&mid=<?php echo $mid ?>&zid=<?php echo $zone['Id'] ?>', 'zmZone', 'zone', <?php echo $monitor->Width() ?>, <?php echo $monitor->Height() ?> ); return( false );"><?php echo $zone['Name'] ?></a></td>
|
<td class="colName"><a href="#" onclick="streamCmdQuit( true ); createPopup( '?view=zone&mid=<?php echo $mid ?>&zid=<?php echo $zone['Id'] ?>', 'zmZone', 'zone', <?php echo $monitor->Width() ?>, <?php echo $monitor->Height() ?> ); return( false );"><?php echo $zone['Name'] ?></a></td>
|
||||||
<td class="colType"><?php echo $zone['Type'] ?></td>
|
<td class="colType"><?php echo $zone['Type'] ?></td>
|
||||||
<td class="colUnits"><?php echo $zone['Area'] ?> / <?php echo sprintf( "%.2f", ($zone['Area']*100)/($monitor->Width()*$monitor->Height()) ) ?></td>
|
<td class="colUnits"><?php echo $zone['Area'] ?> / <?php echo sprintf( "%.2f", ($zone['Area']*100)/($monitor->Width()*$monitor->Height()) ) ?></td>
|
||||||
<td class="colMark"><input type="checkbox" name="markZids[]" value="<?php echo $zone['Id'] ?>" onclick="configureDeleteButton( this );"<?php if ( !canEdit( 'Monitors' ) ) { ?> disabled="disabled"<?php } ?>/></td>
|
<td class="colMark"><input type="checkbox" name="markZids[]" value="<?php echo $zone['Id'] ?>" onclick="configureDeleteButton( this );"<?php if ( !canEdit( 'Monitors' ) ) { ?> disabled="disabled"<?php } ?>/></td>
|
||||||
|
|
|
@ -40,6 +40,7 @@ if ( !canView( 'Events' ) )
|
||||||
|
|
||||||
require_once('includes/Storage.php');
|
require_once('includes/Storage.php');
|
||||||
require_once('includes/Event.php');
|
require_once('includes/Event.php');
|
||||||
|
require_once('includes/Frame.php');
|
||||||
|
|
||||||
header( 'Content-type: image/jpeg' );
|
header( 'Content-type: image/jpeg' );
|
||||||
|
|
||||||
|
@ -67,6 +68,12 @@ if ( empty($_REQUEST['path']) )
|
||||||
$Event = new Event( $_REQUEST['eid'] );
|
$Event = new Event( $_REQUEST['eid'] );
|
||||||
$Storage = $Event->Storage();
|
$Storage = $Event->Storage();
|
||||||
$path = $Event->Relative_Path().'/'.sprintf("%'.0".ZM_EVENT_IMAGE_DIGITS.'d',$_REQUEST['fid']).'-capture.jpg';
|
$path = $Event->Relative_Path().'/'.sprintf("%'.0".ZM_EVENT_IMAGE_DIGITS.'d',$_REQUEST['fid']).'-capture.jpg';
|
||||||
|
} 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'] );
|
||||||
|
$Event = new Event( $Frame->EventId() );
|
||||||
|
$Storage = $Event->Storage();
|
||||||
|
$path = $Event->Relative_Path().'/'.sprintf("%'.0".ZM_EVENT_IMAGE_DIGITS.'d',$Frame->FrameId()).'-capture.jpg';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$errorText = "No image path";
|
$errorText = "No image path";
|
||||||
|
|
Loading…
Reference in New Issue