Merge branch 'zma_to_thread' of github.com:ConnorTechnology/ZoneMinder into zma_to_thread
This commit is contained in:
commit
29782ee938
|
@ -232,6 +232,7 @@ CREATE TABLE `Filters` (
|
||||||
`AutoExecute` tinyint(3) unsigned NOT NULL default '0',
|
`AutoExecute` tinyint(3) unsigned NOT NULL default '0',
|
||||||
`AutoExecuteCmd` tinytext,
|
`AutoExecuteCmd` tinytext,
|
||||||
`AutoDelete` tinyint(3) unsigned NOT NULL default '0',
|
`AutoDelete` tinyint(3) unsigned NOT NULL default '0',
|
||||||
|
`UpdateDiskSpace` tinyint(3) unsigned NOT NULL default '0',
|
||||||
`Background` tinyint(1) unsigned NOT NULL default '0',
|
`Background` tinyint(1) unsigned NOT NULL default '0',
|
||||||
`Concurrent` tinyint(1) unsigned NOT NULL default '0',
|
`Concurrent` tinyint(1) unsigned NOT NULL default '0',
|
||||||
PRIMARY KEY (`Id`),
|
PRIMARY KEY (`Id`),
|
||||||
|
@ -289,6 +290,7 @@ CREATE TABLE `Logs` (
|
||||||
) ENGINE=@ZM_MYSQL_ENGINE@;
|
) ENGINE=@ZM_MYSQL_ENGINE@;
|
||||||
|
|
||||||
CREATE INDEX `Logs_TimeKey_idx` ON `Logs` (`TimeKey`);
|
CREATE INDEX `Logs_TimeKey_idx` ON `Logs` (`TimeKey`);
|
||||||
|
CREATE INDEX `Logs_Level_idx` ON `Logs` (`Level`);
|
||||||
--
|
--
|
||||||
-- Table structure for table `Manufacturers`
|
-- Table structure for table `Manufacturers`
|
||||||
--
|
--
|
||||||
|
@ -382,6 +384,8 @@ CREATE TABLE `Monitors` (
|
||||||
`Deinterlacing` int(10) unsigned NOT NULL default '0',
|
`Deinterlacing` int(10) unsigned NOT NULL default '0',
|
||||||
`SaveJPEGs` TINYINT NOT NULL DEFAULT '3' ,
|
`SaveJPEGs` TINYINT NOT NULL DEFAULT '3' ,
|
||||||
`VideoWriter` TINYINT NOT NULL DEFAULT '0',
|
`VideoWriter` TINYINT NOT NULL DEFAULT '0',
|
||||||
|
`OutputCodec` enum('h264','mjpeg'),
|
||||||
|
`OutputContainer` enum('mp4','mkv'),
|
||||||
`EncoderParameters` TEXT,
|
`EncoderParameters` TEXT,
|
||||||
`RecordAudio` TINYINT NOT NULL DEFAULT '0',
|
`RecordAudio` TINYINT NOT NULL DEFAULT '0',
|
||||||
`RTSPDescribe` tinyint(1) unsigned,
|
`RTSPDescribe` tinyint(1) unsigned,
|
||||||
|
@ -632,7 +636,7 @@ insert into Users VALUES (NULL,'admin',password('admin'),'',1,'View','Edit','Edi
|
||||||
--
|
--
|
||||||
-- Add a sample filter to purge the oldest 100 events when the disk is 95% full
|
-- Add a sample filter to purge the oldest 100 events when the disk is 95% full
|
||||||
--
|
--
|
||||||
insert into Filters values (NULL,'PurgeWhenFull','{"sort_field":"Id","terms":[{"val":0,"attr":"Archived","op":"="},{"cnj":"and","val":95,"attr":"DiskPercent","op":">="}],"limit":100,"sort_asc":1}',0,0,0,0,0,0,'',1,1,0);
|
insert into Filters values (NULL,'PurgeWhenFull','{"sort_field":"Id","terms":[{"val":0,"attr":"Archived","op":"="},{"cnj":"and","val":95,"attr":"DiskPercent","op":">="}],"limit":100,"sort_asc":1}',0,0,0,0,0,0,'',1,0,1,0);
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Add in some sample control protocol definitions
|
-- Add in some sample control protocol definitions
|
||||||
|
@ -760,6 +764,21 @@ CREATE TABLE Maps (
|
||||||
`ParentId` int(1) unsigned,
|
`ParentId` int(1) unsigned,
|
||||||
PRIMARY KEY (`Id`)
|
PRIMARY KEY (`Id`)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE MontageLayouts (
|
||||||
|
`Id` int(10) unsigned NOT NULL auto_increment,
|
||||||
|
`Name` TEXT NOT NULL,
|
||||||
|
`Positions` LONGTEXT,
|
||||||
|
/*`Positions` JSON,*/
|
||||||
|
PRIMARY KEY (`Id`)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('Freeform', '{ "default":{"float":"left","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' );
|
||||||
|
INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('2 Wide', '{ "default":{"float":"left", "width":"49%","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' );
|
||||||
|
INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('3 Wide', '{ "default":{"float":"left", "width":"33%","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' );
|
||||||
|
INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('4 Wide', '{ "default":{"float":"left", "width":"24.5%","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' );
|
||||||
|
INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('5 Wide', '{ "default":{"float":"left", "width":"19%","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' );
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Apply the initial configuration
|
-- Apply the initial configuration
|
||||||
--
|
--
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
--
|
||||||
|
-- Add UpdateDiskSpace action to Filters
|
||||||
|
--
|
||||||
|
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'Filters'
|
||||||
|
AND column_name = 'UpdateDiskSpace'
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Column UpdateDiskSpace already exists in Filters'",
|
||||||
|
"ALTER TABLE Filters ADD `UpdateDiskSpace` tinyint(3) unsigned NOT NULL default '0' AFTER `AutoDelete`"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
||||||
|
--
|
||||||
|
-- Update Logs table to have some Indexes
|
||||||
|
--
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*)
|
||||||
|
FROM INFORMATION_SCHEMA.STATISTICS
|
||||||
|
WHERE table_name = 'Logs'
|
||||||
|
AND table_schema = DATABASE()
|
||||||
|
AND index_name = 'Logs_TimeKey_idx'
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Logs_TimeKey_idx already exists on Logs table'",
|
||||||
|
"CREATE INDEX `Logs_TimeKey_idx` ON `Logs` (`TimeKey`)"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
||||||
|
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*)
|
||||||
|
FROM INFORMATION_SCHEMA.STATISTICS
|
||||||
|
WHERE table_name = 'Logs'
|
||||||
|
AND table_schema = DATABASE()
|
||||||
|
AND index_name = 'Logs_Level_idx'
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Logs_Level_idx already exists on Logs table'",
|
||||||
|
"CREATE INDEX `Logs_Level_idx` ON `Logs` (`Level`)"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
||||||
|
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'Monitors'
|
||||||
|
AND column_name = 'OutputCodec'
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Column OutputCodec already exists in Monitors'",
|
||||||
|
"ALTER TABLE `Monitors` ADD `OutputCodec` enum('h264','mjpeg') AFTER `VideoWriter`"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
||||||
|
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'Monitors'
|
||||||
|
AND column_name = 'OutputContainer'
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'Column OutputContainer already exists in Monitors'",
|
||||||
|
"ALTER TABLE `Monitors` ADD `OutputContainer` enum('mp4','mkv') AFTER `OutputCodec`"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
|
@ -0,0 +1,67 @@
|
||||||
|
--
|
||||||
|
-- This adds Manufacturers and Models
|
||||||
|
--
|
||||||
|
|
||||||
|
SET @s = (SELECT IF(
|
||||||
|
(SELECT COUNT(*)
|
||||||
|
FROM INFORMATION_SCHEMA.TABLES
|
||||||
|
WHERE table_name = 'MontageLayouts'
|
||||||
|
AND table_schema = DATABASE()
|
||||||
|
) > 0,
|
||||||
|
"SELECT 'MontageLayouts table exists'",
|
||||||
|
"
|
||||||
|
CREATE TABLE MontageLayouts (
|
||||||
|
`Id` int(10) unsigned NOT NULL auto_increment,
|
||||||
|
`Name` TEXT NOT NULL,
|
||||||
|
`Positions` LONGTEXT,
|
||||||
|
PRIMARY KEY (`Id`)
|
||||||
|
);
|
||||||
|
"
|
||||||
|
));
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
||||||
|
|
||||||
|
DELETE FROM MontageLayouts WHERE Name IN ('Freeform','2 Wide','3 Wide','4 Wide','5 Wide');
|
||||||
|
|
||||||
|
SET @s = ( SELECT IF(
|
||||||
|
(SELECT COUNT(*) FROM MontageLayouts WHERE Name='Freeform') > 0,
|
||||||
|
"SELECT 'Freeform already in layouts'",
|
||||||
|
'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'Freeform\', \'{"default":{"float":"left","position":"relative","left":"0px","right":"0px","top":"0px","bottom":"0px"}}\');'
|
||||||
|
) );
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
||||||
|
|
||||||
|
SET @s = ( SELECT IF(
|
||||||
|
(SELECT COUNT(*) FROM MontageLayouts WHERE Name='2 Wide') > 0,
|
||||||
|
"SELECT '2 Wide already in layouts'",
|
||||||
|
'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'2 Wide\', \'{"default":{"float":"left","position":"relative","width":"49%","left":"0px","right":"0px","top":"0px","bottom":"0px"}}\');'
|
||||||
|
) );
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
||||||
|
|
||||||
|
SET @s = ( SELECT IF(
|
||||||
|
(SELECT COUNT(*) FROM MontageLayouts WHERE Name='3 Wide') > 0,
|
||||||
|
"SELECT '3 Wide already in layouts'",
|
||||||
|
'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'3 Wide\', \'{"default":{"float":"left","position":"relative","width":"33%","left":"0px","right":"0px","top":"0px","bottom":"0px"}}\');'
|
||||||
|
) );
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
||||||
|
|
||||||
|
SET @s = ( SELECT IF(
|
||||||
|
(SELECT COUNT(*) FROM MontageLayouts WHERE Name='4 Wide') > 0,
|
||||||
|
"SELECT '4 Wide already in layouts'",
|
||||||
|
'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'4 Wide\', \'{"default":{"float":"left","position":"relative","width":"24.5%","left":"0px","right":"0px","top":"0px","bottom":"0px"}}\');'
|
||||||
|
) );
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
||||||
|
|
||||||
|
SET @s = ( SELECT IF(
|
||||||
|
(SELECT COUNT(*) FROM MontageLayouts WHERE Name='5 Wide') > 0,
|
||||||
|
"SELECT '5 Wide already in layouts'",
|
||||||
|
'INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES (\'5 Wide\', \'{"default":{"float":"left","position":"relative","width":"19%"}}\' );'
|
||||||
|
) );
|
||||||
|
|
||||||
|
PREPARE stmt FROM @s;
|
||||||
|
EXECUTE stmt;
|
|
@ -27,7 +27,8 @@ override_dh_auto_configure:
|
||||||
-DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \
|
-DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \
|
||||||
-DZM_DIR_EVENTS="/var/cache/zoneminder/events" \
|
-DZM_DIR_EVENTS="/var/cache/zoneminder/events" \
|
||||||
-DZM_DIR_IMAGES="/var/cache/zoneminder/images" \
|
-DZM_DIR_IMAGES="/var/cache/zoneminder/images" \
|
||||||
-DZM_PATH_ZMS="/zm/cgi-bin/nph-zms"
|
-DZM_PATH_ZMS="/zm/cgi-bin/nph-zms" \
|
||||||
|
-DZM_NO_LIBVLC=1
|
||||||
|
|
||||||
override_dh_clean:
|
override_dh_clean:
|
||||||
dh_clean $(MANPAGES1)
|
dh_clean $(MANPAGES1)
|
||||||
|
|
|
@ -4,5 +4,6 @@ var/cache/zoneminder/events
|
||||||
var/cache/zoneminder/images
|
var/cache/zoneminder/images
|
||||||
var/cache/zoneminder/temp
|
var/cache/zoneminder/temp
|
||||||
usr/share/zoneminder/db
|
usr/share/zoneminder/db
|
||||||
|
usr/share/zoneminder/www/cache
|
||||||
etc/zm/
|
etc/zm/
|
||||||
etc/zm/conf.d
|
etc/zm/conf.d
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
d /var/run/zm 0755 www-data www-data
|
d /var/run/zm 0755 www-data www-data
|
||||||
d /tmp/zm 0755 www-data www-data
|
d /tmp/zm 0755 www-data www-data
|
||||||
d /var/tmp/zm 0755 www-data www-data
|
d /var/tmp/zm 0755 www-data www-data
|
||||||
|
d /usr/share/zoneminder/www/cache 0755 www-data www-data
|
||||||
|
|
|
@ -115,7 +115,7 @@ BEGIN {
|
||||||
, $Config{ZM_DB_USER}
|
, $Config{ZM_DB_USER}
|
||||||
, $Config{ZM_DB_PASS}
|
, $Config{ZM_DB_PASS}
|
||||||
) or croak( "Can't connect to db" );
|
) or croak( "Can't connect to db" );
|
||||||
my $sql = 'select * from Config';
|
my $sql = 'SELECT Name,Value FROM Config';
|
||||||
my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||||
my $res = $sth->execute() or croak( "Can't execute: ".$sth->errstr() );
|
my $res = $sth->execute() or croak( "Can't execute: ".$sth->errstr() );
|
||||||
while( my $config = $sth->fetchrow_hashref() ) {
|
while( my $config = $sth->fetchrow_hashref() ) {
|
||||||
|
|
|
@ -205,6 +205,30 @@ sub zmDbGetMonitorAndControl {
|
||||||
return( $monitor );
|
return( $monitor );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub start_transaction {
|
||||||
|
#my ( $caller, undef, $line ) = caller;
|
||||||
|
#$openprint::log->debug("Called start_transaction from $caller : $line");
|
||||||
|
my $d = shift;
|
||||||
|
$d = $dbh if ! $d;
|
||||||
|
my $ac = $d->{AutoCommit};
|
||||||
|
$d->{AutoCommit} = 0;
|
||||||
|
return $ac;
|
||||||
|
} # end sub start_transaction
|
||||||
|
|
||||||
|
sub end_transaction {
|
||||||
|
#my ( $caller, undef, $line ) = caller;
|
||||||
|
#$openprint::log->debug("Called end_transaction from $caller : $line");
|
||||||
|
my ( $d, $ac ) = @_;
|
||||||
|
if ( ! defined $ac ) {
|
||||||
|
Error("Undefined ac");
|
||||||
|
}
|
||||||
|
$d = $dbh if ! $d;
|
||||||
|
if ( $ac ) {
|
||||||
|
#$log->debug("Committing");
|
||||||
|
$d->commit();
|
||||||
|
} # end if
|
||||||
|
$d->{AutoCommit} = $ac;
|
||||||
|
} # end sub end_transaction
|
||||||
1;
|
1;
|
||||||
__END__
|
__END__
|
||||||
# Below is stub documentation for your module. You'd better edit it!
|
# Below is stub documentation for your module. You'd better edit it!
|
||||||
|
|
|
@ -48,9 +48,38 @@ use ZoneMinder::Logger qw(:all);
|
||||||
use ZoneMinder::Database qw(:all);
|
use ZoneMinder::Database qw(:all);
|
||||||
require Date::Parse;
|
require Date::Parse;
|
||||||
|
|
||||||
use vars qw/ $table $primary_key /;
|
use vars qw/ $table $primary_key %fields $serial @identified_by/;
|
||||||
$table = 'Events';
|
$table = 'Events';
|
||||||
$primary_key = 'Id';
|
@identified_by = ('Id');
|
||||||
|
$serial = $primary_key = 'Id';
|
||||||
|
%fields = map { $_, $_ } qw(
|
||||||
|
Id
|
||||||
|
MonitorId
|
||||||
|
StorageId
|
||||||
|
Name
|
||||||
|
Cause
|
||||||
|
StartTime
|
||||||
|
EndTime
|
||||||
|
Width
|
||||||
|
Height
|
||||||
|
Length
|
||||||
|
Frames
|
||||||
|
AlarmFrames
|
||||||
|
DefaultVideo
|
||||||
|
TotScore
|
||||||
|
AvgScore
|
||||||
|
MaxScore
|
||||||
|
Archived
|
||||||
|
Videoed
|
||||||
|
Uploaded
|
||||||
|
Emailed
|
||||||
|
Messaged
|
||||||
|
Executed
|
||||||
|
Notes
|
||||||
|
StateId
|
||||||
|
Orientation
|
||||||
|
DiskSpace
|
||||||
|
);
|
||||||
|
|
||||||
use POSIX;
|
use POSIX;
|
||||||
|
|
||||||
|
@ -359,14 +388,16 @@ sub age {
|
||||||
return $_[0]{age};
|
return $_[0]{age};
|
||||||
}
|
}
|
||||||
|
|
||||||
sub DiskUsage {
|
sub DiskSpace {
|
||||||
if ( @_ > 1 ) {
|
if ( @_ > 1 ) {
|
||||||
$_[0]{DiskUsage} = $_[1];
|
Debug("Cleared DiskSpace, was $_[0]{DiskSpace}");
|
||||||
|
$_[0]{DiskSpace} = $_[1];
|
||||||
}
|
}
|
||||||
if ( ! defined $_[0]{DiskUsage} ) {
|
if ( ! defined $_[0]{DiskSpace} ) {
|
||||||
my $size = 0;
|
my $size = 0;
|
||||||
File::Find::find( { wanted=>sub { $size += -f $_ ? -s _ : 0 }, untaint=>1 }, $_[0]->Path() );
|
File::Find::find( { wanted=>sub { $size += -f $_ ? -s _ : 0 }, untaint=>1 }, $_[0]->Path() );
|
||||||
$_[0]{DiskUsage} = $size;
|
$_[0]{DiskSpace} = $size;
|
||||||
|
Debug("DiskSpace for event $_[0]{Id} at $_[0]{Path} Updated to $size bytes");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -125,7 +125,7 @@ sub Execute {
|
||||||
push @results, $event;
|
push @results, $event;
|
||||||
}
|
}
|
||||||
$sth->finish();
|
$sth->finish();
|
||||||
Debug("Loaded " . @results . " events for filter $_[0]{Name} using query ($sql)");
|
Debug('Loaded ' . @results . " events for filter $_[0]{Name} using query ($sql)");
|
||||||
return @results;
|
return @results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,38 +147,59 @@ sub Sql {
|
||||||
foreach my $term ( @{$filter_expr->{terms}} ) {
|
foreach my $term ( @{$filter_expr->{terms}} ) {
|
||||||
|
|
||||||
if ( exists($term->{cnj}) ) {
|
if ( exists($term->{cnj}) ) {
|
||||||
$self->{Sql} .= " ".$term->{cnj}." ";
|
$self->{Sql} .= ' '.$term->{cnj}." ";
|
||||||
}
|
}
|
||||||
if ( exists($term->{obr}) ) {
|
if ( exists($term->{obr}) ) {
|
||||||
$self->{Sql} .= " ".str_repeat( "(", $term->{obr} )." ";
|
$self->{Sql} .= ' '.str_repeat( "(", $term->{obr} )." ";
|
||||||
}
|
}
|
||||||
my $value = $term->{val};
|
my $value = $term->{val};
|
||||||
my @value_list;
|
my @value_list;
|
||||||
if ( $term->{attr} ) {
|
if ( $term->{attr} ) {
|
||||||
if ( $term->{attr} =~ /^Monitor/ ) {
|
if ( $term->{attr} =~ /^Monitor/ ) {
|
||||||
my ( $temp_attr_name ) = $term->{attr} =~ /^Monitor(.+)$/;
|
my ( $temp_attr_name ) = $term->{attr} =~ /^Monitor(.+)$/;
|
||||||
$self->{Sql} .= "M.".$temp_attr_name;
|
$self->{Sql} .= 'M.'.$temp_attr_name;
|
||||||
} elsif ( $term->{attr} =~ /^Server/ ) {
|
} elsif ( $term->{attr} =~ /^Server/ ) {
|
||||||
$self->{Sql} .= "M.".$term->{attr};
|
$self->{Sql} .= 'M.'.$term->{attr};
|
||||||
|
|
||||||
|
# StartTime options
|
||||||
} elsif ( $term->{attr} eq 'DateTime' ) {
|
} elsif ( $term->{attr} eq 'DateTime' ) {
|
||||||
$self->{Sql} .= "E.StartTime";
|
$self->{Sql} .= 'E.StartTime';
|
||||||
|
} elsif ( $term->{attr} eq 'StartDateTime' ) {
|
||||||
|
$self->{Sql} .= 'E.StartTime';
|
||||||
} elsif ( $term->{attr} eq 'Date' ) {
|
} elsif ( $term->{attr} eq 'Date' ) {
|
||||||
$self->{Sql} .= "to_days( E.StartTime )";
|
$self->{Sql} .= 'to_days( E.StartTime )';
|
||||||
|
} elsif ( $term->{attr} eq 'StartDate' ) {
|
||||||
|
$self->{Sql} .= 'to_days( E.StartTime )';
|
||||||
} elsif ( $term->{attr} eq 'Time' ) {
|
} elsif ( $term->{attr} eq 'Time' ) {
|
||||||
$self->{Sql} .= "extract( hour_second from E.StartTime )";
|
$self->{Sql} .= "extract( hour_second from E.StartTime )";
|
||||||
} elsif ( $term->{attr} eq 'Weekday' ) {
|
} elsif ( $term->{attr} eq 'Weekday' ) {
|
||||||
$self->{Sql} .= "weekday( E.StartTime )";
|
$self->{Sql} .= "weekday( E.StartTime )";
|
||||||
|
|
||||||
|
# EndTIme options
|
||||||
|
} elsif ( $term->{attr} eq 'EndDateTime' ) {
|
||||||
|
$self->{Sql} .= 'E.EndTime';
|
||||||
|
} elsif ( $term->{attr} eq 'EndDate' ) {
|
||||||
|
$self->{Sql} .= 'to_days( E.EndTime )';
|
||||||
|
} elsif ( $term->{attr} eq 'EndTime' ) {
|
||||||
|
$self->{Sql} .= "extract( hour_second from E.EndTime )";
|
||||||
|
} elsif ( $term->{attr} eq 'EndWeekday' ) {
|
||||||
|
$self->{Sql} .= "weekday( E.EndTime )";
|
||||||
|
|
||||||
|
#
|
||||||
|
} elsif ( $term->{attr} eq 'DiskSpace' ) {
|
||||||
|
$self->{Sql} .= 'E.DiskSpace';
|
||||||
|
$self->{HasDiskPercent} = !undef;
|
||||||
} elsif ( $term->{attr} eq 'DiskPercent' ) {
|
} elsif ( $term->{attr} eq 'DiskPercent' ) {
|
||||||
$self->{Sql} .= "zmDiskPercent";
|
$self->{Sql} .= 'zmDiskPercent';
|
||||||
$self->{HasDiskPercent} = !undef;
|
$self->{HasDiskPercent} = !undef;
|
||||||
} elsif ( $term->{attr} eq 'DiskBlocks' ) {
|
} elsif ( $term->{attr} eq 'DiskBlocks' ) {
|
||||||
$self->{Sql} .= "zmDiskBlocks";
|
$self->{Sql} .= 'zmDiskBlocks';
|
||||||
$self->{HasDiskBlocks} = !undef;
|
$self->{HasDiskBlocks} = !undef;
|
||||||
} elsif ( $term->{attr} eq 'SystemLoad' ) {
|
} elsif ( $term->{attr} eq 'SystemLoad' ) {
|
||||||
$self->{Sql} .= "zmSystemLoad";
|
$self->{Sql} .= 'zmSystemLoad';
|
||||||
$self->{HasSystemLoad} = !undef;
|
$self->{HasSystemLoad} = !undef;
|
||||||
} else {
|
} else {
|
||||||
$self->{Sql} .= "E.".$term->{attr};
|
$self->{Sql} .= 'E.'.$term->{attr};
|
||||||
}
|
}
|
||||||
|
|
||||||
( my $stripped_value = $value ) =~ s/^["\']+?(.+)["\']+?$/$1/;
|
( my $stripped_value = $value ) =~ s/^["\']+?(.+)["\']+?$/$1/;
|
||||||
|
@ -203,7 +224,7 @@ sub Sql {
|
||||||
|| $term->{attr} eq 'Notes'
|
|| $term->{attr} eq 'Notes'
|
||||||
) {
|
) {
|
||||||
$value = "'$temp_value'";
|
$value = "'$temp_value'";
|
||||||
} elsif ( $term->{attr} eq 'DateTime' ) {
|
} elsif ( $term->{attr} eq 'DateTime' or $term->{attr} eq 'StartDateTime' or $term->{attr} eq 'EndDateTime' ) {
|
||||||
$value = DateTimeToSQL( $temp_value );
|
$value = DateTimeToSQL( $temp_value );
|
||||||
if ( !$value ) {
|
if ( !$value ) {
|
||||||
Error( "Error parsing date/time '$temp_value', "
|
Error( "Error parsing date/time '$temp_value', "
|
||||||
|
@ -211,7 +232,7 @@ sub Sql {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$value = "'$value'";
|
$value = "'$value'";
|
||||||
} elsif ( $term->{attr} eq 'Date' ) {
|
} elsif ( $term->{attr} eq 'Date' or $term->{attr} eq 'StartDate' or $term->{attr} eq 'EndDate' ) {
|
||||||
$value = DateTimeToSQL( $temp_value );
|
$value = DateTimeToSQL( $temp_value );
|
||||||
if ( !$value ) {
|
if ( !$value ) {
|
||||||
Error( "Error parsing date/time '$temp_value', "
|
Error( "Error parsing date/time '$temp_value', "
|
||||||
|
@ -219,7 +240,7 @@ sub Sql {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$value = "to_days( '$value' )";
|
$value = "to_days( '$value' )";
|
||||||
} elsif ( $term->{attr} eq 'Time' ) {
|
} elsif ( $term->{attr} eq 'Time' or $term->{attr} eq 'StartTime' or $term->{attr} eq 'EndTime' ) {
|
||||||
$value = DateTimeToSQL( $temp_value );
|
$value = DateTimeToSQL( $temp_value );
|
||||||
if ( !$value ) {
|
if ( !$value ) {
|
||||||
Error( "Error parsing date/time '$temp_value', "
|
Error( "Error parsing date/time '$temp_value', "
|
||||||
|
@ -238,16 +259,20 @@ sub Sql {
|
||||||
$self->{Sql} .= " regexp $value";
|
$self->{Sql} .= " regexp $value";
|
||||||
} elsif ( $term->{op} eq '!~' ) {
|
} elsif ( $term->{op} eq '!~' ) {
|
||||||
$self->{Sql} .= " not regexp $value";
|
$self->{Sql} .= " not regexp $value";
|
||||||
|
} elsif ( $term->{op} eq 'IS' ) {
|
||||||
|
$self->{Sql} .= " IS $value";
|
||||||
|
} elsif ( $term->{op} eq 'IS NOT' ) {
|
||||||
|
$self->{Sql} .= " IS NOT $value";
|
||||||
} elsif ( $term->{op} eq '=[]' ) {
|
} elsif ( $term->{op} eq '=[]' ) {
|
||||||
$self->{Sql} .= " in (".join( ",", @value_list ).")";
|
$self->{Sql} .= " in (".join( ",", @value_list ).")";
|
||||||
} elsif ( $term->{op} eq '!~' ) {
|
} elsif ( $term->{op} eq '!~' ) {
|
||||||
$self->{Sql} .= " not in (".join( ",", @value_list ).")";
|
$self->{Sql} .= " not in (".join( ",", @value_list ).")";
|
||||||
} else {
|
} else {
|
||||||
$self->{Sql} .= " ".$term->{op}." $value";
|
$self->{Sql} .= ' '.$term->{op}." $value";
|
||||||
}
|
}
|
||||||
} # end if has an operator
|
} # end if has an operator
|
||||||
if ( exists($term->{cbr}) ) {
|
if ( exists($term->{cbr}) ) {
|
||||||
$self->{Sql} .= " ".str_repeat( ")", $term->{cbr} )." ";
|
$self->{Sql} .= ' '.str_repeat( ")", $term->{cbr} )." ";
|
||||||
}
|
}
|
||||||
} # end foreach term
|
} # end foreach term
|
||||||
} # end if terms
|
} # end if terms
|
||||||
|
@ -256,15 +281,15 @@ sub Sql {
|
||||||
if ( $self->{AutoMessage} ) {
|
if ( $self->{AutoMessage} ) {
|
||||||
# Include all events, including events that are still ongoing
|
# Include all events, including events that are still ongoing
|
||||||
# and have no EndTime yet
|
# and have no EndTime yet
|
||||||
$sql .= " and ( ".$self->{Sql}." )";
|
$sql .= ' AND ( '.$self->{Sql}.' )';
|
||||||
} else {
|
} else {
|
||||||
# Only include closed events (events with valid EndTime)
|
# Only include closed events (events with valid EndTime)
|
||||||
$sql .= " where not isnull(E.EndTime) and ( ".$self->{Sql}." )";
|
$sql .= ' WHERE (E.EndTime IS NOT NULL) AND ( '.$self->{Sql}.' )';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
my @auto_terms;
|
my @auto_terms;
|
||||||
if ( $self->{AutoArchive} ) {
|
if ( $self->{AutoArchive} ) {
|
||||||
push @auto_terms, "E.Archived = 0";
|
push @auto_terms, 'E.Archived = 0';
|
||||||
}
|
}
|
||||||
# Don't do this, it prevents re-generation and concatenation.
|
# Don't do this, it prevents re-generation and concatenation.
|
||||||
# If the file already exists, then the video won't be re-recreated
|
# If the file already exists, then the video won't be re-recreated
|
||||||
|
@ -284,7 +309,7 @@ sub Sql {
|
||||||
push @auto_terms, "E.Executed = 0";
|
push @auto_terms, "E.Executed = 0";
|
||||||
}
|
}
|
||||||
if ( @auto_terms ) {
|
if ( @auto_terms ) {
|
||||||
$sql .= " and ( ".join( " or ", @auto_terms )." )";
|
$sql .= " and ( ".join( ' or ', @auto_terms )." )";
|
||||||
}
|
}
|
||||||
if ( !$filter_expr->{sort_field} ) {
|
if ( !$filter_expr->{sort_field} ) {
|
||||||
$filter_expr->{sort_field} = 'StartTime';
|
$filter_expr->{sort_field} = 'StartTime';
|
||||||
|
@ -292,30 +317,34 @@ sub Sql {
|
||||||
}
|
}
|
||||||
my $sort_column = '';
|
my $sort_column = '';
|
||||||
if ( $filter_expr->{sort_field} eq 'Id' ) {
|
if ( $filter_expr->{sort_field} eq 'Id' ) {
|
||||||
$sort_column = "E.Id";
|
$sort_column = 'E.Id';
|
||||||
} elsif ( $filter_expr->{sort_field} eq 'MonitorName' ) {
|
} elsif ( $filter_expr->{sort_field} eq 'MonitorName' ) {
|
||||||
$sort_column = "M.Name";
|
$sort_column = 'M.Name';
|
||||||
} elsif ( $filter_expr->{sort_field} eq 'Name' ) {
|
} elsif ( $filter_expr->{sort_field} eq 'Name' ) {
|
||||||
$sort_column = "E.Name";
|
$sort_column = 'E.Name';
|
||||||
} elsif ( $filter_expr->{sort_field} eq 'StartTime' ) {
|
} elsif ( $filter_expr->{sort_field} eq 'StartTime' ) {
|
||||||
$sort_column = "E.StartTime";
|
$sort_column = 'E.StartTime';
|
||||||
|
} elsif ( $filter_expr->{sort_field} eq 'EndTime' ) {
|
||||||
|
$sort_column = 'E.EndTime';
|
||||||
} elsif ( $filter_expr->{sort_field} eq 'Secs' ) {
|
} elsif ( $filter_expr->{sort_field} eq 'Secs' ) {
|
||||||
$sort_column = "E.Length";
|
$sort_column = 'E.Length';
|
||||||
} elsif ( $filter_expr->{sort_field} eq 'Frames' ) {
|
} elsif ( $filter_expr->{sort_field} eq 'Frames' ) {
|
||||||
$sort_column = "E.Frames";
|
$sort_column = 'E.Frames';
|
||||||
} elsif ( $filter_expr->{sort_field} eq 'AlarmFrames' ) {
|
} elsif ( $filter_expr->{sort_field} eq 'AlarmFrames' ) {
|
||||||
$sort_column = "E.AlarmFrames";
|
$sort_column = 'E.AlarmFrames';
|
||||||
} elsif ( $filter_expr->{sort_field} eq 'TotScore' ) {
|
} elsif ( $filter_expr->{sort_field} eq 'TotScore' ) {
|
||||||
$sort_column = "E.TotScore";
|
$sort_column = 'E.TotScore';
|
||||||
} elsif ( $filter_expr->{sort_field} eq 'AvgScore' ) {
|
} elsif ( $filter_expr->{sort_field} eq 'AvgScore' ) {
|
||||||
$sort_column = "E.AvgScore";
|
$sort_column = 'E.AvgScore';
|
||||||
} elsif ( $filter_expr->{sort_field} eq 'MaxScore' ) {
|
} elsif ( $filter_expr->{sort_field} eq 'MaxScore' ) {
|
||||||
$sort_column = "E.MaxScore";
|
$sort_column = 'E.MaxScore';
|
||||||
|
} elsif ( $filter_expr->{sort_field} eq 'DiskSpace' ) {
|
||||||
|
$sort_column = 'E.DiskSpace';
|
||||||
} else {
|
} else {
|
||||||
$sort_column = "E.StartTime";
|
$sort_column = 'E.StartTime';
|
||||||
}
|
}
|
||||||
my $sort_order = $filter_expr->{sort_asc}?"asc":"desc";
|
my $sort_order = $filter_expr->{sort_asc}?'asc':'desc';
|
||||||
$sql .= " order by ".$sort_column." ".$sort_order;
|
$sql .= ' order by '.$sort_column." ".$sort_order;
|
||||||
if ( $filter_expr->{limit} ) {
|
if ( $filter_expr->{limit} ) {
|
||||||
$sql .= " limit 0,".$filter_expr->{limit};
|
$sql .= " limit 0,".$filter_expr->{limit};
|
||||||
}
|
}
|
||||||
|
@ -325,7 +354,7 @@ sub Sql {
|
||||||
} # end sub Sql
|
} # end sub Sql
|
||||||
|
|
||||||
sub getDiskPercent {
|
sub getDiskPercent {
|
||||||
my $command = "df " . ($_[0] ? $_[0] : '.');
|
my $command = 'df ' . ($_[0] ? $_[0] : '.');
|
||||||
my $df = qx( $command );
|
my $df = qx( $command );
|
||||||
my $space = -1;
|
my $space = -1;
|
||||||
if ( $df =~ /\s(\d+)%/ms ) {
|
if ( $df =~ /\s(\d+)%/ms ) {
|
||||||
|
@ -335,7 +364,7 @@ sub getDiskPercent {
|
||||||
}
|
}
|
||||||
|
|
||||||
sub getDiskBlocks {
|
sub getDiskBlocks {
|
||||||
my $command = "df .";
|
my $command = 'df .';
|
||||||
my $df = qx( $command );
|
my $df = qx( $command );
|
||||||
my $space = -1;
|
my $space = -1;
|
||||||
if ( $df =~ /\s(\d+)\s+\d+\s+\d+%/ms ) {
|
if ( $df =~ /\s(\d+)\s+\d+\s+\d+%/ms ) {
|
||||||
|
@ -345,7 +374,7 @@ sub getDiskBlocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
sub getLoad {
|
sub getLoad {
|
||||||
my $command = "uptime .";
|
my $command = 'uptime .';
|
||||||
my $uptime = qx( $command );
|
my $uptime = qx( $command );
|
||||||
my $load = -1;
|
my $load = -1;
|
||||||
if ( $uptime =~ /load average:\s+([\d.]+)/ms ) {
|
if ( $uptime =~ /load average:\s+([\d.]+)/ms ) {
|
||||||
|
|
|
@ -678,6 +678,11 @@ sub Dump {
|
||||||
fetch()->logPrint( DEBUG, Data::Dumper->Dump( [ $var ], [ $label ] ) );
|
fetch()->logPrint( DEBUG, Data::Dumper->Dump( [ $var ], [ $label ] ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub debug {
|
||||||
|
my $log = shift;
|
||||||
|
$log->logPrint( DEBUG, @_ );
|
||||||
|
}
|
||||||
|
|
||||||
sub Debug( @ ) {
|
sub Debug( @ ) {
|
||||||
fetch()->logPrint( DEBUG, @_ );
|
fetch()->logPrint( DEBUG, @_ );
|
||||||
}
|
}
|
||||||
|
@ -685,14 +690,27 @@ sub Debug( @ ) {
|
||||||
sub Info( @ ) {
|
sub Info( @ ) {
|
||||||
fetch()->logPrint( INFO, @_ );
|
fetch()->logPrint( INFO, @_ );
|
||||||
}
|
}
|
||||||
|
sub info {
|
||||||
|
my $log = shift;
|
||||||
|
$log->logPrint( INFO, @_ );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
sub Warning( @ ) {
|
sub Warning( @ ) {
|
||||||
fetch()->logPrint( WARNING, @_ );
|
fetch()->logPrint( WARNING, @_ );
|
||||||
}
|
}
|
||||||
|
sub warn {
|
||||||
|
my $log = shift;
|
||||||
|
$log->logPrint( WARNING, @_ );
|
||||||
|
}
|
||||||
|
|
||||||
sub Error( @ ) {
|
sub Error( @ ) {
|
||||||
fetch()->logPrint( ERROR, @_ );
|
fetch()->logPrint( ERROR, @_ );
|
||||||
}
|
}
|
||||||
|
sub error {
|
||||||
|
my $log = shift;
|
||||||
|
$log->logPrint( ERROR, @_ );
|
||||||
|
}
|
||||||
|
|
||||||
sub Fatal( @ ) {
|
sub Fatal( @ ) {
|
||||||
fetch()->logPrint( FATAL, @_ );
|
fetch()->logPrint( FATAL, @_ );
|
||||||
|
|
|
@ -42,7 +42,13 @@ use ZoneMinder::Config qw(:all);
|
||||||
use ZoneMinder::Logger qw(:all);
|
use ZoneMinder::Logger qw(:all);
|
||||||
use ZoneMinder::Database qw(:all);
|
use ZoneMinder::Database qw(:all);
|
||||||
|
|
||||||
use vars qw/ $AUTOLOAD /;
|
use vars qw/ $AUTOLOAD $log $dbh/;
|
||||||
|
|
||||||
|
*log = \$ZoneMinder::Logger::logger;
|
||||||
|
*dbh = \$ZoneMinder::Database::dbh;
|
||||||
|
|
||||||
|
my $debug = 1;
|
||||||
|
use constant DEBUG_ALL=>0;
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
my ( $parent, $id, $data ) = @_;
|
my ( $parent, $id, $data ) = @_;
|
||||||
|
@ -110,7 +116,282 @@ sub AUTOLOAD {
|
||||||
return $_[0]{$name};
|
return $_[0]{$name};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub save {
|
||||||
|
my ( $self, $data, $force_insert ) = @_;
|
||||||
|
|
||||||
|
my $type = ref $self;
|
||||||
|
if ( ! $type ) {
|
||||||
|
my ( $caller, undef, $line ) = caller;
|
||||||
|
$log->error("No type in Object::save. self:$self from $caller:$line");
|
||||||
|
}
|
||||||
|
my $local_dbh = eval '$'.$type.'::dbh';
|
||||||
|
$local_dbh = $ZoneMinder::Database::dbh if ! $local_dbh;
|
||||||
|
$self->set( $data ? $data : {} );
|
||||||
|
if ( $debug or DEBUG_ALL ) {
|
||||||
|
if ( $data ) {
|
||||||
|
foreach my $k ( keys %$data ) {
|
||||||
|
$log->debug("Object::save after set $k => $$data{$k} $$self{$k}");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$log->debug("No data after set");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#$debug = 0;
|
||||||
|
|
||||||
|
my $table = eval '$'.$type.'::table';
|
||||||
|
my $fields = eval '\%'.$type.'::fields';
|
||||||
|
my $debug = eval '$'.$type.'::debug';
|
||||||
|
#$debug = DEBUG_ALL if ! $debug;
|
||||||
|
|
||||||
|
my %sql;
|
||||||
|
foreach my $k ( keys %$fields ) {
|
||||||
|
$sql{$$fields{$k}} = $$self{$k} if defined $$fields{$k};
|
||||||
|
} # end foreach
|
||||||
|
if ( ! $force_insert ) {
|
||||||
|
$sql{$$fields{updated_on}} = 'NOW()' if exists $$fields{updated_on};
|
||||||
|
} # end if
|
||||||
|
my $serial = eval '$'.$type.'::serial';
|
||||||
|
my @identified_by = eval '@'.$type.'::identified_by';
|
||||||
|
|
||||||
|
my $ac = ZoneMinder::Database::start_transaction( $local_dbh );
|
||||||
|
if ( ! $serial ) {
|
||||||
|
my $insert = $force_insert;
|
||||||
|
my %serial = eval '%'.$type.'::serial';
|
||||||
|
if ( ! %serial ) {
|
||||||
|
$log->debug("No serial") if $debug;
|
||||||
|
# No serial columns defined, which means that we will do saving by delete/insert instead of insert/update
|
||||||
|
if ( @identified_by ) {
|
||||||
|
my $where = join(' AND ', map { $$fields{$_}.'=?' } @identified_by );
|
||||||
|
if ( $debug ) {
|
||||||
|
$log->debug("DELETE FROM $table WHERE $where");
|
||||||
|
} # end if
|
||||||
|
|
||||||
|
if ( ! ( ( $_ = $local_dbh->prepare("DELETE FROM $table WHERE $where") ) and $_->execute( @$self{@identified_by} ) ) ) {
|
||||||
|
$where =~ s/\?/\%s/g;
|
||||||
|
$log->error("Error deleting: DELETE FROM $table WHERE " . sprintf($where, map { defined $_ ? $_ : 'undef' } ( @$self{@identified_by}) ).'):' . $local_dbh->errstr);
|
||||||
|
$local_dbh->rollback();
|
||||||
|
ZoneMinder::Database::end_transaction( $local_dbh, $ac );
|
||||||
|
return $local_dbh->errstr;
|
||||||
|
} elsif ( $debug ) {
|
||||||
|
$log->debug("SQL succesful DELETE FROM $table WHERE $where");
|
||||||
|
} # end if
|
||||||
|
} # end if
|
||||||
|
$insert = 1;
|
||||||
|
} else {
|
||||||
|
foreach my $id ( @identified_by ) {
|
||||||
|
if ( ! $serial{$id} ) {
|
||||||
|
my ( $caller, undef, $line ) = caller;
|
||||||
|
$log->error("$id nor in serial for $type from $caller:$line") if $debug;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if ( ! $$self{$id} ) {
|
||||||
|
my $s = qq{SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES WHERE table_name = '$table'};
|
||||||
|
|
||||||
|
($$self{$id}) = ($sql{$$fields{$id}}) = $local_dbh->selectrow_array( $s );
|
||||||
|
#($$self{$id}) = ($sql{$$fields{$id}}) = $local_dbh->selectrow_array( q{SELECT nextval('} . $serial{$id} . q{')} );
|
||||||
|
$log->debug("SQL statement execution SELECT $s returned $$self{$id}") if $debug or DEBUG_ALL;
|
||||||
|
$insert = 1;
|
||||||
|
} # end if
|
||||||
|
} # end foreach
|
||||||
|
} # end if ! %serial
|
||||||
|
|
||||||
|
if ( $insert ) {
|
||||||
|
my @keys = keys %sql;
|
||||||
|
my $command = "INSERT INTO $table (" . join(',', @keys ) . ') VALUES (' . join(',', map { '?' } @sql{@keys} ) . ')';
|
||||||
|
if ( ! ( ( $_ = $local_dbh->prepare($command) ) and $_->execute( @sql{@keys} ) ) ) {
|
||||||
|
my $error = $local_dbh->errstr;
|
||||||
|
$command =~ s/\?/\%s/g;
|
||||||
|
$log->error('SQL statement execution failed: ('.sprintf($command, , map { defined $_ ? $_ : 'undef' } ( @sql{@keys}) ).'):' . $local_dbh->errstr);
|
||||||
|
$local_dbh->rollback();
|
||||||
|
ZoneMinder::Database::end_transaction( $local_dbh, $ac );
|
||||||
|
return $error;
|
||||||
|
} # end if
|
||||||
|
if ( $debug or DEBUG_ALL ) {
|
||||||
|
$command =~ s/\?/\%s/g;
|
||||||
|
$log->debug('SQL statement execution: ('.sprintf($command, , map { defined $_ ? $_ : 'undef' } ( @sql{@keys} ) ).'):' );
|
||||||
|
} # end if
|
||||||
|
} else {
|
||||||
|
my @keys = keys %sql;
|
||||||
|
my $command = "UPDATE $table SET " . join(',', map { $_ . ' = ?' } @keys ) . ' WHERE ' . join(' AND ', map { $_ . ' = ?' } @$fields{@identified_by} );
|
||||||
|
if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys,@$fields{@identified_by}} ) ) ) {
|
||||||
|
my $error = $local_dbh->errstr;
|
||||||
|
$command =~ s/\?/\%s/g;
|
||||||
|
$log->error('SQL failed: ('.sprintf($command, , map { defined $_ ? $_ : 'undef' } ( @sql{@keys, @$fields{@identified_by}}) ).'):' . $local_dbh->errstr);
|
||||||
|
$local_dbh->rollback();
|
||||||
|
ZoneMinder::Database::end_transaction( $local_dbh, $ac );
|
||||||
|
return $error;
|
||||||
|
} # end if
|
||||||
|
if ( $debug or DEBUG_ALL ) {
|
||||||
|
$command =~ s/\?/\%s/g;
|
||||||
|
$log->debug('SQL DEBUG: ('.sprintf($command, map { defined $_ ? $_ : 'undef' } ( @sql{@keys,@$fields{@identified_by}} ) ).'):' );
|
||||||
|
} # end if
|
||||||
|
} # end if
|
||||||
|
} else { # not identified_by
|
||||||
|
@identified_by = ('Id') if ! @identified_by;
|
||||||
|
|
||||||
|
# If the size of the arrays are not equal which means one or more are missing
|
||||||
|
my @identified_by_without_values = map { $$self{$_} ? () : $_ } @identified_by;
|
||||||
|
my $need_serial = @identified_by_without_values > 0;
|
||||||
|
|
||||||
|
if ( $force_insert or $need_serial ) {
|
||||||
|
|
||||||
|
if ( $need_serial ) {
|
||||||
|
if ( $serial ) {
|
||||||
|
my $s = qq{SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES WHERE table_name = '$table'};
|
||||||
|
@$self{@identified_by} = @sql{@$fields{@identified_by}} = $local_dbh->selectrow_array( $s );
|
||||||
|
#@$self{@identified_by} = @sql{@$fields{@identified_by}} = $local_dbh->selectrow_array( q{SELECT nextval('} . $serial . q{')} );
|
||||||
|
if ( $local_dbh->errstr() ) {
|
||||||
|
$log->error("Error getting next id. " . $local_dbh->errstr() );
|
||||||
|
$log->error("SQL statement execution $s returned ".join(',',@$self{@identified_by}));
|
||||||
|
} elsif ( $debug or DEBUG_ALL ) {
|
||||||
|
$log->debug("SQL statement execution $s returned ".join(',',@$self{@identified_by}));
|
||||||
|
} # end if
|
||||||
|
} # end if
|
||||||
|
} # end if
|
||||||
|
|
||||||
|
my @keys = keys %sql;
|
||||||
|
my $command = "INSERT INTO $table (" . join(',', @keys ) . ') VALUES (' . join(',', map { '?' } @sql{@keys} ) . ')';
|
||||||
|
if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys} ) ) ) {
|
||||||
|
$command =~ s/\?/\%s/g;
|
||||||
|
my $error = $local_dbh->errstr;
|
||||||
|
$log->error('SQL failed: ('.sprintf($command, map { defined $_ ? $_ : 'undef' } ( @sql{@keys}) ).'):' . $error);
|
||||||
|
$local_dbh->rollback();
|
||||||
|
ZoneMinder::Database::end_transaction( $local_dbh, $ac );
|
||||||
|
return $error;
|
||||||
|
} # end if
|
||||||
|
if ( $debug or DEBUG_ALL ) {
|
||||||
|
$command =~ s/\?/\%s/g;
|
||||||
|
$log->debug('SQL DEBUG: ('.sprintf($command, map { defined $_ ? $_ : 'undef' } ( @sql{@keys} ) ).'):' );
|
||||||
|
} # end if
|
||||||
|
} else {
|
||||||
|
delete $sql{created_on};
|
||||||
|
my @keys = keys %sql;
|
||||||
|
my %identified_by = map { $_, $_ } @identified_by;
|
||||||
|
|
||||||
|
@keys = map { $identified_by{$_} ? () : $$fields{$_} } @keys;
|
||||||
|
my $command = "UPDATE $table SET " . join(',', map { $_ . ' = ?' } @keys ) . ' WHERE ' . join(' AND ', map { $$fields{$_} .'= ?' } @identified_by );
|
||||||
|
if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys}, @sql{@$fields{@identified_by}} ) ) ) {
|
||||||
|
my $error = $local_dbh->errstr;
|
||||||
|
$command =~ s/\?/\%s/g;
|
||||||
|
$log->error('SQL failed: ('.sprintf($command, map { defined $_ ? $_ : 'undef' } ( @sql{@keys}, @sql{@$fields{@identified_by}} ) ).'):' . $error) if $log;
|
||||||
|
$local_dbh->rollback();
|
||||||
|
ZoneMinder::Database::end_transaction( $local_dbh, $ac );
|
||||||
|
return $error;
|
||||||
|
} # end if
|
||||||
|
if ( $debug or DEBUG_ALL ) {
|
||||||
|
$command =~ s/\?/\%s/g;
|
||||||
|
$log->debug('SQL DEBUG: ('.sprintf($command, map { defined $_ ? ( ref $_ eq 'ARRAY' ? join(',',@{$_}) : $_ ) : 'undef' } ( @sql{@keys}, @$self{@identified_by} ) ).'):' );
|
||||||
|
} # end if
|
||||||
|
} # end if
|
||||||
|
} # end if
|
||||||
|
ZoneMinder::Database::end_transaction( $local_dbh, $ac );
|
||||||
|
$self->load();
|
||||||
|
#if ( $$fields{id} ) {
|
||||||
|
#if ( ! $ZoneMinder::Object::cache{$type}{$$self{id}} ) {
|
||||||
|
#$ZoneMinder::Object::cache{$type}{$$self{id}} = $self;
|
||||||
|
#} # end if
|
||||||
|
#delete $ZoneMinder::Object::cache{$config{db_name}}{$type}{$$self{id}};
|
||||||
|
#} # end if
|
||||||
|
#$log->debug("after delete");
|
||||||
|
#eval 'if ( %'.$type.'::find_cache ) { %'.$type.'::find_cache = (); }';
|
||||||
|
#$log->debug("after clear cache");
|
||||||
|
return '';
|
||||||
|
} # end sub save
|
||||||
|
|
||||||
|
sub set {
|
||||||
|
my ( $self, $params ) = @_;
|
||||||
|
my @set_fields = ();
|
||||||
|
|
||||||
|
my $type = ref $self;
|
||||||
|
my %fields = eval ('%'.$type.'::fields');
|
||||||
|
if ( ! %fields ) {
|
||||||
|
$log->warn("ZoneMinder::Object::set called on an object ($type) with no fields".$@);
|
||||||
|
} # end if
|
||||||
|
my %defaults = eval('%'.$type.'::defaults');
|
||||||
|
if ( ref $params ne 'HASH' ) {
|
||||||
|
my ( $caller, undef, $line ) = caller;
|
||||||
|
$log->error("$type -> set called with non-hash params from $caller $line");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach my $field ( keys %fields ) {
|
||||||
|
if ( $params ) {
|
||||||
|
$log->debug("field: $field, param: ".$$params{$field}) if $debug;
|
||||||
|
if ( exists $$params{$field} ) {
|
||||||
|
$log->debug("field: $field, $$self{$field} =? param: ".$$params{$field}) if $debug;
|
||||||
|
if ( ( ! defined $$self{$field} ) or ($$self{$field} ne $params->{$field}) ) {
|
||||||
|
# Only make changes to fields that have changed
|
||||||
|
if ( defined $fields{$field} ) {
|
||||||
|
$$self{$field} = $$params{$field} if defined $fields{$field};
|
||||||
|
push @set_fields, $fields{$field}, $$params{$field}; #mark for sql updating
|
||||||
|
} # end if
|
||||||
|
$log->debug("Running $field with $$params{$field}") if $debug;
|
||||||
|
if ( my $func = $self->can( $field ) ) {
|
||||||
|
$func->( $self, $$params{$field} );
|
||||||
|
} # end if
|
||||||
|
} # end if
|
||||||
|
} # end if
|
||||||
|
} # end if $params
|
||||||
|
|
||||||
|
if ( defined $fields{$field} ) {
|
||||||
|
if ( $$self{$field} ) {
|
||||||
|
$$self{$field} = transform( $type, $field, $$self{$field} );
|
||||||
|
} # end if $$self{field}
|
||||||
|
}
|
||||||
|
} # end foreach field
|
||||||
|
|
||||||
|
foreach my $field ( keys %defaults ) {
|
||||||
|
|
||||||
|
if ( ( ! exists $$self{$field} ) or (!defined $$self{$field}) or ( $$self{$field} eq '' ) ) {
|
||||||
|
$log->debug("Setting default ($field) ($$self{$field}) ($defaults{$field}) ") if $debug;
|
||||||
|
if ( defined $defaults{$field} ) {
|
||||||
|
$log->debug("Default $field is defined: $defaults{$field}") if $debug;
|
||||||
|
if ( $defaults{$field} eq 'NOW()' ) {
|
||||||
|
$$self{$field} = 'NOW()';
|
||||||
|
} else {
|
||||||
|
$$self{$field} = eval($defaults{$field});
|
||||||
|
$log->error( "Eval error of object default $field default ($defaults{$field}) Reason: " . $@ ) if $@;
|
||||||
|
} # end if
|
||||||
|
} else {
|
||||||
|
$$self{$field} = $defaults{$field};
|
||||||
|
} # end if
|
||||||
|
#$$self{$field} = ( defined $defaults{$field} ) ? eval($defaults{$field}) : $defaults{$field};
|
||||||
|
$log->debug("Setting default for ($field) using ($defaults{$field}) to ($$self{$field}) ") if $debug;
|
||||||
|
} # end if
|
||||||
|
} # end foreach default
|
||||||
|
return @set_fields;
|
||||||
|
} # end sub set
|
||||||
|
|
||||||
|
sub transform {
|
||||||
|
my $type = ref $_[0];
|
||||||
|
$type = $_[0] if ! $type;
|
||||||
|
my $fields = eval '\%'.$type.'::fields';
|
||||||
|
my $value = $_[2];
|
||||||
|
|
||||||
|
if ( defined $$fields{$_[1]} ) {
|
||||||
|
my @transforms = eval('@{$'.$type.'::transforms{$_[1]}}');
|
||||||
|
$log->debug("Transforms for $_[1] before $_[2]: @transforms") if $debug;
|
||||||
|
if ( @transforms ) {
|
||||||
|
foreach my $transform ( @transforms ) {
|
||||||
|
if ( $transform =~ /^s\// or $transform =~ /^tr\// ) {
|
||||||
|
eval '$value =~ ' . $transform;
|
||||||
|
} elsif ( $transform =~ /^<(\d+)/ ) {
|
||||||
|
if ( $value > $1 ) {
|
||||||
|
$value = undef;
|
||||||
|
} # end if
|
||||||
|
} else {
|
||||||
|
$log->debug("evalling $value ".$transform . " Now value is $value" );
|
||||||
|
eval '$value '.$transform;
|
||||||
|
$log->error("Eval error $@") if $@;
|
||||||
|
}
|
||||||
|
$log->debug("After $transform: $value") if $debug;
|
||||||
|
} # end foreach
|
||||||
|
} # end if
|
||||||
|
} else {
|
||||||
|
$log->error("Object::transform ($_[1]) not in fields for $type");
|
||||||
|
} # end if
|
||||||
|
return $value;
|
||||||
|
|
||||||
|
} # end sub transform
|
||||||
1;
|
1;
|
||||||
__END__
|
__END__
|
||||||
|
|
||||||
|
|
|
@ -246,7 +246,7 @@ MAIN: while( $loop ) {
|
||||||
$$Event{Path} = join('/', $Storage->Path(), $day_dir,$event_path);
|
$$Event{Path} = join('/', $Storage->Path(), $day_dir,$event_path);
|
||||||
$Event->MonitorId( $monitor_dir );
|
$Event->MonitorId( $monitor_dir );
|
||||||
$Event->StorageId( $Storage->Id() );
|
$Event->StorageId( $Storage->Id() );
|
||||||
$Event->DiskUsage( undef );
|
$Event->DiskSpace( undef );
|
||||||
} # event path exists
|
} # event path exists
|
||||||
} # end foreach event_link
|
} # end foreach event_link
|
||||||
chdir( $Storage->Path() );
|
chdir( $Storage->Path() );
|
||||||
|
|
|
@ -214,6 +214,7 @@ sub getFilters {
|
||||||
or AutoMessage = 1
|
or AutoMessage = 1
|
||||||
or AutoExecute = 1
|
or AutoExecute = 1
|
||||||
or AutoDelete = 1
|
or AutoDelete = 1
|
||||||
|
or UpdateDiskSpace = 1
|
||||||
) ORDER BY Name';
|
) ORDER BY Name';
|
||||||
my $sth = $dbh->prepare_cached( $sql )
|
my $sth = $dbh->prepare_cached( $sql )
|
||||||
or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
|
or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
|
||||||
|
@ -250,17 +251,23 @@ sub checkFilter {
|
||||||
my $filter = shift;
|
my $filter = shift;
|
||||||
|
|
||||||
my @Events = $filter->Execute();
|
my @Events = $filter->Execute();
|
||||||
Info( join( "Checking filter '$filter->{Name}'",
|
Info(
|
||||||
($filter->{AutoDelete}?', delete':''),
|
join(' ',
|
||||||
($filter->{AutoArchive}?', archive':''),
|
'Checking filter', $filter->{Name},
|
||||||
($filter->{AutoVideo}?', video':''),
|
join( ', ',
|
||||||
($filter->{AutoUpload}?', upload':''),
|
|
||||||
($filter->{AutoEmail}?', email':''),
|
($filter->{AutoDelete}?'delete':()),
|
||||||
($filter->{AutoMessage}?', message':''),
|
($filter->{AutoArchive}?'archive':()),
|
||||||
($filter->{AutoExecute}?', execute':''),
|
($filter->{AutoVideo}?'video':()),
|
||||||
' returned ' , scalar @Events , ' events',
|
($filter->{AutoUpload}?'upload':()),
|
||||||
"\n",
|
($filter->{AutoEmail}?'email':()),
|
||||||
) );
|
($filter->{AutoMessage}?'message':()),
|
||||||
|
($filter->{AutoExecute}?'execute':()),
|
||||||
|
($filter->{UpdateDiskSpace}?'update disk space':()),
|
||||||
|
),
|
||||||
|
'returned' , scalar @Events , 'events',
|
||||||
|
"\n",
|
||||||
|
) );
|
||||||
|
|
||||||
foreach my $event ( @Events ) {
|
foreach my $event ( @Events ) {
|
||||||
Debug( "Checking event $event->{Id}\n" );
|
Debug( "Checking event $event->{Id}\n" );
|
||||||
|
@ -308,6 +315,12 @@ sub checkFilter {
|
||||||
Error( "Unable toto delete event $event->{Id} as previous operations failed\n" );
|
Error( "Unable toto delete event $event->{Id} as previous operations failed\n" );
|
||||||
}
|
}
|
||||||
} # end if AutoDelete
|
} # end if AutoDelete
|
||||||
|
if ( $filter->{UpdateDiskSpace} ) {
|
||||||
|
my $Event = new ZoneMinder::Event( $$event{Id}, $event );
|
||||||
|
$Event->DiskSpace(undef);
|
||||||
|
$Event->save();
|
||||||
|
|
||||||
|
} # end if UpdateDiskSpace
|
||||||
} # end foreach event
|
} # end foreach event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
AnalysisThread::AnalysisThread(Monitor *p_monitor) {
|
AnalysisThread::AnalysisThread(Monitor *p_monitor) {
|
||||||
monitor = p_monitor;
|
monitor = p_monitor;
|
||||||
terminate = false;
|
terminate = false;
|
||||||
sigemptyset(&block_set);
|
//sigemptyset(&block_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
AnalysisThread::~AnalysisThread() {
|
AnalysisThread::~AnalysisThread() {
|
||||||
|
Debug(2, "THREAD: deleteing");
|
||||||
}
|
}
|
||||||
|
|
||||||
int AnalysisThread::run() {
|
int AnalysisThread::run() {
|
||||||
|
@ -17,11 +18,12 @@ int AnalysisThread::run() {
|
||||||
monitor->UpdateAdaptiveSkip();
|
monitor->UpdateAdaptiveSkip();
|
||||||
last_analysis_update_time = time(0);
|
last_analysis_update_time = time(0);
|
||||||
|
|
||||||
|
Debug(2, "THREAD: Getting ref image");
|
||||||
monitor->get_ref_image();
|
monitor->get_ref_image();
|
||||||
|
|
||||||
while( !terminate ) {
|
while( !terminate ) {
|
||||||
// Process the next image
|
// Process the next image
|
||||||
sigprocmask(SIG_BLOCK, &block_set, 0);
|
//sigprocmask(SIG_BLOCK, &block_set, 0);
|
||||||
|
|
||||||
// Some periodic updates are required for variable capturing framerate
|
// Some periodic updates are required for variable capturing framerate
|
||||||
if ( analysis_update_delay ) {
|
if ( analysis_update_delay ) {
|
||||||
|
@ -34,12 +36,14 @@ int AnalysisThread::run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !monitor->Analyse() ) {
|
if ( !monitor->Analyse() ) {
|
||||||
|
Debug(4, "Sleeping for %d", monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE);
|
||||||
usleep(monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE);
|
usleep(monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE);
|
||||||
} else if ( analysis_rate ) {
|
} else if ( analysis_rate ) {
|
||||||
|
Debug(4, "Sleeping for %d", analysis_rate);
|
||||||
usleep(analysis_rate);
|
usleep(analysis_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
sigprocmask(SIG_UNBLOCK, &block_set, 0);
|
//sigprocmask(SIG_UNBLOCK, &block_set, 0);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} // end in AnalysisThread::run()
|
} // end in AnalysisThread::run()
|
||||||
|
|
|
@ -58,6 +58,7 @@ protected:
|
||||||
int mAudioStreamId;
|
int mAudioStreamId;
|
||||||
AVCodecContext *mVideoCodecContext;
|
AVCodecContext *mVideoCodecContext;
|
||||||
AVCodecContext *mAudioCodecContext;
|
AVCodecContext *mAudioCodecContext;
|
||||||
|
AVStream *video_stream;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Camera(
|
Camera(
|
||||||
|
@ -104,12 +105,12 @@ public:
|
||||||
|
|
||||||
virtual int PrimeCapture() { return( 0 ); }
|
virtual int PrimeCapture() { return( 0 ); }
|
||||||
virtual int PreCapture()=0;
|
virtual int PreCapture()=0;
|
||||||
virtual ZMPacket * Capture( Image &image )=0;
|
virtual int Capture(ZMPacket &p)=0;
|
||||||
virtual int PostCapture()=0;
|
virtual int PostCapture()=0;
|
||||||
AVStream *get_VideoStream() { return NULL; };
|
AVStream *get_VideoStream() { return NULL; };
|
||||||
AVStream *get_AudioStream() { return NULL; };
|
AVStream *get_AudioStream() { return NULL; };
|
||||||
int get_VideoStreamId() { return mVideoStreamId; };
|
int get_VideoStreamId() { return mVideoStreamId; };
|
||||||
int get_AudioStreamId() { return mAudioStreamId; };
|
int get_AudioStreamId() { return mAudioStreamId; };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ZM_CAMERA_H
|
#endif // ZM_CAMERA_H
|
||||||
|
|
|
@ -116,7 +116,7 @@ int cURLCamera::PreCapture() {
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
int cURLCamera::Capture( Image &image ) {
|
int cURLCamera::Capture( ZMPacket &zm_packet ) {
|
||||||
bool frameComplete = false;
|
bool frameComplete = false;
|
||||||
|
|
||||||
/* MODE_STREAM specific variables */
|
/* MODE_STREAM specific variables */
|
||||||
|
@ -128,10 +128,10 @@ int cURLCamera::Capture( Image &image ) {
|
||||||
/* Grab the mutex to ensure exclusive access to the shared data */
|
/* Grab the mutex to ensure exclusive access to the shared data */
|
||||||
lock();
|
lock();
|
||||||
|
|
||||||
while (!frameComplete) {
|
while ( !frameComplete ) {
|
||||||
|
|
||||||
/* If the work thread did a reset, reset our local variables */
|
/* If the work thread did a reset, reset our local variables */
|
||||||
if(bReset) {
|
if ( bReset ) {
|
||||||
SubHeadersParsingComplete = false;
|
SubHeadersParsingComplete = false;
|
||||||
frame_content_length = 0;
|
frame_content_length = 0;
|
||||||
frame_content_type.clear();
|
frame_content_type.clear();
|
||||||
|
@ -139,25 +139,25 @@ int cURLCamera::Capture( Image &image ) {
|
||||||
bReset = false;
|
bReset = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mode == MODE_UNSET) {
|
if ( mode == MODE_UNSET ) {
|
||||||
/* Don't have a mode yet. Sleep while waiting for data */
|
/* Don't have a mode yet. Sleep while waiting for data */
|
||||||
nRet = pthread_cond_wait(&data_available_cond,&shareddata_mutex);
|
nRet = pthread_cond_wait(&data_available_cond,&shareddata_mutex);
|
||||||
if(nRet != 0) {
|
if ( nRet != 0 ) {
|
||||||
Error("Failed waiting for available data condition variable: %s",strerror(nRet));
|
Error("Failed waiting for available data condition variable: %s",strerror(nRet));
|
||||||
return -20;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mode == MODE_STREAM) {
|
if ( mode == MODE_STREAM ) {
|
||||||
|
|
||||||
/* Subheader parsing */
|
/* Subheader parsing */
|
||||||
while(!SubHeadersParsingComplete && !need_more_data) {
|
while( !SubHeadersParsingComplete && !need_more_data ) {
|
||||||
|
|
||||||
size_t crlf_start, crlf_end, crlf_size;
|
size_t crlf_start, crlf_end, crlf_size;
|
||||||
std::string subheader;
|
std::string subheader;
|
||||||
|
|
||||||
/* Check if the buffer contains something */
|
/* Check if the buffer contains something */
|
||||||
if(databuffer.empty()) {
|
if ( databuffer.empty() ) {
|
||||||
/* Empty buffer, wait for data */
|
/* Empty buffer, wait for data */
|
||||||
need_more_data = true;
|
need_more_data = true;
|
||||||
break;
|
break;
|
||||||
|
@ -165,14 +165,14 @@ int cURLCamera::Capture( Image &image ) {
|
||||||
|
|
||||||
/* Find crlf start */
|
/* Find crlf start */
|
||||||
crlf_start = memcspn(databuffer,"\r\n",databuffer.size());
|
crlf_start = memcspn(databuffer,"\r\n",databuffer.size());
|
||||||
if(crlf_start == databuffer.size()) {
|
if ( crlf_start == databuffer.size() ) {
|
||||||
/* Not found, wait for more data */
|
/* Not found, wait for more data */
|
||||||
need_more_data = true;
|
need_more_data = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See if we have enough data for determining crlf length */
|
/* See if we have enough data for determining crlf length */
|
||||||
if(databuffer.size() < crlf_start+5) {
|
if ( databuffer.size() < crlf_start+5 ) {
|
||||||
/* Need more data */
|
/* Need more data */
|
||||||
need_more_data = true;
|
need_more_data = true;
|
||||||
break;
|
break;
|
||||||
|
@ -183,13 +183,13 @@ int cURLCamera::Capture( Image &image ) {
|
||||||
crlf_size = (crlf_start + crlf_end) - crlf_start;
|
crlf_size = (crlf_start + crlf_end) - crlf_start;
|
||||||
|
|
||||||
/* Is this the end of a previous stream? (This is just before the boundary) */
|
/* Is this the end of a previous stream? (This is just before the boundary) */
|
||||||
if(crlf_start == 0) {
|
if ( crlf_start == 0 ) {
|
||||||
databuffer.consume(crlf_size);
|
databuffer.consume(crlf_size);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for invalid CRLF size */
|
/* Check for invalid CRLF size */
|
||||||
if(crlf_size > 4) {
|
if ( crlf_size > 4 ) {
|
||||||
Error("Invalid CRLF length");
|
Error("Invalid CRLF length");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,7 +209,7 @@ int cURLCamera::Capture( Image &image ) {
|
||||||
|
|
||||||
/* Find where the data in this header starts */
|
/* Find where the data in this header starts */
|
||||||
size_t subheader_data_start = subheader.rfind(' ');
|
size_t subheader_data_start = subheader.rfind(' ');
|
||||||
if(subheader_data_start == std::string::npos) {
|
if ( subheader_data_start == std::string::npos ) {
|
||||||
subheader_data_start = subheader.find(':');
|
subheader_data_start = subheader.find(':');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +247,7 @@ int cURLCamera::Capture( Image &image ) {
|
||||||
need_more_data = true;
|
need_more_data = true;
|
||||||
} else {
|
} else {
|
||||||
/* All good. decode the image */
|
/* All good. decode the image */
|
||||||
image.DecodeJpeg(databuffer.extract(frame_content_length), frame_content_length, colours, subpixelorder);
|
zm_packet.image->DecodeJpeg(databuffer.extract(frame_content_length), frame_content_length, colours, subpixelorder);
|
||||||
frameComplete = true;
|
frameComplete = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -257,7 +257,7 @@ int cURLCamera::Capture( Image &image ) {
|
||||||
nRet = pthread_cond_wait(&data_available_cond,&shareddata_mutex);
|
nRet = pthread_cond_wait(&data_available_cond,&shareddata_mutex);
|
||||||
if(nRet != 0) {
|
if(nRet != 0) {
|
||||||
Error("Failed waiting for available data condition variable: %s",strerror(nRet));
|
Error("Failed waiting for available data condition variable: %s",strerror(nRet));
|
||||||
return -18;
|
return -1;
|
||||||
}
|
}
|
||||||
need_more_data = false;
|
need_more_data = false;
|
||||||
}
|
}
|
||||||
|
@ -267,7 +267,7 @@ int cURLCamera::Capture( Image &image ) {
|
||||||
if (!single_offsets.empty()) {
|
if (!single_offsets.empty()) {
|
||||||
if( (single_offsets.front() > 0) && (databuffer.size() >= single_offsets.front()) ) {
|
if( (single_offsets.front() > 0) && (databuffer.size() >= single_offsets.front()) ) {
|
||||||
/* Extract frame */
|
/* Extract frame */
|
||||||
image.DecodeJpeg(databuffer.extract(single_offsets.front()), single_offsets.front(), colours, subpixelorder);
|
zm_packet.image->DecodeJpeg(databuffer.extract(single_offsets.front()), single_offsets.front(), colours, subpixelorder);
|
||||||
single_offsets.pop_front();
|
single_offsets.pop_front();
|
||||||
frameComplete = true;
|
frameComplete = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -281,7 +281,7 @@ int cURLCamera::Capture( Image &image ) {
|
||||||
nRet = pthread_cond_wait(&request_complete_cond,&shareddata_mutex);
|
nRet = pthread_cond_wait(&request_complete_cond,&shareddata_mutex);
|
||||||
if(nRet != 0) {
|
if(nRet != 0) {
|
||||||
Error("Failed waiting for request complete condition variable: %s",strerror(nRet));
|
Error("Failed waiting for request complete condition variable: %s",strerror(nRet));
|
||||||
return -19;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -295,9 +295,9 @@ int cURLCamera::Capture( Image &image ) {
|
||||||
unlock();
|
unlock();
|
||||||
|
|
||||||
if(!frameComplete)
|
if(!frameComplete)
|
||||||
return -1;
|
return 0;
|
||||||
|
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cURLCamera::PostCapture() {
|
int cURLCamera::PostCapture() {
|
||||||
|
@ -305,12 +305,6 @@ int cURLCamera::PostCapture() {
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
int cURLCamera::CaptureAndRecord( Image &image, struct timeval recording, char* event_directory ) {
|
|
||||||
Error("Capture and Record not implemented for the cURL camera type");
|
|
||||||
// Nothing to do here
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t cURLCamera::data_callback(void *buffer, size_t size, size_t nmemb, void *userdata) {
|
size_t cURLCamera::data_callback(void *buffer, size_t size, size_t nmemb, void *userdata) {
|
||||||
lock();
|
lock();
|
||||||
|
|
||||||
|
|
|
@ -76,9 +76,8 @@ public:
|
||||||
|
|
||||||
int PrimeCapture();
|
int PrimeCapture();
|
||||||
int PreCapture();
|
int PreCapture();
|
||||||
int Capture( Image &image );
|
int Capture( ZMPacket &p );
|
||||||
int PostCapture();
|
int PostCapture();
|
||||||
int CaptureAndRecord( Image &image, struct timeval recording, char* event_directory );
|
|
||||||
|
|
||||||
size_t data_callback(void *buffer, size_t size, size_t nmemb, void *userdata);
|
size_t data_callback(void *buffer, size_t size, size_t nmemb, void *userdata);
|
||||||
size_t header_callback(void *buffer, size_t size, size_t nmemb, void *userdata);
|
size_t header_callback(void *buffer, size_t size, size_t nmemb, void *userdata);
|
||||||
|
|
|
@ -140,6 +140,7 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
|
||||||
if ( symlink( time_path, id_file ) < 0 )
|
if ( symlink( time_path, id_file ) < 0 )
|
||||||
Error( "Can't symlink %s -> %s: %s", id_file, path, strerror(errno));
|
Error( "Can't symlink %s -> %s: %s", id_file, path, strerror(errno));
|
||||||
} else {
|
} else {
|
||||||
|
// Shallow Storage
|
||||||
snprintf( path, sizeof(path), "%s/%d/%d", storage->Path(), monitor->Id(), id );
|
snprintf( path, sizeof(path), "%s/%d/%d", storage->Path(), monitor->Id(), id );
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
@ -168,40 +169,11 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
|
||||||
snprintf( video_name, sizeof(video_name), "%d-%s", id, "video.mp4" );
|
snprintf( video_name, sizeof(video_name), "%d-%s", id, "video.mp4" );
|
||||||
snprintf( video_file, sizeof(video_file), staticConfig.video_file_format, path, video_name );
|
snprintf( video_file, sizeof(video_file), staticConfig.video_file_format, path, video_name );
|
||||||
Debug(1,"Writing video file to %s", video_file );
|
Debug(1,"Writing video file to %s", video_file );
|
||||||
|
videowriter = NULL;
|
||||||
#if 0
|
|
||||||
/* X264 MP4 video writer */
|
|
||||||
if ( monitor->GetOptVideoWriter() == Monitor::X264ENCODE ) {
|
|
||||||
#if ZM_HAVE_VIDEOWRITER_X264MP4
|
|
||||||
videowriter = new X264MP4Writer(video_file, monitor->Width(), monitor->Height(), monitor->Colours(), monitor->SubpixelOrder(), monitor->GetOptEncoderParams());
|
|
||||||
#else
|
|
||||||
Error("ZoneMinder was not compiled with the X264 MP4 video writer, check dependencies (x264 and mp4v2)");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( videowriter != NULL ) {
|
|
||||||
/* Open the video stream */
|
|
||||||
int nRet = videowriter->Open();
|
|
||||||
if(nRet != 0) {
|
|
||||||
Error("Failed opening video stream");
|
|
||||||
delete videowriter;
|
|
||||||
videowriter = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf( timecodes_name, sizeof(timecodes_name), "%d-%s", id, "video.timecodes" );
|
|
||||||
snprintf( timecodes_file, sizeof(timecodes_file), staticConfig.video_file_format, path, timecodes_name );
|
|
||||||
|
|
||||||
/* Create timecodes file */
|
|
||||||
timecodes_fd = fopen(timecodes_file, "wb");
|
|
||||||
if ( timecodes_fd == NULL ) {
|
|
||||||
Error("Failed creating timecodes file");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/* No video object */
|
/* No video object */
|
||||||
videowriter = NULL;
|
videowriter = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
} // Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap, bool p_videoEvent )
|
} // Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap, bool p_videoEvent )
|
||||||
|
|
||||||
|
@ -211,7 +183,6 @@ Event::~Event() {
|
||||||
DELTA_TIMEVAL( delta_time, end_time, start_time, DT_PREC_2 );
|
DELTA_TIMEVAL( delta_time, end_time, start_time, DT_PREC_2 );
|
||||||
|
|
||||||
if ( frames > last_db_frame ) {
|
if ( frames > last_db_frame ) {
|
||||||
|
|
||||||
Debug( 1, "Adding closing frame %d to DB", frames );
|
Debug( 1, "Adding closing frame %d to DB", frames );
|
||||||
snprintf( sql, sizeof(sql), "insert into Frames ( EventId, FrameId, TimeStamp, Delta ) values ( %d, %d, from_unixtime( %ld ), %s%ld.%02ld )", id, frames, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec );
|
snprintf( sql, sizeof(sql), "insert into Frames ( EventId, FrameId, TimeStamp, Delta ) values ( %d, %d, from_unixtime( %ld ), %s%ld.%02ld )", id, frames, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec );
|
||||||
if ( mysql_query( &dbconn, sql ) ) {
|
if ( mysql_query( &dbconn, sql ) ) {
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "zm_stream.h"
|
#include "zm_stream.h"
|
||||||
#include "zm_video.h"
|
#include "zm_video.h"
|
||||||
#include "zm_ffmpeg_input.h"
|
#include "zm_ffmpeg_input.h"
|
||||||
|
#include "zm_monitor.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -108,11 +109,17 @@ class EventStream : public StreamBase {
|
||||||
}
|
}
|
||||||
void setStreamStart( int init_event_id, unsigned int init_frame_id=0 ) {
|
void setStreamStart( int init_event_id, unsigned int init_frame_id=0 ) {
|
||||||
loadInitialEventData( init_event_id, init_frame_id );
|
loadInitialEventData( init_event_id, init_frame_id );
|
||||||
loadMonitor( event_data->monitor_id );
|
if ( !(monitor = Monitor::Load( event_data->monitor_id, false, Monitor::QUERY )) ) {
|
||||||
|
Fatal( "Unable to load monitor id %d for streaming", event_data->monitor_id );
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void setStreamStart( int monitor_id, time_t event_time ) {
|
void setStreamStart( int monitor_id, time_t event_time ) {
|
||||||
loadInitialEventData( monitor_id, event_time );
|
loadInitialEventData( monitor_id, event_time );
|
||||||
loadMonitor( monitor_id );
|
if ( !(monitor = Monitor::Load( event_data->monitor_id, false, Monitor::QUERY )) ) {
|
||||||
|
Fatal( "Unable to load monitor id %d for streaming", monitor_id );
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void setStreamMode( StreamMode p_mode ) {
|
void setStreamMode( StreamMode p_mode ) {
|
||||||
mode = p_mode;
|
mode = p_mode;
|
||||||
|
|
|
@ -133,6 +133,7 @@ int av_dict_parse_string(AVDictionary **pm, const char *str,
|
||||||
#endif // HAVE_LIBAVCODEC || HAVE_LIBAVUTIL || HAVE_LIBSWSCALE
|
#endif // HAVE_LIBAVCODEC || HAVE_LIBAVUTIL || HAVE_LIBSWSCALE
|
||||||
|
|
||||||
#if HAVE_LIBAVUTIL
|
#if HAVE_LIBAVUTIL
|
||||||
|
#if LIBAVUTIL_VERSION_CHECK(56, 0, 0, 17, 100)
|
||||||
int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb){
|
int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb){
|
||||||
int64_t a, b, this_thing;
|
int64_t a, b, this_thing;
|
||||||
|
|
||||||
|
@ -156,6 +157,7 @@ simple_round:
|
||||||
return av_rescale_q(this_thing, fs_tb, out_tb);
|
return av_rescale_q(this_thing, fs_tb, out_tb);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
int hacked_up_context2_for_older_ffmpeg(AVFormatContext **avctx, AVOutputFormat *oformat, const char *format, const char *filename) {
|
int hacked_up_context2_for_older_ffmpeg(AVFormatContext **avctx, AVOutputFormat *oformat, const char *format, const char *filename) {
|
||||||
AVFormatContext *s = avformat_alloc_context();
|
AVFormatContext *s = avformat_alloc_context();
|
||||||
|
|
|
@ -177,138 +177,43 @@ int FfmpegCamera::PreCapture() {
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
ZMPacket * FfmpegCamera::Capture( Image &image ) {
|
int FfmpegCamera::Capture( ZMPacket &zm_packet ) {
|
||||||
if ( ! mCanCapture ) {
|
if ( ! mCanCapture ) {
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
char errbuf[AV_ERROR_MAX_STRING_SIZE];
|
|
||||||
|
|
||||||
// If the reopen thread has a value, but mCanCapture != 0, then we have just reopened the connection to the ffmpeg device, and we can clean up the thread.
|
// If the reopen thread has a value, but mCanCapture != 0, then we have just reopened the connection to the ffmpeg device, and we can clean up the thread.
|
||||||
if ( mReopenThread != 0 ) {
|
if ( mReopenThread != 0 ) {
|
||||||
void *retval = 0;
|
void *retval = 0;
|
||||||
|
|
||||||
ret = pthread_join(mReopenThread, &retval);
|
ret = pthread_join(mReopenThread, &retval);
|
||||||
if ( ret != 0 ) {
|
if ( ret != 0 ) {
|
||||||
Error("Could not join reopen thread.");
|
Error("Could not join reopen thread.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Info( "Successfully reopened stream." );
|
Info( "Successfully reopened stream." );
|
||||||
mReopenThread = 0;
|
mReopenThread = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZMPacket *zm_packet = NULL;
|
|
||||||
|
|
||||||
ret = av_read_frame( mFormatContext, &packet );
|
ret = av_read_frame( mFormatContext, &packet );
|
||||||
if ( ret < 0 ) {
|
if ( ret < 0 ) {
|
||||||
av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
|
||||||
if (
|
if (
|
||||||
// Check if EOF.
|
// Check if EOF.
|
||||||
(ret == AVERROR_EOF || (mFormatContext->pb && mFormatContext->pb->eof_reached)) ||
|
(ret == AVERROR_EOF || (mFormatContext->pb && mFormatContext->pb->eof_reached)) ||
|
||||||
// Check for Connection failure.
|
// Check for Connection failure.
|
||||||
(ret == -110)
|
(ret == -110)
|
||||||
) {
|
) {
|
||||||
Info( "av_read_frame returned \"%s\". Reopening stream.", errbuf );
|
Info( "av_read_frame returned \"%s\". Reopening stream.", av_make_error_string(ret).c_str() );
|
||||||
ReopenFfmpeg();
|
ReopenFfmpeg();
|
||||||
}
|
}
|
||||||
|
Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, av_make_error_string(ret).c_str() );
|
||||||
Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, errbuf );
|
return -1;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
Debug( 5, "Got packet from stream %d dts (%d) pts(%d)", packet.stream_index, packet.pts, packet.dts );
|
Debug( 5, "Got packet from stream %d dts (%d) pts(%d)", packet.stream_index, packet.pts, packet.dts );
|
||||||
|
|
||||||
#if 0
|
zm_packet.set_packet( &packet );
|
||||||
// What about audio stream? Maybe someday we could do sound detection...
|
|
||||||
if ( ( packet.stream_index == mVideoStreamId ) && ( keyframe || have_video_keyframe ) ) {
|
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
|
||||||
ret = avcodec_send_packet( mVideoCodecContext, &packet );
|
|
||||||
if ( ret < 0 ) {
|
|
||||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
|
||||||
Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf );
|
|
||||||
zm_av_packet_unref( &packet );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if HAVE_AVUTIL_HWCONTEXT_H
|
|
||||||
if ( hwaccel ) {
|
|
||||||
ret = avcodec_receive_frame( mVideoCodecContext, hwFrame );
|
|
||||||
if ( ret < 0 ) {
|
|
||||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
|
||||||
Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf );
|
|
||||||
zm_av_packet_unref( &packet );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ret = av_hwframe_transfer_data(mRawFrame, hwFrame, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
|
||||||
Error( "Unable to transfer frame at frame %d: %s, continuing", frameCount, errbuf );
|
|
||||||
zm_av_packet_unref( &packet );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
#endif
|
|
||||||
ret = avcodec_receive_frame( mVideoCodecContext, mRawFrame );
|
|
||||||
if ( ret < 0 ) {
|
|
||||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
|
||||||
Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf );
|
|
||||||
zm_av_packet_unref( &packet );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if HAVE_AVUTIL_HWCONTEXT_H
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
frameComplete = 1;
|
|
||||||
# else
|
|
||||||
ret = zm_avcodec_decode_video( mVideoCodecContext, mRawFrame, &frameComplete, &packet );
|
|
||||||
if ( ret < 0 ) {
|
|
||||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
|
||||||
Error( "Unable to decode frame at frame %d: %s, continuing", frameCount, errbuf );
|
|
||||||
zm_av_packet_unref( &packet );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Debug( 4, "Decoded video packet at frame %d", frameCount );
|
|
||||||
|
|
||||||
if ( frameComplete ) {
|
|
||||||
Debug( 4, "Got frame %d", frameCount );
|
|
||||||
|
|
||||||
uint8_t* directbuffer;
|
|
||||||
|
|
||||||
/* Request a writeable buffer of the target image */
|
|
||||||
directbuffer = image.WriteBuffer(width, height, colours, subpixelorder);
|
|
||||||
if ( directbuffer == NULL ) {
|
|
||||||
Error("Failed requesting writeable buffer for the captured image.");
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
|
||||||
av_image_fill_arrays(mFrame->data, mFrame->linesize,
|
|
||||||
directbuffer, imagePixFormat, width, height, 1);
|
|
||||||
#else
|
|
||||||
avpicture_fill( (AVPicture *)mFrame, directbuffer,
|
|
||||||
imagePixFormat, width, height);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if HAVE_LIBSWSCALE
|
|
||||||
if ( sws_scale(mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mVideoCodecContext->height, mFrame->data, mFrame->linesize) < 0 )
|
|
||||||
Fatal("Unable to convert raw format %u to target format %u at frame %d", mVideoCodecContext->pix_fmt, imagePixFormat, frameCount);
|
|
||||||
#else // HAVE_LIBSWSCALE
|
|
||||||
Fatal("You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras");
|
|
||||||
#endif // HAVE_LIBSWSCALE
|
|
||||||
|
|
||||||
frameCount++;
|
|
||||||
} // end if frameComplete
|
|
||||||
} else {
|
|
||||||
Debug( 4, "Different stream_index %d", packet.stream_index );
|
|
||||||
} // end if packet.stream_index == mVideoStreamId
|
|
||||||
#endif
|
|
||||||
zm_packet = new ZMPacket( &packet );
|
|
||||||
zm_av_packet_unref( &packet );
|
zm_av_packet_unref( &packet );
|
||||||
return zm_packet;
|
return 1;
|
||||||
} // FfmpegCamera::Capture
|
} // FfmpegCamera::Capture
|
||||||
|
|
||||||
int FfmpegCamera::PostCapture() {
|
int FfmpegCamera::PostCapture() {
|
||||||
|
@ -448,7 +353,9 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||||
// STolen from ispy
|
// STolen from ispy
|
||||||
//this fixes issues with rtsp streams!! woot.
|
//this fixes issues with rtsp streams!! woot.
|
||||||
//mVideoCodecContext->flags2 |= CODEC_FLAG2_FAST | CODEC_FLAG2_CHUNKS | CODEC_FLAG_LOW_DELAY; // Enable faster H264 decode.
|
//mVideoCodecContext->flags2 |= CODEC_FLAG2_FAST | CODEC_FLAG2_CHUNKS | CODEC_FLAG_LOW_DELAY; // Enable faster H264 decode.
|
||||||
|
#ifdef CODEC_FLAG2_FAST
|
||||||
mVideoCodecContext->flags2 |= CODEC_FLAG2_FAST | CODEC_FLAG_LOW_DELAY;
|
mVideoCodecContext->flags2 |= CODEC_FLAG2_FAST | CODEC_FLAG_LOW_DELAY;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if HAVE_AVUTIL_HWCONTEXT_H
|
#if HAVE_AVUTIL_HWCONTEXT_H
|
||||||
if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H264 ) {
|
if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H264 ) {
|
||||||
|
@ -485,7 +392,16 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
#ifdef AV_CODEC_ID_H265
|
||||||
|
if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H265 ) {
|
||||||
|
Debug( 1, "Input stream appears to be h265. The stored event file may not be viewable in browser." );
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
Error( "Input stream is not h264. The stored event file may not be viewable in browser." );
|
||||||
|
#ifdef AV_CODEC_ID_H265
|
||||||
|
}
|
||||||
|
#endif
|
||||||
} // end if h264
|
} // end if h264
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -517,6 +433,18 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( mVideoCodecContext->codec_id != AV_CODEC_ID_H264 ) {
|
||||||
|
#ifdef AV_CODEC_ID_H265
|
||||||
|
if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H265 ) {
|
||||||
|
Debug( 1, "Input stream appears to be h265. The stored event file may not be viewable in browser." );
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
Warning( "Input stream is not h264. The stored event file may not be viewable in browser." );
|
||||||
|
#ifdef AV_CODEC_ID_H265
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (mVideoCodecContext->hwaccel != NULL) {
|
if (mVideoCodecContext->hwaccel != NULL) {
|
||||||
Debug(1, "HWACCEL in use");
|
Debug(1, "HWACCEL in use");
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -40,6 +40,7 @@ class FfmpegCamera : public Camera {
|
||||||
std::string mPath;
|
std::string mPath;
|
||||||
std::string mMethod;
|
std::string mMethod;
|
||||||
std::string mOptions;
|
std::string mOptions;
|
||||||
|
std::string encoder_options;
|
||||||
|
|
||||||
int frameCount;
|
int frameCount;
|
||||||
|
|
||||||
|
@ -89,7 +90,20 @@ class FfmpegCamera : public Camera {
|
||||||
int64_t startTime;
|
int64_t startTime;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FfmpegCamera( int p_id, const std::string &path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio );
|
FfmpegCamera(
|
||||||
|
int p_id,
|
||||||
|
const std::string &path,
|
||||||
|
const std::string &p_method,
|
||||||
|
const std::string &p_options,
|
||||||
|
int p_width,
|
||||||
|
int p_height,
|
||||||
|
int p_colours,
|
||||||
|
int p_brightness,
|
||||||
|
int p_contrast,
|
||||||
|
int p_hue,
|
||||||
|
int p_colour,
|
||||||
|
bool p_capture,
|
||||||
|
bool p_record_audio );
|
||||||
~FfmpegCamera();
|
~FfmpegCamera();
|
||||||
|
|
||||||
const std::string &Path() const { return( mPath ); }
|
const std::string &Path() const { return( mPath ); }
|
||||||
|
@ -101,15 +115,14 @@ class FfmpegCamera : public Camera {
|
||||||
|
|
||||||
int PrimeCapture();
|
int PrimeCapture();
|
||||||
int PreCapture();
|
int PreCapture();
|
||||||
ZMPacket * Capture( Image &image );
|
int Capture(ZMPacket &p);
|
||||||
int CaptureAndRecord( Image &image, timeval recording, char* event_directory );
|
|
||||||
int PostCapture();
|
int PostCapture();
|
||||||
AVStream *get_VideoStream() {
|
AVStream *get_VideoStream() {
|
||||||
if ( mVideoStreamId != -1 )
|
if ( mVideoStreamId != -1 )
|
||||||
return mFormatContext->streams[mVideoStreamId];
|
return mFormatContext->streams[mVideoStreamId];
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
AVStream *get_AudioStream() {
|
AVStream *get_AudioStream() {
|
||||||
if ( mAudioStreamId != -1 )
|
if ( mAudioStreamId != -1 )
|
||||||
return mFormatContext->streams[mAudioStreamId];
|
return mFormatContext->streams[mAudioStreamId];
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -116,9 +116,9 @@ AVFrame *FFmpeg_Input::get_frame( int stream_id ) {
|
||||||
if ( (stream_id < 0 ) || ( packet.stream_index == stream_id ) ) {
|
if ( (stream_id < 0 ) || ( packet.stream_index == stream_id ) ) {
|
||||||
Debug(1,"Packet is for our stream (%d)", packet.stream_index );
|
Debug(1,"Packet is for our stream (%d)", packet.stream_index );
|
||||||
|
|
||||||
AVCodecContext *context = streams[packet.stream_index].context;
|
|
||||||
|
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
|
AVCodecContext *context = streams[packet.stream_index].context;
|
||||||
|
|
||||||
ret = avcodec_send_packet( context, &packet );
|
ret = avcodec_send_packet( context, &packet );
|
||||||
if ( ret < 0 ) {
|
if ( ret < 0 ) {
|
||||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||||
|
|
|
@ -0,0 +1,180 @@
|
||||||
|
|
||||||
|
#include "zm_ffmpeg_input.h"
|
||||||
|
#include "zm_logger.h"
|
||||||
|
#include "zm_ffmpeg.h"
|
||||||
|
|
||||||
|
FFmpeg_Output::FFmpeg_Output() {
|
||||||
|
input_format_context = NULL;
|
||||||
|
video_stream_id = -1;
|
||||||
|
audio_stream_id = -1;
|
||||||
|
av_register_all();
|
||||||
|
avcodec_register_all();
|
||||||
|
|
||||||
|
}
|
||||||
|
FFmpeg_Output::~FFmpeg_Output() {
|
||||||
|
}
|
||||||
|
|
||||||
|
int FFmpeg_Output::Open( const char *filepath ) {
|
||||||
|
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/** Open the input file to read from it. */
|
||||||
|
if ( (error = avformat_open_input( &input_format_context, filepath, NULL, NULL)) < 0 ) {
|
||||||
|
|
||||||
|
Error("Could not open input file '%s' (error '%s')\n",
|
||||||
|
filepath, av_make_error_string(error).c_str() );
|
||||||
|
input_format_context = NULL;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get information on the input file (number of streams etc.). */
|
||||||
|
if ( (error = avformat_find_stream_info(input_format_context, NULL)) < 0 ) {
|
||||||
|
Error( "Could not open find stream info (error '%s')\n",
|
||||||
|
av_make_error_string(error).c_str() );
|
||||||
|
avformat_close_input(&input_format_context);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( unsigned int i = 0; i < input_format_context->nb_streams; i += 1 ) {
|
||||||
|
if ( is_video_stream( input_format_context->streams[i] ) ) {
|
||||||
|
zm_dump_stream_format(input_format_context, i, 0, 0);
|
||||||
|
if ( video_stream_id == -1 ) {
|
||||||
|
video_stream_id = i;
|
||||||
|
// if we break, then we won't find the audio stream
|
||||||
|
} else {
|
||||||
|
Warning( "Have another video stream." );
|
||||||
|
}
|
||||||
|
} else if ( is_audio_stream( input_format_context->streams[i] ) ) {
|
||||||
|
if ( audio_stream_id == -1 ) {
|
||||||
|
audio_stream_id = i;
|
||||||
|
} else {
|
||||||
|
Warning( "Have another audio stream." );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
streams[i].frame_count = 0;
|
||||||
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
|
streams[i].context = avcodec_alloc_context3( NULL );
|
||||||
|
avcodec_parameters_to_context( streams[i].context, input_format_context->streams[i]->codecpar );
|
||||||
|
#else
|
||||||
|
streams[i].context = input_format_context->streams[i]->codec;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( !(streams[i].codec = avcodec_find_decoder(streams[i].context->codec_id)) ) {
|
||||||
|
Error( "Could not find input codec\n");
|
||||||
|
avformat_close_input(&input_format_context);
|
||||||
|
return AVERROR_EXIT;
|
||||||
|
} else {
|
||||||
|
Debug(1, "Using codec (%s) for stream %d", streams[i].codec->name, i );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((error = avcodec_open2( streams[i].context, streams[i].codec, NULL)) < 0) {
|
||||||
|
Error( "Could not open input codec (error '%s')\n",
|
||||||
|
av_make_error_string(error).c_str() );
|
||||||
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
|
avcodec_free_context( &streams[i].context );
|
||||||
|
#endif
|
||||||
|
avformat_close_input(&input_format_context);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
} // end foreach stream
|
||||||
|
|
||||||
|
if ( video_stream_id == -1 )
|
||||||
|
Error( "Unable to locate video stream in %s", filepath );
|
||||||
|
if ( audio_stream_id == -1 )
|
||||||
|
Debug( 3, "Unable to locate audio stream in %s", filepath );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} // end int FFmpeg_Output::Open( const char * filepath )
|
||||||
|
|
||||||
|
AVFrame *FFmpeg_Output::get_frame( int stream_id ) {
|
||||||
|
Debug(1, "Getting frame from stream %d", stream_id );
|
||||||
|
|
||||||
|
int frameComplete = false;
|
||||||
|
AVPacket packet;
|
||||||
|
av_init_packet( &packet );
|
||||||
|
AVFrame *frame = zm_av_frame_alloc();
|
||||||
|
char errbuf[AV_ERROR_MAX_STRING_SIZE];
|
||||||
|
|
||||||
|
while ( !frameComplete ) {
|
||||||
|
int ret = av_read_frame( input_format_context, &packet );
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
||||||
|
if (
|
||||||
|
// Check if EOF.
|
||||||
|
(ret == AVERROR_EOF || (input_format_context->pb && input_format_context->pb->eof_reached)) ||
|
||||||
|
// Check for Connection failure.
|
||||||
|
(ret == -110)
|
||||||
|
) {
|
||||||
|
Info( "av_read_frame returned %s.", errbuf );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, errbuf );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (stream_id < 0 ) || ( packet.stream_index == stream_id ) ) {
|
||||||
|
Debug(1,"Packet is for our stream (%d)", packet.stream_index );
|
||||||
|
|
||||||
|
AVCodecContext *context = streams[packet.stream_index].context;
|
||||||
|
|
||||||
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
|
ret = avcodec_send_packet( context, &packet );
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||||
|
Error( "Unable to send packet at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf );
|
||||||
|
zm_av_packet_unref( &packet );
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
Debug(1, "Success getting a packet");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_AVUTIL_HWCONTEXT_H
|
||||||
|
if ( hwaccel ) {
|
||||||
|
ret = avcodec_receive_frame( context, hwFrame );
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||||
|
Error( "Unable to receive frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf );
|
||||||
|
zm_av_packet_unref( &packet );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ret = av_hwframe_transfer_data(frame, hwFrame, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||||
|
Error( "Unable to transfer frame at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf );
|
||||||
|
zm_av_packet_unref( &packet );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
Debug(1,"Getting a frame?");
|
||||||
|
ret = avcodec_receive_frame( context, frame );
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||||
|
Error( "Unable to send packet at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf );
|
||||||
|
zm_av_packet_unref( &packet );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_AVUTIL_HWCONTEXT_H
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
frameComplete = 1;
|
||||||
|
# else
|
||||||
|
ret = zm_avcodec_decode_video( streams[packet.stream_index].context, frame, &frameComplete, &packet );
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||||
|
Error( "Unable to decode frame at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf );
|
||||||
|
zm_av_packet_unref( &packet );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // end if it's the right stream
|
||||||
|
|
||||||
|
zm_av_packet_unref( &packet );
|
||||||
|
|
||||||
|
} // end while ! frameComplete
|
||||||
|
return frame;
|
||||||
|
|
||||||
|
} // end AVFrame *FFmpeg_Output::get_frame
|
|
@ -0,0 +1,46 @@
|
||||||
|
#ifndef ZM_FFMPEG_INPUT_H
|
||||||
|
#define ZM_FFMPEG_INPUT_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "libavformat/avformat.h"
|
||||||
|
#include "libavformat/avio.h"
|
||||||
|
#include "libavcodec/avcodec.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class FFmpeg_Output {
|
||||||
|
|
||||||
|
public:
|
||||||
|
FFmpeg_Output();
|
||||||
|
~FFmpeg_Output();
|
||||||
|
|
||||||
|
int Open( const char *filename );
|
||||||
|
int Close();
|
||||||
|
AVFrame *put_frame( int stream_id=-1 );
|
||||||
|
AVFrame *put_packet( int stream_id=-1 );
|
||||||
|
int get_video_stream_id() {
|
||||||
|
return video_stream_id;
|
||||||
|
}
|
||||||
|
int get_audio_stream_id() {
|
||||||
|
return audio_stream_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef struct {
|
||||||
|
AVCodecContext *context;
|
||||||
|
AVCodec *codec;
|
||||||
|
int frame_count;
|
||||||
|
} stream;
|
||||||
|
|
||||||
|
stream streams[2];
|
||||||
|
int video_stream_id;
|
||||||
|
int audio_stream_id;
|
||||||
|
AVFormatContext *input_format_context;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -34,7 +34,31 @@
|
||||||
#include "zm.h"
|
#include "zm.h"
|
||||||
#include "zm_file_camera.h"
|
#include "zm_file_camera.h"
|
||||||
|
|
||||||
FileCamera::FileCamera( int p_id, const char *p_path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) : Camera( p_id, FILE_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio )
|
FileCamera::FileCamera(
|
||||||
|
int p_id,
|
||||||
|
const char *p_path,
|
||||||
|
int p_width,
|
||||||
|
int p_height,
|
||||||
|
int p_colours,
|
||||||
|
int p_brightness,
|
||||||
|
int p_contrast,
|
||||||
|
int p_hue,
|
||||||
|
int p_colour,
|
||||||
|
bool p_capture,
|
||||||
|
bool p_record_audio
|
||||||
|
) : Camera(
|
||||||
|
p_id,
|
||||||
|
FILE_SRC,
|
||||||
|
p_width,
|
||||||
|
p_height,
|
||||||
|
p_colours,
|
||||||
|
ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours),
|
||||||
|
p_brightness,
|
||||||
|
p_contrast,
|
||||||
|
p_hue,
|
||||||
|
p_colour,
|
||||||
|
p_capture,
|
||||||
|
p_record_audio )
|
||||||
{
|
{
|
||||||
strncpy( path, p_path, sizeof(path) );
|
strncpy( path, p_path, sizeof(path) );
|
||||||
if ( capture ) {
|
if ( capture ) {
|
||||||
|
@ -72,11 +96,8 @@ int FileCamera::PreCapture() {
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
ZMPacket * FileCamera::Capture( Image &image ) {
|
int FileCamera::Capture( ZMPacket &zm_packet ) {
|
||||||
ZMPacket * packet = NULL;
|
return zm_packet.image->ReadJpeg( path, colours, subpixelorder ) ;
|
||||||
if ( image.ReadJpeg( path, colours, subpixelorder ) )
|
|
||||||
packet = new ZMPacket( &image );
|
|
||||||
return packet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int FileCamera::PostCapture() {
|
int FileCamera::PostCapture() {
|
||||||
|
|
|
@ -56,7 +56,7 @@ public:
|
||||||
void Initialise();
|
void Initialise();
|
||||||
void Terminate();
|
void Terminate();
|
||||||
int PreCapture();
|
int PreCapture();
|
||||||
ZMPacket * Capture( Image &image );
|
int Capture( ZMPacket &p );
|
||||||
int PostCapture();
|
int PostCapture();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,6 @@ Image::Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uin
|
||||||
}
|
}
|
||||||
|
|
||||||
Image::Image( const AVFrame *frame ) {
|
Image::Image( const AVFrame *frame ) {
|
||||||
AVFrame *dest_frame = zm_av_frame_alloc();
|
|
||||||
|
|
||||||
width = frame->width;
|
width = frame->width;
|
||||||
height = frame->height;
|
height = frame->height;
|
||||||
|
@ -141,7 +140,13 @@ Image::Image( const AVFrame *frame ) {
|
||||||
buffer = 0;
|
buffer = 0;
|
||||||
holdbuffer = 0;
|
holdbuffer = 0;
|
||||||
AllocImgBuffer(size);
|
AllocImgBuffer(size);
|
||||||
|
this->Assign( frame );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::Assign( const AVFrame *frame ) {
|
||||||
|
/* Assume the dimensions etc are correct. FIXME */
|
||||||
|
|
||||||
|
AVFrame *dest_frame = zm_av_frame_alloc();
|
||||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
av_image_fill_arrays(dest_frame->data, dest_frame->linesize,
|
av_image_fill_arrays(dest_frame->data, dest_frame->linesize,
|
||||||
buffer, AV_PIX_FMT_RGBA, width, height, 1);
|
buffer, AV_PIX_FMT_RGBA, width, height, 1);
|
||||||
|
@ -167,7 +172,7 @@ Image::Image( const AVFrame *frame ) {
|
||||||
Fatal("You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras");
|
Fatal("You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras");
|
||||||
#endif // HAVE_LIBSWSCALE
|
#endif // HAVE_LIBSWSCALE
|
||||||
av_frame_free( &dest_frame );
|
av_frame_free( &dest_frame );
|
||||||
}
|
} // end Image::Image( const AVFrame *frame )
|
||||||
|
|
||||||
Image::Image( const Image &p_image ) {
|
Image::Image( const Image &p_image ) {
|
||||||
if ( !initialised )
|
if ( !initialised )
|
||||||
|
@ -613,25 +618,25 @@ void Image::Assign(const unsigned int p_width, const unsigned int p_height, cons
|
||||||
void Image::Assign( const Image &image ) {
|
void Image::Assign( const Image &image ) {
|
||||||
unsigned int new_size = (image.width * image.height) * image.colours;
|
unsigned int new_size = (image.width * image.height) * image.colours;
|
||||||
|
|
||||||
if(image.buffer == NULL) {
|
if ( image.buffer == NULL ) {
|
||||||
Error("Attempt to assign image with an empty buffer");
|
Error("Attempt to assign image with an empty buffer");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(image.colours != ZM_COLOUR_GRAY8 && image.colours != ZM_COLOUR_RGB24 && image.colours != ZM_COLOUR_RGB32) {
|
if ( image.colours != ZM_COLOUR_GRAY8 && image.colours != ZM_COLOUR_RGB24 && image.colours != ZM_COLOUR_RGB32 ) {
|
||||||
Error("Attempt to assign image with unexpected colours per pixel: %d",image.colours);
|
Error("Attempt to assign image with unexpected colours per pixel: %d",image.colours);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !buffer || image.width != width || image.height != height || image.colours != colours || image.subpixelorder != subpixelorder) {
|
if ( !buffer || image.width != width || image.height != height || image.colours != colours || image.subpixelorder != subpixelorder ) {
|
||||||
|
|
||||||
if (holdbuffer && buffer) {
|
if ( holdbuffer && buffer ) {
|
||||||
if (new_size > allocation) {
|
if ( new_size > allocation ) {
|
||||||
Error("Held buffer is undersized for assigned buffer");
|
Error("Held buffer is undersized for assigned buffer");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(new_size > allocation || !buffer) {
|
if ( new_size > allocation || !buffer ) {
|
||||||
// DumpImgBuffer(); This is also done in AllocImgBuffer
|
// DumpImgBuffer(); This is also done in AllocImgBuffer
|
||||||
AllocImgBuffer(new_size);
|
AllocImgBuffer(new_size);
|
||||||
}
|
}
|
||||||
|
@ -645,7 +650,7 @@ void Image::Assign( const Image &image ) {
|
||||||
size = new_size;
|
size = new_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(image.buffer != buffer)
|
if ( image.buffer != buffer )
|
||||||
(*fptr_imgbufcpy)(buffer, image.buffer, size);
|
(*fptr_imgbufcpy)(buffer, image.buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -207,6 +207,7 @@ public:
|
||||||
|
|
||||||
void Assign( unsigned int p_width, unsigned int p_height, unsigned int p_colours, unsigned int p_subpixelorder, const uint8_t* new_buffer, const size_t buffer_size);
|
void Assign( unsigned int p_width, unsigned int p_height, unsigned int p_colours, unsigned int p_subpixelorder, const uint8_t* new_buffer, const size_t buffer_size);
|
||||||
void Assign( const Image &image );
|
void Assign( const Image &image );
|
||||||
|
void Assign( const AVFrame *frame );
|
||||||
void AssignDirect( const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder, uint8_t *new_buffer, const size_t buffer_size, const int p_buffertype);
|
void AssignDirect( const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder, uint8_t *new_buffer, const size_t buffer_size, const int p_buffertype);
|
||||||
|
|
||||||
inline void CopyBuffer( const Image &image ) {
|
inline void CopyBuffer( const Image &image ) {
|
||||||
|
|
|
@ -23,8 +23,7 @@
|
||||||
#if HAVE_LIBVLC
|
#if HAVE_LIBVLC
|
||||||
|
|
||||||
// Do all the buffer checking work here to avoid unnecessary locking
|
// Do all the buffer checking work here to avoid unnecessary locking
|
||||||
void* LibvlcLockBuffer(void* opaque, void** planes)
|
void* LibvlcLockBuffer(void* opaque, void** planes) {
|
||||||
{
|
|
||||||
LibvlcPrivateData* data = (LibvlcPrivateData*)opaque;
|
LibvlcPrivateData* data = (LibvlcPrivateData*)opaque;
|
||||||
data->mutex.lock();
|
data->mutex.lock();
|
||||||
|
|
||||||
|
@ -36,15 +35,12 @@ void* LibvlcLockBuffer(void* opaque, void** planes)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes)
|
void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) {
|
||||||
{
|
|
||||||
LibvlcPrivateData* data = (LibvlcPrivateData*)opaque;
|
LibvlcPrivateData* data = (LibvlcPrivateData*)opaque;
|
||||||
|
|
||||||
bool newFrame = false;
|
bool newFrame = false;
|
||||||
for(uint32_t i = 0; i < data->bufferSize; i++)
|
for( uint32_t i = 0; i < data->bufferSize; i++ ) {
|
||||||
{
|
if ( data->buffer[i] != data->prevBuffer[i] ) {
|
||||||
if(data->buffer[i] != data->prevBuffer[i])
|
|
||||||
{
|
|
||||||
newFrame = true;
|
newFrame = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -54,8 +50,7 @@ void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes)
|
||||||
time_t now;
|
time_t now;
|
||||||
time(&now);
|
time(&now);
|
||||||
// Return frames slightly faster than 1fps (if time() supports greater than one second resolution)
|
// Return frames slightly faster than 1fps (if time() supports greater than one second resolution)
|
||||||
if(newFrame || difftime(now, data->prevTime) >= 0.8)
|
if ( newFrame || difftime(now, data->prevTime) >= 0.8 ) {
|
||||||
{
|
|
||||||
data->prevTime = now;
|
data->prevTime = now;
|
||||||
data->newImage.updateValueSignal(true);
|
data->newImage.updateValueSignal(true);
|
||||||
}
|
}
|
||||||
|
@ -90,58 +85,46 @@ LibvlcCamera::LibvlcCamera( int p_id, const std::string &p_path, const std::stri
|
||||||
Panic("Unexpected colours: %d",colours);
|
Panic("Unexpected colours: %d",colours);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( capture )
|
if ( capture ) {
|
||||||
{
|
|
||||||
Initialise();
|
Initialise();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LibvlcCamera::~LibvlcCamera()
|
LibvlcCamera::~LibvlcCamera() {
|
||||||
{
|
if ( capture ) {
|
||||||
if ( capture )
|
|
||||||
{
|
|
||||||
Terminate();
|
Terminate();
|
||||||
}
|
}
|
||||||
if(mLibvlcMediaPlayer != NULL)
|
if ( mLibvlcMediaPlayer != NULL ) {
|
||||||
{
|
|
||||||
libvlc_media_player_release(mLibvlcMediaPlayer);
|
libvlc_media_player_release(mLibvlcMediaPlayer);
|
||||||
mLibvlcMediaPlayer = NULL;
|
mLibvlcMediaPlayer = NULL;
|
||||||
}
|
}
|
||||||
if(mLibvlcMedia != NULL)
|
if ( mLibvlcMedia != NULL ) {
|
||||||
{
|
|
||||||
libvlc_media_release(mLibvlcMedia);
|
libvlc_media_release(mLibvlcMedia);
|
||||||
mLibvlcMedia = NULL;
|
mLibvlcMedia = NULL;
|
||||||
}
|
}
|
||||||
if(mLibvlcInstance != NULL)
|
if ( mLibvlcInstance != NULL ) {
|
||||||
{
|
|
||||||
libvlc_release(mLibvlcInstance);
|
libvlc_release(mLibvlcInstance);
|
||||||
mLibvlcInstance = NULL;
|
mLibvlcInstance = NULL;
|
||||||
}
|
}
|
||||||
if (mOptArgV != NULL)
|
if ( mOptArgV != NULL ) {
|
||||||
{
|
|
||||||
delete[] mOptArgV;
|
delete[] mOptArgV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibvlcCamera::Initialise()
|
void LibvlcCamera::Initialise() {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibvlcCamera::Terminate()
|
void LibvlcCamera::Terminate() {
|
||||||
{
|
|
||||||
libvlc_media_player_stop(mLibvlcMediaPlayer);
|
libvlc_media_player_stop(mLibvlcMediaPlayer);
|
||||||
if(mLibvlcData.buffer != NULL)
|
if(mLibvlcData.buffer != NULL) {
|
||||||
{
|
|
||||||
zm_freealigned(mLibvlcData.buffer);
|
zm_freealigned(mLibvlcData.buffer);
|
||||||
}
|
}
|
||||||
if(mLibvlcData.prevBuffer != NULL)
|
if(mLibvlcData.prevBuffer != NULL) {
|
||||||
{
|
|
||||||
zm_freealigned(mLibvlcData.prevBuffer);
|
zm_freealigned(mLibvlcData.prevBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int LibvlcCamera::PrimeCapture()
|
int LibvlcCamera::PrimeCapture() {
|
||||||
{
|
|
||||||
Info("Priming capture from %s", mPath.c_str());
|
Info("Priming capture from %s", mPath.c_str());
|
||||||
|
|
||||||
StringVector opVect = split(Options(), ",");
|
StringVector opVect = split(Options(), ",");
|
||||||
|
@ -154,8 +137,7 @@ int LibvlcCamera::PrimeCapture()
|
||||||
else if ( Method() == "rtpRtspHttp" )
|
else if ( Method() == "rtpRtspHttp" )
|
||||||
opVect.push_back("--rtsp-http");
|
opVect.push_back("--rtsp-http");
|
||||||
|
|
||||||
if (opVect.size() > 0)
|
if ( opVect.size() > 0 ) {
|
||||||
{
|
|
||||||
mOptArgV = new char*[opVect.size()];
|
mOptArgV = new char*[opVect.size()];
|
||||||
Debug(2, "Number of Options: %d",opVect.size());
|
Debug(2, "Number of Options: %d",opVect.size());
|
||||||
for (size_t i=0; i< opVect.size(); i++) {
|
for (size_t i=0; i< opVect.size(); i++) {
|
||||||
|
@ -166,7 +148,7 @@ int LibvlcCamera::PrimeCapture()
|
||||||
}
|
}
|
||||||
|
|
||||||
mLibvlcInstance = libvlc_new (opVect.size(), (const char* const*)mOptArgV);
|
mLibvlcInstance = libvlc_new (opVect.size(), (const char* const*)mOptArgV);
|
||||||
if(mLibvlcInstance == NULL)
|
if ( mLibvlcInstance == NULL )
|
||||||
Fatal("Unable to create libvlc instance due to: %s", libvlc_errmsg());
|
Fatal("Unable to create libvlc instance due to: %s", libvlc_errmsg());
|
||||||
|
|
||||||
mLibvlcMedia = libvlc_media_new_location(mLibvlcInstance, mPath.c_str());
|
mLibvlcMedia = libvlc_media_new_location(mLibvlcInstance, mPath.c_str());
|
||||||
|
@ -189,44 +171,27 @@ int LibvlcCamera::PrimeCapture()
|
||||||
|
|
||||||
libvlc_media_player_play(mLibvlcMediaPlayer);
|
libvlc_media_player_play(mLibvlcMediaPlayer);
|
||||||
|
|
||||||
return(0);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int LibvlcCamera::PreCapture()
|
int LibvlcCamera::PreCapture() {
|
||||||
{
|
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should not return -1 as cancels capture. Always wait for image if available.
|
// Should not return -1 as cancels capture. Always wait for image if available.
|
||||||
int LibvlcCamera::Capture( Image &image )
|
int LibvlcCamera::Capture( ZMPacket &zm_packet ) {
|
||||||
{
|
|
||||||
while(!mLibvlcData.newImage.getValueImmediate())
|
while(!mLibvlcData.newImage.getValueImmediate())
|
||||||
mLibvlcData.newImage.getUpdatedValue(1);
|
mLibvlcData.newImage.getUpdatedValue(1);
|
||||||
|
|
||||||
mLibvlcData.mutex.lock();
|
mLibvlcData.mutex.lock();
|
||||||
image.Assign(width, height, colours, subpixelorder, mLibvlcData.buffer, width * height * mBpp);
|
zm_packet.image->Assign(width, height, colours, subpixelorder, mLibvlcData.buffer, width * height * mBpp);
|
||||||
mLibvlcData.newImage.setValueImmediate(false);
|
mLibvlcData.newImage.setValueImmediate(false);
|
||||||
mLibvlcData.mutex.unlock();
|
mLibvlcData.mutex.unlock();
|
||||||
|
|
||||||
return (0);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should not return -1 as cancels capture. Always wait for image if available.
|
int LibvlcCamera::PostCapture() {
|
||||||
int LibvlcCamera::CaptureAndRecord(Image &image, timeval recording, char* event_directory)
|
|
||||||
{
|
|
||||||
while(!mLibvlcData.newImage.getValueImmediate())
|
|
||||||
mLibvlcData.newImage.getUpdatedValue(1);
|
|
||||||
|
|
||||||
mLibvlcData.mutex.lock();
|
|
||||||
image.Assign(width, height, colours, subpixelorder, mLibvlcData.buffer, width * height * mBpp);
|
|
||||||
mLibvlcData.newImage.setValueImmediate(false);
|
|
||||||
mLibvlcData.mutex.unlock();
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int LibvlcCamera::PostCapture()
|
|
||||||
{
|
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,8 +31,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Used by libvlc callbacks
|
// Used by libvlc callbacks
|
||||||
struct LibvlcPrivateData
|
struct LibvlcPrivateData {
|
||||||
{
|
|
||||||
uint8_t* buffer;
|
uint8_t* buffer;
|
||||||
uint8_t* prevBuffer;
|
uint8_t* prevBuffer;
|
||||||
time_t prevTime;
|
time_t prevTime;
|
||||||
|
@ -41,8 +40,7 @@ struct LibvlcPrivateData
|
||||||
ThreadData<bool> newImage;
|
ThreadData<bool> newImage;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LibvlcCamera : public Camera
|
class LibvlcCamera : public Camera {
|
||||||
{
|
|
||||||
protected:
|
protected:
|
||||||
std::string mPath;
|
std::string mPath;
|
||||||
std::string mMethod;
|
std::string mMethod;
|
||||||
|
@ -69,8 +67,7 @@ public:
|
||||||
|
|
||||||
int PrimeCapture();
|
int PrimeCapture();
|
||||||
int PreCapture();
|
int PreCapture();
|
||||||
int Capture( Image &image );
|
int Capture( ZMPacket &p );
|
||||||
int CaptureAndRecord( Image &image, timeval recording, char* event_directory );
|
|
||||||
int PostCapture();
|
int PostCapture();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1902,7 +1902,7 @@ int LocalCamera::PreCapture() {
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
ZMPacket *LocalCamera::Capture( Image &image ) {
|
int LocalCamera::Capture( ZMPacket &zm_packet ) {
|
||||||
|
|
||||||
// We assume that the avpacket is allocated, and just needs to be filled
|
// We assume that the avpacket is allocated, and just needs to be filled
|
||||||
Debug( 3, "Capturing" );
|
Debug( 3, "Capturing" );
|
||||||
|
@ -1938,7 +1938,7 @@ ZMPacket *LocalCamera::Capture( Image &image ) {
|
||||||
Warning( "Capture failure, possible signal loss?: %s", strerror(errno) )
|
Warning( "Capture failure, possible signal loss?: %s", strerror(errno) )
|
||||||
else
|
else
|
||||||
Error( "Unable to capture frame %d: %s", vid_buf.index, strerror(errno) )
|
Error( "Unable to capture frame %d: %s", vid_buf.index, strerror(errno) )
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
v4l2_data.bufptr = &vid_buf;
|
v4l2_data.bufptr = &vid_buf;
|
||||||
|
@ -1946,10 +1946,10 @@ ZMPacket *LocalCamera::Capture( Image &image ) {
|
||||||
if ( --captures_per_frame ) {
|
if ( --captures_per_frame ) {
|
||||||
if ( vidioctl( vid_fd, VIDIOC_QBUF, &vid_buf ) < 0 ) {
|
if ( vidioctl( vid_fd, VIDIOC_QBUF, &vid_buf ) < 0 ) {
|
||||||
Error( "Unable to requeue buffer %d: %s", vid_buf.index, strerror(errno) );
|
Error( "Unable to requeue buffer %d: %s", vid_buf.index, strerror(errno) );
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // while captures_per_frame
|
||||||
|
|
||||||
Debug( 3, "Captured frame %d/%d from channel %d", capture_frame, v4l2_data.bufptr->sequence, channel );
|
Debug( 3, "Captured frame %d/%d from channel %d", capture_frame, v4l2_data.bufptr->sequence, channel );
|
||||||
|
|
||||||
|
@ -1959,7 +1959,7 @@ ZMPacket *LocalCamera::Capture( Image &image ) {
|
||||||
if ( (v4l2_data.fmt.fmt.pix.width * v4l2_data.fmt.fmt.pix.height) != (width * height) ) {
|
if ( (v4l2_data.fmt.fmt.pix.width * v4l2_data.fmt.fmt.pix.height) != (width * height) ) {
|
||||||
Fatal("Captured image dimensions differ: V4L2: %dx%d monitor: %dx%d",v4l2_data.fmt.fmt.pix.width,v4l2_data.fmt.fmt.pix.height,width,height);
|
Fatal("Captured image dimensions differ: V4L2: %dx%d monitor: %dx%d",v4l2_data.fmt.fmt.pix.width,v4l2_data.fmt.fmt.pix.height,width,height);
|
||||||
}
|
}
|
||||||
} else
|
} else // end if v4l2
|
||||||
#endif // ZM_HAS_V4L2
|
#endif // ZM_HAS_V4L2
|
||||||
#if ZM_HAS_V4L1
|
#if ZM_HAS_V4L1
|
||||||
if ( v4l_version == 1 ) {
|
if ( v4l_version == 1 ) {
|
||||||
|
@ -1968,14 +1968,14 @@ ZMPacket *LocalCamera::Capture( Image &image ) {
|
||||||
Debug( 3, "Syncing frame %d", v4l1_data.active_frame );
|
Debug( 3, "Syncing frame %d", v4l1_data.active_frame );
|
||||||
if ( ioctl( vid_fd, VIDIOCSYNC, &v4l1_data.active_frame ) < 0 ) {
|
if ( ioctl( vid_fd, VIDIOCSYNC, &v4l1_data.active_frame ) < 0 ) {
|
||||||
Error( "Sync failure for frame %d buffer %d: %s", v4l1_data.active_frame, captures_per_frame, strerror(errno) );
|
Error( "Sync failure for frame %d buffer %d: %s", v4l1_data.active_frame, captures_per_frame, strerror(errno) );
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
captures_per_frame--;
|
captures_per_frame--;
|
||||||
if ( captures_per_frame ) {
|
if ( captures_per_frame ) {
|
||||||
Debug( 3, "Capturing frame %d", v4l1_data.active_frame );
|
Debug( 3, "Capturing frame %d", v4l1_data.active_frame );
|
||||||
if ( ioctl( vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[v4l1_data.active_frame] ) < 0 ) {
|
if ( ioctl( vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[v4l1_data.active_frame] ) < 0 ) {
|
||||||
Error( "Capture failure for buffer %d (%d): %s", v4l1_data.active_frame, captures_per_frame, strerror(errno) );
|
Error( "Capture failure for buffer %d (%d): %s", v4l1_data.active_frame, captures_per_frame, strerror(errno) );
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1987,17 +1987,15 @@ ZMPacket *LocalCamera::Capture( Image &image ) {
|
||||||
#endif // ZM_HAS_V4L1
|
#endif // ZM_HAS_V4L1
|
||||||
} /* prime capture */
|
} /* prime capture */
|
||||||
|
|
||||||
ZMPacket *packet = new ZMPacket( &image );
|
|
||||||
if ( conversion_type != 0 ) {
|
if ( conversion_type != 0 ) {
|
||||||
|
|
||||||
Debug( 3, "Performing format conversion" );
|
Debug( 3, "Performing format conversion" );
|
||||||
|
|
||||||
/* Request a writeable buffer of the target image */
|
/* Request a writeable buffer of the target image */
|
||||||
directbuffer = image.WriteBuffer(width, height, colours, subpixelorder);
|
directbuffer = zm_packet.image->WriteBuffer(width, height, colours, subpixelorder);
|
||||||
if ( directbuffer == NULL ) {
|
if ( directbuffer == NULL ) {
|
||||||
Error("Failed requesting writeable buffer for the captured image.");
|
Error("Failed requesting writeable buffer for the captured image.");
|
||||||
delete packet;
|
return -1;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
#if HAVE_LIBSWSCALE
|
#if HAVE_LIBSWSCALE
|
||||||
if ( conversion_type == 1 ) {
|
if ( conversion_type == 1 ) {
|
||||||
|
@ -2012,11 +2010,18 @@ ZMPacket *LocalCamera::Capture( Image &image ) {
|
||||||
avpicture_fill( (AVPicture *)tmpPicture, directbuffer,
|
avpicture_fill( (AVPicture *)tmpPicture, directbuffer,
|
||||||
imagePixFormat, width, height );
|
imagePixFormat, width, height );
|
||||||
#endif
|
#endif
|
||||||
sws_scale( imgConversionContext, capturePictures[capture_frame]->data, capturePictures[capture_frame]->linesize, 0, height, tmpPicture->data, tmpPicture->linesize );
|
sws_scale(
|
||||||
|
imgConversionContext,
|
||||||
|
capturePictures[capture_frame]->data,
|
||||||
|
capturePictures[capture_frame]->linesize,
|
||||||
|
0,
|
||||||
|
height,
|
||||||
|
tmpPicture->data,
|
||||||
|
tmpPicture->linesize
|
||||||
|
);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
if ( conversion_type == 2 ) {
|
if ( conversion_type == 2 ) {
|
||||||
|
|
||||||
Debug( 9, "Calling the conversion function" );
|
Debug( 9, "Calling the conversion function" );
|
||||||
/* Call the image conversion function and convert directly into the shared memory */
|
/* Call the image conversion function and convert directly into the shared memory */
|
||||||
(*conversion_fptr)(buffer, directbuffer, pixels);
|
(*conversion_fptr)(buffer, directbuffer, pixels);
|
||||||
|
@ -2024,17 +2029,17 @@ ZMPacket *LocalCamera::Capture( Image &image ) {
|
||||||
// Need to store the jpeg data too
|
// Need to store the jpeg data too
|
||||||
Debug( 9, "Decoding the JPEG image" );
|
Debug( 9, "Decoding the JPEG image" );
|
||||||
/* JPEG decoding */
|
/* JPEG decoding */
|
||||||
image.DecodeJpeg(buffer, buffer_bytesused, colours, subpixelorder);
|
zm_packet.image->DecodeJpeg(buffer, buffer_bytesused, colours, subpixelorder);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Debug( 3, "No format conversion performed. Assigning the image" );
|
Debug( 3, "No format conversion performed. Assigning the image" );
|
||||||
|
|
||||||
/* No conversion was performed, the image is in the V4L buffers and needs to be copied into the shared memory */
|
/* No conversion was performed, the image is in the V4L buffers and needs to be copied into the shared memory */
|
||||||
image.Assign(width, height, colours, subpixelorder, buffer, imagesize);
|
zm_packet.image->Assign(width, height, colours, subpixelorder, buffer, imagesize);
|
||||||
} // end if doing conversion or not
|
} // end if doing conversion or not
|
||||||
|
|
||||||
return packet;
|
return 1;
|
||||||
} // end Capture
|
} // end Capture
|
||||||
|
|
||||||
int LocalCamera::PostCapture() {
|
int LocalCamera::PostCapture() {
|
||||||
|
|
|
@ -156,7 +156,7 @@ public:
|
||||||
|
|
||||||
int PrimeCapture();
|
int PrimeCapture();
|
||||||
int PreCapture();
|
int PreCapture();
|
||||||
ZMPacket *Capture( Image &image );
|
int Capture(ZMPacket &p);
|
||||||
int PostCapture();
|
int PostCapture();
|
||||||
static bool GetCurrentSettings( const char *device, char *output, int version, bool verbose );
|
static bool GetCurrentSettings( const char *device, char *output, int version, bool verbose );
|
||||||
};
|
};
|
||||||
|
|
|
@ -453,6 +453,7 @@ Monitor::Monitor(
|
||||||
adaptive_skip = true;
|
adaptive_skip = true;
|
||||||
|
|
||||||
ReloadLinkedMonitors( p_linked_monitors );
|
ReloadLinkedMonitors( p_linked_monitors );
|
||||||
|
videoStore = NULL;
|
||||||
} // Monitor::Monitor
|
} // Monitor::Monitor
|
||||||
|
|
||||||
bool Monitor::connect() {
|
bool Monitor::connect() {
|
||||||
|
@ -1145,14 +1146,15 @@ bool Monitor::CheckSignal( const Image *image ) {
|
||||||
bool Monitor::Analyse() {
|
bool Monitor::Analyse() {
|
||||||
if ( shared_data->last_read_index == shared_data->last_write_index ) {
|
if ( shared_data->last_read_index == shared_data->last_write_index ) {
|
||||||
// I wonder how often this happens. Maybe if this happens we should sleep or something?
|
// I wonder how often this happens. Maybe if this happens we should sleep or something?
|
||||||
return( false );
|
//Debug(3, " shared_data->last_read_index == shared_data->last_write_index " );
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
gettimeofday( &now, NULL );
|
gettimeofday( &now, NULL );
|
||||||
|
|
||||||
if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) {
|
if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) {
|
||||||
fps = double(fps_report_interval)/(now.tv_sec-last_fps_time);
|
fps = double(fps_report_interval)/(now.tv_sec - last_fps_time);
|
||||||
Info( "%s: %d - Analysing at %.2f fps", name, image_count, fps );
|
Info( "%s: %d - Analysing at %.2f fps", name, image_count, fps );
|
||||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||||
snprintf( sql, sizeof(sql), "UPDATE Monitors SET AnalysisFPS = '%.2lf' WHERE Id = '%d'", fps, id );
|
snprintf( sql, sizeof(sql), "UPDATE Monitors SET AnalysisFPS = '%.2lf' WHERE Id = '%d'", fps, id );
|
||||||
|
@ -1177,7 +1179,8 @@ bool Monitor::Analyse() {
|
||||||
int pending_frames = shared_data->last_write_index - shared_data->last_read_index;
|
int pending_frames = shared_data->last_write_index - shared_data->last_read_index;
|
||||||
if ( pending_frames < 0 ) pending_frames += image_buffer_count;
|
if ( pending_frames < 0 ) pending_frames += image_buffer_count;
|
||||||
|
|
||||||
Debug( 4, "ReadIndex:%d, WriteIndex: %d, PendingFrames = %d, ReadMargin = %d, Step = %d", shared_data->last_read_index, shared_data->last_write_index, pending_frames, read_margin, step );
|
Debug( 4, "ReadIndex:%d, WriteIndex: %d, PendingFrames = %d, ReadMargin = %d, Step = %d",
|
||||||
|
shared_data->last_read_index, shared_data->last_write_index, pending_frames, read_margin, step );
|
||||||
if ( step <= pending_frames ) {
|
if ( step <= pending_frames ) {
|
||||||
index = (shared_data->last_read_index+step)%image_buffer_count;
|
index = (shared_data->last_read_index+step)%image_buffer_count;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1359,12 +1362,12 @@ Debug(3,"before DetectMotion");
|
||||||
if ( event ) {
|
if ( event ) {
|
||||||
//TODO: We shouldn't have to do this every time. Not sure why it clears itself if this isn't here??
|
//TODO: We shouldn't have to do this every time. Not sure why it clears itself if this isn't here??
|
||||||
//snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile());
|
//snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile());
|
||||||
Debug( 3, "Detected new event at (%d.%d)", timestamp->tv_sec,timestamp->tv_usec );
|
//Debug( 3, "Detected new event at (%d.%d)", timestamp->tv_sec,timestamp->tv_usec );
|
||||||
|
|
||||||
if ( section_length ) {
|
if ( section_length ) {
|
||||||
// TODO: Wouldn't this be clearer if we just did something like if now - event->start > section_length ?
|
// TODO: Wouldn't this be clearer if we just did something like if now - event->start > section_length ?
|
||||||
int section_mod = timestamp->tv_sec % section_length;
|
int section_mod = timestamp->tv_sec % section_length;
|
||||||
Debug( 3, "Section length (%d) Last Section Mod(%d), new section mod(%d)", section_length, last_section_mod, section_mod );
|
Debug( 4, "Section length (%d) Last Section Mod(%d), new section mod(%d)", section_length, last_section_mod, section_mod );
|
||||||
if ( section_mod < last_section_mod ) {
|
if ( section_mod < last_section_mod ) {
|
||||||
//if ( state == IDLE || state == TAPE || event_close_mode == CLOSE_TIME ) {
|
//if ( state == IDLE || state == TAPE || event_close_mode == CLOSE_TIME ) {
|
||||||
//if ( state == TAPE ) {
|
//if ( state == TAPE ) {
|
||||||
|
@ -2846,107 +2849,85 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) {
|
||||||
int Monitor::Capture() {
|
int Monitor::Capture() {
|
||||||
static int FirstCapture = 1; // Used in de-interlacing to indicate whether this is the even or odd image
|
static int FirstCapture = 1; // Used in de-interlacing to indicate whether this is the even or odd image
|
||||||
|
|
||||||
unsigned int index = image_count%image_buffer_count;
|
unsigned int index = image_count % image_buffer_count;
|
||||||
Image* capture_image = image_buffer[index].image;
|
Image* capture_image = image_buffer[index].image;
|
||||||
|
ZMPacket packet;
|
||||||
unsigned int deinterlacing_value = deinterlacing & 0xff;
|
packet.set_image(capture_image);
|
||||||
|
|
||||||
ZMPacket *packet;
|
|
||||||
int captureResult = 0;
|
int captureResult = 0;
|
||||||
|
|
||||||
|
unsigned int deinterlacing_value = deinterlacing & 0xff;
|
||||||
if ( deinterlacing_value == 4 ) {
|
if ( deinterlacing_value == 4 ) {
|
||||||
if ( FirstCapture != 1 ) {
|
if ( FirstCapture != 1 ) {
|
||||||
/* Copy the next image into the shared memory */
|
/* Copy the next image into the shared memory */
|
||||||
capture_image->CopyBuffer(*(next_buffer.image));
|
capture_image->CopyBuffer(*(next_buffer.image));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Capture a new next image */
|
/* Capture a new next image */
|
||||||
|
captureResult = camera->Capture(packet);
|
||||||
packet = camera->Capture(*(next_buffer.image));
|
|
||||||
|
|
||||||
if ( FirstCapture ) {
|
if ( FirstCapture ) {
|
||||||
FirstCapture = 0;
|
FirstCapture = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
packet = camera->Capture(*capture_image);
|
captureResult = camera->Capture(packet);
|
||||||
if ( ! packet ) {
|
if ( captureResult < 0 ) {
|
||||||
packet = new ZMPacket(capture_image);
|
|
||||||
// Unable to capture image for temporary reason
|
// Unable to capture image for temporary reason
|
||||||
// Fake a signal loss image
|
// Fake a signal loss image
|
||||||
Rgb signalcolor;
|
Rgb signalcolor;
|
||||||
signalcolor = rgb_convert(signal_check_colour, ZM_SUBPIX_ORDER_BGR); /* HTML colour code is actually BGR in memory, we want RGB */
|
/* HTML colour code is actually BGR in memory, we want RGB */
|
||||||
|
signalcolor = rgb_convert(signal_check_colour, ZM_SUBPIX_ORDER_BGR);
|
||||||
capture_image->Fill(signalcolor);
|
capture_image->Fill(signalcolor);
|
||||||
} else {
|
shared_data->signal = false;
|
||||||
captureResult = 1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int video_stream_id = camera->get_VideoStreamId();
|
int video_stream_id = camera->get_VideoStreamId();
|
||||||
// Should maybe not write to videowriter when no signal FIXME
|
|
||||||
|
|
||||||
//Video recording
|
//Video recording
|
||||||
if ( video_store_data->recording.tv_sec ) {
|
if ( video_store_data->recording.tv_sec ) {
|
||||||
|
|
||||||
if ( shared_data->last_event_id != this->GetVideoWriterEventId() ) {
|
if ( shared_data->last_event_id != this->GetVideoWriterEventId() ) {
|
||||||
Debug(2, "Have change of event. last_event(%d), our current (%d)", shared_data->last_event_id, this->GetVideoWriterEventId() );
|
Debug(2, "Have change of event. last_event(%d), our current (%d)",
|
||||||
|
shared_data->last_event_id,
|
||||||
|
this->GetVideoWriterEventId()
|
||||||
|
);
|
||||||
if ( videoStore ) {
|
if ( videoStore ) {
|
||||||
Info("Re-starting video storage module");
|
Debug(2, "Have videostore already?");
|
||||||
|
|
||||||
// I don't know if this is important or not... but I figure we might as well write this last packet out to the store before closing it.
|
// I don't know if this is important or not... but I figure we might as well write this last packet out to the store before closing it.
|
||||||
// Also don't know how much it matters for audio.
|
// Also don't know how much it matters for audio.
|
||||||
int ret = videoStore->writePacket( packet );
|
int ret = videoStore->writePacket( &packet );
|
||||||
if ( ret < 0 ) { //Less than zero and we skipped a frame
|
if ( ret < 0 ) { //Less than zero and we skipped a frame
|
||||||
Warning("Error writing last packet to videostore.");
|
Warning("Error writing last packet to videostore.");
|
||||||
}
|
}
|
||||||
|
|
||||||
delete videoStore;
|
delete videoStore;
|
||||||
videoStore = NULL;
|
videoStore = NULL;
|
||||||
this->SetVideoWriterEventId( 0 );
|
this->SetVideoWriterEventId( 0 );
|
||||||
} // end if videoStore
|
} // end if videoStore
|
||||||
} // end if end of recording
|
} // end if end of recording
|
||||||
|
|
||||||
if ( shared_data->last_event_id and ! videoStore ) {
|
if ( shared_data->last_event_id and ! videoStore ) {
|
||||||
//Instantiate the video storage module
|
Debug(2,"New videostore");
|
||||||
|
videoStore = new VideoStore(
|
||||||
videoStore = new VideoStore((const char *) video_store_data->event_file, "mp4",
|
(const char *) video_store_data->event_file,
|
||||||
|
"mp4",
|
||||||
camera->get_VideoStream(),
|
camera->get_VideoStream(),
|
||||||
( record_audio ? camera->get_AudioStream() : NULL ),
|
( record_audio ? camera->get_AudioStream() : NULL ),
|
||||||
|
video_store_data->recording.tv_sec,
|
||||||
this );
|
this );
|
||||||
|
|
||||||
if ( ! videoStore->open() ) {
|
if ( ! videoStore->open() ) {
|
||||||
delete videoStore;
|
delete videoStore;
|
||||||
videoStore = NULL;
|
videoStore = NULL;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this->SetVideoWriterEventId( shared_data->last_event_id );
|
this->SetVideoWriterEventId(shared_data->last_event_id);
|
||||||
|
|
||||||
// Need to write out all the frames from the last keyframe?
|
|
||||||
// No... need to write out all frames from when the event began. Due to PreEventFrames, this could be more than since the last keyframe.
|
|
||||||
unsigned int packet_count = 0;
|
|
||||||
ZMPacket *queued_packet;
|
|
||||||
|
|
||||||
|
Debug(2, "Clearing packets");
|
||||||
// Clear all packets that predate the moment when the recording began
|
// Clear all packets that predate the moment when the recording began
|
||||||
packetqueue.clear_unwanted_packets( &video_store_data->recording, video_stream_id );
|
packetqueue.clear_unwanted_packets(&video_store_data->recording, video_stream_id);
|
||||||
|
videoStore->write_packets(packetqueue);
|
||||||
while ( ( queued_packet = packetqueue.popPacket() ) ) {
|
|
||||||
AVPacket *avp = queued_packet->av_packet();
|
|
||||||
|
|
||||||
packet_count += 1;
|
|
||||||
//Write the packet to our video store
|
|
||||||
Debug(2, "Writing queued packet stream: %d KEY %d, remaining (%d)", avp->stream_index, avp->flags & AV_PKT_FLAG_KEY, packetqueue.size() );
|
|
||||||
int ret = videoStore->writePacket( queued_packet );
|
|
||||||
if ( ret < 0 ) {
|
|
||||||
//Less than zero and we skipped a frame
|
|
||||||
}
|
|
||||||
delete queued_packet;
|
|
||||||
} // end while packets in the packetqueue
|
|
||||||
Debug(2, "Wrote %d queued packets", packet_count );
|
|
||||||
} // success opening
|
} // success opening
|
||||||
} // end if ! was recording
|
} // end if ! was recording
|
||||||
|
} else { // Not recording
|
||||||
} else {
|
|
||||||
// Not recording
|
|
||||||
if ( videoStore ) {
|
if ( videoStore ) {
|
||||||
Info("Deleting videoStore instance");
|
Info("Deleting videoStore instance");
|
||||||
delete videoStore;
|
delete videoStore;
|
||||||
|
@ -2954,42 +2935,33 @@ int Monitor::Capture() {
|
||||||
this->SetVideoWriterEventId( 0 );
|
this->SetVideoWriterEventId( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buffer video packets, since we are not recording.
|
// Buffer video packets, since we are not recording.
|
||||||
// All audio packets are keyframes, so only if it's a video keyframe
|
// All audio packets are keyframes, so only if it's a video keyframe
|
||||||
if ( packet->packet.stream_index == video_stream_id ) {
|
if ( ( packet.packet.stream_index == video_stream_id ) && ( packet.keyframe ) ) {
|
||||||
if ( packet->keyframe ) {
|
packetqueue.clearQueue( this->GetPreEventCount(), video_stream_id );
|
||||||
Debug(3, "Clearing queue");
|
|
||||||
packetqueue.clearQueue( this->GetPreEventCount(), video_stream_id );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// The following lines should ensure that the queue always begins with a video keyframe
|
// The following lines should ensure that the queue always begins with a video keyframe
|
||||||
if ( packet->packet.stream_index == camera->get_AudioStreamId() ) {
|
if ( packet.packet.stream_index == camera->get_AudioStreamId() ) {
|
||||||
//Debug(2, "Have audio packet, reocrd_audio is (%d) and packetqueue.size is (%d)", record_audio, packetqueue.size() );
|
//Debug(2, "Have audio packet, reocrd_audio is (%d) and packetqueue.size is (%d)", record_audio, packetqueue.size() );
|
||||||
if ( record_audio && packetqueue.size() ) {
|
if ( record_audio && packetqueue.size() ) {
|
||||||
// if it's audio, and we are doing audio, and there is already something in the queue
|
// if it's audio, and we are doing audio, and there is already something in the queue
|
||||||
packetqueue.queuePacket( packet );
|
packetqueue.queuePacket( &packet );
|
||||||
}
|
}
|
||||||
} else if ( packet->packet.stream_index == video_stream_id ) {
|
} else if ( packet.packet.stream_index == video_stream_id ) {
|
||||||
if ( packet->keyframe || packetqueue.size() ) // it's a keyframe or we already have something in the queue
|
if ( packet.keyframe || packetqueue.size() ) // it's a keyframe or we already have something in the queue
|
||||||
packetqueue.queuePacket( packet );
|
packetqueue.queuePacket( &packet );
|
||||||
}
|
} // end if audio or video
|
||||||
} // end if recording or not
|
} // end if recording or not
|
||||||
|
|
||||||
if ( videoStore ) {
|
if ( videoStore ) {
|
||||||
//Write the packet to our video store, it will be smart enough to know what to do
|
//Write the packet to our video store, it will be smart enough to know what to do
|
||||||
int ret = videoStore->writePacket( packet );
|
int ret = videoStore->writePacket( &packet );
|
||||||
if ( ret < 0 ) { //Less than zero and we skipped a frame
|
if ( ret < 0 ) { //Less than zero and we skipped a frame
|
||||||
Warning("problem writing packet");
|
Warning("problem writing packet");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // end if de-interlacing or not
|
} // end if de-interlacing or not
|
||||||
|
|
||||||
if ( ! captureResult ) {
|
|
||||||
shared_data->signal = false;
|
|
||||||
return -1;
|
|
||||||
} // end if captureResults == 1 which is success I think
|
|
||||||
|
|
||||||
/* Deinterlacing */
|
/* Deinterlacing */
|
||||||
if ( deinterlacing_value == 1 ) {
|
if ( deinterlacing_value == 1 ) {
|
||||||
capture_image->Deinterlace_Discard();
|
capture_image->Deinterlace_Discard();
|
||||||
|
@ -3046,17 +3018,26 @@ int Monitor::Capture() {
|
||||||
shared_data->last_write_time = image_buffer[index].timestamp->tv_sec;
|
shared_data->last_write_time = image_buffer[index].timestamp->tv_sec;
|
||||||
|
|
||||||
image_count++;
|
image_count++;
|
||||||
|
|
||||||
if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) {
|
if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) {
|
||||||
time_t now = image_buffer[index].timestamp->tv_sec;
|
struct timeval now;
|
||||||
fps = double(fps_report_interval)/(now-last_fps_time);
|
if ( !captureResult ) {
|
||||||
//Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time );
|
gettimeofday( &now, NULL );
|
||||||
//Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps );
|
} else {
|
||||||
Info( "%s: %d - Capturing at %.2lf fps", name, image_count, fps );
|
now.tv_sec = image_buffer[index].timestamp->tv_sec;
|
||||||
last_fps_time = now;
|
}
|
||||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
// If we are too fast, we get div by zero. This seems to happen in the case of audio packets.
|
||||||
snprintf( sql, sizeof(sql), "UPDATE Monitors SET CaptureFPS = '%.2lf' WHERE Id = '%d'", fps, id );
|
if ( now.tv_sec != last_fps_time ) {
|
||||||
if ( mysql_query( &dbconn, sql ) ) {
|
fps = double(fps_report_interval)/(now.tv_sec-last_fps_time);
|
||||||
Error( "Can't run query: %s", mysql_error( &dbconn ) );
|
Info( "%d -> %d -> %d", fps_report_interval, now.tv_sec, last_fps_time );
|
||||||
|
//Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps );
|
||||||
|
Info( "%s: %d - Capturing at %.2lf fps", name, image_count, fps );
|
||||||
|
last_fps_time = now.tv_sec;
|
||||||
|
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||||
|
snprintf( sql, sizeof(sql), "UPDATE Monitors SET CaptureFPS='%.2lf' WHERE Id=%d", fps, id );
|
||||||
|
if ( mysql_query( &dbconn, sql ) ) {
|
||||||
|
Error( "Can't run query: %s", mysql_error( &dbconn ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3075,8 +3056,8 @@ int Monitor::Capture() {
|
||||||
camera->Contrast( shared_data->contrast );
|
camera->Contrast( shared_data->contrast );
|
||||||
shared_data->action &= ~SET_SETTINGS;
|
shared_data->action &= ~SET_SETTINGS;
|
||||||
}
|
}
|
||||||
return( 0 );
|
return captureResult;
|
||||||
}
|
} // end Monitor::Capture
|
||||||
|
|
||||||
void Monitor::TimestampImage( Image *ts_image, const struct timeval *ts_time ) const {
|
void Monitor::TimestampImage( Image *ts_image, const struct timeval *ts_time ) const {
|
||||||
if ( label_format[0] ) {
|
if ( label_format[0] ) {
|
||||||
|
|
|
@ -434,6 +434,7 @@ public:
|
||||||
int GetOptSaveJPEGs() const { return( savejpegspref ); }
|
int GetOptSaveJPEGs() const { return( savejpegspref ); }
|
||||||
VideoWriter GetOptVideoWriter() const { return( videowriter ); }
|
VideoWriter GetOptVideoWriter() const { return( videowriter ); }
|
||||||
const std::vector<EncoderParameter_t>* GetOptEncoderParams() const { return( &encoderparamsvec ); }
|
const std::vector<EncoderParameter_t>* GetOptEncoderParams() const { return( &encoderparamsvec ); }
|
||||||
|
const std::string &GetEncoderOptions() const { return( encoderparams ); }
|
||||||
uint32_t GetLastEventId() const { return shared_data->last_event_id; }
|
uint32_t GetLastEventId() const { return shared_data->last_event_id; }
|
||||||
uint32_t GetVideoWriterEventId() const { return video_store_data->current_event; }
|
uint32_t GetVideoWriterEventId() const { return video_store_data->current_event; }
|
||||||
void SetVideoWriterEventId( uint32_t p_event_id ) { video_store_data->current_event = p_event_id; }
|
void SetVideoWriterEventId( uint32_t p_event_id ) { video_store_data->current_event = p_event_id; }
|
||||||
|
|
|
@ -270,7 +270,7 @@ void MonitorStream::processCommand( const CmdMsg *msg ) {
|
||||||
Debug( 1, "Got SCALE command, to %d", scale );
|
Debug( 1, "Got SCALE command, to %d", scale );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_QUIT :
|
case CMD_QUIT :
|
||||||
{
|
{
|
||||||
Info ("User initiated exit - CMD_QUIT");
|
Info ("User initiated exit - CMD_QUIT");
|
||||||
break;
|
break;
|
||||||
|
@ -316,7 +316,7 @@ void MonitorStream::processCommand( const CmdMsg *msg ) {
|
||||||
//status_data.enabled = monitor->shared_data->active;
|
//status_data.enabled = monitor->shared_data->active;
|
||||||
status_data.enabled = monitor->trigger_data->trigger_state!=Monitor::TRIGGER_OFF;
|
status_data.enabled = monitor->trigger_data->trigger_state!=Monitor::TRIGGER_OFF;
|
||||||
status_data.forced = monitor->trigger_data->trigger_state==Monitor::TRIGGER_ON;
|
status_data.forced = monitor->trigger_data->trigger_state==Monitor::TRIGGER_ON;
|
||||||
Debug( 2, "L:%d, D:%d, P:%d, R:%d, d:%.3f, Z:%d, E:%d F:%d",
|
Debug( 2, "Buffer Level:%d, Delayed:%d, Paused:%d, Rate:%d, delay:%.3f, Zoom:%d, Enabled:%d Forced:%d",
|
||||||
status_data.buffer_level,
|
status_data.buffer_level,
|
||||||
status_data.delayed,
|
status_data.delayed,
|
||||||
status_data.paused,
|
status_data.paused,
|
||||||
|
@ -338,11 +338,15 @@ void MonitorStream::processCommand( const CmdMsg *msg ) {
|
||||||
//exit( -1 );
|
//exit( -1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Debug(2, "NUmber of bytes sent: (%d)", nbytes );
|
||||||
|
|
||||||
// quit after sending a status, if this was a quit request
|
// quit after sending a status, if this was a quit request
|
||||||
if ((MsgCommand)msg->msg_data[0]==CMD_QUIT)
|
if ( (MsgCommand)msg->msg_data[0]==CMD_QUIT ) {
|
||||||
exit(0);
|
Debug(2,"Quitting");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug(2,"Updating framrate");
|
||||||
updateFrameRate( monitor->GetFPS() );
|
updateFrameRate( monitor->GetFPS() );
|
||||||
} // end void MonitorStream::processCommand( const CmdMsg *msg )
|
} // end void MonitorStream::processCommand( const CmdMsg *msg )
|
||||||
|
|
||||||
|
@ -553,20 +557,28 @@ void MonitorStream::runStream() {
|
||||||
Debug( 2, "Assigned temporary buffer" );
|
Debug( 2, "Assigned temporary buffer" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // end if connkey & playback_buffer
|
||||||
|
|
||||||
float max_secs_since_last_sent_frame = 10.0; //should be > keep alive amount (5 secs)
|
float max_secs_since_last_sent_frame = 10.0; //should be > keep alive amount (5 secs)
|
||||||
while ( !zm_terminate ) {
|
while ( !zm_terminate ) {
|
||||||
bool got_command = false;
|
bool got_command = false;
|
||||||
if ( feof( stdout ) || ferror( stdout ) || !monitor->ShmValid() ) {
|
if ( feof( stdout ) || ferror( stdout ) || !monitor->ShmValid() ) {
|
||||||
|
if ( feof( stdout ) ) {
|
||||||
|
Debug(2,"feof stdout");
|
||||||
|
} else if ( ferror( stdout ) ) {
|
||||||
|
Debug(2,"ferror stdout");
|
||||||
|
} else if ( !monitor->ShmValid() ) {
|
||||||
|
Debug(2,"monitor not valid.... maybe we should wait until it comes back.");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
gettimeofday( &now, NULL );
|
gettimeofday( &now, NULL );
|
||||||
|
|
||||||
if ( connkey ) {
|
if ( connkey ) {
|
||||||
Debug(2, "checking command Queue");
|
//Debug(2, "checking command Queue for connkey: %d", connkey );
|
||||||
while(checkCommandQueue()) {
|
while(checkCommandQueue()) {
|
||||||
|
Debug(2, "Have checking command Queue for connkey: %d", connkey );
|
||||||
got_command = true;
|
got_command = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -655,8 +667,10 @@ Debug(2, "checking command Queue");
|
||||||
// Send the next frame
|
// Send the next frame
|
||||||
Monitor::Snapshot *snap = &monitor->image_buffer[index];
|
Monitor::Snapshot *snap = &monitor->image_buffer[index];
|
||||||
|
|
||||||
if ( !sendFrame( snap->image, snap->timestamp ) )
|
if ( !sendFrame( snap->image, snap->timestamp ) ) {
|
||||||
|
Debug(2, "sendFrame failed, quiting.");
|
||||||
zm_terminate = true;
|
zm_terminate = true;
|
||||||
|
}
|
||||||
memcpy( &last_frame_timestamp, snap->timestamp, sizeof(last_frame_timestamp) );
|
memcpy( &last_frame_timestamp, snap->timestamp, sizeof(last_frame_timestamp) );
|
||||||
//frame_sent = true;
|
//frame_sent = true;
|
||||||
|
|
||||||
|
@ -693,9 +707,12 @@ Debug(2, "checking command Queue");
|
||||||
} // end if buffered playback
|
} // end if buffered playback
|
||||||
frame_count++;
|
frame_count++;
|
||||||
}
|
}
|
||||||
|
unsigned long sleep_time = (unsigned long)((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*abs(replay_rate*2)));
|
||||||
|
Debug(2, "Sleeping for (%d)", sleep_time);
|
||||||
usleep( (unsigned long)((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*abs(replay_rate*2))) );
|
usleep( (unsigned long)((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*abs(replay_rate*2))) );
|
||||||
if ( ttl ) {
|
if ( ttl ) {
|
||||||
if ( (now.tv_sec - stream_start_time) > ttl ) {
|
if ( (now.tv_sec - stream_start_time) > ttl ) {
|
||||||
|
Debug(2, "now(%d) - start(%d) > ttl(%d) break", now.tv_sec, stream_start_time, ttl);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
135
src/zm_mpeg.cpp
135
src/zm_mpeg.cpp
|
@ -117,10 +117,10 @@ void VideoStream::SetupFormat( ) {
|
||||||
|
|
||||||
void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int height, int bitrate, double frame_rate ) {
|
void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int height, int bitrate, double frame_rate ) {
|
||||||
/* ffmpeg format matching */
|
/* ffmpeg format matching */
|
||||||
switch(colours) {
|
switch ( colours ) {
|
||||||
case ZM_COLOUR_RGB24:
|
case ZM_COLOUR_RGB24:
|
||||||
{
|
{
|
||||||
if(subpixelorder == ZM_SUBPIX_ORDER_BGR) {
|
if ( subpixelorder == ZM_SUBPIX_ORDER_BGR ) {
|
||||||
/* BGR subpixel order */
|
/* BGR subpixel order */
|
||||||
pf = AV_PIX_FMT_BGR24;
|
pf = AV_PIX_FMT_BGR24;
|
||||||
} else {
|
} else {
|
||||||
|
@ -211,39 +211,52 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
|
||||||
|
|
||||||
Debug( 1, "Allocated stream" );
|
Debug( 1, "Allocated stream" );
|
||||||
|
|
||||||
AVCodecContext *c = ost->codec;
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
|
codec_context = avcodec_alloc_context3(NULL);
|
||||||
|
avcodec_parameters_to_context(codec_context, ost->codecpar);
|
||||||
|
#else
|
||||||
|
codec_context = ost->codec;
|
||||||
|
#endif
|
||||||
|
|
||||||
c->codec_id = codec->id;
|
codec_context->codec_id = codec->id;
|
||||||
c->codec_type = codec->type;
|
codec_context->codec_type = codec->type;
|
||||||
|
|
||||||
c->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 ) {
|
if ( bitrate <= 100 ) {
|
||||||
// Quality based bitrate control (VBR). Scale is 1..31 where 1 is best.
|
// 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.
|
// This gets rid of artifacts in the beginning of the movie; and well, even quality.
|
||||||
c->flags |= CODEC_FLAG_QSCALE;
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
c->global_quality = FF_QP2LAMBDA * (31 - (31 * (bitrate / 100.0)));
|
codec_context->flags |= AV_CODEC_FLAG_QSCALE;
|
||||||
|
#else
|
||||||
|
codec_context->flags |= CODEC_FLAG_QSCALE;
|
||||||
|
#endif
|
||||||
|
codec_context->global_quality = FF_QP2LAMBDA * (31 - (31 * (bitrate / 100.0)));
|
||||||
} else {
|
} else {
|
||||||
c->bit_rate = bitrate;
|
codec_context->bit_rate = bitrate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* resolution must be a multiple of two */
|
/* resolution must be a multiple of two */
|
||||||
c->width = width;
|
codec_context->width = width;
|
||||||
c->height = height;
|
codec_context->height = height;
|
||||||
/* time base: this is the fundamental unit of time (in seconds) in terms
|
/* time base: this is the fundamental unit of time (in seconds) in terms
|
||||||
of which frame timestamps are represented. for fixed-fps content,
|
of which frame timestamps are represented. for fixed-fps content,
|
||||||
timebase should be 1/framerate and timestamp increments should be
|
timebase should be 1/framerate and timestamp increments should be
|
||||||
identically 1. */
|
identically 1. */
|
||||||
c->time_base.den = frame_rate;
|
codec_context->time_base.den = frame_rate;
|
||||||
c->time_base.num = 1;
|
codec_context->time_base.num = 1;
|
||||||
|
|
||||||
Debug( 1, "Will encode in %d fps.", c->time_base.den );
|
Debug( 1, "Will encode in %d fps.", codec_context->time_base.den );
|
||||||
|
|
||||||
/* emit one intra frame every second */
|
/* emit one intra frame every second */
|
||||||
c->gop_size = frame_rate;
|
codec_context->gop_size = frame_rate;
|
||||||
|
|
||||||
// some formats want stream headers to be separate
|
// some formats want stream headers to be separate
|
||||||
if ( of->flags & AVFMT_GLOBALHEADER )
|
if ( of->flags & AVFMT_GLOBALHEADER )
|
||||||
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
|
||||||
|
codec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
|
||||||
|
#else
|
||||||
|
codec_context->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
Fatal( "of->video_codec == AV_CODEC_ID_NONE" );
|
Fatal( "of->video_codec == AV_CODEC_ID_NONE" );
|
||||||
}
|
}
|
||||||
|
@ -278,13 +291,11 @@ void VideoStream::OpenStream( ) {
|
||||||
/* now that all the parameters are set, we can open the
|
/* now that all the parameters are set, we can open the
|
||||||
video codecs and allocate the necessary encode buffers */
|
video codecs and allocate the necessary encode buffers */
|
||||||
if ( ost ) {
|
if ( ost ) {
|
||||||
AVCodecContext *c = ost->codec;
|
|
||||||
|
|
||||||
/* open the codec */
|
/* open the codec */
|
||||||
#if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0)
|
#if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0)
|
||||||
if ( (avRet = avcodec_open( c, codec )) < 0 )
|
if ( (avRet = avcodec_open( codec_context, codec )) < 0 )
|
||||||
#else
|
#else
|
||||||
if ( (avRet = avcodec_open2( c, codec, 0 )) < 0 )
|
if ( (avRet = avcodec_open2( codec_context, codec, 0 )) < 0 )
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
Fatal( "Could not open codec. Error code %d \"%s\"", avRet, av_err2str( avRet ) );
|
Fatal( "Could not open codec. Error code %d \"%s\"", avRet, av_err2str( avRet ) );
|
||||||
|
@ -293,19 +304,15 @@ void VideoStream::OpenStream( ) {
|
||||||
Debug( 1, "Opened codec" );
|
Debug( 1, "Opened codec" );
|
||||||
|
|
||||||
/* allocate the encoded raw picture */
|
/* allocate the encoded raw picture */
|
||||||
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
opicture = zm_av_frame_alloc( );
|
||||||
opicture = av_frame_alloc( );
|
|
||||||
#else
|
|
||||||
opicture = avcodec_alloc_frame( );
|
|
||||||
#endif
|
|
||||||
if ( !opicture ) {
|
if ( !opicture ) {
|
||||||
Panic( "Could not allocate opicture" );
|
Panic( "Could not allocate opicture" );
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
int size = av_image_get_buffer_size( c->pix_fmt, c->width, c->height, 1 );
|
int size = av_image_get_buffer_size( codec_context->pix_fmt, codec_context->width, codec_context->height, 1 );
|
||||||
#else
|
#else
|
||||||
int size = avpicture_get_size( c->pix_fmt, c->width, c->height );
|
int size = avpicture_get_size( codec_context->pix_fmt, codec_context->width, codec_context->height );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint8_t *opicture_buf = (uint8_t *)av_malloc( size );
|
uint8_t *opicture_buf = (uint8_t *)av_malloc( size );
|
||||||
|
@ -315,17 +322,17 @@ void VideoStream::OpenStream( ) {
|
||||||
}
|
}
|
||||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
av_image_fill_arrays(opicture->data, opicture->linesize,
|
av_image_fill_arrays(opicture->data, opicture->linesize,
|
||||||
opicture_buf, c->pix_fmt, c->width, c->height, 1);
|
opicture_buf, codec_context->pix_fmt, codec_context->width, codec_context->height, 1);
|
||||||
#else
|
#else
|
||||||
avpicture_fill( (AVPicture *)opicture, opicture_buf, c->pix_fmt,
|
avpicture_fill( (AVPicture *)opicture, opicture_buf, codec_context->pix_fmt,
|
||||||
c->width, c->height );
|
codec_context->width, codec_context->height );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* if the output format is not identical to the input format, then a temporary
|
/* if the output format is not identical to the input format, then a temporary
|
||||||
picture is needed too. It is then converted to the required
|
picture is needed too. It is then converted to the required
|
||||||
output format */
|
output format */
|
||||||
tmp_opicture = NULL;
|
tmp_opicture = NULL;
|
||||||
if ( c->pix_fmt != pf ) {
|
if ( codec_context->pix_fmt != pf ) {
|
||||||
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
||||||
tmp_opicture = av_frame_alloc( );
|
tmp_opicture = av_frame_alloc( );
|
||||||
#else
|
#else
|
||||||
|
@ -335,9 +342,9 @@ void VideoStream::OpenStream( ) {
|
||||||
Panic( "Could not allocate tmp_opicture" );
|
Panic( "Could not allocate tmp_opicture" );
|
||||||
}
|
}
|
||||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
int size = av_image_get_buffer_size( pf, c->width, c->height,1 );
|
int size = av_image_get_buffer_size( pf, codec_context->width, codec_context->height,1 );
|
||||||
#else
|
#else
|
||||||
int size = avpicture_get_size( pf, c->width, c->height );
|
int size = avpicture_get_size( pf, codec_context->width, codec_context->height );
|
||||||
#endif
|
#endif
|
||||||
uint8_t *tmp_opicture_buf = (uint8_t *)av_malloc( size );
|
uint8_t *tmp_opicture_buf = (uint8_t *)av_malloc( size );
|
||||||
if ( !tmp_opicture_buf ) {
|
if ( !tmp_opicture_buf ) {
|
||||||
|
@ -347,10 +354,10 @@ void VideoStream::OpenStream( ) {
|
||||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
av_image_fill_arrays(tmp_opicture->data,
|
av_image_fill_arrays(tmp_opicture->data,
|
||||||
tmp_opicture->linesize, tmp_opicture_buf, pf,
|
tmp_opicture->linesize, tmp_opicture_buf, pf,
|
||||||
c->width, c->height, 1);
|
codec_context->width, codec_context->height, 1);
|
||||||
#else
|
#else
|
||||||
avpicture_fill( (AVPicture *)tmp_opicture,
|
avpicture_fill( (AVPicture *)tmp_opicture,
|
||||||
tmp_opicture_buf, pf, c->width, c->height );
|
tmp_opicture_buf, pf, codec_context->width, codec_context->height );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -375,7 +382,12 @@ void VideoStream::OpenStream( ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
video_outbuf = NULL;
|
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) {
|
||||||
|
#else
|
||||||
if ( !(of->flags & AVFMT_RAWPICTURE) ) {
|
if ( !(of->flags & AVFMT_RAWPICTURE) ) {
|
||||||
|
#endif
|
||||||
/* allocate output buffer */
|
/* allocate output buffer */
|
||||||
/* XXX: API change will be done */
|
/* XXX: API change will be done */
|
||||||
// TODO: Make buffer dynamic.
|
// TODO: Make buffer dynamic.
|
||||||
|
@ -446,6 +458,8 @@ VideoStream::VideoStream( const char *in_filename, const char *in_format, int bi
|
||||||
if ( pthread_mutex_init( buffer_copy_lock, NULL ) != 0 ) {
|
if ( pthread_mutex_init( buffer_copy_lock, NULL ) != 0 ) {
|
||||||
Fatal("pthread_mutex_init failed");
|
Fatal("pthread_mutex_init failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
codec_context = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoStream::~VideoStream( ) {
|
VideoStream::~VideoStream( ) {
|
||||||
|
@ -481,7 +495,7 @@ VideoStream::~VideoStream( ) {
|
||||||
|
|
||||||
/* close each codec */
|
/* close each codec */
|
||||||
if ( ost ) {
|
if ( ost ) {
|
||||||
avcodec_close( ost->codec );
|
avcodec_close( codec_context );
|
||||||
av_free( opicture->data[0] );
|
av_free( opicture->data[0] );
|
||||||
av_frame_free( &opicture );
|
av_frame_free( &opicture );
|
||||||
if ( tmp_opicture ) {
|
if ( tmp_opicture ) {
|
||||||
|
@ -564,17 +578,15 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size,
|
||||||
static struct SwsContext *img_convert_ctx = 0;
|
static struct SwsContext *img_convert_ctx = 0;
|
||||||
#endif // HAVE_LIBSWSCALE
|
#endif // HAVE_LIBSWSCALE
|
||||||
|
|
||||||
AVCodecContext *c = ost->codec;
|
if ( codec_context->pix_fmt != pf ) {
|
||||||
|
|
||||||
if ( c->pix_fmt != pf ) {
|
|
||||||
memcpy( tmp_opicture->data[0], buffer, buffer_size );
|
memcpy( tmp_opicture->data[0], buffer, buffer_size );
|
||||||
#ifdef HAVE_LIBSWSCALE
|
#ifdef HAVE_LIBSWSCALE
|
||||||
if ( !img_convert_ctx ) {
|
if ( !img_convert_ctx ) {
|
||||||
img_convert_ctx = sws_getCachedContext( NULL, c->width, c->height, pf, c->width, c->height, c->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL );
|
img_convert_ctx = sws_getCachedContext( NULL, codec_context->width, codec_context->height, pf, codec_context->width, codec_context->height, codec_context->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL );
|
||||||
if ( !img_convert_ctx )
|
if ( !img_convert_ctx )
|
||||||
Panic( "Unable to initialise image scaling context" );
|
Panic( "Unable to initialise image scaling context" );
|
||||||
}
|
}
|
||||||
sws_scale( img_convert_ctx, tmp_opicture->data, tmp_opicture->linesize, 0, c->height, opicture->data, opicture->linesize );
|
sws_scale( img_convert_ctx, tmp_opicture->data, tmp_opicture->linesize, 0, codec_context->height, opicture->data, opicture->linesize );
|
||||||
#else // HAVE_LIBSWSCALE
|
#else // HAVE_LIBSWSCALE
|
||||||
Fatal( "swscale is required for MPEG mode" );
|
Fatal( "swscale is required for MPEG mode" );
|
||||||
#endif // HAVE_LIBSWSCALE
|
#endif // HAVE_LIBSWSCALE
|
||||||
|
@ -586,7 +598,13 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size,
|
||||||
AVPacket *pkt = packet_buffers[packet_index];
|
AVPacket *pkt = packet_buffers[packet_index];
|
||||||
av_init_packet( pkt );
|
av_init_packet( pkt );
|
||||||
int got_packet = 0;
|
int got_packet = 0;
|
||||||
|
#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) {
|
||||||
|
#else
|
||||||
if ( of->flags & AVFMT_RAWPICTURE ) {
|
if ( of->flags & AVFMT_RAWPICTURE ) {
|
||||||
|
#endif
|
||||||
|
|
||||||
#if LIBAVCODEC_VERSION_CHECK(52, 30, 2, 30, 2)
|
#if LIBAVCODEC_VERSION_CHECK(52, 30, 2, 30, 2)
|
||||||
pkt->flags |= AV_PKT_FLAG_KEY;
|
pkt->flags |= AV_PKT_FLAG_KEY;
|
||||||
#else
|
#else
|
||||||
|
@ -597,19 +615,34 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size,
|
||||||
pkt->size = sizeof (AVPicture);
|
pkt->size = sizeof (AVPicture);
|
||||||
got_packet = 1;
|
got_packet = 1;
|
||||||
} else {
|
} else {
|
||||||
opicture_ptr->pts = c->frame_number;
|
opicture_ptr->pts = codec_context->frame_number;
|
||||||
opicture_ptr->quality = c->global_quality;
|
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 ) {
|
||||||
|
if ( AVERROR_EOF != ret ) {
|
||||||
|
Error("ERror encoding video (%d) (%s)", ret,
|
||||||
|
av_err2str(ret));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
got_packet = 1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
#if LIBAVFORMAT_VERSION_CHECK(54, 1, 0, 2, 100)
|
#if LIBAVFORMAT_VERSION_CHECK(54, 1, 0, 2, 100)
|
||||||
int ret = avcodec_encode_video2( c, pkt, opicture_ptr, &got_packet );
|
int ret = avcodec_encode_video2( codec_context, pkt, opicture_ptr, &got_packet );
|
||||||
if ( ret != 0 ) {
|
if ( ret != 0 ) {
|
||||||
Fatal( "avcodec_encode_video2 failed with errorcode %d \"%s\"", ret, av_err2str( ret ) );
|
Fatal( "avcodec_encode_video2 failed with errorcode %d \"%s\"", ret, av_err2str( ret ) );
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
int out_size = avcodec_encode_video( c, video_outbuf, video_outbuf_size, opicture_ptr );
|
int out_size = avcodec_encode_video( codec_context, video_outbuf, video_outbuf_size, opicture_ptr );
|
||||||
got_packet = out_size > 0 ? 1 : 0;
|
got_packet = out_size > 0 ? 1 : 0;
|
||||||
pkt->data = got_packet ? video_outbuf : NULL;
|
pkt->data = got_packet ? video_outbuf : NULL;
|
||||||
pkt->size = got_packet ? out_size : 0;
|
pkt->size = got_packet ? out_size : 0;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
if ( got_packet ) {
|
if ( got_packet ) {
|
||||||
// if ( c->coded_frame->key_frame )
|
// if ( c->coded_frame->key_frame )
|
||||||
|
@ -622,12 +655,12 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size,
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if ( pkt->pts != (int64_t)AV_NOPTS_VALUE ) {
|
if ( pkt->pts != (int64_t)AV_NOPTS_VALUE ) {
|
||||||
pkt->pts = av_rescale_q( pkt->pts, c->time_base, ost->time_base );
|
pkt->pts = av_rescale_q( pkt->pts, codec_context->time_base, ost->time_base );
|
||||||
}
|
}
|
||||||
if ( pkt->dts != (int64_t)AV_NOPTS_VALUE ) {
|
if ( pkt->dts != (int64_t)AV_NOPTS_VALUE ) {
|
||||||
pkt->dts = av_rescale_q( pkt->dts, c->time_base, ost->time_base );
|
pkt->dts = av_rescale_q( pkt->dts, codec_context->time_base, ost->time_base );
|
||||||
}
|
}
|
||||||
pkt->duration = av_rescale_q( pkt->duration, c->time_base, ost->time_base );
|
pkt->duration = av_rescale_q( pkt->duration, codec_context->time_base, ost->time_base );
|
||||||
pkt->stream_index = ost->index;
|
pkt->stream_index = ost->index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -659,7 +692,11 @@ void *VideoStream::StreamingThreadCallback(void *ctx){
|
||||||
|
|
||||||
const uint64_t nanosecond_multiplier = 1000000000;
|
const uint64_t nanosecond_multiplier = 1000000000;
|
||||||
|
|
||||||
uint64_t target_interval_ns = nanosecond_multiplier * ( ((double)videoStream->ost->codec->time_base.num) / (videoStream->ost->codec->time_base.den) );
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
|
uint64_t target_interval_ns = nanosecond_multiplier * ( ((double)videoStream->codec_context->time_base.num) / (videoStream->codec_context->time_base.den) );
|
||||||
|
#else
|
||||||
|
uint64_t target_interval_ns = nanosecond_multiplier * ( ((double)videoStream->codec_context->time_base.num) / (videoStream->codec_context->time_base.den) );
|
||||||
|
#endif
|
||||||
uint64_t frame_count = 0;
|
uint64_t frame_count = 0;
|
||||||
timespec start_time;
|
timespec start_time;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
||||||
|
|
|
@ -46,6 +46,7 @@ protected:
|
||||||
AVOutputFormat *of;
|
AVOutputFormat *of;
|
||||||
AVFormatContext *ofc;
|
AVFormatContext *ofc;
|
||||||
AVStream *ost;
|
AVStream *ost;
|
||||||
|
AVCodecContext *codec_context;
|
||||||
AVCodec *codec;
|
AVCodec *codec;
|
||||||
AVFrame *opicture;
|
AVFrame *opicture;
|
||||||
AVFrame *tmp_opicture;
|
AVFrame *tmp_opicture;
|
||||||
|
|
|
@ -29,6 +29,7 @@ ZMPacket::ZMPacket( ) {
|
||||||
image = NULL;
|
image = NULL;
|
||||||
frame = NULL;
|
frame = NULL;
|
||||||
av_init_packet( &packet );
|
av_init_packet( &packet );
|
||||||
|
packet.size = 0;
|
||||||
gettimeofday( ×tamp, NULL );
|
gettimeofday( ×tamp, NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,24 +43,31 @@ ZMPacket::ZMPacket( Image *i ) {
|
||||||
|
|
||||||
ZMPacket::ZMPacket( AVPacket *p ) {
|
ZMPacket::ZMPacket( AVPacket *p ) {
|
||||||
av_init_packet( &packet );
|
av_init_packet( &packet );
|
||||||
if ( zm_av_packet_ref( &packet, p ) < 0 ) {
|
set_packet( p );
|
||||||
Error("error refing packet");
|
|
||||||
}
|
|
||||||
gettimeofday( ×tamp, NULL );
|
|
||||||
keyframe = p->flags & AV_PKT_FLAG_KEY;
|
keyframe = p->flags & AV_PKT_FLAG_KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZMPacket::ZMPacket( AVPacket *p, struct timeval *t ) {
|
ZMPacket::ZMPacket( AVPacket *p, struct timeval *t ) {
|
||||||
av_init_packet( &packet );
|
av_init_packet( &packet );
|
||||||
if ( zm_av_packet_ref( &packet, p ) < 0 ) {
|
set_packet( p );
|
||||||
Error("error refing packet");
|
|
||||||
}
|
|
||||||
timestamp = *t;
|
timestamp = *t;
|
||||||
keyframe = p->flags & AV_PKT_FLAG_KEY;
|
keyframe = p->flags & AV_PKT_FLAG_KEY;
|
||||||
}
|
}
|
||||||
|
ZMPacket::ZMPacket( AVPacket *p, AVFrame *f, Image *i ) {
|
||||||
|
av_init_packet( &packet );
|
||||||
|
set_packet( p );
|
||||||
|
image = i;
|
||||||
|
frame = f;
|
||||||
|
}
|
||||||
|
|
||||||
ZMPacket::~ZMPacket() {
|
ZMPacket::~ZMPacket() {
|
||||||
zm_av_packet_unref( &packet );
|
zm_av_packet_unref( &packet );
|
||||||
|
if ( frame ) {
|
||||||
|
av_frame_free( &frame );
|
||||||
|
}
|
||||||
|
if ( image ) {
|
||||||
|
delete image;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZMPacket::decode( AVCodecContext *ctx ) {
|
int ZMPacket::decode( AVCodecContext *ctx ) {
|
||||||
|
@ -74,8 +82,8 @@ int ZMPacket::decode( AVCodecContext *ctx ) {
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
int ret = avcodec_send_packet( ctx, &packet );
|
int ret = avcodec_send_packet( ctx, &packet );
|
||||||
if ( ret < 0 ) {
|
if ( ret < 0 ) {
|
||||||
Error( "Unable to send packet: %s", av_make_error_string( ret ) );
|
Error( "Unable to send packet: %s", av_make_error_string(ret).c_str() );
|
||||||
av_frame_free( &frame );
|
av_frame_free( &frame );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,13 +91,13 @@ int ZMPacket::decode( AVCodecContext *ctx ) {
|
||||||
if ( hwaccel ) {
|
if ( hwaccel ) {
|
||||||
ret = avcodec_receive_frame( ctx, hwFrame );
|
ret = avcodec_receive_frame( ctx, hwFrame );
|
||||||
if ( ret < 0 ) {
|
if ( ret < 0 ) {
|
||||||
Error( "Unable to receive frame: %s", av_make_error_string( ret ) );
|
Error( "Unable to receive frame: %s", av_make_error_string(ret).c_str() );
|
||||||
av_frame_free( &frame );
|
av_frame_free( &frame );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ret = av_hwframe_transfer_data(frame, hwFrame, 0);
|
ret = av_hwframe_transfer_data(frame, hwFrame, 0);
|
||||||
if ( ret < 0 ) {
|
if ( ret < 0 ) {
|
||||||
Error( "Unable to transfer frame: %s", av_make_error_string( ret ) );
|
Error( "Unable to transfer frame: %s", av_make_error_string(ret).c_str() );
|
||||||
av_frame_free( &frame );
|
av_frame_free( &frame );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -97,7 +105,7 @@ int ZMPacket::decode( AVCodecContext *ctx ) {
|
||||||
#endif
|
#endif
|
||||||
ret = avcodec_receive_frame( ctx, frame );
|
ret = avcodec_receive_frame( ctx, frame );
|
||||||
if ( ret < 0 ) {
|
if ( ret < 0 ) {
|
||||||
Error( "Unable to receive frame: %s", av_make_error_string( ret ) );
|
Error( "Unable to receive frame: %s", av_make_error_string(ret).c_str() );
|
||||||
av_frame_free( &frame );
|
av_frame_free( &frame );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -108,15 +116,15 @@ int ZMPacket::decode( AVCodecContext *ctx ) {
|
||||||
|
|
||||||
# else
|
# else
|
||||||
int frameComplete = 0;
|
int frameComplete = 0;
|
||||||
ret = zm_avcodec_decode_video( ctx, frame, &frameComplete, &packet );
|
int ret = zm_avcodec_decode_video( ctx, frame, &frameComplete, &packet );
|
||||||
if ( ret < 0 ) {
|
if ( ret < 0 ) {
|
||||||
Error( "Unable to decode frame at frame %s", av_make_error_string( ret ) );
|
Error( "Unable to decode frame at frame %s", av_make_error_string(ret).c_str() );
|
||||||
av_frame_free( &frame );
|
av_frame_free( &frame );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if ( ! frameComplete ) {
|
if ( ! frameComplete ) {
|
||||||
Debug(1, "incomplete frame?");
|
Debug(1, "incomplete frame?");
|
||||||
av_frame_free( &frame );
|
av_frame_free( &frame );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -124,12 +132,10 @@ int ZMPacket::decode( AVCodecContext *ctx ) {
|
||||||
} // end ZMPacket::decode
|
} // end ZMPacket::decode
|
||||||
|
|
||||||
Image * ZMPacket::get_image( Image *i = NULL ) {
|
Image * ZMPacket::get_image( Image *i = NULL ) {
|
||||||
|
|
||||||
if ( ! frame ) {
|
if ( ! frame ) {
|
||||||
Error("Can't get image without frame.. maybe need to decode first");
|
Error("Can't get image without frame.. maybe need to decode first");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! image ) {
|
if ( ! image ) {
|
||||||
if ( ! i ) {
|
if ( ! i ) {
|
||||||
Error("Need a pre-allocated image buffer");
|
Error("Need a pre-allocated image buffer");
|
||||||
|
@ -137,27 +143,19 @@ Image * ZMPacket::get_image( Image *i = NULL ) {
|
||||||
}
|
}
|
||||||
image = i;
|
image = i;
|
||||||
}
|
}
|
||||||
/* Request a writeable buffer of the target image */
|
image->Assign( frame );
|
||||||
uint8_t* directbuffer = image->WriteBuffer();
|
|
||||||
//uint8_t* directbuffer = image.WriteBuffer(width, height, colours, subpixelorder);
|
|
||||||
if ( directbuffer == NULL ) {
|
|
||||||
Error("Failed requesting writeable buffer for the captured image.");
|
|
||||||
image = NULL;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
AVFrame *mFrame = zm_av_frame_alloc();
|
|
||||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
|
||||||
av_image_fill_arrays(mFrame->data, mFrame->linesize, directbuffer, imagePixFormat, frame->width, frame->height, 1);
|
|
||||||
#else
|
|
||||||
avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, frame->width, frame->height);
|
|
||||||
#endif
|
|
||||||
if (sws_scale(mConvertContext, frame->data, frame->linesize,
|
|
||||||
0, mVideoCodecContext->height, mFrame->data, mFrame->linesize) < 0) {
|
|
||||||
Fatal("Unable to convert raw format %u to target format %u",
|
|
||||||
mVideoCodecContext->pix_fmt, imagePixFormat);
|
|
||||||
}
|
|
||||||
av_frame_free( &mFrame );
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Image *ZMPacket::set_image( Image *i ) {
|
||||||
|
image = i;
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVPacket *ZMPacket::set_packet( AVPacket *p ) {
|
||||||
|
if ( zm_av_packet_ref( &packet, p ) < 0 ) {
|
||||||
|
Error("error refing packet");
|
||||||
|
}
|
||||||
|
gettimeofday( ×tamp, NULL );
|
||||||
|
keyframe = p->flags & AV_PKT_FLAG_KEY;
|
||||||
|
}
|
||||||
|
|
|
@ -40,15 +40,20 @@ class ZMPacket {
|
||||||
struct timeval timestamp;
|
struct timeval timestamp;
|
||||||
public:
|
public:
|
||||||
AVPacket *av_packet() { return &packet; }
|
AVPacket *av_packet() { return &packet; }
|
||||||
|
AVPacket *set_packet( AVPacket *p ) ;
|
||||||
AVFrame *av_frame() { return frame; }
|
AVFrame *av_frame() { return frame; }
|
||||||
Image *get_image( Image * );
|
Image *get_image( Image * );
|
||||||
|
Image *set_image( Image * );
|
||||||
|
|
||||||
int is_keyframe() { return keyframe; };
|
int is_keyframe() { return keyframe; };
|
||||||
int decode( AVCodecContext *ctx );
|
int decode( AVCodecContext *ctx );
|
||||||
ZMPacket( AVPacket *packet, struct timeval *timestamp );
|
ZMPacket( AVPacket *packet, struct timeval *timestamp );
|
||||||
ZMPacket( AVPacket *packet );
|
ZMPacket( AVPacket *packet );
|
||||||
|
ZMPacket( AVPacket *packet, AVFrame *frame, Image *image );
|
||||||
ZMPacket( Image *image );
|
ZMPacket( Image *image );
|
||||||
ZMPacket();
|
ZMPacket();
|
||||||
~ZMPacket();
|
~ZMPacket();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* ZM_PACKET_H */
|
#endif /* ZM_PACKET_H */
|
||||||
|
|
|
@ -103,6 +103,7 @@ int RemoteCamera::Read( int fd, char *buf, int size ) {
|
||||||
int bytes_to_recv = size - ReceivedBytes;
|
int bytes_to_recv = size - ReceivedBytes;
|
||||||
if ( SOCKET_BUF_SIZE < bytes_to_recv )
|
if ( SOCKET_BUF_SIZE < bytes_to_recv )
|
||||||
bytes_to_recv = SOCKET_BUF_SIZE;
|
bytes_to_recv = SOCKET_BUF_SIZE;
|
||||||
|
//Debug(3, "Aiming to receive %d of %d bytes", bytes_to_recv, size );
|
||||||
bytes = recv(fd, &buf[ReceivedBytes], bytes_to_recv, 0); //socket, buffer, len, flags
|
bytes = recv(fd, &buf[ReceivedBytes], bytes_to_recv, 0); //socket, buffer, len, flags
|
||||||
if ( bytes <= 0 ) {
|
if ( bytes <= 0 ) {
|
||||||
Error("RemoteCamera::Read Recv error. Closing Socket\n");
|
Error("RemoteCamera::Read Recv error. Closing Socket\n");
|
||||||
|
|
|
@ -87,8 +87,9 @@ public:
|
||||||
virtual void Terminate() = 0;
|
virtual void Terminate() = 0;
|
||||||
virtual int Connect() = 0;
|
virtual int Connect() = 0;
|
||||||
virtual int Disconnect() = 0;
|
virtual int Disconnect() = 0;
|
||||||
virtual int PreCapture() = 0;
|
virtual int PreCapture() { return 0; };
|
||||||
virtual ZMPacket *Capture( Image &image ) = 0;
|
virtual int PrimeCapture() { return 0; };
|
||||||
|
virtual int Capture( ZMPacket &p ) = 0;
|
||||||
virtual int PostCapture() = 0;
|
virtual int PostCapture() = 0;
|
||||||
int Read( int fd, char*buf, int size );
|
int Read( int fd, char*buf, int size );
|
||||||
};
|
};
|
||||||
|
|
|
@ -75,26 +75,22 @@ RemoteCameraHttp::RemoteCameraHttp(
|
||||||
method = REGEXP;
|
method = REGEXP;
|
||||||
else
|
else
|
||||||
Fatal( "Unrecognised method '%s' when creating HTTP camera %d", p_method.c_str(), monitor_id );
|
Fatal( "Unrecognised method '%s' when creating HTTP camera %d", p_method.c_str(), monitor_id );
|
||||||
if ( capture )
|
if ( capture ) {
|
||||||
{
|
|
||||||
Initialise();
|
Initialise();
|
||||||
}
|
}
|
||||||
|
video_stream = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoteCameraHttp::~RemoteCameraHttp()
|
RemoteCameraHttp::~RemoteCameraHttp() {
|
||||||
{
|
if ( capture ) {
|
||||||
if ( capture )
|
|
||||||
{
|
|
||||||
Terminate();
|
Terminate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteCameraHttp::Initialise()
|
void RemoteCameraHttp::Initialise() {
|
||||||
{
|
|
||||||
RemoteCamera::Initialise();
|
RemoteCamera::Initialise();
|
||||||
|
|
||||||
if ( request.empty() )
|
if ( request.empty() ) {
|
||||||
{
|
|
||||||
request = stringtf( "GET %s HTTP/%s\r\n", path.c_str(), config.http_version );
|
request = stringtf( "GET %s HTTP/%s\r\n", path.c_str(), config.http_version );
|
||||||
request += stringtf( "User-Agent: %s/%s\r\n", config.http_ua, ZM_VERSION );
|
request += stringtf( "User-Agent: %s/%s\r\n", config.http_ua, ZM_VERSION );
|
||||||
request += stringtf( "Host: %s\r\n", host.c_str());
|
request += stringtf( "Host: %s\r\n", host.c_str());
|
||||||
|
@ -106,8 +102,7 @@ void RemoteCameraHttp::Initialise()
|
||||||
Debug( 2, "Request: %s", request.c_str() );
|
Debug( 2, "Request: %s", request.c_str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !timeout.tv_sec )
|
if ( !timeout.tv_sec ) {
|
||||||
{
|
|
||||||
timeout.tv_sec = config.http_timeout/1000;
|
timeout.tv_sec = config.http_timeout/1000;
|
||||||
timeout.tv_usec = (config.http_timeout%1000)*1000;
|
timeout.tv_usec = (config.http_timeout%1000)*1000;
|
||||||
}
|
}
|
||||||
|
@ -121,21 +116,17 @@ void RemoteCameraHttp::Initialise()
|
||||||
state = HEADER;
|
state = HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RemoteCameraHttp::Connect()
|
int RemoteCameraHttp::Connect() {
|
||||||
{
|
|
||||||
struct addrinfo *p;
|
struct addrinfo *p;
|
||||||
|
|
||||||
for(p = hp; p != NULL; p = p->ai_next)
|
for ( p = hp; p != NULL; p = p->ai_next ) {
|
||||||
{
|
|
||||||
sd = socket( p->ai_family, p->ai_socktype, p->ai_protocol );
|
sd = socket( p->ai_family, p->ai_socktype, p->ai_protocol );
|
||||||
if ( sd < 0 )
|
if ( sd < 0 ) {
|
||||||
{
|
|
||||||
Warning("Can't create socket: %s", strerror(errno) );
|
Warning("Can't create socket: %s", strerror(errno) );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( connect( sd, p->ai_addr, p->ai_addrlen ) < 0 )
|
if ( connect( sd, p->ai_addr, p->ai_addrlen ) < 0 ) {
|
||||||
{
|
|
||||||
close(sd);
|
close(sd);
|
||||||
sd = -1;
|
sd = -1;
|
||||||
char buf[sizeof(struct in6_addr)];
|
char buf[sizeof(struct in6_addr)];
|
||||||
|
@ -151,7 +142,7 @@ int RemoteCameraHttp::Connect()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(p == NULL) {
|
if ( p == NULL ) {
|
||||||
Error("Unable to connect to the remote camera, aborting");
|
Error("Unable to connect to the remote camera, aborting");
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
@ -160,16 +151,14 @@ int RemoteCameraHttp::Connect()
|
||||||
return( sd );
|
return( sd );
|
||||||
}
|
}
|
||||||
|
|
||||||
int RemoteCameraHttp::Disconnect()
|
int RemoteCameraHttp::Disconnect() {
|
||||||
{
|
|
||||||
close( sd );
|
close( sd );
|
||||||
sd = -1;
|
sd = -1;
|
||||||
Debug( 3, "Disconnected from host" );
|
Debug( 3, "Disconnected from host" );
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
int RemoteCameraHttp::SendRequest()
|
int RemoteCameraHttp::SendRequest() {
|
||||||
{
|
|
||||||
Debug( 2, "Sending request: %s", request.c_str() );
|
Debug( 2, "Sending request: %s", request.c_str() );
|
||||||
if ( write( sd, request.data(), request.length() ) < 0 )
|
if ( write( sd, request.data(), request.length() ) < 0 )
|
||||||
{
|
{
|
||||||
|
@ -250,12 +239,12 @@ int RemoteCameraHttp::ReadData( Buffer &buffer, unsigned int bytes_expected ) {
|
||||||
// There can be lots of bytes available. I've seen 4MB or more. This will vastly inflate our buffer size unnecessarily.
|
// There can be lots of bytes available. I've seen 4MB or more. This will vastly inflate our buffer size unnecessarily.
|
||||||
if ( total_bytes_to_read > ZM_NETWORK_BUFSIZ ) {
|
if ( total_bytes_to_read > ZM_NETWORK_BUFSIZ ) {
|
||||||
total_bytes_to_read = ZM_NETWORK_BUFSIZ;
|
total_bytes_to_read = ZM_NETWORK_BUFSIZ;
|
||||||
Debug(3, "Just getting 32K" );
|
Debug(4, "Just getting 32K" );
|
||||||
} else {
|
} else {
|
||||||
Debug(3, "Just getting %d", total_bytes_to_read );
|
Debug(4, "Just getting %d", total_bytes_to_read );
|
||||||
}
|
}
|
||||||
} // end if bytes_expected or not
|
} // end if bytes_expected or not
|
||||||
Debug( 3, "Expecting %d bytes", total_bytes_to_read );
|
Debug( 4, "Expecting %d bytes", total_bytes_to_read );
|
||||||
|
|
||||||
int total_bytes_read = 0;
|
int total_bytes_read = 0;
|
||||||
do {
|
do {
|
||||||
|
@ -1036,59 +1025,65 @@ int RemoteCameraHttp::PreCapture() {
|
||||||
return( 0 );
|
return( 0 );
|
||||||
} // end int RemoteCameraHttp::PreCapture()
|
} // end int RemoteCameraHttp::PreCapture()
|
||||||
|
|
||||||
ZMPacket * RemoteCameraHttp::Capture( Image &image ) {
|
int RemoteCameraHttp::Capture( ZMPacket &packet ) {
|
||||||
int content_length = GetResponse();
|
int content_length = GetResponse();
|
||||||
if ( content_length == 0 ) {
|
if ( content_length == 0 ) {
|
||||||
Warning( "Unable to capture image, retrying" );
|
Warning( "Unable to capture image, retrying" );
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
if ( content_length < 0 ) {
|
if ( content_length < 0 ) {
|
||||||
Error( "Unable to get response, disconnecting" );
|
Error( "Unable to get response, disconnecting" );
|
||||||
Disconnect();
|
Disconnect();
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Image *image = packet.image;
|
||||||
|
|
||||||
switch( format ) {
|
switch( format ) {
|
||||||
case JPEG :
|
case JPEG :
|
||||||
{
|
if ( !image->DecodeJpeg( buffer.extract( content_length ), content_length, colours, subpixelorder ) ) {
|
||||||
if ( !image.DecodeJpeg( buffer.extract( content_length ), content_length, colours, subpixelorder ) ) {
|
Error( "Unable to decode jpeg" );
|
||||||
Error( "Unable to decode jpeg" );
|
|
||||||
Disconnect();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case X_RGB :
|
|
||||||
{
|
|
||||||
if ( content_length != (long)image.Size() ) {
|
|
||||||
Error( "Image length mismatch, expected %d bytes, content length was %d", image.Size(), content_length );
|
|
||||||
Disconnect();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
image.Assign( width, height, colours, subpixelorder, buffer, imagesize );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case X_RGBZ :
|
|
||||||
{
|
|
||||||
if ( !image.Unzip( buffer.extract( content_length ), content_length ) ) {
|
|
||||||
Error( "Unable to unzip RGB image" );
|
|
||||||
Disconnect();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
image.Assign( width, height, colours, subpixelorder, buffer, imagesize );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default :
|
|
||||||
{
|
|
||||||
Error( "Unexpected image format encountered" );
|
|
||||||
Disconnect();
|
Disconnect();
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case X_RGB :
|
||||||
|
if ( content_length != (long)image->Size() ) {
|
||||||
|
Error( "Image length mismatch, expected %d bytes, content length was %d", image->Size(), content_length );
|
||||||
|
Disconnect();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
image->Assign( width, height, colours, subpixelorder, buffer, imagesize );
|
||||||
|
break;
|
||||||
|
case X_RGBZ :
|
||||||
|
if ( !image->Unzip( buffer.extract( content_length ), content_length ) ) {
|
||||||
|
Error( "Unable to unzip RGB image" );
|
||||||
|
Disconnect();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
image->Assign( width, height, colours, subpixelorder, buffer, imagesize );
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
Error( "Unexpected image format encountered" );
|
||||||
|
Disconnect();
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
ZMPacket *packet = new ZMPacket( &image );
|
return 1;
|
||||||
return packet;
|
|
||||||
} // end ZmPacket *RmoteCameraHttp::Capture( &image );
|
} // end ZmPacket *RmoteCameraHttp::Capture( &image );
|
||||||
|
|
||||||
int RemoteCameraHttp::PostCapture() {
|
int RemoteCameraHttp::PostCapture() {
|
||||||
return( 0 );
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVStream *RemoteCameraHttp::get_VideoStream() {
|
||||||
|
if ( video_stream ) {
|
||||||
|
AVFormatContext *oc = avformat_alloc_context();
|
||||||
|
video_stream = avformat_new_stream( oc, NULL );
|
||||||
|
if ( video_stream ) {
|
||||||
|
video_stream->codec->width = width;
|
||||||
|
video_stream->codec->height = height;
|
||||||
|
video_stream->codec->pix_fmt = GetFFMPEGPixelFormat(colours,subpixelorder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return video_stream;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,8 +70,9 @@ public:
|
||||||
int ReadData( Buffer &buffer, unsigned int bytes_expected=0 );
|
int ReadData( Buffer &buffer, unsigned int bytes_expected=0 );
|
||||||
int GetResponse();
|
int GetResponse();
|
||||||
int PreCapture();
|
int PreCapture();
|
||||||
ZMPacket *Capture( Image &image );
|
int Capture( ZMPacket &p );
|
||||||
int PostCapture();
|
int PostCapture();
|
||||||
|
AVStream* get_VideoStream();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ZM_REMOTE_CAMERA_HTTP_H
|
#endif // ZM_REMOTE_CAMERA_HTTP_H
|
||||||
|
|
|
@ -67,6 +67,7 @@ RemoteCameraNVSocket::RemoteCameraNVSocket(
|
||||||
|
|
||||||
timeout.tv_sec = 0;
|
timeout.tv_sec = 0;
|
||||||
timeout.tv_usec = 0;
|
timeout.tv_usec = 0;
|
||||||
|
subpixelorder = ZM_SUBPIX_ORDER_BGR;
|
||||||
|
|
||||||
if ( capture ) {
|
if ( capture ) {
|
||||||
Initialise();
|
Initialise();
|
||||||
|
@ -97,43 +98,39 @@ void RemoteCameraNVSocket::Initialise() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int RemoteCameraNVSocket::Connect() {
|
int RemoteCameraNVSocket::Connect() {
|
||||||
|
int port_num = atoi(port.c_str());
|
||||||
//struct addrinfo *p;
|
//struct addrinfo *p;
|
||||||
struct sockaddr_in servaddr;
|
struct sockaddr_in servaddr;
|
||||||
bzero( &servaddr, sizeof(servaddr));
|
bzero( &servaddr, sizeof(servaddr));
|
||||||
servaddr.sin_family = AF_INET;
|
servaddr.sin_family = AF_INET;
|
||||||
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
|
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
|
||||||
servaddr.sin_port = htons(atoi(port.c_str()));
|
servaddr.sin_port = htons(port_num);
|
||||||
|
|
||||||
|
sd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
sd = socket(AF_INET, SOCK_STREAM, 0);
|
|
||||||
//for(p = hp; p != NULL; p = p->ai_next) {
|
//for(p = hp; p != NULL; p = p->ai_next) {
|
||||||
//sd = socket( p->ai_family, p->ai_socktype, p->ai_protocol );
|
//sd = socket( p->ai_family, p->ai_socktype, p->ai_protocol );
|
||||||
if ( sd < 0 ) {
|
if ( sd < 0 ) {
|
||||||
Warning("Can't create socket: %s", strerror(errno) );
|
Warning("Can't create socket: %s", strerror(errno) );
|
||||||
//continue;
|
//continue;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
//if ( connect( sd, p->ai_addr, p->ai_addrlen ) < 0 ) {
|
|
||||||
if ( connect( sd, (struct sockaddr *)&servaddr , sizeof(servaddr) ) < 0 ) {
|
|
||||||
close(sd);
|
|
||||||
sd = -1;
|
|
||||||
|
|
||||||
Warning("Can't connect to socket mid: %d : %s", monitor_id, strerror(errno) );
|
|
||||||
return -1;
|
|
||||||
//continue;
|
|
||||||
//}
|
|
||||||
/* If we got here, we must have connected successfully */
|
|
||||||
//break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//if ( p == NULL ) {
|
//if ( connect( sd, p->ai_addr, p->ai_addrlen ) < 0 ) {
|
||||||
//Error("Unable to connect to the remote camera, aborting");
|
if ( connect( sd, (struct sockaddr *)&servaddr , sizeof(servaddr) ) < 0 ) {
|
||||||
//return( -1 );
|
close(sd);
|
||||||
//}
|
sd = -1;
|
||||||
|
|
||||||
Debug( 3, "Connected to host, socket = %d", sd );
|
Warning("Can't connect to socket mid: %d : %s", monitor_id, strerror(errno) );
|
||||||
return( sd );
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if ( p == NULL ) {
|
||||||
|
//Error("Unable to connect to the remote camera, aborting");
|
||||||
|
//return( -1 );
|
||||||
|
//}
|
||||||
|
|
||||||
|
Debug( 3, "Connected to host:%d, socket = %d", port_num, sd );
|
||||||
|
return sd;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RemoteCameraNVSocket::Disconnect() {
|
int RemoteCameraNVSocket::Disconnect() {
|
||||||
|
@ -144,132 +141,33 @@ int RemoteCameraNVSocket::Disconnect() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int RemoteCameraNVSocket::SendRequest( std::string request ) {
|
int RemoteCameraNVSocket::SendRequest( std::string request ) {
|
||||||
Debug( 2, "Sending request: %s", request.c_str() );
|
Debug( 4, "Sending request: %s", request.c_str() );
|
||||||
if ( write( sd, request.data(), request.length() ) < 0 ) {
|
if ( write( sd, request.data(), request.length() ) < 0 ) {
|
||||||
Error( "Can't write: %s", strerror(errno) );
|
Error( "Can't write: %s", strerror(errno) );
|
||||||
Disconnect();
|
Disconnect();
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
Debug( 3, "Request sent" );
|
Debug( 4, "Request sent" );
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return codes are as follows:
|
int RemoteCameraNVSocket::PrimeCapture() {
|
||||||
* -1 means there was an error
|
|
||||||
* 0 means no bytes were returned but there wasn't actually an error.
|
|
||||||
* > 0 is the # of bytes read.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int RemoteCameraNVSocket::ReadData( Buffer &buffer, unsigned int bytes_expected ) {
|
|
||||||
fd_set rfds;
|
|
||||||
FD_ZERO(&rfds);
|
|
||||||
FD_SET(sd, &rfds);
|
|
||||||
|
|
||||||
struct timeval temp_timeout = timeout;
|
|
||||||
|
|
||||||
int n_found = select(sd+1, &rfds, NULL, NULL, &temp_timeout);
|
|
||||||
if ( n_found == 0 ) {
|
|
||||||
Debug( 4, "Select timed out timeout was %d secs %d usecs", temp_timeout.tv_sec, temp_timeout.tv_usec );
|
|
||||||
int error = 0;
|
|
||||||
socklen_t len = sizeof(error);
|
|
||||||
int retval = getsockopt(sd, SOL_SOCKET, SO_ERROR, &error, &len);
|
|
||||||
if ( retval != 0 ) {
|
|
||||||
Debug(1, "error getting socket error code %s", strerror(retval));
|
|
||||||
}
|
|
||||||
if ( error != 0 ) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
// Why are we disconnecting? It's just a timeout, meaning that data wasn't available.
|
|
||||||
//Disconnect();
|
|
||||||
return 0;
|
|
||||||
} else if ( n_found < 0 ) {
|
|
||||||
Error("Select error: %s", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int total_bytes_to_read = 0;
|
|
||||||
|
|
||||||
if ( bytes_expected ) {
|
|
||||||
total_bytes_to_read = bytes_expected;
|
|
||||||
} else {
|
|
||||||
if ( ioctl( sd, FIONREAD, &total_bytes_to_read ) < 0 ) {
|
|
||||||
Error( "Can't ioctl(): %s", strerror(errno) );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( total_bytes_to_read == 0 ) {
|
|
||||||
if ( mode == SINGLE_IMAGE ) {
|
|
||||||
int error = 0;
|
|
||||||
socklen_t len = sizeof (error);
|
|
||||||
int retval = getsockopt( sd, SOL_SOCKET, SO_ERROR, &error, &len );
|
|
||||||
if(retval != 0 ) {
|
|
||||||
Debug( 1, "error getting socket error code %s", strerror(retval) );
|
|
||||||
}
|
|
||||||
if (error != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
// Case where we are grabbing a single jpg, but no content-length was given, so the expectation is that we read until close.
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
// If socket is closed locally, then select will fail, but if it is closed remotely
|
|
||||||
// then we have an exception on our socket.. but no data.
|
|
||||||
Debug( 3, "Socket closed remotely" );
|
|
||||||
//Disconnect(); // Disconnect is done outside of ReadData now.
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
// There can be lots of bytes available. I've seen 4MB or more. This will vastly inflate our buffer size unnecessarily.
|
|
||||||
if ( total_bytes_to_read > ZM_NETWORK_BUFSIZ ) {
|
|
||||||
total_bytes_to_read = ZM_NETWORK_BUFSIZ;
|
|
||||||
Debug(3, "Just getting 32K" );
|
|
||||||
} else {
|
|
||||||
Debug(3, "Just getting %d", total_bytes_to_read );
|
|
||||||
}
|
|
||||||
} // end if bytes_expected or not
|
|
||||||
Debug( 3, "Expecting %d bytes", total_bytes_to_read );
|
|
||||||
|
|
||||||
int total_bytes_read = 0;
|
|
||||||
do {
|
|
||||||
int bytes_read = buffer.read_into( sd, total_bytes_to_read );
|
|
||||||
if ( bytes_read < 0 ) {
|
|
||||||
Error( "Read error: %s", strerror(errno) );
|
|
||||||
return( -1 );
|
|
||||||
} else if ( bytes_read == 0 ) {
|
|
||||||
Debug( 2, "Socket closed" );
|
|
||||||
//Disconnect(); // Disconnect is done outside of ReadData now.
|
|
||||||
return( -1 );
|
|
||||||
} else if ( (unsigned int)bytes_read < total_bytes_to_read ) {
|
|
||||||
Error( "Incomplete read, expected %d, got %d", total_bytes_to_read, bytes_read );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
Debug( 3, "Read %d bytes", bytes_read );
|
|
||||||
total_bytes_read += bytes_read;
|
|
||||||
total_bytes_to_read -= bytes_read;
|
|
||||||
} while ( total_bytes_to_read );
|
|
||||||
|
|
||||||
Debug( 4, buffer );
|
|
||||||
|
|
||||||
return( total_bytes_read );
|
|
||||||
}
|
|
||||||
|
|
||||||
int RemoteCameraNVSocket::PreCapture() {
|
|
||||||
if ( sd < 0 ) {
|
if ( sd < 0 ) {
|
||||||
Connect();
|
Connect();
|
||||||
if ( sd < 0 ) {
|
if ( sd < 0 ) {
|
||||||
Error( "Unable to connect to camera" );
|
Error( "Unable to connect to camera" );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
mode = SINGLE_IMAGE;
|
|
||||||
buffer.clear();
|
|
||||||
}
|
}
|
||||||
struct image_def {
|
buffer.clear();
|
||||||
uint16_t width;
|
struct image_def {
|
||||||
uint16_t height;
|
uint16_t width;
|
||||||
uint16_t type;
|
uint16_t height;
|
||||||
};
|
uint16_t type;
|
||||||
struct image_def image_def;
|
};
|
||||||
|
struct image_def image_def;
|
||||||
|
|
||||||
if ( SendRequest("GetImageParams") < 0 ) {
|
if ( SendRequest("GetImageParams\n") < 0 ) {
|
||||||
Error( "Unable to send request" );
|
Error( "Unable to send request" );
|
||||||
Disconnect();
|
Disconnect();
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -288,22 +186,29 @@ struct image_def image_def;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZMPacket * RemoteCameraNVSocket::Capture( Image &image ) {
|
int RemoteCameraNVSocket::Capture( ZMPacket &zm_packet ) {
|
||||||
if ( SendRequest("GetNextImage") < 0 ) {
|
if ( SendRequest("GetNextImage\n") < 0 ) {
|
||||||
Warning( "Unable to capture image, retrying" );
|
Warning( "Unable to capture image, retrying" );
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
if ( Read( sd, buffer, imagesize ) < imagesize ) {
|
if ( Read( sd, buffer, imagesize ) < imagesize ) {
|
||||||
Warning( "Unable to capture image, retrying" );
|
Warning( "Unable to capture image, retrying" );
|
||||||
return NULL;
|
return 0;
|
||||||
|
}
|
||||||
|
uint32_t end;
|
||||||
|
if ( Read(sd, (char *) &end , sizeof(end)) < 0 ) {
|
||||||
|
Warning( "Unable to capture image, retrying" );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if ( end != 0xFFFFFFFF) {
|
||||||
|
Warning("End Bytes Failed\n");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
image.Assign( width, height, colours, subpixelorder, buffer, imagesize );
|
zm_packet.image->Assign( width, height, colours, subpixelorder, buffer, imagesize );
|
||||||
ZMPacket *packet = new ZMPacket( &image );
|
return 1;
|
||||||
return packet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int RemoteCameraNVSocket::PostCapture()
|
int RemoteCameraNVSocket::PostCapture() {
|
||||||
{
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,12 +65,10 @@ bool p_record_audio );
|
||||||
int Connect();
|
int Connect();
|
||||||
int Disconnect();
|
int Disconnect();
|
||||||
int SendRequest( std::string );
|
int SendRequest( std::string );
|
||||||
int ReadData( Buffer &buffer, unsigned int bytes_expected=0 );
|
|
||||||
int GetResponse();
|
int GetResponse();
|
||||||
int PreCapture();
|
int PrimeCapture();
|
||||||
ZMPacket * Capture( Image &image );
|
int Capture( ZMPacket &p );
|
||||||
int PostCapture();
|
int PostCapture();
|
||||||
int CaptureAndRecord( Image &image, timeval recording, char* event_directory ) {return(0);};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ZM_REMOTE_CAMERA_NVSOCKET_H
|
#endif // ZM_REMOTE_CAMERA_NVSOCKET_H
|
||||||
|
|
|
@ -155,12 +155,18 @@ int RemoteCameraRtsp::PrimeCapture() {
|
||||||
mVideoStreamId = -1;
|
mVideoStreamId = -1;
|
||||||
mAudioStreamId = -1;
|
mAudioStreamId = -1;
|
||||||
|
|
||||||
|
|
||||||
// Find the first video stream.
|
// Find the first video stream.
|
||||||
for ( unsigned int i = 0; i < mFormatContext->nb_streams; i++ ) {
|
for ( unsigned int i = 0; i < mFormatContext->nb_streams; i++ ) {
|
||||||
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO )
|
AVCodecParameters *codec_context = mFormatContext->streams[i]->codecpar;
|
||||||
#else
|
#else
|
||||||
if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO )
|
AVCodecContext *codec_context = mFormatContext->streams[i]->codec;
|
||||||
|
#endif
|
||||||
|
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
||||||
|
if ( codec_context->codec_type == AVMEDIA_TYPE_VIDEO )
|
||||||
|
#else
|
||||||
|
if ( codec_context->codec_type == CODEC_TYPE_VIDEO )
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if ( mVideoStreamId == -1 ) {
|
if ( mVideoStreamId == -1 ) {
|
||||||
|
@ -171,9 +177,9 @@ int RemoteCameraRtsp::PrimeCapture() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
||||||
if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO )
|
if ( codec_context->codec_type == AVMEDIA_TYPE_AUDIO )
|
||||||
#else
|
#else
|
||||||
if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO )
|
if ( codec_context->codec_type == CODEC_TYPE_AUDIO )
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if ( mAudioStreamId == -1 ) {
|
if ( mAudioStreamId == -1 ) {
|
||||||
|
@ -190,7 +196,12 @@ int RemoteCameraRtsp::PrimeCapture() {
|
||||||
Debug( 3, "Unable to locate audio stream" );
|
Debug( 3, "Unable to locate audio stream" );
|
||||||
|
|
||||||
// Get a pointer to the codec context for the video stream
|
// Get a pointer to the codec context for the video stream
|
||||||
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
|
mCodecContext = avcodec_alloc_context3(NULL);
|
||||||
|
avcodec_parameters_to_context(mCodecContext, mFormatContext->streams[mVideoStreamId]->codecpar);
|
||||||
|
#else
|
||||||
mCodecContext = mFormatContext->streams[mVideoStreamId]->codec;
|
mCodecContext = mFormatContext->streams[mVideoStreamId]->codec;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Find the decoder for the video stream
|
// Find the decoder for the video stream
|
||||||
mCodec = avcodec_find_decoder( mCodecContext->codec_id );
|
mCodec = avcodec_find_decoder( mCodecContext->codec_id );
|
||||||
|
@ -231,6 +242,14 @@ int RemoteCameraRtsp::PrimeCapture() {
|
||||||
if ( (unsigned int)pSize != imagesize ) {
|
if ( (unsigned int)pSize != imagesize ) {
|
||||||
Fatal("Image size mismatch. Required: %d Available: %d",pSize,imagesize);
|
Fatal("Image size mismatch. Required: %d Available: %d",pSize,imagesize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if HAVE_LIBSWSCALE
|
||||||
|
mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL );
|
||||||
|
if ( mConvertContext == NULL )
|
||||||
|
Fatal( "Unable to create conversion context");
|
||||||
|
#else // HAVE_LIBSWSCALE
|
||||||
|
Fatal( "You must compile ffmpeg with the --enable-swscale option to use RTSP cameras" );
|
||||||
|
#endif // HAVE_LIBSWSCALE
|
||||||
/*
|
/*
|
||||||
#if HAVE_LIBSWSCALE
|
#if HAVE_LIBSWSCALE
|
||||||
if(!sws_isSupportedInput(mCodecContext->pix_fmt)) {
|
if(!sws_isSupportedInput(mCodecContext->pix_fmt)) {
|
||||||
|
@ -259,23 +278,22 @@ int RemoteCameraRtsp::PreCapture() {
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
ZMPacket * RemoteCameraRtsp::Capture( Image &image ) {
|
int RemoteCameraRtsp::Capture( ZMPacket &zm_packet ) {
|
||||||
AVPacket packet;
|
AVPacket packet;
|
||||||
ZMPacket *zmpacket = NULL;
|
|
||||||
uint8_t* directbuffer;
|
uint8_t* directbuffer;
|
||||||
int frameComplete = false;
|
int frameComplete = false;
|
||||||
|
|
||||||
/* Request a writeable buffer of the target image */
|
/* Request a writeable buffer of the target image */
|
||||||
directbuffer = image.WriteBuffer(width, height, colours, subpixelorder);
|
directbuffer = zm_packet.image->WriteBuffer(width, height, colours, subpixelorder);
|
||||||
if ( directbuffer == NULL ) {
|
if ( directbuffer == NULL ) {
|
||||||
Error("Failed requesting writeable buffer for the captured image.");
|
Error("Failed requesting writeable buffer for the captured image.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ( true ) {
|
while ( !frameComplete ) {
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
if ( !rtspThread->isRunning() )
|
if ( !rtspThread->isRunning() )
|
||||||
return (-1);
|
return NULL;
|
||||||
|
|
||||||
if ( rtspThread->getFrame( buffer ) ) {
|
if ( rtspThread->getFrame( buffer ) ) {
|
||||||
Debug( 3, "Read frame %d bytes", buffer.size() );
|
Debug( 3, "Read frame %d bytes", buffer.size() );
|
||||||
|
@ -283,7 +301,7 @@ ZMPacket * RemoteCameraRtsp::Capture( Image &image ) {
|
||||||
Hexdump( 4, buffer.head(), 16 );
|
Hexdump( 4, buffer.head(), 16 );
|
||||||
|
|
||||||
if ( !buffer.size() )
|
if ( !buffer.size() )
|
||||||
return( -1 );
|
return NULL;
|
||||||
|
|
||||||
if ( mCodecContext->codec_id == AV_CODEC_ID_H264 ) {
|
if ( mCodecContext->codec_id == AV_CODEC_ID_H264 ) {
|
||||||
// SPS and PPS frames should be saved and appended to IDR frames
|
// SPS and PPS frames should be saved and appended to IDR frames
|
||||||
|
@ -325,223 +343,29 @@ ZMPacket * RemoteCameraRtsp::Capture( Image &image ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Debug( 2, "Frame: %d - %d/%d", frameCount, len, buffer.size() );
|
Debug( 2, "Frame: %d - %d/%d", frameCount, len, buffer.size() );
|
||||||
//if ( buffer.size() < 400 )
|
|
||||||
//Hexdump( 0, buffer.head(), buffer.size() );
|
|
||||||
|
|
||||||
buffer -= len;
|
buffer -= len;
|
||||||
}
|
}
|
||||||
// At this point, we either have a frame or ran out of buffer. What happens if we run out of buffer?
|
// At this point, we either have a frame or ran out of buffer. What happens if we run out of buffer?
|
||||||
if ( frameComplete ) {
|
if ( frameComplete ) {
|
||||||
|
|
||||||
Debug( 3, "Got frame %d", frameCount );
|
Debug( 3, "Got frame %d", frameCount );
|
||||||
|
|
||||||
avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height );
|
avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height );
|
||||||
|
|
||||||
#if HAVE_LIBSWSCALE
|
#if HAVE_LIBSWSCALE
|
||||||
if ( mConvertContext == NULL ) {
|
if ( mConvertContext == NULL ) {
|
||||||
mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL );
|
|
||||||
|
|
||||||
if ( mConvertContext == NULL )
|
|
||||||
Fatal( "Unable to create conversion context");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( sws_scale( mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mCodecContext->height, mFrame->data, mFrame->linesize ) < 0 )
|
|
||||||
Fatal( "Unable to convert raw format %u to target format %u at frame %d", mCodecContext->pix_fmt, imagePixFormat, frameCount );
|
|
||||||
#else // HAVE_LIBSWSCALE
|
|
||||||
Fatal( "You must compile ffmpeg with the --enable-swscale option to use RTSP cameras" );
|
|
||||||
#endif // HAVE_LIBSWSCALE
|
|
||||||
|
|
||||||
frameCount++;
|
|
||||||
|
|
||||||
zm_packet = new ZMPacket( &packet, mFrame, &image );
|
|
||||||
} /* frame complete */
|
|
||||||
|
|
||||||
|
|
||||||
zm_av_packet_unref( &packet );
|
|
||||||
} /* getFrame() */
|
|
||||||
|
|
||||||
if ( frameComplete ) break;
|
|
||||||
|
|
||||||
} // end while true
|
|
||||||
|
|
||||||
return zm_packet;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Function to handle capture and store
|
|
||||||
|
|
||||||
int RemoteCameraRtsp::CaptureAndRecord(Image &image, timeval recording, char* event_file ) {
|
|
||||||
AVPacket packet;
|
|
||||||
uint8_t* directbuffer;
|
|
||||||
int frameComplete = false;
|
|
||||||
|
|
||||||
while ( true ) {
|
|
||||||
|
|
||||||
// WHY Are we clearing it? Might be something good in it.
|
|
||||||
buffer.clear();
|
|
||||||
|
|
||||||
if ( !rtspThread->isRunning() )
|
|
||||||
return (-1);
|
|
||||||
|
|
||||||
//Video recording
|
|
||||||
if ( recording.tv_sec ) {
|
|
||||||
// The directory we are recording to is no longer tied to the current event.
|
|
||||||
// Need to re-init the videostore with the correct directory and start recording again
|
|
||||||
// Not sure why we are only doing this on keyframe, al
|
|
||||||
if ( videoStore && (strcmp(oldDirectory, event_file)!=0) ) {
|
|
||||||
//don't open new videostore until we're on a key frame..would this require an offset adjustment for the event as a result?...if we store our key frame location with the event will that be enough?
|
|
||||||
Info("Re-starting video storage module");
|
|
||||||
if ( videoStore ) {
|
|
||||||
delete videoStore;
|
|
||||||
videoStore = NULL;
|
|
||||||
}
|
|
||||||
} // end if changed to new event
|
|
||||||
|
|
||||||
if ( ! videoStore ) {
|
|
||||||
//Instantiate the video storage module
|
|
||||||
|
|
||||||
videoStore = new VideoStore((const char *)event_file, "mp4",
|
|
||||||
mFormatContext->streams[mVideoStreamId],
|
|
||||||
mAudioStreamId==-1?NULL:mFormatContext->streams[mAudioStreamId],
|
|
||||||
startTime,
|
|
||||||
this->getMonitor() );
|
|
||||||
strcpy(oldDirectory, event_file);
|
|
||||||
} // end if ! videoStore
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if ( videoStore ) {
|
|
||||||
Info("Deleting videoStore instance");
|
|
||||||
delete videoStore;
|
|
||||||
videoStore = NULL;
|
|
||||||
}
|
|
||||||
} // end if recording or not
|
|
||||||
|
|
||||||
if ( rtspThread->getFrame( buffer ) ) {
|
|
||||||
Debug( 3, "Read frame %d bytes", buffer.size() );
|
|
||||||
Debug( 4, "Address %p", buffer.head() );
|
|
||||||
Hexdump( 4, buffer.head(), 16 );
|
|
||||||
|
|
||||||
if ( !buffer.size() )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
if ( mCodecContext->codec_id == AV_CODEC_ID_H264 ) {
|
|
||||||
// SPS and PPS frames should be saved and appended to IDR frames
|
|
||||||
int nalType = (buffer.head()[3] & 0x1f);
|
|
||||||
|
|
||||||
// SPS
|
|
||||||
if(nalType == 7) {
|
|
||||||
lastSps = buffer;
|
|
||||||
continue;
|
|
||||||
} else if(nalType == 8) {
|
|
||||||
// PPS
|
|
||||||
lastPps = buffer;
|
|
||||||
continue;
|
|
||||||
} else if(nalType == 5) {
|
|
||||||
// IDR
|
|
||||||
buffer += lastSps;
|
|
||||||
buffer += lastPps;
|
|
||||||
}
|
|
||||||
} // end if H264, what about other codecs?
|
|
||||||
|
|
||||||
av_init_packet( &packet );
|
|
||||||
|
|
||||||
// Keep decoding until a complete frame is had.
|
|
||||||
while ( !frameComplete && buffer.size() > 0 ) {
|
|
||||||
packet.data = buffer.head();
|
|
||||||
packet.size = buffer.size();
|
|
||||||
|
|
||||||
// Why are we checking for it being the video stream? Because it might be audio or something else.
|
|
||||||
// Um... we just initialized packet... we can't be testing for what it is yet....
|
|
||||||
if ( packet.stream_index == mVideoStreamId ) {
|
|
||||||
// So this does the decode
|
|
||||||
#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0)
|
|
||||||
int len = avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, &packet );
|
|
||||||
#else
|
|
||||||
int len = avcodec_decode_video( mCodecContext, mRawFrame, &frameComplete, packet.data, packet.size );
|
|
||||||
#endif
|
|
||||||
if ( len < 0 ) {
|
|
||||||
Error( "Error while decoding frame %d", frameCount );
|
|
||||||
Hexdump( Logger::ERROR, buffer.head(), buffer.size()>256?256:buffer.size() );
|
|
||||||
buffer.clear();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Debug( 2, "Frame: %d - %d/%d", frameCount, len, buffer.size() );
|
|
||||||
//if ( buffer.size() < 400 )
|
|
||||||
//Hexdump( 0, buffer.head(), buffer.size() );
|
|
||||||
|
|
||||||
buffer -= len;
|
|
||||||
|
|
||||||
if ( frameComplete ) {
|
|
||||||
|
|
||||||
Debug( 3, "Got frame %d", frameCount );
|
|
||||||
|
|
||||||
/* Request a writeable buffer of the target image */
|
|
||||||
directbuffer = image.WriteBuffer(width, height, colours, subpixelorder);
|
|
||||||
if(directbuffer == NULL) {
|
|
||||||
Error("Failed requesting writeable buffer for the captured image.");
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
|
||||||
av_image_fill_arrays(mFrame->data, mFrame->linesize,
|
|
||||||
directbuffer, imagePixFormat, width, height, 1);
|
|
||||||
#else
|
|
||||||
avpicture_fill( (AVPicture *)mFrame, directbuffer,
|
|
||||||
imagePixFormat, width, height);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // endif frameComplete
|
|
||||||
|
|
||||||
if ( videoStore ) {
|
|
||||||
//Write the packet to our video store
|
|
||||||
int ret = videoStore->writeVideoFramePacket(&packet);//, &lastKeyframePkt);
|
|
||||||
if ( ret < 0 ) {//Less than zero and we skipped a frame
|
|
||||||
// Should not
|
|
||||||
zm_av_packet_unref( &packet );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} // end if videoStore, so we are recording
|
|
||||||
|
|
||||||
#if HAVE_LIBSWSCALE
|
|
||||||
// Why are we re-scaling after writing out the packet?
|
|
||||||
if ( mConvertContext == NULL ) {
|
|
||||||
mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL );
|
|
||||||
|
|
||||||
if ( mConvertContext == NULL )
|
|
||||||
Fatal( "Unable to create conversion context");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( sws_scale( mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mCodecContext->height, mFrame->data, mFrame->linesize ) < 0 )
|
if ( sws_scale( mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mCodecContext->height, mFrame->data, mFrame->linesize ) < 0 )
|
||||||
Fatal( "Unable to convert raw format %u to target format %u at frame %d", mCodecContext->pix_fmt, imagePixFormat, frameCount );
|
Fatal( "Unable to convert raw format %u to target format %u at frame %d", mCodecContext->pix_fmt, imagePixFormat, frameCount );
|
||||||
#else // HAVE_LIBSWSCALE
|
|
||||||
Fatal( "You must compile ffmpeg with the --enable-swscale option to use RTSP cameras" );
|
|
||||||
#endif // HAVE_LIBSWSCALE
|
|
||||||
|
|
||||||
frameCount++;
|
|
||||||
|
|
||||||
} else if ( packet.stream_index == mAudioStreamId ) {
|
|
||||||
Debug( 4, "Got audio packet" );
|
|
||||||
if ( videoStore && record_audio ) {
|
|
||||||
Debug( 4, "Storing Audio packet" );
|
|
||||||
//Write the packet to our video store
|
|
||||||
int ret = videoStore->writeAudioFramePacket( &packet ); //FIXME no relevance of last key frame
|
|
||||||
if ( ret < 0 ) { //Less than zero and we skipped a frame
|
|
||||||
zm_av_packet_unref( &packet );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} // end if video or audio packet
|
#endif
|
||||||
|
|
||||||
|
frameCount++;
|
||||||
|
} /* frame complete */
|
||||||
|
zm_packet.set_packet( &packet );
|
||||||
zm_av_packet_unref( &packet );
|
zm_av_packet_unref( &packet );
|
||||||
} // end while ! framecomplete and buffer.size()
|
} /* getFrame() */
|
||||||
if(frameComplete)
|
} // end while true
|
||||||
return (0);
|
|
||||||
} /* getFrame() */
|
|
||||||
|
|
||||||
} // end while true
|
return 1;
|
||||||
|
} // end int RemoteCameraRtsp::Capture(ZMPacket &packet)
|
||||||
// can never get here.
|
|
||||||
return (0) ;
|
|
||||||
} // int RemoteCameraRtsp::CaptureAndRecord( Image &image, bool recording, char* event_file )
|
|
||||||
|
|
||||||
int RemoteCameraRtsp::PostCapture() {
|
int RemoteCameraRtsp::PostCapture() {
|
||||||
return( 0 );
|
return( 0 );
|
||||||
|
|
|
@ -34,8 +34,7 @@
|
||||||
// accessed over a network connection using rtsp protocol
|
// accessed over a network connection using rtsp protocol
|
||||||
// (Real Time Streaming Protocol)
|
// (Real Time Streaming Protocol)
|
||||||
//
|
//
|
||||||
class RemoteCameraRtsp : public RemoteCamera
|
class RemoteCameraRtsp : public RemoteCamera {
|
||||||
{
|
|
||||||
protected:
|
protected:
|
||||||
struct sockaddr_in rtsp_sa;
|
struct sockaddr_in rtsp_sa;
|
||||||
struct sockaddr_in rtcp_sa;
|
struct sockaddr_in rtcp_sa;
|
||||||
|
@ -84,7 +83,7 @@ public:
|
||||||
|
|
||||||
int PrimeCapture();
|
int PrimeCapture();
|
||||||
int PreCapture();
|
int PreCapture();
|
||||||
ZMPacket * Capture( Image &image );
|
int Capture( ZMPacket &p );
|
||||||
int PostCapture();
|
int PostCapture();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -379,21 +379,31 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const
|
||||||
stream->id = i;
|
stream->id = i;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
AVCodecContext *codec_context = NULL;
|
||||||
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
|
codec_context = avcodec_alloc_context3(NULL);
|
||||||
|
avcodec_parameters_to_context(codec_context, stream->codecpar);
|
||||||
|
#else
|
||||||
|
codec_context = stream->codec;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Debug( 1, "Looking for codec for %s payload type %d / %s", mediaDesc->getType().c_str(), mediaDesc->getPayloadType(), mediaDesc->getPayloadDesc().c_str() );
|
Debug( 1, "Looking for codec for %s payload type %d / %s", mediaDesc->getType().c_str(), mediaDesc->getPayloadType(), mediaDesc->getPayloadDesc().c_str() );
|
||||||
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
||||||
if ( mediaDesc->getType() == "video" )
|
if ( mediaDesc->getType() == "video" )
|
||||||
stream->codec->codec_type = AVMEDIA_TYPE_VIDEO;
|
codec_context->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||||
else if ( mediaDesc->getType() == "audio" )
|
else if ( mediaDesc->getType() == "audio" )
|
||||||
stream->codec->codec_type = AVMEDIA_TYPE_AUDIO;
|
codec_context->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||||
else if ( mediaDesc->getType() == "application" )
|
else if ( mediaDesc->getType() == "application" )
|
||||||
stream->codec->codec_type = AVMEDIA_TYPE_DATA;
|
codec_context->codec_type = AVMEDIA_TYPE_DATA;
|
||||||
#else
|
#else
|
||||||
if ( mediaDesc->getType() == "video" )
|
if ( mediaDesc->getType() == "video" )
|
||||||
stream->codec->codec_type = CODEC_TYPE_VIDEO;
|
codec_context->codec_type = CODEC_TYPE_VIDEO;
|
||||||
else if ( mediaDesc->getType() == "audio" )
|
else if ( mediaDesc->getType() == "audio" )
|
||||||
stream->codec->codec_type = CODEC_TYPE_AUDIO;
|
codec_context->codec_type = CODEC_TYPE_AUDIO;
|
||||||
else if ( mediaDesc->getType() == "application" )
|
else if ( mediaDesc->getType() == "application" )
|
||||||
stream->codec->codec_type = CODEC_TYPE_DATA;
|
codec_context->codec_type = CODEC_TYPE_DATA;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103)
|
#if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103)
|
||||||
|
@ -410,31 +420,27 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const
|
||||||
#if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103)
|
#if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103)
|
||||||
codec_name = std::string( smStaticPayloads[i].payloadName );
|
codec_name = std::string( smStaticPayloads[i].payloadName );
|
||||||
#else
|
#else
|
||||||
strncpy( stream->codec->codec_name, smStaticPayloads[i].payloadName, sizeof(stream->codec->codec_name) );;
|
strncpy( codec_context->codec_name, smStaticPayloads[i].payloadName, sizeof(codec_context->codec_name) );;
|
||||||
#endif
|
#endif
|
||||||
stream->codec->codec_type = smStaticPayloads[i].codecType;
|
codec_context->codec_type = smStaticPayloads[i].codecType;
|
||||||
stream->codec->codec_id = smStaticPayloads[i].codecId;
|
codec_context->codec_id = smStaticPayloads[i].codecId;
|
||||||
stream->codec->sample_rate = smStaticPayloads[i].clockRate;
|
codec_context->sample_rate = smStaticPayloads[i].clockRate;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// Look in dynamic table
|
// Look in dynamic table
|
||||||
for ( unsigned int i = 0; i < (sizeof(smDynamicPayloads)/sizeof(*smDynamicPayloads)); i++ )
|
for ( unsigned int i = 0; i < (sizeof(smDynamicPayloads)/sizeof(*smDynamicPayloads)); i++ ) {
|
||||||
{
|
if ( smDynamicPayloads[i].payloadName == mediaDesc->getPayloadDesc() ) {
|
||||||
if ( smDynamicPayloads[i].payloadName == mediaDesc->getPayloadDesc() )
|
|
||||||
{
|
|
||||||
Debug( 1, "Got dynamic payload type %d, %s", mediaDesc->getPayloadType(), smDynamicPayloads[i].payloadName );
|
Debug( 1, "Got dynamic payload type %d, %s", mediaDesc->getPayloadType(), smDynamicPayloads[i].payloadName );
|
||||||
#if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103)
|
#if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103)
|
||||||
codec_name = std::string( smStaticPayloads[i].payloadName );
|
codec_name = std::string( smStaticPayloads[i].payloadName );
|
||||||
#else
|
#else
|
||||||
strncpy( stream->codec->codec_name, smDynamicPayloads[i].payloadName, sizeof(stream->codec->codec_name) );;
|
strncpy( codec_context->codec_name, smDynamicPayloads[i].payloadName, sizeof(codec_context->codec_name) );;
|
||||||
#endif
|
#endif
|
||||||
stream->codec->codec_type = smDynamicPayloads[i].codecType;
|
codec_context->codec_type = smDynamicPayloads[i].codecType;
|
||||||
stream->codec->codec_id = smDynamicPayloads[i].codecId;
|
codec_context->codec_id = smDynamicPayloads[i].codecId;
|
||||||
stream->codec->sample_rate = mediaDesc->getClock();
|
codec_context->sample_rate = mediaDesc->getClock();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -450,14 +456,13 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const
|
||||||
//return( 0 );
|
//return( 0 );
|
||||||
}
|
}
|
||||||
if ( mediaDesc->getWidth() )
|
if ( mediaDesc->getWidth() )
|
||||||
stream->codec->width = mediaDesc->getWidth();
|
codec_context->width = mediaDesc->getWidth();
|
||||||
if ( mediaDesc->getHeight() )
|
if ( mediaDesc->getHeight() )
|
||||||
stream->codec->height = mediaDesc->getHeight();
|
codec_context->height = mediaDesc->getHeight();
|
||||||
if ( stream->codec->codec_id == AV_CODEC_ID_H264 && mediaDesc->getSprops().size())
|
if ( codec_context->codec_id == AV_CODEC_ID_H264 && mediaDesc->getSprops().size()) {
|
||||||
{
|
|
||||||
uint8_t start_sequence[]= { 0, 0, 1 };
|
uint8_t start_sequence[]= { 0, 0, 1 };
|
||||||
stream->codec->extradata_size= 0;
|
codec_context->extradata_size= 0;
|
||||||
stream->codec->extradata= NULL;
|
codec_context->extradata= NULL;
|
||||||
char pvalue[1024], *value = pvalue;
|
char pvalue[1024], *value = pvalue;
|
||||||
|
|
||||||
strcpy(pvalue, mediaDesc->getSprops().c_str());
|
strcpy(pvalue, mediaDesc->getSprops().c_str());
|
||||||
|
@ -482,22 +487,33 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const
|
||||||
if (packet_size) {
|
if (packet_size) {
|
||||||
uint8_t *dest =
|
uint8_t *dest =
|
||||||
(uint8_t *)av_malloc(packet_size + sizeof(start_sequence) +
|
(uint8_t *)av_malloc(packet_size + sizeof(start_sequence) +
|
||||||
stream->codec->extradata_size +
|
codec_context->extradata_size +
|
||||||
FF_INPUT_BUFFER_PADDING_SIZE);
|
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
|
||||||
|
AV_INPUT_BUFFER_PADDING_SIZE
|
||||||
|
#else
|
||||||
|
FF_INPUT_BUFFER_PADDING_SIZE
|
||||||
|
#endif
|
||||||
|
);
|
||||||
if(dest) {
|
if(dest) {
|
||||||
if(stream->codec->extradata_size) {
|
if(codec_context->extradata_size) {
|
||||||
// av_realloc?
|
// av_realloc?
|
||||||
memcpy(dest, stream->codec->extradata, stream->codec->extradata_size);
|
memcpy(dest, codec_context->extradata, codec_context->extradata_size);
|
||||||
av_free(stream->codec->extradata);
|
av_free(codec_context->extradata);
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(dest+stream->codec->extradata_size, start_sequence, sizeof(start_sequence));
|
memcpy(dest+codec_context->extradata_size, start_sequence, sizeof(start_sequence));
|
||||||
memcpy(dest+stream->codec->extradata_size+sizeof(start_sequence), decoded_packet, packet_size);
|
memcpy(dest+codec_context->extradata_size+sizeof(start_sequence), decoded_packet, packet_size);
|
||||||
memset(dest+stream->codec->extradata_size+sizeof(start_sequence)+
|
memset(dest+codec_context->extradata_size+sizeof(start_sequence)+
|
||||||
packet_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
|
packet_size, 0,
|
||||||
|
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
|
||||||
|
AV_INPUT_BUFFER_PADDING_SIZE
|
||||||
|
#else
|
||||||
|
FF_INPUT_BUFFER_PADDING_SIZE
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
stream->codec->extradata= dest;
|
codec_context->extradata= dest;
|
||||||
stream->codec->extradata_size+= sizeof(start_sequence)+packet_size;
|
codec_context->extradata_size+= sizeof(start_sequence)+packet_size;
|
||||||
// } else {
|
// } else {
|
||||||
// av_log(codec, AV_LOG_ERROR, "Unable to allocate memory for extradata!");
|
// av_log(codec, AV_LOG_ERROR, "Unable to allocate memory for extradata!");
|
||||||
// return AVERROR(ENOMEM);
|
// return AVERROR(ENOMEM);
|
||||||
|
|
18
src/zm_sdp.h
18
src/zm_sdp.h
|
@ -31,13 +31,11 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class SessionDescriptor
|
class SessionDescriptor {
|
||||||
{
|
|
||||||
protected:
|
protected:
|
||||||
enum { PAYLOAD_TYPE_DYNAMIC=96 };
|
enum { PAYLOAD_TYPE_DYNAMIC=96 };
|
||||||
|
|
||||||
struct StaticPayloadDesc
|
struct StaticPayloadDesc {
|
||||||
{
|
|
||||||
int payloadType;
|
int payloadType;
|
||||||
const char payloadName[6];
|
const char payloadName[6];
|
||||||
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
||||||
|
@ -50,8 +48,7 @@ protected:
|
||||||
int autoChannels;
|
int autoChannels;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DynamicPayloadDesc
|
struct DynamicPayloadDesc {
|
||||||
{
|
|
||||||
const char payloadName[32];
|
const char payloadName[32];
|
||||||
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
||||||
AVMediaType codecType;
|
AVMediaType codecType;
|
||||||
|
@ -65,8 +62,7 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class ConnInfo
|
class ConnInfo {
|
||||||
{
|
|
||||||
protected:
|
protected:
|
||||||
std::string mNetworkType;
|
std::string mNetworkType;
|
||||||
std::string mAddressType;
|
std::string mAddressType;
|
||||||
|
@ -78,8 +74,7 @@ public:
|
||||||
ConnInfo( const std::string &connInfo );
|
ConnInfo( const std::string &connInfo );
|
||||||
};
|
};
|
||||||
|
|
||||||
class BandInfo
|
class BandInfo {
|
||||||
{
|
|
||||||
protected:
|
protected:
|
||||||
std::string mType;
|
std::string mType;
|
||||||
int mValue;
|
int mValue;
|
||||||
|
@ -88,8 +83,7 @@ public:
|
||||||
BandInfo( const std::string &bandInfo );
|
BandInfo( const std::string &bandInfo );
|
||||||
};
|
};
|
||||||
|
|
||||||
class MediaDescriptor
|
class MediaDescriptor {
|
||||||
{
|
|
||||||
protected:
|
protected:
|
||||||
std::string mType;
|
std::string mType;
|
||||||
int mPort;
|
int mPort;
|
||||||
|
|
|
@ -311,7 +311,7 @@ void StreamBase::openComms() {
|
||||||
strncpy( rem_addr.sun_path, rem_sock_path, sizeof(rem_addr.sun_path) );
|
strncpy( rem_addr.sun_path, rem_sock_path, sizeof(rem_addr.sun_path) );
|
||||||
rem_addr.sun_family = AF_UNIX;
|
rem_addr.sun_family = AF_UNIX;
|
||||||
} // end if connKey > 0
|
} // end if connKey > 0
|
||||||
Debug(3, "comms open" );
|
Debug(2, "comms open" );
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamBase::closeComms() {
|
void StreamBase::closeComms() {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -12,17 +12,24 @@ extern "C" {
|
||||||
|
|
||||||
#if HAVE_LIBAVCODEC
|
#if HAVE_LIBAVCODEC
|
||||||
|
|
||||||
|
class VideoStore;
|
||||||
#include "zm_monitor.h"
|
#include "zm_monitor.h"
|
||||||
#include "zm_packet.h"
|
#include "zm_packet.h"
|
||||||
|
#include "zm_packetqueue.h"
|
||||||
|
|
||||||
class VideoStore {
|
class VideoStore {
|
||||||
private:
|
private:
|
||||||
unsigned int packets_written;
|
unsigned int packets_written;
|
||||||
|
unsigned int frame_count;
|
||||||
|
|
||||||
AVOutputFormat *out_format;
|
AVOutputFormat *out_format;
|
||||||
AVFormatContext *oc;
|
AVFormatContext *oc;
|
||||||
AVStream *video_out_stream;
|
AVStream *video_out_stream;
|
||||||
AVStream *audio_out_stream;
|
AVStream *audio_out_stream;
|
||||||
|
int video_in_stream_index;
|
||||||
|
int audio_in_stream_index;
|
||||||
|
|
||||||
|
AVCodec *video_out_codec;
|
||||||
AVCodecContext *video_out_ctx;
|
AVCodecContext *video_out_ctx;
|
||||||
|
|
||||||
AVStream *video_in_stream;
|
AVStream *video_in_stream;
|
||||||
|
@ -31,6 +38,7 @@ private:
|
||||||
// Move this into the object so that we aren't constantly allocating/deallocating it on the stack
|
// Move this into the object so that we aren't constantly allocating/deallocating it on the stack
|
||||||
AVPacket opkt;
|
AVPacket opkt;
|
||||||
// we are transcoding
|
// we are transcoding
|
||||||
|
AVFrame *video_in_frame;
|
||||||
AVFrame *in_frame;
|
AVFrame *in_frame;
|
||||||
AVFrame *out_frame;
|
AVFrame *out_frame;
|
||||||
|
|
||||||
|
@ -38,6 +46,8 @@ private:
|
||||||
AVCodecContext *audio_in_ctx;
|
AVCodecContext *audio_in_ctx;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
SWScale swscale;
|
||||||
|
|
||||||
// The following are used when encoding the audio stream to AAC
|
// The following are used when encoding the audio stream to AAC
|
||||||
AVCodec *audio_out_codec;
|
AVCodec *audio_out_codec;
|
||||||
AVCodecContext *audio_out_ctx;
|
AVCodecContext *audio_out_ctx;
|
||||||
|
@ -58,12 +68,14 @@ AVAudioResampleContext* resample_ctx;
|
||||||
// These are for in
|
// These are for in
|
||||||
int64_t video_last_pts;
|
int64_t video_last_pts;
|
||||||
int64_t video_last_dts;
|
int64_t video_last_dts;
|
||||||
|
int64_t video_last_duration;
|
||||||
int64_t audio_last_pts;
|
int64_t audio_last_pts;
|
||||||
int64_t audio_last_dts;
|
int64_t audio_last_dts;
|
||||||
|
|
||||||
// These are for out, should start at zero. We assume they do not wrap because we just aren't going to save files that big.
|
// These are for out, should start at zero. We assume they do not wrap because we just aren't going to save files that big.
|
||||||
int64_t video_next_pts;
|
int64_t video_next_pts;
|
||||||
int64_t video_next_dts;
|
int64_t video_next_dts;
|
||||||
|
;
|
||||||
int64_t audio_next_pts;
|
int64_t audio_next_pts;
|
||||||
int64_t audio_next_dts;
|
int64_t audio_next_dts;
|
||||||
|
|
||||||
|
@ -77,14 +89,19 @@ public:
|
||||||
const char *format_in,
|
const char *format_in,
|
||||||
AVStream *video_in_stream,
|
AVStream *video_in_stream,
|
||||||
AVStream *audio_in_stream,
|
AVStream *audio_in_stream,
|
||||||
Monitor * p_monitor);
|
int64_t starttime,
|
||||||
bool open();
|
Monitor * p_monitor
|
||||||
|
);
|
||||||
~VideoStore();
|
~VideoStore();
|
||||||
|
bool open();
|
||||||
|
|
||||||
int writeVideoFramePacket( AVPacket *pkt );
|
void write_video_packet( AVPacket &pkt );
|
||||||
int writeAudioFramePacket( AVPacket *pkt );
|
void write_audio_packet( AVPacket &pkt );
|
||||||
|
int writeVideoFramePacket( ZMPacket *pkt );
|
||||||
|
int writeAudioFramePacket( ZMPacket *pkt );
|
||||||
int writePacket( ZMPacket *pkt );
|
int writePacket( ZMPacket *pkt );
|
||||||
void dumpPacket( AVPacket *pkt );
|
void dumpPacket( AVPacket *pkt );
|
||||||
|
int write_packets( zm_packetqueue &queue );
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //havelibav
|
#endif //havelibav
|
||||||
|
|
|
@ -256,14 +256,14 @@ int main(int argc, char *argv[]) {
|
||||||
alarm_capture_delays[i] = monitors[i]->GetAlarmCaptureDelay();
|
alarm_capture_delays[i] = monitors[i]->GetAlarmCaptureDelay();
|
||||||
|
|
||||||
Monitor::Function function = monitors[0]->GetFunction();
|
Monitor::Function function = monitors[0]->GetFunction();
|
||||||
if ( function == Monitor::MODECT || function == Monitor::MOCORD ) {
|
if ( function == Monitor::MODECT || function == Monitor::MOCORD || function == Monitor::RECORD) {
|
||||||
Debug(1, "Starting an analysis thread for monitor (%d)", monitors[i]->Id());
|
Debug(1, "Starting an analysis thread for monitor (%d)", monitors[i]->Id());
|
||||||
analysis_threads[i] = new AnalysisThread(monitors[i]);
|
analysis_threads[i] = new AnalysisThread(monitors[i]);
|
||||||
analysis_threads[i]->start();
|
analysis_threads[i]->start();
|
||||||
} else {
|
} else {
|
||||||
analysis_threads[i] = NULL;
|
analysis_threads[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
} // end foreach monitor
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
|
|
|
@ -0,0 +1,209 @@
|
||||||
|
<?php
|
||||||
|
function unparse_url($parsed_url, $substitutions = array() ) {
|
||||||
|
$fields = array('scheme','host','port','user','pass','path','query','fragment');
|
||||||
|
|
||||||
|
foreach ( $fields as $field ) {
|
||||||
|
if ( isset( $substitutions[$field] ) ) {
|
||||||
|
$parsed_url[$field] = $substitutions[$field];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
|
||||||
|
$host = isset($parsed_url['host']) ? $parsed_url['host'] : '';
|
||||||
|
$port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
|
||||||
|
$user = isset($parsed_url['user']) ? $parsed_url['user'] : '';
|
||||||
|
$pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : '';
|
||||||
|
$pass = ($user || $pass) ? "$pass@" : '';
|
||||||
|
$path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
|
||||||
|
$query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
|
||||||
|
$fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
|
||||||
|
return "$scheme$user$pass$host$port$path$query$fragment";
|
||||||
|
}
|
||||||
|
|
||||||
|
$defaultMonitor = new Monitor();
|
||||||
|
$defaultMonitor->set(array(
|
||||||
|
'StorageId' => 1,
|
||||||
|
'ServerId' => 'auto',
|
||||||
|
'Function' => 'Record',
|
||||||
|
'Type' => 'Ffmpeg',
|
||||||
|
'Enabled' => '1',
|
||||||
|
'Colour' => '4', // 32bit
|
||||||
|
'PreEventCount' => 0,
|
||||||
|
) );
|
||||||
|
|
||||||
|
function probe( &$url_bits ) {
|
||||||
|
global $defaultMonitor;
|
||||||
|
$available_streams = array();
|
||||||
|
if ( ! isset($url_bits['port']) ) {
|
||||||
|
// No port given, do a port scan
|
||||||
|
foreach ( range( 2000, 2007 ) as $port ) {
|
||||||
|
$socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );
|
||||||
|
socket_set_option( $socket,
|
||||||
|
SOL_SOCKET, // socket level
|
||||||
|
SO_SNDTIMEO, // timeout option
|
||||||
|
array(
|
||||||
|
"sec"=>0, // Timeout in seconds
|
||||||
|
"usec"=>500 // I assume timeout in microseconds
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$new_stream = null;
|
||||||
|
Info("Testing connection to " . $url_bits['host'].':'.$port);
|
||||||
|
if ( socket_connect( $socket, $url_bits['host'], $port ) ) {
|
||||||
|
$new_stream = $url_bits; // make a copy
|
||||||
|
$new_stream['port'] = $port;
|
||||||
|
} else {
|
||||||
|
socket_close($socket);
|
||||||
|
Info("No connection to ".$url_bits['host'] . " on port $port");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( $new_stream ) {
|
||||||
|
if ( ! isset($new_stream['scheme'] ) )
|
||||||
|
$new_stream['scheme'] = 'http';
|
||||||
|
$url = unparse_url($new_stream, array('path'=>'/', 'query'=>'action=snapshot'));
|
||||||
|
list($width, $height, $type, $attr) = getimagesize( $url );
|
||||||
|
Info("Got $width x $height from $url");
|
||||||
|
$new_stream['Width'] = $width;
|
||||||
|
$new_stream['Height'] = $height;
|
||||||
|
|
||||||
|
//try {
|
||||||
|
//if ( $response = do_request( 'GET', $url ) ) {
|
||||||
|
//$new_stream['path'] = '/';
|
||||||
|
//$new_stream['query'] = '?action=stream';
|
||||||
|
//$image = imagecreatefromstring($response);
|
||||||
|
////$size = getimagesize( $image );
|
||||||
|
//
|
||||||
|
//} else {
|
||||||
|
//Info("No response from $url");
|
||||||
|
//}
|
||||||
|
//} catch ( EXception $e ) {
|
||||||
|
//Info("No response from $url");
|
||||||
|
//}
|
||||||
|
$available_streams[] = $new_stream;
|
||||||
|
} // end if new_Stream
|
||||||
|
} // end foreach port to scan
|
||||||
|
} else {
|
||||||
|
// A port was specified, so don't need to port scan.
|
||||||
|
$available_streams[] = $url_bits;
|
||||||
|
}
|
||||||
|
foreach ( $available_streams as &$stream ) {
|
||||||
|
# check for existence in db.
|
||||||
|
$stream['url'] = unparse_url( $stream, array( 'path'=>'/','query'=>'action=stream' ) );
|
||||||
|
$monitors = Monitor::find_all( array( 'Path'=>$stream['url'] ) );
|
||||||
|
if ( count($monitors ) ) {
|
||||||
|
$stream['Monitor'] = $monitors[0];
|
||||||
|
if ( isset( $stream['Width'] ) and ( $stream['Monitor']->Width() != $stream['Width'] ) ) {
|
||||||
|
$stream['Warning'] .= 'Monitor width ('.$stream['Monitor']->Width().') and stream width ('.$stream['Width'].") do not match!\n";
|
||||||
|
}
|
||||||
|
if ( isset( $stream['Height'] ) and ( $stream['Monitor']->Height() != $stream['Height'] ) ) {
|
||||||
|
$stream['Warning'] .= 'Monitor height ('.$stream['Monitor']->Height().') and stream width ('.$stream['Height'].") do not match!\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$stream['Monitor'] = $defaultMonitor;
|
||||||
|
if ( isset($stream['Width']) ) {
|
||||||
|
$stream['Monitor']->Width( $stream['Width'] );
|
||||||
|
$stream['Monitor']->Height( $stream['Height'] );
|
||||||
|
}
|
||||||
|
} // Monitor found or not
|
||||||
|
} // end foreach Stream
|
||||||
|
|
||||||
|
#$macCommandString = 'arp ' . $url_bits['host'] . " | awk 'BEGIN{ i=1; } { i++; if(i==3) print $3 }'";
|
||||||
|
#$mac = exec($macCommandString);
|
||||||
|
#Info("Mac $mac");
|
||||||
|
return $available_streams;
|
||||||
|
} // end function probe
|
||||||
|
|
||||||
|
if ( canEdit( 'Monitors' ) ) {
|
||||||
|
switch ( $_REQUEST['action'] ) {
|
||||||
|
case 'probe' :
|
||||||
|
{
|
||||||
|
$available_streams = array();
|
||||||
|
$url_bits = null;
|
||||||
|
if ( preg_match('/(\d+)\.(\d+)\.(\d+)\.(\d+)/', $_REQUEST['url'] ) ) {
|
||||||
|
$url_bits = array( 'host'=>$_REQUEST['url'] );
|
||||||
|
} else {
|
||||||
|
$url_bits = parse_url( $_REQUEST['url'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( 0 ) {
|
||||||
|
// Shortcut test
|
||||||
|
$monitors = Monitor::find_all( array( 'Path'=>$_REQUEST['url'] ) );
|
||||||
|
if ( count( $monitors ) ) {
|
||||||
|
Info("Monitor found for " . $_REQUEST['url']);
|
||||||
|
$url_bits['url'] = $_REQUEST['url'];
|
||||||
|
$url_bits['Monitor'] = $monitors[0];
|
||||||
|
$available_stream[] = $url_bits;
|
||||||
|
ajaxResponse( array ( 'Streams'=>$available_streams) );
|
||||||
|
return;
|
||||||
|
} # end url already has a monitor
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! $url_bits ) {
|
||||||
|
ajaxError("The given URL was too malformed to parse.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$available_streams = probe( $url_bits );
|
||||||
|
|
||||||
|
ajaxResponse( array('Streams'=>$available_streams) );
|
||||||
|
return;
|
||||||
|
} // end case url_probe
|
||||||
|
case 'import':
|
||||||
|
{
|
||||||
|
|
||||||
|
$file = $_FILES['import_file'];
|
||||||
|
|
||||||
|
if ($file["error"] > 0) {
|
||||||
|
ajaxError($file["error"]);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
$filename = $file["name"];
|
||||||
|
|
||||||
|
$available_streams = array();
|
||||||
|
$row = 1;
|
||||||
|
if (($handle = fopen($file['tmp_name'], 'r')) !== FALSE) {
|
||||||
|
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
|
||||||
|
$name = $data[0];
|
||||||
|
$url = $data[1];
|
||||||
|
$group = $data[2];
|
||||||
|
Info("Have the following line data $name $url $group");
|
||||||
|
|
||||||
|
$url_bits = null;
|
||||||
|
if ( preg_match('/(\d+)\.(\d+)\.(\d+)\.(\d+)/', $url) ) {
|
||||||
|
$url_bits = array( 'host'=>$url, 'scheme'=>'http' );
|
||||||
|
} else {
|
||||||
|
$url_bits = parse_url( $url );
|
||||||
|
}
|
||||||
|
if ( ! $url_bits ) {
|
||||||
|
Info("Bad url, skipping line $name $url $group");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$available_streams += probe( $url_bits );
|
||||||
|
|
||||||
|
//$url_bits['url'] = unparse_url( $url_bits );
|
||||||
|
//$url_bits['Monitor'] = $defaultMonitor;
|
||||||
|
//$url_bits['Monitor']->Name( $name );
|
||||||
|
//$url_bits['Monitor']->merge( $_POST['newMonitor'] );
|
||||||
|
//$available_streams[] = $url_bits;
|
||||||
|
|
||||||
|
} // end while rows
|
||||||
|
fclose($handle);
|
||||||
|
ajaxResponse( array('Streams'=>$available_streams) );
|
||||||
|
} else {
|
||||||
|
ajaxError("Uploaded file does not exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} // end case import
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
Warning("unknown action " . $_REQUEST['action'] );
|
||||||
|
} // end ddcase default
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Warning("Cannot edit monitors" );
|
||||||
|
}
|
||||||
|
|
||||||
|
ajaxError( 'Unrecognised action or insufficient permissions' );
|
||||||
|
|
||||||
|
?>
|
|
@ -1,170 +1,170 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
$statusData = array(
|
$statusData = array(
|
||||||
"system" => array(
|
'system' => array(
|
||||||
"permission" => "System",
|
'permission' => 'System',
|
||||||
"table" => "Monitors",
|
'table' => 'Monitors',
|
||||||
"limit" => 1,
|
'limit' => 1,
|
||||||
"elements" => array(
|
'elements' => array(
|
||||||
"MonitorCount" => array( "sql" => "count(*)" ),
|
'MonitorCount' => array( 'sql' => "count(*)" ),
|
||||||
"ActiveMonitorCount" => array( "sql" => "count(if(Function != 'None',1,NULL))" ),
|
'ActiveMonitorCount' => array( 'sql' => "count(if(Function != 'None',1,NULL))" ),
|
||||||
"State" => array( "func" => "daemonCheck()?".translate('Running').":".translate('Stopped') ),
|
'State' => array( 'func' => "daemonCheck()?".translate('Running').":".translate('Stopped') ),
|
||||||
"Load" => array( "func" => "getLoad()" ),
|
'Load' => array( 'func' => "getLoad()" ),
|
||||||
"Disk" => array( "func" => "getDiskPercent()" ),
|
'Disk' => array( 'func' => "getDiskPercent()" ),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
"monitor" => array(
|
'monitor' => array(
|
||||||
"permission" => "Monitors",
|
'permission' => 'Monitors',
|
||||||
"table" => "Monitors",
|
'table' => 'Monitors',
|
||||||
"limit" => 1,
|
'limit' => 1,
|
||||||
"selector" => "Monitors.Id",
|
'selector' => "Monitors.Id",
|
||||||
"elements" => array(
|
'elements' => array(
|
||||||
"Id" => array( "sql" => "Monitors.Id" ),
|
'Id' => array( 'sql' => "Monitors.Id" ),
|
||||||
"Name" => array( "sql" => "Monitors.Name" ),
|
'Name' => array( 'sql' => "Monitors.Name" ),
|
||||||
"Type" => true,
|
'Type' => true,
|
||||||
"Function" => true,
|
'Function' => true,
|
||||||
"Enabled" => true,
|
'Enabled' => true,
|
||||||
"LinkedMonitors" => true,
|
'LinkedMonitors' => true,
|
||||||
"Triggers" => true,
|
'Triggers' => true,
|
||||||
"Device" => true,
|
'Device' => true,
|
||||||
"Channel" => true,
|
'Channel' => true,
|
||||||
"Format" => true,
|
'Format' => true,
|
||||||
"Host" => true,
|
'Host' => true,
|
||||||
"Port" => true,
|
'Port' => true,
|
||||||
"Path" => true,
|
'Path' => true,
|
||||||
"Width" => array( "sql" => "Monitors.Width" ),
|
'Width' => array( 'sql' => "Monitors.Width" ),
|
||||||
"Height" => array( "sql" => "Monitors.Height" ),
|
'Height' => array( 'sql' => "Monitors.Height" ),
|
||||||
"Palette" => true,
|
'Palette' => true,
|
||||||
"Orientation" => true,
|
'Orientation' => true,
|
||||||
"Brightness" => true,
|
'Brightness' => true,
|
||||||
"Contrast" => true,
|
'Contrast' => true,
|
||||||
"Hue" => true,
|
'Hue' => true,
|
||||||
"Colour" => true,
|
'Colour' => true,
|
||||||
"EventPrefix" => true,
|
'EventPrefix' => true,
|
||||||
"LabelFormat" => true,
|
'LabelFormat' => true,
|
||||||
"LabelX" => true,
|
'LabelX' => true,
|
||||||
"LabelY" => true,
|
'LabelY' => true,
|
||||||
"LabelSize" => true,
|
'LabelSize' => true,
|
||||||
"ImageBufferCount" => true,
|
'ImageBufferCount' => true,
|
||||||
"WarmupCount" => true,
|
'WarmupCount' => true,
|
||||||
"PreEventCount" => true,
|
'PreEventCount' => true,
|
||||||
"PostEventCount" => true,
|
'PostEventCount' => true,
|
||||||
"AlarmFrameCount" => true,
|
'AlarmFrameCount' => true,
|
||||||
"SectionLength" => true,
|
'SectionLength' => true,
|
||||||
"FrameSkip" => true,
|
'FrameSkip' => true,
|
||||||
"MotionFrameSkip" => true,
|
'MotionFrameSkip' => true,
|
||||||
"MaxFPS" => true,
|
'MaxFPS' => true,
|
||||||
"AlarmMaxFPS" => true,
|
'AlarmMaxFPS' => true,
|
||||||
"FPSReportInterval" => true,
|
'FPSReportInterval' => true,
|
||||||
"RefBlendPerc" => true,
|
'RefBlendPerc' => true,
|
||||||
"Controllable" => true,
|
'Controllable' => true,
|
||||||
"ControlId" => true,
|
'ControlId' => true,
|
||||||
"ControlDevice" => true,
|
'ControlDevice' => true,
|
||||||
"ControlAddress" => true,
|
'ControlAddress' => true,
|
||||||
"AutoStopTimeout" => true,
|
'AutoStopTimeout' => true,
|
||||||
"TrackMotion" => true,
|
'TrackMotion' => true,
|
||||||
"TrackDelay" => true,
|
'TrackDelay' => true,
|
||||||
"ReturnLocation" => true,
|
'ReturnLocation' => true,
|
||||||
"ReturnDelay" => true,
|
'ReturnDelay' => true,
|
||||||
"DefaultView" => true,
|
'DefaultView' => true,
|
||||||
"DefaultRate" => true,
|
'DefaultRate' => true,
|
||||||
"DefaultScale" => true,
|
'DefaultScale' => true,
|
||||||
"WebColour" => true,
|
'WebColour' => true,
|
||||||
"Sequence" => true,
|
'Sequence' => true,
|
||||||
"MinEventId" => array( "sql" => "(SELECT min(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id" ),
|
'MinEventId' => array( 'sql' => "(SELECT min(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id" ),
|
||||||
"MaxEventId" => array( "sql" => "(SELECT max(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id" ),
|
'MaxEventId' => array( 'sql' => "(SELECT max(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id" ),
|
||||||
"TotalEvents" => array( "sql" => "(SELECT count(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id" ),
|
'TotalEvents' => array( 'sql' => "(SELECT count(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id" ),
|
||||||
"Status" => array( "zmu" => "-m ".escapeshellarg($_REQUEST['id'][0])." -s" ),
|
'Status' => array( 'zmu' => "-m ".escapeshellarg($_REQUEST['id'][0])." -s" ),
|
||||||
"FrameRate" => array( "zmu" => "-m ".escapeshellarg($_REQUEST['id'][0])." -f" ),
|
'FrameRate' => array( 'zmu' => "-m ".escapeshellarg($_REQUEST['id'][0])." -f" ),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
"events" => array(
|
'events' => array(
|
||||||
"permission" => "Events",
|
'permission' => 'Events',
|
||||||
"table" => "Events",
|
'table' => 'Events',
|
||||||
"selector" => "Events.MonitorId",
|
'selector' => "Events.MonitorId",
|
||||||
"elements" => array(
|
'elements' => array(
|
||||||
"Id" => true,
|
'Id' => true,
|
||||||
"Name" => true,
|
'Name' => true,
|
||||||
"Cause" => true,
|
'Cause' => true,
|
||||||
"Notes" => true,
|
'Notes' => true,
|
||||||
"StartTime" => true,
|
'StartTime' => true,
|
||||||
"StartTimeShort" => array( "sql" => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ),
|
'StartTimeShort' => array( 'sql' => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ),
|
||||||
"EndTime" => true,
|
'EndTime' => true,
|
||||||
"Width" => true,
|
'Width' => true,
|
||||||
"Height" => true,
|
'Height' => true,
|
||||||
"Length" => true,
|
'Length' => true,
|
||||||
"Frames" => true,
|
'Frames' => true,
|
||||||
"AlarmFrames" => true,
|
'AlarmFrames' => true,
|
||||||
"TotScore" => true,
|
'TotScore' => true,
|
||||||
"AvgScore" => true,
|
'AvgScore' => true,
|
||||||
"MaxScore" => true,
|
'MaxScore' => true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
"event" => array(
|
'event' => array(
|
||||||
"permission" => "Events",
|
'permission' => 'Events',
|
||||||
"table" => "Events",
|
'table' => 'Events',
|
||||||
"limit" => 1,
|
'limit' => 1,
|
||||||
"selector" => "Events.Id",
|
'selector' => "Events.Id",
|
||||||
"elements" => array(
|
'elements' => array(
|
||||||
"Id" => array( "sql" => "Events.Id" ),
|
'Id' => array( 'sql' => "Events.Id" ),
|
||||||
"MonitorId" => true,
|
'MonitorId' => true,
|
||||||
"MonitorName" => array("sql" => "(SELECT Monitors.Name FROM Monitors WHERE Monitors.Id = Events.MonitorId)"),
|
'MonitorName' => array('sql' => "(SELECT Monitors.Name FROM Monitors WHERE Monitors.Id = Events.MonitorId)"),
|
||||||
"Name" => true,
|
'Name' => true,
|
||||||
"Cause" => true,
|
'Cause' => true,
|
||||||
"StartTime" => true,
|
'StartTime' => true,
|
||||||
"StartTimeShort" => array( "sql" => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ),
|
'StartTimeShort' => array( 'sql' => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ),
|
||||||
"EndTime" => true,
|
'EndTime' => true,
|
||||||
"Width" => true,
|
'Width' => true,
|
||||||
"Height" => true,
|
'Height' => true,
|
||||||
"Length" => true,
|
'Length' => true,
|
||||||
"Frames" => true,
|
'Frames' => true,
|
||||||
"DefaultVideo" => true,
|
'DefaultVideo' => true,
|
||||||
"AlarmFrames" => true,
|
'AlarmFrames' => true,
|
||||||
"TotScore" => true,
|
'TotScore' => true,
|
||||||
"AvgScore" => true,
|
'AvgScore' => true,
|
||||||
"MaxScore" => true,
|
'MaxScore' => true,
|
||||||
"Archived" => true,
|
'Archived' => true,
|
||||||
"Videoed" => true,
|
'Videoed' => true,
|
||||||
"Uploaded" => true,
|
'Uploaded' => true,
|
||||||
"Emailed" => true,
|
'Emailed' => true,
|
||||||
"Messaged" => true,
|
'Messaged' => true,
|
||||||
"Executed" => true,
|
'Executed' => true,
|
||||||
"Notes" => true,
|
'Notes' => true,
|
||||||
"MinFrameId" => array( "sql" => "(SELECT min(Frames.FrameId) FROM Frames WHERE EventId=Events.Id)" ),
|
'MinFrameId' => array( 'sql' => "(SELECT min(Frames.FrameId) FROM Frames WHERE EventId=Events.Id)" ),
|
||||||
"MaxFrameId" => array( "sql" => "(SELECT max(Frames.FrameId) FROM Frames WHERE Events.Id = Frames.EventId)" ),
|
'MaxFrameId' => array( 'sql' => "(SELECT max(Frames.FrameId) FROM Frames WHERE Events.Id = Frames.EventId)" ),
|
||||||
"MinFrameDelta" => array( "sql" => "(SELECT min(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)" ),
|
'MinFrameDelta' => array( 'sql' => "(SELECT min(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)" ),
|
||||||
"MaxFrameDelta" => array( "sql" => "(SELECT max(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)" ),
|
'MaxFrameDelta' => array( 'sql' => "(SELECT max(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)" ),
|
||||||
//"Path" => array( "postFunc" => "getEventPath" ),
|
//'Path' => array( 'postFunc' => 'getEventPath' ),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
"frame" => array(
|
'frame' => array(
|
||||||
"permission" => "Events",
|
'permission' => 'Events',
|
||||||
"table" => "Frames",
|
'table' => 'Frames',
|
||||||
"limit" => 1,
|
'limit' => 1,
|
||||||
"selector" => array( array( "table" => "Events", "join" => "Events.Id = Frames.EventId", "selector"=>"Events.Id" ), "Frames.FrameId" ),
|
'selector' => array( array( 'table' => 'Events', 'join' => "Events.Id = Frames.EventId", 'selector'=>"Events.Id" ), "Frames.FrameId" ),
|
||||||
"elements" => array(
|
'elements' => array(
|
||||||
//"Id" => array( "sql" => "Frames.FrameId" ),
|
//'Id' => array( 'sql' => "Frames.FrameId" ),
|
||||||
"FrameId" => true,
|
'FrameId' => true,
|
||||||
"EventId" => true,
|
'EventId' => true,
|
||||||
"Type" => true,
|
'Type' => true,
|
||||||
"TimeStamp" => true,
|
'TimeStamp' => true,
|
||||||
"TimeStampShort" => array( "sql" => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ),
|
'TimeStampShort' => array( 'sql' => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ),
|
||||||
"Delta" => true,
|
'Delta' => true,
|
||||||
"Score" => true,
|
'Score' => true,
|
||||||
//"Image" => array( "postFunc" => "getFrameImage" ),
|
//'Image' => array( 'postFunc' => 'getFrameImage' ),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
"frameimage" => array(
|
'frameimage' => array(
|
||||||
"permission" => "Events",
|
'permission' => 'Events',
|
||||||
"func" => "getFrameImage()"
|
'func' => "getFrameImage()"
|
||||||
),
|
),
|
||||||
"nearframe" => array(
|
'nearframe' => array(
|
||||||
"permission" => "Events",
|
'permission' => 'Events',
|
||||||
"func" => "getNearFrame()"
|
'func' => "getNearFrame()"
|
||||||
),
|
),
|
||||||
"nearevents" => array(
|
'nearevents' => array(
|
||||||
"permission" => "Events",
|
'permission' => 'Events',
|
||||||
"func" => "getNearEvents()"
|
'func' => "getNearEvents()"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -290,7 +290,7 @@ function collectData() {
|
||||||
$data = collectData();
|
$data = collectData();
|
||||||
|
|
||||||
if ( !isset($_REQUEST['layout']) ) {
|
if ( !isset($_REQUEST['layout']) ) {
|
||||||
$_REQUEST['layout'] = "json";
|
$_REQUEST['layout'] = 'json';
|
||||||
}
|
}
|
||||||
|
|
||||||
switch( $_REQUEST['layout'] ) {
|
switch( $_REQUEST['layout'] ) {
|
||||||
|
@ -331,7 +331,7 @@ function getFrameImage() {
|
||||||
$frame = array();
|
$frame = array();
|
||||||
$frame['EventId'] = $eventId;
|
$frame['EventId'] = $eventId;
|
||||||
$frame['FrameId'] = $frameId;
|
$frame['FrameId'] = $frameId;
|
||||||
$frame['Type'] = "Virtual";
|
$frame['Type'] = 'Virtual';
|
||||||
}
|
}
|
||||||
$event = dbFetchOne( 'select * from Events where Id = ?', NULL, array( $frame['EventId'] ) );
|
$event = dbFetchOne( 'select * from Events where Id = ?', NULL, array( $frame['EventId'] ) );
|
||||||
$frame['Image'] = getImageSrc( $event, $frame, SCALE_BASE );
|
$frame['Image'] = getImageSrc( $event, $frame, SCALE_BASE );
|
||||||
|
@ -349,7 +349,7 @@ function getNearFrame() {
|
||||||
return( array() );
|
return( array() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$_REQUEST['entity'] = "frame";
|
$_REQUEST['entity'] = 'frame';
|
||||||
$_REQUEST['id'][1] = $nearFrameId;
|
$_REQUEST['id'][1] = $nearFrameId;
|
||||||
return( collectData() );
|
return( collectData() );
|
||||||
}
|
}
|
||||||
|
@ -358,7 +358,7 @@ function getNearEvents() {
|
||||||
global $user, $sortColumn, $sortOrder;
|
global $user, $sortColumn, $sortOrder;
|
||||||
|
|
||||||
$eventId = $_REQUEST['id'];
|
$eventId = $_REQUEST['id'];
|
||||||
$event = dbFetchOne( 'select * from Events where Id = ?', NULL, array( $eventId ) );
|
$event = dbFetchOne( 'SELECT * FROM Events WHERE Id=?', NULL, array( $eventId ) );
|
||||||
|
|
||||||
if ( isset($_REQUEST['filter']) )
|
if ( isset($_REQUEST['filter']) )
|
||||||
parseFilter( $_REQUEST['filter'] );
|
parseFilter( $_REQUEST['filter'] );
|
||||||
|
@ -369,7 +369,7 @@ function getNearEvents() {
|
||||||
else
|
else
|
||||||
$midSql = '';
|
$midSql = '';
|
||||||
|
|
||||||
$sql = "select E.Id as Id, E.StartTime as StartTime from Events as E inner join Monitors as M on E.MonitorId = M.Id where $sortColumn ".($sortOrder=='asc'?'<=':'>=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." order by $sortColumn ".($sortOrder=='asc'?'desc':'asc');
|
$sql = "SELECT E.Id AS Id, E.StartTime AS StartTime FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE $sortColumn ".($sortOrder=='asc'?'<=':'>=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." ORDER BY $sortColumn ".($sortOrder=='asc'?'desc':'asc') . ' LIMIT 2';
|
||||||
$result = dbQuery( $sql );
|
$result = dbQuery( $sql );
|
||||||
while ( $id = dbFetchNext( $result, 'Id' ) ) {
|
while ( $id = dbFetchNext( $result, 'Id' ) ) {
|
||||||
if ( $id == $eventId ) {
|
if ( $id == $eventId ) {
|
||||||
|
@ -378,7 +378,7 @@ function getNearEvents() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql = "select E.Id as Id, E.StartTime as StartTime from Events as E inner join Monitors as M on E.MonitorId = M.Id where $sortColumn ".($sortOrder=='asc'?'>=':'<=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." order by $sortColumn $sortOrder";
|
$sql = "SELECT E.Id AS Id, E.StartTime AS StartTime FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE $sortColumn ".($sortOrder=='asc'?'>=':'<=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." ORDER BY $sortColumn $sortOrder LIMIT 2";
|
||||||
$result = dbQuery( $sql );
|
$result = dbQuery( $sql );
|
||||||
while ( $id = dbFetchNext( $result, 'Id' ) ) {
|
while ( $id = dbFetchNext( $result, 'Id' ) ) {
|
||||||
if ( $id == $eventId ) {
|
if ( $id == $eventId ) {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
$start_time = time();
|
||||||
|
|
||||||
define( "MSG_TIMEOUT", ZM_WEB_AJAX_TIMEOUT );
|
define( "MSG_TIMEOUT", ZM_WEB_AJAX_TIMEOUT );
|
||||||
define( "MSG_DATA_SIZE", 4+256 );
|
define( "MSG_DATA_SIZE", 4+256 );
|
||||||
|
|
||||||
|
@ -11,39 +13,48 @@ if ( !($socket = @socket_create( AF_UNIX, SOCK_DGRAM, 0 )) ) {
|
||||||
ajaxError( "socket_create() failed: ".socket_strerror(socket_last_error()) );
|
ajaxError( "socket_create() failed: ".socket_strerror(socket_last_error()) );
|
||||||
}
|
}
|
||||||
$locSockFile = ZM_PATH_SOCKS.'/zms-'.sprintf("%06d",$_REQUEST['connkey']).'w.sock';
|
$locSockFile = ZM_PATH_SOCKS.'/zms-'.sprintf("%06d",$_REQUEST['connkey']).'w.sock';
|
||||||
|
if ( file_exists( $locSockFile ) ) {
|
||||||
|
Warning("sock file $locSockFile already exists?! Is someone else talking to zms?");
|
||||||
|
} else {
|
||||||
|
Logger::Debug("socket file does not exist, we should be good to connect.");
|
||||||
|
}
|
||||||
if ( !@socket_bind( $socket, $locSockFile ) ) {
|
if ( !@socket_bind( $socket, $locSockFile ) ) {
|
||||||
ajaxError( "socket_bind( $locSockFile ) failed: ".socket_strerror(socket_last_error()) );
|
ajaxError( "socket_bind( $locSockFile ) failed: ".socket_strerror(socket_last_error()) );
|
||||||
|
} else {
|
||||||
|
Logger::Debug("Bound to $locSockFile");
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ( $_REQUEST['command'] ) {
|
switch ( $_REQUEST['command'] ) {
|
||||||
case CMD_VARPLAY :
|
case CMD_VARPLAY :
|
||||||
Logger::Debug( "Varplaying to ".$_REQUEST['rate'] );
|
Logger::Debug( 'Varplaying to '.$_REQUEST['rate'] );
|
||||||
$msg = pack( "lcn", MSG_CMD, $_REQUEST['command'], $_REQUEST['rate']+32768 );
|
$msg = pack( 'lcn', MSG_CMD, $_REQUEST['command'], $_REQUEST['rate']+32768 );
|
||||||
break;
|
break;
|
||||||
case CMD_ZOOMIN :
|
case CMD_ZOOMIN :
|
||||||
Logger::Debug( "Zooming to ".$_REQUEST['x'].",".$_REQUEST['y'] );
|
Logger::Debug( 'Zooming to '.$_REQUEST['x'].",".$_REQUEST['y'] );
|
||||||
$msg = pack( "lcnn", MSG_CMD, $_REQUEST['command'], $_REQUEST['x'], $_REQUEST['y'] );
|
$msg = pack( 'lcnn', MSG_CMD, $_REQUEST['command'], $_REQUEST['x'], $_REQUEST['y'] );
|
||||||
break;
|
break;
|
||||||
case CMD_PAN :
|
case CMD_PAN :
|
||||||
Logger::Debug( "Panning to ".$_REQUEST['x'].",".$_REQUEST['y'] );
|
Logger::Debug( 'Panning to '.$_REQUEST['x'].",".$_REQUEST['y'] );
|
||||||
$msg = pack( "lcnn", MSG_CMD, $_REQUEST['command'], $_REQUEST['x'], $_REQUEST['y'] );
|
$msg = pack( 'lcnn', MSG_CMD, $_REQUEST['command'], $_REQUEST['x'], $_REQUEST['y'] );
|
||||||
break;
|
break;
|
||||||
case CMD_SCALE :
|
case CMD_SCALE :
|
||||||
Logger::Debug( "Scaling to ".$_REQUEST['scale'] );
|
Logger::Debug( 'Scaling to '.$_REQUEST['scale'] );
|
||||||
$msg = pack( "lcn", MSG_CMD, $_REQUEST['command'], $_REQUEST['scale'] );
|
$msg = pack( 'lcn', MSG_CMD, $_REQUEST['command'], $_REQUEST['scale'] );
|
||||||
break;
|
break;
|
||||||
case CMD_SEEK :
|
case CMD_SEEK :
|
||||||
Logger::Debug( "Seeking to ".$_REQUEST['offset'] );
|
Logger::Debug( 'Seeking to '.$_REQUEST['offset'] );
|
||||||
$msg = pack( "lcN", MSG_CMD, $_REQUEST['command'], $_REQUEST['offset'] );
|
$msg = pack( 'lcN', MSG_CMD, $_REQUEST['command'], $_REQUEST['offset'] );
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
$msg = pack( "lc", MSG_CMD, $_REQUEST['command'] );
|
$msg = pack( 'lc', MSG_CMD, $_REQUEST['command'] );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$remSockFile = ZM_PATH_SOCKS.'/zms-'.sprintf("%06d",$_REQUEST['connkey']).'s.sock';
|
$remSockFile = ZM_PATH_SOCKS.'/zms-'.sprintf('%06d',$_REQUEST['connkey']).'s.sock';
|
||||||
$max_socket_tries = 10;
|
$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.
|
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.
|
||||||
|
Logger::Debug("$remSockFile does not exist, waiting, current " . (time() - $start_time) . ' seconds' );
|
||||||
usleep(200000);
|
usleep(200000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,17 +69,26 @@ if ( !file_exists($remSockFile) ) {
|
||||||
$rSockets = array( $socket );
|
$rSockets = array( $socket );
|
||||||
$wSockets = NULL;
|
$wSockets = NULL;
|
||||||
$eSockets = NULL;
|
$eSockets = NULL;
|
||||||
$numSockets = @socket_select( $rSockets, $wSockets, $eSockets, intval(MSG_TIMEOUT/1000), (MSG_TIMEOUT%1000)*1000 );
|
|
||||||
|
$timeout = MSG_TIMEOUT - ( time() - $start_time );
|
||||||
|
Logger::Debug("TImeout is: $timeout " );
|
||||||
|
|
||||||
|
$numSockets = @socket_select( $rSockets, $wSockets, $eSockets, intval($timeout/1000), ($timeout%1000)*1000 );
|
||||||
|
|
||||||
if ( $numSockets === false ) {
|
if ( $numSockets === false ) {
|
||||||
|
Error("socket_select failed: " . socket_strerror(socket_last_error()) );
|
||||||
ajaxError( "socket_select failed: ".socket_strerror(socket_last_error()) );
|
ajaxError( "socket_select failed: ".socket_strerror(socket_last_error()) );
|
||||||
} else if ( $numSockets < 0 ) {
|
} else if ( $numSockets < 0 ) {
|
||||||
|
Error( "Socket closed $remSockFile" );
|
||||||
ajaxError( "Socket closed $remSockFile" );
|
ajaxError( "Socket closed $remSockFile" );
|
||||||
} else if ( $numSockets == 0 ) {
|
} else if ( $numSockets == 0 ) {
|
||||||
|
Error( "Timed out waiting for msg $remSockFile" );
|
||||||
ajaxError( "Timed out waiting for msg $remSockFile" );
|
ajaxError( "Timed out waiting for msg $remSockFile" );
|
||||||
} else if ( $numSockets > 0 ) {
|
} else if ( $numSockets > 0 ) {
|
||||||
if ( count($rSockets) != 1 )
|
if ( count($rSockets) != 1 ) {
|
||||||
ajaxError( "Bogus return from select, ".count($rSockets)." sockets available" );
|
Error( "Bogus return from select, ".count($rSockets).' sockets available' );
|
||||||
|
ajaxError( "Bogus return from select, ".count($rSockets).' sockets available' );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch( $nbytes = @socket_recvfrom( $socket, $msg, MSG_DATA_SIZE, 0, $remSockFile ) ) {
|
switch( $nbytes = @socket_recvfrom( $socket, $msg, MSG_DATA_SIZE, 0, $remSockFile ) ) {
|
||||||
|
@ -79,7 +99,7 @@ switch( $nbytes = @socket_recvfrom( $socket, $msg, MSG_DATA_SIZE, 0, $remSockFil
|
||||||
}
|
}
|
||||||
case 0 :
|
case 0 :
|
||||||
{
|
{
|
||||||
ajaxError( "No data to read from socket" );
|
ajaxError( 'No data to read from socket' );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default :
|
default :
|
||||||
|
@ -90,7 +110,7 @@ switch( $nbytes = @socket_recvfrom( $socket, $msg, MSG_DATA_SIZE, 0, $remSockFil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = unpack( "ltype", $msg );
|
$data = unpack( 'ltype', $msg );
|
||||||
switch ( $data['type'] ) {
|
switch ( $data['type'] ) {
|
||||||
case MSG_DATA_WATCH :
|
case MSG_DATA_WATCH :
|
||||||
{
|
{
|
||||||
|
@ -99,7 +119,7 @@ switch ( $data['type'] ) {
|
||||||
$data['rate'] /= RATE_BASE;
|
$data['rate'] /= RATE_BASE;
|
||||||
$data['delay'] = round( $data['delay'], 2 );
|
$data['delay'] = round( $data['delay'], 2 );
|
||||||
$data['zoom'] = round( $data['zoom']/SCALE_BASE, 1 );
|
$data['zoom'] = round( $data['zoom']/SCALE_BASE, 1 );
|
||||||
if ( ZM_OPT_USE_AUTH && ZM_AUTH_RELAY == "hashed" ) {
|
if ( ZM_OPT_USE_AUTH && ZM_AUTH_RELAY == 'hashed' ) {
|
||||||
session_start();
|
session_start();
|
||||||
$time = time();
|
$time = time();
|
||||||
// Regenerate auth hash after half the lifetime of the hash
|
// Regenerate auth hash after half the lifetime of the hash
|
||||||
|
@ -117,7 +137,7 @@ switch ( $data['type'] ) {
|
||||||
//$data['progress'] = sprintf( "%.2f", $data['progress'] );
|
//$data['progress'] = sprintf( "%.2f", $data['progress'] );
|
||||||
$data['rate'] /= RATE_BASE;
|
$data['rate'] /= RATE_BASE;
|
||||||
$data['zoom'] = round( $data['zoom']/SCALE_BASE, 1 );
|
$data['zoom'] = round( $data['zoom']/SCALE_BASE, 1 );
|
||||||
if ( ZM_OPT_USE_AUTH && ZM_AUTH_RELAY == "hashed" ) {
|
if ( ZM_OPT_USE_AUTH && ZM_AUTH_RELAY == 'hashed' ) {
|
||||||
session_start();
|
session_start();
|
||||||
$time = time();
|
$time = time();
|
||||||
// Regenerate auth hash after half the lifetime of the hash
|
// Regenerate auth hash after half the lifetime of the hash
|
||||||
|
|
|
@ -198,14 +198,6 @@ class Event {
|
||||||
}
|
}
|
||||||
|
|
||||||
function createListThumbnail( $overwrite=false ) {
|
function createListThumbnail( $overwrite=false ) {
|
||||||
# Load the frame with the highest score to use as a thumbnail
|
|
||||||
if ( !($frame = dbFetchOne( 'SELECT * FROM Frames WHERE EventId=? AND Score=? ORDER BY FrameId LIMIT 1', NULL, array( $this->{'Id'}, $this->{'MaxScore'} ) )) ) {
|
|
||||||
Error("Unable to find a Frame matching max score " . $this->{'MaxScore'} . ' for event ' . $this->{'Id'} );
|
|
||||||
// FIXME: What if somehow the db frame was lost or score was changed? Should probably try another search for any frame.
|
|
||||||
return( false );
|
|
||||||
}
|
|
||||||
|
|
||||||
$frameId = $frame['FrameId'];
|
|
||||||
|
|
||||||
if ( ZM_WEB_LIST_THUMB_WIDTH ) {
|
if ( ZM_WEB_LIST_THUMB_WIDTH ) {
|
||||||
$thumbWidth = ZM_WEB_LIST_THUMB_WIDTH;
|
$thumbWidth = ZM_WEB_LIST_THUMB_WIDTH;
|
||||||
|
@ -219,12 +211,25 @@ class Event {
|
||||||
Fatal( "No thumbnail width or height specified, please check in Options->Web" );
|
Fatal( "No thumbnail width or height specified, please check in Options->Web" );
|
||||||
}
|
}
|
||||||
|
|
||||||
$imageData = $this->getImageSrc( $frame, $scale, false, $overwrite );
|
$eventPath = $this->Path();
|
||||||
if ( ! $imageData ) {
|
if ( file_exists( $eventPath.'/snapshot.jpg' ) ) {
|
||||||
return ( false );
|
$frame = 'snapshot';
|
||||||
|
$humbData = array('Path'=>$eventPath.'/snapshot.jpg');
|
||||||
|
} else {
|
||||||
|
# Load the frame with the highest score to use as a thumbnail
|
||||||
|
if ( !($frame = dbFetchOne( 'SELECT * FROM Frames WHERE EventId=? AND Score=? ORDER BY FrameId LIMIT 1', NULL, array( $this->{'Id'}, $this->{'MaxScore'} ) )) ) {
|
||||||
|
Error("Unable to find a Frame matching max score " . $this->{'MaxScore'} . ' for event ' . $this->{'Id'} );
|
||||||
|
// FIXME: What if somehow the db frame was lost or score was changed? Should probably try another search for any frame.
|
||||||
|
return( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
$imageData = $this->getImageSrc( $frame, $scale, false, $overwrite );
|
||||||
|
if ( ! $imageData ) {
|
||||||
|
return ( false );
|
||||||
|
}
|
||||||
|
$thumbData = $frame;
|
||||||
|
$thumbData['Path'] = $imageData['thumbPath'];
|
||||||
}
|
}
|
||||||
$thumbData = $frame;
|
|
||||||
$thumbData['Path'] = $imageData['thumbPath'];
|
|
||||||
$thumbData['Width'] = (int)$thumbWidth;
|
$thumbData['Width'] = (int)$thumbWidth;
|
||||||
$thumbData['Height'] = (int)$thumbHeight;
|
$thumbData['Height'] = (int)$thumbHeight;
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ public $defaults = array(
|
||||||
'AutoArchive' => 0,
|
'AutoArchive' => 0,
|
||||||
'AutoVideo' => 0,
|
'AutoVideo' => 0,
|
||||||
'AutoMessage' => 0,
|
'AutoMessage' => 0,
|
||||||
|
'UpdateDiskSpace' => 0,
|
||||||
'Background' => 0,
|
'Background' => 0,
|
||||||
'Concurrent' => 0,
|
'Concurrent' => 0,
|
||||||
'limit' => 100,
|
'limit' => 100,
|
||||||
|
|
|
@ -4,13 +4,16 @@ require_once( 'Server.php' );
|
||||||
|
|
||||||
class Monitor {
|
class Monitor {
|
||||||
|
|
||||||
private $fields = array(
|
private $defaults = array(
|
||||||
'Id',
|
'Id' => null,
|
||||||
'Name',
|
'Name' => '',
|
||||||
'StorageId',
|
'StorageId' => 0,
|
||||||
'ServerId',
|
'ServerId' => 0,
|
||||||
'Function',
|
'Function' => 'None',
|
||||||
'Enabled',
|
'Enabled' => 1,
|
||||||
|
'Width' => null,
|
||||||
|
'Height' => null,
|
||||||
|
'Orientation' => null,
|
||||||
);
|
);
|
||||||
private $control_fields = array(
|
private $control_fields = array(
|
||||||
'Name' => '',
|
'Name' => '',
|
||||||
|
@ -158,19 +161,20 @@ private $control_fields = array(
|
||||||
public function Server() {
|
public function Server() {
|
||||||
return new Server( $this->{'ServerId'} );
|
return new Server( $this->{'ServerId'} );
|
||||||
}
|
}
|
||||||
public function __call( $fn, array $args){
|
public function __call($fn, array $args){
|
||||||
if ( count( $args ) ) {
|
if ( count($args) ) {
|
||||||
$this->{$fn} = $args[0];
|
$this->{$fn} = $args[0];
|
||||||
}
|
}
|
||||||
if ( array_key_exists( $fn, $this ) ) {
|
if ( array_key_exists($fn, $this) ) {
|
||||||
return $this->{$fn};
|
return $this->{$fn};
|
||||||
#array_unshift($args, $this);
|
#array_unshift($args, $this);
|
||||||
#call_user_func_array( $this->{$fn}, $args);
|
#call_user_func_array( $this->{$fn}, $args);
|
||||||
} else {
|
} else {
|
||||||
if ( array_key_exists( $fn, $this->control_fields ) ) {
|
if ( array_key_exists($fn, $this->control_fields) ) {
|
||||||
return $this->control_fields{$fn};
|
return $this->control_fields{$fn};
|
||||||
|
} else if ( array_key_exists( $fn, $this->defaults ) ) {
|
||||||
|
return $this->defaults{$fn};
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
$backTrace = debug_backtrace();
|
$backTrace = debug_backtrace();
|
||||||
$file = $backTrace[1]['file'];
|
$file = $backTrace[1]['file'];
|
||||||
$line = $backTrace[1]['line'];
|
$line = $backTrace[1]['line'];
|
||||||
|
@ -214,14 +218,19 @@ private $control_fields = array(
|
||||||
return( $streamSrc );
|
return( $streamSrc );
|
||||||
} // end function getStreamSrc
|
} // end function getStreamSrc
|
||||||
|
|
||||||
public function Width() {
|
public function Width( $new = null ) {
|
||||||
|
if ( $new )
|
||||||
|
$this->{'Width'} = $new;
|
||||||
|
|
||||||
if ( $this->Orientation() == '90' or $this->Orientation() == '270' ) {
|
if ( $this->Orientation() == '90' or $this->Orientation() == '270' ) {
|
||||||
return $this->{'Height'};
|
return $this->{'Height'};
|
||||||
}
|
}
|
||||||
return $this->{'Width'};
|
return $this->{'Width'};
|
||||||
}
|
}
|
||||||
|
|
||||||
public function Height() {
|
public function Height( $new=null ) {
|
||||||
|
if ( $new )
|
||||||
|
$this->{'Height'} = $new;
|
||||||
if ( $this->Orientation() == '90' or $this->Orientation() == '270' ) {
|
if ( $this->Orientation() == '90' or $this->Orientation() == '270' ) {
|
||||||
return $this->{'Width'};
|
return $this->{'Width'};
|
||||||
}
|
}
|
||||||
|
@ -287,11 +296,12 @@ private $control_fields = array(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql = 'UPDATE Monitors SET '.implode(', ', array_map( function($field) {return $field.'=?';}, $this->fields ) ) . ' WHERE Id=?';
|
$sql = 'UPDATE Monitors SET '.implode(', ', array_map( function($field) {return $field.'=?';}, array_keys( $this->defaults ) ) ) . ' WHERE Id=?';
|
||||||
$values = array_map( function($field){return $this->{$field};}, $this->fields );
|
$values = array_map( function($field){return $this->{$field};}, $this->fields );
|
||||||
$values[] = $this->{'Id'};
|
$values[] = $this->{'Id'};
|
||||||
dbQuery( $sql, $values );
|
dbQuery( $sql, $values );
|
||||||
} // end function save
|
} // end function save
|
||||||
|
|
||||||
function zmcControl( $mode=false ) {
|
function zmcControl( $mode=false ) {
|
||||||
if ( (!defined('ZM_SERVER_ID')) or ( ZM_SERVER_ID==$this->{'ServerId'} ) ) {
|
if ( (!defined('ZM_SERVER_ID')) or ( ZM_SERVER_ID==$this->{'ServerId'} ) ) {
|
||||||
if ( $this->{'Type'} == 'Local' ) {
|
if ( $this->{'Type'} == 'Local' ) {
|
||||||
|
@ -306,7 +316,8 @@ private $control_fields = array(
|
||||||
if ( $mode == 'restart' ) {
|
if ( $mode == 'restart' ) {
|
||||||
daemonControl( 'stop', 'zmc', $zmcArgs );
|
daemonControl( 'stop', 'zmc', $zmcArgs );
|
||||||
}
|
}
|
||||||
daemonControl( 'start', 'zmc', $zmcArgs );
|
if ( $this->{'Function'} != 'None' )
|
||||||
|
daemonControl( 'start', 'zmc', $zmcArgs );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$Server = $this->Server();
|
$Server = $this->Server();
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once('database.php');
|
||||||
|
|
||||||
|
class MontageLayout {
|
||||||
|
|
||||||
|
private $defaults = array(
|
||||||
|
'Id' => null,
|
||||||
|
'Name' => '',
|
||||||
|
'Positions' => 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
public function __construct( $IdOrRow = NULL ) {
|
||||||
|
if ( $IdOrRow ) {
|
||||||
|
$row = NULL;
|
||||||
|
if ( is_integer( $IdOrRow ) or is_numeric( $IdOrRow ) ) {
|
||||||
|
$row = dbFetchOne( 'SELECT * FROM MontageLayouts WHERE Id=?', NULL, array( $IdOrRow ) );
|
||||||
|
if ( ! $row ) {
|
||||||
|
Error("Unable to load MontageLayout record for Id=" . $IdOrRow );
|
||||||
|
}
|
||||||
|
} elseif ( is_array( $IdOrRow ) ) {
|
||||||
|
$row = $IdOrRow;
|
||||||
|
} else {
|
||||||
|
Error("Unknown argument passed to MontageLayout Constructor ($IdOrRow)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $row ) {
|
||||||
|
foreach ($row as $k => $v) {
|
||||||
|
$this->{$k} = $v;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Error('No row for MontageLayout ' . $IdOrRow );
|
||||||
|
}
|
||||||
|
} # end if isset($IdOrRow)
|
||||||
|
} // end function __construct
|
||||||
|
|
||||||
|
public function __call($fn, array $args){
|
||||||
|
if ( count($args) ) {
|
||||||
|
$this->{$fn} = $args[0];
|
||||||
|
}
|
||||||
|
if ( array_key_exists($fn, $this) ) {
|
||||||
|
return $this->{$fn};
|
||||||
|
} else {
|
||||||
|
if ( array_key_exists( $fn, $this->defaults ) ) {
|
||||||
|
return $this->defaults{$fn};
|
||||||
|
} else {
|
||||||
|
$backTrace = debug_backtrace();
|
||||||
|
$file = $backTrace[1]['file'];
|
||||||
|
$line = $backTrace[1]['line'];
|
||||||
|
Warning( "Unknown function call MontageLayout->$fn from $file:$line" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set( $data ) {
|
||||||
|
foreach ($data as $k => $v) {
|
||||||
|
if ( is_array( $v ) ) {
|
||||||
|
# perhaps should turn into a comma-separated string
|
||||||
|
$this->{$k} = implode(',',$v);
|
||||||
|
} else if ( is_string( $v ) ) {
|
||||||
|
$this->{$k} = trim( $v );
|
||||||
|
} else if ( is_integer( $v ) ) {
|
||||||
|
$this->{$k} = $v;
|
||||||
|
} else if ( is_bool( $v ) ) {
|
||||||
|
$this->{$k} = $v;
|
||||||
|
} else {
|
||||||
|
Error( "Unknown type $k => $v of var " . gettype( $v ) );
|
||||||
|
$this->{$k} = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static function find( $parameters = null, $options = null ) {
|
||||||
|
$filters = array();
|
||||||
|
$sql = 'SELECT * FROM MontageLayouts ';
|
||||||
|
$values = array();
|
||||||
|
|
||||||
|
if ( $parameters ) {
|
||||||
|
$fields = array();
|
||||||
|
$sql .= 'WHERE ';
|
||||||
|
foreach ( $parameters as $field => $value ) {
|
||||||
|
if ( $value == null ) {
|
||||||
|
$fields[] = $field.' IS NULL';
|
||||||
|
} else if ( is_array( $value ) ) {
|
||||||
|
$func = function(){return '?';};
|
||||||
|
$fields[] = $field.' IN ('.implode(',', array_map( $func, $value ) ). ')';
|
||||||
|
$values += $value;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$fields[] = $field.'=?';
|
||||||
|
$values[] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$sql .= implode(' AND ', $fields );
|
||||||
|
}
|
||||||
|
if ( $options and isset($options['order']) ) {
|
||||||
|
$sql .= ' ORDER BY ' . $options['order'];
|
||||||
|
}
|
||||||
|
$result = dbQuery($sql, $values);
|
||||||
|
if ( $result ) {
|
||||||
|
$results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'MontageLayout');
|
||||||
|
foreach ( $results as $row => $obj ) {
|
||||||
|
$filters[] = $obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $filters;
|
||||||
|
}
|
||||||
|
public function save( $new_values = null ) {
|
||||||
|
if ( $new_values ) {
|
||||||
|
foreach ( $new_values as $k=>$v ) {
|
||||||
|
$this->{$k} = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$fields = array_values( array_filter( array_keys($this->defaults), function($field){return $field != 'Id';} ) );
|
||||||
|
$values = null;
|
||||||
|
if ( isset($this->{'Id'}) ) {
|
||||||
|
$sql = 'UPDATE MontageLayouts SET '.implode(', ', array_map( function($field) {return $field.'=?';}, $fields ) ) . ' WHERE Id=?';
|
||||||
|
$values = array_map( function($field){return $this->{$field};}, $fields );
|
||||||
|
$values[] = $this->{'Id'};
|
||||||
|
dbQuery( $sql, $values );
|
||||||
|
} else {
|
||||||
|
$sql = 'INSERT INTO MontageLayouts ('.implode( ',', $fields ).') VALUES ('.implode(',',array_map( function(){return '?';}, $fields ) ).')';
|
||||||
|
$values = array_map( function($field){return $this->{$field};}, $fields );
|
||||||
|
dbQuery( $sql, $values );
|
||||||
|
global $dbConn;
|
||||||
|
$this->{Id} = $dbConn->lastInsertId();
|
||||||
|
}
|
||||||
|
} // end function save
|
||||||
|
|
||||||
|
} // end class MontageLayout
|
||||||
|
?>
|
File diff suppressed because it is too large
Load Diff
|
@ -122,17 +122,26 @@ function dbQuery( $sql, $params=NULL ) {
|
||||||
$result = NULL;
|
$result = NULL;
|
||||||
try {
|
try {
|
||||||
if ( isset($params) ) {
|
if ( isset($params) ) {
|
||||||
$result = $dbConn->prepare( $sql );
|
if ( ! $result = $dbConn->prepare( $sql ) ) {
|
||||||
$result->execute( $params );
|
Error("SQL: Error preparing $sql: " . $pdo->errorInfo);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! $result->execute( $params ) ) {
|
||||||
|
Error("SQL: Error executing $sql: " . implode(',', $result->errorInfo() ) );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$result = $dbConn->query( $sql );
|
$result = $dbConn->query( $sql );
|
||||||
}
|
}
|
||||||
//if ( $params )
|
if ( 0 ) {
|
||||||
//Warning("SQL: $sql" . implode(',',$params));
|
if ( $params )
|
||||||
//else
|
Warning("SQL: $sql" . implode(',',$params) . ' rows: '.$result->rowCount() );
|
||||||
//Warning("SQL: $sql" );
|
else
|
||||||
|
Warning("SQL: $sql: rows:" . $result->rowCount() );
|
||||||
|
}
|
||||||
} catch(PDOException $e) {
|
} catch(PDOException $e) {
|
||||||
Error( "SQL-ERR '".$e->getMessage()."', statement was '".$sql."' params:" . implode(',',$params) );
|
Error( "SQL-ERR '".$e->getMessage()."', statement was '".$sql."' params:" . $params?implode(',',$params):'' );
|
||||||
}
|
}
|
||||||
return( $result );
|
return( $result );
|
||||||
}
|
}
|
||||||
|
|
|
@ -1057,10 +1057,18 @@ function parseSort( $saveToSession=false, $querySep='&' ) {
|
||||||
$sortColumn = 'E.Cause';
|
$sortColumn = 'E.Cause';
|
||||||
break;
|
break;
|
||||||
case 'DateTime' :
|
case 'DateTime' :
|
||||||
|
$sortColumn = 'E.StartTime';
|
||||||
$_REQUEST['sort_field'] = 'StartTime';
|
$_REQUEST['sort_field'] = 'StartTime';
|
||||||
|
break;
|
||||||
|
case 'DiskSpace' :
|
||||||
|
$sortColumn = 'E.DiskSpace';
|
||||||
|
break;
|
||||||
case 'StartTime' :
|
case 'StartTime' :
|
||||||
$sortColumn = 'E.StartTime';
|
$sortColumn = 'E.StartTime';
|
||||||
break;
|
break;
|
||||||
|
case 'EndTime' :
|
||||||
|
$sortColumn = 'E.EndTime';
|
||||||
|
break;
|
||||||
case 'Length' :
|
case 'Length' :
|
||||||
$sortColumn = 'E.Length';
|
$sortColumn = 'E.Length';
|
||||||
break;
|
break;
|
||||||
|
@ -1126,6 +1134,7 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) {
|
||||||
case 'ServerId':
|
case 'ServerId':
|
||||||
$filter['sql'] .= 'M.ServerId';
|
$filter['sql'] .= 'M.ServerId';
|
||||||
break;
|
break;
|
||||||
|
# Unspecified start or end, so assume start, this is to support legacy filters
|
||||||
case 'DateTime':
|
case 'DateTime':
|
||||||
$filter['sql'] .= 'E.StartTime';
|
$filter['sql'] .= 'E.StartTime';
|
||||||
break;
|
break;
|
||||||
|
@ -1138,8 +1147,35 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) {
|
||||||
case 'Weekday':
|
case 'Weekday':
|
||||||
$filter['sql'] .= 'weekday( E.StartTime )';
|
$filter['sql'] .= 'weekday( E.StartTime )';
|
||||||
break;
|
break;
|
||||||
|
# Starting Time
|
||||||
|
case 'StartDateTime':
|
||||||
|
$filter['sql'] .= 'E.StartTime';
|
||||||
|
break;
|
||||||
|
case 'StartDate':
|
||||||
|
$filter['sql'] .= 'to_days( E.StartTime )';
|
||||||
|
break;
|
||||||
|
case 'StartTime':
|
||||||
|
$filter['sql'] .= 'extract( hour_second from E.StartTime )';
|
||||||
|
break;
|
||||||
|
case 'StartWeekday':
|
||||||
|
$filter['sql'] .= 'weekday( E.StartTime )';
|
||||||
|
break;
|
||||||
|
# Ending Time
|
||||||
|
case 'EndDateTime':
|
||||||
|
$filter['sql'] .= 'E.EndTime';
|
||||||
|
break;
|
||||||
|
case 'EndDate':
|
||||||
|
$filter['sql'] .= 'to_days( E.EndTime )';
|
||||||
|
break;
|
||||||
|
case 'EndTime':
|
||||||
|
$filter['sql'] .= 'extract( hour_second from E.EndTime )';
|
||||||
|
break;
|
||||||
|
case 'EndWeekday':
|
||||||
|
$filter['sql'] .= 'weekday( E.EndTime )';
|
||||||
|
break;
|
||||||
case 'Id':
|
case 'Id':
|
||||||
case 'Name':
|
case 'Name':
|
||||||
|
case 'DiskSpace':
|
||||||
case 'MonitorId':
|
case 'MonitorId':
|
||||||
case 'StorageId':
|
case 'StorageId':
|
||||||
case 'Length':
|
case 'Length':
|
||||||
|
@ -1239,6 +1275,12 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) {
|
||||||
case '![]' :
|
case '![]' :
|
||||||
$filter['sql'] .= ' not in ('.join( ',', $valueList ).')';
|
$filter['sql'] .= ' not in ('.join( ',', $valueList ).')';
|
||||||
break;
|
break;
|
||||||
|
case 'IS' :
|
||||||
|
$filter['sql'] .= " IS $value";
|
||||||
|
break;
|
||||||
|
case 'IS NOT' :
|
||||||
|
$filter['sql'] .= " IS NOT $value";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][op]").'='.urlencode($terms[$i]['op']);
|
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][op]").'='.urlencode($terms[$i]['op']);
|
||||||
|
@ -1853,7 +1895,8 @@ function logState() {
|
||||||
Logger::WARNING => array( ZM_LOG_ALERT_WAR_COUNT, ZM_LOG_ALARM_WAR_COUNT ),
|
Logger::WARNING => array( ZM_LOG_ALERT_WAR_COUNT, ZM_LOG_ALARM_WAR_COUNT ),
|
||||||
);
|
);
|
||||||
|
|
||||||
$sql = "select Level, count(Level) as LevelCount from Logs where Level < ".Logger::INFO." and TimeKey > unix_timestamp(now() - interval ".ZM_LOG_CHECK_PERIOD." second) group by Level order by Level asc";
|
# This is an expensive request, as it has to hit every row of the Logs Table
|
||||||
|
$sql = 'SELECT Level, COUNT(Level) AS LevelCount FROM Logs WHERE Level < '.Logger::INFO.' AND TimeKey > unix_timestamp(now() - interval '.ZM_LOG_CHECK_PERIOD.' second) GROUP BY Level ORDER BY Level ASC';
|
||||||
$counts = dbFetchAll( $sql );
|
$counts = dbFetchAll( $sql );
|
||||||
|
|
||||||
foreach ( $counts as $count ) {
|
foreach ( $counts as $count ) {
|
||||||
|
@ -2020,6 +2063,19 @@ function detaintPath( $path ) {
|
||||||
return( $path );
|
return( $path );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cache_bust( $file ) {
|
||||||
|
# Use the last modified timestamp to create a link that gets a different filename
|
||||||
|
# To defeat caching. Should probably use md5 hash
|
||||||
|
$parts = pathinfo($file);
|
||||||
|
$cacheFile = 'cache/'.$parts['filename'].'-'.filemtime($file).'.'.$parts['extension'];
|
||||||
|
if ( file_exists( ZM_PATH_WEB.'/'.$cacheFile ) or symlink( ZM_PATH_WEB.'/'.$file, ZM_PATH_WEB.'/'.$cacheFile ) ) {
|
||||||
|
return $cacheFile;
|
||||||
|
} else {
|
||||||
|
Warning("Failed linking $file to $cacheFile");
|
||||||
|
}
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
function getSkinFile( $file ) {
|
function getSkinFile( $file ) {
|
||||||
global $skinBase;
|
global $skinBase;
|
||||||
$skinFile = false;
|
$skinFile = false;
|
||||||
|
@ -2028,7 +2084,7 @@ function getSkinFile( $file ) {
|
||||||
if ( file_exists( $tempSkinFile ) )
|
if ( file_exists( $tempSkinFile ) )
|
||||||
$skinFile = $tempSkinFile;
|
$skinFile = $tempSkinFile;
|
||||||
}
|
}
|
||||||
return( $skinFile );
|
return $skinFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSkinIncludes( $file, $includeBase=false, $asOverride=false ) {
|
function getSkinIncludes( $file, $includeBase=false, $asOverride=false ) {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -34,7 +34,7 @@ if ( version_compare( phpversion(), '4.1.0', '<') ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Useful debugging lines for mobile devices
|
// Useful debugging lines for mobile devices
|
||||||
if ( false ) {
|
if ( true ) {
|
||||||
ob_start();
|
ob_start();
|
||||||
phpinfo( INFO_VARIABLES );
|
phpinfo( INFO_VARIABLES );
|
||||||
$fp = fopen( '/tmp/env.html', 'w' );
|
$fp = fopen( '/tmp/env.html', 'w' );
|
||||||
|
@ -113,7 +113,7 @@ if ( !file_exists( ZM_SKIN_PATH ) )
|
||||||
$skinBase[] = $skin;
|
$skinBase[] = $skin;
|
||||||
|
|
||||||
$currentCookieParams = session_get_cookie_params();
|
$currentCookieParams = session_get_cookie_params();
|
||||||
Logger::Debug('Setting cookie parameters to lifetime('.$currentCookieParams['lifetime'].') path('.$currentCookieParams['path'].') domain ('.$currentCookieParams['domain'].') secure('.$currentCookieParams['secure'].') httpOnly(1)');
|
//Logger::Debug('Setting cookie parameters to lifetime('.$currentCookieParams['lifetime'].') path('.$currentCookieParams['path'].') domain ('.$currentCookieParams['domain'].') secure('.$currentCookieParams['secure'].') httpOnly(1)');
|
||||||
session_set_cookie_params(
|
session_set_cookie_params(
|
||||||
$currentCookieParams['lifetime'],
|
$currentCookieParams['lifetime'],
|
||||||
$currentCookieParams['path'],
|
$currentCookieParams['path'],
|
||||||
|
@ -175,9 +175,7 @@ foreach ( getSkinIncludes( 'skin.php' ) as $includeFile )
|
||||||
|
|
||||||
if ( ZM_OPT_USE_AUTH && ZM_AUTH_HASH_LOGINS ) {
|
if ( ZM_OPT_USE_AUTH && ZM_AUTH_HASH_LOGINS ) {
|
||||||
if ( empty($user) && ! empty($_REQUEST['auth']) ) {
|
if ( empty($user) && ! empty($_REQUEST['auth']) ) {
|
||||||
Logger::Debug("Getting user from auth hash");
|
|
||||||
if ( $authUser = getAuthUser( $_REQUEST['auth'] ) ) {
|
if ( $authUser = getAuthUser( $_REQUEST['auth'] ) ) {
|
||||||
Logger::Debug("Success Getting user from auth hash");
|
|
||||||
userLogin( $authUser['Username'], $authUser['Password'], true );
|
userLogin( $authUser['Username'], $authUser['Password'], true );
|
||||||
}
|
}
|
||||||
} else if ( ! empty($user) ) {
|
} else if ( ! empty($user) ) {
|
||||||
|
|
|
@ -116,8 +116,11 @@ $SLANG = array(
|
||||||
'AttrArchiveStatus' => 'Archive Status',
|
'AttrArchiveStatus' => 'Archive Status',
|
||||||
'AttrAvgScore' => 'Avg. Score',
|
'AttrAvgScore' => 'Avg. Score',
|
||||||
'AttrCause' => 'Cause',
|
'AttrCause' => 'Cause',
|
||||||
'AttrDate' => 'Date',
|
'AttrStartDate' => 'Start Date',
|
||||||
'AttrDateTime' => 'Date/Time',
|
'AttrEndDate' => 'End Date',
|
||||||
|
'AttrStartDateTime' => 'Start Date/Time',
|
||||||
|
'AttrEndDateTime' => 'End Date/Time',
|
||||||
|
'AttrDiskSpace' => 'Disk Space',
|
||||||
'AttrDiskBlocks' => 'Disk Blocks',
|
'AttrDiskBlocks' => 'Disk Blocks',
|
||||||
'AttrDiskPercent' => 'Disk Percent',
|
'AttrDiskPercent' => 'Disk Percent',
|
||||||
'AttrDuration' => 'Duration',
|
'AttrDuration' => 'Duration',
|
||||||
|
@ -132,9 +135,11 @@ $SLANG = array(
|
||||||
'AttrName' => 'Name',
|
'AttrName' => 'Name',
|
||||||
'AttrNotes' => 'Notes',
|
'AttrNotes' => 'Notes',
|
||||||
'AttrSystemLoad' => 'System Load',
|
'AttrSystemLoad' => 'System Load',
|
||||||
'AttrTime' => 'Time',
|
'AttrStartTime' => 'Start Time',
|
||||||
|
'AttrEndTime' => 'End Time',
|
||||||
'AttrTotalScore' => 'Total Score',
|
'AttrTotalScore' => 'Total Score',
|
||||||
'AttrWeekday' => 'Weekday',
|
'AttrStartWeekday' => 'Start Weekday',
|
||||||
|
'AttrEndWeekday' => 'End Weekday',
|
||||||
'Auto' => 'Auto',
|
'Auto' => 'Auto',
|
||||||
'AutoStopTimeout' => 'Auto Stop Timeout',
|
'AutoStopTimeout' => 'Auto Stop Timeout',
|
||||||
'Available' => 'Available',
|
'Available' => 'Available',
|
||||||
|
@ -297,6 +302,7 @@ $SLANG = array(
|
||||||
'DuplicateMonitorName' => 'Duplicate Monitor Name',
|
'DuplicateMonitorName' => 'Duplicate Monitor Name',
|
||||||
'Duration' => 'Duration',
|
'Duration' => 'Duration',
|
||||||
'Edit' => 'Edit',
|
'Edit' => 'Edit',
|
||||||
|
'EditLayout' => 'Edit Layout',
|
||||||
'Email' => 'Email',
|
'Email' => 'Email',
|
||||||
'EnableAlarms' => 'Enable Alarms',
|
'EnableAlarms' => 'Enable Alarms',
|
||||||
'Enabled' => 'Enabled',
|
'Enabled' => 'Enabled',
|
||||||
|
@ -334,6 +340,7 @@ $SLANG = array(
|
||||||
'Ffmpeg' => 'Ffmpeg',
|
'Ffmpeg' => 'Ffmpeg',
|
||||||
'File' => 'File',
|
'File' => 'File',
|
||||||
'FilterArchiveEvents' => 'Archive all matches',
|
'FilterArchiveEvents' => 'Archive all matches',
|
||||||
|
'FilterUpdateDiskSpace' => 'Update used disk space',
|
||||||
'FilterDeleteEvents' => 'Delete all matches',
|
'FilterDeleteEvents' => 'Delete all matches',
|
||||||
'FilterEmailEvents' => 'Email details of all matches',
|
'FilterEmailEvents' => 'Email details of all matches',
|
||||||
'FilterExecuteEvents' => 'Execute command on all matches',
|
'FilterExecuteEvents' => 'Execute command on all matches',
|
||||||
|
@ -413,6 +420,7 @@ $SLANG = array(
|
||||||
'LimitResultsPre' => 'Limit to first', // This is used at the beginning of the phrase 'Limit to first N results only'
|
'LimitResultsPre' => 'Limit to first', // This is used at the beginning of the phrase 'Limit to first N results only'
|
||||||
'LinkedMonitors' => 'Linked Monitors',
|
'LinkedMonitors' => 'Linked Monitors',
|
||||||
'List' => 'List',
|
'List' => 'List',
|
||||||
|
'ListMatches' => 'List Matches',
|
||||||
'Load' => 'Load',
|
'Load' => 'Load',
|
||||||
'Local' => 'Local',
|
'Local' => 'Local',
|
||||||
'Log' => 'Log',
|
'Log' => 'Log',
|
||||||
|
@ -549,6 +557,8 @@ $SLANG = array(
|
||||||
'OpNe' => 'not equal to',
|
'OpNe' => 'not equal to',
|
||||||
'OpNotIn' => 'not in set',
|
'OpNotIn' => 'not in set',
|
||||||
'OpNotMatches' => 'does not match',
|
'OpNotMatches' => 'does not match',
|
||||||
|
'OpIs' => 'is',
|
||||||
|
'OpIsNot' => 'is not',
|
||||||
'OptionalEncoderParam' => 'Optional Encoder Parameters',
|
'OptionalEncoderParam' => 'Optional Encoder Parameters',
|
||||||
'OptionHelp' => 'Option Help',
|
'OptionHelp' => 'Option Help',
|
||||||
'OptionRestartWarning' => 'These changes may not come into effect fully\nwhile the system is running. When you have\nfinished making your changes please ensure that\nyou restart ZoneMinder.',
|
'OptionRestartWarning' => 'These changes may not come into effect fully\nwhile the system is running. When you have\nfinished making your changes please ensure that\nyou restart ZoneMinder.',
|
||||||
|
|
|
@ -6,6 +6,15 @@
|
||||||
width: 99%;
|
width: 99%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#monitors:after {
|
||||||
|
content: ".";
|
||||||
|
display: block;
|
||||||
|
height: 0;
|
||||||
|
font-size: 0;
|
||||||
|
clear: both;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
#monitors .monitor {
|
#monitors .monitor {
|
||||||
min-width: 180px;
|
min-width: 180px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
|
@ -48,8 +48,10 @@ function xhtmlHeaders( $file, $title ) {
|
||||||
<title><?php echo ZM_WEB_TITLE_PREFIX ?> - <?php echo validHtmlStr($title) ?></title>
|
<title><?php echo ZM_WEB_TITLE_PREFIX ?> - <?php echo validHtmlStr($title) ?></title>
|
||||||
<?php
|
<?php
|
||||||
if ( file_exists( "skins/$skin/css/$css/graphics/favicon.ico" ) ) {
|
if ( file_exists( "skins/$skin/css/$css/graphics/favicon.ico" ) ) {
|
||||||
echo "<link rel=\"icon\" type=\"image/ico\" href=\"skins/$skin/css/$css/graphics/favicon.ico\"/>\n";
|
echo "
|
||||||
echo "<link rel=\"shortcut icon\" href=\"skins/$skin/css/$css/graphics/favicon.ico\"/>\n";
|
<link rel=\"icon\" type=\"image/ico\" href=\"skins/$skin/css/$css/graphics/favicon.ico\"/>
|
||||||
|
<link rel=\"shortcut icon\" href=\"skins/$skin/css/$css/graphics/favicon.ico\"/>
|
||||||
|
";
|
||||||
} else {
|
} else {
|
||||||
echo '
|
echo '
|
||||||
<link rel="icon" type="image/ico" href="graphics/favicon.ico"/>
|
<link rel="icon" type="image/ico" href="graphics/favicon.ico"/>
|
||||||
|
@ -60,11 +62,11 @@ if ( file_exists( "skins/$skin/css/$css/graphics/favicon.ico" ) ) {
|
||||||
<link rel="stylesheet" href="css/reset.css" type="text/css"/>
|
<link rel="stylesheet" href="css/reset.css" type="text/css"/>
|
||||||
<link rel="stylesheet" href="css/overlay.css" type="text/css"/>
|
<link rel="stylesheet" href="css/overlay.css" type="text/css"/>
|
||||||
<link rel="stylesheet" href="css/bootstrap.min.css" type="text/css"/>
|
<link rel="stylesheet" href="css/bootstrap.min.css" type="text/css"/>
|
||||||
<link rel="stylesheet" href="<?php echo $skinCssFile ?>" type="text/css" media="screen"/>
|
<link rel="stylesheet" href="<?php echo cache_bust($skinCssFile) ?>" type="text/css" media="screen"/>
|
||||||
<?php
|
<?php
|
||||||
if ( $viewCssFile ) {
|
if ( $viewCssFile ) {
|
||||||
?>
|
?>
|
||||||
<link rel="stylesheet" href="<?php echo $viewCssFile ?>" type="text/css" media="screen"/>
|
<link rel="stylesheet" href="<?php echo cache_bust($viewCssFile) ?>" type="text/css" media="screen"/>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
if ( $viewCssPhpFile ) {
|
if ( $viewCssPhpFile ) {
|
||||||
|
@ -138,18 +140,18 @@ if ( file_exists( "skins/$skin/css/$css/graphics/favicon.ico" ) ) {
|
||||||
}
|
}
|
||||||
if ( $cssJsFile ) {
|
if ( $cssJsFile ) {
|
||||||
?>
|
?>
|
||||||
<script type="text/javascript" src="<?php echo $cssJsFile ?>"></script>
|
<script type="text/javascript" src="<?php echo cache_bust($cssJsFile) ?>"></script>
|
||||||
<?php
|
<?php
|
||||||
} else {
|
} else {
|
||||||
?>
|
?>
|
||||||
<script type="text/javascript" src="skins/classic/js/classic.js"></script>
|
<script type="text/javascript" src="skins/classic/js/classic.js"></script>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
<script type="text/javascript" src="<?php echo $skinJsFile ?>"></script>
|
<script type="text/javascript" src="<?php echo cache_bust($skinJsFile) ?>"></script>
|
||||||
<script type="text/javascript" src="js/logger.js"></script>
|
<script type="text/javascript" src="js/logger.js"></script>
|
||||||
<?php
|
<?php
|
||||||
if ( $viewJsFile ) {
|
if ( $viewJsFile ) {
|
||||||
?>
|
?>
|
||||||
<script type="text/javascript" src="<?php echo $viewJsFile ?>"></script>
|
<script type="text/javascript" src="<?php echo cache_bust($viewJsFile) ?>"></script>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -194,9 +196,19 @@ ZoneMinder requires Javascript. Please enable Javascript in your browser for thi
|
||||||
<li><a href="?view=console"><?php echo translate('Console') ?></a></li>
|
<li><a href="?view=console"><?php echo translate('Console') ?></a></li>
|
||||||
<?php if ( canView( 'System' ) ) { ?>
|
<?php if ( canView( 'System' ) ) { ?>
|
||||||
<li><a href="?view=options"><?php echo translate('Options') ?></a></li>
|
<li><a href="?view=options"><?php echo translate('Options') ?></a></li>
|
||||||
<li><?php if ( logToDatabase() > Logger::NOLOG ) { ?> <?php echo makePopupLink( '?view=log', 'zmLog', 'log', '<span class="'.logState().'">'.translate('Log').'</span>' ) ?><?php } ?></li>
|
<li>
|
||||||
<?php } ?>
|
<?php
|
||||||
<?php if ( ZM_OPT_X10 && canView( 'Devices' ) ) { ?>
|
if ( logToDatabase() > Logger::NOLOG ) {
|
||||||
|
if ( ! ZM_RUN_AUDIT ) {
|
||||||
|
# zmaudit can clean the logs, but if we aren't running it, then we should clecan them regularly
|
||||||
|
dbQuery("DELETE FROM Logs WHERE TimeKey < NOW()-to_days('".ZM_LOG_DATABASE_LIMIT."')");
|
||||||
|
}
|
||||||
|
echo makePopupLink( '?view=log', 'zmLog', 'log', '<span class="'.logState().'">'.translate('Log').'</span>' );
|
||||||
|
}
|
||||||
|
} // end if canview(System)
|
||||||
|
?></li>
|
||||||
|
<?php
|
||||||
|
if ( ZM_OPT_X10 && canView( 'Devices' ) ) { ?>
|
||||||
<li><a href="?view=devices">Devices</a></li>
|
<li><a href="?view=devices">Devices</a></li>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
<li><a href="?view=groups"<?php echo $view=='groups'?' class="selected"':''?>><?php echo translate('Groups') ?></a></li>
|
<li><a href="?view=groups"<?php echo $view=='groups'?' class="selected"':''?>><?php echo translate('Groups') ?></a></li>
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
<?php
|
||||||
|
//
|
||||||
|
// ZoneMinder web console file, $Date$, $Revision$
|
||||||
|
// Copyright (C) 2001-2008 Philip Coombes
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
$servers = Server::find_all();
|
||||||
|
$ServersById = array();
|
||||||
|
foreach ( $servers as $S ) {
|
||||||
|
$ServersById[$S->Id()] = $S;
|
||||||
|
}
|
||||||
|
session_start();
|
||||||
|
foreach ( array('ServerFilter','StorageFilter','StatusFilter','MonitorId') as $var ) {
|
||||||
|
if ( isset( $_REQUEST[$var] ) ) {
|
||||||
|
if ( $_REQUEST[$var] != '' ) {
|
||||||
|
$_SESSION[$var] = $_REQUEST[$var];
|
||||||
|
} else {
|
||||||
|
unset( $_SESSION[$var] );
|
||||||
|
}
|
||||||
|
} else if ( isset( $_COOKIE[$var] ) ) {
|
||||||
|
if ( $_COOKIE[$var] != '' ) {
|
||||||
|
$_SESSION[$var] = $_COOKIE[$var];
|
||||||
|
} else {
|
||||||
|
unset($_SESSION[$var]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
session_write_close();
|
||||||
|
|
||||||
|
$storage_areas = Storage::find_all();
|
||||||
|
$StorageById = array();
|
||||||
|
foreach ( $storage_areas as $S ) {
|
||||||
|
$StorageById[$S->Id()] = $S;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<div class="controlHeader">
|
||||||
|
<span id="groupControl"><label><?php echo translate('Group') ?>:</label>
|
||||||
|
<?php
|
||||||
|
# This will end up with the group_id of the deepest selection
|
||||||
|
$group_id = Group::get_group_dropdowns();
|
||||||
|
$groupSql = Group::get_group_sql( $group_id );
|
||||||
|
?>
|
||||||
|
</span>
|
||||||
|
<span id="monitorControl"><label><?php echo translate('Monitor') ?>:</label>
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$monitor_id = isset($_SESSION['MonitorId']) ? $_SESSION['MonitorId'] : 0;
|
||||||
|
|
||||||
|
# Used to determine if the Cycle button should be made available
|
||||||
|
|
||||||
|
$conditions = array();
|
||||||
|
$values = array();
|
||||||
|
|
||||||
|
if ( $groupSql )
|
||||||
|
$conditions[] = $groupSql;
|
||||||
|
if ( isset($_SESSION['ServerFilter']) ) {
|
||||||
|
$conditions[] = 'ServerId=?';
|
||||||
|
$values[] = $_SESSION['ServerFilter'];
|
||||||
|
}
|
||||||
|
if ( isset($_SESSION['StorageFilter']) ) {
|
||||||
|
$conditions[] = 'StorageId=?';
|
||||||
|
$values[] = $_SESSION['StorageFilter'];
|
||||||
|
}
|
||||||
|
if ( ! empty( $user['MonitorIds'] ) ) {
|
||||||
|
$ids = explode(',', $user['MonitorIds'] );
|
||||||
|
$conditions[] = 'Id IN ('.implode(',',array_map( function(){return '?';}, $ids) ).')';
|
||||||
|
$values += $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = 'SELECT * FROM Monitors' . ( count($conditions) ? ' WHERE ' . implode(' AND ', $conditions ) : '' ).' ORDER BY Sequence ASC';
|
||||||
|
$monitors = dbFetchAll( $sql, null, $values );
|
||||||
|
$displayMonitors = array();
|
||||||
|
$monitors_dropdown = array(''=>'All');
|
||||||
|
|
||||||
|
if ( $monitor_id ) {
|
||||||
|
$found_selected_monitor = false;
|
||||||
|
|
||||||
|
for ( $i = 0; $i < count($monitors); $i++ ) {
|
||||||
|
if ( !visibleMonitor( $monitors[$i]['Id'] ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$monitors_dropdown[$monitors[$i]['Id']] = $monitors[$i]['Name'];
|
||||||
|
if ( $monitors[$i]['Id'] == $monitor_id ) {
|
||||||
|
$found_selected_monitor = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( ! $found_selected_monitor ) {
|
||||||
|
$monitor_id = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ( $i = 0; $i < count($monitors); $i++ ) {
|
||||||
|
if ( !visibleMonitor( $monitors[$i]['Id'] ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$monitors_dropdown[$monitors[$i]['Id']] = $monitors[$i]['Name'];
|
||||||
|
|
||||||
|
if ( $monitor_id and ( $monitors[$i]['Id'] != $monitor_id ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$displayMonitors[] = $monitors[$i];
|
||||||
|
}
|
||||||
|
echo htmlSelect( 'MonitorId', $monitors_dropdown, $monitor_id, array('onchange'=>'changeMonitor(this);') );
|
||||||
|
?>
|
||||||
|
</span>
|
||||||
|
<?php
|
||||||
|
if ( count($ServersById) > 1 ) {
|
||||||
|
?>
|
||||||
|
<span class="ServerFilter"><label><?php echo translate('Server')?>:</label>
|
||||||
|
<?php
|
||||||
|
echo htmlSelect( 'ServerFilter', array(''=>'All')+$ServersById, (isset($_SESSION['ServerFilter'])?$_SESSION['ServerFilter']:''), array('onchange'=>'changeFilter(this);') );
|
||||||
|
?>
|
||||||
|
</span>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
if ( count($StorageById) > 1 ) { ?>
|
||||||
|
<span class="StorageFilter"><label><?php echo translate('Storage')?>:</label>
|
||||||
|
<?php
|
||||||
|
echo htmlSelect( 'StorageFilter', array(''=>'All')+$StorageById, (isset($_SESSION['StorageFilter'])?$_SESSION['StorageFilter']:''), array('onchange'=>'changeFilter(this);') );
|
||||||
|
?>
|
||||||
|
</span>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<span class="StatusFilter"><label><?php echo translate('Status')?>:</label>
|
||||||
|
<?php
|
||||||
|
$status_options = array(
|
||||||
|
''=>'All',
|
||||||
|
'Unknown' => translate('Unknown'),
|
||||||
|
'NotRunning' => translate('NotRunning'),
|
||||||
|
'Running' => translate('Running'),
|
||||||
|
);
|
||||||
|
echo htmlSelect( 'StatusFilter', $status_options, ( isset($_SESSION['StatusFilter']) ? $_SESSION['StatusFilter'] : '' ), array('onchange'=>'changeFilter(this);') );
|
||||||
|
?>
|
||||||
|
</span>
|
||||||
|
</div>
|
|
@ -0,0 +1,14 @@
|
||||||
|
<input type="hidden" name="newMonitor[Method]" value="<?php echo validHtmlStr($monitor->Method()) ?>"/>
|
||||||
|
<tr><td><?php echo translate('HostName') ?></td><td><input type="text" name="newMonitor[Host]" value="<?php echo validHtmlStr($monitor->Host()) ?>" size="36"/></td></tr>
|
||||||
|
<tr><td><?php echo translate('Port') ?></td><td><input type="number" name="newMonitor[Port]" value="<?php echo validHtmlStr($monitor->Port()) ?>" size="6"/></td></tr>
|
||||||
|
<tr><td><?php echo translate('Path') ?></td><td><input type="text" name="newMonitor[Path]" value="<?php echo validHtmlStr($monitor->Path()) ?>" size="36"/></td></tr>
|
||||||
|
<input type="hidden" name="newMonitor[User]" value="<?php echo validHtmlStr($monitor->User()) ?>"/>
|
||||||
|
<input type="hidden" name="newMonitor[Pass]" value="<?php echo validHtmlStr($monitor->Pass()) ?>"/>
|
||||||
|
<input type="hidden" name="newMonitor[Options]" value="<?php echo validHtmlStr($monitor->Options()) ?>"/>
|
||||||
|
<tr><td><?php echo translate('TargetColorspace') ?></td><td><select name="newMonitor[Colours]"><?php foreach ( $Colours as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->Colours()) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
|
||||||
|
<tr><td><?php echo translate('CaptureWidth') ?> (<?php echo translate('Pixels') ?>)</td><td><input type="number" name="newMonitor[Width]" value="<?php echo validHtmlStr($monitor->Width()) ?>" size="4" onkeyup="updateMonitorDimensions(this);"/></td></tr>
|
||||||
|
<tr><td><?php echo translate('CaptureHeight') ?> (<?php echo translate('Pixels') ?>)</td><td><input type="number" name="newMonitor[Height]" value="<?php echo validHtmlStr($monitor->Height()) ?>" size="4" onkeyup="updateMonitorDimensions(this);"/></td></tr>
|
||||||
|
<tr><td><?php echo translate('PreserveAspect') ?></td><td><input type="checkbox" name="preserveAspectRatio" value="1"/></td></tr>
|
||||||
|
<tr><td><?php echo translate('Orientation') ?></td><td><?php echo htmlselect( 'newMonitor[Orientation]', $orientations, $monitor->Orientation() );?></td></tr>
|
||||||
|
<input type="hidden" name="newMonitor[Deinterlacing]" value="<?php echo validHtmlStr($monitor->Deinterlacing()) ?>"/>
|
||||||
|
<input type="hidden" name="newMonitor[RTSPDescribe]" value="<?php echo validHtmlStr($monitor->RTSPDescribe()) ?>"/>
|
|
@ -0,0 +1,112 @@
|
||||||
|
<?php
|
||||||
|
//
|
||||||
|
// ZoneMinder web function view file, $Date$, $Revision$
|
||||||
|
// Copyright (C) 2017 ZoneMinder LLC
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
if ( !canEdit( 'Monitors' ) ) {
|
||||||
|
$view = 'error';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$focusWindow = true;
|
||||||
|
$navbar = getNavBarHTML();
|
||||||
|
|
||||||
|
xhtmlHeaders(__FILE__, translate('AddMonitors'));
|
||||||
|
?>
|
||||||
|
<body>
|
||||||
|
<div id="page">
|
||||||
|
<?php echo $navbar ?>
|
||||||
|
<div id="content">
|
||||||
|
|
||||||
|
<form name="contentForm" id="contentForm" method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>">
|
||||||
|
<div style="position:relative;">
|
||||||
|
<div id="results" style="position: absolute; top:0; right: 0; width: 50%; height: 100%;">
|
||||||
|
<fieldset><legend>Results</legend>
|
||||||
|
<div id="url_results">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
<div style="width:50%;position: absolute; top:0; left: 0;height: 100%;">
|
||||||
|
<fieldset><legend>Enter by IP or URL</legend>
|
||||||
|
<!--<input type="text" name="newMonitor[Name]" />-->
|
||||||
|
<input type="url" name="newMonitor[Url]" oninput="probe(this);"/>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset><legend>Import CSV Spreadsheet</legend>
|
||||||
|
Spreadsheet should have the following format:<br/>
|
||||||
|
<table class="major">
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>URL</th>
|
||||||
|
<th>Group</th>
|
||||||
|
</tr>
|
||||||
|
<tr title="Example Data">
|
||||||
|
<td>Example Name MN1-30 INQ37.01</td>
|
||||||
|
<td>http://10.34.152.20:2001/?action=stream</td>
|
||||||
|
<td>MN1</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
Defaults to apply to each monitor:<br/>
|
||||||
|
<table><tr><th>Setting</th><th>Value</th></tr>
|
||||||
|
<tr><td><?php echo translate('Function') ?></td><td>
|
||||||
|
<?php
|
||||||
|
$options = array();
|
||||||
|
foreach ( getEnumValues('Monitors', 'Function') as $opt ) {
|
||||||
|
$options[$opt] = translate('Fn'.$opt);
|
||||||
|
}
|
||||||
|
echo htmlSelect( 'newMonitor[Function]', $options, 'Record' );
|
||||||
|
?>
|
||||||
|
</td></tr>
|
||||||
|
<?php
|
||||||
|
$servers = Server::find_all();
|
||||||
|
$ServersById = array();
|
||||||
|
foreach ( $servers as $S ) {
|
||||||
|
$ServersById[$S->Id()] = $S;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( count($ServersById) > 0 ) { ?>
|
||||||
|
<tr class="Server"><td><?php echo translate('Server')?></td><td>
|
||||||
|
<?php echo htmlSelect( 'newMonitor[ServerId]', array(''=>'Auto')+$ServersById, '' ); ?>
|
||||||
|
</td></tr>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
$storage_areas = Storage::find_all();
|
||||||
|
$StorageById = array();
|
||||||
|
foreach ( $storage_areas as $S ) {
|
||||||
|
$StorageById[$S->Id()] = $S;
|
||||||
|
}
|
||||||
|
if ( count($StorageById) > 0 ) {
|
||||||
|
?>
|
||||||
|
<tr class="Storage"><td><?php echo translate('Storage')?></td><td>
|
||||||
|
<?php echo htmlSelect( 'newMonitor[StorageId]', array(''=>'All')+$StorageById, 1 ); ?>
|
||||||
|
</tr>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<input type="file" name="import_file" id="import_file"/>
|
||||||
|
<input type="button" value="Import" onclick="import_csv(this.form);"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php xhtmlFooter() ?>
|
|
@ -18,36 +18,6 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
//
|
//
|
||||||
|
|
||||||
$servers = Server::find_all();
|
|
||||||
$ServersById = array();
|
|
||||||
foreach ( $servers as $S ) {
|
|
||||||
$ServersById[$S->Id()] = $S;
|
|
||||||
}
|
|
||||||
session_start();
|
|
||||||
foreach ( array('ServerFilter','StorageFilter') as $var ) {
|
|
||||||
if ( isset( $_REQUEST[$var] ) ) {
|
|
||||||
if ( $_REQUEST[$var] != '' ) {
|
|
||||||
$_SESSION[$var] = $_REQUEST[$var];
|
|
||||||
} else {
|
|
||||||
unset( $_SESSION[$var] );
|
|
||||||
}
|
|
||||||
} else if ( isset( $_COOKIE[$var] ) ) {
|
|
||||||
if ( $_COOKIE[$var] != '' ) {
|
|
||||||
$_SESSION[$var] = $_COOKIE[$var];
|
|
||||||
} else {
|
|
||||||
unset($_SESSION[$var]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
session_write_close();
|
|
||||||
|
|
||||||
$storage_areas = Storage::find_all();
|
|
||||||
$StorageById = array();
|
|
||||||
foreach ( $storage_areas as $S ) {
|
|
||||||
$StorageById[$S->Id()] = $S;
|
|
||||||
}
|
|
||||||
|
|
||||||
$show_storage_areas = count($storage_areas) > 1 and canEdit( 'System' ) ? 1 : 0;
|
|
||||||
if ( $running == null )
|
if ( $running == null )
|
||||||
$running = daemonCheck();
|
$running = daemonCheck();
|
||||||
|
|
||||||
|
@ -120,6 +90,46 @@ $eventCounts = array(
|
||||||
|
|
||||||
|
|
||||||
$navbar = getNavBarHTML();
|
$navbar = getNavBarHTML();
|
||||||
|
ob_start();
|
||||||
|
include('_monitor_filters.php');
|
||||||
|
$filterbar = ob_get_contents();
|
||||||
|
ob_end_clean();
|
||||||
|
|
||||||
|
$show_storage_areas = count($storage_areas) > 1 and canEdit( 'System' ) ? 1 : 0;
|
||||||
|
$maxWidth = 0;
|
||||||
|
$maxHeight = 0;
|
||||||
|
$zoneCount = 0;
|
||||||
|
for ( $i = 0; $i < count($displayMonitors); $i++ ) {
|
||||||
|
$monitor = &$displayMonitors[$i];
|
||||||
|
if ( $monitor['Function'] != 'None' ) {
|
||||||
|
$scaleWidth = reScale( $monitor['Width'], $monitor['DefaultScale'], ZM_WEB_DEFAULT_SCALE );
|
||||||
|
$scaleHeight = reScale( $monitor['Height'], $monitor['DefaultScale'], ZM_WEB_DEFAULT_SCALE );
|
||||||
|
if ( $maxWidth < $scaleWidth ) $maxWidth = $scaleWidth;
|
||||||
|
if ( $maxHeight < $scaleHeight ) $maxHeight = $scaleHeight;
|
||||||
|
}
|
||||||
|
$monitor['zmc'] = zmcStatus( $monitor );
|
||||||
|
$monitor['zma'] = zmaStatus( $monitor );
|
||||||
|
$monitor['ZoneCount'] = dbFetchOne( 'select count(Id) as ZoneCount from Zones where MonitorId = ?', 'ZoneCount', array($monitor['Id']) );
|
||||||
|
$zoneCount += $monitor['ZoneCount'];
|
||||||
|
|
||||||
|
$counts = array();
|
||||||
|
for ( $j = 0; $j < count($eventCounts); $j += 1 ) {
|
||||||
|
$filter = addFilterTerm( $eventCounts[$j]['filter'], count($eventCounts[$j]['filter']['Query']['terms']), array( 'cnj' => 'and', 'attr' => 'MonitorId', 'op' => '=', 'val' => $monitor['Id'] ) );
|
||||||
|
parseFilter( $filter );
|
||||||
|
$counts[] = 'count(if(1'.$filter['sql'].",1,NULL)) AS EventCount$j, SUM(if(1".$filter['sql'].",DiskSpace,NULL)) As DiskSpace$j";
|
||||||
|
$monitor['eventCounts'][$j]['filter'] = $filter;
|
||||||
|
}
|
||||||
|
$sql = 'SELECT '.join($counts,', ').' FROM Events as E where MonitorId = ?';
|
||||||
|
$counts = dbFetchOne( $sql, NULL, array($monitor['Id']) );
|
||||||
|
if ( $counts )
|
||||||
|
$monitor = array_merge( $monitor, $counts );
|
||||||
|
for ( $j = 0; $j < count($eventCounts); $j += 1 ) {
|
||||||
|
$eventCounts[$j]['total'] += $monitor['EventCount'.$j];
|
||||||
|
}
|
||||||
|
unset($monitor);
|
||||||
|
}
|
||||||
|
$cycleWidth = $maxWidth;
|
||||||
|
$cycleHeight = $maxHeight;
|
||||||
|
|
||||||
noCacheHeaders();
|
noCacheHeaders();
|
||||||
|
|
||||||
|
@ -137,128 +147,7 @@ xhtmlHeaders( __FILE__, translate('Console') );
|
||||||
<input type="hidden" name="action" value=""/>
|
<input type="hidden" name="action" value=""/>
|
||||||
|
|
||||||
<?php echo $navbar ?>
|
<?php echo $navbar ?>
|
||||||
<div class="controlHeader">
|
<?php echo $filterbar ?>
|
||||||
<span id="groupControl"><label><?php echo translate('Group') ?>:</label>
|
|
||||||
<?php
|
|
||||||
# This will end up with the group_id of the deepest selection
|
|
||||||
$group_id = Group::get_group_dropdowns();
|
|
||||||
$groupSql = Group::get_group_sql( $group_id );
|
|
||||||
?>
|
|
||||||
</span>
|
|
||||||
<span id="monitorControl"><label><?php echo translate('Monitor') ?>:</label>
|
|
||||||
<?php
|
|
||||||
|
|
||||||
$monitor_id = 0;
|
|
||||||
if ( isset( $_REQUEST['monitor_id'] ) ) {
|
|
||||||
$monitor_id = $_REQUEST['monitor_id'];
|
|
||||||
} else if ( isset($_COOKIE['zmMonitorId']) ) {
|
|
||||||
$monitor_id = $_COOKIE['zmMonitorId'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$maxWidth = 0;
|
|
||||||
$maxHeight = 0;
|
|
||||||
# Used to determine if the Cycle button should be made available
|
|
||||||
|
|
||||||
$conditions = array();
|
|
||||||
$values = array();
|
|
||||||
|
|
||||||
if ( $groupSql )
|
|
||||||
$conditions[] = $groupSql;
|
|
||||||
if ( isset($_SESSION['ServerFilter']) ) {
|
|
||||||
$conditions[] = 'ServerId=?';
|
|
||||||
$values[] = $_SESSION['ServerFilter'];
|
|
||||||
}
|
|
||||||
if ( isset($_SESSION['StorageFilter']) ) {
|
|
||||||
$conditions[] = 'StorageId=?';
|
|
||||||
$values[] = $_SESSION['StorageFilter'];
|
|
||||||
}
|
|
||||||
$sql = 'SELECT * FROM Monitors' . ( count($conditions) ? ' WHERE ' . implode(' AND ', $conditions ) : '' ).' ORDER BY Sequence ASC';
|
|
||||||
$monitors = dbFetchAll( $sql, null, $values );
|
|
||||||
$displayMonitors = array();
|
|
||||||
$monitors_dropdown = array(''=>'All');
|
|
||||||
|
|
||||||
if ( $monitor_id ) {
|
|
||||||
$found_selected_monitor = false;
|
|
||||||
|
|
||||||
for ( $i = 0; $i < count($monitors); $i++ ) {
|
|
||||||
if ( !visibleMonitor( $monitors[$i]['Id'] ) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$monitors_dropdown[$monitors[$i]['Id']] = $monitors[$i]['Name'];
|
|
||||||
if ( $monitors[$i]['Id'] == $monitor_id ) {
|
|
||||||
$found_selected_monitor = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( ! $found_selected_monitor ) {
|
|
||||||
$monitor_id = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for ( $i = 0; $i < count($monitors); $i++ ) {
|
|
||||||
if ( !visibleMonitor( $monitors[$i]['Id'] ) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$monitors_dropdown[$monitors[$i]['Id']] = $monitors[$i]['Name'];
|
|
||||||
|
|
||||||
if ( $monitor_id and ( $monitors[$i]['Id'] != $monitor_id ) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ( $monitors[$i]['Function'] != 'None' ) {
|
|
||||||
$scaleWidth = reScale( $monitors[$i]['Width'], $monitors[$i]['DefaultScale'], ZM_WEB_DEFAULT_SCALE );
|
|
||||||
$scaleHeight = reScale( $monitors[$i]['Height'], $monitors[$i]['DefaultScale'], ZM_WEB_DEFAULT_SCALE );
|
|
||||||
if ( $maxWidth < $scaleWidth ) $maxWidth = $scaleWidth;
|
|
||||||
if ( $maxHeight < $scaleHeight ) $maxHeight = $scaleHeight;
|
|
||||||
}
|
|
||||||
$displayMonitors[] = $monitors[$i];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
echo htmlSelect( 'monitor_id', $monitors_dropdown, $monitor_id, array('onchange'=>'changeMonitor(this);') );
|
|
||||||
|
|
||||||
$cycleWidth = $maxWidth;
|
|
||||||
$cycleHeight = $maxHeight;
|
|
||||||
$zoneCount = 0;
|
|
||||||
|
|
||||||
for( $i = 0; $i < count($displayMonitors); $i += 1 ) {
|
|
||||||
$monitor = $displayMonitors[$i];
|
|
||||||
$monitor['zmc'] = zmcStatus( $monitor );
|
|
||||||
$monitor['zma'] = zmaStatus( $monitor );
|
|
||||||
$monitor['ZoneCount'] = dbFetchOne( 'select count(Id) as ZoneCount from Zones where MonitorId = ?', 'ZoneCount', array($monitor['Id']) );
|
|
||||||
$counts = array();
|
|
||||||
for ( $j = 0; $j < count($eventCounts); $j += 1 ) {
|
|
||||||
$filter = addFilterTerm( $eventCounts[$j]['filter'], count($eventCounts[$j]['filter']['Query']['terms']), array( 'cnj' => 'and', 'attr' => 'MonitorId', 'op' => '=', 'val' => $monitor['Id'] ) );
|
|
||||||
parseFilter( $filter );
|
|
||||||
$counts[] = 'count(if(1'.$filter['sql'].",1,NULL)) AS EventCount$j, SUM(if(1".$filter['sql'].",DiskSpace,NULL)) As DiskSpace$j";
|
|
||||||
$monitor['eventCounts'][$j]['filter'] = $filter;
|
|
||||||
}
|
|
||||||
$sql = 'SELECT '.join($counts,', ').' FROM Events as E where MonitorId = ?';
|
|
||||||
$counts = dbFetchOne( $sql, NULL, array($monitor['Id']) );
|
|
||||||
if ( $counts )
|
|
||||||
$displayMonitors[$i] = $monitor = array_merge( $monitor, $counts );
|
|
||||||
for ( $j = 0; $j < count($eventCounts); $j += 1 ) {
|
|
||||||
$eventCounts[$j]['total'] += $monitor['EventCount'.$j];
|
|
||||||
}
|
|
||||||
$zoneCount += $monitor['ZoneCount'];
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</span>
|
|
||||||
<?php if ( count($ServersById) > 0 ) { ?>
|
|
||||||
<span class="ServerFilter"><label><?php echo translate('Server')?>:</label>
|
|
||||||
<?php
|
|
||||||
echo htmlSelect( 'ServerFilter', array(''=>'All')+$ServersById, (isset($_SESSION['ServerFilter'])?$_SESSION['ServerFilter']:''), array('onchange'=>'changeFilter(this);') );
|
|
||||||
?>
|
|
||||||
</span>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
if ( count($StorageById) > 0 ) { ?>
|
|
||||||
<span class="StorageFilter"><label><?php echo translate('Storage')?>:</label>
|
|
||||||
<?php
|
|
||||||
echo htmlSelect( 'StorageFilter', array(''=>'All')+$StorageById, (isset($_SESSION['StorageFilter'])?$_SESSION['StorageFilter']:''), array('onchange'=>'changeFilter(this);') );
|
|
||||||
?>
|
|
||||||
</span>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<table class="table table-striped table-hover table-condensed" id="consoleTable">
|
<table class="table table-striped table-hover table-condensed" id="consoleTable">
|
||||||
|
|
|
@ -69,10 +69,14 @@ $attrTypes = array(
|
||||||
'Name' => translate('AttrName'),
|
'Name' => translate('AttrName'),
|
||||||
'Cause' => translate('AttrCause'),
|
'Cause' => translate('AttrCause'),
|
||||||
'Notes' => translate('AttrNotes'),
|
'Notes' => translate('AttrNotes'),
|
||||||
'DateTime' => translate('AttrDateTime'),
|
'StartDateTime' => translate('AttrStartDateTime'),
|
||||||
'Date' => translate('AttrDate'),
|
'StartDate' => translate('AttrStartDate'),
|
||||||
'Time' => translate('AttrTime'),
|
'StartTime' => translate('AttrStartTime'),
|
||||||
'Weekday' => translate('AttrWeekday'),
|
'StartWeekday' => translate('AttrStartWeekday'),
|
||||||
|
'EndDateTime' => translate('AttrEndDateTime'),
|
||||||
|
'EndDate' => translate('AttrEndDate'),
|
||||||
|
'EndTime' => translate('AttrEndTime'),
|
||||||
|
'EndWeekday' => translate('AttrEndWeekday'),
|
||||||
'Length' => translate('AttrDuration'),
|
'Length' => translate('AttrDuration'),
|
||||||
'Frames' => translate('AttrFrames'),
|
'Frames' => translate('AttrFrames'),
|
||||||
'AlarmFrames' => translate('AttrAlarmFrames'),
|
'AlarmFrames' => translate('AttrAlarmFrames'),
|
||||||
|
@ -80,8 +84,9 @@ $attrTypes = array(
|
||||||
'AvgScore' => translate('AttrAvgScore'),
|
'AvgScore' => translate('AttrAvgScore'),
|
||||||
'MaxScore' => translate('AttrMaxScore'),
|
'MaxScore' => translate('AttrMaxScore'),
|
||||||
'Archived' => translate('AttrArchiveStatus'),
|
'Archived' => translate('AttrArchiveStatus'),
|
||||||
'DiskPercent' => translate('AttrDiskPercent'),
|
|
||||||
'DiskBlocks' => translate('AttrDiskBlocks'),
|
'DiskBlocks' => translate('AttrDiskBlocks'),
|
||||||
|
'DiskPercent' => translate('AttrDiskPercent'),
|
||||||
|
'DiskSpace' => translate('AttrDiskSpace'),
|
||||||
'SystemLoad' => translate('AttrSystemLoad'),
|
'SystemLoad' => translate('AttrSystemLoad'),
|
||||||
'StorageId' => translate('AttrStorageArea'),
|
'StorageId' => translate('AttrStorageArea'),
|
||||||
'ServerId' => translate('AttrServer'),
|
'ServerId' => translate('AttrServer'),
|
||||||
|
@ -99,6 +104,8 @@ $opTypes = array(
|
||||||
'!~' => translate('OpNotMatches'),
|
'!~' => translate('OpNotMatches'),
|
||||||
'=[]' => translate('OpIn'),
|
'=[]' => translate('OpIn'),
|
||||||
'![]' => translate('OpNotIn'),
|
'![]' => translate('OpNotIn'),
|
||||||
|
'IS' => translate('OpIs'),
|
||||||
|
'IS NOT' => translate('OpIsNot'),
|
||||||
);
|
);
|
||||||
|
|
||||||
$archiveTypes = array(
|
$archiveTypes = array(
|
||||||
|
@ -297,18 +304,19 @@ if ( count($terms) == 0 ) {
|
||||||
<label for="filter[Query][sort_field]"><?php echo translate('SortBy') ?></label>
|
<label for="filter[Query][sort_field]"><?php echo translate('SortBy') ?></label>
|
||||||
<?php
|
<?php
|
||||||
$sort_fields = array(
|
$sort_fields = array(
|
||||||
'Id' => translate('AttrId'),
|
'Id' => translate('AttrId'),
|
||||||
'Name' => translate('AttrName'),
|
'Name' => translate('AttrName'),
|
||||||
'Cause' => translate('AttrCause'),
|
'Cause' => translate('AttrCause'),
|
||||||
'Notes' => translate('AttrNotes'),
|
'DiskSpace' => translate('AttrDiskSpace'),
|
||||||
'MonitorName' => translate('AttrMonitorName'),
|
'Notes' => translate('AttrNotes'),
|
||||||
'DateTime' => translate('AttrDateTime'),
|
'MonitorName' => translate('AttrMonitorName'),
|
||||||
'Length' => translate('AttrDuration'),
|
'StartDateTime' => translate('AttrStartDateTime'),
|
||||||
'Frames' => translate('AttrFrames'),
|
'Length' => translate('AttrDuration'),
|
||||||
'AlarmFrames' => translate('AttrAlarmFrames'),
|
'Frames' => translate('AttrFrames'),
|
||||||
'TotScore' => translate('AttrTotalScore'),
|
'AlarmFrames' => translate('AttrAlarmFrames'),
|
||||||
'AvgScore' => translate('AttrAvgScore'),
|
'TotScore' => translate('AttrTotalScore'),
|
||||||
'MaxScore' => translate('AttrMaxScore'),
|
'AvgScore' => translate('AttrAvgScore'),
|
||||||
|
'MaxScore' => translate('AttrMaxScore'),
|
||||||
);
|
);
|
||||||
echo htmlSelect( 'filter[Query][sort_field]', $sort_fields, $filter->sort_field() );
|
echo htmlSelect( 'filter[Query][sort_field]', $sort_fields, $filter->sort_field() );
|
||||||
$sort_dirns = array(
|
$sort_dirns = array(
|
||||||
|
@ -332,6 +340,9 @@ echo htmlSelect( 'filter[Query][sort_asc]', $sort_dirns, $filter->sort_asc() );
|
||||||
<label><?php echo translate('FilterArchiveEvents') ?></label>
|
<label><?php echo translate('FilterArchiveEvents') ?></label>
|
||||||
<input type="checkbox" name="filter[AutoArchive]" value="1"<?php if ( !empty($filter->AutoArchive()) ) { ?> checked="checked"<?php } ?> onclick="updateButtons( this )"/>
|
<input type="checkbox" name="filter[AutoArchive]" value="1"<?php if ( !empty($filter->AutoArchive()) ) { ?> checked="checked"<?php } ?> onclick="updateButtons( this )"/>
|
||||||
</p>
|
</p>
|
||||||
|
<p><label><?php echo translate('FilterUpdateDiskSpace') ?></label>
|
||||||
|
<input type="checkbox" name="filter[UpdateDiskSpace]" value="1"<?php echo empty($filter->UpdateDiskSpace()) ? '' : ' checked="checked"' ?> onclick="updateButtons(this);"/>
|
||||||
|
</p>
|
||||||
<?php
|
<?php
|
||||||
if ( ZM_OPT_FFMPEG ) {
|
if ( ZM_OPT_FFMPEG ) {
|
||||||
?>
|
?>
|
||||||
|
@ -387,7 +398,7 @@ if ( ZM_OPT_MESSAGE ) {
|
||||||
</div>
|
</div>
|
||||||
<hr/>
|
<hr/>
|
||||||
<div id="contentButtons">
|
<div id="contentButtons">
|
||||||
<input type="submit" value="<?php echo translate('Submit') ?>" onclick="submitToEvents( this );"/>
|
<input type="submit" value="<?php echo translate('ListMatches') ?>" onclick="submitToEvents( this );"/>
|
||||||
<input type="button" name="executeButton" id="executeButton" value="<?php echo translate('Execute') ?>" onclick="executeFilter( this );"/>
|
<input type="button" name="executeButton" id="executeButton" value="<?php echo translate('Execute') ?>" onclick="executeFilter( this );"/>
|
||||||
<?php
|
<?php
|
||||||
if ( canEdit( 'Events' ) ) {
|
if ( canEdit( 'Events' ) ) {
|
||||||
|
|
|
@ -87,9 +87,11 @@ function get_children($Group) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$kids = get_children($newGroup);
|
$kids = get_children($newGroup);
|
||||||
$kids[] = $newGroup->Id();
|
if ( $newGroup->Id() )
|
||||||
|
$kids[] = $newGroup->Id();
|
||||||
|
$sql = 'SELECT Id,Name from Groups'.(count($kids)?' WHERE Id NOT IN ('.implode(',',array_map(function(){return '?';}, $kids )).')' : '').' ORDER BY Name';
|
||||||
$options = array(''=>'None');
|
$options = array(''=>'None');
|
||||||
foreach ( dbFetchAll( 'SELECT Id,Name from Groups WHERE Id NOT IN ('.implode(',',array_map(function(){return '?';}, $kids )).') ORDER BY Name', null, $kids ) as $option ) {
|
foreach ( dbFetchAll( $sql, null, $kids ) as $option ) {
|
||||||
$options[$option['Id']] = $option['Name'];
|
$options[$option['Id']] = $option['Name'];
|
||||||
}
|
}
|
||||||
echo htmlSelect( 'newGroup[ParentId]', $options, $newGroup->ParentId(), array('onchange'=>'configureButtons(this);' ));
|
echo htmlSelect( 'newGroup[ParentId]', $options, $newGroup->ParentId(), array('onchange'=>'configureButtons(this);' ));
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
|
||||||
|
var probeReq = new Request.JSON( { url:thisUrl, method: 'get', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getProbeResponse } );
|
||||||
|
|
||||||
|
function probe( url_e ) {
|
||||||
|
probeReq.send( "request=add_monitors&action=probe&url="+url_e.value );
|
||||||
|
}
|
||||||
|
|
||||||
|
var ProbeResults;
|
||||||
|
|
||||||
|
function getProbeResponse( respObj, respText ) {
|
||||||
|
if ( checkStreamForErrors( "getProbeResponse", respObj ) )
|
||||||
|
return;
|
||||||
|
//alert(respText);
|
||||||
|
|
||||||
|
if ( respObj.Streams ) {
|
||||||
|
parseStreams( respObj.Streams );
|
||||||
|
} else {
|
||||||
|
alert("No Streams");
|
||||||
|
}
|
||||||
|
} // end function getProbeResponse
|
||||||
|
|
||||||
|
function parseStreams( Streams ) {
|
||||||
|
ProbeResults = Array();
|
||||||
|
|
||||||
|
var results_div = $j('#url_results')[0];
|
||||||
|
if ( ! results_div ) {
|
||||||
|
console.log("No results div found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
results_div.innerHTML = '';
|
||||||
|
var html = '';
|
||||||
|
|
||||||
|
for( i in Streams ) {
|
||||||
|
var stream = Streams[i];
|
||||||
|
if ( stream.url ) {
|
||||||
|
html += '<p>'+stream.url;
|
||||||
|
if ( stream.Monitor.Id ) {
|
||||||
|
html += ' is already entered into the system by Monitor ' + stream.Monitor.Id + ' ' + stream.Monitor.Name + '<br/>';
|
||||||
|
html += '<input type="button" value="Edit" onclick="addMonitor(\''+stream.url+'\');"/>';
|
||||||
|
} else {
|
||||||
|
html += '<input type="button" value="Add" onclick="addMonitor(\''+stream.url+'\');"/>';
|
||||||
|
}
|
||||||
|
html += '</p>';
|
||||||
|
ProbeResults[stream.url] = stream;
|
||||||
|
} else {
|
||||||
|
//console.log(stream);
|
||||||
|
}
|
||||||
|
} // end for eah Stream
|
||||||
|
|
||||||
|
results_div.innerHTML = html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addMonitor(url) {
|
||||||
|
if ( ! ProbeResults[url] ) {
|
||||||
|
alert("Monitor for url " + url + " not found in probe results." );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var Stream = ProbeResults[url];
|
||||||
|
var Monitor = Stream.Monitor;
|
||||||
|
|
||||||
|
popup_url = '?view=monitor&newMonitor[Path]='+url;
|
||||||
|
keys = Object.keys( Monitor );
|
||||||
|
for ( i in Monitor ) {
|
||||||
|
if ( ! Monitor[i] )
|
||||||
|
continue;
|
||||||
|
if ( Monitor[i] == 'null' )
|
||||||
|
Monitor[i]='';
|
||||||
|
popup_url += '&newMonitor['+i+']='+Monitor[i];
|
||||||
|
}
|
||||||
|
createPopup( popup_url, 'zmMonitor0', 'monitor' );
|
||||||
|
}
|
||||||
|
|
||||||
|
function import_csv( form ) {
|
||||||
|
var formData = new FormData( form );
|
||||||
|
console.log(formData);
|
||||||
|
//formData.append('file', $('#file')[0].files[0]);
|
||||||
|
|
||||||
|
$j.ajax({
|
||||||
|
url : thisUrl+"?request=add_monitors&action=import",
|
||||||
|
type : 'POST',
|
||||||
|
data : formData,
|
||||||
|
processData: false, // tell jQuery not to process the data
|
||||||
|
contentType: false, // tell jQuery not to set contentType
|
||||||
|
success : function(data) {
|
||||||
|
var json = JSON.parse(data);
|
||||||
|
parseStreams( json.Streams );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ function setButtonStates( element ) {
|
||||||
form.deleteBtn.disabled = (checked==0);
|
form.deleteBtn.disabled = (checked==0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addMonitor( element) {
|
function addMonitor(element) {
|
||||||
var form = element.form;
|
var form = element.form;
|
||||||
var dupParam;
|
var dupParam;
|
||||||
var monitorId=-1;
|
var monitorId=-1;
|
||||||
|
|
|
@ -19,6 +19,8 @@ function updateButtons( element ) {
|
||||||
canExecute = true;
|
canExecute = true;
|
||||||
else if ( form.elements['filter[AutoDelete]'].checked )
|
else if ( form.elements['filter[AutoDelete]'].checked )
|
||||||
canExecute = true;
|
canExecute = true;
|
||||||
|
else if ( form.elements['filter[UpdateDiskSpace]'].checked )
|
||||||
|
canExecute = true;
|
||||||
form.elements['executeButton'].disabled = !canExecute;
|
form.elements['executeButton'].disabled = !canExecute;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ function validateForm( form ) {
|
||||||
else if ( form.elements.mid.value == 0 && monitorNames[form.elements['newMonitor[Name]'].value] )
|
else if ( form.elements.mid.value == 0 && monitorNames[form.elements['newMonitor[Name]'].value] )
|
||||||
errors[errors.length] = "<?php echo translate('DuplicateMonitorName') ?>";
|
errors[errors.length] = "<?php echo translate('DuplicateMonitorName') ?>";
|
||||||
|
|
||||||
if ( form.elements['newMonitor[AnalysisFPS]'].value && !(parseFloat(form.elements['newMonitor[AnalysisFPS]'].value) > 0 ) )
|
if ( form.elements['newMonitor[AnalysisFPSLimit]'].value && !(parseFloat(form.elements['newMonitor[AnalysisFPSLimit]'].value) > 0 ) )
|
||||||
errors[errors.length] = "<?php echo translate('BadAnalysisFPS') ?>";
|
errors[errors.length] = "<?php echo translate('BadAnalysisFPS') ?>";
|
||||||
if ( form.elements['newMonitor[MaxFPS]'].value && !(parseFloat(form.elements['newMonitor[MaxFPS]'].value) > 0 ) )
|
if ( form.elements['newMonitor[MaxFPS]'].value && !(parseFloat(form.elements['newMonitor[MaxFPS]'].value) > 0 ) )
|
||||||
errors[errors.length] = "<?php echo translate('BadMaxFPS') ?>";
|
errors[errors.length] = "<?php echo translate('BadMaxFPS') ?>";
|
||||||
|
@ -97,7 +97,7 @@ function validateForm( form ) {
|
||||||
errors[errors.length] = "<?php echo translate('BadImageBufferCount') ?>";
|
errors[errors.length] = "<?php echo translate('BadImageBufferCount') ?>";
|
||||||
if ( !form.elements['newMonitor[WarmupCount]'].value || !(parseInt(form.elements['newMonitor[WarmupCount]'].value) >= 0 ) )
|
if ( !form.elements['newMonitor[WarmupCount]'].value || !(parseInt(form.elements['newMonitor[WarmupCount]'].value) >= 0 ) )
|
||||||
errors[errors.length] = "<?php echo translate('BadWarmupCount') ?>";
|
errors[errors.length] = "<?php echo translate('BadWarmupCount') ?>";
|
||||||
if ( !form.elements['newMonitor[PreEventCount]'].value || !(parseInt(form.elements['newMonitor[PreEventCount]'].value) > 0 ) || (parseInt(form.elements['newMonitor[PreEventCount]'].value) > parseInt(form.elements['newMonitor[ImageBufferCount]'].value)) )
|
if ( !form.elements['newMonitor[PreEventCount]'].value || !(parseInt(form.elements['newMonitor[PreEventCount]'].value) >= 0 ) || (parseInt(form.elements['newMonitor[PreEventCount]'].value) > parseInt(form.elements['newMonitor[ImageBufferCount]'].value)) )
|
||||||
errors[errors.length] = "<?php echo translate('BadPreEventCount') ?>";
|
errors[errors.length] = "<?php echo translate('BadPreEventCount') ?>";
|
||||||
if ( !form.elements['newMonitor[PostEventCount]'].value || !(parseInt(form.elements['newMonitor[PostEventCount]'].value) >= 0 ) )
|
if ( !form.elements['newMonitor[PostEventCount]'].value || !(parseInt(form.elements['newMonitor[PostEventCount]'].value) >= 0 ) )
|
||||||
errors[errors.length] = "<?php echo translate('BadPostEventCount') ?>";
|
errors[errors.length] = "<?php echo translate('BadPostEventCount') ?>";
|
||||||
|
|
|
@ -7,11 +7,10 @@ function Monitor( monitorData ) {
|
||||||
this.status = null;
|
this.status = null;
|
||||||
this.alarmState = STATE_IDLE;
|
this.alarmState = STATE_IDLE;
|
||||||
this.lastAlarmState = STATE_IDLE;
|
this.lastAlarmState = STATE_IDLE;
|
||||||
this.streamCmdParms = "view=request&request=stream&connkey="+this.connKey;
|
this.streamCmdParms = 'view=request&request=stream&connkey='+this.connKey;
|
||||||
|
this.onclick = monitorData.onclick;
|
||||||
if ( auth_hash )
|
if ( auth_hash )
|
||||||
this.streamCmdParms += '&auth='+auth_hash;
|
this.streamCmdParms += '&auth='+auth_hash;
|
||||||
else
|
|
||||||
console.log("No auth_hash");
|
|
||||||
this.streamCmdTimer = null;
|
this.streamCmdTimer = null;
|
||||||
|
|
||||||
this.start = function( delay ) {
|
this.start = function( delay ) {
|
||||||
|
@ -34,7 +33,8 @@ function Monitor( monitorData ) {
|
||||||
if ( this.streamCmdTimer )
|
if ( this.streamCmdTimer )
|
||||||
this.streamCmdTimer = clearTimeout( this.streamCmdTimer );
|
this.streamCmdTimer = clearTimeout( this.streamCmdTimer );
|
||||||
|
|
||||||
var stream = $j('#liveStream'+this.id )[0];
|
var stream = $j('#liveStream'+this.id)[0];
|
||||||
|
|
||||||
if ( respObj.result == 'Ok' ) {
|
if ( respObj.result == 'Ok' ) {
|
||||||
this.status = respObj.status;
|
this.status = respObj.status;
|
||||||
this.alarmState = this.status.state;
|
this.alarmState = this.status.state;
|
||||||
|
@ -83,42 +83,100 @@ function Monitor( monitorData ) {
|
||||||
// Try to reload the image stream.
|
// Try to reload the image stream.
|
||||||
if ( stream )
|
if ( stream )
|
||||||
stream.src = stream.src.replace( /auth=\w+/i, 'auth='+this.status.auth );
|
stream.src = stream.src.replace( /auth=\w+/i, 'auth='+this.status.auth );
|
||||||
console.log("Changed auth to " + this.status.auth );
|
console.log("Changed auth from " + auth_hash + " to " + this.status.auth );
|
||||||
|
auth_hash = this.status.auth;
|
||||||
}
|
}
|
||||||
} // end if haev a new auth hash
|
} // end if have a new auth hash
|
||||||
} else {
|
} else {
|
||||||
console.error( respObj.message );
|
console.error( respObj.message );
|
||||||
// Try to reload the image stream.
|
// Try to reload the image stream.
|
||||||
if ( stream )
|
if ( stream ) {
|
||||||
|
console.log('Reloading stream: ' + stream.src );
|
||||||
stream.src = stream.src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) ));
|
stream.src = stream.src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) ));
|
||||||
}
|
} else {
|
||||||
|
console.log( 'No stream to reload?' );
|
||||||
|
}
|
||||||
|
} // end if Ok or not
|
||||||
var streamCmdTimeout = statusRefreshTimeout;
|
var streamCmdTimeout = statusRefreshTimeout;
|
||||||
if ( this.alarmState == STATE_ALARM || this.alarmState == STATE_ALERT )
|
// The idea here is if we are alarmed, do updates faster. However, there is a timeout in the php side which isn't getting modified, so this may cause a problem. Also the server may only be able to update so fast.
|
||||||
streamCmdTimeout = streamCmdTimeout/5;
|
//if ( this.alarmState == STATE_ALARM || this.alarmState == STATE_ALERT ) {
|
||||||
|
//streamCmdTimeout = streamCmdTimeout/5;
|
||||||
|
//}
|
||||||
this.streamCmdTimer = this.streamCmdQuery.delay( streamCmdTimeout, this );
|
this.streamCmdTimer = this.streamCmdQuery.delay( streamCmdTimeout, this );
|
||||||
this.lastAlarmState = this.alarmState;
|
this.lastAlarmState = this.alarmState;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.streamCmdQuery = function( resent ) {
|
this.streamCmdQuery = function( resent ) {
|
||||||
//if ( resent )
|
if ( resent )
|
||||||
//console.log( this.connKey+": Resending" );
|
console.log( this.connKey+": Resending" );
|
||||||
//this.streamCmdReq.cancel();
|
//this.streamCmdReq.cancel();
|
||||||
this.streamCmdReq.send( this.streamCmdParms+"&command="+CMD_QUERY );
|
this.streamCmdReq.send( this.streamCmdParms+"&command="+CMD_QUERY );
|
||||||
};
|
};
|
||||||
|
this.onError = function( text, error ) {
|
||||||
|
console.log('onerror: ' + text + ' error:'+error);
|
||||||
|
};
|
||||||
|
this.onFailure = function( xhr ) {
|
||||||
|
console.log('onFailure: ' );
|
||||||
|
console.log(xhr );
|
||||||
|
};
|
||||||
|
|
||||||
this.streamCmdReq = new Request.JSON( { url: this.server_url, method: 'get', timeout: AJAX_TIMEOUT, onSuccess: this.getStreamCmdResponse.bind( this ), onTimeout: this.streamCmdQuery.bind( this, true ), link: 'cancel' } );
|
this.streamCmdReq = new Request.JSON( {
|
||||||
|
url: this.server_url,
|
||||||
|
method: 'get',
|
||||||
|
timeout: 1000+AJAX_TIMEOUT,
|
||||||
|
onSuccess: this.getStreamCmdResponse.bind( this ),
|
||||||
|
onTimeout: this.streamCmdQuery.bind( this, true ),
|
||||||
|
onError: this.onError.bind(this),
|
||||||
|
onFailure: this.onFailure.bind(this),
|
||||||
|
link: 'cancel'
|
||||||
|
} );
|
||||||
|
|
||||||
requestQueue.addRequest( "cmdReq"+this.id, this.streamCmdReq );
|
requestQueue.addRequest( "cmdReq"+this.id, this.streamCmdReq );
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectLayout( element ) {
|
function selectLayout( element ) {
|
||||||
layout = $(element).get('value')
|
layout = $j(element).val();
|
||||||
var cssFile = skinPath+'/css/'+Cookie.read('zmCSS')+'/views/'+layout;
|
|
||||||
if ( $('dynamicStyles') )
|
if ( layout_id = parseInt(layout) ) {
|
||||||
$('dynamicStyles').destroy();
|
layout = layouts[layout];
|
||||||
new Asset.css( cssFile, { id: 'dynamicStyles' } );
|
console.log(layout);
|
||||||
Cookie.write( 'zmMontageLayout', layout, { duration: 10*365 } );
|
|
||||||
if ( layout != 'montage_freeform.css' ) {
|
for ( var i = 0; i < monitors.length; i++ ) {
|
||||||
|
monitor = monitors[i];
|
||||||
|
// Need to clear the current positioning, and apply the new
|
||||||
|
|
||||||
|
monitor_frame = $j('#monitorFrame'+monitor.id);
|
||||||
|
if ( ! monitor_frame ) {
|
||||||
|
console.log("Error finding frame for " + monitor.id );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply default layout options, like float left
|
||||||
|
if ( layout.Positions['default'] ) {
|
||||||
|
styles = layout.Positions['default'];
|
||||||
|
for ( style in styles ) {
|
||||||
|
monitor_frame.css(style, styles[style]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("No default styles to apply" + layout.Positions);
|
||||||
|
} // end if default styles
|
||||||
|
|
||||||
|
if ( layout.Positions['mId'+monitor.id] ) {
|
||||||
|
styles = layout.Positions['mId'+monitor.id];
|
||||||
|
for ( style in styles ) {
|
||||||
|
monitor_frame.css(style, styles[style]);
|
||||||
|
console.log("Applying " + style + ' : ' + styles[style] );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("No Monitor styles to apply");
|
||||||
|
} // end if specific monitor style
|
||||||
|
} // end foreach monitor
|
||||||
|
} // end if a stored layout
|
||||||
|
if ( ! layout ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Cookie.write( 'zmMontageLayout', layout_id, { duration: 10*365 } );
|
||||||
|
if ( layouts[layout_id].Name != 'Freeform' ) { // 'montage_freeform.css' ) {
|
||||||
Cookie.write( 'zmMontageScale', '', { duration: 10*365 } );
|
Cookie.write( 'zmMontageScale', '', { duration: 10*365 } );
|
||||||
$('scale').set('value', '' );
|
$('scale').set('value', '' );
|
||||||
$('width').set('value', '');
|
$('width').set('value', '');
|
||||||
|
@ -152,6 +210,17 @@ function changeSize() {
|
||||||
|
|
||||||
for ( var x = 0; x < monitors.length; x++ ) {
|
for ( var x = 0; x < monitors.length; x++ ) {
|
||||||
var monitor = monitors[x];
|
var monitor = monitors[x];
|
||||||
|
|
||||||
|
// Scale the frame
|
||||||
|
monitor_frame = $j('#monitorFrame'+monitor.id);
|
||||||
|
if ( ! monitor_frame ) {
|
||||||
|
console.log("Error finding frame for " + monitor.id );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( width )
|
||||||
|
monitor_frame.css('width',width+'px');
|
||||||
|
if ( height )
|
||||||
|
monitor_frame.css('height',height+'px');
|
||||||
/*Stream could be an applet so can't use moo tools*/
|
/*Stream could be an applet so can't use moo tools*/
|
||||||
var streamImg = $( 'liveStream'+monitor.id );
|
var streamImg = $( 'liveStream'+monitor.id );
|
||||||
if ( streamImg ) {
|
if ( streamImg ) {
|
||||||
|
@ -181,13 +250,32 @@ function changeSize() {
|
||||||
|
|
||||||
function changeScale() {
|
function changeScale() {
|
||||||
var scale = $('scale').get('value');
|
var scale = $('scale').get('value');
|
||||||
|
$('width').set('value', '');
|
||||||
|
$('height').set('value', '');
|
||||||
|
Cookie.write( 'zmMontageScale', scale, { duration: 10*365 } );
|
||||||
|
Cookie.write( 'zmMontageWidth', '', { duration: 10*365 } );
|
||||||
|
Cookie.write( 'zmMontageHeight', '', { duration: 10*365 } );
|
||||||
|
if ( ! scale ) {
|
||||||
|
selectLayout('#zmMontageLayout');
|
||||||
|
return;
|
||||||
|
}
|
||||||
for ( var x = 0; x < monitors.length; x++ ) {
|
for ( var x = 0; x < monitors.length; x++ ) {
|
||||||
var monitor = monitors[x];
|
var monitor = monitors[x];
|
||||||
var newWidth = ( monitorData[x].width * scale ) / SCALE_BASE;
|
var newWidth = ( monitorData[x].width * scale ) / SCALE_BASE;
|
||||||
var newHeight = ( monitorData[x].height * scale ) / SCALE_BASE;
|
var newHeight = ( monitorData[x].height * scale ) / SCALE_BASE;
|
||||||
|
|
||||||
|
// Scale the frame
|
||||||
|
monitor_frame = $j('#monitorFrame'+monitor.id);
|
||||||
|
if ( ! monitor_frame ) {
|
||||||
|
console.log("Error finding frame for " + monitor.id );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( width )
|
||||||
|
monitor_frame.css('width',width+'px');
|
||||||
|
if ( height )
|
||||||
|
monitor_frame.css('height',height+'px');
|
||||||
/*Stream could be an applet so can't use moo tools*/
|
/*Stream could be an applet so can't use moo tools*/
|
||||||
var streamImg = document.getElementById( 'liveStream'+monitor.id );
|
var streamImg = $j('#liveStream'+monitor.id )[0];
|
||||||
if ( streamImg ) {
|
if ( streamImg ) {
|
||||||
if ( streamImg.nodeName == 'IMG' ) {
|
if ( streamImg.nodeName == 'IMG' ) {
|
||||||
var src = streamImg.src;
|
var src = streamImg.src;
|
||||||
|
@ -208,22 +296,72 @@ function changeScale() {
|
||||||
zonesSVG.style.height = newHeight + "px";
|
zonesSVG.style.height = newHeight + "px";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$('width').set('value', '');
|
}
|
||||||
$('height').set('value', '');
|
|
||||||
Cookie.write( 'zmMontageScale', scale, { duration: 10*365 } );
|
function toGrid(value) {
|
||||||
Cookie.write( 'zmMontageWidth', '', { duration: 10*365 } );
|
return Math.round(value / 80) * 80;
|
||||||
Cookie.write( 'zmMontageHeight', '', { duration: 10*365 } );
|
}
|
||||||
|
|
||||||
|
// Makes monitorFrames draggable.
|
||||||
|
function edit_layout(button) {
|
||||||
|
|
||||||
|
// Turn off the onclick on the image.
|
||||||
|
|
||||||
|
for ( var i = 0; i < monitors.length; i++ ) {
|
||||||
|
var monitor = monitors[i];
|
||||||
|
monitor_feed = $j('#imageFeed'+monitor.id)[0];
|
||||||
|
monitor_feed.onclick='';
|
||||||
|
};
|
||||||
|
|
||||||
|
$j('#monitors .monitorFrame').draggable({
|
||||||
|
cursor: 'crosshair',
|
||||||
|
//revert: 'invalid'
|
||||||
|
});
|
||||||
|
$j('#SaveLayout').show();
|
||||||
|
$j('#EditLayout').hide();
|
||||||
|
} // end function edit_layout
|
||||||
|
|
||||||
|
function save_layout(button) {
|
||||||
|
var form=button.form;
|
||||||
|
// In fixed positioning, order doesn't matter. In floating positioning, it does.
|
||||||
|
var Positions = {};
|
||||||
|
for ( var i = 0; i < monitors.length; i++ ) {
|
||||||
|
var monitor = monitors[i];
|
||||||
|
monitor_frame = $j('#monitorFrame'+monitor.id);
|
||||||
|
|
||||||
|
Positions['mId'+monitor.id] = {
|
||||||
|
width: monitor_frame.css('width'),
|
||||||
|
height: monitor_frame.css('height'),
|
||||||
|
top: monitor_frame.css('top'),
|
||||||
|
bottom: monitor_frame.css('bottom'),
|
||||||
|
left: monitor_frame.css('left'),
|
||||||
|
right: monitor_frame.css('right'),
|
||||||
|
position: monitor_frame.css('position'),
|
||||||
|
float: monitor_frame.css('float'),
|
||||||
|
};
|
||||||
|
} // end foreach monitor
|
||||||
|
form.Positions.value = JSON.stringify( Positions );
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
function cancel_layout(button) {
|
||||||
|
$j('#SaveLayout').hide();
|
||||||
|
$j('#EditLayout').show();
|
||||||
|
for ( var i = 0; i < monitors.length; i++ ) {
|
||||||
|
var monitor = monitors[i];
|
||||||
|
monitor_feed = $j('#imageFeed'+monitor.id);
|
||||||
|
monitor_feed.click( monitor.onclick );
|
||||||
|
};
|
||||||
|
selectLayout('#zmMontageLayout');
|
||||||
}
|
}
|
||||||
|
|
||||||
var monitors = new Array();
|
var monitors = new Array();
|
||||||
function initPage() {
|
function initPage() {
|
||||||
for ( var i = 0; i < monitorData.length; i++ ) {
|
for ( var i = 0; i < monitorData.length; i++ ) {
|
||||||
monitors[i] = new Monitor( monitorData[i] );
|
monitors[i] = new Monitor(monitorData[i]);
|
||||||
var delay = Math.round( (Math.random()+0.5)*statusRefreshTimeout );
|
var delay = Math.round( (Math.random()+0.75)*statusRefreshTimeout );
|
||||||
monitors[i].start( delay );
|
monitors[i].start(delay);
|
||||||
}
|
}
|
||||||
selectLayout($('layout'));
|
selectLayout('#zmMontageLayout');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kick everything off
|
// Kick everything off
|
||||||
window.addEvent( 'domready', initPage );
|
window.addEvent( 'domready', initPage );
|
||||||
|
|
|
@ -31,12 +31,22 @@ var monitorData = new Array();
|
||||||
foreach ( $monitors as $monitor ) {
|
foreach ( $monitors as $monitor ) {
|
||||||
?>
|
?>
|
||||||
monitorData[monitorData.length] = {
|
monitorData[monitorData.length] = {
|
||||||
'id': <?php echo $monitor->Id() ?>,
|
'id': <?php echo $monitor->Id() ?>,
|
||||||
'connKey': <?php echo $monitor->connKey() ?>,
|
'connKey': <?php echo $monitor->connKey() ?>,
|
||||||
'width': <?php echo $monitor->Width() ?>,
|
'width': <?php echo $monitor->Width() ?>,
|
||||||
'height':<?php echo $monitor->Height() ?>,
|
'height':<?php echo $monitor->Height() ?>,
|
||||||
'server_url': '<?php echo $monitor->Server()->Url().(ZM_MIN_STREAMING_PORT?':'.(ZM_MIN_STREAMING_PORT+$monitor->Id()):'').$_SERVER['PHP_SELF'] ?>'
|
'server_url': '<?php echo $monitor->Server()->Url().(ZM_MIN_STREAMING_PORT?':'.(ZM_MIN_STREAMING_PORT+$monitor->Id()):'').$_SERVER['PHP_SELF'] ?>',
|
||||||
|
'onclick': function(){createPopup( '?view=watch&mid=<?php echo $monitor->Id() ?>', 'zmWatch<?php echo $monitor->Id() ?>', 'watch', <?php echo reScale( $monitor->Width(), $monitor->PopupScale() ); ?>, <?php echo reScale( $monitor->Height(), $monitor->PopupScale() ); ?> );}
|
||||||
};
|
};
|
||||||
<?php
|
<?php
|
||||||
}
|
} // end foreach monitor
|
||||||
|
?>
|
||||||
|
layouts = new Array();
|
||||||
|
layouts[0] = {}; // reserved, should hold which fields to clear when transitioning
|
||||||
|
<?php
|
||||||
|
foreach ( $layouts as $layout ) {
|
||||||
|
?>
|
||||||
|
layouts[<?php echo $layout->Id() ?>] = {"Name":"<?php echo $layout->Name()?>","Positions":<?php echo $layout->Positions() ?>};
|
||||||
|
<?php
|
||||||
|
} // end foreach layout
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -84,7 +84,11 @@ function imagedone( obj, monId, success ) {
|
||||||
if ( ! success ) {
|
if ( ! success ) {
|
||||||
// if we had a failrue queue up the no-data image
|
// if we had a failrue queue up the no-data image
|
||||||
//loadImage2Monitor(monId,"no data"); // leave the staged URL if there is one, just ignore it here.
|
//loadImage2Monitor(monId,"no data"); // leave the staged URL if there is one, just ignore it here.
|
||||||
loadNoData( monId );
|
if ( liveMode ) {
|
||||||
|
writeText( monId, "Camera Offline" );
|
||||||
|
} else {
|
||||||
|
writeText( monId, "No Data" );
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if ( monitorLoadingStageURL[monId] == "" ) {
|
if ( monitorLoadingStageURL[monId] == "" ) {
|
||||||
console.log("Not showing image for " + monId );
|
console.log("Not showing image for " + monId );
|
||||||
|
|
|
@ -122,7 +122,7 @@ if ( ! $monitor ) {
|
||||||
'FrameSkip' => 0,
|
'FrameSkip' => 0,
|
||||||
'MotionFrameSkip' => 0,
|
'MotionFrameSkip' => 0,
|
||||||
'EventPrefix' => 'Event-',
|
'EventPrefix' => 'Event-',
|
||||||
'AnalysisFPS' => '',
|
'AnalysisFPSLimit' => '',
|
||||||
'AnalysisUpdateDelay' => 0,
|
'AnalysisUpdateDelay' => 0,
|
||||||
'MaxFPS' => '',
|
'MaxFPS' => '',
|
||||||
'AlarmMaxFPS' => '',
|
'AlarmMaxFPS' => '',
|
||||||
|
@ -170,8 +170,8 @@ if ( isset( $_REQUEST['newMonitor'] ) ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
# What if it has less zeros? This is not robust code.
|
# What if it has less zeros? This is not robust code.
|
||||||
if ( $monitor->AnalysisFPS() == '0.00' )
|
if ( $monitor->AnalysisFPSLimit() == '0.00' )
|
||||||
$monitor->AnalysisFPS( '' );
|
$monitor->AnalysisFPSLimit( '' );
|
||||||
if ( $monitor->MaxFPS() == '0.00' )
|
if ( $monitor->MaxFPS() == '0.00' )
|
||||||
$monitor->MaxFPS( '' );
|
$monitor->MaxFPS( '' );
|
||||||
if ( $monitor->AlarmMaxFPS() == '0.00' )
|
if ( $monitor->AlarmMaxFPS() == '0.00' )
|
||||||
|
@ -538,7 +538,7 @@ if ( $tab != 'general' ) {
|
||||||
<input type="hidden" name="newMonitor[Enabled]" value="<?php echo validHtmlStr($monitor->Enabled()) ?>"/>
|
<input type="hidden" name="newMonitor[Enabled]" value="<?php echo validHtmlStr($monitor->Enabled()) ?>"/>
|
||||||
<input type="hidden" name="newMonitor[RefBlendPerc]" value="<?php echo validHtmlStr($monitor->RefBlendPerc()) ?>"/>
|
<input type="hidden" name="newMonitor[RefBlendPerc]" value="<?php echo validHtmlStr($monitor->RefBlendPerc()) ?>"/>
|
||||||
<input type="hidden" name="newMonitor[AlarmRefBlendPerc]" value="<?php echo validHtmlStr($monitor->AlarmRefBlendPerc()) ?>"/>
|
<input type="hidden" name="newMonitor[AlarmRefBlendPerc]" value="<?php echo validHtmlStr($monitor->AlarmRefBlendPerc()) ?>"/>
|
||||||
<input type="hidden" name="newMonitor[AnalysisFPS]" value="<?php echo validHtmlStr($monitor->AnalysisFPS()) ?>"/>
|
<input type="hidden" name="newMonitor[AnalysisFPSLimit]" value="<?php echo validHtmlStr($monitor->AnalysisFPSLimit()) ?>"/>
|
||||||
<input type="hidden" name="newMonitor[MaxFPS]" value="<?php echo validHtmlStr($monitor->MaxFPS()) ?>"/>
|
<input type="hidden" name="newMonitor[MaxFPS]" value="<?php echo validHtmlStr($monitor->MaxFPS()) ?>"/>
|
||||||
<input type="hidden" name="newMonitor[AlarmMaxFPS]" value="<?php echo validHtmlStr($monitor->AlarmMaxFPS()) ?>"/>
|
<input type="hidden" name="newMonitor[AlarmMaxFPS]" value="<?php echo validHtmlStr($monitor->AlarmMaxFPS()) ?>"/>
|
||||||
<?php
|
<?php
|
||||||
|
@ -665,7 +665,7 @@ if ( ZM_HAS_V4L && ($tab != 'misc' || $monitor->Type()!= 'Local') ) {
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<table id="contentTable" class="major" cellspacing="0">
|
<table id="contentTable" class="major">
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php
|
<?php
|
||||||
switch ( $tab ) {
|
switch ( $tab ) {
|
||||||
|
@ -727,7 +727,7 @@ switch ( $tab ) {
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr><td><?php echo translate('AnalysisFPS') ?></td><td><input type="text" name="newMonitor[AnalysisFPS]" value="<?php echo validHtmlStr($monitor->AnalysisFPS()) ?>" size="6"/></td></tr>
|
<tr><td><?php echo translate('AnalysisFPS') ?></td><td><input type="text" name="newMonitor[AnalysisFPSLimit]" value="<?php echo validHtmlStr($monitor->AnalysisFPSLimit()) ?>" size="6"/></td></tr>
|
||||||
<?php
|
<?php
|
||||||
if ( $monitor->Type() != 'Local' && $monitor->Type() != 'File' && $monitor->Type() != 'NVSocket' ) {
|
if ( $monitor->Type() != 'Local' && $monitor->Type() != 'File' && $monitor->Type() != 'NVSocket' ) {
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -23,6 +23,8 @@ if ( !canView('Stream') ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
require_once('includes/MontageLayout.php');
|
||||||
|
|
||||||
$showControl = false;
|
$showControl = false;
|
||||||
$showZones = false;
|
$showZones = false;
|
||||||
if ( isset( $_REQUEST['showZones'] ) ) {
|
if ( isset( $_REQUEST['showZones'] ) ) {
|
||||||
|
@ -57,58 +59,52 @@ if ( isset( $_REQUEST['scale'] ) ) {
|
||||||
if ( ! $scale )
|
if ( ! $scale )
|
||||||
$scale = 100;
|
$scale = 100;
|
||||||
|
|
||||||
$focusWindow = true;
|
$layouts = MontageLayout::find(NULL, array('order'=>"lower('Name')"));
|
||||||
|
$layoutsById = array();
|
||||||
|
foreach ( $layouts as $l ) {
|
||||||
|
$layoutsById[$l->Id()] = $l->Name();
|
||||||
|
}
|
||||||
|
|
||||||
$layouts = array(
|
|
||||||
'montage_freeform.css' => translate('MtgDefault'),
|
session_start();
|
||||||
'montage_2wide.css' => translate('Mtg2widgrd'),
|
|
||||||
'montage_3wide.css' => translate('Mtg3widgrd'),
|
|
||||||
'montage_4wide.css' => translate('Mtg4widgrd'),
|
|
||||||
'montage_3wide50enlarge.css' => translate('Mtg3widgrx'),
|
|
||||||
);
|
|
||||||
|
|
||||||
$layout = '';
|
$layout = '';
|
||||||
if ( isset($_COOKIE['zmMontageLayout']) )
|
if ( isset($_COOKIE['zmMontageLayout']) ) {
|
||||||
$layout = $_COOKIE['zmMontageLayout'];
|
$layout = $_SESSION['zmMontageLayout'] = $_COOKIE['zmMontageLayout'];
|
||||||
|
Warning("Setting layout by cookie");
|
||||||
|
} elseif ( isset($_SESSION['zmMontageLayout']) ) {
|
||||||
|
$layout = $_SESSION['zmMontageLayout'];
|
||||||
|
Warning("Setting layout by session");
|
||||||
|
}
|
||||||
|
|
||||||
$options = array();
|
$options = array();
|
||||||
if ( isset($_COOKIE['zmMontageWidth']) and $_COOKIE['zmMontageWidth'] )
|
if ( isset($_COOKIE['zmMontageWidth']) and $_COOKIE['zmMontageWidth'] ) {
|
||||||
$options['width'] = $_COOKIE['zmMontageWidth'];
|
$_SESSION['zmMontageWidth'] = $options['width'] = $_COOKIE['zmMontageWidth'];
|
||||||
else
|
} elseif ( isset($_SESSION['zmMontageWidth']) and $_SESSION['zmMontageWidth'] ) {
|
||||||
|
$options['width'] = $_SESSION['zmMontageWidth'];
|
||||||
|
} else
|
||||||
$options['width'] = '';
|
$options['width'] = '';
|
||||||
|
|
||||||
if ( isset($_COOKIE['zmMontageHeight']) and $_COOKIE['zmMontageHeight'] )
|
if ( isset($_COOKIE['zmMontageHeight']) and $_COOKIE['zmMontageHeight'] )
|
||||||
$options['height'] = $_COOKIE['zmMontageHeight'];
|
$_SESSION['zmMontageHeight'] = $options['height'] = $_COOKIE['zmMontageHeight'];
|
||||||
|
else if ( isset($_SESSION['zmMontageHeight']) and $_SESSION['zmMontageHeight'] )
|
||||||
|
$options['height'] = $_SESSION['zmMontageHeight'];
|
||||||
else
|
else
|
||||||
$options['height'] = '';
|
$options['height'] = '';
|
||||||
|
session_write_close();
|
||||||
|
|
||||||
if ( $scale )
|
if ( $scale )
|
||||||
$options['scale'] = $scale;
|
$options['scale'] = $scale;
|
||||||
|
|
||||||
ob_start();
|
ob_start();
|
||||||
# This will end up with the group_id of the deepest selection
|
include('_monitor_filters.php');
|
||||||
$group_id = Group::get_group_dropdowns();
|
$filterbar = ob_get_contents();
|
||||||
$group_dropdowns = ob_get_contents();
|
|
||||||
ob_end_clean();
|
ob_end_clean();
|
||||||
|
|
||||||
$groupSql = Group::get_group_sql( $group_id );
|
|
||||||
|
|
||||||
$monitor_id = 0;
|
|
||||||
if ( isset( $_REQUEST['monitor_id'] ) ) {
|
|
||||||
$monitor_id = $_REQUEST['monitor_id'];
|
|
||||||
} else if ( isset($_COOKIE['zmMonitorId']) ) {
|
|
||||||
$monitor_id = $_COOKIE['zmMonitorId'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$monitors = array();
|
$monitors = array();
|
||||||
$monitors_dropdown = array( '' => 'All' );
|
foreach( $displayMonitors as &$row ) {
|
||||||
$sql = "SELECT * FROM Monitors WHERE Function != 'None'";
|
if ( $row['Function'] == 'None' )
|
||||||
if ( $groupSql ) { $sql .= ' AND ' . $groupSql; };
|
|
||||||
if ( $monitor_id ) { $sql .= ' AND Id='.$monitor_id; };
|
|
||||||
|
|
||||||
$sql .= ' ORDER BY Sequence';
|
|
||||||
foreach( dbFetchAll( $sql ) as $row ) {
|
|
||||||
if ( !visibleMonitor( $row['Id'] ) ) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
$row['Scale'] = $scale;
|
$row['Scale'] = $scale;
|
||||||
$row['PopupScale'] = reScale( SCALE_BASE, $row['DefaultScale'], ZM_WEB_DEFAULT_SCALE );
|
$row['PopupScale'] = reScale( SCALE_BASE, $row['DefaultScale'], ZM_WEB_DEFAULT_SCALE );
|
||||||
|
@ -116,14 +112,13 @@ foreach( dbFetchAll( $sql ) as $row ) {
|
||||||
if ( ZM_OPT_CONTROL && $row['ControlId'] && $row['Controllable'] )
|
if ( ZM_OPT_CONTROL && $row['ControlId'] && $row['Controllable'] )
|
||||||
$showControl = true;
|
$showControl = true;
|
||||||
$row['connKey'] = generateConnKey();
|
$row['connKey'] = generateConnKey();
|
||||||
$Monitor = $monitors[] = new Monitor( $row );
|
|
||||||
$monitors_dropdown[$Monitor->Id()] = $Monitor->Name();
|
|
||||||
if ( ! isset( $widths[$row['Width']] ) ) {
|
if ( ! isset( $widths[$row['Width']] ) ) {
|
||||||
$widths[$row['Width']] = $row['Width'];
|
$widths[$row['Width']] = $row['Width'];
|
||||||
}
|
}
|
||||||
if ( ! isset( $heights[$row['Height']] ) ) {
|
if ( ! isset( $heights[$row['Height']] ) ) {
|
||||||
$heights[$row['Height']] = $row['Height'];
|
$heights[$row['Height']] = $row['Height'];
|
||||||
}
|
}
|
||||||
|
$monitors[] = new Monitor( $row );
|
||||||
} # end foreach Monitor
|
} # end foreach Monitor
|
||||||
|
|
||||||
xhtmlHeaders(__FILE__, translate('Montage') );
|
xhtmlHeaders(__FILE__, translate('Montage') );
|
||||||
|
@ -141,26 +136,36 @@ if ( $showControl ) {
|
||||||
}
|
}
|
||||||
if ( $showZones ) {
|
if ( $showZones ) {
|
||||||
?>
|
?>
|
||||||
<a href="<?php echo $_SERVER['PHP_SELF'].'?view=montage&showZones=0'; ?>">Hide Zones</a>
|
<a id="ShowZones" href="<?php echo $_SERVER['PHP_SELF'].'?view=montage&showZones=0'; ?>">Hide Zones</a>
|
||||||
<?php
|
<?php
|
||||||
} else {
|
} else {
|
||||||
?>
|
?>
|
||||||
<a href="<?php echo $_SERVER['PHP_SELF'].'?view=montage&showZones=1'; ?>">Show Zones</a>
|
<a id="ShowZones" href="<?php echo $_SERVER['PHP_SELF'].'?view=montage&showZones=1'; ?>">Show Zones</a>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
<div id="headerControl">
|
<?php echo $filterbar ?>
|
||||||
<span id="groupControl"><label><?php echo translate('Group') ?>:</label>
|
<div id="sizeControl">
|
||||||
<?php echo $group_dropdowns; ?>
|
<form action="index.php?view=montage" method="post">
|
||||||
</span>
|
<input type="hidden" name="object" value="MontageLayout"/>
|
||||||
<span id="monitorControl"><label><?php echo translate('Monitor') ?>:</label>
|
<input type="hidden" name="action" value="Save"/>
|
||||||
<?php echo htmlSelect( 'monitor_id', $monitors_dropdown, $monitor_id, array('onchange'=>'changeMonitor(this);') ); ?>
|
|
||||||
</span>
|
<span id="widthControl"><label><?php echo translate('Width') ?>:</label><?php echo htmlSelect( 'width', $widths, $options['width'], 'changeSize(this);' ); ?></span>
|
||||||
<span id="widthControl"><label><?php echo translate('Width') ?>:</label><?php echo htmlSelect( 'width', $widths, $options['width'], 'changeSize(this);' ); ?></span>
|
<span id="heightControl"><label><?php echo translate('Height') ?>:</label><?php echo htmlSelect( 'height', $heights, $options['height'], 'changeSize(this);' ); ?></span>
|
||||||
<span id="heightControl"><label><?php echo translate('Height') ?>:</label><?php echo htmlSelect( 'height', $heights, $options['height'], 'changeSize(this);' ); ?></span>
|
<span id="scaleControl"><label><?php echo translate('Scale') ?>:</label><?php echo htmlSelect( 'scale', $scales, $scale, 'changeScale(this);' ); ?></span>
|
||||||
<span id="scaleControl"><label><?php echo translate('Scale') ?>:</label><?php echo htmlSelect( 'scale', $scales, $scale, 'changeScale(this);' ); ?></span>
|
<span id="layoutControl">
|
||||||
<span id="layoutControl"><label for="layout"><?php echo translate('Layout') ?>:</label><?php echo htmlSelect( 'layout', $layouts, $layout, 'selectLayout(this);' )?></span>
|
<label for="layout"><?php echo translate('Layout') ?>:</label>
|
||||||
|
<?php echo htmlSelect( 'zmMontageLayout', $layoutsById, $layout, array( 'onchange'=>'selectLayout(this);', 'id'=>'zmMontageLayout') ); ?>
|
||||||
|
</span>
|
||||||
|
<input type="hidden" name="Positions"/>
|
||||||
|
<input type="button" id="EditLayout" value="<?php echo translate('EditLayout') ?>" onclick="edit_layout(this);"/>
|
||||||
|
<span id="SaveLayout" style="display:none;">
|
||||||
|
<input type="text" name="Name" placeholder="Enter new name for layout if desired" />
|
||||||
|
<input type="button" value="<?php echo translate('Save') ?>" onclick="save_layout(this);"/>
|
||||||
|
<input type="button" value="Cancel" onclick="cancel_layout(this);"/>
|
||||||
|
</span>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="content">
|
<div id="content">
|
||||||
|
@ -169,7 +174,7 @@ if ( $showZones ) {
|
||||||
foreach ( $monitors as $monitor ) {
|
foreach ( $monitors as $monitor ) {
|
||||||
$connkey = $monitor->connKey(); // Minor hack
|
$connkey = $monitor->connKey(); // Minor hack
|
||||||
?>
|
?>
|
||||||
<div id="monitorFrame<?php echo $monitor->Id() ?>" class="monitorFrame" title="<?php echo $monitor->Id() . ' ' .$monitor->Name() ?>">
|
<div id="monitorFrame<?php echo $monitor->Id() ?>" class="monitorFrame" title="<?php echo $monitor->Id() . ' ' .$monitor->Name() ?>" style="<?php echo $options['width'] ? 'width:'.$options['width'].'px;':''?>">
|
||||||
<div id="monitor<?php echo $monitor->Id() ?>" class="monitor idle">
|
<div id="monitor<?php echo $monitor->Id() ?>" class="monitor idle">
|
||||||
<div id="imageFeed<?php echo $monitor->Id() ?>" class="imageFeed" onclick="createPopup( '?view=watch&mid=<?php echo $monitor->Id() ?>', 'zmWatch<?php echo $monitor->Id() ?>', 'watch', <?php echo reScale( $monitor->Width(), $monitor->PopupScale() ); ?>, <?php echo reScale( $monitor->Height(), $monitor->PopupScale() ); ?> );">
|
<div id="imageFeed<?php echo $monitor->Id() ?>" class="imageFeed" onclick="createPopup( '?view=watch&mid=<?php echo $monitor->Id() ?>', 'zmWatch<?php echo $monitor->Id() ?>', 'watch', <?php echo reScale( $monitor->Width(), $monitor->PopupScale() ); ?>, <?php echo reScale( $monitor->Height(), $monitor->PopupScale() ); ?> );">
|
||||||
<?php
|
<?php
|
||||||
|
@ -210,16 +215,13 @@ foreach ( $monitors as $monitor ) {
|
||||||
$row['Coords'] = pointsToCoords( $row['Points'] );
|
$row['Coords'] = pointsToCoords( $row['Points'] );
|
||||||
$row['AreaCoords'] = preg_replace( '/\s+/', ',', $row['Coords'] );
|
$row['AreaCoords'] = preg_replace( '/\s+/', ',', $row['Coords'] );
|
||||||
$zones[] = $row;
|
$zones[] = $row;
|
||||||
}
|
} // end foreach Zone
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<svg class="zones" id="zones<?php echo $monitor->Id() ?>" style="position:absolute; top: 0; left: 0; background: none; width: <?php echo $width ?>px; height: <?php echo $height ?>px;">
|
<svg class="zones" id="zones<?php echo $monitor->Id() ?>" style="position:absolute; top: 0; left: 0; background: none; width: <?php echo $width ?>px; height: <?php echo $height ?>px;">
|
||||||
<?php
|
<?php
|
||||||
foreach( array_reverse($zones) as $zone ) {
|
foreach( array_reverse($zones) as $zone ) {
|
||||||
?>
|
echo '<polygon points="'. $zone['AreaCoords'] .'" class="'. $zone['Type'].'" />';
|
||||||
<polygon points="<?php echo $zone['AreaCoords'] ?>" class="<?php echo $zone['Type']?>" />
|
|
||||||
<?php
|
|
||||||
} // end foreach zone
|
} // end foreach zone
|
||||||
?>
|
?>
|
||||||
Sorry, your browser does not support inline SVG
|
Sorry, your browser does not support inline SVG
|
||||||
|
|
|
@ -55,62 +55,10 @@ if ( !canView( 'Events' ) ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ob_start();
|
ob_start();
|
||||||
# This will end up with the group_id of the deepest selection
|
include('_monitor_filters.php');
|
||||||
$group_id = Group::get_group_dropdowns();
|
$filter_bar = ob_get_contents();
|
||||||
$group_dropdowns = ob_get_contents();
|
|
||||||
ob_end_clean();
|
ob_end_clean();
|
||||||
|
|
||||||
$groupSql = Group::get_group_sql( $group_id );
|
|
||||||
|
|
||||||
$servers = Server::find_all();
|
|
||||||
$ServersById = array();
|
|
||||||
foreach ( $servers as $S ) {
|
|
||||||
$ServersById[$S->Id()] = $S;
|
|
||||||
}
|
|
||||||
$storage_areas = Storage::find_all();
|
|
||||||
$StorageById = array();
|
|
||||||
foreach ( $storage_areas as $S ) {
|
|
||||||
$StorageById[$S->Id()] = $S;
|
|
||||||
}
|
|
||||||
session_start();
|
|
||||||
foreach ( array('minTime','maxTime','ServerFilter','StorageFilter') as $var ) {
|
|
||||||
if ( isset( $_REQUEST[$var] ) ) {
|
|
||||||
if ( $_REQUEST[$var] != '' ) {
|
|
||||||
$_SESSION[$var] = $_REQUEST[$var];
|
|
||||||
} else {
|
|
||||||
unset( $_SESSION[$var] );
|
|
||||||
}
|
|
||||||
} else if ( isset( $_COOKIE[$var] ) ) {
|
|
||||||
if ( $_COOKIE[$var] != '' ) {
|
|
||||||
$_SESSION[$var] = $_COOKIE[$var];
|
|
||||||
} else {
|
|
||||||
unset($_SESSION[$var]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
session_write_close();
|
|
||||||
|
|
||||||
$monitor_id = 0;
|
|
||||||
if ( isset( $_REQUEST['monitor_id'] ) ) {
|
|
||||||
$monitor_id = $_REQUEST['monitor_id'];
|
|
||||||
} else if ( isset($_COOKIE['zmMonitorId']) ) {
|
|
||||||
$monitor_id = $_COOKIE['zmMonitorId'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$conditions = array();
|
|
||||||
$values = array();
|
|
||||||
|
|
||||||
if ( $groupSql )
|
|
||||||
$conditions[] = $groupSql;
|
|
||||||
if ( isset($_SESSION['ServerFilter']) ) {
|
|
||||||
$conditions[] = 'ServerId=?';
|
|
||||||
$values[] = $_SESSION['ServerFilter'];
|
|
||||||
}
|
|
||||||
if ( isset($_SESSION['StorageFilter']) ) {
|
|
||||||
$conditions[] = 'StorageId=?';
|
|
||||||
$values[] = $_SESSION['StorageFilter'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note that this finds incomplete events as well, and any frame records written, but still cannot "see" to the end frame
|
// Note that this finds incomplete events as well, and any frame records written, but still cannot "see" to the end frame
|
||||||
// if the bulk record has not been written - to be able to include more current frames reduce bulk frame sizes (event size can be large)
|
// if the bulk record has not been written - to be able to include more current frames reduce bulk frame sizes (event size can be large)
|
||||||
// Note we round up just a bit on the end time as otherwise you get gaps, like 59.78 to 00 in the next second, which can give blank frames when moved through slowly.
|
// Note we round up just a bit on the end time as otherwise you get gaps, like 59.78 to 00 in the next second, which can give blank frames when moved through slowly.
|
||||||
|
@ -141,18 +89,12 @@ $frameSql = '
|
||||||
// This program only calls itself with the time range involved -- it does all monitors (the user can see, in the called group) all the time
|
// This program only calls itself with the time range involved -- it does all monitors (the user can see, in the called group) all the time
|
||||||
|
|
||||||
if ( ! empty( $user['MonitorIds'] ) ) {
|
if ( ! empty( $user['MonitorIds'] ) ) {
|
||||||
$eventsSql .= ' AND M.Id IN ('.$user['MonitorIds'].')';
|
$eventsSql .= ' AND M.Id IN ('.$user['MonitorIds'].')';
|
||||||
$monitorsSql .= ' AND Id IN ('.$user['MonitorIds'].')';
|
$frameSql .= ' AND E.MonitorId IN ('.$user['MonitorIds'].')';
|
||||||
$monitor_ids = explode(',',$user['MonitorIds']);
|
|
||||||
$conditions[] .= 'Id IN ('.array_map( function(){return '?';}, $monitor_ids ) . ')';
|
|
||||||
array_push( $values, $monitor_ids );
|
|
||||||
$frameSql .= ' AND E.MonitorId IN ('.$user['MonitorIds'].')';
|
|
||||||
}
|
}
|
||||||
if ( $monitor_id ) {
|
if ( $monitor_id ) {
|
||||||
$conditions[] = 'Id=?';
|
|
||||||
$values[] = $monitor_id;
|
|
||||||
$eventsSql .= ' AND M.Id='.$monitor_id;
|
$eventsSql .= ' AND M.Id='.$monitor_id;
|
||||||
$frameSql .= ' AND E.MonitorId='.$monitor_id;
|
$frameSql .= ' AND E.MonitorId='.$monitor_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse input parameters -- note for future, validate/clean up better in case we don't get called from self.
|
// Parse input parameters -- note for future, validate/clean up better in case we don't get called from self.
|
||||||
|
@ -160,7 +102,6 @@ if ( $monitor_id ) {
|
||||||
|
|
||||||
// The default (nothing at all specified) is for 1 hour so we do not read the whole database
|
// The default (nothing at all specified) is for 1 hour so we do not read the whole database
|
||||||
|
|
||||||
|
|
||||||
if ( !isset($_REQUEST['minTime']) && !isset($_REQUEST['maxTime']) ) {
|
if ( !isset($_REQUEST['minTime']) && !isset($_REQUEST['maxTime']) ) {
|
||||||
$time = time();
|
$time = time();
|
||||||
$maxTime = strftime("%FT%T",$time);
|
$maxTime = strftime("%FT%T",$time);
|
||||||
|
@ -180,7 +121,7 @@ if ( (strtotime($maxTime) - strtotime($minTime))/(365*24*3600) > 30 ) {
|
||||||
$maxTime = null;
|
$maxTime = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$fitMode=1;
|
$fitMode = 1;
|
||||||
if (isset($_REQUEST['fit']) && $_REQUEST['fit']=='0' )
|
if (isset($_REQUEST['fit']) && $_REQUEST['fit']=='0' )
|
||||||
$fitMode = 0;
|
$fitMode = 0;
|
||||||
|
|
||||||
|
@ -196,7 +137,7 @@ if ( isset($_REQUEST['speed']) )
|
||||||
else
|
else
|
||||||
$defaultSpeed = 1;
|
$defaultSpeed = 1;
|
||||||
|
|
||||||
$speedIndex=5; // default to 1x
|
$speedIndex = 5; // default to 1x
|
||||||
for ( $i = 0; $i < count($speeds); $i++ ) {
|
for ( $i = 0; $i < count($speeds); $i++ ) {
|
||||||
if ( $speeds[$i] == $defaultSpeed ) {
|
if ( $speeds[$i] == $defaultSpeed ) {
|
||||||
$speedIndex = $i;
|
$speedIndex = $i;
|
||||||
|
@ -225,10 +166,10 @@ if ( isset($minTime) && isset($maxTime) ) {
|
||||||
}
|
}
|
||||||
$frameSql .= ' GROUP BY E.Id, E.MonitorId, F.TimeStamp, F.Delta ORDER BY E.MonitorId, F.TimeStamp ASC';
|
$frameSql .= ' GROUP BY E.Id, E.MonitorId, F.TimeStamp, F.Delta ORDER BY E.MonitorId, F.TimeStamp ASC';
|
||||||
|
|
||||||
|
|
||||||
$monitors = array();
|
$monitors = array();
|
||||||
$monitorsSql = 'SELECT * FROM Monitors' . ( count($conditions) ? ' WHERE ' . implode(' AND ', $conditions ) : '' ).' ORDER BY Sequence ASC';
|
foreach( $displayMonitors as &$row ) {
|
||||||
foreach( dbFetchAll( $monitorsSql, null, $values ) as $row ) {
|
if ( $row['Function'] == 'None' )
|
||||||
|
continue;
|
||||||
$Monitor = new Monitor( $row );
|
$Monitor = new Monitor( $row );
|
||||||
$monitors[] = $Monitor;
|
$monitors[] = $Monitor;
|
||||||
}
|
}
|
||||||
|
@ -243,32 +184,7 @@ xhtmlHeaders(__FILE__, translate('MontageReview') );
|
||||||
<form action="<?php echo $_SERVER['PHP_SELF'] ?>" method="get">
|
<form action="<?php echo $_SERVER['PHP_SELF'] ?>" method="get">
|
||||||
<input type="hidden" name="view" value="montagereview"/>
|
<input type="hidden" name="view" value="montagereview"/>
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<div id="headerControl">
|
<?php echo $filter_bar ?>
|
||||||
<span id="groupControl"><label><?php echo translate('Group') ?>:</label>
|
|
||||||
<?php echo $group_dropdowns; ?>
|
|
||||||
</span>
|
|
||||||
<span id="monitorControl"><label><?php echo translate('Monitor') ?>:</label>
|
|
||||||
<?php Group::get_monitors_dropdown( $groupSql ? array( 'groupSql'=>$groupSql) : null ); ?>
|
|
||||||
</span>
|
|
||||||
<?php
|
|
||||||
if ( count($ServersById) > 0 ) { ?>
|
|
||||||
<span class="ServerFilter"><label><?php echo translate('Server')?>:</label>
|
|
||||||
<?php
|
|
||||||
echo htmlSelect( 'ServerFilter', array(''=>'All')+$ServersById, (isset($_SESSION['ServerFilter'])?$_SESSION['ServerFilter']:''), array('onchange'=>'changeFilter(this);') );
|
|
||||||
?>
|
|
||||||
</span>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
if ( count($StorageById) > 0 ) { ?>
|
|
||||||
<span class="StorageFilter"><label><?php echo translate('Storage')?>:</label>
|
|
||||||
<?php
|
|
||||||
echo htmlSelect( 'StorageFilter', array(''=>'All')+$StorageById, (isset($_SESSION['StorageFilter'])?$_SESSION['StorageFilter']:''), array('onchange'=>'changeFilter(this);') );
|
|
||||||
?>
|
|
||||||
</span>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
||||||
<div id="DateTimeDiv">
|
<div id="DateTimeDiv">
|
||||||
<input type="datetime-local" name="minTime" id="minTime" value="<?php echo preg_replace('/ /', 'T', $minTime ) ?>" onchange="changeDateTime(this);"> to
|
<input type="datetime-local" name="minTime" id="minTime" value="<?php echo preg_replace('/ /', 'T', $minTime ) ?>" onchange="changeDateTime(this);"> to
|
||||||
<input type="datetime-local" name="maxTime" id="maxTime" value="<?php echo preg_replace('/ /', 'T', $maxTime ) ?>" onchange="changeDateTime(this);">
|
<input type="datetime-local" name="maxTime" id="maxTime" value="<?php echo preg_replace('/ /', 'T', $maxTime ) ?>" onchange="changeDateTime(this);">
|
||||||
|
|
|
@ -25,6 +25,11 @@ if ( !canView( 'Stream' ) ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! isset($_REQUEST['mid']) ) {
|
||||||
|
$view = 'error';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// This is for input sanitation
|
// This is for input sanitation
|
||||||
$mid = intval( $_REQUEST['mid'] );
|
$mid = intval( $_REQUEST['mid'] );
|
||||||
if ( ! visibleMonitor( $mid ) ) {
|
if ( ! visibleMonitor( $mid ) ) {
|
||||||
|
|
Loading…
Reference in New Issue