Merge branch 'storageareas' into zma_to_thread
Conflicts: src/zm_ffmpeg_camera.cpp src/zm_mpeg.cpp src/zmc.cpppull/3122/head
commit
a1392bf613
|
@ -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`)
|
||||
|
|
|
@ -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;
|
|
@ -3,5 +3,3 @@
|
|||
# Process the perl modules subdirectory
|
||||
add_subdirectory(proxy)
|
||||
add_subdirectory(modules)
|
||||
add_subdirectory(scripts)
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
240
src/zmc.cpp
240
src/zmc.cpp
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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.'"
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue