Merge branch 'master' of github.com:ZoneMinder/zoneminder
This commit is contained in:
commit
b4511a8fc3
|
@ -167,6 +167,8 @@ set(ZM_NO_X10 "OFF" CACHE BOOL
|
|||
set(ZM_ONVIF "ON" CACHE BOOL
|
||||
"Set to ON to enable basic ONVIF support. This is EXPERIMENTAL and may not
|
||||
work with all cameras claiming to be ONVIF compliant. default: ON")
|
||||
set(ZM_NO_PCRE "OFF" CACHE BOOL
|
||||
"Set to ON to skip libpcre3 checks and force building ZM without libpcre3. default: OFF")
|
||||
set(ZM_NO_RTSPSERVER "OFF" CACHE BOOL
|
||||
"Set to ON to skip building ZM with rtsp server support. default: OFF")
|
||||
set(ZM_PERL_MM_PARMS INSTALLDIRS=vendor NO_PACKLIST=1 NO_PERLLOCAL=1 CACHE STRING
|
||||
|
@ -407,6 +409,8 @@ else()
|
|||
message(FATAL_ERROR "ZoneMinder requires pthread but it was not found on your system")
|
||||
endif()
|
||||
|
||||
# Do not check for cURL if ZM_NO_CURL is on
|
||||
if(NOT ZM_NO_PRCE)
|
||||
# pcre (using find_library and find_path)
|
||||
find_library(PCRE_LIBRARIES pcre)
|
||||
if(PCRE_LIBRARIES)
|
||||
|
@ -423,6 +427,7 @@ if(PCRE_LIBRARIES)
|
|||
else()
|
||||
set(optlibsnotfound "${optlibsnotfound} PCRE")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# mysqlclient (using find_library and find_path)
|
||||
find_library(MYSQLCLIENT_LIBRARIES mysqlclient PATH_SUFFIXES mysql)
|
||||
|
@ -540,6 +545,7 @@ set(ZM_PCRE 0)
|
|||
if(HAVE_LIBPCRE AND HAVE_PCRE_H)
|
||||
set(ZM_PCRE 1)
|
||||
endif()
|
||||
|
||||
# Check for mmap and enable in all components
|
||||
set(ZM_MEM_MAPPED 0)
|
||||
set(ENABLE_MMAP no)
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
# FindFmt
|
||||
# -------
|
||||
# Finds the Fmt library
|
||||
#
|
||||
# This will define the following variables::
|
||||
#
|
||||
# FMT_FOUND - system has Fmt
|
||||
# FMT_INCLUDE_DIRS - the Fmt include directory
|
||||
# FMT_LIBRARIES - the Fmt libraries
|
||||
#
|
||||
# and the following imported targets::
|
||||
#
|
||||
# Fmt::Fmt - The Fmt library
|
||||
|
||||
if(ENABLE_INTERNAL_FMT)
|
||||
include(ExternalProject)
|
||||
file(STRINGS ${CMAKE_SOURCE_DIR}/tools/depends/target/libfmt/Makefile VER REGEX "^[ ]*VERSION[ ]*=.+$")
|
||||
string(REGEX REPLACE "^[ ]*VERSION[ ]*=[ ]*" "" FMT_VERSION "${VER}")
|
||||
|
||||
# allow user to override the download URL with a local tarball
|
||||
# needed for offline build envs
|
||||
if(FMT_URL)
|
||||
get_filename_component(FMT_URL "${FMT_URL}" ABSOLUTE)
|
||||
else()
|
||||
set(FMT_URL http://mirrors.kodi.tv/build-deps/sources/fmt-${FMT_VERSION}.tar.gz)
|
||||
endif()
|
||||
if(VERBOSE)
|
||||
message(STATUS "FMT_URL: ${FMT_URL}")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(EXTRA_ARGS "-DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}")
|
||||
endif()
|
||||
|
||||
set(FMT_LIBRARY ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/lib/libfmt.a)
|
||||
set(FMT_INCLUDE_DIR ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/include)
|
||||
externalproject_add(fmt
|
||||
URL ${FMT_URL}
|
||||
DOWNLOAD_DIR ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/download
|
||||
PREFIX ${CORE_BUILD_DIR}/fmt
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}
|
||||
-DCMAKE_CXX_EXTENSIONS=${CMAKE_CXX_EXTENSIONS}
|
||||
-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}
|
||||
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
|
||||
-DCMAKE_INSTALL_LIBDIR=lib
|
||||
-DFMT_DOC=OFF
|
||||
-DFMT_TEST=OFF
|
||||
"${EXTRA_ARGS}"
|
||||
BUILD_BYPRODUCTS ${FMT_LIBRARY})
|
||||
set_target_properties(fmt PROPERTIES FOLDER "External Projects")
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Fmt
|
||||
REQUIRED_VARS FMT_LIBRARY FMT_INCLUDE_DIR
|
||||
VERSION_VAR FMT_VERSION)
|
||||
|
||||
set(FMT_LIBRARIES ${FMT_LIBRARY})
|
||||
set(FMT_INCLUDE_DIRS ${FMT_INCLUDE_DIR})
|
||||
|
||||
else()
|
||||
|
||||
find_package(FMT 6.1.2 CONFIG REQUIRED QUIET)
|
||||
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PC_FMT libfmt QUIET)
|
||||
if(PC_FMT_VERSION AND NOT FMT_VERSION)
|
||||
set(FMT_VERSION ${PC_FMT_VERSION})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_path(FMT_INCLUDE_DIR NAMES fmt/format.h
|
||||
PATHS ${PC_FMT_INCLUDEDIR})
|
||||
|
||||
find_library(FMT_LIBRARY_RELEASE NAMES fmt
|
||||
PATHS ${PC_FMT_LIBDIR})
|
||||
find_library(FMT_LIBRARY_DEBUG NAMES fmtd
|
||||
PATHS ${PC_FMT_LIBDIR})
|
||||
|
||||
include(SelectLibraryConfigurations)
|
||||
select_library_configurations(FMT)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Fmt
|
||||
REQUIRED_VARS FMT_LIBRARY FMT_INCLUDE_DIR FMT_VERSION
|
||||
VERSION_VAR FMT_VERSION)
|
||||
|
||||
if(FMT_FOUND)
|
||||
set(FMT_LIBRARIES ${FMT_LIBRARY})
|
||||
set(FMT_INCLUDE_DIRS ${FMT_INCLUDE_DIR})
|
||||
|
||||
if(NOT TARGET fmt)
|
||||
add_library(fmt UNKNOWN IMPORTED)
|
||||
set_target_properties(fmt PROPERTIES
|
||||
IMPORTED_LOCATION "${FMT_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${FMT_INCLUDE_DIR}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endif()
|
||||
mark_as_advanced(FMT_INCLUDE_DIR FMT_LIBRARY)
|
|
@ -456,6 +456,8 @@ CREATE TABLE `Monitors` (
|
|||
`DecodingEnabled` tinyint(3) unsigned NOT NULL default '1',
|
||||
`LinkedMonitors` varchar(255),
|
||||
`Triggers` set('X10') NOT NULL default '',
|
||||
`EventStartCommand` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`EventEndCommand` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`ONVIF_URL` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`ONVIF_Username` VARCHAR(64) NOT NULL DEFAULT '',
|
||||
`ONVIF_Password` VARCHAR(64) NOT NULL DEFAULT '',
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
--
|
||||
-- This update adds EventStartCommand and EventEndCommand
|
||||
--
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE table_name = 'Monitors'
|
||||
AND table_schema = DATABASE()
|
||||
AND column_name = 'EventEndCommand'
|
||||
) > 0,
|
||||
"SELECT 'Column EventEndCommand already exists in Monitors'",
|
||||
"ALTER TABLE `Monitors` ADD COLUMN `EventEndCommand` VARCHAR(255) NOT NULL DEFAULT '' AFTER `Triggers`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE table_name = 'Monitors'
|
||||
AND table_schema = DATABASE()
|
||||
AND column_name = 'EventStartCommand'
|
||||
) > 0,
|
||||
"SELECT 'Column EventStartCommand already exists in Monitors'",
|
||||
"ALTER TABLE `Monitors` ADD COLUMN `EventStartCommand` VARCHAR(255) NOT NULL DEFAULT '' AFTER `Triggers`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
|
@ -36,7 +36,7 @@
|
|||
%global _hardened_build 1
|
||||
|
||||
Name: zoneminder
|
||||
Version: 1.37.3
|
||||
Version: 1.37.5
|
||||
Release: 1%{?dist}
|
||||
Summary: A camera monitoring and analysis tool
|
||||
Group: System Environment/Daemons
|
||||
|
|
|
@ -16,7 +16,6 @@ Build-Depends: debhelper (>= 11), sphinx-doc, python3-sphinx, dh-linktree, dh-ap
|
|||
,libjpeg-turbo8-dev | libjpeg62-turbo-dev | libjpeg8-dev | libjpeg9-dev
|
||||
,libturbojpeg0-dev
|
||||
,default-libmysqlclient-dev | libmysqlclient-dev | libmariadbclient-dev-compat
|
||||
,libpcre3-dev
|
||||
,libpolkit-gobject-1-dev
|
||||
,libv4l-dev [!hurd-any]
|
||||
,libvlc-dev
|
||||
|
@ -70,7 +69,6 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
|
|||
,policykit-1
|
||||
,rsyslog | system-log-daemon
|
||||
,zip
|
||||
,libpcre3
|
||||
,libcrypt-eksblowfish-perl
|
||||
,libdata-entropy-perl
|
||||
,libvncclient1|libvncclient0
|
||||
|
|
|
@ -19,6 +19,7 @@ override_dh_auto_configure:
|
|||
-DCMAKE_VERBOSE_MAKEFILE=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DBUILD_MAN=0 \
|
||||
-DZM_NO_PCRE=ON \
|
||||
-DZM_CONFIG_DIR="/etc/zm" \
|
||||
-DZM_CONFIG_SUBDIR="/etc/zm/conf.d" \
|
||||
-DZM_RUNDIR="/run/zm" \
|
||||
|
|
|
@ -4,7 +4,7 @@ Debian
|
|||
.. contents::
|
||||
|
||||
Easy Way: Debian 11 (Bullseye)
|
||||
------------------------
|
||||
------------------------------
|
||||
|
||||
This procedure will guide you through the installation of ZoneMinder on Debian 11 (Bullseye).
|
||||
|
||||
|
@ -104,7 +104,7 @@ Add the following to the /etc/apt/sources.list.d/zoneminder.list file
|
|||
|
||||
You can do this using:
|
||||
|
||||
.. code-block::
|
||||
::
|
||||
|
||||
echo "deb https://zmrepo.zoneminder.com/debian/release-1.36 buster/" | sudo tee /etc/apt/sources.list.d/zoneminder.list
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ require Date::Parse;
|
|||
require POSIX;
|
||||
use Date::Format qw(time2str);
|
||||
use Time::HiRes qw(gettimeofday tv_interval stat);
|
||||
use Scalar::Util qw(looks_like_number);
|
||||
|
||||
#our @ISA = qw(ZoneMinder::Object);
|
||||
use parent qw(ZoneMinder::Object);
|
||||
|
@ -601,7 +602,7 @@ sub CopyTo {
|
|||
# First determine if we can move it to the dest.
|
||||
# We do this before bothering to lock the event
|
||||
my ( $NewPath ) = ( $NewStorage->Path() =~ /^(.*)$/ ); # De-taint
|
||||
if ( ! $$NewStorage{Id} ) {
|
||||
if ( ! looks_like_number($$NewStorage{Id}) ) {
|
||||
return 'New storage does not have an id. Moving will not happen.';
|
||||
} elsif ( $$NewStorage{Id} == $$self{StorageId} ) {
|
||||
return 'Event is already located at ' . $NewPath;
|
||||
|
@ -733,19 +734,22 @@ sub MoveTo {
|
|||
|
||||
my $was_in_transaction = !$ZoneMinder::Database::dbh->{AutoCommit};
|
||||
$ZoneMinder::Database::dbh->begin_work() if !$was_in_transaction;
|
||||
$self->lock_and_load(); # The fact that we are in a transaction might not imply locking
|
||||
if (!$self->lock_and_load()) {
|
||||
Warning('Unable to lock event record '.$$self{Id}); # The fact that we are in a transaction might not imply locking
|
||||
$ZoneMinder::Database::dbh->commit() if !$was_in_transaction;
|
||||
return 'Unable to lock event record';
|
||||
}
|
||||
|
||||
my $OldStorage = $self->Storage(undef);
|
||||
|
||||
my $error = $self->CopyTo($NewStorage);
|
||||
return $error if $error;
|
||||
|
||||
if (!$error) {
|
||||
# Succeeded in copying all files, so we may now update the Event.
|
||||
$$self{StorageId} = $$NewStorage{Id};
|
||||
$self->Storage($NewStorage);
|
||||
$error .= $self->save();
|
||||
|
||||
# Going to leave it to upper layer as to whether we rollback or not
|
||||
}
|
||||
$ZoneMinder::Database::dbh->commit() if !$was_in_transaction;
|
||||
return $error if $error;
|
||||
|
||||
|
|
|
@ -230,8 +230,8 @@ sub Sql {
|
|||
# PostCondition, so no further SQL
|
||||
} else {
|
||||
( my $stripped_value = $value ) =~ s/^["\']+?(.+)["\']+?$/$1/;
|
||||
foreach my $temp_value ( split( /["'\s]*?,["'\s]*?/, $stripped_value ) ) {
|
||||
|
||||
# Empty value will result in () from split
|
||||
foreach my $temp_value ( $stripped_value ? split( /["'\s]*?,["'\s]*?/, $stripped_value ) : $stripped_value ) {
|
||||
if ( $term->{attr} eq 'AlarmedZoneId' ) {
|
||||
$value = '(SELECT * FROM Stats WHERE EventId=E.Id AND Score > 0 AND ZoneId='.$value.')';
|
||||
} elsif ( $term->{attr} =~ /^MonitorName/ ) {
|
||||
|
@ -250,7 +250,8 @@ sub Sql {
|
|||
$$self{Server} = new ZoneMinder::Server($temp_value);
|
||||
}
|
||||
} elsif ( $term->{attr} eq 'StorageId' ) {
|
||||
$value = "'$temp_value'";
|
||||
# Empty means NULL, otherwise must be an integer
|
||||
$value = $temp_value ne '' ? int($temp_value) : 'NULL';
|
||||
$$self{Storage} = new ZoneMinder::Storage($temp_value);
|
||||
} elsif ( $term->{attr} eq 'Name'
|
||||
|| $term->{attr} eq 'Cause'
|
||||
|
|
|
@ -42,6 +42,7 @@ our @ISA = qw(Exporter ZoneMinder::Base);
|
|||
# will save memory.
|
||||
our %EXPORT_TAGS = (
|
||||
constants => [ qw(
|
||||
STATE_UNKNOWN
|
||||
STATE_IDLE
|
||||
STATE_PREALARM
|
||||
STATE_ALARM
|
||||
|
@ -98,11 +99,12 @@ our $VERSION = $ZoneMinder::Base::VERSION;
|
|||
use ZoneMinder::Config qw(:all);
|
||||
use ZoneMinder::Logger qw(:all);
|
||||
|
||||
use constant STATE_IDLE => 0;
|
||||
use constant STATE_PREALARM => 1;
|
||||
use constant STATE_ALARM => 2;
|
||||
use constant STATE_ALERT => 3;
|
||||
use constant STATE_TAPE => 4;
|
||||
use constant STATE_UNKNOWN => 0;
|
||||
use constant STATE_IDLE => 1;
|
||||
use constant STATE_PREALARM => 2;
|
||||
use constant STATE_ALARM => 3;
|
||||
use constant STATE_ALERT => 4;
|
||||
use constant STATE_TAPE => 5;
|
||||
|
||||
use constant ACTION_GET => 1;
|
||||
use constant ACTION_SET => 2;
|
||||
|
|
|
@ -331,12 +331,18 @@ sub Control {
|
|||
require ZoneMinder::Control;
|
||||
my $Control = ZoneMinder::Control->find_one(Id=>$$self{ControlId});
|
||||
if ($Control) {
|
||||
my $Protocol = $$Control{Protocol};
|
||||
|
||||
if (!$Protocol) {
|
||||
Error("No protocol set in control $$Control{Id}, trying Name $$Control{Name}");
|
||||
$Protocol = $$Control{Name};
|
||||
}
|
||||
require Module::Load::Conditional;
|
||||
if (!Module::Load::Conditional::can_load(modules => {'ZoneMinder::Control::'.$$Control{Protocol} => undef})) {
|
||||
Error("Can't load ZoneMinder::Control::$$Control{Protocol}\n$Module::Load::Conditional::ERROR");
|
||||
if (!Module::Load::Conditional::can_load(modules => {'ZoneMinder::Control::'.$Protocol => undef})) {
|
||||
Error("Can't load ZoneMinder::Control::$Protocol\n$Module::Load::Conditional::ERROR");
|
||||
return undef;
|
||||
}
|
||||
bless $Control, 'ZoneMinder::Control::'.$$Control{Protocol};
|
||||
bless $Control, 'ZoneMinder::Control::'.$Protocol;
|
||||
$$Control{MonitorId} = $$self{Id};
|
||||
$$self{Control} = $Control;
|
||||
} else {
|
||||
|
|
|
@ -429,10 +429,20 @@ sub start {
|
|||
# It's not running, or at least it's not been started by us
|
||||
$process = { daemon=>$daemon, args=>\@args, command=>$command, keepalive=>!undef };
|
||||
} elsif ( $process->{pid} && $pid_hash{$process->{pid}} ) {
|
||||
if ($process->{term_sent_at}) {
|
||||
dPrint(ZoneMinder::Logger::INFO, "'$process->{command}' was told to term at "
|
||||
.strftime('%y/%m/%d %H:%M:%S', localtime($process->{term_sent_at}))
|
||||
.", pid = $process->{pid}\n"
|
||||
);
|
||||
$process->{keepalive} = !undef;
|
||||
$process->{delay} = 0;
|
||||
delete $terminating_processes{$command};
|
||||
} else {
|
||||
dPrint(ZoneMinder::Logger::INFO, "'$process->{command}' already running at "
|
||||
.strftime('%y/%m/%d %H:%M:%S', localtime($process->{started}))
|
||||
.", pid = $process->{pid}\n"
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,28 +21,6 @@
|
|||
#
|
||||
# ==========================================================================
|
||||
|
||||
=head1 NAME
|
||||
|
||||
zmfilter.pl - ZoneMinder tool to filter events
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
zmfilter.pl [-f <filter name>,--filter=<filter name>] [--filter_id=<filter id>] | -v, --version
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This script continuously monitors the recorded events for the given
|
||||
monitor and applies any filters which would delete and/or upload
|
||||
matching events.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
|
||||
-f{filter name}, --filter={filter name} - The name of a specific filter to run
|
||||
--filter_id={filter id} - The id of a specific filter to run
|
||||
-v, --version - Print ZoneMinder version
|
||||
|
||||
=cut
|
||||
use strict;
|
||||
use bytes;
|
||||
|
||||
|
@ -210,7 +188,7 @@ while( !$zm_terminate ) {
|
|||
my ( $id ) = $$filter{Id} =~ /(\d+)/;
|
||||
Debug("Running concurrent filter process $proc --filter_id $$filter{Id} => $id for $$filter{Name}");
|
||||
|
||||
system(qq`$proc --filter "$$filter{Name}" &`);
|
||||
system(qq`$proc --filter_id $id &`);
|
||||
} else {
|
||||
checkFilter($filter);
|
||||
}
|
||||
|
@ -1051,9 +1029,7 @@ sub executeCommand {
|
|||
my $filter = shift;
|
||||
my $Event = shift;
|
||||
|
||||
my $event_path = $Event->Path();
|
||||
|
||||
my $command = $filter->{AutoExecuteCmd}.' '.$event_path;
|
||||
my $command = $filter->{AutoExecuteCmd}.' '.$Event->Path();
|
||||
$command = substituteTags($command, $filter, $Event);
|
||||
|
||||
Info("Executing '$command'");
|
||||
|
@ -1067,11 +1043,33 @@ sub executeCommand {
|
|||
Error("Command '$command' exited with status: $status");
|
||||
return 0;
|
||||
} else {
|
||||
my $sql = 'UPDATE `Events` SET `Executed` = 1 WHERE `Id` = ?';
|
||||
my $sth = $dbh->prepare_cached($sql)
|
||||
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
|
||||
my $res = $sth->execute( $Event->{Id} )
|
||||
or Fatal("Unable to execute '$sql': ".$dbh->errstr());
|
||||
zmSQLExecute('UPDATE `Events` SET `Executed` = 1 WHERE `Id` = ?', $Event->{Id});
|
||||
}
|
||||
return( 1 );
|
||||
return 1;
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
zmfilter.pl - ZoneMinder tool to select events and perform actions on them
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
zmfilter.pl [-f <filter name>,--filter=<filter name>] [--filter_id=<filter id>] [--daemon] | -v, --version
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This script performs a specified database query to select recorded events and performs specified actions on them
|
||||
such as email reporting, deleting, moving, etc. If the --daemon option is given it will remain resident, repeating
|
||||
the query and applying actions. This is normally managed by zmdc.pl however it can be used manually as well.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
-f{filter name}, --filter={filter name} - The name of a specific filter to run
|
||||
--filter_id={filter id} - The id of a specific filter to run
|
||||
--daemon - Causes zmfilter.pl to stay running endlessly repeating the filter(s).
|
||||
-v, --version - Print ZoneMinder version
|
||||
|
||||
=cut
|
||||
|
|
|
@ -166,11 +166,7 @@ while (!$zm_terminate) {
|
|||
foreach my $connection ( values(%spawned_connections) ) {
|
||||
if ( vec($rout, $connection->fileno(), 1) ) {
|
||||
Debug('Got input from spawned connection '
|
||||
.$connection->name()
|
||||
.' ('
|
||||
.$connection->fileno()
|
||||
.')'
|
||||
);
|
||||
.$connection->name().' ('.$connection->fileno().')');
|
||||
my $messages = $connection->getMessages();
|
||||
if (defined($messages)) {
|
||||
foreach my $message ( @$messages ) {
|
||||
|
@ -200,15 +196,17 @@ while (!$zm_terminate) {
|
|||
foreach my $connection ( @in_poll_connections ) {
|
||||
my $messages = $connection->getMessages();
|
||||
if (defined($messages)) {
|
||||
foreach my $message ( @$messages ) {
|
||||
handleMessage($connection, $message);
|
||||
}
|
||||
foreach my $message (@$messages) handleMessage($connection, $message);
|
||||
}
|
||||
}
|
||||
|
||||
# Check for alarms that might have happened
|
||||
my @out_messages;
|
||||
foreach my $monitor ( values %monitors ) {
|
||||
if ($$monitor{Function} eq 'None') {
|
||||
$monitor_reload_time = 0;
|
||||
next;
|
||||
}
|
||||
|
||||
if (!zmMemVerify($monitor)) {
|
||||
# Our attempt to verify the memory handle failed. We should reload the monitors.
|
||||
|
@ -217,15 +215,11 @@ while (!$zm_terminate) {
|
|||
next;
|
||||
}
|
||||
|
||||
my ( $state, $last_event ) = zmMemRead( $monitor,
|
||||
[
|
||||
my ($state, $last_event) = zmMemRead($monitor, [
|
||||
'shared_data:state',
|
||||
'shared_data:last_event'
|
||||
]
|
||||
);
|
||||
]);
|
||||
|
||||
#print( "$monitor->{Id}: S:$state, LE:$last_event" );
|
||||
#print( "$monitor->{Id}: mS:$monitor->{LastState}, mLE:$monitor->{LastEvent}" );
|
||||
if ($state == STATE_ALARM or $state == STATE_ALERT) {
|
||||
# In alarm state
|
||||
if ( !defined($monitor->{LastEvent})
|
||||
|
|
|
@ -251,11 +251,11 @@ void zmDbQueue::process() {
|
|||
mCondition.wait(lock);
|
||||
}
|
||||
while (!mQueue.empty()) {
|
||||
if (mQueue.size() > 10) {
|
||||
if (mQueue.size() > 20) {
|
||||
Logger *log = Logger::fetch();
|
||||
Logger::Level db_level = log->databaseLevel();
|
||||
log->databaseLevel(Logger::NOLOG);
|
||||
Warning("db queue size has grown larger %zu than 10 entries", mQueue.size());
|
||||
Warning("db queue size has grown larger %zu than 20 entries", mQueue.size());
|
||||
log->databaseLevel(db_level);
|
||||
}
|
||||
std::string sql = mQueue.front();
|
||||
|
@ -271,8 +271,10 @@ void zmDbQueue::process() {
|
|||
|
||||
void zmDbQueue::push(std::string &&sql) {
|
||||
if (mTerminate) return;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
mQueue.push(std::move(sql));
|
||||
}
|
||||
mCondition.notify_all();
|
||||
}
|
||||
|
||||
|
|
|
@ -546,7 +546,7 @@ void Event::AddFrame(Image *image,
|
|||
or
|
||||
(frame_type == BULK)
|
||||
or
|
||||
(fps and (frame_data.size() > fps))) {
|
||||
(fps and (frame_data.size() > 5*fps))) {
|
||||
Debug(1, "Adding %zu frames to DB because write_to_db:%d or frames > analysis fps %f or BULK(%d)",
|
||||
frame_data.size(), write_to_db, fps, (frame_type == BULK));
|
||||
WriteDbFrames();
|
||||
|
|
|
@ -23,7 +23,7 @@ void bind_libvnc_symbols() {
|
|||
|
||||
libvnc_lib = dlopen("libvncclient.so", RTLD_LAZY | RTLD_GLOBAL);
|
||||
if (!libvnc_lib) {
|
||||
Error("Error loading libvncclient: %s", dlerror());
|
||||
Error("Error loading libvncclient.so: %s", dlerror());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -135,11 +135,6 @@ VncCamera::VncCamera(
|
|||
}
|
||||
|
||||
VncCamera::~VncCamera() {
|
||||
if (capture and mRfb) {
|
||||
if (mRfb->frameBuffer)
|
||||
free(mRfb->frameBuffer);
|
||||
(*rfbClientCleanup_f)(mRfb);
|
||||
}
|
||||
if (libvnc_lib) {
|
||||
dlclose(libvnc_lib);
|
||||
libvnc_lib = nullptr;
|
||||
|
@ -253,6 +248,12 @@ int VncCamera::PostCapture() {
|
|||
}
|
||||
|
||||
int VncCamera::Close() {
|
||||
if (capture and mRfb) {
|
||||
if (mRfb->frameBuffer)
|
||||
free(mRfb->frameBuffer);
|
||||
(*rfbClientCleanup_f)(mRfb);
|
||||
mRfb = nullptr;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
// It will be used whereever a Monitor dbrow is needed. WHERE conditions can be appended
|
||||
std::string load_monitor_sql =
|
||||
"SELECT `Id`, `Name`, `ServerId`, `StorageId`, `Type`, `Function`+0, `Enabled`, `DecodingEnabled`, "
|
||||
"`LinkedMonitors`, `AnalysisFPSLimit`, `AnalysisUpdateDelay`, `MaxFPS`, `AlarmMaxFPS`,"
|
||||
"`LinkedMonitors`, `EventStartCommand`, `EventEndCommand`, `AnalysisFPSLimit`, `AnalysisUpdateDelay`, `MaxFPS`, `AlarmMaxFPS`,"
|
||||
"`Device`, `Channel`, `Format`, `V4LMultiBuffer`, `V4LCapturesPerFrame`, " // V4L Settings
|
||||
"`Protocol`, `Method`, `Options`, `User`, `Pass`, `Host`, `Port`, `Path`, `SecondPath`, `Width`, `Height`, `Colours`, `Palette`, `Orientation`+0, `Deinterlacing`, "
|
||||
"`DecoderHWAccelName`, `DecoderHWAccelDevice`, `RTSPDescribe`, "
|
||||
|
@ -435,7 +435,7 @@ Monitor::Monitor()
|
|||
|
||||
/*
|
||||
std::string load_monitor_sql =
|
||||
"SELECT Id, Name, ServerId, StorageId, Type, Function+0, Enabled, DecodingEnabled, LinkedMonitors, "
|
||||
"SELECT Id, Name, ServerId, StorageId, Type, Function+0, Enabled, DecodingEnabled, LinkedMonitors, `EventStartCommand`, `EventEndCommand`, "
|
||||
"AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS,"
|
||||
"Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, " // V4L Settings
|
||||
"Protocol, Method, Options, User, Pass, Host, Port, Path, SecondPath, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, "
|
||||
|
@ -489,6 +489,8 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) {
|
|||
// See below after save_jpegs for a recalculation of decoding_enabled
|
||||
|
||||
ReloadLinkedMonitors(dbrow[col]); col++;
|
||||
event_start_command = dbrow[col] ? dbrow[col] : ""; col++;
|
||||
event_end_command = dbrow[col] ? dbrow[col] : ""; col++;
|
||||
|
||||
/* "AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS," */
|
||||
analysis_fps_limit = dbrow[col] ? strtod(dbrow[col], nullptr) : 0.0; col++;
|
||||
|
@ -1873,19 +1875,27 @@ bool Monitor::Analyse() {
|
|||
if (snap->image) {
|
||||
// decoder may not have been able to provide an image
|
||||
if (!ref_image.Buffer()) {
|
||||
Debug(1, "Assigning instead of Dectecting");
|
||||
Debug(1, "Assigning instead of Detecting");
|
||||
ref_image.Assign(*(snap->image));
|
||||
} else {
|
||||
Debug(1, "Detecting motion on image %d, image %p", snap->image_index, snap->image);
|
||||
// Get new score.
|
||||
int motion_score = DetectMotion(*(snap->image), zoneSet);
|
||||
|
||||
// lets construct alarm cause. It will contain cause + names of zones alarmed
|
||||
std::string alarm_cause;
|
||||
snap->zone_stats.reserve(zones.size());
|
||||
for (const Zone &zone : zones) {
|
||||
const ZoneStats &stats = zone.GetStats();
|
||||
stats.DumpToLog("After detect motion");
|
||||
snap->zone_stats.push_back(stats);
|
||||
if (zone.Alarmed()) {
|
||||
if (!alarm_cause.empty()) alarm_cause += ",";
|
||||
alarm_cause += std::string(zone.Label());
|
||||
}
|
||||
}
|
||||
if (!alarm_cause.empty())
|
||||
cause = cause+" "+alarm_cause;
|
||||
|
||||
Debug(3, "After motion detection, score:%d last_motion_score(%d), new motion score(%d)",
|
||||
score, last_motion_score, motion_score);
|
||||
|
@ -1911,6 +1921,7 @@ bool Monitor::Analyse() {
|
|||
);
|
||||
} // end if active and doing motion detection
|
||||
|
||||
|
||||
if (function == RECORD or function == MOCORD) {
|
||||
// If doing record, check to see if we need to close the event or not.
|
||||
if (event) {
|
||||
|
@ -1933,69 +1944,9 @@ bool Monitor::Analyse() {
|
|||
} // end if event
|
||||
|
||||
if (!event) {
|
||||
Debug(2, "Creating continuous event");
|
||||
if (!snap->keyframe and (videowriter == PASSTHROUGH)) {
|
||||
// Must start on a keyframe so rewind. Only for passthrough though I guess.
|
||||
// FIXME this iterator is not protected from invalidation
|
||||
packetqueue_iterator *start_it = packetqueue.get_event_start_packet_it(
|
||||
*analysis_it, 0 /* pre_event_count */
|
||||
);
|
||||
event = openEvent(snap, cause.empty() ? "Continuous" : cause, noteSetMap);
|
||||
|
||||
// This gets a lock on the starting packet
|
||||
|
||||
ZMLockedPacket *starting_packet_lock = nullptr;
|
||||
std::shared_ptr<ZMPacket> starting_packet = nullptr;
|
||||
if (*start_it != *analysis_it) {
|
||||
starting_packet_lock = packetqueue.get_packet(start_it);
|
||||
if (!starting_packet_lock) {
|
||||
Warning("Unable to get starting packet lock");
|
||||
delete packet_lock;
|
||||
return false;
|
||||
}
|
||||
starting_packet = starting_packet_lock->packet_;
|
||||
} else {
|
||||
starting_packet = snap;
|
||||
}
|
||||
|
||||
event = new Event(this, starting_packet->timestamp, "Continuous", noteSetMap);
|
||||
// Write out starting packets, do not modify packetqueue it will garbage collect itself
|
||||
while (starting_packet and ((*start_it) != *analysis_it)) {
|
||||
event->AddPacket(starting_packet);
|
||||
// Have added the packet, don't want to unlock it until we have locked the next
|
||||
|
||||
packetqueue.increment_it(start_it);
|
||||
if ((*start_it) == *analysis_it) {
|
||||
if (starting_packet_lock) delete starting_packet_lock;
|
||||
break;
|
||||
}
|
||||
ZMLockedPacket *lp = packetqueue.get_packet(start_it);
|
||||
delete starting_packet_lock;
|
||||
if (!lp) return false;
|
||||
starting_packet_lock = lp;
|
||||
starting_packet = lp->packet_;
|
||||
}
|
||||
packetqueue.free_it(start_it);
|
||||
delete start_it;
|
||||
start_it = nullptr;
|
||||
} else {
|
||||
// Create event from current snap
|
||||
event = new Event(this, timestamp, "Continuous", noteSetMap);
|
||||
}
|
||||
shared_data->last_event_id = event->Id();
|
||||
|
||||
// lets construct alarm cause. It will contain cause + names of zones alarmed
|
||||
std::string alarm_cause;
|
||||
for (const Zone &zone : zones) {
|
||||
if (zone.Alarmed()) {
|
||||
if (!alarm_cause.empty()) alarm_cause += ",";
|
||||
alarm_cause += std::string(zone.Label());
|
||||
}
|
||||
}
|
||||
alarm_cause = cause+" Continuous "+alarm_cause;
|
||||
strncpy(shared_data->alarm_cause, alarm_cause.c_str(), sizeof(shared_data->alarm_cause)-1);
|
||||
SetVideoWriterStartTime(event->StartTime());
|
||||
|
||||
Info("%s: %03d - Opened new event %" PRIu64 ", section start",
|
||||
Info("%s: %03d - Opened new event %" PRIu64 ", continuous section start",
|
||||
name.c_str(), analysis_image_count, event->Id());
|
||||
/* To prevent cancelling out an existing alert\prealarm\alarm state */
|
||||
if (state == IDLE) {
|
||||
|
@ -2027,63 +1978,12 @@ bool Monitor::Analyse() {
|
|||
(event_close_mode == CLOSE_ALARM));
|
||||
}
|
||||
if ((!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count-1)) {
|
||||
// lets construct alarm cause. It will contain cause + names of zones alarmed
|
||||
std::string alarm_cause = "";
|
||||
for (const Zone &zone : zones) {
|
||||
if (zone.Alarmed()) {
|
||||
alarm_cause = alarm_cause + "," + std::string(zone.Label());
|
||||
}
|
||||
}
|
||||
if (!alarm_cause.empty()) alarm_cause[0] = ' ';
|
||||
alarm_cause = cause + alarm_cause;
|
||||
strncpy(shared_data->alarm_cause, alarm_cause.c_str(), sizeof(shared_data->alarm_cause)-1);
|
||||
Info("%s: %03d - Gone into alarm state PreAlarmCount: %u > AlarmFrameCount:%u Cause:%s",
|
||||
name.c_str(), image_count, Event::PreAlarmCount(), alarm_frame_count, shared_data->alarm_cause);
|
||||
name.c_str(), image_count, Event::PreAlarmCount(), alarm_frame_count, cause.c_str());
|
||||
|
||||
if (!event) {
|
||||
packetqueue_iterator *start_it = packetqueue.get_event_start_packet_it(
|
||||
*analysis_it,
|
||||
(pre_event_count > alarm_frame_count ? pre_event_count : alarm_frame_count)
|
||||
);
|
||||
ZMLockedPacket *starting_packet_lock = nullptr;
|
||||
std::shared_ptr<ZMPacket> starting_packet = nullptr;
|
||||
if (*start_it != *analysis_it) {
|
||||
starting_packet_lock = packetqueue.get_packet(start_it);
|
||||
if (!starting_packet_lock) return false;
|
||||
starting_packet = starting_packet_lock->packet_;
|
||||
} else {
|
||||
starting_packet = snap;
|
||||
}
|
||||
|
||||
event = new Event(this, starting_packet->timestamp, cause, noteSetMap);
|
||||
shared_data->last_event_id = event->Id();
|
||||
snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile());
|
||||
SetVideoWriterStartTime(event->StartTime());
|
||||
event = openEvent(snap, cause, noteSetMap);
|
||||
shared_data->state = state = ALARM;
|
||||
|
||||
// Write out starting packets, do not modify packetqueue it will garbage collect itself
|
||||
while (*start_it != *analysis_it) {
|
||||
event->AddPacket(starting_packet);
|
||||
|
||||
packetqueue.increment_it(start_it);
|
||||
if ( (*start_it) == (*analysis_it) ) {
|
||||
if (starting_packet_lock) delete starting_packet_lock;
|
||||
break;
|
||||
}
|
||||
ZMLockedPacket *lp = packetqueue.get_packet(start_it);
|
||||
delete starting_packet_lock;
|
||||
if (!lp) {
|
||||
// Shutting down event will be closed by ~Monitor()
|
||||
// Perhaps we shouldn't do this.
|
||||
return false;
|
||||
}
|
||||
starting_packet_lock = lp;
|
||||
starting_packet = lp->packet_;
|
||||
}
|
||||
packetqueue.free_it(start_it);
|
||||
delete start_it;
|
||||
start_it = nullptr;
|
||||
|
||||
Info("%s: %03d - Opening new event %" PRIu64 ", alarm start", name.c_str(), analysis_image_count, event->Id());
|
||||
} else {
|
||||
shared_data->state = state = ALARM;
|
||||
|
@ -2193,11 +2093,7 @@ bool Monitor::Analyse() {
|
|||
static_cast<int64>(std::chrono::duration_cast<Seconds>(timestamp - GetVideoWriterStartTime()).count()),
|
||||
static_cast<int64>(Seconds(section_length).count()));
|
||||
closeEvent();
|
||||
event = new Event(this, timestamp, cause, noteSetMap);
|
||||
shared_data->last_event_id = event->Id();
|
||||
//set up video store data
|
||||
snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile());
|
||||
SetVideoWriterStartTime(event->StartTime());
|
||||
event = openEvent(snap, cause, noteSetMap);
|
||||
}
|
||||
} else {
|
||||
Error("ALARM but no event");
|
||||
|
@ -2776,6 +2672,67 @@ void Monitor::TimestampImage(Image *ts_image, SystemTimePoint ts_time) const {
|
|||
Debug(2, "done annotating %s", label_text);
|
||||
} // end void Monitor::TimestampImage
|
||||
|
||||
Event * Monitor::openEvent(
|
||||
const std::shared_ptr<ZMPacket> &snap,
|
||||
const std::string &cause,
|
||||
const Event::StringSetMap noteSetMap) {
|
||||
|
||||
// FIXME this iterator is not protected from invalidation
|
||||
packetqueue_iterator *start_it = packetqueue.get_event_start_packet_it(
|
||||
*analysis_it,
|
||||
(cause == "Continuous" ? 0 : (pre_event_count > alarm_frame_count ? pre_event_count : alarm_frame_count))
|
||||
);
|
||||
|
||||
// This gets a lock on the starting packet
|
||||
|
||||
ZMLockedPacket *starting_packet_lock = nullptr;
|
||||
std::shared_ptr<ZMPacket> starting_packet = nullptr;
|
||||
if (*start_it != *analysis_it) {
|
||||
starting_packet_lock = packetqueue.get_packet(start_it);
|
||||
if (!starting_packet_lock) {
|
||||
Warning("Unable to get starting packet lock");
|
||||
return nullptr;
|
||||
}
|
||||
starting_packet = starting_packet_lock->packet_;
|
||||
} else {
|
||||
starting_packet = snap;
|
||||
}
|
||||
|
||||
event = new Event(this, starting_packet->timestamp, cause, noteSetMap);
|
||||
|
||||
shared_data->last_event_id = event->Id();
|
||||
strncpy(shared_data->alarm_cause, cause.c_str(), sizeof(shared_data->alarm_cause)-1);
|
||||
|
||||
if (!event_start_command.empty()) {
|
||||
if (fork() == 0) {
|
||||
execlp(event_start_command.c_str(), event_start_command.c_str(), std::to_string(event->Id()).c_str(), nullptr);
|
||||
Error("Error execing %s", event_start_command.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Write out starting packets, do not modify packetqueue it will garbage collect itself
|
||||
while (starting_packet and ((*start_it) != *analysis_it)) {
|
||||
event->AddPacket(starting_packet);
|
||||
// Have added the packet, don't want to unlock it until we have locked the next
|
||||
|
||||
packetqueue.increment_it(start_it);
|
||||
if ((*start_it) == *analysis_it) {
|
||||
if (starting_packet_lock) delete starting_packet_lock;
|
||||
break;
|
||||
}
|
||||
ZMLockedPacket *lp = packetqueue.get_packet(start_it);
|
||||
delete starting_packet_lock;
|
||||
if (!lp) return nullptr; // only on terminate FIXME
|
||||
starting_packet_lock = lp;
|
||||
starting_packet = lp->packet_;
|
||||
}
|
||||
packetqueue.free_it(start_it);
|
||||
delete start_it;
|
||||
start_it = nullptr;
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
void Monitor::closeEvent() {
|
||||
if (!event) return;
|
||||
|
||||
|
@ -2786,7 +2743,18 @@ void Monitor::closeEvent() {
|
|||
Debug(1, "close event thread is not joinable");
|
||||
}
|
||||
Debug(1, "Starting thread to close event");
|
||||
close_event_thread = std::thread([](Event *e){ delete e; }, event);
|
||||
close_event_thread = std::thread([](Event *e, const std::string &command){
|
||||
int64_t event_id = e->Id();
|
||||
delete e;
|
||||
|
||||
if (!command.empty()) {
|
||||
if (fork() == 0) {
|
||||
execlp(command.c_str(), command.c_str(), std::to_string(event_id).c_str(), nullptr);
|
||||
Error("Error execing %s", command.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
}, event, event_end_command);
|
||||
Debug(1, "Nulling event");
|
||||
event = nullptr;
|
||||
if (shared_data) video_store_data->recording = {};
|
||||
|
@ -3079,9 +3047,6 @@ int Monitor::PrimeCapture() {
|
|||
int Monitor::PreCapture() const { return camera->PreCapture(); }
|
||||
int Monitor::PostCapture() const { return camera->PostCapture(); }
|
||||
int Monitor::Close() {
|
||||
if (close_event_thread.joinable()) {
|
||||
close_event_thread.join();
|
||||
}
|
||||
// Because the stream indexes may change we have to clear out the packetqueue
|
||||
if (decoder) {
|
||||
decoder->Stop();
|
||||
|
@ -3099,10 +3064,14 @@ int Monitor::Close() {
|
|||
video_fifo = nullptr;
|
||||
}
|
||||
|
||||
if (close_event_thread.joinable()) {
|
||||
close_event_thread.join();
|
||||
}
|
||||
std::lock_guard<std::mutex> lck(event_mutex);
|
||||
if (event) {
|
||||
Info("%s: image_count:%d - Closing event %" PRIu64 ", shutting down", name.c_str(), image_count, event->Id());
|
||||
closeEvent();
|
||||
close_event_thread.join();
|
||||
}
|
||||
if (camera) camera->Close();
|
||||
return 1;
|
||||
|
|
|
@ -404,6 +404,8 @@ protected:
|
|||
|
||||
int n_linked_monitors;
|
||||
MonitorLink **linked_monitors;
|
||||
std::string event_start_command;
|
||||
std::string event_end_command;
|
||||
|
||||
std::vector<Group *> groups;
|
||||
|
||||
|
@ -591,6 +593,10 @@ public:
|
|||
bool Decode();
|
||||
void DumpImage( Image *dump_image ) const;
|
||||
void TimestampImage(Image *ts_image, SystemTimePoint ts_time) const;
|
||||
Event *openEvent(
|
||||
const std::shared_ptr<ZMPacket> &snap,
|
||||
const std::string &cause,
|
||||
const Event::StringSetMap noteSetMap);
|
||||
void closeEvent();
|
||||
|
||||
void Reload();
|
||||
|
|
|
@ -118,12 +118,13 @@ bool PacketQueue::queuePacket(std::shared_ptr<ZMPacket> add_packet) {
|
|||
for (
|
||||
auto it = ++pktQueue.begin();
|
||||
it != pktQueue.end() and *it != add_packet;
|
||||
// iterator is incremented by erase
|
||||
) {
|
||||
std::shared_ptr <ZMPacket>zm_packet = *it;
|
||||
|
||||
ZMLockedPacket *lp = new ZMLockedPacket(zm_packet);
|
||||
if (!lp->trylock()) {
|
||||
Debug(1, "Found locked packet when trying to free up video packets. Skipping to next one");
|
||||
Warning("Found locked packet when trying to free up video packets. This basically means that decoding is not keeping up.");
|
||||
delete lp;
|
||||
++it;
|
||||
continue;
|
||||
|
@ -312,7 +313,6 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
|
|||
pktQueue.size());
|
||||
pktQueue.pop_front();
|
||||
packet_counts[zm_packet->packet.stream_index] -= 1;
|
||||
//delete zm_packet;
|
||||
}
|
||||
} // end if have at least max_video_packet_count video packets remaining
|
||||
// We signal on every packet because someday we may analyze sound
|
||||
|
|
|
@ -252,8 +252,15 @@ void HwCapsDetect() {
|
|||
#elif defined(__arm__)
|
||||
// ARM processor in 32bit mode
|
||||
// To see if it supports NEON, we need to get that information from the kernel
|
||||
#ifdef __linux__
|
||||
unsigned long auxval = getauxval(AT_HWCAP);
|
||||
if (auxval & HWCAP_ARM_NEON) {
|
||||
#elif defined(__FreeBSD__)
|
||||
unsigned long auxval = 0;
|
||||
elf_aux_info(AT_HWCAP, &auxval, sizeof(auxval));
|
||||
if (auxval & HWCAP_NEON) {
|
||||
#error Unsupported OS.
|
||||
#endif
|
||||
Debug(1,"Detected ARM (AArch32) processor with Neon");
|
||||
neonversion = 1;
|
||||
} else {
|
||||
|
|
|
@ -878,16 +878,23 @@ std::vector<Zone> Zone::Load(Monitor *monitor) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (polygon.Extent().Lo().x_ < 0 || polygon.Extent().Hi().x_ > static_cast<int32>(monitor->Width())
|
||||
|| polygon.Extent().Lo().y_ < 0 || polygon.Extent().Hi().y_ > static_cast<int32>(monitor->Height())) {
|
||||
Error("Zone %d/%s for monitor %s extends outside of image dimensions, (%d,%d), (%d,%d), fixing",
|
||||
if (polygon.Extent().Lo().x_ < 0
|
||||
||
|
||||
polygon.Extent().Hi().x_ > static_cast<int32>(monitor->Width())
|
||||
||
|
||||
polygon.Extent().Lo().y_ < 0
|
||||
||
|
||||
polygon.Extent().Hi().y_ > static_cast<int32>(monitor->Height())) {
|
||||
Error("Zone %d/%s for monitor %s extends outside of image dimensions, (%d,%d), (%d,%d) != (%d,%d), fixing",
|
||||
Id,
|
||||
Name,
|
||||
monitor->Name(),
|
||||
polygon.Extent().Lo().x_,
|
||||
polygon.Extent().Lo().y_,
|
||||
polygon.Extent().Hi().x_,
|
||||
polygon.Extent().Hi().y_);
|
||||
polygon.Extent().Hi().y_,
|
||||
monitor->Width(),
|
||||
monitor->Height());
|
||||
|
||||
polygon.Clip(Box(
|
||||
{0, 0},
|
||||
|
|
14
src/zmc.cpp
14
src/zmc.cpp
|
@ -220,12 +220,13 @@ int main(int argc, char *argv[]) {
|
|||
zmSetDefaultTermHandler();
|
||||
zmSetDefaultDieHandler();
|
||||
|
||||
sigset_t block_set;
|
||||
sigemptyset(&block_set);
|
||||
|
||||
sigaddset(&block_set, SIGHUP);
|
||||
sigaddset(&block_set, SIGUSR1);
|
||||
sigaddset(&block_set, SIGUSR2);
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = SIG_IGN; //handle signal by ignoring
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
if (sigaction(SIGCHLD, &sa, 0) == -1) {
|
||||
Error("Unable to set SIGCHLD to ignore. There may be zombies.");
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
int prime_capture_log_count = 0;
|
||||
|
@ -286,7 +287,6 @@ int main(int argc, char *argv[]) {
|
|||
Microseconds sleep_time = Microseconds(0);
|
||||
|
||||
while (!zm_terminate) {
|
||||
//sigprocmask(SIG_BLOCK, &block_set, 0);
|
||||
for (size_t i = 0; i < monitors.size(); i++) {
|
||||
monitors[i]->CheckAction();
|
||||
|
||||
|
|
|
@ -116,6 +116,30 @@ else
|
|||
echo "Defaulting to ZoneMinder upstream git"
|
||||
GITHUB_FORK="ZoneMinder"
|
||||
fi;
|
||||
fi;
|
||||
|
||||
# Instead of cloning from github each time, if we have a fork lying around, update it and pull from there instead.
|
||||
if [ ! -d "${GITHUB_FORK}_zoneminder_release" ]; then
|
||||
if [ -d "${GITHUB_FORK}_ZoneMinder.git" ]; then
|
||||
echo "Using local clone ${GITHUB_FORK}_ZoneMinder.git to pull from."
|
||||
cd "${GITHUB_FORK}_ZoneMinder.git"
|
||||
echo "git fetch..."
|
||||
git fetch
|
||||
cd ../
|
||||
|
||||
echo "git clone ${GITHUB_FORK}_ZoneMinder.git ${GITHUB_FORK}_zoneminder_release"
|
||||
git clone "${GITHUB_FORK}_ZoneMinder.git" "${GITHUB_FORK}_zoneminder_release"
|
||||
else
|
||||
echo "git clone https://github.com/$GITHUB_FORK/ZoneMinder.git ${GITHUB_FORK}_zoneminder_release"
|
||||
git clone "https://github.com/$GITHUB_FORK/ZoneMinder.git" "${GITHUB_FORK}_zoneminder_release"
|
||||
fi
|
||||
else
|
||||
echo "release dir already exists. Please remove it."
|
||||
exit 0;
|
||||
fi;
|
||||
|
||||
cd "${GITHUB_FORK}_zoneminder_release"
|
||||
|
||||
if [ "$SNAPSHOT" == "stable" ]; then
|
||||
if [ "$BRANCH" == "" ]; then
|
||||
#REV=$(git rev-list --tags --max-count=1)
|
||||
|
@ -140,37 +164,17 @@ else
|
|||
SNAPSHOT=`date +%Y%m%d%H%M%S`;
|
||||
else
|
||||
if [ "$SNAPSHOT" == "CURRENT" ]; then
|
||||
# git the latest (short) commit hash of the version file
|
||||
versionhash=$(git log -n1 --pretty=format:%h version)
|
||||
|
||||
# Number of commits since the version file was last changed
|
||||
numcommits=$(git rev-list ${versionhash}..HEAD --count)
|
||||
SNAPSHOT="`date +%Y%m%d.`$(git rev-list ${versionhash}..HEAD --count)"
|
||||
fi;
|
||||
fi;
|
||||
fi;
|
||||
fi
|
||||
|
||||
IFS='.' read -r -a VERSION_PARTS <<< "$RELEASE"
|
||||
if [ "$PPA" == "" ]; then
|
||||
if [ "$RELEASE" != "" ]; then
|
||||
# We need to use our official tarball for the original source, so grab it and overwrite our generated one.
|
||||
if [ "${VERSION_PARTS[0]}.${VERSION_PARTS[1]}" == "1.30" ]; then
|
||||
PPA="ppa:iconnor/zoneminder-stable"
|
||||
else
|
||||
PPA="ppa:iconnor/zoneminder-${VERSION_PARTS[0]}.${VERSION_PARTS[1]}"
|
||||
fi;
|
||||
else
|
||||
if [ "$BRANCH" == "" ]; then
|
||||
PPA="ppa:iconnor/zoneminder-master";
|
||||
else
|
||||
PPA="ppa:iconnor/zoneminder-$BRANCH";
|
||||
fi;
|
||||
fi;
|
||||
fi;
|
||||
|
||||
# Instead of cloning from github each time, if we have a fork lying around, update it and pull from there instead.
|
||||
if [ ! -d "${GITHUB_FORK}_zoneminder_release" ]; then
|
||||
if [ -d "${GITHUB_FORK}_ZoneMinder.git" ]; then
|
||||
echo "Using local clone ${GITHUB_FORK}_ZoneMinder.git to pull from."
|
||||
cd "${GITHUB_FORK}_ZoneMinder.git"
|
||||
echo "git fetch..."
|
||||
git fetch
|
||||
echo "git checkout $BRANCH"
|
||||
git checkout $BRANCH
|
||||
if [ $? -ne 0 ]; then
|
||||
|
@ -179,27 +183,15 @@ if [ ! -d "${GITHUB_FORK}_zoneminder_release" ]; then
|
|||
fi;
|
||||
echo "git pull..."
|
||||
git pull
|
||||
cd ../
|
||||
echo "git clone ${GITHUB_FORK}_ZoneMinder.git ${GITHUB_FORK}_zoneminder_release"
|
||||
git clone "${GITHUB_FORK}_ZoneMinder.git" "${GITHUB_FORK}_zoneminder_release"
|
||||
else
|
||||
echo "git clone https://github.com/$GITHUB_FORK/ZoneMinder.git ${GITHUB_FORK}_zoneminder_release"
|
||||
git clone "https://github.com/$GITHUB_FORK/ZoneMinder.git" "${GITHUB_FORK}_zoneminder_release"
|
||||
fi
|
||||
else
|
||||
echo "release dir already exists. Please remove it."
|
||||
exit 0;
|
||||
fi;
|
||||
|
||||
cd "${GITHUB_FORK}_zoneminder_release"
|
||||
git checkout $BRANCH
|
||||
cd ../
|
||||
|
||||
VERSION=`cat ${GITHUB_FORK}_zoneminder_release/version`
|
||||
|
||||
# Grab the ZoneMinder version from the contents of the version file
|
||||
VERSION=$(cat version)
|
||||
if [ -z "$VERSION" ]; then
|
||||
exit 1;
|
||||
fi;
|
||||
IFS='.' read -r -a VERSION_PARTS <<< "$VERSION"
|
||||
|
||||
cd ../
|
||||
|
||||
if [ "$SNAPSHOT" != "stable" ] && [ "$SNAPSHOT" != "" ]; then
|
||||
VERSION="$VERSION~$SNAPSHOT";
|
||||
fi;
|
||||
|
@ -230,8 +222,8 @@ rm .gitignore
|
|||
cd ../
|
||||
|
||||
|
||||
if [ ! -e "$DIRECTORY.orig.tar.gz" ]; then
|
||||
read -p "$DIRECTORY.orig.tar.gz does not exist, create it? [Y/n]"
|
||||
if [ -e "$DIRECTORY.orig.tar.gz" ]; then
|
||||
read -p "$DIRECTORY.orig.tar.gz exists, overwrite it? [Y/n]"
|
||||
if [[ "$REPLY" == "" || "$REPLY" == [yY] ]]; then
|
||||
tar zcf $DIRECTORY.orig.tar.gz $DIRECTORY.orig
|
||||
fi;
|
||||
|
@ -357,6 +349,22 @@ EOF
|
|||
fi;
|
||||
else
|
||||
SC="zoneminder_${VERSION}-${DISTRO}${PACKAGE_VERSION}_source.changes";
|
||||
if [ "$PPA" == "" ]; then
|
||||
if [ "$RELEASE" != "" ]; then
|
||||
# We need to use our official tarball for the original source, so grab it and overwrite our generated one.
|
||||
if [ "${VERSION_PARTS[0]}.${VERSION_PARTS[1]}" == "1.30" ]; then
|
||||
PPA="ppa:iconnor/zoneminder-stable"
|
||||
else
|
||||
PPA="ppa:iconnor/zoneminder-${VERSION_PARTS[0]}.${VERSION_PARTS[1]}"
|
||||
fi;
|
||||
else
|
||||
if [ "$BRANCH" == "" ]; then
|
||||
PPA="ppa:iconnor/zoneminder-master";
|
||||
else
|
||||
PPA="ppa:iconnor/zoneminder-$BRANCH";
|
||||
fi;
|
||||
fi;
|
||||
fi;
|
||||
|
||||
dput="Y";
|
||||
if [ "$INTERACTIVE" != "no" ]; then
|
||||
|
|
|
@ -321,12 +321,20 @@ class MonitorsController extends AppController {
|
|||
}
|
||||
|
||||
$monitor = $this->Monitor->find('first', array(
|
||||
'fields' => array('Id', 'Type', 'Device'),
|
||||
'fields' => array('Id', 'Type', 'Device', 'Function'),
|
||||
'conditions' => array('Id' => $id)
|
||||
));
|
||||
|
||||
// Clean up the returned array
|
||||
$monitor = Set::extract('/Monitor/.', $monitor);
|
||||
if ($monitor[0]['Function'] == 'None') {
|
||||
$this->set(array(
|
||||
'status' => false,
|
||||
'statustext' => 'Monitor function is set to None',
|
||||
'_serialize' => array('status','statustext'),
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
// Pass -d for local, otherwise -m
|
||||
if ( $monitor[0]['Type'] == 'Local' ) {
|
||||
|
|
|
@ -167,9 +167,15 @@ class Group extends ZM_Object {
|
|||
public function Parents() {
|
||||
$Parents = array();
|
||||
$Parent = $this->Parent();
|
||||
$seen_parents = array();
|
||||
while ($Parent) {
|
||||
$seen_parents[$Parent->Id()] = $Parent;
|
||||
array_unshift($Parents, $Parent);
|
||||
$Parent = $Parent->Parent();
|
||||
if ($Parent and isset($seen_parents[$Parent->Id()])) {
|
||||
Warning("Detected hierarchy loop in group {$Parent->Name()}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $Parents;
|
||||
}
|
||||
|
@ -189,6 +195,9 @@ class Group extends ZM_Object {
|
|||
public function canView($u=null) {
|
||||
global $user;
|
||||
if (!$u) $u = $user;
|
||||
if (!count($this->Monitors()) and !count($this->Children())) {
|
||||
return true;
|
||||
}
|
||||
# Can view if we can view any of the monitors in it.
|
||||
foreach ($this->Monitors() as $monitor) {
|
||||
if ($monitor->canView($u)) return true;
|
||||
|
|
|
@ -57,6 +57,8 @@ class Monitor extends ZM_Object {
|
|||
'DecodingEnabled' => array('type'=>'boolean','default'=>1),
|
||||
'LinkedMonitors' => array('type'=>'set', 'default'=>null),
|
||||
'Triggers' => array('type'=>'set','default'=>''),
|
||||
'EventStartCommand' => '',
|
||||
'EventEndCommand' => '',
|
||||
'ONVIF_URL' => '',
|
||||
'ONVIF_Username' => '',
|
||||
'ONVIF_Password' => '',
|
||||
|
|
|
@ -13,6 +13,10 @@ class Zone extends ZM_Object {
|
|||
'Name' => '',
|
||||
'Type' => 'Active',
|
||||
'Units' => 'Pixels',
|
||||
'NumCoords' => '0',
|
||||
'Coords' => 0,
|
||||
'Area' => '0',
|
||||
'AlarmRGB' => '0',
|
||||
'CheckMethod' => 'Blobs',
|
||||
'MinPixelThreshold' => null,
|
||||
'MaxPixelThreshold' => null,
|
||||
|
@ -46,5 +50,17 @@ class Zone extends ZM_Object {
|
|||
return new Monitor();
|
||||
}
|
||||
|
||||
public function Points() {
|
||||
return coordsToPoints($this->Coords());
|
||||
}
|
||||
|
||||
public function AreaCoords() {
|
||||
return preg_replace('/\s+/', ',', $this->Coords());
|
||||
}
|
||||
|
||||
public function svg_polygon() {
|
||||
return '<polygon points="'.$this->AreaCoords().'" class="'.$this->Type().'" />';
|
||||
}
|
||||
|
||||
} # end class Zone
|
||||
?>
|
||||
|
|
|
@ -87,11 +87,12 @@ define('ZM_PCRE', '@ZM_PCRE@'); // PCRE support enabled
|
|||
//
|
||||
// Alarm states
|
||||
//
|
||||
define('STATE_IDLE', 0);
|
||||
define('STATE_PREALARM', 1);
|
||||
define('STATE_ALARM', 2);
|
||||
define('STATE_ALERT', 3);
|
||||
define('STATE_TAPE', 4);
|
||||
define('STATE_UNKNOWN', 0);
|
||||
define('STATE_IDLE', 1);
|
||||
define('STATE_PREALARM', 2);
|
||||
define('STATE_ALARM', 3);
|
||||
define('STATE_ALERT', 4);
|
||||
define('STATE_TAPE', 5);
|
||||
|
||||
//
|
||||
// DVR Control Commands
|
||||
|
|
|
@ -77,7 +77,7 @@ height: 100%;
|
|||
position: relative;
|
||||
}
|
||||
|
||||
#imageFeed {
|
||||
#videoFeed {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
|
@ -263,3 +263,17 @@ height: 100%;
|
|||
height: 100%;
|
||||
background-color: #999999;
|
||||
}
|
||||
svg.zones {
|
||||
position:absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: none;
|
||||
width: 100%;
|
||||
/*
|
||||
height: 100%;
|
||||
*/
|
||||
}
|
||||
#videoobj {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
min-width: 140px;
|
||||
}
|
||||
|
||||
#menuControls {
|
||||
|
@ -19,19 +21,22 @@
|
|||
#monitorStatus {
|
||||
margin: 4px auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#monitorStatus #enableDisableAlarms {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#monitorStatus #forceCancelAlarm {
|
||||
float: right;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#monitorStatus #monitorState {
|
||||
}
|
||||
|
||||
#replayStatus {
|
||||
margin: 3px 0 2px;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#replayStatus > span {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
#dvrControls {
|
||||
margin-top: 3px;
|
||||
margin-bottom: 2px;
|
||||
|
@ -67,15 +72,6 @@
|
|||
cursor: default;
|
||||
}
|
||||
|
||||
#replayStatus {
|
||||
margin: 3px 0 2px;
|
||||
text-align: center;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#replayStatus > span {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
#events {
|
||||
margin: 0 auto;
|
||||
|
@ -116,3 +112,22 @@ span.alert {
|
|||
background-color: #DCDCDC;
|
||||
}
|
||||
|
||||
.controlHeader {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#viewingFPS,
|
||||
#captureFPS,
|
||||
#analysisFPS
|
||||
{
|
||||
display: inline-block;
|
||||
}
|
||||
#stateValue,
|
||||
#viewingFPSValue,
|
||||
#captureFPSValue,
|
||||
#analysisFPSValue
|
||||
{
|
||||
display: inline-block;
|
||||
min-width: 40px;
|
||||
text-align: right;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
.zones polygon {
|
||||
fill-opacity: 0.25;
|
||||
}
|
||||
.Active {
|
||||
stroke: #ff0000;
|
||||
fill: #ff0000;
|
||||
}
|
||||
.Inclusive {
|
||||
stroke: #FFA500;
|
||||
fill: #FFA500;
|
||||
}
|
||||
.Exclusive {
|
||||
stroke: #800080;
|
||||
fill: #800080;
|
||||
}
|
||||
.Preclusive {
|
||||
stroke: #0000FF;
|
||||
fill: #0000FF;
|
||||
}
|
|
@ -90,3 +90,18 @@ unset($user_without_password['Password']);
|
|||
echo json_encode($user_without_password);
|
||||
?>;
|
||||
var running = <?php echo daemonCheck()?'true':'false' ?>;
|
||||
|
||||
var STATE_UNKNOWN = <?php echo STATE_UNKNOWN ?>;
|
||||
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_UNKNOWN] = "<?php echo translate('Unknown') ?>";
|
||||
stateStrings[STATE_IDLE] = "<?php echo translate('Idle') ?>";
|
||||
stateStrings[STATE_PREALARM] = "<?php echo translate('Prealarm') ?>";
|
||||
stateStrings[STATE_ALARM] = "<?php echo translate('Alarm') ?>";
|
||||
stateStrings[STATE_ALERT] = "<?php echo translate('Alert') ?>";
|
||||
stateStrings[STATE_TAPE] = "<?php echo translate('Record') ?>";
|
||||
|
|
|
@ -260,31 +260,37 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
|
|||
?>
|
||||
<tr id="<?php echo 'monitor_id-'.$monitor['Id'] ?>" title="<?php echo $monitor['Id'] ?>">
|
||||
<?php
|
||||
$source_class = 'infoText';
|
||||
$source_class_reason = '';
|
||||
if ( (!$monitor['Status'] || $monitor['Status'] == 'NotRunning') && $monitor['Type']!='WebSite' ) {
|
||||
$source_class = 'errorText';
|
||||
$source_class_reason = translate('Not Running');
|
||||
} else {
|
||||
if ( $monitor['CaptureFPS'] == '0.00' ) {
|
||||
$source_class = 'errorText';
|
||||
$source_class_reason = translate('No capture FPS');
|
||||
} else if ( (!$monitor['AnalysisFPS']) && ($monitor['Function']!='Monitor') && ($monitor['Function'] != 'Nodect') ) {
|
||||
$source_class = 'warnText';
|
||||
} else {
|
||||
$source_class = 'infoText';
|
||||
$source_class_reason = translate('No analysis FPS');
|
||||
}
|
||||
}
|
||||
if ( $monitor['Function'] == 'None' )
|
||||
$function_class = 'errorText';
|
||||
else
|
||||
$function_class = 'infoText';
|
||||
|
||||
$function_class = 'infoText';
|
||||
if ($monitor['Function'] == 'None') {
|
||||
$function_class = 'errorText';
|
||||
}
|
||||
|
||||
$dot_class = $source_class;
|
||||
$dot_class_reason = $source_class_reason;
|
||||
if ( $function_class != 'infoText' ) {
|
||||
$dot_class = $function_class;
|
||||
} else if (($monitor['Function'] == 'Modect' || $monitor['Function'] == 'Mocord') and !$monitor['Enabled']) {
|
||||
$dot_class .= ' warnText';
|
||||
$dot_class_reason .= ' '.translate('Analysis is disabled');
|
||||
}
|
||||
|
||||
$scale = max(reScale(SCALE_BASE, $monitor['DefaultScale'], ZM_WEB_DEFAULT_SCALE), SCALE_BASE);
|
||||
$stream_available = canView('Stream') and $monitor['Type']=='WebSite' or ($monitor['CaptureFPS'] && $monitor['Function'] != 'None');
|
||||
$dot_class = $source_class;
|
||||
if ( $function_class != 'infoText' ) {
|
||||
$dot_class = $function_class;
|
||||
} else if ( !$monitor['Enabled'] ) {
|
||||
$dot_class .= ' warnText';
|
||||
}
|
||||
|
||||
if ( ZM_WEB_ID_ON_CONSOLE ) {
|
||||
?>
|
||||
|
@ -317,7 +323,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
|
|||
}
|
||||
?>
|
||||
<td class="colName">
|
||||
<i class="material-icons md-18 <?php echo $dot_class ?>">lens</i>
|
||||
<i class="material-icons md-18 <?php echo $dot_class ?>" title="<?php echo $dot_class_reason ?>">lens</i>
|
||||
<a <?php echo ($stream_available ? 'href="?view=watch&mid='.$monitor['Id'].'">' : '>') . validHtmlStr($monitor['Name']) ?></a><br/>
|
||||
<?php echo $imgHTML ?>
|
||||
<div class="small text-nowrap text-muted">
|
||||
|
|
|
@ -25,26 +25,26 @@ if ( !canView('Events') ) {
|
|||
|
||||
require_once('includes/Event.php');
|
||||
require_once('includes/Filter.php');
|
||||
require_once('includes/Zone.php');
|
||||
|
||||
$eid = validInt($_REQUEST['eid']);
|
||||
$fid = !empty($_REQUEST['fid']) ? validInt($_REQUEST['fid']) : 1;
|
||||
|
||||
$Event = new ZM\Event($eid);
|
||||
if ( $user['MonitorIds'] ) {
|
||||
$monitor_ids = explode(',', $user['MonitorIds']);
|
||||
if ( count($monitor_ids) and ! in_array($Event->MonitorId(), $monitor_ids) ) {
|
||||
$monitor = $Event->Monitor();
|
||||
|
||||
if (!$monitor->canView()) {
|
||||
$view = 'error';
|
||||
return;
|
||||
}
|
||||
}
|
||||
$Monitor = $Event->Monitor();
|
||||
|
||||
zm_session_start();
|
||||
if (isset($_REQUEST['rate']) ) {
|
||||
$rate = validInt($_REQUEST['rate']);
|
||||
} else if (isset($_COOKIE['zmEventRate'])) {
|
||||
$rate = $_COOKIE['zmEventRate'];
|
||||
} else {
|
||||
$rate = reScale(RATE_BASE, $Monitor->DefaultRate(), ZM_WEB_DEFAULT_RATE);
|
||||
$rate = reScale(RATE_BASE, $monitor->DefaultRate(), ZM_WEB_DEFAULT_RATE);
|
||||
}
|
||||
|
||||
if (isset($_REQUEST['scale'])) {
|
||||
|
@ -52,20 +52,30 @@ if ( isset($_REQUEST['scale']) ) {
|
|||
} else if (isset($_COOKIE['zmEventScale'.$Event->MonitorId()])) {
|
||||
$scale = $_COOKIE['zmEventScale'.$Event->MonitorId()];
|
||||
} else {
|
||||
$scale = $Monitor->DefaultScale();
|
||||
$scale = $monitor->DefaultScale();
|
||||
}
|
||||
|
||||
$showZones = false;
|
||||
if (isset($_REQUEST['showZones'])) {
|
||||
$showZones = $_REQUEST['showZones'] == 1;
|
||||
$_SESSION['zmEventShowZones'.$monitor->Id()] = $showZones;
|
||||
} else if (isset($_COOKIE['zmEventShowZones'.$monitor->Id()])) {
|
||||
$showZones = $_COOKIE['zmEventShowZones'.$monitor->Id()] == 1;
|
||||
} else if (isset($_SESSION['zmEventShowZones'.$monitor->Id()]) ) {
|
||||
$showZones = $_SESSION['zmEventShowZones'.$monitor->Id()];
|
||||
}
|
||||
|
||||
$codec = 'auto';
|
||||
if (isset($_REQUEST['codec'])) {
|
||||
$codec = $_REQUEST['codec'];
|
||||
zm_session_start();
|
||||
$_SESSION['zmEventCodec'.$Event->MonitorId()] = $codec;
|
||||
session_write_close();
|
||||
} else if ( isset($_SESSION['zmEventCodec'.$Event->MonitorId()]) ) {
|
||||
$codec = $_SESSION['zmEventCodec'.$Event->MonitorId()];
|
||||
} else {
|
||||
$codec = $Monitor->DefaultCodec();
|
||||
$codec = $monitor->DefaultCodec();
|
||||
}
|
||||
session_write_close();
|
||||
|
||||
$codecs = array(
|
||||
'auto' => translate('Auto'),
|
||||
'MP4' => translate('MP4'),
|
||||
|
@ -90,18 +100,16 @@ if ( isset($_REQUEST['replayMode']) )
|
|||
if (isset($_COOKIE['replayMode']) && preg_match('#^[a-z]+$#', $_COOKIE['replayMode']))
|
||||
$replayMode = validHtmlStr($_COOKIE['replayMode']);
|
||||
|
||||
if ( ( !$replayMode ) or ( !$replayModes[$replayMode] ) ) {
|
||||
if ((!$replayMode) or !$replayModes[$replayMode]) {
|
||||
$replayMode = 'none';
|
||||
}
|
||||
|
||||
$video_tag = false;
|
||||
if ( $Event->DefaultVideo() and ( $codec == 'MP4' or $codec == 'auto' ) ) {
|
||||
$video_tag = true;
|
||||
}
|
||||
$video_tag = ($Event->DefaultVideo() and ($codec == 'MP4' or $codec == 'auto'));
|
||||
|
||||
// videojs zoomrotate only when direct recording
|
||||
$Zoom = 1;
|
||||
$Rotation = 0;
|
||||
if ( $Monitor->VideoWriter() == '2' ) {
|
||||
if ($monitor->VideoWriter() == '2') {
|
||||
# Passthrough
|
||||
$Rotation = $Event->Orientation();
|
||||
if (in_array($Event->Orientation(),array('90','270')))
|
||||
|
@ -158,7 +166,13 @@ if ( $Event->Id() and !file_exists($Event->Path()) )
|
|||
<button id="statsBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Stats') ?>" ><i class="fa fa-info"></i></button>
|
||||
<button id="framesBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Frames') ?>" ><i class="fa fa-picture-o"></i></button>
|
||||
<button id="deleteBtn" class="btn btn-danger" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Delete') ?>"><i class="fa fa-trash"></i></button>
|
||||
<?php } // end if Event->Id ?>
|
||||
<?php
|
||||
if (canView('System')) { ?>
|
||||
<button id="toggleZonesButton" class="btn btn-<?php echo $showZones?'normal':'secondary'?>" title="<?php echo translate(($showZones?'Hide':'Show').' Zones')?>" ><span class="material-icons"><?php echo $showZones?'layers_clear':'layers'?></span</button>
|
||||
<?php
|
||||
}
|
||||
} // end if Event->Id
|
||||
?>
|
||||
</div>
|
||||
|
||||
<h2><?php echo translate('Event').' '.$Event->Id() ?></h2>
|
||||
|
@ -190,10 +204,10 @@ if ( $Event->Id() and !file_exists($Event->Path()) )
|
|||
<div class="">
|
||||
<div id="eventVideo">
|
||||
<!-- VIDEO CONTENT -->
|
||||
<div id="videoFeed">
|
||||
<?php
|
||||
if ($video_tag) {
|
||||
?>
|
||||
<div id="videoFeed">
|
||||
<video autoplay id="videoobj" class="video-js vjs-default-skin"
|
||||
style="transform: matrix(1, 0, 0, 1, 0, 0);"
|
||||
<?php echo $scale ? 'width="'.reScale($Event->Width(), $scale).'"' : '' ?>
|
||||
|
@ -209,21 +223,17 @@ if ( $video_tag ) {
|
|||
<track id="monitorCaption" kind="captions" label="English" srclang="en" src='data:plain/text;charset=utf-8,"WEBVTT\n\n 00:00:00.000 --> 00:00:01.000 ZoneMinder"' default/>
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</div><!--videoFeed-->
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<div id="imageFeed">
|
||||
<?php
|
||||
if ( (ZM_WEB_STREAM_METHOD == 'mpeg') && ZM_MPEG_LIVE_FORMAT ) {
|
||||
$streamSrc = $Event->getStreamSrc(array('mode'=>'mpeg', 'scale'=>$scale, 'rate'=>$rate, 'bitrate'=>ZM_WEB_VIDEO_BITRATE, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'format'=>ZM_MPEG_REPLAY_FORMAT, 'replay'=>$replayMode),'&');
|
||||
outputVideoStream('evtStream', $streamSrc, reScale( $Event->Width(), $scale ).'px', reScale( $Event->Height(), $scale ).'px', ZM_MPEG_LIVE_FORMAT );
|
||||
} else {
|
||||
$streamSrc = $Event->getStreamSrc(array('mode'=>'jpeg', 'frame'=>$fid, 'scale'=>$scale, 'rate'=>$rate, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'replay'=>$replayMode),'&');
|
||||
if ( canStreamNative() ) {
|
||||
outputImageStream('evtStream', $streamSrc, reScale($Event->Width(), $scale).'px', reScale($Event->Height(), $scale).'px', validHtmlStr($Event->Name()));
|
||||
outputImageStream('evtStream', $streamSrc, '100%', '100%', validHtmlStr($Event->Name()));
|
||||
} else {
|
||||
outputHelperStream('evtStream', $streamSrc, reScale($Event->Width(), $scale).'px', reScale($Event->Height(), $scale).'px' );
|
||||
outputHelperStream('evtStream', $streamSrc, '100%', '100%');
|
||||
}
|
||||
} // end if stream method
|
||||
?>
|
||||
|
@ -231,10 +241,18 @@ if ( (ZM_WEB_STREAM_METHOD == 'mpeg') && ZM_MPEG_LIVE_FORMAT ) {
|
|||
<div id="progressBar" style="width: <?php echo reScale($Event->Width(), $scale);?>px;">
|
||||
<div class="progressBox" id="progressBox" title="" style="width: 0%;"></div>
|
||||
</div><!--progressBar-->
|
||||
</div><!--imageFeed-->
|
||||
<?php
|
||||
} /*end if !DefaultVideo*/
|
||||
?>
|
||||
<svg class="zones" id="zones<?php echo $monitor->Id() ?>" style="display:<?php echo $showZones ? 'block' : 'none'; ?>" viewBox="0 0 <?php echo $monitor->ViewWidth().' '.$monitor->ViewHeight() ?>" preserveAspectRatio="none">
|
||||
<?php
|
||||
foreach (ZM\Zone::find(array('MonitorId'=>$monitor->Id()), array('order'=>'Area DESC')) as $zone) {
|
||||
echo $zone->svg_polygon();
|
||||
} // end foreach zone
|
||||
?>
|
||||
Sorry, your browser does not support inline SVG
|
||||
</svg>
|
||||
</div><!--videoFeed-->
|
||||
<p id="dvrControls">
|
||||
<button type="button" id="prevBtn" title="<?php echo translate('Prev') ?>" class="inactive" data-on-click-true="streamPrev">
|
||||
<i class="material-icons md-18">skip_previous</i>
|
||||
|
@ -283,4 +301,7 @@ echo htmlSelect('rate', $rates, intval($rate), array('id'=>'rateValue'));
|
|||
</div><!--content-->
|
||||
|
||||
</div><!--page-->
|
||||
<?php xhtmlFooter() ?>
|
||||
<?php
|
||||
echo output_link_if_exists(array('css/base/zones.css'));
|
||||
xhtmlFooter();
|
||||
?>
|
||||
|
|
|
@ -152,7 +152,7 @@ $booleanValues = array(
|
|||
|
||||
$focusWindow = true;
|
||||
|
||||
$storageareas = array('' => 'All') + ZM\ZM_Object::Objects_Indexed_By_Id('ZM\Storage');
|
||||
$storageareas = array('' => array('Name'=>'NULL Unspecified'), '0' => array('Name'=>'Zero')) + ZM\ZM_Object::Objects_Indexed_By_Id('ZM\Storage');
|
||||
|
||||
$weekdays = array();
|
||||
for ( $i = 0; $i < 7; $i++ ) {
|
||||
|
|
|
@ -177,7 +177,7 @@ function changeScale() {
|
|||
var newWidth;
|
||||
var newHeight;
|
||||
var autoScale;
|
||||
var eventViewer= $j(vid ? '#videoobj' : '#evtStream');
|
||||
var eventViewer= $j(vid ? '#videoobj' : '#videoFeed');
|
||||
var alarmCue = $j('div.alarmCue');
|
||||
var bottomEl = $j('#replayStatus');
|
||||
|
||||
|
@ -773,8 +773,9 @@ function manageDelConfirmModalBtns() {
|
|||
return;
|
||||
}
|
||||
|
||||
pauseClicked();
|
||||
evt.preventDefault();
|
||||
$j.getJSON(thisUrl + '?request=event&task=delete&id='+eventData.Id)
|
||||
$j.getJSON(thisUrl + '?request=event&action=delete&id='+eventData.Id)
|
||||
.done(function(data) {
|
||||
$j('#deleteConfirm').modal('hide');
|
||||
streamNext(true);
|
||||
|
@ -909,12 +910,12 @@ function initPage() {
|
|||
progressBarNav();
|
||||
streamCmdTimer = setTimeout(streamQuery, 500);
|
||||
if (canStreamNative) {
|
||||
if (!$j('#imageFeed')) {
|
||||
console.log('No element with id tag imageFeed found.');
|
||||
if (!$j('#videoFeed')) {
|
||||
console.log('No element with id tag videoFeed found.');
|
||||
} else {
|
||||
var streamImg = $j('#imageFeed img');
|
||||
var streamImg = $j('#videoFeed img');
|
||||
if (!streamImg) {
|
||||
streamImg = $j('#imageFeed object');
|
||||
streamImg = $j('#videoFeed object');
|
||||
}
|
||||
$j(streamImg).click(function(event) {
|
||||
handleClick(event);
|
||||
|
@ -1070,5 +1071,27 @@ function initPage() {
|
|||
});
|
||||
} // end initPage
|
||||
|
||||
document.getElementById('toggleZonesButton').addEventListener('click', toggleZones);
|
||||
|
||||
function toggleZones(e) {
|
||||
const zones = $j('#zones'+eventData.MonitorId);
|
||||
const button = document.getElementById('toggleZonesButton');
|
||||
if (zones.length) {
|
||||
if (zones.is(":visible")) {
|
||||
zones.hide();
|
||||
button.setAttribute('title', showZonesString);
|
||||
button.innerHTML = '<span class="material-icons">layers</span>';
|
||||
setCookie('zmEventShowZones'+eventData.MonitorId, '0', 3600);
|
||||
} else {
|
||||
zones.show();
|
||||
button.setAttribute('title', hideZonesString);
|
||||
button.innerHTML = '<span class="material-icons">layers_clear</span>';
|
||||
setCookie('zmEventShowZones'+eventData.MonitorId, '1', 3600);
|
||||
}
|
||||
} else {
|
||||
console.error("Zones svg not found");
|
||||
}
|
||||
}
|
||||
|
||||
// Kick everything off
|
||||
$j(document).ready(initPage);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
global $connkey;
|
||||
global $Event;
|
||||
global $Monitor;
|
||||
global $monitor;
|
||||
global $filterQuery;
|
||||
global $sortQuery;
|
||||
global $rates;
|
||||
|
@ -43,8 +43,9 @@ var eventData = {
|
|||
Id: '<?php echo $Event->Id() ?>',
|
||||
Name: '<?php echo $Event->Name() ?>',
|
||||
MonitorId: '<?php echo $Event->MonitorId() ?>',
|
||||
MonitorName: '<?php echo validJsStr($Monitor->Name()) ?>',
|
||||
MonitorName: '<?php echo validJsStr($monitor->Name()) ?>',
|
||||
Cause: '<?php echo validHtmlStr($Event->Cause()) ?>',
|
||||
Notes: '<?php echo $Event->Notes()?>',
|
||||
Width: '<?php echo $Event->Width() ?>',
|
||||
Height: '<?php echo $Event->Height() ?>',
|
||||
Length: '<?php echo $Event->Length() ?>',
|
||||
|
@ -72,6 +73,7 @@ var eventDataStrings = {
|
|||
MonitorId: '<?php echo translate('AttrMonitorId') ?>',
|
||||
MonitorName: '<?php echo translate('AttrMonitorName') ?>',
|
||||
Cause: '<?php echo translate('Cause') ?>',
|
||||
Notes: '<?php echo translate('Notes') ?>',
|
||||
StartDateTimeShort: '<?php echo translate('AttrStartTime') ?>',
|
||||
Length: '<?php echo translate('Duration') ?>',
|
||||
Frames: '<?php echo translate('AttrFrames') ?>',
|
||||
|
@ -93,7 +95,7 @@ var sortQuery = '<?php echo isset($sortQuery)?validJsStr(htmlspecialchars_decode
|
|||
var rates = <?php echo json_encode(array_keys($rates)) ?>;
|
||||
var rate = '<?php echo $rate ?>'; // really only used when setting up initial playback rate.
|
||||
var scale = "<?php echo $scale ?>";
|
||||
var LabelFormat = "<?php echo validJsStr($Monitor->LabelFormat())?>";
|
||||
var LabelFormat = "<?php echo validJsStr($monitor->LabelFormat())?>";
|
||||
|
||||
var streamTimeout = <?php echo 1000*ZM_WEB_REFRESH_STATUS ?>;
|
||||
|
||||
|
@ -105,6 +107,8 @@ var streamMode = '<?php echo $streamMode ?>';
|
|||
//
|
||||
var deleteString = "<?php echo validJsStr(translate('Delete')) ?>";
|
||||
var causeString = "<?php echo validJsStr(translate('AttrCause')) ?>";
|
||||
var showZonesString = "<?php echo validJsStr(translate('Show Zones'))?>";
|
||||
var hideZonesString = "<?php echo validJsStr(translate('Hide Zones'))?>";
|
||||
var WEB_LIST_THUMB_WIDTH = '<?php echo ZM_WEB_LIST_THUMB_WIDTH ?>';
|
||||
var WEB_LIST_THUMB_HEIGHT = '<?php echo ZM_WEB_LIST_THUMB_HEIGHT ?>';
|
||||
var popup = '<?php echo $popup ?>';
|
||||
|
|
|
@ -63,13 +63,13 @@ function processRows(rows) {
|
|||
|
||||
row.Id = '<a href="?view=event&eid=' + eid + filterQuery + sortQuery + '&page=1">' + eid + '</a>';
|
||||
row.Name = '<a href="?view=event&eid=' + eid + filterQuery + sortQuery + '&page=1">' + row.Name + '</a>' +
|
||||
'<br/><div class="small text-nowrap text-muted">' + archived + emailed + '</div>';
|
||||
'<br/><div class="small text-muted">' + archived + emailed + '</div>';
|
||||
if ( canEdit.Monitors ) row.Monitor = '<a href="?view=event&eid=' + eid + '">' + row.Monitor + '</a>';
|
||||
if ( canEdit.Events ) row.Cause = '<a href="#" title="' + row.Notes + '" class="eDetailLink" data-eid="' + eid + '">' + row.Cause + '</a>';
|
||||
if ( row.Notes.indexOf('detected:') >= 0 ) {
|
||||
row.Cause = row.Cause + '<a href="#" class="objDetectLink" data-eid=' +eid+ '><div class="small text-nowrap text-muted"><u>' + row.Notes + '</u></div></div></a>';
|
||||
row.Cause = row.Cause + '<a href="#" class="objDetectLink" data-eid=' +eid+ '><div class="small text-muted"><u>' + row.Notes + '</u></div></div></a>';
|
||||
} else if ( row.Notes != 'Forced Web: ' ) {
|
||||
row.Cause = row.Cause + '<br/><div class="small text-nowrap text-muted">' + row.Notes + '</div>';
|
||||
row.Cause = row.Cause + '<br/><div class="small text-muted">' + row.Notes + '</div>';
|
||||
}
|
||||
row.Frames = '<a href="?view=frames&eid=' + eid + '">' + row.Frames + '</a>';
|
||||
row.AlarmFrames = '<a href="?view=frames&eid=' + eid + '">' + row.AlarmFrames + '</a>';
|
||||
|
|
|
@ -1,18 +1,6 @@
|
|||
//
|
||||
// Import constants
|
||||
//
|
||||
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 CMD_QUERY = <?php echo CMD_QUERY ?>;
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ function getFrame(monId, time, last_Frame) {
|
|||
|
||||
var events_for_monitor = events_by_monitor_id[monId];
|
||||
if ( !events_for_monitor ) {
|
||||
console.log("No events for monitor " + monId);
|
||||
//console.log("No events for monitor " + monId);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -648,8 +648,11 @@ function setSpeed(speed_index) {
|
|||
}
|
||||
|
||||
function setLive(value) {
|
||||
// When we submit the context etc goes away but we may still be trying to update
|
||||
// So kill the timer.
|
||||
clearInterval(timerObj);
|
||||
liveMode = value;
|
||||
var form = $j('#montagereview_form')[0];
|
||||
var form = document.getElementById('montagereview_form');
|
||||
form.elements['live'].value = value;
|
||||
form.submit();
|
||||
return false;
|
||||
|
@ -985,6 +988,19 @@ function initPage() {
|
|||
});
|
||||
});
|
||||
|
||||
if ( !liveMode ) {
|
||||
canvas = document.getElementById('timeline');
|
||||
|
||||
canvas.addEventListener('mousemove', mmove, false);
|
||||
canvas.addEventListener('touchmove', tmove, false);
|
||||
canvas.addEventListener('mousedown', mdown, false);
|
||||
canvas.addEventListener('mouseup', mup, false);
|
||||
canvas.addEventListener('mouseout', mout, false);
|
||||
|
||||
ctx = canvas.getContext('2d');
|
||||
drawGraph();
|
||||
}
|
||||
|
||||
for ( var i = 0, len = monitorPtr.length; i < len; i += 1 ) {
|
||||
var monId = monitorPtr[i];
|
||||
if ( !monId ) continue;
|
||||
|
@ -1006,18 +1022,6 @@ function initPage() {
|
|||
}
|
||||
} // end foreach monitor
|
||||
|
||||
if ( !liveMode ) {
|
||||
canvas = document.getElementById('timeline');
|
||||
|
||||
canvas.addEventListener('mousemove', mmove, false);
|
||||
canvas.addEventListener('touchmove', tmove, false);
|
||||
canvas.addEventListener('mousedown', mdown, false);
|
||||
canvas.addEventListener('mouseup', mup, false);
|
||||
canvas.addEventListener('mouseout', mout, false);
|
||||
|
||||
ctx = canvas.getContext('2d');
|
||||
drawGraph();
|
||||
}
|
||||
setSpeed(speedIndex);
|
||||
//setFit(fitMode); // will redraw
|
||||
//setLive(liveMode); // will redraw
|
||||
|
|
|
@ -239,6 +239,6 @@ echo "];\n";
|
|||
var cWidth; // save canvas width
|
||||
var cHeight; // save canvas height
|
||||
var canvas; // global canvas definition so we don't have to keep looking it up
|
||||
var ctx;
|
||||
var ctx = null;
|
||||
var underSlider; // use this to hold what is hidden by the slider
|
||||
var underSliderX; // Where the above was taken from (left side, Y is zero)
|
||||
|
|
|
@ -94,8 +94,48 @@ function showPtzControls() {
|
|||
showMode = 'control';
|
||||
}
|
||||
|
||||
function changeSize() {
|
||||
var width = $j('#width').val();
|
||||
var height = $j('#height').val();
|
||||
|
||||
// Scale the frame
|
||||
monitor_frame = $j('#imageFeed');
|
||||
if (!monitor_frame) {
|
||||
console.log('Error finding frame');
|
||||
return;
|
||||
}
|
||||
if (width) monitor_frame.css('width', width);
|
||||
if (height) monitor_frame.css('height', height);
|
||||
|
||||
var streamImg = document.getElementById('liveStream'+monitorData[monIdx].id);
|
||||
if (streamImg) {
|
||||
if (streamImg.nodeName == 'IMG') {
|
||||
let src = streamImg.src;
|
||||
streamImg.src = '';
|
||||
src = src.replace(/width=[\.\d]+/i, 'width='+parseInt(width));
|
||||
src = src.replace(/height=[\.\d]+/i, 'height='+parseInt(height));
|
||||
src = src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) ));
|
||||
streamImg.src = src;
|
||||
}
|
||||
streamImg.style.width = width ? width : null;
|
||||
streamImg.style.height = height ? height : null;
|
||||
} else {
|
||||
console.log('Did not find liveStream'+monitorData[monIdx].id);
|
||||
}
|
||||
$j('#scale').val('');
|
||||
setCookie('zmCycleScale', '', 3600);
|
||||
setCookie('zmCycleWidth', width, 3600);
|
||||
setCookie('zmCycleHeight', height, 3600);
|
||||
} // end function changeSize()
|
||||
|
||||
function changeScale() {
|
||||
var scale = $j('#scale').val();
|
||||
$j('#width').val('auto');
|
||||
$j('#height').val('auto');
|
||||
setCookie('zmCycleScale', scale, 3600);
|
||||
setCookie('zmCycleWidth', 'auto', 3600);
|
||||
setCookie('zmCycleHeight', 'auto', 3600);
|
||||
|
||||
var newWidth;
|
||||
var newHeight;
|
||||
var autoScale;
|
||||
|
@ -104,7 +144,7 @@ function changeScale() {
|
|||
// times and what the consequences would be
|
||||
$j(window).off('resize', endOfResize); //remove resize handler when Scale to Fit is not active
|
||||
if (scale == '0' || scale == 'auto') {
|
||||
var newSize = scaleToFit(monitorWidth, monitorHeight, $j('#liveStream'+monitorId), $j('#replayStatus'));
|
||||
const newSize = scaleToFit(monitorWidth, monitorHeight, $j('#liveStream'+monitorId), $j('#replayStatus'));
|
||||
newWidth = newSize.width;
|
||||
newHeight = newSize.height;
|
||||
autoScale = newSize.autoScale;
|
||||
|
@ -118,16 +158,18 @@ function changeScale() {
|
|||
|
||||
var streamImg = $j('#liveStream'+monitorId);
|
||||
if (streamImg) {
|
||||
var oldSrc = streamImg.attr('src');
|
||||
if (streamImg.nodeName == 'IMG') {
|
||||
const oldSrc = streamImg.attr('src');
|
||||
streamImg.attr('src', '');
|
||||
// This is so that we don't waste bandwidth and let the browser do all the scaling.
|
||||
if (autoScale > 100) autoScale = 100;
|
||||
if (scale > 100) scale = 100;
|
||||
var newSrc = oldSrc.replace(/scale=\d+/i, 'scale='+((scale == 'auto' || scale == '0') ? autoScale : scale));
|
||||
const newSrc = oldSrc.replace(/scale=\d+/i, 'scale='+((scale == 'auto' || scale == '0') ? autoScale : scale));
|
||||
|
||||
streamImg.width(newWidth);
|
||||
streamImg.height(newHeight);
|
||||
streamImg.attr('src', newSrc);
|
||||
}
|
||||
} else {
|
||||
console.error('No element found for liveStream'+monitorId);
|
||||
}
|
||||
|
@ -200,9 +242,15 @@ function getStreamCmdResponse(respObj, respText) {
|
|||
// The get status command can get backed up, in which case we won't be able to get the semaphore and will exit.
|
||||
if (respObj.status) {
|
||||
streamStatus = respObj.status;
|
||||
$j('#fpsValue').text(streamStatus.fps);
|
||||
$j('#capturefpsValue').text(streamStatus.capturefps);
|
||||
$j('#analysisfpsValue').text(streamStatus.analysisfps);
|
||||
if ($j('#viewingFPSValue').text() != streamStatus.fps) {
|
||||
$j('#viewingFPSValue').text(streamStatus.fps);
|
||||
}
|
||||
if ($j('#captureFPSValue').text() != streamStatus.capturefps) {
|
||||
$j('#captureFPSValue').text(streamStatus.capturefps);
|
||||
}
|
||||
if ($j('#analysisFPSValue').text() != streamStatus.analysisfps) {
|
||||
$j('#analysisFPSValue').text(streamStatus.analysisfps);
|
||||
}
|
||||
|
||||
setAlarmState(streamStatus.state);
|
||||
|
||||
|
@ -287,31 +335,19 @@ function getStreamCmdResponse(respObj, respText) {
|
|||
// Try to reload the image stream.
|
||||
var streamImg = $j('#liveStream'+monitorId);
|
||||
if (streamImg) {
|
||||
var oldSrc = streamImg.attr('src');
|
||||
var newSrc = oldSrc.replace(/auth=\w+/i, 'auth='+streamStatus.auth);
|
||||
const oldSrc = streamImg.attr('src');
|
||||
if (oldSrc) {
|
||||
const newSrc = oldSrc.replace(/auth=\w+/i, 'auth='+streamStatus.auth);
|
||||
if (oldSrc != newSrc) {
|
||||
streamImg.attr('src', newSrc);
|
||||
table.bootstrapTable('refresh');
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end if have a new auth hash
|
||||
} // end if respObj.status
|
||||
} else {
|
||||
checkStreamForErrors('getStreamCmdResponse', respObj);//log them
|
||||
// Try to reload the image stream.
|
||||
// If it's an auth error, we should reload the whole page.
|
||||
console.log("have error");
|
||||
//window.location.reload();
|
||||
var streamImg = $j('#liveStream'+monitorId);
|
||||
if (streamImg) {
|
||||
var oldSrc = streamImg.attr('src');
|
||||
var newSrc = oldSrc.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) ));
|
||||
|
||||
streamImg.attr('src', newSrc);
|
||||
console.log('Changing livestream src to ' + newSrc);
|
||||
} else {
|
||||
console.log('Unable to find streamImg liveStream');
|
||||
}
|
||||
}
|
||||
|
||||
var streamCmdTimeout = statusRefreshTimeout;
|
||||
|
@ -368,6 +404,7 @@ function streamCmdPlay(action) {
|
|||
}
|
||||
|
||||
function streamCmdReq(data) {
|
||||
if (auth_hash) data.auth = auth_hash;
|
||||
$j.getJSON(monitorUrl + '?view=request&request=stream&connkey='+connKey, data)
|
||||
.done(getStreamCmdResponse)
|
||||
.fail(getStreamCmdError);
|
||||
|
@ -386,10 +423,7 @@ function streamCmdStop(action) {
|
|||
setButtonState('fastRevBtn', 'unavail');
|
||||
}
|
||||
if (action) {
|
||||
var data = {};
|
||||
if (auth_hash) data.auth = auth_hash;
|
||||
data.command = CMD_STOP;
|
||||
streamCmdReq(data);
|
||||
streamCmdReq({command: CMD_STOP});
|
||||
}
|
||||
setButtonState('stopBtn', 'unavail');
|
||||
setButtonState('playBtn', 'active');
|
||||
|
@ -407,7 +441,6 @@ function streamCmdFastFwd(action) {
|
|||
}
|
||||
if (action) {
|
||||
var data = {};
|
||||
if (auth_hash) data.auth = auth_hash;
|
||||
data.command = CMD_FASTFWD;
|
||||
streamCmdReq(data);
|
||||
}
|
||||
|
@ -425,7 +458,6 @@ function streamCmdSlowFwd(action) {
|
|||
}
|
||||
if (action) {
|
||||
var data = {};
|
||||
if (auth_hash) data.auth = auth_hash;
|
||||
data.command = CMD_SLOWFWD;
|
||||
streamCmdReq(data);
|
||||
}
|
||||
|
@ -447,7 +479,6 @@ function streamCmdSlowRev(action) {
|
|||
}
|
||||
if (action) {
|
||||
var data = {};
|
||||
if (auth_hash) data.auth = auth_hash;
|
||||
data.command = CMD_SLOWREV;
|
||||
streamCmdReq(data);
|
||||
}
|
||||
|
@ -469,7 +500,6 @@ function streamCmdFastRev(action) {
|
|||
}
|
||||
if (action) {
|
||||
var data = {};
|
||||
if (auth_hash) data.auth = auth_hash;
|
||||
data.command = CMD_FASTREV;
|
||||
streamCmdReq(data);
|
||||
}
|
||||
|
@ -477,7 +507,6 @@ function streamCmdFastRev(action) {
|
|||
|
||||
function streamCmdZoomIn(x, y) {
|
||||
var data = {};
|
||||
if (auth_hash) data.auth = auth_hash;
|
||||
data.x = x;
|
||||
data.y = y;
|
||||
data.command = CMD_ZOOMIN;
|
||||
|
@ -486,14 +515,12 @@ function streamCmdZoomIn(x, y) {
|
|||
|
||||
function streamCmdZoomOut() {
|
||||
var data = {};
|
||||
if (auth_hash) data.auth = auth_hash;
|
||||
data.command = CMD_ZOOMOUT;
|
||||
streamCmdReq(data);
|
||||
}
|
||||
|
||||
function streamCmdScale(scale) {
|
||||
var data = {};
|
||||
if (auth_hash) data.auth = auth_hash;
|
||||
data.command = CMD_SCALE;
|
||||
data.scale = scale;
|
||||
streamCmdReq(data);
|
||||
|
@ -501,7 +528,6 @@ function streamCmdScale(scale) {
|
|||
|
||||
function streamCmdPan(x, y) {
|
||||
var data = {};
|
||||
if (auth_hash) data.auth = auth_hash;
|
||||
data.x = x;
|
||||
data.y = y;
|
||||
data.command = CMD_PAN;
|
||||
|
@ -510,11 +536,11 @@ function streamCmdPan(x, y) {
|
|||
|
||||
function streamCmdQuery() {
|
||||
var data = {};
|
||||
if (auth_hash) data.auth = auth_hash;
|
||||
data.command = CMD_QUERY;
|
||||
streamCmdReq(data);
|
||||
}
|
||||
|
||||
/* getStatusCmd is used when not streaming, since there is no persistent zms */
|
||||
function getStatusCmdResponse(respObj, respText) {
|
||||
watchdogOk('status');
|
||||
if (statusCmdTimer) {
|
||||
|
@ -522,7 +548,7 @@ function getStatusCmdResponse(respObj, respText) {
|
|||
}
|
||||
|
||||
if (respObj.result == 'Ok') {
|
||||
$j('#fpsValue').text(respObj.monitor.FrameRate);
|
||||
$j('#captureFPSValue').text(respObj.monitor.FrameRate);
|
||||
setAlarmState(respObj.monitor.Status);
|
||||
} else {
|
||||
checkStreamForErrors('getStatusCmdResponse', respObj);
|
||||
|
@ -536,18 +562,19 @@ function getStatusCmdResponse(respObj, respText) {
|
|||
}
|
||||
|
||||
function statusCmdQuery() {
|
||||
$j.getJSON(monitorUrl + '?view=request&request=status&entity=monitor&element[]=Status&element[]=FrameRate&id='+monitorId)
|
||||
$j.getJSON(monitorUrl + '?view=request&request=status&entity=monitor&element[]=Status&element[]=FrameRate&id='+monitorId+'&'+auth_relay)
|
||||
.done(getStatusCmdResponse)
|
||||
.fail(logAjaxFail);
|
||||
|
||||
streamCmdTimer = null;
|
||||
statusCmdTimer = null;
|
||||
}
|
||||
|
||||
function alarmCmdReq(data) {
|
||||
if (auth_hash) data.auth = auth_hash;
|
||||
$j.getJSON(monitorUrl + '?view=request&request=alarm&id='+monitorId, data)
|
||||
.done(getAlarmCmdResponse)
|
||||
.fail(function(jqxhr, textStatus, error) {
|
||||
if ( textStatus === "timeout" ) {
|
||||
if (textStatus === 'timeout') {
|
||||
streamCmdQuery();
|
||||
} else {
|
||||
logAjaxFail(jqxhr, textStatus, error);
|
||||
|
@ -561,14 +588,12 @@ function getAlarmCmdResponse(respObj, respText) {
|
|||
|
||||
function cmdDisableAlarms() {
|
||||
var data = {};
|
||||
if (auth_hash) data.auth = auth_hash;
|
||||
data.command = 'disableAlarms';
|
||||
alarmCmdReq(data);
|
||||
}
|
||||
|
||||
function cmdEnableAlarms() {
|
||||
var data = {};
|
||||
if (auth_hash) data.auth = auth_hash;
|
||||
data.command = 'enableAlarms';
|
||||
alarmCmdReq(data);
|
||||
}
|
||||
|
@ -583,7 +608,6 @@ function cmdAlarm() {
|
|||
|
||||
function cmdForceAlarm() {
|
||||
var data = {};
|
||||
if (auth_hash) data.auth = auth_hash;
|
||||
data.command = 'forceAlarm';
|
||||
alarmCmdReq(data);
|
||||
if (window.event) window.event.preventDefault();
|
||||
|
@ -591,7 +615,6 @@ function cmdForceAlarm() {
|
|||
|
||||
function cmdCancelForcedAlarm() {
|
||||
var data = {};
|
||||
if (auth_hash) data.auth = auth_hash;
|
||||
data.command = 'cancelForcedAlarm';
|
||||
alarmCmdReq(data);
|
||||
if (window.event) window.event.preventDefault();
|
||||
|
@ -607,6 +630,7 @@ function cmdForce() {
|
|||
}
|
||||
|
||||
function controlReq(data) {
|
||||
if (auth_hash) data.auth = auth_hash;
|
||||
$j.getJSON(monitorUrl + '?view=request&request=control&id='+monitorId, data)
|
||||
.done(getControlResponse)
|
||||
.fail(logAjaxFail);
|
||||
|
@ -639,16 +663,16 @@ function controlCmd(event) {
|
|||
var data = {};
|
||||
|
||||
if (event && (xtell || ytell)) {
|
||||
var target = event.target;
|
||||
var offset = $j(target).offset();
|
||||
var width = $j(target).width();
|
||||
var height = $j(target).height();
|
||||
const target = event.target;
|
||||
const offset = $j(target).offset();
|
||||
const width = $j(target).width();
|
||||
const height = $j(target).height();
|
||||
|
||||
var x = event.pageX - offset.left;
|
||||
var y = event.pageY - offset.top;
|
||||
const x = event.pageX - offset.left;
|
||||
const y = event.pageY - offset.top;
|
||||
|
||||
if (xtell) {
|
||||
var xge = parseInt((x*100)/width);
|
||||
let xge = parseInt((x*100)/width);
|
||||
if (xtell == -1) {
|
||||
xge = 100 - xge;
|
||||
} else if (xtell == 2) {
|
||||
|
@ -657,7 +681,7 @@ function controlCmd(event) {
|
|||
data.xge = xge;
|
||||
}
|
||||
if (ytell) {
|
||||
var yge = parseInt((y*100)/height);
|
||||
let yge = parseInt((y*100)/height);
|
||||
if (ytell == -1) {
|
||||
yge = 100 - yge;
|
||||
} else if (ytell == 2) {
|
||||
|
@ -667,7 +691,6 @@ function controlCmd(event) {
|
|||
}
|
||||
}
|
||||
|
||||
if (auth_hash) data.auth = auth_hash;
|
||||
data.control = control;
|
||||
controlReq(data);
|
||||
|
||||
|
@ -678,7 +701,6 @@ function controlCmd(event) {
|
|||
|
||||
function controlCmdImage(x, y) {
|
||||
var data = {};
|
||||
if (auth_hash) data.auth = auth_hash;
|
||||
data.scale = scale;
|
||||
data.control = imageControlMode;
|
||||
data.x = x;
|
||||
|
@ -768,7 +790,6 @@ function reloadWebSite() {
|
|||
|
||||
function updatePresetLabels() {
|
||||
var lblNdx = $j('#ctrlPresetForm option:selected').val();
|
||||
|
||||
$j('#newLabel').val(labels[lblNdx]);
|
||||
}
|
||||
|
||||
|
@ -878,7 +899,7 @@ function initPage() {
|
|||
// Load the PTZ Preset modal into the DOM
|
||||
if (monitorControllable) getCtrlPresetModal();
|
||||
// Load the settings modal into the DOM
|
||||
if (monitorType == "Local") getSettingsModal();
|
||||
if (monitorType == 'Local') getSettingsModal();
|
||||
}
|
||||
|
||||
if (monitorType != 'WebSite') {
|
||||
|
@ -886,15 +907,12 @@ function initPage() {
|
|||
statusCmdTimer = setTimeout(statusCmdQuery, (Math.random()+0.1)*statusRefreshTimeout);
|
||||
setInterval(watchdogCheck, statusRefreshTimeout*2, 'status');
|
||||
} else {
|
||||
streamCmdTimer = setTimeout(streamCmdQuery, (Math.random()+0.1)*statusRefreshTimeout);
|
||||
setInterval(watchdogCheck, statusRefreshTimeout*2, 'stream');
|
||||
}
|
||||
|
||||
if (canStreamNative || (streamMode == 'single')) {
|
||||
var streamImg = $j('#imageFeed img');
|
||||
if (!streamImg) {
|
||||
streamImg = $j('#imageFeed object');
|
||||
}
|
||||
if (!streamImg) streamImg = $j('#imageFeed object');
|
||||
if (!streamImg) {
|
||||
console.error('No streamImg found for imageFeed');
|
||||
} else {
|
||||
|
@ -905,6 +923,10 @@ function initPage() {
|
|||
streamImg.click(function(event) {
|
||||
handleClick(event);
|
||||
});
|
||||
streamImg.on("error", function(thing) {
|
||||
console.log("Error loading image");
|
||||
console.log(thing);
|
||||
});
|
||||
}
|
||||
} // end if have streamImg
|
||||
} // streamMode native or single
|
||||
|
@ -944,6 +966,18 @@ function initPage() {
|
|||
$j('#settingsModal').modal('show');
|
||||
});
|
||||
|
||||
bindButton('#cyclePlayBtn', 'click', null, cycleStart);
|
||||
bindButton('#cyclePauseBtn', 'click', null, cyclePause);
|
||||
bindButton('#cycleNextBtn', 'click', null, cycleNext);
|
||||
bindButton('#cyclePrevBtn', 'click', null, cyclePrev);
|
||||
bindButton('#cycleToggle', 'click', null, cycleToggle);
|
||||
bindButton('#cyclePeriod', 'change', null, cyclePeriodChange);
|
||||
if (cycle) {
|
||||
cycleStart();
|
||||
} else {
|
||||
cyclePause();
|
||||
}
|
||||
|
||||
// Only enable the settings button for local cameras
|
||||
settingsBtn.prop('disabled', !(canView.Control && (monitorType == 'Local')));
|
||||
|
||||
|
@ -972,7 +1006,6 @@ function initPage() {
|
|||
|
||||
function watchFullscreen() {
|
||||
const btn = document.getElementById('fullscreenBtn');
|
||||
console.log(btn);
|
||||
if (btn.firstElementChild.innerHTML=='fullscreen') {
|
||||
const content = document.getElementById('content');
|
||||
openFullscreen(content);
|
||||
|
@ -985,5 +1018,70 @@ function watchFullscreen() {
|
|||
}
|
||||
}
|
||||
|
||||
var intervalId;
|
||||
var secondsToCycle = 0;
|
||||
|
||||
function nextCycleView() {
|
||||
secondsToCycle --;
|
||||
if (secondsToCycle<=0) {
|
||||
window.location.replace('?view=watch&mid='+nextMid+'&mode='+mode+'&cycle=true');
|
||||
}
|
||||
$j('#secondsToCycle').text(secondsToCycle);
|
||||
}
|
||||
|
||||
function cyclePause() {
|
||||
clearInterval(intervalId);
|
||||
$j('#cyclePauseBtn').hide();
|
||||
$j('#cyclePlayBtn').show();
|
||||
}
|
||||
|
||||
function cycleStart() {
|
||||
secondsToCycle = $j('#cyclePeriod').val();
|
||||
intervalId = setInterval(nextCycleView, 1000);
|
||||
$j('#cyclePauseBtn').show();
|
||||
$j('#cyclePlayBtn').hide();
|
||||
}
|
||||
|
||||
function cycleNext() {
|
||||
monIdx ++;
|
||||
if (monIdx >= monitorData.length) {
|
||||
monIdx = 0;
|
||||
}
|
||||
if (!monitorData[monIdx]) {
|
||||
console.log('No monitorData for ' + monIdx);
|
||||
}
|
||||
window.location.replace('?view=watch&cycle=true&mid='+monitorData[monIdx].id+'&mode='+mode);
|
||||
}
|
||||
|
||||
function cyclePrev() {
|
||||
monIdx --;
|
||||
if (monIdx < 0) {
|
||||
monIdx = monitorData.length - 1;
|
||||
}
|
||||
if (!monitorData[monIdx]) {
|
||||
console.log('No monitorData for ' + monIdx);
|
||||
}
|
||||
window.location.replace('?view=watch&cycle=true&mid='+monitorData[monIdx].id+'&mode='+mode);
|
||||
}
|
||||
|
||||
function cyclePeriodChange() {
|
||||
const cyclePeriodSelect = $j('#cyclePeriod');
|
||||
secondsToCycle = cyclePeriodSelect.val();
|
||||
setCookie('zmCyclePeriod', secondsToCycle, 3600);
|
||||
}
|
||||
function cycleToggle(e) {
|
||||
sidebar = $j('#sidebar');
|
||||
button = $j('#cycleToggle');
|
||||
if (sidebar.is(":visible")) {
|
||||
sidebar.hide();
|
||||
setCookie('zmCycleShow', false, 3600);
|
||||
} else {
|
||||
sidebar.show();
|
||||
setCookie('zmCycleShow', true, 3600);
|
||||
}
|
||||
button.toggleClass('btn-secondary');
|
||||
button.toggleClass('btn-primary');
|
||||
}
|
||||
|
||||
// Kick everything off
|
||||
$j(document).ready(initPage);
|
||||
|
|
|
@ -1,33 +1,20 @@
|
|||
<?php
|
||||
global $monIdx;
|
||||
global $nextMid;
|
||||
global $options;
|
||||
global $monitors;
|
||||
global $streamMode;
|
||||
global $showPtzControls;
|
||||
global $connkey;
|
||||
global $monitor;
|
||||
global $scale;
|
||||
global $labels;
|
||||
global $cycle;
|
||||
?>
|
||||
//
|
||||
// Import constants
|
||||
//
|
||||
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 deleteString = "<?php echo translate('Delete') ?>";
|
||||
|
||||
var enableAlarmsStr = "<?php echo translate('EnableAlarms') ?>";
|
||||
var disableAlarmsStr = "<?php echo translate('DisableAlarms') ?>";
|
||||
var forceAlarmStr = "<?php echo translate('ForceAlarm') ?>";
|
||||
var cancelForcedAlarmStr = "<?php echo translate('CancelForcedAlarm') ?>";
|
||||
|
||||
var CMD_NONE = <?php echo CMD_NONE ?>;
|
||||
var CMD_PAUSE = <?php echo CMD_PAUSE ?>;
|
||||
|
@ -46,14 +33,13 @@ var CMD_NEXT = <?php echo CMD_NEXT ?>;
|
|||
var CMD_SEEK = <?php echo CMD_SEEK ?>;
|
||||
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 POPUP_ON_ALARM = <?php echo ZM_WEB_POPUP_ON_ALARM ?>;
|
||||
var LIST_THUMBS = <?php echo ZM_WEB_LIST_THUMBS?'true':'false' ?>;
|
||||
|
||||
var streamMode = "<?php echo $streamMode ?>";
|
||||
var showMode = "<?php echo ($showPtzControls && !empty($control))?"control":"events" ?>";
|
||||
var cycle = <?php echo $cycle ? 'true' : 'false' ?>;
|
||||
|
||||
var connKey = '<?php echo $connkey ?>';
|
||||
var maxDisplayEvents = <?php echo 2 * MAX_EVENTS ?>;
|
||||
|
@ -67,6 +53,28 @@ var monitorRefresh = '<?php echo $monitor->Refresh() ?>';
|
|||
var monitorStreamReplayBuffer = <?php echo $monitor->StreamReplayBuffer() ?>;
|
||||
var monitorControllable = <?php echo $monitor->Controllable()?'true':'false' ?>;
|
||||
|
||||
var monIdx = '<?php echo $monIdx; ?>';
|
||||
var nextMid = "<?php echo isset($nextMid)?$nextMid:'' ?>";
|
||||
var mode = "<?php echo $options['mode'] ?>";
|
||||
|
||||
var monitorData = new Array();
|
||||
<?php
|
||||
foreach ($monitors as $monitor) {
|
||||
?>
|
||||
monitorData[monitorData.length] = {
|
||||
'id': <?php echo $monitor->Id() ?>,
|
||||
'width': <?php echo $monitor->ViewWidth() ?>,
|
||||
'height':<?php echo $monitor->ViewHeight() ?>,
|
||||
'url': '<?php echo $monitor->UrlToIndex() ?>',
|
||||
'onclick': function(){window.location.assign( '?view=watch&mid=<?php echo $monitor->Id() ?>' );},
|
||||
'type': '<?php echo $monitor->Type() ?>',
|
||||
'refresh': '<?php echo $monitor->Refresh() ?>'
|
||||
};
|
||||
<?php
|
||||
} // end foreach monitor
|
||||
?>
|
||||
|
||||
var SCALE_BASE = <?php echo SCALE_BASE ?>;
|
||||
var scale = '<?php echo $scale ?>';
|
||||
|
||||
var statusRefreshTimeout = <?php echo 1000*ZM_WEB_REFRESH_STATUS ?>;
|
||||
|
@ -75,17 +83,16 @@ var imageRefreshTimeout = <?php echo 1000*ZM_WEB_REFRESH_IMAGE ?>;
|
|||
|
||||
var canStreamNative = <?php echo canStreamNative()?'true':'false' ?>;
|
||||
|
||||
<?php
|
||||
var imageControlMode = '<?php
|
||||
$control = $monitor->Control();
|
||||
if ( $control->CanMoveMap() ) { ?>
|
||||
var imageControlMode = "moveMap";
|
||||
<?php } elseif ( $control->CanMoveRel() ) { ?>
|
||||
var imageControlMode = "movePseudoMap";
|
||||
<?php } elseif ( $control->CanMoveCon() ) { ?>
|
||||
var imageControlMode = "moveConMap";
|
||||
<?php } else { ?>
|
||||
var imageControlMode = null;
|
||||
<?php } ?>
|
||||
if ($control->CanMoveMap()) {
|
||||
echo 'moveMap';
|
||||
} else if ($control->CanMoveRel()) {
|
||||
echo 'movePseudoMap';
|
||||
} else if ($control->CanMoveCon()) {
|
||||
echo 'moveConMap';
|
||||
}
|
||||
?>';
|
||||
|
||||
var refreshApplet = <?php echo (canStreamApplet() && $streamMode == "jpeg")?'true':'false' ?>;
|
||||
var appletRefreshTime = <?php echo ZM_RELOAD_CAMBOZOLA ?>;
|
||||
|
@ -94,16 +101,17 @@ var labels = new Array();
|
|||
<?php
|
||||
$labels = array();
|
||||
foreach (dbFetchAll('SELECT * FROM ControlPresets WHERE MonitorId = ?', NULL, array($monitor->Id())) as $row) {
|
||||
$labels[$row['Preset']] = $row['Label'];
|
||||
}
|
||||
|
||||
foreach ($labels as $index=>$label) {
|
||||
?>
|
||||
labels[<?php echo validInt($index) ?>] = '<?php echo validJsStr($label) ?>';
|
||||
<?php
|
||||
$label = $labels[$row['Preset']] = $row['Label'];
|
||||
echo 'labels['. validInt($index) .'] = '.validJsStr($label).'\'';
|
||||
}
|
||||
?>
|
||||
var deleteString = "<?php echo translate('Delete') ?>";
|
||||
var enableAlarmsStr = "<?php echo translate('EnableAlarms') ?>";
|
||||
var disableAlarmsStr = "<?php echo translate('DisableAlarms') ?>";
|
||||
var forceAlarmStr = "<?php echo translate('ForceAlarm') ?>";
|
||||
var cancelForcedAlarmStr = "<?php echo translate('CancelForcedAlarm') ?>";
|
||||
var translate = {
|
||||
"seconds": "<?php echo translate('seconds') ?>",
|
||||
"Fullscreen": "<?php echo translate('Fullscreen') ?>",
|
||||
"Exit Fullscreen": "<?php echo translate('Exit Fullscreen') ?>",
|
||||
};
|
||||
|
|
|
@ -94,20 +94,6 @@ var deleteString = "<?php echo translate('Delete') ?>";
|
|||
// 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 CMD_PAUSE = <?php echo CMD_PAUSE ?>;
|
||||
var CMD_PLAY = <?php echo CMD_PLAY ?>;
|
||||
var CMD_STOP = <?php echo CMD_STOP ?>;
|
||||
|
|
|
@ -17,25 +17,10 @@ monitorData[monitorData.length] = {
|
|||
}
|
||||
?>
|
||||
|
||||
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('PreAlarm') ?>";
|
||||
stateStrings[STATE_ALARM] = "<?php echo translate('Alarm') ?>";
|
||||
stateStrings[STATE_ALERT] = "<?php echo translate('Alert') ?>";
|
||||
stateStrings[STATE_TAPE] = "<?php echo translate('Record') ?>";
|
||||
|
||||
|
||||
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 CMD_QUIT = <?php echo CMD_QUIT ?>;
|
||||
|
||||
|
||||
var statusRefreshTimeout = <?php echo 1000*ZM_WEB_REFRESH_STATUS ?>;
|
||||
|
|
|
@ -453,7 +453,7 @@ foreach ( $tabs as $name=>$value ) {
|
|||
switch ( $name ) {
|
||||
case 'general' :
|
||||
{
|
||||
if (!$monitor->Id()) {
|
||||
if (!$monitor->Id() and count($monitors)) {
|
||||
$monitor_ids = array();
|
||||
foreach ($monitors as $m) { $monitor_ids[] = $m['Id']; }
|
||||
$available_monitor_ids = array_diff(range(min($monitor_ids),max($monitor_ids)), $monitor_ids);
|
||||
|
@ -470,7 +470,7 @@ if (count($available_monitor_ids)) {
|
|||
</tr>
|
||||
<?php
|
||||
|
||||
} # end if ! $monitor->Id()
|
||||
} # end if ! $monitor->Id() and count($monitors)
|
||||
?>
|
||||
<tr class="Name">
|
||||
<td class="text-right pr-3"><?php echo translate('Name') ?></td>
|
||||
|
@ -675,6 +675,14 @@ if (count($available_monitor_ids)) {
|
|||
}
|
||||
?>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td class="text-right pr-3"><?php echo translate('Event Start Command') ?></td>
|
||||
<td><input type="text" name="newMonitor[EventStartCommand]" value="<?php echo validHtmlStr($monitor->EventStartCommand()) ?>" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-right pr-3"><?php echo translate('Event End Command') ?></td>
|
||||
<td><input type="text" name="newMonitor[EventEndCommand]" value="<?php echo validHtmlStr($monitor->EventEndCommand()) ?>" /></td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -24,6 +24,7 @@ if ( !canView('Stream') ) {
|
|||
}
|
||||
|
||||
require_once('includes/MontageLayout.php');
|
||||
require_once('includes/Zone.php');
|
||||
|
||||
$showControl = false;
|
||||
$showZones = false;
|
||||
|
@ -49,7 +50,6 @@ $heights = array(
|
|||
'1080' => '1080px',
|
||||
);
|
||||
|
||||
|
||||
$layouts = ZM\MontageLayout::find(NULL, array('order'=>"lower('Name')"));
|
||||
$layoutsById = array();
|
||||
foreach ( $layouts as $l ) {
|
||||
|
@ -278,27 +278,25 @@ foreach ( $monitors as $monitor ) {
|
|||
}
|
||||
|
||||
$zones = array();
|
||||
foreach( dbFetchAll('SELECT * FROM Zones WHERE MonitorId=? ORDER BY Area DESC', NULL, array($monitor->Id()) ) as $row ) {
|
||||
$row['Points'] = coordsToPoints($row['Coords']);
|
||||
|
||||
foreach ( ZM\Zone::find(array('MonitorId'=>$monitor->Id()), array('order'=>'Area DESC')) as $row ) {
|
||||
$points = $row->Points();
|
||||
if ($scale) {
|
||||
limitPoints($row['Points'], 0, 0, $monitor->Width(), $monitor->Height());
|
||||
limitPoints($points, 0, 0, $monitor->Width(), $monitor->Height());
|
||||
} else {
|
||||
limitPoints($row['Points'], 0, 0,
|
||||
limitPoints($points, 0, 0,
|
||||
( $width ? $width-1 : $monitor->ViewWidth()-1 ),
|
||||
( $height ? $height-1 : $monitor->ViewHeight()-1 )
|
||||
);
|
||||
}
|
||||
$row['Coords'] = pointsToCoords($row['Points']);
|
||||
$row['AreaCoords'] = preg_replace('/\s+/', ',', $row['Coords']);
|
||||
$row->Coords(pointsToCoords($points));
|
||||
$zones[] = $row;
|
||||
} // end foreach Zone
|
||||
?>
|
||||
|
||||
<svg class="zones" id="zones<?php echo $monitor->Id() ?>" style="position:absolute; top: 0; left: 0; background: none; width: 100%; height: 100%;" viewBox="0 0 <?php echo $monitor->ViewWidth() ?> <?php echo $monitor->ViewHeight() ?>" preserveAspectRatio="none">
|
||||
<svg class="zones" id="zones<?php echo $monitor->Id() ?>" style="position:absolute; top: 0; left: 0; background: none; width: 100%; height: 100%;" viewBox="0 0 <?php echo $monitor->ViewWidth().' '.$monitor->ViewHeight() ?>" preserveAspectRatio="none">
|
||||
<?php
|
||||
foreach (array_reverse($zones) as $zone) {
|
||||
echo '<polygon points="'. $zone['AreaCoords'] .'" class="'. $zone['Type'].'" />';
|
||||
echo $zone->svg_polygon();
|
||||
} // end foreach zone
|
||||
?>
|
||||
Sorry, your browser does not support inline SVG
|
||||
|
@ -310,7 +308,12 @@ foreach ( array_reverse($zones) as $zone ) {
|
|||
<?php
|
||||
if ((!ZM_WEB_COMPACT_MONTAGE) && ($monitor->Type() != 'WebSite')) {
|
||||
?>
|
||||
<div id="monitorState<?php echo $monitor->Id() ?>" class="monitorState idle"><?php echo translate('State') ?>: <span id="stateValue<?php echo $monitor->Id() ?>"></span> - <span id="fpsValue<?php echo $monitor->Id() ?>"></span> fps</div>
|
||||
<div id="monitorState<?php echo $monitor->Id() ?>" class="monitorState idle">
|
||||
<?php echo translate('State') ?>:
|
||||
<span id="stateValue<?php echo $monitor->Id() ?>"></span>
|
||||
-
|
||||
<span id="fpsValue<?php echo $monitor->Id() ?>"></span> fps
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -22,25 +22,90 @@ if ( !canView('Stream') ) {
|
|||
$view = 'error';
|
||||
return;
|
||||
}
|
||||
require_once('includes/Monitor.php');
|
||||
|
||||
ob_start();
|
||||
include('_monitor_filters.php');
|
||||
$filterbar = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
if ( !isset($_REQUEST['mid']) ) {
|
||||
$view = 'error';
|
||||
return;
|
||||
}
|
||||
|
||||
// This is for input sanitation
|
||||
$mid = intval($_REQUEST['mid']);
|
||||
$mid = isset($_REQUEST['mid']) ? intval($_REQUEST['mid']) : 0;
|
||||
|
||||
$widths = array(
|
||||
'auto' => translate('auto'),
|
||||
'100%' => '100%',
|
||||
'160px' => '160px',
|
||||
'320px' => '320px',
|
||||
'352px' => '352px',
|
||||
'640px' => '640px',
|
||||
'1280px' => '1280px',
|
||||
'1920px' => '1920px'
|
||||
);
|
||||
|
||||
$heights = array(
|
||||
'auto' => translate('auto'),
|
||||
'240px' => '240px',
|
||||
'480px' => '480px',
|
||||
'720px' => '720px',
|
||||
'1080px' => '1080px',
|
||||
);
|
||||
|
||||
$monitors = array();
|
||||
$monitor_index = 0;
|
||||
foreach ($displayMonitors as &$row) {
|
||||
if ($row['Function'] == 'None') continue;
|
||||
if ($mid and ($row['Id'] == $mid)) $monitor_index = count($monitors);
|
||||
$monitors[] = new ZM\Monitor($row);
|
||||
if (!isset($widths[$row['Width'].'px'])) {
|
||||
$widths[$row['Width'].'px'] = $row['Width'].'px';
|
||||
}
|
||||
if (!isset($heights[$row['Height'].'px'])) {
|
||||
$heights[$row['Height'].'px'] = $row['Height'].'px';
|
||||
}
|
||||
unset($row);
|
||||
} # end foreach Monitor
|
||||
|
||||
if (!$mid) {
|
||||
$mid = $monitors[0]->Id();
|
||||
$monitor_index = 0;
|
||||
}
|
||||
|
||||
if (!visibleMonitor($mid)) {
|
||||
$view = 'error';
|
||||
return;
|
||||
}
|
||||
|
||||
require_once('includes/Monitor.php');
|
||||
$monitor = new ZM\Monitor($mid);
|
||||
|
||||
$nextMid = ($monitor_index == count($monitors)-1) ? $monitors[0]->Id() : $monitors[$monitor_index+1]->Id();
|
||||
$cycle = isset($_REQUEST['cycle']) and ($_REQUEST['cycle'] == 'true');
|
||||
$showCycle = $cycle;
|
||||
ZM\Error("Show cycle: $showCycle");
|
||||
if (isset($_COOKIE['zmCycleShow'])) {
|
||||
$showCycle = $_COOKIE['zmCycleShow'] == 'true';
|
||||
ZM\Error("Show cycle: $showCycle");
|
||||
} else {
|
||||
ZM\Error("Show cycle: not set");
|
||||
}
|
||||
#Whether to show the controls button
|
||||
$showPtzControls = ( ZM_OPT_CONTROL && $monitor->Controllable() && canView('Control') && $monitor->Type() != 'WebSite' );
|
||||
|
||||
$options = array();
|
||||
if (empty($_REQUEST['mode'])) {
|
||||
$options['mode'] = canStream() ? 'stream' : 'still';
|
||||
} else {
|
||||
$options['mode'] = validHtmlStr($_REQUEST['mode']);
|
||||
}
|
||||
zm_session_start();
|
||||
|
||||
$period = ZM_WEB_REFRESH_CYCLE;
|
||||
if (isset($_REQUEST['period'])) {
|
||||
$period = validInt($_REQUEST['period']);
|
||||
} else if (isset($_COOKIE['zmCyclePeriod'])) {
|
||||
$period = validInt($_COOKIE['zmCyclePeriod']);
|
||||
}
|
||||
|
||||
if (isset($_REQUEST['scale'])) {
|
||||
$scale = validInt($_REQUEST['scale']);
|
||||
} else if ( isset($_COOKIE['zmWatchScale'.$mid]) ) {
|
||||
|
@ -48,62 +113,156 @@ if ( isset($_REQUEST['scale']) ) {
|
|||
} else {
|
||||
$scale = $monitor->DefaultScale();
|
||||
}
|
||||
$options['scale'] = $scale;
|
||||
|
||||
if (isset($_REQUEST['width'])) {
|
||||
$options['width'] = validInt($_REQUEST['width']);
|
||||
} else if ( isset($_COOKIE['zmCycleWidth']) and $_COOKIE['zmCycleWidth'] ) {
|
||||
$_SESSION['zmCycleWidth'] = $options['width'] = $_COOKIE['zmCycleWidth'];
|
||||
#} elseif ( isset($_SESSION['zmCycleWidth']) and $_SESSION['zmCycleWidth'] ) {
|
||||
#$options['width'] = $_SESSION['zmCycleWidth'];
|
||||
} else {
|
||||
$options['width'] = '';
|
||||
}
|
||||
if (isset($_REQUEST['height'])) {
|
||||
$options['height'] =validInt($_REQUEST['height']);
|
||||
} else if (isset($_COOKIE['zmCycleHeight']) and $_COOKIE['zmCycleHeight']) {
|
||||
$_SESSION['zmCycleHeight'] = $options['height'] = $_COOKIE['zmCycleHeight'];
|
||||
#else if ( isset($_SESSION['zmCycleHeight']) and $_SESSION['zmCycleHeight'] )
|
||||
#$options['height'] = $_SESSION['zmCycleHeight'];
|
||||
} else {
|
||||
$options['height'] = '';
|
||||
}
|
||||
session_write_close();
|
||||
|
||||
$connkey = generateConnKey();
|
||||
|
||||
$streamMode = getStreamMode();
|
||||
|
||||
$popup = ((isset($_REQUEST['popup'])) && ($_REQUEST['popup'] == 1));
|
||||
|
||||
noCacheHeaders();
|
||||
xhtmlHeaders(__FILE__, $monitor->Name().' - '.translate('Feed'));
|
||||
?>
|
||||
<body>
|
||||
<?php echo getNavBarHTML() ?>
|
||||
<div id="header">
|
||||
<div class="controlHeader">
|
||||
<form method="get">
|
||||
<input type="hidden" name="view" value="watch"/>
|
||||
<?php echo $filterbar ?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-row justify-content-between px-3 py-1">
|
||||
<div>
|
||||
<div id="navButtons">
|
||||
<button type="button" id="backBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Back') ?>" disabled><i class="fa fa-arrow-left"></i></button>
|
||||
<button type="button" id="refreshBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Refresh') ?>" ><i class="fa fa-refresh"></i></button>
|
||||
<button type="button" id="settingsBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Settings') ?>" disabled><i class="fa fa-sliders"></i></button>
|
||||
<button type="button" id="enableAlmBtn" class="btn btn-normal" data-on-click="cmdAlarm" data-toggle="tooltip" data-placement="top" title="<?php echo translate('DisableAlarms') ?>" disabled><i class="fa fa-bell"></i></button>
|
||||
<button type="button" id="forceAlmBtn" class="btn btn-danger" data-on-click="cmdForce" data-toggle="tooltip" data-placement="top" title="<?php echo translate('ForceAlarm') ?>" disabled><i class="fa fa-exclamation-circle"></i></button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2><?php echo makeLink('?view=monitor&mid='.$monitor->Id(), validHtmlStr($monitor->Name()), canEdit('Monitors')) ?></h2>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<?php echo translate('Scale').': '.htmlSelect('scale', $scales, $scale, array('id'=>'scale')); ?>
|
||||
</div>
|
||||
<div id="headerButtons">
|
||||
<!--
|
||||
<?php if ( $options['mode'] == 'stream' ) { ?>
|
||||
<a href="?view=<?php echo $view ?>&mode=still&mid=<?php echo $monitor ? $monitor->Id() : '' ?>"><?php echo translate('Stills') ?></a>
|
||||
<?php } else { ?>
|
||||
<a href="?view=<?php echo $view ?>&mode=stream&mid=<?php echo $monitor ? $monitor->Id() : '' ?>"><?php echo translate('Stream') ?></a>
|
||||
<?php } ?>
|
||||
-->
|
||||
<button type="button" id="cycleToggle" class="btn <?php echo $showCycle ? 'btn-primary':'btn-secondary'?>" title="<?php echo translate('Toggle cycle sidebar')?>">
|
||||
<span class="material-icons md-18">view_carousel</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="sizeControl">
|
||||
<span id="widthControl">
|
||||
<label><?php echo translate('Width') ?>:</label>
|
||||
<?php echo htmlSelect('width', $widths, $options['width'], array('id'=>'width', 'data-on-change-this'=>'changeSize') ); ?>
|
||||
</span>
|
||||
<span id="heightControl">
|
||||
<label><?php echo translate('Height') ?>:</label>
|
||||
<?php echo htmlSelect('height', $heights, $options['height'], array('id'=>'height', 'data-on-change-this'=>'changeSize') ); ?>
|
||||
</span>
|
||||
<span id="scaleControl">
|
||||
<label><?php echo translate('Scale') ?>:</label>
|
||||
<?php echo htmlSelect('scale', $scales, $options['scale'], array('id'=>'scale', 'data-on-change-this'=>'changeScale') ); ?>
|
||||
</span>
|
||||
</div><!--sizeControl-->
|
||||
</div><!--control header-->
|
||||
</div><!--header-->
|
||||
<?php
|
||||
if ( $monitor->Status() != 'Connected' and $monitor->Type() != 'WebSite' ) {
|
||||
echo '<div class="warning">Monitor is not capturing. We will be unable to provide an image</div>';
|
||||
}
|
||||
?>
|
||||
<div id="content">
|
||||
<div class="container-fluid h-100">
|
||||
<div class="row flex-nowrap h-100" id="content">
|
||||
<nav id="sidebar" class="h-100"<?php echo $showCycle?'':' style="display:none;"'?>>
|
||||
<div id="cycleButtons" class="buttons">
|
||||
<?php
|
||||
$seconds = translate('seconds');
|
||||
$minute = translate('minute');
|
||||
$minutes = translate('minutes');
|
||||
$cyclePeriodOptions = array(
|
||||
10 => '10 '.$seconds,
|
||||
30 => '30 '.$seconds,
|
||||
60 => '1 '.$minute,
|
||||
120 => '2 '.$minutes,
|
||||
300 => '5 '.$minutes,
|
||||
);
|
||||
if (!isset($cyclePeriodOptions[ZM_WEB_REFRESH_CYCLE])) {
|
||||
$cyclePeriodOptions[ZM_WEB_REFRESH_CYCLE] = ZM_WEB_REFRESH_CYCLE.' '.$seconds;
|
||||
}
|
||||
echo htmlSelect('cyclePeriod', $cyclePeriodOptions, $period, array('id'=>'cyclePeriod'));
|
||||
?>
|
||||
<span id="secondsToCycle"></span><br/>
|
||||
<button type="button" id="cyclePrevBtn" title="<?php echo translate('PreviousMonitor') ?>">
|
||||
<i class="material-icons md-18">skip_previous</i>
|
||||
</button>
|
||||
<button type="button" id="cyclePauseBtn" title="<?php echo translate('PauseCycle') ?>">
|
||||
<i class="material-icons md-18">pause</i>
|
||||
</button>
|
||||
<button type="button" id="cyclePlayBtn" title="<?php echo translate('PlayCycle') ?>">
|
||||
<i class="material-icons md-18">play_arrow</i>
|
||||
</button>
|
||||
<button type="button" id="cycleNextBtn" title="<?php echo translate('NextMonitor') ?>">
|
||||
<i class="material-icons md-18">skip_next</i>
|
||||
</button>
|
||||
</div>
|
||||
<ul class="nav nav-pills flex-column h-100">
|
||||
<?php
|
||||
foreach ($monitors as $m) {
|
||||
echo '<li class="nav-item"><a class="nav-link'.( $m->Id() == $monitor->Id() ? ' active' : '' ).'" href="?view=watch&mid='.$m->Id().'">'.$m->Name().'</a></li>';
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</nav>
|
||||
<div class="container-fluid col-sm-offset-2 h-100 pr-0">
|
||||
<div id="imageFeed"
|
||||
<?php
|
||||
if ($streamMode == 'jpeg') {
|
||||
echo 'title="Click to zoom, shift click to pan, ctrl click to zoom out"';
|
||||
}
|
||||
?>
|
||||
><?php echo getStreamHTML($monitor, array('scale'=>$scale)); ?></div>
|
||||
|
||||
><?php echo getStreamHTML($monitor, array('scale'=>$scale)); ?>
|
||||
</div>
|
||||
|
||||
<?php if ($monitor->Type() != 'WebSite') { ?>
|
||||
<div id="monitorStatus">
|
||||
<div id="monitorState">
|
||||
<?php echo translate('State') ?>:
|
||||
<span id="stateValue"></span> -
|
||||
<span title="<?php echo translate('Viewing FPS')?>"><span id="fpsValue"></span> fps</span>
|
||||
<span title="<?php echo translate('Capturing FPS')?>"><span id="capturefpsValue"></span> fps</span>
|
||||
<span><?php echo translate('State') ?>:<span id="stateValue"></span></span>
|
||||
<span id="viewingFPS" title="<?php echo translate('Viewing FPS')?>"><span id="viewingFPSValue"></span> fps</span>
|
||||
<span id="captureFPS" title="<?php echo translate('Capturing FPS')?>"><span id="captureFPSValue"></span> fps</span>
|
||||
<?php if ( $monitor->Function() == 'Modect' or $monitor->Function() == 'Mocord' ) { ?>
|
||||
<span title="<?php echo translate('Analysis FPS')?>"><span id="analysisfpsValue"></span> fps</span>
|
||||
<span id="analysisFPS" title="<?php echo translate('Analysis FPS')?>"><span id="analysisFPSValue"></span> fps</span>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</div>
|
||||
<div id="replayStatus"<?php echo $streamMode=="single" ? ' class="hidden"' : '' ?>>
|
||||
<span id="mode"><?php echo translate('Mode') ?>: <span id="modeValue"></span></span>
|
||||
<span id="rate"><?php echo translate('Rate') ?>: <span id="rateValue"></span>x</span>
|
||||
<span id="delay"><?php echo translate('Delay') ?>: <span id="delayValue"></span>s</span>
|
||||
<span id="level"><?php echo translate('Buffer') ?>: <span id="levelValue"></span>%</span>
|
||||
<span id="zoom"><?php echo translate('Zoom') ?>: <span id="zoomValue"></span>x</span>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<div id="dvrControls">
|
||||
<?php
|
||||
if ($streamMode == 'jpeg') {
|
||||
|
@ -148,13 +307,7 @@ if ( $streamMode == 'jpeg' ) {
|
|||
<?php
|
||||
} // end if streamMode==jpeg
|
||||
?>
|
||||
</div>
|
||||
<div id="replayStatus"<?php echo $streamMode=="single" ? ' class="hidden"' : '' ?>>
|
||||
<span id="mode"><?php echo translate('Mode') ?>: <span id="modeValue"></span></span>
|
||||
<span id="rate"><?php echo translate('Rate') ?>: <span id="rateValue"></span>x</span>
|
||||
<span id="delay"><?php echo translate('Delay') ?>: <span id="delayValue"></span>s</span>
|
||||
<span id="level"><?php echo translate('Buffer') ?>: <span id="levelValue"></span>%</span>
|
||||
<span id="zoom"><?php echo translate('Zoom') ?>: <span id="zoomValue"></span>x</span>
|
||||
</div><!--dvrButtons-->
|
||||
</div>
|
||||
<?php } // end if $monitor->Type() != 'WebSite' ?>
|
||||
<?php
|
||||
|
@ -208,6 +361,7 @@ if ( canView('Events') && ($monitor->Type() != 'WebSite') ) {
|
|||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
if ( ZM_WEB_SOUND_ON_ALARM ) {
|
||||
|
|
|
@ -37,7 +37,8 @@ ZM_WEB_GROUP=@WEB_GROUP@
|
|||
ZM_DB_TYPE=@ZM_DB_TYPE@
|
||||
|
||||
# ZoneMinder database hostname or ip address and optionally port or unix socket
|
||||
# Acceptable formats include hostname[:port], ip_address[:port], or localhost:unix_socket
|
||||
# Acceptable formats include hostname[:port], ip_address[:port], or
|
||||
# localhost:/path/to/unix_socket
|
||||
ZM_DB_HOST=@ZM_DB_HOST@
|
||||
|
||||
# ZoneMinder database name
|
||||
|
|
Loading…
Reference in New Issue