Merge branch 'master' of github.com:ZoneMinder/zoneminder

pull/3174/head
Isaac Connor 2021-02-18 16:05:10 -05:00
commit 0b0df96271
57 changed files with 1006 additions and 1112 deletions

3
.gitignore vendored
View File

@ -122,13 +122,10 @@ src/libzm.a
src/nph-zms
src/zm_config_data.h
src/zm_config_defines.h
src/zma
src/zmc
src/zmf
src/zms
src/zmu
src/zoneminder-zma.8
src/zoneminder-zma.8.gz
src/zoneminder-zmc.8
src/zoneminder-zmc.8.gz
src/zoneminder-zmf.8

View File

@ -93,6 +93,11 @@ mark_as_advanced(
option(BUILD_TEST_SUITE "Build the test suite" 0)
option(BUILD_MAN "Build man pages" 1)
option(ASAN "DEBUGGING: Build with AddressSanitizer (ASan) support" 0)
option(TSAN "DEBUGGING: Build with ThreadSanitizer (TSan) support" 0)
if(ASAN AND TSAN)
message(FATAL_ERROR "ASAN and TSAN options are mutually exclusive")
endif()
set(ZM_RUNDIR "/var/run/zm" CACHE PATH
"Location of transient process files, default: /var/run/zm")

View File

@ -19,3 +19,15 @@ if(ASAN)
message(STATUS "Clang: Enabled AddressSanitizer (ASan)")
endif()
if(TSAN)
target_compile_options(zm-compile-option-interface
INTERFACE
-fsanitize=thread)
target_link_options(zm-compile-option-interface
INTERFACE
-fsanitize=thread)
message(STATUS "Clang: Enabled ThreadSanitizer (TSan)")
endif()

View File

@ -19,3 +19,15 @@ if(ASAN)
message(STATUS "GCC: Enabled AddressSanitizer (ASan)")
endif()
if(TSAN)
target_compile_options(zm-compile-option-interface
INTERFACE
-fsanitize=thread)
target_link_options(zm-compile-option-interface
INTERFACE
-fsanitize=thread)
message(STATUS "GCC: Enabled ThreadSanitizer (TSan)")
endif()

View File

@ -341,7 +341,6 @@ ln -sf %{_sysconfdir}/zm/www/zoneminder.nginx.conf %{_sysconfdir}/zm/www/zonemin
%{_datadir}/polkit-1/actions/com.zoneminder.systemctl.policy
%{_bindir}/zmsystemctl.pl
%{_bindir}/zma
%{_bindir}/zmaudit.pl
%{_bindir}/zmc
%{_bindir}/zmcontrol.pl

View File

@ -1 +1 @@
9
12

View File

@ -16,11 +16,6 @@ Alias /zm/cache /var/cache/zoneminder/cache
# Apache 2.4
Require all granted
</IfModule>
<IfModule !mod_authz_core.c>
# Apache 2.2
Order deny,allow
Allow from all
</IfModule>
</Directory>
Alias /zm /usr/share/zoneminder/www

View File

@ -2,8 +2,7 @@ Source: zoneminder
Section: net
Priority: optional
Maintainer: Isaac Connor <isaac@zoneminder.com>
Uploaders: Isaac Connor <isaac@zoneminder.com>
Build-Depends: debhelper, dh-systemd, sphinx-doc, python3-sphinx, dh-linktree, dh-systemd, dh-apache2
Build-Depends: debhelper (>= 12), sphinx-doc, python3-sphinx, dh-linktree, dh-apache2
,cmake
,libavdevice-dev
,libavcodec-dev
@ -33,10 +32,8 @@ Build-Depends: debhelper, dh-systemd, sphinx-doc, python3-sphinx, dh-linktree, d
,libcrypt-eksblowfish-perl
,libdata-entropy-perl
,libvncserver-dev
Standards-Version: 3.9.8
Homepage: http://www.zoneminder.com/
Vcs-Browser: http://anonscm.debian.org/cgit/collab-maint/zoneminder.git
Vcs-Git: git://anonscm.debian.org/collab-maint/zoneminder.git
Standards-Version: 4.5.0
Homepage: https://www.zoneminder.com/
Package: zoneminder
Architecture: any
@ -68,8 +65,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
,libdata-uuid-perl
,libnumber-bytes-human-perl
,libfile-slurp-perl
,mysql-client | mariadb-client | virtual-mysql-client
,perl-modules
,default-mysql-client | mariadb-client | virtual-mysql-client
,php-mysql, php-gd, php-apcu, php-apc | php-apcu-bc, php-json
,policykit-1
,rsyslog | system-log-daemon
@ -80,9 +76,8 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
,libvncclient1|libvncclient0
Recommends: ${misc:Recommends}
,libapache2-mod-php | php-fpm
,mysql-server | mariadb-server | virtual-mysql-server
,default-mysql-server | mariadb-server | virtual-mysql-server
,zoneminder-doc (>= ${source:Version})
,ffmpeg
Suggests: fcgiwrap, logrotate
Description: video camera security and surveillance solution
ZoneMinder is intended for use in single or multi-camera video security
@ -146,7 +141,7 @@ Description: ZoneMinder documentation
Package: zoneminder-dbg
Section: debug
Priority: extra
Priority: optional
Architecture: any
Depends: zoneminder (= ${binary:Version}), ${misc:Depends}
Description: Zoneminder -- debugging symbols

View File

@ -1,6 +1,6 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: ZoneMinder
Upstream-Contact: Philip Coombes <philip.coombes@zoneminder.com>
Upstream-Contact: Isaac Connor <isaac@zoneminder.com>
Source: https://github.com/ZoneMinder/ZoneMinder
Comment:
This package was originally debianized by matrix <matrix@cecilia>

View File

@ -1,5 +1,4 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
@ -12,13 +11,14 @@ ARGS:= -DZM_NO_MMAP=ON
endif
%:
dh $@ --parallel --buildsystem=cmake --builddirectory=dbuild \
--with systemd,sphinxdoc,apache2,linktree
dh $@ --buildsystem=cmake --builddirectory=dbuild \
--with sphinxdoc,apache2,linktree
override_dh_auto_configure:
dh_auto_configure -- $(ARGS) \
-DCMAKE_VERBOSE_MAKEFILE=ON \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_MAN=0 \
-DZM_CONFIG_DIR="/etc/zm" \
-DZM_CONFIG_SUBDIR="/etc/zm/conf.d" \
-DZM_RUNDIR="/run/zm" \
@ -34,11 +34,26 @@ override_dh_clean:
dh_clean $(MANPAGES1)
$(RM) -r docs/_build
build-indep:
#$(MAKE) -C docs text
override_dh_auto_build-indep:
$(MAKE) -C docs html
dh_auto_build
MANPAGES1 = \
dbuild/scripts/zmupdate.pl.1 \
dbuild/scripts/zmaudit.pl.1 \
dbuild/scripts/zmcamtool.pl.1 \
dbuild/scripts/zmcontrol.pl.1 \
dbuild/scripts/zmdc.pl.1 \
dbuild/scripts/zmfilter.pl.1 \
dbuild/scripts/zmpkg.pl.1 \
dbuild/scripts/zmsystemctl.pl.1 \
dbuild/scripts/zmtelemetry.pl.1 \
dbuild/scripts/zmtrack.pl.1 \
dbuild/scripts/zmtrigger.pl.1 \
dbuild/scripts/zmvideo.pl.1 \
dbuild/scripts/zmwatch.pl.1 \
dbuild/scripts/zmx10.pl.1
MANPAGES1 = dbuild/scripts/zmupdate.pl.1
$(MANPAGES1):
# generate man page(s):
pod2man -s1 --stderr --utf8 $(patsubst %.1, %, $@) $@
@ -51,7 +66,7 @@ override_dh_installman: $(MANPAGES1)
dh_installman --language=C $(MANPAGES1)
override_dh_auto_install:
dh_auto_install --destdir=$(CURDIR)/debian/tmp
dh_auto_install --arch --destdir=$(CURDIR)/debian/tmp
# remove worthless files:
$(RM) -v $(CURDIR)/debian/tmp/usr/share/perl5/*/*/*/.packlist
$(RM) -v $(CURDIR)/debian/tmp/usr/share/perl5/*/*.in
@ -67,11 +82,11 @@ override_dh_fixperms:
chown root:www-data $(CURDIR)/debian/zoneminder/etc/zm/zm.conf
chmod 640 $(CURDIR)/debian/zoneminder/etc/zm/zm.conf
override_dh_systemd_start:
dh_systemd_start --no-start
override_dh_installinit:
dh_installinit --no-start
override_dh_systemd_enable:
dh_systemd_enable --no-enable
override_dh_installsystemd:
dh_installsystemd --no-enable --no-start
override_dh_apache2:
dh_apache2 --noenable
@ -81,16 +96,3 @@ override_dh_strip:
&& dh_strip --dbg-package=zoneminder-dbg \
|| dh_strip
#%:
# dh $@ --parallel --buildsystem=autoconf --with autoreconf
#
#override_dh_auto_configure:
# dh_auto_configure -- \
# --sysconfdir=/etc/zm \
# --with-mysql=/usr \
# --with-webdir=/usr/share/zoneminder \
# --with-ffmpeg=/usr \
# --with-cgidir=/usr/lib/cgi-bin \
# --with-webuser=www-data \
# --with-webgroup=www-data \
# --enable-mmap=yes

View File

@ -6,7 +6,9 @@ usr/share/polkit-1
usr/share/zoneminder/db
usr/share/zoneminder/www
usr/share/zoneminder/fonts
usr/share/zoneminder/icons
usr/share/applications/*
# libzoneminder-perl files:
usr/share/man/man3
#usr/share/man/man3
usr/share/perl5

View File

@ -1,6 +0,0 @@
## cakephp
#replace /usr/share/php/Cake /usr/share/zoneminder/www/api/lib/Cake
## libjs-jquery
replace /usr/share/javascript/jquery/jquery.min.js /usr/share/zoneminder/www/skins/classic/js/jquery-3.5.1.min.js
replace /usr/share/javascript/jquery/jquery.min.js /usr/share/zoneminder/www/skins/flat/js/jquery-3.5.1.min.js

View File

@ -52,7 +52,10 @@ if [ "$1" = "configure" ]; then
chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/*
if [ ! -e "/etc/apache2/mods-enabled/cgi.load" ] && [ "$(command -v a2enmod)" != "" ]; then
echo "The cgi module is not enabled in apache2. I am enabling it using a2enmod cgi."
a2enmod cgi
if [ -e /usr/share/apache2/apache2-maintscript-helper ] ; then
. /usr/share/apache2/apache2-maintscript-helper
apache2_invoke enmod cgi || exit $?
fi
fi
SYSTEMD=0

View File

@ -15,9 +15,6 @@
import sys
import os
def setup(app):
app.add_stylesheet('zmstyle.css')
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
@ -134,7 +131,9 @@ html_theme = 'default'
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
#html_style='zmstyles.css'
html_css_files = [ 'zmstyle.css' ]
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied

View File

@ -184,6 +184,7 @@ sub moveVector {
# Send it to the camera
$self->PutCmd($command,$xml);
}
sub zoomStop { $_[0]->moveVector( 0, 0, 0, splice(@_,1)); }
sub moveStop { $_[0]->moveVector( 0, 0, 0, splice(@_,1)); }
sub moveConUp { $_[0]->moveVector( 0, 1, 0, splice(@_,1)); }
sub moveConUpRight { $_[0]->moveVector( 1, 1, 0, splice(@_,1)); }

View File

@ -144,8 +144,8 @@ our $mem_seq = 0;
our $mem_data = {
shared_data => { type=>'SharedData', seq=>$mem_seq++, contents=> {
size => { type=>'uint32', seq=>$mem_seq++ },
last_write_index => { type=>'uint32', seq=>$mem_seq++ },
last_read_index => { type=>'uint32', seq=>$mem_seq++ },
last_write_index => { type=>'int32', seq=>$mem_seq++ },
last_read_index => { type=>'int32', seq=>$mem_seq++ },
state => { type=>'uint32', seq=>$mem_seq++ },
capture_fps => { type=>'double', seq=>$mem_seq++ },
analysis_fps => { type=>'double', seq=>$mem_seq++ },
@ -162,7 +162,7 @@ our $mem_data = {
signal => { type=>'uint8', seq=>$mem_seq++ },
format => { type=>'uint8', seq=>$mem_seq++ },
imagesize => { type=>'uint32', seq=>$mem_seq++ },
epadding1 => { type=>'uint32', seq=>$mem_seq++ },
last_frame_score => { type=>'uint32', seq=>$mem_seq++ },
startup_time => { type=>'time_t64', seq=>$mem_seq++ },
zmc_heartbeat_time => { type=>'time_t64', seq=>$mem_seq++ },
zma_heartbeat_time => { type=>'time_t64', seq=>$mem_seq++ },

View File

@ -92,7 +92,6 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
my @daemons = (
'zmc',
#'zma',
'zmfilter.pl',
'zmaudit.pl',
'zmtrigger.pl',

View File

@ -360,6 +360,7 @@ sub checkFilter {
if ( $filter->{AutoMove} ) {
my $NewStorage = new ZoneMinder::Storage($filter->{AutoMoveTo});
Info("Moving event $Event->{Id} to datastore $filter->{AutoMoveTo}");
$_ = $Event->MoveTo($NewStorage);
Error($_) if $_;
}
@ -368,6 +369,7 @@ sub checkFilter {
# So we still need to update the Event object with the new SecondaryStorageId
my $NewStorage = ZoneMinder::Storage->find_one(Id=>$filter->{AutoCopyTo});
if ( $NewStorage ) {
Info("Copying event $Event->{Id} to datastore $filter->{AutoCopyTo}");
$_ = $Event->CopyTo($NewStorage);
if ( $_ ) {
$ZoneMinder::Database::dbh->commit();

View File

@ -224,6 +224,7 @@ Debug("@Monitors");
$$Event{RelativePath} = join('/', $day_dir, $event_path);
$$Event{Scheme} = 'Deep';
$$Event{Name} = "Event $event_id recovered";
$$Event{StateId} = 1;
$Event->MonitorId( $monitor_dir );
$Event->StorageId( $Storage->Id() );
$Event->DiskSpace( undef );
@ -287,6 +288,7 @@ Debug("@Monitors");
$$Event{RelativePath} = join('/', $day_dir, $event_dir);
$$Event{Scheme} = 'Deep';
$$Event{Name} = "Event $event_id recovered";
$$Event{StateId} = 1;
$Event->MonitorId( $monitor_dir );
$Event->Width( $Monitor->Width() );
$Event->Height( $Monitor->Height() );
@ -352,6 +354,7 @@ Debug("@Monitors");
$$Event{Scheme} = 'Medium';
$$Event{RelativePath} = $event_dir;
$$Event{Name} = "Event $event_id recovered";
$$Event{StateId} = 1;
$Event->MonitorId( $monitor_dir );
$Event->Width( $Monitor->Width() );
$Event->Height( $Monitor->Height() );
@ -393,6 +396,7 @@ Debug("@Monitors");
if ( confirm() ) {
$$Event{Scheme} = 'Shallow';
$$Event{Name} = "Event $event recovered";
$$Event{StateId} = 1;
#$$Event{Path} = $event_path;
$Event->MonitorId( $monitor_dir );
$Event->Width( $Monitor->Width() );

View File

@ -9,7 +9,7 @@ AnalysisThread::AnalysisThread(std::shared_ptr<Monitor> monitor) :
}
AnalysisThread::~AnalysisThread() {
terminate_ = true;
Stop();
if (thread_.joinable())
thread_.join();
}
@ -40,10 +40,11 @@ void AnalysisThread::Run() {
Debug(2, "Analyzing");
if (!monitor_->Analyse()) {
Microseconds sleep_for = monitor_->Active() ? Microseconds(ZM_SAMPLE_RATE) : Microseconds(ZM_SUSPENDED_RATE);
Debug(2, "Sleeping for %" PRId64 "us", int64(sleep_for.count()));
std::this_thread::sleep_for(sleep_for);
if ( !(terminate_ or zm_terminate) ) {
Microseconds sleep_for = monitor_->Active() ? Microseconds(ZM_SAMPLE_RATE) : Microseconds(ZM_SUSPENDED_RATE);
Debug(2, "Sleeping for %" PRId64 "us", int64(sleep_for.count()));
std::this_thread::sleep_for(sleep_for);
}
} else if (analysis_rate != Microseconds::zero()) {
Debug(2, "Sleeping for %" PRId64 " us", int64(analysis_rate.count()));
std::this_thread::sleep_for(analysis_rate);

View File

@ -13,6 +13,8 @@ class AnalysisThread {
AnalysisThread(AnalysisThread &rhs) = delete;
AnalysisThread(AnalysisThread &&rhs) = delete;
void Stop() { terminate_ = true; }
private:
void Run();

View File

@ -21,10 +21,10 @@
#define ZM_CAMERA_H
#include "zm_image.h"
#include "zm_monitor.h"
#include <sys/ioctl.h>
#include <sys/types.h>
class Monitor;
class ZMPacket;
//
@ -76,7 +76,6 @@ public:
);
virtual ~Camera();
unsigned int getId() const { return monitor->Id(); }
SourceType Type() const { return type; }
bool IsLocal() const { return type == LOCAL_SRC; }
bool IsRemote() const { return type == REMOTE_SRC; }

View File

@ -175,6 +175,37 @@ MYSQL_RES *zmDbRow::fetch(const char *query) {
return result_set;
}
int zmDbDo(const char *query) {
db_mutex.lock();
int rc;
while ( rc = mysql_query(&dbconn, query) ) {
db_mutex.unlock();
Error("Can't run query %s: %s", query, mysql_error(&dbconn));
if ( (mysql_errno(&dbconn) != ER_LOCK_WAIT_TIMEOUT) )
return rc;
db_mutex.lock();
}
db_mutex.unlock();
return 1;
}
int zmDbDoInsert(const char *query) {
db_mutex.lock();
int rc;
while ( rc = mysql_query(&dbconn, query) ) {
db_mutex.unlock();
Error("Can't run query %s: %s", query, mysql_error(&dbconn));
if ( (mysql_errno(&dbconn) != ER_LOCK_WAIT_TIMEOUT) )
return 0;
db_mutex.lock();
}
int id = mysql_insert_id(&dbconn);
db_mutex.unlock();
return id;
}
zmDbRow::~zmDbRow() {
if ( result_set ) {
mysql_free_result(result_set);

View File

@ -22,6 +22,7 @@
#include "zm_thread.h"
#include <mysql/mysql.h>
#include <mysql/mysqld_error.h>
class zmDbRow {
private:
@ -47,6 +48,8 @@ extern bool zmDbConnected;
bool zmDbConnect();
void zmDbClose();
int zmDbDo(const char *query);
int zmDbDoInsert(const char *query);
MYSQL_RES * zmDbFetch( const char *query );
zmDbRow *zmDbFetchOne( const char *query );

View File

@ -105,8 +105,7 @@ Event::Event(
save_jpegs = monitor->GetOptSaveJPEGs();
Storage * storage = monitor->getStorage();
char sql[ZM_SQL_MED_BUFSIZ];
snprintf(sql, sizeof(sql),
std::string sql = stringtf(
"INSERT INTO `Events` "
"( `MonitorId`, `StorageId`, `Name`, `StartDateTime`, `Width`, `Height`, `Cause`, `Notes`, `StateId`, `Orientation`, `Videoed`, `DefaultVideo`, `SaveJPEGs`, `Scheme` )"
" VALUES "
@ -120,25 +119,19 @@ Event::Event(
notes.c_str(),
state_id,
monitor->getOrientation(),
( monitor->GetOptVideoWriter() != 0 ? 1 : 0 ),
( monitor->GetOptVideoWriter() != 0 ? "video.mp4" : "" ),
monitor->GetOptSaveJPEGs(),
0,
"",
save_jpegs,
storage->SchemeString().c_str()
);
db_mutex.lock();
while ( mysql_query(&dbconn, sql) ) {
db_mutex.unlock();
Error("Can't insert event: %s. sql was (%s)", mysql_error(&dbconn), sql);
db_mutex.lock();
}
id = mysql_insert_id(&dbconn);
id = zmDbDoInsert(sql.c_str());
if ( !SetPath(storage) ) {
// Try another
Warning("Failed creating event dir at %s", storage->Path());
std::string sql = stringtf("SELECT `Id` FROM `Storage` WHERE `Id` != %u", storage->Id());
sql = stringtf("SELECT `Id` FROM `Storage` WHERE `Id` != %u", storage->Id());
if ( monitor->ServerId() )
sql += stringtf(" AND ServerId=%u", monitor->ServerId());
@ -182,16 +175,10 @@ Event::Event(
Warning("Failed to find a storage area to save events.");
}
sql = stringtf("UPDATE Events SET StorageId = '%d' WHERE Id=%" PRIu64, storage->Id(), id);
db_mutex.lock();
int rc = mysql_query(&dbconn, sql.c_str());
db_mutex.unlock();
if ( rc ) {
Error("Can't update event: %s. sql was (%s)", mysql_error(&dbconn), sql.c_str());
}
}
zmDbDo(sql.c_str());
} // end if ! setPath(Storage)
Debug(1, "Using storage area at %s", path.c_str());
db_mutex.unlock();
video_name = "";
snapshot_file = path + "/snapshot.jpg";
@ -202,38 +189,33 @@ Event::Event(
if ( monitor->GetOptVideoWriter() != 0 ) {
std::string container = monitor->OutputContainer();
if ( container == "auto" || container == "" ) {
if ( monitor->OutputCodec() == AV_CODEC_ID_H264 ) {
container = "mp4";
} else {
container = "mkv";
}
container = "mp4";
}
video_name = stringtf("%" PRIu64 "-%s.%s", id, "video", container.c_str());
snprintf(sql, sizeof(sql), "UPDATE Events SET DefaultVideo = '%s' WHERE Id=%" PRIu64, video_name.c_str(), id);
db_mutex.lock();
if ( mysql_query(&dbconn, sql) ) {
db_mutex.unlock();
Error("Can't update event: %s. sql was (%s)", mysql_error(&dbconn), sql);
return;
}
db_mutex.unlock();
video_file = path + "/" + video_name;
Debug(1, "Writing video file to %s", video_file.c_str());
Camera * camera = monitor->getCamera();
videoStore = new VideoStore(
video_file.c_str(),
container.c_str(),
camera->get_VideoStream(),
camera->get_VideoCodecContext(),
( monitor->RecordAudio() ? camera->get_AudioStream() : nullptr ),
( monitor->RecordAudio() ? camera->get_AudioCodecContext() : nullptr ),
monitor->GetVideoStream(),
monitor->GetVideoCodecContext(),
( monitor->RecordAudio() ? monitor->GetAudioStream() : nullptr ),
( monitor->RecordAudio() ? monitor->GetAudioCodecContext() : nullptr ),
monitor );
if ( !videoStore->open() ) {
Warning("Failed to open videostore, turning on jpegs");
delete videoStore;
videoStore = nullptr;
save_jpegs |= 1; // Turn on jpeg storage
if ( ! ( save_jpegs & 1 ) ) {
save_jpegs |= 1; // Turn on jpeg storage
sql = stringtf("UPDATE Events SET SaveJpegs=%d WHERE Id=%" PRIu64, save_jpegs, id);
zmDbDo(sql.c_str());
}
} else {
sql = stringtf("UPDATE Events SET Videoed=1, DefaultVideo = '%s' WHERE Id=%" PRIu64, video_name.c_str(), id);
zmDbDo(sql.c_str());
}
} // end if GetOptVideoWriter
} // Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap, bool p_videoEvent )
@ -621,8 +603,8 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
( ! (frames % config.bulk_frame_interval) )
) ? BULK : NORMAL
) );
//Debug(1, "Have frame type %s from score(%d) state %d frames %d bulk frame interval %d and mod%d",
//frame_type_names[frame_type], score, monitor->GetState(), frames, config.bulk_frame_interval, (frames % config.bulk_frame_interval) );
Debug(1, "Have frame type %s from score(%d) state %d frames %d bulk frame interval %d and mod%d",
frame_type_names[frame_type], score, monitor->GetState(), frames, config.bulk_frame_interval, (frames % config.bulk_frame_interval) );
if ( score < 0 )
score = 0;
@ -662,6 +644,8 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
}
}
} // end if is an alarm frame
} else {
Debug(1, "No image");
} // end if has image
bool db_frame = ( frame_type == BULK ) or ( frame_type == ALARM ) or ( frames == 1 ) or ( score > (int)max_score ) or ( monitor_state == Monitor::ALERT ) or ( monitor_state == Monitor::PREALARM );

View File

@ -374,23 +374,19 @@ int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt) {
return 0;
}
void fix_deprecated_pix_fmt(AVCodecContext *ctx) {
enum AVPixelFormat fix_deprecated_pix_fmt(enum AVPixelFormat fmt) {
// Fix deprecated formats
switch ( ctx->pix_fmt ) {
switch ( fmt ) {
case AV_PIX_FMT_YUVJ422P :
ctx->pix_fmt = AV_PIX_FMT_YUV422P;
break;
return AV_PIX_FMT_YUV422P;
case AV_PIX_FMT_YUVJ444P :
ctx->pix_fmt = AV_PIX_FMT_YUV444P;
break;
return AV_PIX_FMT_YUV444P;
case AV_PIX_FMT_YUVJ440P :
ctx->pix_fmt = AV_PIX_FMT_YUV440P;
break;
return AV_PIX_FMT_YUV440P;
case AV_PIX_FMT_NONE :
case AV_PIX_FMT_YUVJ420P :
default:
ctx->pix_fmt = AV_PIX_FMT_YUV420P;
break;
return AV_PIX_FMT_YUV420P;
}
}

View File

@ -423,7 +423,7 @@ void zm_dump_codecpar(const AVCodecParameters *par);
#endif
int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt);
void fix_deprecated_pix_fmt(AVCodecContext *);
enum AVPixelFormat fix_deprecated_pix_fmt(enum AVPixelFormat );
bool is_video_stream(const AVStream *);
bool is_audio_stream(const AVStream *);

View File

@ -280,7 +280,7 @@ void Image::Assign(const AVFrame *frame) {
#if HAVE_LIBSWSCALE
sws_convert_context = sws_getCachedContext(
sws_convert_context,
width, height, (AVPixelFormat)frame->format,
frame->width, frame->height, (AVPixelFormat)frame->format,
width, height, format,
SWS_BICUBIC, nullptr, nullptr, nullptr);
if ( sws_convert_context == nullptr )

View File

@ -36,17 +36,16 @@ void bind_libvnc_symbols() {
*(void**) (&HandleRFBServerMessage_f) = dlsym(libvnc_lib, "HandleRFBServerMessage");
}
static void GotFrameBufferUpdateCallback(rfbClient *rfb, int x, int y, int w, int h){
static void GotFrameBufferUpdateCallback(rfbClient *rfb, int x, int y, int w, int h) {
VncPrivateData *data = (VncPrivateData *)(*rfbClientGetClientData_f)(rfb, &TAG_0);
data->buffer = rfb->frameBuffer;
Debug(1, "GotFrameBufferUpdateallback x:%d y:%d w%d h:%d width: %d, height: %d",
x,y,w,h, rfb->width, rfb->height);
Debug(1, "GotFrameBufferUpdateallback x:%d y:%d w%d h:%d width: %d, height: %d, buffer %p",
x,y,w,h, rfb->width, rfb->height, rfb->frameBuffer);
}
static char* GetPasswordCallback(rfbClient* cl){
Debug(1, "Getcredentials: %s", (*rfbClientGetClientData_f)(cl, &TAG_1));
return strdup(
(const char *)(*rfbClientGetClientData_f)(cl, &TAG_1));
return strdup((const char *)(*rfbClientGetClientData_f)(cl, &TAG_1));
}
static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){
@ -102,15 +101,12 @@ VncCamera::VncCamera(
if ( colours == ZM_COLOUR_RGB32 ) {
subpixelorder = ZM_SUBPIX_ORDER_RGBA;
mImgPixFmt = AV_PIX_FMT_RGBA;
mBpp = 4;
} else if ( colours == ZM_COLOUR_RGB24 ) {
subpixelorder = ZM_SUBPIX_ORDER_RGB;
mImgPixFmt = AV_PIX_FMT_RGB24;
mBpp = 3;
} else if ( colours == ZM_COLOUR_GRAY8 ) {
subpixelorder = ZM_SUBPIX_ORDER_NONE;
mImgPixFmt = AV_PIX_FMT_GRAY8;
mBpp = 1;
} else {
Panic("Unexpected colours: %d", colours);
}
@ -119,7 +115,6 @@ VncCamera::VncCamera(
Debug(3, "Initializing Client");
bind_libvnc_symbols();
scale.init();
}
}
@ -134,13 +129,16 @@ VncCamera::~VncCamera() {
int VncCamera::PrimeCapture() {
Debug(1, "Priming capture from %s", mHost.c_str());
if ( ! mRfb ) {
if (!mRfb) {
mVncData.buffer = nullptr;
mVncData.width = 0;
mVncData.height = 0;
mBufferSize = SWScale::GetBufferSize(AV_PIX_FMT_RGBA, width, height);
mRfb = (*rfbGetClient_f)(8 /* bits per sample */, 3 /* samples per pixel */, 4 /* bytes Per Pixel */);
mRfb->frameBuffer = (uint8_t *)av_malloc(8*4*width*height);
mRfb->frameBuffer = nullptr;
//(uint8_t *)av_malloc(mBufferSize);
mRfb->canHandleNewFBSize = false;
(*rfbClientSetClientData_f)(mRfb, &TAG_0, &mVncData);
@ -157,7 +155,7 @@ int VncCamera::PrimeCapture() {
}
if ( ! (*rfbInitClient_f)(mRfb, 0, nullptr) ) {
/* IF rfbInitClient fails, it calls rdbClientCleanup which will free mRfb */
Warning("Failed to Priming capture from %s", mHost.c_str());
Warning("Failed to Prime capture from %s", mHost.c_str());
mRfb = nullptr;
return -1;
}
@ -165,8 +163,9 @@ int VncCamera::PrimeCapture() {
Warning("Specified dimensions do not match screen size monitor: (%dx%d) != vnc: (%dx%d)",
width, height, mRfb->width, mRfb->height);
}
get_VideoStream();
return 0;
return 1;
}
int VncCamera::PreCapture() {
@ -182,15 +181,24 @@ int VncCamera::PreCapture() {
}
int VncCamera::Capture(ZMPacket &zm_packet) {
if ( ! mVncData.buffer ) {
if ( !mVncData.buffer ) {
Debug(1, "No buffer");
return 0;
}
if ( !zm_packet.image ) {
Debug(1, "Allocating image %dx%d %dcolours = %d", width, height, colours, pixels);
zm_packet.image = new Image(width, height, colours, subpixelorder);
}
zm_packet.keyframe = 1;
zm_packet.codec_type = AVMEDIA_TYPE_VIDEO;
zm_packet.packet.stream_index = mVideoStreamId;
uint8_t *directbuffer = zm_packet.image->WriteBuffer(width, height, colours, subpixelorder);
int rc = scale.Convert(
mVncData.buffer,
mRfb->si.framebufferHeight * mRfb->si.framebufferWidth * 4,
directbuffer,
width * height * mBpp,
width * height * colours,
AV_PIX_FMT_RGBA,
mImgPixFmt,
mRfb->si.framebufferWidth,
@ -201,10 +209,10 @@ int VncCamera::Capture(ZMPacket &zm_packet) {
}
int VncCamera::PostCapture() {
return 0;
return 1;
}
int VncCamera::Close() {
return 0;
return 1;
}
#endif

View File

@ -8,6 +8,13 @@
#if HAVE_LIBVNC
#include <rfb/rfbclient.h>
// Older versions of libvncserver defined a max macro in rfb/rfbproto.h
// Undef it here so it doesn't collide with std::max
// TODO: Remove this once xenial support is dropped
#ifdef max
#undef max
#endif
// Used by vnc callbacks
struct VncPrivateData {
uint8_t *buffer;
@ -19,7 +26,7 @@ class VncCamera : public Camera {
protected:
rfbClient *mRfb;
VncPrivateData mVncData;
int mBpp;
int mBufferSize;
SWScale scale;
AVPixelFormat mImgPixFmt;
std::string mHost;

View File

@ -946,12 +946,12 @@ void LocalCamera::Initialise() {
}
if ( (input.std != V4L2_STD_UNKNOWN) && ((input.std & standard) == V4L2_STD_UNKNOWN) ) {
Fatal("Device does not support video standard %d", standard);
Error("Device does not support video standard %d", standard);
}
stdId = standard;
if ( (input.std != V4L2_STD_UNKNOWN) && (vidioctl(vid_fd, VIDIOC_S_STD, &stdId) < 0) ) {
Fatal("Failed to set video standard %d: %d %s", standard, errno, strerror(errno));
if ((vidioctl(vid_fd, VIDIOC_S_STD, &stdId) < 0)) {
Error("Failed to set video standard %d: %d %s", standard, errno, strerror(errno));
}
Contrast(contrast);
@ -2201,7 +2201,6 @@ int LocalCamera::PostCapture() {
v4l2_std_id stdId = standards[next_channel];
if ( vidioctl(vid_fd, VIDIOC_S_STD, &stdId) < 0 ) {
Error("Failed to set video format %d: %s", standards[next_channel], strerror(errno));
return -1;
}
}
if ( v4l2_data.bufptr ) {

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,7 @@
#define ZM_MONITOR_H
#include "zm_define.h"
#include "zm_camera.h"
#include "zm_event.h"
#include "zm_image.h"
#include "zm_packet.h"
@ -30,7 +31,6 @@
#include <sys/time.h>
#include <vector>
class Camera;
class Group;
#define SIGNAL_CAUSE "Signal"
@ -105,8 +105,8 @@ protected:
/* sizeof(SharedData) expected to be 344 bytes on 32bit and 64bit */
typedef struct {
uint32_t size; /* +0 */
uint32_t last_write_index; /* +4 */
uint32_t last_read_index; /* +8 */
int32_t last_write_index; /* +4 */
int32_t last_read_index; /* +8 */
uint32_t state; /* +12 */
double capture_fps; // Current capturing fps
double analysis_fps; // Current analysis fps
@ -286,7 +286,7 @@ protected:
char label_format[64]; // The format of the timestamp on the images
Coord label_coord; // The coordinates of the timestamp on the images
int label_size; // Size of the timestamp on the images
int image_buffer_count; // Size of circular image buffer, at least twice the size of the pre_event_count
int32_t image_buffer_count; // Size of circular image buffer, at least twice the size of the pre_event_count
int pre_event_buffer_count; // Size of dedicated circular pre event buffer used when analysis is not performed at capturing framerate,
// value is pre_event_count + alarm_frame_count - 1
int warmup_count; // How many images to process before looking for events
@ -358,14 +358,15 @@ protected:
int video_stream_id; // will be filled in PrimeCapture
int audio_stream_id; // will be filled in PrimeCapture
Camera *camera;
std::unique_ptr<Camera> camera;
Event *event;
std::mutex event_mutex;
Storage *storage;
VideoStore *videoStore;
PacketQueue packetqueue;
packetqueue_iterator *analysis_it;
Mutex mutex;
int n_zones;
Zone **zones;
@ -393,13 +394,14 @@ public:
void AddZones( int p_n_zones, Zone *p_zones[] );
void AddPrivacyBitmask( Zone *p_zones[] );
void LoadCamera();
bool connect();
bool disconnect();
inline int ShmValid() const {
return shared_data && shared_data->valid;
}
Camera *getCamera();
inline unsigned int Id() const { return id; }
inline const char *Name() const { return name; }
@ -468,10 +470,15 @@ public:
void SetVideoWriterStartTime(const struct timeval &t) { video_store_data->recording = t; }
unsigned int GetPreEventCount() const { return pre_event_count; };
int GetImageBufferCount() const { return image_buffer_count; };
int32_t GetImageBufferCount() const { return image_buffer_count; };
State GetState() const { return (State)shared_data->state; }
int GetImage( int index=-1, int scale=100 );
AVStream *GetAudioStream() const { return camera ? camera->get_AudioStream() : nullptr; };
AVCodecContext *GetAudioCodecContext() const { return camera ? camera->get_AudioCodecContext() : nullptr; };
AVStream *GetVideoStream() const { return camera ? camera->get_VideoStream() : nullptr; };
AVCodecContext *GetVideoCodecContext() const { return camera ? camera->get_VideoCodecContext() : nullptr; };
int GetImage(int32_t index=-1, int scale=100);
ZMPacket *getSnapshot( int index=-1 ) const;
struct timeval GetTimestamp( int index=-1 ) const;
void UpdateAdaptiveSkip();

View File

@ -487,7 +487,7 @@ void MonitorStream::runStream() {
updateFrameRate(monitor->GetFPS());
// point to end which is theoretically not a valid value because all indexes are % image_buffer_count
unsigned int last_read_index = monitor->image_buffer_count;
int32_t last_read_index = monitor->image_buffer_count;
time_t stream_start_time;
time(&stream_start_time);
@ -850,7 +850,13 @@ void MonitorStream::SingleImage(int scale) {
int img_buffer_size = 0;
static JOCTET img_buffer[ZM_MAX_IMAGE_SIZE];
Image scaled_image;
ZMPacket *snap = &(monitor->image_buffer[monitor->shared_data->last_write_index]);
while ( monitor->shared_data->last_write_index >= monitor->image_buffer_count ) {
Debug(1, "Waiting for capture to begin");
usleep(100000);
}
int index = monitor->shared_data->last_write_index % monitor->image_buffer_count;
Debug(1, "write index: %d %d", monitor->shared_data->last_write_index, index);
ZMPacket *snap = &(monitor->image_buffer[index]);
Image *snap_image = snap->image;
if ( scale != ZM_SCALE_BASE ) {

View File

@ -72,6 +72,14 @@ PacketQueue::~PacketQueue() {
bool PacketQueue::queuePacket(ZMPacket* add_packet) {
Debug(4, "packetqueue queuepacket %p %d", add_packet, add_packet->image_index);
if (iterators.empty()) {
Debug(4, "No iterators so no one needs us to queue packets.");
return false;
}
if (!packet_counts[video_stream_id] and !add_packet->keyframe) {
Debug(4, "No video keyframe so no one needs us to queue packets.");
return false;
}
mutex.lock();
pktQueue.push_back(add_packet);
@ -412,6 +420,10 @@ unsigned int PacketQueue::size() {
}
int PacketQueue::packet_count(int stream_id) {
if ( stream_id < 0 or stream_id > max_stream_id ) {
Error("Invalid stream_id %d", stream_id);
return -1;
}
return packet_counts[stream_id];
} // end int PacketQueue::packet_count(int stream_id)
@ -623,3 +635,10 @@ bool PacketQueue::is_there_an_iterator_pointing_to_packet(ZMPacket *zm_packet) {
} // end foreach iterator
return false;
}
void PacketQueue::setMaxVideoPackets(int p) {
max_video_packet_count = p;
Debug(1, "Setting max_video_packet_count to %d", p);
if ( max_video_packet_count < 1 )
max_video_packet_count = 1 ;
// We can simplify a lot of logic in queuePacket if we can assume at least 1 packet in queue
}

View File

@ -49,12 +49,7 @@ class PacketQueue {
std::list<ZMPacket *>::const_iterator begin() const { return pktQueue.begin(); }
void addStreamId(int p_stream_id);
void setMaxVideoPackets(int p) {
max_video_packet_count = p;
if ( max_video_packet_count < 1 )
max_video_packet_count = 1 ;
// We can simplify a lot of logic in queuePacket if we can assume at least 1 packet in queue
}
void setMaxVideoPackets(int p);
bool queuePacket(ZMPacket* packet);
ZMPacket * popPacket();

View File

@ -19,6 +19,7 @@
#include "zm_remote_camera_http.h"
#include "zm_monitor.h"
#include "zm_packet.h"
#include "zm_signal.h"
#include "zm_regexp.h"

View File

@ -19,6 +19,7 @@
#include "zm_remote_camera_nvsocket.h"
#include "zm_monitor.h"
#include "zm_packet.h"
#include <netdb.h>
#include <sys/socket.h>

View File

@ -20,6 +20,7 @@
#include "zm_remote_camera_rtsp.h"
#include "zm_config.h"
#include "zm_monitor.h"
#include "zm_packet.h"
#if HAVE_LIBAVFORMAT

View File

@ -191,21 +191,11 @@ int SWScale::Convert(
#endif
/* Check the buffer sizes */
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
size_t insize = av_image_get_buffer_size(in_pf, width, height, 32);
#else
size_t insize = avpicture_get_size(in_pf, width, height);
#endif
size_t insize = GetBufferSize(in_pf, width, height);
if ( insize != in_buffer_size ) {
Error("The input buffer size does not match the expected size for the input format. Required: %d Available: %d", insize, in_buffer_size);
return -4;
Debug(1, "The input buffer size does not match the expected size for the input format. Required: %d Available: %d", insize, in_buffer_size);
}
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
size_t outsize = av_image_get_buffer_size(out_pf, new_width, new_height, 32);
#else
size_t outsize = avpicture_get_size(out_pf, new_width, new_height);
#endif
size_t outsize = GetBufferSize(out_pf, new_width, new_height);
if ( outsize < out_buffer_size ) {
Error("The output buffer is undersized for the output format. Required: %d Available: %d", outsize, out_buffer_size);
return -5;
@ -305,4 +295,12 @@ int SWScale::ConvertDefaults(const uint8_t* in_buffer, const size_t in_buffer_si
return Convert(in_buffer,in_buffer_size,out_buffer,out_buffer_size,default_input_pf,default_output_pf,default_width,default_height);
}
size_t SWScale::GetBufferSize(enum _AVPIXELFORMAT pf, unsigned int width, unsigned int height) {
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
return av_image_get_buffer_size(pf, width, height, 32);
#else
return outsize = avpicture_get_size(pf, width,height);
#endif
}
#endif // HAVE_LIBSWSCALE && HAVE_LIBAVUTIL

View File

@ -20,6 +20,7 @@ class SWScale {
int Convert(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height);
int Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height);
int Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height, unsigned int new_width, unsigned int new_height);
static size_t GetBufferSize(enum _AVPIXELFORMAT in_pf, unsigned int width, unsigned int height);
protected:
bool gotdefaults;

View File

@ -22,6 +22,8 @@
#include "zm_config.h"
#include "zm_logger.h"
#include <algorithm>
#include <cstdarg>
#include <cstring>
#include <fcntl.h> /* Definition of AT_* constants */
#include <sstream>
#include <sys/stat.h>

View File

@ -138,7 +138,7 @@ bool VideoStore::open() {
Error("Could not initialize ctx parameters");
return false;
}
fix_deprecated_pix_fmt(video_out_ctx);
video_out_ctx->pix_fmt = fix_deprecated_pix_fmt(video_out_ctx->pix_fmt);
if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) {
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
video_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
@ -164,7 +164,7 @@ bool VideoStore::open() {
std::string wanted_encoder = monitor->Encoder();
for ( unsigned int i = 0; i < sizeof(codec_data) / sizeof(*codec_data); i++ ) {
if ( wanted_encoder != "" ) {
if ( wanted_encoder != "" and wanted_encoder != "auto" ) {
if ( wanted_encoder != codec_data[i].codec_name ) {
Debug(1, "Not the right codec name %s != %s", codec_data[i].codec_name, wanted_encoder.c_str());
continue;
@ -210,10 +210,12 @@ bool VideoStore::open() {
video_out_ctx->gop_size = 12;
video_out_ctx->max_b_frames = 1;
ret = av_opt_set(video_out_ctx->priv_data, "crf", "36", AV_OPT_SEARCH_CHILDREN);
ret = av_opt_set(video_out_ctx, "crf", "36", AV_OPT_SEARCH_CHILDREN);
if ( ret < 0 ) {
Error("Could not set 'crf' for output codec %s.",
codec_data[i].codec_name);
Error("Could not set 'crf' for output codec %s. %s",
codec_data[i].codec_name,
av_make_error_string(ret).c_str()
);
}
} else if ( video_out_ctx->codec_id == AV_CODEC_ID_MPEG2VIDEO ) {
/* just for testing, we also add B frames */
@ -260,7 +262,7 @@ bool VideoStore::open() {
// We allocate and copy in newer ffmpeg, so need to free it
avcodec_free_context(&video_out_ctx);
#endif
video_out_ctx = nullptr;
//video_out_ctx = nullptr;
return false;
} // end if can't open codec

View File

@ -1,194 +0,0 @@
//
// ZoneMinder Analysis Daemon, $Date$, $Revision$
// Copyright (C) 2001-2008 Philip Coombes
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
/*
=head1 NAME
zma - The ZoneMinder Analysis daemon
=head1 SYNOPSIS
zma -m <monitor_id>
zma --monitor <monitor_id>
zma -h
zma --help
zma -v
zma --version
=head1 DESCRIPTION
This is the component that goes through the captured frames and checks them
for motion which might generate an alarm or event. It generally keeps up with
the Capture daemon but if very busy may skip some frames to prevent it falling
behind.
=head1 OPTIONS
-m, --monitor_id - ID of the monitor to analyse
-h, --help - Display usage information
-v, --version - Print the installed version of ZoneMinder
=cut
*/
#include <getopt.h>
#include <signal.h>
#include "zm.h"
#include "zm_db.h"
#include "zm_signal.h"
#include "zm_monitor.h"
#include "zm_fifo.h"
void Usage() {
fprintf(stderr, "zma -m <monitor_id>\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, " -m, --monitor <monitor_id> : Specify which monitor to use\n");
fprintf(stderr, " -h, --help : This screen\n");
fprintf(stderr, " -v, --version : Report the installed version of ZoneMinder\n");
exit(0);
}
int main( int argc, char *argv[] ) {
self = argv[0];
srand(getpid() * time(nullptr));
int id = -1;
static struct option long_options[] = {
{"monitor", 1, nullptr, 'm'},
{"help", 0, nullptr, 'h'},
{"version", 0, nullptr, 'v'},
{nullptr, 0, nullptr, 0}
};
while (1) {
int option_index = 0;
int c = getopt_long(argc, argv, "m:h:v", long_options, &option_index);
if ( c == -1 ) {
break;
}
switch (c) {
case 'm':
id = atoi(optarg);
break;
case 'h':
case '?':
Usage();
break;
case 'v':
std::cout << ZM_VERSION << "\n";
exit(0);
default:
//fprintf( stderr, "?? getopt returned character code 0%o ??\n", c );
break;
}
}
if ( optind < argc ) {
fprintf(stderr, "Extraneous options, ");
while ( optind < argc )
printf("%s ", argv[optind++]);
printf("\n");
Usage();
}
if ( id < 0 ) {
fprintf(stderr, "Bogus monitor %d\n", id);
Usage();
exit(0);
}
char log_id_string[16];
snprintf(log_id_string, sizeof(log_id_string), "zma_m%d", id);
zmLoadConfig();
logInit(log_id_string);
hwcaps_detect();
Monitor *monitor = Monitor::Load(id, true, Monitor::ANALYSIS);
zmFifoDbgInit(monitor);
if ( monitor ) {
Info("In mode %d/%d, warming up", monitor->GetFunction(), monitor->Enabled());
zmSetDefaultHupHandler();
zmSetDefaultTermHandler();
zmSetDefaultDieHandler();
sigset_t block_set;
sigemptyset(&block_set);
useconds_t analysis_rate = monitor->GetAnalysisRate();
unsigned int analysis_update_delay = monitor->GetAnalysisUpdateDelay();
time_t last_analysis_update_time, cur_time;
monitor->UpdateAdaptiveSkip();
last_analysis_update_time = time(nullptr);
while ( !zm_terminate ) {
if ( !monitor->ShmValid() ) {
monitor->disconnect();
Info("Waiting for shm to become valid");
usleep(100000);
monitor->connect();
continue;
}
// Process the next image
sigprocmask(SIG_BLOCK, &block_set, nullptr);
// Some periodic updates are required for variable capturing framerate
if ( analysis_update_delay ) {
cur_time = time(nullptr);
if ( (unsigned int)( cur_time - last_analysis_update_time ) > analysis_update_delay ) {
analysis_rate = monitor->GetAnalysisRate();
monitor->UpdateAdaptiveSkip();
last_analysis_update_time = cur_time;
}
}
if ( !monitor->Analyse() ) {
usleep(monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE);
} else if ( analysis_rate ) {
usleep(analysis_rate);
}
if ( zm_reload ) {
monitor->Reload();
logTerm();
logInit(log_id_string);
zm_reload = false;
}
sigprocmask(SIG_UNBLOCK, &block_set, nullptr);
} // end while ! zm_terminate
delete monitor;
} else {
fprintf(stderr, "Can't find monitor with id of %d\n", id);
}
Image::Deinitialise();
logTerm();
zmDbClose();
return 0;
}

View File

@ -238,8 +238,8 @@ int main(int argc, char *argv[]) {
static char sql[ZM_SQL_SML_BUFSIZ];
for (const std::shared_ptr<Monitor> &monitor : monitors) {
if (!monitor->getCamera()) {
}
monitor->LoadCamera();
if (!monitor->connect()) {
Warning("Couldn't connect to monitor %d", monitor->Id());
}
@ -310,8 +310,7 @@ int main(int argc, char *argv[]) {
#if HAVE_RTSP_SERVER
if ( rtsp_server_threads ) {
rtsp_server_threads[i] = new RTSPServerThread(monitors[i]);
Camera *camera = monitors[i]->getCamera();
rtsp_server_threads[i]->addStream(camera->get_VideoStream(), camera->get_AudioStream());
rtsp_server_threads[i]->addStream(monitors[i]->GetVideoStream(), monitors[i]->GetAudioStream());
rtsp_server_threads[i]->start();
}
#endif
@ -376,17 +375,12 @@ int main(int argc, char *argv[]) {
}
if ( zm_reload ) {
for (std::shared_ptr<Monitor> &monitor : monitors) {
monitor->Reload();
}
logTerm();
logInit(log_id_string);
zm_reload = false;
} // end if zm_reload
break;
}
} // end while ! zm_terminate and connected
// Killoff the analysis threads. Don't need them spinning while we try to reconnect
analysis_threads.clear();
for (std::unique_ptr<AnalysisThread> &analysis_thread: analysis_threads)
analysis_thread->Stop();
for (size_t i = 0; i < monitors.size(); i++) {
#if HAVE_RTSP_SERVER
@ -399,16 +393,16 @@ int main(int argc, char *argv[]) {
#if HAVE_RTSP_SERVER
if (rtsp_server_threads) {
rtsp_server_threads[i]->join();;
rtsp_server_threads[i]->join();
delete rtsp_server_threads[i];
rtsp_server_threads[i] = nullptr;
}
#endif
Camera *camera = monitors[i]->getCamera();
Debug(1, "Closing camera");
camera->Close();
}
// Killoff the analysis threads. Don't need them spinning while we try to reconnect
analysis_threads.clear();
#if HAVE_RTSP_SERVER
if (rtsp_server_threads) {
delete[] rtsp_server_threads;
@ -424,6 +418,14 @@ int main(int argc, char *argv[]) {
Debug(1, "Sleeping for 5");
sleep(5);
}
if (zm_reload) {
for (std::shared_ptr<Monitor> &monitor : monitors) {
monitor->Reload();
}
logTerm();
logInit(log_id_string);
zm_reload = false;
} // end if zm_reload
} // end while ! zm_terminate outer connection loop
Debug(1,"Updating Monitor status");
@ -436,7 +438,6 @@ int main(int argc, char *argv[]) {
if (mysql_query(&dbconn, sql)) {
Error("Can't run query: %s", mysql_error(&dbconn));
}
monitor->disconnect();
}
Image::Deinitialise();

View File

@ -80,7 +80,7 @@ fi;
if [ "$DISTROS" == "" ]; then
if [ "$RELEASE" != "" ]; then
DISTROS="xenial,bionic,focal"
DISTROS="xenial,bionic,focal,groovy,hirsute"
else
DISTROS=`lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'`;
fi;

View File

@ -354,7 +354,7 @@ class Filter extends ZM_Object {
for ( $i = 0; $i < count($terms); $i++ ) {
$term = $terms[$i];
if ( !empty($term['cnj']) ) {
while( true ) {
while ( true ) {
if ( !count($postfixStack) ) {
$postfixStack[] = array('type'=>'cnj', 'value'=>$term['cnj'], 'sqlValue'=>$term['cnj']);
break;
@ -518,7 +518,7 @@ class Filter extends ZM_Object {
ZM\Error('Unknown operator in filter '.$term['op']);
}
while( true ) {
while ( true ) {
if ( !count($postfixStack) ) {
$postfixStack[] = array('type'=>'op', 'value'=>$term['op'], 'sqlValue'=>$sqlValue);
break;
@ -579,11 +579,6 @@ class Filter extends ZM_Object {
case 'StartTime':
$value = 'extract(hour_second from \''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')';
break;
case 'Weekday':
case 'EndWeekday':
case 'StartWeekday':
$value = 'weekday(\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')';
break;
default :
if ( $value != 'NULL' )
$value = dbEscape($value);

View File

@ -62,7 +62,8 @@ if ( $action == 'save' ) {
'RecordAudio' => 0,
'Method' => 'raw',
'GroupIds' => array(),
'LinkedMonitors' => array()
'LinkedMonitors' => array(),
'RTSPServer' => 0
);
# Checkboxes don't return an element in the POST data, so won't be present in newMonitor.

View File

@ -33,15 +33,11 @@ if ( $action == 'save' ) {
}
$Monitor = new ZM\Monitor($mid);
if ( $Monitor->Type() != 'WebSite' ) {
$Monitor->zmaControl('stop');
$Monitor->zmcControl('stop');
}
$Monitor->save($_REQUEST['newMonitor']);
if ( $Monitor->Function() != 'None' && $Monitor->Type() != 'WebSite' ) {
$Monitor->zmcControl('start');
if ( $Monitor->Enabled() ) {
$Monitor->zmaControl('start');
}
}
} // end foreach mid
$view = 'console';

View File

@ -56,9 +56,9 @@ if ( $action == 'delete' ) {
}
$changed = false;
while( $config = dbFetchNext($result) ) {
while ($config = dbFetchNext($result)) {
unset($newValue);
if ( $config['Type'] == 'boolean' && empty($_REQUEST['newConfig'][$config['Name']]) ) {
if ( ($config['Type'] == 'boolean') and empty($_REQUEST['newConfig'][$config['Name']]) ) {
$newValue = 0;
} else if ( isset($_REQUEST['newConfig'][$config['Name']]) ) {
$newValue = preg_replace("/\r\n/", "\n", stripslashes($_REQUEST['newConfig'][$config['Name']]));
@ -98,5 +98,4 @@ if ( $action == 'delete' ) {
}
return;
} // end if object vs action
?>

View File

@ -30,6 +30,14 @@
margin: 2px;
text-align: center;
}
#definitionPanel:after {
content: ".";
display: block;
height: 0;
font-size: 0;
clear: both;
visibility: hidden;
}
#definitionPanel input[type=submit],
#definitionPanel input[type=submit] {

View File

@ -613,7 +613,7 @@ function getEventResponse(respObj, respText) {
} else {
drawProgressBar();
}
nearEventsQuery( eventData.Id );
nearEventsQuery(eventData.Id);
} // end function getEventResponse
function eventQuery(eventId) {
@ -626,10 +626,11 @@ function eventQuery(eventId) {
.fail(logAjaxFail);
}
function getNearEventsResponse( respObj, respText ) {
function getNearEventsResponse(respObj, respText) {
if ( checkStreamForErrors('getNearEventsResponse', respObj) ) {
return;
}
console.log(respObj);
prevEventId = respObj.nearevents.PrevEventId;
nextEventId = respObj.nearevents.NextEventId;
prevEventStartTime = Date.parse(respObj.nearevents.PrevEventStartTime);
@ -641,7 +642,7 @@ function getNearEventsResponse( respObj, respText ) {
$j('#nextBtn').prop('disabled', nextEventId == 0 ? true : false).attr('class', nextEventId == 0 ? 'unavail' : 'inactive');
}
function nearEventsQuery( eventId ) {
function nearEventsQuery(eventId) {
$j.getJSON(thisUrl + '?view=request&request=status&entity=nearevents&id='+eventId+filterQuery+sortQuery)
.done(getNearEventsResponse)
.fail(logAjaxFail);
@ -839,7 +840,8 @@ function getStat() {
});
}
function onStatsResize(vidwidth) {
function onStatsResize(vidWidth) {
if (!vidWidth) return;
var minWidth = 300; // An arbitrary value in pixels used to hide the stats table
var scale = $j('#scale').val();
@ -847,8 +849,8 @@ function onStatsResize(vidwidth) {
vidWidth = vidWidth * (scale/100);
}
var width = $j(window).width() - vidwidth;
//console.log("Width: " + width + " = window.width " + $j(window).width() + "- vidWidth" + vidwidth);
var width = $j(window).width() - vidWidth;
//console.log("Width: " + width + " = window.width " + $j(window).width() + "- vidWidth" + vidWidth);
// Hide the stats table if we have run out of room to show it properly
if ( width < minWidth ) {

View File

@ -4,6 +4,9 @@ xhtmlHeaders(__FILE__, translate('Login'));
<body>
<?php echo getNavBarHTML(); ?>
<div class="container">
<?php
if ( defined('ZM_OPT_USE_AUTH') and ZM_OPT_USE_AUTH ) {
?>
<form class="center-block" name="loginForm" id="loginForm" method="post" action="?">
<input type="hidden" name="action" value="login"/>
<input type="hidden" name="view" value="login"/>
@ -34,6 +37,15 @@ if (
} ?>
<button class="btn btn-lg btn-primary btn-block" type="submit"><?php echo translate('Login') ?></button>
</div>
<?php
} else {
?>
<div class="error">
User Authentication is not turned on. You cannot log in.
</div>
<?php
} # end if ZM_OPT_AUTH
?>
</form>
</div>
<?php xhtmlFooter() ?>

View File

@ -43,20 +43,21 @@ if ( !empty($_REQUEST['mid']) ) {
if ( !$monitor ) {
$nextId = getTableAutoInc('Monitors');
if ( isset($_REQUEST['dupId']) ) {
$monitor = new ZM\Monitor($_REQUEST['dupId']);
$monitor->GroupIds(); // have to load before we change the Id
if ( ZM_OPT_X10 )
$x10Monitor = dbFetchOne('SELECT * FROM TriggersX10 WHERE MonitorId = ?', NULL, array($_REQUEST['dupId']));
$clonedName = $monitor->Name();
$monitor->Id(0);
} else {
$monitor = new ZM\Monitor();
} # end if $_REQUEST['dupID']
$monitor = new ZM\Monitor();
$monitor->Name(translate('Monitor').'-'.$nextId);
$monitor->WebColour(random_colour());
} # end if $_REQUEST['mid']
if ( isset($_REQUEST['dupId']) ) {
$monitor = new ZM\Monitor($_REQUEST['dupId']);
$monitor->GroupIds(); // have to load before we change the Id
if ( ZM_OPT_X10 )
$x10Monitor = dbFetchOne('SELECT * FROM TriggersX10 WHERE MonitorId = ?', NULL, array($_REQUEST['dupId']));
$clonedName = $monitor->Name();
$monitor->Name('Clone of '.$monitor->Name());
$monitor->Id(!empty($_REQUEST['mid'])?validInt($_REQUEST['mid']) : 0);
}
if ( ZM_OPT_X10 && empty($x10Monitor) ) {
$x10Monitor = array(
'Activation' => '',
@ -550,7 +551,7 @@ switch ( $name ) {
<td class="text-right pr-3"><?php echo translate('LinkedMonitors'); echo makeHelpLink('OPTIONS_LINKED_MONITORS') ?></td>
<td>
<?php
$monitors = dbFetchAll('SELECT Id, Name FROM Monitors ORDER BY Sequence ASC');
$monitors = dbFetchAll('SELECT Id, Name FROM Monitors ORDER BY Name,Sequence ASC');
$monitor_options = array();
foreach ( $monitors as $linked_monitor ) {
if ( (!$monitor->Id() || ($monitor->Id()!= $linked_monitor['Id'])) && visibleMonitor($linked_monitor['Id']) ) {

View File

@ -145,7 +145,6 @@ $tree = false;
if ( isset($_REQUEST['filter']) ) {
$filter = ZM\Filter::parse($_REQUEST['filter']);
$tree = $filter->tree();
ZM\Debug('Parse tree: ' . print_r($tree,true));
}
if ( isset($_REQUEST['range']) )
@ -196,9 +195,8 @@ if ( isset($minTime) && isset($maxTime) ) {
$filterSql = parseTreeToSQL($tree);
if ( $filterSql ) {
$filterSql = " AND $filterSql";
$eventsSql .= $filterSql;
$eventIdsSql .= $filterSql;
$eventsSql .= ' AND '.$filterSql;
$eventIdsSql .= ' AND '.$filterSql;
}
} else {
$filterSql = parseTreeToSQL($tree);
@ -206,10 +204,9 @@ if ( isset($minTime) && isset($maxTime) ) {
extractDatetimeRange($tree, $tempMinTime, $tempMaxTime, $tempExpandable);
if ( $filterSql ) {
$filterSql = " AND $filterSql";
$rangeSql .= $filterSql;
$eventsSql .= $filterSql;
$eventIdsSql .= $filterSql;
$rangeSql .= ' AND '.$filterSql;
$eventsSql .= ' AND '.$filterSql;
$eventIdsSql .= ' AND '.$filterSql;
}
if ( !isset($minTime) || !isset($maxTime) ) {
@ -220,8 +217,6 @@ if ( isset($minTime) && isset($maxTime) ) {
$minTime = $row['MinTime'];
if ( !isset($maxTime) )
$maxTime = $row['MaxTime'];
} else {
# Errors will be reported by db functions
}
}
@ -237,10 +232,9 @@ if ( isset($minTime) && isset($maxTime) ) {
$range = ($maxTimeT - $minTimeT) + 1;
$halfRange = (int)($range/2);
$midTimeT = $minTimeT + $halfRange;
$midTime = strftime( STRF_FMT_DATETIME_DB, $midTimeT );
$midTime = strftime(STRF_FMT_DATETIME_DB, $midTimeT);
}
//echo "MnT: $tempMinTime, MxT: $tempMaxTime, ExP: $tempExpandable<br>";
if ( $tree ) {
appendDatetimeRange($tree, $minTime, $maxTime);