From 2c798069d3d9b5a9efc04e16bb5a9188bfdba0c8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 18 Nov 2021 18:12:07 -0500 Subject: [PATCH 01/11] improve debug logging when loading Control in Monitor --- scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm | 26 ++++++++++++-------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm b/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm index c5e09c137..da3a56373 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm @@ -327,17 +327,23 @@ sub resumeMotionDetection { sub Control { my $self = shift; if ( ! exists $$self{Control}) { - require ZoneMinder::Control; - my $Control = ZoneMinder::Control->find_one(Id=>$$self{ControlId}); - if ($Control) { - require Module::Load::Conditional; - if (!Module::Load::Conditional::can_load(modules => {'ZoneMinder::Control::'.$$Control{Protocol} => undef})) { - Error("Can't load ZoneMinder::Control::$$Control{Protocol}\n$Module::Load::Conditional::ERROR"); - return undef; + if ($$self{ControlId}) { + require ZoneMinder::Control; + my $Control = ZoneMinder::Control->find_one(Id=>$$self{ControlId}); + if ($Control) { + require Module::Load::Conditional; + if (!Module::Load::Conditional::can_load(modules => {'ZoneMinder::Control::'.$$Control{Protocol} => undef})) { + Error("Can't load ZoneMinder::Control::$$Control{Protocol}\n$Module::Load::Conditional::ERROR"); + return undef; + } + bless $Control, 'ZoneMinder::Control::'.$$Control{Protocol}; + $$Control{MonitorId} = $$self{Id}; + $$self{Control} = $Control; + } else { + Error("Unable to load control for control $$self{ControlId} for monitor $$self{Id}"); } - bless $Control, 'ZoneMinder::Control::'.$$Control{Protocol}; - $$Control{MonitorId} = $$self{Id}; - $$self{Control} = $Control; + } else { + Info("No ControlId set in monitor $$self{Id}") } } return $$self{Control}; From 2529765df3616af550ac55e86c93e4db810020a6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Nov 2021 11:59:19 -0500 Subject: [PATCH 02/11] timestamp image before scaling. Fixes lack of scaling when TIMESTAMP_ON_CAPTURE is off --- src/zm_monitorstream.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index 9bc04a311..7c2aeeaa2 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -377,10 +377,10 @@ bool MonitorStream::sendFrame(const std::string &filepath, SystemTimePoint times } bool MonitorStream::sendFrame(Image *image, SystemTimePoint timestamp) { - Image *send_image = prepareImage(image); if (!config.timestamp_on_capture) { - monitor->TimestampImage(send_image, timestamp); + monitor->TimestampImage(image, timestamp); } + Image *send_image = prepareImage(image); fputs("--" BOUNDARY "\r\n", stdout); if ( type == STREAM_MPEG ) { @@ -854,16 +854,16 @@ void MonitorStream::SingleImage(int scale) { 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); Image *snap_image = monitor->image_buffer[index]; + if (!config.timestamp_on_capture) { + monitor->TimestampImage(snap_image, + SystemTimePoint(zm::chrono::duration_cast(monitor->shared_timestamps[index]))); + } if ( scale != ZM_SCALE_BASE ) { scaled_image.Assign(*snap_image); scaled_image.Scale(scale); snap_image = &scaled_image; } - if (!config.timestamp_on_capture) { - monitor->TimestampImage(snap_image, - SystemTimePoint(zm::chrono::duration_cast(monitor->shared_timestamps[index]))); - } snap_image->EncodeJpeg(img_buffer, &img_buffer_size); fprintf(stdout, From 40e7f607f5d3dd73fcd714acc3cd7d73e06d9188 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 22 Nov 2021 11:38:40 -0500 Subject: [PATCH 03/11] If no protocol defined, fall back to the name of the Control --- scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm b/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm index da3a56373..5646fb897 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm @@ -326,17 +326,23 @@ sub resumeMotionDetection { sub Control { my $self = shift; - if ( ! exists $$self{Control}) { + if (!exists $$self{Control}) { if ($$self{ControlId}) { require ZoneMinder::Control; my $Control = ZoneMinder::Control->find_one(Id=>$$self{ControlId}); if ($Control) { + my $Protocol = $$Control{Protocol}; + + if (!$Protocol) { + Error("No protocol set in control $$Control{Id}, trying Name $$Control{Name}"); + $Protocol = $$Control{Name}; + } require Module::Load::Conditional; - if (!Module::Load::Conditional::can_load(modules => {'ZoneMinder::Control::'.$$Control{Protocol} => undef})) { - Error("Can't load ZoneMinder::Control::$$Control{Protocol}\n$Module::Load::Conditional::ERROR"); + if (!Module::Load::Conditional::can_load(modules => {'ZoneMinder::Control::'.$Protocol => undef})) { + Error("Can't load ZoneMinder::Control::$Protocol\n$Module::Load::Conditional::ERROR"); return undef; } - bless $Control, 'ZoneMinder::Control::'.$$Control{Protocol}; + bless $Control, 'ZoneMinder::Control::'.$Protocol; $$Control{MonitorId} = $$self{Id}; $$self{Control} = $Control; } else { From cc65c99791ee2ce5c9617dae41d9f7cae8f9a100 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 22 Nov 2021 12:53:51 -0500 Subject: [PATCH 04/11] Move init of ctx up before we setup the monitors. I think in some cases we can calls functions that assume ctx has a value. Uncaught%20TypeError%3A%20Cannot%20read%20properties%20of%20undefined%20(reading%20'getImageData') --- web/skins/classic/views/js/montagereview.js | 25 ++++++++++--------- .../classic/views/js/montagereview.js.php | 2 +- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/web/skins/classic/views/js/montagereview.js b/web/skins/classic/views/js/montagereview.js index 787a910d0..da3301d4d 100644 --- a/web/skins/classic/views/js/montagereview.js +++ b/web/skins/classic/views/js/montagereview.js @@ -985,6 +985,19 @@ function initPage() { }); }); + if ( !liveMode ) { + canvas = document.getElementById('timeline'); + + canvas.addEventListener('mousemove', mmove, false); + canvas.addEventListener('touchmove', tmove, false); + canvas.addEventListener('mousedown', mdown, false); + canvas.addEventListener('mouseup', mup, false); + canvas.addEventListener('mouseout', mout, false); + + ctx = canvas.getContext('2d'); + drawGraph(); + } + for ( var i = 0, len = monitorPtr.length; i < len; i += 1 ) { var monId = monitorPtr[i]; if ( !monId ) continue; @@ -1006,18 +1019,6 @@ function initPage() { } } // end foreach monitor - if ( !liveMode ) { - canvas = document.getElementById('timeline'); - - canvas.addEventListener('mousemove', mmove, false); - canvas.addEventListener('touchmove', tmove, false); - canvas.addEventListener('mousedown', mdown, false); - canvas.addEventListener('mouseup', mup, false); - canvas.addEventListener('mouseout', mout, false); - - ctx = canvas.getContext('2d'); - drawGraph(); - } setSpeed(speedIndex); //setFit(fitMode); // will redraw //setLive(liveMode); // will redraw diff --git a/web/skins/classic/views/js/montagereview.js.php b/web/skins/classic/views/js/montagereview.js.php index d82f103ed..f4b6222f4 100644 --- a/web/skins/classic/views/js/montagereview.js.php +++ b/web/skins/classic/views/js/montagereview.js.php @@ -239,6 +239,6 @@ echo "];\n"; var cWidth; // save canvas width var cHeight; // save canvas height var canvas; // global canvas definition so we don't have to keep looking it up -var ctx; +var ctx = null; var underSlider; // use this to hold what is hidden by the slider var underSliderX; // Where the above was taken from (left side, Y is zero) From 1f75b017ccb4688bfda4726c3ac4bdb3a64bd996 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 22 Nov 2021 14:17:50 -0500 Subject: [PATCH 05/11] kill the background timer when switching to history so that we don't cause a javascript error. comment out debugging and use native javascript instead of jquery. --- web/skins/classic/views/js/montagereview.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/js/montagereview.js b/web/skins/classic/views/js/montagereview.js index da3301d4d..60856f4ca 100644 --- a/web/skins/classic/views/js/montagereview.js +++ b/web/skins/classic/views/js/montagereview.js @@ -57,7 +57,7 @@ function getFrame(monId, time, last_Frame) { var events_for_monitor = events_by_monitor_id[monId]; if ( !events_for_monitor ) { - console.log("No events for monitor " + monId); + //console.log("No events for monitor " + monId); return; } @@ -648,8 +648,11 @@ function setSpeed(speed_index) { } function setLive(value) { + // When we submit the context etc goes away but we may still be trying to update + // So kill the timer. + clearInterval(timerObj); liveMode = value; - var form = $j('#montagereview_form')[0]; + var form = document.getElementById('montagereview_form'); form.elements['live'].value = value; form.submit(); return false; From 46a835b28ab80ec2128d5d4acc2f109f1fb29890 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 22 Nov 2021 14:26:48 -0500 Subject: [PATCH 06/11] fix error when no monitors defined and we are adding one.Fixes #3385 --- web/skins/classic/views/monitor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 7d599904a..3dc6937e8 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -453,7 +453,7 @@ foreach ( $tabs as $name=>$value ) { switch ( $name ) { case 'general' : { - if (!$monitor->Id()) { + if (!$monitor->Id() and count($monitors)) { $monitor_ids = array(); foreach ($monitors as $m) { $monitor_ids[] = $m['Id']; } $available_monitor_ids = array_diff(range(min($monitor_ids),max($monitor_ids)), $monitor_ids); @@ -470,7 +470,7 @@ if (count($available_monitor_ids)) { Id() + } # end if ! $monitor->Id() and count($monitors) ?> From ffdb0f98249819c5a75c123da4709e995deeee80 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 23 Nov 2021 11:05:39 -0500 Subject: [PATCH 07/11] If we are starting a process that is waiting to term, mark it to get started by the reaper. Fixes case where zmdc thought the process was still running and so didn't start it. We never noticed because zmwatch would eventually notice. The result is instant restart. --- scripts/zmdc.pl.in | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index 5cf866e56..793049479 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -429,10 +429,20 @@ sub start { # It's not running, or at least it's not been started by us $process = { daemon=>$daemon, args=>\@args, command=>$command, keepalive=>!undef }; } elsif ( $process->{pid} && $pid_hash{$process->{pid}} ) { - dPrint(ZoneMinder::Logger::INFO, "'$process->{command}' already running at " + if ($process->{term_sent_at}) { + dPrint(ZoneMinder::Logger::INFO, "'$process->{command}' was told to term at " + .strftime('%y/%m/%d %H:%M:%S', localtime($process->{term_sent_at})) + .", pid = $process->{pid}\n" + ); + $process->{keepalive} = !undef; + $process->{delay} = 0; + delete $terminating_processes{$command}; + } else { + dPrint(ZoneMinder::Logger::INFO, "'$process->{command}' already running at " .strftime('%y/%m/%d %H:%M:%S', localtime($process->{started})) .", pid = $process->{pid}\n" - ); + ); + } return; } @@ -523,7 +533,7 @@ sub send_stop { ."\n" ); sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n"; - return(); + return (); } my $pid = $process->{pid}; @@ -586,7 +596,7 @@ sub check_for_processes_to_kill { sub stop { my ( $daemon, @args ) = @_; - my $command = join(' ', $daemon, @args ); + my $command = join(' ', $daemon, @args); my $process = $cmd_hash{$command}; if ( !$process ) { dPrint(ZoneMinder::Logger::WARNING, "Can't find process with command of '$command'"); From 81ffc6df4e763474035d56c098089c7ca6339f8d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 24 Nov 2021 12:06:13 -0500 Subject: [PATCH 08/11] Remove text-nowrap from cause/notes column --- web/skins/classic/views/js/events.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index 6139ba3e4..bafd16763 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -63,13 +63,13 @@ function processRows(rows) { row.Id = '' + eid + ''; row.Name = '' + row.Name + '' + - '
' + archived + emailed + '
'; + '
' + archived + emailed + '
'; if ( canEdit.Monitors ) row.Monitor = '' + row.Monitor + ''; if ( canEdit.Events ) row.Cause = '' + row.Cause + ''; if ( row.Notes.indexOf('detected:') >= 0 ) { - row.Cause = row.Cause + '
' + row.Notes + '
'; + row.Cause = row.Cause + '
' + row.Notes + '
'; } else if ( row.Notes != 'Forced Web: ' ) { - row.Cause = row.Cause + '
' + row.Notes + '
'; + row.Cause = row.Cause + '
' + row.Notes + '
'; } row.Frames = '' + row.Frames + ''; row.AlarmFrames = '' + row.AlarmFrames + ''; From 4be9c6cdd28c87fdaecec89342b758a6876ee6d7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 24 Nov 2021 12:42:31 -0500 Subject: [PATCH 09/11] Code comments and make warning when the first packet in queue is locked. --- src/zm_packetqueue.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 509a25ee6..8b831ec2d 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -116,14 +116,15 @@ bool PacketQueue::queuePacket(std::shared_ptr add_packet) { , max_video_packet_count); for ( - auto it = ++pktQueue.begin(); - it != pktQueue.end() and *it != add_packet; + auto it = ++pktQueue.begin(); + it != pktQueue.end() and *it != add_packet; + // iterator is incremented by erase ) { std::shared_ptr zm_packet = *it; ZMLockedPacket *lp = new ZMLockedPacket(zm_packet); if (!lp->trylock()) { - Debug(1, "Found locked packet when trying to free up video packets. Skipping to next one"); + Warning("Found locked packet when trying to free up video packets. This basically means that decoding is not keeping up."); delete lp; ++it; continue; @@ -312,7 +313,6 @@ void PacketQueue::clearPackets(const std::shared_ptr &add_packet) { pktQueue.size()); pktQueue.pop_front(); packet_counts[zm_packet->packet.stream_index] -= 1; - //delete zm_packet; } } // end if have at least max_video_packet_count video packets remaining // We signal on every packet because someday we may analyze sound From 67556430c661a4e801d306b819442ebc2588844d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 24 Nov 2021 12:44:07 -0500 Subject: [PATCH 10/11] Add option ZM_NO_PCRE to disable testing for libpcre3. debian wants to remove it so this allows us to test building without it. Remove libpcre3 from depends and set ZM_NO_PCRE=ON in debian build config --- CMakeLists.txt | 34 ++++++++++++++++++++-------------- distros/ubuntu2004/control | 2 -- distros/ubuntu2004/rules | 1 + 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c34a9f808..3b789e4c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -167,6 +167,8 @@ set(ZM_NO_X10 "OFF" CACHE BOOL set(ZM_ONVIF "ON" CACHE BOOL "Set to ON to enable basic ONVIF support. This is EXPERIMENTAL and may not work with all cameras claiming to be ONVIF compliant. default: ON") +set(ZM_NO_PCRE "OFF" CACHE BOOL + "Set to ON to skip libpcre3 checks and force building ZM without libpcre3. default: OFF") set(ZM_NO_RTSPSERVER "OFF" CACHE BOOL "Set to ON to skip building ZM with rtsp server support. default: OFF") set(ZM_PERL_MM_PARMS INSTALLDIRS=vendor NO_PACKLIST=1 NO_PERLLOCAL=1 CACHE STRING @@ -407,21 +409,24 @@ else() message(FATAL_ERROR "ZoneMinder requires pthread but it was not found on your system") endif() -# pcre (using find_library and find_path) -find_library(PCRE_LIBRARIES pcre) -if(PCRE_LIBRARIES) - set(HAVE_LIBPCRE 1) - list(APPEND ZM_BIN_LIBS "${PCRE_LIBRARIES}") - find_path(PCRE_INCLUDE_DIR pcre.h) - if(PCRE_INCLUDE_DIR) - include_directories("${PCRE_INCLUDE_DIR}") - set(CMAKE_REQUIRED_INCLUDES "${PCRE_INCLUDE_DIR}") +# Do not check for cURL if ZM_NO_CURL is on +if(NOT ZM_NO_PRCE) + # pcre (using find_library and find_path) + find_library(PCRE_LIBRARIES pcre) + if(PCRE_LIBRARIES) + set(HAVE_LIBPCRE 1) + list(APPEND ZM_BIN_LIBS "${PCRE_LIBRARIES}") + find_path(PCRE_INCLUDE_DIR pcre.h) + if(PCRE_INCLUDE_DIR) + include_directories("${PCRE_INCLUDE_DIR}") + set(CMAKE_REQUIRED_INCLUDES "${PCRE_INCLUDE_DIR}") + endif() + mark_as_advanced(FORCE PCRE_LIBRARIES PCRE_INCLUDE_DIR) + check_include_file("pcre.h" HAVE_PCRE_H) + set(optlibsfound "${optlibsfound} PCRE") + else() + set(optlibsnotfound "${optlibsnotfound} PCRE") endif() - mark_as_advanced(FORCE PCRE_LIBRARIES PCRE_INCLUDE_DIR) - check_include_file("pcre.h" HAVE_PCRE_H) - set(optlibsfound "${optlibsfound} PCRE") -else() - set(optlibsnotfound "${optlibsnotfound} PCRE") endif() # mysqlclient (using find_library and find_path) @@ -540,6 +545,7 @@ set(ZM_PCRE 0) if(HAVE_LIBPCRE AND HAVE_PCRE_H) set(ZM_PCRE 1) endif() + # Check for mmap and enable in all components set(ZM_MEM_MAPPED 0) set(ENABLE_MMAP no) diff --git a/distros/ubuntu2004/control b/distros/ubuntu2004/control index a4683bfde..d14c3fb52 100644 --- a/distros/ubuntu2004/control +++ b/distros/ubuntu2004/control @@ -16,7 +16,6 @@ Build-Depends: debhelper (>= 11), sphinx-doc, python3-sphinx, dh-linktree, dh-ap ,libjpeg-turbo8-dev | libjpeg62-turbo-dev | libjpeg8-dev | libjpeg9-dev ,libturbojpeg0-dev ,default-libmysqlclient-dev | libmysqlclient-dev | libmariadbclient-dev-compat - ,libpcre3-dev ,libpolkit-gobject-1-dev ,libv4l-dev [!hurd-any] ,libvlc-dev @@ -70,7 +69,6 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends} ,policykit-1 ,rsyslog | system-log-daemon ,zip - ,libpcre3 ,libcrypt-eksblowfish-perl ,libdata-entropy-perl ,libvncclient1|libvncclient0 diff --git a/distros/ubuntu2004/rules b/distros/ubuntu2004/rules index c137a9da2..af75a409a 100755 --- a/distros/ubuntu2004/rules +++ b/distros/ubuntu2004/rules @@ -19,6 +19,7 @@ override_dh_auto_configure: -DCMAKE_VERBOSE_MAKEFILE=ON \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_MAN=0 \ + -DZM_NO_PCRE=ON \ -DZM_CONFIG_DIR="/etc/zm" \ -DZM_CONFIG_SUBDIR="/etc/zm/conf.d" \ -DZM_RUNDIR="/run/zm" \ From 77d3109152ab6a238589ec82853d864403af4833 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 24 Nov 2021 13:44:45 -0500 Subject: [PATCH 11/11] Increase to 20 before warning about db queue size. Put lock in it's own scope so that we unlock before notifying --- src/zm_db.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/zm_db.cpp b/src/zm_db.cpp index e3b737c07..f0b13d538 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -251,11 +251,11 @@ void zmDbQueue::process() { mCondition.wait(lock); } while (!mQueue.empty()) { - if (mQueue.size() > 10) { + if (mQueue.size() > 20) { Logger *log = Logger::fetch(); Logger::Level db_level = log->databaseLevel(); log->databaseLevel(Logger::NOLOG); - Warning("db queue size has grown larger %zu than 10 entries", mQueue.size()); + Warning("db queue size has grown larger %zu than 20 entries", mQueue.size()); log->databaseLevel(db_level); } std::string sql = mQueue.front(); @@ -271,8 +271,10 @@ void zmDbQueue::process() { void zmDbQueue::push(std::string &&sql) { if (mTerminate) return; - std::unique_lock lock(mMutex); - mQueue.push(std::move(sql)); + { + std::unique_lock lock(mMutex); + mQueue.push(std::move(sql)); + } mCondition.notify_all(); }