Merge branch 'master' of github.com:ZoneMinder/ZoneMinder
commit
02eb222f17
|
@ -37,8 +37,16 @@ env:
|
|||
- SMPFLAGS=-j4 OS=fedora DIST=29 DOCKER_REPO=knnniggett/packpack
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=trusty
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=xenial
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=bionic
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=disco
|
||||
- SMPFLAGS=-j4 OS=debian DIST=buster
|
||||
- SMPFLAGS=-j4 OS=debian DIST=stretch
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=trusty ARCH=i386
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=xenial ARCH=i386
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=bionic ARCH=i386
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=disco ARCH=i386
|
||||
- SMPFLAGS=-j4 OS=debian DIST=buster ARCH=i386
|
||||
- SMPFLAGS=-j4 OS=debian DIST=stretch ARCH=i386
|
||||
- SMPFLAGS=-j4 OS=raspbian DIST=stretch ARCH=armhf DOCKER_REPO=knnniggett/packpack
|
||||
|
||||
compiler:
|
||||
|
|
|
@ -31,7 +31,7 @@ Better methods exist today that do much of this for you. The current development
|
|||
|
||||
This is the recommended method to install ZoneMinder onto your system. ZoneMinder packages are maintained for the following distros:
|
||||
|
||||
- Ubuntu via [Iconnor's PPA](https://launchpad.net/~iconnor/+archive/ubuntu/zoneminder)
|
||||
- Ubuntu via [Iconnor's PPA](https://launchpad.net/~iconnor)
|
||||
- Debian from their [default repository](https://packages.debian.org/search?searchon=names&keywords=zoneminder)
|
||||
- RHEL/CentOS and clones via [RPM Fusion](http://rpmfusion.org)
|
||||
- Fedora via [RPM Fusion](http://rpmfusion.org)
|
||||
|
|
|
@ -293,6 +293,8 @@ CREATE TABLE `Filters` (
|
|||
`AutoDelete` tinyint(3) unsigned NOT NULL default '0',
|
||||
`AutoMove` tinyint(3) unsigned NOT NULL default '0',
|
||||
`AutoMoveTo` smallint(5) unsigned NOT NULL default 0,
|
||||
`AutoCopy` tinyint(3) unsigned NOT NULL default '0',
|
||||
`AutoCopyTo` smallint(5) unsigned NOT NULL default 0,
|
||||
`UpdateDiskSpace` tinyint(3) unsigned NOT NULL default '0',
|
||||
`Background` tinyint(1) unsigned NOT NULL default '0',
|
||||
`Concurrent` tinyint(1) unsigned NOT NULL default '0',
|
||||
|
@ -756,8 +758,18 @@ insert into Users VALUES (NULL,'admin','$2b$12$NHZsm6AM2f2LQVROriz79ul3D6DnmFiZC
|
|||
-- Add a sample filter to purge the oldest 100 events when the disk is 95% full
|
||||
--
|
||||
|
||||
insert into Filters values (NULL,'PurgeWhenFull','{"sort_field":"Id","terms":[{"val":0,"attr":"Archived","op":"="},{"cnj":"and","val":95,"attr":"DiskPercent","op":">="}],"limit":100,"sort_asc":1}',0/*AutoArchive*/,0/*AutoVideo*/,0/*AutoUpload*/,0/*AutoEmail*/,0/*AutoMessage*/,0/*AutoExecute*/,'',1/*AutoDelete*/,0/*AutoMove*/,0/*MoveTo*/,0/*UpdateDiskSpace*/,1/*Background*/,0/*Concurrent*/);
|
||||
insert into Filters values (NULL,'Update DiskSpace','{"terms":[{"attr":"DiskSpace","op":"IS","val":"NULL"}]}',0,0,0,0,0,0,'',0,0,0,1,1,0);
|
||||
insert into Filters values (NULL,'PurgeWhenFull','{"sort_field":"Id","terms":[{"val":0,"attr":"Archived","op":"="},{"cnj":"and","val":95,"attr":"DiskPercent","op":">="}],"limit":100,"sort_asc":1}',
|
||||
0/*AutoArchive*/,
|
||||
0/*AutoVideo*/,
|
||||
0/*AutoUpload*/,
|
||||
0/*AutoEmail*/,
|
||||
0/*AutoMessage*/,
|
||||
0/*AutoExecute*/,'',
|
||||
1/*AutoDelete*/,
|
||||
0/*AutoMove*/,0/*MoveTo*/,
|
||||
0/*AutoCopy*/,0/*CopyTo*/,
|
||||
0/*UpdateDiskSpace*/,1/*Background*/,0/*Concurrent*/);
|
||||
insert into Filters values (NULL,'Update DiskSpace','{"terms":[{"attr":"DiskSpace","op":"IS","val":"NULL"}]}',0,0,0,0,0,0,'',0,0,0,0,0,1,1,0);
|
||||
|
||||
--
|
||||
-- Add in some sample control protocol definitions
|
||||
|
|
|
@ -3,8 +3,8 @@ Ubuntu
|
|||
|
||||
.. contents::
|
||||
|
||||
Easy Way: Ubuntu 18.04
|
||||
----------------------
|
||||
Easy Way: Ubuntu 18.04 (Bionic)
|
||||
-------------------------------
|
||||
These instructions are for a brand new ubuntu 18.04 system which does not have ZM
|
||||
installed.
|
||||
|
||||
|
@ -15,6 +15,7 @@ achieve the same result by running:
|
|||
|
||||
::
|
||||
|
||||
sudo apt-get install tasksel
|
||||
sudo tasksel install lamp-server
|
||||
|
||||
During installation it will ask you to set up a master/root password for the MySQL.
|
||||
|
@ -39,19 +40,10 @@ guide you with a quick search.
|
|||
following a new release of ZoneMinder. To use this repository instead of the
|
||||
official Ubuntu repository, enter the following from the command line:
|
||||
|
||||
::
|
||||
|
||||
add-apt-repository ppa:iconnor/zoneminder
|
||||
|
||||
Please note that as of 1.32.0 We are creating a new PPA for each major version, as a means to prevent automatic upgrades from one major version to another. So instead of the above ppa line use the following:
|
||||
|
||||
::
|
||||
|
||||
add-apt-repository ppa:iconnor/zoneminder-1.32
|
||||
|
||||
If you are on Trusty or Xenial, you may want to add both, as there are some packages for dependencies included in the old ppa.
|
||||
|
||||
|
||||
Update repo and upgrade.
|
||||
|
||||
::
|
||||
|
@ -202,8 +194,8 @@ CTRL+x to exit
|
|||
|
||||
PPA install may need some tweaking of ZMS_PATH in ZoneMinder options. `Socket_sendto or no live streaming`_
|
||||
|
||||
Easy Way: Ubuntu 16.04
|
||||
----------------------
|
||||
Easy Way: Ubuntu 16.04 (Xenial)
|
||||
-------------------------------
|
||||
These instructions are for a brand new ubuntu 16.04 system which does not have ZM
|
||||
installed.
|
||||
|
||||
|
@ -241,16 +233,8 @@ guide you with a quick search.
|
|||
::
|
||||
|
||||
add-apt-repository ppa:iconnor/zoneminder
|
||||
|
||||
Please note that as of 1.32.0 We are creating a new PPA for each major version, as a means to prevent automatic upgrades from one major version to another. So instead of the above ppa line use the following:
|
||||
|
||||
::
|
||||
|
||||
add-apt-repository ppa:iconnor/zoneminder-1.32
|
||||
|
||||
If you are on Trusty or Xenial, you may want to add both, as there are some packages for dependencies included in the old ppa.
|
||||
|
||||
|
||||
Update repo and upgrade.
|
||||
|
||||
::
|
||||
|
@ -401,8 +385,8 @@ CTRL+x to exit
|
|||
|
||||
PPA install may need some tweaking of ZMS_PATH in ZoneMinder options. `Socket_sendto or no live streaming`_
|
||||
|
||||
Easy Way: Ubuntu 14.x
|
||||
---------------------
|
||||
Easy Way: Ubuntu 14.x (Trusty)
|
||||
------------------------------
|
||||
**These instructions are for a brand new ubuntu 14.x system which does not have ZM installed.**
|
||||
|
||||
**Step 1:** Either run commands in this install using sudo or use the below to become root
|
||||
|
|
|
@ -56,7 +56,8 @@ use ZoneMinder::Config qw(:all);
|
|||
use ZoneMinder::Logger qw(:all);
|
||||
use ZoneMinder::Database qw(:all);
|
||||
|
||||
use vars qw/ $table $primary_key %fields $serial @identified_by %defaults/;
|
||||
use vars qw/ $table $primary_key %fields $serial @identified_by %defaults $debug/;
|
||||
$debug = 0;
|
||||
$table = 'Events';
|
||||
@identified_by = ('Id');
|
||||
$serial = $primary_key = 'Id';
|
||||
|
@ -133,7 +134,11 @@ sub Path {
|
|||
|
||||
if ( ! $$event{Path} ) {
|
||||
my $Storage = $event->Storage();
|
||||
$$event{Path} = join('/', $Storage->Path(), $event->RelativePath());
|
||||
if ( defined $Storage->Id() ) {
|
||||
$$event{Path} = join('/', $Storage->Path(), $event->RelativePath());
|
||||
} else {
|
||||
Error("Storage area for $$event{StorageId} no longer exists in db.");
|
||||
}
|
||||
}
|
||||
return $$event{Path};
|
||||
}
|
||||
|
@ -365,7 +370,7 @@ sub delete {
|
|||
|
||||
if ( $$event{Id} ) {
|
||||
# Need to have an event Id if we are to delete from the db.
|
||||
Info("Deleting event $event->{Id} from Monitor $event->{MonitorId} StartTime:$event->{StartTime}");
|
||||
Info("Deleting event $event->{Id} from Monitor $event->{MonitorId} StartTime:$event->{StartTime} from ".$event->Path());
|
||||
$ZoneMinder::Database::dbh->ping();
|
||||
|
||||
$ZoneMinder::Database::dbh->begin_work();
|
||||
|
@ -421,20 +426,24 @@ sub delete_files {
|
|||
|
||||
my $deleted = 0;
|
||||
if ( $$Storage{Type} and ( $$Storage{Type} eq 's3fs' ) ) {
|
||||
my ( $aws_id, $aws_secret, $aws_host, $aws_bucket ) = ( $$Storage{Url} =~ /^\s*([^:]+):([^@]+)@([^\/]*)\/(.+)\s*$/ );
|
||||
my $url = $$Storage{Url};
|
||||
$url =~ s/^(s3|s3fs):\/\///ig;
|
||||
my ( $aws_id, $aws_secret, $aws_host, $aws_bucket, $subpath ) = ( $url =~ /^\s*([^:]+):([^@]+)@([^\/]*)\/([^\/]+)(\/.+)?\s*$/ );
|
||||
Debug("S3 url parsed to id:$aws_id secret:$aws_secret host:$aws_host, bucket:$aws_bucket, subpath:$subpath\n from $url");
|
||||
eval {
|
||||
require Net::Amazon::S3;
|
||||
my $s3 = Net::Amazon::S3->new( {
|
||||
aws_access_key_id => $aws_id,
|
||||
aws_secret_access_key => $aws_secret,
|
||||
( $aws_host ? ( host => $aws_host ) : () ),
|
||||
authorization_method => 'Net::Amazon::S3::Signature::V4',
|
||||
});
|
||||
my $bucket = $s3->bucket($aws_bucket);
|
||||
if ( ! $bucket ) {
|
||||
Error("S3 bucket $bucket not found.");
|
||||
die;
|
||||
}
|
||||
if ( $bucket->delete_key($event_path) ) {
|
||||
if ( $bucket->delete_key($subpath.$event_path) ) {
|
||||
$deleted = 1;
|
||||
} else {
|
||||
Error('Failed to delete from S3:'.$s3->err . ': ' . $s3->errstr);
|
||||
|
@ -464,7 +473,7 @@ sub StorageId {
|
|||
if ( @_ ) {
|
||||
$$event{StorageId} = shift;
|
||||
delete $$event{Storage};
|
||||
delete $$event{Path};
|
||||
$event->Path(undef);
|
||||
}
|
||||
return $$event{StorageId};
|
||||
}
|
||||
|
@ -474,7 +483,7 @@ sub Storage {
|
|||
$_[0]{Storage} = $_[1];
|
||||
if ( $_[0]{Storage} ) {
|
||||
$_[0]{StorageId} = $_[0]{Storage}->Id();
|
||||
delete $_[0]{Path};
|
||||
$_[0]->Path(undef);
|
||||
}
|
||||
}
|
||||
if ( ! $_[0]{Storage} ) {
|
||||
|
@ -534,7 +543,7 @@ sub CopyTo {
|
|||
my $OldStorage = $self->Storage(undef);
|
||||
my ( $OldPath ) = ( $self->Path() =~ /^(.*)$/ ); # De-taint
|
||||
if ( ! -e $OldPath ) {
|
||||
return "Old path $OldPath does not exist.";
|
||||
return "Src path $OldPath does not exist.";
|
||||
}
|
||||
# First determine if we can move it to the dest.
|
||||
# We do this before bothering to lock the event
|
||||
|
@ -545,8 +554,12 @@ sub CopyTo {
|
|||
return 'Event is already located at ' . $NewPath;
|
||||
} elsif ( !$NewPath ) {
|
||||
return "New path ($NewPath) is empty.";
|
||||
} elsif ( ! -e $NewPath ) {
|
||||
return "New path $NewPath does not exist.";
|
||||
} elsif ( ($$NewStorage{Type} ne 's3fs' ) and ! -e $NewPath ) {
|
||||
if ( ! mkdir($NewPath) ) {
|
||||
return "New path $NewPath does not exist.";
|
||||
}
|
||||
} else {
|
||||
Debug("$NewPath is good");
|
||||
}
|
||||
|
||||
$ZoneMinder::Database::dbh->begin_work();
|
||||
|
@ -562,8 +575,9 @@ sub CopyTo {
|
|||
return 'Old Storage path changed, Event has moved somewhere else.';
|
||||
}
|
||||
|
||||
$NewPath .= $self->Relative_Path();
|
||||
$NewPath = ( $NewPath =~ /^(.*)$/ ); # De-taint
|
||||
Debug("Relative Path: " . $self->RelativePath());
|
||||
$NewPath .= '/'.$self->RelativePath();
|
||||
($NewPath) = ( $NewPath =~ /^(.*)$/ ); # De-taint
|
||||
if ( $NewPath eq $OldPath ) {
|
||||
$ZoneMinder::Database::dbh->commit();
|
||||
return "New path and old path are the same! $NewPath";
|
||||
|
@ -574,7 +588,10 @@ sub CopyTo {
|
|||
|
||||
if ( $$NewStorage{Type} eq 's3fs' ) {
|
||||
if ( $$NewStorage{Url} ) {
|
||||
my ( $aws_id, $aws_secret, $aws_host, $aws_bucket ) = ( $$NewStorage{Url} =~ /^\s*([^:]+):([^@]+)@([^\/]*)\/(.+)\s*$/ );
|
||||
my $url = $$NewStorage{Url};
|
||||
$url =~ s/^(s3|s3fs):\/\///ig;
|
||||
my ( $aws_id, $aws_secret, $aws_host, $aws_bucket, $subpath ) = ( $url =~ /^\s*([^:]+):([^@]+)@([^\/]*)\/([^\/]+)(\/.+)?\s*$/ );
|
||||
Debug("S3 url parsed to id:$aws_id secret:$aws_secret host:$aws_host, bucket:$aws_bucket, subpath:$subpath\n from $url");
|
||||
if ( $aws_id and $aws_secret and $aws_host and $aws_bucket ) {
|
||||
eval {
|
||||
require Net::Amazon::S3;
|
||||
|
@ -583,6 +600,7 @@ sub CopyTo {
|
|||
aws_access_key_id => $aws_id,
|
||||
aws_secret_access_key => $aws_secret,
|
||||
( $aws_host ? ( host => $aws_host ) : () ),
|
||||
authorization_method => 'Net::Amazon::S3::Signature::V4',
|
||||
});
|
||||
my $bucket = $s3->bucket($aws_bucket);
|
||||
if ( !$bucket ) {
|
||||
|
@ -590,10 +608,12 @@ sub CopyTo {
|
|||
die;
|
||||
}
|
||||
|
||||
my $event_path = $self->RelativePath();
|
||||
Debug("Making directory $event_path/");
|
||||
if ( ! $bucket->add_key($event_path.'/', '') ) {
|
||||
die "Unable to add key for $event_path/";
|
||||
my $event_path = $subpath.$self->RelativePath();
|
||||
if ( 0 ) { # Not neccessary
|
||||
Debug("Making directory $event_path/");
|
||||
if ( !$bucket->add_key($event_path.'/', '') ) {
|
||||
Warning("Unable to add key for $event_path/ :". $s3->err . ': '. $s3->errstr());
|
||||
}
|
||||
}
|
||||
|
||||
my @files = glob("$OldPath/*");
|
||||
|
@ -607,15 +627,23 @@ sub CopyTo {
|
|||
if ( ! $size ) {
|
||||
Info('Not moving file with 0 size');
|
||||
}
|
||||
my $file_contents = File::Slurp::read_file($file);
|
||||
if ( ! $file_contents ) {
|
||||
die 'Loaded empty file, but it had a size. Giving up';
|
||||
if ( 0 ) {
|
||||
my $file_contents = File::Slurp::read_file($file);
|
||||
if ( ! $file_contents ) {
|
||||
die 'Loaded empty file, but it had a size. Giving up';
|
||||
}
|
||||
|
||||
my $filename = $event_path.'/'.File::Basename::basename($file);
|
||||
if ( ! $bucket->add_key($filename, $file_contents) ) {
|
||||
die "Unable to add key for $filename : ".$s3->err . ': ' . $s3->errstr;
|
||||
}
|
||||
} else {
|
||||
my $filename = $event_path.'/'.File::Basename::basename($file);
|
||||
if ( ! $bucket->add_key_filename($filename, $file) ) {
|
||||
die "Unable to add key for $filename " . $s3->err . ': '. $s3->errstr;
|
||||
}
|
||||
}
|
||||
|
||||
my $filename = $event_path.'/'.File::Basename::basename($file);
|
||||
if ( ! $bucket->add_key($filename, $file_contents) ) {
|
||||
die "Unable to add key for $filename";
|
||||
}
|
||||
my $duration = tv_interval($starttime);
|
||||
Debug('PUT to S3 ' . Number::Bytes::Human::format_bytes($size) . " in $duration seconds = " . Number::Bytes::Human::format_bytes($duration?$size/$duration:$size) . '/sec');
|
||||
} # end foreach file.
|
||||
|
@ -782,6 +810,33 @@ sub recover_timestamps {
|
|||
}
|
||||
}
|
||||
|
||||
sub files {
|
||||
my $self = shift;
|
||||
|
||||
if ( ! $$self{files} ) {
|
||||
if ( ! opendir(DIR, $self->Path() ) ) {
|
||||
Error("Can't open directory '$$self{Path}': $!");
|
||||
return;
|
||||
}
|
||||
@{$$self{files}} = readdir(DIR);
|
||||
Debug('Have ' . @{$$self{files}} . " files in $$self{Path}");
|
||||
closedir(DIR);
|
||||
}
|
||||
return @{$$self{files}};
|
||||
}
|
||||
|
||||
sub has_capture_jpegs {
|
||||
@{$_[0]{capture_jpegs}} = grep(/^\d+\-capture\.jpg$/, $_[0]->files());
|
||||
Debug("have " . @{$_[0]{capture_jpegs}} . " capture jpegs");
|
||||
return @{$_[0]{capture_jpegs}} ? 1 : 0;
|
||||
}
|
||||
|
||||
sub has_analyse_jpegs {
|
||||
@{$_[0]{analyse_jpegs}} = grep(/^\d+\-analyse\.jpg$/, $_[0]->files());
|
||||
Debug("have " . @{$_[0]{analyse_jpegs}} . " analyse jpegs");
|
||||
return @{$_[0]{analyse_jpegs}} ? 1 : 0;
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
||||
|
|
|
@ -95,32 +95,32 @@ sub new {
|
|||
sub load {
|
||||
my ( $self, $data ) = @_;
|
||||
my $type = ref $self;
|
||||
if ( ! $data ) {
|
||||
if ( !$data ) {
|
||||
no strict 'refs';
|
||||
my $table = ${$type.'::table'};
|
||||
if ( ! $table ) {
|
||||
Error( 'NO table for type ' . $type );
|
||||
Error('No table for type '.$type);
|
||||
return;
|
||||
} # end if
|
||||
my $primary_key = ${$type.'::primary_key'};
|
||||
if ( ! $primary_key ) {
|
||||
Error( 'NO primary_key for type ' . $type );
|
||||
if ( !$primary_key ) {
|
||||
Error('No primary_key for type '.$type);
|
||||
return;
|
||||
} # end if
|
||||
|
||||
if ( ! $$self{$primary_key} ) {
|
||||
my ( $caller, undef, $line ) = caller;
|
||||
Error( (ref $self) . "::load called without $primary_key from $caller:$line");
|
||||
Error("$type ::load called without $primary_key from $caller:$line");
|
||||
} else {
|
||||
#$log->debug("Object::load Loading from db $type");
|
||||
Debug("Loading $type from $table WHERE $primary_key = $$self{$primary_key}");
|
||||
$data = $ZoneMinder::Database::dbh->selectrow_hashref( "SELECT * FROM $table WHERE $primary_key=?", {}, $$self{$primary_key} );
|
||||
if ( ! $data ) {
|
||||
$data = $ZoneMinder::Database::dbh->selectrow_hashref("SELECT * FROM `$table` WHERE `$primary_key`=?", {}, $$self{$primary_key});
|
||||
if ( !$data ) {
|
||||
if ( $ZoneMinder::Database::dbh->errstr ) {
|
||||
Error( "Failure to load Object record for $$self{$primary_key}: Reason: " . $ZoneMinder::Database::dbh->errstr );
|
||||
} else {
|
||||
Debug("No Results Loading $type from $table WHERE $primary_key = $$self{$primary_key}");
|
||||
} # end if
|
||||
delete $$self{$primary_key};
|
||||
} # end if
|
||||
} # end if
|
||||
} # end if ! $data
|
||||
|
@ -137,26 +137,26 @@ sub lock_and_load {
|
|||
no strict 'refs';
|
||||
my $table = ${$type.'::table'};
|
||||
if ( ! $table ) {
|
||||
Error('NO table for type ' . $type);
|
||||
Error('NO table for type '.$type);
|
||||
return;
|
||||
} # end if
|
||||
my $primary_key = ${$type.'::primary_key'};
|
||||
if ( ! $primary_key ) {
|
||||
Error('NO primary_key for type ' . $type);
|
||||
if ( !$primary_key ) {
|
||||
Error('No primary_key for type ' . $type);
|
||||
return;
|
||||
} # end if
|
||||
|
||||
if ( ! $$self{$primary_key} ) {
|
||||
if ( !$$self{$primary_key} ) {
|
||||
my ( $caller, undef, $line ) = caller;
|
||||
Error("$type ::lock_and_load called without $primary_key from $caller:$line");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug("Lock and Load $type from $table WHERE $primary_key = $$self{$primary_key}");
|
||||
my $data = $ZoneMinder::Database::dbh->selectrow_hashref("SELECT * FROM $table WHERE $primary_key=? FOR UPDATE", {}, $$self{$primary_key});
|
||||
my $data = $ZoneMinder::Database::dbh->selectrow_hashref("SELECT * FROM `$table` WHERE `$primary_key`=? FOR UPDATE", {}, $$self{$primary_key});
|
||||
if ( ! $data ) {
|
||||
if ( $ZoneMinder::Database::dbh->errstr ) {
|
||||
Error("Failure to load Object record for $$self{$primary_key}: Reason: " . $ZoneMinder::Database::dbh->errstr);
|
||||
Error("Failure to load Object record for $$self{$primary_key}: Reason: ".$ZoneMinder::Database::dbh->errstr);
|
||||
} else {
|
||||
Debug("No Results Lock and Loading $type from $table WHERE $primary_key = $$self{$primary_key}");
|
||||
} # end if
|
||||
|
@ -216,12 +216,12 @@ sub save {
|
|||
$log->debug("No serial") if $debug;
|
||||
# No serial columns defined, which means that we will do saving by delete/insert instead of insert/update
|
||||
if ( @identified_by ) {
|
||||
my $where = join(' AND ', map { $$fields{$_}.'=?' } @identified_by );
|
||||
my $where = join(' AND ', map { '`'.$$fields{$_}.'`=?' } @identified_by );
|
||||
if ( $debug ) {
|
||||
$log->debug("DELETE FROM $table WHERE $where");
|
||||
$log->debug("DELETE FROM `$table` WHERE $where");
|
||||
} # end if
|
||||
|
||||
if ( ! ( ( $_ = $local_dbh->prepare("DELETE FROM $table WHERE $where") ) and $_->execute( @$self{@identified_by} ) ) ) {
|
||||
if ( ! ( ( $_ = $local_dbh->prepare("DELETE FROM `$table` WHERE $where") ) and $_->execute( @$self{@identified_by} ) ) ) {
|
||||
$where =~ s/\?/\%s/g;
|
||||
$log->error("Error deleting: DELETE FROM $table WHERE " . sprintf($where, map { defined $_ ? $_ : 'undef' } ( @$self{@identified_by}) ).'):' . $local_dbh->errstr);
|
||||
$local_dbh->rollback();
|
||||
|
@ -240,7 +240,7 @@ $log->debug("No serial") if $debug;
|
|||
next;
|
||||
}
|
||||
if ( ! $$self{$id} ) {
|
||||
my $s = qq{SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES WHERE table_name = '$table'};
|
||||
my $s = qq{SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES WHERE `table_name` = '$table'};
|
||||
|
||||
($$self{$id}) = ($sql{$$fields{$id}}) = $local_dbh->selectrow_array( $s );
|
||||
#($$self{$id}) = ($sql{$$fields{$id}}) = $local_dbh->selectrow_array( q{SELECT nextval('} . $serial{$id} . q{')} );
|
||||
|
@ -252,7 +252,7 @@ $log->debug("No serial") if $debug;
|
|||
|
||||
if ( $insert ) {
|
||||
my @keys = keys %sql;
|
||||
my $command = "INSERT INTO $table (" . join(',', @keys ) . ') VALUES (' . join(',', map { '?' } @sql{@keys} ) . ')';
|
||||
my $command = "INSERT INTO `$table` (" . join(',', @keys ) . ') VALUES (' . join(',', map { '?' } @sql{@keys} ) . ')';
|
||||
if ( ! ( ( $_ = $local_dbh->prepare($command) ) and $_->execute( @sql{@keys} ) ) ) {
|
||||
my $error = $local_dbh->errstr;
|
||||
$command =~ s/\?/\%s/g;
|
||||
|
@ -267,7 +267,7 @@ $log->debug("No serial") if $debug;
|
|||
} # end if
|
||||
} else {
|
||||
my @keys = keys %sql;
|
||||
my $command = "UPDATE $table SET " . join(',', map { $_ . ' = ?' } @keys ) . ' WHERE ' . join(' AND ', map { $_ . ' = ?' } @$fields{@identified_by} );
|
||||
my $command = "UPDATE `$table` SET " . join(',', map { '`'.$_ . '` = ?' } @keys ) . ' WHERE ' . join(' AND ', map { '`'.$_ . '` = ?' } @$fields{@identified_by} );
|
||||
if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys,@$fields{@identified_by}} ) ) ) {
|
||||
my $error = $local_dbh->errstr;
|
||||
$command =~ s/\?/\%s/g;
|
||||
|
@ -293,12 +293,12 @@ $log->debug("No serial") if $debug;
|
|||
if ( $need_serial ) {
|
||||
if ( $serial ) {
|
||||
$log->debug("Getting auto_increments");
|
||||
my $s = qq{SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES WHERE table_name = '$table'};
|
||||
my $s = qq{SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES WHERE `table_name` = '$table'};
|
||||
@$self{@identified_by} = @sql{@$fields{@identified_by}} = $local_dbh->selectrow_array( $s );
|
||||
#@$self{@identified_by} = @sql{@$fields{@identified_by}} = $local_dbh->selectrow_array( q{SELECT nextval('} . $serial . q{')} );
|
||||
if ( $local_dbh->errstr() ) {
|
||||
$log->error("Error getting next id. " . $local_dbh->errstr() );
|
||||
$log->error("SQL statement execution $s returned ".join(',',@$self{@identified_by}));
|
||||
$log->error("Error getting next id. " . $local_dbh->errstr() ."\n".
|
||||
"SQL statement execution $s returned ".join(',',@$self{@identified_by}));
|
||||
} elsif ( $debug or DEBUG_ALL ) {
|
||||
$log->debug("SQL statement execution $s returned ".join(',',@$self{@identified_by}));
|
||||
} # end if
|
||||
|
@ -306,7 +306,7 @@ $log->debug("No serial") if $debug;
|
|||
} # end if
|
||||
|
||||
my @keys = keys %sql;
|
||||
my $command = "INSERT INTO $table (" . join(',', @keys ) . ') VALUES (' . join(',', map { '?' } @sql{@keys} ) . ')';
|
||||
my $command = "INSERT INTO `$table` (" . join(',', map { '`'.$_.'`' } @keys ) . ') VALUES (' . join(',', map { '?' } @sql{@keys} ) . ')';
|
||||
if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys} ) ) ) {
|
||||
$command =~ s/\?/\%s/g;
|
||||
my $error = $local_dbh->errstr;
|
||||
|
@ -325,7 +325,7 @@ $log->debug("No serial") if $debug;
|
|||
my %identified_by = map { $_, $_ } @identified_by;
|
||||
|
||||
@keys = map { $identified_by{$_} ? () : $$fields{$_} } @keys;
|
||||
my $command = "UPDATE $table SET " . join(',', map { $_ . ' = ?' } @keys ) . ' WHERE ' . join(' AND ', map { $$fields{$_} .'= ?' } @identified_by );
|
||||
my $command = "UPDATE `$table` SET " . join(',', map { '`'.$_ . '` = ?' } @keys ) . ' WHERE ' . join(' AND ', map { '`'.$$fields{$_} .'`= ?' } @identified_by );
|
||||
if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys}, @sql{@$fields{@identified_by}} ) ) ) {
|
||||
my $error = $local_dbh->errstr;
|
||||
$command =~ s/\?/\%s/g;
|
||||
|
|
|
@ -201,12 +201,12 @@ MAIN: while( $loop ) {
|
|||
|
||||
my %Monitors;
|
||||
my $db_monitors;
|
||||
my $monitorSelectSql = $monitor_id ? 'SELECT * FROM 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 )
|
||||
or Fatal( "Can't prepare '$monitorSelectSql': ".$dbh->errstr() );
|
||||
|
||||
my $eventSelectSql = 'SELECT Id, (unix_timestamp() - unix_timestamp(StartTime)) AS Age
|
||||
FROM Events WHERE MonitorId = ?'.(@Storage_Areas ? ' AND StorageId IN ('.join(',',map { '?'} @Storage_Areas).')' : '' ). ' ORDER BY Id';
|
||||
my $eventSelectSql = 'SELECT `Id`, (unix_timestamp() - unix_timestamp(`StartTime`)) AS Age
|
||||
FROM `Events` WHERE `MonitorId` = ?'.(@Storage_Areas ? ' AND `StorageId` IN ('.join(',',map { '?'} @Storage_Areas).')' : '' ). ' ORDER BY `Id`';
|
||||
my $eventSelectSth = $dbh->prepare_cached( $eventSelectSql )
|
||||
or Fatal( "Can't prepare '$eventSelectSql': ".$dbh->errstr() );
|
||||
|
||||
|
@ -222,7 +222,7 @@ MAIN: while( $loop ) {
|
|||
while ( my $event = $eventSelectSth->fetchrow_hashref() ) {
|
||||
$db_events->{$event->{Id}} = $event->{Age};
|
||||
}
|
||||
Debug( 'Got '.int(keys(%$db_events))." events for monitor $monitor->{Id}" );
|
||||
Debug('Got '.int(keys(%$db_events))." events for monitor $monitor->{Id} using $eventSelectSql");
|
||||
} # end while monitors
|
||||
|
||||
my $fs_monitors;
|
||||
|
@ -245,7 +245,7 @@ MAIN: while( $loop ) {
|
|||
next;
|
||||
}
|
||||
|
||||
Debug( "Found filesystem monitor '$monitor'" );
|
||||
Debug("Found filesystem monitor '$monitor'");
|
||||
$fs_monitors->{$monitor} = {} if ! $fs_monitors->{$monitor};
|
||||
my $fs_events = $fs_monitors->{$monitor};
|
||||
|
||||
|
@ -256,19 +256,19 @@ MAIN: while( $loop ) {
|
|||
my @day_dirs = glob("$monitor_dir/[0-9][0-9]/[0-9][0-9]/[0-9][0-9]");
|
||||
Debug(qq`Checking for Deep Events under $$Storage{Path} using glob("$monitor_dir/[0-9][0-9]/[0-9][0-9]/[0-9][0-9]") returned `. scalar @day_dirs . ' events');
|
||||
foreach my $day_dir ( @day_dirs ) {
|
||||
Debug( "Checking day dir $day_dir" );
|
||||
Debug("Checking day dir $day_dir");
|
||||
( $day_dir ) = ( $day_dir =~ /^(.*)$/ ); # De-taint
|
||||
if ( !chdir($day_dir) ) {
|
||||
Error("Can't chdir to '$$Storage{Path}/$day_dir': $!");
|
||||
next;
|
||||
}
|
||||
if ( ! opendir(DIR, '.') ) {
|
||||
if ( !opendir(DIR, '.') ) {
|
||||
Error("Can't open directory '$$Storage{Path}/$day_dir': $!");
|
||||
next;
|
||||
}
|
||||
my %event_ids_by_path;
|
||||
|
||||
my @event_links = sort { $b <=> $a } grep { -l $_ } readdir( DIR );
|
||||
my @event_links = sort { $b <=> $a } grep { -l $_ } readdir(DIR);
|
||||
Debug("Have " . @event_links . ' event links');
|
||||
closedir(DIR);
|
||||
|
||||
|
@ -280,9 +280,9 @@ MAIN: while( $loop ) {
|
|||
Warning("Non-event link found $event_link in $day_dir, skipping");
|
||||
next;
|
||||
}
|
||||
Debug("Checking link $event_link");
|
||||
#Event path is hour/minute/sec
|
||||
my $event_path = readlink($event_link);
|
||||
Debug("Checking link $event_link points to: $event_path");
|
||||
|
||||
if ( !($event_path and -e $event_path) ) {
|
||||
aud_print("Event link $day_dir/$event_link does not point to valid target at $event_path");
|
||||
|
@ -294,15 +294,50 @@ MAIN: while( $loop ) {
|
|||
} else {
|
||||
$event_ids_by_path{$event_path} = $event_id;
|
||||
|
||||
Debug("Checking link $event_link points to $event_path ");
|
||||
my $Event = $fs_events->{$event_id} = new ZoneMinder::Event();
|
||||
$$Event{Id} = $event_id;
|
||||
$$Event{Path} = join('/', $Storage->Path(), $day_dir, $event_path);
|
||||
$$Event{RelativePath} = join('/', $day_dir, $event_path);
|
||||
$$Event{Scheme} = 'Deep';
|
||||
$Event->MonitorId( $monitor_dir );
|
||||
$Event->StorageId( $Storage->Id() );
|
||||
$Event->DiskSpace( undef );
|
||||
my $Event = $fs_events->{$event_id} = ZoneMinder::Event->find_one(Id=>$event_id);
|
||||
if ( ! $Event ) {
|
||||
$Event = $fs_events->{$event_id} = new ZoneMinder::Event();
|
||||
$$Event{Id} = $event_id;
|
||||
$$Event{Path} = join('/', $Storage->Path(), $day_dir, $event_path);
|
||||
$$Event{RelativePath} = join('/', $day_dir, $event_path);
|
||||
$$Event{Scheme} = 'Deep';
|
||||
$Event->MonitorId( $monitor_dir );
|
||||
$Event->StorageId( $Storage->Id() );
|
||||
$Event->DiskSpace( undef );
|
||||
} else {
|
||||
my $full_path = join('/', $Storage->Path(), $day_dir, $event_path);
|
||||
# Check storage id
|
||||
if ( !$Event->Storage()->Id() ) {
|
||||
Info("Correcting StorageId for event $$Event{Id} from $$Event{StorageId} $$Event{Path} to $$Storage{Id} $full_path");
|
||||
$Event->save({ StorageId=>$Storage->Id() });
|
||||
$Event->Path(undef);
|
||||
} else {
|
||||
|
||||
if ( $Event->Path() ne $full_path ) {
|
||||
if ( ! (-e $Event->Path()) ) {
|
||||
if ( $Event->StorageId() != $Storage->Id() ) {
|
||||
Info("Correcting Storge Id for event $$Event{Id} from $$Event{StorageId} $$Event{Path} to $$Storage{Id} $full_path");
|
||||
$Event->save({ StorageId=>$Storage->Id() });
|
||||
$Event->Path(undef);
|
||||
}
|
||||
} else {
|
||||
Info("Not updating path to event due to it existing at both $$Event{Path} and $event_path");
|
||||
}
|
||||
} # end if change of storage id
|
||||
} # end if valid storage id
|
||||
} # end if event found
|
||||
|
||||
if ( ! $Event->SaveJPEGs() ) {
|
||||
my $saveJPegs = ( $Event->has_capture_jpegs() ? 1 : 0 ) | ( $Event->has_analyse_jpegs() ? 2 : 0 );
|
||||
|
||||
if ( $Event->SaveJPEGs(
|
||||
( $Event->has_capture_jpegs() ? 1 : 0 ) | ( $Event->has_analyse_jpegs() ? 2 : 0 )
|
||||
) ) {
|
||||
Info("Updated Event $$Event{Id} SaveJPEGs to " . $Event->SaveJPEGs());
|
||||
$Event->save();
|
||||
}
|
||||
}
|
||||
|
||||
} # event path exists
|
||||
} # end foreach event_link
|
||||
|
||||
|
@ -314,14 +349,11 @@ MAIN: while( $loop ) {
|
|||
( $event_dir ) = ( $event_dir =~ /^(.*)$/ ); # De-taint
|
||||
|
||||
my $event_id = undef;
|
||||
my $Event = new ZoneMinder::Event();
|
||||
$$Event{Path} = join('/', $Storage->Path(), $day_dir, $event_dir);
|
||||
|
||||
if ( ! opendir(DIR, $event_dir) ) {
|
||||
Error("Can't open directory '$$Storage{Path}/$day_dir': $!");
|
||||
next;
|
||||
}
|
||||
my @contents = readdir( DIR );
|
||||
my @contents = $Event->files();
|
||||
Debug("Have " . @contents . " files in $day_dir/$event_dir");
|
||||
closedir(DIR);
|
||||
|
||||
my @mp4_files = grep( /^\d+\-video.mp4$/, @contents);
|
||||
foreach my $mp4_file ( @mp4_files ) {
|
||||
|
@ -336,21 +368,23 @@ MAIN: while( $loop ) {
|
|||
if ( ! $event_id ) {
|
||||
# Look for .id file
|
||||
my @hidden_files = grep( /^\.\d+$/, @contents);
|
||||
Debug("Have " . @hidden_files . ' hidden files');
|
||||
Debug('Have ' . @hidden_files . ' hidden files');
|
||||
if ( @hidden_files ) {
|
||||
( $event_id ) = $hidden_files[0] =~ /^.(\d+)$/;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $event_id and ! $fs_events->{$event_id} ) {
|
||||
my $Event = $fs_events->{$event_id} = new ZoneMinder::Event();
|
||||
$fs_events->{$event_id} = $Event;
|
||||
$$Event{Id} = $event_id;
|
||||
$$Event{Path} = join('/', $Storage->Path(), $day_dir, $event_dir);
|
||||
$$Event{RelativePath} = join('/', $day_dir, $event_dir);
|
||||
$$Event{Scheme} = 'Deep';
|
||||
$Event->MonitorId( $monitor_dir );
|
||||
$Event->StorageId( $Storage->Id() );
|
||||
$Event->DiskSpace( undef );
|
||||
$Event->SaveJPEGs(
|
||||
( $Event->has_capture_jpegs() ? 1 : 0 ) | ( $Event->has_analyse_jpegs() ? 2 : 0 )
|
||||
);
|
||||
if ( ! $event_ids_by_path{$event_dir} ) {
|
||||
Warning("No event link found at ".$Event->LinkPath() ." for " . $Event->to_string());
|
||||
}
|
||||
|
@ -373,8 +407,7 @@ MAIN: while( $loop ) {
|
|||
}
|
||||
aud_print("Deleting event directories with no event id information at $day_dir/$event_dir");
|
||||
if ( confirm() ) {
|
||||
my $command = "rm -rf $event_dir";
|
||||
executeShellCommand( $command );
|
||||
executeShellCommand("rm -rf $event_dir");
|
||||
$cleaned = 1;
|
||||
}
|
||||
} # end if able to find id
|
||||
|
@ -399,12 +432,12 @@ MAIN: while( $loop ) {
|
|||
}
|
||||
my $Event = $fs_events->{$event_id} = new ZoneMinder::Event();
|
||||
$$Event{Id} = $event_id;
|
||||
$$Event{Path} = join('/', $Storage->Path(), $event_dir );
|
||||
Debug("Have event $$Event{Id} at $$Event{Path}");
|
||||
$$Event{Scheme} = 'Medium';
|
||||
$$Event{RelativePath} = $event_dir;
|
||||
$Event->MonitorId( $monitor_dir );
|
||||
$Event->StorageId( $Storage->Id() );
|
||||
$Event->Path();
|
||||
Debug("Have event $$Event{Id} at $$Event{Path}");
|
||||
$Event->StartTime( POSIX::strftime('%Y-%m-%d %H:%M:%S', gmtime(time_of_youngest_file($Event->Path())) ) );
|
||||
} # end foreach event
|
||||
}
|
||||
|
@ -476,11 +509,10 @@ MAIN: while( $loop ) {
|
|||
} # end if ! in db events
|
||||
} # end foreach fs event
|
||||
} else {
|
||||
aud_print( "Filesystem monitor '$monitor_id' in $$Storage{Path} does not exist in database" );
|
||||
aud_print("Filesystem monitor '$monitor_id' in $$Storage{Path} does not exist in database");
|
||||
|
||||
if ( confirm() ) {
|
||||
my $command = "rm -rf $monitor_id";
|
||||
executeShellCommand( $command );
|
||||
executeShellCommand("rm -rf $monitor_id");
|
||||
$cleaned = 1;
|
||||
}
|
||||
}
|
||||
|
@ -494,8 +526,7 @@ MAIN: while( $loop ) {
|
|||
aud_print("Filesystem monitor link '$link' does not point to valid monitor directory");
|
||||
if ( confirm() ) {
|
||||
( $link ) = ( $link =~ /^(.*)$/ ); # De-taint
|
||||
my $command = qq`rm "$link"`;
|
||||
executeShellCommand($command);
|
||||
executeShellCommand(qq`rm "$link"`);
|
||||
$cleaned = 1;
|
||||
}
|
||||
} # end foreach monitor link
|
||||
|
@ -508,17 +539,17 @@ MAIN: while( $loop ) {
|
|||
|
||||
$cleaned = 0;
|
||||
my $deleteMonitorSql = 'DELETE LOW_PRIORITY FROM Monitors WHERE Id = ?';
|
||||
my $deleteMonitorSth = $dbh->prepare_cached( $deleteMonitorSql )
|
||||
or Fatal( "Can't prepare '$deleteMonitorSql': ".$dbh->errstr() );
|
||||
my $deleteMonitorSth = $dbh->prepare_cached($deleteMonitorSql)
|
||||
or Fatal("Can't prepare '$deleteMonitorSql': ".$dbh->errstr());
|
||||
my $deleteEventSql = 'DELETE LOW_PRIORITY FROM Events WHERE Id = ?';
|
||||
my $deleteEventSth = $dbh->prepare_cached( $deleteEventSql )
|
||||
or Fatal( "Can't prepare '$deleteEventSql': ".$dbh->errstr() );
|
||||
or Fatal("Can't prepare '$deleteEventSql': ".$dbh->errstr());
|
||||
my $deleteFramesSql = 'DELETE LOW_PRIORITY FROM Frames WHERE EventId = ?';
|
||||
my $deleteFramesSth = $dbh->prepare_cached( $deleteFramesSql )
|
||||
or Fatal( "Can't prepare '$deleteFramesSql': ".$dbh->errstr() );
|
||||
or Fatal("Can't prepare '$deleteFramesSql': ".$dbh->errstr());
|
||||
my $deleteStatsSql = 'DELETE LOW_PRIORITY FROM Stats WHERE EventId = ?';
|
||||
my $deleteStatsSth = $dbh->prepare_cached( $deleteStatsSql )
|
||||
or Fatal( "Can't prepare '$deleteStatsSql': ".$dbh->errstr() );
|
||||
or Fatal("Can't prepare '$deleteStatsSql': ".$dbh->errstr());
|
||||
|
||||
# Foreach database monitor and it's list of events.
|
||||
while ( my ( $db_monitor, $db_events ) = each(%$db_monitors) ) {
|
||||
|
@ -631,21 +662,21 @@ if ( $level > 1 ) {
|
|||
# Shouldn't be possible anymore with FOREIGN KEYS in place
|
||||
$cleaned = 0;
|
||||
Debug("Checking for Orphaned Events");
|
||||
my $selectOrphanedEventsSql = 'SELECT Events.Id, Events.Name
|
||||
FROM Events LEFT JOIN Monitors ON (Events.MonitorId = Monitors.Id)
|
||||
WHERE isnull(Monitors.Id)';
|
||||
my $selectOrphanedEventsSql = 'SELECT `Events`.`Id`, `Events`.`Name`
|
||||
FROM `Events` LEFT JOIN `Monitors` ON (`Events`.`MonitorId` = `Monitors`.`Id`)
|
||||
WHERE isnull(`Monitors`.`Id`)';
|
||||
my $selectOrphanedEventsSth = $dbh->prepare_cached( $selectOrphanedEventsSql )
|
||||
or Error( "Can't prepare '$selectOrphanedEventsSql': ".$dbh->errstr() );
|
||||
or Error("Can't prepare '$selectOrphanedEventsSql': ".$dbh->errstr());
|
||||
$res = $selectOrphanedEventsSth->execute()
|
||||
or Error( "Can't execute: ".$selectOrphanedEventsSth->errstr() );
|
||||
or Error("Can't execute: ".$selectOrphanedEventsSth->errstr());
|
||||
|
||||
while( my $event = $selectOrphanedEventsSth->fetchrow_hashref() ) {
|
||||
aud_print( "Found orphaned event with no monitor '$event->{Id}'" );
|
||||
aud_print("Found orphaned event with no monitor '$event->{Id}'");
|
||||
if ( confirm() ) {
|
||||
if ( $res = $deleteEventSth->execute( $event->{Id} ) ) {
|
||||
if ( $res = $deleteEventSth->execute($event->{Id}) ) {
|
||||
$cleaned = 1;
|
||||
} else {
|
||||
Error( "Can't execute: ".$deleteEventSth->errstr() );
|
||||
Error("Can't execute: ".$deleteEventSth->errstr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -655,42 +686,42 @@ if ( $level > 1 ) {
|
|||
# Remove empty events (with no frames)
|
||||
$cleaned = 0;
|
||||
Debug("Checking for Events with no Frames");
|
||||
my $selectEmptyEventsSql = 'SELECT E.Id AS Id, E.StartTime, F.EventId FROM Events as E LEFT JOIN Frames as F ON (E.Id = F.EventId)
|
||||
WHERE isnull(F.EventId) AND now() - interval '.$Config{ZM_AUDIT_MIN_AGE}.' second > E.StartTime';
|
||||
my $selectEmptyEventsSql = 'SELECT `E`.`Id` AS `Id`, `E`.`StartTime`, `F`.`EventId` FROM `Events` AS E LEFT JOIN `Frames` AS F ON (`E`.`Id` = `F`.`EventId`)
|
||||
WHERE isnull(`F`.`EventId`) AND now() - interval '.$Config{ZM_AUDIT_MIN_AGE}.' second > `E`.`StartTime`';
|
||||
if ( my $selectEmptyEventsSth = $dbh->prepare_cached( $selectEmptyEventsSql ) ) {
|
||||
if ( $res = $selectEmptyEventsSth->execute() ) {
|
||||
while( my $event = $selectEmptyEventsSth->fetchrow_hashref() ) {
|
||||
aud_print( "Found empty event with no frame records '$event->{Id}' at $$event{StartTime}" );
|
||||
aud_print("Found empty event with no frame records '$event->{Id}' at $$event{StartTime}");
|
||||
if ( confirm() ) {
|
||||
if ( $res = $deleteEventSth->execute( $event->{Id} ) ) {
|
||||
if ( $res = $deleteEventSth->execute($event->{Id}) ) {
|
||||
$cleaned = 1;
|
||||
} else {
|
||||
Error( "Can't execute: ".$deleteEventSth->errstr() );
|
||||
Error("Can't execute: ".$deleteEventSth->errstr());
|
||||
}
|
||||
}
|
||||
} # end foreach row
|
||||
} else {
|
||||
Error( "Can't execute: ".$selectEmptyEventsSth->errstr() );
|
||||
Error("Can't execute: ".$selectEmptyEventsSth->errstr());
|
||||
}
|
||||
} else {
|
||||
Error( "Can't prepare '$selectEmptyEventsSql': ".$dbh->errstr() );
|
||||
Error("Can't prepare '$selectEmptyEventsSql': ".$dbh->errstr());
|
||||
}
|
||||
redo MAIN if $cleaned;
|
||||
|
||||
# Remove orphaned frame records
|
||||
$cleaned = 0;
|
||||
Debug("Checking for Orphaned Frames");
|
||||
my $selectOrphanedFramesSql = 'SELECT DISTINCT EventId FROM Frames
|
||||
WHERE (SELECT COUNT(*) FROM Events WHERE Events.Id=EventId)=0';
|
||||
Debug('Checking for Orphaned Frames');
|
||||
my $selectOrphanedFramesSql = 'SELECT DISTINCT `EventId` FROM `Frames`
|
||||
WHERE (SELECT COUNT(*) FROM `Events` WHERE `Events`.`Id`=`EventId`)=0';
|
||||
my $selectOrphanedFramesSth = $dbh->prepare_cached( $selectOrphanedFramesSql )
|
||||
or Fatal( "Can't prepare '$selectOrphanedFramesSql': ".$dbh->errstr() );
|
||||
or Fatal("Can't prepare '$selectOrphanedFramesSql': ".$dbh->errstr());
|
||||
$res = $selectOrphanedFramesSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectOrphanedFramesSth->errstr() );
|
||||
or Fatal("Can't execute: ".$selectOrphanedFramesSth->errstr());
|
||||
while( my $frame = $selectOrphanedFramesSth->fetchrow_hashref() ) {
|
||||
aud_print( "Found orphaned frame records for event '$frame->{EventId}'" );
|
||||
aud_print("Found orphaned frame records for event '$frame->{EventId}'");
|
||||
if ( confirm() ) {
|
||||
$res = $deleteFramesSth->execute( $frame->{EventId} )
|
||||
or Fatal( "Can't execute: ".$deleteFramesSth->errstr() );
|
||||
$res = $deleteFramesSth->execute($frame->{EventId})
|
||||
or Fatal("Can't execute: ".$deleteFramesSth->errstr());
|
||||
$cleaned = 1;
|
||||
}
|
||||
}
|
||||
|
@ -699,18 +730,18 @@ if ( $level > 1 ) {
|
|||
if ( $level > 1 ) {
|
||||
# Remove orphaned stats records
|
||||
$cleaned = 0;
|
||||
Debug("Checking for Orphaned Stats");
|
||||
my $selectOrphanedStatsSql = 'SELECT DISTINCT EventId FROM Stats
|
||||
WHERE EventId NOT IN (SELECT Id FROM Events)';
|
||||
Debug('Checking for Orphaned Stats');
|
||||
my $selectOrphanedStatsSql = 'SELECT DISTINCT `EventId` FROM `Stats`
|
||||
WHERE `EventId` NOT IN (SELECT `Id` FROM `Events`)';
|
||||
my $selectOrphanedStatsSth = $dbh->prepare_cached( $selectOrphanedStatsSql )
|
||||
or Fatal( "Can't prepare '$selectOrphanedStatsSql': ".$dbh->errstr() );
|
||||
or Fatal("Can't prepare '$selectOrphanedStatsSql': ".$dbh->errstr());
|
||||
$res = $selectOrphanedStatsSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectOrphanedStatsSth->errstr() );
|
||||
or Fatal("Can't execute: ".$selectOrphanedStatsSth->errstr());
|
||||
while( my $stat = $selectOrphanedStatsSth->fetchrow_hashref() ) {
|
||||
aud_print( "Found orphaned statistic records for event '$stat->{EventId}'" );
|
||||
aud_print("Found orphaned statistic records for event '$stat->{EventId}'");
|
||||
if ( confirm() ) {
|
||||
$res = $deleteStatsSth->execute( $stat->{EventId} )
|
||||
or Fatal( "Can't execute: ".$deleteStatsSth->errstr() );
|
||||
or Fatal("Can't execute: ".$deleteStatsSth->errstr());
|
||||
$cleaned = 1;
|
||||
}
|
||||
}
|
||||
|
@ -732,44 +763,44 @@ if ( $level > 1 ) {
|
|||
#WHERE isnull(E.Frames) or isnull(E.EndTime)
|
||||
#GROUP BY E.Id HAVING EndTime < (now() - interval ".$Config{ZM_AUDIT_MIN_AGE}.' second)'
|
||||
#;
|
||||
'SELECT *, unix_timestamp(StartTime) AS TimeStamp FROM Events WHERE EndTime IS NULL AND StartTime < (now() - interval '.$Config{ZM_AUDIT_MIN_AGE}.' second)';
|
||||
'SELECT *, unix_timestamp(`StartTime`) AS `TimeStamp` FROM `Events` WHERE `EndTime` IS NULL AND `StartTime` < (now() - interval '.$Config{ZM_AUDIT_MIN_AGE}.' second)';
|
||||
|
||||
my $selectFrameDataSql = '
|
||||
SELECT
|
||||
max(TimeStamp) as EndTime,
|
||||
unix_timestamp(max(TimeStamp)) AS EndTimeStamp,
|
||||
max(FrameId) as Frames,
|
||||
count(if(Score>0,1,NULL)) as AlarmFrames,
|
||||
sum(Score) as TotScore,
|
||||
max(Score) as MaxScore
|
||||
FROM Frames WHERE EventId=?';
|
||||
max(`TimeStamp`) AS `EndTime`,
|
||||
unix_timestamp(max(`TimeStamp`)) AS `EndTimeStamp`,
|
||||
max(`FrameId`) AS `Frames`,
|
||||
count(if(`Score`>0,1,NULL)) AS `AlarmFrames`,
|
||||
sum(`Score`) AS `TotScore`,
|
||||
max(`Score`) AS `MaxScore`
|
||||
FROM `Frames` WHERE `EventId`=?';
|
||||
my $selectFrameDataSth = $dbh->prepare_cached($selectFrameDataSql)
|
||||
or Fatal( "Can't prepare '$selectFrameDataSql': ".$dbh->errstr() );
|
||||
|
||||
my $selectUnclosedEventsSth = $dbh->prepare_cached( $selectUnclosedEventsSql )
|
||||
or Fatal( "Can't prepare '$selectUnclosedEventsSql': ".$dbh->errstr() );
|
||||
or Fatal("Can't prepare '$selectUnclosedEventsSql': ".$dbh->errstr());
|
||||
my $updateUnclosedEventsSql =
|
||||
"UPDATE low_priority Events
|
||||
SET Name = ?,
|
||||
EndTime = ?,
|
||||
Length = ?,
|
||||
Frames = ?,
|
||||
AlarmFrames = ?,
|
||||
TotScore = ?,
|
||||
AvgScore = ?,
|
||||
MaxScore = ?,
|
||||
Notes = concat_ws( ' ', Notes, ? )
|
||||
WHERE Id = ?"
|
||||
"UPDATE low_priority `Events`
|
||||
SET `Name` = ?,
|
||||
`EndTime` = ?,
|
||||
`Length` = ?,
|
||||
`Frames` = ?,
|
||||
`AlarmFrames` = ?,
|
||||
`TotScore` = ?,
|
||||
`AvgScore` = ?,
|
||||
`MaxScore` = ?,
|
||||
`Notes` = concat_ws( ' ', `Notes`, ? )
|
||||
WHERE `Id` = ?"
|
||||
;
|
||||
my $updateUnclosedEventsSth = $dbh->prepare_cached( $updateUnclosedEventsSql )
|
||||
or Fatal( "Can't prepare '$updateUnclosedEventsSql': ".$dbh->errstr() );
|
||||
or Fatal("Can't prepare '$updateUnclosedEventsSql': ".$dbh->errstr());
|
||||
$res = $selectUnclosedEventsSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectUnclosedEventsSth->errstr() );
|
||||
or Fatal("Can't execute: ".$selectUnclosedEventsSth->errstr());
|
||||
while( my $event = $selectUnclosedEventsSth->fetchrow_hashref() ) {
|
||||
aud_print( "Found open event '$event->{Id}' on Monitor $event->{MonitorId} at $$event{StartTime}" );
|
||||
if ( confirm( 'close', 'closing' ) ) {
|
||||
aud_print("Found open event '$event->{Id}' on Monitor $event->{MonitorId} at $$event{StartTime}");
|
||||
if ( confirm('close', 'closing') ) {
|
||||
if ( ! ( $res = $selectFrameDataSth->execute($event->{Id}) ) ) {
|
||||
Error( "Can't execute: $selectFrameDataSql:".$selectFrameDataSth->errstr() );
|
||||
Error("Can't execute: $selectFrameDataSql:".$selectFrameDataSth->errstr());
|
||||
next;
|
||||
}
|
||||
my $frame = $selectFrameDataSth->fetchrow_hashref();
|
||||
|
@ -802,7 +833,7 @@ FROM Frames WHERE EventId=?';
|
|||
|
||||
# Now delete any old image files
|
||||
if ( my @old_files = grep { -M > $max_image_age } <$image_path/*.{jpg,gif,wbmp}> ) {
|
||||
aud_print( 'Deleting '.int(@old_files)." old images\n" );
|
||||
aud_print('Deleting '.int(@old_files)." old images\n");
|
||||
my $untainted_old_files = join( ';', @old_files );
|
||||
( $untainted_old_files ) = ( $untainted_old_files =~ /^(.*)$/ );
|
||||
unlink( split( /;/, $untainted_old_files ) );
|
||||
|
@ -816,21 +847,21 @@ FROM Frames WHERE EventId=?';
|
|||
if ( $Config{ZM_LOG_DATABASE_LIMIT} ) {
|
||||
if ( $Config{ZM_LOG_DATABASE_LIMIT} =~ /^\d+$/ ) {
|
||||
# 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 )
|
||||
or Fatal( "Can't prepare '$selectLogRowCountSql': ".$dbh->errstr() );
|
||||
or Fatal("Can't prepare '$selectLogRowCountSql': ".$dbh->errstr());
|
||||
$res = $selectLogRowCountSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectLogRowCountSth->errstr() );
|
||||
or Fatal("Can't execute: ".$selectLogRowCountSth->errstr());
|
||||
my $row = $selectLogRowCountSth->fetchrow_hashref();
|
||||
my $logRows = $row->{Rows};
|
||||
if ( $logRows > $Config{ZM_LOG_DATABASE_LIMIT} ) {
|
||||
my $deleteLogByRowsSql = 'DELETE low_priority FROM Logs ORDER BY TimeKey ASC LIMIT ?';
|
||||
my $deleteLogByRowsSql = 'DELETE low_priority FROM `Logs` ORDER BY `TimeKey` ASC LIMIT ?';
|
||||
my $deleteLogByRowsSth = $dbh->prepare_cached( $deleteLogByRowsSql )
|
||||
or Fatal( "Can't prepare '$deleteLogByRowsSql': ".$dbh->errstr() );
|
||||
or Fatal("Can't prepare '$deleteLogByRowsSql': ".$dbh->errstr());
|
||||
$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() ) {
|
||||
aud_print( 'Deleted '.$deleteLogByRowsSth->rows() ." log table entries by count\n" );
|
||||
aud_print('Deleted '.$deleteLogByRowsSth->rows() ." log table entries by count\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -843,67 +874,67 @@ FROM Frames WHERE EventId=?';
|
|||
my $deleted_rows;
|
||||
do {
|
||||
my $deleteLogByTimeSql =
|
||||
'DELETE FROM Logs
|
||||
WHERE TimeKey < unix_timestamp(now() - interval '.$Config{ZM_LOG_DATABASE_LIMIT}.') LIMIT 10';
|
||||
'DELETE FROM `Logs`
|
||||
WHERE `TimeKey` < unix_timestamp(now() - interval '.$Config{ZM_LOG_DATABASE_LIMIT}.') LIMIT 10';
|
||||
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()
|
||||
or Fatal( "Can't execute: ".$deleteLogByTimeSth->errstr() );
|
||||
or Fatal("Can't execute: ".$deleteLogByTimeSth->errstr());
|
||||
$deleted_rows = $deleteLogByTimeSth->rows();
|
||||
aud_print( "Deleted $deleted_rows log table entries by time\n" );
|
||||
aud_print("Deleted $deleted_rows log table entries by time\n");
|
||||
} while ( $deleted_rows );
|
||||
}
|
||||
} # end if ZM_LOG_DATABASE_LIMIT
|
||||
$loop = $continuous;
|
||||
|
||||
my $eventcounts_sql = q`
|
||||
UPDATE Monitors SET
|
||||
TotalEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id),
|
||||
TotalEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND DiskSpace IS NOT NULL),
|
||||
ArchivedEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id AND Archived=1),
|
||||
ArchivedEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND Archived=1 AND DiskSpace IS NOT NULL)
|
||||
`;
|
||||
my $eventcounts_sql = '
|
||||
UPDATE `Monitors` SET
|
||||
`TotalEvents`=(SELECT COUNT(`Id`) FROM `Events` WHERE `MonitorId`=`Monitors`.`Id`),
|
||||
`TotalEventDiskSpace`=(SELECT SUM(`DiskSpace`) FROM `Events` WHERE `MonitorId`=`Monitors`.`Id` AND `DiskSpace` IS NOT NULL),
|
||||
`ArchivedEvents`=(SELECT COUNT(`Id`) FROM `Events` WHERE `MonitorId`=`Monitors`.`Id` AND `Archived`=1),
|
||||
`ArchivedEventDiskSpace`=(SELECT SUM(`DiskSpace`) FROM `Events` WHERE `MonitorId`=`Monitors`.`Id` AND `Archived`=1 AND `DiskSpace` IS NOT NULL)
|
||||
';
|
||||
|
||||
my $eventcounts_sth = $dbh->prepare_cached( $eventcounts_sql );
|
||||
$eventcounts_sth->execute();
|
||||
$eventcounts_sth->finish();
|
||||
|
||||
my $eventcounts_hour_sql = q`
|
||||
UPDATE Monitors INNER JOIN (
|
||||
SELECT MonitorId, COUNT(*) AS HourEvents, SUM(COALESCE(DiskSpace,0)) AS HourEventDiskSpace
|
||||
FROM Events_Hour GROUP BY MonitorId
|
||||
) AS E ON E.MonitorId=Monitors.Id SET
|
||||
Monitors.HourEvents = E.HourEvents,
|
||||
Monitors.HourEventDiskSpace = E.HourEventDiskSpace
|
||||
`;
|
||||
my $eventcounts_hour_sql = '
|
||||
UPDATE `Monitors` INNER JOIN (
|
||||
SELECT `MonitorId`, COUNT(*) AS `HourEvents`, SUM(COALESCE(`DiskSpace`,0)) AS `HourEventDiskSpace`
|
||||
FROM `Events_Hour` GROUP BY `MonitorId`
|
||||
) AS `E` ON `E`.`MonitorId`=`Monitors`.`Id` SET
|
||||
`Monitors`.`HourEvents` = `E`.`HourEvents`,
|
||||
`Monitors`.`HourEventDiskSpace` = `E`.`HourEventDiskSpace`
|
||||
';
|
||||
|
||||
|
||||
my $eventcounts_day_sql = q`
|
||||
UPDATE Monitors INNER JOIN (
|
||||
SELECT MonitorId, COUNT(*) AS DayEvents, SUM(COALESCE(DiskSpace,0)) AS DayEventDiskSpace
|
||||
FROM Events_Day GROUP BY MonitorId
|
||||
) AS E ON E.MonitorId=Monitors.Id SET
|
||||
Monitors.DayEvents = E.DayEvents,
|
||||
Monitors.DayEventDiskSpace = E.DayEventDiskSpace
|
||||
`;
|
||||
my $eventcounts_day_sql = '
|
||||
UPDATE `Monitors` INNER JOIN (
|
||||
SELECT `MonitorId`, COUNT(*) AS `DayEvents`, SUM(COALESCE(`DiskSpace`,0)) AS `DayEventDiskSpace`
|
||||
FROM `Events_Day` GROUP BY `MonitorId`
|
||||
) AS `E` ON `E`.`MonitorId`=`Monitors`.`Id` SET
|
||||
`Monitors`.`DayEvents` = `E`.`DayEvents`,
|
||||
`Monitors`.`DayEventDiskSpace` = `E`.`DayEventDiskSpace`
|
||||
';
|
||||
|
||||
my $eventcounts_week_sql = q`
|
||||
UPDATE Monitors INNER JOIN (
|
||||
SELECT MonitorId, COUNT(*) AS WeekEvents, SUM(COALESCE(DiskSpace,0)) AS WeekEventDiskSpace
|
||||
FROM Events_Week GROUP BY MonitorId
|
||||
) AS E ON E.MonitorId=Monitors.Id SET
|
||||
Monitors.WeekEvents = E.WeekEvents,
|
||||
Monitors.WeekEventDiskSpace = E.WeekEventDiskSpace
|
||||
`;
|
||||
my $eventcounts_week_sql = '
|
||||
UPDATE `Monitors` INNER JOIN (
|
||||
SELECT `MonitorId`, COUNT(*) AS `WeekEvents`, SUM(COALESCE(`DiskSpace`,0)) AS `WeekEventDiskSpace`
|
||||
FROM `Events_Week` GROUP BY `MonitorId`
|
||||
) AS `E` ON `E`.`MonitorId`=`Monitors`.`Id` SET
|
||||
`Monitors`.`WeekEvents` = `E`.`WeekEvents`,
|
||||
`Monitors`.`WeekEventDiskSpace` = `E`.`WeekEventDiskSpace`
|
||||
';
|
||||
|
||||
my $eventcounts_month_sql = q`
|
||||
UPDATE Monitors INNER JOIN (
|
||||
SELECT MonitorId, COUNT(*) AS MonthEvents, SUM(COALESCE(DiskSpace,0)) AS MonthEventDiskSpace
|
||||
FROM Events_Month GROUP BY MonitorId
|
||||
) AS E ON E.MonitorId=Monitors.Id SET
|
||||
Monitors.MonthEvents = E.MonthEvents,
|
||||
Monitors.MonthEventDiskSpace = E.MonthEventDiskSpace
|
||||
`;
|
||||
my $eventcounts_month_sql = '
|
||||
UPDATE `Monitors` INNER JOIN (
|
||||
SELECT `MonitorId`, COUNT(*) AS `MonthEvents`, SUM(COALESCE(`DiskSpace`,0)) AS `MonthEventDiskSpace`
|
||||
FROM `Events_Month` GROUP BY `MonitorId`
|
||||
) AS `E` ON `E`.`MonitorId`=`Monitors`.`Id` SET
|
||||
`Monitors`.`MonthEvents` = `E`.`MonthEvents`,
|
||||
`Monitors`.`MonthEventDiskSpace` = `E`.`MonthEventDiskSpace`
|
||||
';
|
||||
my $eventcounts_hour_sth = $dbh->prepare_cached($eventcounts_hour_sql);
|
||||
my $eventcounts_day_sth = $dbh->prepare_cached($eventcounts_day_sql);
|
||||
my $eventcounts_week_sth = $dbh->prepare_cached($eventcounts_week_sql);
|
||||
|
|
|
@ -175,8 +175,12 @@ my $dbh = zmDbConnect();
|
|||
|
||||
if ( $filter_name ) {
|
||||
Info("Scanning for events using filter '$filter_name'");
|
||||
} elsif ( $filter_id ) {
|
||||
Info("Scanning for events using filter id '$filter_id'");
|
||||
} elsif ( defined($filter_id) ) {
|
||||
if ( $filter_id ) {
|
||||
Info("Scanning for events using filter id '$filter_id'");
|
||||
} else {
|
||||
Fatal("No filter_id specified");
|
||||
}
|
||||
} else {
|
||||
Info("Scanning for events using all filters");
|
||||
}
|
||||
|
@ -221,27 +225,27 @@ sub getFilters {
|
|||
my @sql_values;
|
||||
|
||||
my @filters;
|
||||
my $sql = 'SELECT * FROM Filters WHERE';
|
||||
my $sql = 'SELECT * FROM `Filters` WHERE';
|
||||
if ( $$sql_filters{Name} ) {
|
||||
$sql .= ' Name = ? AND';
|
||||
$sql .= ' `Name` = ? AND';
|
||||
push @sql_values, $$sql_filters{Name};
|
||||
} elsif ( $$sql_filters{Id} ) {
|
||||
$sql .= ' Id = ? AND';
|
||||
$sql .= ' `Id` = ? AND';
|
||||
push @sql_values, $$sql_filters{Id};
|
||||
} else {
|
||||
$sql .= ' Background = 1 AND';
|
||||
$sql .= ' `Background` = 1 AND';
|
||||
}
|
||||
$sql .= '( AutoArchive = 1
|
||||
or AutoVideo = 1
|
||||
or AutoUpload = 1
|
||||
or AutoEmail = 1
|
||||
or AutoMessage = 1
|
||||
or AutoExecute = 1
|
||||
or AutoDelete = 1
|
||||
or UpdateDiskSpace = 1
|
||||
or AutoMove = 1
|
||||
or AutoCopy = 1
|
||||
) ORDER BY Name';
|
||||
$sql .= '( `AutoArchive` = 1
|
||||
or `AutoVideo` = 1
|
||||
or `AutoUpload` = 1
|
||||
or `AutoEmail` = 1
|
||||
or `AutoMessage` = 1
|
||||
or `AutoExecute` = 1
|
||||
or `AutoDelete` = 1
|
||||
or `UpdateDiskSpace` = 1
|
||||
or `AutoMove` = 1
|
||||
or `AutoCopy` = 1
|
||||
) ORDER BY `Name`';
|
||||
my $sth = $dbh->prepare_cached($sql)
|
||||
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
|
||||
my $res = $sth->execute(@sql_values)
|
||||
|
@ -301,7 +305,7 @@ sub checkFilter {
|
|||
if ( $filter->{AutoArchive} ) {
|
||||
Info("Archiving event $Event->{Id}");
|
||||
# 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)
|
||||
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
|
||||
my $res = $sth->execute($Event->{Id})
|
||||
|
@ -434,7 +438,7 @@ sub generateVideo {
|
|||
}
|
||||
return 0;
|
||||
} 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)
|
||||
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
|
||||
my $res = $sth->execute($Event->{Id})
|
||||
|
@ -619,7 +623,7 @@ sub uploadArchFile {
|
|||
or Error("SFTP - Unable to upload '$archLocPath': ".$sftp->error);
|
||||
}
|
||||
unlink($archLocPath);
|
||||
my $sql = 'UPDATE Events SET Uploaded = 1 WHERE Id = ?';
|
||||
my $sql = 'UPDATE `Events` SET `Uploaded` = 1 WHERE `Id` = ?';
|
||||
my $sth = $dbh->prepare_cached($sql)
|
||||
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
|
||||
my $res = $sth->execute($Event->{Id})
|
||||
|
@ -647,12 +651,10 @@ sub substituteTags {
|
|||
my $max_alarm_frame;
|
||||
my $max_alarm_score = 0;
|
||||
if ( $need_images ) {
|
||||
my $sql = q`SELECT * FROM Frames
|
||||
WHERE EventId = ? AND Type = 'Alarm'
|
||||
ORDER BY FrameId`;
|
||||
my $sql = 'SELECT * FROM `Frames` WHERE `EventId`=? AND `Type`=? ORDER BY `FrameId`';
|
||||
my $sth = $dbh->prepare_cached($sql)
|
||||
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
|
||||
my $res = $sth->execute($Event->{Id})
|
||||
my $res = $sth->execute($Event->{Id},'Alarm')
|
||||
or Fatal("Unable to execute '$sql': ".$dbh->errstr());
|
||||
my $rows = 0;
|
||||
while( my $frame = $sth->fetchrow_hashref() ) {
|
||||
|
@ -879,7 +881,7 @@ sub sendEmail {
|
|||
} else {
|
||||
Info('Notification email sent');
|
||||
}
|
||||
my $sql = 'UPDATE Events SET Emailed = 1 WHERE Id = ?';
|
||||
my $sql = 'UPDATE `Events` SET `Emailed` = 1 WHERE `Id` = ?';
|
||||
my $sth = $dbh->prepare_cached($sql)
|
||||
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
|
||||
my $res = $sth->execute($Event->{Id})
|
||||
|
@ -984,7 +986,7 @@ sub sendMessage {
|
|||
} else {
|
||||
Info('Notification message sent');
|
||||
}
|
||||
my $sql = 'UPDATE Events SET Messaged = 1 WHERE Id = ?';
|
||||
my $sql = 'UPDATE `Events` SET `Messaged` = 1 WHERE `Id` = ?';
|
||||
my $sth = $dbh->prepare_cached($sql)
|
||||
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
|
||||
my $res = $sth->execute($Event->{Id})
|
||||
|
@ -1014,7 +1016,7 @@ sub executeCommand {
|
|||
Error("Command '$command' exited with status: $status");
|
||||
return 0;
|
||||
} 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)
|
||||
or Fatal("Unable to prepare '$sql': ".$dbh->errstr());
|
||||
my $res = $sth->execute( $Event->{Id} )
|
||||
|
|
|
@ -57,7 +57,7 @@ my $dbh = zmDbConnect();
|
|||
Debug("Command: $command");
|
||||
if ( $command and ( $command !~ /^(?:start|stop|restart|status|logrot|version)$/ ) ) {
|
||||
# Check to see if it's a valid run state
|
||||
my $sql = 'SELECT * FROM States WHERE Name=?';
|
||||
my $sql = 'SELECT * FROM `States` WHERE `Name`=?';
|
||||
my $sth = $dbh->prepare_cached($sql)
|
||||
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
|
||||
my $res = $sth->execute($command)
|
||||
|
@ -98,7 +98,7 @@ my $retval = 0;
|
|||
|
||||
if ( $command eq 'state' ) {
|
||||
Info("Updating DB: $state->{Name}");
|
||||
my $sql = 'SELECT * FROM Monitors' . ($Config{ZM_SERVER_ID} ? ' WHERE ServerId=?' : '' ) .' ORDER BY Id ASC';
|
||||
my $sql = 'SELECT * FROM `Monitors`' . ($Config{ZM_SERVER_ID} ? ' WHERE `ServerId`=?' : '' ) .' ORDER BY `Id` ASC';
|
||||
my $sth = $dbh->prepare_cached($sql)
|
||||
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
|
||||
my $res = $sth->execute($Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID}: ())
|
||||
|
@ -118,7 +118,7 @@ if ( $command eq 'state' ) {
|
|||
if ( $monitor->{Function} ne $monitor->{NewFunction}
|
||||
|| $monitor->{Enabled} ne $monitor->{NewEnabled}
|
||||
) {
|
||||
my $sql = 'UPDATE Monitors SET Function=?, Enabled=? WHERE Id=?';
|
||||
my $sql = 'UPDATE `Monitors` SET `Function`=?, `Enabled`=? WHERE `Id`=?';
|
||||
my $sth = $dbh->prepare_cached($sql)
|
||||
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
|
||||
my $res = $sth->execute($monitor->{NewFunction}, $monitor->{NewEnabled}, $monitor->{Id})
|
||||
|
@ -130,7 +130,7 @@ if ( $command eq 'state' ) {
|
|||
# PP - Now mark a specific state as active
|
||||
resetStates();
|
||||
Info("Marking $store_state as Enabled");
|
||||
$sql = 'UPDATE States SET IsActive = 1 WHERE Name = ?';
|
||||
$sql = 'UPDATE `States` SET `IsActive` = 1 WHERE `Name` = ?';
|
||||
$sth = $dbh->prepare_cached($sql)
|
||||
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
|
||||
$res = $sth->execute($store_state)
|
||||
|
@ -197,11 +197,11 @@ if ( $command =~ /^(?:start|restart)$/ ) {
|
|||
require ZoneMinder::Server;
|
||||
Info("Multi-server configuration detected. Starting up services for server $Config{ZM_SERVER_ID}");
|
||||
$Server = new ZoneMinder::Server($Config{ZM_SERVER_ID});
|
||||
$sql = 'SELECT * FROM Monitors WHERE ServerId=?';
|
||||
$sql = 'SELECT * FROM `Monitors` WHERE `ServerId`=?';
|
||||
@values = ( $Config{ZM_SERVER_ID} );
|
||||
} else {
|
||||
Info('Single server configuration detected. Starting up services.');
|
||||
$sql = 'SELECT * FROM Monitors';
|
||||
$sql = 'SELECT * FROM `Monitors`';
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -237,7 +237,7 @@ if ( $command =~ /^(?:start|restart)$/ ) {
|
|||
}
|
||||
|
||||
{
|
||||
my $sql = 'SELECT Id FROM Filters WHERE Background=1';
|
||||
my $sql = 'SELECT `Id` FROM `Filters` WHERE `Background`=1';
|
||||
my $sth = $dbh->prepare_cached($sql)
|
||||
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
|
||||
my $res = $sth->execute()
|
||||
|
@ -311,25 +311,25 @@ sub isActiveSanityCheck {
|
|||
$dbh = zmDbConnect() if ! $dbh;
|
||||
|
||||
# PP - First, make sure default exists and there is only one
|
||||
my $sql = q`SELECT Name FROM States WHERE Name='default'`;
|
||||
my $sql = 'SELECT `Name` FROM `States` WHERE `Name`=?';
|
||||
my $sth = $dbh->prepare_cached($sql)
|
||||
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
|
||||
my $res = $sth->execute()
|
||||
my $res = $sth->execute('default')
|
||||
or Fatal("Can't execute: ".$sth->errstr());
|
||||
|
||||
if ( $sth->rows != 1 ) {
|
||||
# PP - no row, or too many rows. Either case is an error
|
||||
Info('Fixing States table - either no default state or duplicate default states');
|
||||
if ( $sth->rows ) {
|
||||
$dbh->do(q`DELETE FROM States WHERE Name='default'`) or Fatal("Can't execute: ".$dbh->errstr());
|
||||
$dbh->do('DELETE FROM `States` WHERE `Name`=\'default\'') or Fatal("Can't execute: ".$dbh->errstr());
|
||||
}
|
||||
$dbh->do(q`INSERT INTO States (Name,Definition,IsActive) VALUES ('default','','1');`)
|
||||
$dbh->do('INSERT INTO `States` (`Name`,`Definition`,`IsActive`) VALUES (\'default\',\'\',\'1\');')
|
||||
or Fatal("Can't execute: ".$dbh->errstr());
|
||||
}
|
||||
$sth->finish();
|
||||
|
||||
# PP - Now make sure no two states have IsActive=1
|
||||
$sql = 'SELECT Name FROM States WHERE IsActive = 1';
|
||||
$sql = 'SELECT `Name` FROM `States` WHERE `IsActive`=1';
|
||||
$sth = $dbh->prepare_cached($sql)
|
||||
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
|
||||
$res = $sth->execute()
|
||||
|
@ -338,7 +338,7 @@ sub isActiveSanityCheck {
|
|||
if ( $sth->rows != 1 ) {
|
||||
Info('Fixing States table so only one run state is active');
|
||||
resetStates();
|
||||
$dbh->do(q`UPDATE States SET IsActive=1 WHERE Name='default'`)
|
||||
$dbh->do('UPDATE `States` SET `IsActive`=1 WHERE `Name`=\'default\'')
|
||||
or Fatal("Can't execute: ".$dbh->errstr());
|
||||
}
|
||||
$sth->finish();
|
||||
|
@ -347,7 +347,7 @@ sub isActiveSanityCheck {
|
|||
# PP - zeroes out isActive for all states
|
||||
sub resetStates {
|
||||
$dbh = zmDbConnect() if ! $dbh;
|
||||
$dbh->do('UPDATE States SET IsActive=0')
|
||||
$dbh->do('UPDATE `States` SET `IsActive`=0')
|
||||
or Fatal("Can't execute: ".$dbh->errstr());
|
||||
}
|
||||
|
||||
|
|
|
@ -301,7 +301,7 @@ if ( $migrateEvents ) {
|
|||
$sth->finish();
|
||||
|
||||
print( "Updating configuration.\n" );
|
||||
$sql = "update Config set Value = ? where Name = 'ZM_USE_DEEP_STORAGE'";
|
||||
$sql = "UPDATE `Config` SET `Value` = ? WHERE `Name` = 'ZM_USE_DEEP_STORAGE'";
|
||||
$sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
$res = $sth->execute( 1 ) or die( "Can't execute: ".$sth->errstr() );
|
||||
$sth->finish();
|
||||
|
@ -323,7 +323,7 @@ if ( $freshen ) {
|
|||
if ( $interactive ) {
|
||||
# Now check for MyISAM Tables
|
||||
my @MyISAM_Tables;
|
||||
my $sql = "SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='zm' AND engine = 'MyISAM'";
|
||||
my $sql = "SELECT `table_name` FROM INFORMATION_SCHEMA.TABLES WHERE `table_schema`='zm' AND `engine` = 'MyISAM'";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
|
||||
|
||||
|
@ -341,7 +341,7 @@ if ( $interactive ) {
|
|||
$dbh->do(q|SET sql_mode='traditional'|); # Elevate warnings to errors
|
||||
print "\nConverting MyISAM tables to InnoDB. Please wait.\n";
|
||||
foreach (@MyISAM_Tables) {
|
||||
my $sql = "ALTER TABLE $_ ENGINE = InnoDB";
|
||||
my $sql = "ALTER TABLE `$_` ENGINE = InnoDB";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
|
||||
$sth->finish();
|
||||
|
@ -447,7 +447,7 @@ if ( $version ) {
|
|||
# Rename the event directories and create a new symlink for the names
|
||||
chdir( EVENT_PATH );
|
||||
|
||||
my $sql = "select * from Monitors order by Id";
|
||||
my $sql = "SELECT * FROM `Monitors` ORDER BY `Id`";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
|
||||
while( my $monitor = $sth->fetchrow_hashref() ) {
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
#include "zm.h"
|
||||
# include "zm_crypt.h"
|
||||
#include "zm_crypt.h"
|
||||
#include "BCrypt.hpp"
|
||||
#include "jwt.h"
|
||||
#include <algorithm>
|
||||
#include <openssl/sha.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// returns username if valid, "" if not
|
||||
std::pair <std::string, unsigned int> verifyToken(std::string jwt_token_str, std::string key) {
|
||||
std::string username = "";
|
||||
|
@ -22,47 +21,42 @@ std::pair <std::string, unsigned int> verifyToken(std::string jwt_token_str, std
|
|||
verifier.verify(decoded);
|
||||
|
||||
// make sure it has fields we need
|
||||
if (decoded.has_payload_claim("type")) {
|
||||
if ( decoded.has_payload_claim("type") ) {
|
||||
std::string type = decoded.get_payload_claim("type").as_string();
|
||||
if (type != "access") {
|
||||
Error ("Only access tokens are allowed. Please do not use refresh tokens");
|
||||
return std::make_pair("",0);
|
||||
if ( type != "access" ) {
|
||||
Error("Only access tokens are allowed. Please do not use refresh tokens");
|
||||
return std::make_pair("", 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// something is wrong. All ZM tokens have type
|
||||
Error ("Missing token type. This should not happen");
|
||||
Error("Missing token type. This should not happen");
|
||||
return std::make_pair("",0);
|
||||
}
|
||||
if (decoded.has_payload_claim("user")) {
|
||||
if ( decoded.has_payload_claim("user") ) {
|
||||
username = decoded.get_payload_claim("user").as_string();
|
||||
Debug (1, "Got %s as user claim from token", username.c_str());
|
||||
}
|
||||
else {
|
||||
Error ("User not found in claim");
|
||||
return std::make_pair("",0);
|
||||
Debug(1, "Got %s as user claim from token", username.c_str());
|
||||
} else {
|
||||
Error("User not found in claim");
|
||||
return std::make_pair("", 0);
|
||||
}
|
||||
|
||||
if (decoded.has_payload_claim("iat")) {
|
||||
if ( decoded.has_payload_claim("iat") ) {
|
||||
token_issued_at = (unsigned int) (decoded.get_payload_claim("iat").as_int());
|
||||
Debug (1,"Got IAT token=%u", token_issued_at);
|
||||
|
||||
}
|
||||
else {
|
||||
Error ("IAT not found in claim. This should not happen");
|
||||
return std::make_pair("",0);
|
||||
Debug(1, "Got IAT token=%u", token_issued_at);
|
||||
} else {
|
||||
Error("IAT not found in claim. This should not happen");
|
||||
return std::make_pair("", 0);
|
||||
}
|
||||
} // try
|
||||
catch (const std::exception &e) {
|
||||
catch ( const std::exception &e ) {
|
||||
Error("Unable to verify token: %s", e.what());
|
||||
return std::make_pair("",0);
|
||||
return std::make_pair("", 0);
|
||||
}
|
||||
catch (...) {
|
||||
Error ("unknown exception");
|
||||
return std::make_pair("",0);
|
||||
|
||||
Error("unknown exception");
|
||||
return std::make_pair("", 0);
|
||||
}
|
||||
return std::make_pair(username,token_issued_at);
|
||||
return std::make_pair(username, token_issued_at);
|
||||
}
|
||||
|
||||
bool verifyPassword(const char *username, const char *input_password, const char *db_password_hash) {
|
||||
|
@ -102,7 +96,7 @@ bool verifyPassword(const char *username, const char *input_password, const char
|
|||
} else if (
|
||||
(db_password_hash[0] == '$')
|
||||
&&
|
||||
(db_password_hash[1]== '2')
|
||||
(db_password_hash[1] == '2')
|
||||
&&
|
||||
(db_password_hash[3] == '$')
|
||||
) {
|
||||
|
|
|
@ -246,11 +246,13 @@ Event::~Event() {
|
|||
DELTA_TIMEVAL(delta_time, end_time, start_time, DT_PREC_2);
|
||||
Debug(2, "start_time:%d.%d end_time%d.%d", start_time.tv_sec, start_time.tv_usec, end_time.tv_sec, end_time.tv_usec);
|
||||
|
||||
#if 0 // This closing frame has no image. There is no point in adding a db record for it, I think. ICON
|
||||
if ( frames > last_db_frame ) {
|
||||
frames ++;
|
||||
Debug(1, "Adding closing frame %d to DB", frames);
|
||||
frame_data.push(new Frame(id, frames, NORMAL, end_time, delta_time, 0));
|
||||
}
|
||||
#endif
|
||||
if ( frame_data.size() )
|
||||
WriteDbFrames();
|
||||
|
||||
|
|
|
@ -510,7 +510,7 @@ int zm_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet)
|
|||
|
||||
int zm_send_frame(AVCodecContext *ctx, AVFrame *frame, AVPacket &packet) {
|
||||
int ret;
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
if ( (ret = avcodec_send_frame(ctx, frame)) < 0 ) {
|
||||
Error("Could not send frame (error '%s')",
|
||||
av_make_error_string(ret).c_str());
|
||||
|
|
|
@ -299,21 +299,6 @@ void zm_dump_codec(const AVCodecContext *codec);
|
|||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
void zm_dump_codecpar(const AVCodecParameters *par);
|
||||
#endif
|
||||
#if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100)
|
||||
#define zm_dump_frame(frame, text) Debug(1, "%s: format %d %s sample_rate %" PRIu32 " nb_samples %d channels %d" \
|
||||
" duration %" PRId64 \
|
||||
" layout %d pts %" PRId64,\
|
||||
text, \
|
||||
frame->format, \
|
||||
av_get_sample_fmt_name((AVSampleFormat)frame->format), \
|
||||
frame->sample_rate, \
|
||||
frame->nb_samples, \
|
||||
frame->channels, \
|
||||
frame->pkt_duration, \
|
||||
frame->channel_layout, \
|
||||
frame->pts \
|
||||
);
|
||||
#else
|
||||
#define zm_dump_frame(frame, text) Debug(1, "%s: format %d %s sample_rate %" PRIu32 " nb_samples %d channels %d" \
|
||||
" duration %" PRId64 \
|
||||
" layout %d pts %" PRId64, \
|
||||
|
@ -327,8 +312,6 @@ void zm_dump_codecpar(const AVCodecParameters *par);
|
|||
frame->pts \
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
#define zm_dump_video_frame(frame,text) Debug(1, "%s: format %d %s %dx%d linesize:%dx%d pts: %" PRId64, \
|
||||
text, \
|
||||
frame->format, \
|
||||
|
|
|
@ -1102,10 +1102,11 @@ int FfmpegCamera::transfer_to_image(
|
|||
mConvertContext, input_frame->data, input_frame->linesize,
|
||||
0, mVideoCodecContext->height,
|
||||
output_frame->data, output_frame->linesize) <= 0 ) {
|
||||
Error("Unable to convert format %u to format %u at frame %d codec %u",
|
||||
input_frame->format,
|
||||
imagePixFormat, frameCount,
|
||||
mVideoCodecContext->pix_fmt
|
||||
Error("Unable to convert format %u %s to format %u %s at frame %d codec %u %s",
|
||||
input_frame->format, av_get_pix_fmt_name((AVPixelFormat)input_frame->format),
|
||||
av_get_pix_fmt_name(imagePixFormat),
|
||||
frameCount,
|
||||
mVideoCodecContext->pix_fmt, av_get_pix_fmt_name(mVideoCodecContext->pix_fmt)
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -3237,7 +3237,7 @@ void neon32_armv7_fastblend(const uint8_t* col1, const uint8_t* col2, uint8_t* r
|
|||
__asm__ __volatile__ (
|
||||
"mov r12, %4\n\t"
|
||||
"vdup.8 q12, r12\n\t"
|
||||
"neon32_armv7_fastblend_iter:\n\t"
|
||||
"neon32_armv7_fastblend_iter%=:\n\t"
|
||||
"vldm %0!, {q0,q1,q2,q3}\n\t"
|
||||
"vldm %1!, {q4,q5,q6,q7}\n\t"
|
||||
"pld [%0, #256]\n\t"
|
||||
|
@ -3260,7 +3260,7 @@ void neon32_armv7_fastblend(const uint8_t* col1, const uint8_t* col2, uint8_t* r
|
|||
"vadd.i8 q7, q7, q3\n\t"
|
||||
"vstm %2!, {q4,q5,q6,q7}\n\t"
|
||||
"subs %3, %3, #64\n\t"
|
||||
"bne neon32_armv7_fastblend_iter\n\t"
|
||||
"bne neon32_armv7_fastblend_iter%=\n\t"
|
||||
:
|
||||
: "r" (col1), "r" (col2), "r" (result), "r" (count), "r" (divider)
|
||||
: "%r12", "%q0", "%q1", "%q2", "%q3", "%q4", "%q5", "%q6", "%q7", "%q8", "%q9", "%q10", "%q11", "%q12", "cc", "memory"
|
||||
|
@ -3318,7 +3318,7 @@ __attribute__((noinline)) void neon64_armv8_fastblend(const uint8_t* col1, const
|
|||
__asm__ __volatile__ (
|
||||
"mov x12, %4\n\t"
|
||||
"dup v28.16b, w12\n\t"
|
||||
"neon64_armv8_fastblend_iter:\n\t"
|
||||
"neon64_armv8_fastblend_iter%=:\n\t"
|
||||
"ldp q16, q17, [%0], #32\n\t"
|
||||
"ldp q18, q19, [%0], #32\n\t"
|
||||
"ldp q20, q21, [%1], #32\n\t"
|
||||
|
@ -3344,7 +3344,7 @@ __attribute__((noinline)) void neon64_armv8_fastblend(const uint8_t* col1, const
|
|||
"stp q20, q21, [%2], #32\n\t"
|
||||
"stp q22, q23, [%2], #32\n\t"
|
||||
"subs %3, %3, #64\n\t"
|
||||
"bne neon64_armv8_fastblend_iter\n\t"
|
||||
"bne neon64_armv8_fastblend_iter%=\n\t"
|
||||
:
|
||||
: "r" (col1), "r" (col2), "r" (result), "r" (count), "r" (divider)
|
||||
: "%x12", "%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23", "%v24", "%v25", "%v26", "%v27", "%v28", "cc", "memory"
|
||||
|
@ -3702,7 +3702,7 @@ void neon32_armv7_delta8_gray8(const uint8_t* col1, const uint8_t* col2, uint8_t
|
|||
/* Q7(D14,D15) = col2+48 */
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"neon32_armv7_delta8_gray8_iter:\n\t"
|
||||
"neon32_armv7_delta8_gray8_iter%=:\n\t"
|
||||
"vldm %0!, {q0,q1,q2,q3}\n\t"
|
||||
"vldm %1!, {q4,q5,q6,q7}\n\t"
|
||||
"pld [%0, #512]\n\t"
|
||||
|
@ -3713,7 +3713,7 @@ void neon32_armv7_delta8_gray8(const uint8_t* col1, const uint8_t* col2, uint8_t
|
|||
"vabd.u8 q3, q3, q7\n\t"
|
||||
"vstm %2!, {q0,q1,q2,q3}\n\t"
|
||||
"subs %3, %3, #64\n\t"
|
||||
"bne neon32_armv7_delta8_gray8_iter\n\t"
|
||||
"bne neon32_armv7_delta8_gray8_iter%=\n\t"
|
||||
:
|
||||
: "r" (col1), "r" (col2), "r" (result), "r" (count)
|
||||
: "%q0", "%q1", "%q2", "%q3", "%q4", "%q5", "%q6", "%q7", "cc", "memory"
|
||||
|
@ -3737,7 +3737,7 @@ __attribute__((noinline)) void neon64_armv8_delta8_gray8(const uint8_t* col1, co
|
|||
/* V23 = col2+48 */
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"neon64_armv8_delta8_gray8_iter:\n\t"
|
||||
"neon64_armv8_delta8_gray8_iter%=:\n\t"
|
||||
"ldp q16, q17, [%0], #32\n\t"
|
||||
"ldp q18, q19, [%0], #32\n\t"
|
||||
"ldp q20, q21, [%1], #32\n\t"
|
||||
|
@ -3751,7 +3751,7 @@ __attribute__((noinline)) void neon64_armv8_delta8_gray8(const uint8_t* col1, co
|
|||
"stp q16, q17, [%2], #32\n\t"
|
||||
"stp q18, q19, [%2], #32\n\t"
|
||||
"subs %3, %3, #64\n\t"
|
||||
"bne neon64_armv8_delta8_gray8_iter\n\t"
|
||||
"bne neon64_armv8_delta8_gray8_iter%=\n\t"
|
||||
:
|
||||
: "r" (col1), "r" (col2), "r" (result), "r" (count)
|
||||
: "%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23", "cc", "memory"
|
||||
|
@ -3781,7 +3781,7 @@ void neon32_armv7_delta8_rgb32(const uint8_t* col1, const uint8_t* col2, uint8_t
|
|||
__asm__ __volatile__ (
|
||||
"mov r12, %4\n\t"
|
||||
"vdup.32 q8, r12\n\t"
|
||||
"neon32_armv7_delta8_rgb32_iter:\n\t"
|
||||
"neon32_armv7_delta8_rgb32_iter%=:\n\t"
|
||||
"vldm %0!, {q0,q1,q2,q3}\n\t"
|
||||
"vldm %1!, {q4,q5,q6,q7}\n\t"
|
||||
"pld [%0, #256]\n\t"
|
||||
|
@ -3808,7 +3808,7 @@ void neon32_armv7_delta8_rgb32(const uint8_t* col1, const uint8_t* col2, uint8_t
|
|||
"vpadd.i8 d3, d6, d6\n\t"
|
||||
"vst4.32 {d0[0],d1[0],d2[0],d3[0]}, [%2]!\n\t"
|
||||
"subs %3, %3, #16\n\t"
|
||||
"bne neon32_armv7_delta8_rgb32_iter\n\t"
|
||||
"bne neon32_armv7_delta8_rgb32_iter%=\n\t"
|
||||
:
|
||||
: "r" (col1), "r" (col2), "r" (result), "r" (count), "r" (multiplier)
|
||||
: "%r12", "%q0", "%q1", "%q2", "%q3", "%q4", "%q5", "%q6", "%q7", "%q8", "cc", "memory"
|
||||
|
@ -3835,7 +3835,7 @@ __attribute__((noinline)) void neon64_armv8_delta8_rgb32(const uint8_t* col1, co
|
|||
__asm__ __volatile__ (
|
||||
"mov x12, %4\n\t"
|
||||
"dup v24.4s, w12\n\t"
|
||||
"neon64_armv8_delta8_rgb32_iter:\n\t"
|
||||
"neon64_armv8_delta8_rgb32_iter%=:\n\t"
|
||||
"ldp q16, q17, [%0], #32\n\t"
|
||||
"ldp q18, q19, [%0], #32\n\t"
|
||||
"ldp q20, q21, [%1], #32\n\t"
|
||||
|
@ -3864,7 +3864,7 @@ __attribute__((noinline)) void neon64_armv8_delta8_rgb32(const uint8_t* col1, co
|
|||
"addp v19.16b, v19.16b, v19.16b\n\t"
|
||||
"st4 {v16.s, v17.s, v18.s, v19.s}[0], [%2], #16\n\t"
|
||||
"subs %3, %3, #16\n\t"
|
||||
"bne neon64_armv8_delta8_rgb32_iter\n\t"
|
||||
"bne neon64_armv8_delta8_rgb32_iter%=\n\t"
|
||||
:
|
||||
: "r" (col1), "r" (col2), "r" (result), "r" (count), "r" (multiplier)
|
||||
: "%x12", "%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23", "%v24", "cc", "memory"
|
||||
|
|
|
@ -58,32 +58,32 @@ inline void zm_freealigned(void* ptr) {
|
|||
#endif
|
||||
}
|
||||
|
||||
inline char *mempbrk( register const char *s, const char *accept, size_t limit ) {
|
||||
inline char *mempbrk(const char *s, const char *accept, size_t limit) {
|
||||
if ( limit == 0 || !s || !accept || !*accept )
|
||||
return 0;
|
||||
|
||||
register unsigned int i,j;
|
||||
size_t acc_len = strlen( accept );
|
||||
unsigned int i,j;
|
||||
size_t acc_len = strlen(accept);
|
||||
|
||||
for ( i = 0; i < limit; s++, i++ ) {
|
||||
for ( j = 0; j < acc_len; j++ ) {
|
||||
if ( *s == accept[j] ) {
|
||||
return( (char *)s );
|
||||
return (char *)s;
|
||||
}
|
||||
}
|
||||
}
|
||||
return( 0 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline char *memstr( register const char *s, const char *n, size_t limit ) {
|
||||
inline char *memstr(const char *s, const char *n, size_t limit) {
|
||||
if ( limit == 0 || !s || !n )
|
||||
return( 0 );
|
||||
return 0;
|
||||
|
||||
if ( !*n )
|
||||
return( (char *)s );
|
||||
return (char *)s;
|
||||
|
||||
register unsigned int i,j,k;
|
||||
size_t n_len = strlen( n );
|
||||
unsigned int i,j,k;
|
||||
size_t n_len = strlen(n);
|
||||
|
||||
for ( i = 0; i < limit; i++, s++ ) {
|
||||
if ( *s != *n )
|
||||
|
@ -92,23 +92,23 @@ inline char *memstr( register const char *s, const char *n, size_t limit ) {
|
|||
k = 1;
|
||||
while ( true ) {
|
||||
if ( k >= n_len )
|
||||
return( (char *)s );
|
||||
return (char *)s;
|
||||
if ( s[j++] != n[k++] )
|
||||
break;
|
||||
}
|
||||
}
|
||||
return( 0 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline size_t memspn( register const char *s, const char *accept, size_t limit ) {
|
||||
inline size_t memspn(const char *s, const char *accept, size_t limit) {
|
||||
if ( limit == 0 || !s || !accept || !*accept )
|
||||
return( 0 );
|
||||
return 0;
|
||||
|
||||
register unsigned int i,j;
|
||||
size_t acc_len = strlen( accept );
|
||||
unsigned int i,j;
|
||||
size_t acc_len = strlen(accept);
|
||||
|
||||
for ( i = 0; i < limit; s++, i++ ) {
|
||||
register bool found = false;
|
||||
bool found = false;
|
||||
for ( j = 0; j < acc_len; j++ ) {
|
||||
if ( *s == accept[j] ) {
|
||||
found = true;
|
||||
|
@ -116,30 +116,30 @@ inline size_t memspn( register const char *s, const char *accept, size_t limit )
|
|||
}
|
||||
}
|
||||
if ( !found ) {
|
||||
return( i );
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return( limit );
|
||||
return limit;
|
||||
}
|
||||
|
||||
inline size_t memcspn( register const char *s, const char *reject, size_t limit ) {
|
||||
inline size_t memcspn(const char *s, const char *reject, size_t limit) {
|
||||
if ( limit == 0 || !s || !reject )
|
||||
return( 0 );
|
||||
return 0;
|
||||
|
||||
if ( !*reject )
|
||||
return( limit );
|
||||
return limit;
|
||||
|
||||
register unsigned int i,j;
|
||||
unsigned int i,j;
|
||||
size_t rej_len = strlen( reject );
|
||||
|
||||
for ( i = 0; i < limit; s++, i++ ) {
|
||||
for ( j = 0; j < rej_len; j++ ) {
|
||||
if ( *s == reject[j] ) {
|
||||
return( i );
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return( limit );
|
||||
return limit;
|
||||
}
|
||||
|
||||
#endif // ZM_MEM_UTILS_H
|
||||
|
|
|
@ -27,6 +27,18 @@
|
|||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#if HAVE_GNUTLS_OPENSSL_H
|
||||
#include <gnutls/openssl.h>
|
||||
#endif
|
||||
#if HAVE_GNUTLS_GNUTLS_H
|
||||
#include <gnutls/gnutls.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_GCRYPT_H
|
||||
#include <gcrypt.h>
|
||||
#elif HAVE_LIBCRYPTO
|
||||
#include <openssl/md5.h>
|
||||
#endif // HAVE_L || HAVE_LIBCRYPTO
|
||||
|
||||
#include "zm_utils.h"
|
||||
#include "zm_crypt.h"
|
||||
|
@ -38,22 +50,22 @@ User::User() {
|
|||
stream = events = control = monitors = system = PERM_NONE;
|
||||
}
|
||||
|
||||
User::User( MYSQL_ROW &dbrow ) {
|
||||
User::User(const MYSQL_ROW &dbrow) {
|
||||
int index = 0;
|
||||
id = atoi( dbrow[index++] );
|
||||
strncpy( username, dbrow[index++], sizeof(username)-1 );
|
||||
strncpy( password, dbrow[index++], sizeof(password)-1 );
|
||||
enabled = (bool)atoi( dbrow[index++] );
|
||||
stream = (Permission)atoi( dbrow[index++] );
|
||||
events = (Permission)atoi( dbrow[index++] );
|
||||
control = (Permission)atoi( dbrow[index++] );
|
||||
monitors = (Permission)atoi( dbrow[index++] );
|
||||
system = (Permission)atoi( dbrow[index++] );
|
||||
id = atoi(dbrow[index++]);
|
||||
strncpy(username, dbrow[index++], sizeof(username)-1);
|
||||
strncpy(password, dbrow[index++], sizeof(password)-1);
|
||||
enabled = (bool)atoi(dbrow[index++]);
|
||||
stream = (Permission)atoi(dbrow[index++]);
|
||||
events = (Permission)atoi(dbrow[index++]);
|
||||
control = (Permission)atoi(dbrow[index++]);
|
||||
monitors = (Permission)atoi(dbrow[index++]);
|
||||
system = (Permission)atoi(dbrow[index++]);
|
||||
char *monitor_ids_str = dbrow[index++];
|
||||
if ( monitor_ids_str && *monitor_ids_str ) {
|
||||
StringVector ids = split(monitor_ids_str, ",");
|
||||
for( StringVector::iterator i = ids.begin(); i < ids.end(); ++i ) {
|
||||
monitor_ids.push_back( atoi( (*i).c_str()) );
|
||||
monitor_ids.push_back(atoi((*i).c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,10 +74,10 @@ User::~User() {
|
|||
monitor_ids.clear();
|
||||
}
|
||||
|
||||
void User::Copy( const User &u ) {
|
||||
void User::Copy(const User &u) {
|
||||
id=u.id;
|
||||
strncpy( username, u.username, sizeof(username)-1 );
|
||||
strncpy( password, u.password, sizeof(password)-1 );
|
||||
strncpy(username, u.username, sizeof(username)-1);
|
||||
strncpy(password, u.password, sizeof(password)-1);
|
||||
enabled = u.enabled;
|
||||
stream = u.stream;
|
||||
events = u.events;
|
||||
|
@ -75,7 +87,7 @@ void User::Copy( const User &u ) {
|
|||
monitor_ids = u.monitor_ids;
|
||||
}
|
||||
|
||||
bool User::canAccess( int monitor_id ) {
|
||||
bool User::canAccess(int monitor_id) {
|
||||
if ( monitor_ids.empty() )
|
||||
return true;
|
||||
|
||||
|
@ -89,54 +101,52 @@ bool User::canAccess( int monitor_id ) {
|
|||
|
||||
// Function to load a user from username and password
|
||||
// Please note that in auth relay mode = none, password is NULL
|
||||
User *zmLoadUser( const char *username, const char *password ) {
|
||||
User *zmLoadUser(const char *username, const char *password) {
|
||||
char sql[ZM_SQL_MED_BUFSIZ] = "";
|
||||
int username_length = strlen(username);
|
||||
char *safer_username = new char[(username_length * 2) + 1];
|
||||
|
||||
// According to docs, size of safer_whatever must be 2*length+1 due to unicode conversions + null terminator.
|
||||
mysql_real_escape_string(&dbconn, safer_username, username, username_length );
|
||||
|
||||
mysql_real_escape_string(&dbconn, safer_username, username, username_length);
|
||||
|
||||
snprintf(sql, sizeof(sql),
|
||||
"SELECT `Id`, `Username`, `Password`, `Enabled`, `Stream`+0, `Events`+0, `Control`+0, `Monitors`+0, `System`+0, `MonitorIds`"
|
||||
" FROM `Users` WHERE `Username` = '%s' AND `Enabled` = 1", safer_username );
|
||||
|
||||
" FROM `Users` WHERE `Username` = '%s' AND `Enabled` = 1", safer_username);
|
||||
|
||||
if ( mysql_query(&dbconn, sql) ) {
|
||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||
exit(mysql_errno(&dbconn));
|
||||
}
|
||||
delete safer_username;
|
||||
|
||||
MYSQL_RES *result = mysql_store_result(&dbconn);
|
||||
if ( !result ) {
|
||||
Error("Can't use query result: %s", mysql_error(&dbconn));
|
||||
exit(mysql_errno(&dbconn));
|
||||
}
|
||||
int n_users = mysql_num_rows(result);
|
||||
|
||||
if ( n_users != 1 ) {
|
||||
if ( mysql_num_rows(result) != 1 ) {
|
||||
mysql_free_result(result);
|
||||
Warning("Unable to authenticate user %s", username);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MYSQL_ROW dbrow = mysql_fetch_row(result);
|
||||
|
||||
User *user = new User(dbrow);
|
||||
mysql_free_result(result);
|
||||
|
||||
if (verifyPassword(username, password, user->getPassword())) {
|
||||
Info("Authenticated user '%s'", user->getUsername());
|
||||
mysql_free_result(result);
|
||||
delete safer_username;
|
||||
if ( !password ) {
|
||||
// relay type must be none
|
||||
return user;
|
||||
}
|
||||
else {
|
||||
Warning("Unable to authenticate user %s", username);
|
||||
mysql_free_result(result);
|
||||
return NULL;
|
||||
|
||||
if ( verifyPassword(username, password, user->getPassword()) ) {
|
||||
Info("Authenticated user '%s'", user->getUsername());
|
||||
return user;
|
||||
}
|
||||
|
||||
Warning("Unable to authenticate user %s", username);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
User *zmLoadTokenUser (std::string jwt_token_str, bool use_remote_addr ) {
|
||||
|
|
|
@ -23,25 +23,14 @@
|
|||
#ifndef ZM_USER_H
|
||||
#define ZM_USER_H
|
||||
|
||||
#if HAVE_GNUTLS_OPENSSL_H
|
||||
#include <gnutls/openssl.h>
|
||||
#endif
|
||||
#if HAVE_GNUTLS_GNUTLS_H
|
||||
#include <gnutls/gnutls.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_GCRYPT_H
|
||||
#include <gcrypt.h>
|
||||
#elif HAVE_LIBCRYPTO
|
||||
#include <openssl/md5.h>
|
||||
#endif // HAVE_L || HAVE_LIBCRYPTO
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
class User {
|
||||
public:
|
||||
typedef enum { PERM_NONE=1, PERM_VIEW, PERM_EDIT } Permission;
|
||||
|
||||
protected:
|
||||
class User {
|
||||
public:
|
||||
typedef enum { PERM_NONE = 1, PERM_VIEW, PERM_EDIT } Permission;
|
||||
|
||||
protected:
|
||||
int id;
|
||||
char username[32+1];
|
||||
char password[64+1];
|
||||
|
@ -53,32 +42,32 @@ protected:
|
|||
Permission system;
|
||||
std::vector<int> monitor_ids;
|
||||
|
||||
public:
|
||||
public:
|
||||
User();
|
||||
explicit User( MYSQL_ROW &dbrow );
|
||||
explicit User(const MYSQL_ROW &dbrow);
|
||||
~User();
|
||||
User( User &u ) { Copy(u); }
|
||||
void Copy( const User &u );
|
||||
User(User &u) { Copy(u); }
|
||||
void Copy(const User &u);
|
||||
User& operator=(const User &u) {
|
||||
Copy(u); return *this;
|
||||
}
|
||||
|
||||
const int Id() const { return id; }
|
||||
const char *getUsername() const { return( username ); }
|
||||
const char *getPassword() const { return( password ); }
|
||||
bool isEnabled() const { return( enabled ); }
|
||||
Permission getStream() const { return( stream ); }
|
||||
Permission getEvents() const { return( events ); }
|
||||
Permission getControl() const { return( control ); }
|
||||
Permission getMonitors() const { return( monitors ); }
|
||||
Permission getSystem() const { return( system ); }
|
||||
bool canAccess( int monitor_id );
|
||||
const char *getUsername() const { return username; }
|
||||
const char *getPassword() const { return password; }
|
||||
bool isEnabled() const { return enabled; }
|
||||
Permission getStream() const { return stream; }
|
||||
Permission getEvents() const { return events; }
|
||||
Permission getControl() const { return control; }
|
||||
Permission getMonitors() const { return monitors; }
|
||||
Permission getSystem() const { return system; }
|
||||
bool canAccess(int monitor_id);
|
||||
};
|
||||
|
||||
User *zmLoadUser( const char *username, const char *password=0 );
|
||||
User *zmLoadAuthUser( const char *auth, bool use_remote_addr );
|
||||
User *zmLoadTokenUser( std::string jwt, bool use_remote_addr);
|
||||
bool checkUser ( const char *username);
|
||||
bool checkPass (const char *password);
|
||||
User *zmLoadUser(const char *username, const char *password=0);
|
||||
User *zmLoadAuthUser(const char *auth, bool use_remote_addr);
|
||||
User *zmLoadTokenUser(std::string jwt, bool use_remote_addr);
|
||||
bool checkUser(const char *username);
|
||||
bool checkPass(const char *password);
|
||||
|
||||
#endif // ZM_USER_H
|
||||
|
|
|
@ -20,13 +20,14 @@
|
|||
|
||||
#define __STDC_FORMAT_MACROS 1
|
||||
|
||||
#include <cinttypes>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "zm.h"
|
||||
#include "zm_videostore.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cinttypes>
|
||||
|
||||
extern "C" {
|
||||
#include "libavutil/time.h"
|
||||
}
|
||||
|
@ -60,7 +61,7 @@ VideoStore::VideoStore(
|
|||
|
||||
Info("Opening video storage stream %s format: %s", filename, format);
|
||||
|
||||
ret = avformat_alloc_output_context2(&oc, NULL, NULL, filename);
|
||||
int ret = avformat_alloc_output_context2(&oc, NULL, NULL, filename);
|
||||
if ( ret < 0 ) {
|
||||
Warning(
|
||||
"Could not create video storage stream %s as no out ctx"
|
||||
|
@ -91,7 +92,7 @@ VideoStore::VideoStore(
|
|||
|
||||
oc->metadata = pmetadata;
|
||||
out_format = oc->oformat;
|
||||
out_format->flags |= AVFMT_TS_NONSTRICT; // allow non increasing dts
|
||||
out_format->flags |= AVFMT_TS_NONSTRICT; // allow non increasing dts
|
||||
|
||||
video_out_codec = avcodec_find_encoder(video_in_ctx->codec_id);
|
||||
if ( !video_out_codec ) {
|
||||
|
@ -136,7 +137,7 @@ VideoStore::VideoStore(
|
|||
video_out_ctx->time_base = video_in_ctx->time_base;
|
||||
if ( ! (video_out_ctx->time_base.num && video_out_ctx->time_base.den) ) {
|
||||
Debug(2,"No timebase found in video in context, defaulting to Q");
|
||||
video_out_ctx->time_base = AV_TIME_BASE_Q;
|
||||
video_out_ctx->time_base = AV_TIME_BASE_Q;
|
||||
}
|
||||
|
||||
zm_dump_codec(video_out_ctx);
|
||||
|
@ -193,19 +194,6 @@ VideoStore::VideoStore(
|
|||
video_out_stream->r_frame_rate = video_in_stream->r_frame_rate;
|
||||
}
|
||||
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
|
||||
#if 0
|
||||
if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) {
|
||||
//video_out_ctx->level = 32;I//
|
||||
video_out_ctx->bit_rate = 400*1024;
|
||||
video_out_ctx->max_b_frames = 1;
|
||||
if ( video_out_ctx->priv_data ) {
|
||||
av_opt_set(video_out_ctx->priv_data, "crf", "1", AV_OPT_SEARCH_CHILDREN);
|
||||
av_opt_set(video_out_ctx->priv_data, "preset", "ultrafast", 0);
|
||||
} else {
|
||||
Debug(2, "Not setting priv_data");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx);
|
||||
if ( ret < 0 ) {
|
||||
Error("Could not initialize video_out_ctx parameters");
|
||||
|
@ -388,6 +376,7 @@ VideoStore::VideoStore(
|
|||
} // VideoStore::VideoStore
|
||||
|
||||
bool VideoStore::open() {
|
||||
int ret;
|
||||
/* open the out file, if needed */
|
||||
if ( !(out_format->flags & AVFMT_NOFILE) ) {
|
||||
ret = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL);
|
||||
|
@ -424,20 +413,13 @@ bool VideoStore::open() {
|
|||
//avformat_free_context(oc);
|
||||
return false;
|
||||
}
|
||||
Debug(3,
|
||||
"Time bases: VIDEO in stream (%d/%d) in codec: (%d/%d) out "
|
||||
"stream: (%d/%d) out codec (%d/%d)",
|
||||
video_in_stream->time_base.num, video_in_stream->time_base.den,
|
||||
video_in_ctx->time_base.num, video_in_ctx->time_base.den,
|
||||
video_out_stream->time_base.num, video_out_stream->time_base.den,
|
||||
video_out_ctx->time_base.num,
|
||||
video_out_ctx->time_base.den);
|
||||
return true;
|
||||
} // end VideoStore::open()
|
||||
|
||||
VideoStore::~VideoStore() {
|
||||
|
||||
if ( oc->pb ) {
|
||||
int ret;
|
||||
|
||||
if ( audio_out_codec ) {
|
||||
// The codec queues data. We need to send a flush command and out
|
||||
|
@ -476,6 +458,7 @@ VideoStore::~VideoStore() {
|
|||
}
|
||||
#endif
|
||||
|
||||
dumpPacket(&pkt, "raw from encoder");
|
||||
// Need to adjust pts and dts and duration
|
||||
|
||||
pkt.stream_index = audio_out_stream->index;
|
||||
|
@ -486,6 +469,7 @@ VideoStore::~VideoStore() {
|
|||
audio_out_stream->time_base);
|
||||
// Scale the PTS of the outgoing packet to be the correct time base
|
||||
if ( pkt.pts != AV_NOPTS_VALUE ) {
|
||||
#if 0
|
||||
pkt.pts = av_rescale_q(
|
||||
pkt.pts,
|
||||
audio_out_ctx->time_base,
|
||||
|
@ -496,6 +480,12 @@ VideoStore::~VideoStore() {
|
|||
pkt.pts,
|
||||
audio_in_stream->time_base,
|
||||
audio_out_stream->time_base);
|
||||
#else
|
||||
pkt.pts = av_rescale_q(
|
||||
pkt.pts,
|
||||
audio_out_ctx->time_base,
|
||||
audio_out_stream->time_base);
|
||||
#endif
|
||||
|
||||
Debug(2, "audio pkt.pts = %" PRId64 " from first_pts(%" PRId64 ")",
|
||||
pkt.pts, audio_first_pts);
|
||||
|
@ -505,6 +495,7 @@ VideoStore::~VideoStore() {
|
|||
}
|
||||
|
||||
if ( pkt.dts != AV_NOPTS_VALUE ) {
|
||||
#if 0
|
||||
pkt.dts = av_rescale_q(
|
||||
pkt.dts,
|
||||
audio_out_ctx->time_base,
|
||||
|
@ -514,6 +505,12 @@ VideoStore::~VideoStore() {
|
|||
pkt.dts,
|
||||
audio_in_stream->time_base,
|
||||
audio_out_stream->time_base);
|
||||
#else
|
||||
pkt.dts = av_rescale_q(
|
||||
pkt.dts,
|
||||
audio_out_ctx->time_base,
|
||||
audio_out_stream->time_base);
|
||||
#endif
|
||||
Debug(2, "pkt.dts = %" PRId64 " - first_dts(%" PRId64 ")",
|
||||
pkt.dts, audio_first_dts);
|
||||
} else {
|
||||
|
@ -638,6 +635,7 @@ bool VideoStore::setup_resampler() {
|
|||
"Cannot do audio conversion to AAC");
|
||||
return false;
|
||||
#else
|
||||
int ret;
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
// Newer ffmpeg wants to keep everything separate... so have to lookup our own
|
||||
|
@ -656,7 +654,7 @@ bool VideoStore::setup_resampler() {
|
|||
#else
|
||||
// codec is already open in ffmpeg_camera
|
||||
audio_in_ctx = audio_in_stream->codec;
|
||||
audio_in_codec = (AVCodec *)audio_in_ctx->codec;
|
||||
audio_in_codec = reinterpret_cast<const AVCodec *>(audio_in_ctx->codec);
|
||||
//audio_in_codec = avcodec_find_decoder(audio_in_stream->codec->codec_id);
|
||||
#endif
|
||||
|
||||
|
@ -790,9 +788,9 @@ bool VideoStore::setup_resampler() {
|
|||
}
|
||||
|
||||
#if defined(HAVE_LIBSWRESAMPLE)
|
||||
if (!(fifo = av_audio_fifo_alloc(
|
||||
if ( !(fifo = av_audio_fifo_alloc(
|
||||
audio_out_ctx->sample_fmt,
|
||||
audio_out_ctx->channels, 1))) {
|
||||
audio_out_ctx->channels, 1)) ) {
|
||||
Error("Could not allocate FIFO");
|
||||
return false;
|
||||
}
|
||||
|
@ -870,7 +868,7 @@ bool VideoStore::setup_resampler() {
|
|||
NULL, audio_out_ctx->channels,
|
||||
audio_out_ctx->frame_size,
|
||||
audio_out_ctx->sample_fmt, 0);
|
||||
converted_in_samples = (uint8_t *)av_malloc(audioSampleBuffer_size);
|
||||
converted_in_samples = reinterpret_cast<uint8_t *>(av_malloc(audioSampleBuffer_size));
|
||||
|
||||
if ( !converted_in_samples ) {
|
||||
Error("Could not allocate converted in sample pointers");
|
||||
|
@ -966,15 +964,15 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
|
|||
//AV_NOPTS_VALUE;
|
||||
}
|
||||
// Just because the in stream wraps, doesn't mean the out needs to.
|
||||
// Really, if we are limiting ourselves to 10min segments I can't imagine every wrapping in the out.
|
||||
// So need to handle in wrap, without causing out wrap.
|
||||
// Really, if we are limiting ourselves to 10min segments I can't imagine every wrapping in the out.
|
||||
// So need to handle in wrap, without causing out wrap.
|
||||
|
||||
if ( ipkt->dts != AV_NOPTS_VALUE ) {
|
||||
if ( !video_first_dts ) {
|
||||
// && ( ipkt->dts >= 0 ) ) {
|
||||
// This is the first packet.
|
||||
opkt.dts = 0;
|
||||
Debug(1, "Starting video first_dts will become (%" PRId64 ")", ipkt->dts);
|
||||
Debug(2, "Starting video first_dts will become (%" PRId64 ")", ipkt->dts);
|
||||
video_first_dts = ipkt->dts;
|
||||
#if 1
|
||||
if ( audio_in_stream ) {
|
||||
|
@ -1008,49 +1006,27 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
|
|||
opkt.dts = video_out_stream->cur_dts;
|
||||
}
|
||||
|
||||
# if 1
|
||||
if ( opkt.dts < video_out_stream->cur_dts ) {
|
||||
Debug(1, "Fixing non-monotonic dts/pts dts %" PRId64 " pts %" PRId64 " stream %" PRId64,
|
||||
opkt.dts, opkt.pts, video_out_stream->cur_dts);
|
||||
opkt.dts = video_out_stream->cur_dts;
|
||||
if ( opkt.dts > opkt.pts ) {
|
||||
opkt.pts = opkt.dts;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if ( opkt.dts < video_out_stream->cur_dts ) {
|
||||
Debug(1, "Fixing non-monotonic dts/pts dts %" PRId64 " pts %" PRId64 " stream %" PRId64,
|
||||
opkt.dts, opkt.pts, video_out_stream->cur_dts);
|
||||
opkt.dts = video_out_stream->cur_dts;
|
||||
if ( opkt.dts > opkt.pts ) {
|
||||
opkt.pts = opkt.dts;
|
||||
}
|
||||
}
|
||||
|
||||
opkt.flags = ipkt->flags;
|
||||
opkt.pos = -1;
|
||||
opkt.data = ipkt->data;
|
||||
opkt.size = ipkt->size;
|
||||
opkt.stream_index = video_out_stream->index;
|
||||
|
||||
dumpPacket(video_out_stream, &opkt, "writing video packet");
|
||||
if ( (opkt.data == NULL) || (opkt.size < 1) ) {
|
||||
Warning("%s:%d: Mangled AVPacket: discarding frame", __FILE__, __LINE__);
|
||||
dumpPacket(video_in_stream, ipkt,"In Packet");
|
||||
dumpPacket(video_out_stream, &opkt);
|
||||
} else {
|
||||
ret = av_interleaved_write_frame(oc, &opkt);
|
||||
if ( ret < 0 ) {
|
||||
// There's nothing we can really do if the frame is rejected, just drop it
|
||||
// and get on with the next
|
||||
Warning(
|
||||
"%s:%d: Writing frame [av_interleaved_write_frame()] failed: %s(%d)",
|
||||
__FILE__, __LINE__, av_make_error_string(ret).c_str(), ret);
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
zm_dump_codecpar(video_in_stream->codecpar);
|
||||
zm_dump_codecpar(video_out_stream->codecpar);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
write_packet(&opkt, video_out_stream);
|
||||
zm_av_packet_unref(&opkt);
|
||||
|
||||
return 0;
|
||||
} // end int VideoStore::writeVideoFramePacket( AVPacket *ipkt )
|
||||
|
||||
int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
||||
int ret;
|
||||
|
||||
if ( !audio_out_stream ) {
|
||||
Debug(1, "Called writeAudioFramePacket when no audio_out_stream");
|
||||
|
@ -1066,6 +1042,20 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
|||
}
|
||||
|
||||
zm_dump_frame(in_frame, "In frame from decode");
|
||||
if ( in_frame->pts != AV_NOPTS_VALUE ) {
|
||||
if ( !audio_first_pts ) {
|
||||
audio_first_pts = in_frame->pts;
|
||||
Debug(1, "No audio_first_pts setting to %" PRId64, audio_first_pts);
|
||||
in_frame->pts = 0;
|
||||
} else {
|
||||
// out_frame_pts is in codec->timebase, audio_first_pts is in packet timebase.
|
||||
in_frame->pts = in_frame->pts - audio_first_pts;
|
||||
zm_dump_frame(in_frame, "in frame after pts adjustment");
|
||||
}
|
||||
} else {
|
||||
// sending AV_NOPTS_VALUE doesn't really work but we seem to get it in ffmpeg 2.8
|
||||
in_frame->pts = audio_next_pts;
|
||||
}
|
||||
|
||||
if ( !resample_audio() ) {
|
||||
//av_frame_unref(in_frame);
|
||||
|
@ -1099,12 +1089,19 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
|||
}
|
||||
|
||||
dumpPacket(audio_out_stream, &opkt, "raw opkt");
|
||||
Debug(1, "Duration before %d in %d/%d", opkt.duration,
|
||||
audio_out_ctx->time_base.num,
|
||||
audio_out_ctx->time_base.den);
|
||||
|
||||
opkt.duration = av_rescale_q(
|
||||
opkt.duration,
|
||||
audio_out_ctx->time_base,
|
||||
audio_out_stream->time_base);
|
||||
Debug(1, "Duration after %d in %d/%d", opkt.duration,
|
||||
audio_out_stream->time_base.num,
|
||||
audio_out_stream->time_base.den);
|
||||
// Scale the PTS of the outgoing packet to be the correct time base
|
||||
#if 0
|
||||
if ( ipkt->pts != AV_NOPTS_VALUE ) {
|
||||
if ( !audio_first_pts ) {
|
||||
opkt.pts = 0;
|
||||
|
@ -1134,19 +1131,62 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
|||
audio_out_ctx->time_base,
|
||||
audio_out_stream->time_base);
|
||||
opkt.dts -= audio_first_dts;
|
||||
Debug(2, "opkt.dts = %" PRId64 " from first_dts %" PRId64,
|
||||
Debug(2, "audio opkt.dts = %" PRId64 " from first_dts %" PRId64,
|
||||
opkt.dts, audio_first_dts);
|
||||
}
|
||||
audio_last_dts = opkt.dts;
|
||||
} else {
|
||||
opkt.dts = AV_NOPTS_VALUE;
|
||||
}
|
||||
#else
|
||||
opkt.pts = av_rescale_q(
|
||||
opkt.pts,
|
||||
audio_out_ctx->time_base,
|
||||
audio_out_stream->time_base);
|
||||
opkt.dts = av_rescale_q(
|
||||
opkt.dts,
|
||||
audio_out_ctx->time_base,
|
||||
audio_out_stream->time_base);
|
||||
#endif
|
||||
|
||||
write_packet(&opkt, audio_out_stream);
|
||||
zm_av_packet_unref(&opkt);
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
// While the encoder still has packets for us
|
||||
while ( !avcodec_receive_packet(audio_out_ctx, &opkt) ) {
|
||||
opkt.pts = av_rescale_q(
|
||||
opkt.pts,
|
||||
audio_out_ctx->time_base,
|
||||
audio_out_stream->time_base);
|
||||
opkt.dts = av_rescale_q(
|
||||
opkt.dts,
|
||||
audio_out_ctx->time_base,
|
||||
audio_out_stream->time_base);
|
||||
|
||||
dumpPacket(audio_out_stream, &opkt, "raw opkt");
|
||||
Debug(1, "Duration before %d in %d/%d", opkt.duration,
|
||||
audio_out_ctx->time_base.num,
|
||||
audio_out_ctx->time_base.den);
|
||||
|
||||
opkt.duration = av_rescale_q(
|
||||
opkt.duration,
|
||||
audio_out_ctx->time_base,
|
||||
audio_out_stream->time_base);
|
||||
Debug(1, "Duration after %d in %d/%d", opkt.duration,
|
||||
audio_out_stream->time_base.num,
|
||||
audio_out_stream->time_base.den);
|
||||
write_packet(&opkt, audio_out_stream);
|
||||
}
|
||||
#endif
|
||||
zm_av_packet_unref(&opkt);
|
||||
|
||||
} else {
|
||||
Debug(2,"copying");
|
||||
av_init_packet(&opkt);
|
||||
opkt.data = ipkt->data;
|
||||
opkt.size = ipkt->size;
|
||||
opkt.flags = ipkt->flags;
|
||||
|
||||
if ( ipkt->duration && (ipkt->duration != AV_NOPTS_VALUE) ) {
|
||||
opkt.duration = av_rescale_q(
|
||||
|
@ -1189,43 +1229,47 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
|||
} else {
|
||||
opkt.dts = AV_NOPTS_VALUE;
|
||||
}
|
||||
} // end if encoding or copying
|
||||
write_packet(&opkt, audio_out_stream);
|
||||
|
||||
zm_av_packet_unref(&opkt);
|
||||
} // end if encoding or copying
|
||||
|
||||
opkt.pos = -1;
|
||||
opkt.stream_index = audio_out_stream->index;
|
||||
opkt.flags = ipkt->flags;
|
||||
return 0;
|
||||
} // end int VideoStore::writeAudioFramePacket(AVPacket *ipkt)
|
||||
|
||||
if ( opkt.dts < audio_out_stream->cur_dts ) {
|
||||
int VideoStore::write_packet(AVPacket *pkt, AVStream *stream) {
|
||||
pkt->pos = -1;
|
||||
pkt->stream_index = stream->index;
|
||||
|
||||
if ( pkt->dts < stream->cur_dts ) {
|
||||
Warning("non increasing dts, fixing");
|
||||
opkt.dts = audio_out_stream->cur_dts;
|
||||
if ( opkt.dts > opkt.pts ) {
|
||||
pkt->dts = stream->cur_dts;
|
||||
if ( (pkt->pts != AV_NOPTS_VALUE) && (pkt->dts > pkt->pts) ) {
|
||||
Debug(1,
|
||||
"opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 ")."
|
||||
"pkt.dts(%" PRId64 ") must be <= pkt.pts(%" PRId64 ")."
|
||||
"Decompression must happen before presentation.",
|
||||
opkt.dts, opkt.pts);
|
||||
opkt.pts = opkt.dts;
|
||||
pkt->dts, pkt->pts);
|
||||
pkt->pts = pkt->dts;
|
||||
}
|
||||
} else if ( opkt.dts > opkt.pts ) {
|
||||
} else if ( (pkt->pts != AV_NOPTS_VALUE) && (pkt->dts > pkt->pts) ) {
|
||||
Debug(1,
|
||||
"opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 ")."
|
||||
"pkt.dts(%" PRId64 ") must be <= pkt.pts(%" PRId64 ")."
|
||||
"Decompression must happen before presentation.",
|
||||
opkt.dts, opkt.pts);
|
||||
opkt.dts = opkt.pts;
|
||||
pkt->dts, pkt->pts);
|
||||
pkt->dts = pkt->pts;
|
||||
}
|
||||
|
||||
dumpPacket(audio_out_stream, &opkt, "finished opkt");
|
||||
dumpPacket(stream, pkt, "finished pkt");
|
||||
|
||||
ret = av_interleaved_write_frame(oc, &opkt);
|
||||
int ret = av_interleaved_write_frame(oc, pkt);
|
||||
if ( ret != 0 ) {
|
||||
Error("Error writing audio frame packet: %s",
|
||||
Error("Error writing packet: %s",
|
||||
av_make_error_string(ret).c_str());
|
||||
} else {
|
||||
Debug(2, "Success writing audio frame");
|
||||
Debug(2, "Success writing packet");
|
||||
}
|
||||
zm_av_packet_unref(&opkt);
|
||||
return 0;
|
||||
} // end int VideoStore::writeAudioFramePacket(AVPacket *ipkt)
|
||||
return ret;
|
||||
} // end int VideoStore::write_packet(AVPacket *pkt, AVStream *stream)
|
||||
|
||||
int VideoStore::resample_audio() {
|
||||
// Resample the in_frame into the audioSampleBuffer until we process the whole
|
||||
|
@ -1234,7 +1278,7 @@ int VideoStore::resample_audio() {
|
|||
#if defined(HAVE_LIBSWRESAMPLE)
|
||||
Debug(2, "Converting %d to %d samples using swresample",
|
||||
in_frame->nb_samples, out_frame->nb_samples);
|
||||
ret = swr_convert_frame(resample_ctx, out_frame, in_frame);
|
||||
int ret = swr_convert_frame(resample_ctx, out_frame, in_frame);
|
||||
if ( ret < 0 ) {
|
||||
Error("Could not resample frame (error '%s')",
|
||||
av_make_error_string(ret).c_str());
|
||||
|
@ -1261,6 +1305,8 @@ int VideoStore::resample_audio() {
|
|||
|
||||
// AAC requires 1024 samples per encode. Our input tends to be something else, so need to buffer them.
|
||||
if ( frame_size > av_audio_fifo_size(fifo) ) {
|
||||
Debug(1, "Not enough samples in fifo for AAC codec frame_size %d > fifo size %d",
|
||||
frame_size, av_audio_fifo_size(fifo));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1310,4 +1356,4 @@ int VideoStore::resample_audio() {
|
|||
return 0;
|
||||
#endif
|
||||
return 1;
|
||||
} // end int VideoStore::resample_audio
|
||||
} // end int VideoStore::resample_audio
|
||||
|
|
|
@ -40,7 +40,6 @@ private:
|
|||
AVCodecContext *video_in_ctx;
|
||||
AVCodec *audio_in_codec;
|
||||
AVCodecContext *audio_in_ctx;
|
||||
int ret;
|
||||
|
||||
// The following are used when encoding the audio stream to AAC
|
||||
AVStream *audio_out_stream;
|
||||
|
@ -79,6 +78,8 @@ private:
|
|||
bool setup_resampler();
|
||||
int resample_audio();
|
||||
|
||||
int write_packet(AVPacket *pkt, AVStream *stream);
|
||||
|
||||
public:
|
||||
VideoStore(
|
||||
const char *filename_in,
|
||||
|
|
|
@ -86,31 +86,9 @@ commonprep () {
|
|||
git -C packpack pull origin master
|
||||
else
|
||||
echo "Cloning packpack github repo..."
|
||||
git clone https://github.com/packpack/packpack.git packpack
|
||||
git clone https://github.com/zoneminder/packpack.git packpack
|
||||
fi
|
||||
|
||||
# Rpm builds are broken in latest packpack master. Temporarily roll back.
|
||||
#git -C packpack checkout 7cf23ee
|
||||
|
||||
# Patch packpack
|
||||
patch --dry-run --silent -f -p1 < utils/packpack/packpack-rpm.patch
|
||||
if [ $? -eq 0 ]; then
|
||||
patch -p1 < utils/packpack/packpack-rpm.patch
|
||||
fi
|
||||
|
||||
# Skip deb lintian checks to speed up the build
|
||||
patch --dry-run --silent -f -p1 < utils/packpack/nolintian.patch
|
||||
if [ $? -eq 0 ]; then
|
||||
patch -p1 < utils/packpack/nolintian.patch
|
||||
fi
|
||||
|
||||
# fix 32bit rpm builds
|
||||
# FIXME: breaks arm rpm builds
|
||||
#patch --dry-run --silent -f -p1 < utils/packpack/setarch.patch
|
||||
#if [ $? -eq 0 ]; then
|
||||
# patch -p1 < utils/packpack/setarch.patch
|
||||
#fi
|
||||
|
||||
# The rpm specfile requires we download each submodule as a tarball then manually move it into place
|
||||
# Might as well do this for Debian as well, rather than git submodule init
|
||||
CRUDVER="3.1.0-zm"
|
||||
|
@ -177,9 +155,13 @@ installtrusty () {
|
|||
|
||||
if [ -e $pkgname ]; then
|
||||
sudo gdebi --quiet --non-interactive $pkgname
|
||||
echo "Return code from installing $?"
|
||||
mysql -uzmuser -pzmpass zm < db/test.monitor.sql
|
||||
echo "Return code from adding test monitor $?"
|
||||
sudo /usr/bin/zmpkg.pl start
|
||||
sudo /usr/bin/zmfilter.pl -f purgewhenfull
|
||||
echo "Return code from starting $?"
|
||||
sudo /usr/bin/zmfilter.pl --filter=purgewhenfull
|
||||
echo "Return code from running purgewhenfull $?"
|
||||
else
|
||||
echo
|
||||
echo "ERROR: The script cannot find the package $pkgname"
|
||||
|
@ -241,9 +223,9 @@ setrpmchangelog () {
|
|||
setdebchangelog () {
|
||||
DATE=`date -R`
|
||||
cat <<EOF > debian/changelog
|
||||
zoneminder ($VERSION-${DIST}-1) unstable; urgency=low
|
||||
zoneminder ($VERSION-${DIST}) ${DIST}; urgency=low
|
||||
*
|
||||
-- Isaac Connor <iconnor@connortechnology.com> $DATE
|
||||
-- Isaac Connor <isaac@zoneminder.com> $DATE
|
||||
EOF
|
||||
}
|
||||
|
||||
|
@ -312,7 +294,7 @@ checksanity
|
|||
# We don't want to build packages for all supported distros after every commit
|
||||
# Only build all packages when executed via cron
|
||||
# See https://docs.travis-ci.com/user/cron-jobs/
|
||||
if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then
|
||||
if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then
|
||||
commonprep
|
||||
|
||||
# Steps common to Redhat distros
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
* In production mode, flash messages redirect after a time interval.
|
||||
* In development mode, you need to click the flash message to continue.
|
||||
*/
|
||||
Configure::write('debug', 2);
|
||||
Configure::write('debug', 0);
|
||||
|
||||
/**
|
||||
* Configure the Error handler used to handle errors for your application. By default
|
||||
|
|
|
@ -91,7 +91,6 @@ class AppController extends Controller {
|
|||
require_once __DIR__ .'/../../../includes/session.php';
|
||||
$stateful = $this->request->query('stateful') ? $this->request->query('stateful') : $this->request->data('stateful');
|
||||
if ( $stateful ) {
|
||||
|
||||
zm_session_start();
|
||||
$_SESSION['remoteAddr'] = $_SERVER['REMOTE_ADDR']; // To help prevent session hijacking
|
||||
$_SESSION['username'] = $user['Username'];
|
||||
|
@ -99,6 +98,15 @@ class AppController extends Controller {
|
|||
// Need to save this in session, can't use the value in User because it is hashed
|
||||
$_SESSION['password'] = $_REQUEST['password'];
|
||||
}
|
||||
generateAuthHash(ZM_AUTH_HASH_IPS);
|
||||
session_write_close();
|
||||
} else if ( $_COOKIE['ZMSESSID'] and !$user ) {
|
||||
# Have a cookie set, try to load user by session
|
||||
if ( ! is_session_started() )
|
||||
zm_session_start();
|
||||
|
||||
ZM\Logger::Debug(print_r($_SESSION, true));
|
||||
$user = userFromSession();
|
||||
session_write_close();
|
||||
}
|
||||
}
|
||||
|
@ -142,10 +150,7 @@ class AppController extends Controller {
|
|||
return;
|
||||
}
|
||||
} # end if ! login or logout
|
||||
if ($user['APIEnabled'] == 0 ) {
|
||||
throw new UnauthorizedException(__('API Disabled'));
|
||||
return;
|
||||
}
|
||||
|
||||
} # end if ZM_OPT_AUTH
|
||||
// make sure populated user object has APIs enabled
|
||||
} # end function beforeFilter()
|
||||
|
|
|
@ -2,76 +2,50 @@
|
|||
namespace ZM;
|
||||
require_once('Storage.php');
|
||||
require_once('functions.php');
|
||||
require_once('Object.php');
|
||||
|
||||
$event_cache = array();
|
||||
class Event extends ZM_Object {
|
||||
protected static $table = 'Events';
|
||||
|
||||
class Event {
|
||||
|
||||
private $fields = array(
|
||||
'Id',
|
||||
'Name',
|
||||
'MonitorId',
|
||||
'StorageId',
|
||||
'SecondaryStorageId',
|
||||
'Name',
|
||||
'Cause',
|
||||
'StartTime',
|
||||
'EndTime',
|
||||
'Width',
|
||||
'Height',
|
||||
'Length',
|
||||
'Frames',
|
||||
'AlarmFrames',
|
||||
'DefaultVideo',
|
||||
'SaveJPEGs',
|
||||
'TotScore',
|
||||
'AvgScore',
|
||||
'MaxScore',
|
||||
'Archived',
|
||||
'Videoed',
|
||||
'Uploaded',
|
||||
'Emailed',
|
||||
'Messaged',
|
||||
'Executed',
|
||||
'Notes',
|
||||
'StateId',
|
||||
'Orientation',
|
||||
'DiskSpace',
|
||||
'Scheme',
|
||||
'Locked',
|
||||
protected $defaults = array(
|
||||
'Id' => null,
|
||||
'Name' => '',
|
||||
'MonitorId' => null,
|
||||
'StorageId' => null,
|
||||
'SecondaryStorageId' => null,
|
||||
'Cause' => '',
|
||||
'StartTime' => null,
|
||||
'EndTime' => null,
|
||||
'Width' => null,
|
||||
'Height' => null,
|
||||
'Length' => null,
|
||||
'Frames' => null,
|
||||
'AlarmFrames' => null,
|
||||
'DefaultVideo' => '',
|
||||
'SaveJPEGs' => 0,
|
||||
'TotScore' => 0,
|
||||
'AvgScore' => 0,
|
||||
'MaxScore' => 0,
|
||||
'Archived' => 0,
|
||||
'Videoed' => 0,
|
||||
'Uploaded' => 0,
|
||||
'Emailed' => 0,
|
||||
'Messaged' => 0,
|
||||
'Executed' => 0,
|
||||
'Notes' => '',
|
||||
'StateId' => 0,
|
||||
'Orientation' => 0,
|
||||
'DiskSpace' => null,
|
||||
'Scheme' => 0,
|
||||
'Locked' => 0,
|
||||
);
|
||||
public function __construct( $IdOrRow = null ) {
|
||||
$row = NULL;
|
||||
if ( $IdOrRow ) {
|
||||
if ( is_integer($IdOrRow) or is_numeric($IdOrRow) ) {
|
||||
$row = dbFetchOne('SELECT *,unix_timestamp(StartTime) AS Time FROM Events WHERE Id=?', NULL, array($IdOrRow));
|
||||
if ( ! $row ) {
|
||||
Error('Unable to load Event record for Id=' . $IdOrRow);
|
||||
}
|
||||
} elseif ( is_array($IdOrRow) ) {
|
||||
$row = $IdOrRow;
|
||||
} else {
|
||||
$backTrace = debug_backtrace();
|
||||
$file = $backTrace[1]['file'];
|
||||
$line = $backTrace[1]['line'];
|
||||
Error("Unknown argument passed to Event Constructor from $file:$line) Id was $IdOrRow");
|
||||
return;
|
||||
}
|
||||
public static function find( $parameters = array(), $options = array() ) {
|
||||
return ZM_Object::_find(get_class(), $parameters, $options);
|
||||
}
|
||||
|
||||
if ( $row ) {
|
||||
foreach ($row as $k => $v) {
|
||||
$this->{$k} = $v;
|
||||
}
|
||||
global $event_cache;
|
||||
$event_cache[$row['Id']] = $this;
|
||||
} else {
|
||||
$backTrace = debug_backtrace();
|
||||
$file = $backTrace[1]['file'];
|
||||
$line = $backTrace[1]['line'];
|
||||
Error('No row for Event ' . $IdOrRow . " from $file:$line");
|
||||
}
|
||||
} # end if isset($IdOrRow)
|
||||
} // end function __construct
|
||||
public static function find_one( $parameters = array(), $options = array() ) {
|
||||
return ZM_Object::_find_one(get_class(), $parameters, $options);
|
||||
}
|
||||
|
||||
public function Storage( $new = null ) {
|
||||
if ( $new ) {
|
||||
|
@ -108,24 +82,6 @@ class Event {
|
|||
return new Monitor();
|
||||
}
|
||||
|
||||
public function __call($fn, array $args){
|
||||
if ( count($args) ) {
|
||||
$this->{$fn} = $args[0];
|
||||
}
|
||||
if ( array_key_exists($fn, $this) ) {
|
||||
return $this->{$fn};
|
||||
|
||||
$backTrace = debug_backtrace();
|
||||
$file = $backTrace[0]['file'];
|
||||
$line = $backTrace[0]['line'];
|
||||
Warning("Unknown function call Event->$fn from $file:$line");
|
||||
$file = $backTrace[1]['file'];
|
||||
$line = $backTrace[1]['line'];
|
||||
Warning("Unknown function call Event->$fn from $file:$line");
|
||||
Warning(print_r($this, true));
|
||||
}
|
||||
}
|
||||
|
||||
public function Time() {
|
||||
if ( ! isset($this->{'Time'}) ) {
|
||||
$this->{'Time'} = strtotime($this->{'StartTime'});
|
||||
|
@ -170,24 +126,30 @@ class Event {
|
|||
Error('Event delete on event with empty Id');
|
||||
return;
|
||||
}
|
||||
if ( !ZM_OPT_FAST_DELETE ) {
|
||||
if ( ZM_OPT_FAST_DELETE ) {
|
||||
dbQuery('DELETE FROM Events WHERE Id = ?', array($this->{'Id'}));
|
||||
return;
|
||||
}
|
||||
|
||||
global $dbConn;
|
||||
$dbConn->beginTransaction();
|
||||
try {
|
||||
$this->lock();
|
||||
dbQuery('DELETE FROM Stats WHERE EventId = ?', array($this->{'Id'}));
|
||||
dbQuery('DELETE FROM Frames WHERE EventId = ?', array($this->{'Id'}));
|
||||
if ( $this->{'Scheme'} == 'Deep' ) {
|
||||
|
||||
# Assumption: All events have a start time
|
||||
# Assumption: All events have a start time
|
||||
$start_date = date_parse($this->{'StartTime'});
|
||||
if ( ! $start_date ) {
|
||||
Error('Unable to parse start time for event ' . $this->{'Id'} . ' not deleting files.');
|
||||
return;
|
||||
throw new Exception('Unable to parse start time for event ' . $this->{'Id'} . ' not deleting files.');
|
||||
}
|
||||
$start_date['year'] = $start_date['year'] % 100;
|
||||
|
||||
# So this is because ZM creates a link under the day pointing to the time that the event happened.
|
||||
# So this is because ZM creates a link under the day pointing to the time that the event happened.
|
||||
$link_path = $this->Link_Path();
|
||||
if ( ! $link_path ) {
|
||||
Error('Unable to determine link path for event '.$this->{'Id'}.' not deleting files.');
|
||||
return;
|
||||
throw new Exception('Unable to determine link path for event '.$this->{'Id'}.' not deleting files.');
|
||||
}
|
||||
|
||||
$Storage = $this->Storage();
|
||||
|
@ -195,10 +157,9 @@ class Event {
|
|||
|
||||
if ( $id_files = glob($eventlink_path) ) {
|
||||
if ( ! $eventPath = readlink($id_files[0]) ) {
|
||||
Error("Unable to read link at $id_files[0]");
|
||||
return;
|
||||
throw new Exception("Unable to read link at $id_files[0]");
|
||||
}
|
||||
# I know we are using arrays here, but really there can only ever be 1 in the array
|
||||
# I know we are using arrays here, but really there can only ever be 1 in the array
|
||||
$eventPath = preg_replace('/\.'.$this->{'Id'}.'$/', $eventPath, $id_files[0]);
|
||||
deletePath($eventPath);
|
||||
deletePath($id_files[0]);
|
||||
|
@ -215,13 +176,29 @@ class Event {
|
|||
} else {
|
||||
$eventPath = $this->Path();
|
||||
if ( ! $eventPath ) {
|
||||
Error('No event Path in Event delete. Not deleting');
|
||||
return;
|
||||
throw new Exception('No event Path in Event delete. Not deleting');
|
||||
}
|
||||
deletePath($eventPath);
|
||||
if ( $this->SecondaryStorageId() ) {
|
||||
$Storage = $this->SecondaryStorage();
|
||||
if ( $Storage->Id() ) {
|
||||
$eventPath = $Storage->Path().'/'.$this->Relative_Path();
|
||||
if ( ! $eventPath ) {
|
||||
Error('No event Path in Event delete. Not deleting');
|
||||
} else {
|
||||
deletePath($eventPath);
|
||||
}
|
||||
} # end if Storage
|
||||
} # end if has Secondary Storage
|
||||
} # USE_DEEP_STORAGE OR NOT
|
||||
} # ! ZM_OPT_FAST_DELETE
|
||||
dbQuery('DELETE FROM Events WHERE Id = ?', array($this->{'Id'}));
|
||||
dbQuery('DELETE FROM Events WHERE Id = ?', array($this->{'Id'}));
|
||||
$dbConn->commit();
|
||||
} catch (PDOException $e) {
|
||||
$dbConn->rollback();
|
||||
} catch (Exception $e) {
|
||||
Error($e->getMessage());
|
||||
$dbConn->rollback();
|
||||
}
|
||||
} # end Event->delete
|
||||
|
||||
public function getStreamSrc( $args=array(), $querySep='&' ) {
|
||||
|
@ -509,81 +486,6 @@ class Event {
|
|||
return $imageData;
|
||||
}
|
||||
|
||||
public static function find_one( $parameters = null, $options = null ) {
|
||||
global $event_cache;
|
||||
if (
|
||||
( count($parameters) == 1 ) and
|
||||
isset($parameters['Id']) and
|
||||
isset($event_cache[$parameters['Id']]) ) {
|
||||
return $event_cache[$parameters['Id']];
|
||||
}
|
||||
$results = Event::find( $parameters, $options );
|
||||
if ( count($results) > 1 ) {
|
||||
Error("Event Returned more than 1");
|
||||
return $results[0];
|
||||
} else if ( count($results) ) {
|
||||
return $results[0];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static function find( $parameters = null, $options = null ) {
|
||||
$sql = 'SELECT * FROM Events ';
|
||||
$values = array();
|
||||
|
||||
if ( $parameters ) {
|
||||
$fields = array();
|
||||
$sql .= 'WHERE ';
|
||||
foreach ( $parameters as $field => $value ) {
|
||||
if ( $value == null ) {
|
||||
$fields[] = $field.' IS NULL';
|
||||
} else if ( is_array( $value ) ) {
|
||||
$func = function(){return '?';};
|
||||
$fields[] = $field.' IN ('.implode(',', array_map( $func, $value ) ). ')';
|
||||
$values += $value;
|
||||
|
||||
} else {
|
||||
$fields[] = $field.'=?';
|
||||
$values[] = $value;
|
||||
}
|
||||
}
|
||||
$sql .= implode(' AND ', $fields );
|
||||
}
|
||||
if ( $options ) {
|
||||
if ( isset($options['order']) ) {
|
||||
$sql .= ' ORDER BY ' . $options['order'];
|
||||
}
|
||||
if ( isset($options['limit']) ) {
|
||||
if ( is_integer($options['limit']) or ctype_digit($options['limit']) ) {
|
||||
$sql .= ' LIMIT ' . $options['limit'];
|
||||
} else {
|
||||
$backTrace = debug_backtrace();
|
||||
$file = $backTrace[1]['file'];
|
||||
$line = $backTrace[1]['line'];
|
||||
Error("Invalid value for limit(".$options['limit'].") passed to Event::find from $file:$line");
|
||||
return array();
|
||||
}
|
||||
}
|
||||
}
|
||||
$filters = array();
|
||||
$result = dbQuery($sql, $values);
|
||||
if ( $result ) {
|
||||
$results = $result->fetchALL();
|
||||
foreach ( $results as $row ) {
|
||||
$filters[] = new Event($row);
|
||||
}
|
||||
}
|
||||
return $filters;
|
||||
}
|
||||
|
||||
public function save( ) {
|
||||
|
||||
$sql = 'UPDATE Events SET '.implode(', ', array_map( function($field) {return $field.'=?';}, $this->fields ) ) . ' WHERE Id=?';
|
||||
$values = array_map( function($field){return $this->{$field};}, $this->fields );
|
||||
$values[] = $this->{'Id'};
|
||||
dbQuery( $sql, $values );
|
||||
}
|
||||
public function link_to($text=null) {
|
||||
if ( !$text )
|
||||
$text = $this->{'Id'};
|
||||
|
@ -686,18 +588,14 @@ class Event {
|
|||
|
||||
public function can_delete() {
|
||||
if ( $this->Archived() ) {
|
||||
Logger::Debug("Am archived, can't delete");
|
||||
return false;
|
||||
}
|
||||
if ( !$this->EndTime() ) {
|
||||
Logger::Debug("No EndTime can't delete");
|
||||
return false;
|
||||
}
|
||||
if ( !canEdit('Events') ) {
|
||||
Logger::Debug("No permission to edit events, can't delete");
|
||||
return false;
|
||||
}
|
||||
Logger::Debug("Can delete: archived: " . $this->Archived() . " endtime: " . $this->EndTime() );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -167,6 +167,12 @@ class Filter extends ZM_Object {
|
|||
} # end if local or remote
|
||||
} # end foreach erver
|
||||
} # end function control
|
||||
public function execute() {
|
||||
$command = ZM_PATH_BIN.'/zmfilter.pl --filter_id='.escapeshellarg($this->Id());
|
||||
$result = exec($command, $output, $status);
|
||||
Logger::Debug("$command status:$status output:".implode("\n", $output));
|
||||
return $status;
|
||||
}
|
||||
|
||||
} # end class Filter
|
||||
|
||||
|
|
|
@ -252,5 +252,13 @@ class ZM_Object {
|
|||
unset($object_cache[$class][$this->{'Id'}]);
|
||||
}
|
||||
|
||||
} # end class Sensor Action
|
||||
public function lock() {
|
||||
$class = get_class($this);
|
||||
$table = $class::$table;
|
||||
$row = dbFetchOne("SELECT * FROM `$table` WHERE `Id`=?", NULL, array($this->Id()));
|
||||
if ( !$row ) {
|
||||
Error("Unable to lock $class record for Id=".$this->Id());
|
||||
}
|
||||
}
|
||||
} # end class Object
|
||||
?>
|
||||
|
|
|
@ -44,11 +44,9 @@ if ( $action == 'archive' ) {
|
|||
$dbConn->commit();
|
||||
$refreshParent = true;
|
||||
} else if ( $action == 'delete' ) {
|
||||
$dbConn->beginTransaction();
|
||||
foreach ( getAffectedIds('eids') as $markEid ) {
|
||||
deleteEvent($markEid);
|
||||
}
|
||||
$dbConn->commit();
|
||||
$refreshParent = true;
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -50,14 +50,6 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) {
|
|||
$_REQUEST['filter']['Query']['sort_field'] = validStr($_REQUEST['filter']['Query']['sort_field']);
|
||||
$_REQUEST['filter']['Query']['sort_asc'] = validStr($_REQUEST['filter']['Query']['sort_asc']);
|
||||
$_REQUEST['filter']['Query']['limit'] = validInt($_REQUEST['filter']['Query']['limit']);
|
||||
if ( $action == 'execute' ) {
|
||||
$_REQUEST['filter']['Name'] = '_TempFilter'.time();
|
||||
unset($_REQUEST['Id']);
|
||||
#$tempFilterName = '_TempFilter'.time();
|
||||
#$sql .= ' Name = \''.$tempFilterName.'\'';
|
||||
#} else {
|
||||
#$sql .= ' Name = '.dbEscape($_REQUEST['filter']['Name']);
|
||||
}
|
||||
|
||||
$_REQUEST['filter']['AutoCopy'] = empty($_REQUEST['filter']['AutoCopy']) ? 0 : 1;
|
||||
$_REQUEST['filter']['AutoMove'] = empty($_REQUEST['filter']['AutoMove']) ? 0 : 1;
|
||||
|
@ -102,19 +94,28 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) {
|
|||
if ( $filter->Background() )
|
||||
$filter->control('stop');
|
||||
} else {
|
||||
# COuld be execute
|
||||
if ( 0 ) {
|
||||
dbQuery('INSERT INTO Filters SET'.$sql);
|
||||
$_REQUEST['Id'] = dbInsertId();
|
||||
$filter = new ZM\Filter($_REQUEST['Id']);
|
||||
}
|
||||
|
||||
if ( $action == 'execute' ) {
|
||||
if ( count($changes) ) {
|
||||
$filter->Name('_TempFilter'.time());
|
||||
$filter->Id(null);
|
||||
}
|
||||
} else if ( $action == 'SaveAs' ) {
|
||||
$filter->Id(null);
|
||||
}
|
||||
$filter->save($changes);
|
||||
|
||||
// We update the request id so that the newly saved filter is auto-selected
|
||||
$_REQUEST['Id'] = $filter->Id();
|
||||
}
|
||||
if ( $filter->Background() )
|
||||
$filter->control('start');
|
||||
|
||||
if ( $action == 'execute' ) {
|
||||
executeFilter($_REQUEST['Id']);
|
||||
$filter->execute();
|
||||
if ( count($changes) )
|
||||
$filter->delete();
|
||||
|
||||
$view = 'events';
|
||||
}
|
||||
|
||||
|
|
|
@ -83,6 +83,9 @@ if ( $action == 'monitor' ) {
|
|||
dbQuery('UPDATE Monitors SET '.implode(', ', $changes).' WHERE Id=?', array($mid));
|
||||
// Groups will be added below
|
||||
if ( isset($changes['Name']) or isset($changes['StorageId']) ) {
|
||||
// creating symlinks when symlink already exists reports errors, but is perfectly ok
|
||||
error_reporting(0);
|
||||
|
||||
$OldStorage = new ZM\Storage($monitor['StorageId']);
|
||||
$saferOldName = basename($monitor['Name']);
|
||||
if ( file_exists($OldStorage->Path().'/'.$saferOldName) )
|
||||
|
@ -95,8 +98,11 @@ if ( $action == 'monitor' ) {
|
|||
}
|
||||
}
|
||||
$saferNewName = basename($_REQUEST['newMonitor']['Name']);
|
||||
if ( !symlink($NewStorage->Path().'/'.$mid, $NewStorage->Path().'/'.$saferNewName) ) {
|
||||
ZM\Warning('Unable to symlink ' . $NewStorage->Path().'/'.$mid . ' to ' . $NewStorage->Path().'/'.$saferNewName);
|
||||
$link_path = $NewStorage->Path().'/'.$saferNewName;
|
||||
if ( !symlink($NewStorage->Path().'/'.$mid, $link_path) ) {
|
||||
if ( ! ( file_exists($link_path) and is_link($link_path) ) ) {
|
||||
ZM\Warning('Unable to symlink ' . $NewStorage->Path().'/'.$mid . ' to ' . $NewStorage->Path().'/'.$saferNewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( isset($changes['Width']) || isset($changes['Height']) ) {
|
||||
|
|
|
@ -188,7 +188,7 @@ function getAuthUser($auth) {
|
|||
|
||||
if ( $auth == $authHash ) {
|
||||
return $user;
|
||||
} // en dif $auth == $authHash
|
||||
} // end if $auth == $authHash
|
||||
} // end foreach hour
|
||||
} // end foreach user
|
||||
} // end if using auth hash
|
||||
|
@ -243,6 +243,27 @@ function canEdit($area, $mid=false) {
|
|||
return ( $user[$area] == 'Edit' && ( !$mid || visibleMonitor($mid) ));
|
||||
}
|
||||
|
||||
function userFromSession() {
|
||||
$user = null; // Not global
|
||||
if ( isset($_SESSION['username']) ) {
|
||||
if ( ZM_AUTH_HASH_LOGINS and (ZM_AUTH_RELAY == 'hashed') ) {
|
||||
# Extra validation, if logged in, then the auth hash will be set in the session, so we can validate it.
|
||||
# This prevent session modification to switch users
|
||||
if ( isset($_SESSION['AuthHash'.$_SESSION['remoteAddr']]) )
|
||||
$user = getAuthUser($_SESSION['AuthHash'.$_SESSION['remoteAddr']]);
|
||||
else
|
||||
ZM\Logger::Debug("No auth hash in session, there should have been");
|
||||
} else {
|
||||
# Need to refresh permissions and validate that the user still exists
|
||||
$sql = 'SELECT * FROM Users WHERE Enabled=1 AND Username=?';
|
||||
$user = dbFetchOne($sql, NULL, array($_SESSION['username']));
|
||||
}
|
||||
} else {
|
||||
ZM\Logger::Debug('No username in session');
|
||||
}
|
||||
return $user;
|
||||
}
|
||||
|
||||
if ( ZM_OPT_USE_AUTH ) {
|
||||
if ( !empty($_REQUEST['token']) ) {
|
||||
$ret = validateToken($_REQUEST['token'], 'access');
|
||||
|
@ -250,23 +271,7 @@ if ( ZM_OPT_USE_AUTH ) {
|
|||
} else {
|
||||
// Non token based auth
|
||||
|
||||
if ( isset($_SESSION['username']) ) {
|
||||
if ( ZM_AUTH_HASH_LOGINS and (ZM_AUTH_RELAY == 'hashed') ) {
|
||||
# Extra validation, if logged in, then the auth hash will be set in the session, so we can validate it.
|
||||
# This prevent session modification to switch users
|
||||
if ( isset($_SESSION['AuthHash'.$_SESSION['remoteAddr']]) )
|
||||
$user = getAuthUser($_SESSION['AuthHash'.$_SESSION['remoteAddr']]);
|
||||
else
|
||||
ZM\Logger::Debug("No auth hash in session, there should have been");
|
||||
|
||||
} else {
|
||||
# Need to refresh permissions and validate that the user still exists
|
||||
$sql = 'SELECT * FROM Users WHERE Enabled=1 AND Username=?';
|
||||
$user = dbFetchOne($sql, NULL, array($_SESSION['username']));
|
||||
}
|
||||
} else {
|
||||
ZM\Logger::Debug("No username in session");
|
||||
}
|
||||
$user = userFromSession();
|
||||
|
||||
if ( ZM_AUTH_HASH_LOGINS && empty($user) && !empty($_REQUEST['auth']) ) {
|
||||
$user = getAuthUser($_REQUEST['auth']);
|
||||
|
|
|
@ -56,7 +56,7 @@ function dbConnect() {
|
|||
|
||||
$dbConn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
|
||||
$dbConn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
} catch(PDOException $ex ) {
|
||||
} catch(PDOException $ex) {
|
||||
echo 'Unable to connect to ZM db.' . $ex->getMessage();
|
||||
error_log('Unable to connect to ZM DB ' . $ex->getMessage());
|
||||
$dbConn = null;
|
||||
|
|
|
@ -414,6 +414,7 @@ function getEventDefaultVideoPath( $event ) {
|
|||
}
|
||||
|
||||
function deletePath( $path ) {
|
||||
ZM\Logger::Debug("Deleting $path");
|
||||
if ( is_dir( $path ) ) {
|
||||
system( escapeshellcmd( 'rm -rf '.$path ) );
|
||||
} else if ( file_exists($path) ) {
|
||||
|
@ -973,13 +974,6 @@ Logger::Debug("generating Video $command: result($result outptu:(".implode("\n",
|
|||
return( $status?"":rtrim($result) );
|
||||
}
|
||||
|
||||
function executeFilter( $filter_id ) {
|
||||
$command = ZM_PATH_BIN.'/zmfilter.pl --filter_id '.escapeshellarg($filter_id);
|
||||
$result = exec($command, $output, $status);
|
||||
dbQuery('DELETE FROM Filters WHERE Id=?', array($filter_id));
|
||||
return $status;
|
||||
}
|
||||
|
||||
# This takes more than one scale amount, so it runs through each and alters dimension.
|
||||
# I can't imagine why you would want to do that.
|
||||
function reScale( $dimension, $dummy ) {
|
||||
|
@ -1213,6 +1207,7 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&') {
|
|||
case 'DiskSpace':
|
||||
case 'MonitorId':
|
||||
case 'StorageId':
|
||||
case 'SecondaryStorageId':
|
||||
case 'Length':
|
||||
case 'Frames':
|
||||
case 'AlarmFrames':
|
||||
|
|
|
@ -21,11 +21,18 @@ function zm_session_start() {
|
|||
|
||||
session_start();
|
||||
$_SESSION['remoteAddr'] = $_SERVER['REMOTE_ADDR']; // To help prevent session hijacking
|
||||
$now = time();
|
||||
// Do not allow to use expired session ID
|
||||
if ( !empty($_SESSION['last_time']) && ($_SESSION['last_time'] < (time() - 180)) ) {
|
||||
if ( !empty($_SESSION['last_time']) && ($_SESSION['last_time'] < ($now - 180)) ) {
|
||||
ZM\Info('Destroying session due to timeout. ');
|
||||
session_destroy();
|
||||
session_start();
|
||||
} else if ( !empty($_SESSION['generated_at']) ) {
|
||||
ZM\Logger::Debug("Have generated_at: " . $_SESSION['generated_at']);
|
||||
if ( $_SESSION['generated_at']<($now-(ZM_COOKIE_LIFETIME/2)) ) {
|
||||
ZM\Logger::Debug("Regenerating session because generated_at " . $_SESSION['generated_at'] . ' < ' . $now . '-'.ZM_COOKIE_LIFETIME.'/2 = '.($now-ZM_COOKIE_LIFETIME/2));
|
||||
zm_session_regenerate_id();
|
||||
}
|
||||
}
|
||||
} // function zm_session_start()
|
||||
|
||||
|
@ -44,6 +51,7 @@ function zm_session_regenerate_id() {
|
|||
session_start();
|
||||
session_regenerate_id();
|
||||
unset($_SESSION['last_time']);
|
||||
$_SESSION['generated_at'] = time();
|
||||
} // function zm_session_regenerate_id()
|
||||
|
||||
function is_session_started() {
|
||||
|
|
|
@ -143,7 +143,6 @@ if (
|
|||
|
||||
# Only one request can open the session file at a time, so let's close the session here to improve concurrency.
|
||||
# Any file/page that sets session variables must re-open it.
|
||||
session_write_close();
|
||||
|
||||
require_once('includes/lang.php');
|
||||
|
||||
|
@ -176,6 +175,7 @@ if ( isset($_REQUEST['request']) )
|
|||
$request = detaintPath($_REQUEST['request']);
|
||||
|
||||
require_once('includes/auth.php');
|
||||
session_write_close();
|
||||
|
||||
foreach ( getSkinIncludes('skin.php') as $includeFile ) {
|
||||
require_once $includeFile;
|
||||
|
@ -210,7 +210,7 @@ if (
|
|||
}
|
||||
|
||||
# Need to include actions because it does auth
|
||||
if ( $action ) {
|
||||
if ( $action and !$request ) {
|
||||
if ( file_exists('includes/actions/'.$view.'.php') ) {
|
||||
ZM\Logger::Debug("Including includes/actions/$view.php");
|
||||
require_once('includes/actions/'.$view.'.php');
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
input[type="url"] {
|
||||
input[name="newStorage[Name]"],
|
||||
input[name="newStorage[Path]"],
|
||||
input[name="newStorage[Url]"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -152,8 +152,8 @@ if ( canEdit('Events') ) {
|
|||
?>
|
||||
<div id="deleteEvent"><button type="button" data-on-click="deleteEvent" <?php echo $Event->can_delete() ? '' : ' disabled="disabled" title="'.$Event->cant_delete_reason().'"' ?>><?php echo translate('Delete') ?></button></div>
|
||||
<div id="editEvent"><button type="button" data-on-click="editEvent"><?php echo translate('Edit') ?></button></div>
|
||||
<div id="archiveEvent"<?php echo $Event->Archived == 1 ? ' class="hidden"' : '' ?>><button type="button" data-on-click="archiveEvent"><?php echo translate('Archive') ?></button></div>
|
||||
<div id="unarchiveEvent"<?php echo $Event->Archived == 0 ? ' class="hidden"' : '' ?>><button type="button" data-on-click="unarchiveEvent"><?php echo translate('Unarchive') ?></button></div>
|
||||
<div id="archiveEvent"<?php echo $Event->Archived() == 1 ? ' class="hidden"' : '' ?>><button type="button" data-on-click="archiveEvent"><?php echo translate('Archive') ?></button></div>
|
||||
<div id="unarchiveEvent"<?php echo $Event->Archived() == 0 ? ' class="hidden"' : '' ?>><button type="button" data-on-click="unarchiveEvent"><?php echo translate('Unarchive') ?></button></div>
|
||||
<?php
|
||||
} // end if can edit Events
|
||||
?>
|
||||
|
|
|
@ -28,9 +28,9 @@ require_once('includes/Event.php');
|
|||
$countSql = 'SELECT count(E.Id) AS EventCount FROM Monitors AS M INNER JOIN Events AS E ON (M.Id = E.MonitorId) WHERE';
|
||||
$eventsSql = 'SELECT E.*,M.Name AS MonitorName,M.DefaultScale FROM Monitors AS M INNER JOIN Events AS E on (M.Id = E.MonitorId) WHERE';
|
||||
if ( $user['MonitorIds'] ) {
|
||||
$user_monitor_ids = ' M.Id in ('.$user['MonitorIds'].')';
|
||||
$countSql .= $user_monitor_ids;
|
||||
$eventsSql .= $user_monitor_ids;
|
||||
$user_monitor_ids = ' M.Id in ('.$user['MonitorIds'].')';
|
||||
$countSql .= $user_monitor_ids;
|
||||
$eventsSql .= $user_monitor_ids;
|
||||
} else {
|
||||
$countSql .= ' 1';
|
||||
$eventsSql .= ' 1';
|
||||
|
@ -192,24 +192,23 @@ while ( $event_row = dbFetchNext($results) ) {
|
|||
<tr<?php if ($event->Archived()) echo ' class="archived"' ?>>
|
||||
<td class="colId"><a href="?view=event&eid=<?php echo $event->Id().$filterQuery.$sortQuery.'&page=1">'.$event->Id().($event->Archived()?'*':'') ?></a></td>
|
||||
<td class="colName"><a href="?view=event&eid=<?php echo $event->Id().$filterQuery.$sortQuery.'&page=1">'.validHtmlStr($event->Name()).($event->Archived()?'*':'') ?></a></td>
|
||||
<td class="colMonitorName"><?php echo makePopupLink( '?view=monitor&mid='.$event->MonitorId(), 'zmMonitor'.$event->Monitorid(), 'monitor', $event->MonitorName(), canEdit( 'Monitors' ) ) ?></td>
|
||||
<td class="colMonitorName"><?php echo makePopupLink( '?view=monitor&mid='.$event->MonitorId(), 'zmMonitor'.$event->MonitorId(), 'monitor', $event->MonitorName(), canEdit( 'Monitors' ) ) ?></td>
|
||||
<td class="colCause"><?php echo makePopupLink( '?view=eventdetail&eid='.$event->Id(), 'zmEventDetail', 'eventdetail', validHtmlStr($event->Cause()), canEdit( 'Events' ), 'title="'.htmlspecialchars($event->Notes()).'"' ) ?>
|
||||
<?php
|
||||
# display notes as small text
|
||||
if ($event->Notes()) {
|
||||
# if notes include detection objects, then link it to objdetect.jpg
|
||||
if (strpos($event->Notes(),"detected:")!== false){
|
||||
# make a link
|
||||
echo makePopupLink( '?view=image&eid='.$event->Id().'&fid=objdetect', 'zmImage',
|
||||
array('image', reScale($event->Width(), $scale), reScale($event->Height(), $scale)),
|
||||
"<div class=\"small text-nowrap text-muted\"><u>".$event->Notes()."</u></div>");
|
||||
}
|
||||
elseif ($event->Notes() != 'Forced Web: ') {
|
||||
echo "<br/><div class=\"small text-nowrap text-muted\">".$event->Notes()."</div>";
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<?php
|
||||
# display notes as small text
|
||||
if ($event->Notes()) {
|
||||
# if notes include detection objects, then link it to objdetect.jpg
|
||||
if (strpos($event->Notes(),'detected:')!== false){
|
||||
# make a link
|
||||
echo makePopupLink( '?view=image&eid='.$event->Id().'&fid=objdetect', 'zmImage',
|
||||
array('image', reScale($event->Width(), $scale), reScale($event->Height(), $scale)),
|
||||
"<div class=\"small text-nowrap text-muted\"><u>".$event->Notes()."</u></div>");
|
||||
}
|
||||
elseif ($event->Notes() != 'Forced Web: ') {
|
||||
echo "<br/><div class=\"small text-nowrap text-muted\">".$event->Notes()."</div>";
|
||||
}
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td class="colTime"><?php echo strftime(STRF_FMT_DATETIME_SHORTER, strtotime($event->StartTime())) .
|
||||
( $event->EndTime() ? ' until ' . strftime(STRF_FMT_DATETIME_SHORTER, strtotime($event->EndTime()) ) : '' ) ?>
|
||||
|
@ -230,7 +229,18 @@ while ( $event_row = dbFetchNext($results) ) {
|
|||
<?php
|
||||
if ( count($storage_areas) > 1 ) {
|
||||
?>
|
||||
<td class="colStorage"><?php echo isset($StorageById[$event->StorageId()]) ? $StorageById[$event->StorageId()]->Name() : '' ?></td>
|
||||
<td class="colStorage">
|
||||
<?php
|
||||
if ( $event->StorageId() ) {
|
||||
echo isset($StorageById[$event->StorageId()]) ? $StorageById[$event->StorageId()]->Name() : 'Unknown Storage Id: '.$event->StorageId();
|
||||
} else {
|
||||
echo 'Default';
|
||||
}
|
||||
if ( $event->SecondaryStorageId() ) {
|
||||
echo '<br/>'.(isset($StorageById[$event->SecondaryStorageId()]) ? $StorageById[$event->SecondaryStorageId()]->Name() : 'Unknown Storage Id '.$event->SecondaryStorageId());
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
|
||||
<?php
|
||||
}
|
||||
|
@ -247,7 +257,7 @@ while ( $event_row = dbFetchNext($results) ) {
|
|||
$streamSrc = $event->getStreamSrc(array(
|
||||
'mode'=>'jpeg', '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($event->ThumbnailWidth()) .'px;height:'. validInt($event->ThumbnailHeight()).'px;" stream_src="'.$streamSrc.'" still_src="'.$imgSrc.'"/>';
|
||||
$imgHtml = '<img id="thumbnail'.$event->Id().'" src="'.$imgSrc.'" alt="'. validHtmlStr('Event '.$event->Id()) .'" style="width:'. validInt($event->ThumbnailWidth()) .'px;height:'. validInt($event->ThumbnailHeight()).'px;" stream_src="'.$streamSrc.'" still_src="'.$imgSrc.'"/>';
|
||||
echo '<a href="?view=event&eid='. $event->Id().$filterQuery.$sortQuery.'&page=1">'.$imgHtml.'</a>';
|
||||
echo '</td>';
|
||||
} // end if ZM_WEB_LIST_THUMBS
|
||||
|
|
|
@ -144,7 +144,7 @@ while ( $event_row = dbFetchNext($results) ) {
|
|||
<tr<?php echo $event->Archived() ? ' class="archived"' : '' ?>>
|
||||
<td class="colId"><a href="?view=event&eid=<?php echo $event->Id().$filterQuery.$sortQuery ?>&page=1"><?php echo $event->Id().($event->Archived()?'*':'') ?></a></td>
|
||||
<td class="colName"><a href="?view=event&eid=<?php echo $event->Id().$filterQuery.$sortQuery ?>&page=1"><?php echo validHtmlStr($event->Name()).($event->Archived()?'*':'') ?></a></td>
|
||||
<td class="colMonitorName"><?php echo makePopupLink( '?view=monitor&mid='.$event->MonitorId(), 'zmMonitor'.$event->Monitorid(), 'monitor', $event->MonitorName(), canEdit( 'Monitors' ) ) ?></td>
|
||||
<td class="colMonitorName"><?php echo makePopupLink( '?view=monitor&mid='.$event->MonitorId(), 'zmMonitor'.$event->MonitorId(), 'monitor', $event->MonitorName(), canEdit( 'Monitors' ) ) ?></td>
|
||||
<td class="colCause"><?php echo makePopupLink( '?view=eventdetail&eid='.$event->Id(), 'zmEventDetail', 'eventdetail', validHtmlStr($event->Cause()), canEdit( 'Events' ), 'title="'.htmlspecialchars($event->Notes()).'"' ) ?></td>
|
||||
<td class="colTime"><?php echo strftime(STRF_FMT_DATETIME_SHORTER, strtotime($event->StartTime())) .
|
||||
( $event->EndTime() ? ' until ' . strftime(STRF_FMT_DATETIME_SHORTER, strtotime($event->EndTime()) ) : '' ) ?>
|
||||
|
|
|
@ -201,8 +201,9 @@ function changeReplayMode() {
|
|||
}
|
||||
|
||||
var streamParms = "view=request&request=stream&connkey="+connKey;
|
||||
if ( auth_hash )
|
||||
streamCmdParms += '&auth='+auth_hash;
|
||||
if ( auth_hash ) {
|
||||
streamParms += '&auth='+auth_hash;
|
||||
}
|
||||
var streamCmdTimer = null;
|
||||
|
||||
var streamStatus = null;
|
||||
|
@ -312,7 +313,6 @@ function playClicked( ) {
|
|||
vjsPlay(); //handles fast forward and rewind
|
||||
}
|
||||
} else {
|
||||
console.log("sending"+streamParms+"&command="+CMD_PLAY);
|
||||
streamReq.send(streamParms+"&command="+CMD_PLAY);
|
||||
streamPlay();
|
||||
}
|
||||
|
@ -600,8 +600,9 @@ var eventReq = new Request.JSON( {url: thisUrl, method: 'get', timeout: AJAX_TIM
|
|||
|
||||
function eventQuery( eventId ) {
|
||||
var eventParms = "view=request&request=status&entity=event&id="+eventId;
|
||||
if ( auth_hash )
|
||||
eventParms += '&auth='+auth_hash;
|
||||
if ( auth_hash ) {
|
||||
eventParms += '&auth='+auth_hash;
|
||||
}
|
||||
eventReq.send( eventParms );
|
||||
}
|
||||
|
||||
|
@ -900,14 +901,15 @@ function getActResponse( respObj, respText ) {
|
|||
|
||||
var actReq = new Request.JSON( {url: thisUrl, method: 'get', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getActResponse} );
|
||||
|
||||
function actQuery( action, parms ) {
|
||||
function actQuery(action, parms) {
|
||||
var actParms = "view=request&request=event&id="+eventData.Id+"&action="+action;
|
||||
if ( auth_hash )
|
||||
actParms += '&auth='+auth_hash;
|
||||
if ( parms != null ) {
|
||||
actParms += "&"+Object.toQueryString( parms );
|
||||
if ( auth_hash ) {
|
||||
actParms += '&auth='+auth_hash;
|
||||
}
|
||||
actReq.send( actParms );
|
||||
if ( parms != null ) {
|
||||
actParms += "&"+Object.toQueryString(parms);
|
||||
}
|
||||
actReq.send(actParms);
|
||||
}
|
||||
|
||||
function deleteEvent() {
|
||||
|
|
|
@ -36,7 +36,7 @@ var eventData = {
|
|||
Frames: '<?php echo $Event->Frames() ?>',
|
||||
MonitorName: '<?php echo $Monitor->Name() ?>'
|
||||
};
|
||||
var monitorUrl = '<?php echo $Monitor->UrlToIndex(); ?>';
|
||||
var monitorUrl = '<?php echo $Event->Storage()->Server()->UrlToIndex(); ?>';
|
||||
|
||||
var filterQuery = '<?php echo isset($filterQuery)?validJsStr(htmlspecialchars_decode($filterQuery)):'' ?>';
|
||||
var sortQuery = '<?php echo isset($sortQuery)?validJsStr(htmlspecialchars_decode($sortQuery)):'' ?>';
|
||||
|
|
|
@ -30,13 +30,17 @@ function validateForm( form ) {
|
|||
|
||||
function updateButtons(element) {
|
||||
var form = element.form;
|
||||
|
||||
console.log(element);
|
||||
if ( element.type == 'checkbox' && element.checked ) {
|
||||
form.elements['executeButton'].disabled = false;
|
||||
} else {
|
||||
var canExecute = false;
|
||||
if ( form.elements['filter[AutoArchive]'] && form.elements['filter[AutoArchive]'].checked ) {
|
||||
canExecute = true;
|
||||
} else if ( form.elements['filter[AutoCopy]'] && form.elements['filter[AutoCopy]'].checked ) {
|
||||
canExecute = true;
|
||||
} else if ( form.elements['filter[AutoMove]'] && form.elements['filter[AutoMove]'].checked ) {
|
||||
canExecute = true;
|
||||
} else if ( form.elements['filter[AutoVideo]'] && form.elements['filter[AutoVideo]'].checked ) {
|
||||
canExecute = true;
|
||||
} else if ( form.elements['filter[AutoUpload]'] && form.elements['filter[AutoUpload]'].checked ) {
|
||||
|
|
|
@ -155,9 +155,8 @@ function getImageSource(monId, time) {
|
|||
frame_id = Frame.FrameId + parseInt( (NextFrame.FrameId-Frame.FrameId) * ( time-Frame.TimeStampSecs )/duration );
|
||||
//console.log("Have NextFrame: duration: " + duration + " frame_id = " + frame_id + " from " + NextFrame.FrameId + ' - ' + Frame.FrameId + " time: " + (time-Frame.TimeStampSecs) );
|
||||
} else {
|
||||
frame_id = Frame.FrameId;
|
||||
}
|
||||
|
||||
frame_id = Frame.FrameId;
|
||||
}
|
||||
} else {
|
||||
frame_id = Frame.FrameId;
|
||||
console.log("No NextFrame");
|
||||
|
@ -1010,7 +1009,8 @@ function initPage() {
|
|||
$j('#maxTime').datetimepicker({
|
||||
timeFormat: "HH:mm:ss",
|
||||
dateFormat: "yy-mm-dd",
|
||||
minDate: $j('#minTime').val(),
|
||||
//minDate: $j('#minTime').val(),
|
||||
minDate: -7,
|
||||
maxDate: +0,
|
||||
constrainInput: false,
|
||||
onClose: function(newDate, oldData) {
|
||||
|
|
|
@ -19,7 +19,7 @@ xhtmlHeaders(__FILE__, translate('Login') );
|
|||
<h1><i class="material-icons md-36">account_circle</i> <?php echo validHtmlStr(ZM_WEB_TITLE) . ' ' . translate('Login') ?></h1>
|
||||
|
||||
<label for="inputUsername" class="sr-only"><?php echo translate('Username') ?></label>
|
||||
<input type="text" id="inputUsername" name="username" class="form-control" placeholder="Username" required autofocus autocomplete="username"/>
|
||||
<input type="text" id="inputUsername" name="username" class="form-control" autocapitalize="none" placeholder="Username" required autofocus autocomplete="username"/>
|
||||
|
||||
<label for="inputPassword" class="sr-only"><?php echo translate('Password') ?></label>
|
||||
<input type="password" id="inputPassword" name="password" class="form-control" placeholder="Password" required autocomplete="current-password"/>
|
||||
|
|
|
@ -950,10 +950,7 @@ if ( $monitor->Type() == 'Local' ) {
|
|||
0 => 'Disabled',
|
||||
);
|
||||
|
||||
if (stripos(php_uname('m'), 'arm') === false )
|
||||
$videowriteropts[1] = 'X264 Encode';
|
||||
else
|
||||
$videowriteropts[1] = array('text'=>'X264 Encode - Not compatible on Arm','disabled'=>1);
|
||||
$videowriteropts[1] = 'X264 Encode';
|
||||
|
||||
if ($monitor->Type() == 'Ffmpeg' )
|
||||
$videowriteropts[2] = 'H264 Camera Passthrough';
|
||||
|
|
|
@ -100,7 +100,7 @@ if ( empty($_REQUEST['path']) ) {
|
|||
}
|
||||
}
|
||||
$Monitor = $Event->Monitor();
|
||||
if ( $Monitor->SaveJPEGs() & 1 ) {
|
||||
if ( $Event->SaveJPEGs() & 1 ) {
|
||||
# If we store Frames as jpgs, then we don't store an alarmed snapshot
|
||||
$path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d', $Frame->FrameId()).'-'.$show.'.jpg';
|
||||
} else {
|
||||
|
@ -114,14 +114,14 @@ if ( empty($_REQUEST['path']) ) {
|
|||
ZM\Warning('No frame found for event ' . $_REQUEST['eid']);
|
||||
$Frame = new ZM\Frame();
|
||||
$Frame->Delta(1);
|
||||
if ( $Monitor->SaveJPEGs() & 1 ) {
|
||||
if ( $Event->SaveJPEGs() & 1 ) {
|
||||
$Frame->FrameId(0);
|
||||
} else {
|
||||
$Frame->FrameId('snapshot');
|
||||
}
|
||||
}
|
||||
$Monitor = $Event->Monitor();
|
||||
if ( $Monitor->SaveJPEGs() & 1 ) {
|
||||
if ( $Event->SaveJPEGs() & 1 ) {
|
||||
# If we store Frames as jpgs, then we don't store a snapshot
|
||||
$path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d', $Frame->FrameId()).'-'.$show.'.jpg';
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue