Merge branch 'master' into storageareas
This commit is contained in:
commit
085d239a6e
|
@ -103,6 +103,8 @@ mark_as_advanced(
|
|||
ZM_PERL_MM_PARMS
|
||||
ZM_PERL_SEARCH_PATH
|
||||
ZM_TARGET_DISTRO
|
||||
ZM_PATH_MAP
|
||||
ZM_PATH_ARP
|
||||
ZM_CONFIG_DIR
|
||||
ZM_CONFIG_SUBDIR
|
||||
ZM_SYSTEMD)
|
||||
|
@ -135,7 +137,21 @@ set(ZM_WEB_USER "" CACHE STRING
|
|||
set(ZM_WEB_GROUP "" CACHE STRING
|
||||
"The group apache or the local web server runs on,
|
||||
Leave empty to be the same as the web user")
|
||||
set(ZM_DIR_EVENTS "events" CACHE PATH
|
||||
"Location where events are recorded to, default: events")
|
||||
set(ZM_DIR_IMAGES "events" CACHE PATH
|
||||
"Location where images, not directly associated with events,
|
||||
are recorded to, default: images")
|
||||
set(ZM_DIR_SOUNDS "sounds" CACHE PATH
|
||||
"Location to look for optional sound files, default: sounds")
|
||||
set(ZM_PATH_ZMS "/cgi-bin/nph-zms" CACHE PATH
|
||||
"Web url to zms streaming server, default: /cgi-bin/nph-zms")
|
||||
|
||||
# Advanced
|
||||
set(ZM_PATH_MAP "/dev/shm" CACHE PATH
|
||||
"Location to save mapped memory files, default: /dev/shm")
|
||||
set(ZM_PATH_ARP "" CACHE PATH
|
||||
"Full path to compatible arp binary. Leave empty for automatic detection.")
|
||||
set(ZM_CONFIG_DIR "/${CMAKE_INSTALL_SYSCONFDIR}" CACHE PATH
|
||||
"Location of ZoneMinder configuration, default system config directory")
|
||||
set(ZM_CONFIG_SUBDIR "${ZM_CONFIG_DIR}/conf.d" CACHE PATH
|
||||
|
@ -183,6 +199,9 @@ if((ZM_TARGET_DISTRO MATCHES "^el") OR (ZM_TARGET_DISTRO MATCHES "^fc"))
|
|||
set(ZM_CONFIG_SUBDIR "/etc/zm/conf.d")
|
||||
set(ZM_WEBDIR "/usr/share/zoneminder/www")
|
||||
set(ZM_CGIDIR "/usr/libexec/zoneminder/cgi-bin")
|
||||
set(ZM_DIR_EVENTS "/var/lib/zoneminder/events")
|
||||
set(ZM_DIR_IMAGES "/var/lib/zoneminder/images")
|
||||
set(ZM_PATH_ZMS "/cgi-bin-zm/nph-zms")
|
||||
elseif(ZM_TARGET_DISTRO STREQUAL "OS13")
|
||||
set(ZM_RUNDIR "/var/run/zoneminder")
|
||||
set(ZM_TMPDIR "/var/run/zoneminder")
|
||||
|
|
|
@ -70,6 +70,7 @@ ADD src /ZoneMinder/src/
|
|||
ADD umutils /ZoneMinder/umutils/
|
||||
ADD web /ZoneMinder/web/
|
||||
ADD cmakecacheimport.sh CMakeLists.txt version zm.conf.in zmconfgen.pl.in zmlinkcontent.sh.in zoneminder-config.cmake /ZoneMinder/
|
||||
ADD conf.d /ZoneMinder/conf.d
|
||||
|
||||
# Change into the ZoneMinder directory
|
||||
WORKDIR /ZoneMinder
|
||||
|
|
|
@ -2,23 +2,4 @@
|
|||
-- This updates a 1.30.1 database to 1.30.2
|
||||
--
|
||||
|
||||
--
|
||||
-- Update Filters table to have a Concurrent Column
|
||||
--
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE table_name = 'Filters'
|
||||
AND table_schema = DATABASE()
|
||||
AND column_name = 'Concurrent'
|
||||
) > 0,
|
||||
"SELECT 'Column Concurrent already exists in Filters'",
|
||||
"ALTER TABLE Filters ADD COLUMN `Concurrent` tinyint(1) unsigned NOT NULL default '0' AFTER Background"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
|
||||
ALTER TABLE Users MODIFY MonitorIds TEXT NOT NULL;
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
--
|
||||
-- This updates a 1.30.0 database to 1.30.1
|
||||
--
|
||||
-- Add StateId Column to Events.
|
||||
--
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE table_name = 'Events'
|
||||
AND table_schema = DATABASE()
|
||||
AND column_name = 'StateId'
|
||||
) > 0,
|
||||
"SELECT 'Column StateId exists in Events'",
|
||||
"ALTER TABLE Events ADD `StateId` int(10) unsigned default NULL AFTER `Notes`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
--
|
||||
-- Update Filters table to have a Concurrent Column
|
||||
--
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE table_name = 'Filters'
|
||||
AND table_schema = DATABASE()
|
||||
AND column_name = 'Concurrent'
|
||||
) > 0,
|
||||
"SELECT 'Column Concurrent already exists in Filters'",
|
||||
"ALTER TABLE Filters ADD COLUMN `Concurrent` tinyint(1) unsigned NOT NULL default '0' AFTER Background"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
|
@ -23,7 +23,10 @@ override_dh_auto_configure:
|
|||
-DZM_WEB_USER=www-data \
|
||||
-DZM_WEB_GROUP=www-data \
|
||||
-DZM_CONFIG_SUBDIR="/etc/zm/conf.d" \
|
||||
-DZM_CONFIG_DIR="/etc/zm"
|
||||
-DZM_CONFIG_DIR="/etc/zm" \
|
||||
-DZM_DIR_EVENTS="/var/cache/zoneminder/events" \
|
||||
-DZM_DIR_IMAGES="/var/cache/zoneminder/images" \
|
||||
-DZM_PATH_ZMS="/zm/cgi-bin/nph-zms"
|
||||
|
||||
override_dh_auto_install:
|
||||
dh_auto_install --buildsystem=cmake
|
||||
|
|
|
@ -1 +1 @@
|
|||
../redhat/redalert.wav
|
||||
../redhat/misc/redalert.wav
|
|
@ -33,7 +33,7 @@
|
|||
%global _hardened_build 1
|
||||
|
||||
Name: zoneminder
|
||||
Version: 1.30.4
|
||||
Version: 1.31.0
|
||||
Release: 1%{?dist}
|
||||
Summary: A camera monitoring and analysis tool
|
||||
Group: System Environment/Daemons
|
||||
|
@ -142,9 +142,7 @@ too much degradation of performance.
|
|||
%{__mv} -f crud-%{crud_version} ./web/api/app/Plugin/Crud
|
||||
|
||||
# Change the following default values
|
||||
./utils/zmeditconfigdata.sh ZM_PATH_ZMS /cgi-bin-zm/nph-zms
|
||||
./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes
|
||||
./utils/zmeditconfigdata.sh ZM_PATH_SWAP /dev/shm
|
||||
./utils/zmeditconfigdata.sh ZM_UPLOAD_FTP_LOC_DIR %{_localstatedir}/spool/zoneminder-upload
|
||||
./utils/zmeditconfigdata.sh ZM_OPT_CONTROL yes
|
||||
./utils/zmeditconfigdata.sh ZM_CHECK_FOR_UPDATES no
|
||||
|
|
|
@ -25,7 +25,10 @@ override_dh_auto_configure:
|
|||
-DZM_SOCKDIR="/var/run/zm" \
|
||||
-DZM_TMPDIR="/tmp/zm" \
|
||||
-DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \
|
||||
-DZM_CONTENTDIR="/var/cache/zoneminder"
|
||||
-DZM_CONTENTDIR="/var/cache/zoneminder" \
|
||||
-DZM_DIR_EVENTS="/var/cache/zoneminder/events" \
|
||||
-DZM_DIR_IMAGES="/var/cache/zoneminder/images" \
|
||||
-DZM_PATH_ZMS="/zm/cgi-bin/nph-zms" \
|
||||
|
||||
override_dh_clean:
|
||||
dh_clean $(MANPAGES1)
|
||||
|
|
|
@ -63,8 +63,10 @@ override_dh_auto_configure:
|
|||
-DZM_WEB_USER=www-data \
|
||||
-DZM_WEB_GROUP=www-data \
|
||||
-DZM_CONFIG_SUBDIR="/etc/zm/conf.d" \
|
||||
-DZM_CONFIG_DIR="/etc/zm"
|
||||
|
||||
-DZM_CONFIG_DIR="/etc/zm" \
|
||||
-DZM_DIR_EVENTS="/var/cache/zoneminder/events" \
|
||||
-DZM_DIR_IMAGES="/var/cache/zoneminder/images" \
|
||||
-DZM_PATH_ZMS="/zm/cgi-bin/nph-zms"
|
||||
|
||||
override_dh_auto_test:
|
||||
# do not run tests...
|
||||
|
|
|
@ -25,7 +25,10 @@ override_dh_auto_configure:
|
|||
-DZM_SOCKDIR="/var/run/zm" \
|
||||
-DZM_TMPDIR="/tmp/zm" \
|
||||
-DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \
|
||||
-DZM_CONTENTDIR="/var/cache/zoneminder"
|
||||
-DZM_CONTENTDIR="/var/cache/zoneminder" \
|
||||
-DZM_DIR_EVENTS="/var/cache/zoneminder/events" \
|
||||
-DZM_DIR_IMAGES="/var/cache/zoneminder/images" \
|
||||
-DZM_PATH_ZMS="/zm/cgi-bin/nph-zms"
|
||||
|
||||
override_dh_clean:
|
||||
dh_clean $(MANPAGES1)
|
||||
|
|
|
@ -442,23 +442,6 @@ our @options = (
|
|||
type => $types{string},
|
||||
category => 'system',
|
||||
},
|
||||
{
|
||||
name => 'ZM_DIR_EVENTS',
|
||||
default => 'events',
|
||||
description => 'Directory where events are stored',
|
||||
help => q`
|
||||
This is the path to the events directory where all the event
|
||||
images and other miscellaneous files are stored. CAUTION: The
|
||||
directory you specify here cannot be outside the web root. This
|
||||
is a common mistake. Most users should never change this value.
|
||||
If you intend to record events to a second disk or network
|
||||
share, then you should mount the drive or share directly to the
|
||||
ZoneMinder events folder or follow the instructions in the
|
||||
ZoneMinder Wiki titled Using a dedicated Hard Drive.
|
||||
`,
|
||||
type => $types{directory},
|
||||
category => 'paths',
|
||||
},
|
||||
{
|
||||
name => 'ZM_USE_DEEP_STORAGE',
|
||||
default => 'yes',
|
||||
|
@ -480,68 +463,6 @@ our @options = (
|
|||
type => $types{boolean},
|
||||
category => 'hidden',
|
||||
},
|
||||
{
|
||||
name => 'ZM_DIR_IMAGES',
|
||||
default => 'images',
|
||||
description => 'Directory where the images that the ZoneMinder client generates are stored',
|
||||
help => q`
|
||||
ZoneMinder generates a myriad of images, mostly of which are
|
||||
associated with events. For those that aren't this is where
|
||||
they go. CAUTION: The directory you specify here cannot be
|
||||
outside the web root. This is a common mistake. Most users
|
||||
should never change this value. If you intend to save images to
|
||||
a second disk or network share, then you should mount the drive
|
||||
or share directly to the ZoneMinder images folder or follow the
|
||||
instructions in the ZoneMinder Wiki titled Using a dedicated
|
||||
Hard Drive.
|
||||
`,
|
||||
type => $types{directory},
|
||||
category => 'paths',
|
||||
},
|
||||
{
|
||||
name => 'ZM_DIR_SOUNDS',
|
||||
default => 'sounds',
|
||||
description => 'Directory to the sounds that the ZoneMinder client can use',
|
||||
help => q`
|
||||
ZoneMinder can optionally play a sound file when an alarm is
|
||||
detected. This indicates where to look for this file. CAUTION:
|
||||
The directory you specify here cannot be outside the web root.
|
||||
Most users should never change this value.
|
||||
`,
|
||||
type => $types{directory},
|
||||
category => 'paths',
|
||||
},
|
||||
{
|
||||
name => 'ZM_DIR_EXPORTS',
|
||||
default => '@ZM_TMPDIR@',
|
||||
description => 'Directory where exported archives are stored',
|
||||
help => q`
|
||||
This is the path to the exports directory where exported
|
||||
tar.gz and zip archives are stored. By default this points to
|
||||
ZoneMinder's temp folder, which often sits in ram. Since exported
|
||||
archives can potentially become large, it is a good idea to move
|
||||
this folder to some other location on machines with low memory.
|
||||
`,
|
||||
type => $types{directory},
|
||||
category => 'paths',
|
||||
},
|
||||
{
|
||||
name => 'ZM_PATH_ZMS',
|
||||
default => '/cgi-bin/nph-zms',
|
||||
description => 'Web path to zms streaming server',
|
||||
help => q`
|
||||
The ZoneMinder streaming server is required to send streamed
|
||||
images to your browser. It will be installed into the cgi-bin
|
||||
path given at configuration time. This option determines what
|
||||
the web path to the server is rather than the local path on
|
||||
your machine. Ordinarily the streaming server runs in
|
||||
parser-header mode however if you experience problems with
|
||||
streaming you can change this to non-parsed-header (nph) mode
|
||||
by changing 'zms' to 'nph-zms'.
|
||||
`,
|
||||
type => $types{rel_path},
|
||||
category => 'paths',
|
||||
},
|
||||
{
|
||||
name => 'ZM_COLOUR_JPEG_FILES',
|
||||
default => 'no',
|
||||
|
@ -1486,83 +1407,6 @@ our @options = (
|
|||
type => $types{boolean},
|
||||
category => 'logging',
|
||||
},
|
||||
{
|
||||
name => 'ZM_PATH_MAP',
|
||||
default => '/dev/shm',
|
||||
description => 'Path to the mapped memory files that that ZoneMinder can use',
|
||||
help => q`
|
||||
ZoneMinder has historically used IPC shared memory for shared
|
||||
data between processes. This has it's advantages and
|
||||
limitations. This version of ZoneMinder can use an alternate
|
||||
method, mapped memory, instead with can be enabled with the
|
||||
--enable--mmap directive to configure. This requires less
|
||||
system configuration and is generally more flexible. However it
|
||||
requires each shared data segment to map onto a filesystem
|
||||
file. This option indicates where those mapped files go. You
|
||||
should ensure that this location has sufficient space for these
|
||||
files and for the best performance it should be a tmpfs file
|
||||
system or ramdisk otherwise disk access may render this method
|
||||
slower than the regular shared memory one.
|
||||
`,
|
||||
type => $types{abs_path},
|
||||
category => 'paths',
|
||||
},
|
||||
{
|
||||
name => 'ZM_PATH_SOCKS',
|
||||
default => '@ZM_SOCKDIR@',
|
||||
description => 'Path to the various Unix domain socket files that ZoneMinder uses',
|
||||
help => q`
|
||||
ZoneMinder generally uses Unix domain sockets where possible.
|
||||
This reduces the need for port assignments and prevents
|
||||
external applications from possibly compromising the daemons.
|
||||
However each Unix socket requires a .sock file to be created.
|
||||
This option indicates where those socket files go.
|
||||
`,
|
||||
type => $types{abs_path},
|
||||
category => 'paths',
|
||||
},
|
||||
{
|
||||
name => 'ZM_PATH_LOGS',
|
||||
default => '@ZM_LOGDIR@',
|
||||
description => 'Path to the various logs that the ZoneMinder daemons generate',
|
||||
help => q`
|
||||
There are various daemons that are used by ZoneMinder to
|
||||
perform various tasks. Most generate helpful log files and this
|
||||
is where they go. They can be deleted if not required for
|
||||
debugging.
|
||||
`,
|
||||
type => $types{abs_path},
|
||||
category => 'paths',
|
||||
},
|
||||
{
|
||||
name => 'ZM_PATH_SWAP',
|
||||
default => '@ZM_TMPDIR@',
|
||||
description => 'Path to location for temporary swap images used in streaming',
|
||||
help => q`
|
||||
Buffered playback requires temporary swap images to be stored
|
||||
for each instance of the streaming daemons. This option
|
||||
determines where these images will be stored. The images will
|
||||
actually be stored in sub directories beneath this location and
|
||||
will be automatically cleaned up after a period of time.
|
||||
`,
|
||||
type => $types{abs_path},
|
||||
category => 'paths',
|
||||
},
|
||||
{
|
||||
name => 'ZM_PATH_ARP',
|
||||
default => '',
|
||||
description => 'Path to a supported ARP tool',
|
||||
help => q`
|
||||
The camera probe function uses Address Resolution Protocol in
|
||||
order to find known devices on the network. Optionally supply
|
||||
the full path to \"ip neigh\", \"arp -a\", or any other tool on
|
||||
your system that returns ip/mac address pairs. If this field is
|
||||
left empty, ZoneMinder will search for the command \"arp\" and
|
||||
attempt to use that.
|
||||
`,
|
||||
type => $types{abs_path},
|
||||
category => 'paths',
|
||||
},
|
||||
{
|
||||
name => 'ZM_WEB_TITLE_PREFIX',
|
||||
default => 'ZM',
|
||||
|
|
|
@ -311,6 +311,7 @@ if ( $migrateEvents ) {
|
|||
}
|
||||
if ( $freshen ) {
|
||||
print( "\nFreshening configuration in database\n" );
|
||||
migratePaths();
|
||||
ZoneMinder::Config::loadConfigFromDB();
|
||||
ZoneMinder::Config::saveConfigToDB();
|
||||
}
|
||||
|
@ -414,6 +415,7 @@ if ( $version ) {
|
|||
print( "\nUpgrading database to version ".ZM_VERSION."\n" );
|
||||
|
||||
# Update config first of all
|
||||
migratePaths();
|
||||
ZoneMinder::Config::loadConfigFromDB();
|
||||
ZoneMinder::Config::saveConfigToDB();
|
||||
|
||||
|
@ -943,5 +945,62 @@ sub patchDB {
|
|||
my $res = $sth->execute( $version ) or die( "Can't execute: ".$sth->errstr() );
|
||||
}
|
||||
|
||||
sub migratePaths {
|
||||
|
||||
my $customConfigFile = '@ZM_CONFIG_SUBDIR@/zmcustom.conf';
|
||||
|
||||
if ( (! -e $customConfigFile ) && ( ZM_VERSION ge '1.31.0' ) && ($Config{ZM_DYN_DB_VERSION} lt '1.31.1') ) {
|
||||
|
||||
my %customConfig;
|
||||
|
||||
# Check the traditional default values for the variables previsouly found under Options -> Paths
|
||||
if ( $Config{ZM_DIR_EVENTS} ne 'events' ) {
|
||||
$customConfig{ZM_DIR_EVENTS} = $Config{ZM_DIR_EVENTS};
|
||||
}
|
||||
if ( $Config{ZM_DIR_IMAGES} ne 'images' ) {
|
||||
$customConfig{ZM_DIR_IMAGES} = $Config{ZM_DIR_IMAGES};
|
||||
}
|
||||
if ( $Config{ZM_DIR_SOUNDS} ne 'sounds' ) {
|
||||
$customConfig{ZM_DIR_SOUNDS} = $Config{ZM_DIR_SOUNDS};
|
||||
}
|
||||
if ( $Config{ZM_PATH_ZMS} ne '@ZM_PATH_ZMS@' ) {
|
||||
$customConfig{ZM_PATH_ZMS} = $Config{ZM_PATH_ZMS};
|
||||
}
|
||||
if ( $Config{ZM_PATH_MAP} ne '/dev/shm' ) {
|
||||
$customConfig{ZM_PATH_MAP} = $Config{ZM_PATH_MAP};
|
||||
}
|
||||
if ( $Config{ZM_PATH_SOCKS} ne '@ZM_SOCKDIR@' ) {
|
||||
$customConfig{ZM_PATH_SOCKS} = $Config{ZM_PATH_SOCKS};
|
||||
}
|
||||
if ( $Config{ZM_PATH_LOGS} ne '@ZM_LOGDIR@' ) {
|
||||
$customConfig{ZM_PATH_LOGS} = $Config{ZM_PATH_LOGS};
|
||||
}
|
||||
if ( $Config{ZM_PATH_SWAP} ne '@ZM_TMPDIR@' ) {
|
||||
$customConfig{ZM_PATH_SWAP} = $Config{ZM_PATH_SWAP};
|
||||
}
|
||||
if ( $Config{ZM_PATH_ARP} ne '' ) {
|
||||
$customConfig{ZM_PATH_ARP} = $Config{ZM_PATH_ARP};
|
||||
}
|
||||
|
||||
# If any variables differ from their expected default value,
|
||||
# save them to a config file before they get purged from the database
|
||||
if ( %customConfig ) {
|
||||
print("\nMigrating custom config values from Options -> Paths\nto $customConfigFile.\n");
|
||||
print("\nPlease verify these values before starting ZoneMinder.\n\n");
|
||||
open(my $fh, '>', $customConfigFile) or die "Could open $customConfigFile for writing: $!.";
|
||||
print $fh "# These values were autogenerated by zmupdate.pl\n";
|
||||
print $fh "# You may edit these values. ZoneMinder will not overwrite them.\n";
|
||||
print $fh "#\n\n";
|
||||
while (my ($key, $value) = each %customConfig) {
|
||||
print $fh "$key=$value\n";
|
||||
}
|
||||
close $fh;
|
||||
my $gid = getgrnam('@ZM_WEB_GROUP@');
|
||||
chown -1, $gid, $customConfigFile;
|
||||
chmod 0640, $customConfigFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
snprintf( swap_path, sizeof(swap_path), "%s/zmswap-m%d/zmswap-q%06d", config.path_swap, monitor->Id(), connkey );
|
||||
snprintf( swap_path, sizeof(swap_path), "%s/zmswap-m%d/zmswap-q%06d", staticConfig.PATH_SWAP.c_str(), monitor->Id(), connkey );
|
||||
|
||||
int len = snprintf(NULL, 0, "/zmswap-m%d", monitor->Id());
|
||||
|
||||
|
||||
int swap_path_length = strlen(config.path_swap) + snprintf(NULL, 0, "/zmswap-m%d", monitor->Id() ) + snprintf(NULL, 0, "/zmswap-q%06d", connkey ) + 1; // +1 for NULL terminator
|
||||
int swap_path_length = strlen(staticConfig.PATH_SWAP.c_str()) + snprintf(NULL, 0, "/zmswap-m%d", monitor->Id() ) + snprintf(NULL, 0, "/zmswap-q%06d", connkey ) + 1; // +1 for NULL terminator
|
||||
|
||||
if ( connkey && playback_buffer > 0 ) {
|
||||
|
||||
|
@ -11,8 +11,8 @@ int len = snprintf(NULL, 0, "/zmswap-m%d", monitor->Id());
|
|||
Error( "Swap Path is too long. %d > %d ", swap_path_length+max_swap_len_suffix, PATH_MAX );
|
||||
} else {
|
||||
swap_path = (char *)malloc( swap_path_length+max_swap_len_suffix );
|
||||
Debug( 3, "Checking swap image path %s", config.path_swap );
|
||||
strncpy( swap_path, config.path_swap, swap_path_length );
|
||||
Debug( 3, "Checking swap image path %s", staticConfig.PATH_SWAP.c_str() );
|
||||
strncpy( swap_path, staticConfig.PATH_SWAP.c_str(), swap_path_length );
|
||||
if ( checkSwapPath( swap_path, false ) ) {
|
||||
snprintf( &(swap_path[swap_path_length]), max_swap_len_suffix, "/zmswap-m%d", monitor->Id() );
|
||||
if ( checkSwapPath( swap_path, true ) ) {
|
||||
|
|
|
@ -30,9 +30,9 @@
|
|||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#if defined(BSD)
|
||||
#include <sys/uio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
|
|
@ -161,6 +161,26 @@ void process_configfile( char* configFile) {
|
|||
staticConfig.SERVER_NAME = std::string(val_ptr);
|
||||
else if ( strcasecmp( name_ptr, "ZM_SERVER_ID" ) == 0 )
|
||||
staticConfig.SERVER_ID = atoi(val_ptr);
|
||||
else if ( strcasecmp( name_ptr, "ZM_DIR_EVENTS" ) == 0 )
|
||||
staticConfig.DIR_EVENTS = std::string(val_ptr);
|
||||
else if ( strcasecmp( name_ptr, "ZM_DIR_IMAGES" ) == 0 )
|
||||
staticConfig.DIR_IMAGES = std::string(val_ptr);
|
||||
else if ( strcasecmp( name_ptr, "ZM_DIR_SOUNDS" ) == 0 )
|
||||
staticConfig.DIR_SOUNDS = std::string(val_ptr);
|
||||
else if ( strcasecmp( name_ptr, "ZM_DIR_EXPORTS" ) == 0 )
|
||||
staticConfig.DIR_EXPORTS = std::string(val_ptr);
|
||||
else if ( strcasecmp( name_ptr, "ZM_PATH_ZMS" ) == 0 )
|
||||
staticConfig.PATH_ZMS = std::string(val_ptr);
|
||||
else if ( strcasecmp( name_ptr, "ZM_PATH_MAP" ) == 0 )
|
||||
staticConfig.PATH_MAP = std::string(val_ptr);
|
||||
else if ( strcasecmp( name_ptr, "ZM_PATH_SOCKS" ) == 0 )
|
||||
staticConfig.PATH_SOCKS = std::string(val_ptr);
|
||||
else if ( strcasecmp( name_ptr, "ZM_PATH_LOGS" ) == 0 )
|
||||
staticConfig.PATH_LOGS = std::string(val_ptr);
|
||||
else if ( strcasecmp( name_ptr, "ZM_PATH_SWAP" ) == 0 )
|
||||
staticConfig.PATH_SWAP = std::string(val_ptr);
|
||||
else if ( strcasecmp( name_ptr, "ZM_PATH_ARP" ) == 0 )
|
||||
staticConfig.PATH_ARP = std::string(val_ptr);
|
||||
else {
|
||||
// We ignore this now as there may be more parameters than the
|
||||
// c/c++ binaries are bothered about
|
||||
|
|
|
@ -70,6 +70,16 @@ struct StaticConfig
|
|||
std::string PATH_WEB;
|
||||
std::string SERVER_NAME;
|
||||
unsigned int SERVER_ID;
|
||||
std::string DIR_EVENTS;
|
||||
std::string DIR_IMAGES;
|
||||
std::string DIR_SOUNDS;
|
||||
std::string DIR_EXPORTS;
|
||||
std::string PATH_ZMS;
|
||||
std::string PATH_MAP;
|
||||
std::string PATH_SOCKS;
|
||||
std::string PATH_LOGS;
|
||||
std::string PATH_SWAP;
|
||||
std::string PATH_ARP;
|
||||
};
|
||||
|
||||
extern StaticConfig staticConfig;
|
||||
|
|
|
@ -158,7 +158,11 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
|
|||
if ( symlink( time_path, id_file ) < 0 )
|
||||
Fatal( "Can't symlink %s -> %s: %s", id_file, path, strerror(errno));
|
||||
} else {
|
||||
<<<<<<< HEAD
|
||||
snprintf( path, sizeof(path), "%s/%d/%d", storage->Path(), monitor->Id(), id );
|
||||
=======
|
||||
snprintf( path, sizeof(path), "%s/%d/%d", staticConfig.DIR_EVENTS.c_str(), monitor->Id(), id );
|
||||
>>>>>>> master
|
||||
|
||||
errno = 0;
|
||||
stat( path, &statbuf );
|
||||
|
@ -572,7 +576,7 @@ void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image *
|
|||
if ( config.record_diag_images ) {
|
||||
char diag_glob[PATH_MAX] = "";
|
||||
|
||||
snprintf( diag_glob, sizeof(diag_glob), "%s/%d/diag-*.jpg", config.dir_events, monitor->Id() );
|
||||
snprintf( diag_glob, sizeof(diag_glob), "%s/%d/diag-*.jpg", staticConfig.DIR_EVENTS.c_str(), monitor->Id() );
|
||||
glob_t pglob;
|
||||
int glob_status = glob( diag_glob, 0, 0, &pglob );
|
||||
if ( glob_status != 0 ) {
|
||||
|
@ -701,6 +705,7 @@ bool EventStream::loadEventData( int event_id ) {
|
|||
|
||||
if ( config.use_deep_storage ) {
|
||||
struct tm *event_time = localtime( &event_data->start_time );
|
||||
<<<<<<< HEAD
|
||||
if ( storage_path[0] == '/' )
|
||||
snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d", storage_path, event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec );
|
||||
else
|
||||
|
@ -710,6 +715,17 @@ bool EventStream::loadEventData( int event_id ) {
|
|||
snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%ld", storage_path, event_data->monitor_id, event_data->event_id );
|
||||
else
|
||||
snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%ld", staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_data->event_id );
|
||||
=======
|
||||
if ( staticConfig.DIR_EVENTS.c_str()[0] == '/' )
|
||||
snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d", staticConfig.DIR_EVENTS.c_str(), event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec );
|
||||
else
|
||||
snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d", staticConfig.PATH_WEB.c_str(), staticConfig.DIR_EVENTS.c_str(), event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec );
|
||||
} else {
|
||||
if ( staticConfig.DIR_EVENTS.c_str()[0] == '/' )
|
||||
snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%ld", staticConfig.DIR_EVENTS.c_str(), event_data->monitor_id, event_data->event_id );
|
||||
else
|
||||
snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%ld", staticConfig.PATH_WEB.c_str(), staticConfig.DIR_EVENTS.c_str(), event_data->monitor_id, event_data->event_id );
|
||||
>>>>>>> master
|
||||
}
|
||||
event_data->frame_count = dbrow[2] == NULL ? 0 : atoi(dbrow[3]);
|
||||
event_data->duration = atof(dbrow[4]);
|
||||
|
|
|
@ -413,6 +413,26 @@ static void zm_log_fps(double d, const char *postfix) {
|
|||
Debug(1, "%1.0fk %s", d / 1000, postfix);
|
||||
}
|
||||
|
||||
void zm_dump_codecpar ( const AVCodecParameters *par ) {
|
||||
Debug(1, "Dumping codecpar codec_type(%d) codec_id(%d) codec_tag(%d) width(%d) height(%d)",
|
||||
par->codec_type,
|
||||
par->codec_id,
|
||||
par->codec_tag,
|
||||
par->width,
|
||||
par->height
|
||||
);
|
||||
}
|
||||
|
||||
void zm_dump_codec ( const AVCodecContext *codec ) {
|
||||
Debug(1, "Dumping codecpar codec_type(%d) codec_id(%d) width(%d) height(%d)",
|
||||
codec->codec_type,
|
||||
codec->codec_id,
|
||||
codec->width,
|
||||
codec->height
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/* "user interface" functions */
|
||||
void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output) {
|
||||
char buf[256];
|
||||
|
|
|
@ -323,6 +323,9 @@ static av_always_inline av_const int64_t av_clip64_c(int64_t a, int64_t amin, in
|
|||
#endif
|
||||
|
||||
void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output);
|
||||
void zm_dump_codec ( const AVCodecContext *codec );
|
||||
void zm_dump_codecpar ( const AVCodecParameters *par );
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100)
|
||||
#define zm_av_packet_unref( packet ) av_packet_unref( packet )
|
||||
#define zm_av_packet_ref( dst, src ) av_packet_ref( dst, src )
|
||||
|
|
|
@ -146,9 +146,10 @@ int FfmpegCamera::Capture( Image &image ) {
|
|||
|
||||
int frameComplete = false;
|
||||
while ( !frameComplete ) {
|
||||
int ret;
|
||||
int avResult = av_read_frame( mFormatContext, &packet );
|
||||
if ( avResult < 0 ) {
|
||||
char errbuf[AV_ERROR_MAX_STRING_SIZE];
|
||||
if ( avResult < 0 ) {
|
||||
av_strerror(avResult, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
||||
if (
|
||||
// Check if EOF.
|
||||
|
@ -166,9 +167,31 @@ int FfmpegCamera::Capture( Image &image ) {
|
|||
Debug( 5, "Got packet from stream %d dts (%d) pts(%d)", packet.stream_index, packet.pts, packet.dts );
|
||||
// What about audio stream? Maybe someday we could do sound detection...
|
||||
if ( packet.stream_index == mVideoStreamId ) {
|
||||
int ret = zm_avcodec_decode_video( mVideoCodecContext, mRawFrame, &frameComplete, &packet );
|
||||
if ( ret < 0 )
|
||||
Fatal( "Unable to decode frame at frame %d", frameCount );
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
|
||||
ret = avcodec_send_packet( mVideoCodecContext, &packet );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf );
|
||||
zm_av_packet_unref( &packet );
|
||||
continue;
|
||||
}
|
||||
ret = avcodec_receive_frame( mVideoCodecContext, mRawFrame );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf );
|
||||
zm_av_packet_unref( &packet );
|
||||
continue;
|
||||
}
|
||||
frameComplete = 1;
|
||||
# else
|
||||
ret = zm_avcodec_decode_video( mVideoCodecContext, mRawFrame, &frameComplete, &packet );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to decode frame at frame %d: %s, continuing", frameCount, errbuf );
|
||||
zm_av_packet_unref( &packet );
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
Debug( 4, "Decoded video packet at frame %d", frameCount );
|
||||
|
||||
|
@ -304,10 +327,14 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
mVideoStreamId = -1;
|
||||
mAudioStreamId = -1;
|
||||
for (unsigned int i=0; i < mFormatContext->nb_streams; i++ ) {
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
|
||||
if ( mFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ) {
|
||||
#else
|
||||
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) {
|
||||
#else
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO ) {
|
||||
#endif
|
||||
#endif
|
||||
if ( mVideoStreamId == -1 ) {
|
||||
mVideoStreamId = i;
|
||||
|
@ -317,10 +344,14 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
Debug(2, "Have another video stream." );
|
||||
}
|
||||
}
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
|
||||
if ( mFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO ) {
|
||||
#else
|
||||
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO ) {
|
||||
#else
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO ) {
|
||||
#endif
|
||||
#endif
|
||||
if ( mAudioStreamId == -1 ) {
|
||||
mAudioStreamId = i;
|
||||
|
@ -337,7 +368,12 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
Debug ( 3, "Found video stream at index %d", mVideoStreamId );
|
||||
Debug ( 3, "Found audio stream at index %d", mAudioStreamId );
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
|
||||
mVideoCodecContext = avcodec_alloc_context3( NULL );
|
||||
avcodec_parameters_to_context( mVideoCodecContext, mFormatContext->streams[mVideoStreamId]->codecpar );
|
||||
#else
|
||||
mVideoCodecContext = mFormatContext->streams[mVideoStreamId]->codec;
|
||||
#endif
|
||||
// STolen from ispy
|
||||
//this fixes issues with rtsp streams!! woot.
|
||||
//mVideoCodecContext->flags2 |= CODEC_FLAG2_FAST | CODEC_FLAG2_CHUNKS | CODEC_FLAG_LOW_DELAY; // Enable faster H264 decode.
|
||||
|
@ -361,7 +397,12 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
}
|
||||
|
||||
if ( mAudioStreamId >= 0 ) {
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
|
||||
mAudioCodecContext = avcodec_alloc_context3( NULL );
|
||||
avcodec_parameters_to_context( mAudioCodecContext, mFormatContext->streams[mAudioStreamId]->codecpar );
|
||||
#else
|
||||
mAudioCodecContext = mFormatContext->streams[mAudioStreamId]->codec;
|
||||
#endif
|
||||
if ((mAudioCodec = avcodec_find_decoder(mAudioCodecContext->codec_id)) == NULL) {
|
||||
Debug(1, "Can't find codec for audio stream from %s", mPath.c_str());
|
||||
} else {
|
||||
|
@ -576,12 +617,13 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
|
|||
|
||||
//Video recording
|
||||
if ( recording.tv_sec ) {
|
||||
// The directory we are recording to is no longer tied to the current event.
|
||||
// Need to re-init the videostore with the correct directory and start recording again
|
||||
// for efficiency's sake, we should test for keyframe before we test for directory change...
|
||||
if ( videoStore && key_frame && (strcmp(oldDirectory, event_file) != 0 ) ) {
|
||||
// don't open new videostore until we're on a key frame..would this require an offset adjustment for the event as a result?...
|
||||
// if we store our key frame location with the event will that be enough?
|
||||
|
||||
uint32_t last_event_id = monitor->GetLastEventId() ;
|
||||
|
||||
if ( last_event_id != monitor->GetVideoWriterEventId() ) {
|
||||
Debug(2, "Have change of event. last_event(%d), our current (%d)", last_event_id, monitor->GetVideoWriterEventId() );
|
||||
|
||||
if ( videoStore ) {
|
||||
Info("Re-starting video storage module");
|
||||
|
||||
// I don't know if this is important or not... but I figure we might as well write this last packet out to the store before closing it.
|
||||
|
@ -596,9 +638,12 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
|
|||
|
||||
delete videoStore;
|
||||
videoStore = NULL;
|
||||
|
||||
monitor->SetVideoWriterEventId( 0 );
|
||||
} // end if videoStore
|
||||
} // end if end of recording
|
||||
|
||||
if ( ( ! videoStore ) && key_frame && ( packet.stream_index == mVideoStreamId ) ) {
|
||||
if ( last_event_id and ! videoStore ) {
|
||||
//Instantiate the video storage module
|
||||
|
||||
if (record_audio) {
|
||||
|
@ -627,6 +672,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
|
|||
this->getMonitor());
|
||||
} // end if record_audio
|
||||
strcpy(oldDirectory, event_file);
|
||||
monitor->SetVideoWriterEventId( last_event_id );
|
||||
|
||||
// Need to write out all the frames from the last keyframe?
|
||||
// No... need to write out all frames from when the event began. Due to PreEventFrames, this could be more than since the last keyframe.
|
||||
|
@ -664,6 +710,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
|
|||
Info("Deleting videoStore instance");
|
||||
delete videoStore;
|
||||
videoStore = NULL;
|
||||
monitor->SetVideoWriterEventId( 0 );
|
||||
}
|
||||
|
||||
// Buffer video packets, since we are not recording.
|
||||
|
@ -708,7 +755,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) {
|
|||
}
|
||||
Debug(4, "about to decode video" );
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(58, 0, 0, 0, 0)
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
|
||||
ret = avcodec_send_packet( mVideoCodecContext, &packet );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
|
@ -719,7 +766,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) {
|
|||
ret = avcodec_receive_frame( mVideoCodecContext, mRawFrame );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf );
|
||||
Debug( 1, "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf );
|
||||
zm_av_packet_unref( &packet );
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ Logger::Logger() :
|
|||
mFileLevel( NOLOG ),
|
||||
mSyslogLevel( NOLOG ),
|
||||
mEffectiveLevel( NOLOG ),
|
||||
//mLogPath( config.path_logs ),
|
||||
//mLogPath( staticConfig.PATH_LOGS.c_str() ),
|
||||
//mLogFile( mLogPath+"/"+mId+".log" ),
|
||||
mDbConnected( false ),
|
||||
mLogFileFP( NULL ),
|
||||
|
@ -577,7 +577,7 @@ void logInit( const char *name, const Logger::Options &options ) {
|
|||
if ( !Logger::smInstance )
|
||||
Logger::smInstance = new Logger();
|
||||
Logger::Options tempOptions = options;
|
||||
tempOptions.mLogPath = config.path_logs;
|
||||
tempOptions.mLogPath = staticConfig.PATH_LOGS.c_str();
|
||||
Logger::smInstance->initialise( name, tempOptions );
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ Monitor::MonitorLink::MonitorLink( int p_id, const char *p_name ) : id( p_id ) {
|
|||
|
||||
#if ZM_MEM_MAPPED
|
||||
map_fd = -1;
|
||||
snprintf( mem_file, sizeof(mem_file), "%s/zm.mmap.%d", config.path_map, id );
|
||||
snprintf( mem_file, sizeof(mem_file), "%s/zm.mmap.%d", staticConfig.PATH_MAP.c_str(), id );
|
||||
#else // ZM_MEM_MAPPED
|
||||
shm_id = 0;
|
||||
#endif // ZM_MEM_MAPPED
|
||||
|
@ -484,7 +484,7 @@ Monitor::Monitor(
|
|||
bool Monitor::connect() {
|
||||
Debug(3, "Connecting to monitor. Purpose is %d", purpose );
|
||||
#if ZM_MEM_MAPPED
|
||||
snprintf( mem_file, sizeof(mem_file), "%s/zm.mmap.%d", config.path_map, id );
|
||||
snprintf( mem_file, sizeof(mem_file), "%s/zm.mmap.%d", staticConfig.PATH_MAP.c_str(), id );
|
||||
map_fd = open( mem_file, O_RDWR|O_CREAT, (mode_t)0600 );
|
||||
if ( map_fd < 0 )
|
||||
Fatal( "Can't open memory map file %s, probably not enough space free: %s", mem_file, strerror(errno) );
|
||||
|
@ -636,7 +636,7 @@ Monitor::~Monitor() {
|
|||
if ( purpose == CAPTURE ) {
|
||||
// How about we store this in the object on instantiation so that we don't have to do this again.
|
||||
char mmap_path[PATH_MAX] = "";
|
||||
snprintf( mmap_path, sizeof(mmap_path), "%s/zm.mmap.%d", config.path_map, id );
|
||||
snprintf( mmap_path, sizeof(mmap_path), "%s/zm.mmap.%d", staticConfig.PATH_MAP.c_str(), id );
|
||||
|
||||
if ( unlink( mmap_path ) < 0 ) {
|
||||
Warning( "Can't unlink '%s': %s", mmap_path, strerror(errno) );
|
||||
|
|
|
@ -162,6 +162,7 @@ protected:
|
|||
//sizeOf(VideoStoreData) expected to be 4104 bytes on 32bit and 64bit
|
||||
typedef struct {
|
||||
uint32_t size;
|
||||
uint32_t current_event;
|
||||
char event_file[4096];
|
||||
timeval recording; // used as both bool and a pointer to the timestamp when recording should begin
|
||||
//uint32_t frameNumber;
|
||||
|
@ -431,6 +432,9 @@ public:
|
|||
int GetOptSaveJPEGs() const { return( savejpegspref ); }
|
||||
VideoWriter GetOptVideoWriter() const { return( videowriter ); }
|
||||
const std::vector<EncoderParameter_t>* GetOptEncoderParams() const { return( &encoderparamsvec ); }
|
||||
uint32_t GetLastEventId() const { return shared_data->last_event; }
|
||||
uint32_t GetVideoWriterEventId() const { return video_store_data->current_event; }
|
||||
void SetVideoWriterEventId( uint32_t p_event_id ) { video_store_data->current_event = p_event_id; }
|
||||
|
||||
unsigned int GetPreEventCount() const { return pre_event_count; };
|
||||
State GetState() const;
|
||||
|
|
|
@ -26,17 +26,15 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
||||
Storage::Storage() {
|
||||
Warning("Instantiating default Storage Object. Should not happen.");
|
||||
id = 0;
|
||||
strcpy(name, "Default");
|
||||
if ( config.dir_events[0] != '/' ) {
|
||||
if ( staticConfig.DIR_EVENTS[0] != '/' ) {
|
||||
// not using an absolute path. Make it one by appending ZM_PATH_WEB
|
||||
snprintf( path, sizeof (path), "%s/%s", staticConfig.PATH_WEB.c_str( ), config.dir_events );
|
||||
snprintf( path, sizeof (path), "%s/%s", staticConfig.PATH_WEB.c_str( ), staticConfig.DIR_EVENTS.c_str() );
|
||||
} else {
|
||||
strncpy(path, config.dir_events, sizeof(path) );
|
||||
strncpy(path, staticConfig.DIR_EVENTS.c_str(), sizeof(path) );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,11 +65,11 @@ Storage::Storage( unsigned int p_id ) {
|
|||
}
|
||||
}
|
||||
if ( ! id ) {
|
||||
if ( config.dir_events[0] != '/' ) {
|
||||
if ( staticConfig.DIR_EVENTS[0] != '/' ) {
|
||||
// not using an absolute path. Make it one by appending ZM_PATH_WEB
|
||||
snprintf( path, sizeof (path), "%s/%s", staticConfig.PATH_WEB.c_str( ), config.dir_events );
|
||||
snprintf( path, sizeof (path), "%s/%s", staticConfig.PATH_WEB.c_str( ), staticConfig.DIR_EVENTS.c_str() );
|
||||
} else {
|
||||
strncpy(path, config.dir_events, sizeof(path) );
|
||||
strncpy(path, staticConfig.DIR_EVENTS.c_str(), sizeof(path) );
|
||||
}
|
||||
Debug(1,"No id passed to Storage constructor. Using default path %s instead", path );
|
||||
strcpy(name, "Default");
|
||||
|
|
|
@ -291,7 +291,7 @@ void StreamBase::openComms()
|
|||
if ( connkey > 0 )
|
||||
{
|
||||
|
||||
unsigned int length = snprintf( sock_path_lock, sizeof(sock_path_lock), "%s/zms-%06d.lock", config.path_socks, connkey);
|
||||
unsigned int length = snprintf( sock_path_lock, sizeof(sock_path_lock), "%s/zms-%06d.lock", staticConfig.PATH_SOCKS.c_str(), connkey);
|
||||
if ( length >= sizeof(sock_path_lock) ) {
|
||||
Warning("Socket lock path was truncated.");
|
||||
length = sizeof(sock_path_lock)-1;
|
||||
|
@ -321,7 +321,7 @@ void StreamBase::openComms()
|
|||
Debug(3, "Have socket %d", sd );
|
||||
}
|
||||
|
||||
length = snprintf( loc_sock_path, sizeof(loc_sock_path), "%s/zms-%06ds.sock", config.path_socks, connkey );
|
||||
length = snprintf( loc_sock_path, sizeof(loc_sock_path), "%s/zms-%06ds.sock", staticConfig.PATH_SOCKS.c_str(), connkey );
|
||||
if ( length >= sizeof(loc_sock_path) ) {
|
||||
Warning("Socket path was truncated.");
|
||||
length = sizeof(loc_sock_path)-1;
|
||||
|
@ -339,7 +339,7 @@ void StreamBase::openComms()
|
|||
Fatal( "Can't bind: %s", strerror(errno) );
|
||||
}
|
||||
|
||||
snprintf( rem_sock_path, sizeof(rem_sock_path), "%s/zms-%06dw.sock", config.path_socks, connkey );
|
||||
snprintf( rem_sock_path, sizeof(rem_sock_path), "%s/zms-%06dw.sock", staticConfig.PATH_SOCKS.c_str(), connkey );
|
||||
strncpy( rem_addr.sun_path, rem_sock_path, sizeof(rem_addr.sun_path) );
|
||||
rem_addr.sun_family = AF_UNIX;
|
||||
} // end if connKey > 0
|
||||
|
|
|
@ -44,6 +44,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
|||
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
|
||||
video_input_context = avcodec_alloc_context3( NULL );
|
||||
avcodec_parameters_to_context( video_input_context, video_input_stream->codecpar );
|
||||
zm_dump_codecpar( video_input_stream->codecpar );
|
||||
#else
|
||||
video_input_context = video_input_stream->codec;
|
||||
#endif
|
||||
|
@ -85,6 +86,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
|||
output_format = oc->oformat;
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
|
||||
|
||||
// Since we are not re-encoding, all we have to do is copy the parameters
|
||||
video_output_context = avcodec_alloc_context3( NULL );
|
||||
|
||||
|
@ -94,7 +96,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
|||
Error( "Could not initialize context parameteres");
|
||||
return;
|
||||
} else {
|
||||
Debug( 2, "Success getting parameters");
|
||||
zm_dump_codec( video_output_context );
|
||||
}
|
||||
|
||||
video_output_stream = avformat_new_stream( oc, NULL );
|
||||
|
@ -104,6 +106,11 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
|||
Debug(2, "Success creating video out stream" );
|
||||
}
|
||||
|
||||
if ( ! video_output_context->codec_tag ) {
|
||||
video_output_context->codec_tag = av_codec_get_tag(oc->oformat->codec_tag, video_input_context->codec_id);
|
||||
Debug(2, "No codec_tag, setting to %d", video_output_context->codec_tag );
|
||||
}
|
||||
|
||||
// Now copy them to the output stream
|
||||
ret = avcodec_parameters_from_context( video_output_stream->codecpar, video_output_context );
|
||||
if ( ret < 0 ) {
|
||||
|
@ -112,8 +119,8 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
|||
} else {
|
||||
Debug(2, "Success setting parameters");
|
||||
}
|
||||
zm_dump_codecpar( video_output_stream->codecpar );
|
||||
|
||||
zm_dump_stream_format( oc, 0, 0, 1 );
|
||||
#else
|
||||
video_output_stream = avformat_new_stream(oc, (AVCodec*)video_input_context->codec );
|
||||
if ( ! video_output_stream ) {
|
||||
|
@ -129,6 +136,15 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
|||
} else {
|
||||
Debug(3, "Success copying context" );
|
||||
}
|
||||
if ( ! video_output_context->codec_tag ) {
|
||||
Debug(2, "No codec_tag");
|
||||
if (! oc->oformat->codec_tag
|
||||
|| av_codec_get_id (oc->oformat->codec_tag, video_input_context->codec_tag) == video_output_context->codec_id
|
||||
|| av_codec_get_tag(oc->oformat->codec_tag, video_input_context->codec_id) <= 0) {
|
||||
Warning("Setting codec tag");
|
||||
video_output_context->codec_tag = video_input_context->codec_tag;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Just copy them from the input, no reason to choose different
|
||||
|
@ -146,17 +162,6 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
|||
video_output_context->time_base.den
|
||||
);
|
||||
|
||||
// WHY?
|
||||
//video_output_context->codec_tag = 0;
|
||||
if ( ! video_output_context->codec_tag ) {
|
||||
Debug(2, "No codec_tag");
|
||||
if (! oc->oformat->codec_tag
|
||||
|| av_codec_get_id (oc->oformat->codec_tag, video_input_context->codec_tag) == video_output_context->codec_id
|
||||
|| av_codec_get_tag(oc->oformat->codec_tag, video_input_context->codec_id) <= 0) {
|
||||
Warning("Setting codec tag");
|
||||
video_output_context->codec_tag = video_input_context->codec_tag;
|
||||
}
|
||||
}
|
||||
|
||||
if (oc->oformat->flags & AVFMT_GLOBALHEADER) {
|
||||
video_output_context->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
||||
|
@ -218,18 +223,31 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
|||
Debug(2, "setting parameters");
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0)
|
||||
audio_output_context = avcodec_alloc_context3( NULL );
|
||||
audio_output_context = avcodec_alloc_context3( audio_output_codec );
|
||||
// Copy params from inputstream to context
|
||||
ret = avcodec_parameters_to_context( audio_output_context, audio_input_stream->codecpar );
|
||||
if (ret < 0) {
|
||||
Error("Unable to copy audio params to context %s\n", av_make_error_string(ret).c_str());
|
||||
}
|
||||
ret = avcodec_parameters_from_context( audio_output_stream->codecpar, audio_output_context );
|
||||
if (ret < 0) {
|
||||
Error("Unable to copy audio params to stream %s\n", av_make_error_string(ret).c_str());
|
||||
}
|
||||
|
||||
if ( ! audio_output_context->codec_tag ) {
|
||||
audio_output_context->codec_tag = av_codec_get_tag(oc->oformat->codec_tag, audio_input_context->codec_id);
|
||||
Debug(2, "Setting audio codec tag to %d", audio_output_context->codec_tag );
|
||||
}
|
||||
|
||||
#else
|
||||
audio_output_context = audio_output_stream->codec;
|
||||
ret = avcodec_copy_context(audio_output_context, audio_input_context);
|
||||
audio_output_context->codec_tag = 0;
|
||||
#endif
|
||||
if (ret < 0) {
|
||||
Error("Unable to copy audio context %s\n", av_make_error_string(ret).c_str());
|
||||
audio_output_stream = NULL;
|
||||
} else {
|
||||
audio_output_context->codec_tag = 0;
|
||||
if ( audio_output_context->channels > 1 ) {
|
||||
Warning("Audio isn't mono, changing it.");
|
||||
audio_output_context->channels = 1;
|
||||
|
@ -265,10 +283,10 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
|||
zm_dump_stream_format( oc, 1, 0, 1 );
|
||||
|
||||
AVDictionary * opts = NULL;
|
||||
//av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
|
||||
av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
|
||||
//av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
|
||||
//av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov+default_base_moof", 0);
|
||||
if ((ret = avformat_write_header(oc, NULL)) < 0) {
|
||||
if ((ret = avformat_write_header( oc, &opts )) < 0) {
|
||||
//if ((ret = avformat_write_header(oc, &opts)) < 0) {
|
||||
Warning("Unable to set movflags to frag_custom+dash+delay_moov");
|
||||
/* Write the stream header, if any. */
|
||||
|
|
|
@ -112,7 +112,7 @@ void Zone::Setup(
|
|||
if ( config.record_diag_images ) {
|
||||
static char diag_path[PATH_MAX] = "";
|
||||
if ( ! diag_path[0] ) {
|
||||
snprintf( diag_path, sizeof(diag_path), "%s/%s/diag-%d-poly.jpg", config.dir_events, monitor->Name(), id);
|
||||
snprintf( diag_path, sizeof(diag_path), "%s/%s/diag-%d-poly.jpg", staticConfig.DIR_EVENTS.c_str(), monitor->Name(), id);
|
||||
}
|
||||
pg_image->WriteJpeg( diag_path );
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
|||
if ( config.record_diag_images ) {
|
||||
static char diag_path[PATH_MAX] = "";
|
||||
if ( ! diag_path[0] ) {
|
||||
snprintf( diag_path, sizeof(diag_path), "%s/%s/diag-%d-%d.jpg", config.dir_events, monitor->Name(), id, 1 );
|
||||
snprintf( diag_path, sizeof(diag_path), "%s/%s/diag-%d-%d.jpg", staticConfig.DIR_EVENTS.c_str(), monitor->Name(), id, 1 );
|
||||
}
|
||||
diff_image->WriteJpeg( diag_path );
|
||||
}
|
||||
|
@ -315,7 +315,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
|||
if ( config.record_diag_images ) {
|
||||
static char diag_path[PATH_MAX] = "";
|
||||
if ( !diag_path[0] ) {
|
||||
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-%d.jpg", config.dir_events, monitor->Id(), id, 2 );
|
||||
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-%d.jpg", staticConfig.DIR_EVENTS.c_str(), monitor->Id(), id, 2 );
|
||||
}
|
||||
diff_image->WriteJpeg( diag_path );
|
||||
}
|
||||
|
@ -525,7 +525,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
|||
if ( config.record_diag_images ) {
|
||||
static char diag_path[PATH_MAX] = "";
|
||||
if ( !diag_path[0] ) {
|
||||
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-%d.jpg", config.dir_events, monitor->Id(), id, 3 );
|
||||
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-%d.jpg", staticConfig.DIR_EVENTS.c_str(), monitor->Id(), id, 3 );
|
||||
}
|
||||
diff_image->WriteJpeg( diag_path );
|
||||
}
|
||||
|
@ -572,7 +572,7 @@ bool Zone::CheckAlarms( const Image *delta_image ) {
|
|||
if ( config.record_diag_images ) {
|
||||
static char diag_path[PATH_MAX] = "";
|
||||
if ( !diag_path[0] ) {
|
||||
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-%d.jpg", config.dir_events, monitor->Id(), id, 4 );
|
||||
snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-%d-%d.jpg", staticConfig.DIR_EVENTS.c_str(), monitor->Id(), id, 4 );
|
||||
}
|
||||
diff_image->WriteJpeg( diag_path );
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
# A script to provide background noise so Travis doesn't kill us due to inactivity
|
||||
# written by Andrew Bauer
|
||||
|
||||
while true; do
|
||||
echo "$(date) - Please don't kill us Mr. Travis, we are still running!"
|
||||
sleep 30s
|
||||
done
|
||||
|
|
@ -255,7 +255,11 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then
|
|||
setrpmchangelog
|
||||
|
||||
echo "Starting packpack..."
|
||||
packpack/packpack -f utils/packpack/redhat_package.mk redhat_package
|
||||
utils/packpack/heartbeat.sh &
|
||||
mypid=$!
|
||||
packpack/packpack -f utils/packpack/redhat_package.mk redhat_package > buildlog.txt 2>&1
|
||||
kill $mypid
|
||||
tail -n 1000 buildlog.txt
|
||||
|
||||
# Steps common to Debian based distros
|
||||
elif [ "${OS}" == "debian" ] || [ "${OS}" == "ubuntu" ]; then
|
||||
|
@ -275,7 +279,11 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then
|
|||
setdebchangelog
|
||||
|
||||
echo "Starting packpack..."
|
||||
packpack/packpack
|
||||
utils/packpack/heartbeat.sh &
|
||||
mypid=$!
|
||||
packpack/packpack > buildlog.txt 2>&1
|
||||
kill $mypid
|
||||
tail -n 1000 buildlog.txt
|
||||
|
||||
if [ "${OS}" == "ubuntu" ] && [ "${DIST}" == "trusty" ] && [ "${ARCH}" == "x86_64" ] && [ "${TRAVIS}" == "true" ]; then
|
||||
installtrusty
|
||||
|
@ -295,7 +303,11 @@ elif [ "${OS}" == "ubuntu" ] && [ "${DIST}" == "trusty" ] && [ "${ARCH}" == "x86
|
|||
setdebchangelog
|
||||
|
||||
echo "Starting packpack..."
|
||||
packpack/packpack
|
||||
utils/packpack/heartbeat.sh &
|
||||
mypid=$!
|
||||
packpack/packpack > buildlog.txt 2>&1
|
||||
kill $mypid
|
||||
tail -n 1000 buildlog.txt
|
||||
|
||||
# If we are running inside Travis then attempt to install the deb we just built
|
||||
if [ "${TRAVIS}" == "true" ]; then
|
||||
|
|
|
@ -800,7 +800,6 @@ if ( !empty($action) ) {
|
|||
switch( $_REQUEST['tab'] ) {
|
||||
case 'system' :
|
||||
case 'config' :
|
||||
case 'paths' :
|
||||
$restartWarning = true;
|
||||
break;
|
||||
case 'web' :
|
||||
|
|
|
@ -73,8 +73,8 @@ function xhtmlHeaders( $file, $title ) {
|
|||
<script type="text/javascript" src="tools/mootools/mootools-core.js"></script>
|
||||
<script type="text/javascript" src="tools/mootools/mootools-more.js"></script>
|
||||
<script type="text/javascript" src="js/mootools.ext.js"></script>
|
||||
<script type="text/javascript" src="skins/<?php echo $skin; ?>/js/jquery-1.11.3.js"></script>
|
||||
<script type="text/javascript" src="skins/<?php echo $skin; ?>/js/jquery-ui-1.11.3.js"></script>
|
||||
<script type="text/javascript" src="skins/<?php echo $skin; ?>/js/jquery.js"></script>
|
||||
<script type="text/javascript" src="skins/<?php echo $skin; ?>/js/jquery-ui.js"></script>
|
||||
<script type="text/javascript" src="skins/<?php echo $skin; ?>/js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
|
@ -82,7 +82,6 @@ function xhtmlHeaders( $file, $title ) {
|
|||
var $j = jQuery.noConflict();
|
||||
// $j is now an alias to the jQuery function; creating the new alias is optional.
|
||||
|
||||
<?php include("skins/$skin/views/js/state.js.php")?>
|
||||
//-->
|
||||
//]]>
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
jquery-ui-1.11.3.js
|
|
@ -260,8 +260,8 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
|
|||
<input type="button" class="btn btn-primary" name="addBtn" value="<?php echo translate('AddNewMonitor') ?>" onclick="addMonitor( this )"/>
|
||||
<!-- <?php echo makePopupButton( '?view=monitor', 'zmMonitor0', 'monitor', translate('AddNewMonitor'), (canEdit( 'Monitors' ) && !$user['MonitorIds']) ) ?> -->
|
||||
<?php echo makePopupButton( '?view=filter&filter[terms][0][attr]=DateTime&filter[terms][0][op]=%3c&filter[terms][0][val]=now', 'zmFilter', 'filter', translate('Filters'), canView( 'Events' ) ) ?>
|
||||
<input class="btn btn-primary" type="button" name="editBtn" value="<?php echo translate('Edit') ?>" onclick="editMonitor( this )" disabled="disabled"/>
|
||||
<input class="btn btn-danger" type="button" name="deleteBtn" value="<?php echo translate('Delete') ?>" onclick="deleteMonitor( this )" disabled="disabled"/>
|
||||
<input type="button" name="editBtn" value="<?php echo translate('Edit') ?>" onclick="editMonitor( this )" disabled="disabled"/>
|
||||
<input type="button" name="deleteBtn" value="<?php echo translate('Delete') ?>" onclick="deleteMonitor( this )" disabled="disabled"/>
|
||||
</td>
|
||||
<?php
|
||||
for ( $i = 0; $i < count($eventCounts); $i++ ) {
|
||||
|
|
|
@ -225,7 +225,7 @@ for ( $i = 0; isset($_REQUEST['filter']) && $i < count($_REQUEST['filter']['term
|
|||
<?php } ?>
|
||||
</td>
|
||||
<?php
|
||||
} elseif ( $_REQUEST['filter']['terms'][$i]['attr'] == "StateId" ) {
|
||||
} elseif ( $_REQUEST['filter']['terms'][$i]['attr'] == 'StateId' ) {
|
||||
$states = array();
|
||||
foreach ( dbFetchAll( 'SELECT Id,Name FROM States ORDER BY lower(Name) ASC' ) as $state_row ) {
|
||||
$states[$state_row['Id']] = $state_row['Name'];
|
||||
|
|
|
@ -32,7 +32,6 @@ $tabs['system'] = translate('System');
|
|||
$tabs['config'] = translate('Config');
|
||||
$tabs['servers'] = translate('Servers');
|
||||
$tabs['storage'] = translate('Storage');
|
||||
$tabs['paths'] = translate('Paths');
|
||||
$tabs['web'] = translate('Web');
|
||||
$tabs['images'] = translate('Images');
|
||||
$tabs['logging'] = translate('Logging');
|
||||
|
|
40
zm.conf.in
40
zm.conf.in
|
@ -50,3 +50,43 @@ ZM_DB_USER=@ZM_DB_USER@
|
|||
# ZoneMinder database password
|
||||
ZM_DB_PASS=@ZM_DB_PASS@
|
||||
|
||||
# Full path to the folder events are recorded to.
|
||||
# The web account user must have full read/write permission to this folder.
|
||||
ZM_DIR_EVENTS=@ZM_DIR_EVENTS@
|
||||
|
||||
# Full path to the folder images, not directly associated with events,
|
||||
# are recorded to.
|
||||
# The web account user must have full read/write permission to this folder.
|
||||
ZM_DIR_IMAGES=@ZM_DIR_IMAGES@
|
||||
|
||||
# Foldername under the webroot where ZoneMinder looks for optional sound files
|
||||
# to play when an alarm is detected.
|
||||
ZM_DIR_SOUNDS=@ZM_DIR_SOUNDS@
|
||||
|
||||
# Full path to the folder where exported archives are stored
|
||||
# The web account user must have full read/write permission to this folder.
|
||||
ZM_DIR_EXPORTS=@ZM_TMPDIR@
|
||||
|
||||
# ZoneMinder url path to the zms streaming server
|
||||
ZM_PATH_ZMS=@ZM_PATH_ZMS@
|
||||
|
||||
# Full Path to ZoneMinder's mapped memory files
|
||||
# The web account user must have full read/write permission to this folder.
|
||||
ZM_PATH_MAP=@ZM_PATH_MAP@
|
||||
|
||||
# Full Path to ZoneMinder's socket folder
|
||||
# The web account user must have full read/write permission to this folder.
|
||||
ZM_PATH_SOCKS=@ZM_SOCKDIR@
|
||||
|
||||
# Full path to ZoneMinder's log folder
|
||||
# The web account user must have full read/write permission to this folder.
|
||||
ZM_PATH_LOGS=@ZM_LOGDIR@
|
||||
|
||||
# Full path to ZoneMinder's swap folder
|
||||
# The web account user must have full read/write permission to this folder.
|
||||
ZM_PATH_SWAP=@ZM_TMPDIR@
|
||||
|
||||
# Full path to optional arp binary
|
||||
# ZoneMinder will find the arp binary automatically on most systems
|
||||
ZM_PATH_ARP=@ZM_PATH_ARP@
|
||||
|
||||
|
|
Loading…
Reference in New Issue