Merge branch 'storageareas' of github.com:connortechnology/ZoneMinder into storageareas
This commit is contained in:
commit
9aa94bd3ab
|
@ -30,6 +30,7 @@ env:
|
|||
- OS=el DIST=7
|
||||
- OS=fedora DIST=25
|
||||
- OS=fedora DIST=26 DOCKER_REPO=knnniggett/packpack
|
||||
- OS=fedora DIST=27 DOCKER_REPO=knnniggett/packpack
|
||||
- OS=ubuntu DIST=trusty
|
||||
- OS=ubuntu DIST=xenial
|
||||
- OS=ubuntu DIST=trusty ARCH=i386
|
||||
|
|
|
@ -31,6 +31,8 @@ This is the recommended method to install ZoneMinder onto your system. ZoneMinde
|
|||
- Fedora via [RPM Fusion](http://rpmfusion.org)
|
||||
- OpenSuse via [third party repository](http://www.zoneminder.com/wiki/index.php/Installing_using_ZoneMinder_RPMs_for_SuSE)
|
||||
- Mageia from their default repository
|
||||
- Arch via the [AUR](https://aur.archlinux.org/packages/zoneminder/)
|
||||
- Gentoo from their [default repository](https://packages.gentoo.org/packages/www-misc/zoneminder)
|
||||
|
||||
If a repository that hosts ZoneMinder packages is not available for your distro, then you are encouraged to build your own package, rather than build from source. While each distro is different in ways that set it apart from all the others, they are often similar enough to allow you to adapt another distro's package building instructions to your own.
|
||||
|
||||
|
|
|
@ -195,6 +195,7 @@ CREATE TABLE `Events` (
|
|||
`Frames` int(10) unsigned default NULL,
|
||||
`AlarmFrames` int(10) unsigned default NULL,
|
||||
`DefaultVideo` VARCHAR( 64 ) DEFAULT '' NOT NULL,
|
||||
`SaveJPEGs` TINYINT,
|
||||
`TotScore` int(10) unsigned NOT NULL default '0',
|
||||
`AvgScore` smallint(5) unsigned default '0',
|
||||
`MaxScore` smallint(5) unsigned default '0',
|
||||
|
@ -384,6 +385,8 @@ CREATE TABLE `Monitors` (
|
|||
`Deinterlacing` int(10) unsigned NOT NULL default '0',
|
||||
`SaveJPEGs` TINYINT NOT NULL DEFAULT '3' ,
|
||||
`VideoWriter` TINYINT NOT NULL DEFAULT '0',
|
||||
`OutputCodec` enum('h264','mjpeg','mpeg1','mpeg2'),
|
||||
`OutputContainer` enum('auto','mp4','mkv'),
|
||||
`EncoderParameters` TEXT,
|
||||
`RecordAudio` TINYINT NOT NULL DEFAULT '0',
|
||||
`RTSPDescribe` tinyint(1) unsigned,
|
||||
|
@ -431,6 +434,19 @@ CREATE TABLE `Monitors` (
|
|||
`Status` enum('Unknown','NotRunning','Running','NoSignal','Signal') NOT NULL default 'Unknown',
|
||||
`CaptureFPS` DECIMAL(10,2) NOT NULL default 0,
|
||||
`AnalysisFPS` DECIMAL(5,2) NOT NULL default 0,
|
||||
`TotalEvents` int(10) unsigned,
|
||||
`TotalEventDiskSpace` bigint unsigned,
|
||||
`HourEvents` int(10) unsigned,
|
||||
`HourEventDiskSpace` bigint unsigned,
|
||||
`DayEvents` int(10) unsigned,
|
||||
`DayEventDiskSpace` bigint unsigned,
|
||||
`WeekEvents` int(10) unsigned,
|
||||
`WeekEventDiskSpace` bigint unsigned,
|
||||
`MonthEvents` int(10) unsigned,
|
||||
`MonthEventDiskSpace` bigint unsigned,
|
||||
`ArchivedEvents` int(10) unsigned,
|
||||
`ArchivedEventDiskSpace` bigint unsigned,
|
||||
`ZoneCount` TINYINT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`Id`)
|
||||
) ENGINE=@ZM_MYSQL_ENGINE@;
|
||||
|
||||
|
@ -606,13 +622,14 @@ CREATE TABLE `Storage` (
|
|||
`Path` varchar(64) NOT NULL default '',
|
||||
`Name` varchar(64) NOT NULL default '',
|
||||
`Type` enum('local','s3fs') NOT NULL default 'local',
|
||||
`DiskSpace` bigint unsigned default NULL,
|
||||
PRIMARY KEY (`Id`)
|
||||
) ENGINE=@ZM_MYSQL_ENGINE@;
|
||||
|
||||
--
|
||||
-- Create a default storage location
|
||||
--
|
||||
insert into Storage VALUES (NULL, '/var/cache/zoneminder/events', 'Default', 'local' );
|
||||
insert into Storage VALUES (NULL, '/var/cache/zoneminder/events', 'Default', 'local', NULL );
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
|
|
|
@ -67,3 +67,4 @@ SET @s = (SELECT IF(
|
|||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
ALTER TABLE `Monitors` MODIFY `OutputCodec` enum('h264','mjpeg','mpeg1','mpeg2') default 'h264';
|
||||
ALTER TABLE `Monitors` MODIFY `OutputContainer` enum('auto','mp4','mkv') default 'auto';
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Events'
|
||||
AND column_name = 'SaveJPEGs'
|
||||
) > 0,
|
||||
"SELECT 'Column SaveJPEGs already exists in Events'",
|
||||
"ALTER TABLE `Events` ADD `SaveJPEGs` TINYINT AFTER `DefaultVideo`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Storage'
|
||||
AND column_name = 'DiskSpace'
|
||||
) > 0,
|
||||
"SELECT 'Column DiskSpace already exists in Events'",
|
||||
"ALTER TABLE `Storage` ADD `DiskSpace` bigint unsigned default NULL AFTER `Type`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
|
@ -0,0 +1,148 @@
|
|||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Monitors'
|
||||
AND column_name = 'TotalEvents'
|
||||
) > 0,
|
||||
"SELECT 'Column TotalEvents already exists in Monitors'",
|
||||
"ALTER TABLE `Monitors` ADD `TotalEvents` INT(10) AFTER `AnalysisFPS`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Monitors'
|
||||
AND column_name = 'TotalEventDiskSpace'
|
||||
) > 0,
|
||||
"SELECT 'Column TotalEventDiskSpace already exists in Monitors'",
|
||||
"ALTER TABLE `Monitors` ADD `TotalEventDiskSpace` BIGINT AFTER `TotalEvents`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Monitors'
|
||||
AND column_name = 'HourEvents'
|
||||
) > 0,
|
||||
"SELECT 'Column HourEvents already exists in Monitors'",
|
||||
"ALTER TABLE `Monitors` ADD `HourEvents` INT(10) AFTER `TotalEvents`"
|
||||
));
|
||||
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Monitors'
|
||||
AND column_name = 'HourEventDiskSpace'
|
||||
) > 0,
|
||||
"SELECT 'Column HourEventDiskSpace already exists in Monitors'",
|
||||
"ALTER TABLE `Monitors` ADD `HourEventDiskSpace` BIGINT AFTER `HourEvents`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Monitors'
|
||||
AND column_name = 'DayEvents'
|
||||
) > 0,
|
||||
"SELECT 'Column DayEvents already exists in Monitors'",
|
||||
"ALTER TABLE `Monitors` ADD `DayEvents` INT(10) AFTER `HourEvents`"
|
||||
));
|
||||
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Monitors'
|
||||
AND column_name = 'DayEventDiskSpace'
|
||||
) > 0,
|
||||
"SELECT 'Column DayEventDiskSpace already exists in Monitors'",
|
||||
"ALTER TABLE `Monitors` ADD `DayEventDiskSpace` BIGINT AFTER `DayEvents`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Monitors'
|
||||
AND column_name = 'WeekEvents'
|
||||
) > 0,
|
||||
"SELECT 'Column WeekEvents already exists in Monitors'",
|
||||
"ALTER TABLE `Monitors` ADD `WeekEvents` INT(10) AFTER `DayEvents`"
|
||||
));
|
||||
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Monitors'
|
||||
AND column_name = 'WeekEventDiskSpace'
|
||||
) > 0,
|
||||
"SELECT 'Column WeekEventDiskSpace already exists in Monitors'",
|
||||
"ALTER TABLE `Monitors` ADD `WeekEventDiskSpace` BIGINT AFTER `WeekEvents`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Monitors'
|
||||
AND column_name = 'MonthEvents'
|
||||
) > 0,
|
||||
"SELECT 'Column MonthEvents already exists in Monitors'",
|
||||
"ALTER TABLE `Monitors` ADD `MonthEvents` INT(10) AFTER `WeekEvents`"
|
||||
));
|
||||
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Monitors'
|
||||
AND column_name = 'MonthEventDiskSpace'
|
||||
) > 0,
|
||||
"SELECT 'Column MonthEventDiskSpace already exists in Monitors'",
|
||||
"ALTER TABLE `Monitors` ADD `MonthEventDiskSpace` BIGINT AFTER `MonthEvents`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Monitors'
|
||||
AND column_name = 'ArchivedEvents'
|
||||
) > 0,
|
||||
"SELECT 'Column ArchivedEvents already exists in Monitors'",
|
||||
"ALTER TABLE `Monitors` ADD `ArchivedEvents` INT(10) AFTER `MonthEvents`"
|
||||
));
|
||||
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Monitors'
|
||||
AND column_name = 'ArchivedEventDiskSpace'
|
||||
) > 0,
|
||||
"SELECT 'Column ArchivedEventDiskSpace already exists in Monitors'",
|
||||
"ALTER TABLE `Monitors` ADD `ArchivedEventDiskSpace` BIGINT AFTER `ArchivedEvents`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Monitors'
|
||||
AND column_name = 'ZoneCount'
|
||||
) > 0,
|
||||
"SELECT 'Column ZoneCount already exists in Monitors'",
|
||||
"ALTER TABLE `Monitors` ADD `ZoneCount` TINYINT NOT NULL DEFAULT 0 AFTER `ArchivedEventDiskSpace`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
UPDATE Monitors SET ZoneCount=(SELECT COUNT(Id) FROM Zones WHERE MonitorId=Monitors.Id);
|
|
@ -16,3 +16,5 @@ SET @s = (SELECT IF(
|
|||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
INSERT INTO `Controls` VALUES (28,'Floureon 1080P','Ffmpeg','Floureon',0,0,0,1,0,0,0,1,1,18,1,1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,20,0,1,1,1,0,0,0,1,1,0,0,0,0,1,1,8,0,0,1,0,0,0,0,1,1,8,0,0,0,0);
|
||||
|
||||
|
|
|
@ -10,30 +10,23 @@ if [ "$1" = "configure" ]; then
|
|||
chown www-data:root /var/log/zm
|
||||
chown www-data:www-data /var/lib/zm
|
||||
if [ -z "$2" ]; then
|
||||
chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/*
|
||||
chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/* /usr/share/zoneminder/www/cache
|
||||
fi
|
||||
if [ ! -e "/etc/apache2/mods-enabled/cgi.load" ]; then
|
||||
echo "The cgi module is not enabled in apache2. I am enabling it using a2enmod cgi."
|
||||
a2enmod cgi
|
||||
fi
|
||||
|
||||
# Do this every time the package is installed or upgraded
|
||||
# Ensure zoneminder is stopped
|
||||
deb-systemd-invoke stop zoneminder.service || exit $?
|
||||
|
||||
# Ensure zoneminder is stopped
|
||||
deb-systemd-invoke stop zoneminder.service || exit $?
|
||||
if [ "$ZM_DB_HOST" = "localhost" ]; then
|
||||
if [ "$ZM_DB_HOST" = "localhost" ]; then
|
||||
|
||||
if [ -e "/etc/init.d/mysql" ]; then
|
||||
# Do this every time the package is installed or upgraded
|
||||
# Ensure zoneminder is stopped
|
||||
deb-systemd-invoke stop zoneminder.service || exit $?
|
||||
|
||||
#
|
||||
# Get mysql started if it isn't
|
||||
#
|
||||
if ! $(/etc/init.d/mysql status >/dev/null 2>&1); then
|
||||
deb-systemd-invoke start mysql.service || exit $?
|
||||
fi
|
||||
|
||||
if $(/etc/init.d/mysql status >/dev/null 2>&1); then
|
||||
mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload
|
||||
# test if database if already present...
|
||||
|
|
|
@ -15,9 +15,11 @@ achieve the same result by running:
|
|||
|
||||
::
|
||||
|
||||
tasksel install lamp-server
|
||||
sudo tasksel install lamp-server
|
||||
|
||||
During installation it will ask you to set up a master/root password for the MySQL.
|
||||
Installing LAMP is not ZoneMinder specific so you will find plenty of resources to
|
||||
guide you with a quick search.
|
||||
|
||||
**Step 1:** Either run commands in this install using sudo or use the below to become root
|
||||
::
|
||||
|
|
|
@ -2933,6 +2933,16 @@ our @options = (
|
|||
type => $types{integer},
|
||||
category => 'highband',
|
||||
},
|
||||
{
|
||||
name => 'ZM_WEB_H_REFRESH_NAVBAR',
|
||||
default => '5',
|
||||
description => 'How often (in seconds) the navigation header should refresh itself',
|
||||
help => q`
|
||||
The navigation header contains the general status information about server load and storage space.
|
||||
`,
|
||||
type => $types{integer},
|
||||
category => 'highband',
|
||||
},
|
||||
{
|
||||
name => 'ZM_WEB_H_REFRESH_CYCLE',
|
||||
default => '10',
|
||||
|
@ -3196,6 +3206,16 @@ our @options = (
|
|||
`,
|
||||
category => 'medband',
|
||||
},
|
||||
{
|
||||
name => 'ZM_WEB_M_REFRESH_NAVBAR',
|
||||
default => '15',
|
||||
description => 'How often (in seconds) the navigation header should refresh itself',
|
||||
help => q`
|
||||
The navigation header contains the general status information about server load and storage space.
|
||||
`,
|
||||
type => $types{integer},
|
||||
category => 'medband',
|
||||
},
|
||||
{
|
||||
name => 'ZM_WEB_M_REFRESH_CYCLE',
|
||||
default => '20',
|
||||
|
@ -3459,6 +3479,16 @@ our @options = (
|
|||
type => $types{integer},
|
||||
category => 'lowband',
|
||||
},
|
||||
{
|
||||
name => 'ZM_WEB_L_REFRESH_NAVBAR',
|
||||
default => '35',
|
||||
description => 'How often (in seconds) the navigation header should refresh itself',
|
||||
help => q`
|
||||
The navigation header contains the general status information about server load and storage space.
|
||||
`,
|
||||
type => $types{integer},
|
||||
category => 'lowband',
|
||||
},
|
||||
{
|
||||
name => 'ZM_WEB_L_REFRESH_CYCLE',
|
||||
default => '30',
|
||||
|
|
|
@ -0,0 +1,390 @@
|
|||
# Modified on 2017-11-17 by Ognyan Bankov
|
||||
|
||||
# ==========================================================================
|
||||
#
|
||||
# ZoneMinder Floureon 1080p IP Control Protocol Module, $Date: 2017-11-17 09:20:00 +0000 $, $Revision: 0001 $
|
||||
# Copyright (C) 2017 Ognyan Bankov
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This module contains the implementation of the Floureon 1080p 18x (Model: BT-HD54F) IP camera control
|
||||
# protocol. It should work with other Floureon cameras too.
|
||||
#
|
||||
#
|
||||
|
||||
package MyAgent;
|
||||
|
||||
use base 'LWP::UserAgent';
|
||||
|
||||
|
||||
package ZoneMinder::Control::Floureon;
|
||||
|
||||
use 5.006;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
require ZoneMinder::Base;
|
||||
require ZoneMinder::Control;
|
||||
|
||||
our @ISA = qw(ZoneMinder::Control);
|
||||
|
||||
our $VERSION = $ZoneMinder::Base::VERSION;
|
||||
|
||||
# ==========================================================================
|
||||
#
|
||||
# Floureon IP Control Protocol
|
||||
#
|
||||
# ==========================================================================
|
||||
|
||||
use ZoneMinder::Logger qw(:all);
|
||||
use ZoneMinder::Config qw(:all);
|
||||
|
||||
use Time::HiRes qw( usleep );
|
||||
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my $id = shift;
|
||||
my $self = ZoneMinder::Control->new( $id );
|
||||
my $logindetails = "";
|
||||
bless( $self, $class );
|
||||
srand( time() );
|
||||
return $self;
|
||||
}
|
||||
|
||||
our $AUTOLOAD;
|
||||
|
||||
sub AUTOLOAD
|
||||
{
|
||||
my $self = shift;
|
||||
my $class = ref($self) || croak( "$self not object" );
|
||||
my $name = $AUTOLOAD;
|
||||
$name =~ s/.*://;
|
||||
if ( exists($self->{$name}) )
|
||||
{
|
||||
return( $self->{$name} );
|
||||
}
|
||||
Fatal( "Can't access $name member of object of class $class" );
|
||||
}
|
||||
our $stop_command;
|
||||
|
||||
sub open
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
$self->loadMonitor();
|
||||
|
||||
$self->{ua} = MyAgent->new;
|
||||
$self->{ua}->agent( "ZoneMinder Control Agent/" );
|
||||
|
||||
$self->{state} = 'open';
|
||||
}
|
||||
|
||||
sub close
|
||||
{
|
||||
my $self = shift;
|
||||
$self->{state} = 'closed';
|
||||
}
|
||||
|
||||
sub printMsg
|
||||
{
|
||||
my $self = shift;
|
||||
my $msg = shift;
|
||||
my $msg_len = length($msg);
|
||||
|
||||
Debug( $msg."[".$msg_len."]" );
|
||||
}
|
||||
|
||||
sub sendCmd
|
||||
{
|
||||
my $self = shift;
|
||||
my $cmd = shift;
|
||||
my $result = undef;
|
||||
printMsg( $cmd, "Tx" );
|
||||
|
||||
my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$cmd"."&".$self->{Monitor}->{ControlDevice});
|
||||
print ("Sending $req\n");
|
||||
my $res = $self->{ua}->request($req);
|
||||
if ( $res->is_success )
|
||||
{
|
||||
$result = !undef;
|
||||
}
|
||||
else
|
||||
{
|
||||
Error( "Error REALLY check failed:'".$res->status_line()."'" );
|
||||
Error ("Cmd:".$req);
|
||||
}
|
||||
|
||||
return( $result );
|
||||
}
|
||||
|
||||
sub reset
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Camera Reset" );
|
||||
my $cmd = "reboot.cgi?";
|
||||
$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
# PP - in all move operations, added auto stop after timeout
|
||||
|
||||
#Up Arrow
|
||||
sub moveConUp
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
|
||||
Debug( "Move Up" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Direction=1&PanSpeed=6&TiltSpeed=$tiltspeed";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop($tiltspeed);
|
||||
}
|
||||
|
||||
#Down Arrow
|
||||
sub moveConDown
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
|
||||
Debug( "Move Down" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Direction=2&PanSpeed=6&TiltSpeed=$tiltspeed";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop($tiltspeed);
|
||||
}
|
||||
|
||||
#Left Arrow
|
||||
sub moveConLeft
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $panspeed = $self->getParam( $params, 'panspeed' );
|
||||
|
||||
Debug( "Move Left" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Direction=3&PanSpeed=$panspeed&TiltSpeed=6";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop($panspeed);
|
||||
}
|
||||
|
||||
#Right Arrow
|
||||
sub moveConRight
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $panspeed = $self->getParam( $params, 'panspeed' );
|
||||
Debug( "Move Right" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Direction=4&PanSpeed=$panspeed&TiltSpeed=6";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop($panspeed);
|
||||
}
|
||||
|
||||
#Diagonally Up Right Arrow
|
||||
sub moveConUpRight
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $panspeed = $self->getParam( $params, 'panspeed' );
|
||||
my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
|
||||
Debug( "Move Diagonally Up Right" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Direction=7&PanSpeed=$panspeed&TiltSpeed=$tiltspeed";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop($tiltspeed);
|
||||
|
||||
}
|
||||
|
||||
#Diagonally Down Right Arrow
|
||||
sub moveConDownRight
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $panspeed = $self->getParam( $params, 'panspeed' );
|
||||
my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
|
||||
Debug( "Move Diagonally Down Right" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Direction=8&PanSpeed=$panspeed&TiltSpeed=$tiltspeed";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop($tiltspeed);
|
||||
}
|
||||
|
||||
#Diagonally Up Left Arrow
|
||||
sub moveConUpLeft
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $panspeed = $self->getParam( $params, 'panspeed' );
|
||||
my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
|
||||
Debug( "Move Diagonally Up Left" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Direction=5&PanSpeed=$panspeed&TiltSpeed=$tiltspeed";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop($tiltspeed);
|
||||
}
|
||||
|
||||
#Diagonally Down Left Arrow
|
||||
sub moveConDownLeft
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $panspeed = $self->getParam( $params, 'panspeed' );
|
||||
my $tiltspeed = $self->getParam( $params, 'tiltspeed' );
|
||||
Debug( "Move Diagonally Down Left" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Direction=6&PanSpeed=$panspeed&TiltSpeed=$tiltspeed";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop($tiltspeed);
|
||||
}
|
||||
|
||||
#Stop
|
||||
sub moveStop
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Move Stop" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Stop=0";
|
||||
$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
|
||||
sub zoomConTele
|
||||
{
|
||||
my $self = shift;
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Zoom=1";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop();
|
||||
}
|
||||
|
||||
|
||||
sub zoomConWide
|
||||
{
|
||||
my $self = shift;
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Zoom=0";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop();
|
||||
}
|
||||
|
||||
|
||||
sub focusConNear
|
||||
{
|
||||
my $self = shift;
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Focus=1";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop();
|
||||
}
|
||||
|
||||
|
||||
sub focusConFar
|
||||
{
|
||||
my $self = shift;
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Focus=0";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop();
|
||||
}
|
||||
|
||||
|
||||
sub irisConOpen
|
||||
{
|
||||
my $self = shift;
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Iris=1";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop();
|
||||
}
|
||||
|
||||
|
||||
sub irisConClose
|
||||
{
|
||||
my $self = shift;
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Iris=0";
|
||||
$self->sendCmd( $cmd );
|
||||
$self->autoStop();
|
||||
}
|
||||
|
||||
|
||||
#Set preset
|
||||
sub presetSet
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $preset = $self->getParam( $params, 'preset' );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&PresetNumber=1&Preset=0";
|
||||
$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
|
||||
#Goto preset
|
||||
sub presetGoto
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $preset = $self->getParam( $params, 'preset' );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&PresetNumber=1&Preset=1";
|
||||
$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
|
||||
sub autoStop
|
||||
{
|
||||
my $self = shift;
|
||||
my $timeout = shift;
|
||||
|
||||
if ($timeout)
|
||||
{
|
||||
if ($timeout > 1) {
|
||||
usleep(100000*$timeout);
|
||||
}
|
||||
}
|
||||
Debug( "Auto Stop" );
|
||||
my $cmd = "cgi/ptz_set?Channel=1&Group=PTZCtrlInfo&Stop=0";
|
||||
$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
||||
=head1 Floureon
|
||||
|
||||
ZoneMinder::Database - Perl extension for Floureon 1080P
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
Control script for Floureon 1080P IP camera
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
When setuping you monitor in the "Control" tab:
|
||||
|
||||
1. Select "Control type": Floureon 1080P
|
||||
2. Leave "Control device" empty
|
||||
3. Fill "Control Address" like username:password@ip/domain. Example: admin:admin123@192.168.1.110
|
||||
|
||||
=head2 EXPORT
|
||||
|
||||
None by default.
|
||||
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Ognyan Bankov, E<lt>ogibankov@gmail.comE<gt>
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
Copyright (C) 2017 Ognyan Bankov
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the same terms as Perl itself, either Perl version 5.8.3 or,
|
||||
at your option, any later version of Perl 5 you may have available.
|
||||
|
||||
|
||||
=cut
|
||||
|
|
@ -390,7 +390,7 @@ sub age {
|
|||
|
||||
sub DiskSpace {
|
||||
if ( @_ > 1 ) {
|
||||
Debug("Cleared DiskSpace, was $_[0]{DiskSpace}");
|
||||
Debug("Cleared DiskSpace, was $_[0]{DiskSpace}") if $_[0]{DiskSpace};
|
||||
$_[0]{DiskSpace} = $_[1];
|
||||
}
|
||||
if ( ! defined $_[0]{DiskSpace} ) {
|
||||
|
|
|
@ -225,29 +225,41 @@ sub Sql {
|
|||
) {
|
||||
$value = "'$temp_value'";
|
||||
} elsif ( $term->{attr} eq 'DateTime' or $term->{attr} eq 'StartDateTime' or $term->{attr} eq 'EndDateTime' ) {
|
||||
$value = DateTimeToSQL( $temp_value );
|
||||
if ( !$value ) {
|
||||
Error( "Error parsing date/time '$temp_value', "
|
||||
."skipping filter '$self->{Name}'\n" );
|
||||
return;
|
||||
if ( $temp_value == 'NULL' ) {
|
||||
$value = $temp_value;
|
||||
} else {
|
||||
$value = DateTimeToSQL( $temp_value );
|
||||
if ( !$value ) {
|
||||
Error( "Error parsing date/time '$temp_value', "
|
||||
."skipping filter '$self->{Name}'\n" );
|
||||
return;
|
||||
}
|
||||
$value = "'$value'";
|
||||
}
|
||||
$value = "'$value'";
|
||||
} elsif ( $term->{attr} eq 'Date' or $term->{attr} eq 'StartDate' or $term->{attr} eq 'EndDate' ) {
|
||||
$value = DateTimeToSQL( $temp_value );
|
||||
if ( !$value ) {
|
||||
Error( "Error parsing date/time '$temp_value', "
|
||||
."skipping filter '$self->{Name}'\n" );
|
||||
return;
|
||||
if ( $temp_value == 'NULL' ) {
|
||||
$value = $temp_value;
|
||||
} else {
|
||||
$value = DateTimeToSQL( $temp_value );
|
||||
if ( !$value ) {
|
||||
Error( "Error parsing date/time '$temp_value', "
|
||||
."skipping filter '$self->{Name}'\n" );
|
||||
return;
|
||||
}
|
||||
$value = "to_days( '$value' )";
|
||||
}
|
||||
$value = "to_days( '$value' )";
|
||||
} elsif ( $term->{attr} eq 'Time' or $term->{attr} eq 'StartTime' or $term->{attr} eq 'EndTime' ) {
|
||||
$value = DateTimeToSQL( $temp_value );
|
||||
if ( !$value ) {
|
||||
Error( "Error parsing date/time '$temp_value', "
|
||||
."skipping filter '$self->{Name}'\n" );
|
||||
return;
|
||||
if ( $temp_value == 'NULL' ) {
|
||||
$value = $temp_value;
|
||||
} else {
|
||||
$value = DateTimeToSQL( $temp_value );
|
||||
if ( !$value ) {
|
||||
Error( "Error parsing date/time '$temp_value', "
|
||||
."skipping filter '$self->{Name}'\n" );
|
||||
return;
|
||||
}
|
||||
$value = "extract( hour_second from '$value' )";
|
||||
}
|
||||
$value = "extract( hour_second from '$value' )";
|
||||
} else {
|
||||
$value = $temp_value;
|
||||
}
|
||||
|
|
|
@ -21,34 +21,6 @@
|
|||
#
|
||||
# ==========================================================================
|
||||
|
||||
=head1 NAME
|
||||
|
||||
zmaudit.pl - ZoneMinder event file system and database consistency checker
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
zmaudit.pl [-r,-report|-i,-interactive]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This script checks for consistency between the event filesystem and
|
||||
the database. If events are found in one and not the other they are
|
||||
deleted (optionally). Additionally any monitor event directories that
|
||||
do not correspond to a database monitor are similarly disposed of.
|
||||
However monitors in the database that don't have a directory are left
|
||||
alone as this is valid if they are newly created and have no events
|
||||
yet.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
-c, --continuous - Run continuously
|
||||
-i, --interactive - Ask before applying any changes
|
||||
-m, --monitor_id - Restrict zmaudit actions to events pertaining to the specified monitor id
|
||||
-r, --report - Just report don't actually do anything
|
||||
-v, --version - Print the installed version of ZoneMinder
|
||||
|
||||
|
||||
=cut
|
||||
use strict;
|
||||
use bytes;
|
||||
|
||||
|
@ -81,6 +53,7 @@ use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)
|
|||
? $Config{ZM_DIR_EVENTS}
|
||||
: ($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS})
|
||||
;
|
||||
use constant ZM_AUDIT_PID => '@ZM_RUNDIR@/zmaudit.pid';
|
||||
|
||||
$| = 1;
|
||||
|
||||
|
@ -118,6 +91,17 @@ if ( ! exists $Config{ZM_AUDIT_MIN_AGE} ) {
|
|||
Fatal('ZM_AUDIT_MIN_AGE is not set in config.');
|
||||
}
|
||||
|
||||
if ( -e ZM_AUDIT_PID ) {
|
||||
Fatal('zmaudit.pl appears to already be running. If not, please delete ' . ZM_AUDIT_PID );
|
||||
} else {
|
||||
if ( open( my $PID, '>', ZM_AUDIT_PID ) ) {
|
||||
print( $PID $$ );
|
||||
close( $PID );
|
||||
} else {
|
||||
Error( "Can't open pid file at " . ZM_PID );
|
||||
}
|
||||
}
|
||||
|
||||
my $dbh = zmDbConnect();
|
||||
|
||||
require ZoneMinder::Monitor;
|
||||
|
@ -598,6 +582,7 @@ Debug("Event $db_event is not in fs.");
|
|||
sleep( $Config{ZM_AUDIT_CHECK_INTERVAL} ) if $continuous;
|
||||
};
|
||||
|
||||
unlink ZM_AUDIT_PID;
|
||||
exit( 0 );
|
||||
|
||||
sub aud_print {
|
||||
|
@ -688,3 +673,30 @@ sub delete_empty_directories {
|
|||
|
||||
1;
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
zmaudit.pl - ZoneMinder event file system and database consistency checker
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
zmaudit.pl [-r,-report|-i,-interactive]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This script checks for consistency between the event filesystem and
|
||||
the database. If events are found in one and not the other they are
|
||||
deleted (optionally). Additionally any monitor event directories that
|
||||
do not correspond to a database monitor are similarly disposed of.
|
||||
However monitors in the database that don't have a directory are left
|
||||
alone as this is valid if they are newly created and have no events
|
||||
yet.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
-c, --continuous - Run continuously
|
||||
-i, --interactive - Ask before applying any changes
|
||||
-r, --report - Just report don't actually do anything
|
||||
-v, --version - Print the installed version of ZoneMinder
|
||||
|
||||
=cut
|
||||
|
|
|
@ -21,20 +21,6 @@
|
|||
#
|
||||
# ==========================================================================
|
||||
|
||||
=head1 NAME
|
||||
|
||||
zmpkg.pl - ZoneMinder Package Control Script
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
zmpkg.pl {start|stop|restart|status|logrot|'state'|version}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This script is used to start and stop the ZoneMinder package primarily to
|
||||
allow command line control for automatic restart on reboot (see zm script)
|
||||
|
||||
=cut
|
||||
use strict;
|
||||
use bytes;
|
||||
|
||||
|
@ -61,48 +47,41 @@ logInit();
|
|||
|
||||
my $command = $ARGV[0]||'';
|
||||
if ( $command eq 'version' ) {
|
||||
print ZoneMinder::Base::ZM_VERSION . "\n";
|
||||
exit(0);
|
||||
print ZoneMinder::Base::ZM_VERSION . "\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
my $state;
|
||||
|
||||
my $dbh;
|
||||
|
||||
if ( !$command || $command !~ /^(?:start|stop|restart|status|logrot|version)$/ )
|
||||
{
|
||||
if ( $command )
|
||||
{
|
||||
$dbh = zmDbConnect();
|
||||
# Check to see if it's a valid run state
|
||||
my $sql = 'select * from States where Name = ?';
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $command )
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
if ( $state = $sth->fetchrow_hashref() )
|
||||
{
|
||||
$state->{Name} = $command;
|
||||
$state->{Definitions} = [];
|
||||
foreach( split( /,/, $state->{Definition} ) )
|
||||
{
|
||||
my ( $id, $function, $enabled ) = split( /:/, $_ );
|
||||
push( @{$state->{Definitions}},
|
||||
{ Id=>$id, Function=>$function, Enabled=>$enabled }
|
||||
);
|
||||
}
|
||||
$store_state=$command; # PP - Remember the name that was passed to search in DB
|
||||
$command = 'state';
|
||||
}
|
||||
else
|
||||
{
|
||||
$command = undef;
|
||||
}
|
||||
}
|
||||
if ( !$command )
|
||||
{
|
||||
pod2usage(-exitstatus => -1);
|
||||
if ( !$command || $command !~ /^(?:start|stop|restart|status|logrot|version)$/ ) {
|
||||
if ( $command ) {
|
||||
$dbh = zmDbConnect();
|
||||
# Check to see if it's a valid run state
|
||||
my $sql = 'SELECT * FROM States WHERE Name=?';
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $command )
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
if ( $state = $sth->fetchrow_hashref() ) {
|
||||
$state->{Name} = $command;
|
||||
$state->{Definitions} = [];
|
||||
foreach( split( /,/, $state->{Definition} ) ) {
|
||||
my ( $id, $function, $enabled ) = split( /:/, $_ );
|
||||
push( @{$state->{Definitions}},
|
||||
{ Id=>$id, Function=>$function, Enabled=>$enabled }
|
||||
);
|
||||
}
|
||||
$store_state=$command; # PP - Remember the name that was passed to search in DB
|
||||
$command = 'state';
|
||||
} else {
|
||||
$command = undef;
|
||||
}
|
||||
}
|
||||
if ( !$command ) {
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
}
|
||||
$dbh = zmDbConnect() if ! $dbh;
|
||||
# PP - Sane state check
|
||||
|
@ -110,324 +89,297 @@ isActiveSanityCheck();
|
|||
|
||||
# Move to the right place
|
||||
chdir( $Config{ZM_PATH_WEB} )
|
||||
or Fatal( "Can't chdir to '".$Config{ZM_PATH_WEB}."': $!" );
|
||||
or Fatal( "Can't chdir to '".$Config{ZM_PATH_WEB}."': $!" );
|
||||
|
||||
my $dbg_id = "";
|
||||
my $dbg_id = '';
|
||||
|
||||
Info( "Command: $command\n" );
|
||||
Info( "Command: $command\n" );
|
||||
|
||||
my $retval = 0;
|
||||
my $retval = 0;
|
||||
|
||||
if ( $command eq "state" )
|
||||
{
|
||||
if ( $command eq 'state' ) {
|
||||
Info( "Updating DB: $state->{Name}\n" );
|
||||
my $sql = $Config{ZM_SERVER_ID} ? 'SELECT * FROM Monitors WHERE ServerId=? ORDER BY Id ASC' : 'SELECT * FROM Monitors ORDER BY Id ASC';
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID}: () )
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
while( my $monitor = $sth->fetchrow_hashref() )
|
||||
{
|
||||
foreach my $definition ( @{$state->{Definitions}} )
|
||||
{
|
||||
if ( $monitor->{Id} =~ /^$definition->{Id}$/ )
|
||||
{
|
||||
$monitor->{NewFunction} = $definition->{Function};
|
||||
$monitor->{NewEnabled} = $definition->{Enabled};
|
||||
}
|
||||
}
|
||||
#next if ( !$monitor->{NewFunction} );
|
||||
$monitor->{NewFunction} = 'None'
|
||||
if ( !$monitor->{NewFunction} );
|
||||
$monitor->{NewEnabled} = 0
|
||||
if ( !$monitor->{NewEnabled} );
|
||||
if ( $monitor->{Function} ne $monitor->{NewFunction}
|
||||
|| $monitor->{Enabled} ne $monitor->{NewEnabled}
|
||||
)
|
||||
{
|
||||
my $sql = "update Monitors set Function = ?, Enabled = ? where Id = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $monitor->{NewFunction}, $monitor->{NewEnabled}, $monitor->{Id} )
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
while( my $monitor = $sth->fetchrow_hashref() ) {
|
||||
foreach my $definition ( @{$state->{Definitions}} ) {
|
||||
if ( $monitor->{Id} =~ /^$definition->{Id}$/ ) {
|
||||
$monitor->{NewFunction} = $definition->{Function};
|
||||
$monitor->{NewEnabled} = $definition->{Enabled};
|
||||
}
|
||||
}
|
||||
#next if ( !$monitor->{NewFunction} );
|
||||
$monitor->{NewFunction} = 'None'
|
||||
if ( !$monitor->{NewFunction} );
|
||||
$monitor->{NewEnabled} = 0
|
||||
if ( !$monitor->{NewEnabled} );
|
||||
if ( $monitor->{Function} ne $monitor->{NewFunction}
|
||||
|| $monitor->{Enabled} ne $monitor->{NewEnabled}
|
||||
) {
|
||||
my $sql = 'UPDATE Monitors SET Function=?, Enabled=? WHERE Id=?';
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $monitor->{NewFunction}, $monitor->{NewEnabled}, $monitor->{Id} )
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
}
|
||||
}
|
||||
$sth->finish();
|
||||
|
||||
# PP - Now mark a specific state as active
|
||||
# PP - Now mark a specific state as active
|
||||
resetStates();
|
||||
Info ("Marking $store_state as Enabled");
|
||||
$sql = "update States set IsActive = '1' where Name = ?";
|
||||
$sql = "UPDATE States SET IsActive = '1' WHERE Name = ?";
|
||||
$sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
$res = $sth->execute( $store_state )
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
|
||||
# PP - zero out other states isActive
|
||||
$command = "restart";
|
||||
}
|
||||
# PP - zero out other states isActive
|
||||
$command = 'restart';
|
||||
}
|
||||
|
||||
# Check if we are running systemd and if we have been called by the system
|
||||
if ( $command =~ /^(start|stop|restart)$/ )
|
||||
{
|
||||
# We have to detaint to keep perl from complaining
|
||||
$command = $1;
|
||||
if ( $command =~ /^(start|stop|restart)$/ ) {
|
||||
# We have to detaint to keep perl from complaining
|
||||
$command = $1;
|
||||
|
||||
|
||||
if ( systemdRunning() && !calledBysystem() ) {
|
||||
qx(@BINDIR@/zmsystemctl.pl $command);
|
||||
$command = "";
|
||||
}
|
||||
if ( systemdRunning() && !calledBysystem() ) {
|
||||
qx(@BINDIR@/zmsystemctl.pl $command);
|
||||
$command = '';
|
||||
}
|
||||
}
|
||||
|
||||
if ( $command =~ /^(?:stop|restart)$/ )
|
||||
{
|
||||
my $status = runCommand( "zmdc.pl check" );
|
||||
if ( $command =~ /^(?:stop|restart)$/ ) {
|
||||
my $status = runCommand('zmdc.pl check');
|
||||
|
||||
if ( $status eq "running" )
|
||||
{
|
||||
runCommand( "zmdc.pl shutdown" );
|
||||
zmMemTidy();
|
||||
}
|
||||
else
|
||||
{
|
||||
$retval = 1;
|
||||
}
|
||||
if ( $status eq 'running' ) {
|
||||
runCommand('zmdc.pl shutdown');
|
||||
zmMemTidy();
|
||||
} else {
|
||||
$retval = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#runCommand( "zmupdate.pl -f" );
|
||||
|
||||
if ( $command =~ /^(?:start|restart)$/ )
|
||||
{
|
||||
my $status = runCommand( "zmdc.pl check" );
|
||||
if ( $command =~ /^(?:start|restart)$/ ) {
|
||||
my $status = runCommand('zmdc.pl check');
|
||||
|
||||
if ( $status eq "stopped" )
|
||||
{
|
||||
if ( $Config{ZM_DYN_DB_VERSION}
|
||||
and ( $Config{ZM_DYN_DB_VERSION} ne ZM_VERSION )
|
||||
)
|
||||
{
|
||||
Fatal( "Version mismatch, system is version ".ZM_VERSION
|
||||
.", database is ".$Config{ZM_DYN_DB_VERSION}
|
||||
.", please run zmupdate.pl to update."
|
||||
);
|
||||
exit( -1 );
|
||||
}
|
||||
if ( $status eq 'stopped' ) {
|
||||
if ( $Config{ZM_DYN_DB_VERSION}
|
||||
and ( $Config{ZM_DYN_DB_VERSION} ne ZM_VERSION )
|
||||
) {
|
||||
Fatal( 'Version mismatch, system is version '.ZM_VERSION
|
||||
.', database is '.$Config{ZM_DYN_DB_VERSION}
|
||||
.', please run zmupdate.pl to update.'
|
||||
);
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
# Recreate the temporary directory if it's been wiped
|
||||
verifyFolder("@ZM_TMPDIR@");
|
||||
# Recreate the temporary directory if it's been wiped
|
||||
verifyFolder('@ZM_TMPDIR@');
|
||||
|
||||
# Recreate the run directory if it's been wiped
|
||||
verifyFolder("@ZM_RUNDIR@");
|
||||
# Recreate the run directory if it's been wiped
|
||||
verifyFolder('@ZM_RUNDIR@');
|
||||
|
||||
# Recreate the sock directory if it's been wiped
|
||||
verifyFolder("@ZM_SOCKDIR@");
|
||||
# Recreate the sock directory if it's been wiped
|
||||
verifyFolder('@ZM_SOCKDIR@');
|
||||
|
||||
zmMemTidy();
|
||||
runCommand( "zmdc.pl startup" );
|
||||
zmMemTidy();
|
||||
runCommand('zmdc.pl startup');
|
||||
|
||||
if ( $Config{ZM_SERVER_ID} ) {
|
||||
Info( "Multi-server configuration detected. Starting up services for server $Config{ZM_SERVER_ID}\n");
|
||||
if ( $Config{ZM_SERVER_ID} ) {
|
||||
Info("Multi-server configuration detected. Starting up services for server $Config{ZM_SERVER_ID}\n");
|
||||
} else {
|
||||
Info('Single server configuration detected. Starting up services.');
|
||||
}
|
||||
|
||||
my $sql = $Config{ZM_SERVER_ID} ? 'SELECT * FROM Monitors WHERE ServerId=?' : 'SELECT * FROM Monitors';
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID} : () )
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
while( my $monitor = $sth->fetchrow_hashref() ) {
|
||||
if ( $monitor->{Function} ne 'None' ) {
|
||||
if ( $monitor->{Type} eq 'Local' ) {
|
||||
runCommand( "zmdc.pl start zmc -d $monitor->{Device}" );
|
||||
} else {
|
||||
Info( "Single server configuration detected. Starting up services." );
|
||||
runCommand( "zmdc.pl start zmc -m $monitor->{Id}" );
|
||||
}
|
||||
|
||||
my $sql = $Config{ZM_SERVER_ID} ? 'SELECT * FROM Monitors WHERE ServerId=?' : 'SELECT * FROM Monitors';
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID} : () )
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
while( my $monitor = $sth->fetchrow_hashref() )
|
||||
{
|
||||
if ( $monitor->{Function} ne 'None' )
|
||||
{
|
||||
if ( $monitor->{Type} eq 'Local' )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmc -d $monitor->{Device}" );
|
||||
}
|
||||
else
|
||||
{
|
||||
runCommand( "zmdc.pl start zmc -m $monitor->{Id}" );
|
||||
}
|
||||
if ( $monitor->{Function} ne 'Monitor' )
|
||||
{
|
||||
runCommand( "zmdc.pl start zma -m $monitor->{Id}" );
|
||||
}
|
||||
if ( $Config{ZM_OPT_CONTROL} )
|
||||
{
|
||||
if ( $monitor->{Function} eq 'Modect' || $monitor->{Function} eq 'Mocord' )
|
||||
{
|
||||
if ( $monitor->{Controllable} && $monitor->{TrackMotion} )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmtrack.pl -m $monitor->{Id}" );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( $monitor->{Function} ne 'Monitor' ) {
|
||||
runCommand( "zmdc.pl start zma -m $monitor->{Id}" );
|
||||
}
|
||||
if ( $Config{ZM_OPT_CONTROL} ) {
|
||||
if ( $monitor->{Function} eq 'Modect' || $monitor->{Function} eq 'Mocord' ) {
|
||||
if ( $monitor->{Controllable} && $monitor->{TrackMotion} ) {
|
||||
runCommand( "zmdc.pl start zmtrack.pl -m $monitor->{Id}" );
|
||||
}
|
||||
}
|
||||
}
|
||||
$sth->finish();
|
||||
}
|
||||
}
|
||||
$sth->finish();
|
||||
|
||||
# This is now started unconditionally
|
||||
runCommand( "zmdc.pl start zmfilter.pl" );
|
||||
if ( $Config{ZM_RUN_AUDIT} )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmaudit.pl -c" );
|
||||
}
|
||||
if ( $Config{ZM_OPT_TRIGGERS} )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmtrigger.pl" );
|
||||
}
|
||||
if ( $Config{ZM_OPT_X10} )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmx10.pl -c start" );
|
||||
}
|
||||
runCommand( "zmdc.pl start zmwatch.pl" );
|
||||
if ( $Config{ZM_CHECK_FOR_UPDATES} )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmupdate.pl -c" );
|
||||
}
|
||||
if ( $Config{ZM_TELEMETRY_DATA} )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmtelemetry.pl" );
|
||||
}
|
||||
# This is now started unconditionally
|
||||
runCommand('zmdc.pl start zmfilter.pl');
|
||||
if ( $Config{ZM_RUN_AUDIT} ) {
|
||||
runCommand('zmdc.pl start zmaudit.pl -c');
|
||||
}
|
||||
else
|
||||
{
|
||||
$retval = 1;
|
||||
if ( $Config{ZM_OPT_TRIGGERS} ) {
|
||||
runCommand('zmdc.pl start zmtrigger.pl');
|
||||
}
|
||||
if ( $Config{ZM_OPT_X10} ) {
|
||||
runCommand('zmdc.pl start zmx10.pl -c start');
|
||||
}
|
||||
runCommand('zmdc.pl start zmwatch.pl');
|
||||
if ( $Config{ZM_CHECK_FOR_UPDATES} ) {
|
||||
runCommand('zmdc.pl start zmupdate.pl -c');
|
||||
}
|
||||
if ( $Config{ZM_TELEMETRY_DATA} ) {
|
||||
runCommand('zmdc.pl start zmtelemetry.pl');
|
||||
}
|
||||
} else {
|
||||
$retval = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $command eq "status" )
|
||||
{
|
||||
my $status = runCommand( "zmdc.pl check" );
|
||||
if ( $command eq 'status' ) {
|
||||
my $status = runCommand('zmdc.pl check');
|
||||
|
||||
print( STDOUT $status."\n" );
|
||||
}
|
||||
|
||||
if ( $command eq "logrot" )
|
||||
{
|
||||
runCommand( "zmdc.pl logrot" );
|
||||
print( STDOUT $status."\n" );
|
||||
} elsif ( $command eq 'logrot' ) {
|
||||
runCommand('zmdc.pl logrot');
|
||||
}
|
||||
|
||||
exit( $retval );
|
||||
|
||||
# PP - Make sure isActive is on and only one
|
||||
sub isActiveSanityCheck
|
||||
{
|
||||
sub isActiveSanityCheck {
|
||||
|
||||
Info ("Sanity checking States table...");
|
||||
$dbh = zmDbConnect() if ! $dbh;
|
||||
Info ('Sanity checking States table...');
|
||||
$dbh = zmDbConnect() if ! $dbh;
|
||||
|
||||
# PP - First, make sure default exists and there is only one
|
||||
my $sql = "select Name from States where Name = 'default'";
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute()
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
# PP - First, make sure default exists and there is only one
|
||||
my $sql = "SELECT Name FROM States WHERE Name='default'";
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute()
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
|
||||
if ($sth->rows != 1) # PP - no row, or too many rows. Either case is an error
|
||||
{
|
||||
Info( "Fixing States table - either no default state or duplicate default states" );
|
||||
$sql = "delete from States where Name = 'default'";
|
||||
$sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
$res = $sth->execute()
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
$sql = "insert into States (Name,Definition,IsActive) VALUES ('default','','1');";
|
||||
$sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
$res = $sth->execute()
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
}
|
||||
if ($sth->rows != 1) {
|
||||
# PP - no row, or too many rows. Either case is an error
|
||||
Info( 'Fixing States table - either no default state or duplicate default states' );
|
||||
$sql = "DELETE FROM States WHERE Name='default'";
|
||||
$sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
$res = $sth->execute()
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
$sql = "INSERT INTO States (Name,Definition,IsActive) VALUES ('default','','1');";
|
||||
$sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
$res = $sth->execute()
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
}
|
||||
|
||||
|
||||
# PP - Now make sure no two states have IsActive=1
|
||||
$sql = "select Name from States where IsActive = '1'";
|
||||
$sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
$res = $sth->execute()
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
# PP - Now make sure no two states have IsActive=1
|
||||
$sql = "SELECT Name FROM States WHERE IsActive = '1'";
|
||||
$sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
$res = $sth->execute()
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
|
||||
if ( $sth->rows != 1 )
|
||||
{
|
||||
Info( "Fixing States table so only one run state is active" );
|
||||
resetStates();
|
||||
$sql = "update States set IsActive='1' WHERE Name='default'";
|
||||
$sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
$res = $sth->execute()
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
|
||||
|
||||
}
|
||||
if ( $sth->rows != 1 ) {
|
||||
Info( 'Fixing States table so only one run state is active' );
|
||||
resetStates();
|
||||
$sql = "UPDATE States SET IsActive='1' WHERE Name='default'";
|
||||
$sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
$res = $sth->execute()
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# PP - zeroes out isActive for all states
|
||||
sub resetStates
|
||||
{
|
||||
$dbh = zmDbConnect() if ! $dbh;
|
||||
my $sql = "update States set IsActive = '0'";
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute()
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
sub resetStates {
|
||||
$dbh = zmDbConnect() if ! $dbh;
|
||||
my $sql = "UPDATE States SET IsActive='0'";
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute()
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
|
||||
}
|
||||
|
||||
sub systemdRunning
|
||||
{
|
||||
my $result = 0;
|
||||
sub systemdRunning {
|
||||
my $result = 0;
|
||||
|
||||
my $output = qx(ps -o comm="" -p 1);
|
||||
chomp( $output );
|
||||
my $output = qx(ps -o comm="" -p 1);
|
||||
chomp( $output );
|
||||
|
||||
if ($output =~ /systemd/) {
|
||||
$result = 1;
|
||||
if ( $output =~ /systemd/ ) {
|
||||
$result = 1;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub calledBysystem {
|
||||
my $result = 0;
|
||||
my $ppid = getppid();
|
||||
|
||||
my $output = qx(ps -o comm="" -p $ppid);
|
||||
chomp( $output );
|
||||
|
||||
if ($output =~ /^(?:systemd|init)$/) {
|
||||
$result = 1;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub verifyFolder {
|
||||
my $folder = shift;
|
||||
|
||||
# Recreate the temporary directory if it's been wiped
|
||||
if ( !-e $folder ) {
|
||||
Debug( "Recreating directory '$folder'" );
|
||||
mkdir( $folder, 0774 )
|
||||
or Fatal( "Can't create missing temporary directory '$folder': $!" );
|
||||
my ( $runName ) = getpwuid( $> );
|
||||
if ( $runName ne $Config{ZM_WEB_USER} ) {
|
||||
# Not running as web user, so should be root in which case
|
||||
# chown the directory
|
||||
my ( $webName, $webPass, $webUid, $webGid ) = getpwnam( $Config{ZM_WEB_USER} )
|
||||
or Fatal( "Can't get user details for web user '"
|
||||
.$Config{ZM_WEB_USER}."': $!"
|
||||
);
|
||||
chown( $webUid, $webGid, "$folder" )
|
||||
or Fatal( "Can't change ownership of directory '$folder' to '"
|
||||
.$Config{ZM_WEB_USER}.":".$Config{ZM_WEB_GROUP}."': $!"
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
sub calledBysystem
|
||||
{
|
||||
my $result = 0;
|
||||
my $ppid = getppid();
|
||||
|
||||
my $output = qx(ps -o comm="" -p $ppid);
|
||||
chomp( $output );
|
||||
|
||||
if ($output =~ /^(?:systemd|init)$/) {
|
||||
$result = 1;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub verifyFolder
|
||||
{
|
||||
my $folder = shift;
|
||||
|
||||
# Recreate the temporary directory if it's been wiped
|
||||
if ( !-e $folder )
|
||||
{
|
||||
Debug( "Recreating directory '$folder'" );
|
||||
mkdir( "$folder", 0774 )
|
||||
or Fatal( "Can't create missing temporary directory '$folder': $!" );
|
||||
my ( $runName ) = getpwuid( $> );
|
||||
if ( $runName ne $Config{ZM_WEB_USER} )
|
||||
{
|
||||
# Not running as web user, so should be root in which case
|
||||
# chown the directory
|
||||
my ( $webName, $webPass, $webUid, $webGid ) = getpwnam( $Config{ZM_WEB_USER} )
|
||||
or Fatal( "Can't get user details for web user '"
|
||||
.$Config{ZM_WEB_USER}."': $!"
|
||||
);
|
||||
chown( $webUid, $webGid, "$folder" )
|
||||
or Fatal( "Can't change ownership of directory '$folder' to '"
|
||||
.$Config{ZM_WEB_USER}.":".$Config{ZM_WEB_GROUP}."': $!"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
1;
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
zmpkg.pl - ZoneMinder Package Control Script
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
zmpkg.pl {start|stop|restart|status|logrot|'state'|version}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This script is used to start and stop the ZoneMinder package primarily to
|
||||
allow command line control for automatic restart on reboot (see zm script)
|
||||
|
||||
=cut
|
||||
|
|
|
@ -55,6 +55,7 @@ use constant START_DELAY => 30; # To give everything else time to start
|
|||
|
||||
@EXTRA_PERL_LIB@
|
||||
use ZoneMinder;
|
||||
use ZoneMinder::Storage;
|
||||
use POSIX;
|
||||
use DBI;
|
||||
use autouse 'Data::Dumper'=>qw(Dumper);
|
||||
|
@ -78,24 +79,42 @@ my $sql = $Config{ZM_SERVER_ID} ? 'SELECT * FROM Monitors WHERE ServerId=?' : 'S
|
|||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
|
||||
my $eventcounts_sql = q`
|
||||
UPDATE Monitors SET
|
||||
TotalEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id),
|
||||
TotalEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND DiskSpace IS NOT NULL),
|
||||
HourEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB( NOW(), INTERVAL 1 hour) ),
|
||||
HourEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB(NOW(), INTERVAL 1 hour) AND DiskSpace IS NOT NULL),
|
||||
DayEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB(NOW(), INTERVAL 1 day)),
|
||||
DayEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB(NOW(), INTERVAL 1 day) AND DiskSpace IS NOT NULL),
|
||||
WeekEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB(NOW(), INTERVAL 1 week)),
|
||||
WeekEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB(NOW(), INTERVAL 1 week) AND DiskSpace IS NOT NULL),
|
||||
MonthEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB( NOW(), INTERVAL 1 month)),
|
||||
MonthEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB(NOW(), INTERVAL 1 month) AND DiskSpace IS NOT NULL),
|
||||
ArchivedEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id AND Archived=1),
|
||||
ArchivedEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND Archived=1 AND DiskSpace IS NOT NULL)
|
||||
WHERE Id=?`;
|
||||
|
||||
my $eventcounts_sth = $dbh->prepare_cached( $eventcounts_sql );
|
||||
|
||||
while( 1 ) {
|
||||
my $now = time();
|
||||
my $res = $sth->execute( $Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID} : () )
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
while( my $monitor = $sth->fetchrow_hashref() ) {
|
||||
my $now = time();
|
||||
next if $monitor->{Function} eq 'None';
|
||||
my $restart = 0;
|
||||
if ( zmMemVerify( $monitor ) ) {
|
||||
# Check we have got an image recently
|
||||
my $image_time = zmGetLastWriteTime( $monitor );
|
||||
if ( !defined($image_time) ) {
|
||||
my $capture_time = zmGetLastWriteTime( $monitor );
|
||||
if ( !defined($capture_time) ) {
|
||||
# Can't read from shared data
|
||||
Debug( "LastWriteTime is not defined." );
|
||||
zmMemInvalidate( $monitor );
|
||||
next;
|
||||
}
|
||||
Debug( "LastWriteTime is = $image_time." );
|
||||
if ( !$image_time ) {
|
||||
Debug( "LastWriteTime is = $capture_time." );
|
||||
if ( !$capture_time ) {
|
||||
my $startup_time = zmGetStartupTime( $monitor );
|
||||
if ( $now - $startup_time > $Config{ZM_WATCH_MAX_DELAY} ) {
|
||||
Info( "Restarting capture daemon for ".$monitor->{Name}.", no image since startup. Startup time was $startup_time - now $now > $Config{ZM_WATCH_MAX_DELAY}\n" );
|
||||
|
@ -103,7 +122,7 @@ while( 1 ) {
|
|||
} else {
|
||||
# We can't get the last capture time so can't be sure it's died, it might just be starting up.
|
||||
zmMemInvalidate( $monitor );
|
||||
next;
|
||||
next;
|
||||
}
|
||||
}
|
||||
if ( ! $restart ) {
|
||||
|
@ -113,11 +132,11 @@ while( 1 ) {
|
|||
) ? (3/$monitor->{MaxFPS})
|
||||
: $Config{ZM_WATCH_MAX_DELAY}
|
||||
;
|
||||
my $image_delay = $now-$image_time;
|
||||
my $image_delay = $now-$capture_time;
|
||||
Debug( "Monitor $monitor->{Id} last captured $image_delay seconds ago, max is $max_image_delay\n" );
|
||||
if ( $image_delay > $max_image_delay ) {
|
||||
Info( "Restarting capture daemon for "
|
||||
.$monitor->{Name}.", time since last capture $image_delay seconds ($now-$image_time)\n"
|
||||
.$monitor->{Name}.", time since last capture $image_delay seconds ($now-$capture_time)\n"
|
||||
);
|
||||
$restart = 1;
|
||||
}
|
||||
|
@ -147,7 +166,7 @@ while( 1 ) {
|
|||
} elsif ( !$image_time ) {
|
||||
# We can't get the last capture time so can't be sure it's died.
|
||||
$restart = 1;
|
||||
Error( "Error getting last capture time for $$monitor{Id} $$monitor{Name}\n");
|
||||
Error( "Error getting last analyse time for $$monitor{Id} $$monitor{Name}\n");
|
||||
} else {
|
||||
|
||||
my $max_image_delay = ( $monitor->{MaxFPS}
|
||||
|
@ -174,7 +193,23 @@ while( 1 ) {
|
|||
} # end if check analysis daemon
|
||||
# Prevent open handles building up if we have connect to shared memory
|
||||
zmMemInvalidate( $monitor ); # Close our file handle to the zmc process we are about to end
|
||||
|
||||
|
||||
$eventcounts_sth->execute( $$monitor{Id} ) or Error( "Can't execute: ".$eventcounts_sth->errstr() );
|
||||
|
||||
} # end foreach monitor
|
||||
$eventcounts_sth->finish();
|
||||
|
||||
my $diskspace_sql = 'UPDATE Storage SET DiskSpace =(SELECT SUM(DiskSpace) FROM Events WHERE StorageId=? AND DiskSpace IS NOT NULL)';
|
||||
my $diskspace_sth = $dbh->prepare_cached( $diskspace_sql )
|
||||
or Fatal( "Can't prepare '$diskspace_sql': ".$dbh->errstr() );
|
||||
foreach my $Storage ( ZoneMinder::Storage->find() ) {
|
||||
Debug("Updating disk space for $$Storage{Name} was $$Storage{DiskSpace}");
|
||||
$diskspace_sth->execute( $$Storage{Id} ) or Error( "Can't execute: ".$diskspace_sth->errstr() );
|
||||
$Storage->load();
|
||||
Debug("Updated disk space for $$Storage{Name} to $$Storage{DiskSpace}");
|
||||
}
|
||||
$diskspace_sth->finish();
|
||||
sleep( $Config{ZM_WATCH_CHECK_INTERVAL} );
|
||||
} # end while (1)
|
||||
|
||||
|
|
|
@ -42,11 +42,10 @@
|
|||
#include <sys/filio.h> // define FIONREAD
|
||||
#endif
|
||||
|
||||
int CommsBase::readV( int iovcnt, /* const void *, int, */ ... )
|
||||
{
|
||||
int CommsBase::readV( int iovcnt, /* const void *, int, */ ... ) {
|
||||
va_list arg_ptr;
|
||||
//struct iovec iov[iovcnt];
|
||||
struct iovec *iov = (struct iovec *)alloca( sizeof(struct iovec)*iovcnt );
|
||||
struct iovec iov[iovcnt];
|
||||
//struct iovec *iov = (struct iovec *)alloca( sizeof(struct iovec)*iovcnt );
|
||||
|
||||
va_start( arg_ptr, iovcnt );
|
||||
for ( int i = 0; i < iovcnt; i++ )
|
||||
|
@ -62,11 +61,10 @@ int CommsBase::readV( int iovcnt, /* const void *, int, */ ... )
|
|||
return( nBytes );
|
||||
}
|
||||
|
||||
int CommsBase::writeV( int iovcnt, /* const void *, int, */ ... )
|
||||
{
|
||||
int CommsBase::writeV( int iovcnt, /* const void *, int, */ ... ) {
|
||||
va_list arg_ptr;
|
||||
//struct iovec iov[iovcnt];
|
||||
struct iovec *iov = (struct iovec *)alloca( sizeof(struct iovec)*iovcnt );
|
||||
struct iovec iov[iovcnt];
|
||||
//struct iovec *iov = (struct iovec *)alloca( sizeof(struct iovec)*iovcnt );
|
||||
|
||||
va_start( arg_ptr, iovcnt );
|
||||
for ( int i = 0; i < iovcnt; i++ )
|
||||
|
|
332
src/zm_comms.h
332
src/zm_comms.h
|
@ -37,26 +37,20 @@
|
|||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
class CommsException : public Exception
|
||||
{
|
||||
class CommsException : public Exception {
|
||||
public:
|
||||
CommsException( const std::string &message ) : Exception( message )
|
||||
{
|
||||
}
|
||||
explicit CommsException( const std::string &message ) : Exception( message ) { }
|
||||
};
|
||||
|
||||
class CommsBase
|
||||
{
|
||||
class CommsBase {
|
||||
protected:
|
||||
const int &mRd;
|
||||
const int &mWd;
|
||||
|
||||
protected:
|
||||
CommsBase( int &rd, int &wd ) : mRd( rd ), mWd( wd )
|
||||
{
|
||||
CommsBase( int &rd, int &wd ) : mRd( rd ), mWd( wd ) {
|
||||
}
|
||||
virtual ~CommsBase()
|
||||
{
|
||||
virtual ~CommsBase() {
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -66,42 +60,35 @@ public:
|
|||
virtual bool setBlocking( bool blocking )=0;
|
||||
|
||||
public:
|
||||
int getReadDesc() const
|
||||
{
|
||||
int getReadDesc() const {
|
||||
return( mRd );
|
||||
}
|
||||
int getWriteDesc() const
|
||||
{
|
||||
int getWriteDesc() const {
|
||||
return( mWd );
|
||||
}
|
||||
int getMaxDesc() const
|
||||
{
|
||||
int getMaxDesc() const {
|
||||
return( mRd>mWd?mRd:mWd );
|
||||
}
|
||||
|
||||
virtual int read( void *msg, int len )
|
||||
{
|
||||
virtual int read( void *msg, int len ) {
|
||||
ssize_t nBytes = ::read( mRd, msg, len );
|
||||
if ( nBytes < 0 )
|
||||
Debug( 1, "Read of %d bytes max on rd %d failed: %s", len, mRd, strerror(errno) );
|
||||
return( nBytes );
|
||||
}
|
||||
virtual int write( const void *msg, int len )
|
||||
{
|
||||
virtual int write( const void *msg, int len ) {
|
||||
ssize_t nBytes = ::write( mWd, msg, len );
|
||||
if ( nBytes < 0 )
|
||||
Debug( 1, "Write of %d bytes on wd %d failed: %s", len, mWd, strerror(errno) );
|
||||
return( nBytes );
|
||||
}
|
||||
virtual int readV( const struct iovec *iov, int iovcnt )
|
||||
{
|
||||
virtual int readV( const struct iovec *iov, int iovcnt ) {
|
||||
int nBytes = ::readv( mRd, iov, iovcnt );
|
||||
if ( nBytes < 0 )
|
||||
Debug( 1, "Readv of %d buffers max on rd %d failed: %s", iovcnt, mRd, strerror(errno) );
|
||||
return( nBytes );
|
||||
}
|
||||
virtual int writeV( const struct iovec *iov, int iovcnt )
|
||||
{
|
||||
virtual int writeV( const struct iovec *iov, int iovcnt ) {
|
||||
ssize_t nBytes = ::writev( mWd, iov, iovcnt );
|
||||
if ( nBytes < 0 )
|
||||
Debug( 1, "Writev of %d buffers on wd %d failed: %s", iovcnt, mWd, strerror(errno) );
|
||||
|
@ -111,19 +98,16 @@ public:
|
|||
virtual int writeV( int iovcnt, /* const void *msg1, int len1, */ ... );
|
||||
};
|
||||
|
||||
class Pipe : public CommsBase
|
||||
{
|
||||
class Pipe : public CommsBase {
|
||||
protected:
|
||||
int mFd[2];
|
||||
|
||||
public:
|
||||
Pipe() : CommsBase( mFd[0], mFd[1] )
|
||||
{
|
||||
Pipe() : CommsBase( mFd[0], mFd[1] ) {
|
||||
mFd[0] = -1;
|
||||
mFd[1] = -1;
|
||||
}
|
||||
~Pipe()
|
||||
{
|
||||
~Pipe() {
|
||||
close();
|
||||
}
|
||||
|
||||
|
@ -147,46 +131,39 @@ public:
|
|||
bool setBlocking( bool blocking );
|
||||
};
|
||||
|
||||
class SockAddr
|
||||
{
|
||||
class SockAddr {
|
||||
private:
|
||||
const struct sockaddr *mAddr;
|
||||
|
||||
public:
|
||||
SockAddr( const struct sockaddr *addr );
|
||||
virtual ~SockAddr()
|
||||
{
|
||||
explicit SockAddr( const struct sockaddr *addr );
|
||||
virtual ~SockAddr() {
|
||||
}
|
||||
|
||||
static SockAddr *newSockAddr( const struct sockaddr &addr, socklen_t len );
|
||||
static SockAddr *newSockAddr( const SockAddr *addr );
|
||||
|
||||
int getDomain() const
|
||||
{
|
||||
int getDomain() const {
|
||||
return( mAddr?mAddr->sa_family:AF_UNSPEC );
|
||||
}
|
||||
|
||||
const struct sockaddr *getAddr() const
|
||||
{
|
||||
const struct sockaddr *getAddr() const {
|
||||
return( mAddr );
|
||||
}
|
||||
virtual socklen_t getAddrSize() const=0;
|
||||
virtual struct sockaddr *getTempAddr() const=0;
|
||||
};
|
||||
|
||||
class SockAddrInet : public SockAddr
|
||||
{
|
||||
class SockAddrInet : public SockAddr {
|
||||
private:
|
||||
struct sockaddr_in mAddrIn;
|
||||
struct sockaddr_in mTempAddrIn;
|
||||
|
||||
public:
|
||||
SockAddrInet();
|
||||
SockAddrInet( const SockAddrInet &addr ) : SockAddr( (const struct sockaddr *)&mAddrIn ), mAddrIn( addr.mAddrIn )
|
||||
{
|
||||
explicit SockAddrInet( const SockAddrInet &addr ) : SockAddr( (const struct sockaddr *)&mAddrIn ), mAddrIn( addr.mAddrIn ) {
|
||||
}
|
||||
SockAddrInet( const struct sockaddr_in *addr ) : SockAddr( (const struct sockaddr *)&mAddrIn ), mAddrIn( *addr )
|
||||
{
|
||||
explicit SockAddrInet( const struct sockaddr_in *addr ) : SockAddr( (const struct sockaddr *)&mAddrIn ), mAddrIn( *addr ) {
|
||||
}
|
||||
|
||||
|
||||
|
@ -195,57 +172,47 @@ public:
|
|||
bool resolve( const char *serv, const char *proto );
|
||||
bool resolve( int port, const char *proto );
|
||||
|
||||
socklen_t getAddrSize() const
|
||||
{
|
||||
socklen_t getAddrSize() const {
|
||||
return( sizeof(mAddrIn) );
|
||||
}
|
||||
struct sockaddr *getTempAddr() const
|
||||
{
|
||||
struct sockaddr *getTempAddr() const {
|
||||
return( (sockaddr *)&mTempAddrIn );
|
||||
}
|
||||
|
||||
public:
|
||||
static socklen_t addrSize()
|
||||
{
|
||||
static socklen_t addrSize() {
|
||||
return( sizeof(sockaddr_in) );
|
||||
}
|
||||
};
|
||||
|
||||
class SockAddrUnix : public SockAddr
|
||||
{
|
||||
class SockAddrUnix : public SockAddr {
|
||||
private:
|
||||
struct sockaddr_un mAddrUn;
|
||||
struct sockaddr_un mTempAddrUn;
|
||||
|
||||
public:
|
||||
SockAddrUnix();
|
||||
SockAddrUnix( const SockAddrUnix &addr ) : SockAddr( (const struct sockaddr *)&mAddrUn ), mAddrUn( addr.mAddrUn )
|
||||
{
|
||||
SockAddrUnix( const SockAddrUnix &addr ) : SockAddr( (const struct sockaddr *)&mAddrUn ), mAddrUn( addr.mAddrUn ) {
|
||||
}
|
||||
SockAddrUnix( const struct sockaddr_un *addr ) : SockAddr( (const struct sockaddr *)&mAddrUn ), mAddrUn( *addr )
|
||||
{
|
||||
SockAddrUnix( const struct sockaddr_un *addr ) : SockAddr( (const struct sockaddr *)&mAddrUn ), mAddrUn( *addr ) {
|
||||
}
|
||||
|
||||
bool resolve( const char *path, const char *proto );
|
||||
|
||||
socklen_t getAddrSize() const
|
||||
{
|
||||
socklen_t getAddrSize() const {
|
||||
return( sizeof(mAddrUn) );
|
||||
}
|
||||
struct sockaddr *getTempAddr() const
|
||||
{
|
||||
struct sockaddr *getTempAddr() const {
|
||||
return( (sockaddr *)&mTempAddrUn );
|
||||
}
|
||||
|
||||
public:
|
||||
static socklen_t addrSize()
|
||||
{
|
||||
static socklen_t addrSize() {
|
||||
return( sizeof(sockaddr_un) );
|
||||
}
|
||||
};
|
||||
|
||||
class Socket : public CommsBase
|
||||
{
|
||||
class Socket : public CommsBase {
|
||||
protected:
|
||||
typedef enum { CLOSED, DISCONNECTED, LISTENING, CONNECTED } State;
|
||||
|
||||
|
@ -256,45 +223,37 @@ protected:
|
|||
SockAddr *mRemoteAddr;
|
||||
|
||||
protected:
|
||||
Socket() : CommsBase( mSd, mSd ), mSd( -1 ), mState( CLOSED ), mLocalAddr( 0 ), mRemoteAddr( 0 )
|
||||
{
|
||||
Socket() : CommsBase( mSd, mSd ), mSd( -1 ), mState( CLOSED ), mLocalAddr( 0 ), mRemoteAddr( 0 ) {
|
||||
}
|
||||
Socket( const Socket &socket, int newSd ) : CommsBase( mSd, mSd ), mSd( newSd ), mState( CONNECTED ), mLocalAddr( 0 ), mRemoteAddr( 0 )
|
||||
{
|
||||
Socket( const Socket &socket, int newSd ) : CommsBase( mSd, mSd ), mSd( newSd ), mState( CONNECTED ), mLocalAddr( 0 ), mRemoteAddr( 0 ) {
|
||||
if ( socket.mLocalAddr )
|
||||
mLocalAddr = SockAddr::newSockAddr( mLocalAddr );
|
||||
if ( socket.mRemoteAddr )
|
||||
mRemoteAddr = SockAddr::newSockAddr( mRemoteAddr );
|
||||
}
|
||||
virtual ~Socket()
|
||||
{
|
||||
virtual ~Socket() {
|
||||
close();
|
||||
delete mLocalAddr;
|
||||
delete mRemoteAddr;
|
||||
}
|
||||
|
||||
public:
|
||||
bool isOpen() const
|
||||
{
|
||||
bool isOpen() const {
|
||||
return( !isClosed() );
|
||||
}
|
||||
bool isClosed() const
|
||||
{
|
||||
bool isClosed() const {
|
||||
return( mState == CLOSED );
|
||||
}
|
||||
bool isDisconnected() const
|
||||
{
|
||||
bool isDisconnected() const {
|
||||
return( mState == DISCONNECTED );
|
||||
}
|
||||
bool isConnected() const
|
||||
{
|
||||
bool isConnected() const {
|
||||
return( mState == CONNECTED );
|
||||
}
|
||||
virtual bool close();
|
||||
|
||||
protected:
|
||||
bool isListening() const
|
||||
{
|
||||
bool isListening() const {
|
||||
return( mState == LISTENING );
|
||||
}
|
||||
|
||||
|
@ -309,33 +268,28 @@ protected:
|
|||
virtual bool accept( int & );
|
||||
|
||||
public:
|
||||
virtual int send( const void *msg, int len ) const
|
||||
{
|
||||
virtual int send( const void *msg, int len ) const {
|
||||
ssize_t nBytes = ::send( mSd, msg, len, 0 );
|
||||
if ( nBytes < 0 )
|
||||
Debug( 1, "Send of %d bytes on sd %d failed: %s", len, mSd, strerror(errno) );
|
||||
return( nBytes );
|
||||
}
|
||||
virtual int recv( void *msg, int len ) const
|
||||
{
|
||||
virtual int recv( void *msg, int len ) const {
|
||||
ssize_t nBytes = ::recv( mSd, msg, len, 0 );
|
||||
if ( nBytes < 0 )
|
||||
Debug( 1, "Recv of %d bytes max on sd %d failed: %s", len, mSd, strerror(errno) );
|
||||
return( nBytes );
|
||||
}
|
||||
virtual int send( const std::string &msg ) const
|
||||
{
|
||||
virtual int send( const std::string &msg ) const {
|
||||
ssize_t nBytes = ::send( mSd, msg.data(), msg.size(), 0 );
|
||||
if ( nBytes < 0 )
|
||||
Debug( 1, "Send of string '%s' (%zd bytes) on sd %d failed: %s", msg.c_str(), msg.size(), mSd, strerror(errno) );
|
||||
return( nBytes );
|
||||
}
|
||||
virtual int recv( std::string &msg ) const
|
||||
{
|
||||
virtual int recv( std::string &msg ) const {
|
||||
char buffer[msg.capacity()];
|
||||
int nBytes = 0;
|
||||
if ( (nBytes = ::recv( mSd, buffer, sizeof(buffer), 0 )) < 0 )
|
||||
{
|
||||
if ( (nBytes = ::recv( mSd, buffer, sizeof(buffer), 0 )) < 0 ) {
|
||||
Debug( 1, "Recv of %zd bytes max to string on sd %d failed: %s", sizeof(buffer), mSd, strerror(errno) );
|
||||
return( nBytes );
|
||||
}
|
||||
|
@ -343,12 +297,10 @@ public:
|
|||
msg = buffer;
|
||||
return( nBytes );
|
||||
}
|
||||
virtual int recv( std::string &msg, size_t maxLen ) const
|
||||
{
|
||||
virtual int recv( std::string &msg, size_t maxLen ) const {
|
||||
char buffer[maxLen];
|
||||
int nBytes = 0;
|
||||
if ( (nBytes = ::recv( mSd, buffer, sizeof(buffer), 0 )) < 0 )
|
||||
{
|
||||
if ( (nBytes = ::recv( mSd, buffer, sizeof(buffer), 0 )) < 0 ) {
|
||||
Debug( 1, "Recv of %zd bytes max to string on sd %d failed: %s", maxLen, mSd, strerror(errno) );
|
||||
return( nBytes );
|
||||
}
|
||||
|
@ -358,8 +310,7 @@ public:
|
|||
}
|
||||
virtual int bytesToRead() const;
|
||||
|
||||
int getDesc() const
|
||||
{
|
||||
int getDesc() const {
|
||||
return( mSd );
|
||||
}
|
||||
//virtual bool isOpen() const
|
||||
|
@ -371,12 +322,10 @@ public:
|
|||
virtual int getType() const=0;
|
||||
virtual const char *getProtocol() const=0;
|
||||
|
||||
const SockAddr *getLocalAddr() const
|
||||
{
|
||||
const SockAddr *getLocalAddr() const {
|
||||
return( mLocalAddr );
|
||||
}
|
||||
const SockAddr *getRemoteAddr() const
|
||||
{
|
||||
const SockAddr *getRemoteAddr() const {
|
||||
return( mRemoteAddr );
|
||||
}
|
||||
virtual socklen_t getAddrSize() const=0;
|
||||
|
@ -403,12 +352,10 @@ protected:
|
|||
int mAddressFamily;
|
||||
|
||||
public:
|
||||
int getDomain() const
|
||||
{
|
||||
int getDomain() const {
|
||||
return( mAddressFamily );
|
||||
}
|
||||
virtual socklen_t getAddrSize() const
|
||||
{
|
||||
virtual socklen_t getAddrSize() const {
|
||||
return( SockAddrInet::addrSize() );
|
||||
}
|
||||
|
||||
|
@ -422,58 +369,48 @@ protected:
|
|||
bool bind( int port );
|
||||
};
|
||||
|
||||
class UnixSocket : virtual public Socket
|
||||
{
|
||||
class UnixSocket : virtual public Socket {
|
||||
public:
|
||||
int getDomain() const
|
||||
{
|
||||
int getDomain() const {
|
||||
return( AF_UNIX );
|
||||
}
|
||||
virtual socklen_t getAddrSize() const
|
||||
{
|
||||
virtual socklen_t getAddrSize() const {
|
||||
return( SockAddrUnix::addrSize() );
|
||||
}
|
||||
|
||||
protected:
|
||||
bool resolveLocal( const char *serv, const char *proto )
|
||||
{
|
||||
bool resolveLocal( const char *serv, const char *proto ) {
|
||||
SockAddrUnix *addr = new SockAddrUnix;
|
||||
mLocalAddr = addr;
|
||||
return( addr->resolve( serv, proto ) );
|
||||
}
|
||||
|
||||
bool resolveRemote( const char *path, const char *proto )
|
||||
{
|
||||
bool resolveRemote( const char *path, const char *proto ) {
|
||||
SockAddrUnix *addr = new SockAddrUnix;
|
||||
mRemoteAddr = addr;
|
||||
return( addr->resolve( path, proto ) );
|
||||
}
|
||||
|
||||
protected:
|
||||
bool bind( const char *path )
|
||||
{
|
||||
bool bind( const char *path ) {
|
||||
if ( !UnixSocket::resolveLocal( path, getProtocol() ) )
|
||||
return( false );
|
||||
return( Socket::bind() );
|
||||
}
|
||||
|
||||
bool connect( const char *path )
|
||||
{
|
||||
bool connect( const char *path ) {
|
||||
if ( !UnixSocket::resolveRemote( path, getProtocol() ) )
|
||||
return( false );
|
||||
return( Socket::connect() );
|
||||
}
|
||||
};
|
||||
|
||||
class UdpSocket : virtual public Socket
|
||||
{
|
||||
class UdpSocket : virtual public Socket {
|
||||
public:
|
||||
int getType() const
|
||||
{
|
||||
int getType() const {
|
||||
return( SOCK_DGRAM );
|
||||
}
|
||||
const char *getProtocol() const
|
||||
{
|
||||
const char *getProtocol() const {
|
||||
return( "udp" );
|
||||
}
|
||||
|
||||
|
@ -492,8 +429,6 @@ public:
|
|||
nBytes = ::recvfrom( mSd, msg, len, 0, &sockAddr, &sockLen );
|
||||
if ( nBytes < 0 ) {
|
||||
Debug( 1, "Recvfrom of %d bytes max on sd %d (with address) failed: %s", len, mSd, strerror(errno) );
|
||||
} else if ( sockLen ) {
|
||||
addr = SockAddr::newSockAddr( sockAddr, sockLen );
|
||||
}
|
||||
} else {
|
||||
nBytes = ::recvfrom( mSd, msg, len, 0, NULL, 0 );
|
||||
|
@ -504,194 +439,150 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class UdpInetSocket : virtual public UdpSocket, virtual public InetSocket
|
||||
{
|
||||
class UdpInetSocket : virtual public UdpSocket, virtual public InetSocket {
|
||||
public:
|
||||
bool bind( const char *host, const char *serv )
|
||||
{
|
||||
bool bind( const char *host, const char *serv ) {
|
||||
return( InetSocket::bind( host, serv ) );
|
||||
}
|
||||
bool bind( const char *host, int port )
|
||||
{
|
||||
bool bind( const char *host, int port ) {
|
||||
return( InetSocket::bind( host, port ) );
|
||||
}
|
||||
bool bind( const char *serv )
|
||||
{
|
||||
bool bind( const char *serv ) {
|
||||
return( InetSocket::bind( serv ) );
|
||||
}
|
||||
bool bind( int port )
|
||||
{
|
||||
bool bind( int port ) {
|
||||
return( InetSocket::bind( port ) );
|
||||
}
|
||||
|
||||
bool connect( const char *host, const char *serv )
|
||||
{
|
||||
bool connect( const char *host, const char *serv ) {
|
||||
return( InetSocket::connect( host, serv ) );
|
||||
}
|
||||
bool connect( const char *host, int port )
|
||||
{
|
||||
bool connect( const char *host, int port ) {
|
||||
return( InetSocket::connect( host, port ) );
|
||||
}
|
||||
};
|
||||
|
||||
class UdpUnixSocket : virtual public UdpSocket, virtual public UnixSocket
|
||||
{
|
||||
class UdpUnixSocket : virtual public UdpSocket, virtual public UnixSocket {
|
||||
public:
|
||||
bool bind( const char *path )
|
||||
{
|
||||
bool bind( const char *path ) {
|
||||
return( UnixSocket::bind( path ) );
|
||||
}
|
||||
|
||||
bool connect( const char *path )
|
||||
{
|
||||
bool connect( const char *path ) {
|
||||
return( UnixSocket::connect( path ) );
|
||||
}
|
||||
};
|
||||
|
||||
class UdpInetClient : public UdpInetSocket
|
||||
{
|
||||
class UdpInetClient : public UdpInetSocket {
|
||||
public:
|
||||
bool connect( const char *host, const char *serv )
|
||||
{
|
||||
bool connect( const char *host, const char *serv ) {
|
||||
return( UdpInetSocket::connect( host, serv ) );
|
||||
}
|
||||
bool connect( const char *host, int port )
|
||||
{
|
||||
bool connect( const char *host, int port ) {
|
||||
return( UdpInetSocket::connect( host, port ) );
|
||||
}
|
||||
};
|
||||
|
||||
class UdpUnixClient : public UdpUnixSocket
|
||||
{
|
||||
class UdpUnixClient : public UdpUnixSocket {
|
||||
public:
|
||||
bool bind( const char *path )
|
||||
{
|
||||
bool bind( const char *path ) {
|
||||
return( UdpUnixSocket::bind( path ) );
|
||||
}
|
||||
|
||||
public:
|
||||
bool connect( const char *path )
|
||||
{
|
||||
bool connect( const char *path ) {
|
||||
return( UdpUnixSocket::connect( path) );
|
||||
}
|
||||
};
|
||||
|
||||
class UdpInetServer : public UdpInetSocket
|
||||
{
|
||||
class UdpInetServer : public UdpInetSocket {
|
||||
public:
|
||||
bool bind( const char *host, const char *serv )
|
||||
{
|
||||
bool bind( const char *host, const char *serv ) {
|
||||
return( UdpInetSocket::bind( host, serv ) );
|
||||
}
|
||||
bool bind( const char *host, int port )
|
||||
{
|
||||
bool bind( const char *host, int port ) {
|
||||
return( UdpInetSocket::bind( host, port ) );
|
||||
}
|
||||
bool bind( const char *serv )
|
||||
{
|
||||
bool bind( const char *serv ) {
|
||||
return( UdpInetSocket::bind( serv ) );
|
||||
}
|
||||
bool bind( int port )
|
||||
{
|
||||
bool bind( int port ) {
|
||||
return( UdpInetSocket::bind( port ) );
|
||||
}
|
||||
|
||||
protected:
|
||||
bool connect( const char *host, const char *serv )
|
||||
{
|
||||
bool connect( const char *host, const char *serv ) {
|
||||
return( UdpInetSocket::connect( host, serv ) );
|
||||
}
|
||||
bool connect( const char *host, int port )
|
||||
{
|
||||
bool connect( const char *host, int port ) {
|
||||
return( UdpInetSocket::connect( host, port ) );
|
||||
}
|
||||
};
|
||||
|
||||
class UdpUnixServer : public UdpUnixSocket
|
||||
{
|
||||
class UdpUnixServer : public UdpUnixSocket {
|
||||
public:
|
||||
bool bind( const char *path )
|
||||
{
|
||||
bool bind( const char *path ) {
|
||||
return( UdpUnixSocket::bind( path ) );
|
||||
}
|
||||
|
||||
protected:
|
||||
bool connect( const char *path )
|
||||
{
|
||||
bool connect( const char *path ) {
|
||||
return( UdpUnixSocket::connect( path ) );
|
||||
}
|
||||
};
|
||||
|
||||
class TcpSocket : virtual public Socket
|
||||
{
|
||||
class TcpSocket : virtual public Socket {
|
||||
public:
|
||||
TcpSocket()
|
||||
{
|
||||
TcpSocket() {
|
||||
}
|
||||
TcpSocket( const TcpSocket &socket, int newSd ) : Socket( socket, newSd )
|
||||
{
|
||||
TcpSocket( const TcpSocket &socket, int newSd ) : Socket( socket, newSd ) {
|
||||
}
|
||||
|
||||
public:
|
||||
int getType() const
|
||||
{
|
||||
int getType() const {
|
||||
return( SOCK_STREAM );
|
||||
}
|
||||
const char *getProtocol() const
|
||||
{
|
||||
const char *getProtocol() const {
|
||||
return( "tcp" );
|
||||
}
|
||||
};
|
||||
|
||||
class TcpInetSocket : virtual public TcpSocket, virtual public InetSocket
|
||||
{
|
||||
class TcpInetSocket : virtual public TcpSocket, virtual public InetSocket {
|
||||
public:
|
||||
TcpInetSocket()
|
||||
{
|
||||
TcpInetSocket() {
|
||||
}
|
||||
TcpInetSocket( const TcpInetSocket &socket, int newSd ) : TcpSocket( socket, newSd )
|
||||
{
|
||||
TcpInetSocket( const TcpInetSocket &socket, int newSd ) : TcpSocket( socket, newSd ) {
|
||||
}
|
||||
};
|
||||
|
||||
class TcpUnixSocket : virtual public TcpSocket, virtual public UnixSocket
|
||||
{
|
||||
class TcpUnixSocket : virtual public TcpSocket, virtual public UnixSocket {
|
||||
public:
|
||||
TcpUnixSocket()
|
||||
{
|
||||
TcpUnixSocket() {
|
||||
}
|
||||
TcpUnixSocket( const TcpUnixSocket &socket, int newSd ) : TcpSocket( socket, newSd )
|
||||
{
|
||||
TcpUnixSocket( const TcpUnixSocket &socket, int newSd ) : TcpSocket( socket, newSd ) {
|
||||
}
|
||||
};
|
||||
|
||||
class TcpInetClient : public TcpInetSocket
|
||||
{
|
||||
class TcpInetClient : public TcpInetSocket {
|
||||
public:
|
||||
bool connect( const char *host, const char *serv )
|
||||
{
|
||||
bool connect( const char *host, const char *serv ) {
|
||||
return( TcpInetSocket::connect( host, serv ) );
|
||||
}
|
||||
bool connect( const char *host, int port )
|
||||
{
|
||||
bool connect( const char *host, int port ) {
|
||||
return( TcpInetSocket::connect( host, port ) );
|
||||
}
|
||||
};
|
||||
|
||||
class TcpUnixClient : public TcpUnixSocket
|
||||
{
|
||||
class TcpUnixClient : public TcpUnixSocket {
|
||||
public:
|
||||
bool connect( const char *path )
|
||||
{
|
||||
bool connect( const char *path ) {
|
||||
return( TcpUnixSocket::connect( path) );
|
||||
}
|
||||
};
|
||||
|
||||
class TcpInetServer : public TcpInetSocket
|
||||
{
|
||||
class TcpInetServer : public TcpInetSocket {
|
||||
public:
|
||||
bool bind( int port )
|
||||
{
|
||||
bool bind( int port ) {
|
||||
return( TcpInetSocket::bind( port ) );
|
||||
}
|
||||
|
||||
|
@ -702,11 +593,9 @@ public:
|
|||
bool accept( TcpInetSocket *&newSocket );
|
||||
};
|
||||
|
||||
class TcpUnixServer : public TcpUnixSocket
|
||||
{
|
||||
class TcpUnixServer : public TcpUnixSocket {
|
||||
public:
|
||||
bool bind( const char *path )
|
||||
{
|
||||
bool bind( const char *path ) {
|
||||
return( TcpUnixSocket::bind( path ) );
|
||||
}
|
||||
|
||||
|
@ -717,8 +606,7 @@ public:
|
|||
bool accept( TcpUnixSocket *&newSocket );
|
||||
};
|
||||
|
||||
class Select
|
||||
{
|
||||
class Select {
|
||||
public:
|
||||
typedef std::set<CommsBase *> CommsSet;
|
||||
typedef std::vector<CommsBase *> CommsList;
|
||||
|
|
|
@ -229,10 +229,13 @@ ConfigItem::ConfigItem( const ConfigItem &item ) {
|
|||
accessed = false;
|
||||
}
|
||||
void ConfigItem::Copy( const ConfigItem &item ) {
|
||||
if (name) delete name;
|
||||
name = new char[strlen(item.name)+1];
|
||||
strcpy( name, item.name );
|
||||
if (value) delete value;
|
||||
value = new char[strlen(item.value)+1];
|
||||
strcpy( value, item.value );
|
||||
if (type) delete type;
|
||||
type = new char[strlen(item.type)+1];
|
||||
strcpy( type, item.type );
|
||||
|
||||
|
|
|
@ -110,12 +110,16 @@ public:
|
|||
ConfigItem(const char *p_name, const char *p_value, const char *const p_type);
|
||||
ConfigItem(const ConfigItem &);
|
||||
~ConfigItem();
|
||||
void Copy(const ConfigItem&);
|
||||
void ConvertValue() const;
|
||||
bool BooleanValue() const;
|
||||
int IntegerValue() const;
|
||||
double DecimalValue() const;
|
||||
const char *StringValue() const;
|
||||
|
||||
ConfigItem &operator=(const ConfigItem item) {
|
||||
Copy(item);return *this;
|
||||
}
|
||||
inline operator bool() const {
|
||||
return BooleanValue();
|
||||
}
|
||||
|
|
|
@ -236,10 +236,10 @@ int cURLCamera::Capture( Image &image ) {
|
|||
if(!SubHeadersParsingComplete) {
|
||||
/* We haven't parsed all headers yet */
|
||||
need_more_data = true;
|
||||
} else if(frame_content_length <= 0) {
|
||||
} else if ( ! frame_content_length ) {
|
||||
/* Invalid frame */
|
||||
Error("Invalid frame: invalid content length");
|
||||
} else if(frame_content_type != "image/jpeg") {
|
||||
} else if ( frame_content_type != "image/jpeg" ) {
|
||||
/* Unsupported frame type */
|
||||
Error("Unsupported frame: %s",frame_content_type.c_str());
|
||||
} else if(frame_content_length > databuffer.size()) {
|
||||
|
|
|
@ -28,8 +28,9 @@ MYSQL dbconn;
|
|||
int zmDbConnected = false;
|
||||
|
||||
void zmDbConnect() {
|
||||
if ( zmDbConnected )
|
||||
return;
|
||||
// For some reason having these lines causes memory corruption and crashing on newer debian/ubuntu
|
||||
//if ( zmDbConnected )
|
||||
//return;
|
||||
|
||||
if ( !mysql_init( &dbconn ) ) {
|
||||
Error( "Can't initialise database connection: %s", mysql_error( &dbconn ) );
|
||||
|
|
|
@ -71,7 +71,7 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
|
|||
|
||||
static char sql[ZM_SQL_MED_BUFSIZ];
|
||||
struct tm *stime = localtime( &start_time.tv_sec );
|
||||
snprintf( sql, sizeof(sql), "insert into Events ( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed ) values ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d )",
|
||||
snprintf( sql, sizeof(sql), "INSERT INTO Events ( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed, DefaultVideo, SaveJPEGs ) values ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d, '', %d )",
|
||||
monitor->Id(),
|
||||
storage->Id(),
|
||||
start_time.tv_sec,
|
||||
|
@ -81,7 +81,8 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
|
|||
notes.c_str(),
|
||||
state_id,
|
||||
monitor->getOrientation(),
|
||||
videoEvent
|
||||
videoEvent,
|
||||
monitor->GetOptSaveJPEGs()
|
||||
);
|
||||
if ( mysql_query( &dbconn, sql ) ) {
|
||||
Error( "Can't insert event: %s. sql was (%s)", mysql_error( &dbconn ), sql );
|
||||
|
@ -181,7 +182,7 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
|
|||
if ( videowriter != NULL ) {
|
||||
/* Open the video stream */
|
||||
int nRet = videowriter->Open();
|
||||
if(nRet != 0) {
|
||||
if ( nRet != 0 ) {
|
||||
Error("Failed opening video stream");
|
||||
delete videowriter;
|
||||
videowriter = NULL;
|
||||
|
@ -211,7 +212,9 @@ Event::~Event() {
|
|||
if ( frames > last_db_frame ) {
|
||||
|
||||
Debug( 1, "Adding closing frame %d to DB", frames );
|
||||
snprintf( sql, sizeof(sql), "insert into Frames ( EventId, FrameId, TimeStamp, Delta ) values ( %d, %d, from_unixtime( %ld ), %s%ld.%02ld )", id, frames, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec );
|
||||
snprintf( sql, sizeof(sql),
|
||||
"insert into Frames ( EventId, FrameId, TimeStamp, Delta ) values ( %d, %d, from_unixtime( %ld ), %s%ld.%02ld )",
|
||||
id, frames, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec );
|
||||
if ( mysql_query( &dbconn, sql ) ) {
|
||||
Error( "Can't insert frame: %s", mysql_error( &dbconn ) );
|
||||
exit( mysql_errno( &dbconn ) );
|
||||
|
@ -228,8 +231,10 @@ Event::~Event() {
|
|||
videowriter = NULL;
|
||||
|
||||
/* Close the timecodes file */
|
||||
fclose(timecodes_fd);
|
||||
timecodes_fd = NULL;
|
||||
if ( timecodes_fd ) {
|
||||
fclose(timecodes_fd);
|
||||
timecodes_fd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf( sql, sizeof(sql), "update Events set Name='%s%d', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' where Id = %d", monitor->EventPrefix(), id, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, video_name, id );
|
||||
|
@ -302,7 +307,8 @@ bool Event::WriteFrameVideo( const Image *image, const struct timeval timestamp,
|
|||
}
|
||||
|
||||
/* Add the frame to the timecodes file */
|
||||
fprintf(timecodes_fd, "%u\n", timeMS);
|
||||
if ( timecodes_fd )
|
||||
fprintf(timecodes_fd, "%u\n", timeMS);
|
||||
|
||||
return( true );
|
||||
}
|
||||
|
|
|
@ -116,7 +116,8 @@ int av_dict_parse_string(AVDictionary **pm, const char *str,
|
|||
flags &= ~(AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
|
||||
|
||||
while (*str) {
|
||||
if ((int ret = parse_key_value_pair(pm, &str, key_val_sep, pairs_sep, flags)) < 0)
|
||||
int ret;
|
||||
if ( (ret = parse_key_value_pair(pm, &str, key_val_sep, pairs_sep, flags)) < 0)
|
||||
return ret;
|
||||
|
||||
if (*str)
|
||||
|
@ -184,27 +185,13 @@ int hacked_up_context2_for_older_ffmpeg(AVFormatContext **avctx, AVOutputFormat
|
|||
}
|
||||
}
|
||||
|
||||
if (!oformat) {
|
||||
if (format) {
|
||||
oformat = av_guess_format(format, NULL, NULL);
|
||||
if (!oformat) {
|
||||
av_log(s, AV_LOG_ERROR, "Requested output format '%s' is not a suitable output format\n", format);
|
||||
ret = AVERROR(EINVAL);
|
||||
}
|
||||
} else {
|
||||
oformat = av_guess_format(NULL, filename, NULL);
|
||||
if (!oformat) {
|
||||
ret = AVERROR(EINVAL);
|
||||
av_log(s, AV_LOG_ERROR, "Unable to find a suitable output format for '%s'\n", filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
avformat_free_context(s);
|
||||
return ret;
|
||||
} else {
|
||||
s->oformat = oformat;
|
||||
#if 1
|
||||
// This is some very wrong code, and I don't think it is neccessary
|
||||
if (s->oformat->priv_data_size > 0) {
|
||||
s->priv_data = av_mallocz(s->oformat->priv_data_size);
|
||||
if (s->priv_data) {
|
||||
|
@ -219,6 +206,7 @@ int hacked_up_context2_for_older_ffmpeg(AVFormatContext **avctx, AVOutputFormat
|
|||
}
|
||||
s->priv_data = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (filename) strncpy(s->filename, filename, sizeof(s->filename));
|
||||
*avctx = s;
|
||||
|
|
|
@ -328,6 +328,9 @@ int FfmpegCamera::PostCapture() {
|
|||
int FfmpegCamera::OpenFfmpeg() {
|
||||
|
||||
Debug ( 2, "OpenFfmpeg called." );
|
||||
uint32_t last_event_id = monitor->GetLastEventId() ;
|
||||
uint32_t video_writer_event_id = monitor->GetVideoWriterEventId();
|
||||
Debug(2, "last_event(%d), our current (%d)", last_event_id, video_writer_event_id );
|
||||
|
||||
int ret;
|
||||
|
||||
|
@ -372,6 +375,9 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
//FIXME can speed up initial analysis but need sensible parameters...
|
||||
//mFormatContext->probesize = 32;
|
||||
//mFormatContext->max_analyze_duration = 32;
|
||||
last_event_id = monitor->GetLastEventId() ;
|
||||
video_writer_event_id = monitor->GetVideoWriterEventId();
|
||||
Debug(2, "last_event(%d), our current (%d), mpath (%s)", last_event_id, video_writer_event_id, mPath.c_str() );
|
||||
|
||||
if ( avformat_open_input( &mFormatContext, mPath.c_str(), NULL, &opts ) != 0 )
|
||||
#endif
|
||||
|
@ -380,12 +386,18 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
Error( "Unable to open input %s due to: %s", mPath.c_str(), strerror(errno) );
|
||||
return -1;
|
||||
}
|
||||
|
||||
AVDictionaryEntry *e;
|
||||
if ( (e = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
||||
last_event_id = monitor->GetLastEventId() ;
|
||||
video_writer_event_id = monitor->GetVideoWriterEventId();
|
||||
Debug(2, "last_event(%d), our current (%d)", last_event_id, video_writer_event_id );
|
||||
AVDictionaryEntry *e=NULL;
|
||||
while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
||||
Warning( "Option %s not recognized by ffmpeg", e->key);
|
||||
}
|
||||
|
||||
last_event_id = monitor->GetLastEventId() ;
|
||||
video_writer_event_id = monitor->GetVideoWriterEventId();
|
||||
Debug(2, "last_event(%d), our current (%d)", last_event_id, video_writer_event_id );
|
||||
|
||||
mIsOpening = false;
|
||||
Debug ( 1, "Opened input" );
|
||||
|
||||
|
@ -524,15 +536,15 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
Debug ( 1, "Calling avcodec_open2" );
|
||||
if ( avcodec_open2(mVideoCodecContext, mVideoCodec, &opts) < 0 ) {
|
||||
#endif
|
||||
AVDictionaryEntry *e;
|
||||
if ( (e = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
||||
AVDictionaryEntry *e = NULL;
|
||||
while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
||||
Warning( "Option %s not recognized by ffmpeg", e->key);
|
||||
}
|
||||
Fatal( "Unable to open codec for video stream from %s", mPath.c_str() );
|
||||
} else {
|
||||
|
||||
AVDictionaryEntry *e;
|
||||
if ( (e = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
||||
AVDictionaryEntry *e = NULL;
|
||||
if ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
||||
Warning( "Option %s not recognized by ffmpeg", e->key);
|
||||
}
|
||||
}
|
||||
|
@ -567,7 +579,7 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
}
|
||||
}
|
||||
|
||||
Debug ( 1, "Opened codec" );
|
||||
Debug ( 1, "Opened audio codec" );
|
||||
|
||||
// Allocate space for the native video frame
|
||||
mRawFrame = zm_av_frame_alloc();
|
||||
|
@ -666,12 +678,16 @@ int FfmpegCamera::CloseFfmpeg() {
|
|||
|
||||
if ( mVideoCodecContext ) {
|
||||
avcodec_close(mVideoCodecContext);
|
||||
//av_free(mVideoCodecContext);
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
avcodec_free_context(&mVideoCodecContext);
|
||||
#endif
|
||||
mVideoCodecContext = NULL; // Freed by av_close_input_file
|
||||
}
|
||||
if ( mAudioCodecContext ) {
|
||||
avcodec_close(mAudioCodecContext);
|
||||
//av_free(mAudioCodecContext);
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
avcodec_free_context(&mAudioCodecContext);
|
||||
#endif
|
||||
mAudioCodecContext = NULL; // Freed by av_close_input_file
|
||||
}
|
||||
|
||||
|
@ -780,9 +796,10 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
|
|||
if ( recording.tv_sec ) {
|
||||
|
||||
uint32_t last_event_id = monitor->GetLastEventId() ;
|
||||
uint32_t video_writer_event_id = monitor->GetVideoWriterEventId();
|
||||
|
||||
if ( last_event_id != monitor->GetVideoWriterEventId() ) {
|
||||
Debug(2, "Have change of event. last_event(%d), our current (%d)", last_event_id, monitor->GetVideoWriterEventId() );
|
||||
if ( last_event_id != video_writer_event_id ) {
|
||||
Debug(2, "Have change of event. last_event(%d), our current (%d)", last_event_id, video_writer_event_id );
|
||||
|
||||
if ( videoStore ) {
|
||||
Info("Re-starting video storage module");
|
||||
|
|
|
@ -85,7 +85,6 @@ class FfmpegCamera : public Camera {
|
|||
#endif // HAVE_LIBAVFORMAT
|
||||
|
||||
VideoStore *videoStore;
|
||||
unsigned int old_event_id;
|
||||
zm_packetqueue packetqueue;
|
||||
bool have_video_keyframe;
|
||||
|
||||
|
|
|
@ -9,9 +9,14 @@ FFmpeg_Input::FFmpeg_Input() {
|
|||
audio_stream_id = -1;
|
||||
av_register_all();
|
||||
avcodec_register_all();
|
||||
|
||||
streams = NULL;
|
||||
}
|
||||
|
||||
FFmpeg_Input::~FFmpeg_Input() {
|
||||
if ( streams ) {
|
||||
delete streams;
|
||||
streams = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int FFmpeg_Input::Open( const char *filepath ) {
|
||||
|
@ -35,6 +40,8 @@ int FFmpeg_Input::Open( const char *filepath ) {
|
|||
return error;
|
||||
}
|
||||
|
||||
streams = new stream[input_format_context->nb_streams];
|
||||
|
||||
for ( unsigned int i = 0; i < input_format_context->nb_streams; i += 1 ) {
|
||||
if ( is_video_stream( input_format_context->streams[i] ) ) {
|
||||
zm_dump_stream_format(input_format_context, i, 0, 0);
|
||||
|
@ -162,7 +169,7 @@ AVFrame *FFmpeg_Input::get_frame( int stream_id ) {
|
|||
|
||||
frameComplete = 1;
|
||||
# else
|
||||
ret = zm_avcodec_decode_video( streams[packet.stream_index].context, frame, &frameComplete, &packet );
|
||||
ret = zm_avcodec_decode_video( context, frame, &frameComplete, &packet );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to decode frame at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf );
|
||||
|
|
|
@ -36,7 +36,7 @@ class FFmpeg_Input {
|
|||
int frame_count;
|
||||
} stream;
|
||||
|
||||
stream streams[2];
|
||||
stream *streams;
|
||||
int video_stream_id;
|
||||
int audio_stream_id;
|
||||
AVFormatContext *input_format_context;
|
||||
|
|
|
@ -131,6 +131,7 @@ Image::Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uin
|
|||
|
||||
Image::Image( const AVFrame *frame ) {
|
||||
AVFrame *dest_frame = zm_av_frame_alloc();
|
||||
text[0] = '\0';
|
||||
|
||||
width = frame->width;
|
||||
height = frame->height;
|
||||
|
@ -612,12 +613,12 @@ void Image::Assign(const unsigned int p_width, const unsigned int p_height, cons
|
|||
void Image::Assign( const Image &image ) {
|
||||
unsigned int new_size = (image.width * image.height) * image.colours;
|
||||
|
||||
if(image.buffer == NULL) {
|
||||
if ( image.buffer == NULL ) {
|
||||
Error("Attempt to assign image with an empty buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
if(image.colours != ZM_COLOUR_GRAY8 && image.colours != ZM_COLOUR_RGB24 && image.colours != ZM_COLOUR_RGB32) {
|
||||
if ( image.colours != ZM_COLOUR_GRAY8 && image.colours != ZM_COLOUR_RGB24 && image.colours != ZM_COLOUR_RGB32 ) {
|
||||
Error("Attempt to assign image with unexpected colours per pixel: %d",image.colours);
|
||||
return;
|
||||
}
|
||||
|
@ -1847,8 +1848,7 @@ void Image::Delta( const Image &image, Image* targetimage) const
|
|||
#endif
|
||||
}
|
||||
|
||||
const Coord Image::centreCoord( const char *text ) const
|
||||
{
|
||||
const Coord Image::centreCoord( const char *text ) const {
|
||||
int index = 0;
|
||||
int line_no = 0;
|
||||
int text_len = strlen( text );
|
||||
|
@ -1856,14 +1856,12 @@ const Coord Image::centreCoord( const char *text ) const
|
|||
int max_line_len = 0;
|
||||
const char *line = text;
|
||||
|
||||
while ( (index < text_len) && (line_len = strcspn( line, "\n" )) )
|
||||
{
|
||||
while ( (index < text_len) && (line_len = strcspn( line, "\n" )) ) {
|
||||
if ( line_len > max_line_len )
|
||||
max_line_len = line_len;
|
||||
|
||||
index += line_len;
|
||||
while ( text[index] == '\n' )
|
||||
{
|
||||
while ( text[index] == '\n' ) {
|
||||
index++;
|
||||
}
|
||||
line = text+index;
|
||||
|
@ -1875,8 +1873,7 @@ const Coord Image::centreCoord( const char *text ) const
|
|||
}
|
||||
|
||||
/* RGB32 compatible: complete */
|
||||
void Image::MaskPrivacy( const unsigned char *p_bitmask, const Rgb pixel_colour )
|
||||
{
|
||||
void Image::MaskPrivacy( const unsigned char *p_bitmask, const Rgb pixel_colour ) {
|
||||
const uint8_t pixel_r_col = RED_VAL_RGBA(pixel_colour);
|
||||
const uint8_t pixel_g_col = GREEN_VAL_RGBA(pixel_colour);
|
||||
const uint8_t pixel_b_col = BLUE_VAL_RGBA(pixel_colour);
|
||||
|
|
|
@ -95,14 +95,14 @@ protected:
|
|||
double _1_m;
|
||||
|
||||
static int CompareYX( const void *p1, const void *p2 ) {
|
||||
const Edge *e1 = (const Edge *)p1, *e2 = (const Edge *)p2;
|
||||
const Edge *e1 = reinterpret_cast<const Edge *>(p1), *e2 = reinterpret_cast<const Edge *>(p2);
|
||||
if ( e1->min_y == e2->min_y )
|
||||
return( int(e1->min_x - e2->min_x) );
|
||||
else
|
||||
return( int(e1->min_y - e2->min_y) );
|
||||
}
|
||||
static int CompareX( const void *p1, const void *p2 ) {
|
||||
const Edge *e1 = (const Edge *)p1, *e2 = (const Edge *)p2;
|
||||
const Edge *e1 = reinterpret_cast<const Edge *>(p1), *e2 = reinterpret_cast<const Edge *>(p2);
|
||||
return( int(e1->min_x - e2->min_x) );
|
||||
}
|
||||
};
|
||||
|
@ -152,10 +152,10 @@ protected:
|
|||
|
||||
public:
|
||||
Image();
|
||||
Image( const char *filename );
|
||||
explicit Image( const char *filename );
|
||||
Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer=0);
|
||||
Image( const Image &p_image );
|
||||
Image( const AVFrame *frame );
|
||||
explicit Image( const Image &p_image );
|
||||
explicit Image( const AVFrame *frame );
|
||||
~Image();
|
||||
static void Initialise();
|
||||
static void Deinitialise();
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
// Do all the buffer checking work here to avoid unnecessary locking
|
||||
void* LibvlcLockBuffer(void* opaque, void** planes) {
|
||||
LibvlcPrivateData* data = (LibvlcPrivateData*)opaque;
|
||||
LibvlcPrivateData* data = reinterpret_cast<LibvlcPrivateData*>(opaque);
|
||||
data->mutex.lock();
|
||||
|
||||
uint8_t* buffer = data->buffer;
|
||||
|
@ -36,7 +36,7 @@ void* LibvlcLockBuffer(void* opaque, void** planes) {
|
|||
}
|
||||
|
||||
void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) {
|
||||
LibvlcPrivateData* data = (LibvlcPrivateData*)opaque;
|
||||
LibvlcPrivateData* data = reinterpret_cast<LibvlcPrivateData*>(opaque);
|
||||
|
||||
bool newFrame = false;
|
||||
for( uint32_t i = 0; i < data->bufferSize; i++ ) {
|
||||
|
@ -67,6 +67,7 @@ LibvlcCamera::LibvlcCamera( int p_id, const std::string &p_path, const std::stri
|
|||
mLibvlcMediaPlayer = NULL;
|
||||
mLibvlcData.buffer = NULL;
|
||||
mLibvlcData.prevBuffer = NULL;
|
||||
mOptArgV = NULL;
|
||||
|
||||
/* Has to be located inside the constructor so other components such as zma will receive correct colours and subpixel order */
|
||||
if(colours == ZM_COLOUR_RGB32) {
|
||||
|
|
|
@ -1712,8 +1712,8 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
|
|||
sprintf( output+strlen(output), " Name: %s\n", vid_src.name );
|
||||
sprintf( output+strlen(output), " Channel: %d\n", vid_src.channel );
|
||||
sprintf( output+strlen(output), " Flags: %d\n%s%s", vid_src.flags,
|
||||
vid_src.flags&VIDEO_VC_TUNER?" Channel has a tuner\n":"",
|
||||
vid_src.flags&VIDEO_VC_AUDIO?" Channel has audio\n":""
|
||||
(vid_src.flags&VIDEO_VC_TUNER)?" Channel has a tuner\n":"",
|
||||
(vid_src.flags&VIDEO_VC_AUDIO)?" Channel has audio\n":""
|
||||
);
|
||||
sprintf( output+strlen(output), " Type: %d - %s\n", vid_src.type,
|
||||
vid_src.type==VIDEO_TYPE_TV?"TV":(
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
inline void* zm_mallocaligned(unsigned int reqalignment, size_t reqsize) {
|
||||
uint8_t* retptr;
|
||||
#if HAVE_POSIX_MEMALIGN
|
||||
if(posix_memalign((void**)&retptr,reqalignment,reqsize) != 0)
|
||||
if ( posix_memalign((void**)&retptr,reqalignment,reqsize) != 0 )
|
||||
return NULL;
|
||||
|
||||
return retptr;
|
||||
|
@ -34,7 +34,7 @@ inline void* zm_mallocaligned(unsigned int reqalignment, size_t reqsize) {
|
|||
uint8_t* alloc;
|
||||
retptr = (uint8_t*)malloc(reqsize+reqalignment+sizeof(void*));
|
||||
|
||||
if(retptr == NULL)
|
||||
if ( retptr == NULL )
|
||||
return NULL;
|
||||
|
||||
alloc = retptr + sizeof(void*);
|
||||
|
@ -58,20 +58,16 @@ inline void zm_freealigned(void* ptr) {
|
|||
#endif
|
||||
}
|
||||
|
||||
inline char *mempbrk( register const char *s, const char *accept, size_t limit )
|
||||
{
|
||||
if ( limit <= 0 || !s || !accept || !*accept )
|
||||
return( 0 );
|
||||
inline char *mempbrk( register const char *s, const char *accept, size_t limit ) {
|
||||
if ( limit == 0 || !s || !accept || !*accept )
|
||||
return 0;
|
||||
|
||||
register unsigned int i,j;
|
||||
size_t acc_len = strlen( accept );
|
||||
|
||||
for ( i = 0; i < limit; s++, i++ )
|
||||
{
|
||||
for ( j = 0; j < acc_len; j++ )
|
||||
{
|
||||
if ( *s == accept[j] )
|
||||
{
|
||||
for ( i = 0; i < limit; s++, i++ ) {
|
||||
for ( j = 0; j < acc_len; j++ ) {
|
||||
if ( *s == accept[j] ) {
|
||||
return( (char *)s );
|
||||
}
|
||||
}
|
||||
|
@ -79,9 +75,8 @@ inline char *mempbrk( register const char *s, const char *accept, size_t limit )
|
|||
return( 0 );
|
||||
}
|
||||
|
||||
inline char *memstr( register const char *s, const char *n, size_t limit )
|
||||
{
|
||||
if ( limit <= 0 || !s || !n )
|
||||
inline char *memstr( register const char *s, const char *n, size_t limit ) {
|
||||
if ( limit == 0 || !s || !n )
|
||||
return( 0 );
|
||||
|
||||
if ( !*n )
|
||||
|
@ -90,14 +85,12 @@ inline char *memstr( register const char *s, const char *n, size_t limit )
|
|||
register unsigned int i,j,k;
|
||||
size_t n_len = strlen( n );
|
||||
|
||||
for ( i = 0; i < limit; i++, s++ )
|
||||
{
|
||||
for ( i = 0; i < limit; i++, s++ ) {
|
||||
if ( *s != *n )
|
||||
continue;
|
||||
j = 1;
|
||||
k = 1;
|
||||
while ( true )
|
||||
{
|
||||
while ( true ) {
|
||||
if ( k >= n_len )
|
||||
return( (char *)s );
|
||||
if ( s[j++] != n[k++] )
|
||||
|
@ -107,36 +100,30 @@ inline char *memstr( register const char *s, const char *n, size_t limit )
|
|||
return( 0 );
|
||||
}
|
||||
|
||||
inline size_t memspn( register const char *s, const char *accept, size_t limit )
|
||||
{
|
||||
if ( limit <= 0 || !s || !accept || !*accept )
|
||||
inline size_t memspn( register const char *s, const char *accept, size_t limit ) {
|
||||
if ( limit == 0 || !s || !accept || !*accept )
|
||||
return( 0 );
|
||||
|
||||
register unsigned int i,j;
|
||||
size_t acc_len = strlen( accept );
|
||||
|
||||
for ( i = 0; i < limit; s++, i++ )
|
||||
{
|
||||
for ( i = 0; i < limit; s++, i++ ) {
|
||||
register bool found = false;
|
||||
for ( j = 0; j < acc_len; j++ )
|
||||
{
|
||||
if ( *s == accept[j] )
|
||||
{
|
||||
for ( j = 0; j < acc_len; j++ ) {
|
||||
if ( *s == accept[j] ) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !found )
|
||||
{
|
||||
if ( !found ) {
|
||||
return( i );
|
||||
}
|
||||
}
|
||||
return( limit );
|
||||
}
|
||||
|
||||
inline size_t memcspn( register const char *s, const char *reject, size_t limit )
|
||||
{
|
||||
if ( limit <= 0 || !s || !reject )
|
||||
inline size_t memcspn( register const char *s, const char *reject, size_t limit ) {
|
||||
if ( limit == 0 || !s || !reject )
|
||||
return( 0 );
|
||||
|
||||
if ( !*reject )
|
||||
|
@ -145,12 +132,9 @@ inline size_t memcspn( register const char *s, const char *reject, size_t limit
|
|||
register unsigned int i,j;
|
||||
size_t rej_len = strlen( reject );
|
||||
|
||||
for ( i = 0; i < limit; s++, i++ )
|
||||
{
|
||||
for ( j = 0; j < rej_len; j++ )
|
||||
{
|
||||
if ( *s == reject[j] )
|
||||
{
|
||||
for ( i = 0; i < limit; s++, i++ ) {
|
||||
for ( j = 0; j < rej_len; j++ ) {
|
||||
if ( *s == reject[j] ) {
|
||||
return( i );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,12 @@ std::vector<std::string> split(const std::string &s, char delim) {
|
|||
return elems;
|
||||
}
|
||||
|
||||
Monitor::MonitorLink::MonitorLink( int p_id, const char *p_name ) : id( p_id ) {
|
||||
Monitor::MonitorLink::MonitorLink( int p_id, const char *p_name ) :
|
||||
id( p_id ),
|
||||
shared_data(NULL),
|
||||
trigger_data(NULL),
|
||||
video_store_data(NULL)
|
||||
{
|
||||
strncpy( name, p_name, sizeof(name) );
|
||||
|
||||
#if ZM_MEM_MAPPED
|
||||
|
@ -468,9 +473,12 @@ Monitor::Monitor(
|
|||
videoRecording = ((GetOptVideoWriter() == H264PASSTHROUGH) && camera->SupportsNativeVideo());
|
||||
|
||||
if ( purpose == ANALYSIS ) {
|
||||
|
||||
while( shared_data->last_write_index == (unsigned int)image_buffer_count
|
||||
&& shared_data->last_write_time == 0) {
|
||||
Debug(2,"last_write_index(%d), last_write_time(%d)", shared_data->last_write_index, shared_data->last_write_time );
|
||||
while(
|
||||
( shared_data->last_write_index == (unsigned int)image_buffer_count )
|
||||
&&
|
||||
( shared_data->last_write_time == 0)
|
||||
) {
|
||||
Warning( "Waiting for capture daemon" );
|
||||
sleep( 1 );
|
||||
}
|
||||
|
@ -605,7 +613,7 @@ Monitor::~Monitor() {
|
|||
}
|
||||
if ( mem_ptr ) {
|
||||
if ( event ) {
|
||||
Info( "%s: %03d - Closing event %d, shutting down", name, image_count, event->Id() );
|
||||
Info( "%s: image_count:%d - Closing event %d, shutting down", name, image_count, event->Id() );
|
||||
closeEvent();
|
||||
}
|
||||
|
||||
|
@ -771,30 +779,40 @@ unsigned int Monitor::GetLastWriteIndex() const {
|
|||
return( shared_data->last_write_index!=(unsigned int)image_buffer_count?shared_data->last_write_index:-1 );
|
||||
}
|
||||
|
||||
unsigned int Monitor::GetLastEvent() const {
|
||||
uint32_t Monitor::GetLastEventId() const {
|
||||
Debug(2, "mem_ptr(%x), State(%d) last_read_index(%d) last_read_time(%d) last_event(%d)",
|
||||
mem_ptr,
|
||||
shared_data->state,
|
||||
shared_data->last_read_index,
|
||||
shared_data->last_read_time,
|
||||
shared_data->last_event
|
||||
);
|
||||
return( shared_data->last_event );
|
||||
}
|
||||
|
||||
// This function is crap.
|
||||
double Monitor::GetFPS() const {
|
||||
int index1 = shared_data->last_write_index;
|
||||
if ( index1 == image_buffer_count ) {
|
||||
return( 0.0 );
|
||||
// last_write_index only has this value on startup before capturing anything.
|
||||
return 0.0;
|
||||
}
|
||||
Snapshot *snap1 = &image_buffer[index1];
|
||||
if ( !snap1->timestamp || !snap1->timestamp->tv_sec ) {
|
||||
return( 0.0 );
|
||||
// This should be impossible
|
||||
return 0.0;
|
||||
}
|
||||
struct timeval time1 = *snap1->timestamp;
|
||||
|
||||
int image_count = image_buffer_count;
|
||||
int index2 = (index1+1)%image_buffer_count;
|
||||
if ( index2 == image_buffer_count ) {
|
||||
return( 0.0 );
|
||||
}
|
||||
Snapshot *snap2 = &image_buffer[index2];
|
||||
// the timestamp pointers are initialized on connection, so that's redundant
|
||||
// tv_sec is probably only zero during the first loop of capturing, so this basically just counts the unused images.
|
||||
while ( !snap2->timestamp || !snap2->timestamp->tv_sec ) {
|
||||
if ( index1 == index2 ) {
|
||||
return( 0.0 );
|
||||
// We didn't find any initialized images
|
||||
return 0.0;
|
||||
}
|
||||
index2 = (index2+1)%image_buffer_count;
|
||||
snap2 = &image_buffer[index2];
|
||||
|
@ -807,10 +825,10 @@ double Monitor::GetFPS() const {
|
|||
double curr_fps = image_count/time_diff;
|
||||
|
||||
if ( curr_fps < 0.0 ) {
|
||||
//Error( "Negative FPS %f, time_diff = %lf (%d:%ld.%ld - %d:%ld.%ld), ibc: %d", curr_fps, time_diff, index2, time2.tv_sec, time2.tv_usec, index1, time1.tv_sec, time1.tv_usec, image_buffer_count );
|
||||
return( 0.0 );
|
||||
Error( "Negative FPS %f, time_diff = %lf (%d:%ld.%ld - %d:%ld.%ld), ibc: %d", curr_fps, time_diff, index2, time2.tv_sec, time2.tv_usec, index1, time1.tv_sec, time1.tv_usec, image_buffer_count );
|
||||
return 0.0;
|
||||
}
|
||||
return( curr_fps );
|
||||
return curr_fps;
|
||||
}
|
||||
|
||||
useconds_t Monitor::GetAnalysisRate() {
|
||||
|
@ -2974,29 +2992,24 @@ Debug(4, "Return from Capture (%d)", captureResult);
|
|||
shared_data->last_write_time = image_buffer[index].timestamp->tv_sec;
|
||||
|
||||
image_count++;
|
||||
} // end if captureResult
|
||||
|
||||
if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) {
|
||||
|
||||
struct timeval now;
|
||||
if ( !captureResult ) {
|
||||
gettimeofday( &now, NULL );
|
||||
} else {
|
||||
now.tv_sec = image_buffer[index].timestamp->tv_sec;
|
||||
}
|
||||
// If we are too fast, we get div by zero. This seems to happen in the case of audio packets.
|
||||
if ( now.tv_sec != last_fps_time ) {
|
||||
fps = double(fps_report_interval)/(now.tv_sec-last_fps_time);
|
||||
Info( "%d -> %d -> %d", fps_report_interval, now.tv_sec, last_fps_time );
|
||||
//Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps );
|
||||
Info( "%s: %d - Capturing at %.2lf fps", name, image_count, fps );
|
||||
last_fps_time = now.tv_sec;
|
||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||
snprintf( sql, sizeof(sql), "UPDATE Monitors SET CaptureFPS='%.2lf' WHERE Id=%d", fps, id );
|
||||
if ( mysql_query( &dbconn, sql ) ) {
|
||||
Error( "Can't run query: %s", mysql_error( &dbconn ) );
|
||||
if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) {
|
||||
time_t now = image_buffer[index].timestamp->tv_sec;
|
||||
// If we are too fast, we get div by zero. This seems to happen in the case of audio packets.
|
||||
if ( now != last_fps_time ) {
|
||||
// # of images per interval / the amount of time it took
|
||||
fps = double(fps_report_interval)/(now-last_fps_time);
|
||||
Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time );
|
||||
//Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps );
|
||||
Info( "%s: images:%d - Capturing at %.2lf fps", name, image_count, fps );
|
||||
last_fps_time = now;
|
||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||
snprintf( sql, sizeof(sql), "UPDATE Monitors SET CaptureFPS='%.2lf' WHERE Id=%d", fps, id );
|
||||
if ( mysql_query( &dbconn, sql ) ) {
|
||||
Error( "Can't run query: %s", mysql_error( &dbconn ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end if captureResult
|
||||
}
|
||||
|
||||
// Icon: I'm not sure these should be here. They have nothing to do with capturing
|
||||
|
|
|
@ -432,7 +432,6 @@ public:
|
|||
int GetOptSaveJPEGs() const { return( savejpegspref ); }
|
||||
VideoWriter GetOptVideoWriter() const { return( videowriter ); }
|
||||
const std::vector<EncoderParameter_t>* GetOptEncoderParams() const { return( &encoderparamsvec ); }
|
||||
uint32_t GetLastEventId() const { return shared_data->last_event; }
|
||||
uint32_t GetVideoWriterEventId() const { return video_store_data->current_event; }
|
||||
void SetVideoWriterEventId( uint32_t p_event_id ) { video_store_data->current_event = p_event_id; }
|
||||
|
||||
|
@ -448,7 +447,7 @@ public:
|
|||
int GetAlarmCaptureDelay() const { return( alarm_capture_delay ); }
|
||||
unsigned int GetLastReadIndex() const;
|
||||
unsigned int GetLastWriteIndex() const;
|
||||
unsigned int GetLastEvent() const;
|
||||
uint32_t GetLastEventId() const;
|
||||
double GetFPS() const;
|
||||
void ForceAlarmOn( int force_score, const char *force_case, const char *force_text="" );
|
||||
void ForceAlarmOff();
|
||||
|
|
|
@ -498,7 +498,8 @@ void MonitorStream::runStream() {
|
|||
if ( type == STREAM_JPEG )
|
||||
fprintf( stdout, "Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame\r\n\r\n" );
|
||||
|
||||
int last_read_index = monitor->image_buffer_count;
|
||||
// point to end which is theoretically not a valid value because all indexes are % image_buffer_count
|
||||
unsigned int last_read_index = monitor->image_buffer_count;
|
||||
|
||||
time_t stream_start_time;
|
||||
time( &stream_start_time );
|
||||
|
@ -557,6 +558,8 @@ void MonitorStream::runStream() {
|
|||
Debug( 2, "Assigned temporary buffer" );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Debug(2, "Not using playback_buffer");
|
||||
} // end if connkey & playback_buffer
|
||||
|
||||
float max_secs_since_last_sent_frame = 10.0; //should be > keep alive amount (5 secs)
|
||||
|
@ -576,7 +579,7 @@ void MonitorStream::runStream() {
|
|||
gettimeofday( &now, NULL );
|
||||
|
||||
if ( connkey ) {
|
||||
//Debug(2, "checking command Queue for connkey: %d", connkey );
|
||||
Debug(2, "checking command Queue for connkey: %d", connkey );
|
||||
while(checkCommandQueue()) {
|
||||
Debug(2, "Have checking command Queue for connkey: %d", connkey );
|
||||
got_command = true;
|
||||
|
@ -657,26 +660,29 @@ Debug(2, "Have checking command Queue for connkey: %d", connkey );
|
|||
delayed = false;
|
||||
replay_rate = ZM_RATE_BASE;
|
||||
}
|
||||
}
|
||||
if ( (unsigned int)last_read_index != monitor->shared_data->last_write_index ) {
|
||||
int index = monitor->shared_data->last_write_index%monitor->image_buffer_count;
|
||||
} // end if ( buffered_playback && delayed )
|
||||
if ( last_read_index != monitor->shared_data->last_write_index ) {
|
||||
int index = monitor->shared_data->last_write_index % monitor->image_buffer_count; // % shouldn't be neccessary
|
||||
last_read_index = monitor->shared_data->last_write_index;
|
||||
//Debug( 1, "%d: %x - %x", index, image_buffer[index].image, image_buffer[index].image->buffer );
|
||||
Debug( 1, "index: %d: frame_mod: %d frame count: %d", index, frame_mod, frame_count );
|
||||
if ( (frame_mod == 1) || ((frame_count%frame_mod) == 0) ) {
|
||||
if ( !paused && !delayed ) {
|
||||
// Send the next frame
|
||||
Monitor::Snapshot *snap = &monitor->image_buffer[index];
|
||||
|
||||
//Debug(2, "sending Frame.");
|
||||
if ( !sendFrame( snap->image, snap->timestamp ) ) {
|
||||
Debug(2, "sendFrame failed, quiting.");
|
||||
zm_terminate = true;
|
||||
}
|
||||
// Perhaps we should use NOW instead.
|
||||
memcpy( &last_frame_timestamp, snap->timestamp, sizeof(last_frame_timestamp) );
|
||||
//frame_sent = true;
|
||||
|
||||
temp_read_index = temp_write_index;
|
||||
}
|
||||
}
|
||||
} // end if should send frame
|
||||
|
||||
if ( buffered_playback ) {
|
||||
if ( monitor->shared_data->valid ) {
|
||||
if ( monitor->image_buffer[index].timestamp->tv_sec ) {
|
||||
|
@ -706,17 +712,24 @@ Debug(2, "Have checking command Queue for connkey: %d", connkey );
|
|||
}
|
||||
} // end if buffered playback
|
||||
frame_count++;
|
||||
}
|
||||
} else {
|
||||
Debug(2,"Waiting for capture");
|
||||
} // end if ( (unsigned int)last_read_index != monitor->shared_data->last_write_index )
|
||||
|
||||
unsigned long sleep_time = (unsigned long)((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*abs(replay_rate*2)));
|
||||
Debug(2, "Sleeping for (%d)", sleep_time);
|
||||
usleep( (unsigned long)((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*abs(replay_rate*2))) );
|
||||
usleep( sleep_time );
|
||||
if ( ttl ) {
|
||||
if ( (now.tv_sec - stream_start_time) > ttl ) {
|
||||
Debug(2, "now(%d) - start(%d) > ttl(%d) break", now.tv_sec, stream_start_time, ttl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( (TV_2_FLOAT( now ) - last_frame_sent) > max_secs_since_last_sent_frame ) {
|
||||
if ( ! last_frame_sent ) {
|
||||
// If we didn't capture above, because frame_mod was bad? Then last_frame_sent will not have a value.
|
||||
last_frame_sent = now.tv_sec;
|
||||
Warning( "no last_frame_sent. Shouldn't happen. frame_mod was (%d) frame_count (%d) ", frame_mod, frame_count );
|
||||
} else if ( (TV_2_FLOAT( now ) - last_frame_sent) > max_secs_since_last_sent_frame ) {
|
||||
Error( "Terminating, last frame sent time %f secs more than maximum of %f", TV_2_FLOAT( now ) - last_frame_sent, max_secs_since_last_sent_frame );
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ void VideoStream::SetupFormat( ) {
|
|||
AVFormatContext *s= avformat_alloc_context();
|
||||
if(!s) {
|
||||
Fatal( "avformat_alloc_context failed %d \"%s\"", (size_t)ofc, av_err2str((size_t)ofc) );
|
||||
return;
|
||||
}
|
||||
|
||||
AVOutputFormat *oformat;
|
||||
|
@ -417,9 +418,15 @@ void VideoStream::OpenStream( ) {
|
|||
VideoStream::VideoStream( const char *in_filename, const char *in_format, int bitrate, double frame_rate, int colours, int subpixelorder, int width, int height ) :
|
||||
filename(in_filename),
|
||||
format(in_format),
|
||||
opicture(NULL),
|
||||
tmp_opicture(NULL),
|
||||
video_outbuf(NULL),
|
||||
video_outbuf_size(0),
|
||||
last_pts( -1 ),
|
||||
streaming_thread(0),
|
||||
do_streaming(true),
|
||||
add_timestamp(false),
|
||||
timestamp(0),
|
||||
buffer_copy(NULL),
|
||||
buffer_copy_lock(new pthread_mutex_t),
|
||||
buffer_copy_size(0),
|
||||
|
@ -573,11 +580,11 @@ double VideoStream::EncodeFrame( const uint8_t *buffer, int buffer_size, bool _a
|
|||
}
|
||||
|
||||
double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, bool add_timestamp, unsigned int timestamp ) {
|
||||
|
||||
if ( codec_context->pix_fmt != pf ) {
|
||||
#ifdef HAVE_LIBSWSCALE
|
||||
static struct SwsContext *img_convert_ctx = 0;
|
||||
#endif // HAVE_LIBSWSCALE
|
||||
|
||||
if ( codec_context->pix_fmt != pf ) {
|
||||
memcpy( tmp_opicture->data[0], buffer, buffer_size );
|
||||
#ifdef HAVE_LIBSWSCALE
|
||||
if ( !img_convert_ctx ) {
|
||||
|
|
|
@ -24,11 +24,9 @@
|
|||
|
||||
#if HAVE_LIBAVCODEC
|
||||
|
||||
class VideoStream
|
||||
{
|
||||
class VideoStream {
|
||||
protected:
|
||||
struct MimeData
|
||||
{
|
||||
struct MimeData {
|
||||
const char *format;
|
||||
const char *mime_type;
|
||||
};
|
||||
|
@ -56,9 +54,9 @@ protected:
|
|||
|
||||
pthread_t streaming_thread;
|
||||
bool do_streaming;
|
||||
uint8_t *buffer_copy;
|
||||
bool add_timestamp;
|
||||
unsigned int timestamp;
|
||||
uint8_t *buffer_copy;
|
||||
pthread_mutex_t *buffer_copy_lock;
|
||||
int buffer_copy_size;
|
||||
int buffer_copy_used;
|
||||
|
|
|
@ -39,14 +39,14 @@ protected:
|
|||
double _1_m;
|
||||
|
||||
static int CompareYX( const void *p1, const void *p2 ) {
|
||||
const Edge *e1 = (const Edge *)p1, *e2 = (const Edge *)p2;
|
||||
const Edge *e1 = reinterpret_cast<const Edge *>(p1), *e2 = reinterpret_cast<const Edge *>(p2);
|
||||
if ( e1->min_y == e2->min_y )
|
||||
return( int(e1->min_x - e2->min_x) );
|
||||
else
|
||||
return( int(e1->min_y - e2->min_y) );
|
||||
}
|
||||
static int CompareX( const void *p1, const void *p2 ) {
|
||||
const Edge *e1 = (const Edge *)p1, *e2 = (const Edge *)p2;
|
||||
const Edge *e1 = reinterpret_cast<const Edge *>(p1), *e2 = reinterpret_cast<const Edge *>(p2);
|
||||
return( int(e1->min_x - e2->min_x) );
|
||||
}
|
||||
};
|
||||
|
|
|
@ -159,8 +159,7 @@ SessionDescriptor::SessionDescriptor( const std::string &url, const std::string
|
|||
MediaDescriptor *currMedia = 0;
|
||||
|
||||
StringVector lines = split( sdp, "\r\n" );
|
||||
for ( StringVector::const_iterator iter = lines.begin(); iter != lines.end(); iter++ )
|
||||
{
|
||||
for ( StringVector::const_iterator iter = lines.begin(); iter != lines.end(); ++iter ) {
|
||||
std::string line = *iter;
|
||||
if ( line.empty() )
|
||||
break;
|
||||
|
@ -276,48 +275,26 @@ SessionDescriptor::SessionDescriptor( const std::string &url, const std::string
|
|||
{
|
||||
StringVector attr3Tokens = split( attr2Tokens[i], "=" );
|
||||
//Info( "Name = %s, Value = %s", attr3Tokens[0].c_str(), attr3Tokens[1].c_str() );
|
||||
if ( attr3Tokens[0] == "profile-level-id" )
|
||||
{
|
||||
}
|
||||
else if ( attr3Tokens[0] == "config" )
|
||||
{
|
||||
}
|
||||
else if ( attr3Tokens[0] == "sprop-parameter-sets" )
|
||||
{
|
||||
if ( attr3Tokens[0] == "profile-level-id" ) {
|
||||
} else if ( attr3Tokens[0] == "config" ) {
|
||||
} else if ( attr3Tokens[0] == "sprop-parameter-sets" ) {
|
||||
size_t t = attr2Tokens[i].find("=");
|
||||
char *c = (char *)attr2Tokens[i].c_str() + t + 1;
|
||||
Debug(4, "sprop-parameter-sets value %s", c);
|
||||
currMedia->setSprops(std::string(c));
|
||||
}
|
||||
else if ( attr3Tokens[0] == "sprop-parameter-sets" )
|
||||
{
|
||||
size_t t = attr2Tokens[i].find("=");
|
||||
char *c = (char *)attr2Tokens[i].c_str() + t + 1;
|
||||
Debug(4, "sprop-parameter-sets value %s", c);
|
||||
currMedia->setSprops(std::string(c));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Debug( 3, "Ignoring SDP fmtp attribute '%s' for media '%s'", attr3Tokens[0].c_str(), currMedia->getType().c_str() )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( attrName == "mpeg4-iod" )
|
||||
{
|
||||
} else if ( attrName == "mpeg4-iod" ) {
|
||||
// a=mpeg4-iod: "data:application/mpeg4-iod;base64,AoEAAE8BAf73AQOAkwABQHRkYXRhOmFwcGxpY2F0aW9uL21wZWc0LW9kLWF1O2Jhc2U2NCxBVGdCR3dVZkF4Y0F5U1FBWlFRTklCRUVrK0FBQWEyd0FBR3RzQVlCQkFFWkFwOERGUUJsQlFRTlFCVUFDN2dBQVBvQUFBRDZBQVlCQXc9PQQNAQUABAAAAAAAAAAAAAYJAQAAAAAAAAAAA0IAAkA+ZGF0YTphcHBsaWNhdGlvbi9tcGVnNC1iaWZzLWF1O2Jhc2U2NCx3QkFTZ1RBcUJYSmhCSWhRUlFVL0FBPT0EEgINAAACAAAAAAAAAAAFAwAAQAYJAQAAAAAAAAAA"
|
||||
}
|
||||
else if ( attrName == "mpeg4-esid" )
|
||||
{
|
||||
} else if ( attrName == "mpeg4-esid" ) {
|
||||
// a=mpeg4-esid:201
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Debug( 3, "Ignoring SDP attribute '%s' for media '%s'", line.c_str(), currMedia->getType().c_str() )
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Debug( 3, "Ignoring general SDP attribute '%s'", line.c_str() );
|
||||
}
|
||||
break;
|
||||
|
@ -369,8 +346,7 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const
|
|||
strncpy( formatContext->comment, mInfo.c_str(), sizeof(formatContext->comment) );
|
||||
*/
|
||||
//formatContext->nb_streams = mMediaList.size();
|
||||
for ( unsigned int i = 0; i < mMediaList.size(); i++ )
|
||||
{
|
||||
for ( unsigned int i = 0; i < mMediaList.size(); i++ ) {
|
||||
const MediaDescriptor *mediaDesc = mMediaList[i];
|
||||
#if !LIBAVFORMAT_VERSION_CHECK(53, 10, 0, 17, 0)
|
||||
AVStream *stream = av_new_stream( formatContext, i );
|
||||
|
@ -379,16 +355,13 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const
|
|||
stream->id = i;
|
||||
#endif
|
||||
|
||||
AVCodecContext *codec_context = NULL;
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
codec_context = avcodec_alloc_context3(NULL);
|
||||
avcodec_parameters_to_context(codec_context, stream->codecpar);
|
||||
AVCodecContext *codec_context = avcodec_alloc_context3(NULL);
|
||||
avcodec_parameters_to_context(codec_context, stream->codecpar);
|
||||
#else
|
||||
codec_context = stream->codec;
|
||||
AVCodecContext *codec_context = stream->codec;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
Debug( 1, "Looking for codec for %s payload type %d / %s", mediaDesc->getType().c_str(), mediaDesc->getPayloadType(), mediaDesc->getPayloadDesc().c_str() );
|
||||
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
||||
if ( mediaDesc->getType() == "video" )
|
||||
|
@ -409,13 +382,10 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const
|
|||
#if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103)
|
||||
std::string codec_name;
|
||||
#endif
|
||||
if ( mediaDesc->getPayloadType() < PAYLOAD_TYPE_DYNAMIC )
|
||||
{
|
||||
if ( mediaDesc->getPayloadType() < PAYLOAD_TYPE_DYNAMIC ) {
|
||||
// Look in static table
|
||||
for ( unsigned int i = 0; i < (sizeof(smStaticPayloads)/sizeof(*smStaticPayloads)); i++ )
|
||||
{
|
||||
if ( smStaticPayloads[i].payloadType == mediaDesc->getPayloadType() )
|
||||
{
|
||||
for ( unsigned int i = 0; i < (sizeof(smStaticPayloads)/sizeof(*smStaticPayloads)); i++ ) {
|
||||
if ( smStaticPayloads[i].payloadType == mediaDesc->getPayloadType() ) {
|
||||
Debug( 1, "Got static payload type %d, %s", smStaticPayloads[i].payloadType, smStaticPayloads[i].payloadName );
|
||||
#if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103)
|
||||
codec_name = std::string( smStaticPayloads[i].payloadName );
|
||||
|
|
|
@ -69,12 +69,13 @@ void StreamBase::updateFrameRate( double fps ) {
|
|||
while( effective_fps > maxfps ) {
|
||||
effective_fps /= 2.0;
|
||||
frame_mod *= 2;
|
||||
}
|
||||
Debug( 3, "aEFPS:%.2f, aFM:%d", effective_fps, frame_mod );
|
||||
}
|
||||
}
|
||||
|
||||
bool StreamBase::checkCommandQueue() {
|
||||
if ( sd >= 0 ) {
|
||||
Debug(2, "sd is (%d)", sd );
|
||||
CmdMsg msg;
|
||||
memset( &msg, 0, sizeof(msg) );
|
||||
int nbytes = recvfrom( sd, &msg, sizeof(msg), MSG_DONTWAIT, 0, 0 );
|
||||
|
@ -92,6 +93,8 @@ Debug(2, "Message length is (%d)", nbytes );
|
|||
processCommand( &msg );
|
||||
return( true );
|
||||
}
|
||||
} else {
|
||||
Error("sd is < 0");
|
||||
}
|
||||
return( false );
|
||||
}
|
||||
|
@ -288,7 +291,7 @@ void StreamBase::openComms() {
|
|||
if ( sd < 0 ) {
|
||||
Fatal( "Can't create socket: %s", strerror(errno) );
|
||||
} else {
|
||||
Debug(3, "Have socket %d", sd );
|
||||
Debug(1, "Have socket %d", sd );
|
||||
}
|
||||
|
||||
length = snprintf( loc_sock_path, sizeof(loc_sock_path), "%s/zms-%06ds.sock", staticConfig.PATH_SOCKS.c_str(), connkey );
|
||||
|
@ -296,6 +299,7 @@ void StreamBase::openComms() {
|
|||
Warning("Socket path was truncated.");
|
||||
length = sizeof(loc_sock_path)-1;
|
||||
}
|
||||
// Unlink before bind, in case it already exists
|
||||
unlink( loc_sock_path );
|
||||
if ( sizeof(loc_addr.sun_path) < length ) {
|
||||
Error("Not enough space %d in loc_addr.sun_path for socket file %s", sizeof(loc_addr.sun_path), loc_sock_path );
|
||||
|
@ -313,7 +317,7 @@ void StreamBase::openComms() {
|
|||
rem_addr.sun_family = AF_UNIX;
|
||||
} // end if connKey > 0
|
||||
Debug(2, "comms open" );
|
||||
}
|
||||
} // end void StreamBase::openComms()
|
||||
|
||||
void StreamBase::closeComms() {
|
||||
if ( connkey > 0 ) {
|
||||
|
@ -324,10 +328,10 @@ void StreamBase::closeComms() {
|
|||
if ( loc_sock_path[0] ) {
|
||||
unlink( loc_sock_path );
|
||||
}
|
||||
if (lock_fd > 0) {
|
||||
if ( lock_fd > 0 ) {
|
||||
close(lock_fd); //close it rather than unlock it incase it got deleted.
|
||||
unlink(sock_path_lock);
|
||||
// You cannot unlink the lockfile. You have to leave a mess around. SUCKS
|
||||
//unlink(sock_path_lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,8 +32,7 @@
|
|||
#include <sys/thr.h>
|
||||
#endif
|
||||
|
||||
class ThreadException : public Exception
|
||||
{
|
||||
class ThreadException : public Exception {
|
||||
private:
|
||||
#ifndef SOLARIS
|
||||
pid_t pid() {
|
||||
|
@ -55,12 +54,11 @@ private:
|
|||
pthread_t pid() { return( pthread_self() ); }
|
||||
#endif
|
||||
public:
|
||||
ThreadException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)pid() ) ) {
|
||||
explicit ThreadException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)pid() ) ) {
|
||||
}
|
||||
};
|
||||
|
||||
class Mutex
|
||||
{
|
||||
class Mutex {
|
||||
friend class Condition;
|
||||
|
||||
private:
|
||||
|
@ -71,8 +69,7 @@ public:
|
|||
~Mutex();
|
||||
|
||||
private:
|
||||
pthread_mutex_t *getMutex()
|
||||
{
|
||||
pthread_mutex_t *getMutex() {
|
||||
return( &mMutex );
|
||||
}
|
||||
|
||||
|
@ -84,18 +81,15 @@ public:
|
|||
bool locked();
|
||||
};
|
||||
|
||||
class ScopedMutex
|
||||
{
|
||||
class ScopedMutex {
|
||||
private:
|
||||
Mutex &mMutex;
|
||||
|
||||
public:
|
||||
ScopedMutex( Mutex &mutex ) : mMutex( mutex )
|
||||
{
|
||||
explicit ScopedMutex( Mutex &mutex ) : mMutex( mutex ) {
|
||||
mMutex.lock();
|
||||
}
|
||||
~ScopedMutex()
|
||||
{
|
||||
~ScopedMutex() {
|
||||
mMutex.unlock();
|
||||
}
|
||||
|
||||
|
@ -164,8 +158,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
template <class T> class ThreadData
|
||||
{
|
||||
template <class T> class ThreadData {
|
||||
private:
|
||||
T mValue;
|
||||
mutable bool mChanged;
|
||||
|
@ -173,11 +166,11 @@ private:
|
|||
mutable Condition mCondition;
|
||||
|
||||
public:
|
||||
__attribute__((used)) ThreadData() : mCondition( mMutex )
|
||||
{
|
||||
__attribute__((used)) ThreadData() : mCondition( mMutex ) {
|
||||
mChanged = false;
|
||||
}
|
||||
__attribute__((used)) ThreadData( T value ) : mValue( value ), mCondition( mMutex )
|
||||
{
|
||||
__attribute__((used)) ThreadData( T value ) : mValue( value ), mCondition( mMutex ) {
|
||||
mChanged = false;
|
||||
}
|
||||
//~ThreadData() {}
|
||||
|
||||
|
|
|
@ -27,11 +27,12 @@
|
|||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "zm_utils.h"
|
||||
|
||||
User::User() {
|
||||
username[0] = password[0] = 0;
|
||||
enabled = false;
|
||||
stream = events = control = monitors = system = PERM_NONE;
|
||||
monitor_ids = 0;
|
||||
}
|
||||
|
||||
User::User( MYSQL_ROW &dbrow ) {
|
||||
|
@ -44,45 +45,41 @@ User::User( MYSQL_ROW &dbrow ) {
|
|||
control = (Permission)atoi( dbrow[index++] );
|
||||
monitors = (Permission)atoi( dbrow[index++] );
|
||||
system = (Permission)atoi( dbrow[index++] );
|
||||
monitor_ids = 0;
|
||||
char *monitor_ids_str = dbrow[index++];
|
||||
if ( monitor_ids_str && *monitor_ids_str ) {
|
||||
monitor_ids = new int[strlen(monitor_ids_str)];
|
||||
int n_monitor_ids = 0;
|
||||
const char *ptr = monitor_ids_str;
|
||||
do {
|
||||
int id = 0;
|
||||
while( isdigit( *ptr ) ) {
|
||||
id *= 10;
|
||||
id += *ptr-'0';
|
||||
ptr++;
|
||||
}
|
||||
if ( id ) {
|
||||
monitor_ids[n_monitor_ids++] = id;
|
||||
if ( !*ptr )
|
||||
break;
|
||||
}
|
||||
while ( !isdigit( *ptr ) )
|
||||
ptr++;
|
||||
} while( *ptr );
|
||||
monitor_ids[n_monitor_ids] = 0;
|
||||
StringVector ids = split(monitor_ids_str, ",");
|
||||
for( StringVector::iterator i = ids.begin(); i < ids.end(); ++i ) {
|
||||
monitor_ids.push_back( atoi( (*i).c_str()) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
User::~User() {
|
||||
delete monitor_ids;
|
||||
monitor_ids.clear();
|
||||
}
|
||||
|
||||
void User::Copy( const User &u ) {
|
||||
strncpy( username, u.username, sizeof(username)-1 );
|
||||
strncpy( password, u.password, sizeof(password)-1 );
|
||||
enabled = u.enabled;
|
||||
stream = u.stream;
|
||||
events = u.events;
|
||||
control = u.control;
|
||||
monitors = u.monitors;
|
||||
system = u.system;
|
||||
monitor_ids = u.monitor_ids;
|
||||
}
|
||||
|
||||
bool User::canAccess( int monitor_id ) {
|
||||
if ( !monitor_ids ) {
|
||||
return( true );
|
||||
}
|
||||
for ( int i = 0; monitor_ids[i]; i++ ) {
|
||||
if ( monitor_ids[i] == monitor_id ) {
|
||||
return( true );
|
||||
if ( monitor_ids.empty() )
|
||||
return true;
|
||||
|
||||
for ( std::vector<int>::iterator i = monitor_ids.begin(); i != monitor_ids.end(); ++i ) {
|
||||
if ( *i == monitor_id ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return( false );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Function to load a user from username and password
|
||||
|
|
|
@ -36,8 +36,8 @@
|
|||
#include <openssl/md5.h>
|
||||
#endif // HAVE_L || HAVE_LIBCRYPTO
|
||||
|
||||
class User
|
||||
{
|
||||
#include <vector>
|
||||
class User {
|
||||
public:
|
||||
typedef enum { PERM_NONE=1, PERM_VIEW, PERM_EDIT } Permission;
|
||||
|
||||
|
@ -50,12 +50,17 @@ protected:
|
|||
Permission control;
|
||||
Permission monitors;
|
||||
Permission system;
|
||||
int *monitor_ids;
|
||||
std::vector<int> monitor_ids;
|
||||
|
||||
public:
|
||||
User();
|
||||
User( MYSQL_ROW &dbrow );
|
||||
explicit User( MYSQL_ROW &dbrow );
|
||||
~User();
|
||||
User( User &u ) { Copy(u); }
|
||||
void Copy( const User &u );
|
||||
User operator=(const User &u) {
|
||||
Copy(u); return *this;
|
||||
}
|
||||
|
||||
const char *getUsername() const { return( username ); }
|
||||
const char *getPassword() const { return( password ); }
|
||||
|
|
|
@ -49,8 +49,7 @@ std::string trimSet(std::string str, std::string trimset) {
|
|||
return str.substr( startpos, endpos-startpos+1 );
|
||||
}
|
||||
|
||||
std::string trimSpaces(std::string str)
|
||||
{
|
||||
std::string trimSpaces(std::string str) {
|
||||
return trimSet(str, " \t");
|
||||
}
|
||||
|
||||
|
@ -80,7 +79,7 @@ const std::string stringtf( const char *format, ... )
|
|||
return( tempString );
|
||||
}
|
||||
|
||||
const std::string stringtf( const std::string &format, ... )
|
||||
const std::string stringtf( const std::string format, ... )
|
||||
{
|
||||
va_list ap;
|
||||
char tempBuffer[8192];
|
||||
|
@ -209,10 +208,9 @@ int split(const char* string, const char delim, std::vector<std::string>& items)
|
|||
return -2;
|
||||
|
||||
std::string str(string);
|
||||
size_t pos;
|
||||
|
||||
while(true) {
|
||||
pos = str.find(delim);
|
||||
size_t pos = str.find(delim);
|
||||
items.push_back(str.substr(0, pos));
|
||||
str.erase(0, pos+1);
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ std::string trimSet(std::string str, std::string trimset);
|
|||
std::string replaceAll(std::string str, std::string from, std::string to);
|
||||
|
||||
const std::string stringtf( const char *format, ... );
|
||||
const std::string stringtf( const std::string &format, ... );
|
||||
const std::string stringtf( const std::string format, ... );
|
||||
|
||||
bool startsWith( const std::string &haystack, const std::string &needle );
|
||||
StringVector split( const std::string &string, const std::string &chars, int limit=0 );
|
||||
|
|
|
@ -125,7 +125,8 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
|||
|
||||
#else
|
||||
video_out_stream =
|
||||
avformat_new_stream(oc,(const AVCodec *)(video_in_ctx->codec));
|
||||
avformat_new_stream(oc,(AVCodec *)(video_in_ctx->codec));
|
||||
//avformat_new_stream(oc,(const AVCodec *)(video_in_ctx->codec));
|
||||
if (!video_out_stream) {
|
||||
Fatal("Unable to create video out stream\n");
|
||||
} else {
|
||||
|
@ -194,6 +195,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
|||
|
||||
converted_in_samples = NULL;
|
||||
audio_out_codec = NULL;
|
||||
audio_in_codec = NULL;
|
||||
audio_in_ctx = NULL;
|
||||
audio_out_stream = NULL;
|
||||
in_frame = NULL;
|
||||
|
@ -226,7 +228,11 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
|||
Debug(3, "Got AAC");
|
||||
|
||||
audio_out_stream =
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
avformat_new_stream(oc, (const AVCodec *)(audio_in_ctx->codec));
|
||||
#else
|
||||
avformat_new_stream(oc, (AVCodec *)audio_in_ctx->codec);
|
||||
#endif
|
||||
if (!audio_out_stream) {
|
||||
Error("Unable to create audio out stream\n");
|
||||
audio_out_stream = NULL;
|
||||
|
@ -406,12 +412,34 @@ VideoStore::~VideoStore() {
|
|||
// Just do a file open/close/writeheader/etc.
|
||||
// What if we were only doing audio recording?
|
||||
if (video_out_stream) {
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
// We allocate and copy in newer ffmpeg, so need to free it
|
||||
avcodec_free_context(&video_in_ctx);
|
||||
#endif
|
||||
video_in_ctx=NULL;
|
||||
|
||||
avcodec_close(video_out_ctx);
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
avcodec_free_context(&video_out_ctx);
|
||||
#endif
|
||||
video_out_ctx = NULL;
|
||||
Debug(4, "Success freeing video_out_ctx");
|
||||
}
|
||||
if (audio_out_stream) {
|
||||
if ( audio_out_stream ) {
|
||||
if ( audio_in_codec ) {
|
||||
avcodec_close(audio_in_ctx);
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
// We allocate and copy in newer ffmpeg, so need to free it
|
||||
avcodec_free_context(&audio_in_ctx);
|
||||
#endif
|
||||
audio_in_ctx = NULL;
|
||||
audio_in_codec = NULL;
|
||||
} // end if audio_in_codec
|
||||
|
||||
avcodec_close(audio_out_ctx);
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
avcodec_free_context(&audio_out_ctx);
|
||||
#endif
|
||||
audio_out_ctx = NULL;
|
||||
#ifdef HAVE_LIBAVRESAMPLE
|
||||
if (resample_ctx) {
|
||||
|
@ -454,10 +482,10 @@ bool VideoStore::setup_resampler() {
|
|||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
// Newer ffmpeg wants to keep everything separate... so have to lookup our own
|
||||
// decoder, can't reuse the one from the camera.
|
||||
AVCodec *audio_in_codec =
|
||||
audio_in_codec =
|
||||
avcodec_find_decoder(audio_in_stream->codecpar->codec_id);
|
||||
#else
|
||||
AVCodec *audio_in_codec =
|
||||
audio_in_codec =
|
||||
avcodec_find_decoder(audio_in_ctx->codec_id);
|
||||
#endif
|
||||
ret = avcodec_open2(audio_in_ctx, audio_in_codec, NULL);
|
||||
|
@ -778,7 +806,6 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
|
|||
}
|
||||
|
||||
opkt.flags = ipkt->flags;
|
||||
int keyframe = opkt.flags & AV_PKT_FLAG_KEY;
|
||||
opkt.pos = -1;
|
||||
|
||||
opkt.data = ipkt->data;
|
||||
|
@ -792,7 +819,7 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
|
|||
Debug(1,
|
||||
"writing video packet keyframe(%d) pts(%d) dts(%d) duration(%d) "
|
||||
"ipkt.duration(%d)",
|
||||
keyframe, opkt.pts, opkt.dts, duration, ipkt->duration);
|
||||
opkt.flags & AV_PKT_FLAG_KEY, opkt.pts, opkt.dts, duration, ipkt->duration);
|
||||
if ((opkt.data == NULL) || (opkt.size < 1)) {
|
||||
Warning("%s:%d: Mangled AVPacket: discarding frame", __FILE__, __LINE__);
|
||||
dumpPacket(ipkt);
|
||||
|
@ -865,6 +892,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
|||
* If we are at the end of the file, pass an empty packet to the decoder
|
||||
* to flush it.
|
||||
*/
|
||||
int data_present;
|
||||
if ((ret = avcodec_decode_audio4(audio_in_ctx, in_frame,
|
||||
&data_present, ipkt)) < 0) {
|
||||
Error("Could not decode frame (error '%s')\n",
|
||||
|
|
|
@ -16,7 +16,6 @@ extern "C" {
|
|||
|
||||
class VideoStore {
|
||||
private:
|
||||
unsigned int packets_written;
|
||||
|
||||
AVOutputFormat *out_format;
|
||||
AVFormatContext *oc;
|
||||
|
@ -34,13 +33,13 @@ private:
|
|||
AVFrame *out_frame;
|
||||
|
||||
AVCodecContext *video_in_ctx;
|
||||
AVCodec *audio_in_codec;
|
||||
AVCodecContext *audio_in_ctx;
|
||||
int ret;
|
||||
|
||||
// The following are used when encoding the audio stream to AAC
|
||||
AVCodec *audio_out_codec;
|
||||
AVCodecContext *audio_out_ctx;
|
||||
int data_present;
|
||||
AVAudioFifo *fifo;
|
||||
int out_frame_size;
|
||||
#ifdef HAVE_LIBAVRESAMPLE
|
||||
|
|
|
@ -946,13 +946,9 @@ bool Zone::DumpSettings( char *output, bool /*verbose*/ ) {
|
|||
void Zone::std_alarmedpixels(Image* pdiff_image, const Image* ppoly_image, unsigned int* pixel_count, unsigned int* pixel_sum) {
|
||||
uint32_t pixelsalarmed = 0;
|
||||
uint32_t pixelsdifference = 0;
|
||||
uint8_t *pdiff;
|
||||
const uint8_t *ppoly;
|
||||
uint8_t calc_max_pixel_threshold = 255;
|
||||
unsigned int lo_y;
|
||||
unsigned int hi_y;
|
||||
unsigned int lo_x;
|
||||
unsigned int hi_x;
|
||||
|
||||
if(max_pixel_threshold)
|
||||
calc_max_pixel_threshold = max_pixel_threshold;
|
||||
|
@ -960,12 +956,12 @@ void Zone::std_alarmedpixels(Image* pdiff_image, const Image* ppoly_image, unsig
|
|||
lo_y = polygon.LoY();
|
||||
hi_y = polygon.HiY();
|
||||
for ( unsigned int y = lo_y; y <= hi_y; y++ ) {
|
||||
lo_x = ranges[y].lo_x;
|
||||
hi_x = ranges[y].hi_x;
|
||||
unsigned int lo_x = ranges[y].lo_x;
|
||||
unsigned int hi_x = ranges[y].hi_x;
|
||||
|
||||
Debug( 7, "Checking line %d from %d -> %d", y, lo_x, hi_x );
|
||||
pdiff = (uint8_t*)pdiff_image->Buffer( lo_x, y );
|
||||
ppoly = ppoly_image->Buffer( lo_x, y );
|
||||
uint8_t *pdiff = (uint8_t*)pdiff_image->Buffer( lo_x, y );
|
||||
const uint8_t *ppoly = ppoly_image->Buffer( lo_x, y );
|
||||
|
||||
for ( unsigned int x = lo_x; x <= hi_x; x++, pdiff++, ppoly++ ) {
|
||||
if ( *ppoly && (*pdiff > min_pixel_threshold) && (*pdiff <= calc_max_pixel_threshold) ) {
|
||||
|
|
18
src/zms.cpp
18
src/zms.cpp
|
@ -84,12 +84,6 @@ int main( int argc, const char *argv[] ) {
|
|||
|
||||
zmLoadConfig();
|
||||
|
||||
logInit( "zms" );
|
||||
|
||||
hwcaps_detect();
|
||||
|
||||
zmSetDefaultTermHandler();
|
||||
zmSetDefaultDieHandler();
|
||||
|
||||
const char *query = getenv( "QUERY_STRING" );
|
||||
if ( query ) {
|
||||
|
@ -175,6 +169,14 @@ int main( int argc, const char *argv[] ) {
|
|||
} // end foreach parm
|
||||
} // end if query
|
||||
|
||||
char log_id_string[32] = "zms";
|
||||
if ( monitor_id ) {
|
||||
snprintf(log_id_string, sizeof(log_id_string), "zms_m%d", monitor_id);
|
||||
} else {
|
||||
snprintf(log_id_string, sizeof(log_id_string), "zms_e%d", event_id);
|
||||
}
|
||||
logInit( log_id_string );
|
||||
|
||||
if ( config.opt_use_auth ) {
|
||||
User *user = 0;
|
||||
|
||||
|
@ -205,6 +207,10 @@ int main( int argc, const char *argv[] ) {
|
|||
ValidateAccess( user, monitor_id );
|
||||
}
|
||||
|
||||
hwcaps_detect();
|
||||
zmSetDefaultTermHandler();
|
||||
zmSetDefaultDieHandler();
|
||||
|
||||
setbuf( stdout, 0 );
|
||||
if ( nph ) {
|
||||
fprintf( stdout, "HTTP/1.0 200 OK\r\n" );
|
||||
|
|
|
@ -514,10 +514,10 @@ int main( int argc, char *argv[] ) {
|
|||
}
|
||||
if ( function & ZMU_EVENT ) {
|
||||
if ( verbose )
|
||||
printf( "Last event id: %d\n", monitor->GetLastEvent() );
|
||||
printf( "Last event id: %d\n", monitor->GetLastEventId() );
|
||||
else {
|
||||
if ( have_output ) printf( "%c", separator );
|
||||
printf( "%d", monitor->GetLastEvent() );
|
||||
printf( "%d", monitor->GetLastEventId() );
|
||||
have_output = true;
|
||||
}
|
||||
}
|
||||
|
@ -693,8 +693,7 @@ int main( int argc, char *argv[] ) {
|
|||
Error( "Can't use query result: %s", mysql_error( &dbconn ) );
|
||||
exit( mysql_errno( &dbconn ) );
|
||||
}
|
||||
int n_monitors = mysql_num_rows( result );
|
||||
Debug( 1, "Got %d monitors", n_monitors );
|
||||
Debug( 1, "Got %d monitors", mysql_num_rows( result ) );
|
||||
|
||||
printf( "%4s%5s%6s%9s%14s%6s%6s%8s%8s\n", "Id", "Func", "State", "TrgState", "LastImgTim", "RdIdx", "WrIdx", "LastEvt", "FrmRate" );
|
||||
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) {
|
||||
|
@ -713,7 +712,7 @@ int main( int argc, char *argv[] ) {
|
|||
tv.tv_sec, tv.tv_usec/10000,
|
||||
monitor->GetLastReadIndex(),
|
||||
monitor->GetLastWriteIndex(),
|
||||
monitor->GetLastEvent(),
|
||||
monitor->GetLastEventId(),
|
||||
monitor->GetFPS()
|
||||
);
|
||||
delete monitor;
|
||||
|
|
|
@ -8,6 +8,13 @@ exit;
|
|||
|
||||
fi
|
||||
|
||||
DEBUILD=`which debuild`;
|
||||
|
||||
if [ "$DEBUILD" == "" ]; then
|
||||
echo "You must install the devscripts package. Try sudo apt-get install devscripts";
|
||||
exit;
|
||||
fi
|
||||
|
||||
for i in "$@"
|
||||
do
|
||||
case $i in
|
||||
|
|
|
@ -76,6 +76,19 @@ if ( canView( 'Events' ) ) {
|
|||
ajaxError( 'Export Failed' );
|
||||
break;
|
||||
}
|
||||
case 'download' :
|
||||
{
|
||||
require_once( ZM_SKIN_PATH.'/includes/export_functions.php' );
|
||||
$exportVideo = 1;
|
||||
$exportFormat = $_REQUEST['exportFormat'];
|
||||
$exportStructure = 'flat';
|
||||
$exportIds = !empty($_REQUEST['eids'])?$_REQUEST['eids']:$_REQUEST['id'];
|
||||
if ( $exportFile = exportEvents( $exportIds, false, false, false, $exportVideo, false, $exportFormat, $exportStructure ) )
|
||||
ajaxResponse( array( 'exportFile'=>$exportFile ) );
|
||||
else
|
||||
ajaxError( 'Export Failed' );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
<?php
|
||||
if ($_REQUEST['entity'] == "navBar") {
|
||||
ajaxResponse(getNavBarHtml('reload'));
|
||||
return;
|
||||
}
|
||||
|
||||
$statusData = array(
|
||||
'system' => array(
|
||||
|
@ -137,6 +141,17 @@ $statusData = array(
|
|||
//'Path' => array( 'postFunc' => 'getEventPath' ),
|
||||
),
|
||||
),
|
||||
'frames' => array(
|
||||
'permission' => 'Events',
|
||||
'table' => 'Frames',
|
||||
'selector' => 'EventId',
|
||||
'elements' => array(
|
||||
'EventId' => true,
|
||||
'FrameId' => true,
|
||||
'Type' => true,
|
||||
'Delta' => true,
|
||||
),
|
||||
),
|
||||
'frame' => array(
|
||||
'permission' => 'Events',
|
||||
'table' => 'Frames',
|
||||
|
|
|
@ -15,6 +15,7 @@ if ( !($socket = @socket_create( AF_UNIX, SOCK_DGRAM, 0 )) ) {
|
|||
$locSockFile = ZM_PATH_SOCKS.'/zms-'.sprintf("%06d",$_REQUEST['connkey']).'w.sock';
|
||||
if ( file_exists( $locSockFile ) ) {
|
||||
Warning("sock file $locSockFile already exists?! Is someone else talking to zms?");
|
||||
// They could be. We can maybe have concurrent requests from a browser.
|
||||
} else {
|
||||
Logger::Debug("socket file does not exist, we should be good to connect.");
|
||||
}
|
||||
|
@ -115,7 +116,9 @@ switch ( $data['type'] ) {
|
|||
case MSG_DATA_WATCH :
|
||||
{
|
||||
$data = unpack( "ltype/imonitor/istate/dfps/ilevel/irate/ddelay/izoom/Cdelayed/Cpaused/Cenabled/Cforced", $msg );
|
||||
Logger::Debug("FPS: " . $data['fps'] );
|
||||
$data['fps'] = round( $data['fps'], 2 );
|
||||
Logger::Debug("FPS: " . $data['fps'] );
|
||||
$data['rate'] /= RATE_BASE;
|
||||
$data['delay'] = round( $data['delay'], 2 );
|
||||
$data['zoom'] = round( $data['zoom']/SCALE_BASE, 1 );
|
||||
|
|
|
@ -124,7 +124,7 @@ public function beforeFilter() {
|
|||
if (!$this->Monitor->exists($id)) {
|
||||
throw new NotFoundException(__('Invalid monitor'));
|
||||
}
|
||||
if ($this->Session->Read('systemPermission') != 'Edit')
|
||||
if ($this->Session->Read('monitorPermission') != 'Edit')
|
||||
{
|
||||
throw new UnauthorizedException(__('Insufficient privileges'));
|
||||
return;
|
||||
|
|
|
@ -9,6 +9,7 @@ class Event {
|
|||
'StorageId',
|
||||
'Name',
|
||||
'DiskSpace',
|
||||
'SaveJPEGs',
|
||||
);
|
||||
public function __construct( $IdOrRow = null ) {
|
||||
$row = NULL;
|
||||
|
|
|
@ -15,6 +15,9 @@ private $defaults = array(
|
|||
'Height' => null,
|
||||
'Orientation' => null,
|
||||
'AnalysisFPSLimit' => null,
|
||||
'AnalysisFPS' => null,
|
||||
'CaptureFPS' => null,
|
||||
'ZoneCount' => 0,
|
||||
);
|
||||
private $control_fields = array(
|
||||
'Name' => '',
|
||||
|
@ -185,11 +188,13 @@ private $control_fields = array(
|
|||
}
|
||||
|
||||
public function getStreamSrc( $args, $querySep='&' ) {
|
||||
|
||||
$streamSrc = ZM_BASE_PROTOCOL.'://';
|
||||
if ( isset($this->{'ServerId'}) and $this->{'ServerId'} ) {
|
||||
$Server = new Server( $this->{'ServerId'} );
|
||||
$streamSrc = ZM_BASE_PROTOCOL.'://'.$Server->Hostname();
|
||||
$streamSrc .= $Server->Hostname();
|
||||
} else {
|
||||
$streamSrc = ZM_BASE_URL;
|
||||
$streamSrc .= $_SERVER['HTTP_HOST'];
|
||||
}
|
||||
if ( ZM_MIN_STREAMING_PORT )
|
||||
$streamSrc .= ':'. (ZM_MIN_STREAMING_PORT+$this->{'Id'});
|
||||
|
|
|
@ -18,7 +18,7 @@ class MontageLayout {
|
|||
if ( ! $row ) {
|
||||
Error("Unable to load MontageLayout record for Id=" . $IdOrRow );
|
||||
}
|
||||
} elseif ( is_array( $IdOrRow ) ) {
|
||||
} else if ( is_array( $IdOrRow ) ) {
|
||||
$row = $IdOrRow;
|
||||
} else {
|
||||
Error("Unknown argument passed to MontageLayout Constructor ($IdOrRow)");
|
||||
|
|
|
@ -110,23 +110,23 @@ class Storage {
|
|||
}
|
||||
public function disk_used_space() {
|
||||
# This isn't a function like this in php, so we have to add up the space used in each event.
|
||||
if ( ! array_key_exists( 'disk_used_space', $this ) ) {
|
||||
if ( ! array_key_exists( 'DiskSpace', $this ) ) {
|
||||
$used = 0;
|
||||
if ( $this->{'Type'} == 's3fs' ) {
|
||||
$used = dbFetchOne('SELECT SUM(DiskSpace) AS DiskSpace FROM Events WHERE StorageId=? AND DiskSpace IS NOT NULL', 'DiskSpace', array($this->Id()) );
|
||||
|
||||
foreach ( Event::find_all( array( 'StorageId'=>$this->Id(), 'DiskSpace'=>null ) ) as $Event ) {
|
||||
$Event->Storage( $this ); // Prevent further db hit
|
||||
$used += $Event->DiskSpace();
|
||||
}
|
||||
foreach ( Event::find_all( array( 'StorageId'=>$this->Id(), 'DiskSpace'=>null ) ) as $Event ) {
|
||||
$Event->Storage( $this ); // Prevent further db hit
|
||||
$used += $Event->DiskSpace();
|
||||
}
|
||||
} else {
|
||||
$path = $this->Path();
|
||||
$used = disk_total_space( $path ) - disk_free_space( $path );;
|
||||
$path = $this->Path();
|
||||
$used = disk_total_space( $path ) - disk_free_space( $path );;
|
||||
}
|
||||
$this->{'disk_used_space'} = $used;
|
||||
$this->{'DiskSpace'} = $used;
|
||||
}
|
||||
|
||||
return $this->{'disk_used_space'};
|
||||
return $this->{'DiskSpace'};
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -151,14 +151,16 @@ Warning("Addterm");
|
|||
if ( ! empty($_REQUEST['Id']) ) {
|
||||
dbQuery( 'DELETE FROM Filters WHERE Id=?', array( $_REQUEST['Id'] ) );
|
||||
}
|
||||
} else if ( ( $action == 'save' ) or ( $action == 'execute' ) or ( $action == 'submit' ) ) {
|
||||
} else if ( ( $action == 'Save' ) or ( $action == 'SaveAs' ) or ( $action == 'execute' ) ) {
|
||||
# or ( $action == 'submit' ) ) {
|
||||
|
||||
$sql = '';
|
||||
$_REQUEST['filter']['Query']['sort_field'] = validStr($_REQUEST['filter']['Query']['sort_field']);
|
||||
$_REQUEST['filter']['Query']['sort_asc'] = validStr($_REQUEST['filter']['Query']['sort_asc']);
|
||||
$_REQUEST['filter']['Query']['limit'] = validInt($_REQUEST['filter']['Query']['limit']);
|
||||
if ( $action == 'execute' or $action == 'submit' ) {
|
||||
$sql .= ' Name = \'_TempFilter'.time().'\'';
|
||||
if ( $action == 'execute' ) {
|
||||
$tempFilterName = '_TempFilter'.time();
|
||||
$sql .= ' Name = \''.$tempFilterName.'\'';
|
||||
} else {
|
||||
$sql .= ' Name = '.dbEscape($_REQUEST['filter']['Name']);
|
||||
}
|
||||
|
@ -175,12 +177,15 @@ Warning("Addterm");
|
|||
$sql .= ', Background = '. ( !empty($_REQUEST['filter']['Background']) ? 1 : 0);
|
||||
$sql .= ', Concurrent = '. ( !empty($_REQUEST['filter']['Concurrent']) ? 1 : 0);
|
||||
|
||||
if ( $_REQUEST['Id'] ) {
|
||||
if ( $_REQUEST['Id'] and ( $action == 'Save' ) ) {
|
||||
dbQuery( 'UPDATE Filters SET ' . $sql. ' WHERE Id=?', array($_REQUEST['Id']) );
|
||||
} else {
|
||||
dbQuery( 'INSERT INTO Filters SET' . $sql );
|
||||
$_REQUEST['Id'] = dbInsertId();
|
||||
}
|
||||
if ( $action == 'execute' ) {
|
||||
executeFilter( $tempFilterName );
|
||||
}
|
||||
|
||||
} // end if save or execute
|
||||
} // end if canEdit(Events)
|
||||
|
@ -370,6 +375,7 @@ if ( !empty($_REQUEST['mid']) && canEdit( 'Monitors', $_REQUEST['mid'] ) ) {
|
|||
dbQuery( "UPDATE Zones SET ".implode( ", ", $changes )." WHERE MonitorId=? AND Id=?", array( $mid, $zid) );
|
||||
} else {
|
||||
dbQuery( "INSERT INTO Zones SET MonitorId=?, ".implode( ", ", $changes ), array( $mid ) );
|
||||
dbQuery( 'UPDATE Monitors SET ZoneCount=(SELECT COUNT(Id) FROM Zones WHERE MonitorId=Monitors.Id) WHERE Id=?', array($mid));
|
||||
}
|
||||
//if ( $cookies ) session_write_close();
|
||||
if ( daemonCheck() ) {
|
||||
|
@ -422,6 +428,7 @@ if ( !empty($_REQUEST['mid']) && canEdit( 'Monitors', $_REQUEST['mid'] ) ) {
|
|||
foreach( $_REQUEST['markZids'] as $markZid ) {
|
||||
$zone = dbFetchOne( 'select * from Zones where Id=?', NULL, array($markZid) );
|
||||
dbQuery( 'delete from Zones WHERE MonitorId=? AND Id=?', array( $mid, $markZid) );
|
||||
dbQuery( 'UPDATE Monitors SET ZoneCount=(SELECT COUNT(Id) FROM Zones WHERE MonitorId=Monitors.Id) WHERE Id=?', array($mid));
|
||||
$deletedZid = 1;
|
||||
}
|
||||
if ( $deletedZid ) {
|
||||
|
@ -601,10 +608,10 @@ if ( canEdit( 'Monitors' ) ) {
|
|||
} // end if ZM_OPT_FAST_DELETE
|
||||
|
||||
// This is the important stuff
|
||||
dbQuery( 'DELETE FROM Monitors WHERE Id = ?', array($markMid) );
|
||||
dbQuery( 'DELETE FROM Zones WHERE MonitorId = ?', array($markMid) );
|
||||
if ( ZM_OPT_X10 )
|
||||
dbQuery( 'DELETE FROM TriggersX10 WHERE MonitorId=?', array($markMid) );
|
||||
dbQuery( 'DELETE FROM Monitors WHERE Id = ?', array($markMid) );
|
||||
|
||||
fixSequences();
|
||||
|
||||
|
|
|
@ -189,21 +189,21 @@ function csrf_check($fatal = true) {
|
|||
$tokens = '';
|
||||
do {
|
||||
if (!isset($_POST[$name])) {
|
||||
Logger::Debug("POST[$name] is not set");
|
||||
#Logger::Debug("POST[$name] is not set");
|
||||
break;
|
||||
} else {
|
||||
Logger::Debug("POST[$name] is set as " . $_POST[$name] );
|
||||
#} else {
|
||||
#Logger::Debug("POST[$name] is set as " . $_POST[$name] );
|
||||
|
||||
}
|
||||
// we don't regenerate a token and check it because some token creation
|
||||
// schemes are volatile.
|
||||
$tokens = $_POST[$name];
|
||||
if (!csrf_check_tokens($tokens)) {
|
||||
Logger::Debug("Failed checking tokens");
|
||||
#Logger::Debug("Failed checking tokens");
|
||||
break;
|
||||
|
||||
} else {
|
||||
Logger::Debug("Token passed");
|
||||
#} else {
|
||||
#Logger::Debug("Token passed");
|
||||
}
|
||||
$ok = true;
|
||||
} while (false);
|
||||
|
@ -308,27 +308,27 @@ function csrf_check_tokens($tokens) {
|
|||
* Checks if a token is valid.
|
||||
*/
|
||||
function csrf_check_token($token) {
|
||||
Logger::Debug("Checking CSRF token $token");
|
||||
#Logger::Debug("Checking CSRF token $token");
|
||||
if (strpos($token, ':') === false) {
|
||||
Logger::Debug("Checking CSRF token $token bad because no :");
|
||||
#Logger::Debug("Checking CSRF token $token bad because no :");
|
||||
return false;
|
||||
}
|
||||
list($type, $value) = explode(':', $token, 2);
|
||||
if (strpos($value, ',') === false) {
|
||||
Logger::Debug("Checking CSRF token $token bad because no ,");
|
||||
#Logger::Debug("Checking CSRF token $token bad because no ,");
|
||||
return false;
|
||||
}
|
||||
list($x, $time) = explode(',', $token, 2);
|
||||
if ($GLOBALS['csrf']['expires']) {
|
||||
if (time() > $time + $GLOBALS['csrf']['expires']) {
|
||||
Logger::Debug("Checking CSRF token $token bad because expired");
|
||||
#Logger::Debug("Checking CSRF token $token bad because expired");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
switch ($type) {
|
||||
case 'sid':
|
||||
{
|
||||
Logger::Debug("Checking sid: $value === " . csrf_hash(session_id(), $time) );
|
||||
#Logger::Debug("Checking sid: $value === " . csrf_hash(session_id(), $time) );
|
||||
return $value === csrf_hash(session_id(), $time);
|
||||
}
|
||||
case 'cookie':
|
||||
|
@ -341,7 +341,7 @@ return false;
|
|||
Logger::Debug("Checking key: no key set" );
|
||||
return false;
|
||||
}
|
||||
Logger::Debug("Checking sid: $value === " . csrf_hash($GLOBALS['csrf']['key'], $time) );
|
||||
#Logger::Debug("Checking sid: $value === " . csrf_hash($GLOBALS['csrf']['key'], $time) );
|
||||
return $value === csrf_hash($GLOBALS['csrf']['key'], $time);
|
||||
// We could disable these 'weaker' checks if 'key' was set, but
|
||||
// that doesn't make me feel good then about the cookie-based
|
||||
|
|
|
@ -134,7 +134,7 @@ function dbQuery( $sql, $params=NULL ) {
|
|||
} else {
|
||||
$result = $dbConn->query( $sql );
|
||||
}
|
||||
if ( 0 ) {
|
||||
if ( 1 ) {
|
||||
if ( $params )
|
||||
Warning("SQL: $sql" . implode(',',$params) . ' rows: '.$result->rowCount() );
|
||||
else
|
||||
|
|
|
@ -28,13 +28,13 @@ if ( version_compare( phpversion(), '4.3.0', '<') ) {
|
|||
}
|
||||
|
||||
# We are requiring these because this file is getting included from the api, which hasn't already included them.
|
||||
require_once( 'logger.php' );
|
||||
require_once( 'database.php' );
|
||||
require_once('logger.php');
|
||||
require_once('database.php');
|
||||
|
||||
function userLogin( $username, $password='', $passwordHashed=false ) {
|
||||
global $user, $cookies;
|
||||
|
||||
$sql = 'SELECT * FROM Users WHERE Enabled = 1';
|
||||
$sql = 'SELECT * FROM Users WHERE Enabled=1';
|
||||
$sql_values = NULL;
|
||||
if ( ZM_AUTH_TYPE == 'builtin' ) {
|
||||
if ( $passwordHashed ) {
|
||||
|
@ -44,7 +44,7 @@ function userLogin( $username, $password='', $passwordHashed=false ) {
|
|||
}
|
||||
$sql_values = array( $username, $password );
|
||||
} else {
|
||||
$sql .= ' AND Username = ?';
|
||||
$sql .= ' AND Username=?';
|
||||
$sql_values = array( $username );
|
||||
}
|
||||
$_SESSION['username'] = $username;
|
||||
|
@ -138,26 +138,27 @@ function getAuthUser( $auth ) {
|
|||
$authHash = md5( $authKey );
|
||||
|
||||
if ( $auth == $authHash ) {
|
||||
return( $user );
|
||||
return $user;
|
||||
}
|
||||
} // end foreach hour
|
||||
} // end foreach user
|
||||
} // end if using auth hash
|
||||
Error( "Unable to authenticate user from auth hash '$auth'" );
|
||||
return( false );
|
||||
}
|
||||
} // end getAuthUser($auth)
|
||||
|
||||
function generateAuthHash( $useRemoteAddr ) {
|
||||
if ( ZM_OPT_USE_AUTH and ZM_AUTH_RELAY == 'hashed' and isset($_SESSION['username']) and $_SESSION['passwordHash'] ) {
|
||||
# regenerate a hash at half the liftetime of a hash, an hour is 3600 so half is 1800
|
||||
if ( ( ! isset($_SESSION['AuthHash']) ) or ( $_SESSION['AuthHashGeneratedAt'] < time() - ( ZM_AUTH_HASH_TTL * 1800 ) ) ) {
|
||||
$time = time();
|
||||
if ( ( ! isset($_SESSION['AuthHash']) ) or ( $_SESSION['AuthHashGeneratedAt'] < ( $time - ( ZM_AUTH_HASH_TTL * 1800 ) ) ) ) {
|
||||
# Don't both regenerating Auth Hash if an hour hasn't gone by yet
|
||||
$time = localtime();
|
||||
$local_time = localtime();
|
||||
$authKey = '';
|
||||
if ( $useRemoteAddr ) {
|
||||
$authKey = ZM_AUTH_HASH_SECRET.$_SESSION['username'].$_SESSION['passwordHash'].$_SESSION['remoteAddr'].$time[2].$time[3].$time[4].$time[5];
|
||||
$authKey = ZM_AUTH_HASH_SECRET.$_SESSION['username'].$_SESSION['passwordHash'].$_SESSION['remoteAddr'].$local_time[2].$local_time[3].$local_time[4].$local_time[5];
|
||||
} else {
|
||||
$authKey = ZM_AUTH_HASH_SECRET.$_SESSION['username'].$_SESSION['passwordHash'].$time[2].$time[3].$time[4].$time[5];
|
||||
$authKey = ZM_AUTH_HASH_SECRET.$_SESSION['username'].$_SESSION['passwordHash'].$local_time[2].$local_time[3].$local_time[4].$local_time[5];
|
||||
}
|
||||
$auth = md5( $authKey );
|
||||
if ( session_status() == PHP_SESSION_NONE ) {
|
||||
|
@ -167,10 +168,10 @@ function generateAuthHash( $useRemoteAddr ) {
|
|||
Warning("Session is not active. AuthHash will not be cached. called from $file:$line");
|
||||
}
|
||||
$_SESSION['AuthHash'] = $auth;
|
||||
$_SESSION['AuthHashGeneratedAt'] = time();
|
||||
$_SESSION['AuthHashGeneratedAt'] = $time;
|
||||
Logger::Debug("Generated new auth $auth at " . $_SESSION['AuthHashGeneratedAt']. " using $authKey" );
|
||||
} else {
|
||||
Logger::Debug( "Using cached auth " . $_SESSION['AuthHash'] );
|
||||
Logger::Debug( "Using cached auth " . $_SESSION['AuthHash'] ." beacuse " . $_SESSION['AuthHashGeneratedAt'] . ' < '. $time . ' - ' . ZM_AUTH_HASH_TTL . ' * 1800 = '.( $time - (ZM_AUTH_HASH_TTL * 1800) ));
|
||||
} # end if AuthHash is not cached
|
||||
return $_SESSION['AuthHash'];
|
||||
} else {
|
||||
|
@ -347,7 +348,7 @@ function getImageStreamHTML( $id, $src, $width, $height, $title='' ) {
|
|||
if ( canStreamIframe() ) {
|
||||
return '<iframe id="'.$id.'" src="'.$src.'" alt="'. validHtmlStr($title) .'" '.($width? ' width="'. validInt($width).'"' : '').($height?' height="'.validInt($height).'"' : '' ).'/>';
|
||||
} else {
|
||||
return '<img id="'.$id.'" src="'.$src.'" alt="'. validHtmlStr($title) .'" style="'.($width? ' width:'. validInt($width) .'px;': '').($height ? ' height:'. validInt( $height ).'px;':'').'"/>';
|
||||
return '<img id="'.$id.'" src="'.$src.'" alt="'. validHtmlStr($title) .'" style="'.($width? ' width:'.$width.';' : '' ).($height ? ' height:'. $height.';' : '' ).'"/>';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1449,6 +1450,66 @@ function getDiskBlocks() {
|
|||
return( $space );
|
||||
}
|
||||
|
||||
function systemStats() {
|
||||
|
||||
$load = getLoad();
|
||||
$diskPercent = getDiskPercent();
|
||||
$pathMapPercent = getDiskPercent(ZM_PATH_MAP);
|
||||
$cpus = getcpus();
|
||||
|
||||
$normalized_load = $load / $cpus;
|
||||
|
||||
# Colorize the system load stat
|
||||
if ( $normalized_load <= 0.75 ) {
|
||||
$htmlLoad=$load;
|
||||
} elseif ( $normalized_load <= 0.9 ) {
|
||||
$htmlLoad="<span class=\"warning\">$load</span>";
|
||||
} elseif ( $normalized_load <= 1.1 ) {
|
||||
$htmlLoad="<span class=\"error\">$load</span>";
|
||||
} else {
|
||||
$htmlLoad="<span class=\"critical\">$load</span>";
|
||||
}
|
||||
|
||||
# Colorize the disk space stat
|
||||
if ( $diskPercent < 98 ) {
|
||||
$htmlDiskPercent="$diskPercent%";
|
||||
} elseif ( $diskPercent <= 99 ) {
|
||||
$htmlDiskPercent="<span class=\"warning\">$diskPercent%</span>";
|
||||
} else {
|
||||
$htmlDiskPercent="<span class=\"error\">$diskPercent%</span>";
|
||||
}
|
||||
|
||||
# Colorize the PATH_MAP (usually /dev/shm) stat
|
||||
if ( $pathMapPercent < 90 ) {
|
||||
if ( disk_free_space(ZM_PATH_MAP) > 209715200 ) { # have to always have at least 200MiB free
|
||||
$htmlPathMapPercent="$pathMapPercent%";
|
||||
} else {
|
||||
$htmlPathMapPercent="<span class=\"warning\">$pathMapPercent%</span>";
|
||||
}
|
||||
} elseif ( $pathMapPercent < 100 ) {
|
||||
$htmlPathMapPercent="<span class=\"warning\">$pathMapPercent%</span>";
|
||||
} else {
|
||||
$htmlPathMapPercent="<span class=\"critical\">$pathMapPercent%</span>";
|
||||
}
|
||||
|
||||
$htmlString = translate('Load').": $htmlLoad - ".translate('Disk').": $htmlDiskPercent - ".ZM_PATH_MAP.": $htmlPathMapPercent";
|
||||
|
||||
return( $htmlString );
|
||||
}
|
||||
|
||||
function getcpus() {
|
||||
|
||||
if (is_readable("/proc/cpuinfo") ) { # Works on Linux
|
||||
preg_match_all('/^processor/m', file_get_contents('/proc/cpuinfo'), $matches);
|
||||
$num_cpus = count($matches[0]);
|
||||
} else { # Works on BSD
|
||||
$matches = explode(":", shell_exec("sysctl hw.ncpu"));
|
||||
$num_cpus = trim($matches[1]);
|
||||
}
|
||||
|
||||
return( $num_cpus );
|
||||
}
|
||||
|
||||
// Function to fix a problem whereby the built in PHP session handling
|
||||
// features want to put the sid as a hidden field after the form or
|
||||
// fieldset tag, neither of which will work with strict XHTML Basic.
|
||||
|
@ -2076,7 +2137,7 @@ function cache_bust( $file ) {
|
|||
# Use the last modified timestamp to create a link that gets a different filename
|
||||
# To defeat caching. Should probably use md5 hash
|
||||
$parts = pathinfo($file);
|
||||
$cacheFile = 'cache/'.$parts['filename'].'-'.filemtime($file).'.'.$parts['extension'];
|
||||
$cacheFile = 'cache/'.$parts['filename'].'-'.$_COOKIE['zmCSS'].'-'.filemtime($file).'.'.$parts['extension'];
|
||||
if ( file_exists( ZM_PATH_WEB.'/'.$cacheFile ) or symlink( ZM_PATH_WEB.'/'.$file, ZM_PATH_WEB.'/'.$cacheFile ) ) {
|
||||
return $cacheFile;
|
||||
} else {
|
||||
|
@ -2151,16 +2212,18 @@ function getStreamHTML( $monitor, $options = array() ) {
|
|||
|
||||
if ( isset($options['scale']) and $options['scale'] and ( $options['scale'] != 100 ) ) {
|
||||
//Warning("Scale to " . $options['scale'] );
|
||||
$options['width'] = reScale( $monitor->Width(), $options['scale'] );
|
||||
$options['height'] = reScale( $monitor->Height(), $options['scale'] );
|
||||
$options['width'] = reScale( $monitor->Width(), $options['scale'] ) . 'px';
|
||||
$options['height'] = reScale( $monitor->Height(), $options['scale'] ) . 'px';
|
||||
} else {
|
||||
# scale is empty or 100
|
||||
# There may be a fixed width applied though, in which case we need to leave the height empty
|
||||
if ( ! ( isset($options['width']) and $options['width'] ) ) {
|
||||
$options['width'] = $monitor->Width();
|
||||
$options['width'] = $monitor->Width() . 'px';
|
||||
if ( ! ( isset($options['height']) and $options['height'] ) ) {
|
||||
$options['height'] = $monitor->Height();
|
||||
$options['height'] = $monitor->Height() . 'px';
|
||||
}
|
||||
} else if ( ! isset($options['height']) ) {
|
||||
$options['height'] = '';
|
||||
}
|
||||
}
|
||||
if ( ! isset($options['mode'] ) ) {
|
||||
|
@ -2213,6 +2276,7 @@ function getStreamMode( ) {
|
|||
$streamMode = 'single';
|
||||
Info( 'The system has fallen back to single jpeg mode for streaming. Consider enabling Cambozola or upgrading the client browser.' );
|
||||
}
|
||||
return $streamMode;
|
||||
} // end function getStreamMode
|
||||
|
||||
function folder_size($dir) {
|
||||
|
|
|
@ -37,7 +37,7 @@ function loadLanguage( $prefix="" )
|
|||
$fallbackLangFile = $prefix.'lang/en_gb.php';
|
||||
$systemLangFile = $prefix.'lang/'.ZM_LANG_DEFAULT.'.php';
|
||||
if ( isset($user['Language']) )
|
||||
$userLangFile = $prefix.$user['Language'].'.php';
|
||||
$userLangFile = $prefix.'lang/'.$user['Language'].'.php';
|
||||
|
||||
if ( isset($userLangFile) && file_exists( $userLangFile ) )
|
||||
return( $userLangFile );
|
||||
|
|
|
@ -34,7 +34,7 @@ if ( version_compare( phpversion(), '4.1.0', '<') ) {
|
|||
}
|
||||
|
||||
// Useful debugging lines for mobile devices
|
||||
if ( true ) {
|
||||
if ( false ) {
|
||||
ob_start();
|
||||
phpinfo( INFO_VARIABLES );
|
||||
$fp = fopen( '/tmp/env.html', 'w' );
|
||||
|
@ -195,7 +195,7 @@ isset($action) || $action = NULL;
|
|||
|
||||
if ( ZM_ENABLE_CSRF_MAGIC && $action != 'login' && $view != 'view_video' && $view != 'video' && $request != 'control' && $view != 'frames') {
|
||||
require_once( 'includes/csrf/csrf-magic.php' );
|
||||
Logger::Debug("Calling csrf_check with the following values: \$request = \"$request\", \$view = \"$view\", \$action = \"$action\"");
|
||||
#Logger::Debug("Calling csrf_check with the following values: \$request = \"$request\", \$view = \"$view\", \$action = \"$action\"");
|
||||
csrf_check();
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,10 @@ function logReport( level, message, file, line )
|
|||
|
||||
if ( !debugReq )
|
||||
{
|
||||
debugParms = "view=request&request=log&task=create&browser[name]="+Browser.name+"&browser[version]="+Browser.version+"&browser[platform]="+Browser.Platform.name;
|
||||
if ( Browser )
|
||||
debugParms = "view=request&request=log&task=create&browser[name]="+Browser.name+"&browser[version]="+Browser.version+"&browser[platform]="+(Browser.Platform?Browser.Platform.name:'unknown');
|
||||
else
|
||||
debugParms = "view=request&request=log&task=create&browser[name]=unknown&browser[version]=unknown&browser[platform]=unknown";
|
||||
debugReq = new Request.JSON( { url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'chain' } );
|
||||
}
|
||||
var requestParms = debugParms;
|
||||
|
|
|
@ -322,6 +322,8 @@ $SLANG = array(
|
|||
'ExportDetails' => 'Export Event Details',
|
||||
'Exif' => 'Embed EXIF data into image',
|
||||
'Export' => 'Export',
|
||||
'DownloadVideo' => 'Download Video',
|
||||
'GenerateDownload' => 'Generate Download',
|
||||
'ExportFailed' => 'Export Failed',
|
||||
'ExportFormat' => 'Export File Format',
|
||||
'ExportFormatTar' => 'Tar',
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
/*
|
||||
* ZoneMinder Base Stylesheet, $Date$, $Revision$
|
||||
* Copyright (C) 2001-2008 Philip Coombes
|
||||
|
@ -95,9 +96,6 @@ input.noborder {
|
|||
border: 0;
|
||||
}
|
||||
|
||||
input[disabled] {
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
img {
|
||||
display: inline-block;
|
||||
|
@ -349,9 +347,11 @@ th.table-th-sort-rev span.table-th-sort-span {
|
|||
|
||||
#header {
|
||||
width: 100%;
|
||||
line-height: 24px;
|
||||
margin: 8px auto;
|
||||
margin: 0 auto 4px auto;
|
||||
line-height: 1;
|
||||
text-align: left;
|
||||
padding: 3px 0;
|
||||
border-bottom: 1px solid #555555;
|
||||
}
|
||||
|
||||
#header h2 {
|
||||
|
@ -381,7 +381,7 @@ th.table-th-sort-rev span.table-th-sort-span {
|
|||
|
||||
#content {
|
||||
width: 96%;
|
||||
margin: 8px auto;
|
||||
margin: 0 auto 8px auto;
|
||||
line-height: 130%;
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -407,11 +407,15 @@ th.table-th-sort-rev span.table-th-sort-span {
|
|||
}
|
||||
*/
|
||||
|
||||
#content > input[type=submit], #content > input[type=button], #content > button {
|
||||
#content > input[type=submit],
|
||||
#content > input[type=button],
|
||||
#content > button {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
#content table input[type=submit], #content table input[type=button], #content table button {
|
||||
#content table input[type=submit],
|
||||
#content table input[type=button],
|
||||
#content table button {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
|
@ -420,6 +424,7 @@ th.table-th-sort-rev span.table-th-sort-span {
|
|||
float: right;
|
||||
}
|
||||
|
||||
#contentButtons button,
|
||||
#contentButtons input {
|
||||
margin-left: 8px;
|
||||
margin-bottom: 4px;
|
||||
|
@ -487,3 +492,36 @@ margin-left: 0px;
|
|||
.nav-pills > li > a {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button,
|
||||
input[type=button],
|
||||
input[type=submit] {
|
||||
padding: 1px 6px;
|
||||
/*
|
||||
background-color: #3498db;
|
||||
color: #fff;
|
||||
border-color: #3498db;
|
||||
font-weight: 200;
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
*/
|
||||
}
|
||||
|
||||
button:hover,
|
||||
input[type=button]:hover,
|
||||
input[type=submit]:hover {
|
||||
/*
|
||||
background-color: #34a2ee;
|
||||
*/
|
||||
}
|
||||
|
||||
button:disabled,
|
||||
input[disabled],
|
||||
input[type=button]:disabled,
|
||||
input[type=submit]:disabled {
|
||||
color: #888888;
|
||||
/*
|
||||
background-color: #aaaaaa;
|
||||
*/
|
||||
border-color: #bbbbbb;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,19 @@
|
|||
float: right;
|
||||
}
|
||||
|
||||
#systemStats .warning {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
#systemStats .error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#systemStats .critical {
|
||||
color: red;
|
||||
text-decoration: blink;
|
||||
}
|
||||
|
||||
#monitorSummary {
|
||||
float: left;
|
||||
text-align: left;
|
||||
|
|
|
@ -12,108 +12,64 @@
|
|||
|
||||
.alarmCue {
|
||||
background-color: #222222;
|
||||
height: 1.5em;
|
||||
height: 1.25em;
|
||||
text-align: left;
|
||||
margin: 0 auto 0 auto;
|
||||
border-radius: 0 0 .3em .3em;
|
||||
}
|
||||
|
||||
.alarmCue span {
|
||||
background-color:red;
|
||||
height: 1.5em;
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
span.noneCue {
|
||||
background: none;
|
||||
}
|
||||
|
||||
#header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#header h2, #header a {
|
||||
line-height: 1.1;
|
||||
margin:5px 0 0 0;
|
||||
}
|
||||
|
||||
#dataBar {
|
||||
width: 100%;
|
||||
margin: 2px auto;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-wrap:wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#dataBar #dataTable {
|
||||
#menuBar1 {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
margin: 4px 0 0 0;
|
||||
}
|
||||
|
||||
#dataBar #dataTable td {
|
||||
text-align: center;
|
||||
padding: 2px;
|
||||
#menuBar1 #replayControl {
|
||||
margin: 0 4px 0 auto;
|
||||
}
|
||||
|
||||
#menuBar1 div {
|
||||
margin: auto 5px;
|
||||
}
|
||||
|
||||
#nameControl input[type="button"]{
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#eventVideo {
|
||||
display: inline-block;
|
||||
postion: relative;
|
||||
}
|
||||
|
||||
#menuBar1 {
|
||||
width: 100%;
|
||||
padding: 3px 0;
|
||||
text-align: center;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#menuBar1 #nameControl {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#menuBar1 #nameControl #eventName {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
#menuBar1 #replayControl {
|
||||
float: right;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
#menuBar1 #scaleControl {
|
||||
float: right;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
#menuBar2 {
|
||||
width: 100%;
|
||||
padding: 3px 0;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
#menuBar2 div {
|
||||
text-align: left;
|
||||
float: left;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
#menuBar2 #closeWindow {
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#menuBar1:after,
|
||||
#menuBar2:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
height: 0;
|
||||
font-size: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#videoBar1 div {
|
||||
text-align: center;
|
||||
float: center;
|
||||
}
|
||||
|
||||
#videoBar1 #prevEvent {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#videoBar1 #dlEvent {
|
||||
float: center;
|
||||
}
|
||||
|
||||
#videoBar1 #nextEvent {
|
||||
float: right;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#imageFeed {
|
||||
|
@ -142,32 +98,32 @@ span.noneCue {
|
|||
#monitorStatus #monitorState {
|
||||
}
|
||||
|
||||
.dvrControls {
|
||||
#dvrControls {
|
||||
margin-top: 3px;
|
||||
margin-bottom: 2px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dvrControls input {
|
||||
height: 20px;
|
||||
width: 28px;
|
||||
padding-bottom: 3px;
|
||||
#dvrControls input {
|
||||
height: 1.5em;
|
||||
width: 2em;
|
||||
padding: 0 ;
|
||||
margin: 0 3px;
|
||||
}
|
||||
|
||||
.dvrControls input[disabled=disabled] {
|
||||
#dvrControls input[disabled=disabled] {
|
||||
color: #aaaaaa;
|
||||
}
|
||||
|
||||
.dvrControls input.active {
|
||||
#dvrControls input.active {
|
||||
border: 1px solid blue;
|
||||
}
|
||||
|
||||
.dvrControls input.inactive {
|
||||
#dvrControls input.inactive {
|
||||
border: 1px solid green;
|
||||
}
|
||||
|
||||
.dvrControls input.unavail {
|
||||
#dvrControls input.unavail {
|
||||
border: 1px solid red;
|
||||
}
|
||||
|
||||
|
@ -183,31 +139,29 @@ span.noneCue {
|
|||
|
||||
#progressBar {
|
||||
position: relative;
|
||||
top: -1.5em;
|
||||
height: 1.5em;
|
||||
margin: 0 auto -1.5em auto;
|
||||
top: -1.25em;
|
||||
height: 1.25em;
|
||||
margin: 0 auto -1.25em auto;
|
||||
}
|
||||
|
||||
#progressBar .progressBox {
|
||||
height: 1.5em;
|
||||
transition: width .1s;
|
||||
height: 100%;
|
||||
background: rgba(170, 170, 170, .7);
|
||||
border-radius: 0 0 .3em .3em;
|
||||
}
|
||||
|
||||
#eventStills {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#eventThumbsPanel {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
margin: 4px auto;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#eventThumbs {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
height: 300px;
|
||||
}
|
||||
|
@ -226,14 +180,19 @@ span.noneCue {
|
|||
}
|
||||
|
||||
#eventImagePanel {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#eventImageFrame {
|
||||
border: 2px solid gray;
|
||||
background-color: white;
|
||||
padding: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#eventImage {
|
||||
|
@ -243,6 +202,14 @@ span.noneCue {
|
|||
margin-top: 2px;
|
||||
}
|
||||
|
||||
#eventImageBar::after {
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
content: "";
|
||||
clear: both;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
#eventImageStats {
|
||||
float: left;
|
||||
}
|
||||
|
@ -258,6 +225,7 @@ span.noneCue {
|
|||
|
||||
#eventImageNav {
|
||||
position: relative;
|
||||
margin: 0 0 4px 0;
|
||||
}
|
||||
|
||||
#eventImageNav input {
|
||||
|
@ -266,20 +234,20 @@ span.noneCue {
|
|||
}
|
||||
|
||||
#thumbsSliderPanel {
|
||||
width: 400px;
|
||||
margin: 4px auto 0;
|
||||
background: #888888;
|
||||
padding: 1px;
|
||||
width: 80%;
|
||||
margin: 0px auto 4px auto;
|
||||
}
|
||||
|
||||
#thumbsSlider {
|
||||
width: 400px;
|
||||
height: 10px;
|
||||
background: #dddddd;
|
||||
width: 100%;
|
||||
height: 1.25em;
|
||||
position: relative;
|
||||
top: -1.25em;
|
||||
margin: 0 0 -1.25em 0;
|
||||
}
|
||||
|
||||
#thumbsKnob {
|
||||
width: 8px;
|
||||
height: 10px;
|
||||
background-color: #444444;
|
||||
width: 1em;
|
||||
height: 100%;
|
||||
background-color: #999999;
|
||||
}
|
||||
|
|
|
@ -1,31 +1,5 @@
|
|||
#controls {
|
||||
height: 16px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#controls a {
|
||||
width: 32%;
|
||||
}
|
||||
|
||||
#controls #refreshLink {
|
||||
position: absolute;
|
||||
left: 0%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#controls #filterLink {
|
||||
position: absolute;
|
||||
left: 34%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#controls #timelineLink {
|
||||
position: absolute;
|
||||
left: 68%;
|
||||
text-align: right;
|
||||
.archived {
|
||||
background-color: #f8f8f8;;
|
||||
}
|
||||
|
||||
#contentTable.major .colTime {
|
||||
|
@ -40,3 +14,26 @@
|
|||
text-align: right;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
#header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#header h2, #header a {
|
||||
line-height: 1.1;
|
||||
margin:5px 0 0 0;
|
||||
}
|
||||
|
||||
#header #info, #header #pagination, #header #controls {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#header #controls {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
#header #pagination {
|
||||
align-items: center;
|
||||
}
|
||||
|
|
|
@ -31,3 +31,7 @@ table.filterTable {
|
|||
width: 300px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
input#filter\[Name\] {
|
||||
width: 400px;
|
||||
}
|
||||
|
|
|
@ -1,33 +1,16 @@
|
|||
#scaleControl {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#controls {
|
||||
width: 80%;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#controls a {
|
||||
width: 40px;
|
||||
margin-left: -20px;
|
||||
}
|
||||
|
||||
#firstLink {
|
||||
position: absolute;
|
||||
left: 13%;
|
||||
}
|
||||
|
||||
#prevLink {
|
||||
position: absolute;
|
||||
left: 37%;
|
||||
}
|
||||
|
||||
#nextLink {
|
||||
position: absolute;
|
||||
left: 63%;
|
||||
}
|
||||
|
||||
#lastLink {
|
||||
position: absolute;
|
||||
left: 87%;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
|
||||
#monitors .alert {
|
||||
color: #ffa500;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#monitors .imageFeed {
|
||||
|
|
|
@ -36,3 +36,7 @@
|
|||
input[type=range]::-ms-tooltip {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#downloadVideo {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,25 @@
|
|||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#header h2, #header a {
|
||||
line-height: 1.1;
|
||||
margin:5px 0 0 0;
|
||||
}
|
||||
|
||||
#header #info, #header #headerButtons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#header #headerButtons {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
#title {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
|
@ -15,20 +34,6 @@
|
|||
line-height: 20px;
|
||||
}
|
||||
|
||||
#listLink {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 20px;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
#closeLink {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 20px;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
#topPanel {
|
||||
position: relative;
|
||||
height: 220px;
|
||||
|
|
|
@ -1,37 +1,17 @@
|
|||
@import url(../control.css);
|
||||
|
||||
#menuBar {
|
||||
margin: 6px auto 4px;
|
||||
text-align: center;
|
||||
#header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#menuBar #monitorName {
|
||||
float: left;
|
||||
#menuControls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#menuBar #closeControl {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#menuBar #menuControls {
|
||||
margin: 0 auto;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
#menuBar #menuControls #controlControl {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#menuBar #menuControls #eventsControl {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#menuBar #menuControls #settingsControl {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#menuBar #menuControls #scaleControl {
|
||||
margin: 0 auto;
|
||||
#menuControls div {
|
||||
margin: 0 0 0 1em;
|
||||
}
|
||||
|
||||
#imageFeed{
|
||||
|
|
|
@ -108,9 +108,6 @@ input.noborder {
|
|||
border: 0;
|
||||
}
|
||||
|
||||
input[disabled] {
|
||||
color: #777777;
|
||||
}
|
||||
|
||||
img {
|
||||
display: inline-block;
|
||||
|
@ -376,11 +373,12 @@ th.table-th-sort-rev span.table-th-sort-span {
|
|||
|
||||
#header {
|
||||
width: 100%;
|
||||
line-height: 24px;
|
||||
line-height: 1;
|
||||
text-align: left;
|
||||
margin-bottom: 10px;
|
||||
padding: 10px 20px;
|
||||
padding: 5px 20px;
|
||||
margin: 0 auto 4px auto;
|
||||
font-weight: 300;
|
||||
border-bottom: 1px solid #000000;
|
||||
}
|
||||
|
||||
#header h2 {
|
||||
|
@ -410,7 +408,7 @@ th.table-th-sort-rev span.table-th-sort-span {
|
|||
|
||||
#content {
|
||||
width: 96%;
|
||||
margin: 8px auto;
|
||||
margin: 0 auto 8px auto;
|
||||
line-height: 130%;
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -449,6 +447,7 @@ th.table-th-sort-rev span.table-th-sort-span {
|
|||
float: right;
|
||||
}
|
||||
|
||||
#contentButtons button,
|
||||
#contentButtons input {
|
||||
margin-left: 8px;
|
||||
margin-bottom: 4px;
|
||||
|
@ -459,31 +458,34 @@ th.table-th-sort-rev span.table-th-sort-span {
|
|||
margin: 8px auto;
|
||||
}
|
||||
|
||||
button,
|
||||
input[type=button],
|
||||
input[type=submit] {
|
||||
background-color: #3498db;
|
||||
color: #fff;
|
||||
border-color: #3498db;
|
||||
text-transform: uppercase;
|
||||
font-weight: 200;
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
background-color: #444444;
|
||||
color: #eeeeee;
|
||||
border-color: #444444;
|
||||
text-transform: uppercase;
|
||||
font-weight: 200;
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover,
|
||||
input[type=button]:hover,
|
||||
input[type=submit]:hover {
|
||||
background-color: #34a2ee;
|
||||
|
||||
background-color: #555555;
|
||||
}
|
||||
|
||||
|
||||
/* PP - make it easy to identify disabled buttons */
|
||||
|
||||
button:disabled,
|
||||
input[disabled],
|
||||
input[type=button]:disabled,
|
||||
input[type=submit]:disabled {
|
||||
background-color: #aaaaaa;
|
||||
border-color: #bbbbbb;
|
||||
|
||||
color: #888888;
|
||||
background-color: #666666;
|
||||
border-color: #666666;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -518,7 +520,6 @@ input[type=submit]:disabled {
|
|||
.sidebar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
display: block;
|
||||
|
@ -534,8 +535,10 @@ input[type=submit]:disabled {
|
|||
margin-left: 0;
|
||||
}
|
||||
|
||||
|
||||
.table-striped > tbody > tr:nth-of-type(2n+1) {
|
||||
background: none;
|
||||
background-color: #333333;
|
||||
}
|
||||
|
||||
.table-hover>tbody>tr:hover {
|
||||
background-color: #444444;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,19 @@
|
|||
float: right;
|
||||
}
|
||||
|
||||
#systemStats .warning {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
#systemStats .error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#systemStats .critical {
|
||||
color: red;
|
||||
text-decoration: blink;
|
||||
}
|
||||
|
||||
#monitorSummary {
|
||||
float: left;
|
||||
text-align: left;
|
||||
|
|
|
@ -12,90 +12,63 @@
|
|||
|
||||
.alarmCue {
|
||||
background-color: #222222;
|
||||
height: 1.5em;
|
||||
height: 1.25em;
|
||||
text-align: left;
|
||||
margin: 0 auto 0 auto;
|
||||
border-radius: 0 0 .3em .3em;
|
||||
}
|
||||
|
||||
.alarmCue span {
|
||||
background-color:red;
|
||||
height: 1.5em;
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
span.noneCue {
|
||||
background: none;
|
||||
}
|
||||
|
||||
#eventVideo {
|
||||
display: inline-block;
|
||||
#header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#header h2, #header a {
|
||||
line-height: 1.1;
|
||||
margin:5px 0 0 0;
|
||||
}
|
||||
|
||||
#dataBar {
|
||||
width: 100%;
|
||||
margin: 2px auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#dataBar #dataTable {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#dataBar #dataTable td {
|
||||
text-align: center;
|
||||
padding: 2px;
|
||||
display: flex;
|
||||
flex-wrap:wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#menuBar1 {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
padding: 3px 0;
|
||||
text-align: center;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#menuBar1 #nameControl {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#menuBar1 #nameControl #eventName {
|
||||
margin-right: 4px;
|
||||
margin: 4px 0 0 0;
|
||||
}
|
||||
|
||||
#menuBar1 #replayControl {
|
||||
float: right;
|
||||
margin-left: 8px;
|
||||
margin: 0 4px 0 auto;
|
||||
}
|
||||
|
||||
#menuBar1 #scaleControl {
|
||||
float: right;
|
||||
margin-left: 8px;
|
||||
#menuBar1 div {
|
||||
margin: auto 5px;
|
||||
}
|
||||
|
||||
#menuBar2 {
|
||||
width: 100%;
|
||||
padding: 3px 0;
|
||||
margin-bottom: 4px;
|
||||
#nameControl input[type="button"]{
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#menuBar2 div {
|
||||
text-align: left;
|
||||
float: left;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
#menuBar2 #closeWindow {
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#menuBar1:after,
|
||||
#menuBar2:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
height: 0;
|
||||
font-size: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
#eventVideo {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#imageFeed {
|
||||
|
@ -124,32 +97,32 @@ span.noneCue {
|
|||
#monitorStatus #monitorState {
|
||||
}
|
||||
|
||||
.dvrControls {
|
||||
#dvrControls {
|
||||
margin-top: 3px;
|
||||
margin-bottom: 2px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dvrControls input {
|
||||
height: 20px;
|
||||
width: 28px;
|
||||
padding-bottom: 3px;
|
||||
#dvrControls input {
|
||||
height: 1.5em;
|
||||
width: 2em;
|
||||
padding: 0;
|
||||
margin: 0 3px;
|
||||
}
|
||||
|
||||
.dvrControls input[disabled=disabled] {
|
||||
#dvrControls input[disabled=disabled] {
|
||||
color: #aaaaaa;
|
||||
}
|
||||
|
||||
.dvrControls input.active {
|
||||
#dvrControls input.active {
|
||||
border: 1px solid blue;
|
||||
}
|
||||
|
||||
.dvrControls input.inactive {
|
||||
#dvrControls input.inactive {
|
||||
border: 1px solid green;
|
||||
}
|
||||
|
||||
.dvrControls input.unavail {
|
||||
#dvrControls input.unavail {
|
||||
border: 1px solid red;
|
||||
}
|
||||
|
||||
|
@ -165,31 +138,30 @@ span.noneCue {
|
|||
|
||||
#progressBar {
|
||||
position: relative;
|
||||
top: -1.5em;
|
||||
height: 1.5em;
|
||||
margin: 0 auto -1.5em auto;
|
||||
top: -1.25em;
|
||||
height: 1.25em;
|
||||
margin: 0 auto -1.25em auto;
|
||||
}
|
||||
|
||||
#progressBar .progressBox {
|
||||
height: 1.5em;
|
||||
transition: width .1s;
|
||||
height: 100%;
|
||||
background: rgba(170, 170, 170, .7);
|
||||
border-radius: 0 0 .3em .3em;
|
||||
}
|
||||
|
||||
#eventStills {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#eventThumbsPanel {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
margin: 4px auto;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#eventThumbs {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
height: 300px;
|
||||
}
|
||||
|
@ -208,14 +180,19 @@ span.noneCue {
|
|||
}
|
||||
|
||||
#eventImagePanel {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#eventImageFrame {
|
||||
border: 2px solid gray;
|
||||
background-color: white;
|
||||
padding: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#eventImage {
|
||||
|
@ -225,6 +202,14 @@ span.noneCue {
|
|||
margin-top: 2px;
|
||||
}
|
||||
|
||||
#eventImageBar::after {
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
content: "";
|
||||
clear: both;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
#eventImageStats {
|
||||
float: left;
|
||||
}
|
||||
|
@ -240,6 +225,7 @@ span.noneCue {
|
|||
|
||||
#eventImageNav {
|
||||
position: relative;
|
||||
margin: 0 0 4px 0;
|
||||
}
|
||||
|
||||
#eventImageNav input {
|
||||
|
@ -248,25 +234,20 @@ span.noneCue {
|
|||
}
|
||||
|
||||
#thumbsSliderPanel {
|
||||
width: 400px;
|
||||
margin: 4px auto 0;
|
||||
background: #888888;
|
||||
padding: 1px;
|
||||
width: 80%;
|
||||
margin: 0px auto 4px auto;
|
||||
}
|
||||
|
||||
#thumbsSlider {
|
||||
width: 400px;
|
||||
height: 10px;
|
||||
background: #dddddd;
|
||||
}
|
||||
|
||||
#eventVideo {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: 1.25em;
|
||||
position: relative;
|
||||
top: -1.25em;
|
||||
margin: 0 0 -1.25em 0;
|
||||
}
|
||||
|
||||
#thumbsKnob {
|
||||
width: 8px;
|
||||
height: 10px;
|
||||
background-color: #444444;
|
||||
width: 1em;
|
||||
height: 100%;
|
||||
background-color: #999999;
|
||||
}
|
||||
|
|
|
@ -1,31 +1,5 @@
|
|||
#controls {
|
||||
height: 16px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#controls a {
|
||||
width: 32%;
|
||||
}
|
||||
|
||||
#controls #refreshLink {
|
||||
position: absolute;
|
||||
left: 0%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#controls #filterLink {
|
||||
position: absolute;
|
||||
left: 34%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#controls #timelineLink {
|
||||
position: absolute;
|
||||
left: 68%;
|
||||
text-align: right;
|
||||
.archived {
|
||||
background-color: #2e2e2e;
|
||||
}
|
||||
|
||||
#contentTable.major .colTime {
|
||||
|
@ -40,3 +14,26 @@
|
|||
text-align: right;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
#header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#header h2, #header a {
|
||||
line-height: 1.1;
|
||||
margin:5px 0 0 0;
|
||||
}
|
||||
|
||||
#header #info, #header #pagination, #header #controls {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#header #controls {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
#header #pagination {
|
||||
align-items: center;
|
||||
}
|
||||
|
|
|
@ -1,33 +1,16 @@
|
|||
#scaleControl {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#controls {
|
||||
width: 80%;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#controls a {
|
||||
width: 40px;
|
||||
margin-left: -20px;
|
||||
}
|
||||
|
||||
#firstLink {
|
||||
position: absolute;
|
||||
left: 13%;
|
||||
}
|
||||
|
||||
#prevLink {
|
||||
position: absolute;
|
||||
left: 37%;
|
||||
}
|
||||
|
||||
#nextLink {
|
||||
position: absolute;
|
||||
left: 63%;
|
||||
}
|
||||
|
||||
#lastLink {
|
||||
position: absolute;
|
||||
left: 87%;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
|
||||
#monitors .alert {
|
||||
color: #ffa500;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#monitors .imageFeed {
|
||||
|
|
|
@ -36,3 +36,7 @@
|
|||
input[type=range]::-ms-tooltip {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#downloadVideo {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,25 @@
|
|||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#header h2, #header a {
|
||||
line-height: 1.1;
|
||||
margin:5px 0 0 0;
|
||||
}
|
||||
|
||||
#header #info, #header #headerButtons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#header #headerButtons {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
#title {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
|
@ -15,20 +34,6 @@
|
|||
line-height: 20px;
|
||||
}
|
||||
|
||||
#listLink {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 20px;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
#closeLink {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 20px;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
#topPanel {
|
||||
position: relative;
|
||||
height: 220px;
|
||||
|
|
|
@ -1,37 +1,17 @@
|
|||
@import url(../control.css);
|
||||
|
||||
#menuBar {
|
||||
margin: 6px auto 4px;
|
||||
text-align: center;
|
||||
#header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#menuBar #monitorName {
|
||||
float: left;
|
||||
#menuControls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#menuBar #closeControl {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#menuBar #menuControls {
|
||||
margin: 0 auto;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
#menuBar #menuControls #controlControl {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#menuBar #menuControls #eventsControl {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#menuBar #menuControls #settingsControl {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#menuBar #menuControls #scaleControl {
|
||||
margin: 0 auto;
|
||||
#menuControls div {
|
||||
margin: 0 0 0 1em;
|
||||
}
|
||||
|
||||
#imageFeed{
|
||||
|
|
|
@ -250,6 +250,11 @@ ul.tabList li.active a {
|
|||
font-size: 120%;
|
||||
}
|
||||
|
||||
#content table > tbody > tr:hover
|
||||
{
|
||||
background-color: #EEE;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
@ -363,11 +368,11 @@ th.table-th-sort-rev span.table-th-sort-span {
|
|||
|
||||
#header {
|
||||
width: 100%;
|
||||
line-height: 24px;
|
||||
line-height: 1;
|
||||
text-align: left;
|
||||
background-color: #383836;
|
||||
margin-bottom: 10px;
|
||||
padding: 10px 20px;
|
||||
padding: 5px 20px;
|
||||
margin: 0 auto 4px auto;
|
||||
color: #f2f2f2;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
@ -405,7 +410,7 @@ th.table-th-sort-rev span.table-th-sort-span {
|
|||
|
||||
#content {
|
||||
width: 96%;
|
||||
margin: 8px auto;
|
||||
margin: 0 auto 8px auto;
|
||||
line-height: 130%;
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -454,6 +459,7 @@ th.table-th-sort-rev span.table-th-sort-span {
|
|||
margin: 8px auto;
|
||||
}
|
||||
|
||||
button,
|
||||
input[type=button],
|
||||
input[type=submit] {
|
||||
background-color: #3498db;
|
||||
|
@ -465,6 +471,7 @@ input[type=submit] {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover,
|
||||
input[type=button]:hover,
|
||||
input[type=submit]:hover {
|
||||
background-color: #34a2ee;
|
||||
|
@ -474,6 +481,7 @@ input[type=submit]:hover {
|
|||
|
||||
/* PP - make it easy to identify disabled buttons */
|
||||
|
||||
button:disabled,
|
||||
input[type=button]:disabled,
|
||||
input[type=submit]:disabled {
|
||||
background-color: #aaaaaa;
|
||||
|
|
|
@ -12,6 +12,19 @@
|
|||
float: right;
|
||||
}
|
||||
|
||||
#systemStats .warning {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
#systemStats .error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#systemStats .critical {
|
||||
color: red;
|
||||
text-decoration: blink;
|
||||
}
|
||||
|
||||
#monitorSummary {
|
||||
float: left;
|
||||
text-align: left;
|
||||
|
@ -77,7 +90,3 @@
|
|||
#consoleTable .colLeftButtons {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#consoleTable .colLeftButtons input {
|
||||
margin-right: 24px;
|
||||
}
|
||||
|
|
|
@ -12,97 +12,71 @@
|
|||
|
||||
.alarmCue {
|
||||
background-color: #222222;
|
||||
height: 1.5em;
|
||||
height: 1.25em;
|
||||
text-align: left;
|
||||
margin: 0 auto 0 auto;
|
||||
border-radius: 0 0 .3em .3em;
|
||||
}
|
||||
|
||||
.alarmCue span {
|
||||
background-color:red;
|
||||
height: 1.5em;
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
span.noneCue {
|
||||
background: none;
|
||||
}
|
||||
|
||||
#header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-direction: column;
|
||||
margin: 0 0 4px 0;
|
||||
}
|
||||
|
||||
#header h2, #header a {
|
||||
line-height: 1.1;
|
||||
margin:5px 0 0 0;
|
||||
}
|
||||
|
||||
#dataBar {
|
||||
width: 100%;
|
||||
margin: 2px auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#dataBar #dataTable {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#dataBar #dataTable td {
|
||||
text-align: center;
|
||||
padding: 2px;
|
||||
display: flex;
|
||||
flex-wrap:wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#menuBar1 {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
padding: 3px 0;
|
||||
text-align: center;
|
||||
clear: both;
|
||||
margin: 4px 0 0 0;
|
||||
}
|
||||
|
||||
|
||||
#menuBar1 #nameControl {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#menuBar1 #nameControl #eventName {
|
||||
margin-right: 4px;
|
||||
#menuBar1 input, #menuBar1 select {
|
||||
padding: 2px 5px;
|
||||
}
|
||||
|
||||
#menuBar1 #replayControl {
|
||||
float: right;
|
||||
margin-left: 8px;
|
||||
margin: 0 4px 0 auto;
|
||||
}
|
||||
|
||||
#menuBar1 #scaleControl {
|
||||
float: right;
|
||||
margin-left: 8px;
|
||||
#menuBar1 div {
|
||||
margin: auto 5px;
|
||||
}
|
||||
|
||||
#menuBar2 {
|
||||
width: 100%;
|
||||
padding: 3px 0;
|
||||
margin-bottom: 4px;
|
||||
#nameControl input[type="button"]{
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#menuBar2 div {
|
||||
text-align: left;
|
||||
float: left;
|
||||
padding: 0 12px;
|
||||
#eventVideo {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#menuBar2 #closeWindow {
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
#menuBar1:after,
|
||||
#menuBar2:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
height: 0;
|
||||
font-size: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#menuBar1:after,
|
||||
#menuBar2:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
height: 0;
|
||||
font-size: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
#imageFeed {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
|
@ -129,36 +103,36 @@ span.noneCue {
|
|||
#monitorStatus #monitorState {
|
||||
}
|
||||
|
||||
.dvrControls {
|
||||
#dvrControls {
|
||||
margin-top: 3px;
|
||||
margin-bottom: 2px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dvrControls input {
|
||||
#dvrControls input {
|
||||
padding: 10px 10px;
|
||||
width: 50px;
|
||||
margin: 0 3px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.dvrControls input[disabled=disabled] {
|
||||
#dvrControls input[disabled=disabled] {
|
||||
color: #aaaaaa;
|
||||
}
|
||||
|
||||
.dvrControls input.active {
|
||||
#dvrControls input.active {
|
||||
border: 0;
|
||||
background-color: #2ecc71;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.dvrControls input.inactive {
|
||||
#dvrControls input.inactive {
|
||||
border: 0;
|
||||
background-color: #e67e22;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.dvrControls input.unavail {
|
||||
#dvrControls input.unavail {
|
||||
background-color: #ccc;
|
||||
border: 0;
|
||||
cursor: default;
|
||||
|
@ -176,31 +150,30 @@ span.noneCue {
|
|||
|
||||
#progressBar {
|
||||
position: relative;
|
||||
top: -1.5em;
|
||||
height: 1.5em;
|
||||
margin: 0 auto -1.5em auto;
|
||||
top: -1.25em;
|
||||
height: 1.25em;
|
||||
margin: 0 auto -1.25em auto;
|
||||
}
|
||||
|
||||
#progressBar .progressBox {
|
||||
height: 1.5em;
|
||||
transition: width .1s;
|
||||
height: 100%;
|
||||
background: rgba(170, 170, 170, .7);
|
||||
border-radius: 0 0 .3em .3em;
|
||||
}
|
||||
|
||||
#eventStills {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#eventThumbsPanel {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
margin: 4px auto;
|
||||
margin: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#eventThumbs {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
height: 300px;
|
||||
}
|
||||
|
@ -219,14 +192,19 @@ span.noneCue {
|
|||
}
|
||||
|
||||
#eventImagePanel {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#eventImageFrame {
|
||||
border: 2px solid gray;
|
||||
background-color: white;
|
||||
padding: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#eventImage {
|
||||
|
@ -249,8 +227,17 @@ span.noneCue {
|
|||
float: right;
|
||||
}
|
||||
|
||||
#eventImageBar::after {
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
content: "";
|
||||
clear: both;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
#eventImageNav {
|
||||
position: relative;
|
||||
margin: 0 0 4px 0;
|
||||
}
|
||||
|
||||
#eventImageNav input {
|
||||
|
@ -259,82 +246,20 @@ span.noneCue {
|
|||
}
|
||||
|
||||
#thumbsSliderPanel {
|
||||
width: 400px;
|
||||
margin: 4px auto 0;
|
||||
background: #888888;
|
||||
padding: 1px;
|
||||
width: 80%;
|
||||
margin: 0px auto 4px auto;
|
||||
}
|
||||
|
||||
#thumbsSlider {
|
||||
width: 400px;
|
||||
height: 10px;
|
||||
background: #dddddd;
|
||||
width: 100%;
|
||||
height: 1.25em;
|
||||
position: relative;
|
||||
top: -1.25em;
|
||||
margin: 0 0 -1.25em 0;
|
||||
}
|
||||
|
||||
#thumbsKnob {
|
||||
width: 8px;
|
||||
height: 10px;
|
||||
background-color: #444444;
|
||||
}
|
||||
#eventVideo {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#video-controls {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 5px;
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity .3s;
|
||||
-moz-transition: opacity .3s;
|
||||
-o-transition: opacity .3s;
|
||||
-ms-transition: opacity .3s;
|
||||
transition: opacity .3s;
|
||||
background-image: linear-gradient(bottom, rgb(3,113,168) 13%, rgb(0,136,204) 100%);
|
||||
background-image: -o-linear-gradient(bottom, rgb(3,113,168) 13%, rgb(0,136,204) 100%);
|
||||
background-image: -moz-linear-gradient(bottom, rgb(3,113,168) 13%, rgb(0,136,204) 100%);
|
||||
background-image: -webkit-linear-gradient(bottom, rgb(3,113,168) 13%, rgb(0,136,204) 100%);
|
||||
background-image: -ms-linear-gradient(bottom, rgb(3,113,168) 13%, rgb(0,136,204) 100%);
|
||||
|
||||
background-image: -webkit-gradient(
|
||||
linear,
|
||||
left bottom,
|
||||
left top,
|
||||
color-stop(0.13, rgb(3,113,168)),
|
||||
color-stop(1, rgb(0,136,204))
|
||||
);
|
||||
}
|
||||
|
||||
#eventVideo:hover #video-controls {
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
button {
|
||||
background: rgba(0,0,0,.5);
|
||||
border: 0;
|
||||
color: #EEE;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
-o-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#seekbar {
|
||||
width: 360px;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#volume-bar {
|
||||
width: 60px;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
width: 1em;
|
||||
height: 100%;
|
||||
background-color: #999999;
|
||||
}
|
||||
|
|
|
@ -1,31 +1,5 @@
|
|||
#controls {
|
||||
height: 16px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#controls a {
|
||||
width: 32%;
|
||||
}
|
||||
|
||||
#controls #refreshLink {
|
||||
position: absolute;
|
||||
left: 0%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#controls #filterLink {
|
||||
position: absolute;
|
||||
left: 34%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#controls #timelineLink {
|
||||
position: absolute;
|
||||
left: 68%;
|
||||
text-align: right;
|
||||
.archived {
|
||||
background-color: #f8f8f8;;
|
||||
}
|
||||
|
||||
#contentTable.major .colTime {
|
||||
|
@ -40,3 +14,26 @@
|
|||
text-align: right;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
#header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#header h2, #header a {
|
||||
line-height: 1.1;
|
||||
margin:5px 0 0 0;
|
||||
}
|
||||
|
||||
#header #info, #header #pagination, #header #controls {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#header #controls {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
#header #pagination {
|
||||
align-items: center;
|
||||
}
|
||||
|
|
|
@ -6,29 +6,11 @@
|
|||
width: 80%;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#controls a {
|
||||
width: 40px;
|
||||
margin-left: -20px;
|
||||
}
|
||||
|
||||
#firstLink {
|
||||
position: absolute;
|
||||
left: 13%;
|
||||
}
|
||||
|
||||
#prevLink {
|
||||
position: absolute;
|
||||
left: 37%;
|
||||
}
|
||||
|
||||
#nextLink {
|
||||
position: absolute;
|
||||
left: 63%;
|
||||
}
|
||||
|
||||
#lastLink {
|
||||
position: absolute;
|
||||
left: 87%;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
display: inline-flex;
|
||||
border: 1px solid black;
|
||||
width: 25%;
|
||||
padding: 9px;
|
||||
padding: 4px;
|
||||
}
|
||||
#ScaleDiv label,
|
||||
#SpeedDiv label {
|
||||
|
@ -42,3 +42,7 @@ input[type=range]::-ms-tooltip {
|
|||
color: white;
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
#downloadVideo {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,25 @@
|
|||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#header h2, #header a {
|
||||
line-height: 1.1;
|
||||
margin:5px 0 0 0;
|
||||
}
|
||||
|
||||
#header #info, #header #headerButtons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#header #headerButtons {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
#title {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
|
@ -15,20 +34,6 @@
|
|||
line-height: 20px;
|
||||
}
|
||||
|
||||
#listLink {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 20px;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
#closeLink {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 20px;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
#topPanel {
|
||||
position: relative;
|
||||
height: 220px;
|
||||
|
|
|
@ -1,37 +1,17 @@
|
|||
@import url(../control.css);
|
||||
|
||||
#menuBar {
|
||||
margin: 6px auto 4px;
|
||||
text-align: center;
|
||||
#header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#menuBar #monitorName {
|
||||
float: left;
|
||||
#menuControls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#menuBar #closeControl {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#menuBar #menuControls {
|
||||
margin: 0 auto;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
#menuBar #menuControls #controlControl {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#menuBar #menuControls #eventsControl {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#menuBar #menuControls #settingsControl {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#menuBar #menuControls #scaleControl {
|
||||
margin: 0 auto;
|
||||
#menuControls div {
|
||||
margin: 0 0 0 1em;
|
||||
}
|
||||
|
||||
#imageFeed{
|
||||
|
|
|
@ -45,7 +45,7 @@ $scales = array(
|
|||
'12.5' => '1/8x',
|
||||
);
|
||||
|
||||
if (isset($_REQUEST['view'])) unset($scales[$_REQUEST['view'] == 'event' ? '' : 'auto']); //Remove the option we aren't using on montage or event
|
||||
if (isset($_REQUEST['view'])) unset($scales[$_REQUEST['view'] == 'montage' ? 'auto' : '']); //Only use fixed width/Height on montage
|
||||
|
||||
$bandwidth_options = array(
|
||||
'high' => translate('High'),
|
||||
|
@ -56,6 +56,7 @@ $bandwidth_options = array(
|
|||
switch ( $_COOKIE['zmBandwidth'] ) {
|
||||
case 'high' : {
|
||||
define( 'ZM_WEB_REFRESH_MAIN', ZM_WEB_H_REFRESH_MAIN ); // How often (in seconds) the main console window refreshes
|
||||
define( 'ZM_WEB_REFRESH_NAVBAR', ZM_WEB_H_REFRESH_NAVBAR ); // How often (in seconds) the nav header refreshes
|
||||
define( 'ZM_WEB_REFRESH_CYCLE', ZM_WEB_H_REFRESH_CYCLE ); // How often the cycle watch windows swaps to the next monitor
|
||||
define( 'ZM_WEB_REFRESH_IMAGE', ZM_WEB_H_REFRESH_IMAGE ); // How often the watched image is refreshed (if not streaming)
|
||||
define( 'ZM_WEB_REFRESH_STATUS', ZM_WEB_H_REFRESH_STATUS ); // How often the little status frame refreshes itself in the watch window
|
||||
|
@ -73,6 +74,7 @@ switch ( $_COOKIE['zmBandwidth'] ) {
|
|||
break;
|
||||
} case 'medium' : {
|
||||
define( 'ZM_WEB_REFRESH_MAIN', ZM_WEB_M_REFRESH_MAIN ); // How often (in seconds) the main console window refreshes
|
||||
define( 'ZM_WEB_REFRESH_NAVBAR', ZM_WEB_M_REFRESH_NAVBAR ); // How often (in seconds) the nav header refreshes
|
||||
define( 'ZM_WEB_REFRESH_CYCLE', ZM_WEB_M_REFRESH_CYCLE ); // How often the cycle watch windows swaps to the next monitor
|
||||
define( 'ZM_WEB_REFRESH_IMAGE', ZM_WEB_M_REFRESH_IMAGE ); // How often the watched image is refreshed (if not streaming)
|
||||
define( 'ZM_WEB_REFRESH_STATUS', ZM_WEB_M_REFRESH_STATUS ); // How often the little status frame refreshes itself in the watch window
|
||||
|
@ -90,6 +92,7 @@ switch ( $_COOKIE['zmBandwidth'] ) {
|
|||
break;
|
||||
} case 'low' : {
|
||||
define( 'ZM_WEB_REFRESH_MAIN', ZM_WEB_L_REFRESH_MAIN ); // How often (in seconds) the main console window refreshes
|
||||
define( 'ZM_WEB_REFRESH_NAVBAR', ZM_WEB_L_REFRESH_NAVBAR ); // How often (in seconds) the nav header refreshes
|
||||
define( 'ZM_WEB_REFRESH_CYCLE', ZM_WEB_L_REFRESH_CYCLE ); // How often the cycle watch windows swaps to the next monitor
|
||||
define( 'ZM_WEB_REFRESH_IMAGE', ZM_WEB_L_REFRESH_IMAGE ); // How often the watched image is refreshed (if not streaming)
|
||||
define( 'ZM_WEB_REFRESH_STATUS', ZM_WEB_L_REFRESH_STATUS ); // How often the little status frame refreshes itself in the watch window
|
||||
|
|
|
@ -853,7 +853,7 @@ function exportFileList( $eid, $exportDetail, $exportFrames, $exportImages, $exp
|
|||
return( array_values( $exportFileList ) );
|
||||
}
|
||||
|
||||
function exportEvents( $eids, $exportDetail, $exportFrames, $exportImages, $exportVideo, $exportMisc, $exportFormat )
|
||||
function exportEvents( $eids, $exportDetail, $exportFrames, $exportImages, $exportVideo, $exportMisc, $exportFormat, $exportStructure = false )
|
||||
{
|
||||
|
||||
if ( canView( 'Events' ) && !empty($eids) )
|
||||
|
@ -907,8 +907,12 @@ function exportEvents( $eids, $exportDetail, $exportFrames, $exportImages, $expo
|
|||
{
|
||||
$archive = ZM_DIR_EXPORTS."/".$export_root.".tar.gz";
|
||||
@unlink( $archive );
|
||||
$command = "tar --create --gzip --file=$archive --files-from=$listFile";
|
||||
exec( escapeshellcmd( $command ), $output, $status );
|
||||
if ($exportStructure == 'flat') { //strip file paths if we choose
|
||||
$command = "tar --create --gzip --file=".escapeshellarg($archive)." --files-from=".escapeshellarg($listFile)." --xform='s#^.+/##x'";
|
||||
} else {
|
||||
$command = "tar --create --gzip --file=".escapeshellarg($archive)." --files-from=".escapeshellarg($listFile);
|
||||
}
|
||||
exec( $command, $output, $status );
|
||||
if ( $status )
|
||||
{
|
||||
Error( "Command '$command' returned with status $status" );
|
||||
|
@ -921,7 +925,11 @@ function exportEvents( $eids, $exportDetail, $exportFrames, $exportImages, $expo
|
|||
{
|
||||
$archive = ZM_DIR_EXPORTS."/".$export_root.".zip";
|
||||
@unlink( $archive );
|
||||
$command = "cat ".escapeshellarg($listFile)." | zip -q ".escapeshellarg($archive)." -@";
|
||||
if ($exportStructure == 'flat') {
|
||||
$command = "cat ".escapeshellarg($listFile)." | zip -q -j ".escapeshellarg($archive)." -@";
|
||||
} else {
|
||||
$command = "cat ".escapeshellarg($listFile)." | zip -q ".escapeshellarg($archive)." -@";
|
||||
}
|
||||
//cat zmFileList.txt | zip -q zm_export.zip -@
|
||||
//-bash: zip: command not found
|
||||
|
||||
|
|
|
@ -159,26 +159,29 @@ if ( file_exists( "skins/$skin/css/$css/graphics/favicon.ico" ) ) {
|
|||
<?php
|
||||
} // end function xhtmlHeaders( $file, $title )
|
||||
|
||||
function getNavBarHTML() {
|
||||
function getNavBarHTML($reload = null) {
|
||||
|
||||
$versionClass = (ZM_DYN_DB_VERSION&&(ZM_DYN_DB_VERSION!=ZM_VERSION))?'errorText':'';
|
||||
|
||||
|
||||
ob_start();
|
||||
global $running;
|
||||
if ( $running == null )
|
||||
$running = daemonCheck();
|
||||
$status = $running?translate('Running'):translate('Stopped');
|
||||
global $user;
|
||||
global $bandwidth_options;
|
||||
global $view;
|
||||
global $filterQuery;
|
||||
if (!$filterQuery) {
|
||||
parseFilter( $_REQUEST['filter'] );
|
||||
$filterQuery = $_REQUEST['filter']['query'];
|
||||
}
|
||||
if ($reload === null) {
|
||||
ob_start();
|
||||
if ( $running == null )
|
||||
$running = daemonCheck();
|
||||
$status = $running?translate('Running'):translate('Stopped');
|
||||
?>
|
||||
<noscript>
|
||||
<div style="background-color:red;color:white;font-size:x-large;">
|
||||
ZoneMinder requires Javascript. Please enable Javascript in your browser for this site.
|
||||
</div>
|
||||
</noscript>
|
||||
|
||||
<div class="navbar navbar-inverse navbar-static-top">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
|
@ -212,7 +215,7 @@ if ( ZM_OPT_X10 && canView( 'Devices' ) ) { ?>
|
|||
<li><a href="?view=devices">Devices</a></li>
|
||||
<?php } ?>
|
||||
<li><a href="?view=groups"<?php echo $view=='groups'?' class="selected"':''?>><?php echo translate('Groups') ?></a></li>
|
||||
<li><a href="?view=filter"<?php echo $view=='filter'?' class="selected"':''?>><?php echo translate('Filters') ?></a></li>
|
||||
<li><a href="?view=filter<?php echo $filterQuery ?>"<?php echo $view=='filter'?' class="selected"':''?>><?php echo translate('Filters') ?></a></li>
|
||||
|
||||
<?php
|
||||
if ( canView( 'Stream' ) ) {
|
||||
|
@ -221,9 +224,23 @@ if ( ZM_OPT_X10 && canView( 'Devices' ) ) { ?>
|
|||
<li><a href="?view=montage"<?php echo $view=='montage'?' class="selected"':''?>><?php echo translate('Montage') ?></a></li>
|
||||
<?php
|
||||
}
|
||||
if (isset($_REQUEST['filter']['Query']['terms'])) {
|
||||
$terms = $_REQUEST['filter']['Query']['terms'];
|
||||
$count = 0;
|
||||
foreach ($terms as $term) {
|
||||
if ($term['attr'] == "StartDateTime") {
|
||||
$count += 1;
|
||||
if ($term['op'] == '>=') $minTime = $term['val'];
|
||||
if ($term['op'] == '<=') $maxTime = $term['val'];
|
||||
}
|
||||
}
|
||||
if ($count == 2) {
|
||||
$montageReviewQuery = '&minTime='.$minTime.'&maxTime='.$maxTime;
|
||||
}
|
||||
}
|
||||
if ( canView('Events') ) {
|
||||
?>
|
||||
<li><a href="?view=montagereview"<?php echo $view=='montagereview'?' class="selected"':''?>><?php echo translate('MontageReview')?></a></li>
|
||||
<li><a href="?view=montagereview<?php echo isset($montageReviewQuery)?'&fit=1'.$montageReviewQuery.'&live=0':'' ?>"<?php echo $view=='montagereview'?' class="selected"':''?>><?php echo translate('MontageReview')?></a></li>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
@ -243,7 +260,11 @@ if ( ZM_OPT_X10 && canView( 'Devices' ) ) { ?>
|
|||
</div>
|
||||
</div><!-- End .navbar-collapse -->
|
||||
</div> <!-- End .container-fluid -->
|
||||
<div class="container-fluid">
|
||||
<?php
|
||||
}//end reload null. Runs on full page load
|
||||
if ($reload == 'reload') ob_start();
|
||||
?>
|
||||
<div id="reload" class="container-fluid">
|
||||
<div class="pull-left">
|
||||
<?php echo makePopupLink( '?view=bandwidth', 'zmBandwidth', 'bandwidth', $bandwidth_options[$_COOKIE['zmBandwidth']] . ' ' . translate('BandwidthHead'), ($user && $user['MaxBandwidth'] != 'low' ) ) ?>
|
||||
</div>
|
||||
|
@ -277,9 +298,11 @@ if ( ZM_OPT_X10 && canView( 'Devices' ) ) { ?>
|
|||
echo ' ' . ZM_PATH_MAP .': '. getDiskPercent(ZM_PATH_MAP).'%';
|
||||
?></li>
|
||||
</ul>
|
||||
</div> <!-- End .footer -->
|
||||
|
||||
</div> <!-- End .navbar .navbar-default -->
|
||||
</div> <!-- End .footer/reload -->
|
||||
<?php
|
||||
if ($reload == 'reload') return( ob_get_clean() );
|
||||
?>
|
||||
</div><!-- End .navbar .navbar-default -->
|
||||
<?php
|
||||
return( ob_get_clean() );
|
||||
} // end function getNavBarHTML()
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue