Merge branch 'storageareas' into zma_to_thread

Conflicts:
	src/zm_ffmpeg_camera.cpp
	src/zm_mpeg.cpp
	src/zmc.cpp
pull/3122/head
Isaac Connor 2018-02-02 14:23:26 -05:00
commit a1392bf613
23 changed files with 497 additions and 660 deletions

View File

@ -645,7 +645,7 @@ CREATE INDEX `Monitors_ServerId_idx` ON `Monitors` (`ServerId`);
DROP TABLE IF EXISTS `Monitor_Status`;
CREATE TABLE `Monitor_Status` (
`MonitorId` int(10) unsigned NOT NULL,
`Status` enum('Unknown','NotRunning','Running','NoSignal','Signal') NOT NULL default 'Unknown',
`Status` enum('Unknown','NotRunning','Running','Connected','Signal') NOT NULL default 'Unknown',
`CaptureFPS` DECIMAL(10,2) NOT NULL default 0,
`AnalysisFPS` DECIMAL(5,2) NOT NULL default 0,
PRIMARY KEY (`MonitorId`)

20
db/zm_update-1.31.30.sql Normal file
View File

@ -0,0 +1,20 @@
DROP TABLE IF EXISTS `Monitor_Status`;
CREATE TABLE `Monitor_Status` (
`MonitorId` int(10) unsigned NOT NULL,
`Status` enum('Unknown','NotRunning','Running','Connected','Signal') NOT NULL default 'Unknown',
`CaptureFPS` DECIMAL(10,2) NOT NULL default 0,
`AnalysisFPS` DECIMAL(5,2) NOT NULL default 0,
PRIMARY KEY (`MonitorId`)
) ENGINE=MEMORY;
SET SESSION sql_mode='NO_AUTO_VALUE_ON_ZERO';
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM Storage WHERE Name = 'Default' AND Id=0 AND Path='/var/cache/zoneminder/events'
) > 0,
"SELECT 'Default Storage Area already exists.'",
"INSERT INTO Storage (Id,Name,Path,Scheme,ServerId) VALUES (0,'Default','/var/cache/zoneminder/events','Medium',NULL)"
));
PREPARE stmt FROM @s;
EXECUTE stmt;

View File

@ -3,5 +3,3 @@
# Process the perl modules subdirectory
add_subdirectory(proxy)
add_subdirectory(modules)
add_subdirectory(scripts)

View File

@ -1,9 +0,0 @@
# CMakeLists.txt for the ZoneMinder perl scripts.
# If this is an out-of-source build, copy the files we need to the binary directory
if(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR))
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/zmonvif-probe.pl" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
endif(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR))
# Install the perl scripts
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zmonvif-probe.pl" DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)

View File

@ -1,405 +0,0 @@
#!/usr/bin/perl -w
use strict;
#
# ==========================================================================
#
# ZoneMinder ONVIF Control Protocol Module
# Copyright (C) 2014 Jan M. Hochstein
#
# 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 ONVIF capability prober
#
use Getopt::Std;
use Data::UUID;
require ONVIF::Client;
require WSDiscovery10::Interfaces::WSDiscovery::WSDiscoveryPort;
require WSDiscovery10::Elements::Header;
require WSDiscovery10::Elements::Types;
require WSDiscovery10::Elements::Scopes;
require WSDiscovery::TransportUDP;
#
# ========================================================================
# Globals
my $verbose = 0;
my $soap_version = undef;
my $client;
# =========================================================================
# internal functions
sub deserialize_message
{
my ($wsdl_client, $response) = @_;
# copied and adapted from SOAP::WSDL::Client
# get deserializer
my $deserializer = $wsdl_client->get_deserializer();
if(! $deserializer) {
$deserializer = SOAP::WSDL::Factory::Deserializer->get_deserializer({
soap_version => $wsdl_client->get_soap_version(),
%{ $wsdl_client->get_deserializer_args() },
});
}
# set class resolver if serializer supports it
$deserializer->set_class_resolver( $wsdl_client->get_class_resolver() )
if ( $deserializer->can('set_class_resolver') );
# Try deserializing response - there may be some,
# even if transport did not succeed (got a 500 response)
if ( $response ) {
# as our faults are false, returning a success marker is the only
# reliable way of determining whether the deserializer succeeded.
# Custom deserializers may return an empty list, or undef,
# and $@ is not guaranteed to be undefined.
my ($success, $result_body, $result_header) = eval {
(1, $deserializer->deserialize( $response ));
};
if (defined $success) {
return wantarray
? ($result_body, $result_header)
: $result_body;
}
elsif (blessed $@) { #}&& $@->isa('SOAP::WSDL::SOAP::Typelib::Fault11')) {
return $@;
}
else {
return $deserializer->generate_fault({
code => 'soap:Server',
role => 'urn:localhost',
message => "Error deserializing message: $@. \n"
. "Message was: \n$response"
});
}
};
}
sub interpret_messages
{
my ($svc_discover, $services, @responses ) = @_;
foreach my $response ( @responses ) {
if($verbose) {
print "Received message:\n" . $response . "\n";
}
my $result = deserialize_message($svc_discover, $response);
if(not $result) {
if($verbose) {
print "Error deserializing message. No message returned from deserializer.\n";
}
next;
}
my $xaddr;
foreach my $l_xaddr (split ' ', $result->get_ProbeMatch()->get_XAddrs()) {
# find IPv4 address
if($verbose) {
print "l_xaddr = $l_xaddr\n";
}
if($l_xaddr =~ m|//[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[:/]|) {
$xaddr = $l_xaddr;
last;
} else {
print STDERR "Unable to find IPv4 address from xaddr $l_xaddr\n";
}
}
# No usable address found
next if not $xaddr;
# ignore multiple responses from one service
next if defined $services->{$xaddr};
$services->{$xaddr} = 1;
print "$xaddr, " . $svc_discover->get_soap_version() . ", ";
print "(";
my $scopes = $result->get_ProbeMatch()->get_Scopes();
my $count = 0;
foreach my $scope(split ' ', $scopes) {
if($scope =~ m|onvif://www\.onvif\.org/(.+)/(.*)|) {
my ($attr, $value) = ($1,$2);
if( 0 < $count ++) {
print ", ";
}
print $attr . "=\'" . $value . "\'";
}
}
print ")\n";
}
}
# =========================================================================
# functions
sub discover
{
## collect all responses
my @responses = ();
no warnings 'redefine';
*WSDiscovery::TransportUDP::_notify_response = sub {
my ($transport, $response) = @_;
push @responses, $response;
};
## try both soap versions
my %services;
my $uuid_gen = Data::UUID->new();
if ( ( ! $soap_version ) or ( $soap_version eq '1.1' ) ) {
if($verbose) {
print "Probing for SOAP 1.1\n"
}
my $svc_discover = WSDiscovery10::Interfaces::WSDiscovery::WSDiscoveryPort->new({
# no_dispatch => '1',
});
$svc_discover->set_soap_version('1.1');
my $uuid = $uuid_gen->create_str();
my $result = $svc_discover->ProbeOp(
{ # WSDiscovery::Types::ProbeType
Types => 'http://www.onvif.org/ver10/network/wsdl:NetworkVideoTransmitter http://www.onvif.org/ver10/device/wsdl:Device', # QNameListType
Scopes => { value => '' },
},
WSDiscovery10::Elements::Header->new({
Action => { value => 'http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe' },
MessageID => { value => "urn:uuid:$uuid" },
To => { value => 'urn:schemas-xmlsoap-org:ws:2005:04:discovery' },
})
);
print $result . "\n" if $verbose;
interpret_messages($svc_discover, \%services, @responses);
@responses = ();
} # end if doing soap 1.1
if ( ( ! $soap_version ) or ( $soap_version eq '1.2' ) ) {
if($verbose) {
print "Probing for SOAP 1.2\n"
}
my $svc_discover = WSDiscovery10::Interfaces::WSDiscovery::WSDiscoveryPort->new({
# no_dispatch => '1',
});
$svc_discover->set_soap_version('1.2');
# copies of the same Probe message must have the same MessageID.
# This is not a copy. So we generate a new uuid.
my $uuid = $uuid_gen->create_str();
# Everyone else, like the nodejs onvif code and odm only ask for NetworkVideoTransmitter
my $result = $svc_discover->ProbeOp(
{ # WSDiscovery::Types::ProbeType
xmlattr => { 'xmlns:dn' => 'http://www.onvif.org/ver10/network/wsdl', },
Types => 'dn:NetworkVideoTransmitter', # QNameListType
Scopes => { value => '' },
},
WSDiscovery10::Elements::Header->new({
Action => { value => 'http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe' },
MessageID => { value => "urn:uuid:$uuid" },
To => { value => 'urn:schemas-xmlsoap-org:ws:2005:04:discovery' },
})
);
print $result . "\n" if $verbose;
interpret_messages($svc_discover, \%services, @responses);
} # end if doing soap 1.2
}
sub profiles
{
# my $result = $services{media}{ep}->GetVideoSources( { } ,, );
# die $result if not $result;
# print $result . "\n";
my $result = $client->get_endpoint('media')->GetProfiles( { } ,, );
die $result if not $result;
if($verbose) {
print "Received message:\n" . $result . "\n";
}
my $profiles = $result->get_Profiles();
foreach my $profile ( @{ $profiles } ) {
my $token = $profile->attr()->get_token() ;
# Specification gives conflicting values for unicast stream types, try both.
# http://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl#op.GetStreamUri
foreach my $streamtype ( 'RTP_unicast', 'RTP-Unicast' ) {
$result = $client->get_endpoint('media')->GetStreamUri( {
StreamSetup => { # ONVIF::Media::Types::StreamSetup
Stream => $streamtype, # StreamType
Transport => { # ONVIF::Media::Types::Transport
Protocol => 'RTSP', # TransportProtocol
},
},
ProfileToken => $token, # ReferenceToken
} ,, );
last if $result;
}
die $result if not $result;
# print $result . "\n";
my $VideoEncoderConfiguration = $profile->get_VideoEncoderConfiguration();
print join(', ', $token,
$profile->get_Name(),
( $VideoEncoderConfiguration ? (
$VideoEncoderConfiguration->get_Encoding(),
$VideoEncoderConfiguration->get_Resolution()->get_Width(),
$VideoEncoderConfiguration->get_Resolution()->get_Height(),
$VideoEncoderConfiguration->get_RateControl()->get_FrameRateLimit(),
) : () ),
$result->get_MediaUri()->get_Uri() ,
). "\n";
} # end foreach profile
#
# use message parser without schema validation ???
#
}
sub move
{
my ($dir) = @_;
my $result = $client->get_endpoint('ptz')->GetNodes( { } ,, );
die $result if not $result;
print $result . "\n";
}
sub metadata
{
my $result = $client->get_endpoint('media')->GetMetadataConfigurations( { } ,, );
die $result if not $result;
print $result . "\n";
$result = $client->get_endpoint('media')->GetVideoAnalyticsConfigurations( { } ,, );
die $result if not $result;
print $result . "\n";
# $result = $client->get_endpoint('analytics')->GetServiceCapabilities( { } ,, );
# die $result if not $result;
# print $result . "\n";
}
# ========================================================================
# options processing
$Getopt::Std::STANDARD_HELP_VERSION = 1;
our ($opt_v);
my $OPTIONS = "v";
sub HELP_MESSAGE
{
my ($fh, $pkg, $ver, $opts) = @_;
print $fh "Usage: " . __FILE__ . " [-v] probe <soap version>\n";
print $fh " " . __FILE__ . " [-v] <command> <device URI> <soap version> <user> <password>\n";
print $fh <<EOF
Commands are:
probe - scan for devices on the local network and list them
profiles - print the device's supported stream configurations
metadata - print some of the device's configuration settings
move - move the device (only ptz cameras)
Common parameters:
-v - increase verbosity
Device access parameters (for all commands but 'probe'):
device URL - the ONVIF Device service URL
soap version - SOAP version (1.1 or 1.2)
user - username of a user with access to the device
password - password for the user
EOF
}
# ========================================================================
# MAIN
if(!getopts($OPTIONS)) {
HELP_MESSAGE(\*STDOUT);
exit(1);
}
if(defined $opt_v) {
$verbose = 1;
}
my $action = shift;
if(!defined $action) {
HELP_MESSAGE(\*STDOUT);
exit(1);
}
if($action eq "probe") {
$soap_version = shift;
discover();
}
else {
# all other actions need URI and credentials
my $url_svc_device = shift @ARGV;
$soap_version = shift @ARGV;
my $username = @ARGV ? shift @ARGV : '';
my $password = @ARGV ? shift @ARGV: '';
$client = ONVIF::Client->new( {
'url_svc_device' => $url_svc_device,
'soap_version' => $soap_version } );
$client->set_credentials($username, $password, 1);
$client->create_services();
if($action eq "profiles") {
profiles();
}
elsif($action eq "move") {
my $dir = shift;
move($dir);
}
elsif($action eq "metadata") {
metadata();
}
else {
print("Error: Unknown command\"$action\"");
exit(1);
}
}

View File

@ -8,6 +8,7 @@ configure_file(zmaudit.pl.in "${CMAKE_CURRENT_BINARY_DIR}/zmaudit.pl" @ONLY)
configure_file(zmcontrol.pl.in "${CMAKE_CURRENT_BINARY_DIR}/zmcontrol.pl" @ONLY)
configure_file(zmdc.pl.in "${CMAKE_CURRENT_BINARY_DIR}/zmdc.pl" @ONLY)
configure_file(zmfilter.pl.in "${CMAKE_CURRENT_BINARY_DIR}/zmfilter.pl" @ONLY)
configure_file(zmonvif-probe.pl.in "${CMAKE_CURRENT_BINARY_DIR}/zmonvif-probe.pl" @ONLY)
configure_file(zmpkg.pl.in "${CMAKE_CURRENT_BINARY_DIR}/zmpkg.pl" @ONLY)
configure_file(zmtrack.pl.in "${CMAKE_CURRENT_BINARY_DIR}/zmtrack.pl" @ONLY)
configure_file(zmtrigger.pl.in "${CMAKE_CURRENT_BINARY_DIR}/zmtrigger.pl" @ONLY)
@ -34,7 +35,7 @@ FOREACH(PERLSCRIPT ${perlscripts})
ENDFOREACH(PERLSCRIPT ${perlscripts})
# Install the perl scripts
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zmaudit.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmcontrol.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmdc.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmfilter.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmpkg.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtrack.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtrigger.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmupdate.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmvideo.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmwatch.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmcamtool.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtelemetry.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmstats.pl" DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zmaudit.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmcontrol.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmdc.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmfilter.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmonvif-probe.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmpkg.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtrack.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtrigger.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmupdate.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmvideo.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmwatch.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmcamtool.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtelemetry.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmstats.pl" DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
if(NOT ZM_NO_X10)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zmx10.pl" DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
endif(NOT ZM_NO_X10)

View File

@ -45,7 +45,6 @@ our @EXPORT = qw();
our $VERSION = $ZoneMinder::Base::VERSION;
use Getopt::Std;
use Data::UUID;
use vars qw( $verbose $soap_version );
@ -185,11 +184,11 @@ sub discover {
};
## try both soap versions
my %services;
my $uuid_gen = Data::UUID->new();
if ( ( ! $soap_version ) or ( $soap_version eq '1.1' ) ) {
my %services;
if($verbose) {
print "Probing for SOAP 1.1\n"
@ -219,6 +218,7 @@ sub discover {
} # end if doing soap 1.1
if ( ( ! $soap_version ) or ( $soap_version eq '1.2' ) ) {
my %services;
if($verbose) {
print "Probing for SOAP 1.2\n"
}
@ -253,8 +253,17 @@ sub discover {
sub profiles {
my ( $client ) = @_;
my $result = $client->get_endpoint('media')->GetProfiles( { } ,, );
die $result if not $result;
my $endpoint = $client->get_endpoint('media');
if ( ! $endpoint ) {
print "No media enpoint for client.\n";
return;
}
my $result = $endpoint->GetProfiles( { } ,, );
if ( ! $result ) {
print "No result from GetProfiles\n";
return;
}
if($verbose) {
print "Received message:\n" . $result . "\n";
}

View File

@ -269,7 +269,7 @@ MAIN: while( $loop ) {
#Event path is hour/minute/sec
my $event_path = readlink( $event_link );
if ( !-e $event_path ) {
if ( !($event_path and -e $event_path) ) {
aud_print( "Event link $day_dir/$event_link does not point to valid target" );
if ( confirm() ) {
( $event_link ) = ( $event_link =~ /^(.*)$/ ); # De-taint

View File

@ -183,39 +183,39 @@ use Sys::CpuLoad;
socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" );
my $attempts = 0;
while( !connect( CLIENT, $saddr ) ) {
while( !connect(CLIENT, $saddr) ) {
$attempts++;
Debug("Waiting for zmdc.pl server process at ".SOCK_FILE.", attempt $attempts" );
Fatal( "Can't connect: $!" ) if ($attempts > MAX_CONNECT_DELAY);
Debug("Waiting for zmdc.pl server process at ".SOCK_FILE.", attempt $attempts");
Fatal("Can't connect: $!") if $attempts > MAX_CONNECT_DELAY;
usleep(200000);
} # end while
} elsif ( defined($cpid) ) {
ZMServer::run();
} else {
Fatal( "Can't fork: $!" );
Fatal("Can't fork: $!");
}
} # end if ! server is up
if ( $command eq 'check' && ! $daemon ) {
print( "running\n" );
if ( ($command eq 'check') && !$daemon ) {
print("running\n");
exit();
} elsif ( $command eq 'startup' ) {
# Our work here is done
exit() if ( !$server_up );
exit() if !$server_up;
}
# The server is there, connect to it
#print( "Writing commands\n" );
CLIENT->autoflush();
my $message = join(';', $command, ( $daemon ? $daemon : () ), @args );
print( CLIENT $message );
shutdown( CLIENT, 1 );
print(CLIENT $message);
shutdown(CLIENT, 1);
while( my $line = <CLIENT> ) {
chomp( $line );
print( "$line\n" );
chomp($line);
print("$line\n");
}
# And we're done!
close( CLIENT );
close(CLIENT);
#print( "Finished writing, bye\n" );
exit;
@ -344,9 +344,9 @@ sub run {
} else {
dPrint( ZoneMinder::Logger::ERROR, "Invalid command '$command'\n" );
}
close( CLIENT );
close(CLIENT);
} else {
Fatal( 'Bogus descriptor' );
Fatal('Bogus descriptor');
}
} elsif ( $nfound < 0 ) {
if ( $! == EINTR ) {
@ -355,9 +355,9 @@ sub run {
# See if it needs to start up again
restartPending();
} elsif ( $! == EPIPE ) {
Error( "Can't select: $!" );
Error("Can't select: $!");
} else {
Fatal( "Can't select: $!" );
Fatal("Can't select: $!");
}
} else {
#print( "Select timed out\n" );
@ -566,19 +566,19 @@ sub restart {
my $command = $daemon;
$command .= ' '.join( ' ', ( @args ) ) if @args;
dPrint ( ZoneMinder::Logger::WARNING, "Restarting $command\n");
dPrint ( ZoneMinder::Logger::DEBUG, "Restarting $command\n");
my $process = $cmd_hash{$command};
if ( $process ) {
dPrint ( ZoneMinder::Logger::WARNING, "Have process" );
dPrint( ZoneMinder::Logger::DEBUG, "Have process" );
if ( $process->{pid} ) {
dPrint ( ZoneMinder::Logger::WARNING, "Have process pid " .$process->{pid} );
dPrint( ZoneMinder::Logger::DEBUG, "Have process pid " .$process->{pid} );
my $cpid = $process->{pid};
if ( defined($pid_hash{$cpid}) ) {
dPrint ( ZoneMinder::Logger::WARNING, "Have process pid hash " .$process->{pid} );
dPrint( ZoneMinder::Logger::DEBUG, "Have process pid hash " .$process->{pid} );
_stop( 0, $process );
return;
} else {
dPrint ( ZoneMinder::Logger::WARNING, "Not sending stop" );
dPrint( ZoneMinder::Logger::DEBUG, "Not sending stop" );
}
}
}

View File

@ -73,6 +73,7 @@ use autouse 'Data::Dumper'=>qw(Dumper);
my $filter_name = '';
my $filter_id;
my $version = 0;
my $zm_terminate = 0;
GetOptions(
'filter=s' =>\$filter_name,
@ -94,7 +95,20 @@ use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)
;
logInit();
logSetSignal();
sub HupHandler {
Info("Received HUP, reloading");
&ZoneMinder::Logger::logHupHandler();
}
sub TermHandler {
Info("Received TERM, exiting");
$zm_terminate = 1;
}
sub Term {
exit( 0 );
}
$SIG{HUP} = \&HupHandler;
$SIG{TERM} = \&TermHandler;
$SIG{INT} = \&TermHandler;
if ( $Config{ZM_OPT_UPLOAD} ) {
# Comment these out if you don't have them and don't want to upload
@ -166,7 +180,7 @@ if ( ! ( $filter_name or $filter_id ) ) {
my @filters;
my $last_action = 0;
while( 1 ) {
while( ! $zm_terminate ) {
my $now = time;
if ( ($now - $last_action) > $Config{ZM_FILTER_RELOAD_DELAY} ) {
Debug( "Reloading filters\n" );
@ -175,6 +189,7 @@ while( 1 ) {
}
foreach my $filter ( @filters ) {
last if $zm_terminate;
if ( $$filter{Concurrent} and ! ( $filter_id or $filter_name ) ) {
my ( $proc ) = $0 =~ /(\S+)/;
my ( $id ) = $$filter{Id} =~ /(\d+)/;
@ -186,7 +201,7 @@ while( 1 ) {
}
}
last if ( $filter_name or $filter_id );
last if $filter_name or $filter_id or $zm_terminate;
Debug( "Sleeping for $delay seconds\n" );
sleep( $delay );
@ -266,6 +281,7 @@ sub checkFilter {
) );
foreach my $event ( @Events ) {
last if $zm_terminate;
Debug( "Checking event $event->{Id}" );
my $delete_ok = !undef;
$dbh->ping();

155
scripts/zmonvif-probe.pl.in Executable file
View File

@ -0,0 +1,155 @@
#!/usr/bin/perl -w
use strict;
#
# ==========================================================================
#
# ZoneMinder ONVIF Control Protocol Module
# Copyright (C) 2014 Jan M. Hochstein
#
# 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 ONVIF capability prober
#
use Getopt::Std;
require ONVIF::Client;
# ========================================================================
# options processing
$Getopt::Std::STANDARD_HELP_VERSION = 1;
our ($opt_v);
my $OPTIONS = "v";
sub HELP_MESSAGE
{
my ($fh, $pkg, $ver, $opts) = @_;
print $fh "Usage: " . __FILE__ . " [-v] probe <soap version>\n";
print $fh " " . __FILE__ . " [-v] <command> <device URI> <soap version> <user> <password>\n";
print $fh <<EOF
Commands are:
probe - scan for devices on the local network and list them
profiles - print the device's supported stream configurations
metadata - print some of the device's configuration settings
move - move the device (only ptz cameras)
Common parameters:
-v - increase verbosity
Device access parameters (for all commands but 'probe'):
device URL - the ONVIF Device service URL
soap version - SOAP version (1.1 or 1.2)
user - username of a user with access to the device
password - password for the user
EOF
}
# ========================================================================
# MAIN
if ( !getopts($OPTIONS) ) {
HELP_MESSAGE(\*STDOUT);
exit(1);
}
my $action = shift;
if(!defined $action) {
HELP_MESSAGE(\*STDOUT);
exit(1);
}
@EXTRA_PERL_LIB@
require ZoneMinder::ONVIF;
if ( defined $opt_v ) {
$ZoneMinder::ONVIF::verbose = 1;
}
if ( $action eq "probe" ) {
my $soap_version = shift;
ZoneMinder::ONVIF::discover($soap_version);
} else {
# all other actions need URI and credentials
my $url_svc_device = shift @ARGV;
my $soap_version = shift @ARGV;
my $username = @ARGV ? shift @ARGV : '';
my $password = @ARGV ? shift @ARGV: '';
my $client = ONVIF::Client->new( {
'url_svc_device' => $url_svc_device,
'soap_version' => $soap_version } );
$client->set_credentials($username, $password, 1);
$client->create_services();
if ( $action eq "profiles" ) {
ZoneMinder::ONVIF::profiles($client);
} elsif( $action eq "move" ) {
my $dir = shift;
ZoneMinder::ONVIF::move($client, $dir);
} elsif ( $action eq "metadata" ) {
ZoneMinder::ONVIF::metadata($client);
} else {
print("Error: Unknown command\"$action\"");
exit(1);
}
}
1;
__END__
=head1 NAME
zmonvif-probe.pl - ZoneMinder ONVIF probing tool
=head1 SYNOPSIS
zmonfig-probe.pl [-v] probe <soap version>
[-v] <command> <device URI> <soap version> <user> <password>\n";
Commands are:
probe - scan for devices on the local network and list them
profiles - print the device's supported stream configurations
metadata - print some of the device's configuration settings
move - move the device (only ptz cameras)
Common parameters:
-v - increase verbosity
Device access parameters (for all commands but 'probe'):
device URL - the ONVIF Device service URL
soap version - SOAP version (1.1 or 1.2)
user - username of a user with access to the device
password - password for the user
=head1 DESCRIPTION
=head1 OPTIONS
-c, --continuous - Run continuously
-f, --force - Run even if pid file exists
-i, --interactive - Ask before applying any changes
-m, --monitor_id - Only consider the given monitor
-r, --report - Just report don't actually do anything
-s, --storage_id - Specify a storage area to audit instead of all
-v, --version - Print the installed version of ZoneMinder
=cut

View File

@ -58,10 +58,16 @@ Event::Event(
std::string notes;
createNotes(notes);
struct timeval now;
gettimeofday(&now, 0);
bool untimedEvent = false;
if ( !start_time.tv_sec ) {
untimedEvent = true;
gettimeofday(&start_time, 0);
start_time = now;
} else if ( start_time.tv_sec > now.tv_sec ) {
Error("StartTime in the future");
start_time = now;
}
Storage * storage = monitor->getStorage();
@ -420,7 +426,8 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st
struct DeltaTimeval delta_time;
DELTA_TIMEVAL( delta_time, *(timestamps[i]), start_time, DT_PREC_2 );
if ( delta_time.sec > 99999999 ) {
// Delta is Decimal(8,2) so 6 integer digits and 2 decimal digits
if ( delta_time.sec > 999999 ) {
Warning("Invalid delta_time from_unixtime(%ld), %s%ld.%02ld",
timestamps[i]->tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec );
delta_time.sec = 0;

View File

@ -458,5 +458,5 @@ void dumpPacket(AVPacket *pkt, const char *text) {
pkt->flags & AV_PKT_FLAG_KEY,
pkt->pos,
pkt->duration);
Debug(1, "%s:%d:%s: %s", __FILE__, __LINE__, text, b);
Debug(2, "%s:%d:%s: %s", __FILE__, __LINE__, text, b);
}

View File

@ -121,6 +121,9 @@ FfmpegCamera::~FfmpegCamera() {
}
int FfmpegCamera::PrimeCapture() {
if ( mCanCapture ) {
CloseFfmpeg();
}
mVideoStreamId = -1;
mAudioStreamId = -1;
Info( "Priming capture from %s", mPath.c_str() );
@ -129,6 +132,7 @@ int FfmpegCamera::PrimeCapture() {
}
int FfmpegCamera::PreCapture() {
Debug(1, "PreCapture");
// If Reopen was called, then ffmpeg is closed and we need to reopen it.
if ( ! mCanCapture )
return OpenFfmpeg();
@ -177,7 +181,7 @@ int FfmpegCamera::PostCapture() {
int FfmpegCamera::OpenFfmpeg() {
Debug ( 2, "OpenFfmpeg called." );
Debug(2, "OpenFfmpeg called.");
int ret;
mOpenStart = time(NULL);
@ -221,7 +225,7 @@ int FfmpegCamera::OpenFfmpeg() {
#endif
{
mIsOpening = false;
Error( "Unable to open input %s due to: %s", mPath.c_str(), strerror(errno) );
Error("Unable to open input %s due to: %s", mPath.c_str(), strerror(errno));
return -1;
}
@ -235,16 +239,16 @@ int FfmpegCamera::OpenFfmpeg() {
mIsOpening = false;
Debug ( 1, "Opened input" );
Info( "Stream open %s", mPath.c_str() );
Info( "Stream open %s, parsing streams...", mPath.c_str() );
#if !LIBAVFORMAT_VERSION_CHECK(53, 6, 0, 6, 0)
if ( av_find_stream_info( mFormatContext ) < 0 )
#else
if ( avformat_find_stream_info( mFormatContext, 0 ) < 0 )
#endif
Fatal( "Unable to find stream info from %s due to: %s", mPath.c_str(), strerror(errno) );
Fatal("Unable to find stream info from %s due to: %s", mPath.c_str(), strerror(errno));
Debug ( 1, "Got stream info" );
Debug(4, "Got stream info");
// Find first video stream present
// The one we want Might not be the first
@ -289,11 +293,11 @@ int FfmpegCamera::OpenFfmpeg() {
if ( mAudioStreamId == -1 )
Debug( 3, "Unable to locate audio stream in %s", mPath.c_str() );
Debug ( 3, "Found video stream at index %d", mVideoStreamId );
Debug ( 3, "Found audio stream at index %d", mAudioStreamId );
Debug(3, "Found video stream at index %d", mVideoStreamId);
Debug(3, "Found audio stream at index %d", mAudioStreamId);
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
mVideoCodecContext = avcodec_alloc_context3( NULL );
mVideoCodecContext = avcodec_alloc_context3(NULL);
avcodec_parameters_to_context( mVideoCodecContext, mFormatContext->streams[mVideoStreamId]->codecpar );
#else
mVideoCodecContext = mFormatContext->streams[mVideoStreamId]->codec;
@ -345,7 +349,8 @@ int FfmpegCamera::OpenFfmpeg() {
if ( (!mVideoCodec) and ( (mVideoCodec = avcodec_find_decoder(mVideoCodecContext->codec_id)) == NULL ) ) {
// Try and get the codec from the codec context
Fatal("Can't find codec for video stream from %s", mPath.c_str());
Error("Can't find codec for video stream from %s", mPath.c_str());
return -1;
} else {
Debug(1, "Video Found decoder");
zm_dump_stream_format(mFormatContext, mVideoStreamId, 0, 0);
@ -388,7 +393,7 @@ int FfmpegCamera::OpenFfmpeg() {
} else {
Debug(1, "Audio Found decoder");
zm_dump_stream_format(mFormatContext, mAudioStreamId, 0, 0);
// Open the codec
// Open the codec
#if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0)
Debug ( 1, "Calling avcodec_open" );
if ( avcodec_open(mAudioCodecContext, mAudioCodec) < 0 )

View File

@ -99,6 +99,7 @@ void VideoStream::SetupFormat( ) {
}
#endif
} else {
Debug(1,"No allocating priv_data");
s->priv_data = NULL;
}
@ -120,7 +121,6 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
/* ffmpeg format matching */
switch ( colours ) {
case ZM_COLOUR_RGB24:
{
if ( subpixelorder == ZM_SUBPIX_ORDER_BGR ) {
/* BGR subpixel order */
pf = AV_PIX_FMT_BGR24;
@ -129,9 +129,7 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
pf = AV_PIX_FMT_RGB24;
}
break;
}
case ZM_COLOUR_RGB32:
{
if(subpixelorder == ZM_SUBPIX_ORDER_ARGB) {
/* ARGB subpixel order */
pf = AV_PIX_FMT_ARGB;
@ -146,7 +144,6 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
pf = AV_PIX_FMT_RGBA;
}
break;
}
case ZM_COLOUR_GRAY8:
pf = AV_PIX_FMT_GRAY8;
break;
@ -159,6 +156,7 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
// RTP must have a packet_size.
// Not sure what this value should be really...
ofc->packet_size = width*height;
Debug(1,"Setting packet_size to %d", ofc->packet_size);
if ( of->video_codec == AV_CODEC_ID_NONE ) {
// RTP does not have a default codec in ffmpeg <= 0.8.
@ -171,6 +169,7 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
AVCodec *a = avcodec_find_encoder_by_name(codec_name);
if ( a ) {
codec_id = a->id;
Debug( 1, "Using codec \"%s\"", codec_name );
} else {
#if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100))
Debug( 1, "Could not find codec \"%s\". Using default \"%s\"", codec_name, avcodec_get_name( codec_id ) );
@ -209,13 +208,13 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
Fatal( "Could not alloc stream" );
return;
}
Debug( 1, "Allocated stream (%d) !=? (%d)", ost->id , ofc->nb_streams - 1 );
ost->id = ofc->nb_streams - 1;
Debug( 1, "Allocated stream" );
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
codec_context = avcodec_alloc_context3(NULL);
avcodec_parameters_to_context(codec_context, ost->codecpar);
codec_context = avcodec_alloc_context3(NULL);
//avcodec_parameters_to_context(codec_context, ost->codecpar);
#else
codec_context = ost->codec;
#endif
@ -223,7 +222,7 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
codec_context->codec_id = codec->id;
codec_context->codec_type = codec->type;
codec_context->pix_fmt = strcmp( "mjpeg", ofc->oformat->name ) == 0 ? AV_PIX_FMT_YUVJ422P : AV_PIX_FMT_YUV420P;
codec_context->pix_fmt = strcmp("mjpeg", ofc->oformat->name) == 0 ? AV_PIX_FMT_YUVJ422P : AV_PIX_FMT_YUV420P;
if ( bitrate <= 100 ) {
// Quality based bitrate control (VBR). Scale is 1..31 where 1 is best.
// This gets rid of artifacts in the beginning of the movie; and well, even quality.
@ -246,8 +245,11 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
identically 1. */
codec_context->time_base.den = frame_rate;
codec_context->time_base.num = 1;
ost->time_base.den = frame_rate;
ost->time_base.num = 1;
Debug( 1, "Will encode in %d fps.", codec_context->time_base.den );
Debug( 1, "Will encode in %d fps. %dx%d", codec_context->time_base.den, width, height );
/* emit one intra frame every second */
codec_context->gop_size = frame_rate;
@ -258,6 +260,10 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
codec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
#else
codec_context->flags |= CODEC_FLAG_GLOBAL_HEADER;
#endif
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
avcodec_parameters_from_context(ost->codecpar, codec_context);
zm_dump_codecpar(ost->codecpar);
#endif
} else {
Fatal( "of->video_codec == AV_CODEC_ID_NONE" );
@ -271,7 +277,7 @@ const char *VideoStream::MimeType( ) const {
for ( unsigned int i = 0; i < sizeof (mime_data) / sizeof (*mime_data); i++ ) {
if ( strcmp( format, mime_data[i].format ) == 0 ) {
Debug( 1, "MimeType is \"%s\"", mime_data[i].mime_type );
return ( mime_data[i].mime_type);
return mime_data[i].mime_type;
}
}
const char *mime_type = of->mime_type;
@ -282,9 +288,9 @@ const char *VideoStream::MimeType( ) const {
Warning( "Unable to determine mime type for '%s' format, using '%s' as default", format, mime_type );
}
Debug( 1, "MimeType is \"%s\"", mime_type );
Debug(1, "MimeType is \"%s\"", mime_type );
return ( mime_type);
return mime_type;
}
void VideoStream::OpenStream( ) {
@ -293,11 +299,13 @@ void VideoStream::OpenStream( ) {
/* now that all the parameters are set, we can open the
video codecs and allocate the necessary encode buffers */
if ( ost ) {
Debug(1,"Opening codec");
/* open the codec */
#if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0)
if ( (ret = avcodec_open( codec_context, codec )) < 0 )
if ( (ret = avcodec_open(codec_context, codec)) < 0 )
#else
if ( (ret = avcodec_open2( codec_context, codec, 0 )) < 0 )
if ( (ret = avcodec_open2(codec_context, codec, 0)) < 0 )
#endif
{
Fatal( "Could not open codec. Error code %d \"%s\"", ret, av_err2str(ret) );
@ -310,6 +318,9 @@ void VideoStream::OpenStream( ) {
if ( !opicture ) {
Panic( "Could not allocate opicture" );
}
opicture->width = codec_context->width;
opicture->height = codec_context->height;
opicture->format = codec_context->pix_fmt;
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
int size = av_image_get_buffer_size( codec_context->pix_fmt, codec_context->width, codec_context->height, 1 );
@ -362,7 +373,7 @@ void VideoStream::OpenStream( ) {
tmp_opicture_buf, pf, codec_context->width, codec_context->height );
#endif
}
}
} // end if ost
/* open the output file, if needed */
if ( !(of->flags & AVFMT_NOFILE) ) {
@ -384,8 +395,8 @@ void VideoStream::OpenStream( ) {
video_outbuf = NULL;
#if LIBAVFORMAT_VERSION_CHECK(57, 0, 0, 0, 0)
if (codec_context->codec_type == AVMEDIA_TYPE_VIDEO &&
codec_context->codec_id == AV_CODEC_ID_RAWVIDEO) {
if (codec_context->codec_type == AVMEDIA_TYPE_VIDEO &&
codec_context->codec_id == AV_CODEC_ID_RAWVIDEO) {
#else
if ( !(of->flags & AVFMT_RAWPICTURE) ) {
#endif
@ -408,7 +419,7 @@ void VideoStream::OpenStream( ) {
#if !LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 4, 0)
ret = av_write_header( ofc );
#else
ret = avformat_write_header( ofc, NULL );
ret = avformat_write_header(ofc, NULL);
#endif
if ( ret < 0 ) {
@ -451,6 +462,7 @@ VideoStream::VideoStream( const char *in_filename, const char *in_format, int bi
}
}
codec_context = NULL;
SetupFormat( );
SetupCodec( colours, subpixelorder, width, height, bitrate, frame_rate );
SetParameters( );
@ -466,7 +478,6 @@ VideoStream::VideoStream( const char *in_filename, const char *in_format, int bi
Fatal("pthread_mutex_init failed");
}
codec_context = NULL;
}
VideoStream::~VideoStream( ) {
@ -627,7 +638,6 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size,
opicture_ptr->quality = codec_context->global_quality;
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
// Put encoder into flushing mode
avcodec_send_frame(codec_context, opicture_ptr);
int ret = avcodec_receive_packet(codec_context, pkt);
if ( ret < 0 ) {

View File

@ -224,7 +224,7 @@ int main(int argc, char *argv[]) {
Info("Starting Capture version %s", ZM_VERSION);
static char sql[ZM_SQL_SML_BUFSIZ];
for ( int i = 0; i < n_monitors; i ++ ) {
snprintf( sql, sizeof(sql), "REPLACE INTO Monitor_Status (Id, Status ) VALUES ('%d','Running')", monitors[i]->Id() );
snprintf( sql, sizeof(sql), "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','Running')", monitors[i]->Id() );
if ( mysql_query( &dbconn, sql ) ) {
Error( "Can't run query: %s", mysql_error( &dbconn ) );
}
@ -239,128 +239,144 @@ int main(int argc, char *argv[]) {
sigaddset(&block_set, SIGUSR1);
sigaddset(&block_set, SIGUSR2);
monitors[0]->setStartupTime((time_t)time(NULL));
if ( monitors[0]->PrimeCapture() < 0 ) {
Error("Failed to prime capture of initial monitor");
exit(-1);
}
AnalysisThread **analysis_threads = new AnalysisThread *[n_monitors];
long *capture_delays = new long[n_monitors];
long *alarm_capture_delays = new long[n_monitors];
long *next_delays = new long[n_monitors];
struct timeval * last_capture_times = new struct timeval[n_monitors];
for ( int i = 0; i < n_monitors; i++ ) {
last_capture_times[i].tv_sec = last_capture_times[i].tv_usec = 0;
capture_delays[i] = monitors[i]->GetCaptureDelay();
alarm_capture_delays[i] = monitors[i]->GetAlarmCaptureDelay();
Debug(2, "capture delay(%u mSecs 1000/capture_fps) alarm delay(%u)", capture_delays[i], alarm_capture_delays[i] );
Monitor::Function function = monitors[0]->GetFunction();
if ( function == Monitor::MODECT || function == Monitor::MOCORD || function == Monitor::RECORD) {
Debug(1, "Starting an analysis thread for monitor (%d)", monitors[i]->Id());
analysis_threads[i] = new AnalysisThread(monitors[i]);
analysis_threads[i]->start();
} else {
analysis_threads[i] = NULL;
}
} // end foreach monitor
int result = 0;
struct timeval now;
struct DeltaTimeval delta_time;
while ( !zm_terminate ) {
//Debug(2,"blocking");
sigprocmask(SIG_BLOCK, &block_set, 0);
while( ! zm_terminate ) {
for ( int i = 0; i < n_monitors; i ++ ) {
time_t now = (time_t)time(NULL);
monitors[i]->setStartupTime(now);
}
// Outer primary loop, handles connection to camera
if ( monitors[0]->PrimeCapture() < 0 ) {
Error("Failed to prime capture of initial monitor");
sleep(10);
continue;
}
static char sql[ZM_SQL_SML_BUFSIZ];
for ( int i = 0; i < n_monitors; i ++ ) {
snprintf( sql, sizeof(sql), "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','Connected')", monitors[i]->Id() );
if ( mysql_query( &dbconn, sql ) ) {
Error( "Can't run query: %s", mysql_error( &dbconn ) );
}
}
AnalysisThread **analysis_threads = new AnalysisThread *[n_monitors];
long *capture_delays = new long[n_monitors];
long *alarm_capture_delays = new long[n_monitors];
long *next_delays = new long[n_monitors];
struct timeval * last_capture_times = new struct timeval[n_monitors];
for ( int i = 0; i < n_monitors; i++ ) {
long min_delay = MAXINT;
last_capture_times[i].tv_sec = last_capture_times[i].tv_usec = 0;
capture_delays[i] = monitors[i]->GetCaptureDelay();
alarm_capture_delays[i] = monitors[i]->GetAlarmCaptureDelay();
Debug(2, "capture delay(%u mSecs 1000/capture_fps) alarm delay(%u)", capture_delays[i], alarm_capture_delays[i] );
gettimeofday(&now, NULL);
for ( int j = 0; j < n_monitors; j++ ) {
if ( last_capture_times[j].tv_sec ) {
// We pretty much know this is positive.
DELTA_TIMEVAL(delta_time, now, last_capture_times[j], DT_PREC_3);
// capture_delay is the amount of time we should sleep to achieve the desired framerate.
if ( monitors[i]->GetState() == Monitor::ALARM )
next_delays[j] = alarm_capture_delays[j] - delta_time.delta;
else
next_delays[j] = capture_delays[j] - delta_time.delta;
if ( next_delays[j] < 0 )
next_delays[j] = 0;
} else {
next_delays[j] = 0;
}
if ( next_delays[j] <= min_delay ) {
min_delay = next_delays[j];
}
Monitor::Function function = monitors[0]->GetFunction();
if ( function == Monitor::MODECT || function == Monitor::MOCORD || function == Monitor::RECORD) {
Debug(1, "Starting an analysis thread for monitor (%d)", monitors[i]->Id());
analysis_threads[i] = new AnalysisThread(monitors[i]);
analysis_threads[i]->start();
} else {
analysis_threads[i] = NULL;
}
} // end foreach monitor
monitors[i]->CheckAction();
if ( next_delays[i] <= min_delay || next_delays[i] <= 0 ) {
if ( monitors[i]->PreCapture() < 0 ) {
Error("Failed to pre-capture monitor %d %d (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors);
zm_terminate = true;
result = -1;
break;
}
if ( monitors[i]->Capture() < 0 ) {
Error("Failed to capture image from monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors);
result = -1;
break;
}
if ( monitors[i]->PostCapture() < 0 ) {
Error("Failed to post-capture monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors);
zm_terminate = true;
result = -1;
break;
}
if ( next_delays[i] > 0 ) {
gettimeofday(&now, NULL);
DELTA_TIMEVAL(delta_time, now, last_capture_times[i], DT_PREC_3);
long sleep_time = next_delays[i] - delta_time.delta;
if ( sleep_time > 0 ) {
Debug(2,"usleeping (%d)", sleep_time*(DT_MAXGRAN/DT_PREC_3) );
usleep(sleep_time*(DT_MAXGRAN/DT_PREC_3));
}
last_capture_times[i] = now;
} else {
gettimeofday(&(last_capture_times[i]), NULL);
}
} // end if next_delay <= min_delay || next_delays[i] <= 0 )
} // end foreach n_monitors
//Debug(2,"unblocking");
sigprocmask(SIG_UNBLOCK, &block_set, 0);
if ( zm_reload ) {
struct timeval now;
struct DeltaTimeval delta_time;
while ( !zm_terminate ) {
//Debug(2,"blocking");
sigprocmask(SIG_BLOCK, &block_set, 0);
for ( int i = 0; i < n_monitors; i++ ) {
monitors[i]->Reload();
long min_delay = MAXINT;
gettimeofday(&now, NULL);
for ( int j = 0; j < n_monitors; j++ ) {
if ( last_capture_times[j].tv_sec ) {
// We pretty much know this is positive.
DELTA_TIMEVAL(delta_time, now, last_capture_times[j], DT_PREC_3);
// capture_delay is the amount of time we should sleep to achieve the desired framerate.
if ( monitors[i]->GetState() == Monitor::ALARM )
next_delays[j] = alarm_capture_delays[j] - delta_time.delta;
else
next_delays[j] = capture_delays[j] - delta_time.delta;
if ( next_delays[j] < 0 )
next_delays[j] = 0;
}
if ( next_delays[j] <= min_delay ) {
min_delay = next_delays[j];
}
} // end foreach monitor
monitors[i]->CheckAction();
if ( next_delays[i] <= min_delay || next_delays[i] <= 0 ) {
if ( monitors[i]->PreCapture() < 0 ) {
Error("Failed to pre-capture monitor %d %d (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors);
result = -1;
break;
}
if ( monitors[i]->Capture() < 0 ) {
Error("Failed to capture image from monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors);
result = -1;
break;
}
if ( monitors[i]->PostCapture() < 0 ) {
Error("Failed to post-capture monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors);
result = -1;
break;
}
if ( next_delays[i] > 0 ) {
gettimeofday(&now, NULL);
DELTA_TIMEVAL(delta_time, now, last_capture_times[i], DT_PREC_3);
long sleep_time = next_delays[i] - delta_time.delta;
if ( sleep_time > 0 ) {
Debug(2,"usleeping (%d)", sleep_time*(DT_MAXGRAN/DT_PREC_3) );
usleep(sleep_time*(DT_MAXGRAN/DT_PREC_3));
}
last_capture_times[i] = now;
} else {
gettimeofday(&(last_capture_times[i]), NULL);
}
} // end if next_delay <= min_delay || next_delays[i] <= 0 )
} // end foreach n_monitors
//Debug(2,"unblocking");
sigprocmask(SIG_UNBLOCK, &block_set, 0);
if ( zm_reload ) {
for ( int i = 0; i < n_monitors; i++ ) {
monitors[i]->Reload();
}
logTerm();
logInit( log_id_string );
zm_reload = false;
if ( result < 0 ) {
// Failure, try reconnecting
break;
}
} // end if zm_reload
} // end while ! zm_terminate and connected
delete [] alarm_capture_delays;
delete [] capture_delays;
delete [] next_delays;
delete [] last_capture_times;
// Killoff the analysis threads. Don't need them spinning while we try to reconnect
for ( int i = 0; i < n_monitors; i++ ) {
if ( analysis_threads[i] ) {
analysis_threads[i]->stop();
analysis_threads[i]->join();
delete analysis_threads[i];
analysis_threads[i] = 0;
}
logTerm();
logInit( log_id_string );
zm_reload = false;
}
} // end while ! zm_terminate
for ( int i = 0; i < n_monitors; i++ ) {
if ( analysis_threads[i] ) {
analysis_threads[i]->stop();
analysis_threads[i]->join();
delete analysis_threads[i];
analysis_threads[i] = 0;
}
delete monitors[i];
}
delete [] analysis_threads;
} // end foreach monitor
delete [] analysis_threads;
} // end while ! zm_terminate outer connection loop
delete [] monitors;
delete [] alarm_capture_delays;
delete [] capture_delays;
delete [] next_delays;
delete [] last_capture_times;
Image::Deinitialise();
logTerm();
zmDbClose();
return( result );
return result;
}

View File

@ -1 +1 @@
1.31.29
1.31.30

View File

@ -3,19 +3,19 @@
$start_time = time();
define( 'MSG_TIMEOUT', ZM_WEB_AJAX_TIMEOUT );
define( 'MSG_TIMEOUT', ZM_WEB_AJAX_TIMEOUT/2 );
define( 'MSG_DATA_SIZE', 4+256 );
if ( !($_REQUEST['connkey'] && $_REQUEST['command']) ) {
ajaxError( "Unexpected received message type '$type'" );
}
if ( !($socket = @socket_create( AF_UNIX, SOCK_DGRAM, 0 )) ) {
ajaxError( 'socket_create() failed: '.socket_strerror(socket_last_error()) );
}
$key = ftok(ZM_PATH_SOCKS.'/zms-'.sprintf("%06d",$_REQUEST['connkey']).'w.lock', 'Z');
$semaphore = sem_get($key,1);
if ( sem_acquire($semaphore,1) !== false ) {
if ( !($socket = @socket_create( AF_UNIX, SOCK_DGRAM, 0 )) ) {
ajaxError( 'socket_create() failed: '.socket_strerror(socket_last_error()) );
}
$localSocketFile = ZM_PATH_SOCKS.'/zms-'.sprintf('%06d',$_REQUEST['connkey']).'w.sock';
if ( file_exists( $localSocketFile ) ) {
@ -60,8 +60,11 @@ if ( sem_acquire($semaphore,1) !== false ) {
$max_socket_tries = 10;
// FIXME This should not exceed web_ajax_timeout
while ( !file_exists($remSockFile) && $max_socket_tries-- ) { //sometimes we are too fast for our own good, if it hasn't been setup yet give it a second.
// WHY? We will just send another one...
// ANSWER: Because otherwise we get a log of errors logged
//Logger::Debug("$remSockFile does not exist, waiting, current " . (time() - $start_time) . ' seconds' );
usleep(200000);
usleep(1000);
}
if ( !file_exists($remSockFile) ) {

@ -1 +1 @@
Subproject commit 7108489f218c54d36d235d3af91d6da2f8311237
Subproject commit ca91b87fda8e006e4fca2ed870f24f9a29c2905d

View File

@ -269,14 +269,14 @@ function getVideoStreamHTML( $id, $src, $width, $height, $format, $title='' ) {
if ( isWindows() ) {
return '<object id="'.$id.'" width="'.$width.'" height="'.$height.'
classid="CLSID:22D6F312-B0F6-11D0-94AB-0080C74C7E95"
codebase="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=6,0,02,902"
codebase="'.ZM_BASE_PROTOCOL.'://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=6,0,02,902"
standby="Loading Microsoft Windows Media Player components..."
type="'.$mimeType.'">
<param name="FileName" value="'.$src.'"/>
<param name="autoStart" value="1"/>
<param name="showControls" value="0"/>
<embed type="'.$mimeType.'"
pluginspage="http://www.microsoft.com/Windows/MediaPlayer/"
pluginspage="'.ZM_BASE_PROTOCOL.'://www.microsoft.com/Windows/MediaPlayer/"
src="'.$src.'"
name="'.$title.'"
width="'.$width.'"
@ -291,14 +291,14 @@ function getVideoStreamHTML( $id, $src, $width, $height, $format, $title='' ) {
{
return '<object id="'.$id.'" width="'.$width.'" height="'.$height.'"
classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"
codebase="http://www.apple.com/qtactivex/qtplugin.cab"
codebase="'.ZM_BASE_PROTOCOL.'://www.apple.com/qtactivex/qtplugin.cab"
type="'.$mimeType.'">
<param name="src" value="'.$src.'"/>
<param name="autoplay" VALUE="true"/>
<param name="controller" VALUE="false"/>
<embed type="'.$mimeType.'"
src="'.$src.'"
pluginspage="http://www.apple.com/quicktime/download/"
pluginspage="'.ZM_BASE_PROTOCOL.'://www.apple.com/quicktime/download/"
name="'.$title.'" width="'.$width.'" height="'.$height.'"
autoplay="true"
controller="true">
@ -309,13 +309,13 @@ function getVideoStreamHTML( $id, $src, $width, $height, $format, $title='' ) {
{
return '<object id="'.$id.'" width="'.$width.'" height="'.$height.'"
classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"
codebase="'.ZM_BASE_PROTOCOL.'://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"
type="'.$mimeType.'">
<param name="movie" value="'.$src.'"/>
<param name="quality" value="high"/>
<param name="bgcolor" value="#ffffff"/>
<embed type="'.$mimeType.'"
pluginspage="http://www.macromedia.com/go/getflashplayer"
pluginspage="'.ZM_BASE_PROTOCOL.'://www.macromedia.com/go/getflashplayer"
src="'.$src.'"
name="'.$title.'"
width="'.$width.'"

View File

@ -173,12 +173,15 @@ if ( isset($_REQUEST['request']) )
foreach ( getSkinIncludes( 'skin.php' ) as $includeFile )
require_once $includeFile;
if ( ZM_OPT_USE_AUTH && ZM_AUTH_HASH_LOGINS ) {
if ( empty($user) && ! empty($_REQUEST['auth']) ) {
if ( $authUser = getAuthUser( $_REQUEST['auth'] ) ) {
userLogin( $authUser['Username'], $authUser['Password'], true );
if ( ZM_OPT_USE_AUTH ) {
if ( ZM_AUTH_HASH_LOGINS ) {
if ( empty($user) && ! empty($_REQUEST['auth']) ) {
if ( $authUser = getAuthUser( $_REQUEST['auth'] ) ) {
userLogin( $authUser['Username'], $authUser['Password'], true );
}
}
} else if ( ! empty($user) ) {
}
if ( ! empty($user) ) {
// generate it once here, while session is open. Value will be cached in session and return when called later on
generateAuthHash( ZM_AUTH_HASH_IPS );
}

View File

@ -245,6 +245,11 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
$url_parts = parse_url( $monitor['Path'] );
unset($url_parts['user']);
unset($url_parts['pass']);
unset($url_parts['scheme']);
unset($url_parts['query']);
unset($url_parts['path']);
if ( isset($url_parts['port']) and ( $url_parts['port'] == '80' or $url_parts['port'] == '554' ) )
unset($url_parts['port']);
$source = unparse_url( $url_parts );
}
if ( $source == '' ) {
@ -285,9 +290,10 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
<td class="colId"><?php echo count($displayMonitors) ?></td>
<td class="colLeftButtons" colspan="<?php echo $left_columns -1?>">
<input type="button" value="<?php echo translate('Refresh') ?>" onclick="location.reload(true);"/>
<input type="button" name="addBtn" value="<?php echo translate('AddNewMonitor') ?>" onclick="addMonitor(this);"
<!--<input type="button" name="addBtn" value="<?php echo translate('AddNewMonitor') ?>" onclick="addMonitor(this);"
<?php echo (canEdit( 'Monitors' ) && !$user['MonitorIds']) ? '' : ' disabled="disabled"' ?>
/>
/>-->
<?php echo makePopupButton( '?view=monitor', 'zmMonitor0', 'monitor', translate('AddNewMonitor'), (canEdit( 'Monitors' ) && !$user['MonitorIds']) ) ?>
<input type="button" name="editBtn" value="<?php echo translate('Edit') ?>" onclick="editMonitor( this )" disabled="disabled"/>
<input type="button" name="deleteBtn" value="<?php echo translate('Delete') ?>" onclick="deleteMonitor( this )" disabled="disabled"/>
</td>

View File

@ -56,64 +56,66 @@ function Monitor( monitorData ) {
var stream = $j('#liveStream'+this.id)[0];
if ( respObj.result == 'Ok' ) {
this.status = respObj.status;
this.alarmState = this.status.state;
if ( respObj.status ) {
this.status = respObj.status;
this.alarmState = this.status.state;
var stateClass = "";
if ( this.alarmState == STATE_ALARM )
stateClass = "alarm";
else if ( this.alarmState == STATE_ALERT )
stateClass = "alert";
else
stateClass = "idle";
var stateClass = "";
if ( this.alarmState == STATE_ALARM )
stateClass = "alarm";
else if ( this.alarmState == STATE_ALERT )
stateClass = "alert";
else
stateClass = "idle";
if ( !COMPACT_MONTAGE ) {
$('fpsValue'+this.id).set( 'text', this.status.fps );
$('stateValue'+this.id).set( 'text', stateStrings[this.alarmState] );
this.setStateClass( $('monitorState'+this.id), stateClass );
}
this.setStateClass( $('monitor'+this.id), stateClass );
if ( !COMPACT_MONTAGE ) {
$('fpsValue'+this.id).set( 'text', this.status.fps );
$('stateValue'+this.id).set( 'text', stateStrings[this.alarmState] );
this.setStateClass( $('monitorState'+this.id), stateClass );
}
this.setStateClass( $('monitor'+this.id), stateClass );
/*Stream could be an applet so can't use moo tools*/
stream.className = stateClass;
/*Stream could be an applet so can't use moo tools*/
stream.className = stateClass;
var isAlarmed = ( this.alarmState == STATE_ALARM || this.alarmState == STATE_ALERT );
var wasAlarmed = ( this.lastAlarmState == STATE_ALARM || this.lastAlarmState == STATE_ALERT );
var isAlarmed = ( this.alarmState == STATE_ALARM || this.alarmState == STATE_ALERT );
var wasAlarmed = ( this.lastAlarmState == STATE_ALARM || this.lastAlarmState == STATE_ALERT );
var newAlarm = ( isAlarmed && !wasAlarmed );
var oldAlarm = ( !isAlarmed && wasAlarmed );
var newAlarm = ( isAlarmed && !wasAlarmed );
var oldAlarm = ( !isAlarmed && wasAlarmed );
if ( newAlarm ) {
if ( newAlarm ) {
if ( false && SOUND_ON_ALARM ) {
// Enable the alarm sound
$('alarmSound').removeClass( 'hidden' );
}
if ( POPUP_ON_ALARM ) {
windowToFront();
}
}
if ( false && SOUND_ON_ALARM ) {
// Enable the alarm sound
$('alarmSound').removeClass( 'hidden' );
if ( oldAlarm ) {
// Disable alarm sound
$('alarmSound').addClass( 'hidden' );
}
}
if ( POPUP_ON_ALARM ) {
windowToFront();
}
}
if ( false && SOUND_ON_ALARM ) {
if ( oldAlarm ) {
// Disable alarm sound
$('alarmSound').addClass( 'hidden' );
}
}
if ( this.status.auth ) {
if ( this.status.auth != auth_hash ) {
// Try to reload the image stream.
if ( stream )
stream.src = stream.src.replace( /auth=\w+/i, 'auth='+this.status.auth );
console.log("Changed auth from " + auth_hash + " to " + this.status.auth );
auth_hash = this.status.auth;
}
} // end if have a new auth hash
if ( this.status.auth ) {
if ( this.status.auth != auth_hash ) {
// Try to reload the image stream.
if ( stream )
stream.src = stream.src.replace( /auth=\w+/i, 'auth='+this.status.auth );
console.log("Changed auth from " + auth_hash + " to " + this.status.auth );
auth_hash = this.status.auth;
}
} // end if have a new auth hash
} // end if has state
} else {
console.error( respObj.message );
// Try to reload the image stream.
if ( stream ) {
if ( stream.src ) {
console.log('Reloading stream: ' + stream.src );
stream.src = stream.src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) ));
console.log('Reloading stream: ' + stream.src );
stream.src = stream.src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) ));
} else {
}
} else {