Merge branch 'master' of github.com:ZoneMinder/zoneminder
This commit is contained in:
commit
1fc0e93673
|
@ -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)
|
|
@ -43,6 +43,7 @@ require Date::Parse;
|
|||
require POSIX;
|
||||
use Date::Format qw(time2str);
|
||||
use Time::HiRes qw(gettimeofday tv_interval stat);
|
||||
use Scalar::Util qw(looks_like_number);
|
||||
|
||||
#our @ISA = qw(ZoneMinder::Object);
|
||||
use parent qw(ZoneMinder::Object);
|
||||
|
@ -601,7 +602,7 @@ sub CopyTo {
|
|||
# First determine if we can move it to the dest.
|
||||
# We do this before bothering to lock the event
|
||||
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.';
|
||||
} elsif ( $$NewStorage{Id} == $$self{StorageId} ) {
|
||||
return 'Event is already located at ' . $NewPath;
|
||||
|
|
|
@ -546,7 +546,7 @@ void Event::AddFrame(Image *image,
|
|||
or
|
||||
(frame_type == BULK)
|
||||
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)",
|
||||
frame_data.size(), write_to_db, fps, (frame_type == BULK));
|
||||
WriteDbFrames();
|
||||
|
|
|
@ -1882,12 +1882,20 @@ bool Monitor::Analyse() {
|
|||
// Get new score.
|
||||
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());
|
||||
for (const Zone &zone : zones) {
|
||||
const ZoneStats &stats = zone.GetStats();
|
||||
stats.DumpToLog("After detect motion");
|
||||
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)",
|
||||
score, last_motion_score, motion_score);
|
||||
|
@ -1913,6 +1921,7 @@ bool Monitor::Analyse() {
|
|||
);
|
||||
} // end if active and doing motion detection
|
||||
|
||||
|
||||
if (function == RECORD or function == MOCORD) {
|
||||
// If doing record, check to see if we need to close the event or not.
|
||||
if (event) {
|
||||
|
@ -1935,75 +1944,9 @@ bool Monitor::Analyse() {
|
|||
} // end if event
|
||||
|
||||
if (!event) {
|
||||
Debug(2, "Creating continuous event");
|
||||
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 */
|
||||
);
|
||||
event = openEvent(snap, cause.empty() ? "Continuous" : cause, noteSetMap);
|
||||
|
||||
// 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");
|
||||
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",
|
||||
Info("%s: %03d - Opened new event %" PRIu64 ", continuous section start",
|
||||
name.c_str(), analysis_image_count, event->Id());
|
||||
/* To prevent cancelling out an existing alert\prealarm\alarm state */
|
||||
if (state == IDLE) {
|
||||
|
@ -2035,70 +1978,12 @@ bool Monitor::Analyse() {
|
|||
(event_close_mode == CLOSE_ALARM));
|
||||
}
|
||||
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",
|
||||
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) {
|
||||
packetqueue_iterator *start_it = packetqueue.get_event_start_packet_it(
|
||||
*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());
|
||||
event = openEvent(snap, cause, noteSetMap);
|
||||
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());
|
||||
} else {
|
||||
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>(Seconds(section_length).count()));
|
||||
closeEvent();
|
||||
event = new Event(this, timestamp, 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());
|
||||
event = openEvent(snap, cause, noteSetMap);
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
} // 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() {
|
||||
if (!event) return;
|
||||
|
||||
|
|
|
@ -593,6 +593,10 @@ public:
|
|||
bool Decode();
|
||||
void DumpImage( Image *dump_image ) 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 Reload();
|
||||
|
|
14
src/zmc.cpp
14
src/zmc.cpp
|
@ -220,12 +220,13 @@ int main(int argc, char *argv[]) {
|
|||
zmSetDefaultTermHandler();
|
||||
zmSetDefaultDieHandler();
|
||||
|
||||
sigset_t block_set;
|
||||
sigemptyset(&block_set);
|
||||
|
||||
sigaddset(&block_set, SIGHUP);
|
||||
sigaddset(&block_set, SIGUSR1);
|
||||
sigaddset(&block_set, SIGUSR2);
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = SIG_IGN; //handle signal by ignoring
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
if (sigaction(SIGCHLD, &sa, 0) == -1) {
|
||||
Error("Unable to set SIGCHLD to ignore. There may be zombies.");
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
int prime_capture_log_count = 0;
|
||||
|
@ -286,7 +287,6 @@ int main(int argc, char *argv[]) {
|
|||
Microseconds sleep_time = Microseconds(0);
|
||||
|
||||
while (!zm_terminate) {
|
||||
//sigprocmask(SIG_BLOCK, &block_set, 0);
|
||||
for (size_t i = 0; i < monitors.size(); i++) {
|
||||
monitors[i]->CheckAction();
|
||||
|
||||
|
|
|
@ -167,9 +167,15 @@ class Group extends ZM_Object {
|
|||
public function Parents() {
|
||||
$Parents = array();
|
||||
$Parent = $this->Parent();
|
||||
$seen_parents = array();
|
||||
while ($Parent) {
|
||||
$seen_parents[$Parent->Id()] = $Parent;
|
||||
array_unshift($Parents, $Parent);
|
||||
$Parent = $Parent->Parent();
|
||||
if ($Parent and isset($seen_parents[$Parent->Id()])) {
|
||||
Warning("Detected hierarchy loop in group {$Parent->Name()}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $Parents;
|
||||
}
|
||||
|
@ -189,6 +195,9 @@ class Group extends ZM_Object {
|
|||
public function canView($u=null) {
|
||||
global $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.
|
||||
foreach ($this->Monitors() as $monitor) {
|
||||
if ($monitor->canView($u)) return true;
|
||||
|
|
|
@ -37,7 +37,8 @@ ZM_WEB_GROUP=@WEB_GROUP@
|
|||
ZM_DB_TYPE=@ZM_DB_TYPE@
|
||||
|
||||
# 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@
|
||||
|
||||
# ZoneMinder database name
|
||||
|
|
Loading…
Reference in New Issue