Merge branch 'master' into storageareas

This commit is contained in:
Isaac Connor 2017-06-04 21:42:56 -04:00
commit 451714a403
28 changed files with 1464 additions and 1425 deletions

View File

@ -1,6 +1,8 @@
language: cpp language: cpp
sudo: required sudo: required
dist: trusty dist: trusty
git:
depth: 9999999
notifications: notifications:
irc: chat.freenode.net#zoneminder-dev irc: chat.freenode.net#zoneminder-dev
branches: branches:
@ -20,6 +22,7 @@ addons:
- git - git
- curl - curl
- sshfs - sshfs
- sed
env: env:
matrix: matrix:
- OS=el DIST=6 - OS=el DIST=6

View File

@ -1,10 +0,0 @@
zoneminder (1.28.1-1) unstable; urgency=low
This version is no longer automatically initialize or upgrade database.
See README.Debian for details.
Changed installation paths (please correct your web server configuration):
/usr/share/zoneminder --> /usr/share/zoneminder/www
/usr/lib/cgi-bin --> /usr/lib/zoneminder/cgi-bin
-- Dmitry Smirnov <onlyjob@debian.org> Tue, 31 Mar 2015 15:12:17 +1100

View File

@ -1,5 +1,8 @@
<<<<<<< HEAD
zoneminder (1.31.0-trusty) trusty; urgency=medium zoneminder (1.31.0-trusty) trusty; urgency=medium
* placeholder * placeholder
-- Isaac Connor <iconnor@connortechnology.com> Fri, 13 May 2016 09:45:49 -0400 -- Isaac Connor <iconnor@connortechnology.com> Fri, 13 May 2016 09:45:49 -0400
=======
>>>>>>> master

View File

@ -1 +1 @@
3.0 (native) 3.0 (quilt)

View File

@ -1600,7 +1600,7 @@ our @options = (
this overhead is fairly small but may be noticeable on IO-constrained this overhead is fairly small but may be noticeable on IO-constrained
systems. systems.
`, `,
type => $types{string}, type => $types{boolean},
category => 'web', category => 'web',
}, },
{ {

View File

@ -223,9 +223,7 @@ sub GenerateVideo {
my $status = $? >> 8; my $status = $? >> 8;
if ( $status ) { if ( $status ) {
Error( "Unable to generate video, check " Error( "Unable to generate video, check $event_path/ffmpeg.log for details");
.$event_path."/ffmpeg.log for details"
);
return; return;
} }
@ -271,7 +269,6 @@ sub delete {
} }
} # end sub delete } # end sub delete
sub delete_files { sub delete_files {
my $Storage = new ZoneMinder::Storage( $_[0]{StorageId} ); my $Storage = new ZoneMinder::Storage( $_[0]{StorageId} );
@ -353,49 +350,26 @@ sub age {
1; 1;
__END__ __END__
# Below is stub documentation for your module. You'd better edit it!
=head1 NAME =head1 NAME
ZoneMinder::Database - Perl extension for blah blah blah ZoneMinder::Event - Perl Class for events
=head1 SYNOPSIS =head1 SYNOPSIS
use ZoneMinder::Event; use ZoneMinder::Event;
blah blah blah
=head1 DESCRIPTION =head1 DESCRIPTION
Stub documentation for ZoneMinder, created by h2xs. It looks like the The Event class has everything you need to deal with events from Perl.
author of the extension was negligent enough to leave the stub
unedited.
Blah blah blah.
=head2 EXPORT
None by default.
=head1 SEE ALSO
Mention other useful documentation such as the documentation of
related modules or operating system documentation (such as man pages
in UNIX), or any relevant external documentation such as RFCs or
standards.
If you have a mailing list set up for your module, mention it here.
If you have a web site set up for your module, mention it here.
=head1 AUTHOR =head1 AUTHOR
Philip Coombes, E<lt>philip.coombes@zoneminder.comE<gt> Isaac Connor, E<lt>isaac@zoneminder.comE<gt>
=head1 COPYRIGHT AND LICENSE =head1 COPYRIGHT AND LICENSE
Copyright (C) 2001-2008 Philip Coombes Copyright (C) 2001-2017 ZoneMinder LLC
This library is free software; you can redistribute it and/or modify This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.3 or, it under the same terms as Perl itself, either Perl version 5.8.3 or,

View File

@ -41,7 +41,7 @@ our @ISA = qw(Exporter ZoneMinder::Base);
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
# will save memory. # will save memory.
our %EXPORT_TAGS = ( our %EXPORT_TAGS = (
'constants' => [ qw( constants => [ qw(
STATE_IDLE STATE_IDLE
STATE_PREALARM STATE_PREALARM
STATE_ALARM STATE_ALARM
@ -56,7 +56,7 @@ our %EXPORT_TAGS = (
TRIGGER_ON TRIGGER_ON
TRIGGER_OFF TRIGGER_OFF
) ], ) ],
'functions' => [ qw( functions => [ qw(
zmMemVerify zmMemVerify
zmMemInvalidate zmMemInvalidate
zmMemRead zmMemRead
@ -83,7 +83,7 @@ our %EXPORT_TAGS = (
); );
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS; push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{all} } );
our @EXPORT = qw(); our @EXPORT = qw();
@ -142,43 +142,43 @@ our $native = $arch/8;
our $mem_seq = 0; our $mem_seq = 0;
our $mem_data = { our $mem_data = {
'shared_data' => { 'type'=>'SharedData', 'seq'=>$mem_seq++, 'contents'=> { shared_data => { type=>'SharedData', seq=>$mem_seq++, contents=> {
'size' => { 'type'=>'uint32', 'seq'=>$mem_seq++ }, size => { type=>'uint32', seq=>$mem_seq++ },
'last_write_index' => { 'type'=>'uint32', 'seq'=>$mem_seq++ }, last_write_index => { type=>'uint32', seq=>$mem_seq++ },
'last_read_index' => { 'type'=>'uint32', 'seq'=>$mem_seq++ }, last_read_index => { type=>'uint32', seq=>$mem_seq++ },
'state' => { 'type'=>'uint32', 'seq'=>$mem_seq++ }, state => { type=>'uint32', seq=>$mem_seq++ },
'last_event' => { 'type'=>'uint32', 'seq'=>$mem_seq++ }, last_event => { type=>'uint32', seq=>$mem_seq++ },
'action' => { 'type'=>'uint32', 'seq'=>$mem_seq++ }, action => { type=>'uint32', seq=>$mem_seq++ },
'brightness' => { 'type'=>'int32', 'seq'=>$mem_seq++ }, brightness => { type=>'int32', seq=>$mem_seq++ },
'hue' => { 'type'=>'int32', 'seq'=>$mem_seq++ }, hue => { type=>'int32', seq=>$mem_seq++ },
'colour' => { 'type'=>'int32', 'seq'=>$mem_seq++ }, colour => { type=>'int32', seq=>$mem_seq++ },
'contrast' => { 'type'=>'int32', 'seq'=>$mem_seq++ }, contrast => { type=>'int32', seq=>$mem_seq++ },
'alarm_x' => { 'type'=>'int32', 'seq'=>$mem_seq++ }, alarm_x => { type=>'int32', seq=>$mem_seq++ },
'alarm_y' => { 'type'=>'int32', 'seq'=>$mem_seq++ }, alarm_y => { type=>'int32', seq=>$mem_seq++ },
'valid' => { 'type'=>'uint8', 'seq'=>$mem_seq++ }, valid => { type=>'uint8', seq=>$mem_seq++ },
'active' => { 'type'=>'uint8', 'seq'=>$mem_seq++ }, active => { type=>'uint8', seq=>$mem_seq++ },
'signal' => { 'type'=>'uint8', 'seq'=>$mem_seq++ }, signal => { type=>'uint8', seq=>$mem_seq++ },
'format' => { 'type'=>'uint8', 'seq'=>$mem_seq++ }, format => { type=>'uint8', seq=>$mem_seq++ },
'imagesize' => { 'type'=>'uint32', 'seq'=>$mem_seq++ }, imagesize => { type=>'uint32', seq=>$mem_seq++ },
'epadding1' => { 'type'=>'uint32', 'seq'=>$mem_seq++ }, epadding1 => { type=>'uint32', seq=>$mem_seq++ },
'epadding2' => { 'type'=>'uint32', 'seq'=>$mem_seq++ }, epadding2 => { type=>'uint32', seq=>$mem_seq++ },
'startup_time' => { 'type'=>'time_t64', 'seq'=>$mem_seq++ }, startup_time => { type=>'time_t64', seq=>$mem_seq++ },
'last_write_time' => { 'type'=>'time_t64', 'seq'=>$mem_seq++ }, last_write_time => { type=>'time_t64', seq=>$mem_seq++ },
'last_read_time' => { 'type'=>'time_t64', 'seq'=>$mem_seq++ }, last_read_time => { type=>'time_t64', seq=>$mem_seq++ },
'control_state' => { 'type'=>'uint8[256]', 'seq'=>$mem_seq++ }, control_state => { type=>'uint8[256]', seq=>$mem_seq++ },
} }
}, },
'trigger_data' => { 'type'=>'TriggerData', 'seq'=>$mem_seq++, 'contents'=> { trigger_data => { type=>'TriggerData', seq=>$mem_seq++, 'contents'=> {
'size' => { 'type'=>'uint32', 'seq'=>$mem_seq++ }, size => { type=>'uint32', seq=>$mem_seq++ },
'trigger_state' => { 'type'=>'uint32', 'seq'=>$mem_seq++ }, trigger_state => { type=>'uint32', seq=>$mem_seq++ },
'trigger_score' => { 'type'=>'uint32', 'seq'=>$mem_seq++ }, trigger_score => { type=>'uint32', seq=>$mem_seq++ },
'padding' => { 'type'=>'uint32', 'seq'=>$mem_seq++ }, padding => { type=>'uint32', seq=>$mem_seq++ },
'trigger_cause' => { 'type'=>'int8[32]', 'seq'=>$mem_seq++ }, trigger_cause => { type=>'int8[32]', seq=>$mem_seq++ },
'trigger_text' => { 'type'=>'int8[256]', 'seq'=>$mem_seq++ }, trigger_text => { type=>'int8[256]', seq=>$mem_seq++ },
'trigger_showtext' => { 'type'=>'int8[256]', 'seq'=>$mem_seq++ }, trigger_showtext => { type=>'int8[256]', seq=>$mem_seq++ },
} }
}, },
'end' => { 'seq'=>$mem_seq++, 'size'=> 0 } end => { seq=>$mem_seq++, size=>0 }
}; };
our $mem_size = 0; our $mem_size = 0;
@ -420,7 +420,7 @@ sub zmMemWrite {
} elsif ( $type =~ /^uint8\[\d+\]$/ ) { } elsif ( $type =~ /^uint8\[\d+\]$/ ) {
$data = pack( 'C'.$size, $value ); $data = pack( 'C'.$size, $value );
} else { } else {
Fatal( "Unexpected type '".$type."' found for '".$field."'" ); Fatal( "Unexpected type \"$type\" found for \"$field\"" );
} }
if ( !zmMemPut( $monitor, $offset, $size, $data ) ) { if ( !zmMemPut( $monitor, $offset, $size, $data ) ) {

View File

@ -40,15 +40,15 @@ our @ISA = qw(Exporter ZoneMinder::Base);
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
# will save memory. # will save memory.
our %EXPORT_TAGS = ( our %EXPORT_TAGS = (
'functions' => [ qw( functions => [ qw(
zmMemKey zmMemKey
zmMemAttach zmMemAttach
zmMemDetach zmMemDetach
zmMemGet zmMemGet
zmMemPut zmMemPut
zmMemClean zmMemClean
) ], ) ],
); );
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS; push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
@ -102,7 +102,7 @@ sub zmMemAttach {
return ( undef ); return ( undef );
} }
my $MMAP; my $MMAP;
if ( !open( $MMAP, "+<", $mmap_file ) ) { if ( !open( $MMAP, '+<', $mmap_file ) ) {
Error( sprintf( "Can't open memory map file '%s': $!\n", $mmap_file ) ); Error( sprintf( "Can't open memory map file '%s': $!\n", $mmap_file ) );
return( undef ); return( undef );
} }
@ -122,6 +122,7 @@ sub zmMemAttach {
sub zmMemDetach { sub zmMemDetach {
my $monitor = shift; my $monitor = shift;
if ( $monitor->{MMap} ) { if ( $monitor->{MMap} ) {
if ( ! munmap( ${$monitor->{MMap}} ) ) { if ( ! munmap( ${$monitor->{MMap}} ) ) {
Warn( "Unable to munmap for monitor $$monitor{Id}\n"); Warn( "Unable to munmap for monitor $$monitor{Id}\n");
@ -174,7 +175,7 @@ sub zmMemPut {
sub zmMemClean { sub zmMemClean {
Debug( "Removing memory map files\n" ); Debug( "Removing memory map files\n" );
my $mapPath = $Config{ZM_PATH_MAP}."/zm.mmap.*"; my $mapPath = $Config{ZM_PATH_MAP}.'/zm.mmap.*';
foreach my $mapFile( glob( $mapPath ) ) { foreach my $mapFile( glob( $mapPath ) ) {
( $mapFile ) = $mapFile =~ /^(.+)$/; ( $mapFile ) = $mapFile =~ /^(.+)$/;
Debug( "Removing memory map file '$mapFile'\n" ); Debug( "Removing memory map file '$mapFile'\n" );

View File

@ -61,49 +61,22 @@ sub Storage {
1; 1;
__END__ __END__
# Below is stub documentation for your module. You'd better edit it!
=head1 NAME =head1 NAME
ZoneMinder::Database - Perl extension for blah blah blah ZoneMinder::Monitor - Perl Class for Monitors
=head1 SYNOPSIS =head1 SYNOPSIS
use ZoneMinder::Monitor; use ZoneMinder::Monitor;
blah blah blah
=head1 DESCRIPTION
Stub documentation for ZoneMinder, created by h2xs. It looks like the
author of the extension was negligent enough to leave the stub
unedited.
Blah blah blah.
=head2 EXPORT
None by default.
=head1 SEE ALSO
Mention other useful documentation such as the documentation of
related modules or operating system documentation (such as man pages
in UNIX), or any relevant external documentation such as RFCs or
standards.
If you have a mailing list set up for your module, mention it here.
If you have a web site set up for your module, mention it here.
=head1 AUTHOR =head1 AUTHOR
Philip Coombes, E<lt>philip.coombes@zoneminder.comE<gt> Isaac Connor, E<lt>isaac@zoneminder.comE<gt>
=head1 COPYRIGHT AND LICENSE =head1 COPYRIGHT AND LICENSE
Copyright (C) 2001-2008 Philip Coombes Copyright (C) 2001-2017 ZoneMinder LLC
This library is free software; you can redistribute it and/or modify This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.3 or, it under the same terms as Perl itself, either Perl version 5.8.3 or,

View File

@ -59,7 +59,7 @@ use bytes;
# ========================================================================== # ==========================================================================
use constant RECOVER_TAG => '(r)'; # Tag to append to event name when recovered use constant RECOVER_TAG => '(r)'; # Tag to append to event name when recovered
use constant RECOVER_TEXT => "Recovered."; # Text to append to event notes when recovered use constant RECOVER_TEXT => 'Recovered.'; # Text to append to event notes when recovered
# ========================================================================== # ==========================================================================
# #
@ -98,11 +98,11 @@ logInit();
logSetSignal(); logSetSignal();
GetOptions( GetOptions(
'interactive' =>\$interactive, continuous =>\$continuous,
'continuous' =>\$continuous, interactive =>\$interactive,
'monitor_id=s' =>\$monitor_id, monitor_id =>\$monitor_id,
'report' =>\$report, report =>\$report,
'version' =>\$version version =>\$version
) or pod2usage(-exitstatus => -1); ) or pod2usage(-exitstatus => -1);
if ( $version ) { if ( $version ) {
@ -114,6 +114,10 @@ if ( ($report + $interactive + $continuous) > 1 ) {
pod2usage(-exitstatus => -1); pod2usage(-exitstatus => -1);
} }
if ( ! exists $Config{ZM_AUDIT_MIN_AGE} ) {
Fatal('ZM_AUDIT_MIN_AGE is not set in config.');
}
my $dbh = zmDbConnect(); my $dbh = zmDbConnect();
require ZoneMinder::Monitor; require ZoneMinder::Monitor;
@ -128,10 +132,6 @@ my $loop = 1;
my $cleaned = 0; my $cleaned = 0;
MAIN: while( $loop ) { MAIN: while( $loop ) {
if ( ! exists $Config{ZM_AUDIT_MIN_AGE} ) {
Fatal("ZM_AUDIT_MIN_AGE is not set in config.");
}
if ( $continuous ) { if ( $continuous ) {
# if we are running continuously, then just skip to the next # if we are running continuously, then just skip to the next
# interval, otherwise we are a one off run, so wait a second and # interval, otherwise we are a one off run, so wait a second and
@ -158,11 +158,11 @@ MAIN: while( $loop ) {
my %Monitors; my %Monitors;
my $db_monitors; my $db_monitors;
my $monitorSelectSql = $monitor_id ? 'SELECT * FRO Monitors WHERE Id=?' : 'SELECT * FROM Monitors ORDER BY Id'; my $monitorSelectSql = $monitor_id ? 'SELECT * FROM Monitors WHERE Id=?' : 'SELECT * FROM Monitors ORDER BY Id';
my $monitorSelectSth = $dbh->prepare_cached( $monitorSelectSql ) my $monitorSelectSth = $dbh->prepare_cached( $monitorSelectSql )
or Fatal( "Can't prepare '$monitorSelectSql': ".$dbh->errstr() ); or Fatal( "Can't prepare '$monitorSelectSql': ".$dbh->errstr() );
my $eventSelectSql = 'SELECT Id, (unix_timestamp() - unix_timestamp(StartTime)) as Age my $eventSelectSql = 'SELECT Id, (unix_timestamp() - unix_timestamp(StartTime)) AS Age
FROM Events WHERE MonitorId = ? ORDER BY Id'; FROM Events WHERE MonitorId = ? ORDER BY Id';
my $eventSelectSth = $dbh->prepare_cached( $eventSelectSql ) my $eventSelectSth = $dbh->prepare_cached( $eventSelectSql )
or Fatal( "Can't prepare '$eventSelectSql': ".$dbh->errstr() ); or Fatal( "Can't prepare '$eventSelectSql': ".$dbh->errstr() );
@ -555,7 +555,7 @@ Debug("Event $db_event is not in fs.");
if ( $Config{ZM_LOG_DATABASE_LIMIT} ) { if ( $Config{ZM_LOG_DATABASE_LIMIT} ) {
if ( $Config{ZM_LOG_DATABASE_LIMIT} =~ /^\d+$/ ) { if ( $Config{ZM_LOG_DATABASE_LIMIT} =~ /^\d+$/ ) {
# Number of rows # Number of rows
my $selectLogRowCountSql = 'SELECT count(*) as Rows from Logs'; my $selectLogRowCountSql = 'SELECT count(*) AS Rows FROM Logs';
my $selectLogRowCountSth = $dbh->prepare_cached( $selectLogRowCountSql ) my $selectLogRowCountSth = $dbh->prepare_cached( $selectLogRowCountSql )
or Fatal( "Can't prepare '$selectLogRowCountSql': ".$dbh->errstr() ); or Fatal( "Can't prepare '$selectLogRowCountSql': ".$dbh->errstr() );
$res = $selectLogRowCountSth->execute() $res = $selectLogRowCountSth->execute()
@ -569,15 +569,14 @@ Debug("Event $db_event is not in fs.");
$res = $deleteLogByRowsSth->execute( $logRows - $Config{ZM_LOG_DATABASE_LIMIT} ) $res = $deleteLogByRowsSth->execute( $logRows - $Config{ZM_LOG_DATABASE_LIMIT} )
or Fatal( "Can't execute: ".$deleteLogByRowsSth->errstr() ); or Fatal( "Can't execute: ".$deleteLogByRowsSth->errstr() );
if ( $deleteLogByRowsSth->rows() ) { if ( $deleteLogByRowsSth->rows() ) {
aud_print( 'Deleted '.$deleteLogByRowsSth->rows() aud_print( 'Deleted '.$deleteLogByRowsSth->rows() ." log table entries by count\n" );
." log table entries by count\n" );
} }
} }
} else { } else {
# Time of record # Time of record
my $deleteLogByTimeSql = my $deleteLogByTimeSql =
"DELETE low_priority FROM Logs 'DELETE low_priority FROM Logs
WHERE TimeKey < unix_timestamp(now() - interval ".$Config{ZM_LOG_DATABASE_LIMIT}.')'; WHERE TimeKey < unix_timestamp(now() - interval '.$Config{ZM_LOG_DATABASE_LIMIT}.')';
my $deleteLogByTimeSth = $dbh->prepare_cached( $deleteLogByTimeSql ) my $deleteLogByTimeSth = $dbh->prepare_cached( $deleteLogByTimeSql )
or Fatal( "Can't prepare '$deleteLogByTimeSql': ".$dbh->errstr() ); or Fatal( "Can't prepare '$deleteLogByTimeSql': ".$dbh->errstr() );
$res = $deleteLogByTimeSth->execute() $res = $deleteLogByTimeSth->execute()

View File

@ -27,7 +27,11 @@ zmfilter.pl - ZoneMinder tool to filter events
=head1 SYNOPSIS =head1 SYNOPSIS
<<<<<<< HEAD
zmfilter.pl [-f <filter name>,--filter=<filter name>] [--filter_id=<filter id>] | -v, --version zmfilter.pl [-f <filter name>,--filter=<filter name>] [--filter_id=<filter id>] | -v, --version
=======
zmfilter.pl [-f <filter name>,--filter=<filter name>] | -v, --version
>>>>>>> master
=head1 DESCRIPTION =head1 DESCRIPTION
@ -70,7 +74,7 @@ use Getopt::Long;
use autouse 'Pod::Usage'=>qw(pod2usage); use autouse 'Pod::Usage'=>qw(pod2usage);
use autouse 'Data::Dumper'=>qw(Dumper); use autouse 'Data::Dumper'=>qw(Dumper);
my $filter_name = ""; my $filter_name = '';
my $filter_id; my $filter_id;
my $version = 0; my $version = 0;
@ -93,19 +97,19 @@ use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)
: ($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS}) : ($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS})
; ;
logInit(); logInit();
logSetSignal(); logSetSignal();
if ( $Config{ZM_OPT_UPLOAD} ) { if ( $Config{ZM_OPT_UPLOAD} ) {
# Comment these out if you don't have them and don't want to upload # Comment these out if you don't have them and don't want to upload
# or don't want to use that format # or don't want to use that format
if ( $Config{ZM_UPLOAD_ARCH_FORMAT} eq "zip" ) { if ( $Config{ZM_UPLOAD_ARCH_FORMAT} eq 'zip' ) {
require Archive::Zip; require Archive::Zip;
import Archive::Zip qw( :ERROR_CODES :CONSTANTS ); import Archive::Zip qw( :ERROR_CODES :CONSTANTS );
} else { } else {
require Archive::Tar; require Archive::Tar;
} }
if ( $Config{ZM_UPLOAD_PROTOCOL} eq "ftp" ) { if ( $Config{ZM_UPLOAD_PROTOCOL} eq 'ftp' ) {
require Net::FTP; require Net::FTP;
} else { } else {
require Net::SFTP::Foreign; require Net::SFTP::Foreign;
@ -144,8 +148,10 @@ if ( ! EVENT_PATH ) {
die; die;
} }
# In future, should not be neccessary wrt StorageAreas
chdir( EVENT_PATH ); chdir( EVENT_PATH );
# SHould not be neccessary... but nice to get a local var. What if it fails?
my $dbh = zmDbConnect(); my $dbh = zmDbConnect();
if ( $filter_name ) { if ( $filter_name ) {
@ -157,10 +163,11 @@ if ( $filter_name ) {
} }
if ( ! ( $filter_name or $filter_id ) ) { if ( ! ( $filter_name or $filter_id ) ) {
Debug("Sleeping due to start delay: " . START_DELAY . ' seconds...' );
sleep( START_DELAY ); sleep( START_DELAY );
} }
my $filters; my @filters;
my $last_action = 0; my $last_action = 0;
while( 1 ) { while( 1 ) {
@ -194,28 +201,34 @@ sub getFilters {
my @sql_values; my @sql_values;
my @filters; my @filters;
my $sql = "SELECT * FROM Filters WHERE"; my $sql = 'SELECT * FROM Filters WHERE';
if ( $$sql_filters{Name} ) { if ( $$sql_filters{Name} ) {
$sql .= " Name = ? and"; $sql .= ' Name = ? AND';
push @sql_values, $$sql_filters{Name}; push @sql_values, $$sql_filters{Name};
} elsif ( $$sql_filters{Id} ) { } elsif ( $$sql_filters{Id} ) {
$sql .= " Id = ? and"; $sql .= ' Id = ? AND';
push @sql_values, $$sql_filters{Id}; push @sql_values, $$sql_filters{Id};
} else { } else {
$sql .= " Background = 1 and"; $sql .= ' Background = 1 AND';
} }
$sql .= "( AutoArchive = 1 $sql .= '( AutoArchive = 1
or AutoVideo = 1 or AutoVideo = 1
or AutoUpload = 1 or AutoUpload = 1
or AutoEmail = 1 or AutoEmail = 1
or AutoMessage = 1 or AutoMessage = 1
or AutoExecute = 1 or AutoExecute = 1
or AutoDelete = 1 or AutoDelete = 1
) ORDER BY Name"; ) ORDER BY Name';
my $sth = $dbh->prepare_cached( $sql ) my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( @sql_values ) my $res;
or Fatal( "Can't execute '$sql': ".$sth->errstr() ); if ( $filter_name ) {
$res = $sth->execute( $filter_name )
or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
} else {
$res = $sth->execute()
or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
}
FILTER: while( my $db_filter = $sth->fetchrow_hashref() ) { FILTER: while( my $db_filter = $sth->fetchrow_hashref() ) {
my $filter = new ZoneMinder::Filter( $$db_filter{Id}, $db_filter ); my $filter = new ZoneMinder::Filter( $$db_filter{Id}, $db_filter );
Debug( "Found filter '$db_filter->{Name}'\n" ); Debug( "Found filter '$db_filter->{Name}'\n" );
@ -242,14 +255,14 @@ sub checkFilter {
my @Events = $filter->Execute(); my @Events = $filter->Execute();
Info( join( "Checking filter '$filter->{Name}'", Info( join( "Checking filter '$filter->{Name}'",
($filter->{AutoDelete}?", delete":""), ($filter->{AutoDelete}?', delete':''),
($filter->{AutoArchive}?", archive":""), ($filter->{AutoArchive}?', archive':''),
($filter->{AutoVideo}?", video":""), ($filter->{AutoVideo}?', video':''),
($filter->{AutoUpload}?", upload":""), ($filter->{AutoUpload}?', upload':''),
($filter->{AutoEmail}?", email":""), ($filter->{AutoEmail}?', email':''),
($filter->{AutoMessage}?", message":""), ($filter->{AutoMessage}?', message':''),
($filter->{AutoExecute}?", execute":""), ($filter->{AutoExecute}?', execute':''),
" returned " , scalar @Events , ' events', ' returned ' , scalar @Events , ' events',
"\n", "\n",
) ); ) );
@ -260,11 +273,11 @@ sub checkFilter {
if ( $filter->{AutoArchive} ) { if ( $filter->{AutoArchive} ) {
Info( "Archiving event $event->{Id}\n" ); Info( "Archiving event $event->{Id}\n" );
# Do it individually to avoid locking up the table for new events # Do it individually to avoid locking up the table for new events
my $sql = "update Events set Archived = 1 where Id = ?"; my $sql = 'UPDATE Events SET Archived = 1 WHERE Id = ?';
my $sth = $dbh->prepare_cached( $sql ) my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( $event->{Id} ) my $res = $sth->execute( $event->{Id} )
or Error( "Can't execute '$sql': ".$sth->errstr() ); or Error( "Unable toexecute '$sql': ".$sth->errstr() );
} }
if ( $Config{ZM_OPT_FFMPEG} && $filter->{AutoVideo} ) { if ( $Config{ZM_OPT_FFMPEG} && $filter->{AutoVideo} ) {
if ( !$event->{Videoed} ) { if ( !$event->{Videoed} ) {
@ -296,7 +309,7 @@ sub checkFilter {
my $Event = new ZoneMinder::Event( $$event{Id}, $event ); my $Event = new ZoneMinder::Event( $$event{Id}, $event );
$Event->delete(); $Event->delete();
} else { } else {
Error( "Unable to 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
} # end foreach event } # end foreach event
@ -330,8 +343,17 @@ sub generateVideo {
$format = $ffmpeg_formats[0]; $format = $ffmpeg_formats[0];
} }
my $command = $Config{ZM_PATH_BIN}."/zmvideo.pl -e " my $command = join( '',
.$event->{Id}." -r ".$rate." -s ".$scale." -f ".$format; $Config{ZM_PATH_BIN},
'/zmvideo.pl -e ',
$event->{Id},
' -r ',
$rate,
' -s ',
$scale,
' -f ',
$format,
);
my $output = qx($command); my $output = qx($command);
chomp( $output ); chomp( $output );
my $status = $? >> 8; my $status = $? >> 8;
@ -345,13 +367,12 @@ sub generateVideo {
} }
return( 0 ); return( 0 );
} else { } else {
my $sql = "update Events set Videoed = 1 where Id = ?"; my $sql = 'UPDATE Events SET Videoed = 1 WHERE Id = ?';
my $sth = $dbh->prepare_cached( $sql ) my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( $event->{Id} ) my $res = $sth->execute( $event->{Id} )
or Fatal( "Can't execute '$sql': ".$sth->errstr() ); or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
if ( wantarray() ) if ( wantarray() ) {
{
return( $format, $output ); return( $format, $output );
} }
} }
@ -363,52 +384,53 @@ sub generateVideo {
# If neither capture nor analyse image exists it will try to extract a frame from .mp4 file if exists # If neither capture nor analyse image exists it will try to extract a frame from .mp4 file if exists
# An empty string is returned if no one from methods above works # An empty string is returned if no one from methods above works
sub generateImage { sub generateImage {
my $event = shift; my $event = shift;
my $frame = shift; my $frame = shift;
my $analyse = do { @_ ? shift : 0 }; # don't return analyse image by default my $analyse = do { @_ ? shift : 0 }; # don't return analyse image by default
my $capture_image_path = sprintf("%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg", getEventPath($event), $frame->{FrameId}); my $capture_image_path = sprintf('%s/%0'.$Config{ZM_EVENT_IMAGE_DIGITS}.'d-capture.jpg', getEventPath($event), $frame->{FrameId});
my $analyse_image_path = sprintf("%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-analyse.jpg", getEventPath($event), $frame->{FrameId}) if $analyse; my $analyse_image_path = sprintf('%s/%0'.$Config{ZM_EVENT_IMAGE_DIGITS}.'d-analyse.jpg', getEventPath($event), $frame->{FrameId}) if $analyse;
my $video_path = sprintf("%s/%d-video.mp4", getEventPath($event), $event->{Id}); my $video_path = sprintf('%s/%d-video.mp4', getEventPath($event), $event->{Id});
my $image_path = ""; my $image_path = '';
# check if the image file exists. If the file doesn't exist and we use H264 try to extract it from .mp4 video # check if the image file exists. If the file doesn't exist and we use H264 try to extract it from .mp4 video
if ( $analyse && -r $analyse_image_path ) { if ( $analyse && -r $analyse_image_path ) {
$image_path = $analyse_image_path; $image_path = $analyse_image_path;
} elsif ( -r $capture_image_path ) { } elsif ( -r $capture_image_path ) {
$image_path = $capture_image_path; $image_path = $capture_image_path;
} elsif ( -e $video_path ) { } elsif ( -e $video_path ) {
if ( !system("ffmpeg -y -v 0 -i ".$video_path." -vf 'select=gte(n\\,".$frame->{FrameId}."),setpts=PTS-STARTPTS' -vframes 1 -f image2 ".$capture_image_path) ) { if ( !system('ffmpeg -y -v 0 -i '.$video_path." -vf 'select=gte(n\\,".$frame->{FrameId}."),setpts=PTS-STARTPTS' -vframes 1 -f image2 ".$capture_image_path) ) {
$image_path = $capture_image_path; $image_path = $capture_image_path;
}
} }
return $image_path; }
return $image_path;
} }
sub uploadArchFile { sub uploadArchFile {
my $filter = shift; my $filter = shift;
my $event = shift; my $event = shift;
if ( ! $Config{ZM_UPLOAD_HOST} ) { if ( ! $Config{ZM_UPLOAD_HOST} ) {
Error( "Cannot upload archive as no upload host defined" ); Error( 'Cannot upload archive as no upload host defined' );
return( 0 ); return( 0 );
} }
my $archFile = $event->{MonitorName}.'-'.$event->{Id}; my $archFile = $event->{MonitorName}.'-'.$event->{Id};
my $archImagePath = getEventPath( $event ) my $archImagePath = getEventPath( $event )
."/" .'/'
.( .(
( $Config{ZM_UPLOAD_ARCH_ANALYSE} ) ( $Config{ZM_UPLOAD_ARCH_ANALYSE} )
? '{*analyse,*capture}' ? '{*analyse,*capture}'
: '*capture' : '*capture'
) )
.".jpg" .'.jpg'
; ;
my @archImageFiles = glob($archImagePath); my @archImageFiles = glob($archImagePath);
my $archLocPath; my $archLocPath;
my $archError = 0; my $archError = 0;
if ( $Config{ZM_UPLOAD_ARCH_FORMAT} eq "zip" ) { if ( $Config{ZM_UPLOAD_ARCH_FORMAT} eq 'zip' ) {
$archFile .= '.zip'; $archFile .= '.zip';
$archLocPath = $Config{ZM_UPLOAD_LOC_DIR}.'/'.$archFile; $archLocPath = $Config{ZM_UPLOAD_LOC_DIR}.'/'.$archFile;
my $zip = Archive::Zip->new(); my $zip = Archive::Zip->new();
@ -419,7 +441,7 @@ sub uploadArchFile {
Debug( "Adding $imageFile\n" ); Debug( "Adding $imageFile\n" );
my $member = $zip->addFile( $imageFile ); my $member = $zip->addFile( $imageFile );
if ( !$member ) { if ( !$member ) {
Error( "Unable to add image file $imageFile to zip archive $archLocPath" ); Error( "Unable toto add image file $imageFile to zip archive $archLocPath" );
$archError = 1; $archError = 1;
last; last;
} }
@ -437,7 +459,7 @@ sub uploadArchFile {
} else { } else {
Error( "Error adding images to zip archive $archLocPath, not writing" ); Error( "Error adding images to zip archive $archLocPath, not writing" );
} }
} elsif ( $Config{ZM_UPLOAD_ARCH_FORMAT} eq "tar" ) { } elsif ( $Config{ZM_UPLOAD_ARCH_FORMAT} eq 'tar' ) {
if ( $Config{ZM_UPLOAD_ARCH_COMPRESS} ) { if ( $Config{ZM_UPLOAD_ARCH_COMPRESS} ) {
$archFile .= '.tar.gz'; $archFile .= '.tar.gz';
} else { } else {
@ -452,73 +474,72 @@ sub uploadArchFile {
@archImageFiles @archImageFiles
) )
) { ) {
Error( "Tar error: ".Archive::Tar->error()."\n " ); Error( 'Tar error: '.Archive::Tar->error()."\n " );
} }
} }
if ( $archError ) { if ( $archError ) {
return( 0 ); return( 0 );
}
if ( $Config{ZM_UPLOAD_PROTOCOL} eq "ftp" ) {
Info( "Uploading to ".$Config{ZM_UPLOAD_HOST}." using FTP\n" );
my $ftp = Net::FTP->new(
$Config{ZM_UPLOAD_HOST},
Timeout=>$Config{ZM_UPLOAD_TIMEOUT},
Passive=>$Config{ZM_UPLOAD_FTP_PASSIVE},
Debug=>$Config{ZM_UPLOAD_DEBUG}
);
if ( !$ftp ) {
Error( "Can't create FTP connection: $@" );
return( 0 );
}
$ftp->login( $Config{ZM_UPLOAD_USER}, $Config{ZM_UPLOAD_PASS} )
or Error( "FTP - Can't login" );
$ftp->binary()
or Error( "FTP - Can't go binary" );
$ftp->cwd( $Config{ZM_UPLOAD_REM_DIR} )
or Error( "FTP - Can't cwd" )
if ( $Config{ZM_UPLOAD_REM_DIR} );
$ftp->put( $archLocPath )
or Error( "FTP - Can't upload '$archLocPath'" );
$ftp->quit()
or Error( "FTP - Can't quit" );
} else { } else {
my $host = $Config{ZM_UPLOAD_HOST}; if ( $Config{ZM_UPLOAD_PROTOCOL} eq 'ftp' ) {
$host .= ":".$Config{ZM_UPLOAD_PORT} Info( 'Uploading to '.$Config{ZM_UPLOAD_HOST}." using FTP\n" );
if $Config{ZM_UPLOAD_PORT}; my $ftp = Net::FTP->new(
Info( "Uploading to ".$host." using SFTP\n" ); $Config{ZM_UPLOAD_HOST},
my %sftpOptions = ( host=>$Config{ZM_UPLOAD_HOST}, user=>$Config{ZM_UPLOAD_USER} ); Timeout=>$Config{ZM_UPLOAD_TIMEOUT},
$sftpOptions{password} = $Config{ZM_UPLOAD_PASS} Passive=>$Config{ZM_UPLOAD_FTP_PASSIVE},
if $Config{ZM_UPLOAD_PASS}; Debug=>$Config{ZM_UPLOAD_DEBUG}
$sftpOptions{port} = $Config{ZM_UPLOAD_PORT} );
if $Config{ZM_UPLOAD_PORT}; if ( !$ftp ) {
$sftpOptions{timeout} = $Config{ZM_UPLOAD_TIMEOUT} Error( "Unable tocreate FTP connection: $@" );
if $Config{ZM_UPLOAD_TIMEOUT}; return( 0 );
my @more_ssh_args; }
push @more_ssh_args, '-o'=>'StrictHostKeyChecking=no' $ftp->login( $Config{ZM_UPLOAD_USER}, $Config{ZM_UPLOAD_PASS} )
if ! $Config{ZM_UPLOAD_STRICT}; or Error( "FTP - Unable tologin" );
push @more_ssh_args, '-v' $ftp->binary()
if $Config{ZM_UPLOAD_DEBUG}; or Error( "FTP - Unable togo binary" );
$sftpOptions{more} = [@more_ssh_args]; $ftp->cwd( $Config{ZM_UPLOAD_REM_DIR} )
my $sftp = Net::SFTP::Foreign->new( $Config{ZM_UPLOAD_HOST}, %sftpOptions ); or Error( "FTP - Unable tocwd" )
if ( $sftp->error ) { if ( $Config{ZM_UPLOAD_REM_DIR} );
Error( "Can't create SFTP connection: ".$sftp->error ); $ftp->put( $archLocPath )
return( 0 ); or Error( "FTP - Unable toupload '$archLocPath'" );
$ftp->quit()
or Error( "FTP - Unable toquit" );
} else {
my $host = $Config{ZM_UPLOAD_HOST};
$host .= ':'.$Config{ZM_UPLOAD_PORT}
if $Config{ZM_UPLOAD_PORT};
Info( 'Uploading to '.$host." using SFTP\n" );
my %sftpOptions = ( host=>$Config{ZM_UPLOAD_HOST}, user=>$Config{ZM_UPLOAD_USER} );
$sftpOptions{password} = $Config{ZM_UPLOAD_PASS}
if $Config{ZM_UPLOAD_PASS};
$sftpOptions{port} = $Config{ZM_UPLOAD_PORT}
if $Config{ZM_UPLOAD_PORT};
$sftpOptions{timeout} = $Config{ZM_UPLOAD_TIMEOUT}
if $Config{ZM_UPLOAD_TIMEOUT};
my @more_ssh_args;
push @more_ssh_args, '-o'=>'StrictHostKeyChecking=no'
if ! $Config{ZM_UPLOAD_STRICT};
push @more_ssh_args, '-v'
if $Config{ZM_UPLOAD_DEBUG};
$sftpOptions{more} = [@more_ssh_args];
my $sftp = Net::SFTP::Foreign->new( $Config{ZM_UPLOAD_HOST}, %sftpOptions );
if ( $sftp->error ) {
Error( "Unable tocreate SFTP connection: ".$sftp->error );
return( 0 );
}
$sftp->setcwd( $Config{ZM_UPLOAD_REM_DIR} )
or Error( "SFTP - Unable tosetcwd: ".$sftp->error )
if $Config{ZM_UPLOAD_REM_DIR};
$sftp->put( $archLocPath, $archFile )
or Error( "SFTP - Unable toupload '$archLocPath': ".$sftp->error );
} }
$sftp->setcwd( $Config{ZM_UPLOAD_REM_DIR} ) unlink( $archLocPath );
or Error( "SFTP - Can't setcwd: ".$sftp->error ) my $sql = 'UPDATE Events SET Uploaded = 1 WHERE Id = ?';
if $Config{ZM_UPLOAD_REM_DIR}; my $sth = $dbh->prepare_cached( $sql )
$sftp->put( $archLocPath, $archFile ) or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
or Error( "SFTP - Can't upload '$archLocPath': ".$sftp->error ); my $res = $sth->execute( $event->{Id} )
or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
} }
unlink( $archLocPath );
my $sql = "update Events set Uploaded = 1 where Id = ?";
my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( $event->{Id} )
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
return( 1 ); return( 1 );
} }
@ -535,7 +556,7 @@ sub substituteTags {
my $monitor = {}; my $monitor = {};
if ( $need_monitor ) { if ( $need_monitor ) {
my $db_now = strftime( "%Y-%m-%d %H:%M:%S", localtime() ); my $db_now = strftime( '%Y-%m-%d %H:%M:%S', localtime() );
my $sql = "SELECT my $sql = "SELECT
M.Id, M.Id,
count(E.Id) as EventCount, count(E.Id) as EventCount,
@ -555,9 +576,9 @@ sub substituteTags {
ORDER BY Id" ORDER BY Id"
; ;
my $sth = $dbh->prepare_cached( $sql ) my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( $event->{MonitorId} ) my $res = $sth->execute( $event->{MonitorId} )
or Fatal( "Can't execute '$sql': ".$sth->errstr() ); or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
$monitor = $sth->fetchrow_hashref(); $monitor = $sth->fetchrow_hashref();
$sth->finish(); $sth->finish();
return() if ( !$monitor ); return() if ( !$monitor );
@ -574,9 +595,9 @@ sub substituteTags {
ORDER BY FrameId" ORDER BY FrameId"
; ;
my $sth = $dbh->prepare_cached( $sql ) my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( $event->{Id} ) my $res = $sth->execute( $event->{Id} )
or Fatal( "Can't execute '$sql': ".$sth->errstr() ); or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
while( my $frame = $sth->fetchrow_hashref() ) { while( my $frame = $sth->fetchrow_hashref() ) {
if ( !$first_alarm_frame ) { if ( !$first_alarm_frame ) {
$first_alarm_frame = $frame; $first_alarm_frame = $frame;
@ -615,64 +636,47 @@ sub substituteTags {
$text =~ s/%EST%/$event->{TotScore}/g; $text =~ s/%EST%/$event->{TotScore}/g;
$text =~ s/%ESA%/$event->{AvgScore}/g; $text =~ s/%ESA%/$event->{AvgScore}/g;
$text =~ s/%ESM%/$event->{MaxScore}/g; $text =~ s/%ESM%/$event->{MaxScore}/g;
if ( $first_alarm_frame ) { if ( $first_alarm_frame ) {
$text =~ s/%EPI1%/$url?view=frame&mid=$event->{MonitorId}&eid=$event->{Id}&fid=$first_alarm_frame->{FrameId}/g; $text =~ s/%EPI1%/$url?view=frame&mid=$event->{MonitorId}&eid=$event->{Id}&fid=$first_alarm_frame->{FrameId}/g;
$text =~ s/%EPIM%/$url?view=frame&mid=$event->{MonitorId}&eid=$event->{Id}&fid=$max_alarm_frame->{FrameId}/g; $text =~ s/%EPIM%/$url?view=frame&mid=$event->{MonitorId}&eid=$event->{Id}&fid=$max_alarm_frame->{FrameId}/g;
if ( $attachments_ref && $text =~ s/%EI1%//g ) { if ( $attachments_ref && $text =~ s/%EI1%//g ) {
my $path = generateImage( $event, $first_alarm_frame); my $path = generateImage( $event, $first_alarm_frame );
if ( -e $path ) {
push( @$attachments_ref,
{
type=>"image/jpeg",
path=>$path
}
);
}
}
if ( $attachments_ref && $text =~ s/%EIM%//g ) {
# Don't attach the same image twice
if ( !@$attachments_ref
|| ($first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId} )
) {
my $path = generateImage( $event, $max_alarm_frame);
if ( -e $path ) { if ( -e $path ) {
push( @$attachments_ref, push( @$attachments_ref, { type=>'image/jpeg', path=>$path } );
{
type=>"image/jpeg",
path=>$path
}
);
} }
} }
}
if ( $attachments_ref && $text =~ s/%EI1A%//g ) { if ( $attachments_ref && $text =~ s/%EIM%//g ) {
my $path = generateImage( $event, $first_alarm_frame, "analyse" ); # Don't attach the same image twice
if ( -e $path ) { if ( !@$attachments_ref
push( @$attachments_ref, || ($first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId} )
{ ) {
type=>"image/jpeg", my $path = generateImage( $event, $max_alarm_frame );
path=>$path if ( -e $path ) {
push( @$attachments_ref, { type=>'image/jpeg', path=>$path } );
} }
);
}
}
if ( $attachments_ref && $text =~ s/%EIMA%//g ) {
# Don't attach the same image twice
if ( !@$attachments_ref
|| ($first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId} )
) {
my $path = generateImage( $event, $max_alarm_frame, "analyse");
if ( -e $path ) {
push( @$attachments_ref,
{
type=>"image/jpeg",
path=>$path
}
);
} }
} }
} if ( $attachments_ref && $text =~ s/%EI1A%//g ) {
} my $path = generateImage( $event, $first_alarm_frame, 'analyse' );
if ( -e $path ) {
push( @$attachments_ref, { type=>'image/jpeg', path=>$path } );
}
}
if ( $attachments_ref && $text =~ s/%EIMA%//g ) {
# Don't attach the same image twice
if ( !@$attachments_ref
|| ($first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId} )
) {
my $path = generateImage( $event, $max_alarm_frame, 'analyse');
if ( -e $path ) {
push( @$attachments_ref, { type=>'image/jpeg', path=>$path } );
}
}
}
} # end if $first_alarm_frame
if ( $attachments_ref && $Config{ZM_OPT_FFMPEG} ) { if ( $attachments_ref && $Config{ZM_OPT_FFMPEG} ) {
if ( $text =~ s/%EV%//g ) { if ( $text =~ s/%EV%//g ) {
my ( $format, $path ) = generateVideo( $filter, $event ); my ( $format, $path ) = generateVideo( $filter, $event );
@ -694,7 +698,7 @@ sub substituteTags {
$text =~ s/%FP%/$url?view=filter&mid=$event->{MonitorId}&filter_name=$filter_name/g; $text =~ s/%FP%/$url?view=filter&mid=$event->{MonitorId}&filter_name=$filter_name/g;
return( $text ); return( $text );
} } # end subsitituteTags
sub sendEmail { sub sendEmail {
my $filter = shift; my $filter = shift;
@ -705,7 +709,7 @@ sub sendEmail {
return( 0 ); return( 0 );
} }
if ( ! $Config{ZM_EMAIL_ADDRESS} ) { if ( ! $Config{ZM_EMAIL_ADDRESS} ) {
Error( "No email address defined, not sending email" ); Error( 'No email address defined, not sending email' );
return( 0 ); return( 0 );
} }
@ -726,11 +730,11 @@ sub sendEmail {
From => $Config{ZM_FROM_EMAIL}, From => $Config{ZM_FROM_EMAIL},
To => $Config{ZM_EMAIL_ADDRESS}, To => $Config{ZM_EMAIL_ADDRESS},
Subject => $subject, Subject => $subject,
Type => "multipart/mixed" Type => 'multipart/mixed'
); );
### Add the text message part ### Add the text message part
$mail->attach ( $mail->attach (
Type => "TEXT", Type => 'TEXT',
Data => $body Data => $body
); );
### Add the attachments ### Add the attachments
@ -739,7 +743,7 @@ sub sendEmail {
$mail->attach( $mail->attach(
Path => $attachment->{path}, Path => $attachment->{path},
Type => $attachment->{type}, Type => $attachment->{type},
Disposition => "attachment" Disposition => 'attachment'
); );
} }
### Send the Message ### Send the Message
@ -752,15 +756,15 @@ sub sendEmail {
$ssmtp_location = qx('which ssmtp'); $ssmtp_location = qx('which ssmtp');
} }
if ( !$ssmtp_location ) { if ( !$ssmtp_location ) {
Debug( "Can't find ssmtp, trying MIME::Lite->send" ); Debug( "Unable tofind ssmtp, trying MIME::Lite->send" );
MIME::Lite->send( "smtp", $Config{ZM_EMAIL_HOST}, Timeout=>60 ); MIME::Lite->send( 'smtp', $Config{ZM_EMAIL_HOST}, Timeout=>60 );
$mail->send(); $mail->send();
} else { } else {
### Send using SSMTP ### Send using SSMTP
$mail->send( 'sendmail', $ssmtp_location, $Config{ZM_EMAIL_ADDRESS} ); $mail->send( 'sendmail', $ssmtp_location, $Config{ZM_EMAIL_ADDRESS} );
} }
} else { } else {
MIME::Lite->send( "smtp", $Config{ZM_EMAIL_HOST}, Timeout=>60 ); MIME::Lite->send( 'smtp', $Config{ZM_EMAIL_HOST}, Timeout=>60 );
$mail->send(); $mail->send();
} }
} else { } else {
@ -777,23 +781,23 @@ sub sendEmail {
$mail->attach( $mail->attach(
Path => $attachment->{path}, Path => $attachment->{path},
Type => $attachment->{type}, Type => $attachment->{type},
Encoding => "base64" Encoding => 'base64'
); );
} }
$mail->smtpsend( Host => $Config{ZM_EMAIL_HOST}, MailFrom => $Config{ZM_FROM_EMAIL} ); $mail->smtpsend( Host => $Config{ZM_EMAIL_HOST}, MailFrom => $Config{ZM_FROM_EMAIL} );
} }
}; };
if ( $@ ) { if ( $@ ) {
Error( "Can't send email: $@" ); Error( "Unable tosend email: $@" );
return( 0 ); return( 0 );
} else { } else {
Info( "Notification email sent\n" ); Info( "Notification email sent\n" );
} }
my $sql = "update Events set Emailed = 1 where Id = ?"; my $sql = 'update Events set Emailed = 1 where Id = ?';
my $sth = $dbh->prepare_cached( $sql ) my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( $event->{Id} ) my $res = $sth->execute( $event->{Id} )
or Fatal( "Can't execute '$sql': ".$sth->errstr() ); or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
return( 1 ); return( 1 );
} }
@ -807,7 +811,7 @@ sub sendMessage {
return( 0 ); return( 0 );
} }
if ( ! $Config{ZM_MESSAGE_ADDRESS} ) { if ( ! $Config{ZM_MESSAGE_ADDRESS} ) {
Error( "No message address defined, not sending message" ); Error( 'No message address defined, not sending message' );
return( 0 ); return( 0 );
} }
@ -828,11 +832,11 @@ sub sendMessage {
From => $Config{ZM_FROM_EMAIL}, From => $Config{ZM_FROM_EMAIL},
To => $Config{ZM_MESSAGE_ADDRESS}, To => $Config{ZM_MESSAGE_ADDRESS},
Subject => $subject, Subject => $subject,
Type => "multipart/mixed" Type => 'multipart/mixed'
); );
### Add the text message part ### Add the text message part
$mail->attach ( $mail->attach (
Type => "TEXT", Type => 'TEXT',
Data => $body Data => $body
); );
### Add the attachments ### Add the attachments
@ -841,7 +845,7 @@ sub sendMessage {
$mail->attach( $mail->attach(
Path => $attachment->{path}, Path => $attachment->{path},
Type => $attachment->{type}, Type => $attachment->{type},
Disposition => "attachment" Disposition => 'attachment'
); );
} }
### Send the Message ### Send the Message
@ -854,15 +858,15 @@ sub sendMessage {
$ssmtp_location = qx('which ssmtp'); $ssmtp_location = qx('which ssmtp');
} }
if ( !$ssmtp_location ) { if ( !$ssmtp_location ) {
Debug( "Can't find ssmtp, trying MIME::Lite->send" ); Debug( 'Unable tofind ssmtp, trying MIME::Lite->send' );
MIME::Lite->send( "smtp", $Config{ZM_EMAIL_HOST}, Timeout=>60 ); MIME::Lite->send( 'smtp', $Config{ZM_EMAIL_HOST}, Timeout=>60 );
$mail->send(); $mail->send();
} else { } else {
### Send using SSMTP ### Send using SSMTP
$mail->send( 'sendmail', $ssmtp_location, $Config{ZM_MESSAGE_ADDRESS} ); $mail->send( 'sendmail', $ssmtp_location, $Config{ZM_MESSAGE_ADDRESS} );
} }
} else { } else {
MIME::Lite->send( "smtp", $Config{ZM_EMAIL_HOST}, Timeout=>60 ); MIME::Lite->send( 'smtp', $Config{ZM_EMAIL_HOST}, Timeout=>60 );
$mail->send(); $mail->send();
} }
} else { } else {
@ -879,7 +883,7 @@ sub sendMessage {
$mail->attach( $mail->attach(
Path => $attachment->{path}, Path => $attachment->{path},
Type => $attachment->{type}, Type => $attachment->{type},
Encoding => "base64" Encoding => 'base64'
); );
} }
$mail->smtpsend( Host => $Config{ZM_EMAIL_HOST}, $mail->smtpsend( Host => $Config{ZM_EMAIL_HOST},
@ -888,16 +892,16 @@ sub sendMessage {
} }
}; };
if ( $@ ) { if ( $@ ) {
Error( "Can't send email: $@" ); Error( "Unable tosend email: $@" );
return( 0 ); return( 0 );
} else { } else {
Info( "Notification message sent\n" ); Info( "Notification message sent\n" );
} }
my $sql = "update Events set Messaged = 1 where Id = ?"; my $sql = 'update Events set Messaged = 1 where Id = ?';
my $sth = $dbh->prepare_cached( $sql ) my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( $event->{Id} ) my $res = $sth->execute( $event->{Id} )
or Fatal( "Can't execute '$sql': ".$sth->errstr() ); or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
return( 1 ); return( 1 );
} }
@ -923,11 +927,11 @@ sub executeCommand {
Error( "Command '$command' exited with status: $status\n" ); Error( "Command '$command' exited with status: $status\n" );
return( 0 ); return( 0 );
} else { } else {
my $sql = "update Events set Executed = 1 where Id = ?"; my $sql = 'update Events set Executed = 1 where Id = ?';
my $sth = $dbh->prepare_cached( $sql ) my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( $event->{Id} ) my $res = $sth->execute( $event->{Id} )
or Fatal( "Can't execute '$sql': ".$sth->errstr() ); or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
} }
return( 1 ); return( 1 );
} }

View File

@ -23,7 +23,7 @@
#include "zm_ffmpeg_camera.h" #include "zm_ffmpeg_camera.h"
extern "C"{ extern "C" {
#include "libavutil/time.h" #include "libavutil/time.h"
} }
#ifndef AV_ERROR_MAX_STRING_SIZE #ifndef AV_ERROR_MAX_STRING_SIZE
@ -125,8 +125,7 @@ int FfmpegCamera::PreCapture()
return( 0 ); return( 0 );
} }
int FfmpegCamera::Capture( Image &image ) int FfmpegCamera::Capture( Image &image ) {
{
if (!mCanCapture){ if (!mCanCapture){
return -1; return -1;
} }
@ -167,11 +166,8 @@ int FfmpegCamera::Capture( Image &image )
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 );
// What about audio stream? Maybe someday we could do sound detection... // What about audio stream? Maybe someday we could do sound detection...
if ( packet.stream_index == mVideoStreamId ) { if ( packet.stream_index == mVideoStreamId ) {
#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0) int ret = zm_avcodec_decode_video( mVideoCodecContext, mRawFrame, &frameComplete, &packet );
if (avcodec_decode_video2(mVideoCodecContext, mRawFrame, &frameComplete, &packet) < 0) if ( ret < 0 )
#else
if (avcodec_decode_video(mVideoCodecContext, mRawFrame, &frameComplete, packet.data, packet.size) < 0)
#endif
Fatal( "Unable to decode frame at frame %d", frameCount ); Fatal( "Unable to decode frame at frame %d", frameCount );
Debug( 4, "Decoded video packet at frame %d", frameCount ); Debug( 4, "Decoded video packet at frame %d", frameCount );
@ -364,7 +360,7 @@ int FfmpegCamera::OpenFfmpeg() {
Fatal( "Unable to open codec for video stream from %s", mPath.c_str() ); Fatal( "Unable to open codec for video stream from %s", mPath.c_str() );
} }
if (mAudioStreamId >= 0) { if ( mAudioStreamId >= 0 ) {
mAudioCodecContext = mFormatContext->streams[mAudioStreamId]->codec; mAudioCodecContext = mFormatContext->streams[mAudioStreamId]->codec;
if ((mAudioCodec = avcodec_find_decoder(mAudioCodecContext->codec_id)) == NULL) { if ((mAudioCodec = avcodec_find_decoder(mAudioCodecContext->codec_id)) == NULL) {
Debug(1, "Can't find codec for audio stream from %s", mPath.c_str()); Debug(1, "Can't find codec for audio stream from %s", mPath.c_str());
@ -437,7 +433,7 @@ int FfmpegCamera::OpenFfmpeg() {
mCanCapture = true; mCanCapture = true;
return 0; return 0;
} } // int FfmpegCamera::OpenFfmpeg()
int FfmpegCamera::ReopenFfmpeg() { int FfmpegCamera::ReopenFfmpeg() {
@ -462,8 +458,7 @@ int FfmpegCamera::CloseFfmpeg(){
av_frame_free( &mRawFrame ); av_frame_free( &mRawFrame );
#if HAVE_LIBSWSCALE #if HAVE_LIBSWSCALE
if ( mConvertContext ) if ( mConvertContext ) {
{
sws_freeContext( mConvertContext ); sws_freeContext( mConvertContext );
mConvertContext = NULL; mConvertContext = NULL;
} }
@ -490,8 +485,7 @@ int FfmpegCamera::CloseFfmpeg(){
return 0; return 0;
} }
int FfmpegCamera::FfmpegInterruptCallback(void *ctx) int FfmpegCamera::FfmpegInterruptCallback(void *ctx) {
{
FfmpegCamera* camera = reinterpret_cast<FfmpegCamera*>(ctx); FfmpegCamera* camera = reinterpret_cast<FfmpegCamera*>(ctx);
if (camera->mIsOpening){ if (camera->mIsOpening){
int now = time(NULL); int now = time(NULL);
@ -529,14 +523,14 @@ void *FfmpegCamera::ReopenFfmpegThreadCallback(void *ctx){
//Function to handle capture and store //Function to handle capture and store
int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event_file ) { int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event_file ) {
if (!mCanCapture){ if ( ! mCanCapture ) {
return -1; return -1;
} }
int ret; int ret;
static char errbuf[AV_ERROR_MAX_STRING_SIZE]; static 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);
@ -548,7 +542,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
mReopenThread = 0; mReopenThread = 0;
} }
if (mVideoCodecContext->codec_id != AV_CODEC_ID_H264) { if ( mVideoCodecContext->codec_id != AV_CODEC_ID_H264 ) {
Error( "Input stream is not h264. The stored event file may not be viewable in browser." ); Error( "Input stream is not h264. The stored event file may not be viewable in browser." );
} }
@ -639,6 +633,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
unsigned int packet_count = 0; unsigned int packet_count = 0;
ZMPacket *queued_packet; ZMPacket *queued_packet;
// Clear all packets that predate the moment when the recording began
packetqueue.clear_unwanted_packets( &recording, mVideoStreamId ); packetqueue.clear_unwanted_packets( &recording, mVideoStreamId );
while ( ( queued_packet = packetqueue.popPacket() ) ) { while ( ( queued_packet = packetqueue.popPacket() ) ) {
@ -673,7 +668,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
// 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.stream_index == mVideoStreamId) { if ( packet.stream_index == mVideoStreamId ) {
if ( key_frame ) { if ( key_frame ) {
Debug(3, "Clearing queue"); Debug(3, "Clearing queue");
packetqueue.clearQueue( monitor->GetPreEventCount(), mVideoStreamId ); packetqueue.clearQueue( monitor->GetPreEventCount(), mVideoStreamId );
@ -688,18 +683,22 @@ else if ( packet.pts && video_last_pts > packet.pts ) {
} }
#endif #endif
} }
if ( // The following lines should ensure that the queue always begins with a video keyframe
( packet.stream_index != mAudioStreamId || record_audio ) if ( packet.stream_index == mAudioStreamId ) {
&& //Debug(2, "Have audio packet, reocrd_audio is (%d) and packetqueue.size is (%d)", record_audio, packetqueue.size() );
( key_frame || packetqueue.size() ) if ( record_audio && packetqueue.size() ) {
) { // 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.stream_index == mVideoStreamId ) {
if ( key_frame || packetqueue.size() ) // it's a keyframe or we already have something in the queue
packetqueue.queuePacket( &packet );
} }
} // end if recording or not } // end if recording or not
if ( packet.stream_index == mVideoStreamId ) { if ( packet.stream_index == mVideoStreamId ) {
if ( videoStore ) { if ( videoStore ) {
//Write the packet to our video store //Write the packet to our video store
int ret = videoStore->writeVideoFramePacket( &packet ); int ret = videoStore->writeVideoFramePacket( &packet );
if ( ret < 0 ) { //Less than zero and we skipped a frame if ( ret < 0 ) { //Less than zero and we skipped a frame
@ -779,8 +778,10 @@ else if ( packet.pts && video_last_pts > packet.pts ) {
return 0; return 0;
} }
} else { } else {
Debug(4, "Not recording audio packet" ); Debug(4, "Not doing recording of audio packet" );
} }
} else {
Debug(4, "Have audio packet, but not recording atm" );
} }
} else { } else {
#if LIBAVUTIL_VERSION_CHECK(56, 23, 0, 23, 0) #if LIBAVUTIL_VERSION_CHECK(56, 23, 0, 23, 0)

View File

@ -60,14 +60,12 @@ ZMPacket* zm_packetqueue::popPacket( ) {
unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream_id ) { unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream_id ) {
Debug(3, "Clearing all but %d frames", frames_to_keep ); Debug(3, "Clearing all but %d frames, queue has %d", frames_to_keep, pktQueue.size() );
frames_to_keep += 1; frames_to_keep += 1;
if ( pktQueue.empty() ) { if ( pktQueue.empty() ) {
Debug(3, "Queue is empty"); Debug(3, "Queue is empty");
return 0; return 0;
} else {
Debug(3, "Queue has (%d)", pktQueue.size() );
} }
list<ZMPacket *>::reverse_iterator it; list<ZMPacket *>::reverse_iterator it;
@ -77,18 +75,19 @@ unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream
ZMPacket *zm_packet = *it; ZMPacket *zm_packet = *it;
AVPacket *av_packet = &(zm_packet->packet); AVPacket *av_packet = &(zm_packet->packet);
Debug(3, "Looking at packet with stream index (%d) with keyframe (%d), frames_to_keep is (%d)", av_packet->stream_index, ( av_packet->flags & AV_PKT_FLAG_KEY ), frames_to_keep ); Debug(4, "Looking at packet with stream index (%d) with keyframe (%d), frames_to_keep is (%d)", av_packet->stream_index, ( av_packet->flags & AV_PKT_FLAG_KEY ), frames_to_keep );
// Want frames_to_keep video keyframes. Otherwise, we may not have enough // Want frames_to_keep video keyframes. Otherwise, we may not have enough
if ( ( av_packet->stream_index == stream_id) && ( av_packet->flags & AV_PKT_FLAG_KEY ) ) { if ( ( av_packet->stream_index == stream_id) && ( av_packet->flags & AV_PKT_FLAG_KEY ) ) {
if (!frames_to_keep)
break;
frames_to_keep --; frames_to_keep --;
} }
} }
if ( frames_to_keep ) {
Debug(3, "Hit end of queue, still need (%d) video keyframes", frames_to_keep );
}
unsigned int delete_count = 0; unsigned int delete_count = 0;
while ( it != pktQueue.rend() ) { while ( it != pktQueue.rend() ) {
Debug(3, "Deleting a packet from the front, count is (%d)", delete_count ); Debug(4, "Deleting a packet from the front, count is (%d)", delete_count );
packet = pktQueue.front(); packet = pktQueue.front();
pktQueue.pop_front(); pktQueue.pop_front();
@ -96,6 +95,7 @@ unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream
delete_count += 1; delete_count += 1;
} }
Debug(3, "Deleted (%d) packets", delete_count );
return delete_count; return delete_count;
} // end unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream_id ) } // end unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream_id )
@ -123,10 +123,10 @@ void zm_packetqueue::clear_unwanted_packets( timeval *recording_started, int mVi
// Step 2 - pop packets until we get to the packet in step 2 // Step 2 - pop packets until we get to the packet in step 2
list<ZMPacket *>::reverse_iterator it; list<ZMPacket *>::reverse_iterator it;
Debug(3, "Looking for keyframe after start recording stream id (%d)", mVideoStreamId );
for ( it = pktQueue.rbegin(); it != pktQueue.rend(); ++ it ) { for ( it = pktQueue.rbegin(); it != pktQueue.rend(); ++ it ) {
ZMPacket *zm_packet = *it; ZMPacket *zm_packet = *it;
AVPacket *av_packet = &(zm_packet->packet); AVPacket *av_packet = &(zm_packet->packet);
Debug(1, "Looking for keyframe after start" );
if ( if (
( av_packet->flags & AV_PKT_FLAG_KEY ) ( av_packet->flags & AV_PKT_FLAG_KEY )
&& &&
@ -134,7 +134,7 @@ Debug(1, "Looking for keyframe after start" );
&& &&
timercmp( &(zm_packet->timestamp), recording_started, < ) timercmp( &(zm_packet->timestamp), recording_started, < )
) { ) {
Debug(1, "Found keyframe before start" ); Debug(3, "Found keyframe before start with stream index (%d) with keyframe (%d)", av_packet->stream_index, ( av_packet->flags & AV_PKT_FLAG_KEY ) );
break; break;
} }
} }
@ -143,10 +143,29 @@ Debug(1, "Found keyframe before start" );
return; return;
} }
ZMPacket *zm_packet = *it;
AVPacket *av_packet = &(zm_packet->packet);
Debug(3, "Found packet before start with stream index (%d) with keyframe (%d), distance(%d), size(%d)",
av_packet->stream_index,
( av_packet->flags & AV_PKT_FLAG_KEY ),
distance( it, pktQueue.rend() ),
pktQueue.size() );
unsigned int deleted_frames = 0;
ZMPacket *packet = NULL; ZMPacket *packet = NULL;
while ( pktQueue.rend() != it ) { while ( distance( it, pktQueue.rend() ) > 1 ) {
//while ( pktQueue.rend() != it ) {
packet = pktQueue.front(); packet = pktQueue.front();
pktQueue.pop_front(); pktQueue.pop_front();
delete packet; delete packet;
deleted_frames += 1;
}
zm_packet = pktQueue.front();
av_packet = &(zm_packet->packet);
if ( ( ! ( av_packet->flags & AV_PKT_FLAG_KEY ) ) || ( av_packet->stream_index != mVideoStreamId ) ) {
Error( "Done looking for keyframe. Deleted %d frames. Remaining frames in queue: %d stream of head packet is (%d), keyframe (%d), distance(%d), packets(%d)", deleted_frames, pktQueue.size(), av_packet->stream_index, ( av_packet->flags & AV_PKT_FLAG_KEY ), distance( it, pktQueue.rend() ), pktQueue.size() );
} else {
Debug(1, "Done looking for keyframe. Deleted %d frames. Remaining frames in queue: %d stream of head packet is (%d), keyframe (%d), distance(%d), packets(%d)", deleted_frames, pktQueue.size(), av_packet->stream_index, ( av_packet->flags & AV_PKT_FLAG_KEY ), distance( it, pktQueue.rend() ), pktQueue.size() );
} }
} }

View File

@ -27,7 +27,7 @@
#include "zm.h" #include "zm.h"
#include "zm_videostore.h" #include "zm_videostore.h"
extern "C"{ extern "C" {
#include "libavutil/time.h" #include "libavutil/time.h"
} }
@ -37,23 +37,23 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
int64_t nStartTime, int64_t nStartTime,
Monitor * monitor Monitor * monitor
) { ) {
video_input_stream = p_video_input_stream; video_input_stream = p_video_input_stream;
audio_input_stream = p_audio_input_stream; audio_input_stream = p_audio_input_stream;
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
video_input_context = avcodec_alloc_context3( NULL );
avcodec_parameters_to_context( video_input_context, video_input_stream->codecpar );
#else
video_input_context = video_input_stream->codec; video_input_context = video_input_stream->codec;
#endif
//store inputs in variables local to class //store inputs in variables local to class
filename = filename_in; filename = filename_in;
format = format_in; format = format_in;
keyframeMessage = false;
keyframeSkipNumber = 0;
Info("Opening video storage stream %s format: %s\n", filename, format); Info("Opening video storage stream %s format: %s\n", filename, format);
//Init everything we need, shouldn't have to do this, ffmpeg_camera or something else will call it.
//av_register_all();
ret = avformat_alloc_output_context2(&oc, NULL, NULL, filename); ret = avformat_alloc_output_context2(&oc, NULL, NULL, filename);
if ( ret < 0 ) { if ( ret < 0 ) {
Warning("Could not create video storage stream %s as no output context" Warning("Could not create video storage stream %s as no output context"
@ -62,11 +62,11 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
av_make_error_string(ret).c_str() av_make_error_string(ret).c_str()
); );
} else { } else {
Debug(2, "Success alocateing output context"); Debug(2, "Success allocating output context");
} }
//Couldn't deduce format from filename, trying from format name //Couldn't deduce format from filename, trying from format name
if (!oc) { if ( ! oc ) {
avformat_alloc_output_context2(&oc, NULL, format, filename); avformat_alloc_output_context2(&oc, NULL, format, filename);
if (!oc) { if (!oc) {
Fatal("Could not create video storage stream %s as no output context" Fatal("Could not create video storage stream %s as no output context"
@ -82,29 +82,47 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ ); if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ );
oc->metadata = pmetadata; oc->metadata = pmetadata;
output_format = oc->oformat; output_format = oc->oformat;
video_output_stream = avformat_new_stream(oc, (AVCodec*)video_input_context->codec); #if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
if (!video_output_stream) { // Since we are not re-encoding, all we have to do is copy the parameters
video_output_context = avcodec_alloc_context3( NULL );
// Copy params from inputstream to context
ret = avcodec_parameters_to_context( video_output_context, video_input_stream->codecpar );
if ( ret < 0 ) {
Error( "Could not initialize context parameteres");
return;
} else {
Debug( 2, "Success getting parameters");
}
video_output_stream = avformat_new_stream( oc, NULL );
if ( ! video_output_stream ) {
Fatal("Unable to create video out stream\n"); Fatal("Unable to create video out stream\n");
} else { } else {
Debug(2, "Success creating video out stream" ); Debug(2, "Success creating video out stream" );
} }
video_output_context = video_output_stream->codec; // Now copy them to the output stream
ret = avcodec_parameters_from_context( video_output_stream->codecpar, video_output_context );
#if LIBAVCODEC_VERSION_CHECK(58, 0, 0, 0, 0)
Debug(2, "setting parameters");
ret = avcodec_parameters_to_context( video_output_context, video_input_stream->codecpar );
if ( ret < 0 ) { if ( ret < 0 ) {
Error( "Could not initialize stream parameteres"); Error( "Could not initialize stream parameteres");
return; return;
} else { } else {
Debug(2, "Success getting parameters"); Debug(2, "Success setting parameters");
} }
zm_dump_stream_format( oc, 0, 0, 1 );
#else #else
ret = avcodec_copy_context(video_output_context, video_input_context ); video_output_stream = avformat_new_stream(oc, (AVCodec*)video_input_context->codec );
if ( ! video_output_stream ) {
Fatal("Unable to create video out stream\n");
} else {
Debug(2, "Success creating video out stream" );
}
video_output_context = video_output_stream->codec;
ret = avcodec_copy_context( video_output_context, video_input_context );
if (ret < 0) { if (ret < 0) {
Fatal("Unable to copy input video context to output video context %s\n", Fatal("Unable to copy input video context to output video context %s\n",
av_make_error_string(ret).c_str()); av_make_error_string(ret).c_str());
@ -130,7 +148,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
// WHY? // WHY?
//video_output_context->codec_tag = 0; //video_output_context->codec_tag = 0;
if (!video_output_context->codec_tag) { if ( ! video_output_context->codec_tag ) {
Debug(2, "No codec_tag"); Debug(2, "No codec_tag");
if (! oc->oformat->codec_tag if (! oc->oformat->codec_tag
|| av_codec_get_id (oc->oformat->codec_tag, video_input_context->codec_tag) == video_output_context->codec_id || av_codec_get_id (oc->oformat->codec_tag, video_input_context->codec_tag) == video_output_context->codec_id
@ -145,6 +163,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
} }
Monitor::Orientation orientation = monitor->getOrientation(); Monitor::Orientation orientation = monitor->getOrientation();
Debug(3, "Have orientation" );
if ( orientation ) { if ( orientation ) {
if ( orientation == Monitor::ROTATE_0 ) { if ( orientation == Monitor::ROTATE_0 ) {
@ -169,13 +188,22 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
resample_context = NULL; resample_context = NULL;
#endif #endif
if (audio_input_stream) { if ( audio_input_stream ) {
Debug(3, "Have audio stream" );
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
audio_input_context = avcodec_alloc_context3( NULL );
ret = avcodec_parameters_to_context( audio_input_context, audio_input_stream->codecpar );
#else
audio_input_context = audio_input_stream->codec; audio_input_context = audio_input_stream->codec;
#endif
if ( audio_input_context->codec_id != AV_CODEC_ID_AAC ) { if ( audio_input_context->codec_id != AV_CODEC_ID_AAC ) {
static char error_buffer[256]; static char error_buffer[256];
avcodec_string(error_buffer, sizeof(error_buffer), audio_input_context, 0 ); avcodec_string(error_buffer, sizeof(error_buffer), audio_input_context, 0 );
Debug(3, "Got something other than AAC (%s)", error_buffer ); Debug(2, "Got something other than AAC (%s)", error_buffer );
if ( ! setup_resampler() ) { if ( ! setup_resampler() ) {
return; return;
} }
@ -187,9 +215,16 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
Error("Unable to create audio out stream\n"); Error("Unable to create audio out stream\n");
audio_output_stream = NULL; audio_output_stream = NULL;
} else { } else {
audio_output_context = audio_output_stream->codec; Debug(2, "setting parameters");
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
audio_output_context = avcodec_alloc_context3( NULL );
// Copy params from inputstream to context
ret = avcodec_parameters_to_context( audio_output_context, audio_input_stream->codecpar );
#else
audio_output_context = audio_output_stream->codec;
ret = avcodec_copy_context(audio_output_context, audio_input_context); ret = avcodec_copy_context(audio_output_context, audio_input_context);
#endif
if (ret < 0) { if (ret < 0) {
Error("Unable to copy audio context %s\n", av_make_error_string(ret).c_str()); Error("Unable to copy audio context %s\n", av_make_error_string(ret).c_str());
audio_output_stream = NULL; audio_output_stream = NULL;
@ -233,7 +268,8 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
//av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); //av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
//av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); //av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
//av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov+default_base_moof", 0); //av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov+default_base_moof", 0);
if ((ret = avformat_write_header(oc, &opts)) < 0) { if ((ret = avformat_write_header(oc, NULL)) < 0) {
//if ((ret = avformat_write_header(oc, &opts)) < 0) {
Warning("Unable to set movflags to frag_custom+dash+delay_moov"); Warning("Unable to set movflags to frag_custom+dash+delay_moov");
/* Write the stream header, if any. */ /* Write the stream header, if any. */
ret = avformat_write_header(oc, NULL); ret = avformat_write_header(oc, NULL);
@ -252,8 +288,10 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
video_last_dts = 0; video_last_dts = 0;
audio_last_pts = 0; audio_last_pts = 0;
audio_last_dts = 0; audio_last_dts = 0;
previous_pts = 0; video_previous_pts = 0;
previous_dts = 0; video_previous_dts = 0;
audio_previous_pts = 0;
audio_previous_dts = 0;
} // VideoStore::VideoStore } // VideoStore::VideoStore
@ -262,14 +300,14 @@ VideoStore::~VideoStore(){
if ( audio_output_codec ) { if ( audio_output_codec ) {
// Do we need to flush the outputs? I have no idea. // Do we need to flush the outputs? I have no idea.
AVPacket pkt; AVPacket pkt;
int got_packet; int got_packet = 0;
av_init_packet(&pkt); av_init_packet(&pkt);
pkt.data = NULL; pkt.data = NULL;
pkt.size = 0; pkt.size = 0;
int64_t size; int64_t size;
while(1) { while(1) {
#if LIBAVCODEC_VERSION_CHECK(58, 0, 0, 0, 0) #if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
ret = avcodec_receive_packet( audio_output_context, &pkt ); ret = avcodec_receive_packet( audio_output_context, &pkt );
#else #else
ret = avcodec_encode_audio2( audio_output_context, &pkt, NULL, &got_packet ); ret = avcodec_encode_audio2( audio_output_context, &pkt, NULL, &got_packet );
@ -341,6 +379,18 @@ bool VideoStore::setup_resampler() {
#ifdef HAVE_LIBAVRESAMPLE #ifdef HAVE_LIBAVRESAMPLE
static char error_buffer[256]; static char error_buffer[256];
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
// Newer ffmpeg wants to keep everything separate... so have to lookup our own decoder, can't reuse the one from the camera.
AVCodec *audio_input_codec = avcodec_find_decoder(audio_input_stream->codecpar->codec_id);
#else
AVCodec *audio_input_codec = avcodec_find_decoder(audio_input_context->codec_id);
#endif
ret = avcodec_open2( audio_input_context, audio_input_codec, NULL );
if ( ret < 0 ) {
Error("Can't open input codec!");
return false;
}
audio_output_codec = avcodec_find_encoder(AV_CODEC_ID_AAC); audio_output_codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
if ( ! audio_output_codec ) { if ( ! audio_output_codec ) {
Error("Could not find codec for AAC"); Error("Could not find codec for AAC");
@ -348,8 +398,8 @@ bool VideoStore::setup_resampler() {
} }
Debug(2, "Have audio output codec"); Debug(2, "Have audio output codec");
audio_output_stream = avformat_new_stream( oc, audio_output_codec ); //audio_output_context = audio_output_stream->codec;
audio_output_context = audio_output_stream->codec; audio_output_context = avcodec_alloc_context3( audio_output_codec );
if ( ! audio_output_context ) { if ( ! audio_output_context ) {
Error( "could not allocate codec context for AAC\n"); Error( "could not allocate codec context for AAC\n");
@ -359,18 +409,15 @@ bool VideoStore::setup_resampler() {
Debug(2, "Have audio_output_context"); Debug(2, "Have audio_output_context");
AVDictionary *opts = NULL;
av_dict_set(&opts, "strict", "experimental", 0);
/* put sample parameters */ /* put sample parameters */
audio_output_context->bit_rate = audio_input_context->bit_rate; audio_output_context->bit_rate = audio_input_context->bit_rate;
audio_output_context->sample_rate = audio_input_context->sample_rate; audio_output_context->sample_rate = audio_input_context->sample_rate;
audio_output_context->channels = audio_input_context->channels; audio_output_context->channels = audio_input_context->channels;
audio_output_context->channel_layout = audio_input_context->channel_layout; audio_output_context->channel_layout = audio_input_context->channel_layout;
audio_output_context->sample_fmt = audio_input_context->sample_fmt; audio_output_context->sample_fmt = audio_input_context->sample_fmt;
//audio_output_context->refcounted_frames = 1; audio_output_context->refcounted_frames = 1;
if (audio_output_codec->supported_samplerates) { if ( audio_output_codec->supported_samplerates ) {
int found = 0; int found = 0;
for ( unsigned int i = 0; audio_output_codec->supported_samplerates[i]; i++) { for ( unsigned int i = 0; audio_output_codec->supported_samplerates[i]; i++) {
if ( audio_output_context->sample_rate == audio_output_codec->supported_samplerates[i] ) { if ( audio_output_context->sample_rate == audio_output_codec->supported_samplerates[i] ) {
@ -387,36 +434,14 @@ bool VideoStore::setup_resampler() {
} }
/* check that the encoder supports s16 pcm input */ /* check that the encoder supports s16 pcm input */
if (!check_sample_fmt( audio_output_codec, audio_output_context->sample_fmt)) { if ( ! check_sample_fmt( audio_output_codec, audio_output_context->sample_fmt ) ) {
Debug( 3, "Encoder does not support sample format %s, setting to FLTP", Debug( 3, "Encoder does not support sample format %s, setting to FLTP",
av_get_sample_fmt_name( audio_output_context->sample_fmt)); av_get_sample_fmt_name( audio_output_context->sample_fmt));
audio_output_context->sample_fmt = AV_SAMPLE_FMT_FLTP; audio_output_context->sample_fmt = AV_SAMPLE_FMT_FLTP;
} }
//audio_output_stream->time_base = audio_input_stream->time_base;
audio_output_context->time_base = (AVRational){ 1, audio_output_context->sample_rate }; audio_output_context->time_base = (AVRational){ 1, audio_output_context->sample_rate };
Debug(3, "Audio Time bases input stream (%d/%d) input codec: (%d/%d) output_stream (%d/%d) output codec (%d/%d)",
audio_input_stream->time_base.num,
audio_input_stream->time_base.den,
audio_input_context->time_base.num,
audio_input_context->time_base.den,
audio_output_stream->time_base.num,
audio_output_stream->time_base.den,
audio_output_context->time_base.num,
audio_output_context->time_base.den
);
ret = avcodec_open2(audio_output_context, audio_output_codec, &opts );
av_dict_free(&opts);
if ( ret < 0 ) {
av_strerror(ret, error_buffer, sizeof(error_buffer));
Fatal( "could not open codec (%d) (%s)\n", ret, error_buffer );
audio_output_codec = NULL;
audio_output_context = NULL;
audio_output_stream = NULL;
return false;
}
Debug(1, "Audio output bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) layout(%d) frame_size(%d)", Debug(1, "Audio output bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) layout(%d) frame_size(%d)",
audio_output_context->bit_rate, audio_output_context->bit_rate,
@ -427,7 +452,28 @@ bool VideoStore::setup_resampler() {
audio_output_context->frame_size audio_output_context->frame_size
); );
output_frame_size = audio_output_context->frame_size; // Now copy them to the output stream
audio_output_stream = avformat_new_stream( oc, audio_output_codec );
ret = avcodec_parameters_from_context( audio_output_stream->codecpar, audio_output_context );
if ( ret < 0 ) {
Error( "Could not initialize stream parameteres");
return false;
}
AVDictionary *opts = NULL;
av_dict_set( &opts, "strict", "experimental", 0);
ret = avcodec_open2( audio_output_context, audio_output_codec, &opts );
av_dict_free(&opts);
if ( ret < 0 ) {
av_strerror(ret, error_buffer, sizeof(error_buffer));
Fatal( "could not open codec (%d) (%s)\n", ret, error_buffer );
audio_output_codec = NULL;
audio_output_context = NULL;
audio_output_stream = NULL;
return false;
}
/** Create a new frame to store the audio samples. */ /** Create a new frame to store the audio samples. */
if (!(input_frame = zm_av_frame_alloc())) { if (!(input_frame = zm_av_frame_alloc())) {
Error("Could not allocate input frame"); Error("Could not allocate input frame");
@ -562,9 +608,9 @@ int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) {
if ( ipkt->pts < video_last_pts ) { if ( ipkt->pts < video_last_pts ) {
Debug(1, "Resetting video_last_pts from (%d) to (%d)", video_last_pts, ipkt->pts ); Debug(1, "Resetting video_last_pts from (%d) to (%d)", video_last_pts, ipkt->pts );
// wrap around, need to figure out the distance FIXME having this wrong should cause a jump, but then play ok? // wrap around, need to figure out the distance FIXME having this wrong should cause a jump, but then play ok?
opkt.pts = previous_pts + av_rescale_q( ipkt->pts, video_input_stream->time_base, video_output_stream->time_base); opkt.pts = video_previous_pts + av_rescale_q( ipkt->pts, video_input_stream->time_base, video_output_stream->time_base);
} else { } else {
opkt.pts = previous_pts + av_rescale_q( ipkt->pts - video_last_pts, video_input_stream->time_base, video_output_stream->time_base); opkt.pts = video_previous_pts + av_rescale_q( ipkt->pts - video_last_pts, video_input_stream->time_base, video_output_stream->time_base);
} }
} }
Debug(3, "opkt.pts = %d from ipkt->pts(%d) - last_pts(%d)", opkt.pts, ipkt->pts, video_last_pts ); Debug(3, "opkt.pts = %d from ipkt->pts(%d) - last_pts(%d)", opkt.pts, ipkt->pts, video_last_pts );
@ -588,24 +634,20 @@ int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) {
// why are we using cur_dts instead of packet.dts? I think cur_dts is in AV_TIME_BASE_Q, but ipkt.dts is in video_input_stream->time_base // why are we using cur_dts instead of packet.dts? I think cur_dts is in AV_TIME_BASE_Q, but ipkt.dts is in video_input_stream->time_base
if ( video_input_stream->cur_dts < video_last_dts ) { if ( video_input_stream->cur_dts < video_last_dts ) {
Debug(1, "Resetting video_last_dts from (%d) to (%d) p.dts was (%d)", video_last_dts, video_input_stream->cur_dts, ipkt->dts ); Debug(1, "Resetting video_last_dts from (%d) to (%d) p.dts was (%d)", video_last_dts, video_input_stream->cur_dts, ipkt->dts );
opkt.dts = previous_dts + av_rescale_q(video_input_stream->cur_dts, AV_TIME_BASE_Q, video_output_stream->time_base); opkt.dts = video_previous_dts + av_rescale_q(video_input_stream->cur_dts, AV_TIME_BASE_Q, video_output_stream->time_base);
} else { } else {
opkt.dts = previous_dts + av_rescale_q(video_input_stream->cur_dts - video_last_dts, AV_TIME_BASE_Q, video_output_stream->time_base); opkt.dts = video_previous_dts + av_rescale_q(video_input_stream->cur_dts - video_last_dts, AV_TIME_BASE_Q, video_output_stream->time_base);
} }
Debug(3, "opkt.dts = %d from video_input_stream->cur_dts(%d) - previus_dts(%d)", Debug(3, "opkt.dts = %d from video_input_stream->cur_dts(%d) - previus_dts(%d)", opkt.dts, video_input_stream->cur_dts, video_last_dts );
opkt.dts, video_input_stream->cur_dts, video_last_dts
);
video_last_dts = video_input_stream->cur_dts; video_last_dts = video_input_stream->cur_dts;
} else { } else {
if ( ipkt->dts < video_last_dts ) { if ( ipkt->dts < video_last_dts ) {
Debug(1, "Resetting video_last_dts from (%d) to (%d)", video_last_dts, ipkt->dts ); Debug(1, "Resetting video_last_dts from (%d) to (%d)", video_last_dts, ipkt->dts );
opkt.dts = previous_dts + av_rescale_q( ipkt->dts, video_input_stream->time_base, video_output_stream->time_base); opkt.dts = video_previous_dts + av_rescale_q( ipkt->dts, video_input_stream->time_base, video_output_stream->time_base);
} else { } else {
opkt.dts = previous_dts + av_rescale_q( ipkt->dts - video_last_dts, video_input_stream->time_base, video_output_stream->time_base); opkt.dts = video_previous_dts + av_rescale_q( ipkt->dts - video_last_dts, video_input_stream->time_base, video_output_stream->time_base);
} }
Debug(3, "opkt.dts = %d from ipkt.dts(%d) - previus_dts(%d)", Debug(3, "opkt.dts = %d from ipkt.dts(%d) - previus_dts(%d)", opkt.dts, ipkt->dts, video_last_dts );
opkt.dts, ipkt->dts, video_last_dts
);
video_last_dts = ipkt->dts; video_last_dts = ipkt->dts;
} }
} }
@ -642,15 +684,15 @@ Debug(1, "writing video packet pts(%d) dts(%d) duration(%d)", opkt.pts, opkt.dts
dumpPacket( ipkt); dumpPacket( ipkt);
dumpPacket(&opkt); dumpPacket(&opkt);
} else if ((previous_dts > 0) && (previous_dts > opkt.dts)) { } else if ((video_previous_dts > 0) && (video_previous_dts > opkt.dts)) {
Warning("%s:%d: DTS out of order: %lld \u226E %lld; discarding frame", __FILE__, __LINE__, previous_dts, opkt.dts); Warning("%s:%d: DTS out of order: %lld \u226E %lld; discarding frame", __FILE__, __LINE__, video_previous_dts, opkt.dts);
previous_dts = opkt.dts; video_previous_dts = opkt.dts;
dumpPacket(&opkt); dumpPacket(&opkt);
} else { } else {
previous_dts = opkt.dts; // Unsure if av_interleaved_write_frame() clobbers opkt.dts when out of order, so storing in advance video_previous_dts = opkt.dts; // Unsure if av_interleaved_write_frame() clobbers opkt.dts when out of order, so storing in advance
previous_pts = opkt.pts; video_previous_pts = opkt.pts;
ret = av_interleaved_write_frame(oc, &opkt); ret = av_interleaved_write_frame(oc, &opkt);
if(ret<0){ if(ret<0){
// There's nothing we can really do if the frame is rejected, just drop it and get on with the next // There's nothing we can really do if the frame is rejected, just drop it and get on with the next
@ -663,21 +705,20 @@ Debug(1, "writing video packet pts(%d) dts(%d) duration(%d)", opkt.pts, opkt.dts
return 0; return 0;
} } // end int VideoStore::writeVideoFramePacket( AVPacket *ipkt )
int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) {
Debug(4, "writeAudioFrame"); Debug(4, "writeAudioFrame");
if(!audio_output_stream) { if ( ! audio_output_stream ) {
Debug(1, "Called writeAudioFramePacket when no audio_output_stream"); Debug(1, "Called writeAudioFramePacket when no audio_output_stream");
return 0;//FIXME -ve return codes do not free packet in ffmpeg_camera at the moment return 0;//FIXME -ve return codes do not free packet in ffmpeg_camera at the moment
} }
if ( audio_output_codec ) { if ( audio_output_codec ) {
#ifdef HAVE_LIBAVRESAMPLE #ifdef HAVE_LIBAVRESAMPLE
#if 0 #if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
ret = avcodec_send_packet( audio_input_context, ipkt ); ret = avcodec_send_packet( audio_input_context, ipkt );
if ( ret < 0 ) { if ( ret < 0 ) {
Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str()); Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str());
@ -696,26 +737,7 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) {
input_frame->channel_layout, input_frame->channel_layout,
audio_output_context->refcounted_frames audio_output_context->refcounted_frames
); );
ret = avcodec_send_frame( audio_output_context, input_frame );
if ( ret < 0 ) {
av_frame_unref( input_frame );
Error("avcodec_send_frame fail(%d), %s codec is open(%d) is_encoder(%d)", ret, av_make_error_string(ret).c_str(),
avcodec_is_open( audio_output_context ),
av_codec_is_encoder( audio_output_context->codec)
);
return 0;
}
ret = avcodec_receive_packet( audio_output_context, &opkt );
if ( ret < 0 ) {
av_frame_unref( input_frame );
Error("avcodec_receive_packet fail %s", av_make_error_string(ret).c_str());
return 0;
}
av_frame_unref( input_frame );
#else #else
/** /**
* Decode the audio frame stored in the packet. * Decode the audio frame stored in the packet.
* The input audio stream decoder is used to do this. * The input audio stream decoder is used to do this.
@ -728,15 +750,13 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) {
av_make_error_string(ret).c_str()); av_make_error_string(ret).c_str());
dumpPacket( ipkt ); dumpPacket( ipkt );
av_frame_free( &input_frame ); av_frame_free( &input_frame );
zm_av_packet_unref( &opkt );
return 0; return 0;
} }
if ( ! data_present ) { if ( ! data_present ) {
Debug(2, "Not ready to transcode a frame yet."); Debug(2, "Not ready to transcode a frame yet.");
zm_av_packet_unref(&opkt);
return 0; return 0;
} }
#endif
int frame_size = input_frame->nb_samples; int frame_size = input_frame->nb_samples;
Debug(4, "Frame size: %d", frame_size ); Debug(4, "Frame size: %d", frame_size );
@ -778,11 +798,22 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) {
* Encode the audio frame and store it in the temporary packet. * Encode the audio frame and store it in the temporary packet.
* The output audio stream encoder is used to do this. * The output audio stream encoder is used to do this.
*/ */
#if LIBAVCODEC_VERSION_CHECK(58, 0, 0, 0, 0) #if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
if (( ret = avcodec_send_frame( audio_output_context, output_frame ) ) < 0 ) {
Error( "Could not send frame (error '%s')",
av_make_error_string(ret).c_str());
zm_av_packet_unref(&opkt);
return 0;
}
if (( ret = avcodec_receive_packet( audio_output_context, &opkt )) < 0 ) { if (( ret = avcodec_receive_packet( audio_output_context, &opkt )) < 0 ) {
Error( "Could not recieve packet (error '%s')",
av_make_error_string(ret).c_str());
zm_av_packet_unref(&opkt);
return 0;
}
#else #else
if (( ret = avcodec_encode_audio2( audio_output_context, &opkt, output_frame, &data_present )) < 0) { if (( ret = avcodec_encode_audio2( audio_output_context, &opkt, output_frame, &data_present )) < 0) {
#endif
Error( "Could not encode frame (error '%s')", Error( "Could not encode frame (error '%s')",
av_make_error_string(ret).c_str()); av_make_error_string(ret).c_str());
zm_av_packet_unref(&opkt); zm_av_packet_unref(&opkt);
@ -793,8 +824,8 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) {
zm_av_packet_unref(&opkt); zm_av_packet_unref(&opkt);
return 0; return 0;
} }
#endif #endif
#endif #endif
} else { } else {
av_init_packet(&opkt); av_init_packet(&opkt);
@ -807,14 +838,17 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) {
//Scale the PTS of the outgoing packet to be the correct time base //Scale the PTS of the outgoing packet to be the correct time base
if ( ipkt->pts != AV_NOPTS_VALUE ) { if ( ipkt->pts != AV_NOPTS_VALUE ) {
if ( !audio_last_pts ) { if ( ! audio_last_pts ) {
opkt.pts = 0; opkt.pts = 0;
Debug(1, "No audio_last_pts");
} else { } else {
if ( audio_last_pts > ipkt->pts ) { if ( audio_last_pts > ipkt->pts ) {
Debug(1, "Resetting audeo_start_pts from (%d) to (%d)", audio_last_pts, ipkt->pts ); Debug(1, "Resetting audeo_start_pts from (%d) to (%d)", audio_last_pts, ipkt->pts );
opkt.pts = audio_previous_pts + av_rescale_q(ipkt->pts, audio_input_stream->time_base, audio_output_stream->time_base);
} else {
opkt.pts = audio_previous_pts + av_rescale_q(ipkt->pts - audio_last_pts, audio_input_stream->time_base, audio_output_stream->time_base);
} }
opkt.pts = previous_pts + av_rescale_q(ipkt->pts - audio_last_pts, audio_input_stream->time_base, audio_output_stream->time_base); Debug(2, "audio opkt.pts = %d from ipkt->pts(%d) - last_pts(%d)", opkt.pts, ipkt->pts, audio_last_pts );
Debug(2, "opkt.pts = %d from ipkt->pts(%d) - last_pts(%d)", opkt.pts, ipkt->pts, audio_last_pts );
} }
audio_last_pts = ipkt->pts; audio_last_pts = ipkt->pts;
} else { } else {
@ -825,28 +859,30 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) {
//Scale the DTS of the outgoing packet to be the correct time base //Scale the DTS of the outgoing packet to be the correct time base
if ( ! audio_last_dts ) { if ( ! audio_last_dts ) {
opkt.dts = 0; opkt.dts = 0;
} else { } else {
if( ipkt->dts == AV_NOPTS_VALUE ) { if( ipkt->dts == AV_NOPTS_VALUE ) {
// So if the input has no dts assigned... still need an output dts... so we use cur_dts? // So if the input has no dts assigned... still need an output dts... so we use cur_dts?
if ( audio_last_dts > audio_input_stream->cur_dts ) { if ( audio_last_dts > audio_input_stream->cur_dts ) {
Debug(1, "Resetting audio_last_pts from (%d) to cur_dts (%d)", audio_last_dts, audio_input_stream->cur_dts ); Debug(1, "Resetting audio_last_dts from (%d) to cur_dts (%d)", audio_last_dts, audio_input_stream->cur_dts );
opkt.dts = previous_dts + av_rescale_q( audio_input_stream->cur_dts, AV_TIME_BASE_Q, audio_output_stream->time_base); opkt.dts = audio_previous_dts + av_rescale_q( audio_input_stream->cur_dts, AV_TIME_BASE_Q, audio_output_stream->time_base);
} else { } else {
opkt.dts = previous_dts + av_rescale_q( audio_input_stream->cur_dts - audio_last_dts, AV_TIME_BASE_Q, audio_output_stream->time_base); opkt.dts = audio_previous_dts + av_rescale_q( audio_input_stream->cur_dts - audio_last_dts, AV_TIME_BASE_Q, audio_output_stream->time_base);
} }
audio_last_dts = audio_input_stream->cur_dts; audio_last_dts = audio_input_stream->cur_dts;
Debug(2, "opkt.dts = %d from video_input_stream->cur_dts(%d) - last_dts(%d)", opkt.dts, audio_input_stream->cur_dts, audio_last_dts ); Debug(2, "opkt.dts = %d from video_input_stream->cur_dts(%d) - last_dts(%d)", opkt.dts, audio_input_stream->cur_dts, audio_last_dts );
} else { } else {
if ( audio_last_dts > ipkt->dts ) { if ( audio_last_dts > ipkt->dts ) {
Debug(1, "Resetting audio_last_dts from (%d) to (%d)", audio_last_dts, ipkt->dts ); Debug(1, "Resetting audio_last_dts from (%d) to (%d)", audio_last_dts, ipkt->dts );
opkt.dts = previous_dts + av_rescale_q(ipkt->dts, audio_input_stream->time_base, audio_output_stream->time_base); opkt.dts = audio_previous_dts + av_rescale_q(ipkt->dts, audio_input_stream->time_base, audio_output_stream->time_base);
} else { } else {
opkt.dts = previous_dts + av_rescale_q(ipkt->dts - audio_last_dts, audio_input_stream->time_base, audio_output_stream->time_base); opkt.dts = audio_previous_dts + av_rescale_q(ipkt->dts - audio_last_dts, audio_input_stream->time_base, audio_output_stream->time_base);
} }
Debug(2, "opkt.dts = %d from ipkt->dts(%d) - last_dts(%d)", opkt.dts, ipkt->dts, audio_last_dts ); Debug(2, "opkt.dts = %d from ipkt->dts(%d) - last_dts(%d)", opkt.dts, ipkt->dts, audio_last_dts );
} }
} }
audio_last_dts = ipkt->dts;
if ( opkt.dts > opkt.pts ) { if ( opkt.dts > opkt.pts ) {
Debug(1,"opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen before presentation.", opkt.dts, opkt.pts ); Debug(1,"opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen before presentation.", opkt.dts, opkt.pts );
opkt.dts = opkt.pts; opkt.dts = opkt.pts;
@ -854,15 +890,17 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) {
// I wonder if we could just use duration instead of all the hoop jumping above? // I wonder if we could just use duration instead of all the hoop jumping above?
opkt.duration = av_rescale_q(ipkt->duration, audio_input_stream->time_base, audio_output_stream->time_base); opkt.duration = av_rescale_q(ipkt->duration, audio_input_stream->time_base, audio_output_stream->time_base);
Debug( 2, "opkt.pts (%d), opkt.dts(%d) opkt.duration = (%d)", opkt.pts, opkt.dts, opkt.duration );
// pkt.pos: byte position in stream, -1 if unknown // pkt.pos: byte position in stream, -1 if unknown
opkt.pos = -1; opkt.pos = -1;
opkt.flags = ipkt->flags;
opkt.stream_index = ipkt->stream_index; opkt.stream_index = ipkt->stream_index;
Debug(2, "Stream index is %d", opkt.stream_index ); Debug(2, "Stream index is %d", opkt.stream_index );
AVPacket safepkt; AVPacket safepkt;
memcpy(&safepkt, &opkt, sizeof(AVPacket)); memcpy(&safepkt, &opkt, sizeof(AVPacket));
audio_previous_dts = opkt.dts; // Unsure if av_interleaved_write_frame() clobbers opkt.dts when out of order, so storing in advance
audio_previous_pts = opkt.pts;
ret = av_interleaved_write_frame(oc, &opkt); ret = av_interleaved_write_frame(oc, &opkt);
if(ret!=0){ if(ret!=0){
Error("Error writing audio frame packet: %s\n", av_make_error_string(ret).c_str()); Error("Error writing audio frame packet: %s\n", av_make_error_string(ret).c_str());

View File

@ -61,8 +61,10 @@ AVAudioResampleContext* resample_context;
int64_t audio_last_dts; int64_t audio_last_dts;
// These are for output, should start at zero. We assume they do not wrap because we just aren't going to save files that big. // These are for output, should start at zero. We assume they do not wrap because we just aren't going to save files that big.
int64_t previous_pts; int64_t video_previous_pts;
int64_t previous_dts; int64_t video_previous_dts;
int64_t audio_previous_pts;
int64_t audio_previous_dts;
int64_t filter_in_rescale_delta_last; int64_t filter_in_rescale_delta_last;

File diff suppressed because it is too large Load Diff

View File

@ -39,6 +39,23 @@ checksanity () {
} }
# Check key variables before calling packpack
checkvars () {
if [ -z ${VERSION} ]; then
echo
echo "FATAL: VERSION variable was null. Cannot continue."
echo
exit 98
fi
if [ -z ${RELEASE} ]; then
echo
echo "FATAL: RELEASE variable was null. Cannot Continue"
echo
exit 98
fi
}
# Steps common to all builds # Steps common to all builds
commonprep () { commonprep () {
mkdir -p build mkdir -p build
@ -46,7 +63,7 @@ commonprep () {
echo "Checking packpack github repo for changes..." echo "Checking packpack github repo for changes..."
git -C packpack pull origin master git -C packpack pull origin master
else else
echo "Cloning pakcpack github repo..." echo "Cloning packpack github repo..."
git clone https://github.com/packpack/packpack.git packpack git clone https://github.com/packpack/packpack.git packpack
fi fi
@ -116,7 +133,7 @@ installtrusty () {
# This sets the naming convention for the deb packages # This sets the naming convention for the deb packages
setdebpkgver () { setdebpkgver () {
# Set VERSION to x.xx.x+x e.g. 1.30.2+15 # Set VERSION to x.xx.x+x e.g. 1.30.2+15
# the last x is number of commits since release # the last x is number of commits since release
# Creates zoneminder packages in the format: zoneminder-{version}-{release} # Creates zoneminder packages in the format: zoneminder-{version}-{release}
@ -125,6 +142,8 @@ setdebpkgver () {
export VERSION="$zmver+$commitnum" export VERSION="$zmver+$commitnum"
export RELEASE="${DIST}" export RELEASE="${DIST}"
checkvars
echo echo
echo "Packpack VERSION has been set to: ${VERSION}" echo "Packpack VERSION has been set to: ${VERSION}"
echo "Packpack RELEASE has been set to: ${RELEASE}" echo "Packpack RELEASE has been set to: ${RELEASE}"
@ -132,6 +151,16 @@ setdebpkgver () {
} }
# This adds an entry to the debian changelog
setdebchangelog () {
DATE=`date -R`
cat <<EOF > debian/changelog
zoneminder ($VERSION-${DIST}-1) unstable; urgency=low
*
-- Isaac Connor <iconnor@connortechnology.com> $DATE
EOF
}
################ ################
# MAIN PROGRAM # # MAIN PROGRAM #
################ ################
@ -154,6 +183,8 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then
export VERSION=$(git describe --long --always | sed -n 's/^\([0-9\.]*\)-\([0-9]*\)-\([a-z0-9]*\)/\1/p') export VERSION=$(git describe --long --always | sed -n 's/^\([0-9\.]*\)-\([0-9]*\)-\([a-z0-9]*\)/\1/p')
export RELEASE=$(git describe --long --always | sed -n 's/^\([0-9\.]*\)-\([0-9]*\)-\([a-z0-9]*\)/\2/p') export RELEASE=$(git describe --long --always | sed -n 's/^\([0-9\.]*\)-\([0-9]*\)-\([a-z0-9]*\)/\2/p')
checkvars
echo echo
echo "Packpack VERSION has been set to: ${VERSION}" echo "Packpack VERSION has been set to: ${VERSION}"
echo "Packpack RELEASE has been set to: ${RELEASE}" echo "Packpack RELEASE has been set to: ${RELEASE}"
@ -199,7 +230,9 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then
else else
ln -sfT distros/ubuntu1604 debian ln -sfT distros/ubuntu1604 debian
fi fi
setdebchangelog
echo "Starting packpack..." echo "Starting packpack..."
packpack/packpack packpack/packpack
@ -218,6 +251,8 @@ elif [ "${OS}" == "ubuntu" ] && [ "${DIST}" == "trusty" ] && [ "${ARCH}" == "x86
ln -sfT distros/ubuntu1204 debian ln -sfT distros/ubuntu1204 debian
setdebchangelog
echo "Starting packpack..." echo "Starting packpack..."
packpack/packpack packpack/packpack

View File

@ -100,12 +100,12 @@ App::uses('CakeLog', 'Log');
CakeLog::config('debug', array( CakeLog::config('debug', array(
'engine' => 'File', 'engine' => 'File',
'types' => array('notice', 'info', 'debug'), 'types' => array('notice', 'info', 'debug'),
'file' => 'cake_debug', 'file' => '@ZM_LOGDIR@/cake_debug',
)); ));
CakeLog::config('error', array( CakeLog::config('error', array(
'engine' => 'File', 'engine' => 'File',
'types' => array('warning', 'error', 'critical', 'alert', 'emergency'), 'types' => array('warning', 'error', 'critical', 'alert', 'emergency'),
'file' => 'cake_error', 'file' => '@ZM_LOGDIR@/cake_error',
)); ));
CakeLog::config('custom_path', array( CakeLog::config('custom_path', array(
'engine' => 'File', 'engine' => 'File',

View File

@ -29,12 +29,15 @@ class Event {
Error('No row for Event ' . $IdOrRow ); Error('No row for Event ' . $IdOrRow );
} }
} // end function __construct } // end function __construct
public function Storage() { public function Storage() {
return new Storage( isset($this->{'StorageId'}) ? $this->{'StorageId'} : NULL ); return new Storage( isset($this->{'StorageId'}) ? $this->{'StorageId'} : NULL );
} }
public function Monitor() { public function Monitor() {
return new Monitor( isset($this->{'MonitorId'}) ? $this->{'MonitorId'} : NULL ); return new Monitor( isset($this->{'MonitorId'}) ? $this->{'MonitorId'} : NULL );
} }
public function __call( $fn, array $args){ public function __call( $fn, array $args){
if ( array_key_exists( $fn, $this ) ) { if ( array_key_exists( $fn, $this ) ) {
return $this->{$fn}; return $this->{$fn};
@ -54,6 +57,7 @@ class Event {
$Storage = $this->Storage(); $Storage = $this->Storage();
return $Storage->Path().'/'.$this->Relative_Path(); return $Storage->Path().'/'.$this->Relative_Path();
} }
public function Relative_Path() { public function Relative_Path() {
$event_path = ''; $event_path = '';
@ -197,20 +201,26 @@ class Event {
return( $thumbData ); return( $thumbData );
} // end function createListThumbnail } // end function createListThumbnail
// frame is an array representing the db row for a frame.
function getImageSrc( $frame, $scale=SCALE_BASE, $captureOnly=false, $overwrite=false ) { function getImageSrc( $frame, $scale=SCALE_BASE, $captureOnly=false, $overwrite=false ) {
$Storage = new Storage( isset($this->{'StorageId'}) ? $this->{'StorageId'} : NULL ); $Storage = new Storage( isset($this->{'StorageId'}) ? $this->{'StorageId'} : NULL );
$Event = $this; $Event = $this;
$eventPath = $Event->Path(); $eventPath = $Event->Path();
if ( !is_array($frame) ) if ( $frame and ! is_array($frame) ) {
# Must be an Id
Debug("Assuming that $frame is an Id");
$frame = array( 'FrameId'=>$frame, 'Type'=>'' ); $frame = array( 'FrameId'=>$frame, 'Type'=>'' );
}
if ( file_exists( $eventPath.'/snapshot.jpg' ) ) { if ( ( ! $frame ) and file_exists( $eventPath.'/snapshot.jpg' ) ) {
$captImage = "snapshot.jpg"; # No frame specified, so look for a snapshot to use
$captImage = 'snapshot.jpg';
Debug("Frame not specified, using snapshot");
} else { } else {
$captImage = sprintf( '%0'.ZM_EVENT_IMAGE_DIGITS.'d-capture.jpg', $frame['FrameId'] ); $captImage = sprintf( '%0'.ZM_EVENT_IMAGE_DIGITS.'d-capture.jpg', $frame['FrameId'] );
if ( ! file_exists( $eventPath.'/'.$captImage ) ) { if ( ! file_exists( $eventPath.'/'.$captImage ) ) {
# Generate the frame JPG # Generate the frame JPG
if ( $Event->DefaultVideo() ) { if ( $Event->DefaultVideo() ) {
$videoPath = $eventPath.'/'.$Event->DefaultVideo(); $videoPath = $eventPath.'/'.$Event->DefaultVideo();
@ -275,8 +285,7 @@ class Event {
} }
$thumbFile = $thumbPath; $thumbFile = $thumbPath;
if ( $overwrite || !file_exists( $thumbFile ) || !filesize( $thumbFile ) ) if ( $overwrite || ! file_exists( $thumbFile ) || ! filesize( $thumbFile ) ) {
{
// Get new dimensions // Get new dimensions
list( $imageWidth, $imageHeight ) = getimagesize( $imagePath ); list( $imageWidth, $imageHeight ) = getimagesize( $imagePath );
$thumbWidth = $imageWidth * $fraction; $thumbWidth = $imageWidth * $fraction;
@ -290,7 +299,7 @@ class Event {
if ( !imagejpeg( $thumbImage, $thumbPath ) ) if ( !imagejpeg( $thumbImage, $thumbPath ) )
Error( "Can't create thumbnail '$thumbPath'" ); Error( "Can't create thumbnail '$thumbPath'" );
} }
} } # Create thumbnails
$imageData = array( $imageData = array(
'eventPath' => $eventPath, 'eventPath' => $eventPath,
@ -298,7 +307,7 @@ class Event {
'thumbPath' => $thumbPath, 'thumbPath' => $thumbPath,
'imageFile' => $imagePath, 'imageFile' => $imagePath,
'thumbFile' => $thumbFile, 'thumbFile' => $thumbFile,
'imageClass' => $alarmFrame?"alarm":"normal", 'imageClass' => $alarmFrame?'alarm':'normal',
'isAnalImage' => $isAnalImage, 'isAnalImage' => $isAnalImage,
'hasAnalImage' => $hasAnalImage, 'hasAnalImage' => $hasAnalImage,
); );

View File

@ -27,9 +27,11 @@ class Frame {
Error("No row for Frame " . $IdOrRow ); Error("No row for Frame " . $IdOrRow );
} }
} // end function __construct } // end function __construct
public function Storage() { public function Storage() {
return $this->Event()->Storage(); return $this->Event()->Storage();
} }
public function Event() { public function Event() {
return new Event( $this->{'EventId'} ); return new Event( $this->{'EventId'} );
} }
@ -70,7 +72,9 @@ class Frame {
} }
public function getImageSrc( $show='capture' ) { public function getImageSrc( $show='capture' ) {
return $_SERVER['PHP_SELF'].'?view=image&fid='.$this->{'Id'}.'&show='.$show.'&filename='.$this->Event()->MonitorId().'_'.$this->{'EventId'}.'_'.$this->{'FrameId'}.'.jpg';
return $_SERVER['PHP_SELF'].'?view=image&fid='.$this->{'FrameId'}.'&eid='.$this->{'EventId'}.'&show='.$show;
#return $_SERVER['PHP_SELF'].'?view=image&fid='.$this->{'Id'}.'&show='.$show.'&filename='.$this->Event()->MonitorId().'_'.$this->{'EventId'}.'_'.$this->{'FrameId'}.'.jpg';
} // end function getImageSrc } // end function getImageSrc
public static function find( $parameters = array(), $limit = NULL ) { public static function find( $parameters = array(), $limit = NULL ) {

View File

@ -1149,17 +1149,17 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&amp;' ) {
if ( isset($filter['terms']) && count($filter['terms']) ) { if ( isset($filter['terms']) && count($filter['terms']) ) {
for ( $i = 0; $i < count($filter['terms']); $i++ ) { for ( $i = 0; $i < count($filter['terms']); $i++ ) {
if ( isset($filter['terms'][$i]['cnj']) ) { if ( isset($filter['terms'][$i]['cnj']) ) {
$filter['query'] .= $querySep."filter[terms][$i][cnj]=".urlencode($filter['terms'][$i]['cnj']); $filter['query'] .= $querySep.urlencode("filter[terms][$i][cnj]").'='.urlencode($filter['terms'][$i]['cnj']);
$filter['sql'] .= " ".$filter['terms'][$i]['cnj']." "; $filter['sql'] .= ' '.$filter['terms'][$i]['cnj'].' ';
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][cnj]\" value=\"".htmlspecialchars($filter['terms'][$i]['cnj'])."\"/>\n"; $filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][cnj]\" value=\"".htmlspecialchars($filter['terms'][$i]['cnj'])."\"/>\n";
} }
if ( isset($filter['terms'][$i]['obr']) ) { if ( isset($filter['terms'][$i]['obr']) ) {
$filter['query'] .= $querySep."filter[terms][$i][obr]=".urlencode($filter['terms'][$i]['obr']); $filter['query'] .= $querySep.urlencode("filter[terms][$i][obr]").'='.urlencode($filter['terms'][$i]['obr']);
$filter['sql'] .= " ".str_repeat( "(", $filter['terms'][$i]['obr'] )." "; $filter['sql'] .= ' '.str_repeat( '(', $filter['terms'][$i]['obr'] ).' ';
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][obr]\" value=\"".htmlspecialchars($filter['terms'][$i]['obr'])."\"/>\n"; $filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][obr]\" value=\"".htmlspecialchars($filter['terms'][$i]['obr'])."\"/>\n";
} }
if ( isset($filter['terms'][$i]['attr']) ) { if ( isset($filter['terms'][$i]['attr']) ) {
$filter['query'] .= $querySep."filter[terms][$i][attr]=".urlencode($filter['terms'][$i]['attr']); $filter['query'] .= $querySep.urlencode("filter[terms][$i][attr]").'='.urlencode($filter['terms'][$i]['attr']);
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][attr]\" value=\"".htmlspecialchars($filter['terms'][$i]['attr'])."\"/>\n"; $filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][attr]\" value=\"".htmlspecialchars($filter['terms'][$i]['attr'])."\"/>\n";
switch ( $filter['terms'][$i]['attr'] ) { switch ( $filter['terms'][$i]['attr'] ) {
case 'MonitorName': case 'MonitorName':
@ -1267,7 +1267,7 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&amp;' ) {
case '>' : case '>' :
case '<' : case '<' :
case '<=' : case '<=' :
$filter['sql'] .= ' '.$filter['terms'][$i]['op']." $value"; $filter['sql'] .= ' '.$filter['terms'][$i]['op'].' '. $value;
break; break;
case '=~' : case '=~' :
$filter['sql'] .= ' regexp '.$value; $filter['sql'] .= ' regexp '.$value;
@ -1276,20 +1276,20 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&amp;' ) {
$filter['sql'] .= ' not regexp '.$value; $filter['sql'] .= ' not regexp '.$value;
break; break;
case '=[]' : case '=[]' :
$filter['sql'] .= ' in ('.join( ",", $valueList ).')'; $filter['sql'] .= ' in ('.join( ',', $valueList ).')';
break; break;
case '![]' : case '![]' :
$filter['sql'] .= ' not in ('.join( ',', $valueList ).')'; $filter['sql'] .= ' not in ('.join( ',', $valueList ).')';
break; break;
} }
$filter['query'] .= $querySep."filter[terms][$i][op]=".urlencode($filter['terms'][$i]['op']); $filter['query'] .= $querySep.urlencode("filter[terms][$i][op]").'='.urlencode($filter['terms'][$i]['op']);
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][op]\" value=\"".htmlspecialchars($filter['terms'][$i]['op'])."\"/>\n"; $filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][op]\" value=\"".htmlspecialchars($filter['terms'][$i]['op'])."\"/>\n";
$filter['query'] .= $querySep."filter[terms][$i][val]=".urlencode($filter['terms'][$i]['val']); $filter['query'] .= $querySep.urlencode("filter[terms][$i][val]").'='.urlencode($filter['terms'][$i]['val']);
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][val]\" value=\"".htmlspecialchars($filter['terms'][$i]['val'])."\"/>\n"; $filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][val]\" value=\"".htmlspecialchars($filter['terms'][$i]['val'])."\"/>\n";
} }
if ( isset($filter['terms'][$i]['cbr']) ) { if ( isset($filter['terms'][$i]['cbr']) ) {
$filter['query'] .= $querySep."filter[terms][$i][cbr]=".urlencode($filter['terms'][$i]['cbr']); $filter['query'] .= $querySep.urlencode("filter[terms][$i][cbr]").'='.urlencode($filter['terms'][$i]['cbr']);
$filter['sql'] .= ' '.str_repeat( ')', $filter['terms'][$i]['cbr'] ).' '; $filter['sql'] .= ' '.str_repeat( ')', $filter['terms'][$i]['cbr'] ).' ';
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][cbr]\" value=\"".htmlspecialchars($filter['terms'][$i]['cbr'])."\"/>\n"; $filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][cbr]\" value=\"".htmlspecialchars($filter['terms'][$i]['cbr'])."\"/>\n";
} }

View File

@ -23,29 +23,28 @@
$bad_views = array('monitor', 'log'); $bad_views = array('monitor', 'log');
function xhtmlHeaders( $file, $title ) { function xhtmlHeaders( $file, $title ) {
global $css; global $css;
global $skin; global $skin;
$skinCssFile = getSkinFile( 'css/'.$css.'/skin.css' ); $skinCssFile = getSkinFile( 'css/'.$css.'/skin.css' );
$skinCssPhpFile = getSkinFile( 'css/'.$css.'/skin.css.php' ); $skinCssPhpFile = getSkinFile( 'css/'.$css.'/skin.css.php' );
$skinJsFile = getSkinFile( 'js/skin.js' ); $skinJsFile = getSkinFile( 'js/skin.js' );
$skinJsPhpFile = getSkinFile( 'js/skin.js.php' ); $skinJsPhpFile = getSkinFile( 'js/skin.js.php' );
$cssJsFile = getSkinFile( 'js/'.$css.'.js' ); $cssJsFile = getSkinFile( 'js/'.$css.'.js' );
$basename = basename( $file, '.php' ); $basename = basename( $file, '.php' );
$viewCssFile = getSkinFile( '/css/'.$css.'/views/'.$basename.'.css' ); $viewCssFile = getSkinFile( '/css/'.$css.'/views/'.$basename.'.css' );
$viewCssPhpFile = getSkinFile( '/css/'.$css.'/views/'.$basename.'.css.php' ); $viewCssPhpFile = getSkinFile( '/css/'.$css.'/views/'.$basename.'.css.php' );
$viewJsFile = getSkinFile( 'views/js/'.$basename.'.js' ); $viewJsFile = getSkinFile( 'views/js/'.$basename.'.js' );
$viewJsPhpFile = getSkinFile( 'views/js/'.$basename.'.js.php' ); $viewJsPhpFile = getSkinFile( 'views/js/'.$basename.'.js.php' );
extract( $GLOBALS, EXTR_OVERWRITE ); extract( $GLOBALS, EXTR_OVERWRITE );
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<title><?php echo ZM_WEB_TITLE_PREFIX ?> - <?php echo validHtmlStr($title) ?></title> <title><?php echo ZM_WEB_TITLE_PREFIX ?> - <?php echo validHtmlStr($title) ?></title>
<link rel="icon" type="image/ico" href="graphics/favicon.ico"/> <link rel="icon" type="image/ico" href="graphics/favicon.ico"/>
<link rel="shortcut icon" href="graphics/favicon.ico"/> <link rel="shortcut icon" href="graphics/favicon.ico"/>
@ -54,17 +53,17 @@ function xhtmlHeaders( $file, $title ) {
<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 $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 $viewCssFile ?>" type="text/css" media="screen"/>
<?php <?php
} }
if ( $viewCssPhpFile ) { if ( $viewCssPhpFile ) {
?> ?>
<style type="text/css"> <style type="text/css">
/*<![CDATA[*/ /*<![CDATA[*/
<?php <?php
require_once( $viewCssPhpFile ); require_once( $viewCssPhpFile );
?> ?>
/*]]>*/ /*]]>*/
</style> </style>
@ -96,8 +95,9 @@ var $j = jQuery.noConflict();
<script src="skins/<?php echo $skin ?>/js/video.js"></script> <script src="skins/<?php echo $skin ?>/js/video.js"></script>
<script src="./js/videojs.zoomrotate.js"></script> <script src="./js/videojs.zoomrotate.js"></script>
<script src="skins/<?php echo $skin ?>/js/moment.min.js"></script> <script src="skins/<?php echo $skin ?>/js/moment.min.js"></script>
<?php } <?php
if ( $skinJsPhpFile ) { }
if ( $skinJsPhpFile ) {
?> ?>
<script type="text/javascript"> <script type="text/javascript">
//<![CDATA[ //<![CDATA[
@ -109,20 +109,20 @@ var $j = jQuery.noConflict();
//]]> //]]>
</script> </script>
<?php <?php
} }
if ( $viewJsPhpFile ) { if ( $viewJsPhpFile ) {
?> ?>
<script type="text/javascript"> <script type="text/javascript">
//<![CDATA[ //<![CDATA[
<!-- <!--
<?php <?php
require_once( $viewJsPhpFile ); require_once( $viewJsPhpFile );
?> ?>
//--> //-->
//]]> //]]>
</script> </script>
<?php <?php
} }
if ( $cssJsFile ) { if ( $cssJsFile ) {
?> ?>
<script type="text/javascript" src="<?php echo $cssJsFile ?>"></script> <script type="text/javascript" src="<?php echo $cssJsFile ?>"></script>
@ -130,11 +130,11 @@ var $j = jQuery.noConflict();
<script type="text/javascript" src="<?php echo $skinJsFile ?>"></script> <script type="text/javascript" src="<?php echo $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 $viewJsFile ?>"></script>
<?php <?php
} }
?> ?>
</head> </head>
<?php <?php

View File

@ -152,30 +152,6 @@ xhtmlHeaders( __FILE__, translate('Console') );
<?php } ?> <?php } ?>
</tr> </tr>
</thead> </thead>
<tfoot>
<tr>
<td class="colLeftButtons" colspan="<?php echo $left_columns ?>">
<input type="button" class="btn btn-primary" value="<?php echo translate('Refresh') ?>" onclick="location.reload(true);"/>
<input type="button" class="btn btn-primary" name="addBtn" value="<?php echo translate('AddNewMonitor') ?>" onclick="addMonitor( this )"/>
<!-- <?php echo makePopupButton( '?view=monitor', 'zmMonitor0', 'monitor', translate('AddNewMonitor'), (canEdit( 'Monitors' ) && !$user['MonitorIds']) ) ?> -->
<?php echo makePopupButton( '?view=filter&amp;filter[terms][0][attr]=DateTime&amp;filter[terms][0][op]=%3c&amp;filter[terms][0][val]=now', 'zmFilter', 'filter', translate('Filters'), canView( 'Events' ) ) ?>
<input class="btn btn-primary" type="button" name="editBtn" value="<?php echo translate('Edit') ?>" onclick="editMonitor( this )" disabled="disabled"/>
<input class="btn btn-danger" type="button" name="deleteBtn" value="<?php echo translate('Delete') ?>" onclick="deleteMonitor( this )" disabled="disabled"/>
</td>
<?php
for ( $i = 0; $i < count($eventCounts); $i++ ) {
parseFilter( $eventCounts[$i]['filter'] );
?>
<td class="colEvents"><?php echo makePopupLink( '?view='.$eventsView.'&amp;page=1'.$eventCounts[$i]['filter']['query'], $eventsWindow, $eventsView, $eventCounts[$i]['total'], canView( 'Events' ) ) ?></td>
<?php
}
?>
<td class="colZones"><?php echo $zoneCount ?></td>
<?php if ( canEdit('Monitors') ) { ?>
<td class="colMark"></td>
<?php } ?>
</tr>
</tfoot>
<tbody id="consoleTableBody"> <tbody id="consoleTableBody">
<?php <?php
for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
@ -195,7 +171,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
if ( $monitor['Function'] == 'None' ) if ( $monitor['Function'] == 'None' )
$fclass = 'errorText'; $fclass = 'errorText';
//elseif ( $monitor['Function'] == 'Monitor' ) //elseif ( $monitor['Function'] == 'Monitor' )
// $fclass = "warnText"; // $fclass = 'warnText';
else else
$fclass = 'infoText'; $fclass = 'infoText';
if ( !$monitor['Enabled'] ) if ( !$monitor['Enabled'] )
@ -251,6 +227,30 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
} # end for each monitor } # end for each monitor
?> ?>
</tbody> </tbody>
<tfoot>
<tr>
<td class="colLeftButtons" colspan="<?php echo $left_columns ?>">
<input type="button" class="btn btn-primary" value="<?php echo translate('Refresh') ?>" onclick="location.reload(true);"/>
<input type="button" class="btn btn-primary" name="addBtn" value="<?php echo translate('AddNewMonitor') ?>" onclick="addMonitor( this )"/>
<!-- <?php echo makePopupButton( '?view=monitor', 'zmMonitor0', 'monitor', translate('AddNewMonitor'), (canEdit( 'Monitors' ) && !$user['MonitorIds']) ) ?> -->
<?php echo makePopupButton( '?view=filter&amp;filter[terms][0][attr]=DateTime&amp;filter[terms][0][op]=%3c&amp;filter[terms][0][val]=now', 'zmFilter', 'filter', translate('Filters'), canView( 'Events' ) ) ?>
<input class="btn btn-primary" type="button" name="editBtn" value="<?php echo translate('Edit') ?>" onclick="editMonitor( this )" disabled="disabled"/>
<input class="btn btn-danger" type="button" name="deleteBtn" value="<?php echo translate('Delete') ?>" onclick="deleteMonitor( this )" disabled="disabled"/>
</td>
<?php
for ( $i = 0; $i < count($eventCounts); $i++ ) {
parseFilter( $eventCounts[$i]['filter'] );
?>
<td class="colEvents"><?php echo makePopupLink( '?view='.$eventsView.'&amp;page=1'.$eventCounts[$i]['filter']['query'], $eventsWindow, $eventsView, $eventCounts[$i]['total'], canView( 'Events' ) ) ?></td>
<?php
}
?>
<td class="colZones"><?php echo $zoneCount ?></td>
<?php if ( canEdit('Monitors') ) { ?>
<td class="colMark"></td>
<?php } ?>
</tr>
</tfoot>
</table> </table>
</div> </div>
</form> </form>

View File

@ -81,7 +81,7 @@ if ( !empty($page) ) {
} }
$eventsSql .= " limit $limitStart, $limitAmount"; $eventsSql .= " limit $limitStart, $limitAmount";
} elseif ( !empty( $limit ) ) { } elseif ( !empty( $limit ) ) {
$eventsSql .= " limit 0, ".$limit; $eventsSql .= ' limit 0, '.$limit;
} }
$maxWidth = 0; $maxWidth = 0;
@ -118,15 +118,15 @@ xhtmlHeaders(__FILE__, translate('Events') );
<div id="headerButtons"> <div id="headerButtons">
<?php <?php
if ( $pages > 1 ) { if ( $pages > 1 ) {
if ( !empty($page) ) { if ( !empty($page) ) {
?> ?>
<a href="?view=<?php echo $view ?>&amp;page=0<?php echo $filterQuery ?><?php echo $sortQuery ?>&amp;limit=<?php echo $limit ?>"><?php echo translate('ViewAll') ?></a> <a href="?view=<?php echo $view ?>&amp;page=0<?php echo $filterQuery ?><?php echo $sortQuery ?>&amp;limit=<?php echo $limit ?>"><?php echo translate('ViewAll') ?></a>
<?php <?php
} else { } else {
?> ?>
<a href="?view=<?php echo $view ?>&amp;page=1<?php echo $filterQuery ?><?php echo $sortQuery ?>&amp;limit=<?php echo $limit ?>"><?php echo translate('ViewPaged') ?></a> <a href="?view=<?php echo $view ?>&amp;page=1<?php echo $filterQuery ?><?php echo $sortQuery ?>&amp;limit=<?php echo $limit ?>"><?php echo translate('ViewPaged') ?></a>
<?php <?php
} }
} }
?> ?>
<a href="#" onclick="closeWindows();"><?php echo translate('Close') ?></a> <a href="#" onclick="closeWindows();"><?php echo translate('Close') ?></a>
@ -173,21 +173,22 @@ foreach ( $events as $event ) {
<th class="colTotScore"><a href="<?php echo sortHeader( 'TotScore' ) ?>"><?php echo translate('TotalBrScore') ?><?php echo sortTag( 'TotScore' ) ?></a></th> <th class="colTotScore"><a href="<?php echo sortHeader( 'TotScore' ) ?>"><?php echo translate('TotalBrScore') ?><?php echo sortTag( 'TotScore' ) ?></a></th>
<th class="colAvgScore"><a href="<?php echo sortHeader( 'AvgScore' ) ?>"><?php echo translate('AvgBrScore') ?><?php echo sortTag( 'AvgScore' ) ?></a></th> <th class="colAvgScore"><a href="<?php echo sortHeader( 'AvgScore' ) ?>"><?php echo translate('AvgBrScore') ?><?php echo sortTag( 'AvgScore' ) ?></a></th>
<th class="colMaxScore"><a href="<?php echo sortHeader( 'MaxScore' ) ?>"><?php echo translate('MaxBrScore') ?><?php echo sortTag( 'MaxScore' ) ?></a></th> <th class="colMaxScore"><a href="<?php echo sortHeader( 'MaxScore' ) ?>"><?php echo translate('MaxBrScore') ?><?php echo sortTag( 'MaxScore' ) ?></a></th>
<?php if ( ZM_WEB_EVENT_DISK_SPACE ) { ?> <?php
if ( ZM_WEB_EVENT_DISK_SPACE ) { ?>
<th class="colDiskSpace"><a href="<?php echo sortHeader( 'DiskSpace' ) ?>"><?php echo translate('DiskSpace') ?><?php echo sortTag( 'DiskSpace' ) ?></a></th> <th class="colDiskSpace"><a href="<?php echo sortHeader( 'DiskSpace' ) ?>"><?php echo translate('DiskSpace') ?><?php echo sortTag( 'DiskSpace' ) ?></a></th>
<?php <?php
} }
if ( ZM_WEB_LIST_THUMBS ) { if ( ZM_WEB_LIST_THUMBS ) {
?> ?>
<th class="colThumbnail"><?php echo translate('Thumbnail') ?></th> <th class="colThumbnail"><?php echo translate('Thumbnail') ?></th>
<?php <?php
} }
?> ?>
<th class="colMark"><input type="checkbox" name="toggleCheck" value="1" onclick="toggleCheckbox( this, 'markEids' );"<?php if ( !canEdit( 'Events' ) ) { ?> disabled="disabled"<?php } ?>/></th> <th class="colMark"><input type="checkbox" name="toggleCheck" value="1" onclick="toggleCheckbox( this, 'markEids' );"<?php if ( !canEdit( 'Events' ) ) { ?> disabled="disabled"<?php } ?>/></th>
</tr> </tr>
<?php <?php
} }
$scale = max( reScale( SCALE_BASE, $event->DefaultScale(), ZM_WEB_DEFAULT_SCALE ), SCALE_BASE ); $scale = max( reScale( SCALE_BASE, $event->DefaultScale(), ZM_WEB_DEFAULT_SCALE ), SCALE_BASE );
?> ?>
<tr> <tr>
<td class="colId"><?php echo makePopupLink( '?view=event&amp;eid='.$event->Id().$filterQuery.$sortQuery.'&amp;page=1', 'zmEvent', array( 'event', reScale( $event->Width(), $scale ), reScale( $event->Height(), $scale ) ), $event->Id().($event->Archived()?'*':'') ) ?></td> <td class="colId"><?php echo makePopupLink( '?view=event&amp;eid='.$event->Id().$filterQuery.$sortQuery.'&amp;page=1', 'zmEvent', array( 'event', reScale( $event->Width(), $scale ), reScale( $event->Height(), $scale ) ), $event->Id().($event->Archived()?'*':'') ) ?></td>
@ -201,35 +202,37 @@ foreach ( $events as $event ) {
<td class="colTotScore"><?php echo $event->TotScore() ?></td> <td class="colTotScore"><?php echo $event->TotScore() ?></td>
<td class="colAvgScore"><?php echo $event->AvgScore() ?></td> <td class="colAvgScore"><?php echo $event->AvgScore() ?></td>
<td class="colMaxScore"><?php echo makePopupLink( '?view=frame&amp;eid='.$event->Id().'&amp;fid=0', 'zmImage', array( 'image', reScale( $event->Width(), $scale ), reScale( $event->Height(), $scale ) ), $event->MaxScore() ) ?></td> <td class="colMaxScore"><?php echo makePopupLink( '?view=frame&amp;eid='.$event->Id().'&amp;fid=0', 'zmImage', array( 'image', reScale( $event->Width(), $scale ), reScale( $event->Height(), $scale ) ), $event->MaxScore() ) ?></td>
<?php if ( ZM_WEB_EVENT_DISK_SPACE ) { ?> <?php
if ( ZM_WEB_EVENT_DISK_SPACE ) {
?>
<td class="colDiskSpace"><?php echo human_filesize( $event->DiskSpace() ) ?></td> <td class="colDiskSpace"><?php echo human_filesize( $event->DiskSpace() ) ?></td>
<?php <?php
} }
if ( ZM_WEB_LIST_THUMBS ) { if ( ZM_WEB_LIST_THUMBS ) {
if ( $thumbData = $event->createListThumbnail() ) { if ( $thumbData = $event->createListThumbnail() ) {
?> ?>
<td class="colThumbnail"> <td class="colThumbnail">
<?php <?php
$imgSrc = '?view=image&amp;eid='.$event->Id().'&amp;fid='.$thumbData['FrameId'].'&amp;width='.$thumbData['Width'].'&amp;height='.$thumbData['Height'];
$imgSrc = '?view=image&amp;eid='.$event->Id().'&amp;fid='.$thumbData['FrameId'].'&amp;width='.$thumbData['Width'].'&amp;height='.$thumbData['Height']; $streamSrc = getStreamSrc( array( "source=event", "mode=jpeg", "event=".$event->Id(), "scale=".$scale, "maxfps=".ZM_WEB_VIDEO_MAXFPS, "replay=single") );
$streamSrc = getStreamSrc( array( "source=event", "mode=jpeg", "event=".$event->Id(), "scale=".$scale, "maxfps=".ZM_WEB_VIDEO_MAXFPS, "replay=single") );
$imgHtml = '<img id="thumbnail'.$event->id().'" src="'.$imgSrc.'" alt="'. validHtmlStr('Event '.$event->Id()) .'" style="width:'. validInt($thumbData['Width']) .'px;height:'. validInt( $thumbData['Height'] ).'px;" onmouseover="this.src=\''.$streamSrc.'\';" onmouseout="this.src=\''.$imgSrc.'\';"/>'; $imgHtml = '<img id="thumbnail'.$event->id().'" src="'.$imgSrc.'" alt="'. validHtmlStr('Event '.$event->Id()) .'" style="width:'. validInt($thumbData['Width']) .'px;height:'. validInt( $thumbData['Height'] ).'px;" onmouseover="this.src=\''.$streamSrc.'\';" onmouseout="this.src=\''.$imgSrc.'\';"/>';
echo makePopupLink( echo makePopupLink(
'?view=frame&amp;eid='.$event->Id().'&amp;fid='.$thumbData['FrameId'], '?view=frame&amp;eid='.$event->Id().'&amp;fid='.$thumbData['FrameId'],
'zmImage', 'zmImage',
array( 'image', reScale( $event->Width(), $scale ), reScale( $event->Height(), $scale ) ), array( 'image', reScale( $event->Width(), $scale ), reScale( $event->Height(), $scale ) ),
$imgHtml $imgHtml
); );
?></td> ?>
</td>
<?php <?php
} else { } else {
?> ?>
<td class="colThumbnail">&nbsp;</td> <td class="colThumbnail">&nbsp;</td>
<?php <?php
}
} }
} // end if ZM_WEB_LIST_THUMBS
?> ?>
<td class="colMark"><input type="checkbox" name="markEids[]" value="<?php echo $event->Id() ?>" onclick="configureButton( this, 'markEids' );"<?php if ( !canEdit( 'Events' ) ) { ?> disabled="disabled"<?php } ?>/></td> <td class="colMark"><input type="checkbox" name="markEids[]" value="<?php echo $event->Id() ?>" onclick="configureButton( this, 'markEids' );"<?php if ( !canEdit( 'Events' ) ) { ?> disabled="disabled"<?php } ?>/></td>
</tr> </tr>
@ -239,14 +242,12 @@ foreach ( $events as $event ) {
</tbody> </tbody>
</table> </table>
<?php <?php
if ( $pagination ) if ( $pagination ) {
{
?> ?>
<h3 class="pagination"><?php echo $pagination ?></h3> <h3 class="pagination"><?php echo $pagination ?></h3>
<?php <?php
} }
if ( true || canEdit( 'Events' ) ) if ( true || canEdit( 'Events' ) ) {
{
?> ?>
<div id="contentButtons"> <div id="contentButtons">
<input type="button" name="viewBtn" value="<?php echo translate('View') ?>" onclick="viewEvents( this, 'markEids' );" disabled="disabled"/> <input type="button" name="viewBtn" value="<?php echo translate('View') ?>" onclick="viewEvents( this, 'markEids' );" disabled="disabled"/>

View File

@ -68,7 +68,7 @@ if ( isset( $_REQUEST['reload'] ) and ! $_REQUEST['reload'] ) {
$conjunctionTypes = array( $conjunctionTypes = array(
'and' => translate('ConjAnd'), 'and' => translate('ConjAnd'),
'or' => translate('ConjOr') 'or' => translate('ConjOr')
); );
$obracketTypes = array(); $obracketTypes = array();
$cbracketTypes = array(); $cbracketTypes = array();
if ( isset($_REQUEST['filter']['terms']) ) { if ( isset($_REQUEST['filter']['terms']) ) {
@ -102,7 +102,8 @@ $attrTypes = array(
'StorageId' => translate('AttrStorageArea'), 'StorageId' => translate('AttrStorageArea'),
'ServerId' => translate('AttrServer'), 'ServerId' => translate('AttrServer'),
'StateId' => translate('AttrStateId'), 'StateId' => translate('AttrStateId'),
); );
$opTypes = array( $opTypes = array(
'=' => translate('OpEq'), '=' => translate('OpEq'),
'!=' => translate('OpNe'), '!=' => translate('OpNe'),
@ -114,15 +115,18 @@ $opTypes = array(
'!~' => translate('OpNotMatches'), '!~' => translate('OpNotMatches'),
'=[]' => translate('OpIn'), '=[]' => translate('OpIn'),
'![]' => translate('OpNotIn'), '![]' => translate('OpNotIn'),
); );
$archiveTypes = array( $archiveTypes = array(
'0' => translate('ArchUnarchived'), '0' => translate('ArchUnarchived'),
'1' => translate('ArchArchived') '1' => translate('ArchArchived')
); );
$weekdays = array(); $weekdays = array();
for ( $i = 0; $i < 7; $i++ ) { for ( $i = 0; $i < 7; $i++ ) {
$weekdays[$i] = strftime( "%A", mktime( 12, 0, 0, 1, $i+1, 2001 ) ); $weekdays[$i] = strftime( '%A', mktime( 12, 0, 0, 1, $i+1, 2001 ) );
} }
$sort_fields = array( $sort_fields = array(
'Id' => translate('AttrId'), 'Id' => translate('AttrId'),
'Name' => translate('AttrName'), 'Name' => translate('AttrName'),
@ -136,14 +140,16 @@ $sort_fields = array(
'TotScore' => translate('AttrTotalScore'), 'TotScore' => translate('AttrTotalScore'),
'AvgScore' => translate('AttrAvgScore'), 'AvgScore' => translate('AttrAvgScore'),
'MaxScore' => translate('AttrMaxScore'), 'MaxScore' => translate('AttrMaxScore'),
); );
$sort_dirns = array( $sort_dirns = array(
'1' => translate('SortAsc'), '1' => translate('SortAsc'),
'0' => translate('SortDesc') '0' => translate('SortDesc')
); );
if ( empty($_REQUEST['sort_field']) ) { if ( empty($_REQUEST['sort_field']) ) {
$_REQUEST['sort_field'] = ZM_WEB_EVENT_SORT_FIELD; $_REQUEST['sort_field'] = ZM_WEB_EVENT_SORT_FIELD;
$_REQUEST['sort_asc'] = (ZM_WEB_EVENT_SORT_ORDER == "asc"); $_REQUEST['sort_asc'] = (ZM_WEB_EVENT_SORT_ORDER == 'asc');
} }
$hasCal = file_exists( 'tools/jscalendar/calendar.js' ); $hasCal = file_exists( 'tools/jscalendar/calendar.js' );
@ -180,98 +186,108 @@ for ( $i = 0; isset($_REQUEST['filter']) && $i < count($_REQUEST['filter']['term
?> ?>
<tr> <tr>
<?php <?php
if ( $i == 0 ) { if ( $i == 0 ) {
?> ?>
<td>&nbsp;</td> <td>&nbsp;</td>
<?php <?php
} else { } else {
?> ?>
<td><?php echo buildSelect( "filter[terms][$i][cnj]", $conjunctionTypes ); ?></td> <td><?php echo buildSelect( "filter[terms][$i][cnj]", $conjunctionTypes ); ?></td>
<?php <?php
} }
?> ?>
<td><?php if ( count($_REQUEST['filter']['terms']) > 2 ) { echo buildSelect( "filter[terms][$i][obr]", $obracketTypes ); } else { ?>&nbsp;<?php } ?></td> <td><?php if ( count($_REQUEST['filter']['terms']) > 2 ) { echo buildSelect( "filter[terms][$i][obr]", $obracketTypes ); } else { ?>&nbsp;<?php } ?></td>
<td><?php echo buildSelect( "filter[terms][$i][attr]", $attrTypes, "clearValue( this, $i ); submitToFilter( this, 0 );" ); ?></td> <td><?php echo buildSelect( "filter[terms][$i][attr]", $attrTypes, "clearValue( this, $i ); submitToFilter( this, 0 );" ); ?></td>
<?php <?php
if ( isset($_REQUEST['filter']['terms'][$i]['attr']) ) { if ( isset($_REQUEST['filter']['terms'][$i]['attr']) ) {
if ( $_REQUEST['filter']['terms'][$i]['attr'] == "Archived" ) { if ( $_REQUEST['filter']['terms'][$i]['attr'] == 'Archived' ) {
?> ?>
<td><?php echo translate('OpEq') ?><input type="hidden" name="filter[terms][<?php echo $i ?>][op]" value="="/></td> <td><?php echo translate('OpEq') ?><input type="hidden" name="filter[terms][<?php echo $i ?>][op]" value="="/></td>
<td><?php echo buildSelect( "filter[terms][$i][val]", $archiveTypes ); ?></td> <td><?php echo buildSelect( "filter[terms][$i][val]", $archiveTypes ); ?></td>
<?php <?php
} elseif ( $_REQUEST['filter']['terms'][$i]['attr'] == "DateTime" ) { } elseif ( $_REQUEST['filter']['terms'][$i]['attr'] == 'DateTime' ) {
?> ?>
<td><?php echo buildSelect( "filter[terms][$i][op]", $opTypes ); ?></td> <td><?php echo buildSelect( "filter[terms][$i][op]", $opTypes ); ?></td>
<td><input name="filter[terms][<?php echo $i ?>][val]" id="filter[terms][<?php echo $i ?>][val]" value="<?php echo isset($_REQUEST['filter']['terms'][$i]['val'])?validHtmlStr($_REQUEST['filter']['terms'][$i]['val']):'' ?>"/><?php if ( $hasCal ) { ?><script type="text/javascript">Calendar.setup( { inputField: "filter[terms][<?php echo $i ?>][val]", ifFormat: "%Y-%m-%d %H:%M", showsTime: true, timeFormat: "24", showOthers: true, weekNumbers: false });</script><?php } ?></td> <td>
<input name="filter[terms][<?php echo $i ?>][val]" id="filter[terms][<?php echo $i ?>][val]" value="<?php echo isset($_REQUEST['filter']['terms'][$i]['val'])?validHtmlStr($_REQUEST['filter']['terms'][$i]['val']):'' ?>"/>
<?php if ( $hasCal ) { ?>
<script type="text/javascript">Calendar.setup( { inputField: "filter[terms][<?php echo $i ?>][val]", ifFormat: "%Y-%m-%d %H:%M", showsTime: true, timeFormat: "24", showOthers: true, weekNumbers: false });</script>
<?php } ?>
</td>
<?php <?php
} elseif ( $_REQUEST['filter']['terms'][$i]['attr'] == "Date" ) { } elseif ( $_REQUEST['filter']['terms'][$i]['attr'] == 'Date' ) {
?> ?>
<td><?php echo buildSelect( "filter[terms][$i][op]", $opTypes ); ?></td> <td><?php echo buildSelect( "filter[terms][$i][op]", $opTypes ); ?></td>
<td><input name="filter[terms][<?php echo $i ?>][val]" id="filter[terms][<?php echo $i ?>][val]" value="<?php echo isset($_REQUEST['filter']['terms'][$i]['val'])?validHtmlStr($_REQUEST['filter']['terms'][$i]['val']):'' ?>"/><?php if ( $hasCal ) { ?><script type="text/javascript">Calendar.setup( { inputField: "filter[terms][<?php echo $i ?>][val]", ifFormat: "%Y-%m-%d", showOthers: true, weekNumbers: false });</script><?php } ?></td> <td>
<input name="filter[terms][<?php echo $i ?>][val]" id="filter[terms][<?php echo $i ?>][val]" value="<?php echo isset($_REQUEST['filter']['terms'][$i]['val'])?validHtmlStr($_REQUEST['filter']['terms'][$i]['val']):'' ?>"/>
<?php if ( $hasCal ) { ?>
<script type="text/javascript">Calendar.setup( { inputField: "filter[terms][<?php echo $i ?>][val]", ifFormat: "%Y-%m-%d", showOthers: true, weekNumbers: false });</script>
<?php } ?>
</td>
<?php <?php
} elseif ( $_REQUEST['filter']['terms'][$i]['attr'] == "StateId" ) { } elseif ( $_REQUEST['filter']['terms'][$i]['attr'] == "StateId" ) {
$states = array(); $states = array();
foreach ( dbFetchAll( 'SELECT Id,Name FROM States ORDER BY lower(Name) ASC' ) as $state_row ) { foreach ( dbFetchAll( 'SELECT Id,Name FROM States ORDER BY lower(Name) ASC' ) as $state_row ) {
$states[$state_row['Id']] = $state_row['Name']; $states[$state_row['Id']] = $state_row['Name'];
} }
?> ?>
<td><?php echo buildSelect( "filter[terms][$i][op]", $opTypes ); ?></td> <td><?php echo buildSelect( "filter[terms][$i][op]", $opTypes ); ?></td>
<td><?php echo buildSelect( "filter[terms][$i][val]", $states ); ?></td> <td><?php echo buildSelect( "filter[terms][$i][val]", $states ); ?></td>
<?php <?php
} elseif ( $_REQUEST['filter']['terms'][$i]['attr'] == "Weekday" ) { } elseif ( $_REQUEST['filter']['terms'][$i]['attr'] == 'Weekday' ) {
?> ?>
<td><?php echo buildSelect( "filter[terms][$i][op]", $opTypes ); ?></td> <td><?php echo buildSelect( "filter[terms][$i][op]", $opTypes ); ?></td>
<td><?php echo buildSelect( "filter[terms][$i][val]", $weekdays ); ?></td> <td><?php echo buildSelect( "filter[terms][$i][val]", $weekdays ); ?></td>
<?php <?php
} elseif ( false && $_REQUEST['filter']['terms'][$i]['attr'] == "MonitorName" ) { } elseif ( false && $_REQUEST['filter']['terms'][$i]['attr'] == 'MonitorName' ) {
$monitors = array(); $monitors = array();
foreach ( dbFetchAll( "select Id,Name from Monitors order by Sequence asc" ) as $monitor ) { foreach ( dbFetchAll( "select Id,Name from Monitors order by Sequence asc" ) as $monitor ) {
if ( visibleMonitor( $monitor['Id'] ) ) { if ( visibleMonitor( $monitor['Id'] ) ) {
$monitors[$monitor['Name']] = $monitor['Name']; $monitors[$monitor['Name']] = $monitor['Name'];
} }
} }
?> ?>
<td><?php echo buildSelect( "filter[terms][$i][op]", $opTypes ); ?></td> <td><?php echo buildSelect( "filter[terms][$i][op]", $opTypes ); ?></td>
<td><?php echo buildSelect( "filter[terms][$i][val]", $monitors ); ?></td> <td><?php echo buildSelect( "filter[terms][$i][val]", $monitors ); ?></td>
<?php <?php
} elseif ( $_REQUEST['filter']['terms'][$i]['attr'] == "ServerId" ) { } elseif ( $_REQUEST['filter']['terms'][$i]['attr'] == 'ServerId' ) {
$servers = array(); $servers = array();
$servers['ZM_SERVER_ID'] = 'Current Server'; $servers['ZM_SERVER_ID'] = 'Current Server';
foreach ( dbFetchAll( "SELECT Id,Name FROM Servers ORDER BY lower(Name) ASC" ) as $server ) { foreach ( dbFetchAll( "SELECT Id,Name FROM Servers ORDER BY lower(Name) ASC" ) as $server ) {
$servers[$server['Id']] = $server['Name']; $servers[$server['Id']] = $server['Name'];
} }
?> ?>
<td><?php echo buildSelect( "filter[terms][$i][op]", $opTypes ); ?></td> <td><?php echo buildSelect( "filter[terms][$i][op]", $opTypes ); ?></td>
<td><?php echo buildSelect( "filter[terms][$i][val]", $servers ); ?></td> <td><?php echo buildSelect( "filter[terms][$i][val]", $servers ); ?></td>
<?php <?php
} elseif ( $_REQUEST['filter']['terms'][$i]['attr'] == "StorageId" ) { } elseif ( $_REQUEST['filter']['terms'][$i]['attr'] == 'StorageId' ) {
$storageareas = array(); $storageareas = array();
$storageareas[0] = 'Default ' . ZM_DIR_EVENTS; $storageareas[0] = 'Default ' . ZM_DIR_EVENTS;
foreach ( dbFetchAll( "SELECT Id,Name FROM Storage ORDER BY lower(Name) ASC" ) as $storage ) { foreach ( dbFetchAll( "SELECT Id,Name FROM Storage ORDER BY lower(Name) ASC" ) as $storage ) {
$storageareas[$storage['Id']] = $storage['Name']; $storageareas[$storage['Id']] = $storage['Name'];
} }
?> ?>
<td><?php echo buildSelect( "filter[terms][$i][op]", $opTypes ); ?></td> <td><?php echo buildSelect( "filter[terms][$i][op]", $opTypes ); ?></td>
<td><?php echo buildSelect( "filter[terms][$i][val]", $storageareas ); ?></td> <td><?php echo buildSelect( "filter[terms][$i][val]", $storageareas ); ?></td>
<?php <?php
} else { } else {
?> ?>
<td><?php echo buildSelect( "filter[terms][$i][op]", $opTypes ); ?></td> <td><?php echo buildSelect( "filter[terms][$i][op]", $opTypes ); ?></td>
<td><input name="filter[terms][<?php echo $i ?>][val]" value="<?php echo $_REQUEST['filter']['terms'][$i]['val'] ?>"/></td> <td><input name="filter[terms][<?php echo $i ?>][val]" value="<?php echo $_REQUEST['filter']['terms'][$i]['val'] ?>"/></td>
<?php <?php
} }
} else { } else {
?> ?>
<td><?php echo buildSelect( "filter[terms][$i][op]", $opTypes ); ?></td> <td><?php echo buildSelect( "filter[terms][$i][op]", $opTypes ); ?></td>
<td><input name="filter[terms][<?php echo $i ?>][val]" value="<?php echo isset($_REQUEST['filter']['terms'][$i]['val'])?$_REQUEST['filter']['terms'][$i]['val']:'' ?>"/></td> <td><input name="filter[terms][<?php echo $i ?>][val]" value="<?php echo isset($_REQUEST['filter']['terms'][$i]['val'])?$_REQUEST['filter']['terms'][$i]['val']:'' ?>"/></td>
<?php <?php
} }
?> ?>
<td><?php if ( count($_REQUEST['filter']['terms']) > 2 ) { echo buildSelect( "filter[terms][$i][cbr]", $cbracketTypes ); } else { ?>&nbsp;<?php } ?></td> <td><?php if ( count($_REQUEST['filter']['terms']) > 2 ) { echo buildSelect( "filter[terms][$i][cbr]", $cbracketTypes ); } else { ?>&nbsp;<?php } ?></td>
<td><input type="button" onclick="addTerm( this, <?php echo $i+1 ?> )" value="+"/><?php if ( $_REQUEST['filter']['terms'] > 1 ) { ?><input type="button" onclick="delTerm( this, <?php echo $i ?> )" value="-"/><?php } ?></td> <td><input type="button" onclick="addTerm( this, <?php echo $i+1 ?> )" value="+"/><?php if ( $_REQUEST['filter']['terms'] > 1 ) { ?><input type="button" onclick="delTerm( this, <?php echo $i ?> )" value="-"/><?php } ?></td>
</tr> </tr>
<?php <?php
} } # end foreach filter
?> ?>
</tbody> </tbody>
</table> </table>
@ -279,7 +295,7 @@ for ( $i = 0; isset($_REQUEST['filter']) && $i < count($_REQUEST['filter']['term
<table id="sortTable" class="filterTable" cellspacing="0"> <table id="sortTable" class="filterTable" cellspacing="0">
<tbody> <tbody>
<tr> <tr>
<td><label for="sort_field"><?php echo translate('SortBy') ?></label><?php echo buildSelect( "sort_field", $sort_fields ); ?><?php echo buildSelect( "sort_asc", $sort_dirns ); ?></td> <td><label for="sort_field"><?php echo translate('SortBy') ?></label><?php echo buildSelect( 'sort_field', $sort_fields ); ?><?php echo buildSelect( 'sort_asc', $sort_dirns ); ?></td>
<td><label for="limit"><?php echo translate('LimitResultsPre') ?></label><input type="text" size="6" id="limit" name="limit" value="<?php echo isset($_REQUEST['limit'])?validInt($_REQUEST['limit']):"" ?>"/><?php echo translate('LimitResultsPost') ?></td> <td><label for="limit"><?php echo translate('LimitResultsPre') ?></label><input type="text" size="6" id="limit" name="limit" value="<?php echo isset($_REQUEST['limit'])?validInt($_REQUEST['limit']):"" ?>"/><?php echo translate('LimitResultsPost') ?></td>
</tr> </tr>
</tbody> </tbody>
@ -339,12 +355,18 @@ if ( ZM_OPT_MESSAGE ) {
<div id="contentButtons"> <div id="contentButtons">
<input type="submit" value="<?php echo translate('Submit') ?>" onclick="submitToEvents( this );"/> <input type="submit" value="<?php echo translate('Submit') ?>" 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 if ( canEdit( 'Events' ) ) { ?> <?php
if ( canEdit( 'Events' ) ) {
?>
<input type="button" value="<?php echo translate('Save') ?>" onclick="saveFilter( this );"/> <input type="button" value="<?php echo translate('Save') ?>" onclick="saveFilter( this );"/>
<?php } ?> <?php
<?php if ( canEdit( 'Events' ) && isset($dbFilter) && $dbFilter['Name'] ) { ?> if ( isset($dbFilter) && $dbFilter['Name'] ) {
<input type="button" value="<?php echo translate('Delete') ?>" onclick="deleteFilter( this, <?php echo $dbFilter['Id'] ?>, '<?php echo $dbFilter['Name'] ?>' );"/> ?>
<?php } ?> <input type="button" value="<?php echo translate('Delete') ?>" onclick="deleteFilter( this, '<?php echo $dbFilter['Name'] ?>' );"/>
<?php
}
}
?>
<input type="button" value="<?php echo translate('Reset') ?>" onclick="submitToFilter( this, 1 );"/> <input type="button" value="<?php echo translate('Reset') ?>" onclick="submitToFilter( this, 1 );"/>
</div> </div>
</form> </form>

View File

@ -37,7 +37,7 @@ if ( !empty($fid) ) {
if ( !($frame = dbFetchOne( $sql, NULL, array($eid, $fid) )) ) if ( !($frame = dbFetchOne( $sql, NULL, array($eid, $fid) )) )
$frame = array( 'FrameId'=>$fid, 'Type'=>'Normal', 'Score'=>0 ); $frame = array( 'FrameId'=>$fid, 'Type'=>'Normal', 'Score'=>0 );
} else { } else {
$frame = dbFetchOne( 'SELECT * FROM Frames WHERE EventId = ? AND Score = ?', NULL, array( $eid, $Event->MaxScore() ) ); $frame = dbFetchOne( 'SELECT * FROM Frames WHERE EventId = ? AND Score = ?', NULL, array( $eid, $Event->MaxScore() ) );
} }
$Frame = new Frame( $frame ); $Frame = new Frame( $frame );
@ -60,22 +60,27 @@ if ( isset( $_REQUEST['scale'] ) ) {
$scale = max( reScale( SCALE_BASE, $Monitor->DefaultScale(), ZM_WEB_DEFAULT_SCALE ), SCALE_BASE ); $scale = max( reScale( SCALE_BASE, $Monitor->DefaultScale(), ZM_WEB_DEFAULT_SCALE ), SCALE_BASE );
} }
$imageData = $Event->getImageSrc( $frame, $scale, 0 );
if ( ! $imageData ) {
Error("No data found for Event $eid frame $fid");
$imageData = array();
}
$show = 'capt'; $show = 'capt';
if ( isset($_REQUEST['show']) ) { if ( isset($_REQUEST['show']) ) {
$show = $_REQUEST['show']; $show = $_REQUEST['show'];
#} else if ( $imageData['hasAnalImage'] ) { } else if ( $imageData['hasAnalImage'] ) {
#$show = 'anal'; $show = 'anal';
} }
$imageData = $Event->getImageSrc( $frame, $scale, ($show=="capt") );
$imagePath = $imageData['thumbPath']; $imagePath = $imageData['thumbPath'];
$eventPath = $imageData['eventPath']; $eventPath = $imageData['eventPath'];
$dImagePath = sprintf( "%s/%0".ZM_EVENT_IMAGE_DIGITS."d-diag-d.jpg", $eventPath, $Frame->FrameId() ); $dImagePath = sprintf( '%s/%0'.ZM_EVENT_IMAGE_DIGITS.'d-diag-d.jpg', $eventPath, $Frame->FrameId() );
$rImagePath = sprintf( "%s/%0".ZM_EVENT_IMAGE_DIGITS."d-diag-r.jpg", $eventPath, $Frame->FrameId() ); $rImagePath = sprintf( '%s/%0'.ZM_EVENT_IMAGE_DIGITS.'d-diag-r.jpg', $eventPath, $Frame->FrameId() );
$focusWindow = true; $focusWindow = true;
xhtmlHeaders(__FILE__, translate('Frame')." - ".$Event->Id()." - ".$Frame->FrameId() ); xhtmlHeaders(__FILE__, translate('Frame').' - '.$Event->Id()." - ".$Frame->FrameId() );
?> ?>
<body> <body>
<div id="page"> <div id="page">
@ -94,13 +99,13 @@ xhtmlHeaders(__FILE__, translate('Frame')." - ".$Event->Id()." - ".$Frame->Frame
</div> </div>
<div id="content"> <div id="content">
<p id="image"> <p id="image">
<?php if ( $imageData['hasAnalImage'] ) { ?>
<a href="?view=frame&amp;eid=<?php echo $Event->Id() ?>&amp;fid=<?php echo $Frame->FrameId() ?>&amp;scale=<?php echo $scale ?>&amp;show=<?php echo $imageData['isAnalImage']?"capt":"anal" ?>"> <?php if ( $imageData['hasAnalImage'] ) {
<?php } ?> echo sprintf('<a href="?view=frame&amp;eid=%d&amp;fid=%d&scale=%d&amp;show=%s">', $Event->Id(), $Frame->FrameId(), $scale, ( $show=='anal'?'capt':'anal' ) );
<img id="frameImg" src="<?php echo $Frame->getImageSrc($imageData['isAnalImage']?'analyse':'capture') ?>" width="<?php echo reScale( $Event->Width(), $Event->DefaultScale(), $scale ) ?>" height="<?php echo reScale( $Event->Height(), $Event->DefaultScale(), $scale ) ?>" alt="<?php echo $Frame->EventId()."-".$Frame->FrameId() ?>" class="<?php echo $imageData['imageClass'] ?>"/> } ?>
<?php if ( $imageData['hasAnalImage'] ) { ?> <img id="frameImg" src="<?php echo $Frame->getImageSrc($show=='anal'?'analyse':'capture') ?>" width="<?php echo reScale( $Event->Width(), $Event->DefaultScale(), $scale ) ?>" height="<?php echo reScale( $Event->Height(), $Event->DefaultScale(), $scale ) ?>" alt="<?php echo $Frame->EventId()."-".$Frame->FrameId() ?>" class="<?php echo $imageData['imageClass'] ?>"/>
</a> <?php if ( $imageData['hasAnalImage'] ) { ?></a><?php } ?>
<?php } ?>
</p> </p>
<p id="controls"> <p id="controls">
<?php if ( $Frame->FrameId() > 1 ) { ?> <?php if ( $Frame->FrameId() > 1 ) { ?>

View File

@ -7,13 +7,13 @@ function updateButtons( element ) {
var canExecute = false; var canExecute = false;
if ( form.elements['AutoArchive'].checked ) if ( form.elements['AutoArchive'].checked )
canExecute = true; canExecute = true;
else if ( typeof ZM_OPT_FFMPEG !== "undefined" && form.elements['AutoVideo'].checked ) else if ( form.elements['AutoVideo'] && form.elements['AutoVideo'].checked )
canExecute = true; canExecute = true;
else if ( typeof ZM_OPT_UPLOAD !== "undefined" && form.elements['AutoUpload'].checked ) else if ( form.elements['AutoUpload'] && form.elements['AutoUpload'].checked )
canExecute = true; canExecute = true;
else if ( typeof ZM_OPT_EMAIL !== "undefined" && form.elements['AutoEmail'].checked ) else if ( form.elements['AutoEmail'] && form.elements['AutoEmail'].checked )
canExecute = true; canExecute = true;
else if ( typeof ZM_OPT_MESSAGE !== "undefined" && form.elements['AutoMessage'].checked ) else if ( form.elements['AutoMessage'] && form.elements['AutoMessage'].checked )
canExecute = true; canExecute = true;
else if ( form.elements['AutoExecute'].checked && form.elements['AutoExecuteCmd'].value != '' ) else if ( form.elements['AutoExecute'].checked && form.elements['AutoExecuteCmd'].value != '' )
canExecute = true; canExecute = true;

View File

@ -52,7 +52,7 @@ if ( ! $Server ) {
} }
if ( ! empty($_REQUEST['mid']) ) { if ( ! empty($_REQUEST['mid']) ) {
$monitor = new Monitor( $_REQUEST['mid'] ); $monitor = dbFetchMonitor( $_REQUEST['mid'] );
if ( ZM_OPT_X10 ) if ( ZM_OPT_X10 )
$x10Monitor = dbFetchOne( 'SELECT * FROM TriggersX10 WHERE MonitorId = ?', NULL, array($_REQUEST['mid']) ); $x10Monitor = dbFetchOne( 'SELECT * FROM TriggersX10 WHERE MonitorId = ?', NULL, array($_REQUEST['mid']) );
} else { } else {
@ -155,13 +155,12 @@ function fourcc( $a, $b, $c, $d ) {
} }
if ( isset( $_REQUEST['newMonitor'] ) ) { if ( isset( $_REQUEST['newMonitor'] ) ) {
# Update the monitor object with whatever has been set so far. $newMonitor = $_REQUEST['newMonitor'];
$monitor->set( $_REQUEST['newMonitor'] );
if ( ZM_OPT_X10 ) if ( ZM_OPT_X10 )
$newX10Monitor = $_REQUEST['newX10Monitor']; $newX10Monitor = $_REQUEST['newX10Monitor'];
# FIXME: Triggers in the db is a comma separated string. Needs to be an array.
#$monitor->Triggers = explode( ',', isset($monitor->Triggers)?$monitor->Triggers:"" );
} else { } else {
$newMonitor = $monitor;
$newMonitor['Triggers'] = explode( ',', isset($monitor['Triggers'])?$monitor['Triggers']:"" );
if ( ZM_OPT_X10 ) if ( ZM_OPT_X10 )
$newX10Monitor = $x10Monitor; $newX10Monitor = $x10Monitor;
} }
@ -176,28 +175,25 @@ if ( $monitor->AlarmMaxFPS == '0.00' )
if ( !empty($_REQUEST['preset']) ) { if ( !empty($_REQUEST['preset']) ) {
$preset = dbFetchOne( 'SELECT Type, Device, Channel, Format, Protocol, Method, Host, Port, Path, Width, Height, Palette, MaxFPS, Controllable, ControlId, ControlDevice, ControlAddress, DefaultRate, DefaultScale FROM MonitorPresets WHERE Id = ?', NULL, array($_REQUEST['preset']) ); $preset = dbFetchOne( 'SELECT Type, Device, Channel, Format, Protocol, Method, Host, Port, Path, Width, Height, Palette, MaxFPS, Controllable, ControlId, ControlDevice, ControlAddress, DefaultRate, DefaultScale FROM MonitorPresets WHERE Id = ?', NULL, array($_REQUEST['preset']) );
#$monitor->set( $preset );
foreach ( $preset as $name=>$value ) { foreach ( $preset as $name=>$value ) {
# Does isset handle NULL's? I don't think this code is correct.
if ( isset($value) ) { if ( isset($value) ) {
$monitor->$name = $value; $newMonitor[$name] = $value;
} }
} }
} }
if ( !empty($_REQUEST['probe']) ) { if ( !empty($_REQUEST['probe']) ) {
$probe = unserialize(base64_decode($_REQUEST['probe'])); $probe = unserialize(base64_decode($_REQUEST['probe']));
foreach ( $probe as $name=>$value ) { foreach ( $probe as $name=>$value ) {
# Again I don't think isset is useful here.
if ( isset($value) ) { if ( isset($value) ) {
$monitor->$name = $value; $newMonitor[$name] = $value;
} }
} }
if ( ZM_HAS_V4L && $monitor->Type == 'Local' ) { if ( ZM_HAS_V4L && $newMonitor['Type'] == 'Local' ) {
$monitor->Palette = fourCC( substr($monitor->Palette,0,1), substr($monitor->Palette,1,1), substr($monitor->Palette,2,1), substr($monitor->Palette,3,1) ); $newMonitor['Palette'] = fourCC( substr($newMonitor['Palette'],0,1), substr($newMonitor['Palette'],1,1), substr($newMonitor['Palette'],2,1), substr($newMonitor['Palette'],3,1) );
if ( $monitor->Format == 'PAL' ) if ( $newMonitor['Format'] == 'PAL' )
$monitor->Format = 0x000000ff; $newMonitor['Format'] = 0x000000ff;
elseif ( $monitor->Format == 'NTSC' ) elseif ( $newMonitor['Format'] == 'NTSC' )
$monitor->Format = 0x0000b000; $newMonitor['Format'] = 0x0000b000;
} }
} }
@ -469,7 +465,7 @@ $videowriteropts = array(
'H264 Camera Passthrough' => 2 'H264 Camera Passthrough' => 2
); );
xhtmlHeaders(__FILE__, translate('Monitor')." - ".validHtmlStr($monitor->Name) ); xhtmlHeaders(__FILE__, translate('Monitor')." - ".validHtmlStr($monitor['Name']) );
?> ?>
<body> <body>
<div id="page"> <div id="page">
@ -513,6 +509,10 @@ foreach ( $tabs as $name=>$value ) {
<li><a href="#" onclick="submitTab( '<?php echo $name ?>' ); return( false );"><?php echo $value ?></a></li> <li><a href="#" onclick="submitTab( '<?php echo $name ?>' ); return( false );"><?php echo $value ?></a></li>
<?php <?php
} }
?>
<a href="#" onclick="createPopup( '?view=monitorpreset&amp;mid=<?php echo $monitor['Id'] ?>', 'zmMonitorPreset<?php echo $monitor['Id'] ?>', 'monitorpreset' ); return( false );"><?php echo translate('Presets') ?></a>
</div>
<?php
} }
?> ?>
</ul> </ul>
@ -661,6 +661,7 @@ if ( ZM_HAS_V4L && ($tab != 'misc' || $monitor->Type != 'Local') ) {
<input type="hidden" name="newMonitor[SignalCheckColour]" value="<?php echo validHtmlStr($monitor->SignalCheckColour) ?>"/> <input type="hidden" name="newMonitor[SignalCheckColour]" value="<?php echo validHtmlStr($monitor->SignalCheckColour) ?>"/>
<?php <?php
} }
if ( ZM_HAS_V4L && ($tab != 'source' || $newMonitor['Type'] != 'Local') ) {
?> ?>
<table id="contentTable" class="major" cellspacing="0"> <table id="contentTable" class="major" cellspacing="0">
<tbody> <tbody>
@ -754,28 +755,26 @@ switch ( $tab ) {
</select></td></tr> </select></td></tr>
<?php <?php
} else { } else {
?> ?>
<tr><td><?php echo translate('RefImageBlendPct') ?></td><td><input type="text" name="newMonitor[RefBlendPerc]" value="<?php echo validHtmlStr($monitor->RefBlendPerc) ?>" size="4"/></td></tr> <tr><td><?php echo translate('RefImageBlendPct') ?></td><td><input type="text" name="newMonitor[RefBlendPerc]" value="<?php echo validHtmlStr($newMonitor['RefBlendPerc']) ?>" size="4"/></td></tr>
<tr><td><?php echo translate('AlarmRefImageBlendPct') ?></td><td><input type="text" name="newMonitor[AlarmRefBlendPerc]" value="<?php echo validHtmlStr($monitor->AlarmRefBlendPerc) ?>" size="4"/></td></tr> <tr><td><?php echo translate('AlarmRefImageBlendPct') ?></td><td><input type="text" name="newMonitor[AlarmRefBlendPerc]" value="<?php echo validHtmlStr($newMonitor['AlarmRefBlendPerc']) ?>" size="4"/></td></tr>
<?php <?php
} }
?> ?>
<tr><td><?php echo translate('Triggers') ?></td><td> <tr><td><?php echo translate('Triggers') ?></td><td>
<?php <?php
$optTriggers = getSetValues( 'Monitors', 'Triggers' ); $optTriggers = getSetValues( 'Monitors', 'Triggers' );
$breakCount = (int)(ceil(count($optTriggers))); $breakCount = (int)(ceil(count($optTriggers)));
$breakCount = min( 3, $breakCount ); $breakCount = min( 3, $breakCount );
$optCount = 0; $optCount = 0;
foreach( $optTriggers as $optTrigger ) { foreach( $optTriggers as $optTrigger ) {
if ( ( ! ZM_OPT_X10 ) && ( $optTrigger == 'X10' ) ) if ( !ZM_OPT_X10 && $optTrigger == 'X10' )
continue; continue;
if ( $optCount && ($optCount%$breakCount == 0) ) if ( $optCount && ($optCount%$breakCount == 0) )
echo '</br>'; echo '</br>';
echo '<input type="checkbox" name="newMonitor[Triggers][]" value="'. $optTrigger .'"'; ?>
if ( isset($monitor->Triggers) && is_array( $monitor->Triggers ) and in_array( $optTrigger, $monitor->Triggers ) ) { <input type="checkbox" name="newMonitor[Triggers][]" value="<?php echo $optTrigger ?>"<?php if ( isset($newMonitor['Triggers']) && in_array( $optTrigger, $newMonitor['Triggers'] ) ) { ?> checked="checked"<?php } ?>/>&nbsp;<?php echo $optTrigger ?>
echo ' checked="checked"'; <?php
}
echo '/>&nbsp;'. $optTrigger ;
$optCount ++; $optCount ++;
} }
if ( !$optCount ) { if ( !$optCount ) {
@ -844,9 +843,11 @@ switch ( $tab ) {
<tr><td><?php echo translate('Deinterlacing') ?></td><td><select name="newMonitor[Deinterlacing]"><?php foreach ( $deinterlaceopts_v4l2 as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->Deinterlacing ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr> <tr><td><?php echo translate('Deinterlacing') ?></td><td><select name="newMonitor[Deinterlacing]"><?php foreach ( $deinterlaceopts_v4l2 as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->Deinterlacing ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
<?php <?php
} else { } else {
?> ?>
<tr><td><?php echo translate('Deinterlacing') ?></td><td><select name="newMonitor[Deinterlacing]"><?php foreach ( $deinterlaceopts as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->Deinterlacing ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr> <tr><td><?php echo translate('DeviceChannel') ?></td><td><select name="newMonitor[Channel]"><?php foreach ( $v4l2DeviceChannels as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $newMonitor['Channel'] ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
<?php <tr><td><?php echo translate('DeviceFormat') ?></td><td><select name="newMonitor[Format]"><?php foreach ( $v4l2DeviceFormats as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $newMonitor['Format'] ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
<tr><td><?php echo translate('CapturePalette') ?></td><td><select name="newMonitor[Palette]"><?php foreach ( $v4l2LocalPalettes as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $newMonitor['Palette'] ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
<?php
} }
?> ?>
<?php <?php
@ -855,70 +856,111 @@ switch ( $tab ) {
<tr id="RTSPDescribe"<?php if ( $monitor->Protocol != 'rtsp' ) { echo ' style="display:none;"'; } ?>><td><?php echo translate('RTSPDescribe') ?>&nbsp;(<?php echo makePopupLink( '?view=optionhelp&amp;option=OPTIONS_RTSPDESCRIBE', 'zmOptionHelp', 'optionhelp', '?' ) ?>) </td><td><input type="checkbox" name="newMonitor[RTSPDescribe]" value="1"<?php if ( !empty($monitor->RTSPDescribe) ) { ?> checked="checked"<?php } ?>/></td></tr> <tr id="RTSPDescribe"<?php if ( $monitor->Protocol != 'rtsp' ) { echo ' style="display:none;"'; } ?>><td><?php echo translate('RTSPDescribe') ?>&nbsp;(<?php echo makePopupLink( '?view=optionhelp&amp;option=OPTIONS_RTSPDESCRIBE', 'zmOptionHelp', 'optionhelp', '?' ) ?>) </td><td><input type="checkbox" name="newMonitor[RTSPDescribe]" value="1"<?php if ( !empty($monitor->RTSPDescribe) ) { ?> checked="checked"<?php } ?>/></td></tr>
<?php <?php
} }
?> ?>
<?php <tr><td><?php echo translate('RemoteHostName') ?></td><td><input type="text" name="newMonitor[Host]" value="<?php echo validHtmlStr($newMonitor['Host']) ?>" size="36"/></td></tr>
break; <tr><td><?php echo translate('RemoteHostPort') ?></td><td><input type="text" name="newMonitor[Port]" value="<?php echo validHtmlStr($newMonitor['Port']) ?>" size="6"/></td></tr>
<tr><td><?php echo translate('RemoteHostPath') ?></td><td><input type="text" name="newMonitor[Path]" value="<?php echo validHtmlStr($newMonitor['Path']) ?>" size="36"/></td></tr>
<?php
} elseif ( $newMonitor['Type'] == 'File' ) {
?>
<tr><td><?php echo translate('SourcePath') ?></td><td><input type="text" name="newMonitor[Path]" value="<?php echo validHtmlStr($newMonitor['Path']) ?>" size="36"/></td></tr>
<?php
} elseif ( $newMonitor['Type'] == 'cURL' ) {
?>
<tr><td><?php echo 'URL' ?></td><td><input type="text" name="newMonitor[Path]" value="<?php echo validHtmlStr($newMonitor['Path']) ?>" size="36"/></td></tr>
<tr><td><?php echo 'Username' ?></td><td><input type="text" name="newMonitor[User]" value="<?php echo validHtmlStr($newMonitor['User']) ?>" size="12"/></td></tr>
<tr><td><?php echo 'Password' ?></td><td><input type="text" name="newMonitor[Pass]" value="<?php echo validHtmlStr($newMonitor['Pass']) ?>" size="12"/></td></tr>
<?php
} elseif ( $newMonitor['Type'] == 'Ffmpeg' || $newMonitor['Type'] == 'Libvlc' ) {
?>
<tr><td><?php echo translate('SourcePath') ?></td><td><input type="text" name="newMonitor[Path]" value="<?php echo validHtmlStr($newMonitor['Path']) ?>" size="36"/></td></tr>
<tr><td><?php echo translate('RemoteMethod') ?>&nbsp;(<?php echo makePopupLink('?view=optionhelp&amp;option=OPTIONS_RTSPTrans', 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td><td><?php echo buildSelect( "newMonitor[Method]", $rtspFFMpegMethods ); ?></td></tr>
<tr><td><?php echo translate('Options') ?>&nbsp;(<?php echo makePopupLink( '?view=optionhelp&amp;option=OPTIONS_'.strtoupper($newMonitor['Type']), 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td><td><input type="text" name="newMonitor[Options]" value="<?php echo validHtmlStr($newMonitor['Options']) ?>" size="36"/></td></tr>
<?php
}
?>
<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 == $newMonitor['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="text" name="newMonitor[Width]" value="<?php echo validHtmlStr($newMonitor['Width']) ?>" size="4" onkeyup="updateMonitorDimensions(this);"/></td></tr>
<tr><td><?php echo translate('CaptureHeight') ?> (<?php echo translate('Pixels') ?>)</td><td><input type="text" name="newMonitor[Height]" value="<?php echo validHtmlStr($newMonitor['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><select name="newMonitor[Orientation]"><?php foreach ( $orientations as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $newMonitor['Orientation'] ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
<?php
if ( $newMonitor['Type'] == 'Local' ) {
?>
<tr><td><?php echo translate('Deinterlacing') ?></td><td><select name="newMonitor[Deinterlacing]"><?php foreach ( $deinterlaceopts_v4l2 as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $newMonitor['Deinterlacing'] ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
<?php
} else {
?>
<tr><td><?php echo translate('Deinterlacing') ?></td><td><select name="newMonitor[Deinterlacing]"><?php foreach ( $deinterlaceopts as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $newMonitor['Deinterlacing'] ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
<?php
}
if ( $newMonitor['Type'] == 'Remote' ) {
?>
<tr id="RTSPDescribe"<?php if ( $newMonitor['Protocol'] != 'rtsp' ) { echo ' style="display:none;"'; } ?>><td><?php echo translate('RTSPDescribe') ?>&nbsp;(<?php echo makePopupLink( '?view=optionhelp&amp;option=OPTIONS_RTSPDESCRIBE', 'zmOptionHelp', 'optionhelp', '?' ) ?>) </td><td><input type="checkbox" name="newMonitor[RTSPDescribe]" value="1"<?php if ( !empty($newMonitor['RTSPDescribe']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<?php
}
break;
} }
case 'storage' : case 'storage' :
?> ?>
<tr><td><?php echo translate('SaveJPEGs') ?></td><td><select name="newMonitor[SaveJPEGs]"><?php foreach ( $savejpegopts as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->SaveJPEGs ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr> <tr><td><?php echo translate('SaveJPEGs') ?></td><td><select name="newMonitor[SaveJPEGs]"><?php foreach ( $savejpegopts as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $newMonitor['SaveJPEGs'] ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
<tr><td><?php echo translate('VideoWriter') ?></td><td><select name="newMonitor[VideoWriter]"><?php foreach ( $videowriteropts as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->VideoWriter ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr> <tr><td><?php echo translate('VideoWriter') ?></td><td><select name="newMonitor[VideoWriter]"><?php foreach ( $videowriteropts as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $newMonitor['VideoWriter'] ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
<tr><td><?php echo translate('OptionalEncoderParam') ?></td><td><textarea name="newMonitor[EncoderParameters]" rows="4" cols="36"><?php echo validHtmlStr($monitor->EncoderParameters) ?></textarea></td></tr> <tr><td><?php echo translate('OptionalEncoderParam') ?></td><td><textarea name="newMonitor[EncoderParameters]" rows="4" cols="36"><?php echo validHtmlStr($newMonitor['EncoderParameters']) ?></textarea></td></tr>
<tr><td><?php echo translate('RecordAudio') ?></td><td><input type="checkbox" name="newMonitor[RecordAudio]" value="1"<?php if ($monitor->RecordAudio) { ?> checked="checked"<?php } ?>/></td></tr> <tr><td><?php echo translate('RecordAudio') ?></td><td><input type="checkbox" name="newMonitor[RecordAudio]" value="1"<?php if ( !empty($newMonitor['RecordAudio']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<?php <?php
break; break;
case 'timestamp' : case 'timestamp' :
{ {
?> ?>
<tr><td><?php echo translate('TimestampLabelFormat') ?></td><td><input type="text" name="newMonitor[LabelFormat]" value="<?php echo validHtmlStr($monitor->LabelFormat) ?>" size="32"/></td></tr> <tr><td><?php echo translate('TimestampLabelFormat') ?></td><td><input type="text" name="newMonitor[LabelFormat]" value="<?php echo validHtmlStr($newMonitor['LabelFormat']) ?>" size="32"/></td></tr>
<tr><td><?php echo translate('TimestampLabelX') ?></td><td><input type="text" name="newMonitor[LabelX]" value="<?php echo validHtmlStr($monitor->LabelX) ?>" size="4"/></td></tr> <tr><td><?php echo translate('TimestampLabelX') ?></td><td><input type="text" name="newMonitor[LabelX]" value="<?php echo validHtmlStr($newMonitor['LabelX']) ?>" size="4"/></td></tr>
<tr><td><?php echo translate('TimestampLabelY') ?></td><td><input type="text" name="newMonitor[LabelY]" value="<?php echo validHtmlStr($monitor->LabelY) ?>" size="4"/></td></tr> <tr><td><?php echo translate('TimestampLabelY') ?></td><td><input type="text" name="newMonitor[LabelY]" value="<?php echo validHtmlStr($newMonitor['LabelY']) ?>" size="4"/></td></tr>
<tr><td><?php echo translate('TimestampLabelSize') ?></td><td><select name="newMonitor[LabelSize]"><?php foreach ( $label_size as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $monitor->LabelSize ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr> <tr><td><?php echo translate('TimestampLabelSize') ?></td><td><select name="newMonitor[LabelSize]"><?php foreach ( $label_size as $name => $value ) { ?><option value="<?php echo $value ?>"<?php if ( $value == $newMonitor['LabelSize'] ) { ?> selected="selected"<?php } ?>><?php echo $name ?></option><?php } ?></select></td></tr>
<?php <?php
break; break;
} }
case 'buffers' : case 'buffers' :
{ {
?> ?>
<tr><td><?php echo translate('ImageBufferSize') ?></td><td><input type="text" name="newMonitor[ImageBufferCount]" value="<?php echo validHtmlStr($monitor->ImageBufferCount) ?>" size="6"/></td></tr> <tr><td><?php echo translate('ImageBufferSize') ?></td><td><input type="text" name="newMonitor[ImageBufferCount]" value="<?php echo validHtmlStr($newMonitor['ImageBufferCount']) ?>" size="6"/></td></tr>
<tr><td><?php echo translate('WarmupFrames') ?></td><td><input type="text" name="newMonitor[WarmupCount]" value="<?php echo validHtmlStr($monitor->WarmupCount) ?>" size="4"/></td></tr> <tr><td><?php echo translate('WarmupFrames') ?></td><td><input type="text" name="newMonitor[WarmupCount]" value="<?php echo validHtmlStr($newMonitor['WarmupCount']) ?>" size="4"/></td></tr>
<tr><td><?php echo translate('PreEventImageBuffer') ?></td><td><input type="text" name="newMonitor[PreEventCount]" value="<?php echo validHtmlStr($monitor->PreEventCount) ?>" size="4"/></td></tr> <tr><td><?php echo translate('PreEventImageBuffer') ?></td><td><input type="text" name="newMonitor[PreEventCount]" value="<?php echo validHtmlStr($newMonitor['PreEventCount']) ?>" size="4"/></td></tr>
<tr><td><?php echo translate('PostEventImageBuffer') ?></td><td><input type="text" name="newMonitor[PostEventCount]" value="<?php echo validHtmlStr($monitor->PostEventCount) ?>" size="4"/></td></tr> <tr><td><?php echo translate('PostEventImageBuffer') ?></td><td><input type="text" name="newMonitor[PostEventCount]" value="<?php echo validHtmlStr($newMonitor['PostEventCount']) ?>" size="4"/></td></tr>
<tr><td><?php echo translate('StreamReplayBuffer') ?></td><td><input type="text" name="newMonitor[StreamReplayBuffer]" value="<?php echo validHtmlStr($monitor->StreamReplayBuffer) ?>" size="6"/></td></tr> <tr><td><?php echo translate('StreamReplayBuffer') ?></td><td><input type="text" name="newMonitor[StreamReplayBuffer]" value="<?php echo validHtmlStr($newMonitor['StreamReplayBuffer']) ?>" size="6"/></td></tr>
<tr><td><?php echo translate('AlarmFrameCount') ?></td><td><input type="text" name="newMonitor[AlarmFrameCount]" value="<?php echo validHtmlStr($monitor->AlarmFrameCount) ?>" size="4"/></td></tr> <tr><td><?php echo translate('AlarmFrameCount') ?></td><td><input type="text" name="newMonitor[AlarmFrameCount]" value="<?php echo validHtmlStr($newMonitor['AlarmFrameCount']) ?>" size="4"/></td></tr>
<?php <?php
break; break;
} }
case 'control' : case 'control' :
{ {
?> ?>
<tr><td><?php echo translate('Controllable') ?></td><td><input type="checkbox" name="newMonitor[Controllable]" value="1"<?php if ( !empty($monitor->Controllable) ) { ?> checked="checked"<?php } ?>/></td></tr> <tr><td><?php echo translate('Controllable') ?></td><td><input type="checkbox" name="newMonitor[Controllable]" value="1"<?php if ( !empty($newMonitor['Controllable']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<tr><td><?php echo translate('ControlType') ?></td><td><?php echo htmlSelect( "newMonitor[ControlId]", $controlTypes, $monitor->ControlId(), 'loadLocations( this )' ); ?><?php if ( canEdit( 'Control' ) ) { ?>&nbsp;<a href="#" onclick="createPopup( '?view=controlcaps', 'zmControlCaps', 'controlcaps' );"><?php echo translate('Edit') ?></a><?php } ?></td></tr> <tr><td><?php echo translate('ControlType') ?></td><td><?php echo buildSelect( "newMonitor[ControlId]", $controlTypes, 'loadLocations( this )' ); ?><?php if ( canEdit( 'Control' ) ) { ?>&nbsp;<a href="#" onclick="createPopup( '?view=controlcaps', 'zmControlCaps', 'controlcaps' );"><?php echo translate('Edit') ?></a><?php } ?></td></tr>
<tr><td><?php echo translate('ControlDevice') ?></td><td><input type="text" name="newMonitor[ControlDevice]" value="<?php echo validHtmlStr($monitor->ControlDevice) ?>" size="32"/></td></tr> <tr><td><?php echo translate('ControlDevice') ?></td><td><input type="text" name="newMonitor[ControlDevice]" value="<?php echo validHtmlStr($newMonitor['ControlDevice']) ?>" size="32"/></td></tr>
<tr><td><?php echo translate('ControlAddress') ?></td><td><input type="text" name="newMonitor[ControlAddress]" value="<?php echo validHtmlStr($monitor->ControlAddress) ?>" size="32"/></td></tr> <tr><td><?php echo translate('ControlAddress') ?></td><td><input type="text" name="newMonitor[ControlAddress]" value="<?php echo validHtmlStr($newMonitor['ControlAddress']) ?>" size="32"/></td></tr>
<tr><td><?php echo translate('AutoStopTimeout') ?></td><td><input type="text" name="newMonitor[AutoStopTimeout]" value="<?php echo validHtmlStr($monitor->AutoStopTimeout) ?>" size="4"/></td></tr> <tr><td><?php echo translate('AutoStopTimeout') ?></td><td><input type="text" name="newMonitor[AutoStopTimeout]" value="<?php echo validHtmlStr($newMonitor['AutoStopTimeout']) ?>" size="4"/></td></tr>
<tr><td><?php echo translate('TrackMotion') ?></td><td><input type="checkbox" name="newMonitor[TrackMotion]" value="1"<?php if ( !empty($monitor->TrackMotion) ) { ?> checked="checked"<?php } ?>/></td></tr> <tr><td><?php echo translate('TrackMotion') ?></td><td><input type="checkbox" name="newMonitor[TrackMotion]" value="1"<?php if ( !empty($newMonitor['TrackMotion']) ) { ?> checked="checked"<?php } ?>/></td></tr>
<?php <?php
$return_options = array( $return_options = array(
'-1' => translate('None'), '-1' => translate('None'),
'0' => translate('Home'), '0' => translate('Home'),
'1' => translate('Preset')." 1", '1' => translate('Preset')." 1",
); );
?> ?>
<tr><td><?php echo translate('TrackDelay') ?></td><td><input type="text" name="newMonitor[TrackDelay]" value="<?php echo validHtmlStr($monitor->TrackDelay) ?>" size="4"/></td></tr> <tr><td><?php echo translate('TrackDelay') ?></td><td><input type="text" name="newMonitor[TrackDelay]" value="<?php echo validHtmlStr($newMonitor['TrackDelay']) ?>" size="4"/></td></tr>
<tr><td><?php echo translate('ReturnLocation') ?></td><td><?php echo htmlSelect( "newMonitor[ReturnLocation]", $return_options, $monitor->ReturnLocation() ); ?></td></tr> <tr><td><?php echo translate('ReturnLocation') ?></td><td><?php echo buildSelect( "newMonitor[ReturnLocation]", $return_options ); ?></td></tr>
<tr><td><?php echo translate('ReturnDelay') ?></td><td><input type="text" name="newMonitor[ReturnDelay]" value="<?php echo validHtmlStr($monitor->ReturnDelay) ?>" size="4"/></td></tr> <tr><td><?php echo translate('ReturnDelay') ?></td><td><input type="text" name="newMonitor[ReturnDelay]" value="<?php echo validHtmlStr($newMonitor['ReturnDelay']) ?>" size="4"/></td></tr>
<?php <?php
break; break;
} }
case 'x10' : case 'x10' :
{ {
?> ?>
<tr><td><?php echo translate('X10ActivationString') ?></td><td><input type="text" name="newX10Monitor[Activation]" value="<?php echo validHtmlStr($newX10Monitor['Activation']) ?>" size="20"/></td></tr> <tr><td><?php echo translate('X10ActivationString') ?></td><td><input type="text" name="newX10Monitor[Activation]" value="<?php echo validHtmlStr($newX10Monitor['Activation']) ?>" size="20"/></td></tr>
<tr><td><?php echo translate('X10InputAlarmString') ?></td><td><input type="text" name="newX10Monitor[AlarmInput]" value="<?php echo validHtmlStr($newX10Monitor['AlarmInput']) ?>" size="20"/></td></tr> <tr><td><?php echo translate('X10InputAlarmString') ?></td><td><input type="text" name="newX10Monitor[AlarmInput]" value="<?php echo validHtmlStr($newX10Monitor['AlarmInput']) ?>" size="20"/></td></tr>
<tr><td><?php echo translate('X10OutputAlarmString') ?></td><td><input type="text" name="newX10Monitor[AlarmOutput]" value="<?php echo validHtmlStr($newX10Monitor['AlarmOutput']) ?>" size="20"/></td></tr> <tr><td><?php echo translate('X10OutputAlarmString') ?></td><td><input type="text" name="newX10Monitor[AlarmOutput]" value="<?php echo validHtmlStr($newX10Monitor['AlarmOutput']) ?>" size="20"/></td></tr>
<?php <?php
break; break;
} }
case 'misc' : case 'misc' :
{ {
@ -954,12 +996,13 @@ switch ( $tab ) {
<?php <?php
break; break;
} }
} } // end switch tab
?> ?>
</tbody> </tbody>
</table> </table>
<div id="contentButtons"> <div id="contentButtons">
<input type="submit" value="<?php echo translate('Save') ?>"<?php if ( !canEdit( 'Monitors' ) ) { ?> disabled="disabled"<?php } ?>/><input type="button" value="<?php echo translate('Cancel') ?>" onclick="closeWindow()"/> <input type="submit" value="<?php echo translate('Save') ?>"<?php if ( !canEdit( 'Monitors' ) ) { ?> disabled="disabled"<?php } ?>/>
<input type="button" value="<?php echo translate('Cancel') ?>" onclick="closeWindow()"/>
</div> </div>
</form> </form>