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

This commit is contained in:
Isaac Connor 2021-12-03 15:13:13 -05:00
commit 1fc0e93673
8 changed files with 201 additions and 144 deletions

100
cmake/Modules/FindFmt.cmake Normal file
View File

@ -0,0 +1,100 @@
# FindFmt
# -------
# Finds the Fmt library
#
# This will define the following variables::
#
# FMT_FOUND - system has Fmt
# FMT_INCLUDE_DIRS - the Fmt include directory
# FMT_LIBRARIES - the Fmt libraries
#
# and the following imported targets::
#
# Fmt::Fmt - The Fmt library
if(ENABLE_INTERNAL_FMT)
include(ExternalProject)
file(STRINGS ${CMAKE_SOURCE_DIR}/tools/depends/target/libfmt/Makefile VER REGEX "^[ ]*VERSION[ ]*=.+$")
string(REGEX REPLACE "^[ ]*VERSION[ ]*=[ ]*" "" FMT_VERSION "${VER}")
# allow user to override the download URL with a local tarball
# needed for offline build envs
if(FMT_URL)
get_filename_component(FMT_URL "${FMT_URL}" ABSOLUTE)
else()
set(FMT_URL http://mirrors.kodi.tv/build-deps/sources/fmt-${FMT_VERSION}.tar.gz)
endif()
if(VERBOSE)
message(STATUS "FMT_URL: ${FMT_URL}")
endif()
if(APPLE)
set(EXTRA_ARGS "-DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}")
endif()
set(FMT_LIBRARY ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/lib/libfmt.a)
set(FMT_INCLUDE_DIR ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/include)
externalproject_add(fmt
URL ${FMT_URL}
DOWNLOAD_DIR ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/download
PREFIX ${CORE_BUILD_DIR}/fmt
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}
-DCMAKE_CXX_EXTENSIONS=${CMAKE_CXX_EXTENSIONS}
-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
-DCMAKE_INSTALL_LIBDIR=lib
-DFMT_DOC=OFF
-DFMT_TEST=OFF
"${EXTRA_ARGS}"
BUILD_BYPRODUCTS ${FMT_LIBRARY})
set_target_properties(fmt PROPERTIES FOLDER "External Projects")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Fmt
REQUIRED_VARS FMT_LIBRARY FMT_INCLUDE_DIR
VERSION_VAR FMT_VERSION)
set(FMT_LIBRARIES ${FMT_LIBRARY})
set(FMT_INCLUDE_DIRS ${FMT_INCLUDE_DIR})
else()
find_package(FMT 6.1.2 CONFIG REQUIRED QUIET)
if(PKG_CONFIG_FOUND)
pkg_check_modules(PC_FMT libfmt QUIET)
if(PC_FMT_VERSION AND NOT FMT_VERSION)
set(FMT_VERSION ${PC_FMT_VERSION})
endif()
endif()
find_path(FMT_INCLUDE_DIR NAMES fmt/format.h
PATHS ${PC_FMT_INCLUDEDIR})
find_library(FMT_LIBRARY_RELEASE NAMES fmt
PATHS ${PC_FMT_LIBDIR})
find_library(FMT_LIBRARY_DEBUG NAMES fmtd
PATHS ${PC_FMT_LIBDIR})
include(SelectLibraryConfigurations)
select_library_configurations(FMT)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Fmt
REQUIRED_VARS FMT_LIBRARY FMT_INCLUDE_DIR FMT_VERSION
VERSION_VAR FMT_VERSION)
if(FMT_FOUND)
set(FMT_LIBRARIES ${FMT_LIBRARY})
set(FMT_INCLUDE_DIRS ${FMT_INCLUDE_DIR})
if(NOT TARGET fmt)
add_library(fmt UNKNOWN IMPORTED)
set_target_properties(fmt PROPERTIES
IMPORTED_LOCATION "${FMT_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${FMT_INCLUDE_DIR}")
endif()
endif()
endif()
mark_as_advanced(FMT_INCLUDE_DIR FMT_LIBRARY)

View File

@ -43,6 +43,7 @@ require Date::Parse;
require POSIX; require POSIX;
use Date::Format qw(time2str); use Date::Format qw(time2str);
use Time::HiRes qw(gettimeofday tv_interval stat); use Time::HiRes qw(gettimeofday tv_interval stat);
use Scalar::Util qw(looks_like_number);
#our @ISA = qw(ZoneMinder::Object); #our @ISA = qw(ZoneMinder::Object);
use parent qw(ZoneMinder::Object); use parent qw(ZoneMinder::Object);
@ -601,7 +602,7 @@ sub CopyTo {
# First determine if we can move it to the dest. # First determine if we can move it to the dest.
# We do this before bothering to lock the event # We do this before bothering to lock the event
my ( $NewPath ) = ( $NewStorage->Path() =~ /^(.*)$/ ); # De-taint my ( $NewPath ) = ( $NewStorage->Path() =~ /^(.*)$/ ); # De-taint
if ( ! $$NewStorage{Id} ) { if ( ! looks_like_number($$NewStorage{Id}) ) {
return 'New storage does not have an id. Moving will not happen.'; return 'New storage does not have an id. Moving will not happen.';
} elsif ( $$NewStorage{Id} == $$self{StorageId} ) { } elsif ( $$NewStorage{Id} == $$self{StorageId} ) {
return 'Event is already located at ' . $NewPath; return 'Event is already located at ' . $NewPath;

View File

@ -546,7 +546,7 @@ void Event::AddFrame(Image *image,
or or
(frame_type == BULK) (frame_type == BULK)
or or
(fps and (frame_data.size() > fps))) { (fps and (frame_data.size() > 5*fps))) {
Debug(1, "Adding %zu frames to DB because write_to_db:%d or frames > analysis fps %f or BULK(%d)", Debug(1, "Adding %zu frames to DB because write_to_db:%d or frames > analysis fps %f or BULK(%d)",
frame_data.size(), write_to_db, fps, (frame_type == BULK)); frame_data.size(), write_to_db, fps, (frame_type == BULK));
WriteDbFrames(); WriteDbFrames();

View File

@ -1882,12 +1882,20 @@ bool Monitor::Analyse() {
// Get new score. // Get new score.
int motion_score = DetectMotion(*(snap->image), zoneSet); int motion_score = DetectMotion(*(snap->image), zoneSet);
// lets construct alarm cause. It will contain cause + names of zones alarmed
std::string alarm_cause;
snap->zone_stats.reserve(zones.size()); snap->zone_stats.reserve(zones.size());
for (const Zone &zone : zones) { for (const Zone &zone : zones) {
const ZoneStats &stats = zone.GetStats(); const ZoneStats &stats = zone.GetStats();
stats.DumpToLog("After detect motion"); stats.DumpToLog("After detect motion");
snap->zone_stats.push_back(stats); snap->zone_stats.push_back(stats);
if (zone.Alarmed()) {
if (!alarm_cause.empty()) alarm_cause += ",";
alarm_cause += std::string(zone.Label());
}
} }
if (!alarm_cause.empty())
cause = cause+" "+alarm_cause;
Debug(3, "After motion detection, score:%d last_motion_score(%d), new motion score(%d)", Debug(3, "After motion detection, score:%d last_motion_score(%d), new motion score(%d)",
score, last_motion_score, motion_score); score, last_motion_score, motion_score);
@ -1913,6 +1921,7 @@ bool Monitor::Analyse() {
); );
} // end if active and doing motion detection } // end if active and doing motion detection
if (function == RECORD or function == MOCORD) { if (function == RECORD or function == MOCORD) {
// If doing record, check to see if we need to close the event or not. // If doing record, check to see if we need to close the event or not.
if (event) { if (event) {
@ -1935,75 +1944,9 @@ bool Monitor::Analyse() {
} // end if event } // end if event
if (!event) { if (!event) {
Debug(2, "Creating continuous event"); event = openEvent(snap, cause.empty() ? "Continuous" : cause, noteSetMap);
if (!snap->keyframe and (videowriter == PASSTHROUGH)) {
// Must start on a keyframe so rewind. Only for passthrough though I guess.
// FIXME this iterator is not protected from invalidation
packetqueue_iterator *start_it = packetqueue.get_event_start_packet_it(
*analysis_it, 0 /* pre_event_count */
);
// This gets a lock on the starting packet Info("%s: %03d - Opened new event %" PRIu64 ", continuous section start",
ZMLockedPacket *starting_packet_lock = nullptr;
std::shared_ptr<ZMPacket> starting_packet = nullptr;
if (*start_it != *analysis_it) {
starting_packet_lock = packetqueue.get_packet(start_it);
if (!starting_packet_lock) {
Warning("Unable to get starting packet lock");
delete packet_lock;
return false;
}
starting_packet = starting_packet_lock->packet_;
} else {
starting_packet = snap;
}
event = new Event(this, starting_packet->timestamp, "Continuous", noteSetMap);
// Write out starting packets, do not modify packetqueue it will garbage collect itself
while (starting_packet and ((*start_it) != *analysis_it)) {
event->AddPacket(starting_packet);
// Have added the packet, don't want to unlock it until we have locked the next
packetqueue.increment_it(start_it);
if ((*start_it) == *analysis_it) {
if (starting_packet_lock) delete starting_packet_lock;
break;
}
ZMLockedPacket *lp = packetqueue.get_packet(start_it);
delete starting_packet_lock;
if (!lp) return false;
starting_packet_lock = lp;
starting_packet = lp->packet_;
}
packetqueue.free_it(start_it);
delete start_it;
start_it = nullptr;
} else {
// Create event from current snap
event = new Event(this, timestamp, "Continuous", noteSetMap);
}
shared_data->last_event_id = event->Id();
// lets construct alarm cause. It will contain cause + names of zones alarmed
std::string alarm_cause;
for (const Zone &zone : zones) {
if (zone.Alarmed()) {
if (!alarm_cause.empty()) alarm_cause += ",";
alarm_cause += std::string(zone.Label());
}
}
alarm_cause = cause+" Continuous "+alarm_cause;
strncpy(shared_data->alarm_cause, alarm_cause.c_str(), sizeof(shared_data->alarm_cause)-1);
SetVideoWriterStartTime(event->StartTime());
if (!event_start_command.empty()) {
if (fork() == 0) {
execlp(event_start_command.c_str(), event_start_command.c_str(), std::to_string(event->Id()).c_str(), nullptr);
Error("Error execing %s", event_start_command.c_str());
}
}
Info("%s: %03d - Opened new event %" PRIu64 ", section start",
name.c_str(), analysis_image_count, event->Id()); name.c_str(), analysis_image_count, event->Id());
/* To prevent cancelling out an existing alert\prealarm\alarm state */ /* To prevent cancelling out an existing alert\prealarm\alarm state */
if (state == IDLE) { if (state == IDLE) {
@ -2035,70 +1978,12 @@ bool Monitor::Analyse() {
(event_close_mode == CLOSE_ALARM)); (event_close_mode == CLOSE_ALARM));
} }
if ((!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count-1)) { if ((!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count-1)) {
// lets construct alarm cause. It will contain cause + names of zones alarmed
std::string alarm_cause = "";
for (const Zone &zone : zones) {
if (zone.Alarmed()) {
alarm_cause = alarm_cause + "," + std::string(zone.Label());
}
}
if (!alarm_cause.empty()) alarm_cause[0] = ' ';
alarm_cause = cause + alarm_cause;
strncpy(shared_data->alarm_cause, alarm_cause.c_str(), sizeof(shared_data->alarm_cause)-1);
Info("%s: %03d - Gone into alarm state PreAlarmCount: %u > AlarmFrameCount:%u Cause:%s", Info("%s: %03d - Gone into alarm state PreAlarmCount: %u > AlarmFrameCount:%u Cause:%s",
name.c_str(), image_count, Event::PreAlarmCount(), alarm_frame_count, shared_data->alarm_cause); name.c_str(), image_count, Event::PreAlarmCount(), alarm_frame_count, cause.c_str());
if (!event) { if (!event) {
packetqueue_iterator *start_it = packetqueue.get_event_start_packet_it( event = openEvent(snap, cause, noteSetMap);
*analysis_it,
(pre_event_count > alarm_frame_count ? pre_event_count : alarm_frame_count)
);
ZMLockedPacket *starting_packet_lock = nullptr;
std::shared_ptr<ZMPacket> starting_packet = nullptr;
if (*start_it != *analysis_it) {
starting_packet_lock = packetqueue.get_packet(start_it);
if (!starting_packet_lock) return false;
starting_packet = starting_packet_lock->packet_;
} else {
starting_packet = snap;
}
event = new Event(this, starting_packet->timestamp, cause, noteSetMap);
shared_data->last_event_id = event->Id();
snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile());
SetVideoWriterStartTime(event->StartTime());
shared_data->state = state = ALARM; shared_data->state = state = ALARM;
// Write out starting packets, do not modify packetqueue it will garbage collect itself
while (*start_it != *analysis_it) {
event->AddPacket(starting_packet);
packetqueue.increment_it(start_it);
if ( (*start_it) == (*analysis_it) ) {
if (starting_packet_lock) delete starting_packet_lock;
break;
}
ZMLockedPacket *lp = packetqueue.get_packet(start_it);
delete starting_packet_lock;
if (!lp) {
// Shutting down event will be closed by ~Monitor()
// Perhaps we shouldn't do this.
return false;
}
starting_packet_lock = lp;
starting_packet = lp->packet_;
}
packetqueue.free_it(start_it);
delete start_it;
start_it = nullptr;
if (!event_start_command.empty()) {
if (fork() == 0) {
execlp(event_start_command.c_str(), event_start_command.c_str(), std::to_string(event->Id()).c_str(), nullptr);
Error("Error execing %s", event_start_command.c_str());
}
}
Info("%s: %03d - Opening new event %" PRIu64 ", alarm start", name.c_str(), analysis_image_count, event->Id()); Info("%s: %03d - Opening new event %" PRIu64 ", alarm start", name.c_str(), analysis_image_count, event->Id());
} else { } else {
shared_data->state = state = ALARM; shared_data->state = state = ALARM;
@ -2208,11 +2093,7 @@ bool Monitor::Analyse() {
static_cast<int64>(std::chrono::duration_cast<Seconds>(timestamp - GetVideoWriterStartTime()).count()), static_cast<int64>(std::chrono::duration_cast<Seconds>(timestamp - GetVideoWriterStartTime()).count()),
static_cast<int64>(Seconds(section_length).count())); static_cast<int64>(Seconds(section_length).count()));
closeEvent(); closeEvent();
event = new Event(this, timestamp, cause, noteSetMap); event = openEvent(snap, cause, noteSetMap);
shared_data->last_event_id = event->Id();
//set up video store data
snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile());
SetVideoWriterStartTime(event->StartTime());
} }
} else { } else {
Error("ALARM but no event"); Error("ALARM but no event");
@ -2791,6 +2672,67 @@ void Monitor::TimestampImage(Image *ts_image, SystemTimePoint ts_time) const {
Debug(2, "done annotating %s", label_text); Debug(2, "done annotating %s", label_text);
} // end void Monitor::TimestampImage } // end void Monitor::TimestampImage
Event * Monitor::openEvent(
const std::shared_ptr<ZMPacket> &snap,
const std::string &cause,
const Event::StringSetMap noteSetMap) {
// FIXME this iterator is not protected from invalidation
packetqueue_iterator *start_it = packetqueue.get_event_start_packet_it(
*analysis_it,
(cause == "Continuous" ? 0 : (pre_event_count > alarm_frame_count ? pre_event_count : alarm_frame_count))
);
// This gets a lock on the starting packet
ZMLockedPacket *starting_packet_lock = nullptr;
std::shared_ptr<ZMPacket> starting_packet = nullptr;
if (*start_it != *analysis_it) {
starting_packet_lock = packetqueue.get_packet(start_it);
if (!starting_packet_lock) {
Warning("Unable to get starting packet lock");
return nullptr;
}
starting_packet = starting_packet_lock->packet_;
} else {
starting_packet = snap;
}
event = new Event(this, starting_packet->timestamp, cause, noteSetMap);
shared_data->last_event_id = event->Id();
strncpy(shared_data->alarm_cause, cause.c_str(), sizeof(shared_data->alarm_cause)-1);
if (!event_start_command.empty()) {
if (fork() == 0) {
execlp(event_start_command.c_str(), event_start_command.c_str(), std::to_string(event->Id()).c_str(), nullptr);
Error("Error execing %s", event_start_command.c_str());
}
}
// Write out starting packets, do not modify packetqueue it will garbage collect itself
while (starting_packet and ((*start_it) != *analysis_it)) {
event->AddPacket(starting_packet);
// Have added the packet, don't want to unlock it until we have locked the next
packetqueue.increment_it(start_it);
if ((*start_it) == *analysis_it) {
if (starting_packet_lock) delete starting_packet_lock;
break;
}
ZMLockedPacket *lp = packetqueue.get_packet(start_it);
delete starting_packet_lock;
if (!lp) return nullptr; // only on terminate FIXME
starting_packet_lock = lp;
starting_packet = lp->packet_;
}
packetqueue.free_it(start_it);
delete start_it;
start_it = nullptr;
return event;
}
void Monitor::closeEvent() { void Monitor::closeEvent() {
if (!event) return; if (!event) return;

View File

@ -593,6 +593,10 @@ public:
bool Decode(); bool Decode();
void DumpImage( Image *dump_image ) const; void DumpImage( Image *dump_image ) const;
void TimestampImage(Image *ts_image, SystemTimePoint ts_time) const; void TimestampImage(Image *ts_image, SystemTimePoint ts_time) const;
Event *openEvent(
const std::shared_ptr<ZMPacket> &snap,
const std::string &cause,
const Event::StringSetMap noteSetMap);
void closeEvent(); void closeEvent();
void Reload(); void Reload();

View File

@ -220,12 +220,13 @@ int main(int argc, char *argv[]) {
zmSetDefaultTermHandler(); zmSetDefaultTermHandler();
zmSetDefaultDieHandler(); zmSetDefaultDieHandler();
sigset_t block_set; struct sigaction sa;
sigemptyset(&block_set); sa.sa_handler = SIG_IGN; //handle signal by ignoring
sigemptyset(&sa.sa_mask);
sigaddset(&block_set, SIGHUP); sa.sa_flags = 0;
sigaddset(&block_set, SIGUSR1); if (sigaction(SIGCHLD, &sa, 0) == -1) {
sigaddset(&block_set, SIGUSR2); Error("Unable to set SIGCHLD to ignore. There may be zombies.");
}
int result = 0; int result = 0;
int prime_capture_log_count = 0; int prime_capture_log_count = 0;
@ -286,7 +287,6 @@ int main(int argc, char *argv[]) {
Microseconds sleep_time = Microseconds(0); Microseconds sleep_time = Microseconds(0);
while (!zm_terminate) { while (!zm_terminate) {
//sigprocmask(SIG_BLOCK, &block_set, 0);
for (size_t i = 0; i < monitors.size(); i++) { for (size_t i = 0; i < monitors.size(); i++) {
monitors[i]->CheckAction(); monitors[i]->CheckAction();

View File

@ -167,9 +167,15 @@ class Group extends ZM_Object {
public function Parents() { public function Parents() {
$Parents = array(); $Parents = array();
$Parent = $this->Parent(); $Parent = $this->Parent();
while( $Parent ) { $seen_parents = array();
while ($Parent) {
$seen_parents[$Parent->Id()] = $Parent;
array_unshift($Parents, $Parent); array_unshift($Parents, $Parent);
$Parent = $Parent->Parent(); $Parent = $Parent->Parent();
if ($Parent and isset($seen_parents[$Parent->Id()])) {
Warning("Detected hierarchy loop in group {$Parent->Name()}");
break;
}
} }
return $Parents; return $Parents;
} }
@ -189,6 +195,9 @@ class Group extends ZM_Object {
public function canView($u=null) { public function canView($u=null) {
global $user; global $user;
if (!$u) $u = $user; if (!$u) $u = $user;
if (!count($this->Monitors()) and !count($this->Children())) {
return true;
}
# Can view if we can view any of the monitors in it. # Can view if we can view any of the monitors in it.
foreach ($this->Monitors() as $monitor) { foreach ($this->Monitors() as $monitor) {
if ($monitor->canView($u)) return true; if ($monitor->canView($u)) return true;

View File

@ -37,7 +37,8 @@ ZM_WEB_GROUP=@WEB_GROUP@
ZM_DB_TYPE=@ZM_DB_TYPE@ ZM_DB_TYPE=@ZM_DB_TYPE@
# ZoneMinder database hostname or ip address and optionally port or unix socket # ZoneMinder database hostname or ip address and optionally port or unix socket
# Acceptable formats include hostname[:port], ip_address[:port], or localhost:unix_socket # Acceptable formats include hostname[:port], ip_address[:port], or
# localhost:/path/to/unix_socket
ZM_DB_HOST=@ZM_DB_HOST@ ZM_DB_HOST=@ZM_DB_HOST@
# ZoneMinder database name # ZoneMinder database name